From 19cf1ce2b9f3749bc5e5d3a107edc7dd45a002fd Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Fri, 31 May 2019 08:29:11 +0100 Subject: [PATCH] Import cargo_0.35.0.orig-vendor.tar.gz [dgit import orig cargo_0.35.0.orig-vendor.tar.gz] --- aho-corasick/.cargo-checksum.json | 1 + aho-corasick/COPYING | 3 + aho-corasick/Cargo.toml | 45 + aho-corasick/LICENSE-MIT | 21 + aho-corasick/README.md | 190 + aho-corasick/UNLICENSE | 24 + aho-corasick/appveyor.yml | 26 + aho-corasick/src/ahocorasick.rs | 2032 ++ aho-corasick/src/automaton.rs | 401 + aho-corasick/src/buffer.rs | 131 + aho-corasick/src/classes.rs | 243 + aho-corasick/src/dfa.rs | 688 + aho-corasick/src/error.rs | 103 + aho-corasick/src/lib.rs | 289 + aho-corasick/src/nfa.rs | 1230 ++ aho-corasick/src/prefilter.rs | 251 + aho-corasick/src/state_id.rs | 166 + aho-corasick/src/tests.rs | 694 + ansi_term/.cargo-checksum.json | 1 + ansi_term/Cargo.toml | 27 + ansi_term/LICENCE | 21 + ansi_term/README.md | 174 + ansi_term/examples/colours.rs | 13 + ansi_term/src/ansi.rs | 258 + ansi_term/src/debug.rs | 122 + ansi_term/src/difference.rs | 179 + ansi_term/src/display.rs | 279 + ansi_term/src/lib.rs | 205 + ansi_term/src/style.rs | 259 + ansi_term/src/windows.rs | 40 + ansi_term/src/write.rs | 40 + atty/.cargo-checksum.json | 1 + atty/CHANGELOG.md | 61 + atty/Cargo.toml | 33 + atty/LICENSE | 20 + atty/README.md | 76 + atty/appveyor.yml | 16 + atty/examples/atty.rs | 9 + atty/rustfmt.toml | 10 + atty/src/lib.rs | 210 + autocfg/.cargo-checksum.json | 1 + autocfg/Cargo.toml | 24 + autocfg/LICENSE-APACHE | 201 + autocfg/LICENSE-MIT | 25 + autocfg/README.md | 75 + autocfg/examples/integers.rs | 9 + autocfg/examples/paths.rs | 22 + autocfg/examples/traits.rs | 26 + autocfg/examples/versions.rs | 9 + autocfg/src/error.rs | 69 + autocfg/src/lib.rs | 305 + autocfg/src/tests.rs | 65 + autocfg/src/version.rs | 60 + backtrace-sys/.cargo-checksum.json | 1 + backtrace-sys/.pc/.quilt_patches | 1 + backtrace-sys/.pc/.quilt_series | 1 + backtrace-sys/.pc/.version | 1 + backtrace-sys/.pc/applied-patches | 1 + .../.pc/remove-unneeded-dep.patch/.timestamp | 0 .../.pc/remove-unneeded-dep.patch/Cargo.toml | 27 + backtrace-sys/Cargo.toml | 25 + backtrace-sys/LICENSE-APACHE | 201 + backtrace-sys/LICENSE-MIT | 25 + backtrace-sys/build.rs | 10 + backtrace-sys/build.rs.orig | 108 + .../debian/patches/remove-unneeded-dep.patch | 22 + backtrace-sys/debian/patches/series | 1 + backtrace-sys/src/lib.rs | 52 + backtrace/.cargo-checksum.json | 1 + backtrace/Cargo.toml | 107 + backtrace/LICENSE-APACHE | 201 + backtrace/LICENSE-MIT | 25 + backtrace/README.md | 83 + backtrace/azure-pipelines.yml | 158 + backtrace/benches/benchmarks.rs | 94 + backtrace/build.rs | 13 + backtrace/ci/android-ndk.sh | 23 + backtrace/ci/azure-install-rust.yml | 23 + backtrace/ci/azure-test-all.yml | 43 + .../docker/aarch64-linux-android/Dockerfile | 18 + .../aarch64-unknown-linux-gnu/Dockerfile | 11 + .../docker/arm-linux-androideabi/Dockerfile | 18 + .../arm-unknown-linux-gnueabihf/Dockerfile | 10 + .../docker/armv7-linux-androideabi/Dockerfile | 18 + .../armv7-unknown-linux-gnueabihf/Dockerfile | 10 + .../docker/i586-unknown-linux-gnu/Dockerfile | 5 + .../ci/docker/i686-linux-android/Dockerfile | 18 + .../docker/i686-unknown-linux-gnu/Dockerfile | 5 + .../powerpc64-unknown-linux-gnu/Dockerfile | 16 + .../ci/docker/x86_64-linux-android/Dockerfile | 18 + .../docker/x86_64-pc-windows-gnu/Dockerfile | 10 + .../x86_64-unknown-linux-gnu/Dockerfile | 5 + .../x86_64-unknown-linux-musl/Dockerfile | 6 + backtrace/ci/run-docker.sh | 32 + backtrace/ci/run.sh | 5 + backtrace/examples/backtrace.rs | 7 + backtrace/examples/raw.rs | 54 + backtrace/src/backtrace/dbghelp.rs | 207 + backtrace/src/backtrace/libunwind.rs | 248 + backtrace/src/backtrace/mod.rs | 139 + backtrace/src/backtrace/noop.rs | 20 + backtrace/src/backtrace/unix_backtrace.rs | 62 + backtrace/src/capture.rs | 554 + backtrace/src/dbghelp.rs | 329 + backtrace/src/lib.rs | 177 + backtrace/src/symbolize/coresymbolication.rs | 278 + backtrace/src/symbolize/dbghelp.rs | 236 + backtrace/src/symbolize/dladdr.rs | 70 + backtrace/src/symbolize/gimli.rs | 237 + backtrace/src/symbolize/libbacktrace.rs | 448 + backtrace/src/symbolize/mod.rs | 446 + backtrace/src/symbolize/noop.rs | 34 + backtrace/src/types.rs | 89 + backtrace/src/windows.rs | 611 + backtrace/tests/long_fn_name.rs | 50 + backtrace/tests/skip_inner_frames.rs | 55 + backtrace/tests/smoke.rs | 230 + bit-set/.cargo-checksum.json | 1 + bit-set/Cargo.toml | 33 + bit-set/LICENSE-APACHE | 201 + bit-set/LICENSE-MIT | 25 + bit-set/README.md | 17 + bit-set/deploy-docs.sh | 20 + bit-set/src/lib.rs | 1443 ++ bit-vec/.cargo-checksum.json | 1 + bit-vec/Cargo.toml | 30 + bit-vec/LICENSE-APACHE | 201 + bit-vec/LICENSE-MIT | 25 + bit-vec/README.md | 18 + bit-vec/benches/extern.rs | 22 + bit-vec/crusader.sh | 11 + bit-vec/deploy-docs.sh | 20 + bit-vec/src/bench.rs | 116 + bit-vec/src/lib.rs | 2139 +++ bitflags/.cargo-checksum.json | 1 + bitflags/CHANGELOG.md | 108 + bitflags/CODE_OF_CONDUCT.md | 73 + bitflags/Cargo.toml | 33 + bitflags/LICENSE-APACHE | 201 + bitflags/LICENSE-MIT | 25 + bitflags/README.md | 34 + bitflags/src/example_generated.rs | 14 + bitflags/src/lib.rs | 1229 ++ bstr/.cargo-checksum.json | 1 + bstr/COPYING | 8 + bstr/Cargo.toml | 68 + bstr/LICENSE-APACHE | 201 + bstr/LICENSE-MIT | 21 + bstr/README.md | 252 + bstr/examples/graphemes-std.rs | 28 + bstr/examples/graphemes.rs | 24 + bstr/examples/lines-std.rs | 17 + bstr/examples/lines.rs | 19 + bstr/examples/uppercase-std.rs | 15 + bstr/examples/uppercase.rs | 21 + bstr/examples/words-std.rs | 20 + bstr/examples/words.rs | 17 + bstr/rustfmt.toml | 1 + bstr/scripts/generate-unicode-data | 150 + bstr/scripts/regex/grapheme.sh | 50 + bstr/scripts/regex/sentence.sh | 176 + bstr/scripts/regex/word.sh | 111 + bstr/src/ascii.rs | 322 + bstr/src/bstr.rs | 3991 ++++ bstr/src/bstring.rs | 1588 ++ bstr/src/cow.rs | 89 + bstr/src/freqs.rs | 258 + bstr/src/impls.rs | 730 + bstr/src/io.rs | 203 + bstr/src/lib.rs | 407 + bstr/src/search/byte_frequencies.rs | 258 + bstr/src/search/mod.rs | 8 + bstr/src/search/prefilter.rs | 424 + bstr/src/search/tests.rs | 223 + bstr/src/search/twoway.rs | 883 + bstr/src/slice_index.rs | 292 + bstr/src/tests.rs | 32 + bstr/src/unicode/data/GraphemeBreakTest.txt | 700 + bstr/src/unicode/data/SentenceBreakTest.txt | 530 + bstr/src/unicode/data/WordBreakTest.txt | 1851 ++ .../fsm/grapheme_break_fwd.bigendian.dfa | Bin 0 -> 10223 bytes .../fsm/grapheme_break_fwd.littleendian.dfa | Bin 0 -> 10223 bytes bstr/src/unicode/fsm/grapheme_break_fwd.rs | 45 + .../fsm/grapheme_break_rev.bigendian.dfa | Bin 0 -> 51923 bytes .../fsm/grapheme_break_rev.littleendian.dfa | Bin 0 -> 51923 bytes bstr/src/unicode/fsm/grapheme_break_rev.rs | 45 + bstr/src/unicode/fsm/mod.rs | 8 + .../fsm/regional_indicator_rev.bigendian.dfa | Bin 0 -> 366 bytes .../regional_indicator_rev.littleendian.dfa | Bin 0 -> 366 bytes .../src/unicode/fsm/regional_indicator_rev.rs | 45 + .../fsm/sentence_break_fwd.bigendian.dfa | Bin 0 -> 144343 bytes .../fsm/sentence_break_fwd.littleendian.dfa | Bin 0 -> 144343 bytes bstr/src/unicode/fsm/sentence_break_fwd.rs | 45 + .../unicode/fsm/simple_word_fwd.bigendian.dfa | Bin 0 -> 8665 bytes .../fsm/simple_word_fwd.littleendian.dfa | Bin 0 -> 8665 bytes bstr/src/unicode/fsm/simple_word_fwd.rs | 45 + .../fsm/whitespace_anchored_fwd.bigendian.dfa | Bin 0 -> 572 bytes .../whitespace_anchored_fwd.littleendian.dfa | Bin 0 -> 572 bytes .../unicode/fsm/whitespace_anchored_fwd.rs | 45 + .../fsm/whitespace_anchored_rev.bigendian.dfa | Bin 0 -> 598 bytes .../whitespace_anchored_rev.littleendian.dfa | Bin 0 -> 598 bytes .../unicode/fsm/whitespace_anchored_rev.rs | 45 + .../unicode/fsm/word_break_fwd.bigendian.dfa | Bin 0 -> 218729 bytes .../fsm/word_break_fwd.littleendian.dfa | Bin 0 -> 218729 bytes bstr/src/unicode/fsm/word_break_fwd.rs | 45 + bstr/src/unicode/grapheme.rs | 357 + bstr/src/unicode/mod.rs | 12 + bstr/src/unicode/sentence.rs | 221 + bstr/src/unicode/whitespace.rs | 14 + bstr/src/unicode/word.rs | 447 + bstr/src/utf8.rs | 1108 ++ bufstream/.cargo-checksum.json | 1 + bufstream/Cargo.toml | 32 + bufstream/LICENSE-APACHE | 201 + bufstream/LICENSE-MIT | 25 + bufstream/README.md | 22 + bufstream/src/lib.rs | 262 + byteorder/.cargo-checksum.json | 1 + byteorder/CHANGELOG.md | 114 + byteorder/COPYING | 3 + byteorder/Cargo.toml | 45 + byteorder/LICENSE-MIT | 21 + byteorder/README.md | 56 + byteorder/UNLICENSE | 24 + byteorder/benches/bench.rs | 328 + byteorder/build.rs | 87 + byteorder/src/io.rs | 1569 ++ byteorder/src/lib.rs | 3315 ++++ bytes/.cargo-checksum.json | 1 + bytes/CHANGELOG.md | 86 + bytes/Cargo.toml | 46 + bytes/LICENSE | 25 + bytes/README.md | 45 + bytes/benches/bytes.rs | 250 + bytes/ci/before_deploy.ps1 | 23 + bytes/ci/before_deploy.sh | 33 + bytes/ci/install.sh | 31 + bytes/ci/script.sh | 18 + bytes/ci/tsan | 28 + bytes/src/buf/buf.rs | 1154 ++ bytes/src/buf/buf_mut.rs | 1167 ++ bytes/src/buf/chain.rs | 226 + bytes/src/buf/from_buf.rs | 117 + bytes/src/buf/into_buf.rs | 146 + bytes/src/buf/iter.rs | 116 + bytes/src/buf/mod.rs | 38 + bytes/src/buf/reader.rs | 97 + bytes/src/buf/take.rs | 155 + bytes/src/buf/vec_deque.rs | 39 + bytes/src/buf/writer.rs | 88 + bytes/src/bytes.rs | 2947 +++ bytes/src/debug.rs | 40 + bytes/src/either.rs | 89 + bytes/src/lib.rs | 105 + bytes/src/serde.rs | 82 + bytes/tests/test_buf.rs | 58 + bytes/tests/test_buf_mut.rs | 83 + bytes/tests/test_bytes.rs | 773 + bytes/tests/test_chain.rs | 122 + bytes/tests/test_debug.rs | 35 + bytes/tests/test_from_buf.rs | 34 + bytes/tests/test_iter.rs | 22 + bytes/tests/test_reader.rs | 28 + bytes/tests/test_serde.rs | 21 + bytes/tests/test_take.rs | 13 + bytesize/.cargo-checksum.json | 1 + bytesize/Cargo.toml | 27 + bytesize/LICENSE | 202 + bytesize/README.md | 95 + bytesize/src/lib.rs | 365 + cc/.cargo-checksum.json | 1 + cc/Cargo.toml | 33 + cc/LICENSE-APACHE | 201 + cc/LICENSE-MIT | 25 + cc/README.md | 202 + cc/azure-pipelines.yml | 101 + cc/ci/azure-install-rust.yml | 24 + cc/ci/azure-steps.yml | 21 + cc/src/bin/gcc-shim.rs | 23 + cc/src/com.rs | 155 + cc/src/lib.rs | 2422 +++ cc/src/registry.rs | 204 + cc/src/setup_config.rs | 283 + cc/src/winapi.rs | 218 + cc/src/windows_registry.rs | 759 + cc/tests/cc_env.rs | 121 + cc/tests/support/mod.rs | 133 + cc/tests/test.rs | 371 + cfg-if/.cargo-checksum.json | 1 + cfg-if/Cargo.toml | 24 + cfg-if/LICENSE-APACHE | 201 + cfg-if/LICENSE-MIT | 25 + cfg-if/README.md | 52 + cfg-if/src/lib.rs | 144 + cfg-if/tests/xcrate.rs | 17 + chrono/.cargo-checksum.json | 1 + chrono/AUTHORS.txt | 39 + chrono/CHANGELOG.md | 551 + chrono/Cargo.toml | 72 + chrono/LICENSE.txt | 240 + chrono/Makefile | 30 + chrono/README.md | 391 + chrono/appveyor.yml | 21 + chrono/ci/fix-readme.sh | 35 + chrono/ci/travis.sh | 100 + chrono/src/date.rs | 383 + chrono/src/datetime.rs | 1647 ++ chrono/src/div.rs | 42 + chrono/src/format/mod.rs | 625 + chrono/src/format/parse.rs | 794 + chrono/src/format/parsed.rs | 1088 ++ chrono/src/format/scan.rs | 304 + chrono/src/format/strftime.rs | 483 + chrono/src/lib.rs | 994 + chrono/src/naive/date.rs | 2121 ++ chrono/src/naive/datetime.rs | 2351 +++ chrono/src/naive/internals.rs | 779 + chrono/src/naive/isoweek.rs | 161 + chrono/src/naive/time.rs | 1733 ++ chrono/src/offset/fixed.rs | 224 + chrono/src/offset/local.rs | 182 + chrono/src/offset/mod.rs | 419 + chrono/src/offset/utc.rs | 75 + chrono/src/oldtime.rs | 640 + chrono/src/round.rs | 178 + clap/.cargo-checksum.json | 1 + clap/.pc/.quilt_patches | 1 + clap/.pc/.quilt_series | 1 + clap/.pc/.version | 1 + clap/.pc/applied-patches | 2 + clap/.pc/no-clippy.patch/.timestamp | 0 clap/.pc/no-clippy.patch/Cargo.toml | 132 + clap/.pc/relax-dep-versions.patch/.timestamp | 0 clap/.pc/relax-dep-versions.patch/Cargo.toml | 127 + clap/CHANGELOG.md | 2855 +++ clap/CONTRIBUTORS.md | 91 + clap/Cargo.toml | 127 + clap/LICENSE-MIT | 21 + clap/README.md | 542 + clap/SPONSORS.md | 17 + clap/clap-test.rs | 86 + clap/debian/patches/no-clippy.patch | 21 + clap/debian/patches/relax-dep-versions.patch | 20 + clap/debian/patches/series | 2 + clap/justfile | 39 + clap/rustfmt.toml | 4 + clap/src/app/help.rs | 1028 + clap/src/app/meta.rs | 33 + clap/src/app/mod.rs | 1839 ++ clap/src/app/parser.rs | 2167 +++ clap/src/app/settings.rs | 1174 ++ clap/src/app/usage.rs | 479 + clap/src/app/validator.rs | 573 + clap/src/args/any_arg.rs | 74 + clap/src/args/arg.rs | 3954 ++++ clap/src/args/arg_builder/base.rs | 38 + clap/src/args/arg_builder/flag.rs | 159 + clap/src/args/arg_builder/mod.rs | 13 + clap/src/args/arg_builder/option.rs | 244 + clap/src/args/arg_builder/positional.rs | 229 + clap/src/args/arg_builder/switched.rs | 38 + clap/src/args/arg_builder/valued.rs | 67 + clap/src/args/arg_matcher.rs | 218 + clap/src/args/arg_matches.rs | 963 + clap/src/args/group.rs | 635 + clap/src/args/macros.rs | 109 + clap/src/args/matched_arg.rs | 24 + clap/src/args/mod.rs | 21 + clap/src/args/settings.rs | 231 + clap/src/args/subcommand.rs | 66 + clap/src/completions/bash.rs | 219 + clap/src/completions/elvish.rs | 126 + clap/src/completions/fish.rs | 99 + clap/src/completions/macros.rs | 28 + clap/src/completions/mod.rs | 179 + clap/src/completions/powershell.rs | 139 + clap/src/completions/shell.rs | 52 + clap/src/completions/zsh.rs | 472 + clap/src/errors.rs | 912 + clap/src/fmt.rs | 189 + clap/src/lib.rs | 629 + clap/src/macros.rs | 1108 ++ clap/src/map.rs | 74 + clap/src/osstringext.rs | 119 + clap/src/strext.rs | 16 + clap/src/suggestions.rs | 147 + clap/src/usage_parser.rs | 1347 ++ cloudabi/.cargo-checksum.json | 1 + cloudabi/Cargo.toml | 31 + cloudabi/bitflags.rs | 51 + cloudabi/cloudabi.rs | 2847 +++ commoncrypto-sys/.cargo-checksum.json | 1 + commoncrypto-sys/.pc/.quilt_patches | 1 + commoncrypto-sys/.pc/.quilt_series | 1 + commoncrypto-sys/.pc/.version | 1 + commoncrypto-sys/.pc/applied-patches | 1 + .../.pc/no-clippy.patch/.timestamp | 0 .../.pc/no-clippy.patch/Cargo.toml | 20 + commoncrypto-sys/Cargo.toml | 15 + .../debian/patches/no-clippy.patch | 16 + commoncrypto-sys/debian/patches/series | 1 + commoncrypto-sys/src/lib.rs | 237 + commoncrypto-sys/tests/hash.rs | 138 + commoncrypto-sys/tests/pbkdf2.rs | 48 + commoncrypto/.cargo-checksum.json | 1 + commoncrypto/.pc/.quilt_patches | 1 + commoncrypto/.pc/.quilt_series | 1 + commoncrypto/.pc/.version | 1 + commoncrypto/.pc/applied-patches | 1 + commoncrypto/.pc/no-clippy.patch/.timestamp | 0 commoncrypto/.pc/no-clippy.patch/Cargo.toml | 20 + commoncrypto/Cargo.toml | 15 + commoncrypto/debian/patches/no-clippy.patch | 16 + commoncrypto/debian/patches/series | 1 + commoncrypto/src/hash.rs | 127 + commoncrypto/src/lib.rs | 30 + commoncrypto/src/pbkdf2.rs | 66 + commoncrypto/tests/hash.rs | 18 + commoncrypto/tests/pbkdf2.rs | 16 + core-foundation-sys/.cargo-checksum.json | 1 + core-foundation-sys/Cargo.toml | 27 + core-foundation-sys/LICENSE-APACHE | 201 + core-foundation-sys/LICENSE-MIT | 25 + core-foundation-sys/build.rs | 14 + core-foundation-sys/src/array.rs | 55 + core-foundation-sys/src/attributed_string.rs | 56 + core-foundation-sys/src/base.rs | 154 + core-foundation-sys/src/bundle.rs | 36 + core-foundation-sys/src/data.rs | 31 + core-foundation-sys/src/date.rs | 34 + core-foundation-sys/src/dictionary.rs | 91 + core-foundation-sys/src/error.rs | 32 + core-foundation-sys/src/filedescriptor.rs | 58 + core-foundation-sys/src/lib.rs | 30 + core-foundation-sys/src/messageport.rs | 79 + core-foundation-sys/src/number.rs | 60 + core-foundation-sys/src/propertylist.rs | 46 + core-foundation-sys/src/runloop.rs | 164 + core-foundation-sys/src/set.rs | 58 + core-foundation-sys/src/string.rs | 319 + core-foundation-sys/src/timezone.rs | 27 + core-foundation-sys/src/url.rs | 164 + core-foundation-sys/src/uuid.rs | 49 + core-foundation/.cargo-checksum.json | 1 + core-foundation/.pc/.quilt_patches | 1 + core-foundation/.pc/.quilt_series | 1 + core-foundation/.pc/.version | 1 + core-foundation/.pc/applied-patches | 1 + .../update-dep-uuid-version.patch/.timestamp | 0 .../update-dep-uuid-version.patch/Cargo.toml | 41 + .../update-dep-uuid-version.patch/src/uuid.rs | 118 + core-foundation/Cargo.toml | 41 + core-foundation/LICENSE-APACHE | 201 + core-foundation/LICENSE-MIT | 25 + core-foundation/debian/patches/series | 1 + .../patches/update-dep-uuid-version.patch | 22 + core-foundation/src/array.rs | 286 + core-foundation/src/attributed_string.rs | 85 + core-foundation/src/base.rs | 450 + core-foundation/src/boolean.rs | 70 + core-foundation/src/bundle.rs | 141 + core-foundation/src/data.rs | 63 + core-foundation/src/date.rs | 130 + core-foundation/src/dictionary.rs | 409 + core-foundation/src/error.rs | 71 + core-foundation/src/filedescriptor.rs | 210 + core-foundation/src/lib.rs | 232 + core-foundation/src/number.rs | 120 + core-foundation/src/propertylist.rs | 325 + core-foundation/src/runloop.rs | 199 + core-foundation/src/set.rs | 44 + core-foundation/src/string.rs | 150 + core-foundation/src/timezone.rs | 95 + core-foundation/src/url.rs | 156 + core-foundation/src/uuid.rs | 118 + .../tests/use_macro_outside_crate.rs | 28 + crc32fast/.cargo-checksum.json | 1 + crc32fast/Cargo.toml | 41 + crc32fast/LICENSE-APACHE | 202 + crc32fast/LICENSE-MIT | 21 + crc32fast/README.md | 81 + crc32fast/benches/bench.rs | 49 + crc32fast/build.rs | 35 + crc32fast/src/baseline.rs | 94 + crc32fast/src/combine.rs | 77 + crc32fast/src/lib.rs | 178 + crc32fast/src/specialized/aarch64.rs | 88 + crc32fast/src/specialized/mod.rs | 36 + crc32fast/src/specialized/pclmulqdq.rs | 225 + crc32fast/src/table.rs | 626 + crossbeam-channel/.cargo-checksum.json | 1 + crossbeam-channel/.pc/.quilt_patches | 1 + crossbeam-channel/.pc/.quilt_series | 1 + crossbeam-channel/.pc/.version | 1 + crossbeam-channel/.pc/applied-patches | 1 + .../.pc/relax-dep-version.patch/.timestamp | 0 .../.pc/relax-dep-version.patch/Cargo.toml | 34 + crossbeam-channel/CHANGELOG.md | 137 + crossbeam-channel/Cargo.toml | 34 + crossbeam-channel/LICENSE-APACHE | 201 + crossbeam-channel/LICENSE-MIT | 23 + crossbeam-channel/LICENSE-THIRD-PARTY | 625 + crossbeam-channel/README.md | 88 + .../debian/patches/relax-dep-version.patch | 13 + crossbeam-channel/debian/patches/series | 1 + crossbeam-channel/examples/fibonacci.rs | 27 + crossbeam-channel/examples/matching.rs | 75 + crossbeam-channel/examples/stopwatch.rs | 58 + crossbeam-channel/src/channel.rs | 1340 ++ crossbeam-channel/src/context.rs | 189 + crossbeam-channel/src/counter.rs | 132 + crossbeam-channel/src/err.rs | 451 + crossbeam-channel/src/flavors/after.rs | 200 + crossbeam-channel/src/flavors/array.rs | 637 + crossbeam-channel/src/flavors/list.rs | 657 + crossbeam-channel/src/flavors/mod.rs | 17 + crossbeam-channel/src/flavors/never.rs | 110 + crossbeam-channel/src/flavors/tick.rs | 173 + crossbeam-channel/src/flavors/zero.rs | 461 + crossbeam-channel/src/lib.rs | 372 + crossbeam-channel/src/select.rs | 1078 ++ crossbeam-channel/src/select_macro.rs | 1201 ++ crossbeam-channel/src/utils.rs | 118 + crossbeam-channel/src/waker.rs | 285 + crossbeam-channel/tests/after.rs | 335 + crossbeam-channel/tests/array.rs | 604 + crossbeam-channel/tests/golang.rs | 1025 + crossbeam-channel/tests/iter.rs | 110 + crossbeam-channel/tests/list.rs | 488 + crossbeam-channel/tests/mpsc.rs | 1948 ++ crossbeam-channel/tests/never.rs | 99 + crossbeam-channel/tests/ready.rs | 822 + crossbeam-channel/tests/select.rs | 1285 ++ crossbeam-channel/tests/select_macro.rs | 1416 ++ crossbeam-channel/tests/thread_locals.rs | 53 + crossbeam-channel/tests/tick.rs | 350 + crossbeam-channel/tests/zero.rs | 501 + crossbeam-utils/.cargo-checksum.json | 1 + crossbeam-utils/CHANGELOG.md | 89 + crossbeam-utils/Cargo.toml | 37 + crossbeam-utils/LICENSE-APACHE | 201 + crossbeam-utils/LICENSE-MIT | 23 + crossbeam-utils/README.md | 72 + crossbeam-utils/benches/atomic_cell.rs | 159 + crossbeam-utils/src/atomic/atomic_cell.rs | 924 + crossbeam-utils/src/atomic/consume.rs | 82 + crossbeam-utils/src/atomic/mod.rs | 7 + crossbeam-utils/src/backoff.rs | 294 + crossbeam-utils/src/cache_padded.rs | 116 + crossbeam-utils/src/lib.rs | 67 + crossbeam-utils/src/sync/mod.rs | 17 + crossbeam-utils/src/sync/parker.rs | 311 + crossbeam-utils/src/sync/sharded_lock.rs | 600 + crossbeam-utils/src/sync/wait_group.rs | 139 + crossbeam-utils/src/thread.rs | 529 + crossbeam-utils/tests/atomic_cell.rs | 208 + crossbeam-utils/tests/cache_padded.rs | 112 + crossbeam-utils/tests/parker.rs | 42 + crossbeam-utils/tests/sharded_lock.rs | 245 + crossbeam-utils/tests/thread.rs | 175 + crossbeam-utils/tests/wait_group.rs | 66 + crypto-hash/.cargo-checksum.json | 1 + crypto-hash/CONTRIBUTING.md | 77 + crypto-hash/Cargo.toml | 37 + crypto-hash/LICENSE | 19 + crypto-hash/Makefile | 29 + crypto-hash/NEWS.md | 80 + crypto-hash/README.md | 54 + crypto-hash/src/imp/commoncrypto.rs | 81 + crypto-hash/src/imp/cryptoapi.rs | 169 + crypto-hash/src/imp/openssl.rs | 85 + crypto-hash/src/lib.rs | 119 + crypto-hash/src/test.rs | 83 + curl-sys/.cargo-checksum.json | 1 + curl-sys/.pc/.quilt_patches | 1 + curl-sys/.pc/.quilt_series | 1 + curl-sys/.pc/.version | 1 + curl-sys/.pc/applied-patches | 1 + curl-sys/.pc/disable-vendor.patch/.timestamp | 0 curl-sys/.pc/disable-vendor.patch/Cargo.toml | 63 + curl-sys/Cargo.toml | 63 + curl-sys/LICENSE | 19 + curl-sys/build.rs | 456 + curl-sys/debian/patches/disable-vendor.patch | 11 + curl-sys/debian/patches/series | 1 + curl-sys/lib.rs | 1052 + curl/.cargo-checksum.json | 1 + curl/.pc/.quilt_patches | 1 + curl/.pc/.quilt_series | 1 + curl/.pc/.version | 1 + curl/.pc/applied-patches | 1 + curl/.pc/winapi3.patch/.timestamp | 0 curl/.pc/winapi3.patch/Cargo.toml | 68 + curl/.pc/winapi3.patch/src/easy/windows.rs | 131 + curl/.pc/winapi3.patch/src/lib.rs | 130 + curl/.pc/winapi3.patch/src/multi.rs | 1102 ++ curl/Cargo.toml | 67 + curl/LICENSE | 19 + curl/README.md | 171 + curl/azure-pipelines.yml | 101 + curl/build.rs | 24 + curl/ci/Dockerfile-centos7 | 7 + curl/ci/Dockerfile-linux32 | 14 + curl/ci/Dockerfile-linux64 | 7 + curl/ci/Dockerfile-linux64-curl | 6 + curl/ci/Dockerfile-mingw | 6 + curl/ci/Dockerfile-musl | 18 + curl/ci/azure-install-rust.yml | 23 + curl/ci/azure-steps.yml | 31 + curl/ci/run.sh | 11 + curl/debian/patches/series | 1 + curl/debian/patches/winapi3.patch | 67 + curl/src/easy/form.rs | 375 + curl/src/easy/handle.rs | 1487 ++ curl/src/easy/handler.rs | 3265 ++++ curl/src/easy/list.rs | 100 + curl/src/easy/mod.rs | 22 + curl/src/easy/windows.rs | 131 + curl/src/error.rs | 621 + curl/src/lib.rs | 128 + curl/src/multi.rs | 1102 ++ curl/src/panic.rs | 34 + curl/src/version.rs | 315 + curl/tests/atexit.rs | 20 + curl/tests/easy.rs | 809 + curl/tests/formdata | 1 + curl/tests/multi.rs | 269 + curl/tests/post.rs | 120 + curl/tests/server/mod.rs | 178 + env_logger/.cargo-checksum.json | 1 + env_logger/Cargo.toml | 57 + env_logger/LICENSE-APACHE | 201 + env_logger/LICENSE-MIT | 25 + env_logger/README.md | 150 + env_logger/examples/custom_default_format.rs | 44 + env_logger/examples/custom_format.rs | 54 + env_logger/examples/custom_logger.rs | 60 + env_logger/examples/default.rs | 36 + env_logger/examples/direct_logger.rs | 40 + env_logger/src/filter/mod.rs | 579 + env_logger/src/filter/regex.rs | 29 + env_logger/src/filter/string.rs | 22 + env_logger/src/fmt/humantime/extern_impl.rs | 84 + env_logger/src/fmt/humantime/mod.rs | 11 + env_logger/src/fmt/humantime/shim_impl.rs | 7 + env_logger/src/fmt/mod.rs | 356 + env_logger/src/fmt/writer/atty.rs | 34 + env_logger/src/fmt/writer/mod.rs | 206 + .../src/fmt/writer/termcolor/extern_impl.rs | 490 + env_logger/src/fmt/writer/termcolor/mod.rs | 12 + .../src/fmt/writer/termcolor/shim_impl.rs | 65 + env_logger/src/lib.rs | 1170 ++ env_logger/tests/init-twice-retains-filter.rs | 40 + env_logger/tests/log-in-log.rs | 38 + env_logger/tests/regexp_filter.rs | 51 + failure/.cargo-checksum.json | 1 + failure/CODE_OF_CONDUCT.md | 46 + failure/Cargo.lock.ci | 136 + failure/Cargo.toml | 33 + failure/LICENSE-APACHE | 201 + failure/LICENSE-MIT | 23 + failure/Makefile | 15 + failure/README.md | 119 + failure/RELEASES.md | 56 + failure/book/src/SUMMARY.md | 14 + failure/book/src/bail-and-ensure.md | 18 + failure/book/src/custom-fail.md | 75 + failure/book/src/derive-fail.md | 177 + failure/book/src/error-errorkind.md | 147 + failure/book/src/error-msg.md | 59 + failure/book/src/error.md | 100 + failure/book/src/fail.md | 152 + failure/book/src/guidance.md | 24 + failure/book/src/howto.md | 8 + failure/book/src/intro.md | 77 + failure/book/src/string-custom-error.md | 168 + failure/book/src/use-error.md | 66 + failure/build-docs.sh | 8 + failure/examples/bail_ensure.rs | 26 + failure/examples/error_as_cause.rs | 18 + failure/examples/simple.rs | 22 + .../examples/string_custom_error_pattern.rs | 76 + failure/src/as_fail.rs | 37 + failure/src/backtrace/internal.rs | 130 + failure/src/backtrace/mod.rs | 144 + failure/src/box_std.rs | 19 + failure/src/compat.rs | 53 + failure/src/context.rs | 180 + failure/src/error/error_impl.rs | 50 + failure/src/error/error_impl_small.rs | 132 + failure/src/error/mod.rs | 248 + failure/src/error_message.rs | 32 + failure/src/lib.rs | 307 + failure/src/macros.rs | 51 + failure/src/result_ext.rs | 203 + failure/src/small_error.rs | 264 + failure/src/sync_failure.rs | 97 + failure/tests/basic_fail.rs | 21 + failure/tests/fail_compat.rs | 35 + failure/tests/macro_trailing_comma.rs | 54 + failure/travis.sh | 39 + failure_derive/.cargo-checksum.json | 1 + failure_derive/Cargo.toml | 41 + failure_derive/build.rs | 39 + failure_derive/src/lib.rs | 259 + failure_derive/tests/backtrace.rs | 64 + failure_derive/tests/custom_type_bounds.rs | 45 + failure_derive/tests/no_derive_display.rs | 21 + failure_derive/tests/tests.rs | 55 + failure_derive/tests/wraps.rs | 94 + filetime/.cargo-checksum.json | 1 + filetime/Cargo.toml | 35 + filetime/LICENSE-APACHE | 201 + filetime/LICENSE-MIT | 25 + filetime/README.md | 40 + filetime/appveyor.yml | 17 + filetime/src/lib.rs | 553 + filetime/src/redox.rs | 70 + filetime/src/unix/linux.rs | 102 + filetime/src/unix/mod.rs | 87 + filetime/src/unix/utimensat.rs | 58 + filetime/src/unix/utimes.rs | 98 + filetime/src/wasm.rs | 40 + filetime/src/windows.rs | 91 + flate2/.cargo-checksum.json | 1 + flate2/.pc/.quilt_patches | 1 + flate2/.pc/.quilt_series | 1 + flate2/.pc/.version | 1 + flate2/.pc/applied-patches | 1 + flate2/.pc/disable-miniz.patch/.timestamp | 0 flate2/.pc/disable-miniz.patch/Cargo.toml | 82 + flate2/Cargo.toml | 72 + flate2/LICENSE-APACHE | 201 + flate2/LICENSE-MIT | 25 + flate2/README.md | 89 + flate2/azure-pipelines.yml | 52 + flate2/ci/azure-install-rust.yml | 25 + flate2/ci/azure-job-test-all.yml | 20 + flate2/debian/patches/disable-miniz.patch | 36 + flate2/debian/patches/series | 1 + flate2/examples/deflatedecoder-bufread.rs | 24 + flate2/examples/deflatedecoder-read.rs | 24 + flate2/examples/deflatedecoder-write.rs | 26 + flate2/examples/deflateencoder-bufread.rs | 24 + flate2/examples/deflateencoder-read.rs | 20 + flate2/examples/deflateencoder-write.rs | 12 + flate2/examples/gzbuilder.rs | 24 + flate2/examples/gzdecoder-bufread.rs | 24 + flate2/examples/gzdecoder-read.rs | 24 + flate2/examples/gzdecoder-write.rs | 26 + flate2/examples/gzencoder-bufread.rs | 24 + flate2/examples/gzencoder-read.rs | 20 + flate2/examples/gzencoder-write.rs | 12 + flate2/examples/gzmultidecoder-bufread.rs | 24 + flate2/examples/gzmultidecoder-read.rs | 24 + flate2/examples/hello_world.txt | 1 + flate2/examples/zlibdecoder-bufread.rs | 24 + flate2/examples/zlibdecoder-read.rs | 24 + flate2/examples/zlibdecoder-write.rs | 26 + flate2/examples/zlibencoder-bufread.rs | 24 + flate2/examples/zlibencoder-read.rs | 21 + flate2/examples/zlibencoder-write.rs | 12 + flate2/src/bufreader.rs | 104 + flate2/src/crc.rs | 178 + flate2/src/deflate/bufread.rs | 268 + flate2/src/deflate/mod.rs | 193 + flate2/src/deflate/read.rs | 266 + flate2/src/deflate/write.rs | 349 + flate2/src/ffi.rs | 173 + flate2/src/gz/bufread.rs | 631 + flate2/src/gz/mod.rs | 359 + flate2/src/gz/read.rs | 303 + flate2/src/gz/write.rs | 480 + flate2/src/lib.rs | 234 + flate2/src/mem.rs | 736 + flate2/src/zio.rs | 290 + flate2/src/zlib/bufread.rs | 258 + flate2/src/zlib/mod.rs | 159 + flate2/src/zlib/read.rs | 265 + flate2/src/zlib/write.rs | 348 + flate2/tests/async-reader.rs | 94 + flate2/tests/corrupt-file.gz | Bin 0 -> 7128 bytes flate2/tests/early-flush.rs | 20 + flate2/tests/empty-read.rs | 82 + flate2/tests/good-file.gz | Bin 0 -> 6766 bytes flate2/tests/good-file.txt | 733 + flate2/tests/gunzip.rs | 77 + flate2/tests/multi.gz | Bin 0 -> 53 bytes flate2/tests/multi.txt | 2 + flate2/tests/tokio.rs | 133 + flate2/tests/zero-write.rs | 8 + fnv/.cargo-checksum.json | 1 + fnv/Cargo.toml | 25 + fnv/LICENSE-APACHE | 201 + fnv/LICENSE-MIT | 25 + fnv/README.md | 81 + fnv/lib.rs | 349 + foreign-types-shared/.cargo-checksum.json | 1 + foreign-types-shared/Cargo.toml | 21 + foreign-types-shared/LICENSE-APACHE | 202 + foreign-types-shared/LICENSE-MIT | 19 + foreign-types-shared/src/lib.rs | 51 + foreign-types/.cargo-checksum.json | 1 + foreign-types/Cargo.toml | 22 + foreign-types/LICENSE-APACHE | 202 + foreign-types/LICENSE-MIT | 19 + foreign-types/README.md | 23 + foreign-types/src/lib.rs | 306 + fs2/.cargo-checksum.json | 1 + fs2/Cargo.toml | 33 + fs2/LICENSE-APACHE | 201 + fs2/LICENSE-MIT | 25 + fs2/README.md | 50 + fs2/src/lib.rs | 458 + fs2/src/unix.rs | 250 + fs2/src/windows.rs | 279 + fuchsia-cprng/.cargo-checksum.json | 1 + fuchsia-cprng/AUTHORS | 10 + fuchsia-cprng/Cargo.toml | 22 + fuchsia-cprng/LICENSE | 27 + fuchsia-cprng/PATENTS | 22 + fuchsia-cprng/src/lib.rs | 57 + fwdansi/.cargo-checksum.json | 1 + fwdansi/Cargo.toml | 36 + fwdansi/appveyor.yml | 20 + fwdansi/examples/run-rustc.rs | 17 + fwdansi/src/lib.rs | 235 + fwdansi/tests/tests.proptest-regressions | 11 + fwdansi/tests/tests.rs | 99 + git2-curl/.cargo-checksum.json | 1 + git2-curl/Cargo.toml | 48 + git2-curl/LICENSE-APACHE | 201 + git2-curl/LICENSE-MIT | 25 + git2-curl/src/lib.rs | 280 + git2-curl/tests/all.rs | 68 + git2/.cargo-checksum.json | 1 + git2/.pc/.quilt_patches | 1 + git2/.pc/.quilt_series | 1 + git2/.pc/.version | 1 + git2/.pc/applied-patches | 1 + git2/.pc/disable-vendor.patch/.timestamp | 0 git2/.pc/disable-vendor.patch/Cargo.toml | 76 + git2/Cargo.toml | 75 + git2/LICENSE-APACHE | 201 + git2/LICENSE-MIT | 25 + git2/README.md | 64 + git2/appveyor.yml | 19 + git2/debian/patches/disable-vendor.patch | 10 + git2/debian/patches/series | 1 + git2/examples/add.rs | 85 + git2/examples/blame.rs | 106 + git2/examples/cat-file.rs | 142 + git2/examples/clone.rs | 124 + git2/examples/diff.rs | 284 + git2/examples/fetch.rs | 128 + git2/examples/init.rs | 152 + git2/examples/log.rs | 263 + git2/examples/ls-remote.rs | 63 + git2/examples/rev-list.rs | 97 + git2/examples/rev-parse.rs | 70 + git2/examples/status.rs | 369 + git2/examples/tag.rs | 134 + git2/src/blame.rs | 315 + git2/src/blob.rs | 186 + git2/src/branch.rs | 162 + git2/src/buf.rs | 73 + git2/src/build.rs | 701 + git2/src/call.rs | 217 + git2/src/cert.rs | 97 + git2/src/commit.rs | 372 + git2/src/config.rs | 628 + git2/src/cred.rs | 577 + git2/src/describe.rs | 199 + git2/src/diff.rs | 1258 ++ git2/src/error.rs | 284 + git2/src/index.rs | 710 + git2/src/lib.rs | 1339 ++ git2/src/merge.rs | 182 + git2/src/message.rs | 52 + git2/src/note.rs | 130 + git2/src/object.rs | 234 + git2/src/odb.rs | 419 + git2/src/oid.rs | 214 + git2/src/oid_array.rs | 50 + git2/src/packbuilder.rs | 386 + git2/src/panic.rs | 55 + git2/src/patch.rs | 202 + git2/src/pathspec.rs | 301 + git2/src/proxy_options.rs | 56 + git2/src/rebase.rs | 354 + git2/src/reference.rs | 401 + git2/src/reflog.rs | 172 + git2/src/refspec.rs | 89 + git2/src/remote.rs | 753 + git2/src/remote_callbacks.rs | 391 + git2/src/repo.rs | 2599 +++ git2/src/revspec.rs | 26 + git2/src/revwalk.rs | 203 + git2/src/signature.rs | 175 + git2/src/stash.rs | 210 + git2/src/status.rs | 418 + git2/src/string_array.rs | 117 + git2/src/submodule.rs | 357 + git2/src/tag.rs | 191 + git2/src/test.rs | 61 + git2/src/time.rs | 100 + git2/src/transport.rs | 326 + git2/src/tree.rs | 532 + git2/src/treebuilder.rs | 199 + git2/src/util.rs | 152 + glob/.cargo-checksum.json | 1 + glob/Cargo.toml | 15 + glob/LICENSE-APACHE | 201 + glob/LICENSE-MIT | 25 + glob/README.md | 24 + glob/src/lib.rs | 1312 ++ glob/tests/glob-std.rs | 278 + globset/.cargo-checksum.json | 1 + globset/COPYING | 3 + globset/Cargo.toml | 48 + globset/LICENSE-MIT | 21 + globset/README.md | 122 + globset/UNLICENSE | 24 + globset/benches/bench.rs | 121 + globset/src/glob.rs | 1497 ++ globset/src/lib.rs | 871 + globset/src/pathutil.rs | 129 + hex/.cargo-checksum.json | 1 + hex/Cargo.toml | 23 + hex/Dockerfile | 1 + hex/LICENSE-APACHE | 202 + hex/LICENSE-MIT | 20 + hex/README.md | 17 + hex/src/lib.rs | 406 + home/.cargo-checksum.json | 1 + home/Cargo.toml | 26 + home/README.md | 24 + home/src/lib.rs | 297 + http/.cargo-checksum.json | 1 + http/CHANGELOG.md | 106 + http/Cargo.toml | 61 + http/LICENSE-APACHE | 201 + http/LICENSE-MIT | 25 + http/README.md | 80 + http/benches/header_map/basic.rs | 586 + http/benches/header_map/mod.rs | 10 + http/benches/header_map/vec_map.rs | 103 + http/benches/header_value.rs | 54 + http/benches/uri.rs | 33 + http/src/byte_str.rs | 61 + http/src/convert.rs | 64 + http/src/error.rs | 195 + http/src/extensions.rs | 195 + http/src/header/map.rs | 3321 ++++ http/src/header/mod.rs | 196 + http/src/header/name.rs | 2206 +++ http/src/header/value.rs | 797 + http/src/lib.rs | 206 + http/src/method.rs | 422 + http/src/request.rs | 1069 ++ http/src/response.rs | 787 + http/src/status.rs | 563 + http/src/uri/authority.rs | 615 + http/src/uri/builder.rs | 156 + http/src/uri/mod.rs | 1138 ++ http/src/uri/path.rs | 544 + http/src/uri/port.rs | 158 + http/src/uri/scheme.rs | 389 + http/src/uri/tests.rs | 484 + http/src/version.rs | 68 + http/tests/header_map.rs | 329 + http/tests/header_map_fuzz.rs | 365 + http/tests/status_code.rs | 67 + humantime/.cargo-checksum.json | 1 + humantime/Cargo.toml | 37 + humantime/LICENSE-APACHE | 202 + humantime/LICENSE-MIT | 26 + humantime/README.md | 67 + humantime/benches/datetime_format.rs | 58 + humantime/benches/datetime_parse.rs | 50 + humantime/bulk.yaml | 8 + humantime/src/date.rs | 530 + humantime/src/duration.rs | 411 + humantime/src/lib.rs | 30 + humantime/src/wrapper.rs | 107 + humantime/vagga.yaml | 92 + idna/.cargo-checksum.json | 1 + idna/Cargo.toml | 43 + idna/LICENSE-APACHE | 201 + idna/LICENSE-MIT | 25 + idna/src/IdnaMappingTable.txt | 8405 ++++++++ idna/src/lib.rs | 73 + idna/src/make_uts46_mapping_table.py | 192 + idna/src/punycode.rs | 213 + idna/src/uts46.rs | 433 + idna/src/uts46_mapping_table.rs | 16005 ++++++++++++++++ idna/tests/IdnaTest.txt | 7848 ++++++++ idna/tests/punycode.rs | 65 + idna/tests/punycode_tests.json | 120 + idna/tests/tests.rs | 21 + idna/tests/unit.rs | 40 + idna/tests/uts46.rs | 124 + ignore/.cargo-checksum.json | 1 + ignore/COPYING | 3 + ignore/Cargo.toml | 60 + ignore/LICENSE-MIT | 21 + ignore/README.md | 66 + ignore/UNLICENSE | 24 + ignore/examples/walk.rs | 84 + ignore/src/dir.rs | 993 + ignore/src/gitignore.rs | 787 + ignore/src/lib.rs | 444 + ignore/src/overrides.rs | 262 + ignore/src/pathutil.rs | 142 + ignore/src/types.rs | 811 + ignore/src/walk.rs | 2060 ++ ...atched_path_or_any_parents_tests.gitignore | 216 + ...gnore_matched_path_or_any_parents_tests.rs | 323 + im-rc/.cargo-checksum.json | 1 + im-rc/CHANGELOG.md | 308 + im-rc/CODE_OF_CONDUCT.md | 73 + im-rc/Cargo.toml | 80 + im-rc/LICENCE.md | 355 + im-rc/README.md | 26 + im-rc/build.rs | 27 + im-rc/proptest-regressions/hash/map.txt | 16 + im-rc/proptest-regressions/hash/set.txt | 7 + im-rc/proptest-regressions/ord/map | 20 + im-rc/proptest-regressions/ord/map.txt | 7 + im-rc/proptest-regressions/ser.txt | 10 + im-rc/proptest-regressions/sort.txt | 7 + im-rc/proptest-regressions/tests/vector.txt | 8 + im-rc/proptest-regressions/vector/mod.txt | 11 + im-rc/src/config.rs | 15 + im-rc/src/hash/map.rs | 2214 +++ im-rc/src/hash/mod.rs | 8 + im-rc/src/hash/set.rs | 1102 ++ im-rc/src/iter.rs | 122 + im-rc/src/lib.rs | 484 + im-rc/src/nodes/btree.rs | 1189 ++ im-rc/src/nodes/hamt.rs | 671 + im-rc/src/nodes/mod.rs | 19 + im-rc/src/nodes/rrb.rs | 1120 ++ im-rc/src/ord/map.rs | 2353 +++ im-rc/src/ord/mod.rs | 8 + im-rc/src/ord/set.rs | 1160 ++ im-rc/src/ser.rs | 297 + im-rc/src/sort.rs | 92 + im-rc/src/sync.rs | 69 + im-rc/src/test.rs | 86 + im-rc/src/tests/hashset.rs | 85 + im-rc/src/tests/mod.rs | 23 + im-rc/src/tests/ordset.rs | 85 + im-rc/src/tests/vector.rs | 219 + im-rc/src/util.rs | 89 + im-rc/src/vector/focus.rs | 936 + im-rc/src/vector/mod.rs | 2846 +++ iovec/.cargo-checksum.json | 1 + iovec/.pc/.quilt_patches | 1 + iovec/.pc/.quilt_series | 1 + iovec/.pc/.version | 1 + iovec/.pc/applied-patches | 1 + iovec/.pc/b90b433-backport.patch/.timestamp | 0 iovec/.pc/b90b433-backport.patch/Cargo.toml | 28 + .../b90b433-backport.patch/src/sys/windows.rs | 56 + iovec/CHANGELOG.md | 11 + iovec/Cargo.toml | 28 + iovec/LICENSE-APACHE | 201 + iovec/LICENSE-MIT | 25 + iovec/README.md | 35 + iovec/appveyor.yml | 16 + iovec/debian/patches/b90b433-backport.patch | 30 + iovec/debian/patches/series | 1 + iovec/src/lib.rs | 164 + iovec/src/sys/mod.rs | 26 + iovec/src/sys/unix.rs | 52 + iovec/src/sys/unknown.rs | 57 + iovec/src/sys/windows.rs | 57 + iovec/src/unix.rs | 68 + iovec/src/windows.rs | 0 itoa/.cargo-checksum.json | 1 + itoa/Cargo.toml | 30 + itoa/LICENSE-APACHE | 201 + itoa/LICENSE-MIT | 23 + itoa/README.md | 95 + itoa/benches/bench.rs | 83 + itoa/src/lib.rs | 342 + itoa/src/udiv128.rs | 61 + itoa/tests/test.rs | 50 + jobserver/.cargo-checksum.json | 1 + jobserver/.pc/.quilt_patches | 1 + jobserver/.pc/.quilt_series | 1 + jobserver/.pc/.version | 1 + jobserver/.pc/applied-patches | 1 + .../.pc/relax-dep-version.patch/.timestamp | 0 .../.pc/relax-dep-version.patch/Cargo.toml | 64 + jobserver/Cargo.toml | 64 + jobserver/LICENSE-APACHE | 201 + jobserver/LICENSE-MIT | 25 + jobserver/README.md | 41 + .../debian/patches/relax-dep-version.patch | 8 + jobserver/debian/patches/series | 1 + jobserver/src/lib.rs | 963 + jobserver/tests/client-of-myself.rs | 60 + jobserver/tests/client.rs | 200 + jobserver/tests/helper.rs | 44 + jobserver/tests/make-as-a-client.rs | 77 + jobserver/tests/server.rs | 145 + lazy_static/.cargo-checksum.json | 1 + lazy_static/Cargo.toml | 44 + lazy_static/LICENSE-APACHE | 201 + lazy_static/LICENSE-MIT | 25 + lazy_static/README.md | 79 + lazy_static/src/core_lazy.rs | 31 + lazy_static/src/inline_lazy.rs | 65 + lazy_static/src/lib.rs | 211 + lazy_static/tests/no_std.rs | 20 + lazy_static/tests/test.rs | 162 + lazycell/.cargo-checksum.json | 1 + lazycell/.pc/.quilt_patches | 1 + lazycell/.pc/.quilt_series | 1 + lazycell/.pc/.version | 1 + lazycell/.pc/applied-patches | 1 + lazycell/.pc/no-clippy.patch/.timestamp | 0 lazycell/.pc/no-clippy.patch/Cargo.toml | 30 + lazycell/CHANGELOG.md | 178 + lazycell/Cargo.toml | 23 + lazycell/LICENSE-APACHE | 201 + lazycell/LICENSE-MIT | 26 + lazycell/README.md | 72 + lazycell/debian/patches/no-clippy.patch | 11 + lazycell/debian/patches/series | 1 + lazycell/src/lib.rs | 649 + libc/.cargo-checksum.json | 1 + libc/CONTRIBUTING.md | 66 + libc/Cargo.toml | 42 + libc/LICENSE-APACHE | 201 + libc/LICENSE-MIT | 25 + libc/README.md | 103 + libc/build.rs | 65 + libc/rustfmt.toml | 3 + libc/src/cloudabi/aarch64.rs | 4 + libc/src/cloudabi/arm.rs | 4 + libc/src/cloudabi/mod.rs | 334 + libc/src/cloudabi/x86.rs | 4 + libc/src/cloudabi/x86_64.rs | 4 + libc/src/fuchsia/aarch64.rs | 336 + libc/src/fuchsia/align.rs | 142 + libc/src/fuchsia/mod.rs | 4275 +++++ libc/src/fuchsia/no_align.rs | 129 + libc/src/fuchsia/x86_64.rs | 491 + libc/src/hermit/aarch64.rs | 2 + libc/src/hermit/mod.rs | 83 + libc/src/hermit/x86_64.rs | 2 + libc/src/lib.rs | 119 + libc/src/macros.rs | 157 + libc/src/sgx.rs | 56 + libc/src/switch.rs | 59 + libc/src/unix/align.rs | 6 + libc/src/unix/bsd/apple/b32.rs | 97 + libc/src/unix/bsd/apple/b64.rs | 102 + libc/src/unix/bsd/apple/mod.rs | 3294 ++++ .../src/unix/bsd/freebsdlike/dragonfly/mod.rs | 1030 + .../unix/bsd/freebsdlike/freebsd/aarch64.rs | 44 + libc/src/unix/bsd/freebsdlike/freebsd/arm.rs | 47 + libc/src/unix/bsd/freebsdlike/freebsd/mod.rs | 1473 ++ .../unix/bsd/freebsdlike/freebsd/powerpc64.rs | 44 + libc/src/unix/bsd/freebsdlike/freebsd/x86.rs | 43 + .../unix/bsd/freebsdlike/freebsd/x86_64.rs | 43 + libc/src/unix/bsd/freebsdlike/mod.rs | 1315 ++ libc/src/unix/bsd/mod.rs | 675 + libc/src/unix/bsd/netbsdlike/mod.rs | 685 + .../src/unix/bsd/netbsdlike/netbsd/aarch64.rs | 22 + libc/src/unix/bsd/netbsdlike/netbsd/arm.rs | 22 + libc/src/unix/bsd/netbsdlike/netbsd/mod.rs | 1630 ++ .../src/unix/bsd/netbsdlike/netbsd/powerpc.rs | 21 + .../src/unix/bsd/netbsdlike/netbsd/sparc64.rs | 8 + libc/src/unix/bsd/netbsdlike/netbsd/x86.rs | 15 + libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs | 23 + .../unix/bsd/netbsdlike/openbsdlike/mod.rs | 945 + .../netbsdlike/openbsdlike/openbsd/aarch64.rs | 14 + .../bsd/netbsdlike/openbsdlike/openbsd/mod.rs | 497 + .../bsd/netbsdlike/openbsdlike/openbsd/x86.rs | 14 + .../netbsdlike/openbsdlike/openbsd/x86_64.rs | 22 + libc/src/unix/haiku/b32.rs | 3 + libc/src/unix/haiku/b64.rs | 3 + libc/src/unix/haiku/mod.rs | 1384 ++ libc/src/unix/hermit/aarch64.rs | 2 + libc/src/unix/hermit/mod.rs | 1017 + libc/src/unix/hermit/x86_64.rs | 2 + libc/src/unix/mod.rs | 1220 ++ libc/src/unix/newlib/aarch64/mod.rs | 5 + libc/src/unix/newlib/align.rs | 61 + libc/src/unix/newlib/arm/mod.rs | 5 + libc/src/unix/newlib/mod.rs | 707 + libc/src/unix/newlib/no_align.rs | 51 + libc/src/unix/no_align.rs | 6 + libc/src/unix/notbsd/android/b32/arm.rs | 357 + libc/src/unix/notbsd/android/b32/mod.rs | 214 + libc/src/unix/notbsd/android/b32/x86.rs | 415 + libc/src/unix/notbsd/android/b64/aarch64.rs | 325 + libc/src/unix/notbsd/android/b64/mod.rs | 272 + libc/src/unix/notbsd/android/b64/x86_64.rs | 420 + libc/src/unix/notbsd/android/mod.rs | 2143 +++ libc/src/unix/notbsd/emscripten/align.rs | 66 + libc/src/unix/notbsd/emscripten/mod.rs | 1802 ++ libc/src/unix/notbsd/emscripten/no_align.rs | 63 + libc/src/unix/notbsd/linux/align.rs | 98 + libc/src/unix/notbsd/linux/mips/align.rs | 13 + libc/src/unix/notbsd/linux/mips/mips32.rs | 695 + libc/src/unix/notbsd/linux/mips/mips64.rs | 645 + libc/src/unix/notbsd/linux/mips/mod.rs | 960 + libc/src/unix/notbsd/linux/mips/no_align.rs | 10 + libc/src/unix/notbsd/linux/mod.rs | 2489 +++ libc/src/unix/notbsd/linux/musl/b32/arm.rs | 843 + libc/src/unix/notbsd/linux/musl/b32/mips.rs | 853 + libc/src/unix/notbsd/linux/musl/b32/mod.rs | 62 + .../src/unix/notbsd/linux/musl/b32/powerpc.rs | 869 + libc/src/unix/notbsd/linux/musl/b32/x86.rs | 951 + .../src/unix/notbsd/linux/musl/b64/aarch64.rs | 479 + libc/src/unix/notbsd/linux/musl/b64/mod.rs | 339 + .../unix/notbsd/linux/musl/b64/powerpc64.rs | 575 + libc/src/unix/notbsd/linux/musl/b64/x86_64.rs | 634 + libc/src/unix/notbsd/linux/musl/mod.rs | 350 + libc/src/unix/notbsd/linux/no_align.rs | 80 + libc/src/unix/notbsd/linux/other/align.rs | 13 + libc/src/unix/notbsd/linux/other/b32/arm.rs | 609 + libc/src/unix/notbsd/linux/other/b32/mod.rs | 388 + .../unix/notbsd/linux/other/b32/powerpc.rs | 614 + libc/src/unix/notbsd/linux/other/b32/x86.rs | 892 + .../unix/notbsd/linux/other/b64/aarch64.rs | 830 + libc/src/unix/notbsd/linux/other/b64/mod.rs | 85 + .../unix/notbsd/linux/other/b64/not_x32.rs | 421 + .../unix/notbsd/linux/other/b64/powerpc64.rs | 930 + .../unix/notbsd/linux/other/b64/sparc64.rs | 868 + libc/src/unix/notbsd/linux/other/b64/x32.rs | 374 + .../src/unix/notbsd/linux/other/b64/x86_64.rs | 781 + libc/src/unix/notbsd/linux/other/mod.rs | 997 + libc/src/unix/notbsd/linux/other/no_align.rs | 10 + libc/src/unix/notbsd/linux/s390x/align.rs | 10 + libc/src/unix/notbsd/linux/s390x/mod.rs | 1360 ++ libc/src/unix/notbsd/linux/s390x/no_align.rs | 7 + libc/src/unix/notbsd/mod.rs | 1429 ++ libc/src/unix/redox/mod.rs | 588 + libc/src/unix/solarish/compat.rs | 21 + libc/src/unix/solarish/mod.rs | 2031 ++ libc/src/unix/uclibc/align.rs | 66 + libc/src/unix/uclibc/arm/align.rs | 13 + libc/src/unix/uclibc/arm/mod.rs | 687 + libc/src/unix/uclibc/arm/no_align.rs | 10 + libc/src/unix/uclibc/mips/mips32/align.rs | 13 + libc/src/unix/uclibc/mips/mips32/mod.rs | 627 + libc/src/unix/uclibc/mips/mips32/no_align.rs | 10 + libc/src/unix/uclibc/mips/mips64/align.rs | 10 + libc/src/unix/uclibc/mips/mips64/mod.rs | 213 + libc/src/unix/uclibc/mips/mips64/no_align.rs | 8 + libc/src/unix/uclibc/mips/mod.rs | 478 + libc/src/unix/uclibc/mod.rs | 1926 ++ libc/src/unix/uclibc/no_align.rs | 53 + libc/src/unix/uclibc/x86_64/align.rs | 77 + libc/src/unix/uclibc/x86_64/l4re.rs | 48 + libc/src/unix/uclibc/x86_64/mod.rs | 312 + libc/src/unix/uclibc/x86_64/no_align.rs | 59 + libc/src/unix/uclibc/x86_64/other.rs | 5 + libc/src/wasi.rs | 1336 ++ libc/src/windows/gnu.rs | 13 + libc/src/windows/mod.rs | 466 + libc/src/windows/msvc.rs | 10 + libgit2-sys/.cargo-checksum.json | 1 + libgit2-sys/.pc/.quilt_patches | 1 + libgit2-sys/.pc/.quilt_series | 1 + libgit2-sys/.pc/.version | 1 + libgit2-sys/.pc/applied-patches | 1 + .../no-special-snowflake-env.patch/.timestamp | 0 .../no-special-snowflake-env.patch/build.rs | 194 + libgit2-sys/Cargo.toml | 53 + libgit2-sys/LICENSE-APACHE | 201 + libgit2-sys/LICENSE-MIT | 25 + libgit2-sys/build.rs | 192 + .../patches/no-special-snowflake-env.patch | 17 + libgit2-sys/debian/patches/series | 1 + libgit2-sys/lib.rs | 3052 +++ libnghttp2-sys/.cargo-checksum.json | 1 + libnghttp2-sys/.pc/.quilt_patches | 1 + libnghttp2-sys/.pc/.quilt_series | 1 + libnghttp2-sys/.pc/.version | 1 + libnghttp2-sys/.pc/applied-patches | 1 + .../.pc/use-system-lib.patch/.timestamp | 0 .../.pc/use-system-lib.patch/Cargo.toml | 29 + libnghttp2-sys/Cargo.toml | 29 + libnghttp2-sys/LICENSE-APACHE | 201 + libnghttp2-sys/LICENSE-MIT | 25 + libnghttp2-sys/README.md | 52 + libnghttp2-sys/build.rs | 7 + libnghttp2-sys/build.rs.orig | 83 + libnghttp2-sys/debian/patches/series | 1 + .../debian/patches/use-system-lib.patch | 10 + libnghttp2-sys/examples/smoke.rs | 7 + libnghttp2-sys/src/lib.rs | 4820 +++++ libssh2-sys/.cargo-checksum.json | 1 + libssh2-sys/.pc/.quilt_patches | 1 + libssh2-sys/.pc/.quilt_series | 1 + libssh2-sys/.pc/.version | 1 + libssh2-sys/.pc/applied-patches | 1 + .../no-special-snowflake-env.patch/.timestamp | 0 .../no-special-snowflake-env.patch/build.rs | 180 + libssh2-sys/Cargo.toml | 39 + libssh2-sys/build.rs | 181 + .../patches/no-special-snowflake-env.patch | 41 + libssh2-sys/debian/patches/series | 1 + libssh2-sys/lib.rs | 600 + libz-sys/.cargo-checksum.json | 1 + libz-sys/Cargo.toml | 36 + libz-sys/LICENSE-APACHE | 201 + libz-sys/LICENSE-MIT | 25 + libz-sys/README.md | 25 + libz-sys/appveyor.yml | 30 + libz-sys/build.rs | 194 + libz-sys/ci/Dockerfile | 7 + libz-sys/ci/run-docker.sh | 18 + libz-sys/src/lib.rs | 231 + libz-sys/src/smoke.c | 5 + log/.cargo-checksum.json | 1 + log/CHANGELOG.md | 123 + log/Cargo.toml | 59 + log/LICENSE-APACHE | 201 + log/LICENSE-MIT | 25 + log/README.md | 88 + log/appveyor.yml | 19 + log/src/lib.rs | 1469 ++ log/src/macros.rs | 253 + log/src/serde.rs | 327 + log/tests/filters.rs | 66 + matches/.cargo-checksum.json | 1 + matches/Cargo.toml | 24 + matches/LICENSE | 25 + matches/lib.rs | 126 + matches/tests/macro_use_one.rs | 11 + memchr/.cargo-checksum.json | 1 + memchr/COPYING | 3 + memchr/Cargo.toml | 46 + memchr/LICENSE-MIT | 21 + memchr/README.md | 50 + memchr/UNLICENSE | 24 + memchr/build.rs | 134 + memchr/src/c.rs | 44 + memchr/src/fallback.rs | 346 + memchr/src/iter.rs | 177 + memchr/src/lib.rs | 312 + memchr/src/naive.rs | 37 + memchr/src/tests/iter.rs | 228 + memchr/src/tests/memchr.rs | 131 + memchr/src/tests/mod.rs | 422 + memchr/src/x86/avx.rs | 739 + memchr/src/x86/mod.rs | 105 + memchr/src/x86/sse2.rs | 827 + memchr/src/x86/sse42.rs | 75 + miow/.cargo-checksum.json | 1 + miow/Cargo.toml | 31 + miow/LICENSE-APACHE | 201 + miow/LICENSE-MIT | 25 + miow/README.md | 31 + miow/appveyor.yml | 20 + miow/src/handle.rs | 164 + miow/src/iocp.rs | 324 + miow/src/lib.rs | 57 + miow/src/net.rs | 1140 ++ miow/src/overlapped.rs | 95 + miow/src/pipe.rs | 716 + num-integer/.cargo-checksum.json | 1 + num-integer/Cargo.toml | 38 + num-integer/LICENSE-APACHE | 201 + num-integer/LICENSE-MIT | 25 + num-integer/README.md | 50 + num-integer/RELEASES.md | 71 + num-integer/benches/gcd.rs | 176 + num-integer/benches/roots.rs | 170 + num-integer/build.rs | 14 + num-integer/src/lib.rs | 1340 ++ num-integer/src/roots.rs | 391 + num-integer/tests/roots.rs | 272 + num-traits/.cargo-checksum.json | 1 + num-traits/Cargo.toml | 37 + num-traits/LICENSE-APACHE | 201 + num-traits/LICENSE-MIT | 25 + num-traits/README.md | 51 + num-traits/RELEASES.md | 154 + num-traits/build.rs | 14 + num-traits/src/bounds.rs | 127 + num-traits/src/cast.rs | 762 + num-traits/src/float.rs | 2024 ++ num-traits/src/identities.rs | 207 + num-traits/src/int.rs | 409 + num-traits/src/lib.rs | 473 + num-traits/src/macros.rs | 37 + num-traits/src/ops/checked.rs | 277 + num-traits/src/ops/inv.rs | 47 + num-traits/src/ops/mod.rs | 5 + num-traits/src/ops/mul_add.rs | 151 + num-traits/src/ops/saturating.rs | 30 + num-traits/src/ops/wrapping.rs | 272 + num-traits/src/pow.rs | 261 + num-traits/src/real.rs | 832 + num-traits/src/sign.rs | 225 + num-traits/tests/cast.rs | 396 + num_cpus/.cargo-checksum.json | 1 + num_cpus/CHANGELOG.md | 95 + num_cpus/CONTRIBUTING.md | 16 + num_cpus/Cargo.toml | 25 + num_cpus/LICENSE-APACHE | 201 + num_cpus/LICENSE-MIT | 20 + num_cpus/README.md | 28 + num_cpus/src/lib.rs | 425 + numtoa/.cargo-checksum.json | 1 + numtoa/Cargo.toml | 26 + numtoa/LICENSE-APACHE | 202 + numtoa/LICENSE-MIT | 21 + numtoa/README.md | 65 + numtoa/src/lib.rs | 540 + opener/.cargo-checksum.json | 1 + opener/.pc/.quilt_patches | 1 + opener/.pc/.quilt_series | 1 + opener/.pc/.version | 1 + opener/.pc/applied-patches | 1 + opener/.pc/disable-vendor.patch/.timestamp | 0 opener/.pc/disable-vendor.patch/src/lib.rs | 212 + opener/Cargo.toml | 37 + opener/LICENSE-APACHE | 199 + opener/LICENSE-MIT | 19 + opener/LICENSE-THIRD-PARTY | 19 + opener/debian/patches/disable-vendor.patch | 30 + opener/debian/patches/series | 1 + opener/src/lib.rs | 210 + openssl-probe/.cargo-checksum.json | 1 + openssl-probe/Cargo.toml | 21 + openssl-probe/LICENSE-APACHE | 201 + openssl-probe/LICENSE-MIT | 25 + openssl-probe/README.md | 33 + openssl-probe/src/lib.rs | 83 + openssl-sys/.cargo-checksum.json | 1 + openssl-sys/.pc/.quilt_patches | 1 + openssl-sys/.pc/.quilt_series | 1 + openssl-sys/.pc/.version | 1 + openssl-sys/.pc/applied-patches | 1 + .../.pc/disable-vendor.patch/.timestamp | 0 .../.pc/disable-vendor.patch/Cargo.toml | 44 + openssl-sys/CHANGELOG.md | 48 + openssl-sys/Cargo.toml | 41 + openssl-sys/LICENSE-MIT | 25 + openssl-sys/README.md | 24 + openssl-sys/build/cfgs.rs | 64 + openssl-sys/build/expando.c | 67 + openssl-sys/build/find_normal.rs | 251 + openssl-sys/build/find_vendored.rs | 11 + openssl-sys/build/main.rs | 312 + .../debian/patches/disable-vendor.patch | 18 + openssl-sys/debian/patches/series | 1 + openssl-sys/src/aes.rs | 28 + openssl-sys/src/asn1.rs | 66 + openssl-sys/src/bio.rs | 151 + openssl-sys/src/bn.rs | 160 + openssl-sys/src/cms.rs | 91 + openssl-sys/src/conf.rs | 7 + openssl-sys/src/crypto.rs | 128 + openssl-sys/src/dh.rs | 19 + openssl-sys/src/dsa.rs | 58 + openssl-sys/src/dtls1.rs | 3 + openssl-sys/src/ec.rs | 213 + openssl-sys/src/err.rs | 58 + openssl-sys/src/evp.rs | 367 + openssl-sys/src/hmac.rs | 30 + openssl-sys/src/lib.rs | 170 + openssl-sys/src/macros.rs | 87 + openssl-sys/src/obj_mac.rs | 914 + openssl-sys/src/object.rs | 18 + openssl-sys/src/ocsp.rs | 118 + openssl-sys/src/ossl_typ.rs | 991 + openssl-sys/src/pem.rs | 151 + openssl-sys/src/pkcs12.rs | 56 + openssl-sys/src/pkcs7.rs | 74 + openssl-sys/src/rand.rs | 10 + openssl-sys/src/rsa.rs | 179 + openssl-sys/src/safestack.rs | 1 + openssl-sys/src/sha.rs | 70 + openssl-sys/src/srtp.rs | 18 + openssl-sys/src/ssl.rs | 1345 ++ openssl-sys/src/ssl3.rs | 5 + openssl-sys/src/stack.rs | 45 + openssl-sys/src/tls1.rs | 111 + openssl-sys/src/x509.rs | 349 + openssl-sys/src/x509_vfy.rs | 153 + openssl-sys/src/x509v3.rs | 93 + openssl/.cargo-checksum.json | 1 + openssl/.pc/.quilt_patches | 1 + openssl/.pc/.quilt_series | 1 + openssl/.pc/.version | 1 + openssl/.pc/applied-patches | 1 + openssl/.pc/disable-vendor.patch/.timestamp | 0 openssl/.pc/disable-vendor.patch/Cargo.toml | 51 + openssl/CHANGELOG.md | 397 + openssl/Cargo.toml | 51 + openssl/LICENSE | 15 + openssl/README.md | 24 + openssl/build.rs | 65 + openssl/debian/patches/disable-vendor.patch | 8 + openssl/debian/patches/series | 1 + openssl/examples/mk_certs.rs | 160 + openssl/src/aes.rs | 169 + openssl/src/asn1.rs | 394 + openssl/src/bio.rs | 84 + openssl/src/bn.rs | 1424 ++ openssl/src/cms.rs | 239 + openssl/src/conf.rs | 52 + openssl/src/derive.rs | 124 + openssl/src/dh.rs | 188 + openssl/src/dsa.rs | 438 + openssl/src/ec.rs | 952 + openssl/src/ecdsa.rs | 238 + openssl/src/envelope.rs | 282 + openssl/src/error.rs | 292 + openssl/src/ex_data.rs | 26 + openssl/src/fips.rs | 22 + openssl/src/hash.rs | 603 + openssl/src/lib.rs | 199 + openssl/src/macros.rs | 269 + openssl/src/memcmp.rs | 92 + openssl/src/nid.rs | 1120 ++ openssl/src/ocsp.rs | 351 + openssl/src/pkcs12.rs | 289 + openssl/src/pkcs5.rs | 304 + openssl/src/pkcs7.rs | 389 + openssl/src/pkey.rs | 663 + openssl/src/rand.rs | 66 + openssl/src/rsa.rs | 944 + openssl/src/sha.rs | 390 + openssl/src/sign.rs | 732 + openssl/src/srtp.rs | 57 + openssl/src/ssl/bio.rs | 275 + openssl/src/ssl/callbacks.rs | 686 + openssl/src/ssl/connector.rs | 507 + openssl/src/ssl/error.rs | 191 + openssl/src/ssl/mod.rs | 3895 ++++ openssl/src/ssl/test/mod.rs | 1413 ++ openssl/src/ssl/test/server.rs | 167 + openssl/src/stack.rs | 369 + openssl/src/string.rs | 95 + openssl/src/symm.rs | 1310 ++ openssl/src/util.rs | 67 + openssl/src/version.rs | 131 + openssl/src/x509/extension.rs | 520 + openssl/src/x509/mod.rs | 1398 ++ openssl/src/x509/store.rs | 106 + openssl/src/x509/tests.rs | 366 + openssl/src/x509/verify.rs | 90 + openssl/test/alt_name_cert.pem | 22 + openssl/test/cert.pem | 19 + openssl/test/certs.pem | 40 + openssl/test/cms.p12 | Bin 0 -> 1709 bytes openssl/test/cms_pubkey.der | Bin 0 -> 688 bytes openssl/test/dhparams.pem | 8 + openssl/test/dsa.pem | 12 + openssl/test/dsa.pem.pub | 12 + openssl/test/dsaparam.pem | 9 + openssl/test/identity.p12 | Bin 0 -> 3386 bytes openssl/test/key.der | Bin 0 -> 1193 bytes openssl/test/key.der.pub | Bin 0 -> 294 bytes openssl/test/key.pem | 28 + openssl/test/key.pem.pub | 9 + openssl/test/keystore-empty-chain.p12 | Bin 0 -> 2514 bytes openssl/test/nid_test_cert.pem | 12 + openssl/test/nid_uid_test_cert.pem | 24 + openssl/test/pkcs1.pem.pub | 8 + openssl/test/pkcs8.der | Bin 0 -> 1298 bytes openssl/test/root-ca.key | 27 + openssl/test/root-ca.pem | 21 + openssl/test/rsa-encrypted.pem | 30 + openssl/test/rsa.pem | 27 + openssl/test/rsa.pem.pub | 9 + percent-encoding/.cargo-checksum.json | 1 + percent-encoding/Cargo.toml | 24 + percent-encoding/LICENSE-APACHE | 201 + percent-encoding/LICENSE-MIT | 25 + percent-encoding/lib.rs | 442 + pkg-config/.cargo-checksum.json | 1 + pkg-config/.pc/.quilt_patches | 1 + pkg-config/.pc/.quilt_series | 1 + pkg-config/.pc/.version | 1 + pkg-config/.pc/applied-patches | 1 + .../no-special-snowflake-env.patch/.timestamp | 0 .../no-special-snowflake-env.patch/src/lib.rs | 630 + .../tests/test.rs | 118 + pkg-config/CHANGELOG.md | 19 + pkg-config/Cargo.toml | 25 + pkg-config/LICENSE-APACHE | 201 + pkg-config/LICENSE-MIT | 25 + pkg-config/README.md | 73 + .../patches/no-special-snowflake-env.patch | 98 + pkg-config/debian/patches/series | 1 + pkg-config/src/lib.rs | 623 + pkg-config/tests/escape.pc | 5 + pkg-config/tests/foo.pc | 16 + pkg-config/tests/framework.pc | 16 + pkg-config/tests/test.rs | 116 + pretty_env_logger/.cargo-checksum.json | 1 + pretty_env_logger/Cargo.toml | 31 + pretty_env_logger/LICENSE-APACHE | 201 + pretty_env_logger/LICENSE-MIT | 20 + pretty_env_logger/src/lib.rs | 217 + proc-macro2/.cargo-checksum.json | 1 + proc-macro2/Cargo.toml | 39 + proc-macro2/LICENSE-APACHE | 201 + proc-macro2/LICENSE-MIT | 25 + proc-macro2/README.md | 100 + proc-macro2/build.rs | 157 + proc-macro2/src/fallback.rs | 1435 ++ proc-macro2/src/lib.rs | 1156 ++ proc-macro2/src/strnom.rs | 393 + proc-macro2/src/wrapper.rs | 928 + proc-macro2/tests/marker.rs | 61 + proc-macro2/tests/test.rs | 452 + proptest/.cargo-checksum.json | 1 + proptest/CHANGELOG.md | 638 + proptest/Cargo.toml | 81 + proptest/LICENSE-APACHE | 201 + proptest/LICENSE-MIT | 25 + proptest/README.md | 527 + proptest/appveyor.yml | 18 + proptest/examples/config-defaults.rs | 16 + proptest/examples/dateparser_v1.rs | 49 + proptest/examples/dateparser_v2.rs | 67 + proptest/examples/fib.rs | 53 + proptest/examples/tutorial-simplify-play.rs | 29 + proptest/examples/tutorial-strategy-play.rs | 31 + proptest/gen-readme.sh | 8 + .../arbitrary/_std/env.txt | 7 + proptest/readme-antelogue.md | 13 + proptest/readme-prologue.md | 6 + proptest/src/arbitrary/_alloc/alloc.rs | 56 + proptest/src/arbitrary/_alloc/borrow.rs | 27 + proptest/src/arbitrary/_alloc/boxed.rs | 19 + proptest/src/arbitrary/_alloc/char.rs | 84 + proptest/src/arbitrary/_alloc/collections.rs | 290 + proptest/src/arbitrary/_alloc/hash.rs | 32 + proptest/src/arbitrary/_alloc/mod.rs | 22 + proptest/src/arbitrary/_alloc/ops.rs | 100 + proptest/src/arbitrary/_alloc/rc.rs | 21 + proptest/src/arbitrary/_alloc/str.rs | 49 + proptest/src/arbitrary/_alloc/sync.rs | 69 + proptest/src/arbitrary/_core/ascii.rs | 23 + proptest/src/arbitrary/_core/cell.rs | 48 + proptest/src/arbitrary/_core/cmp.rs | 33 + proptest/src/arbitrary/_core/convert.rs | 16 + proptest/src/arbitrary/_core/fmt.rs | 18 + proptest/src/arbitrary/_core/iter.rs | 177 + proptest/src/arbitrary/_core/marker.rs | 19 + proptest/src/arbitrary/_core/mem.rs | 42 + proptest/src/arbitrary/_core/mod.rs | 22 + proptest/src/arbitrary/_core/num.rs | 55 + proptest/src/arbitrary/_core/option.rs | 60 + proptest/src/arbitrary/_core/result.rs | 106 + proptest/src/arbitrary/_std/env.rs | 134 + proptest/src/arbitrary/_std/ffi.rs | 100 + proptest/src/arbitrary/_std/fs.rs | 30 + proptest/src/arbitrary/_std/io.rs | 164 + proptest/src/arbitrary/_std/mod.rs | 22 + proptest/src/arbitrary/_std/net.rs | 116 + proptest/src/arbitrary/_std/panic.rs | 19 + proptest/src/arbitrary/_std/path.rs | 23 + proptest/src/arbitrary/_std/string.rs | 296 + proptest/src/arbitrary/_std/sync.rs | 168 + proptest/src/arbitrary/_std/thread.rs | 81 + proptest/src/arbitrary/_std/time.rs | 50 + proptest/src/arbitrary/arrays.rs | 36 + proptest/src/arbitrary/functor.rs | 212 + proptest/src/arbitrary/macros.rs | 115 + proptest/src/arbitrary/mod.rs | 63 + proptest/src/arbitrary/primitives.rs | 44 + proptest/src/arbitrary/sample.rs | 31 + proptest/src/arbitrary/traits.rs | 297 + proptest/src/arbitrary/tuples.rs | 45 + proptest/src/array.rs | 292 + proptest/src/bits.rs | 654 + proptest/src/bool.rs | 136 + proptest/src/char.rs | 381 + proptest/src/collection.rs | 731 + proptest/src/file-preamble | 8 + proptest/src/lib.rs | 1756 ++ proptest/src/macros.rs | 93 + proptest/src/num.rs | 1313 ++ proptest/src/option.rs | 234 + proptest/src/prelude.rs | 49 + proptest/src/product_frunk.rs | 49 + proptest/src/product_tuple.rs | 49 + proptest/src/regex-contrib/README.md | 3 + proptest/src/regex-contrib/crates_regex.rs | 3129 +++ proptest/src/result.rs | 262 + proptest/src/sample.rs | 551 + proptest/src/std_facade.rs | 74 + proptest/src/strategy/filter.rs | 144 + proptest/src/strategy/filter_map.rs | 189 + proptest/src/strategy/flatten.rs | 326 + proptest/src/strategy/fuse.rs | 228 + proptest/src/strategy/just.rs | 130 + proptest/src/strategy/map.rs | 290 + proptest/src/strategy/mod.rs | 34 + proptest/src/strategy/recursive.rs | 200 + proptest/src/strategy/shuffle.rs | 271 + proptest/src/strategy/statics.rs | 253 + proptest/src/strategy/traits.rs | 924 + proptest/src/strategy/unions.rs | 511 + proptest/src/string.rs | 459 + proptest/src/sugar.rs | 1498 ++ proptest/src/test_runner/config.rs | 407 + proptest/src/test_runner/errors.rs | 109 + .../test_runner/failure_persistence/file.rs | 554 + .../test_runner/failure_persistence/map.rs | 91 + .../test_runner/failure_persistence/mod.rs | 71 + .../test_runner/failure_persistence/noop.rs | 64 + proptest/src/test_runner/mod.rs | 31 + proptest/src/test_runner/reason.rs | 54 + proptest/src/test_runner/replay.rs | 188 + proptest/src/test_runner/result_cache.rs | 115 + proptest/src/test_runner/rng.rs | 87 + proptest/src/test_runner/runner.rs | 1197 ++ proptest/src/tuple.rs | 148 + proptest/test-persistence-location/README.md | 6 + .../test-persistence-location/run-tests.bat | 23 + .../test-persistence-location/run-tests.sh | 28 + quick-error/.cargo-checksum.json | 1 + quick-error/Cargo.toml | 23 + quick-error/LICENSE-APACHE | 202 + quick-error/LICENSE-MIT | 19 + quick-error/README.rst | 69 + quick-error/bulk.yaml | 8 + quick-error/examples/context.rs | 48 + quick-error/src/lib.rs | 1309 ++ quick-error/vagga.yaml | 36 + quote/.cargo-checksum.json | 1 + quote/Cargo.toml | 33 + quote/LICENSE-APACHE | 201 + quote/LICENSE-MIT | 25 + quote/README.md | 241 + quote/src/ext.rs | 112 + quote/src/lib.rs | 861 + quote/src/runtime.rs | 119 + quote/src/to_tokens.rs | 205 + quote/tests/conditional/integer128.rs | 11 + quote/tests/test.rs | 295 + rand-0.5.6/.cargo-checksum.json | 1 + rand-0.5.6/CHANGELOG.md | 422 + rand-0.5.6/CONTRIBUTING.md | 93 + rand-0.5.6/Cargo.toml | 72 + rand-0.5.6/LICENSE-APACHE | 201 + rand-0.5.6/LICENSE-MIT | 25 + rand-0.5.6/README.md | 143 + rand-0.5.6/UPDATING.md | 260 + rand-0.5.6/appveyor.yml | 39 + rand-0.5.6/benches/distributions.rs | 161 + rand-0.5.6/benches/generators.rs | 176 + rand-0.5.6/benches/misc.rs | 194 + rand-0.5.6/examples/monte-carlo.rs | 52 + rand-0.5.6/examples/monty-hall.rs | 117 + rand-0.5.6/src/distributions/bernoulli.rs | 120 + rand-0.5.6/src/distributions/binomial.rs | 178 + rand-0.5.6/src/distributions/cauchy.rs | 116 + rand-0.5.6/src/distributions/exponential.rs | 122 + rand-0.5.6/src/distributions/float.rs | 206 + rand-0.5.6/src/distributions/gamma.rs | 360 + rand-0.5.6/src/distributions/integer.rs | 113 + rand-0.5.6/src/distributions/log_gamma.rs | 51 + rand-0.5.6/src/distributions/mod.rs | 784 + rand-0.5.6/src/distributions/normal.rs | 192 + rand-0.5.6/src/distributions/other.rs | 215 + rand-0.5.6/src/distributions/pareto.rs | 76 + rand-0.5.6/src/distributions/poisson.rs | 158 + rand-0.5.6/src/distributions/uniform.rs | 856 + .../src/distributions/ziggurat_tables.rs | 280 + rand-0.5.6/src/lib.rs | 1238 ++ rand-0.5.6/src/prelude.rs | 28 + rand-0.5.6/src/prng/chacha.rs | 477 + rand-0.5.6/src/prng/hc128.rs | 464 + rand-0.5.6/src/prng/isaac.rs | 494 + rand-0.5.6/src/prng/isaac64.rs | 491 + rand-0.5.6/src/prng/isaac_array.rs | 137 + rand-0.5.6/src/prng/mod.rs | 330 + rand-0.5.6/src/prng/xorshift.rs | 225 + rand-0.5.6/src/rngs/adapter/mod.rs | 17 + rand-0.5.6/src/rngs/adapter/read.rs | 137 + rand-0.5.6/src/rngs/adapter/reseeding.rs | 260 + rand-0.5.6/src/rngs/entropy.rs | 296 + rand-0.5.6/src/rngs/jitter.rs | 887 + rand-0.5.6/src/rngs/mock.rs | 61 + rand-0.5.6/src/rngs/mod.rs | 218 + rand-0.5.6/src/rngs/os.rs | 1171 ++ rand-0.5.6/src/rngs/small.rs | 101 + rand-0.5.6/src/rngs/std.rs | 83 + rand-0.5.6/src/rngs/thread.rs | 141 + rand-0.5.6/src/seq.rs | 334 + rand-0.5.6/tests/bool.rs | 23 + rand-0.5.6/utils/ci/install.sh | 49 + rand-0.5.6/utils/ci/script.sh | 29 + rand-0.5.6/utils/ziggurat_tables.py | 127 + rand/.cargo-checksum.json | 1 + rand/CHANGELOG.md | 522 + rand/COPYRIGHT | 12 + rand/Cargo.toml | 90 + rand/LICENSE-APACHE | 201 + rand/LICENSE-MIT | 26 + rand/README.md | 122 + rand/benches/distributions.rs | 259 + rand/benches/generators.rs | 240 + rand/benches/misc.rs | 160 + rand/benches/seq.rs | 174 + rand/build.rs | 10 + rand/examples/monte-carlo.rs | 51 + rand/examples/monty-hall.rs | 116 + rand/src/deprecated.rs | 544 + rand/src/distributions/bernoulli.rs | 165 + rand/src/distributions/binomial.rs | 177 + rand/src/distributions/cauchy.rs | 115 + rand/src/distributions/dirichlet.rs | 137 + rand/src/distributions/exponential.rs | 124 + rand/src/distributions/float.rs | 259 + rand/src/distributions/gamma.rs | 413 + rand/src/distributions/integer.rs | 161 + rand/src/distributions/mod.rs | 608 + rand/src/distributions/normal.rs | 197 + rand/src/distributions/other.rs | 219 + rand/src/distributions/pareto.rs | 74 + rand/src/distributions/poisson.rs | 157 + rand/src/distributions/triangular.rs | 86 + rand/src/distributions/uniform.rs | 1283 ++ rand/src/distributions/unit_circle.rs | 101 + rand/src/distributions/unit_sphere.rs | 99 + rand/src/distributions/utils.rs | 504 + rand/src/distributions/weibull.rs | 71 + rand/src/distributions/weighted.rs | 230 + rand/src/distributions/ziggurat_tables.rs | 279 + rand/src/lib.rs | 830 + rand/src/prelude.rs | 27 + rand/src/prng/mod.rs | 37 + rand/src/rngs/adapter/mod.rs | 15 + rand/src/rngs/adapter/read.rs | 136 + rand/src/rngs/adapter/reseeding.rs | 370 + rand/src/rngs/entropy.rs | 248 + rand/src/rngs/mock.rs | 59 + rand/src/rngs/mod.rs | 167 + rand/src/rngs/small.rs | 106 + rand/src/rngs/std.rs | 85 + rand/src/rngs/thread.rs | 137 + rand/src/seq/index.rs | 378 + rand/src/seq/mod.rs | 829 + rand/tests/uniformity.rs | 67 + rand_chacha/.cargo-checksum.json | 1 + rand_chacha/CHANGELOG.md | 12 + rand_chacha/COPYRIGHT | 12 + rand_chacha/Cargo.toml | 35 + rand_chacha/LICENSE-APACHE | 201 + rand_chacha/LICENSE-MIT | 26 + rand_chacha/README.md | 45 + rand_chacha/build.rs | 7 + rand_chacha/src/chacha.rs | 449 + rand_chacha/src/lib.rs | 25 + rand_core-0.3.1/.cargo-checksum.json | 1 + rand_core-0.3.1/CHANGELOG.md | 36 + rand_core-0.3.1/COPYRIGHT | 12 + rand_core-0.3.1/Cargo.toml | 37 + rand_core-0.3.1/LICENSE-APACHE | 201 + rand_core-0.3.1/LICENSE-MIT | 26 + rand_core-0.3.1/README.md | 65 + rand_core-0.3.1/src/block.rs | 499 + rand_core-0.3.1/src/error.rs | 177 + rand_core-0.3.1/src/impls.rs | 165 + rand_core-0.3.1/src/le.rs | 68 + rand_core-0.3.1/src/lib.rs | 46 + rand_core/.cargo-checksum.json | 1 + rand_core/CHANGELOG.md | 36 + rand_core/COPYRIGHT | 12 + rand_core/Cargo.toml | 41 + rand_core/LICENSE-APACHE | 201 + rand_core/LICENSE-MIT | 26 + rand_core/README.md | 66 + rand_core/src/block.rs | 499 + rand_core/src/error.rs | 177 + rand_core/src/impls.rs | 165 + rand_core/src/le.rs | 68 + rand_core/src/lib.rs | 477 + rand_hc/.cargo-checksum.json | 1 + rand_hc/CHANGELOG.md | 8 + rand_hc/COPYRIGHT | 12 + rand_hc/Cargo.toml | 32 + rand_hc/LICENSE-APACHE | 201 + rand_hc/LICENSE-MIT | 25 + rand_hc/README.md | 44 + rand_hc/src/hc128.rs | 462 + rand_hc/src/lib.rs | 25 + rand_isaac/.cargo-checksum.json | 1 + rand_isaac/CHANGELOG.md | 12 + rand_isaac/COPYRIGHT | 12 + rand_isaac/Cargo.toml | 45 + rand_isaac/LICENSE-APACHE | 201 + rand_isaac/LICENSE-MIT | 26 + rand_isaac/README.md | 47 + rand_isaac/src/isaac.rs | 484 + rand_isaac/src/isaac64.rs | 481 + rand_isaac/src/isaac_array.rs | 136 + rand_isaac/src/lib.rs | 36 + rand_jitter/.cargo-checksum.json | 1 + rand_jitter/CHANGELOG.md | 21 + rand_jitter/COPYRIGHT | 12 + rand_jitter/Cargo.toml | 42 + rand_jitter/LICENSE-APACHE | 201 + rand_jitter/LICENSE-MIT | 26 + rand_jitter/README.md | 104 + rand_jitter/benches/mod.rs | 18 + rand_jitter/src/dummy_log.rs | 10 + rand_jitter/src/error.rs | 70 + rand_jitter/src/lib.rs | 718 + rand_jitter/src/platform.rs | 44 + rand_jitter/tests/mod.rs | 31 + rand_os/.cargo-checksum.json | 1 + rand_os/CHANGELOG.md | 22 + rand_os/COPYRIGHT | 12 + rand_os/Cargo.toml | 53 + rand_os/LICENSE-APACHE | 201 + rand_os/LICENSE-MIT | 26 + rand_os/README.md | 33 + rand_os/src/cloudabi.rs | 39 + rand_os/src/dragonfly_haiku_emscripten.rs | 39 + rand_os/src/dummy_log.rs | 10 + rand_os/src/freebsd.rs | 45 + rand_os/src/fuchsia.rs | 28 + rand_os/src/lib.rs | 440 + rand_os/src/linux_android.rs | 186 + rand_os/src/macos.rs | 53 + rand_os/src/netbsd.rs | 57 + rand_os/src/openbsd_bitrig.rs | 40 + rand_os/src/random_device.rs | 70 + rand_os/src/redox.rs | 30 + rand_os/src/sgx.rs | 38 + rand_os/src/solarish.rs | 195 + rand_os/src/wasm32_bindgen.rs | 92 + rand_os/src/wasm32_stdweb.rs | 107 + rand_os/src/windows.rs | 44 + rand_os/tests/mod.rs | 80 + rand_pcg/.cargo-checksum.json | 1 + rand_pcg/CHANGELOG.md | 19 + rand_pcg/COPYRIGHT | 12 + rand_pcg/Cargo.toml | 47 + rand_pcg/LICENSE-APACHE | 201 + rand_pcg/LICENSE-MIT | 26 + rand_pcg/README.md | 43 + rand_pcg/build.rs | 7 + rand_pcg/src/lib.rs | 48 + rand_pcg/src/pcg128.rs | 122 + rand_pcg/src/pcg64.rs | 141 + rand_pcg/tests/lcg64xsh32.rs | 58 + rand_pcg/tests/mcg128xsl64.rs | 59 + rand_xorshift/.cargo-checksum.json | 1 + rand_xorshift/CHANGELOG.md | 11 + rand_xorshift/COPYRIGHT | 12 + rand_xorshift/Cargo.toml | 45 + rand_xorshift/LICENSE-APACHE | 201 + rand_xorshift/LICENSE-MIT | 26 + rand_xorshift/README.md | 45 + rand_xorshift/src/lib.rs | 123 + rand_xorshift/tests/mod.rs | 92 + rdrand/.cargo-checksum.json | 1 + rdrand/Cargo.toml | 28 + rdrand/LICENSE | 12 + rdrand/README.mkd | 8 + rdrand/appveyor.yml | 27 + rdrand/benches/rdrand.rs | 49 + rdrand/benches/rdseed.rs | 49 + rdrand/benches/std.rs | 31 + rdrand/src/changelog.rs | 25 + rdrand/src/lib.rs | 472 + redox_syscall/.cargo-checksum.json | 1 + redox_syscall/Cargo.toml | 23 + redox_syscall/LICENSE | 22 + redox_syscall/README.md | 6 + redox_syscall/src/arch/aarch64.rs | 77 + redox_syscall/src/arch/arm.rs | 73 + redox_syscall/src/arch/x86.rs | 73 + redox_syscall/src/arch/x86_64.rs | 74 + redox_syscall/src/call.rs | 389 + redox_syscall/src/data.rs | 219 + redox_syscall/src/error.rs | 311 + redox_syscall/src/flag.rs | 162 + redox_syscall/src/io/dma.rs | 76 + redox_syscall/src/io/io.rs | 67 + redox_syscall/src/io/mmio.rs | 31 + redox_syscall/src/io/mod.rs | 11 + redox_syscall/src/io/pio.rs | 89 + redox_syscall/src/lib.rs | 49 + redox_syscall/src/number.rs | 76 + redox_syscall/src/scheme/generate.sh | 20 + redox_syscall/src/scheme/mod.rs | 9 + redox_syscall/src/scheme/scheme.rs | 167 + redox_syscall/src/scheme/scheme_block.rs | 167 + redox_syscall/src/scheme/scheme_block_mut.rs | 167 + redox_syscall/src/scheme/scheme_mut.rs | 167 + redox_termios/.cargo-checksum.json | 1 + redox_termios/Cargo.toml | 26 + redox_termios/LICENSE | 21 + redox_termios/README.md | 2 + redox_termios/src/lib.rs | 218 + regex-syntax/.cargo-checksum.json | 1 + regex-syntax/Cargo.toml | 23 + regex-syntax/LICENSE-APACHE | 201 + regex-syntax/LICENSE-MIT | 25 + regex-syntax/benches/bench.rs | 73 + regex-syntax/src/ast/mod.rs | 1515 ++ regex-syntax/src/ast/parse.rs | 5384 ++++++ regex-syntax/src/ast/print.rs | 586 + regex-syntax/src/ast/visitor.rs | 557 + regex-syntax/src/either.rs | 8 + regex-syntax/src/error.rs | 297 + regex-syntax/src/hir/interval.rs | 490 + regex-syntax/src/hir/literal/mod.rs | 1551 ++ regex-syntax/src/hir/mod.rs | 2192 +++ regex-syntax/src/hir/print.rs | 375 + regex-syntax/src/hir/translate.rs | 2646 +++ regex-syntax/src/hir/visitor.rs | 222 + regex-syntax/src/lib.rs | 228 + regex-syntax/src/parser.rs | 206 + regex-syntax/src/unicode.rs | 455 + .../src/unicode_tables/LICENSE-UNICODE | 57 + regex-syntax/src/unicode_tables/age.rs | 455 + .../src/unicode_tables/case_folding_simple.rs | 725 + .../src/unicode_tables/general_category.rs | 1907 ++ .../unicode_tables/grapheme_cluster_break.rs | 455 + regex-syntax/src/unicode_tables/mod.rs | 12 + regex-syntax/src/unicode_tables/perl_word.rs | 188 + .../src/unicode_tables/property_bool.rs | 2960 +++ .../src/unicode_tables/property_names.rs | 151 + .../src/unicode_tables/property_values.rs | 326 + regex-syntax/src/unicode_tables/script.rs | 801 + .../src/unicode_tables/script_extension.rs | 829 + .../src/unicode_tables/sentence_break.rs | 642 + regex-syntax/src/unicode_tables/word_break.rs | 351 + regex/.cargo-checksum.json | 1 + regex/CHANGELOG.md | 668 + regex/Cargo.toml | 106 + regex/HACKING.md | 341 + regex/LICENSE-APACHE | 201 + regex/LICENSE-MIT | 25 + regex/PERFORMANCE.md | 279 + regex/README.md | 231 + regex/UNICODE.md | 259 + regex/build.rs | 89 + regex/examples/regexdna-input.txt | 1671 ++ regex/examples/regexdna-output.txt | 13 + regex/examples/shootout-regex-dna-bytes.rs | 66 + regex/examples/shootout-regex-dna-cheat.rs | 88 + regex/examples/shootout-regex-dna-replace.rs | 19 + .../shootout-regex-dna-single-cheat.rs | 73 + regex/examples/shootout-regex-dna-single.rs | 55 + regex/examples/shootout-regex-dna.rs | 66 + regex/rustfmt.toml | 1 + regex/src/backtrack.rs | 303 + regex/src/compile.rs | 1115 ++ regex/src/dfa.rs | 1965 ++ regex/src/error.rs | 84 + regex/src/exec.rs | 1467 ++ regex/src/expand.rs | 215 + regex/src/freqs.rs | 271 + regex/src/input.rs | 420 + regex/src/lib.rs | 683 + regex/src/literal/mod.rs | 1145 ++ regex/src/literal/teddy_avx2/fallback.rs | 20 + regex/src/literal/teddy_avx2/imp.rs | 472 + regex/src/literal/teddy_avx2/mod.rs | 14 + regex/src/literal/teddy_ssse3/fallback.rs | 20 + regex/src/literal/teddy_ssse3/imp.rs | 780 + regex/src/literal/teddy_ssse3/mod.rs | 14 + regex/src/pattern.rs | 62 + regex/src/pikevm.rs | 380 + regex/src/prog.rs | 423 + regex/src/re_builder.rs | 388 + regex/src/re_bytes.rs | 1169 ++ regex/src/re_set.rs | 462 + regex/src/re_trait.rs | 268 + regex/src/re_unicode.rs | 1211 ++ regex/src/sparse.rs | 75 + regex/src/testdata/LICENSE | 19 + regex/src/testdata/README | 17 + regex/src/testdata/basic.dat | 221 + regex/src/testdata/nullsubexpr.dat | 79 + regex/src/testdata/repetition.dat | 163 + regex/src/utf8.rs | 259 + regex/src/vector/avx2.rs | 187 + regex/src/vector/mod.rs | 4 + regex/src/vector/ssse3.rs | 192 + regex/tests/api.rs | 182 + regex/tests/api_str.rs | 31 + regex/tests/bytes.rs | 72 + regex/tests/consistent.rs | 213 + regex/tests/crates_regex.rs | 3129 +++ regex/tests/crazy.rs | 401 + regex/tests/flags.rs | 11 + regex/tests/fowler.rs | 371 + regex/tests/macros.rs | 149 + regex/tests/macros_bytes.rs | 39 + regex/tests/macros_str.rs | 36 + regex/tests/misc.rs | 14 + regex/tests/multiline.rs | 49 + regex/tests/noparse.rs | 50 + regex/tests/regression.rs | 150 + regex/tests/replace.rs | 50 + regex/tests/searcher.rs | 66 + regex/tests/set.rs | 38 + regex/tests/shortest_match.rs | 14 + regex/tests/suffix_reverse.rs | 16 + regex/tests/test_backtrack.rs | 64 + regex/tests/test_backtrack_bytes.rs | 65 + regex/tests/test_backtrack_utf8bytes.rs | 65 + regex/tests/test_crates_regex.rs | 57 + regex/tests/test_default.rs | 121 + regex/tests/test_default_bytes.rs | 73 + regex/tests/test_nfa.rs | 60 + regex/tests/test_nfa_bytes.rs | 65 + regex/tests/test_nfa_utf8bytes.rs | 61 + regex/tests/unicode.rs | 147 + regex/tests/word_boundary.rs | 89 + regex/tests/word_boundary_ascii.rs | 9 + regex/tests/word_boundary_unicode.rs | 6 + remove_dir_all/.cargo-checksum.json | 1 + remove_dir_all/Cargo.toml | 26 + remove_dir_all/LICENCE-APACHE | 191 + remove_dir_all/LICENCE-MIT | 26 + remove_dir_all/src/fs.rs | 265 + remove_dir_all/src/lib.rs | 12 + rustc-demangle/.cargo-checksum.json | 1 + rustc-demangle/Cargo.toml | 33 + rustc-demangle/LICENSE-APACHE | 201 + rustc-demangle/LICENSE-MIT | 25 + rustc-demangle/README.md | 24 + rustc-demangle/src/legacy.rs | 370 + rustc-demangle/src/lib.rs | 365 + rustc-demangle/src/v0.rs | 1067 ++ rustc-workspace-hack/.cargo-checksum.json | 1 + rustc-workspace-hack/Cargo.toml | 20 + rustc-workspace-hack/src/lib.rs | 7 + rustc_version/.cargo-checksum.json | 1 + rustc_version/Cargo.toml | 26 + rustc_version/LICENSE-APACHE | 201 + rustc_version/LICENSE-MIT | 25 + rustc_version/README.md | 75 + rustc_version/src/errors.rs | 79 + rustc_version/src/lib.rs | 347 + rustfix/.cargo-checksum.json | 1 + rustfix/Cargo.toml | 53 + rustfix/LICENSE-APACHE | 202 + rustfix/LICENSE-MIT | 21 + rustfix/Readme.md | 44 + rustfix/bors.toml | 4 + rustfix/proptest-regressions/replace.txt | 8 + rustfix/src/diagnostics.rs | 87 + rustfix/src/lib.rs | 249 + rustfix/src/replace.rs | 327 + rusty-fork/.cargo-checksum.json | 1 + rusty-fork/CHANGELOG.md | 31 + rusty-fork/Cargo.toml | 44 + rusty-fork/LICENSE-APACHE | 201 + rusty-fork/LICENSE-MIT | 25 + rusty-fork/README.md | 115 + rusty-fork/src/child_wrapper.rs | 248 + rusty-fork/src/cmdline.rs | 257 + rusty-fork/src/error.rs | 62 + rusty-fork/src/file-preamble | 8 + rusty-fork/src/fork.rs | 317 + rusty-fork/src/fork_test.rs | 207 + rusty-fork/src/lib.rs | 137 + rusty-fork/src/sugar.rs | 42 + ryu/.cargo-checksum.json | 1 + ryu/Cargo.toml | 35 + ryu/LICENSE-APACHE | 201 + ryu/LICENSE-BOOST | 23 + ryu/README.md | 108 + ryu/benches/bench.rs | 59 + ryu/build.rs | 60 + ryu/examples/upstream_benchmark.rs | 88 + ryu/src/buffer/mod.rs | 97 + ryu/src/common.rs | 72 + ryu/src/d2s.rs | 581 + ryu/src/d2s_full_table.rs | 643 + ryu/src/d2s_intrinsics.rs | 79 + ryu/src/d2s_small_table.rs | 206 + ryu/src/digit_table.rs | 28 + ryu/src/f2s.rs | 494 + ryu/src/lib.rs | 126 + ryu/src/pretty/exponent.rs | 49 + ryu/src/pretty/mantissa.rs | 51 + ryu/src/pretty/mod.rs | 224 + ryu/tests/d2s_table_test.rs | 52 + ryu/tests/d2s_test.rs | 224 + ryu/tests/exhaustive.rs | 55 + ryu/tests/f2s_test.rs | 183 + ryu/tests/macros/mod.rs | 12 + same-file/.cargo-checksum.json | 1 + same-file/COPYING | 3 + same-file/Cargo.toml | 28 + same-file/LICENSE-MIT | 21 + same-file/README.md | 45 + same-file/UNLICENSE | 24 + same-file/examples/is_same_file.rs | 13 + same-file/examples/is_stderr.rs | 33 + same-file/src/lib.rs | 530 + same-file/src/unix.rs | 112 + same-file/src/win.rs | 174 + schannel/.cargo-checksum.json | 1 + schannel/Cargo.toml | 28 + schannel/LICENSE.md | 7 + schannel/README.md | 6 + schannel/appveyor.yml | 26 + schannel/src/cert_chain.rs | 139 + schannel/src/cert_context.rs | 672 + schannel/src/cert_store.rs | 446 + schannel/src/context_buffer.rs | 21 + schannel/src/crypt_key.rs | 15 + schannel/src/crypt_prov.rs | 224 + schannel/src/ctl_context.rs | 187 + schannel/src/key_handle.rs | 5 + schannel/src/lib.rs | 87 + schannel/src/ncrypt_key.rs | 15 + schannel/src/schannel_cred.rs | 262 + schannel/src/security_context.rs | 112 + schannel/src/test.rs | 655 + schannel/src/tls_stream.rs | 944 + schannel/test/cert.der | Bin 0 -> 799 bytes schannel/test/cert.pem | 19 + schannel/test/identity.p12 | Bin 0 -> 3386 bytes schannel/test/key.key | Bin 0 -> 1193 bytes schannel/test/key.pem | 28 + schannel/test/self-signed.badssl.com.cer | Bin 0 -> 893 bytes scopeguard/.cargo-checksum.json | 1 + scopeguard/Cargo.toml | 28 + scopeguard/LICENSE-APACHE | 201 + scopeguard/LICENSE-MIT | 25 + scopeguard/README.rst | 81 + scopeguard/examples/readme.rs | 27 + scopeguard/src/lib.rs | 409 + semver-parser/.cargo-checksum.json | 1 + semver-parser/Cargo.toml | 11 + semver-parser/LICENSE-APACHE | 201 + semver-parser/LICENSE-MIT | 25 + semver-parser/src/common.rs | 66 + semver-parser/src/lib.rs | 8 + semver-parser/src/range.rs | 696 + semver-parser/src/recognize.rs | 154 + semver-parser/src/version.rs | 365 + semver/.cargo-checksum.json | 1 + semver/Cargo.toml | 45 + semver/LICENSE-APACHE | 201 + semver/LICENSE-MIT | 25 + semver/README.md | 103 + semver/src/lib.rs | 182 + semver/src/version.rs | 759 + semver/src/version_req.rs | 895 + semver/tests/deprecation.rs | 22 + semver/tests/regression.rs | 25 + semver/tests/serde.rs | 90 + serde/.cargo-checksum.json | 1 + serde/Cargo.toml | 46 + serde/LICENSE-APACHE | 201 + serde/LICENSE-MIT | 23 + serde/README.md | 99 + serde/build.rs | 100 + serde/crates-io.md | 52 + serde/src/de/from_primitive.rs | 260 + serde/src/de/ignored_any.rs | 218 + serde/src/de/impls.rs | 2547 +++ serde/src/de/mod.rs | 2269 +++ serde/src/de/utf8.rs | 46 + serde/src/de/value.rs | 1497 ++ serde/src/export.rs | 36 + serde/src/integer128.rs | 82 + serde/src/lib.rs | 254 + serde/src/macros.rs | 236 + serde/src/private/de.rs | 2935 +++ serde/src/private/macros.rs | 140 + serde/src/private/mod.rs | 4 + serde/src/private/ser.rs | 1326 ++ serde/src/ser/impls.rs | 840 + serde/src/ser/impossible.rs | 216 + serde/src/ser/mod.rs | 1988 ++ serde_derive/.cargo-checksum.json | 1 + serde_derive/Cargo.toml | 48 + serde_derive/LICENSE-APACHE | 201 + serde_derive/LICENSE-MIT | 23 + serde_derive/README.md | 99 + serde_derive/crates-io.md | 52 + serde_derive/src/bound.rs | 317 + serde_derive/src/de.rs | 3011 +++ serde_derive/src/dummy.rs | 47 + serde_derive/src/fragment.rs | 74 + serde_derive/src/internals/ast.rs | 204 + serde_derive/src/internals/attr.rs | 1974 ++ serde_derive/src/internals/case.rs | 174 + serde_derive/src/internals/check.rs | 412 + serde_derive/src/internals/ctxt.rs | 57 + serde_derive/src/internals/mod.rs | 14 + serde_derive/src/lib.rs | 96 + serde_derive/src/pretend.rs | 140 + serde_derive/src/ser.rs | 1315 ++ serde_derive/src/try.rs | 24 + serde_ignored/.cargo-checksum.json | 1 + serde_ignored/Cargo.toml | 16 + serde_ignored/LICENSE-APACHE | 201 + serde_ignored/LICENSE-MIT | 25 + serde_ignored/README.md | 98 + serde_ignored/src/lib.rs | 1104 ++ serde_json/.cargo-checksum.json | 1 + serde_json/Cargo.toml | 68 + serde_json/LICENSE-APACHE | 201 + serde_json/LICENSE-MIT | 23 + serde_json/README.md | 354 + serde_json/src/de.rs | 2317 +++ serde_json/src/error.rs | 472 + serde_json/src/iter.rs | 70 + serde_json/src/lib.rs | 365 + serde_json/src/macros.rs | 292 + serde_json/src/map.rs | 814 + serde_json/src/number.rs | 752 + serde_json/src/raw.rs | 458 + serde_json/src/read.rs | 859 + serde_json/src/ser.rs | 2262 +++ serde_json/src/value/de.rs | 1480 ++ serde_json/src/value/from.rs | 213 + serde_json/src/value/index.rs | 257 + serde_json/src/value/mod.rs | 1011 + serde_json/src/value/partial_eq.rs | 94 + serde_json/src/value/ser.rs | 1018 + shell-escape/.cargo-checksum.json | 1 + shell-escape/Cargo.toml | 21 + shell-escape/LICENSE-APACHE | 201 + shell-escape/LICENSE-MIT | 25 + shell-escape/README.md | 23 + shell-escape/src/lib.rs | 133 + sized-chunks/.cargo-checksum.json | 1 + sized-chunks/CHANGELOG.md | 43 + sized-chunks/CODE_OF_CONDUCT.md | 73 + sized-chunks/Cargo.toml | 34 + sized-chunks/LICENCE.md | 355 + sized-chunks/README.md | 35 + sized-chunks/src/bitmap.rs | 165 + sized-chunks/src/lib.rs | 18 + sized-chunks/src/sized_chunk.rs | 1178 ++ sized-chunks/src/sparse_chunk.rs | 454 + sized-chunks/src/tests/mod.rs | 9 + sized-chunks/src/tests/sized_chunk.rs | 286 + sized-chunks/src/tests/sparse_chunk.rs | 99 + sized-chunks/src/types.rs | 244 + smallvec/.cargo-checksum.json | 1 + smallvec/Cargo.toml | 39 + smallvec/LICENSE-APACHE | 201 + smallvec/LICENSE-MIT | 25 + smallvec/README.md | 8 + smallvec/benches/bench.rs | 295 + smallvec/lib.rs | 2314 +++ socket2/.cargo-checksum.json | 1 + socket2/Cargo.toml | 40 + socket2/LICENSE-APACHE | 201 + socket2/LICENSE-MIT | 25 + socket2/README.md | 23 + socket2/src/lib.rs | 153 + socket2/src/sockaddr.rs | 212 + socket2/src/socket.rs | 997 + socket2/src/sys/redox/mod.rs | 832 + socket2/src/sys/unix/mod.rs | 1116 ++ socket2/src/sys/unix/weak.rs | 59 + socket2/src/sys/windows.rs | 974 + socket2/src/utils.rs | 48 + strsim/.cargo-checksum.json | 1 + strsim/CHANGELOG.md | 123 + strsim/Cargo.toml | 28 + strsim/LICENSE | 23 + strsim/README.md | 69 + strsim/appveyor.yml | 13 + strsim/benches/benches.rs | 84 + strsim/dev | 41 + strsim/src/lib.rs | 786 + strsim/tests/lib.rs | 49 + syn/.cargo-checksum.json | 1 + syn/Cargo.toml | 68 + syn/LICENSE-APACHE | 201 + syn/LICENSE-MIT | 23 + syn/README.md | 256 + syn/build.rs | 72 + syn/src/attr.rs | 681 + syn/src/buffer.rs | 366 + syn/src/custom_keyword.rs | 252 + syn/src/custom_punctuation.rs | 309 + syn/src/data.rs | 384 + syn/src/derive.rs | 255 + syn/src/error.rs | 221 + syn/src/export.rs | 35 + syn/src/expr.rs | 3816 ++++ syn/src/ext.rs | 145 + syn/src/file.rs | 113 + syn/src/gen/fold.rs | 2937 +++ syn/src/gen/visit.rs | 3371 ++++ syn/src/gen/visit_mut.rs | 3278 ++++ syn/src/gen_helper.rs | 154 + syn/src/generics.rs | 1116 ++ syn/src/group.rs | 283 + syn/src/ident.rs | 86 + syn/src/item.rs | 2677 +++ syn/src/keyword.rs | 0 syn/src/lib.rs | 727 + syn/src/lifetime.rs | 155 + syn/src/lit.rs | 1103 ++ syn/src/lookahead.rs | 168 + syn/src/mac.rs | 131 + syn/src/macros.rs | 165 + syn/src/op.rs | 231 + syn/src/parse.rs | 1111 ++ syn/src/parse_macro_input.rs | 103 + syn/src/parse_quote.rs | 144 + syn/src/path.rs | 704 + syn/src/print.rs | 16 + syn/src/punctuated.rs | 836 + syn/src/sealed.rs | 4 + syn/src/span.rs | 67 + syn/src/spanned.rs | 144 + syn/src/thread.rs | 83 + syn/src/token.rs | 950 + syn/src/tt.rs | 110 + syn/src/ty.rs | 994 + synstructure/.cargo-checksum.json | 1 + synstructure/Cargo.toml | 40 + synstructure/LICENSE | 7 + synstructure/README.md | 159 + synstructure/src/lib.rs | 2301 +++ synstructure/src/macros.rs | 471 + tar/.cargo-checksum.json | 1 + tar/Cargo.toml | 40 + tar/LICENSE-APACHE | 201 + tar/LICENSE-MIT | 25 + tar/README.md | 80 + tar/appveyor.yml | 20 + tar/examples/extract_file.rs | 25 + tar/examples/list.rs | 17 + tar/examples/raw_list.rs | 48 + tar/examples/write.rs | 13 + tar/src/archive.rs | 488 + tar/src/builder.rs | 535 + tar/src/entry.rs | 781 + tar/src/entry_type.rs | 193 + tar/src/error.rs | 40 + tar/src/header.rs | 1626 ++ tar/src/lib.rs | 44 + tar/src/pax.rs | 91 + tar/tests/all.rs | 1013 + tar/tests/entry.rs | 348 + tar/tests/header/mod.rs | 236 + tempfile/.cargo-checksum.json | 1 + tempfile/Cargo.toml | 38 + tempfile/LICENSE-APACHE | 201 + tempfile/LICENSE-MIT | 25 + tempfile/NEWS | 153 + tempfile/README.md | 52 + tempfile/src/dir.rs | 408 + tempfile/src/error.rs | 50 + tempfile/src/file/imp/mod.rs | 12 + tempfile/src/file/imp/other.rs | 30 + tempfile/src/file/imp/unix.rs | 137 + tempfile/src/file/imp/windows.rs | 108 + tempfile/src/file/mod.rs | 910 + tempfile/src/lib.rs | 455 + tempfile/src/spooled.rs | 153 + tempfile/src/util.rs | 51 + tempfile/tests/namedtempfile.rs | 269 + tempfile/tests/spooled.rs | 307 + tempfile/tests/tempdir.rs | 261 + tempfile/tests/tempfile.rs | 62 + termcolor/.cargo-checksum.json | 1 + termcolor/COPYING | 3 + termcolor/Cargo.toml | 30 + termcolor/LICENSE-MIT | 21 + termcolor/README.md | 86 + termcolor/UNLICENSE | 24 + termcolor/src/lib.rs | 1895 ++ termion/.cargo-checksum.json | 1 + termion/Cargo.toml | 32 + termion/LICENSE | 21 + termion/README.md | 181 + termion/examples/alternate_screen.rs | 17 + termion/examples/alternate_screen_raw.rs | 40 + termion/examples/async.rs | 39 + termion/examples/click.rs | 35 + termion/examples/color.rs | 10 + termion/examples/commie.rs | 51 + termion/examples/detect_color.rs | 19 + termion/examples/is_tty.rs | 11 + termion/examples/keys.rs | 44 + termion/examples/mouse.rs | 46 + termion/examples/rainbow.rs | 60 + termion/examples/read.rs | 23 + termion/examples/rustc_fun.rs | 24 + termion/examples/simple.rs | 42 + termion/examples/size.rs | 7 + termion/examples/truecolor.rs | 12 + termion/logo.svg | 9 + termion/src/async.rs | 101 + termion/src/clear.rs | 9 + termion/src/color.rs | 306 + termion/src/cursor.rs | 222 + termion/src/event.rs | 350 + termion/src/input.rs | 388 + termion/src/lib.rs | 63 + termion/src/macros.rs | 27 + termion/src/raw.rs | 131 + termion/src/screen.rs | 91 + termion/src/scroll.rs | 23 + termion/src/style.rs | 22 + termion/src/sys/redox/attr.rs | 33 + termion/src/sys/redox/mod.rs | 15 + termion/src/sys/redox/size.rs | 18 + termion/src/sys/redox/tty.rs | 22 + termion/src/sys/unix/attr.rs | 29 + termion/src/sys/unix/mod.rs | 33 + termion/src/sys/unix/size.rs | 20 + termion/src/sys/unix/tty.rs | 17 + textwrap/.cargo-checksum.json | 1 + textwrap/Cargo.toml | 56 + textwrap/LICENSE | 21 + textwrap/README.md | 337 + textwrap/benches/linear.rs | 122 + textwrap/examples/layout.rs | 38 + textwrap/examples/termwidth.rs | 41 + textwrap/src/indentation.rs | 294 + textwrap/src/lib.rs | 987 + textwrap/src/splitting.rs | 139 + textwrap/tests/version-numbers.rs | 17 + thread_local/.cargo-checksum.json | 1 + thread_local/Cargo.toml | 26 + thread_local/LICENSE-APACHE | 201 + thread_local/LICENSE-MIT | 25 + thread_local/README.md | 41 + thread_local/benches/thread_local.rs | 18 + thread_local/src/lib.rs | 757 + thread_local/src/thread_id.rs | 61 + thread_local/src/unreachable.rs | 74 + time/.cargo-checksum.json | 1 + time/Cargo.toml | 43 + time/LICENSE-APACHE | 201 + time/LICENSE-MIT | 25 + time/README.md | 30 + time/appveyor.yml | 17 + time/benches/precise_time_ns.rs | 14 + time/src/display.rs | 260 + time/src/duration.rs | 654 + time/src/lib.rs | 1276 ++ time/src/parse.rs | 394 + time/src/sys.rs | 1048 + toml/.cargo-checksum.json | 1 + toml/Cargo.toml | 33 + toml/LICENSE-APACHE | 201 + toml/LICENSE-MIT | 25 + toml/README.md | 40 + toml/examples/decode.rs | 55 + toml/examples/enum_external.rs | 46 + toml/examples/toml2json.rs | 51 + toml/src/datetime.rs | 424 + toml/src/de.rs | 1861 ++ toml/src/lib.rs | 175 + toml/src/macros.rs | 462 + toml/src/ser.rs | 1802 ++ toml/src/spanned.rs | 140 + toml/src/tokens.rs | 690 + toml/src/value.rs | 1007 + toml/tests/enum_external_deserialize.rs | 238 + typenum/.cargo-checksum.json | 1 + typenum/.pc/.quilt_patches | 1 + typenum/.pc/.quilt_series | 1 + typenum/.pc/.version | 1 + typenum/.pc/applied-patches | 1 + typenum/.pc/pr115.patch/.timestamp | 0 typenum/.pc/pr115.patch/build/main.rs | 179 + typenum/CHANGELOG.md | 56 + typenum/Cargo.toml | 31 + typenum/LICENSE | 21 + typenum/README.md | 42 + typenum/build/main.rs | 179 + typenum/build/op.rs | 533 + typenum/build/tests.rs | 301 + typenum/debian/patches/pr115.patch | 23 + typenum/debian/patches/series | 1 + typenum/src/array.rs | 282 + typenum/src/bit.rs | 272 + typenum/src/int.rs | 935 + typenum/src/lib.rs | 135 + typenum/src/marker_traits.rs | 194 + typenum/src/operator_aliases.rs | 98 + typenum/src/private.rs | 361 + typenum/src/type_operators.rs | 500 + typenum/src/uint.rs | 1572 ++ typenum/tests/test.rs | 2 + ucd-util/.cargo-checksum.json | 1 + ucd-util/Cargo.toml | 23 + ucd-util/LICENSE-APACHE | 201 + ucd-util/LICENSE-MIT | 21 + ucd-util/LICENSE-UNICODE | 57 + ucd-util/README.md | 27 + ucd-util/src/hangul.rs | 105 + ucd-util/src/ideograph.rs | 83 + ucd-util/src/lib.rs | 28 + ucd-util/src/name.rs | 194 + ucd-util/src/property.rs | 124 + .../src/unicode_tables/jamo_short_name.rs | 22 + ucd-util/src/unicode_tables/mod.rs | 5 + ucd-util/src/unicode_tables/property_names.rs | 147 + .../src/unicode_tables/property_values.rs | 1122 ++ unicode-bidi/.cargo-checksum.json | 1 + unicode-bidi/.pc/.quilt_patches | 1 + unicode-bidi/.pc/.quilt_series | 1 + unicode-bidi/.pc/.version | 1 + unicode-bidi/.pc/applied-patches | 1 + .../.pc/no-flamegraphs.patch/.timestamp | 0 .../.pc/no-flamegraphs.patch/Cargo.toml | 49 + unicode-bidi/AUTHORS | 4 + unicode-bidi/COPYRIGHT | 8 + unicode-bidi/Cargo.toml | 41 + unicode-bidi/LICENSE-APACHE | 201 + unicode-bidi/LICENSE-MIT | 25 + unicode-bidi/README.md | 12 + .../debian/patches/no-flamegraphs.patch | 24 + unicode-bidi/debian/patches/series | 1 + unicode-bidi/src/char_data/mod.rs | 136 + unicode-bidi/src/char_data/tables.rs | 464 + unicode-bidi/src/deprecated.rs | 90 + unicode-bidi/src/explicit.rs | 186 + unicode-bidi/src/format_chars.rs | 42 + unicode-bidi/src/implicit.rs | 228 + unicode-bidi/src/level.rs | 382 + unicode-bidi/src/lib.rs | 890 + unicode-bidi/src/prepare.rs | 366 + unicode-normalization/.cargo-checksum.json | 1 + unicode-normalization/COPYRIGHT | 7 + unicode-normalization/Cargo.toml | 26 + unicode-normalization/LICENSE-APACHE | 201 + unicode-normalization/LICENSE-MIT | 25 + unicode-normalization/README.md | 35 + unicode-normalization/benches/bench.rs | 127 + unicode-normalization/scripts/unicode.py | 475 + unicode-normalization/src/decompose.rs | 159 + unicode-normalization/src/lib.rs | 173 + unicode-normalization/src/normalize.rs | 152 + unicode-normalization/src/quick_check.rs | 189 + unicode-normalization/src/recompose.rs | 160 + unicode-normalization/src/stream_safe.rs | 164 + unicode-normalization/src/tables.rs | 12112 ++++++++++++ unicode-width/.cargo-checksum.json | 1 + unicode-width/COPYRIGHT | 7 + unicode-width/Cargo.toml | 29 + unicode-width/LICENSE-APACHE | 201 + unicode-width/LICENSE-MIT | 25 + unicode-width/README.md | 39 + unicode-width/scripts/unicode.py | 321 + unicode-width/src/lib.rs | 131 + unicode-width/src/tables.rs | 273 + unicode-width/src/tests.rs | 156 + unicode-xid/.cargo-checksum.json | 1 + unicode-xid/COPYRIGHT | 7 + unicode-xid/Cargo.toml | 26 + unicode-xid/LICENSE-APACHE | 201 + unicode-xid/LICENSE-MIT | 25 + unicode-xid/README.md | 34 + unicode-xid/scripts/unicode.py | 187 + unicode-xid/src/lib.rs | 87 + unicode-xid/src/tables.rs | 426 + unicode-xid/src/tests.rs | 113 + url/.cargo-checksum.json | 1 + url/.pc/.quilt_patches | 1 + url/.pc/.quilt_series | 1 + url/.pc/.version | 1 + .../.timestamp | 0 .../Cargo.toml | 83 + url/.pc/applied-patches | 1 + url/Cargo.toml | 77 + url/LICENSE-APACHE | 201 + url/LICENSE-MIT | 25 + url/README.md | 10 + url/UPGRADING.md | 263 + url/appveyor.yml | 13 + url/benches/parse_url.rs | 18 + ...-Remove-dependency-to-outdated-serde.patch | 32 + url/debian/patches/series | 1 + url/docs/404.html | 3 + url/docs/index.html | 3 + url/src/encoding.rs | 146 + url/src/form_urlencoded.rs | 411 + url/src/host.rs | 556 + url/src/lib.rs | 2482 +++ url/src/origin.rs | 130 + url/src/parser.rs | 1290 ++ url/src/path_segments.rs | 217 + url/src/quirks.rs | 217 + url/src/slicing.rs | 182 + url/tests/data.rs | 200 + url/tests/setters_tests.json | 1533 ++ url/tests/unit.rs | 556 + url/tests/urltestdata.json | 6148 ++++++ url_serde/.cargo-checksum.json | 1 + url_serde/Cargo.toml | 23 + url_serde/README.md | 11 + url_serde/src/lib.rs | 410 + utf8-ranges/.cargo-checksum.json | 1 + utf8-ranges/COPYING | 3 + utf8-ranges/Cargo.toml | 29 + utf8-ranges/LICENSE-MIT | 21 + utf8-ranges/README.md | 54 + utf8-ranges/UNLICENSE | 24 + utf8-ranges/benches/bench.rs | 25 + utf8-ranges/src/char_utf8.rs | 36 + utf8-ranges/src/lib.rs | 527 + vcpkg/.cargo-checksum.json | 1 + vcpkg/Cargo.toml | 38 + vcpkg/src/lib.rs | 1154 ++ vec_map/.cargo-checksum.json | 1 + vec_map/Cargo.toml | 30 + vec_map/LICENSE-APACHE | 201 + vec_map/LICENSE-MIT | 25 + vec_map/README.md | 15 + vec_map/deploy-docs.sh | 20 + vec_map/src/lib.rs | 1623 ++ wait-timeout/.cargo-checksum.json | 1 + wait-timeout/Cargo.toml | 30 + wait-timeout/LICENSE-APACHE | 201 + wait-timeout/LICENSE-MIT | 25 + wait-timeout/README.md | 14 + wait-timeout/appveyor.yml | 17 + wait-timeout/src/bin/exit.rs | 4 + wait-timeout/src/bin/reader.rs | 7 + wait-timeout/src/bin/sleep.rs | 4 + wait-timeout/src/lib.rs | 68 + wait-timeout/src/unix.rs | 305 + wait-timeout/src/windows.rs | 34 + wait-timeout/tests/smoke.rs | 103 + walkdir/.cargo-checksum.json | 1 + walkdir/COPYING | 3 + walkdir/Cargo.toml | 53 + walkdir/LICENSE-MIT | 21 + walkdir/README.md | 140 + walkdir/UNLICENSE | 24 + walkdir/compare/nftw.c | 25 + walkdir/compare/walk.py | 10 + walkdir/examples/walkdir.rs | 103 + walkdir/src/lib.rs | 1718 ++ walkdir/src/tests.rs | 912 + walkdir/src/unix.rs | 16 + .../.cargo-checksum.json | 1 + winapi-i686-pc-windows-gnu/Cargo.toml | 22 + winapi-i686-pc-windows-gnu/build.rs | 18 + winapi-i686-pc-windows-gnu/src/lib.rs | 7 + winapi-util/.cargo-checksum.json | 1 + winapi-util/COPYING | 3 + winapi-util/Cargo.toml | 27 + winapi-util/LICENSE-MIT | 21 + winapi-util/README.md | 51 + winapi-util/UNLICENSE | 24 + winapi-util/appveyor.yml | 26 + winapi-util/ci/script.sh | 7 + winapi-util/src/console.rs | 121 + winapi-util/src/file.rs | 171 + winapi-util/src/lib.rs | 35 + winapi-util/src/win.rs | 247 + .../.cargo-checksum.json | 1 + winapi-x86_64-pc-windows-gnu/Cargo.toml | 22 + winapi-x86_64-pc-windows-gnu/build.rs | 18 + winapi-x86_64-pc-windows-gnu/src/lib.rs | 7 + winapi/.cargo-checksum.json | 1 + winapi/Cargo.toml | 402 + winapi/LICENSE-APACHE | 201 + winapi/LICENSE-MIT | 19 + winapi/README.md | 89 + winapi/build.rs | 488 + winapi/src/km/d3dkmthk.rs | 312 + winapi/src/km/mod.rs | 7 + winapi/src/lib.rs | 70 + winapi/src/macros.rs | 424 + winapi/src/shared/basetsd.rs | 70 + winapi/src/shared/bcrypt.rs | 1001 + winapi/src/shared/bugcodes.rs | 456 + winapi/src/shared/cderr.rs | 44 + winapi/src/shared/cfg.rs | 138 + winapi/src/shared/d3d9.rs | 1268 ++ winapi/src/shared/d3d9caps.rs | 366 + winapi/src/shared/d3d9types.rs | 1487 ++ winapi/src/shared/d3dkmdt.rs | 45 + winapi/src/shared/d3dukmdt.rs | 416 + winapi/src/shared/dcomptypes.rs | 50 + winapi/src/shared/devguid.rs | 178 + winapi/src/shared/devpkey.rs | 401 + winapi/src/shared/devpropdef.rs | 83 + winapi/src/shared/dinputd.rs | 21 + winapi/src/shared/dxgi.rs | 411 + winapi/src/shared/dxgi1_2.rs | 355 + winapi/src/shared/dxgi1_3.rs | 190 + winapi/src/shared/dxgi1_4.rs | 112 + winapi/src/shared/dxgi1_5.rs | 92 + winapi/src/shared/dxgi1_6.rs | 98 + winapi/src/shared/dxgiformat.rs | 127 + winapi/src/shared/dxgitype.rs | 109 + winapi/src/shared/evntprov.rs | 309 + winapi/src/shared/evntrace.rs | 990 + winapi/src/shared/guiddef.rs | 36 + winapi/src/shared/hidclass.rs | 68 + winapi/src/shared/hidpi.rs | 393 + winapi/src/shared/hidsdi.rs | 110 + winapi/src/shared/hidusage.rs | 274 + winapi/src/shared/ifdef.rs | 22 + winapi/src/shared/in6addr.rs | 17 + winapi/src/shared/inaddr.rs | 29 + winapi/src/shared/intsafe.rs | 5 + winapi/src/shared/ks.rs | 63 + winapi/src/shared/ksmedia.rs | 59 + winapi/src/shared/ktmtypes.rs | 138 + winapi/src/shared/lmcons.rs | 60 + winapi/src/shared/minwindef.rs | 102 + winapi/src/shared/mmreg.rs | 309 + winapi/src/shared/mod.rs | 75 + winapi/src/shared/mstcpip.rs | 492 + winapi/src/shared/mswsockdef.rs | 48 + winapi/src/shared/netioapi.rs | 57 + winapi/src/shared/ntddscsi.rs | 834 + winapi/src/shared/ntddser.rs | 17 + winapi/src/shared/ntdef.rs | 1073 ++ winapi/src/shared/ntstatus.rs | 2574 +++ winapi/src/shared/qos.rs | 20 + winapi/src/shared/rpc.rs | 9 + winapi/src/shared/rpcdce.rs | 563 + winapi/src/shared/rpcndr.rs | 25 + winapi/src/shared/sddl.rs | 217 + winapi/src/shared/sspi.rs | 1074 ++ winapi/src/shared/stralign.rs | 40 + winapi/src/shared/transportsettingcommon.rs | 10 + winapi/src/shared/tvout.rs | 72 + winapi/src/shared/usb.rs | 523 + winapi/src/shared/usbiodef.rs | 112 + winapi/src/shared/usbspec.rs | 860 + winapi/src/shared/windef.rs | 125 + winapi/src/shared/windowsx.rs | 17 + winapi/src/shared/winerror.rs | 6149 ++++++ winapi/src/shared/winusbio.rs | 38 + winapi/src/shared/wmistr.rs | 199 + winapi/src/shared/wnnc.rs | 77 + winapi/src/shared/ws2def.rs | 556 + winapi/src/shared/ws2ipdef.rs | 92 + winapi/src/shared/wtypes.rs | 344 + winapi/src/shared/wtypesbase.rs | 161 + winapi/src/um/accctrl.rs | 371 + winapi/src/um/aclapi.rs | 362 + winapi/src/um/appmgmt.rs | 122 + winapi/src/um/audioclient.rs | 172 + winapi/src/um/audiosessiontypes.rs | 37 + winapi/src/um/avrt.rs | 82 + winapi/src/um/bits.rs | 295 + winapi/src/um/bits10_1.rs | 37 + winapi/src/um/bits1_5.rs | 70 + winapi/src/um/bits2_0.rs | 51 + winapi/src/um/bits2_5.rs | 64 + winapi/src/um/bits3_0.rs | 179 + winapi/src/um/bits4_0.rs | 32 + winapi/src/um/bits5_0.rs | 95 + winapi/src/um/bitscfg.rs | 70 + winapi/src/um/bitsmsg.rs | 142 + winapi/src/um/cfgmgr32.rs | 2077 ++ winapi/src/um/cguid.rs | 134 + winapi/src/um/combaseapi.rs | 477 + winapi/src/um/coml2api.rs | 10 + winapi/src/um/commapi.rs | 87 + winapi/src/um/commctrl.rs | 4135 ++++ winapi/src/um/commdlg.rs | 712 + winapi/src/um/commoncontrols.rs | 232 + winapi/src/um/consoleapi.rs | 91 + winapi/src/um/corsym.rs | 89 + winapi/src/um/d2d1.rs | 982 + winapi/src/um/d2d1_1.rs | 847 + winapi/src/um/d2d1_2.rs | 68 + winapi/src/um/d2d1_3.rs | 698 + winapi/src/um/d2d1effectauthor.rs | 516 + winapi/src/um/d2d1effects.rs | 617 + winapi/src/um/d2d1effects_1.rs | 31 + winapi/src/um/d2d1effects_2.rs | 40 + winapi/src/um/d2d1svg.rs | 411 + winapi/src/um/d2dbasetypes.rs | 15 + winapi/src/um/d3d.rs | 61 + winapi/src/um/d3d10.rs | 57 + winapi/src/um/d3d10_1.rs | 11 + winapi/src/um/d3d10_1shader.rs | 7 + winapi/src/um/d3d10effect.rs | 45 + winapi/src/um/d3d10misc.rs | 7 + winapi/src/um/d3d10sdklayers.rs | 13 + winapi/src/um/d3d10shader.rs | 206 + winapi/src/um/d3d11.rs | 3420 ++++ winapi/src/um/d3d11_1.rs | 484 + winapi/src/um/d3d11_2.rs | 146 + winapi/src/um/d3d11_3.rs | 23 + winapi/src/um/d3d11_4.rs | 7 + winapi/src/um/d3d11on12.rs | 67 + winapi/src/um/d3d11sdklayers.rs | 2679 +++ winapi/src/um/d3d11shader.rs | 477 + winapi/src/um/d3d11tokenizedprogramformat.rs | 1335 ++ winapi/src/um/d3d12.rs | 2722 +++ winapi/src/um/d3d12sdklayers.rs | 1364 ++ winapi/src/um/d3d12shader.rs | 347 + winapi/src/um/d3dcommon.rs | 744 + winapi/src/um/d3dcompiler.rs | 274 + winapi/src/um/d3dcsx.rs | 11 + winapi/src/um/d3dx10core.rs | 11 + winapi/src/um/d3dx10math.rs | 7 + winapi/src/um/d3dx10mesh.rs | 19 + winapi/src/um/datetimeapi.rs | 60 + winapi/src/um/davclnt.rs | 104 + winapi/src/um/dbghelp.rs | 667 + winapi/src/um/dbt.rs | 192 + winapi/src/um/dcommon.rs | 114 + winapi/src/um/dcomp.rs | 1159 ++ winapi/src/um/dcompanimation.rs | 38 + winapi/src/um/dde.rs | 20 + winapi/src/um/ddraw.rs | 37 + winapi/src/um/ddrawi.rs | 13 + winapi/src/um/ddrawint.rs | 41 + winapi/src/um/debugapi.rs | 41 + winapi/src/um/devicetopology.rs | 462 + winapi/src/um/dinput.rs | 107 + winapi/src/um/dispex.rs | 221 + winapi/src/um/dmksctl.rs | 11 + winapi/src/um/dmusicc.rs | 71 + winapi/src/um/docobj.rs | 136 + winapi/src/um/documenttarget.rs | 24 + winapi/src/um/dpa_dsa.rs | 283 + winapi/src/um/dpapi.rs | 100 + winapi/src/um/dsgetdc.rs | 267 + winapi/src/um/dsound.rs | 342 + winapi/src/um/dsrole.rs | 66 + winapi/src/um/dvp.rs | 25 + winapi/src/um/dwmapi.rs | 295 + winapi/src/um/dwrite.rs | 1477 ++ winapi/src/um/dwrite_1.rs | 746 + winapi/src/um/dwrite_2.rs | 293 + winapi/src/um/dwrite_3.rs | 578 + winapi/src/um/dxdiag.rs | 11 + winapi/src/um/dxfile.rs | 23 + winapi/src/um/dxgidebug.rs | 235 + winapi/src/um/dxva2api.rs | 706 + winapi/src/um/dxvahd.rs | 555 + winapi/src/um/enclaveapi.rs | 64 + winapi/src/um/endpointvolume.rs | 123 + winapi/src/um/errhandlingapi.rs | 75 + winapi/src/um/evntcons.rs | 229 + winapi/src/um/exdisp.rs | 220 + winapi/src/um/fibersapi.rs | 23 + winapi/src/um/fileapi.rs | 639 + winapi/src/um/gl/gl.rs | 52 + winapi/src/um/gl/mod.rs | 7 + winapi/src/um/handleapi.rs | 36 + winapi/src/um/heapapi.rs | 92 + .../um/highlevelmonitorconfigurationapi.rs | 171 + winapi/src/um/http.rs | 1072 ++ winapi/src/um/imm.rs | 42 + winapi/src/um/interlockedapi.rs | 31 + winapi/src/um/ioapiset.rs | 71 + winapi/src/um/jobapi.rs | 14 + winapi/src/um/jobapi2.rs | 63 + winapi/src/um/knownfolders.rs | 287 + winapi/src/um/ktmw32.rs | 63 + winapi/src/um/libloaderapi.rs | 236 + winapi/src/um/lmaccess.rs | 1214 ++ winapi/src/um/lmalert.rs | 75 + winapi/src/um/lmapibuf.rs | 30 + winapi/src/um/lmat.rs | 62 + winapi/src/um/lmdfs.rs | 483 + winapi/src/um/lmerrlog.rs | 268 + winapi/src/um/lmjoin.rs | 232 + winapi/src/um/lmmsg.rs | 56 + winapi/src/um/lmremutl.rs | 61 + winapi/src/um/lmrepl.rs | 200 + winapi/src/um/lmserver.rs | 1255 ++ winapi/src/um/lmshare.rs | 379 + winapi/src/um/lmstats.rs | 85 + winapi/src/um/lmsvc.rs | 180 + winapi/src/um/lmuse.rs | 101 + winapi/src/um/lmwksta.rs | 421 + .../src/um/lowlevelmonitorconfigurationapi.rs | 49 + winapi/src/um/lsalookup.rs | 109 + winapi/src/um/memoryapi.rs | 390 + winapi/src/um/minschannel.rs | 58 + winapi/src/um/minwinbase.rs | 337 + winapi/src/um/mmdeviceapi.rs | 218 + winapi/src/um/mmeapi.rs | 336 + winapi/src/um/mmsystem.rs | 266 + winapi/src/um/mod.rs | 281 + winapi/src/um/msaatext.rs | 59 + winapi/src/um/mscat.rs | 36 + winapi/src/um/mschapp.rs | 48 + winapi/src/um/mssip.rs | 255 + winapi/src/um/mswsock.rs | 413 + winapi/src/um/namedpipeapi.rs | 93 + winapi/src/um/namespaceapi.rs | 36 + winapi/src/um/nb30.rs | 214 + winapi/src/um/ncrypt.rs | 88 + winapi/src/um/ntlsa.rs | 1530 ++ winapi/src/um/ntsecapi.rs | 1728 ++ winapi/src/um/oaidl.rs | 879 + winapi/src/um/objbase.rs | 64 + winapi/src/um/objidl.rs | 507 + winapi/src/um/objidlbase.rs | 952 + winapi/src/um/ocidl.rs | 68 + winapi/src/um/ole2.rs | 21 + winapi/src/um/oleauto.rs | 836 + winapi/src/um/olectl.rs | 14 + winapi/src/um/oleidl.rs | 43 + winapi/src/um/opmapi.rs | 362 + winapi/src/um/pdh.rs | 806 + winapi/src/um/perflib.rs | 331 + .../src/um/physicalmonitorenumerationapi.rs | 43 + winapi/src/um/playsoundapi.rs | 46 + winapi/src/um/portabledevice.rs | 162 + winapi/src/um/portabledeviceapi.rs | 288 + winapi/src/um/portabledevicetypes.rs | 255 + winapi/src/um/powerbase.rs | 35 + winapi/src/um/powersetting.rs | 60 + winapi/src/um/powrprof.rs | 550 + winapi/src/um/processenv.rs | 98 + winapi/src/um/processsnapshot.rs | 120 + winapi/src/um/processthreadsapi.rs | 441 + winapi/src/um/processtopologyapi.rs | 23 + winapi/src/um/profileapi.rs | 15 + winapi/src/um/propidl.rs | 15 + winapi/src/um/propkeydef.rs | 13 + winapi/src/um/propsys.rs | 46 + winapi/src/um/prsht.rs | 361 + winapi/src/um/psapi.rs | 422 + winapi/src/um/realtimeapiset.rs | 30 + winapi/src/um/reason.rs | 60 + winapi/src/um/restartmanager.rs | 150 + winapi/src/um/restrictederrorinfo.rs | 20 + winapi/src/um/rmxfguid.rs | 67 + winapi/src/um/sapi.rs | 1388 ++ winapi/src/um/sapi51.rs | 3726 ++++ winapi/src/um/sapi53.rs | 1823 ++ winapi/src/um/sapiddk.rs | 238 + winapi/src/um/sapiddk51.rs | 651 + winapi/src/um/schannel.rs | 339 + winapi/src/um/securityappcontainer.rs | 16 + winapi/src/um/securitybaseapi.rs | 690 + winapi/src/um/servprov.rs | 23 + winapi/src/um/setupapi.rs | 3571 ++++ winapi/src/um/shellapi.rs | 923 + winapi/src/um/shellscalingapi.rs | 44 + winapi/src/um/shlobj.rs | 260 + winapi/src/um/shobjidl.rs | 373 + winapi/src/um/shobjidl_core.rs | 306 + winapi/src/um/shtypes.rs | 44 + winapi/src/um/spapidef.rs | 53 + winapi/src/um/spellcheck.rs | 146 + winapi/src/um/sporder.rs | 41 + winapi/src/um/sql.rs | 108 + winapi/src/um/sqlext.rs | 95 + winapi/src/um/sqltypes.rs | 142 + winapi/src/um/sqlucode.rs | 106 + winapi/src/um/sspi.rs | 7 + winapi/src/um/stringapiset.rs | 75 + winapi/src/um/strmif.rs | 7 + winapi/src/um/subauth.rs | 204 + winapi/src/um/synchapi.rs | 349 + winapi/src/um/sysinfoapi.rs | 217 + winapi/src/um/systemtopologyapi.rs | 20 + winapi/src/um/taskschd.rs | 1233 ++ winapi/src/um/textstor.rs | 11 + winapi/src/um/threadpoolapiset.rs | 171 + winapi/src/um/threadpoollegacyapiset.rs | 44 + winapi/src/um/timeapi.rs | 20 + winapi/src/um/timezoneapi.rs | 89 + winapi/src/um/tlhelp32.rs | 194 + winapi/src/um/unknwnbase.rs | 43 + winapi/src/um/urlhist.rs | 97 + winapi/src/um/urlmon.rs | 21 + winapi/src/um/userenv.rs | 159 + winapi/src/um/usp10.rs | 560 + winapi/src/um/utilapiset.rs | 25 + winapi/src/um/uxtheme.rs | 772 + winapi/src/um/vsbackup.rs | 520 + winapi/src/um/vss.rs | 284 + winapi/src/um/vsserror.rs | 89 + winapi/src/um/vswriter.rs | 397 + winapi/src/um/wbemads.rs | 41 + winapi/src/um/wbemcli.rs | 1174 ++ winapi/src/um/wbemdisp.rs | 1344 ++ winapi/src/um/wbemprov.rs | 302 + winapi/src/um/wbemtran.rs | 184 + winapi/src/um/wct.rs | 114 + winapi/src/um/werapi.rs | 53 + winapi/src/um/winbase.rs | 2825 +++ winapi/src/um/wincodec.rs | 1861 ++ winapi/src/um/wincodecsdk.rs | 564 + winapi/src/um/wincon.rs | 459 + winapi/src/um/wincontypes.rs | 114 + winapi/src/um/wincred.rs | 532 + winapi/src/um/wincrypt.rs | 7365 +++++++ winapi/src/um/windowsceip.rs | 9 + winapi/src/um/winefs.rs | 178 + winapi/src/um/winevt.rs | 543 + winapi/src/um/wingdi.rs | 5591 ++++++ winapi/src/um/winhttp.rs | 658 + winapi/src/um/wininet.rs | 2364 +++ winapi/src/um/winineti.rs | 142 + winapi/src/um/winioctl.rs | 1076 ++ winapi/src/um/winnetwk.rs | 446 + winapi/src/um/winnls.rs | 817 + winapi/src/um/winnt.rs | 8622 +++++++++ winapi/src/um/winreg.rs | 490 + winapi/src/um/winsafer.rs | 228 + winapi/src/um/winscard.rs | 709 + winapi/src/um/winsmcrd.rs | 166 + winapi/src/um/winsock2.rs | 1450 ++ winapi/src/um/winspool.rs | 2433 +++ winapi/src/um/winsvc.rs | 665 + winapi/src/um/winusb.rs | 224 + winapi/src/um/winuser.rs | 7006 +++++++ winapi/src/um/winver.rs | 53 + winapi/src/um/wow64apiset.rs | 27 + winapi/src/um/wpdmtpextensions.rs | 59 + winapi/src/um/ws2spi.rs | 909 + winapi/src/um/ws2tcpip.rs | 346 + winapi/src/um/xinput.rs | 165 + winapi/src/vc/excpt.rs | 18 + winapi/src/vc/limits.rs | 7 + winapi/src/vc/mod.rs | 10 + winapi/src/vc/vadefs.rs | 8 + winapi/src/vc/vcruntime.rs | 9 + winapi/src/winrt/activation.rs | 13 + winapi/src/winrt/hstring.rs | 25 + winapi/src/winrt/inspectable.rs | 29 + winapi/src/winrt/mod.rs | 12 + winapi/src/winrt/roapi.rs | 60 + winapi/src/winrt/robuffer.rs | 12 + winapi/src/winrt/roerrorapi.rs | 103 + winapi/src/winrt/winstring.rs | 150 + wincolor/.cargo-checksum.json | 1 + wincolor/COPYING | 3 + wincolor/Cargo.toml | 33 + wincolor/LICENSE-MIT | 21 + wincolor/README.md | 44 + wincolor/UNLICENSE | 24 + wincolor/src/lib.rs | 35 + wincolor/src/win.rs | 261 + 3151 files changed, 870694 insertions(+) create mode 100644 aho-corasick/.cargo-checksum.json create mode 100644 aho-corasick/COPYING create mode 100644 aho-corasick/Cargo.toml create mode 100644 aho-corasick/LICENSE-MIT create mode 100644 aho-corasick/README.md create mode 100644 aho-corasick/UNLICENSE create mode 100644 aho-corasick/appveyor.yml create mode 100644 aho-corasick/src/ahocorasick.rs create mode 100644 aho-corasick/src/automaton.rs create mode 100644 aho-corasick/src/buffer.rs create mode 100644 aho-corasick/src/classes.rs create mode 100644 aho-corasick/src/dfa.rs create mode 100644 aho-corasick/src/error.rs create mode 100644 aho-corasick/src/lib.rs create mode 100644 aho-corasick/src/nfa.rs create mode 100644 aho-corasick/src/prefilter.rs create mode 100644 aho-corasick/src/state_id.rs create mode 100644 aho-corasick/src/tests.rs create mode 100644 ansi_term/.cargo-checksum.json create mode 100644 ansi_term/Cargo.toml create mode 100644 ansi_term/LICENCE create mode 100644 ansi_term/README.md create mode 100644 ansi_term/examples/colours.rs create mode 100644 ansi_term/src/ansi.rs create mode 100644 ansi_term/src/debug.rs create mode 100644 ansi_term/src/difference.rs create mode 100644 ansi_term/src/display.rs create mode 100644 ansi_term/src/lib.rs create mode 100644 ansi_term/src/style.rs create mode 100644 ansi_term/src/windows.rs create mode 100644 ansi_term/src/write.rs create mode 100644 atty/.cargo-checksum.json create mode 100644 atty/CHANGELOG.md create mode 100644 atty/Cargo.toml create mode 100644 atty/LICENSE create mode 100644 atty/README.md create mode 100644 atty/appveyor.yml create mode 100644 atty/examples/atty.rs create mode 100644 atty/rustfmt.toml create mode 100644 atty/src/lib.rs create mode 100644 autocfg/.cargo-checksum.json create mode 100644 autocfg/Cargo.toml create mode 100644 autocfg/LICENSE-APACHE create mode 100644 autocfg/LICENSE-MIT create mode 100644 autocfg/README.md create mode 100644 autocfg/examples/integers.rs create mode 100644 autocfg/examples/paths.rs create mode 100644 autocfg/examples/traits.rs create mode 100644 autocfg/examples/versions.rs create mode 100644 autocfg/src/error.rs create mode 100644 autocfg/src/lib.rs create mode 100644 autocfg/src/tests.rs create mode 100644 autocfg/src/version.rs create mode 100644 backtrace-sys/.cargo-checksum.json create mode 100644 backtrace-sys/.pc/.quilt_patches create mode 100644 backtrace-sys/.pc/.quilt_series create mode 100644 backtrace-sys/.pc/.version create mode 100644 backtrace-sys/.pc/applied-patches create mode 100644 backtrace-sys/.pc/remove-unneeded-dep.patch/.timestamp create mode 100644 backtrace-sys/.pc/remove-unneeded-dep.patch/Cargo.toml create mode 100644 backtrace-sys/Cargo.toml create mode 100644 backtrace-sys/LICENSE-APACHE create mode 100644 backtrace-sys/LICENSE-MIT create mode 100644 backtrace-sys/build.rs create mode 100644 backtrace-sys/build.rs.orig create mode 100644 backtrace-sys/debian/patches/remove-unneeded-dep.patch create mode 100644 backtrace-sys/debian/patches/series create mode 100644 backtrace-sys/src/lib.rs create mode 100644 backtrace/.cargo-checksum.json create mode 100644 backtrace/Cargo.toml create mode 100644 backtrace/LICENSE-APACHE create mode 100644 backtrace/LICENSE-MIT create mode 100644 backtrace/README.md create mode 100644 backtrace/azure-pipelines.yml create mode 100644 backtrace/benches/benchmarks.rs create mode 100644 backtrace/build.rs create mode 100755 backtrace/ci/android-ndk.sh create mode 100644 backtrace/ci/azure-install-rust.yml create mode 100644 backtrace/ci/azure-test-all.yml create mode 100644 backtrace/ci/docker/aarch64-linux-android/Dockerfile create mode 100644 backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 backtrace/ci/docker/arm-linux-androideabi/Dockerfile create mode 100644 backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 backtrace/ci/docker/armv7-linux-androideabi/Dockerfile create mode 100644 backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile create mode 100644 backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile create mode 100644 backtrace/ci/docker/i686-linux-android/Dockerfile create mode 100644 backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 backtrace/ci/docker/x86_64-linux-android/Dockerfile create mode 100644 backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile create mode 100644 backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile create mode 100644 backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile create mode 100755 backtrace/ci/run-docker.sh create mode 100755 backtrace/ci/run.sh create mode 100644 backtrace/examples/backtrace.rs create mode 100644 backtrace/examples/raw.rs create mode 100644 backtrace/src/backtrace/dbghelp.rs create mode 100644 backtrace/src/backtrace/libunwind.rs create mode 100644 backtrace/src/backtrace/mod.rs create mode 100644 backtrace/src/backtrace/noop.rs create mode 100644 backtrace/src/backtrace/unix_backtrace.rs create mode 100644 backtrace/src/capture.rs create mode 100644 backtrace/src/dbghelp.rs create mode 100644 backtrace/src/lib.rs create mode 100644 backtrace/src/symbolize/coresymbolication.rs create mode 100644 backtrace/src/symbolize/dbghelp.rs create mode 100644 backtrace/src/symbolize/dladdr.rs create mode 100644 backtrace/src/symbolize/gimli.rs create mode 100644 backtrace/src/symbolize/libbacktrace.rs create mode 100644 backtrace/src/symbolize/mod.rs create mode 100644 backtrace/src/symbolize/noop.rs create mode 100644 backtrace/src/types.rs create mode 100644 backtrace/src/windows.rs create mode 100644 backtrace/tests/long_fn_name.rs create mode 100644 backtrace/tests/skip_inner_frames.rs create mode 100644 backtrace/tests/smoke.rs create mode 100644 bit-set/.cargo-checksum.json create mode 100644 bit-set/Cargo.toml create mode 100644 bit-set/LICENSE-APACHE create mode 100644 bit-set/LICENSE-MIT create mode 100644 bit-set/README.md create mode 100755 bit-set/deploy-docs.sh create mode 100644 bit-set/src/lib.rs create mode 100644 bit-vec/.cargo-checksum.json create mode 100644 bit-vec/Cargo.toml create mode 100644 bit-vec/LICENSE-APACHE create mode 100644 bit-vec/LICENSE-MIT create mode 100644 bit-vec/README.md create mode 100644 bit-vec/benches/extern.rs create mode 100755 bit-vec/crusader.sh create mode 100755 bit-vec/deploy-docs.sh create mode 100644 bit-vec/src/bench.rs create mode 100644 bit-vec/src/lib.rs create mode 100644 bitflags/.cargo-checksum.json create mode 100644 bitflags/CHANGELOG.md create mode 100644 bitflags/CODE_OF_CONDUCT.md create mode 100644 bitflags/Cargo.toml create mode 100644 bitflags/LICENSE-APACHE create mode 100644 bitflags/LICENSE-MIT create mode 100644 bitflags/README.md create mode 100644 bitflags/src/example_generated.rs create mode 100644 bitflags/src/lib.rs create mode 100644 bstr/.cargo-checksum.json create mode 100644 bstr/COPYING create mode 100644 bstr/Cargo.toml create mode 100644 bstr/LICENSE-APACHE create mode 100644 bstr/LICENSE-MIT create mode 100644 bstr/README.md create mode 100644 bstr/examples/graphemes-std.rs create mode 100644 bstr/examples/graphemes.rs create mode 100644 bstr/examples/lines-std.rs create mode 100644 bstr/examples/lines.rs create mode 100644 bstr/examples/uppercase-std.rs create mode 100644 bstr/examples/uppercase.rs create mode 100644 bstr/examples/words-std.rs create mode 100644 bstr/examples/words.rs create mode 100644 bstr/rustfmt.toml create mode 100755 bstr/scripts/generate-unicode-data create mode 100644 bstr/scripts/regex/grapheme.sh create mode 100644 bstr/scripts/regex/sentence.sh create mode 100644 bstr/scripts/regex/word.sh create mode 100644 bstr/src/ascii.rs create mode 100644 bstr/src/bstr.rs create mode 100644 bstr/src/bstring.rs create mode 100644 bstr/src/cow.rs create mode 100644 bstr/src/freqs.rs create mode 100644 bstr/src/impls.rs create mode 100644 bstr/src/io.rs create mode 100644 bstr/src/lib.rs create mode 100644 bstr/src/search/byte_frequencies.rs create mode 100644 bstr/src/search/mod.rs create mode 100644 bstr/src/search/prefilter.rs create mode 100644 bstr/src/search/tests.rs create mode 100644 bstr/src/search/twoway.rs create mode 100644 bstr/src/slice_index.rs create mode 100644 bstr/src/tests.rs create mode 100644 bstr/src/unicode/data/GraphemeBreakTest.txt create mode 100644 bstr/src/unicode/data/SentenceBreakTest.txt create mode 100644 bstr/src/unicode/data/WordBreakTest.txt create mode 100644 bstr/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/grapheme_break_fwd.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/grapheme_break_fwd.rs create mode 100644 bstr/src/unicode/fsm/grapheme_break_rev.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/grapheme_break_rev.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/grapheme_break_rev.rs create mode 100644 bstr/src/unicode/fsm/mod.rs create mode 100644 bstr/src/unicode/fsm/regional_indicator_rev.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/regional_indicator_rev.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/regional_indicator_rev.rs create mode 100644 bstr/src/unicode/fsm/sentence_break_fwd.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/sentence_break_fwd.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/sentence_break_fwd.rs create mode 100644 bstr/src/unicode/fsm/simple_word_fwd.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/simple_word_fwd.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/simple_word_fwd.rs create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_fwd.rs create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/whitespace_anchored_rev.rs create mode 100644 bstr/src/unicode/fsm/word_break_fwd.bigendian.dfa create mode 100644 bstr/src/unicode/fsm/word_break_fwd.littleendian.dfa create mode 100644 bstr/src/unicode/fsm/word_break_fwd.rs create mode 100644 bstr/src/unicode/grapheme.rs create mode 100644 bstr/src/unicode/mod.rs create mode 100644 bstr/src/unicode/sentence.rs create mode 100644 bstr/src/unicode/whitespace.rs create mode 100644 bstr/src/unicode/word.rs create mode 100644 bstr/src/utf8.rs create mode 100644 bufstream/.cargo-checksum.json create mode 100644 bufstream/Cargo.toml create mode 100644 bufstream/LICENSE-APACHE create mode 100644 bufstream/LICENSE-MIT create mode 100644 bufstream/README.md create mode 100644 bufstream/src/lib.rs create mode 100644 byteorder/.cargo-checksum.json create mode 100644 byteorder/CHANGELOG.md create mode 100644 byteorder/COPYING create mode 100644 byteorder/Cargo.toml create mode 100644 byteorder/LICENSE-MIT create mode 100644 byteorder/README.md create mode 100644 byteorder/UNLICENSE create mode 100644 byteorder/benches/bench.rs create mode 100644 byteorder/build.rs create mode 100644 byteorder/src/io.rs create mode 100644 byteorder/src/lib.rs create mode 100644 bytes/.cargo-checksum.json create mode 100644 bytes/CHANGELOG.md create mode 100644 bytes/Cargo.toml create mode 100644 bytes/LICENSE create mode 100644 bytes/README.md create mode 100644 bytes/benches/bytes.rs create mode 100644 bytes/ci/before_deploy.ps1 create mode 100644 bytes/ci/before_deploy.sh create mode 100644 bytes/ci/install.sh create mode 100644 bytes/ci/script.sh create mode 100644 bytes/ci/tsan create mode 100644 bytes/src/buf/buf.rs create mode 100644 bytes/src/buf/buf_mut.rs create mode 100644 bytes/src/buf/chain.rs create mode 100644 bytes/src/buf/from_buf.rs create mode 100644 bytes/src/buf/into_buf.rs create mode 100644 bytes/src/buf/iter.rs create mode 100644 bytes/src/buf/mod.rs create mode 100644 bytes/src/buf/reader.rs create mode 100644 bytes/src/buf/take.rs create mode 100644 bytes/src/buf/vec_deque.rs create mode 100644 bytes/src/buf/writer.rs create mode 100644 bytes/src/bytes.rs create mode 100644 bytes/src/debug.rs create mode 100644 bytes/src/either.rs create mode 100644 bytes/src/lib.rs create mode 100644 bytes/src/serde.rs create mode 100644 bytes/tests/test_buf.rs create mode 100644 bytes/tests/test_buf_mut.rs create mode 100644 bytes/tests/test_bytes.rs create mode 100644 bytes/tests/test_chain.rs create mode 100644 bytes/tests/test_debug.rs create mode 100644 bytes/tests/test_from_buf.rs create mode 100644 bytes/tests/test_iter.rs create mode 100644 bytes/tests/test_reader.rs create mode 100644 bytes/tests/test_serde.rs create mode 100644 bytes/tests/test_take.rs create mode 100644 bytesize/.cargo-checksum.json create mode 100644 bytesize/Cargo.toml create mode 100644 bytesize/LICENSE create mode 100644 bytesize/README.md create mode 100644 bytesize/src/lib.rs create mode 100644 cc/.cargo-checksum.json create mode 100644 cc/Cargo.toml create mode 100644 cc/LICENSE-APACHE create mode 100644 cc/LICENSE-MIT create mode 100644 cc/README.md create mode 100644 cc/azure-pipelines.yml create mode 100644 cc/ci/azure-install-rust.yml create mode 100644 cc/ci/azure-steps.yml create mode 100644 cc/src/bin/gcc-shim.rs create mode 100644 cc/src/com.rs create mode 100644 cc/src/lib.rs create mode 100644 cc/src/registry.rs create mode 100644 cc/src/setup_config.rs create mode 100644 cc/src/winapi.rs create mode 100644 cc/src/windows_registry.rs create mode 100644 cc/tests/cc_env.rs create mode 100644 cc/tests/support/mod.rs create mode 100644 cc/tests/test.rs create mode 100644 cfg-if/.cargo-checksum.json create mode 100644 cfg-if/Cargo.toml create mode 100644 cfg-if/LICENSE-APACHE create mode 100644 cfg-if/LICENSE-MIT create mode 100644 cfg-if/README.md create mode 100644 cfg-if/src/lib.rs create mode 100644 cfg-if/tests/xcrate.rs create mode 100644 chrono/.cargo-checksum.json create mode 100644 chrono/AUTHORS.txt create mode 100644 chrono/CHANGELOG.md create mode 100644 chrono/Cargo.toml create mode 100644 chrono/LICENSE.txt create mode 100644 chrono/Makefile create mode 100644 chrono/README.md create mode 100644 chrono/appveyor.yml create mode 100755 chrono/ci/fix-readme.sh create mode 100755 chrono/ci/travis.sh create mode 100644 chrono/src/date.rs create mode 100644 chrono/src/datetime.rs create mode 100644 chrono/src/div.rs create mode 100644 chrono/src/format/mod.rs create mode 100644 chrono/src/format/parse.rs create mode 100644 chrono/src/format/parsed.rs create mode 100644 chrono/src/format/scan.rs create mode 100644 chrono/src/format/strftime.rs create mode 100644 chrono/src/lib.rs create mode 100644 chrono/src/naive/date.rs create mode 100644 chrono/src/naive/datetime.rs create mode 100644 chrono/src/naive/internals.rs create mode 100644 chrono/src/naive/isoweek.rs create mode 100644 chrono/src/naive/time.rs create mode 100644 chrono/src/offset/fixed.rs create mode 100644 chrono/src/offset/local.rs create mode 100644 chrono/src/offset/mod.rs create mode 100644 chrono/src/offset/utc.rs create mode 100644 chrono/src/oldtime.rs create mode 100644 chrono/src/round.rs create mode 100644 clap/.cargo-checksum.json create mode 100644 clap/.pc/.quilt_patches create mode 100644 clap/.pc/.quilt_series create mode 100644 clap/.pc/.version create mode 100644 clap/.pc/applied-patches create mode 100644 clap/.pc/no-clippy.patch/.timestamp create mode 100644 clap/.pc/no-clippy.patch/Cargo.toml create mode 100644 clap/.pc/relax-dep-versions.patch/.timestamp create mode 100644 clap/.pc/relax-dep-versions.patch/Cargo.toml create mode 100644 clap/CHANGELOG.md create mode 100644 clap/CONTRIBUTORS.md create mode 100644 clap/Cargo.toml create mode 100644 clap/LICENSE-MIT create mode 100644 clap/README.md create mode 100644 clap/SPONSORS.md create mode 100644 clap/clap-test.rs create mode 100644 clap/debian/patches/no-clippy.patch create mode 100644 clap/debian/patches/relax-dep-versions.patch create mode 100644 clap/debian/patches/series create mode 100644 clap/justfile create mode 100644 clap/rustfmt.toml create mode 100644 clap/src/app/help.rs create mode 100644 clap/src/app/meta.rs create mode 100644 clap/src/app/mod.rs create mode 100644 clap/src/app/parser.rs create mode 100644 clap/src/app/settings.rs create mode 100644 clap/src/app/usage.rs create mode 100644 clap/src/app/validator.rs create mode 100644 clap/src/args/any_arg.rs create mode 100644 clap/src/args/arg.rs create mode 100644 clap/src/args/arg_builder/base.rs create mode 100644 clap/src/args/arg_builder/flag.rs create mode 100644 clap/src/args/arg_builder/mod.rs create mode 100644 clap/src/args/arg_builder/option.rs create mode 100644 clap/src/args/arg_builder/positional.rs create mode 100644 clap/src/args/arg_builder/switched.rs create mode 100644 clap/src/args/arg_builder/valued.rs create mode 100644 clap/src/args/arg_matcher.rs create mode 100644 clap/src/args/arg_matches.rs create mode 100644 clap/src/args/group.rs create mode 100644 clap/src/args/macros.rs create mode 100644 clap/src/args/matched_arg.rs create mode 100644 clap/src/args/mod.rs create mode 100644 clap/src/args/settings.rs create mode 100644 clap/src/args/subcommand.rs create mode 100644 clap/src/completions/bash.rs create mode 100644 clap/src/completions/elvish.rs create mode 100644 clap/src/completions/fish.rs create mode 100644 clap/src/completions/macros.rs create mode 100644 clap/src/completions/mod.rs create mode 100644 clap/src/completions/powershell.rs create mode 100644 clap/src/completions/shell.rs create mode 100644 clap/src/completions/zsh.rs create mode 100644 clap/src/errors.rs create mode 100644 clap/src/fmt.rs create mode 100644 clap/src/lib.rs create mode 100644 clap/src/macros.rs create mode 100644 clap/src/map.rs create mode 100644 clap/src/osstringext.rs create mode 100644 clap/src/strext.rs create mode 100644 clap/src/suggestions.rs create mode 100644 clap/src/usage_parser.rs create mode 100644 cloudabi/.cargo-checksum.json create mode 100644 cloudabi/Cargo.toml create mode 100644 cloudabi/bitflags.rs create mode 100644 cloudabi/cloudabi.rs create mode 100644 commoncrypto-sys/.cargo-checksum.json create mode 100644 commoncrypto-sys/.pc/.quilt_patches create mode 100644 commoncrypto-sys/.pc/.quilt_series create mode 100644 commoncrypto-sys/.pc/.version create mode 100644 commoncrypto-sys/.pc/applied-patches create mode 100644 commoncrypto-sys/.pc/no-clippy.patch/.timestamp create mode 100644 commoncrypto-sys/.pc/no-clippy.patch/Cargo.toml create mode 100644 commoncrypto-sys/Cargo.toml create mode 100644 commoncrypto-sys/debian/patches/no-clippy.patch create mode 100644 commoncrypto-sys/debian/patches/series create mode 100644 commoncrypto-sys/src/lib.rs create mode 100644 commoncrypto-sys/tests/hash.rs create mode 100644 commoncrypto-sys/tests/pbkdf2.rs create mode 100644 commoncrypto/.cargo-checksum.json create mode 100644 commoncrypto/.pc/.quilt_patches create mode 100644 commoncrypto/.pc/.quilt_series create mode 100644 commoncrypto/.pc/.version create mode 100644 commoncrypto/.pc/applied-patches create mode 100644 commoncrypto/.pc/no-clippy.patch/.timestamp create mode 100644 commoncrypto/.pc/no-clippy.patch/Cargo.toml create mode 100644 commoncrypto/Cargo.toml create mode 100644 commoncrypto/debian/patches/no-clippy.patch create mode 100644 commoncrypto/debian/patches/series create mode 100644 commoncrypto/src/hash.rs create mode 100644 commoncrypto/src/lib.rs create mode 100644 commoncrypto/src/pbkdf2.rs create mode 100644 commoncrypto/tests/hash.rs create mode 100644 commoncrypto/tests/pbkdf2.rs create mode 100644 core-foundation-sys/.cargo-checksum.json create mode 100644 core-foundation-sys/Cargo.toml create mode 100644 core-foundation-sys/LICENSE-APACHE create mode 100644 core-foundation-sys/LICENSE-MIT create mode 100644 core-foundation-sys/build.rs create mode 100644 core-foundation-sys/src/array.rs create mode 100644 core-foundation-sys/src/attributed_string.rs create mode 100644 core-foundation-sys/src/base.rs create mode 100644 core-foundation-sys/src/bundle.rs create mode 100644 core-foundation-sys/src/data.rs create mode 100644 core-foundation-sys/src/date.rs create mode 100644 core-foundation-sys/src/dictionary.rs create mode 100644 core-foundation-sys/src/error.rs create mode 100644 core-foundation-sys/src/filedescriptor.rs create mode 100644 core-foundation-sys/src/lib.rs create mode 100644 core-foundation-sys/src/messageport.rs create mode 100644 core-foundation-sys/src/number.rs create mode 100644 core-foundation-sys/src/propertylist.rs create mode 100644 core-foundation-sys/src/runloop.rs create mode 100644 core-foundation-sys/src/set.rs create mode 100644 core-foundation-sys/src/string.rs create mode 100644 core-foundation-sys/src/timezone.rs create mode 100644 core-foundation-sys/src/url.rs create mode 100644 core-foundation-sys/src/uuid.rs create mode 100644 core-foundation/.cargo-checksum.json create mode 100644 core-foundation/.pc/.quilt_patches create mode 100644 core-foundation/.pc/.quilt_series create mode 100644 core-foundation/.pc/.version create mode 100644 core-foundation/.pc/applied-patches create mode 100644 core-foundation/.pc/update-dep-uuid-version.patch/.timestamp create mode 100644 core-foundation/.pc/update-dep-uuid-version.patch/Cargo.toml create mode 100644 core-foundation/.pc/update-dep-uuid-version.patch/src/uuid.rs create mode 100644 core-foundation/Cargo.toml create mode 100644 core-foundation/LICENSE-APACHE create mode 100644 core-foundation/LICENSE-MIT create mode 100644 core-foundation/debian/patches/series create mode 100644 core-foundation/debian/patches/update-dep-uuid-version.patch create mode 100644 core-foundation/src/array.rs create mode 100644 core-foundation/src/attributed_string.rs create mode 100644 core-foundation/src/base.rs create mode 100644 core-foundation/src/boolean.rs create mode 100644 core-foundation/src/bundle.rs create mode 100644 core-foundation/src/data.rs create mode 100644 core-foundation/src/date.rs create mode 100644 core-foundation/src/dictionary.rs create mode 100644 core-foundation/src/error.rs create mode 100644 core-foundation/src/filedescriptor.rs create mode 100644 core-foundation/src/lib.rs create mode 100644 core-foundation/src/number.rs create mode 100644 core-foundation/src/propertylist.rs create mode 100644 core-foundation/src/runloop.rs create mode 100644 core-foundation/src/set.rs create mode 100644 core-foundation/src/string.rs create mode 100644 core-foundation/src/timezone.rs create mode 100644 core-foundation/src/url.rs create mode 100644 core-foundation/src/uuid.rs create mode 100644 core-foundation/tests/use_macro_outside_crate.rs create mode 100644 crc32fast/.cargo-checksum.json create mode 100644 crc32fast/Cargo.toml create mode 100644 crc32fast/LICENSE-APACHE create mode 100644 crc32fast/LICENSE-MIT create mode 100644 crc32fast/README.md create mode 100644 crc32fast/benches/bench.rs create mode 100644 crc32fast/build.rs create mode 100644 crc32fast/src/baseline.rs create mode 100644 crc32fast/src/combine.rs create mode 100644 crc32fast/src/lib.rs create mode 100644 crc32fast/src/specialized/aarch64.rs create mode 100644 crc32fast/src/specialized/mod.rs create mode 100644 crc32fast/src/specialized/pclmulqdq.rs create mode 100644 crc32fast/src/table.rs create mode 100644 crossbeam-channel/.cargo-checksum.json create mode 100644 crossbeam-channel/.pc/.quilt_patches create mode 100644 crossbeam-channel/.pc/.quilt_series create mode 100644 crossbeam-channel/.pc/.version create mode 100644 crossbeam-channel/.pc/applied-patches create mode 100644 crossbeam-channel/.pc/relax-dep-version.patch/.timestamp create mode 100644 crossbeam-channel/.pc/relax-dep-version.patch/Cargo.toml create mode 100644 crossbeam-channel/CHANGELOG.md create mode 100644 crossbeam-channel/Cargo.toml create mode 100644 crossbeam-channel/LICENSE-APACHE create mode 100644 crossbeam-channel/LICENSE-MIT create mode 100644 crossbeam-channel/LICENSE-THIRD-PARTY create mode 100644 crossbeam-channel/README.md create mode 100644 crossbeam-channel/debian/patches/relax-dep-version.patch create mode 100644 crossbeam-channel/debian/patches/series create mode 100644 crossbeam-channel/examples/fibonacci.rs create mode 100644 crossbeam-channel/examples/matching.rs create mode 100644 crossbeam-channel/examples/stopwatch.rs create mode 100644 crossbeam-channel/src/channel.rs create mode 100644 crossbeam-channel/src/context.rs create mode 100644 crossbeam-channel/src/counter.rs create mode 100644 crossbeam-channel/src/err.rs create mode 100644 crossbeam-channel/src/flavors/after.rs create mode 100644 crossbeam-channel/src/flavors/array.rs create mode 100644 crossbeam-channel/src/flavors/list.rs create mode 100644 crossbeam-channel/src/flavors/mod.rs create mode 100644 crossbeam-channel/src/flavors/never.rs create mode 100644 crossbeam-channel/src/flavors/tick.rs create mode 100644 crossbeam-channel/src/flavors/zero.rs create mode 100644 crossbeam-channel/src/lib.rs create mode 100644 crossbeam-channel/src/select.rs create mode 100644 crossbeam-channel/src/select_macro.rs create mode 100644 crossbeam-channel/src/utils.rs create mode 100644 crossbeam-channel/src/waker.rs create mode 100644 crossbeam-channel/tests/after.rs create mode 100644 crossbeam-channel/tests/array.rs create mode 100644 crossbeam-channel/tests/golang.rs create mode 100644 crossbeam-channel/tests/iter.rs create mode 100644 crossbeam-channel/tests/list.rs create mode 100644 crossbeam-channel/tests/mpsc.rs create mode 100644 crossbeam-channel/tests/never.rs create mode 100644 crossbeam-channel/tests/ready.rs create mode 100644 crossbeam-channel/tests/select.rs create mode 100644 crossbeam-channel/tests/select_macro.rs create mode 100644 crossbeam-channel/tests/thread_locals.rs create mode 100644 crossbeam-channel/tests/tick.rs create mode 100644 crossbeam-channel/tests/zero.rs create mode 100644 crossbeam-utils/.cargo-checksum.json create mode 100644 crossbeam-utils/CHANGELOG.md create mode 100644 crossbeam-utils/Cargo.toml create mode 100644 crossbeam-utils/LICENSE-APACHE create mode 100644 crossbeam-utils/LICENSE-MIT create mode 100644 crossbeam-utils/README.md create mode 100644 crossbeam-utils/benches/atomic_cell.rs create mode 100644 crossbeam-utils/src/atomic/atomic_cell.rs create mode 100644 crossbeam-utils/src/atomic/consume.rs create mode 100644 crossbeam-utils/src/atomic/mod.rs create mode 100644 crossbeam-utils/src/backoff.rs create mode 100644 crossbeam-utils/src/cache_padded.rs create mode 100644 crossbeam-utils/src/lib.rs create mode 100644 crossbeam-utils/src/sync/mod.rs create mode 100644 crossbeam-utils/src/sync/parker.rs create mode 100644 crossbeam-utils/src/sync/sharded_lock.rs create mode 100644 crossbeam-utils/src/sync/wait_group.rs create mode 100644 crossbeam-utils/src/thread.rs create mode 100644 crossbeam-utils/tests/atomic_cell.rs create mode 100644 crossbeam-utils/tests/cache_padded.rs create mode 100644 crossbeam-utils/tests/parker.rs create mode 100644 crossbeam-utils/tests/sharded_lock.rs create mode 100644 crossbeam-utils/tests/thread.rs create mode 100644 crossbeam-utils/tests/wait_group.rs create mode 100644 crypto-hash/.cargo-checksum.json create mode 100644 crypto-hash/CONTRIBUTING.md create mode 100644 crypto-hash/Cargo.toml create mode 100644 crypto-hash/LICENSE create mode 100644 crypto-hash/Makefile create mode 100644 crypto-hash/NEWS.md create mode 100644 crypto-hash/README.md create mode 100644 crypto-hash/src/imp/commoncrypto.rs create mode 100644 crypto-hash/src/imp/cryptoapi.rs create mode 100644 crypto-hash/src/imp/openssl.rs create mode 100644 crypto-hash/src/lib.rs create mode 100644 crypto-hash/src/test.rs create mode 100644 curl-sys/.cargo-checksum.json create mode 100644 curl-sys/.pc/.quilt_patches create mode 100644 curl-sys/.pc/.quilt_series create mode 100644 curl-sys/.pc/.version create mode 100644 curl-sys/.pc/applied-patches create mode 100644 curl-sys/.pc/disable-vendor.patch/.timestamp create mode 100644 curl-sys/.pc/disable-vendor.patch/Cargo.toml create mode 100644 curl-sys/Cargo.toml create mode 100644 curl-sys/LICENSE create mode 100644 curl-sys/build.rs create mode 100644 curl-sys/debian/patches/disable-vendor.patch create mode 100644 curl-sys/debian/patches/series create mode 100644 curl-sys/lib.rs create mode 100644 curl/.cargo-checksum.json create mode 100644 curl/.pc/.quilt_patches create mode 100644 curl/.pc/.quilt_series create mode 100644 curl/.pc/.version create mode 100644 curl/.pc/applied-patches create mode 100644 curl/.pc/winapi3.patch/.timestamp create mode 100644 curl/.pc/winapi3.patch/Cargo.toml create mode 100644 curl/.pc/winapi3.patch/src/easy/windows.rs create mode 100644 curl/.pc/winapi3.patch/src/lib.rs create mode 100644 curl/.pc/winapi3.patch/src/multi.rs create mode 100644 curl/Cargo.toml create mode 100644 curl/LICENSE create mode 100644 curl/README.md create mode 100644 curl/azure-pipelines.yml create mode 100644 curl/build.rs create mode 100644 curl/ci/Dockerfile-centos7 create mode 100644 curl/ci/Dockerfile-linux32 create mode 100644 curl/ci/Dockerfile-linux64 create mode 100644 curl/ci/Dockerfile-linux64-curl create mode 100644 curl/ci/Dockerfile-mingw create mode 100644 curl/ci/Dockerfile-musl create mode 100644 curl/ci/azure-install-rust.yml create mode 100644 curl/ci/azure-steps.yml create mode 100755 curl/ci/run.sh create mode 100644 curl/debian/patches/series create mode 100644 curl/debian/patches/winapi3.patch create mode 100644 curl/src/easy/form.rs create mode 100644 curl/src/easy/handle.rs create mode 100644 curl/src/easy/handler.rs create mode 100644 curl/src/easy/list.rs create mode 100644 curl/src/easy/mod.rs create mode 100644 curl/src/easy/windows.rs create mode 100644 curl/src/error.rs create mode 100644 curl/src/lib.rs create mode 100644 curl/src/multi.rs create mode 100644 curl/src/panic.rs create mode 100644 curl/src/version.rs create mode 100644 curl/tests/atexit.rs create mode 100644 curl/tests/easy.rs create mode 100644 curl/tests/formdata create mode 100644 curl/tests/multi.rs create mode 100644 curl/tests/post.rs create mode 100644 curl/tests/server/mod.rs create mode 100644 env_logger/.cargo-checksum.json create mode 100644 env_logger/Cargo.toml create mode 100644 env_logger/LICENSE-APACHE create mode 100644 env_logger/LICENSE-MIT create mode 100644 env_logger/README.md create mode 100644 env_logger/examples/custom_default_format.rs create mode 100644 env_logger/examples/custom_format.rs create mode 100644 env_logger/examples/custom_logger.rs create mode 100644 env_logger/examples/default.rs create mode 100644 env_logger/examples/direct_logger.rs create mode 100644 env_logger/src/filter/mod.rs create mode 100644 env_logger/src/filter/regex.rs create mode 100644 env_logger/src/filter/string.rs create mode 100644 env_logger/src/fmt/humantime/extern_impl.rs create mode 100644 env_logger/src/fmt/humantime/mod.rs create mode 100644 env_logger/src/fmt/humantime/shim_impl.rs create mode 100644 env_logger/src/fmt/mod.rs create mode 100644 env_logger/src/fmt/writer/atty.rs create mode 100644 env_logger/src/fmt/writer/mod.rs create mode 100644 env_logger/src/fmt/writer/termcolor/extern_impl.rs create mode 100644 env_logger/src/fmt/writer/termcolor/mod.rs create mode 100644 env_logger/src/fmt/writer/termcolor/shim_impl.rs create mode 100644 env_logger/src/lib.rs create mode 100644 env_logger/tests/init-twice-retains-filter.rs create mode 100644 env_logger/tests/log-in-log.rs create mode 100644 env_logger/tests/regexp_filter.rs create mode 100644 failure/.cargo-checksum.json create mode 100644 failure/CODE_OF_CONDUCT.md create mode 100644 failure/Cargo.lock.ci create mode 100644 failure/Cargo.toml create mode 100644 failure/LICENSE-APACHE create mode 100644 failure/LICENSE-MIT create mode 100644 failure/Makefile create mode 100644 failure/README.md create mode 100644 failure/RELEASES.md create mode 100644 failure/book/src/SUMMARY.md create mode 100644 failure/book/src/bail-and-ensure.md create mode 100644 failure/book/src/custom-fail.md create mode 100644 failure/book/src/derive-fail.md create mode 100644 failure/book/src/error-errorkind.md create mode 100644 failure/book/src/error-msg.md create mode 100644 failure/book/src/error.md create mode 100644 failure/book/src/fail.md create mode 100644 failure/book/src/guidance.md create mode 100644 failure/book/src/howto.md create mode 100644 failure/book/src/intro.md create mode 100644 failure/book/src/string-custom-error.md create mode 100644 failure/book/src/use-error.md create mode 100755 failure/build-docs.sh create mode 100644 failure/examples/bail_ensure.rs create mode 100644 failure/examples/error_as_cause.rs create mode 100644 failure/examples/simple.rs create mode 100644 failure/examples/string_custom_error_pattern.rs create mode 100644 failure/src/as_fail.rs create mode 100644 failure/src/backtrace/internal.rs create mode 100644 failure/src/backtrace/mod.rs create mode 100644 failure/src/box_std.rs create mode 100644 failure/src/compat.rs create mode 100644 failure/src/context.rs create mode 100644 failure/src/error/error_impl.rs create mode 100644 failure/src/error/error_impl_small.rs create mode 100644 failure/src/error/mod.rs create mode 100644 failure/src/error_message.rs create mode 100644 failure/src/lib.rs create mode 100644 failure/src/macros.rs create mode 100644 failure/src/result_ext.rs create mode 100644 failure/src/small_error.rs create mode 100644 failure/src/sync_failure.rs create mode 100644 failure/tests/basic_fail.rs create mode 100644 failure/tests/fail_compat.rs create mode 100644 failure/tests/macro_trailing_comma.rs create mode 100644 failure/travis.sh create mode 100644 failure_derive/.cargo-checksum.json create mode 100644 failure_derive/Cargo.toml create mode 100644 failure_derive/build.rs create mode 100644 failure_derive/src/lib.rs create mode 100644 failure_derive/tests/backtrace.rs create mode 100644 failure_derive/tests/custom_type_bounds.rs create mode 100644 failure_derive/tests/no_derive_display.rs create mode 100644 failure_derive/tests/tests.rs create mode 100644 failure_derive/tests/wraps.rs create mode 100644 filetime/.cargo-checksum.json create mode 100644 filetime/Cargo.toml create mode 100644 filetime/LICENSE-APACHE create mode 100644 filetime/LICENSE-MIT create mode 100644 filetime/README.md create mode 100644 filetime/appveyor.yml create mode 100644 filetime/src/lib.rs create mode 100644 filetime/src/redox.rs create mode 100644 filetime/src/unix/linux.rs create mode 100644 filetime/src/unix/mod.rs create mode 100644 filetime/src/unix/utimensat.rs create mode 100644 filetime/src/unix/utimes.rs create mode 100644 filetime/src/wasm.rs create mode 100644 filetime/src/windows.rs create mode 100644 flate2/.cargo-checksum.json create mode 100644 flate2/.pc/.quilt_patches create mode 100644 flate2/.pc/.quilt_series create mode 100644 flate2/.pc/.version create mode 100644 flate2/.pc/applied-patches create mode 100644 flate2/.pc/disable-miniz.patch/.timestamp create mode 100644 flate2/.pc/disable-miniz.patch/Cargo.toml create mode 100644 flate2/Cargo.toml create mode 100644 flate2/LICENSE-APACHE create mode 100644 flate2/LICENSE-MIT create mode 100644 flate2/README.md create mode 100644 flate2/azure-pipelines.yml create mode 100644 flate2/ci/azure-install-rust.yml create mode 100644 flate2/ci/azure-job-test-all.yml create mode 100644 flate2/debian/patches/disable-miniz.patch create mode 100644 flate2/debian/patches/series create mode 100644 flate2/examples/deflatedecoder-bufread.rs create mode 100644 flate2/examples/deflatedecoder-read.rs create mode 100644 flate2/examples/deflatedecoder-write.rs create mode 100644 flate2/examples/deflateencoder-bufread.rs create mode 100644 flate2/examples/deflateencoder-read.rs create mode 100644 flate2/examples/deflateencoder-write.rs create mode 100644 flate2/examples/gzbuilder.rs create mode 100644 flate2/examples/gzdecoder-bufread.rs create mode 100644 flate2/examples/gzdecoder-read.rs create mode 100644 flate2/examples/gzdecoder-write.rs create mode 100644 flate2/examples/gzencoder-bufread.rs create mode 100644 flate2/examples/gzencoder-read.rs create mode 100644 flate2/examples/gzencoder-write.rs create mode 100644 flate2/examples/gzmultidecoder-bufread.rs create mode 100644 flate2/examples/gzmultidecoder-read.rs create mode 100644 flate2/examples/hello_world.txt create mode 100644 flate2/examples/zlibdecoder-bufread.rs create mode 100644 flate2/examples/zlibdecoder-read.rs create mode 100644 flate2/examples/zlibdecoder-write.rs create mode 100644 flate2/examples/zlibencoder-bufread.rs create mode 100644 flate2/examples/zlibencoder-read.rs create mode 100644 flate2/examples/zlibencoder-write.rs create mode 100644 flate2/src/bufreader.rs create mode 100644 flate2/src/crc.rs create mode 100644 flate2/src/deflate/bufread.rs create mode 100644 flate2/src/deflate/mod.rs create mode 100644 flate2/src/deflate/read.rs create mode 100644 flate2/src/deflate/write.rs create mode 100644 flate2/src/ffi.rs create mode 100644 flate2/src/gz/bufread.rs create mode 100644 flate2/src/gz/mod.rs create mode 100644 flate2/src/gz/read.rs create mode 100644 flate2/src/gz/write.rs create mode 100644 flate2/src/lib.rs create mode 100644 flate2/src/mem.rs create mode 100644 flate2/src/zio.rs create mode 100644 flate2/src/zlib/bufread.rs create mode 100644 flate2/src/zlib/mod.rs create mode 100644 flate2/src/zlib/read.rs create mode 100644 flate2/src/zlib/write.rs create mode 100644 flate2/tests/async-reader.rs create mode 100644 flate2/tests/corrupt-file.gz create mode 100644 flate2/tests/early-flush.rs create mode 100644 flate2/tests/empty-read.rs create mode 100644 flate2/tests/good-file.gz create mode 100644 flate2/tests/good-file.txt create mode 100644 flate2/tests/gunzip.rs create mode 100644 flate2/tests/multi.gz create mode 100644 flate2/tests/multi.txt create mode 100644 flate2/tests/tokio.rs create mode 100644 flate2/tests/zero-write.rs create mode 100644 fnv/.cargo-checksum.json create mode 100644 fnv/Cargo.toml create mode 100644 fnv/LICENSE-APACHE create mode 100644 fnv/LICENSE-MIT create mode 100644 fnv/README.md create mode 100644 fnv/lib.rs create mode 100644 foreign-types-shared/.cargo-checksum.json create mode 100644 foreign-types-shared/Cargo.toml create mode 100644 foreign-types-shared/LICENSE-APACHE create mode 100644 foreign-types-shared/LICENSE-MIT create mode 100644 foreign-types-shared/src/lib.rs create mode 100644 foreign-types/.cargo-checksum.json create mode 100644 foreign-types/Cargo.toml create mode 100644 foreign-types/LICENSE-APACHE create mode 100644 foreign-types/LICENSE-MIT create mode 100644 foreign-types/README.md create mode 100644 foreign-types/src/lib.rs create mode 100644 fs2/.cargo-checksum.json create mode 100644 fs2/Cargo.toml create mode 100644 fs2/LICENSE-APACHE create mode 100644 fs2/LICENSE-MIT create mode 100644 fs2/README.md create mode 100644 fs2/src/lib.rs create mode 100644 fs2/src/unix.rs create mode 100644 fs2/src/windows.rs create mode 100644 fuchsia-cprng/.cargo-checksum.json create mode 100644 fuchsia-cprng/AUTHORS create mode 100644 fuchsia-cprng/Cargo.toml create mode 100644 fuchsia-cprng/LICENSE create mode 100644 fuchsia-cprng/PATENTS create mode 100644 fuchsia-cprng/src/lib.rs create mode 100644 fwdansi/.cargo-checksum.json create mode 100644 fwdansi/Cargo.toml create mode 100644 fwdansi/appveyor.yml create mode 100644 fwdansi/examples/run-rustc.rs create mode 100644 fwdansi/src/lib.rs create mode 100644 fwdansi/tests/tests.proptest-regressions create mode 100644 fwdansi/tests/tests.rs create mode 100644 git2-curl/.cargo-checksum.json create mode 100644 git2-curl/Cargo.toml create mode 100644 git2-curl/LICENSE-APACHE create mode 100644 git2-curl/LICENSE-MIT create mode 100644 git2-curl/src/lib.rs create mode 100644 git2-curl/tests/all.rs create mode 100644 git2/.cargo-checksum.json create mode 100644 git2/.pc/.quilt_patches create mode 100644 git2/.pc/.quilt_series create mode 100644 git2/.pc/.version create mode 100644 git2/.pc/applied-patches create mode 100644 git2/.pc/disable-vendor.patch/.timestamp create mode 100644 git2/.pc/disable-vendor.patch/Cargo.toml create mode 100644 git2/Cargo.toml create mode 100644 git2/LICENSE-APACHE create mode 100644 git2/LICENSE-MIT create mode 100644 git2/README.md create mode 100644 git2/appveyor.yml create mode 100644 git2/debian/patches/disable-vendor.patch create mode 100644 git2/debian/patches/series create mode 100644 git2/examples/add.rs create mode 100644 git2/examples/blame.rs create mode 100644 git2/examples/cat-file.rs create mode 100644 git2/examples/clone.rs create mode 100644 git2/examples/diff.rs create mode 100644 git2/examples/fetch.rs create mode 100644 git2/examples/init.rs create mode 100644 git2/examples/log.rs create mode 100644 git2/examples/ls-remote.rs create mode 100644 git2/examples/rev-list.rs create mode 100644 git2/examples/rev-parse.rs create mode 100644 git2/examples/status.rs create mode 100644 git2/examples/tag.rs create mode 100644 git2/src/blame.rs create mode 100644 git2/src/blob.rs create mode 100644 git2/src/branch.rs create mode 100644 git2/src/buf.rs create mode 100644 git2/src/build.rs create mode 100644 git2/src/call.rs create mode 100644 git2/src/cert.rs create mode 100644 git2/src/commit.rs create mode 100644 git2/src/config.rs create mode 100644 git2/src/cred.rs create mode 100644 git2/src/describe.rs create mode 100644 git2/src/diff.rs create mode 100644 git2/src/error.rs create mode 100644 git2/src/index.rs create mode 100644 git2/src/lib.rs create mode 100644 git2/src/merge.rs create mode 100644 git2/src/message.rs create mode 100644 git2/src/note.rs create mode 100644 git2/src/object.rs create mode 100644 git2/src/odb.rs create mode 100644 git2/src/oid.rs create mode 100644 git2/src/oid_array.rs create mode 100644 git2/src/packbuilder.rs create mode 100644 git2/src/panic.rs create mode 100644 git2/src/patch.rs create mode 100644 git2/src/pathspec.rs create mode 100644 git2/src/proxy_options.rs create mode 100644 git2/src/rebase.rs create mode 100644 git2/src/reference.rs create mode 100644 git2/src/reflog.rs create mode 100644 git2/src/refspec.rs create mode 100644 git2/src/remote.rs create mode 100644 git2/src/remote_callbacks.rs create mode 100644 git2/src/repo.rs create mode 100644 git2/src/revspec.rs create mode 100644 git2/src/revwalk.rs create mode 100644 git2/src/signature.rs create mode 100644 git2/src/stash.rs create mode 100644 git2/src/status.rs create mode 100644 git2/src/string_array.rs create mode 100644 git2/src/submodule.rs create mode 100644 git2/src/tag.rs create mode 100644 git2/src/test.rs create mode 100644 git2/src/time.rs create mode 100644 git2/src/transport.rs create mode 100644 git2/src/tree.rs create mode 100644 git2/src/treebuilder.rs create mode 100644 git2/src/util.rs create mode 100644 glob/.cargo-checksum.json create mode 100644 glob/Cargo.toml create mode 100644 glob/LICENSE-APACHE create mode 100644 glob/LICENSE-MIT create mode 100644 glob/README.md create mode 100644 glob/src/lib.rs create mode 100644 glob/tests/glob-std.rs create mode 100644 globset/.cargo-checksum.json create mode 100644 globset/COPYING create mode 100644 globset/Cargo.toml create mode 100644 globset/LICENSE-MIT create mode 100644 globset/README.md create mode 100644 globset/UNLICENSE create mode 100644 globset/benches/bench.rs create mode 100644 globset/src/glob.rs create mode 100644 globset/src/lib.rs create mode 100644 globset/src/pathutil.rs create mode 100644 hex/.cargo-checksum.json create mode 100644 hex/Cargo.toml create mode 100644 hex/Dockerfile create mode 100644 hex/LICENSE-APACHE create mode 100644 hex/LICENSE-MIT create mode 100644 hex/README.md create mode 100644 hex/src/lib.rs create mode 100644 home/.cargo-checksum.json create mode 100644 home/Cargo.toml create mode 100644 home/README.md create mode 100644 home/src/lib.rs create mode 100644 http/.cargo-checksum.json create mode 100644 http/CHANGELOG.md create mode 100644 http/Cargo.toml create mode 100644 http/LICENSE-APACHE create mode 100644 http/LICENSE-MIT create mode 100644 http/README.md create mode 100644 http/benches/header_map/basic.rs create mode 100644 http/benches/header_map/mod.rs create mode 100644 http/benches/header_map/vec_map.rs create mode 100644 http/benches/header_value.rs create mode 100644 http/benches/uri.rs create mode 100644 http/src/byte_str.rs create mode 100644 http/src/convert.rs create mode 100644 http/src/error.rs create mode 100644 http/src/extensions.rs create mode 100644 http/src/header/map.rs create mode 100644 http/src/header/mod.rs create mode 100644 http/src/header/name.rs create mode 100644 http/src/header/value.rs create mode 100644 http/src/lib.rs create mode 100644 http/src/method.rs create mode 100644 http/src/request.rs create mode 100644 http/src/response.rs create mode 100644 http/src/status.rs create mode 100644 http/src/uri/authority.rs create mode 100644 http/src/uri/builder.rs create mode 100644 http/src/uri/mod.rs create mode 100644 http/src/uri/path.rs create mode 100644 http/src/uri/port.rs create mode 100644 http/src/uri/scheme.rs create mode 100644 http/src/uri/tests.rs create mode 100644 http/src/version.rs create mode 100644 http/tests/header_map.rs create mode 100644 http/tests/header_map_fuzz.rs create mode 100644 http/tests/status_code.rs create mode 100644 humantime/.cargo-checksum.json create mode 100644 humantime/Cargo.toml create mode 100644 humantime/LICENSE-APACHE create mode 100644 humantime/LICENSE-MIT create mode 100644 humantime/README.md create mode 100644 humantime/benches/datetime_format.rs create mode 100644 humantime/benches/datetime_parse.rs create mode 100644 humantime/bulk.yaml create mode 100644 humantime/src/date.rs create mode 100644 humantime/src/duration.rs create mode 100644 humantime/src/lib.rs create mode 100644 humantime/src/wrapper.rs create mode 100644 humantime/vagga.yaml create mode 100644 idna/.cargo-checksum.json create mode 100644 idna/Cargo.toml create mode 100644 idna/LICENSE-APACHE create mode 100644 idna/LICENSE-MIT create mode 100644 idna/src/IdnaMappingTable.txt create mode 100644 idna/src/lib.rs create mode 100644 idna/src/make_uts46_mapping_table.py create mode 100644 idna/src/punycode.rs create mode 100644 idna/src/uts46.rs create mode 100644 idna/src/uts46_mapping_table.rs create mode 100644 idna/tests/IdnaTest.txt create mode 100644 idna/tests/punycode.rs create mode 100644 idna/tests/punycode_tests.json create mode 100644 idna/tests/tests.rs create mode 100644 idna/tests/unit.rs create mode 100644 idna/tests/uts46.rs create mode 100644 ignore/.cargo-checksum.json create mode 100644 ignore/COPYING create mode 100644 ignore/Cargo.toml create mode 100644 ignore/LICENSE-MIT create mode 100644 ignore/README.md create mode 100644 ignore/UNLICENSE create mode 100644 ignore/examples/walk.rs create mode 100644 ignore/src/dir.rs create mode 100644 ignore/src/gitignore.rs create mode 100644 ignore/src/lib.rs create mode 100644 ignore/src/overrides.rs create mode 100644 ignore/src/pathutil.rs create mode 100644 ignore/src/types.rs create mode 100644 ignore/src/walk.rs create mode 100644 ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore create mode 100644 ignore/tests/gitignore_matched_path_or_any_parents_tests.rs create mode 100644 im-rc/.cargo-checksum.json create mode 100644 im-rc/CHANGELOG.md create mode 100644 im-rc/CODE_OF_CONDUCT.md create mode 100644 im-rc/Cargo.toml create mode 100644 im-rc/LICENCE.md create mode 100644 im-rc/README.md create mode 100644 im-rc/build.rs create mode 100644 im-rc/proptest-regressions/hash/map.txt create mode 100644 im-rc/proptest-regressions/hash/set.txt create mode 100644 im-rc/proptest-regressions/ord/map create mode 100644 im-rc/proptest-regressions/ord/map.txt create mode 100644 im-rc/proptest-regressions/ser.txt create mode 100644 im-rc/proptest-regressions/sort.txt create mode 100644 im-rc/proptest-regressions/tests/vector.txt create mode 100644 im-rc/proptest-regressions/vector/mod.txt create mode 100644 im-rc/src/config.rs create mode 100644 im-rc/src/hash/map.rs create mode 100644 im-rc/src/hash/mod.rs create mode 100644 im-rc/src/hash/set.rs create mode 100644 im-rc/src/iter.rs create mode 100644 im-rc/src/lib.rs create mode 100644 im-rc/src/nodes/btree.rs create mode 100644 im-rc/src/nodes/hamt.rs create mode 100644 im-rc/src/nodes/mod.rs create mode 100644 im-rc/src/nodes/rrb.rs create mode 100644 im-rc/src/ord/map.rs create mode 100644 im-rc/src/ord/mod.rs create mode 100644 im-rc/src/ord/set.rs create mode 100644 im-rc/src/ser.rs create mode 100644 im-rc/src/sort.rs create mode 100644 im-rc/src/sync.rs create mode 100644 im-rc/src/test.rs create mode 100644 im-rc/src/tests/hashset.rs create mode 100644 im-rc/src/tests/mod.rs create mode 100644 im-rc/src/tests/ordset.rs create mode 100644 im-rc/src/tests/vector.rs create mode 100644 im-rc/src/util.rs create mode 100644 im-rc/src/vector/focus.rs create mode 100644 im-rc/src/vector/mod.rs create mode 100644 iovec/.cargo-checksum.json create mode 100644 iovec/.pc/.quilt_patches create mode 100644 iovec/.pc/.quilt_series create mode 100644 iovec/.pc/.version create mode 100644 iovec/.pc/applied-patches create mode 100644 iovec/.pc/b90b433-backport.patch/.timestamp create mode 100644 iovec/.pc/b90b433-backport.patch/Cargo.toml create mode 100644 iovec/.pc/b90b433-backport.patch/src/sys/windows.rs create mode 100644 iovec/CHANGELOG.md create mode 100644 iovec/Cargo.toml create mode 100644 iovec/LICENSE-APACHE create mode 100644 iovec/LICENSE-MIT create mode 100644 iovec/README.md create mode 100644 iovec/appveyor.yml create mode 100644 iovec/debian/patches/b90b433-backport.patch create mode 100644 iovec/debian/patches/series create mode 100644 iovec/src/lib.rs create mode 100644 iovec/src/sys/mod.rs create mode 100644 iovec/src/sys/unix.rs create mode 100644 iovec/src/sys/unknown.rs create mode 100644 iovec/src/sys/windows.rs create mode 100644 iovec/src/unix.rs create mode 100644 iovec/src/windows.rs create mode 100644 itoa/.cargo-checksum.json create mode 100644 itoa/Cargo.toml create mode 100644 itoa/LICENSE-APACHE create mode 100644 itoa/LICENSE-MIT create mode 100644 itoa/README.md create mode 100644 itoa/benches/bench.rs create mode 100644 itoa/src/lib.rs create mode 100644 itoa/src/udiv128.rs create mode 100644 itoa/tests/test.rs create mode 100644 jobserver/.cargo-checksum.json create mode 100644 jobserver/.pc/.quilt_patches create mode 100644 jobserver/.pc/.quilt_series create mode 100644 jobserver/.pc/.version create mode 100644 jobserver/.pc/applied-patches create mode 100644 jobserver/.pc/relax-dep-version.patch/.timestamp create mode 100644 jobserver/.pc/relax-dep-version.patch/Cargo.toml create mode 100644 jobserver/Cargo.toml create mode 100644 jobserver/LICENSE-APACHE create mode 100644 jobserver/LICENSE-MIT create mode 100644 jobserver/README.md create mode 100644 jobserver/debian/patches/relax-dep-version.patch create mode 100644 jobserver/debian/patches/series create mode 100644 jobserver/src/lib.rs create mode 100644 jobserver/tests/client-of-myself.rs create mode 100644 jobserver/tests/client.rs create mode 100644 jobserver/tests/helper.rs create mode 100644 jobserver/tests/make-as-a-client.rs create mode 100644 jobserver/tests/server.rs create mode 100644 lazy_static/.cargo-checksum.json create mode 100644 lazy_static/Cargo.toml create mode 100644 lazy_static/LICENSE-APACHE create mode 100644 lazy_static/LICENSE-MIT create mode 100644 lazy_static/README.md create mode 100644 lazy_static/src/core_lazy.rs create mode 100644 lazy_static/src/inline_lazy.rs create mode 100644 lazy_static/src/lib.rs create mode 100644 lazy_static/tests/no_std.rs create mode 100644 lazy_static/tests/test.rs create mode 100644 lazycell/.cargo-checksum.json create mode 100644 lazycell/.pc/.quilt_patches create mode 100644 lazycell/.pc/.quilt_series create mode 100644 lazycell/.pc/.version create mode 100644 lazycell/.pc/applied-patches create mode 100644 lazycell/.pc/no-clippy.patch/.timestamp create mode 100644 lazycell/.pc/no-clippy.patch/Cargo.toml create mode 100644 lazycell/CHANGELOG.md create mode 100644 lazycell/Cargo.toml create mode 100644 lazycell/LICENSE-APACHE create mode 100644 lazycell/LICENSE-MIT create mode 100644 lazycell/README.md create mode 100644 lazycell/debian/patches/no-clippy.patch create mode 100644 lazycell/debian/patches/series create mode 100644 lazycell/src/lib.rs create mode 100644 libc/.cargo-checksum.json create mode 100644 libc/CONTRIBUTING.md create mode 100644 libc/Cargo.toml create mode 100644 libc/LICENSE-APACHE create mode 100644 libc/LICENSE-MIT create mode 100644 libc/README.md create mode 100644 libc/build.rs create mode 100644 libc/rustfmt.toml create mode 100644 libc/src/cloudabi/aarch64.rs create mode 100644 libc/src/cloudabi/arm.rs create mode 100644 libc/src/cloudabi/mod.rs create mode 100644 libc/src/cloudabi/x86.rs create mode 100644 libc/src/cloudabi/x86_64.rs create mode 100644 libc/src/fuchsia/aarch64.rs create mode 100644 libc/src/fuchsia/align.rs create mode 100644 libc/src/fuchsia/mod.rs create mode 100644 libc/src/fuchsia/no_align.rs create mode 100644 libc/src/fuchsia/x86_64.rs create mode 100644 libc/src/hermit/aarch64.rs create mode 100644 libc/src/hermit/mod.rs create mode 100644 libc/src/hermit/x86_64.rs create mode 100644 libc/src/lib.rs create mode 100644 libc/src/macros.rs create mode 100644 libc/src/sgx.rs create mode 100644 libc/src/switch.rs create mode 100644 libc/src/unix/align.rs create mode 100644 libc/src/unix/bsd/apple/b32.rs create mode 100644 libc/src/unix/bsd/apple/b64.rs create mode 100644 libc/src/unix/bsd/apple/mod.rs create mode 100644 libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/arm.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/mod.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/x86.rs create mode 100644 libc/src/unix/bsd/freebsdlike/freebsd/x86_64.rs create mode 100644 libc/src/unix/bsd/freebsdlike/mod.rs create mode 100644 libc/src/unix/bsd/mod.rs create mode 100644 libc/src/unix/bsd/netbsdlike/mod.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/arm.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/mod.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/x86.rs create mode 100644 libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs create mode 100644 libc/src/unix/bsd/netbsdlike/openbsdlike/mod.rs create mode 100644 libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/aarch64.rs create mode 100644 libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/mod.rs create mode 100644 libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86.rs create mode 100644 libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86_64.rs create mode 100644 libc/src/unix/haiku/b32.rs create mode 100644 libc/src/unix/haiku/b64.rs create mode 100644 libc/src/unix/haiku/mod.rs create mode 100644 libc/src/unix/hermit/aarch64.rs create mode 100644 libc/src/unix/hermit/mod.rs create mode 100644 libc/src/unix/hermit/x86_64.rs create mode 100644 libc/src/unix/mod.rs create mode 100644 libc/src/unix/newlib/aarch64/mod.rs create mode 100644 libc/src/unix/newlib/align.rs create mode 100644 libc/src/unix/newlib/arm/mod.rs create mode 100644 libc/src/unix/newlib/mod.rs create mode 100644 libc/src/unix/newlib/no_align.rs create mode 100644 libc/src/unix/no_align.rs create mode 100644 libc/src/unix/notbsd/android/b32/arm.rs create mode 100644 libc/src/unix/notbsd/android/b32/mod.rs create mode 100644 libc/src/unix/notbsd/android/b32/x86.rs create mode 100644 libc/src/unix/notbsd/android/b64/aarch64.rs create mode 100644 libc/src/unix/notbsd/android/b64/mod.rs create mode 100644 libc/src/unix/notbsd/android/b64/x86_64.rs create mode 100644 libc/src/unix/notbsd/android/mod.rs create mode 100644 libc/src/unix/notbsd/emscripten/align.rs create mode 100644 libc/src/unix/notbsd/emscripten/mod.rs create mode 100644 libc/src/unix/notbsd/emscripten/no_align.rs create mode 100644 libc/src/unix/notbsd/linux/align.rs create mode 100644 libc/src/unix/notbsd/linux/mips/align.rs create mode 100644 libc/src/unix/notbsd/linux/mips/mips32.rs create mode 100644 libc/src/unix/notbsd/linux/mips/mips64.rs create mode 100644 libc/src/unix/notbsd/linux/mips/mod.rs create mode 100644 libc/src/unix/notbsd/linux/mips/no_align.rs create mode 100644 libc/src/unix/notbsd/linux/mod.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b32/arm.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b32/mips.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b32/mod.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b32/powerpc.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b32/x86.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b64/aarch64.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b64/mod.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b64/powerpc64.rs create mode 100644 libc/src/unix/notbsd/linux/musl/b64/x86_64.rs create mode 100644 libc/src/unix/notbsd/linux/musl/mod.rs create mode 100644 libc/src/unix/notbsd/linux/no_align.rs create mode 100644 libc/src/unix/notbsd/linux/other/align.rs create mode 100644 libc/src/unix/notbsd/linux/other/b32/arm.rs create mode 100644 libc/src/unix/notbsd/linux/other/b32/mod.rs create mode 100644 libc/src/unix/notbsd/linux/other/b32/powerpc.rs create mode 100644 libc/src/unix/notbsd/linux/other/b32/x86.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/aarch64.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/mod.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/not_x32.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/powerpc64.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/sparc64.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/x32.rs create mode 100644 libc/src/unix/notbsd/linux/other/b64/x86_64.rs create mode 100644 libc/src/unix/notbsd/linux/other/mod.rs create mode 100644 libc/src/unix/notbsd/linux/other/no_align.rs create mode 100644 libc/src/unix/notbsd/linux/s390x/align.rs create mode 100644 libc/src/unix/notbsd/linux/s390x/mod.rs create mode 100644 libc/src/unix/notbsd/linux/s390x/no_align.rs create mode 100644 libc/src/unix/notbsd/mod.rs create mode 100644 libc/src/unix/redox/mod.rs create mode 100644 libc/src/unix/solarish/compat.rs create mode 100644 libc/src/unix/solarish/mod.rs create mode 100644 libc/src/unix/uclibc/align.rs create mode 100644 libc/src/unix/uclibc/arm/align.rs create mode 100644 libc/src/unix/uclibc/arm/mod.rs create mode 100644 libc/src/unix/uclibc/arm/no_align.rs create mode 100644 libc/src/unix/uclibc/mips/mips32/align.rs create mode 100644 libc/src/unix/uclibc/mips/mips32/mod.rs create mode 100644 libc/src/unix/uclibc/mips/mips32/no_align.rs create mode 100644 libc/src/unix/uclibc/mips/mips64/align.rs create mode 100644 libc/src/unix/uclibc/mips/mips64/mod.rs create mode 100644 libc/src/unix/uclibc/mips/mips64/no_align.rs create mode 100644 libc/src/unix/uclibc/mips/mod.rs create mode 100644 libc/src/unix/uclibc/mod.rs create mode 100644 libc/src/unix/uclibc/no_align.rs create mode 100644 libc/src/unix/uclibc/x86_64/align.rs create mode 100644 libc/src/unix/uclibc/x86_64/l4re.rs create mode 100644 libc/src/unix/uclibc/x86_64/mod.rs create mode 100644 libc/src/unix/uclibc/x86_64/no_align.rs create mode 100644 libc/src/unix/uclibc/x86_64/other.rs create mode 100644 libc/src/wasi.rs create mode 100644 libc/src/windows/gnu.rs create mode 100644 libc/src/windows/mod.rs create mode 100644 libc/src/windows/msvc.rs create mode 100644 libgit2-sys/.cargo-checksum.json create mode 100644 libgit2-sys/.pc/.quilt_patches create mode 100644 libgit2-sys/.pc/.quilt_series create mode 100644 libgit2-sys/.pc/.version create mode 100644 libgit2-sys/.pc/applied-patches create mode 100644 libgit2-sys/.pc/no-special-snowflake-env.patch/.timestamp create mode 100644 libgit2-sys/.pc/no-special-snowflake-env.patch/build.rs create mode 100644 libgit2-sys/Cargo.toml create mode 100644 libgit2-sys/LICENSE-APACHE create mode 100644 libgit2-sys/LICENSE-MIT create mode 100644 libgit2-sys/build.rs create mode 100644 libgit2-sys/debian/patches/no-special-snowflake-env.patch create mode 100644 libgit2-sys/debian/patches/series create mode 100644 libgit2-sys/lib.rs create mode 100644 libnghttp2-sys/.cargo-checksum.json create mode 100644 libnghttp2-sys/.pc/.quilt_patches create mode 100644 libnghttp2-sys/.pc/.quilt_series create mode 100644 libnghttp2-sys/.pc/.version create mode 100644 libnghttp2-sys/.pc/applied-patches create mode 100644 libnghttp2-sys/.pc/use-system-lib.patch/.timestamp create mode 100644 libnghttp2-sys/.pc/use-system-lib.patch/Cargo.toml create mode 100644 libnghttp2-sys/Cargo.toml create mode 100644 libnghttp2-sys/LICENSE-APACHE create mode 100644 libnghttp2-sys/LICENSE-MIT create mode 100644 libnghttp2-sys/README.md create mode 100644 libnghttp2-sys/build.rs create mode 100644 libnghttp2-sys/build.rs.orig create mode 100644 libnghttp2-sys/debian/patches/series create mode 100644 libnghttp2-sys/debian/patches/use-system-lib.patch create mode 100644 libnghttp2-sys/examples/smoke.rs create mode 100644 libnghttp2-sys/src/lib.rs create mode 100644 libssh2-sys/.cargo-checksum.json create mode 100644 libssh2-sys/.pc/.quilt_patches create mode 100644 libssh2-sys/.pc/.quilt_series create mode 100644 libssh2-sys/.pc/.version create mode 100644 libssh2-sys/.pc/applied-patches create mode 100644 libssh2-sys/.pc/no-special-snowflake-env.patch/.timestamp create mode 100644 libssh2-sys/.pc/no-special-snowflake-env.patch/build.rs create mode 100644 libssh2-sys/Cargo.toml create mode 100644 libssh2-sys/build.rs create mode 100644 libssh2-sys/debian/patches/no-special-snowflake-env.patch create mode 100644 libssh2-sys/debian/patches/series create mode 100644 libssh2-sys/lib.rs create mode 100644 libz-sys/.cargo-checksum.json create mode 100644 libz-sys/Cargo.toml create mode 100644 libz-sys/LICENSE-APACHE create mode 100644 libz-sys/LICENSE-MIT create mode 100644 libz-sys/README.md create mode 100644 libz-sys/appveyor.yml create mode 100644 libz-sys/build.rs create mode 100644 libz-sys/ci/Dockerfile create mode 100755 libz-sys/ci/run-docker.sh create mode 100644 libz-sys/src/lib.rs create mode 100644 libz-sys/src/smoke.c create mode 100644 log/.cargo-checksum.json create mode 100644 log/CHANGELOG.md create mode 100644 log/Cargo.toml create mode 100644 log/LICENSE-APACHE create mode 100644 log/LICENSE-MIT create mode 100644 log/README.md create mode 100644 log/appveyor.yml create mode 100644 log/src/lib.rs create mode 100644 log/src/macros.rs create mode 100644 log/src/serde.rs create mode 100644 log/tests/filters.rs create mode 100644 matches/.cargo-checksum.json create mode 100644 matches/Cargo.toml create mode 100644 matches/LICENSE create mode 100644 matches/lib.rs create mode 100644 matches/tests/macro_use_one.rs create mode 100644 memchr/.cargo-checksum.json create mode 100644 memchr/COPYING create mode 100644 memchr/Cargo.toml create mode 100644 memchr/LICENSE-MIT create mode 100644 memchr/README.md create mode 100644 memchr/UNLICENSE create mode 100644 memchr/build.rs create mode 100644 memchr/src/c.rs create mode 100644 memchr/src/fallback.rs create mode 100644 memchr/src/iter.rs create mode 100644 memchr/src/lib.rs create mode 100644 memchr/src/naive.rs create mode 100644 memchr/src/tests/iter.rs create mode 100644 memchr/src/tests/memchr.rs create mode 100644 memchr/src/tests/mod.rs create mode 100644 memchr/src/x86/avx.rs create mode 100644 memchr/src/x86/mod.rs create mode 100644 memchr/src/x86/sse2.rs create mode 100644 memchr/src/x86/sse42.rs create mode 100644 miow/.cargo-checksum.json create mode 100644 miow/Cargo.toml create mode 100644 miow/LICENSE-APACHE create mode 100644 miow/LICENSE-MIT create mode 100644 miow/README.md create mode 100644 miow/appveyor.yml create mode 100644 miow/src/handle.rs create mode 100644 miow/src/iocp.rs create mode 100644 miow/src/lib.rs create mode 100644 miow/src/net.rs create mode 100644 miow/src/overlapped.rs create mode 100644 miow/src/pipe.rs create mode 100644 num-integer/.cargo-checksum.json create mode 100644 num-integer/Cargo.toml create mode 100644 num-integer/LICENSE-APACHE create mode 100644 num-integer/LICENSE-MIT create mode 100644 num-integer/README.md create mode 100644 num-integer/RELEASES.md create mode 100644 num-integer/benches/gcd.rs create mode 100644 num-integer/benches/roots.rs create mode 100644 num-integer/build.rs create mode 100644 num-integer/src/lib.rs create mode 100644 num-integer/src/roots.rs create mode 100644 num-integer/tests/roots.rs create mode 100644 num-traits/.cargo-checksum.json create mode 100644 num-traits/Cargo.toml create mode 100644 num-traits/LICENSE-APACHE create mode 100644 num-traits/LICENSE-MIT create mode 100644 num-traits/README.md create mode 100644 num-traits/RELEASES.md create mode 100644 num-traits/build.rs create mode 100644 num-traits/src/bounds.rs create mode 100644 num-traits/src/cast.rs create mode 100644 num-traits/src/float.rs create mode 100644 num-traits/src/identities.rs create mode 100644 num-traits/src/int.rs create mode 100644 num-traits/src/lib.rs create mode 100644 num-traits/src/macros.rs create mode 100644 num-traits/src/ops/checked.rs create mode 100644 num-traits/src/ops/inv.rs create mode 100644 num-traits/src/ops/mod.rs create mode 100644 num-traits/src/ops/mul_add.rs create mode 100644 num-traits/src/ops/saturating.rs create mode 100644 num-traits/src/ops/wrapping.rs create mode 100644 num-traits/src/pow.rs create mode 100644 num-traits/src/real.rs create mode 100644 num-traits/src/sign.rs create mode 100644 num-traits/tests/cast.rs create mode 100644 num_cpus/.cargo-checksum.json create mode 100644 num_cpus/CHANGELOG.md create mode 100644 num_cpus/CONTRIBUTING.md create mode 100644 num_cpus/Cargo.toml create mode 100644 num_cpus/LICENSE-APACHE create mode 100644 num_cpus/LICENSE-MIT create mode 100644 num_cpus/README.md create mode 100644 num_cpus/src/lib.rs create mode 100644 numtoa/.cargo-checksum.json create mode 100644 numtoa/Cargo.toml create mode 100644 numtoa/LICENSE-APACHE create mode 100644 numtoa/LICENSE-MIT create mode 100644 numtoa/README.md create mode 100644 numtoa/src/lib.rs create mode 100644 opener/.cargo-checksum.json create mode 100644 opener/.pc/.quilt_patches create mode 100644 opener/.pc/.quilt_series create mode 100644 opener/.pc/.version create mode 100644 opener/.pc/applied-patches create mode 100644 opener/.pc/disable-vendor.patch/.timestamp create mode 100644 opener/.pc/disable-vendor.patch/src/lib.rs create mode 100644 opener/Cargo.toml create mode 100644 opener/LICENSE-APACHE create mode 100644 opener/LICENSE-MIT create mode 100644 opener/LICENSE-THIRD-PARTY create mode 100644 opener/debian/patches/disable-vendor.patch create mode 100644 opener/debian/patches/series create mode 100644 opener/src/lib.rs create mode 100644 openssl-probe/.cargo-checksum.json create mode 100644 openssl-probe/Cargo.toml create mode 100644 openssl-probe/LICENSE-APACHE create mode 100644 openssl-probe/LICENSE-MIT create mode 100644 openssl-probe/README.md create mode 100644 openssl-probe/src/lib.rs create mode 100644 openssl-sys/.cargo-checksum.json create mode 100644 openssl-sys/.pc/.quilt_patches create mode 100644 openssl-sys/.pc/.quilt_series create mode 100644 openssl-sys/.pc/.version create mode 100644 openssl-sys/.pc/applied-patches create mode 100644 openssl-sys/.pc/disable-vendor.patch/.timestamp create mode 100644 openssl-sys/.pc/disable-vendor.patch/Cargo.toml create mode 100644 openssl-sys/CHANGELOG.md create mode 100644 openssl-sys/Cargo.toml create mode 100644 openssl-sys/LICENSE-MIT create mode 100644 openssl-sys/README.md create mode 100644 openssl-sys/build/cfgs.rs create mode 100644 openssl-sys/build/expando.c create mode 100644 openssl-sys/build/find_normal.rs create mode 100644 openssl-sys/build/find_vendored.rs create mode 100644 openssl-sys/build/main.rs create mode 100644 openssl-sys/debian/patches/disable-vendor.patch create mode 100644 openssl-sys/debian/patches/series create mode 100644 openssl-sys/src/aes.rs create mode 100644 openssl-sys/src/asn1.rs create mode 100644 openssl-sys/src/bio.rs create mode 100644 openssl-sys/src/bn.rs create mode 100644 openssl-sys/src/cms.rs create mode 100644 openssl-sys/src/conf.rs create mode 100644 openssl-sys/src/crypto.rs create mode 100644 openssl-sys/src/dh.rs create mode 100644 openssl-sys/src/dsa.rs create mode 100644 openssl-sys/src/dtls1.rs create mode 100644 openssl-sys/src/ec.rs create mode 100644 openssl-sys/src/err.rs create mode 100644 openssl-sys/src/evp.rs create mode 100644 openssl-sys/src/hmac.rs create mode 100644 openssl-sys/src/lib.rs create mode 100644 openssl-sys/src/macros.rs create mode 100644 openssl-sys/src/obj_mac.rs create mode 100644 openssl-sys/src/object.rs create mode 100644 openssl-sys/src/ocsp.rs create mode 100644 openssl-sys/src/ossl_typ.rs create mode 100644 openssl-sys/src/pem.rs create mode 100644 openssl-sys/src/pkcs12.rs create mode 100644 openssl-sys/src/pkcs7.rs create mode 100644 openssl-sys/src/rand.rs create mode 100644 openssl-sys/src/rsa.rs create mode 100644 openssl-sys/src/safestack.rs create mode 100644 openssl-sys/src/sha.rs create mode 100644 openssl-sys/src/srtp.rs create mode 100644 openssl-sys/src/ssl.rs create mode 100644 openssl-sys/src/ssl3.rs create mode 100644 openssl-sys/src/stack.rs create mode 100644 openssl-sys/src/tls1.rs create mode 100644 openssl-sys/src/x509.rs create mode 100644 openssl-sys/src/x509_vfy.rs create mode 100644 openssl-sys/src/x509v3.rs create mode 100644 openssl/.cargo-checksum.json create mode 100644 openssl/.pc/.quilt_patches create mode 100644 openssl/.pc/.quilt_series create mode 100644 openssl/.pc/.version create mode 100644 openssl/.pc/applied-patches create mode 100644 openssl/.pc/disable-vendor.patch/.timestamp create mode 100644 openssl/.pc/disable-vendor.patch/Cargo.toml create mode 100644 openssl/CHANGELOG.md create mode 100644 openssl/Cargo.toml create mode 100644 openssl/LICENSE create mode 100644 openssl/README.md create mode 100644 openssl/build.rs create mode 100644 openssl/debian/patches/disable-vendor.patch create mode 100644 openssl/debian/patches/series create mode 100644 openssl/examples/mk_certs.rs create mode 100644 openssl/src/aes.rs create mode 100644 openssl/src/asn1.rs create mode 100644 openssl/src/bio.rs create mode 100644 openssl/src/bn.rs create mode 100644 openssl/src/cms.rs create mode 100644 openssl/src/conf.rs create mode 100644 openssl/src/derive.rs create mode 100644 openssl/src/dh.rs create mode 100644 openssl/src/dsa.rs create mode 100644 openssl/src/ec.rs create mode 100644 openssl/src/ecdsa.rs create mode 100644 openssl/src/envelope.rs create mode 100644 openssl/src/error.rs create mode 100644 openssl/src/ex_data.rs create mode 100644 openssl/src/fips.rs create mode 100644 openssl/src/hash.rs create mode 100644 openssl/src/lib.rs create mode 100644 openssl/src/macros.rs create mode 100644 openssl/src/memcmp.rs create mode 100644 openssl/src/nid.rs create mode 100644 openssl/src/ocsp.rs create mode 100644 openssl/src/pkcs12.rs create mode 100644 openssl/src/pkcs5.rs create mode 100644 openssl/src/pkcs7.rs create mode 100644 openssl/src/pkey.rs create mode 100644 openssl/src/rand.rs create mode 100644 openssl/src/rsa.rs create mode 100644 openssl/src/sha.rs create mode 100644 openssl/src/sign.rs create mode 100644 openssl/src/srtp.rs create mode 100644 openssl/src/ssl/bio.rs create mode 100644 openssl/src/ssl/callbacks.rs create mode 100644 openssl/src/ssl/connector.rs create mode 100644 openssl/src/ssl/error.rs create mode 100644 openssl/src/ssl/mod.rs create mode 100644 openssl/src/ssl/test/mod.rs create mode 100644 openssl/src/ssl/test/server.rs create mode 100644 openssl/src/stack.rs create mode 100644 openssl/src/string.rs create mode 100644 openssl/src/symm.rs create mode 100644 openssl/src/util.rs create mode 100644 openssl/src/version.rs create mode 100644 openssl/src/x509/extension.rs create mode 100644 openssl/src/x509/mod.rs create mode 100644 openssl/src/x509/store.rs create mode 100644 openssl/src/x509/tests.rs create mode 100644 openssl/src/x509/verify.rs create mode 100644 openssl/test/alt_name_cert.pem create mode 100644 openssl/test/cert.pem create mode 100644 openssl/test/certs.pem create mode 100644 openssl/test/cms.p12 create mode 100644 openssl/test/cms_pubkey.der create mode 100644 openssl/test/dhparams.pem create mode 100644 openssl/test/dsa.pem create mode 100644 openssl/test/dsa.pem.pub create mode 100644 openssl/test/dsaparam.pem create mode 100644 openssl/test/identity.p12 create mode 100644 openssl/test/key.der create mode 100644 openssl/test/key.der.pub create mode 100644 openssl/test/key.pem create mode 100644 openssl/test/key.pem.pub create mode 100644 openssl/test/keystore-empty-chain.p12 create mode 100644 openssl/test/nid_test_cert.pem create mode 100644 openssl/test/nid_uid_test_cert.pem create mode 100644 openssl/test/pkcs1.pem.pub create mode 100644 openssl/test/pkcs8.der create mode 100644 openssl/test/root-ca.key create mode 100644 openssl/test/root-ca.pem create mode 100644 openssl/test/rsa-encrypted.pem create mode 100644 openssl/test/rsa.pem create mode 100644 openssl/test/rsa.pem.pub create mode 100644 percent-encoding/.cargo-checksum.json create mode 100644 percent-encoding/Cargo.toml create mode 100644 percent-encoding/LICENSE-APACHE create mode 100644 percent-encoding/LICENSE-MIT create mode 100644 percent-encoding/lib.rs create mode 100644 pkg-config/.cargo-checksum.json create mode 100644 pkg-config/.pc/.quilt_patches create mode 100644 pkg-config/.pc/.quilt_series create mode 100644 pkg-config/.pc/.version create mode 100644 pkg-config/.pc/applied-patches create mode 100644 pkg-config/.pc/no-special-snowflake-env.patch/.timestamp create mode 100644 pkg-config/.pc/no-special-snowflake-env.patch/src/lib.rs create mode 100644 pkg-config/.pc/no-special-snowflake-env.patch/tests/test.rs create mode 100644 pkg-config/CHANGELOG.md create mode 100644 pkg-config/Cargo.toml create mode 100644 pkg-config/LICENSE-APACHE create mode 100644 pkg-config/LICENSE-MIT create mode 100644 pkg-config/README.md create mode 100644 pkg-config/debian/patches/no-special-snowflake-env.patch create mode 100644 pkg-config/debian/patches/series create mode 100644 pkg-config/src/lib.rs create mode 100644 pkg-config/tests/escape.pc create mode 100644 pkg-config/tests/foo.pc create mode 100644 pkg-config/tests/framework.pc create mode 100644 pkg-config/tests/test.rs create mode 100644 pretty_env_logger/.cargo-checksum.json create mode 100644 pretty_env_logger/Cargo.toml create mode 100644 pretty_env_logger/LICENSE-APACHE create mode 100644 pretty_env_logger/LICENSE-MIT create mode 100644 pretty_env_logger/src/lib.rs create mode 100644 proc-macro2/.cargo-checksum.json create mode 100644 proc-macro2/Cargo.toml create mode 100644 proc-macro2/LICENSE-APACHE create mode 100644 proc-macro2/LICENSE-MIT create mode 100644 proc-macro2/README.md create mode 100644 proc-macro2/build.rs create mode 100644 proc-macro2/src/fallback.rs create mode 100644 proc-macro2/src/lib.rs create mode 100644 proc-macro2/src/strnom.rs create mode 100644 proc-macro2/src/wrapper.rs create mode 100644 proc-macro2/tests/marker.rs create mode 100644 proc-macro2/tests/test.rs create mode 100644 proptest/.cargo-checksum.json create mode 100644 proptest/CHANGELOG.md create mode 100644 proptest/Cargo.toml create mode 100644 proptest/LICENSE-APACHE create mode 100644 proptest/LICENSE-MIT create mode 100644 proptest/README.md create mode 100644 proptest/appveyor.yml create mode 100644 proptest/examples/config-defaults.rs create mode 100644 proptest/examples/dateparser_v1.rs create mode 100644 proptest/examples/dateparser_v2.rs create mode 100644 proptest/examples/fib.rs create mode 100644 proptest/examples/tutorial-simplify-play.rs create mode 100644 proptest/examples/tutorial-strategy-play.rs create mode 100755 proptest/gen-readme.sh create mode 100644 proptest/proptest-regressions/arbitrary/_std/env.txt create mode 100644 proptest/readme-antelogue.md create mode 100644 proptest/readme-prologue.md create mode 100644 proptest/src/arbitrary/_alloc/alloc.rs create mode 100644 proptest/src/arbitrary/_alloc/borrow.rs create mode 100644 proptest/src/arbitrary/_alloc/boxed.rs create mode 100644 proptest/src/arbitrary/_alloc/char.rs create mode 100644 proptest/src/arbitrary/_alloc/collections.rs create mode 100644 proptest/src/arbitrary/_alloc/hash.rs create mode 100644 proptest/src/arbitrary/_alloc/mod.rs create mode 100644 proptest/src/arbitrary/_alloc/ops.rs create mode 100644 proptest/src/arbitrary/_alloc/rc.rs create mode 100644 proptest/src/arbitrary/_alloc/str.rs create mode 100644 proptest/src/arbitrary/_alloc/sync.rs create mode 100644 proptest/src/arbitrary/_core/ascii.rs create mode 100644 proptest/src/arbitrary/_core/cell.rs create mode 100644 proptest/src/arbitrary/_core/cmp.rs create mode 100644 proptest/src/arbitrary/_core/convert.rs create mode 100644 proptest/src/arbitrary/_core/fmt.rs create mode 100644 proptest/src/arbitrary/_core/iter.rs create mode 100644 proptest/src/arbitrary/_core/marker.rs create mode 100644 proptest/src/arbitrary/_core/mem.rs create mode 100644 proptest/src/arbitrary/_core/mod.rs create mode 100644 proptest/src/arbitrary/_core/num.rs create mode 100644 proptest/src/arbitrary/_core/option.rs create mode 100644 proptest/src/arbitrary/_core/result.rs create mode 100644 proptest/src/arbitrary/_std/env.rs create mode 100644 proptest/src/arbitrary/_std/ffi.rs create mode 100644 proptest/src/arbitrary/_std/fs.rs create mode 100644 proptest/src/arbitrary/_std/io.rs create mode 100644 proptest/src/arbitrary/_std/mod.rs create mode 100644 proptest/src/arbitrary/_std/net.rs create mode 100644 proptest/src/arbitrary/_std/panic.rs create mode 100644 proptest/src/arbitrary/_std/path.rs create mode 100644 proptest/src/arbitrary/_std/string.rs create mode 100644 proptest/src/arbitrary/_std/sync.rs create mode 100644 proptest/src/arbitrary/_std/thread.rs create mode 100644 proptest/src/arbitrary/_std/time.rs create mode 100644 proptest/src/arbitrary/arrays.rs create mode 100644 proptest/src/arbitrary/functor.rs create mode 100644 proptest/src/arbitrary/macros.rs create mode 100644 proptest/src/arbitrary/mod.rs create mode 100644 proptest/src/arbitrary/primitives.rs create mode 100644 proptest/src/arbitrary/sample.rs create mode 100644 proptest/src/arbitrary/traits.rs create mode 100644 proptest/src/arbitrary/tuples.rs create mode 100644 proptest/src/array.rs create mode 100644 proptest/src/bits.rs create mode 100644 proptest/src/bool.rs create mode 100644 proptest/src/char.rs create mode 100644 proptest/src/collection.rs create mode 100644 proptest/src/file-preamble create mode 100644 proptest/src/lib.rs create mode 100644 proptest/src/macros.rs create mode 100644 proptest/src/num.rs create mode 100644 proptest/src/option.rs create mode 100644 proptest/src/prelude.rs create mode 100644 proptest/src/product_frunk.rs create mode 100644 proptest/src/product_tuple.rs create mode 100644 proptest/src/regex-contrib/README.md create mode 100644 proptest/src/regex-contrib/crates_regex.rs create mode 100644 proptest/src/result.rs create mode 100644 proptest/src/sample.rs create mode 100644 proptest/src/std_facade.rs create mode 100644 proptest/src/strategy/filter.rs create mode 100644 proptest/src/strategy/filter_map.rs create mode 100644 proptest/src/strategy/flatten.rs create mode 100644 proptest/src/strategy/fuse.rs create mode 100644 proptest/src/strategy/just.rs create mode 100644 proptest/src/strategy/map.rs create mode 100644 proptest/src/strategy/mod.rs create mode 100644 proptest/src/strategy/recursive.rs create mode 100644 proptest/src/strategy/shuffle.rs create mode 100644 proptest/src/strategy/statics.rs create mode 100644 proptest/src/strategy/traits.rs create mode 100644 proptest/src/strategy/unions.rs create mode 100644 proptest/src/string.rs create mode 100644 proptest/src/sugar.rs create mode 100644 proptest/src/test_runner/config.rs create mode 100644 proptest/src/test_runner/errors.rs create mode 100644 proptest/src/test_runner/failure_persistence/file.rs create mode 100644 proptest/src/test_runner/failure_persistence/map.rs create mode 100644 proptest/src/test_runner/failure_persistence/mod.rs create mode 100644 proptest/src/test_runner/failure_persistence/noop.rs create mode 100644 proptest/src/test_runner/mod.rs create mode 100644 proptest/src/test_runner/reason.rs create mode 100644 proptest/src/test_runner/replay.rs create mode 100644 proptest/src/test_runner/result_cache.rs create mode 100644 proptest/src/test_runner/rng.rs create mode 100644 proptest/src/test_runner/runner.rs create mode 100644 proptest/src/tuple.rs create mode 100644 proptest/test-persistence-location/README.md create mode 100644 proptest/test-persistence-location/run-tests.bat create mode 100755 proptest/test-persistence-location/run-tests.sh create mode 100644 quick-error/.cargo-checksum.json create mode 100644 quick-error/Cargo.toml create mode 100644 quick-error/LICENSE-APACHE create mode 100644 quick-error/LICENSE-MIT create mode 100644 quick-error/README.rst create mode 100644 quick-error/bulk.yaml create mode 100644 quick-error/examples/context.rs create mode 100644 quick-error/src/lib.rs create mode 100644 quick-error/vagga.yaml create mode 100644 quote/.cargo-checksum.json create mode 100644 quote/Cargo.toml create mode 100644 quote/LICENSE-APACHE create mode 100644 quote/LICENSE-MIT create mode 100644 quote/README.md create mode 100644 quote/src/ext.rs create mode 100644 quote/src/lib.rs create mode 100644 quote/src/runtime.rs create mode 100644 quote/src/to_tokens.rs create mode 100644 quote/tests/conditional/integer128.rs create mode 100644 quote/tests/test.rs create mode 100644 rand-0.5.6/.cargo-checksum.json create mode 100644 rand-0.5.6/CHANGELOG.md create mode 100644 rand-0.5.6/CONTRIBUTING.md create mode 100644 rand-0.5.6/Cargo.toml create mode 100644 rand-0.5.6/LICENSE-APACHE create mode 100644 rand-0.5.6/LICENSE-MIT create mode 100644 rand-0.5.6/README.md create mode 100644 rand-0.5.6/UPDATING.md create mode 100644 rand-0.5.6/appveyor.yml create mode 100644 rand-0.5.6/benches/distributions.rs create mode 100644 rand-0.5.6/benches/generators.rs create mode 100644 rand-0.5.6/benches/misc.rs create mode 100644 rand-0.5.6/examples/monte-carlo.rs create mode 100644 rand-0.5.6/examples/monty-hall.rs create mode 100644 rand-0.5.6/src/distributions/bernoulli.rs create mode 100644 rand-0.5.6/src/distributions/binomial.rs create mode 100644 rand-0.5.6/src/distributions/cauchy.rs create mode 100644 rand-0.5.6/src/distributions/exponential.rs create mode 100644 rand-0.5.6/src/distributions/float.rs create mode 100644 rand-0.5.6/src/distributions/gamma.rs create mode 100644 rand-0.5.6/src/distributions/integer.rs create mode 100644 rand-0.5.6/src/distributions/log_gamma.rs create mode 100644 rand-0.5.6/src/distributions/mod.rs create mode 100644 rand-0.5.6/src/distributions/normal.rs create mode 100644 rand-0.5.6/src/distributions/other.rs create mode 100644 rand-0.5.6/src/distributions/pareto.rs create mode 100644 rand-0.5.6/src/distributions/poisson.rs create mode 100644 rand-0.5.6/src/distributions/uniform.rs create mode 100644 rand-0.5.6/src/distributions/ziggurat_tables.rs create mode 100644 rand-0.5.6/src/lib.rs create mode 100644 rand-0.5.6/src/prelude.rs create mode 100644 rand-0.5.6/src/prng/chacha.rs create mode 100644 rand-0.5.6/src/prng/hc128.rs create mode 100644 rand-0.5.6/src/prng/isaac.rs create mode 100644 rand-0.5.6/src/prng/isaac64.rs create mode 100644 rand-0.5.6/src/prng/isaac_array.rs create mode 100644 rand-0.5.6/src/prng/mod.rs create mode 100644 rand-0.5.6/src/prng/xorshift.rs create mode 100644 rand-0.5.6/src/rngs/adapter/mod.rs create mode 100644 rand-0.5.6/src/rngs/adapter/read.rs create mode 100644 rand-0.5.6/src/rngs/adapter/reseeding.rs create mode 100644 rand-0.5.6/src/rngs/entropy.rs create mode 100644 rand-0.5.6/src/rngs/jitter.rs create mode 100644 rand-0.5.6/src/rngs/mock.rs create mode 100644 rand-0.5.6/src/rngs/mod.rs create mode 100644 rand-0.5.6/src/rngs/os.rs create mode 100644 rand-0.5.6/src/rngs/small.rs create mode 100644 rand-0.5.6/src/rngs/std.rs create mode 100644 rand-0.5.6/src/rngs/thread.rs create mode 100644 rand-0.5.6/src/seq.rs create mode 100644 rand-0.5.6/tests/bool.rs create mode 100644 rand-0.5.6/utils/ci/install.sh create mode 100644 rand-0.5.6/utils/ci/script.sh create mode 100755 rand-0.5.6/utils/ziggurat_tables.py create mode 100644 rand/.cargo-checksum.json create mode 100644 rand/CHANGELOG.md create mode 100644 rand/COPYRIGHT create mode 100644 rand/Cargo.toml create mode 100644 rand/LICENSE-APACHE create mode 100644 rand/LICENSE-MIT create mode 100644 rand/README.md create mode 100644 rand/benches/distributions.rs create mode 100644 rand/benches/generators.rs create mode 100644 rand/benches/misc.rs create mode 100644 rand/benches/seq.rs create mode 100644 rand/build.rs create mode 100644 rand/examples/monte-carlo.rs create mode 100644 rand/examples/monty-hall.rs create mode 100644 rand/src/deprecated.rs create mode 100644 rand/src/distributions/bernoulli.rs create mode 100644 rand/src/distributions/binomial.rs create mode 100644 rand/src/distributions/cauchy.rs create mode 100644 rand/src/distributions/dirichlet.rs create mode 100644 rand/src/distributions/exponential.rs create mode 100644 rand/src/distributions/float.rs create mode 100644 rand/src/distributions/gamma.rs create mode 100644 rand/src/distributions/integer.rs create mode 100644 rand/src/distributions/mod.rs create mode 100644 rand/src/distributions/normal.rs create mode 100644 rand/src/distributions/other.rs create mode 100644 rand/src/distributions/pareto.rs create mode 100644 rand/src/distributions/poisson.rs create mode 100644 rand/src/distributions/triangular.rs create mode 100644 rand/src/distributions/uniform.rs create mode 100644 rand/src/distributions/unit_circle.rs create mode 100644 rand/src/distributions/unit_sphere.rs create mode 100644 rand/src/distributions/utils.rs create mode 100644 rand/src/distributions/weibull.rs create mode 100644 rand/src/distributions/weighted.rs create mode 100644 rand/src/distributions/ziggurat_tables.rs create mode 100644 rand/src/lib.rs create mode 100644 rand/src/prelude.rs create mode 100644 rand/src/prng/mod.rs create mode 100644 rand/src/rngs/adapter/mod.rs create mode 100644 rand/src/rngs/adapter/read.rs create mode 100644 rand/src/rngs/adapter/reseeding.rs create mode 100644 rand/src/rngs/entropy.rs create mode 100644 rand/src/rngs/mock.rs create mode 100644 rand/src/rngs/mod.rs create mode 100644 rand/src/rngs/small.rs create mode 100644 rand/src/rngs/std.rs create mode 100644 rand/src/rngs/thread.rs create mode 100644 rand/src/seq/index.rs create mode 100644 rand/src/seq/mod.rs create mode 100644 rand/tests/uniformity.rs create mode 100644 rand_chacha/.cargo-checksum.json create mode 100644 rand_chacha/CHANGELOG.md create mode 100644 rand_chacha/COPYRIGHT create mode 100644 rand_chacha/Cargo.toml create mode 100644 rand_chacha/LICENSE-APACHE create mode 100644 rand_chacha/LICENSE-MIT create mode 100644 rand_chacha/README.md create mode 100644 rand_chacha/build.rs create mode 100644 rand_chacha/src/chacha.rs create mode 100644 rand_chacha/src/lib.rs create mode 100644 rand_core-0.3.1/.cargo-checksum.json create mode 100644 rand_core-0.3.1/CHANGELOG.md create mode 100644 rand_core-0.3.1/COPYRIGHT create mode 100644 rand_core-0.3.1/Cargo.toml create mode 100644 rand_core-0.3.1/LICENSE-APACHE create mode 100644 rand_core-0.3.1/LICENSE-MIT create mode 100644 rand_core-0.3.1/README.md create mode 100644 rand_core-0.3.1/src/block.rs create mode 100644 rand_core-0.3.1/src/error.rs create mode 100644 rand_core-0.3.1/src/impls.rs create mode 100644 rand_core-0.3.1/src/le.rs create mode 100644 rand_core-0.3.1/src/lib.rs create mode 100644 rand_core/.cargo-checksum.json create mode 100644 rand_core/CHANGELOG.md create mode 100644 rand_core/COPYRIGHT create mode 100644 rand_core/Cargo.toml create mode 100644 rand_core/LICENSE-APACHE create mode 100644 rand_core/LICENSE-MIT create mode 100644 rand_core/README.md create mode 100644 rand_core/src/block.rs create mode 100644 rand_core/src/error.rs create mode 100644 rand_core/src/impls.rs create mode 100644 rand_core/src/le.rs create mode 100644 rand_core/src/lib.rs create mode 100644 rand_hc/.cargo-checksum.json create mode 100644 rand_hc/CHANGELOG.md create mode 100644 rand_hc/COPYRIGHT create mode 100644 rand_hc/Cargo.toml create mode 100644 rand_hc/LICENSE-APACHE create mode 100644 rand_hc/LICENSE-MIT create mode 100644 rand_hc/README.md create mode 100644 rand_hc/src/hc128.rs create mode 100644 rand_hc/src/lib.rs create mode 100644 rand_isaac/.cargo-checksum.json create mode 100644 rand_isaac/CHANGELOG.md create mode 100644 rand_isaac/COPYRIGHT create mode 100644 rand_isaac/Cargo.toml create mode 100644 rand_isaac/LICENSE-APACHE create mode 100644 rand_isaac/LICENSE-MIT create mode 100644 rand_isaac/README.md create mode 100644 rand_isaac/src/isaac.rs create mode 100644 rand_isaac/src/isaac64.rs create mode 100644 rand_isaac/src/isaac_array.rs create mode 100644 rand_isaac/src/lib.rs create mode 100644 rand_jitter/.cargo-checksum.json create mode 100644 rand_jitter/CHANGELOG.md create mode 100644 rand_jitter/COPYRIGHT create mode 100644 rand_jitter/Cargo.toml create mode 100644 rand_jitter/LICENSE-APACHE create mode 100644 rand_jitter/LICENSE-MIT create mode 100644 rand_jitter/README.md create mode 100644 rand_jitter/benches/mod.rs create mode 100644 rand_jitter/src/dummy_log.rs create mode 100644 rand_jitter/src/error.rs create mode 100644 rand_jitter/src/lib.rs create mode 100644 rand_jitter/src/platform.rs create mode 100644 rand_jitter/tests/mod.rs create mode 100644 rand_os/.cargo-checksum.json create mode 100644 rand_os/CHANGELOG.md create mode 100644 rand_os/COPYRIGHT create mode 100644 rand_os/Cargo.toml create mode 100644 rand_os/LICENSE-APACHE create mode 100644 rand_os/LICENSE-MIT create mode 100644 rand_os/README.md create mode 100644 rand_os/src/cloudabi.rs create mode 100644 rand_os/src/dragonfly_haiku_emscripten.rs create mode 100644 rand_os/src/dummy_log.rs create mode 100644 rand_os/src/freebsd.rs create mode 100644 rand_os/src/fuchsia.rs create mode 100644 rand_os/src/lib.rs create mode 100644 rand_os/src/linux_android.rs create mode 100644 rand_os/src/macos.rs create mode 100644 rand_os/src/netbsd.rs create mode 100644 rand_os/src/openbsd_bitrig.rs create mode 100644 rand_os/src/random_device.rs create mode 100644 rand_os/src/redox.rs create mode 100644 rand_os/src/sgx.rs create mode 100644 rand_os/src/solarish.rs create mode 100644 rand_os/src/wasm32_bindgen.rs create mode 100644 rand_os/src/wasm32_stdweb.rs create mode 100644 rand_os/src/windows.rs create mode 100644 rand_os/tests/mod.rs create mode 100644 rand_pcg/.cargo-checksum.json create mode 100644 rand_pcg/CHANGELOG.md create mode 100644 rand_pcg/COPYRIGHT create mode 100644 rand_pcg/Cargo.toml create mode 100644 rand_pcg/LICENSE-APACHE create mode 100644 rand_pcg/LICENSE-MIT create mode 100644 rand_pcg/README.md create mode 100644 rand_pcg/build.rs create mode 100644 rand_pcg/src/lib.rs create mode 100644 rand_pcg/src/pcg128.rs create mode 100644 rand_pcg/src/pcg64.rs create mode 100644 rand_pcg/tests/lcg64xsh32.rs create mode 100644 rand_pcg/tests/mcg128xsl64.rs create mode 100644 rand_xorshift/.cargo-checksum.json create mode 100644 rand_xorshift/CHANGELOG.md create mode 100644 rand_xorshift/COPYRIGHT create mode 100644 rand_xorshift/Cargo.toml create mode 100644 rand_xorshift/LICENSE-APACHE create mode 100644 rand_xorshift/LICENSE-MIT create mode 100644 rand_xorshift/README.md create mode 100644 rand_xorshift/src/lib.rs create mode 100644 rand_xorshift/tests/mod.rs create mode 100644 rdrand/.cargo-checksum.json create mode 100644 rdrand/Cargo.toml create mode 100644 rdrand/LICENSE create mode 100644 rdrand/README.mkd create mode 100644 rdrand/appveyor.yml create mode 100644 rdrand/benches/rdrand.rs create mode 100644 rdrand/benches/rdseed.rs create mode 100644 rdrand/benches/std.rs create mode 100644 rdrand/src/changelog.rs create mode 100644 rdrand/src/lib.rs create mode 100644 redox_syscall/.cargo-checksum.json create mode 100644 redox_syscall/Cargo.toml create mode 100644 redox_syscall/LICENSE create mode 100644 redox_syscall/README.md create mode 100644 redox_syscall/src/arch/aarch64.rs create mode 100644 redox_syscall/src/arch/arm.rs create mode 100644 redox_syscall/src/arch/x86.rs create mode 100644 redox_syscall/src/arch/x86_64.rs create mode 100644 redox_syscall/src/call.rs create mode 100644 redox_syscall/src/data.rs create mode 100644 redox_syscall/src/error.rs create mode 100644 redox_syscall/src/flag.rs create mode 100644 redox_syscall/src/io/dma.rs create mode 100644 redox_syscall/src/io/io.rs create mode 100644 redox_syscall/src/io/mmio.rs create mode 100644 redox_syscall/src/io/mod.rs create mode 100644 redox_syscall/src/io/pio.rs create mode 100644 redox_syscall/src/lib.rs create mode 100644 redox_syscall/src/number.rs create mode 100755 redox_syscall/src/scheme/generate.sh create mode 100644 redox_syscall/src/scheme/mod.rs create mode 100644 redox_syscall/src/scheme/scheme.rs create mode 100644 redox_syscall/src/scheme/scheme_block.rs create mode 100644 redox_syscall/src/scheme/scheme_block_mut.rs create mode 100644 redox_syscall/src/scheme/scheme_mut.rs create mode 100644 redox_termios/.cargo-checksum.json create mode 100644 redox_termios/Cargo.toml create mode 100644 redox_termios/LICENSE create mode 100644 redox_termios/README.md create mode 100644 redox_termios/src/lib.rs create mode 100644 regex-syntax/.cargo-checksum.json create mode 100644 regex-syntax/Cargo.toml create mode 100644 regex-syntax/LICENSE-APACHE create mode 100644 regex-syntax/LICENSE-MIT create mode 100644 regex-syntax/benches/bench.rs create mode 100644 regex-syntax/src/ast/mod.rs create mode 100644 regex-syntax/src/ast/parse.rs create mode 100644 regex-syntax/src/ast/print.rs create mode 100644 regex-syntax/src/ast/visitor.rs create mode 100644 regex-syntax/src/either.rs create mode 100644 regex-syntax/src/error.rs create mode 100644 regex-syntax/src/hir/interval.rs create mode 100644 regex-syntax/src/hir/literal/mod.rs create mode 100644 regex-syntax/src/hir/mod.rs create mode 100644 regex-syntax/src/hir/print.rs create mode 100644 regex-syntax/src/hir/translate.rs create mode 100644 regex-syntax/src/hir/visitor.rs create mode 100644 regex-syntax/src/lib.rs create mode 100644 regex-syntax/src/parser.rs create mode 100644 regex-syntax/src/unicode.rs create mode 100644 regex-syntax/src/unicode_tables/LICENSE-UNICODE create mode 100644 regex-syntax/src/unicode_tables/age.rs create mode 100644 regex-syntax/src/unicode_tables/case_folding_simple.rs create mode 100644 regex-syntax/src/unicode_tables/general_category.rs create mode 100644 regex-syntax/src/unicode_tables/grapheme_cluster_break.rs create mode 100644 regex-syntax/src/unicode_tables/mod.rs create mode 100644 regex-syntax/src/unicode_tables/perl_word.rs create mode 100644 regex-syntax/src/unicode_tables/property_bool.rs create mode 100644 regex-syntax/src/unicode_tables/property_names.rs create mode 100644 regex-syntax/src/unicode_tables/property_values.rs create mode 100644 regex-syntax/src/unicode_tables/script.rs create mode 100644 regex-syntax/src/unicode_tables/script_extension.rs create mode 100644 regex-syntax/src/unicode_tables/sentence_break.rs create mode 100644 regex-syntax/src/unicode_tables/word_break.rs create mode 100644 regex/.cargo-checksum.json create mode 100644 regex/CHANGELOG.md create mode 100644 regex/Cargo.toml create mode 100644 regex/HACKING.md create mode 100644 regex/LICENSE-APACHE create mode 100644 regex/LICENSE-MIT create mode 100644 regex/PERFORMANCE.md create mode 100644 regex/README.md create mode 100644 regex/UNICODE.md create mode 100644 regex/build.rs create mode 100644 regex/examples/regexdna-input.txt create mode 100644 regex/examples/regexdna-output.txt create mode 100644 regex/examples/shootout-regex-dna-bytes.rs create mode 100644 regex/examples/shootout-regex-dna-cheat.rs create mode 100644 regex/examples/shootout-regex-dna-replace.rs create mode 100644 regex/examples/shootout-regex-dna-single-cheat.rs create mode 100644 regex/examples/shootout-regex-dna-single.rs create mode 100644 regex/examples/shootout-regex-dna.rs create mode 100644 regex/rustfmt.toml create mode 100644 regex/src/backtrack.rs create mode 100644 regex/src/compile.rs create mode 100644 regex/src/dfa.rs create mode 100644 regex/src/error.rs create mode 100644 regex/src/exec.rs create mode 100644 regex/src/expand.rs create mode 100644 regex/src/freqs.rs create mode 100644 regex/src/input.rs create mode 100644 regex/src/lib.rs create mode 100644 regex/src/literal/mod.rs create mode 100644 regex/src/literal/teddy_avx2/fallback.rs create mode 100644 regex/src/literal/teddy_avx2/imp.rs create mode 100644 regex/src/literal/teddy_avx2/mod.rs create mode 100644 regex/src/literal/teddy_ssse3/fallback.rs create mode 100644 regex/src/literal/teddy_ssse3/imp.rs create mode 100644 regex/src/literal/teddy_ssse3/mod.rs create mode 100644 regex/src/pattern.rs create mode 100644 regex/src/pikevm.rs create mode 100644 regex/src/prog.rs create mode 100644 regex/src/re_builder.rs create mode 100644 regex/src/re_bytes.rs create mode 100644 regex/src/re_set.rs create mode 100644 regex/src/re_trait.rs create mode 100644 regex/src/re_unicode.rs create mode 100644 regex/src/sparse.rs create mode 100644 regex/src/testdata/LICENSE create mode 100644 regex/src/testdata/README create mode 100644 regex/src/testdata/basic.dat create mode 100644 regex/src/testdata/nullsubexpr.dat create mode 100644 regex/src/testdata/repetition.dat create mode 100644 regex/src/utf8.rs create mode 100644 regex/src/vector/avx2.rs create mode 100644 regex/src/vector/mod.rs create mode 100644 regex/src/vector/ssse3.rs create mode 100644 regex/tests/api.rs create mode 100644 regex/tests/api_str.rs create mode 100644 regex/tests/bytes.rs create mode 100644 regex/tests/consistent.rs create mode 100644 regex/tests/crates_regex.rs create mode 100644 regex/tests/crazy.rs create mode 100644 regex/tests/flags.rs create mode 100644 regex/tests/fowler.rs create mode 100644 regex/tests/macros.rs create mode 100644 regex/tests/macros_bytes.rs create mode 100644 regex/tests/macros_str.rs create mode 100644 regex/tests/misc.rs create mode 100644 regex/tests/multiline.rs create mode 100644 regex/tests/noparse.rs create mode 100644 regex/tests/regression.rs create mode 100644 regex/tests/replace.rs create mode 100644 regex/tests/searcher.rs create mode 100644 regex/tests/set.rs create mode 100644 regex/tests/shortest_match.rs create mode 100644 regex/tests/suffix_reverse.rs create mode 100644 regex/tests/test_backtrack.rs create mode 100644 regex/tests/test_backtrack_bytes.rs create mode 100644 regex/tests/test_backtrack_utf8bytes.rs create mode 100644 regex/tests/test_crates_regex.rs create mode 100644 regex/tests/test_default.rs create mode 100644 regex/tests/test_default_bytes.rs create mode 100644 regex/tests/test_nfa.rs create mode 100644 regex/tests/test_nfa_bytes.rs create mode 100644 regex/tests/test_nfa_utf8bytes.rs create mode 100644 regex/tests/unicode.rs create mode 100644 regex/tests/word_boundary.rs create mode 100644 regex/tests/word_boundary_ascii.rs create mode 100644 regex/tests/word_boundary_unicode.rs create mode 100644 remove_dir_all/.cargo-checksum.json create mode 100644 remove_dir_all/Cargo.toml create mode 100644 remove_dir_all/LICENCE-APACHE create mode 100644 remove_dir_all/LICENCE-MIT create mode 100644 remove_dir_all/src/fs.rs create mode 100644 remove_dir_all/src/lib.rs create mode 100644 rustc-demangle/.cargo-checksum.json create mode 100644 rustc-demangle/Cargo.toml create mode 100644 rustc-demangle/LICENSE-APACHE create mode 100644 rustc-demangle/LICENSE-MIT create mode 100644 rustc-demangle/README.md create mode 100644 rustc-demangle/src/legacy.rs create mode 100644 rustc-demangle/src/lib.rs create mode 100644 rustc-demangle/src/v0.rs create mode 100644 rustc-workspace-hack/.cargo-checksum.json create mode 100644 rustc-workspace-hack/Cargo.toml create mode 100644 rustc-workspace-hack/src/lib.rs create mode 100644 rustc_version/.cargo-checksum.json create mode 100644 rustc_version/Cargo.toml create mode 100644 rustc_version/LICENSE-APACHE create mode 100644 rustc_version/LICENSE-MIT create mode 100644 rustc_version/README.md create mode 100644 rustc_version/src/errors.rs create mode 100644 rustc_version/src/lib.rs create mode 100644 rustfix/.cargo-checksum.json create mode 100644 rustfix/Cargo.toml create mode 100644 rustfix/LICENSE-APACHE create mode 100644 rustfix/LICENSE-MIT create mode 100644 rustfix/Readme.md create mode 100644 rustfix/bors.toml create mode 100644 rustfix/proptest-regressions/replace.txt create mode 100644 rustfix/src/diagnostics.rs create mode 100644 rustfix/src/lib.rs create mode 100644 rustfix/src/replace.rs create mode 100644 rusty-fork/.cargo-checksum.json create mode 100644 rusty-fork/CHANGELOG.md create mode 100644 rusty-fork/Cargo.toml create mode 100644 rusty-fork/LICENSE-APACHE create mode 100644 rusty-fork/LICENSE-MIT create mode 100644 rusty-fork/README.md create mode 100644 rusty-fork/src/child_wrapper.rs create mode 100644 rusty-fork/src/cmdline.rs create mode 100644 rusty-fork/src/error.rs create mode 100644 rusty-fork/src/file-preamble create mode 100644 rusty-fork/src/fork.rs create mode 100644 rusty-fork/src/fork_test.rs create mode 100644 rusty-fork/src/lib.rs create mode 100644 rusty-fork/src/sugar.rs create mode 100644 ryu/.cargo-checksum.json create mode 100644 ryu/Cargo.toml create mode 100644 ryu/LICENSE-APACHE create mode 100644 ryu/LICENSE-BOOST create mode 100644 ryu/README.md create mode 100644 ryu/benches/bench.rs create mode 100644 ryu/build.rs create mode 100644 ryu/examples/upstream_benchmark.rs create mode 100644 ryu/src/buffer/mod.rs create mode 100644 ryu/src/common.rs create mode 100644 ryu/src/d2s.rs create mode 100644 ryu/src/d2s_full_table.rs create mode 100644 ryu/src/d2s_intrinsics.rs create mode 100644 ryu/src/d2s_small_table.rs create mode 100644 ryu/src/digit_table.rs create mode 100644 ryu/src/f2s.rs create mode 100644 ryu/src/lib.rs create mode 100644 ryu/src/pretty/exponent.rs create mode 100644 ryu/src/pretty/mantissa.rs create mode 100644 ryu/src/pretty/mod.rs create mode 100644 ryu/tests/d2s_table_test.rs create mode 100644 ryu/tests/d2s_test.rs create mode 100644 ryu/tests/exhaustive.rs create mode 100644 ryu/tests/f2s_test.rs create mode 100644 ryu/tests/macros/mod.rs create mode 100644 same-file/.cargo-checksum.json create mode 100644 same-file/COPYING create mode 100644 same-file/Cargo.toml create mode 100644 same-file/LICENSE-MIT create mode 100644 same-file/README.md create mode 100644 same-file/UNLICENSE create mode 100644 same-file/examples/is_same_file.rs create mode 100644 same-file/examples/is_stderr.rs create mode 100644 same-file/src/lib.rs create mode 100644 same-file/src/unix.rs create mode 100644 same-file/src/win.rs create mode 100644 schannel/.cargo-checksum.json create mode 100644 schannel/Cargo.toml create mode 100644 schannel/LICENSE.md create mode 100644 schannel/README.md create mode 100644 schannel/appveyor.yml create mode 100644 schannel/src/cert_chain.rs create mode 100644 schannel/src/cert_context.rs create mode 100644 schannel/src/cert_store.rs create mode 100644 schannel/src/context_buffer.rs create mode 100644 schannel/src/crypt_key.rs create mode 100644 schannel/src/crypt_prov.rs create mode 100644 schannel/src/ctl_context.rs create mode 100644 schannel/src/key_handle.rs create mode 100644 schannel/src/lib.rs create mode 100644 schannel/src/ncrypt_key.rs create mode 100644 schannel/src/schannel_cred.rs create mode 100644 schannel/src/security_context.rs create mode 100644 schannel/src/test.rs create mode 100644 schannel/src/tls_stream.rs create mode 100644 schannel/test/cert.der create mode 100644 schannel/test/cert.pem create mode 100644 schannel/test/identity.p12 create mode 100644 schannel/test/key.key create mode 100644 schannel/test/key.pem create mode 100644 schannel/test/self-signed.badssl.com.cer create mode 100644 scopeguard/.cargo-checksum.json create mode 100644 scopeguard/Cargo.toml create mode 100644 scopeguard/LICENSE-APACHE create mode 100644 scopeguard/LICENSE-MIT create mode 100644 scopeguard/README.rst create mode 100644 scopeguard/examples/readme.rs create mode 100644 scopeguard/src/lib.rs create mode 100644 semver-parser/.cargo-checksum.json create mode 100644 semver-parser/Cargo.toml create mode 100644 semver-parser/LICENSE-APACHE create mode 100644 semver-parser/LICENSE-MIT create mode 100644 semver-parser/src/common.rs create mode 100644 semver-parser/src/lib.rs create mode 100644 semver-parser/src/range.rs create mode 100644 semver-parser/src/recognize.rs create mode 100644 semver-parser/src/version.rs create mode 100644 semver/.cargo-checksum.json create mode 100644 semver/Cargo.toml create mode 100644 semver/LICENSE-APACHE create mode 100644 semver/LICENSE-MIT create mode 100644 semver/README.md create mode 100644 semver/src/lib.rs create mode 100644 semver/src/version.rs create mode 100644 semver/src/version_req.rs create mode 100644 semver/tests/deprecation.rs create mode 100644 semver/tests/regression.rs create mode 100644 semver/tests/serde.rs create mode 100644 serde/.cargo-checksum.json create mode 100644 serde/Cargo.toml create mode 100644 serde/LICENSE-APACHE create mode 100644 serde/LICENSE-MIT create mode 100644 serde/README.md create mode 100644 serde/build.rs create mode 100644 serde/crates-io.md create mode 100644 serde/src/de/from_primitive.rs create mode 100644 serde/src/de/ignored_any.rs create mode 100644 serde/src/de/impls.rs create mode 100644 serde/src/de/mod.rs create mode 100644 serde/src/de/utf8.rs create mode 100644 serde/src/de/value.rs create mode 100644 serde/src/export.rs create mode 100644 serde/src/integer128.rs create mode 100644 serde/src/lib.rs create mode 100644 serde/src/macros.rs create mode 100644 serde/src/private/de.rs create mode 100644 serde/src/private/macros.rs create mode 100644 serde/src/private/mod.rs create mode 100644 serde/src/private/ser.rs create mode 100644 serde/src/ser/impls.rs create mode 100644 serde/src/ser/impossible.rs create mode 100644 serde/src/ser/mod.rs create mode 100644 serde_derive/.cargo-checksum.json create mode 100644 serde_derive/Cargo.toml create mode 100644 serde_derive/LICENSE-APACHE create mode 100644 serde_derive/LICENSE-MIT create mode 100644 serde_derive/README.md create mode 100644 serde_derive/crates-io.md create mode 100644 serde_derive/src/bound.rs create mode 100644 serde_derive/src/de.rs create mode 100644 serde_derive/src/dummy.rs create mode 100644 serde_derive/src/fragment.rs create mode 100644 serde_derive/src/internals/ast.rs create mode 100644 serde_derive/src/internals/attr.rs create mode 100644 serde_derive/src/internals/case.rs create mode 100644 serde_derive/src/internals/check.rs create mode 100644 serde_derive/src/internals/ctxt.rs create mode 100644 serde_derive/src/internals/mod.rs create mode 100644 serde_derive/src/lib.rs create mode 100644 serde_derive/src/pretend.rs create mode 100644 serde_derive/src/ser.rs create mode 100644 serde_derive/src/try.rs create mode 100644 serde_ignored/.cargo-checksum.json create mode 100644 serde_ignored/Cargo.toml create mode 100644 serde_ignored/LICENSE-APACHE create mode 100644 serde_ignored/LICENSE-MIT create mode 100644 serde_ignored/README.md create mode 100644 serde_ignored/src/lib.rs create mode 100644 serde_json/.cargo-checksum.json create mode 100644 serde_json/Cargo.toml create mode 100644 serde_json/LICENSE-APACHE create mode 100644 serde_json/LICENSE-MIT create mode 100644 serde_json/README.md create mode 100644 serde_json/src/de.rs create mode 100644 serde_json/src/error.rs create mode 100644 serde_json/src/iter.rs create mode 100644 serde_json/src/lib.rs create mode 100644 serde_json/src/macros.rs create mode 100644 serde_json/src/map.rs create mode 100644 serde_json/src/number.rs create mode 100644 serde_json/src/raw.rs create mode 100644 serde_json/src/read.rs create mode 100644 serde_json/src/ser.rs create mode 100644 serde_json/src/value/de.rs create mode 100644 serde_json/src/value/from.rs create mode 100644 serde_json/src/value/index.rs create mode 100644 serde_json/src/value/mod.rs create mode 100644 serde_json/src/value/partial_eq.rs create mode 100644 serde_json/src/value/ser.rs create mode 100644 shell-escape/.cargo-checksum.json create mode 100644 shell-escape/Cargo.toml create mode 100644 shell-escape/LICENSE-APACHE create mode 100644 shell-escape/LICENSE-MIT create mode 100644 shell-escape/README.md create mode 100644 shell-escape/src/lib.rs create mode 100644 sized-chunks/.cargo-checksum.json create mode 100644 sized-chunks/CHANGELOG.md create mode 100644 sized-chunks/CODE_OF_CONDUCT.md create mode 100644 sized-chunks/Cargo.toml create mode 100644 sized-chunks/LICENCE.md create mode 100644 sized-chunks/README.md create mode 100644 sized-chunks/src/bitmap.rs create mode 100644 sized-chunks/src/lib.rs create mode 100644 sized-chunks/src/sized_chunk.rs create mode 100644 sized-chunks/src/sparse_chunk.rs create mode 100644 sized-chunks/src/tests/mod.rs create mode 100644 sized-chunks/src/tests/sized_chunk.rs create mode 100644 sized-chunks/src/tests/sparse_chunk.rs create mode 100644 sized-chunks/src/types.rs create mode 100644 smallvec/.cargo-checksum.json create mode 100644 smallvec/Cargo.toml create mode 100644 smallvec/LICENSE-APACHE create mode 100644 smallvec/LICENSE-MIT create mode 100644 smallvec/README.md create mode 100644 smallvec/benches/bench.rs create mode 100644 smallvec/lib.rs create mode 100644 socket2/.cargo-checksum.json create mode 100644 socket2/Cargo.toml create mode 100644 socket2/LICENSE-APACHE create mode 100644 socket2/LICENSE-MIT create mode 100644 socket2/README.md create mode 100644 socket2/src/lib.rs create mode 100644 socket2/src/sockaddr.rs create mode 100644 socket2/src/socket.rs create mode 100644 socket2/src/sys/redox/mod.rs create mode 100644 socket2/src/sys/unix/mod.rs create mode 100644 socket2/src/sys/unix/weak.rs create mode 100644 socket2/src/sys/windows.rs create mode 100644 socket2/src/utils.rs create mode 100644 strsim/.cargo-checksum.json create mode 100644 strsim/CHANGELOG.md create mode 100644 strsim/Cargo.toml create mode 100644 strsim/LICENSE create mode 100644 strsim/README.md create mode 100644 strsim/appveyor.yml create mode 100644 strsim/benches/benches.rs create mode 100755 strsim/dev create mode 100644 strsim/src/lib.rs create mode 100644 strsim/tests/lib.rs create mode 100644 syn/.cargo-checksum.json create mode 100644 syn/Cargo.toml create mode 100644 syn/LICENSE-APACHE create mode 100644 syn/LICENSE-MIT create mode 100644 syn/README.md create mode 100644 syn/build.rs create mode 100644 syn/src/attr.rs create mode 100644 syn/src/buffer.rs create mode 100644 syn/src/custom_keyword.rs create mode 100644 syn/src/custom_punctuation.rs create mode 100644 syn/src/data.rs create mode 100644 syn/src/derive.rs create mode 100644 syn/src/error.rs create mode 100644 syn/src/export.rs create mode 100644 syn/src/expr.rs create mode 100644 syn/src/ext.rs create mode 100644 syn/src/file.rs create mode 100644 syn/src/gen/fold.rs create mode 100644 syn/src/gen/visit.rs create mode 100644 syn/src/gen/visit_mut.rs create mode 100644 syn/src/gen_helper.rs create mode 100644 syn/src/generics.rs create mode 100644 syn/src/group.rs create mode 100644 syn/src/ident.rs create mode 100644 syn/src/item.rs create mode 100644 syn/src/keyword.rs create mode 100644 syn/src/lib.rs create mode 100644 syn/src/lifetime.rs create mode 100644 syn/src/lit.rs create mode 100644 syn/src/lookahead.rs create mode 100644 syn/src/mac.rs create mode 100644 syn/src/macros.rs create mode 100644 syn/src/op.rs create mode 100644 syn/src/parse.rs create mode 100644 syn/src/parse_macro_input.rs create mode 100644 syn/src/parse_quote.rs create mode 100644 syn/src/path.rs create mode 100644 syn/src/print.rs create mode 100644 syn/src/punctuated.rs create mode 100644 syn/src/sealed.rs create mode 100644 syn/src/span.rs create mode 100644 syn/src/spanned.rs create mode 100644 syn/src/thread.rs create mode 100644 syn/src/token.rs create mode 100644 syn/src/tt.rs create mode 100644 syn/src/ty.rs create mode 100644 synstructure/.cargo-checksum.json create mode 100644 synstructure/Cargo.toml create mode 100644 synstructure/LICENSE create mode 100644 synstructure/README.md create mode 100644 synstructure/src/lib.rs create mode 100644 synstructure/src/macros.rs create mode 100644 tar/.cargo-checksum.json create mode 100644 tar/Cargo.toml create mode 100644 tar/LICENSE-APACHE create mode 100644 tar/LICENSE-MIT create mode 100644 tar/README.md create mode 100644 tar/appveyor.yml create mode 100644 tar/examples/extract_file.rs create mode 100644 tar/examples/list.rs create mode 100644 tar/examples/raw_list.rs create mode 100644 tar/examples/write.rs create mode 100644 tar/src/archive.rs create mode 100644 tar/src/builder.rs create mode 100644 tar/src/entry.rs create mode 100644 tar/src/entry_type.rs create mode 100644 tar/src/error.rs create mode 100644 tar/src/header.rs create mode 100644 tar/src/lib.rs create mode 100644 tar/src/pax.rs create mode 100644 tar/tests/all.rs create mode 100644 tar/tests/entry.rs create mode 100644 tar/tests/header/mod.rs create mode 100644 tempfile/.cargo-checksum.json create mode 100644 tempfile/Cargo.toml create mode 100644 tempfile/LICENSE-APACHE create mode 100644 tempfile/LICENSE-MIT create mode 100644 tempfile/NEWS create mode 100644 tempfile/README.md create mode 100644 tempfile/src/dir.rs create mode 100644 tempfile/src/error.rs create mode 100644 tempfile/src/file/imp/mod.rs create mode 100644 tempfile/src/file/imp/other.rs create mode 100644 tempfile/src/file/imp/unix.rs create mode 100644 tempfile/src/file/imp/windows.rs create mode 100644 tempfile/src/file/mod.rs create mode 100644 tempfile/src/lib.rs create mode 100644 tempfile/src/spooled.rs create mode 100644 tempfile/src/util.rs create mode 100644 tempfile/tests/namedtempfile.rs create mode 100644 tempfile/tests/spooled.rs create mode 100644 tempfile/tests/tempdir.rs create mode 100644 tempfile/tests/tempfile.rs create mode 100644 termcolor/.cargo-checksum.json create mode 100644 termcolor/COPYING create mode 100644 termcolor/Cargo.toml create mode 100644 termcolor/LICENSE-MIT create mode 100644 termcolor/README.md create mode 100644 termcolor/UNLICENSE create mode 100644 termcolor/src/lib.rs create mode 100644 termion/.cargo-checksum.json create mode 100644 termion/Cargo.toml create mode 100644 termion/LICENSE create mode 100644 termion/README.md create mode 100644 termion/examples/alternate_screen.rs create mode 100644 termion/examples/alternate_screen_raw.rs create mode 100644 termion/examples/async.rs create mode 100644 termion/examples/click.rs create mode 100644 termion/examples/color.rs create mode 100644 termion/examples/commie.rs create mode 100644 termion/examples/detect_color.rs create mode 100644 termion/examples/is_tty.rs create mode 100644 termion/examples/keys.rs create mode 100644 termion/examples/mouse.rs create mode 100644 termion/examples/rainbow.rs create mode 100644 termion/examples/read.rs create mode 100644 termion/examples/rustc_fun.rs create mode 100644 termion/examples/simple.rs create mode 100644 termion/examples/size.rs create mode 100644 termion/examples/truecolor.rs create mode 100644 termion/logo.svg create mode 100644 termion/src/async.rs create mode 100644 termion/src/clear.rs create mode 100644 termion/src/color.rs create mode 100644 termion/src/cursor.rs create mode 100644 termion/src/event.rs create mode 100644 termion/src/input.rs create mode 100644 termion/src/lib.rs create mode 100644 termion/src/macros.rs create mode 100644 termion/src/raw.rs create mode 100644 termion/src/screen.rs create mode 100644 termion/src/scroll.rs create mode 100644 termion/src/style.rs create mode 100644 termion/src/sys/redox/attr.rs create mode 100644 termion/src/sys/redox/mod.rs create mode 100644 termion/src/sys/redox/size.rs create mode 100644 termion/src/sys/redox/tty.rs create mode 100644 termion/src/sys/unix/attr.rs create mode 100644 termion/src/sys/unix/mod.rs create mode 100644 termion/src/sys/unix/size.rs create mode 100644 termion/src/sys/unix/tty.rs create mode 100644 textwrap/.cargo-checksum.json create mode 100644 textwrap/Cargo.toml create mode 100644 textwrap/LICENSE create mode 100644 textwrap/README.md create mode 100644 textwrap/benches/linear.rs create mode 100644 textwrap/examples/layout.rs create mode 100644 textwrap/examples/termwidth.rs create mode 100644 textwrap/src/indentation.rs create mode 100644 textwrap/src/lib.rs create mode 100644 textwrap/src/splitting.rs create mode 100644 textwrap/tests/version-numbers.rs create mode 100644 thread_local/.cargo-checksum.json create mode 100644 thread_local/Cargo.toml create mode 100644 thread_local/LICENSE-APACHE create mode 100644 thread_local/LICENSE-MIT create mode 100644 thread_local/README.md create mode 100644 thread_local/benches/thread_local.rs create mode 100644 thread_local/src/lib.rs create mode 100644 thread_local/src/thread_id.rs create mode 100644 thread_local/src/unreachable.rs create mode 100644 time/.cargo-checksum.json create mode 100644 time/Cargo.toml create mode 100644 time/LICENSE-APACHE create mode 100644 time/LICENSE-MIT create mode 100644 time/README.md create mode 100644 time/appveyor.yml create mode 100644 time/benches/precise_time_ns.rs create mode 100644 time/src/display.rs create mode 100644 time/src/duration.rs create mode 100644 time/src/lib.rs create mode 100644 time/src/parse.rs create mode 100644 time/src/sys.rs create mode 100644 toml/.cargo-checksum.json create mode 100644 toml/Cargo.toml create mode 100644 toml/LICENSE-APACHE create mode 100644 toml/LICENSE-MIT create mode 100644 toml/README.md create mode 100644 toml/examples/decode.rs create mode 100644 toml/examples/enum_external.rs create mode 100644 toml/examples/toml2json.rs create mode 100644 toml/src/datetime.rs create mode 100644 toml/src/de.rs create mode 100644 toml/src/lib.rs create mode 100644 toml/src/macros.rs create mode 100644 toml/src/ser.rs create mode 100644 toml/src/spanned.rs create mode 100644 toml/src/tokens.rs create mode 100644 toml/src/value.rs create mode 100644 toml/tests/enum_external_deserialize.rs create mode 100644 typenum/.cargo-checksum.json create mode 100644 typenum/.pc/.quilt_patches create mode 100644 typenum/.pc/.quilt_series create mode 100644 typenum/.pc/.version create mode 100644 typenum/.pc/applied-patches create mode 100644 typenum/.pc/pr115.patch/.timestamp create mode 100644 typenum/.pc/pr115.patch/build/main.rs create mode 100644 typenum/CHANGELOG.md create mode 100644 typenum/Cargo.toml create mode 100644 typenum/LICENSE create mode 100644 typenum/README.md create mode 100644 typenum/build/main.rs create mode 100644 typenum/build/op.rs create mode 100644 typenum/build/tests.rs create mode 100644 typenum/debian/patches/pr115.patch create mode 100644 typenum/debian/patches/series create mode 100644 typenum/src/array.rs create mode 100644 typenum/src/bit.rs create mode 100644 typenum/src/int.rs create mode 100644 typenum/src/lib.rs create mode 100644 typenum/src/marker_traits.rs create mode 100644 typenum/src/operator_aliases.rs create mode 100644 typenum/src/private.rs create mode 100644 typenum/src/type_operators.rs create mode 100644 typenum/src/uint.rs create mode 100644 typenum/tests/test.rs create mode 100644 ucd-util/.cargo-checksum.json create mode 100644 ucd-util/Cargo.toml create mode 100644 ucd-util/LICENSE-APACHE create mode 100644 ucd-util/LICENSE-MIT create mode 100644 ucd-util/LICENSE-UNICODE create mode 100644 ucd-util/README.md create mode 100644 ucd-util/src/hangul.rs create mode 100644 ucd-util/src/ideograph.rs create mode 100644 ucd-util/src/lib.rs create mode 100644 ucd-util/src/name.rs create mode 100644 ucd-util/src/property.rs create mode 100644 ucd-util/src/unicode_tables/jamo_short_name.rs create mode 100644 ucd-util/src/unicode_tables/mod.rs create mode 100644 ucd-util/src/unicode_tables/property_names.rs create mode 100644 ucd-util/src/unicode_tables/property_values.rs create mode 100644 unicode-bidi/.cargo-checksum.json create mode 100644 unicode-bidi/.pc/.quilt_patches create mode 100644 unicode-bidi/.pc/.quilt_series create mode 100644 unicode-bidi/.pc/.version create mode 100644 unicode-bidi/.pc/applied-patches create mode 100644 unicode-bidi/.pc/no-flamegraphs.patch/.timestamp create mode 100644 unicode-bidi/.pc/no-flamegraphs.patch/Cargo.toml create mode 100644 unicode-bidi/AUTHORS create mode 100644 unicode-bidi/COPYRIGHT create mode 100644 unicode-bidi/Cargo.toml create mode 100644 unicode-bidi/LICENSE-APACHE create mode 100644 unicode-bidi/LICENSE-MIT create mode 100644 unicode-bidi/README.md create mode 100644 unicode-bidi/debian/patches/no-flamegraphs.patch create mode 100644 unicode-bidi/debian/patches/series create mode 100644 unicode-bidi/src/char_data/mod.rs create mode 100644 unicode-bidi/src/char_data/tables.rs create mode 100644 unicode-bidi/src/deprecated.rs create mode 100644 unicode-bidi/src/explicit.rs create mode 100644 unicode-bidi/src/format_chars.rs create mode 100644 unicode-bidi/src/implicit.rs create mode 100644 unicode-bidi/src/level.rs create mode 100644 unicode-bidi/src/lib.rs create mode 100644 unicode-bidi/src/prepare.rs create mode 100644 unicode-normalization/.cargo-checksum.json create mode 100644 unicode-normalization/COPYRIGHT create mode 100644 unicode-normalization/Cargo.toml create mode 100644 unicode-normalization/LICENSE-APACHE create mode 100644 unicode-normalization/LICENSE-MIT create mode 100644 unicode-normalization/README.md create mode 100644 unicode-normalization/benches/bench.rs create mode 100644 unicode-normalization/scripts/unicode.py create mode 100644 unicode-normalization/src/decompose.rs create mode 100644 unicode-normalization/src/lib.rs create mode 100644 unicode-normalization/src/normalize.rs create mode 100644 unicode-normalization/src/quick_check.rs create mode 100644 unicode-normalization/src/recompose.rs create mode 100644 unicode-normalization/src/stream_safe.rs create mode 100644 unicode-normalization/src/tables.rs create mode 100644 unicode-width/.cargo-checksum.json create mode 100644 unicode-width/COPYRIGHT create mode 100644 unicode-width/Cargo.toml create mode 100644 unicode-width/LICENSE-APACHE create mode 100644 unicode-width/LICENSE-MIT create mode 100644 unicode-width/README.md create mode 100755 unicode-width/scripts/unicode.py create mode 100644 unicode-width/src/lib.rs create mode 100644 unicode-width/src/tables.rs create mode 100644 unicode-width/src/tests.rs create mode 100644 unicode-xid/.cargo-checksum.json create mode 100644 unicode-xid/COPYRIGHT create mode 100644 unicode-xid/Cargo.toml create mode 100644 unicode-xid/LICENSE-APACHE create mode 100644 unicode-xid/LICENSE-MIT create mode 100644 unicode-xid/README.md create mode 100755 unicode-xid/scripts/unicode.py create mode 100644 unicode-xid/src/lib.rs create mode 100644 unicode-xid/src/tables.rs create mode 100644 unicode-xid/src/tests.rs create mode 100644 url/.cargo-checksum.json create mode 100644 url/.pc/.quilt_patches create mode 100644 url/.pc/.quilt_series create mode 100644 url/.pc/.version create mode 100644 url/.pc/0001-Remove-dependency-to-outdated-serde.patch/.timestamp create mode 100644 url/.pc/0001-Remove-dependency-to-outdated-serde.patch/Cargo.toml create mode 100644 url/.pc/applied-patches create mode 100644 url/Cargo.toml create mode 100644 url/LICENSE-APACHE create mode 100644 url/LICENSE-MIT create mode 100644 url/README.md create mode 100644 url/UPGRADING.md create mode 100644 url/appveyor.yml create mode 100644 url/benches/parse_url.rs create mode 100644 url/debian/patches/0001-Remove-dependency-to-outdated-serde.patch create mode 100644 url/debian/patches/series create mode 100644 url/docs/404.html create mode 100644 url/docs/index.html create mode 100644 url/src/encoding.rs create mode 100644 url/src/form_urlencoded.rs create mode 100644 url/src/host.rs create mode 100644 url/src/lib.rs create mode 100644 url/src/origin.rs create mode 100644 url/src/parser.rs create mode 100644 url/src/path_segments.rs create mode 100644 url/src/quirks.rs create mode 100644 url/src/slicing.rs create mode 100644 url/tests/data.rs create mode 100644 url/tests/setters_tests.json create mode 100644 url/tests/unit.rs create mode 100644 url/tests/urltestdata.json create mode 100644 url_serde/.cargo-checksum.json create mode 100644 url_serde/Cargo.toml create mode 100644 url_serde/README.md create mode 100644 url_serde/src/lib.rs create mode 100644 utf8-ranges/.cargo-checksum.json create mode 100644 utf8-ranges/COPYING create mode 100644 utf8-ranges/Cargo.toml create mode 100644 utf8-ranges/LICENSE-MIT create mode 100644 utf8-ranges/README.md create mode 100644 utf8-ranges/UNLICENSE create mode 100644 utf8-ranges/benches/bench.rs create mode 100644 utf8-ranges/src/char_utf8.rs create mode 100644 utf8-ranges/src/lib.rs create mode 100644 vcpkg/.cargo-checksum.json create mode 100644 vcpkg/Cargo.toml create mode 100644 vcpkg/src/lib.rs create mode 100644 vec_map/.cargo-checksum.json create mode 100644 vec_map/Cargo.toml create mode 100644 vec_map/LICENSE-APACHE create mode 100644 vec_map/LICENSE-MIT create mode 100644 vec_map/README.md create mode 100644 vec_map/deploy-docs.sh create mode 100644 vec_map/src/lib.rs create mode 100644 wait-timeout/.cargo-checksum.json create mode 100644 wait-timeout/Cargo.toml create mode 100644 wait-timeout/LICENSE-APACHE create mode 100644 wait-timeout/LICENSE-MIT create mode 100644 wait-timeout/README.md create mode 100644 wait-timeout/appveyor.yml create mode 100644 wait-timeout/src/bin/exit.rs create mode 100644 wait-timeout/src/bin/reader.rs create mode 100644 wait-timeout/src/bin/sleep.rs create mode 100644 wait-timeout/src/lib.rs create mode 100644 wait-timeout/src/unix.rs create mode 100644 wait-timeout/src/windows.rs create mode 100644 wait-timeout/tests/smoke.rs create mode 100644 walkdir/.cargo-checksum.json create mode 100644 walkdir/COPYING create mode 100644 walkdir/Cargo.toml create mode 100644 walkdir/LICENSE-MIT create mode 100644 walkdir/README.md create mode 100644 walkdir/UNLICENSE create mode 100644 walkdir/compare/nftw.c create mode 100644 walkdir/compare/walk.py create mode 100644 walkdir/examples/walkdir.rs create mode 100644 walkdir/src/lib.rs create mode 100644 walkdir/src/tests.rs create mode 100644 walkdir/src/unix.rs create mode 100644 winapi-i686-pc-windows-gnu/.cargo-checksum.json create mode 100644 winapi-i686-pc-windows-gnu/Cargo.toml create mode 100644 winapi-i686-pc-windows-gnu/build.rs create mode 100644 winapi-i686-pc-windows-gnu/src/lib.rs create mode 100644 winapi-util/.cargo-checksum.json create mode 100644 winapi-util/COPYING create mode 100644 winapi-util/Cargo.toml create mode 100644 winapi-util/LICENSE-MIT create mode 100644 winapi-util/README.md create mode 100644 winapi-util/UNLICENSE create mode 100644 winapi-util/appveyor.yml create mode 100755 winapi-util/ci/script.sh create mode 100644 winapi-util/src/console.rs create mode 100644 winapi-util/src/file.rs create mode 100644 winapi-util/src/lib.rs create mode 100644 winapi-util/src/win.rs create mode 100644 winapi-x86_64-pc-windows-gnu/.cargo-checksum.json create mode 100644 winapi-x86_64-pc-windows-gnu/Cargo.toml create mode 100644 winapi-x86_64-pc-windows-gnu/build.rs create mode 100644 winapi-x86_64-pc-windows-gnu/src/lib.rs create mode 100644 winapi/.cargo-checksum.json create mode 100644 winapi/Cargo.toml create mode 100644 winapi/LICENSE-APACHE create mode 100644 winapi/LICENSE-MIT create mode 100644 winapi/README.md create mode 100644 winapi/build.rs create mode 100644 winapi/src/km/d3dkmthk.rs create mode 100644 winapi/src/km/mod.rs create mode 100644 winapi/src/lib.rs create mode 100644 winapi/src/macros.rs create mode 100644 winapi/src/shared/basetsd.rs create mode 100644 winapi/src/shared/bcrypt.rs create mode 100644 winapi/src/shared/bugcodes.rs create mode 100644 winapi/src/shared/cderr.rs create mode 100644 winapi/src/shared/cfg.rs create mode 100644 winapi/src/shared/d3d9.rs create mode 100644 winapi/src/shared/d3d9caps.rs create mode 100644 winapi/src/shared/d3d9types.rs create mode 100644 winapi/src/shared/d3dkmdt.rs create mode 100644 winapi/src/shared/d3dukmdt.rs create mode 100644 winapi/src/shared/dcomptypes.rs create mode 100644 winapi/src/shared/devguid.rs create mode 100644 winapi/src/shared/devpkey.rs create mode 100644 winapi/src/shared/devpropdef.rs create mode 100644 winapi/src/shared/dinputd.rs create mode 100644 winapi/src/shared/dxgi.rs create mode 100644 winapi/src/shared/dxgi1_2.rs create mode 100644 winapi/src/shared/dxgi1_3.rs create mode 100644 winapi/src/shared/dxgi1_4.rs create mode 100644 winapi/src/shared/dxgi1_5.rs create mode 100644 winapi/src/shared/dxgi1_6.rs create mode 100644 winapi/src/shared/dxgiformat.rs create mode 100644 winapi/src/shared/dxgitype.rs create mode 100644 winapi/src/shared/evntprov.rs create mode 100644 winapi/src/shared/evntrace.rs create mode 100644 winapi/src/shared/guiddef.rs create mode 100644 winapi/src/shared/hidclass.rs create mode 100644 winapi/src/shared/hidpi.rs create mode 100644 winapi/src/shared/hidsdi.rs create mode 100644 winapi/src/shared/hidusage.rs create mode 100644 winapi/src/shared/ifdef.rs create mode 100644 winapi/src/shared/in6addr.rs create mode 100644 winapi/src/shared/inaddr.rs create mode 100644 winapi/src/shared/intsafe.rs create mode 100644 winapi/src/shared/ks.rs create mode 100644 winapi/src/shared/ksmedia.rs create mode 100644 winapi/src/shared/ktmtypes.rs create mode 100644 winapi/src/shared/lmcons.rs create mode 100644 winapi/src/shared/minwindef.rs create mode 100644 winapi/src/shared/mmreg.rs create mode 100644 winapi/src/shared/mod.rs create mode 100644 winapi/src/shared/mstcpip.rs create mode 100644 winapi/src/shared/mswsockdef.rs create mode 100644 winapi/src/shared/netioapi.rs create mode 100644 winapi/src/shared/ntddscsi.rs create mode 100644 winapi/src/shared/ntddser.rs create mode 100644 winapi/src/shared/ntdef.rs create mode 100644 winapi/src/shared/ntstatus.rs create mode 100644 winapi/src/shared/qos.rs create mode 100644 winapi/src/shared/rpc.rs create mode 100644 winapi/src/shared/rpcdce.rs create mode 100644 winapi/src/shared/rpcndr.rs create mode 100644 winapi/src/shared/sddl.rs create mode 100644 winapi/src/shared/sspi.rs create mode 100644 winapi/src/shared/stralign.rs create mode 100644 winapi/src/shared/transportsettingcommon.rs create mode 100644 winapi/src/shared/tvout.rs create mode 100644 winapi/src/shared/usb.rs create mode 100644 winapi/src/shared/usbiodef.rs create mode 100644 winapi/src/shared/usbspec.rs create mode 100644 winapi/src/shared/windef.rs create mode 100644 winapi/src/shared/windowsx.rs create mode 100644 winapi/src/shared/winerror.rs create mode 100644 winapi/src/shared/winusbio.rs create mode 100644 winapi/src/shared/wmistr.rs create mode 100644 winapi/src/shared/wnnc.rs create mode 100644 winapi/src/shared/ws2def.rs create mode 100644 winapi/src/shared/ws2ipdef.rs create mode 100644 winapi/src/shared/wtypes.rs create mode 100644 winapi/src/shared/wtypesbase.rs create mode 100644 winapi/src/um/accctrl.rs create mode 100644 winapi/src/um/aclapi.rs create mode 100644 winapi/src/um/appmgmt.rs create mode 100644 winapi/src/um/audioclient.rs create mode 100644 winapi/src/um/audiosessiontypes.rs create mode 100644 winapi/src/um/avrt.rs create mode 100644 winapi/src/um/bits.rs create mode 100644 winapi/src/um/bits10_1.rs create mode 100644 winapi/src/um/bits1_5.rs create mode 100644 winapi/src/um/bits2_0.rs create mode 100644 winapi/src/um/bits2_5.rs create mode 100644 winapi/src/um/bits3_0.rs create mode 100644 winapi/src/um/bits4_0.rs create mode 100644 winapi/src/um/bits5_0.rs create mode 100644 winapi/src/um/bitscfg.rs create mode 100644 winapi/src/um/bitsmsg.rs create mode 100644 winapi/src/um/cfgmgr32.rs create mode 100644 winapi/src/um/cguid.rs create mode 100644 winapi/src/um/combaseapi.rs create mode 100644 winapi/src/um/coml2api.rs create mode 100644 winapi/src/um/commapi.rs create mode 100644 winapi/src/um/commctrl.rs create mode 100644 winapi/src/um/commdlg.rs create mode 100644 winapi/src/um/commoncontrols.rs create mode 100644 winapi/src/um/consoleapi.rs create mode 100644 winapi/src/um/corsym.rs create mode 100644 winapi/src/um/d2d1.rs create mode 100644 winapi/src/um/d2d1_1.rs create mode 100644 winapi/src/um/d2d1_2.rs create mode 100644 winapi/src/um/d2d1_3.rs create mode 100644 winapi/src/um/d2d1effectauthor.rs create mode 100644 winapi/src/um/d2d1effects.rs create mode 100644 winapi/src/um/d2d1effects_1.rs create mode 100644 winapi/src/um/d2d1effects_2.rs create mode 100644 winapi/src/um/d2d1svg.rs create mode 100644 winapi/src/um/d2dbasetypes.rs create mode 100644 winapi/src/um/d3d.rs create mode 100644 winapi/src/um/d3d10.rs create mode 100644 winapi/src/um/d3d10_1.rs create mode 100644 winapi/src/um/d3d10_1shader.rs create mode 100644 winapi/src/um/d3d10effect.rs create mode 100644 winapi/src/um/d3d10misc.rs create mode 100644 winapi/src/um/d3d10sdklayers.rs create mode 100644 winapi/src/um/d3d10shader.rs create mode 100644 winapi/src/um/d3d11.rs create mode 100644 winapi/src/um/d3d11_1.rs create mode 100644 winapi/src/um/d3d11_2.rs create mode 100644 winapi/src/um/d3d11_3.rs create mode 100644 winapi/src/um/d3d11_4.rs create mode 100644 winapi/src/um/d3d11on12.rs create mode 100644 winapi/src/um/d3d11sdklayers.rs create mode 100644 winapi/src/um/d3d11shader.rs create mode 100644 winapi/src/um/d3d11tokenizedprogramformat.rs create mode 100644 winapi/src/um/d3d12.rs create mode 100644 winapi/src/um/d3d12sdklayers.rs create mode 100644 winapi/src/um/d3d12shader.rs create mode 100644 winapi/src/um/d3dcommon.rs create mode 100644 winapi/src/um/d3dcompiler.rs create mode 100644 winapi/src/um/d3dcsx.rs create mode 100644 winapi/src/um/d3dx10core.rs create mode 100644 winapi/src/um/d3dx10math.rs create mode 100644 winapi/src/um/d3dx10mesh.rs create mode 100644 winapi/src/um/datetimeapi.rs create mode 100644 winapi/src/um/davclnt.rs create mode 100644 winapi/src/um/dbghelp.rs create mode 100644 winapi/src/um/dbt.rs create mode 100644 winapi/src/um/dcommon.rs create mode 100644 winapi/src/um/dcomp.rs create mode 100644 winapi/src/um/dcompanimation.rs create mode 100644 winapi/src/um/dde.rs create mode 100644 winapi/src/um/ddraw.rs create mode 100644 winapi/src/um/ddrawi.rs create mode 100644 winapi/src/um/ddrawint.rs create mode 100644 winapi/src/um/debugapi.rs create mode 100644 winapi/src/um/devicetopology.rs create mode 100644 winapi/src/um/dinput.rs create mode 100644 winapi/src/um/dispex.rs create mode 100644 winapi/src/um/dmksctl.rs create mode 100644 winapi/src/um/dmusicc.rs create mode 100644 winapi/src/um/docobj.rs create mode 100644 winapi/src/um/documenttarget.rs create mode 100644 winapi/src/um/dpa_dsa.rs create mode 100644 winapi/src/um/dpapi.rs create mode 100644 winapi/src/um/dsgetdc.rs create mode 100644 winapi/src/um/dsound.rs create mode 100644 winapi/src/um/dsrole.rs create mode 100644 winapi/src/um/dvp.rs create mode 100644 winapi/src/um/dwmapi.rs create mode 100644 winapi/src/um/dwrite.rs create mode 100644 winapi/src/um/dwrite_1.rs create mode 100644 winapi/src/um/dwrite_2.rs create mode 100644 winapi/src/um/dwrite_3.rs create mode 100644 winapi/src/um/dxdiag.rs create mode 100644 winapi/src/um/dxfile.rs create mode 100644 winapi/src/um/dxgidebug.rs create mode 100644 winapi/src/um/dxva2api.rs create mode 100644 winapi/src/um/dxvahd.rs create mode 100644 winapi/src/um/enclaveapi.rs create mode 100644 winapi/src/um/endpointvolume.rs create mode 100644 winapi/src/um/errhandlingapi.rs create mode 100644 winapi/src/um/evntcons.rs create mode 100644 winapi/src/um/exdisp.rs create mode 100644 winapi/src/um/fibersapi.rs create mode 100644 winapi/src/um/fileapi.rs create mode 100644 winapi/src/um/gl/gl.rs create mode 100644 winapi/src/um/gl/mod.rs create mode 100644 winapi/src/um/handleapi.rs create mode 100644 winapi/src/um/heapapi.rs create mode 100644 winapi/src/um/highlevelmonitorconfigurationapi.rs create mode 100644 winapi/src/um/http.rs create mode 100644 winapi/src/um/imm.rs create mode 100644 winapi/src/um/interlockedapi.rs create mode 100644 winapi/src/um/ioapiset.rs create mode 100644 winapi/src/um/jobapi.rs create mode 100644 winapi/src/um/jobapi2.rs create mode 100644 winapi/src/um/knownfolders.rs create mode 100644 winapi/src/um/ktmw32.rs create mode 100644 winapi/src/um/libloaderapi.rs create mode 100644 winapi/src/um/lmaccess.rs create mode 100644 winapi/src/um/lmalert.rs create mode 100644 winapi/src/um/lmapibuf.rs create mode 100644 winapi/src/um/lmat.rs create mode 100644 winapi/src/um/lmdfs.rs create mode 100644 winapi/src/um/lmerrlog.rs create mode 100644 winapi/src/um/lmjoin.rs create mode 100644 winapi/src/um/lmmsg.rs create mode 100644 winapi/src/um/lmremutl.rs create mode 100644 winapi/src/um/lmrepl.rs create mode 100644 winapi/src/um/lmserver.rs create mode 100644 winapi/src/um/lmshare.rs create mode 100644 winapi/src/um/lmstats.rs create mode 100644 winapi/src/um/lmsvc.rs create mode 100644 winapi/src/um/lmuse.rs create mode 100644 winapi/src/um/lmwksta.rs create mode 100644 winapi/src/um/lowlevelmonitorconfigurationapi.rs create mode 100644 winapi/src/um/lsalookup.rs create mode 100644 winapi/src/um/memoryapi.rs create mode 100644 winapi/src/um/minschannel.rs create mode 100644 winapi/src/um/minwinbase.rs create mode 100644 winapi/src/um/mmdeviceapi.rs create mode 100644 winapi/src/um/mmeapi.rs create mode 100644 winapi/src/um/mmsystem.rs create mode 100644 winapi/src/um/mod.rs create mode 100644 winapi/src/um/msaatext.rs create mode 100644 winapi/src/um/mscat.rs create mode 100644 winapi/src/um/mschapp.rs create mode 100644 winapi/src/um/mssip.rs create mode 100644 winapi/src/um/mswsock.rs create mode 100644 winapi/src/um/namedpipeapi.rs create mode 100644 winapi/src/um/namespaceapi.rs create mode 100644 winapi/src/um/nb30.rs create mode 100644 winapi/src/um/ncrypt.rs create mode 100644 winapi/src/um/ntlsa.rs create mode 100644 winapi/src/um/ntsecapi.rs create mode 100644 winapi/src/um/oaidl.rs create mode 100644 winapi/src/um/objbase.rs create mode 100644 winapi/src/um/objidl.rs create mode 100644 winapi/src/um/objidlbase.rs create mode 100644 winapi/src/um/ocidl.rs create mode 100644 winapi/src/um/ole2.rs create mode 100644 winapi/src/um/oleauto.rs create mode 100644 winapi/src/um/olectl.rs create mode 100644 winapi/src/um/oleidl.rs create mode 100644 winapi/src/um/opmapi.rs create mode 100644 winapi/src/um/pdh.rs create mode 100644 winapi/src/um/perflib.rs create mode 100644 winapi/src/um/physicalmonitorenumerationapi.rs create mode 100644 winapi/src/um/playsoundapi.rs create mode 100644 winapi/src/um/portabledevice.rs create mode 100644 winapi/src/um/portabledeviceapi.rs create mode 100644 winapi/src/um/portabledevicetypes.rs create mode 100644 winapi/src/um/powerbase.rs create mode 100644 winapi/src/um/powersetting.rs create mode 100644 winapi/src/um/powrprof.rs create mode 100644 winapi/src/um/processenv.rs create mode 100644 winapi/src/um/processsnapshot.rs create mode 100644 winapi/src/um/processthreadsapi.rs create mode 100644 winapi/src/um/processtopologyapi.rs create mode 100644 winapi/src/um/profileapi.rs create mode 100644 winapi/src/um/propidl.rs create mode 100644 winapi/src/um/propkeydef.rs create mode 100644 winapi/src/um/propsys.rs create mode 100644 winapi/src/um/prsht.rs create mode 100644 winapi/src/um/psapi.rs create mode 100644 winapi/src/um/realtimeapiset.rs create mode 100644 winapi/src/um/reason.rs create mode 100644 winapi/src/um/restartmanager.rs create mode 100644 winapi/src/um/restrictederrorinfo.rs create mode 100644 winapi/src/um/rmxfguid.rs create mode 100644 winapi/src/um/sapi.rs create mode 100644 winapi/src/um/sapi51.rs create mode 100644 winapi/src/um/sapi53.rs create mode 100644 winapi/src/um/sapiddk.rs create mode 100644 winapi/src/um/sapiddk51.rs create mode 100644 winapi/src/um/schannel.rs create mode 100644 winapi/src/um/securityappcontainer.rs create mode 100644 winapi/src/um/securitybaseapi.rs create mode 100644 winapi/src/um/servprov.rs create mode 100644 winapi/src/um/setupapi.rs create mode 100644 winapi/src/um/shellapi.rs create mode 100644 winapi/src/um/shellscalingapi.rs create mode 100644 winapi/src/um/shlobj.rs create mode 100644 winapi/src/um/shobjidl.rs create mode 100644 winapi/src/um/shobjidl_core.rs create mode 100644 winapi/src/um/shtypes.rs create mode 100644 winapi/src/um/spapidef.rs create mode 100644 winapi/src/um/spellcheck.rs create mode 100644 winapi/src/um/sporder.rs create mode 100644 winapi/src/um/sql.rs create mode 100644 winapi/src/um/sqlext.rs create mode 100644 winapi/src/um/sqltypes.rs create mode 100644 winapi/src/um/sqlucode.rs create mode 100644 winapi/src/um/sspi.rs create mode 100644 winapi/src/um/stringapiset.rs create mode 100644 winapi/src/um/strmif.rs create mode 100644 winapi/src/um/subauth.rs create mode 100644 winapi/src/um/synchapi.rs create mode 100644 winapi/src/um/sysinfoapi.rs create mode 100644 winapi/src/um/systemtopologyapi.rs create mode 100644 winapi/src/um/taskschd.rs create mode 100644 winapi/src/um/textstor.rs create mode 100644 winapi/src/um/threadpoolapiset.rs create mode 100644 winapi/src/um/threadpoollegacyapiset.rs create mode 100644 winapi/src/um/timeapi.rs create mode 100644 winapi/src/um/timezoneapi.rs create mode 100644 winapi/src/um/tlhelp32.rs create mode 100644 winapi/src/um/unknwnbase.rs create mode 100644 winapi/src/um/urlhist.rs create mode 100644 winapi/src/um/urlmon.rs create mode 100644 winapi/src/um/userenv.rs create mode 100644 winapi/src/um/usp10.rs create mode 100644 winapi/src/um/utilapiset.rs create mode 100644 winapi/src/um/uxtheme.rs create mode 100644 winapi/src/um/vsbackup.rs create mode 100644 winapi/src/um/vss.rs create mode 100644 winapi/src/um/vsserror.rs create mode 100644 winapi/src/um/vswriter.rs create mode 100644 winapi/src/um/wbemads.rs create mode 100644 winapi/src/um/wbemcli.rs create mode 100644 winapi/src/um/wbemdisp.rs create mode 100644 winapi/src/um/wbemprov.rs create mode 100644 winapi/src/um/wbemtran.rs create mode 100644 winapi/src/um/wct.rs create mode 100644 winapi/src/um/werapi.rs create mode 100644 winapi/src/um/winbase.rs create mode 100644 winapi/src/um/wincodec.rs create mode 100644 winapi/src/um/wincodecsdk.rs create mode 100644 winapi/src/um/wincon.rs create mode 100644 winapi/src/um/wincontypes.rs create mode 100644 winapi/src/um/wincred.rs create mode 100644 winapi/src/um/wincrypt.rs create mode 100644 winapi/src/um/windowsceip.rs create mode 100644 winapi/src/um/winefs.rs create mode 100644 winapi/src/um/winevt.rs create mode 100644 winapi/src/um/wingdi.rs create mode 100644 winapi/src/um/winhttp.rs create mode 100644 winapi/src/um/wininet.rs create mode 100644 winapi/src/um/winineti.rs create mode 100644 winapi/src/um/winioctl.rs create mode 100644 winapi/src/um/winnetwk.rs create mode 100644 winapi/src/um/winnls.rs create mode 100644 winapi/src/um/winnt.rs create mode 100644 winapi/src/um/winreg.rs create mode 100644 winapi/src/um/winsafer.rs create mode 100644 winapi/src/um/winscard.rs create mode 100644 winapi/src/um/winsmcrd.rs create mode 100644 winapi/src/um/winsock2.rs create mode 100644 winapi/src/um/winspool.rs create mode 100644 winapi/src/um/winsvc.rs create mode 100644 winapi/src/um/winusb.rs create mode 100644 winapi/src/um/winuser.rs create mode 100644 winapi/src/um/winver.rs create mode 100644 winapi/src/um/wow64apiset.rs create mode 100644 winapi/src/um/wpdmtpextensions.rs create mode 100644 winapi/src/um/ws2spi.rs create mode 100644 winapi/src/um/ws2tcpip.rs create mode 100644 winapi/src/um/xinput.rs create mode 100644 winapi/src/vc/excpt.rs create mode 100644 winapi/src/vc/limits.rs create mode 100644 winapi/src/vc/mod.rs create mode 100644 winapi/src/vc/vadefs.rs create mode 100644 winapi/src/vc/vcruntime.rs create mode 100644 winapi/src/winrt/activation.rs create mode 100644 winapi/src/winrt/hstring.rs create mode 100644 winapi/src/winrt/inspectable.rs create mode 100644 winapi/src/winrt/mod.rs create mode 100644 winapi/src/winrt/roapi.rs create mode 100644 winapi/src/winrt/robuffer.rs create mode 100644 winapi/src/winrt/roerrorapi.rs create mode 100644 winapi/src/winrt/winstring.rs create mode 100644 wincolor/.cargo-checksum.json create mode 100644 wincolor/COPYING create mode 100644 wincolor/Cargo.toml create mode 100644 wincolor/LICENSE-MIT create mode 100644 wincolor/README.md create mode 100644 wincolor/UNLICENSE create mode 100644 wincolor/src/lib.rs create mode 100644 wincolor/src/win.rs diff --git a/aho-corasick/.cargo-checksum.json b/aho-corasick/.cargo-checksum.json new file mode 100644 index 000000000..fef1dad6d --- /dev/null +++ b/aho-corasick/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"} \ No newline at end of file diff --git a/aho-corasick/COPYING b/aho-corasick/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/aho-corasick/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/aho-corasick/Cargo.toml b/aho-corasick/Cargo.toml new file mode 100644 index 000000000..6bbcc16da --- /dev/null +++ b/aho-corasick/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "aho-corasick" +version = "0.7.3" +authors = ["Andrew Gallant "] +exclude = ["/aho-corasick-debug", "/bench", "/ci/*", "/.travis.yml"] +autotests = false +description = "Fast multiple substring searching." +homepage = "https://github.com/BurntSushi/aho-corasick" +readme = "README.md" +keywords = ["string", "search", "text", "aho", "multi"] +categories = ["text-processing"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/aho-corasick" +[profile.bench] +debug = true + +[profile.release] +debug = true + +[lib] +name = "aho_corasick" +[dependencies.memchr] +version = "2.2.0" +default-features = false + +[features] +default = ["std"] +std = ["memchr/use_std"] +[badges.appveyor] +repository = "BurntSushi/regex-automata" + +[badges.travis-ci] +repository = "BurntSushi/aho-corasick" diff --git a/aho-corasick/LICENSE-MIT b/aho-corasick/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/aho-corasick/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/aho-corasick/README.md b/aho-corasick/README.md new file mode 100644 index 000000000..6134081d8 --- /dev/null +++ b/aho-corasick/README.md @@ -0,0 +1,190 @@ +aho-corasick +============ +A library for finding occurrences of many patterns at once. This library +provides multiple pattern search principally through an implementation of the +[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), +which builds a fast finite state machine for executing searches in linear time. +Features include case insensitive matching, overlapping matches and search & +replace in streams. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/aho-corasick.svg)](https://travis-ci.org/BurntSushi/aho-corasick) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/aho-corasick?svg=true)](https://ci.appveyor.com/project/BurntSushi/aho-corasick) +[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/aho-corasick + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +aho-corasick = "0.7" +``` + +and this to your crate root (if you're using Rust 2015): + +```rust +extern crate aho_corasick; +``` + + +### Example: basic searching + +This example shows how to search for occurrences of multiple patterns +simultaneously. Each match includes the pattern that matched along with the +byte offsets of the match. + +```rust +use aho_corasick::AhoCorasick; + +let patterns = &["apple", "maple", "Snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasick::new(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + + +### Example: case insensitivity + +This is like the previous example, but matches `Snapple` case insensitively +using `AhoCorasickBuilder`: + +```rust +use aho_corasick::AhoCorasickBuilder; + +let patterns = &["apple", "maple", "snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .build(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + + +### Example: replacing matches in a stream + +This example shows how to execute a search and replace on a stream without +loading the entire stream into memory first. + +```rust +use aho_corasick::AhoCorasick; + +# fn example() -> Result<(), ::std::io::Error> { +let patterns = &["fox", "brown", "quick"]; +let replace_with = &["sloth", "grey", "slow"]; + +// In a real example, these might be `std::fs::File`s instead. All you need to +// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. +let rdr = "The quick brown fox."; +let mut wtr = vec![]; + +let ac = AhoCorasick::new(patterns); +ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?; +assert_eq!(b"The slow grey sloth.".to_vec(), wtr); +# Ok(()) }; example().unwrap() +``` + + +### Example: finding the leftmost first match + +In the textbook description of Aho-Corasick, its formulation is typically +structured such that it reports all possible matches, even when they overlap +with another. In many cases, overlapping matches may not be desired, such as +the case of finding all successive non-overlapping matches like you might with +a standard regular expression. + +Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do +this doesn't always work in the expected way, since it will report matches as +soon as they are seen. For example, consider matching the regex `Samwise|Sam` +against the text `Samwise`. Most regex engines (that are Perl-like, or +non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick +algorithm modified for reporting non-overlapping matches will report `Sam`. + +A novel contribution of this library is the ability to change the match +semantics of Aho-Corasick (without additional search time overhead) such that +`Samwise` is reported instead. For example, here's the standard approach: + +```rust +use aho_corasick::AhoCorasick; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasick::new(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Sam", &haystack[mat.start()..mat.end()]); +``` + +And now here's the leftmost-first version, which matches how a Perl-like +regex will work: + +```rust +use aho_corasick::{AhoCorasickBuilder, MatchKind}; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); +``` + +In addition to leftmost-first semantics, this library also supports +leftmost-longest semantics, which match the POSIX behavior of a regular +expression alternation. See `MatchKind` in the docs for more details. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.24.1`. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. In general, it will follow the `regex` crate's +policy, since `regex` is an important dependent. + + +### Future work + +Here are some plans for the future: + +* Assuming the current API is sufficient, I'd like to commit to it and release + a `1.0` version of this crate some time in the next 6-12 months. +* Despite the crate's name, it seems prudent to consolidate all + multi-pattern search optimizations into this crate so that they get the + widest possible use. A good place to start will be to move the regex + crate's Teddy algorithm into this one. (This is more than just a move. It + will require fleshing out the somewhat simplistic `Prefilter` design that + exists internally currently.) In the future, it would be good to loot + Hyperscan for some of its pertinent algorithms, such as FDR. +* Support stream searching with leftmost match semantics. Currently, only + standard match semantics are supported. Getting this right seems possible, + but is tricky since the match state needs to be propagated through multiple + searches. (With standard semantics, as soon as a match is seen the search + ends.) diff --git a/aho-corasick/UNLICENSE b/aho-corasick/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/aho-corasick/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/aho-corasick/appveyor.yml b/aho-corasick/appveyor.yml new file mode 100644 index 000000000..e4442d46d --- /dev/null +++ b/aho-corasick/appveyor.yml @@ -0,0 +1,26 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + BITS: 64 + MSYS2: 1 + - TARGET: x86_64-pc-windows-msvc + BITS: 64 + - TARGET: i686-pc-windows-gnu + BITS: 32 + MSYS2: 1 + - TARGET: i686-pc-windows-msvc + BITS: 32 +install: + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH% + - rustc -V + - cargo -V +build: false +test_script: + - cargo build --verbose + - cargo test --verbose +branches: + only: + - master diff --git a/aho-corasick/src/ahocorasick.rs b/aho-corasick/src/ahocorasick.rs new file mode 100644 index 000000000..fccd2b8b6 --- /dev/null +++ b/aho-corasick/src/ahocorasick.rs @@ -0,0 +1,2032 @@ +use std::io; + +use automaton::Automaton; +use buffer::Buffer; +use dfa::{self, DFA}; +use error::Result; +use nfa::{self, NFA}; +use prefilter::PrefilterState; +use state_id::StateID; +use Match; + +/// An automaton for searching multiple strings in linear time. +/// +/// The `AhoCorasick` type supports a few basic ways of constructing an +/// automaton, including +/// [`AhoCorasick::new`](struct.AhoCorasick.html#method.new) +/// and +/// [`AhoCorasick::new_auto_configured`](struct.AhoCorasick.html#method.new_auto_configured). +/// However, there are a fair number of configurable options that can be set +/// by using +/// [`AhoCorasickBuilder`](struct.AhoCorasickBuilder.html) +/// instead. Such options include, but are not limited to, how matches are +/// determined, simple case insensitivity, whether to use a DFA or not and +/// various knobs for controlling the space-vs-time trade offs taken when +/// building the automaton. +/// +/// If you aren't sure where to start, try beginning with +/// [`AhoCorasick::new_auto_configured`](struct.AhoCorasick.html#method.new_auto_configured). +/// +/// # Resource usage +/// +/// Aho-Corasick automatons are always constructed in `O(p)` time, where `p` +/// is the combined length of all patterns being searched. With that said, +/// building an automaton can be fairly costly because of high constant +/// factors, particularly when enabling the +/// [DFA](struct.AhoCorasickBuilder.html#method.dfa) +/// option (which is disabled by default). For this reason, it's generally a +/// good idea to build an automaton once and reuse it as much as possible. +/// +/// Aho-Corasick automatons can also use a fair bit of memory. To get a +/// concrete idea of how much memory is being used, try using the +/// [`AhoCorasick::heap_bytes`](struct.AhoCorasick.html#method.heap_bytes) +/// method. +/// +/// # Examples +/// +/// This example shows how to search for occurrences of multiple patterns +/// simultaneously in a case insensitive fashion. Each match includes the +/// pattern that matched along with the byte offsets of the match. +/// +/// ``` +/// use aho_corasick::AhoCorasickBuilder; +/// +/// let patterns = &["apple", "maple", "snapple"]; +/// let haystack = "Nobody likes maple in their apple flavored Snapple."; +/// +/// let ac = AhoCorasickBuilder::new() +/// .ascii_case_insensitive(true) +/// .build(patterns); +/// let mut matches = vec![]; +/// for mat in ac.find_iter(haystack) { +/// matches.push((mat.pattern(), mat.start(), mat.end())); +/// } +/// assert_eq!(matches, vec![ +/// (1, 13, 18), +/// (0, 28, 33), +/// (2, 43, 50), +/// ]); +/// ``` +/// +/// This example shows how to replace matches with some other string: +/// +/// ``` +/// use aho_corasick::AhoCorasick; +/// +/// let patterns = &["fox", "brown", "quick"]; +/// let haystack = "The quick brown fox."; +/// let replace_with = &["sloth", "grey", "slow"]; +/// +/// let ac = AhoCorasick::new(patterns); +/// let result = ac.replace_all(haystack, replace_with); +/// assert_eq!(result, "The slow grey sloth."); +/// ``` +#[derive(Clone, Debug)] +pub struct AhoCorasick { + imp: Imp, + match_kind: MatchKind, +} + +impl AhoCorasick { + /// Create a new Aho-Corasick automaton using the default configuration. + /// + /// The default configuration optimizes for less space usage, but at the + /// expense of longer search times. To change the configuration, use + /// [`AhoCorasickBuilder`](struct.AhoCorasickBuilder.html) + /// for fine-grained control, or + /// [`AhoCorasick::new_auto_configured`](struct.AhoCorasick.html#method.new_auto_configured) + /// for automatic configuration if you aren't sure which settings to pick. + /// + /// This uses the default + /// [`MatchKind::Standard`](enum.MatchKind.html#variant.Standard) + /// match semantics, which reports a match as soon as it is found. This + /// corresponds to the standard match semantics supported by textbook + /// descriptions of the Aho-Corasick algorithm. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new(&[ + /// "foo", "bar", "baz", + /// ]); + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// ``` + pub fn new( + patterns: I, + ) -> AhoCorasick + where I: IntoIterator, + P: AsRef<[u8]> + { + AhoCorasickBuilder::new().build(patterns) + } + + /// Build an Aho-Corasick automaton with an automatically determined + /// configuration. + /// + /// Specifically, this requires a slice of patterns instead of an iterator + /// since the configuration is determined by looking at the patterns before + /// constructing the automaton. The idea here is to balance space and time + /// automatically. That is, when searching a small number of patterns, this + /// will attempt to use the fastest possible configuration since the total + /// space required will be small anyway. As the number of patterns grows, + /// this will fall back to slower configurations that use less space. + /// + /// If you want auto configuration but with match semantics different from + /// the default `MatchKind::Standard`, then use + /// [`AhoCorasickBuilder::auto_configure`](struct.AhoCorasickBuilder.html#method.auto_configure). + /// + /// # Examples + /// + /// Basic usage is just like `new`, except you must provide a slice: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new_auto_configured(&[ + /// "foo", "bar", "baz", + /// ]); + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// ``` + pub fn new_auto_configured( + patterns: &[B], + ) -> AhoCorasick + where B: AsRef<[u8]> + { + AhoCorasickBuilder::new().auto_configure(patterns).build(patterns) + } +} + +impl AhoCorasick { + /// Returns true if and only if this automaton matches the haystack at any + /// position. + /// + /// `haystack` may be any type that is cheaply convertible to a `&[u8]`. + /// This includes, but is not limited to, `String`, `&str`, `Vec`, and + /// `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new(&[ + /// "foo", "bar", "quux", "baz", + /// ]); + /// assert!(ac.is_match("xxx bar xxx")); + /// assert!(!ac.is_match("xxx qux xxx")); + /// ``` + pub fn is_match>(&self, haystack: B) -> bool { + self.earliest_find(haystack).is_some() + } + + /// Returns the location of the first detected match in `haystack`. + /// + /// This method has the same behavior regardless of the + /// [`MatchKind`](enum.MatchKind.html) + /// of this automaton. + /// + /// `haystack` may be any type that is cheaply convertible to a `&[u8]`. + /// This includes, but is not limited to, `String`, `&str`, `Vec`, and + /// `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new(&[ + /// "abc", "b", + /// ]); + /// let mat = ac.earliest_find("abcd").expect("should have match"); + /// assert_eq!(1, mat.pattern()); + /// assert_eq!((1, 2), (mat.start(), mat.end())); + /// ``` + pub fn earliest_find>(&self, haystack: B) -> Option { + let mut prestate = PrefilterState::new(self.max_pattern_len()); + let mut start = self.imp.start_state(); + self.imp.earliest_find_at( + &mut prestate, haystack.as_ref(), 0, &mut start, + ) + } + + /// Returns the location of the first match according to the match + /// semantics that this automaton was constructed with. + /// + /// When using `MatchKind::Standard`, this corresponds precisely to the + /// same behavior as + /// [`earliest_find`](struct.AhoCorasick.html#method.earliest_find). + /// Otherwise, match semantics correspond to either + /// [leftmost-first](enum.MatchKind.html#variant.LeftmostFirst) + /// or + /// [leftmost-longest](enum.MatchKind.html#variant.LeftmostLongest). + /// + /// `haystack` may be any type that is cheaply convertible to a `&[u8]`. + /// This includes, but is not limited to, `String`, `&str`, `Vec`, and + /// `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage, with standard semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::Standard) // default, not necessary + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("b", &haystack[mat.start()..mat.end()]); + /// ``` + /// + /// Now with leftmost-first semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("abc", &haystack[mat.start()..mat.end()]); + /// ``` + /// + /// And finally, leftmost-longest semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostLongest) + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("abcd", &haystack[mat.start()..mat.end()]); + /// ``` + pub fn find>(&self, haystack: B) -> Option { + let mut prestate = PrefilterState::new(self.max_pattern_len()); + let mut start = self.imp.start_state(); + self.imp.find_at(&mut prestate, haystack.as_ref(), 0, &mut start) + } + + /// Returns an iterator of non-overlapping matches, using the match + /// semantics that this automaton was constructed with. + /// + /// `haystack` may be any type that is cheaply convertible to a `&[u8]`. + /// This includes, but is not limited to, `String`, `&str`, `Vec`, and + /// `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage, with standard semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::Standard) // default, not necessary + /// .build(patterns); + /// let matches: Vec = ac + /// .find_iter(haystack) + /// .map(|mat| mat.pattern()) + /// .collect(); + /// assert_eq!(vec![2, 2, 2], matches); + /// ``` + /// + /// Now with leftmost-first semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let matches: Vec = ac + /// .find_iter(haystack) + /// .map(|mat| mat.pattern()) + /// .collect(); + /// assert_eq!(vec![0, 2, 0], matches); + /// ``` + /// + /// And finally, leftmost-longest semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostLongest) + /// .build(patterns); + /// let matches: Vec = ac + /// .find_iter(haystack) + /// .map(|mat| mat.pattern()) + /// .collect(); + /// assert_eq!(vec![0, 2, 1], matches); + /// ``` + pub fn find_iter<'a, 'b, B: ?Sized + AsRef<[u8]>>( + &'a self, + haystack: &'b B, + ) -> FindIter<'a, 'b, S> { + FindIter::new(self, haystack.as_ref()) + } + + /// Returns an iterator of overlapping matches in the given `haystack`. + /// + /// Overlapping matches can _only_ be detected using + /// `MatchKind::Standard` semantics. If this automaton was constructed with + /// leftmost semantics, then this method will panic. To determine whether + /// this will panic at runtime, use the + /// [`AhoCorasick::supports_overlapping`](struct.AhoCorasick.html#method.supports_overlapping) + /// method. + /// + /// `haystack` may be any type that is cheaply convertible to a `&[u8]`. + /// This includes, but is not limited to, `String`, `&str`, `Vec`, and + /// `&[u8]` itself. + /// + /// # Panics + /// + /// This panics when `AhoCorasick::supports_overlapping` returns `false`. + /// That is, this panics when this automaton's match semantics are not + /// `MatchKind::Standard`. + /// + /// # Examples + /// + /// Basic usage, with standard semantics: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasick::new(patterns); + /// let matches: Vec = ac + /// .find_overlapping_iter(haystack) + /// .map(|mat| mat.pattern()) + /// .collect(); + /// assert_eq!(vec![2, 0, 2, 2, 0, 1], matches); + /// ``` + pub fn find_overlapping_iter<'a, 'b, B: ?Sized + AsRef<[u8]>>( + &'a self, + haystack: &'b B, + ) -> FindOverlappingIter<'a, 'b, S> { + FindOverlappingIter::new(self, haystack.as_ref()) + } + + /// Replace all matches with a corresponding value in the `replace_with` + /// slice given. Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// Replacements are determined by the index of the matching pattern. + /// For example, if the pattern with index `2` is found, then it is + /// replaced by `replace_with[2]`. + /// + /// # Panics + /// + /// This panics when `replace_with.len()` does not equal the total number + /// of patterns that are matched by this automaton. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let result = ac.replace_all(haystack, &["x", "y", "z"]); + /// assert_eq!("x the z to the xage", result); + /// ``` + pub fn replace_all( + &self, + haystack: &str, + replace_with: &[B], + ) -> String + where B: AsRef + { + assert_eq!( + replace_with.len(), self.pattern_count(), + "replace_all requires a replacement for every pattern \ + in the automaton" + ); + let mut dst = String::with_capacity(haystack.len()); + self.replace_all_with(haystack, &mut dst, |mat, _, dst| { + dst.push_str(replace_with[mat.pattern()].as_ref()); + true + }); + dst + } + + /// Replace all matches using raw bytes with a corresponding value in the + /// `replace_with` slice given. Matches correspond to the same matches as + /// reported by [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// Replacements are determined by the index of the matching pattern. + /// For example, if the pattern with index `2` is found, then it is + /// replaced by `replace_with[2]`. + /// + /// # Panics + /// + /// This panics when `replace_with.len()` does not equal the total number + /// of patterns that are matched by this automaton. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = b"append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let result = ac.replace_all_bytes(haystack, &["x", "y", "z"]); + /// assert_eq!(b"x the z to the xage".to_vec(), result); + /// ``` + pub fn replace_all_bytes( + &self, + haystack: &[u8], + replace_with: &[B], + ) -> Vec + where B: AsRef<[u8]> + { + assert_eq!( + replace_with.len(), self.pattern_count(), + "replace_all_bytes requires a replacement for every pattern \ + in the automaton" + ); + let mut dst = Vec::with_capacity(haystack.len()); + self.replace_all_with_bytes(haystack, &mut dst, |mat, _, dst| { + dst.extend(replace_with[mat.pattern()].as_ref()); + true + }); + dst + } + + /// Replace all matches using a closure called on each match. + /// Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// The closure accepts three parameters: the match found, the text of + /// the match and a string buffer with which to write the replaced text + /// (if any). If the closure returns `true`, then it continues to the next + /// match. If the closure returns false, then searching is stopped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let mut result = String::new(); + /// ac.replace_all_with(haystack, &mut result, |mat, _, dst| { + /// dst.push_str(&mat.pattern().to_string()); + /// true + /// }); + /// assert_eq!("0 the 2 to the 0age", result); + /// ``` + pub fn replace_all_with( + &self, + haystack: &str, + dst: &mut String, + mut replace_with: F, + ) where F: FnMut(&Match, &str, &mut String) -> bool + { + let mut last_match = 0; + for mat in self.find_iter(haystack) { + dst.push_str(&haystack[last_match..mat.start()]); + last_match = mat.end(); + replace_with(&mat, &haystack[mat.start()..mat.end()], dst); + } + dst.push_str(&haystack[last_match..]); + } + + /// Replace all matches using raw bytes with a closure called on each + /// match. Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// The closure accepts three parameters: the match found, the text of + /// the match and a byte buffer with which to write the replaced text + /// (if any). If the closure returns `true`, then it continues to the next + /// match. If the closure returns false, then searching is stopped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = b"append the app to the appendage"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let mut result = vec![]; + /// ac.replace_all_with_bytes(haystack, &mut result, |mat, _, dst| { + /// dst.extend(mat.pattern().to_string().bytes()); + /// true + /// }); + /// assert_eq!(b"0 the 2 to the 0age".to_vec(), result); + /// ``` + pub fn replace_all_with_bytes( + &self, + haystack: &[u8], + dst: &mut Vec, + mut replace_with: F, + ) where F: FnMut(&Match, &[u8], &mut Vec) -> bool + { + let mut last_match = 0; + for mat in self.find_iter(haystack) { + dst.extend(&haystack[last_match..mat.start()]); + last_match = mat.end(); + replace_with(&mat, &haystack[mat.start()..mat.end()], dst); + } + dst.extend(&haystack[last_match..]); + } + + /// Returns an iterator of non-overlapping matches in the given + /// stream. Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// The matches yielded by this iterator use absolute position offsets in + /// the stream given, where the first byte has index `0`. Matches are + /// yieled until the stream is exhausted. + /// + /// Each item yielded by the iterator is an `io::Result`, where an + /// error is yielded if there was a problem reading from the reader given. + /// + /// When searching a stream, an internal buffer is used. Therefore, callers + /// should avoiding providing a buffered reader, if possible. + /// + /// Searching a stream requires that the automaton was built with + /// `MatchKind::Standard` semantics. If this automaton was constructed + /// with leftmost semantics, then this method will panic. To determine + /// whether this will panic at runtime, use the + /// [`AhoCorasick::supports_stream`](struct.AhoCorasick.html#method.supports_stream) + /// method. + /// + /// # Memory usage + /// + /// In general, searching streams will use a constant amount of memory for + /// its internal buffer. The one requirement is that the internal buffer + /// must be at least the size of the longest possible match. In most use + /// cases, the default buffer size will be much larger than any individual + /// match. + /// + /// # Panics + /// + /// This panics when `AhoCorasick::supports_stream` returns `false`. + /// That is, this panics when this automaton's match semantics are not + /// `MatchKind::Standard`. This restriction may be lifted in the future. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// # fn example() -> Result<(), ::std::io::Error> { + /// let patterns = &["append", "appendage", "app"]; + /// let haystack = "append the app to the appendage"; + /// + /// let ac = AhoCorasick::new(patterns); + /// let mut matches = vec![]; + /// for result in ac.stream_find_iter(haystack.as_bytes()) { + /// let mat = result?; + /// matches.push(mat.pattern()); + /// } + /// assert_eq!(vec![2, 2, 2], matches); + /// # Ok(()) }; example().unwrap() + /// ``` + pub fn stream_find_iter<'a, R: io::Read>( + &'a self, + rdr: R, + ) -> StreamFindIter<'a, R, S> { + StreamFindIter::new(self, rdr) + } + + /// Search for and replace all matches of this automaton in + /// the given reader, and write the replacements to the given + /// writer. Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// Replacements are determined by the index of the matching pattern. + /// For example, if the pattern with index `2` is found, then it is + /// replaced by `replace_with[2]`. + /// + /// After all matches are replaced, the writer is _not_ flushed. + /// + /// If there was a problem reading from the given reader or writing to the + /// given writer, then the corresponding `io::Error` is returned and all + /// replacement is stopped. + /// + /// When searching a stream, an internal buffer is used. Therefore, callers + /// should avoiding providing a buffered reader, if possible. However, + /// callers may want to provide a buffered writer. + /// + /// Searching a stream requires that the automaton was built with + /// `MatchKind::Standard` semantics. If this automaton was constructed + /// with leftmost semantics, then this method will panic. To determine + /// whether this will panic at runtime, use the + /// [`AhoCorasick::supports_stream`](struct.AhoCorasick.html#method.supports_stream) + /// method. + /// + /// # Memory usage + /// + /// In general, searching streams will use a constant amount of memory for + /// its internal buffer. The one requirement is that the internal buffer + /// must be at least the size of the longest possible match. In most use + /// cases, the default buffer size will be much larger than any individual + /// match. + /// + /// # Panics + /// + /// This panics when `AhoCorasick::supports_stream` returns `false`. + /// That is, this panics when this automaton's match semantics are not + /// `MatchKind::Standard`. This restriction may be lifted in the future. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// # fn example() -> Result<(), ::std::io::Error> { + /// let patterns = &["fox", "brown", "quick"]; + /// let haystack = "The quick brown fox."; + /// let replace_with = &["sloth", "grey", "slow"]; + /// + /// let ac = AhoCorasick::new(patterns); + /// let mut result = vec![]; + /// ac.stream_replace_all(haystack.as_bytes(), &mut result, replace_with)?; + /// assert_eq!(b"The slow grey sloth.".to_vec(), result); + /// # Ok(()) }; example().unwrap() + /// ``` + pub fn stream_replace_all( + &self, + rdr: R, + wtr: W, + replace_with: &[B], + ) -> io::Result<()> + where R: io::Read, + W: io::Write, + B: AsRef<[u8]> + { + assert_eq!( + replace_with.len(), self.pattern_count(), + "stream_replace_all requires a replacement for every pattern \ + in the automaton" + ); + self.stream_replace_all_with(rdr, wtr, |mat, _, wtr| { + wtr.write_all(replace_with[mat.pattern()].as_ref()) + }) + } + + /// Search the given reader and replace all matches of this automaton + /// using the given closure. The result is written to the given + /// writer. Matches correspond to the same matches as reported by + /// [`find_iter`](struct.AhoCorasick.html#method.find_iter). + /// + /// The closure accepts three parameters: the match found, the text of + /// the match and the writer with which to write the replaced text + /// (if any). If the closure returns `true`, then it continues to the next + /// match. If the closure returns false, then searching is stopped. + /// + /// After all matches are replaced, the writer is _not_ flushed. + /// + /// If there was a problem reading from the given reader or writing to the + /// given writer, then the corresponding `io::Error` is returned and all + /// replacement is stopped. + /// + /// When searching a stream, an internal buffer is used. Therefore, callers + /// should avoiding providing a buffered reader, if possible. However, + /// callers may want to provide a buffered writer. + /// + /// Searching a stream requires that the automaton was built with + /// `MatchKind::Standard` semantics. If this automaton was constructed + /// with leftmost semantics, then this method will panic. To determine + /// whether this will panic at runtime, use the + /// [`AhoCorasick::supports_stream`](struct.AhoCorasick.html#method.supports_stream) + /// method. + /// + /// # Memory usage + /// + /// In general, searching streams will use a constant amount of memory for + /// its internal buffer. The one requirement is that the internal buffer + /// must be at least the size of the longest possible match. In most use + /// cases, the default buffer size will be much larger than any individual + /// match. + /// + /// # Panics + /// + /// This panics when `AhoCorasick::supports_stream` returns `false`. + /// That is, this panics when this automaton's match semantics are not + /// `MatchKind::Standard`. This restriction may be lifted in the future. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io::Write; + /// use aho_corasick::AhoCorasick; + /// + /// # fn example() -> Result<(), ::std::io::Error> { + /// let patterns = &["fox", "brown", "quick"]; + /// let haystack = "The quick brown fox."; + /// + /// let ac = AhoCorasick::new(patterns); + /// let mut result = vec![]; + /// ac.stream_replace_all_with( + /// haystack.as_bytes(), + /// &mut result, + /// |mat, _, wtr| { + /// wtr.write_all(mat.pattern().to_string().as_bytes()) + /// }, + /// )?; + /// assert_eq!(b"The 2 1 0.".to_vec(), result); + /// # Ok(()) }; example().unwrap() + /// ``` + pub fn stream_replace_all_with( + &self, + rdr: R, + mut wtr: W, + mut replace_with: F, + ) -> io::Result<()> + where R: io::Read, + W: io::Write, + F: FnMut(&Match, &[u8], &mut W) -> io::Result<()> + { + let mut it = StreamChunkIter::new(self, rdr); + while let Some(result) = it.next() { + let chunk = result?; + match chunk { + StreamChunk::NonMatch { bytes, .. } => { + wtr.write_all(bytes)?; + } + StreamChunk::Match { bytes, mat } => { + replace_with(&mat, bytes, &mut wtr)?; + } + } + } + Ok(()) + } + + /// Returns the match kind used by this automaton. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasick, MatchKind}; + /// + /// let ac = AhoCorasick::new(&[ + /// "foo", "bar", "quux", "baz", + /// ]); + /// assert_eq!(&MatchKind::Standard, ac.match_kind()); + /// ``` + pub fn match_kind(&self) -> &MatchKind { + self.imp.match_kind() + } + + /// Returns the length of the longest pattern matched by this automaton. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new(&[ + /// "foo", "bar", "quux", "baz", + /// ]); + /// assert_eq!(4, ac.max_pattern_len()); + /// ``` + pub fn max_pattern_len(&self) -> usize { + self.imp.max_pattern_len() + } + + /// Return the total number of patterns matched by this automaton. + /// + /// This includes patterns that may never participate in a match. For + /// example, if + /// [`MatchKind::LeftmostFirst`](enum.MatchKind.html#variant.LeftmostFirst) + /// match semantics are used, and the patterns `Sam` and `Samwise` were + /// used to build the automaton, then `Samwise` can never participate in a + /// match because `Sam` will always take priority. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasick; + /// + /// let ac = AhoCorasick::new(&[ + /// "foo", "bar", "baz", + /// ]); + /// assert_eq!(3, ac.pattern_count()); + /// ``` + pub fn pattern_count(&self) -> usize { + self.imp.pattern_count() + } + + /// Returns true if and only if this automaton supports reporting + /// overlapping matches. + /// + /// If this returns false and overlapping matches are requested, then it + /// will result in a panic. + /// + /// Since leftmost matching is inherently incompatible with overlapping + /// matches, only + /// [`MatchKind::Standard`](enum.MatchKind.html#variant.Standard) + /// supports overlapping matches. This is unlikely to change in the future. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::Standard) + /// .build(&["foo", "bar", "baz"]); + /// assert!(ac.supports_overlapping()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(&["foo", "bar", "baz"]); + /// assert!(!ac.supports_overlapping()); + /// ``` + pub fn supports_overlapping(&self) -> bool { + self.match_kind.supports_overlapping() + } + + /// Returns true if and only if this automaton supports stream searching. + /// + /// If this returns false and stream searching (or replacing) is attempted, + /// then it will result in a panic. + /// + /// Currently, only + /// [`MatchKind::Standard`](enum.MatchKind.html#variant.Standard) + /// supports streaming. This may be expanded in the future. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::Standard) + /// .build(&["foo", "bar", "baz"]); + /// assert!(ac.supports_stream()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(&["foo", "bar", "baz"]); + /// assert!(!ac.supports_stream()); + /// ``` + pub fn supports_stream(&self) -> bool { + self.match_kind.supports_stream() + } + + /// Returns the total amount of heap used by this automaton, in units of + /// bytes. + /// + /// # Examples + /// + /// This example shows the difference in heap usage between a few + /// configurations: + /// + /// ```ignore + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let ac = AhoCorasickBuilder::new() + /// .dfa(false) // default + /// .build(&["foo", "bar", "baz"]); + /// assert_eq!(10_336, ac.heap_bytes()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .dfa(false) // default + /// .ascii_case_insensitive(true) + /// .build(&["foo", "bar", "baz"]); + /// assert_eq!(10_384, ac.heap_bytes()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .dfa(true) + /// .byte_classes(false) + /// .build(&["foo", "bar", "baz"]); + /// assert_eq!(20_768, ac.heap_bytes()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .dfa(true) + /// .byte_classes(true) // default + /// .build(&["foo", "bar", "baz"]); + /// assert_eq!(1_248, ac.heap_bytes()); + /// + /// let ac = AhoCorasickBuilder::new() + /// .dfa(true) + /// .ascii_case_insensitive(true) + /// .build(&["foo", "bar", "baz"]); + /// assert_eq!(1_248, ac.heap_bytes()); + /// ``` + pub fn heap_bytes(&self) -> usize { + match self.imp { + Imp::NFA(ref nfa) => nfa.heap_bytes(), + Imp::DFA(ref dfa) => dfa.heap_bytes(), + } + } +} + +/// The internal implementation of Aho-Corasick, which is either an NFA or +/// a DFA. The NFA is slower but uses less memory. The DFA is faster but uses +/// more memory. +#[derive(Clone, Debug)] +enum Imp { + NFA(NFA), + DFA(DFA), +} + +impl Imp { + /// Returns the type of match semantics implemented by this automaton. + fn match_kind(&self) -> &MatchKind { + match *self { + Imp::NFA(ref nfa) => nfa.match_kind(), + Imp::DFA(ref dfa) => dfa.match_kind(), + } + } + + /// Returns the identifier of the start state. + fn start_state(&self) -> S { + match *self { + Imp::NFA(ref nfa) => nfa.start_state(), + Imp::DFA(ref dfa) => dfa.start_state(), + } + } + + /// The length, in bytes, of the longest pattern in this automaton. This + /// information is useful for maintaining correct buffer sizes when + /// searching on streams. + fn max_pattern_len(&self) -> usize { + match *self { + Imp::NFA(ref nfa) => nfa.max_pattern_len(), + Imp::DFA(ref dfa) => dfa.max_pattern_len(), + } + } + + /// The total number of patterns added to this automaton. This includes + /// patterns that may never match. The maximum matching pattern that can be + /// reported is exactly one less than this number. + fn pattern_count(&self) -> usize { + match *self { + Imp::NFA(ref nfa) => nfa.pattern_count(), + Imp::DFA(ref dfa) => dfa.pattern_count(), + } + } + + #[inline(always)] + fn overlapping_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + match_index: &mut usize, + ) -> Option { + match *self { + Imp::NFA(ref nfa) => { + nfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + Imp::DFA(ref dfa) => { + dfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + } + } + + #[inline(always)] + fn earliest_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + ) -> Option { + match *self { + Imp::NFA(ref nfa) => { + nfa.earliest_find_at(prestate, haystack, at, state_id) + } + Imp::DFA(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + } + } + + #[inline(always)] + fn find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + ) -> Option { + match *self { + Imp::NFA(ref nfa) => { + nfa.find_at(prestate, haystack, at, state_id) + } + Imp::DFA(ref dfa) => { + dfa.find_at(prestate, haystack, at, state_id) + } + } + } +} + +/// An iterator of non-overlapping matches in a particular haystack. +/// +/// This iterator yields matches according to the +/// [`MatchKind`](enum.MatchKind.html) +/// used by this automaton. +/// +/// This iterator is constructed via the +/// [`AhoCorasick::find_iter`](struct.AhoCorasick.html#method.find_iter) +/// method. +/// +/// The type variable `S` refers to the representation used for state +/// identifiers. (By default, this is `usize`.) +/// +/// The lifetime `'a` refers to the lifetime of the `AhoCorasick` automaton. +/// +/// The lifetime `'b` refers to the lifetime of the haystack being searched. +#[derive(Debug)] +pub struct FindIter<'a, 'b, S: 'a + StateID> { + fsm: &'a Imp, + prestate: PrefilterState, + haystack: &'b [u8], + pos: usize, + start: S, +} + +impl<'a, 'b, S: StateID> FindIter<'a, 'b, S> { + fn new(ac: &'a AhoCorasick, haystack: &'b [u8]) -> FindIter<'a, 'b, S> { + let prestate = PrefilterState::new(ac.max_pattern_len()); + let start = ac.imp.start_state(); + FindIter { fsm: &ac.imp, prestate, haystack, pos: 0, start } + } +} + +impl<'a, 'b, S: StateID> Iterator for FindIter<'a, 'b, S> { + type Item = Match; + + fn next(&mut self) -> Option { + if self.pos > self.haystack.len() { + return None; + } + let mut start = self.start; + let result = self.fsm.find_at( + &mut self.prestate, self.haystack, self.pos, &mut start, + ); + let mat = match result { + None => return None, + Some(mat) => mat, + }; + if mat.end() == self.pos { + // If the automaton can match the empty string and if we found an + // empty match, then we need to forcefully move the position. + self.pos += 1; + } else { + self.pos = mat.end(); + } + Some(mat) + } +} + +/// An iterator of overlapping matches in a particular haystack. +/// +/// This iterator will report all possible matches in a particular haystack, +/// even when the matches overlap. +/// +/// This iterator is constructed via the +/// [`AhoCorasick::find_overlapping_iter`](struct.AhoCorasick.html#method.find_overlapping_iter) +/// method. +/// +/// The type variable `S` refers to the representation used for state +/// identifiers. (By default, this is `usize`.) +/// +/// The lifetime `'a` refers to the lifetime of the `AhoCorasick` automaton. +/// +/// The lifetime `'b` refers to the lifetime of the haystack being searched. +#[derive(Debug)] +pub struct FindOverlappingIter<'a, 'b, S: 'a + StateID> { + fsm: &'a Imp, + prestate: PrefilterState, + haystack: &'b [u8], + pos: usize, + last_match_end: usize, + state_id: S, + match_index: usize, +} + +impl<'a, 'b, S: StateID> FindOverlappingIter<'a, 'b, S> { + fn new( + ac: &'a AhoCorasick, + haystack: &'b [u8], + ) -> FindOverlappingIter<'a, 'b, S> { + assert!( + ac.supports_overlapping(), + "automaton does not support overlapping searches" + ); + let prestate = PrefilterState::new(ac.max_pattern_len()); + FindOverlappingIter { + fsm: &ac.imp, + prestate, + haystack, + pos: 0, + last_match_end: 0, + state_id: ac.imp.start_state(), + match_index: 0, + } + } +} + +impl<'a, 'b, S: StateID> Iterator for FindOverlappingIter<'a, 'b, S> { + type Item = Match; + + fn next(&mut self) -> Option { + let result = self.fsm.overlapping_find_at( + &mut self.prestate, + self.haystack, + self.pos, + &mut self.state_id, + &mut self.match_index, + ); + match result { + None => return None, + Some(m) => { + self.pos = m.end(); + Some(m) + } + } + } +} + +/// An iterator that reports Aho-Corasick matches in a stream. +/// +/// This iterator yields elements of type `io::Result`, where an error +/// is reported if there was a problem reading from the underlying stream. +/// The iterator terminates only when the underlying stream reaches `EOF`. +/// +/// This iterator is constructed via the +/// [`AhoCorasick::stream_find_iter`](struct.AhoCorasick.html#method.stream_find_iter) +/// method. +/// +/// The type variable `R` refers to the `io::Read` stream that is being read +/// from. +/// +/// The type variable `S` refers to the representation used for state +/// identifiers. (By default, this is `usize`.) +/// +/// The lifetime `'a` refers to the lifetime of the `AhoCorasick` automaton. +#[derive(Debug)] +pub struct StreamFindIter<'a, R, S: 'a + StateID> { + it: StreamChunkIter<'a, R, S>, +} + +impl<'a, R: io::Read, S: StateID> StreamFindIter<'a, R, S> { + fn new(ac: &'a AhoCorasick, rdr: R) -> StreamFindIter<'a, R, S> { + StreamFindIter { + it: StreamChunkIter::new(ac, rdr), + } + } +} + +impl<'a, R: io::Read, S: StateID> Iterator for StreamFindIter<'a, R, S> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + loop { + match self.it.next() { + None => return None, + Some(Err(err)) => return Some(Err(err)), + Some(Ok(StreamChunk::NonMatch { .. })) => {} + Some(Ok(StreamChunk::Match { mat, .. })) => { + return Some(Ok(mat)); + } + } + } + } +} + +/// An iterator over chunks in an underlying reader. Each chunk either +/// corresponds to non-matching bytes or matching bytes, but all bytes from +/// the underlying reader are reported in sequence. There may be an arbitrary +/// number of non-matching chunks before seeing a matching chunk. +/// +/// N.B. This does not actually implement Iterator because we need to borrow +/// from the underlying reader. But conceptually, it's still an iterator. +#[derive(Debug)] +struct StreamChunkIter<'a, R, S: 'a + StateID> { + /// The AC automaton. + fsm: &'a Imp, + /// State associated with this automaton's prefilter. It is a heuristic + /// for stopping the prefilter if it's deemed ineffective. + prestate: PrefilterState, + /// The source of bytes we read from. + rdr: R, + /// A fixed size buffer. This is what we actually search. There are some + /// invariants around the buffer's size, namely, it must be big enough to + /// contain the longest possible match. + buf: Buffer, + /// The ID of the FSM state we're currently in. + state_id: S, + /// The current position at which to start the next search in `buf`. + search_pos: usize, + /// The absolute position of `search_pos`, where `0` corresponds to the + /// position of the first byte read from `rdr`. + absolute_pos: usize, + /// The ending position of the last StreamChunk that was returned to the + /// caller. This position is used to determine whether we need to emit + /// non-matching bytes before emitting a match. + report_pos: usize, + /// A match that should be reported on the next call. + pending_match: Option, + /// Enabled only when the automaton can match the empty string. When + /// enabled, we need to execute one final search after consuming the + /// reader to find the trailing empty match. + has_empty_match_at_end: bool, +} + +/// A single chunk yielded by the stream chunk iterator. +/// +/// The `'r` lifetime refers to the lifetime of the stream chunk iterator. +#[derive(Debug)] +enum StreamChunk<'r> { + /// A chunk that does not contain any matches. + NonMatch { bytes: &'r [u8], start: usize }, + /// A chunk that precisely contains a match. + Match { bytes: &'r [u8], mat: Match }, +} + +impl<'a, R: io::Read, S: StateID> StreamChunkIter<'a, R, S> { + fn new(ac: &'a AhoCorasick, rdr: R) -> StreamChunkIter<'a, R, S> { + assert!( + ac.supports_stream(), + "stream searching is only supported for Standard match semantics" + ); + + let prestate = PrefilterState::new(ac.max_pattern_len()); + let buf = Buffer::new(ac.imp.max_pattern_len()); + let state_id = ac.imp.start_state(); + StreamChunkIter { + fsm: &ac.imp, + prestate, + rdr, + buf, + state_id, + absolute_pos: 0, + report_pos: 0, + search_pos: 0, + pending_match: None, + has_empty_match_at_end: ac.is_match(""), + } + } + + fn next<'r>(&'r mut self) -> Option>> { + loop { + if let Some(mut mat) = self.pending_match.take() { + let bytes = &self.buf.buffer()[mat.start()..mat.end()]; + self.report_pos = mat.end(); + mat = mat.increment(self.absolute_pos); + return Some(Ok(StreamChunk::Match { bytes, mat })); + } + if self.search_pos >= self.buf.len() { + if let Some(end) = self.unreported() { + let bytes = &self.buf.buffer()[self.report_pos..end]; + let start = self.absolute_pos + self.report_pos; + self.report_pos = end; + return Some(Ok(StreamChunk::NonMatch { bytes, start })); + } + if self.buf.len() >= self.buf.min_buffer_len() { + // This is the point at which we roll our buffer, which we + // only do if our buffer has at least the minimum amount of + // bytes in it. Before rolling, we update our various + // positions to be consistent with the buffer after it has + // been rolled. + + self.report_pos -= + self.buf.len() - self.buf.min_buffer_len(); + self.absolute_pos += + self.search_pos - self.buf.min_buffer_len(); + self.search_pos = self.buf.min_buffer_len(); + self.buf.roll(); + } + match self.buf.fill(&mut self.rdr) { + Err(err) => return Some(Err(err)), + Ok(false) => { + // We've hit EOF, but if there are still some + // unreported bytes remaining, return them now. + if self.report_pos < self.buf.len() { + let bytes = &self.buf.buffer()[self.report_pos..]; + let start = self.absolute_pos + self.report_pos; + self.report_pos = self.buf.len(); + + let chunk = StreamChunk::NonMatch { bytes, start }; + return Some(Ok(chunk)); + } else { + // We've reported everything, but there might still + // be a match at the very last position. + if !self.has_empty_match_at_end { + return None; + } + // fallthrough for another search to get trailing + // empty matches + self.has_empty_match_at_end = false; + } + } + Ok(true) => {} + } + } + let result = self.fsm.earliest_find_at( + &mut self.prestate, + self.buf.buffer(), + self.search_pos, + &mut self.state_id, + ); + match result { + None => { + self.search_pos = self.buf.len(); + } + Some(mat) => { + self.state_id = self.fsm.start_state(); + if mat.end() == self.search_pos { + // If the automaton can match the empty string and if + // we found an empty match, then we need to forcefully + // move the position. + self.search_pos += 1; + } else { + self.search_pos = mat.end(); + } + self.pending_match = Some(mat.clone()); + if self.report_pos < mat.start() { + let bytes = + &self.buf.buffer()[self.report_pos..mat.start()]; + let start = self.absolute_pos + self.report_pos; + self.report_pos = mat.start(); + + let chunk = StreamChunk::NonMatch { bytes, start }; + return Some(Ok(chunk)); + } + } + } + } + } + + fn unreported(&self) -> Option { + let end = self.search_pos.saturating_sub(self.buf.min_buffer_len()); + if self.report_pos < end { + Some(end) + } else { + None + } + } +} + +/// A builder for configuring an Aho-Corasick automaton. +#[derive(Clone, Debug)] +pub struct AhoCorasickBuilder { + nfa_builder: nfa::Builder, + dfa_builder: dfa::Builder, + dfa: bool, +} + +impl Default for AhoCorasickBuilder { + fn default() -> AhoCorasickBuilder { + AhoCorasickBuilder::new() + } +} + +impl AhoCorasickBuilder { + /// Create a new builder for configuring an Aho-Corasick automaton. + /// + /// If you don't need fine grained configuration or aren't sure which knobs + /// to set, try using + /// [`AhoCorasick::new_auto_configured`](struct.AhoCorasick.html#method.new_auto_configured) + /// instead. + pub fn new() -> AhoCorasickBuilder { + AhoCorasickBuilder { + nfa_builder: nfa::Builder::new(), + dfa_builder: dfa::Builder::new(), + dfa: false, + } + } + + /// Build an Aho-Corasick automaton using the configuration set on this + /// builder. + /// + /// A builder may be reused to create more automatons. + /// + /// This method will use the default for representing internal state + /// identifiers, which is `usize`. This guarantees that building the + /// automaton will succeed and is generally a good default, but can make + /// the size of the automaton 2-8 times bigger than it needs to be, + /// depending on your target platform. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasickBuilder; + /// + /// let patterns = &["foo", "bar", "baz"]; + /// let ac = AhoCorasickBuilder::new() + /// .build(patterns); + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// ``` + pub fn build( + &self, + patterns: I, + ) -> AhoCorasick + where I: IntoIterator, + P: AsRef<[u8]> + { + // The builder only returns an error if the chosen state ID + // representation is too small to fit all of the given patterns. In + // this case, since we fix the representation to usize, it will always + // work because it's impossible to overflow usize since the underlying + // storage would OOM long before that happens. + self.build_with_size::(patterns) + .expect("usize state ID type should always work") + } + + /// Build an Aho-Corasick automaton using the configuration set on this + /// builder with a specific state identifier representation. This only has + /// an effect when the `dfa` option is enabled. + /// + /// Generally, the choices for a state identifier representation are + /// `u8`, `u16`, `u32`, `u64` or `usize`, with `usize` being the default. + /// The advantage of choosing a smaller state identifier representation + /// is that the automaton produced will be smaller. This might be + /// beneficial for just generally using less space, or might even allow it + /// to fit more of the automaton in your CPU's cache, leading to overall + /// better search performance. + /// + /// Unlike the standard `build` method, this can report an error if the + /// state identifier representation cannot support the size of the + /// automaton. + /// + /// Note that the state identifier representation is determined by the + /// `S` type variable. This requires a type hint of some sort, either + /// by specifying the return type or using the turbofish, e.g., + /// `build_with_size::(...)`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; + /// + /// # fn example() -> Result<(), ::aho_corasick::Error> { + /// let patterns = &["foo", "bar", "baz"]; + /// let ac: AhoCorasick = AhoCorasickBuilder::new() + /// .build_with_size(patterns)?; + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// # Ok(()) }; example().unwrap() + /// ``` + /// + /// Or alternatively, with turbofish: + /// + /// ``` + /// use aho_corasick::AhoCorasickBuilder; + /// + /// # fn example() -> Result<(), ::aho_corasick::Error> { + /// let patterns = &["foo", "bar", "baz"]; + /// let ac = AhoCorasickBuilder::new() + /// .build_with_size::(patterns)?; + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// # Ok(()) }; example().unwrap() + /// ``` + pub fn build_with_size( + &self, + patterns: I, + ) -> Result> + where S: StateID, + I: IntoIterator, + P: AsRef<[u8]> + { + let nfa = self.nfa_builder.build(patterns)?; + let match_kind = nfa.match_kind().clone(); + let imp = + if self.dfa { + let dfa = self.dfa_builder.build(&nfa)?; + Imp::DFA(dfa) + } else { + Imp::NFA(nfa) + }; + Ok(AhoCorasick { imp, match_kind }) + } + + /// Automatically configure the settings on this builder according to the + /// patterns that will be used to construct the automaton. + /// + /// The idea here is to balance space and time automatically. That is, when + /// searching a small number of patterns, this will attempt to use the + /// fastest possible configuration since the total space required will be + /// small anyway. As the number of patterns grows, this will fall back to + /// slower configurations that use less space. + /// + /// This is guaranteed to never set `match_kind`, but any other option may + /// be overridden. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasickBuilder; + /// + /// let patterns = &["foo", "bar", "baz"]; + /// let ac = AhoCorasickBuilder::new() + /// .auto_configure(patterns) + /// .build(patterns); + /// assert_eq!(Some(1), ac.find("xxx bar xxx").map(|m| m.pattern())); + /// ``` + pub fn auto_configure>( + &mut self, + patterns: &[B], + ) -> &mut AhoCorasickBuilder { + // N.B. Currently we only use the length of `patterns` to make a + // decision here, and could therefore ask for an `ExactSizeIterator` + // instead. But it's conceivable that we might adapt this to look at + // the total number of bytes, which would requires a second pass. + // + // The logic here is fairly rudimentary at the moment, but probably + // OK. The idea here is to use the fastest thing possible for a small + // number of patterns. That is, a DFA with no byte classes, since byte + // classes require an extra indirection for every byte searched. With a + // moderate number of patterns, we still want a DFA, but save on both + // space and compilation time by enabling byte classes. Finally, fall + // back to the slower but smaller NFA. + if patterns.len() <= 100 { + // N.B. Using byte classes can actually be faster by improving + // locality, but this only really applies for multi-megabyte + // automata (i.e., automata that don't fit in your CPU's cache). + self.dfa(true).byte_classes(false); + } else if patterns.len() <= 5000 { + self.dfa(true); + } + self + } + + /// Set the desired match semantics. + /// + /// The default is `MatchKind::Standard`, which corresponds to the match + /// semantics supported by the standard textbook description of the + /// Aho-Corasick algorithm. Namely, matches are reported as soon as they + /// are found. Moreover, this is the only way to get overlapping matches + /// or do stream searching. + /// + /// The other kinds of match semantics that are supported are + /// `MatchKind::LeftmostFirst` and `MatchKind::LeftmostLongest`. The former + /// corresponds to the match you would get if you were to try to match + /// each pattern at each position in the haystack in the same order that + /// you give to the automaton. That is, it returns the leftmost match + /// corresponding the earliest pattern given to the automaton. The latter + /// corresponds to finding the longest possible match among all leftmost + /// matches. + /// + /// For more details on match semantics, see the + /// [documentation for `MatchKind`](enum.MatchKind.html). + /// + /// # Examples + /// + /// In these examples, we demonstrate the differences between match + /// semantics for a particular set of patterns in a specific order: + /// `b`, `abc`, `abcd`. + /// + /// Standard semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::Standard) // default, not necessary + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("b", &haystack[mat.start()..mat.end()]); + /// ``` + /// + /// Leftmost-first semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostFirst) + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("abc", &haystack[mat.start()..mat.end()]); + /// ``` + /// + /// Leftmost-longest semantics: + /// + /// ``` + /// use aho_corasick::{AhoCorasickBuilder, MatchKind}; + /// + /// let patterns = &["b", "abc", "abcd"]; + /// let haystack = "abcd"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .match_kind(MatchKind::LeftmostLongest) + /// .build(patterns); + /// let mat = ac.find(haystack).expect("should have a match"); + /// assert_eq!("abcd", &haystack[mat.start()..mat.end()]); + /// ``` + pub fn match_kind(&mut self, kind: MatchKind) -> &mut AhoCorasickBuilder { + self.nfa_builder.match_kind(kind); + self + } + + /// Enable ASCII-aware case insensitive matching. + /// + /// When this option is enabled, searching will be performed without + /// respect to case for ASCII letters (`a-z` and `A-Z`) only. + /// + /// Enabling this option does not change the search algorithm, but it may + /// increase the size of the automaton. + /// + /// **NOTE:** In the future, support for full Unicode case insensitivity + /// may be added, but ASCII case insensitivity is comparatively much + /// simpler to add. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use aho_corasick::AhoCorasickBuilder; + /// + /// let patterns = &["FOO", "bAr", "BaZ"]; + /// let haystack = "foo bar baz"; + /// + /// let ac = AhoCorasickBuilder::new() + /// .ascii_case_insensitive(true) + /// .build(patterns); + /// assert_eq!(3, ac.find_iter(haystack).count()); + /// ``` + pub fn ascii_case_insensitive( + &mut self, + yes: bool, + ) -> &mut AhoCorasickBuilder { + self.nfa_builder.ascii_case_insensitive(yes); + self + } + + /// Set the limit on how many NFA states use a dense representation for + /// their transitions. + /// + /// A dense representation uses more space, but supports faster access to + /// transitions at search time. Thus, this setting permits the control of a + /// space vs time trade off when using the NFA variant of Aho-Corasick. + /// + /// This limit is expressed in terms of the depth of a state, i.e., the + /// number of transitions from the starting state of the NFA. The idea is + /// that most of the time searching will be spent near the starting state + /// of the automaton, so states near the start state should use a dense + /// representation. States further away from the start state would then use + /// a sparse representation, which uses less space but is slower to access + /// transitions at search time. + /// + /// By default, this is set to a low but non-zero number. + /// + /// This setting has no effect if the `dfa` option is enabled. + pub fn dense_depth(&mut self, depth: usize) -> &mut AhoCorasickBuilder { + self.nfa_builder.dense_depth(depth); + self + } + + /// Compile the standard Aho-Corasick automaton into a deterministic finite + /// automaton (DFA). + /// + /// When this is disabled (which is the default), then a non-deterministic + /// finite automaton (NFA) is used instead. + /// + /// The main benefit to a DFA is that it can execute searches more quickly + /// than a DFA (perhaps 2-4 times as fast). The main drawback is that the + /// DFA uses more space and can take much longer to build. + /// + /// Enabling this option does not change the time complexity for + /// constructing the Aho-Corasick automaton (which is `O(p)` where + /// `p` is the total number of patterns being compiled). Enabling this + /// option does however reduce the time complexity of non-overlapping + /// searches from `O(n + p)` to `O(n)`, where `n` is the length of the + /// haystack. + /// + /// In general, it's a good idea to enable this if you're searching a + /// small number of fairly short patterns (~1000), or if you want the + /// fastest possible search without regard to compilation time or space + /// usage. + pub fn dfa(&mut self, yes: bool) -> &mut AhoCorasickBuilder { + self.dfa = yes; + self + } + + /// Enable heuristic prefilter optimizations. + /// + /// When enabled, searching will attempt to quickly skip to match + /// candidates using specialized literal search routines. A prefilter + /// cannot always be used, and is generally treated as a heuristic. It + /// can be useful to disable this if the prefilter is observed to be + /// sub-optimal for a particular workload. + /// + /// This is enabled by default. + pub fn prefilter(&mut self, yes: bool) -> &mut AhoCorasickBuilder { + self.nfa_builder.prefilter(yes); + self + } + + /// Shrink the size of the transition alphabet by mapping bytes to their + /// equivalence classes. This only has an effect when the `dfa` option is + /// enabled. + /// + /// When enabled, each a DFA will use a map from all possible bytes + /// to their corresponding equivalence class. Each equivalence class + /// represents a set of bytes that does not discriminate between a match + /// and a non-match in the DFA. For example, the patterns `bar` and `baz` + /// have at least five equivalence classes: singleton sets of `b`, `a`, `r` + /// and `z`, and a final set that contains every other byte. + /// + /// The advantage of this map is that the size of the transition table can + /// be reduced drastically from `#states * 256 * sizeof(id)` to + /// `#states * k * sizeof(id)` where `k` is the number of equivalence + /// classes. As a result, total space usage can decrease substantially. + /// Moreover, since a smaller alphabet is used, compilation becomes faster + /// as well. + /// + /// The disadvantage of this map is that every byte searched must be + /// passed through this map before it can be used to determine the next + /// transition. This has a small match time performance cost. However, if + /// the DFA is otherwise very large without byte classes, then using byte + /// classes can greatly improve memory locality and thus lead to better + /// overall performance. + /// + /// This option is enabled by default. + pub fn byte_classes(&mut self, yes: bool) -> &mut AhoCorasickBuilder { + self.dfa_builder.byte_classes(yes); + self + } + + /// Premultiply state identifiers in the transition table. This only has + /// an effect when the `dfa` option is enabled. + /// + /// When enabled, state identifiers are premultiplied to point to their + /// corresponding row in the transition table. That is, given the `i`th + /// state, its corresponding premultiplied identifier is `i * k` where `k` + /// is the alphabet size of the automaton. (The alphabet size is at most + /// 256, but is in practice smaller if byte classes is enabled.) + /// + /// When state identifiers are not premultiplied, then the identifier of + /// the `i`th state is `i`. + /// + /// The advantage of premultiplying state identifiers is that is saves a + /// multiplication instruction per byte when searching with a DFA. This has + /// been observed to lead to a 20% performance benefit in micro-benchmarks. + /// + /// The primary disadvantage of premultiplying state identifiers is + /// that they require a larger integer size to represent. For example, + /// if the DFA has 200 states, then its premultiplied form requires 16 + /// bits to represent every possible state identifier, where as its + /// non-premultiplied form only requires 8 bits. + /// + /// This option is enabled by default. + pub fn premultiply(&mut self, yes: bool) -> &mut AhoCorasickBuilder { + self.dfa_builder.premultiply(yes); + self + } +} + +/// A knob for controlling the match semantics of an Aho-Corasick automaton. +/// +/// There are two generally different ways that Aho-Corasick automatons can +/// report matches. The first way is the "standard" approach that results from +/// implementing most textbook explanations of Aho-Corasick. The second way is +/// to report only the leftmost non-overlapping matches. The leftmost approach +/// is in turn split into two different ways of resolving ambiguous matches: +/// leftmost-first and leftmost-longest. +/// +/// The `Standard` match kind is the default and is the only one that supports +/// overlapping matches and stream searching. (Trying to find overlapping +/// or streaming matches using leftmost match semantics will result in a +/// panic.) The `Standard` match kind will report matches as they are seen. +/// When searching for overlapping matches, then all possible matches are +/// reported. When searching for non-overlapping matches, the first match seen +/// is reported. For example, for non-overlapping matches, given the patterns +/// `abcd` and `b` and the subject string `abcdef`, only a match for `b` is +/// reported since it is detected first. The `abcd` match is never reported +/// since it overlaps with the `b` match. +/// +/// In contrast, the leftmost match kind always prefers the leftmost match +/// among all possible matches. Given the same example as above with `abcd` and +/// `b` as patterns and `abcdef` as the subject string, the leftmost match is +/// `abcd` since it begins before the `b` match, even though the `b` match is +/// detected before the `abcd` match. In this case, the `b` match is not +/// reported at all since it overlaps with the `abcd` match. +/// +/// The difference between leftmost-first and leftmost-longest is in how they +/// resolve ambiguous matches when there are multiple leftmost matches to +/// choose from. Leftmost-first always chooses the pattern that was provided +/// earliest, where as leftmost-longest always chooses the longest matching +/// pattern. For example, given the patterns `a` and `ab` and the subject +/// string `ab`, the leftmost-first match is `a` but the leftmost-longest match +/// is `ab`. Conversely, if the patterns were given in reverse order, i.e., +/// `ab` and `a`, then both the leftmost-first and leftmost-longest matches +/// would be `ab`. Stated differently, the leftmost-first match depends on the +/// order in which the patterns were given to the Aho-Corasick automaton. +/// Because of that, when leftmost-first matching is used, if a pattern `A` +/// that appears before a pattern `B` is a prefix of `B`, then it is impossible +/// to ever observe a match of `B`. +/// +/// If you're not sure which match kind to pick, then stick with the standard +/// kind, which is the default. In particular, if you need overlapping or +/// streaming matches, then you _must_ use the standard kind. The leftmost +/// kinds are useful in specific circumstances. For example, leftmost-first can +/// be very useful as a way to implement match priority based on the order of +/// patterns given and leftmost-longest can be useful for dictionary searching +/// such that only the longest matching words are reported. +/// +/// # Relationship with regular expression alternations +/// +/// Understanding match semantics can be a little tricky, and one easy way +/// to conceptualize non-overlapping matches from an Aho-Corasick automaton +/// is to think about them as a simple alternation of literals in a regular +/// expression. For example, let's say we wanted to match the strings +/// `Sam` and `Samwise`, which would turn into the regex `Sam|Samwise`. It +/// turns out that regular expression engines have two different ways of +/// matching this alternation. The first way, leftmost-longest, is commonly +/// found in POSIX compatible implementations of regular expressions (such as +/// `grep`). The second way, leftmost-first, is commonly found in backtracking +/// implementations such as Perl. (Some regex engines, such as RE2 and Rust's +/// regex engine do not use backtracking, but still implement leftmost-first +/// semantics in an effort to match the behavior of dominant backtracking +/// regex engines such as those found in Perl, Ruby, Python, Javascript and +/// PHP.) +/// +/// That is, when matching `Sam|Samwise` against `Samwise`, a POSIX regex +/// will match `Samwise` because it is the longest possible match, but a +/// Perl-like regex will match `Sam` since it appears earlier in the +/// alternation. Indeed, the regex `Sam|Samwise` in a Perl-like regex engine +/// will never match `Samwise` since `Sam` will always have higher priority. +/// Conversely, matching the regex `Samwise|Sam` against `Samwise` will lead to +/// a match of `Samwise` in both POSIX and Perl-like regexes since `Samwise` is +/// still longest match, but it also appears earlier than `Sam`. +/// +/// The "standard" match semantics of Aho-Corasick generally don't correspond +/// to the match semantics of any large group of regex implementations, so +/// there's no direct analogy that can be made here. Standard match semantics +/// are generally useful for overlapping matches, or if you just want to see +/// matches as they are detected. +/// +/// The main conclusion to draw from this section is that the match semantics +/// can be tweaked to precisely match either Perl-like regex alternations or +/// POSIX regex alternations. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum MatchKind { + /// Use standard match semantics, which support overlapping matches. When + /// used with non-overlapping matches, matches are reported as they are + /// seen. + Standard, + /// Use leftmost-first match semantics, which reports leftmost matches. + /// When there are multiple possible leftmost matches, the match + /// corresponding to the pattern that appeared earlier when constructing + /// the automaton is reported. + /// + /// This does **not** support overlapping matches or stream searching. If + /// this match kind is used, attempting to find overlapping matches or + /// stream matches will panic. + LeftmostFirst, + /// Use leftmost-longest match semantics, which reports leftmost matches. + /// When there are multiple possible leftmost matches, the longest match + /// is chosen. + /// + /// This does **not** support overlapping matches or stream searching. If + /// this match kind is used, attempting to find overlapping matches or + /// stream matches will panic. + LeftmostLongest, + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +/// The default match kind is `MatchKind::Standard`. +impl Default for MatchKind { + fn default() -> MatchKind { + MatchKind::Standard + } +} + +impl MatchKind { + fn supports_overlapping(&self) -> bool { + self.is_standard() + } + + fn supports_stream(&self) -> bool { + // TODO: It may be possible to support this. It's hard. + // + // See: https://github.com/rust-lang/regex/issues/425#issuecomment-471367838 + self.is_standard() + } + + pub(crate) fn is_standard(&self) -> bool { + *self == MatchKind::Standard + } + + pub(crate) fn is_leftmost(&self) -> bool { + *self == MatchKind::LeftmostFirst + || *self == MatchKind::LeftmostLongest + } + + pub(crate) fn is_leftmost_first(&self) -> bool { + *self == MatchKind::LeftmostFirst + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn oibits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + + fn assert_send() {} + fn assert_sync() {} + fn assert_unwind_safe() {} + + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + } +} diff --git a/aho-corasick/src/automaton.rs b/aho-corasick/src/automaton.rs new file mode 100644 index 000000000..d5935b572 --- /dev/null +++ b/aho-corasick/src/automaton.rs @@ -0,0 +1,401 @@ +use ahocorasick::MatchKind; +use prefilter::{Prefilter, PrefilterState}; +use state_id::{StateID, dead_id, fail_id}; +use Match; + +// NOTE: This trait was essentially copied from regex-automata, with some +// wording changed since we use this trait for NFAs in addition to DFAs in this +// crate. Additionally, we do not export this trait. It's only used internally +// to reduce code duplication. The regex-automata crate needs to expose it +// because its Regex type is generic over implementations of this trait. In +// this crate, we can encapsulate everything behind the AhoCorasick type. + +/// A trait describing the interface of an Aho-Corasick finite state machine. +/// +/// Every automaton has exactly one fail state, one dead state and exactly one +/// start state. Generally, these correspond to the first, second and third +/// states, respectively. The failure state is always treated as a sentinel. +/// That is, no correct Aho-Corasick automaton will ever transition into the +/// fail state. The dead state, however, can be transitioned into, but only +/// when leftmost-first or leftmost-longest match semantics are enabled and +/// only when at least one match has been observed. +/// +/// Every automaton also has one or more match states, such that +/// `Automaton::is_match_state_unchecked(id)` returns `true` if and only if +/// `id` corresponds to a match state. +pub trait Automaton { + /// The representation used for state identifiers in this automaton. + /// + /// Typically, this is one of `u8`, `u16`, `u32`, `u64` or `usize`. + type ID: StateID; + + /// The type of matching that should be done. + fn match_kind(&self) -> &MatchKind; + + /// An optional prefilter for quickly skipping to the next candidate match. + /// A prefilter must report at least every match, although it may report + /// positions that do not correspond to a match. That is, it must not allow + /// false negatives, but can allow false positives. + /// + /// Currently, a prefilter only runs when the automaton is in the start + /// state. That is, the position reported by a prefilter should always + /// correspond to the start of a potential match. + fn prefilter(&self) -> Option<&Prefilter>; + + /// Return the identifier of this automaton's start state. + fn start_state(&self) -> Self::ID; + + /// Returns true if and only if the given state identifier refers to a + /// valid state. + fn is_valid(&self, id: Self::ID) -> bool; + + /// Returns true if and only if the given identifier corresponds to a match + /// state. + /// + /// The state ID given must be valid, or else implementors may panic. + fn is_match_state(&self, id: Self::ID) -> bool; + + /// Returns true if and only if the given identifier corresponds to a state + /// that is either the dead state or a match state. + /// + /// Depending on the implementation of the automaton, this routine can + /// be used to save a branch in the core matching loop. Nevertheless, + /// `is_match_state(id) || id == dead_id()` is always a valid + /// implementation. Indeed, this is the default implementation. + /// + /// The state ID given must be valid, or else implementors may panic. + fn is_match_or_dead_state(&self, id: Self::ID) -> bool { + id == dead_id() || self.is_match_state(id) + } + + /// If the given state is a match state, return the match corresponding + /// to the given match index. `end` must be the ending position of the + /// detected match. If no match exists or if `match_index` exceeds the + /// number of matches in this state, then `None` is returned. + /// + /// The state ID given must be valid, or else implementors may panic. + /// + /// If the given state ID is correct and if the `match_index` is less than + /// the number of matches for that state, then this is guaranteed to return + /// a match. + fn get_match( + &self, + id: Self::ID, + match_index: usize, + end: usize, + ) -> Option; + + /// Returns the number of matches for the given state. If the given state + /// is not a match state, then this returns 0. + /// + /// The state ID given must be valid, or else implementors must panic. + fn match_count(&self, id: Self::ID) -> usize; + + /// Given the current state that this automaton is in and the next input + /// byte, this method returns the identifier of the next state. The + /// identifier returned must always be valid and may never correspond to + /// the fail state. The returned identifier may, however, point to the + /// dead state. + /// + /// This is not safe so that implementors may look up the next state + /// without memory safety checks such as bounds checks. As such, callers + /// must ensure that the given identifier corresponds to a valid automaton + /// state. Implementors must, in turn, ensure that this routine is safe for + /// all valid state identifiers and for all possible `u8` values. + unsafe fn next_state_unchecked( + &self, + current: Self::ID, + input: u8, + ) -> Self::ID; + + /// Like next_state_unchecked, but debug_asserts that the underlying + /// implementation never returns a `fail_id()` for the next state. + unsafe fn next_state_unchecked_no_fail( + &self, + current: Self::ID, + input: u8, + ) -> Self::ID { + let next = self.next_state_unchecked(current, input); + // We should never see a transition to the failure state. + debug_assert!( + next != fail_id(), + "automaton should never return fail_id for next state" + ); + next + } + + /// Execute a search using standard match semantics. + /// + /// This can be used even when the automaton was constructed with leftmost + /// match semantics when you want to find the earliest possible match. This + /// can also be used as part of an overlapping search implementation. + /// + /// N.B. This does not report a match if `state_id` is given as a matching + /// state. As such, this should not be used directly. + #[inline(always)] + fn standard_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + if let Some(pre) = self.prefilter() { + self.standard_find_at_imp( + prestate, Some(pre), haystack, at, state_id, + ) + } else { + self.standard_find_at_imp( + prestate, None, haystack, at, state_id, + ) + } + } + + // It's important for this to always be inlined. Namely, it's only caller + // is standard_find_at, and the inlining should remove the case analysis + // for prefilter scanning when there is no prefilter available. + #[inline(always)] + fn standard_find_at_imp( + &self, + prestate: &mut PrefilterState, + prefilter: Option<&Prefilter>, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + // This is necessary for guaranteeing a safe API, since we use the + // state ID below in a function that exhibits UB if called with an + // invalid state ID. + assert!( + self.is_valid(*state_id), + "{} is not a valid state ID", + state_id.to_usize() + ); + unsafe { + let start = haystack.as_ptr(); + let end = haystack[haystack.len()..].as_ptr(); + let mut ptr = haystack[at..].as_ptr(); + while ptr < end { + if let Some(pre) = prefilter { + if prestate.is_effective() + && *state_id == self.start_state() + { + let at = ptr as usize - start as usize; + match pre.next_candidate(haystack, at) { + None => return None, + Some(i) => { + prestate.update(i - at); + ptr = start.offset(i as isize); + } + } + } + } + // SAFETY: next_state is safe for all possible u8 values, + // so the only thing we're concerned about is the validity + // of `state_id`. `state_id` either comes from the caller + // (in which case, we assert above that it is valid), or it + // comes from the return value of next_state, which is also + // guaranteed to be valid. + *state_id = self.next_state_unchecked_no_fail(*state_id, *ptr); + ptr = ptr.offset(1); + // This routine always quits immediately after seeing a + // match, and since dead states can only come after seeing + // a match, seeing a dead state here is impossible. + debug_assert!( + *state_id != dead_id(), + "standard find should never see a dead state" + ); + + let end = ptr as usize - start as usize; + if let Some(m) = self.get_match(*state_id, 0, end) { + return Some(m); + } + } + None + } + } + + /// Execute a search using leftmost (either first or longest) match + /// semantics. + /// + /// The principle difference between searching with standard semantics and + /// searching with leftmost semantics is that leftmost searching will + /// continue searching even after a match has been found. Once a match + /// is found, the search does not stop until either the haystack has been + /// exhausted or a dead state is observed in the automaton. (Dead states + /// only exist in automatons constructed with leftmost semantics.) That is, + /// we rely on the construction of the automaton to tell us when to quit. + #[inline(never)] + fn leftmost_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + if let Some(pre) = self.prefilter() { + self.leftmost_find_at_imp( + prestate, Some(pre), haystack, at, state_id, + ) + } else { + self.leftmost_find_at_imp( + prestate, None, haystack, at, state_id, + ) + } + } + + // It's important for this to always be inlined. Namely, it's only caller + // is leftmost_find_at, and the inlining should remove the case analysis + // for prefilter scanning when there is no prefilter available. + #[inline(always)] + fn leftmost_find_at_imp( + &self, + prestate: &mut PrefilterState, + prefilter: Option<&Prefilter>, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + debug_assert!(self.match_kind().is_leftmost()); + // This is necessary for guaranteeing a safe API, since we use the + // state ID below in a function that exhibits UB if called with an + // invalid state ID. + assert!( + self.is_valid(*state_id), + "{} is not a valid state ID", + state_id.to_usize() + ); + unsafe { + let start = haystack.as_ptr(); + let end = haystack[haystack.len()..].as_ptr(); + let mut ptr = haystack[at..].as_ptr(); + + let mut last_match = self.get_match(*state_id, 0, at); + while ptr < end { + if let Some(pre) = prefilter { + if prestate.is_effective() + && *state_id == self.start_state() + { + let at = ptr as usize - start as usize; + match pre.next_candidate(haystack, at) { + None => return None, + Some(i) => { + prestate.update(i - at); + ptr = start.offset(i as isize); + } + } + } + } + // SAFETY: next_state is safe for all possible u8 values, + // so the only thing we're concerned about is the validity + // of `state_id`. `state_id` either comes from the caller + // (in which case, we assert above that it is valid), or it + // comes from the return value of next_state, which is also + // guaranteed to be valid. + *state_id = self.next_state_unchecked_no_fail(*state_id, *ptr); + ptr = ptr.offset(1); + if self.is_match_or_dead_state(*state_id) { + if *state_id == dead_id() { + // The only way to enter into a dead state is if a + // match has been found, so we assert as much. This + // is different from normal automata, where you might + // enter a dead state if you know a subsequent match + // will never be found (regardless of whether a match + // has already been found). For Aho-Corasick, it is + // built so that we can match at any position, so the + // possibility of a match always exists. + debug_assert!( + last_match.is_some(), + "failure state should only be seen after match" + ); + return last_match; + } + let end = ptr as usize - start as usize; + last_match = self.get_match(*state_id, 0, end); + } + } + last_match + } + } + + /// Execute an overlapping search. + /// + /// When executing an overlapping match, the previous state ID in addition + /// to the previous match index should be given. If there are more matches + /// at the given state, then the match is reported and the given index is + /// incremented. + #[inline(always)] + fn overlapping_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + match_index: &mut usize, + ) -> Option { + let match_count = self.match_count(*state_id); + if *match_index < match_count { + // This is guaranteed to return a match since + // match_index < match_count. + let result = self.get_match( + *state_id, + *match_index, + at, + ); + debug_assert!(result.is_some(), "must be a match"); + *match_index += 1; + return result; + } + + *match_index = 0; + match self.standard_find_at(prestate, haystack, at, state_id) { + None => None, + Some(m) => { + *match_index = 1; + Some(m) + } + } + } + + /// Return the earliest match found. This returns as soon as we know that + /// we have a match. As such, this does not necessarily correspond to the + /// leftmost starting match, but rather, the leftmost position at which a + /// match ends. + #[inline(always)] + fn earliest_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + if *state_id == self.start_state() { + if let Some(m) = self.get_match(*state_id, 0, at) { + return Some(m); + } + } + self.standard_find_at(prestate, haystack, at, state_id) + } + + /// A convenience function for finding the next match according to the + /// match semantics of this automaton. For standard match semantics, this + /// finds the earliest match. Otherwise, the leftmost match is found. + #[inline(always)] + fn find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut Self::ID, + ) -> Option { + match *self.match_kind() { + MatchKind::Standard => { + self.earliest_find_at(prestate, haystack, at, state_id) + } + MatchKind::LeftmostFirst | MatchKind::LeftmostLongest => { + self.leftmost_find_at(prestate, haystack, at, state_id) + } + MatchKind::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/aho-corasick/src/buffer.rs b/aho-corasick/src/buffer.rs new file mode 100644 index 000000000..f3e632c46 --- /dev/null +++ b/aho-corasick/src/buffer.rs @@ -0,0 +1,131 @@ +use std::cmp; +use std::io; +use std::ptr; + +/// The default buffer capacity that we use for the stream buffer. +const DEFAULT_BUFFER_CAPACITY: usize = 8 * (1<<10); // 8 KB + +/// A fairly simple roll buffer for supporting stream searches. +/// +/// This buffer acts as a temporary place to store a fixed amount of data when +/// reading from a stream. Its central purpose is to allow "rolling" some +/// suffix of the data to the beginning of the buffer before refilling it with +/// more data from the stream. For example, let's say we are trying to match +/// "foobar" on a stream. When we report the match, we'd like to not only +/// report the correct offsets at which the match occurs, but also the matching +/// bytes themselves. So let's say our stream is a file with the following +/// contents: `test test foobar test test`. Now assume that we happen to read +/// the aforementioned file in two chunks: `test test foo` and `bar test test`. +/// Naively, it would not be possible to report a single contiguous `foobar` +/// match, but this roll buffer allows us to do that. Namely, after the second +/// read, the contents of the buffer should be `st foobar test test`, where the +/// search should ultimately resume immediately after `foo`. (The prefix `st ` +/// is included because the roll buffer saves N bytes at the end of the buffer, +/// where N is the maximum possible length of a match.) +/// +/// A lot of the logic for dealing with this is unfortunately split out between +/// this roll buffer and the `StreamChunkIter`. +#[derive(Debug)] +pub struct Buffer { + /// The raw buffer contents. This has a fixed size and never increases. + buf: Vec, + /// The minimum size of the buffer, which is equivalent to the maximum + /// possible length of a match. This corresponds to the amount that we + /// roll + min: usize, + /// The end of the contents of this buffer. + end: usize, +} + +impl Buffer { + /// Create a new buffer for stream searching. The minimum buffer length + /// given should be the size of the maximum possible match length. + pub fn new(min_buffer_len: usize) -> Buffer { + let min = cmp::max(1, min_buffer_len); + // The minimum buffer amount is also the amount that we roll our + // buffer in order to support incremental searching. To this end, + // our actual capacity needs to be at least 1 byte bigger than our + // minimum amount, otherwise we won't have any overlap. In actuality, + // we want our buffer to be a bit bigger than that for performance + // reasons, so we set a lower bound of `8 * min`. + // + // TODO: It would be good to find a way to test the streaming + // implementation with the minimal buffer size. + let capacity = cmp::max(min * 8, DEFAULT_BUFFER_CAPACITY); + Buffer { + buf: vec![0; capacity], + min, + end: 0, + } + } + + /// Return the contents of this buffer. + #[inline] + pub fn buffer(&self) -> &[u8] { + &self.buf[..self.end] + } + + /// Return the minimum size of the buffer. The only way a buffer may be + /// smaller than this is if the stream itself contains less than the + /// minimum buffer amount. + #[inline] + pub fn min_buffer_len(&self) -> usize { + self.min + } + + /// Return the total length of the contents in the buffer. + #[inline] + pub fn len(&self) -> usize { + self.end + } + + /// Return all free capacity in this buffer. + fn free_buffer(&mut self) -> &mut [u8] { + &mut self.buf[self.end..] + } + + /// Refill the contents of this buffer by reading as much as possible into + /// this buffer's free capacity. If no more bytes could be read, then this + /// returns false. Otherwise, this reads until it has filled the buffer + /// past the minimum amount. + pub fn fill(&mut self, mut rdr: R) -> io::Result { + let mut readany = false; + loop { + let readlen = rdr.read(self.free_buffer())?; + if readlen == 0 { + return Ok(readany); + } + readany = true; + self.end += readlen; + if self.len() >= self.min { + return Ok(true); + } + } + } + + /// Roll the contents of the buffer so that the suffix of this buffer is + /// moved to the front and all other contents are dropped. The size of the + /// suffix corresponds precisely to the minimum buffer length. + /// + /// This should only be called when the entire contents of this buffer have + /// been searched. + pub fn roll(&mut self) { + let roll_start = self.end + .checked_sub(self.min) + .expect("buffer capacity should be bigger than minimum amount"); + let roll_len = self.min; + + assert!(roll_start + roll_len <= self.end); + unsafe { + // SAFETY: A buffer contains Copy data, so there's no problem + // moving it around. Safety also depends on our indices being in + // bounds, which they always should be, given the assert above. + ptr::copy( + self.buf[roll_start..].as_ptr(), + self.buf.as_mut_ptr(), + roll_len, + ); + } + self.end = roll_len; + } +} diff --git a/aho-corasick/src/classes.rs b/aho-corasick/src/classes.rs new file mode 100644 index 000000000..f1933c42a --- /dev/null +++ b/aho-corasick/src/classes.rs @@ -0,0 +1,243 @@ +use std::fmt; + +/// A representation of byte oriented equivalence classes. +/// +/// This is used in an FSM to reduce the size of the transition table. This can +/// have a particularly large impact not only on the total size of an FSM, but +/// also on compile times. +#[derive(Clone, Copy)] +pub struct ByteClasses([u8; 256]); + +impl ByteClasses { + /// Creates a new set of equivalence classes where all bytes are mapped to + /// the same class. + pub fn empty() -> ByteClasses { + ByteClasses([0; 256]) + } + + /// Creates a new set of equivalence classes where each byte belongs to + /// its own equivalence class. + pub fn singletons() -> ByteClasses { + let mut classes = ByteClasses::empty(); + for i in 0..256 { + classes.set(i as u8, i as u8); + } + classes + } + + /// Set the equivalence class for the given byte. + #[inline] + pub fn set(&mut self, byte: u8, class: u8) { + self.0[byte as usize] = class; + } + + /// Get the equivalence class for the given byte. + #[inline] + pub fn get(&self, byte: u8) -> u8 { + self.0[byte as usize] + } + + /// Get the equivalence class for the given byte while forcefully + /// eliding bounds checks. + #[inline] + pub unsafe fn get_unchecked(&self, byte: u8) -> u8 { + *self.0.get_unchecked(byte as usize) + } + + /// Return the total number of elements in the alphabet represented by + /// these equivalence classes. Equivalently, this returns the total number + /// of equivalence classes. + #[inline] + pub fn alphabet_len(&self) -> usize { + self.0[255] as usize + 1 + } + + /// Returns true if and only if every byte in this class maps to its own + /// equivalence class. Equivalently, there are 256 equivalence classes + /// and each class contains exactly one byte. + #[inline] + pub fn is_singleton(&self) -> bool { + self.alphabet_len() == 256 + } + + /// Returns an iterator over a sequence of representative bytes from each + /// equivalence class. Namely, this yields exactly N items, where N is + /// equivalent to the number of equivalence classes. Each item is an + /// arbitrary byte drawn from each equivalence class. + /// + /// This is useful when one is determinizing an NFA and the NFA's alphabet + /// hasn't been converted to equivalence classes yet. Picking an arbitrary + /// byte from each equivalence class then permits a full exploration of + /// the NFA instead of using every possible byte value. + pub fn representatives(&self) -> ByteClassRepresentatives { + ByteClassRepresentatives { classes: self, byte: 0, last_class: None } + } + + /// Returns all of the bytes in the given equivalence class. + /// + /// The second element in the tuple indicates the number of elements in + /// the array. + fn elements(&self, equiv: u8) -> ([u8; 256], usize) { + let (mut array, mut len) = ([0; 256], 0); + for b in 0..256 { + if self.get(b as u8) == equiv { + array[len] = b as u8; + len += 1; + } + } + (array, len) + } +} + +impl fmt::Debug for ByteClasses { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_singleton() { + write!(f, "ByteClasses({{singletons}})") + } else { + write!(f, "ByteClasses(")?; + for equiv in 0..self.alphabet_len() { + let (members, len) = self.elements(equiv as u8); + write!(f, " {} => {:?}", equiv, &members[..len])?; + } + write!(f, ")") + } + } +} + +/// An iterator over representative bytes from each equivalence class. +#[derive(Debug)] +pub struct ByteClassRepresentatives<'a> { + classes: &'a ByteClasses, + byte: usize, + last_class: Option, +} + +impl<'a> Iterator for ByteClassRepresentatives<'a> { + type Item = u8; + + fn next(&mut self) -> Option { + while self.byte < 256 { + let byte = self.byte as u8; + let class = self.classes.get(byte); + self.byte += 1; + + if self.last_class != Some(class) { + self.last_class = Some(class); + return Some(byte); + } + } + None + } +} + +/// A byte class builder keeps track of an *approximation* of equivalence +/// classes of bytes during NFA construction. That is, every byte in an +/// equivalence class cannot discriminate between a match and a non-match. +/// +/// For example, in the literals `abc` and `xyz`, the bytes [\x00-`], [d-w] +/// and [{-\xFF] never discriminate between a match and a non-match, precisely +/// because they never occur in the literals anywhere. +/// +/// Note though that this does not necessarily compute the minimal set of +/// equivalence classes. For example, in the literals above, the byte ranges +/// [\x00-`], [d-w] and [{-\xFF] are all treated as distinct equivalence +/// classes even though they could be treated a single class. The reason for +/// this is implementation complexity. In the future, we should endeavor to +/// compute the minimal equivalence classes since they can have a rather large +/// impact on the size of the DFA. +/// +/// The representation here is 256 booleans, all initially set to false. Each +/// boolean maps to its corresponding byte based on position. A `true` value +/// indicates the end of an equivalence class, where its corresponding byte +/// and all of the bytes corresponding to all previous contiguous `false` +/// values are in the same equivalence class. +/// +/// This particular representation only permits contiguous ranges of bytes to +/// be in the same equivalence class, which means that we can never discover +/// the true minimal set of equivalence classes. +#[derive(Debug)] +pub struct ByteClassBuilder(Vec); + +impl ByteClassBuilder { + /// Create a new builder of byte classes where all bytes are part of the + /// same equivalence class. + pub fn new() -> ByteClassBuilder { + ByteClassBuilder(vec![false; 256]) + } + + /// Indicate the the range of byte given (inclusive) can discriminate a + /// match between it and all other bytes outside of the range. + pub fn set_range(&mut self, start: u8, end: u8) { + debug_assert!(start <= end); + if start > 0 { + self.0[start as usize - 1] = true; + } + self.0[end as usize] = true; + } + + /// Build byte classes that map all byte values to their corresponding + /// equivalence class. The last mapping indicates the largest equivalence + /// class identifier (which is never bigger than 255). + pub fn build(&self) -> ByteClasses { + let mut classes = ByteClasses::empty(); + let mut class = 0u8; + let mut i = 0; + loop { + classes.set(i as u8, class as u8); + if i >= 255 { + break; + } + if self.0[i] { + class = class.checked_add(1).unwrap(); + } + i += 1; + } + classes + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn byte_classes() { + let mut set = ByteClassBuilder::new(); + set.set_range(b'a', b'z'); + + let classes = set.build(); + assert_eq!(classes.get(0), 0); + assert_eq!(classes.get(1), 0); + assert_eq!(classes.get(2), 0); + assert_eq!(classes.get(b'a' - 1), 0); + assert_eq!(classes.get(b'a'), 1); + assert_eq!(classes.get(b'm'), 1); + assert_eq!(classes.get(b'z'), 1); + assert_eq!(classes.get(b'z' + 1), 2); + assert_eq!(classes.get(254), 2); + assert_eq!(classes.get(255), 2); + + let mut set = ByteClassBuilder::new(); + set.set_range(0, 2); + set.set_range(4, 6); + let classes = set.build(); + assert_eq!(classes.get(0), 0); + assert_eq!(classes.get(1), 0); + assert_eq!(classes.get(2), 0); + assert_eq!(classes.get(3), 1); + assert_eq!(classes.get(4), 2); + assert_eq!(classes.get(5), 2); + assert_eq!(classes.get(6), 2); + assert_eq!(classes.get(7), 3); + assert_eq!(classes.get(255), 3); + } + + #[test] + fn full_byte_classes() { + let mut set = ByteClassBuilder::new(); + for i in 0..256u16 { + set.set_range(i as u8, i as u8); + } + assert_eq!(set.build().alphabet_len(), 256); + } +} diff --git a/aho-corasick/src/dfa.rs b/aho-corasick/src/dfa.rs new file mode 100644 index 000000000..64fcfa3e6 --- /dev/null +++ b/aho-corasick/src/dfa.rs @@ -0,0 +1,688 @@ +use std::mem::size_of; + +use ahocorasick::MatchKind; +use automaton::Automaton; +use classes::ByteClasses; +use error::Result; +use nfa::{NFA, PatternID, PatternLength}; +use prefilter::{Prefilter, PrefilterObj, PrefilterState}; +use state_id::{StateID, dead_id, fail_id, premultiply_overflow_error}; +use Match; + +#[derive(Clone, Debug)] +pub enum DFA { + Standard(Standard), + ByteClass(ByteClass), + Premultiplied(Premultiplied), + PremultipliedByteClass(PremultipliedByteClass), +} + +impl DFA { + fn repr(&self) -> &Repr { + match *self { + DFA::Standard(ref dfa) => dfa.repr(), + DFA::ByteClass(ref dfa) => dfa.repr(), + DFA::Premultiplied(ref dfa) => dfa.repr(), + DFA::PremultipliedByteClass(ref dfa) => dfa.repr(), + } + } + + pub fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + pub fn heap_bytes(&self) -> usize { + self.repr().heap_bytes + } + + pub fn max_pattern_len(&self) -> usize { + self.repr().max_pattern_len + } + + pub fn pattern_count(&self) -> usize { + self.repr().pattern_count + } + + pub fn start_state(&self) -> S { + self.repr().start_id + } + + #[inline(always)] + pub fn overlapping_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + match_index: &mut usize, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => { + dfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + DFA::ByteClass(ref dfa) => { + dfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + DFA::Premultiplied(ref dfa) => { + dfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + DFA::PremultipliedByteClass(ref dfa) => { + dfa.overlapping_find_at( + prestate, haystack, at, state_id, match_index, + ) + } + } + } + + #[inline(always)] + pub fn earliest_find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::ByteClass(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::Premultiplied(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + DFA::PremultipliedByteClass(ref dfa) => { + dfa.earliest_find_at(prestate, haystack, at, state_id) + } + } + } + + #[inline(always)] + pub fn find_at( + &self, + prestate: &mut PrefilterState, + haystack: &[u8], + at: usize, + state_id: &mut S, + ) -> Option { + match *self { + DFA::Standard(ref dfa) => { + dfa.find_at(prestate, haystack, at, state_id) + } + DFA::ByteClass(ref dfa) => { + dfa.find_at(prestate, haystack, at, state_id) + } + DFA::Premultiplied(ref dfa) => { + dfa.find_at(prestate, haystack, at, state_id) + } + DFA::PremultipliedByteClass(ref dfa) => { + dfa.find_at(prestate, haystack, at, state_id) + } + } + } +} + +#[derive(Clone, Debug)] +pub struct Standard(Repr); + +impl Standard { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for Standard { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn prefilter(&self) -> Option<&Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + id.to_usize() < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + self.repr().get_match(id, match_index, end) + } + + fn match_count(&self, id: S) -> usize { + self.repr().match_count(id) + } + + unsafe fn next_state_unchecked(&self, current: S, input: u8) -> S { + let o = current.to_usize() * 256 + input as usize; + *self.repr().trans.get_unchecked(o) + } +} + +#[derive(Clone, Debug)] +pub struct ByteClass(Repr); + +impl ByteClass { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for ByteClass { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn prefilter(&self) -> Option<&Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + id.to_usize() < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + self.repr().get_match(id, match_index, end) + } + + fn match_count(&self, id: S) -> usize { + self.repr().match_count(id) + } + + unsafe fn next_state_unchecked(&self, current: S, input: u8) -> S { + let alphabet_len = self.repr().byte_classes.alphabet_len(); + let input = self.repr().byte_classes.get_unchecked(input); + let o = current.to_usize() * alphabet_len + input as usize; + *self.repr().trans.get_unchecked(o) + } +} + +#[derive(Clone, Debug)] +pub struct Premultiplied(Repr); + +impl Premultiplied { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for Premultiplied { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn prefilter(&self) -> Option<&Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + (id.to_usize() / 256) < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.repr().max_match { + return None; + } + self.repr() + .matches + .get(id.to_usize() / 256) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + fn match_count(&self, id: S) -> usize { + let o = id.to_usize() / 256; + self.repr().matches[o].len() + } + + unsafe fn next_state_unchecked(&self, current: S, input: u8) -> S { + let o = current.to_usize() + input as usize; + *self.repr().trans.get_unchecked(o) + } +} + +#[derive(Clone, Debug)] +pub struct PremultipliedByteClass(Repr); + +impl PremultipliedByteClass { + fn repr(&self) -> &Repr { + &self.0 + } +} + +impl Automaton for PremultipliedByteClass { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.repr().match_kind + } + + fn prefilter(&self) -> Option<&Prefilter> { + self.repr().prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.repr().start_id + } + + fn is_valid(&self, id: S) -> bool { + (id.to_usize() / self.repr().alphabet_len()) < self.repr().state_count + } + + fn is_match_state(&self, id: S) -> bool { + self.repr().is_match_state(id) + } + + fn is_match_or_dead_state(&self, id: S) -> bool { + self.repr().is_match_or_dead_state(id) + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.repr().max_match { + return None; + } + self.repr() + .matches + .get(id.to_usize() / self.repr().alphabet_len()) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + fn match_count(&self, id: S) -> usize { + let o = id.to_usize() / self.repr().alphabet_len(); + self.repr().matches[o].len() + } + + unsafe fn next_state_unchecked(&self, current: S, input: u8) -> S { + let input = self.repr().byte_classes.get_unchecked(input); + let o = current.to_usize() + input as usize; + *self.repr().trans.get_unchecked(o) + } +} + +#[derive(Clone, Debug)] +pub struct Repr { + match_kind: MatchKind, + premultiplied: bool, + start_id: S, + /// The length, in bytes, of the longest pattern in this automaton. This + /// information is useful for keeping correct buffer sizes when searching + /// on streams. + max_pattern_len: usize, + /// The total number of patterns added to this automaton. This includes + /// patterns that may never match. + pattern_count: usize, + state_count: usize, + max_match: S, + /// The number of bytes of heap used by this NFA's transition table. + heap_bytes: usize, + /// A prefilter for quickly detecting candidate matchs, if pertinent. + prefilter: Option, + byte_classes: ByteClasses, + trans: Vec, + matches: Vec>, +} + +impl Repr { + /// Returns the total alphabet size for this DFA. + /// + /// If byte classes are enabled, then this corresponds to the number of + /// equivalence classes. If they are disabled, then this is always 256. + fn alphabet_len(&self) -> usize { + self.byte_classes.alphabet_len() + } + + /// Returns true only if the given state is a match state. + fn is_match_state(&self, id: S) -> bool { + id <= self.max_match && id > dead_id() + } + + /// Returns true only if the given state is either a dead state or a match + /// state. + fn is_match_or_dead_state(&self, id: S) -> bool { + id <= self.max_match + } + + /// Get the ith match for the given state, where the end position of a + /// match was found at `end`. + /// + /// # Panics + /// + /// The caller must ensure that the given state identifier is valid, + /// otherwise this may panic. The `match_index` need not be valid. That is, + /// if the given state has no matches then this returns `None`. + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + if id > self.max_match { + return None; + } + self.matches + .get(id.to_usize()) + .and_then(|m| m.get(match_index)) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + /// Return the total number of matches for the given state. + /// + /// # Panics + /// + /// The caller must ensure that the given identifier is valid, or else + /// this panics. + fn match_count(&self, id: S) -> usize { + self.matches[id.to_usize()].len() + } + + /// Get the next state given `from` as the current state and `byte` as the + /// current input byte. + fn next_state(&self, from: S, byte: u8) -> S { + let alphabet_len = self.alphabet_len(); + let byte = self.byte_classes.get(byte); + self.trans[from.to_usize() * alphabet_len + byte as usize] + } + + /// Set the `byte` transition for the `from` state to point to `to`. + fn set_next_state(&mut self, from: S, byte: u8, to: S) { + let alphabet_len = self.alphabet_len(); + let byte = self.byte_classes.get(byte); + self.trans[from.to_usize() * alphabet_len + byte as usize] = to; + } + + /// Swap the given states in place. + fn swap_states(&mut self, id1: S, id2: S) { + assert!(!self.premultiplied, "can't swap states in premultiplied DFA"); + + let o1 = id1.to_usize() * self.alphabet_len(); + let o2 = id2.to_usize() * self.alphabet_len(); + for b in 0..self.alphabet_len() { + self.trans.swap(o1 + b, o2 + b); + } + self.matches.swap(id1.to_usize(), id2.to_usize()); + } + + /// This routine shuffles all match states in this DFA to the beginning + /// of the DFA such that every non-match state appears after every match + /// state. (With one exception: the special fail and dead states remain as + /// the first two states.) + /// + /// The purpose of doing this shuffling is to avoid an extra conditional + /// in the search loop, and in particular, detecting whether a state is a + /// match or not does not need to access any memory. + /// + /// This updates `self.max_match` to point to the last matching state as + /// well as `self.start` if the starting state was moved. + fn shuffle_match_states(&mut self) { + assert!( + !self.premultiplied, + "cannot shuffle match states of premultiplied DFA" + ); + + if self.state_count <= 1 { + return; + } + + let mut first_non_match = self.start_id.to_usize(); + while first_non_match < self.state_count + && self.matches[first_non_match].len() > 0 + { + first_non_match += 1; + } + + let mut swaps: Vec = vec![fail_id(); self.state_count]; + let mut cur = self.state_count - 1; + while cur > first_non_match { + if self.matches[cur].len() > 0 { + self.swap_states( + S::from_usize(cur), + S::from_usize(first_non_match), + ); + swaps[cur] = S::from_usize(first_non_match); + swaps[first_non_match] = S::from_usize(cur); + + first_non_match += 1; + while first_non_match < cur + && self.matches[first_non_match].len() > 0 + { + first_non_match += 1; + } + } + cur -= 1; + } + for id in (0..self.state_count).map(S::from_usize) { + let alphabet_len = self.alphabet_len(); + let offset = id.to_usize() * alphabet_len; + for next in &mut self.trans[offset..offset + alphabet_len] { + if swaps[next.to_usize()] != fail_id() { + *next = swaps[next.to_usize()]; + } + } + } + if swaps[self.start_id.to_usize()] != fail_id() { + self.start_id = swaps[self.start_id.to_usize()]; + } + self.max_match = S::from_usize(first_non_match - 1); + } + + fn premultiply(&mut self) -> Result<()> { + if self.premultiplied || self.state_count <= 1 { + return Ok(()); + } + + let alpha_len = self.alphabet_len(); + premultiply_overflow_error( + S::from_usize(self.state_count - 1), + alpha_len, + )?; + + for id in (2..self.state_count).map(S::from_usize) { + let offset = id.to_usize() * alpha_len; + for next in &mut self.trans[offset..offset + alpha_len] { + if *next == dead_id() { + continue; + } + *next = S::from_usize(next.to_usize() * alpha_len); + } + } + self.premultiplied = true; + self.start_id = S::from_usize(self.start_id.to_usize() * alpha_len); + self.max_match = S::from_usize(self.max_match.to_usize() * alpha_len); + Ok(()) + } + + /// Computes the total amount of heap used by this NFA in bytes. + fn calculate_size(&mut self) { + let mut size = + (self.trans.len() * size_of::()) + + (self.matches.len() * + size_of::>()); + for state_matches in &self.matches { + size += + state_matches.len() * size_of::<(PatternID, PatternLength)>(); + } + self.heap_bytes = size; + } +} + +/// A builder for configuring the determinization of an NFA into a DFA. +#[derive(Clone, Debug)] +pub struct Builder { + premultiply: bool, + byte_classes: bool, +} + +impl Builder { + /// Create a new builder for a DFA. + pub fn new() -> Builder { + Builder { + premultiply: true, + byte_classes: true, + } + } + + /// Build a DFA from the given NFA. + /// + /// This returns an error if the state identifiers exceed their + /// representation size. This can only happen when state ids are + /// premultiplied (which is enabled by default). + pub fn build(&self, nfa: &NFA) -> Result> { + let byte_classes = + if self.byte_classes { + nfa.byte_classes().clone() + } else { + ByteClasses::singletons() + }; + let alphabet_len = byte_classes.alphabet_len(); + let trans = vec![fail_id(); alphabet_len * nfa.state_len()]; + let matches = vec![vec![]; nfa.state_len()]; + let mut repr = Repr { + match_kind: nfa.match_kind().clone(), + premultiplied: false, + start_id: nfa.start_state(), + max_pattern_len: nfa.max_pattern_len(), + pattern_count: nfa.pattern_count(), + state_count: nfa.state_len(), + max_match: fail_id(), + heap_bytes: 0, + prefilter: nfa.prefilter_obj().map(|p| p.clone()), + byte_classes: byte_classes.clone(), + trans: trans, + matches: matches, + }; + for id in (0..nfa.state_len()).map(S::from_usize) { + repr.matches[id.to_usize()].extend_from_slice(nfa.matches(id)); + + let fail = nfa.failure_transition(id); + nfa.iter_all_transitions(&byte_classes, id, |b, mut next| { + if next == fail_id() { + next = nfa_next_state_memoized(nfa, &repr, id, fail, b); + } + repr.set_next_state(id, b, next); + }); + } + repr.shuffle_match_states(); + repr.calculate_size(); + if self.premultiply { + repr.premultiply()?; + if byte_classes.is_singleton() { + Ok(DFA::Premultiplied(Premultiplied(repr))) + } else { + Ok(DFA::PremultipliedByteClass(PremultipliedByteClass(repr))) + } + } else { + if byte_classes.is_singleton() { + Ok(DFA::Standard(Standard(repr))) + } else { + Ok(DFA::ByteClass(ByteClass(repr))) + } + } + } + + /// Whether to use byte classes or in the DFA. + pub fn byte_classes(&mut self, yes: bool) -> &mut Builder { + self.byte_classes = yes; + self + } + + /// Whether to premultiply state identifier in the DFA. + pub fn premultiply(&mut self, yes: bool) -> &mut Builder { + self.premultiply = yes; + self + } +} + +/// This returns the next NFA transition (including resolving failure +/// transitions), except once it sees a state id less than the id of the DFA +/// state that is currently being populated, then we no longer need to follow +/// failure transitions and can instead query the pre-computed state id from +/// the DFA itself. +/// +/// In general, this should only be called when a failure transition is seen. +fn nfa_next_state_memoized( + nfa: &NFA, + dfa: &Repr, + populating: S, + mut current: S, + input: u8, +) -> S { + loop { + if current < populating { + return dfa.next_state(current, input); + } + let next = nfa.next_state(current, input); + if next != fail_id() { + return next; + } + current = nfa.failure_transition(current); + } +} diff --git a/aho-corasick/src/error.rs b/aho-corasick/src/error.rs new file mode 100644 index 000000000..c9cb233e1 --- /dev/null +++ b/aho-corasick/src/error.rs @@ -0,0 +1,103 @@ +use std::error; +use std::fmt; +use std::result; + +pub type Result = result::Result; + +/// An error that occurred during the construction of an Aho-Corasick +/// automaton. +#[derive(Clone, Debug)] +pub struct Error { + kind: ErrorKind, +} + +/// The kind of error that occurred. +#[derive(Clone, Debug)] +pub enum ErrorKind { + /// An error that occurs when constructing an automaton would require the + /// use of a state ID that overflows the chosen state ID representation. + /// For example, if one is using `u8` for state IDs and builds a DFA with + /// 257 states, then the last state's ID will be `256` which cannot be + /// represented with `u8`. + StateIDOverflow { + /// The maximum possible state ID. + max: usize, + }, + /// An error that occurs when premultiplication of state IDs is requested + /// when constructing an Aho-Corasick DFA, but doing so would overflow the + /// chosen state ID representation. + /// + /// When `max == requested_max`, then the state ID would overflow `usize`. + PremultiplyOverflow { + /// The maximum possible state id. + max: usize, + /// The maximum ID required by premultiplication. + requested_max: usize, + } +} + +impl Error { + /// Return the kind of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } + + pub(crate) fn state_id_overflow(max: usize) -> Error { + Error { kind: ErrorKind::StateIDOverflow { max } } + } + + pub(crate) fn premultiply_overflow( + max: usize, + requested_max: usize, + ) -> Error { + Error { kind: ErrorKind::PremultiplyOverflow { max, requested_max } } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match self.kind { + ErrorKind::StateIDOverflow { .. } => { + "state id representation too small" + } + ErrorKind::PremultiplyOverflow { .. } => { + "state id representation too small for premultiplication" + } + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.kind { + ErrorKind::StateIDOverflow { max } => { + write!( + f, + "building the automaton failed because it required \ + building more states that can be identified, where the \ + maximum ID for the chosen representation is {}", + max, + ) + } + ErrorKind::PremultiplyOverflow { max, requested_max } => { + if max == requested_max { + write!( + f, + "premultiplication of states requires the ability to \ + represent a state ID greater than what can fit on \ + this platform's usize, which is {}", + ::std::usize::MAX, + ) + } else { + write!( + f, + "premultiplication of states requires the ability to \ + represent at least a state ID of {}, but the chosen \ + representation only permits a maximum state ID of {}", + requested_max, max, + ) + } + } + } + } +} diff --git a/aho-corasick/src/lib.rs b/aho-corasick/src/lib.rs new file mode 100644 index 000000000..0294d12e7 --- /dev/null +++ b/aho-corasick/src/lib.rs @@ -0,0 +1,289 @@ +/*! +A library for finding occurrences of many patterns at once. This library +provides multiple pattern search principally through an implementation of the +[Aho-Corasick algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm), +which builds a fast finite state machine for executing searches in linear time. + +Additionally, this library provides a number of configuration options for +building the automaton that permit controlling the space versus time trade +off. Other features include simple ASCII case insensitive matching, finding +overlapping matches, replacements, searching streams and even searching and +replacing text in streams. + +Finally, unlike all other (known) Aho-Corasick implementations, this one +supports enabling +[leftmost-first](enum.MatchKind.html#variant.LeftmostFirst) +or +[leftmost-longest](enum.MatchKind.html#variant.LeftmostFirst) +match semantics, using a (seemingly) novel alternative construction algorithm. +For more details on what match semantics means, see the +[`MatchKind`](enum.MatchKind.html) +type. + +# Overview + +This section gives a brief overview of the primary types in this crate: + +* [`AhoCorasick`](struct.AhoCorasick.html) is the primary type and represents + an Aho-Corasick automaton. This is the type you use to execute searches. +* [`AhoCorasickBuilder`](struct.AhoCorasickBuilder.html) can be used to build + an Aho-Corasick automaton, and supports configuring a number of options. +* [`Match`](struct.Match.html) represents a single match reported by an + Aho-Corasick automaton. Each match has two pieces of information: the pattern + that matched and the start and end byte offsets corresponding to the position + in the haystack at which it matched. + +# Example: basic searching + +This example shows how to search for occurrences of multiple patterns +simultaneously. Each match includes the pattern that matched along with the +byte offsets of the match. + +``` +use aho_corasick::AhoCorasick; + +let patterns = &["apple", "maple", "Snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasick::new(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + +# Example: case insensitivity + +This is like the previous example, but matches `Snapple` case insensitively +using `AhoCorasickBuilder`: + +``` +use aho_corasick::AhoCorasickBuilder; + +let patterns = &["apple", "maple", "snapple"]; +let haystack = "Nobody likes maple in their apple flavored Snapple."; + +let ac = AhoCorasickBuilder::new() + .ascii_case_insensitive(true) + .build(patterns); +let mut matches = vec![]; +for mat in ac.find_iter(haystack) { + matches.push((mat.pattern(), mat.start(), mat.end())); +} +assert_eq!(matches, vec![ + (1, 13, 18), + (0, 28, 33), + (2, 43, 50), +]); +``` + +# Example: replacing matches in a stream + +This example shows how to execute a search and replace on a stream without +loading the entire stream into memory first. + +``` +use aho_corasick::AhoCorasick; + +# fn example() -> Result<(), ::std::io::Error> { +let patterns = &["fox", "brown", "quick"]; +let replace_with = &["sloth", "grey", "slow"]; + +// In a real example, these might be `std::fs::File`s instead. All you need to +// do is supply a pair of `std::io::Read` and `std::io::Write` implementations. +let rdr = "The quick brown fox."; +let mut wtr = vec![]; + +let ac = AhoCorasick::new(patterns); +ac.stream_replace_all(rdr.as_bytes(), &mut wtr, replace_with)?; +assert_eq!(b"The slow grey sloth.".to_vec(), wtr); +# Ok(()) }; example().unwrap() +``` + +# Example: finding the leftmost first match + +In the textbook description of Aho-Corasick, its formulation is typically +structured such that it reports all possible matches, even when they overlap +with another. In many cases, overlapping matches may not be desired, such as +the case of finding all successive non-overlapping matches like you might with +a standard regular expression. + +Unfortunately the "obvious" way to modify the Aho-Corasick algorithm to do +this doesn't always work in the expected way, since it will report matches as +soon as they are seen. For example, consider matching the regex `Samwise|Sam` +against the text `Samwise`. Most regex engines (that are Perl-like, or +non-POSIX) will report `Samwise` as a match, but the standard Aho-Corasick +algorithm modified for reporting non-overlapping matches will report `Sam`. + +A novel contribution of this library is the ability to change the match +semantics of Aho-Corasick (without additional search time overhead) such that +`Samwise` is reported instead. For example, here's the standard approach: + +``` +use aho_corasick::AhoCorasick; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasick::new(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Sam", &haystack[mat.start()..mat.end()]); +``` + +And now here's the leftmost-first version, which matches how a Perl-like +regex will work: + +``` +use aho_corasick::{AhoCorasickBuilder, MatchKind}; + +let patterns = &["Samwise", "Sam"]; +let haystack = "Samwise"; + +let ac = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(patterns); +let mat = ac.find(haystack).expect("should have a match"); +assert_eq!("Samwise", &haystack[mat.start()..mat.end()]); +``` + +In addition to leftmost-first semantics, this library also supports +leftmost-longest semantics, which match the POSIX behavior of a regular +expression alternation. See +[`MatchKind`](enum.MatchKind.html) +for more details. + +# Prefilters + +While an Aho-Corasick automaton can perform admirably when compared to more +naive solutions, it is generally slower than more specialized algorithms that +are accelerated using vector instructions such as SIMD. + +For that reason, this library will internally use a "prefilter" to attempt +to accelerate searches when possible. Currently, this library has fairly +limited implementation that only applies when there are 3 or fewer unique +starting bytes among all patterns in an automaton. + +In the future, it is intended for this prefilter to grow more sophisticated +by pushing applicable optimizations from the +[`regex`](http://docs.rs/regex) +crate (and other places) down into this library. + +While a prefilter is generally good to have on by default since it works well +in the common case, it can lead to less predictable or even sub-optimal +performance in some cases. For that reason, prefilters can be disabled via +[`AhoCorasickBuilder::prefilter`](struct.AhoCorasickBuilder.html#method.prefilter). +*/ + +#![deny(missing_docs)] + +// We can never be truly no_std, but we could be alloc-only some day, so +// require the std feature for now. +#[cfg(not(feature = "std"))] +compile_error!("`std` feature is currently required to build this crate"); + +extern crate memchr; + +pub use ahocorasick::{ + AhoCorasick, AhoCorasickBuilder, MatchKind, + FindIter, FindOverlappingIter, StreamFindIter, +}; +pub use error::{Error, ErrorKind}; +pub use state_id::StateID; + +mod ahocorasick; +mod automaton; +mod buffer; +mod dfa; +mod error; +mod classes; +mod prefilter; +mod nfa; +mod state_id; +#[cfg(test)] +mod tests; + +/// A representation of a match reported by an Aho-Corasick automaton. +/// +/// A match has two essential pieces of information: the identifier of the +/// pattern that matched, along with the start and end offsets of the match +/// in the haystack. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use aho_corasick::AhoCorasick; +/// +/// let ac = AhoCorasick::new(&[ +/// "foo", "bar", "baz", +/// ]); +/// let mat = ac.find("xxx bar xxx").expect("should have a match"); +/// assert_eq!(1, mat.pattern()); +/// assert_eq!(4, mat.start()); +/// assert_eq!(7, mat.end()); +/// ``` +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Match { + /// The pattern id. + pattern: usize, + /// The length of this match, such that the starting position of the match + /// is `end - len`. + /// + /// We use length here because, other than the pattern id, the only + /// information about each pattern that the automaton stores is its length. + /// So using the length here is just a bit more natural. But it isn't + /// technically required. + len: usize, + /// The end offset of the match, exclusive. + end: usize, +} + +impl Match { + /// Returns the identifier of the pattern that matched. + /// + /// The identifier of a pattern is derived from the position in which it + /// was originally inserted into the corresponding automaton. The first + /// pattern has identifier `0`, and each subsequent pattern is `1`, `2` + /// and so on. + #[inline] + pub fn pattern(&self) -> usize { + self.pattern + } + + /// The starting position of the match. + #[inline] + pub fn start(&self) -> usize { + self.end - self.len + } + + /// The ending position of the match. + #[inline] + pub fn end(&self) -> usize { + self.end + } + + /// Returns true if and only if this match is empty. That is, when + /// `start() == end()`. + /// + /// An empty match can only be returned when the empty string was among + /// the patterns used to build the Aho-Corasick automaton. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + #[inline] + fn increment(&self, by: usize) -> Match { + Match { + pattern: self.pattern, + len: self.len, + end: self.end + by, + } + } +} diff --git a/aho-corasick/src/nfa.rs b/aho-corasick/src/nfa.rs new file mode 100644 index 000000000..289ebaaa2 --- /dev/null +++ b/aho-corasick/src/nfa.rs @@ -0,0 +1,1230 @@ +use std::collections::VecDeque; +use std::cmp; +use std::fmt; +use std::mem::size_of; + +use ahocorasick::MatchKind; +use automaton::Automaton; +use classes::{ByteClasses, ByteClassBuilder}; +use error::Result; +use prefilter::{self, Prefilter, PrefilterObj}; +use state_id::{StateID, dead_id, fail_id, usize_to_state_id}; +use Match; + +/// The identifier for a pattern, which is simply the position of the pattern +/// in the sequence of patterns given by the caller. +pub type PatternID = usize; + +/// The length of a pattern, in bytes. +pub type PatternLength = usize; + +/// An Aho-Corasick automaton, represented as an NFA. +/// +/// This is the classical formulation of Aho-Corasick, which involves building +/// up a prefix trie of a given set of patterns, and then wiring up failure +/// transitions between states in order to guarantee linear time matching. The +/// standard formulation is, technically, an NFA because of these failure +/// transitions. That is, one can see them as enabling the automaton to be in +/// multiple states at once. Indeed, during search, it is possible to check +/// the transitions on multiple states for a single input byte. +/// +/// This particular implementation not only supports the standard style of +/// matching, but also provides a mode for choosing leftmost-first or +/// leftmost-longest match semantics. When a leftmost mode is chosen, some +/// failure transitions that would otherwise be added are elided. See +/// the documentation of `MatchKind` for more details and examples on how the +/// match semantics may differ. +/// +/// If one wants a DFA, then it is necessary to first build an NFA and convert +/// it into a DFA. Note, however, that because we've constrained ourselves to +/// matching literal patterns, this does not need to use subset construction +/// for determinization. Instead, the DFA has at most a number of states +/// equivalent to the number of NFA states. The only real difference between +/// them is that all failure transitions are followed and pre-computed. This +/// uses much more memory, but also executes searches more quickly. +#[derive(Clone)] +pub struct NFA { + /// The match semantics built into this NFA. + match_kind: MatchKind, + /// The start state id as an index into `states`. + start_id: S, + /// The length, in bytes, of the longest pattern in this automaton. This + /// information is useful for keeping correct buffer sizes when searching + /// on streams. + max_pattern_len: usize, + /// The total number of patterns added to this automaton, including + /// patterns that may never be matched. + pattern_count: usize, + /// The number of bytes of heap used by this NFA's transition table. + heap_bytes: usize, + /// A prefilter for quickly skipping to candidate matches, if pertinent. + prefilter: Option, + /// A set of equivalence classes in terms of bytes. We compute this while + /// building the NFA, but don't use it in the NFA's states. Instead, we + /// use this for building the DFA. We store it on the NFA since it's easy + /// to compute while visiting the the patterns. + byte_classes: ByteClasses, + /// A set of states. Each state defines its own transitions, a fail + /// transition and a set of indices corresponding to matches. + /// + /// The first state is always the fail state, which is used only as a + /// sentinel. Namely, in the final NFA, no transition into the fail state + /// exists. (Well, they do, but they aren't followed. Instead, the state's + /// failure transition is followed.) + /// + /// The second state (index 1) is always the dead state. Dead states are + /// in every automaton, but only used when leftmost-{first,longest} match + /// semantics are enabled. Specifically, they instruct search to stop + /// at specific points in order to report the correct match location. In + /// the standard Aho-Corasick construction, there are no transitions to + /// the dead state. + /// + /// The third state (index 2) is generally intended to be the starting or + /// "root" state. + states: Vec>, +} + +impl NFA { + /// Returns the equivalence classes of bytes found while constructing + /// this NFA. + /// + /// Note that the NFA doesn't actually make use of these equivalence + /// classes. Instead, these are useful for building the DFA when desired. + pub fn byte_classes(&self) -> &ByteClasses { + &self.byte_classes + } + + /// Returns a start byte prefilter, if one exists. + pub fn prefilter_obj(&self) -> Option<&PrefilterObj> { + self.prefilter.as_ref() + } + + /// Returns the total number of heap bytes used by this NFA's transition + /// table. + pub fn heap_bytes(&self) -> usize { + self.heap_bytes + } + + /// Return the length of the longest pattern in this automaton. + pub fn max_pattern_len(&self) -> usize { + self.max_pattern_len + } + + /// Return the total number of patterns added to this automaton. + pub fn pattern_count(&self) -> usize { + self.pattern_count + } + + /// Returns the total number of states in this NFA. + pub fn state_len(&self) -> usize { + self.states.len() + } + + /// Returns the matches for the given state. + pub fn matches(&self, id: S) -> &[(PatternID, PatternLength)] { + &self.states[id.to_usize()].matches + } + + /// Returns an iterator over all transitions in the given state according + /// to the given equivalence classes, including transitions to `fail_id()`. + /// The number of transitions returned is always equivalent to the number + /// of equivalence classes. + pub fn iter_all_transitions( + &self, + byte_classes: &ByteClasses, + id: S, + f: F, + ) { + self.states[id.to_usize()].trans.iter_all(byte_classes, f); + } + + /// Returns the failure transition for the given state. + pub fn failure_transition(&self, id: S) -> S { + self.states[id.to_usize()].fail + } + + /// Returns the next state for the given state and input byte. + /// + /// Note that this does not follow failure transitions. As such, the id + /// returned may be `fail_id`. + pub fn next_state(&self, current: S, input: u8) -> S { + self.states[current.to_usize()].next_state(input) + } + + fn state(&self, id: S) -> &State { + &self.states[id.to_usize()] + } + + fn state_mut(&mut self, id: S) -> &mut State { + &mut self.states[id.to_usize()] + } + + fn start(&self) -> &State { + self.state(self.start_id) + } + + fn start_mut(&mut self) -> &mut State { + let id = self.start_id; + self.state_mut(id) + } + + fn iter_transitions_mut(&mut self, id: S) -> IterTransitionsMut { + IterTransitionsMut::new(self, id) + } + + fn copy_matches(&mut self, src: S, dst: S) { + let (src, dst) = get_two_mut( + &mut self.states, src.to_usize(), dst.to_usize(), + ); + dst.matches.extend_from_slice(&src.matches); + } + + fn copy_empty_matches(&mut self, dst: S) { + let start_id = self.start_id; + self.copy_matches(start_id, dst); + } + + fn add_dense_state(&mut self, depth: usize) -> Result { + let trans = Transitions::Dense(vec![fail_id(); 256]); + let id = usize_to_state_id(self.states.len())?; + self.states.push(State { + trans, + fail: self.start_id, + depth: depth, + matches: vec![], + }); + Ok(id) + } + + fn add_sparse_state(&mut self, depth: usize) -> Result { + let trans = Transitions::Sparse(vec![]); + let id = usize_to_state_id(self.states.len())?; + self.states.push(State { + trans, + fail: self.start_id, + depth: depth, + matches: vec![], + }); + Ok(id) + } +} + +impl Automaton for NFA { + type ID = S; + + fn match_kind(&self) -> &MatchKind { + &self.match_kind + } + + fn prefilter(&self) -> Option<&Prefilter> { + self.prefilter.as_ref().map(|p| p.as_ref()) + } + + fn start_state(&self) -> S { + self.start_id + } + + fn is_valid(&self, id: S) -> bool { + id.to_usize() < self.states.len() + } + + fn is_match_state(&self, id: S) -> bool { + self.states[id.to_usize()].is_match() + } + + fn get_match( + &self, + id: S, + match_index: usize, + end: usize, + ) -> Option { + let state = match self.states.get(id.to_usize()) { + None => return None, + Some(state) => state, + }; + state.matches + .get(match_index) + .map(|&(id, len)| Match { pattern: id, len, end }) + } + + fn match_count(&self, id: S) -> usize { + self.states[id.to_usize()].matches.len() + } + + unsafe fn next_state_unchecked(&self, mut current: S, input: u8) -> S { + // This terminates since: + // + // 1. `State.fail` never points to fail_id(). + // 2. All `State.fail` values point to a state closer to `start`. + // 3. The start state has no transitions to fail_id(). + loop { + let state = self.states.get_unchecked(current.to_usize()); + let next = state.next_state(input); + if next != fail_id() { + return next; + } + current = state.fail; + } + } +} + +/// A representation of an NFA state for an Aho-Corasick automaton. +/// +/// It contains the transitions to the next state, a failure transition for +/// cases where there exists no other transition for the current input byte, +/// the matches implied by visiting this state (if any) and the depth of this +/// state. The depth of a state is simply the distance from it to the start +/// state in the automaton, where the depth of the start state is 0. +#[derive(Clone, Debug)] +pub struct State { + trans: Transitions, + fail: S, + matches: Vec<(PatternID, PatternLength)>, + // TODO: Strictly speaking, this isn't needed for searching. It's only + // used when building an NFA that supports leftmost match semantics. We + // could drop this from the state and dynamically build a map only when + // computing failure transitions, but it's not clear which is better. + // Benchmark this. + depth: usize, +} + +impl State { + fn heap_bytes(&self) -> usize { + self.trans.heap_bytes() + + (self.matches.len() * size_of::<(PatternID, PatternLength)>()) + } + + fn add_match(&mut self, i: PatternID, len: PatternLength) { + self.matches.push((i, len)); + } + + fn is_match(&self) -> bool { + !self.matches.is_empty() + } + + fn get_longest_match_len(&self) -> Option { + // Why is this true? Because the first match in any matching state + // will always correspond to the match added to it during trie + // construction (since when we copy matches due to failure transitions, + // we always append them). Therefore, it follows that the first match + // must always be longest since any subsequent match must be from a + // failure transition, and a failure transition by construction points + // to a proper suffix. A proper suffix is, by definition, smaller. + self.matches.get(0).map(|&(_, len)| len) + } + + fn next_state(&self, input: u8) -> S { + self.trans.next_state(input) + } + + fn set_next_state(&mut self, input: u8, next: S) { + self.trans.set_next_state(input, next); + } +} + +/// A representation of transitions in an NFA. +/// +/// Transitions have either a sparse representation, which is slower for +/// lookups but uses less memory, or a dense representation, which is faster +/// for lookups but uses more memory. In the sparse representation, the absence +/// of a state implies a transition to `fail_id()`. Transitions to `dead_id()` +/// are still explicitly represented. +/// +/// For the NFA, by default, we use a dense representation for transitions for +/// states close to the start state because it's likely these are the states +/// that will be most frequently visited. +#[derive(Clone, Debug)] +enum Transitions { + Sparse(Vec<(u8, S)>), + Dense(Vec), +} + +impl Transitions { + fn heap_bytes(&self) -> usize { + match *self { + Transitions::Sparse(ref sparse) => { + sparse.len() * size_of::<(u8, S)>() + } + Transitions::Dense(ref dense) => { + dense.len() * size_of::() + } + } + } + + fn next_state(&self, input: u8) -> S { + match *self { + Transitions::Sparse(ref sparse) => { + for &(b, id) in sparse { + if b == input { + return id; + } + } + fail_id() + } + Transitions::Dense(ref dense) => { + // SAFETY: This is safe because all dense transitions have + // exactly 256 elements, so all u8 values are valid indices. + unsafe { *dense.get_unchecked(input as usize) } + } + } + } + + fn set_next_state(&mut self, input: u8, next: S) { + match *self { + Transitions::Sparse(ref mut sparse) => { + match sparse.binary_search_by_key(&input, |&(b, _)| b) { + Ok(i) => sparse[i] = (input, next), + Err(i) => sparse.insert(i, (input, next)), + } + } + Transitions::Dense(ref mut dense) => { + dense[input as usize] = next; + } + } + } + + /// Iterate over transitions in this state while skipping over transitions + /// to `fail_id()`. + fn iter(&self, mut f: F) { + match *self { + Transitions::Sparse(ref sparse) => { + for &(b, id) in sparse { + f(b, id); + } + } + Transitions::Dense(ref dense) => { + for b in AllBytesIter::new() { + let id = dense[b as usize]; + if id != fail_id() { + f(b, id); + } + } + } + } + } + + /// Iterate over all transitions in this state according to the given + /// equivalence classes, including transitions to `fail_id()`. + fn iter_all(&self, classes: &ByteClasses, mut f: F) { + if classes.is_singleton() { + match *self { + Transitions::Sparse(ref sparse) => { + sparse_iter(sparse, f); + } + Transitions::Dense(ref dense) => { + for b in AllBytesIter::new() { + f(b, dense[b as usize]); + } + } + } + } else { + // In this case, we only want to yield a single byte for each + // equivalence class. + match *self { + Transitions::Sparse(ref sparse) => { + let mut last_class = None; + sparse_iter(sparse, |b, next| { + let class = classes.get(b); + if last_class != Some(class) { + last_class = Some(class); + f(b, next); + } + }) + } + Transitions::Dense(ref dense) => { + for b in classes.representatives() { + f(b, dense[b as usize]); + } + } + } + } + } +} + +/// Iterator over transitions in a state, skipping transitions to `fail_id()`. +/// +/// This abstracts over the representation of NFA transitions, which may be +/// either in a sparse or dense representation. +/// +/// This somewhat idiosyncratically borrows the NFA mutably, so that when one +/// is iterating over transitions, the caller can still mutate the NFA. This +/// is useful when creating failure transitions. +#[derive(Debug)] +struct IterTransitionsMut<'a, S: StateID + 'a> { + nfa: &'a mut NFA, + state_id: S, + cur: usize, +} + +impl<'a, S: StateID> IterTransitionsMut<'a, S> { + fn new(nfa: &'a mut NFA, state_id: S) -> IterTransitionsMut<'a, S> { + IterTransitionsMut { nfa, state_id, cur: 0 } + } + + fn nfa(&mut self) -> &mut NFA { + self.nfa + } +} + +impl<'a, S: StateID> Iterator for IterTransitionsMut<'a, S> { + type Item = (u8, S); + + fn next(&mut self) -> Option<(u8, S)> { + match self.nfa.states[self.state_id.to_usize()].trans { + Transitions::Sparse(ref sparse) => { + if self.cur >= sparse.len() { + return None; + } + let i = self.cur; + self.cur += 1; + Some(sparse[i]) + } + Transitions::Dense(ref dense) => { + while self.cur < dense.len() { + // There are always exactly 255 transitions in dense repr. + debug_assert!(self.cur < 256); + + let b = self.cur as u8; + let id = dense[self.cur]; + self.cur += 1; + if id != fail_id() { + return Some((b, id)); + } + } + None + } + } + } +} + +/// A simple builder for configuring the NFA construction of Aho-Corasick. +#[derive(Clone, Debug)] +pub struct Builder { + dense_depth: usize, + match_kind: MatchKind, + prefilter: bool, + ascii_case_insensitive: bool, +} + +impl Default for Builder { + fn default() -> Builder { + Builder { + dense_depth: 2, + match_kind: MatchKind::default(), + prefilter: true, + ascii_case_insensitive: false, + } + } +} + +impl Builder { + pub fn new() -> Builder { + Builder::default() + } + + pub fn build( + &self, + patterns: I, + ) -> Result> + where I: IntoIterator, + P: AsRef<[u8]> + { + Compiler::new(self)?.compile(patterns) + } + + pub fn match_kind(&mut self, kind: MatchKind) -> &mut Builder { + self.match_kind = kind; + self + } + + pub fn dense_depth(&mut self, depth: usize) -> &mut Builder { + self.dense_depth = depth; + self + } + + pub fn prefilter(&mut self, yes: bool) -> &mut Builder { + self.prefilter = yes; + self + } + + pub fn ascii_case_insensitive(&mut self, yes: bool) -> &mut Builder { + self.ascii_case_insensitive = yes; + self + } +} + +/// A compiler uses a builder configuration and builds up the NFA formulation +/// of an Aho-Corasick automaton. This roughly corresponds to the standard +/// formulation described in textbooks. +#[derive(Debug)] +struct Compiler<'a, S: StateID> { + builder: &'a Builder, + nfa: NFA, + byte_classes: ByteClassBuilder, +} + +impl<'a, S: StateID> Compiler<'a, S> { + fn new(builder: &'a Builder) -> Result> { + Ok(Compiler { + builder: builder, + nfa: NFA { + match_kind: builder.match_kind, + start_id: usize_to_state_id(2)?, + max_pattern_len: 0, + pattern_count: 0, + heap_bytes: 0, + prefilter: None, + byte_classes: ByteClasses::singletons(), + states: vec![], + }, + byte_classes: ByteClassBuilder::new(), + }) + } + + fn compile( + mut self, + patterns: I, + ) -> Result> + where I: IntoIterator, + P: AsRef<[u8]> + { + self.add_state(0)?; // the fail state, which is never entered + self.add_state(0)?; // the dead state, only used for leftmost + self.add_state(0)?; // the start state + self.build_trie(patterns)?; + self.add_start_state_loop(); + self.add_dead_state_loop(); + if self.match_kind().is_leftmost() { + self.fill_failure_transitions_leftmost(); + } else { + self.fill_failure_transitions_standard(); + } + self.close_start_state_loop(); + self.nfa.byte_classes = self.byte_classes.build(); + self.build_prefilters(); + self.calculate_size(); + Ok(self.nfa) + } + + /// This sets up the initial prefix trie that makes up the Aho-Corasick + /// automaton. Effectively, it creates the basic structure of the + /// automaton, where every pattern given has a path from the start state to + /// the end of the pattern. + fn build_trie( + &mut self, + patterns: I, + ) -> Result<()> + where I: IntoIterator, + P: AsRef<[u8]> + { + 'PATTERNS: + for (pati, pat) in patterns.into_iter().enumerate() { + let pat = pat.as_ref(); + self.nfa.max_pattern_len = cmp::max( + self.nfa.max_pattern_len, pat.len(), + ); + self.nfa.pattern_count += 1; + + let mut prev = self.nfa.start_id; + let mut saw_match = false; + for (depth, &b) in pat.iter().enumerate() { + // When leftmost-first match semantics are requested, we + // specifically stop adding patterns when a previously added + // pattern is a prefix of it. We avoid adding it because + // leftmost-first semantics imply that the pattern can never + // match. This is not just an optimization to save space! It + // is necessary for correctness. In fact, this is the only + // difference in the automaton between the implementations for + // leftmost-first and leftmost-longest. + saw_match = saw_match || self.nfa.state(prev).is_match(); + if self.builder.match_kind.is_leftmost_first() && saw_match { + // Skip to the next pattern immediately. This avoids + // incorrectly adding a match after this loop terminates. + continue 'PATTERNS; + } + + // Add this byte to our equivalence classes. We don't use these + // for NFA construction. These are instead used only if we're + // building a DFA. They would technically be useful for the + // NFA, but it would require a second pass over the patterns. + self.byte_classes.set_range(b, b); + + // If the transition from prev using the current byte already + // exists, then just move through it. Otherwise, add a new + // state. We track the depth here so that we can determine + // how to represent transitions. States near the start state + // use a dense representation that uses more memory but is + // faster. Other states use a sparse representation that uses + // less memory but is slower. + let next = self.nfa.state(prev).next_state(b); + if next != fail_id() { + prev = next; + } else { + let next = self.add_state(depth + 1)?; + self.nfa.state_mut(prev).set_next_state(b, next); + if self.builder.ascii_case_insensitive { + if b'A' <= b && b <= b'Z' { + let b = b.to_ascii_lowercase(); + self.nfa.state_mut(prev).set_next_state(b, next); + } else if b'a' <= b && b <= b'z' { + let b = b.to_ascii_uppercase(); + self.nfa.state_mut(prev).set_next_state(b, next); + } + } + prev = next; + } + } + // Once the pattern has been added, log the match in the final + // state that it reached. + self.nfa.state_mut(prev).add_match(pati, pat.len()); + } + Ok(()) + } + + /// This routine creates failure transitions according to the standard + /// textbook formulation of the Aho-Corasick algorithm. + /// + /// Building failure transitions is the most interesting part of building + /// the Aho-Corasick automaton, because they are what allow searches to + /// be performed in linear time. Specifically, a failure transition is + /// a single transition associated with each state that points back to + /// the longest proper suffix of the pattern being searched. The failure + /// transition is followed whenever there exists no transition on the + /// current state for the current input byte. If there is no other proper + /// suffix, then the failure transition points back to the starting state. + /// + /// For example, let's say we built an Aho-Corasick automaton with the + /// following patterns: 'abcd' and 'cef'. The trie looks like this: + /// + /// ```ignore + /// a - S1 - b - S2 - c - S3 - d - S4* + /// / + /// S0 - c - S5 - e - S6 - f - S7* + /// ``` + /// + /// At this point, it should be fairly straight-forward to see how this + /// trie can be used in a simplistic way. At any given position in the + /// text we're searching (called the "subject" string), all we need to do + /// is follow the transitions in the trie by consuming one transition for + /// each byte in the subject string. If we reach a match state, then we can + /// report that location as a match. + /// + /// The trick comes when searching a subject string like 'abcef'. We'll + /// initially follow the transition from S0 to S1 and wind up in S3 after + /// observng the 'c' byte. At this point, the next byte is 'e' but state + /// S3 has no transition for 'e', so the search fails. We then would need + /// to restart the search at the next position in 'abcef', which + /// corresponds to 'b'. The match would fail, but the next search starting + /// at 'c' would finally succeed. The problem with this approach is that + /// we wind up searching the subject string potentially many times. In + /// effect, this makes the algorithm have worst case `O(n * m)` complexity, + /// where `n ~ len(subject)` and `m ~ len(all patterns)`. We would instead + /// like to achieve a `O(n + m)` worst case complexity. + /// + /// This is where failure transitions come in. Instead of dying at S3 in + /// the first search, the automaton can instruct the search to move to + /// another part of the automaton that corresponds to a suffix of what + /// we've seen so far. Recall that we've seen 'abc' in the subject string, + /// and the automaton does indeed have a non-empty suffix, 'c', that could + /// potentially lead to another match. Thus, the actual Aho-Corasick + /// automaton for our patterns in this case looks like this: + /// + /// ```ignore + /// a - S1 - b - S2 - c - S3 - d - S4* + /// / / + /// / ---------------- + /// / / + /// S0 - c - S5 - e - S6 - f - S7* + /// ``` + /// + /// That is, we have a failure transition from S3 to S5, which is followed + /// exactly in cases when we are in state S3 but see any byte other than + /// 'd' (that is, we've "failed" to find a match in this portion of our + /// trie). We know we can transition back to S5 because we've already seen + /// a 'c' byte, so we don't need to re-scan it. We can then pick back up + /// with the search starting at S5 and complete our match. + /// + /// Adding failure transitions to a trie is fairly simple, but subtle. The + /// key issue is that you might have multiple failure transition that you + /// need to follow. For example, look at the trie for the patterns + /// 'abcd', 'b', 'bcd' and 'cd': + /// + /// ```ignore + /// - a - S1 - b - S2 - c - S3 - d - S4* + /// / + /// S0 - b - S5* - c - S6 - d - S7* + /// \ + /// - c - S8 - d - S9* + /// ``` + /// + /// The failure transitions for this trie are defined from S2 to S5, + /// S3 to S6 and S6 to S8. Moreover, state S2 needs to track that it + /// corresponds to a match, since its failure transition to S5 is itself + /// a match state. + /// + /// Perhaps simplest way to think about adding these failure transitions + /// is recursively. That is, if you know the failure transitions for every + /// possible previous state that could be visited (e.g., when computing the + /// failure transition for S3, you already know the failure transitions + /// for S0, S1 and S2), then you can simply follow the failure transition + /// of the previous state and check whether the incoming transition is + /// defined after following the failure transition. + /// + /// For example, when determining the failure state for S3, by our + /// assumptions, we already know that there is a failure transition from + /// S2 (the previous state) to S5. So we follow that transition and check + /// whether the transition connecting S2 to S3 is defined. Indeed, it is, + /// as there is a transition from S5 to S6 for the byte 'c'. If no such + /// transition existed, we could keep following the failure transitions + /// until we reach the start state, which is the failure transition for + /// every state that has no corresponding proper suffix. + /// + /// We don't actually use recursion to implement this, but instead, use a + /// breadth first search of the automaton. Our base case is the start + /// state, whose failure transition is just a transition to itself. + fn fill_failure_transitions_standard(&mut self) { + // Initialize the queue for breadth first search with all transitions + // out of the start state. We handle the start state specially because + // we only want to follow non-self transitions. If we followed self + // transitions, then this would never terminate. + let mut queue = VecDeque::new(); + for b in AllBytesIter::new() { + let next = self.nfa.start().next_state(b); + if next != self.nfa.start_id { + queue.push_back(next); + } + } + while let Some(id) = queue.pop_front() { + let mut it = self.nfa.iter_transitions_mut(id); + while let Some((b, next)) = it.next() { + queue.push_back(next); + + let mut fail = it.nfa().state(id).fail; + while it.nfa().state(fail).next_state(b) == fail_id() { + fail = it.nfa().state(fail).fail; + } + fail = it.nfa().state(fail).next_state(b); + it.nfa().state_mut(next).fail = fail; + it.nfa().copy_matches(fail, next); + } + // If the start state is a match state, then this automaton can + // match the empty string. This implies all states are match states + // since every position matches the empty string, so copy the + // matches from the start state to every state. Strictly speaking, + // this is only necessary for overlapping matches since each + // non-empty non-start match state needs to report empty matches + // in addition to its own. For the non-overlapping case, such + // states only report the first match, which is never empty since + // it isn't a start state. + it.nfa().copy_empty_matches(id); + } + } + + /// This routine is just like fill_failure_transitions_standard, except + /// it adds failure transitions in a way that preserves leftmost match + /// semantics (for both leftmost-first and leftmost-longest). + /// + /// The algorithms are so similar that it would be possible to write it + /// generically. But doing so without overhead would require a bit of + /// ceremony, so we just copy it and add in the extra leftmost logic. + /// Moreover, the standard algorithm above is so simple that it feels like + /// a crime to disturb it. + /// + /// In effect, this proceeds just like the standard approach, but we + /// specifically add only a subset of all failure transitions. Namely, we + /// only add failure transitions that either do not occur after a match + /// or failure transitions that do occur after a match but preserve the + /// match. The comments in the implementation below should help. + /// + /// N.B. The only differences in the automaton between leftmost-first and + /// leftmost-longest are in trie construction. Otherwise, both have exactly + /// the same set of failure transitions. leftmost-longest adds everything + /// to the trie, where as leftmost-first skips any patterns for which there + /// exists a prefix of it that was added earlier. + /// + /// N.B. I came up with this algorithm on my own, and after scouring all of + /// the other AC implementations I know of (Perl, Snort, many on GitHub). + /// I couldn't find any that implement leftmost semantics like this. + /// Perl of course needs leftmost-first semantics, but they implement it + /// with a seeming hack at *search* time instead of encoding it into the + /// automaton. There are also a couple Java libraries that support leftmost + /// longest semantics, but they do it by building a queue of matches at + /// search time, which is even worse than what Perl is doing. ---AG + fn fill_failure_transitions_leftmost(&mut self) { + /// Represents an item in our queue of states to process. + /// + /// Fundamentally, this queue serves the same purpose as the queue + /// for filling failure transitions using the standard formulation. + /// In the leftmost case, though, we need to track a bit more + /// information. See comments below. + #[derive(Clone, Copy, Debug)] + struct QueuedState { + /// The id of the state to visit. + id: S, + /// The depth at which the first match was observed in the path + /// to this state. Note that this corresponds to the depth at + /// which the beginning of the match was detected. If no match + /// has been seen, then this is None. + match_at_depth: Option, + } + + impl QueuedState { + /// Create a queued state corresponding to the given NFA's start + /// state. + fn start(nfa: &NFA) -> QueuedState { + let match_at_depth = + if nfa.start().is_match() { + Some(0) + } else { + None + }; + QueuedState { id: nfa.start_id, match_at_depth } + } + + /// Return the next state to queue up. The given id must be a state + /// corresponding to a single transition from this queued state. + fn next_queued_state( + &self, + nfa: &NFA, + id: S, + ) -> QueuedState { + let match_at_depth = self.next_match_at_depth(nfa, id); + QueuedState { id, match_at_depth } + } + + /// Return the earliest depth at which a match has occurred for + /// the given state. The given state must correspond to a single + /// transition from this queued state. + fn next_match_at_depth( + &self, + nfa: &NFA, + next: S, + ) -> Option { + // This is a little tricky. If the previous state has already + // seen a match or if `next` isn't a match state, then nothing + // needs to change since a later state cannot find an earlier + // match. + match self.match_at_depth { + Some(x) => return Some(x), + None if nfa.state(next).is_match() => {} + None => return None, + } + let depth = + nfa.state(next).depth + - nfa.state(next).get_longest_match_len().unwrap() + + 1; + Some(depth) + } + } + + // Initialize the queue for breadth first search with all transitions + // out of the start state. We handle the start state specially because + // we only want to follow non-self transitions. If we followed self + // transitions, then this would never terminate. + let mut queue: VecDeque> = VecDeque::new(); + let start = QueuedState::start(&self.nfa); + for b in AllBytesIter::new() { + let next = self.nfa.start().next_state(b); + if next != start.id { + queue.push_back(start.next_queued_state(&self.nfa, next)); + } + } + while let Some(item) = queue.pop_front() { + let mut any_trans = false; + let mut it = self.nfa.iter_transitions_mut(item.id); + while let Some((b, next_id)) = it.next() { + any_trans = true; + + // Queue up the next state. + let next = item.next_queued_state(it.nfa(), next_id); + queue.push_back(next); + + // Find the failure state for next. Same as standard. + let mut fail = it.nfa().state(item.id).fail; + while it.nfa().state(fail).next_state(b) == fail_id() { + fail = it.nfa().state(fail).fail; + } + fail = it.nfa().state(fail).next_state(b); + + // This is the key difference from the standard formulation. + // Namely, if we've seen a match, then we only want a failure + // transition if the failure transition preserves the match + // we've seen. In general, this is not true of all failure + // transitions since they can point back to any suffix of what + // we've seen so far. Instead, we only want to point back to + // suffixes that contain any match we've seen. + // + // We achieve this by comparing the depth of the failure + // transition with the number of states between this state + // and the beginning of the earliest match detected. If the + // depth of the failure state is smaller than this difference, + // then it cannot contain the match. If it's bigger or equal + // to the difference, then it necessarily includes the match + // we've seen since all failure transitions correspond to a + // suffix. + // + // If we've determined that we don't want the failure + // transition, then we set this state's failure transition to + // the dead state. In other words, when a search hits this + // state, it will not continue and correctly stop. (N.B. A + // dead state is different than a fail state. A dead state + // MUST be preceded by a match and acts as a sentinel to search + // routines to terminate.) + // + // Understanding this is tricky, and it took me several days + // to think through this and get it right. If you want to grok + // it, then I'd recommend: 1) switch the implementation to + // always use the standard algorithm for filling in failure + // transitions, 2) run the test suite and 3) examine the test + // failures. Write out the automatons for them and try to work + // backwards by figuring out which failure transitions should + // be removed. You should arrive at the same rule used below. + if let Some(match_depth) = next.match_at_depth { + let fail_depth = it.nfa().state(fail).depth; + let next_depth = it.nfa().state(next.id).depth; + if next_depth - match_depth + 1 > fail_depth { + it.nfa().state_mut(next.id).fail = dead_id(); + continue; + } + } + it.nfa().state_mut(next.id).fail = fail; + it.nfa().copy_matches(fail, next.id); + } + // If there are no transitions for this state and if it's a match + // state, then we must set its failure transition to the dead + // state since we never want it to restart the search. + if !any_trans && it.nfa().state(item.id).is_match() { + it.nfa().state_mut(item.id).fail = dead_id(); + } + // We don't need to copy empty matches from the start state here + // because that's only necessary for overlapping matches and + // leftmost match kinds don't support overlapping matches. + } + } + + /// Construct prefilters from the automaton, if applicable. + fn build_prefilters(&mut self) { + if !self.builder.prefilter { + return; + } + + let mut builder = prefilter::StartBytesBuilder::new(); + for b in AllBytesIter::new() { + if self.nfa.start().next_state(b) != self.nfa.start_id { + builder.add(b); + } + } + self.nfa.prefilter = builder.build(); + } + + /// Set the failure transitions on the start state to loop back to the + /// start state. This effectively permits the Aho-Corasick automaton to + /// match at any position. This is also required for finding the next + /// state to terminate, namely, finding the next state should never return + /// a fail_id. + /// + /// This must be done after building the initial trie, since trie + /// construction depends on transitions to `fail_id` to determine whether a + /// state already exists or not. + fn add_start_state_loop(&mut self) { + let start_id = self.nfa.start_id; + let start = self.nfa.start_mut(); + for b in AllBytesIter::new() { + if start.next_state(b) == fail_id() { + start.set_next_state(b, start_id); + } + } + } + + /// Remove the start state loop by rewriting any transitions on the start + /// state back to the start state with transitions to the dead state. + /// + /// The loop is only closed when two conditions are met: the start state + /// is a match state and the match kind is leftmost-first or + /// leftmost-longest. + /// + /// The reason for this is that under leftmost semantics, a start state + /// that is also a match implies that we should never restart the search + /// process. We allow normal transitions out of the start state, but if + /// none exist, we transition to the dead state, which signals that + /// searching should stop. + fn close_start_state_loop(&mut self) { + if self.match_kind().is_leftmost() && self.nfa.start().is_match() { + let start_id = self.nfa.start_id; + let start = self.nfa.start_mut(); + for b in AllBytesIter::new() { + if start.next_state(b) == start_id { + start.set_next_state(b, dead_id()); + } + } + } + } + + /// Sets all transitions on the dead state to point back to the dead state. + /// Normally, missing transitions map back to the failure state, but the + /// point of the dead state is to act as a sink that can never be escaped. + fn add_dead_state_loop(&mut self) { + let dead = self.nfa.state_mut(dead_id()); + for b in AllBytesIter::new() { + dead.set_next_state(b, dead_id()); + } + } + + /// Computes the total amount of heap used by this NFA in bytes. + fn calculate_size(&mut self) { + let mut size = 0; + for state in &self.nfa.states { + size += state.heap_bytes(); + } + self.nfa.heap_bytes = size; + } + + /// Add a new state to the underlying NFA with the given depth. The depth + /// is used to determine how to represent the transitions. + /// + /// If adding the new state would overflow the chosen state ID + /// representation, then this returns an error. + fn add_state(&mut self, depth: usize) -> Result { + if depth < self.builder.dense_depth { + self.nfa.add_dense_state(depth) + } else { + self.nfa.add_sparse_state(depth) + } + } + + /// Returns the match kind configured on the underlying builder. + fn match_kind(&self) -> MatchKind { + self.builder.match_kind + } +} + +/// An iterator over every byte value. +/// +/// We use this instead of (0..256).map(|b| b as u8) because this optimizes +/// better in debug builds. +/// +/// We also use this instead of 0..=255 because we're targeting Rust 1.24 and +/// inclusive range syntax was stabilized in Rust 1.26. We can get rid of this +/// once our MSRV is Rust 1.26 or newer. +#[derive(Debug)] +struct AllBytesIter(u16); + +impl AllBytesIter { + fn new() -> AllBytesIter { + AllBytesIter(0) + } +} + +impl Iterator for AllBytesIter { + type Item = u8; + + fn next(&mut self) -> Option { + if self.0 >= 256 { + None + } else { + let b = self.0 as u8; + self.0 += 1; + Some(b) + } + } +} + +impl fmt::Debug for NFA { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "NFA(")?; + writeln!(f, "match_kind: {:?}", self.match_kind)?; + writeln!(f, "{}", "-".repeat(79))?; + for (id, s) in self.states.iter().enumerate() { + let mut trans = vec![]; + s.trans.iter(|byte, next| { + // The start state has a bunch of uninteresting transitions + // back into itself. It's questionable to hide them since they + // are critical to understanding the automaton, but they are + // very noisy without better formatting for contiugous ranges + // to the same state. + if id == self.start_id.to_usize() && next == self.start_id { + return; + } + // Similarly, the dead state has a bunch of uninteresting + // transitions too. + if id == dead_id() { + return; + } + trans.push(format!("{} => {}", escape(byte), next.to_usize())); + }); + writeln!(f, "{:04}: {}", id, trans.join(", "))?; + + let matches: Vec = s.matches + .iter() + .map(|&(pattern_id, _)| pattern_id.to_string()) + .collect(); + writeln!(f, " matches: {}", matches.join(", "))?; + writeln!(f, " fail: {}", s.fail.to_usize())?; + writeln!(f, " depth: {}", s.depth)?; + } + writeln!(f, "{}", "-".repeat(79))?; + writeln!(f, ")")?; + Ok(()) + } +} + +/// Iterate over all possible byte transitions given a sparse set. +fn sparse_iter(trans: &[(u8, S)], mut f: F) { + let mut byte = 0u16; + for &(b, id) in trans { + while byte < (b as u16) { + f(byte as u8, fail_id()); + byte += 1; + } + f(b, id); + byte += 1; + } + for b in byte..256 { + f(b as u8, fail_id()); + } +} + +/// Safely return two mutable borrows to two different locations in the given +/// slice. +/// +/// This panics if i == j. +fn get_two_mut(xs: &mut [T], i: usize, j: usize) -> (&mut T, &mut T) { + assert!(i != j, "{} must not be equal to {}", i, j); + if i < j { + let (before, after) = xs.split_at_mut(j); + (&mut before[i], &mut after[0]) + } else { + let (before, after) = xs.split_at_mut(i); + (&mut after[0], &mut before[j]) + } +} + +/// Return the given byte as its escaped string form. +fn escape(b: u8) -> String { + use std::ascii; + + String::from_utf8(ascii::escape_default(b).collect::>()).unwrap() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn scratch() { + let nfa: NFA = Builder::new() + .dense_depth(0) + // .match_kind(MatchKind::LeftmostShortest) + .match_kind(MatchKind::LeftmostLongest) + // .build(&["abcd", "ce", "b"]) + // .build(&["ab", "bc"]) + // .build(&["b", "bcd", "ce"]) + // .build(&["abc", "bx"]) + // .build(&["abc", "bd", "ab"]) + // .build(&["abcdefghi", "hz", "abcdefgh"]) + // .build(&["abcd", "bce", "b"]) + .build(&["a", "ababcde"]) + .unwrap(); + println!("{:?}", nfa); + } +} diff --git a/aho-corasick/src/prefilter.rs b/aho-corasick/src/prefilter.rs new file mode 100644 index 000000000..d3e830d75 --- /dev/null +++ b/aho-corasick/src/prefilter.rs @@ -0,0 +1,251 @@ +use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; + +use memchr::{memchr, memchr2, memchr3}; + +/// A prefilter describes the behavior of fast literal scanners for quickly +/// skipping past bytes in the haystack that we know cannot possibly +/// participate in a match. +pub trait Prefilter: Send + Sync + RefUnwindSafe + UnwindSafe + fmt::Debug { + /// Returns the next possible match candidate. This may yield false + /// positives, so callers must "confirm" a match starting at the position + /// returned. This, however, must never produce false negatives. That is, + /// this must, at minimum, return the starting position of the next match + /// in the given haystack after or at the given position. + fn next_candidate(&self, haystack: &[u8], at: usize) -> Option; + + /// A method for cloning a prefilter, to work-around the fact that Clone + /// is not object-safe. + fn clone_prefilter(&self) -> Box; +} + +/// A convenience object for representing any type that implements Prefilter +/// and is cloneable. +#[derive(Debug)] +pub struct PrefilterObj(Box); + +impl Clone for PrefilterObj { + fn clone(&self) -> Self { + PrefilterObj(self.0.clone_prefilter()) + } +} + +impl PrefilterObj { + /// Create a new prefilter object. + pub fn new(t: T) -> PrefilterObj { + PrefilterObj(Box::new(t)) + } + + /// Return the underlying prefilter trait object. + pub fn as_ref(&self) -> &Prefilter { + &*self.0 + } +} + +/// PrefilterState tracks state associated with the effectiveness of a +/// prefilter. It is used to track how many bytes, on average, are skipped by +/// the prefilter. If this average dips below a certain threshold over time, +/// then the state renders the prefilter inert and stops using it. +/// +/// A prefilter state should be created for each search. (Where creating an +/// iterator via, e.g., `find_iter`, is treated as a single search.) +#[derive(Clone, Debug)] +pub struct PrefilterState { + /// The number of skips that has been executed. + skips: usize, + /// The total number of bytes that have been skipped. + skipped: usize, + /// The maximum length of a match. This is used to help determine how many + /// bytes on average should be skipped in order for a prefilter to be + /// effective. + max_match_len: usize, + /// Once this heuristic has been deemed ineffective, it will be inert + /// throughout the rest of its lifetime. This serves as a cheap way to + /// check inertness. + inert: bool, +} + +impl PrefilterState { + /// The minimum number of skip attempts to try before considering whether + /// a prefilter is effective or not. + const MIN_SKIPS: usize = 40; + + /// The minimum amount of bytes that skipping must average, expressed as + /// a factor of the multiple of the length of a possible match. + /// + /// That is, after MIN_SKIPS have occurred, if the average number of bytes + /// skipped ever falls below MIN_AVG_FACTOR, then this searcher is rendered + /// inert. + const MIN_AVG_FACTOR: usize = 2; + + /// Create a fresh prefilter state. + pub fn new(max_match_len: usize) -> PrefilterState { + PrefilterState { skips: 0, skipped: 0, max_match_len, inert: false } + } + + /// Update this state with the number of bytes skipped on the last + /// invocation of the prefilter. + #[inline] + pub fn update(&mut self, skipped: usize) { + self.skips += 1; + self.skipped += skipped; + } + + /// Return true if and only if this state indicates that a prefilter is + /// still effective. + #[inline] + pub fn is_effective(&mut self) -> bool { + if self.inert { + return false; + } + if self.skips < PrefilterState::MIN_SKIPS { + return true; + } + + let min_avg = PrefilterState::MIN_AVG_FACTOR * self.max_match_len; + if self.skipped >= min_avg * self.skips { + return true; + } + + // We're inert. + self.inert = true; + false + } +} + +/// A builder for construction a starting byte prefilter. +/// +/// A starting byte prefilter is a simplistic prefilter that looks for possible +/// matches by reporting all positions corresponding to a particular byte. This +/// generally only takes affect when there are at most 3 distinct possible +/// starting bytes. e.g., the patterns `foo`, `bar`, and `baz` have two +/// distinct starting bytes (`f` and `b`), and this prefiler returns all +/// occurrences of either `f` or `b`. +/// +/// In some cases, a heuristic frequency analysis may determine that it would +/// be better not to use this prefilter even when there are 3 or fewer distinct +/// starting bytes. +#[derive(Clone, Debug)] +pub struct StartBytesBuilder { + byteset: Vec, +} + +impl StartBytesBuilder { + /// Create a new builder for constructing a start byte prefilter. + pub fn new() -> StartBytesBuilder { + StartBytesBuilder { byteset: vec![false; 256] } + } + + /// Build the starting bytes prefilter. + /// + /// If there are more than 3 distinct starting bytes, or if heuristics + /// otherwise determine that this prefilter should not be used, then `None` + /// is returned. + pub fn build(&self) -> Option { + let (mut bytes, mut len) = ([0; 3], 0); + for b in 0..256 { + if !self.byteset[b] { + continue; + } + // We've exceeded our limit, so bail. + if len == 3 { + return None; + } + // We don't handle non-ASCII bytes for now. Getting non-ASCII + // bytes right is trickier, since we generally don't want to put + // a leading UTF-8 code unit into a prefilter that isn't ASCII, + // since they can frequently. Instead, it would be better to use a + // continuation byte, but this requires more sophisticated analysis + // of the automaton and a richer prefilter API. + if b > 0x7F { + return None; + } + bytes[len] = b as u8; + len += 1; + } + match len { + 0 => None, + 1 => { + Some(PrefilterObj::new(StartBytesOne { + byte1: bytes[0], + })) + } + 2 => { + Some(PrefilterObj::new(StartBytesTwo { + byte1: bytes[0], + byte2: bytes[1], + })) + } + 3 => { + Some(PrefilterObj::new(StartBytesThree { + byte1: bytes[0], + byte2: bytes[1], + byte3: bytes[2], + })) + } + _ => unreachable!(), + } + } + + /// Add a starting byte to this builder. + /// + /// In general, all possible starting bytes for an automaton should be + /// added to this builder before attempting to construct the prefilter. + pub fn add(&mut self, byte: u8) { + self.byteset[byte as usize] = true; + } +} + +/// A prefilter for scanning for a single starting byte. +#[derive(Clone, Debug)] +pub struct StartBytesOne { + byte1: u8, +} + +impl Prefilter for StartBytesOne { + fn next_candidate(&self, haystack: &[u8], at: usize) -> Option { + memchr(self.byte1, &haystack[at..]) + .map(|i| at + i) + } + + fn clone_prefilter(&self) -> Box { + Box::new(self.clone()) + } +} + +/// A prefilter for scanning for two starting bytes. +#[derive(Clone, Debug)] +pub struct StartBytesTwo { + byte1: u8, + byte2: u8, +} + +impl Prefilter for StartBytesTwo { + fn next_candidate(&self, haystack: &[u8], at: usize) -> Option { + memchr2(self.byte1, self.byte2, &haystack[at..]) + .map(|i| at + i) + } + + fn clone_prefilter(&self) -> Box { + Box::new(self.clone()) + } +} + +/// A prefilter for scanning for three starting bytes. +#[derive(Clone, Debug)] +pub struct StartBytesThree { + byte1: u8, + byte2: u8, + byte3: u8, +} + +impl Prefilter for StartBytesThree { + fn next_candidate(&self, haystack: &[u8], at: usize) -> Option { + memchr3(self.byte1, self.byte2, self.byte3, &haystack[at..]) + .map(|i| at + i) + } + + fn clone_prefilter(&self) -> Box { + Box::new(self.clone()) + } +} diff --git a/aho-corasick/src/state_id.rs b/aho-corasick/src/state_id.rs new file mode 100644 index 000000000..c7011f17e --- /dev/null +++ b/aho-corasick/src/state_id.rs @@ -0,0 +1,166 @@ +use std::fmt::Debug; +use std::hash::Hash; + +use error::{Error, Result}; + +// NOTE: Most of this code was copied from regex-automata, but without the +// (de)serialization specific stuff. + +/// Check that the premultiplication of the given state identifier can +/// fit into the representation indicated by `S`. If it cannot, or if it +/// overflows `usize` itself, then an error is returned. +pub fn premultiply_overflow_error( + last_state: S, + alphabet_len: usize, +) -> Result<()> { + let requested = match last_state.to_usize().checked_mul(alphabet_len) { + Some(requested) => requested, + None => return Err(Error::premultiply_overflow(0, 0)), + }; + if requested > S::max_id() { + return Err(Error::premultiply_overflow(S::max_id(), requested)); + } + Ok(()) +} + +/// Convert the given `usize` to the chosen state identifier +/// representation. If the given value cannot fit in the chosen +/// representation, then an error is returned. +pub fn usize_to_state_id(value: usize) -> Result { + if value > S::max_id() { + Err(Error::state_id_overflow(S::max_id())) + } else { + Ok(S::from_usize(value)) + } +} + +/// Return the unique identifier for an automaton's fail state in the chosen +/// representation indicated by `S`. +pub fn fail_id() -> S { + S::from_usize(0) +} + +/// Return the unique identifier for an automaton's fail state in the chosen +/// representation indicated by `S`. +pub fn dead_id() -> S { + S::from_usize(1) +} + +mod private { + /// Sealed stops crates other than aho-corasick from implementing any + /// traits that use it. + pub trait Sealed{} + impl Sealed for u8 {} + impl Sealed for u16 {} + impl Sealed for u32 {} + impl Sealed for u64 {} + impl Sealed for usize {} +} + +/// A trait describing the representation of an automaton's state identifier. +/// +/// The purpose of this trait is to safely express both the possible state +/// identifier representations that can be used in an automaton and to convert +/// between state identifier representations and types that can be used to +/// efficiently index memory (such as `usize`). +/// +/// In general, one should not need to implement this trait explicitly. Indeed, +/// for now, this trait is sealed such that it cannot be implemented by any +/// other type. In particular, this crate provides implementations for `u8`, +/// `u16`, `u32`, `u64` and `usize`. (`u32` and `u64` are only provided for +/// targets that can represent all corresponding values in a `usize`.) +/// +/// # Safety +/// +/// This trait is unsafe because the correctness of its implementations may be +/// relied upon by other unsafe code. For example, one possible way to +/// implement this trait incorrectly would be to return a maximum identifier +/// in `max_id` that is greater than the real maximum identifier. This will +/// likely result in wrap-on-overflow semantics in release mode, which can in +/// turn produce incorrect state identifiers. Those state identifiers may then +/// in turn access out-of-bounds memory in an automaton's search routine, where +/// bounds checks are explicitly elided for performance reasons. +pub unsafe trait StateID: + private::Sealed + + Clone + Copy + Debug + Eq + Hash + PartialEq + PartialOrd + Ord +{ + /// Convert from a `usize` to this implementation's representation. + /// + /// Implementors may assume that `n <= Self::max_id`. That is, implementors + /// do not need to check whether `n` can fit inside this implementation's + /// representation. + fn from_usize(n: usize) -> Self; + + /// Convert this implementation's representation to a `usize`. + /// + /// Implementors must not return a `usize` value greater than + /// `Self::max_id` and must not permit overflow when converting between the + /// implementor's representation and `usize`. In general, the preferred + /// way for implementors to achieve this is to simply not provide + /// implementations of `StateID` that cannot fit into the target platform's + /// `usize`. + fn to_usize(self) -> usize; + + /// Return the maximum state identifier supported by this representation. + /// + /// Implementors must return a correct bound. Doing otherwise may result + /// in memory unsafety. + fn max_id() -> usize; +} + +unsafe impl StateID for usize { + #[inline] + fn from_usize(n: usize) -> usize { n } + + #[inline] + fn to_usize(self) -> usize { self } + + #[inline] + fn max_id() -> usize { ::std::usize::MAX } +} + +unsafe impl StateID for u8 { + #[inline] + fn from_usize(n: usize) -> u8 { n as u8 } + + #[inline] + fn to_usize(self) -> usize { self as usize } + + #[inline] + fn max_id() -> usize { ::std::u8::MAX as usize } +} + +unsafe impl StateID for u16 { + #[inline] + fn from_usize(n: usize) -> u16 { n as u16 } + + #[inline] + fn to_usize(self) -> usize { self as usize } + + #[inline] + fn max_id() -> usize { ::std::u16::MAX as usize } +} + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +unsafe impl StateID for u32 { + #[inline] + fn from_usize(n: usize) -> u32 { n as u32 } + + #[inline] + fn to_usize(self) -> usize { self as usize } + + #[inline] + fn max_id() -> usize { ::std::u32::MAX as usize } +} + +#[cfg(target_pointer_width = "64")] +unsafe impl StateID for u64 { + #[inline] + fn from_usize(n: usize) -> u64 { n as u64 } + + #[inline] + fn to_usize(self) -> usize { self as usize } + + #[inline] + fn max_id() -> usize { ::std::u64::MAX as usize } +} diff --git a/aho-corasick/src/tests.rs b/aho-corasick/src/tests.rs new file mode 100644 index 000000000..e3233a6a2 --- /dev/null +++ b/aho-corasick/src/tests.rs @@ -0,0 +1,694 @@ +use std::collections::HashMap; +use std::io; +use std::usize; + +use {AhoCorasickBuilder, Match, MatchKind}; + +/// A description of a single test against an Aho-Corasick automaton. +/// +/// A single test may not necessarily pass on every configuration of an +/// Aho-Corasick automaton. The tests are categorized and grouped appropriately +/// below. +#[derive(Clone, Debug, Eq, PartialEq)] +struct SearchTest { + /// The name of this test, for debugging. + name: &'static str, + /// The patterns to search for. + patterns: &'static [&'static str], + /// The text to search. + haystack: &'static str, + /// Each match is a triple of (pattern_index, start, end), where + /// pattern_index is an index into `patterns` and `start`/`end` are indices + /// into `haystack`. + matches: &'static [(usize, usize, usize)], +} + +/// Short-hand constructor for SearchTest. We use it a lot below. +macro_rules! t { + ($name:ident, $patterns:expr, $haystack:expr, $matches:expr) => { + SearchTest { + name: stringify!($name), + patterns: $patterns, + haystack: $haystack, + matches: $matches, + } + } +} + +/// A collection of test groups. +type TestCollection = &'static [&'static [SearchTest]]; + +// Define several collections corresponding to the different type of match +// semantics supported by Aho-Corasick. These collections have some overlap, +// but each collection should have some tests that no other collection has. + +/// Tests for Aho-Corasick's standard non-overlapping match semantics. +const AC_STANDARD_NON_OVERLAPPING: TestCollection = &[ + BASICS, NON_OVERLAPPING, STANDARD, REGRESSION, +]; + +/// Tests for Aho-Corasick's standard overlapping match semantics. +const AC_STANDARD_OVERLAPPING: TestCollection = &[ + BASICS, OVERLAPPING, REGRESSION, +]; + +/// Tests for Aho-Corasick's leftmost-first match semantics. +const AC_LEFTMOST_FIRST: TestCollection = &[ + BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_FIRST, REGRESSION, +]; + +/// Tests for Aho-Corasick's leftmost-longest match semantics. +const AC_LEFTMOST_LONGEST: TestCollection = &[ + BASICS, NON_OVERLAPPING, LEFTMOST, LEFTMOST_LONGEST, REGRESSION, +]; + +// Now define the individual tests that make up the collections above. + +/// A collection of tests for the Aho-Corasick algorithm that should always be +/// true regardless of match semantics. That is, all combinations of +/// leftmost-{shortest, first, longest} x {overlapping, non-overlapping} +/// should produce the same answer. +const BASICS: &'static [SearchTest] = &[ + t!(basic000, &["a"], "", &[]), + t!(basic010, &["a"], "a", &[(0, 0, 1)]), + t!(basic020, &["a"], "aa", &[(0, 0, 1), (0, 1, 2)]), + t!(basic030, &["a"], "aaa", &[(0, 0, 1), (0, 1, 2), (0, 2, 3)]), + t!(basic040, &["a"], "aba", &[(0, 0, 1), (0, 2, 3)]), + t!(basic050, &["a"], "bba", &[(0, 2, 3)]), + t!(basic060, &["a"], "bbb", &[]), + t!(basic070, &["a"], "bababbbba", &[(0, 1, 2), (0, 3, 4), (0, 8, 9)]), + + t!(basic100, &["aa"], "", &[]), + t!(basic110, &["aa"], "aa", &[(0, 0, 2)]), + t!(basic120, &["aa"], "aabbaa", &[(0, 0, 2), (0, 4, 6)]), + t!(basic130, &["aa"], "abbab", &[]), + t!(basic140, &["aa"], "abbabaa", &[(0, 5, 7)]), + + t!(basic200, &["abc"], "abc", &[(0, 0, 3)]), + t!(basic210, &["abc"], "zazabzabcz", &[(0, 6, 9)]), + t!(basic220, &["abc"], "zazabczabcz", &[(0, 3, 6), (0, 7, 10)]), + + t!(basic300, &["a", "b"], "", &[]), + t!(basic310, &["a", "b"], "z", &[]), + t!(basic320, &["a", "b"], "b", &[(1, 0, 1)]), + t!(basic330, &["a", "b"], "a", &[(0, 0, 1)]), + t!(basic340, &["a", "b"], "abba", &[ + (0, 0, 1), (1, 1, 2), (1, 2, 3), (0, 3, 4), + ]), + t!(basic350, &["b", "a"], "abba", &[ + (1, 0, 1), (0, 1, 2), (0, 2, 3), (1, 3, 4), + ]), + t!(nover360, &["abc", "bc"], "xbc", &[ + (1, 1, 3), + ]), + + t!(basic400, &["foo", "bar"], "", &[]), + t!(basic410, &["foo", "bar"], "foobar", &[ + (0, 0, 3), (1, 3, 6), + ]), + t!(basic420, &["foo", "bar"], "barfoo", &[ + (1, 0, 3), (0, 3, 6), + ]), + t!(basic430, &["foo", "bar"], "foofoo", &[ + (0, 0, 3), (0, 3, 6), + ]), + t!(basic440, &["foo", "bar"], "barbar", &[ + (1, 0, 3), (1, 3, 6), + ]), + t!(basic450, &["foo", "bar"], "bafofoo", &[ + (0, 4, 7), + ]), + t!(basic460, &["bar", "foo"], "bafofoo", &[ + (1, 4, 7), + ]), + t!(basic470, &["foo", "bar"], "fobabar", &[ + (1, 4, 7), + ]), + t!(basic480, &["bar", "foo"], "fobabar", &[ + (0, 4, 7), + ]), + + t!(basic600, &[""], "", &[(0, 0, 0)]), + t!(basic610, &[""], "a", &[(0, 0, 0), (0, 1, 1)]), + t!(basic620, &[""], "abc", &[(0, 0, 0), (0, 1, 1), (0, 2, 2), (0, 3, 3)]), + + t!(basic700, &["yabcdef", "abcdezghi"], "yabcdefghi", &[ + (0, 0, 7), + ]), + t!(basic710, &["yabcdef", "abcdezghi"], "yabcdezghi", &[ + (1, 1, 10), + ]), + t!(basic720, &["yabcdef", "bcdeyabc", "abcdezghi"], "yabcdezghi", &[ + (2, 1, 10), + ]), +]; + +/// Tests for non-overlapping standard match semantics. +/// +/// These tests generally shouldn't pass for leftmost-{first,longest}, although +/// some do in order to write clearer tests. For example, standard000 will +/// pass with leftmost-first semantics, but standard010 will not. We write +/// both to emphasize how the match semantics work. +const STANDARD: &'static [SearchTest] = &[ + t!(standard000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(standard010, &["abcd", "ab"], "abcd", &[(1, 0, 2)]), + t!(standard020, &["abcd", "ab", "abc"], "abcd", &[(1, 0, 2)]), + t!(standard030, &["abcd", "abc", "ab"], "abcd", &[(2, 0, 2)]), + t!(standard040, &["a", ""], "a", &[(1, 0, 0), (1, 1, 1)]), + + t!(standard400, &["abcd", "bcd", "cd", "b"], "abcd", &[ + (3, 1, 2), (2, 2, 4), + ]), + t!(standard410, &["", "a"], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), + t!(standard420, &["", "a"], "aa", &[ + (0, 0, 0), (0, 1, 1), (0, 2, 2), + ]), + t!(standard430, &["", "a", ""], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), + t!(standard440, &["a", "", ""], "a", &[ + (1, 0, 0), (1, 1, 1), + ]), + t!(standard450, &["", "", "a"], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), +]; + +/// Tests for non-overlapping leftmost match semantics. These should pass for +/// both leftmost-first and leftmost-longest match kinds. Stated differently, +/// among ambiguous matches, the longest match and the match that appeared +/// first when constructing the automaton should always be the same. +const LEFTMOST: &'static [SearchTest] = &[ + t!(leftmost000, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + t!(leftmost010, &["a", ""], "a", &[(0, 0, 1), (1, 1, 1)]), + t!(leftmost020, &["", ""], "a", &[(0, 0, 0), (0, 1, 1)]), + + t!(leftmost300, &["abcd", "bce", "b"], "abce", &[(1, 1, 4)]), + t!(leftmost310, &["abcd", "ce", "bc"], "abce", &[(2, 1, 3)]), + t!(leftmost320, &["abcd", "bce", "ce", "b"], "abce", &[(1, 1, 4)]), + t!(leftmost330, &["abcd", "bce", "cz", "bc"], "abcz", &[(3, 1, 3)]), + t!(leftmost340, &["bce", "cz", "bc"], "bcz", &[(2, 0, 2)]), + t!(leftmost350, &["abc", "bd", "ab"], "abd", &[(2, 0, 2)]), + t!(leftmost360, &["abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (2, 0, 8), + ]), + t!(leftmost370, &["abcdefghi", "cde", "hz", "abcdefgh"], "abcdefghz", &[ + (3, 0, 8), + ]), + t!(leftmost380, &["abcdefghi", "hz", "abcdefgh", "a"], "abcdefghz", &[ + (2, 0, 8), + ]), + t!(leftmost390, &["b", "abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (3, 0, 8), + ]), + t!(leftmost400, &["h", "abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (3, 0, 8), + ]), + t!(leftmost410, &["z", "abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (3, 0, 8), (0, 8, 9), + ]), +]; + +/// Tests for non-overlapping leftmost-first match semantics. These tests +/// should generally be specific to leftmost-first, which means they should +/// generally fail under leftmost-longest semantics. +const LEFTMOST_FIRST: &'static [SearchTest] = &[ + t!(leftfirst000, &["ab", "abcd"], "abcd", &[(0, 0, 2)]), + t!(leftfirst010, &["", "a"], "a", &[(0, 0, 0), (0, 1, 1)]), + t!(leftfirst011, &["", "a", ""], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), + t!(leftfirst012, &["a", "", ""], "a", &[ + (0, 0, 1), (1, 1, 1), + ]), + t!(leftfirst013, &["", "", "a"], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), + t!(leftfirst020, &["abcd", "ab"], "abcd", &[(0, 0, 4)]), + t!(leftfirst030, &["ab", "ab"], "abcd", &[(0, 0, 2)]), + + t!(leftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(1, 1, 5)]), + t!(leftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), + + t!(leftfirst300, &["abcd", "b", "bce"], "abce", &[(1, 1, 2)]), + t!(leftfirst310, &["abcd", "b", "bce", "ce"], "abce", &[ + (1, 1, 2), (3, 2, 4), + ]), + t!(leftfirst320, &["a", "abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (0, 0, 1), (2, 7, 9), + ]), + t!(leftfirst330, &["a", "abab"], "abab", &[(0, 0, 1), (0, 2, 3)]), +]; + +/// Tests for non-overlapping leftmost-longest match semantics. These tests +/// should generally be specific to leftmost-longest, which means they should +/// generally fail under leftmost-first semantics. +const LEFTMOST_LONGEST: &'static [SearchTest] = &[ + t!(leftlong000, &["ab", "abcd"], "abcd", &[(1, 0, 4)]), + t!(leftlong010, &["abcd", "bcd", "cd", "b"], "abcd", &[ + (0, 0, 4), + ]), + t!(leftlong020, &["", "a"], "a", &[ + (1, 0, 1), (0, 1, 1), + ]), + t!(leftlong021, &["", "a", ""], "a", &[ + (1, 0, 1), (0, 1, 1), + ]), + t!(leftlong022, &["a", "", ""], "a", &[ + (0, 0, 1), (1, 1, 1), + ]), + t!(leftlong023, &["", "", "a"], "a", &[ + (2, 0, 1), (0, 1, 1), + ]), + t!(leftlong030, &["", "a"], "aa", &[ + (1, 0, 1), (1, 1, 2), (0, 2, 2), + ]), + t!(leftlong040, &["a", "ab"], "a", &[(0, 0, 1)]), + t!(leftlong050, &["a", "ab"], "ab", &[(1, 0, 2)]), + t!(leftlong060, &["ab", "a"], "a", &[(1, 0, 1)]), + t!(leftlong070, &["ab", "a"], "ab", &[(0, 0, 2)]), + + t!(leftlong100, &["abcdefg", "bcde", "bcdef"], "abcdef", &[(2, 1, 6)]), + t!(leftlong110, &["abcdefg", "bcdef", "bcde"], "abcdef", &[(1, 1, 6)]), + + t!(leftlong300, &["abcd", "b", "bce"], "abce", &[(2, 1, 4)]), + t!(leftlong310, &["a", "abcdefghi", "hz", "abcdefgh"], "abcdefghz", &[ + (3, 0, 8), + ]), + t!(leftlong320, &["a", "abab"], "abab", &[(1, 0, 4)]), + t!(leftlong330, &["abcd", "b", "ce"], "abce", &[ + (1, 1, 2), (2, 2, 4), + ]), +]; + +/// Tests for non-overlapping match semantics. +/// +/// Generally these tests shouldn't pass when using overlapping semantics. +/// These should pass for both standard and leftmost match semantics. +const NON_OVERLAPPING: &'static [SearchTest] = &[ + t!(nover010, &["abcd", "bcd", "cd"], "abcd", &[ + (0, 0, 4), + ]), + t!(nover020, &["bcd", "cd", "abcd"], "abcd", &[ + (2, 0, 4), + ]), + t!(nover030, &["abc", "bc"], "zazabcz", &[ + (0, 3, 6), + ]), + + t!(nover100, &["ab", "ba"], "abababa", &[ + (0, 0, 2), (0, 2, 4), (0, 4, 6), + ]), + + t!(nover200, &["foo", "foo"], "foobarfoo", &[ + (0, 0, 3), (0, 6, 9), + ]), + + t!(nover300, &["", ""], "", &[ + (0, 0, 0), + ]), + t!(nover310, &["", ""], "a", &[ + (0, 0, 0), (0, 1, 1), + ]), +]; + +/// Tests for overlapping match semantics. +/// +/// This only supports standard match semantics, since leftmost-{first,longest} +/// do not support overlapping matches. +const OVERLAPPING: &'static [SearchTest] = &[ + t!(over000, &["abcd", "bcd", "cd", "b"], "abcd", &[ + (3, 1, 2), (0, 0, 4), (1, 1, 4), (2, 2, 4), + ]), + t!(over010, &["bcd", "cd", "b", "abcd"], "abcd", &[ + (2, 1, 2), (3, 0, 4), (0, 1, 4), (1, 2, 4), + ]), + t!(over020, &["abcd", "bcd", "cd"], "abcd", &[ + (0, 0, 4), (1, 1, 4), (2, 2, 4), + ]), + t!(over030, &["bcd", "abcd", "cd"], "abcd", &[ + (1, 0, 4), (0, 1, 4), (2, 2, 4), + ]), + t!(over040, &["bcd", "cd", "abcd"], "abcd", &[ + (2, 0, 4), (0, 1, 4), (1, 2, 4), + ]), + t!(over050, &["abc", "bc"], "zazabcz", &[ + (0, 3, 6), (1, 4, 6), + ]), + + t!(over100, &["ab", "ba"], "abababa", &[ + (0, 0, 2), (1, 1, 3), (0, 2, 4), (1, 3, 5), (0, 4, 6), (1, 5, 7), + ]), + + t!(over200, &["foo", "foo"], "foobarfoo", &[ + (0, 0, 3), (1, 0, 3), (0, 6, 9), (1, 6, 9), + ]), + + t!(over300, &["", ""], "", &[ + (0, 0, 0), (1, 0, 0), + ]), + t!(over310, &["", ""], "a", &[ + (0, 0, 0), (1, 0, 0), (0, 1, 1), (1, 1, 1), + ]), + t!(over320, &["", "a"], "a", &[ + (0, 0, 0), (1, 0, 1), (0, 1, 1), + ]), + t!(over330, &["", "a", ""], "a", &[ + (0, 0, 0), (2, 0, 0), (1, 0, 1), (0, 1, 1), (2, 1, 1), + ]), + t!(over340, &["a", "", ""], "a", &[ + (1, 0, 0), (2, 0, 0), (0, 0, 1), (1, 1, 1), (2, 1, 1), + ]), + t!(over350, &["", "", "a"], "a", &[ + (0, 0, 0), (1, 0, 0), (2, 0, 1), (0, 1, 1), (1, 1, 1), + ]), +]; + +/// Regression tests that are applied to all Aho-Corasick combinations. +/// +/// If regression tests are needed for specific match semantics, then add them +/// to the appropriate group above. +const REGRESSION: &'static [SearchTest] = &[ + t!(regression010, &["inf", "ind"], "infind", &[ + (0, 0, 3), (1, 3, 6), + ]), + t!(regression020, &["ind", "inf"], "infind", &[ + (1, 0, 3), (0, 3, 6), + ]), + t!(regression030, &["libcore/", "libstd/"], "libcore/char/methods.rs", &[ + (0, 0, 8), + ]), + t!(regression040, &["libstd/", "libcore/"], "libcore/char/methods.rs", &[ + (1, 0, 8), + ]), + t!(regression050, &["\x00\x00\x01", "\x00\x00\x00"], "\x00\x00\x00", &[ + (1, 0, 3), + ]), + t!(regression060, &["\x00\x00\x00", "\x00\x00\x01"], "\x00\x00\x00", &[ + (0, 0, 3), + ]), +]; + +// Now define a test for each combination of things above that we want to run. +// Since there are a few different combinations for each collection of tests, +// we define a couple of macros to avoid repetition drudgery. The testconfig +// macro constructs the automaton from a given match kind, and runs the search +// tests one-by-one over the given collection. The `with` parameter allows one +// to configure the builder with additional parameters. The testcombo macro +// invokes testconfig in precisely this way: it sets up several tests where +// each one turns a different knob on AhoCorasickBuilder. + +macro_rules! testconfig { + (overlapping, $name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .find_overlapping_iter(test.haystack) + .collect() + }); + } + }; + (stream, $name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let buf = io::BufReader::with_capacity( + 1, + test.haystack.as_bytes(), + ); + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .stream_find_iter(buf) + .map(|result| result.unwrap()) + .collect() + }); + } + }; + ($name:ident, $collection:expr, $kind:ident, $with:expr) => { + #[test] + fn $name() { + run_search_tests($collection, |test| { + let mut builder = AhoCorasickBuilder::new(); + $with(&mut builder); + builder + .match_kind(MatchKind::$kind) + .build(test.patterns) + .find_iter(test.haystack) + .collect() + }); + } + }; +} + +macro_rules! testcombo { + ($name:ident, $collection:expr, $kind:ident) => { + mod $name { + use super::*; + + testconfig!(nfa_default, $collection, $kind, |_| ()); + testconfig!(nfa_no_prefilter, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.prefilter(false); + }); + testconfig!(nfa_all_sparse, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(0); + }); + testconfig!(nfa_all_dense, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dense_depth(usize::MAX); + }); + testconfig!(dfa_default, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true); + }); + testconfig!(dfa_no_prefilter, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).prefilter(false); + }); + testconfig!(dfa_all_sparse, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(0); + }); + testconfig!(dfa_all_dense, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).dense_depth(usize::MAX); + }); + testconfig!(dfa_no_byte_class, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false); + }); + testconfig!(dfa_no_premultiply, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).premultiply(false); + }); + testconfig!(dfa_no_byte_class_no_premultiply, $collection, $kind, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false).premultiply(false); + }); + } + }; +} + +// Write out the combinations. +testcombo!(search_leftmost_longest, AC_LEFTMOST_LONGEST, LeftmostLongest); +testcombo!(search_leftmost_first, AC_LEFTMOST_FIRST, LeftmostFirst); +testcombo!( + search_standard_nonoverlapping, AC_STANDARD_NON_OVERLAPPING, Standard +); + +// Write out the overlapping combo by hand since there is only one of them. +testconfig!( + overlapping, + search_standard_overlapping_nfa_default, + AC_STANDARD_OVERLAPPING, + Standard, + |_| () +); +testconfig!( + overlapping, + search_standard_overlapping_nfa_all_sparse, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dense_depth(0); } +); +testconfig!( + overlapping, + search_standard_overlapping_nfa_all_dense, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dense_depth(usize::MAX); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_default, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_all_sparse, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true).dense_depth(0); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_all_dense, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true).dense_depth(usize::MAX); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_byte_class, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true).byte_classes(false); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_premultiply, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true).premultiply(false); } +); +testconfig!( + overlapping, + search_standard_overlapping_dfa_no_byte_class_no_premultiply, + AC_STANDARD_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { + b.dfa(true).byte_classes(false).premultiply(false); + } +); + +// Also write out tests manually for streams, since we only test the standard +// match semantics. We also don't bother testing different automaton +// configurations, since those are well covered by tests above. +testconfig!( + stream, + search_standard_stream_nfa_default, + AC_STANDARD_NON_OVERLAPPING, + Standard, + |_| () +); +testconfig!( + stream, + search_standard_stream_dfa_default, + AC_STANDARD_NON_OVERLAPPING, + Standard, + |b: &mut AhoCorasickBuilder| { b.dfa(true); } +); + +#[test] +fn search_tests_have_unique_names() { + let assert = |constname, tests: &[SearchTest]| { + let mut seen = HashMap::new(); // map from test name to position + for (i, test) in tests.iter().enumerate() { + if !seen.contains_key(test.name) { + seen.insert(test.name, i); + } else { + let last = seen[test.name]; + panic!( + "{} tests have duplicate names at positions {} and {}", + constname, last, i + ); + } + } + }; + assert("BASICS", BASICS); + assert("STANDARD", STANDARD); + assert("LEFTMOST", LEFTMOST); + assert("LEFTMOST_FIRST", LEFTMOST_FIRST); + assert("LEFTMOST_LONGEST", LEFTMOST_LONGEST); + assert("NON_OVERLAPPING", NON_OVERLAPPING); + assert("OVERLAPPING", OVERLAPPING); + assert("REGRESSION", REGRESSION); +} + +#[test] +#[should_panic] +fn stream_not_allowed_leftmost_first() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(None::); + assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); +} + +#[test] +#[should_panic] +fn stream_not_allowed_leftmost_longest() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostLongest) + .build(None::); + assert_eq!(fsm.stream_find_iter(&b""[..]).count(), 0); +} + +#[test] +#[should_panic] +fn overlapping_not_allowed_leftmost_first() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .build(None::); + assert_eq!(fsm.find_overlapping_iter("").count(), 0); +} + +#[test] +#[should_panic] +fn overlapping_not_allowed_leftmost_longest() { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostLongest) + .build(None::); + assert_eq!(fsm.find_overlapping_iter("").count(), 0); +} + +#[test] +fn state_id_too_small() { + let mut patterns = vec![]; + for c1 in (b'a'..b'z').map(|b| b as char) { + for c2 in (b'a'..b'z').map(|b| b as char) { + for c3 in (b'a'..b'z').map(|b| b as char) { + patterns.push(format!("{}{}{}", c1, c2, c3)); + } + } + } + let result = AhoCorasickBuilder::new() + .build_with_size::(&patterns); + assert!(result.is_err()); +} + +fn run_search_tests Vec>( + which: TestCollection, + mut f: F, +) { + let get_match_triples = + |matches: Vec| -> Vec<(usize, usize, usize)> { + matches.into_iter() + .map(|m| (m.pattern(), m.start(), m.end())) + .collect() + }; + for &tests in which { + for test in tests { + assert_eq!( + test.matches, + get_match_triples(f(&test)).as_slice(), + "test: {}, patterns: {:?}, haystack: {:?}", + test.name, + test.patterns, + test.haystack + ); + } + } +} diff --git a/ansi_term/.cargo-checksum.json b/ansi_term/.cargo-checksum.json new file mode 100644 index 000000000..012a9823a --- /dev/null +++ b/ansi_term/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"} \ No newline at end of file diff --git a/ansi_term/Cargo.toml b/ansi_term/Cargo.toml new file mode 100644 index 000000000..56a7f2d36 --- /dev/null +++ b/ansi_term/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "ansi_term" +version = "0.11.0" +authors = ["ogham@bsago.me", "Ryan Scheel (Havvy) ", "Josh Triplett "] +description = "Library for ANSI terminal colours and styles (bold, underline)" +homepage = "https://github.com/ogham/rust-ansi-term" +documentation = "https://docs.rs/ansi_term" +readme = "README.md" +license = "MIT" + +[lib] +name = "ansi_term" +[target."cfg(target_os=\"windows\")".dependencies.winapi] +version = "0.3.4" +features = ["errhandlingapi", "consoleapi", "processenv"] diff --git a/ansi_term/LICENCE b/ansi_term/LICENCE new file mode 100644 index 000000000..3f39e72bd --- /dev/null +++ b/ansi_term/LICENCE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Benjamin Sago + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ansi_term/README.md b/ansi_term/README.md new file mode 100644 index 000000000..1cb56a19a --- /dev/null +++ b/ansi_term/README.md @@ -0,0 +1,174 @@ +# rust-ansi-term [![ansi-term on crates.io](http://meritbadge.herokuapp.com/ansi-term)](https://crates.io/crates/ansi_term) [![Build status](https://travis-ci.org/ogham/rust-ansi-term.svg?branch=master)](https://travis-ci.org/ogham/rust-ansi-term) [![Coverage status](https://coveralls.io/repos/ogham/rust-ansi-term/badge.svg?branch=master&service=github)](https://coveralls.io/github/ogham/rust-ansi-term?branch=master) + +This is a library for controlling colours and formatting, such as red bold text or blue underlined text, on ANSI terminals. + +### [View the Rustdoc](https://docs.rs/ansi_term/0.9.0/ansi_term/) + + +# Installation + +This crate works with [Cargo](http://crates.io). Add the following to your `Cargo.toml` dependencies section: + +```toml +[dependencies] +ansi_term = "0.9" +``` + + +## Basic usage + +There are two main data structures in this crate that you need to be concerned with: `ANSIString` and `Style`. +A `Style` holds stylistic information: colours, whether the text should be bold, or blinking, or whatever. +There are also `Colour` variants that represent simple foreground colour styles. +An `ANSIString` is a string paired with a `Style`. + +(Yes, it’s British English, but you won’t have to write “colour” very often. `Style` is used the majority of the time.) + +To format a string, call the `paint` method on a `Style` or a `Colour`, passing in the string you want to format as the argument. +For example, here’s how to get some red text: + +```rust +use ansi_term::Colour::Red; +println!("This is in red: {}", Red.paint("a red string")); +``` + +It’s important to note that the `paint` method does *not* actually return a string with the ANSI control characters surrounding it. +Instead, it returns an `ANSIString` value that has a `Display` implementation that, when formatted, returns the characters. +This allows strings to be printed with a minimum of `String` allocations being performed behind the scenes. + +If you *do* want to get at the escape codes, then you can convert the `ANSIString` to a string as you would any other `Display` value: + +```rust +use ansi_term::Colour::Red; +use std::string::ToString; +let red_string = Red.paint("a red string").to_string(); +``` + +**Note for Windows 10 users:** On Windows 10, the application must enable ANSI support first: + +```rust +let enabled = ansi_term::enable_ansi_support(); +``` + +## Bold, underline, background, and other styles + +For anything more complex than plain foreground colour changes, you need to construct `Style` objects themselves, rather than beginning with a `Colour`. +You can do this by chaining methods based on a new `Style`, created with `Style::new()`. +Each method creates a new style that has that specific property set. +For example: + +```rust +use ansi_term::Style; +println!("How about some {} and {}?", + Style::new().bold().paint("bold"), + Style::new().underline().paint("underline")); +``` + +For brevity, these methods have also been implemented for `Colour` values, so you can give your styles a foreground colour without having to begin with an empty `Style` value: + +```rust +use ansi_term::Colour::{Blue, Yellow}; +println!("Demonstrating {} and {}!", + Blue.bold().paint("blue bold"), + Yellow.underline().paint("yellow underline")); +println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); +``` + +The complete list of styles you can use are: +`bold`, `dimmed`, `italic`, `underline`, `blink`, `reverse`, `hidden`, and `on` for background colours. + +In some cases, you may find it easier to change the foreground on an existing `Style` rather than starting from the appropriate `Colour`. +You can do this using the `fg` method: + +```rust + use ansi_term::Style; + use ansi_term::Colour::{Blue, Cyan, Yellow}; + println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); + println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); +``` + +Finally, you can turn a `Colour` into a `Style` with the `normal` method. +This will produce the exact same `ANSIString` as if you just used the `paint` method on the `Colour` directly, but it’s useful in certain cases: for example, you may have a method that returns `Styles`, and need to represent both the “red bold” and “red, but not bold” styles with values of the same type. The `Style` struct also has a `Default` implementation if you want to have a style with *nothing* set. + +```rust +use ansi_term::Style; +use ansi_term::Colour::Red; +Red.normal().paint("yet another red string"); +Style::default().paint("a completely regular string"); +``` + + +## Extended colours + +You can access the extended range of 256 colours by using the `Fixed` colour variant, which takes an argument of the colour number to use. +This can be included wherever you would use a `Colour`: + +```rust +use ansi_term::Colour::Fixed; +Fixed(134).paint("A sort of light purple"); +Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); +``` + +The first sixteen of these values are the same as the normal and bold standard colour variants. +There’s nothing stopping you from using these as `Fixed` colours instead, but there’s nothing to be gained by doing so either. + +You can also access full 24-bit color by using the `RGB` colour variant, which takes separate `u8` arguments for red, green, and blue: + +```rust + use ansi_term::Colour::RGB; + RGB(70, 130, 180).paint("Steel blue"); +``` + +## Combining successive coloured strings + +The benefit of writing ANSI escape codes to the terminal is that they *stack*: you do not need to end every coloured string with a reset code if the text that follows it is of a similar style. +For example, if you want to have some blue text followed by some blue bold text, it’s possible to send the ANSI code for blue, followed by the ANSI code for bold, and finishing with a reset code without having to have an extra one between the two strings. + +This crate can optimise the ANSI codes that get printed in situations like this, making life easier for your terminal renderer. +The `ANSIStrings` struct takes a slice of several `ANSIString` values, and will iterate over each of them, printing only the codes for the styles that need to be updated as part of its formatting routine. + +The following code snippet uses this to enclose a binary number displayed in red bold text inside some red, but not bold, brackets: + +```rust +use ansi_term::Colour::Red; +use ansi_term::{ANSIString, ANSIStrings}; +let some_value = format!("{:b}", 42); +let strings: &[ANSIString<'static>] = &[ + Red.paint("["), + Red.bold().paint(some_value), + Red.paint("]"), +]; +println!("Value: {}", ANSIStrings(strings)); +``` + +There are several things to note here. +Firstly, the `paint` method can take *either* an owned `String` or a borrowed `&str`. +Internally, an `ANSIString` holds a copy-on-write (`Cow`) string value to deal with both owned and borrowed strings at the same time. +This is used here to display a `String`, the result of the `format!` call, using the same mechanism as some statically-available `&str` slices. +Secondly, that the `ANSIStrings` value works in the same way as its singular counterpart, with a `Display` implementation that only performs the formatting when required. + +## Byte strings + +This library also supports formatting `[u8]` byte strings; this supports +applications working with text in an unknown encoding. `Style` and +`Color` support painting `[u8]` values, resulting in an `ANSIByteString`. +This type does not implement `Display`, as it may not contain UTF-8, but +it does provide a method `write_to` to write the result to any +`io::Write`: + +```rust +use ansi_term::Colour::Green; +Green.paint("user data".as_bytes()).write_to(&mut std::io::stdout()).unwrap(); +``` + +Similarly, the type `ANSIByteStrings` supports writing a list of +`ANSIByteString` values with minimal escape sequences: + +```rust +use ansi_term::Colour::Green; +use ansi_term::ANSIByteStrings; +ANSIByteStrings(&[ + Green.paint("user data 1\n".as_bytes()), + Green.bold().paint("user data 2\n".as_bytes()), +]).write_to(&mut std::io::stdout()).unwrap(); +``` diff --git a/ansi_term/examples/colours.rs b/ansi_term/examples/colours.rs new file mode 100644 index 000000000..187031063 --- /dev/null +++ b/ansi_term/examples/colours.rs @@ -0,0 +1,13 @@ +extern crate ansi_term; +use ansi_term::Colour::*; + +fn main() { + println!("{}", Black.paint("Black")); + println!("{}", Red.paint("Red")); + println!("{}", Green.paint("Green")); + println!("{}", Yellow.paint("Yellow")); + println!("{}", Blue.paint("Blue")); + println!("{}", Purple.paint("Purple")); + println!("{}", Cyan.paint("Cyan")); + println!("{}", White.paint("White")); +} diff --git a/ansi_term/src/ansi.rs b/ansi_term/src/ansi.rs new file mode 100644 index 000000000..009043ff7 --- /dev/null +++ b/ansi_term/src/ansi.rs @@ -0,0 +1,258 @@ +use style::{Colour, Style}; + +use std::fmt; + +use write::AnyWrite; + + +// ---- generating ANSI codes ---- + +impl Style { + + /// Write any ANSI codes that go *before* a piece of text. These should be + /// the codes to set the terminal to a different colour or font style. + fn write_prefix(&self, f: &mut W) -> Result<(), W::Error> { + + // If there are actually no styles here, then don’t write *any* codes + // as the prefix. An empty ANSI code may not affect the terminal + // output at all, but a user may just want a code-free string. + if self.is_plain() { + return Ok(()); + } + + // Write the codes’ prefix, then write numbers, separated by + // semicolons, for each text style we want to apply. + write!(f, "\x1B[")?; + let mut written_anything = false; + + { + let mut write_char = |c| { + if written_anything { write!(f, ";")?; } + written_anything = true; + write!(f, "{}", c)?; + Ok(()) + }; + + if self.is_bold { write_char('1')? } + if self.is_dimmed { write_char('2')? } + if self.is_italic { write_char('3')? } + if self.is_underline { write_char('4')? } + if self.is_blink { write_char('5')? } + if self.is_reverse { write_char('7')? } + if self.is_hidden { write_char('8')? } + if self.is_strikethrough { write_char('9')? } + } + + // The foreground and background colours, if specified, need to be + // handled specially because the number codes are more complicated. + // (see `write_background_code` and `write_foreground_code`) + if let Some(bg) = self.background { + if written_anything { write!(f, ";")?; } + written_anything = true; + bg.write_background_code(f)?; + } + + if let Some(fg) = self.foreground { + if written_anything { write!(f, ";")?; } + fg.write_foreground_code(f)?; + } + + // All the codes end with an `m`, because reasons. + write!(f, "m")?; + + Ok(()) + } + + /// Write any ANSI codes that go *after* a piece of text. These should be + /// the codes to *reset* the terminal back to its normal colour and style. + fn write_suffix(&self, f: &mut W) -> Result<(), W::Error> { + if self.is_plain() { + Ok(()) + } + else { + write!(f, "{}", RESET) + } + } +} + + +/// The code to send to reset all styles and return to `Style::default()`. +pub static RESET: &str = "\x1B[0m"; + + + +impl Colour { + fn write_foreground_code(&self, f: &mut W) -> Result<(), W::Error> { + match *self { + Colour::Black => write!(f, "30"), + Colour::Red => write!(f, "31"), + Colour::Green => write!(f, "32"), + Colour::Yellow => write!(f, "33"), + Colour::Blue => write!(f, "34"), + Colour::Purple => write!(f, "35"), + Colour::Cyan => write!(f, "36"), + Colour::White => write!(f, "37"), + Colour::Fixed(num) => write!(f, "38;5;{}", &num), + Colour::RGB(r,g,b) => write!(f, "38;2;{};{};{}", &r, &g, &b), + } + } + + fn write_background_code(&self, f: &mut W) -> Result<(), W::Error> { + match *self { + Colour::Black => write!(f, "40"), + Colour::Red => write!(f, "41"), + Colour::Green => write!(f, "42"), + Colour::Yellow => write!(f, "43"), + Colour::Blue => write!(f, "44"), + Colour::Purple => write!(f, "45"), + Colour::Cyan => write!(f, "46"), + Colour::White => write!(f, "47"), + Colour::Fixed(num) => write!(f, "48;5;{}", &num), + Colour::RGB(r,g,b) => write!(f, "48;2;{};{};{}", &r, &g, &b), + } + } +} + + +/// Like `ANSIString`, but only displays the style prefix. +#[derive(Clone, Copy, Debug)] +pub struct Prefix(Style); + +/// Like `ANSIString`, but only displays the difference between two +/// styles. +#[derive(Clone, Copy, Debug)] +pub struct Infix(Style, Style); + +/// Like `ANSIString`, but only displays the style suffix. +#[derive(Clone, Copy, Debug)] +pub struct Suffix(Style); + + +impl Style { + + /// The prefix for this style. + pub fn prefix(self) -> Prefix { + Prefix(self) + } + + /// The infix between this style and another. + pub fn infix(self, other: Style) -> Infix { + Infix(self, other) + } + + /// The suffix for this style. + pub fn suffix(self) -> Suffix { + Suffix(self) + } +} + + +impl Colour { + + /// The prefix for this colour. + pub fn prefix(self) -> Prefix { + Prefix(self.normal()) + } + + /// The infix between this colour and another. + pub fn infix(self, other: Colour) -> Infix { + Infix(self.normal(), other.normal()) + } + + /// The suffix for this colour. + pub fn suffix(self) -> Suffix { + Suffix(self.normal()) + } +} + + +impl fmt::Display for Prefix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut fmt::Write = f; + self.0.write_prefix(f) + } +} + + +impl fmt::Display for Infix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use difference::Difference; + + match Difference::between(&self.0, &self.1) { + Difference::ExtraStyles(style) => { + let f: &mut fmt::Write = f; + style.write_prefix(f) + }, + Difference::Reset => { + let f: &mut fmt::Write = f; + write!(f, "{}{}", RESET, self.0.prefix()) + }, + Difference::NoDifference => { + Ok(()) // nothing to write + }, + } + } +} + + +impl fmt::Display for Suffix { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut fmt::Write = f; + self.0.write_suffix(f) + } +} + + + +#[cfg(test)] +mod test { + use style::Style; + use style::Colour::*; + + macro_rules! test { + ($name: ident: $style: expr; $input: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($style.paint($input).to_string(), $result.to_string()); + + let mut v = Vec::new(); + $style.paint($input.as_bytes()).write_to(&mut v).unwrap(); + assert_eq!(v.as_slice(), $result.as_bytes()); + } + }; + } + + test!(plain: Style::default(); "text/plain" => "text/plain"); + test!(red: Red; "hi" => "\x1B[31mhi\x1B[0m"); + test!(black: Black.normal(); "hi" => "\x1B[30mhi\x1B[0m"); + test!(yellow_bold: Yellow.bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(yellow_bold_2: Yellow.normal().bold(); "hi" => "\x1B[1;33mhi\x1B[0m"); + test!(blue_underline: Blue.underline(); "hi" => "\x1B[4;34mhi\x1B[0m"); + test!(green_bold_ul: Green.bold().underline(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(green_bold_ul_2: Green.underline().bold(); "hi" => "\x1B[1;4;32mhi\x1B[0m"); + test!(purple_on_white: Purple.on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(purple_on_white_2: Purple.normal().on(White); "hi" => "\x1B[47;35mhi\x1B[0m"); + test!(yellow_on_blue: Style::new().on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(yellow_on_blue_2: Cyan.on(Blue).fg(Yellow); "hi" => "\x1B[44;33mhi\x1B[0m"); + test!(cyan_bold_on_white: Cyan.bold().on(White); "hi" => "\x1B[1;47;36mhi\x1B[0m"); + test!(cyan_ul_on_white: Cyan.underline().on(White); "hi" => "\x1B[4;47;36mhi\x1B[0m"); + test!(cyan_bold_ul_on_white: Cyan.bold().underline().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(cyan_ul_bold_on_white: Cyan.underline().bold().on(White); "hi" => "\x1B[1;4;47;36mhi\x1B[0m"); + test!(fixed: Fixed(100); "hi" => "\x1B[38;5;100mhi\x1B[0m"); + test!(fixed_on_purple: Fixed(100).on(Purple); "hi" => "\x1B[45;38;5;100mhi\x1B[0m"); + test!(fixed_on_fixed: Fixed(100).on(Fixed(200)); "hi" => "\x1B[48;5;200;38;5;100mhi\x1B[0m"); + test!(rgb: RGB(70,130,180); "hi" => "\x1B[38;2;70;130;180mhi\x1B[0m"); + test!(rgb_on_blue: RGB(70,130,180).on(Blue); "hi" => "\x1B[44;38;2;70;130;180mhi\x1B[0m"); + test!(blue_on_rgb: Blue.on(RGB(70,130,180)); "hi" => "\x1B[48;2;70;130;180;34mhi\x1B[0m"); + test!(rgb_on_rgb: RGB(70,130,180).on(RGB(5,10,15)); "hi" => "\x1B[48;2;5;10;15;38;2;70;130;180mhi\x1B[0m"); + test!(bold: Style::new().bold(); "hi" => "\x1B[1mhi\x1B[0m"); + test!(underline: Style::new().underline(); "hi" => "\x1B[4mhi\x1B[0m"); + test!(bunderline: Style::new().bold().underline(); "hi" => "\x1B[1;4mhi\x1B[0m"); + test!(dimmed: Style::new().dimmed(); "hi" => "\x1B[2mhi\x1B[0m"); + test!(italic: Style::new().italic(); "hi" => "\x1B[3mhi\x1B[0m"); + test!(blink: Style::new().blink(); "hi" => "\x1B[5mhi\x1B[0m"); + test!(reverse: Style::new().reverse(); "hi" => "\x1B[7mhi\x1B[0m"); + test!(hidden: Style::new().hidden(); "hi" => "\x1B[8mhi\x1B[0m"); + test!(stricken: Style::new().strikethrough(); "hi" => "\x1B[9mhi\x1B[0m"); + +} diff --git a/ansi_term/src/debug.rs b/ansi_term/src/debug.rs new file mode 100644 index 000000000..da30c625c --- /dev/null +++ b/ansi_term/src/debug.rs @@ -0,0 +1,122 @@ +use std::fmt; + +use style::Style; + + +/// Styles have a special `Debug` implementation that only shows the fields that +/// are set. Fields that haven’t been touched aren’t included in the output. +/// +/// This behaviour gets bypassed when using the alternate formatting mode +/// `format!("{:#?}")`. +/// +/// use ansi_term::Colour::{Red, Blue}; +/// assert_eq!("Style { fg(Red), on(Blue), bold, italic }", +/// format!("{:?}", Red.on(Blue).bold().italic())); +impl fmt::Debug for Style { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if fmt.alternate() { + fmt.debug_struct("Style") + .field("foreground", &self.foreground) + .field("background", &self.background) + .field("blink", &self.is_blink) + .field("bold", &self.is_bold) + .field("dimmed", &self.is_dimmed) + .field("hidden", &self.is_hidden) + .field("italic", &self.is_italic) + .field("reverse", &self.is_reverse) + .field("strikethrough", &self.is_strikethrough) + .field("underline", &self.is_underline) + .finish() + } + else if self.is_plain() { + fmt.write_str("Style {}") + } + else { + fmt.write_str("Style { ")?; + + let mut written_anything = false; + + if let Some(fg) = self.foreground { + if written_anything { fmt.write_str(", ")? } + written_anything = true; + write!(fmt, "fg({:?})", fg)? + } + + if let Some(bg) = self.background { + if written_anything { fmt.write_str(", ")? } + written_anything = true; + write!(fmt, "on({:?})", bg)? + } + + { + let mut write_flag = |name| { + if written_anything { fmt.write_str(", ")? } + written_anything = true; + fmt.write_str(name) + }; + + if self.is_blink { write_flag("blink")? } + if self.is_bold { write_flag("bold")? } + if self.is_dimmed { write_flag("dimmed")? } + if self.is_hidden { write_flag("hidden")? } + if self.is_italic { write_flag("italic")? } + if self.is_reverse { write_flag("reverse")? } + if self.is_strikethrough { write_flag("strikethrough")? } + if self.is_underline { write_flag("underline")? } + } + + write!(fmt, " }}") + } + } +} + + +#[cfg(test)] +mod test { + use style::Colour::*; + use style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $obj: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, format!("{:?}", $obj)); + } + }; + } + + test!(empty: style() => "Style {}"); + test!(bold: style().bold() => "Style { bold }"); + test!(italic: style().italic() => "Style { italic }"); + test!(both: style().bold().italic() => "Style { bold, italic }"); + + test!(red: Red.normal() => "Style { fg(Red) }"); + test!(redblue: Red.normal().on(RGB(3, 2, 4)) => "Style { fg(Red), on(RGB(3, 2, 4)) }"); + + test!(everything: + Red.on(Blue).blink().bold().dimmed().hidden().italic().reverse().strikethrough().underline() => + "Style { fg(Red), on(Blue), blink, bold, dimmed, hidden, italic, reverse, strikethrough, underline }"); + + #[test] + fn long_and_detailed() { + let debug = r##"Style { + foreground: Some( + Blue + ), + background: None, + blink: false, + bold: true, + dimmed: false, + hidden: false, + italic: false, + reverse: false, + strikethrough: false, + underline: false +}"##; + assert_eq!(debug, format!("{:#?}", Blue.bold())); + } +} diff --git a/ansi_term/src/difference.rs b/ansi_term/src/difference.rs new file mode 100644 index 000000000..571574634 --- /dev/null +++ b/ansi_term/src/difference.rs @@ -0,0 +1,179 @@ +use super::Style; + + +/// When printing out one coloured string followed by another, use one of +/// these rules to figure out which *extra* control codes need to be sent. +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum Difference { + + /// Print out the control codes specified by this style to end up looking + /// like the second string's styles. + ExtraStyles(Style), + + /// Converting between these two is impossible, so just send a reset + /// command and then the second string's styles. + Reset, + + /// The before style is exactly the same as the after style, so no further + /// control codes need to be printed. + NoDifference, +} + + +impl Difference { + + /// Compute the 'style difference' required to turn an existing style into + /// the given, second style. + /// + /// For example, to turn green text into green bold text, it's redundant + /// to write a reset command then a second green+bold command, instead of + /// just writing one bold command. This method should see that both styles + /// use the foreground colour green, and reduce it to a single command. + /// + /// This method returns an enum value because it's not actually always + /// possible to turn one style into another: for example, text could be + /// made bold and underlined, but you can't remove the bold property + /// without also removing the underline property. So when this has to + /// happen, this function returns None, meaning that the entire set of + /// styles should be reset and begun again. + pub fn between(first: &Style, next: &Style) -> Difference { + use self::Difference::*; + + // XXX(Havvy): This algorithm is kind of hard to replicate without + // having the Plain/Foreground enum variants, so I'm just leaving + // it commented out for now, and defaulting to Reset. + + if first == next { + return NoDifference; + } + + // Cannot un-bold, so must Reset. + if first.is_bold && !next.is_bold { + return Reset; + } + + if first.is_dimmed && !next.is_dimmed { + return Reset; + } + + if first.is_italic && !next.is_italic { + return Reset; + } + + // Cannot un-underline, so must Reset. + if first.is_underline && !next.is_underline { + return Reset; + } + + if first.is_blink && !next.is_blink { + return Reset; + } + + if first.is_reverse && !next.is_reverse { + return Reset; + } + + if first.is_hidden && !next.is_hidden { + return Reset; + } + + if first.is_strikethrough && !next.is_strikethrough { + return Reset; + } + + // Cannot go from foreground to no foreground, so must Reset. + if first.foreground.is_some() && next.foreground.is_none() { + return Reset; + } + + // Cannot go from background to no background, so must Reset. + if first.background.is_some() && next.background.is_none() { + return Reset; + } + + let mut extra_styles = Style::default(); + + if first.is_bold != next.is_bold { + extra_styles.is_bold = true; + } + + if first.is_dimmed != next.is_dimmed { + extra_styles.is_dimmed = true; + } + + if first.is_italic != next.is_italic { + extra_styles.is_italic = true; + } + + if first.is_underline != next.is_underline { + extra_styles.is_underline = true; + } + + if first.is_blink != next.is_blink { + extra_styles.is_blink = true; + } + + if first.is_reverse != next.is_reverse { + extra_styles.is_reverse = true; + } + + if first.is_hidden != next.is_hidden { + extra_styles.is_hidden = true; + } + + if first.is_strikethrough != next.is_strikethrough { + extra_styles.is_strikethrough = true; + } + + if first.foreground != next.foreground { + extra_styles.foreground = next.foreground; + } + + if first.background != next.background { + extra_styles.background = next.background; + } + + ExtraStyles(extra_styles) + } +} + + +#[cfg(test)] +mod test { + use super::*; + use super::Difference::*; + use style::Colour::*; + use style::Style; + + fn style() -> Style { + Style::new() + } + + macro_rules! test { + ($name: ident: $first: expr; $next: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result, Difference::between(&$first, &$next)); + } + }; + } + + test!(nothing: Green.normal(); Green.normal() => NoDifference); + test!(uppercase: Green.normal(); Green.bold() => ExtraStyles(style().bold())); + test!(lowercase: Green.bold(); Green.normal() => Reset); + test!(nothing2: Green.bold(); Green.bold() => NoDifference); + + test!(colour_change: Red.normal(); Blue.normal() => ExtraStyles(Blue.normal())); + + test!(addition_of_blink: style(); style().blink() => ExtraStyles(style().blink())); + test!(addition_of_dimmed: style(); style().dimmed() => ExtraStyles(style().dimmed())); + test!(addition_of_hidden: style(); style().hidden() => ExtraStyles(style().hidden())); + test!(addition_of_reverse: style(); style().reverse() => ExtraStyles(style().reverse())); + test!(addition_of_strikethrough: style(); style().strikethrough() => ExtraStyles(style().strikethrough())); + + test!(removal_of_strikethrough: style().strikethrough(); style() => Reset); + test!(removal_of_reverse: style().reverse(); style() => Reset); + test!(removal_of_hidden: style().hidden(); style() => Reset); + test!(removal_of_dimmed: style().dimmed(); style() => Reset); + test!(removal_of_blink: style().blink(); style() => Reset); +} diff --git a/ansi_term/src/display.rs b/ansi_term/src/display.rs new file mode 100644 index 000000000..8314ab85f --- /dev/null +++ b/ansi_term/src/display.rs @@ -0,0 +1,279 @@ +use std::borrow::Cow; +use std::fmt; +use std::io; +use std::ops::Deref; + +use ansi::RESET; +use difference::Difference; +use style::{Style, Colour}; +use write::AnyWrite; + + +/// An `ANSIGenericString` includes a generic string type and a `Style` to +/// display that string. `ANSIString` and `ANSIByteString` are aliases for +/// this type on `str` and `[u8]`, respectively. +#[derive(PartialEq, Debug)] +pub struct ANSIGenericString<'a, S: 'a + ToOwned + ?Sized> +where ::Owned: fmt::Debug { + style: Style, + string: Cow<'a, S>, +} + + +/// Cloning an `ANSIGenericString` will clone its underlying string. +/// +/// ### Examples +/// +/// ``` +/// use ansi_term::ANSIString; +/// +/// let plain_string = ANSIString::from("a plain string"); +/// let clone_string = plain_string.clone(); +/// assert_eq!(clone_string, plain_string); +/// ``` +impl<'a, S: 'a + ToOwned + ?Sized> Clone for ANSIGenericString<'a, S> +where ::Owned: fmt::Debug { + fn clone(&self) -> ANSIGenericString<'a, S> { + ANSIGenericString { + style: self.style, + string: self.string.clone(), + } + } +} + +// You might think that the hand-written Clone impl above is the same as the +// one that gets generated with #[derive]. But it’s not *quite* the same! +// +// `str` is not Clone, and the derived Clone implementation puts a Clone +// constraint on the S type parameter (generated using --pretty=expanded): +// +// ↓_________________↓ +// impl <'a, S: ::std::clone::Clone + 'a + ToOwned + ?Sized> ::std::clone::Clone +// for ANSIGenericString<'a, S> where +// ::Owned: fmt::Debug { ... } +// +// This resulted in compile errors when you tried to derive Clone on a type +// that used it: +// +// #[derive(PartialEq, Debug, Clone, Default)] +// pub struct TextCellContents(Vec>); +// ^^^^^^^^^^^^^^^^^^^^^^^^^ +// error[E0277]: the trait `std::clone::Clone` is not implemented for `str` +// +// The hand-written impl above can ignore that constraint and still compile. + + + +/// An ANSI String is a string coupled with the `Style` to display it +/// in a terminal. +/// +/// Although not technically a string itself, it can be turned into +/// one with the `to_string` method. +/// +/// ### Examples +/// +/// ```no_run +/// use ansi_term::ANSIString; +/// use ansi_term::Colour::Red; +/// +/// let red_string = Red.paint("a red string"); +/// println!("{}", red_string); +/// ``` +/// +/// ``` +/// use ansi_term::ANSIString; +/// +/// let plain_string = ANSIString::from("a plain string"); +/// assert_eq!(&*plain_string, "a plain string"); +/// ``` +pub type ANSIString<'a> = ANSIGenericString<'a, str>; + +/// An `ANSIByteString` represents a formatted series of bytes. Use +/// `ANSIByteString` when styling text with an unknown encoding. +pub type ANSIByteString<'a> = ANSIGenericString<'a, [u8]>; + +impl<'a, I, S: 'a + ToOwned + ?Sized> From for ANSIGenericString<'a, S> +where I: Into>, + ::Owned: fmt::Debug { + fn from(input: I) -> ANSIGenericString<'a, S> { + ANSIGenericString { + string: input.into(), + style: Style::default(), + } + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> Deref for ANSIGenericString<'a, S> +where ::Owned: fmt::Debug { + type Target = S; + + fn deref(&self) -> &S { + self.string.deref() + } +} + + +/// A set of `ANSIGenericString`s collected together, in order to be +/// written with a minimum of control characters. +pub struct ANSIGenericStrings<'a, S: 'a + ToOwned + ?Sized> + (pub &'a [ANSIGenericString<'a, S>]) + where ::Owned: fmt::Debug; + +/// A set of `ANSIString`s collected together, in order to be written with a +/// minimum of control characters. +pub type ANSIStrings<'a> = ANSIGenericStrings<'a, str>; + +/// A function to construct an `ANSIStrings` instance. +#[allow(non_snake_case)] +pub fn ANSIStrings<'a>(arg: &'a [ANSIString<'a>]) -> ANSIStrings<'a> { + ANSIGenericStrings(arg) +} + +/// A set of `ANSIByteString`s collected together, in order to be +/// written with a minimum of control characters. +pub type ANSIByteStrings<'a> = ANSIGenericStrings<'a, [u8]>; + +/// A function to construct an `ANSIByteStrings` instance. +#[allow(non_snake_case)] +pub fn ANSIByteStrings<'a>(arg: &'a [ANSIByteString<'a>]) -> ANSIByteStrings<'a> { + ANSIGenericStrings(arg) +} + + +// ---- paint functions ---- + +impl Style { + + /// Paints the given text with this colour, returning an ANSI string. + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S> + where I: Into>, + ::Owned: fmt::Debug { + ANSIGenericString { + string: input.into(), + style: self, + } + } +} + + +impl Colour { + + /// Paints the given text with this colour, returning an ANSI string. + /// This is a short-cut so you don’t have to use `Blue.normal()` just + /// to get blue text. + /// + /// ``` + /// use ansi_term::Colour::Blue; + /// println!("{}", Blue.paint("da ba dee")); + /// ``` + pub fn paint<'a, I, S: 'a + ToOwned + ?Sized>(self, input: I) -> ANSIGenericString<'a, S> + where I: Into>, + ::Owned: fmt::Debug { + ANSIGenericString { + string: input.into(), + style: self.normal(), + } + } +} + + +// ---- writers for individual ANSI strings ---- + +impl<'a> fmt::Display for ANSIString<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let w: &mut fmt::Write = f; + self.write_to_any(w) + } +} + +impl<'a> ANSIByteString<'a> { + /// Write an `ANSIByteString` to an `io::Write`. This writes the escape + /// sequences for the associated `Style` around the bytes. + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + let w: &mut io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericString<'a, S> +where ::Owned: fmt::Debug, &'a S: AsRef<[u8]> { + fn write_to_any + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + write!(w, "{}", self.style.prefix())?; + w.write_str(self.string.as_ref())?; + write!(w, "{}", self.style.suffix()) + } +} + + +// ---- writers for combined ANSI strings ---- + +impl<'a> fmt::Display for ANSIStrings<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let f: &mut fmt::Write = f; + self.write_to_any(f) + } +} + +impl<'a> ANSIByteStrings<'a> { + /// Write `ANSIByteStrings` to an `io::Write`. This writes the minimal + /// escape sequences for the associated `Style`s around each set of + /// bytes. + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + let w: &mut io::Write = w; + self.write_to_any(w) + } +} + +impl<'a, S: 'a + ToOwned + ?Sized> ANSIGenericStrings<'a, S> +where ::Owned: fmt::Debug, &'a S: AsRef<[u8]> { + fn write_to_any + ?Sized>(&self, w: &mut W) -> Result<(), W::Error> { + use self::Difference::*; + + let first = match self.0.first() { + None => return Ok(()), + Some(f) => f, + }; + + write!(w, "{}", first.style.prefix())?; + w.write_str(first.string.as_ref())?; + + for window in self.0.windows(2) { + match Difference::between(&window[0].style, &window[1].style) { + ExtraStyles(style) => write!(w, "{}", style.prefix())?, + Reset => write!(w, "{}{}", RESET, window[1].style.prefix())?, + NoDifference => {/* Do nothing! */}, + } + + w.write_str(&window[1].string)?; + } + + // Write the final reset string after all of the ANSIStrings have been + // written, *except* if the last one has no styles, because it would + // have already been written by this point. + if let Some(last) = self.0.last() { + if !last.style.is_plain() { + write!(w, "{}", RESET)?; + } + } + + Ok(()) + } +} + + +// ---- tests ---- + +#[cfg(test)] +mod tests { + pub use super::super::ANSIStrings; + pub use style::Style; + pub use style::Colour::*; + + #[test] + fn no_control_codes_for_plain() { + let one = Style::default().paint("one"); + let two = Style::default().paint("two"); + let output = format!("{}", ANSIStrings( &[ one, two ] )); + assert_eq!(&*output, "onetwo"); + } +} diff --git a/ansi_term/src/lib.rs b/ansi_term/src/lib.rs new file mode 100644 index 000000000..f2a676a1c --- /dev/null +++ b/ansi_term/src/lib.rs @@ -0,0 +1,205 @@ +//! This is a library for controlling colours and formatting, such as +//! red bold text or blue underlined text, on ANSI terminals. +//! +//! +//! ## Basic usage +//! +//! There are two main data structures in this crate that you need to be +//! concerned with: `ANSIString` and `Style`. A `Style` holds stylistic +//! information: colours, whether the text should be bold, or blinking, or +//! whatever. There are also `Colour` variants that represent simple foreground +//! colour styles. An `ANSIString` is a string paired with a `Style`. +//! +//! (Yes, it’s British English, but you won’t have to write “colour” very often. +//! `Style` is used the majority of the time.) +//! +//! To format a string, call the `paint` method on a `Style` or a `Colour`, +//! passing in the string you want to format as the argument. For example, +//! here’s how to get some red text: +//! +//! use ansi_term::Colour::Red; +//! println!("This is in red: {}", Red.paint("a red string")); +//! +//! It’s important to note that the `paint` method does *not* actually return a +//! string with the ANSI control characters surrounding it. Instead, it returns +//! an `ANSIString` value that has a `Display` implementation that, when +//! formatted, returns the characters. This allows strings to be printed with a +//! minimum of `String` allocations being performed behind the scenes. +//! +//! If you *do* want to get at the escape codes, then you can convert the +//! `ANSIString` to a string as you would any other `Display` value: +//! +//! use ansi_term::Colour::Red; +//! use std::string::ToString; +//! let red_string = Red.paint("a red string").to_string(); +//! +//! +//! ## Bold, underline, background, and other styles +//! +//! For anything more complex than plain foreground colour changes, you need to +//! construct `Style` objects themselves, rather than beginning with a `Colour`. +//! You can do this by chaining methods based on a new `Style`, created with +//! `Style::new()`. Each method creates a new style that has that specific +//! property set. For example: +//! +//! use ansi_term::Style; +//! println!("How about some {} and {}?", +//! Style::new().bold().paint("bold"), +//! Style::new().underline().paint("underline")); +//! +//! For brevity, these methods have also been implemented for `Colour` values, +//! so you can give your styles a foreground colour without having to begin with +//! an empty `Style` value: +//! +//! use ansi_term::Colour::{Blue, Yellow}; +//! println!("Demonstrating {} and {}!", +//! Blue.bold().paint("blue bold"), +//! Yellow.underline().paint("yellow underline")); +//! println!("Yellow on blue: {}", Yellow.on(Blue).paint("wow!")); +//! +//! The complete list of styles you can use are: `bold`, `dimmed`, `italic`, +//! `underline`, `blink`, `reverse`, `hidden`, `strikethrough`, and `on` for +//! background colours. +//! +//! In some cases, you may find it easier to change the foreground on an +//! existing `Style` rather than starting from the appropriate `Colour`. +//! You can do this using the `fg` method: +//! +//! use ansi_term::Style; +//! use ansi_term::Colour::{Blue, Cyan, Yellow}; +//! println!("Yellow on blue: {}", Style::new().on(Blue).fg(Yellow).paint("yow!")); +//! println!("Also yellow on blue: {}", Cyan.on(Blue).fg(Yellow).paint("zow!")); +//! +//! Finally, you can turn a `Colour` into a `Style` with the `normal` method. +//! This will produce the exact same `ANSIString` as if you just used the +//! `paint` method on the `Colour` directly, but it’s useful in certain cases: +//! for example, you may have a method that returns `Styles`, and need to +//! represent both the “red bold” and “red, but not bold” styles with values of +//! the same type. The `Style` struct also has a `Default` implementation if you +//! want to have a style with *nothing* set. +//! +//! use ansi_term::Style; +//! use ansi_term::Colour::Red; +//! Red.normal().paint("yet another red string"); +//! Style::default().paint("a completely regular string"); +//! +//! +//! ## Extended colours +//! +//! You can access the extended range of 256 colours by using the `Fixed` colour +//! variant, which takes an argument of the colour number to use. This can be +//! included wherever you would use a `Colour`: +//! +//! use ansi_term::Colour::Fixed; +//! Fixed(134).paint("A sort of light purple"); +//! Fixed(221).on(Fixed(124)).paint("Mustard in the ketchup"); +//! +//! The first sixteen of these values are the same as the normal and bold +//! standard colour variants. There’s nothing stopping you from using these as +//! `Fixed` colours instead, but there’s nothing to be gained by doing so +//! either. +//! +//! You can also access full 24-bit color by using the `RGB` colour variant, +//! which takes separate `u8` arguments for red, green, and blue: +//! +//! use ansi_term::Colour::RGB; +//! RGB(70, 130, 180).paint("Steel blue"); +//! +//! ## Combining successive coloured strings +//! +//! The benefit of writing ANSI escape codes to the terminal is that they +//! *stack*: you do not need to end every coloured string with a reset code if +//! the text that follows it is of a similar style. For example, if you want to +//! have some blue text followed by some blue bold text, it’s possible to send +//! the ANSI code for blue, followed by the ANSI code for bold, and finishing +//! with a reset code without having to have an extra one between the two +//! strings. +//! +//! This crate can optimise the ANSI codes that get printed in situations like +//! this, making life easier for your terminal renderer. The `ANSIStrings` +//! struct takes a slice of several `ANSIString` values, and will iterate over +//! each of them, printing only the codes for the styles that need to be updated +//! as part of its formatting routine. +//! +//! The following code snippet uses this to enclose a binary number displayed in +//! red bold text inside some red, but not bold, brackets: +//! +//! use ansi_term::Colour::Red; +//! use ansi_term::{ANSIString, ANSIStrings}; +//! let some_value = format!("{:b}", 42); +//! let strings: &[ANSIString<'static>] = &[ +//! Red.paint("["), +//! Red.bold().paint(some_value), +//! Red.paint("]"), +//! ]; +//! println!("Value: {}", ANSIStrings(strings)); +//! +//! There are several things to note here. Firstly, the `paint` method can take +//! *either* an owned `String` or a borrowed `&str`. Internally, an `ANSIString` +//! holds a copy-on-write (`Cow`) string value to deal with both owned and +//! borrowed strings at the same time. This is used here to display a `String`, +//! the result of the `format!` call, using the same mechanism as some +//! statically-available `&str` slices. Secondly, that the `ANSIStrings` value +//! works in the same way as its singular counterpart, with a `Display` +//! implementation that only performs the formatting when required. +//! +//! ## Byte strings +//! +//! This library also supports formatting `[u8]` byte strings; this supports +//! applications working with text in an unknown encoding. `Style` and +//! `Color` support painting `[u8]` values, resulting in an `ANSIByteString`. +//! This type does not implement `Display`, as it may not contain UTF-8, but +//! it does provide a method `write_to` to write the result to any +//! `io::Write`: +//! +//! use ansi_term::Colour::Green; +//! Green.paint("user data".as_bytes()).write_to(&mut std::io::stdout()).unwrap(); +//! +//! Similarly, the type `ANSIByteStrings` supports writing a list of +//! `ANSIByteString` values with minimal escape sequences: +//! +//! use ansi_term::Colour::Green; +//! use ansi_term::ANSIByteStrings; +//! ANSIByteStrings(&[ +//! Green.paint("user data 1\n".as_bytes()), +//! Green.bold().paint("user data 2\n".as_bytes()), +//! ]).write_to(&mut std::io::stdout()).unwrap(); + + +#![crate_name = "ansi_term"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] + +#![warn(missing_copy_implementations)] +#![warn(missing_docs)] +#![warn(trivial_casts, trivial_numeric_casts)] +#![warn(unused_extern_crates, unused_qualifications)] + +#[cfg(target_os="windows")] +extern crate winapi; + +mod ansi; +pub use ansi::{Prefix, Infix, Suffix}; + +mod style; +pub use style::{Colour, Style}; + +/// Color is a type alias for Colour for those who can't be bothered. +pub use Colour as Color; + +// I'm not beyond calling Colour Colour, rather than Color, but I did +// purposefully name this crate 'ansi-term' so people wouldn't get +// confused when they tried to install it. +// +// Only *after* they'd installed it. + +mod difference; +mod display; +pub use display::*; + +mod write; + +mod windows; +pub use windows::*; + +mod debug; diff --git a/ansi_term/src/style.rs b/ansi_term/src/style.rs new file mode 100644 index 000000000..b9fb52326 --- /dev/null +++ b/ansi_term/src/style.rs @@ -0,0 +1,259 @@ +/// A style is a collection of properties that can format a string +/// using ANSI escape codes. +#[derive(PartialEq, Clone, Copy)] +pub struct Style { + + /// The style's foreground colour, if it has one. + pub foreground: Option, + + /// The style's background colour, if it has one. + pub background: Option, + + /// Whether this style is bold. + pub is_bold: bool, + + /// Whether this style is dimmed. + pub is_dimmed: bool, + + /// Whether this style is italic. + pub is_italic: bool, + + /// Whether this style is underlined. + pub is_underline: bool, + + /// Whether this style is blinking. + pub is_blink: bool, + + /// Whether this style has reverse colours. + pub is_reverse: bool, + + /// Whether this style is hidden. + pub is_hidden: bool, + + /// Whether this style is struckthrough. + pub is_strikethrough: bool +} + +impl Style { + /// Creates a new Style with no differences. + pub fn new() -> Style { + Style::default() + } + + /// Returns a `Style` with the bold property set. + pub fn bold(&self) -> Style { + Style { is_bold: true, .. *self } + } + + /// Returns a `Style` with the dimmed property set. + pub fn dimmed(&self) -> Style { + Style { is_dimmed: true, .. *self } + } + + /// Returns a `Style` with the italic property set. + pub fn italic(&self) -> Style { + Style { is_italic: true, .. *self } + } + + /// Returns a `Style` with the underline property set. + pub fn underline(&self) -> Style { + Style { is_underline: true, .. *self } + } + + /// Returns a `Style` with the blink property set. + pub fn blink(&self) -> Style { + Style { is_blink: true, .. *self } + } + + /// Returns a `Style` with the reverse property set. + pub fn reverse(&self) -> Style { + Style { is_reverse: true, .. *self } + } + + /// Returns a `Style` with the hidden property set. + pub fn hidden(&self) -> Style { + Style { is_hidden: true, .. *self } + } + + /// Returns a `Style` with the hidden property set. + pub fn strikethrough(&self) -> Style { + Style { is_strikethrough: true, .. *self } + } + + /// Returns a `Style` with the foreground colour property set. + pub fn fg(&self, foreground: Colour) -> Style { + Style { foreground: Some(foreground), .. *self } + } + + /// Returns a `Style` with the background colour property set. + pub fn on(&self, background: Colour) -> Style { + Style { background: Some(background), .. *self } + } + + /// Return true if this `Style` has no actual styles, and can be written + /// without any control characters. + pub fn is_plain(self) -> bool { + self == Style::default() + } +} + +impl Default for Style { + + /// Returns a style with *no* properties set. Formatting text using this + /// style returns the exact same text. + /// + /// ``` + /// use ansi_term::Style; + /// assert_eq!(None, Style::default().foreground); + /// assert_eq!(None, Style::default().background); + /// assert_eq!(false, Style::default().is_bold); + /// assert_eq!("txt", Style::default().paint("txt").to_string()); + /// ``` + fn default() -> Style { + Style { + foreground: None, + background: None, + is_bold: false, + is_dimmed: false, + is_italic: false, + is_underline: false, + is_blink: false, + is_reverse: false, + is_hidden: false, + is_strikethrough: false, + } + } +} + + +// ---- colours ---- + +/// A colour is one specific type of ANSI escape code, and can refer +/// to either the foreground or background colour. +/// +/// These use the standard numeric sequences. +/// See +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum Colour { + + /// Colour #0 (foreground code `30`, background code `40`). + /// + /// This is not necessarily the background colour, and using it as one may + /// render the text hard to read on terminals with dark backgrounds. + Black, + + /// Colour #1 (foreground code `31`, background code `41`). + Red, + + /// Colour #2 (foreground code `32`, background code `42`). + Green, + + /// Colour #3 (foreground code `33`, background code `43`). + Yellow, + + /// Colour #4 (foreground code `34`, background code `44`). + Blue, + + /// Colour #5 (foreground code `35`, background code `45`). + Purple, + + /// Colour #6 (foreground code `36`, background code `46`). + Cyan, + + /// Colour #7 (foreground code `37`, background code `47`). + /// + /// As above, this is not necessarily the foreground colour, and may be + /// hard to read on terminals with light backgrounds. + White, + + /// A colour number from 0 to 255, for use in 256-colour terminal + /// environments. + /// + /// - Colours 0 to 7 are the `Black` to `White` variants respectively. + /// These colours can usually be changed in the terminal emulator. + /// - Colours 8 to 15 are brighter versions of the eight colours above. + /// These can also usually be changed in the terminal emulator, or it + /// could be configured to use the original colours and show the text in + /// bold instead. It varies depending on the program. + /// - Colours 16 to 231 contain several palettes of bright colours, + /// arranged in six squares measuring six by six each. + /// - Colours 232 to 255 are shades of grey from black to white. + /// + /// It might make more sense to look at a [colour chart][cc]. + /// + /// [cc]: https://upload.wikimedia.org/wikipedia/en/1/15/Xterm_256color_chart.svg + Fixed(u8), + + /// A 24-bit RGB color, as specified by ISO-8613-3. + RGB(u8, u8, u8), +} + + +impl Colour { + /// Return a `Style` with the foreground colour set to this colour. + pub fn normal(self) -> Style { + Style { foreground: Some(self), .. Style::default() } + } + + /// Returns a `Style` with the bold property set. + pub fn bold(self) -> Style { + Style { foreground: Some(self), is_bold: true, .. Style::default() } + } + + /// Returns a `Style` with the dimmed property set. + pub fn dimmed(self) -> Style { + Style { foreground: Some(self), is_dimmed: true, .. Style::default() } + } + + /// Returns a `Style` with the italic property set. + pub fn italic(self) -> Style { + Style { foreground: Some(self), is_italic: true, .. Style::default() } + } + + /// Returns a `Style` with the underline property set. + pub fn underline(self) -> Style { + Style { foreground: Some(self), is_underline: true, .. Style::default() } + } + + /// Returns a `Style` with the blink property set. + pub fn blink(self) -> Style { + Style { foreground: Some(self), is_blink: true, .. Style::default() } + } + + /// Returns a `Style` with the reverse property set. + pub fn reverse(self) -> Style { + Style { foreground: Some(self), is_reverse: true, .. Style::default() } + } + + /// Returns a `Style` with the hidden property set. + pub fn hidden(self) -> Style { + Style { foreground: Some(self), is_hidden: true, .. Style::default() } + } + + /// Returns a `Style` with the strikethrough property set. + pub fn strikethrough(self) -> Style { + Style { foreground: Some(self), is_strikethrough: true, .. Style::default() } + } + + /// Returns a `Style` with the background colour property set. + pub fn on(self, background: Colour) -> Style { + Style { foreground: Some(self), background: Some(background), .. Style::default() } + } +} + +impl From for Style { + + /// You can turn a `Colour` into a `Style` with the foreground colour set + /// with the `From` trait. + /// + /// ``` + /// use ansi_term::{Style, Colour}; + /// let green_foreground = Style::default().fg(Colour::Green); + /// assert_eq!(green_foreground, Colour::Green.normal()); + /// assert_eq!(green_foreground, Colour::Green.into()); + /// assert_eq!(green_foreground, Style::from(Colour::Green)); + /// ``` + fn from(colour: Colour) -> Style { + colour.normal() + } +} diff --git a/ansi_term/src/windows.rs b/ansi_term/src/windows.rs new file mode 100644 index 000000000..ff6fa683d --- /dev/null +++ b/ansi_term/src/windows.rs @@ -0,0 +1,40 @@ +/// Enables ANSI code support on Windows 10. +/// +/// This uses Windows API calls to alter the properties of the console that +/// the program is running in. +/// +/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx +/// +/// Returns a `Result` with the Windows error code if unsuccessful. +#[cfg(windows)] +pub fn enable_ansi_support() -> Result<(), u32> { + use winapi::um::processenv::GetStdHandle; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; + + const STD_OUT_HANDLE: u32 = -11i32 as u32; + const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004; + + unsafe { + // https://docs.microsoft.com/en-us/windows/console/getstdhandle + let std_out_handle = GetStdHandle(STD_OUT_HANDLE); + let error_code = GetLastError(); + if error_code != 0 { return Err(error_code); } + + // https://docs.microsoft.com/en-us/windows/console/getconsolemode + let mut console_mode: u32 = 0; + GetConsoleMode(std_out_handle, &mut console_mode); + let error_code = GetLastError(); + if error_code != 0 { return Err(error_code); } + + // VT processing not already enabled? + if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 { + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + SetConsoleMode(std_out_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + let error_code = GetLastError(); + if error_code != 0 { return Err(error_code); } + } + } + + return Ok(()); +} diff --git a/ansi_term/src/write.rs b/ansi_term/src/write.rs new file mode 100644 index 000000000..bb146ac15 --- /dev/null +++ b/ansi_term/src/write.rs @@ -0,0 +1,40 @@ +use std::fmt; +use std::io; + + +pub trait AnyWrite { + type wstr: ?Sized; + type Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error>; + + fn write_str(&mut self, s: &Self::wstr) -> Result<(), Self::Error>; +} + + +impl<'a> AnyWrite for fmt::Write + 'a { + type wstr = str; + type Error = fmt::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + fmt::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::wstr) -> Result<(), Self::Error> { + fmt::Write::write_str(self, s) + } +} + + +impl<'a> AnyWrite for io::Write + 'a { + type wstr = [u8]; + type Error = io::Error; + + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Self::Error> { + io::Write::write_fmt(self, fmt) + } + + fn write_str(&mut self, s: &Self::wstr) -> Result<(), Self::Error> { + io::Write::write_all(self, s) + } +} diff --git a/atty/.cargo-checksum.json b/atty/.cargo-checksum.json new file mode 100644 index 000000000..d828fa118 --- /dev/null +++ b/atty/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"} \ No newline at end of file diff --git a/atty/CHANGELOG.md b/atty/CHANGELOG.md new file mode 100644 index 000000000..0b5c0eab5 --- /dev/null +++ b/atty/CHANGELOG.md @@ -0,0 +1,61 @@ +# 0.2.11 + +* fix msys detection with `winapi@0.3.5` [#28](https://github.com/softprops/atty/pull/28) + +# 0.2.10 + +* fix wasm regression [#27](https://github.com/softprops/atty/pull/27) + +# 0.2.9 + +* Fix fix pty detection [#25](https://github.com/softprops/atty/pull/25) + +# 0.2.8 + +* Fix an inverted condition on MinGW [#22](https://github.com/softprops/atty/pull/22) + +# 0.2.7 + +* Change `||` to `&&` for whether MSYS is a tty [#24](https://github.com/softprops/atty/pull/24/) + +# 0.2.6 + +* updated winapi dependency to [0.3](https://retep998.github.io/blog/winapi-0.3/) [#18](https://github.com/softprops/atty/pull/18) + +# 0.2.5 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.4 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.3 + +* added support for Redox OS [#14](https://github.com/softprops/atty/pull/14) + +# 0.2.2 + +* use target specific dependencies [#11](https://github.com/softprops/atty/pull/11) +* Add tty detection for MSYS terminals [#12](https://github.com/softprops/atty/pull/12) + +# 0.2.1 + +* fix windows bug + +# 0.2.0 + +* support for various stream types + +# 0.1.2 + +* windows support (with automated testing) +* automated code coverage + +# 0.1.1 + +* bumped libc dep from `0.1` to `0.2` + +# 0.1.0 + +* initial release diff --git a/atty/Cargo.toml b/atty/Cargo.toml new file mode 100644 index 000000000..0d02b6af2 --- /dev/null +++ b/atty/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "atty" +version = "0.2.11" +authors = ["softprops "] +description = "A simple interface for querying atty" +homepage = "https://github.com/softprops/atty" +documentation = "http://softprops.github.io/atty" +readme = "README.md" +keywords = ["terminal", "tty"] +license = "MIT" +repository = "https://github.com/softprops/atty" +[target."cfg(target_os = \"redox\")".dependencies.termion] +version = "1.5" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +default-features = false +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["consoleapi", "processenv", "minwinbase", "minwindef", "winbase"] +[badges.travis-ci] +repository = "softprops/atty" diff --git a/atty/LICENSE b/atty/LICENSE new file mode 100644 index 000000000..d1f01c829 --- /dev/null +++ b/atty/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015-2017 Doug Tangren + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/atty/README.md b/atty/README.md new file mode 100644 index 000000000..5ce32d1d7 --- /dev/null +++ b/atty/README.md @@ -0,0 +1,76 @@ +# atty + +[![Build Status](https://travis-ci.org/softprops/atty.svg?branch=master)](https://travis-ci.org/softprops/atty) [![Build status](https://ci.appveyor.com/api/projects/status/geggrsnsjsuse8cv?svg=true)](https://ci.appveyor.com/project/softprops/atty) [![Coverage Status](https://coveralls.io/repos/softprops/atty/badge.svg?branch=master&service=github)](https://coveralls.io/github/softprops/atty?branch=master) [![crates.io](https://img.shields.io/crates/v/atty.svg)](https://crates.io/crates/atty) [![Released API docs](https://docs.rs/atty/badge.svg)](http://docs.rs/atty) [![Master API docs](https://img.shields.io/badge/docs-master-green.svg)](https://softprops.github.io/atty) + +> are you or are you not a tty? + + +## install + +Add the following to your `Cargo.toml` + +```toml +[dependencies] +atty = "0.2" +``` + +## usage + +```rust +extern crate atty; + +use atty::Stream; + +fn main() { + if atty::is(Stream::Stdout) { + println!("I'm a terminal"); + } else { + println!("I'm not"); + } +} +``` + +## testing + +This library has been unit tested on both unix and windows platforms (via appveyor). + + +A simple example program is provided in this repo to test various tty's. By default. + +It prints + +```bash +$ cargo run --example atty +stdout? true +stderr? true +stdin? true +``` + +To test std in, pipe some text to the program + +```bash +$ echo "test" | cargo run --example atty +stdout? true +stderr? true +stdin? false +``` + +To test std out, pipe the program to something + +```bash +$ cargo run --example atty | grep std +stdout? false +stderr? true +stdin? true +``` + +To test std err, pipe the program to something redirecting std err + +```bash +$ cargo run --example atty 2>&1 | grep std +stdout? false +stderr? false +stdin? true +``` + +Doug Tangren (softprops) 2015-2017 diff --git a/atty/appveyor.yml b/atty/appveyor.yml new file mode 100644 index 000000000..d7fb12794 --- /dev/null +++ b/atty/appveyor.yml @@ -0,0 +1,16 @@ +environment: + matrix: + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + - TARGET: nightly-x86_64-pc-windows-gnu + - TARGET: nightly-i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe" + - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - call "%VCVARS%" || ver>nul + - rustc -vV + - cargo -vV +build: false +test_script: + - cargo build diff --git a/atty/examples/atty.rs b/atty/examples/atty.rs new file mode 100644 index 000000000..3b3635e59 --- /dev/null +++ b/atty/examples/atty.rs @@ -0,0 +1,9 @@ +extern crate atty; + +use atty::{is, Stream}; + +fn main() { + println!("stdout? {}", is(Stream::Stdout)); + println!("stderr? {}", is(Stream::Stderr)); + println!("stdin? {}", is(Stream::Stdin)); +} diff --git a/atty/rustfmt.toml b/atty/rustfmt.toml new file mode 100644 index 000000000..d83987dca --- /dev/null +++ b/atty/rustfmt.toml @@ -0,0 +1,10 @@ +# keep imports tidy +reorder_imported_names = true +reorder_imports = true +reorder_imports_in_group = true +# there is no try! +use_try_shorthand = true +# don't create rustfmt artifacts +write_mode = "Replace" +# reduce wide load +max_width = 80 \ No newline at end of file diff --git a/atty/src/lib.rs b/atty/src/lib.rs new file mode 100644 index 000000000..6bffeadac --- /dev/null +++ b/atty/src/lib.rs @@ -0,0 +1,210 @@ +//! atty is a simple utility that answers one question +//! > is this a tty? +//! +//! usage is just as simple +//! +//! ``` +//! if atty::is(atty::Stream::Stdout) { +//! println!("i'm a tty") +//! } +//! ``` +//! +//! ``` +//! if atty::isnt(atty::Stream::Stdout) { +//! println!("i'm not a tty") +//! } +//! ``` + +#![cfg_attr(unix, no_std)] + +#[cfg(unix)] +extern crate libc; +#[cfg(windows)] +extern crate winapi; +#[cfg(target_os = "redox")] +extern crate termion; + +#[cfg(windows)] +use winapi::shared::minwindef::DWORD; +#[cfg(windows)] +use winapi::shared::ntdef::WCHAR; + +/// possible stream sources +#[derive(Clone, Copy, Debug)] +pub enum Stream { + Stdout, + Stderr, + Stdin, +} + +/// returns true if this is a tty +#[cfg(all(unix, not(target_arch = "wasm32")))] +pub fn is(stream: Stream) -> bool { + extern crate libc; + + let fd = match stream { + Stream::Stdout => libc::STDOUT_FILENO, + Stream::Stderr => libc::STDERR_FILENO, + Stream::Stdin => libc::STDIN_FILENO, + }; + unsafe { libc::isatty(fd) != 0 } +} + +/// returns true if this is a tty +#[cfg(windows)] +pub fn is(stream: Stream) -> bool { + use winapi::um::winbase::{STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT, + STD_OUTPUT_HANDLE as STD_OUTPUT}; + + let (fd, others) = match stream { + Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]), + Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]), + Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]), + }; + if unsafe { console_on_any(&[fd]) } { + // False positives aren't possible. If we got a console then + // we definitely have a tty on stdin. + return true; + } + + // At this point, we *could* have a false negative. We can determine that + // this is true negative if we can detect the presence of a console on + // any of the other streams. If another stream has a console, then we know + // we're in a Windows console and can therefore trust the negative. + if unsafe { console_on_any(&others) } { + return false; + } + + // Otherwise, we fall back to a very strange msys hack to see if we can + // sneakily detect the presence of a tty. + unsafe { msys_tty_on(fd) } +} + +/// returns true if this is _not_ a tty +pub fn isnt(stream: Stream) -> bool { + !is(stream) +} + +/// Returns true if any of the given fds are on a console. +#[cfg(windows)] +unsafe fn console_on_any(fds: &[DWORD]) -> bool { + use winapi::um::consoleapi::GetConsoleMode; + use winapi::um::processenv::GetStdHandle; + + for &fd in fds { + let mut out = 0; + let handle = GetStdHandle(fd); + if GetConsoleMode(handle, &mut out) != 0 { + return true; + } + } + false +} + +/// Returns true if there is an MSYS tty on the given handle. +#[cfg(windows)] +unsafe fn msys_tty_on(fd: DWORD) -> bool { + use std::mem; + use std::slice; + + use winapi::ctypes::c_void; + use winapi::um::winbase::GetFileInformationByHandleEx; + use winapi::um::fileapi::FILE_NAME_INFO; + use winapi::um::minwinbase::FileNameInfo; + use winapi::um::processenv::GetStdHandle; + use winapi::shared::minwindef::MAX_PATH; + + let size = mem::size_of::(); + let mut name_info_bytes = vec![0u8; size + MAX_PATH * mem::size_of::()]; + let res = GetFileInformationByHandleEx( + GetStdHandle(fd), + FileNameInfo, + &mut *name_info_bytes as *mut _ as *mut c_void, + name_info_bytes.len() as u32, + ); + if res == 0 { + return false; + } + let name_info: &FILE_NAME_INFO = &*(name_info_bytes.as_ptr() as *const FILE_NAME_INFO); + let s = slice::from_raw_parts( + name_info.FileName.as_ptr(), + name_info.FileNameLength as usize / 2, + ); + let name = String::from_utf16_lossy(s); + // This checks whether 'pty' exists in the file name, which indicates that + // a pseudo-terminal is attached. To mitigate against false positives + // (e.g., an actual file name that contains 'pty'), we also require that + // either the strings 'msys-' or 'cygwin-' are in the file name as well.) + let is_msys = name.contains("msys-") || name.contains("cygwin-"); + let is_pty = name.contains("-pty"); + is_msys && is_pty +} + +/// returns true if this is a tty +#[cfg(target_os = "redox")] +pub fn is(stream: Stream) -> bool { + use std::io; + use termion::is_tty; + + match stream { + Stream::Stdin => is_tty(&io::stdin()), + Stream::Stdout => is_tty(&io::stdout()), + Stream::Stderr => is_tty(&io::stderr()), + } +} + +/// returns true if this is a tty +#[cfg(target_arch = "wasm32")] +pub fn is(_stream: Stream) -> bool { + false +} + +#[cfg(test)] +mod tests { + use super::{Stream, is}; + + #[test] + #[cfg(windows)] + fn is_err() { + // appveyor pipes its output + assert!(!is(Stream::Stderr)) + } + + #[test] + #[cfg(windows)] + fn is_out() { + // appveyor pipes its output + assert!(!is(Stream::Stdout)) + } + + #[test] + #[cfg(windows)] + fn is_in() { + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(unix)] + fn is_err() { + assert!(is(Stream::Stderr)) + } + + #[test] + #[cfg(unix)] + fn is_out() { + assert!(is(Stream::Stdout)) + } + + #[test] + #[cfg(target_os = "macos")] + fn is_in() { + // macos on travis seems to pipe its input + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(all(not(target_os = "macos"), unix))] + fn is_in() { + assert!(is(Stream::Stdin)) + } +} diff --git a/autocfg/.cargo-checksum.json b/autocfg/.cargo-checksum.json new file mode 100644 index 000000000..0950a2a3e --- /dev/null +++ b/autocfg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"} \ No newline at end of file diff --git a/autocfg/Cargo.toml b/autocfg/Cargo.toml new file mode 100644 index 000000000..615328a93 --- /dev/null +++ b/autocfg/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "autocfg" +version = "0.1.4" +authors = ["Josh Stone "] +description = "Automatic cfg for Rust compiler features" +readme = "README.md" +keywords = ["rustc", "build", "autoconf"] +categories = ["development-tools::build-utils"] +license = "Apache-2.0/MIT" +repository = "https://github.com/cuviper/autocfg" + +[dependencies] diff --git a/autocfg/LICENSE-APACHE b/autocfg/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/autocfg/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/autocfg/LICENSE-MIT b/autocfg/LICENSE-MIT new file mode 100644 index 000000000..44fbc4d8b --- /dev/null +++ b/autocfg/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 Josh Stone + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/autocfg/README.md b/autocfg/README.md new file mode 100644 index 000000000..90ee63cfe --- /dev/null +++ b/autocfg/README.md @@ -0,0 +1,75 @@ +autocfg +======= + +[![autocfg crate](https://img.shields.io/crates/v/autocfg.svg)](https://crates.io/crates/autocfg) +[![autocfg documentation](https://docs.rs/autocfg/badge.svg)](https://docs.rs/autocfg) +![minimum rustc 1.0](https://img.shields.io/badge/rustc-1.0+-red.svg) +[![Travis Status](https://travis-ci.org/cuviper/autocfg.svg?branch=master)](https://travis-ci.org/cuviper/autocfg) + +A Rust library for build scripts to automatically configure code based on +compiler support. Code snippets are dynamically tested to see if the `rustc` +will accept them, rather than hard-coding specific version support. + + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[build-dependencies] +autocfg = "0.1" +``` + +Then use it in your `build.rs` script to detect compiler features. For +example, to test for 128-bit integer support, it might look like: + +```rust +extern crate autocfg; + +fn main() { + let ac = autocfg::new(); + ac.emit_has_type("i128"); + + // (optional) We don't need to rerun for anything external. + autocfg::rerun_path(file!()); +} +``` + +If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +should only be used when the compiler supports it. + + +## Release Notes + +- 0.1.4 (2019-05-22) + - Relax `std`/`no_std` probing to a warning instead of an error. + - Improve `rustc` bootstrap compatibility. + +- 0.1.3 (2019-05-21) + - Auto-detects if `#![no_std]` is needed for the `$TARGET` + +- 0.1.2 (2018-01-16) + - Add `rerun_env(ENV)` to print `cargo:rerun-if-env-changed=ENV` + - Add `rerun_path(PATH)` to print `cargo:rerun-if-changed=PATH` + + +## Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.0.0`. Compatibility is +its entire reason for existence, so this crate will be extremely conservative +about raising this requirement. If this is ever deemed necessary, it will be +treated as a major breaking change for semver purposes. + + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/autocfg/examples/integers.rs b/autocfg/examples/integers.rs new file mode 100644 index 000000000..23d4cba6e --- /dev/null +++ b/autocfg/examples/integers.rs @@ -0,0 +1,9 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + for i in 3..8 { + ac.emit_has_type(&format!("i{}", 1 << i)); + } +} diff --git a/autocfg/examples/paths.rs b/autocfg/examples/paths.rs new file mode 100644 index 000000000..b7a6ca7a2 --- /dev/null +++ b/autocfg/examples/paths.rs @@ -0,0 +1,22 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + + // since ancient times... + ac.emit_has_path("std::vec::Vec"); + ac.emit_path_cfg("std::vec::Vec", "has_vec"); + + // rustc 1.10.0 + ac.emit_has_path("std::panic::PanicInfo"); + ac.emit_path_cfg("std::panic::PanicInfo", "has_panic_info"); + + // rustc 1.20.0 + ac.emit_has_path("std::mem::ManuallyDrop"); + ac.emit_path_cfg("std::mem::ManuallyDrop", "has_manually_drop"); + + // rustc 1.25.0 + ac.emit_has_path("std::ptr::NonNull"); + ac.emit_path_cfg("std::ptr::NonNull", "has_non_null"); +} diff --git a/autocfg/examples/traits.rs b/autocfg/examples/traits.rs new file mode 100644 index 000000000..c1ca00385 --- /dev/null +++ b/autocfg/examples/traits.rs @@ -0,0 +1,26 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + + // since ancient times... + ac.emit_has_trait("std::ops::Add"); + ac.emit_trait_cfg("std::ops::Add", "has_ops"); + + // trait parameters have to be provided + ac.emit_has_trait("std::borrow::Borrow"); + ac.emit_trait_cfg("std::borrow::Borrow", "has_borrow"); + + // rustc 1.8.0 + ac.emit_has_trait("std::ops::AddAssign"); + ac.emit_trait_cfg("std::ops::AddAssign", "has_assign_ops"); + + // rustc 1.12.0 + ac.emit_has_trait("std::iter::Sum"); + ac.emit_trait_cfg("std::iter::Sum", "has_sum"); + + // rustc 1.28.0 + ac.emit_has_trait("std::alloc::GlobalAlloc"); + ac.emit_trait_cfg("std::alloc::GlobalAlloc", "has_global_alloc"); +} diff --git a/autocfg/examples/versions.rs b/autocfg/examples/versions.rs new file mode 100644 index 000000000..992919b7c --- /dev/null +++ b/autocfg/examples/versions.rs @@ -0,0 +1,9 @@ +extern crate autocfg; + +fn main() { + // Normally, cargo will set `OUT_DIR` for build scripts. + let ac = autocfg::AutoCfg::with_dir("target").unwrap(); + for i in 0..100 { + ac.emit_rustc_version(1, i); + } +} diff --git a/autocfg/src/error.rs b/autocfg/src/error.rs new file mode 100644 index 000000000..462483545 --- /dev/null +++ b/autocfg/src/error.rs @@ -0,0 +1,69 @@ +use std::error; +use std::fmt; +use std::io; +use std::num; +use std::str; + +/// A common error type for the `autocfg` crate. +#[derive(Debug)] +pub struct Error { + kind: ErrorKind, +} + +impl error::Error for Error { + fn description(&self) -> &str { + "AutoCfg error" + } + + fn cause(&self) -> Option<&error::Error> { + match self.kind { + ErrorKind::Io(ref e) => Some(e), + ErrorKind::Num(ref e) => Some(e), + ErrorKind::Utf8(ref e) => Some(e), + ErrorKind::Other(_) => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.kind { + ErrorKind::Io(ref e) => e.fmt(f), + ErrorKind::Num(ref e) => e.fmt(f), + ErrorKind::Utf8(ref e) => e.fmt(f), + ErrorKind::Other(s) => s.fmt(f), + } + } +} + +#[derive(Debug)] +enum ErrorKind { + Io(io::Error), + Num(num::ParseIntError), + Utf8(str::Utf8Error), + Other(&'static str), +} + +pub fn from_io(e: io::Error) -> Error { + Error { + kind: ErrorKind::Io(e), + } +} + +pub fn from_num(e: num::ParseIntError) -> Error { + Error { + kind: ErrorKind::Num(e), + } +} + +pub fn from_utf8(e: str::Utf8Error) -> Error { + Error { + kind: ErrorKind::Utf8(e), + } +} + +pub fn from_str(s: &'static str) -> Error { + Error { + kind: ErrorKind::Other(s), + } +} diff --git a/autocfg/src/lib.rs b/autocfg/src/lib.rs new file mode 100644 index 000000000..1461c0c08 --- /dev/null +++ b/autocfg/src/lib.rs @@ -0,0 +1,305 @@ +//! A Rust library for build scripts to automatically configure code based on +//! compiler support. Code snippets are dynamically tested to see if the `rustc` +//! will accept them, rather than hard-coding specific version support. +//! +//! +//! ## Usage +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! autocfg = "0.1" +//! ``` +//! +//! Then use it in your `build.rs` script to detect compiler features. For +//! example, to test for 128-bit integer support, it might look like: +//! +//! ```rust +//! extern crate autocfg; +//! +//! fn main() { +//! # // Normally, cargo will set `OUT_DIR` for build scripts. +//! # std::env::set_var("OUT_DIR", "target"); +//! let ac = autocfg::new(); +//! ac.emit_has_type("i128"); +//! +//! // (optional) We don't need to rerun for anything external. +//! autocfg::rerun_path(file!()); +//! } +//! ``` +//! +//! If the type test succeeds, this will write a `cargo:rustc-cfg=has_i128` line +//! for Cargo, which translates to Rust arguments `--cfg has_i128`. Then in the +//! rest of your Rust code, you can add `#[cfg(has_i128)]` conditions on code that +//! should only be used when the compiler supports it. + +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io::{stderr, Write}; +use std::path::PathBuf; +use std::process::{Command, Stdio}; +#[allow(deprecated)] +use std::sync::atomic::ATOMIC_USIZE_INIT; +use std::sync::atomic::{AtomicUsize, Ordering}; + +mod error; +pub use error::Error; + +mod version; +use version::Version; + +#[cfg(test)] +mod tests; + +/// Helper to detect compiler features for `cfg` output in build scripts. +#[derive(Clone, Debug)] +pub struct AutoCfg { + out_dir: PathBuf, + rustc: PathBuf, + rustc_version: Version, + target: Option, + no_std: bool, +} + +/// Writes a config flag for rustc on standard out. +/// +/// This looks like: `cargo:rustc-cfg=CFG` +/// +/// Cargo will use this in arguments to rustc, like `--cfg CFG`. +pub fn emit(cfg: &str) { + println!("cargo:rustc-cfg={}", cfg); +} + +/// Writes a line telling Cargo to rerun the build script if `path` changes. +/// +/// This looks like: `cargo:rerun-if-changed=PATH` +/// +/// This requires at least cargo 0.7.0, corresponding to rustc 1.6.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_path(path: &str) { + println!("cargo:rerun-if-changed={}", path); +} + +/// Writes a line telling Cargo to rerun the build script if the environment +/// variable `var` changes. +/// +/// This looks like: `cargo:rerun-if-env-changed=VAR` +/// +/// This requires at least cargo 0.21.0, corresponding to rustc 1.20.0. Earlier +/// versions of cargo will simply ignore the directive. +pub fn rerun_env(var: &str) { + println!("cargo:rerun-if-env-changed={}", var); +} + +/// Create a new `AutoCfg` instance. +/// +/// # Panics +/// +/// Panics if `AutoCfg::new()` returns an error. +pub fn new() -> AutoCfg { + AutoCfg::new().unwrap() +} + +impl AutoCfg { + /// Create a new `AutoCfg` instance. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `OUT_DIR` is not set in the environment, or is not a writable directory. + /// + pub fn new() -> Result { + match env::var_os("OUT_DIR") { + Some(d) => Self::with_dir(d), + None => Err(error::from_str("no OUT_DIR specified!")), + } + } + + /// Create a new `AutoCfg` instance with the specified output directory. + /// + /// # Common errors + /// + /// - `rustc` can't be executed, from `RUSTC` or in the `PATH`. + /// - The version output from `rustc` can't be parsed. + /// - `dir` is not a writable directory. + /// + pub fn with_dir>(dir: T) -> Result { + let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); + let rustc: PathBuf = rustc.into(); + let rustc_version = try!(Version::from_rustc(&rustc)); + + // Sanity check the output directory + let dir = dir.into(); + let meta = try!(fs::metadata(&dir).map_err(error::from_io)); + if !meta.is_dir() || meta.permissions().readonly() { + return Err(error::from_str("output path is not a writable directory")); + } + + let mut ac = AutoCfg { + out_dir: dir, + rustc: rustc, + rustc_version: rustc_version, + target: env::var_os("TARGET"), + no_std: false, + }; + + // Sanity check with and without `std`. + if !ac.probe("").unwrap_or(false) { + ac.no_std = true; + if !ac.probe("").unwrap_or(false) { + // Neither worked, so assume nothing... + ac.no_std = false; + let warning = b"warning: autocfg could not probe for `std`\n"; + stderr().write_all(warning).ok(); + } + } + Ok(ac) + } + + /// Test whether the current `rustc` reports a version greater than + /// or equal to "`major`.`minor`". + pub fn probe_rustc_version(&self, major: usize, minor: usize) -> bool { + self.rustc_version >= Version::new(major, minor, 0) + } + + /// Sets a `cfg` value of the form `rustc_major_minor`, like `rustc_1_29`, + /// if the current `rustc` is at least that version. + pub fn emit_rustc_version(&self, major: usize, minor: usize) { + if self.probe_rustc_version(major, minor) { + emit(&format!("rustc_{}_{}", major, minor)); + } + } + + fn probe>(&self, code: T) -> Result { + #[allow(deprecated)] + static ID: AtomicUsize = ATOMIC_USIZE_INIT; + + let id = ID.fetch_add(1, Ordering::Relaxed); + let mut command = Command::new(&self.rustc); + command + .arg("--crate-name") + .arg(format!("probe{}", id)) + .arg("--crate-type=lib") + .arg("--out-dir") + .arg(&self.out_dir) + .arg("--emit=llvm-ir"); + + if let Some(target) = self.target.as_ref() { + command.arg("--target").arg(target); + } + + command.arg("-").stdin(Stdio::piped()); + let mut child = try!(command.spawn().map_err(error::from_io)); + let mut stdin = child.stdin.take().expect("rustc stdin"); + + if self.no_std { + try!(stdin.write_all(b"#![no_std]\n").map_err(error::from_io)); + } + try!(stdin.write_all(code.as_ref()).map_err(error::from_io)); + drop(stdin); + + let status = try!(child.wait().map_err(error::from_io)); + Ok(status.success()) + } + + /// Tests whether the given path can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub use PATH; + /// ``` + pub fn probe_path(&self, path: &str) -> bool { + self.probe(format!("pub use {};", path)).unwrap_or(false) + } + + /// Emits a config value `has_PATH` if `probe_path` returns true. + /// + /// Any non-identifier characters in the `path` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_path(&self, path: &str) { + if self.probe_path(path) { + emit(&format!("has_{}", mangle(path))); + } + } + + /// Emits the given `cfg` value if `probe_path` returns true. + pub fn emit_path_cfg(&self, path: &str, cfg: &str) { + if self.probe_path(path) { + emit(cfg); + } + } + + /// Tests whether the given trait can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub trait Probe: TRAIT + Sized {} + /// ``` + pub fn probe_trait(&self, name: &str) -> bool { + self.probe(format!("pub trait Probe: {} + Sized {{}}", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TRAIT` if `probe_trait` returns true. + /// + /// Any non-identifier characters in the trait `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_trait(&self, name: &str) { + if self.probe_trait(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_trait` returns true. + pub fn emit_trait_cfg(&self, name: &str, cfg: &str) { + if self.probe_trait(name) { + emit(cfg); + } + } + + /// Tests whether the given type can be used. + /// + /// The test code is subject to change, but currently looks like: + /// + /// ```ignore + /// pub type Probe = TYPE; + /// ``` + pub fn probe_type(&self, name: &str) -> bool { + self.probe(format!("pub type Probe = {};", name)) + .unwrap_or(false) + } + + /// Emits a config value `has_TYPE` if `probe_type` returns true. + /// + /// Any non-identifier characters in the type `name` will be replaced with + /// `_` in the generated config value. + pub fn emit_has_type(&self, name: &str) { + if self.probe_type(name) { + emit(&format!("has_{}", mangle(name))); + } + } + + /// Emits the given `cfg` value if `probe_type` returns true. + pub fn emit_type_cfg(&self, name: &str, cfg: &str) { + if self.probe_type(name) { + emit(cfg); + } + } +} + +fn mangle(s: &str) -> String { + s.chars() + .map(|c| match c { + 'A'...'Z' | 'a'...'z' | '0'...'9' => c, + _ => '_', + }) + .collect() +} diff --git a/autocfg/src/tests.rs b/autocfg/src/tests.rs new file mode 100644 index 000000000..f22e0e045 --- /dev/null +++ b/autocfg/src/tests.rs @@ -0,0 +1,65 @@ +use super::AutoCfg; + +#[test] +fn autocfg_version() { + let ac = AutoCfg::with_dir("target").unwrap(); + println!("version: {:?}", ac.rustc_version); + assert!(ac.probe_rustc_version(1, 0)); +} + +#[test] +fn version_cmp() { + use super::version::Version; + let v123 = Version::new(1, 2, 3); + + assert!(Version::new(1, 0, 0) < v123); + assert!(Version::new(1, 2, 2) < v123); + assert!(Version::new(1, 2, 3) == v123); + assert!(Version::new(1, 2, 4) > v123); + assert!(Version::new(1, 10, 0) > v123); + assert!(Version::new(2, 0, 0) > v123); +} + +#[test] +fn probe_add() { + let ac = AutoCfg::with_dir("target").unwrap(); + assert!(ac.probe_path("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_trait("std::ops::Add")); + assert!(ac.probe_type("std::ops::Add")); +} + +#[test] +fn probe_as_ref() { + let ac = AutoCfg::with_dir("target").unwrap(); + assert!(ac.probe_path("std::convert::AsRef")); + assert!(ac.probe_trait("std::convert::AsRef")); + assert!(ac.probe_type("std::convert::AsRef")); +} + +#[test] +fn probe_i128() { + let ac = AutoCfg::with_dir("target").unwrap(); + let missing = !ac.probe_rustc_version(1, 26); + assert!(missing ^ ac.probe_path("std::i128")); + assert!(missing ^ ac.probe_type("i128")); +} + +#[test] +fn probe_sum() { + let ac = AutoCfg::with_dir("target").unwrap(); + let missing = !ac.probe_rustc_version(1, 12); + assert!(missing ^ ac.probe_path("std::iter::Sum")); + assert!(missing ^ ac.probe_trait("std::iter::Sum")); + assert!(missing ^ ac.probe_trait("std::iter::Sum")); + assert!(missing ^ ac.probe_type("std::iter::Sum")); +} + +#[test] +fn probe_no_std() { + let ac = AutoCfg::with_dir("target").unwrap(); + assert!(ac.probe_type("i32")); + assert!(ac.probe_type("[i32]")); + assert_eq!(ac.probe_type("Vec"), !ac.no_std); +} diff --git a/autocfg/src/version.rs b/autocfg/src/version.rs new file mode 100644 index 000000000..378c21e61 --- /dev/null +++ b/autocfg/src/version.rs @@ -0,0 +1,60 @@ +use std::path::Path; +use std::process::Command; +use std::str; + +use super::{error, Error}; + +/// A version structure for making relative comparisons. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + major: usize, + minor: usize, + patch: usize, +} + +impl Version { + /// Creates a `Version` instance for a specific `major.minor.patch` version. + pub fn new(major: usize, minor: usize, patch: usize) -> Self { + Version { + major: major, + minor: minor, + patch: patch, + } + } + + pub fn from_rustc(rustc: &Path) -> Result { + // Get rustc's verbose version + let output = try!(Command::new(rustc) + .args(&["--version", "--verbose"]) + .output() + .map_err(error::from_io)); + if !output.status.success() { + return Err(error::from_str("could not execute rustc")); + } + let output = try!(str::from_utf8(&output.stdout).map_err(error::from_utf8)); + + // Find the release line in the verbose version output. + let release = match output.lines().find(|line| line.starts_with("release: ")) { + Some(line) => &line["release: ".len()..], + None => return Err(error::from_str("could not find rustc release")), + }; + + // Strip off any extra channel info, e.g. "-beta.N", "-nightly" + let version = match release.find('-') { + Some(i) => &release[..i], + None => release, + }; + + // Split the version into semver components. + let mut iter = version.splitn(3, '.'); + let major = try!(iter.next().ok_or(error::from_str("missing major version"))); + let minor = try!(iter.next().ok_or(error::from_str("missing minor version"))); + let patch = try!(iter.next().ok_or(error::from_str("missing patch version"))); + + Ok(Version::new( + try!(major.parse().map_err(error::from_num)), + try!(minor.parse().map_err(error::from_num)), + try!(patch.parse().map_err(error::from_num)), + )) + } +} diff --git a/backtrace-sys/.cargo-checksum.json b/backtrace-sys/.cargo-checksum.json new file mode 100644 index 000000000..34b1ff620 --- /dev/null +++ b/backtrace-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"} \ No newline at end of file diff --git a/backtrace-sys/.pc/.quilt_patches b/backtrace-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/backtrace-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/backtrace-sys/.pc/.quilt_series b/backtrace-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/backtrace-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/backtrace-sys/.pc/.version b/backtrace-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/backtrace-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/backtrace-sys/.pc/applied-patches b/backtrace-sys/.pc/applied-patches new file mode 100644 index 000000000..58c5d72c8 --- /dev/null +++ b/backtrace-sys/.pc/applied-patches @@ -0,0 +1 @@ +remove-unneeded-dep.patch diff --git a/backtrace-sys/.pc/remove-unneeded-dep.patch/.timestamp b/backtrace-sys/.pc/remove-unneeded-dep.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/backtrace-sys/.pc/remove-unneeded-dep.patch/Cargo.toml b/backtrace-sys/.pc/remove-unneeded-dep.patch/Cargo.toml new file mode 100644 index 000000000..f47ab6de1 --- /dev/null +++ b/backtrace-sys/.pc/remove-unneeded-dep.patch/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "backtrace-sys" +version = "0.1.28" +authors = ["Alex Crichton "] +build = "build.rs" +description = "Bindings to the libbacktrace gcc library\n" +homepage = "https://github.com/alexcrichton/backtrace-rs" +documentation = "http://alexcrichton.com/backtrace-rs" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/backtrace-rs" +[dependencies.libc] +version = "0.2" +default-features = false +[build-dependencies.cc] +version = "1.0" diff --git a/backtrace-sys/Cargo.toml b/backtrace-sys/Cargo.toml new file mode 100644 index 000000000..85ca93e44 --- /dev/null +++ b/backtrace-sys/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "backtrace-sys" +version = "0.1.28" +authors = ["Alex Crichton "] +build = "build.rs" +description = "Bindings to the libbacktrace gcc library\n" +homepage = "https://github.com/alexcrichton/backtrace-rs" +documentation = "http://alexcrichton.com/backtrace-rs" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/backtrace-rs" +[dependencies.libc] +version = "0.2" +default-features = false diff --git a/backtrace-sys/LICENSE-APACHE b/backtrace-sys/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/backtrace-sys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/backtrace-sys/LICENSE-MIT b/backtrace-sys/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/backtrace-sys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/backtrace-sys/build.rs b/backtrace-sys/build.rs new file mode 100644 index 000000000..8675c1353 --- /dev/null +++ b/backtrace-sys/build.rs @@ -0,0 +1,10 @@ +use std::process::Command; + +fn main() { + let search_dir = Command::new("sh") + .args(&["-c", "gcc -print-search-dirs | sed -ne 's/^install: //p'"]) + .output().expect("failed to find gcc install dir").stdout; + println!("cargo:rustc-link-lib=static=backtrace"); + println!("cargo:rustc-link-search=native={}", String::from_utf8(search_dir).unwrap().trim_right()); + println!("dh-cargo:deb-built-using=backtrace=0~={}", "libgcc-[0-9]+-dev .*"); +} diff --git a/backtrace-sys/build.rs.orig b/backtrace-sys/build.rs.orig new file mode 100644 index 000000000..01d651eec --- /dev/null +++ b/backtrace-sys/build.rs.orig @@ -0,0 +1,108 @@ +extern crate cc; + +use std::env; +use std::path::PathBuf; +use std::fs::File; + +fn main() { + let target = env::var("TARGET").unwrap(); + + if target.contains("msvc") || // libbacktrace isn't used on MSVC windows + target.contains("emscripten") || // no way this will ever compile for emscripten + target.contains("cloudabi") || + target.contains("wasm32") + { + println!("cargo:rustc-cfg=empty"); + return + } + + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + let mut build = cc::Build::new(); + build + .include("src/libbacktrace") + .include(&out_dir) + .warnings(false) + .file("src/libbacktrace/alloc.c") + .file("src/libbacktrace/dwarf.c") + .file("src/libbacktrace/fileline.c") + .file("src/libbacktrace/posix.c") + .file("src/libbacktrace/read.c") + .file("src/libbacktrace/sort.c") + .file("src/libbacktrace/state.c"); + + // No need to have any symbols reexported form shared objects + build.flag("-fvisibility=hidden"); + + if target.contains("darwin") { + build.file("src/libbacktrace/macho.c"); + } else if target.contains("windows") { + build.file("src/libbacktrace/pecoff.c"); + } else { + build.file("src/libbacktrace/elf.c"); + + let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap(); + if pointer_width == "64" { + build.define("BACKTRACE_ELF_SIZE", "64"); + } else { + build.define("BACKTRACE_ELF_SIZE", "32"); + } + } + + File::create(out_dir.join("backtrace-supported.h")).unwrap(); + build.define("BACKTRACE_SUPPORTED", "1"); + build.define("BACKTRACE_USES_MALLOC", "1"); + build.define("BACKTRACE_SUPPORTS_THREADS", "0"); + build.define("BACKTRACE_SUPPORTS_DATA", "0"); + + File::create(out_dir.join("config.h")).unwrap(); + if !target.contains("apple-ios") && + !target.contains("solaris") && + !target.contains("redox") && + !target.contains("android") && + !target.contains("haiku") { + build.define("HAVE_DL_ITERATE_PHDR", "1"); + } + build.define("_GNU_SOURCE", "1"); + build.define("_LARGE_FILES", "1"); + + // When we're built as part of the Rust compiler, this is used to enable + // debug information in libbacktrace itself. + let any_debug = env::var("RUSTC_DEBUGINFO").unwrap_or_default() == "true" || + env::var("RUSTC_DEBUGINFO_LINES").unwrap_or_default() == "true"; + build.debug(any_debug); + + let syms = [ + "backtrace_full", + "backtrace_dwarf_add", + "backtrace_initialize", + "backtrace_pcinfo", + "backtrace_syminfo", + "backtrace_get_view", + "backtrace_release_view", + "backtrace_alloc", + "backtrace_free", + "backtrace_vector_finish", + "backtrace_vector_grow", + "backtrace_vector_release", + "backtrace_close", + "backtrace_open", + "backtrace_print", + "backtrace_simple", + "backtrace_qsort", + "backtrace_create_state", + "backtrace_uncompress_zdebug", + ]; + let prefix = if cfg!(feature = "rustc-dep-of-std") { + println!("cargo:rustc-cfg=rdos"); + "__rdos_" + } else { + println!("cargo:rustc-cfg=rbt"); + "__rbt_" + }; + for sym in syms.iter() { + build.define(sym, &format!("{}{}", prefix, sym)[..]); + } + + build.compile("backtrace"); +} diff --git a/backtrace-sys/debian/patches/remove-unneeded-dep.patch b/backtrace-sys/debian/patches/remove-unneeded-dep.patch new file mode 100644 index 000000000..57e152c78 --- /dev/null +++ b/backtrace-sys/debian/patches/remove-unneeded-dep.patch @@ -0,0 +1,22 @@ +From ac340f78a08a9a54090fdd1c9b53ddb88794d181 Mon Sep 17 00:00:00 2001 +From: Wolfgang Silbermayr +Date: Fri, 11 Jan 2019 09:45:24 +0100 +Subject: [PATCH] Remove unneeded dep + +--- + Cargo.toml | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index f47ab6d..85ca93e 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -23,5 +23,3 @@ repository = "https://github.com/alexcrichton/backtrace-rs" + [dependencies.libc] + version = "0.2" + default-features = false +-[build-dependencies.cc] +-version = "1.0" +-- +2.20.1 + diff --git a/backtrace-sys/debian/patches/series b/backtrace-sys/debian/patches/series new file mode 100644 index 000000000..58c5d72c8 --- /dev/null +++ b/backtrace-sys/debian/patches/series @@ -0,0 +1 @@ +remove-unneeded-dep.patch diff --git a/backtrace-sys/src/lib.rs b/backtrace-sys/src/lib.rs new file mode 100644 index 000000000..a3e74f3e7 --- /dev/null +++ b/backtrace-sys/src/lib.rs @@ -0,0 +1,52 @@ +#![allow(bad_style)] +#![no_std] + +extern crate libc; + +#[cfg(not(empty))] +pub use self::bindings::*; +#[cfg(not(empty))] +mod bindings { + use libc::{c_void, c_char, c_int, uintptr_t}; + + pub type backtrace_syminfo_callback = + extern fn(data: *mut c_void, + pc: uintptr_t, + symname: *const c_char, + symval: uintptr_t, + symsize: uintptr_t); + pub type backtrace_full_callback = + extern fn(data: *mut c_void, + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char) -> c_int; + pub type backtrace_error_callback = + extern fn(data: *mut c_void, + msg: *const c_char, + errnum: c_int); + pub enum backtrace_state {} + + extern "C" { + #[cfg_attr(rdos, link_name = "__rdos_backtrace_create_state")] + #[cfg_attr(rbt, link_name = "__rbt_backtrace_create_state")] + pub fn backtrace_create_state(filename: *const c_char, + threaded: c_int, + error: backtrace_error_callback, + data: *mut c_void) -> *mut backtrace_state; + #[cfg_attr(rdos, link_name = "__rdos_backtrace_syminfo")] + #[cfg_attr(rbt, link_name = "__rbt_backtrace_syminfo")] + pub fn backtrace_syminfo(state: *mut backtrace_state, + addr: uintptr_t, + cb: backtrace_syminfo_callback, + error: backtrace_error_callback, + data: *mut c_void) -> c_int; + #[cfg_attr(rdos, link_name = "__rdos_backtrace_pcinfo")] + #[cfg_attr(rbt, link_name = "__rbt_backtrace_pcinfo")] + pub fn backtrace_pcinfo(state: *mut backtrace_state, + addr: uintptr_t, + cb: backtrace_full_callback, + error: backtrace_error_callback, + data: *mut c_void) -> c_int; + } +} diff --git a/backtrace/.cargo-checksum.json b/backtrace/.cargo-checksum.json new file mode 100644 index 000000000..34e76c078 --- /dev/null +++ b/backtrace/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b"} \ No newline at end of file diff --git a/backtrace/Cargo.toml b/backtrace/Cargo.toml new file mode 100644 index 000000000..56404b5b2 --- /dev/null +++ b/backtrace/Cargo.toml @@ -0,0 +1,107 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "backtrace" +version = "0.3.26" +authors = ["Alex Crichton ", "The Rust Project Developers"] +autoexamples = true +autotests = true +description = "A library to acquire a stack trace (backtrace) at runtime in a Rust program.\n" +homepage = "https://github.com/alexcrichton/backtrace-rs" +documentation = "https://docs.rs/backtrace" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/backtrace-rs" + +[[example]] +name = "backtrace" +required-features = ["std"] + +[[example]] +name = "raw" +required-features = ["std"] + +[[test]] +name = "skip_inner_frames" +required-features = ["std"] + +[[test]] +name = "long_fn_name" +required-features = ["std"] + +[[test]] +name = "smoke" +required-features = ["std"] +edition = "2018" +[dependencies.addr2line] +version = "0.9.0" +optional = true + +[dependencies.backtrace-sys] +version = "0.1.17" +optional = true + +[dependencies.cfg-if] +version = "0.1.6" + +[dependencies.cpp_demangle] +version = "0.2.3" +optional = true +default-features = false + +[dependencies.findshlibs] +version = "0.4.1" +optional = true + +[dependencies.libc] +version = "0.2.45" +default-features = false + +[dependencies.memmap] +version = "0.7.0" +optional = true + +[dependencies.rustc-demangle] +version = "0.1.4" + +[dependencies.rustc-serialize] +version = "0.3" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true + +[dependencies.serde_derive] +version = "1.0" +optional = true +[build-dependencies.autocfg] +version = "0.1" + +[features] +coresymbolication = [] +dbghelp = [] +default = ["std", "libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"] +dladdr = [] +gimli-symbolize = ["addr2line", "findshlibs", "memmap"] +kernel32 = [] +libbacktrace = ["backtrace-sys"] +libunwind = [] +serialize-rustc = ["rustc-serialize"] +serialize-serde = ["serde", "serde_derive"] +std = [] +unix-backtrace = [] +verify-winapi = ["winapi/dbghelp", "winapi/handleapi", "winapi/libloaderapi", "winapi/minwindef", "winapi/processthreadsapi", "winapi/winbase", "winapi/winnt"] +[target."cfg(windows)".dependencies.winapi] +version = "0.3.3" +optional = true diff --git a/backtrace/LICENSE-APACHE b/backtrace/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/backtrace/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/backtrace/LICENSE-MIT b/backtrace/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/backtrace/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/backtrace/README.md b/backtrace/README.md new file mode 100644 index 000000000..465268b35 --- /dev/null +++ b/backtrace/README.md @@ -0,0 +1,83 @@ +# backtrace-rs + +[![Build Status](https://dev.azure.com/alexcrichton/backtrace-rs/_apis/build/status/alexcrichton.backtrace-rs?branchName=master)](https://dev.azure.com/alexcrichton/backtrace-rs/_build/latest?definitionId=7&branchName=master) + +[Documentation](https://docs.rs/backtrace) + +A library for acquiring backtraces at runtime for Rust. This library aims to +enhance the support of the standard library by providing a programmatic +interface to work with, but it also supports simply easily printing the current +backtrace like libstd's panics. + +## Install + +```toml +[dependencies] +backtrace = "0.3" +``` + +Note that this crate requires `cc` and `ar` to be present on Unix systems when +`libbacktrace` is used (which is the default). For configuring C compilers see +the [`cc` crate documentation](https://github.com/alexcrichton/cc-rs). + +## Usage + +To simply capture a backtrace and defer dealing with it until a later time, +you can use the top-level `Backtrace` type. + +```rust +extern crate backtrace; + +use backtrace::Backtrace; + +fn main() { + let bt = Backtrace::new(); + + // do_some_work(); + + println!("{:?}", bt); +} +``` + +If, however, you'd like more raw access to the actual tracing functionality, you +can use the `trace` and `resolve` functions directly. + +```rust +extern crate backtrace; + +fn main() { + backtrace::trace(|frame| { + let ip = frame.ip(); + let symbol_address = frame.symbol_address(); + + // Resolve this instruction pointer to a symbol name + backtrace::resolve_frame(frame, |symbol| { + if let Some(name) = symbol.name() { + // ... + } + if let Some(filename) = symbol.filename() { + // ... + } + }); + + true // keep going to the next frame + }); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in backtrace-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/backtrace/azure-pipelines.yml b/backtrace/azure-pipelines.yml new file mode 100644 index 000000000..2f9266bc1 --- /dev/null +++ b/backtrace/azure-pipelines.yml @@ -0,0 +1,158 @@ +trigger: + - master + +jobs: + - job: MSRV + pool: + vmImage: ubuntu-16.04 + steps: + - checkout: self + submodules: true + - template: ci/azure-install-rust.yml + - script: cargo build + displayName: "Build crate" + variables: + TOOLCHAIN: 1.32.0 + + - job: Docker + pool: + vmImage: ubuntu-16.04 + steps: + - checkout: self + submodules: true + - template: ci/azure-install-rust.yml + - bash: rustup target add $TARGET + displayName: "Install rust cross target" + - bash: | + set -e + cargo generate-lockfile + ./ci/run-docker.sh $TARGET + displayName: "Run tests in docker" + strategy: + matrix: + aarch64: + TARGET: aarch64-unknown-linux-gnu + armhv: + TARGET: arm-unknown-linux-gnueabihf + armv7: + TARGET: armv7-unknown-linux-gnueabihf + i586: + TARGET: i586-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + powerpc64: + TARGET: powerpc64-unknown-linux-gnu + mingw: + TARGET: x86_64-pc-windows-gnu + x86_64: + TARGET: x86_64-unknown-linux-gnu + gnu: + TARGET: x86_64-unknown-linux-musl + + android-arm: + TARGET: arm-linux-androideabi + android-armv7: + TARGET: armv7-linux-androideabi + android-aarch64: + TARGET: aarch64-linux-android + android-i686: + TARGET: i686-linux-android + android-x86_64: + TARGET: x86_64-linux-android + + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-test-all.yml + strategy: + matrix: + stable: + TOOLCHAIN: stable + beta: + TOOLCHAIN: beta + nightly: + TOOLCHAIN: nightly + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-test-all.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-apple-darwin + + - job: iOS + pool: + vmImage: macos-10.13 + steps: + - checkout: self + submodules: true + - template: ci/azure-install-rust.yml + - script: rustup target add $TARGET + displayName: "Install rust cross target" + - bash: | + set -e + export SDK_PATH=`xcrun --show-sdk-path --sdk $SDK` + export RUSTFLAGS="-C link-arg=-isysroot -C link-arg=$SDK_PATH" + cargo test --no-run --target $TARGET + displayName: "Build for iOS" + strategy: + matrix: + aarch64: + TARGET: aarch64-apple-ios + SDK: iphoneos + armv7: + TARGET: armv7-apple-ios + SDK: iphoneos + armv7s: + TARGET: armv7s-apple-ios + SDK: iphoneos + i386: + TARGET: i386-apple-ios + SDK: iphonesimulator + x86_64: + TARGET: x86_64-apple-ios + SDK: iphonesimulator + + - job: wasm + pool: + vmImage: ubuntu-16.04 + steps: + - checkout: self + submodules: true + - template: ci/azure-install-rust.yml + - script: rustup target add wasm32-unknown-unknown + displayName: "Install rust cross target" + - script: cargo build --target wasm32-unknown-unknown + displayName: "Build for wasm" + + - job: Windows + pool: + vmImage: vs2017-win2016 + steps: + - template: ci/azure-test-all.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-msvc: + TARGET: i686-pc-windows-msvc + x86_64-gnu: + TARGET: x86_64-pc-windows-gnu + i686-gnu: + TARGET: i686-pc-windows-gnu + + - job: Windows_arm64 + pool: + vmImage: windows-2019 + steps: + - template: ci/azure-install-rust.yml + - script: rustup target add aarch64-pc-windows-msvc + displayName: "Install rust cross target" + - script: cargo test --no-run --target aarch64-pc-windows-msvc + displayName: "Build for arm64" + - script: cargo test --no-run --target aarch64-pc-windows-msvc --features verify-winapi + displayName: "Build for arm64" diff --git a/backtrace/benches/benchmarks.rs b/backtrace/benches/benchmarks.rs new file mode 100644 index 000000000..ad55788c2 --- /dev/null +++ b/backtrace/benches/benchmarks.rs @@ -0,0 +1,94 @@ +#![feature(test)] + +extern crate test; + +extern crate backtrace; + +#[cfg(feature = "std")] +use backtrace::Backtrace; + +#[bench] +#[cfg(feature = "std")] +fn trace(b: &mut test::Bencher) { + #[inline(never)] + fn the_function() { + backtrace::trace(|frame| { + let ip = frame.ip(); + test::black_box(ip); + true + }); + } + b.iter(the_function); +} + +#[bench] +#[cfg(feature = "std")] +fn trace_and_resolve_callback(b: &mut test::Bencher) { + #[inline(never)] + fn the_function() { + backtrace::trace(|frame| { + backtrace::resolve(frame.ip(), |symbol| { + let addr = symbol.addr(); + test::black_box(addr); + }); + true + }); + } + b.iter(the_function); +} + +#[bench] +#[cfg(feature = "std")] +fn trace_and_resolve_separate(b: &mut test::Bencher) { + #[inline(never)] + fn the_function(frames: &mut Vec<*mut std::ffi::c_void>) { + backtrace::trace(|frame| { + frames.push(frame.ip()); + true + }); + frames.iter().for_each(|frame_ip| { + backtrace::resolve(*frame_ip, |symbol| { + test::black_box(symbol); + }); + }); + } + let mut frames = Vec::with_capacity(1024); + b.iter(|| { + the_function(&mut frames); + frames.clear(); + }); +} + +#[bench] +#[cfg(feature = "std")] +fn new_unresolved(b: &mut test::Bencher) { + #[inline(never)] + fn the_function() { + let bt = Backtrace::new_unresolved(); + test::black_box(bt); + } + b.iter(the_function); +} + +#[bench] +#[cfg(feature = "std")] +fn new(b: &mut test::Bencher) { + #[inline(never)] + fn the_function() { + let bt = Backtrace::new(); + test::black_box(bt); + } + b.iter(the_function); +} + +#[bench] +#[cfg(feature = "std")] +fn new_unresolved_and_resolve_separate(b: &mut test::Bencher) { + #[inline(never)] + fn the_function() { + let mut bt = Backtrace::new_unresolved(); + bt.resolve(); + test::black_box(bt); + } + b.iter(the_function); +} diff --git a/backtrace/build.rs b/backtrace/build.rs new file mode 100644 index 000000000..a648ea1ce --- /dev/null +++ b/backtrace/build.rs @@ -0,0 +1,13 @@ +extern crate autocfg; + +fn main() { + let ac = autocfg::new(); + + // ffi types moved from `std` to `core` in Rust 1.30, so we need to adjust imports based on + // this. + // + // + ac.emit_rustc_version(1, 30); + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/backtrace/ci/android-ndk.sh b/backtrace/ci/android-ndk.sh new file mode 100755 index 000000000..b5df62b6f --- /dev/null +++ b/backtrace/ci/android-ndk.sh @@ -0,0 +1,23 @@ +set -ex + +ANDROID_ARCH=$1 +ANDROID_SDK_VERSION=4333796 + +mkdir /tmp/android +cd /tmp/android + +curl -o android-sdk.zip \ + "https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_VERSION}.zip" +unzip -q android-sdk.zip + +yes | ./tools/bin/sdkmanager --licenses > /dev/null +./tools/bin/sdkmanager ndk-bundle > /dev/null + +./ndk-bundle/build/tools/make_standalone_toolchain.py \ + --arch $ANDROID_ARCH \ + --stl=libc++ \ + --api 21 \ + --install-dir /android-toolchain + +cd /tmp +rm -rf android diff --git a/backtrace/ci/azure-install-rust.yml b/backtrace/ci/azure-install-rust.yml new file mode 100644 index 000000000..fa7eae459 --- /dev/null +++ b/backtrace/ci/azure-install-rust.yml @@ -0,0 +1,23 @@ +steps: + - bash: | + set -e + toolchain=$TOOLCHAIN + if [ "$toolchain" = "" ]; then + toolchain=stable + fi + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.prependpath]$HOME/.cargo/bin" + displayName: Install rust (unix) + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain stable-%TARGET% + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + displayName: Install rust (windows) + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/backtrace/ci/azure-test-all.yml b/backtrace/ci/azure-test-all.yml new file mode 100644 index 000000000..6f2d192be --- /dev/null +++ b/backtrace/ci/azure-test-all.yml @@ -0,0 +1,43 @@ +steps: + - checkout: self + submodules: true + - template: azure-install-rust.yml + + - bash: cargo build --manifest-path backtrace-sys/Cargo.toml + displayName: "Build backtrace-sys" + - bash: cargo build + displayName: "Build backtrace" + - bash: cargo test + displayName: "Test backtrace" + - bash: cargo test --no-default-features + displayName: "Test backtrace (-default)" + - bash: cargo test --no-default-features --features 'std' + displayName: "Test backtrace (-default + std)" + - bash: cargo test --no-default-features --features 'libunwind std' + displayName: "Test backtrace (-default + libunwind)" + - bash: cargo test --no-default-features --features 'libunwind dladdr std' + displayName: "Test backtrace (-default + libunwind + dladdr)" + - bash: cargo test --no-default-features --features 'libunwind libbacktrace std' + displayName: "Test backtrace (-default + libunwind + libbacktrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace std' + displayName: "Test backtrace (-default + unix-backtrace)" + - bash: cargo test --no-default-features --features 'unix-backtrace dladdr std' + displayName: "Test backtrace (-default + unix-backtrace + dladdr)" + - bash: cargo test --no-default-features --features 'unix-backtrace libbacktrace std' + displayName: "Test backtrace (-default + unix-backtrace + libbacktrace)" + - bash: cargo test --no-default-features --features 'serialize-serde std' + displayName: "Test backtrace (-default + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc std' + displayName: "Test backtrace (-default + serialize-rustc + std)" + - bash: cargo test --no-default-features --features 'serialize-rustc serialize-serde std' + displayName: "Test backtrace (-default + serialize-rustc + serialize-serde + std)" + - bash: cargo test --no-default-features --features 'cpp_demangle std' + displayName: "Test backtrace (-default + cpp_demangle + std)" + - bash: cargo test --no-default-features --features 'gimli-symbolize std' + displayName: "Test backtrace (-default + gimli-symbolize + std)" + - bash: cargo test --no-default-features --features 'dbghelp std' + displayName: "Test backtrace (-default + dbghelp + std)" + - bash: cargo test --no-default-features --features 'dbghelp std verify-winapi' + displayName: "Test backtrace (-default + dbghelp + std + verify-winapi)" + - bash: cd ./cpp_smoke_test && cargo test + displayName: "Test cpp_smoke_test" diff --git a/backtrace/ci/docker/aarch64-linux-android/Dockerfile b/backtrace/ci/docker/aarch64-linux-android/Dockerfile new file mode 100644 index 000000000..b9026c06c --- /dev/null +++ b/backtrace/ci/docker/aarch64-linux-android/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + openjdk-8-jre \ + python \ + gcc \ + libc6-dev + +COPY android-ndk.sh / +RUN /android-ndk.sh arm64 +ENV PATH=$PATH:/android-toolchain/bin + +# TODO: run tests in an emulator eventually +ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android-gcc \ + CARGO_TARGET_AARCH64_LINUX_ANDROID_RUNNER="true" diff --git a/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000..d691aa46e --- /dev/null +++ b/backtrace/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + ca-certificates \ + libc6-dev \ + gcc-aarch64-linux-gnu \ + libc6-dev-arm64-cross \ + qemu-user + +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" diff --git a/backtrace/ci/docker/arm-linux-androideabi/Dockerfile b/backtrace/ci/docker/arm-linux-androideabi/Dockerfile new file mode 100644 index 000000000..10799974e --- /dev/null +++ b/backtrace/ci/docker/arm-linux-androideabi/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + openjdk-8-jre \ + python \ + gcc \ + libc6-dev + +COPY android-ndk.sh / +RUN /android-ndk.sh arm +ENV PATH=$PATH:/android-toolchain/bin + +# TODO: run tests in an emulator eventually +ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \ + CARGO_TARGET_ARM_LINUX_ANDROIDEABI_RUNNER="true" diff --git a/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 000000000..32095e98f --- /dev/null +++ b/backtrace/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + ca-certificates \ + libc6-dev \ + gcc-arm-linux-gnueabihf \ + libc6-dev-armhf-cross \ + qemu-user +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" diff --git a/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile b/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile new file mode 100644 index 000000000..9696677ed --- /dev/null +++ b/backtrace/ci/docker/armv7-linux-androideabi/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + openjdk-8-jre \ + python \ + gcc \ + libc6-dev + +COPY android-ndk.sh / +RUN /android-ndk.sh arm +ENV PATH=$PATH:/android-toolchain/bin + +# TODO: run tests in an emulator eventually +ENV CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \ + CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_RUNNER="true" diff --git a/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 000000000..a55fb2792 --- /dev/null +++ b/backtrace/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + ca-certificates \ + libc6-dev \ + gcc-arm-linux-gnueabihf \ + libc6-dev-armhf-cross \ + qemu-user +ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER="qemu-arm -L /usr/arm-linux-gnueabihf" diff --git a/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile b/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000..d22209295 --- /dev/null +++ b/backtrace/ci/docker/i586-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc-multilib \ + libc6-dev \ + ca-certificates diff --git a/backtrace/ci/docker/i686-linux-android/Dockerfile b/backtrace/ci/docker/i686-linux-android/Dockerfile new file mode 100644 index 000000000..c4946ad1d --- /dev/null +++ b/backtrace/ci/docker/i686-linux-android/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + openjdk-8-jre \ + python \ + gcc \ + libc6-dev + +COPY android-ndk.sh / +RUN /android-ndk.sh x86 +ENV PATH=$PATH:/android-toolchain/bin + +# TODO: run tests in an emulator eventually +ENV CARGO_TARGET_I686_LINUX_ANDROID_LINKER=i686-linux-android-gcc \ + CARGO_TARGET_I686_LINUX_ANDROID_RUNNER="true" diff --git a/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile b/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000..d22209295 --- /dev/null +++ b/backtrace/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc-multilib \ + libc6-dev \ + ca-certificates diff --git a/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000..5e22a9f7c --- /dev/null +++ b/backtrace/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + ca-certificates \ + libc6-dev \ + gcc-powerpc64-linux-gnu \ + libc6-dev-ppc64-cross \ + qemu-user \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + # TODO: should actually run these tests + #CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER="qemu-ppc64 -L /usr/powerpc64-linux-gnu" \ + CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_RUNNER=true \ + CC=powerpc64-linux-gnu-gcc diff --git a/backtrace/ci/docker/x86_64-linux-android/Dockerfile b/backtrace/ci/docker/x86_64-linux-android/Dockerfile new file mode 100644 index 000000000..6ed4a65db --- /dev/null +++ b/backtrace/ci/docker/x86_64-linux-android/Dockerfile @@ -0,0 +1,18 @@ +FROM ubuntu:18.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + unzip \ + openjdk-8-jre \ + python \ + gcc \ + libc6-dev + +COPY android-ndk.sh / +RUN /android-ndk.sh x86_64 +ENV PATH=$PATH:/android-toolchain/bin + +# TODO: run tests in an emulator eventually +ENV CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER=x86_64-linux-android-gcc \ + CARGO_TARGET_X86_64_LINUX_ANDROID_RUNNER="true" diff --git a/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile b/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile new file mode 100644 index 000000000..48db21980 --- /dev/null +++ b/backtrace/ci/docker/x86_64-pc-windows-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libc6-dev \ + ca-certificates \ + gcc-mingw-w64-x86-64 + +# No need to run tests, we're just testing that it compiles +ENV CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER=true \ + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc diff --git a/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000..864d72e62 --- /dev/null +++ b/backtrace/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libc6-dev \ + ca-certificates diff --git a/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile b/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile new file mode 100644 index 000000000..6984dc217 --- /dev/null +++ b/backtrace/ci/docker/x86_64-unknown-linux-musl/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:18.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libc6-dev \ + ca-certificates \ + musl-tools diff --git a/backtrace/ci/run-docker.sh b/backtrace/ci/run-docker.sh new file mode 100755 index 000000000..abce99e70 --- /dev/null +++ b/backtrace/ci/run-docker.sh @@ -0,0 +1,32 @@ +# Small script to run tests for a target (or all targets) inside all the +# respective docker images. + +set -ex + +run() { + docker build -t backtrace -f ci/docker/$1/Dockerfile ci + mkdir -p target + docker run \ + --user `id -u`:`id -g` \ + --rm \ + --init \ + --volume $HOME/.cargo:/cargo \ + --env CARGO_HOME=/cargo \ + --volume `rustc --print sysroot`:/rust:ro \ + --env TARGET=$1 \ + --volume `pwd`:/checkout:ro \ + --volume `pwd`/target:/checkout/target \ + --workdir /checkout \ + --privileged \ + backtrace \ + bash \ + -c 'PATH=$PATH:/rust/bin exec ci/run.sh' +} + +if [ -z "$1" ]; then + for d in `ls ci/docker/`; do + run $d + done +else + run $1 +fi diff --git a/backtrace/ci/run.sh b/backtrace/ci/run.sh new file mode 100755 index 000000000..5cc151507 --- /dev/null +++ b/backtrace/ci/run.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +set -ex + +cargo test --target $TARGET diff --git a/backtrace/examples/backtrace.rs b/backtrace/examples/backtrace.rs new file mode 100644 index 000000000..7f9042ed7 --- /dev/null +++ b/backtrace/examples/backtrace.rs @@ -0,0 +1,7 @@ +extern crate backtrace; + +use backtrace::Backtrace; + +fn main() { + println!("{:?}", Backtrace::new()); +} diff --git a/backtrace/examples/raw.rs b/backtrace/examples/raw.rs new file mode 100644 index 000000000..b43cab8ba --- /dev/null +++ b/backtrace/examples/raw.rs @@ -0,0 +1,54 @@ +extern crate backtrace; + +fn main() { + foo(); +} + +fn foo() { + bar() +} +fn bar() { + baz() +} +fn baz() { + print() +} + +#[cfg(target_pointer_width = "32")] +const HEX_WIDTH: usize = 10; +#[cfg(target_pointer_width = "64")] +const HEX_WIDTH: usize = 20; + +fn print() { + let mut cnt = 0; + backtrace::trace(|frame| { + let ip = frame.ip(); + print!("frame #{:<2} - {:#02$x}", cnt, ip as usize, HEX_WIDTH); + cnt += 1; + + let mut resolved = false; + backtrace::resolve(frame.ip(), |symbol| { + if !resolved { + resolved = true; + } else { + print!("{}", vec![" "; 7 + 2 + 3 + HEX_WIDTH].join("")); + } + + if let Some(name) = symbol.name() { + print!(" - {}", name); + } else { + print!(" - "); + } + if let Some(file) = symbol.filename() { + if let Some(l) = symbol.lineno() { + print!("\n{:13}{:4$}@ {}:{}", "", "", file.display(), l, HEX_WIDTH); + } + } + println!(""); + }); + if !resolved { + println!(" - "); + } + true // keep going + }); +} diff --git a/backtrace/src/backtrace/dbghelp.rs b/backtrace/src/backtrace/dbghelp.rs new file mode 100644 index 000000000..57f18b20d --- /dev/null +++ b/backtrace/src/backtrace/dbghelp.rs @@ -0,0 +1,207 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Backtrace strategy for MSVC platforms. +//! +//! This module contains the ability to generate a backtrace on MSVC using one +//! of two possible methods. The `StackWalkEx` function is primarily used if +//! possible, but not all systems have that. Failing that the `StackWalk64` +//! function is used instead. Note that `StackWalkEx` is favored because it +//! handles debuginfo internally and returns inline frame information. +//! +//! Note that all dbghelp support is loaded dynamically, see `src/dbghelp.rs` +//! for more information about that. + +#![allow(bad_style)] + +use core::mem; +use core::prelude::v1::*; + +use dbghelp; +use windows::*; +use types::c_void; + +#[derive(Clone, Copy)] +pub enum Frame { + New(STACKFRAME_EX), + Old(STACKFRAME64), +} + +// we're just sending around raw pointers and reading them, never interpreting +// them so this should be safe to both send and share across threads. +unsafe impl Send for Frame {} +unsafe impl Sync for Frame {} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + self.addr_pc().Offset as *mut _ + } + + pub fn symbol_address(&self) -> *mut c_void { + self.ip() + } + + fn addr_pc(&self) -> &ADDRESS64 { + match self { + Frame::New(new) => &new.AddrPC, + Frame::Old(old) => &old.AddrPC, + } + } + + fn addr_pc_mut(&mut self) -> &mut ADDRESS64 { + match self { + Frame::New(new) => &mut new.AddrPC, + Frame::Old(old) => &mut old.AddrPC, + } + } + + fn addr_frame_mut(&mut self) -> &mut ADDRESS64 { + match self { + Frame::New(new) => &mut new.AddrFrame, + Frame::Old(old) => &mut old.AddrFrame, + } + } + + fn addr_stack_mut(&mut self) -> &mut ADDRESS64 { + match self { + Frame::New(new) => &mut new.AddrStack, + Frame::Old(old) => &mut old.AddrStack, + } + } +} + +#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now +struct MyContext(CONTEXT); + +#[inline(always)] +pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) { + // Allocate necessary structures for doing the stack walk + let process = GetCurrentProcess(); + let thread = GetCurrentThread(); + + let mut context = mem::zeroed::(); + RtlCaptureContext(&mut context.0); + + // Ensure this process's symbols are initialized + let dbghelp = match dbghelp::init() { + Ok(dbghelp) => dbghelp, + Err(()) => return, // oh well... + }; + + // Attempt to use `StackWalkEx` if we can, but fall back to `StackWalk64` + // since it's in theory supported on more systems. + match (*dbghelp.dbghelp()).StackWalkEx() { + Some(StackWalkEx) => { + let mut frame = super::Frame { + inner: Frame::New(mem::zeroed()), + }; + let image = init_frame(&mut frame.inner, &context.0); + let frame_ptr = match &mut frame.inner { + Frame::New(ptr) => ptr as *mut STACKFRAME_EX, + _ => unreachable!(), + }; + + while StackWalkEx( + image as DWORD, + process, + thread, + frame_ptr, + &mut context.0 as *mut CONTEXT as *mut _, + None, + Some(dbghelp.SymFunctionTableAccess64()), + Some(dbghelp.SymGetModuleBase64()), + None, + 0, + ) == TRUE + { + if !cb(&frame) { + break; + } + } + } + None => { + let mut frame = super::Frame { + inner: Frame::Old(mem::zeroed()), + }; + let image = init_frame(&mut frame.inner, &context.0); + let frame_ptr = match &mut frame.inner { + Frame::Old(ptr) => ptr as *mut STACKFRAME64, + _ => unreachable!(), + }; + + while dbghelp.StackWalk64()( + image as DWORD, + process, + thread, + frame_ptr, + &mut context.0 as *mut CONTEXT as *mut _, + None, + Some(dbghelp.SymFunctionTableAccess64()), + Some(dbghelp.SymGetModuleBase64()), + None, + ) == TRUE + { + if !cb(&frame) { + break; + } + } + } + } +} + +#[cfg(target_arch = "x86_64")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Rip as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Rsp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + frame.addr_frame_mut().Offset = ctx.Rbp as u64; + frame.addr_frame_mut().Mode = AddrModeFlat; + + IMAGE_FILE_MACHINE_AMD64 +} + +#[cfg(target_arch = "x86")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Eip as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Esp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + frame.addr_frame_mut().Offset = ctx.Ebp as u64; + frame.addr_frame_mut().Mode = AddrModeFlat; + + IMAGE_FILE_MACHINE_I386 +} + +#[cfg(target_arch = "aarch64")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Pc as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Sp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + unsafe { + frame.addr_frame_mut().Offset = ctx.u.s().Fp as u64; + } + frame.addr_frame_mut().Mode = AddrModeFlat; + IMAGE_FILE_MACHINE_ARM64 +} + +#[cfg(target_arch = "arm")] +fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD { + frame.addr_pc_mut().Offset = ctx.Pc as u64; + frame.addr_pc_mut().Mode = AddrModeFlat; + frame.addr_stack_mut().Offset = ctx.Sp as u64; + frame.addr_stack_mut().Mode = AddrModeFlat; + unsafe { + frame.addr_frame_mut().Offset = ctx.R11 as u64; + } + frame.addr_frame_mut().Mode = AddrModeFlat; + IMAGE_FILE_MACHINE_ARMNT +} diff --git a/backtrace/src/backtrace/libunwind.rs b/backtrace/src/backtrace/libunwind.rs new file mode 100644 index 000000000..f1e35a42e --- /dev/null +++ b/backtrace/src/backtrace/libunwind.rs @@ -0,0 +1,248 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Backtrace support using libunwind/gcc_s/etc APIs. +//! +//! This module contains the ability to unwind the stack using libunwind-style +//! APIs. Note that there's a whole bunch of implementations of the +//! libunwind-like API, and this is just trying to be compatible with most of +//! them all at once instead of being picky. +//! +//! The libunwind API is powered by `_Unwind_Backtrace` and is in practice very +//! reliable at generating a backtrace. It's not entirely clear how it does it +//! (frame pointers? eh_frame info? both?) but it seems to work! +//! +//! Most of the complexity of this module is handling the various platform +//! differences across libunwind implementations. Otherwise this is a pretty +//! straightforward Rust binding to the libunwind APIs. +//! +//! This is the default unwinding API for all non-Windows platforms currently. + +use types::c_void; + +pub enum Frame { + Raw(*mut uw::_Unwind_Context), + Cloned { + ip: *mut c_void, + symbol_address: *mut c_void, + }, +} + +// With a raw libunwind pointer it should only ever be access in a readonly +// threadsafe fashion, so it's `Sync`. When sending to other threads via `Clone` +// we always switch to a version which doesn't retain interior pointers, so we +// should be `Send` as well. +unsafe impl Send for Frame {} +unsafe impl Sync for Frame {} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + let ctx = match *self { + Frame::Raw(ctx) => ctx, + Frame::Cloned { ip, .. } => return ip, + }; + let mut ip_before_insn = 0; + let mut ip = unsafe { + uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut c_void + }; + if !ip.is_null() && ip_before_insn == 0 { + // this is a non-signaling frame, so `ip` refers to the address + // after the calling instruction. account for that. + ip = (ip as usize - 1) as *mut _; + } + return ip + } + + pub fn symbol_address(&self) -> *mut c_void { + if let Frame::Cloned { symbol_address, .. } = *self { + return symbol_address; + } + + // dladdr() on osx gets whiny when we use FindEnclosingFunction, and + // it appears to work fine without it, so we only use + // FindEnclosingFunction on non-osx platforms. In doing so, we get a + // slightly more accurate stack trace in the process. + // + // This is often because panic involves the last instruction of a + // function being "call std::rt::begin_unwind", with no ret + // instructions after it. This means that the return instruction + // pointer points *outside* of the calling function, and by + // unwinding it we go back to the original function. + if cfg!(target_os = "macos") || cfg!(target_os = "ios") { + self.ip() + } else { + unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) } + } + } +} + +impl Clone for Frame { + fn clone(&self) -> Frame { + Frame::Cloned { + ip: self.ip(), + symbol_address: self.symbol_address(), + } + } +} + +#[inline(always)] +pub unsafe fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) { + uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _); + + extern fn trace_fn(ctx: *mut uw::_Unwind_Context, + arg: *mut c_void) -> uw::_Unwind_Reason_Code { + let cb = unsafe { &mut *(arg as *mut &mut FnMut(&super::Frame) -> bool) }; + let cx = super::Frame { + inner: Frame::Raw(ctx), + }; + + let mut bomb = ::Bomb { enabled: true }; + let keep_going = cb(&cx); + bomb.enabled = false; + + if keep_going { + uw::_URC_NO_REASON + } else { + uw::_URC_FAILURE + } + } +} + +/// Unwind library interface used for backtraces +/// +/// Note that dead code is allowed as here are just bindings +/// iOS doesn't use all of them it but adding more +/// platform-specific configs pollutes the code too much +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(dead_code)] +mod uw { + pub use self::_Unwind_Reason_Code::*; + + use libc::{self, c_int}; + use types::c_void; + + #[repr(C)] + pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EABI + } + + pub enum _Unwind_Context {} + + pub type _Unwind_Trace_Fn = + extern fn(ctx: *mut _Unwind_Context, + arg: *mut c_void) -> _Unwind_Reason_Code; + + extern { + // No native _Unwind_Backtrace on iOS + #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut c_void) + -> _Unwind_Reason_Code; + + // available since GCC 4.2.0, should be fine for our purpose + #[cfg(all(not(all(target_os = "android", target_arch = "arm")), + not(all(target_os = "freebsd", target_arch = "arm")), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> libc::uintptr_t; + + #[cfg(all(not(target_os = "android"), + not(all(target_os = "freebsd", target_arch = "arm")), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) + -> *mut c_void; + } + + // On android, the function _Unwind_GetIP is a macro, and this is the + // expansion of the macro. This is all copy/pasted directly from the + // header file with the definition of _Unwind_GetIP. + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "freebsd", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + + type _Unwind_Word = libc::c_uint; + extern { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + klass: _Unwind_VRS_RegClass, + word: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + } + + let mut val: _Unwind_Word = 0; + let ptr = &mut val as *mut _Unwind_Word; + let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15, + _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, + ptr as *mut c_void); + (val & !1) as libc::uintptr_t + } + + // This function doesn't exist on Android or ARM/Linux, so make it same + // to _Unwind_GetIP + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "freebsd", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> libc::uintptr_t + { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } + + // This function also doesn't exist on Android or ARM/Linux, so make it + // a no-op + #[cfg(any(target_os = "android", + all(target_os = "freebsd", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) + -> *mut c_void + { + pc + } +} + + diff --git a/backtrace/src/backtrace/mod.rs b/backtrace/src/backtrace/mod.rs new file mode 100644 index 000000000..a8f335984 --- /dev/null +++ b/backtrace/src/backtrace/mod.rs @@ -0,0 +1,139 @@ +use core::fmt; +use types::c_void; + +/// Inspects the current call-stack, passing all active frames into the closure +/// provided to calculate a stack trace. +/// +/// This function is the workhorse of this library in calculating the stack +/// traces for a program. The given closure `cb` is yielded instances of a +/// `Frame` which represent information about that call frame on the stack. The +/// closure is yielded frames in a top-down fashion (most recently called +/// functions first). +/// +/// The closure's return value is an indication of whether the backtrace should +/// continue. A return value of `false` will terminate the backtrace and return +/// immediately. +/// +/// Once a `Frame` is acquired you will likely want to call `backtrace::resolve` +/// to convert the `ip` (instruction pointer) or symbol address to a `Symbol` +/// through which the name and/or filename/line number can be learned. +/// +/// Note that this is a relatively low-level function and if you'd like to, for +/// example, capture a backtrace to be inspected later, then the `Backtrace` +/// type may be more appropriate. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +/// +/// # Panics +/// +/// This function strives to never panic, but if the `cb` provided panics then +/// some platforms will force a double panic to abort the process. Some +/// platforms use a C library which internally uses callbacks which cannot be +/// unwound through, so panicking from `cb` may trigger a process abort. +/// +/// # Example +/// +/// ``` +/// extern crate backtrace; +/// +/// fn main() { +/// backtrace::trace(|frame| { +/// // ... +/// +/// true // continue the backtrace +/// }); +/// } +/// ``` +#[cfg(feature = "std")] +pub fn trace bool>(cb: F) { + let _guard = ::lock::lock(); + unsafe { trace_unsynchronized(cb) } +} + +/// Same as `trace`, only unsafe as it's unsynchronized. +/// +/// This function does not have synchronization guarentees but is available +/// when the `std` feature of this crate isn't compiled in. See the `trace` +/// function for more documentation and examples. +/// +/// # Panics +/// +/// See information on `trace` for caveats on `cb` panicking. +pub unsafe fn trace_unsynchronized bool>(mut cb: F) { + trace_imp(&mut cb) +} + +/// A trait representing one frame of a backtrace, yielded to the `trace` +/// function of this crate. +/// +/// The tracing function's closure will be yielded frames, and the frame is +/// virtually dispatched as the underlying implementation is not always known +/// until runtime. +#[derive(Clone)] +pub struct Frame { + pub(crate) inner: FrameImp, +} + +impl Frame { + /// Returns the current instruction pointer of this frame. + /// + /// This is normally the next instruction to execute in the frame, but not + /// all implementations list this with 100% accuracy (but it's generally + /// pretty close). + /// + /// It is recommended to pass this value to `backtrace::resolve` to turn it + /// into a symbol name. + pub fn ip(&self) -> *mut c_void { + self.inner.ip() + } + + /// Returns the starting symbol address of the frame of this function. + /// + /// This will attempt to rewind the instruction pointer returned by `ip` to + /// the start of the function, returning that value. In some cases, however, + /// backends will just return `ip` from this function. + /// + /// The returned value can sometimes be used if `backtrace::resolve` failed + /// on the `ip` given above. + pub fn symbol_address(&self) -> *mut c_void { + self.inner.symbol_address() + } +} + +impl fmt::Debug for Frame { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Frame") + .field("ip", &self.ip()) + .field("symbol_address", &self.symbol_address()) + .finish() + } +} + +cfg_if! { + if #[cfg(any(all(unix, + not(target_os = "emscripten"), + not(all(target_os = "ios", target_arch = "arm")), + feature = "libunwind"), + target_env="sgx"))] { + mod libunwind; + use self::libunwind::trace as trace_imp; + pub(crate) use self::libunwind::Frame as FrameImp; + } else if #[cfg(all(unix, + not(target_os = "emscripten"), + feature = "unix-backtrace"))] { + mod unix_backtrace; + use self::unix_backtrace::trace as trace_imp; + pub(crate) use self::unix_backtrace::Frame as FrameImp; + } else if #[cfg(all(windows, feature = "dbghelp"))] { + mod dbghelp; + use self::dbghelp::trace as trace_imp; + pub(crate) use self::dbghelp::Frame as FrameImp; + } else { + mod noop; + use self::noop::trace as trace_imp; + pub(crate) use self::noop::Frame as FrameImp; + } +} diff --git a/backtrace/src/backtrace/noop.rs b/backtrace/src/backtrace/noop.rs new file mode 100644 index 000000000..0c9069197 --- /dev/null +++ b/backtrace/src/backtrace/noop.rs @@ -0,0 +1,20 @@ +//! Empty implementation of unwinding used when no other implementation is +//! appropriate. + +use types::c_void; + +#[inline(always)] +pub fn trace(_cb: &mut FnMut(&super::Frame) -> bool) {} + +#[derive(Clone)] +pub struct Frame; + +impl Frame { + pub fn ip(&self) -> *mut c_void { + 0 as *mut _ + } + + pub fn symbol_address(&self) -> *mut c_void { + 0 as *mut _ + } +} diff --git a/backtrace/src/backtrace/unix_backtrace.rs b/backtrace/src/backtrace/unix_backtrace.rs new file mode 100644 index 000000000..ca8b44651 --- /dev/null +++ b/backtrace/src/backtrace/unix_backtrace.rs @@ -0,0 +1,62 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unwinding through the `backtrace` function provided in Unix. +//! +//! This is an alternative unwinding strategy for Unix platforms which don't +//! have support for libunwind but do have support for `backtrace`. Currently +//! there's not a whole lot of those though. This module is a relatively +//! straightforward binding of the `backtrace` API to the `Frame` API that we'd +//! like to have. + +use core::mem; +use libc::c_int; + +use types::c_void; + +#[derive(Clone)] +pub struct Frame { + addr: usize, +} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + self.addr as *mut c_void + } + pub fn symbol_address(&self) -> *mut c_void { + self.ip() + } +} + +extern "C" { + fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int; +} + +#[inline(always)] +pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) { + const SIZE: usize = 100; + + let mut buf: [*mut c_void; SIZE]; + let cnt; + + buf = mem::zeroed(); + cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int); + + for addr in buf[..cnt as usize].iter() { + let cx = super::Frame { + inner: Frame { + addr: *addr as usize, + }, + }; + if !cb(&cx) { + return; + } + } +} diff --git a/backtrace/src/capture.rs b/backtrace/src/capture.rs new file mode 100644 index 000000000..24aeef118 --- /dev/null +++ b/backtrace/src/capture.rs @@ -0,0 +1,554 @@ +use std::fmt; +use std::path::{Path, PathBuf}; +use std::prelude::v1::*; + +use types::c_void; +use {resolve, resolve_frame, trace, Symbol, SymbolName}; + +/// Representation of an owned and self-contained backtrace. +/// +/// This structure can be used to capture a backtrace at various points in a +/// program and later used to inspect what the backtrace was at that time. +/// +/// `Backtrace` supports pretty-printing of backtraces through its `Debug` +/// implementation. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +#[derive(Clone)] +#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))] +pub struct Backtrace { + // Frames here are listed from top-to-bottom of the stack + frames: Vec, + // The index we believe is the actual start of the backtrace, omitting + // frames like `Backtrace::new` and `backtrace::trace`. + actual_start_index: usize, +} + +fn _assert_send_sync() { + fn _assert() {} + _assert::(); +} + +/// Captured version of a frame in a backtrace. +/// +/// This type is returned as a list from `Backtrace::frames` and represents one +/// stack frame in a captured backtrace. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +#[derive(Clone)] +pub struct BacktraceFrame { + frame: Frame, + symbols: Option>, +} + +#[derive(Clone)] +enum Frame { + Raw(::Frame), + #[allow(dead_code)] + Deserialized { + ip: usize, + symbol_address: usize, + }, +} + +impl Frame { + fn ip(&self) -> *mut c_void { + match *self { + Frame::Raw(ref f) => f.ip(), + Frame::Deserialized { ip, .. } => ip as *mut c_void, + } + } + + fn symbol_address(&self) -> *mut c_void { + match *self { + Frame::Raw(ref f) => f.symbol_address(), + Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void, + } + } +} + +/// Captured version of a symbol in a backtrace. +/// +/// This type is returned as a list from `BacktraceFrame::symbols` and +/// represents the metadata for a symbol in a backtrace. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +#[derive(Clone)] +#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))] +pub struct BacktraceSymbol { + name: Option>, + addr: Option, + filename: Option, + lineno: Option, +} + +impl Backtrace { + /// Captures a backtrace at the callsite of this function, returning an + /// owned representation. + /// + /// This function is useful for representing a backtrace as an object in + /// Rust. This returned value can be sent across threads and printed + /// elsewhere, and the purpose of this value is to be entirely self + /// contained. + /// + /// Note that on some platforms acquiring a full backtrace and resolving it + /// can be extremely expensive. If the cost is too much for your application + /// it's recommended to instead use `Backtrace::new_unresolved()` which + /// avoids the symbol resolution step (which typically takes the longest) + /// and allows deferring that to a later date. + /// + /// # Examples + /// + /// ``` + /// use backtrace::Backtrace; + /// + /// let current_backtrace = Backtrace::new(); + /// ``` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + #[inline(never)] // want to make sure there's a frame here to remove + pub fn new() -> Backtrace { + let _guard = lock_and_platform_init(); + let mut bt = Self::create(Self::new as usize); + bt.resolve(); + bt + } + + /// Similar to `new` except that this does not resolve any symbols, this + /// simply captures the backtrace as a list of addresses. + /// + /// At a later time the `resolve` function can be called to resolve this + /// backtrace's symbols into readable names. This function exists because + /// the resolution process can sometimes take a significant amount of time + /// whereas any one backtrace may only be rarely printed. + /// + /// # Examples + /// + /// ``` + /// use backtrace::Backtrace; + /// + /// let mut current_backtrace = Backtrace::new_unresolved(); + /// println!("{:?}", current_backtrace); // no symbol names + /// current_backtrace.resolve(); + /// println!("{:?}", current_backtrace); // symbol names now present + /// ``` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + #[inline(never)] // want to make sure there's a frame here to remove + pub fn new_unresolved() -> Backtrace { + let _guard = lock_and_platform_init(); + Self::create(Self::new_unresolved as usize) + } + + fn create(ip: usize) -> Backtrace { + let mut frames = Vec::new(); + let mut actual_start_index = None; + trace(|frame| { + frames.push(BacktraceFrame { + frame: Frame::Raw(frame.clone()), + symbols: None, + }); + + if frame.symbol_address() as usize == ip && actual_start_index.is_none() { + actual_start_index = Some(frames.len()); + } + true + }); + + Backtrace { + frames, + actual_start_index: actual_start_index.unwrap_or(0), + } + } + + /// Returns the frames from when this backtrace was captured. + /// + /// The first entry of this slice is likely the function `Backtrace::new`, + /// and the last frame is likely something about how this thread or the main + /// function started. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn frames(&self) -> &[BacktraceFrame] { + &self.frames[self.actual_start_index..] + } + + /// If this backtrace was created from `new_unresolved` then this function + /// will resolve all addresses in the backtrace to their symbolic names. + /// + /// If this backtrace has been previously resolved or was created through + /// `new`, this function does nothing. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn resolve(&mut self) { + let _guard = lock_and_platform_init(); + for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) { + let mut symbols = Vec::new(); + { + let sym = |symbol: &Symbol| { + symbols.push(BacktraceSymbol { + name: symbol.name().map(|m| m.as_bytes().to_vec()), + addr: symbol.addr().map(|a| a as usize), + filename: symbol.filename().map(|m| m.to_owned()), + lineno: symbol.lineno(), + }); + }; + match frame.frame { + Frame::Raw(ref f) => resolve_frame(f, sym), + Frame::Deserialized { ip, .. } => { + resolve(ip as *mut c_void, sym); + } + } + } + frame.symbols = Some(symbols); + } + } +} + +impl From> for Backtrace { + fn from(frames: Vec) -> Self { + Backtrace { + frames, + actual_start_index: 0, + } + } +} + +impl Into> for Backtrace { + fn into(self) -> Vec { + self.frames + } +} + +impl BacktraceFrame { + /// Same as `Frame::ip` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn ip(&self) -> *mut c_void { + self.frame.ip() as *mut c_void + } + + /// Same as `Frame::symbol_address` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn symbol_address(&self) -> *mut c_void { + self.frame.symbol_address() as *mut c_void + } + + /// Returns the list of symbols that this frame corresponds to. + /// + /// Normally there is only one symbol per frame, but sometimes if a number + /// of functions are inlined into one frame then multiple symbols will be + /// returned. The first symbol listed is the "innermost function", whereas + /// the last symbol is the outermost (last caller). + /// + /// Note that if this frame came from an unresolved backtrace then this will + /// return an empty list. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn symbols(&self) -> &[BacktraceSymbol] { + self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[]) + } +} + +impl BacktraceSymbol { + /// Same as `Symbol::name` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn name(&self) -> Option { + self.name.as_ref().map(|s| SymbolName::new(s)) + } + + /// Same as `Symbol::addr` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn addr(&self) -> Option<*mut c_void> { + self.addr.map(|s| s as *mut c_void) + } + + /// Same as `Symbol::filename` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn filename(&self) -> Option<&Path> { + self.filename.as_ref().map(|p| &**p) + } + + /// Same as `Symbol::lineno` + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn lineno(&self) -> Option { + self.lineno + } +} + +impl fmt::Debug for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "stack backtrace:")?; + + let iter = if fmt.alternate() { + self.frames.iter() + } else { + self.frames[self.actual_start_index..].iter() + }; + + for (idx, frame) in iter.enumerate() { + // To reduce TCB size in Sgx enclave, we do not want to implement symbol resolution functionality. + // Rather, we can print the offset of the address here, which could be later mapped to + // correct function. + let ip: *mut c_void; + #[cfg(target_env = "sgx")] + { + ip = usize::wrapping_sub( + frame.ip() as _, + std::os::fortanix_sgx::mem::image_base() as _, + ) as _; + } + #[cfg(not(target_env = "sgx"))] + { + ip = frame.ip(); + } + + write!(fmt, "\n{:4}: ", idx)?; + + let symbols = match frame.symbols { + Some(ref s) => s, + None => { + write!(fmt, " ({:?})", ip)?; + continue; + } + }; + if symbols.len() == 0 { + write!(fmt, " ({:?})", ip)?; + continue; + } + + for (idx, symbol) in symbols.iter().enumerate() { + if idx != 0 { + write!(fmt, "\n ")?; + } + + if let Some(name) = symbol.name() { + write!(fmt, "{}", name)?; + } else { + write!(fmt, "")?; + } + + if idx == 0 { + write!(fmt, " ({:?})", ip)?; + } + + if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) { + write!(fmt, "\n at {}:{}", file.display(), line)?; + } + } + } + + Ok(()) + } +} + +impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } +} + +impl fmt::Debug for BacktraceFrame { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BacktraceFrame") + .field("ip", &self.ip()) + .field("symbol_address", &self.symbol_address()) + .finish() + } +} + +impl fmt::Debug for BacktraceSymbol { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BacktraceSymbol") + .field("name", &self.name()) + .field("addr", &self.addr()) + .field("filename", &self.filename()) + .field("lineno", &self.lineno()) + .finish() + } +} + +// When using `dbghelp` on Windows this is a performance optimization. If +// we don't do this then `SymInitializeW` is called once per trace and once per +// frame during resolution. That function, however, takes quite some time! To +// help speed it up this function can amortize the calls necessary by ensuring +// that the scope this is called in only initializes when this is called and +// doesn't reinitialize for the rest of the scope. +#[cfg(all(windows, feature = "dbghelp"))] +fn lock_and_platform_init() -> impl Drop { + use std::mem::ManuallyDrop; + + struct Cleanup { + _lock: crate::lock::LockGuard, + + // Need to make sure this is cleaned up before `_lock` + dbghelp_cleanup: Option>, + } + + impl Drop for Cleanup { + fn drop(&mut self) { + if let Some(cleanup) = self.dbghelp_cleanup.as_mut() { + // Unsafety here should be ok since we're only dropping this in + // `Drop` to ensure it's dropped before the lock, and `Drop` + // should only be called once. + unsafe { + ManuallyDrop::drop(cleanup); + } + } + } + } + + // Unsafety here should be ok because we only acquire the `dbghelp` + // initialization (the unsafe part) after acquiring the global lock for this + // crate. Note that we're also careful to drop it before the lock is + // dropped. + unsafe { + Cleanup { + _lock: crate::lock::lock(), + dbghelp_cleanup: crate::dbghelp::init().ok().map(ManuallyDrop::new), + } + } +} + +#[cfg(not(all(windows, feature = "dbghelp")))] +fn lock_and_platform_init() {} + +#[cfg(feature = "serialize-rustc")] +mod rustc_serialize_impls { + use super::*; + use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + + #[derive(RustcEncodable, RustcDecodable)] + struct SerializedFrame { + ip: usize, + symbol_address: usize, + symbols: Option>, + } + + impl Decodable for BacktraceFrame { + fn decode(d: &mut D) -> Result + where + D: Decoder, + { + let frame: SerializedFrame = SerializedFrame::decode(d)?; + Ok(BacktraceFrame { + frame: Frame::Deserialized { + ip: frame.ip, + symbol_address: frame.symbol_address, + }, + symbols: frame.symbols, + }) + } + } + + impl Encodable for BacktraceFrame { + fn encode(&self, e: &mut E) -> Result<(), E::Error> + where + E: Encoder, + { + let BacktraceFrame { frame, symbols } = self; + SerializedFrame { + ip: frame.ip() as usize, + symbol_address: frame.symbol_address() as usize, + symbols: symbols.clone(), + } + .encode(e) + } + } +} + +#[cfg(feature = "serialize-serde")] +mod serde_impls { + extern crate serde; + + use self::serde::de::Deserializer; + use self::serde::ser::Serializer; + use self::serde::{Deserialize, Serialize}; + use super::*; + + #[derive(Serialize, Deserialize)] + struct SerializedFrame { + ip: usize, + symbol_address: usize, + symbols: Option>, + } + + impl Serialize for BacktraceFrame { + fn serialize(&self, s: S) -> Result + where + S: Serializer, + { + let BacktraceFrame { frame, symbols } = self; + SerializedFrame { + ip: frame.ip() as usize, + symbol_address: frame.symbol_address() as usize, + symbols: symbols.clone(), + } + .serialize(s) + } + } + + impl<'a> Deserialize<'a> for BacktraceFrame { + fn deserialize(d: D) -> Result + where + D: Deserializer<'a>, + { + let frame: SerializedFrame = SerializedFrame::deserialize(d)?; + Ok(BacktraceFrame { + frame: Frame::Deserialized { + ip: frame.ip, + symbol_address: frame.symbol_address, + }, + symbols: frame.symbols, + }) + } + } +} diff --git a/backtrace/src/dbghelp.rs b/backtrace/src/dbghelp.rs new file mode 100644 index 000000000..327bd8d01 --- /dev/null +++ b/backtrace/src/dbghelp.rs @@ -0,0 +1,329 @@ +//! A module to assist in managing dbghelp bindings on Windows +//! +//! Backtraces on Windows (at least for MSVC) are largely powered through +//! `dbghelp.dll` and the various functions that it contains. These functions +//! are currently loaded *dynamically* rather than linking to `dbghelp.dll` +//! statically. This is currently done by the standard library (and is in theory +//! required there), but is an effort to help reduce the static dll dependencies +//! of a library since backtraces are typically pretty optional. That being +//! said, `dbghelp.dll` almost always successfully loads on Windows. +//! +//! Note though that since we're loading all this support dynamically we can't +//! actually use the raw definitions in `winapi`, but rather we need to define +//! the function pointer types ourselves and use that. We don't really want to +//! be in the business of duplicating winapi, so we have a Cargo feature +//! `verify-winapi` which asserts that all bindings match those in winapi and +//! this feature is enabled on CI. + +#![allow(non_snake_case)] + +use core::mem; +use core::ptr; +use windows::*; + +// Work around `SymGetOptions` and `SymSetOptions` not being present in winapi +// itself. Otherwise this is only used when we're double-checking types against +// winapi. +#[cfg(feature = "verify-winapi")] +mod dbghelp { + pub use winapi::um::dbghelp::{ + StackWalk64, SymCleanup, SymFromAddrW, SymFunctionTableAccess64, SymGetLineFromAddrW64, + SymGetModuleBase64, SymInitializeW, + }; + use windows::*; + + extern "system" { + // Not defined in winapi yet + pub fn SymGetOptions() -> u32; + pub fn SymSetOptions(_: u32); + + // This is defined in winapi, but it's incorrect (FIXME winapi-rs#768) + pub fn StackWalkEx( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME_EX, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64, + Flags: DWORD, + ) -> BOOL; + + // Not defined in winapi yet + pub fn SymFromInlineContextW( + hProcess: HANDLE, + Address: DWORD64, + InlineContext: ULONG, + Displacement: PDWORD64, + Symbol: PSYMBOL_INFOW, + ) -> BOOL; + pub fn SymGetLineFromInlineContextW( + hProcess: HANDLE, + dwAddr: DWORD64, + InlineContext: ULONG, + qwModuleBaseAddress: DWORD64, + pdwDisplacement: PDWORD, + Line: PIMAGEHLP_LINEW64, + ) -> BOOL; + } + + pub fn assert_equal_types(a: T, _b: T) -> T { + a + } +} + +// This macro is used to define a `Dbghelp` structure which internally contains +// all the function pointers that we might load. +macro_rules! dbghelp { + (extern "system" { + $(fn $name:ident($($arg:ident: $argty:ty),*) -> $ret: ty;)* + }) => ( + pub struct Dbghelp { + /// The loaded DLL for `dbghelp.dll` + dll: HMODULE, + + // Each function pointer for each function we might use + $($name: usize,)* + } + + static mut DBGHELP: Dbghelp = Dbghelp { + // Initially we haven't loaded the DLL + dll: 0 as *mut _, + // Initiall all functions are set to zero to say they need to be + // dynamically loaded. + $($name: 0,)* + }; + + // Convenience typedef for each function type. + $(pub type $name = unsafe extern "system" fn($($argty),*) -> $ret;)* + + impl Dbghelp { + /// Attempts to open `dbghelp.dll`. Returns success if it works or + /// error if `LoadLibraryW` fails. + /// + /// Panics if library is already loaded. + fn open(&mut self) -> Result<(), ()> { + assert!(self.dll.is_null()); + let lib = b"dbghelp.dll\0"; + unsafe { + self.dll = LoadLibraryA(lib.as_ptr() as *const i8); + if self.dll.is_null() { + Err(()) + } else { + Ok(()) + } + } + } + + /// Unloads `dbghelp.dll`, resetting all function pointers to zero + /// as well. + fn close(&mut self) { + assert!(!self.dll.is_null()); + unsafe { + $(self.$name = 0;)* + FreeLibrary(self.dll); + self.dll = ptr::null_mut(); + } + } + + // Function for each method we'd like to use. When called it will + // either read the cached function pointer or load it and return the + // loaded value. Loads are asserted to succeed. + $(pub fn $name(&mut self) -> Option<$name> { + unsafe { + if self.$name == 0 { + let name = concat!(stringify!($name), "\0"); + self.$name = self.symbol(name.as_bytes())?; + } + let ret = mem::transmute::(self.$name); + #[cfg(feature = "verify-winapi")] + dbghelp::assert_equal_types(ret, dbghelp::$name); + Some(ret) + } + })* + + fn symbol(&self, symbol: &[u8]) -> Option { + unsafe { + match GetProcAddress(self.dll, symbol.as_ptr() as *const _) as usize { + 0 => None, + n => Some(n), + } + } + } + } + + // Convenience proxy to use the cleanup locks to reference dbghelp + // functions. + #[allow(dead_code)] + impl Cleanup { + $(pub fn $name(&self) -> $name { + unsafe { + DBGHELP.$name().unwrap() + } + })* + + pub fn dbghelp(&self) -> *mut Dbghelp { + unsafe { + &mut DBGHELP + } + } + } + ) + +} + +const SYMOPT_DEFERRED_LOADS: DWORD = 0x00000004; + +dbghelp! { + extern "system" { + fn SymGetOptions() -> DWORD; + fn SymSetOptions(options: DWORD) -> (); + fn SymInitializeW( + handle: HANDLE, + path: PCWSTR, + invade: BOOL + ) -> BOOL; + fn SymCleanup(handle: HANDLE) -> BOOL; + fn StackWalk64( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME64, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64 + ) -> BOOL; + fn SymFunctionTableAccess64( + hProcess: HANDLE, + AddrBase: DWORD64 + ) -> PVOID; + fn SymGetModuleBase64( + hProcess: HANDLE, + AddrBase: DWORD64 + ) -> DWORD64; + fn SymFromAddrW( + hProcess: HANDLE, + Address: DWORD64, + Displacement: PDWORD64, + Symbol: PSYMBOL_INFOW + ) -> BOOL; + fn SymGetLineFromAddrW64( + hProcess: HANDLE, + dwAddr: DWORD64, + pdwDisplacement: PDWORD, + Line: PIMAGEHLP_LINEW64 + ) -> BOOL; + fn StackWalkEx( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME_EX, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64, + Flags: DWORD + ) -> BOOL; + fn SymFromInlineContextW( + hProcess: HANDLE, + Address: DWORD64, + InlineContext: ULONG, + Displacement: PDWORD64, + Symbol: PSYMBOL_INFOW + ) -> BOOL; + fn SymGetLineFromInlineContextW( + hProcess: HANDLE, + dwAddr: DWORD64, + InlineContext: ULONG, + qwModuleBaseAddress: DWORD64, + pdwDisplacement: PDWORD, + Line: PIMAGEHLP_LINEW64 + ) -> BOOL; + } +} + +pub struct Cleanup; + +// Number of times `init` has been called on this thread. This is externally +// synchronized and doesn't use internal synchronization on our behalf. +static mut COUNT: usize = 0; + +// Used to restore `SymSetOptions` and `SymGetOptions` values. +static mut OPTS_ORIG: DWORD = 0; + +/// Unsafe because this requires external synchronization, must be done +/// inside of the same lock as all other backtrace operations. +/// +/// Note that the `Dbghelp` returned must also be dropped within the same +/// lock. +#[cfg(all(windows, feature = "dbghelp"))] +pub unsafe fn init() -> Result { + // Initializing symbols has significant overhead, but initializing only + // once without cleanup causes problems for external sources. For + // example, the standard library checks the result of SymInitializeW + // (which returns an error if attempting to initialize twice) and in + // the event of an error, will not print a backtrace on panic. + // Presumably, external debuggers may have similar issues. + // + // As a compromise, we'll keep track of the number of internal + // initialization requests within a single API call in order to + // minimize the number of init/cleanup cycles. + if COUNT > 0 { + COUNT += 1; + return Ok(Cleanup); + } + + // Actually load `dbghelp.dll` into the process here, returning an error if + // that fails. + DBGHELP.open()?; + + OPTS_ORIG = DBGHELP.SymGetOptions().unwrap()(); + + // Ensure that the `SYMOPT_DEFERRED_LOADS` flag is set, because + // according to MSVC's own docs about this: "This is the fastest, most + // efficient way to use the symbol handler.", so let's do that! + DBGHELP.SymSetOptions().unwrap()(OPTS_ORIG | SYMOPT_DEFERRED_LOADS); + + let ret = DBGHELP.SymInitializeW().unwrap()(GetCurrentProcess(), ptr::null_mut(), TRUE); + if ret != TRUE { + // Symbols may have been initialized by another library or an + // external debugger + DBGHELP.SymSetOptions().unwrap()(OPTS_ORIG); + DBGHELP.close(); + Err(()) + } else { + COUNT += 1; + Ok(Cleanup) + } +} + +impl Drop for Cleanup { + fn drop(&mut self) { + unsafe { + COUNT -= 1; + if COUNT != 0 { + return; + } + + // Clean up after ourselves by cleaning up symbols and restoring the + // symbol options to their original value. This is currently + // required to cooperate with libstd as libstd's backtracing will + // assert symbol initialization succeeds and will clean up after the + // backtrace is finished. + DBGHELP.SymCleanup().unwrap()(GetCurrentProcess()); + DBGHELP.SymSetOptions().unwrap()(OPTS_ORIG); + + // We can in theory leak this to stay in a global and we simply + // always reuse it, but for now let's be tidy and release all our + // resources. If we get bug reports the we could basically elide + // this `close()` (and the one above) and then update `open` to be a + // noop if it's already opened. + DBGHELP.close(); + } + } +} diff --git a/backtrace/src/lib.rs b/backtrace/src/lib.rs new file mode 100644 index 000000000..724fc2165 --- /dev/null +++ b/backtrace/src/lib.rs @@ -0,0 +1,177 @@ +//! A library for acquiring a backtrace at runtime +//! +//! This library is meant to supplement the `RUST_BACKTRACE=1` support of the +//! standard library by allowing an acquisition of a backtrace at runtime +//! programmatically. The backtraces generated by this library do not need to be +//! parsed, for example, and expose the functionality of multiple backend +//! implementations. +//! +//! # Implementation +//! +//! This library makes use of a number of strategies for actually acquiring a +//! backtrace. For example unix uses libgcc's libunwind bindings by default to +//! acquire a backtrace, but coresymbolication or dladdr is used on OSX to +//! acquire symbol names while linux uses gcc's libbacktrace. +//! +//! When using the default feature set of this library the "most reasonable" set +//! of defaults is chosen for the current platform, but the features activated +//! can also be controlled at a finer granularity. +//! +//! # API Principles +//! +//! This library attempts to be as flexible as possible to accommodate different +//! backend implementations of acquiring a backtrace. Consequently the currently +//! exported functions are closure-based as opposed to the likely expected +//! iterator-based versions. This is done due to limitations of the underlying +//! APIs used from the system. +//! +//! # Usage +//! +//! First, add this to your Cargo.toml +//! +//! ```toml +//! [dependencies] +//! backtrace = "0.3" +//! ``` +//! +//! Next: +//! +//! ``` +//! extern crate backtrace; +//! +//! fn main() { +//! # // Unsafe here so test passes on no_std. +//! # #[cfg(feature = "std")] { +//! backtrace::trace(|frame| { +//! let ip = frame.ip(); +//! let symbol_address = frame.symbol_address(); +//! +//! // Resolve this instruction pointer to a symbol name +//! backtrace::resolve_frame(frame, |symbol| { +//! if let Some(name) = symbol.name() { +//! // ... +//! } +//! if let Some(filename) = symbol.filename() { +//! // ... +//! } +//! }); +//! +//! true // keep going to the next frame +//! }); +//! } +//! # } +//! ``` + +#![doc(html_root_url = "https://docs.rs/backtrace")] +#![deny(missing_docs)] +#![no_std] +#![cfg_attr(all(feature = "std", target_env = "sgx"), feature(sgx_platform))] +#![allow(bare_trait_objects)] // TODO: remove when updating to 2018 edition +#![allow(rust_2018_idioms)] // TODO: remove when updating to 2018 edition + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +extern crate libc; +#[cfg(all(windows, feature = "verify-winapi"))] +extern crate winapi; + +#[cfg(feature = "serde_derive")] +#[cfg_attr(feature = "serde_derive", macro_use)] +extern crate serde_derive; + +#[cfg(feature = "rustc-serialize")] +extern crate rustc_serialize; + +#[macro_use] +extern crate cfg_if; + +extern crate rustc_demangle; + +#[cfg(feature = "cpp_demangle")] +extern crate cpp_demangle; + +cfg_if! { + if #[cfg(all(feature = "gimli-symbolize", unix, target_os = "linux"))] { + extern crate addr2line; + extern crate findshlibs; + extern crate memmap; + } +} + +pub use backtrace::{trace_unsynchronized, Frame}; +mod backtrace; + +pub use symbolize::{resolve_unsynchronized, Symbol, SymbolName}; +pub use symbolize::resolve_frame_unsynchronized; +mod symbolize; + +pub use types::BytesOrWideString; +mod types; + +cfg_if! { + if #[cfg(feature = "std")] { + pub use backtrace::trace; + pub use symbolize::{resolve, resolve_frame}; + pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol}; + mod capture; + } +} + +#[allow(dead_code)] +struct Bomb { + enabled: bool, +} + +#[allow(dead_code)] +impl Drop for Bomb { + fn drop(&mut self) { + if self.enabled { + panic!("cannot panic during the backtrace function"); + } + } +} + +#[allow(dead_code)] +#[cfg(feature = "std")] +mod lock { + use std::boxed::Box; + use std::cell::Cell; + use std::sync::{Mutex, MutexGuard, Once, ONCE_INIT}; + + pub struct LockGuard(Option>); + + static mut LOCK: *mut Mutex<()> = 0 as *mut _; + static INIT: Once = ONCE_INIT; + thread_local!(static LOCK_HELD: Cell = Cell::new(false)); + + impl Drop for LockGuard { + fn drop(&mut self) { + if self.0.is_some() { + LOCK_HELD.with(|slot| { + assert!(slot.get()); + slot.set(false); + }); + } + } + } + + pub fn lock() -> LockGuard { + if LOCK_HELD.with(|l| l.get()) { + return LockGuard(None); + } + LOCK_HELD.with(|s| s.set(true)); + unsafe { + INIT.call_once(|| { + LOCK = Box::into_raw(Box::new(Mutex::new(()))); + }); + LockGuard(Some((*LOCK).lock().unwrap())) + } + } +} + +#[cfg(all(windows, feature = "dbghelp"))] +mod dbghelp; +#[cfg(windows)] +mod windows; diff --git a/backtrace/src/symbolize/coresymbolication.rs b/backtrace/src/symbolize/coresymbolication.rs new file mode 100644 index 000000000..6ba1db8eb --- /dev/null +++ b/backtrace/src/symbolize/coresymbolication.rs @@ -0,0 +1,278 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Symbolication strategy that's OSX-specific and uses the `CoreSymbolication` +//! framework, if possible. +//! +//! This strategy uses internal private APIs that are somewhat undocumented but +//! seem to be widely used on OSX. This is the default symbolication strategy +//! for OSX, but is turned off in release builds for iOS due to reports of apps +//! being rejected due to using these APIs. +//! +//! This would probably be good to get official one day and not using private +//! APIs, but for now it should largely suffice. +//! +//! Note that this module will dynamically load `CoreSymbolication` and its APIs +//! through dlopen/dlsym, and if the loading fails this falls back to `dladdr` +//! as a symbolication strategy. + +#![allow(bad_style)] + +use core::mem; +use core::ptr; +use core::slice; + +use libc::{self, c_char, c_int, Dl_info}; + +use symbolize::ResolveWhat; +use types::{c_void, BytesOrWideString}; +use SymbolName; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub struct CSTypeRef { + cpp_data: *const c_void, + cpp_obj: *const c_void, +} + +const CS_NOW: u64 = 0x80000000; +const CSREF_NULL: CSTypeRef = CSTypeRef { + cpp_data: 0 as *const c_void, + cpp_obj: 0 as *const c_void, +}; + +pub enum Symbol { + Core { + path: *const c_char, + lineno: u32, + name: *const c_char, + addr: *mut c_void, + }, + Dladdr(Dl_info), +} + +impl Symbol { + pub fn name(&self) -> Option { + let name = match *self { + Symbol::Core { name, .. } => name, + Symbol::Dladdr(ref info) => info.dli_sname, + }; + if name.is_null() { + None + } else { + Some(SymbolName::new(unsafe { + let len = libc::strlen(name); + slice::from_raw_parts(name as *const u8, len) + })) + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + match *self { + Symbol::Core { addr, .. } => Some(addr), + Symbol::Dladdr(ref info) => Some(info.dli_saddr as *mut _), + } + } + + fn filename_bytes(&self) -> Option<&[u8]> { + match *self { + Symbol::Core { path, .. } => { + if path.is_null() { + None + } else { + Some(unsafe { + let len = libc::strlen(path); + slice::from_raw_parts(path as *const u8, len) + }) + } + } + Symbol::Dladdr(_) => None, + } + } + + pub fn filename_raw(&self) -> Option { + self.filename_bytes().map(BytesOrWideString::Bytes) + } + + #[cfg(feature = "std")] + pub fn filename(&self) -> Option<&::std::path::Path> { + use std::ffi::OsStr; + use std::os::unix::prelude::*; + use std::path::Path; + + self.filename_bytes().map(OsStr::from_bytes).map(Path::new) + } + + pub fn lineno(&self) -> Option { + match *self { + Symbol::Core { lineno: 0, .. } => None, + Symbol::Core { lineno, .. } => Some(lineno), + Symbol::Dladdr(_) => None, + } + } +} + +macro_rules! coresymbolication { + (#[load_path = $path:tt] extern "C" { + $(fn $name:ident($($arg:ident: $argty:ty),*) -> $ret: ty;)* + }) => ( + pub struct CoreSymbolication { + // The loaded dynamic library + dll: *mut c_void, + + // Each function pointer for each function we might use + $($name: usize,)* + } + + static mut CORESYMBOLICATION: CoreSymbolication = CoreSymbolication { + // Initially we haven't loaded the dynamic library + dll: 0 as *mut _, + // Initiall all functions are set to zero to say they need to be + // dynamically loaded. + $($name: 0,)* + }; + + // Convenience typedef for each function type. + $(pub type $name = unsafe extern "C" fn($($argty),*) -> $ret;)* + + impl CoreSymbolication { + /// Attempts to open `dbghelp.dll`. Returns `true` if it works or + /// `false` if `dlopen` fails. + fn open(&mut self) -> bool { + if !self.dll.is_null() { + return true; + } + let lib = concat!($path, "\0").as_bytes(); + unsafe { + self.dll = libc::dlopen(lib.as_ptr() as *const _, libc::RTLD_LAZY); + !self.dll.is_null() + } + } + + // Function for each method we'd like to use. When called it will + // either read the cached function pointer or load it and return the + // loaded value. Loads are asserted to succeed. + $(pub fn $name(&mut self) -> $name { + unsafe { + if self.$name == 0 { + let name = concat!(stringify!($name), "\0"); + self.$name = self.symbol(name.as_bytes()) + .expect(concat!("symbol ", stringify!($name), " is missing")); + } + mem::transmute::(self.$name) + } + })* + + fn symbol(&self, symbol: &[u8]) -> Option { + unsafe { + match libc::dlsym(self.dll, symbol.as_ptr() as *const _) as usize { + 0 => None, + n => Some(n), + } + } + } + } + ) +} + +coresymbolication! { + #[load_path = "/System/Library/PrivateFrameworks/CoreSymbolication.framework\ + /Versions/A/CoreSymbolication"] + extern "C" { + fn CSSymbolicatorCreateWithPid(pid: c_int) -> CSTypeRef; + fn CSRelease(rf: CSTypeRef) -> (); + fn CSSymbolicatorGetSymbolWithAddressAtTime( + cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef; + fn CSSymbolicatorGetSourceInfoWithAddressAtTime( + cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef; + fn CSSourceInfoGetLineNumber(info: CSTypeRef) -> c_int; + fn CSSourceInfoGetPath(info: CSTypeRef) -> *const c_char; + fn CSSourceInfoGetSymbol(info: CSTypeRef) -> CSTypeRef; + fn CSSymbolGetMangledName(sym: CSTypeRef) -> *const c_char; + fn CSSymbolGetSymbolOwner(sym: CSTypeRef) -> CSTypeRef; + fn CSSymbolOwnerGetBaseAddress(symowner: CSTypeRef) -> *mut c_void; + } +} + +unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool { + // Note that this is externally synchronized so there's no need for + // synchronization here, making this `static mut` safer. + let lib = &mut CORESYMBOLICATION; + if !lib.open() { + return false; + } + + let cs = lib.CSSymbolicatorCreateWithPid()(libc::getpid()); + if cs == CSREF_NULL { + return false; + } + let _dtor = OwnedCSTypeRef { + ptr: cs, + CSRelease: lib.CSRelease(), + }; + + let info = lib.CSSymbolicatorGetSourceInfoWithAddressAtTime()(cs, addr, CS_NOW); + let sym = if info == CSREF_NULL { + lib.CSSymbolicatorGetSymbolWithAddressAtTime()(cs, addr, CS_NOW) + } else { + lib.CSSourceInfoGetSymbol()(info) + }; + if sym == CSREF_NULL { + return false; + } + let owner = lib.CSSymbolGetSymbolOwner()(sym); + if owner == CSREF_NULL { + return false; + } + + cb(&super::Symbol { + inner: Symbol::Core { + path: if info != CSREF_NULL { + lib.CSSourceInfoGetPath()(info) + } else { + ptr::null() + }, + lineno: if info != CSREF_NULL { + lib.CSSourceInfoGetLineNumber()(info) as u32 + } else { + 0 + }, + name: lib.CSSymbolGetMangledName()(sym), + addr: lib.CSSymbolOwnerGetBaseAddress()(owner), + }, + }); + true +} + +struct OwnedCSTypeRef { + ptr: CSTypeRef, + CSRelease: unsafe extern "C" fn(CSTypeRef), +} + +impl Drop for OwnedCSTypeRef { + fn drop(&mut self) { + unsafe { + (self.CSRelease)(self.ptr); + } + } +} + +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + let addr = what.address_or_ip(); + if try_resolve(addr, cb) { + return; + } + let mut info: Dl_info = mem::zeroed(); + if libc::dladdr(addr as *mut _, &mut info) != 0 { + cb(&super::Symbol { + inner: Symbol::Dladdr(info), + }); + } +} diff --git a/backtrace/src/symbolize/dbghelp.rs b/backtrace/src/symbolize/dbghelp.rs new file mode 100644 index 000000000..c31c40867 --- /dev/null +++ b/backtrace/src/symbolize/dbghelp.rs @@ -0,0 +1,236 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Symbolication strategy using `dbghelp.dll` on Windows, only used for MSVC +//! +//! This symbolication strategy, like with backtraces, uses dynamically loaded +//! information from `dbghelp.dll`. (see `src/dbghelp.rs` for info about why +//! it's dynamically loaded). +//! +//! This API selects its resolution strategy based on the frame provided or the +//! information we have at hand. If a frame from `StackWalkEx` is given to us +//! then we use similar APIs to generate correct information about inlined +//! functions. Otherwise if all we have is an address or an older stack frame +//! from `StackWalk64` we use the older APIs for symbolication. +//! +//! There's a good deal of support in this module, but a good chunk of it is +//! converting back and forth between Windows types and Rust types. For example +//! symbols come to us as wide strings which we then convert to utf-8 strings if +//! we can. + +#![allow(bad_style)] + +// This is a hack for compatibility with rustc 1.25.0. The no_std mode of this +// crate is not supported pre-1.30.0, but in std mode the `char` module here +// moved in rustc 1.26.0 (ish). As a result, in std mode we use `std::char` to +// retain compatibility with rustc 1.25.0, but in `no_std` mode (which is +// 1.30.0+ already) we use `core::char`. +#[cfg(not(feature = "std"))] +use core::char; +#[cfg(feature = "std")] +use std::char; + +use core::mem; +use core::slice; + +use backtrace::FrameImp as Frame; +use dbghelp; +use symbolize::ResolveWhat; +use types::{c_void, BytesOrWideString}; +use windows::*; +use SymbolName; + +// Store an OsString on std so we can provide the symbol name and filename. +pub struct Symbol { + name: *const [u8], + addr: *mut c_void, + line: Option, + filename: Option<*const [u16]>, + #[cfg(feature = "std")] + _filename_cache: Option<::std::ffi::OsString>, + #[cfg(not(feature = "std"))] + _filename_cache: (), +} + +impl Symbol { + pub fn name(&self) -> Option { + Some(SymbolName::new(unsafe { &*self.name })) + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.addr as *mut _) + } + + pub fn filename_raw(&self) -> Option { + self.filename + .map(|slice| unsafe { BytesOrWideString::Wide(&*slice) }) + } + + pub fn lineno(&self) -> Option { + self.line + } + + #[cfg(feature = "std")] + pub fn filename(&self) -> Option<&::std::path::Path> { + use std::path::Path; + + self._filename_cache.as_ref().map(Path::new) + } +} + +#[repr(C, align(8))] +struct Aligned8(T); + +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + // Ensure this process's symbols are initialized + let dbghelp = match dbghelp::init() { + Ok(dbghelp) => dbghelp, + Err(()) => return, // oh well... + }; + + match what { + ResolveWhat::Address(addr) => resolve_without_inline(&dbghelp, addr, cb), + ResolveWhat::Frame(frame) => match &frame.inner { + Frame::New(frame) => resolve_with_inline(&dbghelp, frame, cb), + Frame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb), + }, + } +} + +unsafe fn resolve_with_inline( + dbghelp: &dbghelp::Cleanup, + frame: &STACKFRAME_EX, + cb: &mut FnMut(&super::Symbol), +) { + do_resolve( + |info| { + dbghelp.SymFromInlineContextW()( + GetCurrentProcess(), + // FIXME: why is `-1` used here and below? It seems to produce + // more accurate backtraces on Windows (aka passes tests in + // rust-lang/rust), but it's unclear why it's required in the + // first place. + frame.AddrPC.Offset - 1, + frame.InlineFrameContext, + &mut 0, + info, + ) + }, + |line| { + dbghelp.SymGetLineFromInlineContextW()( + GetCurrentProcess(), + frame.AddrPC.Offset - 1, + frame.InlineFrameContext, + 0, + &mut 0, + line, + ) + }, + cb, + ) +} + +unsafe fn resolve_without_inline( + dbghelp: &dbghelp::Cleanup, + addr: *mut c_void, + cb: &mut FnMut(&super::Symbol), +) { + do_resolve( + |info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr as DWORD64, &mut 0, info), + |line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr as DWORD64, &mut 0, line), + cb, + ) +} + +unsafe fn do_resolve( + sym_from_addr: impl FnOnce(*mut SYMBOL_INFOW) -> BOOL, + get_line_from_addr: impl FnOnce(&mut IMAGEHLP_LINEW64) -> BOOL, + cb: &mut FnMut(&super::Symbol), +) { + const SIZE: usize = 2 * MAX_SYM_NAME + mem::size_of::(); + let mut data = Aligned8([0u8; SIZE]); + let data = &mut data.0; + let info = &mut *(data.as_mut_ptr() as *mut SYMBOL_INFOW); + info.MaxNameLen = MAX_SYM_NAME as ULONG; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; + + if sym_from_addr(info) != TRUE { + return; + } + + // If the symbol name is greater than MaxNameLen, SymFromAddrW will + // give a buffer of (MaxNameLen - 1) characters and set NameLen to + // the real value. + let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1); + let name_ptr = info.Name.as_ptr() as *const u16; + let name = slice::from_raw_parts(name_ptr, name_len); + + // Reencode the utf-16 symbol to utf-8 so we can use `SymbolName::new` like + // all other platforms + let mut name_len = 0; + let mut name_buffer = [0; 256]; + { + let mut remaining = &mut name_buffer[..]; + for c in char::decode_utf16(name.iter().cloned()) { + let c = c.unwrap_or(char::REPLACEMENT_CHARACTER); + let len = c.len_utf8(); + if len < remaining.len() { + c.encode_utf8(remaining); + let tmp = remaining; + remaining = &mut tmp[len..]; + name_len += len; + } else { + break; + } + } + } + let name = &name_buffer[..name_len] as *const [u8]; + + let mut line = mem::zeroed::(); + line.SizeOfStruct = mem::size_of::() as DWORD; + + let mut filename = None; + let mut lineno = None; + if get_line_from_addr(&mut line) == TRUE { + lineno = Some(line.LineNumber as u32); + + let base = line.FileName; + let mut len = 0; + while *base.offset(len) != 0 { + len += 1; + } + + let len = len as usize; + + filename = Some(slice::from_raw_parts(base, len) as *const [u16]); + } + + cb(&super::Symbol { + inner: Symbol { + name, + addr: info.Address as *mut _, + line: lineno, + filename, + _filename_cache: cache(filename), + }, + }) +} + +#[cfg(feature = "std")] +unsafe fn cache(filename: Option<*const [u16]>) -> Option<::std::ffi::OsString> { + use std::os::windows::ffi::OsStringExt; + filename.map(|f| ::std::ffi::OsString::from_wide(&*f)) +} + +#[cfg(not(feature = "std"))] +unsafe fn cache(_filename: Option<*const [u16]>) {} diff --git a/backtrace/src/symbolize/dladdr.rs b/backtrace/src/symbolize/dladdr.rs new file mode 100644 index 000000000..43a0121e5 --- /dev/null +++ b/backtrace/src/symbolize/dladdr.rs @@ -0,0 +1,70 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Symbolication strategy using `dladdr` +//! +//! The `dladdr` API is available on most Unix implementations but it's quite +//! basic, not handling inline frame information at all. Since it's so prevalent +//! though we have an option to use it! + +use core::{mem, slice}; + +use types::{BytesOrWideString, c_void}; +use libc::{self, Dl_info}; +use symbolize::ResolveWhat; + +use SymbolName; + +pub struct Symbol { + inner: Dl_info, +} + +impl Symbol { + pub fn name(&self) -> Option { + if self.inner.dli_sname.is_null() { + None + } else { + let ptr = self.inner.dli_sname as *const u8; + unsafe { + let len = libc::strlen(self.inner.dli_sname); + Some(SymbolName::new(slice::from_raw_parts(ptr, len))) + } + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.inner.dli_saddr as *mut _) + } + + pub fn filename_raw(&self) -> Option { + None + } + + #[cfg(feature = "std")] + pub fn filename(&self) -> Option<&::std::path::Path> { + None + } + + pub fn lineno(&self) -> Option { + None + } +} + +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + let addr = what.address_or_ip(); + let mut info: super::Symbol = super::Symbol { + inner: Symbol { + inner: mem::zeroed(), + }, + }; + if libc::dladdr(addr as *mut _, &mut info.inner.inner) != 0 { + cb(&info) + } +} diff --git a/backtrace/src/symbolize/gimli.rs b/backtrace/src/symbolize/gimli.rs new file mode 100644 index 000000000..269e21b85 --- /dev/null +++ b/backtrace/src/symbolize/gimli.rs @@ -0,0 +1,237 @@ +//! Support for symbolication using the `gimli` crate on crates.io +//! +//! This implementation is largely a work in progress and is off by default for +//! all platforms, but it's hoped to be developed over time! Long-term this is +//! intended to wholesale replace the `libbacktrace.rs` implementation. + +use addr2line; +use addr2line::object::{self, Object}; +use findshlibs::{self, Segment, SharedLibrary}; +use libc::c_void; +use memmap::Mmap; +use std::cell::RefCell; +use std::env; +use std::fs::File; +use std::mem; +use std::path::{Path, PathBuf}; +use std::prelude::v1::*; +use std::u32; + +use symbolize::ResolveWhat; +use types::BytesOrWideString; +use SymbolName; + +const MAPPINGS_CACHE_SIZE: usize = 4; + +type Dwarf = addr2line::Context; +type Symbols<'map> = object::SymbolMap<'map>; + +struct Mapping { + dwarf: Dwarf, + // 'static lifetime is a lie to hack around lack of support for self-referential structs. + symbols: Symbols<'static>, + _map: Mmap, +} + +impl Mapping { + fn new(path: &PathBuf) -> Option { + let file = File::open(path).ok()?; + // TODO: not completely safe, see https://github.com/danburkert/memmap-rs/issues/25 + let map = unsafe { Mmap::map(&file).ok()? }; + let (dwarf, symbols) = { + let object = object::ElfFile::parse(&*map).ok()?; + let dwarf = addr2line::Context::new(&object).ok()?; + let symbols = object.symbol_map(); + // Convert to 'static lifetimes. + (dwarf, unsafe { mem::transmute(symbols) }) + }; + Some(Mapping { + dwarf, + symbols, + _map: map, + }) + } + + // Ensure the 'static lifetimes don't leak. + fn rent(&self, mut f: F) + where + F: FnMut(&Dwarf, &Symbols), + { + f(&self.dwarf, &self.symbols) + } +} + +thread_local! { + // A very small, very simple LRU cache for debug info mappings. + // + // The hit rate should be very high, since the typical stack doesn't cross + // between many shared libraries. + // + // The `addr2line::Context` structures are pretty expensive to create. Its + // cost is expected to be amortized by subsequent `locate` queries, which + // leverage the structures built when constructing `addr2line::Context`s to + // get nice speedups. If we didn't have this cache, that amortization would + // never happen, and symbolicating backtraces would be ssssllllooooowwww. + static MAPPINGS_CACHE: RefCell> + = RefCell::new(Vec::with_capacity(MAPPINGS_CACHE_SIZE)); +} + +fn with_mapping_for_path(path: PathBuf, f: F) +where + F: FnMut(&Dwarf, &Symbols), +{ + MAPPINGS_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + + let idx = cache.iter().position(|&(ref p, _)| p == &path); + + // Invariant: after this conditional completes without early returning + // from an error, the cache entry for this path is at index 0. + + if let Some(idx) = idx { + // When the mapping is already in the cache, move it to the front. + if idx != 0 { + let entry = cache.remove(idx); + cache.insert(0, entry); + } + } else { + // When the mapping is not in the cache, create a new mapping, + // insert it into the front of the cache, and evict the oldest cache + // entry if necessary. + let mapping = match Mapping::new(&path) { + None => return, + Some(m) => m, + }; + + if cache.len() == MAPPINGS_CACHE_SIZE { + cache.pop(); + } + + cache.insert(0, (path, mapping)); + } + + cache[0].1.rent(f); + }); +} + +pub fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + let addr = what.address_or_ip(); + + // First, find the file containing the segment that the given AVMA (after + // relocation) address falls within. Use the containing segment to compute + // the SVMA (before relocation) address. + // + // Note that the OS APIs that `SharedLibrary::each` is implemented with hold + // a lock for the duration of the `each` call, so we want to keep this + // section as short as possible to avoid contention with other threads + // capturing backtraces. + let addr = findshlibs::Avma(addr as *mut u8 as *const u8); + let mut so_info = None; + findshlibs::TargetSharedLibrary::each(|so| { + use findshlibs::IterationControl::*; + + for segment in so.segments() { + if segment.contains_avma(so, addr) { + let addr = so.avma_to_svma(addr); + let path = so.name().to_string_lossy(); + so_info = Some((addr, path.to_string())); + return Break; + } + } + + Continue + }); + let (addr, path) = match so_info { + None => return, + Some((a, p)) => (a, p), + }; + + // Second, fixup the path. Empty path means that this address falls within + // the main executable, not a shared library. + let path = if path.is_empty() { + match env::current_exe() { + Err(_) => return, + Ok(p) => p, + } + } else { + PathBuf::from(path) + }; + + // Finally, get a cached mapping or create a new mapping for this file, and + // evaluate the DWARF info to find the file/line/name for this address. + with_mapping_for_path(path, |dwarf, symbols| { + let mut found_sym = false; + if let Ok(mut frames) = dwarf.find_frames(addr.0 as u64) { + while let Ok(Some(frame)) = frames.next() { + let (file, line) = frame + .location + .map(|l| (l.file, l.line)) + .unwrap_or((None, None)); + let name = frame + .function + .and_then(|f| f.raw_name().ok().map(|f| f.to_string())); + let sym = super::Symbol { + inner: Symbol::new(addr.0 as usize, file, line, name), + }; + cb(&sym); + found_sym = true; + } + } + + // No DWARF info found, so fallback to the symbol table. + if !found_sym { + if let Some(name) = symbols.get(addr.0 as u64).and_then(|x| x.name()) { + let sym = super::Symbol { + inner: Symbol::new(addr.0 as usize, None, None, Some(name.to_string())), + }; + cb(&sym); + } + } + }); +} + +pub struct Symbol { + addr: usize, + file: Option, + line: Option, + name: Option, +} + +impl Symbol { + fn new(addr: usize, file: Option, line: Option, name: Option) -> Symbol { + Symbol { + addr, + file, + line, + name, + } + } + + pub fn name(&self) -> Option { + self.name.as_ref().map(|s| SymbolName::new(s.as_bytes())) + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.addr as *mut c_void) + } + + pub fn filename_raw(&self) -> Option { + self.file + .as_ref() + .map(|f| BytesOrWideString::Bytes(f.as_bytes())) + } + + pub fn filename(&self) -> Option<&Path> { + self.file.as_ref().map(Path::new) + } + + pub fn lineno(&self) -> Option { + self.line.and_then(|l| { + if l > (u32::MAX as u64) { + None + } else { + Some(l as u32) + } + }) + } +} diff --git a/backtrace/src/symbolize/libbacktrace.rs b/backtrace/src/symbolize/libbacktrace.rs new file mode 100644 index 000000000..137a25829 --- /dev/null +++ b/backtrace/src/symbolize/libbacktrace.rs @@ -0,0 +1,448 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Symbolication strategy using the DWARF-parsing code in libbacktrace. +//! +//! The libbacktrace C library, typically distributed with gcc, supports not +//! only generating a backtrace (which we don't actually use) but also +//! symbolicating the backtrace and handling dwarf debug information about +//! things like inlined frames and whatnot. +//! +//! This is relatively complicated due to lots of various concerns here, but the +//! basic idea is: +//! +//! * First we call `backtrace_syminfo`. This gets symbol information from the +//! dynamic symbol table if we can. +//! * Next we call `backtrace_pcinfo`. This will parse debuginfo tables if +//! they're available and allow us to recover information about inline frames, +//! filenames, line numbers, etc. +//! +//! There's lots of trickery about getting the dwarf tables into libbacktrace, +//! but hopefully it's not the end of the world and is clear enough when reading +//! below. +//! +//! This is the default symbolication strategy for non-MSVC and non-OSX +//! platforms. In libstd though this is the default strategy for OSX. + +#![allow(bad_style)] + +extern crate backtrace_sys as bt; + +use core::{ptr, slice}; + +use libc::{self, c_char, c_int, c_void, uintptr_t}; + +use SymbolName; + +use symbolize::ResolveWhat; +use types::BytesOrWideString; + +pub enum Symbol { + Syminfo { + pc: uintptr_t, + symname: *const c_char, + }, + Pcinfo { + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char, + symname: *const c_char, + }, +} + +impl Symbol { + pub fn name(&self) -> Option { + let symbol = |ptr: *const c_char| { + unsafe { + if ptr.is_null() { + None + } else { + let len = libc::strlen(ptr); + Some(SymbolName::new(slice::from_raw_parts( + ptr as *const u8, + len, + ))) + } + } + }; + match *self { + Symbol::Syminfo { symname, .. } => symbol(symname), + Symbol::Pcinfo { function, symname, .. } => { + // If possible prefer the `function` name which comes from + // debuginfo and can typically be more accurate for inline + // frames for example. If that's not present though fall back to + // the symbol table name specified in `symname`. + // + // Note that sometimes `function` can feel somewhat less + // accurate, for example being listed as `try` + // isntead of `std::panicking::try::do_call`. It's not really + // clear why, but overall the `function` name seems more accurate. + if let Some(sym) = symbol(function) { + return Some(sym) + } + symbol(symname) + } + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + let pc = match *self { + Symbol::Syminfo { pc, .. } => pc, + Symbol::Pcinfo { pc, .. } => pc, + }; + if pc == 0 { + None + } else { + Some(pc as *mut _) + } + } + + fn filename_bytes(&self) -> Option<&[u8]> { + match *self { + Symbol::Syminfo { .. } => None, + Symbol::Pcinfo { filename, .. } => { + let ptr = filename as *const u8; + unsafe { + let len = libc::strlen(filename); + Some(slice::from_raw_parts(ptr, len)) + } + } + } + } + + pub fn filename_raw(&self) -> Option { + self.filename_bytes().map(BytesOrWideString::Bytes) + } + + #[cfg(feature = "std")] + pub fn filename(&self) -> Option<&::std::path::Path> { + use std::path::Path; + + #[cfg(unix)] + fn bytes2path(bytes: &[u8]) -> Option<&Path> { + use std::ffi::OsStr; + use std::os::unix::prelude::*; + Some(Path::new(OsStr::from_bytes(bytes))) + } + + #[cfg(windows)] + fn bytes2path(bytes: &[u8]) -> Option<&Path> { + use std::str; + str::from_utf8(bytes).ok().map(Path::new) + } + + self.filename_bytes().and_then(bytes2path) + } + + pub fn lineno(&self) -> Option { + match *self { + Symbol::Syminfo { .. } => None, + Symbol::Pcinfo { lineno, .. } => Some(lineno as u32), + } + } +} + +extern "C" fn error_cb(_data: *mut c_void, _msg: *const c_char, _errnum: c_int) { + // do nothing for now +} + +/// Type of the `data` pointer passed into `syminfo_cb` +struct SyminfoState<'a> { + cb: &'a mut (FnMut(&super::Symbol) + 'a), + pc: usize, +} + +extern "C" fn syminfo_cb( + data: *mut c_void, + pc: uintptr_t, + symname: *const c_char, + _symval: uintptr_t, + _symsize: uintptr_t, +) { + let mut bomb = ::Bomb { enabled: true }; + + // Once this callback is invoked from `backtrace_syminfo` when we start + // resolving we go further to call `backtrace_pcinfo`. The + // `backtrace_pcinfo` function will consult debug information and attemp tto + // do things like recover file/line information as well as inlined frames. + // Note though that `backtrace_pcinfo` can fail or not do much if there's + // not debug info, so if that happens we're sure to call the callback with + // at least one symbol from the `syminfo_cb`. + unsafe { + let syminfo_state = &mut *(data as *mut SyminfoState); + let mut pcinfo_state = PcinfoState { + symname, + called: false, + cb: syminfo_state.cb, + }; + bt::backtrace_pcinfo( + init_state(), + syminfo_state.pc as uintptr_t, + pcinfo_cb, + error_cb, + &mut pcinfo_state as *mut _ as *mut _, + ); + if !pcinfo_state.called { + (pcinfo_state.cb)(&super::Symbol { + inner: Symbol::Syminfo { + pc: pc, + symname: symname, + }, + }); + } + } + + bomb.enabled = false; +} + +/// Type of the `data` pointer passed into `pcinfo_cb` +struct PcinfoState<'a> { + cb: &'a mut (FnMut(&super::Symbol) + 'a), + symname: *const c_char, + called: bool, +} + +extern "C" fn pcinfo_cb( + data: *mut c_void, + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char, +) -> c_int { + if filename.is_null() || function.is_null() { + return -1; + } + let mut bomb = ::Bomb { enabled: true }; + + unsafe { + let state = &mut *(data as *mut PcinfoState); + state.called = true; + (state.cb)(&super::Symbol { + inner: Symbol::Pcinfo { + pc: pc, + filename: filename, + lineno: lineno, + symname: state.symname, + function, + }, + }); + } + + bomb.enabled = false; + return 0; +} + +// The libbacktrace API supports creating a state, but it does not +// support destroying a state. I personally take this to mean that a +// state is meant to be created and then live forever. +// +// I would love to register an at_exit() handler which cleans up this +// state, but libbacktrace provides no way to do so. +// +// With these constraints, this function has a statically cached state +// that is calculated the first time this is requested. Remember that +// backtracing all happens serially (one global lock). +// +// Note the lack of synchronization here is due to the requirement that +// `resolve` is externally synchronized. +unsafe fn init_state() -> *mut bt::backtrace_state { + static mut STATE: *mut bt::backtrace_state = 0 as *mut _; + + if !STATE.is_null() { + return STATE; + } + + STATE = bt::backtrace_create_state( + load_filename(), + // Don't exercise threadsafe capabilities of libbacktrace since + // we're always calling it in a synchronized fashion. + 0, + error_cb, + ptr::null_mut(), // no extra data + ); + + return STATE; + + // Note that for libbacktrace to operate at all it needs to find the DWARF + // debug info for the current executable. It typically does that via a + // number of mechanisms including, but not limited to: + // + // * /proc/self/exe on supported platforms + // * The filename passed in explicitly when creating state + // + // The libbacktrace library is a big wad of C code. This naturally means + // it's got memory safety vulnerabilities, especially when handling + // malformed debuginfo. Libstd has run into plenty of these historically. + // + // If /proc/self/exe is used then we can typically ignore these as we + // assume that libbacktrace is "mostly correct" and otherwise doesn't do + // weird things with "attempted to be correct" dwarf debug info. + // + // If we pass in a filename, however, then it's possible on some platforms + // (like BSDs) where a malicious actor can cause an arbitrary file to be + // placed at that location. This means that if we tell libbacktrace about a + // filename it may be using an arbitrary file, possibly causing segfaults. + // If we don't tell libbacktrace anything though then it won't do anything + // on platforms that don't support paths like /proc/self/exe! + // + // Given all that we try as hard as possible to *not* pass in a filename, + // but we must on platforms that don't support /proc/self/exe at all. + cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + // Note that ideally we'd use `std::env::current_exe`, but we can't + // require `std` here. + // + // Use `_NSGetExecutablePath` to load the current executable path + // into a static area (which if it's too small just give up). + // + // Note that we're seriously trusting libbacktrace here to not die + // on corrupt executables, but it surely does... + unsafe fn load_filename() -> *const libc::c_char { + const N: usize = 256; + static mut BUF: [u8; N] = [0; N]; + extern { + fn _NSGetExecutablePath( + buf: *mut libc::c_char, + bufsize: *mut u32, + ) -> libc::c_int; + } + let mut sz: u32 = BUF.len() as u32; + let ptr = BUF.as_mut_ptr() as *mut libc::c_char; + if _NSGetExecutablePath(ptr, &mut sz) == 0 { + ptr + } else { + ptr::null() + } + } + } else if #[cfg(windows)] { + use windows::*; + + // Windows has a mode of opening files where after it's opened it + // can't be deleted. That's in general what we want here because we + // want to ensure that our executable isn't changing out from under + // us after we hand it off to libbacktrace, hopefully mitigating the + // ability to pass in arbitrary data into libbacktrace (which may be + // mishandled). + // + // Given that we do a bit of a dance here to attempt to get a sort + // of lock on our own image: + // + // * Get a handle to the current process, load its filename. + // * Open a file to that filename with the right flags. + // * Reload the current process's filename, making sure it's the same + // + // If that all passes we in theory have indeed opened our process's + // file and we're guaranteed it won't change. FWIW a bunch of this + // is copied from libstd historically, so this is my best + // interpretation of what was happening. + unsafe fn load_filename() -> *const libc::c_char { + load_filename_opt().unwrap_or(ptr::null()) + } + + unsafe fn load_filename_opt() -> Result<*const libc::c_char, ()> { + const N: usize = 256; + // This lives in static memory so we can return it.. + static mut BUF: [i8; N] = [0; N]; + // ... and this lives on the stack since it's temporary + let mut stack_buf = [0; N]; + let name1 = query_full_name(&mut BUF)?; + + let handle = CreateFileA( + name1.as_ptr(), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ); + if handle.is_null() { + return Err(()); + } + + let name2 = query_full_name(&mut stack_buf)?; + if name1 != name2 { + CloseHandle(handle); + return Err(()) + } + // intentionally leak `handle` here because having that open + // should preserve our lock on this file name. + Ok(name1.as_ptr()) + } + + unsafe fn query_full_name(buf: &mut [i8]) -> Result<&[i8], ()> { + let p1 = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); + let mut len = buf.len() as u32; + let rc = QueryFullProcessImageNameA(p1, 0, buf.as_mut_ptr(), &mut len); + CloseHandle(p1); + + // We want to return a slice that is nul-terminated, so if + // everything was filled in and it equals the total length + // then equate that to failure. + // + // Otherwise when returning success make sure the nul byte is + // included in the slice. + if rc == 0 || len == buf.len() as u32 { + Err(()) + } else { + assert_eq!(buf[len as usize], 0); + Ok(&buf[..(len + 1) as usize]) + } + } + + + } else { + unsafe fn load_filename() -> *const libc::c_char { + ptr::null() + } + } + } +} + +pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) { + let mut symaddr = what.address_or_ip() as usize; + + // It's sort of unclear why this is necessary, but it appears that the ip + // values from stack traces are typically the instruction *after* the call + // that's the actual stack trace. Symbolizing this on Windows causes the + // filename/line number to be one ahead and perhaps into the void if it's + // near the end of the function. Apparently on Unix though it's roughly fine + // in that the filename/line number turn out alright. For now just try to + // get good backtraces with this, and hopefully one day we can figure out + // why the `-=1` is here. + if cfg!(windows) && symaddr > 0 { + symaddr -= 1; + } + + // backtrace errors are currently swept under the rug + let state = init_state(); + if state.is_null() { + return; + } + + // Call the `backtrace_syminfo` API first. This is (from reading the code) + // guaranteed to call `syminfo_cb` exactly once (or fail with an error + // presumably). We then handle more within the `syminfo_cb`. + // + // Note that we do this since `syminfo` will consult the symbol table, + // finding symbol names even if there's no debug information in the binary. + let mut syminfo_state = SyminfoState { + pc: symaddr, + cb: cb, + }; + bt::backtrace_syminfo( + state, + symaddr as uintptr_t, + syminfo_cb, + error_cb, + &mut syminfo_state as *mut _ as *mut _, + ); +} diff --git a/backtrace/src/symbolize/mod.rs b/backtrace/src/symbolize/mod.rs new file mode 100644 index 000000000..157613a24 --- /dev/null +++ b/backtrace/src/symbolize/mod.rs @@ -0,0 +1,446 @@ +use core::{fmt, str}; + +cfg_if! { + if #[cfg(feature = "std")] { + use std::path::Path; + use std::prelude::v1::*; + } +} + +use rustc_demangle::{try_demangle, Demangle}; +use types::{c_void, BytesOrWideString}; + +use backtrace::Frame; + +/// Resolve an address to a symbol, passing the symbol to the specified +/// closure. +/// +/// This function will look up the given address in areas such as the local +/// symbol table, dynamic symbol table, or DWARF debug info (depending on the +/// activated implementation) to find symbols to yield. +/// +/// The closure may not be called if resolution could not be performed, and it +/// also may be called more than once in the case of inlined functions. +/// +/// Symbols yielded represent the execution at the specified `addr`, returning +/// file/line pairs for that address (if available). +/// +/// Note that if you have a `Frame` then it's recommended to use the +/// `resolve_frame` function instead of this one. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +/// +/// # Panics +/// +/// This function strives to never panic, but if the `cb` provided panics then +/// some platforms will force a double panic to abort the process. Some +/// platforms use a C library which internally uses callbacks which cannot be +/// unwound through, so panicking from `cb` may trigger a process abort. +/// +/// # Example +/// +/// ``` +/// extern crate backtrace; +/// +/// fn main() { +/// backtrace::trace(|frame| { +/// let ip = frame.ip(); +/// +/// backtrace::resolve(ip, |symbol| { +/// // ... +/// }); +/// +/// false // only look at the top frame +/// }); +/// } +/// ``` +#[cfg(feature = "std")] +pub fn resolve(addr: *mut c_void, cb: F) { + let _guard = ::lock::lock(); + unsafe { resolve_unsynchronized(addr, cb) } +} + +/// Resolve a previously capture frame to a symbol, passing the symbol to the +/// specified closure. +/// +/// This functin performs the same function as `resolve` except that it takes a +/// `Frame` as an argument instead of an address. This can allow some platform +/// implementations of backtracing to provide more accurate symbol information +/// or information about inline frames for example. It's recommended to use this +/// if you can. +/// +/// # Required features +/// +/// This function requires the `std` feature of the `backtrace` crate to be +/// enabled, and the `std` feature is enabled by default. +/// +/// # Panics +/// +/// This function strives to never panic, but if the `cb` provided panics then +/// some platforms will force a double panic to abort the process. Some +/// platforms use a C library which internally uses callbacks which cannot be +/// unwound through, so panicking from `cb` may trigger a process abort. +/// +/// # Example +/// +/// ``` +/// extern crate backtrace; +/// +/// fn main() { +/// backtrace::trace(|frame| { +/// backtrace::resolve_frame(frame, |symbol| { +/// // ... +/// }); +/// +/// false // only look at the top frame +/// }); +/// } +/// ``` +#[cfg(feature = "std")] +pub fn resolve_frame(frame: &Frame, cb: F) { + let _guard = ::lock::lock(); + unsafe { resolve_frame_unsynchronized(frame, cb) } +} + +pub enum ResolveWhat<'a> { + Address(*mut c_void), + Frame(&'a Frame), +} + +impl<'a> ResolveWhat<'a> { + #[allow(dead_code)] + fn address_or_ip(&self) -> *mut c_void { + match *self { + ResolveWhat::Address(a) => a, + ResolveWhat::Frame(ref f) => f.ip(), + } + } +} + +/// Same as `resolve`, only unsafe as it's unsynchronized. +/// +/// This function does not have synchronization guarentees but is available when +/// the `std` feature of this crate isn't compiled in. See the `resolve` +/// function for more documentation and examples. +/// +/// # Panics +/// +/// See information on `resolve` for caveats on `cb` panicking. +pub unsafe fn resolve_unsynchronized(addr: *mut c_void, mut cb: F) +where + F: FnMut(&Symbol), +{ + resolve_imp(ResolveWhat::Address(addr), &mut cb) +} + +/// Same as `resolve_frame`, only unsafe as it's unsynchronized. +/// +/// This function does not have synchronization guarentees but is available +/// when the `std` feature of this crate isn't compiled in. See the +/// `resolve_frame` function for more documentation and examples. +/// +/// # Panics +/// +/// See information on `resolve_frame` for caveats on `cb` panicking. +pub unsafe fn resolve_frame_unsynchronized(frame: &Frame, mut cb: F) +where + F: FnMut(&Symbol), +{ + resolve_imp(ResolveWhat::Frame(frame), &mut cb) +} + +/// A trait representing the resolution of a symbol in a file. +/// +/// This trait is yielded as a trait object to the closure given to the +/// `backtrace::resolve` function, and it is virtually dispatched as it's +/// unknown which implementation is behind it. +/// +/// A symbol can give contextual information about a function, for example the +/// name, filename, line number, precise address, etc. Not all information is +/// always available in a symbol, however, so all methods return an `Option`. +pub struct Symbol { + inner: SymbolImp, +} + +impl Symbol { + /// Returns the name of this function. + /// + /// The returned structure can be used to query various properties about the + /// symbol name: + /// + /// * The `Display` implementation will print out the demangled symbol. + /// * The raw `str` value of the symbol can be accessed (if it's valid + /// utf-8). + /// * The raw bytes for the symbol name can be accessed. + pub fn name(&self) -> Option { + self.inner.name() + } + + /// Returns the starting address of this function. + pub fn addr(&self) -> Option<*mut c_void> { + self.inner.addr().map(|p| p as *mut _) + } + + /// Returns the raw filename as a slice. This is mainly useful for `no_std` + /// environments. + pub fn filename_raw(&self) -> Option { + self.inner.filename_raw() + } + + /// Returns the line number for where this symbol is currently executing. + /// + /// This return value is typically `Some` if `filename` returns `Some`, and + /// is consequently subject to similar caveats. + pub fn lineno(&self) -> Option { + self.inner.lineno() + } + + /// Returns the file name where this function was defined. + /// + /// This is currently only available when libbacktrace is being used (e.g. + /// unix platforms other than OSX) and when a binary is compiled with + /// debuginfo. If neither of these conditions is met then this will likely + /// return `None`. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + #[cfg(feature = "std")] + #[allow(unreachable_code)] + pub fn filename(&self) -> Option<&Path> { + self.inner.filename() + } +} + +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("Symbol"); + if let Some(name) = self.name() { + d.field("name", &name); + } + if let Some(addr) = self.addr() { + d.field("addr", &addr); + } + + #[cfg(feature = "std")] + { + if let Some(filename) = self.filename() { + d.field("filename", &filename); + } + } + + if let Some(lineno) = self.lineno() { + d.field("lineno", &lineno); + } + d.finish() + } +} + +cfg_if! { + if #[cfg(feature = "cpp_demangle")] { + // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust + // failed. + struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>); + + impl<'a> OptionCppSymbol<'a> { + fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> { + OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok()) + } + + fn none() -> OptionCppSymbol<'a> { + OptionCppSymbol(None) + } + } + } else { + use core::marker::PhantomData; + + // Make sure to keep this zero-sized, so that the `cpp_demangle` feature + // has no cost when disabled. + struct OptionCppSymbol<'a>(PhantomData<&'a ()>); + + impl<'a> OptionCppSymbol<'a> { + fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> { + OptionCppSymbol(PhantomData) + } + + fn none() -> OptionCppSymbol<'a> { + OptionCppSymbol(PhantomData) + } + } + } +} + +/// A wrapper around a symbol name to provide ergonomic accessors to the +/// demangled name, the raw bytes, the raw string, etc. +// Allow dead code for when the `cpp_demangle` feature is not enabled. +#[allow(dead_code)] +pub struct SymbolName<'a> { + bytes: &'a [u8], + demangled: Option>, + cpp_demangled: OptionCppSymbol<'a>, +} + +impl<'a> SymbolName<'a> { + /// Creates a new symbol name from the raw underlying bytes. + pub fn new(bytes: &'a [u8]) -> SymbolName<'a> { + let str_bytes = str::from_utf8(bytes).ok(); + let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); + + let cpp = if demangled.is_none() { + OptionCppSymbol::parse(bytes) + } else { + OptionCppSymbol::none() + }; + + SymbolName { + bytes: bytes, + demangled: demangled, + cpp_demangled: cpp, + } + } + + /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8. + /// + /// Use the `Display` implementation if you want the demangled version. + pub fn as_str(&self) -> Option<&'a str> { + self.demangled + .as_ref() + .map(|s| s.as_str()) + .or_else(|| str::from_utf8(self.bytes).ok()) + } + + /// Returns the raw symbol name as a list of bytes + pub fn as_bytes(&self) -> &'a [u8] { + self.bytes + } +} + +fn format_symbol_name( + fmt: fn(&str, &mut fmt::Formatter) -> fmt::Result, + mut bytes: &[u8], + f: &mut fmt::Formatter, +) -> fmt::Result { + while bytes.len() > 0 { + match str::from_utf8(bytes) { + Ok(name) => { + fmt(name, f)?; + break; + } + Err(err) => { + fmt("\u{FFFD}", f)?; + + match err.error_len() { + Some(len) => bytes = &bytes[err.valid_up_to() + len..], + None => break, + } + } + } + } + Ok(()) +} + +cfg_if! { + if #[cfg(feature = "cpp_demangle")] { + impl<'a> fmt::Display for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else if let Some(ref cpp) = self.cpp_demangled.0 { + cpp.fmt(f) + } else { + format_symbol_name(fmt::Display::fmt, self.bytes, f) + } + } + } + } else { + impl<'a> fmt::Display for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else { + format_symbol_name(fmt::Display::fmt, self.bytes, f) + } + } + } + } +} + +cfg_if! { + if #[cfg(all(feature = "std", feature = "cpp_demangle"))] { + impl<'a> fmt::Debug for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Write; + + if let Some(ref s) = self.demangled { + return s.fmt(f) + } + + // This may to print if the demangled symbol isn't actually + // valid, so handle the error here gracefully by not propagating + // it outwards. + if let Some(ref cpp) = self.cpp_demangled.0 { + let mut s = String::new(); + if write!(s, "{}", cpp).is_ok() { + return s.fmt(f) + } + } + + format_symbol_name(fmt::Debug::fmt, self.bytes, f) + } + } + } else { + impl<'a> fmt::Debug for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else { + format_symbol_name(fmt::Debug::fmt, self.bytes, f) + } + } + } + } +} + +cfg_if! { + if #[cfg(all(windows, target_env = "msvc", feature = "dbghelp"))] { + mod dbghelp; + use self::dbghelp::resolve as resolve_imp; + use self::dbghelp::Symbol as SymbolImp; + } else if #[cfg(all(feature = "std", + feature = "gimli-symbolize", + target_os = "linux"))] { + mod gimli; + use self::gimli::resolve as resolve_imp; + use self::gimli::Symbol as SymbolImp; + // Note that we only enable coresymbolication on iOS when debug assertions + // are enabled because it's helpful in debug mode but it looks like apps get + // rejected from the app store if they use this API, see #92 for more info + } else if #[cfg(all(feature = "coresymbolication", + any(target_os = "macos", + all(target_os = "ios", debug_assertions))))] { + mod coresymbolication; + use self::coresymbolication::resolve as resolve_imp; + use self::coresymbolication::Symbol as SymbolImp; + } else if #[cfg(all(feature = "libbacktrace", + any(unix, all(windows, target_env = "gnu")), + not(target_os = "fuchsia"), + not(target_os = "emscripten")))] { + mod libbacktrace; + use self::libbacktrace::resolve as resolve_imp; + use self::libbacktrace::Symbol as SymbolImp; + } else if #[cfg(all(unix, + not(target_os = "emscripten"), + feature = "dladdr"))] { + mod dladdr; + use self::dladdr::resolve as resolve_imp; + use self::dladdr::Symbol as SymbolImp; + } else { + mod noop; + use self::noop::resolve as resolve_imp; + use self::noop::Symbol as SymbolImp; + } +} diff --git a/backtrace/src/symbolize/noop.rs b/backtrace/src/symbolize/noop.rs new file mode 100644 index 000000000..29114ad24 --- /dev/null +++ b/backtrace/src/symbolize/noop.rs @@ -0,0 +1,34 @@ +//! Empty symbolication strategy used to compile for platforms that have no +//! support. + +use types::{BytesOrWideString, c_void}; +use SymbolName; +use symbolize::ResolveWhat; + +pub unsafe fn resolve(_addr: ResolveWhat, _cb: &mut FnMut(&super::Symbol)) { +} + +pub struct Symbol; + +impl Symbol { + pub fn name(&self) -> Option { + None + } + + pub fn addr(&self) -> Option<*mut c_void> { + None + } + + pub fn filename_raw(&self) -> Option { + None + } + + #[cfg(feature = "std")] + pub fn filename(&self) -> Option<&::std::path::Path> { + None + } + + pub fn lineno(&self) -> Option { + None + } +} diff --git a/backtrace/src/types.rs b/backtrace/src/types.rs new file mode 100644 index 000000000..1486023ef --- /dev/null +++ b/backtrace/src/types.rs @@ -0,0 +1,89 @@ +//! Platform dependent types. + +cfg_if! { + if #[cfg(feature = "std")] { + pub use std::os::raw::c_void; + use std::borrow::Cow; + use std::fmt; + use std::path::PathBuf; + use std::prelude::v1::*; + } else if #[cfg(rustc_1_30)] { + pub use core::ffi::c_void; + } else { + compile_error!("`backtrace` requires Rust >=1.30.0 to support `no_std`."); + } +} + +/// A platform independent representation of a string. When working with `std` +/// enabled it is recommended to the convenience methods for providing +/// conversions to `std` types. +#[derive(Debug)] +pub enum BytesOrWideString<'a> { + /// A slice, typically provided on Unix platforms. + Bytes(&'a [u8]), + /// Wide strings typically from Windows. + Wide(&'a [u16]), +} + +#[cfg(feature = "std")] +impl<'a> BytesOrWideString<'a> { + /// Lossy converts to a `Cow`, will allocate if `Bytes` is not valid + /// UTF-8 or if `BytesOrWideString` is `Wide`. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn to_str_lossy(&self) -> Cow<'a, str> { + use self::BytesOrWideString::*; + + match self { + &Bytes(slice) => String::from_utf8_lossy(slice), + &Wide(wide) => Cow::Owned(String::from_utf16_lossy(wide)), + } + } + + /// Provides a `Path` representation of `BytesOrWideString`. + /// + /// # Required features + /// + /// This function requires the `std` feature of the `backtrace` crate to be + /// enabled, and the `std` feature is enabled by default. + pub fn into_path_buf(self) -> PathBuf { + #[cfg(unix)] + { + use self::BytesOrWideString::*; + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + + match self { + Bytes(slice) => PathBuf::from(OsStr::from_bytes(slice)), + _ => unreachable!(), + } + } + + #[cfg(windows)] + { + use self::BytesOrWideString::*; + use std::ffi::OsString; + use std::os::windows::ffi::OsStringExt; + + match self { + Wide(slice) => PathBuf::from(OsString::from_wide(slice)), + _ => unreachable!(), + } + } + + #[cfg(all(not(windows), not(unix)))] + { + unreachable!() + } + } +} + +#[cfg(feature = "std")] +impl<'a> fmt::Display for BytesOrWideString<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.to_str_lossy().fmt(f) + } +} diff --git a/backtrace/src/windows.rs b/backtrace/src/windows.rs new file mode 100644 index 000000000..2df756829 --- /dev/null +++ b/backtrace/src/windows.rs @@ -0,0 +1,611 @@ +//! A module to define the FFI definitions we use on Windows for `dbghelp.dll` +//! +//! This module uses a custom macro, `ffi!`, to wrap all definitions to +//! automatically generate tests to assert that our definitions here are the +//! same as `winapi`. +//! +//! This module largely exists to integrate into libstd itself where winapi is +//! not currently available. + +#![allow(bad_style, dead_code)] + +cfg_if! { + if #[cfg(feature = "verify-winapi")] { + pub use self::winapi::c_void; + pub use self::winapi::HINSTANCE; + pub use self::winapi::FARPROC; + pub use self::winapi::LPSECURITY_ATTRIBUTES; + + mod winapi { + pub use winapi::ctypes::*; + pub use winapi::shared::basetsd::*; + pub use winapi::shared::minwindef::*; + pub use winapi::um::dbghelp::*; + pub use winapi::um::handleapi::*; + pub use winapi::um::libloaderapi::*; + pub use winapi::um::processthreadsapi::*; + pub use winapi::um::winbase::*; + pub use winapi::um::winnt::*; + pub use winapi::um::fileapi::*; + pub use winapi::um::minwinbase::*; + } + } else { + pub use core::ffi::c_void; + pub type HINSTANCE = *mut c_void; + pub type FARPROC = *mut c_void; + pub type LPSECURITY_ATTRIBUTES = *mut c_void; + } +} + +macro_rules! ffi { + () => (); + + (#[repr($($r:tt)*)] pub struct $name:ident { $(pub $field:ident: $ty:ty,)* } $($rest:tt)*) => ( + #[repr($($r)*)] + #[cfg(not(feature = "verify-winapi"))] + #[derive(Copy, Clone)] + pub struct $name { + $(pub $field: $ty,)* + } + + #[cfg(feature = "verify-winapi")] + pub use self::winapi::$name; + + #[test] + #[cfg(feature = "verify-winapi")] + fn $name() { + use core::mem; + + #[repr($($r)*)] + pub struct $name { + $(pub $field: $ty,)* + } + + assert_eq!( + mem::size_of::<$name>(), + mem::size_of::(), + concat!("size of ", stringify!($name), " is wrong"), + ); + assert_eq!( + mem::align_of::<$name>(), + mem::align_of::(), + concat!("align of ", stringify!($name), " is wrong"), + ); + + type Winapi = winapi::$name; + + fn assert_same(_: T, _: T) {} + + unsafe { + let a = &*(mem::align_of::<$name>() as *const $name); + let b = &*(mem::align_of::() as *const Winapi); + + $( + ffi!(@test_fields a b $field $ty); + )* + } + } + + ffi!($($rest)*); + ); + + // Handling verification against unions in winapi requires some special care + (@test_fields $a:ident $b:ident FltSave $ty:ty) => ( + // Skip this field on x86_64 `CONTEXT` since it's a union and a bit funny + ); + (@test_fields $a:ident $b:ident D $ty:ty) => ({ + let a = &$a.D; + let b = $b.D(); + assert_same(a, b); + assert_eq!(a as *const $ty, b as *const $ty, "misplaced field D"); + }); + (@test_fields $a:ident $b:ident s $ty:ty) => ({ + let a = &$a.s; + let b = $b.s(); + assert_same(a, b); + assert_eq!(a as *const $ty, b as *const $ty, "misplaced field s"); + }); + + // Otherwise test all fields normally. + (@test_fields $a:ident $b:ident $field:ident $ty:ty) => ({ + let a = &$a.$field; + let b = &$b.$field; + assert_same(a, b); + assert_eq!(a as *const $ty, b as *const $ty, + concat!("misplaced field ", stringify!($field))); + }); + + (pub type $name:ident = $ty:ty; $($rest:tt)*) => ( + pub type $name = $ty; + + #[cfg(feature = "verify-winapi")] + #[allow(dead_code)] + const $name: () = { + fn _foo() { + trait SameType {} + impl SameType for (T, T) {} + fn assert_same() {} + + assert_same::<($name, winapi::$name)>(); + } + }; + + ffi!($($rest)*); + ); + + (pub const $name:ident: $ty:ty = $val:expr; $($rest:tt)*) => ( + pub const $name: $ty = $val; + + #[cfg(feature = "verify-winapi")] + #[allow(unused_imports)] + mod $name { + use super::*; + #[test] + fn assert_valid() { + let x: $ty = winapi::$name; + assert_eq!(x, $val); + } + } + + + ffi!($($rest)*); + ); + + (extern "system" { $(pub fn $name:ident($($args:tt)*) -> $ret:ty;)* } $($rest:tt)*) => ( + extern "system" { + $(pub fn $name($($args)*) -> $ret;)* + } + + $( + #[cfg(feature = "verify-winapi")] + mod $name { + #[test] + fn assert_same() { + use super::*; + + assert_eq!($name as usize, winapi::$name as usize); + let mut x: unsafe extern "system" fn($($args)*) -> $ret; + x = $name; + drop(x); + x = winapi::$name; + drop(x); + } + } + )* + + ffi!($($rest)*); + ); + + (impl $name:ident { $($i:tt)* } $($rest:tt)*) => ( + #[cfg(not(feature = "verify-winapi"))] + impl $name { + $($i)* + } + + ffi!($($rest)*); + ); +} + +ffi! { + #[repr(C)] + pub struct STACKFRAME64 { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: PVOID, + pub Params: [DWORD64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [DWORD64; 3], + pub KdHelp: KDHELP64, + } + + pub type LPSTACKFRAME64 = *mut STACKFRAME64; + + #[repr(C)] + pub struct STACKFRAME_EX { + pub AddrPC: ADDRESS64, + pub AddrReturn: ADDRESS64, + pub AddrFrame: ADDRESS64, + pub AddrStack: ADDRESS64, + pub AddrBStore: ADDRESS64, + pub FuncTableEntry: PVOID, + pub Params: [DWORD64; 4], + pub Far: BOOL, + pub Virtual: BOOL, + pub Reserved: [DWORD64; 3], + pub KdHelp: KDHELP64, + pub StackFrameSize: DWORD, + pub InlineFrameContext: DWORD, + } + + pub type LPSTACKFRAME_EX = *mut STACKFRAME_EX; + + #[repr(C)] + pub struct IMAGEHLP_LINEW64 { + pub SizeOfStruct: DWORD, + pub Key: PVOID, + pub LineNumber: DWORD, + pub FileName: PWSTR, + pub Address: DWORD64, + } + + pub type PIMAGEHLP_LINEW64 = *mut IMAGEHLP_LINEW64; + + #[repr(C)] + pub struct SYMBOL_INFOW { + pub SizeOfStruct: ULONG, + pub TypeIndex: ULONG, + pub Reserved: [ULONG64; 2], + pub Index: ULONG, + pub Size: ULONG, + pub ModBase: ULONG64, + pub Flags: ULONG, + pub Value: ULONG64, + pub Address: ULONG64, + pub Register: ULONG, + pub Scope: ULONG, + pub Tag: ULONG, + pub NameLen: ULONG, + pub MaxNameLen: ULONG, + pub Name: [WCHAR; 1], + } + + pub type PSYMBOL_INFOW = *mut SYMBOL_INFOW; + + pub type PTRANSLATE_ADDRESS_ROUTINE64 = Option< + unsafe extern "system" fn(hProcess: HANDLE, hThread: HANDLE, lpaddr: LPADDRESS64) -> DWORD64, + >; + pub type PGET_MODULE_BASE_ROUTINE64 = + Option DWORD64>; + pub type PFUNCTION_TABLE_ACCESS_ROUTINE64 = + Option PVOID>; + pub type PREAD_PROCESS_MEMORY_ROUTINE64 = Option< + unsafe extern "system" fn( + hProcess: HANDLE, + qwBaseAddress: DWORD64, + lpBuffer: PVOID, + nSize: DWORD, + lpNumberOfBytesRead: LPDWORD, + ) -> BOOL, + >; + + #[repr(C)] + pub struct ADDRESS64 { + pub Offset: DWORD64, + pub Segment: WORD, + pub Mode: ADDRESS_MODE, + } + + pub type LPADDRESS64 = *mut ADDRESS64; + + pub type ADDRESS_MODE = u32; + + #[repr(C)] + pub struct KDHELP64 { + pub Thread: DWORD64, + pub ThCallbackStack: DWORD, + pub ThCallbackBStore: DWORD, + pub NextCallback: DWORD, + pub FramePointer: DWORD, + pub KiCallUserMode: DWORD64, + pub KeUserCallbackDispatcher: DWORD64, + pub SystemRangeStart: DWORD64, + pub KiUserExceptionDispatcher: DWORD64, + pub StackBase: DWORD64, + pub StackLimit: DWORD64, + pub BuildVersion: DWORD, + pub Reserved0: DWORD, + pub Reserved1: [DWORD64; 4], + } + + pub const MAX_SYM_NAME: usize = 2000; + pub const AddrModeFlat: ADDRESS_MODE = 3; + pub const TRUE: BOOL = 1; + pub const FALSE: BOOL = 0; + pub const PROCESS_QUERY_INFORMATION: DWORD = 0x400; + pub const IMAGE_FILE_MACHINE_ARM64: u16 = 43620; + pub const IMAGE_FILE_MACHINE_AMD64: u16 = 34404; + pub const IMAGE_FILE_MACHINE_I386: u16 = 332; + pub const IMAGE_FILE_MACHINE_ARMNT: u16 = 452; + pub const FILE_SHARE_READ: DWORD = 0x1; + pub const FILE_SHARE_WRITE: DWORD = 0x2; + pub const OPEN_EXISTING: DWORD = 0x3; + pub const GENERIC_READ: DWORD = 0x80000000; + + pub type DWORD = u32; + pub type PDWORD = *mut u32; + pub type BOOL = i32; + pub type DWORD64 = u64; + pub type PDWORD64 = *mut u64; + pub type HANDLE = *mut c_void; + pub type PVOID = HANDLE; + pub type PCWSTR = *const u16; + pub type LPSTR = *mut i8; + pub type LPCSTR = *const i8; + pub type PWSTR = *mut u16; + pub type WORD = u16; + pub type ULONG = u32; + pub type ULONG64 = u64; + pub type WCHAR = u16; + pub type PCONTEXT = *mut CONTEXT; + pub type LPDWORD = *mut DWORD; + pub type DWORDLONG = u64; + pub type HMODULE = HINSTANCE; + + extern "system" { + pub fn GetCurrentProcess() -> HANDLE; + pub fn GetCurrentThread() -> HANDLE; + pub fn RtlCaptureContext(ContextRecord: PCONTEXT) -> (); + pub fn LoadLibraryA(a: *const i8) -> HMODULE; + pub fn FreeLibrary(h: HMODULE) -> BOOL; + pub fn GetProcAddress(h: HMODULE, name: *const i8) -> FARPROC; + pub fn OpenProcess( + dwDesiredAccess: DWORD, + bInheitHandle: BOOL, + dwProcessId: DWORD, + ) -> HANDLE; + pub fn GetCurrentProcessId() -> DWORD; + pub fn CloseHandle(h: HANDLE) -> BOOL; + pub fn QueryFullProcessImageNameA( + hProcess: HANDLE, + dwFlags: DWORD, + lpExeName: LPSTR, + lpdwSize: PDWORD, + ) -> BOOL; + pub fn CreateFileA( + lpFileName: LPCSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + ) -> HANDLE; + } +} + +#[cfg(target_arch = "aarch64")] +ffi! { + #[repr(C, align(16))] + pub struct CONTEXT { + pub ContextFlags: DWORD, + pub Cpsr: DWORD, + pub u: CONTEXT_u, + pub Sp: u64, + pub Pc: u64, + pub V: [ARM64_NT_NEON128; 32], + pub Fpcr: DWORD, + pub Fpsr: DWORD, + pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Bvr: [DWORD64; ARM64_MAX_BREAKPOINTS], + pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], + pub Wvr: [DWORD64; ARM64_MAX_WATCHPOINTS], + } + + #[repr(C)] + pub struct CONTEXT_u { + pub s: CONTEXT_u_s, + } + + impl CONTEXT_u { + pub unsafe fn s(&self) -> &CONTEXT_u_s { + &self.s + } + } + + #[repr(C)] + pub struct CONTEXT_u_s { + pub X0: u64, + pub X1: u64, + pub X2: u64, + pub X3: u64, + pub X4: u64, + pub X5: u64, + pub X6: u64, + pub X7: u64, + pub X8: u64, + pub X9: u64, + pub X10: u64, + pub X11: u64, + pub X12: u64, + pub X13: u64, + pub X14: u64, + pub X15: u64, + pub X16: u64, + pub X17: u64, + pub X18: u64, + pub X19: u64, + pub X20: u64, + pub X21: u64, + pub X22: u64, + pub X23: u64, + pub X24: u64, + pub X25: u64, + pub X26: u64, + pub X27: u64, + pub X28: u64, + pub Fp: u64, + pub Lr: u64, + } + + pub const ARM64_MAX_BREAKPOINTS: usize = 8; + pub const ARM64_MAX_WATCHPOINTS: usize = 2; + + #[repr(C)] + pub struct ARM64_NT_NEON128 { + pub D: [f64; 2], + } +} + +#[cfg(target_arch = "x86")] +ffi! { + #[repr(C)] + pub struct CONTEXT { + pub ContextFlags: DWORD, + pub Dr0: DWORD, + pub Dr1: DWORD, + pub Dr2: DWORD, + pub Dr3: DWORD, + pub Dr6: DWORD, + pub Dr7: DWORD, + pub FloatSave: FLOATING_SAVE_AREA, + pub SegGs: DWORD, + pub SegFs: DWORD, + pub SegEs: DWORD, + pub SegDs: DWORD, + pub Edi: DWORD, + pub Esi: DWORD, + pub Ebx: DWORD, + pub Edx: DWORD, + pub Ecx: DWORD, + pub Eax: DWORD, + pub Ebp: DWORD, + pub Eip: DWORD, + pub SegCs: DWORD, + pub EFlags: DWORD, + pub Esp: DWORD, + pub SegSs: DWORD, + pub ExtendedRegisters: [u8; 512], + } + + #[repr(C)] + pub struct FLOATING_SAVE_AREA { + pub ControlWord: DWORD, + pub StatusWord: DWORD, + pub TagWord: DWORD, + pub ErrorOffset: DWORD, + pub ErrorSelector: DWORD, + pub DataOffset: DWORD, + pub DataSelector: DWORD, + pub RegisterArea: [u8; 80], + pub Spare0: DWORD, + } +} + +#[cfg(target_arch = "x86_64")] +ffi! { + #[repr(C, align(8))] + pub struct CONTEXT { + pub P1Home: DWORDLONG, + pub P2Home: DWORDLONG, + pub P3Home: DWORDLONG, + pub P4Home: DWORDLONG, + pub P5Home: DWORDLONG, + pub P6Home: DWORDLONG, + + pub ContextFlags: DWORD, + pub MxCsr: DWORD, + + pub SegCs: WORD, + pub SegDs: WORD, + pub SegEs: WORD, + pub SegFs: WORD, + pub SegGs: WORD, + pub SegSs: WORD, + pub EFlags: DWORD, + + pub Dr0: DWORDLONG, + pub Dr1: DWORDLONG, + pub Dr2: DWORDLONG, + pub Dr3: DWORDLONG, + pub Dr6: DWORDLONG, + pub Dr7: DWORDLONG, + + pub Rax: DWORDLONG, + pub Rcx: DWORDLONG, + pub Rdx: DWORDLONG, + pub Rbx: DWORDLONG, + pub Rsp: DWORDLONG, + pub Rbp: DWORDLONG, + pub Rsi: DWORDLONG, + pub Rdi: DWORDLONG, + pub R8: DWORDLONG, + pub R9: DWORDLONG, + pub R10: DWORDLONG, + pub R11: DWORDLONG, + pub R12: DWORDLONG, + pub R13: DWORDLONG, + pub R14: DWORDLONG, + pub R15: DWORDLONG, + + pub Rip: DWORDLONG, + + pub FltSave: FLOATING_SAVE_AREA, + + pub VectorRegister: [M128A; 26], + pub VectorControl: DWORDLONG, + + pub DebugControl: DWORDLONG, + pub LastBranchToRip: DWORDLONG, + pub LastBranchFromRip: DWORDLONG, + pub LastExceptionToRip: DWORDLONG, + pub LastExceptionFromRip: DWORDLONG, + } + + #[repr(C)] + pub struct M128A { + pub Low: u64, + pub High: i64, + } +} + +#[repr(C)] +#[cfg(target_arch = "x86_64")] +#[derive(Copy, Clone)] +pub struct FLOATING_SAVE_AREA { + _Dummy: [u8; 512], +} + +#[cfg(target_arch = "arm")] +ffi! { + // #[repr(C)] + // pub struct NEON128 { + // pub Low: ULONG64, + // pub High: LONG64, + // } + + // pub type PNEON128 = *mut NEON128; + + #[repr(C)] + pub struct CONTEXT_u { + // pub Q: [NEON128; 16], + pub D: [ULONG64; 32], + // pub S: [DWORD; 32], + } + + pub const ARM_MAX_BREAKPOINTS: usize = 8; + pub const ARM_MAX_WATCHPOINTS: usize = 1; + + #[repr(C)] + pub struct CONTEXT { + pub ContextFlags: DWORD, + pub R0: DWORD, + pub R1: DWORD, + pub R2: DWORD, + pub R3: DWORD, + pub R4: DWORD, + pub R5: DWORD, + pub R6: DWORD, + pub R7: DWORD, + pub R8: DWORD, + pub R9: DWORD, + pub R10: DWORD, + pub R11: DWORD, + pub R12: DWORD, + pub Sp: DWORD, + pub Lr: DWORD, + pub Pc: DWORD, + pub Cpsr: DWORD, + pub Fpsrc: DWORD, + pub Padding: DWORD, + pub u: CONTEXT_u, + pub Bvr: [DWORD; ARM_MAX_BREAKPOINTS], + pub Bcr: [DWORD; ARM_MAX_BREAKPOINTS], + pub Wvr: [DWORD; ARM_MAX_WATCHPOINTS], + pub Wcr: [DWORD; ARM_MAX_WATCHPOINTS], + pub Padding2: [DWORD; 2], + } +} // IFDEF(arm) diff --git a/backtrace/tests/long_fn_name.rs b/backtrace/tests/long_fn_name.rs new file mode 100644 index 000000000..834c4c06c --- /dev/null +++ b/backtrace/tests/long_fn_name.rs @@ -0,0 +1,50 @@ +extern crate backtrace; + +use backtrace::Backtrace; + +// 50-character module name +mod _234567890_234567890_234567890_234567890_234567890 { + // 50-character struct name + #[allow(non_camel_case_types)] + pub struct _234567890_234567890_234567890_234567890_234567890(T); + impl _234567890_234567890_234567890_234567890_234567890 { + #[allow(dead_code)] + pub fn new() -> ::Backtrace { + ::Backtrace::new() + } + } +} + +// Long function names must be truncated to (MAX_SYM_NAME - 1) characters. +// Only run this test for msvc, since gnu prints "" for all frames. +#[test] +#[cfg(all(windows, feature = "dbghelp", target_env = "msvc"))] +fn test_long_fn_name() { + use _234567890_234567890_234567890_234567890_234567890::_234567890_234567890_234567890_234567890_234567890 as S; + + // 10 repetitions of struct name, so fully qualified function name is + // atleast 10 * (50 + 50) * 2 = 2000 characters long. + // It's actually longer since it also includes `::`, `<>` and the + // name of the current module + let bt = S::>>>>>>>>>::new(); + println!("{:?}", bt); + + let mut found_long_name_frame = false; + + for frame in bt.frames() { + let symbols = frame.symbols(); + if symbols.is_empty() { + continue; + } + + if let Some(function_name) = symbols[0].name() { + let function_name = function_name.as_str().unwrap(); + if function_name.contains("::_234567890_234567890_234567890_234567890_234567890") { + found_long_name_frame = true; + assert!(function_name.len() > 200); + } + } + } + + assert!(found_long_name_frame); +} diff --git a/backtrace/tests/skip_inner_frames.rs b/backtrace/tests/skip_inner_frames.rs new file mode 100644 index 000000000..5c2bfc05e --- /dev/null +++ b/backtrace/tests/skip_inner_frames.rs @@ -0,0 +1,55 @@ +extern crate backtrace; + +use backtrace::Backtrace; + +const FRAME_RANGE: usize = 128; // should be close enough not to give false positives + +#[test] +#[cfg_attr( + any( + not(any( + all(unix, feature = "libunwind", feature = "unix-backtrace"), + all(windows, feature = "dbghelp") + )), + all(target_os = "windows", target_arch = "x86") + ), + ignore +)] +fn backtrace_new_unresolved_should_start_with_call_site_trace() { + let mut b = Backtrace::new_unresolved(); + b.resolve(); + println!("{:?}", b); + println!("{:#?}", b); + + assert!(!b.frames().is_empty()); + + let this_ip = backtrace_new_unresolved_should_start_with_call_site_trace as usize; + let frame_ip = b.frames().first().unwrap().ip() as usize; + + assert!(frame_ip >= this_ip); + assert!(frame_ip <= this_ip + FRAME_RANGE); +} + +#[test] +#[cfg_attr( + any( + not(any( + all(unix, feature = "libunwind", feature = "unix-backtrace"), + all(feature = "dbghelp", windows) + )), + all(target_os = "windows", target_arch = "x86") + ), + ignore +)] +fn backtrace_new_should_start_with_call_site_trace() { + let b = Backtrace::new(); + println!("{:?}", b); + + assert!(!b.frames().is_empty()); + + let this_ip = backtrace_new_should_start_with_call_site_trace as usize; + let frame_ip = b.frames().first().unwrap().ip() as usize; + + assert!(frame_ip >= this_ip); + assert!(frame_ip <= this_ip + FRAME_RANGE); +} diff --git a/backtrace/tests/smoke.rs b/backtrace/tests/smoke.rs new file mode 100644 index 000000000..c073a8c1f --- /dev/null +++ b/backtrace/tests/smoke.rs @@ -0,0 +1,230 @@ +extern crate backtrace; + +use backtrace::Frame; +use std::thread; + +static LIBUNWIND: bool = cfg!(all(unix, feature = "libunwind")); +static UNIX_BACKTRACE: bool = cfg!(all(unix, feature = "unix-backtrace")); +static LIBBACKTRACE: bool = cfg!(feature = "libbacktrace") + && !cfg!(target_os = "fuchsia"); +static CORESYMBOLICATION: bool = cfg!(all( + any(target_os = "macos", target_os = "ios"), + feature = "coresymbolication" +)); +static DLADDR: bool = cfg!(all(unix, feature = "dladdr")) && !cfg!(target_os = "fuchsia"); +static DBGHELP: bool = cfg!(all(windows, feature = "dbghelp")); +static MSVC: bool = cfg!(target_env = "msvc"); +static GIMLI_SYMBOLIZE: bool = cfg!(all(feature = "gimli-symbolize", unix, target_os = "linux")); + +#[test] +// FIXME: shouldn't ignore this test on i686-msvc, unsure why it's failing +#[cfg_attr(all(target_arch = "x86", target_env = "msvc"), ignore)] +#[rustfmt::skip] // we care about line numbers here +fn smoke_test_frames() { + frame_1(line!()); + #[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) } + #[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) } + #[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) } + #[inline(never)] fn frame_4(start_line: u32) { + let mut v = Vec::new(); + backtrace::trace(|cx| { + v.push(cx.clone()); + true + }); + + if v.len() < 5 { + assert!(!LIBUNWIND); + assert!(!UNIX_BACKTRACE); + assert!(!DBGHELP); + return; + } + + // Various platforms have various bits of weirdness about their + // backtraces. To find a good starting spot let's search through the + // frames + let target = frame_4 as usize; + let offset = v + .iter() + .map(|frame| frame.symbol_address() as usize) + .enumerate() + .filter_map(|(i, sym)| { + if sym >= target { + Some((sym, i)) + } else { + None + } + }) + .min() + .unwrap() + .1; + let mut frames = v[offset..].iter(); + + assert_frame( + frames.next().unwrap(), + frame_4 as usize, + "frame_4", + "tests/smoke.rs", + start_line + 6, + ); + assert_frame( + frames.next().unwrap(), + frame_3 as usize, + "frame_3", + "tests/smoke.rs", + start_line + 3, + ); + assert_frame( + frames.next().unwrap(), + frame_2 as usize, + "frame_2", + "tests/smoke.rs", + start_line + 2, + ); + assert_frame( + frames.next().unwrap(), + frame_1 as usize, + "frame_1", + "tests/smoke.rs", + start_line + 1, + ); + assert_frame( + frames.next().unwrap(), + smoke_test_frames as usize, + "smoke_test_frames", + "", + 0, + ); + } + + fn assert_frame( + frame: &Frame, + actual_fn_pointer: usize, + expected_name: &str, + expected_file: &str, + expected_line: u32, + ) { + let ip = frame.ip() as usize; + let sym = frame.symbol_address() as usize; + assert!(ip >= sym); + assert!(sym >= actual_fn_pointer); + + // windows dbghelp is *quite* liberal (and wrong) in many of its reports + // right now... + // + // This assertion can also fail for release builds, so skip it there + if !DBGHELP && cfg!(debug_assertions) { + assert!(sym - actual_fn_pointer < 1024); + } + + let mut resolved = 0; + let can_resolve = DLADDR || LIBBACKTRACE || CORESYMBOLICATION || DBGHELP || GIMLI_SYMBOLIZE; + + let mut name = None; + let mut addr = None; + let mut line = None; + let mut file = None; + backtrace::resolve_frame(frame, |sym| { + resolved += 1; + name = sym.name().map(|v| v.to_string()); + addr = sym.addr(); + line = sym.lineno(); + file = sym.filename().map(|v| v.to_path_buf()); + println!(" sym: {:?}", name); + }); + + // dbghelp doesn't always resolve symbols right now + match resolved { + 0 => return assert!(!can_resolve || DBGHELP), + _ => {} + } + + // * linux dladdr doesn't work (only consults local symbol table) + // * windows dbghelp isn't great for GNU + if can_resolve && !(cfg!(target_os = "linux") && DLADDR) && !(DBGHELP && !MSVC) { + let name = name.expect("didn't find a name"); + + // in release mode names get weird as functions can get merged + // together with `mergefunc`, so only assert this in debug mode + if cfg!(debug_assertions) { + assert!( + name.contains(expected_name), + "didn't find `{}` in `{}`", + expected_name, + name + ); + } + } + + if can_resolve { + addr.expect("didn't find a symbol"); + } + + if (LIBBACKTRACE || CORESYMBOLICATION || (DBGHELP && MSVC)) && cfg!(debug_assertions) { + let line = line.expect("didn't find a line number"); + let file = file.expect("didn't find a line number"); + if !expected_file.is_empty() { + assert!( + file.ends_with(expected_file), + "{:?} didn't end with {:?}", + file, + expected_file + ); + } + if expected_line != 0 { + assert!( + line == expected_line, + "bad line number on frame for `{}`: {} != {}", + expected_name, + line, + expected_line + ); + } + } + } +} + +#[test] +fn many_threads() { + let threads = (0..16) + .map(|_| { + thread::spawn(|| { + for _ in 0..16 { + backtrace::trace(|frame| { + backtrace::resolve(frame.ip(), |symbol| { + let _s = symbol.name().map(|s| s.to_string()); + }); + true + }); + } + }) + }) + .collect::>(); + + for t in threads { + t.join().unwrap() + } +} + +#[test] +#[cfg(feature = "rustc-serialize")] +fn is_rustc_serialize() { + extern crate rustc_serialize; + + fn is_encode() {} + fn is_decode() {} + + is_encode::(); + is_decode::(); +} + +#[test] +#[cfg(feature = "serde")] +fn is_serde() { + extern crate serde; + + fn is_serialize() {} + fn is_deserialize() {} + + is_serialize::(); + is_deserialize::(); +} diff --git a/bit-set/.cargo-checksum.json b/bit-set/.cargo-checksum.json new file mode 100644 index 000000000..212c5edfb --- /dev/null +++ b/bit-set/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"} \ No newline at end of file diff --git a/bit-set/Cargo.toml b/bit-set/Cargo.toml new file mode 100644 index 000000000..46e42c459 --- /dev/null +++ b/bit-set/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bit-set" +version = "0.5.1" +authors = ["Alexis Beingessner "] +description = "A set of bits" +homepage = "https://github.com/contain-rs/bit-set" +documentation = "https://contain-rs.github.io/bit-set/bit_set" +readme = "README.md" +keywords = ["data-structures", "bitset"] +license = "MIT/Apache-2.0" +repository = "https://github.com/contain-rs/bit-set" +[dependencies.bit-vec] +version = "0.5.0" +default-features = false +[dev-dependencies.rand] +version = "0.3" + +[features] +default = ["std"] +nightly = ["bit-vec/nightly"] +std = ["bit-vec/std"] diff --git a/bit-set/LICENSE-APACHE b/bit-set/LICENSE-APACHE new file mode 100644 index 000000000..11069edd7 --- /dev/null +++ b/bit-set/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bit-set/LICENSE-MIT b/bit-set/LICENSE-MIT new file mode 100644 index 000000000..40b8817a4 --- /dev/null +++ b/bit-set/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bit-set/README.md b/bit-set/README.md new file mode 100644 index 000000000..367e4253a --- /dev/null +++ b/bit-set/README.md @@ -0,0 +1,17 @@ +**WARNING: THIS PROJECT IS IN MAINTENANCE MODE, DUE TO INSUFFICIENT MAINTAINER RESOURCES** + +It works fine, but will generally no longer be improved. + +We are currently only accepting changes which: + +* keep this compiling with the latest versions of Rust or its dependencies. +* have minimal review requirements, such as documentation changes (so not totally new APIs). + +------ + +A Set of bits. + +Documentation is available at https://contain-rs.github.io/bit-set/bit_set. + +[![Build Status](https://travis-ci.org/contain-rs/bit-set.svg?branch=master)](https://travis-ci.org/contain-rs/bit-set) +[![crates.io](http://meritbadge.herokuapp.com/bit-set)](https://crates.io/crates/bit-set) diff --git a/bit-set/deploy-docs.sh b/bit-set/deploy-docs.sh new file mode 100755 index 000000000..c8f25ee86 --- /dev/null +++ b/bit-set/deploy-docs.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -o errexit -o nounset + +rev=$(git rev-parse --short HEAD) + +cd target/doc + +git init +git config user.email 'FlashCat@users.noreply.github.com' +git config user.name 'FlashCat' +git remote add upstream "https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git" +git fetch upstream gh-pages +git reset upstream/gh-pages + +touch . + +git add -A . +git commit -m "rebuild pages at ${rev}" +git push -q upstream HEAD:gh-pages diff --git a/bit-set/src/lib.rs b/bit-set/src/lib.rs new file mode 100644 index 000000000..9259adcc3 --- /dev/null +++ b/bit-set/src/lib.rs @@ -0,0 +1,1443 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An implementation of a set using a bit vector as an underlying +//! representation for holding unsigned numerical elements. +//! +//! It should also be noted that the amount of storage necessary for holding a +//! set of objects is proportional to the maximum of the objects when viewed +//! as a `usize`. +//! +//! # Examples +//! +//! ``` +//! use bit_set::BitSet; +//! +//! // It's a regular set +//! let mut s = BitSet::new(); +//! s.insert(0); +//! s.insert(3); +//! s.insert(7); +//! +//! s.remove(7); +//! +//! if !s.contains(7) { +//! println!("There is no 7"); +//! } +//! +//! // Can initialize from a `BitVec` +//! let other = BitSet::from_bytes(&[0b11010000]); +//! +//! s.union_with(&other); +//! +//! // Print 0, 1, 3 in some order +//! for x in s.iter() { +//! println!("{}", x); +//! } +//! +//! // Can convert back to a `BitVec` +//! let bv = s.into_bit_vec(); +//! assert!(bv[3]); +//! ``` + +#![no_std] + +#![cfg_attr(all(test, feature = "nightly"), feature(test))] +#[cfg(all(test, feature = "nightly"))] extern crate test; +#[cfg(all(test, feature = "nightly"))] extern crate rand; +extern crate bit_vec; + +#[cfg(test)] +#[macro_use] +extern crate std; + +use bit_vec::{BitVec, Blocks, BitBlock}; +use core::cmp::Ordering; +use core::cmp; +use core::fmt; +use core::hash; +use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take}; + +type MatchWords<'a, B> = Chain>, Skip>>>>; + +/// Computes how many blocks are needed to store that many bits +fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::bits() == 0 { + bits / B::bits() + } else { + bits / B::bits() + 1 + } +} + +// Take two BitVec's, and return iterators of their words, where the shorter one +// has been padded with 0's +fn match_words<'a, 'b, B: BitBlock>(a: &'a BitVec, b: &'b BitVec) + -> (MatchWords<'a, B>, MatchWords<'b, B>) +{ + let a_len = a.storage().len(); + let b_len = b.storage().len(); + + // have to uselessly pretend to pad the longer one for type matching + if a_len < b_len { + (a.blocks().enumerate().chain(iter::repeat(B::zero()).enumerate().take(b_len).skip(a_len)), + b.blocks().enumerate().chain(iter::repeat(B::zero()).enumerate().take(0).skip(0))) + } else { + (a.blocks().enumerate().chain(iter::repeat(B::zero()).enumerate().take(0).skip(0)), + b.blocks().enumerate().chain(iter::repeat(B::zero()).enumerate().take(a_len).skip(b_len))) + } +} + +pub struct BitSet { + bit_vec: BitVec, +} + +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { + bit_vec: self.bit_vec.clone(), + } + } + + fn clone_from(&mut self, other: &Self) { + self.bit_vec.clone_from(&other.bit_vec); + } +} + +impl Default for BitSet { + #[inline] + fn default() -> Self { BitSet { bit_vec: Default::default() } } +} + +impl FromIterator for BitSet { + fn from_iter>(iter: I) -> Self { + let mut ret = Self::default(); + ret.extend(iter); + ret + } +} + +impl Extend for BitSet { + #[inline] + fn extend>(&mut self, iter: I) { + for i in iter { + self.insert(i); + } + } +} + +impl PartialOrd for BitSet { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +impl Ord for BitSet { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +impl PartialEq for BitSet { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other) + } +} + +impl Eq for BitSet {} + +impl BitSet { + /// Creates a new empty `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Creates a new `BitSet` with initially no contents, able to + /// hold `nbits` elements without resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity(nbits: usize) -> Self { + let bit_vec = BitVec::from_elem(nbits, false); + Self::from_bit_vec(bit_vec) + } + + /// Creates a new `BitSet` from the given bit vector. + /// + /// # Examples + /// + /// ``` + /// extern crate bit_vec; + /// extern crate bit_set; + /// + /// fn main() { + /// use bit_vec::BitVec; + /// use bit_set::BitSet; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// let s = BitSet::from_bit_vec(bv); + /// + /// // Print 1, 2 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// } + /// ``` + #[inline] + pub fn from_bit_vec(bit_vec: BitVec) -> Self { + BitSet { bit_vec: bit_vec } + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + BitSet { bit_vec: BitVec::from_bytes(bytes) } + } +} + +impl BitSet { + + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::with_capacity(100); + /// assert!(s.capacity() >= 100); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.bit_vec.capacity() + } + + /// Reserves capacity for the given `BitSet` to contain `len` distinct elements. In the case + /// of `BitSet` this means reallocations will not occur as long as all inserted elements + /// are less than `len`. + /// + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve(len - cur_len); + } + } + + /// Reserves the minimum capacity for the given `BitSet` to contain `len` distinct elements. + /// In the case of `BitSet` this means reallocations will not occur as long as all inserted + /// elements are less than `len`. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer `reserve_len` if future + /// insertions are expected. + /// + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.reserve_len_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` + pub fn reserve_len_exact(&mut self, len: usize) { + let cur_len = self.bit_vec.len(); + if len >= cur_len { + self.bit_vec.reserve_exact(len - cur_len); + } + } + + /// Consumes this set to return the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(0); + /// s.insert(3); + /// + /// let bv = s.into_bit_vec(); + /// assert!(bv[0]); + /// assert!(bv[3]); + /// ``` + #[inline] + pub fn into_bit_vec(self) -> BitVec { + self.bit_vec + } + + /// Returns a reference to the underlying bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(0); + /// + /// let bv = s.get_ref(); + /// assert_eq!(bv[0], true); + /// ``` + #[inline] + pub fn get_ref(&self) -> &BitVec { + &self.bit_vec + } + + #[inline] + fn other_op(&mut self, other: &Self, mut f: F) where F: FnMut(B, B) -> B { + // Unwrap BitVecs + let self_bit_vec = &mut self.bit_vec; + let other_bit_vec = &other.bit_vec; + + let self_len = self_bit_vec.len(); + let other_len = other_bit_vec.len(); + + // Expand the vector if necessary + if self_len < other_len { + self_bit_vec.grow(other_len - self_len, false); + } + + // virtually pad other with 0's for equal lengths + let other_words = { + let (_, result) = match_words(self_bit_vec, other_bit_vec); + result + }; + + // Apply values found in other + for (i, w) in other_words { + let old = self_bit_vec.storage()[i]; + let new = f(old, w); + unsafe { + self_bit_vec.storage_mut()[i] = new; + } + } + } + + /// Truncates the underlying vector to the least length required. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut s = BitSet::new(); + /// s.insert(32183231); + /// s.remove(32183231); + /// + /// // Internal storage will probably be bigger than necessary + /// println!("old capacity: {}", s.capacity()); + /// + /// // Now should be smaller + /// s.shrink_to_fit(); + /// println!("new capacity: {}", s.capacity()); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + let bit_vec = &mut self.bit_vec; + // Obtain original length + let old_len = bit_vec.storage().len(); + // Obtain coarse trailing zero length + let n = bit_vec.storage().iter().rev().take_while(|&&n| n == B::zero()).count(); + // Truncate + let trunc_len = cmp::max(old_len - n, 1); + unsafe { + bit_vec.storage_mut().truncate(trunc_len); + bit_vec.set_len(trunc_len * B::bits()); + } + } + + /// Iterator over each usize stored in the `BitSet`. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let s = BitSet::from_bytes(&[0b01001010]); + /// + /// // Print 1, 4, 6 in arbitrary order + /// for x in s.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn iter(&self) -> Iter { + Iter(BlockIter::from_blocks(self.bit_vec.blocks())) + } + + /// Iterator over each usize stored in `self` union `other`. + /// See [union_with](#method.union_with) for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 2, 4 in arbitrary order + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, B> { + fn or(w1: B, w2: B) -> B { w1 | w2 } + + Union(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: or, + })) + } + + /// Iterator over each usize stored in `self` intersect `other`. + /// See [intersect_with](#method.intersect_with) for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 2 + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, B> { + fn bitand(w1: B, w2: B) -> B { w1 & w2 } + let min = cmp::min(self.bit_vec.len(), other.bit_vec.len()); + + Intersection(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitand, + }).take(min)) + } + + /// Iterator over each usize stored in the `self` setminus `other`. + /// See [difference_with](#method.difference_with) for an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 1, 4 in arbitrary order + /// for x in a.difference(&b) { + /// println!("{}", x); + /// } + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else. + /// // This prints 0 + /// for x in b.difference(&a) { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, B> { + fn diff(w1: B, w2: B) -> B { w1 & !w2 } + + Difference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: diff, + })) + } + + /// Iterator over each usize stored in the symmetric difference of `self` and `other`. + /// See [symmetric_difference_with](#method.symmetric_difference_with) for + /// an efficient in-place version. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = BitSet::from_bytes(&[0b01101000]); + /// let b = BitSet::from_bytes(&[0b10100000]); + /// + /// // Print 0, 1, 4 in arbitrary order + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, B> { + fn bitxor(w1: B, w2: B) -> B { w1 ^ w2 } + + SymmetricDifference(BlockIter::from_blocks(TwoBitPositions { + set: self.bit_vec.blocks(), + other: other.bit_vec.blocks(), + merge: bitxor, + })) + } + + /// Unions in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11101000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.union_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn union_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 | w2); + } + + /// Intersects in-place with the specified other bit vector. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b00100000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.intersect_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn intersect_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & w2); + } + + /// Makes this bit vector the difference with the specified other bit vector + /// in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let a_b = 0b01001000; // a - b + /// let b_a = 0b10000000; // b - a + /// + /// let mut bva = BitSet::from_bytes(&[a]); + /// let bvb = BitSet::from_bytes(&[b]); + /// let bva_b = BitSet::from_bytes(&[a_b]); + /// let bvb_a = BitSet::from_bytes(&[b_a]); + /// + /// bva.difference_with(&bvb); + /// assert_eq!(bva, bva_b); + /// + /// let bva = BitSet::from_bytes(&[a]); + /// let mut bvb = BitSet::from_bytes(&[b]); + /// + /// bvb.difference_with(&bva); + /// assert_eq!(bvb, bvb_a); + /// ``` + #[inline] + pub fn difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 & !w2); + } + + /// Makes this bit vector the symmetric difference with the specified other + /// bit vector in-place. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let a = 0b01101000; + /// let b = 0b10100000; + /// let res = 0b11001000; + /// + /// let mut a = BitSet::from_bytes(&[a]); + /// let b = BitSet::from_bytes(&[b]); + /// let res = BitSet::from_bytes(&[res]); + /// + /// a.symmetric_difference_with(&b); + /// assert_eq!(a, res); + /// ``` + #[inline] + pub fn symmetric_difference_with(&mut self, other: &Self) { + self.other_op(other, |w1, w2| w1 ^ w2); + } + +/* + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// + /// let mut b = BitSet::new(); + /// b.insert(1); + /// b.insert(3); + /// b.insert(6); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + /// ``` + pub fn append(&mut self, other: &mut Self) { + self.union_with(other); + other.clear(); + } + + /// Splits the `BitSet` into two at the given key including the key. + /// Retains the first part in-place while returning the second part. + /// + /// # Examples + /// + /// ``` + /// use bit_set::BitSet; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// a.insert(1); + /// a.insert(3); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 2); + /// assert_eq!(a, BitSet::from_bytes(&[0b01100000])); + /// assert_eq!(b, BitSet::from_bytes(&[0b00010010])); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = BitSet::new(); + + if at == 0 { + swap(self, &mut other); + return other; + } else if at >= self.bit_vec.len() { + return other; + } + + // Calculate block and bit at which to split + let w = at / BITS; + let b = at % BITS; + + // Pad `other` with `w` zero blocks, + // append `self`'s blocks in the range from `w` to the end to `other` + other.bit_vec.storage_mut().extend(repeat(0u32).take(w) + .chain(self.bit_vec.storage()[w..].iter().cloned())); + other.bit_vec.nbits = self.bit_vec.nbits; + + if b > 0 { + other.bit_vec.storage_mut()[w] &= !0 << b; + } + + // Sets `bit_vec.len()` and fixes the last block as well + self.bit_vec.truncate(at); + + other + } +*/ + + /// Returns the number of set bits in this set. + #[inline] + pub fn len(&self) -> usize { + self.bit_vec.blocks().fold(0, |acc, n| acc + n.count_ones() as usize) + } + + /// Returns whether there are no bits set in this set + #[inline] + pub fn is_empty(&self) -> bool { + self.bit_vec.none() + } + + /// Clears all bits in this set + #[inline] + pub fn clear(&mut self) { + self.bit_vec.clear(); + } + + /// Returns `true` if this set contains the specified integer. + #[inline] + pub fn contains(&self, value: usize) -> bool { + let bit_vec = &self.bit_vec; + value < bit_vec.len() && bit_vec[value] + } + + /// Returns `true` if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + #[inline] + pub fn is_disjoint(&self, other: &Self) -> bool { + self.intersection(other).next().is_none() + } + + /// Returns `true` if the set is a subset of another. + #[inline] + pub fn is_subset(&self, other: &Self) -> bool { + let self_bit_vec = &self.bit_vec; + let other_bit_vec = &other.bit_vec; + let other_blocks = blocks_for_bits::(other_bit_vec.len()); + + // Check that `self` intersect `other` is self + self_bit_vec.blocks().zip(other_bit_vec.blocks()).all(|(w1, w2)| w1 & w2 == w1) && + // Make sure if `self` has any more blocks than `other`, they're all 0 + self_bit_vec.blocks().skip(other_blocks).all(|w| w == B::zero()) + } + + /// Returns `true` if the set is a superset of another. + #[inline] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. Returns `true` if the value was not already + /// present in the set. + pub fn insert(&mut self, value: usize) -> bool { + if self.contains(value) { + return false; + } + + // Ensure we have enough space to hold the new element + let len = self.bit_vec.len(); + if value >= len { + self.bit_vec.grow(value - len + 1, false) + } + + self.bit_vec.set(value, true); + return true; + } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + pub fn remove(&mut self, value: usize) -> bool { + if !self.contains(value) { + return false; + } + + self.bit_vec.set(value, false); + + return true; + } +} + +impl fmt::Debug for BitSet { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set().entries(self).finish() + } +} + +impl hash::Hash for BitSet { + fn hash(&self, state: &mut H) { + for pos in self { + pos.hash(state); + } + } +} + +#[derive(Clone)] +struct BlockIter { + head: B, + head_offset: usize, + tail: T, +} + +impl BlockIter where T: Iterator { + fn from_blocks(mut blocks: T) -> BlockIter { + let h = blocks.next().unwrap_or(B::zero()); + BlockIter {tail: blocks, head: h, head_offset: 0} + } +} + +/// An iterator combining two `BitSet` iterators. +#[derive(Clone)] +struct TwoBitPositions<'a, B: 'a> { + set: Blocks<'a, B>, + other: Blocks<'a, B>, + merge: fn(B, B) -> B, +} + +/// An iterator for `BitSet`. +#[derive(Clone)] +pub struct Iter<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct Union<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct Intersection<'a, B: 'a>(Take, B>>); +#[derive(Clone)] +pub struct Difference<'a, B: 'a>(BlockIter, B>); +#[derive(Clone)] +pub struct SymmetricDifference<'a, B: 'a>(BlockIter, B>); + +impl<'a, T, B: BitBlock> Iterator for BlockIter where T: Iterator { + type Item = usize; + + fn next(&mut self) -> Option { + while self.head == B::zero() { + match self.tail.next() { + Some(w) => self.head = w, + None => return None + } + self.head_offset += B::bits(); + } + + // from the current block, isolate the + // LSB and subtract 1, producing k: + // a block with a number of set bits + // equal to the index of the LSB + let k = (self.head & (!self.head + B::one())) - B::one(); + // update block, removing the LSB + self.head = self.head & (self.head - B::one()); + // return offset + (index of LSB) + Some(self.head_offset + (B::count_ones(k) as usize)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + match self.tail.size_hint() { + (_, Some(h)) => (0, Some(1 + h * B::bits())), + _ => (0, None) + } + } +} + +impl<'a, B: BitBlock> Iterator for TwoBitPositions<'a, B> { + type Item = B; + + fn next(&mut self) -> Option { + match (self.set.next(), self.other.next()) { + (Some(a), Some(b)) => Some((self.merge)(a, b)), + (Some(a), None) => Some((self.merge)(a, B::zero())), + (None, Some(b)) => Some((self.merge)(B::zero(), b)), + _ => return None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (a, au) = self.set.size_hint(); + let (b, bu) = self.other.size_hint(); + + let upper = match (au, bu) { + (Some(au), Some(bu)) => Some(cmp::max(au, bu)), + _ => None + }; + + (cmp::max(a, b), upper) + } +} + +impl<'a, B: BitBlock> Iterator for Iter<'a, B> { + type Item = usize; + + #[inline] fn next(&mut self) -> Option { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +impl<'a, B: BitBlock> Iterator for Union<'a, B> { + type Item = usize; + + #[inline] fn next(&mut self) -> Option { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +impl<'a, B: BitBlock> Iterator for Intersection<'a, B> { + type Item = usize; + + #[inline] fn next(&mut self) -> Option { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +impl<'a, B: BitBlock> Iterator for Difference<'a, B> { + type Item = usize; + + #[inline] fn next(&mut self) -> Option { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +impl<'a, B: BitBlock> Iterator for SymmetricDifference<'a, B> { + type Item = usize; + + #[inline] fn next(&mut self) -> Option { self.0.next() } + #[inline] fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +impl<'a, B: BitBlock> IntoIterator for &'a BitSet { + type Item = usize; + type IntoIter = Iter<'a, B>; + + fn into_iter(self) -> Iter<'a, B> { + self.iter() + } +} + +#[cfg(test)] +mod tests { + use std::cmp::Ordering::{Equal, Greater, Less}; + use super::BitSet; + use bit_vec::BitVec; + use std::vec::Vec; + + #[test] + fn test_bit_set_show() { + let mut s = BitSet::new(); + s.insert(1); + s.insert(10); + s.insert(50); + s.insert(2); + assert_eq!("{1, 2, 10, 50}", format!("{:?}", s)); + } + + #[test] + fn test_bit_set_from_usizes() { + let usizes = vec![0, 2, 2, 3]; + let a: BitSet = usizes.into_iter().collect(); + let mut b = BitSet::new(); + b.insert(0); + b.insert(2); + b.insert(3); + assert_eq!(a, b); + } + + #[test] + fn test_bit_set_iterator() { + let usizes = vec![0, 2, 2, 3]; + let bit_vec: BitSet = usizes.into_iter().collect(); + + let idxs: Vec<_> = bit_vec.iter().collect(); + assert_eq!(idxs, [0, 2, 3]); + + let long: BitSet = (0..10000).filter(|&n| n % 2 == 0).collect(); + let real: Vec<_> = (0..10000/2).map(|x| x*2).collect(); + + let idxs: Vec<_> = long.iter().collect(); + assert_eq!(idxs, real); + } + + #[test] + fn test_bit_set_frombit_vec_init() { + let bools = [true, false]; + let lengths = [10, 64, 100]; + for &b in &bools { + for &l in &lengths { + let bitset = BitSet::from_bit_vec(BitVec::from_elem(l, b)); + assert_eq!(bitset.contains(1), b); + assert_eq!(bitset.contains((l-1)), b); + assert!(!bitset.contains(l)); + } + } + } + + #[test] + fn test_bit_vec_masking() { + let b = BitVec::from_elem(140, true); + let mut bs = BitSet::from_bit_vec(b); + assert!(bs.contains(139)); + assert!(!bs.contains(140)); + assert!(bs.insert(150)); + assert!(!bs.contains(140)); + assert!(!bs.contains(149)); + assert!(bs.contains(150)); + assert!(!bs.contains(151)); + } + + #[test] + fn test_bit_set_basic() { + let mut b = BitSet::new(); + assert!(b.insert(3)); + assert!(!b.insert(3)); + assert!(b.contains(3)); + assert!(b.insert(4)); + assert!(!b.insert(4)); + assert!(b.contains(3)); + assert!(b.insert(400)); + assert!(!b.insert(400)); + assert!(b.contains(400)); + assert_eq!(b.len(), 3); + } + + #[test] + fn test_bit_set_intersection() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let actual: Vec<_> = a.intersection(&b).collect(); + assert_eq!(actual, expected); + } + + #[test] + fn test_bit_set_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(200)); + assert!(a.insert(500)); + + assert!(b.insert(3)); + assert!(b.insert(200)); + + let expected = [1, 5, 500]; + let actual: Vec<_> = a.difference(&b).collect(); + assert_eq!(actual, expected); + } + + #[test] + fn test_bit_set_symmetric_difference() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(220)); + + let expected = [1, 5, 11, 14, 220]; + let actual: Vec<_> = a.symmetric_difference(&b).collect(); + assert_eq!(actual, expected); + } + + #[test] + fn test_bit_set_union() { + let mut a = BitSet::new(); + let mut b = BitSet::new(); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(160)); + assert!(a.insert(19)); + assert!(a.insert(24)); + assert!(a.insert(200)); + + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [1, 3, 5, 9, 11, 13, 19, 24, 160, 200]; + let actual: Vec<_> = a.union(&b).collect(); + assert_eq!(actual, expected); + } + + #[test] + fn test_bit_set_subset() { + let mut set1 = BitSet::new(); + let mut set2 = BitSet::new(); + + assert!(set1.is_subset(&set2)); // {} {} + set2.insert(100); + assert!(set1.is_subset(&set2)); // {} { 1 } + set2.insert(200); + assert!(set1.is_subset(&set2)); // {} { 1, 2 } + set1.insert(200); + assert!(set1.is_subset(&set2)); // { 2 } { 1, 2 } + set1.insert(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 1, 2 } + set2.insert(300); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3 } + set2.insert(400); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 1, 2, 3, 4 } + set2.remove(100); + assert!(set1.is_subset(&set2)); // { 2, 3 } { 2, 3, 4 } + set2.remove(300); + assert!(!set1.is_subset(&set2)); // { 2, 3 } { 2, 4 } + set1.remove(300); + assert!(set1.is_subset(&set2)); // { 2 } { 2, 4 } + } + + #[test] + fn test_bit_set_is_disjoint() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b01000000]); + let c = BitSet::new(); + let d = BitSet::from_bytes(&[0b00110000]); + + assert!(!a.is_disjoint(&d)); + assert!(!d.is_disjoint(&a)); + + assert!(a.is_disjoint(&b)); + assert!(a.is_disjoint(&c)); + assert!(b.is_disjoint(&a)); + assert!(b.is_disjoint(&c)); + assert!(c.is_disjoint(&a)); + assert!(c.is_disjoint(&b)); + } + + #[test] + fn test_bit_set_union_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + let mut b = BitSet::new(); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.union_with(&b); + assert_eq!(a, expected); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.union_with(&b); + b.union_with(&c); + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 4); + } + + #[test] + fn test_bit_set_intersect_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b00000000]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::new(); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert!(a.is_empty()); + assert!(b.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.intersect_with(&b); + b.intersect_with(&c); + assert_eq!(a.len(), 2); + assert_eq!(b.len(), 2); + } + + #[test] + fn test_bit_set_difference_with() { + // Explicitly 0'ed bits + let mut a = BitSet::from_bytes(&[0b00000000]); + let b = BitSet::from_bytes(&[0b10100010]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Uninitialized bits should behave like 0's + let mut a = BitSet::new(); + let b = BitSet::from_bytes(&[0b11111111]); + a.difference_with(&b); + assert!(a.is_empty()); + + // Standard + let mut a = BitSet::from_bytes(&[0b10100010]); + let mut b = BitSet::from_bytes(&[0b01100010]); + let c = a.clone(); + a.difference_with(&b); + b.difference_with(&c); + assert_eq!(a.len(), 1); + assert_eq!(b.len(), 1); + } + + #[test] + fn test_bit_set_symmetric_difference_with() { + //a should grow to include larger elements + let mut a = BitSet::new(); + a.insert(0); + a.insert(1); + let mut b = BitSet::new(); + b.insert(1); + b.insert(5); + let expected = BitSet::from_bytes(&[0b10000100]); + a.symmetric_difference_with(&b); + assert_eq!(a, expected); + + let mut a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::new(); + let c = a.clone(); + a.symmetric_difference_with(&b); + assert_eq!(a, c); + + // Standard + let mut a = BitSet::from_bytes(&[0b11100010]); + let mut b = BitSet::from_bytes(&[0b01101010]); + let c = a.clone(); + a.symmetric_difference_with(&b); + b.symmetric_difference_with(&c); + assert_eq!(a.len(), 2); + assert_eq!(b.len(), 2); + } + + #[test] + fn test_bit_set_eq() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert!(a == a); + assert!(a != b); + assert!(a != c); + assert!(b == b); + assert!(b == c); + assert!(c == c); + } + + #[test] + fn test_bit_set_cmp() { + let a = BitSet::from_bytes(&[0b10100010]); + let b = BitSet::from_bytes(&[0b00000000]); + let c = BitSet::new(); + + assert_eq!(a.cmp(&b), Greater); + assert_eq!(a.cmp(&c), Greater); + assert_eq!(b.cmp(&a), Less); + assert_eq!(b.cmp(&c), Equal); + assert_eq!(c.cmp(&a), Less); + assert_eq!(c.cmp(&b), Equal); + } + + #[test] + fn test_bit_vec_remove() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.remove(1)); + + assert!(a.insert(100)); + assert!(a.remove(100)); + + assert!(a.insert(1000)); + assert!(a.remove(1000)); + a.shrink_to_fit(); + } + + #[test] + fn test_bit_vec_clone() { + let mut a = BitSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(100)); + assert!(a.insert(1000)); + + let mut b = a.clone(); + + assert!(a == b); + + assert!(b.remove(1)); + assert!(a.contains(1)); + + assert!(a.remove(1000)); + assert!(b.contains(1000)); + } + +/* + #[test] + fn test_bit_set_append() { + let mut a = BitSet::new(); + a.insert(2); + a.insert(6); + + let mut b = BitSet::new(); + b.insert(1); + b.insert(3); + b.insert(6); + + a.append(&mut b); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 6); + + assert_eq!(a, BitSet::from_bytes(&[0b01110010])); + } + + #[test] + fn test_bit_set_split_off() { + // Split at 0 + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 21); + + assert_eq!(b, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + // Split behind last element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(50); + + assert_eq!(a.len(), 21); + assert_eq!(b.len(), 0); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + // Split at arbitrary element + let mut a = BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]); + + let b = a.split_off(34); + + assert_eq!(a.len(), 12); + assert_eq!(b.len(), 9); + + assert_eq!(a, BitSet::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01000000])); + assert_eq!(b, BitSet::from_bytes(&[0, 0, 0, 0, + 0b00101011, 0b10101101])); + } +*/ +} + +#[cfg(all(test, feature = "nightly"))] +mod bench { + use super::BitSet; + use bit_vec::BitVec; + use rand::{Rng, thread_rng, ThreadRng}; + + use test::{Bencher, black_box}; + + const BENCH_BITS: usize = 1 << 14; + const BITS: usize = 32; + + fn rng() -> ThreadRng { + thread_rng() + } + + #[bench] + fn bench_bit_vecset_small(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = BitSet::new(); + b.iter(|| { + for _ in 0..100 { + bit_vec.insert((r.next_u32() as usize) % BITS); + } + black_box(&bit_vec); + }); + } + + #[bench] + fn bench_bit_vecset_big(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = BitSet::new(); + b.iter(|| { + for _ in 0..100 { + bit_vec.insert((r.next_u32() as usize) % BENCH_BITS); + } + black_box(&bit_vec); + }); + } + + #[bench] + fn bench_bit_vecset_iter(b: &mut Bencher) { + let bit_vec = BitSet::from_bit_vec(BitVec::from_fn(BENCH_BITS, + |idx| {idx % 3 == 0})); + b.iter(|| { + let mut sum = 0; + for idx in &bit_vec { + sum += idx as usize; + } + sum + }) + } +} diff --git a/bit-vec/.cargo-checksum.json b/bit-vec/.cargo-checksum.json new file mode 100644 index 000000000..124312d52 --- /dev/null +++ b/bit-vec/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"} \ No newline at end of file diff --git a/bit-vec/Cargo.toml b/bit-vec/Cargo.toml new file mode 100644 index 000000000..ca7d8fb60 --- /dev/null +++ b/bit-vec/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bit-vec" +version = "0.5.1" +authors = ["Alexis Beingessner "] +description = "A vector of bits" +homepage = "https://github.com/contain-rs/bit-vec" +documentation = "https://contain-rs.github.io/bit-vec/bit_vec" +readme = "README.md" +keywords = ["data-structures", "bitvec", "bitmask", "bitmap", "bit"] +license = "MIT/Apache-2.0" +repository = "https://github.com/contain-rs/bit-vec" +[dev-dependencies.rand] +version = "0.3.15" + +[features] +default = ["std"] +nightly = [] +std = [] diff --git a/bit-vec/LICENSE-APACHE b/bit-vec/LICENSE-APACHE new file mode 100644 index 000000000..11069edd7 --- /dev/null +++ b/bit-vec/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bit-vec/LICENSE-MIT b/bit-vec/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/bit-vec/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bit-vec/README.md b/bit-vec/README.md new file mode 100644 index 000000000..44d1e2023 --- /dev/null +++ b/bit-vec/README.md @@ -0,0 +1,18 @@ +**WARNING: THIS PROJECT IS IN MAINTENANCE MODE, DUE TO INSUFFICIENT MAINTAINER RESOURCES** + +It works fine, but will generally no longer be improved. + +We are currently only accepting changes which: + +* keep this compiling with the latest versions of Rust or its dependencies. +* have minimal review requirements, such as documentation changes (so not totally new APIs). + +------ + + +A Vec of bits. + +Documentation is available at https://contain-rs.github.io/bit-vec/bit_vec. + +[![Build Status](https://travis-ci.org/contain-rs/bit-vec.svg?branch=master)](https://travis-ci.org/contain-rs/bit-vec) +[![crates.io](http://meritbadge.herokuapp.com/bit-vec)](https://crates.io/crates/bit-vec) diff --git a/bit-vec/benches/extern.rs b/bit-vec/benches/extern.rs new file mode 100644 index 000000000..74aa2f7c5 --- /dev/null +++ b/bit-vec/benches/extern.rs @@ -0,0 +1,22 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(all(test, feature = "nightly"))] + +#![feature(test)] + +extern crate test; +extern crate rand; +extern crate bit_vec; + +pub use bit_vec::BitVec; + +#[path = "../src/bench.rs"] +mod bench; diff --git a/bit-vec/crusader.sh b/bit-vec/crusader.sh new file mode 100755 index 000000000..8becfed7c --- /dev/null +++ b/bit-vec/crusader.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +git clone https://github.com/brson/cargo-crusader +cd cargo-crusader +cargo build --release +export PATH=$PATH:`pwd`/target/release/ +cd ../ + +cargo crusader + +exit diff --git a/bit-vec/deploy-docs.sh b/bit-vec/deploy-docs.sh new file mode 100755 index 000000000..c8f25ee86 --- /dev/null +++ b/bit-vec/deploy-docs.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -o errexit -o nounset + +rev=$(git rev-parse --short HEAD) + +cd target/doc + +git init +git config user.email 'FlashCat@users.noreply.github.com' +git config user.name 'FlashCat' +git remote add upstream "https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git" +git fetch upstream gh-pages +git reset upstream/gh-pages + +touch . + +git add -A . +git commit -m "rebuild pages at ${rev}" +git push -q upstream HEAD:gh-pages diff --git a/bit-vec/src/bench.rs b/bit-vec/src/bench.rs new file mode 100644 index 000000000..29922720c --- /dev/null +++ b/bit-vec/src/bench.rs @@ -0,0 +1,116 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::BitVec; +use rand::{Rng, weak_rng, XorShiftRng}; + +use test::{Bencher, black_box}; + +const BENCH_BITS : usize = 1 << 14; +const U32_BITS: usize = 32; + +fn rng() -> XorShiftRng { + weak_rng() +} + +#[bench] +fn bench_usize_small(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = 0 as usize; + b.iter(|| { + for _ in 0..100 { + bit_vec |= 1 << ((r.next_u32() as usize) % U32_BITS); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_set_big_fixed(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = BitVec::from_elem(BENCH_BITS, false); + b.iter(|| { + for _ in 0..100 { + bit_vec.set((r.next_u32() as usize) % BENCH_BITS, true); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_set_big_variable(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = BitVec::from_elem(BENCH_BITS, false); + b.iter(|| { + for _ in 0..100 { + bit_vec.set((r.next_u32() as usize) % BENCH_BITS, r.gen()); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_set_small(b: &mut Bencher) { + let mut r = rng(); + let mut bit_vec = BitVec::from_elem(U32_BITS, false); + b.iter(|| { + for _ in 0..100 { + bit_vec.set((r.next_u32() as usize) % U32_BITS, true); + } + black_box(&bit_vec); + }); +} + +#[bench] +fn bench_bit_vec_big_union(b: &mut Bencher) { + let mut b1 = BitVec::from_elem(BENCH_BITS, false); + let b2 = BitVec::from_elem(BENCH_BITS, false); + b.iter(|| { + b1.union(&b2) + }) +} + +#[bench] +fn bench_bit_vec_small_iter(b: &mut Bencher) { + let bit_vec = BitVec::from_elem(U32_BITS, false); + b.iter(|| { + let mut sum = 0; + for _ in 0..10 { + for pres in &bit_vec { + sum += pres as usize; + } + } + sum + }) +} + +#[bench] +fn bench_bit_vec_big_iter(b: &mut Bencher) { + let bit_vec = BitVec::from_elem(BENCH_BITS, false); + b.iter(|| { + let mut sum = 0; + for pres in &bit_vec { + sum += pres as usize; + } + sum + }) +} + +#[bench] +fn bench_from_elem(b: &mut Bencher) { + let cap = black_box(BENCH_BITS); + let bit = black_box(true); + b.iter(|| { + // create a BitVec and popcount it + BitVec::from_elem(cap, bit).blocks() + .fold(0, |acc, b| acc + b.count_ones()) + }); + b.bytes = cap as u64 / 8; +} diff --git a/bit-vec/src/lib.rs b/bit-vec/src/lib.rs new file mode 100644 index 000000000..f08703627 --- /dev/null +++ b/bit-vec/src/lib.rs @@ -0,0 +1,2139 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME(Gankro): BitVec and BitSet are very tightly coupled. Ideally (for +// maintenance), they should be in separate files/modules, with BitSet only +// using BitVec's public API. This will be hard for performance though, because +// `BitVec` will not want to leak its internal representation while its internal +// representation as `u32`s must be assumed for best performance. + +// FIXME(tbu-): `BitVec`'s methods shouldn't be `union`, `intersection`, but +// rather `or` and `and`. + +// (1) Be careful, most things can overflow here because the amount of bits in +// memory can overflow `usize`. +// (2) Make sure that the underlying vector has no excess length: +// E. g. `nbits == 16`, `storage.len() == 2` would be excess length, +// because the last word isn't used at all. This is important because some +// methods rely on it (for *CORRECTNESS*). +// (3) Make sure that the unused bits in the last word are zeroed out, again +// other methods rely on it for *CORRECTNESS*. +// (4) `BitSet` is tightly coupled with `BitVec`, so any changes you make in +// `BitVec` will need to be reflected in `BitSet`. + +//! Collections implemented with bit vectors. +//! +//! # Examples +//! +//! This is a simple example of the [Sieve of Eratosthenes][sieve] +//! which calculates prime numbers up to a given limit. +//! +//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes +//! +//! ``` +//! use bit_vec::BitVec; +//! +//! let max_prime = 10000; +//! +//! // Store the primes as a BitVec +//! let primes = { +//! // Assume all numbers are prime to begin, and then we +//! // cross off non-primes progressively +//! let mut bv = BitVec::from_elem(max_prime, true); +//! +//! // Neither 0 nor 1 are prime +//! bv.set(0, false); +//! bv.set(1, false); +//! +//! for i in 2.. 1 + (max_prime as f64).sqrt() as usize { +//! // if i is a prime +//! if bv[i] { +//! // Mark all multiples of i as non-prime (any multiples below i * i +//! // will have been marked as non-prime previously) +//! for j in i.. { +//! if i * j >= max_prime { +//! break; +//! } +//! bv.set(i * j, false) +//! } +//! } +//! } +//! bv +//! }; +//! +//! // Simple primality tests below our max bound +//! let print_primes = 20; +//! print!("The primes below {} are: ", print_primes); +//! for x in 0..print_primes { +//! if primes.get(x).unwrap_or(false) { +//! print!("{} ", x); +//! } +//! } +//! println!(""); +//! +//! let num_primes = primes.iter().filter(|x| *x).count(); +//! println!("There are {} primes below {}", num_primes, max_prime); +//! assert_eq!(num_primes, 1_229); +//! ``` + +#![no_std] +#![cfg_attr(not(feature="std"), feature(alloc))] + +#![cfg_attr(all(test, feature = "nightly"), feature(test))] +#[cfg(all(test, feature = "nightly"))] extern crate test; +#[cfg(all(test, feature = "nightly"))] extern crate rand; + +#[cfg(any(test, feature = "std"))] +#[macro_use] +extern crate std; +#[cfg(feature="std")] +use std::vec::Vec; + +#[cfg(not(feature="std"))] +#[macro_use] +extern crate alloc; +#[cfg(not(feature="std"))] +use alloc::prelude::Vec; + +use core::cmp::Ordering; +use core::cmp; +#[cfg(feature="std")] +use core::fmt; +use core::hash; +use core::iter::FromIterator; +use core::slice; +use core::{u8, usize}; +use core::iter::repeat; + +type MutBlocks<'a, B> = slice::IterMut<'a, B>; +//type MatchWords<'a, B> = Chain>, Skip>>>>; + +use core::ops::*; + +/// Abstracts over a pile of bits (basically unsigned primitives) +pub trait BitBlock: + Copy + + Add + + Sub + + Shl + + Shr + + Not + + BitAnd + + BitOr + + BitXor + + Rem + + Eq + + Ord + + hash::Hash + +{ + /// How many bits it has + fn bits() -> usize; + /// How many bytes it has + #[inline] + fn bytes() -> usize { Self::bits() / 8 } + /// Convert a byte into this type (lowest-order bits set) + fn from_byte(byte: u8) -> Self; + /// Count the number of 1's in the bitwise repr + fn count_ones(self) -> usize; + /// Get `0` + fn zero() -> Self; + /// Get `1` + fn one() -> Self; +} + +macro_rules! bit_block_impl { + ($(($t: ident, $size: expr)),*) => ($( + impl BitBlock for $t { + #[inline] + fn bits() -> usize { $size } + #[inline] + fn from_byte(byte: u8) -> Self { $t::from(byte) } + #[inline] + fn count_ones(self) -> usize { self.count_ones() as usize } + #[inline] + fn one() -> Self { 1 } + #[inline] + fn zero() -> Self { 0 } + } + )*) +} + +bit_block_impl!{ + (u8, 8), + (u16, 16), + (u32, 32), + (u64, 64), + (usize, core::mem::size_of::() * 8) +} + + +fn reverse_bits(byte: u8) -> u8 { + let mut result = 0; + for i in 0..u8::bits() { + result |= ((byte >> i) & 1) << (u8::bits() - 1 - i); + } + result +} + +static TRUE: bool = true; +static FALSE: bool = false; + +/// The bitvector type. +/// +/// # Examples +/// +/// ``` +/// use bit_vec::BitVec; +/// +/// let mut bv = BitVec::from_elem(10, false); +/// +/// // insert all primes less than 10 +/// bv.set(2, true); +/// bv.set(3, true); +/// bv.set(5, true); +/// bv.set(7, true); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// +/// // flip all values in bitvector, producing non-primes less than 10 +/// bv.negate(); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// +/// // reset bitvector to empty +/// bv.clear(); +/// println!("{:?}", bv); +/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count()); +/// ``` +pub struct BitVec { + /// Internal representation of the bit vector + storage: Vec, + /// The number of valid bits in the internal representation + nbits: usize +} + +// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing) +impl Index for BitVec { + type Output = bool; + + #[inline] + fn index(&self, i: usize) -> &bool { + if self.get(i).expect("index out of bounds") { + &TRUE + } else { + &FALSE + } + } +} + +/// Computes how many blocks are needed to store that many bits +fn blocks_for_bits(bits: usize) -> usize { + // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we + // reserve enough. But if we want exactly a multiple of 32, this will actually allocate + // one too many. So we need to check if that's the case. We can do that by computing if + // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically + // superior modulo operator on a power of two to this. + // + // Note that we can technically avoid this branch with the expression + // `(nbits + U32_BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. + if bits % B::bits() == 0 { + bits / B::bits() + } else { + bits / B::bits() + 1 + } +} + +/// Computes the bitmask for the final word of the vector +fn mask_for_bits(bits: usize) -> B { + // Note especially that a perfect multiple of U32_BITS should mask all 1s. + (!B::zero()) >> ((B::bits() - bits % B::bits()) % B::bits()) +} + +type B = u32; + +impl BitVec { + + /// Creates an empty `BitVec`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// let mut bv = BitVec::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Default::default() + } + + /// Creates a `BitVec` that holds `nbits` elements, setting each element + /// to `bit`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.len(), 10); + /// for x in bv.iter() { + /// assert_eq!(x, false); + /// } + /// ``` + #[inline] + pub fn from_elem(nbits: usize, bit: bool) -> Self { + let nblocks = blocks_for_bits::(nbits); + let mut bit_vec = BitVec { + storage: vec![if bit { !B::zero() } else { B::zero() }; nblocks], + nbits, + }; + bit_vec.fix_last_block(); + bit_vec + } + + /// Constructs a new, empty `BitVec` with the specified capacity. + /// + /// The bitvector will be able to hold at least `capacity` bits without + /// reallocating. If `capacity` is 0, it will not allocate. + /// + /// It is important to note that this function does not specify the + /// *length* of the returned bitvector, but only the *capacity*. + #[inline] + pub fn with_capacity(nbits: usize) -> Self { + BitVec { + storage: Vec::with_capacity(blocks_for_bits::(nbits)), + nbits: 0, + } + } + + /// Transforms a byte-vector into a `BitVec`. Each byte becomes eight bits, + /// with the most significant bits of each byte coming first. Each + /// bit becomes `true` if equal to 1 or `false` if equal to 0. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b10100000, 0b00010010]); + /// assert!(bv.eq_vec(&[true, false, true, false, + /// false, false, false, false, + /// false, false, false, true, + /// false, false, true, false])); + /// ``` + pub fn from_bytes(bytes: &[u8]) -> Self { + let len = bytes.len().checked_mul(u8::bits()).expect("capacity overflow"); + let mut bit_vec = BitVec::with_capacity(len); + let complete_words = bytes.len() / B::bytes(); + let extra_bytes = bytes.len() % B::bytes(); + + bit_vec.nbits = len; + + for i in 0..complete_words { + let mut accumulator = B::zero(); + for idx in 0..B::bytes() { + accumulator |= + B::from_byte(reverse_bits(bytes[i * B::bytes() + idx])) << (idx * 8) + } + bit_vec.storage.push(accumulator); + } + + if extra_bytes > 0 { + let mut last_word = B::zero(); + for (i, &byte) in bytes[complete_words * B::bytes()..].iter().enumerate() { + last_word |= + B::from_byte(reverse_bits(byte)) << (i * 8); + } + bit_vec.storage.push(last_word); + } + + bit_vec + } + + /// Creates a `BitVec` of the specified length where the value at each index + /// is `f(index)`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_fn(5, |i| { i % 2 == 0 }); + /// assert!(bv.eq_vec(&[true, false, true, false, true])); + /// ``` + #[inline] + pub fn from_fn(len: usize, mut f: F) -> Self + where F: FnMut(usize) -> bool + { + let mut bit_vec = BitVec::from_elem(len, false); + for i in 0..len { + bit_vec.set(i, f(i)); + } + bit_vec + } +} + +impl BitVec { + /// Applies the given operation to the blocks of self and other, and sets + /// self to be the result. This relies on the caller not to corrupt the + /// last word. + #[inline] + fn process(&mut self, other: &BitVec, mut op: F) -> bool + where F: FnMut(B, B) -> B { + assert_eq!(self.len(), other.len()); + // This could theoretically be a `debug_assert!`. + assert_eq!(self.storage.len(), other.storage.len()); + let mut changed_bits = B::zero(); + for (a, b) in self.blocks_mut().zip(other.blocks()) { + let w = op(*a, b); + changed_bits = changed_bits | (*a ^ w); + *a = w; + } + changed_bits != B::zero() + } + + /// Iterator over mutable refs to the underlying blocks of data. + #[inline] + fn blocks_mut(&mut self) -> MutBlocks { + // (2) + self.storage.iter_mut() + } + + /// Iterator over the underlying blocks of data + #[inline] + pub fn blocks(&self) -> Blocks { + // (2) + Blocks{iter: self.storage.iter()} + } + + /// Exposes the raw block storage of this BitVec + /// + /// Only really intended for BitSet. + #[inline] + pub fn storage(&self) -> &[B] { + &self.storage + } + + /// Exposes the raw block storage of this BitVec + /// + /// Can probably cause unsafety. Only really intended for BitSet. + #[inline] + pub unsafe fn storage_mut(&mut self) -> &mut Vec { + &mut self.storage + } + + /// An operation might screw up the unused bits in the last block of the + /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up. + fn fix_last_block(&mut self) { + let extra_bits = self.len() % B::bits(); + if extra_bits > 0 { + let mask = (B::one() << extra_bits) - B::one(); + let storage_len = self.storage.len(); + let block = &mut self.storage[storage_len - 1]; + *block = *block & mask; + } + } + + + /// Retrieves the value at index `i`, or `None` if the index is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01100000]); + /// assert_eq!(bv.get(0), Some(false)); + /// assert_eq!(bv.get(1), Some(true)); + /// assert_eq!(bv.get(100), None); + /// + /// // Can also use array indexing + /// assert_eq!(bv[1], true); + /// ``` + #[inline] + pub fn get(&self, i: usize) -> Option { + if i >= self.nbits { + return None; + } + let w = i / B::bits(); + let b = i % B::bits(); + self.storage.get(w).map(|&block| + (block & (B::one() << b)) != B::zero() + ) + } + + /// Sets the value of a bit at an index `i`. + /// + /// # Panics + /// + /// Panics if `i` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(5, false); + /// bv.set(3, true); + /// assert_eq!(bv[3], true); + /// ``` + #[inline] + pub fn set(&mut self, i: usize, x: bool) { + assert!(i < self.nbits, "index out of bounds: {:?} >= {:?}", i, self.nbits); + let w = i / B::bits(); + let b = i % B::bits(); + let flag = B::one() << b; + let val = if x { self.storage[w] | flag } + else { self.storage[w] & !flag }; + self.storage[w] = val; + } + + /// Sets all bits to 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let before = 0b01100000; + /// let after = 0b11111111; + /// + /// let mut bv = BitVec::from_bytes(&[before]); + /// bv.set_all(); + /// assert_eq!(bv, BitVec::from_bytes(&[after])); + /// ``` + #[inline] + pub fn set_all(&mut self) { + for w in &mut self.storage { *w = !B::zero(); } + self.fix_last_block(); + } + + /// Flips all bits. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let before = 0b01100000; + /// let after = 0b10011111; + /// + /// let mut bv = BitVec::from_bytes(&[before]); + /// bv.negate(); + /// assert_eq!(bv, BitVec::from_bytes(&[after])); + /// ``` + #[inline] + pub fn negate(&mut self) { + for w in &mut self.storage { *w = !*w; } + self.fix_last_block(); + } + + /// Calculates the union of two bitvectors. This acts like the bitwise `or` + /// function. + /// + /// Sets `self` to the union of `self` and `other`. Both bitvectors must be + /// the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01111110; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.union(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn union(&mut self, other: &Self) -> bool { + self.process(other, |w1, w2| (w1 | w2)) + } + + /// Calculates the intersection of two bitvectors. This acts like the + /// bitwise `and` function. + /// + /// Sets `self` to the intersection of `self` and `other`. Both bitvectors + /// must be the same length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different lengths. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let res = 0b01000000; + /// + /// let mut a = BitVec::from_bytes(&[a]); + /// let b = BitVec::from_bytes(&[b]); + /// + /// assert!(a.intersect(&b)); + /// assert_eq!(a, BitVec::from_bytes(&[res])); + /// ``` + #[inline] + pub fn intersect(&mut self, other: &Self) -> bool { + self.process(other, |w1, w2| (w1 & w2)) + } + + /// Calculates the difference between two bitvectors. + /// + /// Sets each element of `self` to the value of that element minus the + /// element of `other` at the same index. Both bitvectors must be the same + /// length. Returns `true` if `self` changed. + /// + /// # Panics + /// + /// Panics if the bitvectors are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let a = 0b01100100; + /// let b = 0b01011010; + /// let a_b = 0b00100100; // a - b + /// let b_a = 0b00011010; // b - a + /// + /// let mut bva = BitVec::from_bytes(&[a]); + /// let bvb = BitVec::from_bytes(&[b]); + /// + /// assert!(bva.difference(&bvb)); + /// assert_eq!(bva, BitVec::from_bytes(&[a_b])); + /// + /// let bva = BitVec::from_bytes(&[a]); + /// let mut bvb = BitVec::from_bytes(&[b]); + /// + /// assert!(bvb.difference(&bva)); + /// assert_eq!(bvb, BitVec::from_bytes(&[b_a])); + /// ``` + #[inline] + pub fn difference(&mut self, other: &Self) -> bool { + self.process(other, |w1, w2| (w1 & !w2)) + } + + /// Returns `true` if all bits are 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(5, true); + /// assert_eq!(bv.all(), true); + /// + /// bv.set(1, false); + /// assert_eq!(bv.all(), false); + /// ``` + #[inline] + pub fn all(&self) -> bool { + let mut last_word = !B::zero(); + // Check that every block but the last is all-ones... + self.blocks().all(|elem| { + let tmp = last_word; + last_word = elem; + tmp == !B::zero() + // and then check the last one has enough ones + }) && (last_word == mask_for_bits(self.nbits)) + } + + /// Returns an iterator over the elements of the vector in order. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]); + /// assert_eq!(bv.iter().filter(|x| *x).count(), 7); + /// ``` + #[inline] + pub fn iter(&self) -> Iter { + Iter { bit_vec: self, range: 0..self.nbits } + } + +/* + /// Moves all bits from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections, bit_vec_append_split_off)] + /// use bit_vec::BitVec; + /// + /// let mut a = BitVec::from_bytes(&[0b10000000]); + /// let mut b = BitVec::from_bytes(&[0b01100001]); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 16); + /// assert_eq!(b.len(), 0); + /// assert!(a.eq_vec(&[true, false, false, false, false, false, false, false, + /// false, true, true, false, false, false, false, true])); + /// ``` + pub fn append(&mut self, other: &mut Self) { + let b = self.len() % B::bits(); + + self.nbits += other.len(); + other.nbits = 0; + + if b == 0 { + self.storage.append(&mut other.storage); + } else { + self.storage.reserve(other.storage.len()); + + for block in other.storage.drain(..) { + { + let last = self.storage.last_mut().unwrap(); + *last = *last | (block << b); + } + self.storage.push(block >> (B::bits() - b)); + } + } + } + + /// Splits the `BitVec` into two at the given bit, + /// retaining the first half in-place and returning the second one. + /// + /// # Panics + /// + /// Panics if `at` is out of bounds. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections, bit_vec_append_split_off)] + /// use bit_vec::BitVec; + /// let mut a = BitVec::new(); + /// a.push(true); + /// a.push(false); + /// a.push(false); + /// a.push(true); + /// + /// let b = a.split_off(2); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 2); + /// assert!(a.eq_vec(&[true, false])); + /// assert!(b.eq_vec(&[false, true])); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + assert!(at <= self.len(), "`at` out of bounds"); + + let mut other = BitVec::new(); + + if at == 0 { + swap(self, &mut other); + return other; + } else if at == self.len() { + return other; + } + + let w = at / B::bits(); + let b = at % B::bits(); + other.nbits = self.nbits - at; + self.nbits = at; + if b == 0 { + // Split at block boundary + other.storage = self.storage.split_off(w); + } else { + other.storage.reserve(self.storage.len() - w); + + { + let mut iter = self.storage[w..].iter(); + let mut last = *iter.next().unwrap(); + for &cur in iter { + other.storage.push((last >> b) | (cur << (B::bits() - b))); + last = cur; + } + other.storage.push(last >> b); + } + + self.storage.truncate(w + 1); + self.fix_last_block(); + } + + other + } +*/ + + /// Returns `true` if all bits are 0. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.none(), true); + /// + /// bv.set(3, true); + /// assert_eq!(bv.none(), false); + /// ``` + #[inline] + pub fn none(&self) -> bool { + self.blocks().all(|w| w == B::zero()) + } + + /// Returns `true` if any bit is 1. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(10, false); + /// assert_eq!(bv.any(), false); + /// + /// bv.set(3, true); + /// assert_eq!(bv.any(), true); + /// ``` + #[inline] + pub fn any(&self) -> bool { + !self.none() + } + + /// Organises the bits into bytes, such that the first bit in the + /// `BitVec` becomes the high-order bit of the first byte. If the + /// size of the `BitVec` is not a multiple of eight then trailing bits + /// will be filled-in with `false`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, true); + /// bv.set(1, false); + /// + /// assert_eq!(bv.to_bytes(), [0b10100000]); + /// + /// let mut bv = BitVec::from_elem(9, false); + /// bv.set(2, true); + /// bv.set(8, true); + /// + /// assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); + /// ``` + pub fn to_bytes(&self) -> Vec { + // Oh lord, we're mapping this to bytes bit-by-bit! + fn bit(bit_vec: &BitVec, byte: usize, bit: usize) -> u8 { + let offset = byte * 8 + bit; + if offset >= bit_vec.nbits { + 0 + } else { + (bit_vec[offset] as u8) << (7 - bit) + } + } + + let len = self.nbits / 8 + + if self.nbits % 8 == 0 { 0 } else { 1 }; + (0..len).map(|i| + bit(self, i, 0) | + bit(self, i, 1) | + bit(self, i, 2) | + bit(self, i, 3) | + bit(self, i, 4) | + bit(self, i, 5) | + bit(self, i, 6) | + bit(self, i, 7) + ).collect() + } + + /// Compares a `BitVec` to a slice of `bool`s. + /// Both the `BitVec` and slice must have the same length. + /// + /// # Panics + /// + /// Panics if the `BitVec` and slice are of different length. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let bv = BitVec::from_bytes(&[0b10100000]); + /// + /// assert!(bv.eq_vec(&[true, false, true, false, + /// false, false, false, false])); + /// ``` + #[inline] + pub fn eq_vec(&self, v: &[bool]) -> bool { + assert_eq!(self.nbits, v.len()); + self.iter().zip(v.iter().cloned()).all(|(b1, b2)| b1 == b2) + } + + /// Shortens a `BitVec`, dropping excess elements. + /// + /// If `len` is greater than the vector's current length, this has no + /// effect. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001011]); + /// bv.truncate(2); + /// assert!(bv.eq_vec(&[false, true])); + /// ``` + #[inline] + pub fn truncate(&mut self, len: usize) { + if len < self.len() { + self.nbits = len; + // This fixes (2). + self.storage.truncate(blocks_for_bits::(len)); + self.fix_last_block(); + } + } + + /// Reserves capacity for at least `additional` more bits to be inserted in the given + /// `BitVec`. The collection may reserve more space to avoid frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, false); + /// bv.reserve(10); + /// assert_eq!(bv.len(), 3); + /// assert!(bv.capacity() >= 13); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + let desired_cap = self.len().checked_add(additional).expect("capacity overflow"); + let storage_len = self.storage.len(); + if desired_cap > self.capacity() { + self.storage.reserve(blocks_for_bits::(desired_cap) - storage_len); + } + } + + /// Reserves the minimum capacity for exactly `additional` more bits to be inserted in the + /// given `BitVec`. Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the collection more space than it requests. Therefore + /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future + /// insertions are expected. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_elem(3, false); + /// bv.reserve(10); + /// assert_eq!(bv.len(), 3); + /// assert!(bv.capacity() >= 13); + /// ``` + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + let desired_cap = self.len().checked_add(additional).expect("capacity overflow"); + let storage_len = self.storage.len(); + if desired_cap > self.capacity() { + self.storage.reserve_exact(blocks_for_bits::(desired_cap) - storage_len); + } + } + + /// Returns the capacity in bits for this bit vector. Inserting any + /// element less than this amount will not trigger a resizing. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::new(); + /// bv.reserve(10); + /// assert!(bv.capacity() >= 10); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.storage.capacity().checked_mul(B::bits()).unwrap_or(usize::MAX) + } + + /// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`. + /// + /// # Panics + /// + /// Panics if the new len overflows a `usize`. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001011]); + /// bv.grow(2, true); + /// assert_eq!(bv.len(), 10); + /// assert_eq!(bv.to_bytes(), [0b01001011, 0b11000000]); + /// ``` + pub fn grow(&mut self, n: usize, value: bool) { + // Note: we just bulk set all the bits in the last word in this fn in multiple places + // which is technically wrong if not all of these bits are to be used. However, at the end + // of this fn we call `fix_last_block` at the end of this fn, which should fix this. + + let new_nbits = self.nbits.checked_add(n).expect("capacity overflow"); + let new_nblocks = blocks_for_bits::(new_nbits); + let full_value = if value { !B::zero() } else { B::zero() }; + + // Correct the old tail word, setting or clearing formerly unused bits + let num_cur_blocks = blocks_for_bits::(self.nbits); + if self.nbits % B::bits() > 0 { + let mask = mask_for_bits::(self.nbits); + if value { + let block = &mut self.storage[num_cur_blocks - 1]; + *block = *block | !mask; + } else { + // Extra bits are already zero by invariant. + } + } + + // Fill in words after the old tail word + let stop_idx = cmp::min(self.storage.len(), new_nblocks); + for idx in num_cur_blocks..stop_idx { + self.storage[idx] = full_value; + } + + // Allocate new words, if needed + if new_nblocks > self.storage.len() { + let to_add = new_nblocks - self.storage.len(); + self.storage.extend(repeat(full_value).take(to_add)); + } + + // Adjust internal bit count + self.nbits = new_nbits; + + self.fix_last_block(); + } + + /// Removes the last bit from the BitVec, and returns it. Returns None if the BitVec is empty. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::from_bytes(&[0b01001001]); + /// assert_eq!(bv.pop(), Some(true)); + /// assert_eq!(bv.pop(), Some(false)); + /// assert_eq!(bv.len(), 6); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + if self.is_empty() { + None + } else { + let i = self.nbits - 1; + let ret = self[i]; + // (3) + self.set(i, false); + self.nbits = i; + if self.nbits % B::bits() == 0 { + // (2) + self.storage.pop(); + } + Some(ret) + } + } + + /// Pushes a `bool` onto the end. + /// + /// # Examples + /// + /// ``` + /// use bit_vec::BitVec; + /// + /// let mut bv = BitVec::new(); + /// bv.push(true); + /// bv.push(false); + /// assert!(bv.eq_vec(&[true, false])); + /// ``` + #[inline] + pub fn push(&mut self, elem: bool) { + if self.nbits % B::bits() == 0 { + self.storage.push(B::zero()); + } + let insert_pos = self.nbits; + self.nbits = self.nbits.checked_add(1).expect("Capacity overflow"); + self.set(insert_pos, elem); + } + + /// Returns the total number of bits in this vector + #[inline] + pub fn len(&self) -> usize { self.nbits } + + /// Sets the number of bits that this BitVec considers initialized. + /// + /// Almost certainly can cause bad stuff. Only really intended for BitSet. + #[inline] + pub unsafe fn set_len(&mut self, len: usize) { + self.nbits = len; + } + + /// Returns true if there are no bits in this vector + #[inline] + pub fn is_empty(&self) -> bool { self.len() == 0 } + + /// Clears all bits in this vector. + #[inline] + pub fn clear(&mut self) { + for w in &mut self.storage { *w = B::zero(); } + } + + /// Shrinks the capacity of the underlying storage as much as + /// possible. + /// + /// It will drop down as close as possible to the length but the + /// allocator may still inform the underlying storage that there + /// is space for a few more elements/bits. + pub fn shrink_to_fit(&mut self) { + self.storage.shrink_to_fit(); + } +} + +impl Default for BitVec { + #[inline] + fn default() -> Self { BitVec { storage: Vec::new(), nbits: 0 } } +} + +impl FromIterator for BitVec { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut ret: Self = Default::default(); + ret.extend(iter); + ret + } +} + +impl Extend for BitVec { + #[inline] + fn extend>(&mut self, iterable: I) { + let iterator = iterable.into_iter(); + let (min, _) = iterator.size_hint(); + self.reserve(min); + for element in iterator { + self.push(element) + } + } +} + +impl Clone for BitVec { + #[inline] + fn clone(&self) -> Self { + BitVec { storage: self.storage.clone(), nbits: self.nbits } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.nbits = source.nbits; + self.storage.clone_from(&source.storage); + } +} + +impl PartialOrd for BitVec { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for BitVec { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let mut a = self.iter(); + let mut b = other.iter(); + loop { + match (a.next(), b.next()) { + (Some(x), Some(y)) => match x.cmp(&y) { + Ordering::Equal => {} + otherwise => return otherwise, + }, + (None, None) => return Ordering::Equal, + (None, _) => return Ordering::Less, + (_, None) => return Ordering::Greater, + } + } + } +} + +#[cfg(feature="std")] +impl fmt::Debug for BitVec { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + for bit in self { + try!(write!(fmt, "{}", if bit { 1 } else { 0 })); + } + Ok(()) + } +} + +impl hash::Hash for BitVec { + #[inline] + fn hash(&self, state: &mut H) { + self.nbits.hash(state); + for elem in self.blocks() { + elem.hash(state); + } + } +} + +impl cmp::PartialEq for BitVec { + #[inline] + fn eq(&self, other: &Self) -> bool { + if self.nbits != other.nbits { + return false; + } + self.blocks().zip(other.blocks()).all(|(w1, w2)| w1 == w2) + } +} + +impl cmp::Eq for BitVec {} + +/// An iterator for `BitVec`. +#[derive(Clone)] +pub struct Iter<'a, B: 'a = u32> { + bit_vec: &'a BitVec, + range: Range, +} + +impl<'a, B: BitBlock> Iterator for Iter<'a, B> { + type Item = bool; + + #[inline] + fn next(&mut self) -> Option { + // NB: indexing is slow for extern crates when it has to go through &TRUE or &FALSE + // variables. get is more direct, and unwrap is fine since we're sure of the range. + self.range.next().map(|i| self.bit_vec.get(i).unwrap()) + } + + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } +} + +impl<'a, B: BitBlock> DoubleEndedIterator for Iter<'a, B> { + #[inline] + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl<'a, B: BitBlock> ExactSizeIterator for Iter<'a, B> {} + + +impl<'a, B: BitBlock> IntoIterator for &'a BitVec { + type Item = bool; + type IntoIter = Iter<'a, B>; + + #[inline] + fn into_iter(self) -> Iter<'a, B> { + self.iter() + } +} + + +pub struct IntoIter { + bit_vec: BitVec, + range: Range, +} + +impl Iterator for IntoIter { + type Item = bool; + + #[inline] + fn next(&mut self) -> Option { + self.range.next().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| self.bit_vec.get(i).unwrap()) + } +} + +impl ExactSizeIterator for IntoIter {} + +impl IntoIterator for BitVec { + type Item = bool; + type IntoIter = IntoIter; + + #[inline] + fn into_iter(self) -> IntoIter { + let nbits = self.nbits; + IntoIter { bit_vec: self, range: 0..nbits } + } +} + +/// An iterator over the blocks of a `BitVec`. +#[derive(Clone)] +pub struct Blocks<'a, B: 'a> { + iter: slice::Iter<'a, B>, +} + +impl<'a, B: BitBlock> Iterator for Blocks<'a, B> { + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().cloned() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, B: BitBlock> DoubleEndedIterator for Blocks<'a, B> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().cloned() + } +} + +impl<'a, B: BitBlock> ExactSizeIterator for Blocks<'a, B> {} + + + + + + + + + + + +#[cfg(test)] +mod tests { + use super::{BitVec, Iter}; + use std::vec::Vec; + + // This is stupid, but I want to differentiate from a "random" 32 + const U32_BITS: usize = 32; + + #[test] + fn test_to_str() { + let zerolen = BitVec::new(); + assert_eq!(format!("{:?}", zerolen), ""); + + let eightbits = BitVec::from_elem(8, false); + assert_eq!(format!("{:?}", eightbits), "00000000") + } + + #[test] + fn test_0_elements() { + let act = BitVec::new(); + let exp = Vec::new(); + assert!(act.eq_vec(&exp)); + assert!(act.none() && act.all()); + } + + #[test] + fn test_1_element() { + let mut act = BitVec::from_elem(1, false); + assert!(act.eq_vec(&[false])); + assert!(act.none() && !act.all()); + act = BitVec::from_elem(1, true); + assert!(act.eq_vec(&[true])); + assert!(!act.none() && act.all()); + } + + #[test] + fn test_2_elements() { + let mut b = BitVec::from_elem(2, false); + b.set(0, true); + b.set(1, false); + assert_eq!(format!("{:?}", b), "10"); + assert!(!b.none() && !b.all()); + } + + #[test] + fn test_10_elements() { + let mut act; + // all 0 + + act = BitVec::from_elem(10, false); + assert!((act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false]))); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::from_elem(10, true); + assert!((act.eq_vec(&[true, true, true, true, true, true, true, true, true, true]))); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::from_elem(10, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + assert!((act.eq_vec(&[true, true, true, true, true, false, false, false, false, false]))); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(10, false); + act.set(5, true); + act.set(6, true); + act.set(7, true); + act.set(8, true); + act.set(9, true); + assert!((act.eq_vec(&[false, false, false, false, false, true, true, true, true, true]))); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(10, false); + act.set(0, true); + act.set(3, true); + act.set(6, true); + act.set(9, true); + assert!((act.eq_vec(&[true, false, false, true, false, false, true, false, false, true]))); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_31_elements() { + let mut act; + // all 0 + + act = BitVec::from_elem(31, false); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::from_elem(31, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::from_elem(31, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(31, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, true, true, true, true, true, true, true, + false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(31, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, true, true, true, true, true, true, true])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(31, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + assert!(act.eq_vec( + &[false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_32_elements() { + let mut act; + // all 0 + + act = BitVec::from_elem(32, false); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::from_elem(32, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::from_elem(32, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(32, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, true, true, true, true, true, true, true, + false, false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(32, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, true, true, true, true, true, true, true, true])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(32, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec( + &[false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true, true])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_33_elements() { + let mut act; + // all 0 + + act = BitVec::from_elem(33, false); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false])); + assert!(act.none() && !act.all()); + // all 1 + + act = BitVec::from_elem(33, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true])); + assert!(!act.none() && act.all()); + // mixed + + act = BitVec::from_elem(33, false); + act.set(0, true); + act.set(1, true); + act.set(2, true); + act.set(3, true); + act.set(4, true); + act.set(5, true); + act.set(6, true); + act.set(7, true); + assert!(act.eq_vec( + &[true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(33, false); + act.set(16, true); + act.set(17, true); + act.set(18, true); + act.set(19, true); + act.set(20, true); + act.set(21, true); + act.set(22, true); + act.set(23, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, true, true, true, true, true, true, true, + false, false, false, false, false, false, false, false, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(33, false); + act.set(24, true); + act.set(25, true); + act.set(26, true); + act.set(27, true); + act.set(28, true); + act.set(29, true); + act.set(30, true); + act.set(31, true); + assert!(act.eq_vec( + &[false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, true, true, true, true, true, true, true, true, false])); + assert!(!act.none() && !act.all()); + // mixed + + act = BitVec::from_elem(33, false); + act.set(3, true); + act.set(17, true); + act.set(30, true); + act.set(31, true); + act.set(32, true); + assert!(act.eq_vec( + &[false, false, false, true, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, false, false, false, false, false, + false, false, false, false, false, false, true, true, true])); + assert!(!act.none() && !act.all()); + } + + #[test] + fn test_equal_differing_sizes() { + let v0 = BitVec::from_elem(10, false); + let v1 = BitVec::from_elem(11, false); + assert!(v0 != v1); + } + + #[test] + fn test_equal_greatly_differing_sizes() { + let v0 = BitVec::from_elem(10, false); + let v1 = BitVec::from_elem(110, false); + assert!(v0 != v1); + } + + #[test] + fn test_equal_sneaky_small() { + let mut a = BitVec::from_elem(1, false); + a.set(0, true); + + let mut b = BitVec::from_elem(1, true); + b.set(0, true); + + assert_eq!(a, b); + } + + #[test] + fn test_equal_sneaky_big() { + let mut a = BitVec::from_elem(100, false); + for i in 0..100 { + a.set(i, true); + } + + let mut b = BitVec::from_elem(100, true); + for i in 0..100 { + b.set(i, true); + } + + assert_eq!(a, b); + } + + #[test] + fn test_from_bytes() { + let bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111]); + let str = concat!("10110110", "00000000", "11111111"); + assert_eq!(format!("{:?}", bit_vec), str); + } + + #[test] + fn test_to_bytes() { + let mut bv = BitVec::from_elem(3, true); + bv.set(1, false); + assert_eq!(bv.to_bytes(), [0b10100000]); + + let mut bv = BitVec::from_elem(9, false); + bv.set(2, true); + bv.set(8, true); + assert_eq!(bv.to_bytes(), [0b00100000, 0b10000000]); + } + + #[test] + fn test_from_bools() { + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + assert_eq!(format!("{:?}", bit_vec), "1011"); + } + + #[test] + fn test_to_bools() { + let bools = vec![false, false, true, false, false, true, true, false]; + assert_eq!(BitVec::from_bytes(&[0b00100110]).iter().collect::>(), bools); + } + + #[test] + fn test_bit_vec_iterator() { + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + + assert_eq!(bit_vec.iter().collect::>(), bools); + + let long: Vec<_> = (0..10000).map(|i| i % 2 == 0).collect(); + let bit_vec: BitVec = long.iter().map(|n| *n).collect(); + assert_eq!(bit_vec.iter().collect::>(), long) + } + + #[test] + fn test_small_difference() { + let mut b1 = BitVec::from_elem(3, false); + let mut b2 = BitVec::from_elem(3, false); + b1.set(0, true); + b1.set(1, true); + b2.set(1, true); + b2.set(2, true); + assert!(b1.difference(&b2)); + assert!(b1[0]); + assert!(!b1[1]); + assert!(!b1[2]); + } + + #[test] + fn test_big_difference() { + let mut b1 = BitVec::from_elem(100, false); + let mut b2 = BitVec::from_elem(100, false); + b1.set(0, true); + b1.set(40, true); + b2.set(40, true); + b2.set(80, true); + assert!(b1.difference(&b2)); + assert!(b1[0]); + assert!(!b1[40]); + assert!(!b1[80]); + } + + #[test] + fn test_small_clear() { + let mut b = BitVec::from_elem(14, true); + assert!(!b.none() && b.all()); + b.clear(); + assert!(b.none() && !b.all()); + } + + #[test] + fn test_big_clear() { + let mut b = BitVec::from_elem(140, true); + assert!(!b.none() && b.all()); + b.clear(); + assert!(b.none() && !b.all()); + } + + #[test] + fn test_bit_vec_lt() { + let mut a = BitVec::from_elem(5, false); + let mut b = BitVec::from_elem(5, false); + + assert!(!(a < b) && !(b < a)); + b.set(2, true); + assert!(a < b); + a.set(3, true); + assert!(a < b); + a.set(2, true); + assert!(!(a < b) && b < a); + b.set(0, true); + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = BitVec::from_elem(5, false); + let mut b = BitVec::from_elem(5, false); + + assert!(a <= b && a >= b); + a.set(1, true); + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b.set(1, true); + b.set(2, true); + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + + #[test] + fn test_small_bit_vec_tests() { + let v = BitVec::from_bytes(&[0]); + assert!(!v.all()); + assert!(!v.any()); + assert!(v.none()); + + let v = BitVec::from_bytes(&[0b00010100]); + assert!(!v.all()); + assert!(v.any()); + assert!(!v.none()); + + let v = BitVec::from_bytes(&[0xFF]); + assert!(v.all()); + assert!(v.any()); + assert!(!v.none()); + } + + #[test] + fn test_big_bit_vec_tests() { + let v = BitVec::from_bytes(&[ // 88 bits + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0]); + assert!(!v.all()); + assert!(!v.any()); + assert!(v.none()); + + let v = BitVec::from_bytes(&[ // 88 bits + 0, 0, 0b00010100, 0, + 0, 0, 0, 0b00110100, + 0, 0, 0]); + assert!(!v.all()); + assert!(v.any()); + assert!(!v.none()); + + let v = BitVec::from_bytes(&[ // 88 bits + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF]); + assert!(v.all()); + assert!(v.any()); + assert!(!v.none()); + } + + #[test] + fn test_bit_vec_push_pop() { + let mut s = BitVec::from_elem(5 * U32_BITS - 2, false); + assert_eq!(s.len(), 5 * U32_BITS - 2); + assert_eq!(s[5 * U32_BITS - 3], false); + s.push(true); + s.push(true); + assert_eq!(s[5 * U32_BITS - 2], true); + assert_eq!(s[5 * U32_BITS - 1], true); + // Here the internal vector will need to be extended + s.push(false); + assert_eq!(s[5 * U32_BITS], false); + s.push(false); + assert_eq!(s[5 * U32_BITS + 1], false); + assert_eq!(s.len(), 5 * U32_BITS + 2); + // Pop it all off + assert_eq!(s.pop(), Some(false)); + assert_eq!(s.pop(), Some(false)); + assert_eq!(s.pop(), Some(true)); + assert_eq!(s.pop(), Some(true)); + assert_eq!(s.len(), 5 * U32_BITS - 2); + } + + #[test] + fn test_bit_vec_truncate() { + let mut s = BitVec::from_elem(5 * U32_BITS, true); + + assert_eq!(s, BitVec::from_elem(5 * U32_BITS, true)); + assert_eq!(s.len(), 5 * U32_BITS); + s.truncate(4 * U32_BITS); + assert_eq!(s, BitVec::from_elem(4 * U32_BITS, true)); + assert_eq!(s.len(), 4 * U32_BITS); + // Truncating to a size > s.len() should be a noop + s.truncate(5 * U32_BITS); + assert_eq!(s, BitVec::from_elem(4 * U32_BITS, true)); + assert_eq!(s.len(), 4 * U32_BITS); + s.truncate(3 * U32_BITS - 10); + assert_eq!(s, BitVec::from_elem(3 * U32_BITS - 10, true)); + assert_eq!(s.len(), 3 * U32_BITS - 10); + s.truncate(0); + assert_eq!(s, BitVec::from_elem(0, true)); + assert_eq!(s.len(), 0); + } + + #[test] + fn test_bit_vec_reserve() { + let mut s = BitVec::from_elem(5 * U32_BITS, true); + // Check capacity + assert!(s.capacity() >= 5 * U32_BITS); + s.reserve(2 * U32_BITS); + assert!(s.capacity() >= 7 * U32_BITS); + s.reserve(7 * U32_BITS); + assert!(s.capacity() >= 12 * U32_BITS); + s.reserve_exact(7 * U32_BITS); + assert!(s.capacity() >= 12 * U32_BITS); + s.reserve(7 * U32_BITS + 1); + assert!(s.capacity() >= 12 * U32_BITS + 1); + // Check that length hasn't changed + assert_eq!(s.len(), 5 * U32_BITS); + s.push(true); + s.push(false); + s.push(true); + assert_eq!(s[5 * U32_BITS - 1], true); + assert_eq!(s[5 * U32_BITS - 0], true); + assert_eq!(s[5 * U32_BITS + 1], false); + assert_eq!(s[5 * U32_BITS + 2], true); + } + + #[test] + fn test_bit_vec_grow() { + let mut bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010]); + bit_vec.grow(32, true); + assert_eq!(bit_vec, BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010, + 0xFF, 0xFF, 0xFF, 0xFF])); + bit_vec.grow(64, false); + assert_eq!(bit_vec, BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010, + 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0])); + bit_vec.grow(16, true); + assert_eq!(bit_vec, BitVec::from_bytes(&[0b10110110, 0b00000000, 0b10101010, + 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF])); + } + + #[test] + fn test_bit_vec_extend() { + let mut bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111]); + let ext = BitVec::from_bytes(&[0b01001001, 0b10010010, 0b10111101]); + bit_vec.extend(ext.iter()); + assert_eq!(bit_vec, BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111, + 0b01001001, 0b10010010, 0b10111101])); + } + +/* nightly + #[test] + fn test_bit_vec_append() { + // Append to BitVec that holds a multiple of U32_BITS bits + let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]); + let mut b = BitVec::new(); + b.push(false); + b.push(true); + b.push(true); + + a.append(&mut b); + + assert_eq!(a.len(), 35); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 3); + + assert!(a.eq_vec(&[true, false, true, false, false, false, false, false, + false, false, false, true, false, false, true, false, + true, false, false, true, false, false, true, false, + false, false, true, true, false, false, true, true, + false, true, true])); + + // Append to arbitrary BitVec + let mut a = BitVec::new(); + a.push(true); + a.push(false); + + let mut b = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); + + a.append(&mut b); + + assert_eq!(a.len(), 42); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 40); + + assert!(a.eq_vec(&[true, false, true, false, true, false, false, false, + false, false, false, false, false, true, false, false, + true, false, true, false, false, true, false, false, + true, false, false, false, true, true, false, false, + true, true, true, false, false, true, false, true, + false, true])); + + // Append to empty BitVec + let mut a = BitVec::new(); + let mut b = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); + + a.append(&mut b); + + assert_eq!(a.len(), 40); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 40); + + assert!(a.eq_vec(&[true, false, true, false, false, false, false, false, + false, false, false, true, false, false, true, false, + true, false, false, true, false, false, true, false, + false, false, true, true, false, false, true, true, + true, false, false, true, false, true, false, true])); + + // Append empty BitVec + let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]); + let mut b = BitVec::new(); + + a.append(&mut b); + + assert_eq!(a.len(), 40); + assert_eq!(b.len(), 0); + + assert!(a.eq_vec(&[true, false, true, false, false, false, false, false, + false, false, false, true, false, false, true, false, + true, false, false, true, false, false, true, false, + false, false, true, true, false, false, true, true, + true, false, false, true, false, true, false, true])); + } + + + #[test] + fn test_bit_vec_split_off() { + // Split at 0 + let mut a = BitVec::new(); + a.push(true); + a.push(false); + a.push(false); + a.push(true); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 4); + + assert!(b.eq_vec(&[true, false, false, true])); + + // Split at last bit + a.truncate(0); + a.push(true); + a.push(false); + a.push(false); + a.push(true); + + let b = a.split_off(4); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + + assert!(a.eq_vec(&[true, false, false, true])); + + // Split at block boundary + let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011]); + + let b = a.split_off(32); + + assert_eq!(a.len(), 32); + assert_eq!(b.len(), 8); + + assert!(a.eq_vec(&[true, false, true, false, false, false, false, false, + false, false, false, true, false, false, true, false, + true, false, false, true, false, false, true, false, + false, false, true, true, false, false, true, true])); + assert!(b.eq_vec(&[true, true, true, true, false, false, true, true])); + + // Don't split at block boundary + let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, + 0b01101011, 0b10101101]); + + let b = a.split_off(13); + + assert_eq!(a.len(), 13); + assert_eq!(b.len(), 35); + + assert!(a.eq_vec(&[true, false, true, false, false, false, false, false, + false, false, false, true, false])); + assert!(b.eq_vec(&[false, true, false, true, false, false, true, false, + false, true, false, false, false, true, true, false, + false, true, true, false, true, true, false, true, + false, true, true, true, false, true, false, true, + true, false, true])); + } +*/ + + #[test] + fn test_into_iter() { + let bools = vec![true, false, true, true]; + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(false), iter.next()); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(true), iter.next()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next()); + + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(false), iter.next_back()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(None, iter.next_back()); + assert_eq!(None, iter.next_back()); + + let bit_vec: BitVec = bools.iter().map(|n| *n).collect(); + let mut iter = bit_vec.into_iter(); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(Some(true), iter.next()); + assert_eq!(Some(false), iter.next()); + assert_eq!(Some(true), iter.next_back()); + assert_eq!(None, iter.next()); + assert_eq!(None, iter.next_back()); + } + + #[test] + fn iter() { + let b = BitVec::with_capacity(10); + let _a: Iter = b.iter(); + } +} + +#[cfg(all(test, feature = "nightly"))] mod bench; + diff --git a/bitflags/.cargo-checksum.json b/bitflags/.cargo-checksum.json new file mode 100644 index 000000000..fd339c87a --- /dev/null +++ b/bitflags/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"} \ No newline at end of file diff --git a/bitflags/CHANGELOG.md b/bitflags/CHANGELOG.md new file mode 100644 index 000000000..1f5b4252c --- /dev/null +++ b/bitflags/CHANGELOG.md @@ -0,0 +1,108 @@ +# 1.0.3 + +- Improve zero value flag handling and documentation ([#157]) + +[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157 + +# 1.0.2 + +- 30% improvement in compile time of bitflags crate ([#156]) + +- Documentation improvements ([#153]) + +- Implementation cleanup ([#149]) + +[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156 +[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153 +[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149 + +# 1.0.1 +- Add support for `pub(restricted)` specifier on the bitflags struct ([#135]) +- Optimize performance of `all()` when called from a separate crate ([#136]) + +[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135 +[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136 + +# 1.0.0 +- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24]) + +- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants + +- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112]) + +- Other improvements to unit tests and documentation ([#106] and [#115]) + +[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24 +[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106 +[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112 +[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115 + +## How to update your code to use associated constants +Assuming the following structure definition: +```rust +bitflags! { + struct Something: u8 { + const FOO = 0b01, + const BAR = 0b10 + } +} +``` +In 0.9 and older you could do: +```rust +let x = FOO.bits | BAR.bits; +``` +Now you must use: +```rust +let x = Something::FOO.bits | Something::BAR.bits; +``` + +# 0.9.1 +- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105]) + +[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105 + +# 0.9.0 +- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84]) + +- **[breaking change]** Terminate const items with semicolons instead of commas ([#87]) + +- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86]) + +- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85]) + +- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74]) + +[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74 +[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84 +[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85 +[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86 +[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87 + +# 0.8.2 +- Update feature flag used when building bitflags as a dependency of the Rust toolchain + +# 0.8.1 +- Allow bitflags to be used as a dependency of the Rust toolchain + +# 0.8.0 +- Add support for the experimental `i128` and `u128` integer types ([#57]) +- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55]) + This may break code that defines its own set method + +[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55 +[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57 + +# 0.7.1 +*(yanked)* + +# 0.7.0 +- Implement the Extend trait ([#49]) +- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51]) + +[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49 +[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51 + +# 0.6.0 +- The `no_std` feature was removed as it is now the default +- The `assignment_operators` feature was remove as it is now enabled by default +- Some clippy suggestions have been applied diff --git a/bitflags/CODE_OF_CONDUCT.md b/bitflags/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..f7add90ae --- /dev/null +++ b/bitflags/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at coc@senaite.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/bitflags/Cargo.toml b/bitflags/Cargo.toml new file mode 100644 index 000000000..956e9e976 --- /dev/null +++ b/bitflags/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bitflags" +version = "1.0.4" +authors = ["The Rust Project Developers"] +exclude = [".travis.yml", "appveyor.yml", "bors.toml"] +description = "A macro to generate structures which behave like bitflags.\n" +homepage = "https://github.com/bitflags/bitflags" +documentation = "https://docs.rs/bitflags" +readme = "README.md" +keywords = ["bit", "bitmask", "bitflags", "flags"] +categories = ["no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/bitflags/bitflags" +[package.metadata.docs.rs] +features = ["example_generated"] + +[features] +default = [] +example_generated = [] +[badges.travis-ci] +repository = "bitflags/bitflags" diff --git a/bitflags/LICENSE-APACHE b/bitflags/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bitflags/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bitflags/LICENSE-MIT b/bitflags/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/bitflags/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bitflags/README.md b/bitflags/README.md new file mode 100644 index 000000000..df12934c3 --- /dev/null +++ b/bitflags/README.md @@ -0,0 +1,34 @@ +bitflags +======== + +[![Build Status](https://travis-ci.com/bitflags/bitflags.svg?branch=master)](https://travis-ci.com/bitflags/bitflags) +[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) +[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags) +[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg) +![License](https://img.shields.io/crates/l/bitflags.svg) + +A Rust macro to generate structures which behave like a set of bitflags + +- [Documentation](https://docs.rs/bitflags) +- [Release notes](https://github.com/bitflags/bitflags/releases) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bitflags = "1.0" +``` + +and this to your crate root: + +```rust +#[macro_use] +extern crate bitflags; +``` + +## Rust Version Support + +The minimum supported Rust version is 1.20 due to use of associated constants. diff --git a/bitflags/src/example_generated.rs b/bitflags/src/example_generated.rs new file mode 100644 index 000000000..cf188d99c --- /dev/null +++ b/bitflags/src/example_generated.rs @@ -0,0 +1,14 @@ +//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS +//! CRATE**. + +bitflags! { + /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). + /// Note that this struct is just for documentation purposes only, it must not be used outside + /// this crate. + pub struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } +} diff --git a/bitflags/src/lib.rs b/bitflags/src/lib.rs new file mode 100644 index 000000000..9e1bcfd6c --- /dev/null +++ b/bitflags/src/lib.rs @@ -0,0 +1,1229 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates a `struct` that manages a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = Flags::A | Flags::C; +//! let e2 = Flags::B | Flags::C; +//! assert_eq!((e1 | e2), Flags::ABC); // union +//! assert_eq!((e1 & e2), Flags::C); // intersection +//! assert_eq!((e1 - e2), Flags::A); // set difference +//! assert_eq!(!e2, Flags::A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! use std::fmt; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated struct and its associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `flags`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! mod example { +//! bitflags! { +//! pub struct Flags1: u32 { +//! const A = 0b00000001; +//! } +//! } +//! bitflags! { +//! # pub +//! struct Flags2: u32 { +//! const B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::Flags1::A; +//! let flag2 = example::Flags2::B; // error: const `B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct` by placing them +//! before the `flags` keyword. +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits automatically derived for the `struct` using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `flags`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerExp`, `Octal` and `UpperExp` trait is also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to flags +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if all flags are currently set +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! - `set`: inserts or removes the specified flags depending on the passed value +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated struct. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! Flags::A | Flags::C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +//! } +//! ``` +//! +//! # Zero Flags +//! +//! Flags with a value equal to zero will have some strange behavior that one should be aware of. +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const NONE = 0b00000000; +//! const SOME = 0b00000001; +//! } +//! } +//! +//! fn main() { +//! let empty = Flags::empty(); +//! let none = Flags::NONE; +//! let some = Flags::SOME; +//! +//! // Zero flags are treated as always present +//! assert!(empty.contains(Flags::NONE)); +//! assert!(none.contains(Flags::NONE)); +//! assert!(some.contains(Flags::NONE)); +//! +//! // Zero flags will be ignored when testing for emptiness +//! assert!(none.is_empty()); +//! } +//! ``` + +#![no_std] +#![doc(html_root_url = "https://docs.rs/bitflags/1.0.4")] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structure. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// const C = 0b00000100; +/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// use std::fmt; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = Flags::A | Flags::B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + () $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub ($($vis)+)) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __bitflags { + ( + $(#[$outer:meta])* + ($($vis:tt)*) $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $(#[$outer])* + $($vis)* struct $BitFlags { + bits: $T, + } + + __impl_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + impl $crate::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag(&self) -> bool { false } + )+ + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag(&self) -> bool { + if Self::$Flag.bits == 0 && self.bits != 0 { + false + } else { + self.bits & Self::$Flag.bits == Self::$Flag.bits + } + } + } + )+ + } + + let mut first = true; + $( + if <$BitFlags as __BitFlags>::$Flag(self) { + if !first { + f.write_str(" | ")?; + } + first = false; + f.write_str(__bitflags_stringify!($Flag))?; + } + )+ + if first { + f.write_str("(empty)")?; + } + Ok(()) + } + } + impl $crate::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: $BitFlags = $BitFlags { bits: $value }; + )+ + + /// Returns an empty set of flags. + #[inline] + pub fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + + /// Returns the set containing all flags. + #[inline] + pub fn all() -> $BitFlags { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag() -> $T { 0 } + )+ + } + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag() -> $T { Self::$Flag.bits } + } + )+ + } + $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag())|+ } + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub fn bits(&self) -> $T { + self.bits + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) == 0 { + $crate::_core::option::Option::Some($BitFlags { bits }) + } else { + $crate::_core::option::Option::None + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits } & $BitFlags::all() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub fn is_empty(&self) -> bool { + *self == $BitFlags::empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub fn is_all(&self) -> bool { + *self == $BitFlags::all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub fn intersects(&self, other: $BitFlags) -> bool { + !(*self & other).is_empty() + } + + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub fn contains(&self, other: $BitFlags) -> bool { + (*self & other) == other + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: $BitFlags, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + } + + impl $crate::_core::ops::BitOr for $BitFlags { + type Output = $BitFlags; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl $crate::_core::ops::BitOrAssign for $BitFlags { + + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + } + + impl $crate::_core::ops::BitXor for $BitFlags { + type Output = $BitFlags; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl $crate::_core::ops::BitXorAssign for $BitFlags { + + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl $crate::_core::ops::BitAnd for $BitFlags { + type Output = $BitFlags; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl $crate::_core::ops::BitAndAssign for $BitFlags { + + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: $BitFlags) { + self.bits &= other.bits; + } + } + + impl $crate::_core::ops::Sub for $BitFlags { + type Output = $BitFlags; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl $crate::_core::ops::SubAssign for $BitFlags { + + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + } + + impl $crate::_core::ops::Not for $BitFlags { + type Output = $BitFlags; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + + impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> $BitFlags { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // fn f() -> i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // fn f() -> i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + fn $($item:tt)* + ) => { + $(#[$filtered])* + fn $($item)* + }; +} + +// Same as std::stringify but callable from __impl_bitflags, which needs to use +// local_inner_macros so can only directly call macros from this crate. +#[macro_export] +#[doc(hidden)] +macro_rules! __bitflags_stringify { + ($s:ident) => { + stringify!($s) + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +mod tests { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + struct Flags: u32 { + const A = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + } + + bitflags! { + struct _CfgFlags: u32 { + #[cfg(windows)] + const _CFG_A = 0b01; + #[cfg(unix)] + const _CFG_B = 0b01; + #[cfg(windows)] + const _CFG_C = _CFG_A.bits | 0b10; + } + } + + bitflags! { + struct AnotherSetOfFlags: i8 { + const ANOTHER_FLAG = -1_i8; + } + } + + bitflags! { + struct LongFlags: u32 { + const LONG_A = 0b1111111111111111; + } + } + + #[test] + fn test_bits() { + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(Flags::A.bits(), 0b00000001); + assert_eq!(Flags::ABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); + assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); + assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!( + AnotherSetOfFlags::from_bits(!0_i8), + Some(AnotherSetOfFlags::ANOTHER_FLAG) + ); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); + assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); + assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); + + assert_eq!( + AnotherSetOfFlags::from_bits_truncate(0_i8), + AnotherSetOfFlags::empty() + ); + } + + #[test] + fn test_is_empty() { + assert!(Flags::empty().is_empty()); + assert!(!Flags::A.is_empty()); + assert!(!Flags::ABC.is_empty()); + + assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!Flags::A.is_all()); + assert!(Flags::ABC.is_all()); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = Flags::ABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = Flags::A; + let e2 = Flags::B; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(Flags::ABC.contains(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_insert() { + let mut e1 = Flags::A; + let e2 = Flags::A | Flags::B; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); + } + + #[test] + fn test_remove() { + let mut e1 = Flags::A | Flags::B; + let e2 = Flags::A | Flags::C; + e1.remove(e2); + assert_eq!(e1, Flags::B); + + let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; + e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_set() { + let mut e1 = Flags::A | Flags::C; + e1.set(Flags::B, true); + e1.set(Flags::C, false); + + assert_eq!(e1, Flags::A | Flags::B); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = Flags::A | Flags::C; + // union + m1 |= Flags::A; + assert_eq!(m1, Flags::A); + // intersection + m1 &= e1; + assert_eq!(m1, Flags::A); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::A; + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::B; + flags.extend([Flags::A, Flags::ABC].iter().cloned()); + assert_eq!(flags, Flags::ABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!( + [Flags::A, Flags::B].iter().cloned().collect::(), + Flags::A | Flags::B + ); + assert_eq!( + [Flags::A, Flags::ABC].iter().cloned().collect::(), + Flags::ABC + ); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = Flags::B; + assert!(a < b); + a = Flags::C; + assert!(!(a < b) && b < a); + b = Flags::C | Flags::B; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = Flags::A; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = Flags::B; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = Flags::ABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", Flags::ABC), "111"); + assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const X = 0; + } + } + bitflags! { + struct PrivateFlags: i8 { + const Y = 0; + } + } + + #[test] + fn test_private() { + let _ = PrivateFlags::Y; + } + } + + #[test] + fn test_public() { + let _ = submodule::PublicFlags::X; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), Flags::A); + assert_eq!(format!("{:?}", Flags::A), "A"); + } + + #[test] + fn test_deprecated() { + bitflags! { + pub struct TestFlags: u32 { + #[deprecated(note = "Use something else.")] + const ONE = 1; + } + } + } + + #[test] + fn test_pub_crate() { + mod module { + bitflags! { + pub (crate) struct Test: u8 { + const FOO = 1; + } + } + } + + assert_eq!(module::Test::FOO.bits(), 1); + } + + #[test] + fn test_pub_in_module() { + mod module { + mod submodule { + bitflags! { + // `pub (in super)` means only the module `module` will + // be able to access this. + pub (in super) struct Test: u8 { + const FOO = 1; + } + } + } + + mod test { + // Note: due to `pub (in super)`, + // this cannot be accessed directly by the testing code. + pub(super) fn value() -> u8 { + super::submodule::Test::FOO.bits() + } + } + + pub fn value() -> u8 { + test::value() + } + } + + assert_eq!(module::value(), 1) + } + + #[test] + fn test_zero_value_flags() { + bitflags! { + struct Flags: u32 { + const NONE = 0b0; + const SOME = 0b1; + } + } + + assert!(Flags::empty().contains(Flags::NONE)); + assert!(Flags::SOME.contains(Flags::NONE)); + assert!(Flags::NONE.is_empty()); + + assert_eq!(format!("{:?}", Flags::empty()), "NONE"); + assert_eq!(format!("{:?}", Flags::SOME), "SOME"); + } +} diff --git a/bstr/.cargo-checksum.json b/bstr/.cargo-checksum.json new file mode 100644 index 000000000..51934f223 --- /dev/null +++ b/bstr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"59604ece62a407dc9164732e5adea02467898954c3a5811fd2dc140af14ef15b"} \ No newline at end of file diff --git a/bstr/COPYING b/bstr/COPYING new file mode 100644 index 000000000..d5a7d7ec8 --- /dev/null +++ b/bstr/COPYING @@ -0,0 +1,8 @@ +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/bstr/Cargo.toml b/bstr/Cargo.toml new file mode 100644 index 000000000..094b6d237 --- /dev/null +++ b/bstr/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bstr" +version = "0.1.4" +authors = ["Andrew Gallant "] +exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"] +description = "A string type that is not required to be valid UTF-8." +homepage = "https://github.com/BurntSushi/bstr" +documentation = "https://docs.rs/bstr" +readme = "README.md" +keywords = ["string", "str", "byte", "bytes", "text"] +categories = ["text-processing", "encoding"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/BurntSushi/bstr" +[profile.release] +debug = true + +[lib] +bench = false +[dependencies.lazy_static] +version = "1.2" +optional = true + +[dependencies.memchr] +version = "2.1.2" +default-features = false + +[dependencies.regex-automata] +version = "0.1.5" +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.85" +optional = true +default-features = false +[dev-dependencies.quickcheck] +version = "0.8.1" +default-features = false + +[dev-dependencies.ucd-parse] +version = "0.1.3" + +[dev-dependencies.unicode-segmentation] +version = "1.2.1" + +[features] +default = ["std", "unicode"] +serde1 = ["std", "serde1-nostd", "serde/std"] +serde1-nostd = ["serde"] +std = ["memchr/use_std"] +unicode = ["lazy_static", "regex-automata"] +[badges.appveyor] +repository = "BurntSushi/bstr" + +[badges.travis-ci] +repository = "BurntSushi/bstr" diff --git a/bstr/LICENSE-APACHE b/bstr/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bstr/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bstr/LICENSE-MIT b/bstr/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/bstr/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/bstr/README.md b/bstr/README.md new file mode 100644 index 000000000..28be1f32a --- /dev/null +++ b/bstr/README.md @@ -0,0 +1,252 @@ +bstr +==== +This crate provides a `BString` and `BStr` types that are conventionally UTF-8 +for Rust. They differ from the standard library's `String` and `str` types in +that they are not required to be valid UTF-8, but may be fully or partially +valid UTF-8. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/bstr.svg)](https://travis-ci.org/BurntSushi/bstr) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/bstr?svg=true)](https://ci.appveyor.com/project/BurntSushi/bstr) +[![](http://meritbadge.herokuapp.com/bstr)](https://crates.io/crates/bstr) + + +### Documentation + +https://docs.rs/bstr + + +### When should I use byte strings? + +See this part of the documentation for more details: +https://docs.rs/bstr/0.1.0/bstr/#when-should-i-use-byte-strings. + +The short story is that byte strings are useful when it is inconvenient or +incorrect to require valid UTF-8. + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bstr = "0.1" +``` + + +### Examples + +The following two examples exhibit both the API features of byte strings and +the I/O convenience functions provided for reading line-by-line quickly. + +This first example simply shows how to efficiently iterate over lines in +stdin, and print out lines containing a particular substring: + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + if line.contains("Dimension") { + stdout.write_all(line.as_bytes())?; + } + Ok(true) + })?; + Ok(()) +} +``` + +This example shows how to count all of the words (Unicode-aware) in stdin, +line-by-line: + +```rust +use std::error::Error; +use std::io; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut words = 0; + stdin.lock().for_byte_line_with_terminator(|line| { + words += line.words().count(); + Ok(true) + })?; + println!("{}", words); + Ok(()) +} +``` + +This example shows how to convert a stream on stdin to uppercase without +performing UTF-8 validation _and_ amortizing allocation. On standard ASCII +text, this is quite a bit faster than what you can (easily) do with standard +library APIs. (N.B. Any invalid UTF-8 bytes are passed through unchanged.) + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::BString; +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut upper = BString::new(); + stdin.lock().for_byte_line_with_terminator(|line| { + upper.clear(); + line.to_uppercase_into(&mut upper); + stdout.write_all(upper.as_bytes())?; + Ok(true) + })?; + Ok(()) +} +``` + +This example shows how to extract the first 10 visual characters (as grapheme +clusters) from each line, where invalid UTF-8 sequences are generally treated +as a single character and are passed through correctly: + +```rust +use std::error::Error; +use std::io::{self, Write}; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + let end = line + .grapheme_indices() + .map(|(_, end, _)| end) + .take(10) + .last() + .unwrap_or(line.len()); + stdout.write_all(line[..end].trim_end().as_bytes())?; + stdout.write_all(b"\n")?; + Ok(true) + })?; + Ok(()) +} +``` + + +### Cargo features + +This crates comes with a few features that control standard library, serde +and Unicode support. + +* `std` - **Enabled** by default. This provides APIs that require the standard + library, such as `BString`. +* `unicode` - **Enabled** by default. This provides APIs that require sizable + Unicode data compiled into the binary. This includes, but is not limited to, + grapheme/word/sentence segmenters. When this is disabled, basic support such + as UTF-8 decoding is still included. +* `serde1` - **Disabled** by default. Enables implementations of serde traits + for the `BStr` and `BString` types. +* `serde1-nostd` - **Disabled** by default. Enables implementations of serde + traits for the `BStr` type only, intended for use without the standard + library. Generally, you either want `serde1` or `serde1-nostd`, not both. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version (MSRV) is `1.28.0`. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. MSRV may be bumped in minor version releases. + + +### Future work + +Since this is meant to be a core crate, getting a `1.0` release is a priority. +My hope is to move to `1.0` within the next year and commit to its API so that +`bstr` can be used as a public dependency. + +A large part of the API surface area was taken from the standard library, so +from an API design perspective, a good portion of this crate should be mature. +The main differences from the standard library are in how the various substring +search routines work. The standard library provides generic infrastructure for +supporting different types of searches with a single method, where as this +library prefers to define new methods for each type of search and drop the +generic infrastructure. + +Some _probable_ future considerations for APIs include, but are not limited to: + +* A convenience layer on top of the `aho-corasick` crate. +* Unicode normalization. +* More sophisticated support for dealing with Unicode case, perhaps by + combining the use cases supported by [`caseless`](http://docs.rs/caseless) + and [`unicase`](https://docs.rs/unicase). +* Add facilities for dealing with OS strings and file paths, probably via + simple conversion routines. + +Here are some examples that are _probably_ out of scope for this crate: + +* Regular expressions. +* Unicode collation. + +The exact scope isn't quite clear, but I expect we can iterate on it. + +In general, as stated below, this crate is an experiment in bringing lots of +related APIs together into a single crate while simultaneously attempting to +keep the total number of dependencies low. Indeed, every dependency of `bstr`, +except for `memchr`, is optional. + + +### High level motivation + +Strictly speaking, the `bstr` crate provides very little that can't already be +achieved with a `Vec`/`&[u8]` and the ecosystem of library crates. For +example: + +* The standard library's + [`Utf8Error`](https://doc.rust-lang.org/std/str/struct.Utf8Error.html) + can be used for incremental lossy decoding of `&[u8]`. +* The + [`unicode-segmentation`](https://unicode-rs.github.io/unicode-segmentation/unicode_segmentation/index.html) + crate can be used for iterating over graphemes (or words), but is only + implemented for `&str` types. One could use `Utf8Error` above to implement + grapheme iteration with the same semantics as what `bstr` provides (automatic + Unicode replacement codepoint substitution). +* The [`twoway`](https://docs.rs/twoway/0.2.0/twoway/) crate can be used for + fast substring searching on `&[u8]`. + +So why create `bstr`? Part of the point of the `bstr` crate is to provide a +uniform API of coupled components instead of relying on users to piece together +loosely coupled components from the crate ecosystem. For example, if you wanted +to perform a search and replace in a `Vec`, then writing the code to do +that with the `twoway` crate is not that difficult, but it's still additional +glue code you have to write. This work adds up depending on what you're doing. +Consider, for example, trimming and splitting, along with their different +variants. + +In other words, `bstr` is partially a way of pushing back against the +micro-crate ecosystem that appears to be evolving. It's not clear to me whether +this experiment will be successful or not, but it is definitely a goal of +`bstr` to keep its dependency list lightweight. For example, `serde` is an +optional dependency because there is no feasible alternative, but `twoway` is +not, where we instead prefer to implement our own substring search. In service +of this philosophy, currently, the only required dependency of `bstr` is +`memchr`. + + +### License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. diff --git a/bstr/examples/graphemes-std.rs b/bstr/examples/graphemes-std.rs new file mode 100644 index 000000000..da3faf325 --- /dev/null +++ b/bstr/examples/graphemes-std.rs @@ -0,0 +1,28 @@ +extern crate unicode_segmentation; + +use std::error::Error; +use std::io::{self, BufRead, Write}; + +use unicode_segmentation::UnicodeSegmentation; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + let end = line + .grapheme_indices(true) + .map(|(start, g)| start + g.len()) + .take(10) + .last() + .unwrap_or(line.len()); + #[allow(deprecated)] // for Rust 1.28.0 + stdout.write_all(line[..end].trim_right().as_bytes())?; + stdout.write_all(b"\n")?; + + line.clear(); + } + Ok(()) +} diff --git a/bstr/examples/graphemes.rs b/bstr/examples/graphemes.rs new file mode 100644 index 000000000..b680e024c --- /dev/null +++ b/bstr/examples/graphemes.rs @@ -0,0 +1,24 @@ +extern crate bstr; + +use std::error::Error; +use std::io::{self, Write}; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + let end = line + .grapheme_indices() + .map(|(_, end, _)| end) + .take(10) + .last() + .unwrap_or(line.len()); + stdout.write_all(line[..end].trim_end().as_bytes())?; + stdout.write_all(b"\n")?; + Ok(true) + })?; + Ok(()) +} diff --git a/bstr/examples/lines-std.rs b/bstr/examples/lines-std.rs new file mode 100644 index 000000000..51da217b2 --- /dev/null +++ b/bstr/examples/lines-std.rs @@ -0,0 +1,17 @@ +use std::error::Error; +use std::io::{self, BufRead, Write}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + if line.contains("Dimension") { + stdout.write_all(line.as_bytes())?; + } + line.clear(); + } + Ok(()) +} diff --git a/bstr/examples/lines.rs b/bstr/examples/lines.rs new file mode 100644 index 000000000..8429aee36 --- /dev/null +++ b/bstr/examples/lines.rs @@ -0,0 +1,19 @@ +extern crate bstr; + +use std::error::Error; +use std::io::{self, Write}; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + stdin.lock().for_byte_line_with_terminator(|line| { + if line.contains("Dimension") { + stdout.write_all(line.as_bytes())?; + } + Ok(true) + })?; + Ok(()) +} diff --git a/bstr/examples/uppercase-std.rs b/bstr/examples/uppercase-std.rs new file mode 100644 index 000000000..3029d76ca --- /dev/null +++ b/bstr/examples/uppercase-std.rs @@ -0,0 +1,15 @@ +use std::error::Error; +use std::io::{self, BufRead, Write}; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + stdout.write_all(line.to_uppercase().as_bytes())?; + line.clear(); + } + Ok(()) +} diff --git a/bstr/examples/uppercase.rs b/bstr/examples/uppercase.rs new file mode 100644 index 000000000..08bf40af0 --- /dev/null +++ b/bstr/examples/uppercase.rs @@ -0,0 +1,21 @@ +extern crate bstr; + +use std::error::Error; +use std::io::{self, Write}; + +use bstr::BString; +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdout = io::BufWriter::new(io::stdout()); + + let mut upper = BString::new(); + stdin.lock().for_byte_line_with_terminator(|line| { + upper.clear(); + line.to_uppercase_into(&mut upper); + stdout.write_all(upper.as_bytes())?; + Ok(true) + })?; + Ok(()) +} diff --git a/bstr/examples/words-std.rs b/bstr/examples/words-std.rs new file mode 100644 index 000000000..39c82e30f --- /dev/null +++ b/bstr/examples/words-std.rs @@ -0,0 +1,20 @@ +extern crate unicode_segmentation; + +use std::error::Error; +use std::io::{self, BufRead}; + +use unicode_segmentation::UnicodeSegmentation; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut stdin = stdin.lock(); + + let mut words = 0; + let mut line = String::new(); + while stdin.read_line(&mut line)? > 0 { + words += line.unicode_words().count(); + line.clear(); + } + println!("{}", words); + Ok(()) +} diff --git a/bstr/examples/words.rs b/bstr/examples/words.rs new file mode 100644 index 000000000..64fb19d69 --- /dev/null +++ b/bstr/examples/words.rs @@ -0,0 +1,17 @@ +extern crate bstr; + +use std::error::Error; +use std::io; + +use bstr::io::BufReadExt; + +fn main() -> Result<(), Box> { + let stdin = io::stdin(); + let mut words = 0; + stdin.lock().for_byte_line_with_terminator(|line| { + words += line.words().count(); + Ok(true) + })?; + println!("{}", words); + Ok(()) +} diff --git a/bstr/rustfmt.toml b/bstr/rustfmt.toml new file mode 100644 index 000000000..c7ad93baf --- /dev/null +++ b/bstr/rustfmt.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/bstr/scripts/generate-unicode-data b/bstr/scripts/generate-unicode-data new file mode 100755 index 000000000..eac4a75f7 --- /dev/null +++ b/bstr/scripts/generate-unicode-data @@ -0,0 +1,150 @@ +#!/bin/sh + +set -e +D="$(dirname "$0")" + +# Convenience function for checking that a command exists. +requires() { + cmd="$1" + if ! command -v "$cmd" > /dev/null 2>&1; then + echo "DEPENDENCY MISSING: $cmd must be installed" >&2 + exit 1 + fi +} + +# Test if an array ($2) contains a particular element ($1). +array_exists() { + needle="$1" + shift + + for el in "$@"; do + if [ "$el" = "$needle" ]; then + return 0 + fi + done + return 1 +} + +graphemes() { + regex="$(sh "$D/regex/grapheme.sh")" + + echo "generating forward grapheme DFA" + ucd-generate dfa \ + --name GRAPHEME_BREAK_FWD \ + --sparse --minimize --anchored --state-size 2 \ + src/unicode/fsm/ \ + "$regex" + + echo "generating reverse grapheme DFA" + ucd-generate dfa \ + --name GRAPHEME_BREAK_REV \ + --reverse --longest \ + --sparse --minimize --anchored --state-size 2 \ + src/unicode/fsm/ \ + "$regex" +} + +words() { + regex="$(sh "$D/regex/word.sh")" + + echo "generating forward word DFA (this can take a while)" + ucd-generate dfa \ + --name WORD_BREAK_FWD \ + --sparse --minimize --anchored --state-size 4 \ + src/unicode/fsm/ \ + "$regex" +} + +sentences() { + regex="$(sh "$D/regex/sentence.sh")" + + echo "generating forward sentence DFA (this can take a while)" + ucd-generate dfa \ + --name SENTENCE_BREAK_FWD \ + --minimize \ + --sparse --anchored --state-size 4 \ + src/unicode/fsm/ \ + "$regex" +} + +regional_indicator() { + # For finding all occurrences of region indicators. This is used to handle + # regional indicators as a special case for the reverse grapheme iterator + # and the reverse word iterator. + echo "generating regional indicator DFA" + ucd-generate dfa \ + --name REGIONAL_INDICATOR_REV \ + --reverse \ + --classes --minimize --anchored --premultiply --state-size 1 \ + src/unicode/fsm/ \ + "\p{gcb=Regional_Indicator}" +} + +simple_word() { + echo "generating forward simple word DFA" + ucd-generate dfa \ + --name SIMPLE_WORD_FWD \ + --sparse --minimize --state-size 2 \ + src/unicode/fsm/ \ + "\w" +} + +whitespace() { + echo "generating forward whitespace DFA" + ucd-generate dfa \ + --name WHITESPACE_ANCHORED_FWD \ + --anchored --classes --premultiply --minimize --state-size 1 \ + src/unicode/fsm/ \ + "\s+" + + echo "generating reverse whitespace DFA" + ucd-generate dfa \ + --name WHITESPACE_ANCHORED_REV \ + --reverse \ + --anchored --classes --minimize --state-size 1 \ + src/unicode/fsm/ \ + "\s+" +} + +main() { + if array_exists "-h" "$@" || array_exists "--help" "$@"; then + echo "Usage: $(basename "$0") [--list-commands] [] ..." >&2 + exit + fi + + commands=" + graphemes + sentences + words + regional-indicator + simple-word + whitespace + " + if array_exists "--list-commands" "$@"; then + for cmd in $commands; do + echo "$cmd" + done + exit + fi + + # ucd-generate is used to compile regexes into DFAs. + requires ucd-generate + + # For development when ucd-generate needs to be updated. + cargo install -f --path /home/andrew/rust/ucd-generate + + all= + if [ $# -eq 0 ] || array_exists "all" "$@"; then + all=yes + fi + for cmd in "$@"; do + if [ -n "$all" ] || array_exists "$cmd" $commands; then + fun="$(echo "$cmd" | sed 's/-/_/g')" + eval "$fun" + else + echo "unrecognized command: $cmd" >&2 + fi + done +} + +main "$@" diff --git a/bstr/scripts/regex/grapheme.sh b/bstr/scripts/regex/grapheme.sh new file mode 100644 index 000000000..0b2b54daa --- /dev/null +++ b/bstr/scripts/regex/grapheme.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# This regex was manually written, derived from the rules in UAX #29. +# Particularly, from Table 1c, which lays out a regex for grapheme clusters. + +CR="\p{gcb=CR}" +LF="\p{gcb=LF}" +Control="\p{gcb=Control}" +Prepend="\p{gcb=Prepend}" +L="\p{gcb=L}" +V="\p{gcb=V}" +LV="\p{gcb=LV}" +LVT="\p{gcb=LVT}" +T="\p{gcb=T}" +RI="\p{gcb=RI}" +Extend="\p{gcb=Extend}" +ZWJ="\p{gcb=ZWJ}" +SpacingMark="\p{gcb=SpacingMark}" + +Any="\p{any}" +ExtendPict="\p{Extended_Pictographic}" + +echo "(?x) +$CR $LF +| +$Control +| +$Prepend* +( + ( + ($L* ($V+ | $LV $V* | $LVT) $T*) + | + $L+ + | + $T+ + ) + | + $RI $RI + | + $ExtendPict ($Extend* $ZWJ $ExtendPict)* + | + [^$Control $CR $LF] +) +[$Extend $ZWJ $SpacingMark]* +| +$Any +" diff --git a/bstr/scripts/regex/sentence.sh b/bstr/scripts/regex/sentence.sh new file mode 100644 index 000000000..689d1849f --- /dev/null +++ b/bstr/scripts/regex/sentence.sh @@ -0,0 +1,176 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# This is a regex that I reverse engineered from the sentence boundary chain +# rules in UAX #29. Unlike the grapheme regex, which is essentially provided +# for us in UAX #29, no such sentence regex exists. +# +# I looked into how ICU achieves this, since UAX #29 hints that producing +# finite state machines for grapheme/sentence/word/line breaking is possible, +# but only easy to do for graphemes. ICU does this by implementing their own +# DSL for describing the break algorithms in terms of the chaining rules +# directly. You can see an example for sentences in +# icu4c/source/data/brkitr/rules/sent.txt. ICU then builds a finite state +# machine from those rules in a mostly standard way, but implements the +# "chaining" aspect of the rules by connecting overlapping end and start +# states. For example, given SB7: +# +# (Upper | Lower) ATerm x Upper +# +# Then the naive way to convert this into a regex would be something like +# +# [\p{sb=Upper}\p{sb=Lower}]\p{sb=ATerm}\p{sb=Upper} +# +# Unfortunately, this is incorrect. Why? Well, consider an example like so: +# +# U.S.A. +# +# A correct implementation of the sentence breaking algorithm should not insert +# any breaks here, exactly in accordance with repeatedly applying rule SB7 as +# given above. Our regex fails to do this because it will first match `U.S` +# without breaking them---which is correct---but will then start looking for +# its next rule beginning with a full stop (in ATerm) and followed by an +# uppercase letter (A). This will wind up triggering rule SB11 (without +# matching `A`), which inserts a break. +# +# The reason why this happens is because our initial application of rule SB7 +# "consumes" the next uppercase letter (S), which we want to reuse as a prefix +# in the next rule application. A natural way to express this would be with +# look-around, although it's not clear that works in every case since you +# ultimately might want to consume that ending uppercase letter. In any case, +# we can't use look-around in our truly regular regexes, so we must fix this. +# The approach we take is to explicitly repeat rules when a suffix of a rule +# is a prefix of another rule. In the case of SB7, the end of the rule, an +# uppercase letter, also happens to match the beginning of the rule. This can +# in turn be repeated indefinitely. Thus, our actual translation to a regex is: +# +# [\p{sb=Upper}\p{sb=Lower}]\p{sb=ATerm}\p{sb=Upper}(\p{sb=ATerm}\p{sb=Upper}* +# +# It turns out that this is exactly what ICU does, but in their case, they do +# it automatically. In our case, we connect the chaining rules manually. It's +# tedious. With that said, we do no implement Unicode line breaking with this +# approach, which is a far scarier beast. In that case, it would probably be +# worth writing the code to do what ICU does. +# +# In the case of sentence breaks, there aren't *too* many overlaps of this +# nature. We list them out exhaustively to make this clear, because it's +# essentially impossible to easily observe this in the regex. (It took me a +# full day to figure all of this out.) Rules marked with N/A mean that they +# specify a break, and this strategy only really applies to stringing together +# non-breaks. +# +# SB1 - N/A +# SB2 - N/A +# SB3 - None +# SB4 - N/A +# SB5 - None +# SB6 - None +# SB7 - End overlaps with beginning of SB7 +# SB8 - End overlaps with beginning of SB7 +# SB8a - End overlaps with beginning of SB6, SB8, SB8a, SB9, SB10, SB11 +# SB9 - None +# SB10 - None +# SB11 - None +# SB998 - N/A +# +# SB8a is in particular quite tricky to get right without look-ahead, since it +# allows ping-ponging between match rules SB8a and SB9-11, where SB9-11 +# otherwise indicate that a break has been found. In the regex below, we tackle +# this by only permitting part of SB8a to match inside our core non-breaking +# repetition. In particular, we only allow the parts of SB8a to match that +# permit the non-breaking components to continue. If a part of SB8a matches +# that guarantees a pop out to SB9-11, (like `STerm STerm`), then we let it +# happen. This still isn't correct because an SContinue might be seen which +# would allow moving back into SB998 and thus the non-breaking repetition, so +# we handle that case as well. +# +# Finally, the last complication here is the sprinkling of $Ex* everywhere. +# This essentially corresponds to the implementation of SB5 by following +# UAX #29's recommendation in S6.2. Essentially, we use it avoid ever breaking +# in the middle of a grapheme cluster. + +CR="\p{sb=CR}" +LF="\p{sb=LF}" +Sep="\p{sb=Sep}" +Close="\p{sb=Close}" +Sp="\p{sb=Sp}" +STerm="\p{sb=STerm}" +ATerm="\p{sb=ATerm}" +SContinue="\p{sb=SContinue}" +Numeric="\p{sb=Numeric}" +Upper="\p{sb=Upper}" +Lower="\p{sb=Lower}" +OLetter="\p{sb=OLetter}" + +Ex="[\p{sb=Extend}\p{sb=Format}]" +ParaSep="[$Sep $CR $LF]" +SATerm="[$STerm $ATerm]" + +LetterSepTerm="[$OLetter $Upper $Lower $ParaSep $SATerm]" + +echo "(?x) +( + # SB6 + $ATerm $Ex* + $Numeric + | + # SB7 + [$Upper $Lower] $Ex* $ATerm $Ex* + $Upper $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # SB8 + $ATerm $Ex* $Close* $Ex* $Sp* $Ex* + ([^$LetterSepTerm] $Ex*)* $Lower $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # SB8a + $SATerm $Ex* $Close* $Ex* $Sp* $Ex* + ( + $SContinue + | + $ATerm $Ex* + # Permit repetition of SB8a + (($Close $Ex*)* ($Sp $Ex*)* $SATerm)* + # In order to continue non-breaking matching, we now must observe + # a match with a rule that keeps us in SB6-8a. Otherwise, we've entered + # one of SB9-11 and know that a break must follow. + ( + # overlap with SB6 + $Numeric + | + # overlap with SB8 + ($Close $Ex*)* ($Sp $Ex*)* + ([^$LetterSepTerm] $Ex*)* $Lower $Ex* + # overlap with SB7 + ($ATerm $Ex* $Upper $Ex*)* + | + # overlap with SB8a + ($Close $Ex*)* ($Sp $Ex*)* $SContinue + ) + | + $STerm $Ex* + # Permit repetition of SB8a + (($Close $Ex*)* ($Sp $Ex*)* $SATerm)* + # As with ATerm above, in order to continue non-breaking matching, we + # must now observe a match with a rule that keeps us out of SB9-11. + # For STerm, the only such possibility is to see an SContinue. Anything + # else will result in a break. + ($Close $Ex*)* ($Sp $Ex*)* $SContinue + ) + | + # SB998 + # The logic behind this catch-all is that if we get to this point and + # see a Sep, CR, LF, STerm or ATerm, then it has to fall into one of + # SB9, SB10 or SB11. In the cases of SB9-11, we always find a break since + # SB11 acts as a catch-all to induce a break following a SATerm that isn't + # handled by rules SB6-SB8a. + [^$ParaSep $SATerm] +)* +# The following collapses rules SB3, SB4, part of SB8a, SB9, SB10 and SB11. +($SATerm $Ex* ($Close $Ex*)* ($Sp $Ex*)*)* ($CR $LF | $ParaSep)? +" diff --git a/bstr/scripts/regex/word.sh b/bstr/scripts/regex/word.sh new file mode 100644 index 000000000..78c7a05cf --- /dev/null +++ b/bstr/scripts/regex/word.sh @@ -0,0 +1,111 @@ +#!/bin/sh + +# vim: indentexpr= nosmartindent autoindent +# vim: tabstop=2 shiftwidth=2 softtabstop=2 + +# See the comments in regex/sentence.sh for the general approach to how this +# regex was written. +# +# Writing the regex for this was *hard*. It took me two days of hacking to get +# this far, and that was after I had finished the sentence regex, so my brain +# was fully cached on this. Unlike the sentence regex, the rules in the regex +# below don't correspond as nicely to the rules in UAX #29. In particular, the +# UAX #29 rules have a ton of overlap with each other, which requires crazy +# stuff in the regex. I'm not even sure the regex below is 100% correct or even +# minimal, however, I did compare this with the ICU word segmenter on a few +# different corpora, and it produces identical results. (In addition to of +# course passing the UCD tests.) +# +# In general, I consider this approach to be a failure. Firstly, this is +# clearly a write-only regex. Secondly, building the minimized DFA for this is +# incredibly slow. Thirdly, the DFA is itself very large (~240KB). Fourthly, +# reversing this regex (for reverse word iteration) results in a >19MB DFA. +# Yes. That's MB. Wat. And it took 5 minutes to build. +# +# I think we might consider changing our approach to this problem. The normal +# path I've seen, I think, is to decode codepoints one at a time, and then +# thread them through a state machine in the code itself. We could take this +# approach, or possibly combine it with a DFA that tells us which Word_Break +# value a codepoint has. I'd prefer the latter approach, but it requires adding +# RegexSet support to regex-automata. Something that should definitely be done, +# but is a fair amount of work. +# +# Gah. + +CR="\p{wb=CR}" +LF="\p{wb=LF}" +Newline="\p{wb=Newline}" +ZWJ="\p{wb=ZWJ}" +RI="\p{wb=Regional_Indicator}" +Katakana="\p{wb=Katakana}" +HebrewLet="\p{wb=HebrewLetter}" +ALetter="\p{wb=ALetter}" +SingleQuote="\p{wb=SingleQuote}" +DoubleQuote="\p{wb=DoubleQuote}" +MidNumLet="\p{wb=MidNumLet}" +MidLetter="\p{wb=MidLetter}" +MidNum="\p{wb=MidNum}" +Numeric="\p{wb=Numeric}" +ExtendNumLet="\p{wb=ExtendNumLet}" +WSegSpace="\p{wb=WSegSpace}" + +Any="\p{any}" +Ex="[\p{wb=Extend} \p{wb=Format} $ZWJ]" +ExtendPict="\p{Extended_Pictographic}" +AHLetter="[$ALetter $HebrewLet]" +MidNumLetQ="[$MidNumLet $SingleQuote]" + +AHLetterRepeat="$AHLetter $Ex* ([$MidLetter $MidNumLetQ] $Ex* $AHLetter $Ex*)*" +NumericRepeat="$Numeric $Ex* ([$MidNum $MidNumLetQ] $Ex* $Numeric $Ex*)*" + +echo "(?x) +$CR $LF +| +[$Newline $CR $LF] +| +$WSegSpace $WSegSpace+ +| +( + ([^$Newline $CR $LF]? $Ex* $ZWJ $ExtendPict $Ex*)+ + | + ($ExtendNumLet $Ex*)* $AHLetter $Ex* + ( + ( + ($NumericRepeat | $ExtendNumLet $Ex*)* + | + [$MidLetter $MidNumLetQ] $Ex* + ) + $AHLetter $Ex* + )+ + ($NumericRepeat | $ExtendNumLet $Ex*)* + | + ($ExtendNumLet $Ex*)* $AHLetter $Ex* ($NumericRepeat | $ExtendNumLet $Ex*)+ + | + ($ExtendNumLet $Ex*)* $Numeric $Ex* + ( + ( + ($AHLetterRepeat | $ExtendNumLet $Ex*)* + | + [$MidNum $MidNumLetQ] $Ex* + ) + $Numeric $Ex* + )+ + ($AHLetterRepeat | $ExtendNumLet $Ex*)* + | + ($ExtendNumLet $Ex*)* $Numeric $Ex* ($AHLetterRepeat | $ExtendNumLet $Ex*)+ + | + $Katakana $Ex* + (($Katakana | $ExtendNumLet) $Ex*)+ + | + $ExtendNumLet $Ex* + (($ExtendNumLet | $AHLetter | $Numeric | $Katakana) $Ex*)+ +)+ +| +$HebrewLet $Ex* $SingleQuote $Ex* +| +($HebrewLet $Ex* $DoubleQuote $Ex*)+ $HebrewLet $Ex* +| +$RI $Ex* $RI $Ex* +| +$Any $Ex* +" diff --git a/bstr/src/ascii.rs b/bstr/src/ascii.rs new file mode 100644 index 000000000..9799d1083 --- /dev/null +++ b/bstr/src/ascii.rs @@ -0,0 +1,322 @@ +use core::mem; + +// The following ~400 lines of code exists for exactly one purpose, which is +// to optimize this code: +// +// byte_slice.iter().position(|&b| b > 0x7F).unwrap_or(byte_slice.len()) +// +// Yes... Overengineered is a word that comes to mind, but this is effectively +// a very similar problem to memchr, and virtually nobody has been able to +// resist optimizing the crap out of that (except for perhaps the BSD and MUSL +// folks). In particular, this routine makes a very common case (ASCII) very +// fast, which seems worth it. We do stop short of adding AVX variants of the +// code below in order to retain our sanity and also to avoid needing to deal +// with runtime target feature detection. RESIST! +// +// In order to understand the SIMD version below, it would be good to read this +// comment describing how my memchr routine works: +// https://github.com/BurntSushi/rust-memchr/blob/b0a29f267f4a7fad8ffcc8fe8377a06498202883/src/x86/sse2.rs#L19-L106 +// +// The primary difference with memchr is that for ASCII, we can do a bit less +// work. In particular, we don't need to detect the presence of a specific +// byte, but rather, whether any byte has its most significant bit set. That +// means we can effectively skip the _mm_cmpeq_epi8 step and jump straight to +// _mm_movemask_epi8. + +#[cfg(any(test, not(target_arch = "x86_64")))] +const USIZE_BYTES: usize = mem::size_of::(); +#[cfg(any(test, not(target_arch = "x86_64")))] +const FALLBACK_LOOP_SIZE: usize = 2 * USIZE_BYTES; + +// This is a mask where the most significant bit of each byte in the usize +// is set. We test this bit to determine whether a character is ASCII or not. +// Namely, a single byte is regarded as an ASCII codepoint if and only if it's +// most significant bit is not set. +#[cfg(any(test, not(target_arch = "x86_64")))] +const ASCII_MASK_U64: u64 = 0x8080808080808080; +#[cfg(any(test, not(target_arch = "x86_64")))] +const ASCII_MASK: usize = ASCII_MASK_U64 as usize; + +/// Returns the index of the first non ASCII byte in the given slice. +/// +/// If slice only contains ASCII bytes, then the length of the slice is +/// returned. +pub fn first_non_ascii_byte(slice: &[u8]) -> usize { + #[cfg(not(target_arch = "x86_64"))] + { + first_non_ascii_byte_fallback(slice) + } + + #[cfg(target_arch = "x86_64")] + { + first_non_ascii_byte_sse2(slice) + } +} + +#[cfg(any(test, not(target_arch = "x86_64")))] +fn first_non_ascii_byte_fallback(slice: &[u8]) -> usize { + let align = USIZE_BYTES - 1; + let start_ptr = slice.as_ptr(); + let end_ptr = slice[slice.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if slice.len() < USIZE_BYTES { + return first_non_ascii_byte_slow(start_ptr, end_ptr, ptr); + } + + let chunk = read_unaligned_usize(ptr); + let mask = chunk & ASCII_MASK; + if mask != 0 { + return first_non_ascii_byte_mask(mask); + } + + ptr = ptr_add(ptr, USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(ptr_sub(end_ptr, USIZE_BYTES) >= start_ptr); + if slice.len() >= FALLBACK_LOOP_SIZE { + while ptr <= ptr_sub(end_ptr, FALLBACK_LOOP_SIZE) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr as *const usize); + let b = *(ptr_add(ptr, USIZE_BYTES) as *const usize); + if (a | b) & ASCII_MASK != 0 { + // What a kludge. We wrap the position finding code into + // a non-inlineable function, which makes the codegen in + // the tight loop above a bit better by avoiding a + // couple extra movs. We pay for it by two additional + // stores, but only in the case of finding a non-ASCII + // byte. + #[inline(never)] + unsafe fn findpos( + start_ptr: *const u8, + ptr: *const u8, + ) -> usize { + let a = *(ptr as *const usize); + let b = *(ptr_add(ptr, USIZE_BYTES) as *const usize); + + let mut at = sub(ptr, start_ptr); + let maska = a & ASCII_MASK; + if maska != 0 { + return at + first_non_ascii_byte_mask(maska); + } + + at += USIZE_BYTES; + let maskb = b & ASCII_MASK; + debug_assert!(maskb != 0); + return at + first_non_ascii_byte_mask(maskb); + } + return findpos(start_ptr, ptr); + } + ptr = ptr_add(ptr, FALLBACK_LOOP_SIZE); + } + } + first_non_ascii_byte_slow(start_ptr, end_ptr, ptr) + } +} + +#[cfg(target_arch = "x86_64")] +fn first_non_ascii_byte_sse2(slice: &[u8]) -> usize { + use core::arch::x86_64::*; + + const VECTOR_SIZE: usize = mem::size_of::<__m128i>(); + const VECTOR_ALIGN: usize = VECTOR_SIZE - 1; + const VECTOR_LOOP_SIZE: usize = 4 * VECTOR_SIZE; + + let start_ptr = slice.as_ptr(); + let end_ptr = slice[slice.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if slice.len() < VECTOR_SIZE { + return first_non_ascii_byte_slow(start_ptr, end_ptr, ptr); + } + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(chunk); + if mask != 0 { + return mask.trailing_zeros() as usize; + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr); + debug_assert!(end_ptr.sub(VECTOR_SIZE) >= start_ptr); + if slice.len() >= VECTOR_LOOP_SIZE { + while ptr <= ptr_sub(end_ptr, VECTOR_LOOP_SIZE) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let c = _mm_load_si128(ptr.add(2 * VECTOR_SIZE) as *const __m128i); + let d = _mm_load_si128(ptr.add(3 * VECTOR_SIZE) as *const __m128i); + + let or1 = _mm_or_si128(a, b); + let or2 = _mm_or_si128(c, d); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask = _mm_movemask_epi8(a); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(b); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(c); + if mask != 0 { + return at + mask.trailing_zeros() as usize; + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(d); + debug_assert!(mask != 0); + return at + mask.trailing_zeros() as usize; + } + ptr = ptr_add(ptr, VECTOR_LOOP_SIZE); + } + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + debug_assert!(sub(end_ptr, ptr) >= VECTOR_SIZE); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(chunk); + if mask != 0 { + return sub(ptr, start_ptr) + mask.trailing_zeros() as usize; + } + ptr = ptr.add(VECTOR_SIZE); + } + first_non_ascii_byte_slow(start_ptr, end_ptr, ptr) + } +} + +#[inline(always)] +unsafe fn first_non_ascii_byte_slow( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, +) -> usize { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr < end_ptr { + if *ptr > 0x7F { + return sub(ptr, start_ptr); + } + ptr = ptr.offset(1); + } + sub(end_ptr, start_ptr) +} + +/// Compute the position of the first ASCII byte in the given mask. +/// +/// The mask should be computed by `chunk & ASCII_MASK`, where `chunk` is +/// 8 contiguous bytes of the slice being checked where *at least* one of those +/// bytes is not an ASCII byte. +/// +/// The position returned is always in the inclusive range [0, 7]. +#[cfg(any(test, not(target_arch = "x86_64")))] +fn first_non_ascii_byte_mask(mask: usize) -> usize { + #[cfg(target_endian = "little")] + { mask.trailing_zeros() as usize / 8 } + #[cfg(target_endian = "big")] + { mask.leading_zeros() as usize / 8 } +} + +/// Increment the given pointer by the given amount. +unsafe fn ptr_add(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset(amt as isize) +} + +/// Decrement the given pointer by the given amount. +unsafe fn ptr_sub(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset((amt as isize).wrapping_neg()) +} + +#[cfg(any(test, not(target_arch = "x86_64")))] +unsafe fn read_unaligned_usize(ptr: *const u8) -> usize { + use core::ptr; + + let mut n: usize = 0; + ptr::copy_nonoverlapping(ptr, &mut n as *mut _ as *mut u8, USIZE_BYTES); + n +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} + +#[cfg(test)] +mod tests { + use super::*; + + // Our testing approach here is to try and exhaustively test every case. + // This includes the position at which a non-ASCII byte occurs in addition + // to the alignment of the slice that we're searching. + + #[test] + fn positive_fallback_forward() { + for i in 0..517 { + let s = "a".repeat(i); + assert_eq!( + i, + first_non_ascii_byte_fallback(s.as_bytes()), + "i: {:?}, len: {:?}, s: {:?}", + i, s.len(), s + ); + } + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn positive_sse2_forward() { + for i in 0..517 { + let b = "a".repeat(i).into_bytes(); + assert_eq!(b.len(), first_non_ascii_byte_sse2(&b)); + } + } + + #[test] + fn negative_fallback_forward() { + for i in 0..517 { + for align in 0..65 { + let mut s = "a".repeat(i); + s.push_str("☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"); + let s = s.get(align..).unwrap_or(""); + assert_eq!( + i.saturating_sub(align), + first_non_ascii_byte_fallback(s.as_bytes()), + "i: {:?}, align: {:?}, len: {:?}, s: {:?}", + i, align, s.len(), s + ); + } + } + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn negative_sse2_forward() { + for i in 0..517 { + for align in 0..65 { + let mut s = "a".repeat(i); + s.push_str("☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"); + let s = s.get(align..).unwrap_or(""); + assert_eq!( + i.saturating_sub(align), + first_non_ascii_byte_sse2(s.as_bytes()), + "i: {:?}, align: {:?}, len: {:?}, s: {:?}", + i, align, s.len(), s + ); + } + } + } +} diff --git a/bstr/src/bstr.rs b/bstr/src/bstr.rs new file mode 100644 index 000000000..b1bc2f972 --- /dev/null +++ b/bstr/src/bstr.rs @@ -0,0 +1,3991 @@ +#[cfg(feature = "std")] +use std::borrow::Cow; +#[cfg(feature = "std")] +use std::ffi::OsStr; +#[cfg(feature = "std")] +use std::iter; +#[cfg(feature = "std")] +use std::path::Path; + +use core::cmp; +use core::mem; +use core::ops; +use core::ptr; +use core::slice; +use core::str; + +use memchr::{memchr, memrchr}; + +use ascii; +#[cfg(feature = "std")] +use bstring::BString; +use search::{PrefilterState, TwoWay}; +use slice_index::SliceIndex; +#[cfg(feature = "unicode")] +use unicode::{ + Graphemes, GraphemeIndices, + Sentences, SentenceIndices, + Words, WordIndices, WordsWithBreaks, WordsWithBreakIndices, + whitespace_len_fwd, whitespace_len_rev, +}; +use utf8::{self, Chars, CharIndices, Utf8Error}; + +/// A short-hand constructor for building a `&BStr`. +/// +/// This idiosyncratic constructor is useful for concisely building byte string +/// slices. Its primary utility is in conveniently writing byte string literals +/// in a uniform way. For example, consider this code that does not compile: +/// +/// ```ignore +/// let strs = vec![b"a", b"xy"]; +/// ``` +/// +/// The above code doesn't compile because the type of the byte string literal +/// `b"a"` is `&'static [u8; 1]`, and the type of `b"xy"` is +/// `&'static [u8; 2]`. Since their types aren't the same, they can't be stored +/// in the same `Vec`. (This is dissimilar from normal Unicode string slices, +/// where both `"a"` and `"xy"` have the same type of `&'static str`.) +/// +/// One way of getting the above code to compile is to convert byte strings to +/// slices. You might try this: +/// +/// ```ignore +/// let strs = vec![&b"a", &b"xy"]; +/// ``` +/// +/// But this just creates values with type `& &'static [u8; 1]` and +/// `& &'static [u8; 2]`. Instead, you need to force the issue like so: +/// +/// ``` +/// let strs = vec![&b"a"[..], &b"xy"[..]]; +/// // or +/// let strs = vec![b"a".as_ref(), b"xy".as_ref()]; +/// ``` +/// +/// But neither of these are particularly convenient to type, especially when +/// it's something as common as a string literal. Thus, this constructor +/// permits writing the following instead: +/// +/// ``` +/// use bstr::B; +/// +/// let strs = vec![B("a"), B(b"xy")]; +/// ``` +/// +/// Notice that this also lets you mix and match both string literals and byte +/// string literals. This can be quite convenient! +#[allow(non_snake_case)] +#[inline] +pub fn B<'a, B: ?Sized + AsRef<[u8]>>(bytes: &'a B) -> &'a BStr { + BStr::new(bytes.as_ref()) +} + +/// A byte string slice that is conventionally UTF-8. +/// +/// A byte string slice is the core string type in this library, and is usually +/// seen in its borrowed form, `&BStr`. The principle difference between a +/// `&BStr` and a `&str` (Rust's standard Unicode string slice) is that a +/// `&BStr` is only *conventionally* UTF-8, where as a `&str` is guaranteed to +/// always be valid UTF-8. +/// +/// If you need ownership or a growable byte string buffer, then use +/// [`BString`](struct.BString.html). +/// +/// # Literals +/// +/// A byte string literal has type `&'static BStr`. The most convenient way to +/// write a byte string literal is by using the short-hand [`B`](fn.B.html) +/// constructor function: +/// +/// ``` +/// use bstr::{B, BStr}; +/// +/// // A byte string literal can be constructed from a normal Unicode string. +/// let s = B("a byte string literal"); +/// // A byte string literal can also be constructed from a Rust byte string. +/// let s = B(b"another byte string literal"); +/// +/// // BStr::new can also be used: +/// let s = BStr::new("a byte string literal"); +/// let s = BStr::new(b"another byte string literal"); +/// ``` +/// +/// # Representation +/// +/// A `&BStr` has the same representation as a `&str`. That is, a `&BStr` is +/// a fat pointer which consists of a pointer to some bytes and a length. +/// +/// # Trait implementations +/// +/// The `BStr` type has a number of trait implementations, and in particular, +/// defines equality and ordinal comparisons between `&BStr`, `&str` and +/// `&[u8]` for convenience. +/// +/// The `Debug` implementation for `BStr` shows its bytes as a normal string. +/// For invalid UTF-8, hex escape sequences are used. +/// +/// The `Display` implementation behaves as if `BStr` were first lossily +/// converted to a `str`. Invalid UTF-8 bytes are substituted with the Unicode +/// replacement codepoint, which looks like this: �. +/// +/// # Indexing and slicing +/// +/// A `BStr` implements indexing and slicing using `[..]` notation. Unlike +/// the standard `str` type, the `BStr` type permits callers to index +/// individual bytes. For example: +/// +/// ``` +/// use bstr::B; +/// +/// let s = B("foo☃bar"); +/// assert_eq!(&s[0..3], "foo"); +/// assert_eq!(s[2], b'o'); +/// assert_eq!(&s[3..6], "☃"); +/// +/// // Nothing stops you from indexing or slicing invalid UTF-8. +/// assert_eq!(s[3], b'\xE2'); +/// assert_eq!(&s[3..5], B(b"\xE2\x98")); +/// ``` +#[derive(Hash)] +pub struct BStr { + bytes: [u8], +} + +impl BStr { + /// Create a byte string slice from anything that can be borrowed as a + /// sequence of bytes. This includes, but is not limited to, `&Vec`, + /// `&[u8]`, `&String` and `&str`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// assert_eq!("abc", BStr::new("abc")); + /// assert_eq!("abc", BStr::new(b"abc")); + /// ``` + #[inline] + pub fn new>(bytes: &B) -> &BStr { + BStr::from_bytes(bytes.as_ref()) + } + + /// Create a mutable byte string slice from anything that can be borrowed + /// as a sequence of bytes. This includes, but is not limited to, `&mut + /// Vec` and `&mut [u8]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// assert_eq!("abc", BStr::new("abc")); + /// assert_eq!("abc", BStr::new(b"abc")); + /// ``` + #[inline] + pub fn new_mut>(bytes: &mut B) -> &mut BStr { + BStr::from_bytes_mut(bytes.as_mut()) + } + + /// Create an immutable byte string slice from an immutable byte slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// let bytes = &[b'a']; + /// let bs = BStr::from_bytes(bytes); + /// assert_eq!("a", bs); + /// ``` + #[inline] + pub fn from_bytes(slice: &[u8]) -> &BStr { + unsafe { mem::transmute(slice) } + } + + /// Create a mutable byte string slice from a mutable byte slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// let bytes = &mut [b'a']; + /// { + /// let bs = BStr::from_bytes_mut(bytes); + /// bs[0] = b'b'; + /// } + /// assert_eq!(b"b", bytes); + /// ``` + #[inline] + pub fn from_bytes_mut(slice: &mut [u8]) -> &mut BStr { + unsafe { mem::transmute(slice) } + } + + /// Create a byte string from its constituent pointer and length, where + /// the length is the number of bytes in the byte string. + /// + /// # Safety + /// + /// This function is unsafe as there is no guarantee that the given pointer + /// is valid for `len` elements, nor whether the lifetime inferred is a + /// suitable lifetime for the returned slice. + /// + /// `data` must be a non-null pointer, even for a zero length slice. A + /// pointer that is usable for zero-length slices can be obtaining from + /// the standard library's `NonNull::dangling()` constructor. + /// + /// The total size of the given slice must be no larger than `isize::MAX` + /// bytes in memory. + /// + /// # Caveat + /// + /// The lifetime for the returned slice is inferred from its usage. To + /// prevent accidental misuse, it's suggested to tie the lifetime to + /// whichever source lifetime is safe in the context, such as by providing + /// a helper function taking the lifetime of a host value for the slice, or + /// by explicit annotation. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// // manifest a byte string from a single byte + /// let x = b'Z'; + /// let ptr = &x as *const u8; + /// let s = unsafe { BStr::from_raw_parts(ptr, 1) }; + /// assert_eq!(s, "Z"); + /// ``` + pub unsafe fn from_raw_parts<'a>(data: *const u8, len: usize) -> &'a BStr { + BStr::new(slice::from_raw_parts(data, len)) + } + + /// Create a mutable byte string from its constituent pointer and length, + /// where the length is the number of bytes in the byte string. + /// + /// # Safety + /// + /// This function is unsafe as there is no guarantee that the given pointer + /// is valid for `len` elements, nor whether the lifetime inferred is a + /// suitable lifetime for the returned slice. + /// + /// `data` must be a non-null pointer, even for a zero length slice. A + /// pointer that is usable for zero-length slices can be obtaining from + /// the standard library's `NonNull::dangling()` constructor. + /// + /// The total size of the given slice must be no larger than `isize::MAX` + /// bytes in memory. + /// + /// The above reasons are the same as for + /// [`from_raw_parts`](#method.from_raw_parts). In addition, for this + /// constructor, callers must guarantee that the mutable slice returned + /// is not aliased with any other reference. + /// + /// # Caveat + /// + /// The lifetime for the returned slice is inferred from its usage. To + /// prevent accidental misuse, it's suggested to tie the lifetime to + /// whichever source lifetime is safe in the context, such as by providing + /// a helper function taking the lifetime of a host value for the slice, or + /// by explicit annotation. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::mem; + /// use bstr::{BStr, BString}; + /// + /// // For demonstration purposes, get a mutable pointer to a byte string. + /// let mut buf = BString::from("bar"); + /// let ptr = buf.as_mut_ptr(); + /// // Drop buf without deallocating, to avoid &mut aliasing. + /// mem::forget(buf); + /// + /// // Now convert it to a mutable byte string from the raw pointer. + /// let mut s = unsafe { BStr::from_raw_parts_mut(ptr, 3) }; + /// s.make_ascii_uppercase(); + /// assert_eq!(s, "BAR"); + /// ``` + pub unsafe fn from_raw_parts_mut<'a>( + data: *mut u8, + len: usize, + ) -> &'a mut BStr { + BStr::new_mut(slice::from_raw_parts_mut(data, len)) + } + + /// Create an immutable byte string from an OS string slice. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns `None` if the given OS string is not valid UTF-8. (For + /// example, on Windows, file paths are allowed to be a sequence of + /// arbitrary 16-bit integers. Not all such sequences can be transcoded to + /// valid UTF-8.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::BStr; + /// + /// let os_str = OsStr::new("foo"); + /// let bs = BStr::from_os_str(os_str).expect("should be valid UTF-8"); + /// assert_eq!(bs, "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn from_os_str(os_str: &OsStr) -> Option<&BStr> { + BStr::from_os_str_imp(os_str) + } + + #[cfg(feature = "std")] + #[cfg(unix)] + #[inline] + fn from_os_str_imp(os_str: &OsStr) -> Option<&BStr> { + use std::os::unix::ffi::OsStrExt; + + Some(BStr::new(os_str.as_bytes())) + } + + #[cfg(feature = "std")] + #[cfg(not(unix))] + #[inline] + fn from_os_str_imp(os_str: &OsStr) -> Option<&BStr> { + os_str.to_str().map(BStr::new) + } + + /// Create an immutable byte string from a file path. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns `None` if the given path is not valid UTF-8. (For example, + /// on Windows, file paths are allowed to be a sequence of arbitrary 16-bit + /// integers. Not all such sequences can be transcoded to valid UTF-8.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::Path; + /// + /// use bstr::BStr; + /// + /// let path = Path::new("foo"); + /// let bs = BStr::from_path(path).expect("should be valid UTF-8"); + /// assert_eq!(bs, "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn from_path(path: &Path) -> Option<&BStr> { + BStr::from_os_str(path.as_os_str()) + } + + /// Returns the length, in bytes, of this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// assert_eq!(0, BStr::new("").len()); + /// assert_eq!(3, BStr::new("abc").len()); + /// assert_eq!(8, BStr::new("☃βツ").len()); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.bytes.len() + } + + /// Returns true if and only if the length of this byte string is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// assert!(BStr::new("").is_empty()); + /// assert!(!BStr::new("abc").is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// Returns an immutable byte slice of this `BStr`'s contents. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("hello"); + /// + /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes + } + + /// Returns a mutable byte slice of this `BStr`'s contents. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("hello"); + /// s.as_bytes_mut()[1] = b'a'; + /// + /// assert_eq!(&[104, 97, 108, 108, 111], s.as_bytes()); + /// ``` + #[inline] + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } + + /// Create a new owned byte string from this byte string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// let s = BStr::new("abc"); + /// let mut owned = s.to_bstring(); + /// owned.push_char('d'); + /// assert_eq!("abcd", owned); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_bstring(&self) -> BString { + BString::from_vec(self.as_bytes().to_vec()) + } + + /// Safely convert this byte string into a `&str` if it's valid UTF-8. + /// + /// If this byte string is not valid UTF-8, then an error is returned. The + /// error returned indicates the first invalid byte found and the length + /// of the error. + /// + /// In cases where a lossy conversion to `&str` is acceptable, then use one + /// of the [`to_str_lossy`](#method.to_str_lossy) + /// or [`to_str_lossy_into`](#method.to_str_lossy_into) methods. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// # fn example() -> Result<(), bstr::Utf8Error> { + /// let s = B("☃βツ").to_str()?; + /// assert_eq!("☃βツ", s); + /// + /// let mut bstring = BString::from("☃βツ"); + /// bstring.push_byte(b'\xFF'); + /// let err = bstring.to_str().unwrap_err(); + /// assert_eq!(8, err.valid_up_to()); + /// # Ok(()) }; example().unwrap() + /// ``` + #[inline] + pub fn to_str(&self) -> Result<&str, Utf8Error> { + utf8::validate(self.as_bytes()).map(|_| { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { + str::from_utf8_unchecked(self.as_bytes()) + } + }) + } + + /// Unsafely convert this byte string into a `&str`, without checking for + /// valid UTF-8. + /// + /// # Safety + /// + /// Callers *must* ensure that this byte string is valid UTF-8 before + /// calling this method. Converting a byte string into a `&str` that is + /// not valid UTF-8 is considered undefined behavior. + /// + /// This routine is useful in performance sensitive contexts where the + /// UTF-8 validity of the byte string is already known and it is + /// undesirable to pay the cost of an additional UTF-8 validation check + /// that [`to_str`](#method.to_str) performs. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// // SAFETY: This is safe because string literals are guaranteed to be + /// // valid UTF-8 by the Rust compiler. + /// let s = unsafe { B("☃βツ").to_str_unchecked() }; + /// assert_eq!("☃βツ", s); + /// ``` + pub unsafe fn to_str_unchecked(&self) -> &str { + str::from_utf8_unchecked(self.as_bytes()) + } + + /// Convert this byte string to a valid UTF-8 string by replacing invalid + /// UTF-8 bytes with the Unicode replacement codepoint (`U+FFFD`). + /// + /// If the byte string is already valid UTF-8, then no copying or + /// allocation is performed and a borrrowed string slice is returned. If + /// the byte string is not valid UTF-8, then an owned string buffer is + /// returned with invalid bytes replaced by the replacement codepoint. + /// + /// This method uses the "substitution of maximal subparts" (Unicode + /// Standard, Chapter 3, Section 9) strategy for inserting the replacement + /// codepoint. Specifically, a replacement codepoint is inserted whenever a + /// byte is found that cannot possibly lead to a valid code unit sequence. + /// If there were previous bytes that represented a prefix of a well-formed + /// code unit sequence, then all of those bytes are substituted with a + /// single replacement codepoint. The "substitution of maximal subparts" + /// strategy is the same strategy used by + /// [W3C's Encoding standard](https://www.w3.org/TR/encoding/). + /// For a more precise description of the maximal subpart strategy, see + /// the Unicode Standard, Chapter 3, Section 9. See also + /// [Public Review Issue #121](http://www.unicode.org/review/pr-121.html). + /// + /// N.B. Rust's standard library also appears to use the same strategy, + /// but it does not appear to be an API guarantee. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::borrow::Cow; + /// use bstr::BString; + /// + /// let mut bstring = BString::from("☃βツ"); + /// assert_eq!(Cow::Borrowed("☃βツ"), bstring.to_str_lossy()); + /// + /// // Add a byte that makes the sequence invalid. + /// bstring.push_byte(b'\xFF'); + /// assert_eq!(Cow::Borrowed("☃βツ\u{FFFD}"), bstring.to_str_lossy()); + /// ``` + /// + /// This demonstrates the "maximal subpart" substitution logic. + /// + /// ``` + /// use bstr::B; + /// + /// // \x61 is the ASCII codepoint for 'a'. + /// // \xF1\x80\x80 is a valid 3-byte code unit prefix. + /// // \xE1\x80 is a valid 2-byte code unit prefix. + /// // \xC2 is a valid 1-byte code unit prefix. + /// // \x62 is the ASCII codepoint for 'b'. + /// // + /// // In sum, each of the prefixes is replaced by a single replacement + /// // codepoint since none of the prefixes are properly completed. This + /// // is in contrast to other strategies that might insert a replacement + /// // codepoint for every single byte. + /// let bs = B(b"\x61\xF1\x80\x80\xE1\x80\xC2\x62"); + /// assert_eq!("a\u{FFFD}\u{FFFD}\u{FFFD}b", bs.to_str_lossy()); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_str_lossy(&self) -> Cow { + match utf8::validate(self.as_bytes()) { + Ok(()) => { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { + Cow::Borrowed(str::from_utf8_unchecked(self.as_bytes())) + } + } + Err(err) => { + let mut lossy = String::with_capacity(self.len()); + let (valid, after) = self + .as_bytes() + .split_at(err.valid_up_to()); + // SAFETY: This is safe because utf8::validate guarantees + // that all of `valid` is valid UTF-8. + lossy.push_str(unsafe { str::from_utf8_unchecked(valid) }); + lossy.push_str("\u{FFFD}"); + if let Some(len) = err.error_len() { + B(&after[len..]).to_str_lossy_into(&mut lossy); + } + Cow::Owned(lossy) + } + } + } + + /// Copy the contents of this byte string into the given owned string + /// buffer, while replacing invalid UTF-8 code unit sequences with the + /// Unicode replacement codepoint (`U+FFFD`). + /// + /// This method uses the same "substitution of maximal subparts" strategy + /// for inserting the replacement codepoint as the + /// [`to_str_lossy`](#method.to_str_lossy) method. + /// + /// This routine is useful for amortizing allocation. However, unlike + /// `to_str_lossy`, this routine will _always_ copy the contents of this + /// byte string into the destination buffer, even if this byte string is + /// valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::borrow::Cow; + /// use bstr::BString; + /// + /// let mut bstring = BString::from("☃βツ"); + /// // Add a byte that makes the sequence invalid. + /// bstring.push_byte(b'\xFF'); + /// + /// let mut dest = String::new(); + /// bstring.to_str_lossy_into(&mut dest); + /// assert_eq!("☃βツ\u{FFFD}", dest); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_str_lossy_into(&self, dest: &mut String) { + dest.reserve(self.len()); + let mut bytes = self.as_bytes(); + loop { + match utf8::validate(bytes) { + Ok(()) => { + // SAFETY: This is safe because utf8::validate guarantees + // that all of `bytes` is valid UTF-8. + dest.push_str(unsafe { str::from_utf8_unchecked(bytes) }); + break; + } + Err(err) => { + let (valid, after) = bytes.split_at(err.valid_up_to()); + // SAFETY: This is safe because utf8::validate guarantees + // that all of `valid` is valid UTF-8. + dest.push_str(unsafe { str::from_utf8_unchecked(valid) }); + dest.push_str("\u{FFFD}"); + match err.error_len() { + None => break, + Some(len) => bytes = &after[len..], + } + } + } + } + } + + /// Create an OS string slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns a UTF-8 decoding error if this byte string is not valid + /// UTF-8. (For example, on Windows, file paths are allowed to be a + /// sequence of arbitrary 16-bit integers. There is no obvious mapping from + /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of + /// 16-bit integers.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("foo"); + /// let os_str = bs.to_os_str().expect("should be valid UTF-8"); + /// assert_eq!(os_str, "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_os_str(&self) -> Result<&OsStr, Utf8Error> { + self.to_os_str_imp() + } + + #[cfg(feature = "std")] + #[cfg(unix)] + #[inline] + fn to_os_str_imp(&self) -> Result<&OsStr, Utf8Error> { + use std::os::unix::ffi::OsStrExt; + + Ok(OsStr::from_bytes(self.as_bytes())) + } + + #[cfg(feature = "std")] + #[cfg(not(unix))] + #[inline] + fn to_os_str_imp(&self) -> Result<&OsStr, Utf8Error> { + self.to_str().map(OsStr::new) + } + + /// Lossily create an OS string slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"foo\xFFbar"); + /// let os_str = bs.to_os_str_lossy(); + /// assert_eq!(os_str.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_os_str_lossy(&self) -> Cow { + self.to_os_str_lossy_imp() + } + + #[cfg(feature = "std")] + #[cfg(unix)] + #[inline] + fn to_os_str_lossy_imp(&self) -> Cow { + use std::os::unix::ffi::OsStrExt; + + Cow::Borrowed(OsStr::from_bytes(self.as_bytes())) + } + + #[cfg(feature = "std")] + #[cfg(not(unix))] + #[inline] + fn to_os_str_lossy_imp(&self) -> Cow { + use std::ffi::OsString; + + match self.to_str_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(OsStr::new(x)), + Cow::Owned(x) => Cow::Owned(OsString::from(x)), + } + } + + /// Create a path slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns a UTF-8 decoding error if this byte string is not valid + /// UTF-8. (For example, on Windows, file paths are allowed to be a + /// sequence of arbitrary 16-bit integers. There is no obvious mapping from + /// an arbitrary sequence of 8-bit integers to an arbitrary sequence of + /// 16-bit integers.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("foo"); + /// let path = bs.to_path().expect("should be valid UTF-8"); + /// assert_eq!(path.as_os_str(), "foo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_path(&self) -> Result<&Path, Utf8Error> { + self.to_os_str().map(Path::new) + } + + /// Lossily create a path slice from this byte string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"foo\xFFbar"); + /// let path = bs.to_path_lossy(); + /// assert_eq!(path.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_path_lossy(&self) -> Cow { + use std::path::PathBuf; + + match self.to_os_str_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), + Cow::Owned(x) => Cow::Owned(PathBuf::from(x)), + } + } + + /// Create a new `BString` by repeating this byte string `n` times. + /// + /// # Panics + /// + /// This function panics if the capacity of the new `BString` would + /// overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!("foofoofoofoo", B("foo").repeat(4)); + /// assert_eq!("", B("foo").repeat(0)); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn repeat(&self, n: usize) -> BString { + iter::repeat(self).take(n).collect() + } + + /// Returns true if and only if this byte string contains the given needle. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert!(B("foo bar").contains("foo")); + /// assert!(B("foo bar").contains("bar")); + /// assert!(!B("foo").contains("foobar")); + /// ``` + #[inline] + pub fn contains>(&self, needle: B) -> bool { + self.find(needle).is_some() + } + + /// Returns true if and only if this byte string has the given prefix. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert!(B("foo bar").starts_with("foo")); + /// assert!(!B("foo bar").starts_with("bar")); + /// assert!(!B("foo").starts_with("foobar")); + /// ``` + #[inline] + pub fn starts_with>(&self, prefix: B) -> bool { + let prefix = prefix.as_ref(); + self.get(..prefix.len()).map_or(false, |x| x == prefix) + } + + /// Returns true if and only if this byte string has the given suffix. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert!(B("foo bar").ends_with("bar")); + /// assert!(!B("foo bar").ends_with("foo")); + /// assert!(!B("bar").ends_with("foobar")); + /// ``` + #[inline] + pub fn ends_with>(&self, suffix: B) -> bool { + let suffix = suffix.as_ref(); + self.len() + .checked_sub(suffix.len()) + .map_or(false, |s| &self[s..] == suffix) + } + + /// Returns the index of the first occurrence of the given needle. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// Note that if you're are searching for the same needle in many + /// different small haystacks, it may be faster to initialize a + /// [`Finder`](struct.Finder.html) once, and reuse it for each search. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo bar baz"); + /// assert_eq!(Some(0), s.find("foo")); + /// assert_eq!(Some(4), s.find("bar")); + /// assert_eq!(None, s.find("quux")); + /// ``` + #[inline] + pub fn find>(&self, needle: B) -> Option { + Finder::new(needle.as_ref()).find(self) + } + + /// Returns the index of the last occurrence of the given needle. + /// + /// The needle may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// Note that if you're are searching for the same needle in many + /// different small haystacks, it may be faster to initialize a + /// [`FinderReverse`](struct.FinderReverse.html) once, and reuse it for + /// each search. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo bar baz"); + /// assert_eq!(Some(0), s.rfind("foo")); + /// assert_eq!(Some(4), s.rfind("bar")); + /// assert_eq!(Some(8), s.rfind("ba")); + /// assert_eq!(None, s.rfind("quux")); + /// ``` + #[inline] + pub fn rfind>(&self, needle: B) -> Option { + FinderReverse::new(needle.as_ref()).rfind(self) + } + + /// Returns an iterator of the non-overlapping occurrences of the given + /// needle. The iterator yields byte offset positions indicating the start + /// of each match. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo bar foo foo quux foo"); + /// let matches: Vec = s.find_iter("foo").collect(); + /// assert_eq!(matches, vec![0, 8, 12, 21]); + /// ``` + /// + /// An empty string matches at every position, including the position + /// immediately following the last byte: + /// + /// ``` + /// use bstr::B; + /// + /// let matches: Vec = B("foo").find_iter("").collect(); + /// assert_eq!(matches, vec![0, 1, 2, 3]); + /// + /// let matches: Vec = B("").find_iter("").collect(); + /// assert_eq!(matches, vec![0]); + /// ``` + #[inline] + pub fn find_iter<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + needle: &'a B, + ) -> Find<'a> { + Find::new(self, BStr::new(needle.as_ref())) + } + + /// Returns an iterator of the non-overlapping occurrences of the given + /// needle in reverse. The iterator yields byte offset positions indicating + /// the start of each match. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo bar foo foo quux foo"); + /// let matches: Vec = s.rfind_iter("foo").collect(); + /// assert_eq!(matches, vec![21, 12, 8, 0]); + /// ``` + /// + /// An empty string matches at every position, including the position + /// immediately following the last byte: + /// + /// ``` + /// use bstr::B; + /// + /// let matches: Vec = B("foo").rfind_iter("").collect(); + /// assert_eq!(matches, vec![3, 2, 1, 0]); + /// + /// let matches: Vec = B("").rfind_iter("").collect(); + /// assert_eq!(matches, vec![0]); + /// ``` + #[inline] + pub fn rfind_iter<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + needle: &'a B, + ) -> FindReverse<'a> { + FindReverse::new(self, BStr::new(needle.as_ref())) + } + + /// Returns the index of the first occurrence of the given byte. If the + /// byte does not occur in this byte string, then `None` is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(Some(10), B("foo bar baz").find_byte(b'z')); + /// assert_eq!(None, B("foo bar baz").find_byte(b'y')); + /// ``` + #[inline] + pub fn find_byte(&self, byte: u8) -> Option { + memchr(byte, self.as_bytes()) + } + + /// Returns the index of the last occurrence of the given byte. If the + /// byte does not occur in this byte string, then `None` is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(Some(10), B("foo bar baz").rfind_byte(b'z')); + /// assert_eq!(None, B("foo bar baz").rfind_byte(b'y')); + /// ``` + #[inline] + pub fn rfind_byte(&self, byte: u8) -> Option { + memrchr(byte, self.as_bytes()) + } + + /// Returns the index of the first occurrence of the given codepoint. + /// If the codepoint does not occur in this byte string, then `None` is + /// returned. + /// + /// Note that if one searches for the replacement codepoint, `\u{FFFD}`, + /// then only explicit occurrences of that encoding will be found. Invalid + /// UTF-8 sequences will not be matched. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(Some(10), B("foo bar baz").find_char('z')); + /// assert_eq!(Some(4), B("αβγγδ").find_char('γ')); + /// assert_eq!(None, B("foo bar baz").find_char('y')); + /// ``` + #[inline] + pub fn find_char(&self, ch: char) -> Option { + self.find(ch.encode_utf8(&mut [0; 4])) + } + + /// Returns the index of the last occurrence of the given codepoint. + /// If the codepoint does not occur in this byte string, then `None` is + /// returned. + /// + /// Note that if one searches for the replacement codepoint, `\u{FFFD}`, + /// then only explicit occurrences of that encoding will be found. Invalid + /// UTF-8 sequences will not be matched. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(Some(10), B("foo bar baz").rfind_char('z')); + /// assert_eq!(Some(6), B("αβγγδ").rfind_char('γ')); + /// assert_eq!(None, B("foo bar baz").rfind_char('y')); + /// ``` + #[inline] + pub fn rfind_char(&self, ch: char) -> Option { + self.rfind(ch.encode_utf8(&mut [0; 4])) + } + + /// Returns an iterator over the fields in a byte string, separated by + /// contiguous whitespace. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let s = B(" foo\tbar\t\u{2003}\nquux \n"); + /// let fields: Vec<&BStr> = s.fields().collect(); + /// assert_eq!(fields, vec!["foo", "bar", "quux"]); + /// ``` + /// + /// A byte string consisting of just whitespace yields no elements: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(0, B(" \n\t\u{2003}\n \t").fields().count()); + /// ``` + #[inline] + pub fn fields(&self) -> Fields { + Fields::new(self) + } + + /// Returns an iterator over the fields in a byte string, separated by + /// contiguous codepoints satisfying the given predicate. + /// + /// If this byte + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let s = B("123foo999999bar1quux123456"); + /// let fields: Vec<&BStr> = s.fields_with(|c| c.is_numeric()).collect(); + /// assert_eq!(fields, vec!["foo", "bar", "quux"]); + /// ``` + /// + /// A byte string consisting of all codepoints satisfying the predicate + /// yields no elements: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(0, B("1911354563").fields_with(|c| c.is_numeric()).count()); + /// ``` + #[inline] + pub fn fields_with bool>(&self, f: F) -> FieldsWith { + FieldsWith::new(self, f) + } + + /// Returns an iterator over substrings of this byte string, separated + /// by the given byte string. Each element yielded is guaranteed not to + /// include the splitter substring. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("Mary had a little lamb").split(" ").collect(); + /// assert_eq!(x, vec!["Mary", "had", "a", "little", "lamb"]); + /// + /// let x: Vec<&BStr> = B("").split("X").collect(); + /// assert_eq!(x, vec![""]); + /// + /// let x: Vec<&BStr> = B("lionXXtigerXleopard").split("X").collect(); + /// assert_eq!(x, vec!["lion", "", "tiger", "leopard"]); + /// + /// let x: Vec<&BStr> = B("lion::tiger::leopard").split("::").collect(); + /// assert_eq!(x, vec!["lion", "tiger", "leopard"]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings yielded by the iterator: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("||||a||b|c").split("|").collect(); + /// assert_eq!(x, vec!["", "", "", "", "a", "", "b", "c"]); + /// + /// let x: Vec<&BStr> = B("(///)").split("/").collect(); + /// assert_eq!(x, vec!["(", "", "", ")"]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored by empty + /// strings. + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("010").split("0").collect(); + /// assert_eq!(x, vec!["", "1", ""]); + /// ``` + /// + /// When the empty string is used as a separator, it splits every **byte** + /// in the byte string, along with the beginning and end of the byte + /// string. + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("rust").split("").collect(); + /// assert_eq!(x, vec!["", "r", "u", "s", "t", ""]); + /// + /// // Splitting by an empty string is not UTF-8 aware. Elements yielded + /// // may not be valid UTF-8! + /// let x: Vec<&BStr> = B("☃").split("").collect(); + /// assert_eq!(x, vec![B(""), B(b"\xE2"), B(b"\x98"), B(b"\x83"), B("")]); + /// ``` + /// + /// Contiguous separators, especially whitespace, can lead to possibly + /// surprising behavior. For example, this code is correct: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B(" a b c").split(" ").collect(); + /// assert_eq!(x, vec!["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// It does *not* give you `["a", "b", "c"]`. For that behavior, use + /// [`fields`](#method.fields) instead. + #[inline] + pub fn split<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + splitter: &'a B, + ) -> Split<'a> { + Split::new(self, BStr::new(splitter.as_ref())) + } + + /// Returns an iterator over substrings of this byte string, separated by + /// the given byte string, in reverse. Each element yielded is guaranteed + /// not to include the splitter substring. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("Mary had a little lamb").rsplit(" ").collect(); + /// assert_eq!(x, vec!["lamb", "little", "a", "had", "Mary"]); + /// + /// let x: Vec<&BStr> = B("").rsplit("X").collect(); + /// assert_eq!(x, vec![""]); + /// + /// let x: Vec<&BStr> = B("lionXXtigerXleopard").rsplit("X").collect(); + /// assert_eq!(x, vec!["leopard", "tiger", "", "lion"]); + /// + /// let x: Vec<&BStr> = B("lion::tiger::leopard").rsplit("::").collect(); + /// assert_eq!(x, vec!["leopard", "tiger", "lion"]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings yielded by the iterator: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("||||a||b|c").rsplit("|").collect(); + /// assert_eq!(x, vec!["c", "b", "", "a", "", "", "", ""]); + /// + /// let x: Vec<&BStr> = B("(///)").rsplit("/").collect(); + /// assert_eq!(x, vec![")", "", "", "("]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored by empty + /// strings. + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("010").rsplit("0").collect(); + /// assert_eq!(x, vec!["", "1", ""]); + /// ``` + /// + /// When the empty string is used as a separator, it splits every **byte** + /// in the byte string, along with the beginning and end of the byte + /// string. + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B("rust").rsplit("").collect(); + /// assert_eq!(x, vec!["", "t", "s", "u", "r", ""]); + /// + /// // Splitting by an empty string is not UTF-8 aware. Elements yielded + /// // may not be valid UTF-8! + /// let x: Vec<&BStr> = B("☃").rsplit("").collect(); + /// assert_eq!(x, vec![B(""), B(b"\x83"), B(b"\x98"), B(b"\xE2"), B("")]); + /// ``` + /// + /// Contiguous separators, especially whitespace, can lead to possibly + /// surprising behavior. For example, this code is correct: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<&BStr> = B(" a b c").rsplit(" ").collect(); + /// assert_eq!(x, vec!["c", "b", "", "a", "", "", "", ""]); + /// ``` + /// + /// It does *not* give you `["a", "b", "c"]`. + #[inline] + pub fn rsplit<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + splitter: &'a B, + ) -> SplitReverse<'a> { + SplitReverse::new(self, BStr::new(splitter.as_ref())) + } + + /// Returns an iterator of at most `limit` substrings of this byte string, + /// separated by the given byte string. If `limit` substrings are yielded, + /// then the last substring will contain the remainder of this byte string. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<_> = B("Mary had a little lamb").splitn(3, " ").collect(); + /// assert_eq!(x, vec!["Mary", "had", "a little lamb"]); + /// + /// let x: Vec<_> = B("").splitn(3, "X").collect(); + /// assert_eq!(x, vec![""]); + /// + /// let x: Vec<_> = B("lionXXtigerXleopard").splitn(3, "X").collect(); + /// assert_eq!(x, vec!["lion", "", "tigerXleopard"]); + /// + /// let x: Vec<_> = B("lion::tiger::leopard").splitn(2, "::").collect(); + /// assert_eq!(x, vec!["lion", "tiger::leopard"]); + /// + /// let x: Vec<_> = B("abcXdef").splitn(1, "X").collect(); + /// assert_eq!(x, vec!["abcXdef"]); + /// + /// let x: Vec<_> = B("abcXdef").splitn(0, "X").collect(); + /// assert!(x.is_empty()); + /// ``` + #[inline] + pub fn splitn<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + limit: usize, + splitter: &'a B, + ) -> SplitN<'a> { + SplitN::new(self, BStr::new(splitter.as_ref()), limit) + } + + /// Returns an iterator of at most `limit` substrings of this byte string, + /// separated by the given byte string, in reverse. If `limit` substrings + /// are yielded, then the last substring will contain the remainder of this + /// byte string. + /// + /// The splitter may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let x: Vec<_> = B("Mary had a little lamb").rsplitn(3, " ").collect(); + /// assert_eq!(x, vec!["lamb", "little", "Mary had a"]); + /// + /// let x: Vec<_> = B("").rsplitn(3, "X").collect(); + /// assert_eq!(x, vec![""]); + /// + /// let x: Vec<_> = B("lionXXtigerXleopard").rsplitn(3, "X").collect(); + /// assert_eq!(x, vec!["leopard", "tiger", "lionX"]); + /// + /// let x: Vec<_> = B("lion::tiger::leopard").rsplitn(2, "::").collect(); + /// assert_eq!(x, vec!["leopard", "lion::tiger"]); + /// + /// let x: Vec<_> = B("abcXdef").rsplitn(1, "X").collect(); + /// assert_eq!(x, vec!["abcXdef"]); + /// + /// let x: Vec<_> = B("abcXdef").rsplitn(0, "X").collect(); + /// assert!(x.is_empty()); + /// ``` + #[inline] + pub fn rsplitn<'a, B: ?Sized + AsRef<[u8]>>( + &'a self, + limit: usize, + splitter: &'a B, + ) -> SplitNReverse<'a> { + SplitNReverse::new(self, BStr::new(splitter.as_ref()), limit) + } + + /// Replace all matches of the given needle with the given replacement, and + /// the result as a new `BString`. + /// + /// This routine is useful as a convenience. If you need to reuse an + /// allocation, use [`replace_into`](#method.replace_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("this is old").replace("old", "new"); + /// assert_eq!(s, "this is new"); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("this is old").replace("nada nada", "limonada"); + /// assert_eq!(s, "this is old"); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo").replace("", "Z"); + /// assert_eq!(s, "ZfZoZoZ"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn replace, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + ) -> BString { + let mut dest = BString::with_capacity(self.len()); + self.replace_into(needle, replacement, &mut dest); + dest + } + + /// Replace up to `limit` matches of the given needle with the given + /// replacement, and the result as a new `BString`. + /// + /// This routine is useful as a convenience. If you need to reuse an + /// allocation, use [`replacen_into`](#method.replacen_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foofoo").replacen("o", "z", 2); + /// assert_eq!(s, "fzzfoo"); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foofoo").replacen("a", "z", 2); + /// assert_eq!(s, "foofoo"); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("foo").replacen("", "Z", 2); + /// assert_eq!(s, "ZfZoo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn replacen, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + limit: usize, + ) -> BString { + let mut dest = BString::with_capacity(self.len()); + self.replacen_into(needle, replacement, limit, &mut dest); + dest + } + + /// Replace all matches of the given needle with the given replacement, + /// and write the result into the provided `BString`. + /// + /// This does **not** clear `dest` before writing to it. + /// + /// This routine is useful for reusing allocation. For a more convenient + /// API, use [`replace`](#method.replace) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("this is old"); + /// + /// let mut dest = BString::new(); + /// s.replace_into("old", "new", &mut dest); + /// assert_eq!(dest, "this is new"); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("this is old"); + /// + /// let mut dest = BString::new(); + /// s.replace_into("nada nada", "limonada", &mut dest); + /// assert_eq!(dest, "this is old"); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("foo"); + /// + /// let mut dest = BString::new(); + /// s.replace_into("", "Z", &mut dest); + /// assert_eq!(dest, "ZfZoZoZ"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn replace_into, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + dest: &mut BString, + ) { + let (needle, replacement) = (needle.as_ref(), replacement.as_ref()); + + let mut last = 0; + for start in self.find_iter(needle) { + dest.push(&self[last..start]); + dest.push(replacement); + last = start + needle.len(); + } + dest.push(&self[last..]); + } + + /// Replace up to `limit` matches of the given needle with the given + /// replacement, and write the result into the provided `BString`. + /// + /// This does **not** clear `dest` before writing to it. + /// + /// This routine is useful for reusing allocation. For a more convenient + /// API, use [`replace`](#method.replacen) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("foofoo"); + /// + /// let mut dest = BString::new(); + /// s.replacen_into("o", "z", 2, &mut dest); + /// assert_eq!(dest, "fzzfoo"); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("foofoo"); + /// + /// let mut dest = BString::new(); + /// s.replacen_into("a", "z", 2, &mut dest); + /// assert_eq!(dest, "foofoo"); + /// ``` + /// + /// When the needle is an empty string: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("foo"); + /// + /// let mut dest = BString::new(); + /// s.replacen_into("", "Z", 2, &mut dest); + /// assert_eq!(dest, "ZfZoo"); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn replacen_into, R: AsRef<[u8]>>( + &self, + needle: N, + replacement: R, + limit: usize, + dest: &mut BString, + ) { + let (needle, replacement) = (needle.as_ref(), replacement.as_ref()); + + let mut last = 0; + for start in self.find_iter(needle).take(limit) { + dest.push(&self[last..start]); + dest.push(replacement); + last = start + needle.len(); + } + dest.push(&self[last..]); + } + + /// Returns an iterator over the bytes in this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("foobar"); + /// let bytes: Vec = bs.bytes().collect(); + /// assert_eq!(bytes, bs); + /// ``` + #[inline] + pub fn bytes(&self) -> Bytes { + Bytes { it: self.as_bytes().iter() } + } + + /// Returns an iterator over the Unicode scalar values in this byte string. + /// If invalid UTF-8 is encountered, then the Unicode replacement codepoint + /// is yielded instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); + /// let chars: Vec = bs.chars().collect(); + /// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars); + /// ``` + /// + /// Codepoints can also be iterated over in reverse: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); + /// let chars: Vec = bs.chars().rev().collect(); + /// assert_eq!(vec!['a', '\u{FFFD}', '𝞃', '\u{FFFD}', '☃'], chars); + /// ``` + #[inline] + pub fn chars(&self) -> Chars { + Chars::new(self) + } + + /// Returns an iterator over the Unicode scalar values in this byte string + /// along with their starting and ending byte index positions. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// Note that this is slightly different from the `CharIndices` iterator + /// provided by the standard library. Aside from working on possibly + /// invalid UTF-8, this iterator provides both the corresponding starting + /// and ending byte indices of each codepoint yielded. The ending position + /// is necessary to slice the original byte string when invalid UTF-8 bytes + /// are converted into a Unicode replacement codepoint, since a single + /// replacement codepoint can substitute anywhere from 1 to 3 invalid bytes + /// (inclusive). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); + /// let chars: Vec<(usize, usize, char)> = bs.char_indices().collect(); + /// assert_eq!(chars, vec![ + /// (0, 3, '☃'), + /// (3, 4, '\u{FFFD}'), + /// (4, 8, '𝞃'), + /// (8, 10, '\u{FFFD}'), + /// (10, 11, 'a'), + /// ]); + /// ``` + /// + /// Codepoints can also be iterated over in reverse: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"); + /// let chars: Vec<(usize, usize, char)> = bs + /// .char_indices() + /// .rev() + /// .collect(); + /// assert_eq!(chars, vec![ + /// (10, 11, 'a'), + /// (8, 10, '\u{FFFD}'), + /// (4, 8, '𝞃'), + /// (3, 4, '\u{FFFD}'), + /// (0, 3, '☃'), + /// ]); + /// ``` + #[inline] + pub fn char_indices(&self) -> CharIndices { + CharIndices::new(self) + } + + /// Returns an iterator over the grapheme clusters in this byte string. + /// If invalid UTF-8 is encountered, then the Unicode replacement codepoint + /// is yielded instead. + /// + /// # Examples + /// + /// This example shows how multiple codepoints can combine to form a + /// single grapheme cluster: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}"); + /// let graphemes: Vec<&str> = bs.graphemes().collect(); + /// assert_eq!(vec!["à̖", "🇺🇸"], graphemes); + /// ``` + /// + /// This shows that graphemes can be iterated over in reverse: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}"); + /// let graphemes: Vec<&str> = bs.graphemes().rev().collect(); + /// assert_eq!(vec!["🇺🇸", "à̖"], graphemes); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn graphemes(&self) -> Graphemes { + Graphemes::new(self) + } + + /// Returns an iterator over the grapheme clusters in this byte string + /// along with their starting and ending byte index positions. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// grapheme cluster: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("a\u{0300}\u{0316}\u{1F1FA}\u{1F1F8}"); + /// let graphemes: Vec<(usize, usize, &str)> = + /// bs.grapheme_indices().collect(); + /// assert_eq!(vec![(0, 5, "à̖"), (5, 13, "🇺🇸")], graphemes); + /// ``` + /// + /// This example shows what happens when invalid UTF-8 is enountered. Note + /// that the offsets are valid indices into the original string, and do + /// not necessarily correspond to the length of the `&str` returned! + /// + /// ``` + /// use bstr::BString; + /// + /// let mut bytes = BString::new(); + /// bytes.push("a\u{0300}\u{0316}"); + /// bytes.push_byte(b'\xFF'); + /// bytes.push("\u{1F1FA}\u{1F1F8}"); + /// + /// let graphemes: Vec<(usize, usize, &str)> = + /// bytes.grapheme_indices().collect(); + /// assert_eq!( + /// graphemes, + /// vec![(0, 5, "à̖"), (5, 6, "\u{FFFD}"), (6, 14, "🇺🇸")] + /// ); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn grapheme_indices(&self) -> GraphemeIndices { + GraphemeIndices::new(self) + } + + /// Returns an iterator over the words in this byte string. If invalid + /// UTF-8 is encountered, then the Unicode replacement codepoint is yielded + /// instead. + /// + /// This is similar to + /// [`words_with_breaks`](struct.BStr.html#method.words_with_breaks), + /// except it only returns elements that contain a "word" character. A word + /// character is defined by UTS #18 (Annex C) to be the combination of the + /// `Alphabetic` and `Join_Control` properties, along with the + /// `Decimal_Number`, `Mark` and `Connector_Punctuation` general + /// categories. + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(r#"The quick ("brown") fox can't jump 32.3 feet, right?"#); + /// let words: Vec<&str> = bs.words().collect(); + /// assert_eq!(words, vec![ + /// "The", "quick", "brown", "fox", "can't", + /// "jump", "32.3", "feet", "right", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn words(&self) -> Words { + Words::new(self) + } + + /// Returns an iterator over the words in this byte string along with + /// their starting and ending byte index positions. + /// + /// This is similar to + /// [`words_with_break_indices`](struct.BStr.html#method.words_with_break_indices), + /// except it only returns elements that contain a "word" character. A word + /// character is defined by UTS #18 (Annex C) to be the combination of the + /// `Alphabetic` and `Join_Control` properties, along with the + /// `Decimal_Number`, `Mark` and `Connector_Punctuation` general + /// categories. + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// word: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("can't jump 32.3 feet"); + /// let words: Vec<(usize, usize, &str)> = bs.word_indices().collect(); + /// assert_eq!(words, vec![ + /// (0, 5, "can't"), + /// (6, 10, "jump"), + /// (11, 15, "32.3"), + /// (16, 20, "feet"), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn word_indices(&self) -> WordIndices { + WordIndices::new(self) + } + + /// Returns an iterator over the words in this byte string, along with + /// all breaks between the words. Concatenating all elements yielded by + /// the iterator results in the original string (modulo Unicode replacement + /// codepoint substitutions if invalid UTF-8 is encountered). + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B(r#"The quick ("brown") fox can't jump 32.3 feet, right?"#); + /// let words: Vec<&str> = bs.words_with_breaks().collect(); + /// assert_eq!(words, vec![ + /// "The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", + /// " ", "fox", " ", "can't", " ", "jump", " ", "32.3", " ", "feet", + /// ",", " ", "right", "?", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn words_with_breaks(&self) -> WordsWithBreaks { + WordsWithBreaks::new(self) + } + + /// Returns an iterator over the words and their byte offsets in this + /// byte string, along with all breaks between the words. Concatenating + /// all elements yielded by the iterator results in the original string + /// (modulo Unicode replacement codepoint substitutions if invalid UTF-8 is + /// encountered). + /// + /// Since words are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// This example shows how to get the byte offsets of each individual + /// word: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("can't jump 32.3 feet"); + /// let words: Vec<(usize, usize, &str)> = + /// bs.words_with_break_indices().collect(); + /// assert_eq!(words, vec![ + /// (0, 5, "can't"), + /// (5, 6, " "), + /// (6, 10, "jump"), + /// (10, 11, " "), + /// (11, 15, "32.3"), + /// (15, 16, " "), + /// (16, 20, "feet"), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn words_with_break_indices(&self) -> WordsWithBreakIndices { + WordsWithBreakIndices::new(self) + } + + /// Returns an iterator over the sentences in this byte string. + /// + /// Typically, a sentence will include its trailing punctuation and + /// whitespace. Concatenating all elements yielded by the iterator + /// results in the original string (modulo Unicode replacement codepoint + /// substitutions if invalid UTF-8 is encountered). + /// + /// Since sentences are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("I want this. Not that. Right now."); + /// let sentences: Vec<&str> = bs.sentences().collect(); + /// assert_eq!(sentences, vec![ + /// "I want this. ", + /// "Not that. ", + /// "Right now.", + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn sentences(&self) -> Sentences { + Sentences::new(self) + } + + /// Returns an iterator over the sentences in this byte string along with + /// their starting and ending byte index positions. + /// + /// Typically, a sentence will include its trailing punctuation and + /// whitespace. Concatenating all elements yielded by the iterator + /// results in the original string (modulo Unicode replacement codepoint + /// substitutions if invalid UTF-8 is encountered). + /// + /// Since sentences are made up of one or more codepoints, this iterator + /// yields `&str` elements. When invalid UTF-8 is encountered, replacement + /// codepoints are [substituted](index.html#handling-of-invalid-utf-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let bs = B("I want this. Not that. Right now."); + /// let sentences: Vec<(usize, usize, &str)> = + /// bs.sentence_indices().collect(); + /// assert_eq!(sentences, vec![ + /// (0, 13, "I want this. "), + /// (13, 23, "Not that. "), + /// (23, 33, "Right now."), + /// ]); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn sentence_indices(&self) -> SentenceIndices { + SentenceIndices::new(self) + } + + /// An iterator over all lines in a byte string, without their + /// terminators. + /// + /// For this iterator, the only line terminators recognized are `\r\n` and + /// `\n`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let s = B("\ + /// foo + /// + /// bar\r + /// baz + /// + /// + /// quux"); + /// let lines: Vec<&BStr> = s.lines().collect(); + /// assert_eq!(lines, vec![ + /// "foo", "", "bar", "baz", "", "", "quux", + /// ]); + /// ``` + #[inline] + pub fn lines(&self) -> Lines { + Lines::new(self) + } + + /// An iterator over all lines in a byte string, including their + /// terminators. + /// + /// For this iterator, the only line terminator recognized is `\n`. (Since + /// line terminators are included, this also handles `\r\n` line endings.) + /// + /// Line terminators are only included if they are present in the original + /// byte string. For example, the last line in a byte string may not end + /// with a line terminator. + /// + /// Concatenating all elements yielded by this iterator is guaranteed to + /// yield the original byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BStr}; + /// + /// let s = B("\ + /// foo + /// + /// bar\r + /// baz + /// + /// + /// quux"); + /// let lines: Vec<&BStr> = s.lines_with_terminator().collect(); + /// assert_eq!(lines, vec![ + /// "foo\n", "\n", "bar\r\n", "baz\n", "\n", "\n", "quux", + /// ]); + /// ``` + #[inline] + pub fn lines_with_terminator(&self) -> LinesWithTerminator { + LinesWithTerminator::new(self) + } + + /// Return a byte string slice with leading and trailing whitespace + /// removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim(), "foo\tbar"); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn trim(&self) -> &BStr { + self.trim_start().trim_end() + } + + /// Return a byte string slice with leading whitespace removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim_start(), "foo\tbar\t\u{2003}\n"); + /// ``` + #[inline] + pub fn trim_start(&self) -> &BStr { + self.trim_start_imp() + } + + #[cfg(feature = "unicode")] + #[inline] + fn trim_start_imp(&self) -> &BStr { + let start = whitespace_len_fwd(self.as_bytes()); + &self[start..] + } + + #[cfg(not(feature = "unicode"))] + #[inline] + fn trim_start_imp(&self) -> &BStr { + self.trim_start_with(|c| c.is_whitespace()) + } + + /// Return a byte string slice with trailing whitespace removed. + /// + /// Whitespace is defined according to the terms of the `White_Space` + /// Unicode property. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B(" foo\tbar\t\u{2003}\n"); + /// assert_eq!(s.trim_end(), " foo\tbar"); + /// ``` + #[inline] + pub fn trim_end(&self) -> &BStr { + self.trim_end_imp() + } + + #[cfg(feature = "unicode")] + #[inline] + fn trim_end_imp(&self) -> &BStr { + let end = whitespace_len_rev(self.as_bytes()); + &self[..end] + } + + #[cfg(not(feature = "unicode"))] + #[inline] + fn trim_end_imp(&self) -> &BStr { + self.trim_end_with(|c| c.is_whitespace()) + } + + /// Return a byte string slice with leading and trailing characters + /// satisfying the given predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("123foo5bar789"); + /// assert_eq!(s.trim_with(|c| c.is_numeric()), "foo5bar"); + /// ``` + #[inline] + pub fn trim_with bool>(&self, mut trim: F) -> &BStr { + self.trim_start_with(&mut trim).trim_end_with(&mut trim) + } + + /// Return a byte string slice with leading characters satisfying the given + /// predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("123foo5bar789"); + /// assert_eq!(s.trim_start_with(|c| c.is_numeric()), "foo5bar789"); + /// ``` + #[inline] + pub fn trim_start_with bool>( + &self, + mut trim: F, + ) -> &BStr { + for (s, _, ch) in self.char_indices() { + if !trim(ch) { + return &self[s..]; + } + } + B("") + } + + /// Return a byte string slice with trailing characters satisfying the + /// given predicate removed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("123foo5bar"); + /// assert_eq!(s.trim_end_with(|c| c.is_numeric()), "123foo5bar"); + /// ``` + #[inline] + pub fn trim_end_with bool>( + &self, + mut trim: F, + ) -> &BStr { + for (_, e, ch) in self.char_indices().rev() { + if !trim(ch) { + return &self[..e]; + } + } + B("") + } + + /// Returns a new `BString` containing the lowercase equivalent of this + /// byte string. + /// + /// In this case, lowercase is defined according to the `Lowercase` Unicode + /// property. + /// + /// If invalid UTF-8 is seen, or if a character has no lowercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`to_lowercase_into`](#method.to_lowercase_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("HELLO Β"); + /// assert_eq!("hello β", s.to_lowercase()); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("农历新年"); + /// assert_eq!("农历新年", s.to_lowercase()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), s.to_lowercase()); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + pub fn to_lowercase(&self) -> BString { + let mut buf = BString::new(); + self.to_lowercase_into(&mut buf); + buf + } + + /// Writes the lowercase equivalent of this byte string into the given + /// buffer. The buffer is not cleared before written to. + /// + /// In this case, lowercase is defined according to the `Lowercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no lowercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you don't need to amortize allocation and instead prefer + /// convenience, then use [`to_lowercase`](#method.to_lowercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("HELLO Β"); + /// + /// let mut buf = BString::new(); + /// s.to_lowercase_into(&mut buf); + /// assert_eq!("hello β", buf); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("农历新年"); + /// + /// let mut buf = BString::new(); + /// s.to_lowercase_into(&mut buf); + /// assert_eq!("农历新年", buf); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// + /// let mut buf = BString::new(); + /// s.to_lowercase_into(&mut buf); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), buf); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + pub fn to_lowercase_into(&self, buf: &mut BString) { + // TODO: This is the best we can do given what std exposes I think. + // If we roll our own case handling, then we might be able to do this + // a bit faster. We shouldn't roll our own case handling unless we + // need to, e.g., for doing caseless matching or case folding. + + // TODO(BUG): This doesn't handle any special casing rules. + + buf.reserve(self.len()); + for (s, e, ch) in self.char_indices() { + if ch == '\u{FFFD}' { + buf.push(&self[s..e]); + } else { + for upper in ch.to_lowercase() { + buf.push_char(upper); + } + } + } + } + + /// Returns a new `BString` containing the ASCII lowercase equivalent of + /// this byte string. + /// + /// In this case, lowercase is only defined in ASCII letters. Namely, the + /// letters `A-Z` are converted to `a-z`. All other bytes remain unchanged. + /// In particular, the length of the byte string returned is always + /// equivalent to the length of this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`make_ascii_lowercase`](#method.make_ascii_lowercase) to perform + /// the conversion in place. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("HELLO Β"); + /// assert_eq!("hello Β", s.to_ascii_lowercase()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"FOO\xFFBAR\xE2\x98BAZ"); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), s.to_ascii_lowercase()); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_ascii_lowercase(&self) -> BString { + BString::from(self.as_bytes().to_ascii_lowercase()) + } + + /// Convert this byte string to its lowercase ASCII equivalent in place. + /// + /// In this case, lowercase is only defined in ASCII letters. Namely, the + /// letters `A-Z` are converted to `a-z`. All other bytes remain unchanged. + /// + /// If you don't need to do the conversion in + /// place and instead prefer convenience, then use + /// [`to_ascii_lowercase`](#method.to_ascii_lowercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("HELLO Β"); + /// s.make_ascii_lowercase(); + /// assert_eq!("hello Β", s); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let mut s = BString::from_slice(b"FOO\xFFBAR\xE2\x98BAZ"); + /// s.make_ascii_lowercase(); + /// assert_eq!(B(b"foo\xFFbar\xE2\x98baz"), s); + /// ``` + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.as_bytes_mut().make_ascii_lowercase(); + } + + /// Returns a new `BString` containing the uppercase equivalent of this + /// byte string. + /// + /// In this case, uppercase is defined according to the `Uppercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no uppercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`to_uppercase_into`](#method.to_uppercase_into) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("hello β"); + /// assert_eq!("HELLO Β", s.to_uppercase()); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("农历新年"); + /// assert_eq!("农历新年", s.to_uppercase()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// assert_eq!(B(b"FOO\xFFBAR\xE2\x98BAZ"), s.to_uppercase()); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + pub fn to_uppercase(&self) -> BString { + let mut buf = BString::new(); + self.to_uppercase_into(&mut buf); + buf + } + + /// Writes the uppercase equivalent of this byte string into the given + /// buffer. The buffer is not cleared before written to. + /// + /// In this case, uppercase is defined according to the `Uppercase` + /// Unicode property. + /// + /// If invalid UTF-8 is seen, or if a character has no uppercase variant, + /// then it is written to the given buffer unchanged. + /// + /// Note that some characters in this byte string may expand into multiple + /// characters when changing the case, so the number of bytes written to + /// the given byte string may not be equivalent to the number of bytes in + /// this byte string. + /// + /// If you don't need to amortize allocation and instead prefer + /// convenience, then use [`to_uppercase`](#method.to_uppercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("hello β"); + /// + /// let mut buf = BString::new(); + /// s.to_uppercase_into(&mut buf); + /// assert_eq!("HELLO Β", buf); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("农历新年"); + /// + /// let mut buf = BString::new(); + /// s.to_uppercase_into(&mut buf); + /// assert_eq!("农历新年", buf); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// + /// let mut buf = BString::new(); + /// s.to_uppercase_into(&mut buf); + /// assert_eq!(B(b"FOO\xFFBAR\xE2\x98BAZ"), buf); + /// ``` + #[cfg(all(feature = "std", feature = "unicode"))] + #[inline] + pub fn to_uppercase_into(&self, buf: &mut BString) { + // TODO: This is the best we can do given what std exposes I think. + // If we roll our own case handling, then we might be able to do this + // a bit faster. We shouldn't roll our own case handling unless we + // need to, e.g., for doing caseless matching or case folding. + buf.reserve(self.len()); + for (s, e, ch) in self.char_indices() { + if ch == '\u{FFFD}' { + buf.push(&self[s..e]); + } else if ch.is_ascii() { + buf.push_char(ch.to_ascii_uppercase()); + } else { + for upper in ch.to_uppercase() { + buf.push_char(upper); + } + } + } + } + + /// Returns a new `BString` containing the ASCII uppercase equivalent of + /// this byte string. + /// + /// In this case, uppercase is only defined in ASCII letters. Namely, the + /// letters `a-z` are converted to `A-Z`. All other bytes remain unchanged. + /// In particular, the length of the byte string returned is always + /// equivalent to the length of this byte string. + /// + /// If you'd like to reuse an allocation for performance reasons, then use + /// [`make_ascii_uppercase`](#method.make_ascii_uppercase) to perform + /// the conversion in place. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B("hello β"); + /// assert_eq!("HELLO β", s.to_ascii_uppercase()); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let s = B(b"foo\xFFbar\xE2\x98baz"); + /// assert_eq!(B(b"FOO\xFFBAR\xE2\x98BAZ"), s.to_ascii_uppercase()); + /// ``` + #[cfg(feature = "std")] + #[inline] + pub fn to_ascii_uppercase(&self) -> BString { + BString::from(self.as_bytes().to_ascii_uppercase()) + } + + /// Convert this byte string to its uppercase ASCII equivalent in place. + /// + /// In this case, uppercase is only defined in ASCII letters. Namely, the + /// letters `a-z` are converted to `A-Z`. All other bytes remain unchanged. + /// + /// If you don't need to do the conversion in + /// place and instead prefer convenience, then use + /// [`to_ascii_uppercase`](#method.to_ascii_uppercase) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("hello β"); + /// s.make_ascii_uppercase(); + /// assert_eq!("HELLO β", s); + /// ``` + /// + /// Invalid UTF-8 remains as is: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let mut s = BString::from_slice(b"foo\xFFbar\xE2\x98baz"); + /// s.make_ascii_uppercase(); + /// assert_eq!(B(b"FOO\xFFBAR\xE2\x98BAZ"), s); + /// ``` + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.as_bytes_mut().make_ascii_uppercase(); + } + + /// Reverse the bytes in this string, in place. + /// + /// Note that this is not necessarily a well formed operation. For example, + /// if this byte string contains valid UTF-8 that isn't ASCII, then + /// reversing the string will likely result in invalid UTF-8 and otherwise + /// non-sensical content. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("hello"); + /// s.reverse_bytes(); + /// assert_eq!(s, "olleh"); + /// ``` + #[inline] + pub fn reverse_bytes(&mut self) { + self.as_bytes_mut().reverse(); + } + + /// Reverse the codepoints in this string, in place. + /// + /// If this byte string is valid UTF-8, then its reversal by codepoint + /// is also guaranteed to be valid UTF-8. + /// + /// This operation is equivalent to the following, but without allocating: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo☃bar"); + /// + /// let mut chars: Vec = s.chars().collect(); + /// chars.reverse(); + /// + /// let reversed: String = chars.into_iter().collect(); + /// assert_eq!(reversed, "rab☃oof"); + /// ``` + /// + /// Note that this is not necessarily a well formed operation. For example, + /// if this byte string contains grapheme clusters with more than one + /// codepoint, then those grapheme clusters will not necessarily be + /// preserved. If you'd like to preserve grapheme clusters, then use + /// [`reverse_graphemes`](#method.reverse_graphemes) instead. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo☃bar"); + /// s.reverse_chars(); + /// assert_eq!(s, "rab☃oof"); + /// ``` + /// + /// This example shows that not all reversals lead to a well formed string. + /// For example, in this case, combining marks are used to put accents over + /// some letters, and those accent marks must appear after the codepoints + /// they modify. + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let mut s = BString::from("résumé"); + /// s.reverse_chars(); + /// assert_eq!(s, B(b"\xCC\x81emus\xCC\x81er")); + /// ``` + /// + /// A word of warning: the above example relies on the fact that + /// `résumé` is in decomposed normal form, which means there are separate + /// codepoints for the accents above `e`. If it is instead in composed + /// normal form, then the example works: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let mut s = BString::from("résumé"); + /// s.reverse_chars(); + /// assert_eq!(s, "émusér"); + /// ``` + /// + /// The point here is to be cautious and not assume that just because + /// `reverse_chars` works in one case, that it therefore works in all + /// cases. + #[inline] + pub fn reverse_chars(&mut self) { + let mut i = 0; + loop { + let (_, size) = utf8::decode(self[i..].as_bytes()); + if size == 0 { + break; + } + if size > 1 { + self[i..i + size].reverse_bytes(); + } + i += size; + } + self.reverse_bytes(); + } + + /// Reverse the graphemes in this string, in place. + /// + /// If this byte string is valid UTF-8, then its reversal by grapheme + /// is also guaranteed to be valid UTF-8. + /// + /// This operation is equivalent to the following, but without allocating: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo☃bar"); + /// + /// let mut graphemes: Vec<&str> = s.graphemes().collect(); + /// graphemes.reverse(); + /// + /// let reversed = graphemes.concat(); + /// assert_eq!(reversed, "rab☃oof"); + /// ``` + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo☃bar"); + /// s.reverse_graphemes(); + /// assert_eq!(s, "rab☃oof"); + /// ``` + /// + /// This example shows how this correctly handles grapheme clusters, + /// unlike `reverse_chars`. + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("résumé"); + /// s.reverse_graphemes(); + /// assert_eq!(s, "émusér"); + /// ``` + #[cfg(feature = "unicode")] + #[inline] + pub fn reverse_graphemes(&mut self) { + use unicode::decode_grapheme; + + let mut i = 0; + loop { + let (_, size) = decode_grapheme(&self[i..]); + if size == 0 { + break; + } + if size > 1 { + self[i..i + size].reverse_bytes(); + } + i += size; + } + self.reverse_bytes(); + } + + /// Returns true if and only if every byte in this byte string is ASCII. + /// + /// ASCII is an encoding that defines 128 codepoints. A byte corresponds to + /// an ASCII codepoint if and only if it is in the inclusive range + /// `[0, 127]`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert!(B("abc").is_ascii()); + /// assert!(!B("☃βツ").is_ascii()); + /// assert!(!B(b"\xFF").is_ascii()); + /// ``` + #[inline] + pub fn is_ascii(&self) -> bool { + ascii::first_non_ascii_byte(&self.bytes) == self.len() + } + + /// Returns true if and only if the entire byte string is valid UTF-8. + /// + /// If you need location information about where a byte string's first + /// invalid UTF-8 byte is, then use the [`to_str`](#method.to_str) method. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert!(B("abc").is_utf8()); + /// assert!(B("☃βツ").is_utf8()); + /// // invalid bytes + /// assert!(!B(b"abc\xFF").is_utf8()); + /// // surrogate encoding + /// assert!(!B(b"\xED\xA0\x80").is_utf8()); + /// // incomplete sequence + /// assert!(!B(b"\xF0\x9D\x9Ca").is_utf8()); + /// // overlong sequence + /// assert!(!B(b"\xF0\x82\x82\xAC").is_utf8()); + /// ``` + #[inline] + pub fn is_utf8(&self) -> bool { + utf8::validate(self.as_bytes()).is_ok() + } + + /// Divides this byte string into two at an index. + /// + /// The first byte string will contain all bytes at indices `[0, at)`, and + /// the second byte string will contain all bytes at indices `[at, len)`. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(B("foobar").split_at(3), (B("foo"), B("bar"))); + /// assert_eq!(B("foobar").split_at(0), (B(""), B("foobar"))); + /// assert_eq!(B("foobar").split_at(6), (B("foobar"), B(""))); + /// ``` + #[inline] + pub fn split_at(&self, at: usize) -> (&BStr, &BStr) { + let (left, right) = self.as_bytes().split_at(at); + (BStr::new(left), BStr::new(right)) + } + + /// Divides this mutable byte string into two at an index. + /// + /// The first byte string will contain all bytes at indices `[0, at)`, and + /// the second byte string will contain all bytes at indices `[at, len)`. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let mut b = BString::from("foobar"); + /// { + /// let (left, right) = b.split_at_mut(3); + /// left[2] = b'z'; + /// right[2] = b'z'; + /// } + /// assert_eq!(b, B("fozbaz")); + /// ``` + #[inline] + pub fn split_at_mut(&mut self, at: usize) -> (&mut BStr, &mut BStr) { + let (left, right) = self.as_bytes_mut().split_at_mut(at); + (BStr::new_mut(left), BStr::new_mut(right)) + } + + /// Retrieve a reference to a byte or a subslice, depending on the type of + /// the index given. + /// + /// If given a position, this returns a reference to the byte at that + /// position, if it exists. + /// + /// If given a range, this returns the slice of bytes corresponding to that + /// range in this byte string. + /// + /// In the case of invalid indices, this returns `None`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("baz"); + /// assert_eq!(s.get(1), Some(&b'a')); + /// assert_eq!(s.get(0..2), Some(B("ba"))); + /// assert_eq!(s.get(2..), Some(B("z"))); + /// assert_eq!(s.get(1..=2), Some(B("az"))); + /// ``` + #[inline] + pub fn get(&self, at: I) -> Option<&I::Output> { + at.get(self) + } + + /// Retrieve a mutable reference to a byte or a subslice, depending on the + /// type of the index given. + /// + /// If given a position, this returns a reference to the byte at that + /// position, if it exists. + /// + /// If given a range, this returns the slice of bytes corresponding to that + /// range in this byte string. + /// + /// In the case of invalid indices, this returns `None`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("baz"); + /// if let Some(mut slice) = s.get_mut(1..) { + /// slice[0] = b'o'; + /// slice[1] = b'p'; + /// } + /// assert_eq!(s, "bop"); + /// ``` + #[inline] + pub fn get_mut(&mut self, at: I) -> Option<&mut I::Output> { + at.get_mut(self) + } + + /// Retrieve a reference to a byte or a subslice, depending on the type of + /// the index given, while explicitly eliding bounds checks. + /// + /// If given a position, this returns a reference to the byte at that + /// position, if it exists. + /// + /// If given a range, this returns the slice of bytes corresponding to that + /// range in this byte string. + /// + /// In the case of invalid indices, this returns `None`. + /// + /// # Safety + /// + /// Callers must ensure that the supplied bounds are correct. If they + /// are out of bounds, then this results in undefined behavior. For a + /// safe alternative, use [`get`](#method.get). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("baz"); + /// unsafe { + /// assert_eq!(s.get_unchecked(1), &b'a'); + /// assert_eq!(s.get_unchecked(0..2), "ba"); + /// assert_eq!(s.get_unchecked(2..), "z"); + /// assert_eq!(s.get_unchecked(1..=2), "az"); + /// } + /// ``` + pub unsafe fn get_unchecked(&self, at: I) -> &I::Output { + at.get_unchecked(self) + } + + /// Retrieve a mutable reference to a byte or a subslice, depending on the + /// type of the index given, while explicitly eliding bounds checks. + /// + /// If given a position, this returns a reference to the byte at that + /// position, if it exists. + /// + /// If given a range, this returns the slice of bytes corresponding to that + /// range in this byte string. + /// + /// In the case of invalid indices, this returns `None`. + /// + /// # Safety + /// + /// Callers must ensure that the supplied bounds are correct. If they + /// are out of bounds, then this results in undefined behavior. For a + /// safe alternative, use [`get_mut`](#method.get_mut). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("baz"); + /// { + /// let mut slice = unsafe { s.get_unchecked_mut(1..) }; + /// slice[0] = b'o'; + /// slice[1] = b'p'; + /// } + /// assert_eq!(s, "bop"); + /// ``` + pub unsafe fn get_unchecked_mut( + &mut self, + at: I, + ) -> &mut I::Output { + at.get_unchecked_mut(self) + } + + /// Returns the last byte in this byte string, if it's non-empty. If this + /// byte string is empty, this returns `None`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// assert_eq!(Some(b'z'), B("baz").last()); + /// assert_eq!(None, B("").last()); + /// ``` + #[inline] + pub fn last(&self) -> Option { + self.get(self.len().saturating_sub(1)).map(|&b| b) + } + + /// Copies elements from one part of the slice to another part of itself, + /// where the parts may be overlapping. + /// + /// `src` is the range within this byte string to copy from, while `dest` + /// is the starting index of the range within this byte string to copy to. + /// The length indicated by `src` must be less than or equal to the number + /// of bytes from `dest` to the end of the byte string. + /// + /// # Panics + /// + /// Panics if either range is out of bounds, or if `src` is too big to fit + /// into `dest`, or if the end of `src` is before the start. + /// + /// # Examples + /// + /// Copying four bytes within a byte string: + /// + /// ``` + /// use bstr::BStr; + /// + /// let mut buf = *b"Hello, World!"; + /// let s = BStr::new_mut(&mut buf); + /// s.copy_within(1..5, 8); + /// assert_eq!(s, "Hello, Wello!"); + /// ``` + #[inline] + pub fn copy_within( + &mut self, + src: R, + dest: usize, + ) where R: ops::RangeBounds + { + let src_start = match src.start_bound() { + ops::Bound::Included(&n) => n, + ops::Bound::Excluded(&n) => { + n.checked_add(1).expect("attempted to index slice beyond max") + } + ops::Bound::Unbounded => 0, + }; + let src_end = match src.end_bound() { + ops::Bound::Included(&n) => { + n.checked_add(1).expect("attempted to index slice beyond max") + } + ops::Bound::Excluded(&n) => n, + ops::Bound::Unbounded => self.len(), + }; + assert!(src_start <= src_end, "src end is before src start"); + assert!(src_end <= self.len(), "src is out of bounds"); + let count = src_end - src_start; + assert!(dest <= self.len() - count, "dest is out of bounds"); + + // SAFETY: This is safe because we use ptr::copy to handle overlapping + // copies, and is also safe because we've checked all the bounds above. + // Finally, we are only dealing with u8 data, which is Copy, which + // means we can copy without worrying about ownership/destructors. + unsafe { + ptr::copy( + self.get_unchecked(src_start), + self.get_unchecked_mut(dest), + count, + ); + } + } + + /// Returns a raw pointer to this byte string's underlying bytes. + /// + /// # Safety + /// + /// The caller must ensure that the byte string outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container (like a `BString`) referenced by this byte + /// string may cause its buffer to be reallocated, which would also make + /// any pointers to it invalid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B("hello"); + /// let p = s.as_ptr(); + /// + /// unsafe { + /// assert_eq!(*p.add(2), b'l'); + /// } + /// ``` + #[inline] + pub fn as_ptr(&self) -> *const u8 { + self.as_bytes().as_ptr() + } + + /// Returns a raw mutable pointer to this byte string's underlying bytes. + /// + /// # Safety + /// + /// The caller must ensure that the byte string outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container (like a `BString`) referenced by this byte + /// string may cause its buffer to be reallocated, which would also make + /// any pointers to it invalid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BStr; + /// + /// let mut buf = &mut [b'h', b'e', b'l', b'l', b'o']; + /// let mut s = BStr::new_mut(buf); + /// let p = s.as_mut_ptr(); + /// + /// unsafe { + /// *p.add(2) = b'Z'; + /// } + /// assert_eq!("heZlo", s); + /// ``` + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.as_bytes_mut().as_mut_ptr() + } +} + +/// A single substring searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, using +/// [`BStr::find`](struct.BStr.html#method.find) +/// or +/// [`BStr::find_iter`](struct.BStr.html#method.find_iter) +/// is good enough, but `Finder` is useful when you can meaningfully observe +/// searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `Finder` that is not connected to the +/// lifetime of its needle. +#[derive(Clone, Debug)] +pub struct Finder<'a> { + searcher: TwoWay<'a>, +} + +impl<'a> Finder<'a> { + /// Create a new finder for the given needle. + #[inline] + pub fn new>(needle: &'a B) -> Finder<'a> { + Finder { searcher: TwoWay::forward(BStr::new(needle)) } + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "std")] + #[inline] + pub fn into_owned(self) -> Finder<'static> { + Finder { searcher: self.searcher.into_owned() } + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of the finder, and may be shorter than the `'a` lifetime. Namely, a + /// finder's needle can be either borrowed or owned, so the lifetime of the + /// needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &BStr { + self.searcher.needle() + } + + /// Returns the index of the first occurrence of this needle in the given + /// haystack. + /// + /// The haystack may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::Finder; + /// + /// let haystack = "foo bar baz"; + /// assert_eq!(Some(0), Finder::new("foo").find(haystack)); + /// assert_eq!(Some(4), Finder::new("bar").find(haystack)); + /// assert_eq!(None, Finder::new("quux").find(haystack)); + /// ``` + #[inline] + pub fn find>(&self, haystack: B) -> Option { + self.searcher.find(BStr::new(haystack.as_ref())) + } +} + +/// A single substring reverse searcher fixed to a particular needle. +/// +/// The purpose of this type is to permit callers to construct a substring +/// searcher that can be used to search haystacks without the overhead of +/// constructing the searcher in the first place. This is a somewhat niche +/// concern when it's necessary to re-use the same needle to search multiple +/// different haystacks with as little overhead as possible. In general, using +/// [`BStr::rfind`](struct.BStr.html#method.rfind) +/// or +/// [`BStr::rfind_iter`](struct.BStr.html#method.rfind_iter) +/// is good enough, but `FinderReverse` is useful when you can meaningfully +/// observe searcher construction time in a profile. +/// +/// When the `std` feature is enabled, then this type has an `into_owned` +/// version which permits building a `FinderReverse` that is not connected to +/// the lifetime of its needle. +#[derive(Clone, Debug)] +pub struct FinderReverse<'a> { + searcher: TwoWay<'a>, +} + +impl<'a> FinderReverse<'a> { + /// Create a new reverse finder for the given needle. + #[inline] + pub fn new>(needle: &'a B) -> FinderReverse<'a> { + FinderReverse { searcher: TwoWay::reverse(BStr::new(needle)) } + } + + /// Convert this finder into its owned variant, such that it no longer + /// borrows the needle. + /// + /// If this is already an owned finder, then this is a no-op. Otherwise, + /// this copies the needle. + /// + /// This is only available when the `std` feature is enabled. + #[cfg(feature = "std")] + #[inline] + pub fn into_owned(self) -> FinderReverse<'static> { + FinderReverse { searcher: self.searcher.into_owned() } + } + + /// Returns the needle that this finder searches for. + /// + /// Note that the lifetime of the needle returned is tied to the lifetime + /// of this finder, and may be shorter than the `'a` lifetime. Namely, + /// a finder's needle can be either borrowed or owned, so the lifetime of + /// the needle returned must necessarily be the shorter of the two. + #[inline] + pub fn needle(&self) -> &BStr { + self.searcher.needle() + } + + /// Returns the index of the last occurrence of this needle in the given + /// haystack. + /// + /// The haystack may be any type that can be cheaply converted into a + /// `&[u8]`. This includes, but is not limited to, `&str`, `&BStr`, and of + /// course, `&[u8]` itself. + /// + /// # Complexity + /// + /// This routine is guaranteed to have worst case linear time complexity + /// with respect to both the needle and the haystack. That is, this runs + /// in `O(needle.len() + haystack.len())` time. + /// + /// This routine is also guaranteed to have worst case constant space + /// complexity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::FinderReverse; + /// + /// let haystack = "foo bar baz"; + /// assert_eq!(Some(0), FinderReverse::new("foo").rfind(haystack)); + /// assert_eq!(Some(4), FinderReverse::new("bar").rfind(haystack)); + /// assert_eq!(None, FinderReverse::new("quux").rfind(haystack)); + /// ``` + #[inline] + pub fn rfind>(&self, haystack: B) -> Option { + self.searcher.rfind(BStr::new(haystack.as_ref())) + } +} + +/// An iterator over non-overlapping substring matches. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'a` is the shorter of two lifetimes: the byte string being searched or the +/// byte string being looked for. +#[derive(Debug)] +pub struct Find<'a> { + haystack: &'a BStr, + prestate: PrefilterState, + searcher: TwoWay<'a>, + pos: usize, +} + +impl<'a> Find<'a> { + fn new(haystack: &'a BStr, needle: &'a BStr) -> Find<'a> { + let searcher = TwoWay::forward(needle); + let prestate = searcher.prefilter_state(); + Find { haystack, prestate, searcher, pos: 0 } + } +} + +impl<'a> Iterator for Find<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + if self.pos > self.haystack.len() { + return None; + } + let result = self.searcher.find_with( + &mut self.prestate, + &self.haystack[self.pos..], + ); + match result { + None => None, + Some(i) => { + let pos = self.pos + i; + self.pos = pos + cmp::max(1, self.searcher.needle().len()); + Some(pos) + } + } + } +} + +/// An iterator over non-overlapping substring matches in reverse. +/// +/// Matches are reported by the byte offset at which they begin. +/// +/// `'a` is the shorter of two lifetimes: the byte string being searched or the +/// byte string being looked for. +#[derive(Debug)] +pub struct FindReverse<'a> { + haystack: &'a BStr, + prestate: PrefilterState, + searcher: TwoWay<'a>, + /// When searching with an empty needle, this gets set to `None` after + /// we've yielded the last element at `0`. + pos: Option, +} + +impl<'a> FindReverse<'a> { + fn new(haystack: &'a BStr, needle: &'a BStr) -> FindReverse<'a> { + let searcher = TwoWay::reverse(needle); + let prestate = searcher.prefilter_state(); + let pos = Some(haystack.len()); + FindReverse { haystack, prestate, searcher, pos } + } + + fn haystack(&self) -> &'a BStr { + self.haystack + } + + fn needle(&self) -> &BStr { + self.searcher.needle() + } +} + +impl<'a> Iterator for FindReverse<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let pos = match self.pos { + None => return None, + Some(pos) => pos, + }; + let result = self.searcher.rfind_with( + &mut self.prestate, + &self.haystack[..pos], + ); + match result { + None => None, + Some(i) => { + if pos == i { + self.pos = pos.checked_sub(1); + } else { + self.pos = Some(i); + } + Some(i) + } + } + } +} + +/// An iterator over the bytes in a byte string. +/// +/// `'a` is the lifetime of the byte string being traversed. +#[derive(Clone, Debug)] +pub struct Bytes<'a> { + it: slice::Iter<'a, u8>, +} + +impl<'a> Iterator for Bytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.it.next().map(|&b| b) + } +} + +impl<'a> DoubleEndedIterator for Bytes<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back().map(|&b| b) + } +} + +impl<'a> ExactSizeIterator for Bytes<'a> { + #[inline] + fn len(&self) -> usize { + self.it.len() + } +} + +/// An iterator over the fields in a byte string, separated by whitespace. +/// +/// This iterator splits on contiguous runs of whitespace, such that the fields +/// in `foo\t\t\n \nbar` are `foo` and `bar`. +/// +/// `'a` is the lifetime of the byte string being split. +#[derive(Debug)] +pub struct Fields<'a> { + it: FieldsWith<'a, fn(char) -> bool>, +} + +impl<'a> Fields<'a> { + fn new(bytes: &'a BStr) -> Fields<'a> { + Fields { it: bytes.fields_with(|ch| ch.is_whitespace()) } + } +} + +impl<'a> Iterator for Fields<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + self.it.next() + } +} + +/// An iterator over fields in the byte string, separated by a predicate over +/// codepoints. +/// +/// This iterator splits a byte string based on its predicate function such +/// that the elements returned are separated by contiguous runs of codepoints +/// for which the predicate returns true. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct FieldsWith<'a, F> { + f: F, + bytes: &'a BStr, + chars: CharIndices<'a>, +} + +impl<'a, F: FnMut(char) -> bool> FieldsWith<'a, F> { + fn new(bytes: &'a BStr, f: F) -> FieldsWith<'a, F> { + FieldsWith { + f: f, + bytes: bytes, + chars: bytes.char_indices(), + } + } +} + +impl<'a, F: FnMut(char) -> bool> Iterator for FieldsWith<'a, F> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + let (start, mut end); + loop { + match self.chars.next() { + None => return None, + Some((s, e, ch)) => { + if !(self.f)(ch) { + start = s; + end = e; + break; + } + } + } + } + while let Some((_, e, ch)) = self.chars.next() { + if (self.f)(ch) { + break; + } + end = e; + } + Some(&self.bytes[start..end]) + } +} + +/// An iterator over substrings in a byte string, split by a separator. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct Split<'a> { + finder: Find<'a>, + /// The end position of the previous match of our splitter. The element + /// we yield corresponds to the substring starting at `last` up to the + /// beginning of the next match of the splitter. + last: usize, + /// Only set when iteration is complete. A corner case here is when a + /// splitter is matched at the end of the haystack. At that point, we still + /// need to yield an empty string following it. + done: bool, +} + +impl<'a> Split<'a> { + fn new(haystack: &'a BStr, splitter: &'a BStr) -> Split<'a> { + let finder = haystack.find_iter(splitter); + Split { finder, last: 0, done: false } + } +} + +impl<'a> Iterator for Split<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + let haystack = self.finder.haystack; + match self.finder.next() { + Some(start) => { + let next = &haystack[self.last..start]; + self.last = start + self.finder.searcher.needle().len(); + Some(next) + } + None => { + if self.last >= haystack.len() { + if !self.done { + self.done = true; + Some(B("")) + } else { + None + } + } else { + let s = &haystack[self.last..]; + self.last = haystack.len(); + self.done = true; + Some(s) + } + } + } + } +} + +/// An iterator over substrings in a byte string, split by a separator, in +/// reverse. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitReverse<'a> { + finder: FindReverse<'a>, + /// The end position of the previous match of our splitter. The element + /// we yield corresponds to the substring starting at `last` up to the + /// beginning of the next match of the splitter. + last: usize, + /// Only set when iteration is complete. A corner case here is when a + /// splitter is matched at the end of the haystack. At that point, we still + /// need to yield an empty string following it. + done: bool, +} + +impl<'a> SplitReverse<'a> { + fn new(haystack: &'a BStr, splitter: &'a BStr) -> SplitReverse<'a> { + let finder = haystack.rfind_iter(splitter); + SplitReverse { finder, last: haystack.len(), done: false } + } +} + +impl<'a> Iterator for SplitReverse<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + let haystack = self.finder.haystack(); + match self.finder.next() { + Some(start) => { + let nlen = self.finder.needle().len(); + let next = &haystack[start + nlen..self.last]; + self.last = start; + Some(next) + } + None => { + if self.last == 0 { + if !self.done { + self.done = true; + Some(B("")) + } else { + None + } + } else { + let s = &haystack[..self.last]; + self.last = 0; + self.done = true; + Some(s) + } + } + } + } +} + +/// An iterator over at most `n` substrings in a byte string, split by a +/// separator. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitN<'a> { + split: Split<'a>, + limit: usize, + count: usize, +} + +impl<'a> SplitN<'a> { + fn new( + haystack: &'a BStr, + splitter: &'a BStr, + limit: usize, + ) -> SplitN<'a> { + let split = haystack.split(splitter); + SplitN { split, limit, count: 0 } + } +} + +impl<'a> Iterator for SplitN<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + self.count += 1; + if self.count > self.limit { + None + } else if self.count == self.limit { + Some(&self.split.finder.haystack[self.split.last..]) + } else { + self.split.next() + } + } +} + + +/// An iterator over at most `n` substrings in a byte string, split by a +/// separator, in reverse. +/// +/// `'a` is the lifetime of the byte string being split, while `F` is the type +/// of the predicate, i.e., `FnMut(char) -> bool`. +#[derive(Debug)] +pub struct SplitNReverse<'a> { + split: SplitReverse<'a>, + limit: usize, + count: usize, +} + +impl<'a> SplitNReverse<'a> { + fn new( + haystack: &'a BStr, + splitter: &'a BStr, + limit: usize, + ) -> SplitNReverse<'a> { + let split = haystack.rsplit(splitter); + SplitNReverse { split, limit, count: 0 } + } +} + +impl<'a> Iterator for SplitNReverse<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + self.count += 1; + if self.count > self.limit { + None + } else if self.count == self.limit { + Some(&self.split.finder.haystack()[..self.split.last]) + } else { + self.split.next() + } + } +} + +/// An iterator over all lines in a byte string, without their terminators. +/// +/// For this iterator, the only line terminators recognized are `\r\n` and +/// `\n`. +/// +/// `'a` is the lifetime of the byte string being iterated over. +pub struct Lines<'a> { + it: LinesWithTerminator<'a>, +} + +impl<'a> Lines<'a> { + fn new(bytes: &'a BStr) -> Lines<'a> { + Lines { it: LinesWithTerminator::new(bytes) } + } +} + +impl<'a> Iterator for Lines<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + let mut line = self.it.next()?; + if line.last() == Some(b'\n') { + line = &line[..line.len() - 1]; + if line.last() == Some(b'\r') { + line = &line[..line.len() - 1]; + } + } + Some(line) + } +} + +/// An iterator over all lines in a byte string, including their terminators. +/// +/// For this iterator, the only line terminator recognized is `\n`. (Since +/// line terminators are included, this also handles `\r\n` line endings.) +/// +/// Line terminators are only included if they are present in the original +/// byte string. For example, the last line in a byte string may not end with +/// a line terminator. +/// +/// Concatenating all elements yielded by this iterator is guaranteed to yield +/// the original byte string. +/// +/// `'a` is the lifetime of the byte string being iterated over. +pub struct LinesWithTerminator<'a> { + bytes: &'a BStr, +} + +impl<'a> LinesWithTerminator<'a> { + fn new(bytes: &'a BStr) -> LinesWithTerminator<'a> { + LinesWithTerminator { bytes } + } +} + +impl<'a> Iterator for LinesWithTerminator<'a> { + type Item = &'a BStr; + + #[inline] + fn next(&mut self) -> Option<&'a BStr> { + match self.bytes.find_byte(b'\n') { + None if self.bytes.is_empty() => None, + None => { + let line = self.bytes; + self.bytes = B(""); + Some(line) + } + Some(end) => { + let line = &self.bytes[..end + 1]; + self.bytes = &self.bytes[end + 1..]; + Some(line) + } + } + } +} + +#[cfg(test)] +mod tests { + use tests::LOSSY_TESTS; + use super::*; + + #[test] + fn to_str_lossy() { + for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() { + let got = B(input).to_str_lossy(); + assert_eq!( + expected.as_bytes(), + got.as_bytes(), + "to_str_lossy(ith: {:?}, given: {:?})", + i, input, + ); + + let mut got = String::new(); + B(input).to_str_lossy_into(&mut got); + assert_eq!( + expected.as_bytes(), got.as_bytes(), "to_str_lossy_into", + ); + + let got = String::from_utf8_lossy(input); + assert_eq!(expected.as_bytes(), got.as_bytes(), "std"); + } + } + + #[test] + #[should_panic] + fn copy_within_fail1() { + let mut buf = *b"foobar"; + let s = BStr::new_mut(&mut buf); + s.copy_within(0..2, 5); + } + + #[test] + #[should_panic] + fn copy_within_fail2() { + let mut buf = *b"foobar"; + let s = BStr::new_mut(&mut buf); + s.copy_within(3..2, 0); + } + + #[test] + #[should_panic] + fn copy_within_fail3() { + let mut buf = *b"foobar"; + let s = BStr::new_mut(&mut buf); + s.copy_within(5..7, 0); + } + + #[test] + #[should_panic] + fn copy_within_fail4() { + let mut buf = *b"foobar"; + let s = BStr::new_mut(&mut buf); + s.copy_within(0..1, 6); + } +} diff --git a/bstr/src/bstring.rs b/bstr/src/bstring.rs new file mode 100644 index 000000000..016ccbac8 --- /dev/null +++ b/bstr/src/bstring.rs @@ -0,0 +1,1588 @@ +use std::borrow::Cow; +use std::error; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::iter; +use std::ops; +use std::path::{Path, PathBuf}; +use std::ptr; +use std::str; +use std::vec; + +use bstr::BStr; +use utf8::{self, Utf8Error}; + +/// Concatenate the elements given by the iterator together into a single +/// `BString`. +/// +/// The elements may be any type that can be cheaply converted into an `&[u8]`. +/// This includes, but is not limited to, `&str`, `&BStr` and `&[u8]` itself. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr; +/// +/// let s = bstr::concat(&["foo", "bar", "baz"]); +/// assert_eq!(s, "foobarbaz"); +/// ``` +#[inline] +pub fn concat( + elements: I, +) -> BString +where T: AsRef<[u8]>, + I: IntoIterator +{ + let mut dest = BString::new(); + for element in elements { + dest.push(element); + } + dest +} + +/// Join the elements given by the iterator with the given separator into a +/// single `BString`. +/// +/// Both the separator and the elements may be any type that can be cheaply +/// converted into an `&[u8]`. This includes, but is not limited to, +/// `&str`, `&BStr` and `&[u8]` itself. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr; +/// +/// let s = bstr::join(",", &["foo", "bar", "baz"]); +/// assert_eq!(s, "foo,bar,baz"); +/// ``` +#[inline] +pub fn join( + separator: B, + elements: I, +) -> BString +where B: AsRef<[u8]>, + T: AsRef<[u8]>, + I: IntoIterator +{ + let mut it = elements.into_iter(); + let mut dest = BString::new(); + match it.next() { + None => return dest, + Some(first) => { + dest.push(first); + } + } + for element in it { + dest.push(&separator); + dest.push(element); + } + dest +} + +/// A growable byte string that is conventionally UTF-8. +/// +/// A `BString` has ownership over its contents and corresponds to +/// a growable or shrinkable buffer. Its borrowed counterpart is a +/// [`BStr`](struct.BStr.html), called a byte string slice. +/// +/// # Examples +/// +/// You can create a new `BString` from a literal Unicode string or a literal +/// byte string with `BString::from`: +/// +/// ``` +/// use bstr::BString; +/// +/// let s = BString::from("Hello, world!"); +/// ``` +/// +/// You can append bytes, characters or other strings to a `BString`: +/// +/// ``` +/// use bstr::BString; +/// +/// let mut s = BString::from("Hello, "); +/// s.push_byte(b'w'); +/// s.push_char('o'); +/// s.push("rl"); +/// s.push(b"d!"); +/// assert_eq!(s, "Hello, world!"); +/// ``` +/// +/// If you have a `String` or a `Vec`, then you can create a `BString` +/// from it with zero cost: +/// +/// ``` +/// use bstr::BString; +/// +/// let s = BString::from(vec![b'f', b'o', b'o']); +/// let s = BString::from("foo".to_string()); +/// ``` +/// +/// A `BString` can be freely converted back to a `Vec`: +/// +/// ``` +/// use bstr::BString; +/// +/// let s = BString::from("foo"); +/// let vector = s.into_vec(); +/// assert_eq!(vector, vec![b'f', b'o', b'o']); +/// ``` +/// +/// However, converting from a `BString` to a `String` requires UTF-8 +/// validation: +/// +/// ``` +/// use bstr::BString; +/// +/// # fn example() -> Result<(), ::bstr::FromUtf8Error> { +/// let bytes = BString::from("hello"); +/// let string = bytes.into_string()?; +/// +/// assert_eq!("hello", string); +/// # Ok(()) }; example().unwrap() +/// ``` +/// +/// # UTF-8 +/// +/// Like byte string slices (`BStr`), a `BString` is only conventionally +/// UTF-8. This is in constrast to the standard library's `String` type, which +/// is guaranteed to be valid UTF-8. +/// +/// Because of this relaxation, types such as `Vec`, `&[u8]`, `String` and +/// `&str` can all be converted to a `BString` (or `BStr`) at zero cost without +/// any validation step. +/// +/// Moreover, this relaxation implies that many of the restrictions around +/// mutating a `String` do not apply to `BString`. Namely, if your `BString` +/// is valid UTF-8, then the various methods that mutate the `BString` do not +/// necessarily prevent you from causing the bytes to become invalid UTF-8. +/// For example: +/// +/// ``` +/// use bstr::{B, BString}; +/// +/// let mut s = BString::from("hello"); +/// s[1] = b'\xFF'; +/// // `s` was valid UTF-8, but now it's now. +/// assert_eq!(s, B(b"h\xFFllo")); +/// ``` +/// +/// # Deref +/// +/// The `BString` type implements `Deref` and `DerefMut`, where the target +/// types are `&BStr` and `&mut BStr`, respectively. `Deref` permits all of the +/// methods defined on `BStr` to be implicitly callable on any `BString`. +/// For example, the `contains` method is defined on `BStr` and not `BString`, +/// but values of type `BString` can still use it directly: +/// +/// ``` +/// use bstr::BString; +/// +/// let s = BString::from("foobarbaz"); +/// assert!(s.contains("bar")); +/// ``` +/// +/// For more information about how deref works, see the documentation for the +/// [`std::ops::Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) +/// trait. +/// +/// # Representation +/// +/// A `BString` has the same representation as a `Vec` and a `String`. +/// That is, it is made up of three word sized components: a pointer to a +/// region of memory containing the bytes, a length and a capacity. +#[derive(Clone, Hash)] +pub struct BString { + bytes: Vec, +} + +impl BString { + /// Creates a new empty `BString`. + /// + /// Given that the `BString` is empty, this will not allocate any initial + /// buffer. While that means that this initial operation is very + /// inexpensive, it may cause excessive allocation later when you add + /// data. If you have an idea of how much data the `String` will hold, + /// consider the [`with_capacity`] method to prevent excessive + /// re-allocation. + /// + /// [`with_capacity`]: #method.with_capacity + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let s = BString::new(); + /// ``` + #[inline] + pub fn new() -> BString { + BString { bytes: vec![] } + } + + /// Creates a new empty `BString` with a particular capacity. + /// + /// `BString`s have an internal buffer to hold their data. The capacity is + /// the length of that buffer, and can be queried with the [`capacity`] + /// method. This method creates an empty `BString`, but one with an initial + /// buffer that can hold `capacity` bytes. This is useful when you may be + /// appending a bunch of data to the `BString`, reducing the number of + /// reallocations it needs to do. + /// + /// [`capacity`]: #method.capacity + /// + /// If the given capacity is `0`, no allocation will occur, and this method + /// is identical to the [`new`] method. + /// + /// [`new`]: #method.new + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::with_capacity(10); + /// + /// // The String contains no chars, even though it has capacity for more + /// assert_eq!(s.len(), 0); + /// + /// // These are all done without reallocating... + /// let cap = s.capacity(); + /// for i in 0..10 { + /// s.push_char('a'); + /// } + /// + /// assert_eq!(s.capacity(), cap); + /// + /// // ...but this may make the vector reallocate + /// s.push_char('a'); + /// ``` + #[inline] + pub fn with_capacity(capacity: usize) -> BString { + BString { bytes: Vec::with_capacity(capacity) } + } + + /// Create a new byte string from the given bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bytes = vec![b'a', b'b', b'c']; + /// let s = BString::from_vec(bytes); + /// assert_eq!("abc", s); + /// ``` + #[inline] + pub fn from_vec(bytes: Vec) -> BString { + BString { bytes } + } + + /// Create a new byte string by copying the given slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let s = BString::from_slice(b"abc"); + /// assert_eq!("abc", s); + /// ``` + #[inline] + pub fn from_slice>(slice: B) -> BString { + BString::from_vec(slice.as_ref().to_vec()) + } + + /// Create a new byte string from an owned OS string. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original OS string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsString; + /// + /// use bstr::BString; + /// + /// let os_str = OsString::from("foo"); + /// let bs = BString::from_os_string(os_str).expect("must be valid UTF-8"); + /// assert_eq!(bs, "foo"); + /// ``` + #[inline] + pub fn from_os_string(os_str: OsString) -> Result { + BString::from_os_string_imp(os_str) + } + + #[cfg(unix)] + #[inline] + fn from_os_string_imp(os_str: OsString) -> Result { + use std::os::unix::ffi::OsStringExt; + + Ok(BString::from(os_str.into_vec())) + } + + #[cfg(not(unix))] + #[inline] + fn from_os_string_imp(os_str: OsString) -> Result { + os_str.into_string().map(BString::from) + } + + /// Lossily create a new byte string from an OS string slice. + /// + /// On Unix, this always succeeds, is zero cost and always returns a slice. + /// On non-Unix systems, this does a UTF-8 check. If the given OS string + /// slice is not valid UTF-8, then it is lossily decoded into valid UTF-8 + /// (with invalid bytes replaced by the Unicode replacement codepoint). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::{B, BString}; + /// + /// let os_str = OsStr::new("foo"); + /// let bs = BString::from_os_str_lossy(os_str); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + pub fn from_os_str_lossy<'a>(os_str: &'a OsStr) -> Cow<'a, BStr> { + BString::from_os_str_lossy_imp(os_str) + } + + #[cfg(unix)] + #[inline] + fn from_os_str_lossy_imp<'a>(os_str: &'a OsStr) -> Cow<'a, BStr> { + use std::os::unix::ffi::OsStrExt; + + Cow::Borrowed(BStr::new(os_str.as_bytes())) + } + + #[cfg(not(unix))] + #[inline] + fn from_os_str_lossy_imp<'a>(os_str: &'a OsStr) -> Cow<'a, BStr> { + match os_str.to_string_lossy() { + Cow::Borrowed(x) => Cow::Borrowed(BStr::new(x)), + Cow::Owned(x) => Cow::Owned(BString::from(x)), + } + } + + /// Create a new byte string from an owned file path. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original path if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::PathBuf; + /// + /// use bstr::BString; + /// + /// let path = PathBuf::from("foo"); + /// let bs = BString::from_path_buf(path).expect("must be valid UTF-8"); + /// assert_eq!(bs, "foo"); + /// ``` + #[inline] + pub fn from_path_buf(path: PathBuf) -> Result { + BString::from_os_string(path.into_os_string()) + .map_err(PathBuf::from) + } + + /// Lossily create a new byte string from a file path. + /// + /// On Unix, this always succeeds, is zero cost and always returns a slice. + /// On non-Unix systems, this does a UTF-8 check. If the given path is not + /// valid UTF-8, then it is lossily decoded into valid UTF-8 (with invalid + /// bytes replaced by the Unicode replacement codepoint). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::path::Path; + /// + /// use bstr::{B, BString}; + /// + /// let path = Path::new("foo"); + /// let bs = BString::from_path_lossy(path); + /// assert_eq!(bs, B("foo")); + /// ``` + #[inline] + pub fn from_path_lossy<'a>(path: &'a Path) -> Cow<'a, BStr> { + BString::from_os_str_lossy(path.as_os_str()) + } + + /// Appends the given byte to the end of this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("abc"); + /// s.push_byte(b'\xE2'); + /// s.push_byte(b'\x98'); + /// s.push_byte(b'\x83'); + /// assert_eq!("abc☃", s); + /// ``` + #[inline] + pub fn push_byte(&mut self, byte: u8) { + self.bytes.push(byte); + } + + /// Appends the given `char` to the end of this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("abc"); + /// s.push_char('1'); + /// s.push_char('2'); + /// s.push_char('3'); + /// assert_eq!("abc123", s); + /// ``` + #[inline] + pub fn push_char(&mut self, ch: char) { + if ch.len_utf8() == 1 { + self.bytes.push(ch as u8); + return; + } + self.bytes.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()); + } + + /// Appends the given slice to the end of this byte string. This accepts + /// any type that be converted to a `&[u8]`. This includes, but is not + /// limited to, `&str`, `&BStr`, and of course, `&[u8]` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("abc"); + /// s.push(b"123"); + /// assert_eq!("abc123", s); + /// ``` + #[inline] + pub fn push>(&mut self, bytes: B) { + self.bytes.extend_from_slice(bytes.as_ref()); + } + + /// Extracts a byte string slice containing the entire `BString`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{BStr, BString}; + /// + /// let s = BString::from("foo"); + /// + /// assert_eq!(BStr::new("foo"), s.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &BStr { + BStr::from_bytes(&self.bytes) + } + + /// Returns this `BString` as a borrowed byte vector. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bs = BString::from("ab"); + /// assert!(bs.as_vec().capacity() >= 2); + /// ``` + #[inline] + pub fn as_vec(&self) -> &Vec { + &self.bytes + } + + /// Converts a `BString` into a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// let s_mut_str = s.as_mut_bstr(); + /// + /// s_mut_str[0] = b'F'; + /// + /// assert_eq!("Foobar", s_mut_str); + /// ``` + #[inline] + pub fn as_mut_bstr(&mut self) -> &mut BStr { + BStr::from_bytes_mut(&mut self.bytes) + } + + /// Returns this `BString` as a mutable byte vector. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut bs = BString::from("ab"); + /// bs.as_mut_vec().push(b'c'); + /// assert_eq!("abc", bs); + /// ``` + #[inline] + pub fn as_mut_vec(&mut self) -> &mut Vec { + &mut self.bytes + } + + /// Converts a `BString` into a byte vector. + /// + /// This consumes the `BString`, and thus the contents are not copied. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let s = BString::from("hello"); + /// let bytes = s.into_vec(); + /// + /// assert_eq!(vec![104, 101, 108, 108, 111], &bytes[..]); + /// ``` + #[inline] + pub fn into_vec(self) -> Vec { + self.bytes + } + + /// Converts a `BString` into a `String` if and only if this byte string is + /// valid UTF-8. + /// + /// If it is not valid UTF-8, then the error `std::string::FromUtf8Error` + /// is returned. (This error can be used to examine why UTF-8 validation + /// failed, or to regain the original byte string.) + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// # fn example() -> Result<(), ::bstr::FromUtf8Error> { + /// let bytes = BString::from("hello"); + /// let string = bytes.into_string()?; + /// + /// assert_eq!("hello", string); + /// # Ok(()) }; example().unwrap() + /// ``` + /// + /// If this byte string is not valid UTF-8, then an error will be returned. + /// That error can then be used to inspect the location at which invalid + /// UTF-8 was found, or to regain the original byte string: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let bytes = BString::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// assert_eq!(err.utf8_error().valid_up_to(), 3); + /// assert_eq!(err.utf8_error().error_len(), Some(1)); + /// + /// // At no point in this example is an allocation performed. + /// let bytes = BString::from(err.into_bstring()); + /// assert_eq!(bytes, B(b"foo\xFFbar")); + /// ``` + #[inline] + pub fn into_string(self) -> Result { + match utf8::validate(self.as_bytes()) { + Err(err) => { + Err(FromUtf8Error { original: self, err: err }) + } + Ok(()) => { + // SAFETY: This is safe because of the guarantees provided by + // utf8::validate. + unsafe { Ok(self.into_string_unchecked()) } + } + } + } + + /// Lossily converts a `BString` into a `String`. If this byte string + /// contains invalid UTF-8, then the invalid bytes are replaced with the + /// Unicode replacement codepoint. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bytes = BString::from_slice(b"foo\xFFbar"); + /// let string = bytes.into_string_lossy(); + /// assert_eq!(string, "foo\u{FFFD}bar"); + /// ``` + #[inline] + pub fn into_string_lossy(self) -> String { + self.to_string() + } + + /// Unsafely convert this byte string into a `String`, without checking for + /// valid UTF-8. + /// + /// # Safety + /// + /// Callers *must* ensure that this byte string is valid UTF-8 before + /// calling this method. Converting a byte string into a `String` that is + /// not valid UTF-8 is considered undefined behavior. + /// + /// This routine is useful in performance sensitive contexts where the + /// UTF-8 validity of the byte string is already known and it is + /// undesirable to pay the cost of an additional UTF-8 validation check + /// that [`into_string`](#method.into_string) performs. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// // SAFETY: This is safe because string literals are guaranteed to be + /// // valid UTF-8 by the Rust compiler. + /// let s = unsafe { BString::from("☃βツ").into_string_unchecked() }; + /// assert_eq!("☃βツ", s); + /// ``` + pub unsafe fn into_string_unchecked(self) -> String { + String::from_utf8_unchecked(self.into_vec()) + } + + /// Converts this byte string into an OS string, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original byte string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// use bstr::BString; + /// + /// let bs = BString::from("foo"); + /// let os_str = bs.into_os_string().expect("should be valid UTF-8"); + /// assert_eq!(os_str, OsStr::new("foo")); + /// ``` + #[inline] + pub fn into_os_string(self) -> Result { + self.into_os_string_imp() + } + + #[cfg(unix)] + #[inline] + fn into_os_string_imp(self) -> Result { + use std::os::unix::ffi::OsStringExt; + + Ok(OsString::from_vec(self.into_vec())) + } + + #[cfg(not(unix))] + #[inline] + fn into_os_string_imp(self) -> Result { + match self.into_string() { + Ok(s) => Ok(OsString::from(s)), + Err(err) => Err(err.into_bstring()), + } + } + + /// Lossily converts this byte string into an OS string, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bs = BString::from_slice(b"foo\xFFbar"); + /// let os_str = bs.into_os_string_lossy(); + /// assert_eq!(os_str.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[inline] + pub fn into_os_string_lossy(self) -> OsString { + self.into_os_string_lossy_imp() + } + + #[cfg(unix)] + #[inline] + fn into_os_string_lossy_imp(self) -> OsString { + use std::os::unix::ffi::OsStringExt; + + OsString::from_vec(self.into_vec()) + } + + #[cfg(not(unix))] + #[inline] + fn into_os_string_lossy_imp(self) -> OsString { + OsString::from(self.into_string_lossy()) + } + + /// Converts this byte string into an owned file path, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this returns the original byte string if it is not valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bs = BString::from("foo"); + /// let path = bs.into_path_buf().expect("should be valid UTF-8"); + /// assert_eq!(path.as_os_str(), "foo"); + /// ``` + #[inline] + pub fn into_path_buf(self) -> Result { + self.into_os_string().map(PathBuf::from) + } + + /// Lossily converts this byte string into an owned file path, in place. + /// + /// On Unix, this always succeeds and is zero cost. On non-Unix systems, + /// this will perform a UTF-8 check and lossily convert this byte string + /// into valid UTF-8 using the Unicode replacement codepoint. + /// + /// Note that this can prevent the correct roundtripping of file paths on + /// non-Unix systems such as Windows, where file paths are an arbitrary + /// sequence of 16-bit integers. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let bs = BString::from_slice(b"foo\xFFbar"); + /// let path = bs.into_path_buf_lossy(); + /// assert_eq!(path.to_string_lossy(), "foo\u{FFFD}bar"); + /// ``` + #[inline] + pub fn into_path_buf_lossy(self) -> PathBuf { + PathBuf::from(self.into_os_string_lossy()) + } + + /// Converts this `BString` into a `Box`. + /// + /// This will drop any excess capacity. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let s = BString::from("foobar"); + /// let b = s.into_boxed_bstr(); + /// assert_eq!(6, b.len()); + /// ``` + #[inline] + pub fn into_boxed_bstr(self) -> Box { + unsafe { + let slice = self.bytes.into_boxed_slice(); + Box::from_raw(Box::into_raw(slice) as *mut BStr) + } + } + + /// Returns this byte string's capacity, in bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let s = BString::with_capacity(10); + /// assert_eq!(10, s.capacity()); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.bytes.capacity() + } + + /// Truncates this byte string, removing all contents. + /// + /// The resulting byte string will always have length `0`, but its capacity + /// remains unchanged. + #[inline] + pub fn clear(&mut self) { + self.bytes.clear(); + } + + /// Ensures that this `BString`'s capacity is at least `additional` + /// bytes larger than its length. + /// + /// The capacity may be increased by more than `additional` bytes if it + /// chooses, to prevent frequent reallocations. + /// + /// If you do not want this "at least" behavior, use the + /// [`reserve_exact`](#method.reserve_exact) method instead. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::new(); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.bytes.reserve(additional); + } + + /// Ensures that this `BString`'s capacity is exactly `additional` + /// bytes larger than its length. + /// + /// Consider using the [`reserve`](#method.reserve) method unless you + /// absolutely know better than the allocator. + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::new(); + /// s.reserve_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.bytes.reserve_exact(additional); + } + + /// Shrinks the capacity of this `BString` to match its length. + /// + /// Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo"); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// s.shrink_to_fit(); + /// assert_eq!(3, s.capacity()); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + self.bytes.shrink_to_fit(); + } + + /// Shortens this `BString` to the specified length, in bytes. + /// + /// If `new_len` is greater than or equal to this byte string's current + /// length, then this has no effect. + /// + /// Note that this does _not_ panic if the result is not on a valid + /// `char` boundary. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// s.truncate(3); + /// assert_eq!("foo", s); + /// ``` + #[inline] + pub fn truncate(&mut self, new_len: usize) { + if new_len < self.len() { + self.bytes.truncate(new_len); + } + } + + /// Resizes this byte string in place so that the length of this byte + /// string is equivalent to `new_len`. + /// + /// If `new_len` is greater than the length of this byte string, then + /// the byte string is extended by the difference, which each additional + /// byte filled with the given value. If `new_len` is less than the length + /// of this byte string, then it is simply truncated. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("f"); + /// s.resize(3, b'o'); + /// assert_eq!(s, "foo"); + /// s.resize(1, b'o'); + /// assert_eq!(s, "f"); + /// ``` + #[inline] + pub fn resize(&mut self, new_len: usize, value: u8) { + self.bytes.resize(new_len, value); + } + + /// Removes the last codepoint from this `BString` and returns it. + /// + /// If this byte string is empty, then `None` is returned. If the last + /// bytes of this byte string do not correspond to a valid UTF-8 code unit + /// sequence, then the Unicode replacement codepoint is yielded instead in + /// accordance with the + /// [replacement codepoint substitution policy](index.html#handling-of-invalid-utf8-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo"); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('f')); + /// assert_eq!(s.pop_char(), None); + /// ``` + /// + /// This shows the replacement codepoint substitution policy. Note that + /// the first pop yields a replacement codepoint but actually removes two + /// bytes. This is in contrast with subsequent pops when encountering + /// `\xFF` since `\xFF` is never a valid prefix for any valid UTF-8 + /// code unit sequence. + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from_slice(b"f\xFF\xFF\xFFoo\xE2\x98"); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('o')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('\u{FFFD}')); + /// assert_eq!(s.pop_char(), Some('f')); + /// assert_eq!(s.pop_char(), None); + /// ``` + #[inline] + pub fn pop_char(&mut self) -> Option { + let (ch, size) = utf8::decode_last_lossy(self.as_bytes()); + if size == 0 { + return None; + } + let new_len = self.len() - size; + self.truncate(new_len); + Some(ch) + } + + /// Removes the last byte from this `BString` and returns it. + /// + /// If this byte string is empty, then `None` is returned. + /// + /// Note that if the last codepoint in this byte string is not ASCII, then + /// removing the last byte could make this byte string contain invalid + /// UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo"); + /// assert_eq!(s.pop_byte(), Some(b'o')); + /// assert_eq!(s.pop_byte(), Some(b'o')); + /// assert_eq!(s.pop_byte(), Some(b'f')); + /// assert_eq!(s.pop_byte(), None); + /// ``` + #[inline] + pub fn pop_byte(&mut self) -> Option { + self.bytes.pop() + } + + /// **DEPRECATED**: Use + /// [`pop_char`](struct.BString.html#method.pop_char) + /// or + /// [`pop_byte`](struct.BString.html#method.pop_byte) + /// instead. + /// + /// Removes the last codepoint from this `BString` and returns it. + /// + /// If this byte string is empty, then `None` is returned. If the last + /// bytes of this byte string do not correspond to a valid UTF-8 code unit + /// sequence, then the Unicode replacement codepoint is yielded instead in + /// accordance with the + /// [replacement codepoint substitution policy](index.html#handling-of-invalid-utf8-8). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo"); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('f')); + /// assert_eq!(s.pop(), None); + /// ``` + /// + /// This shows the replacement codepoint substitution policy. Note that + /// the first pop yields a replacement codepoint but actually removes two + /// bytes. This is in contrast with subsequent pops when encountering + /// `\xFF` since `\xFF` is never a valid prefix for any valid UTF-8 + /// code unit sequence. + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from_slice(b"f\xFF\xFF\xFFoo\xE2\x98"); + /// assert_eq!(s.pop(), Some('\u{FFFD}')); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('o')); + /// assert_eq!(s.pop(), Some('\u{FFFD}')); + /// assert_eq!(s.pop(), Some('\u{FFFD}')); + /// assert_eq!(s.pop(), Some('\u{FFFD}')); + /// assert_eq!(s.pop(), Some('f')); + /// assert_eq!(s.pop(), None); + /// ``` + #[deprecated(since = "0.1.1", note = "use pop_char or pop_byte instead")] + #[inline] + pub fn pop(&mut self) -> Option { + self.pop_char() + } + + /// Removes a `char` from this `BString` at the given byte position and + /// returns it. + /// + /// If the bytes at the given position do not lead to a valid UTF-8 code + /// unit sequence, then a + /// [replacement codepoint is returned instead](index.html#handling-of-invalid-utf8-8). + /// + /// # Panics + /// + /// Panics if `at` is larger than or equal to this byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foo☃bar"); + /// assert_eq!('☃', s.remove(3)); + /// assert_eq!("foobar", s); + /// ``` + /// + /// This example shows how the Unicode replacement codepoint policy is + /// used: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from_slice(b"foo\xFFbar"); + /// assert_eq!('\u{FFFD}', s.remove(3)); + /// assert_eq!("foobar", s); + /// ``` + #[inline] + pub fn remove(&mut self, at: usize) -> char { + let (ch, size) = utf8::decode_lossy(self[at..].as_bytes()); + assert!(size > 0, "expected {} to be less than {}", at, self.len()); + self.bytes.drain(at..at + size); + ch + } + + /// Inserts the given codepoint into this `BString` at a particular byte + /// position. + /// + /// This is an `O(n)` operation as it may copy a number of elements in this + /// byte string proportional to its length. + /// + /// # Panics + /// + /// Panics if `at` is larger than the byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// s.insert_char(3, '☃'); + /// assert_eq!("foo☃bar", s); + /// ``` + #[inline] + pub fn insert_char(&mut self, at: usize, ch: char) { + self.insert(at, ch.encode_utf8(&mut [0; 4]).as_bytes()); + } + + /// Inserts the given byte string into this byte string at a particular + /// byte position. + /// + /// This is an `O(n)` operation as it may copy a number of elements in this + /// byte string proportional to its length. + /// + /// Note that the type parameter `B` on this method means that it can + /// accept anything that can be cheaply converted to a `&[u8]`. This + /// includes, but is not limited to, `&str`, `&BStr` and `&[u8]` itself. + /// + /// # Panics + /// + /// Panics if `at` is larger than the byte string's length. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// s.insert(3, "☃☃☃"); + /// assert_eq!("foo☃☃☃bar", s); + /// ``` + #[inline] + pub fn insert>(&mut self, at: usize, bytes: B) { + assert!(at <= self.len(), "expected {} to be <= {}", at, self.len()); + + let bytes = bytes.as_ref(); + let len = self.len(); + + // SAFETY: We'd like to efficiently splice in the given bytes into + // this byte string. Since we are only working with `u8` elements here, + // we only need to consider whether our bounds are correct and whether + // our byte string has enough space. + self.reserve(bytes.len()); + unsafe { + // Shift bytes after `at` over by the length of `bytes` to make + // room for it. This requires referencing two regions of memory + // that may overlap, so we use ptr::copy. + ptr::copy( + self.bytes.as_ptr().add(at), + self.bytes.as_mut_ptr().add(at + bytes.len()), + len - at, + ); + // Now copy the bytes given into the room we made above. In this + // case, we know that the given bytes cannot possibly overlap + // with this byte string since we have a mutable borrow of the + // latter. Thus, we can use a nonoverlapping copy. + ptr::copy_nonoverlapping( + bytes.as_ptr(), + self.bytes.as_mut_ptr().add(at), + bytes.len(), + ); + self.bytes.set_len(len + bytes.len()); + } + } + + /// Splits this `BString` into two separate byte strings at the given + /// index. + /// + /// This returns a newly allocated `BString`, while `self` retans bytes + /// `[0, at)` and the returned `BString` contains bytes `[at, len)`. + /// + /// The capacity of `self` does not change. + /// + /// # Panics + /// + /// Panics if `at` is beyond the end of this byte string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// let bar = s.split_off(3); + /// assert_eq!(s, "foo"); + /// assert_eq!(bar, "bar"); + /// ``` + #[inline] + pub fn split_off(&mut self, at: usize) -> BString { + BString::from(self.bytes.split_off(at)) + } + + /// Removes the specified range in this byte string and replaces it with + /// the given bytes. The given bytes do not need to have the same length + /// as the range provided. + /// + /// # Panics + /// + /// Panics if the given range is invalid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// s.replace_range(2..4, "xxxxx"); + /// assert_eq!(s, "foxxxxxar"); + /// ``` + #[inline] + pub fn replace_range( + &mut self, + range: R, + replace_with: B, + ) where R: ops::RangeBounds, + B: AsRef<[u8]> + { + self.bytes.splice(range, replace_with.as_ref().iter().cloned()); + } + + /// Creates a draining iterator that removes the specified range in this + /// `BString` and yields each of the removed bytes. + /// + /// Note that the elements specified by the given range are removed + /// regardless of whether the returned iterator is fully exhausted. + /// + /// Also note that is is unspecified how many bytes are removed from the + /// `BString` if the `DrainBytes` iterator is leaked. + /// + /// # Panics + /// + /// Panics if the given range is not valid. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::BString; + /// + /// let mut s = BString::from("foobar"); + /// { + /// let mut drainer = s.drain_bytes(2..4); + /// assert_eq!(drainer.next(), Some(b'o')); + /// assert_eq!(drainer.next(), Some(b'b')); + /// assert_eq!(drainer.next(), None); + /// } + /// assert_eq!(s, "foar"); + /// ``` + #[inline] + pub fn drain_bytes( + &mut self, + range: R, + ) -> DrainBytes + where R: ops::RangeBounds + { + DrainBytes { it: self.bytes.drain(range) } + } +} + +/// A draining byte oriented iterator for `BString`. +/// +/// This iterator is created by +/// [`BString::drain`](struct.BString.html#method.drain). +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::BString; +/// +/// let mut s = BString::from("foobar"); +/// { +/// let mut drainer = s.drain_bytes(2..4); +/// assert_eq!(drainer.next(), Some(b'o')); +/// assert_eq!(drainer.next(), Some(b'b')); +/// assert_eq!(drainer.next(), None); +/// } +/// assert_eq!(s, "foar"); +/// ``` +#[derive(Debug)] +pub struct DrainBytes<'a> { + it: vec::Drain<'a, u8>, +} + +impl<'a> iter::FusedIterator for DrainBytes<'a> {} + +impl<'a> Iterator for DrainBytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.it.next() + } +} + +impl<'a> DoubleEndedIterator for DrainBytes<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.it.next_back() + } +} + +impl<'a> ExactSizeIterator for DrainBytes<'a> { + #[inline] + fn len(&self) -> usize { + self.it.len() + } +} + +/// An error that may occur when converting a `BString` to a `String`. +/// +/// This error includes the original `BString` that failed to convert to a +/// `String`. This permits callers to recover the allocation used even if it +/// it not valid UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::{B, BString}; +/// +/// let bytes = BString::from_slice(b"foo\xFFbar"); +/// let err = bytes.into_string().unwrap_err(); +/// +/// assert_eq!(err.utf8_error().valid_up_to(), 3); +/// assert_eq!(err.utf8_error().error_len(), Some(1)); +/// +/// // At no point in this example is an allocation performed. +/// let bytes = BString::from(err.into_bstring()); +/// assert_eq!(bytes, B(b"foo\xFFbar")); +/// ``` +#[derive(Debug, Eq, PartialEq)] +pub struct FromUtf8Error { + original: BString, + err: Utf8Error, +} + +impl FromUtf8Error { + /// Return the original bytes as a slice that failed to convert to a + /// `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let bytes = BString::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// // At no point in this example is an allocation performed. + /// assert_eq!(err.as_bstr(), B(b"foo\xFFbar")); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &BStr { + &self.original + } + + /// Consume this error and return the original byte string that failed to + /// convert to a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let bytes = BString::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// let original = err.into_bstring(); + /// + /// // At no point in this example is an allocation performed. + /// assert_eq!(original, B(b"foo\xFFbar")); + /// ``` + #[inline] + pub fn into_bstring(self) -> BString { + self.original + } + + /// Return the underlying UTF-8 error that occurred. This error provides + /// information on the nature and location of the invalid UTF-8 detected. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bstr::{B, BString}; + /// + /// let bytes = BString::from_slice(b"foo\xFFbar"); + /// let err = bytes.into_string().unwrap_err(); + /// + /// assert_eq!(err.utf8_error().valid_up_to(), 3); + /// assert_eq!(err.utf8_error().error_len(), Some(1)); + /// ``` + #[inline] + pub fn utf8_error(&self) -> &Utf8Error { + &self.err + } +} + +impl error::Error for FromUtf8Error { + #[inline] + fn description(&self) -> &str { "invalid UTF-8 vector" } +} + +impl fmt::Display for FromUtf8Error { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.err) + } +} + +#[cfg(test)] +mod tests { + use bstr::B; + use super::*; + + #[test] + fn insert() { + let mut s = BString::new(); + s.insert(0, "foo"); + assert_eq!("foo", s); + + let mut s = BString::from("a"); + s.insert(0, "foo"); + assert_eq!("fooa", s); + + let mut s = BString::from("a"); + s.insert(1, "foo"); + assert_eq!("afoo", s); + + let mut s = BString::from("foobar"); + s.insert(3, "quux"); + assert_eq!("fooquuxbar", s); + + let mut s = BString::from("foobar"); + s.insert(3, "x"); + assert_eq!("fooxbar", s); + + let mut s = BString::from("foobar"); + s.insert(0, "x"); + assert_eq!("xfoobar", s); + + let mut s = BString::from("foobar"); + s.insert(6, "x"); + assert_eq!("foobarx", s); + + let mut s = BString::from("foobar"); + s.insert(3, "quuxbazquux"); + assert_eq!("fooquuxbazquuxbar", s); + } + + #[test] + #[should_panic] + fn insert_fail1() { + let mut s = BString::new(); + s.insert(1, "foo"); + } + + #[test] + #[should_panic] + fn insert_fail2() { + let mut s = BString::from("a"); + s.insert(2, "foo"); + } + + #[test] + #[should_panic] + fn insert_fail3() { + let mut s = BString::from("foobar"); + s.insert(7, "foo"); + } + + #[test] + fn collect() { + let s: BString = vec!['a', 'b', 'c'].into_iter().collect(); + assert_eq!(s, "abc"); + + let s: BString = vec!["a", "b", "c"].into_iter().collect(); + assert_eq!(s, "abc"); + + let s: BString = vec![B("a"), B("b"), B("c")].into_iter().collect(); + assert_eq!(s, "abc"); + } +} diff --git a/bstr/src/cow.rs b/bstr/src/cow.rs new file mode 100644 index 000000000..9e6efa9b0 --- /dev/null +++ b/bstr/src/cow.rs @@ -0,0 +1,89 @@ +#[cfg(feature = "std")] +use std::borrow::Cow; +use core::ops; + +use bstr::BStr; +#[cfg(feature = "std")] +use bstring::BString; + +/// A specialized copy-on-write BStr. +/// +/// The purpose of this type is to permit usage of a "borrowed or owned byte +/// string" in a way that keeps std/no-std compatibility. That is, in no-std +/// mode, this type devolves into a simple &BStr with no owned variant +/// availble. +#[derive(Clone, Debug)] +pub struct CowBStr<'a>(Imp<'a>); + +#[cfg(feature = "std")] +#[derive(Clone, Debug)] +struct Imp<'a>(Cow<'a, BStr>); + +#[cfg(not(feature = "std"))] +#[derive(Clone, Debug)] +struct Imp<'a>(&'a BStr); + +impl<'a> ops::Deref for CowBStr<'a> { + type Target = BStr; + + fn deref(&self) -> &BStr { + self.as_bstr() + } +} + +impl<'a> CowBStr<'a> { + /// Create a new borrowed CowBStr. + pub fn new>(bytes: &'a B) -> CowBStr<'a> { + CowBStr(Imp::new(BStr::new(bytes))) + } + + /// Create a new owned CowBStr. + #[cfg(feature = "std")] + pub fn new_owned(bytes: BString) -> CowBStr<'static> { + CowBStr(Imp(Cow::Owned(bytes))) + } + + /// Return a borrowed byte string, regardless of whether this is an owned + /// or borrowed byte string internally. + pub fn as_bstr(&self) -> &BStr { + self.0.as_bstr() + } + + /// Return an owned version of this copy-on-write byte string. + /// + /// If this is already an owned byte string internally, then this is a + /// no-op. Otherwise, the internal byte string is copied. + #[cfg(feature = "std")] + pub fn into_owned(self) -> CowBStr<'static> { + match (self.0).0 { + Cow::Borrowed(b) => CowBStr::new_owned(b.to_bstring()), + Cow::Owned(b) => CowBStr::new_owned(b), + } + } +} + +impl<'a> Imp<'a> { + #[cfg(feature = "std")] + pub fn new(bytes: &'a BStr) -> Imp<'a> { + Imp(Cow::Borrowed(bytes)) + } + + #[cfg(not(feature = "std"))] + pub fn new(bytes: &'a BStr) -> Imp<'a> { + Imp(bytes) + } + + #[cfg(feature = "std")] + pub fn as_bstr(&self) -> &BStr { + // &*self.0 + match self.0 { + Cow::Owned(ref x) => x, + Cow::Borrowed(x) => x, + } + } + + #[cfg(not(feature = "std"))] + pub fn as_bstr(&self) -> &BStr { + self.0 + } +} diff --git a/bstr/src/freqs.rs b/bstr/src/freqs.rs new file mode 100644 index 000000000..bad6aaf21 --- /dev/null +++ b/bstr/src/freqs.rs @@ -0,0 +1,258 @@ +pub const BYTE_FREQUENCIES: [u8; 256] = [ + 55, // '\x00' + 52, // '\x01' + 51, // '\x02' + 50, // '\x03' + 49, // '\x04' + 48, // '\x05' + 47, // '\x06' + 46, // '\x07' + 45, // '\x08' + 103, // '\t' + 242, // '\n' + 66, // '\x0b' + 67, // '\x0c' + 229, // '\r' + 44, // '\x0e' + 43, // '\x0f' + 42, // '\x10' + 41, // '\x11' + 40, // '\x12' + 39, // '\x13' + 38, // '\x14' + 37, // '\x15' + 36, // '\x16' + 35, // '\x17' + 34, // '\x18' + 33, // '\x19' + 56, // '\x1a' + 32, // '\x1b' + 31, // '\x1c' + 30, // '\x1d' + 29, // '\x1e' + 28, // '\x1f' + 255, // ' ' + 148, // '!' + 164, // '"' + 149, // '#' + 136, // '$' + 160, // '%' + 155, // '&' + 173, // "'" + 221, // '(' + 222, // ')' + 134, // '*' + 122, // '+' + 232, // ',' + 202, // '-' + 215, // '.' + 224, // '/' + 208, // '0' + 220, // '1' + 204, // '2' + 187, // '3' + 183, // '4' + 179, // '5' + 177, // '6' + 168, // '7' + 178, // '8' + 200, // '9' + 226, // ':' + 195, // ';' + 154, // '<' + 184, // '=' + 174, // '>' + 126, // '?' + 120, // '@' + 191, // 'A' + 157, // 'B' + 194, // 'C' + 170, // 'D' + 189, // 'E' + 162, // 'F' + 161, // 'G' + 150, // 'H' + 193, // 'I' + 142, // 'J' + 137, // 'K' + 171, // 'L' + 176, // 'M' + 185, // 'N' + 167, // 'O' + 186, // 'P' + 112, // 'Q' + 175, // 'R' + 192, // 'S' + 188, // 'T' + 156, // 'U' + 140, // 'V' + 143, // 'W' + 123, // 'X' + 133, // 'Y' + 128, // 'Z' + 147, // '[' + 138, // '\\' + 146, // ']' + 114, // '^' + 223, // '_' + 151, // '`' + 249, // 'a' + 216, // 'b' + 238, // 'c' + 236, // 'd' + 253, // 'e' + 227, // 'f' + 218, // 'g' + 230, // 'h' + 247, // 'i' + 135, // 'j' + 180, // 'k' + 241, // 'l' + 233, // 'm' + 246, // 'n' + 244, // 'o' + 231, // 'p' + 139, // 'q' + 245, // 'r' + 243, // 's' + 251, // 't' + 235, // 'u' + 201, // 'v' + 196, // 'w' + 240, // 'x' + 214, // 'y' + 152, // 'z' + 182, // '{' + 205, // '|' + 181, // '}' + 127, // '~' + 27, // '\x7f' + 212, // '\x80' + 211, // '\x81' + 210, // '\x82' + 213, // '\x83' + 228, // '\x84' + 197, // '\x85' + 169, // '\x86' + 159, // '\x87' + 131, // '\x88' + 172, // '\x89' + 105, // '\x8a' + 80, // '\x8b' + 98, // '\x8c' + 96, // '\x8d' + 97, // '\x8e' + 81, // '\x8f' + 207, // '\x90' + 145, // '\x91' + 116, // '\x92' + 115, // '\x93' + 144, // '\x94' + 130, // '\x95' + 153, // '\x96' + 121, // '\x97' + 107, // '\x98' + 132, // '\x99' + 109, // '\x9a' + 110, // '\x9b' + 124, // '\x9c' + 111, // '\x9d' + 82, // '\x9e' + 108, // '\x9f' + 118, // '\xa0' + 141, // '¡' + 113, // '¢' + 129, // '£' + 119, // '¤' + 125, // '¥' + 165, // '¦' + 117, // '§' + 92, // '¨' + 106, // '©' + 83, // 'ª' + 72, // '«' + 99, // '¬' + 93, // '\xad' + 65, // '®' + 79, // '¯' + 166, // '°' + 237, // '±' + 163, // '²' + 199, // '³' + 190, // '´' + 225, // 'µ' + 209, // '¶' + 203, // '·' + 198, // '¸' + 217, // '¹' + 219, // 'º' + 206, // '»' + 234, // '¼' + 248, // '½' + 158, // '¾' + 239, // '¿' + 255, // 'À' + 255, // 'Á' + 255, // 'Â' + 255, // 'Ã' + 255, // 'Ä' + 255, // 'Å' + 255, // 'Æ' + 255, // 'Ç' + 255, // 'È' + 255, // 'É' + 255, // 'Ê' + 255, // 'Ë' + 255, // 'Ì' + 255, // 'Í' + 255, // 'Î' + 255, // 'Ï' + 255, // 'Ð' + 255, // 'Ñ' + 255, // 'Ò' + 255, // 'Ó' + 255, // 'Ô' + 255, // 'Õ' + 255, // 'Ö' + 255, // '×' + 255, // 'Ø' + 255, // 'Ù' + 255, // 'Ú' + 255, // 'Û' + 255, // 'Ü' + 255, // 'Ý' + 255, // 'Þ' + 255, // 'ß' + 255, // 'à' + 255, // 'á' + 255, // 'â' + 255, // 'ã' + 255, // 'ä' + 255, // 'å' + 255, // 'æ' + 255, // 'ç' + 255, // 'è' + 255, // 'é' + 255, // 'ê' + 255, // 'ë' + 255, // 'ì' + 255, // 'í' + 255, // 'î' + 255, // 'ï' + 255, // 'ð' + 255, // 'ñ' + 255, // 'ò' + 255, // 'ó' + 255, // 'ô' + 255, // 'õ' + 255, // 'ö' + 255, // '÷' + 255, // 'ø' + 255, // 'ù' + 255, // 'ú' + 255, // 'û' + 255, // 'ü' + 255, // 'ý' + 255, // 'þ' + 255, // 'ÿ' +]; diff --git a/bstr/src/impls.rs b/bstr/src/impls.rs new file mode 100644 index 000000000..614139b95 --- /dev/null +++ b/bstr/src/impls.rs @@ -0,0 +1,730 @@ +macro_rules! impl_partial_eq { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + } +} + +macro_rules! impl_partial_eq_cow { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = (&**other).as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = (&**other).as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + } +} + +macro_rules! impl_partial_ord { + ($lhs:ty, $rhs:ty) => { + impl<'a, 'b> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + let other: &[u8] = other.as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + impl<'a, 'b> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + let this: &[u8] = self.as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + } +} + +#[cfg(feature = "std")] +mod bstring { + use std::borrow::{Borrow, Cow, ToOwned}; + use std::cmp::Ordering; + use std::fmt; + use std::iter::FromIterator; + use std::ops; + + use bstr::BStr; + use bstring::BString; + + impl fmt::Display for BString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_bstr(), f) + } + } + + impl fmt::Debug for BString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_bstr(), f) + } + } + + impl ops::Deref for BString { + type Target = BStr; + + #[inline] + fn deref(&self) -> &BStr { + self.as_bstr() + } + } + + impl ops::DerefMut for BString { + #[inline] + fn deref_mut(&mut self) -> &mut BStr { + self.as_mut_bstr() + } + } + + impl AsRef<[u8]> for BString { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl AsRef for BString { + #[inline] + fn as_ref(&self) -> &BStr { + self.as_bstr() + } + } + + impl AsMut<[u8]> for BString { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + self.as_bytes_mut() + } + } + + impl AsMut for BString { + #[inline] + fn as_mut(&mut self) -> &mut BStr { + self.as_mut_bstr() + } + } + + impl Borrow for BString { + #[inline] + fn borrow(&self) -> &BStr { + self.as_bstr() + } + } + + impl ToOwned for BStr { + type Owned = BString; + + #[inline] + fn to_owned(&self) -> BString { + self.to_bstring() + } + } + + impl<'a> From<&'a [u8]> for BString { + #[inline] + fn from(s: &'a [u8]) -> BString { + BString::from_vec(s.to_vec()) + } + } + + impl From> for BString { + #[inline] + fn from(s: Vec) -> BString { + BString::from_vec(s) + } + } + + impl From for Vec { + #[inline] + fn from(s: BString) -> Vec { + s.into_vec() + } + } + + impl<'a> From<&'a str> for BString { + #[inline] + fn from(s: &'a str) -> BString { + BString::from_vec(s.as_bytes().to_vec()) + } + } + + impl From for BString { + #[inline] + fn from(s: String) -> BString { + BString::from_vec(s.into_bytes()) + } + } + + impl<'a> From<&'a BStr> for BString { + #[inline] + fn from(s: &'a BStr) -> BString { + s.to_bstring() + } + } + + impl<'a> From for Cow<'a, BStr> { + #[inline] + fn from(s: BString) -> Cow<'a, BStr> { + Cow::Owned(s) + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + BString::from(iter.into_iter().collect::()) + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + BString::from(iter.into_iter().collect::>()) + } + } + + impl<'a> FromIterator<&'a str> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = BString::new(); + for b in iter { + buf.push(b); + } + buf + } + } + + impl<'a> FromIterator<&'a [u8]> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = BString::new(); + for b in iter { + buf.push(b); + } + buf + } + } + + impl<'a> FromIterator<&'a BStr> for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = BString::new(); + for b in iter { + buf.push(b); + } + buf + } + } + + impl FromIterator for BString { + #[inline] + fn from_iter>(iter: T) -> BString { + let mut buf = BString::new(); + for b in iter { + buf.push(b); + } + buf + } + } + + impl Eq for BString {} + + impl PartialEq for BString { + #[inline] + fn eq(&self, other: &BString) -> bool { + &self[..] == &other[..] + } + } + + impl_partial_eq!(BString, Vec); + impl_partial_eq!(BString, [u8]); + impl_partial_eq!(BString, &'a [u8]); + impl_partial_eq!(BString, String); + impl_partial_eq!(BString, str); + impl_partial_eq!(BString, &'a str); + impl_partial_eq!(BString, BStr); + impl_partial_eq!(BString, &'a BStr); + + impl PartialOrd for BString { + #[inline] + fn partial_cmp(&self, other: &BString) -> Option { + PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes()) + } + } + + impl Ord for BString { + #[inline] + fn cmp(&self, other: &BString) -> Ordering { + self.partial_cmp(other).unwrap() + } + } + + impl_partial_ord!(BString, Vec); + impl_partial_ord!(BString, [u8]); + impl_partial_ord!(BString, &'a [u8]); + impl_partial_ord!(BString, String); + impl_partial_ord!(BString, str); + impl_partial_ord!(BString, &'a str); + impl_partial_ord!(BString, BStr); + impl_partial_ord!(BString, &'a BStr); +} + +mod bstr { + #[cfg(feature = "std")] + use std::borrow::Cow; + + use core::cmp::Ordering; + use core::fmt; + use core::ops; + + use bstr::BStr; + + impl fmt::Display for BStr { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Ok(allutf8) = self.to_str() { + return fmt::Display::fmt(allutf8, f); + } + for ch in self.chars() { + write!(f, "{}", ch)?; + } + Ok(()) + } + } + + impl fmt::Debug for BStr { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"")?; + for (s, e, ch) in self.char_indices() { + if ch == '\u{FFFD}' { + for &b in self[s..e].as_bytes() { + write!(f, r"\x{:X}", b)?; + } + } else { + write!(f, "{}", ch.escape_debug())?; + } + } + write!(f, "\"")?; + Ok(()) + } + } + + impl ops::Index for BStr { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.as_bytes()[idx] + } + } + + impl ops::Index for BStr { + type Output = BStr; + + #[inline] + fn index(&self, _: ops::RangeFull) -> &BStr { + self + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::Range) -> &BStr { + BStr::new(&self.as_bytes()[r.start..r.end]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeInclusive) -> &BStr { + BStr::new(&self.as_bytes()[*r.start()..=*r.end()]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeFrom) -> &BStr { + BStr::new(&self.as_bytes()[r.start..]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeTo) -> &BStr { + BStr::new(&self.as_bytes()[..r.end]) + } + } + + impl ops::Index> for BStr { + type Output = BStr; + + #[inline] + fn index(&self, r: ops::RangeToInclusive) -> &BStr { + BStr::new(&self.as_bytes()[..=r.end]) + } + } + + impl ops::IndexMut for BStr { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.as_bytes_mut()[idx] + } + } + + impl ops::IndexMut for BStr { + #[inline] + fn index_mut(&mut self, _: ops::RangeFull) -> &mut BStr { + self + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::Range) -> &mut BStr { + BStr::from_bytes_mut(&mut self.as_bytes_mut()[r.start..r.end]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeInclusive) -> &mut BStr { + BStr::from_bytes_mut(&mut self.as_bytes_mut()[*r.start()..=*r.end()]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeFrom) -> &mut BStr { + BStr::from_bytes_mut(&mut self.as_bytes_mut()[r.start..]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeTo) -> &mut BStr { + BStr::from_bytes_mut(&mut self.as_bytes_mut()[..r.end]) + } + } + + impl ops::IndexMut> for BStr { + #[inline] + fn index_mut(&mut self, r: ops::RangeToInclusive) -> &mut BStr { + BStr::from_bytes_mut(&mut self.as_bytes_mut()[..=r.end]) + } + } + + impl AsRef<[u8]> for BStr { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } + } + + impl AsRef for [u8] { + #[inline] + fn as_ref(&self) -> &BStr { + BStr::new(self) + } + } + + impl AsRef for str { + #[inline] + fn as_ref(&self) -> &BStr { + BStr::new(self) + } + } + + impl AsMut<[u8]> for BStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + self.as_bytes_mut() + } + } + + impl AsMut for [u8] { + #[inline] + fn as_mut(&mut self) -> &mut BStr { + BStr::new_mut(self) + } + } + + impl<'a> From<&'a [u8]> for &'a BStr { + #[inline] + fn from(s: &'a [u8]) -> &'a BStr { + BStr::from_bytes(s) + } + } + + impl<'a> From<&'a str> for &'a BStr { + #[inline] + fn from(s: &'a str) -> &'a BStr { + BStr::from_bytes(s.as_bytes()) + } + } + + #[cfg(feature = "std")] + impl<'a> From<&'a BStr> for Cow<'a, BStr> { + #[inline] + fn from(s: &'a BStr) -> Cow<'a, BStr> { + Cow::Borrowed(s) + } + } + + impl Eq for BStr {} + + impl PartialEq for BStr { + #[inline] + fn eq(&self, other: &BStr) -> bool { + self.as_bytes() == other.as_bytes() + } + } + + impl_partial_eq!(BStr, [u8]); + impl_partial_eq!(BStr, &'a [u8]); + impl_partial_eq!(BStr, str); + impl_partial_eq!(BStr, &'a str); + + #[cfg(feature = "std")] + impl_partial_eq!(BStr, Vec); + #[cfg(feature = "std")] + impl_partial_eq!(&'a BStr, Vec); + #[cfg(feature = "std")] + impl_partial_eq!(BStr, String); + #[cfg(feature = "std")] + impl_partial_eq!(&'a BStr, String); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, BStr>); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, str>); + #[cfg(feature = "std")] + impl_partial_eq_cow!(&'a BStr, Cow<'a, [u8]>); + + impl PartialOrd for BStr { + #[inline] + fn partial_cmp(&self, other: &BStr) -> Option { + PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes()) + } + } + + impl Ord for BStr { + #[inline] + fn cmp(&self, other: &BStr) -> Ordering { + self.partial_cmp(other).unwrap() + } + } + + impl_partial_ord!(BStr, [u8]); + impl_partial_ord!(BStr, &'a [u8]); + impl_partial_ord!(BStr, str); + impl_partial_ord!(BStr, &'a str); + + #[cfg(feature = "std")] + impl_partial_ord!(BStr, Vec); + #[cfg(feature = "std")] + impl_partial_ord!(&'a BStr, Vec); + #[cfg(feature = "std")] + impl_partial_ord!(BStr, String); + #[cfg(feature = "std")] + impl_partial_ord!(&'a BStr, String); +} + +#[cfg(feature = "serde1-nostd")] +mod bstr_serde { + use std::fmt; + + use serde::{ + Serialize, Serializer, + Deserialize, Deserializer, de::Error, de::Visitor, + }; + + use bstr::BStr; + + impl Serialize for BStr { + #[inline] + fn serialize( + &self, + serializer: S, + ) -> Result + where S: Serializer + { + serializer.serialize_bytes(self.as_bytes()) + } + } + + impl<'a, 'de: 'a> Deserialize<'de> for &'a BStr { + #[inline] + fn deserialize( + deserializer: D, + ) -> Result<&'a BStr, D::Error> + where D: Deserializer<'de> + { + struct BStrVisitor; + + impl<'de> Visitor<'de> for BStrVisitor { + type Value = &'de BStr; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a borrowed byte string") + } + + #[inline] + fn visit_borrowed_bytes( + self, + value: &'de [u8], + ) -> Result<&'de BStr, E> { + Ok(BStr::new(value)) + } + + #[inline] + fn visit_borrowed_str( + self, + value: &'de str, + ) -> Result<&'de BStr, E> { + Ok(BStr::new(value)) + } + } + + deserializer.deserialize_bytes(BStrVisitor) + } + } +} + +#[cfg(feature = "serde1")] +mod bstring_serde { + use std::cmp; + use std::fmt; + + use serde::{ + Serialize, Serializer, + Deserialize, Deserializer, de::Error, de::SeqAccess, de::Visitor, + }; + + use bstring::BString; + + impl Serialize for BString { + #[inline] + fn serialize( + &self, + serializer: S, + ) -> Result + where S: Serializer + { + serializer.serialize_bytes(self.as_bytes()) + } + } + + impl<'de> Deserialize<'de> for BString { + #[inline] + fn deserialize( + deserializer: D, + ) -> Result + where D: Deserializer<'de> + { + struct BStringVisitor; + + impl<'de> Visitor<'de> for BStringVisitor { + type Value = BString; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a byte string") + } + + #[inline] + fn visit_seq>( + self, + mut visitor: V, + ) -> Result { + let len = cmp::min(visitor.size_hint().unwrap_or(0), 256); + let mut bytes = BString::with_capacity(len); + while let Some(v) = visitor.next_element()? { + bytes.push_byte(v); + } + Ok(bytes) + } + + #[inline] + fn visit_bytes( + self, + value: &[u8], + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_byte_buf( + self, + value: Vec, + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_str( + self, + value: &str, + ) -> Result { + Ok(BString::from(value)) + } + + #[inline] + fn visit_string( + self, + value: String, + ) -> Result { + Ok(BString::from(value)) + } + } + + deserializer.deserialize_byte_buf(BStringVisitor) + } + } +} + +#[cfg(test)] +mod bstring_arbitrary { + use bstring::BString; + + use quickcheck::{Arbitrary, Gen}; + + impl Arbitrary for BString { + fn arbitrary(g: &mut G) -> BString { + BString::from(Vec::::arbitrary(g)) + } + + fn shrink(&self) -> Box> { + Box::new(self.as_vec().shrink().map(BString::from)) + } + } +} diff --git a/bstr/src/io.rs b/bstr/src/io.rs new file mode 100644 index 000000000..6937be2eb --- /dev/null +++ b/bstr/src/io.rs @@ -0,0 +1,203 @@ +/*! +Utilities for working with I/O using byte strings. + +This module currently only exports a single trait, `BufReadExt`, which provides +facilities for conveniently and efficiently working with lines as byte strings. + +More APIs may be added in the future. +*/ + +use std::io; + +use bstr::BStr; +use bstring::BString; + +/// An extention trait for +/// [`std::io::BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) +/// which provides convenience APIs for dealing with byte strings. +pub trait BufReadExt: io::BufRead { + /// Returns an iterator over the lines of this reader, where each line + /// is represented as a byte string. + /// + /// Each item yielded by this iterator is a `io::Result`, where + /// an error is yielded if there was a problem reading from the underlying + /// reader. + /// + /// On success, the next line in the iterator is returned. The line does + /// *not* contain a trailing `\n` or `\r\n`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// for result in cursor.byte_lines() { + /// let line = result?; + /// lines.push(line); + /// } + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem"); + /// assert_eq!(lines[1], "ipsum"); + /// assert_eq!(lines[2], "dolor"); + /// # Ok(()) }; example().unwrap() + /// ``` + fn byte_lines(self) -> ByteLines where Self: Sized { + ByteLines { buf: self } + } + + /// Executes the given closure on each line in the underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// The closure given is called on exactly the same values as yielded by + /// the [`byte_lines`](trait.BufReadExt.html#method.byte_lines) + /// iterator. Namely, lines do _not_ contain trailing `\n` or `\r\n` bytes. + /// + /// This routine is useful for iterating over lines as quickly as + /// possible. Namely, a single allocation is reused for each line. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// cursor.for_byte_line(|line| { + /// lines.push(line.to_bstring()); + /// Ok(true) + /// })?; + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem"); + /// assert_eq!(lines[1], "ipsum"); + /// assert_eq!(lines[2], "dolor"); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_line( + mut self, + mut for_each_line: F, + ) -> io::Result<()> + where Self: Sized, + F: FnMut(&BStr) -> io::Result + { + let mut bytes = BString::new(); + while self.read_until(b'\n', bytes.as_mut_vec())? > 0 { + trim_line(&mut bytes); + if !for_each_line(&bytes)? { + break; + } + bytes.clear(); + } + Ok(()) + } + + /// Executes the given closure on each line in the underlying reader. + /// + /// If the closure returns an error (or if the underlying reader returns an + /// error), then iteration is stopped and the error is returned. If false + /// is returned, then iteration is stopped and no error is returned. + /// + /// Unlike + /// [`for_byte_line`](trait.BufReadExt.html#method.for_byte_line), + /// the lines given to the closure *do* include the line terminator, if one + /// exists. + /// + /// This routine is useful for iterating over lines as quickly as + /// possible. Namely, a single allocation is reused for each line. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::io; + /// + /// use bstr::io::BufReadExt; + /// + /// # fn example() -> Result<(), io::Error> { + /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor"); + /// + /// let mut lines = vec![]; + /// cursor.for_byte_line_with_terminator(|line| { + /// lines.push(line.to_bstring()); + /// Ok(true) + /// })?; + /// assert_eq!(lines.len(), 3); + /// assert_eq!(lines[0], "lorem\n"); + /// assert_eq!(lines[1], "ipsum\r\n"); + /// assert_eq!(lines[2], "dolor"); + /// # Ok(()) }; example().unwrap() + /// ``` + fn for_byte_line_with_terminator( + mut self, + mut for_each_line: F, + ) -> io::Result<()> + where Self: Sized, + F: FnMut(&BStr) -> io::Result + { + let mut bytes = BString::new(); + while self.read_until(b'\n', bytes.as_mut_vec())? > 0 { + if !for_each_line(&bytes)? { + break; + } + bytes.clear(); + } + Ok(()) + } +} + +impl BufReadExt for B {} + +/// An iterator over lines from an instance of +/// [`std::io::BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html). +/// +/// This iterator is generally created by calling the +/// [`byte_lines`](trait.BufReadExt.html#method.byte_lines) +/// method on the +/// [`BufReadExt`](trait.BufReadExt.html) +/// trait. +#[derive(Debug)] +pub struct ByteLines { + buf: B, +} + +impl Iterator for ByteLines { + type Item = io::Result; + + fn next(&mut self) -> Option> { + let mut bytes = BString::new(); + match self.buf.read_until(b'\n', bytes.as_mut_vec()) { + Err(e) => Some(Err(e)), + Ok(0) => None, + Ok(_) => { + trim_line(&mut bytes); + Some(Ok(bytes)) + } + } + } +} + +fn trim_line(line: &mut BString) { + if line.last() == Some(b'\n') { + line.pop_byte(); + if line.last() == Some(b'\r') { + line.pop_byte(); + } + } +} diff --git a/bstr/src/lib.rs b/bstr/src/lib.rs new file mode 100644 index 000000000..89b6219c6 --- /dev/null +++ b/bstr/src/lib.rs @@ -0,0 +1,407 @@ +/*! +An experimental byte string library. + +Byte strings are just like standard Unicode strings with one very important +difference: byte strings are only *conventionally* UTF-8 while Rust's standard +Unicode strings are *guaranteed* to be valid UTF-8. The primary motivation for +this type is for handling arbitrary bytes that are mostly UTF-8. + +# Overview + +There are two primary types in this crate: + +* [`BString`](struct.BString.html) is an owned growable byte string buffer, + analogous to `String`. +* [`BStr`](struct.BStr.html) is a byte string slice, analogous to `str`. + +Additionally, the free function [`B`](fn.B.html) serves as a convenient short +hand for writing byte string literals. + +# Quick examples + +Byte strings are effectively the same thing as a `Vec` or a `&[u8]`, except +they provide a string oriented API. Operations such as iterating over +graphemes, searching for substrings, replacing substrings, trimming and case +conversion are examples of things not provided on the standard `&[u8]` APIs +but are provided by this crate. For example, this code iterates over all of +occurrences of a subtring: + +``` +use bstr::B; + +let s = B("foo bar foo foo quux foo"); + +let mut matches = vec![]; +for start in s.find_iter("foo") { + matches.push(start); +} +assert_eq!(matches, [0, 8, 12, 21]); +``` + +Here's another example showing how to do a search and replace: + +``` +use bstr::B; + +let old = B("foo bar foo foo quux foo"); +let new = old.replace("foo", "hello"); +assert_eq!(new, "hello bar hello hello quux hello"); +``` + +And here's an example that shows case conversion, even in the presence of +invalid UTF-8: + +``` +use bstr::{B, BString}; + +let mut lower = BString::from("hello β"); +lower[0] = b'\xFF'; +// lowercase β is uppercased to Β +assert_eq!(lower.to_uppercase(), B(b"\xFFELLO \xCE\x92")); +``` + +# When should I use byte strings? + +This library is somewhat of an experiment that reflects my hypothesis that +UTF-8 by convention is a better trade off in some circumstances than guaranteed +UTF-8. It's possible, perhaps even likely, that this is a niche concern for +folks working closely with core text primitives. + +The first time this idea hit me was in the implementation of Rust's regex +engine. In particular, very little of the internal implementation cares at all +about searching valid UTF-8 encoded strings. Indeed, internally, the +implementation converts `&str` from the API to `&[u8]` fairly quickly and +just deals with raw bytes. UTF-8 match boundaries are then guaranteed by the +finite state machine itself rather than any specific string type. This makes it +possible to not only run regexes on `&str` values, but also on `&[u8]` values. + +Why would you ever want to run a regex on a `&[u8]` though? Well, `&[u8]` is +the fundamental way at which one reads data from all sorts of streams, via the +standard library's [`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) +trait. In particular, there is no platform independent way to determine whether +what you're reading from is some binary file or a human readable text file. +Therefore, if you're writing a program to search files, you probably need to +deal with `&[u8]` directly unless you're okay with first converting it to a +`&str` and dropping any bytes that aren't valid UTF-8. (Or otherwise determine +the encoding---which is often impractical---and perform a transcoding step.) +Often, the simplest and most robust way to approach this is to simply treat the +contents of a file as if it were mostly valid UTF-8 and pass through invalid +UTF-8 untouched. This may not be the most correct approach though! + +One case in particular exacerbates these issues, and that's memory mapping +a file. When you memory map a file, that file may be gigabytes big, but all +you get is a `&[u8]`. Converting that to a `&str` all in one go is generally +not a good idea because of the costs associated with doing so, and also +because it generally causes one to do two passes over the data instead of +one, which is quite undesirable. It is of course usually possible to do it an +incremental way by only parsing chunks at a time, but this is often complex to +do or impractical. For example, many regex engines only accept one contiguous +sequence of bytes at a time with no way to perform incremental matching. + +In summary, the conventional UTF-8 byte strings provided by this library is an +experiment. They are definitely useful in some limited circumstances, but how +useful they are more broadly isn't clear yet. + +# `bstr` in public APIs + +Since this library is still experimental, you should not use it in the public +API of your crates until it hits `1.0` (unless you're OK with with tracking +breaking releases of `bstr`). It is a priority to move this crate to `1.0` +expediently so that `BString` and `BStr` may be used in the public APIs of +other crates. While both `BString` and `BStr` do provide zero cost ways of +converting between `Vec` and `&[u8]`, it is often convenient to provide +trait implementations for `BString` and `BStr`, which requires making `bstr` a +public dependency. + +# Differences with standard strings + +The primary difference between `BStr` and `str` is that the former is +conventionally UTF-8 while the latter is guaranteed to be UTF-8. The phrase +"conventionally UTF-8" means that a `BStr` may contain bytes that do not form +a valid UTF-8 sequence, but operations defined on the type are generally most +useful on valid UTF-8 sequences. For example, iterating over Unicode codepoints +or grapheme clusters is an operation that is only defined on valid UTF-8. +Therefore, when invalid UTF-8 is encountered, the Unicode replacement codepoint +is substituted. Thus, a byte string that is not UTF-8 at all is of limited +utility when using these methods. + +However, not all operations on byte strings are specifically Unicode aware. For +example, substring search has no specific Unicode semantics ascribed to it. It +works just as well for byte strings that are completely valid UTF-8 as for byte +strings that contain no valid UTF-8 at all. Similarly for replacements and +various other operations. + +Aside from the difference in how UTF-8 is handled, the APIs between `BStr` and +`str` (and `BString` and `String`) are intentionally very similar, including +maintaining the same behavior for corner cases in things like substring +splitting. There are, however, some differences: + +* Substring search is not done with `matches`, but instead, `find_iter`. + In general, this crate does not define any generic + [`Pattern`](https://doc.rust-lang.org/std/str/pattern/trait.Pattern.html) + infrastructure, and instead prefers adding new methods for different + argument types. For example, `matches` can search by a `char` or a `&str`, + where as `find_iter` can only search by a byte string. `find_char` can be + used for searching by a `char`. +* Since `SliceConcatExt` in the standard library is unstable, it is not + possible to reuse that to implement `join` and `concat` methods. Instead, + [`join`](fn.join.html) and [`concat`](fn.concat.html) are provided as free + functions that perform a similar task. +* This library bundles in a few more Unicode operations, such as grapheme, + word and sentence iterators. More operations, such as normalization and + case folding, may be provided in the future. +* Some `String`/`str` APIs will panic if a particular index was not on a valid + UTF-8 code unit sequence boundary. Conversely, no such checking is performed + in this crate, as is consistent with treating byte strings as a sequence of + bytes. This means callers are responsible for maintaining a UTF-8 invariant + if that's important. + +Otherwise, you should find most of the APIs between this crate and the standard +library to be very similar, if not identical. + +# Handling of invalid UTF-8 + +Since byte strings are only *conventionally* UTF-8, there is no guarantee +that byte strings contain valid UTF-8. Indeed, it is perfectly legal for a +byte string to contain arbitrary bytes. However, since this library defines +a *string* type, it provides many operations specified by Unicode. These +operations are typically only defined over codepoints, and thus have no real +meaning on bytes that are invalid UTF-8 because they do not map to a particular +codepoint. + +For this reason, whenever operations defined only on codepoints are used, this +library will automatically convert invalid UTF-8 to the Unicode replacement +codepoint, `U+FFFD`, which looks like this: `�`. For example, an +[iterator over codepoints](struct.Chars.html) will yield a Unicode +replacement codepoint whenever it comes across bytes that are not valid UTF-8: + +``` +use bstr::B; + +let bs = B(b"a\xFF\xFFz"); +let chars: Vec = bs.chars().collect(); +assert_eq!(vec!['a', '\u{FFFD}', '\u{FFFD}', 'z'], chars); +``` + +There are a few ways in which invalid bytes can be substituted with a Unicode +replacement codepoint. One way, not used by this crate, is to replace every +individual invalid byte with a single replacement codepoint. In contrast, the +approach this crate uses is called the "substitution of maximal subparts," as +specified by the Unicode Standard (Chapter 3, Section 9). (This approach is +also used by [W3C's Encoding Standard](https://www.w3.org/TR/encoding/).) In +this strategy, a replacement codepoint is inserted whenever a byte is found +that cannot possibly lead to a valid UTF-8 code unit sequence. If there were +previous bytes that represented a *prefix* of a well-formed UTF-8 code unit +sequence, then all of those bytes (up to 3) are substituted with a single +replacement codepoint. For example: + +``` +use bstr::B; + +let bs = B(b"a\xF0\x9F\x87z"); +let chars: Vec = bs.chars().collect(); +// The bytes \xF0\x9F\x87 could lead to a valid UTF-8 sequence, but 3 of them +// on their own are invalid. Only one replacement codepoint is substituted, +// which demonstrates the "substitution of maximal subparts" strategy. +assert_eq!(vec!['a', '\u{FFFD}', 'z'], chars); +``` + +If you do need to access the raw bytes for some reason in an iterator like +`Chars`, then you should use the iterator's "indices" variant, which gives +the byte offsets containing the invalid UTF-8 bytes that were substituted with +the replacement codepoint. For example: + +``` +use bstr::{B, BStr}; + +let bs = B(b"a\xE2\x98z"); +let chars: Vec<(usize, usize, char)> = bs.char_indices().collect(); +// Even though the replacement codepoint is encoded as 3 bytes itself, the +// byte range given here is only two bytes, corresponding to the original +// raw bytes. +assert_eq!(vec![(0, 1, 'a'), (1, 3, '\u{FFFD}'), (3, 4, 'z')], chars); + +// Thus, getting the original raw bytes is as simple as slicing the original +// byte string: +let chars: Vec<&BStr> = bs.char_indices().map(|(s, e, _)| &bs[s..e]).collect(); +assert_eq!(vec![B("a"), B(b"\xE2\x98"), B("z")], chars); +``` + +# File paths and OS strings + +One of the premiere features of Rust's standard library is how it handles file +paths. In particular, it makes it very hard to write incorrect code while +simultaneously providing a correct cross platform abstraction for manipulating +file paths. The key challenge that one faces with file paths across platforms +is derived from the following observations: + +* On most Unix-like systems, file paths are an arbitrary sequence of bytes. +* On Windows, file paths are an arbitrary sequence of 16-bit integers. + +(In both cases, certain sequences aren't allowed. For example a `NUL` byte is +not allowed in either case. But we can ignore this for the purposes of this +section.) + +Byte strings, like the ones provided in this crate, line up really well with +file paths on Unix like systems, which are themselves just arbitrary sequences +of bytes. It turns out that if you treat them as "mostly UTF-8," then things +work out pretty well. On the contrary, byte strings _don't_ really work +that well on Windows because it's not possible to correctly roundtrip file +paths between 16-bit integers and something that looks like UTF-8 _without_ +explicitly defining an encoding to do this for you, which is anathema to byte +strings, which are just bytes. + +Rust's standard library elegantly solves this problem by specifying an +internal encoding for file paths that's only used on Windows called +[WTF-8](https://simonsapin.github.io/wtf-8/). Its key properties are that they +permit losslessly roundtripping file paths on Windows by extending UTF-8 to +support an encoding of surrogate codepoints, while simultaneously supporting +zero-cost conversion from Rust's Unicode strings to file paths. (Since UTF-8 is +a proper subset of WTF-8.) + +The fundamental point at which the above strategy fails is when you want to +treat file paths as things that look like strings in a zero cost way. In most +cases, this is actually the wrong thing to do, but some cases call for it, +for example, glob or regex matching on file paths. This is because WTF-8 is +treated as an internal implementation detail, and there is no way to access +those bytes via a public API. Therefore, such consumers are limited in what +they can do: + +1. One could re-implement WTF-8 and re-encode file paths on Windows to WTF-8 + by accessing their underlying 16-bit integer representation. Unfortunately, + this isn't zero cost (it introduces a second WTF-8 decoding step) and it's + not clear this is a good thing to do, since WTF-8 should ideally remain an + internal implementation detail. +2. One could instead declare that they will not handle paths on Windows that + are not valid UTF-16, and return an error when one is encountered. +3. Like (2), but instead of returning an error, lossily decode the file path + on Windows that isn't valid UTF-16 into UTF-16 by replacing invalid bytes + with the Unicode replacement codepoint. + +While this library may provide facilities for (1) in the future, currently, +this library only provides facilities for (2) and (3). In particular, a suite +of conversion functions are provided that permit converting between byte +strings, OS strings and file paths. For owned `BString`s, they are: + +* [`BString::from_os_string`](struct.BString.html#method.from_os_string) +* [`BString::from_os_str_lossy`](struct.BString.html#method.from_os_str_lossy) +* [`BString::from_path_buf`](struct.BString.html#method.from_path_buf) +* [`BString::from_path_lossy`](struct.BString.html#method.from_path_lossy) +* [`BString::into_os_string`](struct.BString.html#method.into_os_string) +* [`BString::into_os_string_lossy`](struct.BString.html#method.into_os_string_lossy) +* [`BString::into_path_buf`](struct.BString.html#method.into_path_buf) +* [`BString::into_path_buf_lossy`](struct.BString.html#method.into_path_buf_lossy) + +For byte string slices, they are: + +* [`BStr::from_os_str`](struct.BStr.html#method.from_os_str) +* [`BStr::from_path`](struct.BStr.html#method.from_path) +* [`BStr::to_os_str`](struct.BStr.html#method.to_os_str) +* [`BStr::to_os_str_lossy`](struct.BStr.html#method.to_os_str_lossy) +* [`BStr::to_path`](struct.BStr.html#method.to_path) +* [`BStr::to_path_lossy`](struct.BStr.html#method.to_path_lossy) + +On Unix, all of these conversions are rigorously zero cost, which gives one +a way to ergonomically deal with raw file paths exactly as they are using +normal string-related functions. On Windows, these conversion routines perform +a UTF-8 check and either return an error or lossily decode the file path +into valid UTF-8, depending on which function you use. This means that you +cannot roundtrip all file paths on Windows correctly using these conversion +routines. However, this may be an acceptable downside since such file paths +are exceptionally rare. Moreover, roundtripping isn't always necessary, for +example, if all you're doing is filtering based on file paths. + +The reason why using byte strings for this is potentially superior than the +standard library's approach is that a lot of Rust code is already lossily +converting file paths to Rust's Unicode strings, which are required to be valid +UTF-8, and thus contain latent bugs on Unix where paths with invalid UTF-8 are +not terribly uncommon. If you instead use byte strings, then you're guaranteed +to write correct code for Unix, at the cost of getting a corner case wrong on +Windows. +*/ + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +extern crate core; + +#[cfg(feature = "unicode")] +#[macro_use] +extern crate lazy_static; +extern crate memchr; +#[cfg(test)] +#[macro_use] +extern crate quickcheck; +#[cfg(feature = "unicode")] +extern crate regex_automata; +#[cfg(feature = "serde1-nostd")] +extern crate serde; +#[cfg(test)] +extern crate ucd_parse; + +pub use bstr::{ + B, BStr, + Bytes, + Finder, FinderReverse, Find, FindReverse, + Split, SplitReverse, SplitN, SplitNReverse, + Fields, FieldsWith, + Lines, LinesWithTerminator, +}; +#[cfg(feature = "std")] +pub use bstring::{BString, DrainBytes, FromUtf8Error, concat, join}; +pub use slice_index::SliceIndex; +#[cfg(feature = "unicode")] +pub use unicode::{ + Graphemes, GraphemeIndices, + Sentences, SentenceIndices, + Words, WordIndices, WordsWithBreaks, WordsWithBreakIndices, +}; +pub use utf8::{ + Utf8Error, Chars, CharIndices, + decode as decode_utf8, + decode_last as decode_last_utf8, +}; + +mod ascii; +mod bstr; +#[cfg(feature = "std")] +mod bstring; +mod cow; +mod impls; +#[cfg(feature = "std")] +pub mod io; +mod search; +mod slice_index; +#[cfg(test)] +mod tests; +#[cfg(feature = "unicode")] +mod unicode; +mod utf8; + +#[cfg(test)] +mod apitests { + use super::*; + + #[test] + fn oibits() { + use std::panic::{RefUnwindSafe, UnwindSafe}; + + fn assert_send() {} + fn assert_sync() {} + fn assert_unwind_safe() {} + + assert_send::<&BStr>(); + assert_sync::<&BStr>(); + assert_unwind_safe::<&BStr>(); + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + assert_send::(); + assert_sync::(); + assert_unwind_safe::(); + } +} diff --git a/bstr/src/search/byte_frequencies.rs b/bstr/src/search/byte_frequencies.rs new file mode 100644 index 000000000..bad6aaf21 --- /dev/null +++ b/bstr/src/search/byte_frequencies.rs @@ -0,0 +1,258 @@ +pub const BYTE_FREQUENCIES: [u8; 256] = [ + 55, // '\x00' + 52, // '\x01' + 51, // '\x02' + 50, // '\x03' + 49, // '\x04' + 48, // '\x05' + 47, // '\x06' + 46, // '\x07' + 45, // '\x08' + 103, // '\t' + 242, // '\n' + 66, // '\x0b' + 67, // '\x0c' + 229, // '\r' + 44, // '\x0e' + 43, // '\x0f' + 42, // '\x10' + 41, // '\x11' + 40, // '\x12' + 39, // '\x13' + 38, // '\x14' + 37, // '\x15' + 36, // '\x16' + 35, // '\x17' + 34, // '\x18' + 33, // '\x19' + 56, // '\x1a' + 32, // '\x1b' + 31, // '\x1c' + 30, // '\x1d' + 29, // '\x1e' + 28, // '\x1f' + 255, // ' ' + 148, // '!' + 164, // '"' + 149, // '#' + 136, // '$' + 160, // '%' + 155, // '&' + 173, // "'" + 221, // '(' + 222, // ')' + 134, // '*' + 122, // '+' + 232, // ',' + 202, // '-' + 215, // '.' + 224, // '/' + 208, // '0' + 220, // '1' + 204, // '2' + 187, // '3' + 183, // '4' + 179, // '5' + 177, // '6' + 168, // '7' + 178, // '8' + 200, // '9' + 226, // ':' + 195, // ';' + 154, // '<' + 184, // '=' + 174, // '>' + 126, // '?' + 120, // '@' + 191, // 'A' + 157, // 'B' + 194, // 'C' + 170, // 'D' + 189, // 'E' + 162, // 'F' + 161, // 'G' + 150, // 'H' + 193, // 'I' + 142, // 'J' + 137, // 'K' + 171, // 'L' + 176, // 'M' + 185, // 'N' + 167, // 'O' + 186, // 'P' + 112, // 'Q' + 175, // 'R' + 192, // 'S' + 188, // 'T' + 156, // 'U' + 140, // 'V' + 143, // 'W' + 123, // 'X' + 133, // 'Y' + 128, // 'Z' + 147, // '[' + 138, // '\\' + 146, // ']' + 114, // '^' + 223, // '_' + 151, // '`' + 249, // 'a' + 216, // 'b' + 238, // 'c' + 236, // 'd' + 253, // 'e' + 227, // 'f' + 218, // 'g' + 230, // 'h' + 247, // 'i' + 135, // 'j' + 180, // 'k' + 241, // 'l' + 233, // 'm' + 246, // 'n' + 244, // 'o' + 231, // 'p' + 139, // 'q' + 245, // 'r' + 243, // 's' + 251, // 't' + 235, // 'u' + 201, // 'v' + 196, // 'w' + 240, // 'x' + 214, // 'y' + 152, // 'z' + 182, // '{' + 205, // '|' + 181, // '}' + 127, // '~' + 27, // '\x7f' + 212, // '\x80' + 211, // '\x81' + 210, // '\x82' + 213, // '\x83' + 228, // '\x84' + 197, // '\x85' + 169, // '\x86' + 159, // '\x87' + 131, // '\x88' + 172, // '\x89' + 105, // '\x8a' + 80, // '\x8b' + 98, // '\x8c' + 96, // '\x8d' + 97, // '\x8e' + 81, // '\x8f' + 207, // '\x90' + 145, // '\x91' + 116, // '\x92' + 115, // '\x93' + 144, // '\x94' + 130, // '\x95' + 153, // '\x96' + 121, // '\x97' + 107, // '\x98' + 132, // '\x99' + 109, // '\x9a' + 110, // '\x9b' + 124, // '\x9c' + 111, // '\x9d' + 82, // '\x9e' + 108, // '\x9f' + 118, // '\xa0' + 141, // '¡' + 113, // '¢' + 129, // '£' + 119, // '¤' + 125, // '¥' + 165, // '¦' + 117, // '§' + 92, // '¨' + 106, // '©' + 83, // 'ª' + 72, // '«' + 99, // '¬' + 93, // '\xad' + 65, // '®' + 79, // '¯' + 166, // '°' + 237, // '±' + 163, // '²' + 199, // '³' + 190, // '´' + 225, // 'µ' + 209, // '¶' + 203, // '·' + 198, // '¸' + 217, // '¹' + 219, // 'º' + 206, // '»' + 234, // '¼' + 248, // '½' + 158, // '¾' + 239, // '¿' + 255, // 'À' + 255, // 'Á' + 255, // 'Â' + 255, // 'Ã' + 255, // 'Ä' + 255, // 'Å' + 255, // 'Æ' + 255, // 'Ç' + 255, // 'È' + 255, // 'É' + 255, // 'Ê' + 255, // 'Ë' + 255, // 'Ì' + 255, // 'Í' + 255, // 'Î' + 255, // 'Ï' + 255, // 'Ð' + 255, // 'Ñ' + 255, // 'Ò' + 255, // 'Ó' + 255, // 'Ô' + 255, // 'Õ' + 255, // 'Ö' + 255, // '×' + 255, // 'Ø' + 255, // 'Ù' + 255, // 'Ú' + 255, // 'Û' + 255, // 'Ü' + 255, // 'Ý' + 255, // 'Þ' + 255, // 'ß' + 255, // 'à' + 255, // 'á' + 255, // 'â' + 255, // 'ã' + 255, // 'ä' + 255, // 'å' + 255, // 'æ' + 255, // 'ç' + 255, // 'è' + 255, // 'é' + 255, // 'ê' + 255, // 'ë' + 255, // 'ì' + 255, // 'í' + 255, // 'î' + 255, // 'ï' + 255, // 'ð' + 255, // 'ñ' + 255, // 'ò' + 255, // 'ó' + 255, // 'ô' + 255, // 'õ' + 255, // 'ö' + 255, // '÷' + 255, // 'ø' + 255, // 'ù' + 255, // 'ú' + 255, // 'û' + 255, // 'ü' + 255, // 'ý' + 255, // 'þ' + 255, // 'ÿ' +]; diff --git a/bstr/src/search/mod.rs b/bstr/src/search/mod.rs new file mode 100644 index 000000000..a0d1b4561 --- /dev/null +++ b/bstr/src/search/mod.rs @@ -0,0 +1,8 @@ +pub use self::prefilter::PrefilterState; +pub use self::twoway::TwoWay; + +mod byte_frequencies; +mod prefilter; +#[cfg(test)] +mod tests; +mod twoway; diff --git a/bstr/src/search/prefilter.rs b/bstr/src/search/prefilter.rs new file mode 100644 index 000000000..43315422f --- /dev/null +++ b/bstr/src/search/prefilter.rs @@ -0,0 +1,424 @@ +use core::mem; + +use bstr::BStr; +use search::byte_frequencies::BYTE_FREQUENCIES; + +/// PrefilterState tracks state associated with the effectiveness of a +/// prefilter. It is used to track how many bytes, on average, are skipped by +/// the prefilter. If this average dips below a certain threshold over time, +/// then the state renders the prefilter inert and stops using it. +/// +/// A prefilter state should be created for each search. (Where creating an +/// iterator via, e.g., `find_iter`, is treated as a single search.) +#[derive(Clone, Debug)] +pub struct PrefilterState { + /// The number of skips that has been executed. + skips: usize, + /// The total number of bytes that have been skipped. + skipped: usize, + /// The maximum length of a match. This is used to help determine how many + /// bytes on average should be skipped in order for a prefilter to be + /// effective. + max_match_len: usize, + /// Once this heuristic has been deemed ineffective, it will be inert + /// throughout the rest of its lifetime. This serves as a cheap way to + /// check inertness. + inert: bool, +} + +impl PrefilterState { + /// The minimum number of skip attempts to try before considering whether + /// a prefilter is effective or not. + const MIN_SKIPS: usize = 50; + + /// The minimum amount of bytes that skipping must average. + /// + /// This value was chosen based on varying it and checking the bstr/find/ + /// microbenchmarks. In particular, this can impact the + /// pathological/repeated-{huge,small} benchmarks quite a bit if it's + /// set too low. + const MIN_SKIP_BYTES: usize = 8; + + /// Create a fresh prefilter state. + pub fn new(max_match_len: usize) -> PrefilterState { + if max_match_len == 0 { + return PrefilterState::inert(); + } + PrefilterState { skips: 0, skipped: 0, max_match_len, inert: false } + } + + /// Create a fresh prefilter state that is always inert. + fn inert() -> PrefilterState { + PrefilterState { skips: 0, skipped: 0, max_match_len: 0, inert: true } + } + + /// Update this state with the number of bytes skipped on the last + /// invocation of the prefilter. + #[inline] + pub fn update(&mut self, skipped: usize) { + self.skips += 1; + self.skipped += skipped; + } + + /// Return true if and only if this state indicates that a prefilter is + /// still effective. + #[inline] + pub fn is_effective(&mut self) -> bool { + if self.inert { + return false; + } + if self.skips < PrefilterState::MIN_SKIPS { + return true; + } + if self.skipped >= PrefilterState::MIN_SKIP_BYTES * self.skips { + return true; + } + + // We're inert. + self.inert = true; + false + } +} + +/// A heuristic frequency based prefilter for searching a single needle. +/// +/// This prefilter attempts to pick out the byte in a needle that is predicted +/// to occur least frequently, and search for that using fast vectorized +/// routines. If a rare enough byte could not be found, then this prefilter's +/// constructors will return `None`. +/// +/// This can be combined with `PrefilterState` to dynamically render this +/// prefilter inert if it proves to ineffective. +#[derive(Clone, Debug)] +pub struct Freqy { + /// Whether this prefilter should be used or not. + inert: bool, + /// The length of the needle we're searching for. + needle_len: usize, + /// The rarest byte in the needle, according to pre-computed frequency + /// analysis. + rare1: u8, + /// The leftmost offset of the rarest byte in the needle. + rare1i: usize, + /// The second rarest byte in the needle, according to pre-computed + /// frequency analysis. (This may be equivalent to the rarest byte.) + /// + /// The second rarest byte is used as a type of guard for quickly detecting + /// a mismatch after memchr locates an instance of the rarest byte. This + /// is a hedge against pathological cases where the pre-computed frequency + /// analysis may be off. (But of course, does not prevent *all* + /// pathological cases.) + rare2: u8, + /// The leftmost offset of the second rarest byte in the needle. + rare2i: usize, +} + +impl Freqy { + /// The maximum frequency rank permitted. If the rarest byte in the needle + /// has a frequency rank above this value, then Freqy is not used. + const MAX_RANK: usize = 200; + + /// Return a fresh prefilter state that can be used with this prefilter. A + /// prefilter state is used to track the effectiveness of a prefilter for + /// speeding up searches. Therefore, the prefilter state should generally + /// be reused on subsequent searches (such as in an iterator). For searches + /// on a different haystack, then a new prefilter state should be used. + pub fn prefilter_state(&self) -> PrefilterState { + if self.inert { + PrefilterState::inert() + } else { + PrefilterState::new(self.needle_len) + } + } + + /// Returns a valid but inert prefilter. This is valid for both the forward + /// and reverse direction. + /// + /// It is never correct to use an inert prefilter. The results of finding + /// the next (or previous) candidate are unspecified. + fn inert() -> Freqy { + Freqy { + inert: true, + needle_len: 0, + rare1: 0, + rare1i: 0, + rare2: 0, + rare2i: 0, + } + } + + /// Return search info for the given needle in the forward direction. + pub fn forward(needle: &BStr) -> Freqy { + if needle.is_empty() { + return Freqy::inert(); + } + + // Find the rarest two bytes. Try to make them distinct (but it's not + // required). + let (mut rare1, mut rare1i) = (needle[0], 0); + let (mut rare2, mut rare2i) = (needle[0], 0); + if needle.len() >= 2 { + rare2 = needle[1]; + rare2i = 1; + } + if Freqy::rank(rare2) < Freqy::rank(rare1) { + mem::swap(&mut rare1, &mut rare2); + mem::swap(&mut rare1i, &mut rare2i); + } + for (i, b) in needle.bytes().enumerate().skip(2) { + if Freqy::rank(b) < Freqy::rank(rare1) { + rare2 = rare1; + rare2i = rare1i; + rare1 = b; + rare1i = i; + } else if b != rare1 && Freqy::rank(b) < Freqy::rank(rare2) { + rare2 = b; + rare2i = i; + } + } + if Freqy::rank(rare1) > Freqy::MAX_RANK { + return Freqy::inert(); + } + let needle_len = needle.len(); + Freqy { inert: false, needle_len, rare1, rare1i, rare2, rare2i } + } + + /// Return search info for the given needle in the reverse direction. + pub fn reverse(needle: &BStr) -> Freqy { + if needle.is_empty() { + return Freqy::inert(); + } + + // Find the rarest two bytes. Try to make them distinct (but it's not + // required). In reverse, the offsets correspond to the number of bytes + // from the end of the needle. So `0` is the last byte in the needle. + let (mut rare1i, mut rare2i) = (0, 0); + if needle.len() >= 2 { + rare2i += 1; + } + let mut rare1 = needle[needle.len() - rare1i - 1]; + let mut rare2 = needle[needle.len() - rare2i - 1]; + if Freqy::rank(rare2) < Freqy::rank(rare1) { + mem::swap(&mut rare1, &mut rare2); + mem::swap(&mut rare1i, &mut rare2i); + } + for (i, b) in needle.bytes().rev().enumerate().skip(2) { + if Freqy::rank(b) < Freqy::rank(rare1) { + rare2 = rare1; + rare2i = rare1i; + rare1 = b; + rare1i = i; + } else if b != rare1 && Freqy::rank(b) < Freqy::rank(rare2) { + rare2 = b; + rare2i = i; + } + } + if Freqy::rank(rare1) > Freqy::MAX_RANK { + return Freqy::inert(); + } + let needle_len = needle.len(); + Freqy { inert: false, needle_len, rare1, rare1i, rare2, rare2i } + } + + /// Look for a possible occurrence of needle. The position returned + /// corresponds to the beginning of the occurrence, if one exists. + /// + /// Callers may assume that this never returns false negatives (i.e., it + /// never misses an actual occurrence), but must check that the returned + /// position corresponds to a match. That is, it can return false + /// positives. + /// + /// This should only be used when Freqy is constructed for forward + /// searching. + pub fn find_candidate( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + ) -> Option { + debug_assert!(!self.inert); + + let mut i = 0; + while prestate.is_effective() { + // Use a fast vectorized implementation to skip to the next + // occurrence of the rarest byte (heuristically chosen) in the + // needle. + i += match haystack[i..].find_byte(self.rare1) { + None => return None, + Some(found) => { + prestate.update(found); + found + } + }; + + // If we can't align our first match with the haystack, then a + // match is impossible. + if i < self.rare1i { + i += 1; + continue; + } + + // Align our rare2 byte with the haystack. A mismatch means that + // a match is impossible. + let aligned_rare2i = i - self.rare1i + self.rare2i; + if haystack.get(aligned_rare2i) != Some(&self.rare2) { + i += 1; + continue; + } + + // We've done what we can. There might be a match here. + return Some(i - self.rare1i); + } + // The only way we get here is if we believe our skipping heuristic + // has become ineffective. We're allowed to return false positives, + // so return the position at which we advanced to, aligned to the + // haystack. + Some(i.saturating_sub(self.rare1i)) + } + + /// Look for a possible occurrence of needle, in reverse, starting from the + /// end of the given haystack. The position returned corresponds to the + /// position immediately after the end of the occurrence, if one exists. + /// + /// Callers may assume that this never returns false negatives (i.e., it + /// never misses an actual occurrence), but must check that the returned + /// position corresponds to a match. That is, it can return false + /// positives. + /// + /// This should only be used when Freqy is constructed for reverse + /// searching. + pub fn rfind_candidate( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + ) -> Option { + debug_assert!(!self.inert); + + let mut i = haystack.len(); + while prestate.is_effective() { + // Use a fast vectorized implementation to skip to the next + // occurrence of the rarest byte (heuristically chosen) in the + // needle. + i = match haystack[..i].rfind_byte(self.rare1) { + None => return None, + Some(found) => { + prestate.update(i - found); + found + } + }; + + // If we can't align our first match with the haystack, then a + // match is impossible. + if i + self.rare1i + 1 > haystack.len() { + continue; + } + + // Align our rare2 byte with the haystack. A mismatch means that + // a match is impossible. + let aligned = match (i + self.rare1i).checked_sub(self.rare2i) { + None => continue, + Some(aligned) => aligned, + }; + if haystack.get(aligned) != Some(&self.rare2) { + continue; + } + + // We've done what we can. There might be a match here. + return Some(i + self.rare1i + 1); + } + // The only way we get here is if we believe our skipping heuristic + // has become ineffective. We're allowed to return false positives, + // so return the position at which we advanced to, aligned to the + // haystack. + Some(i + self.rare1i + 1) + } + + /// Return the heuristical frequency rank of the given byte. A lower rank + /// means the byte is believed to occur less frequently. + fn rank(b: u8) -> usize { + BYTE_FREQUENCIES[b as usize] as usize + } +} + +#[cfg(test)] +mod tests { + use bstr::B; + use super::*; + + #[test] + fn freqy_forward() { + // N.B. We sometimes use uppercase here since that mostly ensures freqy + // will be constructable. Lowercase letters may be too common for freqy + // to work. + + let s = Freqy::forward(B("BAR")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(0), s.find_candidate(&mut pre, B("BARFOO"))); + + let s = Freqy::forward(B("BAR")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(3), s.find_candidate(&mut pre, B("FOOBAR"))); + + let s = Freqy::forward(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(0), s.find_candidate(&mut pre, B("zyzz"))); + + let s = Freqy::forward(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(2), s.find_candidate(&mut pre, B("zzzy"))); + + let s = Freqy::forward(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(None, s.find_candidate(&mut pre, B("zazb"))); + + let s = Freqy::forward(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(0), s.find_candidate(&mut pre, B("yzyy"))); + + let s = Freqy::forward(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(2), s.find_candidate(&mut pre, B("yyyz"))); + + let s = Freqy::forward(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(None, s.find_candidate(&mut pre, B("yayb"))); + } + + #[test] + fn freqy_reverse() { + // N.B. We sometimes use uppercase here since that mostly ensures freqy + // will be constructable. Lowercase letters may be too common for freqy + // to work. + + let s = Freqy::reverse(B("BAR")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(3), s.rfind_candidate(&mut pre, B("BARFOO"))); + + let s = Freqy::reverse(B("BAR")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(6), s.rfind_candidate(&mut pre, B("FOOBAR"))); + + let s = Freqy::reverse(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(2), s.rfind_candidate(&mut pre, B("zyzz"))); + + let s = Freqy::reverse(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(4), s.rfind_candidate(&mut pre, B("zzzy"))); + + let s = Freqy::reverse(B("zyzy")); + let mut pre = s.prefilter_state(); + assert_eq!(None, s.rfind_candidate(&mut pre, B("zazb"))); + + let s = Freqy::reverse(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(2), s.rfind_candidate(&mut pre, B("yzyy"))); + + let s = Freqy::reverse(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(Some(4), s.rfind_candidate(&mut pre, B("yyyz"))); + + let s = Freqy::reverse(B("yzyz")); + let mut pre = s.prefilter_state(); + assert_eq!(None, s.rfind_candidate(&mut pre, B("yayb"))); + } +} diff --git a/bstr/src/search/tests.rs b/bstr/src/search/tests.rs new file mode 100644 index 000000000..aa7f6b268 --- /dev/null +++ b/bstr/src/search/tests.rs @@ -0,0 +1,223 @@ +use bstr::{B, BStr}; +use bstring::BString; +use search::twoway::TwoWay; + +/// Each test is a (needle, haystack, expected_fwd, expected_rev) tuple. +type SearchTest = (&'static str, &'static str, Option, Option); + +const SEARCH_TESTS: &'static [SearchTest] = &[ + ("", "", Some(0), Some(0)), + ("", "a", Some(0), Some(1)), + ("", "ab", Some(0), Some(2)), + ("", "abc", Some(0), Some(3)), + ("a", "", None, None), + ("a", "a", Some(0), Some(0)), + ("a", "aa", Some(0), Some(1)), + ("a", "ba", Some(1), Some(1)), + ("a", "bba", Some(2), Some(2)), + ("a", "bbba", Some(3), Some(3)), + ("a", "bbbab", Some(3), Some(3)), + ("a", "bbbabb", Some(3), Some(3)), + ("a", "bbbabbb", Some(3), Some(3)), + ("a", "bbbbbb", None, None), + ("ab", "", None, None), + ("ab", "a", None, None), + ("ab", "b", None, None), + ("ab", "ab", Some(0), Some(0)), + ("ab", "aab", Some(1), Some(1)), + ("ab", "aaab", Some(2), Some(2)), + ("ab", "abaab", Some(0), Some(3)), + ("ab", "baaab", Some(3), Some(3)), + ("ab", "acb", None, None), + ("ab", "abba", Some(0), Some(0)), + ("abc", "ab", None, None), + ("abc", "abc", Some(0), Some(0)), + ("abc", "abcz", Some(0), Some(0)), + ("abc", "abczz", Some(0), Some(0)), + ("abc", "zabc", Some(1), Some(1)), + ("abc", "zzabc", Some(2), Some(2)), + ("abc", "azbc", None, None), + ("abc", "abzc", None, None), + + ("abczdef", "abczdefzzzzzzzzzzzzzzzzzzzz", Some(0), Some(0)), + ("abczdef", "zzzzzzzzzzzzzzzzzzzzabczdef", Some(20), Some(20)), + + // Failures caught by quickcheck. + ("\u{0}\u{15}", "\u{0}\u{15}\u{15}\u{0}", Some(0), Some(0)), + ("\u{0}\u{1e}", "\u{1e}\u{0}", None, None), +]; + +#[test] +fn unit_twoway_fwd() { + run_search_tests_fwd("TwoWay", |n, h| TwoWay::forward(n).find(h)); +} + +#[test] +fn unit_twoway_rev() { + run_search_tests_rev("TwoWay", |n, h| TwoWay::reverse(n).rfind(h)); +} + +/// Run the substring search tests. `name` should be the type of searcher used, +/// for diagnostics. `search` should be a closure that accepts a needle and a +/// haystack and returns the starting position of the first occurrence of +/// needle in the haystack, or `None` if one doesn't exist. +fn run_search_tests_fwd( + name: &str, + mut search: impl FnMut(&BStr, &BStr) -> Option, +) { + for &(needle, haystack, expected_fwd, _) in SEARCH_TESTS { + let (n, h) = (B(needle), B(haystack)); + assert_eq!( + expected_fwd, + search(n, h), + "{}: needle: {:?}, haystack: {:?}, expected: {:?}", + name, n, h, expected_fwd + ); + } +} + +/// Run the substring search tests. `name` should be the type of searcher used, +/// for diagnostics. `search` should be a closure that accepts a needle and a +/// haystack and returns the starting position of the last occurrence of +/// needle in the haystack, or `None` if one doesn't exist. +fn run_search_tests_rev( + name: &str, + mut search: impl FnMut(&BStr, &BStr) -> Option, +) { + for &(needle, haystack, _, expected_rev) in SEARCH_TESTS { + let (n, h) = (B(needle), B(haystack)); + assert_eq!( + expected_rev, + search(n, h), + "{}: needle: {:?}, haystack: {:?}, expected: {:?}", + name, n, h, expected_rev + ); + } +} + +quickcheck! { + fn qc_twoway_fwd_prefix_is_substring(bs: BString) -> bool { + prop_prefix_is_substring(false, &bs, |n, h| TwoWay::forward(n).find(h)) + } + + fn qc_twoway_fwd_suffix_is_substring(bs: BString) -> bool { + prop_suffix_is_substring(false, &bs, |n, h| TwoWay::forward(n).find(h)) + } + + fn qc_twoway_rev_prefix_is_substring(bs: BString) -> bool { + prop_prefix_is_substring(true, &bs, |n, h| TwoWay::reverse(n).rfind(h)) + } + + fn qc_twoway_rev_suffix_is_substring(bs: BString) -> bool { + prop_suffix_is_substring(true, &bs, |n, h| TwoWay::reverse(n).rfind(h)) + } + + fn qc_twoway_fwd_matches_naive( + needle: BString, + haystack: BString + ) -> bool { + prop_matches_naive( + false, + &needle, + &haystack, + |n, h| TwoWay::forward(n).find(h), + ) + } + + fn qc_twoway_rev_matches_naive( + needle: BString, + haystack: BString + ) -> bool { + prop_matches_naive( + true, + &needle, + &haystack, + |n, h| TwoWay::reverse(n).rfind(h), + ) + } +} + +/// Check that every prefix of the given byte string is a substring. +fn prop_prefix_is_substring( + reverse: bool, + bs: &BStr, + mut search: impl FnMut(&BStr, &BStr) -> Option, +) -> bool { + if bs.is_empty() { + return true; + } + for i in 0..(bs.len() - 1) { + let prefix = &bs[..i]; + if reverse { + assert_eq!(naive_rfind(prefix, bs), search(prefix, bs)); + } else { + assert_eq!(naive_find(prefix, bs), search(prefix, bs)); + } + } + true +} + +/// Check that every suffix of the given byte string is a substring. +fn prop_suffix_is_substring( + reverse: bool, + bs: &BStr, + mut search: impl FnMut(&BStr, &BStr) -> Option, +) -> bool { + if bs.is_empty() { + return true; + } + for i in 0..(bs.len() - 1) { + let suffix = &bs[i..]; + if reverse { + assert_eq!(naive_rfind(suffix, bs), search(suffix, bs)); + } else { + assert_eq!(naive_find(suffix, bs), search(suffix, bs)); + } + } + true +} + +/// Check that naive substring search matches the result of the given search +/// algorithm. +fn prop_matches_naive( + reverse: bool, + needle: &BStr, + haystack: &BStr, + mut search: impl FnMut(&BStr, &BStr) -> Option, +) -> bool { + if reverse { + naive_rfind(needle, haystack) == search(needle, haystack) + } else { + naive_find(needle, haystack) == search(needle, haystack) + } +} + +/// Naively search forwards for the given needle in the given haystack. +fn naive_find(needle: &BStr, haystack: &BStr) -> Option { + if needle.is_empty() { + return Some(0); + } else if haystack.len() < needle.len() { + return None; + } + for i in 0..(haystack.len() - needle.len() + 1) { + if needle == &haystack[i..i + needle.len()] { + return Some(i); + } + } + None +} + +/// Naively search in reverse for the given needle in the given haystack. +fn naive_rfind(needle: &BStr, haystack: &BStr) -> Option { + if needle.is_empty() { + return Some(haystack.len()); + } else if haystack.len() < needle.len() { + return None; + } + for i in (0..(haystack.len() - needle.len() + 1)).rev() { + if needle == &haystack[i..i + needle.len()] { + return Some(i); + } + } + None +} diff --git a/bstr/src/search/twoway.rs b/bstr/src/search/twoway.rs new file mode 100644 index 000000000..b3b45e3b9 --- /dev/null +++ b/bstr/src/search/twoway.rs @@ -0,0 +1,883 @@ +use core::cmp; + +use bstr::BStr; +use cow::CowBStr; +use search::prefilter::{Freqy, PrefilterState}; + +/// An implementation of the TwoWay substring search algorithm, with heuristics +/// for accelerating search based on frequency analysis. +/// +/// This searcher supports forward and reverse search, although not +/// simultaneously. It runs in O(n + m) time and O(1) space, where +/// `n ~ len(needle)` and `m ~ len(haystack)`. +/// +/// The implementation here roughly matches that which was developed by +/// Crochemore and Perrin in their 1991 paper "Two-way string-matching." The +/// only change in this implementation is the use of zero-based indices and +/// the addition of heuristics for a fast skip loop. That is, this will detect +/// bytes that are believed to be rare in the needle and use fast vectorized +/// instructions to find their occurrences quickly. The Two-Way algorithm is +/// then used to confirm whether a match at that location occurred. +/// +/// The heuristic for fast skipping is automatically shut off if it's +/// detected to be ineffective at search time. Generally, this only occurs in +/// pathological cases. But this is generally necessary in order to preserve +/// a `O(n + m)` time bound. +/// +/// The code below is fairly complex and not obviously correct at all. It's +/// likely necessary to read the Two-Way paper cited above in order to fully +/// grok this code. +#[derive(Clone, Debug)] +pub struct TwoWay<'b> { + /// The needle that we're looking for. + needle: CowBStr<'b>, + /// An implementation of a fast skip loop based on hard-coded frequency + /// data. This is only used when conditions are deemed favorable. + freqy: Freqy, + /// A critical position in needle. Specifically, this position corresponds + /// to beginning of either the minimal or maximal suffix in needle. (N.B. + /// See SuffixType below for why "minimal" isn't quite the correct word + /// here.) + /// + /// This is the position at which every search begins. Namely, search + /// starts by scanning text to the right of this position, and only if + /// there's a match does the text to the left of this position get scanned. + critical_pos: usize, + /// The amount we shift by in the Two-Way search algorithm. This + /// corresponds to the "small period" and "large period" cases. + shift: Shift, +} + +impl<'b> TwoWay<'b> { + /// Create a searcher that uses the Two-Way algorithm by searching forwards + /// through any haystack. + pub fn forward(needle: &'b BStr) -> TwoWay<'b> { + let freqy = Freqy::forward(needle); + if needle.is_empty() { + return TwoWay { + needle: CowBStr::new(needle), + freqy, + critical_pos: 0, + shift: Shift::Large { shift: 0 }, + }; + } + + let min_suffix = Suffix::forward(needle, SuffixKind::Minimal); + let max_suffix = Suffix::forward(needle, SuffixKind::Maximal); + let (period_lower_bound, critical_pos) = + if min_suffix.pos > max_suffix.pos { + (min_suffix.period, min_suffix.pos) + } else { + (max_suffix.period, max_suffix.pos) + }; + let shift = Shift::forward(needle, period_lower_bound, critical_pos); + let needle = CowBStr::new(needle); + TwoWay { needle, freqy, critical_pos, shift } + } + + /// Create a searcher that uses the Two-Way algorithm by searching in + /// reverse through any haystack. + pub fn reverse(needle: &'b BStr) -> TwoWay<'b> { + let freqy = Freqy::reverse(needle); + if needle.is_empty() { + return TwoWay { + needle: CowBStr::new(needle), + freqy, + critical_pos: 0, + shift: Shift::Large { shift: 0 }, + }; + } + + let min_suffix = Suffix::reverse(needle, SuffixKind::Minimal); + let max_suffix = Suffix::reverse(needle, SuffixKind::Maximal); + let (period_lower_bound, critical_pos) = + if min_suffix.pos < max_suffix.pos { + (min_suffix.period, min_suffix.pos) + } else { + (max_suffix.period, max_suffix.pos) + }; + let shift = Shift::reverse(needle, period_lower_bound, critical_pos); + let needle = CowBStr::new(needle); + TwoWay { needle, freqy, critical_pos, shift } + } + + /// Return a fresh prefilter state that can be used with this searcher. + /// A prefilter state is used to track the effectiveness of a searcher's + /// prefilter for speeding up searches. Therefore, the prefilter state + /// should generally be reused on subsequent searches (such as in an + /// iterator). For searches on a different haystack, then a new prefilter + /// state should be used. + /// + /// This always initializes a valid prefilter state even if this searcher + /// does not have a prefilter enabled. + pub fn prefilter_state(&self) -> PrefilterState { + self.freqy.prefilter_state() + } + + /// Return the needle used by this searcher. + pub fn needle(&self) -> &BStr { + self.needle.as_bstr() + } + + /// Convert this searched into an owned version, where the needle is + /// copied if it isn't already owned. + #[cfg(feature = "std")] + pub fn into_owned(self) -> TwoWay<'static> { + TwoWay { + needle: self.needle.into_owned(), + freqy: self.freqy, + critical_pos: self.critical_pos, + shift: self.shift, + } + } + + /// Find the position of the first occurrence of this searcher's needle in + /// the given haystack. If one does not exist, then return None. + /// + /// This will automatically initialize prefilter state. This should only + /// be used for one-off searches. + pub fn find(&self, haystack: &BStr) -> Option { + self.find_with(&mut self.prefilter_state(), haystack) + } + + /// Find the position of the last occurrence of this searcher's needle + /// in the given haystack. If one does not exist, then return None. + /// + /// This will automatically initialize prefilter state. This should only + /// be used for one-off searches. + pub fn rfind(&self, haystack: &BStr) -> Option { + self.rfind_with(&mut self.prefilter_state(), haystack) + } + + /// Find the position of the first occurrence of this searcher's needle in + /// the given haystack. If one does not exist, then return None. + /// + /// This accepts prefilter state that is useful when using the same + /// searcher multiple times, such as in an iterator. + pub fn find_with( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + ) -> Option { + if self.needle.is_empty() { + return Some(0); + } else if haystack.len() < self.needle.len() { + return None; + } else if self.needle.len() == 1 { + return haystack.find_byte(self.needle[0]); + } + match self.shift { + Shift::Small { period } => { + self.find_small(prestate, haystack, period) + } + Shift::Large { shift } => { + self.find_large(prestate, haystack, shift) + } + } + } + + /// Find the position of the last occurrence of this searcher's needle + /// in the given haystack. If one does not exist, then return None. + /// + /// This accepts prefilter state that is useful when using the same + /// searcher multiple times, such as in an iterator. + pub fn rfind_with( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + ) -> Option { + if self.needle.is_empty() { + return Some(haystack.len()); + } else if haystack.len() < self.needle.len() { + return None; + } else if self.needle.len() == 1 { + return haystack.rfind_byte(self.needle[0]); + } + match self.shift { + Shift::Small { period } => { + self.rfind_small(prestate, haystack, period) + } + Shift::Large { shift } => { + self.rfind_large(prestate, haystack, shift) + } + } + } + + // Below is the actual implementation of TwoWay searching, including both + // forwards and backwards searching. Each forward and reverse search has + // two fairly similar implementations, each handling the small and large + // period cases, for a total 4 different search routines. + // + // On top of that, each search implementation can be accelerated by a + // Freqy prefilter, but it is not always enabled. To avoid its overhead + // when its disabled, we explicitly inline each search implementation based + // on whether Freqy will be used or not. This brings us up to a total of + // 8 monomorphized versions of the search code. + + #[inline(never)] + fn find_small( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + period: usize, + ) -> Option { + if prestate.is_effective() { + self.find_small_imp(prestate, true, haystack, period) + } else { + self.find_small_imp(prestate, false, haystack, period) + } + } + + #[inline(always)] + fn find_small_imp( + &self, + prestate: &mut PrefilterState, + prefilter: bool, + haystack: &BStr, + period: usize, + ) -> Option { + let needle = self.needle.as_bstr(); + let mut pos = 0; + let mut shift = 0; + while pos + needle.len() <= haystack.len() { + let mut i = cmp::max(self.critical_pos, shift); + if prefilter && prestate.is_effective() { + match self.freqy.find_candidate(prestate, &haystack[pos..]) { + None => return None, + Some(found) => { + shift = 0; + i = self.critical_pos; + pos += found; + if pos + needle.len() > haystack.len() { + return None; + } + } + } + } + while i < needle.len() && needle[i] == haystack[pos + i] { + i += 1; + } + if i < needle.len() { + pos += i - self.critical_pos + 1; + shift = 0; + } else { + let mut j = self.critical_pos; + while j > shift && needle[j] == haystack[pos + j] { + j -= 1; + } + if j <= shift && needle[shift] == haystack[pos + shift] { + return Some(pos); + } + pos += period; + shift = needle.len() - period; + } + } + None + } + + #[inline(never)] + fn find_large( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + shift: usize, + ) -> Option { + if prestate.is_effective() { + self.find_large_imp(prestate, true, haystack, shift) + } else { + self.find_large_imp(prestate, false, haystack, shift) + } + } + + #[inline(always)] + fn find_large_imp( + &self, + prestate: &mut PrefilterState, + prefilter: bool, + haystack: &BStr, + shift: usize, + ) -> Option { + let needle = self.needle.as_bstr(); + let mut pos = 0; + while pos + needle.len() <= haystack.len() { + let mut i = self.critical_pos; + if prefilter && prestate.is_effective() { + match self.freqy.find_candidate(prestate, &haystack[pos..]) { + None => return None, + Some(found) => { + pos += found; + if pos + needle.len() > haystack.len() { + return None; + } + } + } + } + while i < needle.len() && needle[i] == haystack[pos + i] { + i += 1; + } + if i < needle.len() { + pos += i - self.critical_pos + 1; + } else { + let mut j = self.critical_pos; + while j > 0 && needle[j] == haystack[pos + j] { + j -= 1; + } + if j == 0 && needle[0] == haystack[pos] { + return Some(pos); + } + pos += shift; + } + } + None + } + + #[inline(never)] + fn rfind_small( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + period: usize, + ) -> Option { + if prestate.is_effective() { + self.rfind_small_imp(prestate, true, haystack, period) + } else { + self.rfind_small_imp(prestate, false, haystack, period) + } + } + + #[inline(always)] + fn rfind_small_imp( + &self, + prestate: &mut PrefilterState, + prefilter: bool, + haystack: &BStr, + period: usize, + ) -> Option { + let needle = &*self.needle; + let nlen = needle.len(); + let mut pos = haystack.len(); + let mut shift = nlen; + while pos >= nlen { + let mut i = cmp::min(self.critical_pos, shift); + if prefilter && prestate.is_effective() { + match self.freqy.rfind_candidate(prestate, &haystack[..pos]) { + None => return None, + Some(found) => { + shift = nlen; + i = self.critical_pos; + pos = found; + if pos < nlen { + return None; + } + } + } + } + while i > 0 && needle[i - 1] == haystack[pos - nlen + i - 1] { + i -= 1; + } + if i > 0 || needle[0] != haystack[pos - nlen] { + pos -= self.critical_pos - i + 1; + shift = nlen; + } else { + let mut j = self.critical_pos; + while j < shift && needle[j] == haystack[pos - nlen + j] { + j += 1; + } + if j == shift { + return Some(pos - nlen); + } + pos -= period; + shift = period; + } + } + None + } + + #[inline(never)] + fn rfind_large( + &self, + prestate: &mut PrefilterState, + haystack: &BStr, + shift: usize, + ) -> Option { + if prestate.is_effective() { + self.rfind_large_imp(prestate, true, haystack, shift) + } else { + self.rfind_large_imp(prestate, false, haystack, shift) + } + } + + #[inline(always)] + fn rfind_large_imp( + &self, + prestate: &mut PrefilterState, + prefilter: bool, + haystack: &BStr, + shift: usize, + ) -> Option { + let needle = &*self.needle; + let nlen = needle.len(); + let mut pos = haystack.len(); + while pos >= nlen { + if prefilter && prestate.is_effective() { + match self.freqy.rfind_candidate(prestate, &haystack[..pos]) { + None => return None, + Some(found) => { + pos = found; + if pos < nlen { + return None; + } + } + } + } + + let mut i = self.critical_pos; + while i > 0 && needle[i - 1] == haystack[pos - nlen + i - 1] { + i -= 1; + } + if i > 0 || needle[0] != haystack[pos - nlen] { + pos -= self.critical_pos - i + 1; + } else { + let mut j = self.critical_pos; + while j < nlen && needle[j] == haystack[pos - nlen + j] { + j += 1; + } + if j == nlen { + return Some(pos - nlen); + } + pos -= shift; + } + } + None + } +} + +/// A representation of the amount we're allowed to shift by during Two-Way +/// search. +/// +/// When computing a critical factorization of the needle, we find the position +/// of the critical factorization by finding the needle's maximal (or minimal) +/// suffix, along with the period of that suffix. It turns out that the period +/// of that suffix is a lower bound on the period of the needle itself. +/// +/// This lower bound is equivalent to the actual period of the needle in +/// some cases. To describe that case, we denote the needle as `x` where +/// `x = uv` and `v` is the lexicographic maximal suffix of `v`. The lower +/// bound given here is always the period of `v`, which is `<= period(x)`. The +/// case where `period(v) == period(x)` occurs when `len(u) < (len(x) / 2)` and +/// where `u` is a suffix of `v[0..period(v)]`. +/// +/// This case is important because the search algorithm for when the +/// periods are equivalent is slightly different than the search algorithm +/// for when the periods are not equivalent. In particular, when they aren't +/// equivalent, we know that the period of the needle is no less than half its +/// length. In this case, we shift by an amount less than or equal to the +/// period of the needle (determined by the maximum length of the components +/// of the critical factorization of `x`, i.e., `max(len(u), len(v))`).. +/// +/// The above two cases are represented by the variants below. Each entails +/// a different instantiation of the Two-Way search algorithm. +/// +/// N.B. If we could find a way to compute the exact period in all cases, +/// then we could collapse this case analysis and simplify the algorithm. The +/// Two-Way paper suggests this is possible, but more reading is required to +/// grok why the authors didn't pursue that path. +#[derive(Clone, Debug)] +enum Shift { + Small { period: usize }, + Large { shift: usize }, +} + +impl Shift { + /// Compute the shift for a given needle in the forward direction. + /// + /// This requires a lower bound on the period and a critical position. + /// These can be computed by extracting both the minimal and maximal + /// lexicographic suffixes, and choosing the right-most starting position. + /// The lower bound on the period is then the period of the chosen suffix. + fn forward( + needle: &BStr, + period_lower_bound: usize, + critical_pos: usize, + ) -> Shift { + let large = cmp::max(critical_pos, needle.len() - critical_pos); + if critical_pos * 2 >= needle.len() { + return Shift::Large { shift: large }; + } + + let (u, v) = needle.split_at(critical_pos); + if !v[..period_lower_bound].ends_with(u) { + return Shift::Large { shift: large }; + } + Shift::Small { period: period_lower_bound } + } + + /// Compute the shift for a given needle in the reverse direction. + /// + /// This requires a lower bound on the period and a critical position. + /// These can be computed by extracting both the minimal and maximal + /// lexicographic suffixes, and choosing the left-most starting position. + /// The lower bound on the period is then the period of the chosen suffix. + fn reverse( + needle: &BStr, + period_lower_bound: usize, + critical_pos: usize, + ) -> Shift { + let large = cmp::max(critical_pos, needle.len() - critical_pos); + if (needle.len() - critical_pos) * 2 >= needle.len() { + return Shift::Large { shift: large }; + } + + let (v, u) = needle.split_at(critical_pos); + if !v[v.len() - period_lower_bound..].starts_with(u) { + return Shift::Large { shift: large }; + } + Shift::Small { period: period_lower_bound } + } +} + +/// A suffix extracted from a needle along with its period. +#[derive(Debug)] +struct Suffix { + /// The starting position of this suffix. + /// + /// If this is a forward suffix, then `&bytes[pos..]` can be used. If this + /// is a reverse suffix, then `&bytes[..pos]` can be used. That is, for + /// forward suffixes, this is an inclusive starting position, where as for + /// reverse suffixes, this is an exclusive ending position. + pos: usize, + /// The period of this suffix. + /// + /// Note that this is NOT necessarily the period of the string from which + /// this suffix comes from. (It is always less than or equal to the period + /// of the original string.) + period: usize, +} + +impl Suffix { + fn forward(needle: &BStr, kind: SuffixKind) -> Suffix { + debug_assert!(!needle.is_empty()); + + // suffix represents our maximal (or minimal) suffix, along with + // its period. + let mut suffix = Suffix { pos: 0, period: 1 }; + // The start of a suffix in `needle` that we are considering as a + // more maximal (or minimal) suffix than what's in `suffix`. + let mut candidate_start = 1; + // The current offset of our suffixes that we're comparing. + // + // When the characters at this offset are the same, then we mush on + // to the next position since no decision is possible. When the + // candidate's character is greater (or lesser) than the corresponding + // character than our current maximal (or minimal) suffix, then the + // current suffix is changed over to the candidate and we restart our + // search. Otherwise, the candidate suffix is no good and we restart + // our search on the next candidate. + // + // The three cases above correspond to the three cases in the loop + // below. + let mut offset = 0; + + while candidate_start + offset < needle.len() { + let current = needle[suffix.pos + offset]; + let candidate = needle[candidate_start + offset]; + match kind.cmp(current, candidate) { + SuffixOrdering::Accept => { + suffix = Suffix { pos: candidate_start, period: 1 }; + candidate_start += 1; + offset = 0; + } + SuffixOrdering::Skip => { + candidate_start += offset + 1; + offset = 0; + suffix.period = candidate_start - suffix.pos; + } + SuffixOrdering::Push => { + if offset + 1 == suffix.period { + candidate_start += suffix.period; + offset = 0; + } else { + offset += 1; + } + } + } + } + suffix + } + + fn reverse(needle: &BStr, kind: SuffixKind) -> Suffix { + debug_assert!(!needle.is_empty()); + + // See the comments in `forward` for how this works. + let mut suffix = Suffix { pos: needle.len(), period: 1 }; + if needle.len() == 1 { + return suffix; + } + let mut candidate_start = needle.len() - 1; + let mut offset = 0; + + while offset < candidate_start { + let current = needle[suffix.pos - offset - 1]; + let candidate = needle[candidate_start - offset - 1]; + match kind.cmp(current, candidate) { + SuffixOrdering::Accept => { + suffix = Suffix { pos: candidate_start, period: 1 }; + candidate_start -= 1; + offset = 0; + } + SuffixOrdering::Skip => { + candidate_start -= offset + 1; + offset = 0; + suffix.period = suffix.pos - candidate_start; + } + SuffixOrdering::Push => { + if offset + 1 == suffix.period { + candidate_start -= suffix.period; + offset = 0; + } else { + offset += 1; + } + } + } + } + suffix + } +} + +/// The kind of suffix to extract. +#[derive(Clone, Copy, Debug)] +enum SuffixKind { + /// Extract the smallest lexicographic suffix from a string. + /// + /// Technically, this doesn't actually pick the smallest lexicographic + /// suffix. e.g., Given the choice between `a` and `aa`, this will choose + /// the latter over the former, even though `a < aa`. The reasoning for + /// this isn't clear from the paper, but it still smells like a minimal + /// suffix. + Minimal, + /// Extract the largest lexicographic suffix from a string. + /// + /// Unlike `Minimal`, this really does pick the maximum suffix. e.g., Given + /// the choice between `z` and `zz`, this will choose the latter over the + /// former. + Maximal, +} + +/// The result of comparing corresponding bytes between two suffixes. +#[derive(Clone, Copy, Debug)] +enum SuffixOrdering { + /// This occurs when the given candidate byte indicates that the candidate + /// suffix is better than the current maximal (or minimal) suffix. That is, + /// the current candidate suffix should supplant the current maximal (or + /// minimal) suffix. + Accept, + /// This occurs when the given candidate byte excludes the candidate suffix + /// from being better than the current maximal (or minimal) suffix. That + /// is, the current candidate suffix should be dropped and the next one + /// should be considered. + Skip, + /// This occurs when no decision to accept or skip the candidate suffix + /// can be made, e.g., when corresponding bytes are equivalent. In this + /// case, the next corresponding bytes should be compared. + Push, +} + +impl SuffixKind { + /// Returns true if and only if the given candidate byte indicates that + /// it should replace the current suffix as the maximal (or minimal) + /// suffix. + fn cmp(self, current: u8, candidate: u8) -> SuffixOrdering { + use self::SuffixOrdering::*; + + match self { + SuffixKind::Minimal if candidate < current => Accept, + SuffixKind::Minimal if candidate > current => Skip, + SuffixKind::Minimal => Push, + SuffixKind::Maximal if candidate > current => Accept, + SuffixKind::Maximal if candidate < current => Skip, + SuffixKind::Maximal => Push, + } + } +} + +// N.B. There are more holistic tests in src/search/tests.rs. +#[cfg(test)] +mod tests { + use bstr::{B, BStr}; + use bstring::BString; + + use super::*; + + /// Convenience wrapper for computing the suffix as a byte string. + fn get_suffix_forward(needle: &BStr, kind: SuffixKind) -> (&BStr, usize) { + let s = Suffix::forward(needle, kind); + (&needle[s.pos..], s.period) + } + + /// Convenience wrapper for computing the reverse suffix as a byte string. + fn get_suffix_reverse(needle: &BStr, kind: SuffixKind) -> (&BStr, usize) { + let s = Suffix::reverse(needle, kind); + (&needle[..s.pos], s.period) + } + + /// Return all of the non-empty suffixes in the given byte string. + fn suffixes(bytes: &BStr) -> Vec<&BStr> { + (0..bytes.len()).map(|i| &bytes[i..]).collect() + } + + /// Return the lexicographically maximal suffix of the given byte string. + fn naive_maximal_suffix_forward(needle: &BStr) -> &BStr { + let mut sufs = suffixes(needle); + sufs.sort(); + sufs.pop().unwrap() + } + + /// Return the lexicographically maximal suffix of the reverse of the given + /// byte string. + fn naive_maximal_suffix_reverse(needle: &BStr) -> BString { + let mut reversed = needle.to_bstring(); + reversed.reverse_bytes(); + let mut got = naive_maximal_suffix_forward(&reversed).to_bstring(); + got.reverse_bytes(); + got + } + + #[test] + fn suffix_forward() { + macro_rules! assert_suffix_min { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = get_suffix_forward( + B($given), + SuffixKind::Minimal, + ); + assert_eq!((B($expected), $period), (got_suffix, got_period)); + }; + } + + macro_rules! assert_suffix_max { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = get_suffix_forward( + B($given), + SuffixKind::Maximal, + ); + assert_eq!((B($expected), $period), (got_suffix, got_period)); + }; + } + + assert_suffix_min!("a", "a", 1); + assert_suffix_max!("a", "a", 1); + + assert_suffix_min!("ab", "ab", 2); + assert_suffix_max!("ab", "b", 1); + + assert_suffix_min!("ba", "a", 1); + assert_suffix_max!("ba", "ba", 2); + + assert_suffix_min!("abc", "abc", 3); + assert_suffix_max!("abc", "c", 1); + + assert_suffix_min!("acb", "acb", 3); + assert_suffix_max!("acb", "cb", 2); + + assert_suffix_min!("cba", "a", 1); + assert_suffix_max!("cba", "cba", 3); + + assert_suffix_min!("abcabc", "abcabc", 3); + assert_suffix_max!("abcabc", "cabc", 3); + + assert_suffix_min!("abcabcabc", "abcabcabc", 3); + assert_suffix_max!("abcabcabc", "cabcabc", 3); + + assert_suffix_min!("abczz", "abczz", 5); + assert_suffix_max!("abczz", "zz", 1); + + assert_suffix_min!("zzabc", "abc", 3); + assert_suffix_max!("zzabc", "zzabc", 5); + + assert_suffix_min!("aaa", "aaa", 1); + assert_suffix_max!("aaa", "aaa", 1); + + assert_suffix_min!("foobar", "ar", 2); + assert_suffix_max!("foobar", "r", 1); + } + + #[test] + fn suffix_reverse() { + macro_rules! assert_suffix_min { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = get_suffix_reverse( + B($given), + SuffixKind::Minimal, + ); + assert_eq!((B($expected), $period), (got_suffix, got_period)); + }; + } + + macro_rules! assert_suffix_max { + ($given:expr, $expected:expr, $period:expr) => { + let (got_suffix, got_period) = get_suffix_reverse( + B($given), + SuffixKind::Maximal, + ); + assert_eq!((B($expected), $period), (got_suffix, got_period)); + }; + } + + assert_suffix_min!("a", "a", 1); + assert_suffix_max!("a", "a", 1); + + assert_suffix_min!("ab", "a", 1); + assert_suffix_max!("ab", "ab", 2); + + assert_suffix_min!("ba", "ba", 2); + assert_suffix_max!("ba", "b", 1); + + assert_suffix_min!("abc", "a", 1); + assert_suffix_max!("abc", "abc", 3); + + assert_suffix_min!("acb", "a", 1); + assert_suffix_max!("acb", "ac", 2); + + assert_suffix_min!("cba", "cba", 3); + assert_suffix_max!("cba", "c", 1); + + assert_suffix_min!("abcabc", "abca", 3); + assert_suffix_max!("abcabc", "abcabc", 3); + + assert_suffix_min!("abcabcabc", "abcabca", 3); + assert_suffix_max!("abcabcabc", "abcabcabc", 3); + + assert_suffix_min!("abczz", "a", 1); + assert_suffix_max!("abczz", "abczz", 5); + + assert_suffix_min!("zzabc", "zza", 3); + assert_suffix_max!("zzabc", "zz", 1); + + assert_suffix_min!("aaa", "aaa", 1); + assert_suffix_max!("aaa", "aaa", 1); + } + + quickcheck! { + fn qc_suffix_forward_maximal(bytes: Vec) -> bool { + let bytes = BString::from(bytes); + if bytes.is_empty() { + return true; + } + + let (got, _) = get_suffix_forward(&bytes, SuffixKind::Maximal); + let expected = naive_maximal_suffix_forward(&bytes); + got == expected + } + + fn qc_suffix_reverse_maximal(bytes: Vec) -> bool { + let bytes = BString::from(bytes); + if bytes.is_empty() { + return true; + } + + let (got, _) = get_suffix_reverse(&bytes, SuffixKind::Maximal); + let expected = naive_maximal_suffix_reverse(&bytes); + got == expected + } + } +} diff --git a/bstr/src/slice_index.rs b/bstr/src/slice_index.rs new file mode 100644 index 000000000..300ff60b8 --- /dev/null +++ b/bstr/src/slice_index.rs @@ -0,0 +1,292 @@ +use core::ops; + +use bstr::BStr; + +/// Ensure that callers cannot implement `SliceIndex` by making an +/// umplementable trait its super trait. +pub trait Sealed {} +impl Sealed for usize {} +impl Sealed for ops::Range {} +impl Sealed for ops::RangeTo {} +impl Sealed for ops::RangeFrom {} +impl Sealed for ops::RangeFull {} +impl Sealed for ops::RangeInclusive {} +impl Sealed for ops::RangeToInclusive {} + +/// A trait that parameterizes the different types of indexing a byte string. +/// +/// In general, this trait makes it possible to define generic routines like +/// `get` that can accept either single positions or ranges, and return single +/// bytes or slices, respectively. +/// +/// This trait is sealed such that callers cannot implement it. In general, +/// callers should not need to interact with this trait directly unless you're +/// defining generic functions that index or slice a byte string. +pub trait SliceIndex: Sealed { + /// The output type returned by methods. For indexing by position, this + /// is always a single byte (`u8`). For ranges, this is always a slice + /// (`BStr`). + type Output: ?Sized; + + /// Returns a shared reference to the output at this location, if in + /// bounds. + fn get(self, slice: &BStr) -> Option<&Self::Output>; + + /// Returns a mutable reference to the output at this location, if in + /// bounds. + fn get_mut(self, slice: &mut BStr) -> Option<&mut Self::Output>; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + unsafe fn get_unchecked(self, slice: &BStr) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, without + /// performing any bounds checking. + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + fn index(self, slice: &BStr) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, panicking + /// if out of bounds. + fn index_mut(self, slice: &mut BStr) -> &mut Self::Output; +} + +impl SliceIndex for usize { + type Output = u8; + + #[inline] + fn get(self, slice: &BStr) -> Option<&u8> { + slice.as_bytes().get(self) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut u8> { + slice.as_bytes_mut().get_mut(self) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &u8 { + slice.as_bytes().get_unchecked(self) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut u8 { + slice.as_bytes_mut().get_unchecked_mut(self) + } + + #[inline] + fn index(self, slice: &BStr) -> &u8 { + &slice.as_bytes()[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut u8 { + &mut slice.as_bytes_mut()[self] + } +} + +impl SliceIndex for ops::Range { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} + +impl SliceIndex for ops::RangeTo { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} + +impl SliceIndex for ops::RangeFrom { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} + +impl SliceIndex for ops::RangeFull { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} + +impl SliceIndex for ops::RangeInclusive { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} + +impl SliceIndex for ops::RangeToInclusive { + type Output = BStr; + + #[inline] + fn get(self, slice: &BStr) -> Option<&BStr> { + slice.as_bytes().get(self).map(BStr::new) + } + + #[inline] + fn get_mut(self, slice: &mut BStr) -> Option<&mut BStr> { + slice.as_bytes_mut().get_mut(self).map(BStr::new_mut) + } + + #[inline] + unsafe fn get_unchecked(self, slice: &BStr) -> &BStr { + BStr::new(slice.as_bytes().get_unchecked(self)) + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut BStr) -> &mut BStr { + BStr::new_mut(slice.as_bytes_mut().get_unchecked_mut(self)) + } + + #[inline] + fn index(self, slice: &BStr) -> &BStr { + &slice[self] + } + + #[inline] + fn index_mut(self, slice: &mut BStr) -> &mut BStr { + &mut slice[self] + } +} diff --git a/bstr/src/tests.rs b/bstr/src/tests.rs new file mode 100644 index 000000000..f4179fd1d --- /dev/null +++ b/bstr/src/tests.rs @@ -0,0 +1,32 @@ +/// A sequence of tests for checking whether lossy decoding uses the maximal +/// subpart strategy correctly. Namely, if a sequence of otherwise invalid +/// UTF-8 bytes is a valid prefix of a valid UTF-8 sequence, then the entire +/// prefix is replaced by a single replacement codepoint. In all other cases, +/// each invalid byte is replaced by a single replacement codepoint. +/// +/// The first element in each tuple is the expected result of lossy decoding, +/// while the second element is the input given. +pub const LOSSY_TESTS: &[(&str, &[u8])] = &[ + ("a", b"a"), + ("\u{FFFD}", b"\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xFF\xFF"), + ("β\u{FFFD}", b"\xCE\xB2\xFF"), + ("☃\u{FFFD}", b"\xE2\x98\x83\xFF"), + ("𝝱\u{FFFD}", b"\xF0\x9D\x9D\xB1\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xCE\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xCE\xFF"), + ("\u{FFFD}\u{FFFD}", b"\xE2\x98\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xE2\x98\xFF"), + ("\u{FFFD}", b"\xF0\x9D\x9D"), + ("\u{FFFD}\u{FFFD}", b"\xF0\x9D\x9D\xF0"), + ("\u{FFFD}\u{FFFD}", b"\xF0\x9D\x9D\xFF"), + ("\u{FFFD}", b"\xCE"), + ("a\u{FFFD}", b"a\xCE"), + ("\u{FFFD}", b"\xE2\x98"), + ("a\u{FFFD}", b"a\xE2\x98"), + ("\u{FFFD}", b"\xF0\x9D\x9C"), + ("a\u{FFFD}", b"a\xF0\x9D\x9C"), + ("a\u{FFFD}\u{FFFD}\u{FFFD}z", b"a\xED\xA0\x80z"), + ("☃βツ\u{FFFD}", b"\xe2\x98\x83\xce\xb2\xe3\x83\x84\xFF"), + ("a\u{FFFD}\u{FFFD}\u{FFFD}b", b"\x61\xF1\x80\x80\xE1\x80\xC2\x62"), +]; diff --git a/bstr/src/unicode/data/GraphemeBreakTest.txt b/bstr/src/unicode/data/GraphemeBreakTest.txt new file mode 100644 index 000000000..6847953c2 --- /dev/null +++ b/bstr/src/unicode/data/GraphemeBreakTest.txt @@ -0,0 +1,700 @@ +# GraphemeBreakTest-11.0.0.txt +# Date: 2018-03-18, 13:30:33 GMT +# © 2018 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Grapheme_Cluster_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Grapheme_Cluster_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of GraphemeBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0020 × 0308 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000D ÷ 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000D ÷ 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000D ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000D ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000D ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000D ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000D ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000D ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 000D ÷ D800 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Control) ÷ [0.3] +÷ 000D ÷ 0308 ÷ D800 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000A ÷ 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000A ÷ 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 000A ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 000A ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 000A ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 000A ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 000A ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 000A ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 000A ÷ D800 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Control) ÷ [0.3] +÷ 000A ÷ 0308 ÷ D800 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0001 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0001 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0001 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0001 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0001 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0001 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0001 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 ÷ D800 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (CR) ÷ [0.3] +÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (LF) ÷ [0.3] +÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] (Other) ÷ [0.3] +÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 034F ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] (Control) ÷ [0.3] +÷ 034F × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (CR) ÷ [0.3] +÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (LF) ÷ [0.3] +÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3] +÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0600 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] (Control) ÷ [0.3] +÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] (Other) ÷ [0.3] +÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0903 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] (Control) ÷ [0.3] +÷ 0903 × 0308 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (CR) ÷ [0.3] +÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (LF) ÷ [0.3] +÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] (Other) ÷ [0.3] +÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1100 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] (Control) ÷ [0.3] +÷ 1100 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (CR) ÷ [0.3] +÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (LF) ÷ [0.3] +÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] (Other) ÷ [0.3] +÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 1160 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] (Control) ÷ [0.3] +÷ 1160 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (CR) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (LF) ÷ [0.3] +÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] (Other) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 11A8 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] (Control) ÷ [0.3] +÷ 11A8 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (CR) ÷ [0.3] +÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (LF) ÷ [0.3] +÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] (Other) ÷ [0.3] +÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ AC00 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] (Control) ÷ [0.3] +÷ AC00 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (CR) ÷ [0.3] +÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (LF) ÷ [0.3] +÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] (Other) ÷ [0.3] +÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ AC01 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] (Control) ÷ [0.3] +÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (CR) ÷ [0.3] +÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (LF) ÷ [0.3] +÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] (Control) ÷ [0.3] +÷ 231A × 0308 ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0378 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ 0378 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ 0378 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 ÷ 0600 ÷ # ÷ [0.2] (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0378 × 0903 ÷ # ÷ [0.2] (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0378 ÷ 1100 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0378 ÷ 1160 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0378 ÷ AC00 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0378 ÷ AC01 ÷ # ÷ [0.2] (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0378 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0378 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ 0378 × 200D ÷ # ÷ [0.2] (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0378 ÷ 0378 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ 0378 ÷ D800 ÷ # ÷ [0.2] (Other) ÷ [5.0] (Control) ÷ [0.3] +÷ 0378 × 0308 ÷ D800 ÷ # ÷ [0.2] (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ D800 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] SPACE (Other) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ D800 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] (CR) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (CR) ÷ [0.3] +÷ D800 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] (LF) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (LF) ÷ [0.3] +÷ D800 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ D800 ÷ 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ D800 ÷ 0308 × 034F ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3] +÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ D800 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ D800 ÷ 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ D800 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ D800 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ D800 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ D800 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ D800 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ D800 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ D800 ÷ 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3] +÷ D800 ÷ 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ D800 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Other) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] (Other) ÷ [0.3] +÷ D800 ÷ D800 ÷ # ÷ [0.2] (Control) ÷ [4.0] (Control) ÷ [0.3] +÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] (Control) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3] +÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3] +÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3] +# +# Lines: 672 +# +# EOF diff --git a/bstr/src/unicode/data/SentenceBreakTest.txt b/bstr/src/unicode/data/SentenceBreakTest.txt new file mode 100644 index 000000000..70898a317 --- /dev/null +++ b/bstr/src/unicode/data/SentenceBreakTest.txt @@ -0,0 +1,530 @@ +# SentenceBreakTest-11.0.0.txt +# Date: 2018-01-31, 08:20:29 GMT +# © 2018 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Sentence_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Sentence_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of SentenceBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0001 × 0001 ÷ # ÷ [0.2] (Other) × [998.0] (Other) ÷ [0.3] +÷ 0001 × 0308 × 0001 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0001 × 000D ÷ # ÷ [0.2] (Other) × [998.0] (CR) ÷ [0.3] +÷ 0001 × 0308 × 000D ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0001 × 000A ÷ # ÷ [0.2] (Other) × [998.0] (LF) ÷ [0.3] +÷ 0001 × 0308 × 000A ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0001 × 0085 ÷ # ÷ [0.2] (Other) × [998.0] (Sep) ÷ [0.3] +÷ 0001 × 0308 × 0085 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0001 × 0009 ÷ # ÷ [0.2] (Other) × [998.0] (Sp) ÷ [0.3] +÷ 0001 × 0308 × 0009 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0001 × 0061 ÷ # ÷ [0.2] (Other) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0308 × 0061 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0041 ÷ # ÷ [0.2] (Other) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 0308 × 0041 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 01BB ÷ # ÷ [0.2] (Other) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0308 × 01BB ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0030 ÷ # ÷ [0.2] (Other) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 0308 × 0030 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 002E ÷ # ÷ [0.2] (Other) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0308 × 002E ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0021 ÷ # ÷ [0.2] (Other) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0308 × 0021 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0022 ÷ # ÷ [0.2] (Other) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 0308 × 0022 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 002C ÷ # ÷ [0.2] (Other) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 0308 × 002C ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 00AD ÷ # ÷ [0.2] (Other) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0300 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Other) ÷ [0.3] +÷ 000D ÷ 0308 × 0001 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] (CR) ÷ [0.3] +÷ 000D ÷ 0308 × 000D ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 × 000A ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 000D ÷ 0085 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Sep) ÷ [0.3] +÷ 000D ÷ 0308 × 0085 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 000D ÷ 0009 ÷ # ÷ [0.2] (CR) ÷ [4.0] (Sp) ÷ [0.3] +÷ 000D ÷ 0308 × 0009 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 000D ÷ 0061 ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000D ÷ 0308 × 0061 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000D ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000D ÷ 0308 × 0041 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000D ÷ 01BB ÷ # ÷ [0.2] (CR) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000D ÷ 0308 × 01BB ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000D ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 0308 × 0030 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000D ÷ 0308 × 002E ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000D ÷ 0021 ÷ # ÷ [0.2] (CR) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000D ÷ 0308 × 0021 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000D ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000D ÷ 0308 × 0022 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000D ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 000D ÷ 0308 × 002C ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 000D ÷ 00AD ÷ # ÷ [0.2] (CR) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Other) ÷ [0.3] +÷ 000A ÷ 0308 × 0001 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] (CR) ÷ [0.3] +÷ 000A ÷ 0308 × 000D ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] (LF) ÷ [0.3] +÷ 000A ÷ 0308 × 000A ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 000A ÷ 0085 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Sep) ÷ [0.3] +÷ 000A ÷ 0308 × 0085 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 000A ÷ 0009 ÷ # ÷ [0.2] (LF) ÷ [4.0] (Sp) ÷ [0.3] +÷ 000A ÷ 0308 × 0009 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 000A ÷ 0061 ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000A ÷ 0308 × 0061 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000A ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000A ÷ 0308 × 0041 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000A ÷ 01BB ÷ # ÷ [0.2] (LF) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000A ÷ 0308 × 01BB ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000A ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 0308 × 0030 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000A ÷ 0308 × 002E ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000A ÷ 0021 ÷ # ÷ [0.2] (LF) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000A ÷ 0308 × 0021 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000A ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000A ÷ 0308 × 0022 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000A ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 000A ÷ 0308 × 002C ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 000A ÷ 00AD ÷ # ÷ [0.2] (LF) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0085 ÷ 0001 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Other) ÷ [0.3] +÷ 0085 ÷ 0308 × 0001 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0085 ÷ 000D ÷ # ÷ [0.2] (Sep) ÷ [4.0] (CR) ÷ [0.3] +÷ 0085 ÷ 0308 × 000D ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0085 ÷ 000A ÷ # ÷ [0.2] (Sep) ÷ [4.0] (LF) ÷ [0.3] +÷ 0085 ÷ 0308 × 000A ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0085 ÷ 0085 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Sep) ÷ [0.3] +÷ 0085 ÷ 0308 × 0085 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0085 ÷ 0009 ÷ # ÷ [0.2] (Sep) ÷ [4.0] (Sp) ÷ [0.3] +÷ 0085 ÷ 0308 × 0009 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0085 ÷ 0061 ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0085 ÷ 0308 × 0061 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0085 ÷ 0041 ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0085 ÷ 0308 × 0041 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0085 ÷ 01BB ÷ # ÷ [0.2] (Sep) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0085 ÷ 0308 × 01BB ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0085 ÷ 0030 ÷ # ÷ [0.2] (Sep) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0085 ÷ 0308 × 0030 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0085 ÷ 002E ÷ # ÷ [0.2] (Sep) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 002E ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0085 ÷ 0021 ÷ # ÷ [0.2] (Sep) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 0021 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0085 ÷ 0022 ÷ # ÷ [0.2] (Sep) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0085 ÷ 0308 × 0022 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0085 ÷ 002C ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMMA (SContinue) ÷ [0.3] +÷ 0085 ÷ 0308 × 002C ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0085 ÷ 00AD ÷ # ÷ [0.2] (Sep) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0085 ÷ 0308 × 00AD ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0085 ÷ 0300 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0085 ÷ 0308 × 0300 ÷ # ÷ [0.2] (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0009 × 0001 ÷ # ÷ [0.2] (Sp) × [998.0] (Other) ÷ [0.3] +÷ 0009 × 0308 × 0001 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0009 × 000D ÷ # ÷ [0.2] (Sp) × [998.0] (CR) ÷ [0.3] +÷ 0009 × 0308 × 000D ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0009 × 000A ÷ # ÷ [0.2] (Sp) × [998.0] (LF) ÷ [0.3] +÷ 0009 × 0308 × 000A ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0009 × 0085 ÷ # ÷ [0.2] (Sp) × [998.0] (Sep) ÷ [0.3] +÷ 0009 × 0308 × 0085 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0009 × 0009 ÷ # ÷ [0.2] (Sp) × [998.0] (Sp) ÷ [0.3] +÷ 0009 × 0308 × 0009 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0009 × 0061 ÷ # ÷ [0.2] (Sp) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0308 × 0061 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0041 ÷ # ÷ [0.2] (Sp) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 0308 × 0041 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 01BB ÷ # ÷ [0.2] (Sp) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0308 × 01BB ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0030 ÷ # ÷ [0.2] (Sp) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 0308 × 0030 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 002E ÷ # ÷ [0.2] (Sp) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0308 × 002E ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0021 ÷ # ÷ [0.2] (Sp) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0308 × 0021 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0022 ÷ # ÷ [0.2] (Sp) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 0308 × 0022 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 002C ÷ # ÷ [0.2] (Sp) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 0308 × 002C ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 00AD ÷ # ÷ [0.2] (Sp) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0009 × 0308 × 00AD ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0009 × 0300 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0009 × 0308 × 0300 ÷ # ÷ [0.2] (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Other) ÷ [0.3] +÷ 0061 × 0308 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0061 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (CR) ÷ [0.3] +÷ 0061 × 0308 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0061 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (LF) ÷ [0.3] +÷ 0061 × 0308 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0061 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Sep) ÷ [0.3] +÷ 0061 × 0308 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0061 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] (Sp) ÷ [0.3] +÷ 0061 × 0308 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0061 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0308 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0308 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0308 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0308 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 0308 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 0308 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Other) ÷ [0.3] +÷ 0041 × 0308 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0041 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (CR) ÷ [0.3] +÷ 0041 × 0308 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0041 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (LF) ÷ [0.3] +÷ 0041 × 0308 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0041 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Sep) ÷ [0.3] +÷ 0041 × 0308 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0041 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] (Sp) ÷ [0.3] +÷ 0041 × 0308 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0041 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0308 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0308 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0308 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 0308 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 0308 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 01BB × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Other) ÷ [0.3] +÷ 01BB × 0308 × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 01BB × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (CR) ÷ [0.3] +÷ 01BB × 0308 × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 01BB × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (LF) ÷ [0.3] +÷ 01BB × 0308 × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 01BB × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Sep) ÷ [0.3] +÷ 01BB × 0308 × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 01BB × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] (Sp) ÷ [0.3] +÷ 01BB × 0308 × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 01BB × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0308 × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 0308 × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0308 × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 0308 × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0308 × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0308 × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 0308 × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 0308 × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 01BB × 0308 × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 01BB × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 01BB × 0308 × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Other) ÷ [0.3] +÷ 0030 × 0308 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0030 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (CR) ÷ [0.3] +÷ 0030 × 0308 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0030 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (LF) ÷ [0.3] +÷ 0030 × 0308 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0030 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Sep) ÷ [0.3] +÷ 0030 × 0308 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0030 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] (Sp) ÷ [0.3] +÷ 0030 × 0308 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0030 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0308 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0308 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0308 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 0308 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 0308 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E ÷ 0001 ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] (Other) ÷ [0.3] +÷ 002E × 0308 ÷ 0001 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] (Other) ÷ [0.3] +÷ 002E × 000D ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (CR) ÷ [0.3] +÷ 002E × 0308 × 000D ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (CR) ÷ [0.3] +÷ 002E × 000A ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (LF) ÷ [0.3] +÷ 002E × 0308 × 000A ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (LF) ÷ [0.3] +÷ 002E × 0085 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (Sep) ÷ [0.3] +÷ 002E × 0308 × 0085 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sep) ÷ [0.3] +÷ 002E × 0009 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] (Sp) ÷ [0.3] +÷ 002E × 0308 × 0009 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sp) ÷ [0.3] +÷ 002E × 0061 ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002E × 0308 × 0061 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002E ÷ 0041 ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002E × 0308 ÷ 0041 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002E ÷ 01BB ÷ # ÷ [0.2] FULL STOP (ATerm) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 01BB ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002E × 0030 ÷ # ÷ [0.2] FULL STOP (ATerm) × [6.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 0308 × 0030 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [6.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 002E ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 002E × 0308 × 002E ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 002E × 0021 ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002E × 0308 × 0021 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002E × 0022 ÷ # ÷ [0.2] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002E × 0308 × 0022 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002E × 002C ÷ # ÷ [0.2] FULL STOP (ATerm) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 002E × 0308 × 002C ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 002E × 00AD ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0308 × 00AD ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0300 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 0308 × 0300 ÷ # ÷ [0.2] FULL STOP (ATerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0021 ÷ 0001 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] (Other) ÷ [0.3] +÷ 0021 × 0308 ÷ 0001 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] (Other) ÷ [0.3] +÷ 0021 × 000D ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (CR) ÷ [0.3] +÷ 0021 × 0308 × 000D ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (CR) ÷ [0.3] +÷ 0021 × 000A ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (LF) ÷ [0.3] +÷ 0021 × 0308 × 000A ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (LF) ÷ [0.3] +÷ 0021 × 0085 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (Sep) ÷ [0.3] +÷ 0021 × 0308 × 0085 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sep) ÷ [0.3] +÷ 0021 × 0009 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] (Sp) ÷ [0.3] +÷ 0021 × 0308 × 0009 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] (Sp) ÷ [0.3] +÷ 0021 ÷ 0061 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0021 × 0308 ÷ 0061 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0021 ÷ 0041 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0021 × 0308 ÷ 0041 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0021 ÷ 01BB ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0021 × 0308 ÷ 01BB ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0021 ÷ 0030 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) ÷ [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0021 × 0308 ÷ 0030 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0021 × 002E ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 0021 × 0308 × 002E ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] FULL STOP (ATerm) ÷ [0.3] +÷ 0021 × 0021 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0021 × 0308 × 0021 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0021 × 0022 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0021 × 0308 × 0022 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [9.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0021 × 002C ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 0021 × 0308 × 002C ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.1] COMMA (SContinue) ÷ [0.3] +÷ 0021 × 00AD ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0021 × 0308 × 00AD ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0021 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0021 × 0308 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Other) ÷ [0.3] +÷ 0022 × 0308 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0022 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (CR) ÷ [0.3] +÷ 0022 × 0308 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0022 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (LF) ÷ [0.3] +÷ 0022 × 0308 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0022 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Sep) ÷ [0.3] +÷ 0022 × 0308 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0022 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] (Sp) ÷ [0.3] +÷ 0022 × 0308 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0022 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0308 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 0308 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0308 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 0308 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0308 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0308 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 0308 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 0308 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Other) ÷ [0.3] +÷ 002C × 0308 × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 002C × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (CR) ÷ [0.3] +÷ 002C × 0308 × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 002C × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (LF) ÷ [0.3] +÷ 002C × 0308 × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 002C × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Sep) ÷ [0.3] +÷ 002C × 0308 × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 002C × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] (Sp) ÷ [0.3] +÷ 002C × 0308 × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 002C × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0308 × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 0308 × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0308 × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 0308 × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0308 × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0308 × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 0308 × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 0308 × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Other) ÷ [0.3] +÷ 00AD × 0308 × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 00AD × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (CR) ÷ [0.3] +÷ 00AD × 0308 × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 00AD × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (LF) ÷ [0.3] +÷ 00AD × 0308 × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 00AD × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Sep) ÷ [0.3] +÷ 00AD × 0308 × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 00AD × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] (Sp) ÷ [0.3] +÷ 00AD × 0308 × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 00AD × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0308 × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 0308 × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0308 × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 0308 × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0308 × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0308 × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 0308 × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 0308 × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0300 × 0308 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Other) ÷ [0.3] +÷ 0300 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0300 × 0308 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (CR) ÷ [0.3] +÷ 0300 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0300 × 0308 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (LF) ÷ [0.3] +÷ 0300 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0300 × 0308 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sep) ÷ [0.3] +÷ 0300 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0300 × 0308 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] (Sp) ÷ [0.3] +÷ 0300 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0308 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 0308 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0308 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 0308 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0308 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0308 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 0308 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 0308 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) × [998.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D × 0646 ÷ # ÷ [0.2] SPACE (Sp) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] ARABIC LETTER NOON (OLetter) ÷ [0.3] +÷ 0646 × 200D × 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (OLetter) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] SPACE (Sp) ÷ [0.3] +÷ 0028 × 0022 × 0047 × 006F × 002E × 0022 × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0028 × 201C × 0047 × 006F × 003F × 201D × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] QUESTION MARK (STerm) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E × 0020 × 0069 × 0073 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER S (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 003F × 0020 ÷ 0048 × 0065 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [9.0] SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0033 × 002E × 0034 ÷ # ÷ [0.2] DIGIT THREE (Numeric) × [998.0] FULL STOP (ATerm) × [6.0] DIGIT FOUR (Numeric) ÷ [0.3] +÷ 0063 × 002E × 0064 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0043 × 002E × 0064 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0063 × 002E × 0044 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0043 × 002E × 0044 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 2018 × 0028 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 2018 × 0028 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 000A ÷ 0308 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0074 × 0068 × 0065 × 0020 × 0072 × 0065 × 0073 × 0070 × 002E × 0020 × 006C × 0065 × 0061 × 0064 × 0065 × 0072 × 0073 × 0020 × 0061 × 0072 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] LATIN SMALL LETTER P (Lower) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER L (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 5B57 × 002E ÷ 5B57 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E ÷ 5B83 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 3002 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.1] IDEOGRAPHIC FULL STOP (STerm) ÷ [0.3] +÷ 5B57 × 3002 ÷ 5B83 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] IDEOGRAPHIC FULL STOP (STerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 0021 × 0020 × 0020 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] SPACE (Sp) × [10.0] SPACE (Sp) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 0022 × 2060 × 0047 × 2060 × 006F × 2060 × 002E × 2060 × 0022 × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 201C × 2060 × 0047 × 2060 × 006F × 2060 × 003F × 2060 × 201D × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 0020 × 2060 × 0069 × 2060 × 0073 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 003F × 2060 × 0020 × 2060 ÷ 0048 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0033 × 2060 × 002E × 2060 × 0034 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] DIGIT THREE (Numeric) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [6.0] DIGIT FOUR (Numeric) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 2018 × 2060 × 0028 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 2018 × 2060 × 0028 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 000A ÷ 2060 × 0308 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] (LF) ÷ [4.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 0020 × 2060 × 0072 × 2060 × 0065 × 2060 × 0073 × 2060 × 0070 × 2060 × 002E × 2060 × 0020 × 2060 × 006C × 2060 × 0065 × 2060 × 0061 × 2060 × 0064 × 2060 × 0065 × 2060 × 0072 × 2060 × 0073 × 2060 × 0020 × 2060 × 0061 × 2060 × 0072 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER P (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER L (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 002E × 2060 ÷ 5B57 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 3002 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.1] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 3002 × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0021 × 2060 × 0020 × 2060 × 0020 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] EXCLAMATION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [10.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +# +# Lines: 502 +# +# EOF diff --git a/bstr/src/unicode/data/WordBreakTest.txt b/bstr/src/unicode/data/WordBreakTest.txt new file mode 100644 index 000000000..c4c92550e --- /dev/null +++ b/bstr/src/unicode/data/WordBreakTest.txt @@ -0,0 +1,1851 @@ +# WordBreakTest-11.0.0.txt +# Date: 2018-03-16, 20:34:16 GMT +# © 2018 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ +# +# Default Word_Break Test +# +# Format: +# (# )? +# contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and +# × wherever there is not. +# the format can change, but currently it shows: +# - the sample character name +# - (x) the Word_Break property value for the sample character +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of WordBreakTest.html +# +# These samples may be extended or changed in the future. +# +÷ 0001 ÷ 0001 ÷ # ÷ [0.2] (Other) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 × 0308 ÷ 0001 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0001 ÷ 000D ÷ # ÷ [0.2] (Other) ÷ [3.2] (CR) ÷ [0.3] +÷ 0001 × 0308 ÷ 000D ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0001 ÷ 000A ÷ # ÷ [0.2] (Other) ÷ [3.2] (LF) ÷ [0.3] +÷ 0001 × 0308 ÷ 000A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0001 ÷ 000B ÷ # ÷ [0.2] (Other) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0001 × 0308 ÷ 000B ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0001 ÷ 3031 ÷ # ÷ [0.2] (Other) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0001 × 0308 ÷ 3031 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0001 ÷ 0041 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0041 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0001 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 002E ÷ # ÷ [0.2] (Other) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0001 × 0308 ÷ 002E ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0001 ÷ 0030 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 0308 ÷ 0030 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 ÷ 005F ÷ # ÷ [0.2] (Other) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0001 × 0308 ÷ 005F ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 05D0 ÷ # ÷ [0.2] (Other) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0001 × 0308 ÷ 05D0 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0001 ÷ 0022 ÷ # ÷ [0.2] (Other) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0022 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0001 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 231A ÷ # ÷ [0.2] (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 × 0308 ÷ 231A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0001 ÷ 0020 ÷ # ÷ [0.2] (Other) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0001 × 0308 ÷ 0020 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0001 × 00AD ÷ # ÷ [0.2] (Other) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0001 × 0300 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 200D ÷ # ÷ [0.2] (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0001 × 0308 × 200D ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0001 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0001 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Other) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0001 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [3.1] (Other) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000D ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [3.1] (CR) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000D × 000A ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000D ÷ 000B ÷ # ÷ [0.2] (CR) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000D ÷ 3031 ÷ # ÷ [0.2] (CR) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000D ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000D ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000D ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 005F ÷ # ÷ [0.2] (CR) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 05D0 ÷ # ÷ [0.2] (CR) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000D ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000D ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000D ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000D ÷ 00AD ÷ # ÷ [0.2] (CR) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000D ÷ 0300 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] (CR) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000D ÷ 0061 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [3.1] (Other) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000A ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [3.1] (CR) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000A ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [3.1] (LF) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000A ÷ 000B ÷ # ÷ [0.2] (LF) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000A ÷ 3031 ÷ # ÷ [0.2] (LF) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000A ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000A ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000A ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 005F ÷ # ÷ [0.2] (LF) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 05D0 ÷ # ÷ [0.2] (LF) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000A ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000A ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000A ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000A ÷ 00AD ÷ # ÷ [0.2] (LF) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000A ÷ 0300 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] (LF) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000A ÷ 0061 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0001 ÷ # ÷ [0.2] (Newline) ÷ [3.1] (Other) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 000B ÷ 000D ÷ # ÷ [0.2] (Newline) ÷ [3.1] (CR) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000D ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 000B ÷ 000A ÷ # ÷ [0.2] (Newline) ÷ [3.1] (LF) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 000B ÷ 000B ÷ # ÷ [0.2] (Newline) ÷ [3.1] (Newline) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 000B ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 000B ÷ 3031 ÷ # ÷ [0.2] (Newline) ÷ [3.1] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 3031 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 000B ÷ 0041 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0041 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 000B ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 002E ÷ # ÷ [0.2] (Newline) ÷ [3.1] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 002E ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 000B ÷ 0030 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000B ÷ 005F ÷ # ÷ [0.2] (Newline) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 005F ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 000B ÷ 1F1E6 ÷ # ÷ [0.2] (Newline) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000B ÷ 05D0 ÷ # ÷ [0.2] (Newline) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 000B ÷ 0022 ÷ # ÷ [0.2] (Newline) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 000B ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 231A ÷ # ÷ [0.2] (Newline) ÷ [3.1] WATCH (ExtPict) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 231A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 000B ÷ 0020 ÷ # ÷ [0.2] (Newline) ÷ [3.1] SPACE (WSegSpace) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 000B ÷ 00AD ÷ # ÷ [0.2] (Newline) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 00AD ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 000B ÷ 0300 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 0300 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000B ÷ 200D ÷ # ÷ [0.2] (Newline) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 200D ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000B ÷ 0061 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 000B ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0001 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] (Other) ÷ [0.3] +÷ 3031 × 0308 ÷ 0001 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 3031 ÷ 000D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (CR) ÷ [0.3] +÷ 3031 × 0308 ÷ 000D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 3031 ÷ 000A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (LF) ÷ [0.3] +÷ 3031 × 0308 ÷ 000A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 3031 ÷ 000B ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [3.2] (Newline) ÷ [0.3] +÷ 3031 × 0308 ÷ 000B ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 3031 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 3031 × 0308 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 3031 ÷ 0041 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0041 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 3031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 002E ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 3031 × 0308 ÷ 002E ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 3031 ÷ 0030 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 0308 ÷ 0030 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 3031 × 0308 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 3031 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 3031 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 3031 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 3031 × 0308 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 3031 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 3031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 231A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 3031 × 0308 ÷ 231A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 3031 ÷ 0020 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 3031 × 0308 ÷ 0020 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 3031 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 3031 × 0308 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 3031 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 3031 × 0308 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 3031 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 3031 × 0308 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 3031 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 3031 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 3031 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 ÷ 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0041 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0041 ÷ 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0041 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0041 ÷ 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0041 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0041 ÷ 000B ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0041 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0041 ÷ 3031 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 ÷ 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0041 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 × 0308 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0041 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0041 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0041 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0041 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 ÷ 231A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0041 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0041 ÷ 0020 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0041 × 0308 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0041 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0041 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0041 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0041 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0001 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 003A ÷ 000D ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 003A ÷ 000A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 003A ÷ 000B ÷ # ÷ [0.2] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 003A ÷ 3031 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 003A ÷ 0041 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0041 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 003A ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 002E ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 003A ÷ 0030 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 003A ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 003A ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 003A ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 003A ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 231A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 003A ÷ 0020 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 003A × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 003A × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 003A × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 003A × 0308 × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0001 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 002C ÷ 000D ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 002C ÷ 000A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 002C ÷ 000B ÷ # ÷ [0.2] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002C ÷ 3031 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002C ÷ 0041 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002C ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 002E ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002C ÷ 0030 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002C ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002C ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002C ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 231A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002C ÷ 0020 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002C × 0308 × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002C ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002C × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0001 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] (Other) ÷ [0.3] +÷ 002E × 0308 ÷ 0001 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 002E ÷ 000D ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (CR) ÷ [0.3] +÷ 002E × 0308 ÷ 000D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 002E ÷ 000A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (LF) ÷ [0.3] +÷ 002E × 0308 ÷ 000A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 002E ÷ 000B ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002E × 0308 ÷ 000B ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 002E ÷ 3031 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002E × 0308 ÷ 3031 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 002E ÷ 0041 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0041 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 002E ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 002E ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002E × 0308 ÷ 002E ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 002E ÷ 0030 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E × 0308 ÷ 0030 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002E ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002E × 0308 ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 002E ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002E ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002E × 0308 ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 002E ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 002E ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 231A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002E × 0308 ÷ 231A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 002E ÷ 0020 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002E × 0308 ÷ 0020 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 002E × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0308 × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 002E × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 0308 × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002E × 0308 × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002E ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 002E ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 002E × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 ÷ 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] (Other) ÷ [0.3] +÷ 0030 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0030 ÷ 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (CR) ÷ [0.3] +÷ 0030 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0030 ÷ 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (LF) ÷ [0.3] +÷ 0030 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0030 ÷ 000B ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0030 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0030 ÷ 3031 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0030 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 ÷ 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0030 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0030 × 0308 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0030 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0030 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0030 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0030 × 0308 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0030 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0030 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0030 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 ÷ 231A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0030 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0030 ÷ 0020 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0030 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0030 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0030 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0030 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0030 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0030 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F ÷ 0001 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] (Other) ÷ [0.3] +÷ 005F × 0308 ÷ 0001 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 005F ÷ 000D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (CR) ÷ [0.3] +÷ 005F × 0308 ÷ 000D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 005F ÷ 000A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (LF) ÷ [0.3] +÷ 005F × 0308 ÷ 000A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 005F ÷ 000B ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [3.2] (Newline) ÷ [0.3] +÷ 005F × 0308 ÷ 000B ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 005F × 3031 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 005F × 0308 × 3031 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 005F × 0041 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 005F × 0308 × 0041 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 005F ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F ÷ 002E ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 005F × 0308 ÷ 002E ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 005F × 0030 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 005F × 0308 × 0030 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 005F × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 005F × 0308 × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 005F ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 005F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 005F × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 005F × 0308 × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 005F ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 005F × 0308 ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 005F ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F ÷ 231A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 005F × 0308 ÷ 231A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 005F ÷ 0020 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 005F × 0308 ÷ 0020 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 005F × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 005F × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 005F × 0308 × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 005F × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 005F × 0308 × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 005F × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0061 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0061 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0061 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0031 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 005F × 0031 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F × 0031 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 005F × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 005F × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 1F1E6 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] (Newline) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 1F1E6 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 1F1E6 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] (Other) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 05D0 ÷ 000D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (CR) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 05D0 ÷ 000A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (LF) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 05D0 ÷ 000B ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 05D0 × 0308 ÷ 000B ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 05D0 ÷ 3031 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 05D0 × 0308 ÷ 3031 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 05D0 × 0041 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 × 0308 × 0041 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 ÷ 002E ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 05D0 × 0308 ÷ 002E ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 05D0 × 0030 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 05D0 × 0308 × 0030 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 05D0 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 05D0 × 0308 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 05D0 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 05D0 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 05D0 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 05D0 × 0308 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 05D0 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 ÷ 231A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 05D0 × 0308 ÷ 231A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 05D0 ÷ 0020 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 05D0 × 0308 ÷ 0020 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 05D0 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 05D0 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 05D0 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 05D0 × 0308 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 05D0 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0061 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0061 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0061 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0031 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 05D0 × 0031 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0031 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 05D0 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 05D0 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0001 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0022 × 0308 ÷ 0001 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0022 ÷ 000D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0022 × 0308 ÷ 000D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0022 ÷ 000A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0022 × 0308 ÷ 000A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0022 ÷ 000B ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0022 × 0308 ÷ 000B ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0022 ÷ 3031 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0022 × 0308 ÷ 3031 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0022 ÷ 0041 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0041 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0022 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 002E ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0022 × 0308 ÷ 002E ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0022 ÷ 0030 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 0308 ÷ 0030 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0022 × 0308 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0022 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0022 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0022 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0022 × 0308 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0022 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0022 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 231A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0022 × 0308 ÷ 231A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0022 ÷ 0020 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0022 × 0308 ÷ 0020 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0022 × 0308 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0022 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0022 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0022 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0001 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0027 ÷ 000D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0027 ÷ 000A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0027 ÷ 000B ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0027 ÷ 3031 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0027 ÷ 0041 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0041 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0027 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 002E ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0027 ÷ 0030 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0027 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0027 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0027 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 231A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0027 ÷ 0020 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0027 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0027 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0027 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0027 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0027 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (CR) ÷ [0.3] +÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (LF) ÷ [0.3] +÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 231A ÷ 000B ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [3.2] (Newline) ÷ [0.3] +÷ 231A × 0308 ÷ 000B ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 231A ÷ 3031 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 231A × 0308 ÷ 3031 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 231A ÷ 0041 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0041 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 231A ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 002E ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 231A × 0308 ÷ 002E ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 231A ÷ 0030 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 231A × 0308 ÷ 0030 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 231A ÷ 005F ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 231A × 0308 ÷ 005F ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 231A ÷ 05D0 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 231A × 0308 ÷ 05D0 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 231A ÷ 0022 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0022 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 231A ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 231A × 00AD ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 231A × 0308 × 00AD ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 231A ÷ 0061 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 231A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 231A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WATCH (ExtPict) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (CR) ÷ [0.3] +÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (LF) ÷ [0.3] +÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0020 ÷ 000B ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0020 × 0308 ÷ 000B ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0020 ÷ 3031 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0020 × 0308 ÷ 3031 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0020 ÷ 0041 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0041 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0020 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 002E ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0020 × 0308 ÷ 002E ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0020 ÷ 0030 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0020 × 0308 ÷ 0030 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0020 ÷ 005F ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0020 × 0308 ÷ 005F ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 05D0 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0020 × 0308 ÷ 05D0 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0020 ÷ 0022 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0022 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0020 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0020 × 0020 ÷ # ÷ [0.2] SPACE (WSegSpace) × [3.4] SPACE (WSegSpace) ÷ [0.3] +÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0020 × 00AD ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0020 × 0308 × 00AD ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0020 ÷ 0061 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0020 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0020 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 00AD × 0308 ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 00AD ÷ 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 00AD × 0308 ÷ 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 00AD ÷ 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 00AD × 0308 ÷ 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 00AD ÷ 000B ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 00AD × 0308 ÷ 000B ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 00AD ÷ 3031 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 00AD × 0308 ÷ 3031 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 00AD ÷ 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 00AD ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 00AD × 0308 ÷ 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 00AD ÷ 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 0308 ÷ 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 00AD × 0308 ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 00AD ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00AD × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00AD ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 00AD × 0308 ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 00AD ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 00AD ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 231A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 00AD × 0308 ÷ 231A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 00AD ÷ 0020 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 00AD × 0308 ÷ 0020 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 00AD × 0308 × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 00AD ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 00AD ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 00AD × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0300 ÷ 000B ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0300 × 0308 ÷ 000B ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0300 ÷ 3031 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0300 × 0308 ÷ 3031 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0300 ÷ 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0300 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0300 × 0308 ÷ 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0300 ÷ 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 0308 ÷ 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0300 × 0308 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0300 × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0300 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0300 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0300 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0300 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0300 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 200D ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 200D × 0308 ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 200D ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D × 0308 ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D × 0308 ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D × 0308 ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] WATCH (ExtPict) ÷ [0.3] +÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 200D × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0308 × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 × 2060 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 × 2060 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 × 2060 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 × 2060 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 2060 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 2060 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 2060 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 × 2060 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 2060 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 003A × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 003A × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 003A × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 003A × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 003A × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 0027 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 0027 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 0027 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 × 0027 × 2060 × 0308 × 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0061 ÷ 002C × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 003A × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 0027 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 0027 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 0027 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 0027 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 002C × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002C × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002C × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 002C × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] (Other) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (CR) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (LF) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 000B ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] (Newline) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 3031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0041 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 002E ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 231A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WATCH (ExtPict) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0020 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] (CR) × [3.0] (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [3.2] (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (WSegSpace) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] ARABIC LETTER NOON (ALetter) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] SPACE (WSegSpace) ÷ [0.3] +÷ 0041 × 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 × 003A × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 ÷ 003A ÷ 003A ÷ 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 × 0022 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.2] QUOTATION MARK (Double_Quote) × [7.3] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 0041 × 0030 × 0030 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ZERO (Numeric) × [8.0] DIGIT ZERO (Numeric) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 × 002C × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 ÷ 002C ÷ 002C ÷ 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 005F × 0030 × 005F × 3031 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 × 005F × 005F × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [999.0] BABY (ExtPict) ÷ [0.3] +÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 0061 × 200D × 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] UPPER BLADE SCISSORS (Other) ÷ [0.3] +÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] BABY (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 1F6D1 × 1F3FF ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 200D × 1F6D1 × 1F3FF ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) × [4.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend_FE) ÷ [0.3] +÷ 200D × 1F6D1 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 200D × 1F6D1 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 1F6D1 ÷ 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3] +÷ 0061 × 0308 × 200D × 0308 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 0020 × 0020 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] SPACE (WSegSpace) × [3.4] SPACE (WSegSpace) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0031 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 003A ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002E ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 003A ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002E ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0031 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +÷ 0061 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] +# +# Lines: 1823 +# +# EOF diff --git a/bstr/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa b/bstr/src/unicode/fsm/grapheme_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..e6eda05cc6d6063780571c250b96f0f91f7c889d GIT binary patch literal 10223 zcmd5?3w&HvTEF+sGnr(PCiBd5QqqW65Gz(hL_|bHtcbYQiff9c8`o}k4FwUg+)R?0 zyl0Z;(M%qb$K?H*Wb#g$U>7T5scWsJETz0Ec1tO>)QYw4`v1UGs_C4Ege&So(i=TM><{dk?3*Y~NAPN%x z+28tn{wu!8f2Cc5C~34hy}_7}Xi7>pr=+e+OSf2Uc84<~Gb=kM*Oj;ahWrf$KXKzv z-tKD zL%;Lz?>_Q-U-|v5f3WQjAN`}R{&C^<$Npr;<2%1r^rv6{vt8fV{mpOvdGQl_o_y*r zp8m^c{_5Gk-us+f;w~*K_joHRtEy{i>wNzDhJB4q%`N*|18wacox!f|p59Pj|G?nT z@W|-c_(XVeDl$DYJ2$_uxU_s=W%c>LIr!}t{`Sz{z4-Sp{lnpxkNo3z{^{sHAN!Z% zubg=GyRV&m{nQ(8zV-Gyr~mcce>?NNv+tdI|NI9R{{7;Im;U4Oe}42|SN{9z|KM~4 z!G8Gg%P${2di?k+ubepX>Z`B4cJk!wub(>g#v5OH9su5ZXbntf*dB~3uvenauPBYB(G zT>*SCF;OTKEZ1J;TJTd}BKYh43S{fGAzmBjyj>h--jN?ARM$}j>a7Y?yKC>kgWsm} z{VqG-=-HnBo_f0H&(r>KJs)1WBoyU@^~E`dkb1ITz=bK^G^t*nvXPbQyw`M(f@Y<)#?P6Fz6(}1DK*kc?t zjvMEVhm41f$Bk!<7mXhozn@@C@Fbi}xR`J?@s7m%6L$*PvRpzOR90T@@p!9iYHDli z>U=(b!#?7o=9ZTI`&(NBfws2x_KuFu&R}mS)HgCZIyN@GTClUAMqiv?h7>@;dFLO> zKZg9GzIcPM!M5Q>L(zu2kRIGnx8X3_&LdqdNYfV!TC7@GRaL#3zY*i_L5nD_B2Sk? zeSQ5C;qc_-)KnxgJv}osJ3BWwKfkcBxVW^mynNum%E~H6uD9unUAMWmxOTXn$-U?@ zx^g~Q6YgevbC;^S^Hx+;(yFmt`s?c(Xs3-$pSIUvS66p;PfsuHxv#%}U|?`?XlQtN zgztZR;+lAV9(F&DzW)a&@R_&s$>pY?-~cK6Xi0hE!d(jF4!t0 z_=)afJQeI()!e5aMLLCa4(W>KKH>=E8kwk&`k!WPKHeh~33`QdJzj6cs=h&AtZzr^ z(YFf{=Bz?v6cG&kO7cW_6}3Vk3EGnQf##^xOgsjT%Gr|hDDtl(J&oi+Y6M4WWa32X zznj%aPEc(VYMJs{&LX+Nd5L6(Dlyh_5zfI-WY}#eGc+5*hDF0^)XpP)WRxJYk_<)q zVk3Cl=rZ19yxq73ZH2~S>ZiTH+R({0wLU-b9(IH}OE}|^(a9-j^Jtr1COPJ>544Sr z#ad~!B=_|LlK6sc= zBGYPHV-qiF&<9Zw0MRccrdVgq=_;q-(TIi&<+i)5s*N**aL?7voJb`gyX(e*0{=h0`qNFKtmz8_HRHj~kfO@Ng;V`Rfo7;n-fx+Q1 z-p^*%hxtrVuA&+J7%502kplqum7&UwUn#(5Pn#Fb$IPe9 z7tEJagp~Cu8&mE{c_d|LiY#bGN9X5PR?Lm&fH@=>NGdcpx3w`n8%!)q>@m4an@qQx z9yS#UVpmtd_7a0Y0xxlS~eXreFri}?(OaCGwm|DO%;OZ^O<%EBI7!p z?5Wt_*4-QGA6Ds-DAC_cc^Ofqo@weK*e6q*PtgYMLaveB<<%-Z3!=LWZIV1oqgZKl zW`>U|D{BjOgJW1t?C3$SR!R0K{G}&Z8=i_VR|8{< z;yBtpKsE$mQah4V?ukTLNk_9HGqaGBu{lI>l{Kv2FgiX#9t=tCxfNidKv4D=40iSO z;%uU@N}+lbSbR0e3%R7sTTxxx($dr0KgxCn+*C+}&CHy#Bf^GRhMk>p{RyzorXt)X zQ!KI=7V0>msX-Tp!Is|$!TnhwrHxz`fXL<=z#z1d=x9C z)zB~ii;%2Ux)Gv|xcd;ale3G9%Zj{Za3xuhxPrc_&R-7`o7tUfW=Z6p5+p$+$x570 z`RpQcT}f%Vr^YwG$Z3pVQeR&`<)Hz}J$}kNiE5#Zx)>d!9;Euj)HIjXVt5jDz1!{a zR97?i7;_mchCgPOkoLmA7TTq}YjTxQIA5(FIzf=U@U!t-1bTu+0b6}$mON@~ms;Z! zQEy)#Yts!y9q_mj+R{?;JC>KD7-%7Xrsw8Kzw&=UUs8gbhyP9X*8;G5o%Vha_(x+x%gM;aO$A7@xWhtiFd zRw8FQ6u(8P4rOKZ`UBKUI+V3Ub*R!$GoeFS4LTIR(4okg4rQ%hQinPob?kQRaqM-} zI0BAAq=QH&kuExo&NOGf^A<k;cQ z>#2|HuUH;6U9dbxI@$8jTAgf3vSe6pwA^C3-Exnrlhe;y1dCp9#@U?Y zQ-93z@92OYiuawF)t|mCeMkE4^k>uE>HE3WpWc}sG8Cl`BZbpv)0fi^rXNQ6c>0^j zI|ZrMH^JqXG&;#;fuO0Ys}GDRasfJ_4;-v3@dW}C6H|-JQF%dpT}hHil$i|m@Uo9u zrdhd(Z>s9niI8aj<-ra$f^-NoIBiE5XLVFKY`!tMSqR%|IKs zC3ssz9mnhkY8z!%14?3W7`a9!3qi%$Ag{3u&>#OV&d@kmIAjgrUu3dOluM~~Vuox6 zDv>T{C1`B?iX(HBcZ^UzO4w?keW80%V&kEC+gM4gYQ?WKF{?s?cBTD83#pov)%YsV zq^zc4nzTjf5hLux4je!o{7LyNtr@2|m5~Gmnv?R-0OcM(%B#7R9$R)Wnb_=8jsfX=L1HA{W$65eW)p<&t&Z%T%Vuqgp z;PeiU5>&JgBV$Td?d(>g6Jt*})XLDyl9)YG%D!226phnV#&NP)J& zK@Ov$0wXm(-%w;8b_Q>Ay9wIx2MT3}yOOG~d}bEqQ(ZBt8kcQ_ogZNRIr$wATHwsy9H>3#h68lDweE5N&g7TW{aM5TD6bXr2j=3ALDKE8{+=;vYY$?*d~*TL{fWoxarF3+MeD;z8Y`WaY)Uvm8e~E zyA?U2mEE3-D)<-CHE<3}ALdeDQ*#tcnya*uM-rWbGjfw;(N$IXKvVmJ%1v<`q{+z$ zmwckP4x==vFD$9NBv#Pv>Grph=f1EIm2WgxoTR;Ifrq!YrB$7Qc8>?``Z2QR=Xh`k zw8wc2xu7NYfK!)3%{sRmJ~g8-btHbpjv#W0XpGY=(HJXfVI$AZDX&H}1N)|zoQg_D zbt()2v_}w#_SiflY*Pwgjlk_9ziWw)#C*bwl7@x5;JdI|qVk%}DRgvfD#ECg_bRya zeSu!l%3hF|M@jEYpJu^p*}Ea5Wn~Q`wcvG}EN^-fC!ZjO58-5FFXk}H;fph$Rhg;c zj5`R8jIvlLP%3}xo zwNAxCFu*RYsHAv@!ZT_Qo2Mh+72Ff`RjD`XJ7X5ns_K6e{`_CiVjAN*6&hP-4S%U) z**fHnmxBT-5xi9RjJ30~WF@VF31lo^he0GgjTxK=8Ey&=f(CrZux73FN=)3yFy`YF zC|dNuDpyYheKa=8oitX(6x#D+r$K!}0;dY1V2ZtRp62s7EinA)oC&IOW^86`cSdkG z#cYYgJA>eHzI!zX9OCTAGWP0PE)#c32s3S!X<6DW-C_X~3Qmau21W6}T1cf4t z@#A%f0o2se8%KPrf!z|_50lz)xNt~(WkgDpo+4op9N_U*Ra2Y;+7s=h332nlh2K3< zq#f8nx`VI1*Ylpv-vaUq^LAd>dw>`W=56~t9?E-!-h7FFs+WMFI7s*-`h%RkCAi%z zR{ceAJ44Zs>%vY#j60ZjBJULQZWcigp6VrbL*&&{ePEE^m;q5X#z{=Sv3MJClTgTV zqBv+$)Fq@$At^c8oa@^A+;d;(D~3YhF(xAl^FBhn`+3COl&=|#vb3`HYX-ebze&GU z|5bd=pqvta@4x;VBo5CnxUN&m{rtGcwc__{-(d2S*1o}fGLpYG*7|=N)4kzRz8*Zo zcq__Ti=a;rQHOV57g>}N(JOKuiIvbJ$^*!Ch{T2`6$u}ey*gR_&LUnS>t(1+|G)&} zZNOyzjJC9hMpjk@$@^w?l1TKO0=>w`Lm*kw8lVrK*0xe?mdTPe@}G93LNqXaI5-r+ zBP`P~Dz0oj4b%JTSe;B?R*_{JzY19wi%U`K3D|R6m%g@8EE%>s#WIzcDPX6f=B=PH z{AHZ<7TJS@Eq%5XKQpSk*5H=HWFp14)vr7n_VI5!dU}a-KXsN00eY{osbxQ{NcRNn zKQUe-lf@d_J3^=x^r2bYNbHm}0qr2ZRg!CcsN-M5ZVP2a$5W(Qtw}Ol6J_puNJt^nf=UU zp1=9cZ+_32zw?R5ciilJ>>H0gb@P@dc6|F=TXt-@`SI^;aX$Xo&0Du^5kLG$C-nHO zS}Ek;n>zJBU$6cPojxi$#t>^<78jq8Xfh`)PfoE|ZT8f(^o-1`>>S66l{c(fz2>KG z{OOy1X6?6Ei@ymDq%3Z&D_pjaa>-YY~hTpvJx9_i@5B>hbfAFeC#Sbq1*X95I@PDrS@74eN z=!Zhs#o@y*y>#Trv16~ia{TzKufF!$i4(8Ce)8lSZ@l^DTW`Jn_B-#KJ^Svv=gz(N z-uv%gxbVRTPQz*QIrByHRdZZYQc`--+NAYKcP8DF^gvSW$|G54vM#OkN9~Pv-thAB z^((F{7eXiE;&O%MI##(B{1=l5zk0cXY`qSM*Ty-2MHuFaA1Bl!4h8krFjTv6>^ykz zyQJ^;C4CoYd+G-obQ>W4vhm(D;$jxXiQc#IlRat}eSH?!LHfaaqFUDxd@v6&HIv-tvly z%F3!LpRc-h7p17ap<&OS#zw!tscG-t=H`}`Ku2e1*TCT5(9pj5ZEGslI1NRsoCZHq z5b4mWqsT8JiPg5%H?Gc$y$k7q)m5txuXY;FBVApcj5*OC(NJh?Y6w|?*#igW=H@Zdw$f?1&9Tw3)$z3B zVvf;~?f7KvZnZaep|(43Nl7VJjqI|zrlyuVt=s)+dkwUL-Q7Jsy}f;X z{rv-K|NDloiRb5G_mk-R|EIubpUzKW|4%y{UzrC!i@UA||2>X<4)8iTS90w}@cyPX z%S1K#E+SKb*7*%lgN6-JCy~w}T|uHmY>0{yE^;ACPpLMa>d6xZwX?z^kJno=Uu$q0 z_9C?-*K^K%uE>MsaN$4d!@>DHkt-4etR>}vb2M(Ij6tF{WtlqgqS9AQ*~5_KUI2D9@>Rjd~-fhJ+t zzG|&4G^VxH?Up6bvb+NQ3MzKuE#c}oD{Y-Tft|1w+Er^qOL@f-%m9bFTCS6?H!eN} z$t$4Xs?1gAS8Q7WegMaTa>Mz0ohU5j?rRRrV`jcSN))(@ioITz*<0;rZ+RdXWIbBc z?+tYJ^!5*_emS!yC}#p*8E153q+Se!4jkZ^96@dQ<#pvV8C4l|87&!88OJitWtcJ@ znWoIUGIKMXnbnysnNyiBW}eEtlIc%yWNl8nD=Rl^d)AIDPgX@%d)8pqT$Yt*3Er-( z4BIJCqP@MdQ)z5zucW>Xg(fFoPCJu!B`qo4mhMQuDgDm$htfBtKbl^YUYkCfelY!1 z`sMW0j5{(O$Z%%hj9i6&1=o~m>)K8GrP=DVsLP3YHqI1`SV3h0r51wqi&*)+ds|x-#e%`nQDuE+X0FDY5>gY^CES~^ zF=1=M_JoQAe?lG^W-TfM0O5Uw!UIeZ*2x+PN;Gc{tIaNA>{O)oWmuvj26Ye5% zuWN#%WNC1GoTVsHRMZq`gT(Ns6U{BmgJUwEU|usv&FZVAlqjy7T98&i^eFj)1_D0@ zM?*5yAQp=x+TBAR0x%VJdQt2Nh1icBVpeE;0(vqsha6X0!Twk=xNn#d47K*;957K3 z_@B530*TT))x(9qt|J;>)4>_&DixvfC#D8W^JAr6OPz{5|Caon(l+pWb zRB&R5|HRY+R@$y=d*Bh$Tjhy>JG2$}KU$1TOi#~-^)2CIpJ9z_5M@=>HE^+|-??~} zUNAf*B%PpUm6DHqVw&7hP+07#@J&rC9wSVS=;~(P*~8pZ&AbI%i`9Isl8;djus%FG zCUrIVd4#lfyFH%rav2_DE`JIW%q*bwlJ*GEb?XSMw&XCv?uJd!3oqhqjt4)%qkykI zKEa3@+tr|G{{hX_)y4TSqHiGp*Lq2(!a~L!v$Glo(crMrvB@dgSM@W9f&!d8;&(;_ z+FZhn6~LeIJpz2{d9?$MU`Z$XrR{5!){U#=>uqSQhV9acVNgLQNXr-jx#{Q(`$Fqr zHSb2!i@v^n`-lN;C{LuYl$M`1l<+kh$})Sa{p_U;Wj$g;Rll4G8>+^-$~dDNBb5zh z>sPg*kECu--I2O8wIbD@+KY4$=>*cnRAX9l+N!i$()_8nq|I6GP1~H7oAzXyE6tNu zm*!6krcI>1koHAvsM}s)_uB{UqxM<*A^TzbG5ZPoY5N8HWqU$ua%yJkn$%lU*Qef@ z`cP`B)B}vcJf4aQ#+HjMjuuyTcJl0$rLDI4ZLPL$ThKObd*1ejAF)4b&$mBmf5x7iOiklCXK`Adv3M-i7Qdy_vd=PQnX??WoV8rAT(JnN z!J1^fVoA3;tZS@mt?R6JTkp3%Xx(hxYJJk`vQ}9mHu-CoM=TfOAGOdXKWJHMlM^iI zmK!a%SZ=r6W6^B#*%VBZoP(gjhXs;b666xIun$}XuDeSZJ& z@aXjHg1(@{mZF9cQipm}*~gYKS>7%43bg1&iO(OPl(V!C?JQMS2#r}aw=FJ1l2Z1fLW?2ZfS3!m)@zyk{@nww?(u4*H z))o7wCe2Q z*gRF2bSfAa9+wm#oR0oMKxKPBZl1V9WtkeK)oEyGgs&nwSHhGMfQXN_jO*&Ez^kQgozvQMUQQz3oIwIvjol=pfva(rnqoRAWJk8p=(Xg!4 z?iz*PO-S^2u*Y3$v`&;)vR>@z>tnxOv{c_$ayCD+tUncE8dQ@E{tSI=XuL|fBUaao zU2Pq}m%QLAoL-P$)OJ===S>fzLAL5Y(*=F1j`Ju@6*? zZ10$stEqOhN=Wq!E3sVZDY^UW|-{q~?Q^Rgn&;@1F_Fl1`N1^kT%GMn>-Y_iOr%b9G__djXCx z*_92A;TdfAczCNeL~njlJq{^9Q{^}dL<5Su6vxJ3$B3yVhiN0pnau%mDtS!tEP0Hj zXmB%bv%|MWoI(2HCa0uSa-9Z)yeGLHyvKP)`lfuq8bH{^xNAm@okh(#V5hd@LKE;CvwRmqRd0EZH9JI7C*5b=r{{Uiw z2tI^v6!OL#PB~(68MCUH8qPd}&VfPs7N@o0X0*1BegkC!5fyI!rOr~=YNM2VD2i(G z!5V)$!3a*t2kYeR!b0_Spl<6lEMV(g1tq0??+D9`*28(Q7l>UUJqxiadlzD7%p$L9 z@wdW{^P&Z&NvYGI$#s^<7sqKo39%R)P>RRPu$-|^(UK)VRG2`=s&ynpN+4z^8C*O* zigGBiW-IoOgM!3KjMX>=1!w9ifLE?jMbZj41DbSds}YA!QiCv-3B?uUV7|R7nO5^6 z_$zER3@G0U3q=7VrJHZIl<<}SWL)iD%fpf#8iQ5hOiDXx0%;G8LEbeiDe=TJBJm17 z`=Kksr-(g=rC#f$)XTdeda%$7+jLSY7jFI5X1Cf@lmV`Dx!r5BUAE7Q3X-zv&-i@l z*^X>zdO+mO74v=>KUP35K}++F1FgA`VAKMw9i5RH?>#%DfBH!W0xF8AR^mG^o}Tlwn97sN%aQY!gA!dt0% z4FdlI3SUt8vbbnGTKQ(lJB~%IkSv}O&qr$Q2rgkrYGu5XsGdAAO}ppumX+h3V;Vb2 z!fB%gCl6fY*^?vf;B@F5+zolX*K?n)?gDc0-f%tl0f;*Sn^%0E3_ZMpcfORL@|h%^ zPV@qQoB?umm*95Gx9Tr|+nE)74Y?ld^zi=!f#WMq0*4@I1TOHD&yb#s>SevBSDqNC zA5fAc?VEgWqcr78nUWj_OG@pNCo+UcNK7>4ICeh!?7=Va6+^CgRO*Oa@gd%Fo^wRL zW^ftj^h>{Ha2VDZHW|Kd$Tw(IQuqDWe}a59TC?hUsFZV!caLkm-!Hv`Nm#Y?4(5|D z`Agqg9bx|b^6&aza87W(uWKB~?c*q^zU9Ipa^{mhHt0}(3>LGWi_e|5@ zqhyCQyrz56s(oj%NFzf>z-U+Z3`^Oj-r!2aXofiFGQ$lmdUTEY*_7L5c&XbHH3MXlh4N+0Ty zempId!#18T)!`aO$yIYn<>8=wkETwBuf^|H_>zu*rO%x0V_++XkB<6XD=Xy HS77Z&CW844 literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/grapheme_break_fwd.rs b/bstr/src/unicode/fsm/grapheme_break_fwd.rs new file mode 100644 index 000000000..ad1d22d64 --- /dev/null +++ b/bstr/src/unicode/fsm/grapheme_break_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name GRAPHEME_BREAK_FWD --sparse --minimize --anchored --state-size 2 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static! { + pub static ref GRAPHEME_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref GRAPHEME_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/grapheme_break_rev.bigendian.dfa b/bstr/src/unicode/fsm/grapheme_break_rev.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..930d7c24439b823c8535f77da99ee46e6b834e56 GIT binary patch literal 51923 zcmc(I3!IhJb?;#`L`NhkF_x%Fh#`g~NSt9Xgb-sALv2baHL10h+Gq`dVT1$;A%qfw z@hEMnS%x6E>^TuAEzp13OcUhmCztH!K{l3)y%eQ>x)~|l; z>$iPlz@Odz=imH`fqyyZuLl419pC!)-`x4Pcm3Vne?R0O?)k^>+mak}9xoY*Awd>Yz*tltP^AlUPKDllCQ!P7o?%Mry z>odU1FjP&MHhsn~elc_ABac+iohM^2YTWuH z2BMK3c;SJ=^!m*MZ$0qN$V*3d9@&-ty`Ek@N8U`Y+vs)2$RX5Uhbynl4bFA)y-J_+ z<}F(EZc-?(Yh<|npn*=mqHe#hgjj~{yc?BlI-@0mMh z?qqtsHTRu)!{&{hS2^#|xo^$S(Q7EZ4mR8}_pOG34J{4(=yj~2Wx?$WnisS#XkJ*l zaKXY23l}WvMz5LlTHJU|W6wf#FsdTZ!B@LYWR{a33VBZdxn(-*(MKNx+h5ky)PiyS zoH>sR>-h~03q0>7OP4MK_Z3Y|E5U#Dnl)=7gY_FWY=j&(H#a{K%A#e*j@(^0PyNEs zzJ0$~^u?Y19{tk5{#W;Z>&q|PQt_2*zH;K$MPL2?*NVPY{q{-T@Q- z?3UZFy1n_&@Be1;H+TNU=z-k^9{bDLgT6NC{9hdyy!@|+-f`2nI)3ZKx7Ym5)H}=n z_O`pOzU$Y2x8d%oe?NA}uzwhI&%l4|_nn^iUVmSw`+omVC+=_g?%bghzjynv(p>LU z8C1`j^{8@<^Awign9h(bZujn|;iLb0;K08feT96pbwkOJ*25)LCCk^eG#y)eu%xQA zj$Q*xs(N?EtF&(0oTpFsu6+9TvaY==_e?G8x@W_#ma?wTG|}&Gl(qHg1(q{li4VNZK(;=SSL79+&I(gRT9=ZqnqMD-C2C`op_nD~Dft z>E+|kzO8lw^v17A*3Yha?gU}3?7aubceU&(ZYhtfBW5An59YIwTuCOAdGm$IA7k^( zEW0d29n7d_Z$?}aA9CLlVWxZS+ zpLlG_eJaw6W((>SRx9eYYuEXiFpR6lj(~VW8xTjcgILj>BK_xj>}r7*l(l(#Nk+_E z_ZTYVdWsC`X2Sx=*yEB|k{6RmF^qrDu8E_9HzI~_?-oY5D7r!OIzLH9fqVjZbY4OR zj1(9-FtP`cScnW+FU_j3)}7}?zoj&z(oA|9FL+(=%4ZJ}wnb%KMP8Uo5#b=W*8Zso zKj&<-J%p0!WaInyLzp9xnIC<{;DlB)aFSo`YT33^H0x3B8W@+O&iJ{{=0PjA=OwCm zB_D&XLwPFROsqSm@9box%4oMQ@^)C(2AQU#&3z_;6xo%}BhzuF={*llXntp>9n&L} z_laHZYVjyl^ScJdeVB8LeA>@1&jOJ?QEjzPNMWZl$WDQk=3k4|T0kn=8xu0k@+Q%} z_>*Sj7lpXAuJrU%JuTj64#EP&v-)%rzd}@kC8VO3IV?Q}XuOPDL*d9@K62zJS@7y{ z5*0#uL)yT<``IJ|$$mTovE?)dY$-Pe?t=8Krw;2A^m9YL3Ct z&av`Y#qQanndlRqDX@abryFLL^i*Xe83y?HIm1VjXr&!xbn2xU_@gLYC%OPe#Vd1~ z#F9Rpb`1K5YrmA0Mvelx2R>Ms=2G55er|frb>Rr0pYQ_$Xbi%Vx+&Qtb!sp z?;{}2MDsgy>eH#U7#@qro<|>joabgUi|Yh?yZQHZQ+aKQc=`1iI0d{YCwr>r({shH zl$o-kwHvW1h}Gv)S$Us`GXkIZ9(A|^j`>EmrIB_{?^-}CX#X~}wBCy(i*LF0>D_sC zB70PJPbBWsar}0-y)Yif)ylA2Ywb*CF~=g(1$?|W?F_=oo}%|<6@{?LS?kg@bQo9t zs?TS~ny2BqSGa4Ku9H`e9Xo#9TNn7OZ^9grv@g~SbJ|X`fW$3jwEdj|^<$&Kg|jM* z6Jl_{3s(v*lo#|=C@Y>z(yo7G=_{O3y#HvXnjWQ@)6>_8|A5n`$*L=|Jl>Jhcnw{_ zhpeVNqx|y>v&p9?+5ghmt^TCf?fg!d)mCVIa!m*GWs=j)%1Ps!ojJh^tInryS8hAU zN|xxg6~>1SNBvbDW+qp5k`V$k5}5hxbNT!$o12Yx%x?E-)!4?0jmOg1r7M>{m_)zIbzpM$^O#fU^=5@#E4(-4t3-? z(RE|THix7w0=U#UNDk~ zu6DP5oVU4lSp5O3{63|5EbmJu$J1F@{Rrn2d<@LbPIusRFBJOn`Rl&t5#g~0#oj$J zTsL9Gfzp9H&#!3#!_ph9S82Xc+6<;U_mX#A|5Q)Mlvf=)$ClM>e`m)!UU^is7@o3X z>Qj}77+68|r&BIryni>i;y{s}!-#VRU&^aij{~d1*zW9=#XHOgrTiTXDrF&KYsFWp*}e(J&;Cq2n*5 zvQK(%e&(`sr~cbMZ)ej_jj^obI^Hq8q-xt7vFP55dcU!wS6Q27+_IP0v;T^g)uOZb zk`Ln?S?I-&RAZMc9s~^$&ip~Nfq=e zt4Hg@dGvaX=L$Oxxu#n3yTjDmamX`0J|ADPSeULZ62HATrlQj%&kUW)nK~P#E=H%G zDb9O_Ik26B97l~!7r?Pbyp;B%Drk?8?3N=h;!-K>HdT*$Vo*=#Or3`7S;&U7EjDhi zNpA4VR9l4x^~4>`uev8S*4Zhp8c`JTwn{58nroiAL%40H9bV6ky>STf%VMV|K9yZz z+`>E}Z8pv1w{nZ+7e&`hcD?TtcEpWVGuw7jys05}HKIAN!nw~rh9O<439ldM`8{P= zi00xaKlL=WX8MV&sA;)pwS5q=YM&9GEFx`TXEd}$V#8;40v?pnOGL4!twU{v=d6AF zgf%8LX7_T`pM=iouLYhir-Y6oio1T?8r&WD=W^@ z>E$ANT}CYvtwv7TRvom!+4>zPPo8r9a1Z!%KSNcA{@X^rv2R?F7HH#vTYu2Mknx zrfsYh7$~ljr%XH5h3gM3ZGUH9i*$<~i#kg?mUgJyv#+rQXn%~&aXmprI$|M)tC9VQ z|7de9v@Xx|_|apGj69qch`Y5O}tHW`g5{juG~EYhRWF?mGMfw4FmH|h-<@LF(v zh8ST-!PpWjoVFr8Pz6)0o$C)4Z>)fMM?I#DZuCHMjE$Ta6*3IkxKS+&*hs9MVPRXM z5G%W-)d^ai`)$%n2Ist;xSoui*sGno6EdjqExBmso}8src}fMf4tf#$s}As$SjEc ze$R>L1+Ks0{kv^NB}0Z+4DU`mTFbZHQ*wUzmf_v;yL;jHL*>2jD!**_mKAT6FW!7x z`R1T1IA;*TekZy=c&osR-6Y(2={yZNGy$<6!;5>R72Uq3Q zTuheMT~0g1@Wb9nJBmL0XS6nUe4JK>cVBS;mW3U6 zuMy>g_`CIR`C{0M!x`eEpb&<7!myNUkZ% zNMA{A5wpni7Z#nXID(nY>O_}L7U%<-!SL0+5dFoVR<#Va)r_wx;ZYpW=B`-UXqH{pRKktwPHP%j6wdKRNIB7D{ zl|#JUksL{uX-HG5Kf|+l=@_%+nTGMQ@?LAp*PIrF$V=fF>(6m)t=3bJChMQ_+h(2$y1+(_OhdH8x0GMDs;kBNL{Dg4yr`n5 z_z)rww4Z`FSuf%d>+BS_fI?Ao^+I#;>T%-zA#z9=*f-8hqQ@MIELqWu?IzK4zU9wU zX|#HmYW@NZWN>-nNu8t0$;Le+pCxSUCmPXAQgi`sSvp}>a>t3Z7%X`)bmHd&A2p(S zze2Dhx&gE30QeNE%vBOIDteOLnAy`sH(%{y<*wEPl(Nf}jZ)`+jczRC;oVn{dtxYN z3$+)>_yVv7bG<_wkHxt5VX=laTqzY?Nr_^`BuIJAaCxK1l-5dJ@Di!&{I791!vo1BG1xmvtfZ|iCscAD1%lTpuC$ceRvmLS(PvoXJzjd^&5 zwFH_+SiH5zh`#yG zc&x}JZ91%DNJF1m&*wbQ*mN8@);>TFD@jKl_rxS(j=$bQY&Dif47HDNX0-O<&ra)^ zT=v3E2R65ax$x#+s~4)2dA&KKq8ORS#(u!Nc_{3oVgh!xQ)h86<8-vinOv(xyccF7 zUVmqZSk{-AJ7Cc|hf_uuVWzb)tvCxnZL30jy`-!xH3#*xUE!-sfBwT%QLZ>3JfxP- z?#N3-G1A{nOnSnERv#g=xK6O2tvkZ$J1?ocHbuPr z>I(YtI$GBQnbxYVo6bje6)}r4lo{o_!KNTqJ`Pz{-Y4RWF1VI2+tR>d{r**5`T9a& zY2~}&8_1@x7nesTX;(|a`rJ5vy}|&kq@C(WdJNU_DF>R<;$W9~%vHo(pFRfAYp($)&2aVCL&s3bn+Lo6Q86-NtpQF{$NCvP)xFC_lgB=~h8$ zx`P#l>?9*o?Zqw9o=VKe@A!tDh8e;+jpIGotG1J;+!xSYzEu zd&imV-?KVCVZG`*mUUdmbOosUinqj~iD{QL_f-^I#;e~M(O3Lew5%4L#rM6f;{&^r z<@p&S=SgS0rkYoKjxk4P=flLfXPOtk*L8ex&a0+-PiC)wNez<|OjzK{%OXV|0do-<|3cTUl-yTZDnv{kduh-Ht>Yf&qvGHn%gQ|`Rh0N5j2 zX^pp4veLj-X%$9u&8l03+sYx98)r-tFsG)^sP4%P%C0bO$-Qd(%nhtxGWns7&+u!9 zUHN2TN8D&N({v5R8#--`Gs~>|Qv1_^RKK#lM>lj>HvX$_Dze6;4QFVOE zYUO35vrK&{BkYV43pzn-^~J1+P3no8_pFW&%uw6r^F70lEfh8>SKE;f7>;yG9_MJA z28-6{XJ6JBY0ldw*j7-5m)pm|+T}f}<1<|2wyD18n3mrqOvyHh7c6wd-IVp-i9sjI-1HMU&A+YQpFptI?vSa*!sN2HQc7a`Z&{H>WEa+|5a}{kBRIjP+xId#Ik1DWkf^P#+g-8OL@GRkQ&%ZzB$u^ugNd@VmE2 zvmIW4lYhQJKm9J6?xD%k&upEE?4junr_B~J>t>=IK~(>^>IPpqhcgZ(ReMhO`;UaR zb6PovXCm=^Tq{s>%(cZ)RlHQt;gi%Vx}wU54<8F<-^pv2&Zl78+upyFt-|ycSnzMPxS7{k?39Jk|p$aW2pDa#zuZWUVdA$ zWchM@gWe}kuB_zVI?%uO*GS5tcaeC7pq}1y5Kqi=mC}BDO$iCXoD)o-izqojBlXo`&S)zj+NSP zlKS>Oow7BM>u~rm7_r7j>4&B5;^Qp0%vOLQKXhxD?=Skn z?LRm-dhUb09^5(RmN5r^IP`~ajV&L0`bXtIdVSoYA7Az3>EkaOU-gqqe=`0j=O{Na_;B2Y9HR$BD zwMU3GasuOvFTV21oO==|BaDi!c0ldbwFBl1tly7!b)D!ZP%_5a!Eua)(w;2xanD(h zU|p~vhE}m=B85CLGUQpi2lAXl7+9X?>EBl1oznyIB!vAP;!+@v@TQ^Frxoeb7GpRO zff7#`Oi1#;fk@x2HG2bO&^RND5Db{pw{8*MM_Mivk!X0HL8B*Wug6d{=A$(Mu5FbCnKzVjX!xgi7s3B@)%x%o82ysSQQrrLy(O=#-O6hd3iPL^kcvbR-m4 z({DAkZvzEmBrGZ)-~yT&jtnd(t+7!=h}>HFGk0OACrC)7J0)4?x@B>ud#YIZXN>>SOXRVslV%1hw7k&pHGd+K--ME9XoslDQ6vJ$aVAn`E*UkWSL? zdtT(j{(DT~thWuuN7hH4(j78Vi%k3*SS!9|-?=W58|Kwea#n6?ug-&=#u9i$U$x!I zR-vzGRPV7l^$$5|DCZucdN`6&a@2Olq%p`p;UlmU9T!%LI8nbl;^`wf>BZNTH8e!C zv9EZ;JRDRP?R)-kWS_P7sPt(>9+m7?a~QCN$0FXJ!_U;wNy@3COWxwg<~wTad;ZX& z!!I2@D&CPXI_aL~vbROrI=1p=9eeJ<=<~=w9D5nxpBXmer;T1$M|0RIW{;S#zqSVB zN4!Z2e*8$^GK)=_=1!2Mjtx7@9vLz}g^^_rx8u@#$Ud^_YRP~cgtYlQ7eu8Y7=WV(Rg*;h2I(5u<(~0NG8Zkv@ znp+r&B@xy)K_aR_!RcdTeX(RJfK%GXJg#olu`mOC4!QLpFd>_;`vT%(Z}^2l+|b!$rKlDe1f6Ip|tGil02+a0H7Z^!rFLtUiJXN>I#N{)C^KcKQ}M~iV(wVX2&CiXS*cwmgn>eEh}GCwD9 z@XTk|GqU5Efk~xAJ6OC^6vtFQ7^rIdi#{1qDKdJ@NlARU8{B*(-h~LHnS9Vl8fQ;>p$QvH!$xzN%eCrhJ|oE)T;#L#8+&QY+6bAii;wnro#g!4 zc-o0ZG{L?X^%$I$a@nI~PbpYc zmZEFPrS=^<^b+md96Mgu;&e@TflQFol z`VYlSxj#d6UdZ5fm|e8Ax)%?UtV`r8XV$RSNVtz4J${^!(wdd7IK?oNr!!uIb`ha1 zwP*<|bTUlWkQOstBXj4QrmB>EhsWKB0UP4X# zgDhXZhR0W;A_15pO#(1z#dqHDnpv(0hSP|LO75INx_Nym@_Jt3F4 zN_$?4pAaG*)LGZ(}EPuRZfboXAR2Sr`lVvPaB?g~#m$`wWf;$zNC?w*zwf zIuDzn*`bbbJ02YIA{KSDi^`}=`KMYA_2IP<-fd!P0>3`DDV7^3`Y^+ioqvm7P`k{O z@khAhsOxU88w=m8s|r~l4E-Melt=8jD%_eb&Qdit^#hoHEOAyvi=p|l@ z-4hGUD7TZ{^oP7dt4aE5bZ;)cqGWKp$P&m~aqHO!*o%)W+qQ?2#+BIsFR;QwtfU1m zvVWH|Vy;o!u$G}w(0Zv{&5rU2!5T=|BK6sAEDjP%cqPzAYjCy;*mfjc*fXI*rVHub z~71Ah;@h~|_;B-2^jpF77q7~;d# zFuTH*NNi(53~B9YvDi3L-rozb5;BSwwQtibLgz%}x&i$T#5fC)L@n96KbtHP4dbwt ztY#dcWN|gmWf`>_Jlfg=Br}#O%a?XWQ+%w3knz5cwDCAKCyG{)DqH*HA$nM)N;k@f z{e3s}x`MX=zUsJd-_fINpNIkbC1&x+g46BExfn2@76=!sHM)OIUO@?daNxxeg5twWD(#==X`aOJuH!zA55X+Gbp?2!Ds~a@@nIQ+Q9O59zEO{iN3P z34Xt%q2a`dwzk^Q7%z88bv1gWw)jhGb@C*>!8>V#cPCEpXWTEnr9r%yY)`6m6mRM=3j^jEbL=@aV3j7Vrso^)v5r>$RoRoesmym>4Sl16oPEipZH zs;v#H9Gt)OV+iBgiS!pVD#l=}4(*AES#@fJWrD+%M!vvH&w^iGI6OFpwk| zg~%c5EA}16X=wQEZ&@33_Eh>>ut5J-#&HNQm07~e7~iuL#<3hOk?%zVzzxY_eAo?J zO%Yl!E4C&X8Kcgcg*CazNwvV^IxPT`;)DH&&~l&pO^(^K2QVgTNoRJ^e*S!nMDH%Cwieo9-aN9BOXV|TQN%Tp0<_Ck z&H5!7%E@0oHJ)~V2HLoy2eP>nf58(>{2h37=1F~)M0Ebwox}cB-;yD}8p= zV&~+iW}=riPx)%~uz&*VaUthFtO3!uMO>v4fCd)cYFe zFp7fFDUOB)IeQLlbS``t&ZbvY;RJePKl<%D|14C#!v1rq0ITIZ6V|g}0WyrHCfXBP zBPV6$bTUh5F>_90l23qp7^60F!`b$#D*RpUnn{yHS5v0QdFsdb9Q7PtGb8(2L0LFu zU6jwr6OvmfD`Z(rXsn9q$c-2u55MOwkvm%BTs)1-62M7&lE8TR4X5qto4az?{!G@w zgppP?bUj^a;$-fXc^5est$A0=$zeIIE%t&w0?VWmrtxlXwPX~qz4`NT;)QbD zRdTIuE3bbqlG8QW9+>TaG**`PW%FV^qB?>#C;k=fZl-w{?`1DZdKgOyn#=MqmSS9Y zjRR1J@o*LDFvyO^P#mD&q%H$?MW0*~`BqiZv*1^fyQlkAsvQM5M7Q!28qV)YOO|B% z(gm`HH(@NtTRnz8dzU??I>lqI6`o0tnLi&sgG!hTuc=Cn7#!Orrdx?da)nMGo zQvCG3M4!`1Qi>4ok}p-zh+{FTMUlH!d?`7X&7TinTCya4He+u}ixK(RzE9aw9Sr<| z_|go)C!0j-V4R$}=Fe}}vuqr+?=$h_E}cwuOpv|AY??vY>gabyhP;}d@7LkA*YNY~ zSyVKgIfI|Cy+%JNv*OSA-I+7ghTfeygYVG34K1mSw3XJFO8a8?krf|WmzjhsE9?OcBUAC+X{k(434a?{$MHwwdnif}>KCp)- z&*$0^^fUmyExVt3^dm}J-|mKG+$z`6^+$+YFF^Bt_YI?U-}Ps#mrru1;-*G?s6}a_ zm1PV~_%XPjWp@WCd8DI9W4$Ega^y&&#rr4G>_B$nv4~_9t^XF+t}R!z7|fh5i~5i~ zG~4EeWzr8?;GFiww74$nqd4dT`wMm?X(hS=Cmk(p1N~giR~6zdyaujgP94rf{(1(U zEZ+7SJ^7U0ouR5_@z*o#-);CwYrQkCQ7xnU9&PEfv+~)A6V#S!|9B-By_+?wO}?cS z(8-hh*XUoK(+n$7A5N}%+>Q%nNzh!nAM5TA_TAFGnJXZ%0`i_r&;He?-x@zIZN_td z&GQ`9n-}%ov#VuKF+T$rb*bXdc;auSPv<&3^bjf;r%YK+>pl9peECHBohn49Oc^Udkn-@kw7WmT8ob@{pCNmpEd#r{s?uk3c^3!N)J@XZf) z|KQ#~nb75iE+;-T=c<7p?)>3BSC9SEo?Sb3J^GP3*W7Jc$Me7%IN;@ z=&x)|_sLVib7-|4Aw``ys?)Kf7_mw|y;a+DYenN_aO%}pe;s?~ugZb;NZ^5j2KZCu zhStnfTUO8Vy+=KRVai<`v_I6WI}E^^y9;AS4D~JyR)X$Xw&>Z*&)_wh_RpzJwA8*m zVskeJX)V%lvVgq3tW$L3?(qS6m|B0bB4;C}<{o#ofUU7C>|F=~y}=$*HL&Ur6=wqt zU_`G0BY!id;DUr?)Igddf7W}@m)@TtA;S*8!~FoPHy9ZL8^wOLB(!oKnAxMXe%!&q z-HSjuI4?ziUU$xh#7|u-^k?lM;H!NG{$Xv+cptc1{>DN>A2fHJh_x4wirF3Cr^2yJ z{foHWLB{UM%Azy99|&m!tu2RCJPG-zKRP)AiD;1eRD0G|M$2NWPRo$Dm4`!WnQ?zA zhg91}>x6wfUm?42I0IktEofXDmBE1{m9d%=iThb^#>c`kwe*t1v!k4v$csp(&{G}ETlij0;75sX&i$2fUud!r?Mt= z+REi5nvIEX%BbARF|hZaaxBr0&K9_?5ZR#iCi6083youLWNn$qBb@Avmy#_wuIhb8 zTP}Ce*qvaJM{b5|FrxJ$l^mltUdi%3doG9{il6>9{c%dc8%WJna}KgLRAQJhi2uiTqXLltW{1r}r7ObRJTBTF{sJVJu5AG7W4=vt?Mi@^x0?a9R5`?R@r@8N0bJc$vfrtDPtw zLnl@*2@g9#mK@7T#rC*QgOTmSMNnnqw3nO{OlB645U$05dpkH&DfWwOZ9J4SAs{GC9*4k3+Qr5kWk?q$>7AOO21A@?-+S8YxnO&^Y zUL$=$17V*|PH34TDY2Sak2=g6A*Hp-!q`LJoGoCeam(X2Gr!^qGJt3=jCP(fJZ)RG z?)7lip!*`$>K$WcfVsv0U1W7?N3op%Z5P=mq+?e^m@Oku5m{<`r+YVF`uQ9!8`q#E z?Ujm0JG-Y=!8(CkUBoVm{GCDJX1s8w6-gLvsvKm!?yObY86Plnm5q&6FL3#6*)f3B6Rni3@ic>seb`)u&sk^LHW9Q z7p<*drs8q(vHosWx9HXEk3fo+WuR@92z!CDOSLqxOIVw;T<^JJK@OvDLF4KUh1wX$ zBjY3C4u$YAerF{U)2{M}G#l7=7@c)&>euKd9#gbGXeR2@*e$nq^NF@~oY7J<9@clr zTeQvGlRE^T%jAV8mfhR2*^Fkp^Xxw}3gi|{X;jo9{) zo}Bk`6m)1sxz zQ~j9Ks$Cf-*cb$28Pz|iT-`X{^yy}Hqz zjoR!=#wBg#S$&#bw3Q#x`J#>&d2BoW9gVBDiPqJ#Y*dQ+g+}vfHH-(&e{8=FYdj)o zYbT*(WHjFFQJ_7&@~$t1pJ@q(mR~HMXX=V$v#c+T9%Mdt%-FjUnlPj1v65I00-WIr zFP|phw_qhRxQP}TZCOf?YuKk_ALq3-UV?KDI$-ZWlqLs`mZ=0U~vH AjsO4v literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/grapheme_break_rev.littleendian.dfa b/bstr/src/unicode/fsm/grapheme_break_rev.littleendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..b4b5dab9c1ced61cdfff2faadc716e7a04856b9e GIT binary patch literal 51923 zcmc(I4SZHdnQurd(lm`ORu(B%tcX}sBmpWSR@BONU6y6h?XoP}wQNNQX`&Pnk;Rmz z;X|Z>ViHn5LJ}YZ2;nQ`GlVp4k)^#X%TiiWNK&sC1I0?Yz1&_eyYrvtJZGMnGw00< zR@?qw^5%UfGynhdHP6hM=bRZod~D`DGrs%1@6NvG;UCV-fAry*58w0H_aC0|*mv)F zWXi)S|8=cfN~-#QX-$g$Z)qz1%m{v_bW6SI<_~oLV2@kUZcV=}<3k_*vz{Nh{iD79 zy!XfY+|l>rcYdPZC-3@H|4$G2%)rmy{khD027P{TR`!sg!|wgU@Gp+|(#S90_mxp! z{o2>>|HkOQc;GL;`B!89dhFkf``hu~`u5*F`1ce3Vd6hd`lpBf`8y9!{+CC-JLP** zr{zq~eKars`#+fR*vuc!`qAtk&-uyRf1UT!g2(4SQTSxhf`y9~|7^+6mp)azZ28kG zeo<0dwzB-0Rjb#mtyouCRlR=0#+psFo40JO+g87Q$Ie~58=l>>ci;X42OAGH9d3TE z<@pz0Jo3w<|90%9m;cA{e?RdbC;#)*E2m$5?M&9=qF?(*AL{`Wio=j#7`_y7I=|6lvBl$4L81Q?1IELyze=RaS%^r@$cSFNV8E35YI z!$4}JmmfX-=*y4(`q3+oUVHTByo|iwdDkAjOT9Al?#;{0yI;M==S|8>N$Hky+il}g z(nYV-=jzp!mHYM`JUAwQeEyjHN%>RqAF7#^KR17V{=)pF`7822A2>eXBP^FvpDZd`uwdcBMbH_KRJ`oz6)S#GT2{95 znN=jcigoKME32xitJiO=soAu7%a*O%>g%`f+_h`>vwQaJ6-dTE)AG!zXD+ILA6hkY z)qM53vg+EZsjFwLE?m8Q^_5jAYp$%CqFyK0+_(11sxfOD*B(=^v+DIgMMFi4dS$Px zShqvH`c+n}TdH2wm3^u*tCG<{ZobsPS5x}U(=6vdVe?%4Gs$$>^5sv1?Jr77O2K$# zdHFNMdd=Fk6^8fv4I4Is`=;93&EUVau5KG-uzkmlosh%shK6TtSu`FxG$Cc-y;Ht0 ze0b^?o4&Yw#F#Jj8hK^p%U{mDug_Q7zEU~r`(I7{TJhHgef{*;=iT4$8%Mt}cl3RK zar*-e4?OahY2R%6=8V7UH|Fe^6@UG;u~)~Q_?wz>Q~q}F`0n3o`&Qkz7yez&gZKY^ zuL-}Ju;U*VPMr0RQzwo6r!fzW_~*>;-1Tt!MVbMVoBKXKweT3=Vbxua!L*6Eg_teULGy0f(>w-sfTWfx_Q zQLl_4c$Hpiq^$igGNhweDic)0h_+UI)@y*#9IX!F3TQ% zq;Lp0O;nsN52-xRv>!ifpTDd=mCOzd?HmebUo{Ylz7oV)L3u!HdKrcc+g> z?$F*tiN(Md>t4Ju7DI`JjJQ6X+z1mBqe3o-xf}M>WaaKe%ysp0V|?7$^l8=$XAA5V zQY-AW+v?3sXvbAyM?l=U1BfZskQF_stO(K{_+sN>ctPjTlLy#dq7k#diwe0OBSX5m zwgNIXxG0t+#6(iG<6qqiE-H8^;&R;!g+op%Y?Vr4BrnXRh;WeG$QB>M&l%h73L#}W@%aAp z6y``|=B=*_oY1NtCp6o5xM@FW)}S17*p(yC_;)8lOSWeu%6KUsgRX6PGTvCMiw~tY zA(oL;32o&8V~3qXAyYrv&qk3VyE1vCAE!_632;L5=}n6d5z5JdT{a#zC|UDkbe7@f z7YVhWSe{8DEq+#NfAJys^%5mfV8x6eu}TYYBMvO!o~TUYyoq#A{=^yi4IwVeKA)X= zP~tuLJS>1bD}5OG6`~R>!G}7S!~8LTR5%$ZhY!LzqgRIud@X#@WY%~1xF z{TK#h%RUB>{k>7yFA7$owhpkQcQa958`&!(zc2kinaXJp^pr~yp#!Bn`#E6mG1hx>Jv2FQE%)A1YR^g8;unG@y z-m`dS6AOsuH8NMjGWk@r~Jsak=o5& z%UsXqr(0x(gp8Px=RH@JUGRJqd*{%x&m)G%N5R2SD*`PHgl@|%c9>Q-qjh6`JI;gCut{q$kT7Aelq{7#(Gho!a9yqQQJ z!;I&~GjnxZbGA6^AnqV*l2*w8|lr#gA%ielC$tf;}p^C*u0Fi(l@xC&%O5iNMOR zTPy9%X2H6Ek5>j()_D+qlMEZnx_Aw3$5pfHGubicX}IoX?;84b^7`4c=gyr7tqXi= zxATs=ZC}s~ak{4VBY1u$M%VO81vznI{aDf9`dKB%2{G8>g)0Tu%L{r+mKCD2_xeYi zzU&#r_z!2Q{wS?E^?8o`2b|{bVqIknF}gy$hOXd4Qd5Re;&}#a66%Tezc_ZYKk;=t zvlAw@Wm_Lz)4_Zh;dF1viC1Qv)gpF-7gn7QJjdK-HBpvmv}MPK)^7GJ8eG|lMhMJE zU}mn*CGxL$ZZg_wcITT}W4SxeM!XB`d<>K2XS0jdU6h@?j^&FVbmbM9gRMK8-?=G* z-G>D`xwqM%vIwa?n;Z5ObA#PPTX!xu&yM%PMa<0PnrxA-m)TbulVsJo1FWi>Y-6CdFvrc8U{ow;#;{BZ}y3ce4)|EhT34d%Z88t*(;BttGxBb3C4f*^h8e z!NkDC?05%`_d=mBlfNE&2@xJ^Q0(0+hI8vrY#Nh&wW+ZV3 zsaVfUX{9u)sYK1m^@ot9=MI%TX~k4D%#9fMeI!n~*zx|o;EDr9d=A6q48AI_n!Oc_ zl4Col$;UQ#sLS@G%DpBH!=4jf{SKrLi?aUWACqwxTycJ3KsIX=5r*HBW^rY~aJ?L? zfoC;g{r#0ay=|@x=8M!*y~K!j-_sCKNh>3|8|Tl+R^T7hpuMDF+QIS zuf-J~mowt(ipF@>q+v+FuVdxIKC6y;Z(`=ObI1PMHSf@-XC9QST^%nzRFqY|pDemk z?dAk(bC zHd$VBdNwO6b6UprWo6Te`F6!MNBc46q~1D@r7VeKv|qm-raUXTRxQ^dCc}{X7L=>o zTzzr++$43KLt1lD7W7K1N9n`JZf$#Jz4j4YVaGOCpC!LXOpP7eJpJ+cT=gbmn!1(z z_Qsf!PNO{iIt|X$$tZOrIyFpj-qX&3Rcuk0{;Y z#O^!$No&}dhsJo8AkBg87O{%aYZt>ad6w>333p{}PLkuqE}crYV#_3T`m!dAxVpB< zzG#>ZA3{vQlGfWJls54jEL3tmpdt*}X_1aJk}YU?~_)E2<~0h{64 zriygPLJU_a`?lY7hAp^@x`VMEq! z>TzVnKv>lgU#)@|itB}_SHbm+N;SXZ^deQOpss^XF;FEz^wb3;>&Z8%B98L0=qzY6 zu~!f@3u3?DaMJUFuD{Xycd7d)W#vxmKdrH@ChMX7SF`r0_xPP(`2EzhK{+AG0W@^Eo}IAKzEIx99ZpIm{@I4H$W^PA6hy zuFEi^&0BC)w@WsI_p_G3rgopv(J7@Puwyp&@2<`v4H-5KS~smqKR&&HN#Hl;{COf4 zd>zJczA{c#u~lvMT69oWbJk9+j4oPttKL zthe*9pqe}5A2x?cyP9)|#oT?Dwu4KmVw9G2b{?HWG4I%oX8;nRr$@b^>J(<5906Xz12D3^RAA%lQ#FMC7twC9wJ$>b%7mt$tcWv3Qhz_ zkEgv2!;f;n&)6Gc;JFGfS+Fi{goWBY*Y+Or!2HIQf$tR; z=*7$x{nOX*;YQ^A_8P8x=q0BBB!xTpf-` z2-zA;)-J9O56%%X9{fba7#u+a&qIu!Q!C{YL@?|-^W0<3YXS>rF$wDdH7Z>VnAQO6 ztgWZ~i|2U8RGssn!qu!ijO0Xf{MfCKSK00;y1PkM$)MxfI^ zOUs2UeMkpJQQBwmjJ8>xz!)!255^ujgK~1Vov$N=$V**>tnF*{wy#2#2{oQrj!B_J zMUm0?`8xPYhLR-Z&(OIoNwP~HQct}|oab~|`xmEo8||KHJ#u<)kytaIh1SW7G6Nq% z7q`{-O!Lo#$s2QtpaGVr$H7> zXRmKW(gA9Y(8wAw6B25&jJ zwN({j>LqDq$vLQ*?UG+zn)4sBigFY2pjtjyId~W@M*7W4`k6}lSn(sSAi`h=6`V4a zE@)Ovqz{pkNPXDMT%BM)n|Fl$J1>4-yL|eQypU=2-g0#p*%dQmR?RudvJ!DfvNAs5 zGP>?sJ|7eIjUGA2xA)$HT~*uCnseYA$Z+pe*-E^Rc(0Zq62;@^D-6(z?^H+BV^l34 zbD&y2wlkXr>jFOBtgd6h%1&*8-z3AvvM!zx?3ilKsF-U$oQEaLC8&9md}_BdAKSj5 z8RFErnd25S>eOqGuJvO@gX?FNoPH34EnZy9cRjqIr({`SF7fQ1Q5C5#9@sMqM`_%0 zG_KYoc zC&>x5e72tC%n4ptOHSIw+}_HU&JDKUIf|aHnh8?Qjn4P@xf@}Mjd0BflH|z>7nGT!8 zHNW`So{=i9!Sb%|AE}nlu%cSNf%Tk4kgmXp_>}B`pJ9F-KAmil_;Bn<%*Y!xjDN{W zDxZdA24QI_%%Ul7oVzd75>@hn4_^U^KS6v^V%C^zdq(^}*UZH6LeeLx#R&y5vc# zr48cR4@biHw~h~tl4HAMn~&|1=`LG}kJz8VYff!uZj|-=Q^!YKajIanSaFe7jb?Fu zz;MNCi#^lT?AWc~TDL8Z<@;a9M~sJWyP6fpxQ9N|hHEx1XGGN_TamHY8fMm{VMxHQ zj(m^;aij$fBFo&fR1clO*G7>dFQAFY%qLtr^z={CwZvIzBL~ z$x6%^Igg)laUE8BhB4WZt`Lo(IJx{gmW?LQ5ArIjN-#|v!Z^*T^+g}2&V|A6PN$Wrx|*oD zOSV|E$;u&9!&i`ZSyl3h>N2`oWYyi(RiRC?^>L;@|A=$SO$$>qW)PWglc|rR)?Ck~ zE0AP8TTsnrw~`f2st!@q(XlkRKiyLH7uLt2$7Jf`3>(AMRHB)0o!Ti;Q$}sNu8$)` z*roJTfjRxb9?(i^$e>~=pha@^aXdEuLP}TFvRQR+%q41Xs<12u7WWVAj`j&3mu z>&qk~OVU<-ob1P9;nc_3EUcDJeVpAgg6$HjXeBmbBO!L`1Cs5Q^1Cbe_pP_}zn5c9 zZXq+0btaU}^A0Cvx0Ef!*3ASvf~fups~b$^9L_itWwjkK_aCuq=eTkX&qQiGj0$qp z9CKYYKMjd0t)urVgKZQ(dHVF^ya_2csdoz&;QiF#x7ym>yYbu9JhZB<#rtmR-DLGU zPTNk+!@I&K(Q1x<*V>An@Y$I&!Mnos>nG>U%u~G=R#oBsoZz?h>uYN84SJtHzpxO! zsoo3mZ+m;HlKrw}dFuUJZ$Sf{o%p1!4ZXkh*6-d%)NoF!)6>;RAN;g2Qy*vRgrAM) z)G!HM=sE%D0hQoUE#Q73t|ne+zO3$scX>$nU(RZx+VAvX2b3=GbQQk_x}}^x4MvbV zq@J1rnM2~;)H_I~px}uo%JcF2?%i|Lzpbs1#+fttx2g)C)YRbH`SbB_M@L2eD04#A z204=(*+)r>)pH9dCU%#$;x{P4;T zb7q~NmGh&wepEU8_8%|)agRAgb8i00oS$6%NzvTC|9bRaN6kAr@BW{@{L^n2yjJl2 z$KQQ?_WVopi=Vi+@Ic|jC$BuYyeMMDa(27{seFKsD#r>v!9r22VW{mfQBvr9*- ze@B<1Wp?RB^(lU@$gjwcqFlI8KOJxdRo)78bo$mH#MRXZ##df>{q={+U6hQG(Ty(c zr4WrNKfV(0(#uAd0wrM_r}0XR75Uc5BEHT|wRI#Jioo;X4JZYeohB9W1{ zNs=V7;pLTDqon1e5s`*hBOV6NJ2Z1d{dNx?=oS)l5w&Qm8(F$*C1g@kdR$41wb@eQ z!&8y}2@@XzeJ&0x4$qzxbsNy3!E)%>OD9e+4rq?`1`mKtI+UJ(V|Y1ie{^ZOYGbS( z7LWgfr(B782wkTcR6D9_jS33|Fz~&*%yl%4g(PAl!FU)qU7;CR-l5(NQZ_`0@HtC| zJh7LO7NH95h9wfz*sLZUnX@Q_#z!nrPHD<#>j@ybXQ~dQb3(E(% zfQBLiFoiWXj0lmND}Pq4v-JcCk#tNP4rK%jcJYwL7}IfWJtQ4ShNaX?>5=5~arP@h z6XICARv?K*uuAn01h8M02XxazON1h&Z`8n2xvs}QYVGD2_OK7;9yc=N54P!L(eeAm za#r_Lk@Alj|J7IH#=oZIL370Mm5jhA_fIkcL^Ec;8a}d4)>qm7VOhYdubvHLU`qgA z0|fm`FNO#p2OkP?UYgF)F_Kjw5_=ansT|?hOC%p4IUB@TV;lIimwJsZ?OzHRu|>K+ zZM^sv_S%=_hS}eioRk~eYv{qOu_zvv*6}jG$AGh!E9_Q-Y^ea)kVi%Ivv>OL!~s!A%;^NpBUOF*g`AN z$0hx*cXTCX@931bn6dR8HIBV>>eT61TU*IH{G&tn$IIRgvL+szc{|*#(N`<~2-(y4 z=FG4d-#2<$S%;c8z#f)#ysSizPrTEWf{h56-YGMv3Ph|V zRJMeyY?(CV)OP8+>A1Nv-+z~M#<_)%SQKHcvQhF)@>$B0$yP>}rmdt5jDBay@lT%9 zEAlNX77+w-UCEE4hp{AFcT`ygycdW@DBFbhN|`Z^G%YC_5td~1R*`=fMQ3A2;+bn| zmDd;?Mgo>jFmDk8 zWEnhnkv1GK-&UP*>a$WQjs6z z7|;fggf&HaZoeTM$}{v#0zHuCkC%}}CXE976d{sTlxIjRUU|TavrAbTG-DBx(JQk{ zT`V)yXEd)Fix6uQ$b$Fw#MS!brDFU8IwCZrpZc=&(tb)ZE~1O-GlS|8WjmxJ;V(eN z`#647wVS=Nk^Txil*Pp1VOv3TGdLpohNwmeB1ZLkntu$2J$pl+Idf)s7&CwYs|#Z( zz4Sf=EQLp(YVDR-(F$@1vmFudQNe++DYLUiwmpTSW_M))@09V#Bo%kmf#y!*)~F$4 zUct+I+3?)QvD}gZAsL|dJ@AesK=v?F$pF?kTCL;ZG4!5d2hBJ5#6>9fk=Q;$*&rLT z_GWmWLEVB%tr@+$Gp9~LQ&L`Lrs=101(F$gHjpNV(up&|cGNxQC}-pP8^+az7F|@7 zGqSH`m%_eWS*d$PSocxa-V~LVT+h&ICI%Br=}3@6yO_qU1gepNK7lA(?UIm%NAV3X z^O5W4&j?L&jz@Pxi$iwS=#VViV1o{UjMkvAG(r}Kt0G^?P2Pb%f{t_;SQ_JtL3ZZM z*$~^(GDyzFXRNGRA?4Wv^H)@6h>=2Wdd26&NVU@&WT=dcbPDT_*q9Gnx?TtHT!NLU z#FedogO|G2R*|owhm;%pC-1|DmIp7zzL(134Mx7#l8$4|&B%Ogbci8Rc6K!BQ2V>k zaAh$2+6Y^_(d;6kN3d5OO3ywauBGVFut$QugXn?1-Md#tG1@q7l(5pM9Pf_Gk!5Jk z>*y;OVZ38GZc!KBV2M$j=YC&C{!4q%jFU1s!iZgcip@4kp3kF5J@RCvfwm(Ek>Q#8 zhXgn=V;FxSoS4ZdA{$-f9S~j@N~>0*3yeO$Irmy9&9f!P)s7A%Xrw4H!lwyiwVw4U zGmXkpw zj<1CNEYX=cSK!lL9inSclEdy3#cD#3UV2*V7To3rN{LtO(ekhzGjmelK9!JrPG!rj_>?%Y|mX2caI7c(Rbye*muWL&AT znrsX0LwXLF8suj-W_6A1@%fCGrEJF~orgIQ-o7slJ?lW-jNITQv~+bWDqrjy5n{TA z2kT`ClYH5NZM5nxb(90C9g2mF);_BnTni56EOT5RYTQNLK@Pl2wUtQZcz?B|yS`eA zJuk*j`q*w}-7RpVysF{fsuxP|o?+;lA)IUmqKwval-Ys3}U z1Llzj6!MX!khg93v@(%)6XX&4iju$`MixunjGI?>uon|q_8+h$4LRF**+QhG2`}b5 zWRN^Z`(zwOLFuJ*HJi{X3B$522}`6VyLIAVgR*8q%WH7fHA@%vY@|C_Nte;0B~bei z3tJ|i;Mi^rUbX^vso)7$te2lFCKM~X5O=yLmQ`L*Ti_ity=ULF4smDBM zu3#)cUv)fothE*Pi5PG^h*?Ial(AEcWgP=yb!d&OcZpK(k}*Cb!>83#1j2n>5w8qF z*e7eAt`s#=wgxW;KHxMGBz+=-0K)F-MH=s~>=UPi=*$a#UQ+wwBuSFuP3klu@|oGC zGfL-`c1u~ic82=5qGDd@O)0duLf@pSZz?Ld&Fs=t{df3|dg$oD`_^taYuDNhtvfpK z`%UUyTU%%641J>Hrj+7h^g6o~t{?%-BR9uyCVPQfK7Wl{%T&(iy0AU+S?h;2g25Gyus~(ef4U{1JWoi2Gfp?&Q7dy zaQ@PaL5$}qju;hV0INaU7BDL=246^Z*)sH2QPI(Xze-IhR+7gzKvhuzNdPhT*4fFu z-IP*N0^HO$$;JGpM-IMA)h*Eu`XLsn3N_9@LKkR@eo4O25o7^wHwPHrc!N-o90;HL z9qHh=zeO)NdkS5F0sk$H!w7Fqp-j`r7~ew*kTFov_dqpIYKkIgnlayGxQPN@f=B%MQA^c~9*7-3gHOMLhn zVh<*S2@*p)aKcDvU#zW%P-ov{Bw9pnK=cVb_Az@ zFAwSJ6mVahrq($Vozm5nlTVlFGjXuDb?el(rcMMZ1Z;%FQa+$RS+IaVo0^AD`|5o+ zv{iHCLOMOX0?&piQP1Y)ef#QKm1$5E-=puhe(2EY(-?1ZUU>u;A&o=FIM%MEv**Bu z)6h7ZUQ~n==p)qcebs4amY90ZgSwVL&)_T7c_w)oGK|_OqWNt#J7y zM#zABs+N|N7*4bo72)stD2b4+7A&Ci)KBYk)a823jBI?9%ED<@qbDRcs;m&Qm|In( z`i^P}3f${zq?|t#SNOP!;faU`K((?3sn7$^kKI&l@0e!@In31S?2MMe3l}J&C zF+xdP#R2sj)n&l0X6E%_-ztiF7Ge?Q?tZ`W*^wC?@62zc;l!S_etn!TT`%h~#QRC+ z9eRwCyxIqN4?U*XzQlj);>-5PrYl!P8rRC6< z6kAx?d*w^HN}sbLvFnb&m!fmonlzIIsV)m%O>ej3wWXP-UR(brJZ{pvJ7g5o4;R61B^UYLM z`_tZz&*MYbCb#OH zc9-bdsdKWymp7q8%H&P_)J%TPvRylMUOfTM&YO;?%n46KMef8;fkRcBTf^2PrGT;% zl`~dst5=yv>c$=$du~kK*mvWAjhP#D-KD2Ro@k+}9!(3dq~~)Tl0A*qy*;9O6eCjG zu-$--)T+DbPa)!7fJW6EnvukJBX#e$q!fgw;uZ#cQa5HRq{Jv}CHsIT!ZE1DL>r}+ zOKYp$OH?jr&bTcUS~WYUh!J9OaF}m#?b_ipPIFSyqE=K{CfW?xNN9BnoYTI67JY+0 zR9z_MQ0@c!3t}W{MY_?PxTVzw`cWD{CT054EsO^GYEH^)1Ao0>yzR{++S@Lus%7%m z3);UswMQ>ocHzxDRn4dTS$~hV>a&aVSzFtMi>Uq6E5YF1vSpq6TdaWE+ws@<8_zu- zqaGaYxTq`%n)CZH?+#)2#qZ6!0un1A+;*GGB+dj z8!0Kbq@~^ZiGK5b`cwC;1bb^=tJ6a? zL2G^Yfj55TJoA_3VBLiP`1J^`+|Zhzhpb`_cHd3!LC;|5xr+n$hiAHm7^vPHV-v&R z4gkxRO9_Ux`smrn4-q5!#Ax-r-{2XvZp*N5gIL^+fm)L^SQc8|M%EtP(0y8?cR|2Y zec47#%{}gFp`v|YN%AfPtmlxCR|CJ_axqtGKwG8JfRMi#Gk7vEc7@1hENPPbF{<4c z-=D#ip}H%8iaM4z2pIxfY6?qFw+f$@9oM6_B3s7cGlU5pd#Ucv=q|J&@>6aVSY>3~ zsO5zIA#F`~AGk~Y!a{8y6nB%b+mnU5cBk)C;k8oc5V1SRI3g96vu-Upc=2%Gp?ugM zLpcIFX^?QoX_;)5N7wyHd4x!%EMQ@w9K5!T)~?N|$Yornja-bLR&?b4AZzMVT810XjUQOLk$s1{ z=AJF9V2jY!#?gzAQjd^lMBiRZhQ5=-$_Q)?m?zWoEKD}3`-DsltB@1fTf~ArE$gb# zinXdTVxHS!L;5M=Mn9Ub^sZR@mJIYPbcvrxZhFf|)%}H--VpOK>yIVkTAQ>>!vkoBOe!D_Ib6Pkjgjm%*bAme@5mGA;i1leHX&nKiEZa0E&wR~Tg?}Te1>>Vn z9^JH%oF!i^M_OB{oTeTNuL&xxa{-JiB0nx`$< zkOeVD!&%ydlyvAPF)XM*W}!zlEIb@SYhY|5^0BO~s25lbXJcfqG%ETs3{;EIqnIUH zgtG;%D>%K;yo}j`<5-A~TOwDpW=xiy^ipLDAy@W3p)C_-f>thzL~=7+?GcR?6L!WW zy)ww_t@y$1GE!xKI;*nU5&n$SuI1;lkqF2yc@B_B5pQHmmBo6p6Sk}j|BA@TP$UxO zDaUBgn|lwn39?UtQQJotL0#>6<^&ND z3<5}sB8-*+$02J?#_@w&hOwNZLK}2+Nzd?h&yFUweVR;wElu|qGSglv`ZIPRa2gGW zbrR1x$ygiZiWUOz>Nr+kW@Zj!9on*m29eh8GnA9vtAzr&MkotAyEV2bY|KPcF_TBN z5XLQo+i8!#A-^UY=Do0Sv7T1EpR*ri4c>KM$e662aGAf0#5`f61$o>~hg{LJt_nR{86L+GYn^~r6ZE>95Lhx~+ZUF~o=txT9ciBuc{R`5(U#f=xKHFL z5lK+~NJ!*dCF3K>4Eh5*kqv0iBM)V%hWNY|@!>|>8uW-pp4QB5_y(=Kdm@om%vMB3 zgC87lKR)bx>Rv-Tw|6{DuW}YrF~rJLs1^HJL@SmKB?hle3(dfqjO}rJ)OKQ9s*u0k zo_sB|ES8Cd-}e_0d$FV60yB_SUy_b#v{V`hFHb z%1oTbCy9v`YFy5!h&Qg2B-){n{X`_=XqT-)_+7Xfw4*bR?OCCt&v1=L?VuUzQ`)U! zYt3iWmi3}rO1(I|N!#GATS^NIvvz4qVFU=Q&K(`I0j@fb#C_{|!A{jvqeT7$MO zZUtOno^5)|NR{@jad}qs}qm|JVhm8`7Qqm(88g|SPC zLL$(8hH`SbVUB0HbDtWs{THD<$@U}*=9wSh+U&1Ua)7PPs^qvk)JthD@kDM8L4dRy1#J7VLx}7=vGEA zmQF~1E;c3SuodC=VN-gG_yxC1v`#f+CcjQKf8$6;L{*6td4+80u2ZQ$wwvo&r_x_C zPdSFWPQBiij7Ikv>Pz}3ya>JW=*C86c17b-Ze=_|>(q+G)Js>ZPwp+4FG5_dFS4Dp zZR%)Hyi7)=z{g>qu8m4L+VQ~KZ*Ox}0)KW8){G3%ptgduc zL+eYaO*?*S?+T-$)V#nM%E7i0&s<`!@DgZ3TMSsy3?9Y-$jaD)maE-o$llg3Ya+0R SgsVo=f7sf@K?{j3+y4fu33!eG literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/grapheme_break_rev.rs b/bstr/src/unicode/fsm/grapheme_break_rev.rs new file mode 100644 index 000000000..273f68276 --- /dev/null +++ b/bstr/src/unicode/fsm/grapheme_break_rev.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name GRAPHEME_BREAK_REV --reverse --longest --sparse --minimize --anchored --state-size 2 src/unicode/fsm/ [snip (arg too long)] +// +// ucd-generate is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static! { + pub static ref GRAPHEME_BREAK_REV: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref GRAPHEME_BREAK_REV: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("grapheme_break_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/mod.rs b/bstr/src/unicode/fsm/mod.rs new file mode 100644 index 000000000..ae6c499fc --- /dev/null +++ b/bstr/src/unicode/fsm/mod.rs @@ -0,0 +1,8 @@ +pub mod grapheme_break_fwd; +pub mod grapheme_break_rev; +pub mod regional_indicator_rev; +pub mod sentence_break_fwd; +pub mod simple_word_fwd; +pub mod whitespace_anchored_fwd; +pub mod whitespace_anchored_rev; +pub mod word_break_fwd; diff --git a/bstr/src/unicode/fsm/regional_indicator_rev.bigendian.dfa b/bstr/src/unicode/fsm/regional_indicator_rev.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..1a3357f714d45e1cab013e2d861509c889f1c053 GIT binary patch literal 366 zcmXRaEiTb5N=;9#&`m5Y$pMenwnHeBJ7fQ21X-+6T&=eyRcEHR6 e2CO&%8;O9O0~KKLxHLjc1;J!sfQFS2Pz(TV><#+> literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/regional_indicator_rev.littleendian.dfa b/bstr/src/unicode/fsm/regional_indicator_rev.littleendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..e437aae3ad775a5b2aeb507e618100b7d9fa8e90 GIT binary patch literal 366 zcmXRaEiTb5N=;9#&`m5Y$ = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("regional_indicator_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref REGIONAL_INDICATOR_REV: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("regional_indicator_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/sentence_break_fwd.bigendian.dfa b/bstr/src/unicode/fsm/sentence_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..10aec4692b32f7e2d6ebca5c42f6d9ae0d77afd1 GIT binary patch literal 144343 zcmd?S3!Ii!wLiX}_njH85*nGBAtIuA42jH$jL1wqMjj+IL*$?tktvayKaZK`Wf)*) zfSF;qUuQt>*WrFsA~cVg$K&yMJRTz>GLMnR$jppG_WyqOUh8@Hv)|{P8Fa8dpa1*$ ztj~Jhz1LcM?d!8IYwhRG@7{IyNALXlH@<%FM{oY_-QT|B=DTnH=w0J(zVoiHfArST zH=DQrVj@#wGRFM`pY)ddd*+=c%4ADQ%i6W?(6LkJle)aG>&d6QzuN~+{orY*pYfqH zKivJS9%uJFr`Nf?&pZDk7yR9YAMJBd-;eeC_{E>N{ierDij2Yv3c&tLw9 zE3Uli@2~#i;4fYC4@0gU`sHEQUH_FEzB>HI5jTze$5A)m^0iyPKKdJDzIofXZogyf zx5s_w&b#jZ?mhqS-haC9d-s3;fq%}8FP~5`anj_Z6X$&>&3)W1Fb@6Y_lv;XyE|NR?(c=L~M{pslc9s4s%$Cyu;4jq~Kle+Xc`|O?{?bGL?fuH^Cph2G-e&eW{ z@B7|A@8ACjQ+VuOn8p)7`N@+{{_DR!_0+#HrDy)*Kc0Q|KmYT&=l<)zo@atTJ-{S? ze(>NgesSo~FMs*cuMacP|9$PX-~RTCCPjW>`QY9P8y@a2LBJDlm4{GWZ%{a3v5 zd1F>}HKxb;z-w81UK8-gx6pH+}DW-~ayp{Vcs_o{7uszipZQ>_xBC4j*P|{r>mHwA<^-%Hqr2 z{|?Ak8Onjcvg{^h=Z8ytCezs_l*XOMc50*d=G8v{;L27O?0RZupRK4iGJA|Fc?q)SO(Y( z*avvsL@#YM(XXB}(aZJ5d=dHmVh+!b8Z#Jr48GVz|8ooAX=A?B%S5kS4Lr#7Z==5b z-!Hh{ooJ~+|CZWlu7{tp&Xss1tyX)s;tR&0=XNdL!`a&}fDFHfUx1##@YUU255M45 zWB%?Gz(Bw_*R%hw4$sdTb0LzyunV9k;2L8-inRK)2UNPA-DhdCr(Xm;F9PoudH{nT zy}gIFeYSk<-^bUlPd;XBTeTQ%iJ0wA+a)pnXL>(xGUt>7ssZ(`|DH1+&l>>y0qB?K z95I<*=(D}hXM6Pn3;+xR@2e(r9{TxtO(t_L=z637_J*w9tKO?o>f}Di86e1&4bwQ_ z%m)UW%*p!zj{}}|xjY#;KN&edHD*rf0RY`8*8s)<#sTgH-|Z%I>iGche(+S2>2@`6 zFTe=Io%vqnQpQ^7+5A|1a^pM8D-qWr7@K z&KZl=h8FZrTI0E0(F#`q@HPor`y1@T(24H^vz3>Pa^}X=uNE1E!qjhbu49NqjFv&SDFET|dt1g0K3M@P+=e;;Pd z6R!c^2Ur2v4M4~J3HtI+4jc0f=%2xi^FJ`iJ=+rion($~{y5f53 zPK=RvVpO`TAK*3s#?8C712DGU1sQi?cR=KY;bbU*5w z>#2M1w{_LioBd;b-=|OE+Fo`;QdY0|m3`U@fUUea_}$jT+r#`0C4mNLUhf6~@9UQW zMgZKK!@NET&-0D>{q+E}+&A!Eeq$(LAK)$f=J>Feo3oi0UB|RR9wLl5k+}gd3V_`Q zgYn-~0OkTV1NH$>TLv{1VO)zk0#F;#3)qvp6R;St&P3TW09X-c?=)X1GKRSsW4!Z# zovZY|(wbeYlzKbyyAJFX!7hWHRfb_-Sd2C3QDfJ;SDb-ehV$jQuibGlSKJ1CCtw-i zki?-ybA5azMxiTv0q{P!avWe4;Gi*Al>r6B3fwWO4lzshtz_em{MPv8!#1(Fgec=JN-a8S?@31O8Xck&NLC z<1?}TR~p5vGksS4-KJKJWagiyVicQMFp`=3o=c2m=KE0N`@I3EoA1vCJOp^dmW?h0eZLuY;KjK4TvSL2^CrX2N%k<66uZbe=FmEJnFKzQ1*K)tcEHW(ej9ls9K{KSAI63HsJgDgfwP zI-C0m#)T&@0K969GWBI!JxB13A-QLxe%;x?E_A{F6MLM$Ss1}ZLjOWM( z99>%8s#1?GeFn5>(c!%8Go2GXB>K#L6Mg0t6AkPEz|3Ia?SN%~M*)yA5VL{Lo&v!9 zZP1%0`rJKnsYjnfFVcD0Wmt7yw$+w;^!Yxm=plcl(X6>Sbogd(ZVnyNrpy+i?^L#~ zuG(@AeRnSt-Hny$Jy_M>gV9aTB>Xw_|C@=qGu}$x9Qtpdhcs6++C#bxPR;|kSH(EL zhwMfFZ_Uc3t#|x>_^OE>!Jf+_HThC+VaKm?uC}gj`t2^G3PW|yKde3^&58X+O>Q4 z9@Xj$$Jw(Fv;bF6k-)O)=~Bz)Hf`R#Md`~d{mEX*&YU%C_PqJ?7cl>e7B6mSXk_k% zo^pB&1Pld0%O1$>*(g(npWPoY7;rCOE?_6%d8g0WuUlM_dvMvZ<;z$2(lGx+jg;oJ zE+me%c-B!!b~&Ng4V0n%dgB4I7KqPHB$4 zj%_)eza+;VI%R5MY&ORpi*VMroWy2xY^z}y?M=ck(Kx|NbCi&dEiw$_*bs)%^d%XV z$=Oj!QpmtU2Jx|;x$(CBdFiv(CQY6?ZCVXmT~e0vDK5>?a)zce>2z5;Iwa$=Ikv52 zSgEz!sjQkaHyN(!WYH4JCnV#txjhfrR_W=U$;BGmzGeSOtI66lLK!p*N`_@H{vbrS zN^&!1&Y5dR+MxAibF?c8dF^Nxr#N%gy!lCrlH8=p^)oDAAg?sXw}~e+u;1xmd&9Jv znp(E4#wB)~_3~~4dd)#8_~tKYT(V@TXrk##8_4ARQq1OPHI>vklUu(5A;Oo*En1xa zSDM?rWy{v>J9g|$@@UOva(=pH=quGz*b{f{&dX5AinC}{aqi->q?J}OjciW(vsVi2 zjdq+(ge_bYw~M&t)AlPVuQbQ8X8DR@V?;K$X6@Q_NglSUuw}NhZx-5^S(`F9GQ_om zH=(Cn8QMctHQ(ocE$FDFIEywJw^J#R(`?F|FH}{}n8~qv?z}~d-8*f?%9X1)maX5g zVdK_qd@I`)%yhN(PXI2%$Wc|z78;j!N-9~5r14lL@tK?*w?)59&L4&2TJ~hc%Jg!6O3v=V7; z>n=knZQIWIdUNxd_o0Vz1~YY9Z5^#h7c6XOT(^GHX2&aKkfL)~!)gE9S{ionQ4lFyLBH| zDmtq3EyP;q+mCM!zJb{Sv_-ji~-ZPn(a} zSqtl*<04B@*RyUt=jYG8v(j?MoN+XkJYD*fF_#`P<}>|_Iq#^;+h=aYTJ-^A&PV#p z>-oq7@n@jRXSM^L1Moj|W%$4g1YZqW?0(s>+Yk;J*hO>yAH_3Pjh{unKidn?A1l{- zV?NRq&o{W0=4Tf={E@y09|Bkbc+z|z&bM0wxt)Tv`a)~D6tXY9#hBh$Azz9*=?y)4 zV_)>Vo=%VRF2VEV@{IhQH`=9nDfB)M^q)fAQGe$DyvOWwiKGwdpFZMZFNM~iIy1*T zi*PjMjI#Nb21!h#*Ji={knSsPuV6qIV_=hJSKjA#$1`*tFaQ{3G~iAE+R6a%4R{9d zG5~e<=^g;Iw@;&puyIM$_4awet^!rmW3*^jr%2YRd(4D1xkKn9k z>o#wPsXxk=sr8q3-anU5J=}TfKNIzISm;p)dAuU4pz{g0{u5OLhXDl<pX_GLCkFw*OBtV>ia7MUPp**vkKy?( zl+7vbfB%6NpOmuC6^}=h(^J~x#XXR(0jaxP=Hg+98)M}qcD~RJsLN@xU&5JMes_^? zujC$>ma_E7kE2vRKFVqPah3+OVH(=wliFCYBYSO{(jIjsIU%>Vq@7yR|@TOM&QtZ}ogn4k8 zr#oqduLOIBlA`8UBr(R@`60c;WOH@X<2jwTm>t}drKpIz8c8#n$0&~BivMQeC zdRnt2H#Tv`UUVi6>JpSB$0VfW@v?-tBer7Y)@_Al#~B~@t0qn6%tUkyxV1c}v%hD; zaPD-FyRwQY2Wtagjy?-+kN1V{N6AbfDB~~>Tu0irs&v5I{cWyPy4d|OI+#tX;W+3# z%GRxCy%v^*=CdW7!HPsm3MIf@0q&ALhmBGsj{6<)o{LCl`(C@w+j-MeW1h9^!o3@|hw3Stx5WF%UTKHr(vFJ-`&O-+ zzF?u0NT93oaL1h^W4JS-`m=nzohj86n0sv;MdOvS7ss~UKG(Eq`wr^M9h|W5Y5G1c zk=4If(jv1RwB)>(Gr)MiFi1}&m0&lm*cc%F)GNDqUXlpgwmmHWj&XmSGPSmjduy%9 zk&ee%jKwQfN==B~S?qAx-Fh$OQj|d5bZ^H~^C-2)Hq8$$>mEZ83n zyq~;%Ovq|+w>03^8pvXIGn}twb31p1`)6f#?}g)A(a{rS(+*?0Tc4%0Lv7W9JD}y4 zPjF{1Q>HF`Ff3oyFvNV&6t^t z3 zF0NV2TJiSDJPOUVmU3xs>4RL6#(M^&WuAnGCl}=to}|8 z9x?YB3v`cL=Vft9Dw(sbs_KSDmb1%$+?#{6RYxClwiWJ3aJI!giNZd|H$W_1a(t5A z`{bN-(PFL{IXbN0(6lLjf3-pj9b4R3JHFiQ3{Ya&_k7)zs~z4!?mX1nHPt%Q)CHGe zq@OvfrP}7$GGnIf9D8G$rk=r0S-uW=Cd6~m!t&xy5#PEzzptqkjzA-oS!(AIa^jeh zW+_&kYu9aT3P&F0&*o;&iQkZt`!bw@a`x%%DQdZRxYX|LZfuHcRy7owEHn#SLwkhj z?r+dmlv}Y#;ry_1N!l(ucg6hjWWAQ+jlwrme3Gd8iquYMx6amrJ72Co?HN)^$!Q6N zIGd9_Qk4z-KI}hp4&i#^s@3Z^=q_6GWvFe@V$FGgv$?tR!Wzn8_a)zwIM?J3aItqt zJLI}!ag&thO_DB&IWznj$U4PZc5%FWt7rNxUwmqP%!eM6xt(a6DP43yBU7V zGTCFoI;3_gg;!7a`QbZH`LZPoPB34Z>ci{Kar7=EdX+ zXP8RQxk5bdNxJQXhkdW0cL!~br?+;k>D5=q9B=RN_qWsPEUkr7s|-@l_Xdt)Tv$$> z#{H|-SkGkbygo01>3rOD=+wDOkDedBXyBkhC&;5NzKKC?zngnJ--h z+7X3Tr6X$cR;BcryJ;W*{vkJw0>IDYrh5Q&09cmZv<|Qv0E^O*vrY7mJ54kS`*Lcj zIO?{%Rq4&JV!ZhtXUhw(tSDD&_f4(c6ZTJw?#q7o70_XSiF>Wxk2ri*AHkRnorS$a z*_Y*df8Ba_x-DZU_r7}daJy9S-M4#Ty@tCTVZ^=9)<5@icyi`WQP{HFN)NTnQs#Xs z#I$N8W=X5fDCcDwrdZ-i@jjk2SLXRrJC;}IGP&Kf*JBJI605IFZpJL^TuLZczZ2^@ zw_Ce@{YIfCzowrQBJZN81^^ zN9)GY*uITgiVj&jNB439t}>L=-1*L`&5I!y`#rIx;s~5LT~wP%6ypiT<Vpy%Gv1uz(Zz2rOIHfAh#zQ@i595UwHy#d(i|Mru{ zjOz-(Nz6FxTaQB-eWx1${q{Q*0F*Dfpt%r|g0@Qq3Ua`KIrjTuu0KWF7(D_2T}Q71JOnrZIEJ!Cd4krh(AlFatSvO&8ehBAmG0N(18)U@ z>uXP-G|_Irk>RW?S3o<7fxQj6w~KLQRfBsgFXAMjMaOt=bwR>8O1&7i*-?fT}Y0fzyo*;_gTE(Z(+prmeD41m73yy;|o4Y#YX7N92z z>8`PEB!}*&nFwi>V>0mu87+!rNJ1*RgLZl zQxlZ=6}Q=Xceu_zd*`eizje$5mUC7Ku_v5tTbKnp%Q<}q+EGL7`B@%wti^f$WV49< zg`Ev=-4?I9Mxd-m3{C0;81JwnjVwK;4aa6|K1p zAiOt$<|dRh>;0w+0Vv(;`v4CIjFoV-0~?R_cGKekl=Mx90dJ!XK-S1^E`H>hcZJHbQ z8NE3X{puq^^WiQ&3JwW@G@ke9vRQJ z@)cM%7N1`UTnyI~Iikegu#oaWcHH|9FD!t20$-55Y6V3p&$?r}VW z?z%Vaf1X=3$mz3MfglepVK!9`7mz5-29Q(vBM|F^^5itFdJIFfo8+8cBi z16-cX&|55Rv|s_kx|__xg^i7Pg6`;<(Qf2zXqm}4uYqgdwzL?vP=_M#TBm8my+DjS z5v@dsmu_^JXL|gJ3(yUlRFf(z ztE;C@t*e^>bN9J(=g(ibaPeX%ZS7i0d-!3##aobcyz!;g)e9S!EnBmOtFRQ=p3MPc zy|M~y4!jsENB+k)2Of9ApNHWn$yWLE2(6XR(r@Megg=k)wBXOvO3Bn9)t{#bf5M+f zXj1)oitrcs^8|FIuzyJS^AyB$_2~KY6vT6m$rT`4Ls-ICE5+6#UTu5UB3>vPm zDJosC^3w2#r~9Cbaxz{>+sv%pNRJvy0F+hLVznGwl}M!U=ODsN(~vu4qBEFG*_=xgMK!Iy^~D+~cdlihQ~T@n80h)&FX6yQv*oZcbS5x}$N z$||0Z*)tAL^H@uSVYQvNe-Tc~(%f@5#@gep-q>XKq{CVyt&}ECJ75cAcfWl}h_%)* z*mSJLS@AYn=99~-H=7#60LTSvPb758VUt3vU{Kl%7Fa((iT8EUXRTRH0l0mAeP|QI zSf-#{iW!EuvdNRHs%mN$FUHP=Yn4`GauI~O1a>o0D#E8F(UI@nX*JX9SFhf*Y3o+* z`tB8-RYn??JadOmPZesXb4P8Vb$g8MYc#bGQ)U}u#TJ2dS_)c* z!W(fX2G4jOPMTCH??Z{R~Vxg<^>Yh4t6k{dDGX&wtBxrG*^;x#@Xn^a_p%q=`j*=RknJ~UNiAkiLJ7pP)HmhjicY1l zsEKWO0xs&&Ve;ha>d=aZbSbp4K1dO^6R^c)nhh&ftX`eSt=5B;0XgmSmOb-WYF<0{ za&M`%By$aF;iGy;d6i6^x^m^7J$q5|s-@rzT>c+C`CDI3v*yn#)_5 zlo5TOiRqaOoPm`Wo}{cwU`drel4cgIka8qfN#43j^%Sk54X(61;H^gsE6k=>uiml4 z&7vh0O-(hWM1@Rw`NWCwzbJ>*8nxx9jrE0X2mD_*-DzLB(VIc@9t5|y$V>K}Ck_q> zWu%Q;i?*8Z9K{RQk>AO)doY+gEN-Cv@y2c2;Qa?xmV2D6@6;sog9{r*19jzPtm7gIV+uDyuaajt9KW0587H%yOK_! zxBN_#{GxpZ2B6SfY8*3?%Bs5QaP$<5G-?onwnh3_BM$oz&Vo_tkU|N46dPA_w}7Eq za(IU4<3?xICT{?3Yl7+h+u+(RLdufXZAz=lz!I+Q zG?UxD6RU5fE-#-nY04C56US7108Q4KfO)w=7(Cs179^BB@8M|=M)k%`J9j_ykXNdH z{Arl!qXckI+z7v%`F8$W)+{KXBle{)`< zl7{BimV|_1_QKcToQ9Pv-Tnu)O#@q-Z0DSBqr};=N$24*v7z(EIqIvaOCGw|eu?Qs zC9Sd8Z_p=kp9U5n9EW)xOG?dY(A(nPr&2}ND3`PPl(>(8aDRs}9#ynwj}6P@DtM+R ze3{w?dDAlFWNWj>kBQK7B5%95v5B7!5eq(QsB*PlR7)Kn`jPzOpetMd&mOANd&9L!^_qg&C3temv$S{%dLCooB+rzfotY^9Um3#73 z?z_U82jDW4hv!pXB&E!R3cg!~4`WN^l&Sp03&O~uWh_{{%|({yZH^G$0noT)aOvd9wY78Rpk=1SgTEv0j-a=J+i%za%SCHp6O?{j z8`_EmbN|fVq`(w~Ct8cQ5G3Pl8wcODv*#^tT)J%Kdfb1V7zx;J11Kw>hE^Y2lxi${ zC7+oFN+$H#-@|dHNQwF3rC1@OB<5jyl3r4b--N|Sk&?`gA3tgGoH+^J%ycYw;}EXq z5;m^XSTzqyE(1GnsS)TN+!r7@WsWoS8Fnc^0z5vLh8u~rXRKW>yGEohn>G!$vkht~ z?Q1|yM2j*EiVf@6+mkS8p*oV<ROm?*$1%J~ zom~G-;6H2n41>(<#7Q_)ML%G;#BoO~wygEj)p+b+zz-eHHBzd~smPN1Yr(U}_2g+OD;M5TiCIkrJURlqTusL>6>TvR zhf!(?tWxr&0@{qT$rXx{yfv=M6B(EhRZp#($JvFJiKJ9;*8}t6^``b}!@GVx<|lSX zjT9=M*ayVL7P}rz!Hp3?Dy_INBH*y?)YCKVf69#!DNFQK%QHNMmAc?%v~ zzOv9l*)KCKC#~-QXJL=rz_+5(K_9HEw{2r>Qa1syQszHU;#6UGyoV>LmE~%u&#^mm zn4cxVLtDOs33*%bu1TI*-*rm8RJ}=dL6vL7O zD_L8s7j_b6oX~Jeyj!^gE~56H0Vxla+mf~-vrAwTJ$KQf2F?{W<#&d?)ZIr_4SX()2sDUh?VuAPoWHQY8ZcjfMhrXFHnx|SViL>sMD?C>7H zHogxfEw|&E#mc1_ja0)l%@B4H-xsLOX?T;)FR$;)A^8A z%$c`&vm0-GUOszp61E|dR`IsKI?H&UPtypo=2OC9iG))RYag%N8UxFCnJ=ge;l+Lw zcK#<-RZW>%1Dmx*oKmk?v1;|Yb&zDO=C%ELdi!}ueP$Y(j^K6^xwGwdK^EwYQMDx2 zyx_U>crKSYlXn(8&i?nj7n1Ss{jvjs(H?za(&WNhV^|NM z?_C1u3%K4%Z|#jS=iTRSjG?x2Q%sLIO`dhKjp_|O+!5s-gx)fhx9SS)WUaK9agW9W zkb2ZwlK4}qU3w4p<&4q*w!pxxsvvv@C1PU))v_K;~)b&mpmb2YJVkwbur(v zI1N2M-FH~sQSyH!y_s$|JJL?9gac50{j6E@Fz;|By=v7Olyg(l)~z^?+O4|)ZK&xP zlQ6zdomx{xxq}b7>ZK%8TvN+EEp45QabF9=-e-H3kGEP}*!eQ(+3eM3h4t zcx^R4Y0Q$Y@YKQ_cS$b*=4wl>0Nf5(W6aXdfDr)1FU4-ogM$DSfESEeb^%~40Q0wH zsQcw-0`3IN1z?W60=CmDMgr~y)B`XdT-h5i4geV|oARCpZRoY-JUD3)V^8`QAcqT{ zHD+NM0I7fDWq4!ZSv|KF4n{aMT!`5yJ+~GjHw%{{9&@XO+W`lRS%k7*)DdtAY~*2+ zzX)?@`co{b0bn0pJ+~G;h5w{KX6?hx;y%VKz7%jbpb{_}fZn{+3oXIwz^yj?} zjMBFlG8*16rm;U@+`ISSnlsjzInNn07kQt11za4mpbdT=d(>;)*B1v@QmiU-$hlp0HU&M;tb2OeDS!dI&v zbyzXyN)2KiL4thxjE4{g*dtL`OZrbEN&XjRjp)%2st!9c*^ z=pK4yO}snrl{N8c=an@P^*yN(fV>y+%A(z$wHc!~R{2wwFYvx9e*^yGC~dYD;t5^s zbKrfYV;8XaIY>y>-o=YK8%H%+e_5}iHulJJ_u^-DTiC1U$lxA)!we{dMSa*)j7b-yjNBAR{VcR;?ZlW(MRD`)hZ9FYUl(#K4f<= zX}uiY-^tSp?yBUi!5SL9TRfT9$r}KVyYwf&=5S@kn97cT?tohW_X9vz3A#$O%1Y>1 z`8wdJF;(pWeE`=0#sX@bj4I@-3iMSdJET*@r)u)WlJcFjkdP(> z&gg|#aS3_Jt*>ve51Wys1*YT(%r z)91h34E<+H$@j!|Ag zJoh7KIs3EJc-zisT9SK zCjK`f0Vkd5{x^*Gb3Er}xjH%g`D7GlN&)C!w- zai#j-sGJZ}UKkeqxBfQ>EAYP|otA=@q43(BE<7jvZzRsI|JeUVUY7Yv%F1;dY*{9IKTQ|^6Q6}Bt1{G zc0if%I1ve+_lU~W63P3EXpG2em7j?6sD{ASBLs7{W_&)#rFE%TW_fWQy>K0Eiu!yg zuVV6QiRd%2A1@kvJ|EDks~rny(agDk=kt;D_)yutJPlL5^}o^xrd>>aexKs)5zt$m zDU0DETf9A_>|5pSA+!Zv9*`V(c`z+W=R?Q2yPWU{VOu{DAUV-?^1fztjD1kvi5^HN z@LSQ8wPpo(rQb^89M+w}dM597S{vrY^bThNp_ zQ^~EBB4L3C4@0T5a)_=ic<|7Ef|Q!uv=LF$Ry}|N&mBz@F|G2-VXDfb<*O;HCiKc7 zjaqmF@hy7gkX~i^>1n!b{mc>R@LZY;ymB->p-Xt>h>TP0%_*=}tEt8Jn_xu0SS&<% zOV`$|))&Y5zs7aw_c^aT<9H1V>F~cSS20QaZs^lRO3}^7nTlrpZZubdqa3_AAt{5e zBz7dQ z+#?gWBSCgjc5_oHMo+4w|i`*DW&Q8{eU|5`{6hxIZg5O(R7FB)9bU0$1QsLXjzk9p92}Orw_v=uE5hrc{D!s^r39g$&OUcn@6dAZ=OIBQ*4Dd zPoTSa^H3I`LoUUeN7M0h9!QD3c|;C#Al^K}?RoR4JduGJO`10kVzc~mtJ*C|9T)N7 zQJI>)VsOPCJRVKDwOOGpTx_+Kv?OY)v8NSs@V)9f_$OfXzp@E;j4Fq=c=_Ln+l1)N zIOCb`?lN21WcwiFeOi51?8)nZl;$86T3h4hhWvMFl}2R+SUrv=%QtH0EQGG|jaut9 z&9nlZ*8VT*aisODm}zL63~=mmr1cM4&$|erv3HS50}i~4ycnB~^w1*SMWogePQxOt z72ZWEsTihojT4=0$`aP1caid@X{ljK1Kfglkw@uk5o@RtsVQlNUi^8|y^B<)@`hOC zG~->Q5<*N#8m483|DsL0cahSETIheq16uGdQYpo7nq~-V(Yr|HsW#1F(00Pvl=|8v zyo*#$h*R_`OL`Y6ho3USn)NPHo?k2w?@@MLwVZ3{4W=MG}|z2AtR_VQvPG9D2g=4NYr9%-dPQ z+&LiTJ2nLud=(;~$>w-_h^(k24*N#D)lmNNmaUnytk+MF2EV$%TSAiD?`h{NbZl+>5sv9k9Uc)8=;Gv;k8PaRze`m-Tj z>E)mko>M#pNI?#ti@jU^w~=MMpNgh-0&z1|+EOAcjiOfC9u0f5t|IL-{-;`LD-TmlP#QLlP&*JY_ffg znFF2W3P&5*WIqBMvPVWbo9stmh4n}d0Q@uh$lKirNm zl;D4+r`7q9}b&)H<}f7V!=>_^I+ee;R3$=-`m z!v-65@$iL!0f5^9lK}Gps{k(mUV(O90BEKD_cQhmdnY#8d(a1(v&r5AEohUy2U@93 z_8yeap2p*`$>!*_>6t>C?9FfFZL+tZZfIk@<$hzf_GrCLcGE3sHrY*;#;iu`rwu7_ z6M6)m1Dk9ar#MoIO}2#m745Hg4|H17{(3k1Chf0xk1n*o-hJP@v%lVrexdf)yB}-b z{(3js9ZQn-*SlY_&+mc#^>(DV{dxdK$nA9iw4&|km)nm3-Zo|jdNsA8{q+v?+Z|{* zJ9fLUou?YJvpWE#x$_DM8;)nt*|7P*cu$aj=YGM59Iok&Fr;DQkj^fQoVy@Lzl*VJ zB>vwEnB-`7t-$k(0ML?WcQ1=uZGXKDc_QDo=K*gaZx{vis}{cf^>*}%?dTz`wZGoB z*vfrZ_SajX+g9Yw>R00MyRpCChO)G>`XjGsP1{D>|3&Ptw~lnwTNmQ}h0@-N7C`R6 z{H)dmj3`H_C9;-*~So+hv$S1tx(5x0Xlx4+TCG~a`*TwjV*WHTklps zT1rJNW+@*$O2=ohn3a^#x?_u3@4kA*`f2MkWfA0m5nEZGTRBCO3~r$p-65xl<*U$Y zjtem30cwj@)bds3gqS%9!-D_T@)cpF_U3uHb)Gaqeyp`C!m%fg6T*DXsB>)L>d7v! zaMd`KODtiW5%7k2k*XAsELN>TS8DH(_wJAnWQrxLgyJg=jeFzOuxHQ8cm<@tvO+*M;aecl46r5q3z{{Zts5XP_F)GE#TR+#*+{`wnK~98qebp zYdnSk=%q|+;F`MlW^Sd`T=+7nt+T@usxo^kcYGtaNY(T$Mwn-NrxbzwQd$u=nOH3Qt+xclD{lMPNi*2>No$`3SGEp|%H78A5+1qJ)iaE2?lEibuo=#}~ zMy#Hwjc8k7^@O-)t)38XZIpmhY?PRPZOcq0fP{^b#%Y-Wr&=G8&X+6lQ|yP7l31yd zHw7yN<$38^`ys@Y#y17$-#R{B2TW(UrpVt8+~DM}&1t^@W=K*B7vnQ_CUhv z*#iZ#vN^fiS91s1MXY|5Q&Uk4&e-b5qbX`lqI`<|649Iqj;%>lE^~%k{?J0mh0xfV zM5O^^?Iw5CVpZ*hYxxziBOxWF76XywtsA^sYB%QZs8u<|uxOr0M`&BLAW@mcbo6C| z_9U#r_3K)7@cZTcwDIk5&DxHr9OVnK$Z;o+{>`-ZR$Ao_agd{C?M0L~ zOj-Yn2DA;(Qpw*&Yj2`e3B|Cl4W3)H5m7m+L30?i9SUqjys=PaDfVOf>d^$}}G2;N9J%&x&-85@&nN{v$*vlvTOkn?^ zTtRvr^LdSLm&N_(O5FlZwfRsUO-XR4f*WNw@z{=PO6lPOyA8w@*ll?9s)^!+-GgN? zshvRFjD>)f5^zxq0guL(w*Hqsl4>EKG`eQc|B5jO2<~xXj8ZE`SW%k+l|<}63va5; zfYJhs&46%<&4Bz%u^FILiM3klTt>p)z0E+>f1NSEneA)_euER>-|RF|f1Kz1=2a7Y z3g<$vP6EEynE&k!{1osi6Ad`cnAa`=#`(}|dx19_^V{=H^l51O+cm&97;~fx@KWFh zfL{k*VWLYr1Ns~DyHS9<0gdm4&A==5Ci*0dtUlQ<)n*|2 za>aYxelzfd+6+XOTxFt5kS1*gUVf%+Z3h15K4&xV3i3jmfmeF8U^5VX;&o>;@T*r( zgv~(xRAUYuHRhL#O?2_zLYsk?pdW1pUK)mYc%y&fOgwJ@?8oyZ#{4P+j8^?CwC+zd zCTs?xPdxcfYzBUDMYA>o(Z%Qov>Eutn|YgoLue(3j>l#o`e;`Z_32k&GZ0-gEVdbl zE849M}x#*aa*$0}^sv@7d0% zF?}0)663HSE{pp`T*|xXWRyB%J&CwqVp46Ldf+!C;u5srjV;YQ{?xYy)A48$ z&rBbXcx(82kq^)=SG9J_cHBdb4}isgmd$r-<#li!3CdZ*RTD)Edq{4ec;`UrHz%r`5c}m8#>szcKZfUo{TSndTwD7wgva({!cU!J`!NjzF0dcdIF(B* zVV?aMLzDuN#ePia3hc)MnPNYtQpZfyJ0d$!4vp7R2Pi@DS)4GT^ z4f0FwjmcXELkap{u}T)q*@W(E;3|qGOZfFpH$L(NAfUGYDM`Y`{!RY1%KlAg3+@zz z)W9ZAHAWfyP1?i-Wpl!8;*d^Y6Q?O_2?eB4M7L97DXA7VPA7kJ8g9mapmfSke#d;{Fxvl|R#71#|zw<30f%BiU+MryI$phr{GZczCYvrM%_0vy{7s$AwQZ#Rh0*ltjz z0VnJRy>LyXh}|G5sY@{sN#1%f-EL6j6vLFSahjI=Z_#crGRDs1>TIWh-Jo&> z=@qdXRO%LRs@cwHs8P7I0uUNNV8_yFvMPLhJ^;)HKypyFt-`bx_1^P$^Py zf!!cz3hV}bKK~ghChP_!4q7%g@;lpm@KqzuzE3{p-XwgB0Icnw#qh8ro=|0RwyJ8n z{YtaYF)lm4yaM0#PVkrHCf4y@NX#!hNN*~ zzWxjuf8Gbc`P!e+oBn*nn4_J6-$q`#<3>B~^uP;c>QsKUo#kr3({4-8nE!hQDR%_m zr0G~c08%`56#yq{$B^PNoE9Cs4-!!t$I1by#bawQGr>2m!Hx9)?+J6tj2ZgvIM(3O zrG<645$%#Pjy3{T0igZS?Euus(U$6&5q}(hqT`IlPB|A+^pxdYqxG? zyZ#f}&7UCcPsrt;_5xl6ybO2^@TTdh^&;nJ@Daicf67#N!c$M|^v#$Zf0J+F!p26| zhS+vCZ{BL{m^l{waVek)fE50Sy8Poo08)4>1Lz7sIleUz0PWeL-?{}*1DFk11K14M z4R~Ds9|ArMcpX|AKzqQMfW838`4j5nPbjZHLC&90wtuPyEH>?!Z?^Bmbe010B4r3UZ1Z!tSKf=3C6Ri zyuwlDw)3nHJeDuFj=Qe%ucV@)vT{Mg5;x*%C~>stK}!{FkkPowaYao|->AY#kLJ#G zbkk8{4PiQHRW~j z<><3LH-h{u?;TjYI3dTL6(KIlO|apajoWtSQ-a>*6ZqY%1P|p#IkY(9wHRZ8GmF+f zl+Q)94(%PGS$D3J;Les$m^^vUcl8FS+Qq>8pk8FHOZUs);8 zI@&HZpBv9_0SFIfIW@J7n^H;B(+{bU+YB; zd-D1!mA7x~@i8_#e*D@^+w!f3VbOzbUIlB|^76{*GZ!ps;1^1R*`CUd=FPX-bl_g@ z+=gY#+%E1ew7o(eJ8NX^AG17^Q97{-CqK(pYc%9rHl<_?wwa!U0pkK_UyS0 zUOQCHi8GrvZFO%3%f+uEBQ%Rpyt@;Uqe?eND49FYeg~_tG$P)63+@u=K6%=lc}adN zf6^o;pX<@}XlwCW^cdc{ za*}J%e5_l8LPNU-g%s&1dIm2cj%-Vz^Zq&28}vm z{o3&Yz!1Q#SU0u@z88=K%mge2tN|cT9idal7eK?fR{%$#YYE^KKo7tG0Q`YE4Z*4l zI(LGOogQ#DJQF79y3<4*P%a(7-vM>e5&Z4%1O|P_ZWw>KvWz;c1MEA_m1Wd^1!SQt z+iwM6MT3=P)cz0vdUinhcQ_3IJv*R(b+`srI0v zmhJBYptNl&i%prorZiC&WtDx_L?yr_PXV3-AdiiW2)_?46Kiq1nvAk2S#yKHsCYH$ z+G^oyGHUl0(lmhf0IZU*nvB|`CAIGl7}Q3q$*A<8iArBXyUPI11fX4%A%(KRfZ>4q zureG74DH!A%bEZO04V1&XxI)Kwu6T4PL==AupQ{z!AGs#Fu(}FI6wseYaOg6qjo5p zb{ha_6YWr5?GC4|CZp1=&}~1~gqRaxH5rvY4S3$JCZp2EU^N+)4npiTfLj2!0qzA% zidU0SX;=J*cBTFCe(+b1`O$)-0l}>vf$i$?SiE|4vH8_wp3|)!K`E<87n70Iqxrl1GNZE+La`BFzk#zpPtJF-Ye^N?9>&d#=3mF z)gQ%U!%*Q#s^Z(syl5%u4sp+76?5-rRT}>i)vYK?<{%TTroNgGA>?+TN zx-})ZWlbrec1?+N<29v|YU?wxrgY)DrgYr8rj$5YOS*slTGEARo^>thLi20MJXK~( zqMg`v8S;96{f+tKT)&xN{G zA9G^Ai7DLqRbQUht@<$2@K$|JBK2Y}{8gXEI9!5NAMZ2a8bf0oPuAU`CE*grw_#!h zh!V1^KGa*T)~@(A`m4QoK888qn+tekMrv-FDzbfF^uV>rQ~upZ&|Fc@Zksh?8*S+j;yns1h>v&O}KTI3oTq{fkM_< zjzZU2BE_z+(CXs#l?!K@{`!jPxb>Bb$Lu#=UopgKZ@FZBCGze13f!{3a`C+`*Bogw~>Ay{wmWR`uN zSgrBYdM^Ag;dY&dxRiTB$U!QV5a2etC&W)hQ#*mU8Q*LzA>g9-gm^TGQf7$*3VgbY z(X$Wg*F!v-qCVXoOK z8GqLUFcN^3z~4Oucm?pLi7rIgg%1E80$_!3;j#DN4v?r9)=9nk0d7t8_l|m@UIKsb zs2BEB;qM*wB4GV=Zb!f=fPU8RF*ffpTn2PW!?HFnPzO>_=w z@SMJd_kGMe6KVBw9)a_41~CsiwewyF?dA3^kLaA|>|GwwIfs$&j+U;_XFKXS%=&Cc zJ*T$yJs#q-9i8>0iF%9!JXzqg9rbt}zS)CJbT;baY?SNSLjkt~a)27ZJ^)(X*>9jM zP&camg|`styP>@TC-3oyx?!b{0-_%% zanx%RL?v^4IeUk3Nk0q*p7v!lUkJr}*|q)V+I~dxb~c(ci@@ zJnDW=vtHp*_iCpTyuzdIIAMW)C*CVOIs>iX42*DRTn@MufI2;6F5pqXGbZ{F_M=!* z@CuJUbQxd>pvHzpA3`tx(Ca2T^Ax}tF6_)ccm|yf8w*@1;j;yAx7c`I;nA5$>r9L~ zA1;Z#!lMsklz~@x^x=Vy@53YUJR9KnqYodj;m7M09-Y3=M5iAt>J=WHj$VHTHsf0P z?T_g6`Bsm2;}ssAb`U-BsLSW+JuEhD;1wR7j-Gou`sV4kSefZw;n8XLxs*@Ct`olf z5uJuHlQkZAg_p)&;TRJbA9#cp@%r|9e`1CegeSbdB@Sz#yw|sc1zz8tl)&rTi}BM< zczws|h}XBr<9U61p_EkA>s#r#ru61mI=?I8^-V5v2zRQ7x6(jr?BVT)`QP*qIf-w2 zNSN#$@*lwS+-8WUb;5I7sN)=gF4c3Jbj&q%q>T!#4LshWp4-Z&82qyDDBMLnw;Ai{ z96yT=`oDbXpKOWM92a2513Vl1bf0XM6Jq8f3=96--B5%je6mRs zj zYThTCAqtS%j8C>o1TOH&);Q5G@X6L#a@I|+UkRJF?K_}*N*y%oh3&}+c@tjPq*Gd^ z!F(mZ+o7=m4!p1#D>+JdVGCEn3tPi{FKh`b>V+-wv99`GboRp&zScq~zSi>3^R-qv zqI;`+t(8a92Da8sz}OY5qn~xYwW(%hIrXWw{?z2v7OEIwp6@hLajTWQ-?X#?r4KRq zaV`SyXj;a?@_}jSzKYO_|Fh(vRsPRH`#0&)tTiF{gn2YWe&ErpDF=0s@MtED53FBj zB_^RM-pip}{m;6@bKt$KvCty+Ue++1nmu1&2q49KS!p#Fl8S9PiiCOI%M9^ixO+w`^NPyGHP|=UzJnI3DoOQFi7Fj9@K06_ z#B@NPRnO#&O`cCOxm6-}K9xtpILEB2#@Be4(|4EF(y@Q5aw&&m?Tx_nBwn~kdbETm zyo-hBZ^VY|nu}*MeUzwFn^Lm#cBCIX(lY z`sGSoT)UzL?eiL9&J-V9!y@+oFr25naV$Nsb`m$}IM(;_rJKT~PI34dBIT%{KArzItI zDF!0Ro9n0h)2f_enDRAF(~|!!`qPGd%I{;P0dCfx)}!t!4+pIsW%JX&cpBWD* z;!msGA*KW`tXY3rrSntupBWEm#-COt6vMtYcy7_3R^|9w6nh43sz0sD2(hP2S<;_Y zDgBfXR@9$X>5E}6rBr`f<@3|iXT|}V@uyYpV%STa?KJSGRjwetBL1{W-2zVar&S(J zNpQ3Nw93;0#`>BTz_i(>R8k9v_|wY26XH+nrKYK-`qPRI)Uadl9gbbQ;~S@ysu^71 zTMOC(-&&vFe@5yF-&%?L>zy%}gX7#jDb5(0y?M6wIb&*ZB6L$3po`i5N4xOq0Zc#z}a8N|XxjR3Q!XrT9zPC~xaGZBJ||(@$NWH8<2m!iwyz z`x2B}@==1lb;+TGXs+7XFH^JT z_M|D5FVTLJnwopxrBZARX0_UvHXL z!y5Cx)$7x$L=9s(;n~~CBZbBy7u?};U*m<$<;$CP(Wcppw|&)@D$nihS9qyO{3Tv; zDW`HsIWfFoM^0%)N1I0pE0gc;di6m`$|2JA4v31%>G;0s0^CjkyN&!l-RVPI4X6%U z`XN@S(xzJdrCsIIysBJHkGpuJp&pbS#J6~xAn8>WWoUYeWrxhl#dFGT7By1|3I7|DnYo4?gS~f zVwQ)d6yP$oiRONAvTjK!`Rtmj&@XIydoy@z=f9Gwx)sAIbrZkA5!VIR73eoS^~@cH2Hv|1nfCjn${FG`JwekYUjjAxZ;Vo! z{my78CH$Wz6=9u_>xq-x7d&gH^F|X&Y$m@ca-0Qp_!ZC=IM+sLBbPeoHZfjGsYUB^5vA>g7G?H-M-YyB^EpZeuXrP12e|B8`*Y~8M5 zz^T^l)YYR&Jc|wq>vlhH|b%1A0bOY=mZ$R7)jR3@b6?+_Cy#`PZ zc)~=(A!GOe0IYC_F9W<{q8l@St^kDH2>Z($p98?Ya>S|m9U6O2ti44F_qx~C)$um6 z1)TB8ePpmfNV%QMznRQheDij-9xx9`0uyqLA4S2!s0Yt-&n&`Ur0F=me zD5dMLbFzP*{ia!T-95(IxL>!b?QGnyMQsi>#@e_K9oTvs_n}}KjUA++7)9~D%4q0Y z$oFYB4=Fb8*WTuA+^=2Q);8|-DAzqG^J@;7=pSIO`45K*ZQO^nx8JIahM?sQK}#Jn z1_0fM%m$#v4MFP~0vnoZu>*H)ucVFpwL{*Cjr*5SQzN&c=I;aE4-01OH+kPBi@vnM zL|=LtT3-M_YrE!tz$(CY(@pP0n>lmVEZl}M7ZcC8Rl6@K+ne>^pYVC~u*)|W+PHt= z*}RSW6@8t}`V}KgbS3J!wKndbzbwth{qrcfOP_Hq6*&5QxqS|7+;#i`78`d7`RnaJ zM}v1;O|6al;HR98`(U({HvaNiH2BSU|2g^+b~e%H%}DHJkL>2sA9*HP1xjsXFSLMb zBy2FA(a*7~dE)n@=&ILD^!M!n=L4<+pmqFxB>+9*@6md=FU$SstIGfwpRY!5 zM_6<<+U?cb0q8MTW3FMtFxq{QbO`%mKLB>;8UDrLg3$*k&$n^^BGUTeQo!T!{&V!j zSB%+puZad{9N*xccpeUL{L$b>8{X>u=WUNVIagI6zsro--Z^#uIl5{m;-752jr&z2 zt=xCB{~TS3QRm9NPQNQLg0g(t!p8kdjKWuS2DrWY^!?}P%7K#d{m#by$~vb(u>V}d zhTZGki8)mep0Ht;xP%S6gatP2o|M3b-HY+lP1vx<>4*)x$K%o)b3gj0^H(ZP*bW+pr5ib&hS=H4M1m1VH0dF0q7p zHtY;h3P=_kcA+b>5kX(1zWMV|g`e z!yeFT84)LJ*h#0fkV(0L4ZFq$I5>G=tmG(R!!BG28+HxzZP+EOs13Ws$GYl&(b*4A z*su$o*s#k#?*v5Ui0-YjVOJha8<=*m&L5W+?A!#xE)D5)C9YU`<$ovP<9wN44CAUV zws9wowqku&If{|CXZH^2w4WMZK4mH`-?^%EUk#Hzqfi=ipprBWVeECz65ihO?Zzl26IjD51*LmhSZjF1C9L6nT6ykJaNgM9tiUo}!Zltjsz(G)!oRX)Y6SJghiv1Po2lh-JL|J0X_wUTT_Zs%5+yXCel^M7T#hgQJZ!(N;mhRndjR+vOEtl|%CEtA0M7QCrZ3fPxX7&L*W6aGsOS^3}04?#h z8o)vT^u6r~!1I8Yp%u#bTipPtn{Qo}Ji-3fn0Io5Jtl`U%B`qvwAqvsY+KV~cA99+ zGk_NWN1;75_-4=JIl;aeZRBe>9sP#`fMdoC>1gZ?Yqz3}3_;4gZSB?y!A&Om`UTCN zVE5s^-Gm7hw0WbQpl2Q8zB6Xe)aO_m5#Hz4tc6JY1wML>Ticou18{CU3~-BUSwp)x z%zM+u^l)d&W1x9kpDB;I1oH7tzv&S0t<9b($39c^X&Q5<)h`}zY`NeIZ==C^U;qH^cJwWP zae&!YlV~*F5*$A`qW*u~oqvp7#g*speQs=Hj3J0&z<>b{V)*HJ5JIB}MF=4jMG;~~ zk%QQTwOD?55kgrOA%qa~+_c-je_$KC{e$ktv>V$P+Zf|t7=#d$B_zub1{lIH41*$u z%@BqqU<^29Ki{fz?yGy>d+j#Znauw2)wy-*)Tz34@2y*Ps_N8DScWw3NiF6#oseb! z^KK~Zfp|Zd$~A34;BhB6O^xYqnr4)*QF7^=@=ZL2oA^R+8Vv1KctdZZ4ZP`j^zn`% zpWmc>e+6jA6rMIV(BaN0=Qpg3>26rZyT~_q!wZG(Y|b{quUkCd3PI;O?nReg?0CbV#fFe*3Y2p$ax9@vYD`V}SPTykFHb0%-czFKb)sU#o zShI6aAz!O6Uy;Twye|pW7bkhy45{m^cPHf{Zp%{*ot+EUr&>B6ZiMJx&sg~Q6YdAe zw1r+vJ)AFR9QM!5oVOtK>5?+|T{`Vpym;ddP7iG8_ZaMUvpHF;w^x49lU)3oUh4b> z_bpz(o_(;}qDSl&QZ6k@&EB_qO*yApy?cIxQ_LbJnwV4Xnzgzi6E)S@8C2%wdJ{=k zTlJ*&h?s_aW4w+h1T^?j%k-{=I(071t!u`dmAz%T+U(hz8=U-JPSYaAh?z6z%+bj` zNosuF&$L}Z30D%eIq6%12hYdTH%bz@y*D*x(HdGirY~H&w5KQGczz@5_xJQwo?C6! zthJ4_weF=_du$~c)=XHX)Joe?zi-L?J;fYWB9U9}_*vrYuipOt7Cq#sAp-Vcne>SH^ZVD^({_SNo+k6wc zM{L=;Eu4yIHKJPZ(;1p;u(mCn;%Krq%VZ%=gj@93&fR;$d1#3?uh&|A_TZ+X=4&(4 z_s(XJEY-;ROiouUc51cIC7rpoZaT?f^^RRSzpo;h%n?;$j-Xeyl5^O?sfm?1X{kN5 zA$cp9(+}Q}%r{aC`H*HgC%qPB=%{n{+J-0PLB1l-YKS={-$shJ|BUEx-oJshoJh>7 zNk-Kg!5*sj&r6b&Cfpe_GL8G_m^pLd!sW~R8XUjF5%ov6JXvW?!psYL@moG`VR`~! zrB+-=$d8twuc)^XoDMsf{K+Jd>-;jP&8V2Jj`{N!_i;L2i;^wwd-TytI~(RqNI9au ztY=lFwP3cOYu21b8I)Hs2V%L2*TG&@b`{GTX2R8VzC5PR?~ie{`e5=#*=&ZT;T(Z^ zD>zNDSxYf%k!a5cP2)iN$F0@pEm~2OqN5(q32fHrr&es=$)}q9yuOy;Z>?UCDuyIiw|? z9bAc1?j1bICChu)uzRW!OUmUdwr-7QMpoh^%ZWYo1k2C#n7aCDoHjjo-U7}l@9!TN z7#v);e&a?Y!x<_q^i=b07aqYLs#TTmE}tIrryrz~rcFB|fTWM9Ij;!j357Ti9cj%G-KRmC!@9BPz|sb32T*#g3>W z_m*pk61CkCrP8Vns#HACaz~WQ`ict=J0<^ON0jrREq6qztcgtN+R9Mc5tZJX(gE8M zWm?Q`Y@s$gqAWJ7MoBf2;~}so&&U3?U_!7b=L;_68oTgSAbi<7Vut{FGk1WtHCnxETZ0A3GPj3pmu`O?wgqQ;(q z!)H&PdrFqiJrhi6ZBL$yJtjT%V;WY{X&a(FdG2=7y_x0nuo2B01I`WhnS9=L!IG8F zy93^`hCO*6^7Ebpypgie%utT~n`frv-TlC*>&-Lrc4U5=cZ3pD~SJ>?T>J{)#kSU!Qa_6GJlYbQ)taQl+ z%Ug9PZ~FhRw;Y<^`BHe|SeuY4P7Lw33u?QmjPsTMs=j~OHS2GswpY~R{u8!}OQ_91 z`c^TYyXOC&R&h3#`PtjD?A@)cTg7+Zwbt&G#thuQj*Ps2Jfa7rQP`#@=n{G znf#q*(qgLJnMunxi+}tdq}|EhxSV#Tb-VK)xW}^l`|&wyKCF9MoDb{f4{)gG!@6lr zfAoBu59_AI9cqtd_j|ESnh)#V8?OHV^I@Iz<~r{JOTjkq3V1Ke?>!z&1pGtwrd|Ck z*StaZ_5@1XlXYDNt^+q4j~eYlF7Td)+B{R&yD@&o$fz%!51T<=Gx!(J;HgZR zV{*3>UI12GnEu9$kExmCW4Jr^IfgwSHa*sEKApF}^As?-G#{4zAkL8Ho%G#0uO9w< z*mQb0)Wz4@V>x|vmQSA;?`t}Bt@=I`GiK9&h~6KASf_3FSk`Ih^)%~m$N97R$FT&J z`Li~AEd9@X09x8(X|mXz8s`KVucJP&cKwEpK0Z&hR`ysXG3h9=w8yf@$M#qzX*%i~ zA2n}$2{(=_)%VuS^U77S0|dV~>T|eUWmM+;HhV0UN+~S$h`vYhRcLku)6{a`rKcn3 zV&7%Tql{sm(Muz_bT6joS6{HOm}NAc%`_?mlD(MXxIV5+dofMAsB7d(doh!AK}O~A zy_iYbmU}UkRx)WVb8UMuEp?l{n2JsF_G{@9EZk-y_j5=_F^ioaz9}&Cj4R+)zYiX#a>M3L7VnsdYtPOHJ-)+ zcAk(pE`es-i)nIAdoe3IZ7-&4ZS2Jq$AQ)sdoevv*9dLei|KJDTiJ{0vCtZK!#u9Z zHSNqyBvpGu?#!&ndX0&ec4kV>Wzi|Um7SR$TcMSmnToY?mv&}as?yF(=cPL{jn{T( zro|U!^{|yW<(GD5nw;&-v`|O)qWhNKAADfB9xMB>=A%80=M5dgr=_IbF6gv6zD)T3 z&BmRczGJf&r)0Kg)6+Ut+T*_$TOD2NPDImqD`~QalTsZUM$z(PS>4B3tmjfXtC^C% zG{06dmbdm2G<>sYHCbh+rdd6Pt~`~Pm>)N?oa2?wDfc-E4tU0?jbEh z8a8d-##Z*@C9%WufvH?Qjoo39v)8KZ{E~4yzn9FO!~uO^O5UGZnxE(E)(pvUUE0NG zGJhm<#wv}KwrLk1aYOFnBYsSM{(|U}a{Y$nbQ`bFD)l-u8fKc&(q@mJORJ0(l=k>} zoZcy2LtF0gv$*2PnSN%lxP`v>Hdu*U?DX^0qL#9<)6XSTj-)JM)|$A|PQO&vu7}*| z=XH^OPnNEj}k}69(m?r-};^VaS?m*Ymj!M7B zd0rMi;O@X`I!~Wcmw^tsJ1~(;zsHtkGua_`2fDtrEa|o4L7Uxyp1Mkj?VJJ99Q zT+?gCgCTYYx`uW%Ee+QP+#Tq8(o(d$Mz-bdK-W>FNm)jg*H5@)niIUXy8~Um9Zhm- zxjWF)rTO`_;=mBQ13h&+n&htcw6Z(UQ&sY7vpdkG4?tV)4)iphlhGk}2YQ+VP{xtz zxjB-y6t+9iLWgB{V3M2X+H!ZGl|j#7h~0rM)rzY30KaK>AiSpCfob~mn%qmf11)Y8 zf9yDOtlbgVnPf|>ocNvn^>u-NkYlCl3K#D+!#~IojBAnx?`yj@|MR(wQC0vhSlC$6 z>r&LhAEjTJ%9A>5>wL+l;#bCV_8Kx;@+%{m6x5=v_%&_|zcN+59wx1HRs70$EV&nc zWt#IKAvNz6fxax3q5)A}*X|0|DWUB7={)v>I{TMZp>EGv1h&7sD!l4GR!6vj~fi1#aH_MJrdY?qysjIkiG2pOLmUw@L@c0BU<&Yincbwm`4s`c`l^SOx}+5AA!O@N?i- zfa`T*!FVtcTnxSqSm(5ED!3~0Y;vxd z5F2Qo%kwZyxJ~*@5%$!*S2LoWM+3}(4UppicQinb1LQc+3Fd&F zEMFrTYII;7c%Bxs-bw63l;xo}v*VVqf;H|(Y`0r;^Ja7~GrDFaSOZAChSY1Q;Wcl8 zcfrSK8wZ%7eCSMYA-Dou38n$%xH>y>cfs}GHc$sk!5YB5^}Pvr&U&N!GjKk* z2z&=n%6>}O&od8U()KR^%fJBG2%Z72fOo)$U>|od5}XdGkq0l!M){fz_RFzCgE}O? zUh?bxoP0-vW5J1lG+VdAe<>TOHGZ>a$NPfwV{i}PE$QVg>0Jl5)6c8R=K|N4f~jB{ z&tL`gFSC66&hP}7{h8Ineu{y?4aF1jCnK6KS{C?uS8R!DYu9Uz)t()elNoc>s#!Rs z=YVoG{|d`5+LPweVFAVF0bDk z__fVpUzcg_VU&ICB@Ml*j>IWX#)3~2}aznPZ_~G^2qYN<}k8R(*n}g3Q&rZ5@u38~C zf?Z_yEm>ZKl}Am-OBA`~_HR`yrr3OYEc+39&hr+s(W5z!Ah!&ylq+957}E_r9B8e3 z(f#bgK~speTF>n*8zsMEHa=R(m?(ub%cN?3y#0X3moLQ1b!W`;dJl(k&U) zU`majTZuZJT#&nPQlhA!zOl=U) zGBKnQ%v=(#Z7-q8&??TFO{-Xx0Df-ol6DTxf1po02Tj`VG#LeWjM0wi(>detu_qdD zqo)}W&vPr~6lcdfXWh4S)dPLn1FasaKedYHe8tL;c1)c!GM6mv=^GeWw|)b?xm~>L zjlQkDA0b!ud8Nhsz0|@;PQsc^n>sMK`KiV?Sx8u(`TPYTWxgo(G;6cwu5bJiYODI! zHCpf5jP60JWm4z&(&9pEJ*!kI*S9&&gXi|AXD=xG+178`v}aEt6J+)D^sML;DIDf( zpd;tZP4@;$$~32R1p5LPu6&>rH{yZ5HESMT7kRFI6Z=fLrnOSbVzo13@zSl^D$lL9 zc*#~;bH5AiJmR`mU!oC$aTyced#^l9%%#r!**TT;jBd5uCSB`)WJ~-q#L2s6#QR-N zn@4!W{k{ER*PTg=S6lbU7M_&dv(0W;d`G=Y&UzoQGTQxxRQ1jW8-L<_FiO-0c06e{ zj%;XmphqlPyfp3yWJgw#vtQThyOMvm?+|=+#}39G<@P(I@KPv;74g1uc_2h{F~5-H zVtWJ!>>KnLQu8;BJHea>9ohK9`9Cs=^%AqnOaDPeQJlcm@}4BAl@qh)&R_G8cH6bk z!frHaS;pVAWqhr(GwC1DW9XhWhktLAEYB>FL#yQOU)Dye#p@s5q)DaBJL5n3h&gi> zF6F$GzT^!}@1iCfXrUpW8NcWeaOqzZ{Gf3b{TVcO^sERzxSDGt*WOr3Q1+Sgm#-+N z4?4QLgGAdg_ctbm_|lkKJWv`xi>I&0;`H7(jhH>oC^essn3LFKgerHR{r!FrYyvNWH^Hv} zV}vdA;4?jC2*M#$Ok zW`RZUC4-JFl6wQZ$MyHa2s!)Rm)y&Q1C5Y3UqjA4jC!#p@4pawHDI)qjF7YacV*e< z)W-f!_}ukCF+$!vDa*ci;UGuI+2^$UpHuox%b+hXf_)3hXlm02@EjT^0!Fu+*j@9* z_n_}WZ>5|W7~gV)oPFNGNNqc^H$#6N%IhO!<&}Nj(>y|cWE=moce8vWbR$n-<9k`Q zcN1f;$yxJ=H~WnD;4|KX&*(*brg1pW;4@10*$3qM!$UOU%|2bjK6#$Oqql(WEc=vl zJ-U>)u?D5?AAO!tCU4=sE8-ivk2ikb0{HJh=?(1L3U(8whe0^sbS(7O&g%T^@m8f6S0;QLPa4O@lNMr(6i0}Od@@25*Fi4H2oY{+ zOlVT2QJ{EUHc^m_0zK9wiqV?$p~-m6xh8GnG2_S3;nUcRLbci8B)J69A~uidys|2&aO`sJ3!>o4hjS7M6ZccN$5y>HSC z(d(8*ziZXIdfnm;uh%U}fqH7u%k|iV7Cl<=lpiSit}X{}$bKnuNxza%N24d1=nc;! z_8E=a)cX@Zg_S5i8oPD}3riZSYkPm#ec#_NPadjK)g}lw`#|Gp zDcI}@m--bZTiEI?tn{V6hWL7N9#7fLR&Si9o`*{st@J#S*kG$C9BlQ_q$eUN<*J(E z`fK+@_S})>duYq|&<5|JecbaCKwG}&<4B(xZ}d{5Q?vZ3I-o6oigx}f{$-LE-NAqP zsn@_>@FgRJ34k{I>5IU3z*PYI;?sA6#b2o>l0TVc`IEHkPfh}t#h%EMQ@Fks+y*Gy zle54wupK-XdLsFgFLV6{;4k>(e#$%soCzrN9$I|a>i1B_J=5Z<^Ly`g`+Sz~?g!M% zZqo05C(Cz{X7{hbM;Zmn0>Aqn&~uRei(Kco?V1LYNv1)(cN#AVe`=lBRDCI8hY}YkFx%@aAncCj7eA{1wo3s20 z=o8n2Tfk!ewcPKvWBIBJtNXTd>929;0l#*uyWU06+y}{b@^bcTjr0n>(%mw}HC=CEP&?cTmC| z8!b!;cf10q`yJH%j*lqqNH89p9r_^oPU?T><$(8XC-t?n-ntL6{kxRm>Y@*lZ@-c7 zt+5ZX{o+a=B!A*HYMy8J#6F~W+S|v0QyNzHCkBb5bWglU8Pf}|hiu_lqriVm-^qMJtX znylzaTqt)E4*O;Z7yUBDc^;a>B^<2iP_v>-0wldQaje9Ov0j^TgB4xe*n4xXtms@9 zR&?M=f*9p=ZTbA&&45^U_IwLSkFaeJ%^U8 z=aQ`;Sj{Cbt2xxH=8}?DSE{Hir%tGDUV>yh9(YqGUwbtt)UD3;SdE(7NY@D$Ao@=uZ8+XW_xTK?n*rd%uY@uA1 zVXh0yu<^saH!Q<&%`$B9Nq=4(yOWSAT82$7Sca84_VP`(WDz#WwC2nrY%xt^f@%uS z9U3gc#0QHow6F*#X*%#`X5)s0t9vLc!U?}(5l&*#5?3t3ZKO&T;TAF_i*Sp0vj|%Z ze?7MdS7gm1Y}}GXxFV^0C|QJC#0QJ8PbNXne<7rKay+)OShQJ|UL%MZSlPhH)TqExe#9 zg`_GeJbZ|}pryHZZikT$;RVfW2-?;QS|Sr_*~6-F(9#Q<%czBxoQIvtvNN}@Kb(Z& zJZM`lXo*adF7&tbf~GVE^MYnt%nO=@+IT^;*zoU{O(D69L*Vb{4SM|lI6ito`^QOK zUji7{{o{|prYwJR3}EE;<_7RVmjBcFfVh9!o#k&4_ts^AQQcdNUEX5k@XzS@=kJ5X z;OQ)Xy9Q1H=K^?dZv`J_`M-34$$tnhXg{T7KV>xgQ*6(x&%#3&blOP3^|Wtg`3qcE zyrAW8JWm{@f8j#F=;?)fKsOkSUeI3P%ly%ogg+{KLHpTpS^l%r!KKlU#LuR3eJkh( zl;LNzHuHHKdSBq0zy0Zq=6*gd8_EmXL7l4c#zk5FMpvd&HS*`_Q4aT1jpu(7y_x-# zIURX3`za&JpUw;S(86cWFZV~EJE>C9vaC?@&ej>QN*^}ApE2Af~*Lee9e;$0E z<-a^0P?x`CRQyZc#$Vn6Rs#mH*S!GvZdBL5eCMlpGJ9<_9)wtj)aF!;{IyH7{Ixp) zHTN1%_8-Op-mHK4&cS#x`}xEy|KFE4dop|R#)c=e7wHA*bd4AJ68~=Tkf&;tJemFN zHLX0E{cRol*RSK73eEqPnq`kf>;V^^%)I@9nkO^k4Et|5wyXU2bB&dMTjAm7@Oec1 zDs91;^x6M2wgt~mpbenyIlOJb|N8lmZGryfT5sGntA7J4wzuz)*JHg8`XBq>Ecv5_ zzZ>Doj&^@zh&fs-hZd!0%xW$8lY4>1TA|6x?7_II zJopq-sl0@#Ue}+zy`|mi7XL@GTV18Gk~ZyDCvM2y>WZ(PIqNlIG>lb|JHUQ)m7;>u zesqsZ-h`I>(IuBY7b``Jz2`0|>QcNk@{rCEAm7?w5a+9?&wnCuA-g1-kdMl{$i@oKhLA7Ul%S|HL zTVB!CW*@mrxkjgGF7}ZpGT~2A_=VMesXx@IQTeOi3;)PW-tu0Z8olMcN-yP5d&_&3 z)e`P4@713V?Je)sw_};)E$`J2!gcX4?TR}f55wtEzql>Se?br87b^jMv0uCa=$E`a z9?;i%nSP6QT*_PC%RPX(gO~Z%up;zeNxVOAl?uy>>URi4Cwh{k6H51e4uU;7V2kkBI7bkFk^e@|a%lpN5 ziNALE-tu1hFqGqKdCPl=^1O6ayw8{J2=tJ6%X?`KdV9gnptFs)yuW+Na%Kdh)23dU z7)vlbZ+W9>f0B0B+qx<(dCRjj*xMT3@{CvUmX~O+c*{#-()>%_@``-STV9eT@s^ix zrRm79-?)XhJeTu-r-zNU@s_7pr7)?Mp7C5p?WFdO=CpkT5mC?Q6C28Aw!Si%ZNpJIJmb#4>JjEtuF0QQ% z9&Y0WFHN0lQSN==3^yxJ8!vbk>v!Bl6%P`RA+5dOxt=Q3T~v9MaG1@5SMq`-ch90Ro)y0dK(A)3Vcy8@P!{#{x{T0s@H!n$#aDG%F%OGDU6qRju0n_X=yLg zY?^;_sYbts4rvuqdM}NCtNtx(#!hiQV`p_WEUQqe*Yzh>Ay&Yw>MJz2^?jz4DRfu< z#45D#edf6#oA^G1Tg*f!8cV*<629ls#`js0NAVn!8uv0MJ(RVBYRzRz6x0JNp=Gf(3=86DF1nWs4bW%Q8xK9jVi zFyChuIxN1=lH5GkmcGxd40;Abc=&OtA!w8DGh~~5pQY*3YjQ97KC?Kr%8ivO@%$9| z_}{fVp8XzLxK^uGb$R+LI9(o~6-L$qoo&Bb#&jC6=q zD_%>`wyRbWnNrQFUO>xLE1t%CD;{=AzhES*R&*{StB~ZENii<%6kgkPEUrm3y|%P1 z*Ri-P)Yh?BN?XTbp%&{{q}5_WDZO7~yhE^#T)?aV*KI+lGavwYtg@Jj1-Ec-rgTE|kH=J(m@S^n7-fOQ?8-46QWI+o9P z2eppnvwfW8_gp;9@4sU!|NKNiO?`evwD5j@C)eHJY49?5JIii`F-<9M3ir_VI6ZMlJ`ula@*r+_o#^$p00cLU`WWlEyuX?~wlr#E&| zw+Lwc%f7pyta538n%~}@IPble`Ii5-4eSA|G?9NvavCrDgL}bh`2WJ&ysQeEX>Q@s zEX$_O0gJ(4mj9OL@G)=V$L}|y*jNMeZ{Le+VE&DJe*cu=pXT=-b2F@+shsBb917_zwxCHzV%mTEOAG`?O%<_LfJ(fx{k^lbJ;1;kU@bV8wX8DKX0PpUHml^Lm zuJ14&dOqatuOZEc)Fd^N|KD2Fr*pfmdDeKx!ao;W6RM8z8A?l8)F<*9$>O(e!NT>Mx9oC{IqHc^R#YgS z9bWMmGx61=nuu*XXX#p;qRr+kO#}8Cd{@b78D&_sB6yz+D=ii8_mf`xy{TLl-)81A zO_gdQWd}2tcE6HJ?y=1*rb|h(6%-E=+h6NhOxIJT(plwI!eJH@-Y9wYo3AhIf!^Le zdlr6wUOSdH%xH4WSILZ~eU+{^x$9zf)8n8`vzs30d5IcNeF)8NCONoNl8eoBS{kiq zdt{@Yf*c-lA88% zEK1?;va+xLv7Nj31YdlqW`B;((;LEdGW#eAkEJZd?4$ESo?-S;93bnL)?qHtH@$Z4 zmR)M$T-xs@&DXAN4$>q?%U7lTiz_)@YR4}5tTg?hwe<9^kGNz$(j|>H%}0u_JGHwF zb!)tl(W@n=k%m5jxXQy*SibH%dzfdp`PWmWuGPv?S?Qj{4%^?or}6sn9Md^Y$@mKoFME3Jq0x}u|41uwqEHLZg8G)8R|yi2F6;46~S zsAr^d4X#tKEA+Um{A3u*nm#Y?)7HgH7r;01Jf)}GMxAVUBi9&a?Meer=Ty(uOJAYIN(0v$>SwV$pehyIVx@s= zgW?$>?s?ZfnjjUPtt6!1>b=c+14&7DJ6Jx)GP9)-RQaqm#)Vt)|NL|@HndWDX-hPX zvofXe2V8Y-IM)G{3y0t_r&gs(d0uyD8*&}OFiSJ8@njd=zifHWs@`5J(Uz@4 zlql8i*IqJ8d%!gbokCo@V&-;W0LW7?Wn(h z7GGJ?IgALo1MDuX~mJ(Rf{02`Os98#{e@4}W?_;j)Wu z-?2k}-=g=!v{pQYYe=d3h=iNgJiu#O^N^-XugR;l=E35cyf%+|I?G1Bo@F_+8_=+B zf$O|3$GA|PlmsojF6tj8S@HaYBnyjI^13L#?$hH*YhD+PQ}Vi)X!aC|*TqU~@VbbW z;B^t2cwLlk9OODUTSn|Ry(#17JzkNyYZn% zjwAdU*bBbQYTuXu&IcEP?|`eo9pE0&^Od|V){e&K-_ajswQ(l`bdRH4{$rTjD2#!{BCdx!0xaUy!Q0q)``^d3d(quv6n zIT)LPao}ulG59w49+(QI0p&({#%^!v|G75irK~pQb?`R&#sbQF6zPxR>4dyCHu-<9 z9r3HIHu3}j9d#_=DU2fDQOv2~tFd;(o-E9pcIkwq+7Yj@GU93jrHUsc+1JtRtFbnQ znjCW%pyXrbfDM3}978RRdG-+bYOIa^ZdMyjsYc%dy1`Pg2Ji-qehzSNqrc>BW}S!L z=p%UsM_vi0fSUoOJd#o#Im^PNJ#q`!3HW-Bd=b0@_EPE&a2yy9cur$31AGNzuFt9` zB-KWf-)Qn1eF``iTnN4eE(^XIYok7@_-d?;T1?GT>!Wx>M)8J>dI7vn%UBO5B-KV; zN4OKPmyZ*YYNM{fciqm=5|(^7+7t11Ni_Iw6qWBrsQGR*$-;M|g+q$Yt|%FOH(HGO zZnRM1yHT8^)hm2ACj4+hl4>!YkYq9D!_h+Fgd}9b2}z>z=}27g=?JwMBuRt9r=!A_ zd*aj4q$H_W^XX`EXwnHuCR6xyv{>Iv} ziYFwQW@%~i?U=-Q8J&iCl%U5>NRq7QrG6{n;M);uz8xh2_?G>IByp6+($Sjf%p&6k z-;P|HZ%60KwOgGC%*Z1lmuM!?P&7hgd}mJk4NJsJ|2zZ`pw6qaSI=h ziIn+x6bHS*$0OIl$D^oxJVHx89wl2rt`m}!e(hk03%(waF<+08R%~x?jFtZ}`XNnT z$0et~y5Rj4yKZ?xl4JzQ$i^p1K1F)M!6PJkTbz(2$yTXNYvqI_&r38(8GJ{gKlqLm z)yYW2n-59d5h#2}Dy-BX@gZqaUaR3`B%y0$_{NKKipj}H>XG`>N^6!h!Mh~1 zjgNMvlxC$?N|`Vl#gmaN6i!Bx zOgtIMx$+zG->mDX`yg367s?SCA`A_ zrNxK3kNz*E6|UJJEk5yoDUM_cxo|R)$p!zHN*(=QnrzAcrAc~S#=OFbNEXxN|FW9G zbB6~1m&6DEm(ao%n50SkUnX3Yzwm#V@Ue*anSVMFDTzt1Su>NKh}1@^_pllOv1$TqhU<2`t zKPK!1&wy9JJK#ggJqDZzPLJd4(@z+9`?K1_6Tq3^e89MD;+0?u_%WCR z23n7^Pq~Qk-s|Y-M&H<2ULR*GuTw`ikF)=DR#yAd-C6BK=!x6F9zbpSIQvh|ctAIN*67XX_0HEx%QrPNI0|f2ue8jEkwqAA;+_A$+qZp!W~=W}kXFPrWnC z_MZz~2mKcK4wwS22e-ga-t1GKfww`u8Cj4{Jr-Qj_Fc<9*E@Czm=@o)Q`SLgWe)OP z%l5W9PosA7TUqVocL86;$$NRTDc30{fC=ENLuI2m=_gt3B)-3s-lMgv0q%J`IgGy$ zTneUQ7x@x;7obkYF9Xkl7XT$3PYK6U!ts2!3ZF~~Pv+Y_nQ!-GzTJ~A15?1w;7;y> z*7Ib(&y$yeO@Qz1Bi@zS>V3QG*O$KT<8Ivq*G8UFZI8Q^8(I#UtW|Of{ zVv`X^eLRaPY%&SoY%#_$Ta1N*?S<=Ldx4tmMX{i;y(nzCB(@im3VG`fA5W(?IkUaE zCO@4zDXZCDOrm6aN%9N%k}9#ic&zCPHWzq>&BZjTTunBYB+l#1X|TBjJ!W%}tmh${ z3*lgMftt-l5+Jd;h@&)?&TKBm4K^39&F11<*<83TY%by(N;VhcnaxEZaxt5W$3%ICTmHAfv`ly5Ojqx@e_qx?2f zrBQwhnbIh~MZAsjEhZV|S7dFJZ`{%-zapu7D2?)4#D`J7idHiM)}ZWlwXkyqkMQnwxqHdD4kj%uFdLenhLA0!uCETR$r3} z>A5y*uW=J=ucx*cv-TP{SbMoPYp=-^)?Skecf5XkC~IQvHR(_`t`lpo#~4kly&j|c z;kvN)if_DOTYE_}jP_Y|Ty3AlBezQXY}``&4DSGMgi`5F((@_x4>)2neG|1#qO6n< z4Hlfq6${Sf5ZAEa#IWSc7999`Pv8eoez)L6PO}B4p-CyK7MwkU+T+~Gw`aA<{eZszWJYI`p9737Ci4!8{>6z#zipJB{$Jb!=7B-5&G^vs8LRxo zE8t_m80ErKz`5W;a0S4&aN(`s4zTE}S#Zw2Caax&9he1HM+?qmMwVw&_OmJb*)M}P zzyqc2q?!nU0`0c;GDx4=$zfO5cEru^C@eSPv;*0 z8l9v+`yy}&xEy?s?=*~FCy&f(fByQx+GW1UlbrNnR{Q2SFfrO?zKQN{eivL1ZUc7# z?)978>o*6$(}0%goAlF~&Zn$Rx*d&o1Ef{TNj#BB?*MX{v@a{4Pgy(XdG7b~tadK+ zT%Osv`?K146GIQScGec&&%zdS79-F<>om+MY%%eTEq!U<*dN~5la#izbN>7lD^{*- z_z76EMm_@YH;IRjjXGyYKJK?X_SoZ(@7O_!uL0Kq?$@4eK8A7Z;e57#{xIg1O%A^I zH6thXH7QMf$pa4r-O@jFUlVETYepU3*EEefQB7sMzqdc^?@@USX<*NYG4z9+QfxY6UlXqNHKS~~ui41aQ`w1XrlZ9gpGgz=zOac*nglM6_M=HtxV{$L zc&O}0=hMoZe>^xFTn4TJ8pa#YON_YV!ynqs3K+6!q zl<)%DnG0?Kv@;iUf@NR>*ct6d7yN|lSHK5=_F>Yot?ftWy+PaYUc-KL-d@6ZV3Gak zyq{Fno+vek46^KWdaB>~Th4v>$PIo1c(BWy^`y*VpWbV{Zy(3{yr^z%%Q;oD??Tj>Qr{)8F+M#LEu00)1#ZtILI-0T= zD^X)K)yOI7N2K;Ha%<6luyIRK&srIya*40{D)%2;8i~AK4^qu`k#gC?-Kn%7+C@mK z-B9Rg*hLy?QoBfltJDp7U9uJ^hn#TBEv- S77=|bU4Hs!MJifECjURl3`)5G literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/sentence_break_fwd.littleendian.dfa b/bstr/src/unicode/fsm/sentence_break_fwd.littleendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..a7736d18b3ef92831c9de22c80a043dd3b13481f GIT binary patch literal 144343 zcmdqK3wT~tcHVy^3y+8KI1V9%5W+ZwFb-urloCoD$~c5lN?b}QWhlc?h7v+3A%vMw z>LFB?W!aW(NxtB_E!p^fm2Kf0#wLVJ2yrPT#37VY;<%JhN<4&8N-6pO-o4LzzWp72 zpCp6L%=4F?_gUwxz4qFdv(G;Jvey0{_?>Tm=PM8V+OPlGLtpvU?|kRCe)C)3`PNsy zegC%}`1Y@T<<7glmHq9<4Ovsx$bbC%;ERzyaCXjUXdKpb%J9#P`249~82QCfKQj79 zPy4acfBcM}IP)jZ`l+*j`kXI~`I&Qn_Pn1v|I1^4{(`@A;aA3e^`gIf@!z}T7cTw# zm;K`SU%LDsT=BIDzkKDdT=fsH{zupR<7H( zty9~kO`p*|bJpyR&aOFg=gog~!NNt0mn>bjd_{N9%2ki8UbA-H`VAX5ZQinVTkrNA zJNq8rwR_LreNXIv^1#8Te(&kuf94Oq_lM8^(Q|)%=s!IFA7A)SFaF6(e|q@OUjFk} z{`0H<<+cC%`d=LR%cKA8jsO1UU%mA|-u|EO{PnT#zxy}u{jc}`_Xq#y!~gry|NHoF zv+NhL?DMCp@LwD?=4XE9+^>uq_th)D_O%HUe)*Pf-2Sae-~IPbKmGek;d_6mG@kq8 zKR$HmKm3R1pZ||a>BT?!lb2rl(?30Y_|N|AWhMBZUsaO-_4U{P;xCRI`OCjN`d4o$ z(f|3*JAeJx$BupfZ{B-PPvOdjEIf^?ayl`m7Za#(-@i62-kZL>F3U!*&$6*&vg{)0 zRr&P|(0jqrFJ)O9bPsqRNbb}Pk)8v+7+eh`_YAs3&z_QHt9~b5cR;@bc6=wxt^gN- zH_yqkS>KMdHK+IfLv(^M;7pKZ4cV!us#ND^pU-P@jB4`SFaJC(X59GkU;ElOzVXd( ze)qe-`@2s+t=fC>#iGvsJk;5Lc`d26x8721{mtJT_*|?jQPq{``=8IUmxo7$x;j19 zQObAtWsQy5&ER%$H@JFnLv}y36)XaK!1ur#ARE@0jR2#;1>g5;y{`Kcz97 z4*I}9%CZqI=cq5mlK$-ZUykp`xUYWoqVc~J+Rrz>aqF$${N`>pLPrWgKGxjogWo1;hniZ)fWsCWN{Hg)t@vP^HYo`9(8$~@J}_s)v1 z=vq{AqLwjL+w-;QRe#ZtjeL-&4UT{n|CV;}P?qfixBolZ&DFFY(1YB1@I83%g1aVV z*?r&@c(cBnW!F5MWv_#-BMsRu@D4ctFB`InpcSkJJHS)mUC?*5Av^rv8nU@>G-MC_ zYL+#FXShCpVwPP3?)dKw*$d#jf0AX_zS)pXfL?Z@-t9ksCBEHNEw%K1ho_+$)sqk{ zzu}uti~M?T_}v!_{DzMmlVzKcN#F37xfkDW_}ko{_IG#!;C`UDybJmg$S%yXQQ%x~ z9T@!;n)0|Tn-27*uga<4^od_3F3_9)5>#*dn5uW&@AvV%*B||8tRYd=kf_?9+ofoD zpU-d1T7I@MYX@_I-rptAt>9^J1RMjS&*Pm17lZNOM({RqTff|x^@1Zm$NMW?U_JP3 zdZ}@gN+_4geA9_P-k3f0qm9|K;02&kz6^aEWT!P|W576Y9k?6Z4;}*d5^wAo#06*k zL}PaC>5bWW&|AUTgnc%pbYEL8rTL~kl;)F^axNvk?#Jkl!R3@trQ8FK0hRL8x5j#3 znR1ElqosY));O9LxE{O&%B}H={$CS~v&Mb(7svZMQW=Guly67t$oM{r`rDyve-m62 zwZ0eP=^G)s{tt%sU3lvN{W&Oq7tT9a{atv4`|PQP>@sjaXa)PhtKcp00l47zprm`& zAJR7fe;1zm{mOUYwr3i$LqOk!tC7`r;l#cjPk$lSpr~q4^wm>i4Z3I3y=pS$D@+*0 zJ3kIw3a$X^1Fi#ifCs?>uo^rAUITA{cfg1x@W8E0`BH+Xz_?`%*JhGAa;0U;WQ$sc#ocF)76VM0L zdwzairqB11I(Q4b3siy+p`*4pWaok_!S&#N&<^H;C7=)7zk}zsvmv_#TnT!?5ip{! zA^WBNeLyh_N#-D*>D#aGliunwP2c$5FAnXE&qh&BP=4db!}CaR!hg!LW89zdBeZ=m z33Pz(fj7W=pm8*<1RMjWokslvzwys-U5o^OjFBJ+Bf-<-8-G>*IzBgy+AB5v8IITM z^|`9;H@_Hb-n9G#%r{m4>ub}aFJwa+qrdz|jKM+q$(;5a^S*qHt|xONcn97j=vuH3 zybE6a<1Bj%oc1CkPLTZxqsy20CICN~(SJ&RJ28&Yw{m^<;Ve9v7V@aRc#!#2ONHDn)wbH3Ym}f(zoF%VtKQ49 z8^BZG1E4R*Pp75%8I{HJm``7ZtFngdW^g;W8{7|C!6L8&JOy3{AA-gPR#3n>;1%#d zV?(wAYzAiyV@3=f08GDzwDQ2pRqc0WD63dCp4-V@b*Qz

Z*M3iuF=9g}5evBEG` z;Myw=_i+CJSPhQkVejX3G~LX3;977$SPxzY!>^&|0=I#C!6dL5-1m>Oto2%Ys9&x0 zWYf8JPj)#y+D4$a<3ccmp6my*GIae<#&=Cr@0z~fx?cSgyazuX?@iT{i7y#li~8O& zrg}cUHtqeLp?!5`u^KcVlzXzntPc6Bqn<4LUFsX$1{Q$*;5~5qBlJYzB5(&d@82_; zY$nf>E6?f@uKlcDU_ICco&oQJJ)2np+`{wRT6tE_a_whz*Eafjp!e#!-XT4!|KGn?5C757 zp4CuBb9%3yWhAH3-1&dZy9HXoe&EsE2V7rpD9hdkqn^*Q=YU5DA93wxwd6nYL1GlA zXXVk{75%?apYeLeKyQ(IHuq}fUQXfa*+g3|AKJL=MdV%q^GJIazb_L`G zPMzA;Hf`GU=`&`ux6hRJ1q&B0TC`Yu*UOf#T(#=4$5tz?jhlM6Z{M-+i6{1l)E+rE z%jSX}pp>@e^l9ij`Sqwg)pK)tX-;p-={-4p1Uf6fUIN{kUt8|VTwg=h9MV2DYmPbE zw0ZNEEnD~O-Meq!6CvcRTyh*#v2M!mRX6wK*Tb^r?K^ht4D!Qs-jAj=JO9x~7c5?~ zWU0!(e8r0H?jDss$V<-^;0CZ2JPk(vOsxCMpcBDEU=i2@UIwb2cXQg5H9xj`^_n$n z3vCynK@z8A&3+akOi%Gca8@3!vNvWL(>8DG4Oi+zh&7|Vvundfc)FKFH6^?Vk&YNj zS_PN-P>G9sN&HCGtg_2;!KMqUY1Q)+`}aRtCEGvEavrMhNlzuM(m~5sE0pM3e-}B@tD27WeN-CXQc{?@#%$Tyq3p3j1%~$WYXz}tD@td}G z-MaO9^R{f=x~=bVeU)j!WvwUrp0cz~ozboqTJ;w8D~n9@s&Ye{qTjCMr#b0`DSN+O z8(!#NT^FLHzIx5ZOB?R)m-?#DpzjJrlc?X!m6jv`x!@X z>Nz{RLZ6uCuTr||`XDWR*=3SgrO#>6W2oiRhnKaH3+1vZ7Cf0VR`Ezd-!6UMs`yTU zII@|n3WK+9eW|UZ$5xb8vWcF4UjpJxpD{pf5Uw6Cd}+$%)BPyb>a^*q(Kr&Wj0J1d zNG%Pu>YY}g@25=WrF9=uPP2SZ9&GzMU_B@v?IHAYsSavUZK`Wd z5!*RVrAS2|UbQgwRRh-A2tDo2Ez!&$-$>d|`^@g1ZN0tQYig#RV&ACQLp1zV zuUJ)=W!>d_O3*Sz-z<${`8L!lWu=vopW;oW*4C^oD4TfcL?vS4O_*)4zbFCA1AJ0k46N!D+w3Yz*80y1)wX0{HnjYSHsozo=UDd^XPK z((=V`R;|*hWa^DWnV!F#{TOiZKVV+=OAZj=*!?#>hL^p8PGg?^v`G6&0K2+x-6#`!Mh%;1&6?oSIQmd zKyjs@*7G`e9%Z=$+;l$A1bPqjBXDkBwo9Q`<<~br?*d~DAw@F5sOt}X%hf)zk>?ESfp7r0kWd3V*$V=tMsX@#AYmw5v8mi$`v zFdfV#Z%;vA0$<3&Tl?sO1qvK#h!N&WfW4uPjyG2#sp` z9xqmyZpIW@DcqaW=A0_^^2*bE!o2$QVlJmus5kQK4|Doew;8W~cqOWwE7fM&ekyIp z`7O8eFn@pe68Z+P5xfB20!{QM7lEt5!$4)yTGdvr)z=)!d6!+vo*Ym+@jA`D+_&Yt zJnw6^6`t>6l9 zylZ1ih`$v)o9hX!T&s>@o$Ni{38iu|p-Msa-@0cFP_0)kHgSz=&05yz+_nd!)I?|3 zf`wIIZ{C~LYc_1$yrqgOP2@Q6&v2J-OMV}IHa?Ai@uyy+(wGV zXkKrD-hd@b)xPtU8^LH|M z%Gz~(k5{Fqe1s97YOigYMkXPTY055nk>_O1L^%s99g01DhElGY8>D)CZOZ6z(`K(n zg^_|&vV^H?h#FhbOj1UFj3nl*edg>A^@Gu)Z1Wa9*M4>3lm?^BfQjvV z@ND7=tj0)%&T{T~0$aBgt0HL%)I|I`X+=$bZ~b(Xbx{)_;mPvUIaTw1#c?V)|g*9*%szDLWB zo%Q;F@Sdi1#`6i|k`nLnU8VY`f7U9mTJ6kPon2a68$yY!l~gouD%z&_@E%*uYQ1Gd zsne-#U2}>RPnXG0BeZGNKvkQzlqogP*`@hh(PAAEo>{U!TK0b84N6KC`j7!uOUtpH z3MDI6y%XM^y`}XtN~8Ig`nNj0r|N`fuT{pX6;f+;y_k|?&9LL%%gkA;9xK(a`gZ+=x6yeX}vUYi-Jx~beNU8T#g1Fn#akN3nbCo_PAtb3&HKfToAgwQb+S~V zoCdYC>M_ko^ECs>O2%;r*Ha6-etP2N_>@=UqN>{CeQclE+2u82tuvPL?$)W59H(T> zVYD@)y}L*C9Lt}#drLS*ElPemyGkn(ymMMPEwv$)2I-BPlDA4cM#5VA)R=Vn3e6eS zJ8aq7yFLGY4J8-S6vqIIjCRIQp?n^QNXRnD0^|ItC7cIaE? z%?~TbY2K`rz9k>Wh(mqNo3DM*eti@<^Gd6BIl@zSPE4(nG}R*)`(x&t65idjY4f(; zQqSXXp3Q=V`4`eWN<05ijXsMtMTevm&05>t)?26Dpt*HwsWtGFTBmyTx2mnUT&7Nm zT56fnv$Do2JNnnGP3luMPM#iHtuIr)lV~m0%345YSG2Xz%2#}z>><^9T8>+$q#M>q zQ$B0Fads8o#`PPvZ1pPIfOVLr>pYez=`C7ZdP20MWYkWnr?hGXxXw3(_M~~B$C&-v zn@ZwTL;pLaHLjA?trvFp`;T732q&$Tv~>0OXlj|FF}lXVab+~FjMvQNKpN@)_0^Nj z%j^z~rU%#?Omjm|SSgEk5fpdGsnb5ybC-Hv>8GvhJFHoF9N`bDGrTdSXBcv4EjohY zxN=t&+p~;8^WoYdKN>|>wF2HC)o@3r))S;rV}sIL==k+0?N#f|JNrr_Ov{sQ+qAsj zGmkbL@TR@JVl#IS*S0Dh@h##4St`mt9($)w zt)I&7NwnU&?3+K$`jXaJ!LgiZ~Ez^l%9WI zv?37~@16W@Zl3q(9&rTTmB}qr=W1-XY0H*vK|<*`EnkbOCY2v*VO#G`%Al2x(36Xs zrkutWpEoMbRlVMP~N@4>XRmZuFd^mfd~ zY;Et3&<0d0+QE!XT0G!=pr6hA$ck+A4NvQ0%%|R6yyaeYZ@>=lJ@68E6O8&z#wB1Y z_!!)HA9k4F2sr<@Sm_6c!07w4>{8GM4uI2to7HpB3VK2I04wX@60i(B3r_nsI=~HJ zT-F?Sxu)=~c54nhwb;!1xoSK-*xr_RQLFYDulse@@xgSk6}$n4-%aXZJh%pY2eg2> z|C$^^H-ZD;5O^1y`5W{|U?OP0iTw}g$KPa+5&8@`3f>0UJ=7W)2h>;J4!sYo1^d9W z;0X8#oc(X&`ulY`y#v|;UIrh7FBP@InvdRe?cc=xN4;~ZkGPjy-ld5w^1Fruyd?A7I)|%7R&>i{pQ#pM-r`cURO(6M8M8ViGe1o7ZU_ICmUIib4@zkwk zX~p>yZEX$q0-cwW8`bU-&aHO>c<^Cb##xyxvxDvQakPW> z+er(o1y6z3!8_peZ^hh?gW-U1(kk$1401#SSXUC zOi$r1@_8RnPp-V5#vEwFhRWW4x~Cs(eM9dq$?x38PSV$TkDz^E5_R!3^f~Y%cm*5* z$H4f1g?AKK4MtLy>%na*Q`{NVoGOe6sjH->;@2@)7#v(diuSJNBI3Kj<2&3V? z$Mad&_*?1gz#TyO8g)aS*ZlqwXd74pR)I4J-vw2>cnZ;DX#AJ-LqNP`(AD4t@N&-k06OxP z$h!=B8@Lxt0*bRXr+v_;^XtRVW8jQ$#Qs=vmvVhQxCiLI9r`qQC%+%V6A}NEO!g~t z=FmD0>g^NncIf^2b)(*>gW@QJ*4@chD7@J>=RC%r-N7!?W6!PIG`=;W;^?a2d=yZKBo6lF4b%C41>P+a~}Tnq33DHR_1ioHuXde z+2i^Bitc#7FxS$q4kp4F>2ZmgYCz9G5IfnvG5 zqI`oAn}akYmE^eun}ZTh-;!dEqne}-h%=vPDXucvL9g;m>N*>hatI`|T zpXYc|;Ejsk&BULlUVL&=`14qX`1(p~lo7rM1C@~WrV0bp8li9My?W}JqzICK?O3nevb>UBkOhXp?h*S73Fk=nAN8~1R^)(icC(_2!Puy?BzD7Kk%cXE!PF4%yw3R7sZPUZ|&|yl`^24%d ziQ_QQyuS;6ZL+~}n9~w9FU)i3k-}S5m7_Ej`UUK994C$ooP*D0*uiMzEnlC~`(+uY z+?dHmC()D7oYYhDE~>vcplio#$|kq(+$*aQ#W9pK^6lAK=bWYDI1OtTJtb?M8ZC9= zILTp_ZOUfM*cMh!rNN=1q}(z^wZ7f5&eJIw7B#sIPdS$EKTkVuZ?CrE5xX`Hs-O<9w`Ea?KvRSj%t$X5$0|%_# zv@yfwFZ3JYG-UW!LwQbd&6{hd(vU6hj$w1c%v#r#u%68^Y-Xn{gwn8KS?jc}t_4LJ z3ges9sW#A*(dPvF260`E7?S!%DpcGUcYXdni{Gn;EcSbi*@Eu%MJlIcZ2HaEwQDa1 zABt6mq+>jVs9o;dxvPjRo+S1a9Cjq06!!~R#oB59{6#FuM~f%dM439>l+Sb0j$(KG z3i}yJk~$744$G!bmtB;2j>*Yr;a>TQU*Q;IZs0a#GxAWZyoymrQ-&o~&7QO|TfR2d zqqH<-wytt&&Q(LUHPkkvkmy^=XnMnj-Mcl4_7gF6Txm2oiMD0xRNwL3=jys4J8)3* z3$=rI-!(^+lgqbNM$n8dqh;H?`BWG0fM)(|5XPR?t;N*y73U)57d?N}7uH}HJFMtl z#SC!U2S?9fk>>KH z)OFjC%?>5zz3G$%qh*vrQzjq9o(-D=R~)CucWz5=)fT=0)@I5#hcSq9FV65RwQjSF z>%^2CEWlc)$bn*$4jcY6JM0In+=(yfnsj#U*=O!4w9vM;nKNY*r&Ll%W>^+Xz>3o3 z8YcG@(qX?x7IF0IJ=^!}+rPh3t7-XN25HbW{lJW99j6*{sA3Guu!^I9FfUJYN@e^; zn$aSzL#eJ=)4R7i%@`w=S6ciG8Z+6YTJMN#%9QX+7K@n!bnm9KRER?z$8{}!Q`XzN zqi^?~IO?*r=;yM@lcy|M(JlKod5Kz!ODiqrY4oDc;KJ^8>$LtMnOex7rrLSoIW0Lq zNzvh1ZbMh}b7@L01D4f#FPUpk*ROWyz2Pgyc^XVWo;;}iSV_91e#^?#`FCFFznXR3 zl*Jzb>FLp3D#aJ|3Grxit-ZaD*O+y7$FHO~^ch+W(T|D9a-w3px2;z{9TF_~ltb%v znVdWK8`@o#jCYqE?owf0C!3ZT?dp#z7Jk7NN%@exWz+PWu4`R#`IAxO3Etz5FKRjU z4zdRn&pLjBUWTWj6{SHu%cEa;s?T~q4Nc=RzD#_|>!s9~O=+D`eCyP=OrJSRKk*XE z$`VX_zo96g%NdU z=fZ``SIT#MW`46fKDQ`!sAB0_IaZB?uY%fnoMCGnzN*G8SEi>hU+JJG7Bf6i zSQ#;VJCl#vH93raxNX|Pg=xITY!1_1bHZ#cv2hjOId_ejvhR@0-Q*n}XT$t*OI$UQ)Nn=#*v@uGOX)NR%864Sp3y0GZ`l%d!m7R~X$;Po z3t@a!7%47_D;ddrDV25K$@obvVoIxbqSTM^C6#RY{L^dKk#(@z)W)9bHt`)6R>X44 z+BDrtI4cWq9eaKJNTPicM~JMN`EZ*SwU5b}b!iQ+wQ0 zpKIB%^o^<-)wJT#QDv7~k*qwUvKIAHE3rzEtf10iO@cL`V>2tst#Qq<4%*j@_E}wv zrX$7qY~sMgk*#cJhl zTtq7~KtUKp0sm5)CvFpB~EjTsPRJ-d=Va|=8Dl5Flog3;&qp0v?JM=aePnMZW z-5d>+Gv$`2$@hY%Ih!x(BCVG9tXi{f(-y2Ei?*EB%|O?ANh@~XaVZ zC#|!|&xQ?tgUYE&OBnU1w&Dwy`U!oa+W35Y??SqMKF)19edk)?;kl&wSl;b?^u~Fu zrEAfY=N2O#b)X#qa#L$3Kb`RxZ+rf($FEeX+a)Per>RvECXuZR7w_1i z{w9s9>l9zig5N=E6(8PLS;nXF%4zxDY5Jb8V>7!R$@*#~1k3m^UNFaTwI0RFf7^^1 zGiP;Rv)02d_1d*;3vWh~zJGZc(tHngtu&mD>F2VkTG@`PAWJJ_c!xVb(mgVptm(2w z^7`&+ZC;itr8mhjtRbZuQ|eypq+9YCrfZZZq-Qti69~@RLqzov73AoRgQ%!=eft1Lbp0l#b3h5q*mAd-Ln&oX*eb zdT4sa$*Vb^FKzSWgU9l_AJbhN^TwU_{-?(1IUH;{pHnb^PK;5?Lp?EO(wDPvVvOSW zq?j?4G&KuS8}$i2+C$J9gio2OSans|$x7QBXx2F!K9A?(v9-_RX@)QP`8oC3JJ06# zujce4sL$Gw{Ma!uo@n{3ohI2a2d~qy7euKWb4uG$s}0^8_LHK#=4@uFbLL5R#k$T#x z)0yzko%`sciy3#snqI$tBlXK+GkR_LPAh=@y|x^x6jF_< zgE61lYwJ)C;UhB36J5)0$u?Ztj6mA%m+uo*=yL# z0*k;AFlsG!_~0Qh7kmiLUx$r6Xa&8X;%RUKy|!#W8`kFzEyXGw3|~g-pzOId5#B?f z8OXP2K6Dk3=hiOhtDtc?o-W{0AkVEyQ2A4IK(_*WZavTStKcIb`|xoq_{Add9WWg% z0KMQj@EXtvc62x1VTs9VkudJiokDEiQ0*k!K;-y_L3C^2++o)QVTu z3tY>a>LX}R8)XOeyt0@p1)DL+Ki?AL(VOd8=BHe~2Uowfrl%}AiX7;=DN5ygQ0}`# z>G`l6FozW6YgRQIi+#Zf_Q;Co;pXeO^?b7CcE;SxCu=R&^2yoYE*t%?fG@3w``4T0^SWf{!=;Y_+@?2PU&WH zoFkYB9s+a00dNS6o)vR-CG>940-nlwXU`_*;CgT~Q0^as&I01?0j~l1WxWkm_?aD% zo)5KO);RINeL%gfq=fF1?%sv3$1)meEw)|=uJ(g>*f{7&s&XjP?R4c6ULoZ_i8w@#yn2D*MHr;XG3 z0)cbD9pGWG6+8vXL+qF=~bv@5Yv zhv#kClAk(}`20vNMH<&S=xtfsp4u6Ir^Z}K^5w-wouj!P#ZQ3MmdZY5EuG>uX+?Mj zUay zkLqZtcE?h_H0Yjitw%m8`?EUX;a$U1p=Nk^ikJrB0m-Q{sRm!GCGZr3uaBRgD7BpX z`lMXti#dquzn`y<<;vrA^J{zYC{!^lRnJ?;TB#B25~{s*tV6l8w@%8#`o8eiu^ztx ziqnuqJ0t3$@YbaF8EB3F3pn5R|MJ>g3)4)vb+-=ukQy5dom!v9A1g7Rbeu#Xcg zbE5x^^JF>6S|86V_rFOsDO4*)lS}?L(qt{BQJeg4tU)`SVVAPxf1~g;FTQqOq{+P6 z{x_)xOFAC|``=i)sqnvXJf~jU|He|vTP-MD2D6Uj8@Y@kFZp zZ^U!CTnfk4N|&x_D~11!!<44w?SJDi(eUIodgT;c`QJFqX^EN_M!JRnjkuOdQ;GgJ zj#JCy#$nEvwM35_hq5x+Exk>JUyVWxg^(YQyK}!9YqAc}vR{qEEZbD&SL0AoQqKKq zEbAPX{c6%!%Gp4EHD%fKo~NPRN9}+HzZ!)(+-Xa{(BH4dl4a_cy#I+`jig*IdaJ^s z-?4{f75|tDui_VDUPBgtk#1P-1Eah-#bH_eT`=+dHL2%$Vtr-m@}_)Bl6aoD6p~Cm zP8_4+Jz|dYSMe8dh;{J=8`Mw4ahyX@d4y=pR^R7Cv7ElCM|swm@{8W4j?ahVnkueK z;cL+}+&QlJd?;mXi8Pa~;q#Gtd{}p?&phYb_m(jYb}^OleLrsx%cWGhbZ_0!+ru@* z8#Ac4hh=HyRbC#_T4;y!3iyZ>DwNH`{#X0Wh5cYpR+g-OaE6;&58#+4Jsjj(Cy$v6&-PBBF z*5F!EE&2M>Qt3*)f%NQBC_MEB^0Q=oiZ_rY!#+aE8z^lBeoxGkR$bFKC*D8~RT}mN zGEXr`6K^1K1k&v14P@y`E-NEo=OKCnS+c)3koCtDV|?pVSj8L2lBQ*EAn~QerIi-* zsy%qbO+%em?8ns0YRFZ?gGcrgl63CUo=|D}-f227)t)~ET`VwUOCpmIlIYz50=Pjj;%q;8s-MCbyjCvne`uHm( z^L6T?%Hzh;ri9B@G+16Lw)v*iRpD`C9&xHXZp=4r%e5nkOP>dY;y!cCKsj%HBx| z8_4@e;XK6}-ba4oW$L%plvbpEE38ymR^CU_tUcQP-baopi8A;?72Zb`@$QqowDW~*?8Rf7HZ};3v)4D2tKa!@T!S6@?luO#*)5qzE zI*n>iA4@przL%$ut{J^ndHOh9^1gO|%-A_vJ$i2=TFQnJrC*Hnx~#*VKH@v9?CE2^ zDg8v1r;keNJSm@znY?)_(iLwW^HLhx$$;KGu1UvYgn&1X?gT~%{k(Z9l9lIB)}kIz z-aOW$5=3tv$F6wum}4Cp(e(G`Q7BsR=81Moe#Vrrh6j&zI(<{cLQC-ANoDF-oAtMa zE3CFsOCq)E&kB46r*$zK$D?sw?{25++VDNCmk(6@h1wGqSSlhU6h7Mzu(Z>-bIpDD)nG(%6n(C75z}`jHR*yOrp9vW(-FsrA(NF0zI)P0QxG zlZ##{t(7zJ2JLG#$>@I`J+Nw-RFSB6A#7s5D=--L)iixz(q zqN2NYUYR}B_)UnxVmX{r6u$|P@Fut9=hh}X`4Cm*m$(ZS<|kbwa@yAqa()6~ui#U7 z>Uge`j(*IOr+}_iZ@H&U?kOOyVx+OuZhU`YEaTHuoZ88x^qF<6v|S^jVa2kBm3Atl zy70ZO1>#NB1}`IG?}v0-Mo&16V}6`*@Y@>r;Fu>`&n7#SNw1v;-n)J_*^)CDgEFOe z%xIJCJI&*&ZL-rGs{|h9I>wk!ZIgZ0?_)O&^h+8KK%2pQ&mD$4o9y0REWNk)x5<8QN5v-l`km3X z`eEppKE5PvL$k@g1KqOCrtj7sOKy`r9qz6Tv6YLi;$AJDv4Ny=n{4+}qV#-N)0q?B z`yYh;^%eVKPGx_61J|;@z6)Bmzn%o|)7W3P5a0IK-{X29`|DQ-SMACE`px{h(lfT6 zB>U@YcHzkl?gw3<7d!)wfseuEyJN0oe|;a<4}*OlL})Ph)@mjNU{L-kn_Er?J02GuLq$bRxJbzh|6X<2NmC z%TrzkmHl;ZeqXk~CU%YAdGNbD7)>puEz9Uz7Sds)Z619`Vij$!D18qd&(xW-be??C zholl3DWS8ligs8Sk3~z|ke1{;!p-9Z8(hnal8@X5H|0v25oS#rT+5ZmXXe+o!BwbY zSc+d#DNf6`Ci36U?$+^Q{^Ke6)jWC(PRO^8C|5cCzLH+Wp4L2iY3ylrCr}ewspRA- z-C3WmRj)q7-qK3Pa)kQ~`-5pb$;A8wyV)Wo@t8l?w3wAn>vnwQb7v7-t-G+8EzYZV zUL4o?unynXwv|m|Thcjclof19UAjnJD?!CsPVwXv%R03(Rk%>tqUl#?YgoQoPnk+z znODA-<*Rr+4NZ*n8*JgeTpn4wN=|PjJA_5al!h%_Q{CZ7X)KUixH`;wMa`oPY2j+h z)T)%FIa;+^?v!|rd~t@n`PLaNS{%6VD1@HFW0sOVt2K$1?O7e> zw418zSsg0cn4x~V<;pg!sibl5QdJ&Vw(Wo~2BA5{a#< zxXw4vy|7iabZV0KQ`P^l_zE@mb^B(2ac;<*Ibz9@5 zF-Q$-JaGh4vo&6RGPh-&`&6f{qaB{5hR0L6^AowP)#*EK#rDn;re)hZ>vc@!!n`J* zo*i}hs z>d84&?Ub#a6gH66lfq@ABuaZO*(jy;Er~Kx8zqM+j;=*(Ssyvf&(XBM{g5R^D^lr6 z!In^3X}Yo>QW)P_+Yg2NvK-%;vdz$d_Cik2c0#&0uWTn|zA1U>XD8(Rh(RFRGo@rVm&XuXHNvt=P%+@60l5(&nu{Kfa+twsu zZ^2>KTHB69Qm%zs)LPPcLvl*(HlI;zJ@u$`JIv|$elQCX%Q;>xY8g@V^*^6BKbyDb?e?dTWi#^9kGn#m8tbGYtznSdNM7i(mHmTmUHGDB(uKaG+M_kr|f&@AlL@j z=dp4cEho`hLp_@2M%RPch**zvFc6h2eO%c_q;8(lyfE8J>_Td#Djs#G6;15~&c;`r zed=)PY~2)6J-)7G3*xX^rBj%Y+GB*YvHs&sVosTL?0PgUr>-e$V*lY-PFwc^t*j_( zak}hYOAkghYbe`%IF3^?{X+i}W%Ywd!4l7L2BVB@6FUz{I|e77c61hXbTVu^($t*l zDLy$iIW^W{D))$ZT5RQ{*g;EMw%d?4YFW>yI2G0@h^E&{k$%3g+i=*YwGepoi?PS| z=uy$(zZRi=l*pRio&HfGa{Qt>` zPSEwxGsib%m%hXP5cB|a2XyRTQ?_4f$TmW6hK@SMJ|grH=)2Ih(24zt72L zpa)cT#!i;az}z>fxWC_!T?}g34BP;}p3T4`gx&sE?5BX$T)zOcv-Jx1+5>zCnx5k} z?k#rO!0FVWc7Yz|`f9Ep0WWYp7wU7|MpDCL$FN%lJ()HG*IY`PKR2`dW1s`u47~db4Z&vM?f-T%YzB0W+lNQ6a`{V6p1P!=pUuFSqtRyIM(9z( z&n7opxqcd4%5@{Tx(|9Ov@PA_-zKR{)>Ta2EIcsWHazSa)r$RCFlV|w;34y z725Z>hJNR`-T2jpY|`~{&%c*z?ft(BZN8{s$TkBDUZ`a=upjQrf0XaVLJxBv_C3{` z7d8X#r$p)buo*Dtc)qi(BP-uj$2avCQq;U*I$t!mTJTr2|F>w|k4CMICCcc5-|VSa zoTXvuH%M`ZWzo_sm8tdBkZdZGUi({?el^m3Nmd|V`Z911IX?iFduCZrDldJX{+nq&j&i&b3D}FgbuE^g7PK`>ehR!}$)}0d{~|--I{dE3fImJ zt#86;pl`zUApIsh%>AeTCOkslpPud6#{CYUZ$cBfzY)v@$M;QGaG25DpY^vRd*$Vd z9oeOS9{ct?pu=Cm#u3yz+w%u!<#qq-vE|6htCee6c`bsTXe+PH=sX5=%I2xm{XkY; z=Mb*eEGw@I^Xtl3w)G@gdEN0U7G9toYy{7N*TAX&g;6=U2`E?7p$)ASG%Ik1`U$*jM#31V?&8c-}=t0FP zpR##>9+!2H;yg`{DoDMCm6$^Zqp6jcWwokqD>3t$s;tD!6=l4ZSc#<}={O9Xg_W3P z-~}r%-;0t?ZUvTdrHNGp)lYP#^#Yv0iF&4)%Om_mclUs)A&boB1aj7lCEbaQ29N~p! zSQ<|1aRZIOI_)$tC+ShdNJXs&FCQ2dZU1W<6ypePv$xUiM?+@yrVQG2OcymY4mQuJyjk ze$0HOVf!)jM8osc%64u)<}m9OHIJ4S*7~Lft(K7HXg_ATvi+F(juGw0%xx+x#>6qC zm0m)P~G)oGVeCP$)j_y0eR)m0aB2qqB00_rP&d8g{|dhw8W1 zRF*~js557or83g(yqP*&VHJxral@`{JZn(Dr>5WW?nzG>ENk$+sWqF1(S$weIErHB zO8t7L(oI)REG;TczK>@L`i`0z)c(z~w5_T$1*NsxCeArlUVa#D;#?BblVuYp{na*c zPSG`Fn%cxkCWUG-J-g0v_>y8LXG!MZB|EutTE3S)UGt76c5)7tcH7CBrx>J$ot!vA znDOh7jE=6{PR_E?NO3kg`+M7QW z*Umupe2Pn7U*i-rm$6L!oK2~>;uJH>%0f`r+M%pI#Y}l}Oi7fHS_nGK^%D2|qc7u|X{(7*cbiP>2ZqRz_QR#P>)AD^7 zfijn^_q+C%bG%yAGNS0KYd4t6rFk;nx^-`!t@di!4O+(W%G7%3DQnmbI(C_sbLJc* zv;D$u&~eKt``$UIZ#QTS^=O(KT~ojG+dQv2zg%xU&cQ%bvdo|Q*$rApnWlMR&Yjo| zS~5*dyn1$nmaj+Clxo=xI$oNduN5ZLw;OcqdNfU4*OXPOJ^8QFJ61V8T3HRdK}!!t zHQOrN4LXifG9Acn&~XN%jPw(`K}kDCv>Wu@$*>ztQ*%1C>;@gCa@V#Sv_vghwi}cT zwOnO4n8r)5l_LFoVK?Y7<+7(ozq9?s6B>Pg#J5X*ydm2^T|>7;I%S6FFxHml@GH%h zi##oAPn(wVcq&u7bS`9f%GGrvb_l(_=AM#qs`K)0-0U`PF)yX)Y0)o*_g1AS33ApR z>Dr)eShi{B-n~ygna2K7us6&1Bx?Qceed?|JK`_r=`1JjTEt(`V-$Pg$5@Af+ri!7 zVbBFu=k&Rp9?R+Izhw^zTmfzdcLB+ZUiSezAkej7D|jBf3XXygfJ$^0I2T+Fev)>r zedpP;^&4u-mht;mVO3?-D($eWU(fG9aXRsqEjkIC^QAbWc=zrdA8|?ocpbb4M*Kha zwZJ*xLNFd&39bisf(Jk|m=3zYYOn)51zrJff@5IhhwN)X&!H^EymHE{S^CxXwbX0) zo%T?BFaBS~^Q3$MxEPEF*MOVAo#0+D30#N97HB)z2pGrl8`rCe{Tw(gn>WwD9mnt7 zuUxgN|1;dSO*(qOde8-Sf#<+c@HY4moQ}40!3E$lFcI7c?gP`oGVu9q^X9(3J+f9Q zo_rH=RqE5hIH0s{0uKYFwFrDJ>*|^_XTbvfdcB^_jsJ@$3~qd%S_RX=R`4|7_ojL- zB#idVQ`HLZ)!e=G{fJkgtj$jDDO&l6EdCa^p7W+neSJ?px%U5{4eSC3z-!!X;fG&LR6beho426&O}=HzdU|3TQrp?Fqc7MoKk>w>|IJAZ-~f0L zybj(0jkMm;-~w<3xEiQM-vK(n0Ee2;>FJex@(X64@SXl(-$q}H|y4JO#2gGbMo{8T{mQ{p$}@z z)@;~PJUdconL4w&KWoTZS`~wKzUzrXlDo~1KW?o}oGd?m`qJ)|p~p2hrnCI9NVn#_ zac_vl-bctU`3Tw@vPFxc+?)fEcFq+g9rn+3mETRT^x(>E@4hFC&|G5j?AeJtyJEf@ zmg$$pcJB0jF3-M~Icnom+h)w}-}ev8He(TXAmq)`4LoUGH*l_jDEXNpM|_8i>TAd1 z%j|^O`Ee+*9N~D$keQIw{2G?4-MJmkWynd zcio0vmTAhi@7lMIA5E;P6@~I-lP~YEj5W(S^AX^(OXg1&}q&DwasdYvf0me}>^VqHaUtZD5==$^XlT)3!bTYMIl66M|ES9o`P}ITfH=*A3a;CnD|W6y<5} z=qttt>|2L#reldVWi2iIn&iyKLJ8B52F{p|I6ZJh7##M~` z`Myq{Gk@vw?v2~ZqdjYA$QCcrHFGJ}au;>4UL99)_tN&taWra_Y|3X;IYTS7Yqvca z-hwnN=4N(Bq+Mam)|gG7xuNJ`8?&W7>xu z%J*#Q4Q*R@^!`<^RbAVcDZAdiGbh$;NE`rrx4wB8RM+SvRe?b;;5d-J6PhIYi%$ zmBqLmuZSSQj^^$siuz?2dG36E*>y+X?!AteQgrOCeDOY)Em*wtu{G;9Y|-x~#a5C^ zr`NQ`P@aZtUdXGy4Esu726$Sps(Od?h1y?|(=6X#km~PGnj%vCT$)xSdbd};%c+E} zX=VI^?9AD#9@|&cVJZ`QxS6vT@U=?$zHX!yR=#i4eoNc*cD`*6H`Pxew z*`meacd+`^Mnkqe@YKTOdee$?OACdx|l)SjL#TRa!l+oL&XPD78?kWHDP`*aSf z`^bxPP~VG^YCZ=|xk@e0LCr1CLCrVS6RONX%@x%gG}5)bqMn25TIq;>+BxW~FEnI( zz*FE^@G5v8oH{bni*kBXP9KCW0IR_Pa0p0VblGq`rJy6f*pQtLE&*49Yr$>cF3<)# zz^A5lfbk%+s3}uC?|k<24cVLEBhZA72Sy+dJst2C@#Wi0$W!3>W|nKwvjFsgXMtvx zN1(^Rsc1VBi~-}omEc-%CwK%b0wb7NR?jQ1Bj!!uPM};)0v$l9tN_ES=9H_3HDoV= zRZR`q^WZS}2xts92|g{8deCfgK6f|67j6e}HmUX}^q);LOk;@U_450gq zpjUva!HwWna6f1TbAe`)JT`mQpUG{=;DF_-k6 z=aRk`ZOnF7wUZ~qtU$eyLYX6lJf}0tG`6oblZ^7K*NMiNq^^{A`oU1ky%@M`bj7Kv>^JDy#D|0>FlF=+MYS8RYS21Rs{ps4Vn;4hH*`K9M$qTbS-|=Mg zS)XG&B+mNG)vQm~#AeoK8Cp`9^;t?(vp&(LV%BGAKv_A9<8#aG6PhYW__Z(ZJlApx2-bU^LR}0v7DOG&D_qqV%)AU^3hBz-uHx( zHfHG@O!gQG?LXfVw+zp>QoiR~;wgQB_pVv@!!*OIo?n?STA5$PJI${gPJ7AcSK>JLxg7H=%V~ZUxtd>DHl1Ht zGNqJ>`IR~4`IY&mPCeG&;!qyVuN1DnQu8azijw!-9w6l^wr5!>zj~IHhNRckv#c~E zy{0u5v#gZwYr?~fPO~iYQW|Gj=1`7&mSv79^~WsBchc%vmU$_4xMo=?-`ARD={lWd zIV`1dmSv7+S-SQt%Y0GIvP4huENgEix7BjnLn+kS;#?~YjhfopM1wV5&;9(p9hT}+T4NY3tgN}Cm+oc`v@5&n{D$lepx+Jo5IW+^%r3y?U=lbC&L7*5 zJqY%J55VO=&v+di2BR)u<_jJIz2HMI=I<~A2JPT^@FsX4+;$`r`q5|mMpBT^_AKa${p}C?Y#;g( zbI~!ZX$bT9&d+BD6@IgaIYuMS5HqoKSjfRk0|{X z=XjX&gYyc1|EFV4Ed!MManLJ)c=v(nK>P(c-IdeSEBqOFuYo3>ioL?m z<62(fSL9FXHs}JdE5Cm=r^o9R{?t!4WUqsIUg7T%HiB{w)hm1n@+#k_@d|&Px9~$C zJ!5ixC&DZI66peWkINED?efwP>jHX`S zmem}{Uf<@?wuWG7RwY-v&uTG}7@sIt#DwgcrQNeJ@Hnxz~5fl_tiLs)v4F z-^U5An*yr1W`J#DlQbGZ@GVJJnN; z%QGsxuq9_%$;EP|Uf2#TQ))Z$!d9qD#Ir5DupKM)!mjWtUfAZ<^TKv`nL5uYKlQaX zKl)nxuBq^~Hph9VKONN9+Hst=sH~ersTKWZLo%+kG_A!x)%a6O)@hoGSMi-zynMD& z@tZDss(SHxw#}2}ZMbq(;S-(8M*nB$iMMM||7XkoFnTmQZ>A^9qgnc^J(``OpPgyy z(JYx1@%d`Mz+9eh$$Po1*Y}F6YuZ=hz3fn>ZtrFD^3>R05Jw2DsmgoVvd+Cz5smTH z_gJdhd)Zng=lJ4Ptk5iBTJ~NR-zn)@TFh%Ie&wSa5?0T&g3vm>XCt$SUAvzwa_D?W zt2H@=YX9Uk6pfu-_DtT^TlgfWCA*TzrQFe4(;!Q>kv`ryxIrX64IXLLi)*qUP77JD$S%8{Ap8}dj7PIXR7#4xlH{#9M&64VSie2NjdDF zS(_+zTlmwad~2`mPb*33uLo;N$NIJWX|1Oom41ggE#D93Pir~Ht3@p%I*>nYDwpQT zeCyV|dG=MC@PwUuaTF#kskj&Hye_F>ar|f&@puRt?HPoYNZgf4E zKdtpR2Ln;b^1bZmPiq}zn&yQOaNiN@Jz8+0es^w4XcxigRR+v!VpVqPK z(KK~kQ&!E?bAMXLDyK&)tKm;;>A|Q*?+k-l7cSnhLsre@JUBJcf&6I)OUL1iJrjRg zaUBxxAX@gVl`J)0#!f(9>e{t`)fsau#;yGcYeCx7uU(N{(bRN|6<^iXD3_|SDCfPa7%uD^7k0R z$+Lf#^?R@j904Bzojg1CVs_tvYD&K^zJlxW$+LUl>Ezj?xtva(ZTfqWcM()4&)$0r zKA~JoPkQp~)9}U9$+InluLs^^(8;swJE~8feOCH%J?G~&G}JwY37jsgv@WM?w}ScH zrzg+u&%=-RUOCB2_!kKsh0JlioNmenWEzQ(TtD3A27&4ZsjdmxvtxyPWBt2lL5 zb02%iH)e7C#domg+Pme-zj0!I?X`D>Du$&rKHRGF`X1jEdUo|GmWlmK{Eh9D$5%(I z=sHP?nP?i~Jd20sVnto|LaIG{SFo(@=-jZackjO9m$EGG zYO##tP@7uG4z0wzw1z@GBrDjKac)G-_VHRsx>ZMwp=@?9H7Q$KeP^OaPAxr zjiohehd734d5zj(mZc0@F;=d^uRSZ=GEPxB6h`1_+S$p<_1t+2IdO8s#_$vs;uxlm zNgGO5k`?N7nfU-Jo7R&cG&aTvqJ)R|}JXI}Q|C&%Ksmrm2vzi4GGDZhHf&k|0@ zlwKgN;ZZj|+xP6-kAGb%YmMf)CMb2jk|zm=N-G-uYrN=Ov!-`%wMJ=3wfcHQuo31r zgBLH!e~DLGt=Uq}xA^51ImM!j&o^xZpPEV_Nk~vYowCnUty+WpRb=`k8D=ocZm65JyIZSb!Lao&- zhq;ud{nxK7DQYR+ZLdgGy{&EoqOMQ+>1ey9{pNT|T<8-lW1ZzvI$Si=iDDHiOV(~` zEzT|PL+dQXpxfiX*NvO_{XmDMDV5`SbxE>Zmv6LY5&BNI&zzmC&G6OsucRu5(y2$&Fl$YDyoLQwDAT9_-_`h~PNmDKC`^!M zg*lv_wY(-Gog5Efi84)7aXuwO{)!stsQkvLwDCKmWi93VT3W@Ub(Ys9q_M8PT6%H| zXtnP2S3n2Ux_N#nV)X)J3pO~YJ&;-%{p#qW1YXE?1ejb%+` zYHeTa|NETMQ~X9}IbQkRddzRqFLLT#Eo$8opYyL~hBvvVYD}vfTP~I_%-q!<)tJ3I zEywVEO4S4FK7XFFK;u-TO?55W{Y7vOUcNV97VQe77b{t`iz_Khmg$MHXirmdYA2J@ zqm?Y$-RHT6M8k-shDCcSqvz^-T?=9C#6X)di%<0Kwv3;y?@g7yf3eIw(OTB+l1*jO zYv)0;p((Ukog|i)O|k-e99XwIX0&eioxWw&zjK+EQYA<=Ds0TBwsGJ8FBrt!6m8s3 zhn@>A1vi2D;24gaKech6zYN=Uc(QRn1br8rd1FI122222VR;BD zd)Hae!@o!C`wf0)2>Zg#-0uUg0Ie8&2pvHUj|bO*TftLLb9&f{EPIe^*|@KVo+uml z{r`-oc|){uzXCc`8}}QKm5uvRsBGLnfSyUYRR&sR$;SO2Qjv}OD(H!|aes*4sXX)q zHpSOrulY||O#@{c_Yv1)$@?g)YtT!<-Jk_50IR`aa1@+M?#=_Ljr;Z7AHR+Jga2e; z8~3e*zX2{F*O!5Z!FsR@4Bf`P>sNRSuj+5({?b3J*tlPGb+lE#6`K8{q1(7$iSGV3 z?svm|@$&eTMO(Pn6K5`&*tolQ%6l(HK<515)}QxHj5*c%^YdKG#{CHNMBBK(k4~>Y zkLL*wWaEAv;i^5YKi`^PpZxXb*RR2g28{T}^d{gMa4VP&7J!$4a;5d>;n&h0!3{vX ztW~OH@SXjFWL-KkNg!iL>E*@o{4y{kBsFt=e(b?G`?ao4@zI#gZ>FKpP$rHy%vHtcEKu&!LP zVNc8LG!$R?+*#yPt+H5cFV@;6pQi0=#TR^Ed!0RvZAs@K+OYeM)U`8SvSD|qQ!7)2 z3#na8EgN?0DO2ey^UC+KVHc05QP{BSzFZ#Ju#2y^NjB`(qcm*8Zk}j)2f$(0D{3BX zNDKB;rUtE+kmhK^Zn?4zyZMe0ZP?9iDs0%rF{HKr{($3(miGr7=G2<1epk$)F=n+5 zdm5(n2eM%=%cl1{qr!$=e1}PAELXA%Q9L0_nNr)y&V#rv5zn@;VYhT@!(QQ4Y}n1K zXT$FBGIgF)erm&RezaltU1bNv9Os?>bWj_1$8p-C#PiOHEZDUO6l%^haZ|_jJ?m~U z-uy@7FNUq+Oy=CiT{6y>uN}`+X;l!{*OFCyS+DOESJ%A9iB-HqmAb9s&C656Dqb8R%$BRH;w|gkI~CCwUsmy! zs?WOconO7OPH4T;KX-Ix|SC6Dpv935Z>K5=TEHSCF6H4)#z){YO8psqmb}c zvxWC)$uizDetTU??X5Y?yfA{TX(4Y3$1wF9DoP(*{MMGke>kk+l^f@DSXONfudsov z;bVBUHN0!XRMzm4)B0lnU#YT`B+5wl4;`kbscX?%`-cv*UQ;Hv z8r~90In9Nv;T6VL+}P0-3m`zb$adeY#Fb6^U9X-=9@;#c;BU#@#dwJ zoEQ6-%8|=&8R`zpc-;v+$C72db2~ATB5R(X^wS}S`Ev1OIf3- zG?QAej8A3i?T0#^X_a0<0UEm^d`be zx~6{VUwB@1erd{joP&X=Wa+QUJJ5CWl;(w5SYjDpD^>BRyTV$$gF`kJE?nBpZ{OBU zA=TsST9)w+t5rIM3F(e=NIULh_r`HlS{7?FO~Z6eSvCL9E#p%uONvJ;E6Q5zaPPJB zU{oXcvSqyED3ufgS;jlgV3hG^Vi_-K$B35kzB?I~@o8#KrmS= zvuA6!ciy~5A6>X`aajNA?q0c4XZ5aIr{9*@!tXQaSChiY<^1x`ll;1dby)vrK^a3# zZ!c1&);c$B?JMjiR9dVNmWy&~`Ig>Z*H}}wfL|@>~s5G6dkifn-qDE~#R zl|ws?PQMSPHe38g)Q)@ERR(W>T07Y9!B2OvNBk!H?La%&=Rhw56Tyw(ZlFDyhoRcd z8pm}P*WSV2$n_4e52$p{LJxyupo!WX3C;rA!5$0M4z}b@)DHH>f5Z7qK&P}x?@)KJ zj}k{a*bh<{+QDvxt^m@(yB%k(dRfk!2)#Y$-<{J3bDHicKLT$qSPQ(TypQW= z!Ep2`{TH}C3O)w9ADP$CQ1_IV(Eb!}J#;^K4p?^|{!B0D;cr0S14G?YZp-7Hu9WsPfHYgtN-wU*LbV#p0Kh8SbW zjd9tV8$+m}thJOHVyrR77-Pp_7=F*dfH3@!8OLFOVSoX~;io`|rPf+&t+kd~%MxO( zwbWY6x-RSX^?uItexCDv=KCE6fm?6?c;|D@=X}oRoafhh&iR~kKIdA@7(btt%*bJg zFEm~0d-d*F>>~wxTQ~nIVnxH5c_#TK}6xT4U?ZSh8_@ z9-}wXu(=uGya3SfU(OuWikiu8NYVbMva4BMXRT5#yZjUT#{trOa#4ykIPcoiL4a zKGxB&4@jw;I+t>@69Ou7q?%jTY>u_ukTfk`zG-WPT%Bh0at`O~>{AY`=}VR`5B^E4 zfoHRLNxCb@98*pnh~5%PX0EMxqa?+75@{LqUt5c}uReLXb=|u5_JU)L=y;{Qqw=|N zQrOaMc}+PnVBMxX##eROnK0{)Dc7`S?JMos99En%DhZ`yqiSee)w)|P{ZkLE3(C5t&Cb4+h!|ka$N*eIvzkaTt3yC%u}(`^wpCy+?x=0dqyUPtD795^T29P`r3FJfiondmASb za~?6H>VfnxbuHdO*Ceiuc$~Pfr}($ABVkEv>xK;-L+%`{$?pE6m92?pUZewi#I z#R-7o)dJ@UtZMCWD(6nV_Igk8Clh~EvU|5E?+r65maOM%ZtLLejw&^4>)5@!vYpkO ziE>iw_3fKqt;hqfv1#e@Tyv1qc@?`V{$o7lMa`{ys=P&L1;gnjGuWVK8=B-=1G;>f>T0Mpp z`C6xg2anX0bUD{b-S9pcswuJvn$GBZam95FmSnN!WGFTjYYa#0xei>Z!V`PPR>=>n74LS zythhG&e*$3IX88d-M6Ad#xm-saoY5Xl`WiA-r3pR-P5yUXI~$ZBY0-zGU7P%nv0ig zuKeye7dS0n{h-}>O?U!JiausK=T)5Rk)EENpX_n;Sei@o_bTg|I|5a!diwSdZv35s zCz&`6%g70(^LFM|Q>CBm*Uc{C*^G}?TEVg)5^P~8qxDi*YUB< zG4&5?%dOIM56V=!>$8weZC_qzBb7U zyjv_vaL!;ic8s^6%8n?f>I!0wD)H*=$!At!`Dh9DLgL|_V758iLbx&R%s4$BxQ>^s-Xo_xm& zcE*55K{b2wbMRw(@)qpKy*lv&43hQ%cQ&I5Hs)J^t|>k(3mMNeIJt!>e5^Y|WK!F~rm6_%T;tO<$D4nw?%*R zB9_~ihT5Wk{?7_q^g6<_MW2K|(ZKsjX(Kr?WcBkQA8oguW$@X3Vi4~6e;VF$(f5g` zZ+wu-P7HC|B}&W3ZYpzr=wH?Ql&wd9E4758PW#Pk6$fb%fBdat7cJrcFRkLkYJb4~ z&#JeIpTXDr9Jh+2|7+mgmC=WwbF%Q|TE$Ok8DILmR;&04U%O`LYPE`2-|oEhCzb8a zOxl|^pmygHm`e?QJ?+keXZWxF5&sJCF8C0f18SQ>Zy=ikQ{V5`HV^iz=Fom=K5PMD z&4;}Rz1H(#tI_#3JqOK)eMoq?`LNGP*E^{Bu!~u^=r3Kb`LKnJ{4>BhFaSOTpMzT# zF+&RG0oCf%>?CO;+zCF-c+;EMK?)uRPXfuk1Z~TB$Dto*{LeBvdU248=fiG+HwF9( zcs}e|!YyD6kltg^Z@?|totd7|k5>{O=r zYW7%;LC2&_&&-Toiy5=W(DgJ}p6O(zSQQ_CUFschhtEPafA&olFVCN)E7X@P#ZBmD zt@Y4MG_!mDGhdFzdn_$0yOZ}=npdC1do0ZrrAHF&v5ZsHBXAs@`5w!Nm+rB2T$FOM zJ(e+7niyBImSX5RL6$3z%FM66$5N^BNb-iHV>iAEQ#*n+F^a^}Sn0pe`BWqCyR76< zN9Gx=BghqdFFJ_!iGNC?U zFJ_zZ8Z*$!KW6=O|JUnqTi0l=e2YGzp1$3B?ztZ8GnGDvYfmJRzr9uc&#vL#YjCajMl4(j4|;TCTho(|qR$ zdoj(e&-Y@AV@NA)fyXA<46QXduV{HMrqe82U$Ga{siJiW>i1cW)1xa+7m6iSo8fk5 zmSy8OPb}Y=DZbOBGhAi7Gt;SM%Dsv_2`b#qtR$C<6?Qa<0ASYKRTH5tpMdkKp5 znmY5SVyCC&Vyf~K_dN--@xD{E4xWuabU3q%`|3|7yb5%?5Nx8E(Ki$UnvrK)@Of}OiEwY#o z-Q#B|Nt6-q@pGD-R7j(IUfTg6U5 zYqJdfJ?7386L{LCoq(2eK2!5~Lg}2kHK>;1j2uhUC*21R(Q|t<@BLT@d6{J|=CZ}7 z232+kT9->PRcUBRcVxsewRQ(OpQ-Y@Hf8GFfz}(Y%)0}{rQ~!D-`YgE-}&yqm~ZXX zcLz#R`fI_O^8aI{Z`OQwp!L+E((g2v<@n`x2U^bgs!_{`4!1inmW%6TzI7{Zp7-WO zYYg(ed6sd$GPNGsM9p~0=EWT58tqSG^?`GjX}M;uK{O({;u_T69at{C9FJ?G@a1*~ zI)C|IREtZNHg3r7K<)}eb2-&^2RcpHU3+(+rK(Z&9>g#24it|&uIII6)rR)=jnRKfX=Pos z`D#H@TawerFYA@~?d;L2dgAxv*=~?48!MGpxVYCW{*{ejtVtT&*S0qQn=E5m&kDen zRb=Ol`$_Xja9+o2$bei9I}9XiZ#QQFfIF) z5#J>#EG_2M`)r4_^f=|pM!9~k%hct#{2w}&wO)T;<*}^OeTObLmX*9^ha1aEP9w!1 z)-o!$?tt3e&Q9$wK6+F&KlNLobk#u6O1g~h4Rq16Kwo`TEeZR0maSng@+UVH`Pk#p zh*^J$U9Tetqzj_&O{dUwZ~oz6GV7`$Vb zQ>pKANwLB=)mESEI&kRF;lppfDXvO&jz38E3}a!cvD2^Ws-I{-?Grt${Q>Qu6AXa& zz`2Z$*&gCkGWrPgDexj#54wTmMZfG|eG~M&!eHzU_Q!%rU>dj|%m(wo3*h(l9Wypv zwMx5#)18Z{H?poST@9zRvmdNae&zS54ZU}78#*?D zF3<@2!CT-{@EQ09j6>TU;7%|VJOmyA3qT{-0)CqG^$iTD_Qg)>J+HCC2OI}q0M+*% z@EA~8%fU|)?b%zuK0P&xXLD)`Wr9<$vNix*1b1v@b`)^6otsGGt>&pVF+V>*Y|6%f zX;7@>FL$Qjq2A&#>>iNE06phjy9Nf{d~+7Hm<{HE1z;&y4cb8`n3TOQ(F%a2-U;iy zg~h(YE$qPv?@;Ga8mjvl?6w{#l#1$Y8H0~)|O&;?F`Pr!MgH#+HL=O?%q%mlN* zY%o8IH$Yp!de9B}z)A2SI0wE0--6Lx!9*|xJOF-@=(_cOvtN!iz2~`yUxM$z7|Ir5YW$Skk5q~gy(?;U{tbkq_@3T$gCB(<#IT52n|kH0swBXnT90 zYmQ5DRMOfeO8LxPDkM;EX4OulaY>8E`^u~(Pau~PSE=NEdDSY*Nz?X$LX&1C4;*l+ z_>wq~YvB&lDO$#9Z{c5INl~Fb>BF}Hvw~@T&6OVZGwoD-6sM>uPOTSd_RwXEs^7n4 z>55ewHgvt-)7PKZE0%FsGkyx|>Q}7Xx>aH67u76Zpbd*e>yo|f>rzPI-Y~FUwqeVw zip6#0S{dq@i^cVz!ga~3yN>18!?$om+-$dG%2zz_8W$~DvSzdE5pplzxOt00;!+cK zqgkG{_>FLc9euL^YD%sW(;@#VW_U6^EY*Z+uhPzH{n`+_dF-x>|?S}Tw zz5Diur=!1m+@Ek5+Xhcsr@m!AK)1f0ekGw4->ZU}KPm||X8#Q{FPbOXw5g**K37yD zONDzHa*HR7PSoCaWV1fzipDwdDbXR`sO0d`KtunD*042b-MfDv?XM`6H3{rcJD9#D zN)_t8yD+_Dk}|ma2ZIicGR);|T+EnmU$`!%I|ZvPo@EphcT}=ut-`zmj2bM%+t2ob zZQCp*%9obDOZD10xa!r8qj`O;y%+^pk7+&kl`{_ay^+6-&T~W7=Z{O`iSt)%Y+Sl# z-R4(2diSb_8u#O@Rg|`RlPIM}Ne(v0nx8CejZ|+I&a>%i$U9>J~ z-+U~;Z=;gE={z{!QF`ZT1y`}3ZRegn$I`VYE>|@a_-mxCh~{jRHac0pqSzZK3FnCE z4cZsjx+!gy%;yi%(bctmhvJ3yJ$n>ZYqfcculw5{ELz`8WIqA>Z^ zzM7Y!G4Y~B@-VTY#m~+(NNZo9b<`!DyZX~FLmd87i^KJ9*sS;s$tzns*>z`WQFd4E z>Obylrfg<6oX)%7Bxk+5(mMM3LN3i>SdI}xD#5(@!K3LN52YSY$2P1?Xj>Qd10Hsc zm{R89;@_R`5Zrz6AY+e;_FK7Ji%`PG^twhRYtuUGpQU|ev39N@n_q~z%FQ2Qk|+%n}YT)br2id9{&AE_wAa-^qat>u79Vx}1M+ETgcVSs^E_l6z%+b*)aFS-NlhLm-I{q(NsSNH1v%!2IInhVHO_FA457-0V1D}BN;9IZ*-M91HCxQFG4;dlv zzr^b4y`z$|(DP7_kiR87`7hXg10DclDeDR7Ge9HcrO?%2GW`9}>CiLK&%v(b5pNwSzB@q=ou8jF% zJZVlCPdcVCl17M*i>lQLBSggvl|p-;jS$7vU(91dOVQ%xqd@UoH&LM&1v=Fd9<7-# zN=>ryn7NjwCXC0-4dXD!=q=@AE%5|A$S~HjL>LPdF^yduE00w|?$E~SKj65+?&Ujg zxI*{Z%@qx~)N41_{d31fi+;Icl_~Chms8yPj-^N1`&ORXy>6xI&!Q{Um8sV)p8J*J z)$VmmQc&)pytOtYOEufyr2hcO%0=NWjqRw}MsbD%#Ph=)^0SI6AqD8jP zcOK!sfHUA6n0lCh74&PMHnOqtB|`1s$}I5Dqh|qV2AhET7X#2!;1lo#_!=Z=z6IO? zrh!@DNiYTre5L*U{2_WMU@W;*%jsYaP$^G?(G|A$pAVo1{QM1iZD1j21F~0*htKKa5qpNWE%8AFc&NY z4WL>d^oGPyTjvz_hGKr`4Ve>qLyqA^ z?zqCTri)Sz)^vpg^-$DTQrM;N9%g+dOF5OiSzk#UY1%$unYiayg_SWJNc>8kH4Yd|kDy=nDI)Wkpw2Lyu7*m4ffS)Gn#kNIcr}w9c{hJkIT~tmZ+!d%Gw;2I+Y!6tsrB z%(G9e<+7CrDM^MqAWBP_TgP92-GAJeDlB`ra#N?5Z4D21$al*0wb#14ogyo@a>>da z%9d4IA;JA!g_T37$5zzbykf=c=@nU0l)H*G+Z^7C%$n`oP6^g*b7jp|nA}*iEyG)w zTC*)BDr>fA(QCG}>J?J@aq@TY(D7W4CF*l)wmHt@{}4H{Ob{U}+IL%cJsZCxT8vLprBi$ghOd$G7>*j^m- z-MbdA(Av@_S9-7zng8KDwg_7?rd%HuVROo30`pB>x+rf#dOflTD_!lc zEW(x*rS93dA?7N#{s^)N$NWl*aGVl{D=ortN*vbcz!u?{?=b1PMcBNU28*ycTt{XR zHpi6vheg;iX|+YzyqG#&7U7uhuq?s~#};9y#WYxi&5=b|VOxaF7p1?qO7zBjoL1Df zQf^;*6?)r(T{un+nwpzM)0JU`M>MV9sW^E;-@jI?d6$&;2{nufe8)}sr=Cz6tNuz} z(8QILCCl{MctMLxacS3+^8VKFf~K12&WSQBOwR$kAnQT!gpr?L5zAQCYXe2eH^d8? z^QeW6^OzqjJ1aUmISIo&(OO>6VwpJXdhnJH@q#8fgKvgyTh1B0pgG1{P{j+HQ*{NZ zZG06I>65%xb$wO5wrq%JtZ0qgM`svU{3k{OoT@PedLNhto(6lsO`kAw1HIq^nEanf z14qD3pEC9Z3qT(@52pMV?4zI!90zr089{)1KpWT(z5?}s!pbT^&pO@1b-lcx_5Dl! zXW%nX%?sM-cZPaFdz-r=e?L=6n+;w9&7cR!E61l$`7ikz8hb&z`CpAnCW0A2ekA5W zp8}m=0GtB$g7yjFyC-7feRp^-Xup@=p{B5wJ$OK?=JV{tz0|u2=v0mUZx8i&7W?#x z{q~$jwh`}Tv$;p|X0{Nz66hMz70KxnYRXR4xbz=+mj94H9J#LTsTytblGKygv;Tqh zVIQ;Z5WKsVH*+1c8(`)iV?l@a9P|kEZSWnqg&N%rrhx_EIj{u`g4mPUIpSCDQE1FZ zT<6>*d4VT?3i`za>^RUf;2fAi`t#rzcn6H5_S3;kFmg|3lXwpv{MU^7|1e1|ftzLp z&p`9vD?FKEEzvY~|n2`OE*bA7@+8f9G#zTQGsI^C@tB+k$uh#qe!G z`Y%`OArH2+5{ceMMBQ7Ug8D~DFcXUu91H5*xvrZ*-vTHdX$wBdHEhxE!bXMIOZ zHCC0J`YyHiqf4R;#*?gbTD@@-i({P@zX{d$qf1UQF5PtK-g8Te7E-)4@{rCEoxi!#E5l$`ZCtTHRWFL%;S&1+?QekS1A8%tIfkLB7Yb=lJ=470 zsFOKbT6Icrx(7IT^zc=dHA{=r6i&aoO`EeFOWU@I=MkOdT!Y}3&euiG%lf6W?2plN zgzIK{y*x)qf2HRLm+1RzsyWaw|Ggt^*Cc0zr>|LXa~SKCJV%uEIi+*yHsg0uRix2 zAx@maw;SdIB72c$)AWYB9@gmV5FO4cr2H<~Uy8qF&Dbf;Gj=XxBvzqVul4)O6s5Pq zxoy^5%lDab#?aNc7G-MRXD&^$l+v~~Z*lZ5*GzP*k$+6?`z+>Ldv)JuaT)QQcG#NY zo=mIyF*+d(ub`Z7#?J51hg2TxE7LeF)~zs4wShwkE6+lU{D4}Q^Hrmk5k+6)BK2+M zXG|yd>dZ9lb9`ek{|;h#>2ut=6*n(!->F|U-)EL_zB08Q`jMLFEcrfj?lO&Qq%_x{ zn(s5`Etl-L(uLZ-&#a*qjccPY_ZOQO&x<{495={L+s>|S+js5O`slK(Yf+1;Oj?5> zzRyNd7kYz{?=$C!OA?QJm-_>YeVUAtL{+yK$K)DlDrKrfOP)gDo*qJ5Pe$z zGM{^>^)D|#hd<4){bHE+z5u=UYhZfj@f`j)*ZK`}7ofZb=H~ws*1$}K&H&GYHqZkG zz?a}VFqzst1mZO?&k(=zH87K?O}qxCe45`J(si0&H`J&3?I(N^jC>7D-{ zFm9(rY57G@EBMMy1;wj6EN|A zhMH(5@|T1cg5Hcb`YYCJf$87@pc+38eJWW@L1vGm&jPA?fM+AG8SIGvd|G?K(@^H(;bQkRnZ8E!jLr02%}iv=vT&^v(RD9)B-5!mpP@66bFz}#p_+;8%i<%OiS)O8 zIU3JIT9$s2W+JtY<%Ig6=Bt;Z-W}~oG%M*;QQDzsRx(bBdx`Yz^I1vDz)NQ(9T%mX zY*sSnX8lXXhl@4;ziG2p1ZF30S+3j{Gr#(*q*9f`QnD?T&+D>`N@o{QIxAVpD`q9F zhil4bCC#IyWmZx#f%_%P&9YiZrNxBqbP znB#O&!TPwT?BkPdDAuG@v|yKFcvd>OOL9ZCY0lCbWUtBREO~2E?~|;wRJyMx4!bVW z>h$U}mvJsjil?0Q>=VSF7uRc!^;Vz7w3PBzgVKfA_E&8d(|XEOI?KFrT(g+saj!Lt z8CHsI?Wnj@z6$5njHbf+Dw)wtze=a6Ov`(A(`lmVGgZGJJLAh~zL%orrF{s-dW-WC zEESg$W;&fGUC*|wPftOHnsl`8G}p^o!mOuL>+@MpaSWA2J=~Kio&Dv!qUBjnr@6Gs zSx={ioRzblahl2>Zq~Cb8^^iVn)TG(!vpQkol0}M?}hXWWAJatIzg>^->^|5-uxYQ z4pZmkyNzZ;mFg>{mC0vAohzOVEqKLjsCl(!L!Dlxu7AvrXG6_rt=#qqOhPTX*V>P^L)i< zq+cIxwpY7X{A2yKh^oG#^kK^@-_y3nGOmH-9d>!v;Z^YBJFUD5-h9)r3f{4J6})*d zO`nnKm9K?&*``D5rgibsA<&{VtyKPSR$uQf_6%6RG&r}Z(|G&S)$!IN*|0j^62o{Gu-@=&z0yEjN={cASeq#QQLi*$ z-Bp|-{kjvUGq?K9=);2!0R_PpmwBCSmp;sJOQ!T0zoaQ>kyvwaRaNb%qjde+u z|HjZ&2O7tw>kh1~7Ii7AsbnnYng42Q4=m%nWokY22Q_mTuRTz`a0qSy zZG5+I`bJCZI{eaWO;bmw%1rl-xpu=*mudaxosJ5#$vd~L3ecw>{7H?(V1v9mWlapd4Z`F->19&2590BJ zD%L#2`Qor@!rwa=!_VFP;Bct=64WI?=0E0mCqT_yAmwW`h2)+jsezz`}4DJOp!7T6` zcnP$FAL4cKi{GwGz6Q6ALpPWKW`ak-li+#K09wEva16WyJ^*LH1#k)6M4j&hQ^9oA z|21YVpbJ1g%By-p()VNQlKZH^F5`@w_1RhJxro&x6pQut?lhujyz z$owb6@!jZHeeTIx9JgT#+jnEk z*9l3I2|gU15_~v1M*Y%rnb^!bB;?ysacZ6Vc2wBV zpVH??$hV{U)u`rC#Mjl!x1++Yx8_R}=Z~{UH28K@NZ{Vk)zt|}iYbrtajkTw%$09P zg@bR$g4=gQVf%Je*s#}b>k~itc2r2*;M>viIw2`=<>S%Z!pEaIrqqu$;bf$OyLX>-^ZlfEp4Klv8ObuDs-eJYyGF%jPgTB3pYgtXN{L}lmzBJ5 zGLm?O_C0$PRx7o6i|>y8UOIP>(8);V$QG(F`S5#buI66ilaWHc;u-7YsGU149sFK8 z#{X%tX4bthn`JTVP&)&BZc%T=)2+n(z3DtOH0O- z>%{-1Ic5Ks=9{{7QTe|VU;Zye^^el7Bg=|X_skX;bCuivFJrzeBL1TtPv40+)nTNf z6OqgIO)0n%WCQLn>Z24DO^Y9|I!>&?jQay9g|l3zceqVPM817nC~#( zMEVbo{a-pQrosQEIr4w0u>D_}FDn0+qLt?q#1abYI}FnM(reK>7rbDWC0Se5EMBc~ z_SZMMb!j-Eu*TVeE?OoUkFymIyfDsoTvX4`Cn+heHqYsLf5Pbo=9I_T=9}vIg>#jZ z*IZGJvjgqv7cIuwin*Ou_-e=5kNp8HELaWNK_55`&SW&17~*$j^dabc@GNKnTY%(6 z8*it-5B&t32laoQQ3kjjOaU|hMqTn4^a=11_#xx$vwy8F`5cU!zz7I_gs=fBU6S0#JGKDmUE2Z9fGd61PF>X4p?r$9B`3zhD7lCXvx1xOl zxC>08j_U7TosH)7@ALhE&p{on-FPqoOa(K*JRlp*3sAL&>%l4T4)_#&1}=b0S^QRN zdMB6+rh^B-qu@#KJdlm18M+Sa0ms1mpqhqI|(+sV&(cA^+UN95P z0&~GapizlzG#B}*ZzVnf@Yl<2GX8pFDw~YrvdM@Bn~WvUnA&6<50Z^dK~gpur|=$O zlX0v*x5LYiTS}6V@|NeI40YR!m_=HQVzBkg#_xC+FlfPDf%;qv&SsuRPtuF z7jdL%`+#L)+lzUUIFOgcoy=`7)@Z7-3)@S~RaiC`QT1oFNK;{>Y;!Tc8kNmOd|kC{ zE(-gqWphznHW$%gb5Tg(o@6!`#gxbSxJGO)=E~-xaIm=)+`c0U+vcLM5!+nM3pN+U zR7$Y96lt=xI9AwN%rT{2*jgO3t;KQCU~5rGrO4Kzuxu@X4yJXEZ7t%LAsb7O@7^vN zY%B@|t>G@0Z7V@i(&2ySxc+_BY%4y&OY&vgiqgcFZAE&j+g22~e2n(Z z9d5KAq&3>NbQtYBrcu7a9_5=aT8#2TOrw0K^UY_Yd~tj|nH-~h%W0G!xEkeKHXh|$ zGNxP~qkMD9qkQvCUAm}7`QmGoFRE5iqkPMXQul0>A9I!4qx_g(Im(Yy;&A0CKTe6m z8YOy^AM+h1Js;(p7t=7xH;3!UM)~HLa{n0RJ0`6j<(n5%r)!iS^BvYGU*UL^@3feP zQNB4Eod;xAvOjJht|VZ{Be2wC<9jJeO~uC0%Zx#ZzgO?X$UY`z+q@Z-gXN z6INm__W6|3@H2SyO-^KVZ=j2oiN+Qj#RD%`a2yxaw`mKG;(AYiLV;j10zKKnD;dawiZgSWt^;OmUu_V+^k{*2Crz64f+ z9xwnTFM4V+;~VHV;1all#Vz-Mso){-2zUxS2Ude0V!@enH?|Y76l?*q;4Gy4e!_2o z55O7lIT-V|7=-{?aPEXo1~b4T;4$zVXaXyNEI6B>M?iSri}NWbqW_m*GCJ=C_kjn& z!+`IU(d%eZKmMCnYL`j=E|#PzSd5^Pfb25&L4N_B0MCFIz*4XUbc5sIWAHT?dOqc| zXnPTC0jlLG=sBQLz6F)%Q@+i$eh1#Zhi3*Zfk}Tmta<3aE4IbFL#z?2m9QKHTa4a6 zA^y@X(H@I;t)A`kH!-f@O0L(lJ*%gN{@Ty>I1+lce66Vspm(pXG5!WM!=-Cxm2*17 z)!n^gXD`0{kG<);A!)aHk`!NGaJ|k_>*(Y(HN`9~3H3n(-McT)6IsjEnbL5wnsN!6 zZ<5r|o~O8FxaS%3eX^Q(*6O~d<-`wtO>@-ORG6=TzNWdu^)-XE`kIyweND&I*HqYj zP4h*IzGjH2ujzE2PS)2H$5)Wa(bu$``kH~OzNTg4zNRH(%JtFLG-s&&Xae8XU0@2B z24p{a6gn5o2a~dQ=j!Z7qiJ7n0e6E3z$`EqJOdg)Cy@Q<2vlwHN1*QSV5tTZz+GSp zxG#%83Vi}B1TTO_upab+LqPVU)6fsW1#k(B=W43ikIv9;d=6|sx=8r@v@O}c|1`AH zel#D>vtTJ$4YqNkllY zBk{|S{V2$HZx;>rBZY$2aF==Z>Dru5&SMQyk__5Jhn~k8+j%4*P?!81)^KOa)}+@s zht(;v_k@}qJ{ro@Xi6c$qbY@zL#WS3Q = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("sentence_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref SENTENCE_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("sentence_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/simple_word_fwd.bigendian.dfa b/bstr/src/unicode/fsm/simple_word_fwd.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..4864885e9e37a4d2c827b15ec6772bed2da9a645 GIT binary patch literal 8665 zcmb7K3w%@68Na=cG-;EjP1`hWd31~^b3>6ir;agXn`4f#jWM?&tKvYNL+t<=LxxxA z`<1kmwzP$&KuhU^mbA1bf_2CkLqvy&iWL!&p;KhaoXZ^U``?pu?@d}5^82Ot=H7F@ z$Nzhuu=tTBOD8T~c;CY16X!p&^x+5RFP%SeNzVMmOBPOCaPNHK;-^B4APW4S%x+>b z!w*CuMwDd55^J@^#oHYT&cq~Fa!RT@&6A#yIcoHnv00xR_xbT(xa#T&U%ci^U!HjF zb(5~2{FNKNdgIq_y7`u`Px;2wZ%(^)`nSIQo!h=U<9oM%f94Nn{qRRWp8bwm^-}9>l3-7(}{$D@vn?(;k^l;8^7cW`*$gtuW9s9p z*W~8q7Zes1mz0*3dwms^Ypd2(*VL}Bt8dt_vC-eOY4eummaVPZ+S)rhw|8~#2=w&s z?CT%c6?|g%o+k&N`s3cG_x)-ApAY=y;4_DwJ^bABe?9WT(HD=s^ztjmUmbew#Oo*D zIQ8b~x6b_S?A!1B{oVJ@y?_26AAES>pCA3}<9~<#^T~e+9sHXlTsP_FTc+JQ_s;CQ z?z;Q#`70iMZ13KupWb)ynP(0idiL4Fho1x8BQLyg^yrH(9y|8ZOE16t$}7i@zxwLX z&}*-qIPv=HCr`fd#;H?pzIpoeTW8;X`yH@)@7%ff-#-s_A6~d1$Yg`a&wk;w5Q-7# zb4|>Qn8kEe=~Eul5EFFpFkQ#EiCd?M9UDb!j<4lkizS0Yv0}#=owi8 zS&&t)udW_+xqcEM*twnav8ijTs@A~)Teod%gQM{`d_ArrQDGD$74FN|i0Y02ySI?8 zu*mK`M8brp_V?W8dDr;WW;;d3(5+Mfc*W?x!6%}*4m3zHDUjU1gmKAd9 z5(=TTYTL}TEp$DY_OWN2XPV~@&;6cdsjWiDQ|PJow0eS`qjdjKy2pMdeX=VjeOmh5 z^qlln>Av)h>Agx&2&EqrLMgeKT^R!BVKqNu`~22)q3 zwx$MBpHDp@gi_Dj7C<)gB4(LEA>_)@o*GRf;lNO={`FpCuK!SF5Q*8j->R`b-%-ta+0nWQ?pWMlWg}Be@WG>CWMmTO%4ep z6UpXQH*bmduuJ+Dba5RKLXJ|`$z+!}CwT(Vnk-I9o|1ff^1S3_^v#!Cm)z@YP2Ml0 zk-so4tJbZnMy5gXHhd@2s|S@K%cj@`vH7u8@~PMsc~tXAV z^#gg9O|T`%ryxE3l~nj3-6>CL&%EpnMX#)`$wkCNM?#$bifUIki?!>ASu)bk4XJBt znY>r#>A;P7`Cwve;$gz6PYK$lE5XE*^f{OKNm4@6DBH{=^3|jnN!dv`Nvj~8!;?h* zl~k8>z}}E_Jn6g=bcysyblv8fcOy=jmlqV8;}y}$ z^x)X@$Tf5^a!Yh~Cnnsuc2}o@;1L$bQC7m^ws<$1%<^ z4NvfK-0qm?cz~(~@)+_faS`Xx>LGd?N8STek^ML}^xocJTR?wXG^*Y9y>#`c41Hj4 zU=D3K-YipcDM|LYbMaOs7(WhF;wQyVjb9mG9KW0HkH??2TkNCklkGE!*^metKC3vTbr?))zPA2wlYpdEF*uQHli}NwR3vr%8R(q&GY(n z4q7HCF7f)vYxFwn(lCPl3{_TTQByg(@c!t|Y^3j3Yh4OtGhz>3fO>;=b)@{xdBW#7 z&v5P5yN*bmM&f)W&*D_%wfY8s6S@iH+e_(XQSrW`Gtd*=C0bN8;w7c#E{I8o4lOs2 zcS@4VBAChLRM8=zOXqDmVw3kN{|{S9vkzZo*E&e_QQ!c&pfhsk#UzUj$7E44av-O} zF_l!z4g6`WRtpdvEayeys%ToF)8gwvMNyHpSbP}k(SH^dqn1XlMJI(B#{5)L`}%=& zc(>Zo8ObA7Ljawqzlp~Pm!Gbbv%-5-Zc$lnYwzmby+@}hSV$iDJ-Sunsm4)72h8pU zcCkBI%Y$aw70R}ltPsU!-n>VLjG(`1bN_&uFVl(jz_@1-X||U{_!&JmYIxHood-oa zmrb8IR6Tl$Cwr^Vy5^RyZZlov9F8iaZ{60_y(_3wCRrqHRteLm=?Fc7*N4dwTA8$@ zdn4j% zVy=tM6C8W1mRr!d)vj;!o8ysFLcAE>YEv;+qk{MoLra2)lkw%=?yh44e&MNZdOk@tX)IR+*2N@F^A zXc3uTP*RG@j=BzSzkD4MNvlRba$}eeq0F^{1}$3+twf3*{tlAp85(;j&xBV}PUowD zmswtgsKXBo6v0&_Te2OJifkUHBiJcgD%T<}z!MP(yazE`&wQ_Fy$-rvPJ_{}T+8$m zRgMp%})W3YRDoxh1;A4ZlTOz~S+ z-`t|(O)>ZQYMdcL9-JKl|A-x$uS(=?1~SMa#U*BWMUskR==DKMMnl%5#pJ+oQmC@_ z^bU(c>Ubk+9ASckO|$hx>IgWFy0@!6y^OYve4gbF_#8am;K_N@m7s&D<>1 zx3Cl3Xen$|#R>}1|8(y_teN7-Y(tWR;TEf%3Zi~Q<}SuvqRzl%Q=$#J+>*3L>q*Qx zO{UCRRu0^_M(7n0{iwy!cp}!lKEuE8&7kkr=Y*nSP*_)8yMDvQ$TL2iuwrsG_;J3M zyIM$-qGEIzygu^PETiC?NEMS|E~)0ORnmGs-5N9lw6$}O18T9Vz&PV;r{4ah5z@40j`#U^?rbkgWgFoo-q=KD=4V){Z9+~WG zq7bk3^t#bXC@XjysHx<-F=cC~8x0oG*QWQ1fIVpsuf z*l#S{YZx+&qlIceuwj$}6r#WZA(^mFJ3j-_R0Bg@!&~@bbCD4OkJ)-@AYiV3vl+)P! zQtsv6xUms@b_Dd3J)CH1%`Lot8@`9hmKc@=xf=bwS(Yoy`wlJNVcvijp+{%fo1=d?cg}a@Y4S?y zjd`AgXCpf>d$6-n!)u0fXS$>QF*`8SQ2+RE0XW;-(!8}5c?`cHUb!tm+fMe#%g4zJ z!vy{k-D5=hhE2W3Y`V3bmq!qtO8OFk_&SMCR}7o z^B$eQVD!8>_s>~0de);09(icif?1>IXU>{8f6nOH_s!Bixe%c_G);5j!+#kO^2&GO zUxec-r)$8#$f!ZlG49y7_ykX4QgTYFH!VG5@Q|UyhJS9v=SP0w>T5=Q@!BtadGvMH zkGWy&S8n|3O<%kDmRr9*?i=I3IpMa6-}?4F#!yo;4>QAQq^v<9C z{1?;jn(@n-ci%JX-e1k0bKm_B{QAM)%zfzLM>2mqZ~lTu7yfS1?-xI|!YUV7=}mtT41=+ReS zJ$CH1*Nz{5{q++k-gx8W$v59Tb?U7%Z@>KxS-p4m?ECMZBfAgJpLfCr_Rn7Jl%{K1 zgsxp1F)3mmu0DK9BkCf$BKAdm6cOprwG_uV$L)@3j+u@{4&AZyDvxuVbBc4Cb0+>C zcAj*eaZYqKxEfvEu7R4bxuvDGd)v029l_ueeRf_h%~w@jUDLCDdv9MzjtI?%r$HJl zkegRlUf-}`V{2Pmd;8|i9hOxgO5j2IM1I$kPxgha0iE2uy!`xvqT=F`lI6=w*RET) zK1>eD`zp=1t*2+Zu^&%a+1blNPaU0|TZ|_mcg@O`we<}aZg^Wz7$^&qAzJg%mFP>9 z!XId9-Q3Z&wO{i&;gs8n_K8;775fI2dM}O z*iH8}*5Lh?E^$AAy3!&$cY#C*d#5&BYiL+YjMi`1uyJE!-oaA`R}S7kIA+L{Ax%S$4$+3* zIy7@=*U;yO4j6Xhu!n~&8CE*%<6&11pD}#i@RH$Uh#0Y7mQzqzSfuP$>h}i%WkkJp z)vCI>)vMR6sjt6cSt+L}p{`Y>PLA4;s%!gG|D8I*JHdOW_W|!hZ&R|a6?m(>P2QmQ zuvgbU@_N%w$Ba$O^h`*bo|c)mG%b*}CapUy=+d<#X}Xq^G&k;Cnj_ttu4~ufGcJ8< zdP#a?dU8mEoLt(yth~IUqOw2a`Wz`qDPvP6q)bU^N~!V$UAt2bqy$|@Qck7l+6O7l z)DfvSr{0@dkQ#KslNBzKD!r*MJGm*jEBX24C?4L(9|`?l#W>U z!9Kcn$TdXsNtvo^J}aWwACr`lq-!ISZo=Pbj>-5tGbuA^aZ(QMN|O$Gx^dl`a-b<#=cPdcFyeGqp~xx_oa{6<9bvK&S{ zbR^& zp)yB?waDd;`YRyjtRPs$DNNG z1QbTbPmN!MYb`#Jns0fj%qwN(^bv3@!Cqa<2EQuY!M@Z3@3ZlQxbg=WFT$pa@Ft%2 z4{0H*6!W2(Ye?;M%sEKlaC_Y&+!F+SzP-ae!~LKeRfBnq`4wEIp}HQ!TEzOY9HPqX zr?A2IbuqJ}bgdC9bgeUHH?CgIC($SNA%;k!yM(&wkt;i@JKyo<97^ zXMy~1yg@XrUSm`)A0m)73>4O`Gh)oaY}dU_y=TW}tj7DQYPA!qSv4UM(Q9rock?Y) z78Z$>um@wA`Gd8Qm9eGOprNX+yh75PTz|miATmKwu|EK>QFYcMF{1twRas?OQx&@K zezp2?*K1^#LfJyGM=xN#VY}L2epfu{bBd=?yY0GMj`Nj#2h^C?R@F7EWjDcmdkMYJ zkMR4p_O7jAT_V0=BVJr$>4Kz`uy$5~##^jqRcCaFoM*=seo3C}v@BHc zmRU>0M`%6X(g#>e?Q7XdafY$Hg$zC0fwbD~YiqahfK)_)ooK^aBSx&gft+RR^%)k0 z-?y}Obne_`(uCy-3hDRkR?WAPqYoXhao4*;++jcSphb4*;}3AMLKNG08$G&^k@VNC z-`;ECE9oM3(H-&Lh)9dQpna*|?6L7gKQVbA(v@uH#Njie7r2OTAzfbn#>S3L3tf>h z3{-{mP0byhJAx)Sm~sa<<9|tZ=LVl;t7{5-Y=YkW@V*erSI+_|m7?^|QYaIa;mj|B9-pMrTgWfimWy zy49SQ+uDUa``>5NOy*2VZc4>n&{<7VrcLBN*pXA9xf*d*U1Qb=vD24Dt!%kiO5!v2 zfjYzMxIh{(44J$Lp_H38A?IKSI>44dh(s63#To;xn6!!2s<`()@%}QH5DoP?= zOm78M&eg17%wLz}k50=Uu%G}cV)is`$9^DWyFi)f4s1Nz+C$&dJ1qH2AWiK8W$5D6 zE?$8t>p)m#hpj3qt7|OP2=Z)dG9v_5UB5xl!O9g?>^)4XK%M78%(aZ#-W}}qOn*=~ zhOT12#d46SzJYZYIX$$>;A4qFNW{oC__}38=H(Zcu(GqR)7vjwhaBvP>Kl+76(3YZ zr4==3++=D6jg1;(NMdGa?nRz4RwAb>3dGAIFZ8NgO+PSEsjwXpQi$>tOgB(etCt^51b6Nz=nY0` zYnC{&@_-z|9?(b~58HB=(;HJ2NgD;EG&srRYr-*fb z!1OQSDJFfKvM_d7p9+geVMSHV%GGP^XM8+i<>YGeQ+zLX1%5fXg+=T#%#KQG3_mhr z2zN$b2dOMwE1uZ%nbyDz(9&vn9BDvbc>>Aa-DWjP1ba%0+mOJ_Vf6;)72EeAU0`40 z!D`3;#3qT8=ytJjY zeY4TUQx|vy@u*x;-w>8v5!K8Ow5IGPO{xk5v4Yyj-&icufLa0SMa3#}*gO@QZ~`%C zVjV5YPA<$UKqfbj{$!ggu$ya5iG-ak9VWhCRcGP^8l)ap_aQyKV`Z(Zg8kSHQWckQ zh0V{Y8*nTvDp_tp9y~Zd@r>S-N_f3L!08^@N_m*DlBF-lPTD=p%VK5ULhQm%1uR?@ z&ekiWWg_{h*4YnmM*#8BB7OD=pG$`&<)yir{zoqI?#W%^_bO; zyRfdj!uAUe)^V;7xim!g67x&fR{rV{<`1D=3QwHRsQIPTue@J{G3!)$g>{l*Zc-C2`e&>vwANtWrWwPl)r^+Y&80}OUZ?)Ov=Js z&Hmmh%N6B)^q`!*IB(F4*rQAAEzy55cav}b)8rM@8{0fd&t`Uz_K;_zmiSOO*{`Dh zNjpf?SpVcy%_!j+(WWNmG5&^l#kL?1^dZ^Ha`RNqma}eHk71VuRfGAFwxb1h1a0xH z*22z=D@j+L+)orSD) zmdX=aMWlc#PdV5{H@7fbGN = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("simple_word_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref SIMPLE_WORD_FWD: ::regex_automata::SparseDFA<&'static [u8], u16> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("simple_word_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa b/bstr/src/unicode/fsm/whitespace_anchored_fwd.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..bcfc4e9a15d370165a346e47d19a64c7668aa2b3 GIT binary patch literal 572 zcmXRaEiTb5N=;9#&`m5Y$pMenwnHeC!1WI#3X(=epz`zIsOc;Qf zg|>i|jh&sHgA)X}Pysg&5b*NxLx6yQAP5KvV*n9Ryg*D`LJ|*v`yZ1b#efJMsH`7D wM$;Sypg1lWs5*!=h9ZdUHcYD+F1*4b2o}Po8lo15@jyu_5P&JdstiRC0G?SMU;qFB literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa b/bstr/src/unicode/fsm/whitespace_anchored_fwd.littleendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..d534a464a506577560bbfc69c245b8afcd6ee24e GIT binary patch literal 572 zcmXRaEiTb5N=;9#&`m5Y$#$a0WTjv1PBNSf`E`P1`rX&3&g}FB=G>a|1lX-3>bmr$B@x9 uhXE*#O9pBRL>fa8M0OjdRSXwiVG#riVN(rJi^F)Jq!b9i6k%0{A_xGW#~xq+ literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/whitespace_anchored_fwd.rs b/bstr/src/unicode/fsm/whitespace_anchored_fwd.rs new file mode 100644 index 000000000..648b95d87 --- /dev/null +++ b/bstr/src/unicode/fsm/whitespace_anchored_fwd.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name WHITESPACE_ANCHORED_FWD --anchored --classes --premultiply --minimize --state-size 1 src/unicode/fsm/ \s+ +// +// ucd-generate is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static! { + pub static ref WHITESPACE_ANCHORED_FWD: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref WHITESPACE_ANCHORED_FWD: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa b/bstr/src/unicode/fsm/whitespace_anchored_rev.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..bb217f17a0f04cb8547dc29414a4b936931fa275 GIT binary patch literal 598 zcmXRaEiTb5N=;9#&`m5Y$pMenwnHV4dMsq{?j8K|^fe{3lFaR?P zZ2>DAJ3BiECkSw%0&X54;N|0o0099(5D*f^03xDzfta|2Bpv|wKPCedZb0v|vH+#n z*cn)W5DIY1fD~|oRdGSpB2yg5927R13?f<>7|^6pv>|hl^&pFb*|;ScaY=#10jj1J ANB{r; literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa b/bstr/src/unicode/fsm/whitespace_anchored_rev.littleendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..a7cb5a78a7416271dea570ea04061c98167e5693 GIT binary patch literal 598 zcmXRaEiTb5N=;9#&`m5Y$fKqJi x3@kth1-NBE3OK>4xS(p0DGp=~3L8xZId;&bP_!X)ko6#ogW0$x8F5L0!~v@f7Dxa9 literal 0 HcmV?d00001 diff --git a/bstr/src/unicode/fsm/whitespace_anchored_rev.rs b/bstr/src/unicode/fsm/whitespace_anchored_rev.rs new file mode 100644 index 000000000..8e845320b --- /dev/null +++ b/bstr/src/unicode/fsm/whitespace_anchored_rev.rs @@ -0,0 +1,45 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate dfa --name WHITESPACE_ANCHORED_REV --reverse --anchored --classes --minimize --state-size 1 src/unicode/fsm/ \s+ +// +// ucd-generate is available on crates.io. + +#[cfg(target_endian = "big")] +lazy_static! { + pub static ref WHITESPACE_ANCHORED_REV: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_rev.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref WHITESPACE_ANCHORED_REV: ::regex_automata::DenseDFA<&'static [u8], u8> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("whitespace_anchored_rev.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::DenseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/fsm/word_break_fwd.bigendian.dfa b/bstr/src/unicode/fsm/word_break_fwd.bigendian.dfa new file mode 100644 index 0000000000000000000000000000000000000000..ebfcbd4e5d551cd8c48ce61269a53f16118bc745 GIT binary patch literal 218729 zcmdSC3!GL}z5l=VerAS?sAx!NM2Lz=hy)x$QX@hlL?k03@+f)8V;&+85gD0148sfz zx8dRd1I!FC+=kn5m0M&)9*-Fzkr5Fhk;e#)gXHm;+5i1rm;J0~&-2U-h@Ss%Ua!xr zXRq~L-}PPhwb%Nt?;i7=Z;!os%-8?*>yO?1weO7m);GU4_G>qP`_ZqB`S#au9{JGM z)Vu#sfyz;#lE1{gEw!sYe64jms~}9|yNhiSlescU3dKr?QiUGQ^${Yy1DZ$T|UvZTlatJ@yVXI_WIOqx8L#U-k<67*}ix7 z`&|Fe54daK-GlBK{DphJIOI!1zdY(PH7^X;+U8TZ}CzBm5+kN@C_A0{W{Pb`>JSTuP`@ziP4XUr^_HG9t7CrjteUr@Gi z(c`Ce$Ie~5f3)YvPyb}^Pxt-ong4k9 zKcD;g^S{{t%L6YQ{MDgfzxbQOzdiE1qrX4)((#v1{NdyuU-_?B|8(llr(b*hFK7Py z>>KC)`sV+<^}lcb?VZ0G*LI=hUgc{N>Dh?c`ht5^_?OE_>ltubg=YvmQ^Id(&m2XbplMV7FH$YrwmlD7bUrRn zp2Qail9z)3nPc+YbmNVkI(6>c<NCS1c;IW}_wN1aPxn3d^Pfv8?ce`PDgA@L z`qiOBzy7r=u_H$^l^Ip>nk~0*z!2r2E~N~3R+p42)$D+F6Fn(~7uu=d#^-T+s6@|e z0M9Rs0kgG#qGx{_z6HO%gx?3ofl{!|(!8n?w{`;L@7Cd9G@zb)LHnsO;J8ZMMp`$& zrGj6-&F>nOxV;q^syf_wqvX0*uZx%K4-Zoz&^Z>@&vBd9h;01ba8(K`OQK=la zxi3A(Z61ZD091p0CdX~gsKm#*gCXESK#6>8kxI0^UnQ;`3r?s+yD*jGcAHex&8 zIr)Iv%-IHL8N^NGyrUAiy}<}TZRSFgyGkYU9#M%#N$|Q#G$yU86<|HTkE%qIz93)y zpS0xukEPY?`_hv8m#f6*AFADwKR@mNq9u2xmA>CCx$|U|xMgtdmV67X{rzsqEk@B2 z-{+Rxg8Aqw#;bTszKWWrC7;h66~0z}!E;pjml@0l%wKj+2+!2$IjUv5cIPoOg%z)= z@Hg+O@Gvvn;mbfv&<1n@y#ceq;RnIvpajeZm0-OJfBOhHrNSf40dbCu2W8+HbyK@` z7k`XKR@Hb<)^R%Am_9RwmCvZKa(~)59ag@cHcp32LKQ9{&r2B3mkiZm;gWoQ6L-lg z;G7DVHU^!+85M4%TsGoYH8&ck!{w|THeI8_<)_qjpBa8pW??=5Fb9P@tI~RGxRdT(w{?=mxSxa(nluK?t0*C9Z??irKqFk-~l#()2Z7q;#^ z`KMFz67bsVuglt#7lAjC8)kJWtFAXOz1AlnM&^DRoDlx`mRH5_`YPOUlPDi&|wfoYjtB zHp5wm58ngGyDOWo^8P97dRI1IW%T&!!+R}UhUvm}QHww%Kl;3?%1J>yOyi*1D zA63Bv_nESIfH<;tcV#nzwa19(Oxb*`tuC8S+E(@PPMvN}wX9Fw_I{UDu;{F5FEQ7Z zp$m8Is#aMpj+NzN%5rh6EEiL*ep!|`RY7?dFcwfY5>|dv1r@yk?XF@xU{&I5uwoR@ z|0enUx+$Bt`|7g!e`I98k+q38dPyk+H=bjpYM&atI!LdiSGm!v1EY6`cU5o`qu5RK zItjaJtqM9e28?ta`v69zj`X^Zv-aym{7!F~9(OZw{L!m(3q~?Ved%$X5C6YCdc9Ga zR+hmVhg9&!(e#<%+-2!yd9H&B&J6;L`sbcAVSl9@|H`cT*J4l(wu5(6@FpYS|1eX& zHNuqTTQ%ur`M)Dn@W1;_S-yS!2irrtZ81Hv`&YSTT`J%8m&rFzh7dK?8OmHI-J zQePRY)F*p@vBv)^v;ztMB)#vG^uDhw0>l}vKqnJ6d?df02Csm(mHKK6Fi@%cE>r5C zyMP+gL+>Zf?M(scGSaL2@qd63k9MXWAiWQAWRI84Kb5DKO^+wY8~Jo))3rbO&jDW9 zd~$Mn*?f}GrYCvsN#1%&{G+&(*{$UF)}DYexs_4yR?_N4d-)V)ds}GA;x-D@FPq!j z^E}s-&FyD(*__YYw(7#@*jjK9904c58Kpi-9zNO%!2hGY!4PmCpbkGeMyWQPmFjX# zsZTu0Z{mFH4t^Kl7N6JKzPh%ZQrC6_T|qC<2Mh+JbM0fG5LALKfO5WeA3)Z2GnBfH zGQ6%kAkKA^)pdKosq;&}^-=9lclBe z$`&qMv}p0-^74v`${(}0alKMkQ=->A2F5OvullII*B$(xk#E#l=&nPMbD;`ivPf<-Ed4GjG0;rJ}NO$&#f@ zmo2NRTE2Y6ij^x@ty;ahx_Zr;wQJX{Tfct8hMJm#p6qf5aJv3Ky~~u#oow zc6!5wLy&=YxcSG7yYNB$#(@IBZpcE;7ZyHaX-}(gQ8UmUP{YL2JQnrmd8moM=uv)e z0sFyG@Q(3c+|s%oRk-**0Nvsz0BI~<0iI6rYsvfNV&X5RH;HVEdFL!Q@w=pzO<_^d zu&^{gEmMKPf$FskW9&>0A76o~)=$m7!^4+jq$Mn6$1vKlWpY z^jGRwVQD8*0;PkZ9Ec1l?(7MaE(P0E9(C;MhWaR)pQ0+Fr4*T#a=Df|)gN3+VDH;YCr^sVd^5}ZhQ`;qXJ9l~cDrjRk z6fhe?9r7+57SQG=RqE%wr0KcRI!!Fqx+xvI73c~2nOMmUHH6aNRd~J1O-?DES+crX z`|<4jof{GkwG9cA%U9UAAMUKKOs4v}Ys*gR^jZnaucs%`_R1^4dXtOt-TZzIP#)!! zM@1gE#)R?q7FJMh6%T`aut){#)+t4*dbHB+2J<{|igv?UKaw^;h#)Z`zhF{PQS_|+ zl9Nix7SZZ0jkw{|iW=4i)+eWQaYfb2Rn;aX=PPbv=FC~Mq};r?L9$ps2P+JRaLwi) z{V1aNn2eA0jE<=>pmw>1`RoY^vW7Op#Fj`%1#@tFItzGIHXe+nC;g%$T%Pqp? zX|Nxh0H?rN_|O5mTm~5RyL1G7!7!D(cJ218n<)S+iw}w69wj*>1T8v;)X^%K&gM7_QpZo~6tj?&hb|?6hc6Wu>Xlnwm|U z%uKXv7cFH37!4i=l-SMl0i|{G7C=sJJ^+}rX;JFtx0UML9&`q`0ZOYgE6>iu?eoL9 zj{-`na}qG~bf*7xt_GXH(_lY%6}(9fnyMUGKgf6v_uimC7z~D~U=uNJ?yB-wn-or& zVq{mU(_w%tosi|`5HtsER3e#Nwru%w{8xcz!2w3uqM59GuBH60Wt@?btR-WSjIflo z9$(~HRzupQ&4?@G3$7hs_$5!#_+p>6pBrC1KRdoyA8&l|XmngRzIgt6eBoJ-FSvGm zu@vuhd{G^#iH_R=^a0I-r)W<1B?RK#4AnT4MYz83S$BFmxebyhhJ$3W(laz7} zVExgF8LCq+&<6|!_k$-uA*ejB@kQML#deg6bxyI`qXI?Z%gzy7JVk{_&;5eZ(9H z9sy&(G*AZC1Inwz9`HP%oI9KVZ^9ROZ(FN zK|9b9kb@i8H<0n=y0gj~U#@RPi-*F#CE4-Cwxe3(%Z-%jjjw>$0Wx-I3EF`67h`;B z--*`J3-kw+So@KH(rTXsGXSltJ>!G4sP@l*v*2wcA*VM|S~pU=H@3IW)bNeB0ZQt| zfnW%D7>ol?fN7u%Yyo@0i^>~c+EXg+TY%Q!dNaP<@NRs3xuJ?uMV1?o<%a#>C^(fG zUv3!7^IX6RMMjq!Mwt8T|3k+p)n~YjEBuuW|x;1)A6cjA1SYpPmh+=Vh<+6w(sG&TF8`Nww?krlS zJkOl1-7uNI-RE8?>nfX8BAH*aQ)VIitm93e?&7U9oW(bsRJeI_LYuu zBV7BGjQ92_s4%6KNKV|fo3}>iFK(k`LDA%?)91}wx@^T-n+reO{~c^Kal>R`d3nSo zkTo2fg5*T)h8wn~OjB86QOwO!KwWPpu3Cb%B)ehDR zq!w=2v?bLdf*KSC@Xg83FD#rob(!Jpry3?FY)RE?A~~sYV@$qag=zOe(HxUPa$&Iw>AO;LXc<`BYatxDm7N=qdQ)d{7Cl#(<9iDL&k!(@S1Pdu$jrA&Wb;+5436B1OJo|0QKd+w@r>nQsjQTi^g;)cl`-uRVM zx?th59K)<3UHG?>B{?2C)r}jsnDIl$Dl)Apf$xr8 zyVE!alc($F-1!USO>M^xPgw(fYv)XU znI}DG+NWsFw9h)8%$X*h%$Y8pnKRv!nKPp&J!iTnGiTZ-J!kSenlr7x@U1mxdSNbI z=ju6=a64yONHs@W6#FW%t)>!eDoUM=SfN?moO$q#NT+4qoh zi^9Tb)8xEj&YaXvhdVo|s*;^6yQdT;*?CH`cOZL8L$(9f_d^Z=-pq!a0`DsIr999A z@P;L)a$o9U-M;)D2bKcHvM=oe2jNA_uzOSNKjh~ZvrC?=!hbaU?yvn8mu;8m6E*5; zZ!cF)8srSdoCeA6IQvYT1o`JLdjDHw>^d0S4@Lp{V%Hgf($ZnHeC;A{*XQkT@~r)M zujzUcoCfDOp$v_Gx90qAV}5tt#~46+ro_YPGi6Ur>Oh{>Zj_PVJ|$+%m{lfkGWJgRCs%(9AzKTqpTxX^~v{Iq4IoeGmY%1-_HoPvg9Xg_ycrou7%0Xm0c*!>^F&gi!l zU}yB(?Et&D-yRHxfe~P|3deQ??1YY`b&n;^ci6T44m-8qDf~at-VX;HA@A*sCIa_R z!U5;NJNS(Ov$cPCmkZy5-(D5o1>Ifb>#j#ZiKW4RAUpa4+k@_a6RUw^Rd_eFgV-4! zv=fk)XoGMMCA^2ea?e>64({>+-$MyobxO;zoTZ1YkgyeR@-D}%OwNNBY>r#4Ae}4dafRmc+O4Eo4>fcYWbSAndusH@+GOutvY*RC@FfJ;;A=Hve(RMnmY-X z^KN+iGS?A1k(ATjbXjt^379`opQ*W+R)z%9)yO*8`QtVr=jJTgJN@^&b{e>0F*PbDpdM%=O6C)e?UP8zy?j^JVhW7ytOP@b~ERk}{{t zX|+E4bUAl1t(!pdY16&j;h)1?Cb|u_uB@z5R!ul9tzIKHH>HIetq0}O_2?owtc-2b z=JIU16m^{zswY`NJ^89qKVTj&Z46q19)Pt+DSq?r11~By{|-RuEP!UgIB-m-D9`Bta&#qQ#Hqy*N^2d-)be_IxHAu{T~ktI<8OI@`l*jB&{N9dB{=b`pI|dgX&|O;VY|xEr zl3p{zYZm#LHBzau$SwTFGUm^E%!W~J{V6YQPzXOg>f(MhX>#Igy)>+zNmtVN_tv1J z{e6d0GoA*ofVc7AWc~5`_x(!EB)?-Q>zVz)a8M5RfMWpJO5jrhj}lsT31#^0-Q*$9 z@F+R1T`f21x_1jL!;IOax1ymM4N~gU2PpNeYVaI5Y*P3ZQh)25Qjb#OkG6!S56Yy)q6ca_TF$7UB=Ilx^^G6ZmCjzXd8V->1Ulk!V~C{ zR4$>6h4v1l!PP5f?c&dPB^obsGu>*8+;N-I?*fuPc_+AIsIKW8O{F!@+$d??(CCub zQS1}7T3AX$N=AZ|&di1Dkg0#$qSU`pmeO)YQL`fJs20YZHqbuzP-@x;{3*d{<8kMM zwKmQ{exFt9o6SI5Lod9(*%^?3;rC7Q{mn8!THo9YPFVkUj6036(W5{T{%@L*WAtv^ z7gPMCr;a9_=`D@lw@7Px5B)neRu;%v_WPhqri!{NRYVOIJq%`mo#2R4ldlBr0VN|j z{nz{XT>_XrrnEACQ^?g6;!GjVlxMBqIi-rB7r)}pV2D!R7>^5o;ls@;?S6w&_y#>f z`z^ws_{FcAF;@JhUZd0_&`#}bXr?~IZ_=I$e+i$~RlBuy$#i|AF{P=bzKWWf`Ya+h z#B{o3hK?}&a#Ffv!dqe$zN14LpiAar$n5a-PA1*L8E{z7GdchI3gahS9c>|PrI5Dr z_1AUJa$`Gv?Q_FZRG*{FK9{ebTO~~kkU2A@LnzvF=~`t@?+s3pR$toHowQ&1eWxig zox3~x@k~m0ZUfXpzZNFf{V45z)L1`iwqGT98XPzAKc|oey3cji&$2SisDsvre7Ssn zwyoj&*_eILdB())b4a^(1d;KCl~tNH8qa$D z>A6-L&H999cfgKCO_S1-#Gr<((nTk=dJSpYv8g_no#{z4OG@Vv!=-0q=8~J@sWVHo zPNIZ4j&{9zrOvI4wMOsAtY~DdmeT3+xH|3^=-#N`AJWGRX*otaH(mGC&B9JD(am*o zMLLtV9Z};M@f7JS$hF(=^iay}SV$4dzTaaPf0> z$;sPyI*(Mij1{6ao-JI)NYOCQ7B26zVp}IeI6XCy6g_Lgyjsplu3cv(@_a=iGlG>Z zlwO_ob{K0(Ld(wj1o(cAv5%*mWc8X2HJR$YG4JFuiio+NipphG8RU#fasGFdRsU0F zjo$xlr9K}5X2Q=iYkr;??DM_BAi(_d`Nu&4mR2$&!5>HrA4i&^BZ6Ypt# zul1e(>s=MT+Kjz4c0ylm3;G%D{?gw39&Y{7^L=$3C;;2QK5$rte`*dog1&%V(?2}{ zkXf{!|Fj9Pzjn&%Tc6?(wYZ|khimot_$5z~9-n>Ieol|i^Rs$< z*2mN1^JsKjr^n~{Ydt=mwH_a?)#I}iACq_g+8V1VEn9XP>U{J6a-LFOW=8%p_4eg1 zpf4B(Mp<{Zb+=phFz#DQ4I|z#;tgZw7kY6AK{JdtGHf&$2TDN|SPPy8%<{ut1!t7{ zN>lev+aNt*^`+ySk`Q-jW6&C04_Lhn?G5^ap@8-1P~;vu9^?bkA6gDbf9Ou|EI0tj z!_c?P`%6ks_zTqO7mk2)fR;R%T-}>PZ{{p!;zZG-mGdaVMuIV*5X=RO0J;1EJ5Kd! z5f3KLVB!oW&S2sU-UFTo4u|v-bc5iNQcc^az zg8|YG9swQ(kAf#^pBN3iQmKJ=D0R02*8sTRO?}dmaY`U^bvM?%4^R1xJ0ozd={R zow6I$4luSPlcHICH#r`Zqhi{{cO%u^NOkus!27YUe2608BL0r*jz_l6;{4!5kqrpB!8V&YY$CI9A;;l^O(rN)(I;#a3J!y>w z_hd90?331L;CH0aVErY9S{e;rn1uV#8V&eajRqU4H5&M>H5w$;Xf)VRT7+mcI9e$^ zp%sk=aYds+T+wL2jWingEzbh0(O{pnMuYeojRr?!G#c!ar_o@2B3?$L!TLrT4IY)& zXy93EG>9uBfw-d4fSab#z_a7*T&>X{^rF!qu4pufD;f>ByjxdtJdld_p*K}9oikQ( zMZZC4#g%8#s>cmExv$W_bf{=OKxMTa_@#Y?LgI?{1Fon2U@62`U^NEqQ>6XiQEBZ5 zp0)Oaj-fRMEd@2Y9PJ1Dq_rRT9ce#Ue=S2w`@!>-kVyN%^S9a$)+emqun|36d7=ao zV%kyk80@nt6@BVVs4gp6>q?oG(DTHVvvuvx({7&Ap4hO#ma@9HS(FQ*6foY;ooloy ztdCBSR0Gkf5LdJ+#I@2~z`F8Y#st~>y^wX~y(^UZVo&BK<|#tKFUbuAW4s=K@=Wy(e+nY4Ys3 zXihF(ykyC$RWc%aw3&W4Dkvx_5{;xePtKbsn$UI7=R7%Y$H>FF`5U<;!Pe&M8| zg^Qxlu%zV4C!;5=X-s*gX&Otp#}H{6d;WoF8uM&5jcth4G`3G#$3|$3rm^!CO=Iyj zn#R`GY8pEl(KP0Fq-kvZ#V-&|V_d6gY(uQ3arC4$jqOt)n#TOrn#Qzk%&9HSK3(=?4UglkP>q4PD3Gth-b)7XXta#F$XNYmJhp*4+p zPSZ5@!d=N~O=JAo&vlx{F{(f`jqz)sPKwN_vg;GuZOoucB9t*I|2c!^hmDa@Tf?P` zD|_-;wKY6CEvI{qNm5H&!_mcE;$_v=(6sa|DUWW}m2|`(_q?<<{B#`;;cIzCS`)VH zGiYl#O3#h7H5_+1$FwyZHGJ#T*6`?}TC`j*g0{vFSO@)Jx6#)40dJm9GzA^OgW!Nt zKO796Q!3dNu$oUo!yRfh;h<9atT*zR_wr9GHL*XaR;qy6w17ATn*g;jX&_)_G-(=O zRW#`^CsQ2&^o8R;2yKn;(wD!>+w*skGMl!>_pV1P;|_2yKw3FV^R+d;x0mO0Xkv5% zy}$_0*4p6GgGF0oJh}C?HNLOV#%KYcm9whvL;wA;fD-)vGvEk#-Dqn(PFs`o9)HZb zl+=Z4Yka3U8X7%}w#IkJcSE%`#?3a`8sknHZH@2tX_&Ug*nTE|W1m2~VSc){#@ORF zjC{(T)^|eve9^Tu{(U4G8O5NywwA`fQ?6sEhcWE{(j(|;6vOp4GLLqfb^MjSD;O$k=Gl zORdlUxyHpPYFK0+MJ1*1x;x z@{~FBebcyjh<^4^OF&6HbRVF;AEG@xbR3*R)1s@9N;EG1bt%}Z)WaQ(-@}Xp4_AWc z!4c#44f@D8$btBMgIs*$Aut}mS4#XF@YXJU$7x)A<0RS@l++{0AmgNjKk^_T&Lfuo zk^Sh;v;xQ|;r~{q-3!!+_&Oue*O4rnM#R^*5OxUE(uf#&%%m@4uxLb#JguKEP$Oa_ z{d*+sPjWQ!(G=$k(TEsX01rmhk()FhS$$>Hi1?T7sdWD3O*6KPr1V9G3(<)97seyv zdRh(i@+?{n-iVO4>Wlg3)YfXS6t%P(Tui&Ji=CdkP~6z*xfkL~l6HD-X`(Y&FOGKx z>-h?&jAyVh8ogSCmN$7hgSDXzIBAXX;Wp3?;>$V|ZaGOgp-nq!wxyDbMv>?rZ;`v@ zP`Vf{Wzpe|G`?*bk`FoeUApY4?P=%2{tDXi;_jI2H&{7%%R(omWLB-Seakrq4d&T% z(q;)8Q*{59EKQe@J^P7TgI;0_9WG}SMax%gsL?4{uF=Y#XQ}HAHIXK>7t^onMoF;} zH?w5bYSGNLsXA^}BF8lsjw@E$Q};MON~DR_cqlBISt4hiR)5}=w9nK3O}ON4liU&a zcs8X~6ik{tW!iKpf1|1HQ3zMZMe4#yYTZU!uXWAZr?$uR=xy2gC2)z>JrWHCv4JLf zH&Pa)72{dgb1tn;bO&?^`f1p9a)mA#_wgXngmCutJY92_pYupJ%7;z!3R<1{P?6MW z$t=++TC~`FpJ?qm+xA^Lao45m{QZ15KkJ4`-HR+mBTCR{SxM=|YRUDKC}vc)_(=b9 z_ZYN}mQXo4oNGDcB-eB4Ke|U^`I(-OoFH1Mi_2}=u{I~`Hd#GbJunwD#y^4fN1VIW zS+f%4akFdNWd4iE?;aU7Z>eXt_2-^l^%(ZrYrt59CV2 zccIVIEmrDx;Udf1&y%G#Wjm!k`#Rf(I*uBsyg!L z;#oHbON=v1YSkB^c5NZ~(oazj^aGjSyr>$`Py8{tfTeq zoIh?Z_h)97Y~2>MX)B|vQPIMWryzC=izZ9k6f2TZd3jt#`dl5;S}t^9UM=NtcWB=H zOd5lUjA}MoNij(la+>U33MN_Alo5j*{Wo-0x3F~UT zvD96CiYx6vuXH>aLRwNvg50E(n%wA0`RQES6hm&#r9w>3^z0r>HDr!X(S?ja{*xag zm->}jkIKj8&9)dBm!+r0+lA}noDLO=tx{jg%NT`b&ym^D%=oLTW$cSIYh$uTF*Esl zC6%i+eC0hgl@}e?(u7HW>G^OYH0a*~xxY)kX7?z`ylP*Osb(2pS*K6M`-4eyjV|5{` zR&S(srQuxCNE`9QU;D`yAFT|LR9YL|O2IjntgNk!c6_p7O>~QqHIUrsTDmM6sVsM0 zdlJ)sCT^J2cRnpod1KSh9+ix5W@g;DNk)cfe6upTIV|Grm6?_mI??H0zCzxbq*iQc zx%i|l?;vyL+7ZJ^>G2UA==jRM32j7X+y!N#=Wlzp$1_bX;bnVyBI&IwEPWH+9E|3$ z@Y}g7>Om6j%j4!28&6JvWCdAZ?c8K zNBM}}&js;wlJghXm4u&Ps1n@a(EZiLz?EGKNx_zml!VQvyzy34)>=yt>fIyJTxXW( zk-|$Yto7j98Krp1P%dnOM}>|2o8$Ep7|hb#F@^gExt zZMd69wO8|wHk;ct;vv0DR-oroE9MT0tinZtSUd7cTxukjH2i|tG3KIrU{tlyBHqFLiaHRH7+xj(XQy}ujj+EQb^%Oe)N!@0tjqPDsl2ihFWz=cWWEoZB zHU*-!nQ-zXbusI5^Vo0Px~N_{z?J$QP|aWAb_Lh}4dp{D}P&P3_l~<=li? zFPSxOzS;4$>#z)Tx~yF*ChnE2m1KuBzC*ofvsgnhc04G*4D!2t)a!auT%|`6mP%7) zrjxN>_HN57oYWgPnH2S0BJph7i(FSmF3dgq^4VUO)~YOh3!7UR_2l-gzaK9v3oplh z%6=;1-_U0#CGHiB6!JD8IhXlNR@RbpS=pO*n%>)@9M>g>%2zBm_&K~t zx${!IT(3Z6N7tM>$oUnQxXF`z1*MK0`6cK|$!nF8E0>da%M_a{7e6Qd`H75k>FrYH z;W~2Ta!_BcsLK!Q_XX*3t|dHKD!1R=*O{dF_>>8&39)uXny&tR-sjT>v&BQ^X0*vk zh35Rrof+9TO_!s%>$o|8TW6QhuVob~En8Y#t&yreiQ#uSJe)KP;fxJ(lh?JU_g4DN zqfss;W2_xX&RnisF6(oJ-o}&m<4Z4nJ0(3`+?{f|`po3|={Z^aUO}9u%mb;imQ_GB zBV;RMPs-+=lrv_|nJcB78hx|&*i3TSeCzh<$tXK}B4Oz~IW5|>IhsNI{QCSdNG&_G zGN#O!DR<>XMmgh=aWYy(`P^Jd#a$YyK=G-<$ z6H8lm%4I~1*0V0$@)D~~vhOK-ld=YoxkpA!U6-zOVsWC@>HIy{?98uS7g=cYOBK4t zy55T>Pn#}lGrc16V!JjRjWxuU6?&mq*Yrv%s~&~ie9&<`JqqiWRU5*F$Fw2D*XEzQ zf0BOm0&dtAVnEzOgLV+X&MtYWmm6qM&;ljZy&2@vc9bBB4 z9C5j7Jxe@^gX_=MZsw|`?cmahyDnYlZ+ZGP?aIs3c7VE;wu5kR+-wP?Vn%PuI%Z7U z!H*f^5Yu)LN?U_+3Lj}ZIDb$2n6`sYAsnoPY1$5!rj~w#iyOu9^c!qgM!f|Ia}qh1 zv@_@}xD*@}Zk>7yKE39cRd2yj;%3oH@F=8g&r>fU7TeXhxLNfQB#z6eR~J$1kudSc ztwS#%Q_3!;t*H!p2{u-mrhxU!pcP<4vT6X>@CKbkTUx(_GUeE{Z|7z`XO3ixoeH~j zqSor2`r5DyIQ5m7u5`1wvGZ0ZhjZ;WgEO4B#=j;E|61p*aLIDsO6)A>t@;j??9u2q zXt_h><>Eb^y4pO+zEw1`*%q6_OkF%RZNJZ!SBA4yS2oVoIrnyzth}O=8J(?K+N>w0 zHcpgR{}~yhGg8k#>lvv{%Z-*1Pn%cQOT|Cq8L5j;zG|J3dSSvRIwKW-DKXrPXQXNI zs8f-}`9*EsJ0rDWS`AO=dii5jrQet!;VE zaw6lnS~tNdYjo0L{W6@i#9~Q()pODk@h>nZE%I!otaZ}j!lW!?V^Zv-#Zfv}sNtG+ z(jsASN;_$>es!LaSQ_0Ht)x!k$klx98Hq=q^{hZ>>flxDtibV(Q!Fn*Tu(e&{=>-ucePa$J3Xb3XS+%T34S9I16yx<6P@|_EN0(EWo7^cl|V6 znAa*LH!dd)I16wbe6Hu&GX33!tY-l(ooue3zN7JTg-jQ879hNQ-VMoHef03G<1D~Q zA9o#B=WlbD^(;W>T%5XG=;}QSaA{_9eg2Nd%GbcN02j;WR99IGz0l$|=q$kT&*u8+ zI+|Gf$#NFpsC^DjatX6iHsCD4aq?ZCtMj)Uny;9TRs`j0vt`ut#uaQ!Y!``odv|=xDh^+TjyB-d@`H`IPT*5b!q+6&H}7o zUEie$PjRPLY`va(9F&4;V=wj;_F+$PgII_0m8~Lf#{XIA=d0M;lyB_F*^!())b*W> z@Xy@0{qwz`*zo#uxe8BTufmq^n&;C4cphedKg93xCjHYh_`L-j2Uym8ttWUy)8$lG zuUofu>&~4@UBOLcc^4BGuri*nzXNQa#ZTLO(_!<y@i5}&vV*Y&^Tqlb!5%+H zn_I|dL9sHmM7~Yr#dp8a)|A^UHiSJ4^Zg-tw%mA26>VEf!S|LHpm0)NF1OAy@Jl2o z&(g9u4kDwd%@h@tRBymOlW=vg@pFt#UE%0L#3i(m`8LoRR6&i-uj6_p_n`&u8TXRp z9M16;n{NTRF9C_gETM69mT#1f_&YxQ&P9V$PM7uGlTT~ohsk2O4PZm$J%H1`6nCiP zJw<=zXXj3_h30rWUY5^AuoCkcxqprO@vof$w8+=73GjM*a4#qY$Cdg^8^B%uzi^NL zF9(%6(;V~%vjI2M&tMbazgvPKU>d;hzd3C_i{IHkU@*8Ji~&i&%yaf>a9nkcdXnsr zyRXH_$!5u{I=<Zmcxn?MC#Oy;C4HJc zs{Y&>bTl-7?#l1pU=SeZe|{V+0#$(A9g*kfl{$`HfC>NKTx8Xl*~F@0N|?g<8h z5dez{rz^pFup7JxPMLIGYi(W9eeDkL2zWxTAiePg&6qi~+n9}JrB03o)XB-G!L#6i zQh#iLR9F}IV+YU$Aju#5nNm<-6xACcydN7=*Iwu|jp7FjSpnFB}4?<8e$ zlCr3nk4t%+ybp|2YF#_rQSZrix90is>q@=+rs4ncyGosC1xWJ*QlCI#N%sV4o*>N= zqd+-W0T}&GyrR?}6d>1sAjf~`4~BxrK`Gbc<=|aA=Df$eblnr+f8I_LJfCDC%$Byxv+BimS9-}s2qV>FVC1?w}gFc4tC2Hp-TKP+lfkNvy zgWuHFOI3il{$Jo=n2Mw z^Gf_Ie`B$=#P=} zV@sJOcw5%_LHERz#qTI9DU;uY*2SiyXj?|UVF}}^c{=j8YQ~*YMp9S5J9bFT?$LXr z!bQfpBL!eKpmiQWt|Q1LVLJQ(&*bgMS!s=?)RbB?#)PgJ&+p0VL$XGiGR2iUcU@xN zo-w7aR5hhjO?#=Py$JW}+W>W5jTF_Cc6E*Qe~#aW!CCm{0cvLrwX=rWSwrcpxu11o zveJB$WVzN=*{Rg(920vrWhmTNcLn{x69D;5OPPty;Z^WnMf+QI4)9%4xmCuDn@CP6 zS#5v2)j*KM;y+=5=pWP9Sc^}dzmSiKtf)5gyX}K+rGO2@5?Z>QzvWD&xP;oU&oa-W zYcUBG)2gbKD_6_M?Xl%!jFR=SR>Eqwc$IurB#kb=V5)pc#Q9P8*6O+~A8U2pm7cS@ z?w4LNsnq4X7bL4|c1N6Yl9Njo7(48aw~dpsQFUIcEqyymueaPd!3`+49*M2Ele)G2W_mu%S`jLZ%&?H#xKWu;VzB1n`VnN1HGI%X0=6{fj-V(o@?16 zts`D8cMHw!)bu<%zD@KOVr7jceZb!2se_-37jlynjd+9t9QNyG;6A`O`XY1l ziz@)Mzv%#&Ie)WXsl#0WG>6v$!hXxF`rC&`0NMk4!2$55@sszX7g`&>&r*^*hV$PxLWG8(waQGiq(7=SZ$4AL4F)SO3=UoY)sgjcaafvRWv1)cQcIhVFe`sh`qg zM82Q&H?scJw!oiK_9FXF9|Yq-38(_(_NNC;oS(j>)ILgRAGN-(Un;NCLiPj0eivG6hG;SKO?PYOm9%nwB@&vGqoZ!JITh< zkJ|?`yNI$+U~U$qcEqIq%saZ>31elJT9X+qeS61RN@vdqkOWA$hZeZ!h$(>|Bhin0 z8cBbAKfjlP-AX-8skoYddc2{1y3+VPP5h^A{HM>Eacw)L^b<-#;<%dl32pKxBds4L z^pipW4;e!>9ejTBic)*?%=2Exti81Uy{qgqX+W3ZJFPlLeGQfV-NQ(@hZau^(Kpg| zbX*vIvG26%5F>8`t&&O%k^DzCM?ZSPj3hr=i+eaFi{wnxk~5l`+S7u!^yCCrH}sp` z@1&@I)RfrQ>*ou!O1g8dQajfhjyn&fIPZKFe^S~t42%NXj9j};@cT`qAV0hNfCoXo ziMM+xzoFaBNI^cbS|#1i_~i1r{aM3z`w8Q>oiukmLfVuSG@>PKTDI)zl6#4_y*C&H zM%(Adwd?7zF^Z&pr!~V`$lAQKA)ZB3e6myf`(U!*aZH`z-1HaH3 zi{-DdeF^IGe_y`PdXZ$SPxkW-&+>)V21*;VG3&(=9WCz*tzL*<6Y?$;eWBITL| z{j@K%W}wUEjVbyM zEQJ{z^$u|?4m)31PNEd-8?U&s(u}MGTY7s}E_%{;<)SBlbhUToY*^a8IP2%jnS-4t zd&4vqn(;1NjK*nUvlg5szGy5Md%%%3;4G9b#XM~VII;npg*vPK z-z@ZwyYHHIsc+84VqLDsn9Le$`VMN0-skGqcP4+)-Er0gWMw9IWEU-#oA;5e-}k^> zQWrgBY0a`nlU{SaZ0rg%&WY7ezm3HumK`x|>%@~u-g?BENNwJ-wv*AhZk{35F;j7C z-Cy%k5_#=f#`=1edGSfGR~7GjVbb@J`z?}3()0SE{6FM-Qf6Yecbxu@CGZ9x3SdX|wh&&ZB$ zJ+WjIi>&8b+KiTS>)|80@GR%XsO|kt>zj51F7mUsqr8~jtvJtD%1ETvwsJjxvx3dk zqa&M<9(Bx0t{39!K-@Gdxfy6YE4i`I$V#r~Z>{87AI~nXMnfu(YquHVdiNEy6#nkJXWy1E*;(+*!Sv_IzHN+m?7n3z)V0eD z_boF}M)xhfu-JXew2(CWwq8h`w<-URq4@tw<Szm`yIzt+-u_G@*R|K4KnI$27wOlam2XMZ-;3Z0CZ+(gpa zi?n=%M#ehZ8$Dks2Q(6}C!1zXHbxOoL$o_YE^99~3w4(Jk6EZC4fDn(mX|kfiqC3s z8S1eMTSqGK79{VES|8GjlgE3KXBE~9@ndJbOPPh<dnt&Fx_8<0{~Tdxg> z>!i$L>$QO#%-ATetMZmw_dJkh>oo&^?^bUtRQjdfDe?S0Td$t4dE>XXUOjrDl6A-Q8Di;G+j)(Jy4q~4=d(2Hu30Eu4DTK>l(BonS>k56 zN1TCDT6XOjL@bv@7F;vLlDwu_aJ4j22YMgCE3q)CZxvgL3^$51@Q>Xn&Ol*GJIzXK z7OEU=Q`KL8x>8NEqnaVM?Ec9)pty$#9Lpc=a`Mu zEL<97BQ;B0m*;G5$hs}nvva6(Yxgw9ua?czTH(feq@H18VUl*{JvDbfIVC|hIqUMj zGTKw~Et85oX;w)yNR_Eh>PkuI&-3>2MM_nqx-6?D(o8${_2t8byIYmn?i$w~N6)v^ zF0Ey2)U*|Cb^8L!$4Q)dhc>d-e*v6b&iq~4)IDO?!nJjq_rP6Jk(HZzrq)EypuQE+hV|*o^og77vda7`>kOH@O-VP5gR3*&HM>f_T~lW>^ul=h zH*Q5rV1|8{<>!wr?yv<89vmD3L~qZ z87QQErQPtgG(mE^)_-T;wsN)6gcp7Kl65s(%o7^$qF;h`i|EAjl#`rTvS8U$?rwp* zVM%C^L*dE?cyy7DpW$PC3b0bNF7Ve~(0X0IVi*$7=e_#TBb!w;xRJDX^`4TFY1ocCra&94-u(-Jzn%Q>T}d%$p})5M8lW zYFxq{TuRQh{`R!R`s)45k_F{9p7`22v06zH9cO6VL8g9%kN8?zc^BU*XJ(dC!V}4) z*yc{r8oz=9KR)Sje`C#4QA~ZONPHKsaW$@Kuxgp2k#{{(lD+@c?sl?BjGxqG^o`Ca zMkJS&FNa*%FLSz_SeKqr$oDuGBe&36dU3f~B46KhxpW~WS0xL?>bUq>Ie5dGy>hkJ z0-?hy>EtQ$Ma`Xj9>B>haXenG=0t~|v&@nOm11PPb}QF$Y+QK@!=N``%A4={zvRZj zN)^giFr&0`lT)X!Sd~Ez%QH+)FG-a_kTj(qB+ZBt*j~y>i>(Whhck@I$|wcSZr9l| zA&eUU@|8*xDrq2Hm|X0|M$>2V%vs#zvl58Qxm;y*>&%vHn4B{|b>k{buJn3bkX)wY z2T7CDF!^NV%7`Op;Ple19H#7!m%f*##IfasZ;&)CozmN~HR2>RwjV>o3AfmPw>-qc z9>&_GQ$IOx!Pf0NU0SX_#P!m1^%PX@*8V|~5s2_avPiz*n4%?KkTfz#`sn3aEsB~zBszlFEQZ}($-20H_~XFESxjXd~vaQ+xA+w=Hk+8Nl^okuPIu2 z#0`?>PJbX@Pt?zh>*C7UJT7NT-rch>SyYp%Q~FNjhRxnc)_jOcOrMF32IBHt;u{`O zJt9@OBr0iW!U<(7tVGO`=6rXLId!o)$jvV*o;iD7*`gh(lpSZ&I+uAZ3%#AGDY_tu z#}m1!!bmnZ4v3B5OV-5`n82-1n{YkIVdG>kHQe~`O|dOu&nq^~&|TiWt0do+A&P|C&j zMn}brUNpzH;FO>JvY_LHiv|T+ZVQ$#ccZ&-cd6lq@&&;tKcc6oza3bzV3#Rr$6LEL zUQSI77d-i_m62Iev&fw=p^|+wx-L9DDRe#aoHwCx%8Xg1l`B@oZ!JbG0r|KQ>9vF$ z`JNvJ+`V~RI3r8Wq)F8qHg4Tz`ms(=R%lZ0V%Ji}I-wLlfToLlXU;uM@-2jLd#W-u zR_Z&r&;=!XG<}eqr`>SFhW!L*%ve4RI5brp%b(jqnmDus247q*TxG;+*92l`Gfjb{LZftqM~b&Yu|EOw={JZ9C=X{5@ChEzc+^ zo$sd|(Gfq`utCSWq06nG8UDZnUmL%7?@xca@427<{Q2j9@r(WYfBDM;FC0Aht6v>D z^y^>0_~LJVbNKLYe|zM}?|ygm=?rItXq zq$8lEErDjq7^RkWCyi4|{TFk?vNx5gVrHpg#a^`+Kc1IAtn$z`z_!l%^~So6*bfrP zq|DuKp08zo^XzkA7YDsnvC@%lQ$S{rsw%OZ5Z#uIzMr7fpU{B+(|BxXJPpvI{}a-P z^^QLw$&f<;jrt)-E0#P?k()2&0m8r3PN}Z_aeG*|FTclurGV1<5~cX1gTy1}^;rJk z+|jdQ6xoD82GY!C`(w!cgpD*>|JeU{54J2`?XIrYx-dpBPj*B^|JQw)k^w{RuSYjs z57NOi9cD)TM;|=^Ep9r6jsSCw^TiQSH)}x}F55!8y)LLgU}9 zIlpOBnr5HOwcPKbA4;v;n&(DB$?CNmH|hO(*LPg2z-4BbF=JMlTk*M=xK^W2d}v8| zGDgxO7$s#5>9;Q#3FR5eMyZj_tkt9q#>Y0{Nblj)YRZ)O2xr6MquiybQEe$!2E@V# z;~L-d$TqSGAD3I-wf@{~pSxgnbtJdQZf+3U_i#%Wtl497pPW*Ozle9@Ot4Uvw?|>Q$!Rk%>mXlcjQn(YNnBFPmG3ZCu3gU?v+6YkbDvJ+#!qUh#*$I-cP=WV`nja#*fKL`rhJ%MW=@3^?3*y@dBN<3L! zsaLF)+Q>AeWI+wBL+V#RSoEz!p|g1u4UMTK3)YZB=WD5B_I6#UbA<{XtYKE9N=Nhz zQ}5jLUB1S*po}`Q)Xt@SmtYnxRhn>WTrxZTi-oE3w6Z#xor`XgwGd)*_vC#4y-%oE zgHE1a;;eS0+KT2NTs@$pzAgS%(kQ>6a9YWn(uI|n`q;)i;L*o_H;#WL&``Vb%HSsC z`+$|Um)r2La?7@qocb+?kTiS088|iKq|$!-kM)>sbt0=zYwJMtVp4lUo3~};JHEbK%U(~v`xq`p-em##+_$svBkd+!!%g4U0#p!F7T2%J;FM?-*Jj*kup&#ItJ zf3Q~tAL|I_18CYl2%b~HwL?KAIH`hmy}?oyT-Ov3=Q`G<*S)TS>-&O{pa9f>11h+o zEr9-pF&}`1nxJK&3R;!{r2KG8y>AhGco4s51El#dcIU)KRjVFg02pa#T8-g1aa&b_ zo#3bF#IO*7Ed_+112HKPC}c+DPg z5WJ#-k3jR0PA0vN(0;L&7kq@0`bZUcn;L0*UKVPC7L8TVqBB7D7RcU$d|yRrU;2uX zIuMcg(q6=m4p+kn> zhh8_f2gC-!b7##C#>KEuBeFKX7mP6JG#|@v^4R=oKnrgEs`Yi7QXL^=t-hM))*VqLlx=3 z+ObH+O?!fCeLe`wG(ppCDrib;liInYv1yH$(95NTUvj;5d-8iAcnFLKw3tgM1s#W0 za|vTwGw7R9deUOWzgZV>hl$^87{3<*(rUI3oV5P$8uwCK*`=dFJ}3b-fL?wnCGPmq z1A|LR=Q4J|M7GP?fj;{8`)`>h$fc#_wgQwy?)`xNo=bntJppKmdEJdvc_a8;1;}M1 z#wC%o(Oj?;><34UUt`9Z#^gZ!8utMYgU3O!4QI}jxQ!`=#_S8~-;_WTN~#GmFm`Ic zCL?)9mL`_I$pLEf8gRb}Z@Ngk87$LC9pxABP}bjO~<-0%QQjI zT?N4)%^?WJrqT~4;}7@XEfs{#z);h+!+d_1g1z7bsfWO{{UFhY-$Q}PkF5AAoPF07 z=4-@SyZIlcZ|VI0<3W?}f0)@o{ev`BQ((%;XrIZ>vuBy+UFzgr>hB+>&#Hg4)N3_amAH&RSuE4ou_NDo1*{88# zk$oCZhI;MOc(kq^H`I;n(|A1UuutPrH6(>v_G#*fAK9nzXv~cs&pwS87EeFTK1~L? zH2X9e!#(>n8N)sMH1TkHYGj|rt7XqVjpr+pn-MH#pC(4*MikE?O)T9E7HMJ>j)!xt zMH)-xS)_6C?3h!_B8>~TGRhu-zJDtI)=%;z`|y!n8W+d%^n0i;H#&NT$JFaQpbC2_*B(r|cUHJGs{omb0^VWXP-Q$_%d+v^cSP@65LnoV%4zF(& z$E6c@UAoTS&xiA~uBYXSPpxml3zg&MdRP=wpMP84(l5;^z4T6ID?et8gZEANm}F_+ zgtzJF^zCnX)AOw9_!Ql!S1V!kO?Z#HU2|EAS{8O3r-+07LVOyB=-msO^g1`g%PO4rx|>nv;9&XRZ2p zd_1c@&NrgAR(+g5Zmza}g>JE&F?;?lk7;_Aq$o5o+dh6QOChqQ+4gZXUM+dHeO#z@ zBilZnzqRdSeXNBJ`{Y^r@nVP!SuOp<=+biT+q9Ui~5Oxuer1jSN{ zSqO5a6>~FK2yzr2zsN$6^MfWQS-E8AuE;`3T1c9OAQyuESq?kP6_q-UXroC=HndLL zL5@Q<*Ge4O4)W+c+d-bMw0mni$ofjz>XIkK$z;k#>z%tV8@f2!ly}GOWl1{#&VBJ*MEkuwV_~n zMjGoLm5hn95~~oc_3dKm+nyl`4IJFO7o{M6mY;T^lYJ~S+4&|SxpAfC;zKL%Es-@N ziR*<)8uH$+d%yVGaJl&*`)O%*j{JCT?r?tgIUzdlR=3}!)5K}M`&N*g9L`0Kw7l}1 z#UheRF@q~o%h`e0mq5dgLv>rfj@D1j`(2N9B%wr}v~th#99c*5;xrO1d*42im$EA( zm-nnTk{mym6Y0~Q4Du~^^zs)+YhR&rG5h^m@%Mv>tUlns^*va*;tsgvjQR&8hfBHjgZ?3$S_Q%IzY$8EhV9;O^Nx zBGlSEvUHKXA1_{H^T_kd(>9ORZ`inLv*>+#A-V?ab1nNvKAqH-_nc<`$n$qKl*Rs0 zoHEOEM*BxuXd|hp+o(J|Y18Z<+4`@;{!x59vN8OY>hdVA+&dDh5i-KbJQ*7&B(`vL zT*yO4TS)cgjqt3tkQxxz^^+{NkQ&Ir?3{YGkm`t+W(z3;oo5Tlh1xQb{;JE-`Qv)F zkUU?>m1hfykjNI2MY%my-4OtRvwQvySBAI@h+%4Azli6q1_klUt2#V{QsW;H3Ar|tfaaEkoU@Lpug%u1HQc9N6Xb7QuXEI-FLB}c&|J&s9Cn;Xe(nnfiS z)-5HMiyzYtca+YRRN*Q!a5P#<7@TCas_h`VGQ>}0o@R8#MaR&|EEJZL#1x&inI*EP z8*591NotqS>cw8us@2kh%$g&z-PGKquH|Uxjm#h0i_T%%nqJP9u;n`|!pWc?G_e{ytQI<;&-#pLte3`r?X z_dP?(O{jIN`_5~*T~}qG(>e26)|HHDvM(C9{^M*(S&Io7vJ zYhCQgmdujVE@M51TVJB-?b3+5K2I0swMvQSauRQu&i2s7&53_%lCn|da$~hvout{^ z`f}B+yZW$xZ$D34Rg#|18$R#(8J>06tCAEYmALDqaQ?Q=E|Gft|mQ!GB*R>lXpg?L(T-UDbb8rK9m%Q+_ zTSzXB=jvNVJg418^1>aj47ZRZn>6}j(gU*DV{2)A8wym z?|h1MLUZY9Q|Hcg{$p34oou)l;V#k_9#_E^7}vgV2;KN2xaU-GZwr9#{=GX@@Woz$@FA^1F+ijI zOG5x-+R*-hF>>gOD)@3&Fc-X|f?>oNwg?ju0sVMp^(1!#20RF;70K%W zYIZ;kI0`6_yLy2!ny${fNd1QyUj0kVU8Mf-5PtocGq(5EVHfi*lIDFU`MdKrlg^!k z`Ar_~Tm(q_&VAOO^1YMRcjxOW=+_=}2ej6H)4*DQjQt4zTr1ECj0B}%KeFSe^MJp& z$scRi-AOVsD0sIxpF2r?PO0Fty}<}D+Hn5t{{>)c*}(Kr8V{)0Ju-k zmwwZCcRhEKf?KGwF4XBK3cxl%9dN%W_yjj+#O>P8x}*60t_r$w6DD>iDd@~tSL;qv zaLbkEu7SO45!}M;uJ3lF-AQsI9j<3pl2Pgdxs&v1%IeekrtCg#Zm(R&V@!cLse-oZb)fo3idrS@+&%=%x01)1rDGG|#pPp60KbCBEO;QY4VfpPEyd#_ASY0w>J&n?#+!1-AS{1IWn1Y z%5*0w=tg~Yqb$4GKHIHY$Mxb;ZX(VlN^kB{cal7sMvQS2 z^1VArURXT+v^z-|=+f>aWeoT3BxMZu?j*&->8a73B(Ju;J4v3eNS^UdQjErp1Kypa zSh^YRB*iEk59iuDNtVjHll1=)_x5pGRoA`vIcEk$B*q%cHTl@o5Tn*htTonatTD#7 zTI=;vL#?&e7;C6eG=>;sh_MgDFu=gPFu?E*BQFCC12e$zPOYU}W2iA`Ew#iLgTz{D zthM?0$;Y49{J!74*E-KS`#I;C2PDZK>$A?;d+oK?emO6D?X}j{a`Mip@JZ7Abe@V& z64NEE!Y4_~2v7SIi#4cFWPFmel;IrsB(XlB%J?Knn)oE8cg`m%y>ng}>7DaQlDpI= zN%;e3e3GP{slEXBflrbt>E@@D$n{B5Zc@8)&G;mR{LqtyK1t+bdD?5txYQ@f@GS62 zQVM<>l?%sEB^6xZlVtO?oZv#ABwHr<7FRyuh=~uI4X4>>IjuwHS4}=iTIML~O-EAd zw7YACK1o_nh_zl#x9!k0!Qv4i6cs*6q*8ABgry~&t!i2_@JX^I0}jR~NlI($Gd@XD zkE>s<1D_;I!EqG{Q=cTmUH-X*qQWOhIi(!LCn>`rwJ<}f@kt_$_6@H2J<0eaDUT3C z;vAnOmBdhce=p;c#5|qHmfms9_$1{~qD00gNohsO67eQq2$ zkry%Yy-l#;V|G+UpQL~;eUs&+8=s^gSA3ErwZbPUpf)~9K~CzEWYP!qNg}PC zwVY#i_8MMpR19s#CrRkUCrR!yK1r67a1rZg$uT}jmKG9;Pm-jHPf~j4_VMK|;XHr>Wm{=zAd}x@D8(Uc2pGtdh#C})DaCd(9EW|&bGk0#Mk4h-D z3x$?cob6xnTv0hNK3*e1>nNN?w8;7}DTffJ98sgU0A9tjFQf+?cHRsb-zLrkskN$a zlS)>EWk#jGO@_|+Hknk)Bfd?N$}viPnhAT!|=4~tO=I*HT zZ8BwyZxd3*w~6^q;?yq&DY?E)%BcuDF3!qUc&5HhA`@jV^lj4i=(}Fa*in|6GrmpQ zTUs788Q&(A*6>Mvo3sw#T;C?cQ@`tJ|BIZdZD!hdJx|xQkwqK*_ek@-zHP0!neuP9QI$KZm& zsci3v60Od8CftSu3Vj~gX8ma%2q%$q` zf08oC;QwT5sdbzOqs#Gs%BjWpKOtBApVGFmxA9&#AAlNR_tnH)E_|0hdfMpH*N*Z+xSEUkTpB;EKwAtmsC(z1$W zZszzu1r&THsFTn5KdCepi$sC{6DgRZTm@(RpF|dpmeaJ7K1~z#YT#w@_1r7 zot=ucS2R!Wt$gO`NM#fHqx5*ntA&!-TC3e_dElBno(z3O%k%1COIgOWUdOWrk0-6I z*48MUsc}$`C#@sI%F9TezKtbKTT+9^lXACQ^ZF~yH!ZPyGKC&bT2B$S{FTN$YaG*K z@_14?YiW~}p&C7SR`GaJ=|imCHC2mNO z9#1Nbax22xbCO@-@f4J+@OaXE;gjp}q%;Ap@OaXE;Z@b+DQsWRj&znPPvDHlla^PE z{2Y%bQ(9+-{pMsmo`iOg^LVsA)vM^eVCU(Ayc|y!mI$creRWS3Cv}z5IbJJLU#_Q# zN)JrUQKhFzR^x6pO?i@3_?Q^}j$ZH4g52|N*fP@SEKscJz(?g{qV*9g4?cr>PyS4o z=Q78~L@5nUeN31pB?BK5rABU59}`2D${}2jgOADA&yV7-kMlkzUvI)S{6xM!0C+u$ zAG#HAFp9r17O*>tABH{Z!=QN>7RcYc4e(kNPlWC4MA)ZJd@hQ=brE1O0A(Jz3{V2V zR`n6so_>2I0QTJ9hK2ICHvvHZX#KCk$7BL*qbER`36Q+V$7I5G_>f!-xE=ueW?IZz zACn1?_G|S3@c9~OzV-mDZyy2fgoXIkzO*lLrs@`o8`VkH<6~yN}6NM@R8jZ}L7SUxjS7`j~vR$NQLkb-(v9`Rbds`ItQL zyl>xEM?}#q^qciDndL3;qgn9(yAHPEvlcqq-$MKv#vh@lDfieGE%uQPvZw7rzrBVL z7wKKbI3-^D>c%DXF}WXodO!N~e)Q=zdwm~XgYlw|$^GbC`j~v>WWXrEH~{9sSGoZ^ z0dGa|1499@vwr|%YJE%|SmSt|S}IFGpYSbP>HEm|1wQtj_~p^!{=O^VBSN?XaKD!% z^dq?sqjKMFpLgFOT)zz|PXXZBy8r6vWLU)e{^5>h=RDg#u$2E|LlobMu?qc2{_1J( zKXTXkg7L)O^=cG<>AXrmk}u-jR_RCb#arR?wbhR%aQwvw-8FT3=4=~%n*oazxTO5r z{Yb{cW5)TD;K?0-v-cwzj}blIek9}D@x&*9k*EjnNIv~VekAwdsZc+X`$oI#Ux6RV zUt=cyHRkhQ-wwdLJRTP|`0y1VEWDqs*5d zm$V~Md{4bkyXP!iUl0F~Q-E*x`S(2P@n`Vf`OF=X)`9%T0f*gt((%3*W#~t8@5P?x zUc3+QMcwxv@%Q7;b@&+lJjUUf8uub)zm{Gs#*-}#qZ050Am;u!rr zz62S*^tNx&xHCK^=VS5n7)NQY2Kb&X^z-=AUFCYdwA{a2zO>t?9gCmGmu_}tjjslt z@&aEC^G3-0y#?txz8XSN;j5t~<-acQ3D8{Nz$d`uSV=NI0YZ~nmYXuhvfQMSQ?6xs zK%;-XHQ0{_B@6Asg)Tj-!u*>ST6asCz`C2M@&}t*WNR95#v)rdq<`1A4=l1xN!!o4 z7TL;8|DR<{GZxt)KhRXQ$hJJ~HAX76$TmC+EV7k?|K`di_|x}e&#&>i-fi0h|9dkU zT0V2agUy##*JMqtvS^RhinTq!R&!TqO|A8WSnJbt+YU_=Y-~A^QejO^D&;0Upgkr3 z4#L}8{5DOUI!$)CY{`H_U`;KOkZ;DCTGNg6fi<Q! z?V_2d5-CRAId;)ngHi!kwTrg&j$@%+v{C{W*gYExJ^@E*_Z*bg5hpIRduADJsTqrO z_Arm>z*X#?^J>zW4Xkje*HCeg}t?i+_7Tb5MpXXDjO`9&U z^|gJ(sca?^zDY07aEWwp@{Yl(l(pH~Wqfp;h=UmOdF^#njA@x?yJ`8SG3K>Sa0_D0 zXL2$z<~8RJ2T&%p!^EBIGs%5lc9_z(Alf@Qhpk3h#v+pWF3ng(N|{1CM=6s^Z|~8g zsb!-{FSKlwx^#A=Jj3w>U9M%LmPZ>ZEE`Q8=R<1Q$aLwOT+2pVF8Fe&oEghTp)a&- zH1)ap8SpHyY*Z<7aG_GbK4(dK=D zU6gVaT!-^7T)b!HfcE6rI|ZfK(n0K zPRs+RjJ=bjRkc(S8aImC8zFXlB}$v2FSOVpO~^yE%9 zpOZu9-YVM9sI|xnBF8?5+#r|AS2H$J9F={J)@L#Mi85%K-rN3@d6AJ-=#SDqC$E;H z=>aVdT$6o{q0h8Z(`{=h2V2TK(|R4x8tik5xQ4Za_ol`{?Q^t_5L=#_XJ#c^r7fw! zK1VrNuC&*4LybEpSctIm*8X+j^BIm_G&fIZACg zsN~EODQmFLQBD?Hu9_|!-FwQ&Sk*qqmR0F;aE7;PEf|Z>DgPFZg5rm9MI+1=a|wuJM1?nW1l0m;^`P+A0{~qeKr8EtD(&N zQxWXF8(1c}&x|3;ryjPJ|XRKnBKB>gBwe-Y9#uf>@Z1ZYhd6S;tgfFowLTYMD zV<;Hac*|D)+e)1OfPnK{_U;OktQ|Mj zZY9%kr?-;nc*I-DbS$pTN@mvGzJ0U0etlLlZLn2fzg-2}l+a41eT46C=C^+Ya1&s> zr*ChHT%67J$B~9Hoi#FRB{S2v!SW@ZI#w{A-f3w2v@w-dGL5hbsI-!4ge>SK zXV1XiYVOzSNe;qw80B;(@|ZM79omRiZQ z?x}7i)B2*9iP2VD-*(r(0xKDgUh{bX%&g|S0PTR4e$F>z?#z%FowSmff!>*cH}Z^? z<&mE`)YHx!?bBvrUd_atoP1|umhjz0E18)CKL4|eJ+@XdGx5%yc?f{FKCB7d$h3^| zRx&MO&(v~v6u0yO4*UGpkq#fDmCW=P{nK1zB{Ln8G~)>$+)8G8kCWpVtz@R5p6R|N z@$}1l%h+?rVkI+u40vG#r+Yi3LMxeR-mb@u(6p!gNKHHB>pm7MnQ4B+jFk+Y`vNN& z^G2|LCib6)={Z(1QnKEivu-2psqQhbk1;g`_Aw^M%8;>-5t`IK#+0cq^{$t5s7xw3 z<=V#tG}_V{>|=tGh4wK*=ljgXK?q9LxpQL6|B;k6W9y>y=I^z>l>Sj_uHanzmVidb zq|W{Sn}2%Lz+P&a+SZQ1Hn1SgN~OJ{n0r6dru(!0yalM?rFG`~@eXyiwYjz`XuEQ+ zFJ)r>F-LmfgK~Nh4(q}pleE9($yWX(BzNAf)_n|^D|tQPtZbFSlZATMbN4r=g-2Nn zcP0Gks7sd_Zf0~j1BSXY$x>UBunwW-X&>(VMU&63{Ji-~mKxrY8`zeZGVVzeo=M4a ztgtH4QYp2a(~RarnNhbHNscHZmrZF}u#i^Nm6GY0b45A5nU>4>GzGRGDwALzbCTz| zZQbVWp9f#xhVq_>_)i?AWnHVfyH|6L8Hs|iQt63@;c4cy?3g`&0nZ&Vr2;8+HZvwz z_@rg*JfvKXokyC(8I?ElKj5B}rl~V#aZEnl`O-hWOu6;y1osQY_<}Y5tKIKSrWo+k=QVxc5;&4d|RBMoO5IswUbq45Z<=|@P z-m{c{Up5xPV@PS!=FJ1eElbc}AXSduBE%9{31q*lXa&fq{L_l3&rJ&R~m^Ns%-KS+q_#D_4QTCzu zCamjai_=)J_B|uA3~H00QmDOw+*jBnFkNYY2Z?PYTy*wjF!PLNux7gj;TiS=?=x|X zgpPk%J?m`zFfCctRsp4t$yUKh(X-AyKV}?iuvHLwRk|WvV5?wDbIi?sj;(^^GFn_q zD^IYl_7xxIo}0|6)rNccmEgUxOaNtInGlvupQYv*{)}`Rzt(X#&lBxH!e~wf76?H- zNh!5Ia8J#gxjfHWG@NFnY|jm1dmuG4E2n4=>tC* zY5R_&m;+{Bsl-Kl>F-}+yB;a;pX+Q-qf;JDzZm)1FN}S6lqdNf?HJcUUuDm{hSF|) zrClew_q;vBx3;l88PBmj`*z;^g^QMT`JS$ggU&K5jsF9;rwZ$dy~n^4Jz;m6=U_tk z6MA(%*totmKNrD#@Ol!JxVn@dNc)WE@bVO1FG>3DuVr4E`m648*EkPq+~ppOn~{p+ zS+UC+gCD&3;tzlL(n~-3(aSIY_{WD1z4FSDBmeoI zZ@&58|LycU@!v0u;=f-G=mBg3>;ym$`uETY|NWa$yk|H78u2~Y7ua(x0DCZd?u_Dp zz>eEL^aHS~_Ya4ocrWtyLesss1KQ5U%&D+qYsk52=VvhD+G8&M1@dy@U$8{b3%rjP zV+RK~CxV5P80z#K_Ow)2hSI1Mz+5F1#<4JT_I(q|!_j&RfI`_XRW%KIP9$`$2 zvR`{&e|m1JsW&apK43cVQN^?{yqw&5_v9_3loQiJYSr3_(|vg5=0;*wH+6*aHq%nz zds2GtuzJe}JN1S((_S-H$6@DwJ9eVBW5#pme)~Sa3xJJ&q zJW-(k`zwDHJNH{2j^Zsd0eC)(cJ8-ezolAyi>=u6*?JuSE!f%$K#LjQVk=t9o%?M= zvpe_OMkDPCz&O8uvJLfbL(8{e4`$}=ryhmu&T;2^_B+>#l>HdwsJ3%g()|{MvW!`$l=$KZ}0tyV&pC_n}XZ_s)Ia1Ld9j zKGemhzbL*%AHGZ)-=cqnyZ#mI-1iKR;vT%UdoBlHUiY*E`T=-8dhk4~yVOg?o%?m; z08M~5d|L0#QQV6%y(rTwR!6<~D)b)qY3u8wc>Q^P=YIX=zRddDJ+?dd>+$|szZ9^y zymP<)O}}%$VWg+ua9I>@K;0Ym`TIU^QE-eq_iGnN@!H*}?FH=4*L#k5#!^d^wfm6| z2?pP}Uwe-$b&NarYaqj#1HRrh@0RO7mYw^xr$FYj0KTUSckb6*U9M+MgMYWIS?tq} zW#@j)#jdQ`xyMspuyb$T2${dZAU$X2UMMQ!TU3->xoT}s?|S?}nLi)?Zw34JK{@wl zh7y_md!b49?@bxAe{WJ*XYT%eK%=$Quzw$vEZn~rx=efvNh^$RA^Aak3#Q87Y#QG} z(||L3{=z}qqy601pYHpcl6FLL_y3if{!7b!CcZ@uzpC*qEKhsw#=2p$(?l4a1@SGE zBA8R!Pl~IaIHVTL?c&l!0Y(adBpdM<=Qo9JrJBIicEUCR)fV~GR?LW+kWhkfG z48>^=$UgN+?$ok!oWC&kg_aAkm8Zhu0`>ZtJYyy`%&l$IN@dP3qwWl|Eaa;9DR)R2 zM9DCH@xClL$OjVSM9Gkxw5QPHnJ5_|LFU{rDN`6FL&`Xw96@^zDbgqzCcQ99hSZhH zr)A`+)u)&FxluB-JmlctNXCN1l z{v@EXr3#~DXc=3Zxz3G}p=AO*s6~p>tF;O1LF+0kQb?yXz$ax++X~Lw5}x|xD0Xc( zwkX_9;QpU~L#$lo_t7_Qa#kHemzLFXDz9RZmm`z0OOgC4@ia)0ws!TJ^t3R;(al@X z9g~d;%4Ondh(tBms0gKI- z+Gk$Ujim}w0!tMw8{nK68UY1IFE@q;=~QZBk*L6eCE%Kgp&@xWF*Jfw?4d#ISfoUH zW)Sa1%8D2onwRsQ31Vm{Wq>m=G?)iYnHU<9RyBr((74gJ{b}oRd}UwD&=AlvX_ks(fXE0yORKuVfGt=9 zt_XZ`qGwp{Ib)fzF%nuI$zg6Mbur#EKNa_{#1>PpksZT{Q8b@WR2+t8Ce zwt^=w(`%{nYzlrc=$BG-K1BRXZxla+9qVVX>;B9Ez>z5aK6V?wj~#l4uNM4(;7(xd zwS6DEliw%p&jF+d{>~FoydOKD`%z~94FK#$?k@pa0kH7ek9O=w9s6Gb{5(3{`GGXF zw3JWUSiYPs(RQRKY@ijJH*eb(#oxOE0DFS(-4B=sXa``w^LuE;_XYq@0Z_yD4g=70 z-+^S`gN?;A31B4PJisLYNcYSgfV%-`*)xvlNH*emug|+SL2B1y*&^PnMwv^4*z$9>6BR(}05j>;~_H zbo+(_(C7Ou1i&U>-&g=zxvwD_(%ZXz`>tKiXDa?K(!To;0J1oKbD|R%J*KmB(IR-- z!Rj9taC-pY`+w0J|Mv~R+mK-t;NmFm>O$T^tWMEV_~Z3 zzlKenI%7slOGn3=HS5+53}E)f--VRlJri)QwCn<0j{)2Q7#DrqkLqM<7^XDQJ8;?z zr~A_rL~weDIb)@(YsCtGqKf;w+2m*Hu3Z?rGXNN`?_3VJ34rnX&Vzsk0LJ}0D*@<9 z&bseBAH`2afMEcXd+ICzdh)3&a~#semL*`EThr!bCBf!9;L;8PF06M&w3 z>JR`u_uW&Xp= z_L#gQrF^nvY1fLBBJNu2-%R}jKCOSN$B>EK<5}oAmTc>AI4L#2=d&zdQ+J=daUC@% zA#?vu&N!79IB98-Hz=ttcD^C#A`D z)cUrVUcsAY@shG^rIMkH*WnGtdP~!NJC>|7lE=N6#jJT!^X479%I#xXGIi>#MJd;~ z+0U7zZ>z1jWA$1YKa{B7xOFGOC7CaxtC{>u_$~%LTHlPH+u8FlAC!vNwR^Mh)KTTz z2zl{VFYS;?lczMzY}>vwrzS_Y3QrH{la;G&TbuAUAQ$Q3q}0}BW~%a9y3AAUz`KP! z`Zf)ixz)eXrPenzG&Rkbv0}BSC0Bu@G-;qb6YBBxU(mHtc&B4ZzNP8i>&v4&b+)gq zG}+8UynWjjtXgH;fRc`j^m_f|$unEp7wjrasCCr$_iq~5wmq1Yl(KHpq;-8;%A@Ae zR=|Wq>fycP(j&dIV4-ib+nH(W!CMIw@xE8fZSGpxZF;i3-{{=G_2CzD zz%e6e8I1O4ek zfaQSQfW3g{!0Q0MB6!#0-vMu+hK6Q*3!eTt?w5k!?X`cupS~&ju=DSh?UpzF#Qv8I(^D`Az}$#2#c``$D_{kfm;FSE#$>dqg{>$@?Q9~T%*k{ z?M2|jfY$*(gAOe5>7P0U*B|xQ7w*NZcRTUY_jNtcRmd~WaUcxQS+*NrzF?j)zi#?; zH`{pa@=3GKzqz2{?Od?5Yx&C6>o*RRpDj`tsBdUNZ!B0?eq-u06EE@4e$p{#lYE^} zF6o%Psr;pg<>{^~&0ey^yt~LFnbB(AyvdZNwdHqP(zUMNzfqhlO>JJjdHxMsH+N~* zZhZrZtoV;_U(o-!qf-f!QlojhKv&(qV4asuDe$d(tl~-T7Wr5DZvoytkdq|{L)ts$ ztXaPvZ;Q$`2W3r4JIwdKzH`B%6{}XS4gL`*^8)!=%+{~jyU)&Aj*rMdoNU}U;J>BrZmONPb;#SXOP)R{mrTP~Cgm`6{(`QxT>I?U zA+52!t5U@qec!^iuxV<`yaic~j;g82Kbcrva}{3S)3bj4mMuGXIz5&1ljm9=fL)*Y z{O@pjr8I5c(v`j0G`CLwL=$!%V3n|S+fMf{f_qzz*F&1n@p#uiwjx_z>5|eG#<)pq znlyQOv%goVU?YY0DaDXd=Yj=`7B5|jZ=I%DTvwXrGzCl}2f`4qEokrQ!_z5g%AIul zcYx-AU(Xp*>Pw3OoErP+AXLz4i_2XqM=`gZc&qVgy=D~sk455e1!T1R@A zD@TiyQgcf=hdWtVcRTJ%HKdtd;21}|+qD+0fi%a#FXoL)qxcQ{9lU|B{2Q$R^y?e= zr+MSWDE`kg0e1ngQvJ_^QT!%WqHkUgm_}81N8J(cpYV4KLzknz-Yh? zfboC_0Vw<8Gr;Xpd}z>-KCU+bo(8-e#s3xo&ct(#|Dr~xF#tc%`~*_{WWbmC$)4zapU(OU_`M?h zUO`X40=Zv-+^@VB#fL}udJaSO!|18Qm_vte2HXyq0DwG)QT{OI%i-q%uL0hMd?NuD z0LB0w5?LD^rj?M>#c%{)X$LHgej}YBRrGO(y3uzp0A2_D%=0|-F3O{SUxA#jd<1YV z;9{Tm%GJ2O32-amPQU}vaMiTT!S|x96*>Tp{{qf0YzJVDy@2}{FxLMH4*z-!;AsGQ zgKM$_yRC-kz=0@!7Bh!%;IL|l^xZ|xDX!1aCua&)gqbHNJvVl~J5#s(f7;!hJxkZk zFZ2zcnJ9i4a=eTlXAi!NdHFJ=co}lP{3-xF^J6?0KRyL;7T`ip_v34EJr;nT`0)dh z_AstXfL6c&o)_@>@gBf_0QmhF{cs384vhv}1i*82Xbj+XU!F7h(EWgi0F8k8(I>R6 ze#TPAr7hOJFRwH3rgxe_ZEL9K`r#c>{KE$U4S>af9>C)O$o9jxqWGm#0g&w_jPgsM zeQ7BGZFuQ0;O9~NqoDxIiXWXX_gCT?^8X0({|K`G2)uvv2%s6z57_7589ze#AH9dZ z9052Ja06fhpacI=*tc~p!OFt-!VkfbBk@D@j>ES^SZBAlr>RLh-j8y3MKq$z>7wj2EdAD-+>JMJTKe;(kHsLuD7&wH^Ov;)zHyoOEt+O2;w zXEv+m?FVSn5AbCC0OLo#KfoCN0Au)rt$@9NBf_^He9_M@js{!-7z?-?0Qwg}|6)fp ztW@d}{jNV{If@Tn?MolLOE7xxU<6QxdOtg;%{zEH0DXKA^XuSc@IdolZLS2? z%60l3r9Ov$6Z|*FbCuEl=`&|A{yd@o)2}hKNsZ0v9qjq1U|VhF%GImaav87#dR48b z8vam2!_=wMr$h7GHmhUKoO$!`59HRCj#p1FdF{r3do>e0`mXvz>p{)>J^`&X;3!G+GQ`n~tO3;UZDlRSc zwYIN^{?ny^g1!Y?(>qv;uGkjzbzH*Q80ERTZHG44@=w}2W-oKKIDTD^c}^w&haZ=q zscw<+0`T+R6$WRjz~E+vm+&g1vXI%@%1a z9m}ee#AW{z-a)rLwV9e%Tq|YS&%{%}gMvFvLP4s!(gvsL))Jnsgg*pmZ!(-pjsB@7 zC1xtL-f5X7>l|%DKag^&tkjayGP5?~&R+A3O`B;k=VzX+MLE_(m)$;#k+j0x`qE_j zfGkQQ=PJTJ`~obH@=n#1zY-fR2;*Wxy(Q@0fG-I+FhMt`bZR}PkjoCp#hv}+Ys zewFfRNm_Y3?fd-s8CkSFN!KRm;FbT7(u|hwHD0r?94t;sE$yboCF$joJoWNaB_*z9 zwH%^9;tx`5z$nmzP9D3AZ1coVxEYkG<$ye3xTML zCND0n@HLlw8UT18)!lww$^Y4$v~cf6)&>-O-w9?H$~@KHd};BwntJ4>P~ zfR@nTi;ke(-{Wu5d>xb0RA@~}N01#Gndu2MJZ0WVNk_}|#A7lCCoS|PVT1j6`m_#d znA+UdF>m2w?C~gX#Vn1UF|#EpHO(l~#ig09Ox*6}t}D%KU)HlO!-rmQ*fo;(ijxOi zS%dWo(H`Slu&h6c=V`zA85D~iiV+VRFmdn}g|=ZicAm&jdF0`^v{~w$)WFD(mIiaY zYvZPE_|I`V2kBAm1La)TysCS>^n{k?dwjOe#k5tE8^bRgb}-u7xMM9e#7Sul_N|mV zy-X)JA_fh1uQW|Dsm%@+?wF!51hxl=fQUzKYlgp;9y+OMdh4vtuI@GAUlA!3@W*9F zxvsRFdtj*~tgCLyl%76lLY1$>+zmrsGR5luaN`F&Nddl+8ge>*poyqGLbN38+C-L998G5`0OIEJr3b!wU^Z8dLAC%-&1aS8kI z?wPWEg#QLZkEo&RHuNEacG_o@jHT*Ju)bNZbHmnMS6bc29ePb;31~;%SZv*1{+rW$ zVy<0U+dJpmx;3BWV_3)V{^Os!^@|ht?D>a(*t_o^|B=z7o_Xf`-{1f2bI<+LKRy5a zKmW5vk~(-WFP7AQy#CXlYCI|MBER_GpfP!NlwXxSd$DLQuzr3PE3{`jB)v;8{`#JU zKH%9yfVZRgxsiYieBN_d^*+}M*Z|lK*bjI!ivMX-6u$=kuVMZ8&(}xsC$SFyXRKil zU=924rvMMoW`tVr4I8}P8@pOgGWN4v^ZsL5O@iO0q^_;3KY+g+V`$4hWu6Z1$ZgOr zJ_3DOJzxZ`7X#k{{3`bPo(CKPKvL1i9rgZY4f;F$U#b3%yPHQYgGQ_ufWGCr8yYeKj~@HpXI)EMpNrbcah0*H z=gPh}jpfRDSC#dlPHKmX|~XAY<{`>A}E%-e`{4e|S_?w!PY z_q=iT$ulyd{2p2k4Z&bA;yYy&VsdmRpMI7+PHJeR+xQTmB8Y9?%6KnAD~TT z4MS*If;C#+TABHXsMg$qcguWNI+RK85nmou{hPKFyrE!;(J*CN=lt?}O-t65+B@b3 z=}BoJc9Ka!Y5CVuE{C0^?S7sV^=q2SIP5*a*PrcCZgu!pa8Ens z?6~5D<1{7R)kaP_ZrIW0wfb2pM@^f-{cNd)n12afk8uwx`v;>^;46;ZZIyxlwB?mw z($coD+}D_Y?br}ZT%Z`UQH#+h{3Emd7u zxqjw_fRi@1hJVs0G&DBNY@gk^s0#|Tt^V&LET{LwN^?7@(WGTBHL2zQ7gE@M)cd;9 z`~{1;%DMrjCtU+u%W}rtzjr-9xsj*eSzUqU$oK^9v*yi*PJlbTX3VrMVn)R&Yacdk z^%`D33R;GAA!r^k{57b7Xl*0{1In{w|-3~bh z(Sc}5mWJ1{w=P(KJzm74hn=+J$~=XzW~~*Os(27`e4pPJ!^V)WM*W@le|Fd?JDLkWY1;zg{@%x8T6Us4BeRYnARF{ zx9Q{rPX%8ScK-Ps;C~OP7L!HjUS#=^-7{p?M?s)>eAHaNgH21IT9x7K)t< zH*Vf#^qI<^7&=6?5;0#1D>bjhMnu~)75}%mPOU>Uop@S{%fsIt4iZtj5Y`m(bR3|$ z=ry(zOhd#Z9Ii9dTZstgOnF+0Af3@id3uVT_TVfaU^(LaHR91(tm(keFY${So#E_E z_~z=t%7z{fl6qo?&n1>}HAaU$74Om!%B%N(P32z zV7_q+qr)0HSHIo|^5jN`60q;i1$a4YL0p~)yFBJ}*JK2GX2hW=`M@wAZSMo;-TNAZeJ8_zry83`|xI3KPrm;aj3h0-&Qu)oR3(rSo?F$f6bUEIRX8D z!aaaTD`LbZCv>8kZ0v-Zv0PF$0gEpYwOpMs%#JgM_wa17} zhF(2rjM!u-Mnq!7CPSa|F=DTt79~Spg@n;yF=F4rm+b$8p6K^5M}7}u^?T@N#)N%$ zzsLXYLc!3?{6A=8-h<`=`8*BG#kwNxJD0dL?pEPd-$?H%{2RV=J8aXQ_cH@He&=C# zjkPPN(ikNAW&@V}H%a+*$B0daTGSIvJU{sOIyAVFn}*xm1X`T0J%04d%+p6nhPAnh&4G@l1z+Pp-E%JnldIvtVt!O+!(O|js8K_5F<7ySr{W$=rS>4 zC9N<XGvpwh3MXgyQdP1!AX}a*VPn7Fj^jq0Rhba{? zV#z_dNe`4urn?rdWDq0PmJB!qF=9z6BS@>Ld9>|Winp4k8|nGKLpyVNZv_mEwu&G9Zlw`M2b;&PK;QsL8*YN#)!4_j$>hrSfvCmh!JZj z*tbU+BQ_|Vjs(&RW5lwIw$zM8I(wMMbl@s6V)JU&k}^^`F=C}uCPu8J)#Hp=`EOP} zl2aHXR`P3#5i7K|hw@si^ILIYjM!ARAV#d#lg?HXBUbW`Ax11qYOfUF+!(Par`im~ zX%9#o$cp%`C}X0seh}*yQ~Udh%1S=&dGY!@^NyFCR5rBH+TW-InW(H%rZ6h2N}Y!x zMH-dW zo{}vmvn}nvboRlDN4?{OzA!4Qsn4}1;8_rrRi((ml$xtqo`CB2?C>Svn?-4*b+-3- zog0-^%P1D<293(9^qj}6n{@(LL}ewN(g0VD$|^kdiBjy^rO{P^k0~mv%Bxu9rQDgQ ztdd_PDk~|{)>eti3c6#8%8GKCsH`GU4N+NzGMxtn_XQ^hTWZb%y+>PfBD6~GAQ4&( z59L=Fq1Dow8Kvb+gjP@n5n8pZVwuG`5n2NZjwJWhWUn7j6rLrHF6k^5i3%dLDp$do z2(6Nq6QMOI#X1Lx(3$6zv&@{a#)-;(H8JQ&SC?m8gM_WrR zEmnFh5BwWgg=6D%dNZse=(9b4fwKWzMqPljQlPb`p?A`U_sUl>TS^+<3$2c44RKnP zyK<`)n;Hj=)2elZ*w&?aW>&H_+L9XLv?>S7wU%*WIhFyo>-fSrty)hJw)HEGZ53oX zrZ}zSWqH@qw!!GZvr3#+l|IDERnw()g>hO*r)8>P&YRqJcglNPw9IIYUR2-|vcCsNiBr&T#wY`JQ>a16gE zRpYeUvMOB;t}#xlax22xbCO>Xr!^?Ym6=~<1?v>ylN+Zs;Gu8fia4!GC%kHk(;Adf z-g&rcoL2D3iPNgwiS1ZQdL~Y*q$N1>7=0sFHz$@l=lKX4{!8ZeEhSHB@-SEN8EYVv zIo|#P$wd#t_8<2A+-HKnKypzB0K37)Um&??r{oVH9s6e&Jp(utCBL5l&Tx6j?_Y*% z?9=`JLckipZorFCa`DnA`Cqud1Ur+LTpX#tKynFomOp(XU}iML$H>{XO`_yP7xlWH zPX5O&4%^5#n&(D>qX8J|Vr|;kH(JtC(Q`{9-Y6Fv!^Wkd=Aq>nHUk5ZrfLatB=>S8 zn~>rJZ!feC##nyzC?#9O8BNf8V8rvyMz!gOb*k!Rl}>sit%vE#2iG>XO)8}+<73-s zj*V@jX)0voUICKjrUA6Q83`%r7yrP4bBwBSyAK zK5;W5(%`B6#9hFcEfU!#`2@aDM;X~B`NT~0ICvnkP4bDo?%BzUY?FNA1>`k?=Jn`o zZ7X);B+6uQWE*;>bybUPlY9*CpiyYesF8pR0I&xeg*i3~PwFTz!=%H>Jh^R&(B$>0?r2902t@r7H5@k zjqmVTc$c1qXW%Tz@`;ZCYKcyhd~8~je5@0&5`ej7qSGWFdm3r5CCQ0SlYH#{nxoSs zAB(`}WPtp697S}Rk5?I>BqgHAk$3*YyB#w#R6IVtq(Oi1Jdaqc=H;r4u{Bqn9&jZnz%aKd;F8~sS zQA=D|7q!II;wXGH61^veSG9|4?b682$*D0(ETyAnOcF%vP18|=5lmo@L46O(+TIQ0 zlVtKm9(O9QDaW05#3zA1l@UrZB}`i@qm(#G*B-FshX66PR|2V;?No+?ku23i}DMC*XByNgJY(xME~ z8WEkfTpnf1aY;y-xJcZtjLXyLBut^T=UV-@rG%)RW0Kk1ak%JP-5 zNtB{8Hi^q|av%b=Mkf(Duw#@)C{em<5lWOsG5q7W20>ixRW3$}OV?IN9Xb>Ew=Ho> z^vPsf6SJ7>Yj(xToj*!^eM1j1xXL%ad`gN#}A%@ zB#o&-is~^nTzy)PU_{WJJ-e%KvtMnwwHqbC&ft)iwvLXubA40{+%wOv?aC1{$al!p zsjaOG7e2-q>PneXv$Tttp%PS!m_eF)M!|qzj){XI{h5u0;rLNrv?j9`FKOji7^KXP zd7(1p;dK99_>l(ljWO8MXcw*=rBfR1Vcf$XTVq~`{7PlxUX;^(+zY)Yh7A+<)Lqo} zG+k>0F2}%NF888b3=9{;-OVYLidf2(BVjm>%n`7WFw)u#hk75?!p=eAYhznz$r!OM zczvReUon3HBf|CIX`)gH^ta`T1!Fkc9GL(Q3!M!3*a$DLHt&x~-vw94ob zj?&GHYzzse^Dm<)Mg;TEJ?EVB&%fZ)mtOk0Tfgvy;}Ru8p9=Se5$%d=6C_N|yEvl> z;_4td{RY5zq<8o~snb1D|cR33wTRRSy5QK8(N7592TP!_5G!MLvvP{xJS> zKZ2Fad3Q$1|HS{>8J9$12R$19 zxQHLYRc$gFe~bn3Ba%dpx%_Ozg)~p{8F7JWdSZafrzCj0*YU&v zm4a`3l&OrqkaA=xas}Av3(7Hp?%YRTaP`TV0-Ed682R6vDd5w@o%`~$>v@@157ilv3sq9AC!u8fRsdTr_*5k^7a9>0r& z;5d-dP-i%3KT9v<$3jR;hcf8B)G*w}LQp#cU$@Gja)8Hl^X0 z%##~@M1<}>7ZbsiC5_UtEU&fIxXzD@kSSqnR1Sh=?b#{OCm6x2xV@(4;^+ufYtE4b zPaPuxFggNGmT;w64?$%`YiR{#VcIULi-1wKYX$W=KT?!}Q3s@0?NNi2i8ojy_m z`fyXW9XU0!Y#1-0qAo25OppCcyaac?hbuuUrPMYlmU&{MCS+(y=Ojs^Cb+XTv}GCo zGTVLZ1kFjN@_Y?~ko`klaQw&NOF?rX4yxOOPu zdO$1S=_vU_{FndXl>q#w|KTRU;V8N8e87!>i2$rWu0z@%jRb)1kB|oM^5l=e?~k4V z8~_{vycH$apAHxexZ#(0)K;FQCD9JKufQ_ z&Fl5AzQ^rkBv-d1Z6yFba`lq{wDjsjfVa_$=!t8v^C4$lB-dORxmDRUcR3s%+wR|0 zm!L)1o#Hy_syl#B1Ka{>u;Y+()-Jp_5co4?*4u5u;2Zo&-9g8lU|86=#_T?9tO+=bOAO1(7RV+=f&>+T{X=0 zW=*?)pBs&SdI9h{;Aegm4!w)ry?Ve1z(*k8?Z8-nbN&3e@wmPTa4W7cpFcOPX!q~a zd!yvi{_O7GA7F0$!9l}t80q(33r^BR=MNER8oae%b8wn$BFsW zIXgNNyO{SO)TgnFZH{Ym8YkHC$%*XCbnTrmvajZ8KK0D52A)h?mcm8$RoY73vgRoE zy-|+r>o~GiscxAm8re6^MOqBKvde=OivD@LR@oTsmyvyKnvLvh(^8L5@wbc}Bp2gWnxi-hvQcXv!Wk?@_<`EY~ z%4ME{tuyaBUpuU|gthCva?gvDt9goT8I>SkFI=rw%_FXil&f_qmDZy;Un6X(RZ7L0 zM-1($KN~oWl*?2LVX0zWu=3Rs)i7yoq};GZ-iKP?BK|^4jVX==_mOffKUUNcmlIk^eySyHG!Ke4^;TajvJ*Veld7|7y&p9fc4`ztRKf+4!8+`)$zEQfGz-ZMdR>Q9k(}1{<;(;cb^Kl z1b|ia-N?K9DZtMH4RiD9>}`wTh80QNrq(l?H#()2FAW zDkr2Qe}Fw%S<|!>x#7%!nJsd*GSh8Y<_}Y^l-^$JmqPB;z_YJJF6BC?Z;D7p?x{q) zCO=|;)kP~`i^VsEoIq`L(MolK`lf8(?$2IU?o!4|eH`@CcRU>>cf9BI(qF{*e-T=g zFJ20OUgV2C0BC9Mybu7*&7Js9yYtm3`Kz-4w*k5VDF0VKkCMAE$L_itfO&Nn(!Mkt zfV3~&47dw00nh}P19$@PJm6=)Y!8*&UyhR7UyG72oLsD%{=)gyb<Ra&^x)rg3%xNyi-9zP; z_oC#_PX~;y)KUNWrCvw<=i`xI0`vl&1RMms0ohIlpl5Hr5`bL-tE0a45!ahF>8Nj^ zw)6$S>wp3s^(~mYw>;!W>Xya0M!!%;ean8pOGP^BF?b68WNcPPeG{Ijn=p57nja;f z9|5>LaysfUmtZ}U>Zr%ugm)5V4`Iw5qNCO~jq^~!JK$HMqy96@PkN~Q*&MH<{xj;T z(PQt&L*>t)t5hBJpS^+W0v+`&3G&caw~RdA9x7wUM#)%=&R9IjV=>Ri_5k(*4g>HG z`_qqlE%l#Xg6kUq&44`sjQ5`&0f6S_QvqlD`T)gzr#OApDzh+twmG)`CGh)3g*4lRO>Tg zvGGs=b;d&l_wIY|^wnBM_0@V$>^xL}#T$j?++8nD3Q;=MSL;1-rM_BolT=^L6ytw_ zyHH>4D7=>ma{d2-c$vsODN-*Jrt#kZxP0<0@7%u#F`!PpOf(%OjF*X~5+f(nU}w0w z{}q1G3`^wE35G)JtIq{o+2#g#!B_xq^PdXIm!9|O_--w}4%Yd`^ zj<6k+qsnQklsl_ccP){UR;#WpENj)7lCM=)+B~dUb(>e=A;S7G0x6C5tdq9FLnM{9 zd@`z*Oye#J4b!o2SN0Imbgj*eyPlFt>KqRdEki8j$~t#fGjjy2&fTT4ErvtjA)+P0 z*J|Fig!2#q&9JidxcY}6HTjEij(0fI#A3X$F|ZhSa|ZK8W!0y}d5C~trM_O}2=(<$ zucohO{_mV~&gjwf5&45ZIDS4N<_U1mEbd(^*eX6fx80uc6Y>A(u(GfbL;iS_|7%h| zkw3mTO8$5Z-~m9p|L6H*{7c?26oCK78!iG|2Y4__{x@iE!yoTo-Vh}>9*j~yk^h7L z&%d02wZH{Y{t2V5Cyk~3aq$qj{UNNGH>9h|U#f>l!HN{$w1$SpMtY^=gwf>oo3Yl* zu1TwSh}5$F`pf=bj)%zYJYAG<>?e#G4-h^Np$7=k)Q5uDczN*|_WmEBDSV1KTQINj zhu+v&;r-#BWub6$i?zvn(|Kp$KF2$QQ~_kXGc-@%k9?-mT{D)<_0C`^dC!HrX0A4o zi`ULO132~0U|9m+fa;wg_vBf*gO+k6m2l2@X9&mg4jN174w@@16m_9@2I*us&DLVP zGgy*!O8*4j8Jeq@RG>EA8OSN`tg(*DowZa#)}x#Z79R|zuzc=`lzHWx+$dpp)|Afq zU?9)#tZAOb6+Rf0B9v2FU2T6Y<;k)k7@k#pFi53fCD3b;LZ!>!WveQOazZTyJ{VfR zVr_}c4qJDQ4+cwVi4bcZaIO!A)~IwUtF{{H`8#e^TddrGWo4H2!C<}xm6~Z%bMd}g z)tZ%)VsH$6Fv5DJ&T#jwuolp#dtzlD49k_*rhc}lcn_{xJv#2POP2M)7^Fs)4R_)y z>QYI83w$taEw)X(W}b|e-H)rN#YvLmgJF3qFJSS(kX-S>kbK>nb9E>MPVI%4hESZ4 z=Yt`6wiK_!eLAMueY%uhTZ??>gF(E0y<3$zj|==gI(uT`$7n|cbY~V zm+&V=-0k_{JGE{zqbvwd=KVHKCwpuK&mmsb-K|l;)~)O1DUkTP$T{ndF^_k-^HzCk zP4WQ#Rv(xNm;*p-9zb0W>;t^y@mGfnzF07{reAFUv;#o<)yE|rcsyvo3eD^U;0dP! zpp~6)EnqAFTHFZ_0Z_+;m4L^i)4lC>OUq)7If!UQY>BqRwqo<WXox7G{2Hn>I zSO{1XecX>K;w!k-0M5vpHe&|Yt&|cc0?p2z&(_toVg*jn=9%a2T*d*OZM1dQt|+;8 z900v>FUIy>%$j?90GMU>J`FescmwdRpLOFu3XC~1{w4s*jlUm&UL4;n_w#|fz21NP z23+sxk62MJd%lT&tXCPz$kFCDd-=Vlx^U*`dknJm@8rxPwL(ja zyeZw=vDDyVENQMQIi+bcEZda6)Id9JxkIlqic)&-=zF(e?35yL8f@Nq{*!m{T=Fy* z>G-3dtVtNH{l*OL?@pImH>r8^j$Ni*q?|f+)}oYK+${ajx7F6@VhL%D^&7YD#F6v- z9;gh0@s)G&m^7WT*ZbH&hzz8u#LS5|%N&r=bUUWVi?@1dhrkQDX=dAY7yTxvi9F&} zcsiKww6ZDJrgoPaBYu?2^_Im_J{GCtrOQ0k4!k><*SBe)Jg4IRjV`smp`od1#*7uK zJ&o}2Tqn_bQc~y{iRd-L+l`pgmZo>FPv>qtb+#{4nr!AD-mVghhWxa&>!G#2hw3L! zhAqs3U1bTCs;pB~SrpeznzXKOi!Yz1t?22s{}ir{9{;>LdtFNH?R8atMv6(>>1=e7 z6ZiT4i4hfnyq%RTaHZ}*Yqr?g+9I|2GUxSj@dW?T{$=lTGXYw z08Mv1s0(nE?ruucS~Kgq*7eI+Q)0wmU`bu!D;Jj*tngi4snLu#clH+0QWhLkcD$D! ztLWQqPZO{7PvwyIjyY@AuirGVZAaQ3TeH}|f-6(&I~Ockv1;{N|L`2HowBrRKLRE9rJaCljgD~-3mu3hR$EmwU+;v zJ9bEGQof`Wh!NR>*U&jNO>LRCV0W66QqbZM6kN$LZo9WO0mcf3_ldXBV?=g{sEW_$WQ|fiqlBQ^mu2=M)nClgXv0fog{AxvNd*3USNAVB$DE_b>#kb^9 z=;a?h05}48&*Q(r{~GWA=6b>R;JO)ra({zzfAfT-13!Et?q9~gNd&;(Sm|8A#emBJ zHvw)1Oa$ORzqD9S5)W4@{{ODLO7UxyZ%>GlZ=>wD7Xt9F`E9(hzr7dm9N-|}HNcwy z%8mc+M^6Kw{zoqWp#Dd10Ne_|KlY<&!=ugNx@6)@Q8Mx8QSz;!fRm%-n`p_mMnY1z zE}8fYat}lwT!1K&i;7nz$v45_n~-H9xJ(3>iI8C;`d}jZZzB3&B4n6&H{c<_qks-T zFW`ynisYO7zz1!k6y*2KH!D{pUq>H&{ZN!Vv=Z<*;7I`fh`)h9V#fXbdaGTLe0@#C z({u^R1hmGjNOY#1;8!H&^~g6TqE3v{H!;@VgpA+Z1lS4K6P;Q6T7P)>f=ALXzDaOD{n4JCf_DEt_bZ(+vj+j;`tmJ{%W znt=EF*YLLd+G&7MfXe`QvwiIrz#V}5qvS!nLBECf*dtft8fCtIDXx+Kb-c0GuB8ss z@0~&(?wvY~AvH@)O|*w;Lrm7JHi;Url`Hv0Rvq5AFUOY_?^1j#qp{loPXe9?90D8x zym!J#Ea@9%z!~nRR>F7>gk~zjp7A!Wl-Iy6MyXJmc;(#}D9lr16{^-%ZW4 zxX$}-rsZ5&tR#v3N>Zu)N>cCqt}>rL`eLT3Gtf6I=~j=Lnz+@Y-f{KFYh68RIx#&g ziD9p5-UGP9dQs`{4SLKxi&!PPl2|1Y+f|~LuvqtUeJ_<)iI#@fTqQaT4@hENC0aUI z`f-)$@-SZ*usXCk_8Plyer4#^g*L}t!?VY)39%xy>3WS_8C?zL<|l3) zsMN4_<;rf}yb4XoQ52m4`pJ!q zo?1?c;?XYWROB>H;c55F-9D_}h26Ay^T0NL)(3W5O)250e2*5N97k!{A z?rGn_G|`s|#rxKm&i;9n%zP6@&C;Cf0ay(=+$gw5@IK%p0F;}Ha&yo0 z>BKDqxW58$2jFhNGyt?*bC&|Jewzz@+uVbILx6XWPG8#b9R4g&w&R^BnSC-~B;YK- zg@8)|SkcVJx^Xt-o;@D$AOQ8xZU>AFvnj zG~jsvdZ+D80D8E61mJAIrO`0jckI|;AR)S6@FL%8n*EcIH}nfH4wEBZL2WtBeHHv+NKvJ$(v zeW$3FRVdYtBU7TG(Z4^umQ^T4%c|wXj>DGob{v{QI}TSr>^K~zmX&f)%L*)7)|9)` zvMP76;2@oX)3W+<)Us+huVvLcuVqc|oR(GZyp~n&oR$^Wsg_mJ$+tqwYVx#R#ZJqL ze9^KBrPH$F+G$yt>$R+sidO3?KBOFuJrpVLdJ9x|Lwipx-+wGC6i!ErYp0_n7XBF> zDQTe{I0hYQM-#rj_%7o6c-(ZP<~ut~zq5K)C2AXw+HS^|Rlc;)n%b{zg$A|g`!?&z zUycT~1M(a{uON&}JvFEsw@`;F=d?Vyc3K|bjFv}eY@0>PBRNLP6VN*SD$<;m2RPO87`jx; zW7Aa2W6}aGkIAu;1^U$js*IK=hbE)t$;lTjkK`CFPe3bL9!bq;c>+qdA*1EV$#+^F z(pfD}4xMOuB*$raaGh#-ObMsu!F@){WAe3Uot6jbM#~dWIV}&;lG64acvs6hu^y2P zc%EK4MYTK__4f4}kZ$xP5>-IT!ds(}tI_2vwr$U>Rz**wbr55pvb|gfq?|$>PB}$s z>q;H7m+@V1YULS~k1fxp;csSYxpY$6&}Z+g)(Sh5jpaQ2O-|khtI#a}Rj>k+G?ATj zX_~Z`e(r15_Te=6YNGJds|RixR-lC;#U|R_?}E+d1v1O zJy*biG6!4`%L10?>v};M?hKGo^7h63(MJi&Kl_l~P=yRA>DaEkV_vJ^wmuhjKdyni!Nx~I(S$db_{?GVS zx@Um@XQteV=pnv0*^+tl7c8v!$_H~n<*LKn37?LmvSiv{ijw`)0PTSJfG)rWz%u~o zZ}-0$CC@_l_$;)9&q7Q1?D>Gp0MLv+2R-9+O99YV{?jl3^8V>o_~!aAYqQrgw{rI> z=!=5ZuvJ5Pde*O}z4%UQZ#waFICEHF1+ze<1JRK$5>j5_cP<}h+y zMai1W0XG4j1pM4-z>`&P;jNW=J$K_d=|V1{8)NHz4EW3goG%UVIi%+v;V<)avGr&* zBe$-kz3cp5Bd;Bc>Vt49l5pV)QQMvi7CQ$gOK%hs0R8=0$FW zUH6B)F9y~k&eI+L%X2$bOW}O;)k|aTZQy?o;8FkNA8q8;wM{5H2e3TCzj>FpJX+=L zjga~g{~WEoR4_*WAl^p@@s#{vbX1R(I{rxDWgZ_q9dIV#B9y|Lh@K#r_nAFP+`I3o z!O#=7%ijf3Y5CF&FHQGFCKbNU;u|7m(p^i#gWl)<`@B_Z^>;3EtCrJUOH(c>sh}>%PMIN`JG3nHHn8>XrC;hWR$@(d(H>03@iSrfSx6cV|WWnA9>-`m*-Yf)Y4zR%mo0}@13Mj6L(j4^Upb{lV&EQ8I;Ck^RXbhq;NW6wYMM0yCL39Wo z2RLG)=nz0OmSx@Fv-ev4?(VnW11ioRt5)x|*Is+~?%iMO>0Yad+=?XiHreb-udK`2UUff~?=jt=7(Gx+QX}>fM%RS=&Z>5}w&}3-7yk@OOWq ztf7{$Ao2w%1LCj=U zSV9+%Xfw{L_u##Sqg2FMrB;#iemIQ}BttBO;;8$KSi1zBm&JriaaO&zgjeFMdQ0q< z;;dSW@b47cNsPw(@ApWn(iyNU^scqx6h^}u(K_M!P>HoFX)#`#=YZy8ttQT@jiV*b zDstVEXZFmxV|Kv)o9C?0*+6AX$Wy!-9uDzzyQP!&o~yIZHBM=p_b-mn)Fe*n!jD_t!1{?(x+iZN z3orWAUnF$=iRaWYBeIUShPD3FwQ$?s{31c?sT!wLYtL5zd{F!@;f_1!&5P$i{5nBe z{hbA}z?vV>{8Hf&MNtXofz`E~5Bh2WyRETC3QhHDREksTa=*T?Qj<8P)Yir+RV!QP zEpbY{&g#P#56C<=iH|~8$0AOt+Gqr{0rkhpFF)~oT|>=Ei6bk;DOGDIiBqcn{5uJ& zl}1aP(jc1_vi^l}S#QFVe;lHj6jGZXU2W(7pI_ja3!Z=3PDg0_ki;oPBZ*T=sU}XT ztW+%}W&8HRwA#ceP4r76LSBkfYI@=O47N*gN^5Mi#3`-O@gvu7oKkP6*{YJ)!TX6* zDlMmU&VAeF-uJ#uoKo+rItDLW4{hRReefnJDcx*;*`2|Z`B`1mvc*hBlh%!_%$v4${Ky@KaQJb_T2iw z{3qfU0PT7~UK6KO+9~;%B*Xe3?$SRr`;Y$Wi4f(nauxCx&ec-e@Y*<~X>YD;`hMoL z#3@bnT-SJ;IHhSX(yX-do=R~_tG&>M_agt+C`9ln?4wcA%mR%3BWRieK5_9$r= zqxgi`566*Af=L{oq9?PS9;KEzrC8OsQ`g^cQ;6(S==xq$AHGk5cSiKbv7dp>clv<) zP%hy!tAW^ z!pey3ywJxsZ^m8(O<+1`Qisz<9EkHS3;mTzgwR*UK$Er3|#}^t$gW~tno6k zm+`>AjNZ%0US0-a@8u6c9~%(f&y|Nm<00NdR$iTrDW1-oe+BA$Ce55hCr$nb6#mE` zb=Bxae4C^%283@X@nM&5${Nex${H&MwMTVU;ER15@B7>M_uu|7_#8X7k`rtzUs7&m zq$`+(73V`&LG0;@8={|f1?Z(vofS_)yk)OoMpkTx*wYvAAHRVA_yuO-h4VmdE{bT* z3ztNn<_kTspHG*EZ#iD%<#>zrCbIk{_-@dg<)9}*bC!eR2+di(v=z-+&Ympi?dEer zb2>INOV6!>-pv}%GrN6*;|%mM_P)cAG223Oo@d6M7rz$jf#yMrpckPv5VO0SHYu93 z{G?!OkI4za^xDLm8`szK$ah^ULJ7b`6(e@|6aXQw1hjwQ}oU2b?UWel>-4xHDryItH zg4D21`p0pWu8BAfE53x|*x69rZz(4@PAGxn#QU;JF}jzvDi9nihx2MG2u^4h5FD$q z|IWOfBREOB&h8s}?u-$>bO-i3vMe=o@2P}G>+zz#1;LR$?*Xq#fEk>hyC+o#~b9sW%peg_F4E+J7R@NdxXM#pRXPO#lm2esBufSzW zmdI{Xv`i2gbiyBYaD5YO-#}5S!D147KEecxsnm9M|B&x~?^K*1pEuKBee$iZq9vDV zs4ZbJ(uVrQVob+pl-Q~I#(M6(JO^W4wdvg3IQD6xFwJ_mgieCLAPx8nJi%Wmwcszv z+Tt(N`3Q?W_HhMU75oL6yh8drFg{J|o5`M{v>W6_z1f~Rx43OKjs$H{PZ4dgR{f$a z=v2@av#5SbXp31(&=w?Z&=%8eIaS}h%Au^Egb zOb`}pBW%5TRpI>k$xrU(zecwUZ*&)^3MC@xMpQ-d<&qx!C?|M|Y$Q~|QzWmn&b#l4 zQRiHaP6&9y%2fEc%0`XS(VmU?P-jFcH&g!9>vjW;HH z73z%f#)Pb-HH<6qCd*FuO*3z~^`{(P?hTp&p9SMB-eg%z^ny1Tnf*U!eKmeO(|bm@ z#)IruoTF9pAiJIJS>Z3ccup1`WUJMlg+J}!MRqII+1Mrfu_Br!GOeTFFV;UkiQM-o z@f1^=c#0|2c#37AY9%R~r`WXGc#0E!AG!0Ar`Ys@r=fZ;^7ZgAa@`;(B@%DCvoSKd9EpTO}>p zc!XWUTcq6U;CN4C%(*zrkMOU#YE$x-)~X+0uxS*>!&}yIbS;v(e8H_fQs3eQZf8I0 z#wd3&TUFU!+K%mh{J*JYI%=203xD(M**Zp#EbO;0%|(mn*R6REUWS`@dFITY5~WJ( z-mfXraXq#3ZQ~`Muh+SKcvsWstN49xL7EAfx7Q@$A5*pqKX0NL{xPM@^JN;vuZ`Un z-!3gnzFoJRv=6>r)#5K<{RaEe+^kXtZ&B z2BAE~IQQZ$k3+QELc1+nA?d?cADK1Y91QU${w7~CzBw7fFYzW{SiX53G#$DR;;sM9 z=Ra9=qQ2Q#qmQ^a@Vs2j3 z+|0`MLQMBp@6H;p&W9F3FG8yzj_a!&*H=GgJ+YQn9~#%y>XYG@K^&#k?CI)mh<#W+ z%gXcM4?)cL>L(#)ZZ$Kvn)zPM%&q>2Q8VAK9R-brCZsWkUS(EZod(?m{WQjOfAz|0 zw4qmrQF|oBSYG`aGzq$xr?~EzJ8D%Ql4Z$+E7swvqpJ4&l+XrpcS)5nIvS5VmoAw5+~Y_v_jS>>BOv2 z+6pCkal9`^74t=TEnLxtq9&Q53QZzXC`Xj*#T-#ZNzsOix|kix>J)8AH6CrK&_Y&? zHk8&?w?kei*$gq=y*6ZoLaJy(K^AjCNiXQ~gJLl*#dMc6WPuVV+E6It2@&^bL!qTw zi(>vKD~0?|+K&03Tqov#vQjhJP|1#JLriy0!y<+*bsC)$w8X|$oV zoo_4JP-urgA#gki;$8ZdY|aDoA72!nj=9T8>UTTmLN}*P|4B(6y$R9|_H5;Z{7}d` zlpji5c~h_&aMZww2Pm$1fa)#gPhm@?A|9ZXgUsUrCNhf$Xp-g~SNbXW9XFNfj;nHr z2MD)#fY$Oe-*G`18XLJzZ{#|?@gC@LXa%%B@=aVpRNge&_(Zm^fM~agcAGe^p&q`D zYw@NfP%p$hZypF83>^+}mD_wObTP!0bMv*I?2g-ee%9!vZSOS@{q%CB?VSfLgcd{3 zLn|T1-Mbaq$++l$<4}nHH;#c$h0cK3hmBWM@3_5a^`g~_Rxer`j)0>X@3_4~C>^}} zJMM;4XgLa+0G$hc2bu!SfS9ihcR>$8%=3n)pjRM`H_J*H9XAX@ejvmsg1zHg@3m`o zWsN@^3H3oAXN|R85PPte)iQT()>!jWdaqsc$E@)>8iClGh=$oZYPr|0XHM5Ig;qd} zas77aL&nnB8~56E16eHxLq|c(*t&5Lv$gJ9&=nA?Yu$8cCUg(<60{m(PuDS9>o~gW z8?n5eBfNe%#7wOp1sxBKht7vChQ0$$fqJ0X(8BayyOvp5yAApPYgxS4u3b~T*RJhG zgR!h-ENkaOi=buAd+pluD1Q$Ev(vqH?b+d8n=!lTy;kKag~)!$Lu5a=AuOip_u8~o z_(w*XF|wa&8p7i39AUAt+FN8llZ42AZ0laDTHR{{S7bkFhkLEIVksadR`PqT*NTV8 zezBb}5^onH`*|rw_A5#uvY(gYzbRG_;1m?B~|?6(-vu zvY%>WWIwCrjMx7muFJhP=qi7T+9$Tz`vY$Bj+EAW5H*!VxL!RDi({{ccBKxVmeD~t=+KUUqWC3pi{fXJkUxd(;JJpI=h|v5XNv3gEC@Y>czkLj z|E;*bWQLdg&DJIzQ4xPFsSEMfC|mqBtFicNRto-O>BRVJE>-+BNn`vqlUn>W*O6zK z?ZPW;a>;^M7!De&{1#S2N#5Y16ymR0Da2o6JH%gum*TIPj<*yy&#u)Z@z*N4A^sY& z;I)NwO$b>KQ(ItgF~3F9w#aXh$SU#IlA6?7CH`6)ty2888XY`7&HNTM^%j54YCxeq zzePotIZxKE#aH{6S;}8g(Nx*$W0d`x`VfCjdj3tM{9`qG<{Pt`;2UGR@Qo!cf^Up+ zDgIhg@76>7HRPT8$}xW9SkVeTFl6ysQar0GODoUj&1;F*6g=c&@{(UmyezJ3N#NvS z3i6nlm6}-6wIpmwmw$G(?bi~Qi#IW{R2sBB53Ac052%=H>RO_0T}y&2W?*&wkQb-W zyZkhFO% zDd}h=%BU(%)EsfYmZW-qEh))7mnv;sUcQ#Nw93oZl4`A&(`$*#Ql4H*QhBi*bEewp zn%9z|-p3uYrCKSymb7T1lU_^e>UAxVJiV6G>BVb_*XUZJZNHYdTwK=@@$_1f*86tI zgo{+64g(w zym#aJVxhSo`ZG!Yfm-yzN-y44QO)K*D8!PMNsm67!T6i`to}wtT%2|LoVkkgWqB%U zw7pdw*LUQtYw4c2#NQHZ&mqs^_NdD;jQyhn){@uPb$~f7&p$)xAfIGtm%AP#5&CeeKoq% z2(r39R9BMXFjV6rc6HCYcm9J9|56b`TaTvqHh^`hy;t6vs@3YgbrQL-wQp$+;`-D) zJM_hW^$J$Cm6rLwi+E^=wp?3Hrxe>QXyN9gHI2{gqy6CQ ztntBR5T3CQu7bF;eZVv12M-%xWgP#UAmgHhqN08Fcr>J|R;;H>fIQy}`;PCwgOkK50HE{tB`ZGBm16M^0Kah46|Oo1BjEOf81t=tx` z@OvE5_pXGdK#cLd+0cE^!+XOkyyLN~v12K;5@N=7;OX7LUhEtQ9Sm_5-8mLI6*?EX z2AT@7o_8`^J6T&hSzDpZ`r66*+R04qTm`L#wm}~=+AfHhdGAQ*G>G;3-X*D5c*jra z`EF<)^icE)@0eco3hx+0Eo0fiSaw_pT@GEP6%rBH?H^G-3_9vl|NY-@M%V4{?#;jd zIp!r_wXFeN^PGaOnsV?}!_8N18ilVqZ2>N<*5<3W8uL|qJNH#5?aWtglHjXmJNT-_ z<*OE#uNrQ?YPMo2_^Pc`_^PcO+9}s}Y$so}w~M}NFGXK>&jOxUHPiT<*OE#uNq$Xs@Yaq zWWH)E1z)wK@k@8tiLr*Pl=!MmQrHT(u$Ky7b)pq~)s%y;T72%@Fp7|chH}YQowReC z!B?$z@>Pq=S1m4IHQapFYz3)&)uDDy-3R6M;_ibg$vmHk^`N@44=UA8x63}Lv?kq7eNd^~w^JXK z%TjLsY#UwE2bJn*+x*$4m-?WpnkuJ0sJi;#&z4^5&oXW?h4bU^>RK>2>`(FP&??ZI|TW%#0Z5uuQr}$aZ zg5LY9`_f4S@74(Pnhmb4$_vVt_C4=@h*#jIEy?t>d)Lq6n>t>LWQID)Kks_x;>3a`={u_dpnJl$Eo{KoYVg2Wr&>{%^pjcqIT1huaGL=m%KOfHTyXl z{w1y3gUZq2Z=GWAb;WLXji~lFD4c({@sE$6f4errFmAptrjq=Y_a}Q}n^G^?vnaVvUahMMHUc@}aq451M7)L1%lQ0jfcV5I{ zO4=83m|P}1x_MlGz4C9weq<}L*BL$9dIIzst8K}=;Z_eMl7Ps|@V1#Zq~m(ttM?hH;$VxDs8-*qdRK;A{17q%t|gzKWdh`9WwL#CNfM z%taq_p}Fg0uKKKd&y<%V*xdMTmTlY>?Qi@z%Ma{?4u|M>)8r`MM4y{3 zN5(id&4ynEO@|gjFG8%S16ffAG4}@@37rjHmSvk6|K_!E?+=<9_?|>^$`81fS^S7` z4TXl=*p6VES>4F2Zv0x7AMh~z(rEjDrEFt=BggrGl~7-sNKW~_i?e(XZ(#Rd1u>)d zb54BWCWuw>g>6|rn7tg#U;p?7^L=Mzx=R0mPsOgM#MkoMFUYd>E8`5TXSJ^1lI27D;Je^kvyAWa^PwNYPlC>fdK)feo0YubYG}I2X0kmC zng^|bUWa-ij{b&^n6V+uIPLk{AU}Zh%9)k*UI}p|wDPp3dzq&LE`~nSd05V2C+ugeHZ#Z+bbc>AnQxllA)ac>zIY19YG^-C@L+#`}j_Q;T{t*3v&|$It z{L`{*{zQnL=g)vxEwVeGBTOEXZ2oro=z>T;vMWJ;*n3fv* z;4NA9^9j&(5aW+mDE=+T9zf#(R?h=F(IQTkzVcx8m#`Z)^GKpH%PUJvleIMSe1A z_=c|MPT?-9m(*t4zA-BFitHS&XSzicDANqb!?Sa^E*v~HX6JAj{a7q0YiZdzR3GX> zL@2APM1=CbDm;k@<-HhBB0{N6(k_VzmDbP>?_5O8TpL+SL?~~Q==c$6$tyZ9w0!Y0;rfT11CZ*<`iRp{&kFn~uh1MRtzFmcGQif58)l?Rcz0 zj3~2M6C=vod!K2UZDu;==Fkj@hE8U$LL^yh5hFZt71{rkVx^YiMO7@yN)j*1tOVPk zKl3iS9B%QVOj7-J6Pz;9bvr39;zeovrrVO8Lv=dxt|L9ujbCVn>>R!}OsmMwk&K}D zHq$M^_eryJxZHcw>WOir%!+@NY1ugv+hKIpE8h&-A-jE zc;r{Vd9v8|a8wyVj+f|efBV&uhPq;|0?*VT8~bqI6c@2lL|h-z>>MU7w6u3nz(Q%& z**!0QjTc9d?0XT3%38>R?#V@V4wpNpzN?vQL$REN*}6sFru;>Ju8q$CpDN2nelX9C z2e0C-Wl4Nr`V&uQdSCj}F1}zwK6w-L7BZgl-x`!<7x3hA0reLg8NV^P;AG?DkxhZ_ zfjABqJOjN#JLY^h?^?u3O5e3S@+jk)${Wk$jBPA5E?i5`qCAlm8~+G1DdNl=HQ@Z%lei@R`h^s-VLpC zt5c7GWETqPzDCh~V;UdLuLiDdyp(st>s%LW7AZ}(sVzlHv;K;{Lp=b%+=m`spnsCA zP2jd2z6?OG$h(pBSmfQ1Oe3I;zSA|7O&D8hQCccPMbtE}r_Sg&J<(D413iHzM|d&p{hr zL{m%Z!*>i=EFnWReYfP@sL}Bw*EXhF(yt%C5>IUQlXpW}PF0JN+uZwXw27?deaS){ zSr2XUZg~IB-GZ%-wC|euYW?-?b@1A}8{VVq`3(48BX1LBEp6fBb?$X=d&8JzvFsGx zu{qz;bKOeM{lr>JTX>J{IJ%r$Y2FR*)2)cJw?g4dc{jYiY8iPE2Q5ZiyYH8~-J>>f z*L)ckmeVt=c%e$cx^~E3TRHEB_hi=7UW?dlK2mJx8>1rchWFw& zD2MNOq*u+lE?kKiZk`XVg!Win8Xd4edldK0>I<~TWymYp)}`qrE$cDCe7shi+7`^m zZ7UCn$jk7yn2&T^&+L{);dam|VLqv@wKvSiY6{H9t-~vrkK1-zrnwg|pRp^moTo5l zThCAAF3wX}ej*<26Y*Z2_%QTAmY;Mogs1W(JnSdEmE~U<1zifU7QaIKui&jb8IRt{ z--YHu$o^pngzO(KhQ0$$fo4GX^8Vo&=ym9W&l~eOzAwv<-PweNWQ zThLVK9_UHx#=_S_TcOsx9Qg_3&|z;+V1`b(0lGWH-Oo?J*GOKD{Djq6$M3dh9nW>L z&Fq}OjEx-(9RZyLoeMF0WBD@QvaRQ1d%{@qu}kBaK2?5>{8&bF?2?e5BR_V_Zu4{G z$G#i#bL7Vj4EZ_ozROSeoU>tb*Rn@-eKtN`8)f z%+QdZBOikoeawXr??Pklh894qn=u^GG20pAaEK$9i6eGSL@^j?JfYTh)E9rJgK5>e^C%j{M7) zW%-vMf|g|Y2-d`iZ%0(;OPBIIT%bB%x+d%RcRn72@-N-s|DNcahXSetAL(zudkNL) z=$)H&^ssx$K1EFa0y895Jn3VH?N>M)A4brfgo zD6)=_Z9N}#Da08&itF7d&gfB`(MKN$p>y=95NC8Kb5xI>60)u5M>FE1Z!NN|=SR<_ zybS7%SBs=S&~TRe9v3mTc?!NUpFWudL0| zk&irT&+(iQD_ECYl}B(!=y-mDEFFz6j;7sC#=%+{IkXPX8F53fnvZzE_~Uz!r6V8F z9q}C2eF@K@T-!*dGDA=|pQb37+$m*6?- z&-;|6X08sEnz=eC6?jh4#&UJYHqrvmv9k8Lz;h(ia{)ZTa}v#R4ebg%$F-5Q;5ptV(eWeDg6E`T(kv%!D|k-T zn#!7!X0~-~1w03yWc#30;5lv`SuLJZ*GJMOoLALs>%o4KZJlyFRz=PaBsF-B+x0%v zGTWWaZ0ocS?^Uu)?%*W1Ii^{I=eUhF zyufqJp89IRb5y4z?>e$&_7XhD*M?~ocuvxDf#N<8M~Jluf2^@xn{8b>o$rR;J=1!+Mzl^Ucn*?~Wm+w* z2hDT9b0{Zxj>hKWgBN&CA}`@NE_aT#eTblN`yKig9B;FFt9(=2Hn+NT<&Vdf`x5pF z>T~=xybmra-k3hm-0JP#wm2UCwl!l0qv7eT^1jtRxB4EvTm1cFpBmTcFSmMr{Geb>LvDbAe|#*>^Ier~m7!;!^AFJL^#3XCV|vA}pF(+Fr+!FXiJEjmY5U_4$= zU6Na!Qi1WPl~IB5s4v^&0^^a6SxYb;mzs73B z)2hLEd=A?10^>>Q1IB~J62?>0cMHZ-qvJ=eEyk1dTdWMpoD!S;U_8=ts#=uX=H8EC z8;r;M^1iFwdT4|3c>m75wXKe{?;4D!zrMW=UW@T~kFMu4;Cqd{4aSqU@bNnLI(RL{ zqxzK6cGh!07>`@`R{e2wD;Q6;UzO>z1>#2nCRC_^}w;=!Tx|v%&wXJR0f*ZzTwTAIn zeSz^%g#sg3O=}~RRm||wbKRuMY z@M@3{d-4B!D*P{(bEdLq0CIx?9{Qu^!r}Oi#WBwOzt}yguQE`h#R=QRuvf0{R0V`CozljAxAt{TaU) zREP6t{PS?`2%iQ08NZg<#>S>G%pOO%9r|-7=c>@3Gf&&w=+EibWcleFozw4uzl}s=R?;)^Y#?|IsG(7JFyl0IsGE!ob6-{$?cDx za7|fzAMzvj9Q_%`*)?u8#FgaJpg-fb(_aP+$!h-Q88PF&5~LWO_D$C+JV28MGb!aXBp#^v9**)U=>KX}ygn zpg)Pcg8n2m#ghvyYtSEQLM8M^GRDyc{c+pa3r|ET_d0kj`lEU$wM+C}o}fR}Cg_jr z+H5E2PtYsSAJ>z8bW7-u>YxJsaos4JHcijGAGJyLT-zb~27hDx^3lh_c=YsN zyy@W2OfVo?8wO-{`o)0IsbD~AWi3k>kjWAZ2uT|Z$aLLK$_orA(P_beRHx(bIzAhe zYcL?wDq%o{%;K%PC3pz~a=G^wj#ZHxp4u7=$lHipy95K0G@%j(l(y79QLbP>-V(bd z49Hpr42bQ4@gIjf?wmKz|KgEGzAMDx|e%SfF@< zgX$cJ|N2O$-C1Cm4^O4jrrmgB-MQeXkgSOOd{A6Z$~CBvYbLye3c1{`FIY@aA!=(; zA+@qK-hv8woz(|a2w8y&sa~Wj$d70C+-ZKXaHXP64JzaoougGkh0J1t3Lz;_A*)rN zEvQhCP5V)Z&@Vk3bAk%F)aIvx3VE$_X<;Klg{VnTAxbrjilYDkSZcd`yyIy&qIa8m^skm&0pOA=RhkZ6&ig zY(a%o=X&B^hPOe5q~YW(lUCkS2^I2s*N4}lLT=Z&M$NXNLMAm-NG0kERLI*%KcYgW zF`y0=vbthVtaS@2guH|bnVz42Y9CM`_}FaUL4)_(Z^+*ral{w@{`miP>bTP{{vVh8 z^FLpD>HoaufBo;JOP_xFnH4X*@ZyWV``t?~z5MdZe}Cnb-~WEqs#jlKz52D+UVr^R z{$tIWKm1|s+I8#Juivntw|C>lO`A4v?)%eQZ@sB0pq2-xv+f z8V7%zb?o3<_8olFzGHN#>-aZ(%GZs6hU32iDHwTJ)-i&pLl5$|_w2WzyRbbh%g#QP z|Cbrl@sG#yVLV|U!vE02JE6fbi#FpsIC^hyzWFYYtB|>S&fK~8+%s=p$kQ|bA;oo7 zE}8|8KKg6&yjAjtGW~HR!ZGS1 z2EYveSKFkqChJ;4S#Jh-_ld?hPyZBJE6F;#yF~AmRf45wT5`8wU$~+to2Z9 zmt|RYmp{Awae;MNR#+BT7Fd>L<)7do9FE5jO9?TA5JL>LmJ-7;lv+#e@AI9R`+4Vm z_T6O>O|Rd3UEk||X6BxI?wM!)Ju~;rJL50E^5|z~{Lvr((c_=_@?Sps=YRI)N5A}; zuT1~)jIaFBXQn>*<>Wu#DN6b##mS(%`y~2(;$w~^BLhu}iu?4vqTdIu{HgvQyy`<& ze|W%02LALlA070u!5_c&XRiC%AwM_t6W4!o*r#sz^zfg*@fSvXX5?o_eeR}Ty!pS~ z^51X${OB*-_Di?_@|Z7<{grXQddIJg|Mfe6W5RFV^;;8v`|jVF^t<=`-sIoE_Ydy- z!~4H9<;xHJkEwt3;2%HqClCMWv_E^~&!_*zjITWUmyi9`6zjNZd zuYB+1_h0?NsegFwA7B5c)Bk+thj0Ao?Eic7$LId#{J*~SZ*Twmh5vZxKNCu4=+N(f z|J7H2@PlHCX7QvxNgY@ZKAP;`f9TNHzkcM%%P)WHTgQ%l``h37&WRJ>{q8HTeD8ZF zPx?5gPygsgXV3ol$K!sdPjcPhBx(O)ak2~S2ZzBa@D}LzMsYF}+zf65K_#+ z2TAJ;xcO{xQUm(&d;*#zMM?ku_0U1+*n3?R^WEw*fqWbRZ-J~nKc9U1(<4TV969Rq zU--fo@BPx3zC3gP{;z)Zz>8n|no8-Vm;O$rf8-nAIC}J(-?S1te!Nhb@hX1k%Wcw~ z#fjm}hZ6T(`@tkRd{vT&Cb#xUuK)X@kEC7lOVZ`e1E1WdHb71NgL0Df2mJ$4;W6qmFv-? z->Y0t{#bD$D9564j;|Y%pW}oa-G<+^!NqBg@53GEcslMf&;kyGu(Qycf38n52|NHE z1NGqkp?#7^KhY<76%=2e%W*r;*M723G8ud-8TI-1Dz7aAlVtiwc(VgM9nlwES0%}E z&v^M&C52yTTBX-tw4pcHp4=mdvD*ahgAEBYi;z$2g(tOpPG>ywmxpilA! z7;$Bvq`4_cHiHv9kNYY3z<)(eetdlXdwoA@asz2R`0HJ3@_hV$@-_Lsk@-1(KWcIX zX-xcV*P8qoe(!fpo_5XqUy~P;#=RfyT9X^_Q%$~c@Z3at~eRHm-h@TPXqVyKEV#~U-2%R zc~9{ye^J~yc*WwLQf45p3N0Wq9O^aPTON*P6@Kl@qDyuL8zi}(J){a^ahlqp}H`PYB@?&h7R{^_(n0)F_$8=8CaA@JjK z=WhPRBoWF#Rg_27;>}MjLp++3ikkb5CySC+YP)Lu(LihPyJ2`yG8M>w4{p)LxSPRY z+-Je)zb#501PYrEJq%s}Q+}l=c@sLMq$oKFic9Gsz}>ec$q}epOfu5DOJ^esoc<+d zQDsF*zuS}Kvnn~2*!x^wDxbJ4vSsu5z4>L+iF+?N3#@EL{y~1(jK}>DXa&bY*ns)Nx4^DHEJ{w?&s_gYzARdyaoOBAr6_q3sBDIQ*_X|Kw_5cJBSw5CSF^rw z+xuKrZ`S*|m8DjO=5O_?OIfbWlqK%HATG)EXz_VuhgdZ0B)iZ><6_29-p?}R=E zI)eL!Ku5 z29JY1;B_FLq5qO3Pk_~+6C4Ito~InZnSV`^X>a+m*aOwq*0g`~?h@!5K=o$a+rDgW zwl=#@7X zB_qLDa35F-?)inH zeJ;QE8jkxeuo%1;!mj)mMh;K~8o&;40qi}`NcpdfoNxKEY=g#SIpyDql9zzWa@gBH z+1{(;7k!ItrP`}yYSt!d?t#BgOS^@&32+KD{dST}#P1ef_M<@lrMN{`REDslJut>1_HU;a1Z&CZ=sJuf0Dgd zwrm>yTYlL*Nxt>~n6TwvQI4B2=pabjy z2fz`q@OsMdle`Ns7Bqmp;54|D^!Jn3cbossMN_4O-PHZ-hS)wpliU`q7kN%Fw8yg9HQT!Y{KK!^Q|ci#zZ2B(6%C@I+| zK4^8I`?O9Xe=@*tkTliv&+in%qg#|s+u=%{`>_C7A~yTeuZhXY`NEERb%5b z&#Yd(W=&Jm+O^Hi>(;GbzhOg5%f^kZt(!J&-n?Z?TiaIcVsvcZy=TvJ>|qo?U7U;t zS|6JPRobsC_w)hWkAX6<9JGUjK)h$5SJf9MH-OPV@#H_A=X-*CIqi zqRzjwTq)(s$Cpg|HkHlx&dz6d?cTj-U-2?h12=-(!TsQI&;)jX(?FW`rNqXA2f*G? zdMd>;U`#C~wZiiqeSk5lB|IO1o(6sE0P)0kBhTZ&%;28N za}{_2DEy5;uS`mOO;OENt=*@0^je6eXK5sQF8Hy2t#WgG3Uj%WpGwcwOmV*$LIxxy zs~U4<=yo!TE$?b^F9jUmkkhFBw@DuKIz!EmS_e3t3fB|r*~}cX5VtY_l>KW z=jVg_!(QuLd$2bhTBpT%WlnMOCb+AdcLiF3QalDd0|q1SRxlYn9%T1d9<4<^yFdq#`%^`0?9N?8@E08oW=UN zME&DMddFNJ(52i4ma<+1ZU(o3iC`*tJkW+f4+MG&+IKcJAB+H_f%rvV`wZhgbS5YT zt3eys0S1K?rsI4B1T!D`R~c7TK6C^!L5fxhVMTH>tPv$t*AzWv!}A7hqK0~$axc>J^M zbU~?&C8ebg^7IJ!aN_&iMl|hO>RYzd5UT_7-Te$n z5nwbJ3+@5;gC{{bXatwizdZKy#03qY9qa-xfS185;0!niiqT~N7z{>$o55Hx5!??R z1do7)AisYZOYDi@e()d|Hylo=?_X}>X*9T4|8gI(CV+>*3@{(mfz6;3>;;FwaqucQ z4+bE27>N6qk@(*Nq=n>70@?oM+F^|6;L1yt%(e64 zWbKAcE~b1*p>)o?7S|_PELO|P^i0j{^l1cF>-O!&!(M&a)2p6weV6$aCo3Bo*O&{d zpAJ1kJ3U>r*VF37qDU{@k?Mh~d|&F4R&BeUdro|YqGZ7Wi?_~6_O3bQ+qM~xWNu5P z;3}z{p9^b!cCXVwK1InYS6ZYrd-tBbX&i-pASo%ETQP6JvSq8+G`IR(n3OCnO18VW z(!Zg>Ldmo9rEi@rzv5)e_Po57)UV9(mXzqZDB1X|rz*RDOxT`iVTG-n2Du0BcC!kR@(mYG|$DA^X? zpnoH3``*9PX?R64YxbP-`PDmib(QY<);4?Ew9eD=8c%(Rp+R+HT9b+rFNJlynNogHBPd83`m{Tk>-~7Jg0GMzJBb1g|T?<5}!iJ?EKoZ zcCAS(N_<)NNoLQUzhHN&hr;_N%xyZJ-H~656vDfkwQU`+@>XywG%C}5Yb5t@lZiFsMwz$0W9zreK=xWCmN$rY;#??*hHf>GYhe;B}#$`cu zbzNHXYF(ro;wp>~~uF zF(vlST>r(aXvNcO)~?%-$}`@gWQEhRC|Tn2sXk#>rcc1HdJ+AB#S!K0&fb&ZW6V$c zj$CgO$I>%grRrh$*4vuvQ?p$3>~rQ;&Rej0%`T@`fpC{rZALHS<14H*S0@>%OUo;& z=+!LTsLDLYN2+Dwd#W}+x5jPZ>K)B5ri>o0&$}Y2s;XXETf2N!t|rBN#mUyK9j^b7 zZ&5PW)uul3-MM>D%*p!60=ch9maov4+RmLhZS(oIx^g0?eDEw-wjxi8Po=!vOUjLz z_9Y!tjhX(NyUcxi`!Ulvs0(h)G`Ht0Efb|I88a;e7h|TmY|J#b=hv8NJ{mLitTEHm zMSDH1UMz|{#!Nj07h|Tmq?N`@bBk)s44kFwoMi9Pm}z{Hxh<7~i!n17rZLl88Z-5* z_MtJ;{6({4W*nA%)|e?j(qhcCP>q>-)|lx-HD+3<^r~NJE_g~j@5X06UAfWI)?K1D zX6o7C$4qmv^R+_Hj4F(o=1afFm}#!um}x#n(I#5;u`$y^MKxx6>feaQOz-Y=8pdO0 z9M7JMlC{mAziFMP&V%pA9`2O2Xy*UsIde$32qwQbdN-*n8h5Ti(C%rqD8 z*^Qaz7S)*P>D(ov#9+)c4qPQ`*P2UXrk-ugG=I_Dm>K(eZa-$m{>6#LO!Lv0sb~7_ zI?=v~+dp93bR6^)#_7jTbJ42Z3Yx}G`Dy$VC7*6pRcnHW|B>|}&?nijLHi2>KkB84 z4kmZAST8CoD=(ivU;7nHmgH7CZ11G0Nh?==O=(97D~~{HN;@VozXwObtKc+v2lV@0 zz7W9mK)Z6c1Ue4-7+4MVfCJzNh}WjjoVBT{swUFV>eT(n%YMamw@TE;F4)I;du7^% zv7H9(!T8-Et&X$K#7?pc0D34q9}V;b^b|M)&Vgcf zZxv?%bVztsJlgj@m3VQopnA&|J$YB_*1gVOu0F}ag^TJorEbrmm18~mUVc_}UEP)~ z?Ys8maVcCVN-CW{wU+g7`S@B<@|+JXcYf$n?cE*0{Zydyoj-dW)pe`HA;`7ag?rch zC~eZ2GdB%W9#!KmWf$<^4D1qb=Nl3FGI#}?0m)Zb83osa+rUIH8B76>fEyoWB@`S6 zuYl2iiQOV72mck;`^WFhw-7yt`vQn9W3T^>e9PEda8Cr&K}`tT5A8RBJv(qS7!Mu= zxBMn6!*_9Z2pk8pV9+^~s^4O_1dN)CW#?iiZ<=xM z0w=-SA?${av(62wz;e(Ej)0}t@`itg{hsUC?*W$M*Lj}!v#f`M_wyXe!>ia=2eR$a zIg}2t2gK)4`ZxOUA*C)d`d@}ihfYzrS|!K?y75AHg4Xs zt;6Lk<}?06Ib>crr@XqxcDY^e8S|T*kdLZ)s~Wv^fKE4te2S+d)B>a8m%k``t$xhY zETG99kKDkD*p{}PESNCjS>7y;rC-P``7u9VdKy!;Tg~2QHl|77t?0mJnmhUP4%arz zw!x)ux=I4?tFo$PqfTzBhC8bVOE=~-J>;i&Lz#m*;Y&DY4dM65dz)9a_;eq+Wii@-E0>_%~`qgU>Xq5Oz1+e9!w&<9P9;$z?)#mA2EMiN}u%zE6LDfGuZ=VBtHXv826K)3CQn7 z=qsQrA_@r;8`1+9;Ic?Y47hp=+!o8u|(;8w4zI6s?|_?*O6FTH!u`=s-Af5A8b^n5$? z`GxF1fVV+=@P8iq61cjWvYx@-2lQUh0QQ1cz?z&^#FQzO7JAStgw&w=9Uv_H@Y&q1KDGth(-t_3%PyFkxY zUQ8cI;Zi7p6e&tW}9;lw_?^JWJJX0L&vqYIU(|4NB=epLgoQ0Hnf}G9FyS5?g_*2Rf zs7(7!^ZH#A=!E&+eGBd>JWqwrgf54+0>wE3eG^>uXY{&2`IG-ho^K28d!Tio1MCN{ z0`Xl4v~E77{Rp!oaGq!N9DBgaz~rf=z6k~`@P0$77q^7xsIQE_@T@hy2exE4&*cq* zhrmLx3mgXnE7&~)Q-L(S|Bu<_=eZ3GuJnE-(1lSN`1?L2rNPLeTDxgUhKfpfuq6QwEtuC`=)M}x_MLiOCAXVDvi zAGO`tl3AGesJFqE%wkf@|*Z zWi$pl36y|F@H{vPq<4ZQ*MN~hBR4ZFV1xE5y^G~@=&yLWqoMM<7y1I|KrgwO8QR)~ zTD{YGIq{pp!64^opuPuDzoI!2^VZZF&E`lkg*%!#<6?Ed`XuJ+>cw=ShGtT-Np0Df z_D$ADbw{ZyWpk=)YL}&RO5;SQ*=1Gps%x-GlrHAqfzB>%pIh~{-tNd-!fLLTv*}8u z#<{UvUkd%S|9-GlA>U`H=6LJeeA`nSg-tKn=9*r?X7Wt@?>1)ze)8~B3+cW(#m`dnS`Dw?bP=^l~wu*%1b31 z4^8y>mB&MT%?tDe=q#8E<-p|7ilnW+zVl>6;p!`7HQrsg`bb%rcNebjS>3JECA@={ zivF^*&U@R`kk(C3BWu$}Ll0K>v|4rabtr9($0)r}$*g@H^q&evX3NGcZ3W&tV_HR} zdJ$dsv#N1TQx`o=qR~q~qkMY2pQFDGE&g>zNiZ0U0As*i;34n?Cba9|N0zC$O3-p^z zJTMZ7Uv$S^)Dh?-;4x4Onm{Xf9=rfv2WLV5-_L#1_Qp>5zyZ{b^W8f{|zhBHwxZ}5(<$`nI0+>9J_IS6OkFXard$#Oo zwI4N=uo<8nECuyIC(>HM#jO0wk+~GqgC?*S90Di7>)Ug?48mGwo} z7fyY#3$8~v{M@B%mi za&~_Mk$f$<9^44jf48?^palEk%D4Vojc*$`01koU;B~-g;;f5j@Vpq*0a^b&?C5S+ z#*BEW^`Eu%n97ntZdw0{dP@f5AO&a1U~bP@TIM-r$zUPqk0pb-%#y*}qVzu{I+5wE z04+oo4L-E3)6+$JJ*{3Wid-xj^b}lJG?+`;$)dsBqOxcRoLDqih-{FU3Fo9>(GaoJE8Ai)!8yTLH#l*=Jca$dBA$(O{vnXwWkyGuwyCqQOE{BkEV0 zOQq*|H$Lm>%8j13?h-YN20a_RMT5Cy(V%B<(O|ybqQP7_iw5&CiZ)m@n9D30%q=R5 z22cGPQBUCAole8pq9KlF&$4Ln{7vgTEwAy^ml*E=iv|`bLk?A!c-z&U`dT5|K<{pL z6s?)&$j3|Cxm(m*J(wKXMEKCQt)hKX>j&d7iZrYr%!NMA`oY|yvVQP%?h;XAVEtem zxUhaOm#iQ3Y}OCvFPgJ{hGR6P zq??W+%oi_ZUfE3CTYo1vuY8zi%`0O&4r!-Z@1@&uOq;~|9?+QoUfFTPa|dSaVeVk3 zVaJhLJbRF3M?8b*?U-FlIlLEE9wSLVw(__Iw^na2)5>G5-iPX||7Ow~>P!7*=We_2 zWfZO&=lPZ`Td_hLNZv=H?QyZ4$)y~^ChOWhZu`N1)#CiS5% z%&Azs6wAq#E1!90{rYVk#@8MF0JivZ=gJ~!$y3Xgty$L{pZxnKPc3`qnYOllX?n(u z-NAM}GnUSMy54-TwWxXODRW_??#9m8(%8x{reeVAlrxsb79tmWsA&z5rLno_=Us>_jpY|x z8XHeck%gtP`Q$8(&Bv%LjrA-`V^PgJWNB>S!OvM5=lgj}=a9$*iUwZ;X||4F_@!2{qhnE1Es;DDP-lB5w_01wY%_Y&M+ z%HB3O1IEv07a9yKBMxW>=fQ+ItfPSWU6ktTpa<)aUO>=yDKSYn%*WZ$P!C zRg69=i_2NXRXJs?G^YLqH`Ra!khRh{fuF22t_Qb(nV=5r0xyAnUtt9X+zrY=Y^8B6 zdMmx&TVhQ5^NU+zjGE309FXKEpf#Wc9012a&z2Z3e~C4{DP1iwhCbk}DoO)g4;}qK zSh)jP3ycb6$j`4>n#ILteD#*}hD2Y$t!MhI$l}8K9Z|+<_9M*azuMyB`e|NYSzO!+ zWO4C0c&{xk2GH8g;$k7sJy~2N)CZNJEH1``=cvDXpDZqlA7q^p+yd?c6<|F$3C@9= z{@80Ji;LA@Ke+KB@3$D*2o8bc!LQ$+kOLsUG0+ErEG{a5a<@Lv*y7?8egm+sxCNNS z#RELc;$l5eyqBPZ{}dg8+;xGzJBx@r=#3u)-C0C*5Ox%FwTO6Ss!v}nQWg+bY~Hc{dgjEkPbFJXkfTl^3>Z zu=am3NfryXSF;;+dP7Sh{;2`MEtYDW%WSQ+! zwJ_7jq>^Ik?B;cD*F7swJj}^u@lZaux<-~N&VF8LNlq*?epa~4UHi7Y+|hPQW|hsU zsGPq*~2&R>6O`b!CH-V5MX{Zr-Mv>FmJFH!Gi7*s?JroqS@mW*U%A z{mPB4UD}C-BVl7J{lArq^gu#rYGBJVDS_}NtDd0n%BN9vIml;Cd;T~k{{Jr zz2B$nyR=w~70R}(eBj3g*_EXn+ksBg*5Te_UnvCF=YunoSthcr5(n__>g?3a zzFAiA>DW;yMJq3p=-y}hHgaq7EEavC>=k5BDEq2z^JnplB2g_j^S%^HO$v1@xIzn* zi<;-otLWJ@z^{HKb5P+0Ny~p$^Pu zQB!r3TO?y?(#_mRR!nzuq4{+XZanC@Wa+Zy1uO>1)w=bW-kFk#EV6J#wGT;8)#~oa zF1ond<8K1hNVS9O5xSg9GJU$EL3)&)9&rfy)fkpa zl0??(N@n?ycHVq{vRE}&ePe1%XzwVdrcIW{Jfyd(k(o}c19_=mnQA~@RBAfWmHJ7d zNr5}E6AU?HbkC*=Uu3t4tD-XH!4<_I#Wh^)*zM>_c>PMXv`oFQJdme3<=j;oYk9SL zp~XuyI{FcRLyP*pU|E~h)nXR%w^T&YMC-)*PEGR?$01))--&DSlC-38Mei9Gvq_Up z4%D;e$)sfGR%~f2&_-N8ysB|aoBoC{9TDyQ7==r7E58!%QnHX(V^Yp*72+Y~#%Ekj zGyOzENXe|ar#UU24RQ4<%v4Q2EpQgwD6$$~v{?V9Sie%OFfXq0W~u2)IdQ_zLR~pg zigD^8pXzNgXG=TK+G4`Bd5cqLQBtf|swK#e< zd7|>CK37()_YjrCGj@=iaaJ z#;L{6%yvpDqxvalDXlz;v$vG|tF+R0uDHzcR_T?+wOhTGks3;ma+ws^B?y@;bA+7zEKSCB(uWHQ9B@{|s zCSN8Usns>~6y^>b%a*4-8EsYL-a2xU;fpn){+GJ`l z?SeOC@r_C*^Ypm&Xsj;4X)&^ty03SmUPoWVUGigE#8jzTdBpzswQS7PJ6d^VmCk)} z?bI{Rtk&FU(`F3guwSG`DYn&=i&1)}S*89ic1a8GF^(mP=2kw*oBs;(>o^xZ&0%?= zedwD{UmJGvC>`63=VFw%VlvdaGy}bax8lBeXO(KfLK<{=@9|rte(0Qw{&l$^AH9qI zj5+!mu`=R)Ro6uRk_xwUjpkdH7VV*AR@ypW=4dt2r1Dnv zc67JCM&szqO&q3a{LEX`zf9|!Of@NOXEAU5cFZ6BX^{$%5AAfxQh&mUR&G2-JKz#0 zTvhY@h@7c!#v#pkTUuN4{}T~fvm}|;qLL~ck&8!1elQR5`dvN@UAlgq6}nH6=q6C#~i zDWz8WT*fpN6}Kp8cHO+f(perS_~|C3~kpfz}pl zoXtV(rcAWz+{4$IxcM&Dz6F=2@?E2UXn(q1?MHc6+_Y84l6$KG?a`m>)tIgoE>0hI zS9a#FbSSUoE2IbKSz~`om+)1M(l5+G&EF{PIea7PEx|pzO!ue2UFfZ$rB+^+E%z(F zZXQ;MPnvZAD+zY&{fa_%g}Qy4ZbR|+cofv%^t>32wcs|5+$#0LYW4kEyKPuyT5oOl zDKeHQp0tdqrDcBR7BxTRF7}UQTw}RaucyuJFp_oRn%D%o-F)Ay;FgmyyW9KI*Hi&LcCX$GPdUBBy~{VNV}lPCQP zO1C+ROVCP5xlwK{H)&3?HB)!4yyrQ|+dol1mtQY64tJXy%fZERrQCf?J(a#(%jT%e z{LDtD-|gR-RDArE39|{^c9o9jv1}`)%c0VlxvSP6Y#!(LjNF%|wtR%8zPXrl-1?rjkcpQV;I6p$n&P&|J&v(`A)Db`sXh<#f!eM^@`DrfD25tu3Cb zKe6^|+d1uN;(nJ?@vZc-)JoT6injyAX)^Ct-LbOPEFg>sF;`ZSNu(TdWxTL@$x@Ya zuJ`Sx#b%{hN~V9TBQ=35%FwWOnRbiXw}lZzag0BfXR>1IR%q3yEUeb)bLpr(9`%!9 z78Oe~sae_)O3wTlLH%r+c}=1CgqP3tbK$&jlf%5w$M^fTc|4YeQDpgPSU6u!ku`*TE&t4aNI!B#Ut@%Ydp(pcuGwWN zCz?Bp36mv?7OBOArQ8wfhum%+pIS`BF(uz(Py_szc4RSOVWy`^CB@WYA}dck%-8%r zP63OFSZ4ezU0m+yOJbSy2?Z=Bj3ds0QZ`MElB;elCMCg-M-l^;C z%C{Qox5csadrK8hyrOxdbvM=ymQI#hdggC3<8rbvYF7ASmk%YCXYC+AlV&9l#SCA{ zA!hE@Mrv*xGb@1>5m`H!JW)zNwRSN7SbJ)*ALaDz+NGRLLuycJ?O;-noM+!){!yIN zzQMvMjV^Wz3Nww2s$9`5W4B;Zj7t=WDy4#U3o(C?sF^|my9MJEC0$MPGj<6vhh$xv zT|zc?>}K@yD{^`RkzIm#ET>Ab1Bl8mOKHuORT_uXD)a0T;*=E2r0TgNNTl{?zd71x zvRJ%#H&?KjqHt%d0*sp)QP2Xw!h5q5ZM-opl;c<<@sf7IeP)wGc;2qC`CA!~({$I@ z!Y+N+S24TO*8E-lO7~kWEu;3I!Ej~vTP?)oh`RR^t)WT^@29|it6~#UV82x-qzKU( z4U*)FbK&M@?{e4G@`RRanldZ;q^N!|TJN)bk@L*ns>v}La-Oa#nZBfx?yVXxV`jk} zQ;SoGs%|06?UBaeuBG}`nzu)4X<1#eIFe(z5|uyou*)8)#TO6Zd3&UBSkTMuky;v} zhX&f)sOESz&9@9Ni<40D(J<>S6Scb(byhm!Gg{afIz#ggbT8SyO_?aHR%PywH zF={y^4b5S@-Nj7#sr8nQC~raE*Xcf{_|!5KCQ8Y}C9b^ECuMepjJxL@8RLp;DP>Y{M<(XAHzR8P z)DgZ{&4>3B?Z_C9QRy#ExH3C3Sq^DNee1F#BRGQgE-JkPIsY$#Q*Ev{zs<#iMX)QrHVn2;AvjKq1L!(Pb~7 z5T7J>08yundZt3(Z(a5Rvig~x7o)Kjm$DaN>BZF2GCy;RnxAqP`zxmwc4>P77Aq^Q zw{D9s%Gc{f_X1-6SZnjormLJPO#a4`uApCZFTi4CrC!V(r+Bfw081lF<1{Qxxlyhy zH)&2Tx))#)VyPynC#rasTHfkHH+un=PIoj;-+1C&NtbuC7hrn!l$SW|-tb9g_j>`R zeU@4(=5M*9Z_TYwM|%O{vp79b@m*{$z|!oF#`2BF^y}STfW?X>^;DMP7q6(RKNr~x zF!|llI9=nh99UT4y#V7ju9zxJZqbYH1(>9mW~Et~7*DJtHKE(R0OOD4nXH)hZZE*3 zbw^Dr3ugq)+Y2y%qlD+}1(?6dVdm0hFTi-R6j^zD0Tynudb1ahjbrXY)TP(WUV!+! z?ghkBtaj)fm_IX}bT7dCdir0AJGs+UcfCFVtpzRNj@JXwSAfFKK+n%DPLhB2?o0Wf zjjM@sH>e768=%9^6esTt^0Myac`{Hs4?<@G-D$fJ+5t|2x52GHEKVK<;_I8Vv~1e6 zefzFm(?8$3An5a=V~&6Sl0OskKX(zU6oiSlDxPmj4KrJC3jCE4b07 zqKaFlo>`L@-}spGZGScmA*EUR{~?8%G&r_wO*u%fb_E6}4GoQ{pUDzMLd7C-o7@JA$5+&xn!0-K!?O@kh0+4tZ8IA&1(nUONo^U(9Sy+TqVxkx*vDJx z{|m_e3CL?=d?we@k-y2&^A+3=hJA~>M<(XA_>@J}g0!5;>stNSkA;f5?-chhKf884 z_ngT#S;jf^vTuoL`5~vu!CCMQ==VmF+yL$dwcsQe@*~djgF0{o3^>azFJLj)0ZxHI z|Bw6s!F;d-oCky6K!Io|~X!z+K=z z@C2v_O<;%I$GJ5D`rt|KEQIzugA6bT3um`*hP6MTL9VIS$BlLFg zFnAKU8KhZW(3`Qgz9h|Ix&!;@Dc%Wq9=re!gKPeQ`%chmICK=a72E-o$|UF`paRr` zJ>Ue;j$E+vaQgxN*4@5H8vx*Q*@qKCw(DOUc!LO1g zxC2ZA^1lx{6-)ySpc(7}uYu$TM2mQHMkKV!k zpF(Zz)BMw>v%gqN?QEu%ksyLz>qzt;1@Su)=a|WuO1=t&NTRx566Bt#57EZei`P zd-t{9p{D|4!F^ylr~)luFE|C>0mDwv;=p5IGuQ)O2B*L~VBmMX`v&M}Fdj?<_k(HR zQBVOkgBO7MnOC6~zyL~h7?=p20ILC`1YgT8KiHnAEc&B`XmOwep^P^4rsm6?j`XW? zy^Zv%63(2`liK^;xl?a;FRQ}hQ2J$HF=zyv!3#iP!eO3Ifj5C_qc61?8-3_ZXa)G` zL~o$7(#oB)E}8$H@ufbnh57<+29kao^iJ>ur~++3{x3q0fj2=v?XAtt80ax7Yc}|2 zjlcqJtJ2fmuDvm@NpIw~_7_v$MOjU)jo(P*hLoBW=GHjRdf4nan3y&-ty{N2e{RoR z?h3ycewzD7=gzIHoHuU)rj$#U>b6w%EUUb%mR8Byvv=>sJ$}Ns%qLjK0uWEK_T|KudTewkjw6wOPGtVEtg*BV= zYYBc8RqI=_e5Gac7N&lB_oU0M>sCIvxOLrJcI&#iMX7xyw|>~gYiZkKTA^=6%?kaq zy!lw1QSiT;*_JyU<>p(~Pjolq($~q%6~)PKZm+JJcW zLXUtmpx=e!WCW0`yP=ZRmw)njkmuzqi<6h?xi>b1H$!)Y=NAHf6?z^F`VamO8H}zk zPVR(G2Q@(HNw(-7+$X?I@9-4{m<#prFS06YeQS0{^;LuYpXQ+Z3h`*}A%FPNe~~T3 z$M=dxp7cLt3-Op9Xza%~n>%adcKbLz#j@DcOn3iH%!{Aqo_RUI&wV+?eDqXZ{y8=d zw=}Yp+^2Vu7UJg%OiM928>Hx;V+-+T<;zV8=G{fwQ#|yse~rz{v&ki&IxDF;n%aOn z$XK8pnhKOKtO^*NXnr)qJz`^1u1kA7N$;4uc&B{Y?HW&jY@} zECd_}la4aG0atyK84uVChQ7?46r2Uazs1N2UIL?z!2?>sS#Za7(>zN^p z1rLGuzZWY1I$uWM6zKnw&*4~TIXD2$f&qWWcNe%FOa}U%c@R1iECrjvQPA%&-xpvs zxaT?M_0W$0&0Gyy2XsH%X6Sx!7@QA&l6T$Td$}zyFiZJglmPDgz!Sm0KF~JkVQ>R) zVFI|6^`&dRhHl_VuoyIh5r_ERK}YF!H_uamo*#jh0_j!@Z38F31u&YjngPVu(|XzD z7d=l6v<2)1l6MR`W`_@ZGx+sG7sbr~K8O^o!G-Uh!u?)3468YrCCssKkSn{u}#gF<;ruO z`WUDIO<*rL0+gq>po0(ae!v~T@~Rp#DYzejwu3|9ICvX~@0!rMhC?3*^FbX@&#)hy z047f@@h#Ag_btDn&@tgT>I>8F)My>duOe!lz@IG0t%&J%B>#;bR>GK>q#q(Vl>`x*xh4>;Z$H&uKrCXYn=$zk|@@!S5VY{n{hctKs1d z*qgWq_tfC0+FTAAf%;ITcaZ1TKtJB1+#{gV!TR7n9w^@e{+zj1O!VdGTIRUDISp^& zSsLCQ{Ajf*H^-+iNvGaM|I;e&;UR>bCEdG}KfBfGhIGY8@fAawPYv2X2~|C51;>J) zc#QWo{1Q^Q2Dp}G?`GeHJvpxaa19Hw-`%aGOLsB)0Hu30Q0ehH&lkYt-Hhp=6UhHn z=y^S(#aQqFC=D8|hIWF(!R_W@1^%bCD)jP__X5vOZt%MReRwBj6?9=9CL0a)09w;^ z|I?~b;x3?CBfXyp)b}7Zdtz3W{!gp*Dlvtd9R~Bk6;8^?hdHrUd}K-I|1oo|{-@P= zFGi^=;YQOeCn4cqTC*XH3d*NirTr7C>XcTbqkm}4#(KAIR`N7McdJ@yZ=pKxRutW7 zv|LZ&*A{bnb@LCc?^c)hJ09;+BS+>RT6>!+Z!EfFHjYKB)D2kSA6nxOtAV2QCE9dK zXYs+$^+RzSYykWi=Ifho_|tl+tsM8d?!_`q4|Gu7%9DWwgxXYre`qZv!6X%;v{2tZ z!#}k46dz68KeWa?#Mg`<{fE{#ESnx}S|z8^DK9t1N4R=|E0K@VU_7PXXdtFoxBfs{a%VR>nmbP2}bw&b|(!k|0Uv1oOQ>=``5}_ zUI|fdI?Kjwr`cG@^j4@n%B03e5~;^|=hw0_;btylzPO^VEwpp@@>-}U98qgTSJjhn zUro%1u3A$I_w2?Yaao2ww%avK!b@f;x6#T~EQ?g4Q*3caoJy$88rk#i*6ohJkU#5k z%4go$wL*Mxx(cU-+KIJrkM6}{QR=H2!znf6CG{>h=UP}#l=l;E&dqZ19yz~hzNDF+ zfQ$Ux$q;jkA}^eZi+z=6r!{xw#{O`tr9}11Lg9Ajn#?WgYD{`dZX6PqDK$bd-7UF= zct|tclA8@BO?Mk=>`y6hORo74H{6SBK1QiQ>Qpoz$h#NU!h1u5^k`hPSZL9(D%FA< z=G}{HTtTApA&YQ1w<-9v_W4^eId-8YhIoum$eCW@8faXF! zl@vGOnvYTVqPbYe2Pd{I+$en9>l(SZ1vhd2X}r4d)f)i;HvL7LF_GNhxXdZE2{uT-mz&!z_+b z*Au4aEzLJe;mVx1%yP(0%3byyNI5!h8OI`|BzM1U973z<_Ac9)ucx|)F78xi%ukBp zRAuZdDU={L-FL~>- zPJo}jj?>atEZ(b5nnvy2QlcIBeFm-6T;xlNo+v$uYVl*rDpi4dUt^A*-XAqwb9T*2 z{T)Y{JaiY=${-HMFFo68>C=k4x%bsLdP{k4{@zzNSB%q*CAc0{Ir3lKUD{fA@n{E{ z&#Bi_IcN>D%bc{kxaQBBFd4E5*0)^rbrfr9F=86}M$IgxL0(OY`6P!rp*;zmxhlv< z%?qb`v#Iiq++DA+KitwantNC%^`5mQOP#pxu2%~cC9cN%=sVH42?=+-#{3H9P3rCF zrq}4JBg@6;lDXYA%aL`XZ8%4)5K@WG5odYL4OiwIv4zCc)$B|=C1!M9IOetz5G7`M zgRAklcfeXx%!lsW-)bDl&YUQ=keI?1ohXh&V##ntXNSAv;%!w{&0kQU4p7(9dsGX> zCfuJ9W(E|eYrN#P%Q_BmRCl{=VVq`CJ5X!%ZPD)iYgko4Lrdvml#k`{_-5-x>a+Ueu>Dpkp$4t96?IQnkA)D&5f^s9E=oi#4lhAt%) zzVWrzsP!$iAFa^%x)QDBUy8g`Y7U?k3f&^wt2RxYR?p^VDY?5teM$F9LZQ5dRi#)Xzk1J2 zN0*v2@w@sEYw7oqtv*C6KJP}la^QAVa;L9*)RNp;ndv4_-2>`1iN5$RMGv~Z<<(>A;hEwX= z_b7PtXO_1&ZkJv-?OTYSxq;rYW*a@UB{!Q3w|$xvEcSND+MThzp>czryghx*rnU~b zWC2eYH-4InaesEriZ##rvjyT-h=8nWQPL@+=T6TLcp3UPR6Tjl#%Dr|@<2BS>dtf^ zX|~)*a<_b1JW>40o45GWwn|-o=u|qJn?0X}5uc)Y6 zP`z^1`ux)mO3^^Bxs$VPr)eYEe6h`*!(SLIS>M86foz3s^Zn4arFOPFtv!dOVlj(tO z)r;3{NNb>Y>75w(^pBdmG+d^qUn~`q7kJ%%ZOw{CT{5252!&Z1rXhLe9?F_Ux`WcU z|5%c^d>QJtNlS~~Xx@V6^rU5`?f_*M!RC(ffdHJr{QJ*7|B zs!eGa$_9_34x`F~t&>D-YyH75>n#y}>QQI)49pfGfCXZnkhCC(rB zbKbwkxk0YBv7nke8usbg(k51TkJ73*c_x&!csK=I z*X&Z#D2YUU>F?FE<=~2>bZ%Ak;$?O9JJXa+vX@t~CRejat9)L{M{eea+_+rPH_Ye% zi}?3KlVG)#5bo9N$lT^2uAr0C(R3me_9YZ5pQ2=$m7S|=MTx&C_ia$Jc?&>$&I^5vu&T{&$!49H)#4A9QnCh zGtDhZzf;0W?~1i+^T%_ANhT%0?Ucx*5*Pf18&0P0{3(rmt^VEm$SYtTef1N zZ}L^&^xP-Wy_Wt|y8HyBa;h@tniJg+LfFE_w682m{Mmw{q{h`?-sUpJ>zDBF#e8A6 zuovLp+o^xZ-HF;NZUb4dvZ<+= zlkhE@w(RVB3e@5kqJ5G%l?xZ3{!Fl{1TC1AEmppgtY~HNfb##A_G*b!Kv)rGcK816%`d%rYKOc*{YTf6M zf2V*(kftWxoY3|5j=TPevu5D=Q~vgjW}bC>$9d?{Nm%NG(?B}FbaL&9)$=1`_XACI?L*R8uZ=YWpVTC zN%C=KJeIn%<1PPjsM5BfHZ3YUv7C+Gg;85^8 z8t4h=DR2gy1I4UEh<5;VNO)E}jkTQba`)2Po2QL%{=ao=J41wOfnZ^xv`E_eqB=k0 zlaE3D+-@gJHL0KLBdHPelFy|*x_H&2nbZ$NJ)7ogika=(6i2Ox@vEe=a%o-3sb!qyClAa-dW!HNrXk(b&3~FKF|N`HGSbSB~htg!^4K#AVti znYWPHj|;axnex;Af;$!EN0>M@lZ>>6#*Kc~Y7&c*@@h$86kQ=o9=WU6bn25l)zBDf zv&BG4WzCAVz2X++kDt4NH%^te!Fi3E6&u~{Uy^9tZjO}xvtb;^xJ1!}`*uweT->y4 zE@W3?gS4V9y=zOd6^bSmHC&6PXTz0A&EoujEVR6syeuWPow=JGkonZ|Ouf_`v|>Sx z-P)1X6-zUw#P8_Le3g8Fn>5Pj*DR@hx{<3sI^Fy$juSsKd(PbatI%w@#copM{{b6a zD>wh*q_Lwj)l*+N3ZW*Z_x&1YOv$JAL)?G=F&}ervZ-6yYkcB6($J7 zIA8W`VWO<}yY-=k3zsd!cvdS!d|&LL^b~4{HLz#X!rc86bm4D0!#Y*x4z%fcoyuY= z6;`?U6Zv@y7A;!At#|f6dX~OX#SpA!n*^6O7rWRRnY*PYEjx=9Q%SVgvd5TPsWmbk z18d%*f4j33jn8;3*YbC%TIsVgcgd-`lCMq6ee2dZ)$UThiV2$-?_6jJ074_5AdhDF-RhNi}ZRzWrHlP4aUziyg<(GyU1z%GTU{ zl=7qJ;xaY;>)47k70a!{8QIE3U3uxo5ZR5%mcdz8Xpcrv3{lO?Vz>E|iY$xV`3m!k zDdFkeFtNYM;;Yep!BP{su`|9U#=fJBGfUCi&GIX{+!RwNoosAM%-s|d^D=5`o)>QV zR1DJrZg*cy%uQYHa$igwo=wr*lt_ACjPYCPin>ukUok#+)iu$5F)^R%XL4go-O0Nz zrl)x1!`&uI4WJ6-ZWL7T0;#m9cbVK1s0@ zMTcJYt)x#}$9xqW1?NEV&lV-ugL}aXVEmAxWIwp^=Zcc$;2d~hXi@SaxaSkBB7;+4 z%=JadYS90a!~ref4KQw4Q8E>jfi`d$4E+@RUcA;5=wsx9b&I>8i@{-V0bDn@D7gjP38n(^%z&1IMz9N<0mD9C zl-vX+gV*~MB~L=zK16Pzhk?%6pMt&xuDTXpAiv4bX<#|n3yy%-z*Rp}l#BpMZ+f6* z&?fLU7|I*DlpAWUyrw7_31)zDPzQ#7l(f)MdfdVDB%tR9ppOBiT?K6eC%^?TnzEV! z#OHRV{Tm8v7iq7y?}?xGJRMNoP;(S2d2c}9j~i+v`|bfn$rPaHN1=7#d2kfG4&;9x z+V>+x$v|)?m<*K;tDpf*29VN z?M0txK0k?@X*&DU&j6L(l^^uAaZsSc0=*SF0Xzt1f;zAnD9%ynIdJt=^m{=0lm955 zZx8Ot(0b4b4uDfYeD4H0kk<7GCa`!22zQt_ClG6T$DwD=94?zp>DV zz!RVfD0eM^?u8x-&#yrT{uDX@^_}9I%5xQH0dgOPUd!9OAIM!FC^N9k%`|#PulMy_ zdOpsx==tDBt5vzVyHyn?Y1G^3W*TuH3L#iv_2On4mnNE@584kP_9!q8Ob?R8qqIby z#IFJD0Ip?qxtT^>^+@Xs65rj;G&dI&C3gX(`)Ht&T)}facne%r%yjaoycabNn6N zAGk8a85F4RK{U6~T!;B+dNYm9ePRlCG$Y0pEV@Qdh#wG?t#l zKqqdJH_~MFW)#cZ zNR#C-8Aj>RuwpkZB!?Sm%*Xm1a+`M}jfI;Wa_jzqUH<0h@}yoY+)HC|Os2U-(Sv^5 zd`K<*?{@POHOc51{dc>3jSD@}J8H}i*;trHF7Bv_T%niMTY!^0YAg&{&eGH5i=tV2 zZ;feV`H|bT^z{GSpSy)w>L%6IGb}@O&r(*Nc=)nci`9)bI$!P9 zb*zrYGUI23yWC+n8q1{r!)`R(c!TZe)A|R2lq1f8QZ`MEk}KVPgGDJP-+EXBksL;S z8&UFZz%g09p_EMepYYIsU+3l;c29@`gtOQIdG5KmT*{)sM`Wm%gT&9On zlR!%g{|RrgO(RNQ_T>D%ZG)2_|CqmYf5OKx(Uv)vX+S!8H|&@s z3rB+chxm+y@a-sH@*rEbP$Mm#LMVxnS*dlcU$wK+h^g{MepF*M^Wj{fl|r2BAW>_V z=|9QKFXpjlQ6y@F3I8Nth*LVaa#k6JRXxRw^MI7-jvkX@rDT*bT-s}PgT3yvTII%I zA=^q#JBw9_(sFZkC;F#(@hWwT6YFSljk!xr2LE zBe(jPzbNlpts2|nT)Og);>h+hFAjBJHrsQmo7|}yOOtNqMzUhMyM4^h%2aOj40roj zs8RHEcl(%Il(OJ%AM?S*?GxrgQn=~Ie2luG$VB`Fq4JM8xEAmizdn#O49?hcCiNHN?U6#Is< zvP#g)8a}aD^Ln6vo)1TIRomot3)(R~eIDh=zP~hk|L34$fjd=5~FeM)*~-TBkSB zZPmOp@koNTIE!PYVpRUL0cXjsyHBjNEWXkv9DDYqs~YKL90qbhH>3qvYS+jugjXriqn(*kjK0sFn*WPjaBXtjirqCeQfQ zrej@r$6AYY^AGup&v-&_5Z#Jo(nM*s;Z~&BS2AdAnLCdx^_WtF3*LDY^O#04jZ>r4 zs%yfXN9OPR!ktGZ>(cK$GHLH6rCc(19u<;K4-)P?QYfxyEs4B!S$o3I-FXztA|>5< zw0X{nJjnx&O%8k8xg%(zp2gkJKZ%(IT#!iYKIuaX4?qWT-z3cOk_b-Nlr@`_i3Nsykq$K{_54ickGW z??NgRPHz!<84I;C;(fWhkj!5c?r;}U>?@sU4<-ICB!v*y-Gvl$5mz&t=v&_MNJzK~ zDdtxwZ&hzc|1Y8OG_06dJkwOM?3uU9W(H%UY{2|^`*duwcrmqj=pSxJk`L`Px*f@Q zj9T4a#yUEJGZ{YQC={IKw@ zPg7JFDP-tBw^u#YWUsGz&>Q#K7l6R+5p%@mkCrX(_cRF<^g|FdR7rWD` zySNwgr#)sY+Bc{5QE|H~L&^)g_Il0yQvNungy-D>mDPjx9KH;d0^F(Xd!ZE3QtK_w z_MOjiXCYaLPa0S&P>Sr{`gMfty0qOT<<^uepRxW~eYRRBG`>S(WeZwkiKz5cX5DIgZ`g^p#V| zmcONyzR&LNpX#zkn3Z}lcbp>aPBW1BE-HJI`k$lpo6)p08mD1?ajleJnv-nJw7ZAi z)12h(n&j@NvfMZ;R@1aQda+#TU4BeGmA*YM;jSvB7t5BM%XLd8bJuR}tGZYYE!^H2 zV@~e2CCw9bV-;gqZ#5SmbxGfuepZ>gyUN}`w{^*MiA%)%Oh4?Mte4B(s+Cud6x(9O zl6op@@moAse`4*O4W-Uigx)ypZN}}{(lZ*TYkrmk3uE5xcM*L)da-X9Ye_le%2>Bu z`EMfAvYQrbX4n>`EWT0k^A)1^?oOci z8?a(2;*8xY6=s0y+4E+NpG>}Z?|X4NzxIRtM<}@R@3F%JhdzxpI`mF(H<$qy1Nk=w z+5z1UUIpjDpd;8K0`W|QE(Dvw9&i|(1?}I!eH2^%Zz3DK^%<>E*p-8Sl6#}W1{mhckLZ>HO4OT4a*;8z4yt7t`c_=T9*6jbAujv4{n`4{5D0A>Gr;y@s(=$sciS!hb z@muQ^b!)+zGx*%uDJ0esBq`>M-6l!Y-Vt>r?<`VJamh`Wvq+MqIA=cO>w;197iApp z@hp;ftOVlpO@`$`Zpn}N`5M$pUUU{o5-g@s-iYb%fVi71iS{WnuyImPZPLO*I;QO$b|CW84H!$W`ijpbd5g;i~K&!xV&;zt3^D0lWxwzUWk-ciiON)1dEwvA^iu=W;qk=~C! zE;^Gm5Xm}gpf@c#0=J&&&!RI)*3*fyZWPvN)k}TO^Z74MKYrx5^!MQ3vhVz5&H@3I zT|HF#wFJ5&&_mFZ;BC3bP?Nw|pg0dfE5K^d2^3%c2Y5ab+-IPpzQ}t4lfmOae2W8Z zh8FXl2Z3QgJ;U8#8Zdcki4~wW_;o^G4$o0vsF|`^gIb^H$DGSLleGNv)HHAiya|Sk z=EN0v3{-&^fHXY^z4Z&^53{FujWHyz^75;b1~A!B`>ZA;%cwa|lBi%n*VxL+}Y9 z3?>X=2*WT8#)J?;2qA%dXmc*Q%iEtiz4Eu1n*eDz5`N6GiJhm3a@mbS5d5fjP*iXOg0<`}ue& z`KfP}GeYTNhNh9#;!M)9=EOM7qqI1aG+KH}lFlSW8PZqIB*nOT4H-q{nWR>7#Oqm+ z_Jy>G*SsN}Noo`CT~?LWQaLnIDStYX6z?`Yq&Sllxk^zy!768x>M{H7is_T;sGklHM5oeO5C+dvXDod(eu?N|* zJpWppNph~S2FlqbHKkUSGfC!KdrZ$;-*1%4nWUIT@}q@mnet3h%)>3ms)bsn^$J_D zwoq@C(ejJsahr%%R@d}ql!b7)eCo40Qk+S0K6UE+%#Zaj&y;?QRm>8!cI8Zxq^!*? z5K=O03Mre`w&FydQ<_=>Bds`-^Op;3y zrO{Y9lcYG;JIWUt^@b_VB(;)Miqy_(Lv~YJCf0#+g)>Q(a9*ao!&Q2H-PFz`IYp#S z)rvB5^9)jD3TKieD;-V~%jgy`P2X91`&P~*#njeftx9Q)>3)`Hl42^Jg(J=+#dU*wD5+~x?B26|q(O7HT*OM8NyLKN-AnIvLWmT{XZOgW1)Nscw8R_RQV!=khWXOhez#4dD)&{UjBGRHLa zo)%}496ugfXb<^06{X-zl0($Dawf@q(?SpH!seJ#-*hI)VNt%i^D29rGf9&1J&H8y zh<78(kY7425aX!}JG7mex|C;<%!@f9%^n-a6gA`RZjLE(oJk5H&Lo9UNI{O}nIuWL zyzVi?muHf!AyVp;&LqXOqn}BNsofIFwH4p-qLidOlhjII@r zXOhIB2I)+aV?}A%;!INHsuX;C=bee=xg@uk*QXqQDb;fc@m&52vXPaU^ z=<=*vHBD!m9B&$RIG?oMt{pCwvrUd|MN_F;oNcmf%q?E0^=$0|WvehVfmQwTZJ4YK zv7MA+tT6RYXPcrd-a^}yB3iaQ z|73pR73ZIv=Gf0aS=%>Bc~aHRKef`%Q>Hloq*y|nf3h5P8)4^ym(B}WMwFbw`KK78 z7IBz9SULY>ek)2}D$hUF_n%(d=KPb#m?g)eJbzl8e~PK3(P5R9y5)IRIRE52j7AwBd6#MJ{L^S@VmnBV zyJ8)BW)|n4#;YOCs>AuG(bCaB%JWaH@z9me zKPiT^>HJfaB5gSTREsIjKSi#za#w5TpQ40IDxR;ot0T@o#rT+BIXE5VFU~)S!#EA+ zpDbhQzKK-r{8L>*xpB8D=bv1fNZmis7|uVrtk!Bu>z3!AT$XgVit|r_m(D*qC*?v8 zwewHb8YxoY{FC*WT9Q1|`6q>)N2+Z&|KvF3T~ALg;rx>&O(iX@gbs!kUzl@lc+BQk-~^GP>KIe^SXL?-I76Md{Ms$0$#}<@u+WpYtF6{8OtG zPB|K-O~U!7c3PNuKRwp@r*>(_;xiscoPSc9R&8g#YD9aL=bs|q`4L|^|75-?@#Tr9 zR(Vk_SsE)Ro?6MNEU_=OJy%jW@zkosF4#a$&tXyX;^=U^5#MRc`#I)`C#R@u9V;AjWTfevLsnwhLuIw} z>4|jW$$8Xi%)@c9SBh8Gr1g4CJ{eb;4MeT2+N&O~T*MQttjV-F@#K=Wqfx(QVy#rB z<2mspT~YUV>Nb|Vbn>;@=ERdrU#He;zH7%@rsatz$vMqvRC4qs%|7#YWQ!9|&a)kj z`Yq$~v70K}V)gZnsKt!s0eSSFT{p3wHhljWm6>xy*r6HiWUZSAN_<#^tp zl@m|qn-X6+@npXB@Fh6n#FJ&}6kU}QPmZ^)(M~+o>*qAq(Tb-0iW5&xZz_4_9lGz~ z#8cEF$r#qX;EPmG_R8~>zE?dJ)AB@&?JCaSRJ)fImn>_QlPuy|sud;QJhS!w)5=Mf z*mGK?W}a3%wc`9}wGk&xTzXOZvO05f?K}MMCd#P<4%bUSuc@3dv0R-h9p7**&zMNo zy}(rR;*0X+9QPTMn6GuX{0d9Is9TjUZdpsh858FkDZM3~F|l@OpxxKz(^byLdZ}mI zGbYyR{9QKDb5Hnm+Qt8d|3CnpG3kab0z1G_aK~euI{~-;TlTnv3m-=Yd=BpXcl@;g zT>1q2Q^8?y*}rG6D0mxO^(4I;906Z|N&kWU+~6Lt4IBoYPyLrTV{*YGlm>Kzc4tiX z5I5Qxlf%S!{%iDr8^FUr`=k4y+DU#08qb(~MEGlP-lKW9?e)+*!3?k&90ERLa)fK` z%>6DcE_xzoOfLFY>}m%(W6}p5?-`RpWOc^m4XDnTd@3E|IAikW!?}K^A%E}u>KT*A z32XOpH}tdX`A2dQ{_A;5R$g|B`zF?gQOm z0PF*wfs?7j)!<JzhQS52#h%)CFvfN+TIg%efn9HkkB)4&`b0iN#zv*)%z3B8glA~OYc8=sU?ycHT z=SVIpuD|_rBp3cu`ZKr-Oa;T>4RFf+oTUSI0F_GTNV>TmQ23u^-eb_IU>F=McppPM zAIQA(p*H}XBe@GIJx>)ho+DWR?;!X9_#DX@|2&@~xg4r=cR~li$3^%8T2uVvJLhrW zK2FGicIP}kCGHGbVdOcFJN|xtPH9ByoJS9mD#!7i^LU35_XUuKa|%t;d_3noE+PH3 z;I2YX`ub{d&g0%9Kjrg0*P;gs-tnCCxUERb2rtfRXq5BKsgu_(`x+F1>! z;G45@R>ORM*O4-u32>}vvM!hZDTy)h8;NJ1Y@g}7-7@gf&T@xE$*0&^9=X!Q7prEN zm7V2v8Hf3nA7lTxB~7V+%YEUFr>y0^aPvsha(B1msY}@1Ev~;b(Ux{(nY_R#{T**nt&w(r;Vr z$hJhRfpT_9O{rDe9of#^lv-7GQ=9KvV-d-g3hirHuuvA4Jb&J?Gy4o-7mm|7|M60# zldNdPa;KR}i`~@Dr%s)p`PLcR$#Fa%irv)W&{CD%)Z$s2TOgz?c2gHAn=?vQxMIq> z26}ebO>KRmw0^mp+Wc60dU3XRY1hk$c6JHrLFI00Ye92m|FrobO}T&CakR#WebI_@ ziA>e5luS=n-Kk<P{ zHr`*^YEj$wtTe8v(zsp4Q#eva^UR)>`<`3n?3C6>@6mqNu$RoKxbNjoWb=@&?K*Z0 zJ)-3fW5;8E$bD^;ovxOR)a9+yC_~;Y_pw@r_{y$R^W6s2wA@wdxMSZ{s+9Fo*2AfP zm3ujzSDhlIHQg3_H>19Ef5N^NY2p5a{h5|7Vp{CO+`*R~X^MTA3Q5-KlATulTw_AJ ztd_6X!%x4{cY|fxQP+vO)OJKV##9=pOSvP`C4g7%h_ozk!It|Rou(DlctKa%*%;%~ z*lV$~(RsOdI8A-riBHcOv9r2R1jmQO9q zqpRi4#+YB!;dIIVsyA_EXQN|V(NyXdI~y&l)@XIjGknC}L(7@EhU78o-b2f)AIH1J zU8w9ml$>Qm>7z9t>DCl!nrq00x~e~W(^va2{-TU>t%u_X;U3NFE%pOij@;YqkCTK` zQ-`*D-Xurc9P_R>X;B9E;MATI^7ZsdR50R$X}-)%IpN7G0z4i?USg zXS7MneNj<1_7n4)`=Z3*{)Bx|mN9kTM5?wgsxG0D(c4Gti;|p6E$R}XvBkb9Yc=Km zmHVB{BV}#BlVc)9YLxv>mPCKr@1(FxnQ9UCJ2_4zcY8QJxrF^rmNb>Lw317?-^nTA zmHVB{V+^+4sbm@JZbel>^rkhbC{Ismxnrl54!44Ir6)__u{iQ|t$2D;aV|ufkS_P< zw9-r|^u=4*pVLY%wzG0-y9;8({v2sjYL{=kG?wC6_UAaiNS&v74vU)Sei6&+xMSO& z<5V%1sC6v9(~B~T9CLq8lvh6Wa6LcOR5G#l<^3FUe~z`+wT=~zIgYhI$9dFg%)@aW z{jN<}lQH+_SVPo0p8KS9&aE=bZ?iwg`Lv@kf6K&LsZ7VSKgZ=9Pn}{JMw6G$_WN^O z`Z~3C^Ibchtu6QGNX}_SqmmnIe~$BPN27krxP0T=pW{?f(^zdNS*1(;XN>(h*58iC zd@bV|IF1>6i~Tv4wp65wQ&@ED{W;bYX2im%NGeJ9qs9sJj;C>=0(cWrMjD^t&iJ!fAFa*^J)3Yejf8% zQOd1Ze&y5+B^|L3C#I#O>a<-{l`T8hplqTwp9*FANkz3x${cP3oVrP(nJZ$J+o)$uF`H^*AUBo?g{Ub zx%3%U_JMZE*hAzUgr5LMzzu!uJpkt}#?v7<3@%&39t?2KQuZBymEd!5?K0Lq!C`RT zv&4Y|;2rQaxL`T{Fu@YA2fPcys33Oy6_M?&@P@^2b%E?_?oxO8Fr zT{8C)H`*?lr-)wzj(`uqsf+UJ?W(G%Gv^WuEUMqRZ_<|gQPcgfs?taiyf3Dqu{<yOpJ+TNZ+5u{us-^ zOZ#IS7A2oze@x^`6W?MZ_Q%v^9Ok=zjQuf|G)-UaoA^_3o3GoV&BEHCQ&J20QYgP8 zRaUf>dtEH&mQ)yRgbeD~<}QR%%CVN_4(c3yC7yQE4wDrtD_oU`oWtG{ z>oT=Yo)keNJ+ZQ@q=j_2hvc32h*WyB(vY|2fm*L_Q8H^yGs>AgZU4H0mKJ+KoZ6IU ztM`KJ+O4_Qex`Pzl$INf(zmtOrQ-R{@@^@IBjw5AeIHAfY92b`E?C-HxQDCyYaMiuQMCwyVAD>M#5DA7g8{KT`&M;|#1DQ7dBPIj+TM zr9a_4-6g^%&^>*@Lix?q&NAI;)$};ZLrd5Ea5)cK4IH+eCADfTCwMDX!qb|w<&&-L zIQLjs2R&J{*S0mIRo1O9TZP^x`-Xa(|5abcxt~~bq_q0X9=&yv7tLBs@n`zT)qNzd z5qlY;Og%q`8GAY_9DFfJn`5nkyOMp=S9U2lwiV@#lV>H`SyCGZb$QAV{`X#wby?DT zX%v4*PUrmw4s*{cdlJOAj3|9~6yHYH;@%gj;@k^G)7RfP_AOXvD@xBT_boV{{-Ave z!GD-zs9W2;3X-ACj(M+w(ou?XuY&WUoyPE{W67~7y{W}sg_uhBJcen3+Fk|6(s%S_ zq`e}=eo#NvA|=P#U#p$I9c3gJ9$O?qE@5XvJ&k)PQnj54mb8Szscpl&ywKlb2ZB?Z zQYQ9jIz(=@y$6no6sb}69#|5ou*<;QSZcKKUR=FJ?%db0;eBbFSQNBR3k1o9hpIx5+Jt61j z>()~S|A{UMez`>Sw&2!4H!wcRXV*hyUCQAxg zsPCKN)0emUV&7u={I?|j{5%^pV?OT53! zm2KxTsd33K9y;{eYrpxMhYue)@_WDc)?2^-`+x8U@4WMefB5dZfAmN1z4ym|{QmoY z@+TjE{AYjm>8F4G=c?bb|BcguU=VBr`@k#U9q=hQ^$-?ua5cCN+yw3c-}`k|y}%Lh z0l4lZEZtxMz}i_|F;Cwax~r{5tjlgH{}(D*n%Pv=%f+=+q@S@CsxaRxH4hd}L5u1+ z(>uSMA1aMXBMH+qOBlI+p57@@&hoJ~E)P$`Y2CBZ>nT6eu{1hut30iPbUm~3D*DhS z%`n*^EuBs)>h$J|@_nFr%`<&^F3JC^X8B6rVtqa8vJTh9VNsWfR;&56kcKF!F#RyC z!&|%Jxf8*sg;Pl{ZET+wc?=bHRm+%4HrChW6g}~k`$zWBg|EB9X^ ztCjn6X$P&`UjrS_%KcZ{bNwzQ{a@6|{pPLoUhom9uiSqPFa1Mx8}|>)21DRA@E$mu z@?Qk*1$`i{+`mp(_htMm_va3ey>kB;GMj-ke+E675^ClCX6OT8^p*R2)^PrQ?Z}n; zp@F;_fBL#iFN3}ePF+88<^C*mj9j_D67H@Q`EH8dN?1LY=T}&{_mfSO8FFF$)05~g zdgcDSExEk%Z*e)-TDiX&`c1FgKa5VV+`q>4Xe;+eiB}tH<^DA8wXVbS?ps>9KXs6& zHn`ixm}eZv%Kh>U>=Fa*R_@;*?o%-K z%KZaKsb0soa({pkcLYeo*9FyBKc1EQGbqXV;Oe48>8q@Te~W8FK9jjte#;Bq@vPim zUZiD&7c2J~@2ywv;}ao%nbi3_M`|ngmS7H0@o!Rx%6$%P|&J9+DAFCl^NUB&hr?&}FJq=VQKg*4s&8o)5)(hNNk!ihm37 z>e{R|e>+%r8ef{h=XLM$?!|U+N_uwiZ(*(|tzY`LFyA>y6TLX>L5LEuZuFqizlCMc zT-k|WzA0%+{}$#^r>^>c{}ksEnHD9>buax}Sc|1Zi&mQ1(_$w>lrJ=DHr3+4f0h)b zMOy4>h!WD3*3HN5-=dy6hIxNA?{fIBpJZIqcrV0LI8sJ)8~+wDCu?y^$I*Lg{w*BC zJuLS?rWp?x3FxaE^nPi8S-xF-@-D)SNvO;Z%R!|{}$#Q zyMGI%te3JL<|(dyOnJ3=%kVZH*L+_%U7g1K)BOxP zE|f>nllA{bt@Fq#75rn=wbjGcu2Rx7f|rcg7L@(C|5oO9U|iO`WH`oDWubI2y;dIt*>hg+mH_Lq~j%O@sU&`h!TY3CcR+J>+)YP`^9u>*aipRW1 zMd>I}xktq%8hek5CC8%FE$>lD&wn6Lt&RP)gtU}aa^l=N-n{Nh9&EiTuL7rijyXIr4J4B z7{_gWXjrDMJBACrXYWdsFF3&z-Q>#yTaVczROdLqjo0mp(LFX{HqV zj;Q$1XeB4jF{iek3cPP8eJjRtyL{uNu@uMRL&K$v)Onicu&8;WksoV(YD>WR{^%;wi~6<<8Zmv^$=&Ylrp{dJ9Fg=3C<_iKg|cllKQZsStb zY0RTloOoqTTH6o8eg$iYTGe)Ag_TY+q7@rLbN7#Hqwkz!x;HM9smpRa-ZNaz@zlxr zj76oh{Z1g4x=yXN&gZGx(tC#FoMtpCIr@@!xM=UFPJ_q-={s;jt z*J`wq#(Ut}iKhNDa<`C6&xY%4rE4{&Tjgt>smp{tAluX`f48YiSz1(arnEz|ja&ZR z#+o9nYjYb!8T04~ZM|n$KI(J2NXNIY$lAtBd3RR!71h%bU)fhwkLR0Z#J-}sjKk=v z>?<6RP|PjZK?0$I)J&f^Nxl%1qIY#{3t4lwuT`*w9kO^y#`bRI=V>%a=PW z+S!=J4y}zFhldqX9RyvU)aYBWY7N^eHx2KNDJ(a!F>l`d`NL(7;#0PsOb3!aa-6ww z`wK5vr{aDl`H)zxKQHG$_v(qF6BF9QqdxsNC;H-lWTo*9(tsPmBcKb+19-SPA&Xr$kexY~Q|f=kDDDuTm%QIyeHR{vVVb%C~UW8F8Jd zrc;?+?;xc8ciw~7(Rljl{<0sQ(wIJd)~q>m7A#o5e&fa+J6?FYE`b+lkj@LN-zL6g9G4I zz?kk@y?X81>$tuTJOn22EVw$+{pmjFjWA=$v(K$wGcc$zUkB~cCtgQmYESP{UFiwY z(OA1-Q+XfBXY#aJgXx*)^wfW8PE9aQCbq(#@Y1xU5sZ*a_^;~*Jn%B`- zv9f=)L-ec-%9nAzLpYZo zoH_XkDk({<+p(+EB3?&hTKD$tP5G|L+sk;h_RQJ2jU6t{v@@;%J8{@vd#z*=!X( zX_l|BR)w096B-+LD~4z6%v_HZ8=EDkKkrj4Z?2y0d-s?16R(3YJ^xv2rEjJ_)6v+n zE9Sgl-G+4kB-h#4x@(`d)mK^~>+j;dSZ&eHMh~0u7cTDK;5MW4ubRZkJy#p0{V;$egm=+5ypy#+r4puHC&kHn%YCG_SwxsS_Gm7vpbLmfE{N z>)5hwN7=Wy8(YQgY)qcq-92m8>U9c5p!Mk;W&Jz#_Fvk+HS6|0&3e0L4s0@KLSy>E zf;*+z4@u3PT)Vbe2g&3X%B|knm@;MdoZhAT%Mw~+XJdGH+m79Ps=ZR_xz|r`+_JO0 zYniuta439pL&3H!JiZZyZsfqtU-+Ahcv}`VN`U*pk|cyO-MI z*!O%t_#4gl&9UzJ?jr4(uQm64f1hjZ`JTu#THicp{&fE063t&2tSU_H?w&oHwWoOt z7gpasdSk9xqbGZQ=by&c!bL#u{5`ie8ZU!4!TaE2@MCcDKWa420_TD2FKsj~FX*+< z$H4R80C));2JzcLPoT+@dwRa4)cSh33w`5#f8Royzn14+#e0>tX6@L`U&DH%@&%x; zsOR+G#r#dkH-pM}Gq?*p2reeixzNo(aUY{s^d<0G!F#iy??68QN5SWygKu-mo&o({ zajkTW4)!d$?I$({`SQ$TTs+~VvX>n=Q154opV*i=Q@zbPB*QZFlx%GjMlYb;$>J~1shp|K*3{f@?hMcdNbNofcz+*ZCR_<~HmnLD&_#fs*$ zOFB9lv*tFRyn4fID4%VNk&VOYiIPj)Jui>3#pww_7NLbuSAeYLkDPqcaS^+qh87D}m-@Kl;|pe9{;hi+-U zeU-*=y^)=)_wD@o1FW$&zewtG3e!)fO`kbyj>@qwmDN(B)`(PkgZGUnucal~!JDA@ zjO80_a`%iL-ul%VTCeV3Q(8Gl`kB6Zi^Lo(mA)h@?G~l@N}Hna$&H?#d5ik`maH1s z((JWSQr8`gty_1bcWDky5B+wc;`nuh(`1Pmyk&HyI-lHFvb2AL=01D(=GwT;Vwwq! zt*LFf=S(2xEM8jCC`ophc4yl4BhAJ;8-s(JHtpQGZ=dG)IwvnG(5w5F@ZI5X!CSm? z%}|A>dAibZAJ~<^CPKbNq8_I|iJWKj@T`AsbtS#yxlcQHmoeo2^pu%BDQs;>Y{@5I zl!pBJmM(pE`O203Wh(0uMZ*kP3UnvPS9AJ=t+$p z`5NFpzVJfi`}*7y_Go$KC(O`57nlqBz%K9(IQP$(!GY(&+u-a^@skE-fPJ9z|7PX~ zZU#?+ec&iK`!jgpVbBNGfFbZAcm;d{I{utFGPsEM^Rb_c8ELH;>B;h|kICgflMA>C zXt(g4(8=I=Z~(jk-UUa&S3oiyN120y?}3ZJjo?A>D3}ahe~0-W^!oQ{Dd?-+~=EUGCa09p<+y|Zj(mzztebCpzSKxG7JFR=<6GCYouRTE{tx0eEpV)yw=ZDOL z!CByTa37_45c(*167&G&wgkFO*Wf+S_)pwdK+os9Xllx73HpY>4xluLpeOow)}cQ^ zACSHS&^N%x;K$&!4>JEO=sDnga2vP_JOY-0A@Cx26MO`|0Fx-!CE#Z87?AF%1!eRk zTa0+U?gfP28h;M8Of z%6qt)R-vOu(ENLR)xJd^14qGE;M(8kj)B*}kAdc72ax3{#Ym8a=m?=3emmm>uCs+m zPY!{xx<&K{<;a=FjIiPh*89nxS(46}H@{B@2J*@(Ai3+Hw}N}X!v*hgXcw3Zc7P*{mqXAuz`NimIG+~22wVmB4fS)QXY;Nmx{&eXw`!K);n%nxuKVW2l zhk(*Q2Av9aftSF?K>SX0o(V1j*MM8W{opY$6)XU(U3B#qv#NCVdf&Bg=hXKW^bu$m z*aI#?b0;=4Spw(HI~&fq;4*L(knKnBOr8=mdpG23g#~oX%yfTx7xQE+t$!YKk#ZNN z_Vy`-xP&;>;Sl>Urc7J)95(fJ>o#Z_uy_A{#f^oZ;@fxn^qDiU{LW*W(xSzS`36dJ z%cN^?NV*OjJUEt~V~MApGiPDsT)Sao%Q9wrrfW{iC3~jBqKu)bMH?*YE5C}kZ_8J% zdj9#f0~>}mQ~&H6VziQ}4X2gq84J^<_sm(;w|pgbw07w_^)1}p)4QNdXGyfJ&3?bc zL9T1^vgLfXIo^~SE$YLT>98ogxxJgK{R7^Np7q(woMp*l^3+)&gdNu{LmYNohiu1n zxM;7z;R8-h31{>!m1Wl)%hEIVhzDIM%81`IyhB%o7S78!L@B4N-d$~L(#=ymaZ?$& zWn1Rd^A;>zr7KDB4tg%ruI_?vF6h#NP7y^@I#uIzMLD|j+(02}GkFSUXkK_B%4E4Y zb9&dCn=}oq+u^Y2NgBW1ItjC@te0}NOiIIgy2CjQZ_TMQXD?%AF!Gg7pgi*zZj{B@ z97zfEvu@rZbLOpBwZ3}CEh);~gUcoBvF$6f2q|0*woo zly3+^>zZ+tEIqZLsgA@x)4$HT)Pjt#oj9Njvu4MdrZg$FIBKsQJ1cQ}LumKGvTlqf zj0sx3=w0~C;-x#ah9ODcKT)TQe4cgb*-M$1i%$zopSfo3fMu1AxKxHzwr!4qJ73q( z83j#oNO2NH9Hm9y@^ztBY$n_KD|u2b+D?_ zf6!$-sWEwa&%6bTmo490>Xwv{HFvFU_7*gE&no38@9bRu-c)YtIJknjyCtH`wzr8H}scbW2X zYGY`Vbx7|-<`08g_NQ^@d?qxOF4HyE{b2t?*WCW{dDUDgljH^esag8Yv{JT}^+3f~ zr}Cu#r*RD(7XL4$Z|ffHcuQBTS)&>7;HE8mM}7~+8r82U|IE2_n@`Q0PaZS$jtvS^ z^3XNHZ7TYPV?}Albz4}WH%}?J)A?TP+EaedI9`+lLST&hNbW=I{Ql zJxRU&b}L^}|M}>j{%Q6nW!+zMXU@Z7p}F1Vh2`QF=p$f3!S65V4(K89KKKGmI*e5Z zDDBPAxnMIm0Nwzff^ENp{*RbHf*XF9dH3IB4huaU>&O}Z7jsmo_Ke8ty?L|j-dfdC z=~Qc9EBv#Jro!Hs=8AchQns6R>y#sHaCc%^d=l6Ox14L);68-LwM*OMj&=QVJoY<% zU)g@w({mL$*DZKj={$bR)J?SN@veP-NZPN!S(K{2_IWY96J7h9*qAeqopx#U)AyEf z#LRxE_zKpYjxlrR&R>?lio`V-qs1C(9$R`w4G-&^zTR_`BCe-OK0b|dd|pr0Gf82| z2+}2-7M?@ebvOExNE)27PI)rSShRFQnw3aS(8_JDMRVQOC5W^$t=TT)3ovq(1J4fT z49wA5%#{^Sk7KsPvt@}=*URKES|l~RZD;Ez6!!^3!i>HpBQ#K}-UZK8`P`vpD^^Lj zN=s;7GiO3O_oO?e_z8`tlSa5hTT0znPM1|u3~o*{YNep0vvnp+C&FBM<>K6k=L}f? z&}L?O=0!Q4I;joGk@ai0rdF!3cxd8&P>+~$i4)Ps{$<`UuzRWmea-m1wp42 zJteJuZ;-uRCtCO`fXiwfbxIDbhFc1q&n&6+D`socSS__Jtjs^=>ub{Q*j4+I{*LTZ zvwIizJ=>1~ZCCpGuza2JRaiU6C5hOk^)NXuS^8{$X&X>HvzHya%5rM`UK(im^7K|K zjr5Z8^w!o9_r@vMh0P?Ov_5Rxl`XvKE?A~st9qGrUPEj9bLTEzynF?Q%GJYL*(;Fx zk#ty(X-x0yQyY|`r?i3W+Cw=;w}CjNv@&Zeb{8yVjhEvQ?2~rRrjmCW)08X5QCnV; zb-QdUr-;;b5asTseG0w3I#+@p&$8cH%K4b4{DP(DnDZ-kJmgm1y47_vbxEDS-VRe} z*SS0caeRRVb@iI{gPYkEUf?Uw$bvEHtNA>Ah*J!jI}u@hec(1 zQ$6O+UBq5!_4~1Vfb=lGoieR&+1Bm*oAylW7iHvjdzVP_Em1Fd-XmfzI~3>Y+Pg!{ z7iDdIjwpJ0xOiWPa*9&E<_R=?=1_C*g!tTjmJnym)-Dmt#q^BvZt-amc0QDU@l4)F zeU9TImWg$)!_<6Hp4!a1ed;4UxpeAWCms@a!B6D0qE3g^bR6Dc2hSYo1w|)Qm|y)! zarBVvA7l3(`Qc@@Ew1Vo&k!lBoiL(&YiOol>^G5=Q&8?U-eFw|(e%XC%sTJ>o7bEF zuA0uqL^*4&mqTINd4zXZr&T#)TJu$Q+N^nh^j1xGNHLPqE+M7#ZXxHaILRD~k67pG zwDqv^kWS}8+tqx;#*{80eKYxpwKnm&AHhegQ%Nr^J*tn`DC<^pnViG9C%hNttkXLh zHv;*HeGvKtSOyM*Yksn$@glhLjE=_h;Ecc0(RdKN4SslLN8@#H_D^**?gV?lch6!! z8+Z|%_tPDX`@jM44)_{eFsY+)Jy-(vfRDi?dc)@(Am5UY*wg=jum6yo%(D--P*9pH5PWj6n$y?yX&>w<_z#_07*hlOEu4M;k z(Bh&e;v@E>pXg{@bZSTP5&I-`ygp)kk(H0wT~PUmJt7^yl06-!^Lt^B4*L-N58fa3 zlApXGz5*S5wb2;9KHD^2gwu$Vqb;63(h-*`vC3%kAcnL5cmpQL>;1!*n0^p5B4ZEPr9|;Q=^(*dop9@ z@3Mme_)p1Ca@_-#fFZC98T*Jm%(Z;P&bSsk3fB!vIJ%G6?ys;D{Xg`PU*KMWSAqP! zzVUUYm;S$*-VXg3T>Rr4=E+q4-SrA|jPwzE7u+}5o2Gh*K2BKIJijzPi$4kaxg*M3 z5zB))zt9}V$;L!4ss5|E+@I68IPcKGk{$Pu5BNNucXJfy3f1Dp`S%?Or@c;304;&U(W zos?&+XKJ>&W@{Da7HKEFALGeOow@wc#oU=6f_uOWumijaPMgrtI2YUnR4Vz1?csV5 zoY|3iPe5mY9pF&G`viK*#LT+@dJ~Y3*n6PTGr6GAM{FOwL*OG|AF*e3b|fFMS3;HU zZs;KRqzGR`Yl_dg?c?wf`{Mt{UO&*zN9^asokc5*^bz~@f&5%jueyY1`dlPcj^pzY z`yM0iDB<)@yyPR+GNR;D_=t^MY0|7~>eOi!AF*{AhxuY3!$+(oO{srNAF+<7 ztfh}w^EBg`re_5+0)G?wD^w+>F2P5vQdtUZX*Y{`qG&69#5xDJzQU=UOCPZ@Wo&0! zX@rkhYjf__N{*$E*t$N+FoRHw>yNP`e8fhb@mgg`wPUwT)JeZ(w@m$yvX+Q7P|hx? zDYep@i`_IM|10acJO8aV@#`%wzDxG9S zEB;;7OY+}lu>i2-KeQ?RP1yO=sq-`6I%7LIj^{(MM@Jl5s^TM7JZp0cgp|dqMUk>O z-{ddPF=br?Jv;b_wLVc=zw{Anek?t`7+WH}N~gEV=T==mJ*e~%Yb|K5_=q*%wIWUF zBi3=WM%W9KN2%gmB2%?1CDW5tcZyv>v862~ibl0kOCPb$RdR*KHa=o4DN4RAe8ffx z=_)*H>T8ZYL}UH=ww^kMd4JieQ27I{WL#6_=yr8&B4sqU@evzyavM6OHPU-(K4P7U zdzi+bQ;H&8^AT%ldPGYfv5p^)k66n_>hjiUlp*hyK4L9He8oqs`ECPh%D$ZZ?_9?n zyN_63{Ll5lEj+tw?qJp9ZmDQ4CQF>g9KL^KD>IDv~Ts*gG9$FoXu2DR+ zT1q;6O`Ejz(CT=%gQ@v^rxhMr#o_)053QClbuUJ$=ApGNpE3b_VfRaTj_8sNLP9W1rM#( z>AOWwDm=6*2I+E*zm;Z6q4$5qLu)I!*v`tStvAdO9$M?=b2-PNu@uMRq1E|C>b%Tz zSkyfC3)R%|jypCFtxjbv$4Z@ElzC!153Ty9Nj_Smyh>jW*Yo%DPkhUk_j61?txi$b zI#yWeoa0!2TAfFo#ylM7r=fM1H5t=St2IQe@$R?dE1h$z%;VemX>~sBXw1hlu~sV6 z@%U+VImc6{SccK$rL(=CR+qj`t=)Xrj%RC2Kdq8;n$f7_#`4qZJloNz-!d*AcJ6GC z7}Za!Q$&L72dE1E02 zfh7A)pBH%iGS;7eJFm{@yubp&%RoFYu#d1-Z+u?hb;9q1j=$B>I0q>1D(Dkn8CVYv zfOo*k%L)H&_BdR@UIyUv0v~dH(=T>3W`mOoA33{sXD>NJm*sJI`(N!yZMLX$etUv-EglE$~VoHsT4Kv`HRs<-=yj4s)GCnxvf>RN={{ED|V<9qYW$J>gwF*ZNTh@ILtdB^`~2!Det2T=)yD6@z~87C7%x zcIkje!2tLGob%tn1KnT%90u=!Pe2F#^9*nmxEVYQF4nv4ICk}T4?yX|L{B%Z0O?=! zr9a^x{>_fY4d7wW&dW_Naie*;SxNjs$$$^RS3n*kPQRF%;(g;XsJ;7M&-HEK0q_)9 z0EWO}@E-UC$lJ{+w5~?zl?6RMZ#TUcbTnQ8I%)F>bS!T-UmzoIH)s3}N&`I~TK9JI zC^9p^x8?2T(D!);fiJ+RKVYu`o@>++_I7hNJbAmh0eTnc0c*e>@ESM@z5?e`#w$Ve zc5??|=^Bq`o3DPJKFr-4&9lu#l<_(so%cZ>1@dgO2>Lu|eSYZWzfLQEj}qg}#-44K z{0t)sd;uOfx1+Hf$g@o!vOKjI0rG4!Oz54<8wm%w&Yo>F<^^_oZV~-KIbyy&&o(#F zIv>7=-yx_x+uRF{o^2i{e5{^rW=jVxF3&bEaox_d&0ECDv&~WH_shCYE%(5*_iV$T z+(z|n^U2RroAY?@flI)(;4bhKSOE3_`L;O>{Sci0bL?0I4}hs)0T===7U4Ic9|8Gs z{sP*`$AJ9XoC*CtxDnh3^t9-LE(4pvA@B+KE;YOcjP0Ff1|{zUYrr-Tz0geR6Ni0CjT4?>kXQHwm1zE$!CkhqVm}ys<^4M=BDoiy=!x7 z`J=Wpx#7peA^S0LShSPxn5yRz$C7qse>xSL_1bTV;)yH#mJ~Yh#%#|e{t8fuC}G8G zNlq)TCAumk(*6yHMM;(XTI*WcL@8(ClO#%JY561>-fO;6BxyX8>?*%r6swrJe-fuM zRhv#>9_g?sUpef!kPmEmD2Xw#uH;$sQX)wKo$R9+PAAwERw~Ug%X2`b7ZU4M%hcgG zQRW3BypV`*C~cHCpZiwqa1e(Qv%^6?wk@lY={nut^7|9H%vOkOa@;QG9AhBIc!Q?iJpt`zL+jL5;oaixC_2;nyY-2xzsU!?y(pknWtT3fb z>+HknPX{pYNRitopBnwFrCxV{#G@DS zjSD=heV6NY{v$4CE`B2ZBihY~)x(0 zKT-b?i~#wH*t!juJswNG&!Rk83cnC}yj1-{#9krkQ%8((dApL-Xro*yHLiK4cFmkw z9qW#h4#8#o%dI^~?7`P(Sr5yKN>2>?+Whp4pFAafr<*4~63UbQQTqdcOA{$?v*Hf` z{i()^^RrgD(UOJ#2F1|sBRnpMFUcal;&H)oj+e&;@hErtV}Py&9X{PGUe!0BfT+5-nv^+G~IjaUL-yA%$$_J!cQ>Sb`)IWUh4z7SLf?K5z!sZ%L$YZh(o5y28p6{+Jy z`8p3C5eBx%CxZBf(<$s)>$owrguPkLmBrxnj_NS!MF5)@}S*WHv7*8C;t{~qmfa4P4-TcPxtP|roOl%({Upnq#P zebg^q3TNL5j^R&Q{9i*M#oL2|W3#;euVD#t;<42H!-jLR_L!0)T4_uGYbX+2WV51?bO`)x)_>wfC-yqU{&KaYk;(O0bdiA$*X<3tYW zud|lsy_#1192V7zUzXJBo@3C$>YhVh-E&y9bHwVNW1IgW5C=`gdY(d*pt5S0CA4a% zE4|BA#wok^q>}jEjt>4IAPIq-i}gCEag6>(+q>S}q=}U}hehjabTO{Xoi)11r~T6! zomS`~U-AOwsjbdQN}$}u-vJcj3#vIYE!X9&(b^()oT%qU@$UfQ8%h`D&8G~-x|}$) z3F~qzS4PQnhmwV;kVq?XmXKajm1}Y07jkJW&T^t?;_m?F5Gq#T#L?dY3YlX4O(Eu6 zUDf{pICZ4WwYJDr$!Po9TAL+^sjamsMxZw3x|(^KbF}mPZy8g{oYvLys+zd5?R72C zYswWh$6JHK@?@Vq|BI`&G*Q~DSW8ogl2+Ez#G@Z*b~wVXz2Xd)A?Ay&%DS0k$*u5A zUxbPkGlh7Pjk01UiI_{Sk^b|mm_l2z3YJ4Uk?K^Vt#V0*dl%NS#BoY$QLbf~M=grA zEO97zi?uAvwxZ}vYgsW)_qe%|r5MM$)(S_z?T$xVxqcORY5mIKoL1{sYu82|H7VAt z#H9xnYgT#1DoX0Qxmu-AL|mEb$-(`cPa*SxLy8?hyuzSYffn`p&J zJnmm@#YtRAk#l9mN&NJFYqR2{c-fq@T+?^4!gX|(zKdgwa;04hJ9E}E(#|ZtTZi&g z?97gHyzI>4p%pu`u5w78eJxA>so9ntV_LLEX-zx$BN3cZ;m4mPAlr# zWutwuCvV&yd8r@uKc~M_R%De%AjiUntW<;w8?r(pEydzS?atYh^jL~5#b|6{DIP67 zH7G5`mXoDe*VLr66gw_bTD`OsZyixrOO9qEwv5{*Qpbs+qh=${7GlL2ZV~Hndh=Ub zhoh8JMr!T62ZD7t+lC!y>U7pA+S)E`38#qEaiZMMU>BBESX{%YVv5!lVM{ngq>d9M zznZ69aU-14soL9uE#VZSQORoD*cM#RQDMFrDpufj`YoHSve^n8^~H3$Zg2mMlCkvW zi>k$<{dem&aU-14si;TA@@sxwPJCOJqo>@_bX!-n`I=|_qKw?q=9?|PQLC@Bwbvne z%GI^)yylC_Q?4j_d7MN~xlzj3Jaa0xUGcg5rES-8Dygq!+tu}?#wEXa=#c)Aarm(R zi_z+@82OJFvMhi7Pk2M#$LtrJ1+a7`z0!{wdz)?q{9}t^@1A zE8ufbwJ`4}&d#d5vM?)5OB5Dn`NoYBlDZZ9qbMy=+L z@SIB8Xv1l<=kzjf>Q6bww2G&%7N=5%hMMP6q(SW@xLnpc*4Y%vSvFovmvYRdYW{aQ z$|_D_S{hrlV`!1m7Hu9Qrtn9*XOI59Z0(MZr9StB?b5H^jRghBE`8>&VMPH~g8RTA z_#9k%4`)2UX7C|6{~u$a1q0wU@FlqL-j2ropdY*jPNg4S2yO%Sf=56%SOi`KZ-URk zw|he6y}Phvg42Jsy>0qp;zqMgUq$?#;7KqQECI4T4MAmRI}G&+l@Gc89GpUno&zoc zH-Lx1Q@|%wW^*mO&B1~mpN)Fk9jpZa*{IL>pU1XQpN))c)R#hKqrMJWw^8?@ZxDQ2 zHfo(v`SIhmeX zST^e0ka-M9=W^&E&%9gG** zs6XMlosGJKmX(cq67>6JUB_di9_xh4t+(=w0#AZIFbG}(AAm2x_x@3~QeOeR5%hpV z;0^FG_!69X8>IpYUkSYl=!D9h&k~;6Dmic4QhW8xE(wN#BRdRU0_yR{VyV^%mDfo3Huwne?yXs>?=G}< z6?86iY)kd+NXb&Ie$V^9v{ZXcM2fz`QY|iT*7Agk!g`D56Dm%FM6y>qEGm1oD7vs$ zJBASUYKLsEc38A?guU9aO?$OCXe#X03Q>ZJy*f+CUac#AF{q5PS36v!N~cV8ty+na ze_^$bl36;RGBIB%l5{#{Vy>uS>K5!6UzP_8cI4|TxOvJX#z>=53FKL`V@pz?j^!y6 zg_WwcHQTzaGg8Niwz6i6Zzx@qH=nyxShK~U#KkES%c^9$PIoccvxdE4MhQ{VOL*tS8c@l{<1(QtDZ=a$AC! znw48I0<|cu+~)D!+SbZ#8B=5{r$@y1T~Q5nZBW0`)}2p}Sc_BTHnGK9Tv@zDX~n|g ztq`TISiHq+XYp2?;gYz7g|3RlyWo{4MHDXXRblrQhv(ubc5g|mx$M z8!hinDa*UAPYJun^Z5{Q?_*XV>VBbXp8}zcS%a(Y7?+&lB`3I@Wv^G5veoSMmZGgI z_ImNtTfU9GUh#i}6CxK~q%$JF^h@8=84=f1RBa}zTBuf{cimY%C-OP*UxVl|T}ZeCq%|G z{~D%Mzl{?j*Hh9HJt4xgu{Z&e$3yi5NW9~^^YN6I#<0$RNT%H=RvPtdeW6dCT0i}v zo^J_h5t`$9<3WY>K5nj+`PpS@Q{ETl=?wEMD~;5$ST$2DqkhEc4Dlsd#8+0$9Orng znu*5~C7sUDwUD2Hv)H$rZG;Ld4Rxrkpjo4-q|jEbpjjj3E>_UQ@d}z_Gp~9&qu{00 zG+n#QJQs`88Roiu(%T}fso@)^@~y43t^*}0R@RiBP_eS6(8!fFah*>qN_tk-EJg2V zv9i`Gooho|l`CtO)5@Bzxx3}cn&Tqntx~S6=?q4UvwqilwDmQoQ<^#)C))lDhGGrp zY)#_36pm}X$|gytYDJv`vz)NX<}(j{V3l<`@py8T>vWcPTPdt{x=c51(z{dZVFlfi>6DqG9SyB;=}MSbtZX@)dHL)_ zq)CuuaPhLc7FnsA29i(l`k;Pf8xiY^a%FI!>lfXMPNA?2Css53wr9m z%HhikdM9);=mo>zAdtN1sSjeA6@7$n5^x2$4%`av2akc}U=273_)k>&_MJ0lxqS}y z>tE+<*RCu6)D^v%ZQs6o_c{L(iz>JQ+zTEAPkz>B~uJg;+o1bhsB3{Io8 z=Yq??Rp8;*`4b-WUcj@45>1)1eY@6(KYEDs3ZPS|z{~%F6&omTUcPnTBIZ4CMq^3# zoA_)$r5|}Gwrn~2GJbwY`#LxZJ_o0h@*HqExE9<9?f{R1CqW+=1}}k=8bd>S_UzxU zmD*v_?g1)`^c?};Y2Yh*eqZ0S&t}h!=l?TSWWa?FFrxvtgQ;K%&>F_qX@yudWvEP_ zgrwG=y#}4vFxtapR61FT8LEIo<;v0IJy|&;?)_SPy=#xU2jL zwcMpXYu0RhwW^f-5olrc|7`vJt5@e!EBT*nxu@>mf8Rf+HNXt891Mbk;5G0z_yl|n z)a$+nZUDD{`@losNzhY-mp})A?Eagf2Y|}{67((bA@~Gz{zrD>Lra}av6aNZ$15Dsq(4Xl3^gKv2>?O}Ww|dRMpzlkh%-j1E<}Tx7M^}34WZSvr z$S2v(9Tt`CT$KKd?c6bhu$?<(+quJ8e#OfE)#kAOY=^F)yE2`BFw=PpMA0{SPpO@9 zBwM&*{A^U&hFLck&(PlO{G^nWB;;esvAKTJy0>pPN4ab-~E65_kc zF&&L9JDaUS96w63MunP^?04L)m~2sYdRDXd>6$lF&-T6h%X($W>C@*wt1E$j6{cLt zaaYW7!MY9Ueo3aYv31wJeFwrD >qYnIiP>}>Gk@%alE_iwP2sOmeRvAyU6`EKfI zqd5M#nM#XQEbUd^)540G<<<^}@+8N9Pg84mZ;s6^OZ%|1Se(qw@97DRm8)`i?|xD0 zyKP6=r??AS#qGo^LU;G9S*zD66oJ;Kca%M#v#?EO-M*JuZ`aI$P3ExcXko#f((Hev z<_@l1+pL3Ratq~F?`%w&!d@7>&$tZM*t97+#*};g^u{ea%eyB2#K!8uq3}(S^B63? zWtJ|JOx~|+E$sNfQ;b8h`RRH>V@qlu?pSIA?Xnf0H)73p;FOWls)g;qT-Szu{^_pp zj##uUJtrhVXyLYU?8+7(E`2T80-}zN0T>-LSu32^Pb^b zizu2a{ujjKeot-QZzNdH*_g`YvcsGF+=#XvNHP-|YtpDZsnNS&(fUoBw(Z!R`fJR! z$c0(Dxt)!^rO&QjyKY1J_B2-%3vVjDX5b2w_mq9LClbAC-h4fc%DX2?m6o0{1&;(} zKH^uNUt5|_KE)ZXDYC`9R&(0s)4wjKFg+s8LsgD_l^hjojYt(cHS6V#I{B8I+$=Tk zxir&TytrCJ>(w1=N-Kvvs~Rl_OQolHrQKpVcoR-h_~b@U&%8x_eM?qpmSYK1*DcR* z%*`_#h4P))x^>6i{RbQ?$~O!n-4Z7^;u&*uqr9#sG`6O;<(~7AHfQnDipDI_-JR*C zO_!yaP1lx8r_2=1GZ2bc@p^YwfK7b3r z<=|>?3%CP30VadxfIpqIoT=1LTWgN;$bTR$SOzwOUEn2f7`zQW0-u5(gVQL_S>OV2 z3Ah^E2<`y)fCoSipcjXE$-7Um;s8$m_sk=}d;gB_NhsrkdCBX<905PsNZ#Dr&Pu){ z)kolDWKRbdfXl%R;1+NPxF0+Qo&pQN5O@*98Of{YI1E$@>H8GaXC%A+4X3}sn#cHt z2QP!8pz&|j)BF495=T!jW+dwg=`X;->&z4LjKuxuJH?E|^N}aWZ!+is3&1w84;%vL zCY{=OHTGOY=Vd()*|yEIkXI<-5%2-{5;W*Jr-O6Ah2RQs9Z-+D2h0V1U=0`oJHVkL z{08(b@E-UGdHYnL}NdPccl`>`9VzQ>j{mu16h8} zx=g!!GtDhV378o)rE@>f%pgnc-7lJF22H8qt-9_kX9kWjMJqD{hq%w21#I>(@%ejr z@eZE8P+?Lq8*mCjU2E4mG@+5(a$=eR?6369=C{A4P5tffuxLm6_BUrjW3YJtFI^^H zXR%jcaI-?+K9-@tj` zDsVHn9o!8b0vA5Y^P05RK1mv`ujI*pJJ;RNiP&5=ZQ8t9tD7p9Xto&YY2MwPSIXL1jmFF1P4GVW82lIBkUaF()hhRR z-+oi6>G7^<-+U>%9KeI%V)C2|-3+vreGX;$=GL^;_7mw_!^3&Z>OKf3mHq3$0m;N3 zrud1CnKL!h)V1OT%_>E)hA&;&|NNSDo3^%mCQdBQZaQ5~yCRKZo<__h9Yctjq(hoX z>Y5S9OtQ(HH8*oLdo(xC9v#x`QP-Y5nlH*TIF%Z$%orV`(8e-nLd+E%$MYb?XqG5m zoF!T&Qc^QZG^aUBG{;o4L|to^D5`gkW{Hk3cxjec<>mQd2V@v33u`&zR; zUE@otnDsS#l4V5me9s)6Gt;%#vdkCNIWy6dnB)1BS&a9!W_P-#rp4^eF{WCl(zQq4 z#eX%Ay86fy|KdqNw2+A-&wPzMUB{8k!P7m^T;!&Ir7Xg)yUJe zMxLlgp5qH%8hKS-9(j>h9eFV(UROt6jEUEAhI^rds>IhtFT&gZLYSKsW?!QQXMb- z0pFs`XZ0^J{r9gYt*mJ;4(n=*7V)dg#a@kUuBn#g8e}f%avji|@<%^X4UV@g-*!6o zG^mEpF7IdQYt7mXgM%CS|M7TpWrQx`zhxD9{z|Ep=2hIP^ee}8>o@SFxY;Y>71?8L z89fo`2NfOcThgxio>{Z!s4U7m{YBzO6{+#$q?x2v6{pYa(JJbw=_v`FaD7FF^s-_k@U3{^(dhUpLjVeZ7*V8{b zgMB9|86$6yKV-8wRWA!MGiFxCq$Oy9rzg+ssic_D*tAJHnI$LP&@DMUWu|Dhm+DHe zz0~2%%l6X9%l1-pn)Xt2Ol>c9SduNd5)6TT;1GBfd<=MZ27BoPy-0&WunpWej}%ai z3E2jCU|#v-sBtN}w{ENkim=zJV>ff?X=FbrM-uYotg``}aXB{+?I zz7MVhr=>^%>@*S)8v0owL~s0WJc!fct=K zET8m5`|2r3elb1c$IxtFb-%0ISKph9wGw;^z658J|GD4-(bUc-Vqd+Oo^=(t0o(=d z1CN5qpckwJLqI+774SLu8k|Z=&II2D7XXDX2UmmZz)j#b@Bnxmbb+~GIoJhW0&jt) zef4y-P6FQp-v@dMZQJ(sKj0BWsA^>$pj~%>SHK(KU2qie+(}l}$GGkTD}k)64<))k zJ$HCImZu`!=8?+Es<5oAqS?x7335nQR)@3X)9KN-8 z=o-2!)AGksIaXFy$EqhRU*QlkUAor3j7(Q- z%yejQK|lYK|$T!OH58t*j1<%F3E)z9V`93l6KYnETLF4OMbOmmBI53sUsFYoCWKczf#Z=iI1Ux|}b?Ah8n#Q;7c;9a?&;NET zsCQAmZ_a|MJA+3a{b_k;9+A3Fy2qm534KFnfh1k;9hT?aQU3qM=|z=Bkd;R?T6r87 zsjWPbCo7M_*~;UXY~^uCR-P;)D^HUTM(Ys^be@vhq}U*~$}n zRVz=7iPu#tPmGDz-1pMH8u`8^zO?d~7iqTgn8S0Xu&d0Jm$#Cqib7v%omlFM>JY_V!W?q<fL+7Y}Fb(Hx(u2yxuYom2#SFI3>rj zJ{z|U!WWT8J(APb^OigI>mKX|FE8?b1E#uIYyj4UC0KB#A0!#W`_9R#ETsH3h zyx#R2w&=uLOz$-6Wm5*$?c6mYHno&$yluPABvj(9-8AKl|B9G{-X~8hJ%34+2bmR> zSmp23rj$iH&o>U0HFpfB(`-wdGk5MhRu5OHP9x+j--@Dr<*L*Uj&&PgZ{k$aoVoL4 zpOZaAe`VKMjJ<5O<$q$aR!%!!n%cj2{_+*IzTouSX?$ZigtY8X$yyR~bxG4bk$q|U zj1e-{VOj3U;w8^6uaqABvVM(7>ok;RaAR2-LRe=UhrY5GnTJHUTePr7CH6{{#WK21 zGkyEgDD}Iq5UK4h_$RWMnE zoo+Nrd#Y2nXff^^XQ7>zJeRNF`Q@-E65&agN;R~pB7t`GRGu6$omvBFS#K+RYCnaS zpYCtX+8f)C`=pc`_zEjiyJeIMc`jVEcu5P(D0!}1A5s-{SiPpyLydTfxvXe~i&tFRydU$r5V@iE@ z@1a-@i>4>;yk4y^sGqgCGf}#@Q>*%U3&wju33*mqk`kyb)~qc#jzKQuP?VIO>v&V- zf+d_#kRjFTH7%dXw9N7q>hZOE>XM>oT6dY(>3VK1Sh#peKB1;@sZ(^t>WNEYy5J|W z&3Y_KpVcakEc$#0w33!aN)nzbgcd9;+mleZM}*Mh8gK{o!YS(@U8%LV47cvzypndN z)RQLW@>9Oqc&WidD5nN1F|KJ*zVMwx4*k#ZhwSQ_k~9+2_4Kl5*AA2=R7s2PGmT2p zDCF{s@??6NjR!M({{Py}KiH}&%kNhnO&dZpG$D>Ljzbe04RIX97-J}77-9$^h8T;s zEMhr^vaBx3vMkG@C_@pz=MxYgPjmoj#MkuWiGc8U(1^$&Lla|c+NN!qW@wtGZHCx1 z%`h}^3}sRIeD~hpbN4;(-pB7hzP0vVYwaIrpL6y;XRUMA){!h;^6JvkDxdcwFUPTm zXNp{YAzw1h+=KlVw1Fj{9jpT%flt6m(EmqR3Bho1E4T}M4yJvK#Sg3nSN|9pm;}=7 z{`{Qit$VRm-lv+e$a|X~jrdDp?fQP3F3UTjrdmox{o+JV~S|uGJW>($UxPf@*MW=ZfFzx?RTQT#xwq zUSgK#lzW5tt>$pVMf_It!uq*-4L3m^z132;Jrpb2w{_+&`d{0pzsvuBK#^OwLU)2s zz`)H|>%lT`09^Yv))CMOc7wiKuxEp(K|A;u40;C(1$Y{CgO9;kFkmY-ad0cR3w#qy z2g|^fjodnCBXxh!whvivkz0=-@4E^A54Z)428zWv5vu5u&p`cOZ!76#pbP8* z`@t!2Eh9P{ICAUlq!k_Uu|zK}a_e!9Vxt!LNc z!+?J!Bey=bj_VD)0?LtFSHM%`*1gbA!4Ud$D;NVF08>FTSPgc8JaX$1^5+}5_0U_K z9nRiya2lxG7tp>$W*q>o1A}OPERkj<8$tSM(u&-Ar}&_LJ*-5tFbO$-n# zYc`Dk9Vq4j@3zH%69ZS{bq05U`@o}M23QWd!G56q#ZE!{t>Ft`FdfVT9iSWR28UDr zH1z7V@el56pf>_XZXHSbLGTpNY%w3I$gQ2wt>7pa%n{xR&M$K7o;R7NKsj>jad;Ja zTrYC#W@P6Zx%DA*r+^tiSNw%WZf&95D_{lCvw3@3m11;<>r$Re7z>(QD~4XaujN^P*S>n?)1*NoaRa;y0&5wt_(R&zxqDMxP2y-YSx2}4obU2G4a%<8{ zkz1{&`lZW}6_Hyd6X1o&t=2WKnLmBaQ(4+bkz2)$|Jf^*WGQm1IAQ#4ZQ5QwHs`C6 zTiuE&$61Qpnn_BLTO|=ViXw8Wc|2n`jNED+Q*^^@PDHhp#Gk3To^*ujwGp0#!(Tf~ zmc+=du0>Q@aZDV!Ra`}G6=f7tekH2ddmI~{IroWGjCWSoKWDdoVxj~#&$+=ddy#~YL*7N$d_sjfY zwR*MwvC_W^Ter%~?D2EjR)()}WS1JJ^akGU9?~0LdWSl63(sw&j~?S4gf9U6PuAn` zZv7*k3%^mR3<1M{yzzG=dJl9eSOKg~ENxhfvi-dSR)y63m&u3kKBb^UOKLmkJyBTT(pBREJQ#AJ&A~RI5+*zcAnX);49nE#j1#XI<6E z47&8S*L@vx*Yt=}>b6CZ*TgBc%;ojPgLvGLAvTH9LYzTjoKojihGQtjDV5Ze?QA`pq#3@zUtuU{oIHl%#eCXZmXNx$cmYPaSb!&$>l*4&%Jc1owV0*q#3`*;&PT&o6>&}%mzLwFOP-n0nxowqHT5WPg*2F1o)Qb4rE9v{2xJzJd zt$9h;&Ux1p_Wahig{xMxr!@XWyhLul-VwMKQH^2z-e>vpcMM$mHE5|voKnm3Qc5#})x;?kkC_WI|=c&t@8RlNtEvfc|!Xx zo(V~}UtJwp`F)h9ro!)&%RM%ANT+Yg9)0NTMJFz6$!+~66|2|fmceuxDg zJOMhv``|b@1N!XY9|dp&xCcB4rh!{@-|J2B+2-nBf%=|Ft6z#vn*9%$yjbPvMY7-W z#en?VMSR##{x^Trfc_sg_Uhb-tT(UDNaXi}r@%8{4v?L85mc7xZO}d75I6=0nfr&3OeKd2`l5<;~d%Eqimu!Fvc? zDR0g;ydiu47k(|!=YyW!oI&v9%^4#Krh_)n0k(kM-~c!ShS1O4n{zvPjp|qV6G`ub z{MpwqV(^2se=cv%Jaq1$zp8Ty>HA5`o6|{p6R7XaIr(0n%E2AA-kfcJ$$Q{Ve43yY z>;UrS>_C?pDS2}aklT)jQ}~p0^ycW^7Uazly{WiMuADdL{r96c=Od`RIR~M+H)kxo ziC{8#5@>{`L1%(iunFwr-q;D<0}g?cs)PGP-kh5my++=gyO7D7GamZ&;#ix{!<(bn zSB-r+d%j2fD{u-7*u}X3w}J^^GMEkI%UK3p4L$`!|0gq5JK=Z@39QRrHBcWr#Q(y_$0?zHn(I_sY$L-(@>486wqpcBN2X7~+=f{}_ z|9t&8H=uh97!6eKh4^v4NuS11?g8*9;AyYq$N7Y7UA6W}wGV=x+mCY~+#&D!*`V;_ z_-@E4^(8-!xa9ETc!i7}9BZ?#1`m$&qVnLRa(Hkop%y$i&e?|qX#t}oTwoWj#BEi`X~>M^HF0a|EVb@&~ozKY5E2iet zhvcIXhcUrNvwXSI)(mGTyk8`Z;GMCCv?x{hWyDW5%RpX0s>6})5F*#Q~W9&=57;7LY`C=pyIGVy2W1ikQ=FH{m-V{MubsN?( zrO&|^6Fo8FO4HP(xN3_1^DK7_$}^{RZ`^E&{4bI+X377e96hb^zlg_mptr-8`FzRw z=ZjzcuA(rzmb`xPaz1s{_+L_M_+P9=+sX4H88cZgo)>Aj1yjoNN1^*bF1;VbmgH@5 zDc%4ZdRwH!xy!sQu2Jo96ot3Nwb2ssZhaK=yNZS6(Eawi@9NuL zNi6lzD$jqLD?8unD#kzcu<)?B3@ro?i}SIpJS;0$<~)uhc~!*a3QAs;=u^oxm9F|z zl*^I(Q}R+CBl;8kDb7nL_oTRtJSj@Y*wac0eM9VN*@MmTn8+s*HOf8_antD3_(a6# zI9uj4@QFyS|KXxu)vm038GTc{vG$^0(on06YqBQCdU{%ut(oLC)?~{(TCygKN3B?s zm5R9+T4T%73zWN~akwp3Jq+C>>{Y>a(z-#D{ajn{0H+`Mod z1$*(<&~Nia1&$+GidBkSvJ@-V(^4#MUVC0!DvzbuTHK9wEXBQ*=LiZ*vGrsrR+=Lz zEX9`Plu<7%#T$AYt2KMG5nIP&lT*t?sU!TW*V?*xF+WFOBkkI-ZQJ&6UL?e^WcGV5>`n-Nu?*R11mu2VF$+QTkv4VTENWulzV%q}deu(*axF*ag;Y~5I2WQx>RFZur*wwH!5A-H?{?rTU4HBh8inyqx!8It+LSy zoY$9^Q@XMJH`mO2Z@#ETEVut|=oUAJOS%-tQDgZvzpN*|t;tumsu*IfN$sS>sZp6YctI?0w)UI05<`#j*)TBzj+>QxjbT-3)etL*O`& zzUZ)h*aQ9#Z{px~FcC}!Q@{++0y@Du@Bz4x=tRqpP!_xo4uDUcbHmEExW*epuVWq&pNNtALpaKzS%X0C(%txLpMkI()LIfEEJ_aq75mPa#(SkQ?C?l$azsk8%ml)8?q!u z8>;3MZ79nTZK#@4v?1pdZAfWa3ekql7uDLGM;ppz<+P#=iO10pZOBrNIdGX_pN&#Q z8?qE#eo%A{ota82+EApgt%-E)R#8VAQrd{ohMZHhA*ExqA#=HBi8kb1HQJClru2q2 z$2mtEa$Z!?h9Zq;ME8EoZw@_V-75Bc%F8*eXhTuIOY@mFu&!qc%< zIB`XDaE4|*+uX7s=h0`Z3DS=B#Vbcq;A8%scO!l4EtS&ho9OyTpPefjS6`(B#{+ae z^5Tk{^WutYPIbjK$J8sX^P*aDBkk-GjVrD-E_KD7_Djw=SPE8v&EP|DDAB&3#Qcav z$3v%pX<#8}2hta9{W)_z^f34oT+PaI4Y&b}1f#$tFd0k-7qa5sf0(l18PEzAfez3O zwt^499&iX82dBZ+^lK2f0o(#cfiYk_m;!27+#4uy3m65)fT6!Y6RJCJ_UwVAt^wy- zaqpzm&0s8;0KN&Pf_Y#eSPE8w&0stD7#s%`>dyC1=?`x(P%l*9ZJ@l?es+Kr;AeP8 zz**4mAV&a31Kn>QA@57?Q~JL!YHO{vHnp?XI;UP~t#w{hYpp1nthJWJwYHkmTASrqYpXe}wa#g+ zRhpKl-tyMa%wdTgP*176hYmO(;e+x^0LvL8ns*^jH- z7g{4%@z>0y$Lx;ioZ_!3ZL6^PqTC~)*Nijq*DO(PP0=zr;;&hz_-nCbN4Qh+_-oe5 zDW$ROnp2IxW{#=iuPH67t*GV%#b2{L@k0EyT3(F5mh)Kii|6#}Y?Es!jaIUSYJZEe z)Olw1BL13rIhDo7QTB7b(=q;Z_B{9DyypQH{iOb~Fb4kwAT%vrOODu_ViF2Au zqK@X0D))uf$kkk8Zk$V;(_Eso=MwWpHJ6Ao&dep2D7R)~mSZk)PIHOUisdMp&n4E$ zDRnWIm{Xlg%rVtmqO|4`QO_loCtjFKYI$)k$$7PNNiNCLwR1@>$(1t$m?U=^yTrZ zON*#}(st{n9LK6Ri{sF}!`I6%@NG&Kt|l$OH|9XSu}=I0bYxW`c=X9F zTll3FsZe{Byx2+rLjCpHMF}5?>5hK!$d;uebj&c(@P(10#3_oZ;(<^;m#a6f$Ndxy zy(>ldx+dNkF?yov{PRUi2>VbQeM#Rczr%p{7#Fpaw{Wp}uFK}<=FZc%^rbkgdF_m3 z7H5xK7D1L{>#R7pY&ARo95LzS2`_3D&;zPc%O5bUh=DJ)@HF9mF zt3U6nwD1$>cZa_CFU?@(y7D|%yUvR4aqTyhMI9`+b5wOy{b^@FKv_y46=P_A0+!Sm*ArHzk({tQ2tRrm;H_kvU43>ZSW zVc-sMHy8^hg2`YCm;si6wIH_&Z>H>apuVWSgP?2`9`Lu=RKXcA0=j>zC-hmf;_9QTw`>)DjP{-YQ^5?d9CU(pU?}5~#{yt3m~&ws z*iFB~<_z|LBj7kV1Fq(py$0L}Mgm>K6TmZIHfRG&Ks#8M^4p-hz;3V?90Vu9S@D$J$@}2LjT=|7YpZtyB zV*mc{ZAaG=)PMQ@{@3|t_AUIvp1pD^Teb4CRf|SjwKX{IV5@dMYR+zsnzB_}!di%} z+Bw^*osasmRhz^6<0hq{nD~)#jMe8*J6i*;ehmsBG1d z#xtTBDdsna9_F^{yqwdrRY(1fHzI9mi!_cHJ-}97)sEMJY}HZgop(i}eW|L|wL$5= zg{|5WQ)Qd$NeVLW_^SX8O-C@NOWP^%yeHb6vpkjVaxb|}!l*{DQHmIB@ z8*$#HF9NxGB?_woRbYoY1^R87nKc4lyiX%$`a+)Y|L`l zpq!HpN@>}kL~|RIb#h8w*r3d*+Mvual?_U1*`P!mC7cg{+9It&$8@7;+DMW})yTWi*3SV+7?IszF+!^niHou9Grz=gC(3>Qc^|Ys&Ri4=roI)?goV$(%A$ zaX((!_c9x4xeuu>U1JUJ1mgDVdevQ1-VwRZm6i9RUTc;`j$^-X!w(DnK9D~lHU{yWF{ z%UceuE?TVJl)5*@7&LXq%&nO+$F)2k&ZIf670Jw5HTxoE674@z+IvV>JgcT6Gu5#2ytl*_G0tsxFmULIbE!(^VyW&inXRNins98rqHWQnMx zTx~TwZ@AXgg9%y=oEPQlF2!VGAGdAqy(gLVT(8>^-}NY+M`p@(U7lwIA~RXSv99c7 zcCb`5JU0}vnOwI^SaT?rgKuBb&Kt+CZK~YxkD4kce_N@HgpLA}KnwT~47skUazAJT zAAx@VxT$gvm=4|t$HBGNH&w=iIba7k4o3U|JTMhBgN2|IYyyYDX)xr5rYpSjM&WEDTa-UgsqBV6 zcDPbG1?_jdQW*&PF`7fb&EPI@AD9B#z;dt+oqb>}X|;1G(GiUP-Czos0S4>dj8Ut? zpFFH-FUMU3h(e|360NjbKKuuqH?ZRf_rj2-${y&Dzphl8>DA59+rXV*EKqAVp!0-y z&}Gnjp$DP*H!}Z{Ia;ijQS)Xnl3GUt)i4425O@>}d#h4;9Qp@({-=NJ5!NuC*2?Ia zi%F>WXD&a^jT=%!CaAGB$)U~ukXHvg(pIS5quZ1SS#6Uk}%SDPwdFp7id&$X#Dt1oQuXQ)M4G2_7BLR9OUM6P$-Ga~f9yuh!3ZkQ>`K zqMLN|Qg{Ypu3fM6O~sXSc_KM=9pZ?9j`9%nC^#~xsqz{0ICStYDwQ+P+o5BC^d5jt z0npie-D7stx8 z(k1W9vGyz6NnkHH0s0JVs$3850{4Nb;Ox&h$IuS&3Apa}xYxlLa37cgW~BT=XeSu= z^GanCbSHS6^wVGu>CeC*Mox3d2%SauFR{^zaFUeyH<0?z;rMVbOG@{gzg8YKtI~J z4%`ZEq})g_8tBUqo@K*V3vqXjE!3{k`x8A19s4FTA~*&5R^oYHuwefxt{!k2bfKl) zIdt{&q*3^8d}rj8b(g44UOicN!|oi;Yn6@O9G5{OcypW=y^7dQqSS>q#}aaQbDXm` z$9YjkKkd$;_S~ip{y+)&*3!@p*)yd zvf*jD*qy^#u1WbgCW;PasiH$kgHa?pl)3aeM2Aw|Jgya9P->$?S(dkvml2=3LUgE{ z4=?P_;qvKR5hKbReM9u};`|R!m$ycqS6U;jy*b>MiG#vXrFWLp6Il+n-}!rSY*p$@ zS-hxnjVi;LP4S{6b=|2w)mB{H;)UzIc!S{>YQNol!*w*G97Fh8Q|(xXtEFal4#_lL z){&ld>22Db!`Ftjs5!)rvZg4!@NK4bL|HqE-8sy6Yw0WzN6NKu#ick>+MUB(Q_16okLu~T8wLmM3wWynw%n0 znQy9c{j$9_;!Yc`QNCMievKaHZ$$IwV@p|}_l`yO{n$dbyrV;J7(L&YR?*yEu!FZ2 zy)SkCI=(M`2F-Wb(7RLrWAyAB7q-jB`MhgkU8s52@;-92=~tt-Eqz_}X!gc+@oyFf z|6$Wbe}%LAQ?4CQVYJG7a6C=#FW*-pnN4c;-4M?*l@olm>2I~zi+tY=-__POWhO25-7wF(s*$;oNNK*RxgUysH{6~| zW%43Ynt8dNz6_8)_ZnXYw7;3R*i?!8ZiuHIs2ulp;brTpnX}!hw5TmaO>>Kq(Qo$M zFvs5$xIIxy&24+NYrER=5yK0fHPIzVy&w68@=V48&QrhL{rP<`i?<0a&`;PP`$Rf3hfyR`)<_J@lk88 z(4Gaj%2uuJ>h9j0b}h);Rl1D4&c^$0NXsbKD874PS^darZmZk}=iLHN>se&A;CsT3 zWvQu4`Rb@?yGMMr-rBZIl;^kbO-H`(hFi3rTk=thUq8xPUc&t~wM^7+82P>%;^)ZA zx#h;O)?B+w^+u(udrM!H#CKj_&HowJdYvAR1Ac$^DIvrBPq|Zdiks zn3me#bX>N)r+F!*nZZJAHtAT8nX8D+W_`<)*LOUk*l(ITV!QPKA*A%<5A=DQ3>g2mlN-r;@TSdeB5W(?K)h}^@yMQ zd@Ro?s}4RNb2#Fa^7*(%QSR5d)%`eJw@X-a=q3An_Kd{3`6u*%Jvpv{-T>|fQ@}d# zIk@BYrpnWx8yo{S{|l_$U^UnSz5uu0fkhK^fIVQ~zk~-Sfp3DTU>;Zkc7grib8uyM zTR(Ce9w;#QpJTiIO^j^+5Og+J0k(mW$a>qCV>I$dz)Ua)ECY(W-v!kk1N)%fZT%SO z&%ppjbtt$UOaM=V*}%K4w~i1n6@MBgI}E8i^s$>%ky+VSf%$FdHlbU0@eD0#1Qz z>ElR{@6T~RdDV43UY&bs|6KcX%s|JxtuG<%-PSuvZvyq-z1sc>*7qCn4Q9KoPyTvS zWi8kNZXb?E1IVlM2)fK#$*c1Wxyp~O3YbGWdUbTq3-aoS-W2rZqq{s_o%X|5RdxW4 z+(*!TVAF`EigsJy2G#x?A42o}Ii`J`|8wA9$o?FMR0sEq_UE{U(QC9n#|UKFpW|-m z@ZwmTFN0TS`b~IWK?m3lJ_g6ZfSb7wz*wLiIv#;O4Z6WG@HrU#PtgIRzyzTDWH1#x z`T_rcKo3I1beAh3wKXg8rSRTp!vS1b8+q`E%x^T302y8G7zrI%c9J ze~zwuo+S!@j`C%&rlwswB%$_Vw{_*Uf<}Li%b^kcInIl+GBk@)7ycYe$l=d%&i)+d zMf(>19Ieb=oh6C>9CN5C?bRU}J*e5MBkIeaqm;_1kMid@pGpOPj?y|RQQA-boLn<% zM}Lm_DiO4UKgV2ANpgRV`<&CzAN)CaIi6H9e@-q@jVdkBW@!%(X$sU??6$7FO4ax0 zxNg^(Q_DpCww3#H#5Ytf*EgTDlXmhDhaM+?j&;>DrNdbadlDqQX$A@R_y8_ znE)^NbF6Eg{5j^SEN!H{J;aUv9Ho*h?eHN^82`ebQ$9B5tNt9fV#;xrcKFC7r5!#b z5jcushY$1gcGGBw59^qsTjS3W-#yh4Ds6-(;liI|E!U)c924*MA&LAsqKsnN?L#?w zU9;PVcw8%bC+)G@hh&C(lDAD=HM@PJ`itGxl~3m??fD@N^J2-LQ?5JDE6v$SyRECd z-m65lPcX-ZmD7ESyRAzm4sW6j_y3R%wPyQ&h~ttRSMcY!UeR#97jGvVL&=|$>$;wt zQfKhzdp5EaS267Qo7!5>*Am28(Y`4VTiA5M9}>3 zO5x8jR~mxHS^ga5>04>Hb!#!!H9L!lAJ*gsJBuW_JTm%1Evy;kFQpspt*)}N$E$a? zC0q`#&ojIWZUKH{x{`aVH+tLB`Ka!#K8fCx-?tj?t$sf57MuR~;{7_k?X7+ zop^QB?ya7mb)EhCd#g*Uw`*P{b(J&2)cAPBvrKge)vJHacICC!RQJH~oo;PYX4k^U zW1e+YBlBh24M$S$k;2F0_QY2@$qOHkdAXi^JksMj2|gaBg*abCACL1Y$1!9+p1ekB zxn^oBcE)jy^gHdXE{=UXmPTIf-s*`Ld^}3KHD;0I<1yFcL+`TxrYtp;mg=ALh zd8X^(<8h1Db4xyI@$36|@)GW^sb!*m>&SgP;^)ZAx#h+_9@p+ty;14v-m3a|%Izwz zHn}2ed_0X>5ubada($5i9vk<5B| z+v3;v@ic0|rQK5Q<0-cyU3yaE<8k@Ce$}OX^zm2{eLTuZZXb`OQC~hDYtT}SkH;;! z_PiuBSk3-Bk}-1?J|6434&~+J5v~5yBdPui5*4sWhQC<3?vj^hJO4}P8q%6Lp6K*Y z`cU|Ktiw9NAJ;GaMSPEurX)iCe~)=CrP}B{zn!)51!;R|F)u4QS8nq7tX*5(b6quP zd<6H)wVuoG<6fxtJgvIKi@geaiNCavzvWzSPFacY`wvU>6uT0h=S32R;Cm|BQDCOa(i@Q84&E{sIEC z!B%h--1uMMfhWNXFdwvob>ILv0S4ZGrM*9A#$%EEkJwv5Bk#{RWW9NR9zZ@7ECS0x zH;_H|eW)zh$D#KAR2a>HU>LXqj0cZ`d0+{!_otJzEUfzzy*TgB{C|%X8|Yo;81!7; zpHt|_`!ir%^!^Nmmc2huqSFknr1xk4zhlHezp*{NKSSWj`!g0g3ABKAunBwsJ_VnF z>*?biAou<}KwhJIKHi`4w0|z|&vbOAK1jqY>Rd*8HEHe6zMAwFP~ZF0`mdWR&)i+> z{dwfyP#SCpBS&*h0C|5NMwb~dd4HynyY9}27ShrCqx)Wv_eb=mpnqk(Ki&64@6T4K zygwg6FV*{VP<15l&k#nhk@x3jWb*#p1sz@-Yx8CB{yg)iO_f%#0&D|&z%kH&3|?<= z50LlgVdzt!3w#Pb1B3o8I^a%lFHrsw@HCM3XEwA=dG=u+%%ZuR^e%7+XtwwqDkIKd zMqxO(AItz9;QYKlchS@FpzQs55Z>dUp7&=M{PXqxe84ri4;%v*Zypb@-3&Wmy$ zn?1jfJl=sK^R4RCX zl-5y+(th&(4O(<>Q#x`y+|G zKcb9c^8P4CuWP(N;&H9i_5Mg^xF>nr)K%mCN%a@rALY}zO5PuFm=}BT{zxNlOKE03 ztVdYy`J+d2J^lMlNA^sPF!_KajXogP)0+=SI-K9k2PBS5a&(0c$h>gX2Op3)97!D? zkag=(>I^=hT&C+F_W?NQvPyyh1z&e`~dh(>PmWr8oh;S9{(Nk%2^W3>T?*(h97NL4S ztl6%-)}UIikTr9fdxgyRJfRwyL6cWVQtp}_ULo;)jU%t|3Rz~kyh7q}M+UEu(n6d; zqF2aymEjmlULi?co2Wo-g;&Tm((mLI631R4OCzt=E0lP_E2OkrVO~jIA#*)GVYV&) z{IS$jTB?JdB(IPpfXFUE~heOSSH%oD&M zsC0F2RlP#xc9mC~T#?QBpFfRS5ubadxnuqTHh-qiQ$rYDYuk+g)FzeC_U-n6>`0%s!QqU6*4z^g_M)rULi}P zzPv)#prsyOAtn}$bNsizJ#pf1{^sP# zzy00m(|%4|o}LxGD~@`QKPz6t6L6j%jcxm`TVe7w{S0<-&~6SNb+PwtJAWUr2bTB; zo{#h%zMC2V&R)ZgAiv|Ab}#}+=YhYxsxo}WRh4VOIPAdJgGs~rcVtbaa*R$b1w*KN z)Hu%FpHwQFZ;SbfbY|V}^CXRI0Jy61R*0g_Zav}8^%q}M?2{1J;q~_R6)QSAR)u(2 zMKr9gjT_&7yS#tMyovld@OPKKhX^wQy?FN7jT`lU*nQMG6=;8ud|waNN1jN>AknTK z=ew)MNc6Si@2EiIlfG(Ny`Iqy=ZMz1ndgW2&a2mnYsrqZXOhljQ-x@Z#2~OtJZ#`I zmA|U8bg9Nd_0F2rMQVF!ZRX6xrGD4TUIaSdngz3C?(+?N2%!EkpP@D#v-T%cyM2p4 Q%azM}NwjtPD6a7T0gD>%8vp = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("word_break_fwd.bigendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} + +#[cfg(target_endian = "little")] +lazy_static! { + pub static ref WORD_BREAK_FWD: ::regex_automata::SparseDFA<&'static [u8], u32> = { + #[repr(C)] + struct Aligned { + _align: [u8; 0], + bytes: B, + } + + static ALIGNED: &'static Aligned<[u8]> = &Aligned { + _align: [], + bytes: *include_bytes!("word_break_fwd.littleendian.dfa"), + }; + + unsafe { + ::regex_automata::SparseDFA::from_bytes(&ALIGNED.bytes) + } + }; +} diff --git a/bstr/src/unicode/grapheme.rs b/bstr/src/unicode/grapheme.rs new file mode 100644 index 000000000..fe9a85237 --- /dev/null +++ b/bstr/src/unicode/grapheme.rs @@ -0,0 +1,357 @@ +use regex_automata::DFA; + +use bstr::BStr; +use unicode::fsm::grapheme_break_fwd::GRAPHEME_BREAK_FWD; +use unicode::fsm::grapheme_break_rev::GRAPHEME_BREAK_REV; +use unicode::fsm::regional_indicator_rev::REGIONAL_INDICATOR_REV; +use utf8; + +/// An iterator over grapheme clusters in a byte string. +/// +/// This iterator is typically constructed by +/// [`bstr::graphemes`](struct.BStr.html#method.graphemes). +/// +/// Unicode defines a grapheme cluster as an *approximation* to a single user +/// visible character. A grapheme cluster, or just "grapheme," is made up of +/// one or more codepoints. For end user oriented tasks, one should generally +/// prefer using graphemes instead of [`Chars`](struct.Chars.html), which +/// always yields one codepoint at a time. +/// +/// Since graphemes are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator can be used in reverse. When reversed, exactly the same +/// set of grapheme clusters are yielded, but in reverse order. +/// +/// This iterator only yields *extended* grapheme clusters, in accordance with +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Grapheme_Cluster_Boundaries). +#[derive(Clone, Debug)] +pub struct Graphemes<'a> { + bs: &'a BStr, +} + +impl<'a> Graphemes<'a> { + pub(crate) fn new(bs: &'a BStr) -> Graphemes<'a> { + Graphemes { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("abc").graphemes(); + /// + /// assert_eq!("abc", it.as_bstr()); + /// it.next(); + /// assert_eq!("bc", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for Graphemes<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (grapheme, size) = decode_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(grapheme) + } +} + +impl<'a> DoubleEndedIterator for Graphemes<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + let (grapheme, size) = decode_last_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len()-size]; + Some(grapheme) + } +} + +/// An iterator over grapheme clusters in a byte string and their byte index +/// positions. +/// +/// This iterator is typically constructed by +/// [`bstr::grapheme_indices`](struct.BStr.html#method.grapheme_indices). +/// +/// Unicode defines a grapheme cluster as an *approximation* to a single user +/// visible character. A grapheme cluster, or just "grapheme," is made up of +/// one or more codepoints. For end user oriented tasks, one should generally +/// prefer using graphemes instead of [`Chars`](struct.Chars.html), which +/// always yields one codepoint at a time. +/// +/// Since graphemes are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// grapheme cluster yielded with those indices. For example, when this +/// iterator encounters `\xFF` in the byte string, then it will yield a pair +/// of indices ranging over a single byte, but will provide an `&str` +/// equivalent to `"\u{FFFD}"`, which is three bytes in length. However, when +/// given only valid UTF-8, then all indices are in exact correspondence with +/// their paired grapheme cluster. +/// +/// This iterator can be used in reverse. When reversed, exactly the same +/// set of grapheme clusters are yielded, but in reverse order. +/// +/// This iterator only yields *extended* grapheme clusters, in accordance with +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Grapheme_Cluster_Boundaries). +#[derive(Clone, Debug)] +pub struct GraphemeIndices<'a> { + bs: &'a BStr, + forward_index: usize, + reverse_index: usize, +} + +impl<'a> GraphemeIndices<'a> { + pub(crate) fn new(bs: &'a BStr) -> GraphemeIndices<'a> { + GraphemeIndices { bs: bs, forward_index: 0, reverse_index: bs.len() } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("abc").grapheme_indices(); + /// + /// assert_eq!("abc", it.as_bstr()); + /// it.next(); + /// assert_eq!("bc", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for GraphemeIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (grapheme, size) = decode_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, grapheme)) + } +} + +impl<'a> DoubleEndedIterator for GraphemeIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, usize, &'a str)> { + let (grapheme, size) = decode_last_grapheme(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len()-size]; + self.reverse_index -= size; + Some((self.reverse_index, self.reverse_index + size, grapheme)) + } +} + +/// Decode a grapheme from the given byte string. +/// +/// This returns the resulting grapheme (which may be a Unicode replacement +/// codepoint if invalid UTF-8 was found), along with the number of bytes +/// decoded in the byte string. The number of bytes decoded may not be the +/// same as the length of grapheme in the case where invalid UTF-8 is found. +pub fn decode_grapheme(bs: &BStr) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = GRAPHEME_BREAK_FWD.find(bs.as_bytes()) { + // Safe because a match can only occur for valid UTF-8. + let grapheme = unsafe { bs[..end].to_str_unchecked() }; + (grapheme, grapheme.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs.as_bytes()); + (INVALID, size) + } +} + +fn decode_last_grapheme(bs: &BStr) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(mut start) = GRAPHEME_BREAK_REV.rfind(bs.as_bytes()) { + start = adjust_rev_for_regional_indicator(bs, start); + // Safe because a match can only occur for valid UTF-8. + let grapheme = unsafe { bs[start..].to_str_unchecked() }; + (grapheme, grapheme.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_last_lossy(bs.as_bytes()); + (INVALID, size) + } +} + +/// Return the correct offset for the next grapheme decoded at the end of the +/// given byte string, where `i` is the initial guess. In particular, +/// `&bs[i..]` represents the candidate grapheme. +/// +/// `i` is returned by this function in all cases except when `&bs[i..]` is +/// a pair of regional indicator codepoints. In that case, if an odd number of +/// additional regional indicator codepoints precedes `i`, then `i` is +/// adjusted such that it points to only a single regional indicator. +/// +/// This "fixing" is necessary to handle the requirement that a break cannot +/// occur between regional indicators where it would cause an odd number of +/// regional indicators to exist before the break from the *start* of the +/// string. A reverse regex cannot detect this case easily without look-around. +fn adjust_rev_for_regional_indicator(mut bs: &BStr, i: usize) -> usize { + // All regional indicators use a 4 byte encoding, and we only care about + // the case where we found a pair of regional indicators. + if bs.len() - i != 8 { + return i; + } + // Count all contiguous occurrences of regional indicators. If there's an + // even number of them, then we can accept the pair we found. Otherwise, + // we can only take one of them. + // + // FIXME: This is quadratic in the worst case, e.g., a string of just + // regional indicator codepoints. A fix probably requires refactoring this + // code a bit such that we don't rescan regional indicators. + let mut count = 0; + while let Some(start) = REGIONAL_INDICATOR_REV.rfind(bs.as_bytes()) { + bs = &bs[..start]; + count += 1; + } + if count % 2 == 0 { + i + } else { + i + 4 + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::GraphemeClusterBreakTest; + + use bstr::B; + use tests::LOSSY_TESTS; + use super::*; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.grapheme_clusters.concat(); + let got: Vec = Graphemes::new(B(&given)) + .map(|cluster| cluster.to_string()) + .collect(); + assert_eq!( + test.grapheme_clusters, + got, + "\ngrapheme forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + uniescape(&given), + uniescape_vec(&test.grapheme_clusters), + uniescape_vec(&got), + ); + } + } + + #[test] + fn reverse_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.grapheme_clusters.concat(); + let mut got: Vec = Graphemes::new(B(&given)) + .rev() + .map(|cluster| cluster.to_string()) + .collect(); + got.reverse(); + assert_eq!( + test.grapheme_clusters, + got, + "\n\ngrapheme reverse break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + uniescape(&given), + uniescape_vec(&test.grapheme_clusters), + uniescape_vec(&got), + ); + } + } + + #[test] + fn forward_lossy() { + for &(expected, input) in LOSSY_TESTS { + let got = Graphemes::new(B(input)).collect::(); + assert_eq!(expected, got); + } + } + + #[test] + fn reverse_lossy() { + for &(expected, input) in LOSSY_TESTS { + let expected: String = expected.chars().rev().collect(); + let got = Graphemes::new(B(input)) + .rev() + .collect::(); + assert_eq!(expected, got); + } + } + + fn uniescape(s: &str) -> String { + s.chars().flat_map(|c| c.escape_unicode()).collect::() + } + + fn uniescape_vec(strs: &[String]) -> Vec { + strs.iter().map(|s| uniescape(s)).collect() + } + + /// Return all of the UCD for grapheme breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = include_str!( + "data/GraphemeBreakTest.txt" + ); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/bstr/src/unicode/mod.rs b/bstr/src/unicode/mod.rs new file mode 100644 index 000000000..b3835c7f2 --- /dev/null +++ b/bstr/src/unicode/mod.rs @@ -0,0 +1,12 @@ +pub use self::grapheme::{Graphemes, GraphemeIndices, decode_grapheme}; +pub use self::sentence::{Sentences, SentenceIndices}; +pub use self::whitespace::{whitespace_len_fwd, whitespace_len_rev}; +pub use self::word::{ + Words, WordIndices, WordsWithBreaks, WordsWithBreakIndices, +}; + +mod fsm; +mod grapheme; +mod sentence; +mod whitespace; +mod word; diff --git a/bstr/src/unicode/sentence.rs b/bstr/src/unicode/sentence.rs new file mode 100644 index 000000000..f732f081a --- /dev/null +++ b/bstr/src/unicode/sentence.rs @@ -0,0 +1,221 @@ +use regex_automata::DFA; + +use bstr::BStr; +use unicode::fsm::sentence_break_fwd::SENTENCE_BREAK_FWD; +use utf8; + +/// An iterator over sentences in a byte string. +/// +/// This iterator is typically constructed by +/// [`bstr::sentences`](struct.BStr.html#method.sentences). +/// +/// Sentences typically include their trailing punctuation and whitespace. +/// +/// Since sentences are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default sentence boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Sentence_Boundaries). +#[derive(Clone, Debug)] +pub struct Sentences<'a> { + bs: &'a BStr, +} + +impl<'a> Sentences<'a> { + pub(crate) fn new(bs: &'a BStr) -> Sentences<'a> { + Sentences { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("I want this. Not that. Right now.").sentences(); + /// + /// assert_eq!("I want this. Not that. Right now.", it.as_bstr()); + /// it.next(); + /// assert_eq!("Not that. Right now.", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for Sentences<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (sentence, size) = decode_sentence(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(sentence) + } +} + +/// An iterator over sentences in a byte string, along with their byte offsets. +/// +/// This iterator is typically constructed by +/// [`bstr::sentence_indices`](struct.BStr.html#method.sentence_indices). +/// +/// Sentences typically include their trailing punctuation and whitespace. +/// +/// Since sentences are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// sentence yielded with those indices. For example, when this iterator +/// encounters `\xFF` in the byte string, then it will yield a pair of indices +/// ranging over a single byte, but will provide an `&str` equivalent to +/// `"\u{FFFD}"`, which is three bytes in length. However, when given only +/// valid UTF-8, then all indices are in exact correspondence with their paired +/// word. +/// +/// This iterator yields words in accordance with the default sentence boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Sentence_Boundaries). +#[derive(Clone, Debug)] +pub struct SentenceIndices<'a> { + bs: &'a BStr, + forward_index: usize, +} + +impl<'a> SentenceIndices<'a> { + pub(crate) fn new(bs: &'a BStr) -> SentenceIndices<'a> { + SentenceIndices { bs: bs, forward_index: 0 } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("I want this. Not that. Right now.").sentence_indices(); + /// + /// assert_eq!("I want this. Not that. Right now.", it.as_bstr()); + /// it.next(); + /// assert_eq!("Not that. Right now.", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for SentenceIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (word, size) = decode_sentence(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, word)) + } +} + +fn decode_sentence(bs: &BStr) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = SENTENCE_BREAK_FWD.find(bs.as_bytes()) { + // Safe because a match can only occur for valid UTF-8. + let sentence = unsafe { bs[..end].to_str_unchecked() }; + (sentence, sentence.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs.as_bytes()); + (INVALID, size) + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::SentenceBreakTest; + + use bstr::{B, BStr}; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.sentences.concat(); + let got = sentences(given.as_bytes()); + assert_eq!( + test.sentences, + got, + "\n\nsentence forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + BStr::new(&given), + strs_to_bstrs(&test.sentences), + strs_to_bstrs(&got), + ); + } + } + + // Some additional tests that don't seem to be covered by the UCD tests. + #[test] + fn forward_additional() { + assert_eq!(vec!["a.. ", "A"], sentences(b"a.. A")); + assert_eq!(vec!["a.. a"], sentences(b"a.. a")); + + assert_eq!(vec!["a... ", "A"], sentences(b"a... A")); + assert_eq!(vec!["a... a"], sentences(b"a... a")); + + assert_eq!(vec!["a...,..., a"], sentences(b"a...,..., a")); + } + + fn sentences(bytes: &[u8]) -> Vec<&str> { + BStr::new(bytes).sentences().collect() + } + + fn strs_to_bstrs>(strs: &[S]) -> Vec<&BStr> { + strs.iter().map(|s| B(s.as_ref())).collect() + } + + /// Return all of the UCD for sentence breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = include_str!( + "data/SentenceBreakTest.txt" + ); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/bstr/src/unicode/whitespace.rs b/bstr/src/unicode/whitespace.rs new file mode 100644 index 000000000..a8da1447a --- /dev/null +++ b/bstr/src/unicode/whitespace.rs @@ -0,0 +1,14 @@ +use regex_automata::DFA; + +use unicode::fsm::whitespace_anchored_fwd::WHITESPACE_ANCHORED_FWD; +use unicode::fsm::whitespace_anchored_rev::WHITESPACE_ANCHORED_REV; + +/// Return the first position of a non-whitespace character. +pub fn whitespace_len_fwd(slice: &[u8]) -> usize { + WHITESPACE_ANCHORED_FWD.find(slice).unwrap_or(0) +} + +/// Return the last position of a non-whitespace character. +pub fn whitespace_len_rev(slice: &[u8]) -> usize { + WHITESPACE_ANCHORED_REV.rfind(slice).unwrap_or(slice.len()) +} diff --git a/bstr/src/unicode/word.rs b/bstr/src/unicode/word.rs new file mode 100644 index 000000000..d55dfc503 --- /dev/null +++ b/bstr/src/unicode/word.rs @@ -0,0 +1,447 @@ +use regex_automata::DFA; + +use bstr::BStr; +use unicode::fsm::simple_word_fwd::SIMPLE_WORD_FWD; +use unicode::fsm::word_break_fwd::WORD_BREAK_FWD; +use utf8; + +/// An iterator over words in a byte string. +/// +/// This iterator is typically constructed by +/// [`bstr::words`](struct.BStr.html#method.words). +/// +/// This is similar to the [`WordsWithBreaks`](struct.WordsWithBreaks.html) +/// iterator, except it only returns elements that contain a "word" character. +/// A word character is defined by UTS #18 (Annex C) to be the combination +/// of the `Alphabetic` and `Join_Control` properties, along with the +/// `Decimal_Number`, `Mark` and `Connector_Punctuation` general categories. +/// +/// Since words are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct Words<'a>(WordsWithBreaks<'a>); + +impl<'a> Words<'a> { + pub(crate) fn new(bs: &'a BStr) -> Words<'a> { + Words(WordsWithBreaks::new(bs)) + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("foo bar baz").words(); + /// + /// assert_eq!("foo bar baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!(" baz", it.as_bstr()); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.0.as_bstr() + } +} + +impl<'a> Iterator for Words<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + while let Some(word) = self.0.next() { + if SIMPLE_WORD_FWD.is_match(word.as_bytes()) { + return Some(word); + } + } + None + } +} + +/// An iterator over words in a byte string and their byte index positions. +/// +/// This iterator is typically constructed by +/// [`bstr::word_indices`](struct.BStr.html#method.word_indices). +/// +/// This is similar to the +/// [`WordsWithBreakIndices`](struct.WordsWithBreakIndices.html) iterator, +/// except it only returns elements that contain a "word" character. A +/// word character is defined by UTS #18 (Annex C) to be the combination +/// of the `Alphabetic` and `Join_Control` properties, along with the +/// `Decimal_Number`, `Mark` and `Connector_Punctuation` general categories. +/// +/// Since words are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// word yielded with those indices. For example, when this iterator encounters +/// `\xFF` in the byte string, then it will yield a pair of indices ranging +/// over a single byte, but will provide an `&str` equivalent to `"\u{FFFD}"`, +/// which is three bytes in length. However, when given only valid UTF-8, then +/// all indices are in exact correspondence with their paired word. +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordIndices<'a>(WordsWithBreakIndices<'a>); + +impl<'a> WordIndices<'a> { + pub(crate) fn new(bs: &'a BStr) -> WordIndices<'a> { + WordIndices(WordsWithBreakIndices::new(bs)) + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("foo bar baz").word_indices(); + /// + /// assert_eq!("foo bar baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!(" baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.0.as_bstr() + } +} + +impl<'a> Iterator for WordIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + while let Some((start, end, word)) = self.0.next() { + if SIMPLE_WORD_FWD.is_match(word.as_bytes()) { + return Some((start, end, word)); + } + } + None + } +} + +/// An iterator over all word breaks in a byte string. +/// +/// This iterator is typically constructed by +/// [`bstr::words_with_breaks`](struct.BStr.html#method.words_with_breaks). +/// +/// This iterator yields not only all words, but the content that comes between +/// words. In particular, if all elements yielded by this iterator are +/// concatenated, then the result is the original string (subject to Unicode +/// replacement codepoint substitutions). +/// +/// Since words are made up of one or more codepoints, this iterator yields +/// `&str` elements. When invalid UTF-8 is encountered, replacement codepoints +/// are [substituted](index.html#handling-of-invalid-utf-8). +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordsWithBreaks<'a> { + bs: &'a BStr, +} + +impl<'a> WordsWithBreaks<'a> { + pub(crate) fn new(bs: &'a BStr) -> WordsWithBreaks<'a> { + WordsWithBreaks { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("foo bar baz").words_with_breaks(); + /// + /// assert_eq!("foo bar baz", it.as_bstr()); + /// it.next(); + /// assert_eq!(" bar baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!(" baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for WordsWithBreaks<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + let (word, size) = decode_word(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(word) + } +} + +/// An iterator over all word breaks in a byte string, along with their byte +/// index positions. +/// +/// This iterator is typically constructed by +/// [`bstr::words_with_break_indices`](struct.BStr.html#method.words_with_break_indices). +/// +/// This iterator yields not only all words, but the content that comes between +/// words. In particular, if all elements yielded by this iterator are +/// concatenated, then the result is the original string (subject to Unicode +/// replacement codepoint substitutions). +/// +/// Since words are made up of one or more codepoints, this iterator +/// yields `&str` elements (along with their start and end byte offsets). +/// When invalid UTF-8 is encountered, replacement codepoints are +/// [substituted](index.html#handling-of-invalid-utf-8). Because of this, the +/// indices yielded by this iterator may not correspond to the length of the +/// word yielded with those indices. For example, when this iterator encounters +/// `\xFF` in the byte string, then it will yield a pair of indices ranging +/// over a single byte, but will provide an `&str` equivalent to `"\u{FFFD}"`, +/// which is three bytes in length. However, when given only valid UTF-8, then +/// all indices are in exact correspondence with their paired word. +/// +/// This iterator yields words in accordance with the default word boundary +/// rules specified in +/// [UAX #29](https://www.unicode.org/reports/tr29/tr29-33.html#Word_Boundaries). +/// In particular, this may not be suitable for Japanese and Chinese scripts +/// that do not use spaces between words. +#[derive(Clone, Debug)] +pub struct WordsWithBreakIndices<'a> { + bs: &'a BStr, + forward_index: usize, +} + +impl<'a> WordsWithBreakIndices<'a> { + pub(crate) fn new(bs: &'a BStr) -> WordsWithBreakIndices<'a> { + WordsWithBreakIndices { bs: bs, forward_index: 0 } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("foo bar baz").words_with_break_indices(); + /// + /// assert_eq!("foo bar baz", it.as_bstr()); + /// it.next(); + /// assert_eq!(" bar baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!(" baz", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for WordsWithBreakIndices<'a> { + type Item = (usize, usize, &'a str); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, &'a str)> { + let index = self.forward_index; + let (word, size) = decode_word(self.bs); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, word)) + } +} + +fn decode_word(bs: &BStr) -> (&str, usize) { + if bs.is_empty() { + ("", 0) + } else if let Some(end) = WORD_BREAK_FWD.find(bs.as_bytes()) { + // Safe because a match can only occur for valid UTF-8. + let word = unsafe { bs[..end].to_str_unchecked() }; + (word, word.len()) + } else { + const INVALID: &'static str = "\u{FFFD}"; + // No match on non-empty bytes implies we found invalid UTF-8. + let (_, size) = utf8::decode_lossy(bs.as_bytes()); + (INVALID, size) + } +} + +#[cfg(test)] +mod tests { + use ucd_parse::WordBreakTest; + + use bstr::BStr; + + #[test] + fn forward_ucd() { + for (i, test) in ucdtests().into_iter().enumerate() { + let given = test.words.concat(); + let got = words(given.as_bytes()); + assert_eq!( + test.words, + got, + "\n\nword forward break test {} failed:\n\ + given: {:?}\n\ + expected: {:?}\n\ + got: {:?}\n", + i, + BStr::new(&given), + strs_to_bstrs(&test.words), + strs_to_bstrs(&got), + ); + } + } + + // Some additional tests that don't seem to be covered by the UCD tests. + // + // It's pretty amazing that the UCD tests miss these cases. I only found + // them by running this crate's segmenter and ICU's segmenter on the same + // text and comparing the output. + #[test] + fn forward_additional() { + assert_eq!(vec!["a", ".", " ", "Y"], words(b"a. Y")); + assert_eq!( + vec!["r", ".", " ", "Yo"], + words(b"r. Yo") + ); + assert_eq!( + vec!["whatsoever", ".", " ", "You", " ", "may"], + words(b"whatsoever. You may") + ); + assert_eq!( + vec!["21stcentury'syesterday"], + words(b"21stcentury'syesterday") + ); + + assert_eq!( + vec!["Bonta_", "'", "s"], + words(b"Bonta_'s") + ); + assert_eq!( + vec!["_vhat's"], + words(b"_vhat's") + ); + assert_eq!( + vec!["__on'anima"], + words(b"__on'anima") + ); + assert_eq!( + vec!["123_", "'", "4"], + words(b"123_'4") + ); + assert_eq!( + vec!["_123'4"], + words(b"_123'4") + ); + assert_eq!( + vec!["__12'345"], + words(b"__12'345") + ); + + assert_eq!( + vec!["tomorrowat4", ":", "00", ","], + words(b"tomorrowat4:00,") + ); + assert_eq!( + vec!["RS1", "'", "s"], + words(b"RS1's") + ); + assert_eq!( + vec!["X38"], + words(b"X38") + ); + + assert_eq!( + vec!["4abc", ":", "00", ","], + words(b"4abc:00,") + ); + assert_eq!( + vec!["12S", "'", "1"], + words(b"12S'1") + ); + assert_eq!( + vec!["1XY"], + words(b"1XY") + ); + + assert_eq!( + vec!["\u{FEFF}", "Ты"], + words("\u{FEFF}Ты".as_bytes()) + ); + } + + fn words(bytes: &[u8]) -> Vec<&str> { + BStr::new(bytes).words_with_breaks().collect() + } + + fn strs_to_bstrs>(strs: &[S]) -> Vec<&BStr> { + strs.iter().map(|s| BStr::new(s.as_ref())).collect() + } + + /// Return all of the UCD for word breaks. + fn ucdtests() -> Vec { + const TESTDATA: &'static str = include_str!( + "data/WordBreakTest.txt" + ); + + let mut tests = vec![]; + for mut line in TESTDATA.lines() { + line = line.trim(); + if line.starts_with("#") || line.contains("surrogate") { + continue; + } + tests.push(line.parse().unwrap()); + } + tests + } +} diff --git a/bstr/src/utf8.rs b/bstr/src/utf8.rs new file mode 100644 index 000000000..e35da3624 --- /dev/null +++ b/bstr/src/utf8.rs @@ -0,0 +1,1108 @@ +use core::char; +use core::cmp; +#[cfg(feature = "std")] +use std::error; +use core::fmt; + +use ascii; +use bstr::BStr; + +// The UTF-8 decoder provided here is based on the one presented here: +// https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ +// +// We *could* have done UTF-8 decoding by using a DFA generated by `\p{any}` +// using regex-automata that is roughly the same size. The real benefit of +// Hoehrmann's formulation is that the byte class mapping below is manually +// tailored such that each byte's class doubles as a shift to mask out the +// bits necessary for constructing the leading bits of each codepoint value +// from the initial byte. +// +// There are some minor differences between this implementation and Hoehrmann's +// formulation. +// +// Firstly, we make REJECT have state ID 0, since it makes the state table +// itself a little easier to read and is consistent with the notion that 0 +// means "false" or "bad." +// +// Secondly, when doing bulk decoding, we add a SIMD accelerated ASCII fast +// path. +// +// Thirdly, we pre-multiply the state IDs to avoid a multiplication instruction +// in the core decoding loop. (Which is what regex-automata would do by +// default.) +// +// Fourthly, we split the byte class mapping and transition table into two +// arrays because it's clearer. +// +// It is unlikely that this is the fastest way to do UTF-8 decoding, however, +// it is fairly simple. + +const ACCEPT: usize = 12; +const REJECT: usize = 0; + +static CLASSES: [u8; 256] = [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, +]; + +static STATES_FORWARD: &'static [u8] = &[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 24, 36, 60, 96, 84, 0, 0, 0, 48, 72, + 0, 12, 0, 0, 0, 0, 0, 12, 0, 12, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 24, 0, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0, + 0, 36, 0, 0, 0, 0, 0, 36, 0, 36, 0, 0, + 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; + +/// An iterator over Unicode scalar values in a byte string. +/// +/// When invalid UTF-8 byte sequences are found, they are substituted with the +/// Unicode replacement codepoint (`U+FFFD`) using the +/// ["maximal subpart" strategy](http://www.unicode.org/review/pr-121.html). +/// +/// This iterator is created by the +/// [`chars`](struct.BStr.html#method.chars) method on +/// [`BStr`](struct.BStr.html). +#[derive(Clone, Debug)] +pub struct Chars<'a> { + bs: &'a BStr, +} + +impl<'a> Chars<'a> { + pub(crate) fn new(bs: &'a BStr) -> Chars<'a> { + Chars { bs } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::BStr; + /// + /// let mut chars = BStr::new("abc").chars(); + /// + /// assert_eq!("abc", chars.as_bstr()); + /// chars.next(); + /// assert_eq!("bc", chars.as_bstr()); + /// chars.next(); + /// chars.next(); + /// assert_eq!("", chars.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for Chars<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + let (ch, size) = decode_lossy(self.bs.as_bytes()); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + Some(ch) + } +} + +impl<'a> DoubleEndedIterator for Chars<'a> { + #[inline] + fn next_back(&mut self) -> Option { + let (ch, size) = decode_last_lossy(self.bs.as_bytes()); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len()-size]; + Some(ch) + } +} + +/// An iterator over Unicode scalar values in a byte string and their +/// byte index positions. +/// +/// When invalid UTF-8 byte sequences are found, they are substituted with the +/// Unicode replacement codepoint (`U+FFFD`) using the +/// ["maximal subpart" strategy](http://www.unicode.org/review/pr-121.html). +/// +/// Note that this is slightly different from the `CharIndices` iterator +/// provided by the standard library. Aside from working on possibly invalid +/// UTF-8, this iterator provides both the corresponding starting and ending +/// byte indices of each codepoint yielded. The ending position is necessary to +/// slice the original byte string when invalid UTF-8 bytes are converted into +/// a Unicode replacement codepoint, since a single replacement codepoint can +/// substitute anywhere from 1 to 3 invalid bytes (inclusive). +/// +/// This iterator is created by the +/// [`char_indices`](struct.BStr.html#method.char_indices) method on +/// [`BStr`](struct.BStr.html). +#[derive(Clone, Debug)] +pub struct CharIndices<'a> { + bs: &'a BStr, + forward_index: usize, + reverse_index: usize, +} + +impl<'a> CharIndices<'a> { + pub(crate) fn new(bs: &'a BStr) -> CharIndices<'a> { + CharIndices { bs: bs, forward_index: 0, reverse_index: bs.len() } + } + + /// View the underlying data as a subslice of the original data. + /// + /// The slice returned has the same lifetime as the original slice, and so + /// the iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// use bstr::B; + /// + /// let mut it = B("abc").char_indices(); + /// + /// assert_eq!("abc", it.as_bstr()); + /// it.next(); + /// assert_eq!("bc", it.as_bstr()); + /// it.next(); + /// it.next(); + /// assert_eq!("", it.as_bstr()); + /// ``` + #[inline] + pub fn as_bstr(&self) -> &'a BStr { + self.bs + } +} + +impl<'a> Iterator for CharIndices<'a> { + type Item = (usize, usize, char); + + #[inline] + fn next(&mut self) -> Option<(usize, usize, char)> { + let index = self.forward_index; + let (ch, size) = decode_lossy(self.bs.as_bytes()); + if size == 0 { + return None; + } + self.bs = &self.bs[size..]; + self.forward_index += size; + Some((index, index + size, ch)) + } +} + +impl<'a> DoubleEndedIterator for CharIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, usize, char)> { + let (ch, size) = decode_last_lossy(self.bs.as_bytes()); + if size == 0 { + return None; + } + self.bs = &self.bs[..self.bs.len()-size]; + self.reverse_index -= size; + Some((self.reverse_index, self.reverse_index + size, ch)) + } +} + +/// An error that occurs when UTF-8 decoding fails. +/// +/// This error occurs when attempting to convert a non-UTF-8 byte +/// string to a Rust string that must be valid UTF-8. For example, +/// [`to_str`](struct.BStr.html#method.to_str) is one such method. +/// +/// # Example +/// +/// This example shows what happens when a given byte sequence is invalid, +/// but ends with a sequence that is a possible prefix of valid UTF-8. +/// +/// ``` +/// use bstr::B; +/// +/// let s = B(b"foobar\xF1\x80\x80"); +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), None); +/// ``` +/// +/// This example shows what happens when a given byte sequence contains +/// invalid UTF-8. +/// +/// ``` +/// use bstr::B; +/// +/// let s = B(b"foobar\xF1\x80\x80quux"); +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// // The error length reports the maximum number of bytes that correspond to +/// // a valid prefix of a UTF-8 encoded codepoint. +/// assert_eq!(err.error_len(), Some(3)); +/// +/// // In contrast to the above which contains a single invalid prefix, +/// // consider the case of multiple individal bytes that are never valid +/// // prefixes. Note how the value of error_len changes! +/// let s = B(b"foobar\xFF\xFFquux"); +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), Some(1)); +/// +/// // The fact that it's an invalid prefix does not change error_len even +/// // when it immediately precedes the end of the string. +/// let s = B(b"foobar\xFF"); +/// let err = s.to_str().unwrap_err(); +/// assert_eq!(err.valid_up_to(), 6); +/// assert_eq!(err.error_len(), Some(1)); +/// ``` +#[derive(Debug, Eq, PartialEq)] +pub struct Utf8Error { + valid_up_to: usize, + error_len: Option, +} + +impl Utf8Error { + /// Returns the byte index of the position immediately following the last + /// valid UTF-8 byte. + /// + /// # Example + /// + /// This examples shows how `valid_up_to` can be used to retrieve a + /// possibly empty prefix that is guaranteed to be valid UTF-8: + /// + /// ``` + /// use bstr::B; + /// + /// let s = B(b"foobar\xF1\x80\x80quux"); + /// let err = s.to_str().unwrap_err(); + /// + /// // This is guaranteed to never panic. + /// let string = s[..err.valid_up_to()].to_str().unwrap(); + /// assert_eq!(string, "foobar"); + /// ``` + #[inline] + pub fn valid_up_to(&self) -> usize { + self.valid_up_to + } + + /// Returns the total number of invalid UTF-8 bytes immediately following + /// the position returned by `valid_up_to`. This value is always at least + /// `1`, but can be up to `3` if bytes form a valid prefix of some UTF-8 + /// encoded codepoint. + /// + /// If the end of the original input was found before a valid UTF-8 encoded + /// codepoint could be completed, then this returns `None`. This is useful + /// when processing streams, where a `None` value signals that more input + /// might be needed. + #[inline] + pub fn error_len(&self) -> Option { + self.error_len + } +} + +#[cfg(feature = "std")] +impl error::Error for Utf8Error { + fn description(&self) -> &str { "invalid UTF-8" } +} + +impl fmt::Display for Utf8Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid UTF-8 found at byte offset {}", self.valid_up_to) + } +} + +/// Returns OK if and only if the given slice is completely valid UTF-8. +/// +/// If the slice isn't valid UTF-8, then an error is returned that explains +/// the first location at which invalid UTF-89 was detected. +pub fn validate(slice: &[u8]) -> Result<(), Utf8Error> { + // The fast path for validating UTF-8. It steps through a UTF-8 automaton + // and uses a SIMD accelerated ASCII fast path on x86_64. If an error is + // detected, it backs up and runs the slower version of the UTF-8 automaton + // to determine correct error information. + fn fast(slice: &[u8]) -> Result<(), Utf8Error> { + let mut state = ACCEPT; + let mut i = 0; + + while i < slice.len() { + let b = slice[i]; + + // ASCII fast path. If we see two consecutive ASCII bytes, then try + // to validate as much ASCII as possible very quickly. + if state == ACCEPT + && b <= 0x7F + && slice.get(i+1).map_or(false, |&b| b <= 0x7F) + { + i += ascii::first_non_ascii_byte(&slice[i..]); + continue; + } + + state = step(state, b); + if state == REJECT { + return Err(find_valid_up_to(slice, i)); + } + i += 1; + } + if state != ACCEPT { + Err(find_valid_up_to(slice, slice.len())) + } else { + Ok(()) + } + } + + // Given the first position at which a UTF-8 sequence was determined to be + // invalid, return an error that correctly reports the position at which + // the last complete UTF-8 sequence ends. + #[inline(never)] + fn find_valid_up_to(slice: &[u8], rejected_at: usize) -> Utf8Error { + // In order to find the last valid byte, we need to back up an amount + // that guarantees every preceding byte is part of a valid UTF-8 + // code unit sequence. To do this, we simply locate the last leading + // byte that occurs before rejected_at. + let mut backup = rejected_at.saturating_sub(1); + while backup > 0 && !is_leading_utf8_byte(slice[backup]) { + backup -= 1; + } + let upto = cmp::min(slice.len(), rejected_at.saturating_add(1)); + let mut err = slow(&slice[backup..upto]).unwrap_err(); + err.valid_up_to += backup; + err + } + + // Like top-level UTF-8 decoding, except it correctly reports a UTF-8 error + // when an invalid sequence is found. This is split out from validate so + // that the fast path doesn't need to keep track of the position of the + // last valid UTF-8 byte. In particular, tracking this requires checking + // for an ACCEPT state on each byte, which degrades throughput pretty + // badly. + fn slow(slice: &[u8]) -> Result<(), Utf8Error> { + let mut state = ACCEPT; + let mut valid_up_to = 0; + for (i, &b) in slice.iter().enumerate() { + state = step(state, b); + if state == ACCEPT { + valid_up_to = i + 1; + } else if state == REJECT { + // Our error length must always be at least 1. + let error_len = Some(cmp::max(1, i - valid_up_to)); + return Err(Utf8Error { valid_up_to, error_len }); + } + } + if state != ACCEPT { + Err(Utf8Error { valid_up_to, error_len: None }) + } else { + Ok(()) + } + } + + // Advance to the next state given the current state and current byte. + fn step(state: usize, b: u8) -> usize { + let class = CLASSES[b as usize]; + // SAFETY: This is safe because 'class' is always <=11 and 'state' is + // always <=96. Therefore, the maximal index is 96+11 = 107, where + // STATES_FORWARD.len() = 108 such that every index is guaranteed to be + // valid by construction of the state machine and the byte equivalence + // classes. + unsafe { + *STATES_FORWARD.get_unchecked(state + class as usize) as usize + } + } + + fast(slice) +} + +/// UTF-8 decode a single Unicode scalar value from the beginning of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, `None` is returned along with the number of bytes that +/// make up a maximal prefix of a valid UTF-8 code unit sequence. In this case, +/// the number of bytes consumed is always between 0 and 3, inclusive, where +/// 0 is only returned when `slice` is empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::decode_utf8; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_utf8(b"\xE2\x98\x83"); +/// assert_eq!(Some('☃'), ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_utf8(b"\xE2\x98"); +/// assert_eq!(None, ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes, while replacing invalid UTF-8 sequences with the replacement +/// codepoint: +/// +/// ``` +/// use bstr::decode_utf8; +/// +/// let mut bytes = &b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"[..]; +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_utf8(bytes); +/// bytes = &bytes[size..]; +/// chars.push(ch.unwrap_or('\u{FFFD}')); +/// } +/// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars); +/// ``` +#[inline] +pub fn decode>(slice: B) -> (Option, usize) { + let slice = slice.as_ref(); + match slice.get(0) { + None => return (None, 0), + Some(&b) if b <= 0x7F => return (Some(b as char), 1), + _ => {} + } + + let (mut state, mut cp, mut i) = (ACCEPT, 0, 0); + while i < slice.len() { + decode_step(&mut state, &mut cp, slice[i]); + i += 1; + + if state == ACCEPT { + // SAFETY: This is safe because `decode_step` guarantees that + // `cp` is a valid Unicode scalar value in an ACCEPT state. + let ch = unsafe { char::from_u32_unchecked(cp) }; + return (Some(ch), i); + } else if state == REJECT { + // At this point, we always want to advance at least one byte. + return (None, cmp::max(1, i.saturating_sub(1))); + } + } + (None, i) +} + +/// Lossily UTF-8 decode a single Unicode scalar value from the beginning of a +/// slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned +/// along with the number of bytes that make up a maximal prefix of a valid +/// UTF-8 code unit sequence. In this case, the number of bytes consumed is +/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is +/// empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ```ignore +/// use bstr::decode_utf8_lossy; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98\x83"); +/// assert_eq!('☃', ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_utf8_lossy(b"\xE2\x98"); +/// assert_eq!('\u{FFFD}', ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes, while replacing invalid UTF-8 sequences with the replacement +/// codepoint: +/// +/// ```ignore +/// use bstr::decode_utf8_lossy; +/// +/// let mut bytes = &b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"[..]; +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_utf8_lossy(bytes); +/// bytes = &bytes[size..]; +/// chars.push(ch); +/// } +/// assert_eq!(vec!['☃', '\u{FFFD}', '𝞃', '\u{FFFD}', 'a'], chars); +/// ``` +#[inline] +pub fn decode_lossy>(slice: B) -> (char, usize) { + match decode(slice) { + (Some(ch), size) => (ch, size), + (None, size) => ('\u{FFFD}', size), + } +} + +/// UTF-8 decode a single Unicode scalar value from the end of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, `None` is returned along with the number of bytes that +/// make up a maximal prefix of a valid UTF-8 code unit sequence. In this case, +/// the number of bytes consumed is always between 0 and 3, inclusive, where +/// 0 is only returned when `slice` is empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bstr::decode_last_utf8; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_last_utf8(b"\xE2\x98\x83"); +/// assert_eq!(Some('☃'), ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_last_utf8(b"\xE2\x98"); +/// assert_eq!(None, ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes in reverse, while replacing invalid UTF-8 sequences with the +/// replacement codepoint: +/// +/// ``` +/// use bstr::decode_last_utf8; +/// +/// let mut bytes = &b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"[..]; +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_last_utf8(bytes); +/// bytes = &bytes[..bytes.len()-size]; +/// chars.push(ch.unwrap_or('\u{FFFD}')); +/// } +/// assert_eq!(vec!['a', '\u{FFFD}', '𝞃', '\u{FFFD}', '☃'], chars); +/// ``` +#[inline] +pub fn decode_last>(slice: B) -> (Option, usize) { + // TODO: We could implement this by reversing the UTF-8 automaton, but for + // now, we do it the slow way by using the forward automaton. + + let slice = slice.as_ref(); + if slice.is_empty() { + return (None, 0); + } + let mut start = slice.len() - 1; + let limit = slice.len().saturating_sub(4); + while start > limit && !is_leading_utf8_byte(slice[start]) { + start -= 1; + } + let (ch, size) = decode(&slice[start..]); + // If we didn't consume all of the bytes, then that means there's at least + // one stray byte that never occurs in a valid code unit prefix, so we can + // advance by one byte. + if start + size != slice.len() { + (None, 1) + } else { + (ch, size) + } +} + +/// Lossily UTF-8 decode a single Unicode scalar value from the end of a slice. +/// +/// When successful, the corresponding Unicode scalar value is returned along +/// with the number of bytes it was encoded with. The number of bytes consumed +/// for a successful decode is always between 1 and 4, inclusive. +/// +/// When unsuccessful, the Unicode replacement codepoint (`U+FFFD`) is returned +/// along with the number of bytes that make up a maximal prefix of a valid +/// UTF-8 code unit sequence. In this case, the number of bytes consumed is +/// always between 0 and 3, inclusive, where 0 is only returned when `slice` is +/// empty. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ```ignore +/// use bstr::decode_last_utf8_lossy; +/// +/// // Decoding a valid codepoint. +/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98\x83"); +/// assert_eq!('☃', ch); +/// assert_eq!(3, size); +/// +/// // Decoding an incomplete codepoint. +/// let (ch, size) = decode_last_utf8_lossy(b"\xE2\x98"); +/// assert_eq!('\u{FFFD}', ch); +/// assert_eq!(2, size); +/// ``` +/// +/// This example shows how to iterate over all codepoints in UTF-8 encoded +/// bytes in reverse, while replacing invalid UTF-8 sequences with the +/// replacement codepoint: +/// +/// ```ignore +/// use bstr::decode_last_utf8_lossy; +/// +/// let mut bytes = &b"\xE2\x98\x83\xFF\xF0\x9D\x9E\x83\xE2\x98\x61"[..]; +/// let mut chars = vec![]; +/// while !bytes.is_empty() { +/// let (ch, size) = decode_last_utf8_lossy(bytes); +/// bytes = &bytes[..bytes.len()-size]; +/// chars.push(ch); +/// } +/// assert_eq!(vec!['a', '\u{FFFD}', '𝞃', '\u{FFFD}', '☃'], chars); +/// ``` +#[inline] +pub fn decode_last_lossy>(slice: B) -> (char, usize) { + match decode_last(slice) { + (Some(ch), size) => (ch, size), + (None, size) => ('\u{FFFD}', size), + } +} + +#[inline] +pub fn decode_step(state: &mut usize, cp: &mut u32, b: u8) { + let class = CLASSES[b as usize]; + if *state == ACCEPT { + *cp = (0xFF >> class) & (b as u32); + } else { + *cp = (b as u32 & 0b111111) | (*cp << 6); + } + *state = STATES_FORWARD[*state + class as usize] as usize; +} + +fn is_leading_utf8_byte(b: u8) -> bool { + // In the ASCII case, the most significant bit is never set. The leading + // byte of a 2/3/4-byte sequence always has the top two most significant + // bigs set. + (b & 0b1100_0000) != 0b1000_0000 +} + +#[cfg(test)] +mod tests { + use std::char; + + use bstr::B; + use tests::LOSSY_TESTS; + use utf8::{self, Utf8Error}; + + fn utf8e(valid_up_to: usize) -> Utf8Error { + Utf8Error { valid_up_to, error_len: None } + } + + fn utf8e2(valid_up_to: usize, error_len: usize) -> Utf8Error { + Utf8Error { valid_up_to, error_len: Some(error_len) } + } + + #[test] + fn validate_all_codepoints() { + for i in 0..(0x10FFFF + 1) { + let cp = match char::from_u32(i) { + None => continue, + Some(cp) => cp, + }; + let mut buf = [0; 4]; + let s = cp.encode_utf8(&mut buf); + assert_eq!(Ok(()), utf8::validate(s.as_bytes())); + } + } + + #[test] + fn validate_multiple_codepoints() { + assert_eq!(Ok(()), utf8::validate(b"abc")); + assert_eq!(Ok(()), utf8::validate(b"a\xE2\x98\x83a")); + assert_eq!(Ok(()), utf8::validate(b"a\xF0\x9D\x9C\xB7a")); + assert_eq!(Ok(()), utf8::validate( + b"\xE2\x98\x83\xF0\x9D\x9C\xB7", + )); + assert_eq!(Ok(()), utf8::validate( + b"a\xE2\x98\x83a\xF0\x9D\x9C\xB7a", + )); + assert_eq!(Ok(()), utf8::validate( + b"\xEF\xBF\xBD\xE2\x98\x83\xEF\xBF\xBD", + )); + } + + #[test] + fn validate_errors() { + // single invalid byte + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xFF")); + // single invalid byte after ASCII + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xFF")); + // single invalid byte after 2 byte sequence + assert_eq!(Err(utf8e2(2, 1)), utf8::validate(b"\xCE\xB2\xFF")); + // single invalid byte after 3 byte sequence + assert_eq!(Err(utf8e2(3, 1)), utf8::validate(b"\xE2\x98\x83\xFF")); + // single invalid byte after 4 byte sequence + assert_eq!(Err(utf8e2(4, 1)), utf8::validate(b"\xF0\x9D\x9D\xB1\xFF")); + + // An invalid 2-byte sequence with a valid 1-byte prefix. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCE\xF0")); + // An invalid 3-byte sequence with a valid 2-byte prefix. + assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98\xF0")); + // An invalid 4-byte sequence with a valid 3-byte prefix. + assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9D\xF0")); + + // An overlong sequence. Should be \xE2\x82\xAC, but we encode the + // same codepoint value in 4 bytes. This not only tests that we reject + // overlong sequences, but that we get valid_up_to correct. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xF0\x82\x82\xAC")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xF0\x82\x82\xAC")); + assert_eq!(Err(utf8e2(3, 1)), utf8::validate( + b"\xE2\x98\x83\xF0\x82\x82\xAC", + )); + + // Check that encoding a surrogate codepoint using the UTF-8 scheme + // fails validation. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xED\xA0\x80")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xED\xA0\x80")); + assert_eq!(Err(utf8e2(3, 1)), utf8::validate( + b"\xE2\x98\x83\xED\xA0\x80", + )); + + // Check that an incomplete 2-byte sequence fails. + assert_eq!(Err(utf8e2(0, 1)), utf8::validate(b"\xCEa")); + assert_eq!(Err(utf8e2(1, 1)), utf8::validate(b"a\xCEa")); + assert_eq!(Err(utf8e2(3, 1)), utf8::validate( + b"\xE2\x98\x83\xCE\xE2\x98\x83", + )); + // Check that an incomplete 3-byte sequence fails. + assert_eq!(Err(utf8e2(0, 2)), utf8::validate(b"\xE2\x98a")); + assert_eq!(Err(utf8e2(1, 2)), utf8::validate(b"a\xE2\x98a")); + assert_eq!(Err(utf8e2(3, 2)), utf8::validate( + b"\xE2\x98\x83\xE2\x98\xE2\x98\x83", + )); + // Check that an incomplete 4-byte sequence fails. + assert_eq!(Err(utf8e2(0, 3)), utf8::validate(b"\xF0\x9D\x9Ca")); + assert_eq!(Err(utf8e2(1, 3)), utf8::validate(b"a\xF0\x9D\x9Ca")); + assert_eq!(Err(utf8e2(4, 3)), utf8::validate( + b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C\xE2\x98\x83", + )); + assert_eq!(Err(utf8e2(6, 3)), utf8::validate( + b"foobar\xF1\x80\x80quux", + )); + + // Check that an incomplete (EOF) 2-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xCE")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xCE")); + assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xCE")); + // Check that an incomplete (EOF) 3-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xE2\x98")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xE2\x98")); + assert_eq!(Err(utf8e(3)), utf8::validate(b"\xE2\x98\x83\xE2\x98")); + // Check that an incomplete (EOF) 4-byte sequence fails. + assert_eq!(Err(utf8e(0)), utf8::validate(b"\xF0\x9D\x9C")); + assert_eq!(Err(utf8e(1)), utf8::validate(b"a\xF0\x9D\x9C")); + assert_eq!(Err(utf8e(4)), utf8::validate( + b"\xF0\x9D\x9C\xB1\xF0\x9D\x9C", + )); + + // Test that we errors correct even after long valid sequences. This + // checks that our "backup" logic for detecting errors is correct. + assert_eq!(Err(utf8e2(8, 1)), utf8::validate( + b"\xe2\x98\x83\xce\xb2\xe3\x83\x84\xFF", + )); + } + + #[test] + fn decode_valid() { + fn d(mut s: &str) -> Vec { + let mut chars = vec![]; + while !s.is_empty() { + let (ch, size) = utf8::decode(s.as_bytes()); + s = &s[size..]; + chars.push(ch.unwrap()); + } + chars + } + + assert_eq!(vec!['☃'], d("☃")); + assert_eq!(vec!['☃', '☃'], d("☃☃")); + assert_eq!(vec!['α', 'β', 'γ', 'δ', 'ε'], d("αβγδε")); + assert_eq!(vec!['☃', '⛄', '⛇'], d("☃⛄⛇")); + assert_eq!(vec!['𝗮', '𝗯', '𝗰', '𝗱', '𝗲'], d("𝗮𝗯𝗰𝗱𝗲")); + } + + #[test] + fn decode_invalid() { + let (ch, size) = utf8::decode(b""); + assert_eq!(None, ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode(b"\xFF"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xCE\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xE2\x98\xF0"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9D"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9D\xF0"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode(b"\xF0\x82\x82\xAC"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xED\xA0\x80"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xCEa"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode(b"\xE2\x98a"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode(b"\xF0\x9D\x9Ca"); + assert_eq!(None, ch); + assert_eq!(3, size); + } + + #[test] + fn decode_lossy() { + let (ch, size) = utf8::decode_lossy(b""); + assert_eq!('\u{FFFD}', ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_lossy(b"\xFF"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xCE\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xE2\x98\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9D\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x82\x82\xAC"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xED\xA0\x80"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xCEa"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_lossy(b"\xE2\x98a"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_lossy(b"\xF0\x9D\x9Ca"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + } + + #[test] + fn decode_last_valid() { + fn d(mut s: &str) -> Vec { + let mut chars = vec![]; + while !s.is_empty() { + let (ch, size) = utf8::decode_last(s.as_bytes()); + s = &s[..s.len()-size]; + chars.push(ch.unwrap()); + } + chars + } + + assert_eq!(vec!['☃'], d("☃")); + assert_eq!(vec!['☃', '☃'], d("☃☃")); + assert_eq!(vec!['ε', 'δ', 'γ', 'β', 'α'], d("αβγδε")); + assert_eq!(vec!['⛇', '⛄', '☃'], d("☃⛄⛇")); + assert_eq!(vec!['𝗲', '𝗱', '𝗰', '𝗯', '𝗮'], d("𝗮𝗯𝗰𝗱𝗲")); + } + + #[test] + fn decode_last_invalid() { + let (ch, size) = utf8::decode_last(b""); + assert_eq!(None, ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_last(b"\xFF"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xCE\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xCE"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xE2\x98\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xE2\x98"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D\xF0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x9D\x9D"); + assert_eq!(None, ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_last(b"\xF0\x82\x82\xAC"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED\xA0\x80"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED\xA0"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"\xED"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"a\xCE"); + assert_eq!(None, ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last(b"a\xE2\x98"); + assert_eq!(None, ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last(b"a\xF0\x9D\x9C"); + assert_eq!(None, ch); + assert_eq!(3, size); + } + + #[test] + fn decode_last_lossy() { + let (ch, size) = utf8::decode_last_lossy(b""); + assert_eq!('\u{FFFD}', ch); + assert_eq!(0, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xFF"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xCE\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xCE"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xE2\x98"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D\xF0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x9D\x9D"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xF0\x82\x82\xAC"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0\x80"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED\xA0"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"\xED"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xCE"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(1, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xE2\x98"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(2, size); + + let (ch, size) = utf8::decode_last_lossy(b"a\xF0\x9D\x9C"); + assert_eq!('\u{FFFD}', ch); + assert_eq!(3, size); + } + + #[test] + fn chars() { + for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() { + let got: String = B(input).chars().collect(); + assert_eq!( + expected, got, + "chars(ith: {:?}, given: {:?})", i, input, + ); + let got: String = B(input) + .char_indices() + .map(|(_, _, ch)| ch) + .collect(); + assert_eq!( + expected, got, + "char_indices(ith: {:?}, given: {:?})", i, input, + ); + + let expected: String = expected.chars().rev().collect(); + + let got: String = B(input).chars().rev().collect(); + assert_eq!( + expected, got, + "chars.rev(ith: {:?}, given: {:?})", i, input, + ); + let got: String = B(input) + .char_indices() + .rev() + .map(|(_, _, ch)| ch) + .collect(); + assert_eq!( + expected, got, + "char_indices.rev(ith: {:?}, given: {:?})", i, input, + ); + } + } +} diff --git a/bufstream/.cargo-checksum.json b/bufstream/.cargo-checksum.json new file mode 100644 index 000000000..15d5b4014 --- /dev/null +++ b/bufstream/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"} \ No newline at end of file diff --git a/bufstream/Cargo.toml b/bufstream/Cargo.toml new file mode 100644 index 000000000..31fdded48 --- /dev/null +++ b/bufstream/Cargo.toml @@ -0,0 +1,32 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bufstream" +version = "0.1.4" +authors = ["The Rust Project Developers"] +description = "Buffered I/O for streams where each read/write half is separately buffered\n" +homepage = "https://github.com/alexcrichton/bufstream" +documentation = "https://docs.rs/bufstream" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/bufstream" +[dependencies.futures] +version = "0.1.13" +optional = true + +[dependencies.tokio-io] +version = "0.1.1" +optional = true + +[features] +default = [] +tokio = ["futures", "tokio-io"] diff --git a/bufstream/LICENSE-APACHE b/bufstream/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bufstream/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bufstream/LICENSE-MIT b/bufstream/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/bufstream/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bufstream/README.md b/bufstream/README.md new file mode 100644 index 000000000..d3cf0eb47 --- /dev/null +++ b/bufstream/README.md @@ -0,0 +1,22 @@ +bufstream +========= + +Buffered I/O streams for reading/writing + +[![Build Status](https://travis-ci.org/alexcrichton/bufstream.svg?branch=master)](https://travis-ci.org/alexcrichton/bufstream) + +[Documentation](https://docs.rs/bufstream/) + +## Usage + +```toml +[dependencies] +bufstream = "0.1" +``` + +## Tokio + +There is support for tokio's `AsyncRead` + `AsyncWrite` traits through the `tokio` +feature. When using this crate with asynchronous IO, make sure to properly flush +the stream before dropping it since IO during drop may cause panics. For the same +reason you should stay away from `BufStream::into_inner`. diff --git a/bufstream/src/lib.rs b/bufstream/src/lib.rs new file mode 100644 index 000000000..8e2e6c516 --- /dev/null +++ b/bufstream/src/lib.rs @@ -0,0 +1,262 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A crate for separately buffered streams. +//! +//! This crate provides a `BufStream` type which provides buffering of both the +//! reading and writing halves of a `Read + Write` type. Each half is completely +//! independently buffered of the other, which may not always be desired. For +//! example `BufStream` may have surprising semantics. +//! +//! # Usage +//! +//! ```toml +//! [dependencies] +//! bufstream = "0.1" +//! ``` +//! +//! ```no_run +//! use std::io::prelude::*; +//! use std::net::TcpStream; +//! use bufstream::BufStream; +//! +//! +//! let stream = TcpStream::connect("localhost:4000").unwrap(); +//! let mut buf = BufStream::new(stream); +//! buf.read(&mut [0; 1024]).unwrap(); +//! buf.write(&[0; 1024]).unwrap(); +//! ``` +//! +//! # Async I/O +//! +//! This crate optionally can support async I/O streams with the [Tokio stack] via +//! the `tokio` feature of this crate: +//! +//! [Tokio stack]: https://tokio.rs/ +//! +//! ```toml +//! bufstream = { version = "0.2", features = ["tokio"] } +//! ``` +//! +//! All methods are internally capable of working with streams that may return +//! [`ErrorKind::WouldBlock`] when they're not ready to perform the particular +//! operation. +//! +//! [`ErrorKind::WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html +//! +//! Note that care needs to be taken when using these objects, however. The +//! Tokio runtime, in particular, requires that data is fully flushed before +//! dropping streams. For compatibility with blocking streams all streams are +//! flushed/written when they are dropped, and this is not always a suitable +//! time to perform I/O. If I/O streams are flushed before drop, however, then +//! these operations will be a noop. + +#[cfg(feature = "tokio")] extern crate futures; +#[cfg(feature = "tokio")] #[macro_use] extern crate tokio_io; + +use std::fmt; +use std::io::prelude::*; +use std::io::{self, BufReader, BufWriter}; +use std::error; + +#[cfg(feature = "tokio")] use futures::Poll; +#[cfg(feature = "tokio")] use tokio_io::{AsyncRead, AsyncWrite}; + +const DEFAULT_BUF_SIZE: usize = 8 * 1024; + +/// Wraps a Stream and buffers input and output to and from it. +/// +/// It can be excessively inefficient to work directly with a `Read+Write`. For +/// example, every call to `read` or `write` on `TcpStream` results in a system +/// call. A `BufStream` keeps in memory buffers of data, making large, +/// infrequent calls to `read` and `write` on the underlying `Read+Write`. +/// +/// The output buffer will be written out when this stream is dropped. +#[derive(Debug)] +pub struct BufStream { + inner: BufReader> +} + +/// An error returned by `into_inner` which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +#[derive(Debug)] +pub struct IntoInnerError(W, io::Error); + +impl IntoInnerError { + /// Returns the error which caused the call to `into_inner()` to fail. + /// + /// This error was returned when attempting to write the internal buffer. + pub fn error(&self) -> &io::Error { &self.1 } + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + pub fn into_inner(self) -> W { self.0 } +} + +impl From> for io::Error { + fn from(iie: IntoInnerError) -> io::Error { iie.1 } +} + +impl error::Error for IntoInnerError { + fn description(&self) -> &str { + error::Error::description(self.error()) + } +} + +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error().fmt(f) + } +} + +struct InternalBufWriter(Option>); + +impl InternalBufWriter { + fn get_ref(&self) -> &BufWriter { + self.0.as_ref().unwrap() + } + + fn get_mut(&mut self) -> &mut BufWriter { + self.0.as_mut().unwrap() + } +} + +impl Read for InternalBufWriter { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().get_mut().read(buf) + } +} + +impl fmt::Debug for InternalBufWriter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.get_ref().fmt(f) + } +} + +impl BufStream { + /// Creates a new buffered stream with explicitly listed capacities for the + /// reader/writer buffer. + pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) + -> BufStream { + let writer = BufWriter::with_capacity(writer_cap, inner); + let internal_writer = InternalBufWriter(Some(writer)); + let reader = BufReader::with_capacity(reader_cap, internal_writer); + BufStream { inner: reader } + } + + /// Creates a new buffered stream with the default reader/writer buffer + /// capacities. + pub fn new(inner: S) -> BufStream { + BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner) + } + + /// Gets a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + self.inner.get_ref().get_ref().get_ref() + } + + /// Gets a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read directly from or write directly to the + /// underlying stream. + pub fn get_mut(&mut self) -> &mut S { + self.inner.get_mut().get_mut().get_mut() + } + + /// Unwraps this `BufStream`, returning the underlying stream. + /// + /// The internal write buffer is written out before returning the stream. + /// Any leftover data in the read buffer is lost. + pub fn into_inner(mut self) -> Result>> { + let e = { + let InternalBufWriter(ref mut w) = *self.inner.get_mut(); + let (e, w2) = match w.take().unwrap().into_inner() { + Ok(s) => return Ok(s), + Err(err) => { + (io::Error::new(err.error().kind(), err.error().to_string()), + err.into_inner()) + } + }; + *w = Some(w2); + e + }; + Err(IntoInnerError(self, e)) + } +} + +impl BufRead for BufStream { + fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + fn consume(&mut self, amt: usize) { self.inner.consume(amt) } + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { + self.inner.read_until(byte, buf) + } + fn read_line(&mut self, string: &mut String) -> io::Result { + self.inner.read_line(string) + } +} + +impl Read for BufStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +impl Write for BufStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.get_mut().0.as_mut().unwrap().write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.get_mut().0.as_mut().unwrap().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for BufStream {} + +#[cfg(feature = "tokio")] +impl AsyncWrite for BufStream { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.flush()); + let mut inner = self.inner.get_mut().0.as_mut().unwrap(); + inner.shutdown() + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::io; + + use super::BufStream; + // This is just here to make sure that we don't infinite loop in the + // newtype struct autoderef weirdness + #[test] + fn test_buffered_stream() { + struct S; + + impl Write for S { + fn write(&mut self, b: &[u8]) -> io::Result { Ok(b.len()) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + + impl Read for S { + fn read(&mut self, _: &mut [u8]) -> io::Result { Ok(0) } + } + + let mut stream = BufStream::new(S); + assert_eq!(stream.read(&mut [0; 10]).unwrap(), 0); + stream.write(&[0; 10]).unwrap(); + stream.flush().unwrap(); + } +} diff --git a/byteorder/.cargo-checksum.json b/byteorder/.cargo-checksum.json new file mode 100644 index 000000000..2d70b83c1 --- /dev/null +++ b/byteorder/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"} \ No newline at end of file diff --git a/byteorder/CHANGELOG.md b/byteorder/CHANGELOG.md new file mode 100644 index 000000000..020beb464 --- /dev/null +++ b/byteorder/CHANGELOG.md @@ -0,0 +1,114 @@ +1.3.0 +===== +This new minor release now enables `i128` support automatically on Rust +compilers that support 128-bit integers. The `i128` feature is now a no-op, but +continues to exist for backward compatibility purposes. The crate continues to +maintain compatibility with Rust 1.12.0. + +This release also deprecates the `ByteOrder` trait methods +`read_f32_into_unchecked` and `read_f64_into_unchecked` in favor of +`read_f32_into` and `read_f64_into`. This was an oversight from the 1.2 release +where the corresponding methods on `ReadBytesExt` were deprecated. + +`quickcheck` and `rand` were bumped to `0.8` and `0.6`, respectively. + +A few small documentation related bugs have been fixed. + + +1.2.7 +===== +This patch release excludes some CI files from the crate release and updates +the license field to use `OR` instead of `/`. + + +1.2.6 +===== +This patch release fixes some test compilation errors introduced by an +over-eager release of 1.2.5. + + +1.2.5 +===== +This patch release fixes some typos in the docs, adds doc tests to methods on +`WriteByteExt` and bumps the quickcheck dependency to `0.7`. + + +1.2.4 +===== +This patch release adds support for 48-bit integers by adding the following +methods to the `ByteOrder` trait: `read_u48`, `read_i48`, `write_u48` and +`write_i48`. Corresponding methods have been added to the `ReadBytesExt` and +`WriteBytesExt` traits as well. + + +1.2.3 +===== +This patch release removes the use of `feature(i128_type)` from byteorder, +since it has been stabilized. We leave byteorder's `i128` feature in place +in order to continue supporting compilation on older versions of Rust. + + +1.2.2 +===== +This patch release only consists of internal improvements and refactorings. +Notably, this removes all uses of `transmute` and instead uses pointer casts. + + +1.2.1 +===== +This patch release removes more unnecessary uses of `unsafe` that +were overlooked in the prior `1.2.0` release. In particular, the +`ReadBytesExt::read_{f32,f64}_into_checked` methods have been deprecated and +replaced by more appropriately named `read_{f32,f64}_into` methods. + + +1.2.0 +===== +The most prominent change in this release of `byteorder` is the removal of +unnecessary signaling NaN masking, and in turn, the `unsafe` annotations +associated with methods that didn't do masking. See +[#103](https://github.com/BurntSushi/byteorder/issues/103) +for more details. + +* [BUG #102](https://github.com/BurntSushi/byteorder/issues/102): + Fix big endian tests. +* [BUG #103](https://github.com/BurntSushi/byteorder/issues/103): + Remove sNaN masking. + + +1.1.0 +===== +This release of `byteorder` features a number of fixes and improvements, mostly +as a result of the +[Litz Blitz evaluation](https://public.etherpad-mozilla.org/p/rust-crate-eval-byteorder). + +Feature enhancements: + +* [FEATURE #63](https://github.com/BurntSushi/byteorder/issues/63): + Add methods for reading/writing slices of numbers for a specific + endianness. +* [FEATURE #65](https://github.com/BurntSushi/byteorder/issues/65): + Add support for `u128`/`i128` types. (Behind the nightly only `i128` + feature.) +* [FEATURE #72](https://github.com/BurntSushi/byteorder/issues/72): + Add "panics" and "errors" sections for each relevant public API item. +* [FEATURE #74](https://github.com/BurntSushi/byteorder/issues/74): + Add CI badges to Cargo.toml. +* [FEATURE #75](https://github.com/BurntSushi/byteorder/issues/75): + Add more examples to public API items. +* Add 24-bit read/write methods. +* Add `BE` and `LE` type aliases for `BigEndian` and `LittleEndian`, + respectively. + +Bug fixes: + +* [BUG #68](https://github.com/BurntSushi/byteorder/issues/68): + Panic in {BigEndian,LittleEndian}::default. +* [BUG #69](https://github.com/BurntSushi/byteorder/issues/69): + Seal the `ByteOrder` trait to prevent out-of-crate implementations. +* [BUG #71](https://github.com/BurntSushi/byteorder/issues/71): + Guarantee that the results of `read_f32`/`read_f64` are always defined. +* [BUG #73](https://github.com/BurntSushi/byteorder/issues/73): + Add crates.io categories. +* [BUG #77](https://github.com/BurntSushi/byteorder/issues/77): + Add `html_root` doc attribute. diff --git a/byteorder/COPYING b/byteorder/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/byteorder/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/byteorder/Cargo.toml b/byteorder/Cargo.toml new file mode 100644 index 000000000..a2c32cbae --- /dev/null +++ b/byteorder/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "byteorder" +version = "1.3.1" +authors = ["Andrew Gallant "] +build = "build.rs" +exclude = ["/ci/*"] +description = "Library for reading/writing numbers in big-endian and little-endian." +homepage = "https://github.com/BurntSushi/byteorder" +documentation = "https://docs.rs/byteorder" +readme = "README.md" +keywords = ["byte", "endian", "big-endian", "little-endian", "binary"] +categories = ["encoding", "parsing"] +license = "Unlicense OR MIT" +repository = "https://github.com/BurntSushi/byteorder" +[profile.bench] +opt-level = 3 + +[lib] +name = "byteorder" +bench = false +[dev-dependencies.quickcheck] +version = "0.8" +default-features = false + +[dev-dependencies.rand] +version = "0.6" + +[features] +default = ["std"] +i128 = [] +std = [] +[badges.travis-ci] +repository = "BurntSushi/byteorder" diff --git a/byteorder/LICENSE-MIT b/byteorder/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/byteorder/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/byteorder/README.md b/byteorder/README.md new file mode 100644 index 000000000..f282ab72e --- /dev/null +++ b/byteorder/README.md @@ -0,0 +1,56 @@ +This crate provides convenience methods for encoding and decoding numbers in +either big-endian or little-endian order. + +[![Build status](https://api.travis-ci.org/BurntSushi/byteorder.svg)](https://travis-ci.org/BurntSushi/byteorder) +[![](http://meritbadge.herokuapp.com/byteorder)](https://crates.io/crates/byteorder) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/byteorder + + +### Installation + +This crate works with Cargo and is on +[crates.io](https://crates.io/crates/byteorder). Add it to your `Cargo.toml` +like so: + +```toml +[dependencies] +byteorder = "1" +``` + +If you want to augment existing `Read` and `Write` traits, then import the +extension methods like so: + +```rust +extern crate byteorder; + +use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian}; +``` + +For example: + +```rust +use std::io::Cursor; +use byteorder::{BigEndian, ReadBytesExt}; + +let mut rdr = Cursor::new(vec![2, 5, 3, 0]); +// Note that we use type parameters to indicate which kind of byte order +// we want! +assert_eq!(517, rdr.read_u16::().unwrap()); +assert_eq!(768, rdr.read_u16::().unwrap()); +``` + +### `no_std` crates + +This crate has a feature, `std`, that is enabled by default. To use this crate +in a `no_std` context, add the following to your `Cargo.toml`: + +```toml +[dependencies] +byteorder = { version = "1", default-features = false } +``` diff --git a/byteorder/UNLICENSE b/byteorder/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/byteorder/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/byteorder/benches/bench.rs b/byteorder/benches/bench.rs new file mode 100644 index 000000000..d53d25e4b --- /dev/null +++ b/byteorder/benches/bench.rs @@ -0,0 +1,328 @@ +#![feature(test)] + +extern crate byteorder; +extern crate rand; +extern crate test; + +macro_rules! bench_num { + ($name:ident, $read:ident, $bytes:expr, $data:expr) => ( + mod $name { + use byteorder::{ByteOrder, BigEndian, NativeEndian, LittleEndian}; + use super::test::Bencher; + use super::test::black_box as bb; + + const NITER: usize = 100_000; + + #[bench] + fn read_big_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(BigEndian::$read(&buf, $bytes)); + } + }); + } + + #[bench] + fn read_little_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(LittleEndian::$read(&buf, $bytes)); + } + }); + } + + #[bench] + fn read_native_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(NativeEndian::$read(&buf, $bytes)); + } + }); + } + } + ); + ($ty:ident, $max:ident, + $read:ident, $write:ident, $size:expr, $data:expr) => ( + mod $ty { + use std::$ty; + use byteorder::{ByteOrder, BigEndian, NativeEndian, LittleEndian}; + use super::test::Bencher; + use super::test::black_box as bb; + + const NITER: usize = 100_000; + + #[bench] + fn read_big_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(BigEndian::$read(&buf)); + } + }); + } + + #[bench] + fn read_little_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(LittleEndian::$read(&buf)); + } + }); + } + + #[bench] + fn read_native_endian(b: &mut Bencher) { + let buf = $data; + b.iter(|| { + for _ in 0..NITER { + bb(NativeEndian::$read(&buf)); + } + }); + } + + #[bench] + fn write_big_endian(b: &mut Bencher) { + let mut buf = $data; + let n = $ty::$max; + b.iter(|| { + for _ in 0..NITER { + bb(BigEndian::$write(&mut buf, n)); + } + }); + } + + #[bench] + fn write_little_endian(b: &mut Bencher) { + let mut buf = $data; + let n = $ty::$max; + b.iter(|| { + for _ in 0..NITER { + bb(LittleEndian::$write(&mut buf, n)); + } + }); + } + + #[bench] + fn write_native_endian(b: &mut Bencher) { + let mut buf = $data; + let n = $ty::$max; + b.iter(|| { + for _ in 0..NITER { + bb(NativeEndian::$write(&mut buf, n)); + } + }); + } + } + ); +} + +bench_num!(u16, MAX, read_u16, write_u16, 2, [1, 2]); +bench_num!(i16, MAX, read_i16, write_i16, 2, [1, 2]); +bench_num!(u32, MAX, read_u32, write_u32, 4, [1, 2, 3, 4]); +bench_num!(i32, MAX, read_i32, write_i32, 4, [1, 2, 3, 4]); +bench_num!(u64, MAX, read_u64, write_u64, 8, [1, 2, 3, 4, 5, 6, 7, 8]); +bench_num!(i64, MAX, read_i64, write_i64, 8, [1, 2, 3, 4, 5, 6, 7, 8]); +bench_num!(f32, MAX, read_f32, write_f32, 4, [1, 2, 3, 4]); +bench_num!(f64, MAX, read_f64, write_f64, 8, + [1, 2, 3, 4, 5, 6, 7, 8]); + +bench_num!(uint_1, read_uint, 1, [1]); +bench_num!(uint_2, read_uint, 2, [1, 2]); +bench_num!(uint_3, read_uint, 3, [1, 2, 3]); +bench_num!(uint_4, read_uint, 4, [1, 2, 3, 4]); +bench_num!(uint_5, read_uint, 5, [1, 2, 3, 4, 5]); +bench_num!(uint_6, read_uint, 6, [1, 2, 3, 4, 5, 6]); +bench_num!(uint_7, read_uint, 7, [1, 2, 3, 4, 5, 6, 7]); +bench_num!(uint_8, read_uint, 8, [1, 2, 3, 4, 5, 6, 7, 8]); + +bench_num!(int_1, read_int, 1, [1]); +bench_num!(int_2, read_int, 2, [1, 2]); +bench_num!(int_3, read_int, 3, [1, 2, 3]); +bench_num!(int_4, read_int, 4, [1, 2, 3, 4]); +bench_num!(int_5, read_int, 5, [1, 2, 3, 4, 5]); +bench_num!(int_6, read_int, 6, [1, 2, 3, 4, 5, 6]); +bench_num!(int_7, read_int, 7, [1, 2, 3, 4, 5, 6, 7]); +bench_num!(int_8, read_int, 8, [1, 2, 3, 4, 5, 6, 7, 8]); + +#[cfg(byteorder_i128)] +bench_num!(u128, MAX, read_u128, write_u128, + 16, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); +#[cfg(byteorder_i128)] +bench_num!(i128, MAX, read_i128, write_i128, + 16, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + +#[cfg(byteorder_i128)] +bench_num!(uint128_1, read_uint128, + 1, [1]); +#[cfg(byteorder_i128)] +bench_num!(uint128_2, read_uint128, + 2, [1, 2]); +#[cfg(byteorder_i128)] +bench_num!(uint128_3, read_uint128, + 3, [1, 2, 3]); +#[cfg(byteorder_i128)] +bench_num!(uint128_4, read_uint128, + 4, [1, 2, 3, 4]); +#[cfg(byteorder_i128)] +bench_num!(uint128_5, read_uint128, + 5, [1, 2, 3, 4, 5]); +#[cfg(byteorder_i128)] +bench_num!(uint128_6, read_uint128, + 6, [1, 2, 3, 4, 5, 6]); +#[cfg(byteorder_i128)] +bench_num!(uint128_7, read_uint128, + 7, [1, 2, 3, 4, 5, 6, 7]); +#[cfg(byteorder_i128)] +bench_num!(uint128_8, read_uint128, + 8, [1, 2, 3, 4, 5, 6, 7, 8]); +#[cfg(byteorder_i128)] +bench_num!(uint128_9, read_uint128, + 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]); +#[cfg(byteorder_i128)] +bench_num!(uint128_10, read_uint128, + 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +#[cfg(byteorder_i128)] +bench_num!(uint128_11, read_uint128, + 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); +#[cfg(byteorder_i128)] +bench_num!(uint128_12, read_uint128, + 12, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); +#[cfg(byteorder_i128)] +bench_num!(uint128_13, read_uint128, + 13, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]); +#[cfg(byteorder_i128)] +bench_num!(uint128_14, read_uint128, + 14, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); +#[cfg(byteorder_i128)] +bench_num!(uint128_15, read_uint128, + 15, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); +#[cfg(byteorder_i128)] +bench_num!(uint128_16, read_uint128, + 16, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + +#[cfg(byteorder_i128)] +bench_num!(int128_1, read_int128, + 1, [1]); +#[cfg(byteorder_i128)] +bench_num!(int128_2, read_int128, + 2, [1, 2]); +#[cfg(byteorder_i128)] +bench_num!(int128_3, read_int128, + 3, [1, 2, 3]); +#[cfg(byteorder_i128)] +bench_num!(int128_4, read_int128, + 4, [1, 2, 3, 4]); +#[cfg(byteorder_i128)] +bench_num!(int128_5, read_int128, + 5, [1, 2, 3, 4, 5]); +#[cfg(byteorder_i128)] +bench_num!(int128_6, read_int128, + 6, [1, 2, 3, 4, 5, 6]); +#[cfg(byteorder_i128)] +bench_num!(int128_7, read_int128, + 7, [1, 2, 3, 4, 5, 6, 7]); +#[cfg(byteorder_i128)] +bench_num!(int128_8, read_int128, + 8, [1, 2, 3, 4, 5, 6, 7, 8]); +#[cfg(byteorder_i128)] +bench_num!(int128_9, read_int128, + 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]); +#[cfg(byteorder_i128)] +bench_num!(int128_10, read_int128, + 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +#[cfg(byteorder_i128)] +bench_num!(int128_11, read_int128, + 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); +#[cfg(byteorder_i128)] +bench_num!(int128_12, read_int128, + 12, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); +#[cfg(byteorder_i128)] +bench_num!(int128_13, read_int128, + 13, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]); +#[cfg(byteorder_i128)] +bench_num!(int128_14, read_int128, + 14, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); +#[cfg(byteorder_i128)] +bench_num!(int128_15, read_int128, + 15, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); +#[cfg(byteorder_i128)] +bench_num!(int128_16, read_int128, + 16, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + + +macro_rules! bench_slice { + ($name:ident, $numty:ty, $read:ident, $write:ident) => { + mod $name { + use std::mem::size_of; + + use byteorder::{ByteOrder, BigEndian, LittleEndian}; + use rand::{self, Rng}; + use rand::distributions; + use test::Bencher; + + #[bench] + fn read_big_endian(b: &mut Bencher) { + let mut numbers: Vec<$numty> = rand::thread_rng() + .sample_iter(&distributions::Standard) + .take(100000) + .collect(); + let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; + BigEndian::$write(&numbers, &mut bytes); + + b.bytes = bytes.len() as u64; + b.iter(|| { + BigEndian::$read(&bytes, &mut numbers); + }); + } + + #[bench] + fn read_little_endian(b: &mut Bencher) { + let mut numbers: Vec<$numty> = rand::thread_rng() + .sample_iter(&distributions::Standard) + .take(100000) + .collect(); + let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; + LittleEndian::$write(&numbers, &mut bytes); + + b.bytes = bytes.len() as u64; + b.iter(|| { + LittleEndian::$read(&bytes, &mut numbers); + }); + } + + #[bench] + fn write_big_endian(b: &mut Bencher) { + let numbers: Vec<$numty> = rand::thread_rng() + .sample_iter(&distributions::Standard) + .take(100000) + .collect(); + let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; + + b.bytes = bytes.len() as u64; + b.iter(|| { + BigEndian::$write(&numbers, &mut bytes); + }); + } + + #[bench] + fn write_little_endian(b: &mut Bencher) { + let numbers: Vec<$numty> = rand::thread_rng() + .sample_iter(&distributions::Standard) + .take(100000) + .collect(); + let mut bytes = vec![0; numbers.len() * size_of::<$numty>()]; + + b.bytes = bytes.len() as u64; + b.iter(|| { + LittleEndian::$write(&numbers, &mut bytes); + }); + } + } + } +} + +bench_slice!(slice_u64, u64, read_u64_into, write_u64_into); diff --git a/byteorder/build.rs b/byteorder/build.rs new file mode 100644 index 000000000..002135b64 --- /dev/null +++ b/byteorder/build.rs @@ -0,0 +1,87 @@ +use std::env; +use std::ffi::OsString; +use std::io::{self, Write}; +use std::process::Command; + +fn main() { + let version = match Version::read() { + Ok(version) => version, + Err(err) => { + writeln!( + &mut io::stderr(), + "failed to parse `rustc --version`: {}", + err + ).unwrap(); + return; + } + }; + enable_i128(version); +} + +fn enable_i128(version: Version) { + if version < (Version { major: 1, minor: 26, patch: 0 }) { + return; + } + + println!("cargo:rustc-cfg=byteorder_i128"); +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +struct Version { + major: u32, + minor: u32, + patch: u32, +} + +impl Version { + fn read() -> Result { + let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); + let output = Command::new(&rustc) + .arg("--version") + .output() + .unwrap() + .stdout; + Version::parse(&String::from_utf8(output).unwrap()) + } + + fn parse(mut s: &str) -> Result { + if !s.starts_with("rustc ") { + return Err(format!("unrecognized version string: {}", s)); + } + s = &s["rustc ".len()..]; + + let parts: Vec<&str> = s.split(".").collect(); + if parts.len() < 3 { + return Err(format!("not enough version parts: {:?}", parts)); + } + + let mut num = String::new(); + for c in parts[0].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let major = try!(num.parse::().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[1].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let minor = try!(num.parse::().map_err(|e| e.to_string())); + + num.clear(); + for c in parts[2].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let patch = try!(num.parse::().map_err(|e| e.to_string())); + + Ok(Version { major: major, minor: minor, patch: patch }) + } +} diff --git a/byteorder/src/io.rs b/byteorder/src/io.rs new file mode 100644 index 000000000..bc49a1c9c --- /dev/null +++ b/byteorder/src/io.rs @@ -0,0 +1,1569 @@ +use std::io::{self, Result}; +use std::slice; + +use ByteOrder; + +/// Extends [`Read`] with methods for reading numbers. (For `std::io`.) +/// +/// Most of the methods defined here have an unconstrained type parameter that +/// must be explicitly instantiated. Typically, it is instantiated with either +/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate. +/// +/// # Examples +/// +/// Read unsigned 16 bit big-endian integers from a [`Read`]: +/// +/// ```rust +/// use std::io::Cursor; +/// use byteorder::{BigEndian, ReadBytesExt}; +/// +/// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); +/// assert_eq!(517, rdr.read_u16::().unwrap()); +/// assert_eq!(768, rdr.read_u16::().unwrap()); +/// ``` +/// +/// [`BigEndian`]: enum.BigEndian.html +/// [`LittleEndian`]: enum.LittleEndian.html +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +pub trait ReadBytesExt: io::Read { + /// Reads an unsigned 8 bit integer from the underlying reader. + /// + /// Note that since this reads a single byte, no byte order conversions + /// are used. It is included for completeness. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read unsigned 8 bit integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::ReadBytesExt; + /// + /// let mut rdr = Cursor::new(vec![2, 5]); + /// assert_eq!(2, rdr.read_u8().unwrap()); + /// assert_eq!(5, rdr.read_u8().unwrap()); + /// ``` + #[inline] + fn read_u8(&mut self) -> Result { + let mut buf = [0; 1]; + try!(self.read_exact(&mut buf)); + Ok(buf[0]) + } + + /// Reads a signed 8 bit integer from the underlying reader. + /// + /// Note that since this reads a single byte, no byte order conversions + /// are used. It is included for completeness. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read signed 8 bit integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::ReadBytesExt; + /// + /// let mut rdr = Cursor::new(vec![0x02, 0xfb]); + /// assert_eq!(2, rdr.read_i8().unwrap()); + /// assert_eq!(-5, rdr.read_i8().unwrap()); + /// ``` + #[inline] + fn read_i8(&mut self) -> Result { + let mut buf = [0; 1]; + try!(self.read_exact(&mut buf)); + Ok(buf[0] as i8) + } + + /// Reads an unsigned 16 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read unsigned 16 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); + /// assert_eq!(517, rdr.read_u16::().unwrap()); + /// assert_eq!(768, rdr.read_u16::().unwrap()); + /// ``` + #[inline] + fn read_u16(&mut self) -> Result { + let mut buf = [0; 2]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u16(&buf)) + } + + /// Reads a signed 16 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read signed 16 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x00, 0xc1, 0xff, 0x7c]); + /// assert_eq!(193, rdr.read_i16::().unwrap()); + /// assert_eq!(-132, rdr.read_i16::().unwrap()); + /// ``` + #[inline] + fn read_i16(&mut self) -> Result { + let mut buf = [0; 2]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i16(&buf)) + } + + /// Reads an unsigned 24 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read unsigned 24 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x00, 0x01, 0x0b]); + /// assert_eq!(267, rdr.read_u24::().unwrap()); + /// ``` + #[inline] + fn read_u24(&mut self) -> Result { + let mut buf = [0; 3]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u24(&buf)) + } + + /// Reads a signed 24 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read signed 24 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0xff, 0x7a, 0x33]); + /// assert_eq!(-34253, rdr.read_i24::().unwrap()); + /// ``` + #[inline] + fn read_i24(&mut self) -> Result { + let mut buf = [0; 3]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i24(&buf)) + } + + /// Reads an unsigned 32 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read unsigned 32 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x00, 0x00, 0x01, 0x0b]); + /// assert_eq!(267, rdr.read_u32::().unwrap()); + /// ``` + #[inline] + fn read_u32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u32(&buf)) + } + + /// Reads a signed 32 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read signed 32 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0xff, 0xff, 0x7a, 0x33]); + /// assert_eq!(-34253, rdr.read_i32::().unwrap()); + /// ``` + #[inline] + fn read_i32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i32(&buf)) + } + + /// Reads an unsigned 48 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read unsigned 48 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0xb6, 0x71, 0x6b, 0xdc, 0x2b, 0x31]); + /// assert_eq!(200598257150769, rdr.read_u48::().unwrap()); + /// ``` + #[inline] + fn read_u48(&mut self) -> Result { + let mut buf = [0; 6]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u48(&buf)) + } + + /// Reads a signed 48 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read signed 48 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x9d, 0x71, 0xab, 0xe7, 0x97, 0x8f]); + /// assert_eq!(-108363435763825, rdr.read_i48::().unwrap()); + /// ``` + #[inline] + fn read_i48(&mut self) -> Result { + let mut buf = [0; 6]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i48(&buf)) + } + + /// Reads an unsigned 64 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read an unsigned 64 bit big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83]); + /// assert_eq!(918733457491587, rdr.read_u64::().unwrap()); + /// ``` + #[inline] + fn read_u64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u64(&buf)) + } + + /// Reads a signed 64 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a signed 64 bit big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0]); + /// assert_eq!(i64::min_value(), rdr.read_i64::().unwrap()); + /// ``` + #[inline] + fn read_i64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i64(&buf)) + } + + /// Reads an unsigned 128 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read an unsigned 128 bit big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83, + /// 0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83 + /// ]); + /// assert_eq!(16947640962301618749969007319746179, rdr.read_u128::().unwrap()); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_u128(&mut self) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf)); + Ok(T::read_u128(&buf)) + } + + /// Reads a signed 128 bit integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a signed 128 bit big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// assert_eq!(i128::min_value(), rdr.read_i128::().unwrap()); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_i128(&mut self) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf)); + Ok(T::read_i128(&buf)) + } + + /// Reads an unsigned n-bytes integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read an unsigned n-byte big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0x80, 0x74, 0xfa]); + /// assert_eq!(8418554, rdr.read_uint::(3).unwrap()); + #[inline] + fn read_uint(&mut self, nbytes: usize) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf[..nbytes])); + Ok(T::read_uint(&buf[..nbytes], nbytes)) + } + + /// Reads a signed n-bytes integer from the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read an unsigned n-byte big-endian integer from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0xc1, 0xff, 0x7c]); + /// assert_eq!(-4063364, rdr.read_int::(3).unwrap()); + #[inline] + fn read_int(&mut self, nbytes: usize) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf[..nbytes])); + Ok(T::read_int(&buf[..nbytes], nbytes)) + } + + /// Reads an unsigned n-bytes integer from the underlying reader. + #[cfg(byteorder_i128)] + #[inline] + fn read_uint128(&mut self, nbytes: usize) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf[..nbytes])); + Ok(T::read_uint128(&buf[..nbytes], nbytes)) + } + + /// Reads a signed n-bytes integer from the underlying reader. + #[cfg(byteorder_i128)] + #[inline] + fn read_int128(&mut self, nbytes: usize) -> Result { + let mut buf = [0; 16]; + try!(self.read_exact(&mut buf[..nbytes])); + Ok(T::read_int128(&buf[..nbytes], nbytes)) + } + + /// Reads a IEEE754 single-precision (4 bytes) floating point number from + /// the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a big-endian single-precision floating point number from a `Read`: + /// + /// ```rust + /// use std::f32; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x49, 0x0f, 0xdb, + /// ]); + /// assert_eq!(f32::consts::PI, rdr.read_f32::().unwrap()); + /// ``` + #[inline] + fn read_f32(&mut self) -> Result { + let mut buf = [0; 4]; + try!(self.read_exact(&mut buf)); + Ok(T::read_f32(&buf)) + } + + /// Reads a IEEE754 double-precision (8 bytes) floating point number from + /// the underlying reader. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a big-endian double-precision floating point number from a `Read`: + /// + /// ```rust + /// use std::f64; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, + /// ]); + /// assert_eq!(f64::consts::PI, rdr.read_f64::().unwrap()); + /// ``` + #[inline] + fn read_f64(&mut self) -> Result { + let mut buf = [0; 8]; + try!(self.read_exact(&mut buf)); + Ok(T::read_f64(&buf)) + } + + /// Reads a sequence of unsigned 16 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of unsigned 16 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); + /// let mut dst = [0; 2]; + /// rdr.read_u16_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_u16_into(&mut self, dst: &mut [u16]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_u16(dst); + Ok(()) + } + + /// Reads a sequence of unsigned 32 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of unsigned 32 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]); + /// let mut dst = [0; 2]; + /// rdr.read_u32_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_u32_into(&mut self, dst: &mut [u32]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_u32(dst); + Ok(()) + } + + /// Reads a sequence of unsigned 64 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of unsigned 64 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0, 0, 0, 0, 0, 0, 2, 5, + /// 0, 0, 0, 0, 0, 0, 3, 0, + /// ]); + /// let mut dst = [0; 2]; + /// rdr.read_u64_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_u64_into(&mut self, dst: &mut [u64]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_u64(dst); + Ok(()) + } + + /// Reads a sequence of unsigned 128 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of unsigned 128 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, + /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + /// ]); + /// let mut dst = [0; 2]; + /// rdr.read_u128_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_u128_into( + &mut self, + dst: &mut [u128], + ) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_u128(dst); + Ok(()) + } + + /// Reads a sequence of signed 16 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of signed 16 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]); + /// let mut dst = [0; 2]; + /// rdr.read_i16_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_i16_into(&mut self, dst: &mut [i16]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_i16(dst); + Ok(()) + } + + /// Reads a sequence of signed 32 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of signed 32 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]); + /// let mut dst = [0; 2]; + /// rdr.read_i32_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_i32_into(&mut self, dst: &mut [i32]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_i32(dst); + Ok(()) + } + + /// Reads a sequence of signed 64 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of signed 64 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0, 0, 0, 0, 0, 0, 2, 5, + /// 0, 0, 0, 0, 0, 0, 3, 0, + /// ]); + /// let mut dst = [0; 2]; + /// rdr.read_i64_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[inline] + fn read_i64_into(&mut self, dst: &mut [i64]) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_i64(dst); + Ok(()) + } + + /// Reads a sequence of signed 128 bit integers from the underlying + /// reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of signed 128 bit big-endian integers from a `Read`: + /// + /// ```rust + /// use std::io::Cursor; + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, + /// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + /// ]); + /// let mut dst = [0; 2]; + /// rdr.read_i128_into::(&mut dst).unwrap(); + /// assert_eq!([517, 768], dst); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_i128_into( + &mut self, + dst: &mut [i128], + ) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_i128(dst); + Ok(()) + } + + /// Reads a sequence of IEEE754 single-precision (4 bytes) floating + /// point numbers from the underlying reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of big-endian single-precision floating point number + /// from a `Read`: + /// + /// ```rust + /// use std::f32; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x49, 0x0f, 0xdb, + /// 0x3f, 0x80, 0x00, 0x00, + /// ]); + /// let mut dst = [0.0; 2]; + /// rdr.read_f32_into::(&mut dst).unwrap(); + /// assert_eq!([f32::consts::PI, 1.0], dst); + /// ``` + #[inline] + fn read_f32_into( + &mut self, + dst: &mut [f32], + ) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_f32(dst); + Ok(()) + } + + /// **DEPRECATED**. + /// + /// This method is deprecated. Use `read_f32_into` instead. + /// + /// Reads a sequence of IEEE754 single-precision (4 bytes) floating + /// point numbers from the underlying reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of big-endian single-precision floating point number + /// from a `Read`: + /// + /// ```rust + /// use std::f32; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x49, 0x0f, 0xdb, + /// 0x3f, 0x80, 0x00, 0x00, + /// ]); + /// let mut dst = [0.0; 2]; + /// rdr.read_f32_into_unchecked::(&mut dst).unwrap(); + /// assert_eq!([f32::consts::PI, 1.0], dst); + /// ``` + #[inline] + #[deprecated(since="1.2.0", note="please use `read_f32_into` instead")] + fn read_f32_into_unchecked( + &mut self, + dst: &mut [f32], + ) -> Result<()> { + self.read_f32_into::(dst) + } + + /// Reads a sequence of IEEE754 double-precision (8 bytes) floating + /// point numbers from the underlying reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of big-endian single-precision floating point number + /// from a `Read`: + /// + /// ```rust + /// use std::f64; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, + /// 0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /// ]); + /// let mut dst = [0.0; 2]; + /// rdr.read_f64_into::(&mut dst).unwrap(); + /// assert_eq!([f64::consts::PI, 1.0], dst); + /// ``` + #[inline] + fn read_f64_into( + &mut self, + dst: &mut [f64], + ) -> Result<()> { + { + let buf = unsafe { slice_to_u8_mut(dst) }; + try!(self.read_exact(buf)); + } + T::from_slice_f64(dst); + Ok(()) + } + + /// **DEPRECATED**. + /// + /// This method is deprecated. Use `read_f64_into` instead. + /// + /// Reads a sequence of IEEE754 double-precision (8 bytes) floating + /// point numbers from the underlying reader. + /// + /// The given buffer is either filled completely or an error is returned. + /// If an error is returned, the contents of `dst` are unspecified. + /// + /// # Safety + /// + /// This method is unsafe because there are no guarantees made about the + /// floating point values. In particular, this method does not check for + /// signaling NaNs, which may result in undefined behavior. + /// + /// # Errors + /// + /// This method returns the same errors as [`Read::read_exact`]. + /// + /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact + /// + /// # Examples + /// + /// Read a sequence of big-endian single-precision floating point number + /// from a `Read`: + /// + /// ```rust + /// use std::f64; + /// use std::io::Cursor; + /// + /// use byteorder::{BigEndian, ReadBytesExt}; + /// + /// let mut rdr = Cursor::new(vec![ + /// 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18, + /// 0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /// ]); + /// let mut dst = [0.0; 2]; + /// rdr.read_f64_into_unchecked::(&mut dst).unwrap(); + /// assert_eq!([f64::consts::PI, 1.0], dst); + /// ``` + #[inline] + #[deprecated(since="1.2.0", note="please use `read_f64_into` instead")] + fn read_f64_into_unchecked( + &mut self, + dst: &mut [f64], + ) -> Result<()> { + self.read_f64_into::(dst) + } +} + +/// All types that implement `Read` get methods defined in `ReadBytesExt` +/// for free. +impl ReadBytesExt for R {} + +/// Extends [`Write`] with methods for writing numbers. (For `std::io`.) +/// +/// Most of the methods defined here have an unconstrained type parameter that +/// must be explicitly instantiated. Typically, it is instantiated with either +/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate. +/// +/// # Examples +/// +/// Write unsigned 16 bit big-endian integers to a [`Write`]: +/// +/// ```rust +/// use byteorder::{BigEndian, WriteBytesExt}; +/// +/// let mut wtr = vec![]; +/// wtr.write_u16::(517).unwrap(); +/// wtr.write_u16::(768).unwrap(); +/// assert_eq!(wtr, vec![2, 5, 3, 0]); +/// ``` +/// +/// [`BigEndian`]: enum.BigEndian.html +/// [`LittleEndian`]: enum.LittleEndian.html +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +pub trait WriteBytesExt: io::Write { + /// Writes an unsigned 8 bit integer to the underlying writer. + /// + /// Note that since this writes a single byte, no byte order conversions + /// are used. It is included for completeness. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 8 bit integers to a `Write`: + /// + /// ```rust + /// use byteorder::WriteBytesExt; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u8(2).unwrap(); + /// wtr.write_u8(5).unwrap(); + /// assert_eq!(wtr, b"\x02\x05"); + /// ``` + #[inline] + fn write_u8(&mut self, n: u8) -> Result<()> { + self.write_all(&[n]) + } + + /// Writes a signed 8 bit integer to the underlying writer. + /// + /// Note that since this writes a single byte, no byte order conversions + /// are used. It is included for completeness. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 8 bit integers to a `Write`: + /// + /// ```rust + /// use byteorder::WriteBytesExt; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i8(2).unwrap(); + /// wtr.write_i8(-5).unwrap(); + /// assert_eq!(wtr, b"\x02\xfb"); + /// ``` + #[inline] + fn write_i8(&mut self, n: i8) -> Result<()> { + self.write_all(&[n as u8]) + } + + /// Writes an unsigned 16 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 16 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u16::(517).unwrap(); + /// wtr.write_u16::(768).unwrap(); + /// assert_eq!(wtr, b"\x02\x05\x03\x00"); + /// ``` + #[inline] + fn write_u16(&mut self, n: u16) -> Result<()> { + let mut buf = [0; 2]; + T::write_u16(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 16 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 16 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i16::(193).unwrap(); + /// wtr.write_i16::(-132).unwrap(); + /// assert_eq!(wtr, b"\x00\xc1\xff\x7c"); + /// ``` + #[inline] + fn write_i16(&mut self, n: i16) -> Result<()> { + let mut buf = [0; 2]; + T::write_i16(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned 24 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 24 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u24::(267).unwrap(); + /// wtr.write_u24::(120111).unwrap(); + /// assert_eq!(wtr, b"\x00\x01\x0b\x01\xd5\x2f"); + /// ``` + #[inline] + fn write_u24(&mut self, n: u32) -> Result<()> { + let mut buf = [0; 3]; + T::write_u24(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 24 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 24 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i24::(-34253).unwrap(); + /// wtr.write_i24::(120111).unwrap(); + /// assert_eq!(wtr, b"\xff\x7a\x33\x01\xd5\x2f"); + /// ``` + #[inline] + fn write_i24(&mut self, n: i32) -> Result<()> { + let mut buf = [0; 3]; + T::write_i24(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned 32 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 32 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u32::(267).unwrap(); + /// wtr.write_u32::(1205419366).unwrap(); + /// assert_eq!(wtr, b"\x00\x00\x01\x0b\x47\xd9\x3d\x66"); + /// ``` + #[inline] + fn write_u32(&mut self, n: u32) -> Result<()> { + let mut buf = [0; 4]; + T::write_u32(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 32 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 32 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i32::(-34253).unwrap(); + /// wtr.write_i32::(1205419366).unwrap(); + /// assert_eq!(wtr, b"\xff\xff\x7a\x33\x47\xd9\x3d\x66"); + /// ``` + #[inline] + fn write_i32(&mut self, n: i32) -> Result<()> { + let mut buf = [0; 4]; + T::write_i32(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned 48 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 48 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u48::(52360336390828).unwrap(); + /// wtr.write_u48::(541).unwrap(); + /// assert_eq!(wtr, b"\x2f\x9f\x17\x40\x3a\xac\x00\x00\x00\x00\x02\x1d"); + /// ``` + #[inline] + fn write_u48(&mut self, n: u64) -> Result<()> { + let mut buf = [0; 6]; + T::write_u48(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 48 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 48 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i48::(-108363435763825).unwrap(); + /// wtr.write_i48::(77).unwrap(); + /// assert_eq!(wtr, b"\x9d\x71\xab\xe7\x97\x8f\x00\x00\x00\x00\x00\x4d"); + /// ``` + #[inline] + fn write_i48(&mut self, n: i64) -> Result<()> { + let mut buf = [0; 6]; + T::write_i48(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned 64 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write unsigned 64 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_u64::(918733457491587).unwrap(); + /// wtr.write_u64::(143).unwrap(); + /// assert_eq!(wtr, b"\x00\x03\x43\x95\x4d\x60\x86\x83\x00\x00\x00\x00\x00\x00\x00\x8f"); + /// ``` + #[inline] + fn write_u64(&mut self, n: u64) -> Result<()> { + let mut buf = [0; 8]; + T::write_u64(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 64 bit integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write signed 64 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_i64::(i64::min_value()).unwrap(); + /// wtr.write_i64::(i64::max_value()).unwrap(); + /// assert_eq!(wtr, b"\x80\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff"); + /// ``` + #[inline] + fn write_i64(&mut self, n: i64) -> Result<()> { + let mut buf = [0; 8]; + T::write_i64(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned 128 bit integer to the underlying writer. + #[cfg(byteorder_i128)] + #[inline] + fn write_u128(&mut self, n: u128) -> Result<()> { + let mut buf = [0; 16]; + T::write_u128(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a signed 128 bit integer to the underlying writer. + #[cfg(byteorder_i128)] + #[inline] + fn write_i128(&mut self, n: i128) -> Result<()> { + let mut buf = [0; 16]; + T::write_i128(&mut buf, n); + self.write_all(&buf) + } + + /// Writes an unsigned n-bytes integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Panics + /// + /// If the given integer is not representable in the given number of bytes, + /// this method panics. If `nbytes > 8`, this method panics. + /// + /// # Examples + /// + /// Write unsigned 40 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_uint::(312550384361, 5).unwrap(); + /// wtr.write_uint::(43, 5).unwrap(); + /// assert_eq!(wtr, b"\x48\xc5\x74\x62\xe9\x00\x00\x00\x00\x2b"); + /// ``` + #[inline] + fn write_uint( + &mut self, + n: u64, + nbytes: usize, + ) -> Result<()> { + let mut buf = [0; 8]; + T::write_uint(&mut buf, n, nbytes); + self.write_all(&buf[0..nbytes]) + } + + /// Writes a signed n-bytes integer to the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Panics + /// + /// If the given integer is not representable in the given number of bytes, + /// this method panics. If `nbytes > 8`, this method panics. + /// + /// # Examples + /// + /// Write signed 56 bit big-endian integers to a `Write`: + /// + /// ```rust + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_int::(-3548172039376767, 7).unwrap(); + /// wtr.write_int::(43, 7).unwrap(); + /// assert_eq!(wtr, b"\xf3\x64\xf4\xd1\xfd\xb0\x81\x00\x00\x00\x00\x00\x00\x2b"); + /// ``` + #[inline] + fn write_int( + &mut self, + n: i64, + nbytes: usize, + ) -> Result<()> { + let mut buf = [0; 8]; + T::write_int(&mut buf, n, nbytes); + self.write_all(&buf[0..nbytes]) + } + + /// Writes an unsigned n-bytes integer to the underlying writer. + /// + /// If the given integer is not representable in the given number of bytes, + /// this method panics. If `nbytes > 16`, this method panics. + #[cfg(byteorder_i128)] + #[inline] + fn write_uint128( + &mut self, + n: u128, + nbytes: usize, + ) -> Result<()> { + let mut buf = [0; 16]; + T::write_uint128(&mut buf, n, nbytes); + self.write_all(&buf[0..nbytes]) + } + + /// Writes a signed n-bytes integer to the underlying writer. + /// + /// If the given integer is not representable in the given number of bytes, + /// this method panics. If `nbytes > 16`, this method panics. + #[cfg(byteorder_i128)] + #[inline] + fn write_int128( + &mut self, + n: i128, + nbytes: usize, + ) -> Result<()> { + let mut buf = [0; 16]; + T::write_int128(&mut buf, n, nbytes); + self.write_all(&buf[0..nbytes]) + } + + /// Writes a IEEE754 single-precision (4 bytes) floating point number to + /// the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write a big-endian single-precision floating point number to a `Write`: + /// + /// ```rust + /// use std::f32; + /// + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_f32::(f32::consts::PI).unwrap(); + /// assert_eq!(wtr, b"\x40\x49\x0f\xdb"); + /// ``` + #[inline] + fn write_f32(&mut self, n: f32) -> Result<()> { + let mut buf = [0; 4]; + T::write_f32(&mut buf, n); + self.write_all(&buf) + } + + /// Writes a IEEE754 double-precision (8 bytes) floating point number to + /// the underlying writer. + /// + /// # Errors + /// + /// This method returns the same errors as [`Write::write_all`]. + /// + /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all + /// + /// # Examples + /// + /// Write a big-endian double-precision floating point number to a `Write`: + /// + /// ```rust + /// use std::f64; + /// + /// use byteorder::{BigEndian, WriteBytesExt}; + /// + /// let mut wtr = Vec::new(); + /// wtr.write_f64::(f64::consts::PI).unwrap(); + /// assert_eq!(wtr, b"\x40\x09\x21\xfb\x54\x44\x2d\x18"); + /// ``` + #[inline] + fn write_f64(&mut self, n: f64) -> Result<()> { + let mut buf = [0; 8]; + T::write_f64(&mut buf, n); + self.write_all(&buf) + } +} + +/// All types that implement `Write` get methods defined in `WriteBytesExt` +/// for free. +impl WriteBytesExt for W {} + +/// Convert a slice of T (where T is plain old data) to its mutable binary +/// representation. +/// +/// This function is wildly unsafe because it permits arbitrary modification of +/// the binary representation of any `Copy` type. Use with care. +unsafe fn slice_to_u8_mut(slice: &mut [T]) -> &mut [u8] { + use std::mem::size_of; + + let len = size_of::() * slice.len(); + slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len) +} diff --git a/byteorder/src/lib.rs b/byteorder/src/lib.rs new file mode 100644 index 000000000..497e914b1 --- /dev/null +++ b/byteorder/src/lib.rs @@ -0,0 +1,3315 @@ +/*! +This crate provides convenience methods for encoding and decoding numbers +in either [big-endian or little-endian order]. + +The organization of the crate is pretty simple. A trait, [`ByteOrder`], specifies +byte conversion methods for each type of number in Rust (sans numbers that have +a platform dependent size like `usize` and `isize`). Two types, [`BigEndian`] +and [`LittleEndian`] implement these methods. Finally, [`ReadBytesExt`] and +[`WriteBytesExt`] provide convenience methods available to all types that +implement [`Read`] and [`Write`]. + +An alias, [`NetworkEndian`], for [`BigEndian`] is provided to help improve +code clarity. + +An additional alias, [`NativeEndian`], is provided for the endianness of the +local platform. This is convenient when serializing data for use and +conversions are not desired. + +# Examples + +Read unsigned 16 bit big-endian integers from a [`Read`] type: + +```rust +use std::io::Cursor; +use byteorder::{BigEndian, ReadBytesExt}; + +let mut rdr = Cursor::new(vec![2, 5, 3, 0]); +// Note that we use type parameters to indicate which kind of byte order +// we want! +assert_eq!(517, rdr.read_u16::().unwrap()); +assert_eq!(768, rdr.read_u16::().unwrap()); +``` + +Write unsigned 16 bit little-endian integers to a [`Write`] type: + +```rust +use byteorder::{LittleEndian, WriteBytesExt}; + +let mut wtr = vec![]; +wtr.write_u16::(517).unwrap(); +wtr.write_u16::(768).unwrap(); +assert_eq!(wtr, vec![5, 2, 0, 3]); +``` + +# Optional Features + +This crate optionally provides support for 128 bit values (`i128` and `u128`) +when built with the `i128` feature enabled. + +This crate can also be used without the standard library. + +[big-endian or little-endian order]: https://en.wikipedia.org/wiki/Endianness +[`ByteOrder`]: trait.ByteOrder.html +[`BigEndian`]: enum.BigEndian.html +[`LittleEndian`]: enum.LittleEndian.html +[`ReadBytesExt`]: trait.ReadBytesExt.html +[`WriteBytesExt`]: trait.WriteBytesExt.html +[`NetworkEndian`]: type.NetworkEndian.html +[`NativeEndian`]: type.NativeEndian.html +[`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +[`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +*/ + +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +extern crate core; + +use core::fmt::Debug; +use core::hash::Hash; +use core::ptr::copy_nonoverlapping; +use core::slice; + +#[cfg(feature = "std")] +pub use io::{ReadBytesExt, WriteBytesExt}; + +#[cfg(feature = "std")] +mod io; + +#[inline] +fn extend_sign(val: u64, nbytes: usize) -> i64 { + let shift = (8 - nbytes) * 8; + (val << shift) as i64 >> shift +} + +#[cfg(byteorder_i128)] +#[inline] +fn extend_sign128(val: u128, nbytes: usize) -> i128 { + let shift = (16 - nbytes) * 8; + (val << shift) as i128 >> shift +} + +#[inline] +fn unextend_sign(val: i64, nbytes: usize) -> u64 { + let shift = (8 - nbytes) * 8; + (val << shift) as u64 >> shift +} + +#[cfg(byteorder_i128)] +#[inline] +fn unextend_sign128(val: i128, nbytes: usize) -> u128 { + let shift = (16 - nbytes) * 8; + (val << shift) as u128 >> shift +} + +#[inline] +fn pack_size(n: u64) -> usize { + if n < 1 << 8 { + 1 + } else if n < 1 << 16 { + 2 + } else if n < 1 << 24 { + 3 + } else if n < 1 << 32 { + 4 + } else if n < 1 << 40 { + 5 + } else if n < 1 << 48 { + 6 + } else if n < 1 << 56 { + 7 + } else { + 8 + } +} + +#[cfg(byteorder_i128)] +#[inline] +fn pack_size128(n: u128) -> usize { + if n < 1 << 8 { + 1 + } else if n < 1 << 16 { + 2 + } else if n < 1 << 24 { + 3 + } else if n < 1 << 32 { + 4 + } else if n < 1 << 40 { + 5 + } else if n < 1 << 48 { + 6 + } else if n < 1 << 56 { + 7 + } else if n < 1 << 64 { + 8 + } else if n < 1 << 72 { + 9 + } else if n < 1 << 80 { + 10 + } else if n < 1 << 88 { + 11 + } else if n < 1 << 96 { + 12 + } else if n < 1 << 104 { + 13 + } else if n < 1 << 112 { + 14 + } else if n < 1 << 120 { + 15 + } else { + 16 + } +} + +mod private { + /// Sealed stops crates other than byteorder from implementing any traits + /// that use it. + pub trait Sealed{} + impl Sealed for super::LittleEndian {} + impl Sealed for super::BigEndian {} +} + +/// `ByteOrder` describes types that can serialize integers as bytes. +/// +/// Note that `Self` does not appear anywhere in this trait's definition! +/// Therefore, in order to use it, you'll need to use syntax like +/// `T::read_u16(&[0, 1])` where `T` implements `ByteOrder`. +/// +/// This crate provides two types that implement `ByteOrder`: [`BigEndian`] +/// and [`LittleEndian`]. +/// This trait is sealed and cannot be implemented for callers to avoid +/// breaking backwards compatibility when adding new derived traits. +/// +/// # Examples +/// +/// Write and read `u32` numbers in little endian order: +/// +/// ```rust +/// use byteorder::{ByteOrder, LittleEndian}; +/// +/// let mut buf = [0; 4]; +/// LittleEndian::write_u32(&mut buf, 1_000_000); +/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); +/// ``` +/// +/// Write and read `i16` numbers in big endian order: +/// +/// ```rust +/// use byteorder::{ByteOrder, BigEndian}; +/// +/// let mut buf = [0; 2]; +/// BigEndian::write_i16(&mut buf, -50_000); +/// assert_eq!(-50_000, BigEndian::read_i16(&buf)); +/// ``` +/// +/// [`BigEndian`]: enum.BigEndian.html +/// [`LittleEndian`]: enum.LittleEndian.html +pub trait ByteOrder + : Clone + Copy + Debug + Default + Eq + Hash + Ord + PartialEq + PartialOrd + + private::Sealed +{ + /// Reads an unsigned 16 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + fn read_u16(buf: &[u8]) -> u16; + + /// Reads an unsigned 24 bit integer from `buf`, stored in u32. + /// + /// # Panics + /// + /// Panics when `buf.len() < 3`. + /// + /// # Examples + /// + /// Write and read 24 bit `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_u24(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf)); + /// ``` + fn read_u24(buf: &[u8]) -> u32 { + Self::read_uint(buf, 3) as u32 + } + + /// Reads an unsigned 32 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 4]; + /// LittleEndian::write_u32(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); + /// ``` + fn read_u32(buf: &[u8]) -> u32; + + /// Reads an unsigned 48 bit integer from `buf`, stored in u64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 6`. + /// + /// # Examples + /// + /// Write and read 48 bit `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 6]; + /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000); + /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf)); + /// ``` + fn read_u48(buf: &[u8]) -> u64 { + Self::read_uint(buf, 6) as u64 + } + + /// Reads an unsigned 64 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 8]; + /// LittleEndian::write_u64(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf)); + /// ``` + fn read_u64(buf: &[u8]) -> u64; + + /// Reads an unsigned 128 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 16`. + /// + /// # Examples + /// + /// Write and read `u128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 16]; + /// LittleEndian::write_u128(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf)); + /// ``` + #[cfg(byteorder_i128)] + fn read_u128(buf: &[u8]) -> u128; + + /// Reads an unsigned n-bytes integer from `buf`. + /// + /// # Panics + /// + /// Panics when `nbytes < 1` or `nbytes > 8` or + /// `buf.len() < nbytes` + /// + /// # Examples + /// + /// Write and read an n-byte number in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_uint(&mut buf, 1_000_000, 3); + /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3)); + /// ``` + fn read_uint(buf: &[u8], nbytes: usize) -> u64; + + /// Reads an unsigned n-bytes integer from `buf`. + /// + /// # Panics + /// + /// Panics when `nbytes < 1` or `nbytes > 16` or + /// `buf.len() < nbytes` + /// + /// # Examples + /// + /// Write and read an n-byte number in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3); + /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3)); + /// ``` + #[cfg(byteorder_i128)] + fn read_uint128(buf: &[u8], nbytes: usize) -> u128; + + /// Writes an unsigned 16 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + /// + /// # Examples + /// + /// Write and read `u16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 2]; + /// LittleEndian::write_u16(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u16(&buf)); + /// ``` + fn write_u16(buf: &mut [u8], n: u16); + + /// Writes an unsigned 24 bit integer `n` to `buf`, stored in u32. + /// + /// # Panics + /// + /// Panics when `buf.len() < 3`. + /// + /// # Examples + /// + /// Write and read 24 bit `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_u24(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf)); + /// ``` + fn write_u24(buf: &mut [u8], n: u32) { + Self::write_uint(buf, n as u64, 3) + } + + /// Writes an unsigned 32 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 4]; + /// LittleEndian::write_u32(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); + /// ``` + fn write_u32(buf: &mut [u8], n: u32); + + /// Writes an unsigned 48 bit integer `n` to `buf`, stored in u64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 6`. + /// + /// # Examples + /// + /// Write and read 48 bit `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 6]; + /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000); + /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf)); + /// ``` + fn write_u48(buf: &mut [u8], n: u64) { + Self::write_uint(buf, n as u64, 6) + } + + /// Writes an unsigned 64 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 8]; + /// LittleEndian::write_u64(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf)); + /// ``` + fn write_u64(buf: &mut [u8], n: u64); + + /// Writes an unsigned 128 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 16`. + /// + /// # Examples + /// + /// Write and read `u128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 16]; + /// LittleEndian::write_u128(&mut buf, 1_000_000); + /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf)); + /// ``` + #[cfg(byteorder_i128)] + fn write_u128(buf: &mut [u8], n: u128); + + /// Writes an unsigned integer `n` to `buf` using only `nbytes`. + /// + /// # Panics + /// + /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then + /// this method panics. + /// + /// # Examples + /// + /// Write and read an n-byte number in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_uint(&mut buf, 1_000_000, 3); + /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3)); + /// ``` + fn write_uint(buf: &mut [u8], n: u64, nbytes: usize); + + /// Writes an unsigned integer `n` to `buf` using only `nbytes`. + /// + /// # Panics + /// + /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then + /// this method panics. + /// + /// # Examples + /// + /// Write and read an n-byte number in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3); + /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3)); + /// ``` + #[cfg(byteorder_i128)] + fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize); + + /// Reads a signed 16 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + /// + /// # Examples + /// + /// Write and read `i16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 2]; + /// LittleEndian::write_i16(&mut buf, -1_000); + /// assert_eq!(-1_000, LittleEndian::read_i16(&buf)); + /// ``` + #[inline] + fn read_i16(buf: &[u8]) -> i16 { + Self::read_u16(buf) as i16 + } + + /// Reads a signed 24 bit integer from `buf`, stored in i32. + /// + /// # Panics + /// + /// Panics when `buf.len() < 3`. + /// + /// # Examples + /// + /// Write and read 24 bit `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_i24(&mut buf, -1_000_000); + /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf)); + /// ``` + #[inline] + fn read_i24(buf: &[u8]) -> i32 { + Self::read_int(buf, 3) as i32 + } + + /// Reads a signed 32 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 4]; + /// LittleEndian::write_i32(&mut buf, -1_000_000); + /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf)); + /// ``` + #[inline] + fn read_i32(buf: &[u8]) -> i32 { + Self::read_u32(buf) as i32 + } + + /// Reads a signed 48 bit integer from `buf`, stored in i64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 6`. + /// + /// # Examples + /// + /// Write and read 48 bit `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 6]; + /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000); + /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf)); + /// ``` + #[inline] + fn read_i48(buf: &[u8]) -> i64 { + Self::read_int(buf, 6) as i64 + } + + /// Reads a signed 64 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 8]; + /// LittleEndian::write_i64(&mut buf, -1_000_000_000); + /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf)); + /// ``` + #[inline] + fn read_i64(buf: &[u8]) -> i64 { + Self::read_u64(buf) as i64 + } + + /// Reads a signed 128 bit integer from `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 16`. + /// + /// # Examples + /// + /// Write and read `i128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 16]; + /// LittleEndian::write_i128(&mut buf, -1_000_000_000); + /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf)); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_i128(buf: &[u8]) -> i128 { + Self::read_u128(buf) as i128 + } + + /// Reads a signed n-bytes integer from `buf`. + /// + /// # Panics + /// + /// Panics when `nbytes < 1` or `nbytes > 8` or + /// `buf.len() < nbytes` + /// + /// # Examples + /// + /// Write and read n-length signed numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_int(&mut buf, -1_000, 3); + /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3)); + /// ``` + #[inline] + fn read_int(buf: &[u8], nbytes: usize) -> i64 { + extend_sign(Self::read_uint(buf, nbytes), nbytes) + } + + /// Reads a signed n-bytes integer from `buf`. + /// + /// # Panics + /// + /// Panics when `nbytes < 1` or `nbytes > 16` or + /// `buf.len() < nbytes` + /// + /// # Examples + /// + /// Write and read n-length signed numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_int128(&mut buf, -1_000, 3); + /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3)); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_int128(buf: &[u8], nbytes: usize) -> i128 { + extend_sign128(Self::read_uint128(buf, nbytes), nbytes) + } + + /// Reads a IEEE754 single-precision (4 bytes) floating point number. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `f32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let e = 2.71828; + /// let mut buf = [0; 4]; + /// LittleEndian::write_f32(&mut buf, e); + /// assert_eq!(e, LittleEndian::read_f32(&buf)); + /// ``` + #[inline] + fn read_f32(buf: &[u8]) -> f32 { + unsafe { *(&Self::read_u32(buf) as *const u32 as *const f32) } + } + + /// Reads a IEEE754 double-precision (8 bytes) floating point number. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `f64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let phi = 1.6180339887; + /// let mut buf = [0; 8]; + /// LittleEndian::write_f64(&mut buf, phi); + /// assert_eq!(phi, LittleEndian::read_f64(&buf)); + /// ``` + #[inline] + fn read_f64(buf: &[u8]) -> f64 { + unsafe { *(&Self::read_u64(buf) as *const u64 as *const f64) } + } + + /// Writes a signed 16 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 2`. + /// + /// # Examples + /// + /// Write and read `i16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 2]; + /// LittleEndian::write_i16(&mut buf, -1_000); + /// assert_eq!(-1_000, LittleEndian::read_i16(&buf)); + /// ``` + #[inline] + fn write_i16(buf: &mut [u8], n: i16) { + Self::write_u16(buf, n as u16) + } + + /// Writes a signed 24 bit integer `n` to `buf`, stored in i32. + /// + /// # Panics + /// + /// Panics when `buf.len() < 3`. + /// + /// # Examples + /// + /// Write and read 24 bit `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_i24(&mut buf, -1_000_000); + /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf)); + /// ``` + #[inline] + fn write_i24(buf: &mut [u8], n: i32) { + Self::write_int(buf, n as i64, 3) + } + + /// Writes a signed 32 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 4]; + /// LittleEndian::write_i32(&mut buf, -1_000_000); + /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf)); + /// ``` + #[inline] + fn write_i32(buf: &mut [u8], n: i32) { + Self::write_u32(buf, n as u32) + } + + /// Writes a signed 48 bit integer `n` to `buf`, stored in i64. + /// + /// # Panics + /// + /// Panics when `buf.len() < 6`. + /// + /// # Examples + /// + /// Write and read 48 bit `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 6]; + /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000); + /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf)); + /// ``` + #[inline] + fn write_i48(buf: &mut [u8], n: i64) { + Self::write_int(buf, n as i64, 6) + } + + /// Writes a signed 64 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 8]; + /// LittleEndian::write_i64(&mut buf, -1_000_000_000); + /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf)); + /// ``` + #[inline] + fn write_i64(buf: &mut [u8], n: i64) { + Self::write_u64(buf, n as u64) + } + + /// Writes a signed 128 bit integer `n` to `buf`. + /// + /// # Panics + /// + /// Panics when `buf.len() < 16`. + /// + /// # Examples + /// + /// Write and read n-byte `i128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 16]; + /// LittleEndian::write_i128(&mut buf, -1_000_000_000); + /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf)); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn write_i128(buf: &mut [u8], n: i128) { + Self::write_u128(buf, n as u128) + } + + /// Writes a signed integer `n` to `buf` using only `nbytes`. + /// + /// # Panics + /// + /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then + /// this method panics. + /// + /// # Examples + /// + /// Write and read an n-byte number in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_int(&mut buf, -1_000, 3); + /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3)); + /// ``` + #[inline] + fn write_int(buf: &mut [u8], n: i64, nbytes: usize) { + Self::write_uint(buf, unextend_sign(n, nbytes), nbytes) + } + + /// Writes a signed integer `n` to `buf` using only `nbytes`. + /// + /// # Panics + /// + /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then + /// this method panics. + /// + /// # Examples + /// + /// Write and read n-length signed numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut buf = [0; 3]; + /// LittleEndian::write_int128(&mut buf, -1_000, 3); + /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3)); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn write_int128(buf: &mut [u8], n: i128, nbytes: usize) { + Self::write_uint128(buf, unextend_sign128(n, nbytes), nbytes) + } + + /// Writes a IEEE754 single-precision (4 bytes) floating point number. + /// + /// # Panics + /// + /// Panics when `buf.len() < 4`. + /// + /// # Examples + /// + /// Write and read `f32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let e = 2.71828; + /// let mut buf = [0; 4]; + /// LittleEndian::write_f32(&mut buf, e); + /// assert_eq!(e, LittleEndian::read_f32(&buf)); + /// ``` + #[inline] + fn write_f32(buf: &mut [u8], n: f32) { + let n = unsafe { *(&n as *const f32 as *const u32) }; + Self::write_u32(buf, n) + } + + /// Writes a IEEE754 double-precision (8 bytes) floating point number. + /// + /// # Panics + /// + /// Panics when `buf.len() < 8`. + /// + /// # Examples + /// + /// Write and read `f64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let phi = 1.6180339887; + /// let mut buf = [0; 8]; + /// LittleEndian::write_f64(&mut buf, phi); + /// assert_eq!(phi, LittleEndian::read_f64(&buf)); + /// ``` + #[inline] + fn write_f64(buf: &mut [u8], n: f64) { + let n = unsafe { *(&n as *const f64 as *const u64) }; + Self::write_u64(buf, n) + } + + /// Reads unsigned 16 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 2*dst.len()`. + /// + /// # Examples + /// + /// Write and read `u16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 8]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u16_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u16_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn read_u16_into(src: &[u8], dst: &mut [u16]); + + /// Reads unsigned 32 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 4*dst.len()`. + /// + /// # Examples + /// + /// Write and read `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u32_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn read_u32_into(src: &[u8], dst: &mut [u32]); + + /// Reads unsigned 64 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 8*dst.len()`. + /// + /// # Examples + /// + /// Write and read `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u64_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn read_u64_into(src: &[u8], dst: &mut [u64]); + + /// Reads unsigned 128 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 16*dst.len()`. + /// + /// # Examples + /// + /// Write and read `u128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 64]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u128_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u128_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[cfg(byteorder_i128)] + fn read_u128_into(src: &[u8], dst: &mut [u128]); + + /// Reads signed 16 bit integers from `src` to `dst`. + /// + /// # Panics + /// + /// Panics when `buf.len() != 2*dst.len()`. + /// + /// # Examples + /// + /// Write and read `i16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 8]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i16_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i16_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + fn read_i16_into(src: &[u8], dst: &mut [i16]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u16, dst.len()) + }; + Self::read_u16_into(src, dst) + } + + /// Reads signed 32 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 4*dst.len()`. + /// + /// # Examples + /// + /// Write and read `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i32_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + fn read_i32_into(src: &[u8], dst: &mut [i32]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len()) + }; + Self::read_u32_into(src, dst); + } + + /// Reads signed 64 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 8*dst.len()`. + /// + /// # Examples + /// + /// Write and read `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i64_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + fn read_i64_into(src: &[u8], dst: &mut [i64]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len()) + }; + Self::read_u64_into(src, dst); + } + + /// Reads signed 128 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 16*dst.len()`. + /// + /// # Examples + /// + /// Write and read `i128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 64]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i128_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i128_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn read_i128_into(src: &[u8], dst: &mut [i128]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u128, dst.len()) + }; + Self::read_u128_into(src, dst); + } + + /// Reads IEEE754 single-precision (4 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 4*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; + /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// LittleEndian::read_f32_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + fn read_f32_into(src: &[u8], dst: &mut [f32]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len()) + }; + Self::read_u32_into(src, dst); + } + + /// **DEPRECATED**. + /// + /// This method is deprecated. Use `read_f32_into` instead. + /// Reads IEEE754 single-precision (4 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 4*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; + /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// LittleEndian::read_f32_into_unchecked(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + #[deprecated(since="1.3.0", note="please use `read_f32_into` instead")] + fn read_f32_into_unchecked(src: &[u8], dst: &mut [f32]) { + Self::read_f32_into(src, dst); + } + + /// Reads IEEE754 single-precision (4 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 8*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1.0, 2.0, 31.312e311, -11.32e91]; + /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// LittleEndian::read_f64_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + fn read_f64_into(src: &[u8], dst: &mut [f64]) { + let dst = unsafe { + slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len()) + }; + Self::read_u64_into(src, dst); + } + + /// **DEPRECATED**. + /// + /// This method is deprecated. Use `read_f64_into` instead. + /// + /// Reads IEEE754 single-precision (4 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 8*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1.0, 2.0, 31.312e311, -11.32e91]; + /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// LittleEndian::read_f64_into_unchecked(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[inline] + #[deprecated(since="1.3.0", note="please use `read_f64_into` instead")] + fn read_f64_into_unchecked(src: &[u8], dst: &mut [f64]) { + Self::read_f64_into(src, dst); + } + + /// Writes unsigned 16 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 2*src.len()`. + /// + /// # Examples + /// + /// Write and read `u16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 8]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u16_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u16_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_u16_into(src: &[u16], dst: &mut [u8]); + + /// Writes unsigned 32 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 4*src.len()`. + /// + /// # Examples + /// + /// Write and read `u32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u32_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_u32_into(src: &[u32], dst: &mut [u8]); + + /// Writes unsigned 64 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 8*src.len()`. + /// + /// # Examples + /// + /// Write and read `u64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u64_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_u64_into(src: &[u64], dst: &mut [u8]); + + /// Writes unsigned 128 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 16*src.len()`. + /// + /// # Examples + /// + /// Write and read `u128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 64]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_u128_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_u128_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[cfg(byteorder_i128)] + fn write_u128_into(src: &[u128], dst: &mut [u8]); + + /// Writes signed 16 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `buf.len() != 2*src.len()`. + /// + /// # Examples + /// + /// Write and read `i16` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 8]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i16_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i16_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_i16_into(src: &[i16], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u16, src.len()) + }; + Self::write_u16_into(src, dst); + } + + /// Writes signed 32 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 4*src.len()`. + /// + /// # Examples + /// + /// Write and read `i32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i32_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_i32_into(src: &[i32], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u32, src.len()) + }; + Self::write_u32_into(src, dst); + } + + /// Writes signed 64 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 8*src.len()`. + /// + /// # Examples + /// + /// Write and read `i64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i64_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_i64_into(src: &[i64], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u64, src.len()) + }; + Self::write_u64_into(src, dst); + } + + /// Writes signed 128 bit integers from `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `dst.len() != 16*src.len()`. + /// + /// # Examples + /// + /// Write and read `i128` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 64]; + /// let numbers_given = [1, 2, 0xf00f, 0xffee]; + /// LittleEndian::write_i128_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0; 4]; + /// LittleEndian::read_i128_into(&bytes, &mut numbers_got); + /// assert_eq!(numbers_given, numbers_got); + /// ``` + #[cfg(byteorder_i128)] + fn write_i128_into(src: &[i128], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u128, src.len()) + }; + Self::write_u128_into(src, dst); + } + + /// Writes IEEE754 single-precision (4 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 4*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f32` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 16]; + /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19]; + /// LittleEndian::write_f32_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// unsafe { + /// LittleEndian::read_f32_into(&bytes, &mut numbers_got); + /// } + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_f32_into(src: &[f32], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u32, src.len()) + }; + Self::write_u32_into(src, dst); + } + + /// Writes IEEE754 double-precision (8 bytes) floating point numbers from + /// `src` into `dst`. + /// + /// # Panics + /// + /// Panics when `src.len() != 8*dst.len()`. + /// + /// # Examples + /// + /// Write and read `f64` numbers in little endian order: + /// + /// ```rust + /// use byteorder::{ByteOrder, LittleEndian}; + /// + /// let mut bytes = [0; 32]; + /// let numbers_given = [1.0, 2.0, 31.312e311, -11.32e91]; + /// LittleEndian::write_f64_into(&numbers_given, &mut bytes); + /// + /// let mut numbers_got = [0.0; 4]; + /// unsafe { + /// LittleEndian::read_f64_into(&bytes, &mut numbers_got); + /// } + /// assert_eq!(numbers_given, numbers_got); + /// ``` + fn write_f64_into(src: &[f64], dst: &mut [u8]) { + let src = unsafe { + slice::from_raw_parts(src.as_ptr() as *const u64, src.len()) + }; + Self::write_u64_into(src, dst); + } + + /// Converts the given slice of unsigned 16 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_u16(&mut numbers); + /// assert_eq!(numbers, [5u16.to_be(), 65000u16.to_be()]); + /// ``` + fn from_slice_u16(numbers: &mut [u16]); + + /// Converts the given slice of unsigned 32 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_u32(&mut numbers); + /// assert_eq!(numbers, [5u32.to_be(), 65000u32.to_be()]); + /// ``` + fn from_slice_u32(numbers: &mut [u32]); + + /// Converts the given slice of unsigned 64 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_u64(&mut numbers); + /// assert_eq!(numbers, [5u64.to_be(), 65000u64.to_be()]); + /// ``` + fn from_slice_u64(numbers: &mut [u64]); + + /// Converts the given slice of unsigned 128 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_u128(&mut numbers); + /// assert_eq!(numbers, [5u128.to_be(), 65000u128.to_be()]); + /// ``` + #[cfg(byteorder_i128)] + fn from_slice_u128(numbers: &mut [u128]); + + /// Converts the given slice of signed 16 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_i16(&mut numbers); + /// assert_eq!(numbers, [5i16.to_be(), 65000i16.to_be()]); + /// ``` + #[inline] + fn from_slice_i16(src: &mut [i16]) { + let src = unsafe { + slice::from_raw_parts_mut(src.as_ptr() as *mut u16, src.len()) + }; + Self::from_slice_u16(src); + } + + /// Converts the given slice of signed 32 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_i32(&mut numbers); + /// assert_eq!(numbers, [5i32.to_be(), 65000i32.to_be()]); + /// ``` + #[inline] + fn from_slice_i32(src: &mut [i32]) { + let src = unsafe { + slice::from_raw_parts_mut(src.as_ptr() as *mut u32, src.len()) + }; + Self::from_slice_u32(src); + } + + /// Converts the given slice of signed 64 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_i64(&mut numbers); + /// assert_eq!(numbers, [5i64.to_be(), 65000i64.to_be()]); + /// ``` + #[inline] + fn from_slice_i64(src: &mut [i64]) { + let src = unsafe { + slice::from_raw_parts_mut(src.as_ptr() as *mut u64, src.len()) + }; + Self::from_slice_u64(src); + } + + /// Converts the given slice of signed 128 bit integers to a particular + /// endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + /// + /// # Examples + /// + /// Convert the host platform's endianness to big-endian: + /// + /// ```rust + /// use byteorder::{ByteOrder, BigEndian}; + /// + /// let mut numbers = [5, 65000]; + /// BigEndian::from_slice_i128(&mut numbers); + /// assert_eq!(numbers, [5i128.to_be(), 65000i128.to_be()]); + /// ``` + #[cfg(byteorder_i128)] + #[inline] + fn from_slice_i128(src: &mut [i128]) { + let src = unsafe { + slice::from_raw_parts_mut(src.as_ptr() as *mut u128, src.len()) + }; + Self::from_slice_u128(src); + } + + /// Converts the given slice of IEEE754 single-precision (4 bytes) floating + /// point numbers to a particular endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + fn from_slice_f32(numbers: &mut [f32]); + + /// Converts the given slice of IEEE754 double-precision (8 bytes) floating + /// point numbers to a particular endianness. + /// + /// If the endianness matches the endianness of the host platform, then + /// this is a no-op. + fn from_slice_f64(numbers: &mut [f64]); +} + +/// Defines big-endian serialization. +/// +/// Note that this type has no value constructor. It is used purely at the +/// type level. +/// +/// # Examples +/// +/// Write and read `u32` numbers in big endian order: +/// +/// ```rust +/// use byteorder::{ByteOrder, BigEndian}; +/// +/// let mut buf = [0; 4]; +/// BigEndian::write_u32(&mut buf, 1_000_000); +/// assert_eq!(1_000_000, BigEndian::read_u32(&buf)); +/// ``` +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum BigEndian {} + +impl Default for BigEndian { + fn default() -> BigEndian { + panic!("BigEndian default") + } +} + +/// A type alias for [`BigEndian`]. +/// +/// [`BigEndian`]: enum.BigEndian.html +pub type BE = BigEndian; + +/// Defines little-endian serialization. +/// +/// Note that this type has no value constructor. It is used purely at the +/// type level. +/// +/// # Examples +/// +/// Write and read `u32` numbers in little endian order: +/// +/// ```rust +/// use byteorder::{ByteOrder, LittleEndian}; +/// +/// let mut buf = [0; 4]; +/// LittleEndian::write_u32(&mut buf, 1_000_000); +/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf)); +/// ``` +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum LittleEndian {} + +impl Default for LittleEndian { + fn default() -> LittleEndian { + panic!("LittleEndian default") + } +} + +/// A type alias for [`LittleEndian`]. +/// +/// [`LittleEndian`]: enum.LittleEndian.html +pub type LE = LittleEndian; + +/// Defines network byte order serialization. +/// +/// Network byte order is defined by [RFC 1700][1] to be big-endian, and is +/// referred to in several protocol specifications. This type is an alias of +/// [`BigEndian`]. +/// +/// [1]: https://tools.ietf.org/html/rfc1700 +/// +/// Note that this type has no value constructor. It is used purely at the +/// type level. +/// +/// # Examples +/// +/// Write and read `i16` numbers in big endian order: +/// +/// ```rust +/// use byteorder::{ByteOrder, NetworkEndian, BigEndian}; +/// +/// let mut buf = [0; 2]; +/// BigEndian::write_i16(&mut buf, -50_000); +/// assert_eq!(-50_000, NetworkEndian::read_i16(&buf)); +/// ``` +/// +/// [`BigEndian`]: enum.BigEndian.html +pub type NetworkEndian = BigEndian; + +/// Defines system native-endian serialization. +/// +/// Note that this type has no value constructor. It is used purely at the +/// type level. +/// +/// On this platform, this is an alias for [`LittleEndian`]. +/// +/// [`LittleEndian`]: enum.LittleEndian.html +#[cfg(target_endian = "little")] +pub type NativeEndian = LittleEndian; + +/// Defines system native-endian serialization. +/// +/// Note that this type has no value constructor. It is used purely at the +/// type level. +/// +/// On this platform, this is an alias for [`BigEndian`]. +/// +/// [`BigEndian`]: enum.BigEndian.html +#[cfg(target_endian = "big")] +pub type NativeEndian = BigEndian; + +macro_rules! read_num_bytes { + ($ty:ty, $size:expr, $src:expr, $which:ident) => ({ + assert!($size == ::core::mem::size_of::<$ty>()); + assert!($size <= $src.len()); + let mut data: $ty = 0; + unsafe { + copy_nonoverlapping( + $src.as_ptr(), + &mut data as *mut $ty as *mut u8, + $size); + } + data.$which() + }); +} + +macro_rules! write_num_bytes { + ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => ({ + assert!($size <= $dst.len()); + unsafe { + // N.B. https://github.com/rust-lang/rust/issues/22776 + let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); + copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); + } + }); +} + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} + +macro_rules! write_slice_native { + ($src:expr, $dst:expr, $ty:ty, $size:expr) => {{ + assert!($size == ::core::mem::size_of::<$ty>()); + assert_eq!($size * $src.len(), $dst.len()); + + unsafe { + copy_nonoverlapping( + $src.as_ptr() as *const u8, + $dst.as_mut_ptr(), + $dst.len()); + } + }}; +} + +macro_rules! write_slice { + ($src:expr, $dst:expr, $ty:ty, $size:expr, $write:expr) => ({ + assert!($size == ::core::mem::size_of::<$ty>()); + assert_eq!($size * $src.len(), $dst.len()); + + for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + $write(chunk, n); + } + }); +} + +impl ByteOrder for BigEndian { + #[inline] + fn read_u16(buf: &[u8]) -> u16 { + read_num_bytes!(u16, 2, buf, to_be) + } + + #[inline] + fn read_u32(buf: &[u8]) -> u32 { + read_num_bytes!(u32, 4, buf, to_be) + } + + #[inline] + fn read_u64(buf: &[u8]) -> u64 { + read_num_bytes!(u64, 8, buf, to_be) + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_u128(buf: &[u8]) -> u128 { + read_num_bytes!(u128, 16, buf, to_be) + } + + #[inline] + fn read_uint(buf: &[u8], nbytes: usize) -> u64 { + assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); + let mut out = [0u8; 8]; + let ptr_out = out.as_mut_ptr(); + unsafe { + copy_nonoverlapping( + buf.as_ptr(), ptr_out.offset((8 - nbytes) as isize), nbytes); + (*(ptr_out as *const u64)).to_be() + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { + assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); + let mut out = [0u8; 16]; + let ptr_out = out.as_mut_ptr(); + unsafe { + copy_nonoverlapping( + buf.as_ptr(), ptr_out.offset((16 - nbytes) as isize), nbytes); + (*(ptr_out as *const u128)).to_be() + } + } + + #[inline] + fn write_u16(buf: &mut [u8], n: u16) { + write_num_bytes!(u16, 2, n, buf, to_be); + } + + #[inline] + fn write_u32(buf: &mut [u8], n: u32) { + write_num_bytes!(u32, 4, n, buf, to_be); + } + + #[inline] + fn write_u64(buf: &mut [u8], n: u64) { + write_num_bytes!(u64, 8, n, buf, to_be); + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_u128(buf: &mut [u8], n: u128) { + write_num_bytes!(u128, 16, n, buf, to_be); + } + + #[inline] + fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) { + assert!(pack_size(n) <= nbytes && nbytes <= 8); + assert!(nbytes <= buf.len()); + unsafe { + let bytes = *(&n.to_be() as *const u64 as *const [u8; 8]); + copy_nonoverlapping( + bytes.as_ptr().offset((8 - nbytes) as isize), + buf.as_mut_ptr(), + nbytes); + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) { + assert!(pack_size128(n) <= nbytes && nbytes <= 16); + assert!(nbytes <= buf.len()); + unsafe { + let bytes = *(&n.to_be() as *const u128 as *const [u8; 16]); + copy_nonoverlapping( + bytes.as_ptr().offset((16 - nbytes) as isize), + buf.as_mut_ptr(), + nbytes); + } + } + + #[inline] + fn read_u16_into(src: &[u8], dst: &mut [u16]) { + read_slice!(src, dst, 2, to_be); + } + + #[inline] + fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_be); + } + + #[inline] + fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_be); + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_u128_into(src: &[u8], dst: &mut [u128]) { + read_slice!(src, dst, 16, to_be); + } + + #[inline] + fn write_u16_into(src: &[u16], dst: &mut [u8]) { + if cfg!(target_endian = "big") { + write_slice_native!(src, dst, u16, 2); + } else { + write_slice!(src, dst, u16, 2, Self::write_u16); + } + } + + #[inline] + fn write_u32_into(src: &[u32], dst: &mut [u8]) { + if cfg!(target_endian = "big") { + write_slice_native!(src, dst, u32, 4); + } else { + write_slice!(src, dst, u32, 4, Self::write_u32); + } + } + + #[inline] + fn write_u64_into(src: &[u64], dst: &mut [u8]) { + if cfg!(target_endian = "big") { + write_slice_native!(src, dst, u64, 8); + } else { + write_slice!(src, dst, u64, 8, Self::write_u64); + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_u128_into(src: &[u128], dst: &mut [u8]) { + if cfg!(target_endian = "big") { + write_slice_native!(src, dst, u128, 16); + } else { + write_slice!(src, dst, u128, 16, Self::write_u128); + } + } + + #[inline] + fn from_slice_u16(numbers: &mut [u16]) { + if cfg!(target_endian = "little") { + for n in numbers { + *n = n.to_be(); + } + } + } + + #[inline] + fn from_slice_u32(numbers: &mut [u32]) { + if cfg!(target_endian = "little") { + for n in numbers { + *n = n.to_be(); + } + } + } + + #[inline] + fn from_slice_u64(numbers: &mut [u64]) { + if cfg!(target_endian = "little") { + for n in numbers { + *n = n.to_be(); + } + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn from_slice_u128(numbers: &mut [u128]) { + if cfg!(target_endian = "little") { + for n in numbers { + *n = n.to_be(); + } + } + } + + #[inline] + fn from_slice_f32(numbers: &mut [f32]) { + if cfg!(target_endian = "little") { + for n in numbers { + unsafe { + let int = *(n as *const f32 as *const u32); + *n = *(&int.to_be() as *const u32 as *const f32); + } + } + } + } + + #[inline] + fn from_slice_f64(numbers: &mut [f64]) { + if cfg!(target_endian = "little") { + for n in numbers { + unsafe { + let int = *(n as *const f64 as *const u64); + *n = *(&int.to_be() as *const u64 as *const f64); + } + } + } + } +} + +impl ByteOrder for LittleEndian { + #[inline] + fn read_u16(buf: &[u8]) -> u16 { + read_num_bytes!(u16, 2, buf, to_le) + } + + #[inline] + fn read_u32(buf: &[u8]) -> u32 { + read_num_bytes!(u32, 4, buf, to_le) + } + + #[inline] + fn read_u64(buf: &[u8]) -> u64 { + read_num_bytes!(u64, 8, buf, to_le) + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_u128(buf: &[u8]) -> u128 { + read_num_bytes!(u128, 16, buf, to_le) + } + + #[inline] + fn read_uint(buf: &[u8], nbytes: usize) -> u64 { + assert!(1 <= nbytes && nbytes <= 8 && nbytes <= buf.len()); + let mut out = [0u8; 8]; + let ptr_out = out.as_mut_ptr(); + unsafe { + copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); + (*(ptr_out as *const u64)).to_le() + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_uint128(buf: &[u8], nbytes: usize) -> u128 { + assert!(1 <= nbytes && nbytes <= 16 && nbytes <= buf.len()); + let mut out = [0u8; 16]; + let ptr_out = out.as_mut_ptr(); + unsafe { + copy_nonoverlapping(buf.as_ptr(), ptr_out, nbytes); + (*(ptr_out as *const u128)).to_le() + } + } + + #[inline] + fn write_u16(buf: &mut [u8], n: u16) { + write_num_bytes!(u16, 2, n, buf, to_le); + } + + #[inline] + fn write_u32(buf: &mut [u8], n: u32) { + write_num_bytes!(u32, 4, n, buf, to_le); + } + + #[inline] + fn write_u64(buf: &mut [u8], n: u64) { + write_num_bytes!(u64, 8, n, buf, to_le); + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_u128(buf: &mut [u8], n: u128) { + write_num_bytes!(u128, 16, n, buf, to_le); + } + + #[inline] + fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) { + assert!(pack_size(n as u64) <= nbytes && nbytes <= 8); + assert!(nbytes <= buf.len()); + unsafe { + let bytes = *(&n.to_le() as *const u64 as *const [u8; 8]); + copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes); + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) { + assert!(pack_size128(n as u128) <= nbytes && nbytes <= 16); + assert!(nbytes <= buf.len()); + unsafe { + let bytes = *(&n.to_le() as *const u128 as *const [u8; 16]); + copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes); + } + } + + #[inline] + fn read_u16_into(src: &[u8], dst: &mut [u16]) { + read_slice!(src, dst, 2, to_le); + } + + #[inline] + fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); + } + + #[inline] + fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); + } + + #[cfg(byteorder_i128)] + #[inline] + fn read_u128_into(src: &[u8], dst: &mut [u128]) { + read_slice!(src, dst, 16, to_le); + } + + #[inline] + fn write_u16_into(src: &[u16], dst: &mut [u8]) { + if cfg!(target_endian = "little") { + write_slice_native!(src, dst, u16, 2); + } else { + write_slice!(src, dst, u16, 2, Self::write_u16); + } + } + + #[inline] + fn write_u32_into(src: &[u32], dst: &mut [u8]) { + if cfg!(target_endian = "little") { + write_slice_native!(src, dst, u32, 4); + } else { + write_slice!(src, dst, u32, 4, Self::write_u32); + } + } + + #[inline] + fn write_u64_into(src: &[u64], dst: &mut [u8]) { + if cfg!(target_endian = "little") { + write_slice_native!(src, dst, u64, 8); + } else { + write_slice!(src, dst, u64, 8, Self::write_u64); + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn write_u128_into(src: &[u128], dst: &mut [u8]) { + if cfg!(target_endian = "little") { + write_slice_native!(src, dst, u128, 16); + } else { + write_slice!(src, dst, u128, 16, Self::write_u128); + } + } + + #[inline] + fn from_slice_u16(numbers: &mut [u16]) { + if cfg!(target_endian = "big") { + for n in numbers { + *n = n.to_le(); + } + } + } + + #[inline] + fn from_slice_u32(numbers: &mut [u32]) { + if cfg!(target_endian = "big") { + for n in numbers { + *n = n.to_le(); + } + } + } + + #[inline] + fn from_slice_u64(numbers: &mut [u64]) { + if cfg!(target_endian = "big") { + for n in numbers { + *n = n.to_le(); + } + } + } + + #[cfg(byteorder_i128)] + #[inline] + fn from_slice_u128(numbers: &mut [u128]) { + if cfg!(target_endian = "big") { + for n in numbers { + *n = n.to_le(); + } + } + } + + #[inline] + fn from_slice_f32(numbers: &mut [f32]) { + if cfg!(target_endian = "big") { + for n in numbers { + unsafe { + let int = *(n as *const f32 as *const u32); + *n = *(&int.to_le() as *const u32 as *const f32); + } + } + } + } + + #[inline] + fn from_slice_f64(numbers: &mut [f64]) { + if cfg!(target_endian = "big") { + for n in numbers { + unsafe { + let int = *(n as *const f64 as *const u64); + *n = *(&int.to_le() as *const u64 as *const f64); + } + } + } + } +} + +#[cfg(test)] +mod test { + extern crate quickcheck; + extern crate rand; + + use self::quickcheck::{QuickCheck, StdGen, Testable}; + use self::rand::thread_rng; + #[cfg(byteorder_i128)] + use self::rand::Rng; + #[cfg(byteorder_i128)] + use self::quickcheck::{Arbitrary, Gen}; + + pub const U24_MAX: u32 = 16_777_215; + pub const I24_MAX: i32 = 8_388_607; + pub const U48_MAX: u64 = 281_474_976_710_655; + pub const I48_MAX: i64 = 140_737_488_355_327; + + pub const U64_MAX: u64 = ::core::u64::MAX; + pub const I64_MAX: u64 = ::core::i64::MAX as u64; + + macro_rules! calc_max { + ($max:expr, $bytes:expr) => { calc_max!($max, $bytes, 8) }; + ($max:expr, $bytes:expr, $maxbytes:expr) => { + ($max - 1) >> (8 * ($maxbytes - $bytes)) + }; + } + + #[derive(Clone, Debug)] + pub struct Wi128(pub T); + + #[cfg(byteorder_i128)] + impl Wi128 { + pub fn clone(&self) -> T { + self.0.clone() + } + } + + impl PartialEq for Wi128 { + fn eq(&self, other: &T) -> bool { + self.0.eq(other) + } + } + + #[cfg(byteorder_i128)] + impl Arbitrary for Wi128 { + fn arbitrary(gen: &mut G) -> Wi128 { + let max = calc_max!(::core::u128::MAX, gen.size(), 16); + let output = + (gen.gen::() as u128) | + ((gen.gen::() as u128) << 64); + Wi128(output & (max - 1)) + } + } + + #[cfg(byteorder_i128)] + impl Arbitrary for Wi128 { + fn arbitrary(gen: &mut G) -> Wi128 { + let max = calc_max!(::core::i128::MAX, gen.size(), 16); + let output = + (gen.gen::() as i128) | + ((gen.gen::() as i128) << 64); + Wi128(output & (max - 1)) + } + } + + pub fn qc_sized(f: A, size: u64) { + QuickCheck::new() + .gen(StdGen::new(thread_rng(), size as usize)) + .tests(1_00) + .max_tests(10_000) + .quickcheck(f); + } + + macro_rules! qc_byte_order { + ($name:ident, $ty_int:ty, $max:expr, + $bytes:expr, $read:ident, $write:ident) => ( + mod $name { + use {BigEndian, ByteOrder, NativeEndian, LittleEndian}; + #[allow(unused_imports)] use super::{ qc_sized, Wi128 }; + + #[test] + fn big_endian() { + fn prop(n: $ty_int) -> bool { + let mut buf = [0; 16]; + BigEndian::$write(&mut buf, n.clone(), $bytes); + n == BigEndian::$read(&mut buf[..$bytes], $bytes) + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + + #[test] + fn little_endian() { + fn prop(n: $ty_int) -> bool { + let mut buf = [0; 16]; + LittleEndian::$write(&mut buf, n.clone(), $bytes); + n == LittleEndian::$read(&mut buf[..$bytes], $bytes) + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + + #[test] + fn native_endian() { + fn prop(n: $ty_int) -> bool { + let mut buf = [0; 16]; + NativeEndian::$write(&mut buf, n.clone(), $bytes); + n == NativeEndian::$read(&mut buf[..$bytes], $bytes) + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + } + ); + ($name:ident, $ty_int:ty, $max:expr, + $read:ident, $write:ident) => ( + mod $name { + use core::mem::size_of; + use {BigEndian, ByteOrder, NativeEndian, LittleEndian}; + #[allow(unused_imports)] use super::{ qc_sized, Wi128 }; + + #[test] + fn big_endian() { + fn prop(n: $ty_int) -> bool { + let bytes = size_of::<$ty_int>(); + let mut buf = [0; 16]; + BigEndian::$write(&mut buf[16 - bytes..], n.clone()); + n == BigEndian::$read(&mut buf[16 - bytes..]) + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + + #[test] + fn little_endian() { + fn prop(n: $ty_int) -> bool { + let bytes = size_of::<$ty_int>(); + let mut buf = [0; 16]; + LittleEndian::$write(&mut buf[..bytes], n.clone()); + n == LittleEndian::$read(&mut buf[..bytes]) + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + + #[test] + fn native_endian() { + fn prop(n: $ty_int) -> bool { + let bytes = size_of::<$ty_int>(); + let mut buf = [0; 16]; + NativeEndian::$write(&mut buf[..bytes], n.clone()); + n == NativeEndian::$read(&mut buf[..bytes]) + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + } + ); + } + + qc_byte_order!(prop_u16, u16, ::core::u16::MAX as u64, read_u16, write_u16); + qc_byte_order!(prop_i16, i16, ::core::i16::MAX as u64, read_i16, write_i16); + qc_byte_order!(prop_u24, u32, ::test::U24_MAX as u64, read_u24, write_u24); + qc_byte_order!(prop_i24, i32, ::test::I24_MAX as u64, read_i24, write_i24); + qc_byte_order!(prop_u32, u32, ::core::u32::MAX as u64, read_u32, write_u32); + qc_byte_order!(prop_i32, i32, ::core::i32::MAX as u64, read_i32, write_i32); + qc_byte_order!(prop_u48, u64, ::test::U48_MAX as u64, read_u48, write_u48); + qc_byte_order!(prop_i48, i64, ::test::I48_MAX as u64, read_i48, write_i48); + qc_byte_order!(prop_u64, u64, ::core::u64::MAX as u64, read_u64, write_u64); + qc_byte_order!(prop_i64, i64, ::core::i64::MAX as u64, read_i64, write_i64); + qc_byte_order!(prop_f32, f32, ::core::u64::MAX as u64, read_f32, write_f32); + qc_byte_order!(prop_f64, f64, ::core::i64::MAX as u64, read_f64, write_f64); + + #[cfg(byteorder_i128)] + qc_byte_order!(prop_u128, Wi128, 16 + 1, read_u128, write_u128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_i128, Wi128, 16 + 1, read_i128, write_i128); + + qc_byte_order!(prop_uint_1, + u64, calc_max!(super::U64_MAX, 1), 1, read_uint, write_uint); + qc_byte_order!(prop_uint_2, + u64, calc_max!(super::U64_MAX, 2), 2, read_uint, write_uint); + qc_byte_order!(prop_uint_3, + u64, calc_max!(super::U64_MAX, 3), 3, read_uint, write_uint); + qc_byte_order!(prop_uint_4, + u64, calc_max!(super::U64_MAX, 4), 4, read_uint, write_uint); + qc_byte_order!(prop_uint_5, + u64, calc_max!(super::U64_MAX, 5), 5, read_uint, write_uint); + qc_byte_order!(prop_uint_6, + u64, calc_max!(super::U64_MAX, 6), 6, read_uint, write_uint); + qc_byte_order!(prop_uint_7, + u64, calc_max!(super::U64_MAX, 7), 7, read_uint, write_uint); + qc_byte_order!(prop_uint_8, + u64, calc_max!(super::U64_MAX, 8), 8, read_uint, write_uint); + + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_1, + Wi128, 1, 1, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_2, + Wi128, 2, 2, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_3, + Wi128, 3, 3, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_4, + Wi128, 4, 4, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_5, + Wi128, 5, 5, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_6, + Wi128, 6, 6, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_7, + Wi128, 7, 7, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_8, + Wi128, 8, 8, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_9, + Wi128, 9, 9, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_10, + Wi128, 10, 10, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_11, + Wi128, 11, 11, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_12, + Wi128, 12, 12, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_13, + Wi128, 13, 13, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_14, + Wi128, 14, 14, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_15, + Wi128, 15, 15, read_uint128, write_uint128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_uint128_16, + Wi128, 16, 16, read_uint128, write_uint128); + + qc_byte_order!(prop_int_1, + i64, calc_max!(super::I64_MAX, 1), 1, read_int, write_int); + qc_byte_order!(prop_int_2, + i64, calc_max!(super::I64_MAX, 2), 2, read_int, write_int); + qc_byte_order!(prop_int_3, + i64, calc_max!(super::I64_MAX, 3), 3, read_int, write_int); + qc_byte_order!(prop_int_4, + i64, calc_max!(super::I64_MAX, 4), 4, read_int, write_int); + qc_byte_order!(prop_int_5, + i64, calc_max!(super::I64_MAX, 5), 5, read_int, write_int); + qc_byte_order!(prop_int_6, + i64, calc_max!(super::I64_MAX, 6), 6, read_int, write_int); + qc_byte_order!(prop_int_7, + i64, calc_max!(super::I64_MAX, 7), 7, read_int, write_int); + qc_byte_order!(prop_int_8, + i64, calc_max!(super::I64_MAX, 8), 8, read_int, write_int); + + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_1, + Wi128, 1, 1, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_2, + Wi128, 2, 2, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_3, + Wi128, 3, 3, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_4, + Wi128, 4, 4, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_5, + Wi128, 5, 5, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_6, + Wi128, 6, 6, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_7, + Wi128, 7, 7, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_8, + Wi128, 8, 8, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_9, + Wi128, 9, 9, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_10, + Wi128, 10, 10, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_11, + Wi128, 11, 11, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_12, + Wi128, 12, 12, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_13, + Wi128, 13, 13, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_14, + Wi128, 14, 14, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_15, + Wi128, 15, 15, read_int128, write_int128); + #[cfg(byteorder_i128)] + qc_byte_order!(prop_int128_16, + Wi128, 16, 16, read_int128, write_int128); + + + // Test that all of the byte conversion functions panic when given a + // buffer that is too small. + // + // These tests are critical to ensure safety, otherwise we might end up + // with a buffer overflow. + macro_rules! too_small { + ($name:ident, $maximally_small:expr, $zero:expr, + $read:ident, $write:ident) => ( + mod $name { + use {BigEndian, ByteOrder, NativeEndian, LittleEndian}; + + #[test] + #[should_panic] + fn read_big_endian() { + let buf = [0; $maximally_small]; + BigEndian::$read(&buf); + } + + #[test] + #[should_panic] + fn read_little_endian() { + let buf = [0; $maximally_small]; + LittleEndian::$read(&buf); + } + + #[test] + #[should_panic] + fn read_native_endian() { + let buf = [0; $maximally_small]; + NativeEndian::$read(&buf); + } + + #[test] + #[should_panic] + fn write_big_endian() { + let mut buf = [0; $maximally_small]; + BigEndian::$write(&mut buf, $zero); + } + + #[test] + #[should_panic] + fn write_little_endian() { + let mut buf = [0; $maximally_small]; + LittleEndian::$write(&mut buf, $zero); + } + + #[test] + #[should_panic] + fn write_native_endian() { + let mut buf = [0; $maximally_small]; + NativeEndian::$write(&mut buf, $zero); + } + } + ); + ($name:ident, $maximally_small:expr, $read:ident) => ( + mod $name { + use {BigEndian, ByteOrder, NativeEndian, LittleEndian}; + + #[test] + #[should_panic] + fn read_big_endian() { + let buf = [0; $maximally_small]; + BigEndian::$read(&buf, $maximally_small + 1); + } + + #[test] + #[should_panic] + fn read_little_endian() { + let buf = [0; $maximally_small]; + LittleEndian::$read(&buf, $maximally_small + 1); + } + + #[test] + #[should_panic] + fn read_native_endian() { + let buf = [0; $maximally_small]; + NativeEndian::$read(&buf, $maximally_small + 1); + } + } + ); + } + + too_small!(small_u16, 1, 0, read_u16, write_u16); + too_small!(small_i16, 1, 0, read_i16, write_i16); + too_small!(small_u32, 3, 0, read_u32, write_u32); + too_small!(small_i32, 3, 0, read_i32, write_i32); + too_small!(small_u64, 7, 0, read_u64, write_u64); + too_small!(small_i64, 7, 0, read_i64, write_i64); + too_small!(small_f32, 3, 0.0, read_f32, write_f32); + too_small!(small_f64, 7, 0.0, read_f64, write_f64); + #[cfg(byteorder_i128)] + too_small!(small_u128, 15, 0, read_u128, write_u128); + #[cfg(byteorder_i128)] + too_small!(small_i128, 15, 0, read_i128, write_i128); + + too_small!(small_uint_1, 1, read_uint); + too_small!(small_uint_2, 2, read_uint); + too_small!(small_uint_3, 3, read_uint); + too_small!(small_uint_4, 4, read_uint); + too_small!(small_uint_5, 5, read_uint); + too_small!(small_uint_6, 6, read_uint); + too_small!(small_uint_7, 7, read_uint); + + #[cfg(byteorder_i128)] + too_small!(small_uint128_1, 1, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_2, 2, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_3, 3, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_4, 4, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_5, 5, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_6, 6, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_7, 7, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_8, 8, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_9, 9, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_10, 10, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_11, 11, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_12, 12, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_13, 13, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_14, 14, read_uint128); + #[cfg(byteorder_i128)] + too_small!(small_uint128_15, 15, read_uint128); + + too_small!(small_int_1, 1, read_int); + too_small!(small_int_2, 2, read_int); + too_small!(small_int_3, 3, read_int); + too_small!(small_int_4, 4, read_int); + too_small!(small_int_5, 5, read_int); + too_small!(small_int_6, 6, read_int); + too_small!(small_int_7, 7, read_int); + + #[cfg(byteorder_i128)] + too_small!(small_int128_1, 1, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_2, 2, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_3, 3, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_4, 4, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_5, 5, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_6, 6, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_7, 7, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_8, 8, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_9, 9, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_10, 10, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_11, 11, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_12, 12, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_13, 13, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_14, 14, read_int128); + #[cfg(byteorder_i128)] + too_small!(small_int128_15, 15, read_int128); + + // Test that reading/writing slices enforces the correct lengths. + macro_rules! slice_lengths { + ($name:ident, $read:ident, $write:ident, + $num_bytes:expr, $numbers:expr) => { + mod $name { + use {ByteOrder, BigEndian, NativeEndian, LittleEndian}; + + #[test] + #[should_panic] + fn read_big_endian() { + let bytes = [0; $num_bytes]; + let mut numbers = $numbers; + BigEndian::$read(&bytes, &mut numbers); + } + + #[test] + #[should_panic] + fn read_little_endian() { + let bytes = [0; $num_bytes]; + let mut numbers = $numbers; + LittleEndian::$read(&bytes, &mut numbers); + } + + #[test] + #[should_panic] + fn read_native_endian() { + let bytes = [0; $num_bytes]; + let mut numbers = $numbers; + NativeEndian::$read(&bytes, &mut numbers); + } + + #[test] + #[should_panic] + fn write_big_endian() { + let mut bytes = [0; $num_bytes]; + let numbers = $numbers; + BigEndian::$write(&numbers, &mut bytes); + } + + #[test] + #[should_panic] + fn write_little_endian() { + let mut bytes = [0; $num_bytes]; + let numbers = $numbers; + LittleEndian::$write(&numbers, &mut bytes); + } + + #[test] + #[should_panic] + fn write_native_endian() { + let mut bytes = [0; $num_bytes]; + let numbers = $numbers; + NativeEndian::$write(&numbers, &mut bytes); + } + } + } + } + + slice_lengths!( + slice_len_too_small_u16, read_u16_into, write_u16_into, 3, [0, 0]); + slice_lengths!( + slice_len_too_big_u16, read_u16_into, write_u16_into, 5, [0, 0]); + slice_lengths!( + slice_len_too_small_i16, read_i16_into, write_i16_into, 3, [0, 0]); + slice_lengths!( + slice_len_too_big_i16, read_i16_into, write_i16_into, 5, [0, 0]); + + slice_lengths!( + slice_len_too_small_u32, read_u32_into, write_u32_into, 7, [0, 0]); + slice_lengths!( + slice_len_too_big_u32, read_u32_into, write_u32_into, 9, [0, 0]); + slice_lengths!( + slice_len_too_small_i32, read_i32_into, write_i32_into, 7, [0, 0]); + slice_lengths!( + slice_len_too_big_i32, read_i32_into, write_i32_into, 9, [0, 0]); + + slice_lengths!( + slice_len_too_small_u64, read_u64_into, write_u64_into, 15, [0, 0]); + slice_lengths!( + slice_len_too_big_u64, read_u64_into, write_u64_into, 17, [0, 0]); + slice_lengths!( + slice_len_too_small_i64, read_i64_into, write_i64_into, 15, [0, 0]); + slice_lengths!( + slice_len_too_big_i64, read_i64_into, write_i64_into, 17, [0, 0]); + + #[cfg(byteorder_i128)] + slice_lengths!( + slice_len_too_small_u128, read_u128_into, write_u128_into, 31, [0, 0]); + #[cfg(byteorder_i128)] + slice_lengths!( + slice_len_too_big_u128, read_u128_into, write_u128_into, 33, [0, 0]); + #[cfg(byteorder_i128)] + slice_lengths!( + slice_len_too_small_i128, read_i128_into, write_i128_into, 31, [0, 0]); + #[cfg(byteorder_i128)] + slice_lengths!( + slice_len_too_big_i128, read_i128_into, write_i128_into, 33, [0, 0]); + + #[test] + fn uint_bigger_buffer() { + use {ByteOrder, LittleEndian}; + let n = LittleEndian::read_uint(&[1, 2, 3, 4, 5, 6, 7, 8], 5); + assert_eq!(n, 0x0504030201); + } +} + +#[cfg(test)] +#[cfg(feature = "std")] +mod stdtests { + extern crate quickcheck; + extern crate rand; + + use self::quickcheck::{QuickCheck, StdGen, Testable}; + use self::rand::thread_rng; + + fn qc_unsized(f: A) { + + QuickCheck::new() + .gen(StdGen::new(thread_rng(), 16)) + .tests(1_00) + .max_tests(10_000) + .quickcheck(f); + } + + macro_rules! calc_max { + ($max:expr, $bytes:expr) => { ($max - 1) >> (8 * (8 - $bytes)) }; + } + + macro_rules! qc_bytes_ext { + ($name:ident, $ty_int:ty, $max:expr, + $bytes:expr, $read:ident, $write:ident) => ( + mod $name { + use std::io::Cursor; + use { + ReadBytesExt, WriteBytesExt, + BigEndian, NativeEndian, LittleEndian, + }; + #[allow(unused_imports)] use test::{qc_sized, Wi128}; + + #[test] + fn big_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let offset = wtr.len() - $bytes; + let mut rdr = Cursor::new(&mut wtr[offset..]); + n == rdr.$read::($bytes).unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + + #[test] + fn little_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let mut rdr = Cursor::new(wtr); + n == rdr.$read::($bytes).unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + + #[test] + fn native_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let offset = if cfg!(target_endian = "big") { + wtr.len() - $bytes + } else { + 0 + }; + let mut rdr = Cursor::new(&mut wtr[offset..]); + n == rdr.$read::($bytes).unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max); + } + } + ); + ($name:ident, $ty_int:ty, $max:expr, $read:ident, $write:ident) => ( + mod $name { + use std::io::Cursor; + use { + ReadBytesExt, WriteBytesExt, + BigEndian, NativeEndian, LittleEndian, + }; + #[allow(unused_imports)] use test::{qc_sized, Wi128}; + + #[test] + fn big_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let mut rdr = Cursor::new(wtr); + n == rdr.$read::().unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + + #[test] + fn little_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let mut rdr = Cursor::new(wtr); + n == rdr.$read::().unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + + #[test] + fn native_endian() { + fn prop(n: $ty_int) -> bool { + let mut wtr = vec![]; + wtr.$write::(n.clone()).unwrap(); + let mut rdr = Cursor::new(wtr); + n == rdr.$read::().unwrap() + } + qc_sized(prop as fn($ty_int) -> bool, $max - 1); + } + } + ); + } + + qc_bytes_ext!(prop_ext_u16, + u16, ::std::u16::MAX as u64, read_u16, write_u16); + qc_bytes_ext!(prop_ext_i16, + i16, ::std::i16::MAX as u64, read_i16, write_i16); + qc_bytes_ext!(prop_ext_u32, + u32, ::std::u32::MAX as u64, read_u32, write_u32); + qc_bytes_ext!(prop_ext_i32, + i32, ::std::i32::MAX as u64, read_i32, write_i32); + qc_bytes_ext!(prop_ext_u64, + u64, ::std::u64::MAX as u64, read_u64, write_u64); + qc_bytes_ext!(prop_ext_i64, + i64, ::std::i64::MAX as u64, read_i64, write_i64); + qc_bytes_ext!(prop_ext_f32, + f32, ::std::u64::MAX as u64, read_f32, write_f32); + qc_bytes_ext!(prop_ext_f64, + f64, ::std::i64::MAX as u64, read_f64, write_f64); + + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_u128, Wi128, 16 + 1, read_u128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_i128, Wi128, 16 + 1, read_i128, write_i128); + + qc_bytes_ext!(prop_ext_uint_1, + u64, calc_max!(::test::U64_MAX, 1), 1, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_2, + u64, calc_max!(::test::U64_MAX, 2), 2, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_3, + u64, calc_max!(::test::U64_MAX, 3), 3, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_4, + u64, calc_max!(::test::U64_MAX, 4), 4, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_5, + u64, calc_max!(::test::U64_MAX, 5), 5, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_6, + u64, calc_max!(::test::U64_MAX, 6), 6, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_7, + u64, calc_max!(::test::U64_MAX, 7), 7, read_uint, write_u64); + qc_bytes_ext!(prop_ext_uint_8, + u64, calc_max!(::test::U64_MAX, 8), 8, read_uint, write_u64); + + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_1, + Wi128, 1, 1, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_2, + Wi128, 2, 2, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_3, + Wi128, 3, 3, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_4, + Wi128, 4, 4, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_5, + Wi128, 5, 5, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_6, + Wi128, 6, 6, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_7, + Wi128, 7, 7, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_8, + Wi128, 8, 8, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_9, + Wi128, 9, 9, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_10, + Wi128, 10, 10, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_11, + Wi128, 11, 11, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_12, + Wi128, 12, 12, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_13, + Wi128, 13, 13, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_14, + Wi128, 14, 14, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_15, + Wi128, 15, 15, read_uint128, write_u128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_uint128_16, + Wi128, 16, 16, read_uint128, write_u128); + + qc_bytes_ext!(prop_ext_int_1, + i64, calc_max!(::test::I64_MAX, 1), 1, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_2, + i64, calc_max!(::test::I64_MAX, 2), 2, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_3, + i64, calc_max!(::test::I64_MAX, 3), 3, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_4, + i64, calc_max!(::test::I64_MAX, 4), 4, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_5, + i64, calc_max!(::test::I64_MAX, 5), 5, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_6, + i64, calc_max!(::test::I64_MAX, 6), 6, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_7, + i64, calc_max!(::test::I64_MAX, 1), 7, read_int, write_i64); + qc_bytes_ext!(prop_ext_int_8, + i64, calc_max!(::test::I64_MAX, 8), 8, read_int, write_i64); + + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_1, + Wi128, 1, 1, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_2, + Wi128, 2, 2, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_3, + Wi128, 3, 3, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_4, + Wi128, 4, 4, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_5, + Wi128, 5, 5, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_6, + Wi128, 6, 6, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_7, + Wi128, 7, 7, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_8, + Wi128, 8, 8, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_9, + Wi128, 9, 9, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_10, + Wi128, 10, 10, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_11, + Wi128, 11, 11, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_12, + Wi128, 12, 12, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_13, + Wi128, 13, 13, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_14, + Wi128, 14, 14, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_15, + Wi128, 15, 15, read_int128, write_i128); + #[cfg(byteorder_i128)] + qc_bytes_ext!(prop_ext_int128_16, + Wi128, 16, 16, read_int128, write_i128); + + // Test slice serialization/deserialization. + macro_rules! qc_slice { + ($name:ident, $ty_int:ty, $read:ident, $write:ident, $zero:expr) => { + mod $name { + use core::mem::size_of; + use {ByteOrder, BigEndian, NativeEndian, LittleEndian}; + use super::qc_unsized; + #[allow(unused_imports)] + use test::Wi128; + + #[test] + fn big_endian() { + #[allow(unused_unsafe)] + fn prop(numbers: Vec<$ty_int>) -> bool { + let numbers: Vec<_> = numbers + .into_iter() + .map(|x| x.clone()) + .collect(); + let num_bytes = size_of::<$ty_int>() * numbers.len(); + let mut bytes = vec![0; num_bytes]; + + BigEndian::$write(&numbers, &mut bytes); + + let mut got = vec![$zero; numbers.len()]; + unsafe { BigEndian::$read(&bytes, &mut got); } + + numbers == got + } + qc_unsized(prop as fn(_) -> bool); + } + + #[test] + fn little_endian() { + #[allow(unused_unsafe)] + fn prop(numbers: Vec<$ty_int>) -> bool { + let numbers: Vec<_> = numbers + .into_iter() + .map(|x| x.clone()) + .collect(); + let num_bytes = size_of::<$ty_int>() * numbers.len(); + let mut bytes = vec![0; num_bytes]; + + LittleEndian::$write(&numbers, &mut bytes); + + let mut got = vec![$zero; numbers.len()]; + unsafe { LittleEndian::$read(&bytes, &mut got); } + + numbers == got + } + qc_unsized(prop as fn(_) -> bool); + } + + #[test] + fn native_endian() { + #[allow(unused_unsafe)] + fn prop(numbers: Vec<$ty_int>) -> bool { + let numbers: Vec<_> = numbers + .into_iter() + .map(|x| x.clone()) + .collect(); + let num_bytes = size_of::<$ty_int>() * numbers.len(); + let mut bytes = vec![0; num_bytes]; + + NativeEndian::$write(&numbers, &mut bytes); + + let mut got = vec![$zero; numbers.len()]; + unsafe { NativeEndian::$read(&bytes, &mut got); } + + numbers == got + } + qc_unsized(prop as fn(_) -> bool); + } + } + } + } + + qc_slice!(prop_slice_u16, u16, read_u16_into, write_u16_into, 0); + qc_slice!(prop_slice_i16, i16, read_i16_into, write_i16_into, 0); + qc_slice!(prop_slice_u32, u32, read_u32_into, write_u32_into, 0); + qc_slice!(prop_slice_i32, i32, read_i32_into, write_i32_into, 0); + qc_slice!(prop_slice_u64, u64, read_u64_into, write_u64_into, 0); + qc_slice!(prop_slice_i64, i64, read_i64_into, write_i64_into, 0); + #[cfg(byteorder_i128)] + qc_slice!( + prop_slice_u128, Wi128, read_u128_into, write_u128_into, 0); + #[cfg(byteorder_i128)] + qc_slice!( + prop_slice_i128, Wi128, read_i128_into, write_i128_into, 0); + + qc_slice!( + prop_slice_f32, f32, read_f32_into, write_f32_into, 0.0); + qc_slice!( + prop_slice_f64, f64, read_f64_into, write_f64_into, 0.0); +} diff --git a/bytes/.cargo-checksum.json b/bytes/.cargo-checksum.json new file mode 100644 index 000000000..520b3c559 --- /dev/null +++ b/bytes/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"} \ No newline at end of file diff --git a/bytes/CHANGELOG.md b/bytes/CHANGELOG.md new file mode 100644 index 000000000..881b6f602 --- /dev/null +++ b/bytes/CHANGELOG.md @@ -0,0 +1,86 @@ +# 0.4.12 (March 6, 2018) + +### Added +- Implement `FromIterator<&'a u8>` for `BytesMut`/`Bytes` (#244). +- Implement `Buf` for `VecDeque` (#249). + +# 0.4.11 (November 17, 2018) + +* Use raw pointers for potentially racy loads (#233). +* Implement `BufRead` for `buf::Reader` (#232). +* Documentation tweaks (#234). + +# 0.4.10 (September 4, 2018) + +* impl `Buf` and `BufMut` for `Either` (#225). +* Add `Bytes::slice_ref` (#208). + +# 0.4.9 (July 12, 2018) + +* Add 128 bit number support behind a feature flag (#209). +* Implement `IntoBuf` for `&mut [u8]` + +# 0.4.8 (May 25, 2018) + +* Fix panic in `BytesMut` `FromIterator` implementation. +* Bytes: Recycle space when reserving space in vec mode (#197). +* Bytes: Add resize fn (#203). + +# 0.4.7 (April 27, 2018) + +* Make `Buf` and `BufMut` usable as trait objects (#186). +* impl BorrowMut for BytesMut (#185). +* Improve accessor performance (#195). + +# 0.4.6 (Janary 8, 2018) + +* Implement FromIterator for Bytes/BytesMut (#148). +* Add `advance` fn to Bytes/BytesMut (#166). +* Add `unsplit` fn to `BytesMut` (#162, #173). +* Improvements to Bytes split fns (#92). + +# 0.4.5 (August 12, 2017) + +* Fix range bug in `Take::bytes` +* Misc performance improvements +* Add extra `PartialEq` implementations. +* Add `Bytes::with_capacity` +* Implement `AsMut[u8]` for `BytesMut` + +# 0.4.4 (May 26, 2017) + +* Add serde support behind feature flag +* Add `extend_from_slice` on `Bytes` and `BytesMut` +* Add `truncate` and `clear` on `Bytes` +* Misc additional std trait implementations +* Misc performance improvements + +# 0.4.3 (April 30, 2017) + +* Fix Vec::advance_mut bug +* Bump minimum Rust version to 1.15 +* Misc performance tweaks + +# 0.4.2 (April 5, 2017) + +* Misc performance tweaks +* Improved `Debug` implementation for `Bytes` +* Avoid some incorrect assert panics + +# 0.4.1 (March 15, 2017) + +* Expose `buf` module and have most types available from there vs. root. +* Implement `IntoBuf` for `T: Buf`. +* Add `FromBuf` and `Buf::collect`. +* Add iterator adapter for `Buf`. +* Add scatter/gather support to `Buf` and `BufMut`. +* Add `Buf::chain`. +* Reduce allocations on repeated calls to `BytesMut::reserve`. +* Implement `Debug` for more types. +* Remove `Source` in favor of `IntoBuf`. +* Implement `Extend` for `BytesMut`. + + +# 0.4.0 (February 24, 2017) + +* Initial release diff --git a/bytes/Cargo.toml b/bytes/Cargo.toml new file mode 100644 index 000000000..96137c151 --- /dev/null +++ b/bytes/Cargo.toml @@ -0,0 +1,46 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bytes" +version = "0.4.12" +authors = ["Carl Lerche "] +exclude = [".gitignore", ".travis.yml", "deploy.sh", "bench/**/*", "test/**/*"] +description = "Types and traits for working with bytes" +homepage = "https://github.com/carllerche/bytes" +documentation = "https://docs.rs/bytes/0.4.12/bytes" +readme = "README.md" +keywords = ["buffers", "zero-copy", "io"] +categories = ["network-programming", "data-structures"] +license = "MIT" +repository = "https://github.com/carllerche/bytes" +[package.metadata.docs.rs] +features = ["i128"] +[dependencies.byteorder] +version = "1.1.0" + +[dependencies.either] +version = "1.5" +optional = true +default-features = false + +[dependencies.iovec] +version = "0.1" + +[dependencies.serde] +version = "1.0" +optional = true +[dev-dependencies.serde_test] +version = "1.0" + +[features] +i128 = ["byteorder/i128"] diff --git a/bytes/LICENSE b/bytes/LICENSE new file mode 100644 index 000000000..58fb29a12 --- /dev/null +++ b/bytes/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2018 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bytes/README.md b/bytes/README.md new file mode 100644 index 000000000..01359742c --- /dev/null +++ b/bytes/README.md @@ -0,0 +1,45 @@ +# Bytes + +A utility library for working with bytes. + +[![Crates.io](https://img.shields.io/crates/v/bytes.svg?maxAge=2592000)](https://crates.io/crates/bytes) +[![Build Status](https://travis-ci.org/carllerche/bytes.svg?branch=master)](https://travis-ci.org/carllerche/bytes) + +[Documentation](https://docs.rs/bytes/0.4.12/bytes/) + +## Usage + +To use `bytes`, first add this to your `Cargo.toml`: + +```toml +[dependencies] +bytes = "0.4.12" +``` + +Next, add this to your crate: + +```rust +extern crate bytes; + +use bytes::{Bytes, BytesMut, Buf, BufMut}; +``` + +## Serde support + +Serde support is optional and disabled by default. To enable use the feature `serde`. + +```toml +[dependencies] +bytes = { version = "0.4.12", features = ["serde"] } +``` + +## License + +This project is licensed under the [MIT license](LICENSE). + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `bytes` by you, shall be licensed as MIT, without any additional +terms or conditions. + diff --git a/bytes/benches/bytes.rs b/bytes/benches/bytes.rs new file mode 100644 index 000000000..7a338746b --- /dev/null +++ b/bytes/benches/bytes.rs @@ -0,0 +1,250 @@ +#![feature(test)] + +extern crate bytes; +extern crate test; + +use test::Bencher; +use bytes::{Bytes, BytesMut, BufMut}; + +#[bench] +fn alloc_small(b: &mut Bencher) { + b.iter(|| { + for _ in 0..1024 { + test::black_box(BytesMut::with_capacity(12)); + } + }) +} + +#[bench] +fn alloc_mid(b: &mut Bencher) { + b.iter(|| { + test::black_box(BytesMut::with_capacity(128)); + }) +} + +#[bench] +fn alloc_big(b: &mut Bencher) { + b.iter(|| { + test::black_box(BytesMut::with_capacity(4096)); + }) +} + +#[bench] +fn split_off_and_drop(b: &mut Bencher) { + b.iter(|| { + for _ in 0..1024 { + let v = vec![10; 200]; + let mut b = Bytes::from(v); + test::black_box(b.split_off(100)); + test::black_box(b); + } + }) +} + +#[bench] +fn deref_unique(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_unique_unroll(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..128 { + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_shared(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(4096); + buf.put(&[0u8; 1024][..]); + let _b2 = buf.split_off(1024); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_inline(b: &mut Bencher) { + let mut buf = BytesMut::with_capacity(8); + buf.put(&[0u8; 8][..]); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&buf[..]); + } + }) +} + +#[bench] +fn deref_two(b: &mut Bencher) { + let mut buf1 = BytesMut::with_capacity(8); + buf1.put(&[0u8; 8][..]); + + let mut buf2 = BytesMut::with_capacity(4096); + buf2.put(&[0u8; 1024][..]); + + b.iter(|| { + for _ in 0..512 { + test::black_box(&buf1[..]); + test::black_box(&buf2[..]); + } + }) +} + +#[bench] +fn clone_inline(b: &mut Bencher) { + let bytes = Bytes::from_static(b"hello world"); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn clone_static(b: &mut Bencher) { + let bytes = Bytes::from_static("hello world 1234567890 and have a good byte 0987654321".as_bytes()); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn clone_arc(b: &mut Bencher) { + let bytes = Bytes::from("hello world 1234567890 and have a good byte 0987654321".as_bytes()); + + b.iter(|| { + for _ in 0..1024 { + test::black_box(&bytes.clone()); + } + }) +} + +#[bench] +fn alloc_write_split_to_mid(b: &mut Bencher) { + b.iter(|| { + let mut buf = BytesMut::with_capacity(128); + buf.put_slice(&[0u8; 64]); + test::black_box(buf.split_to(64)); + }) +} + +#[bench] +fn drain_write_drain(b: &mut Bencher) { + let data = [0u8; 128]; + + b.iter(|| { + let mut buf = BytesMut::with_capacity(1024); + let mut parts = Vec::with_capacity(8); + + for _ in 0..8 { + buf.put(&data[..]); + parts.push(buf.split_to(128)); + } + + test::black_box(parts); + }) +} + +#[bench] +fn fmt_write(b: &mut Bencher) { + use std::fmt::Write; + let mut buf = BytesMut::with_capacity(128); + let s = "foo bar baz quux lorem ipsum dolor et"; + + b.bytes = s.len() as u64; + b.iter(|| { + let _ = write!(buf, "{}", s); + test::black_box(&buf); + unsafe { buf.set_len(0); } + }) +} + +#[bench] +fn from_long_slice(b: &mut Bencher) { + let data = [0u8; 128]; + b.bytes = data.len() as u64; + b.iter(|| { + let buf = BytesMut::from(&data[..]); + test::black_box(buf); + }) +} + +#[bench] +fn slice_empty(b: &mut Bencher) { + b.iter(|| { + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + test::black_box(b.slice(i % 100, i % 100)); + } + }) +} + +#[bench] +fn slice_short_from_arc(b: &mut Bencher) { + b.iter(|| { + // `clone` is to convert to ARC + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + test::black_box(b.slice(1, 2 + i % 10)); + } + }) +} + +// Keep in sync with bytes.rs +#[cfg(target_pointer_width = "64")] +const INLINE_CAP: usize = 4 * 8 - 1; +#[cfg(target_pointer_width = "32")] +const INLINE_CAP: usize = 4 * 4 - 1; + +#[bench] +fn slice_avg_le_inline_from_arc(b: &mut Bencher) { + b.iter(|| { + // `clone` is to convert to ARC + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + // [1, INLINE_CAP] + let len = 1 + i % (INLINE_CAP - 1); + test::black_box(b.slice(i % 10, i % 10 + len)); + } + }) +} + +#[bench] +fn slice_large_le_inline_from_arc(b: &mut Bencher) { + b.iter(|| { + // `clone` is to convert to ARC + let b = Bytes::from(vec![17; 1024]).clone(); + for i in 0..1000 { + // [INLINE_CAP - 10, INLINE_CAP] + let len = INLINE_CAP - 9 + i % 10; + test::black_box(b.slice(i % 10, i % 10 + len)); + } + }) +} diff --git a/bytes/ci/before_deploy.ps1 b/bytes/ci/before_deploy.ps1 new file mode 100644 index 000000000..191a30b88 --- /dev/null +++ b/bytes/ci/before_deploy.ps1 @@ -0,0 +1,23 @@ +# This script takes care of packaging the build artifacts that will go in the +# release zipfile + +$SRC_DIR = $PWD.Path +$STAGE = [System.Guid]::NewGuid().ToString() + +Set-Location $ENV:Temp +New-Item -Type Directory -Name $STAGE +Set-Location $STAGE + +$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip" + +# TODO Update this to package the right artifacts +Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\hello.exe" '.\' + +7z a "$ZIP" * + +Push-AppveyorArtifact "$ZIP" + +Remove-Item *.* -Force +Set-Location .. +Remove-Item $STAGE +Set-Location $SRC_DIR diff --git a/bytes/ci/before_deploy.sh b/bytes/ci/before_deploy.sh new file mode 100644 index 000000000..026dc2898 --- /dev/null +++ b/bytes/ci/before_deploy.sh @@ -0,0 +1,33 @@ +# This script takes care of building your crate and packaging it for release + +set -ex + +main() { + local src=$(pwd) \ + stage= + + case $TRAVIS_OS_NAME in + linux) + stage=$(mktemp -d) + ;; + osx) + stage=$(mktemp -d -t tmp) + ;; + esac + + test -f Cargo.lock || cargo generate-lockfile + + # TODO Update this to build the artifacts that matter to you + cross rustc --bin hello --target $TARGET --release -- -C lto + + # TODO Update this to package the right artifacts + cp target/$TARGET/release/hello $stage/ + + cd $stage + tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz * + cd $src + + rm -rf $stage +} + +main diff --git a/bytes/ci/install.sh b/bytes/ci/install.sh new file mode 100644 index 000000000..76bb7340d --- /dev/null +++ b/bytes/ci/install.sh @@ -0,0 +1,31 @@ +set -ex + +main() { + curl https://sh.rustup.rs -sSf | \ + sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION + + local target= + if [ $TRAVIS_OS_NAME = linux ]; then + target=x86_64-unknown-linux-gnu + sort=sort + else + target=x86_64-apple-darwin + sort=gsort # for `sort --sort-version`, from brew's coreutils. + fi + + # This fetches latest stable release + local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ + | cut -d/ -f3 \ + | grep -E '^v[0-9.]+$' \ + | $sort --version-sort \ + | tail -n1) + echo cross version: $tag + curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- \ + --force \ + --git japaric/cross \ + --tag $tag \ + --target $target +} + +main diff --git a/bytes/ci/script.sh b/bytes/ci/script.sh new file mode 100644 index 000000000..d1ed7f924 --- /dev/null +++ b/bytes/ci/script.sh @@ -0,0 +1,18 @@ +# This script takes care of testing your crate + +set -ex + +main() { + cross build --target $TARGET $EXTRA_ARGS + + if [ ! -z $DISABLE_TESTS ]; then + return + fi + + cross test --target $TARGET $EXTRA_ARGS +} + +# we don't run the "test phase" when doing deploys +if [ -z $TRAVIS_TAG ]; then + main +fi diff --git a/bytes/ci/tsan b/bytes/ci/tsan new file mode 100644 index 000000000..9cc54841b --- /dev/null +++ b/bytes/ci/tsan @@ -0,0 +1,28 @@ +# TSAN suppressions file for `bytes` + +# TSAN does not understand fences and `Arc::drop` is implemented using a fence. +# This causes many false positives. +race:Arc*drop +race:arc*Weak*drop + +# `std` mpsc is not used in any Bytes code base. This race is triggered by some +# rust runtime logic. +race:std*mpsc_queue + +# Some test runtime races. Allocation should be race free +race:alloc::alloc + +# Not sure why this is warning, but it is in the test harness and not the library. +race:TestEvent*clone +race:test::run_tests_console::*closure + +# Probably more fences in std. +race:__call_tls_dtors + +# `is_inline_or_static` is explicitly called concurrently without synchronization. +# The safety explanation can be found in a comment. +race:Inner::is_inline_or_static + +# This ignores a false positive caused by `thread::park()`/`thread::unpark()`. +# See: https://github.com/rust-lang/rust/pull/54806#issuecomment-436193353 +race:pthread_cond_destroy diff --git a/bytes/src/buf/buf.rs b/bytes/src/buf/buf.rs new file mode 100644 index 000000000..dc20567d3 --- /dev/null +++ b/bytes/src/buf/buf.rs @@ -0,0 +1,1154 @@ +use super::{IntoBuf, Take, Reader, Iter, FromBuf, Chain}; +use byteorder::{BigEndian, ByteOrder, LittleEndian}; +use iovec::IoVec; + +use std::{cmp, io, ptr}; + +macro_rules! buf_get_impl { + ($this:ident, $size:expr, $conv:path) => ({ + // try to convert directly from the bytes + let ret = { + // this Option trick is to avoid keeping a borrow on self + // when advance() is called (mut borrow) and to call bytes() only once + if let Some(src) = $this.bytes().get(..($size)) { + Some($conv(src)) + } else { + None + } + }; + if let Some(ret) = ret { + // if the direct convertion was possible, advance and return + $this.advance($size); + return ret; + } else { + // if not we copy the bytes in a temp buffer then convert + let mut buf = [0; ($size)]; + $this.copy_to_slice(&mut buf); // (do the advance) + return $conv(&buf); + } + }); + ($this:ident, $buf_size:expr, $conv:path, $len_to_read:expr) => ({ + // The same trick as above does not improve the best case speed. + // It seems to be linked to the way the method is optimised by the compiler + let mut buf = [0; ($buf_size)]; + $this.copy_to_slice(&mut buf[..($len_to_read)]); + return $conv(&buf[..($len_to_read)], $len_to_read); + }); +} + +/// Read bytes from a buffer. +/// +/// A buffer stores bytes in memory such that read operations are infallible. +/// The underlying storage may or may not be in contiguous memory. A `Buf` value +/// is a cursor into the buffer. Reading from `Buf` advances the cursor +/// position. It can be thought of as an efficient `Iterator` for collections of +/// bytes. +/// +/// The simplest `Buf` is a `Cursor` wrapping a `[u8]`. +/// +/// ``` +/// use bytes::Buf; +/// use std::io::Cursor; +/// +/// let mut buf = Cursor::new(b"hello world"); +/// +/// assert_eq!(b'h', buf.get_u8()); +/// assert_eq!(b'e', buf.get_u8()); +/// assert_eq!(b'l', buf.get_u8()); +/// +/// let mut rest = [0; 8]; +/// buf.copy_to_slice(&mut rest); +/// +/// assert_eq!(&rest[..], b"lo world"); +/// ``` +pub trait Buf { + /// Returns the number of bytes between the current position and the end of + /// the buffer. + /// + /// This value is greater than or equal to the length of the slice returned + /// by `bytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world"); + /// + /// assert_eq!(buf.remaining(), 11); + /// + /// buf.get_u8(); + /// + /// assert_eq!(buf.remaining(), 10); + /// ``` + /// + /// # Implementer notes + /// + /// Implementations of `remaining` should ensure that the return value does + /// not change unless a call is made to `advance` or any other function that + /// is documented to change the `Buf`'s current position. + fn remaining(&self) -> usize; + + /// Returns a slice starting at the current position and of length between 0 + /// and `Buf::remaining()`. Note that this *can* return shorter slice (this allows + /// non-continuous internal representation). + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world"); + /// + /// assert_eq!(buf.bytes(), b"hello world"); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), b"world"); + /// ``` + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `Buf::remaining` returns 0, calls to `bytes` should return an + /// empty slice. + fn bytes(&self) -> &[u8]; + + /// Fills `dst` with potentially multiple slices starting at `self`'s + /// current position. + /// + /// If the `Buf` is backed by disjoint slices of bytes, `bytes_vec` enables + /// fetching more than one slice at once. `dst` is a slice of `IoVec` + /// references, enabling the slice to be directly used with [`writev`] + /// without any further conversion. The sum of the lengths of all the + /// buffers in `dst` will be less than or equal to `Buf::remaining()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vec` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `Buf::remaining` returns 0, calls to `bytes_vec` must return 0 + /// without mutating `dst`. + /// + /// Implementations should also take care to properly handle being called + /// with `dst` being a zero length slice. + /// + /// [`writev`]: http://man7.org/linux/man-pages/man2/readv.2.html + fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { + if dst.is_empty() { + return 0; + } + + if self.has_remaining() { + dst[0] = self.bytes().into(); + 1 + } else { + 0 + } + } + + /// Advance the internal cursor of the Buf + /// + /// The next call to `bytes` will return a slice starting `cnt` bytes + /// further into the underlying buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world"); + /// + /// assert_eq!(buf.bytes(), b"hello world"); + /// + /// buf.advance(6); + /// + /// assert_eq!(buf.bytes(), b"world"); + /// ``` + /// + /// # Panics + /// + /// This function **may** panic if `cnt > self.remaining()`. + /// + /// # Implementer notes + /// + /// It is recommended for implementations of `advance` to panic if `cnt > + /// self.remaining()`. If the implementation does not panic, the call must + /// behave as if `cnt == self.remaining()`. + /// + /// A call with `cnt == 0` should never panic and be a no-op. + fn advance(&mut self, cnt: usize); + + /// Returns true if there are any more bytes to consume + /// + /// This is equivalent to `self.remaining() != 0`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"a"); + /// + /// assert!(buf.has_remaining()); + /// + /// buf.get_u8(); + /// + /// assert!(!buf.has_remaining()); + /// ``` + fn has_remaining(&self) -> bool { + self.remaining() > 0 + } + + /// Copies bytes from `self` into `dst`. + /// + /// The cursor is advanced by the number of bytes copied. `self` must have + /// enough remaining bytes to fill `dst`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world"); + /// let mut dst = [0; 5]; + /// + /// buf.copy_to_slice(&mut dst); + /// assert_eq!(b"hello", &dst); + /// assert_eq!(6, buf.remaining()); + /// ``` + /// + /// # Panics + /// + /// This function panics if `self.remaining() < dst.len()` + fn copy_to_slice(&mut self, dst: &mut [u8]) { + let mut off = 0; + + assert!(self.remaining() >= dst.len()); + + while off < dst.len() { + let cnt; + + unsafe { + let src = self.bytes(); + cnt = cmp::min(src.len(), dst.len() - off); + + ptr::copy_nonoverlapping( + src.as_ptr(), dst[off..].as_mut_ptr(), cnt); + + off += src.len(); + } + + self.advance(cnt); + } + } + + /// Gets an unsigned 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08 hello"); + /// assert_eq!(8, buf.get_u8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. + fn get_u8(&mut self) -> u8 { + assert!(self.remaining() >= 1); + let ret = self.bytes()[0]; + self.advance(1); + ret + } + + /// Gets a signed 8 bit integer from `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08 hello"); + /// assert_eq!(8, buf.get_i8()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is no more remaining data in `self`. + fn get_i8(&mut self) -> i8 { + assert!(self.remaining() >= 1); + let ret = self.bytes()[0] as i8; + self.advance(1); + ret + } + + #[doc(hidden)] + #[deprecated(note="use get_u16_be or get_u16_le")] + fn get_u16(&mut self) -> u16 where Self: Sized { + let mut buf = [0; 2]; + self.copy_to_slice(&mut buf); + T::read_u16(&buf) + } + + /// Gets an unsigned 16 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09 hello"); + /// assert_eq!(0x0809, buf.get_u16_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u16_be(&mut self) -> u16 { + buf_get_impl!(self, 2, BigEndian::read_u16); + } + + /// Gets an unsigned 16 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x09\x08 hello"); + /// assert_eq!(0x0809, buf.get_u16_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u16_le(&mut self) -> u16 { + buf_get_impl!(self, 2, LittleEndian::read_u16); + } + + #[doc(hidden)] + #[deprecated(note="use get_i16_be or get_i16_le")] + fn get_i16(&mut self) -> i16 where Self: Sized { + let mut buf = [0; 2]; + self.copy_to_slice(&mut buf); + T::read_i16(&buf) + } + + /// Gets a signed 16 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09 hello"); + /// assert_eq!(0x0809, buf.get_i16_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i16_be(&mut self) -> i16 { + buf_get_impl!(self, 2, BigEndian::read_i16); + } + + /// Gets a signed 16 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x09\x08 hello"); + /// assert_eq!(0x0809, buf.get_i16_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i16_le(&mut self) -> i16 { + buf_get_impl!(self, 2, LittleEndian::read_i16); + } + + #[doc(hidden)] + #[deprecated(note="use get_u32_be or get_u32_le")] + fn get_u32(&mut self) -> u32 where Self: Sized { + let mut buf = [0; 4]; + self.copy_to_slice(&mut buf); + T::read_u32(&buf) + } + + /// Gets an unsigned 32 bit integer from `self` in the big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello"); + /// assert_eq!(0x0809A0A1, buf.get_u32_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u32_be(&mut self) -> u32 { + buf_get_impl!(self, 4, BigEndian::read_u32); + } + + /// Gets an unsigned 32 bit integer from `self` in the little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\xA1\xA0\x09\x08 hello"); + /// assert_eq!(0x0809A0A1, buf.get_u32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u32_le(&mut self) -> u32 { + buf_get_impl!(self, 4, LittleEndian::read_u32); + } + + #[doc(hidden)] + #[deprecated(note="use get_i32_be or get_i32_le")] + fn get_i32(&mut self) -> i32 where Self: Sized { + let mut buf = [0; 4]; + self.copy_to_slice(&mut buf); + T::read_i32(&buf) + } + + /// Gets a signed 32 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x09\xA0\xA1 hello"); + /// assert_eq!(0x0809A0A1, buf.get_i32_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i32_be(&mut self) -> i32 { + buf_get_impl!(self, 4, BigEndian::read_i32); + } + + /// Gets a signed 32 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\xA1\xA0\x09\x08 hello"); + /// assert_eq!(0x0809A0A1, buf.get_i32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i32_le(&mut self) -> i32 { + buf_get_impl!(self, 4, LittleEndian::read_i32); + } + + #[doc(hidden)] + #[deprecated(note="use get_u64_be or get_u64_le")] + fn get_u64(&mut self) -> u64 where Self: Sized { + let mut buf = [0; 8]; + self.copy_to_slice(&mut buf); + T::read_u64(&buf) + } + + /// Gets an unsigned 64 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"); + /// assert_eq!(0x0102030405060708, buf.get_u64_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u64_be(&mut self) -> u64 { + buf_get_impl!(self, 8, BigEndian::read_u64); + } + + /// Gets an unsigned 64 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x07\x06\x05\x04\x03\x02\x01 hello"); + /// assert_eq!(0x0102030405060708, buf.get_u64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_u64_le(&mut self) -> u64 { + buf_get_impl!(self, 8, LittleEndian::read_u64); + } + + #[doc(hidden)] + #[deprecated(note="use get_i64_be or get_i64_le")] + fn get_i64(&mut self) -> i64 where Self: Sized { + let mut buf = [0; 8]; + self.copy_to_slice(&mut buf); + T::read_i64(&buf) + } + + /// Gets a signed 64 bit integer from `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08 hello"); + /// assert_eq!(0x0102030405060708, buf.get_i64_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i64_be(&mut self) -> i64 { + buf_get_impl!(self, 8, BigEndian::read_i64); + } + + /// Gets a signed 64 bit integer from `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x08\x07\x06\x05\x04\x03\x02\x01 hello"); + /// assert_eq!(0x0102030405060708, buf.get_i64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_i64_le(&mut self) -> i64 { + buf_get_impl!(self, 8, LittleEndian::read_i64); + } + + /// Gets an unsigned 128 bit integer from `self` in big-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello"); + /// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + #[cfg(feature = "i128")] + fn get_u128_be(&mut self) -> u128 { + buf_get_impl!(self, 16, BigEndian::read_u128); + } + + /// Gets an unsigned 128 bit integer from `self` in little-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello"); + /// assert_eq!(0x01020304050607080910111213141516, buf.get_u128_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + #[cfg(feature = "i128")] + fn get_u128_le(&mut self) -> u128 { + buf_get_impl!(self, 16, LittleEndian::read_u128); + } + + /// Gets a signed 128 bit integer from `self` in big-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16 hello"); + /// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + #[cfg(feature = "i128")] + fn get_i128_be(&mut self) -> i128 { + buf_get_impl!(self, 16, BigEndian::read_i128); + } + + /// Gets a signed 128 bit integer from `self` in little-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01 hello"); + /// assert_eq!(0x01020304050607080910111213141516, buf.get_i128_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + #[cfg(feature = "i128")] + fn get_i128_le(&mut self) -> i128 { + buf_get_impl!(self, 16, LittleEndian::read_i128); + } + + #[doc(hidden)] + #[deprecated(note="use get_uint_be or get_uint_le")] + fn get_uint(&mut self, nbytes: usize) -> u64 where Self: Sized { + let mut buf = [0; 8]; + self.copy_to_slice(&mut buf[..nbytes]); + T::read_uint(&buf[..nbytes], nbytes) + } + + /// Gets an unsigned n-byte integer from `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BigEndian}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03 hello"); + /// assert_eq!(0x010203, buf.get_uint_be(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_uint_be(&mut self, nbytes: usize) -> u64 { + buf_get_impl!(self, 8, BigEndian::read_uint, nbytes); + } + + /// Gets an unsigned n-byte integer from `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x03\x02\x01 hello"); + /// assert_eq!(0x010203, buf.get_uint_le(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_uint_le(&mut self, nbytes: usize) -> u64 { + buf_get_impl!(self, 8, LittleEndian::read_uint, nbytes); + } + + #[doc(hidden)] + #[deprecated(note="use get_int_be or get_int_le")] + fn get_int(&mut self, nbytes: usize) -> i64 where Self: Sized { + let mut buf = [0; 8]; + self.copy_to_slice(&mut buf[..nbytes]); + T::read_int(&buf[..nbytes], nbytes) + } + + /// Gets a signed n-byte integer from `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x01\x02\x03 hello"); + /// assert_eq!(0x010203, buf.get_int_be(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_int_be(&mut self, nbytes: usize) -> i64 { + buf_get_impl!(self, 8, BigEndian::read_int, nbytes); + } + + /// Gets a signed n-byte integer from `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x03\x02\x01 hello"); + /// assert_eq!(0x010203, buf.get_int_le(3)); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_int_le(&mut self, nbytes: usize) -> i64 { + buf_get_impl!(self, 8, LittleEndian::read_int, nbytes); + } + + #[doc(hidden)] + #[deprecated(note="use get_f32_be or get_f32_le")] + fn get_f32(&mut self) -> f32 where Self: Sized { + let mut buf = [0; 4]; + self.copy_to_slice(&mut buf); + T::read_f32(&buf) + } + + /// Gets an IEEE754 single-precision (4 bytes) floating point number from + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x3F\x99\x99\x9A hello"); + /// assert_eq!(1.2f32, buf.get_f32_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f32_be(&mut self) -> f32 { + buf_get_impl!(self, 4, BigEndian::read_f32); + } + + /// Gets an IEEE754 single-precision (4 bytes) floating point number from + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x9A\x99\x99\x3F hello"); + /// assert_eq!(1.2f32, buf.get_f32_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f32_le(&mut self) -> f32 { + buf_get_impl!(self, 4, LittleEndian::read_f32); + } + + #[doc(hidden)] + #[deprecated(note="use get_f64_be or get_f64_le")] + fn get_f64(&mut self) -> f64 where Self: Sized { + let mut buf = [0; 8]; + self.copy_to_slice(&mut buf); + T::read_f64(&buf) + } + + /// Gets an IEEE754 double-precision (8 bytes) floating point number from + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x3F\xF3\x33\x33\x33\x33\x33\x33 hello"); + /// assert_eq!(1.2f64, buf.get_f64_be()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f64_be(&mut self) -> f64 { + buf_get_impl!(self, 8, BigEndian::read_f64); + } + + /// Gets an IEEE754 double-precision (8 bytes) floating point number from + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"\x33\x33\x33\x33\x33\x33\xF3\x3F hello"); + /// assert_eq!(1.2f64, buf.get_f64_le()); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining data in `self`. + fn get_f64_le(&mut self) -> f64 { + buf_get_impl!(self, 8, LittleEndian::read_f64); + } + + /// Transforms a `Buf` into a concrete buffer. + /// + /// `collect()` can operate on any value that implements `Buf`, and turn it + /// into the relevent concrete buffer type. + /// + /// # Examples + /// + /// Collecting a buffer and loading the contents into a `Vec`. + /// + /// ``` + /// use bytes::{Buf, Bytes, IntoBuf}; + /// + /// let buf = Bytes::from(&b"hello world"[..]).into_buf(); + /// let vec: Vec = buf.collect(); + /// + /// assert_eq!(vec, &b"hello world"[..]); + /// ``` + fn collect(self) -> B + where Self: Sized, + B: FromBuf, + { + B::from_buf(self) + } + + /// Creates an adaptor which will read at most `limit` bytes from `self`. + /// + /// This function returns a new instance of `Buf` which will read at most + /// `limit` bytes. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new("hello world").take(5); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(dst, b"hello"); + /// + /// let mut buf = buf.into_inner(); + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` + fn take(self, limit: usize) -> Take + where Self: Sized + { + super::take::new(self, limit) + } + + /// Creates an adaptor which will chain this buffer with another. + /// + /// The returned `Buf` instance will first consume all bytes from `self`. + /// Afterwards the output is equivalent to the output of next. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// use bytes::buf::Chain; + /// + /// let buf = Bytes::from(&b"hello "[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// let full: Bytes = buf.collect(); + /// assert_eq!(full[..], b"hello world"[..]); + /// ``` + fn chain(self, next: U) -> Chain + where U: IntoBuf, + Self: Sized, + { + Chain::new(self, next.into_buf()) + } + + /// Creates a "by reference" adaptor for this instance of `Buf`. + /// + /// The returned adaptor also implements `Buf` and will simply borrow `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new("hello world"); + /// let mut dst = vec![]; + /// + /// { + /// let mut reference = buf.by_ref(); + /// dst.put(&mut reference.take(5)); + /// assert_eq!(dst, b"hello"); + /// } // drop our &mut reference so we can use `buf` again + /// + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(dst, b" world"); + /// ``` + fn by_ref(&mut self) -> &mut Self where Self: Sized { + self + } + + /// Creates an adaptor which implements the `Read` trait for `self`. + /// + /// This function returns a new value which implements `Read` by adapting + /// the `Read` trait functions to the `Buf` trait functions. Given that + /// `Buf` operations are infallible, none of the `Read` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, IntoBuf, Bytes}; + /// use std::io::Read; + /// + /// let buf = Bytes::from("hello world").into_buf(); + /// + /// let mut reader = buf.reader(); + /// let mut dst = [0; 1024]; + /// + /// let num = reader.read(&mut dst).unwrap(); + /// + /// assert_eq!(11, num); + /// assert_eq!(&dst[..11], b"hello world"); + /// ``` + fn reader(self) -> Reader where Self: Sized { + super::reader::new(self) + } + + /// Returns an iterator over the bytes contained by the buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, IntoBuf, Bytes}; + /// + /// let buf = Bytes::from(&b"abc"[..]).into_buf(); + /// let mut iter = buf.iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// assert_eq!(iter.next(), Some(b'b')); + /// assert_eq!(iter.next(), Some(b'c')); + /// assert_eq!(iter.next(), None); + /// ``` + fn iter(self) -> Iter where Self: Sized { + super::iter::new(self) + } +} + +impl<'a, T: Buf + ?Sized> Buf for &'a mut T { + fn remaining(&self) -> usize { + (**self).remaining() + } + + fn bytes(&self) -> &[u8] { + (**self).bytes() + } + + fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { + (**self).bytes_vec(dst) + } + + fn advance(&mut self, cnt: usize) { + (**self).advance(cnt) + } +} + +impl Buf for Box { + fn remaining(&self) -> usize { + (**self).remaining() + } + + fn bytes(&self) -> &[u8] { + (**self).bytes() + } + + fn bytes_vec<'b>(&'b self, dst: &mut [&'b IoVec]) -> usize { + (**self).bytes_vec(dst) + } + + fn advance(&mut self, cnt: usize) { + (**self).advance(cnt) + } +} + +impl> Buf for io::Cursor { + fn remaining(&self) -> usize { + let len = self.get_ref().as_ref().len(); + let pos = self.position(); + + if pos >= len as u64 { + return 0; + } + + len - pos as usize + } + + fn bytes(&self) -> &[u8] { + let len = self.get_ref().as_ref().len(); + let pos = self.position() as usize; + + if pos >= len { + return Default::default(); + } + + &(self.get_ref().as_ref())[pos..] + } + + fn advance(&mut self, cnt: usize) { + let pos = (self.position() as usize) + .checked_add(cnt).expect("overflow"); + + assert!(pos <= self.get_ref().as_ref().len()); + + self.set_position(pos as u64); + } +} + +impl Buf for Option<[u8; 1]> { + fn remaining(&self) -> usize { + if self.is_some() { + 1 + } else { + 0 + } + } + + fn bytes(&self) -> &[u8] { + self.as_ref().map(AsRef::as_ref) + .unwrap_or(Default::default()) + } + + fn advance(&mut self, cnt: usize) { + if cnt == 0 { + return; + } + + if self.is_none() { + panic!("overflow"); + } else { + assert_eq!(1, cnt); + *self = None; + } + } +} + +// The existance of this function makes the compiler catch if the Buf +// trait is "object-safe" or not. +fn _assert_trait_object(_b: &Buf) {} diff --git a/bytes/src/buf/buf_mut.rs b/bytes/src/buf/buf_mut.rs new file mode 100644 index 000000000..7f3c1f756 --- /dev/null +++ b/bytes/src/buf/buf_mut.rs @@ -0,0 +1,1167 @@ +use super::{IntoBuf, Writer}; +use byteorder::{LittleEndian, ByteOrder, BigEndian}; +use iovec::IoVec; + +use std::{cmp, io, ptr, usize}; + +/// A trait for values that provide sequential write access to bytes. +/// +/// Write bytes to a buffer +/// +/// A buffer stores bytes in memory such that write operations are infallible. +/// The underlying storage may or may not be in contiguous memory. A `BufMut` +/// value is a cursor into the buffer. Writing to `BufMut` advances the cursor +/// position. +/// +/// The simplest `BufMut` is a `Vec`. +/// +/// ``` +/// use bytes::BufMut; +/// +/// let mut buf = vec![]; +/// +/// buf.put("hello world"); +/// +/// assert_eq!(buf, b"hello world"); +/// ``` +pub trait BufMut { + /// Returns the number of bytes that can be written from the current + /// position until the end of the buffer is reached. + /// + /// This value is greater than or equal to the length of the slice returned + /// by `bytes_mut`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// use std::io::Cursor; + /// + /// let mut dst = [0; 10]; + /// let mut buf = Cursor::new(&mut dst[..]); + /// + /// assert_eq!(10, buf.remaining_mut()); + /// buf.put("hello"); + /// + /// assert_eq!(5, buf.remaining_mut()); + /// ``` + /// + /// # Implementer notes + /// + /// Implementations of `remaining_mut` should ensure that the return value + /// does not change unless a call is made to `advance_mut` or any other + /// function that is documented to change the `BufMut`'s current position. + fn remaining_mut(&self) -> usize; + + /// Advance the internal cursor of the BufMut + /// + /// The next call to `bytes_mut` will return a slice starting `cnt` bytes + /// further into the underlying buffer. + /// + /// This function is unsafe because there is no guarantee that the bytes + /// being advanced past have been initialized. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = Vec::with_capacity(16); + /// + /// unsafe { + /// buf.bytes_mut()[0] = b'h'; + /// buf.bytes_mut()[1] = b'e'; + /// + /// buf.advance_mut(2); + /// + /// buf.bytes_mut()[0] = b'l'; + /// buf.bytes_mut()[1..3].copy_from_slice(b"lo"); + /// + /// buf.advance_mut(3); + /// } + /// + /// assert_eq!(5, buf.len()); + /// assert_eq!(buf, b"hello"); + /// ``` + /// + /// # Panics + /// + /// This function **may** panic if `cnt > self.remaining_mut()`. + /// + /// # Implementer notes + /// + /// It is recommended for implementations of `advance_mut` to panic if + /// `cnt > self.remaining_mut()`. If the implementation does not panic, + /// the call must behave as if `cnt == self.remaining_mut()`. + /// + /// A call with `cnt == 0` should never panic and be a no-op. + unsafe fn advance_mut(&mut self, cnt: usize); + + /// Returns true if there is space in `self` for more bytes. + /// + /// This is equivalent to `self.remaining_mut() != 0`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// use std::io::Cursor; + /// + /// let mut dst = [0; 5]; + /// let mut buf = Cursor::new(&mut dst); + /// + /// assert!(buf.has_remaining_mut()); + /// + /// buf.put("hello"); + /// + /// assert!(!buf.has_remaining_mut()); + /// ``` + fn has_remaining_mut(&self) -> bool { + self.remaining_mut() > 0 + } + + /// Returns a mutable slice starting at the current BufMut position and of + /// length between 0 and `BufMut::remaining_mut()`. Note that this *can* be shorter than the + /// whole remainder of the buffer (this allows non-continuous implementation). + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// The returned byte slice may represent uninitialized memory. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = Vec::with_capacity(16); + /// + /// unsafe { + /// buf.bytes_mut()[0] = b'h'; + /// buf.bytes_mut()[1] = b'e'; + /// + /// buf.advance_mut(2); + /// + /// buf.bytes_mut()[0] = b'l'; + /// buf.bytes_mut()[1..3].copy_from_slice(b"lo"); + /// + /// buf.advance_mut(3); + /// } + /// + /// assert_eq!(5, buf.len()); + /// assert_eq!(buf, b"hello"); + /// ``` + /// + /// # Implementer notes + /// + /// This function should never panic. `bytes_mut` should return an empty + /// slice **if and only if** `remaining_mut` returns 0. In other words, + /// `bytes_mut` returning an empty slice implies that `remaining_mut` will + /// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will + /// return an empty slice. + unsafe fn bytes_mut(&mut self) -> &mut [u8]; + + /// Fills `dst` with potentially multiple mutable slices starting at `self`'s + /// current position. + /// + /// If the `BufMut` is backed by disjoint slices of bytes, `bytes_vec_mut` + /// enables fetching more than one slice at once. `dst` is a slice of + /// mutable `IoVec` references, enabling the slice to be directly used with + /// [`readv`] without any further conversion. The sum of the lengths of all + /// the buffers in `dst` will be less than or equal to + /// `Buf::remaining_mut()`. + /// + /// The entries in `dst` will be overwritten, but the data **contained** by + /// the slices **will not** be modified. If `bytes_vec_mut` does not fill every + /// entry in `dst`, then `dst` is guaranteed to contain all remaining slices + /// in `self. + /// + /// This is a lower level function. Most operations are done with other + /// functions. + /// + /// # Implementer notes + /// + /// This function should never panic. Once the end of the buffer is reached, + /// i.e., `BufMut::remaining_mut` returns 0, calls to `bytes_vec_mut` must + /// return 0 without mutating `dst`. + /// + /// Implementations should also take care to properly handle being called + /// with `dst` being a zero length slice. + /// + /// [`readv`]: http://man7.org/linux/man-pages/man2/readv.2.html + unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { + if dst.is_empty() { + return 0; + } + + if self.has_remaining_mut() { + dst[0] = self.bytes_mut().into(); + 1 + } else { + 0 + } + } + + /// Transfer bytes into `self` from `src` and advance the cursor by the + /// number of bytes written. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// + /// buf.put(b'h'); + /// buf.put(&b"ello"[..]); + /// buf.put(" world"); + /// + /// assert_eq!(buf, b"hello world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `self` does not have enough capacity to contain `src`. + fn put(&mut self, src: T) where Self: Sized { + use super::Buf; + + let mut src = src.into_buf(); + + assert!(self.remaining_mut() >= src.remaining()); + + while src.has_remaining() { + let l; + + unsafe { + let s = src.bytes(); + let d = self.bytes_mut(); + l = cmp::min(s.len(), d.len()); + + ptr::copy_nonoverlapping( + s.as_ptr(), + d.as_mut_ptr(), + l); + } + + src.advance(l); + unsafe { self.advance_mut(l); } + } + } + + /// Transfer bytes into `self` from `src` and advance the cursor by the + /// number of bytes written. + /// + /// `self` must have enough remaining capacity to contain all of `src`. + /// + /// ``` + /// use bytes::BufMut; + /// use std::io::Cursor; + /// + /// let mut dst = [0; 6]; + /// + /// { + /// let mut buf = Cursor::new(&mut dst); + /// buf.put_slice(b"hello"); + /// + /// assert_eq!(1, buf.remaining_mut()); + /// } + /// + /// assert_eq!(b"hello\0", &dst); + /// ``` + fn put_slice(&mut self, src: &[u8]) { + let mut off = 0; + + assert!(self.remaining_mut() >= src.len(), "buffer overflow"); + + while off < src.len() { + let cnt; + + unsafe { + let dst = self.bytes_mut(); + cnt = cmp::min(dst.len(), src.len() - off); + + ptr::copy_nonoverlapping( + src[off..].as_ptr(), + dst.as_mut_ptr(), + cnt); + + off += cnt; + + } + + unsafe { self.advance_mut(cnt); } + } + } + + /// Writes an unsigned 8 bit integer to `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u8(0x01); + /// assert_eq!(buf, b"\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u8(&mut self, n: u8) { + let src = [n]; + self.put_slice(&src); + } + + /// Writes a signed 8 bit integer to `self`. + /// + /// The current position is advanced by 1. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i8(0x01); + /// assert_eq!(buf, b"\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i8(&mut self, n: i8) { + let src = [n as u8]; + self.put_slice(&src) + } + + #[doc(hidden)] + #[deprecated(note="use put_u16_be or put_u16_le")] + fn put_u16(&mut self, n: u16) where Self: Sized { + let mut buf = [0; 2]; + T::write_u16(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 16 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u16_be(0x0809); + /// assert_eq!(buf, b"\x08\x09"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u16_be(&mut self, n: u16) { + let mut buf = [0; 2]; + BigEndian::write_u16(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 16 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u16_le(0x0809); + /// assert_eq!(buf, b"\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u16_le(&mut self, n: u16) { + let mut buf = [0; 2]; + LittleEndian::write_u16(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_i16_be or put_i16_le")] + fn put_i16(&mut self, n: i16) where Self: Sized { + let mut buf = [0; 2]; + T::write_i16(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 16 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i16_be(0x0809); + /// assert_eq!(buf, b"\x08\x09"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i16_be(&mut self, n: i16) { + let mut buf = [0; 2]; + BigEndian::write_i16(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 16 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 2. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i16_le(0x0809); + /// assert_eq!(buf, b"\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i16_le(&mut self, n: i16) { + let mut buf = [0; 2]; + LittleEndian::write_i16(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_u32_be or put_u32_le")] + fn put_u32(&mut self, n: u32) where Self: Sized { + let mut buf = [0; 4]; + T::write_u32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 32 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u32_be(0x0809A0A1); + /// assert_eq!(buf, b"\x08\x09\xA0\xA1"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u32_be(&mut self, n: u32) { + let mut buf = [0; 4]; + BigEndian::write_u32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 32 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u32_le(0x0809A0A1); + /// assert_eq!(buf, b"\xA1\xA0\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u32_le(&mut self, n: u32) { + let mut buf = [0; 4]; + LittleEndian::write_u32(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_i32_be or put_i32_le")] + fn put_i32(&mut self, n: i32) where Self: Sized { + let mut buf = [0; 4]; + T::write_i32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 32 bit integer to `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i32_be(0x0809A0A1); + /// assert_eq!(buf, b"\x08\x09\xA0\xA1"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i32_be(&mut self, n: i32) { + let mut buf = [0; 4]; + BigEndian::write_i32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 32 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i32_le(0x0809A0A1); + /// assert_eq!(buf, b"\xA1\xA0\x09\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i32_le(&mut self, n: i32) { + let mut buf = [0; 4]; + LittleEndian::write_i32(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_u64_be or put_u64_le")] + fn put_u64(&mut self, n: u64) where Self: Sized { + let mut buf = [0; 8]; + T::write_u64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 64 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u64_be(0x0102030405060708); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u64_be(&mut self, n: u64) { + let mut buf = [0; 8]; + BigEndian::write_u64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 64 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u64_le(0x0102030405060708); + /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_u64_le(&mut self, n: u64) { + let mut buf = [0; 8]; + LittleEndian::write_u64(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_i64_be or put_i64_le")] + fn put_i64(&mut self, n: i64) where Self: Sized { + let mut buf = [0; 8]; + T::write_i64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 64 bit integer to `self` in the big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i64_be(0x0102030405060708); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i64_be(&mut self, n: i64) { + let mut buf = [0; 8]; + BigEndian::write_i64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 64 bit integer to `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i64_le(0x0102030405060708); + /// assert_eq!(buf, b"\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_i64_le(&mut self, n: i64) { + let mut buf = [0; 8]; + LittleEndian::write_i64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 128 bit integer to `self` in the big-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u128_be(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + #[cfg(feature = "i128")] + fn put_u128_be(&mut self, n: u128) { + let mut buf = [0; 16]; + BigEndian::write_u128(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an unsigned 128 bit integer to `self` in little-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_u128_le(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + #[cfg(feature = "i128")] + fn put_u128_le(&mut self, n: u128) { + let mut buf = [0; 16]; + LittleEndian::write_u128(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 128 bit integer to `self` in the big-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i128_be(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + #[cfg(feature = "i128")] + fn put_i128_be(&mut self, n: i128) { + let mut buf = [0; 16]; + BigEndian::write_i128(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes a signed 128 bit integer to `self` in little-endian byte order. + /// + /// **NOTE:** This method requires the `i128` feature. + /// The current position is advanced by 16. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_i128_le(0x01020304050607080910111213141516); + /// assert_eq!(buf, b"\x16\x15\x14\x13\x12\x11\x10\x09\x08\x07\x06\x05\x04\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + #[cfg(feature = "i128")] + fn put_i128_le(&mut self, n: i128) { + let mut buf = [0; 16]; + LittleEndian::write_i128(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_uint_be or put_uint_le")] + fn put_uint(&mut self, n: u64, nbytes: usize) where Self: Sized { + let mut buf = [0; 8]; + T::write_uint(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + /// Writes an unsigned n-byte integer to `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_uint_be(0x010203, 3); + /// assert_eq!(buf, b"\x01\x02\x03"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_uint_be(&mut self, n: u64, nbytes: usize) { + let mut buf = [0; 8]; + BigEndian::write_uint(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + /// Writes an unsigned n-byte integer to `self` in the little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_uint_le(0x010203, 3); + /// assert_eq!(buf, b"\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_uint_le(&mut self, n: u64, nbytes: usize) { + let mut buf = [0; 8]; + LittleEndian::write_uint(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + #[doc(hidden)] + #[deprecated(note="use put_int_be or put_int_le")] + fn put_int(&mut self, n: i64, nbytes: usize) where Self: Sized { + let mut buf = [0; 8]; + T::write_int(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + /// Writes a signed n-byte integer to `self` in big-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_int_be(0x010203, 3); + /// assert_eq!(buf, b"\x01\x02\x03"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_int_be(&mut self, n: i64, nbytes: usize) { + let mut buf = [0; 8]; + BigEndian::write_int(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + /// Writes a signed n-byte integer to `self` in little-endian byte order. + /// + /// The current position is advanced by `nbytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_int_le(0x010203, 3); + /// assert_eq!(buf, b"\x03\x02\x01"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_int_le(&mut self, n: i64, nbytes: usize) { + let mut buf = [0; 8]; + LittleEndian::write_int(&mut buf, n, nbytes); + self.put_slice(&buf[0..nbytes]) + } + + #[doc(hidden)] + #[deprecated(note="use put_f32_be or put_f32_le")] + fn put_f32(&mut self, n: f32) where Self: Sized { + let mut buf = [0; 4]; + T::write_f32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an IEEE754 single-precision (4 bytes) floating point number to + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f32_be(1.2f32); + /// assert_eq!(buf, b"\x3F\x99\x99\x9A"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f32_be(&mut self, n: f32) { + let mut buf = [0; 4]; + BigEndian::write_f32(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an IEEE754 single-precision (4 bytes) floating point number to + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 4. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f32_le(1.2f32); + /// assert_eq!(buf, b"\x9A\x99\x99\x3F"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f32_le(&mut self, n: f32) { + let mut buf = [0; 4]; + LittleEndian::write_f32(&mut buf, n); + self.put_slice(&buf) + } + + #[doc(hidden)] + #[deprecated(note="use put_f64_be or put_f64_le")] + fn put_f64(&mut self, n: f64) where Self: Sized { + let mut buf = [0; 8]; + T::write_f64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an IEEE754 double-precision (8 bytes) floating point number to + /// `self` in big-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f64_be(1.2f64); + /// assert_eq!(buf, b"\x3F\xF3\x33\x33\x33\x33\x33\x33"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f64_be(&mut self, n: f64) { + let mut buf = [0; 8]; + BigEndian::write_f64(&mut buf, n); + self.put_slice(&buf) + } + + /// Writes an IEEE754 double-precision (8 bytes) floating point number to + /// `self` in little-endian byte order. + /// + /// The current position is advanced by 8. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut buf = vec![]; + /// buf.put_f64_le(1.2f64); + /// assert_eq!(buf, b"\x33\x33\x33\x33\x33\x33\xF3\x3F"); + /// ``` + /// + /// # Panics + /// + /// This function panics if there is not enough remaining capacity in + /// `self`. + fn put_f64_le(&mut self, n: f64) { + let mut buf = [0; 8]; + LittleEndian::write_f64(&mut buf, n); + self.put_slice(&buf) + } + + /// Creates a "by reference" adaptor for this instance of `BufMut`. + /// + /// The returned adapter also implements `BufMut` and will simply borrow + /// `self`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// use std::io; + /// + /// let mut buf = vec![]; + /// + /// { + /// let mut reference = buf.by_ref(); + /// + /// // Adapt reference to `std::io::Write`. + /// let mut writer = reference.writer(); + /// + /// // Use the buffer as a writter + /// io::Write::write(&mut writer, &b"hello world"[..]).unwrap(); + /// } // drop our &mut reference so that we can use `buf` again + /// + /// assert_eq!(buf, &b"hello world"[..]); + /// ``` + fn by_ref(&mut self) -> &mut Self where Self: Sized { + self + } + + /// Creates an adaptor which implements the `Write` trait for `self`. + /// + /// This function returns a new value which implements `Write` by adapting + /// the `Write` trait functions to the `BufMut` trait functions. Given that + /// `BufMut` operations are infallible, none of the `Write` functions will + /// return with `Err`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// use std::io::Write; + /// + /// let mut buf = vec![].writer(); + /// + /// let num = buf.write(&b"hello world"[..]).unwrap(); + /// assert_eq!(11, num); + /// + /// let buf = buf.into_inner(); + /// + /// assert_eq!(*buf, b"hello world"[..]); + /// ``` + fn writer(self) -> Writer where Self: Sized { + super::writer::new(self) + } +} + +impl<'a, T: BufMut + ?Sized> BufMut for &'a mut T { + fn remaining_mut(&self) -> usize { + (**self).remaining_mut() + } + + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + (**self).bytes_mut() + } + + unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { + (**self).bytes_vec_mut(dst) + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + (**self).advance_mut(cnt) + } +} + +impl BufMut for Box { + fn remaining_mut(&self) -> usize { + (**self).remaining_mut() + } + + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + (**self).bytes_mut() + } + + unsafe fn bytes_vec_mut<'b>(&'b mut self, dst: &mut [&'b mut IoVec]) -> usize { + (**self).bytes_vec_mut(dst) + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + (**self).advance_mut(cnt) + } +} + +impl + AsRef<[u8]>> BufMut for io::Cursor { + fn remaining_mut(&self) -> usize { + use Buf; + self.remaining() + } + + /// Advance the internal cursor of the BufMut + unsafe fn advance_mut(&mut self, cnt: usize) { + use Buf; + self.advance(cnt); + } + + /// Returns a mutable slice starting at the current BufMut position and of + /// length between 0 and `BufMut::remaining()`. + /// + /// The returned byte slice may represent uninitialized memory. + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + let len = self.get_ref().as_ref().len(); + let pos = self.position() as usize; + + if pos >= len { + return Default::default(); + } + + &mut (self.get_mut().as_mut())[pos..] + } +} + +impl BufMut for Vec { + #[inline] + fn remaining_mut(&self) -> usize { + usize::MAX - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let len = self.len(); + let remaining = self.capacity() - len; + if cnt > remaining { + // Reserve additional capacity, and ensure that the total length + // will not overflow usize. + self.reserve(cnt); + } + + self.set_len(len + cnt); + } + + #[inline] + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + use std::slice; + + if self.capacity() == self.len() { + self.reserve(64); // Grow the vec + } + + let cap = self.capacity(); + let len = self.len(); + + let ptr = self.as_mut_ptr(); + &mut slice::from_raw_parts_mut(ptr, cap)[len..] + } +} + +// The existance of this function makes the compiler catch if the BufMut +// trait is "object-safe" or not. +fn _assert_trait_object(_b: &BufMut) {} diff --git a/bytes/src/buf/chain.rs b/bytes/src/buf/chain.rs new file mode 100644 index 000000000..7dd44ab02 --- /dev/null +++ b/bytes/src/buf/chain.rs @@ -0,0 +1,226 @@ +use {Buf, BufMut}; +use iovec::IoVec; + +/// A `Chain` sequences two buffers. +/// +/// `Chain` is an adapter that links two underlying buffers and provides a +/// continous view across both buffers. It is able to sequence either immutable +/// buffers ([`Buf`] values) or mutable buffers ([`BufMut`] values). +/// +/// This struct is generally created by calling [`Buf::chain`]. Please see that +/// function's documentation for more detail. +/// +/// # Examples +/// +/// ``` +/// use bytes::{Bytes, Buf, IntoBuf}; +/// use bytes::buf::Chain; +/// +/// let buf = Bytes::from(&b"hello "[..]).into_buf() +/// .chain(Bytes::from(&b"world"[..])); +/// +/// let full: Bytes = buf.collect(); +/// assert_eq!(full[..], b"hello world"[..]); +/// ``` +/// +/// [`Buf::chain`]: trait.Buf.html#method.chain +/// [`Buf`]: trait.Buf.html +/// [`BufMut`]: trait.BufMut.html +#[derive(Debug)] +pub struct Chain { + a: T, + b: U, +} + +impl Chain { + /// Creates a new `Chain` sequencing the provided values. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// use bytes::buf::Chain; + /// + /// let buf = Chain::new( + /// BytesMut::with_capacity(1024), + /// BytesMut::with_capacity(1024)); + /// + /// // Use the chained buffer + /// ``` + pub fn new(a: T, b: U) -> Chain { + Chain { + a: a, + b: b, + } + } + + /// Gets a reference to the first underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let buf = Bytes::from(&b"hello"[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// assert_eq!(buf.first_ref().get_ref()[..], b"hello"[..]); + /// ``` + pub fn first_ref(&self) -> &T { + &self.a + } + + /// Gets a mutable reference to the first underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let mut buf = Bytes::from(&b"hello "[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// buf.first_mut().set_position(1); + /// + /// let full: Bytes = buf.collect(); + /// assert_eq!(full[..], b"ello world"[..]); + /// ``` + pub fn first_mut(&mut self) -> &mut T { + &mut self.a + } + + /// Gets a reference to the last underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let buf = Bytes::from(&b"hello"[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// assert_eq!(buf.last_ref().get_ref()[..], b"world"[..]); + /// ``` + pub fn last_ref(&self) -> &U { + &self.b + } + + /// Gets a mutable reference to the last underlying `Buf`. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let mut buf = Bytes::from(&b"hello "[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// buf.last_mut().set_position(1); + /// + /// let full: Bytes = buf.collect(); + /// assert_eq!(full[..], b"hello orld"[..]); + /// ``` + pub fn last_mut(&mut self) -> &mut U { + &mut self.b + } + + /// Consumes this `Chain`, returning the underlying values. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Bytes, Buf, IntoBuf}; + /// + /// let buf = Bytes::from(&b"hello"[..]).into_buf() + /// .chain(Bytes::from(&b"world"[..])); + /// + /// let (first, last) = buf.into_inner(); + /// assert_eq!(first.get_ref()[..], b"hello"[..]); + /// assert_eq!(last.get_ref()[..], b"world"[..]); + /// ``` + pub fn into_inner(self) -> (T, U) { + (self.a, self.b) + } +} + +impl Buf for Chain + where T: Buf, + U: Buf, +{ + fn remaining(&self) -> usize { + self.a.remaining() + self.b.remaining() + } + + fn bytes(&self) -> &[u8] { + if self.a.has_remaining() { + self.a.bytes() + } else { + self.b.bytes() + } + } + + fn advance(&mut self, mut cnt: usize) { + let a_rem = self.a.remaining(); + + if a_rem != 0 { + if a_rem >= cnt { + self.a.advance(cnt); + return; + } + + // Consume what is left of a + self.a.advance(a_rem); + + cnt -= a_rem; + } + + self.b.advance(cnt); + } + + fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { + let mut n = self.a.bytes_vec(dst); + n += self.b.bytes_vec(&mut dst[n..]); + n + } +} + +impl BufMut for Chain + where T: BufMut, + U: BufMut, +{ + fn remaining_mut(&self) -> usize { + self.a.remaining_mut() + self.b.remaining_mut() + } + + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + if self.a.has_remaining_mut() { + self.a.bytes_mut() + } else { + self.b.bytes_mut() + } + } + + unsafe fn advance_mut(&mut self, mut cnt: usize) { + let a_rem = self.a.remaining_mut(); + + if a_rem != 0 { + if a_rem >= cnt { + self.a.advance_mut(cnt); + return; + } + + // Consume what is left of a + self.a.advance_mut(a_rem); + + cnt -= a_rem; + } + + self.b.advance_mut(cnt); + } + + unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { + let mut n = self.a.bytes_vec_mut(dst); + n += self.b.bytes_vec_mut(&mut dst[n..]); + n + } +} diff --git a/bytes/src/buf/from_buf.rs b/bytes/src/buf/from_buf.rs new file mode 100644 index 000000000..55f5cef31 --- /dev/null +++ b/bytes/src/buf/from_buf.rs @@ -0,0 +1,117 @@ +use {Buf, BufMut, IntoBuf, Bytes, BytesMut}; + +/// Conversion from a [`Buf`] +/// +/// Implementing `FromBuf` for a type defines how it is created from a buffer. +/// This is common for types which represent byte storage of some kind. +/// +/// [`FromBuf::from_buf`] is rarely called explicitly, and it is instead used +/// through [`Buf::collect`]. See [`Buf::collect`] documentation for more examples. +/// +/// See also [`IntoBuf`]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bytes::{Bytes, IntoBuf}; +/// use bytes::buf::FromBuf; +/// +/// let buf = Bytes::from(&b"hello world"[..]).into_buf(); +/// let vec = Vec::from_buf(buf); +/// +/// assert_eq!(vec, &b"hello world"[..]); +/// ``` +/// +/// Using [`Buf::collect`] to implicitly use `FromBuf`: +/// +/// ``` +/// use bytes::{Buf, Bytes, IntoBuf}; +/// +/// let buf = Bytes::from(&b"hello world"[..]).into_buf(); +/// let vec: Vec = buf.collect(); +/// +/// assert_eq!(vec, &b"hello world"[..]); +/// ``` +/// +/// Implementing `FromBuf` for your type: +/// +/// ``` +/// use bytes::{BufMut, Bytes}; +/// use bytes::buf::{IntoBuf, FromBuf}; +/// +/// // A sample buffer, that's just a wrapper over Vec +/// struct MyBuffer(Vec); +/// +/// impl FromBuf for MyBuffer { +/// fn from_buf(buf: B) -> Self where B: IntoBuf { +/// let mut v = Vec::new(); +/// v.put(buf.into_buf()); +/// MyBuffer(v) +/// } +/// } +/// +/// // Now we can make a new buf +/// let buf = Bytes::from(&b"hello world"[..]); +/// +/// // And make a MyBuffer out of it +/// let my_buf = MyBuffer::from_buf(buf); +/// +/// assert_eq!(my_buf.0, &b"hello world"[..]); +/// ``` +/// +/// [`Buf`]: trait.Buf.html +/// [`FromBuf::from_buf`]: #method.from_buf +/// [`Buf::collect`]: trait.Buf.html#method.collect +/// [`IntoBuf`]: trait.IntoBuf.html +pub trait FromBuf { + /// Creates a value from a buffer. + /// + /// See the [type-level documentation](#) for more details. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use bytes::{Bytes, IntoBuf}; + /// use bytes::buf::FromBuf; + /// + /// let buf = Bytes::from(&b"hello world"[..]).into_buf(); + /// let vec = Vec::from_buf(buf); + /// + /// assert_eq!(vec, &b"hello world"[..]); + /// ``` + fn from_buf(buf: T) -> Self where T: IntoBuf; +} + +impl FromBuf for Vec { + fn from_buf(buf: T) -> Self + where T: IntoBuf + { + let buf = buf.into_buf(); + let mut ret = Vec::with_capacity(buf.remaining()); + ret.put(buf); + ret + } +} + +impl FromBuf for Bytes { + fn from_buf(buf: T) -> Self + where T: IntoBuf + { + BytesMut::from_buf(buf).freeze() + } +} + +impl FromBuf for BytesMut { + fn from_buf(buf: T) -> Self + where T: IntoBuf + { + let buf = buf.into_buf(); + let mut ret = BytesMut::with_capacity(buf.remaining()); + ret.put(buf); + ret + } +} diff --git a/bytes/src/buf/into_buf.rs b/bytes/src/buf/into_buf.rs new file mode 100644 index 000000000..4c3b42072 --- /dev/null +++ b/bytes/src/buf/into_buf.rs @@ -0,0 +1,146 @@ +use super::{Buf}; + +use std::io; + +/// Conversion into a `Buf` +/// +/// An `IntoBuf` implementation defines how to convert a value into a `Buf`. +/// This is common for types that represent byte storage of some kind. `IntoBuf` +/// may be implemented directly for types or on references for those types. +/// +/// # Examples +/// +/// ``` +/// use bytes::{Buf, IntoBuf, BigEndian}; +/// +/// let bytes = b"\x00\x01hello world"; +/// let mut buf = bytes.into_buf(); +/// +/// assert_eq!(1, buf.get_u16::()); +/// +/// let mut rest = [0; 11]; +/// buf.copy_to_slice(&mut rest); +/// +/// assert_eq!(b"hello world", &rest); +/// ``` +pub trait IntoBuf { + /// The `Buf` type that `self` is being converted into + type Buf: Buf; + + /// Creates a `Buf` from a value. + /// + /// # Examples + /// + /// ``` + /// use bytes::{Buf, IntoBuf, BigEndian}; + /// + /// let bytes = b"\x00\x01hello world"; + /// let mut buf = bytes.into_buf(); + /// + /// assert_eq!(1, buf.get_u16::()); + /// + /// let mut rest = [0; 11]; + /// buf.copy_to_slice(&mut rest); + /// + /// assert_eq!(b"hello world", &rest); + /// ``` + fn into_buf(self) -> Self::Buf; +} + +impl IntoBuf for T { + type Buf = Self; + + fn into_buf(self) -> Self { + self + } +} + +impl<'a> IntoBuf for &'a [u8] { + type Buf = io::Cursor<&'a [u8]>; + + fn into_buf(self) -> Self::Buf { + io::Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a mut [u8] { + type Buf = io::Cursor<&'a mut [u8]>; + + fn into_buf(self) -> Self::Buf { + io::Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a str { + type Buf = io::Cursor<&'a [u8]>; + + fn into_buf(self) -> Self::Buf { + self.as_bytes().into_buf() + } +} + +impl IntoBuf for Vec { + type Buf = io::Cursor>; + + fn into_buf(self) -> Self::Buf { + io::Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a Vec { + type Buf = io::Cursor<&'a [u8]>; + + fn into_buf(self) -> Self::Buf { + io::Cursor::new(&self[..]) + } +} + +// Kind of annoying... but this impl is required to allow passing `&'static +// [u8]` where for<'a> &'a T: IntoBuf is required. +impl<'a> IntoBuf for &'a &'static [u8] { + type Buf = io::Cursor<&'static [u8]>; + + fn into_buf(self) -> Self::Buf { + io::Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a &'static str { + type Buf = io::Cursor<&'static [u8]>; + + fn into_buf(self) -> Self::Buf { + self.as_bytes().into_buf() + } +} + +impl IntoBuf for String { + type Buf = io::Cursor>; + + fn into_buf(self) -> Self::Buf { + self.into_bytes().into_buf() + } +} + +impl<'a> IntoBuf for &'a String { + type Buf = io::Cursor<&'a [u8]>; + + fn into_buf(self) -> Self::Buf { + self.as_bytes().into_buf() + } +} + +impl IntoBuf for u8 { + type Buf = Option<[u8; 1]>; + + fn into_buf(self) -> Self::Buf { + Some([self]) + } +} + +impl IntoBuf for i8 { + type Buf = Option<[u8; 1]>; + + fn into_buf(self) -> Self::Buf { + Some([self as u8; 1]) + } +} diff --git a/bytes/src/buf/iter.rs b/bytes/src/buf/iter.rs new file mode 100644 index 000000000..9345c05b6 --- /dev/null +++ b/bytes/src/buf/iter.rs @@ -0,0 +1,116 @@ +use Buf; + +/// Iterator over the bytes contained by the buffer. +/// +/// This struct is created by the [`iter`] method on [`Buf`]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use bytes::{Buf, IntoBuf, Bytes}; +/// +/// let buf = Bytes::from(&b"abc"[..]).into_buf(); +/// let mut iter = buf.iter(); +/// +/// assert_eq!(iter.next(), Some(b'a')); +/// assert_eq!(iter.next(), Some(b'b')); +/// assert_eq!(iter.next(), Some(b'c')); +/// assert_eq!(iter.next(), None); +/// ``` +/// +/// [`iter`]: trait.Buf.html#method.iter +/// [`Buf`]: trait.Buf.html +#[derive(Debug)] +pub struct Iter { + inner: T, +} + +impl Iter { + /// Consumes this `Iter`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, IntoBuf, Bytes}; + /// + /// let buf = Bytes::from(&b"abc"[..]).into_buf(); + /// let mut iter = buf.iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// let buf = iter.into_inner(); + /// assert_eq!(2, buf.remaining()); + /// ``` + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, IntoBuf, Bytes}; + /// + /// let buf = Bytes::from(&b"abc"[..]).into_buf(); + /// let mut iter = buf.iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// assert_eq!(2, iter.get_ref().remaining()); + /// ``` + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, IntoBuf, BytesMut}; + /// + /// let buf = BytesMut::from(&b"abc"[..]).into_buf(); + /// let mut iter = buf.iter(); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// + /// iter.get_mut().set_position(0); + /// + /// assert_eq!(iter.next(), Some(b'a')); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } +} + +pub fn new(inner: T) -> Iter { + Iter { inner: inner } +} + +impl Iterator for Iter { + type Item = u8; + + fn next(&mut self) -> Option { + if !self.inner.has_remaining() { + return None; + } + + let b = self.inner.bytes()[0]; + self.inner.advance(1); + Some(b) + } + + fn size_hint(&self) -> (usize, Option) { + let rem = self.inner.remaining(); + (rem, Some(rem)) + } +} + +impl ExactSizeIterator for Iter { } diff --git a/bytes/src/buf/mod.rs b/bytes/src/buf/mod.rs new file mode 100644 index 000000000..35b4857ec --- /dev/null +++ b/bytes/src/buf/mod.rs @@ -0,0 +1,38 @@ +//! Utilities for working with buffers. +//! +//! A buffer is any structure that contains a sequence of bytes. The bytes may +//! or may not be stored in contiguous memory. This module contains traits used +//! to abstract over buffers as well as utilities for working with buffer types. +//! +//! # `Buf`, `BufMut` +//! +//! These are the two foundational traits for abstractly working with buffers. +//! They can be thought as iterators for byte structures. They offer additional +//! performance over `Iterator` by providing an API optimized for byte slices. +//! +//! See [`Buf`] and [`BufMut`] for more details. +//! +//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure) +//! [`Buf`]: trait.Buf.html +//! [`BufMut`]: trait.BufMut.html + +mod buf; +mod buf_mut; +mod from_buf; +mod chain; +mod into_buf; +mod iter; +mod reader; +mod take; +mod vec_deque; +mod writer; + +pub use self::buf::Buf; +pub use self::buf_mut::BufMut; +pub use self::from_buf::FromBuf; +pub use self::chain::Chain; +pub use self::into_buf::IntoBuf; +pub use self::iter::Iter; +pub use self::reader::Reader; +pub use self::take::Take; +pub use self::writer::Writer; diff --git a/bytes/src/buf/reader.rs b/bytes/src/buf/reader.rs new file mode 100644 index 000000000..f1154dace --- /dev/null +++ b/bytes/src/buf/reader.rs @@ -0,0 +1,97 @@ +use {Buf}; + +use std::{cmp, io}; + +/// A `Buf` adapter which implements `io::Read` for the inner value. +/// +/// This struct is generally created by calling `reader()` on `Buf`. See +/// documentation of [`reader()`](trait.Buf.html#method.reader) for more +/// details. +#[derive(Debug)] +pub struct Reader { + buf: B, +} + +pub fn new(buf: B) -> Reader { + Reader { buf: buf } +} + +impl Reader { + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::Buf; + /// use std::io::{self, Cursor}; + /// + /// let mut buf = Cursor::new(b"hello world").reader(); + /// + /// assert_eq!(0, buf.get_ref().position()); + /// ``` + pub fn get_ref(&self) -> &B { + &self.buf + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::Buf; + /// use std::io::{self, Cursor}; + /// + /// let mut buf = Cursor::new(b"hello world").reader(); + /// let mut dst = vec![]; + /// + /// buf.get_mut().set_position(2); + /// io::copy(&mut buf, &mut dst).unwrap(); + /// + /// assert_eq!(*dst, b"llo world"[..]); + /// ``` + pub fn get_mut(&mut self) -> &mut B { + &mut self.buf + } + + /// Consumes this `Reader`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::Buf; + /// use std::io::{self, Cursor}; + /// + /// let mut buf = Cursor::new(b"hello world").reader(); + /// let mut dst = vec![]; + /// + /// io::copy(&mut buf, &mut dst).unwrap(); + /// + /// let buf = buf.into_inner(); + /// assert_eq!(0, buf.remaining()); + /// ``` + pub fn into_inner(self) -> B { + self.buf + } +} + +impl io::Read for Reader { + fn read(&mut self, dst: &mut [u8]) -> io::Result { + let len = cmp::min(self.buf.remaining(), dst.len()); + + Buf::copy_to_slice(&mut self.buf, &mut dst[0..len]); + Ok(len) + } +} + +impl io::BufRead for Reader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Ok(self.buf.bytes()) + } + fn consume(&mut self, amt: usize) { + self.buf.advance(amt) + } +} diff --git a/bytes/src/buf/take.rs b/bytes/src/buf/take.rs new file mode 100644 index 000000000..a0c8ed479 --- /dev/null +++ b/bytes/src/buf/take.rs @@ -0,0 +1,155 @@ +use {Buf}; + +use std::cmp; + +/// A `Buf` adapter which limits the bytes read from an underlying buffer. +/// +/// This struct is generally created by calling `take()` on `Buf`. See +/// documentation of [`take()`](trait.Buf.html#method.take) for more details. +#[derive(Debug)] +pub struct Take { + inner: T, + limit: usize, +} + +pub fn new(inner: T, limit: usize) -> Take { + Take { + inner: inner, + limit: limit, + } +} + +impl Take { + /// Consumes this `Take`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world").take(2); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"he"[..]); + /// + /// let mut buf = buf.into_inner(); + /// + /// dst.clear(); + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"llo world"[..]); + /// ``` + pub fn into_inner(self) -> T { + self.inner + } + + /// Gets a reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world").take(2); + /// + /// assert_eq!(0, buf.get_ref().position()); + /// ``` + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying `Buf`. + /// + /// It is inadvisable to directly read from the underlying `Buf`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world").take(2); + /// let mut dst = vec![]; + /// + /// buf.get_mut().set_position(2); + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"ll"[..]); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + /// Returns the maximum number of bytes that can be read. + /// + /// # Note + /// + /// If the inner `Buf` has fewer bytes than indicated by this method then + /// that is the actual number of available bytes. + /// + /// # Examples + /// + /// ```rust + /// use bytes::Buf; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world").take(2); + /// + /// assert_eq!(2, buf.limit()); + /// assert_eq!(b'h', buf.get_u8()); + /// assert_eq!(1, buf.limit()); + /// ``` + pub fn limit(&self) -> usize { + self.limit + } + + /// Sets the maximum number of bytes that can be read. + /// + /// # Note + /// + /// If the inner `Buf` has fewer bytes than `lim` then that is the actual + /// number of available bytes. + /// + /// # Examples + /// + /// ```rust + /// use bytes::{Buf, BufMut}; + /// use std::io::Cursor; + /// + /// let mut buf = Cursor::new(b"hello world").take(2); + /// let mut dst = vec![]; + /// + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"he"[..]); + /// + /// dst.clear(); + /// + /// buf.set_limit(3); + /// dst.put(&mut buf); + /// assert_eq!(*dst, b"llo"[..]); + /// ``` + pub fn set_limit(&mut self, lim: usize) { + self.limit = lim + } +} + +impl Buf for Take { + fn remaining(&self) -> usize { + cmp::min(self.inner.remaining(), self.limit) + } + + fn bytes(&self) -> &[u8] { + let bytes = self.inner.bytes(); + &bytes[..cmp::min(bytes.len(), self.limit)] + } + + fn advance(&mut self, cnt: usize) { + assert!(cnt <= self.limit); + self.inner.advance(cnt); + self.limit -= cnt; + } +} diff --git a/bytes/src/buf/vec_deque.rs b/bytes/src/buf/vec_deque.rs new file mode 100644 index 000000000..1cd650f51 --- /dev/null +++ b/bytes/src/buf/vec_deque.rs @@ -0,0 +1,39 @@ +use std::collections::VecDeque; + +use super::Buf; + +impl Buf for VecDeque { + fn remaining(&self) -> usize { + self.len() + } + + fn bytes(&self) -> &[u8] { + let (s1, s2) = self.as_slices(); + if s1.is_empty() { + s2 + } else { + s1 + } + } + + fn advance(&mut self, cnt: usize) { + self.drain(..cnt); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hello_world() { + let mut buffer: VecDeque = VecDeque::new(); + buffer.extend(b"hello world"); + assert_eq!(11, buffer.remaining()); + assert_eq!(b"hello world", buffer.bytes()); + buffer.advance(6); + assert_eq!(b"world", buffer.bytes()); + buffer.extend(b" piece"); + assert_eq!(b"world piece" as &[u8], &buffer.collect::>()[..]); + } +} diff --git a/bytes/src/buf/writer.rs b/bytes/src/buf/writer.rs new file mode 100644 index 000000000..38a739aa6 --- /dev/null +++ b/bytes/src/buf/writer.rs @@ -0,0 +1,88 @@ +use BufMut; + +use std::{cmp, io}; + +/// A `BufMut` adapter which implements `io::Write` for the inner value. +/// +/// This struct is generally created by calling `writer()` on `BufMut`. See +/// documentation of [`writer()`](trait.BufMut.html#method.writer) for more +/// details. +#[derive(Debug)] +pub struct Writer { + buf: B, +} + +pub fn new(buf: B) -> Writer { + Writer { buf: buf } +} + +impl Writer { + /// Gets a reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::BufMut; + /// + /// let mut buf = Vec::with_capacity(1024).writer(); + /// + /// assert_eq!(1024, buf.get_ref().capacity()); + /// ``` + pub fn get_ref(&self) -> &B { + &self.buf + } + + /// Gets a mutable reference to the underlying `BufMut`. + /// + /// It is inadvisable to directly write to the underlying `BufMut`. + /// + /// # Examples + /// + /// ```rust + /// use bytes::BufMut; + /// + /// let mut buf = vec![].writer(); + /// + /// buf.get_mut().reserve(1024); + /// + /// assert_eq!(1024, buf.get_ref().capacity()); + /// ``` + pub fn get_mut(&mut self) -> &mut B { + &mut self.buf + } + + /// Consumes this `Writer`, returning the underlying value. + /// + /// # Examples + /// + /// ```rust + /// use bytes::BufMut; + /// use std::io::{self, Cursor}; + /// + /// let mut buf = vec![].writer(); + /// let mut src = Cursor::new(b"hello world"); + /// + /// io::copy(&mut src, &mut buf).unwrap(); + /// + /// let buf = buf.into_inner(); + /// assert_eq!(*buf, b"hello world"[..]); + /// ``` + pub fn into_inner(self) -> B { + self.buf + } +} + +impl io::Write for Writer { + fn write(&mut self, src: &[u8]) -> io::Result { + let n = cmp::min(self.buf.remaining_mut(), src.len()); + + self.buf.put(&src[0..n]); + Ok(n) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} diff --git a/bytes/src/bytes.rs b/bytes/src/bytes.rs new file mode 100644 index 000000000..e1559311b --- /dev/null +++ b/bytes/src/bytes.rs @@ -0,0 +1,2947 @@ +use {IntoBuf, Buf, BufMut}; +use buf::Iter; +use debug; + +use std::{cmp, fmt, mem, hash, ops, slice, ptr, usize}; +use std::borrow::{Borrow, BorrowMut}; +use std::io::Cursor; +use std::sync::atomic::{self, AtomicUsize, AtomicPtr}; +use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, AcqRel}; +use std::iter::{FromIterator, Iterator}; + +/// A reference counted contiguous slice of memory. +/// +/// `Bytes` is an efficient container for storing and operating on contiguous +/// slices of memory. It is intended for use primarily in networking code, but +/// could have applications elsewhere as well. +/// +/// `Bytes` values facilitate zero-copy network programming by allowing multiple +/// `Bytes` objects to point to the same underlying memory. This is managed by +/// using a reference count to track when the memory is no longer needed and can +/// be freed. +/// +/// ``` +/// use bytes::Bytes; +/// +/// let mut mem = Bytes::from(&b"Hello world"[..]); +/// let a = mem.slice(0, 5); +/// +/// assert_eq!(&a[..], b"Hello"); +/// +/// let b = mem.split_to(6); +/// +/// assert_eq!(&mem[..], b"world"); +/// assert_eq!(&b[..], b"Hello "); +/// ``` +/// +/// # Memory layout +/// +/// The `Bytes` struct itself is fairly small, limited to a pointer to the +/// memory and 4 `usize` fields used to track information about which segment of +/// the underlying memory the `Bytes` handle has access to. +/// +/// The memory layout looks like this: +/// +/// ```text +/// +-------+ +/// | Bytes | +/// +-------+ +/// / \_____ +/// | \ +/// v v +/// +-----+------------------------------------+ +/// | Arc | | Data | | +/// +-----+------------------------------------+ +/// ``` +/// +/// `Bytes` keeps both a pointer to the shared `Arc` containing the full memory +/// slice and a pointer to the start of the region visible by the handle. +/// `Bytes` also tracks the length of its view into the memory. +/// +/// # Sharing +/// +/// The memory itself is reference counted, and multiple `Bytes` objects may +/// point to the same region. Each `Bytes` handle point to different sections within +/// the memory region, and `Bytes` handle may or may not have overlapping views +/// into the memory. +/// +/// +/// ```text +/// +/// Arc ptrs +---------+ +/// ________________________ / | Bytes 2 | +/// / +---------+ +/// / +-----------+ | | +/// |_________/ | Bytes 1 | | | +/// | +-----------+ | | +/// | | | ___/ data | tail +/// | data | tail |/ | +/// v v v v +/// +-----+---------------------------------+-----+ +/// | Arc | | | | | +/// +-----+---------------------------------+-----+ +/// ``` +/// +/// # Mutating +/// +/// While `Bytes` handles may potentially represent overlapping views of the +/// underlying memory slice and may not be mutated, `BytesMut` handles are +/// guaranteed to be the only handle able to view that slice of memory. As such, +/// `BytesMut` handles are able to mutate the underlying memory. Note that +/// holding a unique view to a region of memory does not mean that there are no +/// other `Bytes` and `BytesMut` handles with disjoint views of the underlying +/// memory. +/// +/// # Inline bytes +/// +/// As an optimization, when the slice referenced by a `Bytes` or `BytesMut` +/// handle is small enough [^1], `with_capacity` will avoid the allocation by +/// inlining the slice directly in the handle. In this case, a clone is no +/// longer "shallow" and the data will be copied. Converting from a `Vec` will +/// never use inlining. +/// +/// [^1]: Small enough: 31 bytes on 64 bit systems, 15 on 32 bit systems. +/// +pub struct Bytes { + inner: Inner, +} + +/// A unique reference to a contiguous slice of memory. +/// +/// `BytesMut` represents a unique view into a potentially shared memory region. +/// Given the uniqueness guarantee, owners of `BytesMut` handles are able to +/// mutate the memory. It is similar to a `Vec` but with less copies and +/// allocations. +/// +/// For more detail, see [Bytes](struct.Bytes.html). +/// +/// # Growth +/// +/// One key difference from `Vec` is that most operations **do not +/// implicitly grow the buffer**. This means that calling `my_bytes.put("hello +/// world");` could panic if `my_bytes` does not have enough capacity. Before +/// writing to the buffer, ensure that there is enough remaining capacity by +/// calling `my_bytes.remaining_mut()`. In general, avoiding calls to `reserve` +/// is preferable. +/// +/// The only exception is `extend` which implicitly reserves required capacity. +/// +/// # Examples +/// +/// ``` +/// use bytes::{BytesMut, BufMut}; +/// +/// let mut buf = BytesMut::with_capacity(64); +/// +/// buf.put(b'h'); +/// buf.put(b'e'); +/// buf.put("llo"); +/// +/// assert_eq!(&buf[..], b"hello"); +/// +/// // Freeze the buffer so that it can be shared +/// let a = buf.freeze(); +/// +/// // This does not allocate, instead `b` points to the same memory. +/// let b = a.clone(); +/// +/// assert_eq!(&a[..], b"hello"); +/// assert_eq!(&b[..], b"hello"); +/// ``` +pub struct BytesMut { + inner: Inner, +} + +// Both `Bytes` and `BytesMut` are backed by `Inner` and functions are delegated +// to `Inner` functions. The `Bytes` and `BytesMut` shims ensure that functions +// that mutate the underlying buffer are only performed when the data range +// being mutated is only available via a single `BytesMut` handle. +// +// # Data storage modes +// +// The goal of `bytes` is to be as efficient as possible across a wide range of +// potential usage patterns. As such, `bytes` needs to be able to handle buffers +// that are never shared, shared on a single thread, and shared across many +// threads. `bytes` also needs to handle both tiny buffers as well as very large +// buffers. For example, [Cassandra](http://cassandra.apache.org) values have +// been known to be in the hundreds of megabyte, and HTTP header values can be a +// few characters in size. +// +// To achieve high performance in these various situations, `Bytes` and +// `BytesMut` use different strategies for storing the buffer depending on the +// usage pattern. +// +// ## Delayed `Arc` allocation +// +// When a `Bytes` or `BytesMut` is first created, there is only one outstanding +// handle referencing the buffer. Since sharing is not yet required, an `Arc`* is +// not used and the buffer is backed by a `Vec` directly. Using an +// `Arc>` requires two allocations, so if the buffer ends up never being +// shared, that allocation is avoided. +// +// When sharing does become necessary (`clone`, `split_to`, `split_off`), that +// is when the buffer is promoted to being shareable. The `Vec` is moved +// into an `Arc` and both the original handle and the new handle use the same +// buffer via the `Arc`. +// +// * `Arc` is being used to signify an atomically reference counted cell. We +// don't use the `Arc` implementation provided by `std` and instead use our own. +// This ends up simplifying a number of the `unsafe` code snippets. +// +// ## Inlining small buffers +// +// The `Bytes` / `BytesMut` structs require 4 pointer sized fields. On 64 bit +// systems, this ends up being 32 bytes, which is actually a lot of storage for +// cases where `Bytes` is being used to represent small byte strings, such as +// HTTP header names and values. +// +// To avoid any allocation at all in these cases, `Bytes` will use the struct +// itself for storing the buffer, reserving 1 byte for meta data. This means +// that, on 64 bit systems, 31 byte buffers require no allocation at all. +// +// The byte used for metadata stores a 2 bits flag used to indicate that the +// buffer is stored inline as well as 6 bits for tracking the buffer length (the +// return value of `Bytes::len`). +// +// ## Static buffers +// +// `Bytes` can also represent a static buffer, which is created with +// `Bytes::from_static`. No copying or allocations are required for tracking +// static buffers. The pointer to the `&'static [u8]`, the length, and a flag +// tracking that the `Bytes` instance represents a static buffer is stored in +// the `Bytes` struct. +// +// # Struct layout +// +// Both `Bytes` and `BytesMut` are wrappers around `Inner`, which provides the +// data fields as well as all of the function implementations. +// +// The `Inner` struct is carefully laid out in order to support the +// functionality described above as well as being as small as possible. Size is +// important as growing the size of the `Bytes` struct from 32 bytes to 40 bytes +// added as much as 15% overhead in benchmarks using `Bytes` in an HTTP header +// map structure. +// +// The `Inner` struct contains the following fields: +// +// * `ptr: *mut u8` +// * `len: usize` +// * `cap: usize` +// * `arc: AtomicPtr` +// +// ## `ptr: *mut u8` +// +// A pointer to start of the handle's buffer view. When backed by a `Vec`, +// this is always the `Vec`'s pointer. When backed by an `Arc>`, `ptr` +// may have been shifted to point somewhere inside the buffer. +// +// When in "inlined" mode, `ptr` is used as part of the inlined buffer. +// +// ## `len: usize` +// +// The length of the handle's buffer view. When backed by a `Vec`, this is +// always the `Vec`'s length. The slice represented by `ptr` and `len` should +// (ideally) always be initialized memory. +// +// When in "inlined" mode, `len` is used as part of the inlined buffer. +// +// ## `cap: usize` +// +// The capacity of the handle's buffer view. When backed by a `Vec`, this is +// always the `Vec`'s capacity. The slice represented by `ptr+len` and `cap-len` +// may or may not be initialized memory. +// +// When in "inlined" mode, `cap` is used as part of the inlined buffer. +// +// ## `arc: AtomicPtr` +// +// When `Inner` is in allocated mode (backed by Vec or Arc>), this +// will be the pointer to the `Arc` structure tracking the ref count for the +// underlying buffer. When the pointer is null, then the `Arc` has not been +// allocated yet and `self` is the only outstanding handle for the underlying +// buffer. +// +// The lower two bits of `arc` are used to track the storage mode of `Inner`. +// `0b01` indicates inline storage, `0b10` indicates static storage, and `0b11` +// indicates vector storage, not yet promoted to Arc. Since pointers to +// allocated structures are aligned, the lower two bits of a pointer will always +// be 0. This allows disambiguating between a pointer and the two flags. +// +// When in "inlined" mode, the least significant byte of `arc` is also used to +// store the length of the buffer view (vs. the capacity, which is a constant). +// +// The rest of `arc`'s bytes are used as part of the inline buffer, which means +// that those bytes need to be located next to the `ptr`, `len`, and `cap` +// fields, which make up the rest of the inline buffer. This requires special +// casing the layout of `Inner` depending on if the target platform is big or +// little endian. +// +// On little endian platforms, the `arc` field must be the first field in the +// struct. On big endian platforms, the `arc` field must be the last field in +// the struct. Since a deterministic struct layout is required, `Inner` is +// annotated with `#[repr(C)]`. +// +// # Thread safety +// +// `Bytes::clone()` returns a new `Bytes` handle with no copying. This is done +// by bumping the buffer ref count and returning a new struct pointing to the +// same buffer. However, the `Arc` structure is lazily allocated. This means +// that if `Bytes` is stored itself in an `Arc` (`Arc`), the `clone` +// function can be called concurrently from multiple threads. This is why an +// `AtomicPtr` is used for the `arc` field vs. a `*const`. +// +// Care is taken to ensure that the need for synchronization is minimized. Most +// operations do not require any synchronization. +// +#[cfg(target_endian = "little")] +#[repr(C)] +struct Inner { + // WARNING: Do not access the fields directly unless you know what you are + // doing. Instead, use the fns. See implementation comment above. + arc: AtomicPtr, + ptr: *mut u8, + len: usize, + cap: usize, +} + +#[cfg(target_endian = "big")] +#[repr(C)] +struct Inner { + // WARNING: Do not access the fields directly unless you know what you are + // doing. Instead, use the fns. See implementation comment above. + ptr: *mut u8, + len: usize, + cap: usize, + arc: AtomicPtr, +} + +// Thread-safe reference-counted container for the shared storage. This mostly +// the same as `std::sync::Arc` but without the weak counter. The ref counting +// fns are based on the ones found in `std`. +// +// The main reason to use `Shared` instead of `std::sync::Arc` is that it ends +// up making the overall code simpler and easier to reason about. This is due to +// some of the logic around setting `Inner::arc` and other ways the `arc` field +// is used. Using `Arc` ended up requiring a number of funky transmutes and +// other shenanigans to make it work. +struct Shared { + vec: Vec, + original_capacity_repr: usize, + ref_count: AtomicUsize, +} + +// Buffer storage strategy flags. +const KIND_ARC: usize = 0b00; +const KIND_INLINE: usize = 0b01; +const KIND_STATIC: usize = 0b10; +const KIND_VEC: usize = 0b11; +const KIND_MASK: usize = 0b11; + +// The max original capacity value. Any `Bytes` allocated with a greater initial +// capacity will default to this. +const MAX_ORIGINAL_CAPACITY_WIDTH: usize = 17; +// The original capacity algorithm will not take effect unless the originally +// allocated capacity was at least 1kb in size. +const MIN_ORIGINAL_CAPACITY_WIDTH: usize = 10; +// The original capacity is stored in powers of 2 starting at 1kb to a max of +// 64kb. Representing it as such requires only 3 bits of storage. +const ORIGINAL_CAPACITY_MASK: usize = 0b11100; +const ORIGINAL_CAPACITY_OFFSET: usize = 2; + +// When the storage is in the `Vec` representation, the pointer can be advanced +// at most this value. This is due to the amount of storage available to track +// the offset is usize - number of KIND bits and number of ORIGINAL_CAPACITY +// bits. +const VEC_POS_OFFSET: usize = 5; +const MAX_VEC_POS: usize = usize::MAX >> VEC_POS_OFFSET; +const NOT_VEC_POS_MASK: usize = 0b11111; + +// Bit op constants for extracting the inline length value from the `arc` field. +const INLINE_LEN_MASK: usize = 0b11111100; +const INLINE_LEN_OFFSET: usize = 2; + +// Byte offset from the start of `Inner` to where the inline buffer data +// starts. On little endian platforms, the first byte of the struct is the +// storage flag, so the data is shifted by a byte. On big endian systems, the +// data starts at the beginning of the struct. +#[cfg(target_endian = "little")] +const INLINE_DATA_OFFSET: isize = 1; +#[cfg(target_endian = "big")] +const INLINE_DATA_OFFSET: isize = 0; + +#[cfg(target_pointer_width = "64")] +const PTR_WIDTH: usize = 64; +#[cfg(target_pointer_width = "32")] +const PTR_WIDTH: usize = 32; + +// Inline buffer capacity. This is the size of `Inner` minus 1 byte for the +// metadata. +#[cfg(target_pointer_width = "64")] +const INLINE_CAP: usize = 4 * 8 - 1; +#[cfg(target_pointer_width = "32")] +const INLINE_CAP: usize = 4 * 4 - 1; + +/* + * + * ===== Bytes ===== + * + */ + +impl Bytes { + /// Creates a new `Bytes` with the specified capacity. + /// + /// The returned `Bytes` will be able to hold at least `capacity` bytes + /// without reallocating. If `capacity` is under `4 * size_of::() - 1`, + /// then `BytesMut` will not allocate. + /// + /// It is important to note that this function does not specify the length + /// of the returned `Bytes`, but only the capacity. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut bytes = Bytes::with_capacity(64); + /// + /// // `bytes` contains no data, even though there is capacity + /// assert_eq!(bytes.len(), 0); + /// + /// bytes.extend_from_slice(&b"hello world"[..]); + /// + /// assert_eq!(&bytes[..], b"hello world"); + /// ``` + #[inline] + pub fn with_capacity(capacity: usize) -> Bytes { + Bytes { + inner: Inner::with_capacity(capacity), + } + } + + /// Creates a new empty `Bytes`. + /// + /// This will not allocate and the returned `Bytes` handle will be empty. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::new(); + /// assert_eq!(&b[..], b""); + /// ``` + #[inline] + pub fn new() -> Bytes { + Bytes::with_capacity(0) + } + + /// Creates a new `Bytes` from a static slice. + /// + /// The returned `Bytes` will point directly to the static slice. There is + /// no allocating or copying. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::from_static(b"hello"); + /// assert_eq!(&b[..], b"hello"); + /// ``` + #[inline] + pub fn from_static(bytes: &'static [u8]) -> Bytes { + Bytes { + inner: Inner::from_static(bytes), + } + } + + /// Returns the number of bytes contained in this `Bytes`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::from(&b"hello"[..]); + /// assert_eq!(b.len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + /// Returns true if the `Bytes` has a length of 0. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let b = Bytes::new(); + /// assert!(b.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Returns a slice of self for the index range `[begin..end)`. + /// + /// This will increment the reference count for the underlying memory and + /// return a new `Bytes` handle set to the slice. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let a = Bytes::from(&b"hello world"[..]); + /// let b = a.slice(2, 5); + /// + /// assert_eq!(&b[..], b"llo"); + /// ``` + /// + /// # Panics + /// + /// Requires that `begin <= end` and `end <= self.len()`, otherwise slicing + /// will panic. + pub fn slice(&self, begin: usize, end: usize) -> Bytes { + assert!(begin <= end); + assert!(end <= self.len()); + + if end - begin <= INLINE_CAP { + return Bytes::from(&self[begin..end]); + } + + let mut ret = self.clone(); + + unsafe { + ret.inner.set_end(end); + ret.inner.set_start(begin); + } + + ret + } + + /// Returns a slice of self for the index range `[begin..self.len())`. + /// + /// This will increment the reference count for the underlying memory and + /// return a new `Bytes` handle set to the slice. + /// + /// This operation is `O(1)` and is equivalent to `self.slice(begin, + /// self.len())`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let a = Bytes::from(&b"hello world"[..]); + /// let b = a.slice_from(6); + /// + /// assert_eq!(&b[..], b"world"); + /// ``` + /// + /// # Panics + /// + /// Requires that `begin <= self.len()`, otherwise slicing will panic. + pub fn slice_from(&self, begin: usize) -> Bytes { + self.slice(begin, self.len()) + } + + /// Returns a slice of self for the index range `[0..end)`. + /// + /// This will increment the reference count for the underlying memory and + /// return a new `Bytes` handle set to the slice. + /// + /// This operation is `O(1)` and is equivalent to `self.slice(0, end)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let a = Bytes::from(&b"hello world"[..]); + /// let b = a.slice_to(5); + /// + /// assert_eq!(&b[..], b"hello"); + /// ``` + /// + /// # Panics + /// + /// Requires that `end <= self.len()`, otherwise slicing will panic. + pub fn slice_to(&self, end: usize) -> Bytes { + self.slice(0, end) + } + + /// Returns a slice of self that is equivalent to the given `subset`. + /// + /// When processing a `Bytes` buffer with other tools, one often gets a + /// `&[u8]` which is in fact a slice of the `Bytes`, i.e. a subset of it. + /// This function turns that `&[u8]` into another `Bytes`, as if one had + /// called `self.slice()` with the offsets that correspond to `subset`. + /// + /// This operation is `O(1)`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let bytes = Bytes::from(&b"012345678"[..]); + /// let as_slice = bytes.as_ref(); + /// let subset = &as_slice[2..6]; + /// let subslice = bytes.slice_ref(&subset); + /// assert_eq!(&subslice[..], b"2345"); + /// ``` + /// + /// # Panics + /// + /// Requires that the given `sub` slice is in fact contained within the + /// `Bytes` buffer; otherwise this function will panic. + pub fn slice_ref(&self, subset: &[u8]) -> Bytes { + let bytes_p = self.as_ptr() as usize; + let bytes_len = self.len(); + + let sub_p = subset.as_ptr() as usize; + let sub_len = subset.len(); + + assert!(sub_p >= bytes_p); + assert!(sub_p + sub_len <= bytes_p + bytes_len); + + let sub_offset = sub_p - bytes_p; + + self.slice(sub_offset, sub_offset + sub_len) + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[0, at)`, and the returned `Bytes` + /// contains elements `[at, len)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut a = Bytes::from(&b"hello world"[..]); + /// let b = a.split_off(5); + /// + /// assert_eq!(&a[..], b"hello"); + /// assert_eq!(&b[..], b" world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + pub fn split_off(&mut self, at: usize) -> Bytes { + assert!(at <= self.len()); + + if at == self.len() { + return Bytes::new(); + } + + if at == 0 { + return mem::replace(self, Bytes::new()); + } + + Bytes { + inner: self.inner.split_off(at), + } + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[at, len)`, and the returned + /// `Bytes` contains elements `[0, at)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut a = Bytes::from(&b"hello world"[..]); + /// let b = a.split_to(5); + /// + /// assert_eq!(&a[..], b" world"); + /// assert_eq!(&b[..], b"hello"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + pub fn split_to(&mut self, at: usize) -> Bytes { + assert!(at <= self.len()); + + if at == self.len() { + return mem::replace(self, Bytes::new()); + } + + if at == 0 { + return Bytes::new(); + } + + Bytes { + inner: self.inner.split_to(at), + } + } + + #[deprecated(since = "0.4.1", note = "use split_to instead")] + #[doc(hidden)] + pub fn drain_to(&mut self, at: usize) -> Bytes { + self.split_to(at) + } + + /// Shortens the buffer, keeping the first `len` bytes and dropping the + /// rest. + /// + /// If `len` is greater than the buffer's current length, this has no + /// effect. + /// + /// The [`split_off`] method can emulate `truncate`, but this causes the + /// excess bytes to be returned instead of dropped. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::from(&b"hello world"[..]); + /// buf.truncate(5); + /// assert_eq!(buf, b"hello"[..]); + /// ``` + /// + /// [`split_off`]: #method.split_off + pub fn truncate(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Shortens the buffer, dropping the first `cnt` bytes and keeping the + /// rest. + /// + /// This is the same function as `Buf::advance`, and in the next breaking + /// release of `bytes`, this implementation will be removed in favor of + /// having `Bytes` implement `Buf`. + /// + /// # Panics + /// + /// This function panics if `cnt` is greater than `self.len()` + #[inline] + pub fn advance(&mut self, cnt: usize) { + assert!(cnt <= self.len(), "cannot advance past `remaining`"); + unsafe { self.inner.set_start(cnt); } + } + + /// Clears the buffer, removing all data. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::from(&b"hello world"[..]); + /// buf.clear(); + /// assert!(buf.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.truncate(0); + } + + /// Attempts to convert into a `BytesMut` handle. + /// + /// This will only succeed if there are no other outstanding references to + /// the underlying chunk of memory. `Bytes` handles that contain inlined + /// bytes will always be convertable to `BytesMut`. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let a = Bytes::from(&b"Mary had a little lamb, little lamb, little lamb..."[..]); + /// + /// // Create a shallow clone + /// let b = a.clone(); + /// + /// // This will fail because `b` shares a reference with `a` + /// let a = a.try_mut().unwrap_err(); + /// + /// drop(b); + /// + /// // This will succeed + /// let mut a = a.try_mut().unwrap(); + /// + /// a[0] = b'b'; + /// + /// assert_eq!(&a[..4], b"bary"); + /// ``` + pub fn try_mut(mut self) -> Result { + if self.inner.is_mut_safe() { + Ok(BytesMut { inner: self.inner }) + } else { + Err(self) + } + } + + /// Appends given bytes to this object. + /// + /// If this `Bytes` object has not enough capacity, it is resized first. + /// If it is shared (`refcount > 1`), it is copied first. + /// + /// This operation can be less effective than the similar operation on + /// `BytesMut`, especially on small additions. + /// + /// # Examples + /// + /// ``` + /// use bytes::Bytes; + /// + /// let mut buf = Bytes::from("aabb"); + /// buf.extend_from_slice(b"ccdd"); + /// buf.extend_from_slice(b"eeff"); + /// + /// assert_eq!(b"aabbccddeeff", &buf[..]); + /// ``` + pub fn extend_from_slice(&mut self, extend: &[u8]) { + if extend.is_empty() { + return; + } + + let new_cap = self.len().checked_add(extend.len()).expect("capacity overflow"); + + let result = match mem::replace(self, Bytes::new()).try_mut() { + Ok(mut bytes_mut) => { + bytes_mut.extend_from_slice(extend); + bytes_mut + }, + Err(bytes) => { + let mut bytes_mut = BytesMut::with_capacity(new_cap); + bytes_mut.put_slice(&bytes); + bytes_mut.put_slice(extend); + bytes_mut + } + }; + + mem::replace(self, result.freeze()); + } +} + +impl IntoBuf for Bytes { + type Buf = Cursor; + + fn into_buf(self) -> Self::Buf { + Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a Bytes { + type Buf = Cursor; + + fn into_buf(self) -> Self::Buf { + Cursor::new(self) + } +} + +impl Clone for Bytes { + fn clone(&self) -> Bytes { + Bytes { + inner: unsafe { self.inner.shallow_clone(false) }, + } + } +} + +impl AsRef<[u8]> for Bytes { + #[inline] + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl ops::Deref for Bytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl From for Bytes { + fn from(src: BytesMut) -> Bytes { + src.freeze() + } +} + +impl From> for Bytes { + fn from(src: Vec) -> Bytes { + BytesMut::from(src).freeze() + } +} + +impl From for Bytes { + fn from(src: String) -> Bytes { + BytesMut::from(src).freeze() + } +} + +impl<'a> From<&'a [u8]> for Bytes { + fn from(src: &'a [u8]) -> Bytes { + BytesMut::from(src).freeze() + } +} + +impl<'a> From<&'a str> for Bytes { + fn from(src: &'a str) -> Bytes { + BytesMut::from(src).freeze() + } +} + +impl FromIterator for BytesMut { + fn from_iter>(into_iter: T) -> Self { + let iter = into_iter.into_iter(); + let (min, maybe_max) = iter.size_hint(); + + let mut out = BytesMut::with_capacity(maybe_max.unwrap_or(min)); + + for i in iter { + out.reserve(1); + out.put(i); + } + + out + } +} + +impl FromIterator for Bytes { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter).freeze() + } +} + +impl<'a> FromIterator<&'a u8> for BytesMut { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter.into_iter().map(|b| *b)) + } +} + +impl<'a> FromIterator<&'a u8> for Bytes { + fn from_iter>(into_iter: T) -> Self { + BytesMut::from_iter(into_iter).freeze() + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &Bytes) -> bool { + self.inner.as_ref() == other.inner.as_ref() + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &Bytes) -> Option { + self.inner.as_ref().partial_cmp(other.inner.as_ref()) + } +} + +impl Ord for Bytes { + fn cmp(&self, other: &Bytes) -> cmp::Ordering { + self.inner.as_ref().cmp(other.inner.as_ref()) + } +} + +impl Eq for Bytes { +} + +impl Default for Bytes { + #[inline] + fn default() -> Bytes { + Bytes::new() + } +} + +impl fmt::Debug for Bytes { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&debug::BsDebug(&self.inner.as_ref()), fmt) + } +} + +impl hash::Hash for Bytes { + fn hash(&self, state: &mut H) where H: hash::Hasher { + let s: &[u8] = self.as_ref(); + s.hash(state); + } +} + +impl Borrow<[u8]> for Bytes { + fn borrow(&self) -> &[u8] { + self.as_ref() + } +} + +impl IntoIterator for Bytes { + type Item = u8; + type IntoIter = Iter>; + + fn into_iter(self) -> Self::IntoIter { + self.into_buf().iter() + } +} + +impl<'a> IntoIterator for &'a Bytes { + type Item = u8; + type IntoIter = Iter>; + + fn into_iter(self) -> Self::IntoIter { + self.into_buf().iter() + } +} + +impl Extend for Bytes { + fn extend(&mut self, iter: T) where T: IntoIterator { + let iter = iter.into_iter(); + + let (lower, upper) = iter.size_hint(); + + // Avoid possible conversion into mut if there's nothing to add + if let Some(0) = upper { + return; + } + + let mut bytes_mut = match mem::replace(self, Bytes::new()).try_mut() { + Ok(bytes_mut) => bytes_mut, + Err(bytes) => { + let mut bytes_mut = BytesMut::with_capacity(bytes.len() + lower); + bytes_mut.put_slice(&bytes); + bytes_mut + } + }; + + bytes_mut.extend(iter); + + mem::replace(self, bytes_mut.freeze()); + } +} + +impl<'a> Extend<&'a u8> for Bytes { + fn extend(&mut self, iter: T) where T: IntoIterator { + self.extend(iter.into_iter().map(|b| *b)) + } +} + +/* + * + * ===== BytesMut ===== + * + */ + +impl BytesMut { + /// Creates a new `BytesMut` with the specified capacity. + /// + /// The returned `BytesMut` will be able to hold at least `capacity` bytes + /// without reallocating. If `capacity` is under `4 * size_of::() - 1`, + /// then `BytesMut` will not allocate. + /// + /// It is important to note that this function does not specify the length + /// of the returned `BytesMut`, but only the capacity. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut bytes = BytesMut::with_capacity(64); + /// + /// // `bytes` contains no data, even though there is capacity + /// assert_eq!(bytes.len(), 0); + /// + /// bytes.put(&b"hello world"[..]); + /// + /// assert_eq!(&bytes[..], b"hello world"); + /// ``` + #[inline] + pub fn with_capacity(capacity: usize) -> BytesMut { + BytesMut { + inner: Inner::with_capacity(capacity), + } + } + + /// Creates a new `BytesMut` with default capacity. + /// + /// Resulting object has length 0 and unspecified capacity. + /// This function does not allocate. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut bytes = BytesMut::new(); + /// + /// assert_eq!(0, bytes.len()); + /// + /// bytes.reserve(2); + /// bytes.put_slice(b"xy"); + /// + /// assert_eq!(&b"xy"[..], &bytes[..]); + /// ``` + #[inline] + pub fn new() -> BytesMut { + BytesMut::with_capacity(0) + } + + /// Returns the number of bytes contained in this `BytesMut`. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::from(&b"hello"[..]); + /// assert_eq!(b.len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.inner.len() + } + + /// Returns true if the `BytesMut` has a length of 0. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::with_capacity(64); + /// assert!(b.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of bytes the `BytesMut` can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let b = BytesMut::with_capacity(64); + /// assert_eq!(b.capacity(), 64); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + /// Converts `self` into an immutable `Bytes`. + /// + /// The conversion is zero cost and is used to indicate that the slice + /// referenced by the handle will no longer be mutated. Once the conversion + /// is done, the handle can be cloned and shared across threads. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// use std::thread; + /// + /// let mut b = BytesMut::with_capacity(64); + /// b.put("hello world"); + /// let b1 = b.freeze(); + /// let b2 = b1.clone(); + /// + /// let th = thread::spawn(move || { + /// assert_eq!(&b1[..], b"hello world"); + /// }); + /// + /// assert_eq!(&b2[..], b"hello world"); + /// th.join().unwrap(); + /// ``` + #[inline] + pub fn freeze(self) -> Bytes { + Bytes { inner: self.inner } + } + + /// Splits the bytes into two at the given index. + /// + /// Afterwards `self` contains elements `[0, at)`, and the returned + /// `BytesMut` contains elements `[at, capacity)`. + /// + /// This is an `O(1)` operation that just increases the reference count + /// and sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut a = BytesMut::from(&b"hello world"[..]); + /// let mut b = a.split_off(5); + /// + /// a[0] = b'j'; + /// b[0] = b'!'; + /// + /// assert_eq!(&a[..], b"jello"); + /// assert_eq!(&b[..], b"!world"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > capacity`. + pub fn split_off(&mut self, at: usize) -> BytesMut { + BytesMut { + inner: self.inner.split_off(at), + } + } + + /// Removes the bytes from the current view, returning them in a new + /// `BytesMut` handle. + /// + /// Afterwards, `self` will be empty, but will retain any additional + /// capacity that it had before the operation. This is identical to + /// `self.split_to(self.len())`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut buf = BytesMut::with_capacity(1024); + /// buf.put(&b"hello world"[..]); + /// + /// let other = buf.take(); + /// + /// assert!(buf.is_empty()); + /// assert_eq!(1013, buf.capacity()); + /// + /// assert_eq!(other, b"hello world"[..]); + /// ``` + pub fn take(&mut self) -> BytesMut { + let len = self.len(); + self.split_to(len) + } + + #[deprecated(since = "0.4.1", note = "use take instead")] + #[doc(hidden)] + pub fn drain(&mut self) -> BytesMut { + self.take() + } + + /// Splits the buffer into two at the given index. + /// + /// Afterwards `self` contains elements `[at, len)`, and the returned `BytesMut` + /// contains elements `[0, at)`. + /// + /// This is an `O(1)` operation that just increases the reference count and + /// sets a few indices. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut a = BytesMut::from(&b"hello world"[..]); + /// let mut b = a.split_to(5); + /// + /// a[0] = b'!'; + /// b[0] = b'j'; + /// + /// assert_eq!(&a[..], b"!world"); + /// assert_eq!(&b[..], b"jello"); + /// ``` + /// + /// # Panics + /// + /// Panics if `at > len`. + pub fn split_to(&mut self, at: usize) -> BytesMut { + BytesMut { + inner: self.inner.split_to(at), + } + } + + #[deprecated(since = "0.4.1", note = "use split_to instead")] + #[doc(hidden)] + pub fn drain_to(&mut self, at: usize) -> BytesMut { + self.split_to(at) + } + + /// Shortens the buffer, keeping the first `len` bytes and dropping the + /// rest. + /// + /// If `len` is greater than the buffer's current length, this has no + /// effect. + /// + /// The [`split_off`] method can emulate `truncate`, but this causes the + /// excess bytes to be returned instead of dropped. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello world"[..]); + /// buf.truncate(5); + /// assert_eq!(buf, b"hello"[..]); + /// ``` + /// + /// [`split_off`]: #method.split_off + pub fn truncate(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Shortens the buffer, dropping the first `cnt` bytes and keeping the + /// rest. + /// + /// This is the same function as `Buf::advance`, and in the next breaking + /// release of `bytes`, this implementation will be removed in favor of + /// having `BytesMut` implement `Buf`. + /// + /// # Panics + /// + /// This function panics if `cnt` is greater than `self.len()` + #[inline] + pub fn advance(&mut self, cnt: usize) { + assert!(cnt <= self.len(), "cannot advance past `remaining`"); + unsafe { self.inner.set_start(cnt); } + } + + /// Clears the buffer, removing all data. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello world"[..]); + /// buf.clear(); + /// assert!(buf.is_empty()); + /// ``` + pub fn clear(&mut self) { + self.truncate(0); + } + + /// Resizes the buffer so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the buffer is extended by the + /// difference with each additional byte set to `value`. If `new_len` is + /// less than `len`, the buffer is simply truncated. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::new(); + /// + /// buf.resize(3, 0x1); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x1]); + /// + /// buf.resize(2, 0x2); + /// assert_eq!(&buf[..], &[0x1, 0x1]); + /// + /// buf.resize(4, 0x3); + /// assert_eq!(&buf[..], &[0x1, 0x1, 0x3, 0x3]); + /// ``` + pub fn resize(&mut self, new_len: usize, value: u8) { + self.inner.resize(new_len, value); + } + + /// Sets the length of the buffer. + /// + /// This will explicitly set the size of the buffer without actually + /// modifying the data, so it is up to the caller to ensure that the data + /// has been initialized. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut b = BytesMut::from(&b"hello world"[..]); + /// + /// unsafe { + /// b.set_len(5); + /// } + /// + /// assert_eq!(&b[..], b"hello"); + /// + /// unsafe { + /// b.set_len(11); + /// } + /// + /// assert_eq!(&b[..], b"hello world"); + /// ``` + /// + /// # Panics + /// + /// This method will panic if `len` is out of bounds for the underlying + /// slice or if it comes after the `end` of the configured window. + pub unsafe fn set_len(&mut self, len: usize) { + self.inner.set_len(len) + } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// into the given `BytesMut`. + /// + /// More than `additional` bytes may be reserved in order to avoid frequent + /// reallocations. A call to `reserve` may result in an allocation. + /// + /// Before allocating new buffer space, the function will attempt to reclaim + /// space in the existing buffer. If the current handle references a small + /// view in the original buffer and all other handles have been dropped, + /// and the requested capacity is less than or equal to the existing + /// buffer's capacity, then the current view will be copied to the front of + /// the buffer and the handle will take ownership of the full buffer. + /// + /// # Examples + /// + /// In the following example, a new buffer is allocated. + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::from(&b"hello"[..]); + /// buf.reserve(64); + /// assert!(buf.capacity() >= 69); + /// ``` + /// + /// In the following example, the existing buffer is reclaimed. + /// + /// ``` + /// use bytes::{BytesMut, BufMut}; + /// + /// let mut buf = BytesMut::with_capacity(128); + /// buf.put(&[0; 64][..]); + /// + /// let ptr = buf.as_ptr(); + /// let other = buf.take(); + /// + /// assert!(buf.is_empty()); + /// assert_eq!(buf.capacity(), 64); + /// + /// drop(other); + /// buf.reserve(128); + /// + /// assert_eq!(buf.capacity(), 128); + /// assert_eq!(buf.as_ptr(), ptr); + /// ``` + /// + /// # Panics + /// + /// Panics if the new capacity overflows `usize`. + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + /// Appends given bytes to this object. + /// + /// If this `BytesMut` object has not enough capacity, it is resized first. + /// So unlike `put_slice` operation, `extend_from_slice` does not panic. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::with_capacity(0); + /// buf.extend_from_slice(b"aaabbb"); + /// buf.extend_from_slice(b"cccddd"); + /// + /// assert_eq!(b"aaabbbcccddd", &buf[..]); + /// ``` + pub fn extend_from_slice(&mut self, extend: &[u8]) { + self.reserve(extend.len()); + self.put_slice(extend); + } + + /// Combine splitted BytesMut objects back as contiguous. + /// + /// If `BytesMut` objects were not contiguous originally, they will be extended. + /// + /// # Examples + /// + /// ``` + /// use bytes::BytesMut; + /// + /// let mut buf = BytesMut::with_capacity(64); + /// buf.extend_from_slice(b"aaabbbcccddd"); + /// + /// let splitted = buf.split_off(6); + /// assert_eq!(b"aaabbb", &buf[..]); + /// assert_eq!(b"cccddd", &splitted[..]); + /// + /// buf.unsplit(splitted); + /// assert_eq!(b"aaabbbcccddd", &buf[..]); + /// ``` + pub fn unsplit(&mut self, other: BytesMut) { + let ptr; + + if other.is_empty() { + return; + } + + if self.is_empty() { + *self = other; + return; + } + + unsafe { + ptr = self.inner.ptr.offset(self.inner.len as isize); + } + if ptr == other.inner.ptr && + self.inner.kind() == KIND_ARC && + other.inner.kind() == KIND_ARC + { + debug_assert_eq!(self.inner.arc.load(Acquire), + other.inner.arc.load(Acquire)); + // Contiguous blocks, just combine directly + self.inner.len += other.inner.len; + self.inner.cap += other.inner.cap; + } + else { + self.extend_from_slice(&other); + } + } +} + +impl BufMut for BytesMut { + #[inline] + fn remaining_mut(&self) -> usize { + self.capacity() - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let new_len = self.len() + cnt; + + // This call will panic if `cnt` is too big + self.inner.set_len(new_len); + } + + #[inline] + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + let len = self.len(); + + // This will never panic as `len` can never become invalid + &mut self.inner.as_raw()[len..] + } + + #[inline] + fn put_slice(&mut self, src: &[u8]) { + assert!(self.remaining_mut() >= src.len()); + + let len = src.len(); + + unsafe { + self.bytes_mut()[..len].copy_from_slice(src); + self.advance_mut(len); + } + } + + #[inline] + fn put_u8(&mut self, n: u8) { + self.inner.put_u8(n); + } + + #[inline] + fn put_i8(&mut self, n: i8) { + self.put_u8(n as u8); + } +} + +impl IntoBuf for BytesMut { + type Buf = Cursor; + + fn into_buf(self) -> Self::Buf { + Cursor::new(self) + } +} + +impl<'a> IntoBuf for &'a BytesMut { + type Buf = Cursor<&'a BytesMut>; + + fn into_buf(self) -> Self::Buf { + Cursor::new(self) + } +} + +impl AsRef<[u8]> for BytesMut { + #[inline] + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl ops::Deref for BytesMut { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.as_ref() + } +} + +impl AsMut<[u8]> for BytesMut { + fn as_mut(&mut self) -> &mut [u8] { + self.inner.as_mut() + } +} + +impl ops::DerefMut for BytesMut { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + self.inner.as_mut() + } +} + +impl From> for BytesMut { + fn from(src: Vec) -> BytesMut { + BytesMut { + inner: Inner::from_vec(src), + } + } +} + +impl From for BytesMut { + fn from(src: String) -> BytesMut { + BytesMut::from(src.into_bytes()) + } +} + +impl<'a> From<&'a [u8]> for BytesMut { + fn from(src: &'a [u8]) -> BytesMut { + let len = src.len(); + + if len == 0 { + BytesMut::new() + } else if len <= INLINE_CAP { + unsafe { + let mut inner: Inner = mem::uninitialized(); + + // Set inline mask + inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared); + inner.set_inline_len(len); + inner.as_raw()[0..len].copy_from_slice(src); + + BytesMut { + inner: inner, + } + } + } else { + BytesMut::from(src.to_vec()) + } + } +} + +impl<'a> From<&'a str> for BytesMut { + fn from(src: &'a str) -> BytesMut { + BytesMut::from(src.as_bytes()) + } +} + +impl From for BytesMut { + fn from(src: Bytes) -> BytesMut { + src.try_mut() + .unwrap_or_else(|src| BytesMut::from(&src[..])) + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &BytesMut) -> bool { + self.inner.as_ref() == other.inner.as_ref() + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &BytesMut) -> Option { + self.inner.as_ref().partial_cmp(other.inner.as_ref()) + } +} + +impl Ord for BytesMut { + fn cmp(&self, other: &BytesMut) -> cmp::Ordering { + self.inner.as_ref().cmp(other.inner.as_ref()) + } +} + +impl Eq for BytesMut { +} + +impl Default for BytesMut { + #[inline] + fn default() -> BytesMut { + BytesMut::new() + } +} + +impl fmt::Debug for BytesMut { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&debug::BsDebug(&self.inner.as_ref()), fmt) + } +} + +impl hash::Hash for BytesMut { + fn hash(&self, state: &mut H) where H: hash::Hasher { + let s: &[u8] = self.as_ref(); + s.hash(state); + } +} + +impl Borrow<[u8]> for BytesMut { + fn borrow(&self) -> &[u8] { + self.as_ref() + } +} + +impl BorrowMut<[u8]> for BytesMut { + fn borrow_mut(&mut self) -> &mut [u8] { + self.as_mut() + } +} + +impl fmt::Write for BytesMut { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + if self.remaining_mut() >= s.len() { + self.put_slice(s.as_bytes()); + Ok(()) + } else { + Err(fmt::Error) + } + } + + #[inline] + fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { + fmt::write(self, args) + } +} + +impl Clone for BytesMut { + fn clone(&self) -> BytesMut { + BytesMut::from(&self[..]) + } +} + +impl IntoIterator for BytesMut { + type Item = u8; + type IntoIter = Iter>; + + fn into_iter(self) -> Self::IntoIter { + self.into_buf().iter() + } +} + +impl<'a> IntoIterator for &'a BytesMut { + type Item = u8; + type IntoIter = Iter>; + + fn into_iter(self) -> Self::IntoIter { + self.into_buf().iter() + } +} + +impl Extend for BytesMut { + fn extend(&mut self, iter: T) where T: IntoIterator { + let iter = iter.into_iter(); + + let (lower, _) = iter.size_hint(); + self.reserve(lower); + + for b in iter { + unsafe { + self.bytes_mut()[0] = b; + self.advance_mut(1); + } + } + } +} + +impl<'a> Extend<&'a u8> for BytesMut { + fn extend(&mut self, iter: T) where T: IntoIterator { + self.extend(iter.into_iter().map(|b| *b)) + } +} + +/* + * + * ===== Inner ===== + * + */ + +impl Inner { + #[inline] + fn from_static(bytes: &'static [u8]) -> Inner { + let ptr = bytes.as_ptr() as *mut u8; + + Inner { + // `arc` won't ever store a pointer. Instead, use it to + // track the fact that the `Bytes` handle is backed by a + // static buffer. + arc: AtomicPtr::new(KIND_STATIC as *mut Shared), + ptr: ptr, + len: bytes.len(), + cap: bytes.len(), + } + } + + #[inline] + fn from_vec(mut src: Vec) -> Inner { + let len = src.len(); + let cap = src.capacity(); + let ptr = src.as_mut_ptr(); + + mem::forget(src); + + let original_capacity_repr = original_capacity_to_repr(cap); + let arc = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC; + + Inner { + arc: AtomicPtr::new(arc as *mut Shared), + ptr: ptr, + len: len, + cap: cap, + } + } + + #[inline] + fn with_capacity(capacity: usize) -> Inner { + if capacity <= INLINE_CAP { + unsafe { + // Using uninitialized memory is ~30% faster + let mut inner: Inner = mem::uninitialized(); + inner.arc = AtomicPtr::new(KIND_INLINE as *mut Shared); + inner + } + } else { + Inner::from_vec(Vec::with_capacity(capacity)) + } + } + + /// Return a slice for the handle's view into the shared buffer + #[inline] + fn as_ref(&self) -> &[u8] { + unsafe { + if self.is_inline() { + slice::from_raw_parts(self.inline_ptr(), self.inline_len()) + } else { + slice::from_raw_parts(self.ptr, self.len) + } + } + } + + /// Return a mutable slice for the handle's view into the shared buffer + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + debug_assert!(!self.is_static()); + + unsafe { + if self.is_inline() { + slice::from_raw_parts_mut(self.inline_ptr(), self.inline_len()) + } else { + slice::from_raw_parts_mut(self.ptr, self.len) + } + } + } + + /// Return a mutable slice for the handle's view into the shared buffer + /// including potentially uninitialized bytes. + #[inline] + unsafe fn as_raw(&mut self) -> &mut [u8] { + debug_assert!(!self.is_static()); + + if self.is_inline() { + slice::from_raw_parts_mut(self.inline_ptr(), INLINE_CAP) + } else { + slice::from_raw_parts_mut(self.ptr, self.cap) + } + } + + /// Insert a byte into the next slot and advance the len by 1. + #[inline] + fn put_u8(&mut self, n: u8) { + if self.is_inline() { + let len = self.inline_len(); + assert!(len < INLINE_CAP); + unsafe { + *self.inline_ptr().offset(len as isize) = n; + } + self.set_inline_len(len + 1); + } else { + assert!(self.len < self.cap); + unsafe { + *self.ptr.offset(self.len as isize) = n; + } + self.len += 1; + } + } + + #[inline] + fn len(&self) -> usize { + if self.is_inline() { + self.inline_len() + } else { + self.len + } + } + + /// Pointer to the start of the inline buffer + #[inline] + unsafe fn inline_ptr(&self) -> *mut u8 { + (self as *const Inner as *mut Inner as *mut u8) + .offset(INLINE_DATA_OFFSET) + } + + #[inline] + fn inline_len(&self) -> usize { + let p: &usize = unsafe { mem::transmute(&self.arc) }; + (p & INLINE_LEN_MASK) >> INLINE_LEN_OFFSET + } + + /// Set the length of the inline buffer. This is done by writing to the + /// least significant byte of the `arc` field. + #[inline] + fn set_inline_len(&mut self, len: usize) { + debug_assert!(len <= INLINE_CAP); + let p = self.arc.get_mut(); + *p = ((*p as usize & !INLINE_LEN_MASK) | (len << INLINE_LEN_OFFSET)) as _; + } + + /// slice. + #[inline] + unsafe fn set_len(&mut self, len: usize) { + if self.is_inline() { + assert!(len <= INLINE_CAP); + self.set_inline_len(len); + } else { + assert!(len <= self.cap); + self.len = len; + } + } + + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + fn capacity(&self) -> usize { + if self.is_inline() { + INLINE_CAP + } else { + self.cap + } + } + + fn split_off(&mut self, at: usize) -> Inner { + let mut other = unsafe { self.shallow_clone(true) }; + + unsafe { + other.set_start(at); + self.set_end(at); + } + + return other + } + + fn split_to(&mut self, at: usize) -> Inner { + let mut other = unsafe { self.shallow_clone(true) }; + + unsafe { + other.set_end(at); + self.set_start(at); + } + + return other + } + + fn truncate(&mut self, len: usize) { + if len <= self.len() { + unsafe { self.set_len(len); } + } + } + + fn resize(&mut self, new_len: usize, value: u8) { + let len = self.len(); + if new_len > len { + let additional = new_len - len; + self.reserve(additional); + unsafe { + let dst = self.as_raw()[len..].as_mut_ptr(); + ptr::write_bytes(dst, value, additional); + self.set_len(new_len); + } + } else { + self.truncate(new_len); + } + } + + unsafe fn set_start(&mut self, start: usize) { + // Setting the start to 0 is a no-op, so return early if this is the + // case. + if start == 0 { + return; + } + + let kind = self.kind(); + + // Always check `inline` first, because if the handle is using inline + // data storage, all of the `Inner` struct fields will be gibberish. + if kind == KIND_INLINE { + assert!(start <= INLINE_CAP); + + let len = self.inline_len(); + + if len <= start { + self.set_inline_len(0); + } else { + // `set_start` is essentially shifting data off the front of the + // view. Inlined buffers only track the length of the slice. + // So, to update the start, the data at the new starting point + // is copied to the beginning of the buffer. + let new_len = len - start; + + let dst = self.inline_ptr(); + let src = (dst as *const u8).offset(start as isize); + + ptr::copy(src, dst, new_len); + + self.set_inline_len(new_len); + } + } else { + assert!(start <= self.cap); + + if kind == KIND_VEC { + // Setting the start when in vec representation is a little more + // complicated. First, we have to track how far ahead the + // "start" of the byte buffer from the beginning of the vec. We + // also have to ensure that we don't exceed the maximum shift. + let (mut pos, prev) = self.uncoordinated_get_vec_pos(); + pos += start; + + if pos <= MAX_VEC_POS { + self.uncoordinated_set_vec_pos(pos, prev); + } else { + // The repr must be upgraded to ARC. This will never happen + // on 64 bit systems and will only happen on 32 bit systems + // when shifting past 134,217,727 bytes. As such, we don't + // worry too much about performance here. + let _ = self.shallow_clone(true); + } + } + + // Updating the start of the view is setting `ptr` to point to the + // new start and updating the `len` field to reflect the new length + // of the view. + self.ptr = self.ptr.offset(start as isize); + + if self.len >= start { + self.len -= start; + } else { + self.len = 0; + } + + self.cap -= start; + } + } + + unsafe fn set_end(&mut self, end: usize) { + debug_assert!(self.is_shared()); + + // Always check `inline` first, because if the handle is using inline + // data storage, all of the `Inner` struct fields will be gibberish. + if self.is_inline() { + assert!(end <= INLINE_CAP); + let new_len = cmp::min(self.inline_len(), end); + self.set_inline_len(new_len); + } else { + assert!(end <= self.cap); + + self.cap = end; + self.len = cmp::min(self.len, end); + } + } + + /// Checks if it is safe to mutate the memory + fn is_mut_safe(&mut self) -> bool { + let kind = self.kind(); + + // Always check `inline` first, because if the handle is using inline + // data storage, all of the `Inner` struct fields will be gibberish. + if kind == KIND_INLINE { + // Inlined buffers can always be mutated as the data is never shared + // across handles. + true + } else if kind == KIND_VEC { + true + } else if kind == KIND_STATIC { + false + } else { + // Otherwise, the underlying buffer is potentially shared with other + // handles, so the ref_count needs to be checked. + unsafe { (**self.arc.get_mut()).is_unique() } + } + } + + /// Increments the ref count. This should only be done if it is known that + /// it can be done safely. As such, this fn is not public, instead other + /// fns will use this one while maintaining the guarantees. + /// Parameter `mut_self` should only be set to `true` if caller holds + /// `&mut self` reference. + /// + /// "Safely" is defined as not exposing two `BytesMut` values that point to + /// the same byte window. + /// + /// This function is thread safe. + unsafe fn shallow_clone(&self, mut_self: bool) -> Inner { + // Always check `inline` first, because if the handle is using inline + // data storage, all of the `Inner` struct fields will be gibberish. + // + // Additionally, if kind is STATIC, then Arc is *never* changed, making + // it safe and faster to check for it now before an atomic acquire. + + if self.is_inline_or_static() { + // In this case, a shallow_clone still involves copying the data. + let mut inner: Inner = mem::uninitialized(); + ptr::copy_nonoverlapping( + self, + &mut inner, + 1, + ); + inner + } else { + self.shallow_clone_sync(mut_self) + } + } + + + #[cold] + unsafe fn shallow_clone_sync(&self, mut_self: bool) -> Inner { + // The function requires `&self`, this means that `shallow_clone` + // could be called concurrently. + // + // The first step is to load the value of `arc`. This will determine + // how to proceed. The `Acquire` ordering synchronizes with the + // `compare_and_swap` that comes later in this function. The goal is + // to ensure that if `arc` is currently set to point to a `Shared`, + // that the current thread acquires the associated memory. + let arc = self.arc.load(Acquire); + let kind = arc as usize & KIND_MASK; + + if kind == KIND_ARC { + self.shallow_clone_arc(arc) + } else { + assert!(kind == KIND_VEC); + self.shallow_clone_vec(arc as usize, mut_self) + } + } + + unsafe fn shallow_clone_arc(&self, arc: *mut Shared) -> Inner { + debug_assert!(arc as usize & KIND_MASK == KIND_ARC); + + let old_size = (*arc).ref_count.fetch_add(1, Relaxed); + + if old_size == usize::MAX { + abort(); + } + + Inner { + arc: AtomicPtr::new(arc), + .. *self + } + } + + #[cold] + unsafe fn shallow_clone_vec(&self, arc: usize, mut_self: bool) -> Inner { + // If the buffer is still tracked in a `Vec`. It is time to + // promote the vec to an `Arc`. This could potentially be called + // concurrently, so some care must be taken. + + debug_assert!(arc & KIND_MASK == KIND_VEC); + + let original_capacity_repr = + (arc as usize & ORIGINAL_CAPACITY_MASK) >> ORIGINAL_CAPACITY_OFFSET; + + // The vec offset cannot be concurrently mutated, so there + // should be no danger reading it. + let off = (arc as usize) >> VEC_POS_OFFSET; + + // First, allocate a new `Shared` instance containing the + // `Vec` fields. It's important to note that `ptr`, `len`, + // and `cap` cannot be mutated without having `&mut self`. + // This means that these fields will not be concurrently + // updated and since the buffer hasn't been promoted to an + // `Arc`, those three fields still are the components of the + // vector. + let shared = Box::new(Shared { + vec: rebuild_vec(self.ptr, self.len, self.cap, off), + original_capacity_repr: original_capacity_repr, + // Initialize refcount to 2. One for this reference, and one + // for the new clone that will be returned from + // `shallow_clone`. + ref_count: AtomicUsize::new(2), + }); + + let shared = Box::into_raw(shared); + + // The pointer should be aligned, so this assert should + // always succeed. + debug_assert!(0 == (shared as usize & 0b11)); + + // If there are no references to self in other threads, + // expensive atomic operations can be avoided. + if mut_self { + self.arc.store(shared, Relaxed); + return Inner { + arc: AtomicPtr::new(shared), + .. *self + }; + } + + // Try compare & swapping the pointer into the `arc` field. + // `Release` is used synchronize with other threads that + // will load the `arc` field. + // + // If the `compare_and_swap` fails, then the thread lost the + // race to promote the buffer to shared. The `Acquire` + // ordering will synchronize with the `compare_and_swap` + // that happened in the other thread and the `Shared` + // pointed to by `actual` will be visible. + let actual = self.arc.compare_and_swap(arc as *mut Shared, shared, AcqRel); + + if actual as usize == arc { + // The upgrade was successful, the new handle can be + // returned. + return Inner { + arc: AtomicPtr::new(shared), + .. *self + }; + } + + // The upgrade failed, a concurrent clone happened. Release + // the allocation that was made in this thread, it will not + // be needed. + let shared = Box::from_raw(shared); + mem::forget(*shared); + + // Buffer already promoted to shared storage, so increment ref + // count. + self.shallow_clone_arc(actual) + } + + #[inline] + fn reserve(&mut self, additional: usize) { + let len = self.len(); + let rem = self.capacity() - len; + + if additional <= rem { + // The handle can already store at least `additional` more bytes, so + // there is no further work needed to be done. + return; + } + + let kind = self.kind(); + + // Always check `inline` first, because if the handle is using inline + // data storage, all of the `Inner` struct fields will be gibberish. + if kind == KIND_INLINE { + let new_cap = len + additional; + + // Promote to a vector + let mut v = Vec::with_capacity(new_cap); + v.extend_from_slice(self.as_ref()); + + self.ptr = v.as_mut_ptr(); + self.len = v.len(); + self.cap = v.capacity(); + + // Since the minimum capacity is `INLINE_CAP`, don't bother encoding + // the original capacity as INLINE_CAP + self.arc = AtomicPtr::new(KIND_VEC as *mut Shared); + + mem::forget(v); + return; + } + + if kind == KIND_VEC { + // If there's enough free space before the start of the buffer, then + // just copy the data backwards and reuse the already-allocated + // space. + // + // Otherwise, since backed by a vector, use `Vec::reserve` + unsafe { + let (off, prev) = self.uncoordinated_get_vec_pos(); + + // Only reuse space if we stand to gain at least capacity/2 + // bytes of space back + if off >= additional && off >= (self.cap / 2) { + // There's space - reuse it + // + // Just move the pointer back to the start after copying + // data back. + let base_ptr = self.ptr.offset(-(off as isize)); + ptr::copy(self.ptr, base_ptr, self.len); + self.ptr = base_ptr; + self.uncoordinated_set_vec_pos(0, prev); + + // Length stays constant, but since we moved backwards we + // can gain capacity back. + self.cap += off; + } else { + // No space - allocate more + let mut v = rebuild_vec(self.ptr, self.len, self.cap, off); + v.reserve(additional); + + // Update the info + self.ptr = v.as_mut_ptr().offset(off as isize); + self.len = v.len() - off; + self.cap = v.capacity() - off; + + // Drop the vec reference + mem::forget(v); + } + return; + } + } + + let arc = *self.arc.get_mut(); + + debug_assert!(kind == KIND_ARC); + + // Reserving involves abandoning the currently shared buffer and + // allocating a new vector with the requested capacity. + // + // Compute the new capacity + let mut new_cap = len + additional; + let original_capacity; + let original_capacity_repr; + + unsafe { + original_capacity_repr = (*arc).original_capacity_repr; + original_capacity = original_capacity_from_repr(original_capacity_repr); + + // First, try to reclaim the buffer. This is possible if the current + // handle is the only outstanding handle pointing to the buffer. + if (*arc).is_unique() { + // This is the only handle to the buffer. It can be reclaimed. + // However, before doing the work of copying data, check to make + // sure that the vector has enough capacity. + let v = &mut (*arc).vec; + + if v.capacity() >= new_cap { + // The capacity is sufficient, reclaim the buffer + let ptr = v.as_mut_ptr(); + + ptr::copy(self.ptr, ptr, len); + + self.ptr = ptr; + self.cap = v.capacity(); + + return; + } + + // The vector capacity is not sufficient. The reserve request is + // asking for more than the initial buffer capacity. Allocate more + // than requested if `new_cap` is not much bigger than the current + // capacity. + // + // There are some situations, using `reserve_exact` that the + // buffer capacity could be below `original_capacity`, so do a + // check. + new_cap = cmp::max( + cmp::max(v.capacity() << 1, new_cap), + original_capacity); + } else { + new_cap = cmp::max(new_cap, original_capacity); + } + } + + // Create a new vector to store the data + let mut v = Vec::with_capacity(new_cap); + + // Copy the bytes + v.extend_from_slice(self.as_ref()); + + // Release the shared handle. This must be done *after* the bytes are + // copied. + release_shared(arc); + + // Update self + self.ptr = v.as_mut_ptr(); + self.len = v.len(); + self.cap = v.capacity(); + + let arc = (original_capacity_repr << ORIGINAL_CAPACITY_OFFSET) | KIND_VEC; + + self.arc = AtomicPtr::new(arc as *mut Shared); + + // Forget the vector handle + mem::forget(v); + } + + /// Returns true if the buffer is stored inline + #[inline] + fn is_inline(&self) -> bool { + self.kind() == KIND_INLINE + } + + #[inline] + fn is_inline_or_static(&self) -> bool { + // The value returned by `kind` isn't itself safe, but the value could + // inform what operations to take, and unsafely do something without + // synchronization. + // + // KIND_INLINE and KIND_STATIC will *never* change, so branches on that + // information is safe. + let kind = self.kind(); + kind == KIND_INLINE || kind == KIND_STATIC + } + + /// Used for `debug_assert` statements. &mut is used to guarantee that it is + /// safe to check VEC_KIND + #[inline] + fn is_shared(&mut self) -> bool { + match self.kind() { + KIND_VEC => false, + _ => true, + } + } + + /// Used for `debug_assert` statements + #[inline] + fn is_static(&mut self) -> bool { + match self.kind() { + KIND_STATIC => true, + _ => false, + } + } + + #[inline] + fn kind(&self) -> usize { + // This function is going to probably raise some eyebrows. The function + // returns true if the buffer is stored inline. This is done by checking + // the least significant bit in the `arc` field. + // + // Now, you may notice that `arc` is an `AtomicPtr` and this is + // accessing it as a normal field without performing an atomic load... + // + // Again, the function only cares about the least significant bit, and + // this bit is set when `Inner` is created and never changed after that. + // All platforms have atomic "word" operations and won't randomly flip + // bits, so even without any explicit atomic operations, reading the + // flag will be correct. + // + // This is undefind behavior due to a data race, but experimental + // evidence shows that it works in practice (discussion: + // https://internals.rust-lang.org/t/bit-wise-reasoning-for-atomic-accesses/8853). + // + // This function is very critical performance wise as it is called for + // every operation. Performing an atomic load would mess with the + // compiler's ability to optimize. Simple benchmarks show up to a 10% + // slowdown using a `Relaxed` atomic load on x86. + + #[cfg(target_endian = "little")] + #[inline] + fn imp(arc: &AtomicPtr) -> usize { + unsafe { + let p: *const u8 = mem::transmute(arc); + (*p as usize) & KIND_MASK + } + } + + #[cfg(target_endian = "big")] + #[inline] + fn imp(arc: &AtomicPtr) -> usize { + unsafe { + let p: *const usize = mem::transmute(arc); + *p & KIND_MASK + } + } + + imp(&self.arc) + } + + #[inline] + fn uncoordinated_get_vec_pos(&mut self) -> (usize, usize) { + // Similar to above, this is a pretty crazed function. This should only + // be called when in the KIND_VEC mode. This + the &mut self argument + // guarantees that there is no possibility of concurrent calls to this + // function. + let prev = unsafe { + let p: &AtomicPtr = &self.arc; + let p: *const usize = mem::transmute(p); + *p + }; + + (prev >> VEC_POS_OFFSET, prev) + } + + #[inline] + fn uncoordinated_set_vec_pos(&mut self, pos: usize, prev: usize) { + // Once more... crazy + debug_assert!(pos <= MAX_VEC_POS); + + unsafe { + let p: &mut AtomicPtr = &mut self.arc; + let p: &mut usize = mem::transmute(p); + *p = (pos << VEC_POS_OFFSET) | (prev & NOT_VEC_POS_MASK); + } + } +} + +fn rebuild_vec(ptr: *mut u8, mut len: usize, mut cap: usize, off: usize) -> Vec { + unsafe { + let ptr = ptr.offset(-(off as isize)); + len += off; + cap += off; + + Vec::from_raw_parts(ptr, len, cap) + } +} + +impl Drop for Inner { + fn drop(&mut self) { + let kind = self.kind(); + + if kind == KIND_VEC { + let (off, _) = self.uncoordinated_get_vec_pos(); + + // Vector storage, free the vector + let _ = rebuild_vec(self.ptr, self.len, self.cap, off); + } else if kind == KIND_ARC { + release_shared(*self.arc.get_mut()); + } + } +} + +fn release_shared(ptr: *mut Shared) { + // `Shared` storage... follow the drop steps from Arc. + unsafe { + if (*ptr).ref_count.fetch_sub(1, Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + atomic::fence(Acquire); + + // Drop the data + Box::from_raw(ptr); + } +} + +impl Shared { + fn is_unique(&self) -> bool { + // The goal is to check if the current handle is the only handle + // that currently has access to the buffer. This is done by + // checking if the `ref_count` is currently 1. + // + // The `Acquire` ordering synchronizes with the `Release` as + // part of the `fetch_sub` in `release_shared`. The `fetch_sub` + // operation guarantees that any mutations done in other threads + // are ordered before the `ref_count` is decremented. As such, + // this `Acquire` will guarantee that those mutations are + // visible to the current thread. + self.ref_count.load(Acquire) == 1 + } +} + +fn original_capacity_to_repr(cap: usize) -> usize { + let width = PTR_WIDTH - ((cap >> MIN_ORIGINAL_CAPACITY_WIDTH).leading_zeros() as usize); + cmp::min(width, MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH) +} + +fn original_capacity_from_repr(repr: usize) -> usize { + if repr == 0 { + return 0; + } + + 1 << (repr + (MIN_ORIGINAL_CAPACITY_WIDTH - 1)) +} + +#[test] +fn test_original_capacity_to_repr() { + assert_eq!(original_capacity_to_repr(0), 0); + + let max_width = 32; + + for width in 1..(max_width + 1) { + let cap = 1 << width - 1; + + let expected = if width < MIN_ORIGINAL_CAPACITY_WIDTH { + 0 + } else if width < MAX_ORIGINAL_CAPACITY_WIDTH { + width - MIN_ORIGINAL_CAPACITY_WIDTH + } else { + MAX_ORIGINAL_CAPACITY_WIDTH - MIN_ORIGINAL_CAPACITY_WIDTH + }; + + assert_eq!(original_capacity_to_repr(cap), expected); + + if width > 1 { + assert_eq!(original_capacity_to_repr(cap + 1), expected); + } + + // MIN_ORIGINAL_CAPACITY_WIDTH must be bigger than 7 to pass tests below + if width == MIN_ORIGINAL_CAPACITY_WIDTH + 1 { + assert_eq!(original_capacity_to_repr(cap - 24), expected - 1); + assert_eq!(original_capacity_to_repr(cap + 76), expected); + } else if width == MIN_ORIGINAL_CAPACITY_WIDTH + 2 { + assert_eq!(original_capacity_to_repr(cap - 1), expected - 1); + assert_eq!(original_capacity_to_repr(cap - 48), expected - 1); + } + } +} + +#[test] +fn test_original_capacity_from_repr() { + assert_eq!(0, original_capacity_from_repr(0)); + + let min_cap = 1 << MIN_ORIGINAL_CAPACITY_WIDTH; + + assert_eq!(min_cap, original_capacity_from_repr(1)); + assert_eq!(min_cap * 2, original_capacity_from_repr(2)); + assert_eq!(min_cap * 4, original_capacity_from_repr(3)); + assert_eq!(min_cap * 8, original_capacity_from_repr(4)); + assert_eq!(min_cap * 16, original_capacity_from_repr(5)); + assert_eq!(min_cap * 32, original_capacity_from_repr(6)); + assert_eq!(min_cap * 64, original_capacity_from_repr(7)); +} + +unsafe impl Send for Inner {} +unsafe impl Sync for Inner {} + +/* + * + * ===== PartialEq / PartialOrd ===== + * + */ + +impl PartialEq<[u8]> for BytesMut { + fn eq(&self, other: &[u8]) -> bool { + &**self == other + } +} + +impl PartialOrd<[u8]> for BytesMut { + fn partial_cmp(&self, other: &[u8]) -> Option { + (**self).partial_cmp(other) + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for [u8] { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &str) -> bool { + &**self == other.as_bytes() + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &str) -> Option { + (**self).partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for str { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for str { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq> for BytesMut { + fn eq(&self, other: &Vec) -> bool { + *self == &other[..] + } +} + +impl PartialOrd> for BytesMut { + fn partial_cmp(&self, other: &Vec) -> Option { + (**self).partial_cmp(&other[..]) + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for Vec { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for BytesMut { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + +impl PartialOrd for BytesMut { + fn partial_cmp(&self, other: &String) -> Option { + (**self).partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl<'a, T: ?Sized> PartialEq<&'a T> for BytesMut + where BytesMut: PartialEq +{ + fn eq(&self, other: &&'a T) -> bool { + *self == **other + } +} + +impl<'a, T: ?Sized> PartialOrd<&'a T> for BytesMut + where BytesMut: PartialOrd +{ + fn partial_cmp(&self, other: &&'a T) -> Option { + self.partial_cmp(*other) + } +} + +impl<'a> PartialEq for &'a [u8] { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl<'a> PartialOrd for &'a [u8] { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &BytesMut) -> bool { + *other == *self + } +} + +impl<'a> PartialOrd for &'a str { + fn partial_cmp(&self, other: &BytesMut) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq<[u8]> for Bytes { + fn eq(&self, other: &[u8]) -> bool { + self.inner.as_ref() == other + } +} + +impl PartialOrd<[u8]> for Bytes { + fn partial_cmp(&self, other: &[u8]) -> Option { + self.inner.as_ref().partial_cmp(other) + } +} + +impl PartialEq for [u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for [u8] { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &str) -> bool { + self.inner.as_ref() == other.as_bytes() + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &str) -> Option { + self.inner.as_ref().partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for str { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq> for Bytes { + fn eq(&self, other: &Vec) -> bool { + *self == &other[..] + } +} + +impl PartialOrd> for Bytes { + fn partial_cmp(&self, other: &Vec) -> Option { + self.inner.as_ref().partial_cmp(&other[..]) + } +} + +impl PartialEq for Vec { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for Vec { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl PartialEq for Bytes { + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + +impl PartialOrd for Bytes { + fn partial_cmp(&self, other: &String) -> Option { + self.inner.as_ref().partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl<'a> PartialEq for &'a [u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl<'a> PartialOrd for &'a [u8] { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &Bytes) -> bool { + *other == *self + } +} + +impl<'a> PartialOrd for &'a str { + fn partial_cmp(&self, other: &Bytes) -> Option { + other.partial_cmp(self) + } +} + +impl<'a, T: ?Sized> PartialEq<&'a T> for Bytes + where Bytes: PartialEq +{ + fn eq(&self, other: &&'a T) -> bool { + *self == **other + } +} + +impl<'a, T: ?Sized> PartialOrd<&'a T> for Bytes + where Bytes: PartialOrd +{ + fn partial_cmp(&self, other: &&'a T) -> Option { + self.partial_cmp(&**other) + } +} + +impl PartialEq for Bytes +{ + fn eq(&self, other: &BytesMut) -> bool { + &other[..] == &self[..] + } +} + +impl PartialEq for BytesMut +{ + fn eq(&self, other: &Bytes) -> bool { + &other[..] == &self[..] + } +} + +// While there is `std::process:abort`, it's only available in Rust 1.17, and +// our minimum supported version is currently 1.15. So, this acts as an abort +// by triggering a double panic, which always aborts in Rust. +struct Abort; + +impl Drop for Abort { + fn drop(&mut self) { + panic!(); + } +} + +#[inline(never)] +#[cold] +fn abort() { + let _a = Abort; + panic!(); +} diff --git a/bytes/src/debug.rs b/bytes/src/debug.rs new file mode 100644 index 000000000..f8b830a24 --- /dev/null +++ b/bytes/src/debug.rs @@ -0,0 +1,40 @@ +use std::fmt; + +/// Alternative implementation of `fmt::Debug` for byte slice. +/// +/// Standard `Debug` implementation for `[u8]` is comma separated +/// list of numbers. Since large amount of byte strings are in fact +/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP), +/// it is convenient to print strings as ASCII when possible. +/// +/// This struct wraps `&[u8]` just to override `fmt::Debug`. +/// +/// `BsDebug` is not a part of public API of bytes crate. +pub struct BsDebug<'a>(pub &'a [u8]); + +impl<'a> fmt::Debug for BsDebug<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + try!(write!(fmt, "b\"")); + for &c in self.0 { + // https://doc.rust-lang.org/reference.html#byte-escapes + if c == b'\n' { + try!(write!(fmt, "\\n")); + } else if c == b'\r' { + try!(write!(fmt, "\\r")); + } else if c == b'\t' { + try!(write!(fmt, "\\t")); + } else if c == b'\\' || c == b'"' { + try!(write!(fmt, "\\{}", c as char)); + } else if c == b'\0' { + try!(write!(fmt, "\\0")); + // ASCII printable + } else if c >= 0x20 && c < 0x7f { + try!(write!(fmt, "{}", c as char)); + } else { + try!(write!(fmt, "\\x{:02x}", c)); + } + } + try!(write!(fmt, "\"")); + Ok(()) + } +} diff --git a/bytes/src/either.rs b/bytes/src/either.rs new file mode 100644 index 000000000..53a277599 --- /dev/null +++ b/bytes/src/either.rs @@ -0,0 +1,89 @@ +extern crate either; + +use {Buf, BufMut}; + +use self::either::Either; +use self::either::Either::*; +use iovec::IoVec; + +impl Buf for Either +where + L: Buf, + R: Buf, +{ + fn remaining(&self) -> usize { + match *self { + Left(ref b) => b.remaining(), + Right(ref b) => b.remaining(), + } + } + + fn bytes(&self) -> &[u8] { + match *self { + Left(ref b) => b.bytes(), + Right(ref b) => b.bytes(), + } + } + + fn bytes_vec<'a>(&'a self, dst: &mut [&'a IoVec]) -> usize { + match *self { + Left(ref b) => b.bytes_vec(dst), + Right(ref b) => b.bytes_vec(dst), + } + } + + fn advance(&mut self, cnt: usize) { + match *self { + Left(ref mut b) => b.advance(cnt), + Right(ref mut b) => b.advance(cnt), + } + } + + fn copy_to_slice(&mut self, dst: &mut [u8]) { + match *self { + Left(ref mut b) => b.copy_to_slice(dst), + Right(ref mut b) => b.copy_to_slice(dst), + } + } +} + +impl BufMut for Either +where + L: BufMut, + R: BufMut, +{ + fn remaining_mut(&self) -> usize { + match *self { + Left(ref b) => b.remaining_mut(), + Right(ref b) => b.remaining_mut(), + } + } + + unsafe fn bytes_mut(&mut self) -> &mut [u8] { + match *self { + Left(ref mut b) => b.bytes_mut(), + Right(ref mut b) => b.bytes_mut(), + } + } + + unsafe fn bytes_vec_mut<'a>(&'a mut self, dst: &mut [&'a mut IoVec]) -> usize { + match *self { + Left(ref mut b) => b.bytes_vec_mut(dst), + Right(ref mut b) => b.bytes_vec_mut(dst), + } + } + + unsafe fn advance_mut(&mut self, cnt: usize) { + match *self { + Left(ref mut b) => b.advance_mut(cnt), + Right(ref mut b) => b.advance_mut(cnt), + } + } + + fn put_slice(&mut self, src: &[u8]) { + match *self { + Left(ref mut b) => b.put_slice(src), + Right(ref mut b) => b.put_slice(src), + } + } +} diff --git a/bytes/src/lib.rs b/bytes/src/lib.rs new file mode 100644 index 000000000..a4f1573e0 --- /dev/null +++ b/bytes/src/lib.rs @@ -0,0 +1,105 @@ +//! Provides abstractions for working with bytes. +//! +//! The `bytes` crate provides an efficient byte buffer structure +//! ([`Bytes`](struct.Bytes.html)) and traits for working with buffer +//! implementations ([`Buf`], [`BufMut`]). +//! +//! [`Buf`]: trait.Buf.html +//! [`BufMut`]: trait.BufMut.html +//! +//! # `Bytes` +//! +//! `Bytes` is an efficient container for storing and operating on continguous +//! slices of memory. It is intended for use primarily in networking code, but +//! could have applications elsewhere as well. +//! +//! `Bytes` values facilitate zero-copy network programming by allowing multiple +//! `Bytes` objects to point to the same underlying memory. This is managed by +//! using a reference count to track when the memory is no longer needed and can +//! be freed. +//! +//! A `Bytes` handle can be created directly from an existing byte store (such as `&[u8]` +//! or `Vec`), but usually a `BytesMut` is used first and written to. For +//! example: +//! +//! ```rust +//! use bytes::{BytesMut, BufMut, BigEndian}; +//! +//! let mut buf = BytesMut::with_capacity(1024); +//! buf.put(&b"hello world"[..]); +//! buf.put_u16::(1234); +//! +//! let a = buf.take(); +//! assert_eq!(a, b"hello world\x04\xD2"[..]); +//! +//! buf.put(&b"goodbye world"[..]); +//! +//! let b = buf.take(); +//! assert_eq!(b, b"goodbye world"[..]); +//! +//! assert_eq!(buf.capacity(), 998); +//! ``` +//! +//! In the above example, only a single buffer of 1024 is allocated. The handles +//! `a` and `b` will share the underlying buffer and maintain indices tracking +//! the view into the buffer represented by the handle. +//! +//! See the [struct docs] for more details. +//! +//! [struct docs]: struct.Bytes.html +//! +//! # `Buf`, `BufMut` +//! +//! These two traits provide read and write access to buffers. The underlying +//! storage may or may not be in contiguous memory. For example, `Bytes` is a +//! buffer that guarantees contiguous memory, but a [rope] stores the bytes in +//! disjoint chunks. `Buf` and `BufMut` maintain cursors tracking the current +//! position in the underlying byte storage. When bytes are read or written, the +//! cursor is advanced. +//! +//! [rope]: https://en.wikipedia.org/wiki/Rope_(data_structure) +//! +//! ## Relation with `Read` and `Write` +//! +//! At first glance, it may seem that `Buf` and `BufMut` overlap in +//! functionality with `std::io::Read` and `std::io::Write`. However, they +//! serve different purposes. A buffer is the value that is provided as an +//! argument to `Read::read` and `Write::write`. `Read` and `Write` may then +//! perform a syscall, which has the potential of failing. Operations on `Buf` +//! and `BufMut` are infallible. + +#![deny(warnings, missing_docs, missing_debug_implementations)] +#![doc(html_root_url = "https://docs.rs/bytes/0.4.12")] + +extern crate byteorder; +extern crate iovec; + +pub mod buf; +pub use buf::{ + Buf, + BufMut, + IntoBuf, +}; +#[deprecated(since = "0.4.1", note = "moved to `buf` module")] +#[doc(hidden)] +pub use buf::{ + Reader, + Writer, + Take, +}; + +mod bytes; +mod debug; +pub use bytes::{Bytes, BytesMut}; + +#[deprecated] +pub use byteorder::{ByteOrder, BigEndian, LittleEndian}; + +// Optional Serde support +#[cfg(feature = "serde")] +#[doc(hidden)] +pub mod serde; + +// Optional `Either` support +#[cfg(feature = "either")] +mod either; diff --git a/bytes/src/serde.rs b/bytes/src/serde.rs new file mode 100644 index 000000000..d45caff05 --- /dev/null +++ b/bytes/src/serde.rs @@ -0,0 +1,82 @@ +extern crate serde; + +use std::{cmp, fmt}; +use self::serde::{Serialize, Serializer, Deserialize, Deserializer, de}; +use super::{Bytes, BytesMut}; + +macro_rules! serde_impl { + ($ty:ident, $visitor_ty:ident) => ( + impl Serialize for $ty { + #[inline] + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + serializer.serialize_bytes(&self) + } + } + + struct $visitor_ty; + + impl<'de> de::Visitor<'de> for $visitor_ty { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + #[inline] + fn visit_seq(self, mut seq: V) -> Result + where V: de::SeqAccess<'de> + { + let len = cmp::min(seq.size_hint().unwrap_or(0), 4096); + let mut values = Vec::with_capacity(len); + + while let Some(value) = try!(seq.next_element()) { + values.push(value); + } + + Ok(values.into()) + } + + #[inline] + fn visit_bytes(self, v: &[u8]) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_byte_buf(self, v: Vec) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_str(self, v: &str) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + + #[inline] + fn visit_string(self, v: String) -> Result + where E: de::Error + { + Ok($ty::from(v)) + } + } + + impl<'de> Deserialize<'de> for $ty { + #[inline] + fn deserialize(deserializer: D) -> Result<$ty, D::Error> + where D: Deserializer<'de> + { + deserializer.deserialize_byte_buf($visitor_ty) + } + } + ); +} + +serde_impl!(Bytes, BytesVisitor); +serde_impl!(BytesMut, BytesMutVisitor); diff --git a/bytes/tests/test_buf.rs b/bytes/tests/test_buf.rs new file mode 100644 index 000000000..f25c25f2b --- /dev/null +++ b/bytes/tests/test_buf.rs @@ -0,0 +1,58 @@ +extern crate bytes; +extern crate byteorder; +extern crate iovec; + +use bytes::Buf; +use iovec::IoVec; +use std::io::Cursor; + +#[test] +fn test_fresh_cursor_vec() { + let mut buf = Cursor::new(b"hello".to_vec()); + + assert_eq!(buf.remaining(), 5); + assert_eq!(buf.bytes(), b"hello"); + + buf.advance(2); + + assert_eq!(buf.remaining(), 3); + assert_eq!(buf.bytes(), b"llo"); + + buf.advance(3); + + assert_eq!(buf.remaining(), 0); + assert_eq!(buf.bytes(), b""); +} + +#[test] +fn test_get_u8() { + let mut buf = Cursor::new(b"\x21zomg"); + assert_eq!(0x21, buf.get_u8()); +} + +#[test] +fn test_get_u16() { + let buf = b"\x21\x54zomg"; + assert_eq!(0x2154, Cursor::new(buf).get_u16_be()); + assert_eq!(0x5421, Cursor::new(buf).get_u16_le()); +} + +#[test] +#[should_panic] +fn test_get_u16_buffer_underflow() { + let mut buf = Cursor::new(b"\x21"); + buf.get_u16_be(); +} + +#[test] +fn test_bufs_vec() { + let buf = Cursor::new(b"hello world"); + + let b1: &[u8] = &mut [0]; + let b2: &[u8] = &mut [0]; + + let mut dst: [&IoVec; 2] = + [b1.into(), b2.into()]; + + assert_eq!(1, buf.bytes_vec(&mut dst[..])); +} diff --git a/bytes/tests/test_buf_mut.rs b/bytes/tests/test_buf_mut.rs new file mode 100644 index 000000000..2c8faa104 --- /dev/null +++ b/bytes/tests/test_buf_mut.rs @@ -0,0 +1,83 @@ +extern crate bytes; +extern crate byteorder; +extern crate iovec; + +use bytes::{BufMut, BytesMut}; +use iovec::IoVec; +use std::usize; +use std::fmt::Write; + +#[test] +fn test_vec_as_mut_buf() { + let mut buf = Vec::with_capacity(64); + + assert_eq!(buf.remaining_mut(), usize::MAX); + + unsafe { + assert!(buf.bytes_mut().len() >= 64); + } + + buf.put(&b"zomg"[..]); + + assert_eq!(&buf, b"zomg"); + + assert_eq!(buf.remaining_mut(), usize::MAX - 4); + assert_eq!(buf.capacity(), 64); + + for _ in 0..16 { + buf.put(&b"zomg"[..]); + } + + assert_eq!(buf.len(), 68); +} + +#[test] +fn test_put_u8() { + let mut buf = Vec::with_capacity(8); + buf.put::(33); + assert_eq!(b"\x21", &buf[..]); +} + +#[test] +fn test_put_u16() { + let mut buf = Vec::with_capacity(8); + buf.put_u16_be(8532); + assert_eq!(b"\x21\x54", &buf[..]); + + buf.clear(); + buf.put_u16_le(8532); + assert_eq!(b"\x54\x21", &buf[..]); +} + +#[test] +fn test_vec_advance_mut() { + // Regression test for carllerche/bytes#108. + let mut buf = Vec::with_capacity(8); + unsafe { + buf.advance_mut(12); + assert_eq!(buf.len(), 12); + assert!(buf.capacity() >= 12, "capacity: {}", buf.capacity()); + } +} + +#[test] +fn test_clone() { + let mut buf = BytesMut::with_capacity(100); + buf.write_str("this is a test").unwrap(); + let buf2 = buf.clone(); + + buf.write_str(" of our emergecy broadcast system").unwrap(); + assert!(buf != buf2); +} + +#[test] +fn test_bufs_vec_mut() { + use std::mem; + + let mut buf = BytesMut::from(&b"hello world"[..]); + + unsafe { + let mut dst: [&mut IoVec; 2] = mem::zeroed(); + assert_eq!(1, buf.bytes_vec_mut(&mut dst[..])); + } +} diff --git a/bytes/tests/test_bytes.rs b/bytes/tests/test_bytes.rs new file mode 100644 index 000000000..4cf340e6a --- /dev/null +++ b/bytes/tests/test_bytes.rs @@ -0,0 +1,773 @@ +extern crate bytes; + +use bytes::{Bytes, BytesMut, BufMut, IntoBuf}; + +const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb"; +const SHORT: &'static [u8] = b"hello world"; + +fn inline_cap() -> usize { + use std::mem; + 4 * mem::size_of::() - 1 +} + +fn is_sync() {} +fn is_send() {} + +#[test] +fn test_bounds() { + is_sync::(); + is_sync::(); + is_send::(); + is_send::(); +} + +#[test] +fn from_slice() { + let a = Bytes::from(&b"abcdefgh"[..]); + assert_eq!(a, b"abcdefgh"[..]); + assert_eq!(a, &b"abcdefgh"[..]); + assert_eq!(a, Vec::from(&b"abcdefgh"[..])); + assert_eq!(b"abcdefgh"[..], a); + assert_eq!(&b"abcdefgh"[..], a); + assert_eq!(Vec::from(&b"abcdefgh"[..]), a); + + let a = BytesMut::from(&b"abcdefgh"[..]); + assert_eq!(a, b"abcdefgh"[..]); + assert_eq!(a, &b"abcdefgh"[..]); + assert_eq!(a, Vec::from(&b"abcdefgh"[..])); + assert_eq!(b"abcdefgh"[..], a); + assert_eq!(&b"abcdefgh"[..], a); + assert_eq!(Vec::from(&b"abcdefgh"[..]), a); +} + +#[test] +fn fmt() { + let a = format!("{:?}", Bytes::from(&b"abcdefg"[..])); + let b = "b\"abcdefg\""; + + assert_eq!(a, b); + + let a = format!("{:?}", BytesMut::from(&b"abcdefg"[..])); + assert_eq!(a, b); +} + +#[test] +fn fmt_write() { + use std::fmt::Write; + use std::iter::FromIterator; + let s = String::from_iter((0..10).map(|_| "abcdefg")); + + let mut a = BytesMut::with_capacity(64); + write!(a, "{}", &s[..64]).unwrap(); + assert_eq!(a, s[..64].as_bytes()); + + + let mut b = BytesMut::with_capacity(64); + write!(b, "{}", &s[..32]).unwrap(); + write!(b, "{}", &s[32..64]).unwrap(); + assert_eq!(b, s[..64].as_bytes()); + + + let mut c = BytesMut::with_capacity(64); + write!(c, "{}", s).unwrap_err(); + assert!(c.is_empty()); +} + +#[test] +fn len() { + let a = Bytes::from(&b"abcdefg"[..]); + assert_eq!(a.len(), 7); + + let a = BytesMut::from(&b"abcdefg"[..]); + assert_eq!(a.len(), 7); + + let a = Bytes::from(&b""[..]); + assert!(a.is_empty()); + + let a = BytesMut::from(&b""[..]); + assert!(a.is_empty()); +} + +#[test] +fn index() { + let a = Bytes::from(&b"hello world"[..]); + assert_eq!(a[0..5], *b"hello"); +} + +#[test] +fn slice() { + let a = Bytes::from(&b"hello world"[..]); + + let b = a.slice(3, 5); + assert_eq!(b, b"lo"[..]); + + let b = a.slice(0, 0); + assert_eq!(b, b""[..]); + + let b = a.slice(3, 3); + assert_eq!(b, b""[..]); + + let b = a.slice(a.len(), a.len()); + assert_eq!(b, b""[..]); + + let b = a.slice_to(5); + assert_eq!(b, b"hello"[..]); + + let b = a.slice_from(3); + assert_eq!(b, b"lo world"[..]); +} + +#[test] +#[should_panic] +fn slice_oob_1() { + let a = Bytes::from(&b"hello world"[..]); + a.slice(5, inline_cap() + 1); +} + +#[test] +#[should_panic] +fn slice_oob_2() { + let a = Bytes::from(&b"hello world"[..]); + a.slice(inline_cap() + 1, inline_cap() + 5); +} + +#[test] +fn split_off() { + let mut hello = Bytes::from(&b"helloworld"[..]); + let world = hello.split_off(5); + + assert_eq!(hello, &b"hello"[..]); + assert_eq!(world, &b"world"[..]); + + let mut hello = BytesMut::from(&b"helloworld"[..]); + let world = hello.split_off(5); + + assert_eq!(hello, &b"hello"[..]); + assert_eq!(world, &b"world"[..]); +} + +#[test] +#[should_panic] +fn split_off_oob() { + let mut hello = Bytes::from(&b"helloworld"[..]); + hello.split_off(inline_cap() + 1); +} + +#[test] +fn split_off_uninitialized() { + let mut bytes = BytesMut::with_capacity(1024); + let other = bytes.split_off(128); + + assert_eq!(bytes.len(), 0); + assert_eq!(bytes.capacity(), 128); + + assert_eq!(other.len(), 0); + assert_eq!(other.capacity(), 896); +} + +#[test] +fn split_off_to_loop() { + let s = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for i in 0..(s.len() + 1) { + { + let mut bytes = Bytes::from(&s[..]); + let off = bytes.split_off(i); + assert_eq!(i, bytes.len()); + let mut sum = Vec::new(); + sum.extend(&bytes); + sum.extend(&off); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = BytesMut::from(&s[..]); + let off = bytes.split_off(i); + assert_eq!(i, bytes.len()); + let mut sum = Vec::new(); + sum.extend(&bytes); + sum.extend(&off); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = Bytes::from(&s[..]); + let off = bytes.split_to(i); + assert_eq!(i, off.len()); + let mut sum = Vec::new(); + sum.extend(&off); + sum.extend(&bytes); + assert_eq!(&s[..], &sum[..]); + } + { + let mut bytes = BytesMut::from(&s[..]); + let off = bytes.split_to(i); + assert_eq!(i, off.len()); + let mut sum = Vec::new(); + sum.extend(&off); + sum.extend(&bytes); + assert_eq!(&s[..], &sum[..]); + } + } +} + +#[test] +fn split_to_1() { + // Inline + let mut a = Bytes::from(SHORT); + let b = a.split_to(4); + + assert_eq!(SHORT[4..], a); + assert_eq!(SHORT[..4], b); + + // Allocated + let mut a = Bytes::from(LONG); + let b = a.split_to(4); + + assert_eq!(LONG[4..], a); + assert_eq!(LONG[..4], b); + + let mut a = Bytes::from(LONG); + let b = a.split_to(30); + + assert_eq!(LONG[30..], a); + assert_eq!(LONG[..30], b); +} + +#[test] +fn split_to_2() { + let mut a = Bytes::from(LONG); + assert_eq!(LONG, a); + + let b = a.split_to(1); + + assert_eq!(LONG[1..], a); + drop(b); +} + +#[test] +#[should_panic] +fn split_to_oob() { + let mut hello = Bytes::from(&b"helloworld"[..]); + hello.split_to(inline_cap() + 1); +} + +#[test] +#[should_panic] +fn split_to_oob_mut() { + let mut hello = BytesMut::from(&b"helloworld"[..]); + hello.split_to(inline_cap() + 1); +} + +#[test] +fn split_to_uninitialized() { + let mut bytes = BytesMut::with_capacity(1024); + let other = bytes.split_to(128); + + assert_eq!(bytes.len(), 0); + assert_eq!(bytes.capacity(), 896); + + assert_eq!(other.len(), 0); + assert_eq!(other.capacity(), 128); +} + +#[test] +fn split_off_to_at_gt_len() { + fn make_bytes() -> Bytes { + let mut bytes = BytesMut::with_capacity(100); + bytes.put_slice(&[10, 20, 30, 40]); + bytes.freeze() + } + + use std::panic; + + make_bytes().split_to(4); + make_bytes().split_off(4); + + assert!(panic::catch_unwind(move || { + make_bytes().split_to(5); + }).is_err()); + + assert!(panic::catch_unwind(move || { + make_bytes().split_off(5); + }).is_err()); +} + +#[test] +fn fns_defined_for_bytes_mut() { + let mut bytes = BytesMut::from(&b"hello world"[..]); + + bytes.as_ptr(); + bytes.as_mut_ptr(); + + // Iterator + let v: Vec = bytes.iter().map(|b| *b).collect(); + assert_eq!(&v[..], bytes); +} + +#[test] +fn mut_into_buf() { + let mut v = vec![0, 0, 0, 0]; + let s = &mut v[..]; + s.into_buf().put_u32_le(42); +} + +#[test] +fn reserve_convert() { + // Inline -> Vec + let mut bytes = BytesMut::with_capacity(8); + bytes.put("hello"); + bytes.reserve(40); + assert_eq!(bytes.capacity(), 45); + assert_eq!(bytes, "hello"); + + // Inline -> Inline + let mut bytes = BytesMut::with_capacity(inline_cap()); + bytes.put("abcdefghijkl"); + + let a = bytes.split_to(10); + bytes.reserve(inline_cap() - 3); + assert_eq!(inline_cap(), bytes.capacity()); + + assert_eq!(bytes, "kl"); + assert_eq!(a, "abcdefghij"); + + // Vec -> Vec + let mut bytes = BytesMut::from(LONG); + bytes.reserve(64); + assert_eq!(bytes.capacity(), LONG.len() + 64); + + // Arc -> Vec + let mut bytes = BytesMut::from(LONG); + let a = bytes.split_to(30); + + bytes.reserve(128); + assert!(bytes.capacity() >= bytes.len() + 128); + + drop(a); +} + +#[test] +fn reserve_growth() { + let mut bytes = BytesMut::with_capacity(64); + bytes.put("hello world"); + let _ = bytes.take(); + + bytes.reserve(65); + assert_eq!(bytes.capacity(), 128); +} + +#[test] +fn reserve_allocates_at_least_original_capacity() { + let mut bytes = BytesMut::with_capacity(1024); + + for i in 0..1020 { + bytes.put(i as u8); + } + + let _other = bytes.take(); + + bytes.reserve(16); + assert_eq!(bytes.capacity(), 1024); +} + +#[test] +fn reserve_max_original_capacity_value() { + const SIZE: usize = 128 * 1024; + + let mut bytes = BytesMut::with_capacity(SIZE); + + for _ in 0..SIZE { + bytes.put(0u8); + } + + let _other = bytes.take(); + + bytes.reserve(16); + assert_eq!(bytes.capacity(), 64 * 1024); +} + +// Without either looking at the internals of the BytesMut or doing weird stuff +// with the memory allocator, there's no good way to automatically verify from +// within the program that this actually recycles memory. Instead, just exercise +// the code path to ensure that the results are correct. +#[test] +fn reserve_vec_recycling() { + let mut bytes = BytesMut::from(Vec::with_capacity(16)); + assert_eq!(bytes.capacity(), 16); + bytes.put("0123456789012345"); + bytes.advance(10); + assert_eq!(bytes.capacity(), 6); + bytes.reserve(8); + assert_eq!(bytes.capacity(), 16); +} + +#[test] +fn reserve_in_arc_unique_does_not_overallocate() { + let mut bytes = BytesMut::with_capacity(1000); + bytes.take(); + + // now bytes is Arc and refcount == 1 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(2001); + assert_eq!(2001, bytes.capacity()); +} + +#[test] +fn reserve_in_arc_unique_doubles() { + let mut bytes = BytesMut::with_capacity(1000); + bytes.take(); + + // now bytes is Arc and refcount == 1 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(1001); + assert_eq!(2000, bytes.capacity()); +} + +#[test] +fn reserve_in_arc_nonunique_does_not_overallocate() { + let mut bytes = BytesMut::with_capacity(1000); + let _copy = bytes.take(); + + // now bytes is Arc and refcount == 2 + + assert_eq!(1000, bytes.capacity()); + bytes.reserve(2001); + assert_eq!(2001, bytes.capacity()); +} + +#[test] +fn inline_storage() { + let mut bytes = BytesMut::with_capacity(inline_cap()); + let zero = [0u8; 64]; + + bytes.put(&zero[0..inline_cap()]); + assert_eq!(*bytes, zero[0..inline_cap()]); +} + +#[test] +fn extend_mut() { + let mut bytes = BytesMut::with_capacity(0); + bytes.extend(LONG); + assert_eq!(*bytes, LONG[..]); +} + +#[test] +fn extend_shr() { + let mut bytes = Bytes::new(); + bytes.extend(LONG); + assert_eq!(*bytes, LONG[..]); +} + +#[test] +fn extend_from_slice_mut() { + for &i in &[3, 34] { + let mut bytes = BytesMut::new(); + bytes.extend_from_slice(&LONG[..i]); + bytes.extend_from_slice(&LONG[i..]); + assert_eq!(LONG[..], *bytes); + } +} + +#[test] +fn extend_from_slice_shr() { + for &i in &[3, 34] { + let mut bytes = Bytes::new(); + bytes.extend_from_slice(&LONG[..i]); + bytes.extend_from_slice(&LONG[i..]); + assert_eq!(LONG[..], *bytes); + } +} + +#[test] +fn from_static() { + let mut a = Bytes::from_static(b"ab"); + let b = a.split_off(1); + + assert_eq!(a, b"a"[..]); + assert_eq!(b, b"b"[..]); +} + +#[test] +fn advance_inline() { + let mut a = Bytes::from(&b"hello world"[..]); + a.advance(6); + assert_eq!(a, &b"world"[..]); +} + +#[test] +fn advance_static() { + let mut a = Bytes::from_static(b"hello world"); + a.advance(6); + assert_eq!(a, &b"world"[..]); +} + +#[test] +fn advance_vec() { + let mut a = BytesMut::from(b"hello world boooo yah world zomg wat wat".to_vec()); + a.advance(16); + assert_eq!(a, b"o yah world zomg wat wat"[..]); + + a.advance(4); + assert_eq!(a, b"h world zomg wat wat"[..]); + + // Reserve some space. + a.reserve(1024); + assert_eq!(a, b"h world zomg wat wat"[..]); + + a.advance(6); + assert_eq!(a, b"d zomg wat wat"[..]); +} + +#[test] +#[should_panic] +fn advance_past_len() { + let mut a = BytesMut::from(b"hello world".to_vec()); + a.advance(20); +} + +#[test] +// Only run these tests on little endian systems. CI uses qemu for testing +// little endian... and qemu doesn't really support threading all that well. +#[cfg(target_endian = "little")] +fn stress() { + // Tests promoting a buffer from a vec -> shared in a concurrent situation + use std::sync::{Arc, Barrier}; + use std::thread; + + const THREADS: usize = 8; + const ITERS: usize = 1_000; + + for i in 0..ITERS { + let data = [i as u8; 256]; + let buf = Arc::new(Bytes::from(&data[..])); + + let barrier = Arc::new(Barrier::new(THREADS)); + let mut joins = Vec::with_capacity(THREADS); + + for _ in 0..THREADS { + let c = barrier.clone(); + let buf = buf.clone(); + + joins.push(thread::spawn(move || { + c.wait(); + let buf: Bytes = (*buf).clone(); + drop(buf); + })); + } + + for th in joins { + th.join().unwrap(); + } + + assert_eq!(*buf, data[..]); + } +} + +#[test] +fn partial_eq_bytesmut() { + let bytes = Bytes::from(&b"The quick red fox"[..]); + let bytesmut = BytesMut::from(&b"The quick red fox"[..]); + assert!(bytes == bytesmut); + assert!(bytesmut == bytes); + let bytes2 = Bytes::from(&b"Jumped over the lazy brown dog"[..]); + assert!(bytes2 != bytesmut); + assert!(bytesmut != bytes2); +} + +#[test] +fn unsplit_basic() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + let splitted = buf.split_off(6); + assert_eq!(b"aaabbb", &buf[..]); + assert_eq!(b"cccddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn unsplit_empty_other() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaabbbcccddd"); + + // empty other + let other = BytesMut::new(); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn unsplit_empty_self() { + // empty self + let mut buf = BytesMut::new(); + + let mut other = BytesMut::with_capacity(64); + other.extend_from_slice(b"aaabbbcccddd"); + + buf.unsplit(other); + assert_eq!(b"aaabbbcccddd", &buf[..]); +} + +#[test] +fn unsplit_inline_arc() { + let mut buf = BytesMut::with_capacity(8); //inline + buf.extend_from_slice(b"aaaabbbb"); + + let mut buf2 = BytesMut::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn unsplit_arc_inline() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + buf.split_off(8); //arc + + let mut buf2 = BytesMut::with_capacity(8); //inline + buf2.extend_from_slice(b"ccccdddd"); + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); + +} + +#[test] +fn unsplit_both_inline() { + let mut buf = BytesMut::with_capacity(16); //inline + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let splitted = buf.split_off(8); // both inline + assert_eq!(b"aaaabbbb", &buf[..]); + assert_eq!(b"ccccdddd", &splitted[..]); + + buf.unsplit(splitted); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + + +#[test] +fn unsplit_arc_different() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeee"); + + buf.split_off(8); //arc + + let mut buf2 = BytesMut::with_capacity(64); + buf2.extend_from_slice(b"ccccddddeeee"); + + buf2.split_off(8); //arc + + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn unsplit_arc_non_contiguous() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbeeeeccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + + let buf3 = buf2.split_off(4); //arc + + buf.unsplit(buf3); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn unsplit_two_split_offs() { + let mut buf = BytesMut::with_capacity(64); + buf.extend_from_slice(b"aaaabbbbccccdddd"); + + let mut buf2 = buf.split_off(8); //arc + let buf3 = buf2.split_off(4); //arc + + buf2.unsplit(buf3); + buf.unsplit(buf2); + assert_eq!(b"aaaabbbbccccdddd", &buf[..]); +} + +#[test] +fn from_iter_no_size_hint() { + use std::iter; + + let mut expect = vec![]; + + let actual: Bytes = iter::repeat(b'x') + .scan(100, |cnt, item| { + if *cnt >= 1 { + *cnt -= 1; + expect.push(item); + Some(item) + } else { + None + } + }) + .collect(); + + assert_eq!(&actual[..], &expect[..]); +} + +fn test_slice_ref(bytes: &Bytes, start: usize, end: usize, expected: &[u8]) { + let slice = &(bytes.as_ref()[start..end]); + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], expected); +} + +#[test] +fn slice_ref_works() { + let bytes = Bytes::from(&b"012345678"[..]); + + test_slice_ref(&bytes, 0, 0, b""); + test_slice_ref(&bytes, 0, 3, b"012"); + test_slice_ref(&bytes, 2, 6, b"2345"); + test_slice_ref(&bytes, 7, 9, b"78"); + test_slice_ref(&bytes, 9, 9, b""); +} + + +#[test] +fn slice_ref_empty() { + let bytes = Bytes::from(&b""[..]); + let slice = &(bytes.as_ref()[0..0]); + + let sub = bytes.slice_ref(&slice); + assert_eq!(&sub[..], b""); +} + +#[test] +#[should_panic] +fn slice_ref_catches_not_a_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b"012345"[0..4]; + + bytes.slice_ref(slice); +} + +#[test] +#[should_panic] +fn slice_ref_catches_not_an_empty_subset() { + let bytes = Bytes::from(&b"012345678"[..]); + let slice = &b""[0..0]; + + bytes.slice_ref(slice); +} + +#[test] +#[should_panic] +fn empty_slice_ref_catches_not_an_empty_subset() { + let bytes = Bytes::from(&b""[..]); + let slice = &b""[0..0]; + + bytes.slice_ref(slice); +} diff --git a/bytes/tests/test_chain.rs b/bytes/tests/test_chain.rs new file mode 100644 index 000000000..2789e7c06 --- /dev/null +++ b/bytes/tests/test_chain.rs @@ -0,0 +1,122 @@ +extern crate bytes; +extern crate iovec; + +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use bytes::buf::Chain; +use iovec::IoVec; +use std::io::Cursor; + +#[test] +fn collect_two_bufs() { + let a = Cursor::new(Bytes::from(&b"hello"[..])); + let b = Cursor::new(Bytes::from(&b"world"[..])); + + let res: Vec = a.chain(b).collect(); + assert_eq!(res, &b"helloworld"[..]); +} + +#[test] +fn writing_chained() { + let mut a = BytesMut::with_capacity(64); + let mut b = BytesMut::with_capacity(64); + + { + let mut buf = Chain::new(&mut a, &mut b); + + for i in 0..128 { + buf.put(i as u8); + } + } + + assert_eq!(64, a.len()); + assert_eq!(64, b.len()); + + for i in 0..64 { + let expect = i as u8; + assert_eq!(expect, a[i]); + assert_eq!(expect + 64, b[i]); + } +} + +#[test] +fn iterating_two_bufs() { + let a = Cursor::new(Bytes::from(&b"hello"[..])); + let b = Cursor::new(Bytes::from(&b"world"[..])); + + let res: Vec = a.chain(b).iter().collect(); + assert_eq!(res, &b"helloworld"[..]); +} + +#[test] +fn vectored_read() { + let a = Cursor::new(Bytes::from(&b"hello"[..])); + let b = Cursor::new(Bytes::from(&b"world"[..])); + + let mut buf = a.chain(b); + + { + let b1: &[u8] = &mut [0]; + let b2: &[u8] = &mut [0]; + let b3: &[u8] = &mut [0]; + let b4: &[u8] = &mut [0]; + let mut iovecs: [&IoVec; 4] = + [b1.into(), b2.into(), b3.into(), b4.into()]; + + assert_eq!(2, buf.bytes_vec(&mut iovecs)); + assert_eq!(iovecs[0][..], b"hello"[..]); + assert_eq!(iovecs[1][..], b"world"[..]); + assert_eq!(iovecs[2][..], b"\0"[..]); + assert_eq!(iovecs[3][..], b"\0"[..]); + } + + buf.advance(2); + + { + let b1: &[u8] = &mut [0]; + let b2: &[u8] = &mut [0]; + let b3: &[u8] = &mut [0]; + let b4: &[u8] = &mut [0]; + let mut iovecs: [&IoVec; 4] = + [b1.into(), b2.into(), b3.into(), b4.into()]; + + assert_eq!(2, buf.bytes_vec(&mut iovecs)); + assert_eq!(iovecs[0][..], b"llo"[..]); + assert_eq!(iovecs[1][..], b"world"[..]); + assert_eq!(iovecs[2][..], b"\0"[..]); + assert_eq!(iovecs[3][..], b"\0"[..]); + } + + buf.advance(3); + + { + let b1: &[u8] = &mut [0]; + let b2: &[u8] = &mut [0]; + let b3: &[u8] = &mut [0]; + let b4: &[u8] = &mut [0]; + let mut iovecs: [&IoVec; 4] = + [b1.into(), b2.into(), b3.into(), b4.into()]; + + assert_eq!(1, buf.bytes_vec(&mut iovecs)); + assert_eq!(iovecs[0][..], b"world"[..]); + assert_eq!(iovecs[1][..], b"\0"[..]); + assert_eq!(iovecs[2][..], b"\0"[..]); + assert_eq!(iovecs[3][..], b"\0"[..]); + } + + buf.advance(3); + + { + let b1: &[u8] = &mut [0]; + let b2: &[u8] = &mut [0]; + let b3: &[u8] = &mut [0]; + let b4: &[u8] = &mut [0]; + let mut iovecs: [&IoVec; 4] = + [b1.into(), b2.into(), b3.into(), b4.into()]; + + assert_eq!(1, buf.bytes_vec(&mut iovecs)); + assert_eq!(iovecs[0][..], b"ld"[..]); + assert_eq!(iovecs[1][..], b"\0"[..]); + assert_eq!(iovecs[2][..], b"\0"[..]); + assert_eq!(iovecs[3][..], b"\0"[..]); + } +} diff --git a/bytes/tests/test_debug.rs b/bytes/tests/test_debug.rs new file mode 100644 index 000000000..9945a2835 --- /dev/null +++ b/bytes/tests/test_debug.rs @@ -0,0 +1,35 @@ +extern crate bytes; + +use bytes::Bytes; + +#[test] +fn fmt() { + let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect(); + + let expected = "b\"\ + \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\ + \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\ + \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\ + \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\ + \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\ + @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\ + `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ + \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\ + \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ + \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\ + \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ + \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\ + \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ + \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\ + \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ + \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\ + \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ + \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\ + \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ + \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\ + \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ + \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\ + \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\""; + + assert_eq!(expected, format!("{:?}", Bytes::from(vec))); +} diff --git a/bytes/tests/test_from_buf.rs b/bytes/tests/test_from_buf.rs new file mode 100644 index 000000000..216bf1232 --- /dev/null +++ b/bytes/tests/test_from_buf.rs @@ -0,0 +1,34 @@ +extern crate bytes; + +use bytes::{Buf, Bytes, BytesMut}; +use std::io::Cursor; + +const LONG: &'static [u8] = b"mary had a little lamb, little lamb, little lamb"; +const SHORT: &'static [u8] = b"hello world"; + +#[test] +fn collect_to_vec() { + let buf: Vec = Cursor::new(SHORT).collect(); + assert_eq!(buf, SHORT); + + let buf: Vec = Cursor::new(LONG).collect(); + assert_eq!(buf, LONG); +} + +#[test] +fn collect_to_bytes() { + let buf: Bytes = Cursor::new(SHORT).collect(); + assert_eq!(buf, SHORT); + + let buf: Bytes = Cursor::new(LONG).collect(); + assert_eq!(buf, LONG); +} + +#[test] +fn collect_to_bytes_mut() { + let buf: BytesMut = Cursor::new(SHORT).collect(); + assert_eq!(buf, SHORT); + + let buf: BytesMut = Cursor::new(LONG).collect(); + assert_eq!(buf, LONG); +} diff --git a/bytes/tests/test_iter.rs b/bytes/tests/test_iter.rs new file mode 100644 index 000000000..c16dbf694 --- /dev/null +++ b/bytes/tests/test_iter.rs @@ -0,0 +1,22 @@ +extern crate bytes; + +use bytes::{Buf, IntoBuf, Bytes}; + +#[test] +fn iter_len() { + let buf = Bytes::from(&b"hello world"[..]).into_buf(); + let iter = buf.iter(); + + assert_eq!(iter.size_hint(), (11, Some(11))); + assert_eq!(iter.len(), 11); +} + + +#[test] +fn empty_iter_len() { + let buf = Bytes::from(&b""[..]).into_buf(); + let iter = buf.iter(); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.len(), 0); +} diff --git a/bytes/tests/test_reader.rs b/bytes/tests/test_reader.rs new file mode 100644 index 000000000..7103f3592 --- /dev/null +++ b/bytes/tests/test_reader.rs @@ -0,0 +1,28 @@ +extern crate bytes; + +use std::io::{BufRead, Cursor, Read}; + +use bytes::Buf; + +#[test] +fn read() { + let buf1 = Cursor::new(b"hello "); + let buf2 = Cursor::new(b"world"); + let buf = Buf::chain(buf1, buf2); // Disambiguate with Read::chain + let mut buffer = Vec::new(); + buf.reader().read_to_end(&mut buffer).unwrap(); + assert_eq!(b"hello world", &buffer[..]); +} + +#[test] +fn buf_read() { + let buf1 = Cursor::new(b"hell"); + let buf2 = Cursor::new(b"o\nworld"); + let mut reader = Buf::chain(buf1, buf2).reader(); + let mut line = String::new(); + reader.read_line(&mut line).unwrap(); + assert_eq!("hello\n", &line); + line.clear(); + reader.read_line(&mut line).unwrap(); + assert_eq!("world", &line); +} diff --git a/bytes/tests/test_serde.rs b/bytes/tests/test_serde.rs new file mode 100644 index 000000000..ff440242f --- /dev/null +++ b/bytes/tests/test_serde.rs @@ -0,0 +1,21 @@ +#![cfg(feature = "serde")] + +extern crate bytes; +extern crate serde_test; +use serde_test::{Token, assert_tokens}; + +#[test] +fn test_ser_de_empty() { + let b = bytes::Bytes::new(); + assert_tokens(&b, &[Token::Bytes(b"")]); + let b = bytes::BytesMut::with_capacity(0); + assert_tokens(&b, &[Token::Bytes(b"")]); +} + +#[test] +fn test_ser_de() { + let b = bytes::Bytes::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); + let b = bytes::BytesMut::from(&b"bytes"[..]); + assert_tokens(&b, &[Token::Bytes(b"bytes")]); +} diff --git a/bytes/tests/test_take.rs b/bytes/tests/test_take.rs new file mode 100644 index 000000000..93e0c6c5a --- /dev/null +++ b/bytes/tests/test_take.rs @@ -0,0 +1,13 @@ +extern crate bytes; + +use bytes::Buf; +use std::io::Cursor; + +#[test] +fn long_take() { + // Tests that take with a size greater than the buffer length will not + // overrun the buffer. Regression test for #138. + let buf = Cursor::new(b"hello world").take(100); + assert_eq!(11, buf.remaining()); + assert_eq!(b"hello world", buf.bytes()); +} diff --git a/bytesize/.cargo-checksum.json b/bytesize/.cargo-checksum.json new file mode 100644 index 000000000..f6f4569a9 --- /dev/null +++ b/bytesize/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"} \ No newline at end of file diff --git a/bytesize/Cargo.toml b/bytesize/Cargo.toml new file mode 100644 index 000000000..f40b67071 --- /dev/null +++ b/bytesize/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bytesize" +version = "1.0.0" +authors = ["Hyunsik Choi "] +description = "an utility for human-readable bytes representations" +homepage = "https://github.com/hyunsik/bytesize/" +documentation = "https://docs.rs/bytesize/" +readme = "README.md" +keywords = ["byte", "byte-size", "utility", "human-readable", "format"] +license = "Apache-2.0" +repository = "https://github.com/hyunsik/bytesize/" +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true diff --git a/bytesize/LICENSE b/bytesize/LICENSE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/bytesize/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/bytesize/README.md b/bytesize/README.md new file mode 100644 index 000000000..9c3464d0e --- /dev/null +++ b/bytesize/README.md @@ -0,0 +1,95 @@ +## ByteSize +[![Build Status](https://travis-ci.org/hyunsik/bytesize.svg?branch=master)](https://travis-ci.org/hyunsik/bytesize) +[![Crates.io Version](https://img.shields.io/crates/v/bytesize.svg)](https://crates.io/crates/bytesize) + + +ByteSize is an utility for human-readable byte count representation. + +[API Documentation](https://docs.rs/bytesize/) + +## Usage + +Add this to your Cargo.toml: + +```toml +[dependencies] +bytesize = "1.0.0" +``` + +and this to your crate root: +```rust +extern crate bytesize; +``` + +## Example +### Human readable representations (SI unit and Binary unit) +```rust +#[allow(dead_code)] +fn assert_display(expected: &str, b: ByteSize) { + assert_eq!(expected, format!("{}", b)); +} + +#[test] + fn test_display() { + assert_display("215 B", ByteSize(215)); + assert_display("215 B", ByteSize::b(215)); + assert_display("1.0 KB", ByteSize::kb(1)); + assert_display("301.0 KB", ByteSize::kb(301)); + assert_display("419.0 MB", ByteSize::mb(419)); + assert_display("518.0 GB", ByteSize::gb(518)); + assert_display("815.0 TB", ByteSize::tb(815)); + assert_display("609.0 PB", ByteSize::pb(609)); + } + + fn assert_to_string(expected: &str, b: ByteSize, si: bool) { + assert_eq!(expected.to_string(), b.to_string_as(si)); + } + + #[test] + fn test_to_string() { + assert_to_string("215 B", ByteSize(215), true); + assert_to_string("215 B", ByteSize(215), false); + + assert_to_string("215 B", ByteSize::b(215), true); + assert_to_string("215 B", ByteSize::b(215), false); + + assert_to_string("1.0 kiB", ByteSize::kib(1), true); + assert_to_string("1.0 KB", ByteSize::kib(1), false); + + assert_to_string("293.9 kiB", ByteSize::kb(301), true); + assert_to_string("301.0 KB", ByteSize::kb(301), false); + + assert_to_string("1.0 MiB", ByteSize::mib(1), true); + assert_to_string("1048.6 KB", ByteSize::mib(1), false); + + assert_to_string("399.6 MiB", ByteSize::mb(419), true); + assert_to_string("419.0 MB", ByteSize::mb(419), false); + + assert_to_string("482.4 GiB", ByteSize::gb(518), true); + assert_to_string("518.0 GB", ByteSize::gb(518), false); + + assert_to_string("741.2 TiB", ByteSize::tb(815), true); + assert_to_string("815.0 TB", ByteSize::tb(815), false); + + assert_to_string("540.9 PiB", ByteSize::pb(609), true); + assert_to_string("609.0 PB", ByteSize::pb(609), false); +} +``` + +### Arithmetic operations +```rust +extern crate bytesize; + +use bytesize::ByteSize; + +fn byte_arithmetic_operator() { + let x = ByteSize::mb(1); + let y = ByteSize::kb(100); + + let plus = x + y; + print!("{}", plus); + + let minus = ByteSize::tb(100) + ByteSize::gb(4); + print!("{}", minus); +} +``` diff --git a/bytesize/src/lib.rs b/bytesize/src/lib.rs new file mode 100644 index 000000000..26ffbd6ef --- /dev/null +++ b/bytesize/src/lib.rs @@ -0,0 +1,365 @@ +//! ByteSize is an utility that easily makes bytes size representation +//! and helps its arithmetic operations. +//! +//! ## Example +//! +//! ```ignore +//! extern crate bytesize; +//! +//! use bytesize::ByteSize; +//! +//! fn byte_arithmetic_operator() { +//! let x = ByteSize::mb(1); +//! let y = ByteSize::kb(100); +//! +//! let plus = x + y; +//! print!("{} bytes", plus.as_u64()); +//! +//! let minus = ByteSize::tb(100) - ByteSize::gb(4); +//! print!("{} bytes", minus.as_u64()); +//! } +//! ``` +//! +//! It also provides its human readable string as follows: +//! +//! ```ignore= +//! assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true)); +//! assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false)); +//! ``` + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +use std::fmt::{Debug, Display, Formatter, Result}; +use std::ops::{Add, Mul}; + +/// byte size for 1 byte +pub const B: u64 = 1; +/// bytes size for 1 kilobyte +pub const KB: u64 = 1_000; +/// bytes size for 1 megabyte +pub const MB: u64 = 1_000_000; +/// bytes size for 1 gigabyte +pub const GB: u64 = 1_000_000_000; +/// bytes size for 1 terabyte +pub const TB: u64 = 1_000_000_000_000; +/// bytes size for 1 petabyte +pub const PB: u64 = 1_000_000_000_000_000; + +/// bytes size for 1 kibibyte +pub const KIB: u64 = 1_024; +/// bytes size for 1 mebibyte +pub const MIB: u64 = 1_048_576; +/// bytes size for 1 gibibyte +pub const GIB: u64 = 1_073_741_824; +/// bytes size for 1 tebibyte +pub const TIB: u64 = 1_099_511_627_776; +/// bytes size for 1 pebibyte +pub const PIB: u64 = 1_125_899_906_842_624; + +static UNITS: &'static str = "KMGTPE"; +static UNITS_SI: &'static str = "kMGTPE"; +static LN_KB: f64 = 6.931471806; // ln 1024 +static LN_KIB: f64 = 6.907755279; // ln 1000 + +pub fn kb>(size: V) -> u64 { + size.into() * KB +} + +pub fn kib>(size: V) -> u64 { + size.into() * KIB +} + +pub fn mb>(size: V) -> u64 { + size.into() * MB +} + +pub fn mib>(size: V) -> u64 { + size.into() * MIB +} + +pub fn gb>(size: V) -> u64 { + size.into() * GB +} + +pub fn gib>(size: V) -> u64 { + size.into() * GIB +} + +pub fn tb>(size: V) -> u64 { + size.into() * TB +} + +pub fn tib>(size: V) -> u64 { + size.into() * TIB +} + +pub fn pb>(size: V) -> u64 { + size.into() * PB +} + +pub fn pib>(size: V) -> u64 { + size.into() * PIB +} + +/// Byte size representation +#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ByteSize(pub u64); + +impl ByteSize { + #[inline(always)] + pub fn b(size: u64) -> ByteSize { + ByteSize(size) + } + + #[inline(always)] + pub fn kb(size: u64) -> ByteSize { + ByteSize(size * KB) + } + + #[inline(always)] + pub fn kib(size: u64) -> ByteSize { + ByteSize(size * KIB) + } + + #[inline(always)] + pub fn mb(size: u64) -> ByteSize { + ByteSize(size * MB) + } + + #[inline(always)] + pub fn mib(size: u64) -> ByteSize { + ByteSize(size * MIB) + } + + #[inline(always)] + pub fn gb(size: u64) -> ByteSize { + ByteSize(size * GB) + } + + #[inline(always)] + pub fn gib(size: u64) -> ByteSize { + ByteSize(size * GIB) + } + + #[inline(always)] + pub fn tb(size: u64) -> ByteSize { + ByteSize(size * TB) + } + + #[inline(always)] + pub fn tib(size: u64) -> ByteSize { + ByteSize(size * TIB) + } + + #[inline(always)] + pub fn pb(size: u64) -> ByteSize { + ByteSize(size * PB) + } + + #[inline(always)] + pub fn pib(size: u64) -> ByteSize { + ByteSize(size * PIB) + } + + #[inline(always)] + pub fn as_u64(&self) -> u64 { + self.0 + } + + #[inline(always)] + pub fn to_string_as(&self, si_unit: bool) -> String { + to_string(self.0, si_unit) + } +} + +pub fn to_string(bytes: u64, si_prefix: bool) -> String { + let unit = if si_prefix { KIB } else { KB }; + let unit_base = if si_prefix { LN_KIB } else { LN_KB }; + let unit_prefix = if si_prefix { + UNITS_SI.as_bytes() + } else { + UNITS.as_bytes() + }; + let unit_suffix = if si_prefix { "iB" } else { "B" }; + + if bytes < unit { + format!("{} B", bytes) + } else { + let size = bytes as f64; + let exp = match (size.ln() / unit_base) as usize { + e if e == 0 => 1, + e => e, + }; + + format!( + "{:.1} {}{}", + (size / unit.pow(exp as u32) as f64), + unit_prefix[exp - 1] as char, + unit_suffix + ) + } +} + +impl Display for ByteSize { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "{}", to_string(self.0, false)) + } +} + +impl Debug for ByteSize { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "{}", self) + } +} + +macro_rules! commutative_op { + ($t:ty) => { + impl Add<$t> for ByteSize { + type Output = ByteSize; + #[inline(always)] + fn add(self, rhs: $t) -> ByteSize { + ByteSize(self.0 + (rhs as u64)) + } + } + + impl Add for $t { + type Output = ByteSize; + #[inline(always)] + fn add(self, rhs: ByteSize) -> ByteSize { + ByteSize(rhs.0 + (self as u64)) + } + } + + impl Mul<$t> for ByteSize { + type Output = ByteSize; + #[inline(always)] + fn mul(self, rhs: $t) -> ByteSize { + ByteSize(self.0 * (rhs as u64)) + } + } + + impl Mul for $t { + type Output = ByteSize; + #[inline(always)] + fn mul(self, rhs: ByteSize) -> ByteSize { + ByteSize(rhs.0 * (self as u64)) + } + } + }; +} + +commutative_op!(u64); +commutative_op!(u32); +commutative_op!(u16); +commutative_op!(u8); + +impl Add for ByteSize { + type Output = ByteSize; + + #[inline(always)] + fn add(self, rhs: ByteSize) -> ByteSize { + ByteSize(self.0 + rhs.0) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_arithmetic_op() { + let x = ByteSize::mb(1); + let y = ByteSize::kb(100); + + assert_eq!((x + y).as_u64(), 1_100_000u64); + + assert_eq!((x + (100 * 1000) as u64).as_u64(), 1_100_000); + + assert_eq!((x * 2u64).as_u64(), 2_000_000); + } + + #[test] + fn test_arithmetic_primitives() { + let x = ByteSize::mb(1); + + assert_eq!((x + MB as u64).as_u64(), 2_000_000); + + assert_eq!((x + MB as u32).as_u64(), 2_000_000); + + assert_eq!((x + KB as u16).as_u64(), 1_001_000); + + assert_eq!((x + B as u8).as_u64(), 1_000_001); + } + + #[test] + fn test_comparison() { + assert!(ByteSize::mb(1) == ByteSize::kb(1000)); + assert!(ByteSize::mib(1) == ByteSize::kib(1024)); + assert!(ByteSize::mb(1) != ByteSize::kib(1024)); + assert!(ByteSize::mb(1) < ByteSize::kib(1024)); + assert!(ByteSize::b(0) < ByteSize::tib(1)); + } + + fn assert_display(expected: &str, b: ByteSize) { + assert_eq!(expected, format!("{}", b)); + } + + #[test] + fn test_display() { + assert_display("215 B", ByteSize::b(215)); + assert_display("1.0 KB", ByteSize::kb(1)); + assert_display("301.0 KB", ByteSize::kb(301)); + assert_display("419.0 MB", ByteSize::mb(419)); + assert_display("518.0 GB", ByteSize::gb(518)); + assert_display("815.0 TB", ByteSize::tb(815)); + assert_display("609.0 PB", ByteSize::pb(609)); + } + + fn assert_to_string(expected: &str, b: ByteSize, si: bool) { + assert_eq!(expected.to_string(), b.to_string_as(si)); + } + + #[test] + fn test_to_string_as() { + assert_to_string("215 B", ByteSize::b(215), true); + assert_to_string("215 B", ByteSize::b(215), false); + + assert_to_string("1.0 kiB", ByteSize::kib(1), true); + assert_to_string("1.0 KB", ByteSize::kib(1), false); + + assert_to_string("293.9 kiB", ByteSize::kb(301), true); + assert_to_string("301.0 KB", ByteSize::kb(301), false); + + assert_to_string("1.0 MiB", ByteSize::mib(1), true); + assert_to_string("1048.6 KB", ByteSize::mib(1), false); + + // a bug case: https://github.com/flang-project/bytesize/issues/8 + assert_to_string("1.9 GiB", ByteSize::mib(1907), true); + assert_to_string("2.0 GB", ByteSize::mib(1908), false); + + assert_to_string("399.6 MiB", ByteSize::mb(419), true); + assert_to_string("419.0 MB", ByteSize::mb(419), false); + + assert_to_string("482.4 GiB", ByteSize::gb(518), true); + assert_to_string("518.0 GB", ByteSize::gb(518), false); + + assert_to_string("741.2 TiB", ByteSize::tb(815), true); + assert_to_string("815.0 TB", ByteSize::tb(815), false); + + assert_to_string("540.9 PiB", ByteSize::pb(609), true); + assert_to_string("609.0 PB", ByteSize::pb(609), false); + } + + #[test] + fn test_default() { + assert_eq!(ByteSize::b(0), ByteSize::default()); + } + + #[test] + fn test_to_string() { + assert_to_string("609.0 PB", ByteSize::pb(609), false); + } +} diff --git a/cc/.cargo-checksum.json b/cc/.cargo-checksum.json new file mode 100644 index 000000000..ae7b7ad52 --- /dev/null +++ b/cc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"} \ No newline at end of file diff --git a/cc/Cargo.toml b/cc/Cargo.toml new file mode 100644 index 000000000..10cd06006 --- /dev/null +++ b/cc/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cc" +version = "1.0.37" +authors = ["Alex Crichton "] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" +homepage = "https://github.com/alexcrichton/cc-rs" +documentation = "https://docs.rs/cc" +readme = "README.md" +keywords = ["build-dependencies"] +categories = ["development-tools::build-utils"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cc-rs" +[dependencies.rayon] +version = "1.0" +optional = true +[dev-dependencies.tempdir] +version = "0.3" + +[features] +parallel = ["rayon"] diff --git a/cc/LICENSE-APACHE b/cc/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/cc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cc/LICENSE-MIT b/cc/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/cc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cc/README.md b/cc/README.md new file mode 100644 index 000000000..e3c6ad006 --- /dev/null +++ b/cc/README.md @@ -0,0 +1,202 @@ +# cc-rs + +A library to compile C/C++/assembly into a Rust library/application. + +[![Build Status](https://dev.azure.com/alexcrichton/cc-rs/_apis/build/status/alexcrichton.cc-rs?branchName=master)](https://dev.azure.com/alexcrichton/cc-rs/_build/latest?definitionId=5&branchName=master) + +[Documentation](https://docs.rs/cc) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. This crate calls out +to the most relevant compiler for a platform, for example using `cl` on MSVC. + +> **Note**: this crate was recently renamed from the `gcc` crate, so if you're +> looking for the `gcc` crate you're in the right spot! + +## Using cc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[build-dependencies] +cc = "1.0" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +extern crate cc; + +fn main() { + cc::Build::new() + .file("foo.c") + .file("bar.c") + .compile("foo"); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into a file +named libfoo.a. You can call the functions in Rust by declaring functions in +your Rust code like so: + +``` +extern { + fn foo_function(); + fn bar_function(); +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(); + } +} + +fn main() { + // ... +} +``` + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to compilers. Note that + individual flags cannot currently contain spaces, so doing + something like: "-L=foo\ bar" is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. +* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags. + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, cc-rs uses built-in defaults + +In addition to the above optional environment variables, `cc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +### Parallel + +Currently cc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +``` + +By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. If you are using cargo, +use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` +is supplied by cargo. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing cc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `cc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`cc-rs` supports C++ libraries compilation by using the `cpp` method on +`Build`: + +```rust,no_run +extern crate cc; + +fn main() { + cc::Build::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env +variables are used instead of `CC` and `CFLAGS` and the C++ standard library is +linked to the crate target. + +## CUDA C++ support + +`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method +on `Build` (currently for GNU/Clang toolchains only): + +```rust,no_run +extern crate cc; + +fn main() { + cc::Build::new() + // Switch to CUDA C++ library compilation using NVCC. + .cuda(true) + // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). + .flag("-gencode").flag("arch=compute_52,code=sm_52") + // Generate code for Maxwell (Jetson TX1). + .flag("-gencode").flag("arch=compute_53,code=sm_53") + // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). + .flag("-gencode").flag("arch=compute_61,code=sm_61") + // Generate code for Pascal (Tesla P100). + .flag("-gencode").flag("arch=compute_60,code=sm_60") + // Generate code for Pascal (Jetson TX2). + .flag("-gencode").flag("arch=compute_62,code=sm_62") + .file("bar.cu") + .compile("libbar.a"); +} +``` + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/cc/azure-pipelines.yml b/cc/azure-pipelines.yml new file mode 100644 index 000000000..e81619660 --- /dev/null +++ b/cc/azure-pipelines.yml @@ -0,0 +1,101 @@ +trigger: + - master + +jobs: + - job: min_linux + pool: + vmImage: ubuntu-16.04 + displayName: Minimum Rust (Linux) + variables: + TOOLCHAIN: 1.16.0 + steps: + - template: ci/azure-install-rust.yml + - script: cargo build + + - job: min_Windows + pool: + vmImage: vs2017-win2016 + displayName: Minimum Rust (Windows) + variables: + TOOLCHAIN: 1.16.0 + steps: + - template: ci/azure-install-rust.yml + - script: cargo build + + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-unknown-linux-gnu + i686: + TARGET: i686-unknown-linux-gnu + x86_64-beta: + TARGET: x86_64-unknown-linux-gnu + TOOLCHAIN: beta + x86_64-nightly: + TARGET: x86_64-unknown-linux-gnu + TOOLCHAIN: nightly + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-apple-darwin + aarch64-ios: + TARGET: aarch64-apple-ios + NO_RUN: --no-run + + - job: Windows_vs2019 + pool: + vmImage: windows-2019 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + + - job: Windows_vs2017 + pool: + vmImage: vs2017-win2016 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-msvc: + TARGET: i686-pc-windows-msvc + x86_64-gnu: + TARGET: x86_64-pc-windows-gnu + i686-gnu: + TARGET: i686-pc-windows-gnu + + - job: Windows_vs2015 + pool: + vmImage: vs2015-win2012r2 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-msvc: + TARGET: i686-pc-windows-msvc + + - job: docs + steps: + - template: ci/azure-install-rust.yml + - script: cargo doc --no-deps --all-features + - script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + env: + GITHUB_DEPLOY_KEY: $(GITHUB_DEPLOY_KEY) diff --git a/cc/ci/azure-install-rust.yml b/cc/ci/azure-install-rust.yml new file mode 100644 index 000000000..118d65e45 --- /dev/null +++ b/cc/ci/azure-install-rust.yml @@ -0,0 +1,24 @@ +steps: + - bash: | + set -e + toolchain=$TOOLCHAIN + if [ "$toolchain" = "" ]; then + toolchain=stable + fi + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.prependpath]$HOME/.cargo/bin" + displayName: Install rust (unix) + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + IF "%TOOLCHAIN%"=="" (SET TOOLCHAIN=stable-%TARGET%) + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain %TOOLCHAIN% + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + displayName: Install rust (windows) + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/cc/ci/azure-steps.yml b/cc/ci/azure-steps.yml new file mode 100644 index 000000000..c240ed0c8 --- /dev/null +++ b/cc/ci/azure-steps.yml @@ -0,0 +1,21 @@ +steps: + - template: azure-install-rust.yml + - bash: rustup target add $TARGET + displayName: Install Rust target + + - bash: sudo apt-get install g++-multilib + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: Install g++-multilib + + - script: cargo build + displayName: "Normal build" + - bash: cargo test $NO_RUN -- --test-threads 1 + displayName: "Crate tests" + - bash: cargo test $NO_RUN --features parallel -- --test-threads 1 + displayName: "Crate tests (parallel)" + - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET + displayName: "cc-test tests" + - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel + displayName: "cc-test tests (parallel)" + - bash: cargo test $NO_RUN --manifest-path cc-test/Cargo.toml --target $TARGET --release + displayName: "cc-test tests (release)" diff --git a/cc/src/bin/gcc-shim.rs b/cc/src/bin/gcc-shim.rs new file mode 100644 index 000000000..7fd0ea8fa --- /dev/null +++ b/cc/src/bin/gcc-shim.rs @@ -0,0 +1,23 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +fn main() { + let out_dir = PathBuf::from(env::var_os("GCCTEST_OUT_DIR").unwrap()); + for i in 0.. { + let candidate = out_dir.join(format!("out{}", i)); + if candidate.exists() { + continue; + } + let mut f = File::create(candidate).unwrap(); + for arg in env::args().skip(1) { + writeln!(f, "{}", arg).unwrap(); + } + + File::create(out_dir.join("libfoo.a")).unwrap(); + break; + } +} diff --git a/cc/src/com.rs b/cc/src/com.rs new file mode 100644 index 000000000..9b75d476d --- /dev/null +++ b/cc/src/com.rs @@ -0,0 +1,155 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use std::ffi::{OsStr, OsString}; +use std::mem::forget; +use std::ops::Deref; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ptr::null_mut; +use std::slice::from_raw_parts; +use winapi::CoInitializeEx; +use winapi::IUnknown; +use winapi::Interface; +use winapi::BSTR; +use winapi::COINIT_MULTITHREADED; +use winapi::{SysFreeString, SysStringLen}; +use winapi::{HRESULT, S_FALSE, S_OK}; + +pub fn initialize() -> Result<(), HRESULT> { + let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) }; + if err != S_OK && err != S_FALSE { + // S_FALSE just means COM is already initialized + return Err(err); + } + Ok(()) +} + +pub struct ComPtr(*mut T) +where + T: Interface; +impl ComPtr +where + T: Interface, +{ + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// Casts up the inheritance chain + pub fn up(self) -> ComPtr + where + T: Deref, + U: Interface, + { + ComPtr(self.into_raw() as *mut U) + } + /// Extracts the raw pointer. + /// You are now responsible for releasing it yourself. + pub fn into_raw(self) -> *mut T { + let p = self.0; + forget(self); + p + } + /// For internal use only. + fn as_unknown(&self) -> &IUnknown { + unsafe { &*(self.0 as *mut IUnknown) } + } + /// Performs QueryInterface fun. + pub fn cast(&self) -> Result, i32> + where + U: Interface, + { + let mut obj = null_mut(); + let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { ComPtr::from_raw(obj as *mut U) }) + } +} +impl Deref for ComPtr +where + T: Interface, +{ + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} +impl Clone for ComPtr +where + T: Interface, +{ + fn clone(&self) -> Self { + unsafe { + self.as_unknown().AddRef(); + ComPtr::from_raw(self.0) + } + } +} +impl Drop for ComPtr +where + T: Interface, +{ + fn drop(&mut self) { + unsafe { + self.as_unknown().Release(); + } + } +} +pub struct BStr(BSTR); +impl BStr { + pub unsafe fn from_raw(s: BSTR) -> BStr { + BStr(s) + } + pub fn to_osstring(&self) -> OsString { + let len = unsafe { SysStringLen(self.0) }; + let slice = unsafe { from_raw_parts(self.0, len as usize) }; + OsStringExt::from_wide(slice) + } +} +impl Drop for BStr { + fn drop(&mut self) { + unsafe { SysFreeString(self.0) }; + } +} + +pub trait ToWide { + fn to_wide(&self) -> Vec; + fn to_wide_null(&self) -> Vec; +} +impl ToWide for T +where + T: AsRef, +{ + fn to_wide(&self) -> Vec { + self.as_ref().encode_wide().collect() + } + fn to_wide_null(&self) -> Vec { + self.as_ref().encode_wide().chain(Some(0)).collect() + } +} +pub trait FromWide +where + Self: Sized, +{ + fn from_wide(wide: &[u16]) -> Self; + fn from_wide_null(wide: &[u16]) -> Self { + let len = wide.iter().take_while(|&&c| c != 0).count(); + Self::from_wide(&wide[..len]) + } +} +impl FromWide for OsString { + fn from_wide(wide: &[u16]) -> OsString { + OsStringExt::from_wide(wide) + } +} diff --git a/cc/src/lib.rs b/cc/src/lib.rs new file mode 100644 index 000000000..9fef14763 --- /dev/null +++ b/cc/src/lib.rs @@ -0,0 +1,2422 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cc = "1.0" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! Configuration is available through the `Build` struct. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! The crate is not limited to C code, it can accept any source code that can +//! be passed to a C or C++ compiler. As such, assembly files with extensions +//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. +//! +//! [`Build`]: struct.Build.html +//! +//! # Parallelism +//! +//! To parallelize computation, enable the `parallel` feature for the crate. +//! +//! ```toml +//! [build-dependencies] +//! cc = { version = "1.0", features = ["parallel"] } +//! ``` +//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` +//! environment variable to the desired amount. +//! +//! Cargo will also set this environment variable when executed with the `-jN` flag. +//! +//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can +//! also specify the build paralellism. +//! +//! # Examples +//! +//! Use the `Build` struct to compile `src/foo.c`: +//! +//! ```no_run +//! extern crate cc; +//! +//! fn main() { +//! cc::Build::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("foo"); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/cc/1.0")] +#![cfg_attr(test, deny(warnings))] +#![allow(deprecated)] +#![deny(missing_docs)] + +#[cfg(feature = "parallel")] +extern crate rayon; + +use std::collections::HashMap; +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fs; +use std::io::{self, BufRead, BufReader, Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; + +// These modules are all glue to support reading the MSVC version from +// the registry and from COM interfaces +#[cfg(windows)] +mod registry; +#[cfg(windows)] +#[macro_use] +mod winapi; +#[cfg(windows)] +mod com; +#[cfg(windows)] +mod setup_config; + +pub mod windows_registry; + +/// A builder for compilation of a native static library. +/// +/// A `Build` is the main type of the `cc` crate and is used to control all the +/// various configuration options and such of a compile. You'll find more +/// documentation on each method itself. +#[derive(Clone, Debug)] +pub struct Build { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + flags_supported: Vec, + known_flag_support_status: Arc>>, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + cuda: bool, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, + use_plt: Option, + static_crt: Option, + shared_flag: Option, + static_flag: Option, + warnings_into_errors: bool, + warnings: Option, + extra_warnings: Option, + env_cache: Arc>>>, +} + +/// Represents the types of errors that may occur while using cc-rs. +#[derive(Clone, Debug)] +enum ErrorKind { + /// Error occurred while performing I/O. + IOError, + /// Invalid architecture supplied. + ArchitectureInvalid, + /// Environment variable not found, with the var in question as extra info. + EnvVarNotFound, + /// Error occurred while using external tools (ie: invocation of compiler). + ToolExecError, + /// Error occurred due to missing external tools. + ToolNotFound, +} + +/// Represents an internal error that occurred, with an explanation. +#[derive(Clone, Debug)] +pub struct Error { + /// Describes the kind of error that occurred. + kind: ErrorKind, + /// More explanation of error that occurred. + message: String, +} + +impl Error { + fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind: kind, + message: message.to_owned(), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Error { + Error::new(ErrorKind::IOError, &format!("{}", e)) + } +} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +#[derive(Clone, Debug)] +pub struct Tool { + path: PathBuf, + cc_wrapper_path: Option, + cc_wrapper_args: Vec, + args: Vec, + env: Vec<(OsString, OsString)>, + family: ToolFamily, + cuda: bool, + removed_args: Vec, +} + +/// Represents the family of tools this tool belongs to. +/// +/// Each family of tools differs in how and what arguments they accept. +/// +/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. +#[derive(Copy, Clone, Debug, PartialEq)] +enum ToolFamily { + /// Tool is GNU Compiler Collection-like. + Gnu, + /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags + /// and its cross-compilation approach is different. + Clang, + /// Tool is the MSVC cl.exe. + Msvc { clang_cl: bool }, +} + +impl ToolFamily { + /// What the flag to request debug info for this family of tools look like + fn add_debug_flags(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("/Z7".into()); + } + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-g".into()); + cmd.push_cc_arg("-fno-omit-frame-pointer".into()); + } + } + } + + /// What the flag to include directories into header search path looks like + fn include_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "/I", + ToolFamily::Gnu | ToolFamily::Clang => "-I", + } + } + + /// What the flag to request macro-expanded source output looks like + fn expand_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "/E", + ToolFamily::Gnu | ToolFamily::Clang => "-E", + } + } + + /// What the flags to enable all warnings + fn warnings_flags(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "/W4", + ToolFamily::Gnu | ToolFamily::Clang => "-Wall", + } + } + + /// What the flags to enable extra warnings + fn extra_warnings_flags(&self) -> Option<&'static str> { + match *self { + ToolFamily::Msvc { .. } => None, + ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), + } + } + + /// What the flag to turn warning into errors + fn warnings_to_errors_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "/WX", + ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + } + } + + /// NVCC-specific. Device code debug info flag. This is separate from the + /// debug info flag passed to the C++ compiler. + fn nvcc_debug_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => unimplemented!(), + ToolFamily::Gnu | ToolFamily::Clang => "-G", + } + } + + /// NVCC-specific. Redirect the following flag to the underlying C++ + /// compiler. + fn nvcc_redirect_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => unimplemented!(), + ToolFamily::Gnu | ToolFamily::Clang => "-Xcompiler", + } + } + + fn verbose_stderr(&self) -> bool { + *self == ToolFamily::Clang + } +} + +/// Represents an object. +/// +/// This is a source file -> object file pair. +#[derive(Clone, Debug)] +struct Object { + src: PathBuf, + dst: PathBuf, +} + +impl Object { + /// Create a new source file -> object file pair. + fn new(src: PathBuf, dst: PathBuf) -> Object { + Object { src: src, dst: dst } + } +} + +impl Build { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the [`compile`] function. + /// + /// [`compile`]: struct.Build.html#method.compile + pub fn new() -> Build { + Build { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + flags_supported: Vec::new(), + known_flag_support_status: Arc::new(Mutex::new(HashMap::new())), + files: Vec::new(), + shared_flag: None, + static_flag: None, + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + cuda: false, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + use_plt: None, + static_crt: None, + warnings: None, + extra_warnings: None, + warnings_into_errors: false, + env_cache: Arc::new(Mutex::new(HashMap::new())), + } + } + + /// Add a directory to the `-I` or include path for headers + /// + /// # Example + /// + /// ```no_run + /// use std::path::Path; + /// + /// let library_path = Path::new("/path/to/library"); + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .include(library_path) + /// .include("src") + /// .compile("foo"); + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Build { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Specify a `-D` variable with an optional value. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .define("FOO", "BAR") + /// .define("BAZ", None) + /// .compile("foo"); + /// ``` + pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { + self.definitions + .push((var.to_string(), val.into().map(|s| s.to_string()))); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Build { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag("-ffunction-sections") + /// .compile("foo"); + /// ``` + pub fn flag(&mut self, flag: &str) -> &mut Build { + self.flags.push(flag.to_string()); + self + } + + fn ensure_check_file(&self) -> Result { + let out_dir = self.get_out_dir()?; + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + Ok(src) + } + + /// Run the compiler to test if it accepts the given flag. + /// + /// For a convenience method for setting flags conditionally, + /// see `flag_if_supported()`. + /// + /// It may return error if it's unable to run the compilier with a test file + /// (e.g. the compiler is missing or a write to the `out_dir` failed). + /// + /// Note: Once computed, the result of this call is stored in the + /// `known_flag_support` field. If `is_flag_supported(flag)` + /// is called again, the result will be read from the hash table. + pub fn is_flag_supported(&self, flag: &str) -> Result { + let mut known_status = self.known_flag_support_status.lock().unwrap(); + if let Some(is_supported) = known_status.get(flag).cloned() { + return Ok(is_supported); + } + + let out_dir = self.get_out_dir()?; + let src = self.ensure_check_file()?; + let obj = out_dir.join("flag_check"); + let target = self.get_target()?; + let host = self.get_host()?; + let mut cfg = Build::new(); + cfg.flag(flag) + .target(&target) + .opt_level(0) + .host(&host) + .debug(false) + .cpp(self.cpp) + .cuda(self.cuda); + let mut compiler = cfg.try_get_compiler()?; + + // Clang uses stderr for verbose output, which yields a false positive + // result if the CFLAGS/CXXFLAGS include -v to aid in debugging. + if compiler.family.verbose_stderr() { + compiler.remove_arg("-v".into()); + } + + let mut cmd = compiler.to_command(); + let is_arm = target.contains("aarch64") || target.contains("arm"); + command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false, is_arm); + + // We need to explicitly tell msvc not to link and create an exe + // in the root directory of the crate + if target.contains("msvc") { + cmd.arg("/c"); + } + + cmd.arg(&src); + + let output = cmd.output()?; + let is_supported = output.stderr.is_empty(); + + known_status.insert(flag.to_owned(), is_supported); + Ok(is_supported) + } + + /// Add an arbitrary flag to the invocation of the compiler if it supports it + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag_if_supported("-Wlogical-op") // only supported by GCC + /// .flag_if_supported("-Wunreachable-code") // only supported by clang + /// .compile("foo"); + /// ``` + pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { + self.flags_supported.push(flag.to_string()); + self + } + + /// Set the `-shared` flag. + /// + /// When enabled, the compiler will produce a shared object which can + /// then be linked with other objects to form an executable. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .compile("libfoo.so"); + /// ``` + + pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { + self.shared_flag = Some(shared_flag); + self + } + + /// Set the `-static` flag. + /// + /// When enabled on systems that support dynamic linking, this prevents + /// linking with the shared libraries. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .static_flag(true) + /// .compile("foo"); + /// ``` + pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { + self.static_flag = Some(static_flag); + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Build { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Add files which will be compiled + pub fn files

(&mut self, p: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for file in p.into_iter() { + self.file(file); + } + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Build { + self.cpp = cpp; + self + } + + /// Set CUDA C++ support. + /// + /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to + /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; + /// any other arguments for the C/C++ toolchain will be redirected using + /// "-Xcompiler" flags. + /// + /// If enabled, this also implicitly enables C++ support. + pub fn cuda(&mut self, cuda: bool) -> &mut Build { + self.cuda = cuda; + if cuda { + self.cpp = true; + } + self + } + + /// Set warnings into errors flag. + /// + /// Disabled by default. + /// + /// Warning: turning warnings into errors only make sense + /// if you are a developer of the crate using cc-rs. + /// Some warnings only appear on some architecture or + /// specific version of the compiler. Any user of this crate, + /// or any other crate depending on it, could fail during + /// compile time. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings_into_errors(true) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { + self.warnings_into_errors = warnings_into_errors; + self + } + + /// Set warnings flags. + /// + /// Adds some flags: + /// - "/Wall" for MSVC. + /// - "-Wall", "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings(&mut self, warnings: bool) -> &mut Build { + self.warnings = Some(warnings); + self.extra_warnings = Some(warnings); + self + } + + /// Set extra warnings flags. + /// + /// Adds some flags: + /// - nothing for MSVC. + /// - "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// // Disables -Wextra, -Wall remains enabled: + /// cc::Build::new() + /// .file("src/foo.c") + /// .extra_warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build { + self.extra_warnings = Some(warnings); + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// The default value of this property depends on the current target: On + /// OS X `Some("c++")` is used, when compiling for a Visual Studio based + /// target `None` is used and for other targets `Some("stdc++")` is used. + /// If the `CXXSTDLIB` environment variable is set, its value will + /// override the default value. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .cpp_link_stdlib("stdc++") + /// .compile("libfoo.so"); + /// ``` + pub fn cpp_link_stdlib<'a, V: Into>>( + &mut self, + cpp_link_stdlib: V, + ) -> &mut Build { + self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .cpp_set_stdlib("c++") + /// .compile("libfoo.a"); + /// ``` + pub fn cpp_set_stdlib<'a, V: Into>>( + &mut self, + cpp_set_stdlib: V, + ) -> &mut Build { + let cpp_set_stdlib = cpp_set_stdlib.into(); + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .target("aarch64-linux-android") + /// .compile("foo"); + /// ``` + pub fn target(&mut self, target: &str) -> &mut Build { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .host("arm-linux-gnueabihf") + /// .compile("foo"); + /// ``` + pub fn host(&mut self, host: &str) -> &mut Build { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `PROFILE` environment + /// variable by build scripts (only enabled when the profile is "debug"), so + /// it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Build { + self.debug = Some(debug); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Build { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Build { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + /// + /// The emitted metadata is: + /// + /// - `rustc-link-lib=static=`*compiled lib* + /// - `rustc-link-search=native=`*target folder* + /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` + /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` + /// + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `windows-gnu` targets and + /// to `true` for all other targets. + pub fn pic(&mut self, pic: bool) -> &mut Build { + self.pic = Some(pic); + self + } + + /// Configures whether the Procedure Linkage Table is used for indirect + /// calls into shared libraries. + /// + /// The PLT is used to provide features like lazy binding, but introduces + /// a small performance loss due to extra pointer indirection. Setting + /// `use_plt` to `false` can provide a small performance increase. + /// + /// Note that skipping the PLT requires a recent version of GCC/Clang. + /// + /// This only applies to ELF targets. It has no effect on other platforms. + pub fn use_plt(&mut self, use_plt: bool) -> &mut Build { + self.use_plt = Some(use_plt); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { + self.static_crt = Some(static_crt); + self + } + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Build + where + A: AsRef, + B: AsRef, + { + self.env + .push((a.as_ref().to_owned(), b.as_ref().to_owned())); + self + } + + /// Run the compiler, generating the file `output` + /// + /// This will return a result instead of panicing; see compile() for the complete description. + pub fn try_compile(&self, output: &str) -> Result<(), Error> { + let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { + (&output[3..output.len() - 2], output.to_owned()) + } else { + let mut gnu = String::with_capacity(5 + output.len()); + gnu.push_str("lib"); + gnu.push_str(&output); + gnu.push_str(".a"); + (output, gnu) + }; + let dst = self.get_out_dir()?; + + let mut objects = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().ok_or_else(|| { + Error::new(ErrorKind::IOError, "Getting object file details failed.") + })?) + } else { + obj + }; + + match obj.parent() { + Some(s) => fs::create_dir_all(s)?, + None => { + return Err(Error::new( + ErrorKind::IOError, + "Getting object file details failed.", + )); + } + }; + + objects.push(Object::new(file.to_path_buf(), obj)); + } + self.compile_objects(&objects)?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; + + if self.get_target()?.contains("msvc") { + let compiler = self.get_base_compiler()?; + let atlmfc_lib = compiler + .env() + .iter() + .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) + .and_then(|&(_, ref lib_paths)| { + env::split_paths(lib_paths).find(|path| { + let sub = Path::new("atlmfc/lib"); + path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) + }) + }); + + if let Some(atlmfc_lib) = atlmfc_lib { + self.print(&format!( + "cargo:rustc-link-search=native={}", + atlmfc_lib.display() + )); + } + } + + self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib()? { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + + Ok(()) + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` should be the name of the library. For backwards compatibility, + /// the `output` may start with `lib` and end with `.a`. The Rust compilier will create + /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, + /// ending with `.lib`. + /// + /// # Panics + /// + /// Panics if `output` is not formatted correctly or if one of the underlying + /// compiler commands fails. It can also panic if it fails reading file names + /// or creating directories. + pub fn compile(&self, output: &str) { + if let Err(e) = self.try_compile(output) { + fail(&e.message); + } + } + + #[cfg(feature = "parallel")] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + use self::rayon::prelude::*; + + if let Some(amt) = self.getenv("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + let _ = rayon::ThreadPoolBuilder::new() + .num_threads(amt) + .build_global(); + } + } + + // Check for any errors and return the first one found. + objs.par_iter() + .with_max_len(1) + .map(|obj| self.compile_object(obj)) + .collect() + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + for obj in objs { + self.compile_object(obj)?; + } + Ok(()) + } + + fn compile_object(&self, obj: &Object) -> Result<(), Error> { + let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); + let target = self.get_target()?; + let msvc = target.contains("msvc"); + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler()? + } else { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + ( + cmd, + compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(), + ) + }; + let is_arm = target.contains("aarch64") || target.contains("arm"); + command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm, is_arm); + // armasm and armasm64 don't requrie -c option + if !msvc || !is_asm || !is_arm { + cmd.arg(if msvc { "/c" } else { "-c" }); + } + cmd.arg(&obj.src); + + run(&mut cmd, &name)?; + Ok(()) + } + + /// This will return a result instead of panicing; see expand() for the complete description. + pub fn try_expand(&self) -> Result, Error> { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd.arg(compiler.family.expand_flag()); + + assert!( + self.files.len() <= 1, + "Expand may only be called for a single file" + ); + + for file in self.files.iter() { + cmd.arg(file); + } + + let name = compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(); + + Ok(run_output(&mut cmd, &name)?) + } + + /// Run the compiler, returning the macro-expanded version of the input files. + /// + /// This is only relevant for C and C++ files. + /// + /// # Panics + /// Panics if more than one file is present in the config, or if compiler + /// path has an invalid file name. + /// + /// # Example + /// ```no_run + /// let out = cc::Build::new().file("src/foo.c").expand(); + /// ``` + pub fn expand(&self) -> Vec { + match self.try_expand() { + Err(e) => fail(&e.message), + Ok(v) => v, + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + /// + /// # Panics + /// + /// Panics if an error occurred while determining the architecture. + pub fn get_compiler(&self) -> Tool { + match self.try_get_compiler() { + Ok(tool) => tool, + Err(e) => fail(&e.message), + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This will return a result instead of panicing; see get_compiler() for the complete description. + pub fn try_get_compiler(&self) -> Result { + let opt_level = self.get_opt_level()?; + let target = self.get_target()?; + + let mut cmd = self.get_base_compiler()?; + let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); + + // Disable default flag generation via environment variable or when + // certain cross compiling arguments are set + let use_defaults = self.getenv("CRATE_CC_NO_DEFAULTS").is_none(); + + if use_defaults { + self.add_default_flags(&mut cmd, &target, &opt_level)?; + } else { + println!("Info: default compiler flags are disabled"); + } + + for arg in envflags { + cmd.push_cc_arg(arg.into()); + } + + for directory in self.include_directories.iter() { + cmd.args.push(cmd.family.include_flag().into()); + cmd.args.push(directory.into()); + } + + // If warnings and/or extra_warnings haven't been explicitly set, + // then we set them only if the environment doesn't already have + // CFLAGS/CXXFLAGS, since those variables presumably already contain + // the desired set of warnings flags. + + if self + .warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + let wflags = cmd.family.warnings_flags().into(); + cmd.push_cc_arg(wflags); + } + + if self + .extra_warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + if let Some(wflags) = cmd.family.extra_warnings_flags() { + cmd.push_cc_arg(wflags.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + let lead = if let ToolFamily::Msvc { .. } = cmd.family { + "/" + } else { + "-" + }; + if let Some(ref value) = *value { + cmd.args.push(format!("{}D{}={}", lead, key, value).into()); + } else { + cmd.args.push(format!("{}D{}", lead, key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn add_default_flags( + &self, + cmd: &mut Tool, + target: &str, + opt_level: &str, + ) -> Result<(), Error> { + // Non-target flags + // If the flag is not conditioned on target variable, it belongs here :) + match cmd.family { + ToolFamily::Msvc { .. } => { + assert!(!self.cuda, + "CUDA C++ compilation not supported for MSVC, yet... but you are welcome to implement it :)"); + + cmd.args.push("/nologo".into()); + + let crt_flag = match self.static_crt { + Some(true) => "/MT", + Some(false) => "/MD", + None => { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + "/MT" + } else { + "/MD" + } + } + }; + cmd.args.push(crt_flag.into()); + + match &opt_level[..] { + // Msvc uses /O1 to enable all optimizations that minimize code size. + "z" | "s" | "1" => cmd.push_opt_unless_duplicate("/O1".into()), + // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. + "2" | "3" => cmd.push_opt_unless_duplicate("/O2".into()), + _ => {} + } + } + ToolFamily::Gnu | ToolFamily::Clang => { + // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does + // not support '-Oz' + if opt_level == "z" && cmd.family != ToolFamily::Clang { + cmd.push_opt_unless_duplicate("-Os".into()); + } else { + cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); + } + + if !target.contains("-ios") { + cmd.push_cc_arg("-ffunction-sections".into()); + cmd.push_cc_arg("-fdata-sections".into()); + } + if self.pic.unwrap_or(!target.contains("windows-gnu")) { + cmd.push_cc_arg("-fPIC".into()); + // PLT only applies if code is compiled with PIC support, + // and only for ELF targets. + if target.contains("linux") && !self.use_plt.unwrap_or(true) { + cmd.push_cc_arg("-fno-plt".into()); + } + } + } + } + + if self.get_debug() { + if self.cuda { + let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into(); + cmd.args.push(nvcc_debug_flag); + } + let family = cmd.family; + family.add_debug_flags(cmd); + } + + // Target flags + match cmd.family { + ToolFamily::Clang => { + cmd.args.push(format!("--target={}", target).into()); + } + ToolFamily::Msvc { clang_cl } => { + if clang_cl { + if target.contains("x86_64") { + cmd.args.push("-m64".into()); + } else if target.contains("86") { + cmd.args.push("-m32".into()); + cmd.args.push("/arch:IA32".into()); + } else { + cmd.args.push(format!("--target={}", target).into()); + } + } else { + if target.contains("i586") { + cmd.args.push("/ARCH:IA32".into()); + } + } + + // There is a check in corecrt.h that will generate a + // compilation error if + // _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE is + // not defined to 1. The check was added in Windows + // 8 days because only store apps were allowed on ARM. + // This changed with the release of Windows 10 IoT Core. + // The check will be going away in future versions of + // the SDK, but for all released versions of the + // Windows SDK it is required. + if target.contains("arm") || target.contains("thumb") { + cmd.args + .push("/D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); + } + } + ToolFamily::Gnu => { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target == "x86_64-unknown-linux-gnux32" { + cmd.args.push("-mx32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if self.static_flag.is_none() { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + cmd.args.push("-static".into()); + } + } + + // armv7 targets get to use armv7 instructions + if (target.starts_with("armv7") || target.starts_with("thumbv7")) + && target.contains("-linux-") + { + cmd.args.push("-march=armv7-a".into()); + } + + // (x86 Android doesn't say "eabi") + if target.contains("-androideabi") && target.contains("v7") { + // -march=armv7-a handled above + cmd.args.push("-mthumb".into()); + if !target.contains("neon") { + // On android we can guarantee some extra float instructions + // (specified in the android spec online) + // NEON guarantees even more; see below. + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + cmd.args.push("-mfloat-abi=softfp".into()); + } + + if target.contains("neon") { + cmd.args.push("-mfpu=neon-vfpv4".into()); + } + + if target.starts_with("armv4t-unknown-linux-") { + cmd.args.push("-march=armv4t".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + if target.starts_with("armv5te-unknown-linux-") { + cmd.args.push("-march=armv5te".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + // For us arm == armv6 by default + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + if target.ends_with("hf") { + cmd.args.push("-mfpu=vfp".into()); + } else { + cmd.args.push("-mfloat-abi=soft".into()); + } + } + + // We can guarantee some settings for FRC + if target.starts_with("arm-frc-") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mcpu=cortex-a9".into()); + cmd.args.push("-mfpu=vfpv3".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + cmd.args.push("-marm".into()); + } + + // Turn codegen down on i586 to avoid some instructions. + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + + // Set codegen level for i686 correctly + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + + // Looks like `musl-gcc` makes is hard for `-m32` to make its way + // all the way to the linker, so we need to actually instruct the + // linker that we're generating 32-bit executables as well. This'll + // typically only be used for build scripts which transitively use + // these flags that try to compile executables. + if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" { + cmd.args.push("-Wl,-melf_i386".into()); + } + + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6s-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv4-sp-d16".into()) + } + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + if target.starts_with("thumbv8m.base") { + cmd.args.push("-march=armv8-m.base".into()); + } + if target.starts_with("thumbv8m.main") { + cmd.args.push("-march=armv8-m.main".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv5-sp-d16".into()) + } + } + if target.starts_with("armebv7r") | target.starts_with("armv7r") { + if target.starts_with("armeb") { + cmd.args.push("-mbig-endian".into()); + } else { + cmd.args.push("-mlittle-endian".into()); + } + + // ARM mode + cmd.args.push("-marm".into()); + + // R Profile + cmd.args.push("-march=armv7-r".into()); + + if target.ends_with("eabihf") { + // Calling convention + cmd.args.push("-mfloat-abi=hard".into()); + + // lowest common denominator FPU + // (see Cortex-R4 technical reference manual) + cmd.args.push("-mfpu=vfpv3-d16".into()) + } else { + // Calling convention + cmd.args.push("-mfloat-abi=soft".into()); + } + } + } + } + + if target.contains("-ios") { + // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be + // detected instead. + self.ios_flags(cmd)?; + } + + if self.static_flag.unwrap_or(false) { + cmd.args.push("-static".into()); + } + if self.shared_flag.unwrap_or(false) { + cmd.args.push("-shared".into()); + } + + if self.cpp { + match (self.cpp_set_stdlib.as_ref(), cmd.family) { + (None, _) => {} + (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { + cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); + } + _ => { + println!( + "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + does not support this option, ignored", + cmd.family + ); + } + } + } + + Ok(()) + } + + fn has_flags(&self) -> bool { + let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; + let flags_env_var_value = self.get_var(flags_env_var_name); + if let Ok(_) = flags_env_var_value { + true + } else { + false + } + } + + fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { + let target = self.get_target()?; + let tool = if target.contains("x86_64") { + "ml64.exe" + } else if target.contains("arm") { + "armasm.exe" + } else if target.contains("aarch64") { + "armasm64.exe" + } else { + "ml.exe" + }; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + for directory in self.include_directories.iter() { + cmd.arg("/I").arg(directory); + } + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.arg(&format!("/D{}={}", key, value)); + } else { + cmd.arg(&format!("/D{}", key)); + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("/safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + Ok((cmd, tool.to_string())) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { + // Delete the destination if it exists as the `ar` tool at least on Unix + // appends to it, which we don't want. + let _ = fs::remove_file(&dst); + + let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); + let target = self.get_target()?; + if target.contains("msvc") { + let (mut cmd, program) = self.get_ar()?; + let mut out = OsString::from("/OUT:"); + out.push(dst); + cmd.arg(out).arg("/nologo"); + + // Similar to https://github.com/rust-lang/rust/pull/47507 + // and https://github.com/rust-lang/rust/pull/48548 + let estimated_command_line_len = objects + .iter() + .chain(&self.objects) + .map(|a| a.as_os_str().len()) + .sum::(); + if estimated_command_line_len > 1024 * 6 { + let mut args = String::from("\u{FEFF}"); // BOM + for arg in objects.iter().chain(&self.objects) { + args.push('"'); + for c in arg.to_str().unwrap().chars() { + if c == '"' { + args.push('\\') + } + args.push(c) + } + args.push('"'); + args.push('\n'); + } + + let mut utf16le = Vec::new(); + for code_unit in args.encode_utf16() { + utf16le.push(code_unit as u8); + utf16le.push((code_unit >> 8) as u8); + } + + let mut args_file = OsString::from(dst); + args_file.push(".args"); + fs::File::create(&args_file) + .unwrap() + .write_all(&utf16le) + .unwrap(); + + let mut args_file_arg = OsString::from("@"); + args_file_arg.push(args_file); + cmd.arg(args_file_arg); + } else { + cmd.args(&objects).args(&self.objects); + } + run(&mut cmd, &program)?; + + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + match fs::hard_link(&dst, &lib_dst).or_else(|_| { + // if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }) { + Ok(_) => (), + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Could not copy or create a hard-link to the generated lib file.", + )); + } + }; + } else { + let (mut ar, cmd) = self.get_ar()?; + run( + ar.arg("crs").arg(dst).args(&objects).args(&self.objects), + &cmd, + )?; + } + + Ok(()) + } + + fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + } + + let target = self.get_target()?; + let arch = target.split('-').nth(0).ok_or_else(|| { + Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + ) + })?; + let arch = match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + }; + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args.push("-miphoneos-version-min=7.0".into()); + "iphoneos" + } + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args.push("-mios-simulator-version-min=7.0".into()); + "iphonesimulator" + } + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self + .cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk) + .stderr(Stdio::inherit()) + .output()? + .stdout; + + let sdk_path = match String::from_utf8(sdk_path) { + Ok(p) => p, + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Unable to determine iOS SDK path.", + )); + } + }; + + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path.trim().into()); + cmd.args.push("-fembed-bitcode".into()); + /* + * TODO we probably ultimatedly want the -fembed-bitcode-marker flag + * but can't have it now because of an issue in LLVM: + * https://github.com/alexcrichton/cc-rs/issues/301 + * https://github.com/rust-lang/rust/pull/48896#comment-372192660 + */ + /* + if self.get_opt_level()? == "0" { + cmd.args.push("-fembed-bitcode-marker".into()); + } + */ + + Ok(()) + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd + } + + fn get_base_compiler(&self) -> Result { + if let Some(ref c) = self.compiler { + return Ok(Tool::new(c.clone())); + } + let host = self.get_host()?; + let target = self.get_target()?; + let (env, msvc, gnu, traditional, clang) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++", "clang++") + } else { + ("CC", "cl.exe", "gcc", "cc", "clang") + }; + + // On Solaris, c++/cc unlikely to exist or be correct. + let default = if host.contains("solaris") { + gnu + } else { + traditional + }; + + let cl_exe = windows_registry::find_tool(&target, "cl.exe"); + + let tool_opt: Option = self + .env_tool(env) + .map(|(tool, cc, args)| { + // chop off leading/trailing whitespace to work around + // semi-buggy build scripts which are shared in + // makefiles/configure scripts (where spaces are far more + // lenient) + let mut t = Tool::new(PathBuf::from(tool.trim())); + if let Some(cc) = cc { + t.cc_wrapper_path = Some(PathBuf::from(cc)); + } + for arg in args { + t.cc_wrapper_args.push(arg.into()); + } + t + }) + .or_else(|| { + if target.contains("emscripten") { + let tool = if self.cpp { "em++" } else { "emcc" }; + // Windows uses bat file so we have to be a bit more specific + if cfg!(windows) { + let mut t = Tool::new(PathBuf::from("cmd")); + t.args.push("/c".into()); + t.args.push(format!("{}.bat", tool).into()); + Some(t) + } else { + Some(Tool::new(PathBuf::from(tool))) + } + } else { + None + } + }) + .or_else(|| cl_exe.clone()); + + let tool = match tool_opt { + Some(t) => t, + None => { + let compiler = if host.contains("windows") && target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + let target = target + .replace("armv7neon", "arm") + .replace("armv7", "arm") + .replace("thumbv7neon", "arm") + .replace("thumbv7", "arm"); + let gnu_compiler = format!("{}-{}", target, gnu); + let clang_compiler = format!("{}-{}", target, clang); + // Check if gnu compiler is present + // if not, use clang + if Command::new(&gnu_compiler).spawn().is_ok() { + gnu_compiler + } else { + clang_compiler + } + } else if target.contains("cloudabi") { + format!("{}-{}", target, traditional) + } else if target == "wasm32-wasi" || + target == "wasm32-unknown-wasi" || + target == "wasm32-unknown-unknown" { + "clang".to_string() + } else if self.get_host()? != target { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-')); + let prefix = cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "i586-unknown-linux-musl" => Some("musl"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => { + Some("mipsisa64r6el-linux-gnuabi64") + } + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "armebv7r-none-eabi" => Some("arm-none-eabi"), + "armebv7r-none-eabihf" => Some("arm-none-eabi"), + "armv7r-none-eabi" => Some("arm-none-eabi"), + "armv7r-none-eabihf" => Some("arm-none-eabi"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + }); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + Tool::new(PathBuf::from(compiler)) + } + }; + + let mut tool = if self.cuda { + assert!( + tool.args.is_empty(), + "CUDA compilation currently assumes empty pre-existing args" + ); + let nvcc = match self.get_var("NVCC") { + Err(_) => "nvcc".into(), + Ok(nvcc) => nvcc, + }; + let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), self.cuda); + nvcc_tool + .args + .push(format!("-ccbin={}", tool.path.display()).into()); + nvcc_tool + } else { + tool + }; + + // If we found `cl.exe` in our environment, the tool we're returning is + // an MSVC-like tool, *and* no env vars were set then set env vars for + // the tool that we're returning. + // + // Env vars are needed for things like `link.exe` being put into PATH as + // well as header include paths sometimes. These paths are automatically + // included by default but if the `CC` or `CXX` env vars are set these + // won't be used. This'll ensure that when the env vars are used to + // configure for invocations like `clang-cl` we still get a "works out + // of the box" experience. + if let Some(cl_exe) = cl_exe { + if tool.family == (ToolFamily::Msvc { clang_cl: true }) + && tool.env.len() == 0 + && target.contains("msvc") + { + for &(ref k, ref v) in cl_exe.env.iter() { + tool.env.push((k.to_owned(), v.to_owned())); + } + } + } + + Ok(tool) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target()?; + let host = self.get_host()?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + let res = self + .getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Could not find environment variable {}.", var_base), + )), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name) + .unwrap_or(String::new()) + .split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() + } + + /// Returns compiler path, optional modifier name from whitelist, and arguments vec + fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { + let tool = match self.get_var(name) { + Ok(tool) => tool, + Err(_) => return None, + }; + + // If this is an exact path on the filesystem we don't want to do any + // interpretation at all, just pass it on through. This'll hopefully get + // us to support spaces-in-paths. + if Path::new(&tool).exists() { + return Some((tool, None, Vec::new())); + } + + // Ok now we want to handle a couple of scenarios. We'll assume from + // here on out that spaces are splitting separate arguments. Two major + // features we want to support are: + // + // CC='sccache cc' + // + // aka using `sccache` or any other wrapper/caching-like-thing for + // compilations. We want to know what the actual compiler is still, + // though, because our `Tool` API support introspection of it to see + // what compiler is in use. + // + // additionally we want to support + // + // CC='cc -flag' + // + // where the CC env var is used to also pass default flags to the C + // compiler. + // + // It's true that everything here is a bit of a pain, but apparently if + // you're not literally make or bash then you get a lot of bug reports. + let known_wrappers = ["ccache", "distcc", "sccache", "icecc"]; + + let mut parts = tool.split_whitespace(); + let maybe_wrapper = match parts.next() { + Some(s) => s, + None => return None, + }; + + let file_stem = Path::new(maybe_wrapper) + .file_stem() + .unwrap() + .to_str() + .unwrap(); + if known_wrappers.contains(&file_stem) { + if let Some(compiler) = parts.next() { + return Some(( + compiler.to_string(), + Some(maybe_wrapper.to_string()), + parts.map(|s| s.to_string()).collect(), + )); + } + } + + Some(( + maybe_wrapper.to_string(), + None, + parts.map(|s| s.to_string()).collect(), + )) + } + + /// Returns the default C++ standard library for the current target: `libc++` + /// for OS X and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Result, Error> { + match self.cpp_link_stdlib.clone() { + Some(s) => Ok(s), + None => { + if let Ok(stdlib) = self.get_var("CXXSTDLIB") { + if stdlib.is_empty() { + Ok(None) + } else { + Ok(Some(stdlib)) + } + } else { + let target = self.get_target()?; + if target.contains("msvc") { + Ok(None) + } else if target.contains("apple") { + Ok(Some("c++".to_string())) + } else if target.contains("freebsd") { + Ok(Some("c++".to_string())) + } else if target.contains("openbsd") { + Ok(Some("c++".to_string())) + } else { + Ok(Some("stdc++".to_string())) + } + } + } + } + } + + fn get_ar(&self) -> Result<(Command, String), Error> { + if let Some(ref p) = self.archiver { + let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); + return Ok((self.cmd(p), name.to_string())); + } + if let Ok(p) = self.get_var("AR") { + return Ok((self.cmd(&p), p)); + } + let target = self.get_target()?; + let program = if target.contains("android") { + format!("{}-ar", target.replace("armv7", "arm")) + } else if target.contains("emscripten") { + // Windows use bat files so we have to be a bit more specific + if cfg!(windows) { + let mut cmd = self.cmd("cmd"); + cmd.arg("/c").arg("emar.bat"); + return Ok((cmd, "emar.bat".to_string())); + } + + "emar".to_string() + } else if target.contains("msvc") { + match windows_registry::find(&target, "lib.exe") { + Some(t) => return Ok((t, "lib.exe".to_string())), + None => "lib.exe".to_string(), + } + } else { + "ar".to_string() + }; + Ok((self.cmd(&program), program)) + } + + fn get_target(&self) -> Result { + match self.target.clone() { + Some(t) => Ok(t), + None => Ok(self.getenv_unwrap("TARGET")?), + } + } + + fn get_host(&self) -> Result { + match self.host.clone() { + Some(h) => Ok(h), + None => Ok(self.getenv_unwrap("HOST")?), + } + } + + fn get_opt_level(&self) -> Result { + match self.opt_level.as_ref().cloned() { + Some(ol) => Ok(ol), + None => Ok(self.getenv_unwrap("OPT_LEVEL")?), + } + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { + Some(s) => s != "false", + None => false, + }) + } + + fn get_out_dir(&self) -> Result { + match self.out_dir.clone() { + Some(p) => Ok(p), + None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + "Environment variable OUT_DIR not defined.", + ) + })?), + } + } + + fn getenv(&self, v: &str) -> Option { + let mut cache = self.env_cache.lock().unwrap(); + if let Some(val) = cache.get(v) { + return val.clone(); + } + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + cache.insert(v.to_string(), r.clone()); + r + } + + fn getenv_unwrap(&self, v: &str) -> Result { + match self.getenv(v) { + Some(s) => Ok(s), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Environment variable {} not defined.", v.to_string()), + )), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } +} + +impl Default for Build { + fn default() -> Build { + Build::new() + } +} + +impl Tool { + fn new(path: PathBuf) -> Tool { + Tool::with_features(path, false) + } + + fn with_features(path: PathBuf, cuda: bool) -> Tool { + // Try to detect family of the tool from its name, falling back to Gnu. + let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { + if fname.contains("clang-cl") { + ToolFamily::Msvc { clang_cl: true } + } else if fname.contains("cl") + && !fname.contains("cloudabi") + && !fname.contains("uclibc") + && !fname.contains("clang") + { + ToolFamily::Msvc { clang_cl: false } + } else if fname.contains("clang") { + ToolFamily::Clang + } else { + ToolFamily::Gnu + } + } else { + ToolFamily::Gnu + }; + Tool { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: cuda, + removed_args: Vec::new(), + } + } + + /// Add an argument to be stripped from the final command arguments. + fn remove_arg(&mut self, flag: OsString) { + self.removed_args.push(flag); + } + + /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". + /// + /// Currently this is only used for compiling CUDA sources, since NVCC only + /// accepts a limited set of GNU-like flags, and the rest must be prefixed + /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. + fn push_cc_arg(&mut self, flag: OsString) { + if self.cuda { + self.args.push(self.family.nvcc_redirect_flag().into()); + } + self.args.push(flag); + } + + fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { + let flag = flag.to_str().unwrap(); + let mut chars = flag.chars(); + + // Only duplicate check compiler flags + if self.is_like_msvc() { + if chars.next() != Some('/') { + return false; + } + } else if self.is_like_gnu() || self.is_like_clang() { + if chars.next() != Some('-') { + return false; + } + } + + // Check for existing optimization flags (-O, /O) + if chars.next() == Some('O') { + return self + .args() + .iter() + .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); + } + + // TODO Check for existing -m..., -m...=..., /arch:... flags + return false; + } + + /// Don't push optimization arg if it conflicts with existing args + fn push_opt_unless_duplicate(&mut self, flag: OsString) { + if self.is_duplicate_opt_arg(&flag) { + println!("Info: Ignoring duplicate arg {:?}", &flag); + } else { + self.push_cc_arg(flag); + } + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cmd = Command::new(&cc_wrapper_path); + cmd.arg(&self.path); + cmd + } + None => Command::new(&self.path), + }; + cmd.args(&self.cc_wrapper_args); + + let value = self + .args + .iter() + .filter(|a| !self.removed_args.contains(a)) + .collect::>(); + cmd.args(&value); + + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } + + /// Returns the compiler command in format of CC environment variable. + /// Or empty string if CC env was not present + /// + /// This is typically used by configure script + pub fn cc_env(&self) -> OsString { + match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); + cc_env.push(" "); + cc_env.push(self.path.to_path_buf().into_os_string()); + for arg in self.cc_wrapper_args.iter() { + cc_env.push(" "); + cc_env.push(arg); + } + cc_env + } + None => OsString::from(""), + } + } + + /// Returns the compiler flags in format of CFLAGS environment variable. + /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS + /// This is typically used by configure script + pub fn cflags_env(&self) -> OsString { + let mut flags = OsString::new(); + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(arg); + } + flags + } + + /// Whether the tool is GNU Compiler Collection-like. + pub fn is_like_gnu(&self) -> bool { + self.family == ToolFamily::Gnu + } + + /// Whether the tool is Clang-like. + pub fn is_like_clang(&self) -> bool { + self.family == ToolFamily::Clang + } + + /// Whether the tool is MSVC-like. + pub fn is_like_msvc(&self) -> bool { + match self.family { + ToolFamily::Msvc { .. } => true, + _ => false, + } + } +} + +fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { + let (mut child, print) = spawn(cmd, program)?; + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { + cmd.stdout(Stdio::piped()); + let (mut child, print) = spawn(cmd, program)?; + let mut stdout = vec![]; + child + .stdout + .take() + .unwrap() + .read_to_end(&mut stdout) + .unwrap(); + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(stdout) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { + println!("running: {:?}", cmd); + + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + let print = thread::spawn(move || { + for line in stderr.split(b'\n').filter_map(|l| l.ok()) { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + } + }); + Ok((child, print)) + } + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + Err(Error::new( + ErrorKind::ToolNotFound, + &format!("Failed to find tool. Is `{}` installed?{}", program, extra), + )) + } + Err(_) => Err(Error::new( + ErrorKind::ToolExecError, + &format!("Command {:?} with args {:?} failed to start.", cmd, program), + )), + } +} + +fn fail(s: &str) -> ! { + let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); + std::process::exit(1); +} + +fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool, is_arm: bool) { + if msvc && is_asm && is_arm { + cmd.arg("-o").arg(&dst); + } else if msvc && is_asm { + cmd.arg("/Fo").arg(dst); + } else if msvc { + let mut s = OsString::from("/Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } +} diff --git a/cc/src/registry.rs b/cc/src/registry.rs new file mode 100644 index 000000000..2ac2fa63b --- /dev/null +++ b/cc/src/registry.rs @@ -0,0 +1,204 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi::{OsStr, OsString}; +use std::io; +use std::ops::RangeFrom; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const ERROR_NO_MORE_ITEMS: DWORD = 259; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const REG_SZ: DWORD = 1; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW( + key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LONG; + fn RegEnumKeyExW( + key: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LONG; + fn RegQueryValueExW( + hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW( + self.raw(), + key.as_ptr(), + 0, + KEY_READ | KEY_WOW64_32KEY, + &mut ret, + ) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { + idx: 0.., + key: self, + } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + &mut kind, + 0 as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + if kind != REG_SZ { + return Err(io::Error::new( + io::ErrorKind::Other, + "registry key wasn't a string", + )); + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + 0 as *mut _, + v.as_mut_ptr() as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { + RegCloseKey(self.0); + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW( + self.key.raw(), + i, + v.as_mut_ptr(), + &mut len, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + ); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS as LONG { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/cc/src/setup_config.rs b/cc/src/setup_config.rs new file mode 100644 index 000000000..56fe114d7 --- /dev/null +++ b/cc/src/setup_config.rs @@ -0,0 +1,283 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] +#![allow(unused)] + +use std::ffi::OsString; +use std::ptr::null_mut; +use winapi::Interface; +use winapi::BSTR; +use winapi::LPCOLESTR; +use winapi::LPSAFEARRAY; +use winapi::S_FALSE; +use winapi::{CoCreateInstance, CLSCTX_ALL}; +use winapi::{IUnknown, IUnknownVtbl}; +use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG}; +use winapi::{LPFILETIME, ULONG}; + +use com::{BStr, ComPtr}; + +// Bindings to the Setup.Configuration stuff +pub type InstanceState = u32; + +pub const eNone: InstanceState = 0; +pub const eLocal: InstanceState = 1; +pub const eRegistered: InstanceState = 2; +pub const eNoRebootRequired: InstanceState = 4; +pub const eComplete: InstanceState = -1i32 as u32; + +RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { + fn GetInstanceId( + pbstrInstanceId: *mut BSTR, + ) -> HRESULT, + fn GetInstallDate( + pInstallDate: LPFILETIME, + ) -> HRESULT, + fn GetInstallationName( + pbstrInstallationName: *mut BSTR, + ) -> HRESULT, + fn GetInstallationPath( + pbstrInstallationPath: *mut BSTR, + ) -> HRESULT, + fn GetInstallationVersion( + pbstrInstallationVersion: *mut BSTR, + ) -> HRESULT, + fn GetDisplayName( + lcid: LCID, + pbstrDisplayName: *mut BSTR, + ) -> HRESULT, + fn GetDescription( + lcid: LCID, + pbstrDescription: *mut BSTR, + ) -> HRESULT, + fn ResolvePath( + pwszRelativePath: LPCOLESTR, + pbstrAbsolutePath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { + fn GetState( + pState: *mut InstanceState, + ) -> HRESULT, + fn GetPackages( + ppsaPackages: *mut LPSAFEARRAY, + ) -> HRESULT, + fn GetProduct( + ppPackage: *mut *mut ISetupPackageReference, + ) -> HRESULT, + fn GetProductPath( + pbstrProductPath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut ISetupInstance, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { + fn EnumInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, + fn GetInstanceForCurrentProcess( + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, + fn GetInstanceForPath( + wzPath: LPCWSTR, + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +interface ISetupConfiguration2(ISetupConfiguration2Vtbl): + ISetupConfiguration(ISetupConfigurationVtbl) { + fn EnumAllInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pbstrId: *mut BSTR, + ) -> HRESULT, + fn GetVersion( + pbstrVersion: *mut BSTR, + ) -> HRESULT, + fn GetChip( + pbstrChip: *mut BSTR, + ) -> HRESULT, + fn GetLanguage( + pbstrLanguage: *mut BSTR, + ) -> HRESULT, + fn GetBranch( + pbstrBranch: *mut BSTR, + ) -> HRESULT, + fn GetType( + pbstrType: *mut BSTR, + ) -> HRESULT, + fn GetUniqueId( + pbstrUniqueId: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { + fn ParseVersion( + pwszVersion: LPCOLESTR, + pullVersion: PULONGLONG, + ) -> HRESULT, + fn ParseVersionRange( + pwszVersionRange: LPCOLESTR, + pullMinVersion: PULONGLONG, + pullMaxVersion: PULONGLONG, + ) -> HRESULT, +}} + +DEFINE_GUID! {CLSID_SetupConfiguration, +0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} + +// Safe wrapper around the COM interfaces +pub struct SetupConfiguration(ComPtr); + +impl SetupConfiguration { + pub fn new() -> Result { + let mut obj = null_mut(); + let err = unsafe { + CoCreateInstance( + &CLSID_SetupConfiguration, + null_mut(), + CLSCTX_ALL, + &ISetupConfiguration::uuidof(), + &mut obj, + ) + }; + if err < 0 { + return Err(err); + } + let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) }; + Ok(SetupConfiguration(obj)) + } + pub fn get_instance_for_current_process(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { SetupInstance::from_raw(obj) }) + } + pub fn enum_instances(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.EnumInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } + pub fn enum_all_instances(&self) -> Result { + let mut obj = null_mut(); + let this = try!(self.0.cast::()); + let err = unsafe { this.EnumAllInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } +} + +pub struct SetupInstance(ComPtr); + +impl SetupInstance { + pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance { + SetupInstance(ComPtr::from_raw(obj)) + } + pub fn instance_id(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstanceId(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_name(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationName(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_path(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_version(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationVersion(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn product_path(&self) -> Result { + let mut s = null_mut(); + let this = try!(self.0.cast::()); + let err = unsafe { this.GetProductPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } +} + +pub struct EnumSetupInstances(ComPtr); + +impl EnumSetupInstances { + pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances { + EnumSetupInstances(ComPtr::from_raw(obj)) + } +} + +impl Iterator for EnumSetupInstances { + type Item = Result; + fn next(&mut self) -> Option> { + let mut obj = null_mut(); + let err = unsafe { self.0.Next(1, &mut obj, null_mut()) }; + if err < 0 { + return Some(Err(err)); + } + if err == S_FALSE { + return None; + } + Some(Ok(unsafe { SetupInstance::from_raw(obj) })) + } +} diff --git a/cc/src/winapi.rs b/cc/src/winapi.rs new file mode 100644 index 000000000..c416325b5 --- /dev/null +++ b/cc/src/winapi.rs @@ -0,0 +1,218 @@ +// Copyright © 2015-2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::os::raw; + +pub type wchar_t = u16; + +pub type UINT = raw::c_uint; +pub type LPUNKNOWN = *mut IUnknown; +pub type REFIID = *const IID; +pub type IID = GUID; +pub type REFCLSID = *const IID; +pub type PVOID = *mut raw::c_void; +pub type USHORT = raw::c_ushort; +pub type ULONG = raw::c_ulong; +pub type LONG = raw::c_long; +pub type DWORD = u32; +pub type LPVOID = *mut raw::c_void; +pub type HRESULT = raw::c_long; +pub type LPFILETIME = *mut FILETIME; +pub type BSTR = *mut OLECHAR; +pub type OLECHAR = WCHAR; +pub type WCHAR = wchar_t; +pub type LPCOLESTR = *const OLECHAR; +pub type LCID = DWORD; +pub type LPCWSTR = *const WCHAR; +pub type PULONGLONG = *mut ULONGLONG; +pub type ULONGLONG = u64; + +pub const S_OK: HRESULT = 0; +pub const S_FALSE: HRESULT = 1; +pub const COINIT_MULTITHREADED: u32 = 0x0; + +pub type CLSCTX = u32; + +pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1; +pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2; +pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4; +pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10; + +pub const CLSCTX_ALL: CLSCTX = + CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct GUID { + pub Data1: raw::c_ulong, + pub Data2: raw::c_ushort, + pub Data3: raw::c_ushort, + pub Data4: [raw::c_uchar; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +pub trait Interface { + fn uuidof() -> GUID; +} + +#[link(name = "ole32")] +#[link(name = "oleaut32")] +extern "C" {} + +extern "system" { + pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT; + pub fn CoCreateInstance( + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn SysFreeString(bstrString: BSTR); + pub fn SysStringLen(pbstr: BSTR) -> UINT; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAYBOUND { + pub cElements: ULONG, + pub lLbound: LONG, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAY { + pub cDims: USHORT, + pub fFeatures: USHORT, + pub cbElements: ULONG, + pub cLocks: ULONG, + pub pvData: PVOID, + pub rgsabound: [SAFEARRAYBOUND; 1], +} + +pub type LPSAFEARRAY = *mut SAFEARRAY; + +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::winapi::GUID = $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + }; +} + +macro_rules! RIDL { + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t),* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) { + }) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl ::std::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@impl $interface:ident {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + impl $interface { + $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + })+ + } + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::winapi::Interface for $interface { + #[inline] + fn uuidof() -> $crate::winapi::GUID { + $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); +} + +RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut raw::c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} diff --git a/cc/src/windows_registry.rs b/cc/src/windows_registry.rs new file mode 100644 index 000000000..af812a70b --- /dev/null +++ b/cc/src/windows_registry.rs @@ -0,0 +1,759 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use Tool; + +#[cfg(windows)] +macro_rules! otry { + ($expr:expr) => { + match $expr { + Some(val) => val, + None => return None, + } + }; +} + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + use std::env; + + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None; + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return impl_::find_msbuild(target); + } + + if tool.contains("devenv") { + return impl_::find_devenv(target); + } + + // If VCINSTALLDIR is set, then someone's probably already run vcvars and we + // should just find whatever that indicates. + if env::var_os("VCINSTALLDIR").is_some() { + return env::var_os("PATH") + .and_then(|path| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }) + .map(|path| Tool::new(path.into())); + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return impl_::find_msvc_15(tool, target) + .or_else(|| impl_::find_msvc_14(tool, target)) + .or_else(|| impl_::find_msvc_12(tool, target)) + .or_else(|| impl_::find_msvc_11(tool, target)); +} + +/// A version of Visual Studio +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum VsVers { + /// Visual Studio 12 (2013) + Vs12, + /// Visual Studio 14 (2015) + Vs14, + /// Visual Studio 15 (2017) + Vs15, + /// Visual Studio 16 (2019) + Vs16, + + /// Hidden variant that should not be matched on. Callers that want to + /// handle an enumeration of `VsVers` instances should always have a default + /// case meaning that it's a VS version they don't understand. + #[doc(hidden)] + #[allow(bad_style)] + __Nonexhaustive_do_not_match_this_or_your_code_will_break, +} + +/// Find the most recent installed version of Visual Studio +/// +/// This is used by the cmake crate to figure out the correct +/// generator. +#[cfg(not(windows))] +pub fn find_vs_version() -> Result { + Err(format!("not windows")) +} + +/// Documented above +#[cfg(windows)] +pub fn find_vs_version() -> Result { + use std::env; + + match env::var("VisualStudioVersion") { + Ok(version) => match &version[..] { + "16.0" => Ok(VsVers::Vs16), + "15.0" => Ok(VsVers::Vs15), + "14.0" => Ok(VsVers::Vs14), + "12.0" => Ok(VsVers::Vs12), + vers => Err(format!( + "\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", + vers + )), + }, + _ => { + // Check for the presense of a specific registry key + // that indicates visual studio is installed. + if impl_::has_msbuild_version("16.0") { + Ok(VsVers::Vs16) + } else if impl_::has_msbuild_version("15.0") { + Ok(VsVers::Vs15) + } else if impl_::has_msbuild_version("14.0") { + Ok(VsVers::Vs14) + } else if impl_::has_msbuild_version("12.0") { + Ok(VsVers::Vs12) + } else { + Err(format!( + "\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + " + )) + } + } + } +} + +#[cfg(windows)] +mod impl_ { + use com; + use registry::{RegistryKey, LOCAL_MACHINE}; + use setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance}; + use std::env; + use std::ffi::OsString; + use std::fs::File; + use std::io::Read; + use std::mem; + use std::iter; + use std::path::{Path, PathBuf}; + + use Tool; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { + tool, + libs, + path, + include, + } = self; + let mut tool = Tool::new(tool.into()); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + tool + } + } + + fn vs16_instances() -> Box> { + let instances = if let Some(instances) = vs15_instances() { + instances + } else { + return Box::new(iter::empty()); + }; + Box::new(instances.filter_map(|instance| { + let instance = otry!(instance.ok()); + let installation_name = otry!(instance.installation_name().ok()); + if otry!(installation_name.to_str()).starts_with("VisualStudio/16.") { + Some(PathBuf::from(otry!(instance.installation_path().ok()))) + } else { + None + } + })) + } + + fn find_tool_in_vs16_path(tool: &str, target: &str) -> Option { + vs16_instances().filter_map(|path| { + let path = path.join(tool); + if !path.is_file() { + return None; + } + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + Some(tool) + }).next() + } + + fn find_msbuild_vs16(target: &str) -> Option { + find_tool_in_vs16_path(r"MSBuild\Current\Bin\MSBuild.exe", target) + } + + // In MSVC 15 (2017) MS once again changed the scheme for locating + // the tooling. Now we must go through some COM interfaces, which + // is super fun for Rust. + // + // Note that much of this logic can be found [online] wrt paths, COM, etc. + // + // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ + fn vs15_instances() -> Option { + otry!(com::initialize().ok()); + + let config = otry!(SetupConfiguration::new().ok()); + config.enum_all_instances().ok() + } + + pub fn find_msvc_15(tool: &str, target: &str) -> Option { + let iter = otry!(vs15_instances()); + for instance in iter { + let instance = otry!(instance.ok()); + let tool = tool_from_vs15_instance(tool, target, &instance); + if tool.is_some() { + return tool; + } + } + + None + } + + // While the paths to Visual Studio 2017's devenv and MSBuild could + // potentially be retrieved from the registry, finding them via + // SetupConfiguration has shown to be [more reliable], and is preferred + // according to Microsoft. To help head off potential regressions though, + // we keep the registry method as a fallback option. + // + // [more reliable]: https://github.com/alexcrichton/cc-rs/pull/331 + fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option { + let mut path = match vs15_instances() { + Some(instances) => instances + .filter_map(|instance| { + instance + .ok() + .and_then(|instance| instance.installation_path().ok()) + }) + .map(|path| PathBuf::from(path).join(tool)) + .find(|ref path| path.is_file()), + None => None, + }; + + if path.is_none() { + let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; + path = LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| key.query_str("15.0").ok()) + .map(|path| PathBuf::from(path).join(tool)) + .and_then(|path| if path.is_file() { Some(path) } else { None }); + } + + path.map(|path| { + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } + + fn tool_from_vs15_instance(tool: &str, target: &str, instance: &SetupInstance) -> Option { + let (bin_path, host_dylib_path, lib_path, include_path) = + otry!(vs15_vc_paths(target, instance)); + let tool_path = bin_path.join(tool); + if !tool_path.exists() { + return None; + }; + + let mut tool = MsvcTool::new(tool_path); + tool.path.push(host_dylib_path); + tool.libs.push(lib_path); + tool.include.push(include_path); + + if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) { + tool.libs.push(atl_lib_path); + tool.include.push(atl_include_path); + } + + otry!(add_sdks(&mut tool, target)); + + Some(tool.into_tool()) + } + + fn vs15_vc_paths( + target: &str, + instance: &SetupInstance, + ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> { + let instance_path: PathBuf = otry!(instance.installation_path().ok()).into(); + let version_path = + instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); + let mut version_file = otry!(File::open(version_path).ok()); + let mut version = String::new(); + otry!(version_file.read_to_string(&mut version).ok()); + let version = version.trim(); + let host = match host_arch() { + X86 => "X86", + X86_64 => "X64", + _ => return None, + }; + let target = otry!(lib_subdir(target)); + // The directory layout here is MSVC/bin/Host$host/$target/ + let path = instance_path.join(r"VC\Tools\MSVC").join(version); + // This is the path to the toolchain for a particular target, running + // on a given host + let bin_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&target); + // But! we also need PATH to contain the target directory for the host + // architecture, because it contains dlls like mspdb140.dll compiled for + // the host architecture. + let host_dylib_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&host.to_lowercase()); + let lib_path = path.join("lib").join(&target); + let include_path = path.join("include"); + Some((bin_path, host_dylib_path, lib_path, include_path)) + } + + fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> { + let atl_path = path.join("atlfmc"); + let sub = otry!(lib_subdir(target)); + if atl_path.exists() { + Some((atl_path.join("lib").join(sub), atl_path.join("include"))) + } else { + None + } + } + + // For MSVC 14 we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + pub fn find_msvc_14(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("14.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + otry!(add_sdks(&mut tool, target)); + Some(tool.into_tool()) + } + + fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> { + let sub = otry!(lib_subdir(target)); + let (ucrt, ucrt_version) = otry!(get_ucrt_dir()); + + tool.path + .push(ucrt.join("bin").join(&ucrt_version).join(sub)); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("cppwinrt")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } + + Some(()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("12.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk81 = otry!(get_sdk81_dir()); + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("11.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk8 = otry!(get_sdk8_dir()); + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env + .push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target) + .into_iter() + .map(|(sub, host)| { + ( + path.join("bin").join(sub).join(tool), + path.join("bin").join(host), + ) + }) + .filter(|&(ref path, _)| path.is_file()) + .map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }) + .filter_map(|mut tool| { + let sub = otry!(vc_lib_subdir(target)); + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + let atlmfc_path = path.join("atlmfc"); + if atlmfc_path.exists() { + tool.libs.push(atlmfc_path.join("lib").join(sub)); + tool.include.push(atlmfc_path.join("include")); + } + Some(tool) + }) + .next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let path = otry!(key.query_str(ver).ok()); + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("KitsRoot10").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let max_libdir = otry!(readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| dir + .components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false)) + .max()); + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let mut dirs = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = otry!(dirs + .into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()); + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targetting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | ("i686", X86) => vec![("", "")], + ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")], + ("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey + .to_str() + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + max_key + } + + pub fn has_msbuild_version(version: &str) -> bool { + match version { + "16.0" => { + find_msbuild_vs16("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs16("i686-pc-windows-msvc").is_some() + } + "15.0" => { + find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs15("i686-pc-windows-msvc").is_some() + } + "12.0" | "14.0" => LOCAL_MACHINE + .open(&OsString::from(format!( + "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version + ))) + .is_ok(), + _ => false, + } + } + + pub fn find_devenv(target: &str) -> Option { + find_devenv_vs15(&target) + } + + fn find_devenv_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + pub fn find_msbuild(target: &str) -> Option { + // VS 15 (2017) changed how to locate msbuild + if let Some(r) = find_msbuild_vs15(target) { + return Some(r); + } else { + find_old_msbuild(target) + } + } + + fn find_msbuild_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target) + } + + fn find_old_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| { + max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok()) + }) + .map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/cc/tests/cc_env.rs b/cc/tests/cc_env.rs new file mode 100644 index 000000000..e862fea7d --- /dev/null +++ b/cc/tests/cc_env.rs @@ -0,0 +1,121 @@ +extern crate cc; +extern crate tempdir; + +use std::env; +use std::ffi::OsString; +use std::path::Path; + +mod support; +use support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); + ccache_env_flags(); + leading_spaces(); + extra_flags(); + path_to_ccache(); + more_spaces(); +} + +fn ccache() { + let test = Test::gnu(); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_env_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler")); + assert_eq!( + compiler.cc_env(), + OsString::from("ccache lol-this-is-not-a-compiler") + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains("ccache") + == false + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains(" lol-this-is-not-a-compiler") + == false + ); + + env::set_var("CC", ""); +} + +fn leading_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", " test "); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("test")); + + env::set_var("CC", ""); +} + +fn extra_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn path_to_ccache() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "/path/to/ccache.exe cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); + assert_eq!( + compiler.cc_env(), + OsString::from("/path/to/ccache.exe cc -m32"), + ); +} + +fn more_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} diff --git a/cc/tests/support/mod.rs b/cc/tests/support/mod.rs new file mode 100644 index 000000000..72ca3fa97 --- /dev/null +++ b/cc/tests/support/mod.rs @@ -0,0 +1,133 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::OsStr; +use std::fs::{self, File}; +use std::io::prelude::*; +use std::path::PathBuf; + +use cc; +use tempdir::TempDir; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + if gcc.ends_with("deps") { + gcc.pop(); + } + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: TempDir::new("gcc-test").unwrap(), + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("c++").shim("ar"); + t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + t + } + + pub fn shim(&self, name: &str) -> &Test { + let fname = format!("{}{}", name, env::consts::EXE_SUFFIX); + fs::hard_link(&self.gcc, self.td.path().join(&fname)) + .or_else(|_| fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ())) + .unwrap(); + self + } + + pub fn gcc(&self) -> cc::Build { + let mut cfg = cc::Build::new(); + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, self.td.path().to_owned()); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target) + .host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", env::join_paths(path).unwrap()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + cfg + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))) + .unwrap() + .read_to_string(&mut s) + .unwrap(); + Execution { + args: s.lines().map(|s| s.to_string()).collect(), + } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| OsStr::new(arg) == p) + } + + pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution { + let before_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(before)); + let after_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(after)); + match (before_position, after_position) { + (Some(b), Some(a)) if b < a => {} + (b, a) => panic!( + "{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", + before, b, after, a + ), + }; + self + } +} diff --git a/cc/tests/test.rs b/cc/tests/test.rs new file mode 100644 index 000000000..5147b77cb --- /dev/null +++ b/cc/tests/test.rs @@ -0,0 +1,371 @@ +extern crate cc; +extern crate tempdir; + +use std::env; +use support::Test; + +mod support; + +#[test] +fn gnu_smoke() { + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-g") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + let test = Test::gnu(); + test.gcc().opt_level(1).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-O1").must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + let test = Test::gnu(); + test.gcc().opt_level_str("s").file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-g"); +} + +#[test] +fn gnu_warnings_into_errors() { + let test = Test::gnu(); + test.gcc() + .warnings_into_errors(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Werror"); +} + +#[test] +fn gnu_warnings() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings0() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .extra_warnings(false) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_not_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings1() { + let test = Test::gnu(); + test.gcc() + .warnings(false) + .extra_warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_warnings_overridable() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have_in_order("-Wall", "-Wno-missing-field-initializers"); +} + +#[test] +fn gnu_no_warnings_if_cflags() { + env::set_var("CFLAGS", "-Wflag-does-not-exist"); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); + env::set_var("CFLAGS", ""); +} + +#[test] +fn gnu_no_warnings_if_cxxflags() { + env::set_var("CXXFLAGS", "-Wflag-does-not-exist"); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); + env::set_var("CXXFLAGS", ""); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC").must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_x86_64_no_plt() { + let target = "x86_64-unknown-linux-gnu"; + let test = Test::gnu(); + test.gcc() + .pic(true) + .use_plt(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-fno-plt"); +} + +#[test] +fn gnu_set_stdlib() { + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc().file("foo.S").compile("foo"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn gnu_shared() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(true) + .static_flag(false) + .compile("foo"); + + test.cmd(0).must_have("-shared").must_not_have("-static"); +} + +#[test] +fn gnu_flag_if_supported() { + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .flag("-v") + .flag_if_supported("-Wall") + .flag_if_supported("-Wflag-does-not-exist") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-v") + .must_have("-Wall") + .must_not_have("-Wflag-does-not-exist") + .must_not_have("-std=c++11"); +} + +#[test] +fn gnu_flag_if_supported_cpp() { + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .cpp(true) + .file("foo.cpp") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0).must_have("-std=c++11"); +} + +#[test] +fn gnu_static() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(false) + .static_flag(true) + .compile("foo"); + + test.cmd(0).must_have("-static").must_not_have("-shared"); +} + +#[test] +fn msvc_smoke() { + let test = Test::msvc(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("/O2") + .must_have("foo.c") + .must_not_have("/Z7") + .must_have("/c") + .must_have("/MD"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + let test = Test::msvc(); + test.gcc().opt_level(0).file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("/O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("/Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("/I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR"); +} + +#[test] +fn msvc_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(true).file("foo.c").compile("foo"); + + test.cmd(0).must_have("/MT"); +} + +#[test] +fn msvc_no_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(false).file("foo.c").compile("foo"); + + test.cmd(0).must_have("/MD"); +} diff --git a/cfg-if/.cargo-checksum.json b/cfg-if/.cargo-checksum.json new file mode 100644 index 000000000..0f5a252ac --- /dev/null +++ b/cfg-if/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"} \ No newline at end of file diff --git a/cfg-if/Cargo.toml b/cfg-if/Cargo.toml new file mode 100644 index 000000000..a5f7c3c76 --- /dev/null +++ b/cfg-if/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cfg-if" +version = "0.1.9" +authors = ["Alex Crichton "] +description = "A macro to ergonomically define an item depending on a large number of #[cfg]\nparameters. Structured like an if-else chain, the first matching branch is the\nitem that gets emitted.\n" +homepage = "https://github.com/alexcrichton/cfg-if" +documentation = "https://docs.rs/cfg-if" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cfg-if" +[badges.travis-ci] +repository = "alexcrichton/cfg-if" diff --git a/cfg-if/LICENSE-APACHE b/cfg-if/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/cfg-if/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cfg-if/LICENSE-MIT b/cfg-if/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/cfg-if/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cfg-if/README.md b/cfg-if/README.md new file mode 100644 index 000000000..86837212c --- /dev/null +++ b/cfg-if/README.md @@ -0,0 +1,52 @@ +# cfg-if + +[![Build Status](https://travis-ci.com/alexcrichton/cfg-if.svg?branch=master)](https://travis-ci.com/alexcrichton/cfg-if) + +[Documentation](https://docs.rs/cfg-if) + +A macro to ergonomically define an item depending on a large number of #[cfg] +parameters. Structured like an if-else chain, the first matching branch is the +item that gets emitted. + +```toml +[dependencies] +cfg-if = "0.1" +``` + +## Example + +```rust +#[macro_use] +extern crate cfg_if; + +cfg_if! { + if #[cfg(unix)] { + fn foo() { /* unix specific functionality */ } + } else if #[cfg(target_pointer_width = "32")] { + fn foo() { /* non-unix, 32-bit functionality */ } + } else { + fn foo() { /* fallback implementation */ } + } +} + +fn main() { + foo(); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/cfg-if/src/lib.rs b/cfg-if/src/lib.rs new file mode 100644 index 000000000..e867e65a8 --- /dev/null +++ b/cfg-if/src/lib.rs @@ -0,0 +1,144 @@ +//! A macro for defining `#[cfg]` if-else statements. +//! +//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C +//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases, +//! emitting the implementation which matches first. +//! +//! This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +//! without having to rewrite each clause multiple times. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate cfg_if; +//! +//! cfg_if! { +//! if #[cfg(unix)] { +//! fn foo() { /* unix specific functionality */ } +//! } else if #[cfg(target_pointer_width = "32")] { +//! fn foo() { /* non-unix, 32-bit functionality */ } +//! } else { +//! fn foo() { /* fallback implementation */ } +//! } +//! } +//! +//! # fn main() {} +//! ``` + +#![no_std] + +#![doc(html_root_url = "https://docs.rs/cfg-if")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +/// The main macro provided by this crate. See crate documentation for more +/// information. +#[macro_export(local_inner_macros)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an approprate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +#[cfg(test)] +mod tests { + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } else { + fn works1() -> Option { None } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works2() -> bool { false } + } else if #[cfg(test)] { + fn works2() -> bool { true } + } else { + fn works2() -> bool { false } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works3() -> bool { false } + } else { + fn works3() -> bool { true } + } + } + + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works5() -> bool { false } + } else if #[cfg(test)] { + fn works5() -> bool { true } + } + } + + #[test] + fn it_works() { + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); + } +} diff --git a/cfg-if/tests/xcrate.rs b/cfg-if/tests/xcrate.rs new file mode 100644 index 000000000..f42b87767 --- /dev/null +++ b/cfg-if/tests/xcrate.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate cfg_if; + +cfg_if! { + if #[cfg(foo)] { + fn works() -> bool { false } + } else if #[cfg(test)] { + fn works() -> bool { true } + } else { + fn works() -> bool { false } + } +} + +#[test] +fn smoke() { + assert!(works()); +} diff --git a/chrono/.cargo-checksum.json b/chrono/.cargo-checksum.json new file mode 100644 index 000000000..53f8ea596 --- /dev/null +++ b/chrono/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"} \ No newline at end of file diff --git a/chrono/AUTHORS.txt b/chrono/AUTHORS.txt new file mode 100644 index 000000000..9e738193f --- /dev/null +++ b/chrono/AUTHORS.txt @@ -0,0 +1,39 @@ +Chrono is mainly written by Kang Seonghoon , +and also the following people (in ascending order): + +Alex Mikhalev +Alexander Bulaev +Ashley Mannix +Ben Boeckel +Ben Eills +Brandon W Maister +Brandon W Maister +Colin Ray +Corey Farwell +Dan +Danilo Bargen +David Hewson +David Ross +David Tolnay +David Willie +Eric Findlay +Eunchong Yu +Frans Skarman +Huon Wilson +Igor Gnatenko +Jim Turner +Jisoo Park +Joe Wilm +John Heitmann +John Nagle +Jonas mg +János Illés +Ken Tossell +Martin Risell Lilja +Richard Petrie +Ryan Lewis +Sergey V. Galtsev +Steve Klabnik +Tom Gallacher +klutzy +kud1ing diff --git a/chrono/CHANGELOG.md b/chrono/CHANGELOG.md new file mode 100644 index 000000000..d4f05ba73 --- /dev/null +++ b/chrono/CHANGELOG.md @@ -0,0 +1,551 @@ +ChangeLog for Chrono +==================== + +This documents all notable changes to [Chrono](https://github.com/chronotope/chrono). + +Chrono obeys the principle of [Semantic Versioning](http://semver.org/). + +There were/are numerous minor versions before 1.0 due to the language changes. +Versions with only mechnical changes will be omitted from the following list. + +## 0.4.5 + +### Features + +* Added several more serde deserialization helpers (@novacrazy #258) +* Enabled all features on the playground (@davidtwco #267) +* Derive `Hash` on `FixedOffset` (@LuoZijun #254) +* Improved docs (@storyfeet #261, @quodlibetor #252) + +## 0.4.4 + +### Features + +* Added support for parsing nanoseconds without the leading dot (@emschwartz #251) + +## 0.4.3 + +### Features + +* Added methods to DateTime/NaiveDateTime to present the stored value as a number + of nanoseconds since the UNIX epoch (@harkonenbade #247) +* Added a serde serialise/deserialise module for nanosecond timestamps. (@harkonenbade #247) +* Added "Permissive" timezone parsing which allows a numeric timezone to + be specified without minutes. (@quodlibetor #242) + +## 0.4.2 + +### Deprecations + +* More strongly deprecate RustcSerialize: remove it from documentation unless + the feature is enabled, issue a deprecation warning if the rustc-serialize + feature is enabled (@quodlibetor #174) + +### Features + +* Move all uses of the system clock behind a `clock` feature, for use in + environments where we don't have access to the current time. (@jethrogb #236) +* Implement subtraction of two `Date`s, `Time`s, or `DateTime`s, returning a + `Duration` (@tobz1000 #237) + +## 0.4.1 + +### Bug Fixes + +* Allow parsing timestamps with subsecond precision (@jonasbb) +* RFC2822 allows times to not include the second (@upsuper) + +### Features + +* New `timestamp_millis` method on `DateTime` and `NaiveDateTim` that returns + number of milliseconds since the epoch. (@quodlibetor) +* Support exact decimal width on subsecond display for RFC3339 via a new + `to_rfc3339_opts` method on `DateTime` (@dekellum) +* Use no_std-compatible num dependencies (@cuviper) +* Add `SubsecRound` trait that allows rounding to the nearest second + (@dekellum) + +### Code Hygiene and Docs + +* Docs! (@alatiera @kosta @quodlibetor @kennytm) +* Run clippy and various fixes (@quodlibetor) + +## 0.4.0 (2017-06-22) + +This was originally planned as a minor release but was pushed to a major +release due to the compatibility concern raised. + +### Added + +- `IsoWeek` has been added for the ISO week without time zone. + +- The `+=` and `-=` operators against `time::Duration` are now supported for + `NaiveDate`, `NaiveTime` and `NaiveDateTime`. (#99) + + (Note that this does not invalidate the eventual deprecation of `time::Duration`.) + +- `SystemTime` and `DateTime` types can be now converted to each other via `From`. + Due to the obvious lack of time zone information in `SystemTime`, + the forward direction is limited to `DateTime` and `DateTime` only. + +### Changed + +- Intermediate implementation modules have been flattened (#161), + and `UTC` has been renamed to `Utc` in accordance with the current convention (#148). + + The full list of changes is as follows: + + Before | After + ---------------------------------------- | ---------------------------- + `chrono::date::Date` | `chrono::Date` + `chrono::date::MIN` | `chrono::MIN_DATE` + `chrono::date::MAX` | `chrono::MAX_DATE` + `chrono::datetime::DateTime` | `chrono::DateTime` + `chrono::naive::time::NaiveTime` | `chrono::naive::NaiveTime` + `chrono::naive::date::NaiveDate` | `chrono::naive::NaiveDate` + `chrono::naive::date::MIN` | `chrono::naive::MIN_DATE` + `chrono::naive::date::MAX` | `chrono::naive::MAX_DATE` + `chrono::naive::datetime::NaiveDateTime` | `chrono::naive::NaiveDateTime` + `chrono::offset::utc::UTC` | `chrono::offset::Utc` + `chrono::offset::fixed::FixedOffset` | `chrono::offset::FixedOffset` + `chrono::offset::local::Local` | `chrono::offset::Local` + `chrono::format::parsed::Parsed` | `chrono::format::Parsed` + + With an exception of `Utc`, this change does not affect any direct usage of + `chrono::*` or `chrono::prelude::*` types. + +- `Datelike::isoweekdate` is replaced by `Datelike::iso_week` which only returns the ISO week. + + The original method used to return a tuple of year number, week number and day of the week, + but this duplicated the `Datelike::weekday` method and it had been hard to deal with + the raw year and week number for the ISO week date. + This change isolates any logic and API for the week date into a separate type. + +- `NaiveDateTime` and `DateTime` can now be deserialized from an integral UNIX timestamp. (#125) + + This turns out to be very common input for web-related usages. + The existing string representation is still supported as well. + +- `chrono::serde` and `chrono::naive::serde` modules have been added + for the serialization utilities. (#125) + + Currently they contain the `ts_seconds` modules that can be used to + serialize `NaiveDateTime` and `DateTime` values into an integral UNIX timestamp. + This can be combined with Serde's `[de]serialize_with` attributes + to fully support the (de)serialization to/from the timestamp. + + For rustc-serialize, there are separate `chrono::TsSeconds` and `chrono::naive::TsSeconds` types + that are newtype wrappers implementing different (de)serialization logics. + This is a suboptimal API, however, and it is strongly recommended to migrate to Serde. + +### Fixed + +- The major version was made to fix the broken Serde dependency issues. (#146, #156, #158, #159) + + The original intention to technically break the dependency was + to faciliate the use of Serde 1.0 at the expense of temporary breakage. + Whether this was appropriate or not is quite debatable, + but it became clear that there are several high-profile crates requiring Serde 0.9 + and it is not feasible to force them to use Serde 1.0 anyway. + + To the end, the new major release was made with some known lower-priority breaking changes. + 0.3.1 is now yanked and any remaining 0.3 users can safely roll back to 0.3.0. + +- Various documentation fixes and goodies. (#92, #131, #136) + +## 0.3.1 (2017-05-02) + +### Added + +- `Weekday` now implements `FromStr`, `Serialize` and `Deserialize`. (#113) + + The syntax is identical to `%A`, i.e. either the shortest or the longest form of English names. + +### Changed + +- Serde 1.0 is now supported. (#142) + + This is technically a breaking change because Serde 0.9 and 1.0 are not compatible, + but this time we decided not to issue a minor version because + we have already seen Serde 0.8 and 0.9 compatibility problems even after 0.3.0 and + a new minor version turned out to be not very helpful for this kind of issues. + +### Fixed + +- Fixed a bug that the leap second can be mapped wrongly in the local time zone. + Only occurs when the local time zone is behind UTC. (#130) + +## 0.3.0 (2017-02-07) + +The project has moved to the [Chronotope](https://github.com/chronotope/) organization. + +### Added + +- `chrono::prelude` module has been added. All other glob imports are now discouraged. + +- `FixedOffset` can be added to or subtracted from any timelike types. + + - `FixedOffset::local_minus_utc` and `FixedOffset::utc_minus_local` methods have been added. + Note that the old `Offset::local_minus_utc` method is gone; see below. + +- Serde support for non-self-describing formats like Bincode is added. (#89) + +- Added `Item::Owned{Literal,Space}` variants for owned formatting items. (#76) + +- Formatting items and the `Parsed` type have been slightly adjusted so that + they can be internally extended without breaking any compatibility. + +- `Weekday` is now `Hash`able. (#109) + +- `ParseError` now implements `Eq` as well as `PartialEq`. (#114) + +- More documentation improvements. (#101, #108, #112) + +### Changed + +- Chrono now only supports Rust 1.13.0 or later (previously: Rust 1.8.0 or later). + +- Serde 0.9 is now supported. + Due to the API difference, support for 0.8 or older is discontinued. (#122) + +- Rustc-serialize implementations are now on par with corresponding Serde implementations. + They both standardize on the `std::fmt::Debug` textual output. + + **This is a silent breaking change (hopefully the last though).** + You should be prepared for the format change if you depended on rustc-serialize. + +- `Offset::local_minus_utc` is now `Offset::fix`, and returns `FixedOffset` instead of a duration. + + This makes every time zone operation operate within a bias less than one day, + and vastly simplifies many logics. + +- `chrono::format::format` now receives `FixedOffset` instead of `time::Duration`. + +- The following methods and implementations have been renamed and older names have been *removed*. + The older names will be reused for the same methods with `std::time::Duration` in the future. + + - `checked_*` → `checked_*_signed` in `Date`, `DateTime`, `NaiveDate` and `NaiveDateTime` types + + - `overflowing_*` → `overflowing_*_signed` in the `NaiveTime` type + + - All subtraction implementations between two time instants have been moved to + `signed_duration_since`, following the naming in `std::time`. + +### Fixed + +- Fixed a panic when the `Local` offset receives a leap second. (#123) + +### Removed + +- Rustc-serialize support for `Date` types and all offset types has been dropped. + + These implementations were automatically derived and never had been in a good shape. + Moreover there are no corresponding Serde implementations, limiting their usefulness. + In the future they may be revived with more complete implementations. + +- The following method aliases deprecated in the 0.2 branch have been removed. + + - `DateTime::num_seconds_from_unix_epoch` (→ `DateTime::timestamp`) + - `NaiveDateTime::from_num_seconds_from_unix_epoch` (→ `NaiveDateTime::from_timestamp`) + - `NaiveDateTime::from_num_seconds_from_unix_epoch_opt` (→ `NaiveDateTime::from_timestamp_opt`) + - `NaiveDateTime::num_seconds_unix_epoch` (→ `NaiveDateTime::timestamp`) + +- Formatting items are no longer `Copy`, except for `chrono::format::Pad`. + +- `chrono::offset::add_with_leapsecond` has been removed. + Use a direct addition with `FixedOffset` instead. + +## 0.2.25 (2016-08-04) + +This is the last version officially supports Rust 1.12.0 or older. + +(0.2.24 was accidentally uploaded without a proper check for warnings in the default state, +and replaced by 0.2.25 very shortly. Duh.) + +### Added + +- Serde 0.8 is now supported. 0.7 also remains supported. (#86) + +### Fixed + +- The deserialization implementation for rustc-serialize now properly verifies the input. + All serialization codes are also now thoroughly tested. (#42) + +## 0.2.23 (2016-08-03) + +### Added + +- The documentation was greatly improved for several types, + and tons of cross-references have been added. (#77, #78, #80, #82) + +- `DateTime::timestamp_subsec_{millis,micros,nanos}` methods have been added. (#81) + +### Fixed + +- When the system time records a leap second, + the nanosecond component was mistakenly reset to zero. (#84) + +- `Local` offset misbehaves in Windows for August and later, + due to the long-standing libtime bug (dates back to mid-2015). + Workaround has been implemented. (#85) + +## 0.2.22 (2016-04-22) + +### Fixed + +- `%.6f` and `%.9f` used to print only three digits when the nanosecond part is zero. (#71) +- The documentation for `%+` has been updated to reflect the current status. (#71) + +## 0.2.21 (2016-03-29) + +### Fixed + +- `Fixed::LongWeekdayName` was unable to recognize `"sunday"` (whoops). (#66) + +## 0.2.20 (2016-03-06) + +### Changed + +- `serde` dependency has been updated to 0.7. (#63, #64) + +## 0.2.19 (2016-02-05) + +### Added + +- The documentation for `Date` is made clear about its ambiguity and guarantees. + +### Fixed + +- `DateTime::date` had been wrong when the local date and the UTC date is in disagreement. (#61) + +## 0.2.18 (2016-01-23) + +### Fixed + +- Chrono no longer pulls a superfluous `rand` dependency. (#57) + +## 0.2.17 (2015-11-22) + +### Added + +- Naive date and time types and `DateTime` now have a `serde` support. + They serialize as an ISO 8601 / RFC 3339 string just like `Debug`. (#51) + +## 0.2.16 (2015-09-06) + +### Added + +- Added `%.3f`, `%.6f` and `%.9f` specifier for formatting fractional seconds + up to 3, 6 or 9 decimal digits. This is a natural extension to the existing `%f`. + Note that this is (not yet) generic, no other value of precision is supported. (#45) + +### Changed + +- Forbade unsized types from implementing `Datelike` and `Timelike`. + This does not make a big harm as any type implementing them should be already sized + to be practical, but this change still can break highly generic codes. (#46) + +### Fixed + +- Fixed a broken link in the `README.md`. (#41) + +## 0.2.15 (2015-07-05) + +### Added + +- Padding modifiers `%_?`, `%-?` and `%0?` are implemented. + They are glibc extensions which seem to be reasonably widespread (e.g. Ruby). + +- Added `%:z` specifier and corresponding formatting items + which is essentially same to `%z` but with a colon. + +- Added a new specifier `%.f` which precision adapts from the input. + This was added as a response to the UX problems in the original nanosecond specifier `%f`. + +### Fixed + +- `Numeric::Timestamp` specifier (`%s`) was ignoring the time zone offset when provided. + +- Improved the documentation and associated tests for `strftime`. + +## 0.2.14 (2015-05-15) + +### Fixed + +- `NaiveDateTime +/- Duration` or `NaiveTime +/- Duration` could have gone wrong + when the `Duration` to be added is negative and has a fractional second part. + This was caused by an underflow in the conversion from `Duration` to the parts; + the lack of tests for this case allowed a bug. (#37) + +## 0.2.13 (2015-04-29) + +### Added + +- The optional dependency on `rustc_serialize` and + relevant `Rustc{En,De}codable` implementations for supported types has been added. + This is enabled by the `rustc-serialize` Cargo feature. (#34) + +### Changed + +- `chrono::Duration` reexport is changed to that of crates.io `time` crate. + This enables Rust 1.0 beta compatibility. + +## 0.2.4 (2015-03-03) + +### Fixed + +- Clarified the meaning of `Date` and fixed unwanted conversion problem + that only occurs with positive UTC offsets. (#27) + +## 0.2.3 (2015-02-27) + +### Added + +- `DateTime` and `Date` is now `Copy`/`Send` when `Tz::Offset` is `Copy`/`Send`. + The implementations for them were mistakenly omitted. (#25) + +### Fixed + +- `Local::from_utc_datetime` didn't set a correct offset. (#26) + +## 0.2.1 (2015-02-21) + +### Changed + +- `DelayedFormat` no longer conveys a redundant lifetime. + +## 0.2.0 (2015-02-19) + +### Added + +- `Offset` is splitted into `TimeZone` (constructor) and `Offset` (storage) types. + You would normally see only the former, as the latter is mostly an implementation detail. + Most importantly, `Local` now can be used to directly construct timezone-aware values. + + Some types (currently, `UTC` and `FixedOffset`) are both `TimeZone` and `Offset`, + but others aren't (e.g. `Local` is not what is being stored to each `DateTime` values). + +- `LocalResult::map` convenience method has been added. + +- `TimeZone` now allows a construction of `DateTime` values from UNIX timestamp, + via `timestamp` and `timestamp_opt` methods. + +- `TimeZone` now also has a method for parsing `DateTime`, namely `datetime_from_str`. + +- The following methods have been added to all date and time types: + + - `checked_add` + - `checked_sub` + - `format_with_items` + +- The following methods have been added to all timezone-aware types: + + - `timezone` + - `with_timezone` + - `naive_utc` + - `naive_local` + +- `parse_from_str` method has been added to all naive types and `DateTime`. + +- All naive types and instances of `DateTime` with time zones `UTC`, `Local` and `FixedOffset` + implement the `FromStr` trait. They parse what `std::fmt::Debug` would print. + +- `chrono::format` has been greatly rewritten. + + - The formatting syntax parser is modular now, available at `chrono::format::strftime`. + + - The parser and resolution algorithm is also modular, the former is available at + `chrono::format::parse` while the latter is available at `chrono::format::parsed`. + + - Explicit support for RFC 2822 and 3339 syntaxes is landed. + + - There is a minor formatting difference with atypical values, + e.g. for years not between 1 BCE and 9999 CE. + +### Changed + +- Most uses of `Offset` are converted to `TimeZone`. + In fact, *all* user-facing code is expected to be `Offset`-free. + +- `[Naive]DateTime::*num_seconds_from_unix_epoch*` methods have been renamed to + simply `timestamp` or `from_timestamp*`. The original names have been deprecated. + +### Removed + +- `Time` has been removed. This also prompts a related set of methods in `TimeZone`. + + This is in principle possible, but in practice has seen a little use + because it can only be meaningfully constructed via an existing `DateTime` value. + This made many operations to `Time` unintuitive or ambiguous, + so we simply let it go. + + In the case that `Time` is really required, one can use a simpler `NaiveTime`. + `NaiveTime` and `NaiveDate` can be freely combined and splitted, + and `TimeZone::from_{local,utc}_datetime` can be used to convert from/to the local time. + +- `with_offset` method has been removed. Use `with_timezone` method instead. + (This is not deprecated since it is an integral part of offset reform.) + +## 0.1.14 (2015-01-10) + +### Added + +- Added a missing `std::fmt::String` impl for `Local`. + +## 0.1.13 (2015-01-10) + +### Changed + +- Most types now implement both `std::fmt::Show` and `std::fmt::String`, + with the former used for the stricter output and the latter used for more casual output. + +### Removed + +- `Offset::name` has been replaced by a `std::fmt::String` implementation to `Offset`. + +## 0.1.12 (2015-01-08) + +### Removed + +- `Duration + T` no longer works due to the updated impl reachability rules. + Use `T + Duration` as a workaround. + +## 0.1.4 (2014-12-13) + +### Fixed + +- Fixed a bug that `Date::and_*` methods with an offset that can change the date are + off by one day. + +## 0.1.3 (2014-11-28) + +### Added + +- `{Date,Time,DateTime}::with_offset` methods have been added. + +- `LocalResult` now implements a common set of traits. + +- `LocalResult::and_*` methods have been added. + They are useful for safely chaining `LocalResult>` methods + to make `LocalResult>`. + +### Changed + +- `Offset::name` now returns `SendStr`. + +- `{Date,Time} - Duration` overloadings are now allowed. + +## 0.1.2 (2014-11-24) + +### Added + +- `Duration + Date` overloading is now allowed. + +### Changed + +- Chrono no longer needs `num` dependency. + +## 0.1.0 (2014-11-20) + +The initial version that was available to `crates.io`. + diff --git a/chrono/Cargo.toml b/chrono/Cargo.toml new file mode 100644 index 000000000..44448a75a --- /dev/null +++ b/chrono/Cargo.toml @@ -0,0 +1,72 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "chrono" +version = "0.4.6" +authors = ["Kang Seonghoon ", "Brandon W Maister "] +description = "Date and time library for Rust" +homepage = "https://github.com/chronotope/chrono" +documentation = "https://docs.rs/chrono/" +readme = "README.md" +keywords = ["date", "time", "calendar"] +categories = ["date-and-time"] +license = "MIT/Apache-2.0" +repository = "https://github.com/chronotope/chrono" +[package.metadata.docs.rs] +all-features = true + +[package.metadata.playground] +all-features = true + +[lib] +name = "chrono" +[dependencies.num-integer] +version = "0.1.36" +default-features = false + +[dependencies.num-traits] +version = "0.2" +default-features = false + +[dependencies.rustc-serialize] +version = "0.3.20" +optional = true + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.time] +version = "0.1.39" +optional = true +[dev-dependencies.bincode] +version = "0.8.0" + +[dev-dependencies.num-iter] +version = "0.1.35" +default-features = false + +[dev-dependencies.serde_derive] +version = "1" + +[dev-dependencies.serde_json] +version = "1" + +[features] +clock = ["time"] +default = ["clock"] +[badges.appveyor] +repository = "chronotope/chrono" + +[badges.travis-ci] +repository = "chronotope/chrono" diff --git a/chrono/LICENSE.txt b/chrono/LICENSE.txt new file mode 100644 index 000000000..924ff57f2 --- /dev/null +++ b/chrono/LICENSE.txt @@ -0,0 +1,240 @@ +Rust-chrono is dual-licensed under The MIT License [1] and +Apache 2.0 License [2]. Copyright (c) 2014--2017, Kang Seonghoon and +contributors. + +Nota Bene: This is same as the Rust Project's own license. + + +[1]: , which is reproduced below: + +~~~~ +The MIT License (MIT) + +Copyright (c) 2014, Kang Seonghoon. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +~~~~ + + +[2]: , which is reproduced below: + +~~~~ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +~~~~ + diff --git a/chrono/Makefile b/chrono/Makefile new file mode 100644 index 000000000..bb938ccea --- /dev/null +++ b/chrono/Makefile @@ -0,0 +1,30 @@ +# this Makefile is mostly for the packaging convenience. +# casual users should use `cargo` to retrieve the appropriate version of Chrono. + +.PHONY: all +all: + @echo 'Try `cargo build` instead.' + +.PHONY: authors +authors: + echo 'Chrono is mainly written by Kang Seonghoon ,' > AUTHORS.txt + echo 'and also the following people (in ascending order):' >> AUTHORS.txt + echo >> AUTHORS.txt + git log --format='%aN <%aE>' | grep -v 'Kang Seonghoon' | sort -u >> AUTHORS.txt + +.PHONY: readme README.md +readme: README.md + +README.md: src/lib.rs + ( ./ci/fix-readme.sh $< ) > $@ + +.PHONY: test +test: + TZ=UTC0 cargo test --features 'serde rustc-serialize bincode' --lib + TZ=ACST-9:30 cargo test --features 'serde rustc-serialize bincode' --lib + TZ=EST4 cargo test --features 'serde rustc-serialize bincode' + +.PHONY: doc +doc: authors readme + cargo doc --features 'serde rustc-serialize bincode' + diff --git a/chrono/README.md b/chrono/README.md new file mode 100644 index 000000000..8a37c7b77 --- /dev/null +++ b/chrono/README.md @@ -0,0 +1,391 @@ +[Chrono][docsrs]: Date and Time for Rust +======================================== + +[![Chrono on Travis CI][travis-image]][travis] +[![Chrono on Appveyor][appveyor-image]][appveyor] +[![Chrono on crates.io][cratesio-image]][cratesio] +[![Chrono on docs.rs][docsrs-image]][docsrs] +[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter] + +[travis-image]: https://travis-ci.org/chronotope/chrono.svg?branch=master +[travis]: https://travis-ci.org/chronotope/chrono +[appveyor-image]: https://ci.appveyor.com/api/projects/status/2ia91ofww4w31m2w/branch/master?svg=true +[appveyor]: https://ci.appveyor.com/project/chronotope/chrono +[cratesio-image]: https://img.shields.io/crates/v/chrono.svg +[cratesio]: https://crates.io/crates/chrono +[docsrs-image]: https://docs.rs/chrono/badge.svg +[docsrs]: https://docs.rs/chrono +[gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg +[gitter]: https://gitter.im/chrono-rs/chrono + +It aims to be a feature-complete superset of +the [time](https://github.com/rust-lang-deprecated/time) library. +In particular, + +* Chrono strictly adheres to ISO 8601. +* Chrono is timezone-aware by default, with separate timezone-naive types. +* Chrono is space-optimal and (while not being the primary goal) reasonably efficient. + +There were several previous attempts to bring a good date and time library to Rust, +which Chrono builds upon and should acknowledge: + +* [Initial research on + the wiki](https://github.com/rust-lang/rust-wiki-backup/blob/master/Lib-datetime.md) +* Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs) +* Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime) + +Any significant changes to Chrono are documented in +the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/master/CHANGELOG.md) file. + + +## Usage + +Put this in your `Cargo.toml`: + +```toml +[dependencies] +chrono = "0.4" +``` + +Or, if you want [Serde](https://github.com/serde-rs/serde) include the +feature like this: + +```toml +[dependencies] +chrono = { version = "0.4", features = ["serde"] } +``` + +Then put this in your crate root: + +```rust +extern crate chrono; +``` + +Avoid using `use chrono::*;` as Chrono exports several modules other than types. +If you prefer the glob imports, use the following instead: + +```rust +use chrono::prelude::*; +``` + +## Overview + +### Duration + +Chrono currently uses +the [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type +from the `time` crate to represent the magnitude of a time span. +Since this has the same name to the newer, standard type for duration, +the reference will refer this type as `OldDuration`. +Note that this is an "accurate" duration represented as seconds and +nanoseconds and does not represent "nominal" components such as days or +months. + +Chrono does not yet natively support +the standard [`Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type, +but it will be supported in the future. +Meanwhile you can convert between two types with +[`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std) +and +[`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std) +methods. + +### Date and Time + +Chrono provides a +[**`DateTime`**](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html) +type to represent a date and a time in a timezone. + +For more abstract moment-in-time tracking such as internal timekeeping +that is unconcerned with timezones, consider +[`time::SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html), +which tracks your system clock, or +[`time::Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html), which +is an opaque but monotonically-increasing representation of a moment in time. + +`DateTime` is timezone-aware and must be constructed from +the [**`TimeZone`**](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html) object, +which defines how the local date is converted to and back from the UTC date. +There are three well-known `TimeZone` implementations: + +* [**`Utc`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Utc.html) specifies the UTC time zone. It is most efficient. + +* [**`Local`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Local.html) specifies the system local time zone. + +* [**`FixedOffset`**](https://docs.rs/chrono/0.4.6/chrono/offset/struct.FixedOffset.html) specifies + an arbitrary, fixed time zone such as UTC+09:00 or UTC-10:30. + This often results from the parsed textual date and time. + Since it stores the most information and does not depend on the system environment, + you would want to normalize other `TimeZone`s into this type. + +`DateTime`s with different `TimeZone` types are distinct and do not mix, +but can be converted to each other using +the [`DateTime::with_timezone`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.with_timezone) method. + +You can get the current date and time in the UTC time zone +([`Utc::now()`](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Utc.html#method.now)) +or in the local time zone +([`Local::now()`](https://docs.rs/chrono/0.4.6/chrono/offset/struct.Local.html#method.now)). + +```rust +use chrono::prelude::*; + +let utc: DateTime = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z` +let local: DateTime = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00` +``` + +Alternatively, you can create your own date and time. +This is a bit verbose due to Rust's lack of function and method overloading, +but in turn we get a rich combination of initialization methods. + +```rust +use chrono::prelude::*; +use chrono::offset::LocalResult; + +let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z` +// July 8 is 188th day of the year 2014 (`o` for "ordinal") +assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11)); +// July 8 is Tuesday in ISO week 28 of the year 2014. +assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11)); + +let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z` +assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000)); +assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000)); + +// dynamic verification +assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33), + LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33))); +assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None); +assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None); + +// other time zone objects can be used to construct a local datetime. +// obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical. +let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); +let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12); +assert_eq!(dt, fixed_dt); +``` + +Various properties are available to the date and time, and can be altered individually. +Most of them are defined in the traits [`Datelike`](https://docs.rs/chrono/0.4.6/chrono/trait.Datelike.html) and +[`Timelike`](https://docs.rs/chrono/0.4.6/chrono/trait.Timelike.html) which you should `use` before. +Addition and subtraction is also supported. +The following illustrates most supported operations to the date and time: + +```rust +use chrono::prelude::*; +use time::Duration; + +// assume this returned `2014-11-28T21:45:59.324310806+09:00`: +let dt = Local::now(); + +// property accessors +assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); +assert_eq!((dt.month0(), dt.day0()), (10, 27)); // for unfortunate souls +assert_eq!((dt.hour(), dt.minute(), dt.second()), (21, 45, 59)); +assert_eq!(dt.weekday(), Weekday::Fri); +assert_eq!(dt.weekday().number_from_monday(), 5); // Mon=1, ..., Sat=7 +assert_eq!(dt.ordinal(), 332); // the day of year +assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1 + +// time zone accessor and manipulation +assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600); +assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)); +assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806)); + +// a sample of property manipulations (validates dynamically) +assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday +assert_eq!(dt.with_day(32), None); +assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE + +// arithmetic operations +let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10); +let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8); +assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2)); +assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2)); +assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000), + Utc.ymd(2001, 9, 9).and_hms(1, 46, 40)); +assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000), + Utc.ymd(1938, 4, 24).and_hms(22, 13, 20)); +``` + +### Formatting and Parsing + +Formatting is done via the [`format`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.format) method, +which format is equivalent to the familiar `strftime` format. + +See [`format::strftime`](https://docs.rs/chrono/0.4.6/chrono/format/strftime/index.html#specifiers) +documentation for full syntax and list of specifiers. + +The default `to_string` method and `{:?}` specifier also give a reasonable representation. +Chrono also provides [`to_rfc2822`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.to_rfc2822) and +[`to_rfc3339`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.to_rfc3339) methods +for well-known formats. + +```rust +use chrono::prelude::*; + +let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); +assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); +assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); +assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string()); + +assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); +assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000"); +assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00"); +assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); + +// Note that milli/nanoseconds are only printed if they are non-zero +let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1); +assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z"); +``` + +Parsing can be done with three methods: + +1. The standard [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait + (and [`parse`](https://doc.rust-lang.org/std/primitive.str.html#method.parse) method + on a string) can be used for parsing `DateTime`, `DateTime` and + `DateTime` values. This parses what the `{:?}` + ([`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html)) + format specifier prints, and requires the offset to be present. + +2. [`DateTime::parse_from_str`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_str) parses + a date and time with offsets and returns `DateTime`. + This should be used when the offset is a part of input and the caller cannot guess that. + It *cannot* be used when the offset can be missing. + [`DateTime::parse_from_rfc2822`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_rfc2822) + and + [`DateTime::parse_from_rfc3339`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.parse_from_rfc3339) + are similar but for well-known formats. + +3. [`Offset::datetime_from_str`](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html#method.datetime_from_str) is + similar but returns `DateTime` of given offset. + When the explicit offset is missing from the input, it simply uses given offset. + It issues an error when the input contains an explicit offset different + from the current offset. + +More detailed control over the parsing process is available via +[`format`](https://docs.rs/chrono/0.4.6/chrono/format/index.html) module. + +```rust +use chrono::prelude::*; + +let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); +let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600)); + +// method 1 +assert_eq!("2014-11-28T12:00:09Z".parse::>(), Ok(dt.clone())); +assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(dt.clone())); +assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(fixed_dt.clone())); + +// method 2 +assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00", "%Y-%m-%d %H:%M:%S %z"), + Ok(fixed_dt.clone())); +assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900"), + Ok(fixed_dt.clone())); +assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone())); + +// method 3 +assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone())); +assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone())); + +// oops, the year is missing! +assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err()); +// oops, the format string does not include the year at all! +assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err()); +// oops, the weekday is incorrect! +assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err()); +``` + +Again : See [`format::strftime`](https://docs.rs/chrono/0.4.6/chrono/format/strftime/index.html#specifiers) +documentation for full syntax and list of specifiers. + +### Conversion from and to EPOCH timestamps + +Use [`Utc.timestamp(seconds, nanoseconds)`](https://docs.rs/chrono/0.4.6/chrono/offset/trait.TimeZone.html#method.timestamp) +to construct a [`DateTime`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html) from a UNIX timestamp +(seconds, nanoseconds that passed since January 1st 1970). + +Use [`DateTime.timestamp`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.timestamp) to get the timestamp (in seconds) +from a [`DateTime`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html). Additionally, you can use +[`DateTime.timestamp_subsec_nanos`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.timestamp_subsec_nanos) +to get the number of additional number of nanoseconds. + +```rust +// We need the trait in scope to use Utc::timestamp(). +use chrono::TimeZone; + +// Construct a datetime from epoch: +let dt = Utc.timestamp(1_500_000_000, 0); +assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000"); + +// Get epoch value from a datetime: +let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap(); +assert_eq!(dt.timestamp(), 1_500_000_000); +``` + +### Individual date + +Chrono also provides an individual date type ([**`Date`**](https://docs.rs/chrono/0.4.6/chrono/struct.Date.html)). +It also has time zones attached, and have to be constructed via time zones. +Most operations available to `DateTime` are also available to `Date` whenever appropriate. + +```rust +use chrono::prelude::*; +use chrono::offset::LocalResult; + +assert_eq!(Utc::today(), Utc::now().date()); +assert_eq!(Local::today(), Local::now().date()); + +assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri); +assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); +assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), + "070809"); +``` + +There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. + +`DateTime` has [`date`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.date) method +which returns a `Date` which represents its date component. +There is also a [`time`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.time) method, +which simply returns a naive local time described below. + +### Naive date and time + +Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime` +as [**`NaiveDate`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveDate.html), +[**`NaiveTime`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveTime.html) and +[**`NaiveDateTime`**](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveDateTime.html) respectively. + +They have almost equivalent interfaces as their timezone-aware twins, +but are not associated to time zones obviously and can be quite low-level. +They are mostly useful for building blocks for higher-level types. + +Timezone-aware `DateTime` and `Date` types have two methods returning naive versions: +[`naive_local`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.naive_local) returns +a view to the naive local time, +and [`naive_utc`](https://docs.rs/chrono/0.4.6/chrono/struct.DateTime.html#method.naive_utc) returns +a view to the naive UTC time. + +## Limitations + +Only proleptic Gregorian calendar (i.e. extended to support older dates) is supported. +Be very careful if you really have to deal with pre-20C dates, they can be in Julian or others. + +Date types are limited in about +/- 262,000 years from the common epoch. +Time types are limited in the nanosecond accuracy. + +[Leap seconds are supported in the representation but +Chrono doesn't try to make use of them](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveTime.html#leap-second-handling). +(The main reason is that leap seconds are not really predictable.) +Almost *every* operation over the possible leap seconds will ignore them. +Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale +if you want. + +Chrono inherently does not support an inaccurate or partial date and time representation. +Any operation that can be ambiguous will return `None` in such cases. +For example, "a month later" of 2014-01-30 is not well-defined +and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `None`. + +Advanced time zone handling is not yet supported. +For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead. + diff --git a/chrono/appveyor.yml b/chrono/appveyor.yml new file mode 100644 index 000000000..42d85d9d8 --- /dev/null +++ b/chrono/appveyor.yml @@ -0,0 +1,21 @@ +environment: + matrix: + - TARGET: 1.13.0-x86_64-pc-windows-gnu + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + - TARGET: nightly-x86_64-pc-windows-gnu + - TARGET: nightly-i686-pc-windows-gnu +matrix: + allow_failures: + - channel: nightly +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe" + - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - rustc -vV + - cargo -vV + +build: false + +test_script: + - sh -c 'PATH=`rustc --print sysroot`/bin:$PATH ./ci/travis.sh' diff --git a/chrono/ci/fix-readme.sh b/chrono/ci/fix-readme.sh new file mode 100755 index 000000000..87d838f64 --- /dev/null +++ b/chrono/ci/fix-readme.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +VERSION="$( cargo read-manifest | python -c 'import json, sys; print(json.load(sys.stdin)["version"])')" +LIB="$1" + +# Make the Chrono in the header a link to the docs +awk '/^\/\/! # Chrono: / { print "[Chrono][docsrs]:", substr($0, index($0, $4))}' "$LIB" +awk '/^\/\/! # Chrono: / { print "[Chrono][docsrs]:", substr($0, index($0, $4))}' "$LIB" | sed 's/./=/g' +# Add all the badges +echo ' +[![Chrono on Travis CI][travis-image]][travis] +[![Chrono on Appveyor][appveyor-image]][appveyor] +[![Chrono on crates.io][cratesio-image]][cratesio] +[![Chrono on docs.rs][docsrs-image]][docsrs] +[![Join the chat at https://gitter.im/chrono-rs/chrono][gitter-image]][gitter] + +[travis-image]: https://travis-ci.org/chronotope/chrono.svg?branch=master +[travis]: https://travis-ci.org/chronotope/chrono +[appveyor-image]: https://ci.appveyor.com/api/projects/status/2ia91ofww4w31m2w/branch/master?svg=true +[appveyor]: https://ci.appveyor.com/project/chronotope/chrono +[cratesio-image]: https://img.shields.io/crates/v/chrono.svg +[cratesio]: https://crates.io/crates/chrono +[docsrs-image]: https://docs.rs/chrono/badge.svg +[docsrs]: https://docs.rs/chrono +[gitter-image]: https://badges.gitter.im/chrono-rs/chrono.svg +[gitter]: https://gitter.im/chrono-rs/chrono' + +# print the section between the header and the usage +awk '/^\/\/! # Chrono:/,/^\/\/! ## /' "$LIB" | cut -b 5- | grep -v '^#' | \ + sed 's/](\.\//](https:\/\/docs.rs\/chrono\/'$VERSION'\/chrono\//g' +echo +# Replace relative doc links with links to this exact version of docs on +# docs.rs +awk '/^\/\/! ## /,!/^\/\/!/' "$LIB" | cut -b 5- | grep -v '^# ' | \ + sed 's/](\.\//](https:\/\/docs.rs\/chrono\/'$VERSION'\/chrono\//g' \ diff --git a/chrono/ci/travis.sh b/chrono/ci/travis.sh new file mode 100755 index 000000000..4a974b139 --- /dev/null +++ b/chrono/ci/travis.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +# This is the script that's executed by travis, you can run it yourself to run +# the exact same suite + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +channel() { + if [ -n "${TRAVIS}" ]; then + if [ "${TRAVIS_RUST_VERSION}" = "${CHANNEL}" ]; then + pwd + (set -x; cargo "$@") + fi + elif [ -n "${APPVEYOR}" ]; then + if [ "${APPVEYOR_RUST_CHANNEL}" = "${CHANNEL}" ]; then + pwd + (set -x; cargo "$@") + fi + else + pwd + (set -x; cargo "+${CHANNEL}" "$@") + fi +} + +build_and_test() { + # interleave building and testing in hope that it saves time + # also vary the local time zone to (hopefully) catch tz-dependent bugs + # also avoid doc-testing multiple times---it takes a lot and rarely helps + cargo clean + channel build -v + TZ=ACST-9:30 channel test -v --lib + channel build -v --features rustc-serialize + TZ=EST4 channel test -v --features rustc-serialize --lib + channel build -v --features serde + TZ=UTC0 channel test -v --features serde --lib + channel build -v --features serde,rustc-serialize + TZ=Asia/Katmandu channel test -v --features serde,rustc-serialize + + # without default "clock" feature + channel build -v --no-default-features + TZ=ACST-9:30 channel test -v --no-default-features --lib + channel build -v --no-default-features --features rustc-serialize + TZ=EST4 channel test -v --no-default-features --features rustc-serialize --lib + channel build -v --no-default-features --features serde + TZ=UTC0 channel test -v --no-default-features --features serde --lib + channel build -v --no-default-features --features serde,rustc-serialize + TZ=Asia/Katmandu channel test -v --no-default-features --features serde,rustc-serialize --lib + + if [[ "$CHANNEL" == stable ]]; then + if [[ -n "$TRAVIS" ]] ; then + check_readme + fi + fi +} + +build_only() { + # Rust 1.13 doesn't support custom derive, so, to avoid doctests which + # validate that, we just build there. + cargo clean + channel build -v + channel build -v --features rustc-serialize + channel build -v --features 'serde bincode' + channel build -v --no-default-features +} + +run_clippy() { + # cached installation will not work on a later nightly + if [ -n "${TRAVIS}" ] && ! cargo install clippy --debug --force; then + echo "COULD NOT COMPILE CLIPPY, IGNORING CLIPPY TESTS" + exit + fi + + cargo clippy --features 'serde bincode rustc-serialize' -- -Dclippy +} + +check_readme() { + make readme + (set -x; git diff --exit-code -- README.md) ; echo $? +} + +rustc --version +cargo --version + +CHANNEL=nightly +if [ "x${CLIPPY}" = xy ] ; then + run_clippy +else + build_and_test +fi + +CHANNEL=beta +build_and_test + +CHANNEL=stable +build_and_test + +CHANNEL=1.13.0 +build_only diff --git a/chrono/src/date.rs b/chrono/src/date.rs new file mode 100644 index 000000000..f8b59cea7 --- /dev/null +++ b/chrono/src/date.rs @@ -0,0 +1,383 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 calendar date with time zone. + +use std::{fmt, hash}; +use std::cmp::Ordering; +use std::ops::{Add, Sub}; +use oldtime::Duration as OldDuration; + +use {Weekday, Datelike}; +use offset::{TimeZone, Utc}; +use naive::{self, NaiveDate, NaiveTime, IsoWeek}; +use DateTime; +use format::{Item, DelayedFormat, StrftimeItems}; + +/// ISO 8601 calendar date with time zone. +/// +/// This type should be considered ambiguous at best, +/// due to the inherent lack of precision required for the time zone resolution. +/// For serialization and deserialization uses, it is best to use `NaiveDate` instead. +/// There are some guarantees on the usage of `Date`: +/// +/// - If properly constructed via `TimeZone::ymd` and others without an error, +/// the corresponding local date should exist for at least a moment. +/// (It may still have a gap from the offset changes.) +/// +/// - The `TimeZone` is free to assign *any* `Offset` to the local date, +/// as long as that offset did occur in given day. +/// For example, if `2015-03-08T01:59-08:00` is followed by `2015-03-08T03:00-07:00`, +/// it may produce either `2015-03-08-08:00` or `2015-03-08-07:00` +/// but *not* `2015-03-08+00:00` and others. +/// +/// - Once constructed as a full `DateTime`, +/// `DateTime::date` and other associated methods should return those for the original `Date`. +/// For example, if `dt = tz.ymd(y,m,d).hms(h,n,s)` were valid, `dt.date() == tz.ymd(y,m,d)`. +/// +/// - The date is timezone-agnostic up to one day (i.e. practically always), +/// so the local date and UTC date should be equal for most cases +/// even though the raw calculation between `NaiveDate` and `Duration` may not. +#[derive(Clone)] +pub struct Date { + date: NaiveDate, + offset: Tz::Offset, +} + +/// The minimum possible `Date`. +pub const MIN_DATE: Date = Date { date: naive::MIN_DATE, offset: Utc }; +/// The maximum possible `Date`. +pub const MAX_DATE: Date = Date { date: naive::MAX_DATE, offset: Utc }; + +impl Date { + /// Makes a new `Date` with given *UTC* date and offset. + /// The local date should be constructed via the `TimeZone` trait. + // + // note: this constructor is purposedly not named to `new` to discourage the direct usage. + #[inline] + pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date { + Date { date: date, offset: offset } + } + + /// Makes a new `DateTime` from the current date and given `NaiveTime`. + /// The offset in the current date is preserved. + /// + /// Panics on invalid datetime. + #[inline] + pub fn and_time(&self, time: NaiveTime) -> Option> { + let localdt = self.naive_local().and_time(time); + self.timezone().from_local_datetime(&localdt).single() + } + + /// Makes a new `DateTime` from the current date, hour, minute and second. + /// The offset in the current date is preserved. + /// + /// Panics on invalid hour, minute and/or second. + #[inline] + pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime { + self.and_hms_opt(hour, min, sec).expect("invalid time") + } + + /// Makes a new `DateTime` from the current date, hour, minute and second. + /// The offset in the current date is preserved. + /// + /// Returns `None` on invalid hour, minute and/or second. + #[inline] + pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option> { + NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time)) + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. + /// The millisecond part can exceed 1,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Panics on invalid hour, minute, second and/or millisecond. + #[inline] + pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime { + self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. + /// The millisecond part can exceed 1,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Returns `None` on invalid hour, minute, second and/or millisecond. + #[inline] + pub fn and_hms_milli_opt(&self, hour: u32, min: u32, sec: u32, + milli: u32) -> Option> { + NaiveTime::from_hms_milli_opt(hour, min, sec, milli).and_then(|time| self.and_time(time)) + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. + /// The microsecond part can exceed 1,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Panics on invalid hour, minute, second and/or microsecond. + #[inline] + pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime { + self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. + /// The microsecond part can exceed 1,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Returns `None` on invalid hour, minute, second and/or microsecond. + #[inline] + pub fn and_hms_micro_opt(&self, hour: u32, min: u32, sec: u32, + micro: u32) -> Option> { + NaiveTime::from_hms_micro_opt(hour, min, sec, micro).and_then(|time| self.and_time(time)) + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. + /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Panics on invalid hour, minute, second and/or nanosecond. + #[inline] + pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime { + self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. + /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Returns `None` on invalid hour, minute, second and/or nanosecond. + #[inline] + pub fn and_hms_nano_opt(&self, hour: u32, min: u32, sec: u32, + nano: u32) -> Option> { + NaiveTime::from_hms_nano_opt(hour, min, sec, nano).and_then(|time| self.and_time(time)) + } + + /// Makes a new `Date` for the next date. + /// + /// Panics when `self` is the last representable date. + #[inline] + pub fn succ(&self) -> Date { + self.succ_opt().expect("out of bound") + } + + /// Makes a new `Date` for the next date. + /// + /// Returns `None` when `self` is the last representable date. + #[inline] + pub fn succ_opt(&self) -> Option> { + self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone())) + } + + /// Makes a new `Date` for the prior date. + /// + /// Panics when `self` is the first representable date. + #[inline] + pub fn pred(&self) -> Date { + self.pred_opt().expect("out of bound") + } + + /// Makes a new `Date` for the prior date. + /// + /// Returns `None` when `self` is the first representable date. + #[inline] + pub fn pred_opt(&self) -> Option> { + self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone())) + } + + /// Retrieves an associated offset from UTC. + #[inline] + pub fn offset(&self) -> &Tz::Offset { + &self.offset + } + + /// Retrieves an associated time zone. + #[inline] + pub fn timezone(&self) -> Tz { + TimeZone::from_offset(&self.offset) + } + + /// Changes the associated time zone. + /// This does not change the actual `Date` (but will change the string representation). + #[inline] + pub fn with_timezone(&self, tz: &Tz2) -> Date { + tz.from_utc_date(&self.date) + } + + /// Adds given `Duration` to the current date. + /// + /// Returns `None` when it will result in overflow. + #[inline] + pub fn checked_add_signed(self, rhs: OldDuration) -> Option> { + let date = try_opt!(self.date.checked_add_signed(rhs)); + Some(Date { date: date, offset: self.offset }) + } + + /// Subtracts given `Duration` from the current date. + /// + /// Returns `None` when it will result in overflow. + #[inline] + pub fn checked_sub_signed(self, rhs: OldDuration) -> Option> { + let date = try_opt!(self.date.checked_sub_signed(rhs)); + Some(Date { date: date, offset: self.offset }) + } + + /// Subtracts another `Date` from the current date. + /// Returns a `Duration` of integral numbers. + /// + /// This does not overflow or underflow at all, + /// as all possible output fits in the range of `Duration`. + #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] + #[inline] + pub fn signed_duration_since(self, rhs: Date) -> OldDuration { + self.date.signed_duration_since(rhs.date) + } + + /// Returns a view to the naive UTC date. + #[inline] + pub fn naive_utc(&self) -> NaiveDate { + self.date + } + + /// Returns a view to the naive local date. + /// + /// This is technically same to [`naive_utc`](#method.naive_utc) + /// because the offset is restricted to never exceed one day, + /// but provided for the consistency. + #[inline] + pub fn naive_local(&self) -> NaiveDate { + self.date + } +} + +/// Maps the local date to other date with given conversion function. +fn map_local(d: &Date, mut f: F) -> Option> + where F: FnMut(NaiveDate) -> Option { + f(d.naive_local()).and_then(|date| d.timezone().from_local_date(&date).single()) +} + +impl Date where Tz::Offset: fmt::Display { + /// Formats the date with the specified formatting items. + #[inline] + pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat + where I: Iterator> + Clone { + DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items) + } + + /// Formats the date with the specified format string. + /// See the [`format::strftime` module](./format/strftime/index.html) + /// on the supported escape sequences. + #[inline] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } +} + +impl Datelike for Date { + #[inline] fn year(&self) -> i32 { self.naive_local().year() } + #[inline] fn month(&self) -> u32 { self.naive_local().month() } + #[inline] fn month0(&self) -> u32 { self.naive_local().month0() } + #[inline] fn day(&self) -> u32 { self.naive_local().day() } + #[inline] fn day0(&self) -> u32 { self.naive_local().day0() } + #[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() } + #[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() } + #[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() } + #[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() } + + #[inline] + fn with_year(&self, year: i32) -> Option> { + map_local(self, |date| date.with_year(year)) + } + + #[inline] + fn with_month(&self, month: u32) -> Option> { + map_local(self, |date| date.with_month(month)) + } + + #[inline] + fn with_month0(&self, month0: u32) -> Option> { + map_local(self, |date| date.with_month0(month0)) + } + + #[inline] + fn with_day(&self, day: u32) -> Option> { + map_local(self, |date| date.with_day(day)) + } + + #[inline] + fn with_day0(&self, day0: u32) -> Option> { + map_local(self, |date| date.with_day0(day0)) + } + + #[inline] + fn with_ordinal(&self, ordinal: u32) -> Option> { + map_local(self, |date| date.with_ordinal(ordinal)) + } + + #[inline] + fn with_ordinal0(&self, ordinal0: u32) -> Option> { + map_local(self, |date| date.with_ordinal0(ordinal0)) + } +} + +// we need them as automatic impls cannot handle associated types +impl Copy for Date where ::Offset: Copy {} +unsafe impl Send for Date where ::Offset: Send {} + +impl PartialEq> for Date { + fn eq(&self, other: &Date) -> bool { self.date == other.date } +} + +impl Eq for Date { +} + +impl PartialOrd for Date { + fn partial_cmp(&self, other: &Date) -> Option { + self.date.partial_cmp(&other.date) + } +} + +impl Ord for Date { + fn cmp(&self, other: &Date) -> Ordering { self.date.cmp(&other.date) } +} + +impl hash::Hash for Date { + fn hash(&self, state: &mut H) { self.date.hash(state) } +} + +impl Add for Date { + type Output = Date; + + #[inline] + fn add(self, rhs: OldDuration) -> Date { + self.checked_add_signed(rhs).expect("`Date + Duration` overflowed") + } +} + +impl Sub for Date { + type Output = Date; + + #[inline] + fn sub(self, rhs: OldDuration) -> Date { + self.checked_sub_signed(rhs).expect("`Date - Duration` overflowed") + } +} + +impl Sub> for Date { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: Date) -> OldDuration { + self.signed_duration_since(rhs) + } +} + +impl fmt::Debug for Date { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}{:?}", self.naive_local(), self.offset) + } +} + +impl fmt::Display for Date where Tz::Offset: fmt::Display { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{}", self.naive_local(), self.offset) + } +} + diff --git a/chrono/src/datetime.rs b/chrono/src/datetime.rs new file mode 100644 index 000000000..2e553062d --- /dev/null +++ b/chrono/src/datetime.rs @@ -0,0 +1,1647 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 date and time with time zone. + +use std::{str, fmt, hash}; +use std::cmp::Ordering; +use std::ops::{Add, Sub}; +use std::time::{SystemTime, UNIX_EPOCH}; +use oldtime::Duration as OldDuration; + +use {Weekday, Timelike, Datelike}; +#[cfg(feature="clock")] +use offset::Local; +use offset::{TimeZone, Offset, Utc, FixedOffset}; +use naive::{NaiveTime, NaiveDateTime, IsoWeek}; +use Date; +use format::{Item, Numeric, Pad, Fixed}; +use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; + +/// Specific formatting options for seconds. This may be extended in the +/// future, so exhaustive matching in external code is not recommended. +/// +/// See the `TimeZone::to_rfc3339_opts` function for usage. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SecondsFormat { + /// Format whole seconds only, with no decimal point nor subseconds. + Secs, + + /// Use fixed 3 subsecond digits. This corresponds to + /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3). + Millis, + + /// Use fixed 6 subsecond digits. This corresponds to + /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6). + Micros, + + /// Use fixed 9 subsecond digits. This corresponds to + /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9). + Nanos, + + /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to + /// display all available non-zero sub-second digits. This corresponds to + /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond). + AutoSi, + + // Do not match against this. + #[doc(hidden)] + __NonExhaustive, +} + +/// ISO 8601 combined date and time with time zone. +/// +/// There are some constructors implemented here (the `from_*` methods), but +/// the general-purpose constructors are all via the methods on the +/// [`TimeZone`](./offset/trait.TimeZone.html) implementations. +#[derive(Clone)] +pub struct DateTime { + datetime: NaiveDateTime, + offset: Tz::Offset, +} + +impl DateTime { + /// Makes a new `DateTime` with given *UTC* datetime and offset. + /// The local datetime should be constructed via the `TimeZone` trait. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; + /// + /// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); + /// assert_eq!(Utc.timestamp(61, 0), dt); + /// ~~~~ + // + // note: this constructor is purposedly not named to `new` to discourage the direct usage. + #[inline] + pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime { + DateTime { datetime: datetime, offset: offset } + } + + /// Retrieves a date component. + #[inline] + pub fn date(&self) -> Date { + Date::from_utc(self.naive_local().date(), self.offset.clone()) + } + + /// Retrieves a time component. + /// Unlike `date`, this is not associated to the time zone. + #[inline] + pub fn time(&self) -> NaiveTime { + self.datetime.time() + self.offset.fix() + } + + /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC + /// (aka "UNIX timestamp"). + #[inline] + pub fn timestamp(&self) -> i64 { + self.datetime.timestamp() + } + + /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC + /// + /// Note that this does reduce the number of years that can be represented + /// from ~584 Billion to ~584 Million. (If this is a problem, please file + /// an issue to let me know what domain needs millisecond precision over + /// billions of years, I'm curious.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::Utc; + /// use chrono::TimeZone; + /// + /// let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444); + /// assert_eq!(dt.timestamp_millis(), 1_444); + /// + /// let dt = Utc.ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555); + /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); + /// ~~~~ + #[inline] + pub fn timestamp_millis(&self) -> i64 { + self.datetime.timestamp_millis() + } + + /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC + /// + /// Note that this does reduce the number of years that can be represented + /// from ~584 Billion to ~584. (If this is a problem, please file + /// an issue to let me know what domain needs nanosecond precision over + /// millenia, I'm curious.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::Utc; + /// use chrono::TimeZone; + /// + /// let dt = Utc.ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444); + /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); + /// + /// let dt = Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555); + /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); + /// ~~~~ + #[inline] + pub fn timestamp_nanos(&self) -> i64 { + self.datetime.timestamp_nanos() + } + + /// Returns the number of milliseconds since the last second boundary + /// + /// warning: in event of a leap second, this may exceed 999 + /// + /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC + #[inline] + pub fn timestamp_subsec_millis(&self) -> u32 { + self.datetime.timestamp_subsec_millis() + } + + /// Returns the number of microseconds since the last second boundary + /// + /// warning: in event of a leap second, this may exceed 999_999 + /// + /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC + #[inline] + pub fn timestamp_subsec_micros(&self) -> u32 { + self.datetime.timestamp_subsec_micros() + } + + /// Returns the number of nanoseconds since the last second boundary + /// + /// warning: in event of a leap second, this may exceed 999_999_999 + /// + /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC + #[inline] + pub fn timestamp_subsec_nanos(&self) -> u32 { + self.datetime.timestamp_subsec_nanos() + } + + /// Retrieves an associated offset from UTC. + #[inline] + pub fn offset(&self) -> &Tz::Offset { + &self.offset + } + + /// Retrieves an associated time zone. + #[inline] + pub fn timezone(&self) -> Tz { + TimeZone::from_offset(&self.offset) + } + + /// Changes the associated time zone. + /// This does not change the actual `DateTime` (but will change the string representation). + #[inline] + pub fn with_timezone(&self, tz: &Tz2) -> DateTime { + tz.from_utc_datetime(&self.datetime) + } + + /// Adds given `Duration` to the current date and time. + /// + /// Returns `None` when it will result in overflow. + #[inline] + pub fn checked_add_signed(self, rhs: OldDuration) -> Option> { + let datetime = try_opt!(self.datetime.checked_add_signed(rhs)); + Some(DateTime { datetime: datetime, offset: self.offset }) + } + + /// Subtracts given `Duration` from the current date and time. + /// + /// Returns `None` when it will result in overflow. + #[inline] + pub fn checked_sub_signed(self, rhs: OldDuration) -> Option> { + let datetime = try_opt!(self.datetime.checked_sub_signed(rhs)); + Some(DateTime { datetime: datetime, offset: self.offset }) + } + + /// Subtracts another `DateTime` from the current date and time. + /// This does not overflow or underflow at all. + #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] + #[inline] + pub fn signed_duration_since(self, rhs: DateTime) -> OldDuration { + self.datetime.signed_duration_since(rhs.datetime) + } + + /// Returns a view to the naive UTC datetime. + #[inline] + pub fn naive_utc(&self) -> NaiveDateTime { + self.datetime + } + + /// Returns a view to the naive local datetime. + #[inline] + pub fn naive_local(&self) -> NaiveDateTime { + self.datetime + self.offset.fix() + } +} + +/// Maps the local datetime to other datetime with given conversion function. +fn map_local(dt: &DateTime, mut f: F) -> Option> + where F: FnMut(NaiveDateTime) -> Option { + f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single()) +} + +impl DateTime { + /// Parses an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`, + /// then returns a new `DateTime` with a parsed `FixedOffset`. + pub fn parse_from_rfc2822(s: &str) -> ParseResult> { + const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_datetime() + } + + /// Parses an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`, + /// then returns a new `DateTime` with a parsed `FixedOffset`. + /// + /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows some freedom + /// over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format. + pub fn parse_from_rfc3339(s: &str) -> ParseResult> { + const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_datetime() + } + + /// Parses a string with the specified format string and + /// returns a new `DateTime` with a parsed `FixedOffset`. + /// See the [`format::strftime` module](./format/strftime/index.html) + /// on the supported escape sequences. + /// + /// See also `Offset::datetime_from_str` which gives a local `DateTime` on specific time zone. + /// + /// Note that this method *requires a timezone* in the string. See + /// [`NaiveDateTime::parse_from_str`](./naive/struct.NaiveDateTime.html#method.parse_from_str) + /// for a version that does not require a timezone in the to-be-parsed str. + /// + /// # Example + /// + /// ```rust + /// use chrono::{DateTime, FixedOffset, TimeZone}; + /// + /// let dt = DateTime::parse_from_str( + /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z"); + /// assert_eq!(dt, Ok(FixedOffset::east(0).ymd(1983, 4, 13).and_hms_milli(12, 9, 14, 274))); + /// ``` + pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult> { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); + parsed.to_datetime() + } +} + +impl DateTime where Tz::Offset: fmt::Display { + /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`. + pub fn to_rfc2822(&self) -> String { + const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; + self.format_with_items(ITEMS.iter().cloned()).to_string() + } + + /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. + pub fn to_rfc3339(&self) -> String { + const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; + self.format_with_items(ITEMS.iter().cloned()).to_string() + } + + /// Return an RFC 3339 and ISO 8601 date and time string with subseconds + /// formatted as per a `SecondsFormat`. If passed `use_z` true and the + /// timezone is UTC (offset 0), use 'Z', as per + /// [Fixed::TimezoneOffsetColonZ](format/enum.Fixed.html#variant.TimezoneOffsetColonZ). + /// If passed `use_z` false, use + /// [Fixed::TimezoneOffsetColon](format/enum.Fixed.html#variant.TimezoneOffsetColon). + /// + /// # Examples + /// + /// ```rust + /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc}; + /// let dt = Utc.ymd(2018, 1, 26).and_hms_micro(18, 30, 9, 453_829); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false), + /// "2018-01-26T18:30:09.453+00:00"); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true), + /// "2018-01-26T18:30:09.453Z"); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), + /// "2018-01-26T18:30:09Z"); + /// + /// let pst = FixedOffset::east(8 * 60 * 60); + /// let dt = pst.ymd(2018, 1, 26).and_hms_micro(10, 30, 9, 453_829); + /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true), + /// "2018-01-26T10:30:09+08:00"); + /// ``` + pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String { + use format::Numeric::*; + use format::Pad::Zero; + use SecondsFormat::*; + + debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!"); + + const PREFIX: &'static [Item<'static>] = &[ + Item::Numeric(Year, Zero), + Item::Literal("-"), + Item::Numeric(Month, Zero), + Item::Literal("-"), + Item::Numeric(Day, Zero), + Item::Literal("T"), + Item::Numeric(Hour, Zero), + Item::Literal(":"), + Item::Numeric(Minute, Zero), + Item::Literal(":"), + Item::Numeric(Second, Zero), + ]; + + let ssitem = match secform { + Secs => None, + Millis => Some(Item::Fixed(Fixed::Nanosecond3)), + Micros => Some(Item::Fixed(Fixed::Nanosecond6)), + Nanos => Some(Item::Fixed(Fixed::Nanosecond9)), + AutoSi => Some(Item::Fixed(Fixed::Nanosecond)), + __NonExhaustive => unreachable!(), + }; + + let tzitem = Item::Fixed( + if use_z { + Fixed::TimezoneOffsetColonZ + } else { + Fixed::TimezoneOffsetColon + } + ); + + match ssitem { + None => + self.format_with_items( + PREFIX.iter().chain([tzitem].iter()).cloned() + ).to_string(), + Some(s) => + self.format_with_items( + PREFIX.iter().chain([s, tzitem].iter()).cloned() + ).to_string(), + } + } + + /// Formats the combined date and time with the specified formatting items. + #[inline] + pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat + where I: Iterator> + Clone { + let local = self.naive_local(); + DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items) + } + + /// Formats the combined date and time with the specified format string. + /// See the [`format::strftime` module](./format/strftime/index.html) + /// on the supported escape sequences. + #[inline] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } +} + +impl Datelike for DateTime { + #[inline] fn year(&self) -> i32 { self.naive_local().year() } + #[inline] fn month(&self) -> u32 { self.naive_local().month() } + #[inline] fn month0(&self) -> u32 { self.naive_local().month0() } + #[inline] fn day(&self) -> u32 { self.naive_local().day() } + #[inline] fn day0(&self) -> u32 { self.naive_local().day0() } + #[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() } + #[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() } + #[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() } + #[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() } + + #[inline] + fn with_year(&self, year: i32) -> Option> { + map_local(self, |datetime| datetime.with_year(year)) + } + + #[inline] + fn with_month(&self, month: u32) -> Option> { + map_local(self, |datetime| datetime.with_month(month)) + } + + #[inline] + fn with_month0(&self, month0: u32) -> Option> { + map_local(self, |datetime| datetime.with_month0(month0)) + } + + #[inline] + fn with_day(&self, day: u32) -> Option> { + map_local(self, |datetime| datetime.with_day(day)) + } + + #[inline] + fn with_day0(&self, day0: u32) -> Option> { + map_local(self, |datetime| datetime.with_day0(day0)) + } + + #[inline] + fn with_ordinal(&self, ordinal: u32) -> Option> { + map_local(self, |datetime| datetime.with_ordinal(ordinal)) + } + + #[inline] + fn with_ordinal0(&self, ordinal0: u32) -> Option> { + map_local(self, |datetime| datetime.with_ordinal0(ordinal0)) + } +} + +impl Timelike for DateTime { + #[inline] fn hour(&self) -> u32 { self.naive_local().hour() } + #[inline] fn minute(&self) -> u32 { self.naive_local().minute() } + #[inline] fn second(&self) -> u32 { self.naive_local().second() } + #[inline] fn nanosecond(&self) -> u32 { self.naive_local().nanosecond() } + + #[inline] + fn with_hour(&self, hour: u32) -> Option> { + map_local(self, |datetime| datetime.with_hour(hour)) + } + + #[inline] + fn with_minute(&self, min: u32) -> Option> { + map_local(self, |datetime| datetime.with_minute(min)) + } + + #[inline] + fn with_second(&self, sec: u32) -> Option> { + map_local(self, |datetime| datetime.with_second(sec)) + } + + #[inline] + fn with_nanosecond(&self, nano: u32) -> Option> { + map_local(self, |datetime| datetime.with_nanosecond(nano)) + } +} + +// we need them as automatic impls cannot handle associated types +impl Copy for DateTime where ::Offset: Copy {} +unsafe impl Send for DateTime where ::Offset: Send {} + +impl PartialEq> for DateTime { + fn eq(&self, other: &DateTime) -> bool { self.datetime == other.datetime } +} + +impl Eq for DateTime { +} + +impl PartialOrd for DateTime { + fn partial_cmp(&self, other: &DateTime) -> Option { + self.datetime.partial_cmp(&other.datetime) + } +} + +impl Ord for DateTime { + fn cmp(&self, other: &DateTime) -> Ordering { self.datetime.cmp(&other.datetime) } +} + +impl hash::Hash for DateTime { + fn hash(&self, state: &mut H) { self.datetime.hash(state) } +} + +impl Add for DateTime { + type Output = DateTime; + + #[inline] + fn add(self, rhs: OldDuration) -> DateTime { + self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed") + } +} + +impl Sub for DateTime { + type Output = DateTime; + + #[inline] + fn sub(self, rhs: OldDuration) -> DateTime { + self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed") + } +} + +impl Sub> for DateTime { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: DateTime) -> OldDuration { + self.signed_duration_since(rhs) + } +} + +impl fmt::Debug for DateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}{:?}", self.naive_local(), self.offset) + } +} + +impl fmt::Display for DateTime where Tz::Offset: fmt::Display { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.naive_local(), self.offset) + } +} + +impl str::FromStr for DateTime { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult> { + const ITEMS: &'static [Item<'static>] = &[ + Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive? + Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Fixed(Fixed::Nanosecond), + Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ), + Item::Space(""), + ]; + + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_datetime() + } +} + +impl str::FromStr for DateTime { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult> { + s.parse::>().map(|dt| dt.with_timezone(&Utc)) + } +} + +#[cfg(feature="clock")] +impl str::FromStr for DateTime { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult> { + s.parse::>().map(|dt| dt.with_timezone(&Local)) + } +} + +impl From for DateTime { + fn from(t: SystemTime) -> DateTime { + let (sec, nsec) = match t.duration_since(UNIX_EPOCH) { + Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()), + Err(e) => { // unlikely but should be handled + let dur = e.duration(); + let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos()); + if nsec == 0 { + (-sec, 0) + } else { + (-sec - 1, 1_000_000_000 - nsec) + } + }, + }; + Utc.timestamp(sec, nsec) + } +} + +#[cfg(feature="clock")] +impl From for DateTime { + fn from(t: SystemTime) -> DateTime { + DateTime::::from(t).with_timezone(&Local) + } +} + +impl From> for SystemTime { + fn from(dt: DateTime) -> SystemTime { + use std::time::Duration; + + let sec = dt.timestamp(); + let nsec = dt.timestamp_subsec_nanos(); + if sec < 0 { + // unlikely but should be handled + UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec) + } else { + UNIX_EPOCH + Duration::new(sec as u64, nsec) + } + } +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_encodable_json(to_string_utc: FUtc, to_string_fixed: FFixed) + where FUtc: Fn(&DateTime) -> Result, + FFixed: Fn(&DateTime) -> Result, + E: ::std::fmt::Debug +{ + assert_eq!(to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + Some(r#""2014-07-24T12:34:06Z""#.into())); + + assert_eq!(to_string_fixed(&FixedOffset::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + Some(r#""2014-07-24T12:34:06+01:01""#.into())); + assert_eq!(to_string_fixed(&FixedOffset::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + Some(r#""2014-07-24T12:34:06+01:00:50""#.into())); +} + +#[cfg(all(test, feature="clock", any(feature = "rustc-serialize", feature = "serde")))] +fn test_decodable_json(utc_from_str: FUtc, + fixed_from_str: FFixed, + local_from_str: FLocal) + where FUtc: Fn(&str) -> Result, E>, + FFixed: Fn(&str) -> Result, E>, + FLocal: Fn(&str) -> Result, E>, + E: ::std::fmt::Debug +{ + // should check against the offset as well (the normal DateTime comparison will ignore them) + fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { + dt.as_ref().map(|dt| (dt, dt.offset())) + } + + assert_eq!(norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()), + norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)))); + assert_eq!(norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), + norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)))); + + assert_eq!(norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()), + norm(&Some(FixedOffset::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6)))); + assert_eq!(norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()), + norm(&Some(FixedOffset::east(60*60 + 23*60).ymd(2014, 7, 24).and_hms(13, 57, 6)))); + + // we don't know the exact local offset but we can check that + // the conversion didn't change the instant itself + assert_eq!(local_from_str(r#""2014-07-24T12:34:06Z""#) + .expect("local shouuld parse"), + Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)); + assert_eq!(local_from_str(r#""2014-07-24T13:57:06+01:23""#) + .expect("local should parse with offset"), + Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)); + + assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); + assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); +} + +#[cfg(all(test, feature="clock", feature = "rustc-serialize"))] +fn test_decodable_json_timestamps(utc_from_str: FUtc, + fixed_from_str: FFixed, + local_from_str: FLocal) + where FUtc: Fn(&str) -> Result, E>, + FFixed: Fn(&str) -> Result, E>, + FLocal: Fn(&str) -> Result, E>, + E: ::std::fmt::Debug +{ + fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { + dt.as_ref().map(|dt| (dt, dt.offset())) + } + + assert_eq!(norm(&utc_from_str("0").ok().map(DateTime::from)), + norm(&Some(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)))); + assert_eq!(norm(&utc_from_str("-1").ok().map(DateTime::from)), + norm(&Some(Utc.ymd(1969, 12, 31).and_hms(23, 59, 59)))); + + assert_eq!(norm(&fixed_from_str("0").ok().map(DateTime::from)), + norm(&Some(FixedOffset::east(0).ymd(1970, 1, 1).and_hms(0, 0, 0)))); + assert_eq!(norm(&fixed_from_str("-1").ok().map(DateTime::from)), + norm(&Some(FixedOffset::east(0).ymd(1969, 12, 31).and_hms(23, 59, 59)))); + + assert_eq!(*fixed_from_str("0").expect("0 timestamp should parse"), + Utc.ymd(1970, 1, 1).and_hms(0, 0, 0)); + assert_eq!(*local_from_str("-1").expect("-1 timestamp should parse"), + Utc.ymd(1969, 12, 31).and_hms(23, 59, 59)); +} + +#[cfg(feature = "rustc-serialize")] +pub mod rustc_serialize { + use std::fmt; + use std::ops::Deref; + use super::DateTime; + #[cfg(feature="clock")] + use offset::Local; + use offset::{TimeZone, LocalResult, Utc, FixedOffset}; + use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + + impl Encodable for DateTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } + } + + // try!-like function to convert a LocalResult into a serde-ish Result + fn from(me: LocalResult, d: &mut D) -> Result + where D: Decoder, + T: fmt::Display, + { + match me { + LocalResult::None => Err(d.error( + "value is not a legal timestamp")), + LocalResult::Ambiguous(..) => Err(d.error( + "value is an ambiguous timestamp")), + LocalResult::Single(val) => Ok(val) + } + } + + impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_str()?.parse::>() + .map_err(|_| d.error("invalid date and time")) + } + } + + #[allow(deprecated)] + impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result, D::Error> { + from(FixedOffset::east(0).timestamp_opt(d.read_i64()?, 0), d) + .map(TsSeconds) + } + } + + impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_str()? + .parse::>() + .map(|dt| dt.with_timezone(&Utc)) + .map_err(|_| d.error("invalid date and time")) + } + } + + /// A `DateTime` that can be deserialized from a timestamp + /// + /// A timestamp here is seconds since the epoch + #[derive(Debug)] + pub struct TsSeconds(DateTime); + + #[allow(deprecated)] + impl From> for DateTime { + /// Pull the inner DateTime out + #[allow(deprecated)] + fn from(obj: TsSeconds) -> DateTime { + obj.0 + } + } + + #[allow(deprecated)] + impl Deref for TsSeconds { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + #[allow(deprecated)] + impl Decodable for TsSeconds { + fn decode(d: &mut D) -> Result, D::Error> { + from(Utc.timestamp_opt(d.read_i64()?, 0), d) + .map(TsSeconds) + } + } + + #[cfg(feature="clock")] + impl Decodable for DateTime { + fn decode(d: &mut D) -> Result, D::Error> { + match d.read_str()?.parse::>() { + Ok(dt) => Ok(dt.with_timezone(&Local)), + Err(_) => Err(d.error("invalid date and time")), + } + } + } + + #[cfg(feature="clock")] + #[allow(deprecated)] + impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result, D::Error> { + from(Utc.timestamp_opt(d.read_i64()?, 0), d) + .map(|dt| TsSeconds(dt.with_timezone(&Local))) + } + } + + #[cfg(test)] use rustc_serialize::json; + + #[test] + fn test_encodable() { + super::test_encodable_json(json::encode, json::encode); + } + + #[cfg(feature="clock")] + #[test] + fn test_decodable() { + super::test_decodable_json(json::decode, json::decode, json::decode); + } + + #[cfg(feature="clock")] + #[test] + fn test_decodable_timestamps() { + super::test_decodable_json_timestamps(json::decode, json::decode, json::decode); + } + +} + +/// documented at re-export site +#[cfg(feature = "serde")] +pub mod serde { + use std::fmt; + use super::DateTime; + #[cfg(feature="clock")] + use offset::Local; + use offset::{LocalResult, TimeZone, Utc, FixedOffset}; + use serdelib::{ser, de}; + + // try!-like function to convert a LocalResult into a serde-ish Result + fn serde_from(me: LocalResult, ts: &V) -> Result + where E: de::Error, + V: fmt::Display, + T: fmt::Display, + { + match me { + LocalResult::None => Err(E::custom( + format!("value is not a legal timestamp: {}", ts))), + LocalResult::Ambiguous(min, max) => Err(E::custom( + format!("value is an ambiguous timestamp: {}, could be either of {}, {}", + ts, min, max))), + LocalResult::Single(val) => Ok(val) + } + } + + /// Ser/de to/from timestamps in nanoseconds + /// + /// Intended for use with `serde`'s `with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_nanoseconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_nanoseconds")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let time = Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_nanoseconds { + use std::fmt; + use serdelib::{ser, de}; + + use {DateTime, Utc}; + use offset::TimeZone; + + use super::serde_from; + + /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_nano_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &DateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp_nanos()) + } + + /// Deserialize a `DateTime` from a nanosecond timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{DateTime, Utc}; + /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_nano_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(NanoSecondsTimestampVisitor))) + } + + struct NanoSecondsTimestampVisitor; + + impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + write!(formatter, "a unix timestamp in seconds") + } + + /// Deserialize a timestamp in nanoseconds since the epoch + fn visit_i64(self, value: i64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt(value / 1_000_000_000, + (value % 1_000_000_000) as u32), + &value) + } + + /// Deserialize a timestamp in nanoseconds since the epoch + fn visit_u64(self, value: u64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt((value / 1_000_000_000) as i64, + (value % 1_000_000_000) as u32), + &value) + } + } + } + + /// Ser/de to/from timestamps in milliseconds + /// + /// Intended for use with `serde`s `with` attribute. + /// + /// # Example + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_milliseconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_milliseconds")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let time = Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_milliseconds { + use std::fmt; + use serdelib::{ser, de}; + + use {DateTime, Utc}; + use offset::TimeZone; + + use super::serde_from; + + /// Serialize a UTC datetime into an integer number of milliseconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_milli_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &DateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp_millis()) + } + + /// Deserialize a `DateTime` from a millisecond timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{DateTime, Utc}; + /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_milli_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc)))) + } + + struct MilliSecondsTimestampVisitor; + + impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + formatter.write_str("a unix timestamp in milliseconds") + } + + /// Deserialize a timestamp in milliseconds since the epoch + fn visit_i64(self, value: i64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt(value / 1000, + ((value % 1000) * 1_000_000) as u32), + &value) + } + + /// Deserialize a timestamp in milliseconds since the epoch + fn visit_u64(self, value: u64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt((value / 1000) as i64, + ((value % 1000) * 1_000_000) as u32), + &value) + } + } + } + + /// Ser/de to/from timestamps in seconds + /// + /// Intended for use with `serde`'s `with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_seconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_seconds")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let time = Utc.ymd(2015, 5, 15).and_hms(10, 0, 0); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1431684000}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_seconds { + use std::fmt; + use serdelib::{ser, de}; + + use {DateTime, Utc}; + use offset::TimeZone; + + use super::serde_from; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{TimeZone, DateTime, Utc}; + /// use chrono::serde::ts_seconds::serialize as to_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: Utc.ymd(2015, 5, 15).and_hms(10, 0, 0), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1431684000}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &DateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp()) + } + + /// Deserialize a `DateTime` from a seconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate chrono; + /// # use chrono::{DateTime, Utc}; + /// use chrono::serde::ts_seconds::deserialize as from_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_ts")] + /// time: DateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(SecondsTimestampVisitor))) + } + + struct SecondsTimestampVisitor; + + impl<'de> de::Visitor<'de> for SecondsTimestampVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + formatter.write_str("a unix timestamp in seconds") + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_i64(self, value: i64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt(value, 0), &value) + } + + /// Deserialize a timestamp in seconds since the epoch + fn visit_u64(self, value: u64) -> Result, E> + where E: de::Error + { + serde_from(Utc.timestamp_opt(value as i64, 0), &value) + } + } + } + + impl ser::Serialize for DateTime { + /// Serialize into a rfc3339 time string + /// + /// See [the `serde` module](./serde/index.html) for alternate + /// serializations. + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer + { + struct FormatWrapped<'a, D: 'a> { + inner: &'a D + } + + impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + // Debug formatting is correct RFC3339, and it allows Zulu. + serializer.collect_str(&FormatWrapped { inner: &self }) + } + } + + struct DateTimeVisitor; + + impl<'de> de::Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + write!(formatter, "a formatted date and time string or a unix timestamp") + } + + fn visit_str(self, value: &str) -> Result, E> + where E: de::Error + { + value.parse().map_err(|err| E::custom(format!("{}", err))) + } + } + + /// Deserialize a value that optionally includes a timezone offset in its + /// string representation + /// + /// The value to be deserialized must be an rfc3339 string. + /// + /// See [the `serde` module](./serde/index.html) for alternate + /// deserialization formats. + impl<'de> de::Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(DateTimeVisitor) + } + } + + /// Deserialize into a UTC value + /// + /// The value to be deserialized must be an rfc3339 string. + /// + /// See [the `serde` module](./serde/index.html) for alternate + /// deserialization formats. + impl<'de> de::Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc)) + } + } + + /// Deserialize a value that includes no timezone in its string + /// representation + /// + /// The value to be deserialized must be an rfc3339 string. + /// + /// See [the `serde` module](./serde/index.html) for alternate + /// serialization formats. + #[cfg(feature="clock")] + impl<'de> de::Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local)) + } + } + + #[cfg(test)] extern crate serde_json; + #[cfg(test)] extern crate bincode; + + #[test] + fn test_serde_serialize() { + super::test_encodable_json(self::serde_json::to_string, self::serde_json::to_string); + } + + #[cfg(feature="clock")] + #[test] + fn test_serde_deserialize() { + super::test_decodable_json(|input| self::serde_json::from_str(&input), |input| self::serde_json::from_str(&input), + |input| self::serde_json::from_str(&input)); + } + + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use self::bincode::{Infinite, serialize, deserialize}; + + let dt = Utc.ymd(2014, 7, 24).and_hms(12, 34, 6); + let encoded = serialize(&dt, Infinite).unwrap(); + let decoded: DateTime = deserialize(&encoded).unwrap(); + assert_eq!(dt, decoded); + assert_eq!(dt.offset(), decoded.offset()); + } +} + +#[cfg(test)] +mod tests { + use super::DateTime; + #[cfg(feature="clock")] + use Datelike; + use naive::{NaiveTime, NaiveDate}; + #[cfg(feature="clock")] + use offset::Local; + use offset::{TimeZone, Utc, FixedOffset}; + use oldtime::Duration; + use std::time::{SystemTime, UNIX_EPOCH}; + + #[test] + #[allow(non_snake_case)] + fn test_datetime_offset() { + let Est = FixedOffset::west(5*60*60); + let Edt = FixedOffset::west(4*60*60); + let Kst = FixedOffset::east(9*60*60); + + assert_eq!(format!("{}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 UTC"); + assert_eq!(format!("{}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 -04:00"); + assert_eq!(format!("{}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06 07:08:09 +09:00"); + assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09Z"); + assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09-04:00"); + assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)), + "2014-05-06T07:08:09+09:00"); + + // edge cases + assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00Z"); + assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00-04:00"); + assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(0, 0, 0)), + "2014-05-06T00:00:00+09:00"); + assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59Z"); + assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59-04:00"); + assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(23, 59, 59)), + "2014-05-06T23:59:59+09:00"); + + let dt = Utc.ymd(2014, 5, 6).and_hms(7, 8, 9); + assert_eq!(dt, Edt.ymd(2014, 5, 6).and_hms(3, 8, 9)); + assert_eq!(dt + Duration::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10)); + assert_eq!(dt.signed_duration_since(Edt.ymd(2014, 5, 6).and_hms(10, 11, 12)), + Duration::seconds(-7*3600 - 3*60 - 3)); + + assert_eq!(*Utc.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc); + assert_eq!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Edt); + assert!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != Est); + } + + #[test] + fn test_datetime_date_and_time() { + let tz = FixedOffset::east(5*60*60); + let d = tz.ymd(2014, 5, 6).and_hms(7, 8, 9); + assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9)); + assert_eq!(d.date(), tz.ymd(2014, 5, 6)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2014, 5, 6)); + assert_eq!(d.date().and_time(d.time()), Some(d)); + + let tz = FixedOffset::east(4*60*60); + let d = tz.ymd(2016, 5, 4).and_hms(3, 2, 1); + assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1)); + assert_eq!(d.date(), tz.ymd(2016, 5, 4)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2016, 5, 4)); + assert_eq!(d.date().and_time(d.time()), Some(d)); + + let tz = FixedOffset::west(13*60*60); + let d = tz.ymd(2017, 8, 9).and_hms(12, 34, 56); + assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56)); + assert_eq!(d.date(), tz.ymd(2017, 8, 9)); + assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2017, 8, 9)); + assert_eq!(d.date().and_time(d.time()), Some(d)); + } + + #[test] + #[cfg(feature="clock")] + fn test_datetime_with_timezone() { + let local_now = Local::now(); + let utc_now = local_now.with_timezone(&Utc); + let local_now2 = utc_now.with_timezone(&Local); + assert_eq!(local_now, local_now2); + } + + #[test] + #[allow(non_snake_case)] + fn test_datetime_rfc2822_and_rfc3339() { + let EDT = FixedOffset::east(5*60*60); + assert_eq!(Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(), + "Wed, 18 Feb 2015 23:16:09 +0000"); + assert_eq!(Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(), + "2015-02-18T23:16:09+00:00"); + assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(), + "Wed, 18 Feb 2015 23:16:09 +0500"); + assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(), + "2015-02-18T23:16:09.150+05:00"); + assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(), + "Wed, 18 Feb 2015 23:59:60 +0500"); + assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(), + "2015-02-18T23:59:60.234567+05:00"); + + assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"), + Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9))); + assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"), + Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9))); + assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"), + Ok(EDT.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000))); + assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"), + Ok(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567))); + } + + #[test] + fn test_rfc3339_opts() { + use SecondsFormat::*; + let pst = FixedOffset::east(8 * 60 * 60); + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000); + assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00"); + assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00"); + assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00"); + assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00"); + assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00"); + assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00"); + + let ut = DateTime::::from_utc(dt.naive_utc(), Utc); + assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00"); + assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z"); + assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00"); + assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z"); + assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z"); + assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z"); + assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z"); + } + + #[test] + #[should_panic] + fn test_rfc3339_opts_nonexhaustive() { + use SecondsFormat; + let dt = Utc.ymd(1999, 10, 9).and_hms(1, 2, 3); + dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true); + } + + #[test] + fn test_datetime_from_str() { + assert_eq!("2015-2-18T23:16:9.15Z".parse::>(), + Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))); + assert_eq!("2015-2-18T13:16:9.15-10:00".parse::>(), + Ok(FixedOffset::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150))); + assert!("2015-2-18T23:16:9.15".parse::>().is_err()); + + assert_eq!("2015-2-18T23:16:9.15Z".parse::>(), + Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))); + assert_eq!("2015-2-18T13:16:9.15-10:00".parse::>(), + Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150))); + assert!("2015-2-18T23:16:9.15".parse::>().is_err()); + + // no test for `DateTime`, we cannot verify that much. + } + + #[test] + fn test_datetime_parse_from_str() { + let ymdhms = |y,m,d,h,n,s,off| FixedOffset::east(off).ymd(y,m,d).and_hms(h,n,s); + assert_eq!(DateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570*60))); // ignore offset + assert!(DateTime::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset + assert!(DateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT", + "%a, %d %b %Y %H:%M:%S GMT").is_err()); + assert_eq!(Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT", + "%a, %d %b %Y %H:%M:%S GMT"), + Ok(Utc.ymd(2013, 8, 9).and_hms(23, 54, 35))); + } + + #[test] + #[cfg(feature="clock")] + fn test_datetime_format_with_local() { + // if we are not around the year boundary, local and UTC date should have the same year + let dt = Local::now().with_month(5).unwrap(); + assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string()); + } + + #[test] + #[cfg(feature="clock")] + fn test_datetime_is_copy() { + // UTC is known to be `Copy`. + let a = Utc::now(); + let b = a; + assert_eq!(a, b); + } + + #[test] + #[cfg(feature="clock")] + fn test_datetime_is_send() { + use std::thread; + + // UTC is known to be `Send`. + let a = Utc::now(); + thread::spawn(move || { + let _ = a; + }).join().unwrap(); + } + + #[test] + fn test_subsecond_part() { + let datetime = Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 1234567); + + assert_eq!(1, datetime.timestamp_subsec_millis()); + assert_eq!(1234, datetime.timestamp_subsec_micros()); + assert_eq!(1234567, datetime.timestamp_subsec_nanos()); + } + + #[test] + fn test_from_system_time() { + use std::time::Duration; + + let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0); + + // SystemTime -> DateTime + assert_eq!(DateTime::::from(UNIX_EPOCH), epoch); + assert_eq!(DateTime::::from(UNIX_EPOCH + Duration::new(999_999_999, 999_999_999)), + Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999)); + assert_eq!(DateTime::::from(UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)), + Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)); + + // DateTime -> SystemTime + assert_eq!(SystemTime::from(epoch), UNIX_EPOCH); + assert_eq!(SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999)), + UNIX_EPOCH + Duration::new(999_999_999, 999_999_999)); + assert_eq!(SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)), + UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)); + + // DateTime -> SystemTime (via `with_timezone`) + #[cfg(feature="clock")] { + assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH); + } + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH); + assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH); + } +} diff --git a/chrono/src/div.rs b/chrono/src/div.rs new file mode 100644 index 000000000..c5f0ef667 --- /dev/null +++ b/chrono/src/div.rs @@ -0,0 +1,42 @@ +// This is a part of Chrono. +// Portions Copyright 2013-2014 The Rust Project Developers. +// See README.md and LICENSE.txt for details. + +//! Integer division utilities. (Shamelessly copied from [num](https://github.com/rust-lang/num/)) + +// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, +// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + +pub use num_integer::{div_rem, div_floor, mod_floor, div_mod_floor}; + +#[cfg(test)] +mod tests { + use super::{mod_floor, div_mod_floor}; + + #[test] + fn test_mod_floor() { + assert_eq!(mod_floor( 8, 3), 2); + assert_eq!(mod_floor( 8, -3), -1); + assert_eq!(mod_floor(-8, 3), 1); + assert_eq!(mod_floor(-8, -3), -2); + + assert_eq!(mod_floor( 1, 2), 1); + assert_eq!(mod_floor( 1, -2), -1); + assert_eq!(mod_floor(-1, 2), 1); + assert_eq!(mod_floor(-1, -2), -1); + } + + #[test] + fn test_div_mod_floor() { + assert_eq!(div_mod_floor( 8, 3), ( 2, 2)); + assert_eq!(div_mod_floor( 8, -3), (-3, -1)); + assert_eq!(div_mod_floor(-8, 3), (-3, 1)); + assert_eq!(div_mod_floor(-8, -3), ( 2, -2)); + + assert_eq!(div_mod_floor( 1, 2), ( 0, 1)); + assert_eq!(div_mod_floor( 1, -2), (-1, -1)); + assert_eq!(div_mod_floor(-1, 2), (-1, 1)); + assert_eq!(div_mod_floor(-1, -2), ( 0, -1)); + } +} + diff --git a/chrono/src/format/mod.rs b/chrono/src/format/mod.rs new file mode 100644 index 000000000..bd8337ba0 --- /dev/null +++ b/chrono/src/format/mod.rs @@ -0,0 +1,625 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! Formatting (and parsing) utilities for date and time. +//! +//! This module provides the common types and routines to implement, +//! for example, [`DateTime::format`](../struct.DateTime.html#method.format) or +//! [`DateTime::parse_from_str`](../struct.DateTime.html#method.parse_from_str) methods. +//! For most cases you should use these high-level interfaces. +//! +//! Internally the formatting and parsing shares the same abstract **formatting items**, +//! which are just an [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) of +//! the [`Item`](./enum.Item.html) type. +//! They are generated from more readable **format strings**; +//! currently Chrono supports [one built-in syntax closely resembling +//! C's `strftime` format](./strftime/index.html). + +use std::fmt; +use std::str::FromStr; +use std::error::Error; + +use {Datelike, Timelike, Weekday, ParseWeekdayError}; +use div::{div_floor, mod_floor}; +use offset::{Offset, FixedOffset}; +use naive::{NaiveDate, NaiveTime}; + +pub use self::strftime::StrftimeItems; +pub use self::parsed::Parsed; +pub use self::parse::parse; + +/// An unhabitated type used for `InternalNumeric` and `InternalFixed` below. +#[derive(Clone, PartialEq, Eq)] +enum Void {} + +/// Padding characters for numeric items. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Pad { + /// No padding. + None, + /// Zero (`0`) padding. + Zero, + /// Space padding. + Space, +} + +/// Numeric item types. +/// They have associated formatting width (FW) and parsing width (PW). +/// +/// The **formatting width** is the minimal width to be formatted. +/// If the number is too short, and the padding is not [`Pad::None`](./enum.Pad.html#variant.None), +/// then it is left-padded. +/// If the number is too long or (in some cases) negative, it is printed as is. +/// +/// The **parsing width** is the maximal width to be scanned. +/// The parser only tries to consume from one to given number of digits (greedily). +/// It also trims the preceding whitespaces if any. +/// It cannot parse the negative number, so some date and time cannot be formatted then +/// parsed with the same formatting items. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Numeric { + /// Full Gregorian year (FW=4, PW=∞). + /// May accept years before 1 BCE or after 9999 CE, given an initial sign. + Year, + /// Gregorian year divided by 100 (century number; FW=PW=2). Implies the non-negative year. + YearDiv100, + /// Gregorian year modulo 100 (FW=PW=2). Cannot be negative. + YearMod100, + /// Year in the ISO week date (FW=4, PW=∞). + /// May accept years before 1 BCE or after 9999 CE, given an initial sign. + IsoYear, + /// Year in the ISO week date, divided by 100 (FW=PW=2). Implies the non-negative year. + IsoYearDiv100, + /// Year in the ISO week date, modulo 100 (FW=PW=2). Cannot be negative. + IsoYearMod100, + /// Month (FW=PW=2). + Month, + /// Day of the month (FW=PW=2). + Day, + /// Week number, where the week 1 starts at the first Sunday of January (FW=PW=2). + WeekFromSun, + /// Week number, where the week 1 starts at the first Monday of January (FW=PW=2). + WeekFromMon, + /// Week number in the ISO week date (FW=PW=2). + IsoWeek, + /// Day of the week, where Sunday = 0 and Saturday = 6 (FW=PW=1). + NumDaysFromSun, + /// Day of the week, where Monday = 1 and Sunday = 7 (FW=PW=1). + WeekdayFromMon, + /// Day of the year (FW=PW=3). + Ordinal, + /// Hour number in the 24-hour clocks (FW=PW=2). + Hour, + /// Hour number in the 12-hour clocks (FW=PW=2). + Hour12, + /// The number of minutes since the last whole hour (FW=PW=2). + Minute, + /// The number of seconds since the last whole minute (FW=PW=2). + Second, + /// The number of nanoseconds since the last whole second (FW=PW=9). + /// Note that this is *not* left-aligned; + /// see also [`Fixed::Nanosecond`](./enum.Fixed.html#variant.Nanosecond). + Nanosecond, + /// The number of non-leap seconds since the midnight UTC on January 1, 1970 (FW=1, PW=∞). + /// For formatting, it assumes UTC upon the absence of time zone offset. + Timestamp, + + /// Internal uses only. + /// + /// This item exists so that one can add additional internal-only formatting + /// without breaking major compatibility (as enum variants cannot be selectively private). + Internal(InternalNumeric), +} + +/// An opaque type representing numeric item types for internal uses only. +pub struct InternalNumeric { + _dummy: Void, +} + +impl Clone for InternalNumeric { + fn clone(&self) -> Self { + match self._dummy {} + } +} + +impl PartialEq for InternalNumeric { + fn eq(&self, _other: &InternalNumeric) -> bool { + match self._dummy {} + } +} + +impl Eq for InternalNumeric { +} + +impl fmt::Debug for InternalNumeric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "") + } +} + +/// Fixed-format item types. +/// +/// They have their own rules of formatting and parsing. +/// Otherwise noted, they print in the specified cases but parse case-insensitively. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Fixed { + /// Abbreviated month names. + /// + /// Prints a three-letter-long name in the title case, reads the same name in any case. + ShortMonthName, + /// Full month names. + /// + /// Prints a full name in the title case, reads either a short or full name in any case. + LongMonthName, + /// Abbreviated day of the week names. + /// + /// Prints a three-letter-long name in the title case, reads the same name in any case. + ShortWeekdayName, + /// Full day of the week names. + /// + /// Prints a full name in the title case, reads either a short or full name in any case. + LongWeekdayName, + /// AM/PM. + /// + /// Prints in lower case, reads in any case. + LowerAmPm, + /// AM/PM. + /// + /// Prints in upper case, reads in any case. + UpperAmPm, + /// An optional dot plus one or more digits for left-aligned nanoseconds. + /// May print nothing, 3, 6 or 9 digits according to the available accuracy. + /// See also [`Numeric::Nanosecond`](./enum.Numeric.html#variant.Nanosecond). + Nanosecond, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 3. + Nanosecond3, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 6. + Nanosecond6, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 9. + Nanosecond9, + /// Timezone name. + /// + /// It does not support parsing, its use in the parser is an immediate failure. + TimezoneName, + /// Offset from the local time to UTC (`+09:00` or `-04:00` or `+00:00`). + /// + /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces. + /// The offset is limited from `-24:00` to `+24:00`, + /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. + TimezoneOffsetColon, + /// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`). + /// + /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces, + /// and `Z` can be either in upper case or in lower case. + /// The offset is limited from `-24:00` to `+24:00`, + /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. + TimezoneOffsetColonZ, + /// Same to [`TimezoneOffsetColon`](#variant.TimezoneOffsetColon) but prints no colon. + /// Parsing allows an optional colon. + TimezoneOffset, + /// Same to [`TimezoneOffsetColonZ`](#variant.TimezoneOffsetColonZ) but prints no colon. + /// Parsing allows an optional colon. + TimezoneOffsetZ, + /// RFC 2822 date and time syntax. Commonly used for email and MIME date and time. + RFC2822, + /// RFC 3339 & ISO 8601 date and time syntax. + RFC3339, + + /// Internal uses only. + /// + /// This item exists so that one can add additional internal-only formatting + /// without breaking major compatibility (as enum variants cannot be selectively private). + Internal(InternalFixed), +} + +/// An opaque type representing fixed-format item types for internal uses only. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InternalFixed { + val: InternalInternal, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum InternalInternal { + /// Same as [`TimezoneOffsetColonZ`](#variant.TimezoneOffsetColonZ), but + /// allows missing minutes (per [ISO 8601][iso8601]). + /// + /// # Panics + /// + /// If you try to use this for printing. + /// + /// [iso8601]: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC + TimezoneOffsetPermissive, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 3 and there is no leading dot. + Nanosecond3NoDot, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 6 and there is no leading dot. + Nanosecond6NoDot, + /// Same to [`Nanosecond`](#variant.Nanosecond) but the accuracy is fixed to 9 and there is no leading dot. + Nanosecond9NoDot, +} + +/// A single formatting item. This is used for both formatting and parsing. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Item<'a> { + /// A literally printed and parsed text. + Literal(&'a str), + /// Same to `Literal` but with the string owned by the item. + OwnedLiteral(Box), + /// Whitespace. Prints literally but reads zero or more whitespace. + Space(&'a str), + /// Same to `Space` but with the string owned by the item. + OwnedSpace(Box), + /// Numeric item. Can be optionally padded to the maximal length (if any) when formatting; + /// the parser simply ignores any padded whitespace and zeroes. + Numeric(Numeric, Pad), + /// Fixed-format item. + Fixed(Fixed), + /// Issues a formatting error. Used to signal an invalid format string. + Error, +} + +macro_rules! lit { ($x:expr) => (Item::Literal($x)) } +macro_rules! sp { ($x:expr) => (Item::Space($x)) } +macro_rules! num { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::None)) } +macro_rules! num0 { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::Zero)) } +macro_rules! nums { ($x:ident) => (Item::Numeric(Numeric::$x, Pad::Space)) } +macro_rules! fix { ($x:ident) => (Item::Fixed(Fixed::$x)) } +macro_rules! internal_fix { ($x:ident) => (Item::Fixed(Fixed::Internal(InternalFixed { val: InternalInternal::$x })))} + +/// An error from the `parse` function. +#[derive(Debug, Clone, PartialEq, Eq, Copy)] +pub struct ParseError(ParseErrorKind); + +#[derive(Debug, Clone, PartialEq, Eq, Copy)] +enum ParseErrorKind { + /// Given field is out of permitted range. + OutOfRange, + + /// There is no possible date and time value with given set of fields. + /// + /// This does not include the out-of-range conditions, which are trivially invalid. + /// It includes the case that there are one or more fields that are inconsistent to each other. + Impossible, + + /// Given set of fields is not enough to make a requested date and time value. + /// + /// Note that there *may* be a case that given fields constrain the possible values so much + /// that there is a unique possible value. Chrono only tries to be correct for + /// most useful sets of fields however, as such constraint solving can be expensive. + NotEnough, + + /// The input string has some invalid character sequence for given formatting items. + Invalid, + + /// The input string has been prematurely ended. + TooShort, + + /// All formatting items have been read but there is a remaining input. + TooLong, + + /// There was an error on the formatting string, or there were non-supported formating items. + BadFormat, +} + +/// Same to `Result`. +pub type ParseResult = Result; + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ParseError { + fn description(&self) -> &str { + match self.0 { + ParseErrorKind::OutOfRange => "input is out of range", + ParseErrorKind::Impossible => "no possible date and time matching input", + ParseErrorKind::NotEnough => "input is not enough for unique date and time", + ParseErrorKind::Invalid => "input contains invalid characters", + ParseErrorKind::TooShort => "premature end of input", + ParseErrorKind::TooLong => "trailing input", + ParseErrorKind::BadFormat => "bad or unsupported format string", + } + } +} + +// to be used in this module and submodules +const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange); +const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible); +const NOT_ENOUGH: ParseError = ParseError(ParseErrorKind::NotEnough); +const INVALID: ParseError = ParseError(ParseErrorKind::Invalid); +const TOO_SHORT: ParseError = ParseError(ParseErrorKind::TooShort); +const TOO_LONG: ParseError = ParseError(ParseErrorKind::TooLong); +const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat); + +/// Tries to format given arguments with given formatting items. +/// Internally used by `DelayedFormat`. +pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveTime>, + off: Option<&(String, FixedOffset)>, items: I) -> fmt::Result + where I: Iterator> { + // full and abbreviated month and weekday names + static SHORT_MONTHS: [&'static str; 12] = + ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + static LONG_MONTHS: [&'static str; 12] = + ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"]; + static SHORT_WEEKDAYS: [&'static str; 7] = + ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; + static LONG_WEEKDAYS: [&'static str; 7] = + ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + + for item in items { + match item { + Item::Literal(s) | Item::Space(s) => try!(write!(w, "{}", s)), + Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => try!(write!(w, "{}", s)), + + Item::Numeric(spec, pad) => { + use self::Numeric::*; + + let week_from_sun = |d: &NaiveDate| + (d.ordinal() as i32 - d.weekday().num_days_from_sunday() as i32 + 7) / 7; + let week_from_mon = |d: &NaiveDate| + (d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7; + + let (width, v) = match spec { + Year => (4, date.map(|d| i64::from(d.year()))), + YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))), + YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))), + IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))), + IsoYearDiv100 => (2, date.map(|d| div_floor( + i64::from(d.iso_week().year()), 100))), + IsoYearMod100 => (2, date.map(|d| mod_floor( + i64::from(d.iso_week().year()), 100))), + Month => (2, date.map(|d| i64::from(d.month()))), + Day => (2, date.map(|d| i64::from(d.day()))), + WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))), + WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))), + IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))), + NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday() + .num_days_from_sunday()))), + WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday() + .number_from_monday()))), + Ordinal => (3, date.map(|d| i64::from(d.ordinal()))), + Hour => (2, time.map(|t| i64::from(t.hour()))), + Hour12 => (2, time.map(|t| i64::from(t.hour12().1))), + Minute => (2, time.map(|t| i64::from(t.minute()))), + Second => (2, time.map(|t| i64::from(t.second() + + t.nanosecond() / 1_000_000_000))), + Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))), + Timestamp => (1, match (date, time, off) { + (Some(d), Some(t), None) => + Some(d.and_time(*t).timestamp()), + (Some(d), Some(t), Some(&(_, off))) => + Some((d.and_time(*t) - off).timestamp()), + (_, _, _) => None + }), + + // for the future expansion + Internal(ref int) => match int._dummy {}, + }; + + if let Some(v) = v { + if (spec == Year || spec == IsoYear) && !(0 <= v && v < 10_000) { + // non-four-digit years require an explicit sign as per ISO 8601 + match pad { + Pad::None => try!(write!(w, "{:+}", v)), + Pad::Zero => try!(write!(w, "{:+01$}", v, width + 1)), + Pad::Space => try!(write!(w, "{:+1$}", v, width + 1)), + } + } else { + match pad { + Pad::None => try!(write!(w, "{}", v)), + Pad::Zero => try!(write!(w, "{:01$}", v, width)), + Pad::Space => try!(write!(w, "{:1$}", v, width)), + } + } + } else { + return Err(fmt::Error); // insufficient arguments for given format + } + }, + + Item::Fixed(spec) => { + use self::Fixed::*; + + /// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`. + /// `Z` instead of `+00[:]00` is allowed when `allow_zulu` is true. + fn write_local_minus_utc(w: &mut fmt::Formatter, off: FixedOffset, + allow_zulu: bool, use_colon: bool) -> fmt::Result { + let off = off.local_minus_utc(); + if !allow_zulu || off != 0 { + let (sign, off) = if off < 0 {('-', -off)} else {('+', off)}; + if use_colon { + write!(w, "{}{:02}:{:02}", sign, off / 3600, off / 60 % 60) + } else { + write!(w, "{}{:02}{:02}", sign, off / 3600, off / 60 % 60) + } + } else { + write!(w, "Z") + } + } + + let ret = match spec { + ShortMonthName => + date.map(|d| write!(w, "{}", SHORT_MONTHS[d.month0() as usize])), + LongMonthName => + date.map(|d| write!(w, "{}", LONG_MONTHS[d.month0() as usize])), + ShortWeekdayName => + date.map(|d| write!(w, "{}", + SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize])), + LongWeekdayName => + date.map(|d| write!(w, "{}", + LONG_WEEKDAYS[d.weekday().num_days_from_monday() as usize])), + LowerAmPm => + time.map(|t| write!(w, "{}", if t.hour12().0 {"pm"} else {"am"})), + UpperAmPm => + time.map(|t| write!(w, "{}", if t.hour12().0 {"PM"} else {"AM"})), + Nanosecond => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + if nano == 0 { + Ok(()) + } else if nano % 1_000_000 == 0 { + write!(w, ".{:03}", nano / 1_000_000) + } else if nano % 1_000 == 0 { + write!(w, ".{:06}", nano / 1_000) + } else { + write!(w, ".{:09}", nano) + } + }), + Nanosecond3 => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, ".{:03}", nano / 1_000_000) + }), + Nanosecond6 => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, ".{:06}", nano / 1_000) + }), + Nanosecond9 => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, ".{:09}", nano) + }), + Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, "{:03}", nano / 1_000_000) + }), + Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, "{:06}", nano / 1_000) + }), + Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => + time.map(|t| { + let nano = t.nanosecond() % 1_000_000_000; + write!(w, "{:09}", nano) + }), + TimezoneName => + off.map(|&(ref name, _)| write!(w, "{}", *name)), + TimezoneOffsetColon => + off.map(|&(_, off)| write_local_minus_utc(w, off, false, true)), + TimezoneOffsetColonZ => + off.map(|&(_, off)| write_local_minus_utc(w, off, true, true)), + TimezoneOffset => + off.map(|&(_, off)| write_local_minus_utc(w, off, false, false)), + TimezoneOffsetZ => + off.map(|&(_, off)| write_local_minus_utc(w, off, true, false)), + Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => + panic!("Do not try to write %#z it is undefined"), + RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z` + if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) { + let sec = t.second() + t.nanosecond() / 1_000_000_000; + try!(write!(w, "{}, {:2} {} {:04} {:02}:{:02}:{:02} ", + SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize], + d.day(), SHORT_MONTHS[d.month0() as usize], d.year(), + t.hour(), t.minute(), sec)); + Some(write_local_minus_utc(w, off, false, false)) + } else { + None + }, + RFC3339 => // same to `%Y-%m-%dT%H:%M:%S%.f%:z` + if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) { + // reuse `Debug` impls which already print ISO 8601 format. + // this is faster in this way. + try!(write!(w, "{:?}T{:?}", d, t)); + Some(write_local_minus_utc(w, off, false, true)) + } else { + None + }, + }; + + match ret { + Some(ret) => try!(ret), + None => return Err(fmt::Error), // insufficient arguments for given format + } + }, + + Item::Error => return Err(fmt::Error), + } + } + + Ok(()) +} + +mod parsed; + +// due to the size of parsing routines, they are in separate modules. +mod scan; +mod parse; + +pub mod strftime; + +/// A *temporary* object which can be used as an argument to `format!` or others. +/// This is normally constructed via `format` methods of each date and time type. +#[derive(Debug)] +pub struct DelayedFormat { + /// The date view, if any. + date: Option, + /// The time view, if any. + time: Option, + /// The name and local-to-UTC difference for the offset (timezone), if any. + off: Option<(String, FixedOffset)>, + /// An iterator returning formatting items. + items: I, +} + +impl<'a, I: Iterator> + Clone> DelayedFormat { + /// Makes a new `DelayedFormat` value out of local date and time. + pub fn new(date: Option, time: Option, items: I) -> DelayedFormat { + DelayedFormat { date: date, time: time, off: None, items: items } + } + + /// Makes a new `DelayedFormat` value out of local date and time and UTC offset. + pub fn new_with_offset(date: Option, time: Option, + offset: &Off, items: I) -> DelayedFormat + where Off: Offset + fmt::Display { + let name_and_diff = (offset.to_string(), offset.fix()); + DelayedFormat { date: date, time: time, off: Some(name_and_diff), items: items } + } +} + +impl<'a, I: Iterator> + Clone> fmt::Display for DelayedFormat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone()) + } +} + +// this implementation is here only because we need some private code from `scan` + +/// Parsing a `str` into a `Weekday` uses the format [`%W`](./format/strftime/index.html). +/// +/// # Example +/// +/// ~~~~ +/// use chrono::Weekday; +/// +/// assert_eq!("Sunday".parse::(), Ok(Weekday::Sun)); +/// assert!("any day".parse::().is_err()); +/// ~~~~ +/// +/// The parsing is case-insensitive. +/// +/// ~~~~ +/// # use chrono::Weekday; +/// assert_eq!("mON".parse::(), Ok(Weekday::Mon)); +/// ~~~~ +/// +/// Only the shortest form (e.g. `sun`) and the longest form (e.g. `sunday`) is accepted. +/// +/// ~~~~ +/// # use chrono::Weekday; +/// assert!("thurs".parse::().is_err()); +/// ~~~~ +impl FromStr for Weekday { + type Err = ParseWeekdayError; + + fn from_str(s: &str) -> Result { + if let Ok(("", w)) = scan::short_or_long_weekday(s) { + Ok(w) + } else { + Err(ParseWeekdayError { _dummy: () }) + } + } +} diff --git a/chrono/src/format/parse.rs b/chrono/src/format/parse.rs new file mode 100644 index 000000000..88c32d104 --- /dev/null +++ b/chrono/src/format/parse.rs @@ -0,0 +1,794 @@ +// This is a part of Chrono. +// Portions copyright (c) 2015, John Nagle. +// See README.md and LICENSE.txt for details. + +//! Date and time parsing routines. + +use std::usize; + +use Weekday; + +use super::scan; +use super::{Parsed, ParseResult, Item, InternalFixed, InternalInternal}; +use super::{OUT_OF_RANGE, INVALID, TOO_SHORT, TOO_LONG, BAD_FORMAT}; + +fn set_weekday_with_num_days_from_sunday(p: &mut Parsed, v: i64) -> ParseResult<()> { + p.set_weekday(match v { + 0 => Weekday::Sun, 1 => Weekday::Mon, 2 => Weekday::Tue, + 3 => Weekday::Wed, 4 => Weekday::Thu, 5 => Weekday::Fri, + 6 => Weekday::Sat, _ => return Err(OUT_OF_RANGE) + }) +} + +fn set_weekday_with_number_from_monday(p: &mut Parsed, v: i64) -> ParseResult<()> { + p.set_weekday(match v { + 1 => Weekday::Mon, 2 => Weekday::Tue, 3 => Weekday::Wed, + 4 => Weekday::Thu, 5 => Weekday::Fri, 6 => Weekday::Sat, + 7 => Weekday::Sun, _ => return Err(OUT_OF_RANGE) + }) +} + +fn parse_rfc2822<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a str, ())> { + macro_rules! try_consume { + ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) + } + + // an adapted RFC 2822 syntax from Section 3.3 and 4.3: + // + // date-time = [ day-of-week "," ] date 1*S time *S + // day-of-week = *S day-name *S + // day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" + // date = day month year + // day = *S 1*2DIGIT *S + // month = 1*S month-name 1*S + // month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / + // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" + // year = *S 2*DIGIT *S + // time = time-of-day 1*S zone + // time-of-day = hour ":" minute [ ":" second ] + // hour = *S 2DIGIT *S + // minute = *S 2DIGIT *S + // second = *S 2DIGIT *S + // zone = ( "+" / "-" ) 4DIGIT / + // "UT" / "GMT" / ; same to +0000 + // "EST" / "CST" / "MST" / "PST" / ; same to -0500 to -0800 + // "EDT" / "CDT" / "MDT" / "PDT" / ; same to -0400 to -0700 + // 1*(%d65-90 / %d97-122) ; same to -0000 + // + // some notes: + // + // - quoted characters can be in any mixture of lower and upper cases. + // + // - we do not recognize a folding white space (FWS) or comment (CFWS). + // for our purposes, instead, we accept any sequence of Unicode + // white space characters (denoted here to `S`). any actual RFC 2822 + // parser is expected to parse FWS and/or CFWS themselves and replace + // it with a single SP (`%x20`); this is legitimate. + // + // - two-digit year < 50 should be interpreted by adding 2000. + // two-digit year >= 50 or three-digit year should be interpreted + // by adding 1900. note that four-or-more-digit years less than 1000 + // are *never* affected by this rule. + // + // - zone of `-0000` and any unrecognized legacy time zones (including + // *every* one-letter military time zones) are considered "missing", + // in such that we don't actually know what time zone is being used. + // + // - mismatching day-of-week is always an error, which is consistent to + // Chrono's own rules. + // + // - zones can range from `-9959` to `+9959`, but `FixedOffset` does not + // support offsets larger than 24 hours. this is not *that* problematic + // since we do not directly go to a `DateTime` so one can recover + // the offset information from `Parsed` anyway. + + s = s.trim_left(); + + if let Ok((s_, weekday)) = scan::short_weekday(s) { + if !s_.starts_with(',') { return Err(INVALID); } + s = &s_[1..]; + try!(parsed.set_weekday(weekday)); + } + + s = s.trim_left(); + try!(parsed.set_day(try_consume!(scan::number(s, 1, 2)))); + s = try!(scan::space(s)); // mandatory + try!(parsed.set_month(1 + i64::from(try_consume!(scan::short_month0(s))))); + s = try!(scan::space(s)); // mandatory + + // distinguish two- and three-digit years from four-digit years + let prevlen = s.len(); + let mut year = try_consume!(scan::number(s, 2, usize::MAX)); + let yearlen = prevlen - s.len(); + match (yearlen, year) { + (2, 0...49) => { year += 2000; } // 47 -> 2047, 05 -> 2005 + (2, 50...99) => { year += 1900; } // 79 -> 1979 + (3, _) => { year += 1900; } // 112 -> 2012, 009 -> 1909 + (_, _) => {} // 1987 -> 1987, 0654 -> 0654 + } + try!(parsed.set_year(year)); + + s = try!(scan::space(s)); // mandatory + try!(parsed.set_hour(try_consume!(scan::number(s, 2, 2)))); + s = try!(scan::char(s.trim_left(), b':')).trim_left(); // *S ":" *S + try!(parsed.set_minute(try_consume!(scan::number(s, 2, 2)))); + if let Ok(s_) = scan::char(s.trim_left(), b':') { // [ ":" *S 2DIGIT ] + try!(parsed.set_second(try_consume!(scan::number(s_, 2, 2)))); + } + + s = try!(scan::space(s)); // mandatory + if let Some(offset) = try_consume!(scan::timezone_offset_2822(s)) { + // only set the offset when it is definitely known (i.e. not `-0000`) + try!(parsed.set_offset(i64::from(offset))); + } + + Ok((s, ())) +} + +fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a str, ())> { + macro_rules! try_consume { + ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) + } + + // an adapted RFC 3339 syntax from Section 5.6: + // + // date-fullyear = 4DIGIT + // date-month = 2DIGIT ; 01-12 + // date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year + // time-hour = 2DIGIT ; 00-23 + // time-minute = 2DIGIT ; 00-59 + // time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules + // time-secfrac = "." 1*DIGIT + // time-numoffset = ("+" / "-") time-hour ":" time-minute + // time-offset = "Z" / time-numoffset + // partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] + // full-date = date-fullyear "-" date-month "-" date-mday + // full-time = partial-time time-offset + // date-time = full-date "T" full-time + // + // some notes: + // + // - quoted characters can be in any mixture of lower and upper cases. + // + // - it may accept any number of fractional digits for seconds. + // for Chrono, this means that we should skip digits past first 9 digits. + // + // - unlike RFC 2822, the valid offset ranges from -23:59 to +23:59. + // note that this restriction is unique to RFC 3339 and not ISO 8601. + // since this is not a typical Chrono behavior, we check it earlier. + + try!(parsed.set_year(try_consume!(scan::number(s, 4, 4)))); + s = try!(scan::char(s, b'-')); + try!(parsed.set_month(try_consume!(scan::number(s, 2, 2)))); + s = try!(scan::char(s, b'-')); + try!(parsed.set_day(try_consume!(scan::number(s, 2, 2)))); + + s = match s.as_bytes().first() { + Some(&b't') | Some(&b'T') => &s[1..], + Some(_) => return Err(INVALID), + None => return Err(TOO_SHORT), + }; + + try!(parsed.set_hour(try_consume!(scan::number(s, 2, 2)))); + s = try!(scan::char(s, b':')); + try!(parsed.set_minute(try_consume!(scan::number(s, 2, 2)))); + s = try!(scan::char(s, b':')); + try!(parsed.set_second(try_consume!(scan::number(s, 2, 2)))); + if s.starts_with('.') { + let nanosecond = try_consume!(scan::nanosecond(&s[1..])); + try!(parsed.set_nanosecond(nanosecond)); + } + + let offset = try_consume!(scan::timezone_offset_zulu(s, |s| scan::char(s, b':'))); + if offset <= -86_400 || offset >= 86_400 { return Err(OUT_OF_RANGE); } + try!(parsed.set_offset(i64::from(offset))); + + Ok((s, ())) +} + +/// Tries to parse given string into `parsed` with given formatting items. +/// Returns `Ok` when the entire string has been parsed (otherwise `parsed` should not be used). +/// There should be no trailing string after parsing; +/// use a stray [`Item::Space`](./enum.Item.html#variant.Space) to trim whitespaces. +/// +/// This particular date and time parser is: +/// +/// - Greedy. It will consume the longest possible prefix. +/// For example, `April` is always consumed entirely when the long month name is requested; +/// it equally accepts `Apr`, but prefers the longer prefix in this case. +/// +/// - Padding-agnostic (for numeric items). +/// The [`Pad`](./enum.Pad.html) field is completely ignored, +/// so one can prepend any number of whitespace then any number of zeroes before numbers. +/// +/// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`. +pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()> + where I: Iterator> { + macro_rules! try_consume { + ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) + } + + for item in items { + match item { + Item::Literal(prefix) => { + if s.len() < prefix.len() { return Err(TOO_SHORT); } + if !s.starts_with(prefix) { return Err(INVALID); } + s = &s[prefix.len()..]; + } + + Item::OwnedLiteral(ref prefix) => { + if s.len() < prefix.len() { return Err(TOO_SHORT); } + if !s.starts_with(&prefix[..]) { return Err(INVALID); } + s = &s[prefix.len()..]; + } + + Item::Space(_) | Item::OwnedSpace(_) => { + s = s.trim_left(); + } + + Item::Numeric(spec, _pad) => { + use super::Numeric::*; + type Setter = fn(&mut Parsed, i64) -> ParseResult<()>; + + let (width, signed, set): (usize, bool, Setter) = match spec { + Year => (4, true, Parsed::set_year), + YearDiv100 => (2, false, Parsed::set_year_div_100), + YearMod100 => (2, false, Parsed::set_year_mod_100), + IsoYear => (4, true, Parsed::set_isoyear), + IsoYearDiv100 => (2, false, Parsed::set_isoyear_div_100), + IsoYearMod100 => (2, false, Parsed::set_isoyear_mod_100), + Month => (2, false, Parsed::set_month), + Day => (2, false, Parsed::set_day), + WeekFromSun => (2, false, Parsed::set_week_from_sun), + WeekFromMon => (2, false, Parsed::set_week_from_mon), + IsoWeek => (2, false, Parsed::set_isoweek), + NumDaysFromSun => (1, false, set_weekday_with_num_days_from_sunday), + WeekdayFromMon => (1, false, set_weekday_with_number_from_monday), + Ordinal => (3, false, Parsed::set_ordinal), + Hour => (2, false, Parsed::set_hour), + Hour12 => (2, false, Parsed::set_hour12), + Minute => (2, false, Parsed::set_minute), + Second => (2, false, Parsed::set_second), + Nanosecond => (9, false, Parsed::set_nanosecond), + Timestamp => (usize::MAX, false, Parsed::set_timestamp), + + // for the future expansion + Internal(ref int) => match int._dummy {}, + }; + + s = s.trim_left(); + let v = if signed { + if s.starts_with('-') { + let v = try_consume!(scan::number(&s[1..], 1, usize::MAX)); + try!(0i64.checked_sub(v).ok_or(OUT_OF_RANGE)) + } else if s.starts_with('+') { + try_consume!(scan::number(&s[1..], 1, usize::MAX)) + } else { + // if there is no explicit sign, we respect the original `width` + try_consume!(scan::number(s, 1, width)) + } + } else { + try_consume!(scan::number(s, 1, width)) + }; + try!(set(parsed, v)); + } + + Item::Fixed(spec) => { + use super::Fixed::*; + + match spec { + ShortMonthName => { + let month0 = try_consume!(scan::short_month0(s)); + try!(parsed.set_month(i64::from(month0) + 1)); + } + + LongMonthName => { + let month0 = try_consume!(scan::short_or_long_month0(s)); + try!(parsed.set_month(i64::from(month0) + 1)); + } + + ShortWeekdayName => { + let weekday = try_consume!(scan::short_weekday(s)); + try!(parsed.set_weekday(weekday)); + } + + LongWeekdayName => { + let weekday = try_consume!(scan::short_or_long_weekday(s)); + try!(parsed.set_weekday(weekday)); + } + + LowerAmPm | UpperAmPm => { + if s.len() < 2 { return Err(TOO_SHORT); } + let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) { + (b'a',b'm') => false, + (b'p',b'm') => true, + _ => return Err(INVALID) + }; + try!(parsed.set_ampm(ampm)); + s = &s[2..]; + } + + Nanosecond | Nanosecond3 | Nanosecond6 | Nanosecond9 => { + if s.starts_with('.') { + let nano = try_consume!(scan::nanosecond(&s[1..])); + try!(parsed.set_nanosecond(nano)); + } + } + + Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => { + if s.len() < 3 { return Err(TOO_SHORT); } + let nano = try_consume!(scan::nanosecond_fixed(s, 3)); + try!(parsed.set_nanosecond(nano)); + } + + Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => { + if s.len() < 6 { return Err(TOO_SHORT); } + let nano = try_consume!(scan::nanosecond_fixed(s, 6)); + try!(parsed.set_nanosecond(nano)); + } + + Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => { + if s.len() < 9 { return Err(TOO_SHORT); } + let nano = try_consume!(scan::nanosecond_fixed(s, 9)); + try!(parsed.set_nanosecond(nano)); + } + + TimezoneName => return Err(BAD_FORMAT), + + TimezoneOffsetColon | TimezoneOffset => { + let offset = try_consume!(scan::timezone_offset(s.trim_left(), + scan::colon_or_space)); + try!(parsed.set_offset(i64::from(offset))); + } + + TimezoneOffsetColonZ | TimezoneOffsetZ => { + let offset = try_consume!(scan::timezone_offset_zulu(s.trim_left(), + scan::colon_or_space)); + try!(parsed.set_offset(i64::from(offset))); + } + Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => { + let offset = try_consume!(scan::timezone_offset_permissive( + s.trim_left(), scan::colon_or_space)); + try!(parsed.set_offset(i64::from(offset))); + } + + RFC2822 => try_consume!(parse_rfc2822(parsed, s)), + RFC3339 => try_consume!(parse_rfc3339(parsed, s)), + } + } + + Item::Error => { + return Err(BAD_FORMAT); + } + } + } + + // if there are trailling chars, it is an error + if !s.is_empty() { + Err(TOO_LONG) + } else { + Ok(()) + } +} + +#[cfg(test)] +#[test] +fn test_parse() { + use super::*; + use super::IMPOSSIBLE; + + // workaround for Rust issue #22255 + fn parse_all(s: &str, items: &[Item]) -> ParseResult { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, items.iter().cloned())); + Ok(parsed) + } + + macro_rules! check { + ($fmt:expr, $items:expr; $err:tt) => ( + assert_eq!(parse_all($fmt, &$items), Err($err)) + ); + ($fmt:expr, $items:expr; $($k:ident: $v:expr),*) => (#[allow(unused_mut)] { + let mut expected = Parsed::new(); + $(expected.$k = Some($v);)* + assert_eq!(parse_all($fmt, &$items), Ok(expected)) + }); + } + + // empty string + check!("", []; ); + check!(" ", []; TOO_LONG); + check!("a", []; TOO_LONG); + + // whitespaces + check!("", [sp!("")]; ); + check!(" ", [sp!("")]; ); + check!("\t", [sp!("")]; ); + check!(" \n\r \n", [sp!("")]; ); + check!("a", [sp!("")]; TOO_LONG); + + // literal + check!("", [lit!("a")]; TOO_SHORT); + check!(" ", [lit!("a")]; INVALID); + check!("a", [lit!("a")]; ); + check!("aa", [lit!("a")]; TOO_LONG); + check!("A", [lit!("a")]; INVALID); + check!("xy", [lit!("xy")]; ); + check!("xy", [lit!("x"), lit!("y")]; ); + check!("x y", [lit!("x"), lit!("y")]; INVALID); + check!("xy", [lit!("x"), sp!(""), lit!("y")]; ); + check!("x y", [lit!("x"), sp!(""), lit!("y")]; ); + + // numeric + check!("1987", [num!(Year)]; year: 1987); + check!("1987 ", [num!(Year)]; TOO_LONG); + check!("0x12", [num!(Year)]; TOO_LONG); // `0` is parsed + check!("x123", [num!(Year)]; INVALID); + check!("2015", [num!(Year)]; year: 2015); + check!("0000", [num!(Year)]; year: 0); + check!("9999", [num!(Year)]; year: 9999); + check!(" \t987", [num!(Year)]; year: 987); + check!("5", [num!(Year)]; year: 5); + check!("5\0", [num!(Year)]; TOO_LONG); + check!("\05", [num!(Year)]; INVALID); + check!("", [num!(Year)]; TOO_SHORT); + check!("12345", [num!(Year), lit!("5")]; year: 1234); + check!("12345", [nums!(Year), lit!("5")]; year: 1234); + check!("12345", [num0!(Year), lit!("5")]; year: 1234); + check!("12341234", [num!(Year), num!(Year)]; year: 1234); + check!("1234 1234", [num!(Year), num!(Year)]; year: 1234); + check!("1234 1235", [num!(Year), num!(Year)]; IMPOSSIBLE); + check!("1234 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); + check!("1234x1234", [num!(Year), lit!("x"), num!(Year)]; year: 1234); + check!("1234xx1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); + check!("1234 x 1234", [num!(Year), lit!("x"), num!(Year)]; INVALID); + + // signed numeric + check!("-42", [num!(Year)]; year: -42); + check!("+42", [num!(Year)]; year: 42); + check!("-0042", [num!(Year)]; year: -42); + check!("+0042", [num!(Year)]; year: 42); + check!("-42195", [num!(Year)]; year: -42195); + check!("+42195", [num!(Year)]; year: 42195); + check!(" -42195", [num!(Year)]; year: -42195); + check!(" +42195", [num!(Year)]; year: 42195); + check!(" - 42", [num!(Year)]; INVALID); + check!(" + 42", [num!(Year)]; INVALID); + check!("-", [num!(Year)]; TOO_SHORT); + check!("+", [num!(Year)]; TOO_SHORT); + + // unsigned numeric + check!("345", [num!(Ordinal)]; ordinal: 345); + check!("+345", [num!(Ordinal)]; INVALID); + check!("-345", [num!(Ordinal)]; INVALID); + check!(" 345", [num!(Ordinal)]; ordinal: 345); + check!(" +345", [num!(Ordinal)]; INVALID); + check!(" -345", [num!(Ordinal)]; INVALID); + + // various numeric fields + check!("1234 5678", + [num!(Year), num!(IsoYear)]; + year: 1234, isoyear: 5678); + check!("12 34 56 78", + [num!(YearDiv100), num!(YearMod100), num!(IsoYearDiv100), num!(IsoYearMod100)]; + year_div_100: 12, year_mod_100: 34, isoyear_div_100: 56, isoyear_mod_100: 78); + check!("1 2 3 4 5 6", + [num!(Month), num!(Day), num!(WeekFromSun), num!(WeekFromMon), num!(IsoWeek), + num!(NumDaysFromSun)]; + month: 1, day: 2, week_from_sun: 3, week_from_mon: 4, isoweek: 5, weekday: Weekday::Sat); + check!("7 89 01", + [num!(WeekdayFromMon), num!(Ordinal), num!(Hour12)]; + weekday: Weekday::Sun, ordinal: 89, hour_mod_12: 1); + check!("23 45 6 78901234 567890123", + [num!(Hour), num!(Minute), num!(Second), num!(Nanosecond), num!(Timestamp)]; + hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6, nanosecond: 78_901_234, + timestamp: 567_890_123); + + // fixed: month and weekday names + check!("apr", [fix!(ShortMonthName)]; month: 4); + check!("Apr", [fix!(ShortMonthName)]; month: 4); + check!("APR", [fix!(ShortMonthName)]; month: 4); + check!("ApR", [fix!(ShortMonthName)]; month: 4); + check!("April", [fix!(ShortMonthName)]; TOO_LONG); // `Apr` is parsed + check!("A", [fix!(ShortMonthName)]; TOO_SHORT); + check!("Sol", [fix!(ShortMonthName)]; INVALID); + check!("Apr", [fix!(LongMonthName)]; month: 4); + check!("Apri", [fix!(LongMonthName)]; TOO_LONG); // `Apr` is parsed + check!("April", [fix!(LongMonthName)]; month: 4); + check!("Aprill", [fix!(LongMonthName)]; TOO_LONG); + check!("Aprill", [fix!(LongMonthName), lit!("l")]; month: 4); + check!("Aprl", [fix!(LongMonthName), lit!("l")]; month: 4); + check!("April", [fix!(LongMonthName), lit!("il")]; TOO_SHORT); // do not backtrack + check!("thu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); + check!("Thu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); + check!("THU", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); + check!("tHu", [fix!(ShortWeekdayName)]; weekday: Weekday::Thu); + check!("Thursday", [fix!(ShortWeekdayName)]; TOO_LONG); // `Thu` is parsed + check!("T", [fix!(ShortWeekdayName)]; TOO_SHORT); + check!("The", [fix!(ShortWeekdayName)]; INVALID); + check!("Nop", [fix!(ShortWeekdayName)]; INVALID); + check!("Thu", [fix!(LongWeekdayName)]; weekday: Weekday::Thu); + check!("Thur", [fix!(LongWeekdayName)]; TOO_LONG); // `Thu` is parsed + check!("Thurs", [fix!(LongWeekdayName)]; TOO_LONG); // ditto + check!("Thursday", [fix!(LongWeekdayName)]; weekday: Weekday::Thu); + check!("Thursdays", [fix!(LongWeekdayName)]; TOO_LONG); + check!("Thursdays", [fix!(LongWeekdayName), lit!("s")]; weekday: Weekday::Thu); + check!("Thus", [fix!(LongWeekdayName), lit!("s")]; weekday: Weekday::Thu); + check!("Thursday", [fix!(LongWeekdayName), lit!("rsday")]; TOO_SHORT); // do not backtrack + + // fixed: am/pm + check!("am", [fix!(LowerAmPm)]; hour_div_12: 0); + check!("pm", [fix!(LowerAmPm)]; hour_div_12: 1); + check!("AM", [fix!(LowerAmPm)]; hour_div_12: 0); + check!("PM", [fix!(LowerAmPm)]; hour_div_12: 1); + check!("am", [fix!(UpperAmPm)]; hour_div_12: 0); + check!("pm", [fix!(UpperAmPm)]; hour_div_12: 1); + check!("AM", [fix!(UpperAmPm)]; hour_div_12: 0); + check!("PM", [fix!(UpperAmPm)]; hour_div_12: 1); + check!("Am", [fix!(LowerAmPm)]; hour_div_12: 0); + check!(" Am", [fix!(LowerAmPm)]; INVALID); + check!("ame", [fix!(LowerAmPm)]; TOO_LONG); // `am` is parsed + check!("a", [fix!(LowerAmPm)]; TOO_SHORT); + check!("p", [fix!(LowerAmPm)]; TOO_SHORT); + check!("x", [fix!(LowerAmPm)]; TOO_SHORT); + check!("xx", [fix!(LowerAmPm)]; INVALID); + check!("", [fix!(LowerAmPm)]; TOO_SHORT); + + // fixed: dot plus nanoseconds + check!("", [fix!(Nanosecond)]; ); // no field set, but not an error + check!("4", [fix!(Nanosecond)]; TOO_LONG); // never consumes `4` + check!("4", [fix!(Nanosecond), num!(Second)]; second: 4); + check!(".0", [fix!(Nanosecond)]; nanosecond: 0); + check!(".4", [fix!(Nanosecond)]; nanosecond: 400_000_000); + check!(".42", [fix!(Nanosecond)]; nanosecond: 420_000_000); + check!(".421", [fix!(Nanosecond)]; nanosecond: 421_000_000); + check!(".42195", [fix!(Nanosecond)]; nanosecond: 421_950_000); + check!(".421950803", [fix!(Nanosecond)]; nanosecond: 421_950_803); + check!(".421950803547", [fix!(Nanosecond)]; nanosecond: 421_950_803); + check!(".000000003547", [fix!(Nanosecond)]; nanosecond: 3); + check!(".000000000547", [fix!(Nanosecond)]; nanosecond: 0); + check!(".", [fix!(Nanosecond)]; TOO_SHORT); + check!(".4x", [fix!(Nanosecond)]; TOO_LONG); + check!(". 4", [fix!(Nanosecond)]; INVALID); + check!(" .4", [fix!(Nanosecond)]; TOO_LONG); // no automatic trimming + + // fixed: nanoseconds without the dot + check!("", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!("0", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!("4", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!("42", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!("421", [internal_fix!(Nanosecond3NoDot)]; nanosecond: 421_000_000); + check!("42143", [internal_fix!(Nanosecond3NoDot), num!(Second)]; nanosecond: 421_000_000, second: 43); + check!("42195", [internal_fix!(Nanosecond3NoDot)]; TOO_LONG); + check!("4x", [internal_fix!(Nanosecond3NoDot)]; TOO_SHORT); + check!(" 4", [internal_fix!(Nanosecond3NoDot)]; INVALID); + check!(".421", [internal_fix!(Nanosecond3NoDot)]; INVALID); + + check!("", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!("0", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!("42195", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!("421950", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 421_950_000); + check!("000003", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 3000); + check!("000000", [internal_fix!(Nanosecond6NoDot)]; nanosecond: 0); + check!("4x", [internal_fix!(Nanosecond6NoDot)]; TOO_SHORT); + check!(" 4", [internal_fix!(Nanosecond6NoDot)]; INVALID); + check!(".42100", [internal_fix!(Nanosecond6NoDot)]; INVALID); + + check!("", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); + check!("42195", [internal_fix!(Nanosecond9NoDot)]; TOO_SHORT); + check!("421950803", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 421_950_803); + check!("000000003", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 3); + check!("42195080354", [internal_fix!(Nanosecond9NoDot), num!(Second)]; nanosecond: 421_950_803, second: 54); // don't skip digits that come after the 9 + check!("421950803547", [internal_fix!(Nanosecond9NoDot)]; TOO_LONG); + check!("000000000", [internal_fix!(Nanosecond9NoDot)]; nanosecond: 0); + check!("00000000x", [internal_fix!(Nanosecond9NoDot)]; INVALID); + check!(" 4", [internal_fix!(Nanosecond9NoDot)]; INVALID); + check!(".42100000", [internal_fix!(Nanosecond9NoDot)]; INVALID); + + // fixed: timezone offsets + check!("+00:00", [fix!(TimezoneOffset)]; offset: 0); + check!("-00:00", [fix!(TimezoneOffset)]; offset: 0); + check!("+00:01", [fix!(TimezoneOffset)]; offset: 60); + check!("-00:01", [fix!(TimezoneOffset)]; offset: -60); + check!("+00:30", [fix!(TimezoneOffset)]; offset: 30 * 60); + check!("-00:30", [fix!(TimezoneOffset)]; offset: -30 * 60); + check!("+04:56", [fix!(TimezoneOffset)]; offset: 296 * 60); + check!("-04:56", [fix!(TimezoneOffset)]; offset: -296 * 60); + check!("+24:00", [fix!(TimezoneOffset)]; offset: 24 * 60 * 60); + check!("-24:00", [fix!(TimezoneOffset)]; offset: -24 * 60 * 60); + check!("+99:59", [fix!(TimezoneOffset)]; offset: (100 * 60 - 1) * 60); + check!("-99:59", [fix!(TimezoneOffset)]; offset: -(100 * 60 - 1) * 60); + check!("+00:59", [fix!(TimezoneOffset)]; offset: 59 * 60); + check!("+00:60", [fix!(TimezoneOffset)]; OUT_OF_RANGE); + check!("+00:99", [fix!(TimezoneOffset)]; OUT_OF_RANGE); + check!("#12:34", [fix!(TimezoneOffset)]; INVALID); + check!("12:34", [fix!(TimezoneOffset)]; INVALID); + check!("+12:34 ", [fix!(TimezoneOffset)]; TOO_LONG); + check!(" +12:34", [fix!(TimezoneOffset)]; offset: 754 * 60); + check!("\t -12:34", [fix!(TimezoneOffset)]; offset: -754 * 60); + check!("", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+1", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+12", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+123", [fix!(TimezoneOffset)]; TOO_SHORT); + check!("+1234", [fix!(TimezoneOffset)]; offset: 754 * 60); + check!("+12345", [fix!(TimezoneOffset)]; TOO_LONG); + check!("+12345", [fix!(TimezoneOffset), num!(Day)]; offset: 754 * 60, day: 5); + check!("Z", [fix!(TimezoneOffset)]; INVALID); + check!("z", [fix!(TimezoneOffset)]; INVALID); + check!("Z", [fix!(TimezoneOffsetZ)]; offset: 0); + check!("z", [fix!(TimezoneOffsetZ)]; offset: 0); + check!("Y", [fix!(TimezoneOffsetZ)]; INVALID); + check!("Zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0); + check!("zulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 0); + check!("+1234ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60); + check!("+12:34ulu", [fix!(TimezoneOffsetZ), lit!("ulu")]; offset: 754 * 60); + check!("Z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); + check!("z", [internal_fix!(TimezoneOffsetPermissive)]; offset: 0); + check!("+12:00", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60); + check!("+12", [internal_fix!(TimezoneOffsetPermissive)]; offset: 12 * 60 * 60); + check!("???", [fix!(TimezoneName)]; BAD_FORMAT); // not allowed + + // some practical examples + check!("2015-02-04T14:37:05+09:00", + [num!(Year), lit!("-"), num!(Month), lit!("-"), num!(Day), lit!("T"), + num!(Hour), lit!(":"), num!(Minute), lit!(":"), num!(Second), fix!(TimezoneOffset)]; + year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2, + minute: 37, second: 5, offset: 32400); + check!("20150204143705567", + [num!(Year), num!(Month), num!(Day), + num!(Hour), num!(Minute), num!(Second), internal_fix!(Nanosecond3NoDot)]; + year: 2015, month: 2, day: 4, hour_div_12: 1, hour_mod_12: 2, + minute: 37, second: 5, nanosecond: 567000000); + check!("Mon, 10 Jun 2013 09:32:37 GMT", + [fix!(ShortWeekdayName), lit!(","), sp!(" "), num!(Day), sp!(" "), + fix!(ShortMonthName), sp!(" "), num!(Year), sp!(" "), num!(Hour), lit!(":"), + num!(Minute), lit!(":"), num!(Second), sp!(" "), lit!("GMT")]; + year: 2013, month: 6, day: 10, weekday: Weekday::Mon, + hour_div_12: 0, hour_mod_12: 9, minute: 32, second: 37); + check!("20060102150405", + [num!(Year), num!(Month), num!(Day), num!(Hour), num!(Minute), num!(Second)]; + year: 2006, month: 1, day: 2, hour_div_12: 1, hour_mod_12: 3, minute: 4, second: 5); + check!("3:14PM", + [num!(Hour12), lit!(":"), num!(Minute), fix!(LowerAmPm)]; + hour_div_12: 1, hour_mod_12: 3, minute: 14); + check!("12345678901234.56789", + [num!(Timestamp), lit!("."), num!(Nanosecond)]; + nanosecond: 56_789, timestamp: 12_345_678_901_234); + check!("12345678901234.56789", + [num!(Timestamp), fix!(Nanosecond)]; + nanosecond: 567_890_000, timestamp: 12_345_678_901_234); +} + +#[cfg(test)] +#[test] +fn test_rfc2822() { + use DateTime; + use offset::FixedOffset; + use super::*; + use super::NOT_ENOUGH; + + // Test data - (input, Ok(expected result after parse and format) or Err(error code)) + let testdates = [ + ("Tue, 20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // normal case + ("20 Jan 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // no day of week + ("20 JAN 2015 17:35:20 -0800", Ok("Tue, 20 Jan 2015 17:35:20 -0800")), // upper case month + ("Tue, 20 Jan 2015 17:35 -0800", Ok("Tue, 20 Jan 2015 17:35:00 -0800")), // no second + ("11 Sep 2001 09:45:00 EST", Ok("Tue, 11 Sep 2001 09:45:00 -0500")), + ("30 Feb 2015 17:35:20 -0800", Err(OUT_OF_RANGE)), // bad day of month + ("Tue, 20 Jan 2015", Err(TOO_SHORT)), // omitted fields + ("Tue, 20 Avr 2015 17:35:20 -0800", Err(INVALID)), // bad month name + ("Tue, 20 Jan 2015 25:35:20 -0800", Err(OUT_OF_RANGE)), // bad hour + ("Tue, 20 Jan 2015 7:35:20 -0800", Err(INVALID)), // bad # of digits in hour + ("Tue, 20 Jan 2015 17:65:20 -0800", Err(OUT_OF_RANGE)), // bad minute + ("Tue, 20 Jan 2015 17:35:90 -0800", Err(OUT_OF_RANGE)), // bad second + ("Tue, 20 Jan 2015 17:35:20 -0890", Err(OUT_OF_RANGE)), // bad offset + ("6 Jun 1944 04:00:00Z", Err(INVALID)), // bad offset (zulu not allowed) + ("Tue, 20 Jan 2015 17:35:20 HAS", Err(NOT_ENOUGH)) // bad named time zone + ]; + + fn rfc2822_to_datetime(date: &str) -> ParseResult> { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter().cloned())); + parsed.to_datetime() + } + + fn fmt_rfc2822_datetime(dt: DateTime) -> String { + dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter().cloned()).to_string() + } + + // Test against test data above + for &(date, checkdate) in testdates.iter() { + let d = rfc2822_to_datetime(date); // parse a date + let dt = match d { // did we get a value? + Ok(dt) => Ok(fmt_rfc2822_datetime(dt)), // yes, go on + Err(e) => Err(e), // otherwise keep an error for the comparison + }; + if dt != checkdate.map(|s| s.to_string()) { // check for expected result + panic!("Date conversion failed for {}\nReceived: {:?}\nExpected: {:?}", + date, dt, checkdate); + } + }; +} + + + +#[cfg(test)] +#[test] +fn parse_rfc850() { + use ::{Utc, TimeZone}; + + static RFC850_FMT: &'static str = "%A, %d-%b-%y %T GMT"; + + let dt_str = "Sunday, 06-Nov-94 08:49:37 GMT"; + let dt = Utc.ymd(1994, 11, 6).and_hms(8, 49, 37); + + // Check that the format is what we expect + assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str); + + // Check that it parses correctly + assert_eq!(Ok(dt), Utc.datetime_from_str("Sunday, 06-Nov-94 08:49:37 GMT", RFC850_FMT)); + + // Check that the rest of the weekdays parse correctly (this test originally failed because + // Sunday parsed incorrectly). + let testdates = [ + (Utc.ymd(1994, 11, 7).and_hms(8, 49, 37), "Monday, 07-Nov-94 08:49:37 GMT"), + (Utc.ymd(1994, 11, 8).and_hms(8, 49, 37), "Tuesday, 08-Nov-94 08:49:37 GMT"), + (Utc.ymd(1994, 11, 9).and_hms(8, 49, 37), "Wednesday, 09-Nov-94 08:49:37 GMT"), + (Utc.ymd(1994, 11, 10).and_hms(8, 49, 37), "Thursday, 10-Nov-94 08:49:37 GMT"), + (Utc.ymd(1994, 11, 11).and_hms(8, 49, 37), "Friday, 11-Nov-94 08:49:37 GMT"), + (Utc.ymd(1994, 11, 12).and_hms(8, 49, 37), "Saturday, 12-Nov-94 08:49:37 GMT"), + ]; + + for val in &testdates { + assert_eq!(Ok(val.0), Utc.datetime_from_str(val.1, RFC850_FMT)); + } +} + +#[cfg(test)] +#[test] +fn test_rfc3339() { + use DateTime; + use offset::FixedOffset; + use super::*; + + // Test data - (input, Ok(expected result after parse and format) or Err(error code)) + let testdates = [ + ("2015-01-20T17:35:20-08:00", Ok("2015-01-20T17:35:20-08:00")), // normal case + ("1944-06-06T04:04:00Z", Ok("1944-06-06T04:04:00+00:00")), // D-day + ("2001-09-11T09:45:00-08:00", Ok("2001-09-11T09:45:00-08:00")), + ("2015-01-20T17:35:20.001-08:00", Ok("2015-01-20T17:35:20.001-08:00")), + ("2015-01-20T17:35:20.000031-08:00", Ok("2015-01-20T17:35:20.000031-08:00")), + ("2015-01-20T17:35:20.000000004-08:00", Ok("2015-01-20T17:35:20.000000004-08:00")), + ("2015-01-20T17:35:20.000000000452-08:00", Ok("2015-01-20T17:35:20-08:00")), // too small + ("2015-02-30T17:35:20-08:00", Err(OUT_OF_RANGE)), // bad day of month + ("2015-01-20T25:35:20-08:00", Err(OUT_OF_RANGE)), // bad hour + ("2015-01-20T17:65:20-08:00", Err(OUT_OF_RANGE)), // bad minute + ("2015-01-20T17:35:90-08:00", Err(OUT_OF_RANGE)), // bad second + ("2015-01-20T17:35:20-24:00", Err(OUT_OF_RANGE)), // bad offset + ]; + + fn rfc3339_to_datetime(date: &str) -> ParseResult> { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter().cloned())); + parsed.to_datetime() + } + + fn fmt_rfc3339_datetime(dt: DateTime) -> String { + dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter().cloned()).to_string() + } + + // Test against test data above + for &(date, checkdate) in testdates.iter() { + let d = rfc3339_to_datetime(date); // parse a date + let dt = match d { // did we get a value? + Ok(dt) => Ok(fmt_rfc3339_datetime(dt)), // yes, go on + Err(e) => Err(e), // otherwise keep an error for the comparison + }; + if dt != checkdate.map(|s| s.to_string()) { // check for expected result + panic!("Date conversion failed for {}\nReceived: {:?}\nExpected: {:?}", + date, dt, checkdate); + } + }; +} + diff --git a/chrono/src/format/parsed.rs b/chrono/src/format/parsed.rs new file mode 100644 index 000000000..7b9708d07 --- /dev/null +++ b/chrono/src/format/parsed.rs @@ -0,0 +1,1088 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! A collection of parsed date and time items. +//! They can be constructed incrementally while being checked for consistency. + +use num_traits::ToPrimitive; +use oldtime::Duration as OldDuration; + +use {Datelike, Timelike}; +use Weekday; +use div::div_rem; +use offset::{TimeZone, Offset, LocalResult, FixedOffset}; +use naive::{NaiveDate, NaiveTime, NaiveDateTime}; +use DateTime; +use super::{ParseResult, OUT_OF_RANGE, IMPOSSIBLE, NOT_ENOUGH}; + +/// Parsed parts of date and time. There are two classes of methods: +/// +/// - `set_*` methods try to set given field(s) while checking for the consistency. +/// It may or may not check for the range constraint immediately (for efficiency reasons). +/// +/// - `to_*` methods try to make a concrete date and time value out of set fields. +/// It fully checks any remaining out-of-range conditions and inconsistent/impossible fields. +#[allow(missing_copy_implementations)] +#[derive(Clone, PartialEq, Debug)] +pub struct Parsed { + /// Year. + /// + /// This can be negative unlike [`year_div_100`](#structfield.year_div_100) + /// and [`year_mod_100`](#structfield.year_mod_100) fields. + pub year: Option, + + /// Year divided by 100. Implies that the year is >= 1 BCE when set. + /// + /// Due to the common usage, if this field is missing but + /// [`year_mod_100`](#structfield.year_mod_100) is present, + /// it is inferred to 19 when `year_mod_100 >= 70` and 20 otherwise. + pub year_div_100: Option, + + /// Year modulo 100. Implies that the year is >= 1 BCE when set. + pub year_mod_100: Option, + + /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date). + /// + /// This can be negative unlike [`isoyear_div_100`](#structfield.isoyear_div_100) and + /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) fields. + pub isoyear: Option, + + /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), divided by 100. + /// Implies that the year is >= 1 BCE when set. + /// + /// Due to the common usage, if this field is missing but + /// [`isoyear_mod_100`](#structfield.isoyear_mod_100) is present, + /// it is inferred to 19 when `isoyear_mod_100 >= 70` and 20 otherwise. + pub isoyear_div_100: Option, + + /// Year in the [ISO week date](../naive/struct.NaiveDate.html#week-date), modulo 100. + /// Implies that the year is >= 1 BCE when set. + pub isoyear_mod_100: Option, + + /// Month (1--12). + pub month: Option, + + /// Week number, where the week 1 starts at the first Sunday of January + /// (0--53, 1--53 or 1--52 depending on the year). + pub week_from_sun: Option, + + /// Week number, where the week 1 starts at the first Monday of January + /// (0--53, 1--53 or 1--52 depending on the year). + pub week_from_mon: Option, + + /// [ISO week number](../naive/struct.NaiveDate.html#week-date) + /// (1--52 or 1--53 depending on the year). + pub isoweek: Option, + + /// Day of the week. + pub weekday: Option, + + /// Day of the year (1--365 or 1--366 depending on the year). + pub ordinal: Option, + + /// Day of the month (1--28, 1--29, 1--30 or 1--31 depending on the month). + pub day: Option, + + /// Hour number divided by 12 (0--1). 0 indicates AM and 1 indicates PM. + pub hour_div_12: Option, + + /// Hour number modulo 12 (0--11). + pub hour_mod_12: Option, + + /// Minute number (0--59). + pub minute: Option, + + /// Second number (0--60, accounting for leap seconds). + pub second: Option, + + /// The number of nanoseconds since the whole second (0--999,999,999). + pub nanosecond: Option, + + /// The number of non-leap seconds since the midnight UTC on January 1, 1970. + /// + /// This can be off by one if [`second`](#structfield.second) is 60 (a leap second). + pub timestamp: Option, + + /// Offset from the local time to UTC, in seconds. + pub offset: Option, + + /// A dummy field to make this type not fully destructible (required for API stability). + _dummy: (), +} + +/// Checks if `old` is either empty or has the same value to `new` (i.e. "consistent"), +/// and if it is empty, set `old` to `new` as well. +fn set_if_consistent(old: &mut Option, new: T) -> ParseResult<()> { + if let Some(ref old) = *old { + if *old == new {Ok(())} else {Err(IMPOSSIBLE)} + } else { + *old = Some(new); + Ok(()) + } +} + +impl Default for Parsed { + fn default() -> Parsed { + Parsed { + year: None, year_div_100: None, year_mod_100: None, isoyear: None, + isoyear_div_100: None, isoyear_mod_100: None, month: None, + week_from_sun: None, week_from_mon: None, isoweek: None, weekday: None, + ordinal: None, day: None, hour_div_12: None, hour_mod_12: None, minute: None, + second: None, nanosecond: None, timestamp: None, offset: None, + _dummy: (), + } + } +} + +impl Parsed { + /// Returns the initial value of parsed parts. + pub fn new() -> Parsed { + Parsed::default() + } + + /// Tries to set the [`year`](#structfield.year) field from given value. + pub fn set_year(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.year, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. + pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> { + if value < 0 { return Err(OUT_OF_RANGE); } + set_if_consistent(&mut self.year_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. + pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> { + if value < 0 { return Err(OUT_OF_RANGE); } + set_if_consistent(&mut self.year_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. + pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.isoyear, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. + pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> { + if value < 0 { return Err(OUT_OF_RANGE); } + set_if_consistent(&mut self.isoyear_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value. + pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> { + if value < 0 { return Err(OUT_OF_RANGE); } + set_if_consistent(&mut self.isoyear_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`month`](#structfield.month) field from given value. + pub fn set_month(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.month, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value. + pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.week_from_sun, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value. + pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.week_from_mon, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. + pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.isoweek, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`weekday`](#structfield.weekday) field from given value. + pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> { + set_if_consistent(&mut self.weekday, value) + } + + /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. + pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.ordinal, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`day`](#structfield.day) field from given value. + pub fn set_day(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.day, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. + /// (`false` for AM, `true` for PM) + pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> { + set_if_consistent(&mut self.hour_div_12, if value {1} else {0}) + } + + /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from + /// given hour number in 12-hour clocks. + pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> { + if value < 1 || value > 12 { return Err(OUT_OF_RANGE); } + set_if_consistent(&mut self.hour_mod_12, value as u32 % 12) + } + + /// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and + /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. + pub fn set_hour(&mut self, value: i64) -> ParseResult<()> { + let v = try!(value.to_u32().ok_or(OUT_OF_RANGE)); + try!(set_if_consistent(&mut self.hour_div_12, v / 12)); + try!(set_if_consistent(&mut self.hour_mod_12, v % 12)); + Ok(()) + } + + /// Tries to set the [`minute`](#structfield.minute) field from given value. + pub fn set_minute(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.minute, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`second`](#structfield.second) field from given value. + pub fn set_second(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.second, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. + pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.nanosecond, try!(value.to_u32().ok_or(OUT_OF_RANGE))) + } + + /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. + pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.timestamp, value) + } + + /// Tries to set the [`offset`](#structfield.offset) field from given value. + pub fn set_offset(&mut self, value: i64) -> ParseResult<()> { + set_if_consistent(&mut self.offset, try!(value.to_i32().ok_or(OUT_OF_RANGE))) + } + + /// Returns a parsed naive date out of given fields. + /// + /// This method is able to determine the date from given subset of fields: + /// + /// - Year, month, day. + /// - Year, day of the year (ordinal). + /// - Year, week number counted from Sunday or Monday, day of the week. + /// - ISO week date. + /// + /// Gregorian year and ISO week date year can have their century number (`*_div_100`) omitted, + /// the two-digit year is used to guess the century number then. + pub fn to_naive_date(&self) -> ParseResult { + fn resolve_year(y: Option, q: Option, + r: Option) -> ParseResult> { + match (y, q, r) { + // if there is no further information, simply return the given full year. + // this is a common case, so let's avoid division here. + (y, None, None) => Ok(y), + + // if there is a full year *and* also quotient and/or modulo, + // check if present quotient and/or modulo is consistent to the full year. + // since the presence of those fields means a positive full year, + // we should filter a negative full year first. + (Some(y), q, r @ Some(0...99)) | (Some(y), q, r @ None) => { + if y < 0 { return Err(OUT_OF_RANGE); } + let (q_, r_) = div_rem(y, 100); + if q.unwrap_or(q_) == q_ && r.unwrap_or(r_) == r_ { + Ok(Some(y)) + } else { + Err(IMPOSSIBLE) + } + }, + + // the full year is missing but we have quotient and modulo. + // reconstruct the full year. make sure that the result is always positive. + (None, Some(q), Some(r @ 0...99)) => { + if q < 0 { return Err(OUT_OF_RANGE); } + let y = q.checked_mul(100).and_then(|v| v.checked_add(r)); + Ok(Some(try!(y.ok_or(OUT_OF_RANGE)))) + }, + + // we only have modulo. try to interpret a modulo as a conventional two-digit year. + // note: we are affected by Rust issue #18060. avoid multiple range patterns. + (None, None, Some(r @ 0...99)) => Ok(Some(r + if r < 70 {2000} else {1900})), + + // otherwise it is an out-of-bound or insufficient condition. + (None, Some(_), None) => Err(NOT_ENOUGH), + (_, _, Some(_)) => Err(OUT_OF_RANGE), + } + } + + let given_year = + try!(resolve_year(self.year, self.year_div_100, self.year_mod_100)); + let given_isoyear = + try!(resolve_year(self.isoyear, self.isoyear_div_100, self.isoyear_mod_100)); + + // verify the normal year-month-day date. + let verify_ymd = |date: NaiveDate| { + let year = date.year(); + let (year_div_100, year_mod_100) = if year >= 0 { + let (q, r) = div_rem(year, 100); + (Some(q), Some(r)) + } else { + (None, None) // they should be empty to be consistent + }; + let month = date.month(); + let day = date.day(); + (self.year.unwrap_or(year) == year && + self.year_div_100.or(year_div_100) == year_div_100 && + self.year_mod_100.or(year_mod_100) == year_mod_100 && + self.month.unwrap_or(month) == month && + self.day.unwrap_or(day) == day) + }; + + // verify the ISO week date. + let verify_isoweekdate = |date: NaiveDate| { + let week = date.iso_week(); + let isoyear = week.year(); + let isoweek = week.week(); + let weekday = date.weekday(); + let (isoyear_div_100, isoyear_mod_100) = if isoyear >= 0 { + let (q, r) = div_rem(isoyear, 100); + (Some(q), Some(r)) + } else { + (None, None) // they should be empty to be consistent + }; + (self.isoyear.unwrap_or(isoyear) == isoyear && + self.isoyear_div_100.or(isoyear_div_100) == isoyear_div_100 && + self.isoyear_mod_100.or(isoyear_mod_100) == isoyear_mod_100 && + self.isoweek.unwrap_or(isoweek) == isoweek && + self.weekday.unwrap_or(weekday) == weekday) + }; + + // verify the ordinal and other (non-ISO) week dates. + let verify_ordinal = |date: NaiveDate| { + let ordinal = date.ordinal(); + let weekday = date.weekday(); + let week_from_sun = (ordinal as i32 - weekday.num_days_from_sunday() as i32 + 7) / 7; + let week_from_mon = (ordinal as i32 - weekday.num_days_from_monday() as i32 + 7) / 7; + (self.ordinal.unwrap_or(ordinal) == ordinal && + self.week_from_sun.map_or(week_from_sun, |v| v as i32) == week_from_sun && + self.week_from_mon.map_or(week_from_mon, |v| v as i32) == week_from_mon) + }; + + // test several possibilities. + // tries to construct a full `NaiveDate` as much as possible, then verifies that + // it is consistent with other given fields. + let (verified, parsed_date) = match (given_year, given_isoyear, self) { + (Some(year), _, &Parsed { month: Some(month), day: Some(day), .. }) => { + // year, month, day + let date = try!(NaiveDate::from_ymd_opt(year, month, day).ok_or(OUT_OF_RANGE)); + (verify_isoweekdate(date) && verify_ordinal(date), date) + }, + + (Some(year), _, &Parsed { ordinal: Some(ordinal), .. }) => { + // year, day of the year + let date = try!(NaiveDate::from_yo_opt(year, ordinal).ok_or(OUT_OF_RANGE)); + (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) + }, + + (Some(year), _, &Parsed { week_from_sun: Some(week_from_sun), + weekday: Some(weekday), .. }) => { + // year, week (starting at 1st Sunday), day of the week + let newyear = try!(NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)); + let firstweek = match newyear.weekday() { + Weekday::Sun => 0, + Weekday::Mon => 6, + Weekday::Tue => 5, + Weekday::Wed => 4, + Weekday::Thu => 3, + Weekday::Fri => 2, + Weekday::Sat => 1, + }; + + // `firstweek+1`-th day of January is the beginning of the week 1. + if week_from_sun > 53 { return Err(OUT_OF_RANGE); } // can it overflow? + let ndays = firstweek + (week_from_sun as i32 - 1) * 7 + + weekday.num_days_from_sunday() as i32; + let date = try!(newyear.checked_add_signed(OldDuration::days(i64::from(ndays))) + .ok_or(OUT_OF_RANGE)); + if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error + + (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) + }, + + (Some(year), _, &Parsed { week_from_mon: Some(week_from_mon), + weekday: Some(weekday), .. }) => { + // year, week (starting at 1st Monday), day of the week + let newyear = try!(NaiveDate::from_yo_opt(year, 1).ok_or(OUT_OF_RANGE)); + let firstweek = match newyear.weekday() { + Weekday::Sun => 1, + Weekday::Mon => 0, + Weekday::Tue => 6, + Weekday::Wed => 5, + Weekday::Thu => 4, + Weekday::Fri => 3, + Weekday::Sat => 2, + }; + + // `firstweek+1`-th day of January is the beginning of the week 1. + if week_from_mon > 53 { return Err(OUT_OF_RANGE); } // can it overflow? + let ndays = firstweek + (week_from_mon as i32 - 1) * 7 + + weekday.num_days_from_monday() as i32; + let date = try!(newyear.checked_add_signed(OldDuration::days(i64::from(ndays))) + .ok_or(OUT_OF_RANGE)); + if date.year() != year { return Err(OUT_OF_RANGE); } // early exit for correct error + + (verify_ymd(date) && verify_isoweekdate(date) && verify_ordinal(date), date) + }, + + (_, Some(isoyear), &Parsed { isoweek: Some(isoweek), weekday: Some(weekday), .. }) => { + // ISO year, week, day of the week + let date = NaiveDate::from_isoywd_opt(isoyear, isoweek, weekday); + let date = try!(date.ok_or(OUT_OF_RANGE)); + (verify_ymd(date) && verify_ordinal(date), date) + }, + + (_, _, _) => return Err(NOT_ENOUGH) + }; + + if verified { + Ok(parsed_date) + } else { + Err(IMPOSSIBLE) + } + } + + /// Returns a parsed naive time out of given fields. + /// + /// This method is able to determine the time from given subset of fields: + /// + /// - Hour, minute. (second and nanosecond assumed to be 0) + /// - Hour, minute, second. (nanosecond assumed to be 0) + /// - Hour, minute, second, nanosecond. + /// + /// It is able to handle leap seconds when given second is 60. + pub fn to_naive_time(&self) -> ParseResult { + let hour_div_12 = match self.hour_div_12 { + Some(v @ 0...1) => v, + Some(_) => return Err(OUT_OF_RANGE), + None => return Err(NOT_ENOUGH), + }; + let hour_mod_12 = match self.hour_mod_12 { + Some(v @ 0...11) => v, + Some(_) => return Err(OUT_OF_RANGE), + None => return Err(NOT_ENOUGH), + }; + let hour = hour_div_12 * 12 + hour_mod_12; + + let minute = match self.minute { + Some(v @ 0...59) => v, + Some(_) => return Err(OUT_OF_RANGE), + None => return Err(NOT_ENOUGH), + }; + + // we allow omitting seconds or nanoseconds, but they should be in the range. + let (second, mut nano) = match self.second.unwrap_or(0) { + v @ 0...59 => (v, 0), + 60 => (59, 1_000_000_000), + _ => return Err(OUT_OF_RANGE), + }; + nano += match self.nanosecond { + Some(v @ 0...999_999_999) if self.second.is_some() => v, + Some(0...999_999_999) => return Err(NOT_ENOUGH), // second is missing + Some(_) => return Err(OUT_OF_RANGE), + None => 0, + }; + + NaiveTime::from_hms_nano_opt(hour, minute, second, nano).ok_or(OUT_OF_RANGE) + } + + /// Returns a parsed naive date and time out of given fields, + /// except for the [`offset`](#structfield.offset) field (assumed to have a given value). + /// This is required for parsing a local time or other known-timezone inputs. + /// + /// This method is able to determine the combined date and time + /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field. + /// Either way those fields have to be consistent to each other. + pub fn to_naive_datetime_with_offset(&self, offset: i32) -> ParseResult { + let date = self.to_naive_date(); + let time = self.to_naive_time(); + if let (Ok(date), Ok(time)) = (date, time) { + let datetime = date.and_time(time); + + // verify the timestamp field if any + // the following is safe, `timestamp` is very limited in range + let timestamp = datetime.timestamp() - i64::from(offset); + if let Some(given_timestamp) = self.timestamp { + // if `datetime` represents a leap second, it might be off by one second. + if given_timestamp != timestamp && + !(datetime.nanosecond() >= 1_000_000_000 && given_timestamp == timestamp + 1) { + return Err(IMPOSSIBLE); + } + } + + Ok(datetime) + } else if let Some(timestamp) = self.timestamp { + use super::ParseError as PE; + use super::ParseErrorKind::{OutOfRange, Impossible}; + + // if date and time is problematic already, there is no point proceeding. + // we at least try to give a correct error though. + match (date, time) { + (Err(PE(OutOfRange)), _) | (_, Err(PE(OutOfRange))) => return Err(OUT_OF_RANGE), + (Err(PE(Impossible)), _) | (_, Err(PE(Impossible))) => return Err(IMPOSSIBLE), + (_, _) => {} // one of them is insufficient + } + + // reconstruct date and time fields from timestamp + let ts = try!(timestamp.checked_add(i64::from(offset)).ok_or(OUT_OF_RANGE)); + let datetime = NaiveDateTime::from_timestamp_opt(ts, 0); + let mut datetime = try!(datetime.ok_or(OUT_OF_RANGE)); + + // fill year, ordinal, hour, minute and second fields from timestamp. + // if existing fields are consistent, this will allow the full date/time reconstruction. + let mut parsed = self.clone(); + if parsed.second == Some(60) { + // `datetime.second()` cannot be 60, so this is the only case for a leap second. + match datetime.second() { + // it's okay, just do not try to overwrite the existing field. + 59 => {} + // `datetime` is known to be off by one second. + 0 => { datetime -= OldDuration::seconds(1); } + // otherwise it is impossible. + _ => return Err(IMPOSSIBLE) + } + // ...and we have the correct candidates for other fields. + } else { + try!(parsed.set_second(i64::from(datetime.second()))); + } + try!(parsed.set_year (i64::from(datetime.year()))); + try!(parsed.set_ordinal(i64::from(datetime.ordinal()))); // more efficient than ymd + try!(parsed.set_hour (i64::from(datetime.hour()))); + try!(parsed.set_minute (i64::from(datetime.minute()))); + + // validate other fields (e.g. week) and return + let date = try!(parsed.to_naive_date()); + let time = try!(parsed.to_naive_time()); + Ok(date.and_time(time)) + } else { + // reproduce the previous error(s) + try!(date); + try!(time); + unreachable!() + } + } + + /// Returns a parsed fixed time zone offset out of given fields. + pub fn to_fixed_offset(&self) -> ParseResult { + self.offset.and_then(FixedOffset::east_opt).ok_or(OUT_OF_RANGE) + } + + /// Returns a parsed timezone-aware date and time out of given fields. + /// + /// This method is able to determine the combined date and time + /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field, + /// plus a time zone offset. + /// Either way those fields have to be consistent to each other. + pub fn to_datetime(&self) -> ParseResult> { + let offset = try!(self.offset.ok_or(NOT_ENOUGH)); + let datetime = try!(self.to_naive_datetime_with_offset(offset)); + let offset = try!(FixedOffset::east_opt(offset).ok_or(OUT_OF_RANGE)); + match offset.from_local_datetime(&datetime) { + LocalResult::None => Err(IMPOSSIBLE), + LocalResult::Single(t) => Ok(t), + LocalResult::Ambiguous(..) => Err(NOT_ENOUGH), + } + } + + /// Returns a parsed timezone-aware date and time out of given fields, + /// with an additional `TimeZone` used to interpret and validate the local date. + /// + /// This method is able to determine the combined date and time + /// from date and time fields or a single [`timestamp`](#structfield.timestamp) field, + /// plus a time zone offset. + /// Either way those fields have to be consistent to each other. + /// If parsed fields include an UTC offset, it also has to be consistent to + /// [`offset`](#structfield.offset). + pub fn to_datetime_with_timezone(&self, tz: &Tz) -> ParseResult> { + // if we have `timestamp` specified, guess an offset from that. + let mut guessed_offset = 0; + if let Some(timestamp) = self.timestamp { + // make a naive `DateTime` from given timestamp and (if any) nanosecond. + // an empty `nanosecond` is always equal to zero, so missing nanosecond is fine. + let nanosecond = self.nanosecond.unwrap_or(0); + let dt = NaiveDateTime::from_timestamp_opt(timestamp, nanosecond); + let dt = try!(dt.ok_or(OUT_OF_RANGE)); + guessed_offset = tz.offset_from_utc_datetime(&dt).fix().local_minus_utc(); + } + + // checks if the given `DateTime` has a consistent `Offset` with given `self.offset`. + let check_offset = |dt: &DateTime| { + if let Some(offset) = self.offset { + dt.offset().fix().local_minus_utc() == offset + } else { + true + } + }; + + // `guessed_offset` should be correct when `self.timestamp` is given. + // it will be 0 otherwise, but this is fine as the algorithm ignores offset for that case. + let datetime = try!(self.to_naive_datetime_with_offset(guessed_offset)); + match tz.from_local_datetime(&datetime) { + LocalResult::None => Err(IMPOSSIBLE), + LocalResult::Single(t) => if check_offset(&t) {Ok(t)} else {Err(IMPOSSIBLE)}, + LocalResult::Ambiguous(min, max) => { + // try to disambiguate two possible local dates by offset. + match (check_offset(&min), check_offset(&max)) { + (false, false) => Err(IMPOSSIBLE), + (false, true) => Ok(max), + (true, false) => Ok(min), + (true, true) => Err(NOT_ENOUGH), + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::Parsed; + use super::super::{OUT_OF_RANGE, IMPOSSIBLE, NOT_ENOUGH}; + use Datelike; + use Weekday::*; + use naive::{MIN_DATE, MAX_DATE, NaiveDate, NaiveTime}; + use offset::{TimeZone, Utc, FixedOffset}; + + #[test] + fn test_parsed_set_fields() { + // year*, isoyear* + let mut p = Parsed::new(); + assert_eq!(p.set_year(1987), Ok(())); + assert_eq!(p.set_year(1986), Err(IMPOSSIBLE)); + assert_eq!(p.set_year(1988), Err(IMPOSSIBLE)); + assert_eq!(p.set_year(1987), Ok(())); + assert_eq!(p.set_year_div_100(20), Ok(())); // independent to `year` + assert_eq!(p.set_year_div_100(21), Err(IMPOSSIBLE)); + assert_eq!(p.set_year_div_100(19), Err(IMPOSSIBLE)); + assert_eq!(p.set_year_mod_100(37), Ok(())); // ditto + assert_eq!(p.set_year_mod_100(38), Err(IMPOSSIBLE)); + assert_eq!(p.set_year_mod_100(36), Err(IMPOSSIBLE)); + + let mut p = Parsed::new(); + assert_eq!(p.set_year(0), Ok(())); + assert_eq!(p.set_year_div_100(0), Ok(())); + assert_eq!(p.set_year_mod_100(0), Ok(())); + + let mut p = Parsed::new(); + assert_eq!(p.set_year_div_100(-1), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year_mod_100(-1), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year(-1), Ok(())); + assert_eq!(p.set_year(-2), Err(IMPOSSIBLE)); + assert_eq!(p.set_year(0), Err(IMPOSSIBLE)); + + let mut p = Parsed::new(); + assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE)); + assert_eq!(p.set_year_div_100(8), Ok(())); + assert_eq!(p.set_year_div_100(0x1_0000_0008), Err(OUT_OF_RANGE)); + + // month, week*, isoweek, ordinal, day, minute, second, nanosecond, offset + let mut p = Parsed::new(); + assert_eq!(p.set_month(7), Ok(())); + assert_eq!(p.set_month(1), Err(IMPOSSIBLE)); + assert_eq!(p.set_month(6), Err(IMPOSSIBLE)); + assert_eq!(p.set_month(8), Err(IMPOSSIBLE)); + assert_eq!(p.set_month(12), Err(IMPOSSIBLE)); + + let mut p = Parsed::new(); + assert_eq!(p.set_month(8), Ok(())); + assert_eq!(p.set_month(0x1_0000_0008), Err(OUT_OF_RANGE)); + + // hour + let mut p = Parsed::new(); + assert_eq!(p.set_hour(12), Ok(())); + assert_eq!(p.set_hour(11), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(13), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(12), Ok(())); + assert_eq!(p.set_ampm(false), Err(IMPOSSIBLE)); + assert_eq!(p.set_ampm(true), Ok(())); + assert_eq!(p.set_hour12(12), Ok(())); + assert_eq!(p.set_hour12(0), Err(OUT_OF_RANGE)); // requires canonical representation + assert_eq!(p.set_hour12(1), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour12(11), Err(IMPOSSIBLE)); + + let mut p = Parsed::new(); + assert_eq!(p.set_ampm(true), Ok(())); + assert_eq!(p.set_hour12(7), Ok(())); + assert_eq!(p.set_hour(7), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(18), Err(IMPOSSIBLE)); + assert_eq!(p.set_hour(19), Ok(())); + + // timestamp + let mut p = Parsed::new(); + assert_eq!(p.set_timestamp(1_234_567_890), Ok(())); + assert_eq!(p.set_timestamp(1_234_567_889), Err(IMPOSSIBLE)); + assert_eq!(p.set_timestamp(1_234_567_891), Err(IMPOSSIBLE)); + } + + #[test] + fn test_parsed_to_naive_date() { + macro_rules! parse { + ($($k:ident: $v:expr),*) => ( + Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_date() + ) + } + + let ymd = |y,m,d| Ok(NaiveDate::from_ymd(y, m, d)); + + // ymd: omission of fields + assert_eq!(parse!(), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 1984), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 1984, month: 1), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 1984, month: 1, day: 2), ymd(1984, 1, 2)); + assert_eq!(parse!(year: 1984, day: 2), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 19), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 1, day: 2), ymd(1984, 1, 2)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, day: 2), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_div_100: 19, month: 1, day: 2), Err(NOT_ENOUGH)); + assert_eq!(parse!(year_mod_100: 70, month: 1, day: 2), ymd(1970, 1, 2)); + assert_eq!(parse!(year_mod_100: 69, month: 1, day: 2), ymd(2069, 1, 2)); + + // ymd: out-of-range conditions + assert_eq!(parse!(year_div_100: 19, year_mod_100: 84, month: 2, day: 29), + ymd(1984, 2, 29)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 83, month: 2, day: 29), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 83, month: 13, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 31), + ymd(1983, 12, 31)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 32), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 83, month: 12, day: 0), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: 100, month: 1, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 19, year_mod_100: -1, month: 1, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year_div_100: 0, year_mod_100: 0, month: 1, day: 1), + ymd(0, 1, 1)); + assert_eq!(parse!(year_div_100: -1, year_mod_100: 42, month: 1, day: 1), + Err(OUT_OF_RANGE)); + let max_year = MAX_DATE.year(); + assert_eq!(parse!(year_div_100: max_year / 100, + year_mod_100: max_year % 100, month: 1, day: 1), + ymd(max_year, 1, 1)); + assert_eq!(parse!(year_div_100: (max_year + 1) / 100, + year_mod_100: (max_year + 1) % 100, month: 1, day: 1), + Err(OUT_OF_RANGE)); + + // ymd: conflicting inputs + assert_eq!(parse!(year: 1984, year_div_100: 19, month: 1, day: 1), ymd(1984, 1, 1)); + assert_eq!(parse!(year: 1984, year_div_100: 20, month: 1, day: 1), Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 1984, year_mod_100: 84, month: 1, day: 1), ymd(1984, 1, 1)); + assert_eq!(parse!(year: 1984, year_mod_100: 83, month: 1, day: 1), Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 1984, year_div_100: 19, year_mod_100: 84, month: 1, day: 1), + ymd(1984, 1, 1)); + assert_eq!(parse!(year: 1984, year_div_100: 18, year_mod_100: 94, month: 1, day: 1), + Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 1984, year_div_100: 18, year_mod_100: 184, month: 1, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: -1, year_div_100: 0, year_mod_100: -1, month: 1, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: -1, year_div_100: -1, year_mod_100: 99, month: 1, day: 1), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: -1, year_div_100: 0, month: 1, day: 1), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: -1, year_mod_100: 99, month: 1, day: 1), Err(OUT_OF_RANGE)); + + // weekdates + assert_eq!(parse!(year: 2000, week_from_mon: 0), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2000, week_from_sun: 0), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2000, weekday: Sun), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Fri), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Fri), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sat), ymd(2000, 1, 1)); + assert_eq!(parse!(year: 2000, week_from_sun: 0, weekday: Sat), ymd(2000, 1, 1)); + assert_eq!(parse!(year: 2000, week_from_mon: 0, weekday: Sun), ymd(2000, 1, 2)); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sun), ymd(2000, 1, 2)); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Mon), ymd(2000, 1, 3)); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Mon), ymd(2000, 1, 3)); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sat), ymd(2000, 1, 8)); + assert_eq!(parse!(year: 2000, week_from_sun: 1, weekday: Sat), ymd(2000, 1, 8)); + assert_eq!(parse!(year: 2000, week_from_mon: 1, weekday: Sun), ymd(2000, 1, 9)); + assert_eq!(parse!(year: 2000, week_from_sun: 2, weekday: Sun), ymd(2000, 1, 9)); + assert_eq!(parse!(year: 2000, week_from_mon: 2, weekday: Mon), ymd(2000, 1, 10)); + assert_eq!(parse!(year: 2000, week_from_sun: 52, weekday: Sat), ymd(2000, 12, 30)); + assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Sun), ymd(2000, 12, 31)); + assert_eq!(parse!(year: 2000, week_from_sun: 53, weekday: Mon), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2000, week_from_sun: 0xffffffff, weekday: Mon), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2006, week_from_sun: 0, weekday: Sat), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2006, week_from_sun: 1, weekday: Sun), ymd(2006, 1, 1)); + + // weekdates: conflicting inputs + assert_eq!(parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sat), + ymd(2000, 1, 8)); + assert_eq!(parse!(year: 2000, week_from_mon: 1, week_from_sun: 2, weekday: Sun), + ymd(2000, 1, 9)); + assert_eq!(parse!(year: 2000, week_from_mon: 1, week_from_sun: 1, weekday: Sun), + Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 2000, week_from_mon: 2, week_from_sun: 2, weekday: Sun), + Err(IMPOSSIBLE)); + + // ISO weekdates + assert_eq!(parse!(isoyear: 2004, isoweek: 53), Err(NOT_ENOUGH)); + assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Fri), ymd(2004, 12, 31)); + assert_eq!(parse!(isoyear: 2004, isoweek: 53, weekday: Sat), ymd(2005, 1, 1)); + assert_eq!(parse!(isoyear: 2004, isoweek: 0xffffffff, weekday: Sat), Err(OUT_OF_RANGE)); + assert_eq!(parse!(isoyear: 2005, isoweek: 0, weekday: Thu), Err(OUT_OF_RANGE)); + assert_eq!(parse!(isoyear: 2005, isoweek: 5, weekday: Thu), ymd(2005, 2, 3)); + assert_eq!(parse!(isoyear: 2005, weekday: Thu), Err(NOT_ENOUGH)); + + // year and ordinal + assert_eq!(parse!(ordinal: 123), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2000, ordinal: 0), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2000, ordinal: 1), ymd(2000, 1, 1)); + assert_eq!(parse!(year: 2000, ordinal: 60), ymd(2000, 2, 29)); + assert_eq!(parse!(year: 2000, ordinal: 61), ymd(2000, 3, 1)); + assert_eq!(parse!(year: 2000, ordinal: 366), ymd(2000, 12, 31)); + assert_eq!(parse!(year: 2000, ordinal: 367), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2000, ordinal: 0xffffffff), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2100, ordinal: 0), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2100, ordinal: 1), ymd(2100, 1, 1)); + assert_eq!(parse!(year: 2100, ordinal: 59), ymd(2100, 2, 28)); + assert_eq!(parse!(year: 2100, ordinal: 60), ymd(2100, 3, 1)); + assert_eq!(parse!(year: 2100, ordinal: 365), ymd(2100, 12, 31)); + assert_eq!(parse!(year: 2100, ordinal: 366), Err(OUT_OF_RANGE)); + assert_eq!(parse!(year: 2100, ordinal: 0xffffffff), Err(OUT_OF_RANGE)); + + // more complex cases + assert_eq!(parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2015, isoweek: 1, + week_from_sun: 52, week_from_mon: 52, weekday: Wed), + ymd(2014, 12, 31)); + assert_eq!(parse!(year: 2014, month: 12, ordinal: 365, isoyear: 2015, isoweek: 1, + week_from_sun: 52, week_from_mon: 52), + ymd(2014, 12, 31)); + assert_eq!(parse!(year: 2014, month: 12, day: 31, ordinal: 365, isoyear: 2014, isoweek: 53, + week_from_sun: 52, week_from_mon: 52, weekday: Wed), + Err(IMPOSSIBLE)); // no ISO week date 2014-W53-3 + assert_eq!(parse!(year: 2012, isoyear: 2015, isoweek: 1, + week_from_sun: 52, week_from_mon: 52), + Err(NOT_ENOUGH)); // ambiguous (2014-12-29, 2014-12-30, 2014-12-31) + assert_eq!(parse!(year_div_100: 20, isoyear_mod_100: 15, ordinal: 366), + Err(NOT_ENOUGH)); // technically unique (2014-12-31) but Chrono gives up + } + + #[test] + fn test_parsed_to_naive_time() { + macro_rules! parse { + ($($k:ident: $v:expr),*) => ( + Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_time() + ) + } + + let hms = |h,m,s| Ok(NaiveTime::from_hms(h, m, s)); + let hmsn = |h,m,s,n| Ok(NaiveTime::from_hms_nano(h, m, s, n)); + + // omission of fields + assert_eq!(parse!(), Err(NOT_ENOUGH)); + assert_eq!(parse!(hour_div_12: 0), Err(NOT_ENOUGH)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1), Err(NOT_ENOUGH)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23), hms(1,23,0)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45), hms(1,23,45)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 45, + nanosecond: 678_901_234), + hmsn(1,23,45,678_901_234)); + assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 11, minute: 45, second: 6), hms(23,45,6)); + assert_eq!(parse!(hour_mod_12: 1, minute: 23), Err(NOT_ENOUGH)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, nanosecond: 456_789_012), + Err(NOT_ENOUGH)); + + // out-of-range conditions + assert_eq!(parse!(hour_div_12: 2, hour_mod_12: 0, minute: 0), Err(OUT_OF_RANGE)); + assert_eq!(parse!(hour_div_12: 1, hour_mod_12: 12, minute: 0), Err(OUT_OF_RANGE)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 60), Err(OUT_OF_RANGE)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 61), + Err(OUT_OF_RANGE)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 34, + nanosecond: 1_000_000_000), + Err(OUT_OF_RANGE)); + + // leap seconds + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60), + hmsn(1,23,59,1_000_000_000)); + assert_eq!(parse!(hour_div_12: 0, hour_mod_12: 1, minute: 23, second: 60, + nanosecond: 999_999_999), + hmsn(1,23,59,1_999_999_999)); + } + + #[test] + fn test_parsed_to_naive_datetime_with_offset() { + macro_rules! parse { + (offset = $offset:expr; $($k:ident: $v:expr),*) => ( + Parsed { $($k: Some($v),)* ..Parsed::new() }.to_naive_datetime_with_offset($offset) + ); + ($($k:ident: $v:expr),*) => (parse!(offset = 0; $($k: $v),*)) + } + + let ymdhms = |y,m,d,h,n,s| Ok(NaiveDate::from_ymd(y, m, d).and_hms(h, n, s)); + let ymdhmsn = + |y,m,d,h,n,s,nano| Ok(NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano)); + + // omission of fields + assert_eq!(parse!(), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2015, month: 1, day: 30, + hour_div_12: 1, hour_mod_12: 2, minute: 38), + ymdhms(2015,1,30, 14,38,0)); + assert_eq!(parse!(year: 1997, month: 1, day: 30, + hour_div_12: 1, hour_mod_12: 2, minute: 38, second: 5), + ymdhms(1997,1,30, 14,38,5)); + assert_eq!(parse!(year: 2012, ordinal: 34, hour_div_12: 0, hour_mod_12: 5, + minute: 6, second: 7, nanosecond: 890_123_456), + ymdhmsn(2012,2,3, 5,6,7,890_123_456)); + assert_eq!(parse!(timestamp: 0), ymdhms(1970,1,1, 0,0,0)); + assert_eq!(parse!(timestamp: 1, nanosecond: 0), ymdhms(1970,1,1, 0,0,1)); + assert_eq!(parse!(timestamp: 1, nanosecond: 1), ymdhmsn(1970,1,1, 0,0,1, 1)); + assert_eq!(parse!(timestamp: 1_420_000_000), ymdhms(2014,12,31, 4,26,40)); + assert_eq!(parse!(timestamp: -0x1_0000_0000), ymdhms(1833,11,24, 17,31,44)); + + // full fields + assert_eq!(parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31, + ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15, + isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed, + hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, + nanosecond: 12_345_678, timestamp: 1_420_000_000), + ymdhmsn(2014,12,31, 4,26,40,12_345_678)); + assert_eq!(parse!(year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31, + ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15, + isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed, + hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, + nanosecond: 12_345_678, timestamp: 1_419_999_999), + Err(IMPOSSIBLE)); + assert_eq!(parse!(offset = 32400; + year: 2014, year_div_100: 20, year_mod_100: 14, month: 12, day: 31, + ordinal: 365, isoyear: 2015, isoyear_div_100: 20, isoyear_mod_100: 15, + isoweek: 1, week_from_sun: 52, week_from_mon: 52, weekday: Wed, + hour_div_12: 0, hour_mod_12: 4, minute: 26, second: 40, + nanosecond: 12_345_678, timestamp: 1_419_967_600), + ymdhmsn(2014,12,31, 4,26,40,12_345_678)); + + // more timestamps + let max_days_from_year_1970 = + MAX_DATE.signed_duration_since(NaiveDate::from_ymd(1970,1,1)); + let year_0_from_year_1970 = + NaiveDate::from_ymd(0,1,1).signed_duration_since(NaiveDate::from_ymd(1970,1,1)); + let min_days_from_year_1970 = + MIN_DATE.signed_duration_since(NaiveDate::from_ymd(1970,1,1)); + assert_eq!(parse!(timestamp: min_days_from_year_1970.num_seconds()), + ymdhms(MIN_DATE.year(),1,1, 0,0,0)); + assert_eq!(parse!(timestamp: year_0_from_year_1970.num_seconds()), + ymdhms(0,1,1, 0,0,0)); + assert_eq!(parse!(timestamp: max_days_from_year_1970.num_seconds() + 86399), + ymdhms(MAX_DATE.year(),12,31, 23,59,59)); + + // leap seconds #1: partial fields + assert_eq!(parse!(second: 59, timestamp: 1_341_100_798), Err(IMPOSSIBLE)); + assert_eq!(parse!(second: 59, timestamp: 1_341_100_799), ymdhms(2012,6,30, 23,59,59)); + assert_eq!(parse!(second: 59, timestamp: 1_341_100_800), Err(IMPOSSIBLE)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_799), + ymdhmsn(2012,6,30, 23,59,59,1_000_000_000)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_800), + ymdhmsn(2012,6,30, 23,59,59,1_000_000_000)); + assert_eq!(parse!(second: 0, timestamp: 1_341_100_800), ymdhms(2012,7,1, 0,0,0)); + assert_eq!(parse!(second: 1, timestamp: 1_341_100_800), Err(IMPOSSIBLE)); + assert_eq!(parse!(second: 60, timestamp: 1_341_100_801), Err(IMPOSSIBLE)); + + // leap seconds #2: full fields + // we need to have separate tests for them since it uses another control flow. + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 59, timestamp: 1_341_100_798), + Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 59, timestamp: 1_341_100_799), + ymdhms(2012,6,30, 23,59,59)); + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 59, timestamp: 1_341_100_800), + Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 60, timestamp: 1_341_100_799), + ymdhmsn(2012,6,30, 23,59,59,1_000_000_000)); + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 60, timestamp: 1_341_100_800), + ymdhmsn(2012,6,30, 23,59,59,1_000_000_000)); + assert_eq!(parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0, + minute: 0, second: 0, timestamp: 1_341_100_800), + ymdhms(2012,7,1, 0,0,0)); + assert_eq!(parse!(year: 2012, ordinal: 183, hour_div_12: 0, hour_mod_12: 0, + minute: 0, second: 1, timestamp: 1_341_100_800), + Err(IMPOSSIBLE)); + assert_eq!(parse!(year: 2012, ordinal: 182, hour_div_12: 1, hour_mod_12: 11, + minute: 59, second: 60, timestamp: 1_341_100_801), + Err(IMPOSSIBLE)); + + // error codes + assert_eq!(parse!(year: 2015, month: 1, day: 20, weekday: Tue, + hour_div_12: 2, hour_mod_12: 1, minute: 35, second: 20), + Err(OUT_OF_RANGE)); // `hour_div_12` is out of range + } + + #[test] + fn test_parsed_to_datetime() { + macro_rules! parse { + ($($k:ident: $v:expr),*) => ( + Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime() + ) + } + + let ymdhmsn = |y,m,d,h,n,s,nano,off| Ok(FixedOffset::east(off).ymd(y, m, d) + .and_hms_nano(h, n, s, nano)); + + assert_eq!(parse!(offset: 0), Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, + minute: 26, second: 40, nanosecond: 12_345_678), + Err(NOT_ENOUGH)); + assert_eq!(parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), + ymdhmsn(2014,12,31, 4,26,40,12_345_678, 0)); + assert_eq!(parse!(year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), + ymdhmsn(2014,12,31, 13,26,40,12_345_678, 32400)); + assert_eq!(parse!(year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 1, + minute: 42, second: 4, nanosecond: 12_345_678, offset: -9876), + ymdhmsn(2014,12,31, 1,42,4,12_345_678, -9876)); + assert_eq!(parse!(year: 2015, ordinal: 1, hour_div_12: 0, hour_mod_12: 4, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 86_400), + Err(OUT_OF_RANGE)); // `FixedOffset` does not support such huge offset + } + + #[test] + fn test_parsed_to_datetime_with_timezone() { + macro_rules! parse { + ($tz:expr; $($k:ident: $v:expr),*) => ( + Parsed { $($k: Some($v),)* ..Parsed::new() }.to_datetime_with_timezone(&$tz) + ) + } + + // single result from ymdhms + assert_eq!(parse!(Utc; + year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), + Ok(Utc.ymd(2014, 12, 31).and_hms_nano(4, 26, 40, 12_345_678))); + assert_eq!(parse!(Utc; + year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), + Err(IMPOSSIBLE)); + assert_eq!(parse!(FixedOffset::east(32400); + year: 2014, ordinal: 365, hour_div_12: 0, hour_mod_12: 4, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 0), + Err(IMPOSSIBLE)); + assert_eq!(parse!(FixedOffset::east(32400); + year: 2014, ordinal: 365, hour_div_12: 1, hour_mod_12: 1, + minute: 26, second: 40, nanosecond: 12_345_678, offset: 32400), + Ok(FixedOffset::east(32400).ymd(2014, 12, 31) + .and_hms_nano(13, 26, 40, 12_345_678))); + + // single result from timestamp + assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 0), + Ok(Utc.ymd(2014, 12, 31).and_hms(4, 26, 40))); + assert_eq!(parse!(Utc; timestamp: 1_420_000_000, offset: 32400), + Err(IMPOSSIBLE)); + assert_eq!(parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 0), + Err(IMPOSSIBLE)); + assert_eq!(parse!(FixedOffset::east(32400); timestamp: 1_420_000_000, offset: 32400), + Ok(FixedOffset::east(32400).ymd(2014, 12, 31).and_hms(13, 26, 40))); + + // TODO test with a variable time zone (for None and Ambiguous cases) + } +} + diff --git a/chrono/src/format/scan.rs b/chrono/src/format/scan.rs new file mode 100644 index 000000000..f2f97d91c --- /dev/null +++ b/chrono/src/format/scan.rs @@ -0,0 +1,304 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +/*! + * Various scanning routines for the parser. + */ + +use Weekday; +use super::{ParseResult, TOO_SHORT, INVALID, OUT_OF_RANGE}; + +/// Returns true when two slices are equal case-insensitively (in ASCII). +/// Assumes that the `pattern` is already converted to lower case. +fn equals(s: &str, pattern: &str) -> bool { + let mut xs = s.as_bytes().iter().map(|&c| match c { b'A'...b'Z' => c + 32, _ => c }); + let mut ys = pattern.as_bytes().iter().cloned(); + loop { + match (xs.next(), ys.next()) { + (None, None) => return true, + (None, _) | (_, None) => return false, + (Some(x), Some(y)) if x != y => return false, + _ => (), + } + } +} + +/// Tries to parse the non-negative number from `min` to `max` digits. +/// +/// The absence of digits at all is an unconditional error. +/// More than `max` digits are consumed up to the first `max` digits. +/// Any number that does not fit in `i64` is an error. +pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { + assert!(min <= max); + + // limit `s` to given number of digits + let mut window = s.as_bytes(); + if window.len() > max { window = &window[..max]; } + + // scan digits + let upto = window.iter().position(|&c| c < b'0' || b'9' < c) + .unwrap_or_else(|| window.len()); + if upto < min { + return Err(if window.is_empty() {TOO_SHORT} else {INVALID}); + } + + // we can overflow here, which is the only possible cause of error from `parse`. + let v: i64 = try!(s[..upto].parse().map_err(|_| OUT_OF_RANGE)); + Ok((&s[upto..], v)) +} + +/// Tries to consume at least one digits as a fractional second. +/// Returns the number of whole nanoseconds (0--999,999,999). +pub fn nanosecond(s: &str) -> ParseResult<(&str, i64)> { + // record the number of digits consumed for later scaling. + let origlen = s.len(); + let (s, v) = try!(number(s, 1, 9)); + let consumed = origlen - s.len(); + + // scale the number accordingly. + static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, + 1_000, 100, 10, 1]; + let v = try!(v.checked_mul(SCALE[consumed]).ok_or(OUT_OF_RANGE)); + + // if there are more than 9 digits, skip next digits. + let s = s.trim_left_matches(|c: char| '0' <= c && c <= '9'); + + Ok((s, v)) +} + +/// Tries to consume a fixed number of digits as a fractional second. +/// Returns the number of whole nanoseconds (0--999,999,999). +pub fn nanosecond_fixed(s: &str, digits: usize) -> ParseResult<(&str, i64)> { + // record the number of digits consumed for later scaling. + let (s, v) = try!(number(s, digits, digits)); + + // scale the number accordingly. + static SCALE: [i64; 10] = [0, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, + 1_000, 100, 10, 1]; + let v = try!(v.checked_mul(SCALE[digits]).ok_or(OUT_OF_RANGE)); + + Ok((s, v)) +} + +/// Tries to parse the month index (0 through 11) with the first three ASCII letters. +pub fn short_month0(s: &str) -> ParseResult<(&str, u8)> { + if s.len() < 3 { return Err(TOO_SHORT); } + let buf = s.as_bytes(); + let month0 = match (buf[0] | 32, buf[1] | 32, buf[2] | 32) { + (b'j',b'a',b'n') => 0, + (b'f',b'e',b'b') => 1, + (b'm',b'a',b'r') => 2, + (b'a',b'p',b'r') => 3, + (b'm',b'a',b'y') => 4, + (b'j',b'u',b'n') => 5, + (b'j',b'u',b'l') => 6, + (b'a',b'u',b'g') => 7, + (b's',b'e',b'p') => 8, + (b'o',b'c',b't') => 9, + (b'n',b'o',b'v') => 10, + (b'd',b'e',b'c') => 11, + _ => return Err(INVALID) + }; + Ok((&s[3..], month0)) +} + +/// Tries to parse the weekday with the first three ASCII letters. +pub fn short_weekday(s: &str) -> ParseResult<(&str, Weekday)> { + if s.len() < 3 { return Err(TOO_SHORT); } + let buf = s.as_bytes(); + let weekday = match (buf[0] | 32, buf[1] | 32, buf[2] | 32) { + (b'm',b'o',b'n') => Weekday::Mon, + (b't',b'u',b'e') => Weekday::Tue, + (b'w',b'e',b'd') => Weekday::Wed, + (b't',b'h',b'u') => Weekday::Thu, + (b'f',b'r',b'i') => Weekday::Fri, + (b's',b'a',b't') => Weekday::Sat, + (b's',b'u',b'n') => Weekday::Sun, + _ => return Err(INVALID) + }; + Ok((&s[3..], weekday)) +} + +/// Tries to parse the month index (0 through 11) with short or long month names. +/// It prefers long month names to short month names when both are possible. +pub fn short_or_long_month0(s: &str) -> ParseResult<(&str, u8)> { + // lowercased month names, minus first three chars + static LONG_MONTH_SUFFIXES: [&'static str; 12] = + ["uary", "ruary", "ch", "il", "", "e", "y", "ust", "tember", "ober", "ember", "ember"]; + + let (mut s, month0) = try!(short_month0(s)); + + // tries to consume the suffix if possible + let suffix = LONG_MONTH_SUFFIXES[month0 as usize]; + if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { + s = &s[suffix.len()..]; + } + + Ok((s, month0)) +} + +/// Tries to parse the weekday with short or long weekday names. +/// It prefers long weekday names to short weekday names when both are possible. +pub fn short_or_long_weekday(s: &str) -> ParseResult<(&str, Weekday)> { + // lowercased weekday names, minus first three chars + static LONG_WEEKDAY_SUFFIXES: [&'static str; 7] = + ["day", "sday", "nesday", "rsday", "day", "urday", "day"]; + + let (mut s, weekday) = try!(short_weekday(s)); + + // tries to consume the suffix if possible + let suffix = LONG_WEEKDAY_SUFFIXES[weekday.num_days_from_monday() as usize]; + if s.len() >= suffix.len() && equals(&s[..suffix.len()], suffix) { + s = &s[suffix.len()..]; + } + + Ok((s, weekday)) +} + +/// Tries to consume exactly one given character. +pub fn char(s: &str, c1: u8) -> ParseResult<&str> { + match s.as_bytes().first() { + Some(&c) if c == c1 => Ok(&s[1..]), + Some(_) => Err(INVALID), + None => Err(TOO_SHORT), + } +} + +/// Tries to consume one or more whitespace. +pub fn space(s: &str) -> ParseResult<&str> { + let s_ = s.trim_left(); + if s_.len() < s.len() { + Ok(s_) + } else if s.is_empty() { + Err(TOO_SHORT) + } else { + Err(INVALID) + } +} + +/// Consumes any number (including zero) of colon or spaces. +pub fn colon_or_space(s: &str) -> ParseResult<&str> { + Ok(s.trim_left_matches(|c: char| c == ':' || c.is_whitespace())) +} + +/// Tries to parse `[-+]\d\d` continued by `\d\d`. Return an offset in seconds if possible. +/// +/// The additional `colon` may be used to parse a mandatory or optional `:` +/// between hours and minutes, and should return either a new suffix or `Err` when parsing fails. +pub fn timezone_offset(s: &str, consume_colon: F) -> ParseResult<(&str, i32)> + where F: FnMut(&str) -> ParseResult<&str> { + timezone_offset_internal(s, consume_colon, false) +} + +fn timezone_offset_internal(mut s: &str, mut consume_colon: F, allow_missing_minutes: bool) +-> ParseResult<(&str, i32)> + where F: FnMut(&str) -> ParseResult<&str> +{ + fn digits(s: &str) -> ParseResult<(u8, u8)> { + let b = s.as_bytes(); + if b.len() < 2 { + Err(TOO_SHORT) + } else { + Ok((b[0], b[1])) + } + } + let negative = match s.as_bytes().first() { + Some(&b'+') => false, + Some(&b'-') => true, + Some(_) => return Err(INVALID), + None => return Err(TOO_SHORT), + }; + s = &s[1..]; + + // hours (00--99) + let hours = match try!(digits(s)) { + (h1 @ b'0'...b'9', h2 @ b'0'...b'9') => i32::from((h1 - b'0') * 10 + (h2 - b'0')), + _ => return Err(INVALID), + }; + s = &s[2..]; + + // colons (and possibly other separators) + s = try!(consume_colon(s)); + + // minutes (00--59) + // if the next two items are digits then we have to add minutes + let minutes = if let Ok(ds) = digits(s) { + match ds { + (m1 @ b'0'...b'5', m2 @ b'0'...b'9') => i32::from((m1 - b'0') * 10 + (m2 - b'0')), + (b'6'...b'9', b'0'...b'9') => return Err(OUT_OF_RANGE), + _ => return Err(INVALID), + } + } else if allow_missing_minutes { + 0 + } else { + return Err(TOO_SHORT); + }; + s = match s.len() { + len if len >= 2 => &s[2..], + len if len == 0 => s, + _ => return Err(TOO_SHORT), + }; + + let seconds = hours * 3600 + minutes * 60; + Ok((s, if negative {-seconds} else {seconds})) +} + +/// Same to `timezone_offset` but also allows for `z`/`Z` which is same to `+00:00`. +pub fn timezone_offset_zulu(s: &str, colon: F) +-> ParseResult<(&str, i32)> + where F: FnMut(&str) -> ParseResult<&str> +{ + match s.as_bytes().first() { + Some(&b'z') | Some(&b'Z') => Ok((&s[1..], 0)), + _ => timezone_offset(s, colon), + } +} + +/// Same to `timezone_offset` but also allows for `z`/`Z` which is same to +/// `+00:00`, and allows missing minutes entirely. +pub fn timezone_offset_permissive(s: &str, colon: F) +-> ParseResult<(&str, i32)> + where F: FnMut(&str) -> ParseResult<&str> +{ + match s.as_bytes().first() { + Some(&b'z') | Some(&b'Z') => Ok((&s[1..], 0)), + _ => timezone_offset_internal(s, colon, true), + } +} + +/// Same to `timezone_offset` but also allows for RFC 2822 legacy timezones. +/// May return `None` which indicates an insufficient offset data (i.e. `-0000`). +pub fn timezone_offset_2822(s: &str) -> ParseResult<(&str, Option)> { + // tries to parse legacy time zone names + let upto = s.as_bytes().iter().position(|&c| match c { b'a'...b'z' | b'A'...b'Z' => false, + _ => true }) + .unwrap_or_else(|| s.len()); + if upto > 0 { + let name = &s[..upto]; + let s = &s[upto..]; + let offset_hours = |o| Ok((s, Some(o * 3600))); + if equals(name, "gmt") || equals(name, "ut") { + offset_hours(0) + } else if equals(name, "edt") { + offset_hours(-4) + } else if equals(name, "est") || equals(name, "cdt") { + offset_hours(-5) + } else if equals(name, "cst") || equals(name, "mdt") { + offset_hours(-6) + } else if equals(name, "mst") || equals(name, "pdt") { + offset_hours(-7) + } else if equals(name, "pst") { + offset_hours(-8) + } else { + Ok((s, None)) // recommended by RFC 2822: consume but treat it as -0000 + } + } else { + let (s_, offset) = try!(timezone_offset(s, |s| Ok(s))); + if offset == 0 && s.starts_with('-') { // -0000 is not same to +0000 + Ok((s_, None)) + } else { + Ok((s_, Some(offset))) + } + } +} + diff --git a/chrono/src/format/strftime.rs b/chrono/src/format/strftime.rs new file mode 100644 index 000000000..d7cf68c76 --- /dev/null +++ b/chrono/src/format/strftime.rs @@ -0,0 +1,483 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +/*! +`strftime`/`strptime`-inspired date and time formatting syntax. + +## Specifiers + +The following specifiers are available both to formatting and parsing. + +| Spec. | Example | Description | +|-------|----------|----------------------------------------------------------------------------| +| | | **DATE SPECIFIERS:** | +| `%Y` | `2001` | The full proleptic Gregorian year, zero-padded to 4 digits. [1] | +| `%C` | `20` | The proleptic Gregorian year divided by 100, zero-padded to 2 digits. [2] | +| `%y` | `01` | The proleptic Gregorian year modulo 100, zero-padded to 2 digits. [2] | +| | | | +| `%m` | `07` | Month number (01--12), zero-padded to 2 digits. | +| `%b` | `Jul` | Abbreviated month name. Always 3 letters. | +| `%B` | `July` | Full month name. Also accepts corresponding abbreviation in parsing. | +| `%h` | `Jul` | Same to `%b`. | +| | | | +| `%d` | `08` | Day number (01--31), zero-padded to 2 digits. | +| `%e` | ` 8` | Same to `%d` but space-padded. Same to `%_d`. | +| | | | +| `%a` | `Sun` | Abbreviated weekday name. Always 3 letters. | +| `%A` | `Sunday` | Full weekday name. Also accepts corresponding abbreviation in parsing. | +| `%w` | `0` | Sunday = 0, Monday = 1, ..., Saturday = 6. | +| `%u` | `7` | Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601) | +| | | | +| `%U` | `28` | Week number starting with Sunday (00--53), zero-padded to 2 digits. [3] | +| `%W` | `27` | Same to `%U`, but week 1 starts with the first Monday in that year instead.| +| | | | +| `%G` | `2001` | Same to `%Y` but uses the year number in ISO 8601 week date. [4] | +| `%g` | `01` | Same to `%y` but uses the year number in ISO 8601 week date. [4] | +| `%V` | `27` | Same to `%U` but uses the week number in ISO 8601 week date (01--53). [4] | +| | | | +| `%j` | `189` | Day of the year (001--366), zero-padded to 3 digits. | +| | | | +| `%D` | `07/08/01` | Month-day-year format. Same to `%m/%d/%y`. | +| `%x` | `07/08/01` | Same to `%D`. | +| `%F` | `2001-07-08` | Year-month-day format (ISO 8601). Same to `%Y-%m-%d`. | +| `%v` | ` 8-Jul-2001` | Day-month-year format. Same to `%e-%b-%Y`. | +| | | | +| | | **TIME SPECIFIERS:** | +| `%H` | `00` | Hour number (00--23), zero-padded to 2 digits. | +| `%k` | ` 0` | Same to `%H` but space-padded. Same to `%_H`. | +| `%I` | `12` | Hour number in 12-hour clocks (01--12), zero-padded to 2 digits. | +| `%l` | `12` | Same to `%I` but space-padded. Same to `%_I`. | +| | | | +| `%P` | `am` | `am` or `pm` in 12-hour clocks. | +| `%p` | `AM` | `AM` or `PM` in 12-hour clocks. | +| | | | +| `%M` | `34` | Minute number (00--59), zero-padded to 2 digits. | +| `%S` | `60` | Second number (00--60), zero-padded to 2 digits. [5] | +| `%f` | `026490000` | The fractional seconds (in nanoseconds) since last whole second. [8] | +| `%.f` | `.026490`| Similar to `.%f` but left-aligned. These all consume the leading dot. [8] | +| `%.3f`| `.026` | Similar to `.%f` but left-aligned but fixed to a length of 3. [8] | +| `%.6f`| `.026490` | Similar to `.%f` but left-aligned but fixed to a length of 6. [8] | +| `%.9f`| `.026490000` | Similar to `.%f` but left-aligned but fixed to a length of 9. [8] | +| `%3f` | `026` | Similar to `%.3f` but without the leading dot. [8] | +| `%6f` | `026490` | Similar to `%.6f` but without the leading dot. [8] | +| `%9f` | `026490000` | Similar to `%.9f` but without the leading dot. [8] | +| | | | +| `%R` | `00:34` | Hour-minute format. Same to `%H:%M`. | +| `%T` | `00:34:60` | Hour-minute-second format. Same to `%H:%M:%S`. | +| `%X` | `00:34:60` | Same to `%T`. | +| `%r` | `12:34:60 AM` | Hour-minute-second format in 12-hour clocks. Same to `%I:%M:%S %p`. | +| | | | +| | | **TIME ZONE SPECIFIERS:** | +| `%Z` | `ACST` | *Formatting only:* Local time zone name. | +| `%z` | `+0930` | Offset from the local time to UTC (with UTC being `+0000`). | +| `%:z` | `+09:30` | Same to `%z` but with a colon. | +| `%#z` | `+09` | *Parsing only:* Same to `%z` but allows minutes to be missing or present. | +| | | | +| | | **DATE & TIME SPECIFIERS:** | +|`%c`|`Sun Jul 8 00:34:60 2001`|`ctime` date & time format. Same to `%a %b %e %T %Y` sans `\n`.| +| `%+` | `2001-07-08T00:34:60.026490+09:30` | ISO 8601 / RFC 3339 date & time format. [6] | +| | | | +| `%s` | `994518299` | UNIX timestamp, the number of seconds since 1970-01-01 00:00 UTC. [7] | +| | | | +| | | **SPECIAL SPECIFIERS:** | +| `%t` | | Literal tab (`\t`). | +| `%n` | | Literal newline (`\n`). | +| `%%` | | Literal percent sign. | + +It is possible to override the default padding behavior of numeric specifiers `%?`. +This is not allowed for other specifiers and will result in the `BAD_FORMAT` error. + +Modifier | Description +-------- | ----------- +`%-?` | Suppresses any padding including spaces and zeroes. (e.g. `%j` = `012`, `%-j` = `12`) +`%_?` | Uses spaces as a padding. (e.g. `%j` = `012`, `%_j` = ` 12`) +`%0?` | Uses zeroes as a padding. (e.g. `%e` = ` 9`, `%0e` = `09`) + +Notes: + +1. `%Y`: + Negative years are allowed in formatting but not in parsing. + +2. `%C`, `%y`: + This is floor division, so 100 BCE (year number -99) will print `-1` and `99` respectively. + +3. `%U`: + Week 1 starts with the first Sunday in that year. + It is possible to have week 0 for days before the first Sunday. + +4. `%G`, `%g`, `%V`: + Week 1 is the first week with at least 4 days in that year. + Week 0 does not exist, so this should be used with `%G` or `%g`. + +5. `%S`: + It accounts for leap seconds, so `60` is possible. + +6. `%+`: + Same to `%Y-%m-%dT%H:%M:%S%.f%:z`, + i.e. 0, 3, 6 or 9 fractional digits for seconds and colons in the time zone offset. + + The typical `strftime` implementations have + different (and locale-dependent) formats for this specifier. + While Chrono's format for `%+` is far more stable, + it is best to avoid this specifier if you want to control the exact output. + +7. `%s`: + This is not padded and can be negative. + For the purpose of Chrono, it only accounts for non-leap seconds + so it slightly differs from ISO C `strftime` behavior. + +8. `%f`, `%.f`, `%.3f`, `%.6f`, `%.9f`, `%3f`, `%6f`, `%9f`: + + The default `%f` is right-aligned and always zero-padded to 9 digits + for the compatibility with glibc and others, + so it always counts the number of nanoseconds since the last whole second. + E.g. 7ms after the last second will print `007000000`, + and parsing `7000000` will yield the same. + + The variant `%.f` is left-aligned and print 0, 3, 6 or 9 fractional digits + according to the precision. + E.g. 70ms after the last second under `%.f` will print `.070` (note: not `.07`), + and parsing `.07`, `.070000` etc. will yield the same. + Note that they can print or read nothing if the fractional part is zero or + the next character is not `.`. + + The variant `%.3f`, `%.6f` and `%.9f` are left-aligned and print 3, 6 or 9 fractional digits + according to the number preceding `f`. + E.g. 70ms after the last second under `%.3f` will print `.070` (note: not `.07`), + and parsing `.07`, `.070000` etc. will yield the same. + Note that they can read nothing if the fractional part is zero or + the next character is not `.` however will print with the specified length. + + The variant `%3f`, `%6f` and `%9f` are left-aligned and print 3, 6 or 9 fractional digits + according to the number preceding `f`, but without the leading dot. + E.g. 70ms after the last second under `%3f` will print `070` (note: not `07`), + and parsing `07`, `070000` etc. will yield the same. + Note that they can read nothing if the fractional part is zero. + +*/ + +use super::{Item, Numeric, Fixed, InternalFixed, InternalInternal, Pad}; + +/// Parsing iterator for `strftime`-like format strings. +#[derive(Clone, Debug)] +pub struct StrftimeItems<'a> { + /// Remaining portion of the string. + remainder: &'a str, + /// If the current specifier is composed of multiple formatting items (e.g. `%+`), + /// parser refers to the statically reconstructed slice of them. + /// If `recons` is not empty they have to be returned earlier than the `remainder`. + recons: &'static [Item<'static>], +} + +impl<'a> StrftimeItems<'a> { + /// Creates a new parsing iterator from the `strftime`-like format string. + pub fn new(s: &'a str) -> StrftimeItems<'a> { + static FMT_NONE: [Item<'static>; 0] = []; + StrftimeItems { remainder: s, recons: &FMT_NONE } + } +} + +const HAVE_ALTERNATES: &'static str = "z"; + +impl<'a> Iterator for StrftimeItems<'a> { + type Item = Item<'a>; + + fn next(&mut self) -> Option> { + // we have some reconstructed items to return + if !self.recons.is_empty() { + let item = self.recons[0].clone(); + self.recons = &self.recons[1..]; + return Some(item); + } + + match self.remainder.chars().next() { + // we are done + None => None, + + // the next item is a specifier + Some('%') => { + self.remainder = &self.remainder[1..]; + + macro_rules! next { + () => ( + match self.remainder.chars().next() { + Some(x) => { + self.remainder = &self.remainder[x.len_utf8()..]; + x + }, + None => return Some(Item::Error), // premature end of string + } + ) + } + + let spec = next!(); + let pad_override = match spec { + '-' => Some(Pad::None), + '0' => Some(Pad::Zero), + '_' => Some(Pad::Space), + _ => None, + }; + let is_alternate = spec == '#'; + let spec = if pad_override.is_some() || is_alternate { next!() } else { spec }; + if is_alternate && !HAVE_ALTERNATES.contains(spec) { + return Some(Item::Error); + } + + macro_rules! recons { + [$head:expr, $($tail:expr),+] => ({ + const RECONS: &'static [Item<'static>] = &[$($tail),+]; + self.recons = RECONS; + $head + }) + } + + let item = match spec { + 'A' => fix!(LongWeekdayName), + 'B' => fix!(LongMonthName), + 'C' => num0!(YearDiv100), + 'D' => recons![num0!(Month), lit!("/"), num0!(Day), lit!("/"), + num0!(YearMod100)], + 'F' => recons![num0!(Year), lit!("-"), num0!(Month), lit!("-"), num0!(Day)], + 'G' => num0!(IsoYear), + 'H' => num0!(Hour), + 'I' => num0!(Hour12), + 'M' => num0!(Minute), + 'P' => fix!(LowerAmPm), + 'R' => recons![num0!(Hour), lit!(":"), num0!(Minute)], + 'S' => num0!(Second), + 'T' => recons![num0!(Hour), lit!(":"), num0!(Minute), lit!(":"), num0!(Second)], + 'U' => num0!(WeekFromSun), + 'V' => num0!(IsoWeek), + 'W' => num0!(WeekFromMon), + 'X' => recons![num0!(Hour), lit!(":"), num0!(Minute), lit!(":"), num0!(Second)], + 'Y' => num0!(Year), + 'Z' => fix!(TimezoneName), + 'a' => fix!(ShortWeekdayName), + 'b' | 'h' => fix!(ShortMonthName), + 'c' => recons![fix!(ShortWeekdayName), sp!(" "), fix!(ShortMonthName), + sp!(" "), nums!(Day), sp!(" "), num0!(Hour), lit!(":"), + num0!(Minute), lit!(":"), num0!(Second), sp!(" "), num0!(Year)], + 'd' => num0!(Day), + 'e' => nums!(Day), + 'f' => num0!(Nanosecond), + 'g' => num0!(IsoYearMod100), + 'j' => num0!(Ordinal), + 'k' => nums!(Hour), + 'l' => nums!(Hour12), + 'm' => num0!(Month), + 'n' => sp!("\n"), + 'p' => fix!(UpperAmPm), + 'r' => recons![num0!(Hour12), lit!(":"), num0!(Minute), lit!(":"), + num0!(Second), sp!(" "), fix!(UpperAmPm)], + 's' => num!(Timestamp), + 't' => sp!("\t"), + 'u' => num!(WeekdayFromMon), + 'v' => recons![nums!(Day), lit!("-"), fix!(ShortMonthName), lit!("-"), + num0!(Year)], + 'w' => num!(NumDaysFromSun), + 'x' => recons![num0!(Month), lit!("/"), num0!(Day), lit!("/"), + num0!(YearMod100)], + 'y' => num0!(YearMod100), + 'z' => if is_alternate { + internal_fix!(TimezoneOffsetPermissive) + } else { + fix!(TimezoneOffset) + }, + '+' => fix!(RFC3339), + ':' => match next!() { + 'z' => fix!(TimezoneOffsetColon), + _ => Item::Error, + }, + '.' => match next!() { + '3' => match next!() { + 'f' => fix!(Nanosecond3), + _ => Item::Error, + }, + '6' => match next!() { + 'f' => fix!(Nanosecond6), + _ => Item::Error, + }, + '9' => match next!() { + 'f' => fix!(Nanosecond9), + _ => Item::Error, + }, + 'f' => fix!(Nanosecond), + _ => Item::Error, + }, + '3' => match next!() { + 'f' => internal_fix!(Nanosecond3NoDot), + _ => Item::Error, + }, + '6' => match next!() { + 'f' => internal_fix!(Nanosecond6NoDot), + _ => Item::Error, + }, + '9' => match next!() { + 'f' => internal_fix!(Nanosecond9NoDot), + _ => Item::Error, + }, + '%' => lit!("%"), + _ => Item::Error, // no such specifier + }; + + // adjust `item` if we have any padding modifier + if let Some(new_pad) = pad_override { + match item { + Item::Numeric(ref kind, _pad) if self.recons.is_empty() => + Some(Item::Numeric(kind.clone(), new_pad)), + _ => Some(Item::Error), // no reconstructed or non-numeric item allowed + } + } else { + Some(item) + } + }, + + // the next item is space + Some(c) if c.is_whitespace() => { + // `%` is not a whitespace, so `c != '%'` is redundant + let nextspec = self.remainder.find(|c: char| !c.is_whitespace()) + .unwrap_or_else(|| self.remainder.len()); + assert!(nextspec > 0); + let item = sp!(&self.remainder[..nextspec]); + self.remainder = &self.remainder[nextspec..]; + Some(item) + }, + + // the next item is literal + _ => { + let nextspec = self.remainder.find(|c: char| c.is_whitespace() || c == '%') + .unwrap_or_else(|| self.remainder.len()); + assert!(nextspec > 0); + let item = lit!(&self.remainder[..nextspec]); + self.remainder = &self.remainder[nextspec..]; + Some(item) + }, + } + } +} + +#[cfg(test)] +#[test] +fn test_strftime_items() { + fn parse_and_collect<'a>(s: &'a str) -> Vec> { + // map any error into `[Item::Error]`. useful for easy testing. + let items = StrftimeItems::new(s); + let items = items.map(|spec| if spec == Item::Error {None} else {Some(spec)}); + items.collect::>>().unwrap_or(vec![Item::Error]) + } + + assert_eq!(parse_and_collect(""), []); + assert_eq!(parse_and_collect(" \t\n\r "), [sp!(" \t\n\r ")]); + assert_eq!(parse_and_collect("hello?"), [lit!("hello?")]); + assert_eq!(parse_and_collect("a b\t\nc"), [lit!("a"), sp!(" "), lit!("b"), sp!("\t\n"), + lit!("c")]); + assert_eq!(parse_and_collect("100%%"), [lit!("100"), lit!("%")]); + assert_eq!(parse_and_collect("100%% ok"), [lit!("100"), lit!("%"), sp!(" "), lit!("ok")]); + assert_eq!(parse_and_collect("%%PDF-1.0"), [lit!("%"), lit!("PDF-1.0")]); + assert_eq!(parse_and_collect("%Y-%m-%d"), [num0!(Year), lit!("-"), num0!(Month), lit!("-"), + num0!(Day)]); + assert_eq!(parse_and_collect("[%F]"), parse_and_collect("[%Y-%m-%d]")); + assert_eq!(parse_and_collect("%m %d"), [num0!(Month), sp!(" "), num0!(Day)]); + assert_eq!(parse_and_collect("%"), [Item::Error]); + assert_eq!(parse_and_collect("%%"), [lit!("%")]); + assert_eq!(parse_and_collect("%%%"), [Item::Error]); + assert_eq!(parse_and_collect("%%%%"), [lit!("%"), lit!("%")]); + assert_eq!(parse_and_collect("foo%?"), [Item::Error]); + assert_eq!(parse_and_collect("bar%42"), [Item::Error]); + assert_eq!(parse_and_collect("quux% +"), [Item::Error]); + assert_eq!(parse_and_collect("%.Z"), [Item::Error]); + assert_eq!(parse_and_collect("%:Z"), [Item::Error]); + assert_eq!(parse_and_collect("%-Z"), [Item::Error]); + assert_eq!(parse_and_collect("%0Z"), [Item::Error]); + assert_eq!(parse_and_collect("%_Z"), [Item::Error]); + assert_eq!(parse_and_collect("%.j"), [Item::Error]); + assert_eq!(parse_and_collect("%:j"), [Item::Error]); + assert_eq!(parse_and_collect("%-j"), [num!(Ordinal)]); + assert_eq!(parse_and_collect("%0j"), [num0!(Ordinal)]); + assert_eq!(parse_and_collect("%_j"), [nums!(Ordinal)]); + assert_eq!(parse_and_collect("%.e"), [Item::Error]); + assert_eq!(parse_and_collect("%:e"), [Item::Error]); + assert_eq!(parse_and_collect("%-e"), [num!(Day)]); + assert_eq!(parse_and_collect("%0e"), [num0!(Day)]); + assert_eq!(parse_and_collect("%_e"), [nums!(Day)]); + assert_eq!(parse_and_collect("%z"), [fix!(TimezoneOffset)]); + assert_eq!(parse_and_collect("%#z"), [internal_fix!(TimezoneOffsetPermissive)]); + assert_eq!(parse_and_collect("%#m"), [Item::Error]); +} + +#[cfg(test)] +#[test] +fn test_strftime_docs() { + use {FixedOffset, TimeZone, Timelike}; + + let dt = FixedOffset::east(34200).ymd(2001, 7, 8).and_hms_nano(0, 34, 59, 1_026_490_708); + + // date specifiers + assert_eq!(dt.format("%Y").to_string(), "2001"); + assert_eq!(dt.format("%C").to_string(), "20"); + assert_eq!(dt.format("%y").to_string(), "01"); + assert_eq!(dt.format("%m").to_string(), "07"); + assert_eq!(dt.format("%b").to_string(), "Jul"); + assert_eq!(dt.format("%B").to_string(), "July"); + assert_eq!(dt.format("%h").to_string(), "Jul"); + assert_eq!(dt.format("%d").to_string(), "08"); + assert_eq!(dt.format("%e").to_string(), " 8"); + assert_eq!(dt.format("%e").to_string(), dt.format("%_d").to_string()); + assert_eq!(dt.format("%a").to_string(), "Sun"); + assert_eq!(dt.format("%A").to_string(), "Sunday"); + assert_eq!(dt.format("%w").to_string(), "0"); + assert_eq!(dt.format("%u").to_string(), "7"); + assert_eq!(dt.format("%U").to_string(), "28"); + assert_eq!(dt.format("%W").to_string(), "27"); + assert_eq!(dt.format("%G").to_string(), "2001"); + assert_eq!(dt.format("%g").to_string(), "01"); + assert_eq!(dt.format("%V").to_string(), "27"); + assert_eq!(dt.format("%j").to_string(), "189"); + assert_eq!(dt.format("%D").to_string(), "07/08/01"); + assert_eq!(dt.format("%x").to_string(), "07/08/01"); + assert_eq!(dt.format("%F").to_string(), "2001-07-08"); + assert_eq!(dt.format("%v").to_string(), " 8-Jul-2001"); + + // time specifiers + assert_eq!(dt.format("%H").to_string(), "00"); + assert_eq!(dt.format("%k").to_string(), " 0"); + assert_eq!(dt.format("%k").to_string(), dt.format("%_H").to_string()); + assert_eq!(dt.format("%I").to_string(), "12"); + assert_eq!(dt.format("%l").to_string(), "12"); + assert_eq!(dt.format("%l").to_string(), dt.format("%_I").to_string()); + assert_eq!(dt.format("%P").to_string(), "am"); + assert_eq!(dt.format("%p").to_string(), "AM"); + assert_eq!(dt.format("%M").to_string(), "34"); + assert_eq!(dt.format("%S").to_string(), "60"); + assert_eq!(dt.format("%f").to_string(), "026490708"); + assert_eq!(dt.format("%.f").to_string(), ".026490708"); + assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").to_string(), + ".026490"); + assert_eq!(dt.format("%.3f").to_string(), ".026"); + assert_eq!(dt.format("%.6f").to_string(), ".026490"); + assert_eq!(dt.format("%.9f").to_string(), ".026490708"); + assert_eq!(dt.format("%3f").to_string(), "026"); + assert_eq!(dt.format("%6f").to_string(), "026490"); + assert_eq!(dt.format("%9f").to_string(), "026490708"); + assert_eq!(dt.format("%R").to_string(), "00:34"); + assert_eq!(dt.format("%T").to_string(), "00:34:60"); + assert_eq!(dt.format("%X").to_string(), "00:34:60"); + assert_eq!(dt.format("%r").to_string(), "12:34:60 AM"); + + // time zone specifiers + //assert_eq!(dt.format("%Z").to_string(), "ACST"); + assert_eq!(dt.format("%z").to_string(), "+0930"); + assert_eq!(dt.format("%:z").to_string(), "+09:30"); + + // date & time specifiers + assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001"); + assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30"); + assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(), + "2001-07-08T00:34:60.026490+09:30"); + assert_eq!(dt.format("%s").to_string(), "994518299"); + + // special specifiers + assert_eq!(dt.format("%t").to_string(), "\t"); + assert_eq!(dt.format("%n").to_string(), "\n"); + assert_eq!(dt.format("%%").to_string(), "%"); +} diff --git a/chrono/src/lib.rs b/chrono/src/lib.rs new file mode 100644 index 000000000..1f149ed5d --- /dev/null +++ b/chrono/src/lib.rs @@ -0,0 +1,994 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! # Chrono: Date and Time for Rust +//! +//! It aims to be a feature-complete superset of +//! the [time](https://github.com/rust-lang-deprecated/time) library. +//! In particular, +//! +//! * Chrono strictly adheres to ISO 8601. +//! * Chrono is timezone-aware by default, with separate timezone-naive types. +//! * Chrono is space-optimal and (while not being the primary goal) reasonably efficient. +//! +//! There were several previous attempts to bring a good date and time library to Rust, +//! which Chrono builds upon and should acknowledge: +//! +//! * [Initial research on +//! the wiki](https://github.com/rust-lang/rust-wiki-backup/blob/master/Lib-datetime.md) +//! * Dietrich Epp's [datetime-rs](https://github.com/depp/datetime-rs) +//! * Luis de Bethencourt's [rust-datetime](https://github.com/luisbg/rust-datetime) +//! +//! Any significant changes to Chrono are documented in +//! the [`CHANGELOG.md`](https://github.com/chronotope/chrono/blob/master/CHANGELOG.md) file. +//! +//! ## Usage +//! +//! Put this in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! chrono = "0.4" +//! ``` +//! +//! Or, if you want [Serde](https://github.com/serde-rs/serde) include the +//! feature like this: +//! +//! ```toml +//! [dependencies] +//! chrono = { version = "0.4", features = ["serde"] } +//! ``` +//! +//! Then put this in your crate root: +//! +//! ```rust +//! extern crate chrono; +//! ``` +//! +//! Avoid using `use chrono::*;` as Chrono exports several modules other than types. +//! If you prefer the glob imports, use the following instead: +//! +//! ```rust +//! use chrono::prelude::*; +//! ``` +//! +//! ## Overview +//! +//! ### Duration +//! +//! Chrono currently uses +//! the [`time::Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type +//! from the `time` crate to represent the magnitude of a time span. +//! Since this has the same name to the newer, standard type for duration, +//! the reference will refer this type as `OldDuration`. +//! Note that this is an "accurate" duration represented as seconds and +//! nanoseconds and does not represent "nominal" components such as days or +//! months. +//! +//! Chrono does not yet natively support +//! the standard [`Duration`](https://docs.rs/time/0.1.40/time/struct.Duration.html) type, +//! but it will be supported in the future. +//! Meanwhile you can convert between two types with +//! [`Duration::from_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.from_std) +//! and +//! [`Duration::to_std`](https://docs.rs/time/0.1.40/time/struct.Duration.html#method.to_std) +//! methods. +//! +//! ### Date and Time +//! +//! Chrono provides a +//! [**`DateTime`**](./struct.DateTime.html) +//! type to represent a date and a time in a timezone. +//! +//! For more abstract moment-in-time tracking such as internal timekeeping +//! that is unconcerned with timezones, consider +//! [`time::SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html), +//! which tracks your system clock, or +//! [`time::Instant`](https://doc.rust-lang.org/std/time/struct.Instant.html), which +//! is an opaque but monotonically-increasing representation of a moment in time. +//! +//! `DateTime` is timezone-aware and must be constructed from +//! the [**`TimeZone`**](./offset/trait.TimeZone.html) object, +//! which defines how the local date is converted to and back from the UTC date. +//! There are three well-known `TimeZone` implementations: +//! +//! * [**`Utc`**](./offset/struct.Utc.html) specifies the UTC time zone. It is most efficient. +//! +//! * [**`Local`**](./offset/struct.Local.html) specifies the system local time zone. +//! +//! * [**`FixedOffset`**](./offset/struct.FixedOffset.html) specifies +//! an arbitrary, fixed time zone such as UTC+09:00 or UTC-10:30. +//! This often results from the parsed textual date and time. +//! Since it stores the most information and does not depend on the system environment, +//! you would want to normalize other `TimeZone`s into this type. +//! +//! `DateTime`s with different `TimeZone` types are distinct and do not mix, +//! but can be converted to each other using +//! the [`DateTime::with_timezone`](./struct.DateTime.html#method.with_timezone) method. +//! +//! You can get the current date and time in the UTC time zone +//! ([`Utc::now()`](./offset/struct.Utc.html#method.now)) +//! or in the local time zone +//! ([`Local::now()`](./offset/struct.Local.html#method.now)). +//! +//! ```rust +//! use chrono::prelude::*; +//! +//! let utc: DateTime = Utc::now(); // e.g. `2014-11-28T12:45:59.324310806Z` +//! let local: DateTime = Local::now(); // e.g. `2014-11-28T21:45:59.324310806+09:00` +//! # let _ = utc; let _ = local; +//! ``` +//! +//! Alternatively, you can create your own date and time. +//! This is a bit verbose due to Rust's lack of function and method overloading, +//! but in turn we get a rich combination of initialization methods. +//! +//! ```rust +//! use chrono::prelude::*; +//! use chrono::offset::LocalResult; +//! +//! let dt = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11); // `2014-07-08T09:10:11Z` +//! // July 8 is 188th day of the year 2014 (`o` for "ordinal") +//! assert_eq!(dt, Utc.yo(2014, 189).and_hms(9, 10, 11)); +//! // July 8 is Tuesday in ISO week 28 of the year 2014. +//! assert_eq!(dt, Utc.isoywd(2014, 28, Weekday::Tue).and_hms(9, 10, 11)); +//! +//! let dt = Utc.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); // `2014-07-08T09:10:11.012Z` +//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_micro(9, 10, 11, 12_000)); +//! assert_eq!(dt, Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 12_000_000)); +//! +//! // dynamic verification +//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(21, 15, 33), +//! LocalResult::Single(Utc.ymd(2014, 7, 8).and_hms(21, 15, 33))); +//! assert_eq!(Utc.ymd_opt(2014, 7, 8).and_hms_opt(80, 15, 33), LocalResult::None); +//! assert_eq!(Utc.ymd_opt(2014, 7, 38).and_hms_opt(21, 15, 33), LocalResult::None); +//! +//! // other time zone objects can be used to construct a local datetime. +//! // obviously, `local_dt` is normally different from `dt`, but `fixed_dt` should be identical. +//! let local_dt = Local.ymd(2014, 7, 8).and_hms_milli(9, 10, 11, 12); +//! let fixed_dt = FixedOffset::east(9 * 3600).ymd(2014, 7, 8).and_hms_milli(18, 10, 11, 12); +//! assert_eq!(dt, fixed_dt); +//! # let _ = local_dt; +//! ``` +//! +//! Various properties are available to the date and time, and can be altered individually. +//! Most of them are defined in the traits [`Datelike`](./trait.Datelike.html) and +//! [`Timelike`](./trait.Timelike.html) which you should `use` before. +//! Addition and subtraction is also supported. +//! The following illustrates most supported operations to the date and time: +//! +//! ```rust +//! # extern crate chrono; extern crate time; fn main() { +//! use chrono::prelude::*; +//! use time::Duration; +//! +//! # /* we intentionally fake the datetime... +//! // assume this returned `2014-11-28T21:45:59.324310806+09:00`: +//! let dt = Local::now(); +//! # */ // up to here. we now define a fixed datetime for the illustrative purpose. +//! # let dt = FixedOffset::east(9*3600).ymd(2014, 11, 28).and_hms_nano(21, 45, 59, 324310806); +//! +//! // property accessors +//! assert_eq!((dt.year(), dt.month(), dt.day()), (2014, 11, 28)); +//! assert_eq!((dt.month0(), dt.day0()), (10, 27)); // for unfortunate souls +//! assert_eq!((dt.hour(), dt.minute(), dt.second()), (21, 45, 59)); +//! assert_eq!(dt.weekday(), Weekday::Fri); +//! assert_eq!(dt.weekday().number_from_monday(), 5); // Mon=1, ..., Sat=7 +//! assert_eq!(dt.ordinal(), 332); // the day of year +//! assert_eq!(dt.num_days_from_ce(), 735565); // the number of days from and including Jan 1, 1 +//! +//! // time zone accessor and manipulation +//! assert_eq!(dt.offset().fix().local_minus_utc(), 9 * 3600); +//! assert_eq!(dt.timezone(), FixedOffset::east(9 * 3600)); +//! assert_eq!(dt.with_timezone(&Utc), Utc.ymd(2014, 11, 28).and_hms_nano(12, 45, 59, 324310806)); +//! +//! // a sample of property manipulations (validates dynamically) +//! assert_eq!(dt.with_day(29).unwrap().weekday(), Weekday::Sat); // 2014-11-29 is Saturday +//! assert_eq!(dt.with_day(32), None); +//! assert_eq!(dt.with_year(-300).unwrap().num_days_from_ce(), -109606); // November 29, 301 BCE +//! +//! // arithmetic operations +//! let dt1 = Utc.ymd(2014, 11, 14).and_hms(8, 9, 10); +//! let dt2 = Utc.ymd(2014, 11, 14).and_hms(10, 9, 8); +//! assert_eq!(dt1.signed_duration_since(dt2), Duration::seconds(-2 * 3600 + 2)); +//! assert_eq!(dt2.signed_duration_since(dt1), Duration::seconds(2 * 3600 - 2)); +//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) + Duration::seconds(1_000_000_000), +//! Utc.ymd(2001, 9, 9).and_hms(1, 46, 40)); +//! assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0) - Duration::seconds(1_000_000_000), +//! Utc.ymd(1938, 4, 24).and_hms(22, 13, 20)); +//! # } +//! ``` +//! +//! ### Formatting and Parsing +//! +//! Formatting is done via the [`format`](./struct.DateTime.html#method.format) method, +//! which format is equivalent to the familiar `strftime` format. +//! +//! See [`format::strftime`](./format/strftime/index.html#specifiers) +//! documentation for full syntax and list of specifiers. +//! +//! The default `to_string` method and `{:?}` specifier also give a reasonable representation. +//! Chrono also provides [`to_rfc2822`](./struct.DateTime.html#method.to_rfc2822) and +//! [`to_rfc3339`](./struct.DateTime.html#method.to_rfc3339) methods +//! for well-known formats. +//! +//! ```rust +//! use chrono::prelude::*; +//! +//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); +//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); +//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); +//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string()); +//! +//! assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); +//! assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000"); +//! assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00"); +//! assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z"); +//! +//! // Note that milli/nanoseconds are only printed if they are non-zero +//! let dt_nano = Utc.ymd(2014, 11, 28).and_hms_nano(12, 0, 9, 1); +//! assert_eq!(format!("{:?}", dt_nano), "2014-11-28T12:00:09.000000001Z"); +//! ``` +//! +//! Parsing can be done with three methods: +//! +//! 1. The standard [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) trait +//! (and [`parse`](https://doc.rust-lang.org/std/primitive.str.html#method.parse) method +//! on a string) can be used for parsing `DateTime`, `DateTime` and +//! `DateTime` values. This parses what the `{:?}` +//! ([`std::fmt::Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html)) +//! format specifier prints, and requires the offset to be present. +//! +//! 2. [`DateTime::parse_from_str`](./struct.DateTime.html#method.parse_from_str) parses +//! a date and time with offsets and returns `DateTime`. +//! This should be used when the offset is a part of input and the caller cannot guess that. +//! It *cannot* be used when the offset can be missing. +//! [`DateTime::parse_from_rfc2822`](./struct.DateTime.html#method.parse_from_rfc2822) +//! and +//! [`DateTime::parse_from_rfc3339`](./struct.DateTime.html#method.parse_from_rfc3339) +//! are similar but for well-known formats. +//! +//! 3. [`Offset::datetime_from_str`](./offset/trait.TimeZone.html#method.datetime_from_str) is +//! similar but returns `DateTime` of given offset. +//! When the explicit offset is missing from the input, it simply uses given offset. +//! It issues an error when the input contains an explicit offset different +//! from the current offset. +//! +//! More detailed control over the parsing process is available via +//! [`format`](./format/index.html) module. +//! +//! ```rust +//! use chrono::prelude::*; +//! +//! let dt = Utc.ymd(2014, 11, 28).and_hms(12, 0, 9); +//! let fixed_dt = dt.with_timezone(&FixedOffset::east(9*3600)); +//! +//! // method 1 +//! assert_eq!("2014-11-28T12:00:09Z".parse::>(), Ok(dt.clone())); +//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(dt.clone())); +//! assert_eq!("2014-11-28T21:00:09+09:00".parse::>(), Ok(fixed_dt.clone())); +//! +//! // method 2 +//! assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00", "%Y-%m-%d %H:%M:%S %z"), +//! Ok(fixed_dt.clone())); +//! assert_eq!(DateTime::parse_from_rfc2822("Fri, 28 Nov 2014 21:00:09 +0900"), +//! Ok(fixed_dt.clone())); +//! assert_eq!(DateTime::parse_from_rfc3339("2014-11-28T21:00:09+09:00"), Ok(fixed_dt.clone())); +//! +//! // method 3 +//! assert_eq!(Utc.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone())); +//! assert_eq!(Utc.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone())); +//! +//! // oops, the year is missing! +//! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T %Y").is_err()); +//! // oops, the format string does not include the year at all! +//! assert!(Utc.datetime_from_str("Fri Nov 28 12:00:09", "%a %b %e %T").is_err()); +//! // oops, the weekday is incorrect! +//! assert!(Utc.datetime_from_str("Sat Nov 28 12:00:09 2014", "%a %b %e %T %Y").is_err()); +//! ``` +//! +//! Again : See [`format::strftime`](./format/strftime/index.html#specifiers) +//! documentation for full syntax and list of specifiers. +//! +//! ### Conversion from and to EPOCH timestamps +//! +//! Use [`Utc.timestamp(seconds, nanoseconds)`](./offset/trait.TimeZone.html#method.timestamp) +//! to construct a [`DateTime`](./struct.DateTime.html) from a UNIX timestamp +//! (seconds, nanoseconds that passed since January 1st 1970). +//! +//! Use [`DateTime.timestamp`](./struct.DateTime.html#method.timestamp) to get the timestamp (in seconds) +//! from a [`DateTime`](./struct.DateTime.html). Additionally, you can use +//! [`DateTime.timestamp_subsec_nanos`](./struct.DateTime.html#method.timestamp_subsec_nanos) +//! to get the number of additional number of nanoseconds. +//! +//! ```rust +//! # use chrono::DateTime; +//! # use chrono::Utc; +//! // We need the trait in scope to use Utc::timestamp(). +//! use chrono::TimeZone; +//! +//! // Construct a datetime from epoch: +//! let dt = Utc.timestamp(1_500_000_000, 0); +//! assert_eq!(dt.to_rfc2822(), "Fri, 14 Jul 2017 02:40:00 +0000"); +//! +//! // Get epoch value from a datetime: +//! let dt = DateTime::parse_from_rfc2822("Fri, 14 Jul 2017 02:40:00 +0000").unwrap(); +//! assert_eq!(dt.timestamp(), 1_500_000_000); +//! ``` +//! +//! ### Individual date +//! +//! Chrono also provides an individual date type ([**`Date`**](./struct.Date.html)). +//! It also has time zones attached, and have to be constructed via time zones. +//! Most operations available to `DateTime` are also available to `Date` whenever appropriate. +//! +//! ```rust +//! use chrono::prelude::*; +//! use chrono::offset::LocalResult; +//! +//! # // these *may* fail, but only very rarely. just rerun the test if you were that unfortunate ;) +//! assert_eq!(Utc::today(), Utc::now().date()); +//! assert_eq!(Local::today(), Local::now().date()); +//! +//! assert_eq!(Utc.ymd(2014, 11, 28).weekday(), Weekday::Fri); +//! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); +//! assert_eq!(Utc.ymd(2014, 11, 28).and_hms_milli(7, 8, 9, 10).format("%H%M%S").to_string(), +//! "070809"); +//! ``` +//! +//! There is no timezone-aware `Time` due to the lack of usefulness and also the complexity. +//! +//! `DateTime` has [`date`](./struct.DateTime.html#method.date) method +//! which returns a `Date` which represents its date component. +//! There is also a [`time`](./struct.DateTime.html#method.time) method, +//! which simply returns a naive local time described below. +//! +//! ### Naive date and time +//! +//! Chrono provides naive counterparts to `Date`, (non-existent) `Time` and `DateTime` +//! as [**`NaiveDate`**](./naive/struct.NaiveDate.html), +//! [**`NaiveTime`**](./naive/struct.NaiveTime.html) and +//! [**`NaiveDateTime`**](./naive/struct.NaiveDateTime.html) respectively. +//! +//! They have almost equivalent interfaces as their timezone-aware twins, +//! but are not associated to time zones obviously and can be quite low-level. +//! They are mostly useful for building blocks for higher-level types. +//! +//! Timezone-aware `DateTime` and `Date` types have two methods returning naive versions: +//! [`naive_local`](./struct.DateTime.html#method.naive_local) returns +//! a view to the naive local time, +//! and [`naive_utc`](./struct.DateTime.html#method.naive_utc) returns +//! a view to the naive UTC time. +//! +//! ## Limitations +//! +//! Only proleptic Gregorian calendar (i.e. extended to support older dates) is supported. +//! Be very careful if you really have to deal with pre-20C dates, they can be in Julian or others. +//! +//! Date types are limited in about +/- 262,000 years from the common epoch. +//! Time types are limited in the nanosecond accuracy. +//! +//! [Leap seconds are supported in the representation but +//! Chrono doesn't try to make use of them](./naive/struct.NaiveTime.html#leap-second-handling). +//! (The main reason is that leap seconds are not really predictable.) +//! Almost *every* operation over the possible leap seconds will ignore them. +//! Consider using `NaiveDateTime` with the implicit TAI (International Atomic Time) scale +//! if you want. +//! +//! Chrono inherently does not support an inaccurate or partial date and time representation. +//! Any operation that can be ambiguous will return `None` in such cases. +//! For example, "a month later" of 2014-01-30 is not well-defined +//! and consequently `Utc.ymd(2014, 1, 30).with_month(2)` returns `None`. +//! +//! Advanced time zone handling is not yet supported. +//! For now you can try the [Chrono-tz](https://github.com/chronotope/chrono-tz/) crate instead. + +#![doc(html_root_url = "https://docs.rs/chrono/latest/")] + +#![cfg_attr(bench, feature(test))] // lib stability features as per RFC #507 +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +// The explicit 'static lifetimes are still needed for rustc 1.13-16 +// backward compatibility, and this appeases clippy. If minimum rustc +// becomes 1.17, should be able to remove this, those 'static lifetimes, +// and use `static` in a lot of places `const` is used now. +// +// Similarly, redundant_field_names lints on not using the +// field-init-shorthand, which was stabilized in rust 1.17. +// +// Changing trivially_copy_pass_by_ref would require an incompatible version +// bump. +#![cfg_attr(feature = "cargo-clippy", allow( + const_static_lifetime, + redundant_field_names, + trivially_copy_pass_by_ref, +))] + +#[cfg(feature="clock")] +extern crate time as oldtime; +extern crate num_integer; +extern crate num_traits; +#[cfg(feature = "rustc-serialize")] +extern crate rustc_serialize; +#[cfg(feature = "serde")] +extern crate serde as serdelib; + +// this reexport is to aid the transition and should not be in the prelude! +pub use oldtime::Duration; + +#[cfg(feature="clock")] +#[doc(no_inline)] pub use offset::Local; +#[doc(no_inline)] pub use offset::{TimeZone, Offset, LocalResult, Utc, FixedOffset}; +#[doc(no_inline)] pub use naive::{NaiveDate, IsoWeek, NaiveTime, NaiveDateTime}; +pub use date::{Date, MIN_DATE, MAX_DATE}; +pub use datetime::{DateTime, SecondsFormat}; +#[cfg(feature = "rustc-serialize")] +pub use datetime::rustc_serialize::TsSeconds; +pub use format::{ParseError, ParseResult}; +pub use round::SubsecRound; + +/// A convenience module appropriate for glob imports (`use chrono::prelude::*;`). +pub mod prelude { + #[doc(no_inline)] pub use {Datelike, Timelike, Weekday}; + #[doc(no_inline)] pub use {TimeZone, Offset}; + #[cfg(feature="clock")] + #[doc(no_inline)] pub use Local; + #[doc(no_inline)] pub use {Utc, FixedOffset}; + #[doc(no_inline)] pub use {NaiveDate, NaiveTime, NaiveDateTime}; + #[doc(no_inline)] pub use Date; + #[doc(no_inline)] pub use {DateTime, SecondsFormat}; + #[doc(no_inline)] pub use SubsecRound; +} + +// useful throughout the codebase +macro_rules! try_opt { + ($e:expr) => (match $e { Some(v) => v, None => return None }) +} + +mod div; +#[cfg(not(feature="clock"))] +mod oldtime; +pub mod offset; +pub mod naive { + //! Date and time types which do not concern about the timezones. + //! + //! They are primarily building blocks for other types + //! (e.g. [`TimeZone`](../offset/trait.TimeZone.html)), + //! but can be also used for the simpler date and time handling. + + mod internals; + mod date; + mod isoweek; + mod time; + mod datetime; + + pub use self::date::{NaiveDate, MIN_DATE, MAX_DATE}; + pub use self::isoweek::IsoWeek; + pub use self::time::NaiveTime; + pub use self::datetime::NaiveDateTime; + #[cfg(feature = "rustc-serialize")] + #[allow(deprecated)] + pub use self::datetime::rustc_serialize::TsSeconds; + + + /// Serialization/Deserialization of naive types in alternate formats + /// + /// The various modules in here are intended to be used with serde's [`with` + /// annotation][1] to serialize as something other than the default [RFC + /// 3339][2] format. + /// + /// [1]: https://serde.rs/attributes.html#field-attributes + /// [2]: https://tools.ietf.org/html/rfc3339 + #[cfg(feature = "serde")] + pub mod serde { + pub use super::datetime::serde::*; + } +} +mod date; +mod datetime; +pub mod format; +mod round; + +/// Serialization/Deserialization in alternate formats +/// +/// The various modules in here are intended to be used with serde's [`with` +/// annotation][1] to serialize as something other than the default [RFC +/// 3339][2] format. +/// +/// [1]: https://serde.rs/attributes.html#field-attributes +/// [2]: https://tools.ietf.org/html/rfc3339 +#[cfg(feature = "serde")] +pub mod serde { + pub use super::datetime::serde::*; +} + +/// The day of week. +/// +/// The order of the days of week depends on the context. +/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.) +/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result. +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +pub enum Weekday { + /// Monday. + Mon = 0, + /// Tuesday. + Tue = 1, + /// Wednesday. + Wed = 2, + /// Thursday. + Thu = 3, + /// Friday. + Fri = 4, + /// Saturday. + Sat = 5, + /// Sunday. + Sun = 6, +} + +impl Weekday { + /// The next day in the week. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon` + #[inline] + pub fn succ(&self) -> Weekday { + match *self { + Weekday::Mon => Weekday::Tue, + Weekday::Tue => Weekday::Wed, + Weekday::Wed => Weekday::Thu, + Weekday::Thu => Weekday::Fri, + Weekday::Fri => Weekday::Sat, + Weekday::Sat => Weekday::Sun, + Weekday::Sun => Weekday::Mon, + } + } + + /// The previous day in the week. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` + #[inline] + pub fn pred(&self) -> Weekday { + match *self { + Weekday::Mon => Weekday::Sun, + Weekday::Tue => Weekday::Mon, + Weekday::Wed => Weekday::Tue, + Weekday::Thu => Weekday::Wed, + Weekday::Fri => Weekday::Thu, + Weekday::Sat => Weekday::Fri, + Weekday::Sun => Weekday::Sat, + } + } + + /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number) + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7 + #[inline] + pub fn number_from_monday(&self) -> u32 { + match *self { + Weekday::Mon => 1, + Weekday::Tue => 2, + Weekday::Wed => 3, + Weekday::Thu => 4, + Weekday::Fri => 5, + Weekday::Sat => 6, + Weekday::Sun => 7, + } + } + + /// Returns a day-of-week number starting from Sunday = 1. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1 + #[inline] + pub fn number_from_sunday(&self) -> u32 { + match *self { + Weekday::Mon => 2, + Weekday::Tue => 3, + Weekday::Wed => 4, + Weekday::Thu => 5, + Weekday::Fri => 6, + Weekday::Sat => 7, + Weekday::Sun => 1, + } + } + + /// Returns a day-of-week number starting from Monday = 0. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6 + #[inline] + pub fn num_days_from_monday(&self) -> u32 { + match *self { + Weekday::Mon => 0, + Weekday::Tue => 1, + Weekday::Wed => 2, + Weekday::Thu => 3, + Weekday::Fri => 4, + Weekday::Sat => 5, + Weekday::Sun => 6, + } + } + + /// Returns a day-of-week number starting from Sunday = 0. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0 + #[inline] + pub fn num_days_from_sunday(&self) -> u32 { + match *self { + Weekday::Mon => 1, + Weekday::Tue => 2, + Weekday::Wed => 3, + Weekday::Thu => 4, + Weekday::Fri => 5, + Weekday::Sat => 6, + Weekday::Sun => 0, + } + } +} + +/// Any weekday can be represented as an integer from 0 to 6, which equals to +/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. +/// Do not heavily depend on this though; use explicit methods whenever possible. +impl num_traits::FromPrimitive for Weekday { + #[inline] + fn from_i64(n: i64) -> Option { + match n { + 0 => Some(Weekday::Mon), + 1 => Some(Weekday::Tue), + 2 => Some(Weekday::Wed), + 3 => Some(Weekday::Thu), + 4 => Some(Weekday::Fri), + 5 => Some(Weekday::Sat), + 6 => Some(Weekday::Sun), + _ => None, + } + } + + #[inline] + fn from_u64(n: u64) -> Option { + match n { + 0 => Some(Weekday::Mon), + 1 => Some(Weekday::Tue), + 2 => Some(Weekday::Wed), + 3 => Some(Weekday::Thu), + 4 => Some(Weekday::Fri), + 5 => Some(Weekday::Sat), + 6 => Some(Weekday::Sun), + _ => None, + } + } +} + +use std::fmt; + +/// An error resulting from reading `Weekday` value with `FromStr`. +#[derive(Clone, PartialEq)] +pub struct ParseWeekdayError { + _dummy: (), +} + +impl fmt::Debug for ParseWeekdayError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ParseWeekdayError {{ .. }}") + } +} + +// the actual `FromStr` implementation is in the `format` module to leverage the existing code + +#[cfg(feature = "serde")] +mod weekday_serde { + use super::Weekday; + use std::fmt; + use serdelib::{ser, de}; + + impl ser::Serialize for Weekday { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_str(&format!("{:?}", self)) + } + } + + struct WeekdayVisitor; + + impl<'de> de::Visitor<'de> for WeekdayVisitor { + type Value = Weekday; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Weekday") + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|_| E::custom("short or long weekday names expected")) + } + } + + impl<'de> de::Deserialize<'de> for Weekday { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(WeekdayVisitor) + } + } + + #[cfg(test)] + extern crate serde_json; + + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + use Weekday::*; + + let cases: Vec<(Weekday, &str)> = vec![ + (Mon, "\"Mon\""), + (Tue, "\"Tue\""), + (Wed, "\"Wed\""), + (Thu, "\"Thu\""), + (Fri, "\"Fri\""), + (Sat, "\"Sat\""), + (Sun, "\"Sun\""), + ]; + + for (weekday, expected_str) in cases { + let string = to_string(&weekday).unwrap(); + assert_eq!(string, expected_str); + } + } + + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + use Weekday::*; + + let cases: Vec<(&str, Weekday)> = vec![ + ("\"mon\"", Mon), + ("\"MONDAY\"", Mon), + ("\"MonDay\"", Mon), + ("\"mOn\"", Mon), + ("\"tue\"", Tue), + ("\"tuesday\"", Tue), + ("\"wed\"", Wed), + ("\"wednesday\"", Wed), + ("\"thu\"", Thu), + ("\"thursday\"", Thu), + ("\"fri\"", Fri), + ("\"friday\"", Fri), + ("\"sat\"", Sat), + ("\"saturday\"", Sat), + ("\"sun\"", Sun), + ("\"sunday\"", Sun), + ]; + + for (str, expected_weekday) in cases { + let weekday = from_str::(str).unwrap(); + assert_eq!(weekday, expected_weekday); + } + + let errors: Vec<&str> = vec![ + "\"not a weekday\"", + "\"monDAYs\"", + "\"mond\"", + "mon", + "\"thur\"", + "\"thurs\"", + ]; + + for str in errors { + from_str::(str).unwrap_err(); + } + } +} + +/// The common set of methods for date component. +pub trait Datelike: Sized { + /// Returns the year number in the [calendar date](./naive/struct.NaiveDate.html#calendar-date). + fn year(&self) -> i32; + + /// Returns the absolute year number starting from 1 with a boolean flag, + /// which is false when the year predates the epoch (BCE/BC) and true otherwise (CE/AD). + #[inline] + fn year_ce(&self) -> (bool, u32) { + let year = self.year(); + if year < 1 { + (false, (1 - year) as u32) + } else { + (true, year as u32) + } + } + + /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. + fn month(&self) -> u32; + + /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. + fn month0(&self) -> u32; + + /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) + fn day(&self) -> u32; + + /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) + fn day0(&self) -> u32; + + /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) + fn ordinal(&self) -> u32; + + /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) + fn ordinal0(&self) -> u32; + + /// Returns the day of week. + fn weekday(&self) -> Weekday; + + /// Returns the ISO week. + fn iso_week(&self) -> IsoWeek; + + /// Makes a new value with the year number changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_year(&self, year: i32) -> Option; + + /// Makes a new value with the month number (starting from 1) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_month(&self, month: u32) -> Option; + + /// Makes a new value with the month number (starting from 0) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_month0(&self, month0: u32) -> Option; + + /// Makes a new value with the day of month (starting from 1) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_day(&self, day: u32) -> Option; + + /// Makes a new value with the day of month (starting from 0) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_day0(&self, day0: u32) -> Option; + + /// Makes a new value with the day of year (starting from 1) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_ordinal(&self, ordinal: u32) -> Option; + + /// Makes a new value with the day of year (starting from 0) changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_ordinal0(&self, ordinal0: u32) -> Option; + + /// Returns the number of days since January 1, Year 1 (aka Day 1) in the + /// proleptic Gregorian calendar. + /// + /// # Example: + /// + /// ~~~ + /// use chrono::{NaiveDate, Datelike}; + /// assert_eq!(NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce(), 719163); + /// assert_eq!(NaiveDate::from_ymd(0, 1, 1).num_days_from_ce(), -365); + /// ~~~ + fn num_days_from_ce(&self) -> i32 { + // we know this wouldn't overflow since year is limited to 1/2^13 of i32's full range. + let mut year = self.year() - 1; + let mut ndays = 0; + if year < 0 { + let excess = 1 + (-year) / 400; + year += excess * 400; + ndays -= excess * 146_097; + } + let div_100 = year / 100; + ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2); + ndays + self.ordinal() as i32 + } +} + +/// The common set of methods for time component. +pub trait Timelike: Sized { + /// Returns the hour number from 0 to 23. + fn hour(&self) -> u32; + + /// Returns the hour number from 1 to 12 with a boolean flag, + /// which is false for AM and true for PM. + #[inline] + fn hour12(&self) -> (bool, u32) { + let hour = self.hour(); + let mut hour12 = hour % 12; + if hour12 == 0 { + hour12 = 12; + } + (hour >= 12, hour12) + } + + /// Returns the minute number from 0 to 59. + fn minute(&self) -> u32; + + /// Returns the second number from 0 to 59. + fn second(&self) -> u32; + + /// Returns the number of nanoseconds since the whole non-leap second. + /// The range from 1,000,000,000 to 1,999,999,999 represents + /// the [leap second](./naive/struct.NaiveTime.html#leap-second-handling). + fn nanosecond(&self) -> u32; + + /// Makes a new value with the hour number changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_hour(&self, hour: u32) -> Option; + + /// Makes a new value with the minute number changed. + /// + /// Returns `None` when the resulting value would be invalid. + fn with_minute(&self, min: u32) -> Option; + + /// Makes a new value with the second number changed. + /// + /// Returns `None` when the resulting value would be invalid. + /// As with the [`second`](#tymethod.second) method, + /// the input range is restricted to 0 through 59. + fn with_second(&self, sec: u32) -> Option; + + /// Makes a new value with nanoseconds since the whole non-leap second changed. + /// + /// Returns `None` when the resulting value would be invalid. + /// As with the [`nanosecond`](#tymethod.nanosecond) method, + /// the input range can exceed 1,000,000,000 for leap seconds. + fn with_nanosecond(&self, nano: u32) -> Option; + + /// Returns the number of non-leap seconds past the last midnight. + #[inline] + fn num_seconds_from_midnight(&self) -> u32 { + self.hour() * 3600 + self.minute() * 60 + self.second() + } +} + +#[cfg(test)] extern crate num_iter; + +#[test] +fn test_readme_doomsday() { + use num_iter::range_inclusive; + + for y in range_inclusive(naive::MIN_DATE.year(), naive::MAX_DATE.year()) { + // even months + let d4 = NaiveDate::from_ymd(y, 4, 4); + let d6 = NaiveDate::from_ymd(y, 6, 6); + let d8 = NaiveDate::from_ymd(y, 8, 8); + let d10 = NaiveDate::from_ymd(y, 10, 10); + let d12 = NaiveDate::from_ymd(y, 12, 12); + + // nine to five, seven-eleven + let d59 = NaiveDate::from_ymd(y, 5, 9); + let d95 = NaiveDate::from_ymd(y, 9, 5); + let d711 = NaiveDate::from_ymd(y, 7, 11); + let d117 = NaiveDate::from_ymd(y, 11, 7); + + // "March 0" + let d30 = NaiveDate::from_ymd(y, 3, 1).pred(); + + let weekday = d30.weekday(); + let other_dates = [d4, d6, d8, d10, d12, d59, d95, d711, d117]; + assert!(other_dates.iter().all(|d| d.weekday() == weekday)); + } +} diff --git a/chrono/src/naive/date.rs b/chrono/src/naive/date.rs new file mode 100644 index 000000000..aad98bc60 --- /dev/null +++ b/chrono/src/naive/date.rs @@ -0,0 +1,2121 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 calendar date without timezone. + +use std::{str, fmt}; +use std::ops::{Add, Sub, AddAssign, SubAssign}; +use num_traits::ToPrimitive; +use oldtime::Duration as OldDuration; + +use {Weekday, Datelike}; +use div::div_mod_floor; +use naive::{NaiveTime, NaiveDateTime, IsoWeek}; +use format::{Item, Numeric, Pad}; +use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; + +use super::isoweek; +use super::internals::{self, DateImpl, Of, Mdf, YearFlags}; + +const MAX_YEAR: i32 = internals::MAX_YEAR; +const MIN_YEAR: i32 = internals::MIN_YEAR; + +// MAX_YEAR-12-31 minus 0000-01-01 +// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + (0001-01-01 minus 0000-01-01) - 1 day +// = ((MAX_YEAR+1)-01-01 minus 0001-01-01) + 365 days +// = MAX_YEAR * 365 + (# of leap years from 0001 to MAX_YEAR) + 365 days +#[cfg(test)] // only used for testing +const MAX_DAYS_FROM_YEAR_0: i32 = MAX_YEAR * 365 + + MAX_YEAR / 4 - + MAX_YEAR / 100 + + MAX_YEAR / 400 + 365; + +// MIN_YEAR-01-01 minus 0000-01-01 +// = (MIN_YEAR+400n+1)-01-01 minus (400n+1)-01-01 +// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - ((400n+1)-01-01 minus 0001-01-01) +// = ((MIN_YEAR+400n+1)-01-01 minus 0001-01-01) - 146097n days +// +// n is set to 1000 for convenience. +#[cfg(test)] // only used for testing +const MIN_DAYS_FROM_YEAR_0: i32 = (MIN_YEAR + 400_000) * 365 + + (MIN_YEAR + 400_000) / 4 - + (MIN_YEAR + 400_000) / 100 + + (MIN_YEAR + 400_000) / 400 - 146097_000; + +#[cfg(test)] // only used for testing, but duplicated in naive::datetime +const MAX_BITS: usize = 44; + +/// ISO 8601 calendar date without timezone. +/// Allows for every [proleptic Gregorian date](#calendar-date) +/// from Jan 1, 262145 BCE to Dec 31, 262143 CE. +/// Also supports the conversion from ISO 8601 ordinal and week date. +/// +/// # Calendar Date +/// +/// The ISO 8601 **calendar date** follows the proleptic Gregorian calendar. +/// It is like a normal civil calendar but note some slight differences: +/// +/// * Dates before the Gregorian calendar's inception in 1582 are defined via the extrapolation. +/// Be careful, as historical dates are often noted in the Julian calendar and others +/// and the transition to Gregorian may differ across countries (as late as early 20C). +/// +/// (Some example: Both Shakespeare from Britain and Cervantes from Spain seemingly died +/// on the same calendar date---April 23, 1616---but in the different calendar. +/// Britain used the Julian calendar at that time, so Shakespeare's death is later.) +/// +/// * ISO 8601 calendars has the year 0, which is 1 BCE (a year before 1 CE). +/// If you need a typical BCE/BC and CE/AD notation for year numbers, +/// use the [`Datelike::year_ce`](../trait.Datelike.html#method.year_ce) method. +/// +/// # Week Date +/// +/// The ISO 8601 **week date** is a triple of year number, week number +/// and [day of the week](../enum.Weekday.html) with the following rules: +/// +/// * A week consists of Monday through Sunday, and is always numbered within some year. +/// The week number ranges from 1 to 52 or 53 depending on the year. +/// +/// * The week 1 of given year is defined as the first week containing January 4 of that year, +/// or equivalently, the first week containing four or more days in that year. +/// +/// * The year number in the week date may *not* correspond to the actual Gregorian year. +/// For example, January 3, 2016 (Sunday) was on the last (53rd) week of 2015. +/// +/// Chrono's date types default to the ISO 8601 [calendar date](#calendar-date), +/// but [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) and +/// [`Datelike::weekday`](../trait.Datelike.html#tymethod.weekday) methods +/// can be used to get the corresponding week date. +/// +/// # Ordinal Date +/// +/// The ISO 8601 **ordinal date** is a pair of year number and day of the year ("ordinal"). +/// The ordinal number ranges from 1 to 365 or 366 depending on the year. +/// The year number is same to that of the [calendar date](#calendar-date). +/// +/// This is currently the internal format of Chrono's date types. +#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)] +pub struct NaiveDate { + ymdf: DateImpl, // (year << 13) | of +} + +/// The minimum possible `NaiveDate` (January 1, 262145 BCE). +pub const MIN_DATE: NaiveDate = NaiveDate { ymdf: (MIN_YEAR << 13) | (1 << 4) | 0o07 /*FE*/ }; +/// The maximum possible `NaiveDate` (December 31, 262143 CE). +pub const MAX_DATE: NaiveDate = NaiveDate { ymdf: (MAX_YEAR << 13) | (365 << 4) | 0o17 /*F*/ }; + +// as it is hard to verify year flags in `MIN_DATE` and `MAX_DATE`, +// we use a separate run-time test. +#[test] +fn test_date_bounds() { + let calculated_min = NaiveDate::from_ymd(MIN_YEAR, 1, 1); + let calculated_max = NaiveDate::from_ymd(MAX_YEAR, 12, 31); + assert!(MIN_DATE == calculated_min, + "`MIN_DATE` should have a year flag {:?}", calculated_min.of().flags()); + assert!(MAX_DATE == calculated_max, + "`MAX_DATE` should have a year flag {:?}", calculated_max.of().flags()); + + // let's also check that the entire range do not exceed 2^44 seconds + // (sometimes used for bounding `Duration` against overflow) + let maxsecs = MAX_DATE.signed_duration_since(MIN_DATE).num_seconds(); + let maxsecs = maxsecs + 86401; // also take care of DateTime + assert!(maxsecs < (1 << MAX_BITS), + "The entire `NaiveDate` range somehow exceeds 2^{} seconds", MAX_BITS); +} + +impl NaiveDate { + /// Makes a new `NaiveDate` from year and packed ordinal-flags, with a verification. + fn from_of(year: i32, of: Of) -> Option { + if year >= MIN_YEAR && year <= MAX_YEAR && of.valid() { + let Of(of) = of; + Some(NaiveDate { ymdf: (year << 13) | (of as DateImpl) }) + } else { + None + } + } + + /// Makes a new `NaiveDate` from year and packed month-day-flags, with a verification. + fn from_mdf(year: i32, mdf: Mdf) -> Option { + NaiveDate::from_of(year, mdf.to_of()) + } + + /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) + /// (year, month and day). + /// + /// Panics on the out-of-range date, invalid month and/or day. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 3, 14); + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.ordinal(), 73); // day of year + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE + /// ~~~~ + pub fn from_ymd(year: i32, month: u32, day: u32) -> NaiveDate { + NaiveDate::from_ymd_opt(year, month, day).expect("invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [calendar date](#calendar-date) + /// (year, month and day). + /// + /// Returns `None` on the out-of-range date, invalid month and/or day. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let from_ymd_opt = NaiveDate::from_ymd_opt; + /// + /// assert!(from_ymd_opt(2015, 3, 14).is_some()); + /// assert!(from_ymd_opt(2015, 0, 14).is_none()); + /// assert!(from_ymd_opt(2015, 2, 29).is_none()); + /// assert!(from_ymd_opt(-4, 2, 29).is_some()); // 5 BCE is a leap year + /// assert!(from_ymd_opt(400000, 1, 1).is_none()); + /// assert!(from_ymd_opt(-400000, 1, 1).is_none()); + /// ~~~~ + pub fn from_ymd_opt(year: i32, month: u32, day: u32) -> Option { + let flags = YearFlags::from_year(year); + NaiveDate::from_mdf(year, Mdf::new(month, day, flags)) + } + + /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) + /// (year and day of the year). + /// + /// Panics on the out-of-range date and/or invalid day of year. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_yo(2015, 73); + /// assert_eq!(d.ordinal(), 73); + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE + /// ~~~~ + pub fn from_yo(year: i32, ordinal: u32) -> NaiveDate { + NaiveDate::from_yo_opt(year, ordinal).expect("invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [ordinal date](#ordinal-date) + /// (year and day of the year). + /// + /// Returns `None` on the out-of-range date and/or invalid day of year. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let from_yo_opt = NaiveDate::from_yo_opt; + /// + /// assert!(from_yo_opt(2015, 100).is_some()); + /// assert!(from_yo_opt(2015, 0).is_none()); + /// assert!(from_yo_opt(2015, 365).is_some()); + /// assert!(from_yo_opt(2015, 366).is_none()); + /// assert!(from_yo_opt(-4, 366).is_some()); // 5 BCE is a leap year + /// assert!(from_yo_opt(400000, 1).is_none()); + /// assert!(from_yo_opt(-400000, 1).is_none()); + /// ~~~~ + pub fn from_yo_opt(year: i32, ordinal: u32) -> Option { + let flags = YearFlags::from_year(year); + NaiveDate::from_of(year, Of::new(ordinal, flags)) + } + + /// Makes a new `NaiveDate` from the [ISO week date](#week-date) + /// (year, week number and day of the week). + /// The resulting `NaiveDate` may have a different year from the input year. + /// + /// Panics on the out-of-range date and/or invalid week number. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_isoywd(2015, 11, Weekday::Sat); + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.ordinal(), 73); // day of year + /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE + /// ~~~~ + pub fn from_isoywd(year: i32, week: u32, weekday: Weekday) -> NaiveDate { + NaiveDate::from_isoywd_opt(year, week, weekday).expect("invalid or out-of-range date") + } + + /// Makes a new `NaiveDate` from the [ISO week date](#week-date) + /// (year, week number and day of the week). + /// The resulting `NaiveDate` may have a different year from the input year. + /// + /// Returns `None` on the out-of-range date and/or invalid week number. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Weekday}; + /// + /// let from_ymd = NaiveDate::from_ymd; + /// let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// + /// assert_eq!(from_isoywd_opt(2015, 0, Weekday::Sun), None); + /// assert_eq!(from_isoywd_opt(2015, 10, Weekday::Sun), Some(from_ymd(2015, 3, 8))); + /// assert_eq!(from_isoywd_opt(2015, 30, Weekday::Mon), Some(from_ymd(2015, 7, 20))); + /// assert_eq!(from_isoywd_opt(2015, 60, Weekday::Mon), None); + /// + /// assert_eq!(from_isoywd_opt(400000, 10, Weekday::Fri), None); + /// assert_eq!(from_isoywd_opt(-400000, 10, Weekday::Sat), None); + /// ~~~~ + /// + /// The year number of ISO week date may differ from that of the calendar date. + /// + /// ~~~~ + /// # use chrono::{NaiveDate, Weekday}; + /// # let from_ymd = NaiveDate::from_ymd; + /// # let from_isoywd_opt = NaiveDate::from_isoywd_opt; + /// // Mo Tu We Th Fr Sa Su + /// // 2014-W52 22 23 24 25 26 27 28 has 4+ days of new year, + /// // 2015-W01 29 30 31 1 2 3 4 <- so this is the first week + /// assert_eq!(from_isoywd_opt(2014, 52, Weekday::Sun), Some(from_ymd(2014, 12, 28))); + /// assert_eq!(from_isoywd_opt(2014, 53, Weekday::Mon), None); + /// assert_eq!(from_isoywd_opt(2015, 1, Weekday::Mon), Some(from_ymd(2014, 12, 29))); + /// + /// // 2015-W52 21 22 23 24 25 26 27 has 4+ days of old year, + /// // 2015-W53 28 29 30 31 1 2 3 <- so this is the last week + /// // 2016-W01 4 5 6 7 8 9 10 + /// assert_eq!(from_isoywd_opt(2015, 52, Weekday::Sun), Some(from_ymd(2015, 12, 27))); + /// assert_eq!(from_isoywd_opt(2015, 53, Weekday::Sun), Some(from_ymd(2016, 1, 3))); + /// assert_eq!(from_isoywd_opt(2015, 54, Weekday::Mon), None); + /// assert_eq!(from_isoywd_opt(2016, 1, Weekday::Mon), Some(from_ymd(2016, 1, 4))); + /// ~~~~ + pub fn from_isoywd_opt(year: i32, week: u32, weekday: Weekday) -> Option { + let flags = YearFlags::from_year(year); + let nweeks = flags.nisoweeks(); + if 1 <= week && week <= nweeks { + // ordinal = week ordinal - delta + let weekord = week * 7 + weekday as u32; + let delta = flags.isoweek_delta(); + if weekord <= delta { // ordinal < 1, previous year + let prevflags = YearFlags::from_year(year - 1); + NaiveDate::from_of(year - 1, Of::new(weekord + prevflags.ndays() - delta, + prevflags)) + } else { + let ordinal = weekord - delta; + let ndays = flags.ndays(); + if ordinal <= ndays { // this year + NaiveDate::from_of(year, Of::new(ordinal, flags)) + } else { // ordinal > ndays, next year + let nextflags = YearFlags::from_year(year + 1); + NaiveDate::from_of(year + 1, Of::new(ordinal - ndays, nextflags)) + } + } + } else { + None + } + } + + /// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1) + /// in the proleptic Gregorian calendar. + /// + /// Panics on the out-of-range date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_num_days_from_ce(735671); + /// assert_eq!(d.num_days_from_ce(), 735671); // days since January 1, 1 CE + /// assert_eq!(d.year(), 2015); + /// assert_eq!(d.month(), 3); + /// assert_eq!(d.day(), 14); + /// assert_eq!(d.ordinal(), 73); // day of year + /// assert_eq!(d.iso_week().year(), 2015); + /// assert_eq!(d.iso_week().week(), 11); + /// assert_eq!(d.weekday(), Weekday::Sat); + /// ~~~~ + /// + /// While not directly supported by Chrono, + /// it is easy to convert from the Julian day number + /// (January 1, 4713 BCE in the *Julian* calendar being Day 0) + /// to Gregorian with this method. + /// (Note that this panics when `jd` is out of range.) + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// fn jd_to_date(jd: i32) -> NaiveDate { + /// // keep in mind that the Julian day number is 0-based + /// // while this method requires an 1-based number. + /// NaiveDate::from_num_days_from_ce(jd - 1721425) + /// } + /// + /// // January 1, 4713 BCE in Julian = November 24, 4714 BCE in Gregorian + /// assert_eq!(jd_to_date(0), NaiveDate::from_ymd(-4713, 11, 24)); + /// + /// assert_eq!(jd_to_date(1721426), NaiveDate::from_ymd(1, 1, 1)); + /// assert_eq!(jd_to_date(2450000), NaiveDate::from_ymd(1995, 10, 9)); + /// assert_eq!(jd_to_date(2451545), NaiveDate::from_ymd(2000, 1, 1)); + /// ~~~~ + #[inline] + pub fn from_num_days_from_ce(days: i32) -> NaiveDate { + NaiveDate::from_num_days_from_ce_opt(days).expect("out-of-range date") + } + + /// Makes a new `NaiveDate` from the number of days since January 1, 1 (Day 1) + /// in the proleptic Gregorian calendar. + /// + /// Returns `None` on the out-of-range date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let from_ndays_opt = NaiveDate::from_num_days_from_ce_opt; + /// let from_ymd = NaiveDate::from_ymd; + /// + /// assert_eq!(from_ndays_opt(730_000), Some(from_ymd(1999, 9, 3))); + /// assert_eq!(from_ndays_opt(1), Some(from_ymd(1, 1, 1))); + /// assert_eq!(from_ndays_opt(0), Some(from_ymd(0, 12, 31))); + /// assert_eq!(from_ndays_opt(-1), Some(from_ymd(0, 12, 30))); + /// assert_eq!(from_ndays_opt(100_000_000), None); + /// assert_eq!(from_ndays_opt(-100_000_000), None); + /// ~~~~ + pub fn from_num_days_from_ce_opt(days: i32) -> Option { + let days = days + 365; // make December 31, 1 BCE equal to day 0 + let (year_div_400, cycle) = div_mod_floor(days, 146_097); + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, + Of::new(ordinal, flags)) + } + + /// Parses a string with the specified format string and returns a new `NaiveDate`. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let parse_from_str = NaiveDate::parse_from_str; + /// + /// assert_eq!(parse_from_str("2015-09-05", "%Y-%m-%d"), + /// Ok(NaiveDate::from_ymd(2015, 9, 5))); + /// assert_eq!(parse_from_str("5sep2015", "%d%b%Y"), + /// Ok(NaiveDate::from_ymd(2015, 9, 5))); + /// ~~~~ + /// + /// Time and offset is ignored for the purpose of parsing. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + /// Ok(NaiveDate::from_ymd(2014, 5, 17))); + /// ~~~~ + /// + /// Out-of-bound dates or insufficient fields are errors. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert!(parse_from_str("2015/9", "%Y/%m").is_err()); + /// assert!(parse_from_str("2015/9/31", "%Y/%m/%d").is_err()); + /// ~~~~ + /// + /// All parsed fields should be consistent to each other, otherwise it's an error. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # let parse_from_str = NaiveDate::parse_from_str; + /// assert!(parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); + /// ~~~~ + pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); + parsed.to_naive_date() + } + + /// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789); + /// + /// let dt: NaiveDateTime = d.and_time(t); + /// assert_eq!(dt.date(), d); + /// assert_eq!(dt.time(), t); + /// ~~~~ + #[inline] + pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime { + NaiveDateTime::new(*self, time) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. + /// + /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; + /// use `NaiveDate::and_hms_*` methods with a subsecond parameter instead. + /// + /// Panics on invalid hour, minute and/or second. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// + /// let dt: NaiveDateTime = d.and_hms(12, 34, 56); + /// assert_eq!(dt.year(), 2015); + /// assert_eq!(dt.weekday(), Weekday::Wed); + /// assert_eq!(dt.second(), 56); + /// ~~~~ + #[inline] + pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { + self.and_hms_opt(hour, min, sec).expect("invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute and second. + /// + /// No [leap second](./struct.NaiveTime.html#leap-second-handling) is allowed here; + /// use `NaiveDate::and_hms_*_opt` methods with a subsecond parameter instead. + /// + /// Returns `None` on invalid hour, minute and/or second. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// assert!(d.and_hms_opt(12, 34, 56).is_some()); + /// assert!(d.and_hms_opt(12, 34, 60).is_none()); // use `and_hms_milli_opt` instead + /// assert!(d.and_hms_opt(12, 60, 56).is_none()); + /// assert!(d.and_hms_opt(24, 34, 56).is_none()); + /// ~~~~ + #[inline] + pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option { + NaiveTime::from_hms_opt(hour, min, sec).map(|time| self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. + /// + /// The millisecond part can exceed 1,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or millisecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// + /// let dt: NaiveDateTime = d.and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.year(), 2015); + /// assert_eq!(dt.weekday(), Weekday::Wed); + /// assert_eq!(dt.second(), 56); + /// assert_eq!(dt.nanosecond(), 789_000_000); + /// ~~~~ + #[inline] + pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> NaiveDateTime { + self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and millisecond. + /// + /// The millisecond part can exceed 1,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or millisecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// assert!(d.and_hms_milli_opt(12, 34, 56, 789).is_some()); + /// assert!(d.and_hms_milli_opt(12, 34, 59, 1_789).is_some()); // leap second + /// assert!(d.and_hms_milli_opt(12, 34, 59, 2_789).is_none()); + /// assert!(d.and_hms_milli_opt(12, 34, 60, 789).is_none()); + /// assert!(d.and_hms_milli_opt(12, 60, 56, 789).is_none()); + /// assert!(d.and_hms_milli_opt(24, 34, 56, 789).is_none()); + /// ~~~~ + #[inline] + pub fn and_hms_milli_opt(&self, hour: u32, min: u32, sec: u32, + milli: u32) -> Option { + NaiveTime::from_hms_milli_opt(hour, min, sec, milli).map(|time| self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. + /// + /// The microsecond part can exceed 1,000,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// + /// let dt: NaiveDateTime = d.and_hms_micro(12, 34, 56, 789_012); + /// assert_eq!(dt.year(), 2015); + /// assert_eq!(dt.weekday(), Weekday::Wed); + /// assert_eq!(dt.second(), 56); + /// assert_eq!(dt.nanosecond(), 789_012_000); + /// ~~~~ + #[inline] + pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> NaiveDateTime { + self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and microsecond. + /// + /// The microsecond part can exceed 1,000,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// assert!(d.and_hms_micro_opt(12, 34, 56, 789_012).is_some()); + /// assert!(d.and_hms_micro_opt(12, 34, 59, 1_789_012).is_some()); // leap second + /// assert!(d.and_hms_micro_opt(12, 34, 59, 2_789_012).is_none()); + /// assert!(d.and_hms_micro_opt(12, 34, 60, 789_012).is_none()); + /// assert!(d.and_hms_micro_opt(12, 60, 56, 789_012).is_none()); + /// assert!(d.and_hms_micro_opt(24, 34, 56, 789_012).is_none()); + /// ~~~~ + #[inline] + pub fn and_hms_micro_opt(&self, hour: u32, min: u32, sec: u32, + micro: u32) -> Option { + NaiveTime::from_hms_micro_opt(hour, min, sec, micro).map(|time| self.and_time(time)) + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Timelike, Weekday}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// + /// let dt: NaiveDateTime = d.and_hms_nano(12, 34, 56, 789_012_345); + /// assert_eq!(dt.year(), 2015); + /// assert_eq!(dt.weekday(), Weekday::Wed); + /// assert_eq!(dt.second(), 56); + /// assert_eq!(dt.nanosecond(), 789_012_345); + /// ~~~~ + #[inline] + pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> NaiveDateTime { + self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time") + } + + /// Makes a new `NaiveDateTime` from the current date, hour, minute, second and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// assert!(d.and_hms_nano_opt(12, 34, 56, 789_012_345).is_some()); + /// assert!(d.and_hms_nano_opt(12, 34, 59, 1_789_012_345).is_some()); // leap second + /// assert!(d.and_hms_nano_opt(12, 34, 59, 2_789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(12, 34, 60, 789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(12, 60, 56, 789_012_345).is_none()); + /// assert!(d.and_hms_nano_opt(24, 34, 56, 789_012_345).is_none()); + /// ~~~~ + #[inline] + pub fn and_hms_nano_opt(&self, hour: u32, min: u32, sec: u32, + nano: u32) -> Option { + NaiveTime::from_hms_nano_opt(hour, min, sec, nano).map(|time| self.and_time(time)) + } + + /// Returns the packed month-day-flags. + #[inline] + fn mdf(&self) -> Mdf { + self.of().to_mdf() + } + + /// Returns the packed ordinal-flags. + #[inline] + fn of(&self) -> Of { + Of((self.ymdf & 0b1_1111_1111_1111) as u32) + } + + /// Makes a new `NaiveDate` with the packed month-day-flags changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + #[inline] + fn with_mdf(&self, mdf: Mdf) -> Option { + self.with_of(mdf.to_of()) + } + + /// Makes a new `NaiveDate` with the packed ordinal-flags changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + #[inline] + fn with_of(&self, of: Of) -> Option { + if of.valid() { + let Of(of) = of; + Some(NaiveDate { ymdf: (self.ymdf & !0b1_1111_1111_1111) | of as DateImpl }) + } else { + None + } + } + + /// Makes a new `NaiveDate` for the next calendar date. + /// + /// Panics when `self` is the last representable date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ(), NaiveDate::from_ymd(2015, 6, 4)); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 30).succ(), NaiveDate::from_ymd(2015, 7, 1)); + /// assert_eq!(NaiveDate::from_ymd(2015, 12, 31).succ(), NaiveDate::from_ymd(2016, 1, 1)); + /// ~~~~ + #[inline] + pub fn succ(&self) -> NaiveDate { + self.succ_opt().expect("out of bound") + } + + /// Makes a new `NaiveDate` for the next calendar date. + /// + /// Returns `None` when `self` is the last representable date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// use chrono::naive::MAX_DATE; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).succ_opt(), + /// Some(NaiveDate::from_ymd(2015, 6, 4))); + /// assert_eq!(MAX_DATE.succ_opt(), None); + /// ~~~~ + #[inline] + pub fn succ_opt(&self) -> Option { + self.with_of(self.of().succ()).or_else(|| NaiveDate::from_ymd_opt(self.year() + 1, 1, 1)) + } + + /// Makes a new `NaiveDate` for the previous calendar date. + /// + /// Panics when `self` is the first representable date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred(), NaiveDate::from_ymd(2015, 6, 2)); + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 1).pred(), NaiveDate::from_ymd(2015, 5, 31)); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).pred(), NaiveDate::from_ymd(2014, 12, 31)); + /// ~~~~ + #[inline] + pub fn pred(&self) -> NaiveDate { + self.pred_opt().expect("out of bound") + } + + /// Makes a new `NaiveDate` for the previous calendar date. + /// + /// Returns `None` when `self` is the first representable date. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// use chrono::naive::MIN_DATE; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 6, 3).pred_opt(), + /// Some(NaiveDate::from_ymd(2015, 6, 2))); + /// assert_eq!(MIN_DATE.pred_opt(), None); + /// ~~~~ + #[inline] + pub fn pred_opt(&self) -> Option { + self.with_of(self.of().pred()).or_else(|| NaiveDate::from_ymd_opt(self.year() - 1, 12, 31)) + } + + /// Adds the `days` part of given `Duration` to the current date. + /// + /// Returns `None` when it will result in overflow. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use chrono::naive::MAX_DATE; + /// use time::Duration; + /// + /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(d.checked_add_signed(Duration::days(40)), + /// Some(NaiveDate::from_ymd(2015, 10, 15))); + /// assert_eq!(d.checked_add_signed(Duration::days(-40)), + /// Some(NaiveDate::from_ymd(2015, 7, 27))); + /// assert_eq!(d.checked_add_signed(Duration::days(1_000_000_000)), None); + /// assert_eq!(d.checked_add_signed(Duration::days(-1_000_000_000)), None); + /// assert_eq!(MAX_DATE.checked_add_signed(Duration::days(1)), None); + /// # } + /// ~~~~ + pub fn checked_add_signed(self, rhs: OldDuration) -> Option { + let year = self.year(); + let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); + let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); + let cycle = try_opt!((cycle as i32).checked_add(try_opt!(rhs.num_days().to_i32()))); + let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); + year_div_400 += cycle_div_400y; + + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, + Of::new(ordinal, flags)) + } + + /// Subtracts the `days` part of given `Duration` from the current date. + /// + /// Returns `None` when it will result in overflow. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use chrono::naive::MIN_DATE; + /// use time::Duration; + /// + /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(d.checked_sub_signed(Duration::days(40)), + /// Some(NaiveDate::from_ymd(2015, 7, 27))); + /// assert_eq!(d.checked_sub_signed(Duration::days(-40)), + /// Some(NaiveDate::from_ymd(2015, 10, 15))); + /// assert_eq!(d.checked_sub_signed(Duration::days(1_000_000_000)), None); + /// assert_eq!(d.checked_sub_signed(Duration::days(-1_000_000_000)), None); + /// assert_eq!(MIN_DATE.checked_sub_signed(Duration::days(1)), None); + /// # } + /// ~~~~ + pub fn checked_sub_signed(self, rhs: OldDuration) -> Option { + let year = self.year(); + let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400); + let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal()); + let cycle = try_opt!((cycle as i32).checked_sub(try_opt!(rhs.num_days().to_i32()))); + let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097); + year_div_400 += cycle_div_400y; + + let (year_mod_400, ordinal) = internals::cycle_to_yo(cycle as u32); + let flags = YearFlags::from_year_mod_400(year_mod_400 as i32); + NaiveDate::from_of(year_div_400 * 400 + year_mod_400 as i32, + Of::new(ordinal, flags)) + } + + /// Subtracts another `NaiveDate` from the current date. + /// Returns a `Duration` of integral numbers. + /// + /// This does not overflow or underflow at all, + /// as all possible output fits in the range of `Duration`. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use time::Duration; + /// + /// let from_ymd = NaiveDate::from_ymd; + /// let since = NaiveDate::signed_duration_since; + /// + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 1)), Duration::zero()); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 12, 31)), Duration::days(1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2014, 1, 2)), Duration::days(-1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 9, 23)), Duration::days(100)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2013, 1, 1)), Duration::days(365)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(2010, 1, 1)), Duration::days(365*4 + 1)); + /// assert_eq!(since(from_ymd(2014, 1, 1), from_ymd(1614, 1, 1)), Duration::days(365*400 + 97)); + /// # } + /// ~~~~ + pub fn signed_duration_since(self, rhs: NaiveDate) -> OldDuration { + let year1 = self.year(); + let year2 = rhs.year(); + let (year1_div_400, year1_mod_400) = div_mod_floor(year1, 400); + let (year2_div_400, year2_mod_400) = div_mod_floor(year2, 400); + let cycle1 = i64::from(internals::yo_to_cycle(year1_mod_400 as u32, self.of().ordinal())); + let cycle2 = i64::from(internals::yo_to_cycle(year2_mod_400 as u32, rhs.of().ordinal())); + OldDuration::days((i64::from(year1_div_400) - i64::from(year2_div_400)) * 146_097 + + (cycle1 - cycle2)) + } + + /// Formats the date with the specified formatting items. + /// Otherwise it is same to the ordinary `format` method. + /// + /// The `Iterator` of items should be `Clone`able, + /// since the resulting `DelayedFormat` value may be formatted multiple times. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// use chrono::format::strftime::StrftimeItems; + /// + /// let fmt = StrftimeItems::new("%Y-%m-%d"); + /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05"); + /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # use chrono::format::strftime::StrftimeItems; + /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); + /// # let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); + /// ~~~~ + #[inline] + pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat + where I: Iterator> + Clone { + DelayedFormat::new(Some(*self), None, items) + } + + /// Formats the date with the specified format string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// This returns a `DelayedFormat`, + /// which gets converted to a string only when actual formatting happens. + /// You may use the `to_string` method to get a `String`, + /// or just feed it into `print!` and other formatting macros. + /// (In this way it avoids the redundant memory allocation.) + /// + /// A wrong format string does *not* issue an error immediately. + /// Rather, converting or formatting the `DelayedFormat` fails. + /// You are recommended to immediately use `DelayedFormat` for this reason. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # let d = NaiveDate::from_ymd(2015, 9, 5); + /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); + /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); + /// ~~~~ + #[inline] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } +} + +impl Datelike for NaiveDate { + /// Returns the year number in the [calendar date](#calendar-date). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).year(), 2015); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).year(), -308); // 309 BCE + /// ~~~~ + #[inline] + fn year(&self) -> i32 { + self.ymdf >> 13 + } + + /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month(), 9); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month(), 3); + /// ~~~~ + #[inline] + fn month(&self) -> u32 { + self.mdf().month() + } + + /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).month0(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).month0(), 2); + /// ~~~~ + #[inline] + fn month0(&self) -> u32 { + self.mdf().month() - 1 + } + + /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day(), 8); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day(), 14); + /// ~~~~ + /// + /// Combined with [`NaiveDate::pred`](#method.pred), + /// one can determine the number of days in a particular month. + /// (Note that this panics when `year` is out of range.) + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_month(year: i32, month: u32) -> u32 { + /// // the first day of the next month... + /// let (y, m) = if month == 12 { (year + 1, 1) } else { (year, month + 1) }; + /// let d = NaiveDate::from_ymd(y, m, 1); + /// + /// // ...is preceded by the last day of the original month + /// d.pred().day() + /// } + /// + /// assert_eq!(ndays_in_month(2015, 8), 31); + /// assert_eq!(ndays_in_month(2015, 9), 30); + /// assert_eq!(ndays_in_month(2015, 12), 31); + /// assert_eq!(ndays_in_month(2016, 2), 29); + /// assert_eq!(ndays_in_month(2017, 2), 28); + /// ~~~~ + #[inline] + fn day(&self) -> u32 { + self.mdf().day() + } + + /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).day0(), 7); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).day0(), 13); + /// ~~~~ + #[inline] + fn day0(&self) -> u32 { + self.mdf().day() - 1 + } + + /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal(), 251); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal(), 74); + /// ~~~~ + /// + /// Combined with [`NaiveDate::pred`](#method.pred), + /// one can determine the number of days in a particular year. + /// (Note that this panics when `year` is out of range.) + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// fn ndays_in_year(year: i32) -> u32 { + /// // the first day of the next year... + /// let d = NaiveDate::from_ymd(year + 1, 1, 1); + /// + /// // ...is preceded by the last day of the original year + /// d.pred().ordinal() + /// } + /// + /// assert_eq!(ndays_in_year(2015), 365); + /// assert_eq!(ndays_in_year(2016), 366); + /// assert_eq!(ndays_in_year(2017), 365); + /// assert_eq!(ndays_in_year(2000), 366); + /// assert_eq!(ndays_in_year(2100), 365); + /// ~~~~ + #[inline] + fn ordinal(&self) -> u32 { + self.of().ordinal() + } + + /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).ordinal0(), 250); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).ordinal0(), 73); + /// ~~~~ + #[inline] + fn ordinal0(&self) -> u32 { + self.of().ordinal() - 1 + } + + /// Returns the day of week. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).weekday(), Weekday::Tue); + /// assert_eq!(NaiveDate::from_ymd(-308, 3, 14).weekday(), Weekday::Fri); + /// ~~~~ + #[inline] + fn weekday(&self) -> Weekday { + self.of().weekday() + } + + #[inline] + fn iso_week(&self) -> IsoWeek { + isoweek::iso_week_from_yof(self.year(), self.of()) + } + + /// Makes a new `NaiveDate` with the year number changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(2016), + /// Some(NaiveDate::from_ymd(2016, 9, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_year(-308), + /// Some(NaiveDate::from_ymd(-308, 9, 8))); + /// ~~~~ + /// + /// A leap day (February 29) is a good example that this method can return `None`. + /// + /// ~~~~ + /// # use chrono::{NaiveDate, Datelike}; + /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2015).is_none()); + /// assert!(NaiveDate::from_ymd(2016, 2, 29).with_year(2020).is_some()); + /// ~~~~ + #[inline] + fn with_year(&self, year: i32) -> Option { + // we need to operate with `mdf` since we should keep the month and day number as is + let mdf = self.mdf(); + + // adjust the flags as needed + let flags = YearFlags::from_year(year); + let mdf = mdf.with_flags(flags); + + NaiveDate::from_mdf(year, mdf) + } + + /// Makes a new `NaiveDate` with the month number (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(10), + /// Some(NaiveDate::from_ymd(2015, 10, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month(13), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month(2), None); // no February 30 + /// ~~~~ + #[inline] + fn with_month(&self, month: u32) -> Option { + self.with_mdf(self.mdf().with_month(month)) + } + + /// Makes a new `NaiveDate` with the month number (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(9), + /// Some(NaiveDate::from_ymd(2015, 10, 8))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_month0(12), None); // no month 13 + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 30).with_month0(1), None); // no February 30 + /// ~~~~ + #[inline] + fn with_month0(&self, month0: u32) -> Option { + self.with_mdf(self.mdf().with_month(month0 + 1)) + } + + /// Makes a new `NaiveDate` with the day of month (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(30), + /// Some(NaiveDate::from_ymd(2015, 9, 30))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day(31), + /// None); // no September 31 + /// ~~~~ + #[inline] + fn with_day(&self, day: u32) -> Option { + self.with_mdf(self.mdf().with_day(day)) + } + + /// Makes a new `NaiveDate` with the day of month (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(29), + /// Some(NaiveDate::from_ymd(2015, 9, 30))); + /// assert_eq!(NaiveDate::from_ymd(2015, 9, 8).with_day0(30), + /// None); // no September 31 + /// ~~~~ + #[inline] + fn with_day0(&self, day0: u32) -> Option { + self.with_mdf(self.mdf().with_day(day0 + 1)) + } + + /// Makes a new `NaiveDate` with the day of year (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(60), + /// Some(NaiveDate::from_ymd(2015, 3, 1))); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal(366), + /// None); // 2015 had only 365 days + /// + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(60), + /// Some(NaiveDate::from_ymd(2016, 2, 29))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal(366), + /// Some(NaiveDate::from_ymd(2016, 12, 31))); + /// ~~~~ + #[inline] + fn with_ordinal(&self, ordinal: u32) -> Option { + self.with_of(self.of().with_ordinal(ordinal)) + } + + /// Makes a new `NaiveDate` with the day of year (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDate` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike}; + /// + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2015, 3, 1))); + /// assert_eq!(NaiveDate::from_ymd(2015, 1, 1).with_ordinal0(365), + /// None); // 2015 had only 365 days + /// + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2016, 2, 29))); + /// assert_eq!(NaiveDate::from_ymd(2016, 1, 1).with_ordinal0(365), + /// Some(NaiveDate::from_ymd(2016, 12, 31))); + /// ~~~~ + #[inline] + fn with_ordinal0(&self, ordinal0: u32) -> Option { + self.with_of(self.of().with_ordinal(ordinal0 + 1)) + } +} + +/// An addition of `Duration` to `NaiveDate` discards the fractional days, +/// rounding to the closest integral number of days towards `Duration::zero()`. +/// +/// Panics on underflow or overflow. +/// Use [`NaiveDate::checked_add_signed`](#method.checked_add_signed) to detect that. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(-1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(364), from_ymd(2014, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*4 + 1), from_ymd(2018, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) + Duration::days(365*400 + 97), from_ymd(2414, 1, 1)); +/// # } +/// ~~~~ +impl Add for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn add(self, rhs: OldDuration) -> NaiveDate { + self.checked_add_signed(rhs).expect("`NaiveDate + Duration` overflowed") + } +} + +impl AddAssign for NaiveDate { + #[inline] + fn add_assign(&mut self, rhs: OldDuration) { + *self = self.add(rhs); + } +} + +/// A subtraction of `Duration` from `NaiveDate` discards the fractional days, +/// rounding to the closest integral number of days towards `Duration::zero()`. +/// It is same to the addition with a negated `Duration`. +/// +/// Panics on underflow or overflow. +/// Use [`NaiveDate::checked_sub_signed`](#method.checked_sub_signed) to detect that. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::zero(), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::seconds(-86399), from_ymd(2014, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(1), from_ymd(2013, 12, 31)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(-1), from_ymd(2014, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(364), from_ymd(2013, 1, 2)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*4 + 1), from_ymd(2010, 1, 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - Duration::days(365*400 + 97), from_ymd(1614, 1, 1)); +/// # } +/// ~~~~ +impl Sub for NaiveDate { + type Output = NaiveDate; + + #[inline] + fn sub(self, rhs: OldDuration) -> NaiveDate { + self.checked_sub_signed(rhs).expect("`NaiveDate - Duration` overflowed") + } +} + +impl SubAssign for NaiveDate { + #[inline] + fn sub_assign(&mut self, rhs: OldDuration) { + *self = self.sub(rhs); + } +} + +/// Subtracts another `NaiveDate` from the current date. +/// Returns a `Duration` of integral numbers. +/// +/// This does not overflow or underflow at all, +/// as all possible output fits in the range of `Duration`. +/// +/// The implementation is a wrapper around +/// [`NaiveDate::signed_duration_since`](#method.signed_duration_since). +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 1), Duration::zero()); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 12, 31), Duration::days(1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2014, 1, 2), Duration::days(-1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 9, 23), Duration::days(100)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2013, 1, 1), Duration::days(365)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(2010, 1, 1), Duration::days(365*4 + 1)); +/// assert_eq!(from_ymd(2014, 1, 1) - from_ymd(1614, 1, 1), Duration::days(365*400 + 97)); +/// # } +/// ~~~~ +impl Sub for NaiveDate { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: NaiveDate) -> OldDuration { + self.signed_duration_since(rhs) + } +} + +/// The `Debug` output of the naive date `d` is same to +/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveDate; +/// +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// ~~~~ +/// +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ~~~~ +/// # use chrono::NaiveDate; +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); +/// ~~~~ +impl fmt::Debug for NaiveDate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let year = self.year(); + let mdf = self.mdf(); + if 0 <= year && year <= 9999 { + write!(f, "{:04}-{:02}-{:02}", year, mdf.month(), mdf.day()) + } else { + // ISO 8601 requires the explicit sign for out-of-range years + write!(f, "{:+05}-{:02}-{:02}", year, mdf.month(), mdf.day()) + } + } +} + +/// The `Display` output of the naive date `d` is same to +/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveDate; +/// +/// assert_eq!(format!("{}", NaiveDate::from_ymd(2015, 9, 5)), "2015-09-05"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd( 0, 1, 1)), "0000-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(9999, 12, 31)), "9999-12-31"); +/// ~~~~ +/// +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ~~~~ +/// # use chrono::NaiveDate; +/// assert_eq!(format!("{}", NaiveDate::from_ymd( -1, 1, 1)), "-0001-01-01"); +/// assert_eq!(format!("{}", NaiveDate::from_ymd(10000, 12, 31)), "+10000-12-31"); +/// ~~~~ +impl fmt::Display for NaiveDate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } +} + +/// Parsing a `str` into a `NaiveDate` uses the same format, +/// [`%Y-%m-%d`](../format/strftime/index.html), as in `Debug` and `Display`. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveDate; +/// +/// let d = NaiveDate::from_ymd(2015, 9, 18); +/// assert_eq!("2015-09-18".parse::(), Ok(d)); +/// +/// let d = NaiveDate::from_ymd(12345, 6, 7); +/// assert_eq!("+12345-6-7".parse::(), Ok(d)); +/// +/// assert!("foo".parse::().is_err()); +/// ~~~~ +impl str::FromStr for NaiveDate { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult { + const ITEMS: &'static [Item<'static>] = &[ + Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Space(""), + ]; + + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_naive_date() + } +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_encodable_json(to_string: F) + where F: Fn(&NaiveDate) -> Result, E: ::std::fmt::Debug +{ + assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(), + Some(r#""2014-07-24""#.into())); + assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(), + Some(r#""0000-01-01""#.into())); + assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(), + Some(r#""-0001-12-31""#.into())); + assert_eq!(to_string(&MIN_DATE).ok(), + Some(r#""-262144-01-01""#.into())); + assert_eq!(to_string(&MAX_DATE).ok(), + Some(r#""+262143-12-31""#.into())); +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_decodable_json(from_str: F) + where F: Fn(&str) -> Result, E: ::std::fmt::Debug +{ + use std::{i32, i64}; + + assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); + assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); + assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8))); + assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); + assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1))); + assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31))); + assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(MIN_DATE)); + assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(MAX_DATE)); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""20001231""#).is_err()); + assert!(from_str(r#""2000-00-00""#).is_err()); + assert!(from_str(r#""2000-02-30""#).is_err()); + assert!(from_str(r#""2001-02-29""#).is_err()); + assert!(from_str(r#""2002-002-28""#).is_err()); + assert!(from_str(r#""yyyy-mm-dd""#).is_err()); + assert!(from_str(r#"0"#).is_err()); + assert!(from_str(r#"20.01"#).is_err()); + assert!(from_str(&i32::MIN.to_string()).is_err()); + assert!(from_str(&i32::MAX.to_string()).is_err()); + assert!(from_str(&i64::MIN.to_string()).is_err()); + assert!(from_str(&i64::MAX.to_string()).is_err()); + assert!(from_str(r#"{}"#).is_err()); + // pre-0.3.0 rustc-serialize format is now invalid + assert!(from_str(r#"{"ymdf":20}"#).is_err()); + assert!(from_str(r#"null"#).is_err()); +} + +#[cfg(feature = "rustc-serialize")] +mod rustc_serialize { + use super::NaiveDate; + use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + + impl Encodable for NaiveDate { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } + } + + impl Decodable for NaiveDate { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid date")) + } + } + + #[cfg(test)] use rustc_serialize::json; + + #[test] + fn test_encodable() { + super::test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + super::test_decodable_json(json::decode); + } +} + +#[cfg(feature = "serde")] +mod serde { + use std::fmt; + use super::NaiveDate; + use serdelib::{ser, de}; + + // TODO not very optimized for space (binary formats would want something better) + + impl ser::Serialize for NaiveDate { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer + { + struct FormatWrapped<'a, D: 'a> { + inner: &'a D + } + + impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + serializer.collect_str(&FormatWrapped { inner: &self }) + } + } + + struct NaiveDateVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateVisitor { + type Value = NaiveDate; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + write!(formatter, "a formatted date string") + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::custom(format!("{}", err))) + } + } + + impl<'de> de::Deserialize<'de> for NaiveDate { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(NaiveDateVisitor) + } + } + + #[cfg(test)] extern crate serde_json; + #[cfg(test)] extern crate bincode; + + #[test] + fn test_serde_serialize() { + super::test_encodable_json(self::serde_json::to_string); + } + + #[test] + fn test_serde_deserialize() { + super::test_decodable_json(|input| self::serde_json::from_str(&input)); + } + + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use self::bincode::{Infinite, serialize, deserialize}; + + let d = NaiveDate::from_ymd(2014, 7, 24); + let encoded = serialize(&d, Infinite).unwrap(); + let decoded: NaiveDate = deserialize(&encoded).unwrap(); + assert_eq!(d, decoded); + } +} + +#[cfg(test)] +mod tests { + use super::NaiveDate; + use super::{MIN_DATE, MIN_YEAR, MIN_DAYS_FROM_YEAR_0}; + use super::{MAX_DATE, MAX_YEAR, MAX_DAYS_FROM_YEAR_0}; + use {Datelike, Weekday}; + use std::{i32, u32}; + use oldtime::Duration; + + #[test] + fn test_date_from_ymd() { + let ymd_opt = |y,m,d| NaiveDate::from_ymd_opt(y, m, d); + + assert!(ymd_opt(2012, 0, 1).is_none()); + assert!(ymd_opt(2012, 1, 1).is_some()); + assert!(ymd_opt(2012, 2, 29).is_some()); + assert!(ymd_opt(2014, 2, 29).is_none()); + assert!(ymd_opt(2014, 3, 0).is_none()); + assert!(ymd_opt(2014, 3, 1).is_some()); + assert!(ymd_opt(2014, 3, 31).is_some()); + assert!(ymd_opt(2014, 3, 32).is_none()); + assert!(ymd_opt(2014, 12, 31).is_some()); + assert!(ymd_opt(2014, 13, 1).is_none()); + } + + #[test] + fn test_date_from_yo() { + let yo_opt = |y,o| NaiveDate::from_yo_opt(y, o); + let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); + + assert_eq!(yo_opt(2012, 0), None); + assert_eq!(yo_opt(2012, 1), Some(ymd(2012, 1, 1))); + assert_eq!(yo_opt(2012, 2), Some(ymd(2012, 1, 2))); + assert_eq!(yo_opt(2012, 32), Some(ymd(2012, 2, 1))); + assert_eq!(yo_opt(2012, 60), Some(ymd(2012, 2, 29))); + assert_eq!(yo_opt(2012, 61), Some(ymd(2012, 3, 1))); + assert_eq!(yo_opt(2012, 100), Some(ymd(2012, 4, 9))); + assert_eq!(yo_opt(2012, 200), Some(ymd(2012, 7, 18))); + assert_eq!(yo_opt(2012, 300), Some(ymd(2012, 10, 26))); + assert_eq!(yo_opt(2012, 366), Some(ymd(2012, 12, 31))); + assert_eq!(yo_opt(2012, 367), None); + + assert_eq!(yo_opt(2014, 0), None); + assert_eq!(yo_opt(2014, 1), Some(ymd(2014, 1, 1))); + assert_eq!(yo_opt(2014, 2), Some(ymd(2014, 1, 2))); + assert_eq!(yo_opt(2014, 32), Some(ymd(2014, 2, 1))); + assert_eq!(yo_opt(2014, 59), Some(ymd(2014, 2, 28))); + assert_eq!(yo_opt(2014, 60), Some(ymd(2014, 3, 1))); + assert_eq!(yo_opt(2014, 100), Some(ymd(2014, 4, 10))); + assert_eq!(yo_opt(2014, 200), Some(ymd(2014, 7, 19))); + assert_eq!(yo_opt(2014, 300), Some(ymd(2014, 10, 27))); + assert_eq!(yo_opt(2014, 365), Some(ymd(2014, 12, 31))); + assert_eq!(yo_opt(2014, 366), None); + } + + #[test] + fn test_date_from_isoywd() { + let isoywd_opt = |y,w,d| NaiveDate::from_isoywd_opt(y, w, d); + let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); + + assert_eq!(isoywd_opt(2004, 0, Weekday::Sun), None); + assert_eq!(isoywd_opt(2004, 1, Weekday::Mon), Some(ymd(2003, 12, 29))); + assert_eq!(isoywd_opt(2004, 1, Weekday::Sun), Some(ymd(2004, 1, 4))); + assert_eq!(isoywd_opt(2004, 2, Weekday::Mon), Some(ymd(2004, 1, 5))); + assert_eq!(isoywd_opt(2004, 2, Weekday::Sun), Some(ymd(2004, 1, 11))); + assert_eq!(isoywd_opt(2004, 52, Weekday::Mon), Some(ymd(2004, 12, 20))); + assert_eq!(isoywd_opt(2004, 52, Weekday::Sun), Some(ymd(2004, 12, 26))); + assert_eq!(isoywd_opt(2004, 53, Weekday::Mon), Some(ymd(2004, 12, 27))); + assert_eq!(isoywd_opt(2004, 53, Weekday::Sun), Some(ymd(2005, 1, 2))); + assert_eq!(isoywd_opt(2004, 54, Weekday::Mon), None); + + assert_eq!(isoywd_opt(2011, 0, Weekday::Sun), None); + assert_eq!(isoywd_opt(2011, 1, Weekday::Mon), Some(ymd(2011, 1, 3))); + assert_eq!(isoywd_opt(2011, 1, Weekday::Sun), Some(ymd(2011, 1, 9))); + assert_eq!(isoywd_opt(2011, 2, Weekday::Mon), Some(ymd(2011, 1, 10))); + assert_eq!(isoywd_opt(2011, 2, Weekday::Sun), Some(ymd(2011, 1, 16))); + + assert_eq!(isoywd_opt(2018, 51, Weekday::Mon), Some(ymd(2018, 12, 17))); + assert_eq!(isoywd_opt(2018, 51, Weekday::Sun), Some(ymd(2018, 12, 23))); + assert_eq!(isoywd_opt(2018, 52, Weekday::Mon), Some(ymd(2018, 12, 24))); + assert_eq!(isoywd_opt(2018, 52, Weekday::Sun), Some(ymd(2018, 12, 30))); + assert_eq!(isoywd_opt(2018, 53, Weekday::Mon), None); + } + + #[test] + fn test_date_from_isoywd_and_iso_week() { + for year in 2000..2401 { + for week in 1..54 { + for &weekday in [Weekday::Mon, Weekday::Tue, Weekday::Wed, Weekday::Thu, + Weekday::Fri, Weekday::Sat, Weekday::Sun].iter() { + let d = NaiveDate::from_isoywd_opt(year, week, weekday); + if d.is_some() { + let d = d.unwrap(); + assert_eq!(d.weekday(), weekday); + let w = d.iso_week(); + assert_eq!(w.year(), year); + assert_eq!(w.week(), week); + } + } + } + } + + for year in 2000..2401 { + for month in 1..13 { + for day in 1..32 { + let d = NaiveDate::from_ymd_opt(year, month, day); + if d.is_some() { + let d = d.unwrap(); + let w = d.iso_week(); + let d_ = NaiveDate::from_isoywd(w.year(), w.week(), d.weekday()); + assert_eq!(d, d_); + } + } + } + } + } + + #[test] + fn test_date_from_num_days_from_ce() { + let from_ndays_from_ce = |days| NaiveDate::from_num_days_from_ce_opt(days); + assert_eq!(from_ndays_from_ce(1), Some(NaiveDate::from_ymd(1, 1, 1))); + assert_eq!(from_ndays_from_ce(2), Some(NaiveDate::from_ymd(1, 1, 2))); + assert_eq!(from_ndays_from_ce(31), Some(NaiveDate::from_ymd(1, 1, 31))); + assert_eq!(from_ndays_from_ce(32), Some(NaiveDate::from_ymd(1, 2, 1))); + assert_eq!(from_ndays_from_ce(59), Some(NaiveDate::from_ymd(1, 2, 28))); + assert_eq!(from_ndays_from_ce(60), Some(NaiveDate::from_ymd(1, 3, 1))); + assert_eq!(from_ndays_from_ce(365), Some(NaiveDate::from_ymd(1, 12, 31))); + assert_eq!(from_ndays_from_ce(365*1 + 1), Some(NaiveDate::from_ymd(2, 1, 1))); + assert_eq!(from_ndays_from_ce(365*2 + 1), Some(NaiveDate::from_ymd(3, 1, 1))); + assert_eq!(from_ndays_from_ce(365*3 + 1), Some(NaiveDate::from_ymd(4, 1, 1))); + assert_eq!(from_ndays_from_ce(365*4 + 2), Some(NaiveDate::from_ymd(5, 1, 1))); + assert_eq!(from_ndays_from_ce(146097 + 1), Some(NaiveDate::from_ymd(401, 1, 1))); + assert_eq!(from_ndays_from_ce(146097*5 + 1), Some(NaiveDate::from_ymd(2001, 1, 1))); + assert_eq!(from_ndays_from_ce(719163), Some(NaiveDate::from_ymd(1970, 1, 1))); + assert_eq!(from_ndays_from_ce(0), Some(NaiveDate::from_ymd(0, 12, 31))); // 1 BCE + assert_eq!(from_ndays_from_ce(-365), Some(NaiveDate::from_ymd(0, 1, 1))); + assert_eq!(from_ndays_from_ce(-366), Some(NaiveDate::from_ymd(-1, 12, 31))); // 2 BCE + + for days in (-9999..10001).map(|x| x * 100) { + assert_eq!(from_ndays_from_ce(days).map(|d| d.num_days_from_ce()), Some(days)); + } + + assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce()), Some(MIN_DATE)); + assert_eq!(from_ndays_from_ce(MIN_DATE.num_days_from_ce() - 1), None); + assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce()), Some(MAX_DATE)); + assert_eq!(from_ndays_from_ce(MAX_DATE.num_days_from_ce() + 1), None); + } + + #[test] + fn test_date_fields() { + fn check(year: i32, month: u32, day: u32, ordinal: u32) { + let d1 = NaiveDate::from_ymd(year, month, day); + assert_eq!(d1.year(), year); + assert_eq!(d1.month(), month); + assert_eq!(d1.day(), day); + assert_eq!(d1.ordinal(), ordinal); + + let d2 = NaiveDate::from_yo(year, ordinal); + assert_eq!(d2.year(), year); + assert_eq!(d2.month(), month); + assert_eq!(d2.day(), day); + assert_eq!(d2.ordinal(), ordinal); + + assert_eq!(d1, d2); + } + + check(2012, 1, 1, 1); + check(2012, 1, 2, 2); + check(2012, 2, 1, 32); + check(2012, 2, 29, 60); + check(2012, 3, 1, 61); + check(2012, 4, 9, 100); + check(2012, 7, 18, 200); + check(2012, 10, 26, 300); + check(2012, 12, 31, 366); + + check(2014, 1, 1, 1); + check(2014, 1, 2, 2); + check(2014, 2, 1, 32); + check(2014, 2, 28, 59); + check(2014, 3, 1, 60); + check(2014, 4, 10, 100); + check(2014, 7, 19, 200); + check(2014, 10, 27, 300); + check(2014, 12, 31, 365); + } + + #[test] + fn test_date_weekday() { + assert_eq!(NaiveDate::from_ymd(1582, 10, 15).weekday(), Weekday::Fri); + // May 20, 1875 = ISO 8601 reference date + assert_eq!(NaiveDate::from_ymd(1875, 5, 20).weekday(), Weekday::Thu); + assert_eq!(NaiveDate::from_ymd(2000, 1, 1).weekday(), Weekday::Sat); + } + + #[test] + fn test_date_with_fields() { + let d = NaiveDate::from_ymd(2000, 2, 29); + assert_eq!(d.with_year(-400), Some(NaiveDate::from_ymd(-400, 2, 29))); + assert_eq!(d.with_year(-100), None); + assert_eq!(d.with_year(1600), Some(NaiveDate::from_ymd(1600, 2, 29))); + assert_eq!(d.with_year(1900), None); + assert_eq!(d.with_year(2000), Some(NaiveDate::from_ymd(2000, 2, 29))); + assert_eq!(d.with_year(2001), None); + assert_eq!(d.with_year(2004), Some(NaiveDate::from_ymd(2004, 2, 29))); + assert_eq!(d.with_year(i32::MAX), None); + + let d = NaiveDate::from_ymd(2000, 4, 30); + assert_eq!(d.with_month(0), None); + assert_eq!(d.with_month(1), Some(NaiveDate::from_ymd(2000, 1, 30))); + assert_eq!(d.with_month(2), None); + assert_eq!(d.with_month(3), Some(NaiveDate::from_ymd(2000, 3, 30))); + assert_eq!(d.with_month(4), Some(NaiveDate::from_ymd(2000, 4, 30))); + assert_eq!(d.with_month(12), Some(NaiveDate::from_ymd(2000, 12, 30))); + assert_eq!(d.with_month(13), None); + assert_eq!(d.with_month(u32::MAX), None); + + let d = NaiveDate::from_ymd(2000, 2, 8); + assert_eq!(d.with_day(0), None); + assert_eq!(d.with_day(1), Some(NaiveDate::from_ymd(2000, 2, 1))); + assert_eq!(d.with_day(29), Some(NaiveDate::from_ymd(2000, 2, 29))); + assert_eq!(d.with_day(30), None); + assert_eq!(d.with_day(u32::MAX), None); + + let d = NaiveDate::from_ymd(2000, 5, 5); + assert_eq!(d.with_ordinal(0), None); + assert_eq!(d.with_ordinal(1), Some(NaiveDate::from_ymd(2000, 1, 1))); + assert_eq!(d.with_ordinal(60), Some(NaiveDate::from_ymd(2000, 2, 29))); + assert_eq!(d.with_ordinal(61), Some(NaiveDate::from_ymd(2000, 3, 1))); + assert_eq!(d.with_ordinal(366), Some(NaiveDate::from_ymd(2000, 12, 31))); + assert_eq!(d.with_ordinal(367), None); + assert_eq!(d.with_ordinal(u32::MAX), None); + } + + #[test] + fn test_date_num_days_from_ce() { + assert_eq!(NaiveDate::from_ymd(1, 1, 1).num_days_from_ce(), 1); + + for year in -9999..10001 { + assert_eq!(NaiveDate::from_ymd(year, 1, 1).num_days_from_ce(), + NaiveDate::from_ymd(year - 1, 12, 31).num_days_from_ce() + 1); + } + } + + #[test] + fn test_date_succ() { + let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); + assert_eq!(ymd(2014, 5, 6).succ_opt(), Some(ymd(2014, 5, 7))); + assert_eq!(ymd(2014, 5, 31).succ_opt(), Some(ymd(2014, 6, 1))); + assert_eq!(ymd(2014, 12, 31).succ_opt(), Some(ymd(2015, 1, 1))); + assert_eq!(ymd(2016, 2, 28).succ_opt(), Some(ymd(2016, 2, 29))); + assert_eq!(ymd(MAX_DATE.year(), 12, 31).succ_opt(), None); + } + + #[test] + fn test_date_pred() { + let ymd = |y,m,d| NaiveDate::from_ymd(y, m, d); + assert_eq!(ymd(2016, 3, 1).pred_opt(), Some(ymd(2016, 2, 29))); + assert_eq!(ymd(2015, 1, 1).pred_opt(), Some(ymd(2014, 12, 31))); + assert_eq!(ymd(2014, 6, 1).pred_opt(), Some(ymd(2014, 5, 31))); + assert_eq!(ymd(2014, 5, 7).pred_opt(), Some(ymd(2014, 5, 6))); + assert_eq!(ymd(MIN_DATE.year(), 1, 1).pred_opt(), None); + } + + #[test] + fn test_date_add() { + fn check((y1,m1,d1): (i32, u32, u32), rhs: Duration, ymd: Option<(i32, u32, u32)>) { + let lhs = NaiveDate::from_ymd(y1, m1, d1); + let sum = ymd.map(|(y,m,d)| NaiveDate::from_ymd(y, m, d)); + assert_eq!(lhs.checked_add_signed(rhs), sum); + assert_eq!(lhs.checked_sub_signed(-rhs), sum); + } + + check((2014, 1, 1), Duration::zero(), Some((2014, 1, 1))); + check((2014, 1, 1), Duration::seconds(86399), Some((2014, 1, 1))); + // always round towards zero + check((2014, 1, 1), Duration::seconds(-86399), Some((2014, 1, 1))); + check((2014, 1, 1), Duration::days(1), Some((2014, 1, 2))); + check((2014, 1, 1), Duration::days(-1), Some((2013, 12, 31))); + check((2014, 1, 1), Duration::days(364), Some((2014, 12, 31))); + check((2014, 1, 1), Duration::days(365*4 + 1), Some((2018, 1, 1))); + check((2014, 1, 1), Duration::days(365*400 + 97), Some((2414, 1, 1))); + + check((-7, 1, 1), Duration::days(365*12 + 3), Some((5, 1, 1))); + + // overflow check + check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64), Some((MAX_YEAR, 12, 31))); + check((0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64 + 1), None); + check((0, 1, 1), Duration::max_value(), None); + check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64), Some((MIN_YEAR, 1, 1))); + check((0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64 - 1), None); + check((0, 1, 1), Duration::min_value(), None); + } + + #[test] + fn test_date_sub() { + fn check((y1,m1,d1): (i32, u32, u32), (y2,m2,d2): (i32, u32, u32), diff: Duration) { + let lhs = NaiveDate::from_ymd(y1, m1, d1); + let rhs = NaiveDate::from_ymd(y2, m2, d2); + assert_eq!(lhs.signed_duration_since(rhs), diff); + assert_eq!(rhs.signed_duration_since(lhs), -diff); + } + + check((2014, 1, 1), (2014, 1, 1), Duration::zero()); + check((2014, 1, 2), (2014, 1, 1), Duration::days(1)); + check((2014, 12, 31), (2014, 1, 1), Duration::days(364)); + check((2015, 1, 3), (2014, 1, 1), Duration::days(365 + 2)); + check((2018, 1, 1), (2014, 1, 1), Duration::days(365*4 + 1)); + check((2414, 1, 1), (2014, 1, 1), Duration::days(365*400 + 97)); + + check((MAX_YEAR, 12, 31), (0, 1, 1), Duration::days(MAX_DAYS_FROM_YEAR_0 as i64)); + check((MIN_YEAR, 1, 1), (0, 1, 1), Duration::days(MIN_DAYS_FROM_YEAR_0 as i64)); + } + + #[test] + fn test_date_addassignment() { + let ymd = NaiveDate::from_ymd; + let mut date = ymd(2016, 10, 1); + date += Duration::days(10); + assert_eq!(date, ymd(2016, 10, 11)); + date += Duration::days(30); + assert_eq!(date, ymd(2016, 11, 10)); + } + + #[test] + fn test_date_subassignment() { + let ymd = NaiveDate::from_ymd; + let mut date = ymd(2016, 10, 11); + date -= Duration::days(10); + assert_eq!(date, ymd(2016, 10, 1)); + date -= Duration::days(2); + assert_eq!(date, ymd(2016, 9, 29)); + } + + #[test] + fn test_date_fmt() { + assert_eq!(format!("{:?}", NaiveDate::from_ymd(2012, 3, 4)), "2012-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(0, 3, 4)), "0000-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(-307, 3, 4)), "-0307-03-04"); + assert_eq!(format!("{:?}", NaiveDate::from_ymd(12345, 3, 4)), "+12345-03-04"); + + assert_eq!(NaiveDate::from_ymd(2012, 3, 4).to_string(), "2012-03-04"); + assert_eq!(NaiveDate::from_ymd(0, 3, 4).to_string(), "0000-03-04"); + assert_eq!(NaiveDate::from_ymd(-307, 3, 4).to_string(), "-0307-03-04"); + assert_eq!(NaiveDate::from_ymd(12345, 3, 4).to_string(), "+12345-03-04"); + + // the format specifier should have no effect on `NaiveTime` + assert_eq!(format!("{:+30?}", NaiveDate::from_ymd(1234, 5, 6)), "1234-05-06"); + assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07"); + } + + #[test] + fn test_date_from_str() { + // valid cases + let valid = [ + "-0000000123456-1-2", + " -123456 - 1 - 2 ", + "-12345-1-2", + "-1234-12-31", + "-7-6-5", + "350-2-28", + "360-02-29", + "0360-02-29", + "2015-2 -18", + "+70-2-18", + "+70000-2-18", + "+00007-2-18", + ]; + for &s in &valid { + let d = match s.parse::() { + Ok(d) => d, + Err(e) => panic!("parsing `{}` has failed: {}", s, e) + }; + let s_ = format!("{:?}", d); + // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same + let d_ = match s_.parse::() { + Ok(d) => d, + Err(e) => panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", + s, d, e) + }; + assert!(d == d_, "`{}` is parsed into `{:?}`, but reparsed result \ + `{:?}` does not match", s, d, d_); + } + + // some invalid cases + // since `ParseErrorKind` is private, all we can do is to check if there was an error + assert!("".parse::().is_err()); + assert!("x".parse::().is_err()); + assert!("2014".parse::().is_err()); + assert!("2014-01".parse::().is_err()); + assert!("2014-01-00".parse::().is_err()); + assert!("2014-13-57".parse::().is_err()); + assert!("9999999-9-9".parse::().is_err()); // out-of-bounds + } + + #[test] + fn test_date_parse_from_str() { + let ymd = |y,m,d| NaiveDate::from_ymd(y,m,d); + assert_eq!(NaiveDate::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + Ok(ymd(2014, 5, 7))); // ignore time and offset + assert_eq!(NaiveDate::parse_from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"), + Ok(ymd(2015, 2, 2))); + assert_eq!(NaiveDate::parse_from_str("Fri, 09 Aug 13", "%a, %d %b %y"), + Ok(ymd(2013, 8, 9))); + assert!(NaiveDate::parse_from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err()); + assert!(NaiveDate::parse_from_str("2014-57", "%Y-%m-%d").is_err()); + assert!(NaiveDate::parse_from_str("2014", "%Y").is_err()); // insufficient + } + + #[test] + fn test_date_format() { + let d = NaiveDate::from_ymd(2012, 3, 4); + assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12"); + assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March"); + assert_eq!(d.format("%d,%e").to_string(), "04, 4"); + assert_eq!(d.format("%U,%W,%V").to_string(), "10,09,09"); + assert_eq!(d.format("%a,%A,%w,%u").to_string(), "Sun,Sunday,0,7"); + assert_eq!(d.format("%j").to_string(), "064"); // since 2012 is a leap year + assert_eq!(d.format("%D,%x").to_string(), "03/04/12,03/04/12"); + assert_eq!(d.format("%F").to_string(), "2012-03-04"); + assert_eq!(d.format("%v").to_string(), " 4-Mar-2012"); + assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + + // non-four-digit years + assert_eq!(NaiveDate::from_ymd(12345, 1, 1).format("%Y").to_string(), "+12345"); + assert_eq!(NaiveDate::from_ymd(1234, 1, 1).format("%Y").to_string(), "1234"); + assert_eq!(NaiveDate::from_ymd(123, 1, 1).format("%Y").to_string(), "0123"); + assert_eq!(NaiveDate::from_ymd(12, 1, 1).format("%Y").to_string(), "0012"); + assert_eq!(NaiveDate::from_ymd(1, 1, 1).format("%Y").to_string(), "0001"); + assert_eq!(NaiveDate::from_ymd(0, 1, 1).format("%Y").to_string(), "0000"); + assert_eq!(NaiveDate::from_ymd(-1, 1, 1).format("%Y").to_string(), "-0001"); + assert_eq!(NaiveDate::from_ymd(-12, 1, 1).format("%Y").to_string(), "-0012"); + assert_eq!(NaiveDate::from_ymd(-123, 1, 1).format("%Y").to_string(), "-0123"); + assert_eq!(NaiveDate::from_ymd(-1234, 1, 1).format("%Y").to_string(), "-1234"); + assert_eq!(NaiveDate::from_ymd(-12345, 1, 1).format("%Y").to_string(), "-12345"); + + // corner cases + assert_eq!(NaiveDate::from_ymd(2007, 12, 31).format("%G,%g,%U,%W,%V").to_string(), + "2008,08,53,53,01"); + assert_eq!(NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), + "2009,09,01,00,53"); + } +} + diff --git a/chrono/src/naive/datetime.rs b/chrono/src/naive/datetime.rs new file mode 100644 index 000000000..d228a54f5 --- /dev/null +++ b/chrono/src/naive/datetime.rs @@ -0,0 +1,2351 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 date and time without timezone. + +use std::{str, fmt, hash}; +use std::ops::{Add, Sub, AddAssign, SubAssign}; +use num_traits::ToPrimitive; +use oldtime::Duration as OldDuration; + +use {Weekday, Timelike, Datelike}; +use div::div_mod_floor; +use naive::{NaiveTime, NaiveDate, IsoWeek}; +use format::{Item, Numeric, Pad, Fixed}; +use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; + +/// The tight upper bound guarantees that a duration with `|Duration| >= 2^MAX_SECS_BITS` +/// will always overflow the addition with any date and time type. +/// +/// So why is this needed? `Duration::seconds(rhs)` may overflow, and we don't have +/// an alternative returning `Option` or `Result`. Thus we need some early bound to avoid +/// touching that call when we are already sure that it WILL overflow... +const MAX_SECS_BITS: usize = 44; + +/// ISO 8601 combined date and time without timezone. +/// +/// # Example +/// +/// `NaiveDateTime` is commonly created from [`NaiveDate`](./struct.NaiveDate.html). +/// +/// ~~~~ +/// use chrono::{NaiveDate, NaiveDateTime}; +/// +/// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); +/// # let _ = dt; +/// ~~~~ +/// +/// You can use typical [date-like](../trait.Datelike.html) and +/// [time-like](../trait.Timelike.html) methods, +/// provided that relevant traits are in the scope. +/// +/// ~~~~ +/// # use chrono::{NaiveDate, NaiveDateTime}; +/// # let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); +/// use chrono::{Datelike, Timelike, Weekday}; +/// +/// assert_eq!(dt.weekday(), Weekday::Fri); +/// assert_eq!(dt.num_seconds_from_midnight(), 33011); +/// ~~~~ +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +pub struct NaiveDateTime { + date: NaiveDate, + time: NaiveTime, +} + +impl NaiveDateTime { + /// Makes a new `NaiveDateTime` from date and time components. + /// Equivalent to [`date.and_time(time)`](./struct.NaiveDate.html#method.and_time) + /// and many other helper constructors on `NaiveDate`. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveTime, NaiveDateTime}; + /// + /// let d = NaiveDate::from_ymd(2015, 6, 3); + /// let t = NaiveTime::from_hms_milli(12, 34, 56, 789); + /// + /// let dt = NaiveDateTime::new(d, t); + /// assert_eq!(dt.date(), d); + /// assert_eq!(dt.time(), t); + /// ~~~~ + #[inline] + pub fn new(date: NaiveDate, time: NaiveTime) -> NaiveDateTime { + NaiveDateTime { date: date, time: time } + } + + /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, + /// from the number of non-leap seconds + /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp") + /// and the number of nanoseconds since the last whole non-leap second. + /// + /// For a non-naive version of this function see + /// [`TimeZone::timestamp`](../offset/trait.TimeZone.html#method.timestamp). + /// + /// The nanosecond part can exceed 1,000,000,000 in order to represent the + /// [leap second](./struct.NaiveTime.html#leap-second-handling). (The true "UNIX + /// timestamp" cannot represent a leap second unambiguously.) + /// + /// Panics on the out-of-range number of seconds and/or invalid nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDateTime, NaiveDate}; + /// + /// let dt = NaiveDateTime::from_timestamp(0, 42_000_000); + /// assert_eq!(dt, NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 0, 42)); + /// + /// let dt = NaiveDateTime::from_timestamp(1_000_000_000, 0); + /// assert_eq!(dt, NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40)); + /// ~~~~ + #[inline] + pub fn from_timestamp(secs: i64, nsecs: u32) -> NaiveDateTime { + let datetime = NaiveDateTime::from_timestamp_opt(secs, nsecs); + datetime.expect("invalid or out-of-range datetime") + } + + /// Makes a new `NaiveDateTime` corresponding to a UTC date and time, + /// from the number of non-leap seconds + /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp") + /// and the number of nanoseconds since the last whole non-leap second. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// (The true "UNIX timestamp" cannot represent a leap second unambiguously.) + /// + /// Returns `None` on the out-of-range number of seconds and/or invalid nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDateTime, NaiveDate}; + /// use std::i64; + /// + /// let from_timestamp_opt = NaiveDateTime::from_timestamp_opt; + /// + /// assert!(from_timestamp_opt(0, 0).is_some()); + /// assert!(from_timestamp_opt(0, 999_999_999).is_some()); + /// assert!(from_timestamp_opt(0, 1_500_000_000).is_some()); // leap second + /// assert!(from_timestamp_opt(0, 2_000_000_000).is_none()); + /// assert!(from_timestamp_opt(i64::MAX, 0).is_none()); + /// ~~~~ + #[inline] + pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option { + let (days, secs) = div_mod_floor(secs, 86_400); + let date = days.to_i32().and_then(|days| days.checked_add(719_163)) + .and_then(NaiveDate::from_num_days_from_ce_opt); + let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs); + match (date, time) { + (Some(date), Some(time)) => Some(NaiveDateTime { date: date, time: time }), + (_, _) => None, + } + } + + /// Parses a string with the specified format string and returns a new `NaiveDateTime`. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDateTime, NaiveDate}; + /// + /// let parse_from_str = NaiveDateTime::parse_from_str; + /// + /// assert_eq!(parse_from_str("2015-09-05 23:56:04", "%Y-%m-%d %H:%M:%S"), + /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4))); + /// assert_eq!(parse_from_str("5sep2015pm012345.6789", "%d%b%Y%p%I%M%S%.f"), + /// Ok(NaiveDate::from_ymd(2015, 9, 5).and_hms_micro(13, 23, 45, 678_900))); + /// ~~~~ + /// + /// Offset is ignored for the purpose of parsing. + /// + /// ~~~~ + /// # use chrono::{NaiveDateTime, NaiveDate}; + /// # let parse_from_str = NaiveDateTime::parse_from_str; + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + /// Ok(NaiveDate::from_ymd(2014, 5, 17).and_hms(12, 34, 56))); + /// ~~~~ + /// + /// [Leap seconds](./struct.NaiveTime.html#leap-second-handling) are correctly handled by + /// treating any time of the form `hh:mm:60` as a leap second. + /// (This equally applies to the formatting, so the round trip is possible.) + /// + /// ~~~~ + /// # use chrono::{NaiveDateTime, NaiveDate}; + /// # let parse_from_str = NaiveDateTime::parse_from_str; + /// assert_eq!(parse_from_str("2015-07-01 08:59:60.123", "%Y-%m-%d %H:%M:%S%.f"), + /// Ok(NaiveDate::from_ymd(2015, 7, 1).and_hms_milli(8, 59, 59, 1_123))); + /// ~~~~ + /// + /// Missing seconds are assumed to be zero, + /// but out-of-bound times or insufficient fields are errors otherwise. + /// + /// ~~~~ + /// # use chrono::{NaiveDateTime, NaiveDate}; + /// # let parse_from_str = NaiveDateTime::parse_from_str; + /// assert_eq!(parse_from_str("94/9/4 7:15", "%y/%m/%d %H:%M"), + /// Ok(NaiveDate::from_ymd(1994, 9, 4).and_hms(7, 15, 0))); + /// + /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err()); + /// assert!(parse_from_str("94/9/4 12", "%y/%m/%d %H").is_err()); + /// assert!(parse_from_str("94/9/4 17:60", "%y/%m/%d %H:%M").is_err()); + /// assert!(parse_from_str("94/9/4 24:00:00", "%y/%m/%d %H:%M:%S").is_err()); + /// ~~~~ + /// + /// All parsed fields should be consistent to each other, otherwise it's an error. + /// + /// ~~~~ + /// # use chrono::NaiveDateTime; + /// # let parse_from_str = NaiveDateTime::parse_from_str; + /// let fmt = "%Y-%m-%d %H:%M:%S = UNIX timestamp %s"; + /// assert!(parse_from_str("2001-09-09 01:46:39 = UNIX timestamp 999999999", fmt).is_ok()); + /// assert!(parse_from_str("1970-01-01 00:00:00 = UNIX timestamp 1", fmt).is_err()); + /// ~~~~ + pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); + parsed.to_naive_datetime_with_offset(0) // no offset adjustment + } + + /// Retrieves a date component. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); + /// assert_eq!(dt.date(), NaiveDate::from_ymd(2016, 7, 8)); + /// ~~~~ + #[inline] + pub fn date(&self) -> NaiveDate { + self.date + } + + /// Retrieves a time component. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveTime}; + /// + /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11); + /// assert_eq!(dt.time(), NaiveTime::from_hms(9, 10, 11)); + /// ~~~~ + #[inline] + pub fn time(&self) -> NaiveTime { + self.time + } + + /// Returns the number of non-leap seconds since the midnight on January 1, 1970. + /// + /// Note that this does *not* account for the timezone! + /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 980); + /// assert_eq!(dt.timestamp(), 1); + /// + /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms(1, 46, 40); + /// assert_eq!(dt.timestamp(), 1_000_000_000); + /// + /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms(23, 59, 59); + /// assert_eq!(dt.timestamp(), -1); + /// + /// let dt = NaiveDate::from_ymd(-1, 1, 1).and_hms(0, 0, 0); + /// assert_eq!(dt.timestamp(), -62198755200); + /// ~~~~ + #[inline] + pub fn timestamp(&self) -> i64 { + const UNIX_EPOCH_DAY: i64 = 719_163; + let gregorian_day = i64::from(self.date.num_days_from_ce()); + let seconds_from_midnight = i64::from(self.time.num_seconds_from_midnight()); + (gregorian_day - UNIX_EPOCH_DAY) * 86_400 + seconds_from_midnight + } + + /// Returns the number of non-leap *milliseconds* since midnight on January 1, 1970. + /// + /// Note that this does *not* account for the timezone! + /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. + /// + /// Note also that this does reduce the number of years that can be + /// represented from ~584 Billion to ~584 Million. (If this is a problem, + /// please file an issue to let me know what domain needs millisecond + /// precision over billions of years, I'm curious.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444); + /// assert_eq!(dt.timestamp_millis(), 1_444); + /// + /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555); + /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); + /// + /// let dt = NaiveDate::from_ymd(1969, 12, 31).and_hms_milli(23, 59, 59, 100); + /// assert_eq!(dt.timestamp_millis(), -900); + /// ~~~~ + #[inline] + pub fn timestamp_millis(&self) -> i64 { + let as_ms = self.timestamp() * 1000; + as_ms + i64::from(self.timestamp_subsec_millis()) + } + + /// Returns the number of non-leap *nanoseconds* since midnight on January 1, 1970. + /// + /// Note that this does *not* account for the timezone! + /// The true "UNIX timestamp" would count seconds since the midnight *UTC* on the epoch. + /// + /// Note also that this does reduce the number of years that can be + /// represented from ~584 Billion to ~584. (If this is a problem, + /// please file an issue to let me know what domain needs nanosecond + /// precision over millenia, I'm curious.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444); + /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444); + /// + /// let dt = NaiveDate::from_ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555); + /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555); + /// ~~~~ + #[inline] + pub fn timestamp_nanos(&self) -> i64 { + let as_ns = self.timestamp() * 1_000_000_000; + as_ns + i64::from(self.timestamp_subsec_nanos()) + } + + /// Returns the number of milliseconds since the last whole non-leap second. + /// + /// The return value ranges from 0 to 999, + /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// assert_eq!(dt.timestamp_subsec_millis(), 123); + /// + /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// assert_eq!(dt.timestamp_subsec_millis(), 1_234); + /// ~~~~ + #[inline] + pub fn timestamp_subsec_millis(&self) -> u32 { + self.timestamp_subsec_nanos() / 1_000_000 + } + + /// Returns the number of microseconds since the last whole non-leap second. + /// + /// The return value ranges from 0 to 999,999, + /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// assert_eq!(dt.timestamp_subsec_micros(), 123_456); + /// + /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// assert_eq!(dt.timestamp_subsec_micros(), 1_234_567); + /// ~~~~ + #[inline] + pub fn timestamp_subsec_micros(&self) -> u32 { + self.timestamp_subsec_nanos() / 1_000 + } + + /// Returns the number of nanoseconds since the last whole non-leap second. + /// + /// The return value ranges from 0 to 999,999,999, + /// or for [leap seconds](./struct.NaiveTime.html#leap-second-handling), to 1,999,999,999. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_nano(9, 10, 11, 123_456_789); + /// assert_eq!(dt.timestamp_subsec_nanos(), 123_456_789); + /// + /// let dt = NaiveDate::from_ymd(2015, 7, 1).and_hms_nano(8, 59, 59, 1_234_567_890); + /// assert_eq!(dt.timestamp_subsec_nanos(), 1_234_567_890); + /// ~~~~ + #[inline] + pub fn timestamp_subsec_nanos(&self) -> u32 { + self.time.nanosecond() + } + + /// Adds given `Duration` to the current date and time. + /// + /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), + /// the addition assumes that **there is no leap second ever**, + /// except when the `NaiveDateTime` itself represents a leap second + /// in which case the assumption becomes that **there is exactly a single leap second ever**. + /// + /// Returns `None` when it will result in overflow. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use time::Duration; + /// + /// let from_ymd = NaiveDate::from_ymd; + /// + /// let d = from_ymd(2016, 7, 8); + /// let hms = |h, m, s| d.and_hms(h, m, s); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::zero()), + /// Some(hms(3, 5, 7))); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(1)), + /// Some(hms(3, 5, 8))); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(-1)), + /// Some(hms(3, 5, 6))); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(3600 + 60)), + /// Some(hms(4, 6, 7))); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::seconds(86_400)), + /// Some(from_ymd(2016, 7, 9).and_hms(3, 5, 7))); + /// + /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); + /// assert_eq!(hmsm(3, 5, 7, 980).checked_add_signed(Duration::milliseconds(450)), + /// Some(hmsm(3, 5, 8, 430))); + /// # } + /// ~~~~ + /// + /// Overflow returns `None`. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveDate; + /// # use time::Duration; + /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s); + /// assert_eq!(hms(3, 5, 7).checked_add_signed(Duration::days(1_000_000_000)), None); + /// # } + /// ~~~~ + /// + /// Leap seconds are handled, + /// but the addition assumes that it is the only leap second happened. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveDate; + /// # use time::Duration; + /// # let from_ymd = NaiveDate::from_ymd; + /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); + /// let leap = hmsm(3, 5, 59, 1_300); + /// assert_eq!(leap.checked_add_signed(Duration::zero()), + /// Some(hmsm(3, 5, 59, 1_300))); + /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(-500)), + /// Some(hmsm(3, 5, 59, 800))); + /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(500)), + /// Some(hmsm(3, 5, 59, 1_800))); + /// assert_eq!(leap.checked_add_signed(Duration::milliseconds(800)), + /// Some(hmsm(3, 6, 0, 100))); + /// assert_eq!(leap.checked_add_signed(Duration::seconds(10)), + /// Some(hmsm(3, 6, 9, 300))); + /// assert_eq!(leap.checked_add_signed(Duration::seconds(-10)), + /// Some(hmsm(3, 5, 50, 300))); + /// assert_eq!(leap.checked_add_signed(Duration::days(1)), + /// Some(from_ymd(2016, 7, 9).and_hms_milli(3, 5, 59, 300))); + /// # } + /// ~~~~ + pub fn checked_add_signed(self, rhs: OldDuration) -> Option { + let (time, rhs) = self.time.overflowing_add_signed(rhs); + + // early checking to avoid overflow in OldDuration::seconds + if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { + return None; + } + + let date = try_opt!(self.date.checked_add_signed(OldDuration::seconds(rhs))); + Some(NaiveDateTime { date: date, time: time }) + } + + /// Subtracts given `Duration` from the current date and time. + /// + /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), + /// the subtraction assumes that **there is no leap second ever**, + /// except when the `NaiveDateTime` itself represents a leap second + /// in which case the assumption becomes that **there is exactly a single leap second ever**. + /// + /// Returns `None` when it will result in overflow. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use time::Duration; + /// + /// let from_ymd = NaiveDate::from_ymd; + /// + /// let d = from_ymd(2016, 7, 8); + /// let hms = |h, m, s| d.and_hms(h, m, s); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::zero()), + /// Some(hms(3, 5, 7))); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(1)), + /// Some(hms(3, 5, 6))); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(-1)), + /// Some(hms(3, 5, 8))); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(3600 + 60)), + /// Some(hms(2, 4, 7))); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::seconds(86_400)), + /// Some(from_ymd(2016, 7, 7).and_hms(3, 5, 7))); + /// + /// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); + /// assert_eq!(hmsm(3, 5, 7, 450).checked_sub_signed(Duration::milliseconds(670)), + /// Some(hmsm(3, 5, 6, 780))); + /// # } + /// ~~~~ + /// + /// Overflow returns `None`. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveDate; + /// # use time::Duration; + /// # let hms = |h, m, s| NaiveDate::from_ymd(2016, 7, 8).and_hms(h, m, s); + /// assert_eq!(hms(3, 5, 7).checked_sub_signed(Duration::days(1_000_000_000)), None); + /// # } + /// ~~~~ + /// + /// Leap seconds are handled, + /// but the subtraction assumes that it is the only leap second happened. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveDate; + /// # use time::Duration; + /// # let from_ymd = NaiveDate::from_ymd; + /// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); + /// let leap = hmsm(3, 5, 59, 1_300); + /// assert_eq!(leap.checked_sub_signed(Duration::zero()), + /// Some(hmsm(3, 5, 59, 1_300))); + /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(200)), + /// Some(hmsm(3, 5, 59, 1_100))); + /// assert_eq!(leap.checked_sub_signed(Duration::milliseconds(500)), + /// Some(hmsm(3, 5, 59, 800))); + /// assert_eq!(leap.checked_sub_signed(Duration::seconds(60)), + /// Some(hmsm(3, 5, 0, 300))); + /// assert_eq!(leap.checked_sub_signed(Duration::days(1)), + /// Some(from_ymd(2016, 7, 7).and_hms_milli(3, 6, 0, 300))); + /// # } + /// ~~~~ + pub fn checked_sub_signed(self, rhs: OldDuration) -> Option { + let (time, rhs) = self.time.overflowing_sub_signed(rhs); + + // early checking to avoid overflow in OldDuration::seconds + if rhs <= (-1 << MAX_SECS_BITS) || rhs >= (1 << MAX_SECS_BITS) { + return None; + } + + let date = try_opt!(self.date.checked_sub_signed(OldDuration::seconds(rhs))); + Some(NaiveDateTime { date: date, time: time }) + } + + /// Subtracts another `NaiveDateTime` from the current date and time. + /// This does not overflow or underflow at all. + /// + /// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), + /// the subtraction assumes that **there is no leap second ever**, + /// except when any of the `NaiveDateTime`s themselves represents a leap second + /// in which case the assumption becomes that + /// **there are exactly one (or two) leap second(s) ever**. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveDate; + /// use time::Duration; + /// + /// let from_ymd = NaiveDate::from_ymd; + /// + /// let d = from_ymd(2016, 7, 8); + /// assert_eq!(d.and_hms(3, 5, 7).signed_duration_since(d.and_hms(2, 4, 6)), + /// Duration::seconds(3600 + 60 + 1)); + /// + /// // July 8 is 190th day in the year 2016 + /// let d0 = from_ymd(2016, 1, 1); + /// assert_eq!(d.and_hms_milli(0, 7, 6, 500).signed_duration_since(d0.and_hms(0, 0, 0)), + /// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500)); + /// # } + /// ~~~~ + /// + /// Leap seconds are handled, but the subtraction assumes that + /// there were no other leap seconds happened. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveDate; + /// # use time::Duration; + /// # let from_ymd = NaiveDate::from_ymd; + /// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); + /// assert_eq!(leap.signed_duration_since(from_ymd(2015, 6, 30).and_hms(23, 0, 0)), + /// Duration::seconds(3600) + Duration::milliseconds(500)); + /// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0).signed_duration_since(leap), + /// Duration::seconds(3600) - Duration::milliseconds(500)); + /// # } + /// ~~~~ + pub fn signed_duration_since(self, rhs: NaiveDateTime) -> OldDuration { + self.date.signed_duration_since(rhs.date) + self.time.signed_duration_since(rhs.time) + } + + /// Formats the combined date and time with the specified formatting items. + /// Otherwise it is same to the ordinary [`format`](#method.format) method. + /// + /// The `Iterator` of items should be `Clone`able, + /// since the resulting `DelayedFormat` value may be formatted multiple times. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// use chrono::format::strftime::StrftimeItems; + /// + /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S"); + /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// assert_eq!(dt.format_with_items(fmt.clone()).to_string(), "2015-09-05 23:56:04"); + /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # use chrono::format::strftime::StrftimeItems; + /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone(); + /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04"); + /// ~~~~ + #[inline] + pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat + where I: Iterator> + Clone { + DelayedFormat::new(Some(self.date), Some(self.time), items) + } + + /// Formats the combined date and time with the specified format string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// This returns a `DelayedFormat`, + /// which gets converted to a string only when actual formatting happens. + /// You may use the `to_string` method to get a `String`, + /// or just feed it into `print!` and other formatting macros. + /// (In this way it avoids the redundant memory allocation.) + /// + /// A wrong format string does *not* issue an error immediately. + /// Rather, converting or formatting the `DelayedFormat` fails. + /// You are recommended to immediately use `DelayedFormat` for this reason. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveDate; + /// + /// let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); + /// assert_eq!(dt.format("around %l %p on %b %-d").to_string(), "around 11 PM on Sep 5"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveDate; + /// # let dt = NaiveDate::from_ymd(2015, 9, 5).and_hms(23, 56, 4); + /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04"); + /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5"); + /// ~~~~ + #[inline] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } +} + +impl Datelike for NaiveDateTime { + /// Returns the year number in the [calendar date](./index.html#calendar-date). + /// + /// See also the [`NaiveDate::year`](./struct.NaiveDate.html#method.year) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.year(), 2015); + /// ~~~~ + #[inline] + fn year(&self) -> i32 { + self.date.year() + } + + /// Returns the month number starting from 1. + /// + /// The return value ranges from 1 to 12. + /// + /// See also the [`NaiveDate::month`](./struct.NaiveDate.html#method.month) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.month(), 9); + /// ~~~~ + #[inline] + fn month(&self) -> u32 { + self.date.month() + } + + /// Returns the month number starting from 0. + /// + /// The return value ranges from 0 to 11. + /// + /// See also the [`NaiveDate::month0`](./struct.NaiveDate.html#method.month0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.month0(), 8); + /// ~~~~ + #[inline] + fn month0(&self) -> u32 { + self.date.month0() + } + + /// Returns the day of month starting from 1. + /// + /// The return value ranges from 1 to 31. (The last day of month differs by months.) + /// + /// See also the [`NaiveDate::day`](./struct.NaiveDate.html#method.day) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.day(), 25); + /// ~~~~ + #[inline] + fn day(&self) -> u32 { + self.date.day() + } + + /// Returns the day of month starting from 0. + /// + /// The return value ranges from 0 to 30. (The last day of month differs by months.) + /// + /// See also the [`NaiveDate::day0`](./struct.NaiveDate.html#method.day0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.day0(), 24); + /// ~~~~ + #[inline] + fn day0(&self) -> u32 { + self.date.day0() + } + + /// Returns the day of year starting from 1. + /// + /// The return value ranges from 1 to 366. (The last day of year differs by years.) + /// + /// See also the [`NaiveDate::ordinal`](./struct.NaiveDate.html#method.ordinal) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.ordinal(), 268); + /// ~~~~ + #[inline] + fn ordinal(&self) -> u32 { + self.date.ordinal() + } + + /// Returns the day of year starting from 0. + /// + /// The return value ranges from 0 to 365. (The last day of year differs by years.) + /// + /// See also the [`NaiveDate::ordinal0`](./struct.NaiveDate.html#method.ordinal0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.ordinal0(), 267); + /// ~~~~ + #[inline] + fn ordinal0(&self) -> u32 { + self.date.ordinal0() + } + + /// Returns the day of week. + /// + /// See also the [`NaiveDate::weekday`](./struct.NaiveDate.html#method.weekday) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike, Weekday}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.weekday(), Weekday::Fri); + /// ~~~~ + #[inline] + fn weekday(&self) -> Weekday { + self.date.weekday() + } + + #[inline] + fn iso_week(&self) -> IsoWeek { + self.date.iso_week() + } + + /// Makes a new `NaiveDateTime` with the year number changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_year`](./struct.NaiveDate.html#method.with_year) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 25).and_hms(12, 34, 56); + /// assert_eq!(dt.with_year(2016), Some(NaiveDate::from_ymd(2016, 9, 25).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_year(-308), Some(NaiveDate::from_ymd(-308, 9, 25).and_hms(12, 34, 56))); + /// ~~~~ + #[inline] + fn with_year(&self, year: i32) -> Option { + self.date.with_year(year).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the month number (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_month`](./struct.NaiveDate.html#method.with_month) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56); + /// assert_eq!(dt.with_month(10), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_month(13), None); // no month 13 + /// assert_eq!(dt.with_month(2), None); // no February 30 + /// ~~~~ + #[inline] + fn with_month(&self, month: u32) -> Option { + self.date.with_month(month).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the month number (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_month0`](./struct.NaiveDate.html#method.with_month0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56); + /// assert_eq!(dt.with_month0(9), Some(NaiveDate::from_ymd(2015, 10, 30).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_month0(12), None); // no month 13 + /// assert_eq!(dt.with_month0(1), None); // no February 30 + /// ~~~~ + #[inline] + fn with_month0(&self, month0: u32) -> Option { + self.date.with_month0(month0).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the day of month (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_day`](./struct.NaiveDate.html#method.with_day) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_day(30), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_day(31), None); // no September 31 + /// ~~~~ + #[inline] + fn with_day(&self, day: u32) -> Option { + self.date.with_day(day).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the day of month (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_day0`](./struct.NaiveDate.html#method.with_day0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_day0(29), Some(NaiveDate::from_ymd(2015, 9, 30).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_day0(30), None); // no September 31 + /// ~~~~ + #[inline] + fn with_day0(&self, day0: u32) -> Option { + self.date.with_day0(day0).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the day of year (starting from 1) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_ordinal`](./struct.NaiveDate.html#method.with_ordinal) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_ordinal(60), + /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_ordinal(366), None); // 2015 had only 365 days + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_ordinal(60), + /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_ordinal(366), + /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56))); + /// ~~~~ + #[inline] + fn with_ordinal(&self, ordinal: u32) -> Option { + self.date.with_ordinal(ordinal).map(|d| NaiveDateTime { date: d, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the day of year (starting from 0) changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveDate::with_ordinal0`](./struct.NaiveDate.html#method.with_ordinal0) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Datelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2015, 3, 1).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_ordinal0(365), None); // 2015 had only 365 days + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2016, 9, 8).and_hms(12, 34, 56); + /// assert_eq!(dt.with_ordinal0(59), + /// Some(NaiveDate::from_ymd(2016, 2, 29).and_hms(12, 34, 56))); + /// assert_eq!(dt.with_ordinal0(365), + /// Some(NaiveDate::from_ymd(2016, 12, 31).and_hms(12, 34, 56))); + /// ~~~~ + #[inline] + fn with_ordinal0(&self, ordinal0: u32) -> Option { + self.date.with_ordinal0(ordinal0).map(|d| NaiveDateTime { date: d, ..*self }) + } +} + +impl Timelike for NaiveDateTime { + /// Returns the hour number from 0 to 23. + /// + /// See also the [`NaiveTime::hour`](./struct.NaiveTime.html#method.hour) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.hour(), 12); + /// ~~~~ + #[inline] + fn hour(&self) -> u32 { + self.time.hour() + } + + /// Returns the minute number from 0 to 59. + /// + /// See also the [`NaiveTime::minute`](./struct.NaiveTime.html#method.minute) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.minute(), 34); + /// ~~~~ + #[inline] + fn minute(&self) -> u32 { + self.time.minute() + } + + /// Returns the second number from 0 to 59. + /// + /// See also the [`NaiveTime::second`](./struct.NaiveTime.html#method.second) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.second(), 56); + /// ~~~~ + #[inline] + fn second(&self) -> u32 { + self.time.second() + } + + /// Returns the number of nanoseconds since the whole non-leap second. + /// The range from 1,000,000,000 to 1,999,999,999 represents + /// the [leap second](./struct.NaiveTime.html#leap-second-handling). + /// + /// See also the + /// [`NaiveTime::nanosecond`](./struct.NaiveTime.html#method.nanosecond) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.nanosecond(), 789_000_000); + /// ~~~~ + #[inline] + fn nanosecond(&self) -> u32 { + self.time.nanosecond() + } + + /// Makes a new `NaiveDateTime` with the hour number changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveTime::with_hour`](./struct.NaiveTime.html#method.with_hour) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.with_hour(7), + /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(7, 34, 56, 789))); + /// assert_eq!(dt.with_hour(24), None); + /// ~~~~ + #[inline] + fn with_hour(&self, hour: u32) -> Option { + self.time.with_hour(hour).map(|t| NaiveDateTime { time: t, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the minute number changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// + /// See also the + /// [`NaiveTime::with_minute`](./struct.NaiveTime.html#method.with_minute) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.with_minute(45), + /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 45, 56, 789))); + /// assert_eq!(dt.with_minute(60), None); + /// ~~~~ + #[inline] + fn with_minute(&self, min: u32) -> Option { + self.time.with_minute(min).map(|t| NaiveDateTime { time: t, ..*self }) + } + + /// Makes a new `NaiveDateTime` with the second number changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// As with the [`second`](#method.second) method, + /// the input range is restricted to 0 through 59. + /// + /// See also the + /// [`NaiveTime::with_second`](./struct.NaiveTime.html#method.with_second) method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.with_second(17), + /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 17, 789))); + /// assert_eq!(dt.with_second(60), None); + /// ~~~~ + #[inline] + fn with_second(&self, sec: u32) -> Option { + self.time.with_second(sec).map(|t| NaiveDateTime { time: t, ..*self }) + } + + /// Makes a new `NaiveDateTime` with nanoseconds since the whole non-leap second changed. + /// + /// Returns `None` when the resulting `NaiveDateTime` would be invalid. + /// As with the [`nanosecond`](#method.nanosecond) method, + /// the input range can exceed 1,000,000,000 for leap seconds. + /// + /// See also the + /// [`NaiveTime::with_nanosecond`](./struct.NaiveTime.html#method.with_nanosecond) + /// method. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, NaiveDateTime, Timelike}; + /// + /// let dt: NaiveDateTime = NaiveDate::from_ymd(2015, 9, 8).and_hms_milli(12, 34, 56, 789); + /// assert_eq!(dt.with_nanosecond(333_333_333), + /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 333_333_333))); + /// assert_eq!(dt.with_nanosecond(1_333_333_333), // leap second + /// Some(NaiveDate::from_ymd(2015, 9, 8).and_hms_nano(12, 34, 56, 1_333_333_333))); + /// assert_eq!(dt.with_nanosecond(2_000_000_000), None); + /// ~~~~ + #[inline] + fn with_nanosecond(&self, nano: u32) -> Option { + self.time.with_nanosecond(nano).map(|t| NaiveDateTime { time: t, ..*self }) + } +} + +/// `NaiveDateTime` can be used as a key to the hash maps (in principle). +/// +/// Practically this also takes account of fractional seconds, so it is not recommended. +/// (For the obvious reason this also distinguishes leap seconds from non-leap seconds.) +#[cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))] +impl hash::Hash for NaiveDateTime { + fn hash(&self, state: &mut H) { + self.date.hash(state); + self.time.hash(state); + } +} + +/// An addition of `Duration` to `NaiveDateTime` yields another `NaiveDateTime`. +/// +/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), +/// the addition assumes that **there is no leap second ever**, +/// except when the `NaiveDateTime` itself represents a leap second +/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// +/// Panics on underflow or overflow. +/// Use [`NaiveDateTime::checked_add_signed`](#method.checked_add_signed) to detect that. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// let d = from_ymd(2016, 7, 8); +/// let hms = |h, m, s| d.and_hms(h, m, s); +/// assert_eq!(hms(3, 5, 7) + Duration::zero(), hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) + Duration::seconds(1), hms(3, 5, 8)); +/// assert_eq!(hms(3, 5, 7) + Duration::seconds(-1), hms(3, 5, 6)); +/// assert_eq!(hms(3, 5, 7) + Duration::seconds(3600 + 60), hms(4, 6, 7)); +/// assert_eq!(hms(3, 5, 7) + Duration::seconds(86_400), +/// from_ymd(2016, 7, 9).and_hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) + Duration::days(365), +/// from_ymd(2017, 7, 8).and_hms(3, 5, 7)); +/// +/// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); +/// assert_eq!(hmsm(3, 5, 7, 980) + Duration::milliseconds(450), hmsm(3, 5, 8, 430)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, +/// but the addition assumes that it is the only leap second happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveDate; +/// # use time::Duration; +/// # let from_ymd = NaiveDate::from_ymd; +/// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); +/// let leap = hmsm(3, 5, 59, 1_300); +/// assert_eq!(leap + Duration::zero(), hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap + Duration::milliseconds(-500), hmsm(3, 5, 59, 800)); +/// assert_eq!(leap + Duration::milliseconds(500), hmsm(3, 5, 59, 1_800)); +/// assert_eq!(leap + Duration::milliseconds(800), hmsm(3, 6, 0, 100)); +/// assert_eq!(leap + Duration::seconds(10), hmsm(3, 6, 9, 300)); +/// assert_eq!(leap + Duration::seconds(-10), hmsm(3, 5, 50, 300)); +/// assert_eq!(leap + Duration::days(1), +/// from_ymd(2016, 7, 9).and_hms_milli(3, 5, 59, 300)); +/// # } +/// ~~~~ +impl Add for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn add(self, rhs: OldDuration) -> NaiveDateTime { + self.checked_add_signed(rhs).expect("`NaiveDateTime + Duration` overflowed") + } +} + +impl AddAssign for NaiveDateTime { + #[inline] + fn add_assign(&mut self, rhs: OldDuration) { + *self = self.add(rhs); + } +} + +/// A subtraction of `Duration` from `NaiveDateTime` yields another `NaiveDateTime`. +/// It is same to the addition with a negated `Duration`. +/// +/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), +/// the addition assumes that **there is no leap second ever**, +/// except when the `NaiveDateTime` itself represents a leap second +/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// +/// Panics on underflow or overflow. +/// Use [`NaiveDateTime::checked_sub_signed`](#method.checked_sub_signed) to detect that. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// let d = from_ymd(2016, 7, 8); +/// let hms = |h, m, s| d.and_hms(h, m, s); +/// assert_eq!(hms(3, 5, 7) - Duration::zero(), hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) - Duration::seconds(1), hms(3, 5, 6)); +/// assert_eq!(hms(3, 5, 7) - Duration::seconds(-1), hms(3, 5, 8)); +/// assert_eq!(hms(3, 5, 7) - Duration::seconds(3600 + 60), hms(2, 4, 7)); +/// assert_eq!(hms(3, 5, 7) - Duration::seconds(86_400), +/// from_ymd(2016, 7, 7).and_hms(3, 5, 7)); +/// assert_eq!(hms(3, 5, 7) - Duration::days(365), +/// from_ymd(2015, 7, 9).and_hms(3, 5, 7)); +/// +/// let hmsm = |h, m, s, milli| d.and_hms_milli(h, m, s, milli); +/// assert_eq!(hmsm(3, 5, 7, 450) - Duration::milliseconds(670), hmsm(3, 5, 6, 780)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, +/// but the subtraction assumes that it is the only leap second happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveDate; +/// # use time::Duration; +/// # let from_ymd = NaiveDate::from_ymd; +/// # let hmsm = |h, m, s, milli| from_ymd(2016, 7, 8).and_hms_milli(h, m, s, milli); +/// let leap = hmsm(3, 5, 59, 1_300); +/// assert_eq!(leap - Duration::zero(), hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap - Duration::milliseconds(200), hmsm(3, 5, 59, 1_100)); +/// assert_eq!(leap - Duration::milliseconds(500), hmsm(3, 5, 59, 800)); +/// assert_eq!(leap - Duration::seconds(60), hmsm(3, 5, 0, 300)); +/// assert_eq!(leap - Duration::days(1), +/// from_ymd(2016, 7, 7).and_hms_milli(3, 6, 0, 300)); +/// # } +/// ~~~~ +impl Sub for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn sub(self, rhs: OldDuration) -> NaiveDateTime { + self.checked_sub_signed(rhs).expect("`NaiveDateTime - Duration` overflowed") + } +} + +impl SubAssign for NaiveDateTime { + #[inline] + fn sub_assign(&mut self, rhs: OldDuration) { + *self = self.sub(rhs); + } +} + +/// Subtracts another `NaiveDateTime` from the current date and time. +/// This does not overflow or underflow at all. +/// +/// As a part of Chrono's [leap second handling](./struct.NaiveTime.html#leap-second-handling), +/// the subtraction assumes that **there is no leap second ever**, +/// except when any of the `NaiveDateTime`s themselves represents a leap second +/// in which case the assumption becomes that +/// **there are exactly one (or two) leap second(s) ever**. +/// +/// The implementation is a wrapper around +/// [`NaiveDateTime::signed_duration_since`](#method.signed_duration_since). +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveDate; +/// use time::Duration; +/// +/// let from_ymd = NaiveDate::from_ymd; +/// +/// let d = from_ymd(2016, 7, 8); +/// assert_eq!(d.and_hms(3, 5, 7) - d.and_hms(2, 4, 6), Duration::seconds(3600 + 60 + 1)); +/// +/// // July 8 is 190th day in the year 2016 +/// let d0 = from_ymd(2016, 1, 1); +/// assert_eq!(d.and_hms_milli(0, 7, 6, 500) - d0.and_hms(0, 0, 0), +/// Duration::seconds(189 * 86_400 + 7 * 60 + 6) + Duration::milliseconds(500)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, but the subtraction assumes that +/// there were no other leap seconds happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveDate; +/// # use time::Duration; +/// # let from_ymd = NaiveDate::from_ymd; +/// let leap = from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); +/// assert_eq!(leap - from_ymd(2015, 6, 30).and_hms(23, 0, 0), +/// Duration::seconds(3600) + Duration::milliseconds(500)); +/// assert_eq!(from_ymd(2015, 7, 1).and_hms(1, 0, 0) - leap, +/// Duration::seconds(3600) - Duration::milliseconds(500)); +/// # } +/// ~~~~ +impl Sub for NaiveDateTime { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: NaiveDateTime) -> OldDuration { + self.signed_duration_since(rhs) + } +} + +/// The `Debug` output of the naive date and time `dt` is same to +/// [`dt.format("%Y-%m-%dT%H:%M:%S%.f")`](../format/strftime/index.html). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// It should be noted that, for leap seconds not on the minute boundary, +/// it may print a representation not distinguishable from non-leap seconds. +/// This doesn't matter in practice, since such leap seconds never happened. +/// (By the time of the first leap second on 1972-06-30, +/// every time zone offset around the world has standardized to the 5-minute alignment.) +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveDate; +/// +/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24); +/// assert_eq!(format!("{:?}", dt), "2016-11-15T07:39:24"); +/// ~~~~ +/// +/// Leap seconds may also be used. +/// +/// ~~~~ +/// # use chrono::NaiveDate; +/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); +/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60.500"); +/// ~~~~ +impl fmt::Debug for NaiveDateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}T{:?}", self.date, self.time) + } +} + +/// The `Debug` output of the naive date and time `dt` is same to +/// [`dt.format("%Y-%m-%d %H:%M:%S%.f")`](../format/strftime/index.html). +/// +/// It should be noted that, for leap seconds not on the minute boundary, +/// it may print a representation not distinguishable from non-leap seconds. +/// This doesn't matter in practice, since such leap seconds never happened. +/// (By the time of the first leap second on 1972-06-30, +/// every time zone offset around the world has standardized to the 5-minute alignment.) +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveDate; +/// +/// let dt = NaiveDate::from_ymd(2016, 11, 15).and_hms(7, 39, 24); +/// assert_eq!(format!("{}", dt), "2016-11-15 07:39:24"); +/// ~~~~ +/// +/// Leap seconds may also be used. +/// +/// ~~~~ +/// # use chrono::NaiveDate; +/// let dt = NaiveDate::from_ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_500); +/// assert_eq!(format!("{}", dt), "2015-06-30 23:59:60.500"); +/// ~~~~ +impl fmt::Display for NaiveDateTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.date, self.time) + } +} + +/// Parsing a `str` into a `NaiveDateTime` uses the same format, +/// [`%Y-%m-%dT%H:%M:%S%.f`](../format/strftime/index.html), as in `Debug`. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::{NaiveDateTime, NaiveDate}; +/// +/// let dt = NaiveDate::from_ymd(2015, 9, 18).and_hms(23, 56, 4); +/// assert_eq!("2015-09-18T23:56:04".parse::(), Ok(dt)); +/// +/// let dt = NaiveDate::from_ymd(12345, 6, 7).and_hms_milli(7, 59, 59, 1_500); // leap second +/// assert_eq!("+12345-6-7T7:59:60.5".parse::(), Ok(dt)); +/// +/// assert!("foo".parse::().is_err()); +/// ~~~~ +impl str::FromStr for NaiveDateTime { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult { + const ITEMS: &'static [Item<'static>] = &[ + Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Space(""), Item::Literal("-"), + Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive? + Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Fixed(Fixed::Nanosecond), Item::Space(""), + ]; + + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_naive_datetime_with_offset(0) + } +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_encodable_json(to_string: F) + where F: Fn(&NaiveDateTime) -> Result, E: ::std::fmt::Debug +{ + use naive::{MIN_DATE, MAX_DATE}; + + assert_eq!( + to_string(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(), + Some(r#""2016-07-08T09:10:48.090""#.into())); + assert_eq!( + to_string(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), + Some(r#""2014-07-24T12:34:06""#.into())); + assert_eq!( + to_string(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(), + Some(r#""0000-01-01T00:00:60""#.into())); + assert_eq!( + to_string(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(), + Some(r#""-0001-12-31T23:59:59.000000007""#.into())); + assert_eq!( + to_string(&MIN_DATE.and_hms(0, 0, 0)).ok(), + Some(r#""-262144-01-01T00:00:00""#.into())); + assert_eq!( + to_string(&MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(), + Some(r#""+262143-12-31T23:59:60.999999999""#.into())); +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_decodable_json(from_str: F) + where F: Fn(&str) -> Result, E: ::std::fmt::Debug +{ + use naive::{MIN_DATE, MAX_DATE}; + + assert_eq!( + from_str(r#""2016-07-08T09:10:48.090""#).ok(), + Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90))); + assert_eq!( + from_str(r#""2016-7-8T9:10:48.09""#).ok(), + Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90))); + assert_eq!( + from_str(r#""2014-07-24T12:34:06""#).ok(), + Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6))); + assert_eq!( + from_str(r#""0000-01-01T00:00:60""#).ok(), + Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000))); + assert_eq!( + from_str(r#""0-1-1T0:0:60""#).ok(), + Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000))); + assert_eq!( + from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(), + Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7))); + assert_eq!( + from_str(r#""-262144-01-01T00:00:00""#).ok(), + Some(MIN_DATE.and_hms(0, 0, 0))); + assert_eq!( + from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(), + Some(MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999))); + assert_eq!( + from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored + Some(MAX_DATE.and_hms_nano(23, 59, 59, 1_999_999_999))); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""2016-07-08""#).is_err()); + assert!(from_str(r#""09:10:48.090""#).is_err()); + assert!(from_str(r#""20160708T091048.090""#).is_err()); + assert!(from_str(r#""2000-00-00T00:00:00""#).is_err()); + assert!(from_str(r#""2000-02-30T00:00:00""#).is_err()); + assert!(from_str(r#""2001-02-29T00:00:00""#).is_err()); + assert!(from_str(r#""2002-02-28T24:00:00""#).is_err()); + assert!(from_str(r#""2002-02-28T23:60:00""#).is_err()); + assert!(from_str(r#""2002-02-28T23:59:61""#).is_err()); + assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err()); + assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err()); + assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err()); + assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err()); + assert!(from_str(r#"20160708000000"#).is_err()); + assert!(from_str(r#"{}"#).is_err()); + // pre-0.3.0 rustc-serialize format is now invalid + assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err()); + assert!(from_str(r#"null"#).is_err()); +} + + +#[cfg(all(test, feature = "rustc-serialize"))] +fn test_decodable_json_timestamp(from_str: F) + where F: Fn(&str) -> Result, E: ::std::fmt::Debug +{ + assert_eq!( + *from_str("0").unwrap(), + NaiveDate::from_ymd(1970, 1, 1).and_hms(0, 0, 0), + "should parse integers as timestamps" + ); + assert_eq!( + *from_str("-1").unwrap(), + NaiveDate::from_ymd(1969, 12, 31).and_hms(23, 59, 59), + "should parse integers as timestamps" + ); +} + +#[cfg(feature = "rustc-serialize")] +pub mod rustc_serialize { + use std::ops::Deref; + use super::NaiveDateTime; + use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + + impl Encodable for NaiveDateTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } + } + + impl Decodable for NaiveDateTime { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid date time string")) + } + } + + /// A `DateTime` that can be deserialized from a seconds-based timestamp + #[derive(Debug)] + #[deprecated(since = "1.4.2", + note = "RustcSerialize will be removed before chrono 1.0, use Serde instead")] + pub struct TsSeconds(NaiveDateTime); + + #[allow(deprecated)] + impl From for NaiveDateTime { + /// Pull the internal NaiveDateTime out + #[allow(deprecated)] + fn from(obj: TsSeconds) -> NaiveDateTime { + obj.0 + } + } + + #[allow(deprecated)] + impl Deref for TsSeconds { + type Target = NaiveDateTime; + + #[allow(deprecated)] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + #[allow(deprecated)] + impl Decodable for TsSeconds { + #[allow(deprecated)] + fn decode(d: &mut D) -> Result { + Ok(TsSeconds( + NaiveDateTime::from_timestamp_opt(d.read_i64()?, 0) + .ok_or_else(|| d.error("invalid timestamp"))?)) + } + } + + #[cfg(test)] use rustc_serialize::json; + + #[test] + fn test_encodable() { + super::test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + super::test_decodable_json(json::decode); + } + + #[test] + fn test_decodable_timestamps() { + super::test_decodable_json_timestamp(json::decode); + + } + +} + +/// Tools to help serializing/deserializing `NaiveDateTime`s +#[cfg(feature = "serde")] +pub mod serde { + use std::fmt; + use super::{NaiveDateTime}; + use serdelib::{ser, de}; + + /// Serialize a `NaiveDateTime` as an RFC 3339 string + /// + /// See [the `serde` module](./serde/index.html) for alternate + /// serialization formats. + impl ser::Serialize for NaiveDateTime { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer + { + struct FormatWrapped<'a, D: 'a> { + inner: &'a D + } + + impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + serializer.collect_str(&FormatWrapped { inner: &self }) + } + } + + struct NaiveDateTimeVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor { + type Value = NaiveDateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + write!(formatter, "a formatted date and time string") + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::custom(format!("{}", err))) + } + } + + impl<'de> de::Deserialize<'de> for NaiveDateTime { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(NaiveDateTimeVisitor) + } + } + + /// Used to serialize/deserialize from nanosecond-precision timestamps + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// use chrono::naive::serde::ts_nanoseconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_nanoseconds")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_nanoseconds { + use std::fmt; + use serdelib::{ser, de}; + + use NaiveDateTime; + + /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # #[macro_use] extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// # use serde::Serialize; + /// use chrono::naive::serde::ts_nanoseconds::serialize as to_nano_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_nano_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp_nanos()) + } + + /// Deserialize a `DateTime` from a nanoseconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{NaiveDateTime, Utc}; + /// # use serde::Deserialize; + /// use chrono::naive::serde::ts_nanoseconds::deserialize as from_nano_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_nano_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(NaiveDateTimeFromNanoSecondsVisitor))) + } + + struct NaiveDateTimeFromNanoSecondsVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateTimeFromNanoSecondsVisitor { + type Value = NaiveDateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + formatter.write_str("a unix timestamp") + } + + fn visit_i64(self, value: i64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt(value / 1_000_000_000, + (value % 1_000_000_000) as u32) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + + fn visit_u64(self, value: u64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt(value as i64 / 1_000_000_000, + (value as i64 % 1_000_000_000) as u32) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + } + } + + /// Used to serialize/deserialize from millisecond-precision timestamps + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// use chrono::naive::serde::ts_milliseconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_milliseconds")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let time = NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_milliseconds { + use std::fmt; + use serdelib::{ser, de}; + + use NaiveDateTime; + + /// Serialize a UTC datetime into an integer number of milliseconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # #[macro_use] extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// # use serde::Serialize; + /// use chrono::naive::serde::ts_milliseconds::serialize as to_milli_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_milli_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: NaiveDate::from_ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1526522699918}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp_millis()) + } + + /// Deserialize a `DateTime` from a milliseconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{NaiveDateTime, Utc}; + /// # use serde::Deserialize; + /// use chrono::naive::serde::ts_milliseconds::deserialize as from_milli_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_milli_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(NaiveDateTimeFromMilliSecondsVisitor))) + } + + struct NaiveDateTimeFromMilliSecondsVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateTimeFromMilliSecondsVisitor { + type Value = NaiveDateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + formatter.write_str("a unix timestamp") + } + + fn visit_i64(self, value: i64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt(value / 1000, + ((value % 1000) * 1_000_000) as u32) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + + fn visit_u64(self, value: u64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt((value / 1000) as i64, + ((value % 1000) * 1_000_000) as u32) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + } + } + + /// Used to serialize/deserialize from second-precision timestamps + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// use chrono::naive::serde::ts_seconds; + /// #[derive(Deserialize, Serialize)] + /// struct S { + /// #[serde(with = "ts_seconds")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let time = NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0); + /// let my_s = S { + /// time: time.clone(), + /// }; + /// + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1431684000}"#); + /// let my_s: S = serde_json::from_str(&as_string)?; + /// assert_eq!(my_s.time, time); + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub mod ts_seconds { + use std::fmt; + use serdelib::{ser, de}; + + use NaiveDateTime; + + /// Serialize a UTC datetime into an integer number of seconds since the epoch + /// + /// Intended for use with `serde`s `serialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # #[macro_use] extern crate serde; + /// # extern crate chrono; + /// # use chrono::{TimeZone, NaiveDate, NaiveDateTime, Utc}; + /// # use serde::Serialize; + /// use chrono::naive::serde::ts_seconds::serialize as to_ts; + /// #[derive(Serialize)] + /// struct S { + /// #[serde(serialize_with = "to_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s = S { + /// time: NaiveDate::from_ymd(2015, 5, 15).and_hms(10, 0, 0), + /// }; + /// let as_string = serde_json::to_string(&my_s)?; + /// assert_eq!(as_string, r#"{"time":1431684000}"#); + /// # Ok(as_string) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn serialize(dt: &NaiveDateTime, serializer: S) -> Result + where S: ser::Serializer + { + serializer.serialize_i64(dt.timestamp()) + } + + /// Deserialize a `DateTime` from a seconds timestamp + /// + /// Intended for use with `serde`s `deserialize_with` attribute. + /// + /// # Example: + /// + /// ```rust + /// # // We mark this ignored so that we can test on 1.13 (which does not + /// # // support custom derive), and run tests with --ignored on beta and + /// # // nightly to actually trigger these. + /// # + /// # #[macro_use] extern crate serde_derive; + /// # #[macro_use] extern crate serde_json; + /// # extern crate serde; + /// # extern crate chrono; + /// # use chrono::{NaiveDateTime, Utc}; + /// # use serde::Deserialize; + /// use chrono::naive::serde::ts_seconds::deserialize as from_ts; + /// #[derive(Deserialize)] + /// struct S { + /// #[serde(deserialize_with = "from_ts")] + /// time: NaiveDateTime + /// } + /// + /// # fn example() -> Result { + /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; + /// # Ok(my_s) + /// # } + /// # fn main() { example().unwrap(); } + /// ``` + pub fn deserialize<'de, D>(d: D) -> Result + where D: de::Deserializer<'de> + { + Ok(try!(d.deserialize_i64(NaiveDateTimeFromSecondsVisitor))) + } + + struct NaiveDateTimeFromSecondsVisitor; + + impl<'de> de::Visitor<'de> for NaiveDateTimeFromSecondsVisitor { + type Value = NaiveDateTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + formatter.write_str("a unix timestamp") + } + + fn visit_i64(self, value: i64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt(value, 0) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + + fn visit_u64(self, value: u64) -> Result + where E: de::Error + { + NaiveDateTime::from_timestamp_opt(value as i64, 0) + .ok_or_else(|| E::custom(format!("value is not a legal timestamp: {}", value))) + } + } + } + + #[cfg(test)] extern crate serde_json; + #[cfg(test)] extern crate bincode; + + #[test] + fn test_serde_serialize() { + super::test_encodable_json(self::serde_json::to_string); + } + + #[test] + fn test_serde_deserialize() { + super::test_decodable_json(|input| self::serde_json::from_str(&input)); + } + + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use naive::NaiveDate; + use self::bincode::{Infinite, serialize, deserialize}; + + let dt = NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90); + let encoded = serialize(&dt, Infinite).unwrap(); + let decoded: NaiveDateTime = deserialize(&encoded).unwrap(); + assert_eq!(dt, decoded); + } +} + +#[cfg(test)] +mod tests { + use super::NaiveDateTime; + use Datelike; + use naive::{NaiveDate, MIN_DATE, MAX_DATE}; + use std::i64; + use oldtime::Duration; + + #[test] + fn test_datetime_from_timestamp() { + let from_timestamp = |secs| NaiveDateTime::from_timestamp_opt(secs, 0); + let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s); + assert_eq!(from_timestamp(-1), Some(ymdhms(1969, 12, 31, 23, 59, 59))); + assert_eq!(from_timestamp(0), Some(ymdhms(1970, 1, 1, 0, 0, 0))); + assert_eq!(from_timestamp(1), Some(ymdhms(1970, 1, 1, 0, 0, 1))); + assert_eq!(from_timestamp(1_000_000_000), Some(ymdhms(2001, 9, 9, 1, 46, 40))); + assert_eq!(from_timestamp(0x7fffffff), Some(ymdhms(2038, 1, 19, 3, 14, 7))); + assert_eq!(from_timestamp(i64::MIN), None); + assert_eq!(from_timestamp(i64::MAX), None); + } + + #[test] + fn test_datetime_add() { + fn check((y,m,d,h,n,s): (i32,u32,u32,u32,u32,u32), rhs: Duration, + result: Option<(i32,u32,u32,u32,u32,u32)>) { + let lhs = NaiveDate::from_ymd(y, m, d).and_hms(h, n, s); + let sum = result.map(|(y,m,d,h,n,s)| NaiveDate::from_ymd(y, m, d).and_hms(h, n, s)); + assert_eq!(lhs.checked_add_signed(rhs), sum); + assert_eq!(lhs.checked_sub_signed(-rhs), sum); + }; + + check((2014,5,6, 7,8,9), Duration::seconds(3600 + 60 + 1), Some((2014,5,6, 8,9,10))); + check((2014,5,6, 7,8,9), Duration::seconds(-(3600 + 60 + 1)), Some((2014,5,6, 6,7,8))); + check((2014,5,6, 7,8,9), Duration::seconds(86399), Some((2014,5,7, 7,8,8))); + check((2014,5,6, 7,8,9), Duration::seconds(86_400 * 10), Some((2014,5,16, 7,8,9))); + check((2014,5,6, 7,8,9), Duration::seconds(-86_400 * 10), Some((2014,4,26, 7,8,9))); + check((2014,5,6, 7,8,9), Duration::seconds(86_400 * 10), Some((2014,5,16, 7,8,9))); + + // overflow check + // assumes that we have correct values for MAX/MIN_DAYS_FROM_YEAR_0 from `naive::date`. + // (they are private constants, but the equivalence is tested in that module.) + let max_days_from_year_0 = MAX_DATE.signed_duration_since(NaiveDate::from_ymd(0,1,1)); + check((0,1,1, 0,0,0), max_days_from_year_0, Some((MAX_DATE.year(),12,31, 0,0,0))); + check((0,1,1, 0,0,0), max_days_from_year_0 + Duration::seconds(86399), + Some((MAX_DATE.year(),12,31, 23,59,59))); + check((0,1,1, 0,0,0), max_days_from_year_0 + Duration::seconds(86_400), None); + check((0,1,1, 0,0,0), Duration::max_value(), None); + + let min_days_from_year_0 = MIN_DATE.signed_duration_since(NaiveDate::from_ymd(0,1,1)); + check((0,1,1, 0,0,0), min_days_from_year_0, Some((MIN_DATE.year(),1,1, 0,0,0))); + check((0,1,1, 0,0,0), min_days_from_year_0 - Duration::seconds(1), None); + check((0,1,1, 0,0,0), Duration::min_value(), None); + } + + #[test] + fn test_datetime_sub() { + let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s); + let since = NaiveDateTime::signed_duration_since; + assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 9)), + Duration::zero()); + assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 10), ymdhms(2014, 5, 6, 7, 8, 9)), + Duration::seconds(1)); + assert_eq!(since(ymdhms(2014, 5, 6, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), + Duration::seconds(-1)); + assert_eq!(since(ymdhms(2014, 5, 7, 7, 8, 9), ymdhms(2014, 5, 6, 7, 8, 10)), + Duration::seconds(86399)); + assert_eq!(since(ymdhms(2001, 9, 9, 1, 46, 39), ymdhms(1970, 1, 1, 0, 0, 0)), + Duration::seconds(999_999_999)); + } + + #[test] + fn test_datetime_addassignment() { + let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s); + let mut date = ymdhms(2016, 10, 1, 10, 10, 10); + date += Duration::minutes(10_000_000); + assert_eq!(date, ymdhms(2035, 10, 6, 20, 50, 10)); + date += Duration::days(10); + assert_eq!(date, ymdhms(2035, 10, 16, 20, 50, 10)); + } + + #[test] + fn test_datetime_subassignment() { + let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s); + let mut date = ymdhms(2016, 10, 1, 10, 10, 10); + date -= Duration::minutes(10_000_000); + assert_eq!(date, ymdhms(1997, 9, 26, 23, 30, 10)); + date -= Duration::days(10); + assert_eq!(date, ymdhms(1997, 9, 16, 23, 30, 10)); + } + + #[test] + fn test_datetime_timestamp() { + let to_timestamp = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s).timestamp(); + assert_eq!(to_timestamp(1969, 12, 31, 23, 59, 59), -1); + assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 0), 0); + assert_eq!(to_timestamp(1970, 1, 1, 0, 0, 1), 1); + assert_eq!(to_timestamp(2001, 9, 9, 1, 46, 40), 1_000_000_000); + assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff); + } + + #[test] + fn test_datetime_from_str() { + // valid cases + let valid = [ + "2015-2-18T23:16:9.15", + "-77-02-18T23:16:09", + " +82701 - 05 - 6 T 15 : 9 : 60.898989898989 ", + ]; + for &s in &valid { + let d = match s.parse::() { + Ok(d) => d, + Err(e) => panic!("parsing `{}` has failed: {}", s, e) + }; + let s_ = format!("{:?}", d); + // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same + let d_ = match s_.parse::() { + Ok(d) => d, + Err(e) => panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", + s, d, e) + }; + assert!(d == d_, "`{}` is parsed into `{:?}`, but reparsed result \ + `{:?}` does not match", s, d, d_); + } + + // some invalid cases + // since `ParseErrorKind` is private, all we can do is to check if there was an error + assert!("".parse::().is_err()); + assert!("x".parse::().is_err()); + assert!("15".parse::().is_err()); + assert!("15:8:9".parse::().is_err()); + assert!("15-8-9".parse::().is_err()); + assert!("2015-15-15T15:15:15".parse::().is_err()); + assert!("2012-12-12T12:12:12x".parse::().is_err()); + assert!("2012-123-12T12:12:12".parse::().is_err()); + assert!("+ 82701-123-12T12:12:12".parse::().is_err()); + assert!("+802701-123-12T12:12:12".parse::().is_err()); // out-of-bound + } + + #[test] + fn test_datetime_parse_from_str() { + let ymdhms = |y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s); + let ymdhmsn = + |y,m,d,h,n,s,nano| NaiveDate::from_ymd(y, m, d).and_hms_nano(h, n, s, nano); + assert_eq!(NaiveDateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + Ok(ymdhms(2014, 5, 7, 12, 34, 56))); // ignore offset + assert_eq!(NaiveDateTime::parse_from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"), + Ok(ymdhms(2015, 2, 2, 0, 0, 0))); + assert_eq!(NaiveDateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT", + "%a, %d %b %Y %H:%M:%S GMT"), + Ok(ymdhms(2013, 8, 9, 23, 54, 35))); + assert!(NaiveDateTime::parse_from_str("Sat, 09 Aug 2013 23:54:35 GMT", + "%a, %d %b %Y %H:%M:%S GMT").is_err()); + assert!(NaiveDateTime::parse_from_str("2014-5-7 12:3456", "%Y-%m-%d %H:%M:%S").is_err()); + assert!(NaiveDateTime::parse_from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient + assert_eq!(NaiveDateTime::parse_from_str("1441497364", "%s"), + Ok(ymdhms(2015, 9, 5, 23, 56, 4))); + assert_eq!(NaiveDateTime::parse_from_str("1283929614.1234", "%s.%f"), + Ok(ymdhmsn(2010, 9, 8, 7, 6, 54, 1234))); + assert_eq!(NaiveDateTime::parse_from_str("1441497364.649", "%s%.3f"), + Ok(ymdhmsn(2015, 9, 5, 23, 56, 4, 649000000))); + assert_eq!(NaiveDateTime::parse_from_str("1497854303.087654", "%s%.6f"), + Ok(ymdhmsn(2017, 6, 19, 6, 38, 23, 87654000))); + assert_eq!(NaiveDateTime::parse_from_str("1437742189.918273645", "%s%.9f"), + Ok(ymdhmsn(2015, 7, 24, 12, 49, 49, 918273645))); + } + + #[test] + fn test_datetime_format() { + let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321); + assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010"); + assert_eq!(dt.format("%s").to_string(), "1283929614"); + assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + + // a horror of leap second: coming near to you. + let dt = NaiveDate::from_ymd(2012, 6, 30).and_hms_milli(23, 59, 59, 1_000); + assert_eq!(dt.format("%c").to_string(), "Sat Jun 30 23:59:60 2012"); + assert_eq!(dt.format("%s").to_string(), "1341100799"); // not 1341100800, it's intentional. + } + + #[test] + fn test_datetime_add_sub_invariant() { // issue #37 + let base = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0); + let t = -946684799990000; + let time = base + Duration::microseconds(t); + assert_eq!(t, time.signed_duration_since(base).num_microseconds().unwrap()); + } +} diff --git a/chrono/src/naive/internals.rs b/chrono/src/naive/internals.rs new file mode 100644 index 000000000..dd9d535b1 --- /dev/null +++ b/chrono/src/naive/internals.rs @@ -0,0 +1,779 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The internal implementation of the calendar and ordinal date. +//! +//! The current implementation is optimized for determining year, month, day and day of week. +//! 4-bit `YearFlags` map to one of 14 possible classes of year in the Gregorian calendar, +//! which are included in every packed `NaiveDate` instance. +//! The conversion between the packed calendar date (`Mdf`) and the ordinal date (`Of`) is +//! based on the moderately-sized lookup table (~1.5KB) +//! and the packed representation is chosen for the efficient lookup. +//! Every internal data structure does not validate its input, +//! but the conversion keeps the valid value valid and the invalid value invalid +//! so that the user-facing `NaiveDate` can validate the input as late as possible. + +#![allow(dead_code)] // some internal methods have been left for consistency + +use std::{i32, fmt}; +use num_traits::FromPrimitive; +use Weekday; +use div::{div_rem, mod_floor}; + +/// The internal date representation. This also includes the packed `Mdf` value. +pub type DateImpl = i32; + +pub const MAX_YEAR: DateImpl = i32::MAX >> 13; +pub const MIN_YEAR: DateImpl = i32::MIN >> 13; + +/// The year flags (aka the dominical letter). +/// +/// There are 14 possible classes of year in the Gregorian calendar: +/// common and leap years starting with Monday through Sunday. +/// The `YearFlags` stores this information into 4 bits `abbb`, +/// where `a` is `1` for the common year (simplifies the `Of` validation) +/// and `bbb` is a non-zero `Weekday` (mapping `Mon` to 7) of the last day in the past year +/// (simplifies the day of week calculation from the 1-based ordinal). +#[derive(PartialEq, Eq, Copy, Clone)] +pub struct YearFlags(pub u8); + +pub const A: YearFlags = YearFlags(0o15); pub const AG: YearFlags = YearFlags(0o05); +pub const B: YearFlags = YearFlags(0o14); pub const BA: YearFlags = YearFlags(0o04); +pub const C: YearFlags = YearFlags(0o13); pub const CB: YearFlags = YearFlags(0o03); +pub const D: YearFlags = YearFlags(0o12); pub const DC: YearFlags = YearFlags(0o02); +pub const E: YearFlags = YearFlags(0o11); pub const ED: YearFlags = YearFlags(0o01); +pub const F: YearFlags = YearFlags(0o17); pub const FE: YearFlags = YearFlags(0o07); +pub const G: YearFlags = YearFlags(0o16); pub const GF: YearFlags = YearFlags(0o06); + +static YEAR_TO_FLAGS: [YearFlags; 400] = [ + BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, + ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, + AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, + DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, + GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, // 100 + C, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, + GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, + CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, + FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, + BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, // 200 + E, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, + BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, + ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, + AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, + DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, // 300 + G, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, + DC, B, A, G, FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, + GF, E, D, C, BA, G, F, E, DC, B, A, G, FE, D, C, B, AG, F, E, D, + CB, A, G, F, ED, C, B, A, GF, E, D, C, BA, G, F, E, DC, B, A, G, + FE, D, C, B, AG, F, E, D, CB, A, G, F, ED, C, B, A, GF, E, D, C, // 400 +]; + +static YEAR_DELTAS: [u8; 401] = [ + 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, + 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, // 100 + 25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, + 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, + 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, + 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, + 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, // 200 + 49, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, + 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, + 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, + 63, 64, 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, + 68, 69, 69, 69, 69, 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, // 300 + 73, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, + 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, + 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, + 87, 88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, + 92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97 // 400+1 +]; + +pub fn cycle_to_yo(cycle: u32) -> (u32, u32) { + let (mut year_mod_400, mut ordinal0) = div_rem(cycle, 365); + let delta = u32::from(YEAR_DELTAS[year_mod_400 as usize]); + if ordinal0 < delta { + year_mod_400 -= 1; + ordinal0 += 365 - u32::from(YEAR_DELTAS[year_mod_400 as usize]); + } else { + ordinal0 -= delta; + } + (year_mod_400, ordinal0 + 1) +} + +pub fn yo_to_cycle(year_mod_400: u32, ordinal: u32) -> u32 { + year_mod_400 * 365 + u32::from(YEAR_DELTAS[year_mod_400 as usize]) + ordinal - 1 +} + +impl YearFlags { + #[inline] + pub fn from_year(year: i32) -> YearFlags { + let year = mod_floor(year, 400); + YearFlags::from_year_mod_400(year) + } + + #[inline] + pub fn from_year_mod_400(year: i32) -> YearFlags { + YEAR_TO_FLAGS[year as usize] + } + + #[inline] + pub fn ndays(&self) -> u32 { + let YearFlags(flags) = *self; + 366 - u32::from(flags >> 3) + } + + #[inline] + pub fn isoweek_delta(&self) -> u32 { + let YearFlags(flags) = *self; + let mut delta = u32::from(flags) & 0b0111; + if delta < 3 { delta += 7; } + delta + } + + #[inline] + pub fn nisoweeks(&self) -> u32 { + let YearFlags(flags) = *self; + 52 + ((0b0000_0100_0000_0110 >> flags as usize) & 1) + } +} + +impl fmt::Debug for YearFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let YearFlags(flags) = *self; + match flags { + 0o15 => "A".fmt(f), 0o05 => "AG".fmt(f), + 0o14 => "B".fmt(f), 0o04 => "BA".fmt(f), + 0o13 => "C".fmt(f), 0o03 => "CB".fmt(f), + 0o12 => "D".fmt(f), 0o02 => "DC".fmt(f), + 0o11 => "E".fmt(f), 0o01 => "ED".fmt(f), + 0o10 => "F?".fmt(f), 0o00 => "FE?".fmt(f), // non-canonical + 0o17 => "F".fmt(f), 0o07 => "FE".fmt(f), + 0o16 => "G".fmt(f), 0o06 => "GF".fmt(f), + _ => write!(f, "YearFlags({})", flags), + } + } +} + +pub const MIN_OL: u32 = 1 << 1; +pub const MAX_OL: u32 = 366 << 1; // larger than the non-leap last day `(365 << 1) | 1` +pub const MIN_MDL: u32 = (1 << 6) | (1 << 1); +pub const MAX_MDL: u32 = (12 << 6) | (31 << 1) | 1; + +const XX: i8 = -128; +static MDL_TO_OL: [i8; (MAX_MDL as usize + 1)] = [ + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, + XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, // 0 + XX, XX, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1 + XX, XX, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, XX, XX, XX, XX, XX, // 2 + XX, XX, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, // 3 + XX, XX, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, XX, XX, // 4 + XX, XX, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, // 5 + XX, XX, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, XX, XX, // 6 + XX, XX, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, // 7 + XX, XX, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, // 8 + XX, XX, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, XX, XX, // 9 + XX, XX, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, // 10 + XX, XX, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, XX, XX, // 11 + XX, XX, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, // 12 +]; + +static OL_TO_MDL: [u8; (MAX_OL as usize + 1)] = [ + 0, 0, // 0 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, // 1 + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, // 2 + 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, + 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, 74, 72, // 3 + 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, + 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, 76, 74, // 4 + 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, + 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, 80, 78, // 5 + 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, + 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, 82, 80, // 6 + 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, + 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, 86, 84, // 7 + 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, + 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, 88, 86, // 8 + 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, + 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, 90, 88, // 9 + 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, + 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, 94, 92, // 10 + 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, + 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, 96, 94, // 11 + 100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, + 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98,100, 98, // 12 +]; + +/// Ordinal (day of year) and year flags: `(ordinal << 4) | flags`. +/// +/// The whole bits except for the least 3 bits are referred as `Ol` (ordinal and leap flag), +/// which is an index to the `OL_TO_MDL` lookup table. +#[derive(PartialEq, PartialOrd, Copy, Clone)] +pub struct Of(pub u32); + +impl Of { + #[inline] + fn clamp_ordinal(ordinal: u32) -> u32 { + if ordinal > 366 {0} else {ordinal} + } + + #[inline] + pub fn new(ordinal: u32, YearFlags(flags): YearFlags) -> Of { + let ordinal = Of::clamp_ordinal(ordinal); + Of((ordinal << 4) | u32::from(flags)) + } + + #[inline] + pub fn from_mdf(Mdf(mdf): Mdf) -> Of { + let mdl = mdf >> 3; + match MDL_TO_OL.get(mdl as usize) { + Some(&v) => Of(mdf.wrapping_sub((i32::from(v) as u32 & 0x3ff) << 3)), + None => Of(0) + } + } + + #[inline] + pub fn valid(&self) -> bool { + let Of(of) = *self; + let ol = of >> 3; + MIN_OL <= ol && ol <= MAX_OL + } + + #[inline] + pub fn ordinal(&self) -> u32 { + let Of(of) = *self; + of >> 4 + } + + #[inline] + pub fn with_ordinal(&self, ordinal: u32) -> Of { + let ordinal = Of::clamp_ordinal(ordinal); + let Of(of) = *self; + Of((of & 0b1111) | (ordinal << 4)) + } + + #[inline] + pub fn flags(&self) -> YearFlags { + let Of(of) = *self; + YearFlags((of & 0b1111) as u8) + } + + #[inline] + pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Of { + let Of(of) = *self; + Of((of & !0b1111) | u32::from(flags)) + } + + #[inline] + pub fn weekday(&self) -> Weekday { + let Of(of) = *self; + Weekday::from_u32(((of >> 4) + (of & 0b111)) % 7).unwrap() + } + + #[inline] + pub fn isoweekdate_raw(&self) -> (u32, Weekday) { + // week ordinal = ordinal + delta + let Of(of) = *self; + let weekord = (of >> 4).wrapping_add(self.flags().isoweek_delta()); + (weekord / 7, Weekday::from_u32(weekord % 7).unwrap()) + } + + #[inline] + pub fn to_mdf(&self) -> Mdf { + Mdf::from_of(*self) + } + + #[inline] + pub fn succ(&self) -> Of { + let Of(of) = *self; + Of(of + (1 << 4)) + } + + #[inline] + pub fn pred(&self) -> Of { + let Of(of) = *self; + Of(of - (1 << 4)) + } +} + +impl fmt::Debug for Of { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let Of(of) = *self; + write!(f, "Of(({} << 4) | {:#04o} /*{:?}*/)", + of >> 4, of & 0b1111, YearFlags((of & 0b1111) as u8)) + } +} + +/// Month, day of month and year flags: `(month << 9) | (day << 4) | flags` +/// +/// The whole bits except for the least 3 bits are referred as `Mdl` +/// (month, day of month and leap flag), +/// which is an index to the `MDL_TO_OL` lookup table. +#[derive(PartialEq, PartialOrd, Copy, Clone)] +pub struct Mdf(pub u32); + +impl Mdf { + #[inline] + fn clamp_month(month: u32) -> u32 { + if month > 12 {0} else {month} + } + + #[inline] + fn clamp_day(day: u32) -> u32 { + if day > 31 {0} else {day} + } + + #[inline] + pub fn new(month: u32, day: u32, YearFlags(flags): YearFlags) -> Mdf { + let month = Mdf::clamp_month(month); + let day = Mdf::clamp_day(day); + Mdf((month << 9) | (day << 4) | u32::from(flags)) + } + + #[inline] + pub fn from_of(Of(of): Of) -> Mdf { + let ol = of >> 3; + match OL_TO_MDL.get(ol as usize) { + Some(&v) => Mdf(of + (u32::from(v) << 3)), + None => Mdf(0) + } + } + + #[inline] + pub fn valid(&self) -> bool { + let Mdf(mdf) = *self; + let mdl = mdf >> 3; + match MDL_TO_OL.get(mdl as usize) { + Some(&v) => v >= 0, + None => false + } + } + + #[inline] + pub fn month(&self) -> u32 { + let Mdf(mdf) = *self; + mdf >> 9 + } + + #[inline] + pub fn with_month(&self, month: u32) -> Mdf { + let month = Mdf::clamp_month(month); + let Mdf(mdf) = *self; + Mdf((mdf & 0b1_1111_1111) | (month << 9)) + } + + #[inline] + pub fn day(&self) -> u32 { + let Mdf(mdf) = *self; + (mdf >> 4) & 0b1_1111 + } + + #[inline] + pub fn with_day(&self, day: u32) -> Mdf { + let day = Mdf::clamp_day(day); + let Mdf(mdf) = *self; + Mdf((mdf & !0b1_1111_0000) | (day << 4)) + } + + #[inline] + pub fn flags(&self) -> YearFlags { + let Mdf(mdf) = *self; + YearFlags((mdf & 0b1111) as u8) + } + + #[inline] + pub fn with_flags(&self, YearFlags(flags): YearFlags) -> Mdf { + let Mdf(mdf) = *self; + Mdf((mdf & !0b1111) | u32::from(flags)) + } + + #[inline] + pub fn to_of(&self) -> Of { + Of::from_mdf(*self) + } +} + +impl fmt::Debug for Mdf { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let Mdf(mdf) = *self; + write!(f, "Mdf(({} << 9) | ({} << 4) | {:#04o} /*{:?}*/)", + mdf >> 9, (mdf >> 4) & 0b1_1111, mdf & 0b1111, YearFlags((mdf & 0b1111) as u8)) + } +} + +#[cfg(test)] +mod tests { + #[cfg(test)] extern crate num_iter; + #[cfg(bench)] extern crate test; + + use Weekday; + use super::{Of, Mdf}; + use super::{YearFlags, A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF}; + use self::num_iter::range_inclusive; + use std::u32; + + const NONLEAP_FLAGS: [YearFlags; 7] = [A, B, C, D, E, F, G]; + const LEAP_FLAGS: [YearFlags; 7] = [AG, BA, CB, DC, ED, FE, GF]; + const FLAGS: [YearFlags; 14] = [A, B, C, D, E, F, G, AG, BA, CB, DC, ED, FE, GF]; + + #[test] + fn test_year_flags_ndays_from_year() { + assert_eq!(YearFlags::from_year(2014).ndays(), 365); + assert_eq!(YearFlags::from_year(2012).ndays(), 366); + assert_eq!(YearFlags::from_year(2000).ndays(), 366); + assert_eq!(YearFlags::from_year(1900).ndays(), 365); + assert_eq!(YearFlags::from_year(1600).ndays(), 366); + assert_eq!(YearFlags::from_year( 1).ndays(), 365); + assert_eq!(YearFlags::from_year( 0).ndays(), 366); // 1 BCE (proleptic Gregorian) + assert_eq!(YearFlags::from_year( -1).ndays(), 365); // 2 BCE + assert_eq!(YearFlags::from_year( -4).ndays(), 366); // 5 BCE + assert_eq!(YearFlags::from_year( -99).ndays(), 365); // 100 BCE + assert_eq!(YearFlags::from_year(-100).ndays(), 365); // 101 BCE + assert_eq!(YearFlags::from_year(-399).ndays(), 365); // 400 BCE + assert_eq!(YearFlags::from_year(-400).ndays(), 366); // 401 BCE + } + + #[test] + fn test_year_flags_nisoweeks() { + assert_eq!(A.nisoweeks(), 52); + assert_eq!(B.nisoweeks(), 52); + assert_eq!(C.nisoweeks(), 52); + assert_eq!(D.nisoweeks(), 53); + assert_eq!(E.nisoweeks(), 52); + assert_eq!(F.nisoweeks(), 52); + assert_eq!(G.nisoweeks(), 52); + assert_eq!(AG.nisoweeks(), 52); + assert_eq!(BA.nisoweeks(), 52); + assert_eq!(CB.nisoweeks(), 52); + assert_eq!(DC.nisoweeks(), 53); + assert_eq!(ED.nisoweeks(), 53); + assert_eq!(FE.nisoweeks(), 52); + assert_eq!(GF.nisoweeks(), 52); + } + + #[cfg(bench)] + #[bench] + fn bench_year_flags_from_year(bh: &mut test::Bencher) { + bh.iter(|| { + for year in -999i32..1000 { + YearFlags::from_year(year); + } + }); + } + + #[test] + fn test_of() { + fn check(expected: bool, flags: YearFlags, ordinal1: u32, ordinal2: u32) { + for ordinal in range_inclusive(ordinal1, ordinal2) { + let of = Of::new(ordinal, flags); + assert!(of.valid() == expected, + "ordinal {} = {:?} should be {} for dominical year {:?}", + ordinal, of, if expected {"valid"} else {"invalid"}, flags); + } + } + + for &flags in NONLEAP_FLAGS.iter() { + check(false, flags, 0, 0); + check(true, flags, 1, 365); + check(false, flags, 366, 1024); + check(false, flags, u32::MAX, u32::MAX); + } + + for &flags in LEAP_FLAGS.iter() { + check(false, flags, 0, 0); + check(true, flags, 1, 366); + check(false, flags, 367, 1024); + check(false, flags, u32::MAX, u32::MAX); + } + } + + #[test] + fn test_mdf_valid() { + fn check(expected: bool, flags: YearFlags, month1: u32, day1: u32, + month2: u32, day2: u32) { + for month in range_inclusive(month1, month2) { + for day in range_inclusive(day1, day2) { + let mdf = Mdf::new(month, day, flags); + assert!(mdf.valid() == expected, + "month {} day {} = {:?} should be {} for dominical year {:?}", + month, day, mdf, if expected {"valid"} else {"invalid"}, flags); + } + } + } + + for &flags in NONLEAP_FLAGS.iter() { + check(false, flags, 0, 0, 0, 1024); + check(false, flags, 0, 0, 16, 0); + check(true, flags, 1, 1, 1, 31); check(false, flags, 1, 32, 1, 1024); + check(true, flags, 2, 1, 2, 28); check(false, flags, 2, 29, 2, 1024); + check(true, flags, 3, 1, 3, 31); check(false, flags, 3, 32, 3, 1024); + check(true, flags, 4, 1, 4, 30); check(false, flags, 4, 31, 4, 1024); + check(true, flags, 5, 1, 5, 31); check(false, flags, 5, 32, 5, 1024); + check(true, flags, 6, 1, 6, 30); check(false, flags, 6, 31, 6, 1024); + check(true, flags, 7, 1, 7, 31); check(false, flags, 7, 32, 7, 1024); + check(true, flags, 8, 1, 8, 31); check(false, flags, 8, 32, 8, 1024); + check(true, flags, 9, 1, 9, 30); check(false, flags, 9, 31, 9, 1024); + check(true, flags, 10, 1, 10, 31); check(false, flags, 10, 32, 10, 1024); + check(true, flags, 11, 1, 11, 30); check(false, flags, 11, 31, 11, 1024); + check(true, flags, 12, 1, 12, 31); check(false, flags, 12, 32, 12, 1024); + check(false, flags, 13, 0, 16, 1024); + check(false, flags, u32::MAX, 0, u32::MAX, 1024); + check(false, flags, 0, u32::MAX, 16, u32::MAX); + check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX); + } + + for &flags in LEAP_FLAGS.iter() { + check(false, flags, 0, 0, 0, 1024); + check(false, flags, 0, 0, 16, 0); + check(true, flags, 1, 1, 1, 31); check(false, flags, 1, 32, 1, 1024); + check(true, flags, 2, 1, 2, 29); check(false, flags, 2, 30, 2, 1024); + check(true, flags, 3, 1, 3, 31); check(false, flags, 3, 32, 3, 1024); + check(true, flags, 4, 1, 4, 30); check(false, flags, 4, 31, 4, 1024); + check(true, flags, 5, 1, 5, 31); check(false, flags, 5, 32, 5, 1024); + check(true, flags, 6, 1, 6, 30); check(false, flags, 6, 31, 6, 1024); + check(true, flags, 7, 1, 7, 31); check(false, flags, 7, 32, 7, 1024); + check(true, flags, 8, 1, 8, 31); check(false, flags, 8, 32, 8, 1024); + check(true, flags, 9, 1, 9, 30); check(false, flags, 9, 31, 9, 1024); + check(true, flags, 10, 1, 10, 31); check(false, flags, 10, 32, 10, 1024); + check(true, flags, 11, 1, 11, 30); check(false, flags, 11, 31, 11, 1024); + check(true, flags, 12, 1, 12, 31); check(false, flags, 12, 32, 12, 1024); + check(false, flags, 13, 0, 16, 1024); + check(false, flags, u32::MAX, 0, u32::MAX, 1024); + check(false, flags, 0, u32::MAX, 16, u32::MAX); + check(false, flags, u32::MAX, u32::MAX, u32::MAX, u32::MAX); + } + } + + #[test] + fn test_of_fields() { + for &flags in FLAGS.iter() { + for ordinal in range_inclusive(1u32, 366) { + let of = Of::new(ordinal, flags); + if of.valid() { + assert_eq!(of.ordinal(), ordinal); + } + } + } + } + + #[test] + fn test_of_with_fields() { + fn check(flags: YearFlags, ordinal: u32) { + let of = Of::new(ordinal, flags); + + for ordinal in range_inclusive(0u32, 1024) { + let of = of.with_ordinal(ordinal); + assert_eq!(of.valid(), Of::new(ordinal, flags).valid()); + if of.valid() { + assert_eq!(of.ordinal(), ordinal); + } + } + } + + for &flags in NONLEAP_FLAGS.iter() { + check(flags, 1); + check(flags, 365); + } + for &flags in LEAP_FLAGS.iter() { + check(flags, 1); + check(flags, 366); + } + } + + #[test] + fn test_of_weekday() { + assert_eq!(Of::new(1, A).weekday(), Weekday::Sun); + assert_eq!(Of::new(1, B).weekday(), Weekday::Sat); + assert_eq!(Of::new(1, C).weekday(), Weekday::Fri); + assert_eq!(Of::new(1, D).weekday(), Weekday::Thu); + assert_eq!(Of::new(1, E).weekday(), Weekday::Wed); + assert_eq!(Of::new(1, F).weekday(), Weekday::Tue); + assert_eq!(Of::new(1, G).weekday(), Weekday::Mon); + assert_eq!(Of::new(1, AG).weekday(), Weekday::Sun); + assert_eq!(Of::new(1, BA).weekday(), Weekday::Sat); + assert_eq!(Of::new(1, CB).weekday(), Weekday::Fri); + assert_eq!(Of::new(1, DC).weekday(), Weekday::Thu); + assert_eq!(Of::new(1, ED).weekday(), Weekday::Wed); + assert_eq!(Of::new(1, FE).weekday(), Weekday::Tue); + assert_eq!(Of::new(1, GF).weekday(), Weekday::Mon); + + for &flags in FLAGS.iter() { + let mut prev = Of::new(1, flags).weekday(); + for ordinal in range_inclusive(2u32, flags.ndays()) { + let of = Of::new(ordinal, flags); + let expected = prev.succ(); + assert_eq!(of.weekday(), expected); + prev = expected; + } + } + } + + #[test] + fn test_mdf_fields() { + for &flags in FLAGS.iter() { + for month in range_inclusive(1u32, 12) { + for day in range_inclusive(1u32, 31) { + let mdf = Mdf::new(month, day, flags); + if mdf.valid() { + assert_eq!(mdf.month(), month); + assert_eq!(mdf.day(), day); + } + } + } + } + } + + #[test] + fn test_mdf_with_fields() { + fn check(flags: YearFlags, month: u32, day: u32) { + let mdf = Mdf::new(month, day, flags); + + for month in range_inclusive(0u32, 16) { + let mdf = mdf.with_month(month); + assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid()); + if mdf.valid() { + assert_eq!(mdf.month(), month); + assert_eq!(mdf.day(), day); + } + } + + for day in range_inclusive(0u32, 1024) { + let mdf = mdf.with_day(day); + assert_eq!(mdf.valid(), Mdf::new(month, day, flags).valid()); + if mdf.valid() { + assert_eq!(mdf.month(), month); + assert_eq!(mdf.day(), day); + } + } + } + + for &flags in NONLEAP_FLAGS.iter() { + check(flags, 1, 1); + check(flags, 1, 31); + check(flags, 2, 1); + check(flags, 2, 28); + check(flags, 2, 29); + check(flags, 12, 31); + } + for &flags in LEAP_FLAGS.iter() { + check(flags, 1, 1); + check(flags, 1, 31); + check(flags, 2, 1); + check(flags, 2, 29); + check(flags, 2, 30); + check(flags, 12, 31); + } + } + + #[test] + fn test_of_isoweekdate_raw() { + for &flags in FLAGS.iter() { + // January 4 should be in the first week + let (week, _) = Of::new(4 /* January 4 */, flags).isoweekdate_raw(); + assert_eq!(week, 1); + } + } + + #[test] + fn test_of_to_mdf() { + for i in range_inclusive(0u32, 8192) { + let of = Of(i); + assert_eq!(of.valid(), of.to_mdf().valid()); + } + } + + #[test] + fn test_mdf_to_of() { + for i in range_inclusive(0u32, 8192) { + let mdf = Mdf(i); + assert_eq!(mdf.valid(), mdf.to_of().valid()); + } + } + + #[test] + fn test_of_to_mdf_to_of() { + for i in range_inclusive(0u32, 8192) { + let of = Of(i); + if of.valid() { + assert_eq!(of, of.to_mdf().to_of()); + } + } + } + + #[test] + fn test_mdf_to_of_to_mdf() { + for i in range_inclusive(0u32, 8192) { + let mdf = Mdf(i); + if mdf.valid() { + assert_eq!(mdf, mdf.to_of().to_mdf()); + } + } + } +} + diff --git a/chrono/src/naive/isoweek.rs b/chrono/src/naive/isoweek.rs new file mode 100644 index 000000000..667cf2f8e --- /dev/null +++ b/chrono/src/naive/isoweek.rs @@ -0,0 +1,161 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 week. + +use std::fmt; + +use super::internals::{DateImpl, Of, YearFlags}; + +/// ISO 8601 week. +/// +/// This type, combined with [`Weekday`](../enum.Weekday.html), +/// constitues the ISO 8601 [week date](./struct.NaiveDate.html#week-date). +/// One can retrieve this type from the existing [`Datelike`](../trait.Datelike.html) types +/// via the [`Datelike::iso_week`](../trait.Datelike.html#tymethod.iso_week) method. +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +pub struct IsoWeek { + // note that this allows for larger year range than `NaiveDate`. + // this is crucial because we have an edge case for the first and last week supported, + // which year number might not match the calendar year number. + ywf: DateImpl, // (year << 10) | (week << 4) | flag +} + +/// Returns the corresponding `IsoWeek` from the year and the `Of` internal value. +// +// internal use only. we don't expose the public constructor for `IsoWeek` for now, +// because the year range for the week date and the calendar date do not match and +// it is confusing to have a date that is out of range in one and not in another. +// currently we sidestep this issue by making `IsoWeek` fully dependent of `Datelike`. +pub fn iso_week_from_yof(year: i32, of: Of) -> IsoWeek { + let (rawweek, _) = of.isoweekdate_raw(); + let (year, week) = if rawweek < 1 { // previous year + let prevlastweek = YearFlags::from_year(year - 1).nisoweeks(); + (year - 1, prevlastweek) + } else { + let lastweek = of.flags().nisoweeks(); + if rawweek > lastweek { // next year + (year + 1, 1) + } else { + (year, rawweek) + } + }; + IsoWeek { ywf: (year << 10) | (week << 4) as DateImpl | DateImpl::from(of.flags().0) } +} + +impl IsoWeek { + /// Returns the year number for this ISO week. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// assert_eq!(d.iso_week().year(), 2015); + /// ~~~~ + /// + /// This year number might not match the calendar year number. + /// Continuing the example... + /// + /// ~~~~ + /// # use chrono::{NaiveDate, Datelike, Weekday}; + /// # let d = NaiveDate::from_isoywd(2015, 1, Weekday::Mon); + /// assert_eq!(d.year(), 2014); + /// assert_eq!(d, NaiveDate::from_ymd(2014, 12, 29)); + /// ~~~~ + #[inline] + pub fn year(&self) -> i32 { + self.ywf >> 10 + } + + /// Returns the ISO week number starting from 1. + /// + /// The return value ranges from 1 to 53. (The last week of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// assert_eq!(d.iso_week().week(), 15); + /// ~~~~ + #[inline] + pub fn week(&self) -> u32 { + ((self.ywf >> 4) & 0x3f) as u32 + } + + /// Returns the ISO week number starting from 0. + /// + /// The return value ranges from 0 to 52. (The last week of year differs by years.) + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveDate, Datelike, Weekday}; + /// + /// let d = NaiveDate::from_isoywd(2015, 15, Weekday::Mon); + /// assert_eq!(d.iso_week().week0(), 14); + /// ~~~~ + #[inline] + pub fn week0(&self) -> u32 { + ((self.ywf >> 4) & 0x3f) as u32 - 1 + } +} + +/// The `Debug` output of the ISO week `w` is same to +/// [`d.format("%G-W%V")`](../format/strftime/index.html) +/// where `d` is any `NaiveDate` value in that week. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::{NaiveDate, Datelike}; +/// +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(2015, 9, 5).iso_week()), "2015-W36"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 3).iso_week()), "0000-W01"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(9999, 12, 31).iso_week()), "9999-W52"); +/// ~~~~ +/// +/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE. +/// +/// ~~~~ +/// # use chrono::{NaiveDate, Datelike}; +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd( 0, 1, 2).iso_week()), "-0001-W52"); +/// assert_eq!(format!("{:?}", NaiveDate::from_ymd(10000, 12, 31).iso_week()), "+10000-W52"); +/// ~~~~ +impl fmt::Debug for IsoWeek { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let year = self.year(); + let week = self.week(); + if 0 <= year && year <= 9999 { + write!(f, "{:04}-W{:02}", year, week) + } else { + // ISO 8601 requires the explicit sign for out-of-range years + write!(f, "{:+05}-W{:02}", year, week) + } + } +} + +#[cfg(test)] +mod tests { + use naive::{internals, MIN_DATE, MAX_DATE}; + use Datelike; + + #[test] + fn test_iso_week_extremes() { + let minweek = MIN_DATE.iso_week(); + let maxweek = MAX_DATE.iso_week(); + + assert_eq!(minweek.year(), internals::MIN_YEAR); + assert_eq!(minweek.week(), 1); + assert_eq!(minweek.week0(), 0); + assert_eq!(format!("{:?}", minweek), MIN_DATE.format("%G-W%V").to_string()); + + assert_eq!(maxweek.year(), internals::MAX_YEAR + 1); + assert_eq!(maxweek.week(), 1); + assert_eq!(maxweek.week0(), 0); + assert_eq!(format!("{:?}", maxweek), MAX_DATE.format("%G-W%V").to_string()); + } +} diff --git a/chrono/src/naive/time.rs b/chrono/src/naive/time.rs new file mode 100644 index 000000000..440c8a7ac --- /dev/null +++ b/chrono/src/naive/time.rs @@ -0,0 +1,1733 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! ISO 8601 time without timezone. + +use std::{str, fmt, hash}; +use std::ops::{Add, Sub, AddAssign, SubAssign}; +use oldtime::Duration as OldDuration; + +use Timelike; +use div::div_mod_floor; +use format::{Item, Numeric, Pad, Fixed}; +use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}; + +/// ISO 8601 time without timezone. +/// Allows for the nanosecond precision and optional leap second representation. +/// +/// # Leap Second Handling +/// +/// Since 1960s, the manmade atomic clock has been so accurate that +/// it is much more accurate than Earth's own motion. +/// It became desirable to define the civil time in terms of the atomic clock, +/// but that risks the desynchronization of the civil time from Earth. +/// To account for this, the designers of the Coordinated Universal Time (UTC) +/// made that the UTC should be kept within 0.9 seconds of the observed Earth-bound time. +/// When the mean solar day is longer than the ideal (86,400 seconds), +/// the error slowly accumulates and it is necessary to add a **leap second** +/// to slow the UTC down a bit. +/// (We may also remove a second to speed the UTC up a bit, but it never happened.) +/// The leap second, if any, follows 23:59:59 of June 30 or December 31 in the UTC. +/// +/// Fast forward to the 21st century, +/// we have seen 26 leap seconds from January 1972 to December 2015. +/// Yes, 26 seconds. Probably you can read this paragraph within 26 seconds. +/// But those 26 seconds, and possibly more in the future, are never predictable, +/// and whether to add a leap second or not is known only before 6 months. +/// Internet-based clocks (via NTP) do account for known leap seconds, +/// but the system API normally doesn't (and often can't, with no network connection) +/// and there is no reliable way to retrieve leap second information. +/// +/// Chrono does not try to accurately implement leap seconds; it is impossible. +/// Rather, **it allows for leap seconds but behaves as if there are *no other* leap seconds.** +/// Various operations will ignore any possible leap second(s) +/// except when any of the operands were actually leap seconds. +/// +/// If you cannot tolerate this behavior, +/// you must use a separate `TimeZone` for the International Atomic Time (TAI). +/// TAI is like UTC but has no leap seconds, and thus slightly differs from UTC. +/// Chrono does not yet provide such implementation, but it is planned. +/// +/// ## Representing Leap Seconds +/// +/// The leap second is indicated via fractional seconds more than 1 second. +/// This makes possible to treat a leap second as the prior non-leap second +/// if you don't care about sub-second accuracy. +/// You should use the proper formatting to get the raw leap second. +/// +/// All methods accepting fractional seconds will accept such values. +/// +/// ~~~~ +/// use chrono::{NaiveDate, NaiveTime, Utc, TimeZone}; +/// +/// let t = NaiveTime::from_hms_milli(8, 59, 59, 1_000); +/// +/// let dt1 = NaiveDate::from_ymd(2015, 7, 1).and_hms_micro(8, 59, 59, 1_000_000); +/// +/// let dt2 = Utc.ymd(2015, 6, 30).and_hms_nano(23, 59, 59, 1_000_000_000); +/// # let _ = (t, dt1, dt2); +/// ~~~~ +/// +/// Note that the leap second can happen anytime given an appropriate time zone; +/// 2015-07-01 01:23:60 would be a proper leap second if UTC+01:24 had existed. +/// Practically speaking, though, by the time of the first leap second on 1972-06-30, +/// every time zone offset around the world has standardized to the 5-minute alignment. +/// +/// ## Date And Time Arithmetics +/// +/// As a concrete example, let's assume that `03:00:60` and `04:00:60` are leap seconds. +/// In reality, of course, leap seconds are separated by at least 6 months. +/// We will also use some intuitive concise notations for the explanation. +/// +/// `Time + Duration` +/// (short for [`NaiveTime::overflowing_add_signed`](#method.overflowing_add_signed)): +/// +/// - `03:00:00 + 1s = 03:00:01`. +/// - `03:00:59 + 60s = 03:02:00`. +/// - `03:00:59 + 1s = 03:01:00`. +/// - `03:00:60 + 1s = 03:01:00`. +/// Note that the sum is identical to the previous. +/// - `03:00:60 + 60s = 03:01:59`. +/// - `03:00:60 + 61s = 03:02:00`. +/// - `03:00:60.1 + 0.8s = 03:00:60.9`. +/// +/// `Time - Duration` +/// (short for [`NaiveTime::overflowing_sub_signed`](#method.overflowing_sub_signed)): +/// +/// - `03:00:00 - 1s = 02:59:59`. +/// - `03:01:00 - 1s = 03:00:59`. +/// - `03:01:00 - 60s = 03:00:00`. +/// - `03:00:60 - 60s = 03:00:00`. +/// Note that the result is identical to the previous. +/// - `03:00:60.7 - 0.4s = 03:00:60.3`. +/// - `03:00:60.7 - 0.9s = 03:00:59.8`. +/// +/// `Time - Time` +/// (short for [`NaiveTime::signed_duration_since`](#method.signed_duration_since)): +/// +/// - `04:00:00 - 03:00:00 = 3600s`. +/// - `03:01:00 - 03:00:00 = 60s`. +/// - `03:00:60 - 03:00:00 = 60s`. +/// Note that the difference is identical to the previous. +/// - `03:00:60.6 - 03:00:59.4 = 1.2s`. +/// - `03:01:00 - 03:00:59.8 = 0.2s`. +/// - `03:01:00 - 03:00:60.5 = 0.5s`. +/// Note that the difference is larger than the previous, +/// even though the leap second clearly follows the previous whole second. +/// - `04:00:60.9 - 03:00:60.1 = +/// (04:00:60.9 - 04:00:00) + (04:00:00 - 03:01:00) + (03:01:00 - 03:00:60.1) = +/// 60.9s + 3540s + 0.9s = 3601.8s`. +/// +/// In general, +/// +/// - `Time + Duration` unconditionally equals to `Duration + Time`. +/// +/// - `Time - Duration` unconditionally equals to `Time + (-Duration)`. +/// +/// - `Time1 - Time2` unconditionally equals to `-(Time2 - Time1)`. +/// +/// - Associativity does not generally hold, because +/// `(Time + Duration1) - Duration2` no longer equals to `Time + (Duration1 - Duration2)` +/// for two positive durations. +/// +/// - As a special case, `(Time + Duration) - Duration` also does not equal to `Time`. +/// +/// - If you can assume that all durations have the same sign, however, +/// then the associativity holds: +/// `(Time + Duration1) + Duration2` equals to `Time + (Duration1 + Duration2)` +/// for two positive durations. +/// +/// ## Reading And Writing Leap Seconds +/// +/// The "typical" leap seconds on the minute boundary are +/// correctly handled both in the formatting and parsing. +/// The leap second in the human-readable representation +/// will be represented as the second part being 60, as required by ISO 8601. +/// +/// ~~~~ +/// use chrono::{Utc, TimeZone}; +/// +/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 59, 59, 1_000); +/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:59:60Z"); +/// ~~~~ +/// +/// There are hypothetical leap seconds not on the minute boundary +/// nevertheless supported by Chrono. +/// They are allowed for the sake of completeness and consistency; +/// there were several "exotic" time zone offsets with fractional minutes prior to UTC after all. +/// For such cases the human-readable representation is ambiguous +/// and would be read back to the next non-leap second. +/// +/// ~~~~ +/// use chrono::{DateTime, Utc, TimeZone}; +/// +/// let dt = Utc.ymd(2015, 6, 30).and_hms_milli(23, 56, 4, 1_000); +/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); +/// +/// let dt = Utc.ymd(2015, 6, 30).and_hms(23, 56, 5); +/// assert_eq!(format!("{:?}", dt), "2015-06-30T23:56:05Z"); +/// assert_eq!(DateTime::parse_from_rfc3339("2015-06-30T23:56:05Z").unwrap(), dt); +/// ~~~~ +/// +/// Since Chrono alone cannot determine any existence of leap seconds, +/// **there is absolutely no guarantee that the leap second read has actually happened**. +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +pub struct NaiveTime { + secs: u32, + frac: u32, +} + +impl NaiveTime { + /// Makes a new `NaiveTime` from hour, minute and second. + /// + /// No [leap second](#leap-second-handling) is allowed here; + /// use `NaiveTime::from_hms_*` methods with a subsecond parameter instead. + /// + /// Panics on invalid hour, minute and/or second. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let t = NaiveTime::from_hms(23, 56, 4); + /// assert_eq!(t.hour(), 23); + /// assert_eq!(t.minute(), 56); + /// assert_eq!(t.second(), 4); + /// assert_eq!(t.nanosecond(), 0); + /// ~~~~ + #[inline] + pub fn from_hms(hour: u32, min: u32, sec: u32) -> NaiveTime { + NaiveTime::from_hms_opt(hour, min, sec).expect("invalid time") + } + + /// Makes a new `NaiveTime` from hour, minute and second. + /// + /// No [leap second](#leap-second-handling) is allowed here; + /// use `NaiveTime::from_hms_*_opt` methods with a subsecond parameter instead. + /// + /// Returns `None` on invalid hour, minute and/or second. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let from_hms_opt = NaiveTime::from_hms_opt; + /// + /// assert!(from_hms_opt(0, 0, 0).is_some()); + /// assert!(from_hms_opt(23, 59, 59).is_some()); + /// assert!(from_hms_opt(24, 0, 0).is_none()); + /// assert!(from_hms_opt(23, 60, 0).is_none()); + /// assert!(from_hms_opt(23, 59, 60).is_none()); + /// ~~~~ + #[inline] + pub fn from_hms_opt(hour: u32, min: u32, sec: u32) -> Option { + NaiveTime::from_hms_nano_opt(hour, min, sec, 0) + } + + /// Makes a new `NaiveTime` from hour, minute, second and millisecond. + /// + /// The millisecond part can exceed 1,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or millisecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let t = NaiveTime::from_hms_milli(23, 56, 4, 12); + /// assert_eq!(t.hour(), 23); + /// assert_eq!(t.minute(), 56); + /// assert_eq!(t.second(), 4); + /// assert_eq!(t.nanosecond(), 12_000_000); + /// ~~~~ + #[inline] + pub fn from_hms_milli(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime { + NaiveTime::from_hms_milli_opt(hour, min, sec, milli).expect("invalid time") + } + + /// Makes a new `NaiveTime` from hour, minute, second and millisecond. + /// + /// The millisecond part can exceed 1,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or millisecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let from_hmsm_opt = NaiveTime::from_hms_milli_opt; + /// + /// assert!(from_hmsm_opt(0, 0, 0, 0).is_some()); + /// assert!(from_hmsm_opt(23, 59, 59, 999).is_some()); + /// assert!(from_hmsm_opt(23, 59, 59, 1_999).is_some()); // a leap second after 23:59:59 + /// assert!(from_hmsm_opt(24, 0, 0, 0).is_none()); + /// assert!(from_hmsm_opt(23, 60, 0, 0).is_none()); + /// assert!(from_hmsm_opt(23, 59, 60, 0).is_none()); + /// assert!(from_hmsm_opt(23, 59, 59, 2_000).is_none()); + /// ~~~~ + #[inline] + pub fn from_hms_milli_opt(hour: u32, min: u32, sec: u32, milli: u32) -> Option { + milli.checked_mul(1_000_000) + .and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) + } + + /// Makes a new `NaiveTime` from hour, minute, second and microsecond. + /// + /// The microsecond part can exceed 1,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let t = NaiveTime::from_hms_micro(23, 56, 4, 12_345); + /// assert_eq!(t.hour(), 23); + /// assert_eq!(t.minute(), 56); + /// assert_eq!(t.second(), 4); + /// assert_eq!(t.nanosecond(), 12_345_000); + /// ~~~~ + #[inline] + pub fn from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> NaiveTime { + NaiveTime::from_hms_micro_opt(hour, min, sec, micro).expect("invalid time") + } + + /// Makes a new `NaiveTime` from hour, minute, second and microsecond. + /// + /// The microsecond part can exceed 1,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or microsecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let from_hmsu_opt = NaiveTime::from_hms_micro_opt; + /// + /// assert!(from_hmsu_opt(0, 0, 0, 0).is_some()); + /// assert!(from_hmsu_opt(23, 59, 59, 999_999).is_some()); + /// assert!(from_hmsu_opt(23, 59, 59, 1_999_999).is_some()); // a leap second after 23:59:59 + /// assert!(from_hmsu_opt(24, 0, 0, 0).is_none()); + /// assert!(from_hmsu_opt(23, 60, 0, 0).is_none()); + /// assert!(from_hmsu_opt(23, 59, 60, 0).is_none()); + /// assert!(from_hmsu_opt(23, 59, 59, 2_000_000).is_none()); + /// ~~~~ + #[inline] + pub fn from_hms_micro_opt(hour: u32, min: u32, sec: u32, micro: u32) -> Option { + micro.checked_mul(1_000) + .and_then(|nano| NaiveTime::from_hms_nano_opt(hour, min, sec, nano)) + } + + /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Panics on invalid hour, minute, second and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(t.hour(), 23); + /// assert_eq!(t.minute(), 56); + /// assert_eq!(t.second(), 4); + /// assert_eq!(t.nanosecond(), 12_345_678); + /// ~~~~ + #[inline] + pub fn from_hms_nano(hour: u32, min: u32, sec: u32, nano: u32) -> NaiveTime { + NaiveTime::from_hms_nano_opt(hour, min, sec, nano).expect("invalid time") + } + + /// Makes a new `NaiveTime` from hour, minute, second and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Returns `None` on invalid hour, minute, second and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let from_hmsn_opt = NaiveTime::from_hms_nano_opt; + /// + /// assert!(from_hmsn_opt(0, 0, 0, 0).is_some()); + /// assert!(from_hmsn_opt(23, 59, 59, 999_999_999).is_some()); + /// assert!(from_hmsn_opt(23, 59, 59, 1_999_999_999).is_some()); // a leap second after 23:59:59 + /// assert!(from_hmsn_opt(24, 0, 0, 0).is_none()); + /// assert!(from_hmsn_opt(23, 60, 0, 0).is_none()); + /// assert!(from_hmsn_opt(23, 59, 60, 0).is_none()); + /// assert!(from_hmsn_opt(23, 59, 59, 2_000_000_000).is_none()); + /// ~~~~ + #[inline] + pub fn from_hms_nano_opt(hour: u32, min: u32, sec: u32, nano: u32) -> Option { + if hour >= 24 || min >= 60 || sec >= 60 || nano >= 2_000_000_000 { return None; } + let secs = hour * 3600 + min * 60 + sec; + Some(NaiveTime { secs: secs, frac: nano }) + } + + /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Panics on invalid number of seconds and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let t = NaiveTime::from_num_seconds_from_midnight(86164, 12_345_678); + /// assert_eq!(t.hour(), 23); + /// assert_eq!(t.minute(), 56); + /// assert_eq!(t.second(), 4); + /// assert_eq!(t.nanosecond(), 12_345_678); + /// ~~~~ + #[inline] + pub fn from_num_seconds_from_midnight(secs: u32, nano: u32) -> NaiveTime { + NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).expect("invalid time") + } + + /// Makes a new `NaiveTime` from the number of seconds since midnight and nanosecond. + /// + /// The nanosecond part can exceed 1,000,000,000 + /// in order to represent the [leap second](#leap-second-handling). + /// + /// Returns `None` on invalid number of seconds and/or nanosecond. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let from_nsecs_opt = NaiveTime::from_num_seconds_from_midnight_opt; + /// + /// assert!(from_nsecs_opt(0, 0).is_some()); + /// assert!(from_nsecs_opt(86399, 999_999_999).is_some()); + /// assert!(from_nsecs_opt(86399, 1_999_999_999).is_some()); // a leap second after 23:59:59 + /// assert!(from_nsecs_opt(86_400, 0).is_none()); + /// assert!(from_nsecs_opt(86399, 2_000_000_000).is_none()); + /// ~~~~ + #[inline] + pub fn from_num_seconds_from_midnight_opt(secs: u32, nano: u32) -> Option { + if secs >= 86_400 || nano >= 2_000_000_000 { return None; } + Some(NaiveTime { secs: secs, frac: nano }) + } + + /// Parses a string with the specified format string and returns a new `NaiveTime`. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let parse_from_str = NaiveTime::parse_from_str; + /// + /// assert_eq!(parse_from_str("23:56:04", "%H:%M:%S"), + /// Ok(NaiveTime::from_hms(23, 56, 4))); + /// assert_eq!(parse_from_str("pm012345.6789", "%p%I%M%S%.f"), + /// Ok(NaiveTime::from_hms_micro(13, 23, 45, 678_900))); + /// ~~~~ + /// + /// Date and offset is ignored for the purpose of parsing. + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # let parse_from_str = NaiveTime::parse_from_str; + /// assert_eq!(parse_from_str("2014-5-17T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + /// Ok(NaiveTime::from_hms(12, 34, 56))); + /// ~~~~ + /// + /// [Leap seconds](#leap-second-handling) are correctly handled by + /// treating any time of the form `hh:mm:60` as a leap second. + /// (This equally applies to the formatting, so the round trip is possible.) + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # let parse_from_str = NaiveTime::parse_from_str; + /// assert_eq!(parse_from_str("08:59:60.123", "%H:%M:%S%.f"), + /// Ok(NaiveTime::from_hms_milli(8, 59, 59, 1_123))); + /// ~~~~ + /// + /// Missing seconds are assumed to be zero, + /// but out-of-bound times or insufficient fields are errors otherwise. + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # let parse_from_str = NaiveTime::parse_from_str; + /// assert_eq!(parse_from_str("7:15", "%H:%M"), + /// Ok(NaiveTime::from_hms(7, 15, 0))); + /// + /// assert!(parse_from_str("04m33s", "%Mm%Ss").is_err()); + /// assert!(parse_from_str("12", "%H").is_err()); + /// assert!(parse_from_str("17:60", "%H:%M").is_err()); + /// assert!(parse_from_str("24:00:00", "%H:%M:%S").is_err()); + /// ~~~~ + /// + /// All parsed fields should be consistent to each other, otherwise it's an error. + /// Here `%H` is for 24-hour clocks, unlike `%I`, + /// and thus can be independently determined without AM/PM. + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # let parse_from_str = NaiveTime::parse_from_str; + /// assert!(parse_from_str("13:07 AM", "%H:%M %p").is_err()); + /// ~~~~ + pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); + parsed.to_naive_time() + } + + /// Adds given `Duration` to the current time, + /// and also returns the number of *seconds* + /// in the integral number of days ignored from the addition. + /// (We cannot return `Duration` because it is subject to overflow or underflow.) + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveTime; + /// use time::Duration; + /// + /// let from_hms = NaiveTime::from_hms; + /// + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(11)), + /// (from_hms(14, 4, 5), 0)); + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(23)), + /// (from_hms(2, 4, 5), 86_400)); + /// assert_eq!(from_hms(3, 4, 5).overflowing_add_signed(Duration::hours(-7)), + /// (from_hms(20, 4, 5), -86_400)); + /// # } + /// ~~~~ + #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))] + pub fn overflowing_add_signed(&self, mut rhs: OldDuration) -> (NaiveTime, i64) { + let mut secs = self.secs; + let mut frac = self.frac; + + // check if `self` is a leap second and adding `rhs` would escape that leap second. + // if it's the case, update `self` and `rhs` to involve no leap second; + // otherwise the addition immediately finishes. + if frac >= 1_000_000_000 { + let rfrac = 2_000_000_000 - frac; + if rhs >= OldDuration::nanoseconds(i64::from(rfrac)) { + rhs = rhs - OldDuration::nanoseconds(i64::from(rfrac)); + secs += 1; + frac = 0; + } else if rhs < OldDuration::nanoseconds(-i64::from(frac)) { + rhs = rhs + OldDuration::nanoseconds(i64::from(frac)); + frac = 0; + } else { + frac = (i64::from(frac) + rhs.num_nanoseconds().unwrap()) as u32; + debug_assert!(frac < 2_000_000_000); + return (NaiveTime { secs: secs, frac: frac }, 0); + } + } + debug_assert!(secs <= 86_400); + debug_assert!(frac < 1_000_000_000); + + let rhssecs = rhs.num_seconds(); + let rhsfrac = (rhs - OldDuration::seconds(rhssecs)).num_nanoseconds().unwrap(); + debug_assert_eq!(OldDuration::seconds(rhssecs) + OldDuration::nanoseconds(rhsfrac), rhs); + let rhssecsinday = rhssecs % 86_400; + let mut morerhssecs = rhssecs - rhssecsinday; + let rhssecs = rhssecsinday as i32; + let rhsfrac = rhsfrac as i32; + debug_assert!(-86_400 < rhssecs && rhssecs < 86_400); + debug_assert_eq!(morerhssecs % 86_400, 0); + debug_assert!(-1_000_000_000 < rhsfrac && rhsfrac < 1_000_000_000); + + let mut secs = secs as i32 + rhssecs; + let mut frac = frac as i32 + rhsfrac; + debug_assert!(-86_400 < secs && secs < 2 * 86_400); + debug_assert!(-1_000_000_000 < frac && frac < 2_000_000_000); + + if frac < 0 { + frac += 1_000_000_000; + secs -= 1; + } else if frac >= 1_000_000_000 { + frac -= 1_000_000_000; + secs += 1; + } + debug_assert!(-86_400 <= secs && secs < 2 * 86_400); + debug_assert!(0 <= frac && frac < 1_000_000_000); + + if secs < 0 { + secs += 86_400; + morerhssecs -= 86_400; + } else if secs >= 86_400 { + secs -= 86_400; + morerhssecs += 86_400; + } + debug_assert!(0 <= secs && secs < 86_400); + + (NaiveTime { secs: secs as u32, frac: frac as u32 }, morerhssecs) + } + + /// Subtracts given `Duration` from the current time, + /// and also returns the number of *seconds* + /// in the integral number of days ignored from the subtraction. + /// (We cannot return `Duration` because it is subject to overflow or underflow.) + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveTime; + /// use time::Duration; + /// + /// let from_hms = NaiveTime::from_hms; + /// + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(2)), + /// (from_hms(1, 4, 5), 0)); + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(17)), + /// (from_hms(10, 4, 5), 86_400)); + /// assert_eq!(from_hms(3, 4, 5).overflowing_sub_signed(Duration::hours(-22)), + /// (from_hms(1, 4, 5), -86_400)); + /// # } + /// ~~~~ + #[inline] + pub fn overflowing_sub_signed(&self, rhs: OldDuration) -> (NaiveTime, i64) { + let (time, rhs) = self.overflowing_add_signed(-rhs); + (time, -rhs) // safe to negate, rhs is within +/- (2^63 / 1000) + } + + /// Subtracts another `NaiveTime` from the current time. + /// Returns a `Duration` within +/- 1 day. + /// This does not overflow or underflow at all. + /// + /// As a part of Chrono's [leap second handling](#leap-second-handling), + /// the subtraction assumes that **there is no leap second ever**, + /// except when any of the `NaiveTime`s themselves represents a leap second + /// in which case the assumption becomes that + /// **there are exactly one (or two) leap second(s) ever**. + /// + /// # Example + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// use chrono::NaiveTime; + /// use time::Duration; + /// + /// let from_hmsm = NaiveTime::from_hms_milli; + /// let since = NaiveTime::signed_duration_since; + /// + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 900)), + /// Duration::zero()); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 7, 875)), + /// Duration::milliseconds(25)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 6, 925)), + /// Duration::milliseconds(975)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 5, 0, 900)), + /// Duration::seconds(7)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(3, 0, 7, 900)), + /// Duration::seconds(5 * 60)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(0, 5, 7, 900)), + /// Duration::seconds(3 * 3600)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(4, 5, 7, 900)), + /// Duration::seconds(-3600)); + /// assert_eq!(since(from_hmsm(3, 5, 7, 900), from_hmsm(2, 4, 6, 800)), + /// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100)); + /// # } + /// ~~~~ + /// + /// Leap seconds are handled, but the subtraction assumes that + /// there were no other leap seconds happened. + /// + /// ~~~~ + /// # extern crate chrono; extern crate time; fn main() { + /// # use chrono::NaiveTime; + /// # use time::Duration; + /// # let from_hmsm = NaiveTime::from_hms_milli; + /// # let since = NaiveTime::signed_duration_since; + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 59, 0)), + /// Duration::seconds(1)); + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_500), from_hmsm(3, 0, 59, 0)), + /// Duration::milliseconds(1500)); + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(3, 0, 0, 0)), + /// Duration::seconds(60)); + /// assert_eq!(since(from_hmsm(3, 0, 0, 0), from_hmsm(2, 59, 59, 1_000)), + /// Duration::seconds(1)); + /// assert_eq!(since(from_hmsm(3, 0, 59, 1_000), from_hmsm(2, 59, 59, 1_000)), + /// Duration::seconds(61)); + /// # } + /// ~~~~ + pub fn signed_duration_since(self, rhs: NaiveTime) -> OldDuration { + // | | :leap| | | | | | | :leap| | + // | | : | | | | | | | : | | + // ----+----+-----*---+----+----+----+----+----+----+-------*-+----+---- + // | `rhs` | | `self` + // |======================================>| | + // | | `self.secs - rhs.secs` |`self.frac` + // |====>| | |======>| + // `rhs.frac`|========================================>| + // | | | `self - rhs` | | + + use std::cmp::Ordering; + + let secs = i64::from(self.secs) - i64::from(rhs.secs); + let frac = i64::from(self.frac) - i64::from(rhs.frac); + + // `secs` may contain a leap second yet to be counted + let adjust = match self.secs.cmp(&rhs.secs) { + Ordering::Greater => if rhs.frac >= 1_000_000_000 { 1 } else { 0 }, + Ordering::Equal => 0, + Ordering::Less => if self.frac >= 1_000_000_000 { -1 } else { 0 }, + }; + + OldDuration::seconds(secs + adjust) + OldDuration::nanoseconds(frac) + } + + /// Formats the time with the specified formatting items. + /// Otherwise it is same to the ordinary [`format`](#method.format) method. + /// + /// The `Iterator` of items should be `Clone`able, + /// since the resulting `DelayedFormat` value may be formatted multiple times. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// use chrono::format::strftime::StrftimeItems; + /// + /// let fmt = StrftimeItems::new("%H:%M:%S"); + /// let t = NaiveTime::from_hms(23, 56, 4); + /// assert_eq!(t.format_with_items(fmt.clone()).to_string(), "23:56:04"); + /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # use chrono::format::strftime::StrftimeItems; + /// # let fmt = StrftimeItems::new("%H:%M:%S").clone(); + /// # let t = NaiveTime::from_hms(23, 56, 4); + /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); + /// ~~~~ + #[inline] + pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat + where I: Iterator> + Clone { + DelayedFormat::new(None, Some(*self), items) + } + + /// Formats the time with the specified format string. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// This returns a `DelayedFormat`, + /// which gets converted to a string only when actual formatting happens. + /// You may use the `to_string` method to get a `String`, + /// or just feed it into `print!` and other formatting macros. + /// (In this way it avoids the redundant memory allocation.) + /// + /// A wrong format string does *not* issue an error immediately. + /// Rather, converting or formatting the `DelayedFormat` fails. + /// You are recommended to immediately use `DelayedFormat` for this reason. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::NaiveTime; + /// + /// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); + /// assert_eq!(t.format("%H:%M:%S%.6f").to_string(), "23:56:04.012345"); + /// assert_eq!(t.format("%-I:%M %p").to_string(), "11:56 PM"); + /// ~~~~ + /// + /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. + /// + /// ~~~~ + /// # use chrono::NaiveTime; + /// # let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(format!("{}", t.format("%H:%M:%S")), "23:56:04"); + /// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345"); + /// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM"); + /// ~~~~ + #[inline] + pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { + self.format_with_items(StrftimeItems::new(fmt)) + } + + /// Returns a triple of the hour, minute and second numbers. + fn hms(&self) -> (u32, u32, u32) { + let (mins, sec) = div_mod_floor(self.secs, 60); + let (hour, min) = div_mod_floor(mins, 60); + (hour, min, sec) + } +} + +impl Timelike for NaiveTime { + /// Returns the hour number from 0 to 23. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).hour(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).hour(), 23); + /// ~~~~ + #[inline] + fn hour(&self) -> u32 { + self.hms().0 + } + + /// Returns the minute number from 0 to 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).minute(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).minute(), 56); + /// ~~~~ + #[inline] + fn minute(&self) -> u32 { + self.hms().1 + } + + /// Returns the second number from 0 to 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).second(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).second(), 4); + /// ~~~~ + /// + /// This method never returns 60 even when it is a leap second. + /// ([Why?](#leap-second-handling)) + /// Use the proper [formatting method](#method.format) to get a human-readable representation. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// assert_eq!(leap.second(), 59); + /// assert_eq!(leap.format("%H:%M:%S").to_string(), "23:59:60"); + /// ~~~~ + #[inline] + fn second(&self) -> u32 { + self.hms().2 + } + + /// Returns the number of nanoseconds since the whole non-leap second. + /// The range from 1,000,000,000 to 1,999,999,999 represents + /// the [leap second](#leap-second-handling). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(0, 0, 0).nanosecond(), 0); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).nanosecond(), 12_345_678); + /// ~~~~ + /// + /// Leap seconds may have seemingly out-of-range return values. + /// You can reduce the range with `time.nanosecond() % 1_000_000_000`, or + /// use the proper [formatting method](#method.format) to get a human-readable representation. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// let leap = NaiveTime::from_hms_milli(23, 59, 59, 1_000); + /// assert_eq!(leap.nanosecond(), 1_000_000_000); + /// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000"); + /// ~~~~ + #[inline] + fn nanosecond(&self) -> u32 { + self.frac + } + + /// Makes a new `NaiveTime` with the hour number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_hour(7), Some(NaiveTime::from_hms_nano(7, 56, 4, 12_345_678))); + /// assert_eq!(dt.with_hour(24), None); + /// ~~~~ + #[inline] + fn with_hour(&self, hour: u32) -> Option { + if hour >= 24 { return None; } + let secs = hour * 3600 + self.secs % 3600; + Some(NaiveTime { secs: secs, ..*self }) + } + + /// Makes a new `NaiveTime` with the minute number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_minute(45), Some(NaiveTime::from_hms_nano(23, 45, 4, 12_345_678))); + /// assert_eq!(dt.with_minute(60), None); + /// ~~~~ + #[inline] + fn with_minute(&self, min: u32) -> Option { + if min >= 60 { return None; } + let secs = self.secs / 3600 * 3600 + min * 60 + self.secs % 60; + Some(NaiveTime { secs: secs, ..*self }) + } + + /// Makes a new `NaiveTime` with the second number changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// As with the [`second`](#method.second) method, + /// the input range is restricted to 0 through 59. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_second(17), Some(NaiveTime::from_hms_nano(23, 56, 17, 12_345_678))); + /// assert_eq!(dt.with_second(60), None); + /// ~~~~ + #[inline] + fn with_second(&self, sec: u32) -> Option { + if sec >= 60 { return None; } + let secs = self.secs / 60 * 60 + sec; + Some(NaiveTime { secs: secs, ..*self }) + } + + /// Makes a new `NaiveTime` with nanoseconds since the whole non-leap second changed. + /// + /// Returns `None` when the resulting `NaiveTime` would be invalid. + /// As with the [`nanosecond`](#method.nanosecond) method, + /// the input range can exceed 1,000,000,000 for leap seconds. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_nanosecond(333_333_333), + /// Some(NaiveTime::from_hms_nano(23, 56, 4, 333_333_333))); + /// assert_eq!(dt.with_nanosecond(2_000_000_000), None); + /// ~~~~ + /// + /// Leap seconds can theoretically follow *any* whole second. + /// The following would be a proper leap second at the time zone offset of UTC-00:03:57 + /// (there are several historical examples comparable to this "non-sense" offset), + /// and therefore is allowed. + /// + /// ~~~~ + /// # use chrono::{NaiveTime, Timelike}; + /// # let dt = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); + /// assert_eq!(dt.with_nanosecond(1_333_333_333), + /// Some(NaiveTime::from_hms_nano(23, 56, 4, 1_333_333_333))); + /// ~~~~ + #[inline] + fn with_nanosecond(&self, nano: u32) -> Option { + if nano >= 2_000_000_000 { return None; } + Some(NaiveTime { frac: nano, ..*self }) + } + + /// Returns the number of non-leap seconds past the last midnight. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{NaiveTime, Timelike}; + /// + /// assert_eq!(NaiveTime::from_hms(1, 2, 3).num_seconds_from_midnight(), + /// 3723); + /// assert_eq!(NaiveTime::from_hms_nano(23, 56, 4, 12_345_678).num_seconds_from_midnight(), + /// 86164); + /// assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).num_seconds_from_midnight(), + /// 86399); + /// ~~~~ + #[inline] + fn num_seconds_from_midnight(&self) -> u32 { + self.secs // do not repeat the calculation! + } +} + +/// `NaiveTime` can be used as a key to the hash maps (in principle). +/// +/// Practically this also takes account of fractional seconds, so it is not recommended. +/// (For the obvious reason this also distinguishes leap seconds from non-leap seconds.) +#[cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))] +impl hash::Hash for NaiveTime { + fn hash(&self, state: &mut H) { + self.secs.hash(state); + self.frac.hash(state); + } +} + +/// An addition of `Duration` to `NaiveTime` wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. +/// +/// As a part of Chrono's [leap second handling](#leap-second-handling), +/// the addition assumes that **there is no leap second ever**, +/// except when the `NaiveTime` itself represents a leap second +/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveTime; +/// use time::Duration; +/// +/// let from_hmsm = NaiveTime::from_hms_milli; +/// +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::zero(), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(1), from_hmsm(3, 5, 8, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-1), from_hmsm(3, 5, 6, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(60 + 4), from_hmsm(3, 6, 11, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(7*60*60 - 6*60), from_hmsm(9, 59, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::milliseconds(80), from_hmsm(3, 5, 7, 80)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(280), from_hmsm(3, 5, 8, 230)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) + Duration::milliseconds(-980), from_hmsm(3, 5, 6, 970)); +/// # } +/// ~~~~ +/// +/// The addition wraps around. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveTime; +/// # use time::Duration; +/// # let from_hmsm = NaiveTime::from_hms_milli; +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(22*60*60), from_hmsm(1, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::seconds(-8*60*60), from_hmsm(19, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) + Duration::days(800), from_hmsm(3, 5, 7, 0)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, but the addition assumes that it is the only leap second happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveTime; +/// # use time::Duration; +/// # let from_hmsm = NaiveTime::from_hms_milli; +/// let leap = from_hmsm(3, 5, 59, 1_300); +/// assert_eq!(leap + Duration::zero(), from_hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap + Duration::milliseconds(-500), from_hmsm(3, 5, 59, 800)); +/// assert_eq!(leap + Duration::milliseconds(500), from_hmsm(3, 5, 59, 1_800)); +/// assert_eq!(leap + Duration::milliseconds(800), from_hmsm(3, 6, 0, 100)); +/// assert_eq!(leap + Duration::seconds(10), from_hmsm(3, 6, 9, 300)); +/// assert_eq!(leap + Duration::seconds(-10), from_hmsm(3, 5, 50, 300)); +/// assert_eq!(leap + Duration::days(1), from_hmsm(3, 5, 59, 300)); +/// # } +/// ~~~~ +impl Add for NaiveTime { + type Output = NaiveTime; + + #[inline] + fn add(self, rhs: OldDuration) -> NaiveTime { + self.overflowing_add_signed(rhs).0 + } +} + +impl AddAssign for NaiveTime { + #[inline] + fn add_assign(&mut self, rhs: OldDuration) { + *self = self.add(rhs); + } +} + +/// A subtraction of `Duration` from `NaiveTime` wraps around and never overflows or underflows. +/// In particular the addition ignores integral number of days. +/// It is same to the addition with a negated `Duration`. +/// +/// As a part of Chrono's [leap second handling](#leap-second-handling), +/// the addition assumes that **there is no leap second ever**, +/// except when the `NaiveTime` itself represents a leap second +/// in which case the assumption becomes that **there is exactly a single leap second ever**. +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveTime; +/// use time::Duration; +/// +/// let from_hmsm = NaiveTime::from_hms_milli; +/// +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::zero(), from_hmsm(3, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(1), from_hmsm(3, 5, 6, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(60 + 5), from_hmsm(3, 4, 2, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(2*60*60 + 6*60), from_hmsm(0, 59, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::milliseconds(80), from_hmsm(3, 5, 6, 920)); +/// assert_eq!(from_hmsm(3, 5, 7, 950) - Duration::milliseconds(280), from_hmsm(3, 5, 7, 670)); +/// # } +/// ~~~~ +/// +/// The subtraction wraps around. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveTime; +/// # use time::Duration; +/// # let from_hmsm = NaiveTime::from_hms_milli; +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::seconds(8*60*60), from_hmsm(19, 5, 7, 0)); +/// assert_eq!(from_hmsm(3, 5, 7, 0) - Duration::days(800), from_hmsm(3, 5, 7, 0)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, but the subtraction assumes that it is the only leap second happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveTime; +/// # use time::Duration; +/// # let from_hmsm = NaiveTime::from_hms_milli; +/// let leap = from_hmsm(3, 5, 59, 1_300); +/// assert_eq!(leap - Duration::zero(), from_hmsm(3, 5, 59, 1_300)); +/// assert_eq!(leap - Duration::milliseconds(200), from_hmsm(3, 5, 59, 1_100)); +/// assert_eq!(leap - Duration::milliseconds(500), from_hmsm(3, 5, 59, 800)); +/// assert_eq!(leap - Duration::seconds(60), from_hmsm(3, 5, 0, 300)); +/// assert_eq!(leap - Duration::days(1), from_hmsm(3, 6, 0, 300)); +/// # } +/// ~~~~ +impl Sub for NaiveTime { + type Output = NaiveTime; + + #[inline] + fn sub(self, rhs: OldDuration) -> NaiveTime { + self.overflowing_sub_signed(rhs).0 + } +} + +impl SubAssign for NaiveTime { + #[inline] + fn sub_assign(&mut self, rhs: OldDuration) { + *self = self.sub(rhs); + } +} + +/// Subtracts another `NaiveTime` from the current time. +/// Returns a `Duration` within +/- 1 day. +/// This does not overflow or underflow at all. +/// +/// As a part of Chrono's [leap second handling](#leap-second-handling), +/// the subtraction assumes that **there is no leap second ever**, +/// except when any of the `NaiveTime`s themselves represents a leap second +/// in which case the assumption becomes that +/// **there are exactly one (or two) leap second(s) ever**. +/// +/// The implementation is a wrapper around +/// [`NaiveTime::signed_duration_since`](#method.signed_duration_since). +/// +/// # Example +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// use chrono::NaiveTime; +/// use time::Duration; +/// +/// let from_hmsm = NaiveTime::from_hms_milli; +/// +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 900), Duration::zero()); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 7, 875), Duration::milliseconds(25)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 6, 925), Duration::milliseconds(975)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 5, 0, 900), Duration::seconds(7)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(3, 0, 7, 900), Duration::seconds(5 * 60)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(0, 5, 7, 900), Duration::seconds(3 * 3600)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(4, 5, 7, 900), Duration::seconds(-3600)); +/// assert_eq!(from_hmsm(3, 5, 7, 900) - from_hmsm(2, 4, 6, 800), +/// Duration::seconds(3600 + 60 + 1) + Duration::milliseconds(100)); +/// # } +/// ~~~~ +/// +/// Leap seconds are handled, but the subtraction assumes that +/// there were no other leap seconds happened. +/// +/// ~~~~ +/// # extern crate chrono; extern crate time; fn main() { +/// # use chrono::NaiveTime; +/// # use time::Duration; +/// # let from_hmsm = NaiveTime::from_hms_milli; +/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 59, 0), Duration::seconds(1)); +/// assert_eq!(from_hmsm(3, 0, 59, 1_500) - from_hmsm(3, 0, 59, 0), +/// Duration::milliseconds(1500)); +/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(3, 0, 0, 0), Duration::seconds(60)); +/// assert_eq!(from_hmsm(3, 0, 0, 0) - from_hmsm(2, 59, 59, 1_000), Duration::seconds(1)); +/// assert_eq!(from_hmsm(3, 0, 59, 1_000) - from_hmsm(2, 59, 59, 1_000), +/// Duration::seconds(61)); +/// # } +/// ~~~~ +impl Sub for NaiveTime { + type Output = OldDuration; + + #[inline] + fn sub(self, rhs: NaiveTime) -> OldDuration { + self.signed_duration_since(rhs) + } +} + +/// The `Debug` output of the naive time `t` is same to +/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// It should be noted that, for leap seconds not on the minute boundary, +/// it may print a representation not distinguishable from non-leap seconds. +/// This doesn't matter in practice, since such leap seconds never happened. +/// (By the time of the first leap second on 1972-06-30, +/// every time zone offset around the world has standardized to the 5-minute alignment.) +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveTime; +/// +/// assert_eq!(format!("{:?}", NaiveTime::from_hms(23, 56, 4)), "23:56:04"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234"); +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456"); +/// ~~~~ +/// +/// Leap seconds may also be used. +/// +/// ~~~~ +/// # use chrono::NaiveTime; +/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500"); +/// ~~~~ +impl fmt::Debug for NaiveTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (hour, min, sec) = self.hms(); + let (sec, nano) = if self.frac >= 1_000_000_000 { + (sec + 1, self.frac - 1_000_000_000) + } else { + (sec, self.frac) + }; + + try!(write!(f, "{:02}:{:02}:{:02}", hour, min, sec)); + if nano == 0 { + Ok(()) + } else if nano % 1_000_000 == 0 { + write!(f, ".{:03}", nano / 1_000_000) + } else if nano % 1_000 == 0 { + write!(f, ".{:06}", nano / 1_000) + } else { + write!(f, ".{:09}", nano) + } + } +} + +/// The `Display` output of the naive time `t` is same to +/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html). +/// +/// The string printed can be readily parsed via the `parse` method on `str`. +/// +/// It should be noted that, for leap seconds not on the minute boundary, +/// it may print a representation not distinguishable from non-leap seconds. +/// This doesn't matter in practice, since such leap seconds never happened. +/// (By the time of the first leap second on 1972-06-30, +/// every time zone offset around the world has standardized to the 5-minute alignment.) +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveTime; +/// +/// assert_eq!(format!("{}", NaiveTime::from_hms(23, 56, 4)), "23:56:04"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 56, 4, 12)), "23:56:04.012"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_micro(23, 56, 4, 1234)), "23:56:04.001234"); +/// assert_eq!(format!("{}", NaiveTime::from_hms_nano(23, 56, 4, 123456)), "23:56:04.000123456"); +/// ~~~~ +/// +/// Leap seconds may also be used. +/// +/// ~~~~ +/// # use chrono::NaiveTime; +/// assert_eq!(format!("{}", NaiveTime::from_hms_milli(6, 59, 59, 1_500)), "06:59:60.500"); +/// ~~~~ +impl fmt::Display for NaiveTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } +} + +/// Parsing a `str` into a `NaiveTime` uses the same format, +/// [`%H:%M:%S%.f`](../format/strftime/index.html), as in `Debug` and `Display`. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::NaiveTime; +/// +/// let t = NaiveTime::from_hms(23, 56, 4); +/// assert_eq!("23:56:04".parse::(), Ok(t)); +/// +/// let t = NaiveTime::from_hms_nano(23, 56, 4, 12_345_678); +/// assert_eq!("23:56:4.012345678".parse::(), Ok(t)); +/// +/// let t = NaiveTime::from_hms_nano(23, 59, 59, 1_234_567_890); // leap second +/// assert_eq!("23:59:60.23456789".parse::(), Ok(t)); +/// +/// assert!("foo".parse::().is_err()); +/// ~~~~ +impl str::FromStr for NaiveTime { + type Err = ParseError; + + fn from_str(s: &str) -> ParseResult { + const ITEMS: &'static [Item<'static>] = &[ + Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Space(""), Item::Literal(":"), + Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Fixed(Fixed::Nanosecond), Item::Space(""), + ]; + + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + parsed.to_naive_time() + } +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_encodable_json(to_string: F) + where F: Fn(&NaiveTime) -> Result, E: ::std::fmt::Debug +{ + assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(), + Some(r#""00:00:00""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(), + Some(r#""00:00:00.950""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(), + Some(r#""00:00:60""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(), + Some(r#""00:01:02""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(), + Some(r#""03:05:07.098765432""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(), + Some(r#""07:08:09""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(), + Some(r#""12:34:56.000789""#.into())); + assert_eq!(to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(), + Some(r#""23:59:60.999999999""#.into())); +} + +#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))] +fn test_decodable_json(from_str: F) + where F: Fn(&str) -> Result, E: ::std::fmt::Debug +{ + assert_eq!(from_str(r#""00:00:00""#).ok(), + Some(NaiveTime::from_hms(0, 0, 0))); + assert_eq!(from_str(r#""0:0:0""#).ok(), + Some(NaiveTime::from_hms(0, 0, 0))); + assert_eq!(from_str(r#""00:00:00.950""#).ok(), + Some(NaiveTime::from_hms_milli(0, 0, 0, 950))); + assert_eq!(from_str(r#""0:0:0.95""#).ok(), + Some(NaiveTime::from_hms_milli(0, 0, 0, 950))); + assert_eq!(from_str(r#""00:00:60""#).ok(), + Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000))); + assert_eq!(from_str(r#""00:01:02""#).ok(), + Some(NaiveTime::from_hms(0, 1, 2))); + assert_eq!(from_str(r#""03:05:07.098765432""#).ok(), + Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432))); + assert_eq!(from_str(r#""07:08:09""#).ok(), + Some(NaiveTime::from_hms(7, 8, 9))); + assert_eq!(from_str(r#""12:34:56.000789""#).ok(), + Some(NaiveTime::from_hms_micro(12, 34, 56, 789))); + assert_eq!(from_str(r#""23:59:60.999999999""#).ok(), + Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999))); + assert_eq!(from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored + Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999))); + + // bad formats + assert!(from_str(r#""""#).is_err()); + assert!(from_str(r#""000000""#).is_err()); + assert!(from_str(r#""00:00:61""#).is_err()); + assert!(from_str(r#""00:60:00""#).is_err()); + assert!(from_str(r#""24:00:00""#).is_err()); + assert!(from_str(r#""23:59:59,1""#).is_err()); + assert!(from_str(r#""012:34:56""#).is_err()); + assert!(from_str(r#""hh:mm:ss""#).is_err()); + assert!(from_str(r#"0"#).is_err()); + assert!(from_str(r#"86399"#).is_err()); + assert!(from_str(r#"{}"#).is_err()); + // pre-0.3.0 rustc-serialize format is now invalid + assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err()); + assert!(from_str(r#"null"#).is_err()); +} + +#[cfg(feature = "rustc-serialize")] +mod rustc_serialize { + use super::NaiveTime; + use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; + + impl Encodable for NaiveTime { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + format!("{:?}", self).encode(s) + } + } + + impl Decodable for NaiveTime { + fn decode(d: &mut D) -> Result { + d.read_str()?.parse().map_err(|_| d.error("invalid time")) + } + } + + #[cfg(test)] use rustc_serialize::json; + + #[test] + fn test_encodable() { + super::test_encodable_json(json::encode); + } + + #[test] + fn test_decodable() { + super::test_decodable_json(json::decode); + } +} + +#[cfg(feature = "serde")] +mod serde { + use std::fmt; + use super::NaiveTime; + use serdelib::{ser, de}; + + // TODO not very optimized for space (binary formats would want something better) + // TODO round-trip for general leap seconds (not just those with second = 60) + + impl ser::Serialize for NaiveTime { + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer + { + serializer.collect_str(&self) + } + } + + struct NaiveTimeVisitor; + + impl<'de> de::Visitor<'de> for NaiveTimeVisitor { + type Value = NaiveTime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + { + write!(formatter, "a formatted time string") + } + + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::custom(format!("{}", err))) + } + } + + impl<'de> de::Deserialize<'de> for NaiveTime { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + deserializer.deserialize_str(NaiveTimeVisitor) + } + } + + #[cfg(test)] extern crate serde_json; + #[cfg(test)] extern crate bincode; + + #[test] + fn test_serde_serialize() { + super::test_encodable_json(self::serde_json::to_string); + } + + #[test] + fn test_serde_deserialize() { + super::test_decodable_json(|input| self::serde_json::from_str(&input)); + } + + #[test] + fn test_serde_bincode() { + // Bincode is relevant to test separately from JSON because + // it is not self-describing. + use self::bincode::{Infinite, serialize, deserialize}; + + let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + let encoded = serialize(&t, Infinite).unwrap(); + let decoded: NaiveTime = deserialize(&encoded).unwrap(); + assert_eq!(t, decoded); + } +} + +#[cfg(test)] +mod tests { + use super::NaiveTime; + use Timelike; + use std::u32; + use oldtime::Duration; + + #[test] + fn test_time_from_hms_milli() { + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 0), + Some(NaiveTime::from_hms_nano(3, 5, 7, 0))); + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 777), + Some(NaiveTime::from_hms_nano(3, 5, 7, 777_000_000))); + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 1_999), + Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_000_000))); + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 2_000), None); + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, 5_000), None); // overflow check + assert_eq!(NaiveTime::from_hms_milli_opt(3, 5, 7, u32::MAX), None); + } + + #[test] + fn test_time_from_hms_micro() { + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 0), + Some(NaiveTime::from_hms_nano(3, 5, 7, 0))); + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 333), + Some(NaiveTime::from_hms_nano(3, 5, 7, 333_000))); + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 777_777), + Some(NaiveTime::from_hms_nano(3, 5, 7, 777_777_000))); + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 1_999_999), + Some(NaiveTime::from_hms_nano(3, 5, 7, 1_999_999_000))); + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 2_000_000), None); + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, 5_000_000), None); // overflow check + assert_eq!(NaiveTime::from_hms_micro_opt(3, 5, 7, u32::MAX), None); + } + + #[test] + fn test_time_hms() { + assert_eq!(NaiveTime::from_hms(3, 5, 7).hour(), 3); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(0), + Some(NaiveTime::from_hms(0, 5, 7))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(23), + Some(NaiveTime::from_hms(23, 5, 7))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(24), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_hour(u32::MAX), None); + + assert_eq!(NaiveTime::from_hms(3, 5, 7).minute(), 5); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(0), + Some(NaiveTime::from_hms(3, 0, 7))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(59), + Some(NaiveTime::from_hms(3, 59, 7))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(60), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_minute(u32::MAX), None); + + assert_eq!(NaiveTime::from_hms(3, 5, 7).second(), 7); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(0), + Some(NaiveTime::from_hms(3, 5, 0))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(59), + Some(NaiveTime::from_hms(3, 5, 59))); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(60), None); + assert_eq!(NaiveTime::from_hms(3, 5, 7).with_second(u32::MAX), None); + } + + #[test] + fn test_time_add() { + macro_rules! check { + ($lhs:expr, $rhs:expr, $sum:expr) => ({ + assert_eq!($lhs + $rhs, $sum); + //assert_eq!($rhs + $lhs, $sum); + }) + } + + let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi); + + check!(hmsm(3, 5, 7, 900), Duration::zero(), hmsm(3, 5, 7, 900)); + check!(hmsm(3, 5, 7, 900), Duration::milliseconds(100), hmsm(3, 5, 8, 0)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-1800), hmsm(3, 5, 6, 500)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-800), hmsm(3, 5, 7, 500)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(-100), hmsm(3, 5, 7, 1_200)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(100), hmsm(3, 5, 7, 1_400)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(800), hmsm(3, 5, 8, 100)); + check!(hmsm(3, 5, 7, 1_300), Duration::milliseconds(1800), hmsm(3, 5, 9, 100)); + check!(hmsm(3, 5, 7, 900), Duration::seconds(86399), hmsm(3, 5, 6, 900)); // overwrap + check!(hmsm(3, 5, 7, 900), Duration::seconds(-86399), hmsm(3, 5, 8, 900)); + check!(hmsm(3, 5, 7, 900), Duration::days(12345), hmsm(3, 5, 7, 900)); + check!(hmsm(3, 5, 7, 1_300), Duration::days(1), hmsm(3, 5, 7, 300)); + check!(hmsm(3, 5, 7, 1_300), Duration::days(-1), hmsm(3, 5, 8, 300)); + + // regression tests for #37 + check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-990), hmsm(23, 59, 59, 10)); + check!(hmsm(0, 0, 0, 0), Duration::milliseconds(-9990), hmsm(23, 59, 50, 10)); + } + + #[test] + fn test_time_overflowing_add() { + let hmsm = NaiveTime::from_hms_milli; + + assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(11)), + (hmsm(14, 4, 5, 678), 0)); + assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(23)), + (hmsm(2, 4, 5, 678), 86_400)); + assert_eq!(hmsm(3, 4, 5, 678).overflowing_add_signed(Duration::hours(-7)), + (hmsm(20, 4, 5, 678), -86_400)); + + // overflowing_add_signed with leap seconds may be counter-intuitive + assert_eq!(hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(1)), + (hmsm(3, 4, 5, 678), 86_400)); + assert_eq!(hmsm(3, 4, 5, 1_678).overflowing_add_signed(Duration::days(-1)), + (hmsm(3, 4, 6, 678), -86_400)); + } + + #[test] + fn test_time_addassignment() { + let hms = NaiveTime::from_hms; + let mut time = hms(12, 12, 12); + time += Duration::hours(10); + assert_eq!(time, hms(22, 12, 12)); + time += Duration::hours(10); + assert_eq!(time, hms(8, 12, 12)); + } + + #[test] + fn test_time_subassignment() { + let hms = NaiveTime::from_hms; + let mut time = hms(12, 12, 12); + time -= Duration::hours(10); + assert_eq!(time, hms(2, 12, 12)); + time -= Duration::hours(10); + assert_eq!(time, hms(16, 12, 12)); + } + + #[test] + fn test_time_sub() { + macro_rules! check { + ($lhs:expr, $rhs:expr, $diff:expr) => ({ + // `time1 - time2 = duration` is equivalent to `time2 - time1 = -duration` + assert_eq!($lhs.signed_duration_since($rhs), $diff); + assert_eq!($rhs.signed_duration_since($lhs), -$diff); + }) + } + + let hmsm = |h,m,s,mi| NaiveTime::from_hms_milli(h, m, s, mi); + + check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 900), Duration::zero()); + check!(hmsm(3, 5, 7, 900), hmsm(3, 5, 7, 600), Duration::milliseconds(300)); + check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 200), Duration::seconds(3600 + 60 + 1)); + check!(hmsm(3, 5, 7, 200), hmsm(2, 4, 6, 300), + Duration::seconds(3600 + 60) + Duration::milliseconds(900)); + + // treats the leap second as if it coincides with the prior non-leap second, + // as required by `time1 - time2 = duration` and `time2 - time1 = -duration` equivalence. + check!(hmsm(3, 5, 7, 200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(400)); + check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 1_800), Duration::milliseconds(1400)); + check!(hmsm(3, 5, 7, 1_200), hmsm(3, 5, 6, 800), Duration::milliseconds(1400)); + + // additional equality: `time1 + duration = time2` is equivalent to + // `time2 - time1 = duration` IF AND ONLY IF `time2` represents a non-leap second. + assert_eq!(hmsm(3, 5, 6, 800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200)); + assert_eq!(hmsm(3, 5, 6, 1_800) + Duration::milliseconds(400), hmsm(3, 5, 7, 200)); + } + + #[test] + fn test_time_fmt() { + assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 999)), "23:59:59.999"); + assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_000)), "23:59:60"); + assert_eq!(format!("{}", NaiveTime::from_hms_milli(23, 59, 59, 1_001)), "23:59:60.001"); + assert_eq!(format!("{}", NaiveTime::from_hms_micro(0, 0, 0, 43210)), "00:00:00.043210"); + assert_eq!(format!("{}", NaiveTime::from_hms_nano(0, 0, 0, 6543210)), "00:00:00.006543210"); + + // the format specifier should have no effect on `NaiveTime` + assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009"); + } + + #[test] + fn test_date_from_str() { + // valid cases + let valid = [ + "0:0:0", + "0:0:0.0000000", + "0:0:0.0000003", + " 4 : 3 : 2.1 ", + " 09:08:07 ", + " 9:8:07 ", + "23:59:60.373929310237", + ]; + for &s in &valid { + let d = match s.parse::() { + Ok(d) => d, + Err(e) => panic!("parsing `{}` has failed: {}", s, e) + }; + let s_ = format!("{:?}", d); + // `s` and `s_` may differ, but `s.parse()` and `s_.parse()` must be same + let d_ = match s_.parse::() { + Ok(d) => d, + Err(e) => panic!("`{}` is parsed into `{:?}`, but reparsing that has failed: {}", + s, d, e) + }; + assert!(d == d_, "`{}` is parsed into `{:?}`, but reparsed result \ + `{:?}` does not match", s, d, d_); + } + + // some invalid cases + // since `ParseErrorKind` is private, all we can do is to check if there was an error + assert!("".parse::().is_err()); + assert!("x".parse::().is_err()); + assert!("15".parse::().is_err()); + assert!("15:8".parse::().is_err()); + assert!("15:8:x".parse::().is_err()); + assert!("15:8:9x".parse::().is_err()); + assert!("23:59:61".parse::().is_err()); + assert!("12:34:56.x".parse::().is_err()); + assert!("12:34:56. 0".parse::().is_err()); + } + + #[test] + fn test_time_parse_from_str() { + let hms = |h,m,s| NaiveTime::from_hms(h,m,s); + assert_eq!(NaiveTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"), + Ok(hms(12, 34, 56))); // ignore date and offset + assert_eq!(NaiveTime::parse_from_str("PM 12:59", "%P %H:%M"), + Ok(hms(12, 59, 0))); + assert!(NaiveTime::parse_from_str("12:3456", "%H:%M:%S").is_err()); + } + + #[test] + fn test_time_format() { + let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM"); + assert_eq!(t.format("%M").to_string(), "05"); + assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432"); + assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".098,.098765,.098765432"); + assert_eq!(t.format("%R").to_string(), "03:05"); + assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07"); + assert_eq!(t.format("%r").to_string(), "03:05:07 AM"); + assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + + let t = NaiveTime::from_hms_micro(3, 5, 7, 432100); + assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100"); + assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000"); + + let t = NaiveTime::from_hms_milli(3, 5, 7, 210); + assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210"); + assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000"); + + let t = NaiveTime::from_hms(3, 5, 7); + assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,"); + assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000"); + + // corner cases + assert_eq!(NaiveTime::from_hms(13, 57, 9).format("%r").to_string(), "01:57:09 PM"); + assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).format("%X").to_string(), + "23:59:60"); + } +} + diff --git a/chrono/src/offset/fixed.rs b/chrono/src/offset/fixed.rs new file mode 100644 index 000000000..ef861ceec --- /dev/null +++ b/chrono/src/offset/fixed.rs @@ -0,0 +1,224 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The time zone which has a fixed offset from UTC. + +use std::ops::{Add, Sub}; +use std::fmt; +use oldtime::Duration as OldDuration; + +use Timelike; +use div::div_mod_floor; +use naive::{NaiveTime, NaiveDate, NaiveDateTime}; +use DateTime; +use super::{TimeZone, Offset, LocalResult}; + +/// The time zone with fixed offset, from UTC-23:59:59 to UTC+23:59:59. +/// +/// Using the [`TimeZone`](./trait.TimeZone.html) methods +/// on a `FixedOffset` struct is the preferred way to construct +/// `DateTime` instances. See the [`east`](#method.east) and +/// [`west`](#method.west) methods for examples. +#[derive(PartialEq, Eq, Hash, Copy, Clone)] +pub struct FixedOffset { + local_minus_utc: i32, +} + +impl FixedOffset { + /// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference. + /// The negative `secs` means the Western Hemisphere. + /// + /// Panics on the out-of-bound `secs`. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{FixedOffset, TimeZone}; + /// let hour = 3600; + /// let datetime = FixedOffset::east(5 * hour).ymd(2016, 11, 08) + /// .and_hms(0, 0, 0); + /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00+05:00") + /// ~~~~ + pub fn east(secs: i32) -> FixedOffset { + FixedOffset::east_opt(secs).expect("FixedOffset::east out of bounds") + } + + /// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference. + /// The negative `secs` means the Western Hemisphere. + /// + /// Returns `None` on the out-of-bound `secs`. + pub fn east_opt(secs: i32) -> Option { + if -86_400 < secs && secs < 86_400 { + Some(FixedOffset { local_minus_utc: secs }) + } else { + None + } + } + + /// Makes a new `FixedOffset` for the Western Hemisphere with given timezone difference. + /// The negative `secs` means the Eastern Hemisphere. + /// + /// Panics on the out-of-bound `secs`. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{FixedOffset, TimeZone}; + /// let hour = 3600; + /// let datetime = FixedOffset::west(5 * hour).ymd(2016, 11, 08) + /// .and_hms(0, 0, 0); + /// assert_eq!(&datetime.to_rfc3339(), "2016-11-08T00:00:00-05:00") + /// ~~~~ + pub fn west(secs: i32) -> FixedOffset { + FixedOffset::west_opt(secs).expect("FixedOffset::west out of bounds") + } + + /// Makes a new `FixedOffset` for the Western Hemisphere with given timezone difference. + /// The negative `secs` means the Eastern Hemisphere. + /// + /// Returns `None` on the out-of-bound `secs`. + pub fn west_opt(secs: i32) -> Option { + if -86_400 < secs && secs < 86_400 { + Some(FixedOffset { local_minus_utc: -secs }) + } else { + None + } + } + + /// Returns the number of seconds to add to convert from UTC to the local time. + pub fn local_minus_utc(&self) -> i32 { + self.local_minus_utc + } + + /// Returns the number of seconds to add to convert from the local time to UTC. + pub fn utc_minus_local(&self) -> i32 { + -self.local_minus_utc + } +} + +impl TimeZone for FixedOffset { + type Offset = FixedOffset; + + fn from_offset(offset: &FixedOffset) -> FixedOffset { *offset } + + fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult { + LocalResult::Single(*self) + } + fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { + LocalResult::Single(*self) + } + + fn offset_from_utc_date(&self, _utc: &NaiveDate) -> FixedOffset { *self } + fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> FixedOffset { *self } +} + +impl Offset for FixedOffset { + fn fix(&self) -> FixedOffset { *self } +} + +impl fmt::Debug for FixedOffset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let offset = self.local_minus_utc; + let (sign, offset) = if offset < 0 {('-', -offset)} else {('+', offset)}; + let (mins, sec) = div_mod_floor(offset, 60); + let (hour, min) = div_mod_floor(mins, 60); + if sec == 0 { + write!(f, "{}{:02}:{:02}", sign, hour, min) + } else { + write!(f, "{}{:02}:{:02}:{:02}", sign, hour, min, sec) + } + } +} + +impl fmt::Display for FixedOffset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) } +} + +// addition or subtraction of FixedOffset to/from Timelike values is same to +// adding or subtracting the offset's local_minus_utc value +// but keep keeps the leap second information. +// this should be implemented more efficiently, but for the time being, this is generic right now. + +fn add_with_leapsecond(lhs: &T, rhs: i32) -> T + where T: Timelike + Add +{ + // extract and temporarily remove the fractional part and later recover it + let nanos = lhs.nanosecond(); + let lhs = lhs.with_nanosecond(0).unwrap(); + (lhs + OldDuration::seconds(i64::from(rhs))).with_nanosecond(nanos).unwrap() +} + +impl Add for NaiveTime { + type Output = NaiveTime; + + #[inline] + fn add(self, rhs: FixedOffset) -> NaiveTime { + add_with_leapsecond(&self, rhs.local_minus_utc) + } +} + +impl Sub for NaiveTime { + type Output = NaiveTime; + + #[inline] + fn sub(self, rhs: FixedOffset) -> NaiveTime { + add_with_leapsecond(&self, -rhs.local_minus_utc) + } +} + +impl Add for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn add(self, rhs: FixedOffset) -> NaiveDateTime { + add_with_leapsecond(&self, rhs.local_minus_utc) + } +} + +impl Sub for NaiveDateTime { + type Output = NaiveDateTime; + + #[inline] + fn sub(self, rhs: FixedOffset) -> NaiveDateTime { + add_with_leapsecond(&self, -rhs.local_minus_utc) + } +} + +impl Add for DateTime { + type Output = DateTime; + + #[inline] + fn add(self, rhs: FixedOffset) -> DateTime { + add_with_leapsecond(&self, rhs.local_minus_utc) + } +} + +impl Sub for DateTime { + type Output = DateTime; + + #[inline] + fn sub(self, rhs: FixedOffset) -> DateTime { + add_with_leapsecond(&self, -rhs.local_minus_utc) + } +} + +#[cfg(test)] +mod tests { + use offset::TimeZone; + use super::FixedOffset; + + #[test] + fn test_date_extreme_offset() { + // starting from 0.3 we don't have an offset exceeding one day. + // this makes everything easier! + assert_eq!(format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29)), + "2012-02-29+23:59:59".to_string()); + assert_eq!(format!("{:?}", FixedOffset::east(86399).ymd(2012, 2, 29).and_hms(5, 6, 7)), + "2012-02-29T05:06:07+23:59:59".to_string()); + assert_eq!(format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4)), + "2012-03-04-23:59:59".to_string()); + assert_eq!(format!("{:?}", FixedOffset::west(86399).ymd(2012, 3, 4).and_hms(5, 6, 7)), + "2012-03-04T05:06:07-23:59:59".to_string()); + } +} + diff --git a/chrono/src/offset/local.rs b/chrono/src/offset/local.rs new file mode 100644 index 000000000..6aa4ab755 --- /dev/null +++ b/chrono/src/offset/local.rs @@ -0,0 +1,182 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The local (system) time zone. + +use oldtime; + +use {Datelike, Timelike}; +use naive::{NaiveDate, NaiveTime, NaiveDateTime}; +use {Date, DateTime}; +use super::{TimeZone, LocalResult}; +use super::fixed::FixedOffset; + +/// Converts a `time::Tm` struct into the timezone-aware `DateTime`. +/// This assumes that `time` is working correctly, i.e. any error is fatal. +fn tm_to_datetime(mut tm: oldtime::Tm) -> DateTime { + if tm.tm_sec >= 60 { + tm.tm_nsec += (tm.tm_sec - 59) * 1_000_000_000; + tm.tm_sec = 59; + } + + #[cfg(not(windows))] + fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate { + // from_yo is more efficient than from_ymd (since it's the internal representation). + NaiveDate::from_yo(tm.tm_year + 1900, tm.tm_yday as u32 + 1) + } + + #[cfg(windows)] + fn tm_to_naive_date(tm: &oldtime::Tm) -> NaiveDate { + // ...but tm_yday is broken in Windows (issue #85) + NaiveDate::from_ymd(tm.tm_year + 1900, tm.tm_mon as u32 + 1, tm.tm_mday as u32) + } + + let date = tm_to_naive_date(&tm); + let time = NaiveTime::from_hms_nano(tm.tm_hour as u32, tm.tm_min as u32, + tm.tm_sec as u32, tm.tm_nsec as u32); + let offset = FixedOffset::east(tm.tm_utcoff); + DateTime::from_utc(date.and_time(time) - offset, offset) +} + +/// Converts a local `NaiveDateTime` to the `time::Timespec`. +fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec { + // well, this exploits an undocumented `Tm::to_timespec` behavior + // to get the exact function we want (either `timegm` or `mktime`). + // the number 1 is arbitrary but should be non-zero to trigger `mktime`. + let tm_utcoff = if local {1} else {0}; + + let tm = oldtime::Tm { + tm_sec: d.second() as i32, + tm_min: d.minute() as i32, + tm_hour: d.hour() as i32, + tm_mday: d.day() as i32, + tm_mon: d.month0() as i32, // yes, C is that strange... + tm_year: d.year() - 1900, // this doesn't underflow, we know that d is `NaiveDateTime`. + tm_wday: 0, // to_local ignores this + tm_yday: 0, // and this + tm_isdst: -1, + tm_utcoff: tm_utcoff, + // do not set this, OS APIs are heavily inconsistent in terms of leap second handling + tm_nsec: 0, + }; + + tm.to_timespec() +} + +/// The local timescale. This is implemented via the standard `time` crate. +/// +/// Using the [`TimeZone`](./trait.TimeZone.html) methods +/// on the Local struct is the preferred way to construct `DateTime` +/// instances. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::{Local, DateTime, TimeZone}; +/// +/// let dt: DateTime = Local::now(); +/// let dt: DateTime = Local.timestamp(0, 0); +/// ~~~~ +#[derive(Copy, Clone, Debug)] +pub struct Local; + +impl Local { + /// Returns a `Date` which corresponds to the current date. + pub fn today() -> Date { + Local::now().date() + } + + /// Returns a `DateTime` which corresponds to the current date. + pub fn now() -> DateTime { + tm_to_datetime(oldtime::now()) + } +} + +impl TimeZone for Local { + type Offset = FixedOffset; + + fn from_offset(_offset: &FixedOffset) -> Local { Local } + + // they are easier to define in terms of the finished date and time unlike other offsets + fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult { + self.from_local_date(local).map(|date| *date.offset()) + } + + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult { + self.from_local_datetime(local).map(|datetime| *datetime.offset()) + } + + fn offset_from_utc_date(&self, utc: &NaiveDate) -> FixedOffset { + *self.from_utc_date(utc).offset() + } + + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> FixedOffset { + *self.from_utc_datetime(utc).offset() + } + + // override them for avoiding redundant works + fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { + // this sounds very strange, but required for keeping `TimeZone::ymd` sane. + // in the other words, we use the offset at the local midnight + // but keep the actual date unaltered (much like `FixedOffset`). + let midnight = self.from_local_datetime(&local.and_hms(0, 0, 0)); + midnight.map(|datetime| Date::from_utc(*local, *datetime.offset())) + } + + fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { + let timespec = datetime_to_timespec(local, true); + + // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them + let mut tm = oldtime::at(timespec); + assert_eq!(tm.tm_nsec, 0); + tm.tm_nsec = local.nanosecond() as i32; + + LocalResult::Single(tm_to_datetime(tm)) + } + + fn from_utc_date(&self, utc: &NaiveDate) -> Date { + let midnight = self.from_utc_datetime(&utc.and_hms(0, 0, 0)); + Date::from_utc(*utc, *midnight.offset()) + } + + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { + let timespec = datetime_to_timespec(utc, false); + + // datetime_to_timespec completely ignores leap seconds, so we need to adjust for them + let mut tm = oldtime::at(timespec); + assert_eq!(tm.tm_nsec, 0); + tm.tm_nsec = utc.nanosecond() as i32; + + tm_to_datetime(tm) + } +} + +#[cfg(test)] +mod tests { + use Datelike; + use offset::TimeZone; + use super::Local; + + #[test] + fn test_local_date_sanity_check() { // issue #27 + assert_eq!(Local.ymd(2999, 12, 28).day(), 28); + } + + #[test] + fn test_leap_second() { // issue #123 + let today = Local::today(); + + let dt = today.and_hms_milli(1, 2, 59, 1000); + let timestr = dt.time().to_string(); + // the OS API may or may not support the leap second, + // but there are only two sensible options. + assert!(timestr == "01:02:60" || timestr == "01:03:00", + "unexpected timestr {:?}", timestr); + + let dt = today.and_hms_milli(1, 2, 3, 1234); + let timestr = dt.time().to_string(); + assert!(timestr == "01:02:03.234" || timestr == "01:02:04.234", + "unexpected timestr {:?}", timestr); + } +} + diff --git a/chrono/src/offset/mod.rs b/chrono/src/offset/mod.rs new file mode 100644 index 000000000..ca8657471 --- /dev/null +++ b/chrono/src/offset/mod.rs @@ -0,0 +1,419 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The time zone, which calculates offsets from the local time to UTC. +//! +//! There are four operations provided by the `TimeZone` trait: +//! +//! 1. Converting the local `NaiveDateTime` to `DateTime` +//! 2. Converting the UTC `NaiveDateTime` to `DateTime` +//! 3. Converting `DateTime` to the local `NaiveDateTime` +//! 4. Constructing `DateTime` objects from various offsets +//! +//! 1 is used for constructors. 2 is used for the `with_timezone` method of date and time types. +//! 3 is used for other methods, e.g. `year()` or `format()`, and provided by an associated type +//! which implements `Offset` (which then passed to `TimeZone` for actual implementations). +//! Technically speaking `TimeZone` has a total knowledge about given timescale, +//! but `Offset` is used as a cache to avoid the repeated conversion +//! and provides implementations for 1 and 3. +//! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance. + +use std::fmt; + +use Weekday; +use naive::{NaiveDate, NaiveTime, NaiveDateTime}; +use {Date, DateTime}; +use format::{parse, Parsed, ParseResult, StrftimeItems}; + +/// The conversion result from the local time to the timezone-aware datetime types. +#[derive(Clone, PartialEq, Debug)] +pub enum LocalResult { + /// Given local time representation is invalid. + /// This can occur when, for example, the positive timezone transition. + None, + /// Given local time representation has a single unique result. + Single(T), + /// Given local time representation has multiple results and thus ambiguous. + /// This can occur when, for example, the negative timezone transition. + Ambiguous(T /*min*/, T /*max*/), +} + +impl LocalResult { + /// Returns `Some` only when the conversion result is unique, or `None` otherwise. + pub fn single(self) -> Option { + match self { LocalResult::Single(t) => Some(t), _ => None } + } + + /// Returns `Some` for the earliest possible conversion result, or `None` if none. + pub fn earliest(self) -> Option { + match self { LocalResult::Single(t) | LocalResult::Ambiguous(t,_) => Some(t), _ => None } + } + + /// Returns `Some` for the latest possible conversion result, or `None` if none. + pub fn latest(self) -> Option { + match self { LocalResult::Single(t) | LocalResult::Ambiguous(_,t) => Some(t), _ => None } + } + + /// Maps a `LocalResult` into `LocalResult` with given function. + pub fn map U>(self, mut f: F) -> LocalResult { + match self { + LocalResult::None => LocalResult::None, + LocalResult::Single(v) => LocalResult::Single(f(v)), + LocalResult::Ambiguous(min, max) => LocalResult::Ambiguous(f(min), f(max)), + } + } +} + +impl LocalResult> { + /// Makes a new `DateTime` from the current date and given `NaiveTime`. + /// The offset in the current date is preserved. + /// + /// Propagates any error. Ambiguous result would be discarded. + #[inline] + pub fn and_time(self, time: NaiveTime) -> LocalResult> { + match self { + LocalResult::Single(d) => d.and_time(time) + .map_or(LocalResult::None, LocalResult::Single), + _ => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the current date, hour, minute and second. + /// The offset in the current date is preserved. + /// + /// Propagates any error. Ambiguous result would be discarded. + #[inline] + pub fn and_hms_opt(self, hour: u32, min: u32, sec: u32) -> LocalResult> { + match self { + LocalResult::Single(d) => d.and_hms_opt(hour, min, sec) + .map_or(LocalResult::None, LocalResult::Single), + _ => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and millisecond. + /// The millisecond part can exceed 1,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Propagates any error. Ambiguous result would be discarded. + #[inline] + pub fn and_hms_milli_opt(self, hour: u32, min: u32, sec: u32, + milli: u32) -> LocalResult> { + match self { + LocalResult::Single(d) => d.and_hms_milli_opt(hour, min, sec, milli) + .map_or(LocalResult::None, LocalResult::Single), + _ => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and microsecond. + /// The microsecond part can exceed 1,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Propagates any error. Ambiguous result would be discarded. + #[inline] + pub fn and_hms_micro_opt(self, hour: u32, min: u32, sec: u32, + micro: u32) -> LocalResult> { + match self { + LocalResult::Single(d) => d.and_hms_micro_opt(hour, min, sec, micro) + .map_or(LocalResult::None, LocalResult::Single), + _ => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond. + /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second. + /// The offset in the current date is preserved. + /// + /// Propagates any error. Ambiguous result would be discarded. + #[inline] + pub fn and_hms_nano_opt(self, hour: u32, min: u32, sec: u32, + nano: u32) -> LocalResult> { + match self { + LocalResult::Single(d) => d.and_hms_nano_opt(hour, min, sec, nano) + .map_or(LocalResult::None, LocalResult::Single), + _ => LocalResult::None, + } + } + +} + +impl LocalResult { + /// Returns the single unique conversion result, or panics accordingly. + pub fn unwrap(self) -> T { + match self { + LocalResult::None => panic!("No such local time"), + LocalResult::Single(t) => t, + LocalResult::Ambiguous(t1,t2) => { + panic!("Ambiguous local time, ranging from {:?} to {:?}", t1, t2) + } + } + } +} + +/// The offset from the local time to UTC. +pub trait Offset: Sized + Clone + fmt::Debug { + /// Returns the fixed offset from UTC to the local time stored. + fn fix(&self) -> FixedOffset; +} + +/// The time zone. +/// +/// The methods here are the primarily constructors for [`Date`](../struct.Date.html) and +/// [`DateTime`](../struct.DateTime.html) types. +pub trait TimeZone: Sized + Clone { + /// An associated offset type. + /// This type is used to store the actual offset in date and time types. + /// The original `TimeZone` value can be recovered via `TimeZone::from_offset`. + type Offset: Offset; + + /// Makes a new `Date` from year, month, day and the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Panics on the out-of-range date, invalid month and/or day. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone}; + /// + /// assert_eq!(Utc.ymd(2015, 5, 15).to_string(), "2015-05-15UTC"); + /// ~~~~ + fn ymd(&self, year: i32, month: u32, day: u32) -> Date { + self.ymd_opt(year, month, day).unwrap() + } + + /// Makes a new `Date` from year, month, day and the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Returns `None` on the out-of-range date, invalid month and/or day. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, LocalResult, TimeZone}; + /// + /// assert_eq!(Utc.ymd_opt(2015, 5, 15).unwrap().to_string(), "2015-05-15UTC"); + /// assert_eq!(Utc.ymd_opt(2000, 0, 0), LocalResult::None); + /// ~~~~ + fn ymd_opt(&self, year: i32, month: u32, day: u32) -> LocalResult> { + match NaiveDate::from_ymd_opt(year, month, day) { + Some(d) => self.from_local_date(&d), + None => LocalResult::None, + } + } + + /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Panics on the out-of-range date and/or invalid DOY. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone}; + /// + /// assert_eq!(Utc.yo(2015, 135).to_string(), "2015-05-15UTC"); + /// ~~~~ + fn yo(&self, year: i32, ordinal: u32) -> Date { + self.yo_opt(year, ordinal).unwrap() + } + + /// Makes a new `Date` from year, day of year (DOY or "ordinal") and the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Returns `None` on the out-of-range date and/or invalid DOY. + fn yo_opt(&self, year: i32, ordinal: u32) -> LocalResult> { + match NaiveDate::from_yo_opt(year, ordinal) { + Some(d) => self.from_local_date(&d), + None => LocalResult::None, + } + } + + /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and + /// the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// The resulting `Date` may have a different year from the input year. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Panics on the out-of-range date and/or invalid week number. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, Weekday, TimeZone}; + /// + /// assert_eq!(Utc.isoywd(2015, 20, Weekday::Fri).to_string(), "2015-05-15UTC"); + /// ~~~~ + fn isoywd(&self, year: i32, week: u32, weekday: Weekday) -> Date { + self.isoywd_opt(year, week, weekday).unwrap() + } + + /// Makes a new `Date` from ISO week date (year and week number), day of the week (DOW) and + /// the current time zone. + /// This assumes the proleptic Gregorian calendar, with the year 0 being 1 BCE. + /// The resulting `Date` may have a different year from the input year. + /// + /// The time zone normally does not affect the date (unless it is between UTC-24 and UTC+24), + /// but it will propagate to the `DateTime` values constructed via this date. + /// + /// Returns `None` on the out-of-range date and/or invalid week number. + fn isoywd_opt(&self, year: i32, week: u32, weekday: Weekday) -> LocalResult> { + match NaiveDate::from_isoywd_opt(year, week, weekday) { + Some(d) => self.from_local_date(&d), + None => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the number of non-leap seconds + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") + /// and the number of nanoseconds since the last whole non-leap second. + /// + /// Panics on the out-of-range number of seconds and/or invalid nanosecond, + /// for a non-panicking version see [`timestamp_opt`](#method.timestamp_opt). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone}; + /// + /// assert_eq!(Utc.timestamp(1431648000, 0).to_string(), "2015-05-15 00:00:00 UTC"); + /// ~~~~ + fn timestamp(&self, secs: i64, nsecs: u32) -> DateTime { + self.timestamp_opt(secs, nsecs).unwrap() + } + + /// Makes a new `DateTime` from the number of non-leap seconds + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp") + /// and the number of nanoseconds since the last whole non-leap second. + /// + /// Returns `LocalResult::None` on out-of-range number of seconds and/or + /// invalid nanosecond, otherwise always returns `LocalResult::Single`. + fn timestamp_opt(&self, secs: i64, nsecs: u32) -> LocalResult> { + match NaiveDateTime::from_timestamp_opt(secs, nsecs) { + Some(dt) => LocalResult::Single(self.from_utc_datetime(&dt)), + None => LocalResult::None, + } + } + + /// Makes a new `DateTime` from the number of non-leap milliseconds + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). + /// + /// Panics on out-of-range number of milliseconds for a non-panicking + /// version see [`timestamp_millis_opt`](#method.timestamp_millis_opt). + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone}; + /// + /// assert_eq!(Utc.timestamp_millis(1431648000).timestamp(), 1431648); + /// ~~~~ + fn timestamp_millis(&self, millis: i64) -> DateTime { + self.timestamp_millis_opt(millis).unwrap() + } + + /// Makes a new `DateTime` from the number of non-leap milliseconds + /// since January 1, 1970 0:00:00 UTC (aka "UNIX timestamp"). + /// + /// + /// Returns `LocalResult::None` on out-of-range number of milliseconds + /// and/or invalid nanosecond, otherwise always returns + /// `LocalResult::Single`. + /// + /// # Example + /// + /// ~~~~ + /// use chrono::{Utc, TimeZone, LocalResult}; + /// match Utc.timestamp_millis_opt(1431648000) { + /// LocalResult::Single(dt) => assert_eq!(dt.timestamp(), 1431648), + /// _ => panic!("Incorrect timestamp_millis"), + /// }; + /// ~~~~ + fn timestamp_millis_opt(&self, millis: i64) -> LocalResult> { + let (secs, millis) = (millis / 1000, millis % 1000); + self.timestamp_opt(secs, millis as u32 * 1_000_000) + } + + /// Parses a string with the specified format string and + /// returns a `DateTime` with the current offset. + /// See the [`format::strftime` module](../format/strftime/index.html) + /// on the supported escape sequences. + /// + /// If the format does not include offsets, the current offset is assumed; + /// otherwise the input should have a matching UTC offset. + /// + /// See also `DateTime::parse_from_str` which gives a local `DateTime` + /// with parsed `FixedOffset`. + fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult> { + let mut parsed = Parsed::new(); + try!(parse(&mut parsed, s, StrftimeItems::new(fmt))); + parsed.to_datetime_with_timezone(self) + } + + /// Reconstructs the time zone from the offset. + fn from_offset(offset: &Self::Offset) -> Self; + + /// Creates the offset(s) for given local `NaiveDate` if possible. + fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult; + + /// Creates the offset(s) for given local `NaiveDateTime` if possible. + fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult; + + /// Converts the local `NaiveDate` to the timezone-aware `Date` if possible. + fn from_local_date(&self, local: &NaiveDate) -> LocalResult> { + self.offset_from_local_date(local).map(|offset| { + // since FixedOffset is within +/- 1 day, the date is never affected + Date::from_utc(*local, offset) + }) + } + + /// Converts the local `NaiveDateTime` to the timezone-aware `DateTime` if possible. + fn from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult> { + self.offset_from_local_datetime(local).map(|offset| { + DateTime::from_utc(*local - offset.fix(), offset) + }) + } + + /// Creates the offset for given UTC `NaiveDate`. This cannot fail. + fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset; + + /// Creates the offset for given UTC `NaiveDateTime`. This cannot fail. + fn offset_from_utc_datetime(&self, utc: &NaiveDateTime) -> Self::Offset; + + /// Converts the UTC `NaiveDate` to the local time. + /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). + fn from_utc_date(&self, utc: &NaiveDate) -> Date { + Date::from_utc(*utc, self.offset_from_utc_date(utc)) + } + + /// Converts the UTC `NaiveDateTime` to the local time. + /// The UTC is continuous and thus this cannot fail (but can give the duplicate local time). + fn from_utc_datetime(&self, utc: &NaiveDateTime) -> DateTime { + DateTime::from_utc(*utc, self.offset_from_utc_datetime(utc)) + } +} + +mod utc; +mod fixed; +#[cfg(feature="clock")] +mod local; + +pub use self::utc::Utc; +pub use self::fixed::FixedOffset; +#[cfg(feature="clock")] +pub use self::local::Local; diff --git a/chrono/src/offset/utc.rs b/chrono/src/offset/utc.rs new file mode 100644 index 000000000..d4e8d10b5 --- /dev/null +++ b/chrono/src/offset/utc.rs @@ -0,0 +1,75 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +//! The UTC (Coordinated Universal Time) time zone. + +use std::fmt; +#[cfg(feature="clock")] +use oldtime; + +use naive::{NaiveDate, NaiveDateTime}; +#[cfg(feature="clock")] +use {Date, DateTime}; +use super::{TimeZone, Offset, LocalResult, FixedOffset}; + +/// The UTC time zone. This is the most efficient time zone when you don't need the local time. +/// It is also used as an offset (which is also a dummy type). +/// +/// Using the [`TimeZone`](./trait.TimeZone.html) methods +/// on the UTC struct is the preferred way to construct `DateTime` +/// instances. +/// +/// # Example +/// +/// ~~~~ +/// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc}; +/// +/// let dt = DateTime::::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc); +/// +/// assert_eq!(Utc.timestamp(61, 0), dt); +/// assert_eq!(Utc.ymd(1970, 1, 1).and_hms(0, 1, 1), dt); +/// ~~~~ +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Utc; + +#[cfg(feature="clock")] +impl Utc { + /// Returns a `Date` which corresponds to the current date. + pub fn today() -> Date { Utc::now().date() } + + /// Returns a `DateTime` which corresponds to the current date. + pub fn now() -> DateTime { + let spec = oldtime::get_time(); + let naive = NaiveDateTime::from_timestamp(spec.sec, spec.nsec as u32); + DateTime::from_utc(naive, Utc) + } +} + +impl TimeZone for Utc { + type Offset = Utc; + + fn from_offset(_state: &Utc) -> Utc { Utc } + + fn offset_from_local_date(&self, _local: &NaiveDate) -> LocalResult { + LocalResult::Single(Utc) + } + fn offset_from_local_datetime(&self, _local: &NaiveDateTime) -> LocalResult { + LocalResult::Single(Utc) + } + + fn offset_from_utc_date(&self, _utc: &NaiveDate) -> Utc { Utc } + fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> Utc { Utc } +} + +impl Offset for Utc { + fn fix(&self) -> FixedOffset { FixedOffset::east(0) } +} + +impl fmt::Debug for Utc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Z") } +} + +impl fmt::Display for Utc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "UTC") } +} + diff --git a/chrono/src/oldtime.rs b/chrono/src/oldtime.rs new file mode 100644 index 000000000..2bdc2f64e --- /dev/null +++ b/chrono/src/oldtime.rs @@ -0,0 +1,640 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification + +use std::{fmt, i64}; +use std::error::Error; +use std::ops::{Add, Sub, Mul, Div, Neg}; +use std::time::Duration as StdDuration; + +/// The number of nanoseconds in a microsecond. +const NANOS_PER_MICRO: i32 = 1000; +/// The number of nanoseconds in a millisecond. +const NANOS_PER_MILLI: i32 = 1000_000; +/// The number of nanoseconds in seconds. +const NANOS_PER_SEC: i32 = 1_000_000_000; +/// The number of microseconds per second. +const MICROS_PER_SEC: i64 = 1000_000; +/// The number of milliseconds per second. +const MILLIS_PER_SEC: i64 = 1000; +/// The number of seconds in a minute. +const SECS_PER_MINUTE: i64 = 60; +/// The number of seconds in an hour. +const SECS_PER_HOUR: i64 = 3600; +/// The number of (non-leap) seconds in days. +const SECS_PER_DAY: i64 = 86400; +/// The number of (non-leap) seconds in a week. +const SECS_PER_WEEK: i64 = 604800; + +macro_rules! try_opt { + ($e:expr) => (match $e { Some(v) => v, None => return None }) +} + + +/// ISO 8601 time duration with nanosecond precision. +/// This also allows for the negative duration; see individual methods for details. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Duration { + secs: i64, + nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC +} + +/// The minimum possible `Duration`: `i64::MIN` milliseconds. +pub const MIN: Duration = Duration { + secs: i64::MIN / MILLIS_PER_SEC - 1, + nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +/// The maximum possible `Duration`: `i64::MAX` milliseconds. +pub const MAX: Duration = Duration { + secs: i64::MAX / MILLIS_PER_SEC, + nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +impl Duration { + /// Makes a new `Duration` with given number of weeks. + /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn weeks(weeks: i64) -> Duration { + let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn days(days: i64) -> Duration { + let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn hours(hours: i64) -> Duration { + let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn minutes(minutes: i64) -> Duration { + let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of seconds. + /// Panics when the duration is more than `i64::MAX` milliseconds + /// or less than `i64::MIN` milliseconds. + #[inline] + pub fn seconds(seconds: i64) -> Duration { + let d = Duration { secs: seconds, nanos: 0 }; + if d < MIN || d > MAX { + panic!("Duration::seconds out of bounds"); + } + d + } + + /// Makes a new `Duration` with given number of milliseconds. + #[inline] + pub fn milliseconds(milliseconds: i64) -> Duration { + let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); + let nanos = millis as i32 * NANOS_PER_MILLI; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of microseconds. + #[inline] + pub fn microseconds(microseconds: i64) -> Duration { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + let nanos = micros as i32 * NANOS_PER_MICRO; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of nanoseconds. + #[inline] + pub fn nanoseconds(nanos: i64) -> Duration { + let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); + Duration { secs: secs, nanos: nanos as i32 } + } + + /// Returns the total number of whole weeks in the duration. + #[inline] + pub fn num_weeks(&self) -> i64 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the duration. + pub fn num_days(&self) -> i64 { + self.num_seconds() / SECS_PER_DAY + } + + /// Returns the total number of whole hours in the duration. + #[inline] + pub fn num_hours(&self) -> i64 { + self.num_seconds() / SECS_PER_HOUR + } + + /// Returns the total number of whole minutes in the duration. + #[inline] + pub fn num_minutes(&self) -> i64 { + self.num_seconds() / SECS_PER_MINUTE + } + + /// Returns the total number of whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + // If secs is negative, nanos should be subtracted from the duration. + if self.secs < 0 && self.nanos > 0 { + self.secs + 1 + } else { + self.secs + } + } + + /// Returns the number of nanoseconds such that + /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of + /// nanoseconds in the duration. + fn nanos_mod_sec(&self) -> i32 { + if self.secs < 0 && self.nanos > 0 { + self.nanos - NANOS_PER_SEC + } else { + self.nanos + } + } + + /// Returns the total number of whole milliseconds in the duration, + pub fn num_milliseconds(&self) -> i64 { + // A proper Duration will not overflow, because MIN and MAX are defined + // such that the range is exactly i64 milliseconds. + let secs_part = self.num_seconds() * MILLIS_PER_SEC; + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI; + secs_part + nanos_part as i64 + } + + /// Returns the total number of whole microseconds in the duration, + /// or `None` on overflow (exceeding 2^63 microseconds in either direction). + pub fn num_microseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; + secs_part.checked_add(nanos_part as i64) + } + + /// Returns the total number of whole nanoseconds in the duration, + /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). + pub fn num_nanoseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); + let nanos_part = self.nanos_mod_sec(); + secs_part.checked_add(nanos_part as i64) + } + + /// Add two durations, returning `None` if overflow occurred. + pub fn checked_add(&self, rhs: &Duration) -> Option { + let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs = try_opt!(secs.checked_add(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// Subtract two durations, returning `None` if overflow occurred. + pub fn checked_sub(&self, rhs: &Duration) -> Option { + let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs = try_opt!(secs.checked_sub(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// The minimum possible `Duration`: `i64::MIN` milliseconds. + #[inline] + pub fn min_value() -> Duration { MIN } + + /// The maximum possible `Duration`: `i64::MAX` milliseconds. + #[inline] + pub fn max_value() -> Duration { MAX } + + /// A duration where the stored seconds and nanoseconds are equal to zero. + #[inline] + pub fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + + /// Returns `true` if the duration equals `Duration::zero()`. + #[inline] + pub fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } + + /// Creates a `time::Duration` object from `std::time::Duration` + /// + /// This function errors when original duration is larger than the maximum + /// value supported for this type. + pub fn from_std(duration: StdDuration) -> Result { + // We need to check secs as u64 before coercing to i64 + if duration.as_secs() > MAX.secs as u64 { + return Err(OutOfRangeError(())); + } + let d = Duration { + secs: duration.as_secs() as i64, + nanos: duration.subsec_nanos() as i32, + }; + if d > MAX { + return Err(OutOfRangeError(())); + } + Ok(d) + } + + /// Creates a `std::time::Duration` object from `time::Duration` + /// + /// This function errors when duration is less than zero. As standard + /// library implementation is limited to non-negative values. + pub fn to_std(&self) -> Result { + if self.secs < 0 { + return Err(OutOfRangeError(())); + } + Ok(StdDuration::new(self.secs as u64, self.nanos as u32)) + } +} + +impl Neg for Duration { + type Output = Duration; + + #[inline] + fn neg(self) -> Duration { + if self.nanos == 0 { + Duration { secs: -self.secs, nanos: 0 } + } else { + Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } + } + } +} + +impl Add for Duration { + type Output = Duration; + + fn add(self, rhs: Duration) -> Duration { + let mut secs = self.secs + rhs.secs; + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Sub for Duration { + type Output = Duration; + + fn sub(self, rhs: Duration) -> Duration { + let mut secs = self.secs - rhs.secs; + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Mul for Duration { + type Output = Duration; + + fn mul(self, rhs: i32) -> Duration { + // Multiply nanoseconds as i64, because it cannot overflow that way. + let total_nanos = self.nanos as i64 * rhs as i64; + let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); + let secs = self.secs * rhs as i64 + extra_secs; + Duration { secs: secs, nanos: nanos as i32 } + } +} + +impl Div for Duration { + type Output = Duration; + + fn div(self, rhs: i32) -> Duration { + let mut secs = self.secs / rhs as i64; + let carry = self.secs - secs * rhs as i64; + let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; + let mut nanos = self.nanos / rhs + extra_nanos as i32; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl fmt::Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // technically speaking, negative duration is not valid ISO 8601, + // but we need to print it anyway. + let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; + + let days = abs.secs / SECS_PER_DAY; + let secs = abs.secs - days * SECS_PER_DAY; + let hasdate = days != 0; + let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; + + try!(write!(f, "{}P", sign)); + + if hasdate { + try!(write!(f, "{}D", days)); + } + if hastime { + if abs.nanos == 0 { + try!(write!(f, "T{}S", secs)); + } else if abs.nanos % NANOS_PER_MILLI == 0 { + try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)); + } else if abs.nanos % NANOS_PER_MICRO == 0 { + try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)); + } else { + try!(write!(f, "T{}.{:09}S", secs, abs.nanos)); + } + } + Ok(()) + } +} + +/// Represents error when converting `Duration` to/from a standard library +/// implementation +/// +/// The `std::time::Duration` supports a range from zero to `u64::MAX` +/// *seconds*, while this module supports signed range of up to +/// `i64::MAX` of *milliseconds*. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutOfRangeError(()); + +impl fmt::Display for OutOfRangeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl Error for OutOfRangeError { + fn description(&self) -> &str { + "Source duration value is out of range for the target type" + } +} + +// Copied from libnum +#[inline] +fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { + (div_floor_64(this, other), mod_floor_64(this, other)) +} + +#[inline] +fn div_floor_64(this: i64, other: i64) -> i64 { + match div_rem_64(this, other) { + (d, r) if (r > 0 && other < 0) + || (r < 0 && other > 0) => d - 1, + (d, _) => d, + } +} + +#[inline] +fn mod_floor_64(this: i64, other: i64) -> i64 { + match this % other { + r if (r > 0 && other < 0) + || (r < 0 && other > 0) => r + other, + r => r, + } +} + +#[inline] +fn div_rem_64(this: i64, other: i64) -> (i64, i64) { + (this / other, this % other) +} + +#[cfg(test)] +mod tests { + use super::{Duration, MIN, MAX, OutOfRangeError}; + use std::{i32, i64}; + use std::time::Duration as StdDuration; + + #[test] + fn test_duration() { + assert!(Duration::seconds(1) != Duration::zero()); + assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); + assert_eq!(Duration::seconds(86399) + Duration::seconds(4), + Duration::days(1) + Duration::seconds(3)); + assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); + assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); + assert_eq!(Duration::days(2) + Duration::seconds(86399) + + Duration::nanoseconds(1234567890), + Duration::days(3) + Duration::nanoseconds(234567890)); + assert_eq!(-Duration::days(3), Duration::days(-3)); + assert_eq!(-(Duration::days(3) + Duration::seconds(70)), + Duration::days(-4) + Duration::seconds(86400-70)); + } + + #[test] + fn test_duration_num_days() { + assert_eq!(Duration::zero().num_days(), 0); + assert_eq!(Duration::days(1).num_days(), 1); + assert_eq!(Duration::days(-1).num_days(), -1); + assert_eq!(Duration::seconds(86399).num_days(), 0); + assert_eq!(Duration::seconds(86401).num_days(), 1); + assert_eq!(Duration::seconds(-86399).num_days(), 0); + assert_eq!(Duration::seconds(-86401).num_days(), -1); + assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); + assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); + } + + #[test] + fn test_duration_num_seconds() { + assert_eq!(Duration::zero().num_seconds(), 0); + assert_eq!(Duration::seconds(1).num_seconds(), 1); + assert_eq!(Duration::seconds(-1).num_seconds(), -1); + assert_eq!(Duration::milliseconds(999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); + assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); + } + + #[test] + fn test_duration_num_milliseconds() { + assert_eq!(Duration::zero().num_milliseconds(), 0); + assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); + assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); + assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); + assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); + assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); + assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); + assert_eq!(MAX.num_milliseconds(), i64::MAX); + assert_eq!(MIN.num_milliseconds(), i64::MIN); + } + + #[test] + fn test_duration_num_microseconds() { + assert_eq!(Duration::zero().num_microseconds(), Some(0)); + assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); + assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); + assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); + assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MIN.num_microseconds(), None); + + // overflow checks + const MICROS_PER_DAY: i64 = 86400_000_000; + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), + Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(), + Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None); + } + + #[test] + fn test_duration_num_nanoseconds() { + assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); + assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_nanoseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); + + // overflow checks + const NANOS_PER_DAY: i64 = 86400_000_000_000; + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); + } + + #[test] + fn test_duration_checked_ops() { + assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), + Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999))); + assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000)) + .is_none()); + + assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), + Some(Duration::milliseconds(i64::MIN))); + assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)) + .is_none()); + } + + #[test] + fn test_duration_mul() { + assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); + assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); + assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(30) * 333_333_333, + Duration::seconds(10) - Duration::nanoseconds(10)); + assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, + Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3)); + assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); + assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); + } + + #[test] + fn test_duration_div() { + assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); + assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); + assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); + assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); + assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); + } + + #[test] + fn test_duration_fmt() { + assert_eq!(Duration::zero().to_string(), "PT0S"); + assert_eq!(Duration::days(42).to_string(), "P42D"); + assert_eq!(Duration::days(-42).to_string(), "-P42D"); + assert_eq!(Duration::seconds(42).to_string(), "PT42S"); + assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S"); + assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S"); + assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S"); + assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), + "P7DT6.543S"); + assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S"); + assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S"); + + // the format specifier should have no effect on `Duration` + assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), + "P1DT2.345S"); + } + + #[test] + fn test_to_std() { + assert_eq!(Duration::seconds(1).to_std(), Ok(StdDuration::new(1, 0))); + assert_eq!(Duration::seconds(86401).to_std(), Ok(StdDuration::new(86401, 0))); + assert_eq!(Duration::milliseconds(123).to_std(), Ok(StdDuration::new(0, 123000000))); + assert_eq!(Duration::milliseconds(123765).to_std(), Ok(StdDuration::new(123, 765000000))); + assert_eq!(Duration::nanoseconds(777).to_std(), Ok(StdDuration::new(0, 777))); + assert_eq!(MAX.to_std(), Ok(StdDuration::new(9223372036854775, 807000000))); + assert_eq!(Duration::seconds(-1).to_std(), + Err(OutOfRangeError(()))); + assert_eq!(Duration::milliseconds(-1).to_std(), + Err(OutOfRangeError(()))); + } + + #[test] + fn test_from_std() { + assert_eq!(Ok(Duration::seconds(1)), + Duration::from_std(StdDuration::new(1, 0))); + assert_eq!(Ok(Duration::seconds(86401)), + Duration::from_std(StdDuration::new(86401, 0))); + assert_eq!(Ok(Duration::milliseconds(123)), + Duration::from_std(StdDuration::new(0, 123000000))); + assert_eq!(Ok(Duration::milliseconds(123765)), + Duration::from_std(StdDuration::new(123, 765000000))); + assert_eq!(Ok(Duration::nanoseconds(777)), + Duration::from_std(StdDuration::new(0, 777))); + assert_eq!(Ok(MAX), + Duration::from_std(StdDuration::new(9223372036854775, 807000000))); + assert_eq!(Duration::from_std(StdDuration::new(9223372036854776, 0)), + Err(OutOfRangeError(()))); + assert_eq!(Duration::from_std(StdDuration::new(9223372036854775, 807000001)), + Err(OutOfRangeError(()))); + } +} diff --git a/chrono/src/round.rs b/chrono/src/round.rs new file mode 100644 index 000000000..bf6276216 --- /dev/null +++ b/chrono/src/round.rs @@ -0,0 +1,178 @@ +// This is a part of Chrono. +// See README.md and LICENSE.txt for details. + +use Timelike; +use std::ops::{Add, Sub}; +use oldtime::Duration; + +/// Extension trait for subsecond rounding or truncation to a maximum number +/// of digits. Rounding can be used to decrease the error variance when +/// serializing/persisting to lower precision. Truncation is the default +/// behavior in Chrono display formatting. Either can be used to guarantee +/// equality (e.g. for testing) when round-tripping through a lower precision +/// format. +pub trait SubsecRound { + /// Return a copy rounded to the specified number of subsecond digits. With + /// 9 or more digits, self is returned unmodified. Halfway values are + /// rounded up (away from zero). + /// + /// # Example + /// ``` rust + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; + /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// assert_eq!(dt.round_subsecs(2).nanosecond(), 150_000_000); + /// assert_eq!(dt.round_subsecs(1).nanosecond(), 200_000_000); + /// ``` + fn round_subsecs(self, digits: u16) -> Self; + + /// Return a copy truncated to the specified number of subsecond + /// digits. With 9 or more digits, self is returned unmodified. + /// + /// # Example + /// ``` rust + /// # use chrono::{DateTime, SubsecRound, Timelike, TimeZone, Utc}; + /// let dt = Utc.ymd(2018, 1, 11).and_hms_milli(12, 0, 0, 154); + /// assert_eq!(dt.trunc_subsecs(2).nanosecond(), 150_000_000); + /// assert_eq!(dt.trunc_subsecs(1).nanosecond(), 100_000_000); + /// ``` + fn trunc_subsecs(self, digits: u16) -> Self; +} + +impl SubsecRound for T +where T: Timelike + Add + Sub +{ + fn round_subsecs(self, digits: u16) -> T { + let span = span_for_digits(digits); + let delta_down = self.nanosecond() % span; + if delta_down > 0 { + let delta_up = span - delta_down; + if delta_up <= delta_down { + self + Duration::nanoseconds(delta_up.into()) + } else { + self - Duration::nanoseconds(delta_down.into()) + } + } else { + self // unchanged + } + } + + fn trunc_subsecs(self, digits: u16) -> T { + let span = span_for_digits(digits); + let delta_down = self.nanosecond() % span; + if delta_down > 0 { + self - Duration::nanoseconds(delta_down.into()) + } else { + self // unchanged + } + } +} + +// Return the maximum span in nanoseconds for the target number of digits. +fn span_for_digits(digits: u16) -> u32 { + // fast lookup form of: 10^(9-min(9,digits)) + match digits { + 0 => 1_000_000_000, + 1 => 100_000_000, + 2 => 10_000_000, + 3 => 1_000_000, + 4 => 100_000, + 5 => 10_000, + 6 => 1_000, + 7 => 100, + 8 => 10, + _ => 1 + } +} + +#[cfg(test)] +mod tests { + use Timelike; + use offset::{FixedOffset, TimeZone, Utc}; + use super::SubsecRound; + + #[test] + fn test_round() { + let pst = FixedOffset::east(8 * 60 * 60); + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684); + + assert_eq!(dt.round_subsecs(10), dt); + assert_eq!(dt.round_subsecs(9), dt); + assert_eq!(dt.round_subsecs(8).nanosecond(), 084_660_680); + assert_eq!(dt.round_subsecs(7).nanosecond(), 084_660_700); + assert_eq!(dt.round_subsecs(6).nanosecond(), 084_661_000); + assert_eq!(dt.round_subsecs(5).nanosecond(), 084_660_000); + assert_eq!(dt.round_subsecs(4).nanosecond(), 084_700_000); + assert_eq!(dt.round_subsecs(3).nanosecond(), 085_000_000); + assert_eq!(dt.round_subsecs(2).nanosecond(), 080_000_000); + assert_eq!(dt.round_subsecs(1).nanosecond(), 100_000_000); + + assert_eq!(dt.round_subsecs(0).nanosecond(), 0); + assert_eq!(dt.round_subsecs(0).second(), 13); + + let dt = Utc.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + assert_eq!(dt.round_subsecs(9), dt); + assert_eq!(dt.round_subsecs(4), dt); + assert_eq!(dt.round_subsecs(3).nanosecond(), 751_000_000); + assert_eq!(dt.round_subsecs(2).nanosecond(), 750_000_000); + assert_eq!(dt.round_subsecs(1).nanosecond(), 800_000_000); + + assert_eq!(dt.round_subsecs(0).nanosecond(), 0); + assert_eq!(dt.round_subsecs(0).second(), 28); + } + + #[test] + fn test_round_leap_nanos() { + let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + assert_eq!(dt.round_subsecs(9), dt); + assert_eq!(dt.round_subsecs(4), dt); + assert_eq!(dt.round_subsecs(2).nanosecond(), 1_750_000_000); + assert_eq!(dt.round_subsecs(1).nanosecond(), 1_800_000_000); + assert_eq!(dt.round_subsecs(1).second(), 59); + + assert_eq!(dt.round_subsecs(0).nanosecond(), 0); + assert_eq!(dt.round_subsecs(0).second(), 0); + } + + #[test] + fn test_trunc() { + let pst = FixedOffset::east(8 * 60 * 60); + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_684); + + assert_eq!(dt.trunc_subsecs(10), dt); + assert_eq!(dt.trunc_subsecs(9), dt); + assert_eq!(dt.trunc_subsecs(8).nanosecond(), 084_660_680); + assert_eq!(dt.trunc_subsecs(7).nanosecond(), 084_660_600); + assert_eq!(dt.trunc_subsecs(6).nanosecond(), 084_660_000); + assert_eq!(dt.trunc_subsecs(5).nanosecond(), 084_660_000); + assert_eq!(dt.trunc_subsecs(4).nanosecond(), 084_600_000); + assert_eq!(dt.trunc_subsecs(3).nanosecond(), 084_000_000); + assert_eq!(dt.trunc_subsecs(2).nanosecond(), 080_000_000); + assert_eq!(dt.trunc_subsecs(1).nanosecond(), 0); + + assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); + assert_eq!(dt.trunc_subsecs(0).second(), 13); + + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 27, 750_500_000); + assert_eq!(dt.trunc_subsecs(9), dt); + assert_eq!(dt.trunc_subsecs(4), dt); + assert_eq!(dt.trunc_subsecs(3).nanosecond(), 750_000_000); + assert_eq!(dt.trunc_subsecs(2).nanosecond(), 750_000_000); + assert_eq!(dt.trunc_subsecs(1).nanosecond(), 700_000_000); + + assert_eq!(dt.trunc_subsecs(0).nanosecond(), 0); + assert_eq!(dt.trunc_subsecs(0).second(), 27); + } + + #[test] + fn test_trunc_leap_nanos() { + let dt = Utc.ymd(2016, 12, 31).and_hms_nano(23, 59, 59, 1_750_500_000); + assert_eq!(dt.trunc_subsecs(9), dt); + assert_eq!(dt.trunc_subsecs(4), dt); + assert_eq!(dt.trunc_subsecs(2).nanosecond(), 1_750_000_000); + assert_eq!(dt.trunc_subsecs(1).nanosecond(), 1_700_000_000); + assert_eq!(dt.trunc_subsecs(1).second(), 59); + + assert_eq!(dt.trunc_subsecs(0).nanosecond(), 1_000_000_000); + assert_eq!(dt.trunc_subsecs(0).second(), 59); + } +} diff --git a/clap/.cargo-checksum.json b/clap/.cargo-checksum.json new file mode 100644 index 000000000..902a5a0d5 --- /dev/null +++ b/clap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"} \ No newline at end of file diff --git a/clap/.pc/.quilt_patches b/clap/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/clap/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/clap/.pc/.quilt_series b/clap/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/clap/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/clap/.pc/.version b/clap/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/clap/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/clap/.pc/applied-patches b/clap/.pc/applied-patches new file mode 100644 index 000000000..9d44adc3b --- /dev/null +++ b/clap/.pc/applied-patches @@ -0,0 +1,2 @@ +no-clippy.patch +relax-dep-versions.patch diff --git a/clap/.pc/no-clippy.patch/.timestamp b/clap/.pc/no-clippy.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/clap/.pc/no-clippy.patch/Cargo.toml b/clap/.pc/no-clippy.patch/Cargo.toml new file mode 100644 index 000000000..c76ceb42b --- /dev/null +++ b/clap/.pc/no-clippy.patch/Cargo.toml @@ -0,0 +1,132 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "clap" +version = "2.33.0" +authors = ["Kevin K. "] +exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] +description = "A simple to use, efficient, and full-featured Command Line Argument Parser\n" +homepage = "https://clap.rs/" +documentation = "https://docs.rs/clap/" +readme = "README.md" +keywords = ["argument", "cli", "arg", "parser", "parse"] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/clap-rs/clap" +[package.metadata.docs.rs] +features = ["doc"] +[profile.test] +opt-level = 1 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.bench] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false + +[profile.dev] +opt-level = 0 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false +[dependencies.atty] +version = "0.2.2" +optional = true + +[dependencies.bitflags] +version = "1.0" + +[dependencies.clippy] +version = "~0.0.166" +optional = true + +[dependencies.strsim] +version = "0.8" +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.textwrap] +version = "0.11.0" + +[dependencies.unicode-width] +version = "0.1.4" + +[dependencies.vec_map] +version = "0.8" +optional = true + +[dependencies.yaml-rust] +version = "0.3.5" +optional = true +[dev-dependencies.lazy_static] +version = "1.3" + +[dev-dependencies.regex] +version = "1" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +color = ["ansi_term", "atty"] +debug = [] +default = ["suggestions", "color", "vec_map"] +doc = ["yaml"] +lints = ["clippy"] +nightly = [] +no_cargo = [] +suggestions = ["strsim"] +unstable = [] +wrap_help = ["term_size", "textwrap/term_size"] +yaml = ["yaml-rust"] +[target."cfg(not(windows))".dependencies.ansi_term] +version = "0.11" +optional = true +[badges.appveyor] +repository = "clap-rs/clap" + +[badges.coveralls] +branch = "master" +repository = "clap-rs/clap" + +[badges.is-it-maintained-issue-resolution] +repository = "clap-rs/clap" + +[badges.is-it-maintained-open-issues] +repository = "clap-rs/clap" + +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "clap-rs/clap" diff --git a/clap/.pc/relax-dep-versions.patch/.timestamp b/clap/.pc/relax-dep-versions.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/clap/.pc/relax-dep-versions.patch/Cargo.toml b/clap/.pc/relax-dep-versions.patch/Cargo.toml new file mode 100644 index 000000000..e1a45bf1e --- /dev/null +++ b/clap/.pc/relax-dep-versions.patch/Cargo.toml @@ -0,0 +1,127 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "clap" +version = "2.33.0" +authors = ["Kevin K. "] +exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] +description = "A simple to use, efficient, and full-featured Command Line Argument Parser\n" +homepage = "https://clap.rs/" +documentation = "https://docs.rs/clap/" +readme = "README.md" +keywords = ["argument", "cli", "arg", "parser", "parse"] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/clap-rs/clap" +[package.metadata.docs.rs] +features = ["doc"] +[profile.test] +opt-level = 1 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.bench] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false + +[profile.dev] +opt-level = 0 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false +[dependencies.atty] +version = "0.2.2" +optional = true + +[dependencies.bitflags] +version = "1.0" + +[dependencies.strsim] +version = "0.8" +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.textwrap] +version = "0.11.0" + +[dependencies.unicode-width] +version = "0.1.4" + +[dependencies.vec_map] +version = "0.8" +optional = true + +[dependencies.yaml-rust] +version = "0.3.5" +optional = true +[dev-dependencies.lazy_static] +version = "1.3" + +[dev-dependencies.regex] +version = "1" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +color = ["ansi_term", "atty"] +debug = [] +default = ["suggestions", "color", "vec_map"] +doc = ["yaml"] +nightly = [] +no_cargo = [] +suggestions = ["strsim"] +unstable = [] +wrap_help = ["term_size", "textwrap/term_size"] +yaml = ["yaml-rust"] +[target."cfg(not(windows))".dependencies.ansi_term] +version = "0.11" +optional = true +[badges.appveyor] +repository = "clap-rs/clap" + +[badges.coveralls] +branch = "master" +repository = "clap-rs/clap" + +[badges.is-it-maintained-issue-resolution] +repository = "clap-rs/clap" + +[badges.is-it-maintained-open-issues] +repository = "clap-rs/clap" + +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "clap-rs/clap" diff --git a/clap/CHANGELOG.md b/clap/CHANGELOG.md new file mode 100644 index 000000000..d1fdd401a --- /dev/null +++ b/clap/CHANGELOG.md @@ -0,0 +1,2855 @@ + +## v2.33.0 (2019-04-06) + +#### New Sponsor + +* Stephen Oats is now a sponsor \o/ ([823457c0](https://github.com/kbknapp/clap-rs/commit/823457c0ef5e994ed7080cf62addbfe1aa3b1833)) +* **SPONSORS.md:** fixes Josh Triplett's info in the sponsor document ([24cb5740](https://github.com/kbknapp/clap-rs/commit/24cb574090a11159b48bba105d5ec2dfb0a20e4e)) + +#### Features + +* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9)) +* There is a new setting to disable automatic building of `--help` and `-h` flags (`AppSettings::DisableAutoHelp`) + +#### Improvements + +* **arg_matches.rs:** add Debug implementations ([47192b7a](https://github.com/kbknapp/clap-rs/commit/47192b7a2d84ec716b81ae4af621e008a8762dc9)) +* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559)) + +#### Documentation + +* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c)) +* **README.md:** use https for all links ([96a7639a](https://github.com/kbknapp/clap-rs/commit/96a7639a36bcb184c3f45348986883115ef1ab3a)) + +#### Bug Fixes + +* add debug assertion for missing args in subcommand ArgGroup ([2699d9e5](https://github.com/kbknapp/clap-rs/commit/2699d9e51e7eadc258ba64c4e347c5d1fef61343)) +* Restore compat with Rust 1.21 ([6b263de1](https://github.com/kbknapp/clap-rs/commit/6b263de1d42ede692ec5ee55019ad2fc6386f92e)) +* Dont mention unused subcommands ([ef92e2b6](https://github.com/kbknapp/clap-rs/commit/ef92e2b639ed305bdade4741f60fa85cb0101c5a)) +* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4)) +* **arg_enum!:** + * Fix comma position for valid values. ([1f1f9ff3](https://github.com/kbknapp/clap-rs/commit/1f1f9ff3fa38a43231ef8be9cfea89a32e53f518)) + * Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862)) +* **completions:** improve correctness of completions when whitespace is involved ([5a08ff29](https://github.com/kbknapp/clap-rs/commit/5a08ff295b2aa6ce29420df6252a0e3ff4441bdc)) +* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897)) +* **macros:** fixes broken pattern which prevented calling multi-argument Arg methods ([9e7a352e](https://github.com/kbknapp/clap-rs/commit/9e7a352e13aaf8025d80f2bac5c47fb32528672b)) +* **parser:** Better interaction between AllowExternalSubcommands and SubcommandRequired ([9601c95a](https://github.com/kbknapp/clap-rs/commit/9601c95a03d2b82bf265c328b4769238f1b79002)) + +#### Minimum Required Rust + +* As of this release, `clap` requires `rustc 1.31.0` or greater. + + +## v2.32.0 (2018-06-26) + +#### Minimum Required Rust + +* As of this release, `clap` requires `rustc 1.21.0` or greater. + + +#### Features + +* **Completions:** adds completion support for Elvish. ([e9d0562a](https://github.com/kbknapp/clap-rs/commit/e9d0562a1dc5dfe731ed7c767e6cee0af08f0cf9)) + +#### Improvements + +* **macros:** Support shorthand syntax for ArgGroups ([df9095e7](https://github.com/kbknapp/clap-rs/commit/df9095e75bb1e7896415251d0d4ffd8a0ebcd559)) + +#### Bug Fixes + +* **OsValues:** Add `ExactSizeIterator` implementation ([356c69e5](https://github.com/kbknapp/clap-rs/commit/356c69e508fd25a9f0ea2d27bf80ae1d9a8d88f4)) +* **arg_enum!:** Invalid expansions of some trailing-comma patterns ([7023184f](https://github.com/kbknapp/clap-rs/commit/7023184fca04e852c270341548d6a16207d13862)) +* **help message:** Unconditionally uses long description for subcommands ([6acc8b6a](https://github.com/kbknapp/clap-rs/commit/6acc8b6a621a765cbf513450188000d943676a30), closes [#897](https://github.com/kbknapp/clap-rs/issues/897)) + +#### Documentation + +* Refer to macOS rather than OSX. ([ab0d767f](https://github.com/kbknapp/clap-rs/commit/ab0d767f3a5a57e2bbb97d0183c2ef63c8c77a6c)) + + + + +### v2.31.2 (2018-03-19) + +#### Bug Fixes + +* **Fish Completions:** fixes a bug that only allowed a single completion in in Fish Shell ([e8774a8](https://github.com/kbknapp/clap-rs/pull/1214/commits/e8774a84ee4a319c888036e7c595ab46451d8e48), closes [#1212](https://github.com/kbknapp/clap-rs/issues/1212)) +* **AllowExternalSubcommands**: fixes a bug where external subcommands would be blocked by a similarly named subcommand (suggestions were getting in the way). ([a410e85](https://github.com/kbknapp/clap-rs/pull/1215/commits/a410e855bcd82b05f9efa73fa8b9774dc8842c6b)) + +#### Documentation + +* Fixes some typos in the `README.md` ([c8e685d7](https://github.com/kbknapp/clap-rs/commit/c8e685d76adee2a3cc06cac6952ffcf6f9548089)) + + +### v2.31.1 (2018-03-06) + + +#### Improvements + +* **AllowMissingPositional:** improves the ability of AllowMissingPositional to allow 'skipping' to the last positional arg with '--' ([df20e6e2](https://github.com/kbknapp/clap-rs/commit/df20e6e24b4e782be0b423b484b9798e3e2efe2f)) + + + +## v2.31.0 (2018-03-04) + + +#### Features + +* **Arg Indices:** adds the ability to query argument value indices ([f58d0576](https://github.com/kbknapp/clap-rs/commit/f58d05767ec8133c8eb2de117cb642b9ae29ccbc)) +* **Indices:** implements an Indices iterator ([1e67be44](https://github.com/kbknapp/clap-rs/commit/1e67be44f0ccf161cc84c4e6082382072e89c302)) +* **Raw Args** adds a convenience function to `Arg` that allows implying all of `Arg::last` `Arg::allow_hyphen_values` and `Arg::multiple(true)` ([66a78f29](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) + +#### Documentation + +* Fix some typos and markdown issues. ([935ba0dd](https://github.com/kbknapp/clap-rs/commit/935ba0dd547a69c3f636c5486795012019408794)) +* **Arg Indices:** adds the documentation for the arg index querying methods ([50bc0047](https://github.com/kbknapp/clap-rs/commit/50bc00477afa64dc6cdc5de161d3de3ba1d105a7)) +* **CONTRIBUTING.md:** fix url to clippy upstream repo to point to https://github.com/rust-lang-nursery/rust-clippy instead of https://github.com/Manishearth/rust-clippy ([42407d7f](https://github.com/kbknapp/clap-rs/commit/42407d7f21d794103cda61f49d2615aae0a4bcd9)) +* **Values:** improves the docs example of the Values iterator ([74075d65](https://github.com/kbknapp/clap-rs/commit/74075d65e8db1ddb5e2a4558009a5729d749d1b6)) +* Updates readme to hint that the `wrap_help` feature is a thing ([fc7ab227](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) + +### Improvements + +* Cargo.toml: use codegen-units = 1 in release and bench profiles ([19f425ea](https://github.com/kbknapp/clap-rs/commit/66a78f2972786f5fe7c07937a1ac23da2542afd2)) +* Adds WASM support (clap now compiles on WASM!) ([689949e5](https://github.com/kbknapp/clap-rs/commit/689949e57d390bb61bc69f3ed91f60a2105738d0)) +* Uses the short help tool-tip for PowerShell completion scripts ([ecda22ce](https://github.com/kbknapp/clap-rs/commit/ecda22ce7210ce56d7b2d1a5445dd1b8a2959656)) + + + +## v2.30.0 (2018-02-13) + +#### Bug Fixes + +* **YAML:** Adds a missing conversion from `Arg::last` when instantiating from a YAML file ([aab77c81a5](https://github.com/kbknapp/clap-rs/pull/1175/commits/aab77c81a519b045f95946ae0dd3e850f9b93070), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1173)) + +#### Improvements + +* **Bash Completions:** instead of completing a generic option name, all bash completions fall back to file completions UNLESS `Arg::possible_values` was used ([872f02ae](https://github.com/kbknapp/clap-rs/commit/872f02aea900ffa376850a279eb164645e1234fa)) +* **Deps:** No longer needlessly compiles `ansi_term` on Windows since its not used ([b57ee946](https://github.com/kbknapp/clap-rs/commit/b57ee94609da3ddc897286cfba968f26ff961491), closes [#1155](https://github.com/kbknapp/clap-rs/issues/1155)) +* **Help Message:** changes the `[values: foo bar baz]` array to `[possible values: foo bar baz]` for consistency with the API ([414707e4e97](https://github.com/kbknapp/clap-rs/pull/1176/commits/414707e4e979d07bfe555247e5d130c546673708), closes [#1160](https://github.com/kbknapp/clap-rs/issues/1160)) + + + +### v2.29.4 (2018-02-06) + + +#### Bug Fixes + +* **Overrides Self:** fixes a bug where options with multiple values couldnt ever have multiple values ([d95907cf](https://github.com/kbknapp/clap-rs/commit/d95907cff6d011a901fe35fa00b0f4e18547a1fb)) + + + + +### v2.29.3 (2018-02-05) + + +#### Improvements + +* **Overrides:** clap now supports arguments which override with themselves ([6c7a0010](https://github.com/kbknapp/clap-rs/commit/6c7a001023ca1eac1cc6ffe6c936b4c4a2aa3c45), closes [#976](https://github.com/kbknapp/clap-rs/issues/976)) + +#### Bug Fixes + +* **Requirements:** fixes an issue where conflicting args would still show up as required ([e06cefac](https://github.com/kbknapp/clap-rs/commit/e06cefac97083838c0a4e1444dcad02a5c3f911e), closes [#1158](https://github.com/kbknapp/clap-rs/issues/1158)) +* Fixes a bug which disallows proper nesting of `--` ([73993fe](https://github.com/kbknapp/clap-rs/commit/73993fe30d135f682e763ec93dcb0814ed518011), closes [#1161](https://github.com/kbknapp/clap-rs/issues/1161)) + +#### New Settings + +* **AllArgsOverrideSelf:** adds a new convenience setting to allow all args to override themselves ([4670325d](https://github.com/kbknapp/clap-rs/commit/4670325d1bf0369addec2ae2bcb56f1be054c924)) + + + + +### v2.29.2 (2018-01-16) + + +#### Features + +* **completions/zsh.rs:** + * Escape possible values for options ([25561dec](https://github.com/kbknapp/clap-rs/commit/25561decf147d329b64634a14d9695673c2fc78f)) + * Implement postional argument possible values completion ([f3b0afd2](https://github.com/kbknapp/clap-rs/commit/f3b0afd2bef8b7be97162f8a7802ddf7603dff36)) + * Complete positional arguments properly ([e39aeab8](https://github.com/kbknapp/clap-rs/commit/e39aeab8487596046fbdbc6a226e5c8820585245)) + +#### Bug Fixes + +* **completions/zsh.rs:** + * Add missing autoload for is-at-least ([a6522607](https://github.com/kbknapp/clap-rs/commit/a652260795d1519f6ec2a7a09ccc1258499cad7b)) + * Don't pass -S to _arguments if Zsh is too old ([16b4f143](https://github.com/kbknapp/clap-rs/commit/16b4f143ff466b7ef18a267bc44ade0f9639109b)) + * Maybe fix completions with mixed positionals and subcommands ([1146f0da](https://github.com/kbknapp/clap-rs/commit/1146f0da154d6796fbfcb09db8efa3593cb0d898)) +* **completions/zsh.zsh:** Remove redundant code from output ([0e185b92](https://github.com/kbknapp/clap-rs/commit/0e185b922ed1e0fd653de00b4cd8d567d72ff68e), closes [#1142](https://github.com/kbknapp/clap-rs/issues/1142)) + + + + +### 2.29.1 (2018-01-09) + + +#### Documentation + +* fixes broken links. ([56e734b8](https://github.com/kbknapp/clap-rs/commit/56e734b839303d733d2e5baf7dac39bd7b97b8e4)) +* updates contributors list ([e1313a5a](https://github.com/kbknapp/clap-rs/commit/e1313a5a0f69d8f4016f73b860a63af8318a6676)) + +#### Performance + +* further debloating by removing generics from error cases ([eb8d919e](https://github.com/kbknapp/clap-rs/commit/eb8d919e6f3443db279ba0c902f15d76676c02dc)) +* debloats clap by deduplicating logic and refactors ([03e413d7](https://github.com/kbknapp/clap-rs/commit/03e413d7175d35827cd7d8908d47dbae15a849a3)) + +#### Bug Fixes + +* fixes the ripgrep benchmark by adding a value to a flag that expects it ([d26ab2b9](https://github.com/kbknapp/clap-rs/commit/d26ab2b97cf9c0ea675b440b7b0eaf6ac3ad01f4)) +* **bash completion:** Change the bash completion script code generation to support hyphens. ([ba7f1d18](https://github.com/kbknapp/clap-rs/commit/ba7f1d18eba7a07ce7f57e0981986f66c994b639)) +* **completions/zsh.rs:** Fix completion of long option values ([46365cf8](https://github.com/kbknapp/clap-rs/commit/46365cf8be5331ba04c895eb183e2f230b5aad51)) + + + +## 2.29.0 (2017-12-02) + + +#### API Additions + +* **Arg:** adds Arg::hide_env_values(bool) which allows one to hide any current env values and display only the key in help messages ([fb41d062](https://github.com/kbknapp/clap-rs/commit/fb41d062eedf37cb4f805c90adca29909bd197d7)) + + + + +## 2.28.0 (2017-11-28) + +The minimum required Rust is now 1.20. This was done to start using bitflags 1.0 and having >1.0 deps is a *very good* thing! + +#### Documentation + +* changes the demo version to 2.28 to stay in sync ([ce6ca492](https://github.com/kbknapp/clap-rs/commit/ce6ca492c7510ab6474075806360b96081b021a9)) +* Fix URL path to github hosted files ([ce72aada](https://github.com/kbknapp/clap-rs/commit/ce72aada56a9581d4a6cb4bf9bdb861c3906f8df), closes [#1106](https://github.com/kbknapp/clap-rs/issues/1106)) +* fix typo ([002b07fc](https://github.com/kbknapp/clap-rs/commit/002b07fc98a1c85acb66296b1eec0b2aba906125)) +* **README.md:** updates the readme and pulls out some redundant sections ([db6caf86](https://github.com/kbknapp/clap-rs/commit/db6caf8663747e679d2f4ed3bd127f33476754aa)) + +#### Improvements + +* adds '[SUBCOMMAND]' to usage strings with only AppSettings::AllowExternalSubcommands is used with no other subcommands ([e78bb757](https://github.com/kbknapp/clap-rs/commit/e78bb757a3df16e82d539e450c06767a6bfcf859), closes [#1093](https://github.com/kbknapp/clap-rs/issues/1093)) + +#### API Additions + +* Adds Arg::case_insensitive(bool) which allows matching Arg::possible_values without worrying about ASCII case ([1fec268e](https://github.com/kbknapp/clap-rs/commit/1fec268e51736602e38e67c76266f439e2e0ef12), closes [#1118](https://github.com/kbknapp/clap-rs/issues/1118)) +* Adds the traits to be used with the clap-derive crate to be able to use Custom Derive ([6f4c3412](https://github.com/kbknapp/clap-rs/commit/6f4c3412415e882f5ca2cc3fbd6d4dce79440828)) + +#### Bug Fixes + +* Fixes a regression where --help couldn't be overridden ([a283d69f](https://github.com/kbknapp/clap-rs/commit/a283d69fc08aa016ae1bf9ba010012abecc7ba69), closes [#1112](https://github.com/kbknapp/clap-rs/issues/1112)) +* fixes a bug that allowed options to pass parsing when no value was provided ([2fb75821](https://github.com/kbknapp/clap-rs/commit/2fb758219c7a60d639da67692e100b855a8165ac), closes [#1105](https://github.com/kbknapp/clap-rs/issues/1105)) +* ignore PropagateGlobalValuesDown deprecation warning ([f61ce3f5](https://github.com/kbknapp/clap-rs/commit/f61ce3f55fe65e16b3db0bd4facdc4575de22767), closes [#1086](https://github.com/kbknapp/clap-rs/issues/1086)) + +#### Deps + +* Updates `bitflags` to 1.0 + + + + +## v2.27.1 (2017-10-24) + + +#### Bug Fixes + +* Adds `term_size` as an optional dependency (with feature `wrap_help`) to fix compile bug + + +## v2.27.0 (2017-10-24) + +** This release raises the minimum required version of Rust to 1.18 ** + +** This release also contains a very minor breaking change to fix a bug ** + +The only CLIs affected will be those using unrestrained multiple values and subcommands where the +subcommand name can coincide with one of the multiple values. + +See the commit [0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31) for full details. + + +#### Bug Fixes + +* Values from global args are now propagated UP and DOWN! +* fixes a bug where using AppSettings::AllowHyphenValues would allow invalid arguments even when there is no way for them to be valid ([77ed4684](https://github.com/kbknapp/clap-rs/commit/77ed46841fc0263d7aa32fcc5cc49ef703b37c04), closes [#1066](https://github.com/kbknapp/clap-rs/issues/1066)) +* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/)) +* fixes a bug that prevented number_of_values and default_values to be used together ([5eb342a9](https://github.com/kbknapp/clap-rs/commit/5eb342a99dde07b0f011048efde3e283bc1110fc), closes [#1050](https://github.com/kbknapp/clap-rs/issues/1050), [#1056](https://github.com/kbknapp/clap-rs/issues/1056)) +* fixes a bug that didn't allow args with default values to have conflicts ([58b5b4be](https://github.com/kbknapp/clap-rs/commit/58b5b4be315280888d50d9b15119b91a9028f050), closes [#1071](https://github.com/kbknapp/clap-rs/issues/1071)) +* fixes a panic when using global args and calling App::get_matches_from_safe_borrow multiple times ([d86ec797](https://github.com/kbknapp/clap-rs/commit/d86ec79742c77eb3f663fb30e225954515cf25bb), closes [#1076](https://github.com/kbknapp/clap-rs/issues/1076)) +* fixes issues and potential regressions with global args values not being propagated properly or at all ([a43f9dd4](https://github.com/kbknapp/clap-rs/commit/a43f9dd4aaf1864dd14a3c28dec89ccdd70c61e5), closes [#1010](https://github.com/kbknapp/clap-rs/issues/1010), [#1061](https://github.com/kbknapp/clap-rs/issues/1061), [#978](https://github.com/kbknapp/clap-rs/issues/978)) +* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047)) + +#### Documentation + +* adds addtional blurbs about using multiples with subcommands ([03455b77](https://github.com/kbknapp/clap-rs/commit/03455b7751a757e7b2f6ffaf2d16168539c99661)) +* updates the docs to reflect changes to global args and that global args values can now be propagated back up the stack ([ead076f0](https://github.com/kbknapp/clap-rs/commit/ead076f03ada4c322bf3e34203925561ec496d87)) +* add html_root_url attribute ([e67a061b](https://github.com/kbknapp/clap-rs/commit/e67a061bcf567c6518d6c2f58852e01f02764b22)) +* sync README version numbers with crate version ([5536361b](https://github.com/kbknapp/clap-rs/commit/5536361bcda29887ed86bb68e43d0b603cbc423f)) + +#### Improvements + +* args that have require_delimiter(true) is now reflected in help and usage strings ([dce61699](https://github.com/kbknapp/clap-rs/commit/dce616998ed9bd95e8ed3bec1f09a4883da47b85), closes [#1052](https://github.com/kbknapp/clap-rs/issues/1052)) +* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046)) + +#### Breaking Changes + +* when an argument requires a value and that value happens to match a subcommand name, its parsed as a value ([0c223f54](https://github.com/kbknapp/clap-rs/commit/0c223f54ed46da406bc8b43a5806e0b227863b31), closes [#1031](https://github.com/kbknapp/clap-rs/issues/1031), breaks [#](https://github.com/kbknapp/clap-rs/issues/), [#](https://github.com/kbknapp/clap-rs/issues/)) + +#### Deprecations + +* **AppSettings::PropagateGlobalValuesDown:** this setting is no longer required to propagate values down or up ([2bb5ddce](https://github.com/kbknapp/clap-rs/commit/2bb5ddcee61c791ca1aaca494fbeb4bd5e277488)) + + + + +### v2.26.2 (2017-09-14) + + +#### Improvements + +* if all subcommands are hidden, the subcommands section of the help message is no longer displayed ([4ae7b046](https://github.com/kbknapp/clap-rs/commit/4ae7b0464750bc07ec80ece38e43f003fdd1b8ae), closes [#1046](https://github.com/kbknapp/clap-rs/issues/1046)) + +#### Bug Fixes + +* fixes a bug where default values are not applied if the option supports zero values ([9c248cbf](https://github.com/kbknapp/clap-rs/commit/9c248cbf7d8a825119bc387c23e9a1d1989682b0), closes [#1047](https://github.com/kbknapp/clap-rs/issues/1047)) + + + + +### v2.26.1 (2017-09-14) + + +#### Bug Fixes + +* fixes using require_equals(true) and min_values(0) together ([10ae208f](https://github.com/kbknapp/clap-rs/commit/10ae208f68518eff6e98166724065745f4083174), closes [#1044](https://github.com/kbknapp/clap-rs/issues/1044)) +* escape special characters in zsh and fish completions ([87e019fc](https://github.com/kbknapp/clap-rs/commit/87e019fc84ba6193a8c4ddc26c61eb99efffcd25)) +* avoid panic generating default help msg if term width set to 0 due to bug in textwrap 0.7.0 ([b3eadb0d](https://github.com/kbknapp/clap-rs/commit/b3eadb0de516106db4e08f078ad32e8f6d6e7a57)) +* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349)) +* adds a debug assertion to ensure all args added to groups actually exist ([7ad123e2](https://github.com/kbknapp/clap-rs/commit/7ad123e2c02577e3ca30f7e205181e896b157d11), closes [#917](https://github.com/kbknapp/clap-rs/issues/917)) +* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ab2f4c9e](https://github.com/kbknapp/clap-rs/commit/ab2f4c9e563e36ec739a4b55d5a5b76fdb9e9fa4), closes [#960](https://github.com/kbknapp/clap-rs/issues/960)) +* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21)) +* **Help Message:** fixes long_about not being usable ([a8257ea0](https://github.com/kbknapp/clap-rs/commit/a8257ea0ffb812e552aca256c4a3d2aebfd8065b), closes [#1043](https://github.com/kbknapp/clap-rs/issues/1043)) +* **Suggestions:** output for flag after subcommand ([434ea5ba](https://github.com/kbknapp/clap-rs/commit/434ea5ba71395d8c1afcf88e69f0b0d8339b01a1)) + + + + +## v2.26.0 (2017-07-29) + +Minimum version of Rust is now v1.13.0 (Stable) + + +#### Improvements + +* bumps unicode-segmentation to v1.2 ([cd7b40a2](https://github.com/kbknapp/clap-rs/commit/cd7b40a21c77bae17ba453c5512cb82b7d1ce474)) + + +#### Performance + +* update textwrap to version 0.7.0 ([c2d4e637](https://github.com/kbknapp/clap-rs/commit/c2d4e63756a6f070e38c16dff846e9b0a53d6f93)) + + + + + +### v2.25.1 (2017-07-21) + +#### Improvements + +* impl Default for Values + OsValues for any lifetime. ([fb7d6231f1](https://github.com/kbknapp/clap-rs/commit/fb7d6231f13a2f79f411e62dca210b7dc9994c18)) + +#### Documentation + +* Various documentation typos and grammar fixes + + +### v2.25.0 (2017-06-20) + + +#### Features + +* use textwrap crate for wrapping help texts ([b93870c1](https://github.com/kbknapp/clap-rs/commit/b93870c10ae3bd90d233c586a33e086803117285)) + +#### Improvements + +* **Suggestions:** suggests to use flag after subcommand when applicable ([2671ca72](https://github.com/kbknapp/clap-rs/commit/2671ca7260119d4311d21c4075466aafdd9da734)) +* Bumps bitflags crate to v0.9 + +#### Documentation + +* Change `who's` -> `whose` ([53c1ffe8](https://github.com/kbknapp/clap-rs/commit/53c1ffe87f38b05d8804a0f7832412a952845349)) + +#### Documentation + +* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cbea3d5a](https://github.com/kbknapp/clap-rs/commit/cbea3d5acf3271a7a734498c4d99c709941c331e), closes [#949](https://github.com/kbknapp/clap-rs/issues/949)) +* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([f9b0d657](https://github.com/kbknapp/clap-rs/commit/f9b0d657835d3f517f313d70962177dc30acf4a7)) +* **README.md:** + * added a warning about using ~ deps ([821929b5](https://github.com/kbknapp/clap-rs/commit/821929b51bd60213955705900a436c9a64fcb79f), closes [#964](https://github.com/kbknapp/clap-rs/issues/964)) +* **clap_app!:** adds using the @group specifier to the macro docs ([826048cb](https://github.com/kbknapp/clap-rs/commit/826048cb3cbc0280169303f1498ff0a2b7395883), closes [#932](https://github.com/kbknapp/clap-rs/issues/932)) + + + + +### v2.24.2 (2017-05-15) + + +#### Bug Fixes + +* adds a debug assertion to ensure all args added to groups actually exist ([14f6b8f3](https://github.com/kbknapp/clap-rs/commit/14f6b8f3a2f6df73aeeec9c54a54909b1acfc158), closes [#917](https://github.com/kbknapp/clap-rs/issues/917)) +* fixes a bug where args that allow values to start with a hyphen couldnt contain a double hyphen -- as a value ([ebf73a09](https://github.com/kbknapp/clap-rs/commit/ebf73a09db6f3c03c19cdd76b1ba6113930e1643), closes [#960](https://github.com/kbknapp/clap-rs/issues/960)) +* fixes a bug where positional argument help text is misaligned ([54c16836](https://github.com/kbknapp/clap-rs/commit/54c16836dea4651806a2cfad53146a83fa3abf21)) + +#### Documentation + +* **App::template:** adds details about the necessity to use AppSettings::UnifiedHelpMessage when using {unified} tags in the help template ([cf569438](https://github.com/kbknapp/clap-rs/commit/cf569438f309c199800bb8e46c9f140187de69d7), closes [#949](https://github.com/kbknapp/clap-rs/issues/949)) +* **Arg::allow_hyphen_values:** updates the docs to include warnings for allow_hyphen_values and multiple(true) used together ([ded5a2f1](https://github.com/kbknapp/clap-rs/commit/ded5a2f15474d4a5bd46a67b130ccb8b6781bd01)) +* **clap_app!:** adds using the @group specifier to the macro docs ([fe85fcb1](https://github.com/kbknapp/clap-rs/commit/fe85fcb1772b61f13b20b7ea5290e2437a76190c), closes [#932](https://github.com/kbknapp/clap-rs/issues/932)) + + + + +### v2.24.0 (2017-05-07) + + +#### Bug Fixes + +* fixes a bug where args with last(true) and required(true) set were not being printed in the usage string ([3ac533fe](https://github.com/kbknapp/clap-rs/commit/3ac533fedabf713943eedf006f830a5a486bbe80), closes [#944](https://github.com/kbknapp/clap-rs/issues/944)) +* fixes a bug that was printing the arg name, instead of value name when Arg::last(true) was used ([e1fe8ac3](https://github.com/kbknapp/clap-rs/commit/e1fe8ac3bc1f9cf4e36df0d881f8419755f1787b), closes [#940](https://github.com/kbknapp/clap-rs/issues/940)) +* fixes a bug where flags were parsed as flags AND positional values when specific combinations of settings were used ([20f83292](https://github.com/kbknapp/clap-rs/commit/20f83292d070038b8cee2a6b47e91f6b0a2f7871), closes [#946](https://github.com/kbknapp/clap-rs/issues/946)) + + + + +## v2.24.0 (2017-05-05) + + +#### Documentation + +* **README.md:** fix some typos ([fa34deac](https://github.com/kbknapp/clap-rs/commit/fa34deac079f334c3af97bb7fb151880ba8887f8)) + +#### API Additions + +* **Arg:** add `default_value_os` ([d5ef8955](https://github.com/kbknapp/clap-rs/commit/d5ef8955414b1587060f7218385256105b639c88)) +* **arg_matches.rs:** Added a Default implementation for Values and OsValues iterators. ([0a4384e3](https://github.com/kbknapp/clap-rs/commit/0a4384e350eed74c2a4dc8964c203f21ac64897f)) + + + +### v2.23.2 (2017-04-19) + + +#### Bug Fixes + +* **PowerShell Completions:** fixes a bug where powershells completions cant be used if no subcommands are defined ([a8bce558](https://github.com/kbknapp/clap-rs/commit/a8bce55837dc4e0fb187dc93180884a40ae09c6f), closes [#931](https://github.com/kbknapp/clap-rs/issues/931)) + +#### Improvements + +* bumps term_size to take advantage of better terminal dimension handling ([e05100b7](https://github.com/kbknapp/clap-rs/commit/e05100b73d74066a90876bf38f952adf5e8ee422)) +* **PowerShell Completions:** massively dedups subcommand names in the generate script to make smaller scripts that are still functionally equiv ([85b0e1cc](https://github.com/kbknapp/clap-rs/commit/85b0e1cc4b9755dda75a93d898d79bc38631552b)) + +#### Documentation + +* Fix a typo the minimum rust version required ([71dabba3](https://github.com/kbknapp/clap-rs/commit/71dabba3ea0a17c88b0e2199c9d99f0acbf3bc17)) + + +### v2.23.1 (2017-04-05) + + +#### Bug Fixes + +* fixes a missing newline character in the autogenerated help and version messages in some instances ([5ae9007d](https://github.com/kbknapp/clap-rs/commit/5ae9007d984ae94ae2752df51bcbaeb0ec89bc15)) + + + +## v2.23.0 (2017-04-05) + + +#### API Additions + +* `App::long_about` +* `App::long_version` +* `App::print_long_help` +* `App::write_long_help` +* `App::print_long_version` +* `App::write_long_version` +* `Arg::long_help` + +#### Features + +* allows distinguishing between short and long version messages (-V/short or --version/long) ([59272b06](https://github.com/kbknapp/clap-rs/commit/59272b06cc213289dc604dbc694cb95d383a5d68)) +* allows distinguishing between short and long help with subcommands in the same manner as args ([6b371891](https://github.com/kbknapp/clap-rs/commit/6b371891a1702173a849d1e95f9fecb168bf6fc4)) +* allows specifying a short help vs a long help (i.e. varying levels of detail depending on if -h or --help was used) ([ef1b24c3](https://github.com/kbknapp/clap-rs/commit/ef1b24c3a0dff2f58c5e2e90880fbc2b69df20ee)) +* **clap_app!:** adds support for arg names with hyphens similar to longs with hyphens ([f7a88779](https://github.com/kbknapp/clap-rs/commit/f7a8877978c8f90e6543d4f0d9600c086cf92cd7), closes [#869](https://github.com/kbknapp/clap-rs/issues/869)) + +#### Bug Fixes + +* fixes a bug that wasn't allowing help and version to be properly overridden ([8b2ceb83](https://github.com/kbknapp/clap-rs/commit/8b2ceb8368bcb70689fadf1c7f4b9549184926c1), closes [#922](https://github.com/kbknapp/clap-rs/issues/922)) + +#### Documentation + +* **clap_app!:** documents the `--("some-arg")` method for using args with hyphens inside them ([bc08ef3e](https://github.com/kbknapp/clap-rs/commit/bc08ef3e185393073d969d301989b6319c616c1f), closes [#919](https://github.com/kbknapp/clap-rs/issues/919)) + + + + +### v2.22.2 (2017-03-30) + + +#### Bug Fixes + +* **Custom Usage Strings:** fixes the usage string regression when using help templates ([0e4fd96d](https://github.com/kbknapp/clap-rs/commit/0e4fd96d74280d306d09e60ac44f938a82321769)) + + + + +### v2.22.1 (2017-03-24) + + +#### Bug Fixes + +* **usage:** fixes a big regression with custom usage strings ([2c41caba](https://github.com/kbknapp/clap-rs/commit/2c41caba3c7d723a2894e315d04da796b0e97759)) + + +## v2.22.0 (2017-03-23) + +#### API Additions + +* **App::name:** adds the ability to change the name of the App instance after creation ([d49e8292](https://github.com/kbknapp/clap-rs/commit/d49e8292b026b06e2b70447cd9f08299f4fcba76), closes [#908](https://github.com/kbknapp/clap-rs/issues/908)) +* **Arg::hide_default_value:** adds ability to hide the default value of an argument from the help string ([89e6ea86](https://github.com/kbknapp/clap-rs/commit/89e6ea861e16a1ad56757ca12f6b32d02253e44a), closes [#902](https://github.com/kbknapp/clap-rs/issues/902)) + + + +### v2.21.3 (2017-03-23) + +#### Bug Fixes + +* **yaml:** adds support for loading author info from yaml ([e04c390c](https://github.com/kbknapp/clap-rs/commit/e04c390c597a55fa27e724050342f16c42f1c5c9)) + + + +### v2.21.2 (2017-03-17) + + +#### Improvements + +* add fish subcommand help support ([f8f68cf8](https://github.com/kbknapp/clap-rs/commit/f8f68cf8251669aef4539a25a7c1166f0ac81ea6)) +* options that use `require_equals(true)` now display the equals sign in help messages, usage strings, and errors" ([c8eb0384](https://github.com/kbknapp/clap-rs/commit/c8eb0384d394d2900ccdc1593099c97808a3fa05), closes [#903](https://github.com/kbknapp/clap-rs/issues/903)) + + +#### Bug Fixes + +* setting the max term width now correctly propagates down through child subcommands + + + + +### v2.21.1 (2017-03-12) + + +#### Bug Fixes + +* **ArgRequiredElseHelp:** fixes the precedence of this error to prioritize over other error messages ([74b751ff](https://github.com/kbknapp/clap-rs/commit/74b751ff2e3631e337b7946347c1119829a41c53), closes [#895](https://github.com/kbknapp/clap-rs/issues/895)) +* **Positionals:** fixes some regression bugs resulting from old asserts in debug mode. ([9a3bc98e](https://github.com/kbknapp/clap-rs/commit/9a3bc98e9b55e7514b74b73374c5ac8b6e5e0508), closes [#896](https://github.com/kbknapp/clap-rs/issues/896)) + + + + +## v2.21.0 (2017-03-09) + +#### Performance + +* doesn't run `arg_post_processing` on multiple values anymore ([ec516182](https://github.com/kbknapp/clap-rs/commit/ec5161828729f6a53f0fccec8648f71697f01f78)) +* changes internal use of `VecMap` to `Vec` for matched values of `Arg`s ([22bf137a](https://github.com/kbknapp/clap-rs/commit/22bf137ac581684c6ed460d2c3c640c503d62621)) +* vastly reduces the amount of cloning when adding non-global args minus when they're added from `App::args` which is forced to clone ([8da0303b](https://github.com/kbknapp/clap-rs/commit/8da0303bc02db5fe047cfc0631a9da41d9dc60f7)) +* refactor to remove unneeded vectors and allocations and checks for significant performance increases ([0efa4119](https://github.com/kbknapp/clap-rs/commit/0efa4119632f134fc5b8b9695b007dd94b76735d)) + +#### Documentation + +* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1)) + +#### Improvements + +* when `AppSettings::SubcommandsNegateReqs` and `ArgsNegateSubcommands` are used, a new more accurate double line usage string is shown ([50f02300](https://github.com/kbknapp/clap-rs/commit/50f02300d81788817acefef0697e157e01b6ca32), closes [#871](https://github.com/kbknapp/clap-rs/issues/871)) + +#### API Additions + +* **Arg::last:** adds the ability to mark a positional argument as 'last' which means it should be used with `--` syntax and can be accessed early ([6a7aea90](https://github.com/kbknapp/clap-rs/commit/6a7aea9043b83badd9ab038b4ecc4c787716147e), closes [#888](https://github.com/kbknapp/clap-rs/issues/888)) +* provides `default_value_os` and `default_value_if[s]_os` ([0f2a3782](https://github.com/kbknapp/clap-rs/commit/0f2a378219a6930748d178ba350fe5925be5dad5), closes [#849](https://github.com/kbknapp/clap-rs/issues/849)) +* provides `App::help_message` and `App::version_message` which allows one to override the auto-generated help/version flag associated help ([389c413](https://github.com/kbknapp/clap-rs/commit/389c413b7023dccab8c76aa00577ea1d048e7a99), closes [#889](https://github.com/kbknapp/clap-rs/issues/889)) + +#### New Settings + +* **InferSubcommands:** adds a setting to allow one to infer shortened subcommands or aliases (i.e. for subcommmand "test", "t", "te", or "tes" would be allowed assuming no other ambiguities) ([11602032](https://github.com/kbknapp/clap-rs/commit/11602032f6ff05881e3adf130356e37d5e66e8f9), closes [#863](https://github.com/kbknapp/clap-rs/issues/863)) + +#### Bug Fixes + +* doesn't print the argument sections in the help message if all args in that section are hidden ([ce5ee5f5](https://github.com/kbknapp/clap-rs/commit/ce5ee5f5a76f838104aeddd01c8ec956dd347f50)) +* doesn't include the various [ARGS] [FLAGS] or [OPTIONS] if the only ones available are hidden ([7b4000af](https://github.com/kbknapp/clap-rs/commit/7b4000af97637703645c5fb2ac8bb65bd546b95b), closes [#882](https://github.com/kbknapp/clap-rs/issues/882)) +* now correctly shows subcommand as required in the usage string when AppSettings::SubcommandRequiredElseHelp is used ([8f0884c1](https://github.com/kbknapp/clap-rs/commit/8f0884c1764983a49b45de52a1eddf8d721564d8)) +* fixes some memory leaks when an error is detected and clap exits ([8c2dd287](https://github.com/kbknapp/clap-rs/commit/8c2dd28718262ace4ae0db98563809548e02a86b)) +* fixes a trait that's marked private accidentlly, but should be crate internal public ([1ae21108](https://github.com/kbknapp/clap-rs/commit/1ae21108015cea87e5360402e1747025116c7878)) +* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846)) + +#### Features + +* **Options:** adds the ability to require the equals syntax with options --opt=val ([f002693d](https://github.com/kbknapp/clap-rs/commit/f002693dec6a6959c4e9590cb7b7bfffd6d6e5bc), closes [#833](https://github.com/kbknapp/clap-rs/issues/833)) + + + + +### v2.20.5 (2017-02-18) + + +#### Bug Fixes + +* **clap_app!:** fixes a critical bug of a missing fragment specifier when using `!property` style tags. ([5635c1f94](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94)) + + + +### v2.20.4 (2017-02-15) + + +#### Bug Fixes + +* **Completions:** fixes a bug that tried to propogate global args multiple times when generating multiple completion scripts ([5e9b9cf4](https://github.com/kbknapp/clap-rs/commit/5e9b9cf4dd80fa66a624374fd04e6545635c1f94), closes [#846](https://github.com/kbknapp/clap-rs/issues/846)) + +#### Documentation + +* Fix examples link in CONTRIBUTING.md ([60cf875d](https://github.com/kbknapp/clap-rs/commit/60cf875d67a252e19bb85054be57696fac2c57a1)) + + + +### v2.20.3 (2017-02-03) + + +#### Documentation + +* **Macros:** adds a warning about changing values in Cargo.toml not triggering a rebuild automatically ([112aea3e](https://github.com/kbknapp/clap-rs/commit/112aea3e42ae9e0c0a2d33ebad89496dbdd95e5d), closes [#838](https://github.com/kbknapp/clap-rs/issues/838)) + +#### Bug Fixes + +* fixes a println->debugln typo ([279aa62e](https://github.com/kbknapp/clap-rs/commit/279aa62eaf08f56ce090ba16b937bc763cbb45be)) +* fixes bash completions for commands that have an underscore in the name ([7f5cfa72](https://github.com/kbknapp/clap-rs/commit/7f5cfa724f0ac4e098f5fe466c903febddb2d994), closes [#581](https://github.com/kbknapp/clap-rs/issues/581)) +* fixes a bug where ZSH completions would panic if the binary name had an underscore in it ([891a2a00](https://github.com/kbknapp/clap-rs/commit/891a2a006f775e92c556dda48bb32fac9807c4fb), closes [#581](https://github.com/kbknapp/clap-rs/issues/581)) +* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828)) +* fixes a bug where global args weren't included in the generated completion scripts ([9a1e006e](https://github.com/kbknapp/clap-rs/commit/9a1e006eb75ad5a6057ebd119aa90f7e06c0ace8), closes [#841](https://github.com/kbknapp/clap-rs/issues/841)) + + + + +### v2.20.2 (2017-02-03) + +#### Bug Fixes + +* fixes a critical bug where subcommand settings were being propogated too far ([74648c94](https://github.com/kbknapp/clap-rs/commit/74648c94b893df542bfa5bb595e68c7bb8167e36), closes [#832](https://github.com/kbknapp/clap-rs/issues/832)) + + +#### Improvements + +* adds ArgGroup::multiple to the supported YAML fields for building ArgGroups from YAML ([d8590037](https://github.com/kbknapp/clap-rs/commit/d8590037ce07dafd8cd5b26928aa4a9fd3018288), closes [#840](https://github.com/kbknapp/clap-rs/issues/840)) + + +### v2.20.1 (2017-01-31) + +#### Bug Fixes + +* allow final word to be wrapped in wrap_help ([564c5f0f](https://github.com/kbknapp/clap-rs/commit/564c5f0f1730f4a2c1cdd128664f1a981c31dcd4), closes [#828](https://github.com/kbknapp/clap-rs/issues/828)) +* actually show character in debug output ([84d8c547](https://github.com/kbknapp/clap-rs/commit/84d8c5476de95b7f37d61888bc4f13688b712434)) +* include final character in line lenght ([aff4ba18](https://github.com/kbknapp/clap-rs/commit/aff4ba18da8147e1259b04b0bfbc1fcb5c78a3c0)) + +#### Improvements + +* updates libc and term_size deps for the libc version conflict ([6802ac4a](https://github.com/kbknapp/clap-rs/commit/6802ac4a59c142cda9ec55ca0c45ae5cb9a6ab55)) + +#### Documentation + +* fix link from app_from_crate! to crate_authors! (#822) ([5b29be9b](https://github.com/kbknapp/clap-rs/commit/5b29be9b073330ab1f7227cdd19fe4aab39d5dcb)) +* fix spelling of "guaranteed" ([4f30a65b](https://github.com/kbknapp/clap-rs/commit/4f30a65b9c03eb09607eb91a929a6396637dc105)) + + + +#### New Settings + +* **ArgsNegateSubcommands:** disables args being allowed between subcommands ([5e2af8c9](https://github.com/kbknapp/clap-rs/commit/5e2af8c96adb5ab75fa2d1536237ebcb41869494), closes [#793](https://github.com/kbknapp/clap-rs/issues/793)) +* **DontCollapseArgsInUsage:** disables the collapsing of positional args into `[ARGS]` in the usage string ([c2978afc](https://github.com/kbknapp/clap-rs/commit/c2978afc61fb46d5263ab3b2d87ecde1c9ce1553), closes [#769](https://github.com/kbknapp/clap-rs/issues/769)) +* **DisableHelpSubcommand:** disables building the `help` subcommand ([a10fc859](https://github.com/kbknapp/clap-rs/commit/a10fc859ee20159fbd9ff4337be59b76467a64f2)) +* **AllowMissingPositional:** allows one to implement `$ prog [optional] ` style CLIs where the second postional argument is required, but the first is optional ([1110fdc7](https://github.com/kbknapp/clap-rs/commit/1110fdc7a345c108820dc45783a9bf893fa4c214), closes [#636](https://github.com/kbknapp/clap-rs/issues/636)) +* **PropagateGlobalValuesDown:** automatically propagats global arg's values down through *used* subcommands ([985536c8](https://github.com/kbknapp/clap-rs/commit/985536c8ebcc09af98aac835f42a8072ad58c262), closes [#694](https://github.com/kbknapp/clap-rs/issues/694)) + +#### API Additions + +##### Arg + +* **Arg::value_terminator:** adds the ability to terminate multiple values with a given string or char ([be64ce0c](https://github.com/kbknapp/clap-rs/commit/be64ce0c373efc106384baca3f487ea99fe7b8cf), closes [#782](https://github.com/kbknapp/clap-rs/issues/782)) +* **Arg::default_value_if[s]:** adds new methods for *conditional* default values (such as a particular value from another argument was used) ([eb4010e7](https://github.com/kbknapp/clap-rs/commit/eb4010e7b21724447ef837db11ac441915728f22)) +* **Arg::requires_if[s]:** adds the ability to *conditionally* require additional args (such as if a particular value was used) ([198449d6](https://github.com/kbknapp/clap-rs/commit/198449d64393c265f0bc327aaeac23ec4bb97226)) +* **Arg::required_if[s]:** adds the ability for an arg to be *conditionally* required (i.e. "arg X is only required if arg Y was used with value Z") ([ee9cfddf](https://github.com/kbknapp/clap-rs/commit/ee9cfddf345a6b5ae2af42ba72aa5c89e2ca7f59)) +* **Arg::validator_os:** adds ability to validate values which may contain invalid UTF-8 ([47232498](https://github.com/kbknapp/clap-rs/commit/47232498a813db4f3366ccd3e9faf0bff56433a4)) + +##### Macros + +* **crate_description!:** Uses the `Cargo.toml` description field to fill in the `App::about` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) +* **crate_name!:** Uses the `Cargo.toml` name field to fill in the `App::new` method at compile time ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) +* **app_from_crate!:** Combines `crate_version!`, `crate_name!`, `crate_description!`, and `crate_authors!` into a single macro call to build a default `App` instance from the `Cargo.toml` fields ([4d9a82db](https://github.com/kbknapp/clap-rs/commit/4d9a82db8e875e9b64a9c2a5c6e22c25afc1279d), closes [#778](https://github.com/kbknapp/clap-rs/issues/778)) + + +#### Features + +* **no_cargo:** adds a `no_cargo` feature to disable Cargo-env-var-dependent macros for those *not* using `cargo` to build their crates (#786) ([6fdd2f9d](https://github.com/kbknapp/clap-rs/commit/6fdd2f9d693aaf1118fc61bd362273950703f43d)) + +#### Bug Fixes + +* **Options:** fixes a critical bug where options weren't forced to have a value ([5a5f2b1e](https://github.com/kbknapp/clap-rs/commit/5a5f2b1e9f598a0d0280ef3e98abbbba2bc41132), closes [#665](https://github.com/kbknapp/clap-rs/issues/665)) +* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([d3d34a2b](https://github.com/kbknapp/clap-rs/commit/d3d34a2b51ef31004055b0ab574f766d801c3adf), closes [#789](https://github.com/kbknapp/clap-rs/issues/789)) +* **Help Subcommand:** fixes a bug where the help subcommand couldn't be overriden ([d34ec3e0](https://github.com/kbknapp/clap-rs/commit/d34ec3e032d03e402d8e87af9b2942fe2819b2da), closes [#787](https://github.com/kbknapp/clap-rs/issues/787)) +* **Low Index Multiples:** fixes a bug which caused combinations of LowIndexMultiples and `Arg::allow_hyphen_values` to fail parsing ([26c670ca](https://github.com/kbknapp/clap-rs/commit/26c670ca16d2c80dc26d5c1ce83380ace6357318)) + +#### Improvements + +* **Default Values:** improves the error message when default values are involved ([1f33de54](https://github.com/kbknapp/clap-rs/commit/1f33de545036e7fd2f80faba251fca009bd519b8), closes [#774](https://github.com/kbknapp/clap-rs/issues/774)) +* **YAML:** adds conditional requirements and conditional default values to YAML ([9a4df327](https://github.com/kbknapp/clap-rs/commit/9a4df327893486adb5558ffefba790c634ccdc6e), closes [#764](https://github.com/kbknapp/clap-rs/issues/764)) +* Support `--("some-arg-name")` syntax for defining long arg names when using `clap_app!` macro ([f41ec962](https://github.com/kbknapp/clap-rs/commit/f41ec962c243a5ffff8b1be1ae2ad63970d3d1d4)) +* Support `("some app name")` syntax for defining app names when using `clap_app!` macro ([9895b671](https://github.com/kbknapp/clap-rs/commit/9895b671cff784f35cf56abcd8270f7c2ba09699), closes [#759](https://github.com/kbknapp/clap-rs/issues/759)) +* **Help Wrapping:** long app names (with spaces), authors, and descriptions are now wrapped appropriately ([ad4691b7](https://github.com/kbknapp/clap-rs/commit/ad4691b71a63e951ace346318238d8834e04ad8a), closes [#777](https://github.com/kbknapp/clap-rs/issues/777)) + + +#### Documentation + +* **Conditional Default Values:** fixes the failing doc tests of Arg::default_value_ifs ([4ef09101](https://github.com/kbknapp/clap-rs/commit/4ef091019c083b4db1a0c13f1c1e95ac363259f2)) +* **Conditional Requirements:** adds docs for Arg::requires_ifs ([7f296e29](https://github.com/kbknapp/clap-rs/commit/7f296e29db7d9036e76e5dbcc9c8b20dfe7b25bd)) +* **README.md:** fix some typos ([f22c21b4](https://github.com/kbknapp/clap-rs/commit/f22c21b422d5b287d1a1ac183a379ee02eebf54f)) +* **src/app/mod.rs:** fix some typos ([5c9b0d47](https://github.com/kbknapp/clap-rs/commit/5c9b0d47ca78dea285c5b9dec79063d24c3e451a)) + + +### v2.19.3 (2016-12-28) + + +#### Bug Fixes + +* fixes a bug where calling the help of a subcommand wasn't ignoring required args of parent commands ([a0ee4993](https://github.com/kbknapp/clap-rs/commit/a0ee4993015ea97b06b5bc9f378d8bcb18f1c51c), closes [#789](https://github.com/kbknapp/clap-rs/issues/789)) + + + + +### v2.19.2 (2016-12-08) + +#### Bug Fixes + +* **ZSH Completions:** escapes square brackets in ZSH completions ([7e17d5a3](https://github.com/kbknapp/clap-rs/commit/7e17d5a36b2cc2cc77e7b15796b14d639ed3cbf7), closes [#771](https://github.com/kbknapp/clap-rs/issues/771)) + +#### Documentation + +* **Examples:** adds subcommand examples ([0e0f3354](https://github.com/kbknapp/clap-rs/commit/0e0f33547a6901425afc1d9fbe19f7ae3832d9a4), closes [#766](https://github.com/kbknapp/clap-rs/issues/766)) +* **README.md:** adds guidance on when to use ~ in version pinning, and clarifies breaking change policy ([591eaefc](https://github.com/kbknapp/clap-rs/commit/591eaefc7319142ba921130e502bb0729feed907), closes [#765](https://github.com/kbknapp/clap-rs/issues/765)) + + + + +### v2.19.1 (2016-12-01) + + +#### Bug Fixes + +* **Help Messages:** fixes help message alignment when specific settings are used on options ([cd94b318](https://github.com/kbknapp/clap-rs/commit/cd94b3188d63b63295a319e90e826bca46befcd2), closes [#760](https://github.com/kbknapp/clap-rs/issues/760)) + +#### Improvements + +* **Bash Completion:** allows bash completion to fall back to traidtional bash completion upon no matching completing function ([b1b16d56](https://github.com/kbknapp/clap-rs/commit/b1b16d56d8fddf819bdbe24b3724bb6a9f3fa613))) + + + +## v2.19.0 (2016-11-21) + +#### Features + +* allows specifying AllowLeadingHyphen style values, but only for specific args vice command wide ([c0d70feb](https://github.com/kbknapp/clap-rs/commit/c0d70febad9996a77a54107054daf1914c50d4ef), closes [#742](https://github.com/kbknapp/clap-rs/issues/742)) + +#### Bug Fixes + +* **Required Unless:** fixes a bug where having required_unless set doesn't work when conflicts are also set ([d20331b6](https://github.com/kbknapp/clap-rs/commit/d20331b6f7940ac3a4e919999f8bb4780875125d), closes [#753](https://github.com/kbknapp/clap-rs/issues/753)) +* **ZSH Completions:** fixes an issue where zsh completions caused panics if there were no subcommands ([49e7cdab](https://github.com/kbknapp/clap-rs/commit/49e7cdab76dd1ccc07221e360f07808ec62648aa), closes [#754](https://github.com/kbknapp/clap-rs/issues/754)) + +#### Improvements + +* **Validators:** improves the error messages for validators ([65eb3385](https://github.com/kbknapp/clap-rs/commit/65eb33859d3ff53e7d3277f02a9d3fd9038a9dfb), closes [#744](https://github.com/kbknapp/clap-rs/issues/744)) + +#### Documentation + +* updates the docs landing page ([01e1e33f](https://github.com/kbknapp/clap-rs/commit/01e1e33f377934099a4a725fab5cd6c5ff50eaa2)) +* adds the macro version back to the readme ([45eb9bf1](https://github.com/kbknapp/clap-rs/commit/45eb9bf130329c3f3853aba0342c2fe3c64ff80f)) +* fix broken docs links ([808e7cee](https://github.com/kbknapp/clap-rs/commit/808e7ceeb86d4a319bdc270f51c23a64621dbfb3)) +* **Compatibility Policy:** adds an official compatibility policy to ([760d66dc](https://github.com/kbknapp/clap-rs/commit/760d66dc17310b357f257776624151da933cd25d), closes [#740](https://github.com/kbknapp/clap-rs/issues/740)) +* **Contributing:** updates the readme to improve the readability and contributing sections ([eb51316c](https://github.com/kbknapp/clap-rs/commit/eb51316cdfdc7258d287ba13b67ef2f42bd2b8f6)) + + +## v2.18.0 (2016-11-05) + + +#### Features + +* **Completions:** adds completion support for PowerShell. ([cff82c88](https://github.com/kbknapp/clap-rs/commit/cff82c880e21064fca63351507b80350df6caadf), closes [#729](https://github.com/kbknapp/clap-rs/issues/729)) + + + + +### v2.17.1 (2016-11-02) + + +#### Bug Fixes + +* **Low Index Multiples:** fixes a bug where using low index multiples was propagated to subcommands ([33924e88](https://github.com/kbknapp/clap-rs/commit/33924e884461983c4e6b5ea1330fecc769a4ade7), closes [#725](https://github.com/kbknapp/clap-rs/issues/725)) + + + + +## v2.17.0 (2016-11-01) + + +#### Features + +* **Positional Args:** allows specifying the second to last positional argument as multiple(true) ([1ced2a74](https://github.com/kbknapp/clap-rs/commit/1ced2a7433ea8937a1b260ea65d708f32ca7c95e), closes [#725](https://github.com/kbknapp/clap-rs/issues/725)) + + + + +### v2.16.4 (2016-10-31) + + +#### Improvements + +* **Error Output:** conflicting errors are now symetrical, meaning more consistent and less confusing ([3d37001d](https://github.com/kbknapp/clap-rs/commit/3d37001d1dc647d73cc597ff172f1072d4beb80d), closes [#718](https://github.com/kbknapp/clap-rs/issues/718)) + +#### Documentation + +* Fix typo in example `13a_enum_values_automatic` ([c22fbc07](https://github.com/kbknapp/clap-rs/commit/c22fbc07356e556ffb5d1a79ec04597d149b915e)) +* **README.md:** fixes failing yaml example (#715) ([21fba9e6](https://github.com/kbknapp/clap-rs/commit/21fba9e6cd8c163012999cd0ce271ec8780c5695)) + +#### Bug Fixes + +* **ZSH Completions:** fixes bug that caused panic on subcommands with aliases ([5c70e1a0](https://github.com/kbknapp/clap-rs/commit/5c70e1a01bc977e44c10015d18bb8e215c32dfc8), closes [#714](https://github.com/kbknapp/clap-rs/issues/714)) +* **debug:** fixes the debug feature (#716) ([6c11ccf4](https://github.com/kbknapp/clap-rs/commit/6c11ccf443d46258d51f7cda33fbcc81e7fe8e90)) + + + + +### v2.16.3 (2016-10-28) + + +#### Bug Fixes + +* Derive display order after propagation ([9cb6facf](https://github.com/kbknapp/clap-rs/commit/9cb6facf507aff7cddd124b8c29714d2b0e7bd13), closes [#706](https://github.com/kbknapp/clap-rs/issues/706)) +* **yaml-example:** inconsistent args ([847f7199](https://github.com/kbknapp/clap-rs/commit/847f7199219ead5065561d91d64780d99ae4b587)) + + + + +### v2.16.2 (2016-10-25) + + +#### Bug Fixes + +* **Fish Completions:** fixes a bug where single quotes are not escaped ([780b4a18](https://github.com/kbknapp/clap-rs/commit/780b4a18281b6f7f7071e1b9db2290fae653c406), closes [#704](https://github.com/kbknapp/clap-rs/issues/704)) + + + +### v2.16.1 (2016-10-24) + + +#### Bug Fixes + +* **Help Message:** fixes a regression bug where args with multiple(true) threw off alignment ([ebddac79](https://github.com/kbknapp/clap-rs/commit/ebddac791f3ceac193d5ad833b4b734b9643a7af), closes [#702](https://github.com/kbknapp/clap-rs/issues/702)) + + + + +## v2.16.0 (2016-10-23) + + +#### Features + +* **Completions:** adds ZSH completion support ([3e36b0ba](https://github.com/kbknapp/clap-rs/commit/3e36b0bac491d3f6194aee14604caf7be26b3d56), closes [#699](https://github.com/kbknapp/clap-rs/issues/699)) + + + + +## v2.15.0 (2016-10-21) + + +#### Features + +* **AppSettings:** adds new setting `AppSettings::AllowNegativeNumbers` ([ab064546](https://github.com/kbknapp/clap-rs/commit/ab06454677fb6aa9b9f804644fcca2168b1eaee3), closes [#696](https://github.com/kbknapp/clap-rs/issues/696)) + +#### Documentation + +* **app/settings.rs:** moves variants to roughly alphabetical order ([9ed4d4d7](https://github.com/kbknapp/clap-rs/commit/9ed4d4d7957a23357aef60081e45639ab9e3905f)) + + + +### v2.14.1 (2016-10-20) + + +#### Documentation + +* Improve documentation around features ([4ee85b95](https://github.com/kbknapp/clap-rs/commit/4ee85b95d2d16708a016a3ba4e6e2c93b89b7fad)) +* reword docs for ErrorKind and app::Settings ([3ccde7a4](https://github.com/kbknapp/clap-rs/commit/3ccde7a4b8f7a2ea8b916a5415c04a8ff4b5cb7a)) +* fix tests that fail when the "suggestions" feature is disabled ([996fc381](https://github.com/kbknapp/clap-rs/commit/996fc381763a48d125c7ea8a58fed057fd0b4ac6)) +* fix the OsString-using doc-tests ([af9e1a39](https://github.com/kbknapp/clap-rs/commit/af9e1a393ce6cdda46a03c8a4f48df222b015a24)) +* tag non-rust code blocks as such instead of ignoring them ([0ba9f4b1](https://github.com/kbknapp/clap-rs/commit/0ba9f4b123f281952581b6dec948f7e51dd22890)) +* **ErrorKind:** improve some errors about subcommands ([9f6217a4](https://github.com/kbknapp/clap-rs/commit/9f6217a424da823343d7b801b9c350dee3cd1906)) +* **yaml:** make sure the doc-tests don't fail before "missing file" ([8c0f5551](https://github.com/kbknapp/clap-rs/commit/8c0f55516f4910c78c9f8a2bdbd822729574f95b)) + +#### Improvements + +* Stabilize clap_app! ([cd516006](https://github.com/kbknapp/clap-rs/commit/cd516006e35c37b005f329338560a0a53d1f3e00)) +* **with_defaults:** Deprecate App::with_defaults() ([26085409](https://github.com/kbknapp/clap-rs/commit/2608540940c8bb66e517b65706bc7dea55510682), closes [#638](https://github.com/kbknapp/clap-rs/issues/638)) + +#### Bug Fixes + +* fixes a bug that made determining when to auto-wrap long help messages inconsistent ([468baadb](https://github.com/kbknapp/clap-rs/commit/468baadb8398fc1d37897b0c49374aef4cf97dca), closes [#688](https://github.com/kbknapp/clap-rs/issues/688)) +* **Completions:** fish completions for nested subcommands ([a61eaf8a](https://github.com/kbknapp/clap-rs/commit/a61eaf8aade76cfe90ccc0f7125751ebf60e3254)) +* **features:** Make lints not enable other nightly-requiring features ([835f75e3](https://github.com/kbknapp/clap-rs/commit/835f75e3ba20999117363ed9f916464d777f36ef)) + + + + +## v2.14.0 (2016-10-05) + + +#### Features + +* **arg_aliases:** Ability to alias arguments ([33b5f6ef](https://github.com/kbknapp/clap-rs/commit/33b5f6ef2c9612ecabb31f96b824793e46bfd3dd), closes [#669](https://github.com/kbknapp/clap-rs/issues/669)) +* **flag_aliases:** Ability to alias flags ([40d6dac9](https://github.com/kbknapp/clap-rs/commit/40d6dac973927dded6ab423481634ef47ee7bfd7)) + +#### Bug Fixes + +* **UsageParser:** Handle non-ascii names / options. ([1d6a7c6e](https://github.com/kbknapp/clap-rs/commit/1d6a7c6e7e6aadc527346aa822f19d8587f714f3), closes [#664](https://github.com/kbknapp/clap-rs/issues/664)) + +#### Documentation + +* typo ([bac417fa](https://github.com/kbknapp/clap-rs/commit/bac417fa1cea3d32308334c7cccfcf54546cd9d8)) + + + +## v2.13.0 (2016-09-18) + + +#### Documentation + +* updates README.md with new website information and updated video tutorials info ([0c19c580](https://github.com/kbknapp/clap-rs/commit/0c19c580cf50f1b82ff32f70b36708ae2bcac132)) +* updates the docs about removing implicit value_delimiter(true) ([c81bc722](https://github.com/kbknapp/clap-rs/commit/c81bc722ebb8a86d22be89b5aec98df9fe222a08)) +* **Default Values:** adds better examples on using default values ([57a8d9ab](https://github.com/kbknapp/clap-rs/commit/57a8d9abb2f973c235a8a14f8fc031673d7a7460), closes [#418](https://github.com/kbknapp/clap-rs/issues/418)) + +#### Bug Fixes + +* **Value Delimiters:** fixes the confusion around implicitly setting value delimiters. (default is now `false`) ([09d4d0a9](https://github.com/kbknapp/clap-rs/commit/09d4d0a9038d7ce2df55c2aec95e16f36189fcee), closes [#666](https://github.com/kbknapp/clap-rs/issues/666)) + + + + +### v2.12.1 (2016-09-13) + + +#### Bug Fixes + +* **Help Wrapping:** fixes a regression-bug where the old {n} newline char stopped working ([92ac353b](https://github.com/kbknapp/clap-rs/commit/92ac353b48b7caa2511ad2a046d94da93c236cf6), closes [#661](https://github.com/kbknapp/clap-rs/issues/661)) + + + + +## v2.12.0 (2016-09-13) + + +#### Features + +* **Help:** adds ability to hide the possible values on a per argument basis ([9151ef73](https://github.com/kbknapp/clap-rs/commit/9151ef739871f2e74910c342299c0de196b95dec), closes [#640](https://github.com/kbknapp/clap-rs/issues/640)) +* **help:** allow for limiting detected terminal width ([a43e28af](https://github.com/kbknapp/clap-rs/commit/a43e28af85c9a9deaedd5ef735f4f13008daab29), closes [#653](https://github.com/kbknapp/clap-rs/issues/653)) + +#### Documentation + +* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611)) +* **Value Delimiters:** updates the docs for the Arg::multiple method WRT value delimiters and default settings ([f9d17a06](https://github.com/kbknapp/clap-rs/commit/f9d17a060aa53f10d0a6e1a7eed5d989d1a59533)) +* **appsettings:** Document AppSetting::DisableVersion ([94501965](https://github.com/kbknapp/clap-rs/commit/945019654d2ca67eb2b1d6014fdf80b84d528d30), closes [#589](https://github.com/kbknapp/clap-rs/issues/589)) + +#### Bug Fixes + +* **AllowLeadingHyphen:** fixes a bug where valid args aren't recognized with this setting ([a9699e4d](https://github.com/kbknapp/clap-rs/commit/a9699e4d7cdc9a06e73b845933ff1fe6d76f016a), closes [#588](https://github.com/kbknapp/clap-rs/issues/588)) + +#### Improvements + +* **Help Wrapping:** + * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617)) + * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f)) +* **Value Delimiters:** changes the default value delimiter rules ([f9e69254](https://github.com/kbknapp/clap-rs/commit/f9e692548e8c94de15f909432de301407d6bb834), closes [#655](https://github.com/kbknapp/clap-rs/issues/655)) +* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816)) + +#### Performance + +* **help:** fix redundant contains() checks ([a8afed74](https://github.com/kbknapp/clap-rs/commit/a8afed7428bf0733f8e93bb11ad6c00d9e970fcc)) + + + + +### v2.11.3 (2016-09-07) + + +#### Documentation + +* **Help Wrapping:** removes the verbiage about using `'{n}'` to insert newlines in help text ([c5a2b352](https://github.com/kbknapp/clap-rs/commit/c5a2b352ca600f5b802290ad945731066cd53611)) + +#### Improvements + +* **Help Wrapping:** + * clap now ignores hard newlines in help messages and properly re-aligns text, but still wraps if the term width is too small ([c7678523](https://github.com/kbknapp/clap-rs/commit/c76785239fd42adc8ca04f9202b6fec615aa9f14), closes [#617](https://github.com/kbknapp/clap-rs/issues/617)) + * makes some minor changes to when next line help is automatically used ([01cae799](https://github.com/kbknapp/clap-rs/commit/01cae7990a33167ac35103fb36c811b4fe6eb98f)) +* **YAML:** supports setting Arg::require_delimiter from YAML ([b9b55a39](https://github.com/kbknapp/clap-rs/commit/b9b55a39dfebcdbdc05dca2692927e503db50816)) + + + + + +### v2.11.2 (2016-09-06) + +#### Improvements + +* **Help Wrapping:** makes some minor changes to when next line help is automatically used ([5658b117](https://github.com/kbknapp/clap-rs/commit/5658b117aec3e03adff9c8c52a4c4bc1fcb4e1ff)) + + + +### v2.11.1 (2016-09-05) + + +#### Bug Fixes + +* **Settings:** fixes an issue where settings weren't propogated down through grand-child subcommands ([b3efc107](https://github.com/kbknapp/clap-rs/commit/b3efc107515d78517b20798ff3890b8a2b04498e), closes [#638](https://github.com/kbknapp/clap-rs/issues/638)) + +#### Features + +* **Errors:** Errors with custom description ([58512f2f](https://github.com/kbknapp/clap-rs/commit/58512f2fcb430745f1ee6ee8f1c67f62dc216c73)) + +#### Improvements + +* **help:** use term_size instead of home-grown solution ([fc7327e9](https://github.com/kbknapp/clap-rs/commit/fc7327e9dcf4258ef2baebf0a8714d9c0622855b)) + + + + +### v2.11.0 (2016-08-28) + + +#### Bug Fixes + +* **Groups:** fixes some usage strings that contain both args in groups and ones that conflict with each other ([3d782def](https://github.com/kbknapp/clap-rs/commit/3d782def57725e2de26ca5a5bc5cc2e40ddebefb), closes [#616](https://github.com/kbknapp/clap-rs/issues/616)) + +#### Documentation + +* moves docs to docs.rs ([03209d5e](https://github.com/kbknapp/clap-rs/commit/03209d5e1300906f00bafec1869c2047a92e5071), closes [#634](https://github.com/kbknapp/clap-rs/issues/634)) + +#### Improvements + +* **Completions:** uses standard conventions for bash completion files, namely '{bin}.bash-completion' ([27f5bbfb](https://github.com/kbknapp/clap-rs/commit/27f5bbfbcc9474c2f57c2b92b1feb898ae46ee70), closes [#567](https://github.com/kbknapp/clap-rs/issues/567)) +* **Help:** automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long ([150964c4](https://github.com/kbknapp/clap-rs/commit/150964c4e7124d54476c9d9b4b3f2406f0fd00e5), closes [#597](https://github.com/kbknapp/clap-rs/issues/597)) +* **YAML Errors:** vastly improves error messages when using YAML ([f43b7c65](https://github.com/kbknapp/clap-rs/commit/f43b7c65941c53adc0616b8646a21dc255862eb2), closes [#574](https://github.com/kbknapp/clap-rs/issues/574)) + +#### Features + +* adds App::with_defaults to automatically use crate_authors! and crate_version! macros ([5520bb01](https://github.com/kbknapp/clap-rs/commit/5520bb012c127dfd299fd55699443c744d8dcd5b), closes [#600](https://github.com/kbknapp/clap-rs/issues/600)) + + + + +### v2.10.4 (2016-08-25) + + +#### Bug Fixes + +* **Help Wrapping:** fixes a bug where help is wrapped incorrectly and causing a panic with some non-English characters ([d0b442c7](https://github.com/kbknapp/clap-rs/commit/d0b442c7beeecac9764406bc3bd171ced0b8825e), closes [#626](https://github.com/kbknapp/clap-rs/issues/626)) + + + + +### v2.10.3 (2016-08-25) + +#### Features + +* **Help:** adds new short hand way to use source formatting and ignore term width in help messages ([7dfdaf20](https://github.com/kbknapp/clap-rs/commit/7dfdaf200ebb5c431351a045b48f5e0f0d3f31db), closes [#625](https://github.com/kbknapp/clap-rs/issues/625)) + +#### Documentation + +* **Term Width:** adds details about set_term_width(0) ([00b8205d](https://github.com/kbknapp/clap-rs/commit/00b8205d22639d1b54b9c453c55c785aace52cb2)) + +#### Bug Fixes + +* **Unicode:** fixes two bugs where non-English characters were stripped or caused a panic with help wrapping ([763a5c92](https://github.com/kbknapp/clap-rs/commit/763a5c920e23efc74d190af0cb8b5dd714b2d67a), closes [#626](https://github.com/kbknapp/clap-rs/issues/626)) + + + + +### v2.10.2 (2016-08-22) + + +#### Bug Fixes + +* fixes a bug where the help is printed twice ([a643fb28](https://github.com/kbknapp/clap-rs/commit/a643fb283acd9905dc727c4579c5c9fa2ceaa7e7), closes [#623](https://github.com/kbknapp/clap-rs/issues/623)) + + + + +### v2.10.1 (2016-08-21) + + +#### Bug Fixes + +* **Help Subcommand:** fixes misleading usage string when using multi-level subcommmands ([e203515e](https://github.com/kbknapp/clap-rs/commit/e203515e3ac495b405dbba4f78fb6af148fd282e), closes [#618](https://github.com/kbknapp/clap-rs/issues/618)) + +#### Features + +* **YAML:** allows using lists or single values with arg declarations ([9ade2cd4](https://github.com/kbknapp/clap-rs/commit/9ade2cd4b268d6d7fe828319ce6a523c641b9c38), closes [#614](https://github.com/kbknapp/clap-rs/issues/614), [#613](https://github.com/kbknapp/clap-rs/issues/613)) + + + + +## v2.10.0 (2016-07-29) + + +#### Features + +* **Completions:** one can generate a basic fish completions script at compile time ([1979d2f2](https://github.com/kbknapp/clap-rs/commit/1979d2f2f3216e57d02a97e624a8a8f6cf867ed9)) + +#### Bug Fixes + +* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635)) + +#### Breaking Changes + +* **parser:** preserve external subcommand name ([875df243](https://github.com/kbknapp/clap-rs/commit/875df24316c266920a073c13bbefbf546bc1f635)) + +#### Documentation + +* **YAML:** fixes example 17's incorrect reference to arg_groups instead of groups ([b6c99e13](https://github.com/kbknapp/clap-rs/commit/b6c99e1377f918e78c16c8faced70a71607da931), closes [#601](https://github.com/kbknapp/clap-rs/issues/601)) + + + + +### 2.9.3 (2016-07-24) + + +#### Bug Fixes + +* fixes bug where only first arg in list of required_unless_one is recognized ([1fc3b55b](https://github.com/kbknapp/clap-rs/commit/1fc3b55bd6c8653b02e7c4253749c6b77737d2ac), closes [#575](https://github.com/kbknapp/clap-rs/issues/575)) +* **Settings:** fixes typo subcommandsrequired->subcommandrequired ([fc72cdf5](https://github.com/kbknapp/clap-rs/commit/fc72cdf591d30f5d9375d0b5cc2a2ff3e812f9f6), closes [#593](https://github.com/kbknapp/clap-rs/issues/593)) + +#### Features + +* **Completions:** adds the ability to generate completions to io::Write object ([9f62cf73](https://github.com/kbknapp/clap-rs/commit/9f62cf7378ba5acb5ce8c5bac89b4aa60c30755f)) +* **Settings:** Add unset_setting and unset_settings fns to App (#598) ([0ceba231](https://github.com/kbknapp/clap-rs/commit/0ceba231c6767cd6d88fdb1feeeea41deadf77ff), closes [#590](https://github.com/kbknapp/clap-rs/issues/590)) + + + +### 2.9.2 (2016-07-03) + + +#### Documentation + +* **Completions:** fixes the formatting of the Cargo.toml excerpt in the completions example ([722f2607](https://github.com/kbknapp/clap-rs/commit/722f2607beaef56b6a0e433db5fd09492d9f028c)) + +#### Bug Fixes + +* **Completions:** fixes bug where --help and --version short weren't added to the completion list ([e9f2438e](https://github.com/kbknapp/clap-rs/commit/e9f2438e2ce99af0ae570a2eaf541fc7f55b771b), closes [#536](https://github.com/kbknapp/clap-rs/issues/536)) + + + + +### 2.9.1 (2016-07-02) + + +#### Improvements + +* **Completions:** allows multiple completions to be built by namespacing with bin name ([57484b2d](https://github.com/kbknapp/clap-rs/commit/57484b2daeaac01c1026e8c84efc8bf099e0eb31)) + + + +## v2.9.0 (2016-07-01) + + +#### Documentation + +* **Completions:** + * fixes some errors in the completion docs ([9b359bf0](https://github.com/kbknapp/clap-rs/commit/9b359bf06255d3dad8f489308044b60a9d1e6a87)) + * adds documentation for completion scripts ([c6c519e4](https://github.com/kbknapp/clap-rs/commit/c6c519e40efd6c4533a9ef5efe8e74fd150391b7)) + +#### Features + +* **Completions:** + * one can now generate a bash completions script at compile time! ([e75b6c7b](https://github.com/kbknapp/clap-rs/commit/e75b6c7b75f729afb9eb1d2a2faf61dca7674634), closes [#376](https://github.com/kbknapp/clap-rs/issues/376)) + * completions now include aliases to subcommands, including all subcommand options ([0ab9f840](https://github.com/kbknapp/clap-rs/commit/0ab9f84052a8cf65b5551657f46c0c270841e634), closes [#556](https://github.com/kbknapp/clap-rs/issues/556)) + * completions now continue completing even after first completion ([18fc2e5b](https://github.com/kbknapp/clap-rs/commit/18fc2e5b5af63bf54a94b72cec5e1223d49f4806)) + * allows matching on possible values in options ([89cc2026](https://github.com/kbknapp/clap-rs/commit/89cc2026ba9ac69cf44c5254360bbf99236d4f89), closes [#557](https://github.com/kbknapp/clap-rs/issues/557)) + +#### Bug Fixes + +* **AllowLeadingHyphen:** fixes an issue where isn't ignored like it should be with this setting ([96c24c9a](https://github.com/kbknapp/clap-rs/commit/96c24c9a8fa1f85e06138d3cdd133e51659e19d2), closes [#558](https://github.com/kbknapp/clap-rs/issues/558)) + + +## v2.8.0 (2016-06-30) + + +#### Features + +* **Arg:** adds new setting `Arg::require_delimiter` which requires val delimiter to parse multiple values ([920b5595](https://github.com/kbknapp/clap-rs/commit/920b5595ed72abfb501ce054ab536067d8df2a66)) + +#### Bug Fixes + +* Declare term::Winsize as repr(C) ([5d663d90](https://github.com/kbknapp/clap-rs/commit/5d663d905c9829ce6e7a164f1f0896cdd70236dd)) + +#### Documentation + +* **Arg:** adds docs for ([49af4e38](https://github.com/kbknapp/clap-rs/commit/49af4e38a5dae2ab0a7fc3b4147e2c053d532484)) + + + + +### v2.7.1 (2016-06-29) + + +#### Bug Fixes + +* **Options:** + * options with multiple values and using delimiters no longer parse additional values after a trailing space ([cdc500bd](https://github.com/kbknapp/clap-rs/commit/cdc500bdde6abe238c36ade406ddafc2bafff583)) + * using options with multiple values and with an = no longer parse args after the trailing space as values ([290f61d0](https://github.com/kbknapp/clap-rs/commit/290f61d07177413cf082ada55526d83405f6d011)) + + + + +## v2.7.0 (2016-06-28) + + +#### Documentation + +* fix typos ([43b3d40b](https://github.com/kbknapp/clap-rs/commit/43b3d40b8c38b1571da75af86b5088be96cccec2)) +* **ArgGroup:** vastly improves ArgGroup docs by adding better examples ([9e5f4f5d](https://github.com/kbknapp/clap-rs/commit/9e5f4f5d734d630bca5535c3a0aa4fd4f9db3e39), closes [#534](https://github.com/kbknapp/clap-rs/issues/534)) + +#### Features + +* **ArgGroup:** one can now specify groups which require AT LEAST one of the args ([33689acc](https://github.com/kbknapp/clap-rs/commit/33689acc689b217a8c0ee439f1b1225590c38355), closes [#533](https://github.com/kbknapp/clap-rs/issues/533)) + +#### Bug Fixes + +* **App:** using `App::print_help` now prints the same as would have been printed by `--help` or the like ([e84cc018](https://github.com/kbknapp/clap-rs/commit/e84cc01836bbe0527e97de6db9889bd9e0fd6ba1), closes [#536](https://github.com/kbknapp/clap-rs/issues/536)) +* **Help:** + * prevents invoking help help and displaying incorrect help message ([e3d2893f](https://github.com/kbknapp/clap-rs/commit/e3d2893f377942a2d4cf3c6ff04524d0346e6fdb), closes [#538](https://github.com/kbknapp/clap-rs/issues/538)) + * subcommand help messages requested via help now correctly match --help ([08ad1cff](https://github.com/kbknapp/clap-rs/commit/08ad1cff4fec57224ea957a2891a057b323c01bc), closes [#539](https://github.com/kbknapp/clap-rs/issues/539)) + +#### Improvements + +* **ArgGroup:** Add multiple ArgGroups per Arg ([902e182f](https://github.com/kbknapp/clap-rs/commit/902e182f7a58aff11ff01e0a452abcdbdb2262aa), closes [#426](https://github.com/kbknapp/clap-rs/issues/426)) +* **Usage Strings:** `[FLAGS]` and `[ARGS]` are no longer blindly added to usage strings ([9b2e45b1](https://github.com/kbknapp/clap-rs/commit/9b2e45b170aff567b038d8b3368880b6046c10c6), closes [#537](https://github.com/kbknapp/clap-rs/issues/537)) +* **arg_enum!:** allows using meta items like repr(C) with arg_enum!s ([edf9b233](https://github.com/kbknapp/clap-rs/commit/edf9b2331c17a2cbcc13f961add4c55c2778e773), closes [#543](https://github.com/kbknapp/clap-rs/issues/543)) + + + + +## v2.6.0 (2016-06-14) + + +#### Improvements + +* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115)) +* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724)) +* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589)) +* **Aliases:** improves readability of asliases in help messages ([ca511de7](https://github.com/kbknapp/clap-rs/commit/ca511de71f5b8c2ac419f1b188658e8c63b67846), closes [#526](https://github.com/kbknapp/clap-rs/issues/526), [#529](https://github.com/kbknapp/clap-rs/issues/529)) +* **Usage Strings:** improves the default usage string when only a single positional arg is present ([ec86f2da](https://github.com/kbknapp/clap-rs/commit/ec86f2dada1545a63fc72355e22fcdc4c466c215), closes [#518](https://github.com/kbknapp/clap-rs/issues/518)) + +#### Features + +* **Help:** allows wrapping at specified term width (Even on Windows!) ([1761dc0d](https://github.com/kbknapp/clap-rs/commit/1761dc0d27d0d621229d792be40c36fbf65c3014), closes [#451](https://github.com/kbknapp/clap-rs/issues/451)) +* **Settings:** + * adds new setting to stop delimiting values with -- or TrailingVarArg ([fc3e0f5a](https://github.com/kbknapp/clap-rs/commit/fc3e0f5afda6d24cdb3c4676614beebe13e1e870), closes [#511](https://github.com/kbknapp/clap-rs/issues/511)) + * one can now set an AppSetting which is propogated down through child subcommands ([e2341835](https://github.com/kbknapp/clap-rs/commit/e23418351a3b98bf08dfd7744bc14377c70d59ee), closes [#519](https://github.com/kbknapp/clap-rs/issues/519)) +* **Subcommands:** adds support for visible aliases ([7b10e7f8](https://github.com/kbknapp/clap-rs/commit/7b10e7f8937a07fdb8d16a6d8df79ce78d080cd3), closes [#522](https://github.com/kbknapp/clap-rs/issues/522)) + +#### Bug Fixes + +* fixes bug where args are printed out of order with templates ([05abb534](https://github.com/kbknapp/clap-rs/commit/05abb534864764102031a0d402e64ac65867aa87)) +* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514)) +* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106)) +* **Help:** `App::before_help` and `App::after_help` now correctly wrap ([1f4da767](https://github.com/kbknapp/clap-rs/commit/1f4da7676e6e71aa8dda799f3eeefad105a47819), closes [#516](https://github.com/kbknapp/clap-rs/issues/516)) +* **Settings:** fixes bug where new color settings couldn't be converted from strs ([706a7c11](https://github.com/kbknapp/clap-rs/commit/706a7c11b0900be594de6d5a3121938eff197602)) +* **Subcommands:** subcommands with aliases now display help of the aliased subcommand ([5354d14b](https://github.com/kbknapp/clap-rs/commit/5354d14b51f189885ba110e01e6b76cca3752992), closes [#521](https://github.com/kbknapp/clap-rs/issues/521)) +* **Windows:** fixes a failing windows build ([01e7dfd6](https://github.com/kbknapp/clap-rs/commit/01e7dfd6c07228c0be6695b3c7bf9370d82860d4)) +* **YAML:** adds missing YAML methods for App and Arg ([e468faf3](https://github.com/kbknapp/clap-rs/commit/e468faf3f05950fd9f72d84b69aa2061e91c6c64), closes [#528](https://github.com/kbknapp/clap-rs/issues/528)) + + + + +### v2.5.2 (2016-05-31) + + +#### Improvements + +* removes extra newline from help output ([86e61d19](https://github.com/kbknapp/clap-rs/commit/86e61d19a748fb9870fcf1175308984e51ca1115)) +* allows printing version to any io::Write object ([921f5f79](https://github.com/kbknapp/clap-rs/commit/921f5f7916597f1d028cd4a65bfe76a01c801724)) +* removes extra newline when printing version ([7e2e2cbb](https://github.com/kbknapp/clap-rs/commit/7e2e2cbb4a8a0f050bb8072a376f742fc54b8589)) + +#### Bug Fixes + +* fixes bug where args are printed out of order with templates ([3935431d](https://github.com/kbknapp/clap-rs/commit/3935431d5633f577c0826ae2142794b301f4b8ca)) +* fixes bug where one can't override version or help flags ([90d7d6a2](https://github.com/kbknapp/clap-rs/commit/90d7d6a2ea8240122dd9bf8d82d3c4f5ebb5c703), closes [#514](https://github.com/kbknapp/clap-rs/issues/514)) +* fixes issue where before_help wasn't printed ([b3faff60](https://github.com/kbknapp/clap-rs/commit/b3faff6030f76a23f26afcfa6a90169002ed7106)) + +#### Documentation + +* inter-links all types and pages ([3312893d](https://github.com/kbknapp/clap-rs/commit/3312893ddaef3f44d68d8d26ed3d08010be50d97), closes [#505](https://github.com/kbknapp/clap-rs/issues/505)) +* makes all publicly available types viewable in docs ([52ca6505](https://github.com/kbknapp/clap-rs/commit/52ca6505b4fec7b5c2d53d160c072d395eb21da6)) + + +### v2.5.1 (2016-05-11) + + +#### Bug Fixes + +* **Subcommand Aliases**: fixes lifetime issue when setting multiple aliases at once ([ac42f6cf0](https://github.com/kbknapp/clap-rs/commit/ac42f6cf0de6c4920f703807d63061803930b18d)) + + +## v2.5.0 (2016-05-10) + + +#### Improvements + +* **SubCommand Aliases:** adds feature to yaml configs too ([69592195](https://github.com/kbknapp/clap-rs/commit/695921954dde46dfd483399dcdef482c9dd7f34a)) + +#### Features + +* **SubCommands:** adds support for subcommand aliases ([66b4dea6](https://github.com/kbknapp/clap-rs/commit/66b4dea65c44d8f77ff522238a9237aed1bcab6d), closes [#469](https://github.com/kbknapp/clap-rs/issues/469)) + + + +### v2.4.3 (2016-05-10) + + +#### Bug Fixes + +* **Usage Strings:** + * now properly dedups args that are also in groups ([3ca0947c](https://github.com/kbknapp/clap-rs/commit/3ca0947c166b4f8525752255e3a4fa6565eb9689), closes [#498](https://github.com/kbknapp/clap-rs/issues/498)) + * removes duplicate groups from usage strings ([f574fb8a](https://github.com/kbknapp/clap-rs/commit/f574fb8a7cde4d4a2fa4c4481d59be2d0f135427)) + +#### Improvements + +* **Groups:** formats positional args in groups in a better way ([fef11154](https://github.com/kbknapp/clap-rs/commit/fef11154fb7430d1cbf04a672aabb366e456a368)) +* **Help:** + * moves positionals to standard <> formatting ([03dfe5ce](https://github.com/kbknapp/clap-rs/commit/03dfe5ceff1d63f172788ff688567ddad9fe119b)) + * default help subcommand string has been shortened ([5b7fe8e4](https://github.com/kbknapp/clap-rs/commit/5b7fe8e4161e43ab19e2e5fcf55fbe46791134e9), closes [#494](https://github.com/kbknapp/clap-rs/issues/494)) + + +### v2.4.3 (2016-05-10) + +* Ghost Release + + +### v2.4.3 (2016-05-10) + +* Ghost Release + + +## v2.4.0 (2016-05-02) + + +#### Features + +* **Help:** adds support for displaying info before help message ([29fbfa3b](https://github.com/kbknapp/clap-rs/commit/29fbfa3b963f2f3ca7704bf5d3e1201531baa373)) +* **Required:** adds allowing args that are required unless certain args are present ([af1f7916](https://github.com/kbknapp/clap-rs/commit/af1f79168390ea7da4074d0d9777de458ea64971)) + +#### Documentation + +* hides formatting from docs ([cb708093](https://github.com/kbknapp/clap-rs/commit/cb708093a7cd057f08c98b7bd1ed54c2db86ae7e)) +* **required_unless:** adds docs and examples for required_unless ([ca727b52](https://github.com/kbknapp/clap-rs/commit/ca727b52423b9883acd88b2f227b2711bc144573)) + +#### Bug Fixes + +* **Required Args:** fixes issue where missing required args are sometimes duplicatd in error messages ([3beebd81](https://github.com/kbknapp/clap-rs/commit/3beebd81e7bc2faa4115ac109cf570e512c5477f), closes [#492](https://github.com/kbknapp/clap-rs/issues/492)) + + + +## v2.3.0 (2016-04-18) + + +#### Improvements + +* **macros.rs:** Added write_nspaces macro (a new version of write_spaces) ([9d757e86](https://github.com/kbknapp/clap-rs/commit/9d757e8678e334e5a740ac750c76a9ed4e785cba)) +* **parser.rs:** + * Provide a way to create a usage string without the USAGE: title ([a91d378b](https://github.com/kbknapp/clap-rs/commit/a91d378ba0c91b5796457f8c6e881b13226ab735)) + * Make Parser's create_usage public allowing to have function outside the parser to generate the help ([d51945f8](https://github.com/kbknapp/clap-rs/commit/d51945f8b82ebb0963f4f40b384a9e8335783091)) + * Expose Parser's flags, opts and positionals argument as iterators ([9b23e7ee](https://github.com/kbknapp/clap-rs/commit/9b23e7ee40e51f7a823644c4496be955dc6c9d3a)) +* **src/args:** Exposes argument display order by introducing a new Trait ([1321630e](https://github.com/kbknapp/clap-rs/commit/1321630ef56955f152c73376d4d85cceb0bb4a12)) +* **srs/args:** Added longest_filter to AnyArg trait ([65b3f667](https://github.com/kbknapp/clap-rs/commit/65b3f667532685f854c699ddd264d326599cf7e5)) + +#### Features + +* **Authors Macro:** adds a crate_authors macro ([38fb59ab](https://github.com/kbknapp/clap-rs/commit/38fb59abf480eb2b6feca269097412f8b00b5b54), closes [#447](https://github.com/kbknapp/clap-rs/issues/447)) +* **HELP:** + * implements optional colored help messages ([abc8f669](https://github.com/kbknapp/clap-rs/commit/abc8f669c3c8193ffc3a3b0ac6c3ac2198794d4f), closes [#483](https://github.com/kbknapp/clap-rs/issues/483)) + * Add a Templated Help system. ([81e121ed](https://github.com/kbknapp/clap-rs/commit/81e121edd616f7285593f11120c63bcccae0d23e)) + +#### Bug Fixes + +* **HELP:** Adjust Help to semantic changes introduced in 6933b84 ([8d23806b](https://github.com/kbknapp/clap-rs/commit/8d23806bd67530ad412c34a1dcdcb1435555573d)) + + +### v2.2.6 (2016-04-11) + +#### Bug Fixes + +* **Arg Groups**: fixes bug where arg name isn't printed properly ([3019a685](https://github.com/kbknapp/clap-rs/commit/3019a685eee747ccbe6be09ad5dddce0b1d1d4db), closes [#476](https://github.com/kbknapp/clap-rs/issues/476)) + + + +### v2.2.5 (2016-04-03) + + +#### Bug Fixes + +* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470)) +* **Help Message:** fixes bug where arg name is printed twice ([71acf1d5](https://github.com/kbknapp/clap-rs/commit/71acf1d576946658b8bbdb5ae79e6716c43a030f), closes [#472](https://github.com/kbknapp/clap-rs/issues/472)) + + + +### v2.2.4 (2016-03-30) + + +#### Bug Fixes + +* fixes compiling with debug cargo feature ([d4b55450](https://github.com/kbknapp/clap-rs/commit/d4b554509928031ac0808076178075bb21f8c1da)) +* **Empty Values:** fixes bug where empty values weren't stored ([885d166f](https://github.com/kbknapp/clap-rs/commit/885d166f04eb3fb581898ae5818c6c8032e5a686), closes [#470](https://github.com/kbknapp/clap-rs/issues/470)) + + + + +### v2.2.3 (2016-03-28) + + +#### Bug Fixes + +* **Help Subcommand:** fixes issue where help and version flags weren't properly displayed ([205b07bf](https://github.com/kbknapp/clap-rs/commit/205b07bf2e6547851f1290f8cd6b169145e144f1), closes [#466](https://github.com/kbknapp/clap-rs/issues/466)) + + +### v2.2.2 (2016-03-27) + + +#### Bug Fixes + +* **Help Message:** fixes bug with wrapping in the middle of a unicode sequence ([05365ddc](https://github.com/kbknapp/clap-rs/commit/05365ddcc252e4b49e7a75e199d6001a430bd84d), closes [#456](https://github.com/kbknapp/clap-rs/issues/456)) +* **Usage Strings:** fixes small bug where -- would appear needlessly in usage strings ([6933b849](https://github.com/kbknapp/clap-rs/commit/6933b8491c2a7e28cdb61b47dcf10caf33c2f78a), closes [#461](https://github.com/kbknapp/clap-rs/issues/461)) + + + +### 2.2.1 (2016-03-16) + + +#### Features + +* **Help Message:** wraps and aligns the help message of subcommands ([813d75d0](https://github.com/kbknapp/clap-rs/commit/813d75d06fbf077c65762608c0fa5e941cfc393c), closes [#452](https://github.com/kbknapp/clap-rs/issues/452)) + +#### Bug Fixes + +* **Help Message:** fixes a bug where small terminal sizes causing a loop ([1d73b035](https://github.com/kbknapp/clap-rs/commit/1d73b0355236923aeaf6799abc759762ded7e1d0), closes [#453](https://github.com/kbknapp/clap-rs/issues/453)) + + + +## v2.2.0 (2016-03-15) + + +#### Features + +* **Help Message:** can auto wrap and aligning help text to term width ([e36af026](https://github.com/kbknapp/clap-rs/commit/e36af0266635f23e85e951b9088d561e9a5d1bf6), closes [#428](https://github.com/kbknapp/clap-rs/issues/428)) +* **Help Subcommand:** adds support passing additional subcommands to help subcommand ([2c12757b](https://github.com/kbknapp/clap-rs/commit/2c12757bbdf34ce481f3446c074e24c09c2e60fd), closes [#416](https://github.com/kbknapp/clap-rs/issues/416)) +* **Opts and Flags:** adds support for custom ordering in help messages ([9803b51e](https://github.com/kbknapp/clap-rs/commit/9803b51e799904c0befaac457418ee766ccc1ab9)) +* **Settings:** adds support for automatically deriving custom display order of args ([ad86e433](https://github.com/kbknapp/clap-rs/commit/ad86e43334c4f70e86909689a088fb87e26ff95a), closes [#444](https://github.com/kbknapp/clap-rs/issues/444)) +* **Subcommands:** adds support for custom ordering in help messages ([7d2a2ed4](https://github.com/kbknapp/clap-rs/commit/7d2a2ed413f5517d45988eef0765cdcd663b6372), closes [#442](https://github.com/kbknapp/clap-rs/issues/442)) + +#### Bug Fixes + +* **From Usage:** fixes a bug where adding empty lines werent ignored ([c5c58c86](https://github.com/kbknapp/clap-rs/commit/c5c58c86b9c503d8de19da356a5a5cffb59fbe84)) + +#### Documentation + +* **Groups:** explains required ArgGroups better ([4ff0205b](https://github.com/kbknapp/clap-rs/commit/4ff0205b85a45151b59bbaf090a89df13438380f), closes [#439](https://github.com/kbknapp/clap-rs/issues/439)) + + +### v2.1.2 (2016-02-24) + +#### Bug Fixes + +* **Nightly:** fixes failing nightly build ([d752c170](https://github.com/kbknapp/clap-rs/commit/d752c17029598b19037710f204b7943f0830ae75), closes [#434](https://github.com/kbknapp/clap-rs/issues/434)) + + + +### v2.1.1 (2016-02-19) + + +#### Documentation + +* **AppSettings:** clarifies that AppSettings do not propagate ([3c8db0e9](https://github.com/kbknapp/clap-rs/commit/3c8db0e9be1d24edaad364359513cbb02abb4186), closes [#429](https://github.com/kbknapp/clap-rs/issues/429)) +* **Arg Examples:** adds better examples ([1e79cccc](https://github.com/kbknapp/clap-rs/commit/1e79cccc12937bc0e7cd2aad8e404410798e9fff)) + +#### Improvements + +* **Help:** adds setting for next line help by arg ([066df748](https://github.com/kbknapp/clap-rs/commit/066df7486e684cf50a8479a356a12ba972c34ce1), closes [#427](https://github.com/kbknapp/clap-rs/issues/427)) + + + +## v2.1.0 (2016-02-10) + + +#### Features + +* **Defult Values:** adds support for default values in args ([73211952](https://github.com/kbknapp/clap-rs/commit/73211952964a79d97b434dd567e6d7d34be7feb5), closes [#418](https://github.com/kbknapp/clap-rs/issues/418)) + +#### Documentation + +* **Default Values:** adds better examples and notes for default values ([9facd74f](https://github.com/kbknapp/clap-rs/commit/9facd74f843ef3807c5d35259558a344e6c25905)) + + + +### v2.0.6 (2016-02-09) + + +#### Improvements + +* **Positional Arguments:** now displays value name if appropriate ([f0a99916](https://github.com/kbknapp/clap-rs/commit/f0a99916c59ce675515c6dcdfe9a40b130510908), closes [#420](https://github.com/kbknapp/clap-rs/issues/420)) + + + +### v2.0.5 (2016-02-05) + + +#### Bug Fixes + +* **Multiple Values:** fixes bug where number_of_values wasnt respected ([72c387da](https://github.com/kbknapp/clap-rs/commit/72c387da0bb8a6f526f863770f08bb8ca0d3de03)) + + + +### v2.0.4 (2016-02-04) + + +#### Bug Fixes + +* adds support for building ArgGroups from standalone YAML ([fcbc7e12](https://github.com/kbknapp/clap-rs/commit/fcbc7e12f5d7b023b8f30cba8cad28a01cf6cd26)) +* Stop lonely hyphens from causing panic ([85b11468](https://github.com/kbknapp/clap-rs/commit/85b11468b0189d5cc15f1cfac5db40d17a0077dc), closes [#410](https://github.com/kbknapp/clap-rs/issues/410)) +* **AppSettings:** fixes bug where subcmds didn't receive parent ver ([a62e4527](https://github.com/kbknapp/clap-rs/commit/a62e452754b3b0e3ac9a15aa8b5330636229ead1)) + + +### v2.0.3 (2016-02-02) + + +#### Improvements + +* **values:** adds support for up to u64::max values per arg ([c7abf7d7](https://github.com/kbknapp/clap-rs/commit/c7abf7d7611e317b0d31d97632e3d2e13570947c)) +* **occurrences:** Allow for more than 256 occurrences of an argument. ([3731ddb3](https://github.com/kbknapp/clap-rs/commit/3731ddb361163f3d6b86844362871e48c80fa530)) + +#### Features + +* **AppSettings:** adds HidePossibleValuesInHelp to skip writing those values ([cdee7a0e](https://github.com/kbknapp/clap-rs/commit/cdee7a0eb2beeec723cb98acfacf03bf629c1da3)) + +#### Bug Fixes + +* **value_t_or_exit:** fixes typo which causes value_t_or_exit to return a Result ([ee96baff](https://github.com/kbknapp/clap-rs/commit/ee96baffd306cb8d20ddc5575cf739bb1a6354e8)) + + + +### v2.0.2 (2016-01-31) + + +#### Improvements + +* **arg_enum:** enum declared with arg_enum returns [&'static str; #] instead of Vec ([9c4b8a1a](https://github.com/kbknapp/clap-rs/commit/9c4b8a1a6b12949222f17d1074578ad7676b9c0d)) + +#### Bug Fixes + +* clap_app! should be gated by unstable, not nightly feature ([0c8b84af](https://github.com/kbknapp/clap-rs/commit/0c8b84af6161d5baf683688eafc00874846f83fa)) +* **SubCommands:** fixed where subcmds weren't recognized after mult args ([c19c17a8](https://github.com/kbknapp/clap-rs/commit/c19c17a8850602990e24347aeb4427cf43316223), closes [#405](https://github.com/kbknapp/clap-rs/issues/405)) +* **Usage Parser:** fixes a bug where literal single quotes weren't allowed in help strings ([0bcc7120](https://github.com/kbknapp/clap-rs/commit/0bcc71206478074769e311479b34a9f74fe80f5c), closes [#406](https://github.com/kbknapp/clap-rs/issues/406)) + + + +### v2.0.1 (2016-01-30) + + +#### Bug Fixes + +* fixes cargo features to NOT require nightly with unstable features ([dcbcc60c](https://github.com/kbknapp/clap-rs/commit/dcbcc60c9ba17894be636472ea4b07a82d86a9db), closes [#402](https://github.com/kbknapp/clap-rs/issues/402)) + + + +## v2.0.0 (2016-01-28) + + +#### Improvements + +* **From Usage:** vastly improves the usage parser ([fa3a2f86](https://github.com/kbknapp/clap-rs/commit/fa3a2f86bd674c5eb07128c95098fab7d1437247), closes [#350](https://github.com/kbknapp/clap-rs/issues/350)) + +#### Features + +* adds support for external subcommands ([177fe5cc](https://github.com/kbknapp/clap-rs/commit/177fe5cce745c2164a8e38c23be4c4460d2d7211), closes [#372](https://github.com/kbknapp/clap-rs/issues/372)) +* adds support values with a leading hyphen ([e4d429b9](https://github.com/kbknapp/clap-rs/commit/e4d429b9d52e95197bd0b572d59efacecf305a59), closes [#385](https://github.com/kbknapp/clap-rs/issues/385)) +* adds support for turning off the value delimiter ([508db850](https://github.com/kbknapp/clap-rs/commit/508db850a87c2e251cf6b6ddead9ad56b29f9e57), closes [#352](https://github.com/kbknapp/clap-rs/issues/352)) +* adds support changing the value delimiter ([dafeae8a](https://github.com/kbknapp/clap-rs/commit/dafeae8a526162640f6a68da434370c64d190889), closes [#353](https://github.com/kbknapp/clap-rs/issues/353)) +* adds support for comma separated values ([e69da6af](https://github.com/kbknapp/clap-rs/commit/e69da6afcd2fe48a3c458ca031db40997f860eda), closes [#348](https://github.com/kbknapp/clap-rs/issues/348)) +* adds support with options with optional values ([4555736c](https://github.com/kbknapp/clap-rs/commit/4555736cad01441dcde4ea84a285227e0844c16e), closes [#367](https://github.com/kbknapp/clap-rs/issues/367)) +* **UTF-8:** adds support for invalid utf8 in values ([c5c59dec](https://github.com/kbknapp/clap-rs/commit/c5c59dec0bc33b86b2e99d30741336f17ec84282), closes [#269](https://github.com/kbknapp/clap-rs/issues/269)) +* **v2:** implementing the base of 2.x ([a3536054](https://github.com/kbknapp/clap-rs/commit/a3536054512ba833533dc56615ce3663d884381c)) + +#### Bug Fixes + +* fixes nightly build with new lints ([17599195](https://github.com/kbknapp/clap-rs/commit/175991956c37dc83ba9c49396e927a1cb65c5b11)) +* fixes Windows build for 2x release ([674c9b48](https://github.com/kbknapp/clap-rs/commit/674c9b48c7c92079cb180cc650a9e39f34781c32), closes [#392](https://github.com/kbknapp/clap-rs/issues/392)) +* fixes yaml build for 2x base ([adceae64](https://github.com/kbknapp/clap-rs/commit/adceae64c8556d00ab715677377b216f9f468ad7)) + +#### Documentation + +* updates examples for 2x release ([1303b360](https://github.com/kbknapp/clap-rs/commit/1303b3607468f362ab1b452d5614c1a064dc69b4), closes [#394](https://github.com/kbknapp/clap-rs/issues/394)) +* updates examples for 2x release ([0a011f31](https://github.com/kbknapp/clap-rs/commit/0a011f3142aec338d388a6c8bfe22fa7036021bb), closes [#394](https://github.com/kbknapp/clap-rs/issues/394)) +* updates documentation for v2 release ([8d51724e](https://github.com/kbknapp/clap-rs/commit/8d51724ef73dfde5bb94fb9466bc5463a1cc1502)) +* updating docs for 2x release ([576d0e0e](https://github.com/kbknapp/clap-rs/commit/576d0e0e2c7b8f386589179bbf7419b93abacf1c)) +* **README.md:** + * updates readme for v2 release ([acaba01a](https://github.com/kbknapp/clap-rs/commit/acaba01a353c12144b9cd9a3ce447400691849b0), closes [#393](https://github.com/kbknapp/clap-rs/issues/393)) + * fix typo and make documentation conspicuous ([07b9f614](https://github.com/kbknapp/clap-rs/commit/07b9f61495d927f69f7abe6c0d85253f0f4e6107)) + +#### BREAKING CHANGES + +* **Fewer liftimes! Yay!** + * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>` + * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>` + * `ArgMatches<'a, 'b>` => `ArgMatches<'a>` +* **Simply Renamed** + * `App::arg_group` => `App::group` + * `App::arg_groups` => `App::groups` + * `ArgGroup::add` => `ArgGroup::arg` + * `ArgGroup::add_all` => `ArgGroup::args` + * `ClapError` => `Error` + * struct field `ClapError::error_type` => `Error::kind` + * `ClapResult` => `Result` + * `ClapErrorType` => `ErrorKind` +* **Removed Deprecated Functions and Methods** + * `App::subcommands_negate_reqs` + * `App::subcommand_required` + * `App::arg_required_else_help` + * `App::global_version(bool)` + * `App::versionless_subcommands` + * `App::unified_help_messages` + * `App::wait_on_error` + * `App::subcommand_required_else_help` + * `SubCommand::new` + * `App::error_on_no_subcommand` + * `Arg::new` + * `Arg::mutually_excludes` + * `Arg::mutually_excludes_all` + * `Arg::mutually_overrides_with` + * `simple_enum!` +* **Renamed Error Variants** + * `InvalidUnicode` => `InvalidUtf8` + * `InvalidArgument` => `UnknownArgument` +* **Usage Parser** + * Value names can now be specified inline, i.e. `-o, --option 'some option which takes two files'` + * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code** +* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code) +* `crate_version!` returns `&'static str` instead of `String` +* Using the `clap_app!` macro requires compiling with the `unstable` feature because the syntax could change slightly in the future + + + +### v1.5.5 (2016-01-04) + + +#### Bug Fixes + +* fixes an issue where invalid short args didn't cause an error ([c9bf7e44](https://github.com/kbknapp/clap-rs/commit/c9bf7e4440bd2f9b524ea955311d433c40a7d1e0)) +* prints the name in version and help instead of binary name ([8f3817f6](https://github.com/kbknapp/clap-rs/commit/8f3817f665c0cab6726bc16c56a53b6a61e44448), closes [#368](https://github.com/kbknapp/clap-rs/issues/368)) +* fixes an intentional panic issue discovered via clippy ([ea83a3d4](https://github.com/kbknapp/clap-rs/commit/ea83a3d421ea8856d4cac763942834d108b71406)) + + + +### v1.5.4 (2015-12-18) + + +#### Examples + +* **17_yaml:** conditinonally compile 17_yaml example ([575de089](https://github.com/kbknapp/clap-rs/commit/575de089a3e240c398cb10e6cf5a5c6b68662c01)) + +#### Improvements + +* clippy improvements ([99cdebc2](https://github.com/kbknapp/clap-rs/commit/99cdebc23da3a45a165f14b27bebeb2ed828a2ce)) + +#### Bug Fixes + + +* **errors:** return correct error type in WrongNumValues error builder ([5ba8ba9d](https://github.com/kbknapp/clap-rs/commit/5ba8ba9dcccdfa74dd1c44260e64b359bbb36be6)) +* ArgRequiredElseHelp setting now takes precedence over missing required args ([faad83fb](https://github.com/kbknapp/clap-rs/commit/faad83fbef6752f3093b6e98fca09a9449b830f4), closes [#362](https://github.com/kbknapp/clap-rs/issues/362)) + + + +### v1.5.3 (2015-11-20) + + +#### Bug Fixes + +* **Errors:** fixes some instances when errors are missing a final newline ([c4d2b171](https://github.com/kbknapp/clap-rs/commit/c4d2b1711994479ad64ee52b6b49d2ceccbf2118)) + + + + + +### v1.5.2 (2015-11-14) + + +#### Bug Fixes + +* **Errors:** fixes a compiling bug when built on Windows or without the color feature ([a35f7634](https://github.com/kbknapp/clap-rs/commit/a35f76346fe6ecc88dda6a1eb13627186e7ce185)) + + + + +### v1.5.1 (2015-11-13) + + +#### Bug Fixes + +* **Required Args:** fixes a bug where required args are not correctly accounted for ([f03b88a9](https://github.com/kbknapp/clap-rs/commit/f03b88a9766b331a63879bcd747687f2e5a2661b), closes [#343](https://github.com/kbknapp/clap-rs/issues/343)) + + + + +## v1.5.0 (2015-11-13) + + +#### Bug Fixes + +* fixes a bug with required positional args in usage strings ([c6858f78](https://github.com/kbknapp/clap-rs/commit/c6858f78755f8e860204323c828c8355a066dc83)) + +#### Documentation + +* **FAQ:** updates readme with slight changes to FAQ ([a4ef0fab](https://github.com/kbknapp/clap-rs/commit/a4ef0fab73c8dc68f1b138965d1340459c113398)) + +#### Improvements + +* massive errors overhaul ([cdc29175](https://github.com/kbknapp/clap-rs/commit/cdc29175bc9c53e5b4aec86cbc04c1743154dae6)) +* **ArgMatcher:** huge refactor and deduplication of code ([8988853f](https://github.com/kbknapp/clap-rs/commit/8988853fb8825e8f841fde349834cc12cdbad081)) +* **Errors:** errors have been vastly improved ([e59bc0c1](https://github.com/kbknapp/clap-rs/commit/e59bc0c16046db156a88ba71a037db05028e995c)) +* **Traits:** refactoring some configuration into traits ([5800cdec](https://github.com/kbknapp/clap-rs/commit/5800cdec6dce3def4242b9f7bd136308afb19685)) + +#### Performance + +* **App:** + * more BTreeMap->Vec, Opts and SubCmds ([bc4495b3](https://github.com/kbknapp/clap-rs/commit/bc4495b32ec752b6c4b29719e831c043ef2a26ce)) + * changes flags BTreeMap->Vec ([d357640f](https://github.com/kbknapp/clap-rs/commit/d357640fab55e5964fe83efc3c771e53aa3222fd)) + * removed unneeded BTreeMap ([78971fd6](https://github.com/kbknapp/clap-rs/commit/78971fd68d7dc5c8e6811b4520cdc54e4188f733)) + * changes BTreeMap to VecMap in some instances ([64b921d0](https://github.com/kbknapp/clap-rs/commit/64b921d087fdd03775c95ba0bcf65d3f5d36f812)) + * removed excess clones ([ec0089d4](https://github.com/kbknapp/clap-rs/commit/ec0089d42ed715d293fb668d3a90b0db0aa3ec39)) + + + + +### v1.4.7 (2015-11-03) + + +#### Documentation + +* Clarify behavior of Arg::multiple with options. ([434f497a](https://github.com/kbknapp/clap-rs/commit/434f497ab6d831f8145cf09278c97ca6ee6c6fe7)) +* Fix typos and improve grammar. ([c1f66b5d](https://github.com/kbknapp/clap-rs/commit/c1f66b5de7b5269fbf8760a005ef8c645edd3229)) + +#### Bug Fixes + +* **Error Status:** fixes bug where --help and --version return non-zero exit code ([89b51fdf](https://github.com/kbknapp/clap-rs/commit/89b51fdf8b1ab67607567344e2317ff1a757cb12)) + + + + +### v1.4.6 (2015-10-29) + + +#### Features + +* allows parsing without a binary name for daemons and interactive CLIs ([aff89d57](https://github.com/kbknapp/clap-rs/commit/aff89d579b5b85c3dc81b64f16d5865299ec39a2), closes [#318](https://github.com/kbknapp/clap-rs/issues/318)) + +#### Bug Fixes + +* **Errors:** tones down quoting in some error messages ([34ce59ed](https://github.com/kbknapp/clap-rs/commit/34ce59ede53bfa2eef722c74881cdba7419fd9c7), closes [#309](https://github.com/kbknapp/clap-rs/issues/309)) +* **Help and Version:** only builds help and version once ([e3be87cf](https://github.com/kbknapp/clap-rs/commit/e3be87cfc095fc41c9811adcdc6d2b079f237d5e)) +* **Option Args:** fixes bug with args and multiple values ([c9a9548a](https://github.com/kbknapp/clap-rs/commit/c9a9548a8f96cef8a3dd9a980948325fbbc1b91b), closes [#323](https://github.com/kbknapp/clap-rs/issues/323)) +* **POSIX Overrides:** fixes bug where required args are overridden ([40ed2b50](https://github.com/kbknapp/clap-rs/commit/40ed2b50c3a9fe88bfdbaa43cef9fd6493ecaa8e)) +* **Safe Matches:** using 'safe' forms of the get_matches family no longer exit the process ([c47025dc](https://github.com/kbknapp/clap-rs/commit/c47025dca2b3305dea0a0acfdd741b09af0c0d05), closes [#256](https://github.com/kbknapp/clap-rs/issues/256)) +* **Versionless SubCommands:** fixes a bug where the -V flag was needlessly built ([27df8b9d](https://github.com/kbknapp/clap-rs/commit/27df8b9d98d13709dad3929a009f40ebff089a1a), closes [#329](https://github.com/kbknapp/clap-rs/issues/329)) + +#### Documentation + +* adds comparison in readme ([1a8bf31e](https://github.com/kbknapp/clap-rs/commit/1a8bf31e7a6b87ce48a66af2cde1645b2dd5bc95), closes [#325](https://github.com/kbknapp/clap-rs/issues/325)) + + + + +### v1.4.5 (2015-10-06) + + +#### Bug Fixes + +* fixes crash on invalid arg error ([c78ce128](https://github.com/kbknapp/clap-rs/commit/c78ce128ebbe7b8f730815f8176c29d76f4ade8c)) + + + + +### v1.4.4 (2015-10-06) + + +#### Documentation + +* clean up some formatting ([b7df92d7](https://github.com/kbknapp/clap-rs/commit/b7df92d7ea25835701dd22ddff984b9749f48a00)) +* move the crate-level docs to top of the lib.rs file ([d7233bf1](https://github.com/kbknapp/clap-rs/commit/d7233bf122dbf80ba8fc79e5641be2df8af10e7a)) +* changes doc comments to rustdoc comments ([34b601be](https://github.com/kbknapp/clap-rs/commit/34b601be5fdde76c1a0859385b359b96d66b8732)) +* fixes panic in 14_groups example ([945b00a0](https://github.com/kbknapp/clap-rs/commit/945b00a0c27714b63bdca48d003fe205fcfdc578), closes [#295](https://github.com/kbknapp/clap-rs/issues/295)) +* avoid suggesting star dependencies. ([d33228f4](https://github.com/kbknapp/clap-rs/commit/d33228f40b5fefb84cf3dd51546bfb340dcd9f5a)) +* **Rustdoc:** adds portions of the readme to main rustdoc page ([6f9ee181](https://github.com/kbknapp/clap-rs/commit/6f9ee181e69d90bd4206290e59d6f3f1e8f0cbb2), closes [#293](https://github.com/kbknapp/clap-rs/issues/293)) + +#### Bug Fixes + +* grammar error in some conflicting option errors ([e73b07e1](https://github.com/kbknapp/clap-rs/commit/e73b07e19474323ad2260da66abbf6a6d4ecbd4f)) +* **Unified Help:** sorts both flags and options as a unified category ([2a223dad](https://github.com/kbknapp/clap-rs/commit/2a223dad82901fa2e74baad3bfc4c7b94509300f)) +* **Usage:** fixes a bug where required args aren't filtered properly ([72b453dc](https://github.com/kbknapp/clap-rs/commit/72b453dc170af3050bb123d35364f6da77fc06d7), closes [#277](https://github.com/kbknapp/clap-rs/issues/277)) +* **Usage Strings:** fixes a bug ordering of elements in usage strings ([aaf0d6fe](https://github.com/kbknapp/clap-rs/commit/aaf0d6fe7aa2403e76096c16204d254a9ee61ee2), closes [#298](https://github.com/kbknapp/clap-rs/issues/298)) + +#### Features + +* supports -aValue style options ([0e3733e4](https://github.com/kbknapp/clap-rs/commit/0e3733e4fec2015c2d566a51432dcd92cb69cad3)) +* **Trailing VarArg:** adds opt-in setting for final arg being vararg ([27018b18](https://github.com/kbknapp/clap-rs/commit/27018b1821a4bcd5235cfe92abe71b3c99efc24d), closes [#278](https://github.com/kbknapp/clap-rs/issues/278)) + + + + +### v1.4.3 (2015-09-30) + + +#### Features + +* allows accessing arg values by group name ([c92a4b9e](https://github.com/kbknapp/clap-rs/commit/c92a4b9eff2d679957f61c0c41ff404b40d38a91)) + +#### Documentation + +* use links to examples instead of plain text ([bb4fe237](https://github.com/kbknapp/clap-rs/commit/bb4fe237858535627271465147add537e4556b43)) + +#### Bug Fixes + +* **Help Message:** required args no longer double list in usage ([1412e639](https://github.com/kbknapp/clap-rs/commit/1412e639e0a79df84936d1101a837f90077d1c83), closes [#277](https://github.com/kbknapp/clap-rs/issues/277)) +* **Possible Values:** possible value validation is restored ([f121ae74](https://github.com/kbknapp/clap-rs/commit/f121ae749f8f4bfe754ef2e8a6dfc286504b5b75), closes [#287](https://github.com/kbknapp/clap-rs/issues/287)) + + + + +### v1.4.2 (2015-09-23) + + +#### Bug Fixes + +* **Conflicts:** fixes bug with conflicts not removing required args ([e17fcec5](https://github.com/kbknapp/clap-rs/commit/e17fcec53b3216ad047a13dddc6f740473fad1a1), closes [#271](https://github.com/kbknapp/clap-rs/issues/271)) + + + + +### v1.4.1 (2015-09-22) + + +#### Examples + +* add clap_app quick example ([4ba6249c](https://github.com/kbknapp/clap-rs/commit/4ba6249c3cf4d2e083370d1fe4dcc7025282c28a)) + +#### Features + +* **Unicode:** allows non-panicing on invalid unicode characters ([c5bf7ddc](https://github.com/kbknapp/clap-rs/commit/c5bf7ddc8cfb876ec928a5aaf5591232bbb32e5d)) + +#### Documentation + +* properly names Examples section for rustdoc ([87ba5445](https://github.com/kbknapp/clap-rs/commit/87ba54451d7ec7b1c9b9ef134f90bbe39e6fac69)) +* fixes various typos and spelling ([f85640f9](https://github.com/kbknapp/clap-rs/commit/f85640f9f6d8fd3821a40e9b8b7a34fabb789d02)) +* **Arg:** unhides fields of the Arg struct ([931aea88](https://github.com/kbknapp/clap-rs/commit/931aea88427edf43a3da90d5a500c1ff2b2c3614)) + +#### Bug Fixes + +* flush the buffer in App::print_version() ([cbc42a37](https://github.com/kbknapp/clap-rs/commit/cbc42a37d212d84d22b1777d08e584ff191934e7)) +* Macro benchmarks ([13712da1](https://github.com/kbknapp/clap-rs/commit/13712da1d36dc7614eec3a10ad488257ba615751)) + + + + +## v1.4.0 (2015-09-09) + + +#### Features + +* allows printing help message by library consumers ([56b95f32](https://github.com/kbknapp/clap-rs/commit/56b95f320875c62dda82cb91b29059671e120ed1)) +* allows defining hidden args and subcmds ([2cab4d03](https://github.com/kbknapp/clap-rs/commit/2cab4d0334ea3c2439a1d4bfca5bf9905c7ea9ac), closes [#231](https://github.com/kbknapp/clap-rs/issues/231)) +* Builder macro to assist with App/Arg/Group/SubCommand building ([443841b0](https://github.com/kbknapp/clap-rs/commit/443841b012a8d795cd5c2bd69ae6e23ef9b16477)) +* **Errors:** allows consumers to write to stderr and exit on error ([1e6403b6](https://github.com/kbknapp/clap-rs/commit/1e6403b6a863574fa3cb6946b1fb58f034e8664c)) + + + + +### v1.3.2 (2015-09-08) + + +#### Documentation + +* fixed ErrorKind docs ([dd057843](https://github.com/kbknapp/clap-rs/commit/dd05784327fa070eb6ce5ce89a8507e011d8db94)) +* **ErrorKind:** changed examples content ([b9ca2616](https://github.com/kbknapp/clap-rs/commit/b9ca261634b89613bbf3d98fd74d55cefbb31a8c)) + +#### Bug Fixes + +* fixes a bug where the help subcommand wasn't overridable ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745)) + +#### Features + +* adds abiltiy not consume self when parsing matches and/or exit on help ([94003db4](https://github.com/kbknapp/clap-rs/commit/94003db4b5eebe552ca337521c1c001295822745)) +* **App:** Added ability for users to handle errors themselves ([934e6fbb](https://github.com/kbknapp/clap-rs/commit/934e6fbb643b2385efc23444fe6fce31494dc288)) + + + + +### v1.3.1 (2015-09-04) + + +#### Examples + +* **17_yaml:** fixed example ([9b848622](https://github.com/kbknapp/clap-rs/commit/9b848622296c8c5c7b9a39b93ddd41f51df790b5)) + +#### Performance + +* changes ArgGroup HashSets to Vec ([3cb4a48e](https://github.com/kbknapp/clap-rs/commit/3cb4a48ebd15c20692f4f3a2a924284dc7fd5e10)) +* changes BTreeSet for Vec in some instances ([baab2e3f](https://github.com/kbknapp/clap-rs/commit/baab2e3f4060e811abee14b1654cbcd5cf3b5fea)) + + + + +## v1.3.0 (2015-09-01) + + +#### Features + +* **YAML:** allows building a CLI from YAML files ([86cf4c45](https://github.com/kbknapp/clap-rs/commit/86cf4c45626a36b8115446952f9069f73c1debc3)) +* **ArgGroups:** adds support for building ArgGroups from yaml ([ecf88665](https://github.com/kbknapp/clap-rs/commit/ecf88665cbff367018b29161a1b75d44a212707d)) +* **Subcommands:** adds support for subcommands from yaml ([e415cf78](https://github.com/kbknapp/clap-rs/commit/e415cf78ba916052d118a8648deba2b9c16b1530)) + +#### Documentation + +* **YAML:** adds examples for using YAML to build a CLI ([ab41d7f3](https://github.com/kbknapp/clap-rs/commit/ab41d7f38219544750e6e1426076dc498073191b)) +* **Args from YAML:** fixes doc examples ([19b348a1](https://github.com/kbknapp/clap-rs/commit/19b348a10050404cd93888dbbbe4f396681b67d0)) +* **Examples:** adds better usage examples instead of having unused variables ([8cbacd88](https://github.com/kbknapp/clap-rs/commit/8cbacd8883004fe71a8ea036ec4391c7dd8efe94)) + +#### Examples + +* Add AppSettings example ([12705079](https://github.com/kbknapp/clap-rs/commit/12705079ca96a709b4dd94f7ddd20a833b26838c)) + +#### Bug Fixes + +* **Unified Help Messages:** fixes a crash from this setting and no opts ([169ffec1](https://github.com/kbknapp/clap-rs/commit/169ffec1003d58d105d7ef2585b3425e57980000), closes [#210](https://github.com/kbknapp/clap-rs/issues/210)) + + + + +### v1.2.5 (2015-08-27) + + +#### Examples + +* add custom validator example ([b9997d1f](https://github.com/kbknapp/clap-rs/commit/b9997d1fca74d4d8f93971f2a01bdf9798f913d5)) +* fix indentation ([d4f1b740](https://github.com/kbknapp/clap-rs/commit/d4f1b740ede410fd2528b9ecd89592c2fd8b1e20)) + +#### Features + +* **Args:** allows opts and args to define a name for help and usage msgs ([ad962ec4](https://github.com/kbknapp/clap-rs/commit/ad962ec478da999c7dba0afdb84c266f4d09b1bd)) + + + + +### v1.2.4 (2015-08-26) + + +#### Bug Fixes + +* **Possible Values:** fixes a bug where suggestions arent made when using --long=value format ([3d5e9a6c](https://github.com/kbknapp/clap-rs/commit/3d5e9a6cedb26668839b481c9978e2fbbab8be6f), closes [#192](https://github.com/kbknapp/clap-rs/issues/192)) + + + + +### v1.2.3 (2015-08-24) + + +#### Bug Fixes + +* **App, Args:** fixed subcommand reqs negation ([b41afa8c](https://github.com/kbknapp/clap-rs/commit/b41afa8c3ded3d1be12f7a2f8ea06cc44afc9458), closes [#188](https://github.com/kbknapp/clap-rs/issues/188)) + + + + +### v1.2.2 (2015-08-23) + + +#### Bug Fixes + +* fixed confusing error message, also added test for it ([fc7a31a7](https://github.com/kbknapp/clap-rs/commit/fc7a31a745efbf1768ee2c62cd3bb72bfe30c708)) +* **App:** fixed requirmets overriding ([9c135eb7](https://github.com/kbknapp/clap-rs/commit/9c135eb790fa16183e5bdb2009ddc3cf9e25f99f)) + + + + +### v1.2.1 (2015-08-20) + + +#### Documentation + +* **README.md:** updates for new features ([16cf9245](https://github.com/kbknapp/clap-rs/commit/16cf9245fb5fc4cf6face898e358368bf9961cbb)) + +#### Features + +* implements posix compatible conflicts for long args ([8c2d48ac](https://github.com/kbknapp/clap-rs/commit/8c2d48acf5473feebd721a9049a9c9b7051e70f9)) +* added overrides to support conflicts in POSIX compatible manner ([0b916a00](https://github.com/kbknapp/clap-rs/commit/0b916a00de26f6941538f6bc5f3365fa302083c1)) +* **Args:** allows defining POSIX compatible argument conflicts ([d715646e](https://github.com/kbknapp/clap-rs/commit/d715646e69759ccd95e01f49b04f489827ecf502)) + +#### Bug Fixes + +* fixed links in cargo and license buttons ([6d9837ad](https://github.com/kbknapp/clap-rs/commit/6d9837ad9a9e006117cd7372fdc60f9a3889c7e2)) + +#### Performance + +* **Args and Apps:** changes HashSet->Vec in some instances for increased performance ([d0c3b379](https://github.com/kbknapp/clap-rs/commit/d0c3b379700757e0a9b0c40af709f8af1f5b4949)) + + + + +### v1.2.0 (2015-08-15) + + +#### Bug Fixes + +* fixed misspell and enum name ([7df170d7](https://github.com/kbknapp/clap-rs/commit/7df170d7f4ecff06608317655d1e0c4298f62076)) +* fixed use for clap crate ([dc3ada73](https://github.com/kbknapp/clap-rs/commit/dc3ada738667d4b689678f79d14251ee82004ece)) + +#### Documentation + +* updates docs for new features ([03496547](https://github.com/kbknapp/clap-rs/commit/034965471782d872ca495045b58d34b31807c5b1)) +* fixed docs for previous changes ([ade36778](https://github.com/kbknapp/clap-rs/commit/ade367780c366425de462506d256e0f554ed3b9c)) + +#### Improvements + +* **AppSettings:** adds ability to add multiple settings at once ([4a00e251](https://github.com/kbknapp/clap-rs/commit/4a00e2510d0ca8d095d5257d51691ba3b61c1374)) + +#### Features + +* Replace application level settings with enum variants ([618dc4e2](https://github.com/kbknapp/clap-rs/commit/618dc4e2c205bf26bc43146164e65eb1f6b920ed)) +* **Args:** allows for custom argument value validations to be defined ([84ae2ddb](https://github.com/kbknapp/clap-rs/commit/84ae2ddbceda34b5cbda98a6959edaa52fde2e1a), closes [#170](https://github.com/kbknapp/clap-rs/issues/170)) + + + + +### v1.1.6 (2015-08-01) + + +#### Bug Fixes + +* fixes two bugs in App when printing newlines in help and subcommands required error ([d63c0136](https://github.com/kbknapp/clap-rs/commit/d63c0136310db9dd2b1c7b4745938311601d8938)) + + + + +### v1.1.5 (2015-07-29) + +#### Performance + +* removes some unneeded allocations ([93e915df](https://github.com/kbknapp/clap-rs/commit/93e915dfe300f7b7d6209ca93323c6a46f89a8c1)) + + +### v1.1.4 (2015-07-20) + + +#### Improvements + +* **Usage Strings** displays a [--] when it may be helpful ([86c3be85](https://github.com/kbknapp/clap-rs/commit/86c3be85fb6f77f83b5a6d2df40ae60937486984)) + +#### Bug Fixes + +* **Macros** fixes a typo in a macro generated error message ([c9195c5f](https://github.com/kbknapp/clap-rs/commit/c9195c5f92abb8cd6a37b4f4fbb2f1fee2a8e368)) +* **Type Errors** fixes formatting of error output when failed type parsing ([fe5d95c6](https://github.com/kbknapp/clap-rs/commit/fe5d95c64f3296e6eddcbec0cb8b86659800145f)) + + + + +### v1.1.3 (2015-07-18) + + +#### Documentation + +* updates README.md to include lack of color support on Windows ([52f81e17](https://github.com/kbknapp/clap-rs/commit/52f81e17377b18d2bd0f34693b642b7f358998ee)) + +#### Bug Fixes + +* fixes formatting bug which prevented compiling on windows ([9cb5dceb](https://github.com/kbknapp/clap-rs/commit/9cb5dceb3e5fe5e0e7b24619ff77e5040672b723), closes [#163](https://github.com/kbknapp/clap-rs/issues/163)) + + + + +### v1.1.2 (2015-07-17) + + +#### Bug Fixes + +* fixes a bug when parsing multiple {n} newlines inside help strings ([6d214b54](https://github.com/kbknapp/clap-rs/commit/6d214b549a9b7e189a94e5fa2b7c92cc333ca637)) + + + + +## v1.1.1 (2015-07-17) + + +#### Bug Fixes + +* fixes a logic bug and allows setting Arg::number_of_values() < 2 ([42b6d1fc](https://github.com/kbknapp/clap-rs/commit/42b6d1fc3c519c92dfb3af15276e7d3b635e6cfe), closes [#161](https://github.com/kbknapp/clap-rs/issues/161)) + + + + +## v1.1.0 (2015-07-16) + + +#### Features + +* allows creating unified help messages, a la docopt or getopts ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1), closes [#158](https://github.com/kbknapp/clap-rs/issues/158)) +* allows stating all subcommands should *not* have --version flags ([336c476f](https://github.com/kbknapp/clap-rs/commit/336c476f631d512b54ac56fdca6f29ebdc2c00c5), closes [#156](https://github.com/kbknapp/clap-rs/issues/156)) +* allows setting version number to auto-propagate through subcommands ([bc66d3c6](https://github.com/kbknapp/clap-rs/commit/bc66d3c6deedeca62463fff95369ab1cfcdd366b), closes [#157](https://github.com/kbknapp/clap-rs/issues/157)) + +#### Improvements + +* **Help Strings** properly aligns and handles newlines in long help strings ([f9800a29](https://github.com/kbknapp/clap-rs/commit/f9800a29696dd2cc0b0284bf693b3011831e556f), closes [#145](https://github.com/kbknapp/clap-rs/issues/145)) + + +#### Performance + +* **Help Messages** big performance improvements when printing help messages ([52bcd892](https://github.com/kbknapp/clap-rs/commit/52bcd892ea51564ce463bc5865acd64f8fe91cb1)) + +#### Documentation + +* updates readme with new features ([8232f7bb](https://github.com/kbknapp/clap-rs/commit/8232f7bb52e88862bc13c3d4f99ee4f56cfe4bc0)) +* fix incorrect code example for `App::subcommand_required` ([8889689d](https://github.com/kbknapp/clap-rs/commit/8889689dc6336ccc45b2c9f2cf8e2e483a639e93)) + + + +### v1.0.3 (2015-07-11) + + +#### Improvements + +* **Errors** writes errors to stderr ([cc76ab8c](https://github.com/kbknapp/clap-rs/commit/cc76ab8c2b77c67b42f4717ded530df7806142cf), closes [#154](https://github.com/kbknapp/clap-rs/issues/154)) + +#### Documentation + +* **README.md** updates example help message to new format ([0aca29bd](https://github.com/kbknapp/clap-rs/commit/0aca29bd5d6d1a4e9971bdc88d946ffa58606efa)) + + + + +### v1.0.2 (2015-07-09) + + +#### Improvements + +* **Usage** re-orders optional arguments and required to natural standard ([dc7e1fce](https://github.com/kbknapp/clap-rs/commit/dc7e1fcea5c85d317018fb201d2a9262249131b4), closes [#147](https://github.com/kbknapp/clap-rs/issues/147)) + + + + +### v1.0.1 (2015-07-08) + + +#### Bug Fixes + +* allows empty values when using --long='' syntax ([083f82d3](https://github.com/kbknapp/clap-rs/commit/083f82d333b69720a6ef30074875310921d964d1), closes [#151](https://github.com/kbknapp/clap-rs/issues/151)) + + + + +## v1.0.0 (2015-07-08) + + +#### Documentation + +* **README.md** adds new features to what's new list ([938f7f01](https://github.com/kbknapp/clap-rs/commit/938f7f01340f521969376cf4e2e3d9436bca21f7)) +* **README.md** use with_name for subcommands ([28b7e316](https://github.com/kbknapp/clap-rs/commit/28b7e3161fb772e5309042648fe8c3a420645bac)) + +#### Features + +* args can now be parsed from arbitrary locations, not just std::env::args() ([75312528](https://github.com/kbknapp/clap-rs/commit/753125282b1b9bfff875f1557ce27610edcc59e1)) + + + + +## v1.0.0-beta (2015-06-30) + + +#### Features + +* allows waiting for user input on error ([d0da3bdd](https://github.com/kbknapp/clap-rs/commit/d0da3bdd9d1871541907ea9c645322a74d260e07), closes [#140](https://github.com/kbknapp/clap-rs/issues/140)) +* **Help** allows one to fully override the auto-generated help message ([26d5ae3e](https://github.com/kbknapp/clap-rs/commit/26d5ae3e330d1e150811d5b60b2b01a8f8df854e), closes [#141](https://github.com/kbknapp/clap-rs/issues/141)) + +#### Documentation + +* adds "whats new" section to readme ([ff149a29](https://github.com/kbknapp/clap-rs/commit/ff149a29dd9e179865e6d577cd7dc87c54f8f95c)) + +#### Improvements + +* removes deprecated functions in prep for 1.0 ([274484df](https://github.com/kbknapp/clap-rs/commit/274484dfd08fff4859cefd7e9bef3b73d3a9cb5f)) + + + + +## v0.11.0 (2015-06-17) - BREAKING CHANGE + + +#### Documentation + +* updates docs to new version flag defaults ([ebf442eb](https://github.com/kbknapp/clap-rs/commit/ebf442ebebbcd2ec6bfe2c06566c9d362bccb112)) + +#### Features + +* **Help and Version** default short for version is now `-V` but can be overridden (only breaks manual documentation) (**BREAKING CHANGE** [eb1d9320](https://github.com/kbknapp/clap-rs/commit/eb1d9320c509c1e4e57d7c7959da82bcfe06ada0)) + + + + +### v0.10.5 (2015-06-06) + + +#### Bug Fixes + +* **Global Args** global arguments propogate fully now ([1f377960](https://github.com/kbknapp/clap-rs/commit/1f377960a48c82f54ca5f39eb56bcb393140b046), closes [#137](https://github.com/kbknapp/clap-rs/issues/137)) + + + + +### v0.10.4 (2015-06-06) + + +#### Bug Fixes + +* **Global Args** global arguments propogate fully now ([8f2c0160](https://github.com/kbknapp/clap-rs/commit/8f2c0160c8d844daef375a33dbaec7d89de00a00), closes [#137](https://github.com/kbknapp/clap-rs/issues/137)) + + + + +### v0.10.3 (2015-05-31) + + +#### Bug Fixes + +* **Global Args** fixes a bug where globals only transfer to one subcommand ([a37842ee](https://github.com/kbknapp/clap-rs/commit/a37842eec1ee3162b86fdbda23420b221cdb1e3b), closes [#135](https://github.com/kbknapp/clap-rs/issues/135)) + + + + +### v0.10.2 (2015-05-30) + + +#### Improvements + +* **Binary Names** allows users to override the system determined bin name ([2191fe94](https://github.com/kbknapp/clap-rs/commit/2191fe94bda35771383b52872fb7f5421b178be1), closes [#134](https://github.com/kbknapp/clap-rs/issues/134)) + +#### Documentation + +* adds contributing guidelines ([6f76bd0a](https://github.com/kbknapp/clap-rs/commit/6f76bd0a07e8b7419b391243ab2d6687cd8a9c5f)) + + + + +### v0.10.1 (2015-05-26) + + +#### Features + +* can now specify that an app or subcommand should display help on no args or subcommands ([29ca7b2f](https://github.com/kbknapp/clap-rs/commit/29ca7b2f74376ca0cdb9d8ee3bfa99f7640cc404), closes [#133](https://github.com/kbknapp/clap-rs/issues/133)) + + + + +## v0.10.0 (2015-05-23) + + +#### Features + +* **Global Args** allows args that propagate down to child commands ([2bcc6137](https://github.com/kbknapp/clap-rs/commit/2bcc6137a83cb07757771a0afea953e68e692f0b), closes [#131](https://github.com/kbknapp/clap-rs/issues/131)) + +#### Improvements + +* **Colors** implements more structured colored output ([d6c3ed54](https://github.com/kbknapp/clap-rs/commit/d6c3ed54d21cf7b40d9f130d4280ff5448522fc5), closes [#129](https://github.com/kbknapp/clap-rs/issues/129)) + +#### Deprecations + +* **SubCommand/App** several methods and functions for stable release ([28b73855](https://github.com/kbknapp/clap-rs/commit/28b73855523ad170544afdb20665db98702fbe70)) + +#### Documentation + +* updates for deprecations and new features ([743eefe8](https://github.com/kbknapp/clap-rs/commit/743eefe8dd40c1260065ce086d572e9e9358bc4c)) + + + + +## v0.9.2 (2015-05-20) + + +#### Bug Fixes + +* **help** allows parent requirements to be ignored with help and version ([52218cc1](https://github.com/kbknapp/clap-rs/commit/52218cc1fdb06a42456c964d98cc2c7ac3432412), closes [#124](https://github.com/kbknapp/clap-rs/issues/124)) + + + + +## v0.9.1 (2015-05-18) + + +#### Bug Fixes + +* **help** fixes a bug where requirements are included as program name in help and version ([08ba3f25](https://github.com/kbknapp/clap-rs/commit/08ba3f25cf38b149229ba8b9cb37a5804fe6b789)) + + + + +## v0.9.0 (2015-05-17) + + +#### Improvements + +* **usage** usage strings now include parent command requirements ([dd8f21c7](https://github.com/kbknapp/clap-rs/commit/dd8f21c7c15cde348fdcf44fa7c205f0e98d2e4a), closes [#125](https://github.com/kbknapp/clap-rs/issues/125)) +* **args** allows consumer of clap to decide if empty values are allowed or not ([ab4ec609](https://github.com/kbknapp/clap-rs/commit/ab4ec609ccf692b9b72cccef5c9f74f5577e360d), closes [#122](https://github.com/kbknapp/clap-rs/issues/122)) + +#### Features + +* **subcommands** + * allows optionally specifying that no subcommand is an error ([7554f238](https://github.com/kbknapp/clap-rs/commit/7554f238fd3afdd60b7e4dcf00ff4a9eccf842c1), closes [#126](https://github.com/kbknapp/clap-rs/issues/126)) + * subcommands can optionally negate parent requirements ([4a4229f5](https://github.com/kbknapp/clap-rs/commit/4a4229f500e21c350e1ef78dd09ef27559653288), closes [#123](https://github.com/kbknapp/clap-rs/issues/123)) + + + + +## v0.8.6 (2015-05-17) + + +#### Bug Fixes + +* **args** `-` can now be parsed as a value for an argument ([bc12e78e](https://github.com/kbknapp/clap-rs/commit/bc12e78eadd7eaf9d008a8469fdd2dfd7990cb5d), closes [#121](https://github.com/kbknapp/clap-rs/issues/121)) + + + + +## v0.8.5 (2015-05-15) + + +#### Bug Fixes + +* **macros** makes macro errors consistent with others ([0c264a8c](https://github.com/kbknapp/clap-rs/commit/0c264a8ca57ec1cfdcb74dae79145d766cdc9b97), closes [#118](https://github.com/kbknapp/clap-rs/issues/118)) + +#### Features + +* **macros** + * arg_enum! and simple_enum! provide a Vec<&str> of variant names ([30fa87ba](https://github.com/kbknapp/clap-rs/commit/30fa87ba4e0f3189351d8f4f78b72e616a30d0bd), closes [#119](https://github.com/kbknapp/clap-rs/issues/119)) + * arg_enum! and simple_enum! auto-implement Display ([d1219f0d](https://github.com/kbknapp/clap-rs/commit/d1219f0d1371d872061bd0718057eca4ef47b739), closes [#120](https://github.com/kbknapp/clap-rs/issues/120)) + + + + +## v0.8.4 (2015-05-12) + + +#### Bug Fixes + +* **suggestions** --help and --version now get suggestions ([d2b3b1fa](https://github.com/kbknapp/clap-rs/commit/d2b3b1faa0bdc1c5d2350cc4635aba81e02e9d96), closes [#116](https://github.com/kbknapp/clap-rs/issues/116)) + + + + +## v0.8.3 (2015-05-10) + + +#### Bug Fixes + +* **usage** groups unfold their members in usage strings ([55d15582](https://github.com/kbknapp/clap-rs/commit/55d155827ea4a6b077a83669701e797ce1ad68f4), closes [#114](https://github.com/kbknapp/clap-rs/issues/114)) + +#### Performance + +* **usage** removes unneeded allocations ([fd53cd18](https://github.com/kbknapp/clap-rs/commit/fd53cd188555f5c3dc8bc341c5d7eb04b761a70f)) + + + + +## v0.8.2 (2015-05-08) + + +#### Bug Fixes + +* **usage strings** positional arguments are presented in index order ([eb0e374e](https://github.com/kbknapp/clap-rs/commit/eb0e374ecf952f1eefbc73113f21e0705936e40b), closes [#112](https://github.com/kbknapp/clap-rs/issues/112)) + + + + +## v0.8.1 (2015-05-06) + + +#### Bug Fixes + +* **subcommands** stops parsing multiple values when subcommands are found ([fc79017e](https://github.com/kbknapp/clap-rs/commit/fc79017eced04fd41cc1801331e5054df41fac17), closes [#109](https://github.com/kbknapp/clap-rs/issues/109)) + +#### Improvements + +* **color** reduces color in error messages ([aab44cca](https://github.com/kbknapp/clap-rs/commit/aab44cca6352f47e280c296e50c535f5d752dd46), closes [#110](https://github.com/kbknapp/clap-rs/issues/110)) +* **suggestions** adds suggested arguments to usage strings ([99447414](https://github.com/kbknapp/clap-rs/commit/994474146e9fb8b701af773a52da71553d74d4b7)) + + + + +## v0.8.0 (2015-05-06) + + +#### Bug Fixes + +* **did-you-mean** for review ([0535cfb0](https://github.com/kbknapp/clap-rs/commit/0535cfb0c711331568b4de8080eeef80bd254b68)) +* **Positional** positionals were ignored if they matched a subcmd, even after '--' ([90e7b081](https://github.com/kbknapp/clap-rs/commit/90e7b0818741668b47cbe3becd029bab588e3553)) +* **help** fixes bug where space between arg and help is too long ([632fb115](https://github.com/kbknapp/clap-rs/commit/632fb11514c504999ea86bdce47cdd34f8ebf646)) + +#### Features + +* **from_usage** adds ability to add value names or num of vals in usage string ([3d581976](https://github.com/kbknapp/clap-rs/commit/3d58197674ed7886ca315efb76e411608a327501), closes [#98](https://github.com/kbknapp/clap-rs/issues/98)) +* **did-you-mean** + * gate it behind 'suggestions' ([c0e38351](https://github.com/kbknapp/clap-rs/commit/c0e383515d01bdd5ca459af9c2f7e2cf49e2488b)) + * for possible values ([1cc2deb2](https://github.com/kbknapp/clap-rs/commit/1cc2deb29158e0e4e8b434e4ce26b3d819301a7d)) + * for long flags (i.e. --long) ([52a0b850](https://github.com/kbknapp/clap-rs/commit/52a0b8505c99354bdf5fd1cd256cf41197ac2d81)) + * for subcommands ([06e869b5](https://github.com/kbknapp/clap-rs/commit/06e869b5180258047ed3c60ba099de818dd25fff)) +* **Flags** adds sugestions functionality ([8745071c](https://github.com/kbknapp/clap-rs/commit/8745071c3257dd327c497013516f12a823df9530)) +* **errors** colorizes output red on error ([f8b26b13](https://github.com/kbknapp/clap-rs/commit/f8b26b13da82ba3ba9a932d3d1ab4ea45d1ab036)) + +#### Improvements + +* **arg_enum** allows ascii case insensitivity for enum variants ([b249f965](https://github.com/kbknapp/clap-rs/commit/b249f9657c6921c004764bd80d13ebca81585eec), closes [#104](https://github.com/kbknapp/clap-rs/issues/104)) +* **clap-test** simplified `make test` invocation ([d17dcb29](https://github.com/kbknapp/clap-rs/commit/d17dcb2920637a1f58c61c596b7bd362fd53047c)) + +#### Documentation + +* **README** adds details about optional and new features ([960389de](https://github.com/kbknapp/clap-rs/commit/960389de02c9872aaee9adabe86987f71f986e39)) +* **clap** fix typos caught by codespell ([8891d929](https://github.com/kbknapp/clap-rs/commit/8891d92917aa1a069cca67272be41b99e548356e)) +* **from_usage** explains new usage strings with multiple values ([05476fc6](https://github.com/kbknapp/clap-rs/commit/05476fc61cd1e5f4a4e750d258c878732a3a9c64)) + + + + +## v0.7.6 (2015-05-05) + + +#### Improvements + +* **Options** adds number of values to options in help/usage ([c1c993c4](https://github.com/kbknapp/clap-rs/commit/c1c993c419d18e35c443785053d8de9a2ef88073)) + +#### Features + +* **from_usage** adds ability to add value names or num of vals in usage string ([ad55748c](https://github.com/kbknapp/clap-rs/commit/ad55748c265cf27935c7b210307d2040b6a09125), closes [#98](https://github.com/kbknapp/clap-rs/issues/98)) + +#### Bug Fixes + +* **MultipleValues** properly distinguishes between multiple values and multiple occurrences ([dd2a7564](https://github.com/kbknapp/clap-rs/commit/dd2a75640ca68a91b973faad15f04df891356cef), closes [#99](https://github.com/kbknapp/clap-rs/issues/99)) +* **help** fixes tab alignment with multiple values ([847001ff](https://github.com/kbknapp/clap-rs/commit/847001ff6d8f4d9518e810fefb8edf746dd0f31e)) + +#### Documentation + +* **from_usage** explains new usage strings with multiple values ([5a3a42df](https://github.com/kbknapp/clap-rs/commit/5a3a42dfa3a783537f88dedc0fd5f0edcb8ea372)) + + + + +## v0.7.5 (2015-05-04) + + +#### Bug Fixes + +* **Options** fixes bug where options with no value don't error out ([a1fb94be](https://github.com/kbknapp/clap-rs/commit/a1fb94be53141572ffd97aad037295d4ffec82d0)) + + + + +## v0.7.4 (2015-05-03) + + +#### Bug Fixes + +* **Options** fixes a bug where option arguments in succession get their values skipped ([f66334d0](https://github.com/kbknapp/clap-rs/commit/f66334d0ce984e2b56e5c19abb1dd536fae9342a)) + + + + +## v0.7.3 (2015-05-03) + + +#### Bug Fixes + +* **RequiredValues** fixes a bug where missing values are parsed as missing arguments ([93c4a723](https://github.com/kbknapp/clap-rs/commit/93c4a7231ba1a08152648598f7aa4503ea82e4de)) + +#### Improvements + +* **ErrorMessages** improves error messages and corrections ([a29c3983](https://github.com/kbknapp/clap-rs/commit/a29c3983c4229906655a29146ec15a0e46dd942d)) +* **ArgGroups** improves requirement and confliction support for groups ([c236dc5f](https://github.com/kbknapp/clap-rs/commit/c236dc5ff475110d2a1b80e62903f80296163ad3)) + + + + +## v0.7.2 (2015-05-03) + + +#### Bug Fixes + +* **RequiredArgs** fixes bug where required-by-default arguments are not listed in usage ([12aea961](https://github.com/kbknapp/clap-rs/commit/12aea9612d290845ba86515c240aeeb0a21198db), closes [#96](https://github.com/kbknapp/clap-rs/issues/96)) + + + + +## v0.7.1 (2015-05-01) + + +#### Bug Fixes + +* **MultipleValues** stops evaluating values if the max or exact number of values was reached ([86d92c9f](https://github.com/kbknapp/clap-rs/commit/86d92c9fdbf9f422442e9562977bbaf268dbbae1)) + + + + +## v0.7.0 (2015-04-30) - BREAKING CHANGE + + +#### Bug Fixes + +* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83)) + +#### Features + +* **MultipleValues** + * add support for minimum and maximum number of values ([53f6b8c9](https://github.com/kbknapp/clap-rs/commit/53f6b8c9d8dc408b4fa9f833fc3a63683873c42f)) + * adds support limited number and named values ([ae09f05e](https://github.com/kbknapp/clap-rs/commit/ae09f05e92251c1b39a83d372736fcc7b504e432)) + * implement shorthand for options with multiple values ([6669f0a9](https://github.com/kbknapp/clap-rs/commit/6669f0a9687d4f668523145d7bd5c007d1eb59a8)) +* **arg** allow other types besides Vec for multiple value settings (**BREAKING CHANGE** [0cc2f698](https://github.com/kbknapp/clap-rs/commit/0cc2f69839b9b1db5d06330771b494783049a88e), closes [#87](https://github.com/kbknapp/clap-rs/issues/87)) +* **usage** implement smart usage strings on errors ([d77048ef](https://github.com/kbknapp/clap-rs/commit/d77048efb1e595ffe831f1a2bea2f2700db53b9f), closes [#88](https://github.com/kbknapp/clap-rs/issues/88)) + + + + +## v0.6.9 (2015-04-29) + + +#### Bug Fixes + +* **from_usage** removes bug where usage strings have no help text ([ad4e5451](https://github.com/kbknapp/clap-rs/commit/ad4e54510739aeabf75f0da3278fb0952db531b3), closes [#83](https://github.com/kbknapp/clap-rs/issues/83)) + + + + +## 0.6.8 (2015-04-27) + + +#### Bug Fixes + +* **help** change long help --long=long -> --long ([1e25abfc](https://github.com/kbknapp/clap-rs/commit/1e25abfc36679ab89eae71bf98ced4de81992d00)) +* **RequiredArgs** required by default args should no longer be required when their exclusions are present ([4bb4c3cc](https://github.com/kbknapp/clap-rs/commit/4bb4c3cc076b49e86720e882bf8c489877199f2d)) + +#### Features + +* **ArgGroups** add ability to create arg groups ([09eb4d98](https://github.com/kbknapp/clap-rs/commit/09eb4d9893af40c347e50e2b717e1adef552357d)) + + + + +## v0.6.7 (2015-04-22) + + +#### Bug Fixes + +* **from_usage** fix bug causing args to not be required ([b76129e9](https://github.com/kbknapp/clap-rs/commit/b76129e9b71a63365d5c77a7f57b58dbd1e94d49)) + +#### Features + +* **apps** add ability to display additional help info after auto-gen'ed help msg ([65cc259e](https://github.com/kbknapp/clap-rs/commit/65cc259e4559cbe3653c865ec0c4b1e42a389b07)) + + + + +## v0.6.6 (2015-04-19) + + +#### Bug Fixes + +* **from_usage** tabs and spaces should be treated equally ([4fd44181](https://github.com/kbknapp/clap-rs/commit/4fd44181d55d8eb88caab1e625231cfa3129e347)) + +#### Features + +* **macros.rs** add macro to get version from Cargo.toml ([c630969a](https://github.com/kbknapp/clap-rs/commit/c630969aa3bbd386379219cae27ba1305b117f3e)) + + + + +## v0.6.5 (2015-04-19) + + +#### Bug Fixes + +* **macros.rs** fix use statements for trait impls ([86e4075e](https://github.com/kbknapp/clap-rs/commit/86e4075eb111937c8a7bdb344e866e350429f042)) + + + + +## v0.6.4 (2015-04-17) + + +#### Features + +* **macros** add ability to create enums pub or priv with derives ([2c499f80](https://github.com/kbknapp/clap-rs/commit/2c499f8015a199827cdf1fa3ec4f6f171722f8c7)) + + + + +## v0.6.3 (2015-04-16) + + +#### Features + +* **macros** add macro to create custom enums to use as types ([fb672aff](https://github.com/kbknapp/clap-rs/commit/fb672aff561c29db2e343d6c607138f141aca8b6)) + + + + +## v0.6.2 (2015-04-14) + + +#### Features + +* **macros** + * add ability to get multiple typed values or exit ([0b87251f](https://github.com/kbknapp/clap-rs/commit/0b87251fc088234bee51c323c2b652d7254f7a59)) + * add ability to get a typed multiple values ([e243fe38](https://github.com/kbknapp/clap-rs/commit/e243fe38ddbbf845a46c0b9baebaac3778c80927)) + * add convenience macro to get a typed value or exit ([4b7cd3ea](https://github.com/kbknapp/clap-rs/commit/4b7cd3ea4947780d9daa39f3e1ddab53ad4c7fef)) + * add convenience macro to get a typed value ([8752700f](https://github.com/kbknapp/clap-rs/commit/8752700fbb30e89ee68adbce24489ae9a24d33a9)) + + + + +## v0.6.1 (2015-04-13) + + +#### Bug Fixes + +* **from_usage** trim all whitespace before parsing ([91d29045](https://github.com/kbknapp/clap-rs/commit/91d2904599bd602deef2e515dfc65dc2863bdea0)) + + + + +## v0.6.0 (2015-04-13) + + +#### Bug Fixes + +* **tests** fix failing doc tests ([3710cd69](https://github.com/kbknapp/clap-rs/commit/3710cd69162f87221a62464f63437c1ce843ad3c)) + +#### Features + +* **app** add support for building args from usage strings ([d5d48bcf](https://github.com/kbknapp/clap-rs/commit/d5d48bcf463a4e494ef758836bd69a4c220bbbb5)) +* **args** add ability to create basic arguments from a usage string ([ab409a8f](https://github.com/kbknapp/clap-rs/commit/ab409a8f1db9e37cc70200f6f4a84a162692e618)) + + + + +## v0.5.14 (2015-04-10) + + +#### Bug Fixes + +* **usage** + * remove unneeded space ([51372789](https://github.com/kbknapp/clap-rs/commit/5137278942121bc2593ce6e5dc224ec2682549e6)) + * remove warning about unused variables ([ba817b9d](https://github.com/kbknapp/clap-rs/commit/ba817b9d815e37320650973f1bea0e7af3030fd7)) + +#### Features + +* **usage** add ability to get usage string for subcommands too ([3636afc4](https://github.com/kbknapp/clap-rs/commit/3636afc401c2caa966efb5b1869ef4f1ed3384aa)) + + + + +## v0.5.13 (2015-04-09) + + +#### Features + +* **SubCommands** add method to get name and subcommand matches together ([64e53928](https://github.com/kbknapp/clap-rs/commit/64e539280e23e567cf5de393b346eb0ca20e7eb5)) +* **ArgMatches** add method to get default usage string ([02462150](https://github.com/kbknapp/clap-rs/commit/02462150ca750bdc7012627d7e8d96379d494d7f)) + + + + +## v0.5.12 (2015-04-08) + + +#### Features + +* **help** sort arguments by name so as to not display a random order ([f4b2bf57](https://github.com/kbknapp/clap-rs/commit/f4b2bf5767386013069fb74862e6e938dacf44d2)) + + + + +## v0.5.11 (2015-04-08) + + +#### Bug Fixes + +* **flags** fix bug not allowing users to specify -v or -h ([90e72cff](https://github.com/kbknapp/clap-rs/commit/90e72cffdee321b79eea7a2207119533540062b4)) + + + + +## v0.5.10 (2015-04-08) + + +#### Bug Fixes + +* **help** fix spacing when option argument has not long version ([ca17fa49](https://github.com/kbknapp/clap-rs/commit/ca17fa494b68e92da83ee364bf64b0687006824b)) + + + + +## v0.5.9 (2015-04-08) + + +#### Bug Fixes + +* **positional args** all previous positional args become required when a latter one is required ([c14c3f31](https://github.com/kbknapp/clap-rs/commit/c14c3f31fd557c165570b60911d8ee483d89d6eb), closes [#50](https://github.com/kbknapp/clap-rs/issues/50)) +* **clap** remove unstable features for Rust 1.0 ([9abdb438](https://github.com/kbknapp/clap-rs/commit/9abdb438e36e364d41550e7f5d44ebcaa8ee6b10)) +* **args** improve error messages for arguments with mutual exclusions ([18dbcf37](https://github.com/kbknapp/clap-rs/commit/18dbcf37024daf2b76ca099a6f118b53827aa339), closes [#51](https://github.com/kbknapp/clap-rs/issues/51)) + + + + +## v0.5.8 (2015-04-08) + + +#### Bug Fixes + +* **option args** fix bug in getting the wrong number of occurrences for options ([82ad6ad7](https://github.com/kbknapp/clap-rs/commit/82ad6ad77539cf9f9a03b78db466f575ebd972cc)) +* **help** fix formatting for option arguments with no long ([e8691004](https://github.com/kbknapp/clap-rs/commit/e869100423d93fa3acff03c4620cbcc0d0e790a1)) +* **flags** add assertion to catch flags with specific value sets ([a0a2a40f](https://github.com/kbknapp/clap-rs/commit/a0a2a40fed57f7c5ad9d68970d090e9856306c7d), closes [#52](https://github.com/kbknapp/clap-rs/issues/52)) +* **args** improve error messages for arguments with mutual exclusions ([bff945fc](https://github.com/kbknapp/clap-rs/commit/bff945fc5d03bba4266533340adcffb002508d1b), closes [#51](https://github.com/kbknapp/clap-rs/issues/51)) +* **tests** add missing .takes_value(true) to option2 ([bdb0e88f](https://github.com/kbknapp/clap-rs/commit/bdb0e88f696c8595c3def3bfb0e52d538c7be085)) +* **positional args** all previous positional args become required when a latter one is required ([343d47dc](https://github.com/kbknapp/clap-rs/commit/343d47dcbf83786a45c0d0f01b27fd9dd76725de), closes [#50](https://github.com/kbknapp/clap-rs/issues/50)) + + + + +## v0.5.7 (2015-04-08) + + +#### Bug Fixes + +* **args** fix bug in arguments who are required and mutually exclusive ([6ceb88a5](https://github.com/kbknapp/clap-rs/commit/6ceb88a594caae825605abc1cdad95204996bf29)) + + + + +## v0.5.6 (2015-04-08) + + +#### Bug Fixes + +* **help** fix formatting of help and usage ([28691b52](https://github.com/kbknapp/clap-rs/commit/28691b52f67e65c599e10e4ea2a0f6f9765a06b8)) + + + + +## v0.5.5 (2015-04-08) + + +#### Bug Fixes + +* **help** fix formatting of help for flags and options ([6ec10115](https://github.com/kbknapp/clap-rs/commit/6ec1011563a746f0578a93b76d45e63878e0f9a8)) + + + + +## v0.5.4 (2015-04-08) + + +#### Features + +* **help** add '...' to indicate multiple values supported ([297ddba7](https://github.com/kbknapp/clap-rs/commit/297ddba77000e2228762ab0eca50b480f7467386)) + + + + +## v0.5.3 (2015-04-08) + + +#### Features + +* **positionals** + * add assertions for positional args with multiple vals ([b7fa72d4](https://github.com/kbknapp/clap-rs/commit/b7fa72d40f18806ec2042dd67a518401c2cf5681)) + * add support for multiple values ([80784009](https://github.com/kbknapp/clap-rs/commit/807840094109fbf90b348039ae22669ef27889ba)) + + + + +## v0.5.2 (2015-04-08) + + +#### Bug Fixes + +* **apps** allow use of hyphens in application and subcommand names ([da549dcb](https://github.com/kbknapp/clap-rs/commit/da549dcb6c7e0d773044ab17829744483a8b0f7f)) + + + + +## v0.5.1 (2015-04-08) + + +#### Bug Fixes + +* **args** determine if the only arguments allowed are also required ([0a09eb36](https://github.com/kbknapp/clap-rs/commit/0a09eb365ced9a03faf8ed24f083ef730acc90e8)) + + + + +## v0.5.0 (2015-04-08) + + +#### Features + +* **args** add support for a specific set of allowed values on options or positional arguments ([270eb889](https://github.com/kbknapp/clap-rs/commit/270eb88925b6dc2881bff1f31ee344f085d31809)) + + + + +## v0.4.18 (2015-04-08) + + +#### Bug Fixes + +* **usage** display required args in usage, even if only required by others ([1b7316d4](https://github.com/kbknapp/clap-rs/commit/1b7316d4a8df70b0aa584ccbfd33f68966ad2a54)) + +#### Features + +* **subcommands** properly list subcommands in help and usage ([4ee02344](https://github.com/kbknapp/clap-rs/commit/4ee023442abc3dba54b68138006a52b714adf331)) + + + + +## v0.4.17 (2015-04-08) + + +#### Bug Fixes + +* **tests** remove cargo test from claptests makefile ([1cf73817](https://github.com/kbknapp/clap-rs/commit/1cf73817d6fb1dccb5b6a23b46c2efa8b567ad62)) + + + + +## v0.4.16 (2015-04-08) + + +#### Bug Fixes + +* **option** fix bug with option occurrence values ([9af52e93](https://github.com/kbknapp/clap-rs/commit/9af52e93cef9e17ac9974963f132013d0b97b946)) +* **tests** fix testing script bug and formatting ([d8f03a55](https://github.com/kbknapp/clap-rs/commit/d8f03a55c4f74d126710ee06aad5a667246a8001)) + +#### Features + +* **arg** allow lifetimes other than 'static in arguments ([9e8c1fb9](https://github.com/kbknapp/clap-rs/commit/9e8c1fb9406f8448873ca58bab07fe905f1551e5)) diff --git a/clap/CONTRIBUTORS.md b/clap/CONTRIBUTORS.md new file mode 100644 index 000000000..f0fd77724 --- /dev/null +++ b/clap/CONTRIBUTORS.md @@ -0,0 +1,91 @@ +the following is a list of contributors: + + +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | +:---: |:---: |:---: |:---: |:---: |:---: | +[kbknapp](https://github.com/kbknapp) |[homu](https://github.com/homu) |[Vinatorul](https://github.com/Vinatorul) |[tormol](https://github.com/tormol) |[willmurphyscode](https://github.com/willmurphyscode) |[little-dude](https://github.com/little-dude) | + +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | +:---: |:---: |:---: |:---: |:---: |:---: | +[sru](https://github.com/sru) |[mgeisler](https://github.com/mgeisler) |[nabijaczleweli](https://github.com/nabijaczleweli) |[Byron](https://github.com/Byron) |[hgrecco](https://github.com/hgrecco) |[bluejekyll](https://github.com/bluejekyll) | + +[segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | +:---: |:---: |:---: |:---: |:---: |:---: | +[segevfiner](https://github.com/segevfiner) |[ignatenkobrain](https://github.com/ignatenkobrain) |[james-darkfox](https://github.com/james-darkfox) |[H2CO3](https://github.com/H2CO3) |[nateozem](https://github.com/nateozem) |[glowing-chemist](https://github.com/glowing-chemist) | + +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | +:---: |:---: |:---: |:---: |:---: |:---: | +[discosultan](https://github.com/discosultan) |[rtaycher](https://github.com/rtaycher) |[Arnavion](https://github.com/Arnavion) |[japaric](https://github.com/japaric) |[untitaker](https://github.com/untitaker) |[afiune](https://github.com/afiune) | + +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | +:---: |:---: |:---: |:---: |:---: |:---: | +[crazymerlyn](https://github.com/crazymerlyn) |[SuperFluffy](https://github.com/SuperFluffy) |[matthiasbeyer](https://github.com/matthiasbeyer) |[malbarbo](https://github.com/malbarbo) |[tshepang](https://github.com/tshepang) |[golem131](https://github.com/golem131) | + +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | +:---: |:---: |:---: |:---: |:---: |:---: | +[jimmycuadra](https://github.com/jimmycuadra) |[Nemo157](https://github.com/Nemo157) |[severen](https://github.com/severen) |[Eijebong](https://github.com/Eijebong) |[cstorey](https://github.com/cstorey) |[wdv4758h](https://github.com/wdv4758h) | + +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | +:---: |:---: |:---: |:---: |:---: |:---: | +[frewsxcv](https://github.com/frewsxcv) |[hoodie](https://github.com/hoodie) |[huonw](https://github.com/huonw) |[GrappigPanda](https://github.com/GrappigPanda) |[shepmaster](https://github.com/shepmaster) |[starkat99](https://github.com/starkat99) | + +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | +:---: |:---: |:---: |:---: |:---: |:---: | +[porglezomp](https://github.com/porglezomp) |[kraai](https://github.com/kraai) |[musoke](https://github.com/musoke) |[nelsonjchen](https://github.com/nelsonjchen) |[pkgw](https://github.com/pkgw) |[Deedasmi](https://github.com/Deedasmi) | + +[vmchale](https://github.com/vmchale) |[etopiei](https://github.com/etopiei) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) | +:---: |:---: |:---: |:---: |:---: |:---: | +[vmchale](https://github.com/vmchale) |[etopiei](https://github.com/etopiei) |[messense](https://github.com/messense) |[Keats](https://github.com/Keats) |[kieraneglin](https://github.com/kieraneglin) |[durka](https://github.com/durka) | + +[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[AndrewGaspar](https://github.com/AndrewGaspar) | +:---: |:---: |:---: |:---: |:---: |:---: | +[alex-gulyas](https://github.com/alex-gulyas) |[cite-reader](https://github.com/cite-reader) |[alexbool](https://github.com/alexbool) |[AluisioASG](https://github.com/AluisioASG) |[BurntSushi](https://github.com/BurntSushi) |[AndrewGaspar](https://github.com/AndrewGaspar) | + +[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[pixelistik](https://github.com/pixelistik) |[ogham](https://github.com/ogham) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) | +:---: |:---: |:---: |:---: |:---: |:---: | +[nox](https://github.com/nox) |[mitsuhiko](https://github.com/mitsuhiko) |[pixelistik](https://github.com/pixelistik) |[ogham](https://github.com/ogham) |[Bilalh](https://github.com/Bilalh) |[dotdash](https://github.com/dotdash) | + +[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) | +:---: |:---: |:---: |:---: |:---: |:---: | +[bradurani](https://github.com/bradurani) |[Seeker14491](https://github.com/Seeker14491) |[brianp](https://github.com/brianp) |[cldershem](https://github.com/cldershem) |[casey](https://github.com/casey) |[volks73](https://github.com/volks73) | + +[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) | +:---: |:---: |:---: |:---: |:---: |:---: | +[daboross](https://github.com/daboross) |[da-x](https://github.com/da-x) |[mernen](https://github.com/mernen) |[dguo](https://github.com/dguo) |[davidszotten](https://github.com/davidszotten) |[drusellers](https://github.com/drusellers) | + +[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) | +:---: |:---: |:---: |:---: |:---: |:---: | +[eddyb](https://github.com/eddyb) |[Enet4](https://github.com/Enet4) |[Fraser999](https://github.com/Fraser999) |[birkenfeld](https://github.com/birkenfeld) |[guanqun](https://github.com/guanqun) |[tanakh](https://github.com/tanakh) | + +[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) | +:---: |:---: |:---: |:---: |:---: |:---: | +[SirVer](https://github.com/SirVer) |[idmit](https://github.com/idmit) |[archer884](https://github.com/archer884) |[jacobmischka](https://github.com/jacobmischka) |[jespino](https://github.com/jespino) |[jfrankenau](https://github.com/jfrankenau) | + +[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) | +:---: |:---: |:---: |:---: |:---: |:---: | +[jtdowney](https://github.com/jtdowney) |[andete](https://github.com/andete) |[joshtriplett](https://github.com/joshtriplett) |[Kalwyn](https://github.com/Kalwyn) |[manuel-rhdt](https://github.com/manuel-rhdt) |[Marwes](https://github.com/Marwes) | + +[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) | +:---: |:---: |:---: |:---: |:---: |:---: | +[mdaffin](https://github.com/mdaffin) |[iliekturtles](https://github.com/iliekturtles) |[nicompte](https://github.com/nicompte) |[NickeZ](https://github.com/NickeZ) |[nvzqz](https://github.com/nvzqz) |[nuew](https://github.com/nuew) | + +[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) | +:---: |:---: |:---: |:---: |:---: |:---: | +[Geogi](https://github.com/Geogi) |[focusaurus](https://github.com/focusaurus) |[flying-sheep](https://github.com/flying-sheep) |[Phlosioneer](https://github.com/Phlosioneer) |[peppsac](https://github.com/peppsac) |[golddranks](https://github.com/golddranks) | + +[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) | +:---: |:---: |:---: |:---: |:---: |:---: | +[hexjelly](https://github.com/hexjelly) |[rom1v](https://github.com/rom1v) |[rnelson](https://github.com/rnelson) |[swatteau](https://github.com/swatteau) |[tchajed](https://github.com/tchajed) |[tspiteri](https://github.com/tspiteri) | + +[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) | +:---: |:---: |:---: |:---: |:---: |:---: | +[siiptuo](https://github.com/siiptuo) |[vks](https://github.com/vks) |[vsupalov](https://github.com/vsupalov) |[mineo](https://github.com/mineo) |[wabain](https://github.com/wabain) |[grossws](https://github.com/grossws) | + +[kennytm](https://github.com/kennytm) |[king6cong](https://github.com/king6cong) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[brennie](https://github.com/brennie) | +:---: |:---: |:---: |:---: |:---: | +[kennytm](https://github.com/kennytm) |[king6cong](https://github.com/king6cong) |[mvaude](https://github.com/mvaude) |[panicbit](https://github.com/panicbit) |[brennie](https://github.com/brennie) | + + + + +This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list) diff --git a/clap/Cargo.toml b/clap/Cargo.toml new file mode 100644 index 000000000..0d0ed5a4e --- /dev/null +++ b/clap/Cargo.toml @@ -0,0 +1,127 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "clap" +version = "2.33.0" +authors = ["Kevin K. "] +exclude = ["examples/*", "clap-test/*", "tests/*", "benches/*", "*.png", "clap-perf/*", "*.dot"] +description = "A simple to use, efficient, and full-featured Command Line Argument Parser\n" +homepage = "https://clap.rs/" +documentation = "https://docs.rs/clap/" +readme = "README.md" +keywords = ["argument", "cli", "arg", "parser", "parse"] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/clap-rs/clap" +[package.metadata.docs.rs] +features = ["doc"] +[profile.test] +opt-level = 1 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.bench] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false + +[profile.dev] +opt-level = 0 +lto = false +codegen-units = 4 +debug = true +debug-assertions = true +rpath = false + +[profile.release] +opt-level = 3 +lto = true +codegen-units = 1 +debug = false +debug-assertions = false +rpath = false +[dependencies.atty] +version = "0.2.2" +optional = true + +[dependencies.bitflags] +version = "1.0" + +[dependencies.strsim] +version = ">= 0.7, < 0.9" +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.textwrap] +version = "0.11.0" + +[dependencies.unicode-width] +version = "0.1.4" + +[dependencies.vec_map] +version = "0.8" +optional = true + +[dependencies.yaml-rust] +version = ">= 0.3.5, < 0.5" +optional = true +[dev-dependencies.lazy_static] +version = "1.3" + +[dev-dependencies.regex] +version = "1" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +color = ["ansi_term", "atty"] +debug = [] +default = ["suggestions", "color", "vec_map"] +doc = ["yaml"] +nightly = [] +no_cargo = [] +suggestions = ["strsim"] +unstable = [] +wrap_help = ["term_size", "textwrap/term_size"] +yaml = ["yaml-rust"] +[target."cfg(not(windows))".dependencies.ansi_term] +version = "0.11" +optional = true +[badges.appveyor] +repository = "clap-rs/clap" + +[badges.coveralls] +branch = "master" +repository = "clap-rs/clap" + +[badges.is-it-maintained-issue-resolution] +repository = "clap-rs/clap" + +[badges.is-it-maintained-open-issues] +repository = "clap-rs/clap" + +[badges.maintenance] +status = "actively-developed" + +[badges.travis-ci] +repository = "clap-rs/clap" diff --git a/clap/LICENSE-MIT b/clap/LICENSE-MIT new file mode 100644 index 000000000..5acedf041 --- /dev/null +++ b/clap/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2016 Kevin B. Knapp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/clap/README.md b/clap/README.md new file mode 100644 index 000000000..c95f49406 --- /dev/null +++ b/clap/README.md @@ -0,0 +1,542 @@ +clap +==== + +[![Crates.io](https://img.shields.io/crates/v/clap.svg)](https://crates.io/crates/clap) [![Crates.io](https://img.shields.io/crates/d/clap.svg)](https://crates.io/crates/clap) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/clap-rs/clap/blob/master/LICENSE-MIT) [![Coverage Status](https://coveralls.io/repos/kbknapp/clap-rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/kbknapp/clap-rs?branch=master) [![Join the chat at https://gitter.im/kbknapp/clap-rs](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/kbknapp/clap-rs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +Linux: [![Build Status](https://travis-ci.org/clap-rs/clap.svg?branch=master)](https://travis-ci.org/clap-rs/clap) +Windows: [![Build status](https://ci.appveyor.com/api/projects/status/ejg8c33dn31nhv36/branch/master?svg=true)](https://ci.appveyor.com/project/kbknapp/clap-rs/branch/master) + +Command Line Argument Parser for Rust + +It is a simple-to-use, efficient, and full-featured library for parsing command line arguments and subcommands when writing console/terminal applications. + +* [documentation](https://docs.rs/clap/) +* [website](https://clap.rs/) +* [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U) + +Table of Contents +================= + +* [About](#about) +* [FAQ](#faq) +* [Features](#features) +* [Quick Example](#quick-example) +* [Try it!](#try-it) + * [Pre-Built Test](#pre-built-test) + * [BYOB (Build Your Own Binary)](#byob-build-your-own-binary) +* [Usage](#usage) + * [Optional Dependencies / Features](#optional-dependencies--features) + * [Dependencies Tree](#dependencies-tree) + * [More Information](#more-information) + * [Video Tutorials](#video-tutorials) +* [How to Contribute](#how-to-contribute) + * [Compatibility Policy](#compatibility-policy) + * [Minimum Version of Rust](#minimum-version-of-rust) +* [Related Crates](#related-crates) +* [License](#license) +* [Recent Breaking Changes](#recent-breaking-changes) + * [Deprecations](#deprecations) + +Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) + +## About + +`clap` is used to parse *and validate* the string of command line arguments provided by a user at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means you focus on your *applications* functionality, and less on the parsing and validating of arguments. + +`clap` provides many things 'for free' (with no configuration) including the traditional version and help switches (or flags) along with associated messages. If you are using subcommands, `clap` will also auto-generate a `help` subcommand and separate associated help messages. + +Once `clap` parses the user provided string of arguments, it returns the matches along with any applicable values. If the user made an error or typo, `clap` informs them with a friendly message and exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to exit). Because of this, you can make reasonable assumptions in your code about the validity of the arguments prior to your applications main execution. + +## FAQ + +For a full FAQ and more in depth details, see [the wiki page](https://github.com/clap-rs/clap/wiki/FAQ) + +### Comparisons + +First, let me say that these comparisons are highly subjective, and not meant in a critical or harsh manner. All the argument parsing libraries out there (to include `clap`) have their own strengths and weaknesses. Sometimes it just comes down to personal taste when all other factors are equal. When in doubt, try them all and pick one that you enjoy :) There's plenty of room in the Rust community for multiple implementations! + +#### How does `clap` compare to [getopts](https://github.com/rust-lang-nursery/getopts)? + +`getopts` is a very basic, fairly minimalist argument parsing library. This isn't a bad thing, sometimes you don't need tons of features, you just want to parse some simple arguments, and have some help text generated for you based on valid arguments you specify. The downside to this approach is that you must manually implement most of the common features (such as checking to display help messages, usage strings, etc.). If you want a highly custom argument parser, and don't mind writing the majority of the functionality yourself, `getopts` is an excellent base. + +`getopts` also doesn't allocate much, or at all. This gives it a very small performance boost. Although, as you start implementing additional features, that boost quickly disappears. + +Personally, I find many, many uses of `getopts` are manually implementing features that `clap` provides by default. Using `clap` simplifies your codebase allowing you to focus on your application, and not argument parsing. + +#### How does `clap` compare to [docopt.rs](https://github.com/docopt/docopt.rs)? + +I first want to say I'm a big a fan of BurntSushi's work, the creator of `Docopt.rs`. I aspire to produce the quality of libraries that this man does! When it comes to comparing these two libraries they are very different. `docopt` tasks you with writing a help message, and then it parsers that message for you to determine all valid arguments and their use. Some people LOVE this approach, others do not. If you're willing to write a detailed help message, it's nice that you can stick that in your program and have `docopt` do the rest. On the downside, it's far less flexible. + +`docopt` is also excellent at translating arguments into Rust types automatically. There is even a syntax extension which will do all this for you, if you're willing to use a nightly compiler (use of a stable compiler requires you to somewhat manually translate from arguments to Rust types). To use BurntSushi's words, `docopt` is also a sort of black box. You get what you get, and it's hard to tweak implementation or customize the experience for your use case. + +Because `docopt` is doing a ton of work to parse your help messages and determine what you were trying to communicate as valid arguments, it's also one of the more heavy weight parsers performance-wise. For most applications this isn't a concern and this isn't to say `docopt` is slow, in fact far from it. This is just something to keep in mind while comparing. + +#### All else being equal, what are some reasons to use `clap`? (The Pitch) + +`clap` is as fast, and as lightweight as possible while still giving all the features you'd expect from a modern argument parser. In fact, for the amount and type of features `clap` offers it remains about as fast as `getopts`. If you use `clap` when just need some simple arguments parsed, you'll find it's a walk in the park. `clap` also makes it possible to represent extremely complex, and advanced requirements, without too much thought. `clap` aims to be intuitive, easy to use, and fully capable for wide variety use cases and needs. + +#### All else being equal, what are some reasons *not* to use `clap`? (The Anti Pitch) + +Depending on the style in which you choose to define the valid arguments, `clap` can be very verbose. `clap` also offers so many fine-tuning knobs and dials, that learning everything can seem overwhelming. I strive to keep the simple cases simple, but when turning all those custom dials it can get complex. `clap` is also opinionated about parsing. Even though so much can be tweaked and tuned with `clap` (and I'm adding more all the time), there are still certain features which `clap` implements in specific ways which may be contrary to some users use-cases. Finally, `clap` is "stringly typed" when referring to arguments which can cause typos in code. This particular paper-cut is being actively worked on, and should be gone in v3.x. + +## Features + +Below are a few of the features which `clap` supports, full descriptions and usage can be found in the [documentation](https://docs.rs/clap/) and [examples/](examples) directory + +* **Auto-generated Help, Version, and Usage information** + - Can optionally be fully, or partially overridden if you want a custom help, version, or usage statements +* **Auto-generated completion scripts at compile time (Bash, Zsh, Fish, and PowerShell)** + - Even works through many multiple levels of subcommands + - Works with options which only accept certain values + - Works with subcommand aliases +* **Flags / Switches** (i.e. bool fields) + - Both short and long versions supported (i.e. `-f` and `--flag` respectively) + - Supports combining short versions (i.e. `-fBgoZ` is the same as `-f -B -g -o -Z`) + - Supports multiple occurrences (i.e. `-vvv` or `-v -v -v`) +* **Positional Arguments** (i.e. those which are based off an index from the program name) + - Supports multiple values (i.e. `myprog ...` such as `myprog file1.txt file2.txt` being two values for the same "file" argument) + - Supports Specific Value Sets (See below) + - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values) + - Can set custom validations on values to extend the argument parsing capability to truly custom domains +* **Option Arguments** (i.e. those that take values) + - Both short and long versions supported (i.e. `-o value`, `-ovalue`, `-o=value` and `--option value` or `--option=value` respectively) + - Supports multiple values (i.e. `-o -o ` or `-o `) + - Supports delimited values (i.e. `-o=val1,val2,val3`, can also change the delimiter) + - Supports Specific Value Sets (See below) + - Supports named values so that the usage/help info appears as `-o ` etc. for when you require specific multiple values + - Can set value parameters (such as the minimum number of values, the maximum number of values, or the exact number of values) + - Can set custom validations on values to extend the argument parsing capability to truly custom domains +* **Sub-Commands** (i.e. `git add ` where `add` is a sub-command of `git`) + - Support their own sub-arguments, and sub-sub-commands independent of the parent + - Get their own auto-generated Help, Version, and Usage independent of parent +* **Support for building CLIs from YAML** - This keeps your Rust source nice and tidy and makes supporting localized translation very simple! +* **Requirement Rules**: Arguments can define the following types of requirement rules + - Can be required by default + - Can be required only if certain arguments are present + - Can require other arguments to be present + - Can be required only if certain values of other arguments are used +* **Confliction Rules**: Arguments can optionally define the following types of exclusion rules + - Can be disallowed when certain arguments are present + - Can disallow use of other arguments when present +* **Groups**: Arguments can be made part of a group + - Fully compatible with other relational rules (requirements, conflicts, and overrides) which allows things like requiring the use of any arg in a group, or denying the use of an entire group conditionally +* **Specific Value Sets**: Positional or Option Arguments can define a specific set of allowed values (i.e. imagine a `--mode` option which may *only* have one of two values `fast` or `slow` such as `--mode fast` or `--mode slow`) +* **Default Values** + - Also supports conditional default values (i.e. a default which only applies if specific arguments are used, or specific values of those arguments) +* **Automatic Version from Cargo.toml**: `clap` is fully compatible with Rust's `env!()` macro for automatically setting the version of your application to the version in your Cargo.toml. See [09_auto_version example](examples/09_auto_version.rs) for how to do this (Thanks to [jhelwig](https://github.com/jhelwig) for pointing this out) +* **Typed Values**: You can use several convenience macros provided by `clap` to get typed values (i.e. `i32`, `u8`, etc.) from positional or option arguments so long as the type you request implements `std::str::FromStr` See the [12_typed_values example](examples/12_typed_values.rs). You can also use `clap`s `arg_enum!` macro to create an enum with variants that automatically implement `std::str::FromStr`. See [13a_enum_values_automatic example](examples/13a_enum_values_automatic.rs) for details +* **Suggestions**: Suggests corrections when the user enters a typo. For example, if you defined a `--myoption` argument, and the user mistakenly typed `--moyption` (notice `y` and `o` transposed), they would receive a `Did you mean '--myoption'?` error and exit gracefully. This also works for subcommands and flags. (Thanks to [Byron](https://github.com/Byron) for the implementation) (This feature can optionally be disabled, see 'Optional Dependencies / Features') +* **Colorized Errors (Non Windows OS only)**: Error message are printed in in colored text (this feature can optionally be disabled, see 'Optional Dependencies / Features'). +* **Global Arguments**: Arguments can optionally be defined once, and be available to all child subcommands. There values will also be propagated up/down throughout all subcommands. +* **Custom Validations**: You can define a function to use as a validator of argument values. Imagine defining a function to validate IP addresses, or fail parsing upon error. This means your application logic can be solely focused on *using* values. +* **POSIX Compatible Conflicts/Overrides** - In POSIX args can be conflicting, but not fail parsing because whichever arg comes *last* "wins" so to speak. This allows things such as aliases (i.e. `alias ls='ls -l'` but then using `ls -C` in your terminal which ends up passing `ls -l -C` as the final arguments. Since `-l` and `-C` aren't compatible, this effectively runs `ls -C` in `clap` if you choose...`clap` also supports hard conflicts that fail parsing). (Thanks to [Vinatorul](https://github.com/Vinatorul)!) +* Supports the Unix `--` meaning, only positional arguments follow + +## Quick Example + +The following examples show a quick example of some of the very basic functionality of `clap`. For more advanced usage, such as requirements, conflicts, groups, multiple values and occurrences see the [documentation](https://docs.rs/clap/), [examples/](examples) directory of this repository or the [video tutorials](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). + + **NOTE:** All of these examples are functionally the same, but show different styles in which to use `clap`. These different styles are purely a matter of personal preference. + +The first example shows a method using the 'Builder Pattern' which allows more advanced configuration options (not shown in this small example), or even dynamically generating arguments when desired. + +```rust +// (Full example with detailed comments in examples/01b_quick_example.rs) +// +// This example demonstrates clap's full 'builder pattern' style of creating arguments which is +// more verbose, but allows easier editing, and at times more advanced options, or the possibility +// to generate arguments dynamically. +extern crate clap; +use clap::{Arg, App, SubCommand}; + +fn main() { + let matches = App::new("My Super Program") + .version("1.0") + .author("Kevin K. ") + .about("Does awesome things") + .arg(Arg::with_name("config") + .short("c") + .long("config") + .value_name("FILE") + .help("Sets a custom config file") + .takes_value(true)) + .arg(Arg::with_name("INPUT") + .help("Sets the input file to use") + .required(true) + .index(1)) + .arg(Arg::with_name("v") + .short("v") + .multiple(true) + .help("Sets the level of verbosity")) + .subcommand(SubCommand::with_name("test") + .about("controls testing features") + .version("1.3") + .author("Someone E. ") + .arg(Arg::with_name("debug") + .short("d") + .help("print debug information verbosely"))) + .get_matches(); + + // Gets a value for config if supplied by user, or defaults to "default.conf" + let config = matches.value_of("config").unwrap_or("default.conf"); + println!("Value for config: {}", config); + + // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't + // required we could have used an 'if let' to conditionally get the value) + println!("Using input file: {}", matches.value_of("INPUT").unwrap()); + + // Vary the output based on how many times the user used the "verbose" flag + // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v' + match matches.occurrences_of("v") { + 0 => println!("No verbose info"), + 1 => println!("Some verbose info"), + 2 => println!("Tons of verbose info"), + 3 | _ => println!("Don't be crazy"), + } + + // You can handle information about subcommands by requesting their matches by name + // (as below), requesting just the name used, or both at the same time + if let Some(matches) = matches.subcommand_matches("test") { + if matches.is_present("debug") { + println!("Printing debug info..."); + } else { + println!("Printing normally..."); + } + } + + // more program logic goes here... +} +``` + +One could also optionally declare their CLI in YAML format and keep your Rust source tidy +or support multiple localized translations by having different YAML files for each localization. + +First, create the `cli.yml` file to hold your CLI options, but it could be called anything we like: + +```yaml +name: myapp +version: "1.0" +author: Kevin K. +about: Does awesome things +args: + - config: + short: c + long: config + value_name: FILE + help: Sets a custom config file + takes_value: true + - INPUT: + help: Sets the input file to use + required: true + index: 1 + - verbose: + short: v + multiple: true + help: Sets the level of verbosity +subcommands: + - test: + about: controls testing features + version: "1.3" + author: Someone E. + args: + - debug: + short: d + help: print debug information +``` + +Since this feature requires additional dependencies that not everyone may want, it is *not* compiled in by default and we need to enable a feature flag in Cargo.toml: + +Simply change your `clap = "2.33"` to `clap = {version = "2.33", features = ["yaml"]}`. + +Finally we create our `main.rs` file just like we would have with the previous two examples: + +```rust +// (Full example with detailed comments in examples/17_yaml.rs) +// +// This example demonstrates clap's building from YAML style of creating arguments which is far +// more clean, but takes a very small performance hit compared to the other two methods. +#[macro_use] +extern crate clap; +use clap::App; + +fn main() { + // The YAML file is found relative to the current file, similar to how modules are found + let yaml = load_yaml!("cli.yml"); + let matches = App::from_yaml(yaml).get_matches(); + + // Same as previous examples... +} +``` + +If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or `help` subcommand, since we defined `test` as a subcommand) the following would be output + +```sh +$ myprog --help +My Super Program 1.0 +Kevin K. +Does awesome things + +USAGE: + MyApp [FLAGS] [OPTIONS] [SUBCOMMAND] + +FLAGS: + -h, --help Prints help information + -v Sets the level of verbosity + -V, --version Prints version information + +OPTIONS: + -c, --config Sets a custom config file + +ARGS: + INPUT The input file to use + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + test Controls testing features +``` + +**NOTE:** You could also run `myapp test --help` or `myapp help test` to see the help message for the `test` subcommand. + +There are also two other methods to create CLIs. Which style you choose is largely a matter of personal preference. The two other methods are: + +* Using [usage strings (examples/01a_quick_example.rs)](examples/01a_quick_example.rs) similar to (but not exact) docopt style usage statements. This is far less verbose than the above methods, but incurs a slight runtime penalty. +* Using [a macro (examples/01c_quick_example.rs)](examples/01c_quick_example.rs) which is like a hybrid of the builder and usage string style. It's less verbose, but doesn't incur the runtime penalty of the usage string style. The downside is that it's harder to debug, and more opaque. + +Examples of each method can be found in the [examples/](examples) directory of this repository. + +## Try it! + +### Pre-Built Test + +To try out the pre-built examples, use the following steps: + +* Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/` +* Compile the example `$ cargo build --example ` +* Run the help info `$ ./target/debug/examples/ --help` +* Play with the arguments! +* You can also do a onetime run via `$ cargo run --example -- [args to example]` + +### BYOB (Build Your Own Binary) + +To test out `clap`'s default auto-generated help/version follow these steps: +* Create a new cargo project `$ cargo new fake --bin && cd fake` +* Add `clap` to your `Cargo.toml` + +```toml +[dependencies] +clap = "2" +``` + +* Add the following to your `src/main.rs` + +```rust +extern crate clap; +use clap::App; + +fn main() { + App::new("fake").version("v1.0-beta").get_matches(); +} +``` + +* Build your program `$ cargo build --release` +* Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake --version` + +## Usage + +For full usage, add `clap` as a dependency in your `Cargo.toml` () to use from crates.io: + +```toml +[dependencies] +clap = "~2.33" +``` + +(**note**: If you are concerned with supporting a minimum version of Rust that is *older* than the current stable Rust minus 2 stable releases, it's recommended to use the `~major.minor.patch` style versions in your `Cargo.toml` which will only update the patch version automatically. For more information see the [Compatibility Policy](#compatibility-policy)) + +Then add `extern crate clap;` to your crate root. + +Define a list of valid arguments for your program (see the [documentation](https://docs.rs/clap/) or [examples/](examples) directory of this repo) + +Then run `cargo build` or `cargo update && cargo build` for your project. + +### Optional Dependencies / Features + +#### Features enabled by default + +* **"suggestions"**: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`) +* **"color"**: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` only on non-Windows targets) +* **"vec_map"**: Use [`VecMap`](https://crates.io/crates/vec_map) internally instead of a [`BTreeMap`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html). This feature provides a _slight_ performance improvement. (builds dependency `vec_map`) + +To disable these, add this to your `Cargo.toml`: + +```toml +[dependencies.clap] +version = "2.33" +default-features = false +``` + +You can also selectively enable only the features you'd like to include, by adding: + +```toml +[dependencies.clap] +version = "2.33" +default-features = false + +# Cherry-pick the features you'd like to use +features = [ "suggestions", "color" ] +``` + +#### Opt-in features + +* **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`) +* **"unstable"**: Enables unstable `clap` features that may change from release to release +* **"wrap_help"**: Turns on the help text wrapping feature, based on the terminal size. (builds dependency `term-size`) + +### Dependencies Tree + +The following graphic depicts `clap`s dependency graph (generated using [cargo-graph](https://github.com/kbknapp/cargo-graph)). + + * **Dashed** Line: Optional dependency + * **Red** Color: **NOT** included by default (must use cargo `features` to enable) + * **Blue** Color: Dev dependency, only used while developing. + +![clap dependencies](clap_dep_graph.png) + +### More Information + +You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project. + +You can also find usage examples in the [examples/](examples) directory of this repo. + +#### Video Tutorials + +There's also the video tutorial series [Argument Parsing with Rust v2](https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U). + +These videos slowly trickle out as I finish them and currently a work in progress. + +## How to Contribute + +Details on how to contribute can be found in the [CONTRIBUTING.md](.github/CONTRIBUTING.md) file. + +### Compatibility Policy + +Because `clap` takes SemVer and compatibility seriously, this is the official policy regarding breaking changes and minimum required versions of Rust. + +`clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version of `clap` will be bumped. + +In order to keep from being surprised of breaking changes, it is **highly** recommended to use the `~major.minor.patch` style in your `Cargo.toml` only if you wish to target a version of Rust that is *older* than current stable minus two releases: + +```toml +[dependencies] +clap = "~2.33" +``` + +This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore cannot break due to new features, or bumped minimum versions of Rust. + +#### Warning about '~' Dependencies + +Using `~` can cause issues in certain circumstances. + +From @alexcrichton: + +Right now Cargo's version resolution is pretty naive, it's just a brute-force search of the solution space, returning the first resolvable graph. This also means that it currently won't terminate until it proves there is not possible resolvable graph. This leads to situations where workspaces with multiple binaries, for example, have two different dependencies such as: + +```toml,no_sync + +# In one Cargo.toml +[dependencies] +clap = "~2.33.0" + +# In another Cargo.toml +[dependencies] +clap = "2.33.0" +``` + +This is inherently an unresolvable crate graph in Cargo right now. Cargo requires there's only one major version of a crate, and being in the same workspace these two crates must share a version. This is impossible in this location, though, as these version constraints cannot be met. + +#### Minimum Version of Rust + +`clap` will officially support current stable Rust, minus two releases, but may work with prior releases as well. For example, current stable Rust at the time of this writing is 1.32.0, meaning `clap` is guaranteed to compile with 1.30.0 and beyond. + +At the 1.33.0 stable release, `clap` will be guaranteed to compile with 1.31.0 and beyond, etc. + +Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be clearly annotated in the `CHANGELOG.md` + +#### Breaking Changes + +`clap` takes a similar policy to Rust and will bump the major version number upon breaking changes with only the following exceptions: + + * The breaking change is to fix a security concern + * The breaking change is to be fixing a bug (i.e. relying on a bug as a feature) + * The breaking change is a feature isn't used in the wild, or all users of said feature have given approval *prior* to the change + +#### Compatibility with Wasm + +A best effort is made to ensure that `clap` will work on projects targeting `wasm32-unknown-unknown`. However there is no dedicated CI build +covering this specific target. + +## License + +`clap` is licensed under the MIT license. Please read the [LICENSE-MIT](LICENSE-MIT) file in this repository for more information. + +## Related Crates + +There are several excellent crates which can be used with `clap`, I recommend checking them all out! If you've got a crate that would be a good fit to be used with `clap` open an issue and let me know, I'd love to add it! + +* [`structopt`](https://github.com/TeXitoi/structopt) - This crate allows you to define a struct, and build a CLI from it! No more "stringly typed" and it uses `clap` behind the scenes! (*Note*: There is work underway to pull this crate into mainline `clap`). +* [`assert_cli`](https://github.com/assert-rs/assert_cli) - This crate allows you test your CLIs in a very intuitive and functional way! + +## Recent Breaking Changes + +`clap` follows semantic versioning, so breaking changes should only happen upon major version bumps. The only exception to this rule is breaking changes that happen due to implementation that was deemed to be a bug, security concerns, or it can be reasonably proved to affect no code. For the full details, see [CHANGELOG.md](./CHANGELOG.md). + +As of 2.27.0: + +* Argument values now take precedence over subcommand names. This only arises by using unrestrained multiple values and subcommands together where the subcommand name can coincide with one of the multiple values. Such as `$ prog ... `. The fix is to place restraints on number of values, or disallow the use of `$ prog ` structure. + +As of 2.0.0 (From 1.x) + +* **Fewer lifetimes! Yay!** + * `App<'a, 'b, 'c, 'd, 'e, 'f>` => `App<'a, 'b>` + * `Arg<'a, 'b, 'c, 'd, 'e, 'f>` => `Arg<'a, 'b>` + * `ArgMatches<'a, 'b>` => `ArgMatches<'a>` +* **Simply Renamed** + * `App::arg_group` => `App::group` + * `App::arg_groups` => `App::groups` + * `ArgGroup::add` => `ArgGroup::arg` + * `ArgGroup::add_all` => `ArgGroup::args` + * `ClapError` => `Error` + * struct field `ClapError::error_type` => `Error::kind` + * `ClapResult` => `Result` + * `ClapErrorType` => `ErrorKind` +* **Removed Deprecated Functions and Methods** + * `App::subcommands_negate_reqs` + * `App::subcommand_required` + * `App::arg_required_else_help` + * `App::global_version(bool)` + * `App::versionless_subcommands` + * `App::unified_help_messages` + * `App::wait_on_error` + * `App::subcommand_required_else_help` + * `SubCommand::new` + * `App::error_on_no_subcommand` + * `Arg::new` + * `Arg::mutually_excludes` + * `Arg::mutually_excludes_all` + * `Arg::mutually_overrides_with` + * `simple_enum!` +* **Renamed Error Variants** + * `InvalidUnicode` => `InvalidUtf8` + * `InvalidArgument` => `UnknownArgument` +* **Usage Parser** + * Value names can now be specified inline, i.e. `-o, --option 'some option which takes two files'` + * **There is now a priority of order to determine the name** - This is perhaps the biggest breaking change. See the documentation for full details. Prior to this change, the value name took precedence. **Ensure your args are using the proper names (i.e. typically the long or short and NOT the value name) throughout the code** +* `ArgMatches::values_of` returns an `Values` now which implements `Iterator` (should not break any code) +* `crate_version!` returns `&'static str` instead of `String` + +### Deprecations + +Old method names will be left around for several minor version bumps, or one major version bump. + +As of 2.27.0: + +* **AppSettings::PropagateGlobalValuesDown:** this setting deprecated and is no longer required to propagate values down or up diff --git a/clap/SPONSORS.md b/clap/SPONSORS.md new file mode 100644 index 000000000..67f5544f9 --- /dev/null +++ b/clap/SPONSORS.md @@ -0,0 +1,17 @@ +Below is a list of sponsors for the clap-rs project + +If you are interested in becoming a sponsor for this project please our [sponsorship page](https://clap.rs/sponsorship/). + +## Recurring Sponsors: + +| [Noelia Seva-Gonzalez](https://noeliasg.com/about/) | [messense](https://github.com/messense) | [Josh](https://joshtriplett.org) | Stephen Oats | +|:-:|:-:|:-:|:-:| +|Noelia Seva-Gonzalez | Messense | Josh Triplett | Stephen Oats | + + +## Single-Donation and Former Sponsors: + +| [Rob Tsuk](https://github.com/rtsuk)| | | +|:-:|:-:|:-:| +|Rob Tsuk| | | + diff --git a/clap/clap-test.rs b/clap/clap-test.rs new file mode 100644 index 000000000..7d57ac4f3 --- /dev/null +++ b/clap/clap-test.rs @@ -0,0 +1,86 @@ +#[allow(unused_imports, dead_code)] +mod test { + use std::str; + use std::io::{Cursor, Write}; + + use regex::Regex; + + use clap::{App, Arg, SubCommand, ArgGroup}; + + fn compare(l: S, r: S2) -> bool + where S: AsRef, + S2: AsRef + { + let re = Regex::new("\x1b[^m]*m").unwrap(); + // Strip out any mismatching \r character on windows that might sneak in on either side + let ls = l.as_ref().trim().replace("\r", ""); + let rs = r.as_ref().trim().replace("\r", ""); + let left = re.replace_all(&*ls, ""); + let right = re.replace_all(&*rs, ""); + let b = left == right; + if !b { + println!(); + println!("--> left"); + println!("{}", left); + println!("--> right"); + println!("{}", right); + println!("--") + } + b + } + + pub fn compare_output(l: App, args: &str, right: &str, stderr: bool) -> bool { + let mut buf = Cursor::new(Vec::with_capacity(50)); + let res = l.get_matches_from_safe(args.split(' ').collect::>()); + let err = res.unwrap_err(); + err.write_to(&mut buf).unwrap(); + let content = buf.into_inner(); + let left = String::from_utf8(content).unwrap(); + assert_eq!(stderr, err.use_stderr()); + compare(left, right) + } + pub fn compare_output2(l: App, args: &str, right1: &str, right2: &str, stderr: bool) -> bool { + let mut buf = Cursor::new(Vec::with_capacity(50)); + let res = l.get_matches_from_safe(args.split(' ').collect::>()); + let err = res.unwrap_err(); + err.write_to(&mut buf).unwrap(); + let content = buf.into_inner(); + let left = String::from_utf8(content).unwrap(); + assert_eq!(stderr, err.use_stderr()); + compare(&*left, right1) || compare(&*left, right2) + } + + // Legacy tests from the Python script days + + pub fn complex_app() -> App<'static, 'static> { + let args = "-o --option=[opt]... 'tests options' + [positional] 'tests positionals'"; + let opt3_vals = ["fast", "slow"]; + let pos3_vals = ["vi", "emacs"]; + App::new("clap-test") + .version("v1.4.8") + .about("tests clap library") + .author("Kevin K. ") + .args_from_usage(args) + .arg(Arg::from_usage("-f --flag... 'tests flags'") + .global(true)) + .args(&[ + Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("long-option-2"), + Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"), + Arg::from_usage("[positional2] 'tests positionals with exclusions'"), + Arg::from_usage("-O --Option [option3] 'specific vals'").possible_values(&opt3_vals), + Arg::from_usage("[positional3]... 'tests specific values'").possible_values(&pos3_vals), + Arg::from_usage("--multvals [one] [two] 'Tests multiple values, not mult occs'"), + Arg::from_usage("--multvalsmo... [one] [two] 'Tests multiple values, and mult occs'"), + Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2), + Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3) + ]) + .subcommand(SubCommand::with_name("subcmd") + .about("tests subcommands") + .version("0.1") + .author("Kevin K. ") + .arg_from_usage("-o --option [scoption]... 'tests options'") + .arg_from_usage("-s --subcmdarg [subcmdarg] 'tests other args'") + .arg_from_usage("[scpositional] 'tests positionals'")) + } +} diff --git a/clap/debian/patches/no-clippy.patch b/clap/debian/patches/no-clippy.patch new file mode 100644 index 000000000..bf6f81852 --- /dev/null +++ b/clap/debian/patches/no-clippy.patch @@ -0,0 +1,21 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -63,10 +63,6 @@ + [dependencies.bitflags] + version = "1.0" + +-[dependencies.clippy] +-version = "~0.0.166" +-optional = true +- + [dependencies.strsim] + version = "0.8" + optional = true +@@ -102,7 +98,6 @@ + debug = [] + default = ["suggestions", "color", "vec_map"] + doc = ["yaml"] +-lints = ["clippy"] + nightly = [] + no_cargo = [] + suggestions = ["strsim"] diff --git a/clap/debian/patches/relax-dep-versions.patch b/clap/debian/patches/relax-dep-versions.patch new file mode 100644 index 000000000..4f68326ac --- /dev/null +++ b/clap/debian/patches/relax-dep-versions.patch @@ -0,0 +1,20 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -64,7 +64,7 @@ + version = "1.0" + + [dependencies.strsim] +-version = "0.8" ++version = ">= 0.7, < 0.9" + optional = true + + [dependencies.term_size] +@@ -82,7 +82,7 @@ + optional = true + + [dependencies.yaml-rust] +-version = "0.3.5" ++version = ">= 0.3.5, < 0.5" + optional = true + [dev-dependencies.lazy_static] + version = "1.3" diff --git a/clap/debian/patches/series b/clap/debian/patches/series new file mode 100644 index 000000000..9d44adc3b --- /dev/null +++ b/clap/debian/patches/series @@ -0,0 +1,2 @@ +no-clippy.patch +relax-dep-versions.patch diff --git a/clap/justfile b/clap/justfile new file mode 100644 index 000000000..0768764b3 --- /dev/null +++ b/clap/justfile @@ -0,0 +1,39 @@ +@update-contributors: + echo 'Removing old CONTRIBUTORS.md' + mv CONTRIBUTORS.md CONTRIBUTORS.md.bak + echo 'Downloading a list of new contributors' + echo "the following is a list of contributors:" > CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + githubcontrib --owner clap-rs --repo clap --sha master --cols 6 --format md --showlogin true --sortBy contributions --sortOrder desc >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "" >> CONTRIBUTORS.md + echo "This list was generated by [mgechev/github-contributors-list](https://github.com/mgechev/github-contributors-list)" >> CONTRIBUTORS.md + rm CONTRIBUTORS.md.bak + +run-test TEST: + cargo test --test {{TEST}} + +debug TEST: + cargo test --test {{TEST}} --features debug + +run-tests: + cargo test --features "yaml unstable" + +@bench: nightly + cargo bench && just remove-nightly + +nightly: + rustup override add nightly + +remove-nightly: + rustup override remove + +@lint: nightly + cargo build --features lints && just remove-nightly + +clean: + cargo clean + find . -type f -name "*.orig" -exec rm {} \; + find . -type f -name "*.bk" -exec rm {} \; + find . -type f -name ".*~" -exec rm {} \; diff --git a/clap/rustfmt.toml b/clap/rustfmt.toml new file mode 100644 index 000000000..0136d86e3 --- /dev/null +++ b/clap/rustfmt.toml @@ -0,0 +1,4 @@ +format_strings = false +chain_overflow_last = false +same_line_if_else = true +fn_single_line = true diff --git a/clap/src/app/help.rs b/clap/src/app/help.rs new file mode 100644 index 000000000..34f97ac32 --- /dev/null +++ b/clap/src/app/help.rs @@ -0,0 +1,1028 @@ +// Std +use std::borrow::Cow; +use std::cmp; +use std::collections::BTreeMap; +use std::fmt::Display; +use std::io::{self, Cursor, Read, Write}; +use std::usize; + +// Internal +use app::parser::Parser; +use app::usage; +use app::{App, AppSettings}; +use args::{AnyArg, ArgSettings, DispOrder}; +use errors::{Error, Result as ClapResult}; +use fmt::{Colorizer, ColorizerOption, Format}; +use map::VecMap; +use INTERNAL_ERROR_MSG; + +// Third Party +#[cfg(feature = "wrap_help")] +use term_size; +use textwrap; +use unicode_width::UnicodeWidthStr; + +#[cfg(not(feature = "wrap_help"))] +mod term_size { + pub fn dimensions() -> Option<(usize, usize)> { + None + } +} + +fn str_width(s: &str) -> usize { + UnicodeWidthStr::width(s) +} + +const TAB: &'static str = " "; + +// These are just convenient traits to make the code easier to read. +trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {} +impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T +where + T: AnyArg<'b, 'c> + Display, +{ +} + +trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder { + fn as_base(&self) -> &ArgWithDisplay<'b, 'c>; +} +impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T +where + T: ArgWithDisplay<'b, 'c> + DispOrder, +{ + fn as_base(&self) -> &ArgWithDisplay<'b, 'c> { + self + } +} + +fn as_arg_trait<'a, 'b, T: ArgWithOrder<'a, 'b>>(x: &T) -> &ArgWithOrder<'a, 'b> { + x +} + +impl<'b, 'c> DispOrder for App<'b, 'c> { + fn disp_ord(&self) -> usize { + 999 + } +} + +macro_rules! color { + ($_self:ident, $s:expr, $c:ident) => { + if $_self.color { + write!($_self.writer, "{}", $_self.cizer.$c($s)) + } else { + write!($_self.writer, "{}", $s) + } + }; + ($_self:ident, $fmt_s:expr, $v:expr, $c:ident) => { + if $_self.color { + write!($_self.writer, "{}", $_self.cizer.$c(format!($fmt_s, $v))) + } else { + write!($_self.writer, $fmt_s, $v) + } + }; +} + +/// `clap` Help Writer. +/// +/// Wraps a writer stream providing different methods to generate help for `clap` objects. +pub struct Help<'a> { + writer: &'a mut Write, + next_line_help: bool, + hide_pv: bool, + term_w: usize, + color: bool, + cizer: Colorizer, + longest: usize, + force_next_line: bool, + use_long: bool, +} + +// Public Functions +impl<'a> Help<'a> { + /// Create a new `Help` instance. + #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] + pub fn new( + w: &'a mut Write, + next_line_help: bool, + hide_pv: bool, + color: bool, + cizer: Colorizer, + term_w: Option, + max_w: Option, + use_long: bool, + ) -> Self { + debugln!("Help::new;"); + Help { + writer: w, + next_line_help: next_line_help, + hide_pv: hide_pv, + term_w: match term_w { + Some(width) => if width == 0 { + usize::MAX + } else { + width + }, + None => cmp::min( + term_size::dimensions().map_or(120, |(w, _)| w), + match max_w { + None | Some(0) => usize::MAX, + Some(mw) => mw, + }, + ), + }, + color: color, + cizer: cizer, + longest: 0, + force_next_line: false, + use_long: use_long, + } + } + + /// Reads help settings from an App + /// and write its help to the wrapped stream. + pub fn write_app_help(w: &'a mut Write, app: &App, use_long: bool) -> ClapResult<()> { + debugln!("Help::write_app_help;"); + Self::write_parser_help(w, &app.p, use_long) + } + + /// Reads help settings from a Parser + /// and write its help to the wrapped stream. + pub fn write_parser_help(w: &'a mut Write, parser: &Parser, use_long: bool) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + Self::_write_parser_help(w, parser, false, use_long) + } + + /// Reads help settings from a Parser + /// and write its help to the wrapped stream which will be stderr. This method prevents + /// formatting when required. + pub fn write_parser_help_to_stderr(w: &'a mut Write, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + Self::_write_parser_help(w, parser, true, false) + } + + #[doc(hidden)] + pub fn _write_parser_help( + w: &'a mut Write, + parser: &Parser, + stderr: bool, + use_long: bool, + ) -> ClapResult<()> { + debugln!("Help::write_parser_help;"); + let nlh = parser.is_set(AppSettings::NextLineHelp); + let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp); + let color = parser.is_set(AppSettings::ColoredHelp); + let cizer = Colorizer::new(ColorizerOption { + use_stderr: stderr, + when: parser.color(), + }); + Self::new( + w, + nlh, + hide_v, + color, + cizer, + parser.meta.term_w, + parser.meta.max_w, + use_long, + ).write_help(parser) + } + + /// Writes the parser help to the wrapped stream. + pub fn write_help(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_help;"); + if let Some(h) = parser.meta.help_str { + write!(self.writer, "{}", h).map_err(Error::from)?; + } else if let Some(tmpl) = parser.meta.template { + self.write_templated_help(parser, tmpl)?; + } else { + self.write_default_help(parser)?; + } + Ok(()) + } +} + +// Methods to write AnyArg help. +impl<'a> Help<'a> { + /// Writes help for each argument in the order they were declared to the wrapped stream. + fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> + where + I: Iterator>, + { + debugln!("Help::write_args_unsorted;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut arg_v = Vec::with_capacity(10); + let use_long = self.use_long; + for arg in args.filter(|arg| should_show_arg(use_long, *arg)) { + if arg.longest_filter() { + self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); + } + arg_v.push(arg) + } + let mut first = true; + for arg in arg_v { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(arg.as_base())?; + } + Ok(()) + } + + /// Sorts arguments by length and display order and write their help to the wrapped stream. + fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> + where + I: Iterator>, + { + debugln!("Help::write_args;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut ord_m = VecMap::new(); + let use_long = self.use_long; + // Determine the longest + for arg in args.filter(|arg| { + // If it's NextLineHelp, but we don't care to compute how long because it may be + // NextLineHelp on purpose *because* it's so long and would throw off all other + // args alignment + should_show_arg(use_long, *arg) + }) { + if arg.longest_filter() { + debugln!("Help::write_args: Current Longest...{}", self.longest); + self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); + debugln!("Help::write_args: New Longest...{}", self.longest); + } + let btm = ord_m.entry(arg.disp_ord()).or_insert(BTreeMap::new()); + btm.insert(arg.name(), arg); + } + let mut first = true; + for btm in ord_m.values() { + for arg in btm.values() { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(arg.as_base())?; + } + } + Ok(()) + } + + /// Writes help for an argument to the wrapped stream. + fn write_arg<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::write_arg;"); + self.short(arg)?; + self.long(arg)?; + let spec_vals = self.val(arg)?; + self.help(arg, &*spec_vals)?; + Ok(()) + } + + /// Writes argument's short command to the wrapped stream. + fn short<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::short;"); + write!(self.writer, "{}", TAB)?; + if let Some(s) = arg.short() { + color!(self, "-{}", s, good) + } else if arg.has_switch() { + write!(self.writer, "{}", TAB) + } else { + Ok(()) + } + } + + /// Writes argument's long command to the wrapped stream. + fn long<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> io::Result<()> { + debugln!("Help::long;"); + if !arg.has_switch() { + return Ok(()); + } + if arg.takes_value() { + if let Some(l) = arg.long() { + if arg.short().is_some() { + write!(self.writer, ", ")?; + } + color!(self, "--{}", l, good)? + } + + let sep = if arg.is_set(ArgSettings::RequireEquals) { + "=" + } else { + " " + }; + write!(self.writer, "{}", sep)?; + } else if let Some(l) = arg.long() { + if arg.short().is_some() { + write!(self.writer, ", ")?; + } + color!(self, "--{}", l, good)?; + } + Ok(()) + } + + /// Writes argument's possible values to the wrapped stream. + fn val<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>) -> Result { + debugln!("Help::val: arg={}", arg); + if arg.takes_value() { + let delim = if arg.is_set(ArgSettings::RequireDelimiter) { + arg.val_delim().expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }; + if let Some(vec) = arg.val_names() { + let mut it = vec.iter().peekable(); + while let Some((_, val)) = it.next() { + color!(self, "<{}>", val, good)?; + if it.peek().is_some() { + write!(self.writer, "{}", delim)?; + } + } + let num = vec.len(); + if arg.is_set(ArgSettings::Multiple) && num == 1 { + color!(self, "...", good)?; + } + } else if let Some(num) = arg.num_vals() { + let mut it = (0..num).peekable(); + while let Some(_) = it.next() { + color!(self, "<{}>", arg.name(), good)?; + if it.peek().is_some() { + write!(self.writer, "{}", delim)?; + } + } + if arg.is_set(ArgSettings::Multiple) && num == 1 { + color!(self, "...", good)?; + } + } else if arg.has_switch() { + color!(self, "<{}>", arg.name(), good)?; + if arg.is_set(ArgSettings::Multiple) { + color!(self, "...", good)?; + } + } else { + color!(self, "{}", arg, good)?; + } + } + + let spec_vals = self.spec_vals(arg); + let h = arg.help().unwrap_or(""); + let h_w = str_width(h) + str_width(&*spec_vals); + let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp); + let taken = self.longest + 12; + self.force_next_line = !nlh && self.term_w >= taken + && (taken as f32 / self.term_w as f32) > 0.40 + && h_w > (self.term_w - taken); + + debug!("Help::val: Has switch..."); + if arg.has_switch() { + sdebugln!("Yes"); + debugln!("Help::val: force_next_line...{:?}", self.force_next_line); + debugln!("Help::val: nlh...{:?}", nlh); + debugln!("Help::val: taken...{}", taken); + debugln!( + "Help::val: help_width > (width - taken)...{} > ({} - {})", + h_w, + self.term_w, + taken + ); + debugln!("Help::val: longest...{}", self.longest); + debug!("Help::val: next_line..."); + if !(nlh || self.force_next_line) { + sdebugln!("No"); + let self_len = str_width(arg.to_string().as_str()); + // subtract ourself + let mut spcs = self.longest - self_len; + // Since we're writing spaces from the tab point we first need to know if we + // had a long and short, or just short + if arg.long().is_some() { + // Only account 4 after the val + spcs += 4; + } else { + // Only account for ', --' + 4 after the val + spcs += 8; + } + + write_nspaces!(self.writer, spcs); + } else { + sdebugln!("Yes"); + } + } else if !(nlh || self.force_next_line) { + sdebugln!("No, and not next_line"); + write_nspaces!( + self.writer, + self.longest + 4 - (str_width(arg.to_string().as_str())) + ); + } else { + sdebugln!("No"); + } + Ok(spec_vals) + } + + fn write_before_after_help(&mut self, h: &str) -> io::Result<()> { + debugln!("Help::write_before_after_help;"); + let mut help = String::from(h); + // determine if our help fits or needs to wrap + debugln!( + "Help::write_before_after_help: Term width...{}", + self.term_w + ); + let too_long = str_width(h) >= self.term_w; + + debug!("Help::write_before_after_help: Too long..."); + if too_long || h.contains("{n}") { + sdebugln!("Yes"); + debugln!("Help::write_before_after_help: help: {}", help); + debugln!( + "Help::write_before_after_help: help width: {}", + str_width(&*help) + ); + // Determine how many newlines we need to insert + debugln!( + "Help::write_before_after_help: Usable space: {}", + self.term_w + ); + help = wrap_help(&help.replace("{n}", "\n"), self.term_w); + } else { + sdebugln!("No"); + } + write!(self.writer, "{}", help)?; + Ok(()) + } + + /// Writes argument's help to the wrapped stream. + fn help<'b, 'c>(&mut self, arg: &ArgWithDisplay<'b, 'c>, spec_vals: &str) -> io::Result<()> { + debugln!("Help::help;"); + let h = if self.use_long && arg.name() != "" { + arg.long_help().unwrap_or_else(|| arg.help().unwrap_or("")) + } else { + arg.help().unwrap_or_else(|| arg.long_help().unwrap_or("")) + }; + let mut help = String::from(h) + spec_vals; + let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp) || (self.use_long && arg.name() != ""); + debugln!("Help::help: Next Line...{:?}", nlh); + + let spcs = if nlh || self.force_next_line { + 12 // "tab" * 3 + } else { + self.longest + 12 + }; + + let too_long = spcs + str_width(h) + str_width(&*spec_vals) >= self.term_w; + + // Is help on next line, if so then indent + if nlh || self.force_next_line { + write!(self.writer, "\n{}{}{}", TAB, TAB, TAB)?; + } + + debug!("Help::help: Too long..."); + if too_long && spcs <= self.term_w || h.contains("{n}") { + sdebugln!("Yes"); + debugln!("Help::help: help...{}", help); + debugln!("Help::help: help width...{}", str_width(&*help)); + // Determine how many newlines we need to insert + let avail_chars = self.term_w - spcs; + debugln!("Help::help: Usable space...{}", avail_chars); + help = wrap_help(&help.replace("{n}", "\n"), avail_chars); + } else { + sdebugln!("No"); + } + if let Some(part) = help.lines().next() { + write!(self.writer, "{}", part)?; + } + for part in help.lines().skip(1) { + write!(self.writer, "\n")?; + if nlh || self.force_next_line { + write!(self.writer, "{}{}{}", TAB, TAB, TAB)?; + } else if arg.has_switch() { + write_nspaces!(self.writer, self.longest + 12); + } else { + write_nspaces!(self.writer, self.longest + 8); + } + write!(self.writer, "{}", part)?; + } + if !help.contains('\n') && (nlh || self.force_next_line) { + write!(self.writer, "\n")?; + } + Ok(()) + } + + fn spec_vals(&self, a: &ArgWithDisplay) -> String { + debugln!("Help::spec_vals: a={}", a); + let mut spec_vals = vec![]; + if let Some(ref env) = a.env() { + debugln!( + "Help::spec_vals: Found environment variable...[{:?}:{:?}]", + env.0, + env.1 + ); + let env_val = if !a.is_set(ArgSettings::HideEnvValues) { + format!( + "={}", + env.1.map_or(Cow::Borrowed(""), |val| val.to_string_lossy()) + ) + } else { + String::new() + }; + let env_info = format!(" [env: {}{}]", env.0.to_string_lossy(), env_val); + spec_vals.push(env_info); + } + if !a.is_set(ArgSettings::HideDefaultValue) { + if let Some(pv) = a.default_val() { + debugln!("Help::spec_vals: Found default value...[{:?}]", pv); + spec_vals.push(format!( + " [default: {}]", + if self.color { + self.cizer.good(pv.to_string_lossy()) + } else { + Format::None(pv.to_string_lossy()) + } + )); + } + } + if let Some(ref aliases) = a.aliases() { + debugln!("Help::spec_vals: Found aliases...{:?}", aliases); + spec_vals.push(format!( + " [aliases: {}]", + if self.color { + aliases + .iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + } else { + aliases.join(", ") + } + )); + } + if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) { + if let Some(pv) = a.possible_vals() { + debugln!("Help::spec_vals: Found possible vals...{:?}", pv); + spec_vals.push(if self.color { + format!( + " [possible values: {}]", + pv.iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + ) + } else { + format!(" [possible values: {}]", pv.join(", ")) + }); + } + } + spec_vals.join(" ") + } +} + +fn should_show_arg(use_long: bool, arg: &ArgWithOrder) -> bool { + if arg.is_set(ArgSettings::Hidden) { + return false; + } + + (!arg.is_set(ArgSettings::HiddenLongHelp) && use_long) + || (!arg.is_set(ArgSettings::HiddenShortHelp) && !use_long) + || arg.is_set(ArgSettings::NextLineHelp) +} + +// Methods to write Parser help. +impl<'a> Help<'a> { + /// Writes help for all arguments (options, flags, args, subcommands) + /// including titles of a Parser Object to the wrapped stream. + #[cfg_attr(feature = "lints", allow(useless_let_if_seq))] + #[cfg_attr(feature = "cargo-clippy", allow(useless_let_if_seq))] + pub fn write_all_args(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_all_args;"); + let flags = parser.has_flags(); + let pos = parser + .positionals() + .filter(|arg| !arg.is_set(ArgSettings::Hidden)) + .count() > 0; + let opts = parser.has_opts(); + let subcmds = parser.has_visible_subcommands(); + + let unified_help = parser.is_set(AppSettings::UnifiedHelpMessage); + + let mut first = true; + + if unified_help && (flags || opts) { + let opts_flags = parser + .flags() + .map(as_arg_trait) + .chain(parser.opts().map(as_arg_trait)); + color!(self, "OPTIONS:\n", warning)?; + self.write_args(opts_flags)?; + first = false; + } else { + if flags { + color!(self, "FLAGS:\n", warning)?; + self.write_args(parser.flags().map(as_arg_trait))?; + first = false; + } + if opts { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "OPTIONS:\n", warning)?; + self.write_args(parser.opts().map(as_arg_trait))?; + first = false; + } + } + + if pos { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "ARGS:\n", warning)?; + self.write_args_unsorted(parser.positionals().map(as_arg_trait))?; + first = false; + } + + if subcmds { + if !first { + self.writer.write_all(b"\n\n")?; + } + color!(self, "SUBCOMMANDS:\n", warning)?; + self.write_subcommands(parser)?; + } + + Ok(()) + } + + /// Writes help for subcommands of a Parser Object to the wrapped stream. + fn write_subcommands(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_subcommands;"); + // The shortest an arg can legally be is 2 (i.e. '-x') + self.longest = 2; + let mut ord_m = VecMap::new(); + for sc in parser + .subcommands + .iter() + .filter(|s| !s.p.is_set(AppSettings::Hidden)) + { + let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new()); + self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str())); + //self.longest = cmp::max(self.longest, sc.p.meta.name.len()); + btm.insert(sc.p.meta.name.clone(), sc.clone()); + } + + let mut first = true; + for btm in ord_m.values() { + for sc in btm.values() { + if first { + first = false; + } else { + self.writer.write_all(b"\n")?; + } + self.write_arg(sc)?; + } + } + Ok(()) + } + + /// Writes version of a Parser Object to the wrapped stream. + fn write_version(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_version;"); + write!(self.writer, "{}", parser.meta.version.unwrap_or(""))?; + Ok(()) + } + + /// Writes binary name of a Parser Object to the wrapped stream. + fn write_bin_name(&mut self, parser: &Parser) -> io::Result<()> { + debugln!("Help::write_bin_name;"); + macro_rules! write_name { + () => {{ + let mut name = parser.meta.name.clone(); + name = name.replace("{n}", "\n"); + color!(self, wrap_help(&name, self.term_w), good)?; + }}; + } + if let Some(bn) = parser.meta.bin_name.as_ref() { + if bn.contains(' ') { + // Incase we're dealing with subcommands i.e. git mv is translated to git-mv + color!(self, bn.replace(" ", "-"), good)? + } else { + write_name!(); + } + } else { + write_name!(); + } + Ok(()) + } + + /// Writes default help for a Parser Object to the wrapped stream. + pub fn write_default_help(&mut self, parser: &Parser) -> ClapResult<()> { + debugln!("Help::write_default_help;"); + if let Some(h) = parser.meta.pre_help { + self.write_before_after_help(h)?; + self.writer.write_all(b"\n\n")?; + } + + macro_rules! write_thing { + ($thing:expr) => {{ + let mut owned_thing = $thing.to_owned(); + owned_thing = owned_thing.replace("{n}", "\n"); + write!(self.writer, "{}\n", wrap_help(&owned_thing, self.term_w))? + }}; + } + // Print the version + self.write_bin_name(parser)?; + self.writer.write_all(b" ")?; + self.write_version(parser)?; + self.writer.write_all(b"\n")?; + if let Some(author) = parser.meta.author { + write_thing!(author) + } + // if self.use_long { + // if let Some(about) = parser.meta.long_about { + // debugln!("Help::write_default_help: writing long about"); + // write_thing!(about) + // } else if let Some(about) = parser.meta.about { + // debugln!("Help::write_default_help: writing about"); + // write_thing!(about) + // } + // } else + if let Some(about) = parser.meta.long_about { + debugln!("Help::write_default_help: writing long about"); + write_thing!(about) + } else if let Some(about) = parser.meta.about { + debugln!("Help::write_default_help: writing about"); + write_thing!(about) + } + + color!(self, "\nUSAGE:", warning)?; + write!( + self.writer, + "\n{}{}\n\n", + TAB, + usage::create_usage_no_title(parser, &[]) + )?; + + let flags = parser.has_flags(); + let pos = parser.has_positionals(); + let opts = parser.has_opts(); + let subcmds = parser.has_subcommands(); + + if flags || opts || pos || subcmds { + self.write_all_args(parser)?; + } + + if let Some(h) = parser.meta.more_help { + if flags || opts || pos || subcmds { + self.writer.write_all(b"\n\n")?; + } + self.write_before_after_help(h)?; + } + + self.writer.flush().map_err(Error::from) + } +} + +/// Possible results for a copying function that stops when a given +/// byte was found. +enum CopyUntilResult { + DelimiterFound(usize), + DelimiterNotFound(usize), + ReaderEmpty, + ReadError(io::Error), + WriteError(io::Error), +} + +/// Copies the contents of a reader into a writer until a delimiter byte is found. +/// On success, the total number of bytes that were +/// copied from reader to writer is returned. +fn copy_until(r: &mut R, w: &mut W, delimiter_byte: u8) -> CopyUntilResult { + debugln!("copy_until;"); + + let mut count = 0; + for wb in r.bytes() { + match wb { + Ok(b) => { + if b == delimiter_byte { + return CopyUntilResult::DelimiterFound(count); + } + match w.write(&[b]) { + Ok(c) => count += c, + Err(e) => return CopyUntilResult::WriteError(e), + } + } + Err(e) => return CopyUntilResult::ReadError(e), + } + } + if count > 0 { + CopyUntilResult::DelimiterNotFound(count) + } else { + CopyUntilResult::ReaderEmpty + } +} + +/// Copies the contents of a reader into a writer until a {tag} is found, +/// copying the tag content to a buffer and returning its size. +/// In addition to errors, there are three possible outputs: +/// - `None`: The reader was consumed. +/// - `Some(Ok(0))`: No tag was captured but the reader still contains data. +/// - `Some(Ok(length>0))`: a tag with `length` was captured to the `tag_buffer`. +fn copy_and_capture( + r: &mut R, + w: &mut W, + tag_buffer: &mut Cursor>, +) -> Option> { + use self::CopyUntilResult::*; + debugln!("copy_and_capture;"); + + // Find the opening byte. + match copy_until(r, w, b'{') { + // The end of the reader was reached without finding the opening tag. + // (either with or without having copied data to the writer) + // Return None indicating that we are done. + ReaderEmpty | DelimiterNotFound(_) => None, + + // Something went wrong. + ReadError(e) | WriteError(e) => Some(Err(e)), + + // The opening byte was found. + // (either with or without having copied data to the writer) + DelimiterFound(_) => { + // Lets reset the buffer first and find out how long it is. + tag_buffer.set_position(0); + let buffer_size = tag_buffer.get_ref().len(); + + // Find the closing byte,limiting the reader to the length of the buffer. + let mut rb = r.take(buffer_size as u64); + match copy_until(&mut rb, tag_buffer, b'}') { + // We were already at the end of the reader. + // Return None indicating that we are done. + ReaderEmpty => None, + + // The closing tag was found. + // Return the tag_length. + DelimiterFound(tag_length) => Some(Ok(tag_length)), + + // The end of the reader was found without finding the closing tag. + // Write the opening byte and captured text to the writer. + // Return 0 indicating that nothing was captured but the reader still contains data. + DelimiterNotFound(not_tag_length) => match w.write(b"{") { + Err(e) => Some(Err(e)), + _ => match w.write(&tag_buffer.get_ref()[0..not_tag_length]) { + Err(e) => Some(Err(e)), + _ => Some(Ok(0)), + }, + }, + + ReadError(e) | WriteError(e) => Some(Err(e)), + } + } + } +} + +// Methods to write Parser help using templates. +impl<'a> Help<'a> { + /// Write help to stream for the parser in the format defined by the template. + /// + /// Tags arg given inside curly brackets: + /// Valid tags are: + /// * `{bin}` - Binary name. + /// * `{version}` - Version number. + /// * `{author}` - Author information. + /// * `{usage}` - Automatically generated or given usage string. + /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments, + /// and subcommands) including titles. + /// * `{unified}` - Unified help for options and flags. + /// * `{flags}` - Help for flags. + /// * `{options}` - Help for options. + /// * `{positionals}` - Help for positionals arguments. + /// * `{subcommands}` - Help for subcommands. + /// * `{after-help}` - Info to be displayed after the help message. + /// * `{before-help}` - Info to be displayed before the help message. + /// + /// The template system is, on purpose, very simple. Therefore the tags have to written + /// in the lowercase and without spacing. + fn write_templated_help(&mut self, parser: &Parser, template: &str) -> ClapResult<()> { + debugln!("Help::write_templated_help;"); + let mut tmplr = Cursor::new(&template); + let mut tag_buf = Cursor::new(vec![0u8; 15]); + + // The strategy is to copy the template from the reader to wrapped stream + // until a tag is found. Depending on its value, the appropriate content is copied + // to the wrapped stream. + // The copy from template is then resumed, repeating this sequence until reading + // the complete template. + + loop { + let tag_length = match copy_and_capture(&mut tmplr, &mut self.writer, &mut tag_buf) { + None => return Ok(()), + Some(Err(e)) => return Err(Error::from(e)), + Some(Ok(val)) if val > 0 => val, + _ => continue, + }; + + debugln!("Help::write_template_help:iter: tag_buf={};", unsafe { + String::from_utf8_unchecked( + tag_buf.get_ref()[0..tag_length] + .iter() + .map(|&i| i) + .collect::>(), + ) + }); + match &tag_buf.get_ref()[0..tag_length] { + b"?" => { + self.writer.write_all(b"Could not decode tag name")?; + } + b"bin" => { + self.write_bin_name(parser)?; + } + b"version" => { + write!( + self.writer, + "{}", + parser.meta.version.unwrap_or("unknown version") + )?; + } + b"author" => { + write!( + self.writer, + "{}", + parser.meta.author.unwrap_or("unknown author") + )?; + } + b"about" => { + write!( + self.writer, + "{}", + parser.meta.about.unwrap_or("unknown about") + )?; + } + b"long-about" => { + write!( + self.writer, + "{}", + parser.meta.long_about.unwrap_or("unknown about") + )?; + } + b"usage" => { + write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?; + } + b"all-args" => { + self.write_all_args(parser)?; + } + b"unified" => { + let opts_flags = parser + .flags() + .map(as_arg_trait) + .chain(parser.opts().map(as_arg_trait)); + self.write_args(opts_flags)?; + } + b"flags" => { + self.write_args(parser.flags().map(as_arg_trait))?; + } + b"options" => { + self.write_args(parser.opts().map(as_arg_trait))?; + } + b"positionals" => { + self.write_args(parser.positionals().map(as_arg_trait))?; + } + b"subcommands" => { + self.write_subcommands(parser)?; + } + b"after-help" => { + write!( + self.writer, + "{}", + parser.meta.more_help.unwrap_or("unknown after-help") + )?; + } + b"before-help" => { + write!( + self.writer, + "{}", + parser.meta.pre_help.unwrap_or("unknown before-help") + )?; + } + // Unknown tag, write it back. + r => { + self.writer.write_all(b"{")?; + self.writer.write_all(r)?; + self.writer.write_all(b"}")?; + } + } + } + } +} + +fn wrap_help(help: &str, avail_chars: usize) -> String { + let wrapper = textwrap::Wrapper::new(avail_chars).break_words(false); + help.lines() + .map(|line| wrapper.fill(line)) + .collect::>() + .join("\n") +} + +#[cfg(test)] +mod test { + use super::wrap_help; + + #[test] + fn wrap_help_last_word() { + let help = String::from("foo bar baz"); + assert_eq!(wrap_help(&help, 5), "foo\nbar\nbaz"); + } +} diff --git a/clap/src/app/meta.rs b/clap/src/app/meta.rs new file mode 100644 index 000000000..c7f128fe5 --- /dev/null +++ b/clap/src/app/meta.rs @@ -0,0 +1,33 @@ +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[derive(Default, Clone)] +pub struct AppMeta<'b> { + pub name: String, + pub bin_name: Option, + pub author: Option<&'b str>, + pub version: Option<&'b str>, + pub long_version: Option<&'b str>, + pub about: Option<&'b str>, + pub long_about: Option<&'b str>, + pub more_help: Option<&'b str>, + pub pre_help: Option<&'b str>, + pub aliases: Option>, // (name, visible) + pub usage_str: Option<&'b str>, + pub usage: Option, + pub help_str: Option<&'b str>, + pub disp_ord: usize, + pub term_w: Option, + pub max_w: Option, + pub template: Option<&'b str>, +} + +impl<'b> AppMeta<'b> { + pub fn new() -> Self { Default::default() } + pub fn with_name(s: String) -> Self { + AppMeta { + name: s, + disp_ord: 999, + ..Default::default() + } + } +} diff --git a/clap/src/app/mod.rs b/clap/src/app/mod.rs new file mode 100644 index 000000000..3a1a3831e --- /dev/null +++ b/clap/src/app/mod.rs @@ -0,0 +1,1839 @@ +mod settings; +pub mod parser; +mod meta; +mod help; +mod validator; +mod usage; + +// Std +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::io::{self, BufRead, BufWriter, Write}; +use std::path::Path; +use std::process; +use std::rc::Rc; +use std::result::Result as StdResult; + +// Third Party +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +// Internal +use app::help::Help; +use app::parser::Parser; +use args::{AnyArg, Arg, ArgGroup, ArgMatcher, ArgMatches, ArgSettings}; +use errors::Result as ClapResult; +pub use self::settings::AppSettings; +use completions::Shell; +use map::{self, VecMap}; + +/// Used to create a representation of a command line program and all possible command line +/// arguments. Application settings are set using the "builder pattern" with the +/// [`App::get_matches`] family of methods being the terminal methods that starts the +/// runtime-parsing process. These methods then return information about the user supplied +/// arguments (or lack there of). +/// +/// **NOTE:** There aren't any mandatory "options" that one must set. The "options" may +/// also appear in any order (so long as one of the [`App::get_matches`] methods is the last method +/// called). +/// +/// # Examples +/// +/// ```no_run +/// # use clap::{App, Arg}; +/// let m = App::new("My Program") +/// .author("Me, me@mail.com") +/// .version("1.0.2") +/// .about("Explains in brief what the program does") +/// .arg( +/// Arg::with_name("in_file").index(1) +/// ) +/// .after_help("Longer explanation to appear after the options when \ +/// displaying the help information from --help or -h") +/// .get_matches(); +/// +/// // Your program logic starts here... +/// ``` +/// [`App::get_matches`]: ./struct.App.html#method.get_matches +#[allow(missing_debug_implementations)] +pub struct App<'a, 'b> +where + 'a: 'b, +{ + #[doc(hidden)] pub p: Parser<'a, 'b>, +} + + +impl<'a, 'b> App<'a, 'b> { + /// Creates a new instance of an application requiring a name. The name may be, but doesn't + /// have to be same as the binary. The name will be displayed to the user when they request to + /// print version or help and usage information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let prog = App::new("My Program") + /// # ; + /// ``` + pub fn new>(n: S) -> Self { + App { + p: Parser::with_name(n.into()), + } + } + + /// Get the name of the app + pub fn get_name(&self) -> &str { &self.p.meta.name } + + /// Get the name of the binary + pub fn get_bin_name(&self) -> Option<&str> { self.p.meta.bin_name.as_ref().map(|s| s.as_str()) } + + /// Creates a new instance of an application requiring a name, but uses the [`crate_authors!`] + /// and [`crate_version!`] macros to fill in the [`App::author`] and [`App::version`] fields. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let prog = App::with_defaults("My Program") + /// # ; + /// ``` + /// [`crate_authors!`]: ./macro.crate_authors!.html + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`App::author`]: ./struct.App.html#method.author + /// [`App::version`]: ./struct.App.html#method.author + #[deprecated(since="2.14.1", note="Can never work; use explicit App::author() and App::version() calls instead")] + pub fn with_defaults>(n: S) -> Self { + let mut a = App { + p: Parser::with_name(n.into()), + }; + a.p.meta.author = Some("Kevin K. "); + a.p.meta.version = Some("2.19.2"); + a + } + + /// Creates a new instance of [`App`] from a .yml (YAML) file. A full example of supported YAML + /// objects can be found in [`examples/17_yaml.rs`] and [`examples/17_yaml.yml`]. One great use + /// for using YAML is when supporting multiple languages and dialects, as each language could + /// be a distinct YAML file and determined at compiletime via `cargo` "features" in your + /// `Cargo.toml` + /// + /// In order to use this function you must compile `clap` with the `features = ["yaml"]` in + /// your settings for the `[dependencies.clap]` table of your `Cargo.toml` + /// + /// **NOTE:** Due to how the YAML objects are built there is a convenience macro for loading + /// the YAML file at compile time (relative to the current file, like modules work). That YAML + /// object can then be passed to this function. + /// + /// # Panics + /// + /// The YAML file must be properly formatted or this function will [`panic!`]. A good way to + /// ensure this doesn't happen is to run your program with the `--help` switch. If this passes + /// without error, you needn't worry because the YAML is properly formatted. + /// + /// # Examples + /// + /// The following example shows how to load a properly formatted YAML file to build an instance + /// of an [`App`] struct. + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::App; + /// # fn main() { + /// let yml = load_yaml!("app.yml"); + /// let app = App::from_yaml(yml); + /// + /// // continued logic goes here, such as `app.get_matches()` etc. + /// # } + /// ``` + /// [`App`]: ./struct.App.html + /// [`examples/17_yaml.rs`]: https://github.com/clap-rs/clap/blob/master/examples/17_yaml.rs + /// [`examples/17_yaml.yml`]: https://github.com/clap-rs/clap/blob/master/examples/17_yaml.yml + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + #[cfg(feature = "yaml")] + pub fn from_yaml(yaml: &'a Yaml) -> App<'a, 'a> { App::from(yaml) } + + /// Sets a string of author(s) that will be displayed to the user when they + /// request the help information with `--help` or `-h`. + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_authors!`] to automatically set your + /// application's author(s) to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .author("Me, me@mymain.com") + /// # ; + /// ``` + /// [`crate_authors!`]: ./macro.crate_authors!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples + pub fn author>(mut self, author: S) -> Self { + self.p.meta.author = Some(author.into()); + self + } + + /// Overrides the system-determined binary name. This should only be used when absolutely + /// necessary, such as when the binary name for your application is misleading, or perhaps + /// *not* how the user should invoke your program. + /// + /// **Pro-tip:** When building things such as third party `cargo` subcommands, this setting + /// **should** be used! + /// + /// **NOTE:** This command **should not** be used for [`SubCommand`]s. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("My Program") + /// .bin_name("my_binary") + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn bin_name>(mut self, name: S) -> Self { + self.p.meta.bin_name = Some(name.into()); + self + } + + /// Sets a string describing what the program does. This will be displayed when displaying help + /// information with `-h`. + /// + /// **NOTE:** If only `about` is provided, and not [`App::long_about`] but the user requests + /// `--help` clap will still display the contents of `about` appropriately + /// + /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be + /// concise + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .about("Does really amazing things to great people") + /// # ; + /// ``` + /// [`App::long_about`]: ./struct.App.html#method.long_about + pub fn about>(mut self, about: S) -> Self { + self.p.meta.about = Some(about.into()); + self + } + + /// Sets a string describing what the program does. This will be displayed when displaying help + /// information. + /// + /// **NOTE:** If only `long_about` is provided, and not [`App::about`] but the user requests + /// `-h` clap will still display the contents of `long_about` appropriately + /// + /// **NOTE:** Only [`App::about`] is used in completion script generation in order to be + /// concise + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .long_about( + /// "Does really amazing things to great people. Now let's talk a little + /// more in depth about how this subcommand really works. It may take about + /// a few lines of text, but that's ok!") + /// # ; + /// ``` + /// [`App::about`]: ./struct.App.html#method.about + pub fn long_about>(mut self, about: S) -> Self { + self.p.meta.long_about = Some(about.into()); + self + } + + /// Sets the program's name. This will be displayed when displaying help information. + /// + /// **Pro-top:** This function is particularly useful when configuring a program via + /// [`App::from_yaml`] in conjunction with the [`crate_name!`] macro to derive the program's + /// name from its `Cargo.toml`. + /// + /// # Examples + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::App; + /// # fn main() { + /// let yml = load_yaml!("app.yml"); + /// let app = App::from_yaml(yml) + /// .name(crate_name!()); + /// + /// // continued logic goes here, such as `app.get_matches()` etc. + /// # } + /// ``` + /// + /// [`App::from_yaml`]: ./struct.App.html#method.from_yaml + /// [`crate_name!`]: ./macro.crate_name.html + pub fn name>(mut self, name: S) -> Self { + self.p.meta.name = name.into(); + self + } + + /// Adds additional help information to be displayed in addition to auto-generated help. This + /// information is displayed **after** the auto-generated help information. This is often used + /// to describe how to use the arguments, or caveats to be noted. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .after_help("Does really amazing things to great people...but be careful with -R") + /// # ; + /// ``` + pub fn after_help>(mut self, help: S) -> Self { + self.p.meta.more_help = Some(help.into()); + self + } + + /// Adds additional help information to be displayed in addition to auto-generated help. This + /// information is displayed **before** the auto-generated help information. This is often used + /// for header information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .before_help("Some info I'd like to appear before the help info") + /// # ; + /// ``` + pub fn before_help>(mut self, help: S) -> Self { + self.p.meta.pre_help = Some(help.into()); + self + } + + /// Sets a string of the version number to be displayed when displaying version or help + /// information with `-V`. + /// + /// **NOTE:** If only `version` is provided, and not [`App::long_version`] but the user + /// requests `--version` clap will still display the contents of `version` appropriately + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your + /// application's version to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version("v0.1.24") + /// # ; + /// ``` + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples + /// [`App::long_version`]: ./struct.App.html#method.long_version + pub fn version>(mut self, ver: S) -> Self { + self.p.meta.version = Some(ver.into()); + self + } + + /// Sets a string of the version number to be displayed when displaying version or help + /// information with `--version`. + /// + /// **NOTE:** If only `long_version` is provided, and not [`App::version`] but the user + /// requests `-V` clap will still display the contents of `long_version` appropriately + /// + /// **Pro-tip:** Use `clap`s convenience macro [`crate_version!`] to automatically set your + /// application's version to the same thing as your crate at compile time. See the [`examples/`] + /// directory for more information + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .long_version( + /// "v0.1.24 + /// commit: abcdef89726d + /// revision: 123 + /// release: 2 + /// binary: myprog") + /// # ; + /// ``` + /// [`crate_version!`]: ./macro.crate_version!.html + /// [`examples/`]: https://github.com/clap-rs/clap/tree/master/examples + /// [`App::version`]: ./struct.App.html#method.version + pub fn long_version>(mut self, ver: S) -> Self { + self.p.meta.long_version = Some(ver.into()); + self + } + + /// Sets a custom usage string to override the auto-generated usage string. + /// + /// This will be displayed to the user when errors are found in argument parsing, or when you + /// call [`ArgMatches::usage`] + /// + /// **CAUTION:** Using this setting disables `clap`s "context-aware" usage strings. After this + /// setting is set, this will be the only usage string displayed to the user! + /// + /// **NOTE:** You do not need to specify the "USAGE: \n\t" portion, as that will + /// still be applied by `clap`, you only need to specify the portion starting + /// with the binary name. + /// + /// **NOTE:** This will not replace the entire help message, *only* the portion + /// showing the usage. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .usage("myapp [-clDas] ") + /// # ; + /// ``` + /// [`ArgMatches::usage`]: ./struct.ArgMatches.html#method.usage + pub fn usage>(mut self, usage: S) -> Self { + self.p.meta.usage_str = Some(usage.into()); + self + } + + /// Sets a custom help message and overrides the auto-generated one. This should only be used + /// when the auto-generated message does not suffice. + /// + /// This will be displayed to the user when they use `--help` or `-h` + /// + /// **NOTE:** This replaces the **entire** help message, so nothing will be auto-generated. + /// + /// **NOTE:** This **only** replaces the help message for the current command, meaning if you + /// are using subcommands, those help messages will still be auto-generated unless you + /// specify a [`Arg::help`] for them as well. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myapp") + /// .help("myapp v1.0\n\ + /// Does awesome things\n\ + /// (C) me@mail.com\n\n\ + /// + /// USAGE: myapp \n\n\ + /// + /// Options:\n\ + /// -h, --help Display this message\n\ + /// -V, --version Display version info\n\ + /// -s Do something with stuff\n\ + /// -v Be verbose\n\n\ + /// + /// Commmands:\n\ + /// help Prints this message\n\ + /// work Do some work") + /// # ; + /// ``` + /// [`Arg::help`]: ./struct.Arg.html#method.help + pub fn help>(mut self, help: S) -> Self { + self.p.meta.help_str = Some(help.into()); + self + } + + /// Sets the [`short`] for the auto-generated `help` argument. + /// + /// By default `clap` automatically assigns `h`, but this can be overridden if you have a + /// different argument which you'd prefer to use the `-h` short with. This can be done by + /// defining your own argument with a lowercase `h` as the [`short`]. + /// + /// `clap` lazily generates these `help` arguments **after** you've defined any arguments of + /// your own. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the [`short`] version + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .help_short("H") // Using an uppercase `H` instead of the default lowercase `h` + /// # ; + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn help_short + 'b>(mut self, s: S) -> Self { + self.p.help_short(s.as_ref()); + self + } + + /// Sets the [`short`] for the auto-generated `version` argument. + /// + /// By default `clap` automatically assigns `V`, but this can be overridden if you have a + /// different argument which you'd prefer to use the `-V` short with. This can be done by + /// defining your own argument with an uppercase `V` as the [`short`]. + /// + /// `clap` lazily generates these `version` arguments **after** you've defined any arguments of + /// your own. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the `short` version + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version_short("v") // Using a lowercase `v` instead of the default capital `V` + /// # ; + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn version_short>(mut self, s: S) -> Self { + self.p.version_short(s.as_ref()); + self + } + + /// Sets the help text for the auto-generated `help` argument. + /// + /// By default `clap` sets this to `"Prints help information"`, but if you're using a + /// different convention for your help messages and would prefer a different phrasing you can + /// override it. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .help_message("Print help information") // Perhaps you want imperative help messages + /// + /// # ; + /// ``` + pub fn help_message>(mut self, s: S) -> Self { + self.p.help_message = Some(s.into()); + self + } + + /// Sets the help text for the auto-generated `version` argument. + /// + /// By default `clap` sets this to `"Prints version information"`, but if you're using a + /// different convention for your help messages and would prefer a different phrasing then you + /// can change it. + /// + /// # Examples + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version_message("Print version information") // Perhaps you want imperative help messages + /// # ; + /// ``` + pub fn version_message>(mut self, s: S) -> Self { + self.p.version_message = Some(s.into()); + self + } + + /// Sets the help template to be used, overriding the default format. + /// + /// Tags arg given inside curly brackets. + /// + /// Valid tags are: + /// + /// * `{bin}` - Binary name. + /// * `{version}` - Version number. + /// * `{author}` - Author information. + /// * `{about}` - General description (from [`App::about`]) + /// * `{usage}` - Automatically generated or given usage string. + /// * `{all-args}` - Help for all arguments (options, flags, positionals arguments, + /// and subcommands) including titles. + /// * `{unified}` - Unified help for options and flags. Note, you must *also* set + /// [`AppSettings::UnifiedHelpMessage`] to fully merge both options and + /// flags, otherwise the ordering is "best effort" + /// * `{flags}` - Help for flags. + /// * `{options}` - Help for options. + /// * `{positionals}` - Help for positionals arguments. + /// * `{subcommands}` - Help for subcommands. + /// * `{after-help}` - Help from [`App::after_help`] + /// * `{before-help}` - Help from [`App::before_help`] + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .version("1.0") + /// .template("{bin} ({version}) - {usage}") + /// # ; + /// ``` + /// **NOTE:** The template system is, on purpose, very simple. Therefore the tags have to be + /// written in lowercase and without spacing. + /// + /// [`App::about`]: ./struct.App.html#method.about + /// [`App::after_help`]: ./struct.App.html#method.after_help + /// [`App::before_help`]: ./struct.App.html#method.before_help + /// [`AppSettings::UnifiedHelpMessage`]: ./enum.AppSettings.html#variant.UnifiedHelpMessage + pub fn template>(mut self, s: S) -> Self { + self.p.meta.template = Some(s.into()); + self + } + + /// Enables a single command, or [`SubCommand`], level settings. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::SubcommandRequired) + /// .setting(AppSettings::WaitOnError) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn setting(mut self, setting: AppSettings) -> Self { + self.p.set(setting); + self + } + + /// Enables multiple command, or [`SubCommand`], level settings + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .settings(&[AppSettings::SubcommandRequired, + /// AppSettings::WaitOnError]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.set(*s); + } + self + } + + /// Enables a single setting that is propagated down through all child [`SubCommand`]s. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .global_setting(AppSettings::SubcommandRequired) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn global_setting(mut self, setting: AppSettings) -> Self { + self.p.set(setting); + self.p.g_settings.set(setting); + self + } + + /// Enables multiple settings which are propagated *down* through all child [`SubCommand`]s. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// **NOTE**: The setting is *only* propagated *down* and not up through parent commands. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .global_settings(&[AppSettings::SubcommandRequired, + /// AppSettings::ColoredHelp]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn global_settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.set(*s); + self.p.g_settings.set(*s) + } + self + } + + /// Disables a single command, or [`SubCommand`], level setting. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .unset_setting(AppSettings::ColorAuto) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn unset_setting(mut self, setting: AppSettings) -> Self { + self.p.unset(setting); + self + } + + /// Disables multiple command, or [`SubCommand`], level settings. + /// + /// See [`AppSettings`] for a full list of possibilities and examples. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .unset_settings(&[AppSettings::ColorAuto, + /// AppSettings::AllowInvalidUtf8]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings`]: ./enum.AppSettings.html + pub fn unset_settings(mut self, settings: &[AppSettings]) -> Self { + for s in settings { + self.p.unset(*s); + } + self + } + + /// Sets the terminal width at which to wrap help messages. Defaults to `120`. Using `0` will + /// ignore terminal widths and use source formatting. + /// + /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows + /// if the `wrap_help` cargo "feature" has been used while compiling. If the terminal width + /// cannot be determined, `clap` defaults to `120`. + /// + /// **NOTE:** This setting applies globally and *not* on a per-command basis. + /// + /// **NOTE:** This setting must be set **before** any subcommands are added! + /// + /// # Platform Specific + /// + /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width. + /// Even on those platforms, this setting is useful if for any reason the terminal width + /// cannot be determined. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .set_term_width(80) + /// # ; + /// ``` + pub fn set_term_width(mut self, width: usize) -> Self { + self.p.meta.term_w = Some(width); + self + } + + /// Sets the max terminal width at which to wrap help messages. Using `0` will ignore terminal + /// widths and use source formatting. + /// + /// `clap` automatically tries to determine the terminal width on Unix, Linux, macOS and Windows + /// if the `wrap_help` cargo "feature" has been used while compiling, but one might want to + /// limit the size (e.g. when the terminal is running fullscreen). + /// + /// **NOTE:** This setting applies globally and *not* on a per-command basis. + /// + /// **NOTE:** This setting must be set **before** any subcommands are added! + /// + /// # Platform Specific + /// + /// Only Unix, Linux, macOS and Windows support automatic determination of terminal width. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::App; + /// App::new("myprog") + /// .max_term_width(100) + /// # ; + /// ``` + pub fn max_term_width(mut self, w: usize) -> Self { + self.p.meta.max_w = Some(w); + self + } + + /// Adds an [argument] to the list of valid possibilities. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// // Adding a single "flag" argument with a short and help text, using Arg::with_name() + /// .arg( + /// Arg::with_name("debug") + /// .short("d") + /// .help("turns on debugging mode") + /// ) + /// // Adding a single "option" argument with a short, a long, and help text using the less + /// // verbose Arg::from_usage() + /// .arg( + /// Arg::from_usage("-c --config=[CONFIG] 'Optionally sets a config file to use'") + /// ) + /// # ; + /// ``` + /// [argument]: ./struct.Arg.html + pub fn arg>>(mut self, a: A) -> Self { + self.p.add_arg(a.into()); + self + } + + /// Adds multiple [arguments] to the list of valid possibilities + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .args( + /// &[Arg::from_usage("[debug] -d 'turns on debugging info'"), + /// Arg::with_name("input").index(1).help("the input file to use")] + /// ) + /// # ; + /// ``` + /// [arguments]: ./struct.Arg.html + pub fn args(mut self, args: &[Arg<'a, 'b>]) -> Self { + for arg in args { + self.p.add_arg_ref(arg); + } + self + } + + /// A convenience method for adding a single [argument] from a usage type string. The string + /// used follows the same rules and syntax as [`Arg::from_usage`] + /// + /// **NOTE:** The downside to using this method is that you can not set any additional + /// properties of the [`Arg`] other than what [`Arg::from_usage`] supports. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .arg_from_usage("-c --config= 'Sets a configuration file to use'") + /// # ; + /// ``` + /// [argument]: ./struct.Arg.html + /// [`Arg`]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + pub fn arg_from_usage(mut self, usage: &'a str) -> Self { + self.p.add_arg(Arg::from_usage(usage)); + self + } + + /// Adds multiple [arguments] at once from a usage string, one per line. See + /// [`Arg::from_usage`] for details on the syntax and rules supported. + /// + /// **NOTE:** Like [`App::arg_from_usage`] the downside is you only set properties for the + /// [`Arg`]s which [`Arg::from_usage`] supports. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// App::new("myprog") + /// .args_from_usage( + /// "-c --config=[FILE] 'Sets a configuration file to use' + /// [debug]... -d 'Sets the debugging level' + /// 'The input file to use'" + /// ) + /// # ; + /// ``` + /// [arguments]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + /// [`App::arg_from_usage`]: ./struct.App.html#method.arg_from_usage + /// [`Arg`]: ./struct.Arg.html + pub fn args_from_usage(mut self, usage: &'a str) -> Self { + for line in usage.lines() { + let l = line.trim(); + if l.is_empty() { + continue; + } + self.p.add_arg(Arg::from_usage(l)); + } + self + } + + /// Allows adding a [`SubCommand`] alias, which function as "hidden" subcommands that + /// automatically dispatch as if this subcommand was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .alias("do-stuff")) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + als.push((name.into(), false)); + } else { + self.p.meta.aliases = Some(vec![(name.into(), false)]); + } + self + } + + /// Allows adding [`SubCommand`] aliases, which function as "hidden" subcommands that + /// automatically dispatch as if this subcommand was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .aliases(&["do-stuff", "do-tests", "tests"])) + /// .arg(Arg::with_name("input") + /// .help("the file to add") + /// .index(1) + /// .required(false)) + /// .get_matches_from(vec!["myprog", "do-tests"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + for n in names { + als.push((n, false)); + } + } else { + self.p.meta.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); + } + self + } + + /// Allows adding a [`SubCommand`] alias that functions exactly like those defined with + /// [`App::alias`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .visible_alias("do-stuff")) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App::alias`]: ./struct.App.html#method.alias + pub fn visible_alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + als.push((name.into(), true)); + } else { + self.p.meta.aliases = Some(vec![(name.into(), true)]); + } + self + } + + /// Allows adding multiple [`SubCommand`] aliases that functions exactly like those defined + /// with [`App::aliases`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .visible_aliases(&["do-stuff", "tests"])) + /// .get_matches_from(vec!["myprog", "do-stuff"]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App::aliases`]: ./struct.App.html#method.aliases + pub fn visible_aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.p.meta.aliases { + for n in names { + als.push((n, true)); + } + } else { + self.p.meta.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); + } + self + } + + /// Adds an [`ArgGroup`] to the application. [`ArgGroup`]s are a family of related arguments. + /// By placing them in a logical group, you can build easier requirement and exclusion rules. + /// For instance, you can make an entire [`ArgGroup`] required, meaning that one (and *only* + /// one) argument from that group must be present at runtime. + /// + /// You can also do things such as name an [`ArgGroup`] as a conflict to another argument. + /// Meaning any of the arguments that belong to that group will cause a failure if present with + /// the conflicting argument. + /// + /// Another added benefit of [`ArgGroup`]s is that you can extract a value from a group instead + /// of determining exactly which argument was used. + /// + /// Finally, using [`ArgGroup`]s to ensure exclusion between arguments is another very common + /// use + /// + /// # Examples + /// + /// The following example demonstrates using an [`ArgGroup`] to ensure that one, and only one, + /// of the arguments from the specified group is present at runtime. + /// + /// ```no_run + /// # use clap::{App, ArgGroup}; + /// App::new("app") + /// .args_from_usage( + /// "--set-ver [ver] 'set the version manually' + /// --major 'auto increase major' + /// --minor 'auto increase minor' + /// --patch 'auto increase patch'") + /// .group(ArgGroup::with_name("vers") + /// .args(&["set-ver", "major", "minor","patch"]) + /// .required(true)) + /// # ; + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn group(mut self, group: ArgGroup<'a>) -> Self { + self.p.add_group(group); + self + } + + /// Adds multiple [`ArgGroup`]s to the [`App`] at once. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, ArgGroup}; + /// App::new("app") + /// .args_from_usage( + /// "--set-ver [ver] 'set the version manually' + /// --major 'auto increase major' + /// --minor 'auto increase minor' + /// --patch 'auto increase patch' + /// -c [FILE] 'a config file' + /// -i [IFACE] 'an interface'") + /// .groups(&[ + /// ArgGroup::with_name("vers") + /// .args(&["set-ver", "major", "minor","patch"]) + /// .required(true), + /// ArgGroup::with_name("input") + /// .args(&["c", "i"]) + /// ]) + /// # ; + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + /// [`App`]: ./struct.App.html + pub fn groups(mut self, groups: &[ArgGroup<'a>]) -> Self { + for g in groups { + self = self.group(g.into()); + } + self + } + + /// Adds a [`SubCommand`] to the list of valid possibilities. Subcommands are effectively + /// sub-[`App`]s, because they can contain their own arguments, subcommands, version, usage, + /// etc. They also function just like [`App`]s, in that they get their own auto generated help, + /// version, and usage. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// App::new("myprog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Controls configuration features") + /// .arg_from_usage(" 'Required configuration file to use'")) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + pub fn subcommand(mut self, subcmd: App<'a, 'b>) -> Self { + self.p.add_subcommand(subcmd); + self + } + + /// Adds multiple subcommands to the list of valid possibilities by iterating over an + /// [`IntoIterator`] of [`SubCommand`]s + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// # App::new("myprog") + /// .subcommands( vec![ + /// SubCommand::with_name("config").about("Controls configuration functionality") + /// .arg(Arg::with_name("config_file").index(1)), + /// SubCommand::with_name("debug").about("Controls debug functionality")]) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html + pub fn subcommands(mut self, subcmds: I) -> Self + where + I: IntoIterator>, + { + for subcmd in subcmds { + self.p.add_subcommand(subcmd); + } + self + } + + /// Allows custom ordering of [`SubCommand`]s within the help message. Subcommands with a lower + /// value will be displayed first in the help message. This is helpful when one would like to + /// emphasise frequently used subcommands, or prioritize those towards the top of the list. + /// Duplicate values **are** allowed. Subcommands with duplicate display orders will be + /// displayed in alphabetical order. + /// + /// **NOTE:** The default is 999 for all subcommands. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, SubCommand}; + /// let m = App::new("cust-ord") + /// .subcommand(SubCommand::with_name("alpha") // typically subcommands are grouped + /// // alphabetically by name. Subcommands + /// // without a display_order have a value of + /// // 999 and are displayed alphabetically with + /// // all other 999 subcommands + /// .about("Some help and text")) + /// .subcommand(SubCommand::with_name("beta") + /// .display_order(1) // In order to force this subcommand to appear *first* + /// // all we have to do is give it a value lower than 999. + /// // Any other subcommands with a value of 1 will be displayed + /// // alphabetically with this one...then 2 values, then 3, etc. + /// .about("I should be first!")) + /// .get_matches_from(vec![ + /// "cust-ord", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```text + /// cust-ord + /// + /// USAGE: + /// cust-ord [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// SUBCOMMANDS: + /// beta I should be first! + /// alpha Some help and text + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + pub fn display_order(mut self, ord: usize) -> Self { + self.p.meta.disp_ord = ord; + self + } + + /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same + /// method as if someone ran `-h` to request the help message + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// let mut app = App::new("myprog"); + /// app.print_help(); + /// ``` + /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html + /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn print_help(&mut self) -> ClapResult<()> { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + + self.p.create_help_and_version(); + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_help(&mut buf_w) + } + + /// Prints the full help message to [`io::stdout()`] using a [`BufWriter`] using the same + /// method as if someone ran `--help` to request the help message + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// let mut app = App::new("myprog"); + /// app.print_long_help(); + /// ``` + /// [`io::stdout()`]: https://doc.rust-lang.org/std/io/fn.stdout.html + /// [`BufWriter`]: https://doc.rust-lang.org/std/io/struct.BufWriter.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn print_long_help(&mut self) -> ClapResult<()> { + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_long_help(&mut buf_w) + } + + /// Writes the full help message to the user to a [`io::Write`] object in the same method as if + /// the user ran `-h` + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// **NOTE:** There is a known bug where this method does not write propagated global arguments + /// or autogenerated arguments (i.e. the default help/version args). Prefer + /// [`App::write_long_help`] instead if possible! + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_help(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn write_help(&self, w: &mut W) -> ClapResult<()> { + // PENDING ISSUE: 808 + // https://github.com/clap-rs/clap/issues/808 + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + // self.p.propagate_globals(); + // self.p.propagate_settings(); + // self.p.derive_display_order(); + // self.p.create_help_and_version(); + + Help::write_app_help(w, self, false) + } + + /// Writes the full help message to the user to a [`io::Write`] object in the same method as if + /// the user ran `--help` + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" help messages + /// depending on if the user ran [`-h` (short)] or [`--help` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_long_help(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-h` (short)]: ./struct.Arg.html#method.help + /// [`--help` (long)]: ./struct.Arg.html#method.long_help + pub fn write_long_help(&mut self, w: &mut W) -> ClapResult<()> { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + self.p.create_help_and_version(); + + Help::write_app_help(w, self, true) + } + + /// Writes the version message to the user to a [`io::Write`] object as if the user ran `-V`. + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages + /// depending on if the user ran [`-V` (short)] or [`--version` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_version(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-V` (short)]: ./struct.App.html#method.version + /// [`--version` (long)]: ./struct.App.html#method.long_version + pub fn write_version(&self, w: &mut W) -> ClapResult<()> { + self.p.write_version(w, false).map_err(From::from) + } + + /// Writes the version message to the user to a [`io::Write`] object + /// + /// **NOTE:** clap has the ability to distinguish between "short" and "long" version messages + /// depending on if the user ran [`-V` (short)] or [`--version` (long)] + /// + /// # Examples + /// + /// ```rust + /// # use clap::App; + /// use std::io; + /// let mut app = App::new("myprog"); + /// let mut out = io::stdout(); + /// app.write_long_version(&mut out).expect("failed to write to stdout"); + /// ``` + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + /// [`-V` (short)]: ./struct.App.html#method.version + /// [`--version` (long)]: ./struct.App.html#method.long_version + pub fn write_long_version(&self, w: &mut W) -> ClapResult<()> { + self.p.write_version(w, true).map_err(From::from) + } + + /// Generate a completions file for a specified shell at compile time. + /// + /// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script" + /// + /// # Examples + /// + /// The following example generates a bash completion script via a `build.rs` script. In this + /// simple example, we'll demo a very small application with only a single subcommand and two + /// args. Real applications could be many multiple levels deep in subcommands, and have tens or + /// potentially hundreds of arguments. + /// + /// First, it helps if we separate out our `App` definition into a separate file. Whether you + /// do this as a function, or bare App definition is a matter of personal preference. + /// + /// ``` + /// // src/cli.rs + /// + /// use clap::{App, Arg, SubCommand}; + /// + /// pub fn build_cli() -> App<'static, 'static> { + /// App::new("compl") + /// .about("Tests completions") + /// .arg(Arg::with_name("file") + /// .help("some input file")) + /// .subcommand(SubCommand::with_name("test") + /// .about("tests things") + /// .arg(Arg::with_name("case") + /// .long("case") + /// .takes_value(true) + /// .help("the case to test"))) + /// } + /// ``` + /// + /// In our regular code, we can simply call this `build_cli()` function, then call + /// `get_matches()`, or any of the other normal methods directly after. For example: + /// + /// ```ignore + /// // src/main.rs + /// + /// mod cli; + /// + /// fn main() { + /// let m = cli::build_cli().get_matches(); + /// + /// // normal logic continues... + /// } + /// ``` + /// + /// Next, we set up our `Cargo.toml` to use a `build.rs` build script. + /// + /// ```toml + /// # Cargo.toml + /// build = "build.rs" + /// + /// [build-dependencies] + /// clap = "2.23" + /// ``` + /// + /// Next, we place a `build.rs` in our project root. + /// + /// ```ignore + /// extern crate clap; + /// + /// use clap::Shell; + /// + /// include!("src/cli.rs"); + /// + /// fn main() { + /// let outdir = match env::var_os("OUT_DIR") { + /// None => return, + /// Some(outdir) => outdir, + /// }; + /// let mut app = build_cli(); + /// app.gen_completions("myapp", // We need to specify the bin name manually + /// Shell::Bash, // Then say which shell to build completions for + /// outdir); // Then say where write the completions to + /// } + /// ``` + /// Now, once we compile there will be a `{bin_name}.bash` file in the directory. + /// Assuming we compiled with debug mode, it would be somewhere similar to + /// `/target/debug/build/myapp-/out/myapp.bash`. + /// + /// Fish shell completions will use the file format `{bin_name}.fish` + pub fn gen_completions, S: Into>( + &mut self, + bin_name: S, + for_shell: Shell, + out_dir: T, + ) { + self.p.meta.bin_name = Some(bin_name.into()); + self.p.gen_completions(for_shell, out_dir.into()); + } + + + /// Generate a completions file for a specified shell at runtime. Until `cargo install` can + /// install extra files like a completion script, this may be used e.g. in a command that + /// outputs the contents of the completion script, to be redirected into a file by the user. + /// + /// # Examples + /// + /// Assuming a separate `cli.rs` like the [example above](./struct.App.html#method.gen_completions), + /// we can let users generate a completion script using a command: + /// + /// ```ignore + /// // src/main.rs + /// + /// mod cli; + /// use std::io; + /// + /// fn main() { + /// let matches = cli::build_cli().get_matches(); + /// + /// if matches.is_present("generate-bash-completions") { + /// cli::build_cli().gen_completions_to("myapp", Shell::Bash, &mut io::stdout()); + /// } + /// + /// // normal logic continues... + /// } + /// + /// ``` + /// + /// Usage: + /// + /// ```shell + /// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash + /// ``` + pub fn gen_completions_to>( + &mut self, + bin_name: S, + for_shell: Shell, + buf: &mut W, + ) { + self.p.meta.bin_name = Some(bin_name.into()); + self.p.gen_completions_to(for_shell, buf); + } + + /// Starts the parsing process, upon a failed parse an error will be displayed to the user and + /// the process will exit with the appropriate error code. By default this method gets all user + /// provided arguments from [`env::args_os`] in order to allow for invalid UTF-8 code points, + /// which are legal on many platforms. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches(); + /// ``` + /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html + pub fn get_matches(self) -> ArgMatches<'a> { self.get_matches_from(&mut env::args_os()) } + + /// Starts the parsing process. This method will return a [`clap::Result`] type instead of exiting + /// the process on failed parse. By default this method gets matches from [`env::args_os`] + /// + /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are + /// used. It will return a [`clap::Error`], where the [`kind`] is a + /// [`ErrorKind::HelpDisplayed`] or [`ErrorKind::VersionDisplayed`] respectively. You must call + /// [`Error::exit`] or perform a [`std::process::exit`]. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_safe() + /// .unwrap_or_else( |e| e.exit() ); + /// ``` + /// [`env::args_os`]: https://doc.rust-lang.org/std/env/fn.args_os.html + /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed + /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html + /// [`clap::Result`]: ./type.Result.html + /// [`clap::Error`]: ./struct.Error.html + /// [`kind`]: ./struct.Error.html + pub fn get_matches_safe(self) -> ClapResult> { + // Start the parsing + self.get_matches_from_safe(&mut env::args_os()) + } + + /// Starts the parsing process. Like [`App::get_matches`] this method does not return a [`clap::Result`] + /// and will automatically exit with an error message. This method, however, lets you specify + /// what iterator to use when performing matches, such as a [`Vec`] of your making. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_from(arg_vec); + /// ``` + /// [`App::get_matches`]: ./struct.App.html#method.get_matches + /// [`clap::Result`]: ./type.Result.html + /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from(mut self, itr: I) -> ArgMatches<'a> + where + I: IntoIterator, + T: Into + Clone, + { + self.get_matches_from_safe_borrow(itr).unwrap_or_else(|e| { + // Otherwise, write to stderr and exit + if e.use_stderr() { + wlnerr!("{}", e.message); + if self.p.is_set(AppSettings::WaitOnError) { + wlnerr!("\nPress [ENTER] / [RETURN] to continue..."); + let mut s = String::new(); + let i = io::stdin(); + i.lock().read_line(&mut s).unwrap(); + } + drop(self); + drop(e); + process::exit(1); + } + + drop(self); + e.exit() + }) + } + + /// Starts the parsing process. A combination of [`App::get_matches_from`], and + /// [`App::get_matches_safe`] + /// + /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are + /// used. It will return a [`clap::Error`], where the [`kind`] is a [`ErrorKind::HelpDisplayed`] + /// or [`ErrorKind::VersionDisplayed`] respectively. You must call [`Error::exit`] or + /// perform a [`std::process::exit`] yourself. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let matches = App::new("myprog") + /// // Args and options go here... + /// .get_matches_from_safe(arg_vec) + /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) }); + /// ``` + /// [`App::get_matches_from`]: ./struct.App.html#method.get_matches_from + /// [`App::get_matches_safe`]: ./struct.App.html#method.get_matches_safe + /// [`ErrorKind::HelpDisplayed`]: ./enum.ErrorKind.html#variant.HelpDisplayed + /// [`ErrorKind::VersionDisplayed`]: ./enum.ErrorKind.html#variant.VersionDisplayed + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`std::process::exit`]: https://doc.rust-lang.org/std/process/fn.exit.html + /// [`clap::Error`]: ./struct.Error.html + /// [`Error::exit`]: ./struct.Error.html#method.exit + /// [`kind`]: ./struct.Error.html + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from_safe(mut self, itr: I) -> ClapResult> + where + I: IntoIterator, + T: Into + Clone, + { + self.get_matches_from_safe_borrow(itr) + } + + /// Starts the parsing process without consuming the [`App`] struct `self`. This is normally not + /// the desired functionality, instead prefer [`App::get_matches_from_safe`] which *does* + /// consume `self`. + /// + /// **NOTE:** The first argument will be parsed as the binary name unless + /// [`AppSettings::NoBinaryName`] is used + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg}; + /// let arg_vec = vec!["my_prog", "some", "args", "to", "parse"]; + /// + /// let mut app = App::new("myprog"); + /// // Args and options go here... + /// let matches = app.get_matches_from_safe_borrow(arg_vec) + /// .unwrap_or_else( |e| { panic!("An error occurs: {}", e) }); + /// ``` + /// [`App`]: ./struct.App.html + /// [`App::get_matches_from_safe`]: ./struct.App.html#method.get_matches_from_safe + /// [`AppSettings::NoBinaryName`]: ./enum.AppSettings.html#variant.NoBinaryName + pub fn get_matches_from_safe_borrow(&mut self, itr: I) -> ClapResult> + where + I: IntoIterator, + T: Into + Clone, + { + // If there are global arguments, or settings we need to propagate them down to subcommands + // before parsing incase we run into a subcommand + if !self.p.is_set(AppSettings::Propagated) { + self.p.propagate_globals(); + self.p.propagate_settings(); + self.p.derive_display_order(); + self.p.set(AppSettings::Propagated); + } + + let mut matcher = ArgMatcher::new(); + + let mut it = itr.into_iter(); + // Get the name of the program (argument 1 of env::args()) and determine the + // actual file + // that was used to execute the program. This is because a program called + // ./target/release/my_prog -a + // will have two arguments, './target/release/my_prog', '-a' but we don't want + // to display + // the full path when displaying help messages and such + if !self.p.is_set(AppSettings::NoBinaryName) { + if let Some(name) = it.next() { + let bn_os = name.into(); + let p = Path::new(&*bn_os); + if let Some(f) = p.file_name() { + if let Some(s) = f.to_os_string().to_str() { + if self.p.meta.bin_name.is_none() { + self.p.meta.bin_name = Some(s.to_owned()); + } + } + } + } + } + + // do the real parsing + if let Err(e) = self.p.get_matches_with(&mut matcher, &mut it.peekable()) { + return Err(e); + } + + let global_arg_vec: Vec<&str> = (&self).p.global_args.iter().map(|ga| ga.b.name).collect(); + matcher.propagate_globals(&global_arg_vec); + + Ok(matcher.into()) + } +} + +#[cfg(feature = "yaml")] +impl<'a> From<&'a Yaml> for App<'a, 'a> { + fn from(mut yaml: &'a Yaml) -> Self { + use args::SubCommand; + // We WANT this to panic on error...so expect() is good. + let mut is_sc = None; + let mut a = if let Some(name) = yaml["name"].as_str() { + App::new(name) + } else { + let yaml_hash = yaml.as_hash().unwrap(); + let sc_key = yaml_hash.keys().nth(0).unwrap(); + is_sc = Some(yaml_hash.get(sc_key).unwrap()); + App::new(sc_key.as_str().unwrap()) + }; + yaml = if let Some(sc) = is_sc { sc } else { yaml }; + + macro_rules! yaml_str { + ($a:ident, $y:ident, $i:ident) => { + if let Some(v) = $y[stringify!($i)].as_str() { + $a = $a.$i(v); + } else if $y[stringify!($i)] != Yaml::BadValue { + panic!("Failed to convert YAML value {:?} to a string", $y[stringify!($i)]); + } + }; + } + + yaml_str!(a, yaml, version); + yaml_str!(a, yaml, long_version); + yaml_str!(a, yaml, author); + yaml_str!(a, yaml, bin_name); + yaml_str!(a, yaml, about); + yaml_str!(a, yaml, long_about); + yaml_str!(a, yaml, before_help); + yaml_str!(a, yaml, after_help); + yaml_str!(a, yaml, template); + yaml_str!(a, yaml, usage); + yaml_str!(a, yaml, help); + yaml_str!(a, yaml, help_short); + yaml_str!(a, yaml, version_short); + yaml_str!(a, yaml, help_message); + yaml_str!(a, yaml, version_message); + yaml_str!(a, yaml, alias); + yaml_str!(a, yaml, visible_alias); + + if let Some(v) = yaml["display_order"].as_i64() { + a = a.display_order(v as usize); + } else if yaml["display_order"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a u64", + yaml["display_order"] + ); + } + if let Some(v) = yaml["setting"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["setting"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to an AppSetting", + yaml["setting"] + ); + } + if let Some(v) = yaml["settings"].as_vec() { + for ys in v { + if let Some(s) = ys.as_str() { + a = a.setting(s.parse().expect("unknown AppSetting found in YAML file")); + } + } + } else if let Some(v) = yaml["settings"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["settings"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a string", + yaml["settings"] + ); + } + if let Some(v) = yaml["global_setting"].as_str() { + a = a.setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["global_setting"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to an AppSetting", + yaml["setting"] + ); + } + if let Some(v) = yaml["global_settings"].as_vec() { + for ys in v { + if let Some(s) = ys.as_str() { + a = a.global_setting(s.parse().expect("unknown AppSetting found in YAML file")); + } + } + } else if let Some(v) = yaml["global_settings"].as_str() { + a = a.global_setting(v.parse().expect("unknown AppSetting found in YAML file")); + } else if yaml["global_settings"] != Yaml::BadValue { + panic!( + "Failed to convert YAML value {:?} to a string", + yaml["global_settings"] + ); + } + + macro_rules! vec_or_str { + ($a:ident, $y:ident, $as_vec:ident, $as_single:ident) => {{ + let maybe_vec = $y[stringify!($as_vec)].as_vec(); + if let Some(vec) = maybe_vec { + for ys in vec { + if let Some(s) = ys.as_str() { + $a = $a.$as_single(s); + } else { + panic!("Failed to convert YAML value {:?} to a string", ys); + } + } + } else { + if let Some(s) = $y[stringify!($as_vec)].as_str() { + $a = $a.$as_single(s); + } else if $y[stringify!($as_vec)] != Yaml::BadValue { + panic!("Failed to convert YAML value {:?} to either a vec or string", $y[stringify!($as_vec)]); + } + } + $a + } + }; + } + + a = vec_or_str!(a, yaml, aliases, alias); + a = vec_or_str!(a, yaml, visible_aliases, visible_alias); + + if let Some(v) = yaml["args"].as_vec() { + for arg_yaml in v { + a = a.arg(Arg::from_yaml(arg_yaml.as_hash().unwrap())); + } + } + if let Some(v) = yaml["subcommands"].as_vec() { + for sc_yaml in v { + a = a.subcommand(SubCommand::from_yaml(sc_yaml)); + } + } + if let Some(v) = yaml["groups"].as_vec() { + for ag_yaml in v { + a = a.group(ArgGroup::from(ag_yaml.as_hash().unwrap())); + } + } + + a + } +} + +impl<'a, 'b> Clone for App<'a, 'b> { + fn clone(&self) -> Self { App { p: self.p.clone() } } +} + +impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> { + fn name(&self) -> &'n str { + "" + } + fn overrides(&self) -> Option<&[&'e str]> { None } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { None } + fn blacklist(&self) -> Option<&[&'e str]> { None } + fn required_unless(&self) -> Option<&[&'e str]> { None } + fn val_names(&self) -> Option<&VecMap<&'e str>> { None } + fn is_set(&self, _: ArgSettings) -> bool { false } + fn val_terminator(&self) -> Option<&'e str> { None } + fn set(&mut self, _: ArgSettings) { + unreachable!("App struct does not support AnyArg::set, this is a bug!") + } + fn has_switch(&self) -> bool { false } + fn max_vals(&self) -> Option { None } + fn num_vals(&self) -> Option { None } + fn possible_vals(&self) -> Option<&[&'e str]> { None } + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { None } + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { None } + fn min_vals(&self) -> Option { None } + fn short(&self) -> Option { None } + fn long(&self) -> Option<&'e str> { None } + fn val_delim(&self) -> Option { None } + fn takes_value(&self) -> bool { true } + fn help(&self) -> Option<&'e str> { self.p.meta.about } + fn long_help(&self) -> Option<&'e str> { self.p.meta.long_about } + fn default_val(&self) -> Option<&'e OsStr> { None } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + None + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None } + fn longest_filter(&self) -> bool { true } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.p.meta.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> fmt::Display for App<'n, 'e> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.p.meta.name) } +} diff --git a/clap/src/app/parser.rs b/clap/src/app/parser.rs new file mode 100644 index 000000000..decfde4f8 --- /dev/null +++ b/clap/src/app/parser.rs @@ -0,0 +1,2167 @@ +// Std +use std::ffi::{OsStr, OsString}; +use std::fmt::Display; +use std::fs::File; +use std::io::{self, BufWriter, Write}; +#[cfg(all(feature = "debug", not(any(target_os = "windows", target_arch = "wasm32"))))] +use std::os::unix::ffi::OsStrExt; +#[cfg(all(feature = "debug", any(target_os = "windows", target_arch = "wasm32")))] +use osstringext::OsStrExt3; +use std::path::PathBuf; +use std::slice::Iter; +use std::iter::Peekable; +use std::cell::Cell; + +// Internal +use INTERNAL_ERROR_MSG; +use INVALID_UTF8; +use SubCommand; +use app::App; +use app::help::Help; +use app::meta::AppMeta; +use app::settings::AppFlags; +use args::{AnyArg, Arg, ArgGroup, ArgMatcher, Base, FlagBuilder, OptBuilder, PosBuilder, Switched}; +use args::settings::ArgSettings; +use completions::ComplGen; +use errors::{Error, ErrorKind}; +use errors::Result as ClapResult; +use fmt::ColorWhen; +use osstringext::OsStrExt2; +use completions::Shell; +use suggestions; +use app::settings::AppSettings as AS; +use app::validator::Validator; +use app::usage; +use map::{self, VecMap}; + +#[derive(Debug, PartialEq, Copy, Clone)] +#[doc(hidden)] +pub enum ParseResult<'a> { + Flag, + Opt(&'a str), + Pos(&'a str), + MaybeHyphenValue, + MaybeNegNum, + NotFound, + ValuesDone, +} + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Clone, Default)] +pub struct Parser<'a, 'b> +where + 'a: 'b, +{ + pub meta: AppMeta<'b>, + settings: AppFlags, + pub g_settings: AppFlags, + pub flags: Vec>, + pub opts: Vec>, + pub positionals: VecMap>, + pub subcommands: Vec>, + pub groups: Vec>, + pub global_args: Vec>, + pub required: Vec<&'a str>, + pub r_ifs: Vec<(&'a str, &'b str, &'a str)>, + pub overrides: Vec<(&'b str, &'a str)>, + help_short: Option, + version_short: Option, + cache: Option<&'a str>, + pub help_message: Option<&'a str>, + pub version_message: Option<&'a str>, + cur_idx: Cell, +} + +impl<'a, 'b> Parser<'a, 'b> +where + 'a: 'b, +{ + pub fn with_name(n: String) -> Self { + Parser { + meta: AppMeta::with_name(n), + g_settings: AppFlags::zeroed(), + cur_idx: Cell::new(0), + ..Default::default() + } + } + + pub fn help_short(&mut self, s: &str) { + let c = s.trim_left_matches(|c| c == '-') + .chars() + .nth(0) + .unwrap_or('h'); + self.help_short = Some(c); + } + + pub fn version_short(&mut self, s: &str) { + let c = s.trim_left_matches(|c| c == '-') + .chars() + .nth(0) + .unwrap_or('V'); + self.version_short = Some(c); + } + + pub fn gen_completions_to(&mut self, for_shell: Shell, buf: &mut W) { + if !self.is_set(AS::Propagated) { + self.propagate_help_version(); + self.build_bin_names(); + self.propagate_globals(); + self.propagate_settings(); + self.set(AS::Propagated); + } + + ComplGen::new(self).generate(for_shell, buf) + } + + pub fn gen_completions(&mut self, for_shell: Shell, od: OsString) { + use std::error::Error; + + let out_dir = PathBuf::from(od); + let name = &*self.meta.bin_name.as_ref().unwrap().clone(); + let file_name = match for_shell { + Shell::Bash => format!("{}.bash", name), + Shell::Fish => format!("{}.fish", name), + Shell::Zsh => format!("_{}", name), + Shell::PowerShell => format!("_{}.ps1", name), + Shell::Elvish => format!("{}.elv", name), + }; + + let mut file = match File::create(out_dir.join(file_name)) { + Err(why) => panic!("couldn't create completion file: {}", why.description()), + Ok(file) => file, + }; + self.gen_completions_to(for_shell, &mut file) + } + + #[inline] + fn app_debug_asserts(&self) -> bool { + assert!(self.verify_positionals()); + let should_err = self.groups.iter().all(|g| { + g.args.iter().all(|arg| { + (self.flags.iter().any(|f| &f.b.name == arg) + || self.opts.iter().any(|o| &o.b.name == arg) + || self.positionals.values().any(|p| &p.b.name == arg) + || self.groups.iter().any(|g| &g.name == arg)) + }) + }); + let g = self.groups.iter().find(|g| { + g.args.iter().any(|arg| { + !(self.flags.iter().any(|f| &f.b.name == arg) + || self.opts.iter().any(|o| &o.b.name == arg) + || self.positionals.values().any(|p| &p.b.name == arg) + || self.groups.iter().any(|g| &g.name == arg)) + }) + }); + assert!( + should_err, + "The group '{}' contains the arg '{}' that doesn't actually exist.", + g.unwrap().name, + g.unwrap() + .args + .iter() + .find(|arg| !(self.flags.iter().any(|f| &&f.b.name == arg) + || self.opts.iter().any(|o| &&o.b.name == arg) + || self.positionals.values().any(|p| &&p.b.name == arg) + || self.groups.iter().any(|g| &&g.name == arg))) + .unwrap() + ); + true + } + + #[inline] + fn debug_asserts(&self, a: &Arg) -> bool { + assert!( + !arg_names!(self).any(|name| name == a.b.name), + format!("Non-unique argument name: {} is already in use", a.b.name) + ); + if let Some(l) = a.s.long { + assert!( + !self.contains_long(l), + "Argument long must be unique\n\n\t--{} is already in use", + l + ); + } + if let Some(s) = a.s.short { + assert!( + !self.contains_short(s), + "Argument short must be unique\n\n\t-{} is already in use", + s + ); + } + let i = if a.index.is_none() { + (self.positionals.len() + 1) + } else { + a.index.unwrap() as usize + }; + assert!( + !self.positionals.contains_key(i), + "Argument \"{}\" has the same index as another positional \ + argument\n\n\tPerhaps try .multiple(true) to allow one positional argument \ + to take multiple values", + a.b.name + ); + assert!( + !(a.is_set(ArgSettings::Required) && a.is_set(ArgSettings::Global)), + "Global arguments cannot be required.\n\n\t'{}' is marked as \ + global and required", + a.b.name + ); + if a.b.is_set(ArgSettings::Last) { + assert!( + !self.positionals + .values() + .any(|p| p.b.is_set(ArgSettings::Last)), + "Only one positional argument may have last(true) set. Found two." + ); + assert!(a.s.long.is_none(), + "Flags or Options may not have last(true) set. {} has both a long and last(true) set.", + a.b.name); + assert!(a.s.short.is_none(), + "Flags or Options may not have last(true) set. {} has both a short and last(true) set.", + a.b.name); + } + true + } + + #[inline] + fn add_conditional_reqs(&mut self, a: &Arg<'a, 'b>) { + if let Some(ref r_ifs) = a.r_ifs { + for &(arg, val) in r_ifs { + self.r_ifs.push((arg, val, a.b.name)); + } + } + } + + #[inline] + fn add_arg_groups(&mut self, a: &Arg<'a, 'b>) { + if let Some(ref grps) = a.b.groups { + for g in grps { + let mut found = false; + if let Some(ref mut ag) = self.groups.iter_mut().find(|grp| &grp.name == g) { + ag.args.push(a.b.name); + found = true; + } + if !found { + let mut ag = ArgGroup::with_name(g); + ag.args.push(a.b.name); + self.groups.push(ag); + } + } + } + } + + #[inline] + fn add_reqs(&mut self, a: &Arg<'a, 'b>) { + if a.is_set(ArgSettings::Required) { + // If the arg is required, add all it's requirements to master required list + self.required.push(a.b.name); + if let Some(ref areqs) = a.b.requires { + for name in areqs + .iter() + .filter(|&&(val, _)| val.is_none()) + .map(|&(_, name)| name) + { + self.required.push(name); + } + } + } + } + + #[inline] + fn implied_settings(&mut self, a: &Arg<'a, 'b>) { + if a.is_set(ArgSettings::Last) { + // if an arg has `Last` set, we need to imply DontCollapseArgsInUsage so that args + // in the usage string don't get confused or left out. + self.set(AS::DontCollapseArgsInUsage); + self.set(AS::ContainsLast); + } + if let Some(l) = a.s.long { + if l == "version" { + self.unset(AS::NeedsLongVersion); + } else if l == "help" { + self.unset(AS::NeedsLongHelp); + } + } + } + + // actually adds the arguments + pub fn add_arg(&mut self, a: Arg<'a, 'b>) { + // if it's global we have to clone anyways + if a.is_set(ArgSettings::Global) { + return self.add_arg_ref(&a); + } + debug_assert!(self.debug_asserts(&a)); + self.add_conditional_reqs(&a); + self.add_arg_groups(&a); + self.add_reqs(&a); + self.implied_settings(&a); + if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { + let i = if a.index.is_none() { + (self.positionals.len() + 1) + } else { + a.index.unwrap() as usize + }; + self.positionals + .insert(i, PosBuilder::from_arg(a, i as u64)); + } else if a.is_set(ArgSettings::TakesValue) { + let mut ob = OptBuilder::from(a); + ob.s.unified_ord = self.flags.len() + self.opts.len(); + self.opts.push(ob); + } else { + let mut fb = FlagBuilder::from(a); + fb.s.unified_ord = self.flags.len() + self.opts.len(); + self.flags.push(fb); + } + } + // actually adds the arguments but from a borrow (which means we have to do some cloning) + pub fn add_arg_ref(&mut self, a: &Arg<'a, 'b>) { + debug_assert!(self.debug_asserts(a)); + self.add_conditional_reqs(a); + self.add_arg_groups(a); + self.add_reqs(a); + self.implied_settings(a); + if a.index.is_some() || (a.s.short.is_none() && a.s.long.is_none()) { + let i = if a.index.is_none() { + (self.positionals.len() + 1) + } else { + a.index.unwrap() as usize + }; + let pb = PosBuilder::from_arg_ref(a, i as u64); + self.positionals.insert(i, pb); + } else if a.is_set(ArgSettings::TakesValue) { + let mut ob = OptBuilder::from(a); + ob.s.unified_ord = self.flags.len() + self.opts.len(); + self.opts.push(ob); + } else { + let mut fb = FlagBuilder::from(a); + fb.s.unified_ord = self.flags.len() + self.opts.len(); + self.flags.push(fb); + } + if a.is_set(ArgSettings::Global) { + self.global_args.push(a.into()); + } + } + + pub fn add_group(&mut self, group: ArgGroup<'a>) { + if group.required { + self.required.push(group.name); + if let Some(ref reqs) = group.requires { + self.required.extend_from_slice(reqs); + } + // if let Some(ref bl) = group.conflicts { + // self.blacklist.extend_from_slice(bl); + // } + } + if self.groups.iter().any(|g| g.name == group.name) { + let grp = self.groups + .iter_mut() + .find(|g| g.name == group.name) + .expect(INTERNAL_ERROR_MSG); + grp.args.extend_from_slice(&group.args); + grp.requires = group.requires.clone(); + grp.conflicts = group.conflicts.clone(); + grp.required = group.required; + } else { + self.groups.push(group); + } + } + + pub fn add_subcommand(&mut self, mut subcmd: App<'a, 'b>) { + debugln!( + "Parser::add_subcommand: term_w={:?}, name={}", + self.meta.term_w, + subcmd.p.meta.name + ); + subcmd.p.meta.term_w = self.meta.term_w; + if subcmd.p.meta.name == "help" { + self.unset(AS::NeedsSubcommandHelp); + } + + self.subcommands.push(subcmd); + } + + pub fn propagate_settings(&mut self) { + debugln!( + "Parser::propagate_settings: self={}, g_settings={:#?}", + self.meta.name, + self.g_settings + ); + for sc in &mut self.subcommands { + debugln!( + "Parser::propagate_settings: sc={}, settings={:#?}, g_settings={:#?}", + sc.p.meta.name, + sc.p.settings, + sc.p.g_settings + ); + // We have to create a new scope in order to tell rustc the borrow of `sc` is + // done and to recursively call this method + { + let vsc = self.settings.is_set(AS::VersionlessSubcommands); + let gv = self.settings.is_set(AS::GlobalVersion); + + if vsc { + sc.p.set(AS::DisableVersion); + } + if gv && sc.p.meta.version.is_none() && self.meta.version.is_some() { + sc.p.set(AS::GlobalVersion); + sc.p.meta.version = Some(self.meta.version.unwrap()); + } + sc.p.settings = sc.p.settings | self.g_settings; + sc.p.g_settings = sc.p.g_settings | self.g_settings; + sc.p.meta.term_w = self.meta.term_w; + sc.p.meta.max_w = self.meta.max_w; + } + sc.p.propagate_settings(); + } + } + + #[cfg_attr(feature = "lints", allow(needless_borrow))] + pub fn derive_display_order(&mut self) { + if self.is_set(AS::DeriveDisplayOrder) { + let unified = self.is_set(AS::UnifiedHelpMessage); + for (i, o) in self.opts + .iter_mut() + .enumerate() + .filter(|&(_, ref o)| o.s.disp_ord == 999) + { + o.s.disp_ord = if unified { o.s.unified_ord } else { i }; + } + for (i, f) in self.flags + .iter_mut() + .enumerate() + .filter(|&(_, ref f)| f.s.disp_ord == 999) + { + f.s.disp_ord = if unified { f.s.unified_ord } else { i }; + } + for (i, sc) in &mut self.subcommands + .iter_mut() + .enumerate() + .filter(|&(_, ref sc)| sc.p.meta.disp_ord == 999) + { + sc.p.meta.disp_ord = i; + } + } + for sc in &mut self.subcommands { + sc.p.derive_display_order(); + } + } + + pub fn required(&self) -> Iter<&str> { self.required.iter() } + + #[cfg_attr(feature = "lints", allow(needless_borrow))] + #[inline] + pub fn has_args(&self) -> bool { + !(self.flags.is_empty() && self.opts.is_empty() && self.positionals.is_empty()) + } + + #[inline] + pub fn has_opts(&self) -> bool { !self.opts.is_empty() } + + #[inline] + pub fn has_flags(&self) -> bool { !self.flags.is_empty() } + + #[inline] + pub fn has_positionals(&self) -> bool { !self.positionals.is_empty() } + + #[inline] + pub fn has_subcommands(&self) -> bool { !self.subcommands.is_empty() } + + #[inline] + pub fn has_visible_opts(&self) -> bool { + if self.opts.is_empty() { + return false; + } + self.opts.iter().any(|o| !o.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_flags(&self) -> bool { + if self.flags.is_empty() { + return false; + } + self.flags.iter().any(|f| !f.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_positionals(&self) -> bool { + if self.positionals.is_empty() { + return false; + } + self.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Hidden)) + } + + #[inline] + pub fn has_visible_subcommands(&self) -> bool { + self.has_subcommands() + && self.subcommands + .iter() + .filter(|sc| sc.p.meta.name != "help") + .any(|sc| !sc.p.is_set(AS::Hidden)) + } + + #[inline] + pub fn is_set(&self, s: AS) -> bool { self.settings.is_set(s) } + + #[inline] + pub fn set(&mut self, s: AS) { self.settings.set(s) } + + #[inline] + pub fn unset(&mut self, s: AS) { self.settings.unset(s) } + + #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))] + pub fn verify_positionals(&self) -> bool { + // Because you must wait until all arguments have been supplied, this is the first chance + // to make assertions on positional argument indexes + // + // First we verify that the index highest supplied index, is equal to the number of + // positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3 + // but no 2) + if let Some((idx, p)) = self.positionals.iter().rev().next() { + assert!( + !(idx != self.positionals.len()), + "Found positional argument \"{}\" whose index is {} but there \ + are only {} positional arguments defined", + p.b.name, + idx, + self.positionals.len() + ); + } + + // Next we verify that only the highest index has a .multiple(true) (if any) + if self.positionals.values().any(|a| { + a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) + }) { + let mut it = self.positionals.values().rev(); + let last = it.next().unwrap(); + let second_to_last = it.next().unwrap(); + // Either the final positional is required + // Or the second to last has a terminator or .last(true) set + let ok = last.is_set(ArgSettings::Required) + || (second_to_last.v.terminator.is_some() + || second_to_last.b.is_set(ArgSettings::Last)) + || last.is_set(ArgSettings::Last); + assert!( + ok, + "When using a positional argument with .multiple(true) that is *not the \ + last* positional argument, the last positional argument (i.e the one \ + with the highest index) *must* have .required(true) or .last(true) set." + ); + let ok = second_to_last.is_set(ArgSettings::Multiple) || last.is_set(ArgSettings::Last); + assert!( + ok, + "Only the last positional argument, or second to last positional \ + argument may be set to .multiple(true)" + ); + + let count = self.positionals + .values() + .filter(|p| p.b.settings.is_set(ArgSettings::Multiple) && p.v.num_vals.is_none()) + .count(); + let ok = count <= 1 + || (last.is_set(ArgSettings::Last) && last.is_set(ArgSettings::Multiple) + && second_to_last.is_set(ArgSettings::Multiple) + && count == 2); + assert!( + ok, + "Only one positional argument with .multiple(true) set is allowed per \ + command, unless the second one also has .last(true) set" + ); + } + + if self.is_set(AS::AllowMissingPositional) { + // Check that if a required positional argument is found, all positions with a lower + // index are also required. + let mut found = false; + let mut foundx2 = false; + for p in self.positionals.values().rev() { + if foundx2 && !p.b.settings.is_set(ArgSettings::Required) { + assert!( + p.b.is_set(ArgSettings::Required), + "Found positional argument which is not required with a lower \ + index than a required positional argument by two or more: {:?} \ + index {}", + p.b.name, + p.index + ); + } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + // Args that .last(true) don't count since they can be required and have + // positionals with a lower index that aren't required + // Imagine: prog [opt1] -- + // Both of these are valid invocations: + // $ prog r1 -- r2 + // $ prog r1 o1 -- r2 + if found { + foundx2 = true; + continue; + } + found = true; + continue; + } else { + found = false; + } + } + } else { + // Check that if a required positional argument is found, all positions with a lower + // index are also required + let mut found = false; + for p in self.positionals.values().rev() { + if found { + assert!( + p.b.is_set(ArgSettings::Required), + "Found positional argument which is not required with a lower \ + index than a required positional argument: {:?} index {}", + p.b.name, + p.index + ); + } else if p.b.is_set(ArgSettings::Required) && !p.b.is_set(ArgSettings::Last) { + // Args that .last(true) don't count since they can be required and have + // positionals with a lower index that aren't required + // Imagine: prog [opt1] -- + // Both of these are valid invocations: + // $ prog r1 -- r2 + // $ prog r1 o1 -- r2 + found = true; + continue; + } + } + } + if self.positionals + .values() + .any(|p| p.b.is_set(ArgSettings::Last) && p.b.is_set(ArgSettings::Required)) + && self.has_subcommands() && !self.is_set(AS::SubcommandsNegateReqs) + { + panic!( + "Having a required positional argument with .last(true) set *and* child \ + subcommands without setting SubcommandsNegateReqs isn't compatible." + ); + } + + true + } + + pub fn propagate_globals(&mut self) { + for sc in &mut self.subcommands { + // We have to create a new scope in order to tell rustc the borrow of `sc` is + // done and to recursively call this method + { + for a in &self.global_args { + sc.p.add_arg_ref(a); + } + } + sc.p.propagate_globals(); + } + } + + // Checks if the arg matches a subcommand name, or any of it's aliases (if defined) + fn possible_subcommand(&self, arg_os: &OsStr) -> (bool, Option<&str>) { + #[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] + use std::os::unix::ffi::OsStrExt; + #[cfg(any(target_os = "windows", target_arch = "wasm32"))] + use osstringext::OsStrExt3; + debugln!("Parser::possible_subcommand: arg={:?}", arg_os); + fn starts(h: &str, n: &OsStr) -> bool { + let n_bytes = n.as_bytes(); + let h_bytes = OsStr::new(h).as_bytes(); + + h_bytes.starts_with(n_bytes) + } + + if self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound) { + return (false, None); + } + if !self.is_set(AS::InferSubcommands) { + if let Some(sc) = find_subcmd!(self, arg_os) { + return (true, Some(&sc.p.meta.name)); + } + } else { + let v = self.subcommands + .iter() + .filter(|s| { + starts(&s.p.meta.name[..], &*arg_os) + || (s.p.meta.aliases.is_some() + && s.p + .meta + .aliases + .as_ref() + .unwrap() + .iter() + .filter(|&&(a, _)| starts(a, &*arg_os)) + .count() == 1) + }) + .map(|sc| &sc.p.meta.name) + .collect::>(); + + for sc in &v { + if OsStr::new(sc) == arg_os { + return (true, Some(sc)); + } + } + + if v.len() == 1 { + return (true, Some(v[0])); + } + } + (false, None) + } + + fn parse_help_subcommand(&self, it: &mut I) -> ClapResult> + where + I: Iterator, + T: Into, + { + debugln!("Parser::parse_help_subcommand;"); + let cmds: Vec = it.map(|c| c.into()).collect(); + let mut help_help = false; + let mut bin_name = self.meta + .bin_name + .as_ref() + .unwrap_or(&self.meta.name) + .clone(); + let mut sc = { + let mut sc: &Parser = self; + for (i, cmd) in cmds.iter().enumerate() { + if &*cmd.to_string_lossy() == "help" { + // cmd help help + help_help = true; + } + if let Some(c) = sc.subcommands + .iter() + .find(|s| &*s.p.meta.name == cmd) + .map(|sc| &sc.p) + { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else if let Some(c) = sc.subcommands + .iter() + .find(|s| { + if let Some(ref als) = s.p.meta.aliases { + als.iter().any(|&(a, _)| a == &*cmd.to_string_lossy()) + } else { + false + } + }) + .map(|sc| &sc.p) + { + sc = c; + if i == cmds.len() - 1 { + break; + } + } else { + return Err(Error::unrecognized_subcommand( + cmd.to_string_lossy().into_owned(), + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + self.color(), + )); + } + bin_name = format!("{} {}", bin_name, &*sc.meta.name); + } + sc.clone() + }; + if help_help { + let mut pb = PosBuilder::new("subcommand", 1); + pb.b.help = Some("The subcommand whose help message to display"); + pb.set(ArgSettings::Multiple); + sc.positionals.insert(1, pb); + sc.settings = sc.settings | self.g_settings; + } else { + sc.create_help_and_version(); + } + if sc.meta.bin_name != self.meta.bin_name { + sc.meta.bin_name = Some(format!("{} {}", bin_name, sc.meta.name)); + } + Err(sc._help(false)) + } + + // allow wrong self convention due to self.valid_neg_num = true and it's a private method + #[cfg_attr(feature = "lints", allow(wrong_self_convention))] + fn is_new_arg(&mut self, arg_os: &OsStr, needs_val_of: ParseResult) -> bool { + debugln!("Parser::is_new_arg:{:?}:{:?}", arg_os, needs_val_of); + let app_wide_settings = if self.is_set(AS::AllowLeadingHyphen) { + true + } else if self.is_set(AS::AllowNegativeNumbers) { + let a = arg_os.to_string_lossy(); + if a.parse::().is_ok() || a.parse::().is_ok() { + self.set(AS::ValidNegNumFound); + true + } else { + false + } + } else { + false + }; + let arg_allows_tac = match needs_val_of { + ParseResult::Opt(name) => { + let o = self.opts + .iter() + .find(|o| o.b.name == name) + .expect(INTERNAL_ERROR_MSG); + (o.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + } + ParseResult::Pos(name) => { + let p = self.positionals + .values() + .find(|p| p.b.name == name) + .expect(INTERNAL_ERROR_MSG); + (p.is_set(ArgSettings::AllowLeadingHyphen) || app_wide_settings) + } + ParseResult::ValuesDone => return true, + _ => false, + }; + debugln!("Parser::is_new_arg: arg_allows_tac={:?}", arg_allows_tac); + + // Is this a new argument, or values from a previous option? + let mut ret = if arg_os.starts_with(b"--") { + debugln!("Parser::is_new_arg: -- found"); + if arg_os.len() == 2 && !arg_allows_tac { + return true; // We have to return true so override everything else + } else if arg_allows_tac { + return false; + } + true + } else if arg_os.starts_with(b"-") { + debugln!("Parser::is_new_arg: - found"); + // a singe '-' by itself is a value and typically means "stdin" on unix systems + !(arg_os.len() == 1) + } else { + debugln!("Parser::is_new_arg: probably value"); + false + }; + + ret = ret && !arg_allows_tac; + + debugln!("Parser::is_new_arg: starts_new_arg={:?}", ret); + ret + } + + // The actual parsing function + #[cfg_attr(feature = "lints", allow(while_let_on_iterator, collapsible_if))] + pub fn get_matches_with( + &mut self, + matcher: &mut ArgMatcher<'a>, + it: &mut Peekable, + ) -> ClapResult<()> + where + I: Iterator, + T: Into + Clone, + { + debugln!("Parser::get_matches_with;"); + // Verify all positional assertions pass + debug_assert!(self.app_debug_asserts()); + if self.positionals.values().any(|a| { + a.b.is_set(ArgSettings::Multiple) && (a.index as usize != self.positionals.len()) + }) + && self.positionals + .values() + .last() + .map_or(false, |p| !p.is_set(ArgSettings::Last)) + { + self.settings.set(AS::LowIndexMultiplePositional); + } + let has_args = self.has_args(); + + // Next we create the `--help` and `--version` arguments and add them if + // necessary + self.create_help_and_version(); + + let mut subcmd_name: Option = None; + let mut needs_val_of: ParseResult<'a> = ParseResult::NotFound; + let mut pos_counter = 1; + let mut sc_is_external = false; + while let Some(arg) = it.next() { + let arg_os = arg.into(); + debugln!( + "Parser::get_matches_with: Begin parsing '{:?}' ({:?})", + arg_os, + &*arg_os.as_bytes() + ); + + self.unset(AS::ValidNegNumFound); + // Is this a new argument, or values from a previous option? + let starts_new_arg = self.is_new_arg(&arg_os, needs_val_of); + if !self.is_set(AS::TrailingValues) && arg_os.starts_with(b"--") && arg_os.len() == 2 + && starts_new_arg + { + debugln!("Parser::get_matches_with: setting TrailingVals=true"); + self.set(AS::TrailingValues); + continue; + } + + // Has the user already passed '--'? Meaning only positional args follow + if !self.is_set(AS::TrailingValues) { + // Does the arg match a subcommand name, or any of it's aliases (if defined) + { + match needs_val_of { + ParseResult::Opt(_) | ParseResult::Pos(_) => (), + _ => { + let (is_match, sc_name) = self.possible_subcommand(&arg_os); + debugln!( + "Parser::get_matches_with: possible_sc={:?}, sc={:?}", + is_match, + sc_name + ); + if is_match { + let sc_name = sc_name.expect(INTERNAL_ERROR_MSG); + if sc_name == "help" && self.is_set(AS::NeedsSubcommandHelp) { + self.parse_help_subcommand(it)?; + } + subcmd_name = Some(sc_name.to_owned()); + break; + } + } + } + } + + if starts_new_arg { + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + + if arg_os.starts_with(b"--") { + needs_val_of = self.parse_long_arg(matcher, &arg_os, it)?; + debugln!( + "Parser:get_matches_with: After parse_long_arg {:?}", + needs_val_of + ); + match needs_val_of { + ParseResult::Flag | ParseResult::Opt(..) | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } else if arg_os.starts_with(b"-") && arg_os.len() != 1 { + // Try to parse short args like normal, if AllowLeadingHyphen or + // AllowNegativeNumbers is set, parse_short_arg will *not* throw + // an error, and instead return Ok(None) + needs_val_of = self.parse_short_arg(matcher, &arg_os)?; + // If it's None, we then check if one of those two AppSettings was set + debugln!( + "Parser:get_matches_with: After parse_short_arg {:?}", + needs_val_of + ); + match needs_val_of { + ParseResult::MaybeNegNum => { + if !(arg_os.to_string_lossy().parse::().is_ok() + || arg_os.to_string_lossy().parse::().is_ok()) + { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + ParseResult::Opt(..) | ParseResult::Flag | ParseResult::ValuesDone => { + continue + } + _ => (), + } + } + } else { + if let ParseResult::Opt(name) = needs_val_of { + // Check to see if parsing a value from a previous arg + let arg = self.opts + .iter() + .find(|o| o.b.name == name) + .expect(INTERNAL_ERROR_MSG); + // get the OptBuilder so we can check the settings + needs_val_of = self.add_val_to_arg(arg, &arg_os, matcher)?; + // get the next value from the iterator + continue; + } + } + } + + if !(self.is_set(AS::ArgsNegateSubcommands) && self.is_set(AS::ValidArgFound)) + && !self.is_set(AS::InferSubcommands) && !self.is_set(AS::AllowExternalSubcommands) + { + if let Some(cdate) = + suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) + { + return Err(Error::invalid_subcommand( + arg_os.to_string_lossy().into_owned(), + cdate, + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + + let low_index_mults = self.is_set(AS::LowIndexMultiplePositional) + && pos_counter == (self.positionals.len() - 1); + let missing_pos = self.is_set(AS::AllowMissingPositional) + && (pos_counter == (self.positionals.len() - 1) + && !self.is_set(AS::TrailingValues)); + debugln!( + "Parser::get_matches_with: Positional counter...{}", + pos_counter + ); + debugln!( + "Parser::get_matches_with: Low index multiples...{:?}", + low_index_mults + ); + if low_index_mults || missing_pos { + if let Some(na) = it.peek() { + let n = (*na).clone().into(); + needs_val_of = if needs_val_of != ParseResult::ValuesDone { + if let Some(p) = self.positionals.get(pos_counter) { + ParseResult::Pos(p.b.name) + } else { + ParseResult::ValuesDone + } + } else { + ParseResult::ValuesDone + }; + let sc_match = { self.possible_subcommand(&n).0 }; + if self.is_new_arg(&n, needs_val_of) || sc_match + || suggestions::did_you_mean(&n.to_string_lossy(), sc_names!(self)) + .is_some() + { + debugln!("Parser::get_matches_with: Bumping the positional counter..."); + pos_counter += 1; + } + } else { + debugln!("Parser::get_matches_with: Bumping the positional counter..."); + pos_counter += 1; + } + } else if (self.is_set(AS::AllowMissingPositional) && self.is_set(AS::TrailingValues)) + || (self.is_set(AS::ContainsLast) && self.is_set(AS::TrailingValues)) + { + // Came to -- and one postional has .last(true) set, so we go immediately + // to the last (highest index) positional + debugln!("Parser::get_matches_with: .last(true) and --, setting last pos"); + pos_counter = self.positionals.len(); + } + if let Some(p) = self.positionals.get(pos_counter) { + if p.is_set(ArgSettings::Last) && !self.is_set(AS::TrailingValues) { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + if !self.is_set(AS::TrailingValues) + && (self.is_set(AS::TrailingVarArg) && pos_counter == self.positionals.len()) + { + self.settings.set(AS::TrailingValues); + } + if self.cache.map_or(true, |name| name != p.b.name) { + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + self.cache = Some(p.b.name); + } + let _ = self.add_val_to_arg(p, &arg_os, matcher)?; + + matcher.inc_occurrence_of(p.b.name); + let _ = self.groups_for_arg(p.b.name) + .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + + self.settings.set(AS::ValidArgFound); + // Only increment the positional counter if it doesn't allow multiples + if !p.b.settings.is_set(ArgSettings::Multiple) { + pos_counter += 1; + } + self.settings.set(AS::ValidArgFound); + } else if self.is_set(AS::AllowExternalSubcommands) { + // Get external subcommand name + let sc_name = match arg_os.to_str() { + Some(s) => s.to_string(), + None => { + if !self.is_set(AS::StrictUtf8) { + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + arg_os.to_string_lossy().into_owned() + } + }; + + // Collect the external subcommand args + let mut sc_m = ArgMatcher::new(); + while let Some(v) = it.next() { + let a = v.into(); + if a.to_str().is_none() && !self.is_set(AS::StrictUtf8) { + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + sc_m.add_val_to("", &a); + } + + matcher.subcommand(SubCommand { + name: sc_name, + matches: sc_m.into(), + }); + sc_is_external = true; + } else if !((self.is_set(AS::AllowLeadingHyphen) + || self.is_set(AS::AllowNegativeNumbers)) + && arg_os.starts_with(b"-")) + && !self.is_set(AS::InferSubcommands) + { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else if !has_args || self.is_set(AS::InferSubcommands) && self.has_subcommands() { + if let Some(cdate) = + suggestions::did_you_mean(&*arg_os.to_string_lossy(), sc_names!(self)) + { + return Err(Error::invalid_subcommand( + arg_os.to_string_lossy().into_owned(), + cdate, + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else { + return Err(Error::unrecognized_subcommand( + arg_os.to_string_lossy().into_owned(), + self.meta.bin_name.as_ref().unwrap_or(&self.meta.name), + self.color(), + )); + } + } else { + return Err(Error::unknown_argument( + &*arg_os.to_string_lossy(), + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + + if !sc_is_external { + if let Some(ref pos_sc_name) = subcmd_name { + let sc_name = { + find_subcmd!(self, pos_sc_name) + .expect(INTERNAL_ERROR_MSG) + .p + .meta + .name + .clone() + }; + self.parse_subcommand(&*sc_name, matcher, it)?; + } else if self.is_set(AS::SubcommandRequired) { + let bn = self.meta.bin_name.as_ref().unwrap_or(&self.meta.name); + return Err(Error::missing_subcommand( + bn, + &usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else if self.is_set(AS::SubcommandRequiredElseHelp) { + debugln!("Parser::get_matches_with: SubcommandRequiredElseHelp=true"); + let mut out = vec![]; + self.write_help_err(&mut out)?; + return Err(Error { + message: String::from_utf8_lossy(&*out).into_owned(), + kind: ErrorKind::MissingArgumentOrSubcommand, + info: None, + }); + } + } + + // In case the last arg was new, we need to process it's overrides + let check_all = self.is_set(AS::AllArgsOverrideSelf); + { + let any_arg = find_any_by_name!(self, self.cache.unwrap_or("")); + matcher.process_arg_overrides( + any_arg, + &mut self.overrides, + &mut self.required, + check_all, + ); + } + + self.remove_overrides(matcher); + + Validator::new(self).validate(needs_val_of, subcmd_name, matcher) + } + + fn remove_overrides(&mut self, matcher: &mut ArgMatcher) { + debugln!("Parser::remove_overrides:{:?};", self.overrides); + for &(overr, name) in &self.overrides { + debugln!("Parser::remove_overrides:iter:({},{});", overr, name); + if matcher.is_present(overr) { + debugln!( + "Parser::remove_overrides:iter:({},{}): removing {};", + overr, + name, + name + ); + matcher.remove(name); + for i in (0..self.required.len()).rev() { + debugln!( + "Parser::remove_overrides:iter:({},{}): removing required {};", + overr, + name, + name + ); + if self.required[i] == name { + self.required.swap_remove(i); + break; + } + } + } + } + } + + fn propagate_help_version(&mut self) { + debugln!("Parser::propagate_help_version;"); + self.create_help_and_version(); + for sc in &mut self.subcommands { + sc.p.propagate_help_version(); + } + } + + fn build_bin_names(&mut self) { + debugln!("Parser::build_bin_names;"); + for sc in &mut self.subcommands { + debug!("Parser::build_bin_names:iter: bin_name set..."); + if sc.p.meta.bin_name.is_none() { + sdebugln!("No"); + let bin_name = format!( + "{}{}{}", + self.meta + .bin_name + .as_ref() + .unwrap_or(&self.meta.name.clone()), + if self.meta.bin_name.is_some() { + " " + } else { + "" + }, + &*sc.p.meta.name + ); + debugln!( + "Parser::build_bin_names:iter: Setting bin_name of {} to {}", + self.meta.name, + bin_name + ); + sc.p.meta.bin_name = Some(bin_name); + } else { + sdebugln!("yes ({:?})", sc.p.meta.bin_name); + } + debugln!( + "Parser::build_bin_names:iter: Calling build_bin_names from...{}", + sc.p.meta.name + ); + sc.p.build_bin_names(); + } + } + + fn parse_subcommand( + &mut self, + sc_name: &str, + matcher: &mut ArgMatcher<'a>, + it: &mut Peekable, + ) -> ClapResult<()> + where + I: Iterator, + T: Into + Clone, + { + use std::fmt::Write; + debugln!("Parser::parse_subcommand;"); + let mut mid_string = String::new(); + if !self.is_set(AS::SubcommandsNegateReqs) { + let mut hs: Vec<&str> = self.required.iter().map(|n| &**n).collect(); + for k in matcher.arg_names() { + hs.push(k); + } + let reqs = usage::get_required_usage_from(self, &hs, Some(matcher), None, false); + + for s in &reqs { + write!(&mut mid_string, " {}", s).expect(INTERNAL_ERROR_MSG); + } + } + mid_string.push_str(" "); + if let Some(ref mut sc) = self.subcommands + .iter_mut() + .find(|s| s.p.meta.name == sc_name) + { + let mut sc_matcher = ArgMatcher::new(); + // bin_name should be parent's bin_name + [] + the sc's name separated by + // a space + sc.p.meta.usage = Some(format!( + "{}{}{}", + self.meta.bin_name.as_ref().unwrap_or(&String::new()), + if self.meta.bin_name.is_some() { + &*mid_string + } else { + "" + }, + &*sc.p.meta.name + )); + sc.p.meta.bin_name = Some(format!( + "{}{}{}", + self.meta.bin_name.as_ref().unwrap_or(&String::new()), + if self.meta.bin_name.is_some() { + " " + } else { + "" + }, + &*sc.p.meta.name + )); + debugln!( + "Parser::parse_subcommand: About to parse sc={}", + sc.p.meta.name + ); + debugln!("Parser::parse_subcommand: sc settings={:#?}", sc.p.settings); + sc.p.get_matches_with(&mut sc_matcher, it)?; + matcher.subcommand(SubCommand { + name: sc.p.meta.name.clone(), + matches: sc_matcher.into(), + }); + } + Ok(()) + } + + pub fn groups_for_arg(&self, name: &str) -> Option> { + debugln!("Parser::groups_for_arg: name={}", name); + + if self.groups.is_empty() { + debugln!("Parser::groups_for_arg: No groups defined"); + return None; + } + let mut res = vec![]; + debugln!("Parser::groups_for_arg: Searching through groups..."); + for grp in &self.groups { + for a in &grp.args { + if a == &name { + sdebugln!("\tFound '{}'", grp.name); + res.push(&*grp.name); + } + } + } + if res.is_empty() { + return None; + } + + Some(res) + } + + pub fn args_in_group(&self, group: &str) -> Vec { + debug_assert!(self.app_debug_asserts()); + + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in &self.groups + .iter() + .find(|g| g.name == group) + .expect(INTERNAL_ERROR_MSG) + .args + { + if let Some(f) = self.flags.iter().find(|f| &f.b.name == n) { + args.push(f.to_string()); + } else if let Some(f) = self.opts.iter().find(|o| &o.b.name == n) { + args.push(f.to_string()); + } else if let Some(p) = self.positionals.values().find(|p| &p.b.name == n) { + args.push(p.b.name.to_owned()); + } else { + g_vec.push(*n); + } + } + + for av in g_vec.iter().map(|g| self.args_in_group(g)) { + args.extend(av); + } + args.dedup(); + args.iter().map(ToOwned::to_owned).collect() + } + + pub fn arg_names_in_group(&self, group: &str) -> Vec<&'a str> { + let mut g_vec = vec![]; + let mut args = vec![]; + + for n in &self.groups + .iter() + .find(|g| g.name == group) + .expect(INTERNAL_ERROR_MSG) + .args + { + if self.groups.iter().any(|g| g.name == *n) { + args.extend(self.arg_names_in_group(n)); + g_vec.push(*n); + } else if !args.contains(n) { + args.push(*n); + } + } + + args.iter().map(|s| *s).collect() + } + + pub fn create_help_and_version(&mut self) { + debugln!("Parser::create_help_and_version;"); + // name is "hclap_help" because flags are sorted by name + if !self.is_set(AS::DisableHelpFlags) && !self.contains_long("help") { + debugln!("Parser::create_help_and_version: Building --help"); + if self.help_short.is_none() && !self.contains_short('h') { + self.help_short = Some('h'); + } + let arg = FlagBuilder { + b: Base { + name: "hclap_help", + help: self.help_message.or(Some("Prints help information")), + ..Default::default() + }, + s: Switched { + short: self.help_short, + long: Some("help"), + ..Default::default() + }, + }; + self.flags.push(arg); + } + if !self.is_set(AS::DisableVersion) && !self.contains_long("version") { + debugln!("Parser::create_help_and_version: Building --version"); + if self.version_short.is_none() && !self.contains_short('V') { + self.version_short = Some('V'); + } + // name is "vclap_version" because flags are sorted by name + let arg = FlagBuilder { + b: Base { + name: "vclap_version", + help: self.version_message.or(Some("Prints version information")), + ..Default::default() + }, + s: Switched { + short: self.version_short, + long: Some("version"), + ..Default::default() + }, + }; + self.flags.push(arg); + } + if !self.subcommands.is_empty() && !self.is_set(AS::DisableHelpSubcommand) + && self.is_set(AS::NeedsSubcommandHelp) + { + debugln!("Parser::create_help_and_version: Building help"); + self.subcommands.push( + App::new("help") + .about("Prints this message or the help of the given subcommand(s)"), + ); + } + } + + // Retrieves the names of all args the user has supplied thus far, except required ones + // because those will be listed in self.required + fn check_for_help_and_version_str(&self, arg: &OsStr) -> ClapResult<()> { + debugln!("Parser::check_for_help_and_version_str;"); + debug!( + "Parser::check_for_help_and_version_str: Checking if --{} is help or version...", + arg.to_str().unwrap() + ); + if arg == "help" && self.is_set(AS::NeedsLongHelp) { + sdebugln!("Help"); + return Err(self._help(true)); + } + if arg == "version" && self.is_set(AS::NeedsLongVersion) { + sdebugln!("Version"); + return Err(self._version(true)); + } + sdebugln!("Neither"); + + Ok(()) + } + + fn check_for_help_and_version_char(&self, arg: char) -> ClapResult<()> { + debugln!("Parser::check_for_help_and_version_char;"); + debug!( + "Parser::check_for_help_and_version_char: Checking if -{} is help or version...", + arg + ); + if let Some(h) = self.help_short { + if arg == h && self.is_set(AS::NeedsLongHelp) { + sdebugln!("Help"); + return Err(self._help(false)); + } + } + if let Some(v) = self.version_short { + if arg == v && self.is_set(AS::NeedsLongVersion) { + sdebugln!("Version"); + return Err(self._version(false)); + } + } + sdebugln!("Neither"); + Ok(()) + } + + fn use_long_help(&self) -> bool { + // In this case, both must be checked. This allows the retention of + // original formatting, but also ensures that the actual -h or --help + // specified by the user is sent through. If HiddenShortHelp is not included, + // then items specified with hidden_short_help will also be hidden. + let should_long = |v: &Base| { + v.long_help.is_some() || + v.is_set(ArgSettings::HiddenLongHelp) || + v.is_set(ArgSettings::HiddenShortHelp) + }; + + self.meta.long_about.is_some() + || self.flags.iter().any(|f| should_long(&f.b)) + || self.opts.iter().any(|o| should_long(&o.b)) + || self.positionals.values().any(|p| should_long(&p.b)) + || self.subcommands + .iter() + .any(|s| s.p.meta.long_about.is_some()) + } + + fn _help(&self, mut use_long: bool) -> Error { + debugln!("Parser::_help: use_long={:?}", use_long); + use_long = use_long && self.use_long_help(); + let mut buf = vec![]; + match Help::write_parser_help(&mut buf, self, use_long) { + Err(e) => e, + _ => Error { + message: String::from_utf8(buf).unwrap_or_default(), + kind: ErrorKind::HelpDisplayed, + info: None, + }, + } + } + + fn _version(&self, use_long: bool) -> Error { + debugln!("Parser::_version: "); + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + match self.print_version(&mut buf_w, use_long) { + Err(e) => e, + _ => Error { + message: String::new(), + kind: ErrorKind::VersionDisplayed, + info: None, + }, + } + } + + fn parse_long_arg( + &mut self, + matcher: &mut ArgMatcher<'a>, + full_arg: &OsStr, + it: &mut Peekable, + ) -> ClapResult> + where + I: Iterator, + T: Into + Clone, + { + // maybe here lifetime should be 'a + debugln!("Parser::parse_long_arg;"); + + // Update the current index + self.cur_idx.set(self.cur_idx.get() + 1); + + let mut val = None; + debug!("Parser::parse_long_arg: Does it contain '='..."); + let arg = if full_arg.contains_byte(b'=') { + let (p0, p1) = full_arg.trim_left_matches(b'-').split_at_byte(b'='); + sdebugln!("Yes '{:?}'", p1); + val = Some(p1); + p0 + } else { + sdebugln!("No"); + full_arg.trim_left_matches(b'-') + }; + + if let Some(opt) = find_opt_by_long!(@os self, arg) { + debugln!( + "Parser::parse_long_arg: Found valid opt '{}'", + opt.to_string() + ); + self.settings.set(AS::ValidArgFound); + let ret = self.parse_opt(val, opt, val.is_some(), matcher)?; + if self.cache.map_or(true, |name| name != opt.b.name) { + self.cache = Some(opt.b.name); + } + + return Ok(ret); + } else if let Some(flag) = find_flag_by_long!(@os self, arg) { + debugln!( + "Parser::parse_long_arg: Found valid flag '{}'", + flag.to_string() + ); + self.settings.set(AS::ValidArgFound); + // Only flags could be help or version, and we need to check the raw long + // so this is the first point to check + self.check_for_help_and_version_str(arg)?; + + self.parse_flag(flag, matcher)?; + + // Handle conflicts, requirements, etc. + if self.cache.map_or(true, |name| name != flag.b.name) { + self.cache = Some(flag.b.name); + } + + return Ok(ParseResult::Flag); + } else if self.is_set(AS::AllowLeadingHyphen) { + return Ok(ParseResult::MaybeHyphenValue); + } else if self.is_set(AS::ValidNegNumFound) { + return Ok(ParseResult::MaybeNegNum); + } + + debugln!("Parser::parse_long_arg: Didn't match anything"); + + let args_rest: Vec<_> = it.map(|x| x.clone().into()).collect(); + let args_rest2: Vec<_> = args_rest.iter().map(|x| x.to_str().expect(INVALID_UTF8)).collect(); + self.did_you_mean_error( + arg.to_str().expect(INVALID_UTF8), + matcher, + &args_rest2[..] + ).map(|_| ParseResult::NotFound) + } + + #[cfg_attr(feature = "lints", allow(len_zero))] + fn parse_short_arg( + &mut self, + matcher: &mut ArgMatcher<'a>, + full_arg: &OsStr, + ) -> ClapResult> { + debugln!("Parser::parse_short_arg: full_arg={:?}", full_arg); + let arg_os = full_arg.trim_left_matches(b'-'); + let arg = arg_os.to_string_lossy(); + + // If AllowLeadingHyphen is set, we want to ensure `-val` gets parsed as `-val` and not + // `-v` `-a` `-l` assuming `v` `a` and `l` are all, or mostly, valid shorts. + if self.is_set(AS::AllowLeadingHyphen) { + if arg.chars().any(|c| !self.contains_short(c)) { + debugln!( + "Parser::parse_short_arg: LeadingHyphenAllowed yet -{} isn't valid", + arg + ); + return Ok(ParseResult::MaybeHyphenValue); + } + } else if self.is_set(AS::ValidNegNumFound) { + // TODO: Add docs about having AllowNegativeNumbers and `-2` as a valid short + // May be better to move this to *after* not finding a valid flag/opt? + debugln!("Parser::parse_short_arg: Valid negative num..."); + return Ok(ParseResult::MaybeNegNum); + } + + let mut ret = ParseResult::NotFound; + for c in arg.chars() { + debugln!("Parser::parse_short_arg:iter:{}", c); + + // update each index because `-abcd` is four indices to clap + self.cur_idx.set(self.cur_idx.get() + 1); + + // Check for matching short options, and return the name if there is no trailing + // concatenated value: -oval + // Option: -o + // Value: val + if let Some(opt) = find_opt_by_short!(self, c) { + debugln!("Parser::parse_short_arg:iter:{}: Found valid opt", c); + self.settings.set(AS::ValidArgFound); + // Check for trailing concatenated value + let p: Vec<_> = arg.splitn(2, c).collect(); + debugln!( + "Parser::parse_short_arg:iter:{}: p[0]={:?}, p[1]={:?}", + c, + p[0].as_bytes(), + p[1].as_bytes() + ); + let i = p[0].as_bytes().len() + 1; + let val = if p[1].as_bytes().len() > 0 { + debugln!( + "Parser::parse_short_arg:iter:{}: val={:?} (bytes), val={:?} (ascii)", + c, + arg_os.split_at(i).1.as_bytes(), + arg_os.split_at(i).1 + ); + Some(arg_os.split_at(i).1) + } else { + None + }; + + // Default to "we're expecting a value later" + let ret = self.parse_opt(val, opt, false, matcher)?; + + if self.cache.map_or(true, |name| name != opt.b.name) { + self.cache = Some(opt.b.name); + } + + return Ok(ret); + } else if let Some(flag) = find_flag_by_short!(self, c) { + debugln!("Parser::parse_short_arg:iter:{}: Found valid flag", c); + self.settings.set(AS::ValidArgFound); + // Only flags can be help or version + self.check_for_help_and_version_char(c)?; + ret = self.parse_flag(flag, matcher)?; + + // Handle conflicts, requirements, overrides, etc. + // Must be called here due to mutabililty + if self.cache.map_or(true, |name| name != flag.b.name) { + self.cache = Some(flag.b.name); + } + } else { + let arg = format!("-{}", c); + return Err(Error::unknown_argument( + &*arg, + "", + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + } + Ok(ret) + } + + fn parse_opt( + &self, + val: Option<&OsStr>, + opt: &OptBuilder<'a, 'b>, + had_eq: bool, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> { + debugln!("Parser::parse_opt; opt={}, val={:?}", opt.b.name, val); + debugln!("Parser::parse_opt; opt.settings={:?}", opt.b.settings); + let mut has_eq = false; + let no_val = val.is_none(); + let empty_vals = opt.is_set(ArgSettings::EmptyValues); + let min_vals_zero = opt.v.min_vals.unwrap_or(1) == 0; + let needs_eq = opt.is_set(ArgSettings::RequireEquals); + + debug!("Parser::parse_opt; Checking for val..."); + if let Some(fv) = val { + has_eq = fv.starts_with(&[b'=']) || had_eq; + let v = fv.trim_left_matches(b'='); + if !empty_vals && (v.len() == 0 || (needs_eq && !has_eq)) { + sdebugln!("Found Empty - Error"); + return Err(Error::empty_value( + opt, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } + sdebugln!("Found - {:?}, len: {}", v, v.len()); + debugln!( + "Parser::parse_opt: {:?} contains '='...{:?}", + fv, + fv.starts_with(&[b'=']) + ); + self.add_val_to_arg(opt, v, matcher)?; + } else if needs_eq && !(empty_vals || min_vals_zero) { + sdebugln!("None, but requires equals...Error"); + return Err(Error::empty_value( + opt, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )); + } else { + sdebugln!("None"); + } + + matcher.inc_occurrence_of(opt.b.name); + // Increment or create the group "args" + self.groups_for_arg(opt.b.name) + .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + + let needs_delim = opt.is_set(ArgSettings::RequireDelimiter); + let mult = opt.is_set(ArgSettings::Multiple); + if no_val && min_vals_zero && !has_eq && needs_eq { + debugln!("Parser::parse_opt: More arg vals not required..."); + return Ok(ParseResult::ValuesDone); + } else if no_val || (mult && !needs_delim) && !has_eq && matcher.needs_more_vals(opt) { + debugln!("Parser::parse_opt: More arg vals required..."); + return Ok(ParseResult::Opt(opt.b.name)); + } + debugln!("Parser::parse_opt: More arg vals not required..."); + Ok(ParseResult::ValuesDone) + } + + fn add_val_to_arg( + &self, + arg: &A, + val: &OsStr, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Parser::add_val_to_arg; arg={}, val={:?}", arg.name(), val); + debugln!( + "Parser::add_val_to_arg; trailing_vals={:?}, DontDelimTrailingVals={:?}", + self.is_set(AS::TrailingValues), + self.is_set(AS::DontDelimitTrailingValues) + ); + if !(self.is_set(AS::TrailingValues) && self.is_set(AS::DontDelimitTrailingValues)) { + if let Some(delim) = arg.val_delim() { + if val.is_empty() { + Ok(self.add_single_val_to_arg(arg, val, matcher)?) + } else { + let mut iret = ParseResult::ValuesDone; + for v in val.split(delim as u32 as u8) { + iret = self.add_single_val_to_arg(arg, v, matcher)?; + } + // If there was a delimiter used, we're not looking for more values + if val.contains_byte(delim as u32 as u8) + || arg.is_set(ArgSettings::RequireDelimiter) + { + iret = ParseResult::ValuesDone; + } + Ok(iret) + } + } else { + self.add_single_val_to_arg(arg, val, matcher) + } + } else { + self.add_single_val_to_arg(arg, val, matcher) + } + } + + fn add_single_val_to_arg( + &self, + arg: &A, + v: &OsStr, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Parser::add_single_val_to_arg;"); + debugln!("Parser::add_single_val_to_arg: adding val...{:?}", v); + + // update the current index because each value is a distinct index to clap + self.cur_idx.set(self.cur_idx.get() + 1); + + // @TODO @docs @p4: docs for indices should probably note that a terminator isn't a value + // and therefore not reported in indices + if let Some(t) = arg.val_terminator() { + if t == v { + return Ok(ParseResult::ValuesDone); + } + } + + matcher.add_val_to(arg.name(), v); + matcher.add_index_to(arg.name(), self.cur_idx.get()); + + // Increment or create the group "args" + if let Some(grps) = self.groups_for_arg(arg.name()) { + for grp in grps { + matcher.add_val_to(&*grp, v); + } + } + + if matcher.needs_more_vals(arg) { + return Ok(ParseResult::Opt(arg.name())); + } + Ok(ParseResult::ValuesDone) + } + + fn parse_flag( + &self, + flag: &FlagBuilder<'a, 'b>, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult> { + debugln!("Parser::parse_flag;"); + + matcher.inc_occurrence_of(flag.b.name); + matcher.add_index_to(flag.b.name, self.cur_idx.get()); + + // Increment or create the group "args" + self.groups_for_arg(flag.b.name) + .and_then(|vec| Some(matcher.inc_occurrences_of(&*vec))); + + Ok(ParseResult::Flag) + } + + fn did_you_mean_error(&self, arg: &str, matcher: &mut ArgMatcher<'a>, args_rest: &[&str]) -> ClapResult<()> { + // Didn't match a flag or option + let suffix = suggestions::did_you_mean_flag_suffix(arg, &args_rest, longs!(self), &self.subcommands); + + // Add the arg to the matches to build a proper usage string + if let Some(name) = suffix.1 { + if let Some(opt) = find_opt_by_long!(self, name) { + self.groups_for_arg(&*opt.b.name) + .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); + matcher.insert(&*opt.b.name); + } else if let Some(flg) = find_flag_by_long!(self, name) { + self.groups_for_arg(&*flg.b.name) + .and_then(|grps| Some(matcher.inc_occurrences_of(&*grps))); + matcher.insert(&*flg.b.name); + } + } + + let used_arg = format!("--{}", arg); + Err(Error::unknown_argument( + &*used_arg, + &*suffix.0, + &*usage::create_error_usage(self, matcher, None), + self.color(), + )) + } + + // Prints the version to the user and exits if quit=true + fn print_version(&self, w: &mut W, use_long: bool) -> ClapResult<()> { + self.write_version(w, use_long)?; + w.flush().map_err(Error::from) + } + + pub fn write_version(&self, w: &mut W, use_long: bool) -> io::Result<()> { + let ver = if use_long { + self.meta + .long_version + .unwrap_or_else(|| self.meta.version.unwrap_or("")) + } else { + self.meta + .version + .unwrap_or_else(|| self.meta.long_version.unwrap_or("")) + }; + if let Some(bn) = self.meta.bin_name.as_ref() { + if bn.contains(' ') { + // Incase we're dealing with subcommands i.e. git mv is translated to git-mv + write!(w, "{} {}", bn.replace(" ", "-"), ver) + } else { + write!(w, "{} {}", &self.meta.name[..], ver) + } + } else { + write!(w, "{} {}", &self.meta.name[..], ver) + } + } + + pub fn print_help(&self) -> ClapResult<()> { + let out = io::stdout(); + let mut buf_w = BufWriter::new(out.lock()); + self.write_help(&mut buf_w) + } + + pub fn write_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, self, false) + } + + pub fn write_long_help(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help(w, self, true) + } + + pub fn write_help_err(&self, w: &mut W) -> ClapResult<()> { + Help::write_parser_help_to_stderr(w, self) + } + + pub fn add_defaults(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + debugln!("Parser::add_defaults;"); + macro_rules! add_val { + (@default $_self:ident, $a:ident, $m:ident) => { + if let Some(ref val) = $a.v.default_val { + debugln!("Parser::add_defaults:iter:{}: has default vals", $a.b.name); + if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { + debugln!("Parser::add_defaults:iter:{}: has no user defined vals", $a.b.name); + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } else if $m.get($a.b.name).is_some() { + debugln!("Parser::add_defaults:iter:{}: has user defined vals", $a.b.name); + } else { + debugln!("Parser::add_defaults:iter:{}: wasn't used", $a.b.name); + + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } else { + debugln!("Parser::add_defaults:iter:{}: doesn't have default vals", $a.b.name); + } + }; + ($_self:ident, $a:ident, $m:ident) => { + if let Some(ref vm) = $a.v.default_vals_ifs { + sdebugln!(" has conditional defaults"); + let mut done = false; + if $m.get($a.b.name).is_none() { + for &(arg, val, default) in vm.values() { + let add = if let Some(a) = $m.get(arg) { + if let Some(v) = val { + a.vals.iter().any(|value| v == value) + } else { + true + } + } else { + false + }; + if add { + $_self.add_val_to_arg($a, OsStr::new(default), $m)?; + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + done = true; + break; + } + } + } + + if done { + continue; // outer loop (outside macro) + } + } else { + sdebugln!(" doesn't have conditional defaults"); + } + add_val!(@default $_self, $a, $m) + }; + } + + for o in &self.opts { + debug!("Parser::add_defaults:iter:{}:", o.b.name); + add_val!(self, o, matcher); + } + for p in self.positionals.values() { + debug!("Parser::add_defaults:iter:{}:", p.b.name); + add_val!(self, p, matcher); + } + Ok(()) + } + + pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + macro_rules! add_val { + ($_self:ident, $a:ident, $m:ident) => { + if let Some(ref val) = $a.v.env { + if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { + if let Some(ref val) = val.1 { + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } else { + if let Some(ref val) = val.1 { + $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + + if $_self.cache.map_or(true, |name| name != $a.name()) { + $_self.cache = Some($a.name()); + } + } + } + } + }; + } + + for o in &self.opts { + add_val!(self, o, matcher); + } + for p in self.positionals.values() { + add_val!(self, p, matcher); + } + Ok(()) + } + + pub fn flags(&self) -> Iter> { self.flags.iter() } + + pub fn opts(&self) -> Iter> { self.opts.iter() } + + pub fn positionals(&self) -> map::Values> { self.positionals.values() } + + pub fn subcommands(&self) -> Iter { self.subcommands.iter() } + + // Should we color the output? None=determined by output location, true=yes, false=no + #[doc(hidden)] + pub fn color(&self) -> ColorWhen { + debugln!("Parser::color;"); + debug!("Parser::color: Color setting..."); + if self.is_set(AS::ColorNever) { + sdebugln!("Never"); + ColorWhen::Never + } else if self.is_set(AS::ColorAlways) { + sdebugln!("Always"); + ColorWhen::Always + } else { + sdebugln!("Auto"); + ColorWhen::Auto + } + } + + pub fn find_any_arg(&self, name: &str) -> Option<&AnyArg<'a, 'b>> { + if let Some(f) = find_by_name!(self, name, flags, iter) { + return Some(f); + } + if let Some(o) = find_by_name!(self, name, opts, iter) { + return Some(o); + } + if let Some(p) = find_by_name!(self, name, positionals, values) { + return Some(p); + } + None + } + + /// Check is a given string matches the binary name for this parser + fn is_bin_name(&self, value: &str) -> bool { + self.meta + .bin_name + .as_ref() + .and_then(|name| Some(value == name)) + .unwrap_or(false) + } + + /// Check is a given string is an alias for this parser + fn is_alias(&self, value: &str) -> bool { + self.meta + .aliases + .as_ref() + .and_then(|aliases| { + for alias in aliases { + if alias.0 == value { + return Some(true); + } + } + Some(false) + }) + .unwrap_or(false) + } + + // Only used for completion scripts due to bin_name messiness + #[cfg_attr(feature = "lints", allow(block_in_if_condition_stmt))] + pub fn find_subcommand(&'b self, sc: &str) -> Option<&'b App<'a, 'b>> { + debugln!("Parser::find_subcommand: sc={}", sc); + debugln!( + "Parser::find_subcommand: Currently in Parser...{}", + self.meta.bin_name.as_ref().unwrap() + ); + for s in &self.subcommands { + if s.p.is_bin_name(sc) { + return Some(s); + } + // XXX: why do we split here? + // isn't `sc` supposed to be single word already? + let last = sc.split(' ').rev().next().expect(INTERNAL_ERROR_MSG); + if s.p.is_alias(last) { + return Some(s); + } + + if let Some(app) = s.p.find_subcommand(sc) { + return Some(app); + } + } + None + } + + #[inline] + fn contains_long(&self, l: &str) -> bool { longs!(self).any(|al| al == &l) } + + #[inline] + fn contains_short(&self, s: char) -> bool { shorts!(self).any(|arg_s| arg_s == &s) } +} diff --git a/clap/src/app/settings.rs b/clap/src/app/settings.rs new file mode 100644 index 000000000..ec0399722 --- /dev/null +++ b/clap/src/app/settings.rs @@ -0,0 +1,1174 @@ +// Std +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::str::FromStr; +use std::ops::BitOr; + +bitflags! { + struct Flags: u64 { + const SC_NEGATE_REQS = 1; + const SC_REQUIRED = 1 << 1; + const A_REQUIRED_ELSE_HELP = 1 << 2; + const GLOBAL_VERSION = 1 << 3; + const VERSIONLESS_SC = 1 << 4; + const UNIFIED_HELP = 1 << 5; + const WAIT_ON_ERROR = 1 << 6; + const SC_REQUIRED_ELSE_HELP= 1 << 7; + const NEEDS_LONG_HELP = 1 << 8; + const NEEDS_LONG_VERSION = 1 << 9; + const NEEDS_SC_HELP = 1 << 10; + const DISABLE_VERSION = 1 << 11; + const HIDDEN = 1 << 12; + const TRAILING_VARARG = 1 << 13; + const NO_BIN_NAME = 1 << 14; + const ALLOW_UNK_SC = 1 << 15; + const UTF8_STRICT = 1 << 16; + const UTF8_NONE = 1 << 17; + const LEADING_HYPHEN = 1 << 18; + const NO_POS_VALUES = 1 << 19; + const NEXT_LINE_HELP = 1 << 20; + const DERIVE_DISP_ORDER = 1 << 21; + const COLORED_HELP = 1 << 22; + const COLOR_ALWAYS = 1 << 23; + const COLOR_AUTO = 1 << 24; + const COLOR_NEVER = 1 << 25; + const DONT_DELIM_TRAIL = 1 << 26; + const ALLOW_NEG_NUMS = 1 << 27; + const LOW_INDEX_MUL_POS = 1 << 28; + const DISABLE_HELP_SC = 1 << 29; + const DONT_COLLAPSE_ARGS = 1 << 30; + const ARGS_NEGATE_SCS = 1 << 31; + const PROPAGATE_VALS_DOWN = 1 << 32; + const ALLOW_MISSING_POS = 1 << 33; + const TRAILING_VALUES = 1 << 34; + const VALID_NEG_NUM_FOUND = 1 << 35; + const PROPAGATED = 1 << 36; + const VALID_ARG_FOUND = 1 << 37; + const INFER_SUBCOMMANDS = 1 << 38; + const CONTAINS_LAST = 1 << 39; + const ARGS_OVERRIDE_SELF = 1 << 40; + const DISABLE_HELP_FLAGS = 1 << 41; + } +} + +#[doc(hidden)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct AppFlags(Flags); + +impl BitOr for AppFlags { + type Output = Self; + fn bitor(self, rhs: Self) -> Self { AppFlags(self.0 | rhs.0) } +} + +impl Default for AppFlags { + fn default() -> Self { + AppFlags( + Flags::NEEDS_LONG_VERSION | Flags::NEEDS_LONG_HELP | Flags::NEEDS_SC_HELP + | Flags::UTF8_NONE | Flags::COLOR_AUTO, + ) + } +} + +#[allow(deprecated)] +impl AppFlags { + pub fn new() -> Self { AppFlags::default() } + pub fn zeroed() -> Self { AppFlags(Flags::empty()) } + + impl_settings! { AppSettings, + ArgRequiredElseHelp => Flags::A_REQUIRED_ELSE_HELP, + ArgsNegateSubcommands => Flags::ARGS_NEGATE_SCS, + AllArgsOverrideSelf => Flags::ARGS_OVERRIDE_SELF, + AllowExternalSubcommands => Flags::ALLOW_UNK_SC, + AllowInvalidUtf8 => Flags::UTF8_NONE, + AllowLeadingHyphen => Flags::LEADING_HYPHEN, + AllowNegativeNumbers => Flags::ALLOW_NEG_NUMS, + AllowMissingPositional => Flags::ALLOW_MISSING_POS, + ColoredHelp => Flags::COLORED_HELP, + ColorAlways => Flags::COLOR_ALWAYS, + ColorAuto => Flags::COLOR_AUTO, + ColorNever => Flags::COLOR_NEVER, + DontDelimitTrailingValues => Flags::DONT_DELIM_TRAIL, + DontCollapseArgsInUsage => Flags::DONT_COLLAPSE_ARGS, + DeriveDisplayOrder => Flags::DERIVE_DISP_ORDER, + DisableHelpFlags => Flags::DISABLE_HELP_FLAGS, + DisableHelpSubcommand => Flags::DISABLE_HELP_SC, + DisableVersion => Flags::DISABLE_VERSION, + GlobalVersion => Flags::GLOBAL_VERSION, + HidePossibleValuesInHelp => Flags::NO_POS_VALUES, + Hidden => Flags::HIDDEN, + LowIndexMultiplePositional => Flags::LOW_INDEX_MUL_POS, + NeedsLongHelp => Flags::NEEDS_LONG_HELP, + NeedsLongVersion => Flags::NEEDS_LONG_VERSION, + NeedsSubcommandHelp => Flags::NEEDS_SC_HELP, + NoBinaryName => Flags::NO_BIN_NAME, + PropagateGlobalValuesDown=> Flags::PROPAGATE_VALS_DOWN, + StrictUtf8 => Flags::UTF8_STRICT, + SubcommandsNegateReqs => Flags::SC_NEGATE_REQS, + SubcommandRequired => Flags::SC_REQUIRED, + SubcommandRequiredElseHelp => Flags::SC_REQUIRED_ELSE_HELP, + TrailingVarArg => Flags::TRAILING_VARARG, + UnifiedHelpMessage => Flags::UNIFIED_HELP, + NextLineHelp => Flags::NEXT_LINE_HELP, + VersionlessSubcommands => Flags::VERSIONLESS_SC, + WaitOnError => Flags::WAIT_ON_ERROR, + TrailingValues => Flags::TRAILING_VALUES, + ValidNegNumFound => Flags::VALID_NEG_NUM_FOUND, + Propagated => Flags::PROPAGATED, + ValidArgFound => Flags::VALID_ARG_FOUND, + InferSubcommands => Flags::INFER_SUBCOMMANDS, + ContainsLast => Flags::CONTAINS_LAST + } +} + +/// Application level settings, which affect how [`App`] operates +/// +/// **NOTE:** When these settings are used, they apply only to current command, and are *not* +/// propagated down or up through child or parent subcommands +/// +/// [`App`]: ./struct.App.html +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum AppSettings { + /// Specifies that any invalid UTF-8 code points should *not* be treated as an error. + /// This is the default behavior of `clap`. + /// + /// **NOTE:** Using argument values with invalid UTF-8 code points requires using + /// [`ArgMatches::os_value_of`], [`ArgMatches::os_values_of`], [`ArgMatches::lossy_value_of`], + /// or [`ArgMatches::lossy_values_of`] for those particular arguments which may contain invalid + /// UTF-8 values + /// + /// **NOTE:** This rule only applies to argument values, as flags, options, and + /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// + /// # Platform Specific + /// + /// Non Windows systems only + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, AppSettings}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let r = App::new("myprog") + /// //.setting(AppSettings::AllowInvalidUtf8) + /// .arg_from_usage(" 'some positional arg'") + /// .get_matches_from_safe( + /// vec![ + /// OsString::from("myprog"), + /// OsString::from_vec(vec![0xe9])]); + /// + /// assert!(r.is_ok()); + /// let m = r.unwrap(); + /// assert_eq!(m.value_of_os("arg").unwrap().as_bytes(), &[0xe9]); + /// ``` + /// [`ArgMatches::os_value_of`]: ./struct.ArgMatches.html#method.os_value_of + /// [`ArgMatches::os_values_of`]: ./struct.ArgMatches.html#method.os_values_of + /// [`ArgMatches::lossy_value_of`]: ./struct.ArgMatches.html#method.lossy_value_of + /// [`ArgMatches::lossy_values_of`]: ./struct.ArgMatches.html#method.lossy_values_of + /// [`SubCommand`]: ./struct.SubCommand.html + AllowInvalidUtf8, + + /// Essentially sets [`Arg::overrides_with("itself")`] for all arguments. + /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). This setting ignores positional arguments. + /// [`Arg::overrides_with("itself")`]: ./struct.Arg.html#method.overrides_with + AllArgsOverrideSelf, + + /// Specifies that leading hyphens are allowed in argument *values*, such as negative numbers + /// like `-10`. (which would otherwise be parsed as another flag or option) + /// + /// **NOTE:** Use this setting with caution as it silences certain circumstances which would + /// otherwise be an error (such as accidentally forgetting to specify a value for leading + /// option). It is preferred to set this on a per argument basis, via [`Arg::allow_hyphen_values`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{Arg, App, AppSettings}; + /// // Imagine you needed to represent negative numbers as well, such as -10 + /// let m = App::new("nums") + /// .setting(AppSettings::AllowLeadingHyphen) + /// .arg(Arg::with_name("neg").index(1)) + /// .get_matches_from(vec![ + /// "nums", "-20" + /// ]); + /// + /// assert_eq!(m.value_of("neg"), Some("-20")); + /// # ; + /// ``` + /// [`Arg::allow_hyphen_values`]: ./struct.Arg.html#method.allow_hyphen_values + AllowLeadingHyphen, + + /// Allows negative numbers to pass as values. This is similar to + /// `AllowLeadingHyphen` except that it only allows numbers, all + /// other undefined leading hyphens will fail to parse. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::AllowNegativeNumbers) + /// .arg(Arg::with_name("num")) + /// .get_matches_from_safe(vec![ + /// "myprog", "-20" + /// ]); + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("num").unwrap(), "-20"); + /// ``` + /// [`AllowLeadingHyphen`]: ./enum.AppSettings.html#variant.AllowLeadingHyphen + AllowNegativeNumbers, + + /// Allows one to implement two styles of CLIs where positionals can be used out of order. + /// + /// The first example is a CLI where the second to last positional argument is optional, but + /// the final positional argument is required. Such as `$ prog [optional] ` where one + /// of the two following usages is allowed: + /// + /// * `$ prog [optional] ` + /// * `$ prog ` + /// + /// This would otherwise not be allowed. This is useful when `[optional]` has a default value. + /// + /// **Note:** when using this style of "missing positionals" the final positional *must* be + /// [required] if `--` will not be used to skip to the final positional argument. + /// + /// **Note:** This style also only allows a single positional argument to be "skipped" without + /// the use of `--`. To skip more than one, see the second example. + /// + /// The second example is when one wants to skip multiple optional positional arguments, and use + /// of the `--` operator is OK (but not required if all arguments will be specified anyways). + /// + /// For example, imagine a CLI which has three positional arguments `[foo] [bar] [baz]...` where + /// `baz` accepts multiple values (similar to man `ARGS...` style training arguments). + /// + /// With this setting the following invocations are possible: + /// + /// * `$ prog foo bar baz1 baz2 baz3` + /// * `$ prog foo -- baz1 baz2 baz3` + /// * `$ prog -- baz1 baz2 baz3` + /// + /// # Examples + /// + /// Style number one from above: + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("arg1")) + /// .arg(Arg::with_name("arg2") + /// .required(true)) + /// .get_matches_from(vec![ + /// "prog", "other" + /// ]); + /// + /// assert_eq!(m.value_of("arg1"), None); + /// assert_eq!(m.value_of("arg2"), Some("other")); + /// ``` + /// + /// Now the same example, but using a default value for the first optional positional argument + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("arg1") + /// .default_value("something")) + /// .arg(Arg::with_name("arg2") + /// .required(true)) + /// .get_matches_from(vec![ + /// "prog", "other" + /// ]); + /// + /// assert_eq!(m.value_of("arg1"), Some("something")); + /// assert_eq!(m.value_of("arg2"), Some("other")); + /// ``` + /// Style number two from above: + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("foo")) + /// .arg(Arg::with_name("bar")) + /// .arg(Arg::with_name("baz").multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "foo", "bar", "baz1", "baz2", "baz3" + /// ]); + /// + /// assert_eq!(m.value_of("foo"), Some("foo")); + /// assert_eq!(m.value_of("bar"), Some("bar")); + /// assert_eq!(m.values_of("baz").unwrap().collect::>(), &["baz1", "baz2", "baz3"]); + /// ``` + /// + /// Now notice if we don't specify `foo` or `baz` but use the `--` operator. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowMissingPositional) + /// .arg(Arg::with_name("foo")) + /// .arg(Arg::with_name("bar")) + /// .arg(Arg::with_name("baz").multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "--", "baz1", "baz2", "baz3" + /// ]); + /// + /// assert_eq!(m.value_of("foo"), None); + /// assert_eq!(m.value_of("bar"), None); + /// assert_eq!(m.values_of("baz").unwrap().collect::>(), &["baz1", "baz2", "baz3"]); + /// ``` + /// [required]: ./struct.Arg.html#method.required + AllowMissingPositional, + + /// Specifies that an unexpected positional argument, + /// which would otherwise cause a [`ErrorKind::UnknownArgument`] error, + /// should instead be treated as a [`SubCommand`] within the [`ArgMatches`] struct. + /// + /// **NOTE:** Use this setting with caution, + /// as a truly unexpected argument (i.e. one that is *NOT* an external subcommand) + /// will **not** cause an error and instead be treated as a potential subcommand. + /// One should check for such cases manually and inform the user appropriately. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let m = App::new("myprog") + /// .setting(AppSettings::AllowExternalSubcommands) + /// .get_matches_from(vec![ + /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" + /// ]); + /// + /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty + /// // string argument name + /// match m.subcommand() { + /// (external, Some(ext_m)) => { + /// let ext_args: Vec<&str> = ext_m.values_of("").unwrap().collect(); + /// assert_eq!(external, "subcmd"); + /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); + /// }, + /// _ => {}, + /// } + /// ``` + /// [`ErrorKind::UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + AllowExternalSubcommands, + + /// Specifies that use of a valid [argument] negates [subcommands] being used after. By default + /// `clap` allows arguments between subcommands such as + /// ` [cmd_args] [cmd2_args] [cmd3_args]`. This setting disables that + /// functionality and says that arguments can only follow the *final* subcommand. For instance + /// using this setting makes only the following invocations possible: + /// + /// * ` [cmd3_args]` + /// * ` [cmd2_args]` + /// * ` [cmd_args]` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ArgsNegateSubcommands) + /// # ; + /// ``` + /// [subcommands]: ./struct.SubCommand.html + /// [argument]: ./struct.Arg.html + ArgsNegateSubcommands, + + /// Specifies that the help text should be displayed (and then exit gracefully), + /// if no arguments are present at runtime (i.e. an empty run such as, `$ myprog`. + /// + /// **NOTE:** [`SubCommand`]s count as arguments + /// + /// **NOTE:** Setting [`Arg::default_value`] effectively disables this option as it will + /// ensure that some argument is always present. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ArgRequiredElseHelp) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + ArgRequiredElseHelp, + + /// Uses colorized help messages. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms) + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColoredHelp) + /// .get_matches(); + /// ``` + ColoredHelp, + + /// Enables colored output only when the output is going to a terminal or TTY. + /// + /// **NOTE:** This is the default behavior of `clap`. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature. + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms). + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorAuto) + /// .get_matches(); + /// ``` + ColorAuto, + + /// Enables colored output regardless of whether or not the output is going to a terminal/TTY. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature. + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms). + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorAlways) + /// .get_matches(); + /// ``` + ColorAlways, + + /// Disables colored output no matter if the output is going to a terminal/TTY, or not. + /// + /// **NOTE:** Must be compiled with the `color` cargo feature + /// + /// # Platform Specific + /// + /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms) + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::ColorNever) + /// .get_matches(); + /// ``` + ColorNever, + + /// Disables the automatic collapsing of positional args into `[ARGS]` inside the usage string + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DontCollapseArgsInUsage) + /// .get_matches(); + /// ``` + DontCollapseArgsInUsage, + + /// Disables the automatic delimiting of values when `--` or [`AppSettings::TrailingVarArg`] + /// was used. + /// + /// **NOTE:** The same thing can be done manually by setting the final positional argument to + /// [`Arg::use_delimiter(false)`]. Using this setting is safer, because it's easier to locate + /// when making changes. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DontDelimitTrailingValues) + /// .get_matches(); + /// ``` + /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg + /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter + DontDelimitTrailingValues, + + /// Disables `-h` and `--help` [`App`] without affecting any of the [`SubCommand`]s + /// (Defaults to `false`; application *does* have help flags) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .setting(AppSettings::DisableHelpFlags) + /// .get_matches_from_safe(vec![ + /// "myprog", "-h" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .setting(AppSettings::DisableHelpFlags) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-h" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::HelpDisplayed); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + DisableHelpFlags, + + /// Disables the `help` subcommand + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind, SubCommand}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableHelpSubcommand) + /// // Normally, creating a subcommand causes a `help` subcommand to automatically + /// // be generated as well + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "help" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + DisableHelpSubcommand, + + /// Disables `-V` and `--version` [`App`] without affecting any of the [`SubCommand`]s + /// (Defaults to `false`; application *does* have a version flag) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .get_matches_from_safe(vec![ + /// "myprog", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::DisableVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::VersionDisplayed); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + DisableVersion, + + /// Displays the arguments and [`SubCommand`]s in the help message in the order that they were + /// declared in, and not alphabetically which is the default. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::DeriveDisplayOrder) + /// .get_matches(); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + DeriveDisplayOrder, + + /// Specifies to use the version of the current command for all child [`SubCommand`]s. + /// (Defaults to `false`; subcommands have independent version strings from their parents.) + /// + /// **NOTE:** The version for the current command **and** this setting must be set **prior** to + /// adding any child subcommands + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::GlobalVersion) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches(); + /// // running `$ myprog test --version` will display + /// // "myprog-test v1.1" + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + GlobalVersion, + + /// Specifies that this [`SubCommand`] should be hidden from help messages + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// App::new("myprog") + /// .subcommand(SubCommand::with_name("test") + /// .setting(AppSettings::Hidden)) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + Hidden, + + /// Tells `clap` *not* to print possible values when displaying help information. + /// This can be useful if there are many values, or they are explained elsewhere. + HidePossibleValuesInHelp, + + /// Tries to match unknown args to partial [`subcommands`] or their [aliases]. For example to + /// match a subcommand named `test`, one could use `t`, `te`, `tes`, and `test`. + /// + /// **NOTE:** The match *must not* be ambiguous at all in order to succeed. i.e. to match `te` + /// to `test` there could not also be a subcommand or alias `temp` because both start with `te` + /// + /// **CAUTION:** This setting can interfere with [positional/free arguments], take care when + /// designing CLIs which allow inferred subcommands and have potential positional/free + /// arguments whose values could start with the same characters as subcommands. If this is the + /// case, it's recommended to use settings such as [`AppSeettings::ArgsNegateSubcommands`] in + /// conjunction with this setting. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// let m = App::new("prog") + /// .setting(AppSettings::InferSubcommands) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from(vec![ + /// "prog", "te" + /// ]); + /// assert_eq!(m.subcommand_name(), Some("test")); + /// ``` + /// [`subcommands`]: ./struct.SubCommand.html + /// [positional/free arguments]: ./struct.Arg.html#method.index + /// [aliases]: ./struct.App.html#method.alias + /// [`AppSeettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands + InferSubcommands, + + /// Specifies that the parser should not assume the first argument passed is the binary name. + /// This is normally the case when using a "daemon" style mode, or an interactive CLI where one + /// one would not normally type the binary or program name for each command. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let m = App::new("myprog") + /// .setting(AppSettings::NoBinaryName) + /// .arg(Arg::from_usage("... 'commands to run'")) + /// .get_matches_from(vec!["command", "set"]); + /// + /// let cmds: Vec<&str> = m.values_of("cmd").unwrap().collect(); + /// assert_eq!(cmds, ["command", "set"]); + /// ``` + NoBinaryName, + + /// Places the help string for all arguments on the line after the argument. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::NextLineHelp) + /// .get_matches(); + /// ``` + NextLineHelp, + + /// **DEPRECATED**: This setting is no longer required in order to propagate values up or down + /// + /// Specifies that the parser should propagate global arg's values down or up through any *used* + /// child subcommands. Meaning, if a subcommand wasn't used, the values won't be propagated to + /// said subcommand. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// let m = App::new("myprog") + /// .arg(Arg::from_usage("[cmd] 'command to run'") + /// .global(true)) + /// .subcommand(SubCommand::with_name("foo")) + /// .get_matches_from(vec!["myprog", "set", "foo"]); + /// + /// assert_eq!(m.value_of("cmd"), Some("set")); + /// + /// let sub_m = m.subcommand_matches("foo").unwrap(); + /// assert_eq!(sub_m.value_of("cmd"), Some("set")); + /// ``` + /// Now doing the same thing, but *not* using any subcommands will result in the value not being + /// propagated down. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand}; + /// let m = App::new("myprog") + /// .arg(Arg::from_usage("[cmd] 'command to run'") + /// .global(true)) + /// .subcommand(SubCommand::with_name("foo")) + /// .get_matches_from(vec!["myprog", "set"]); + /// + /// assert_eq!(m.value_of("cmd"), Some("set")); + /// + /// assert!(m.subcommand_matches("foo").is_none()); + /// ``` + #[deprecated(since = "2.27.0", note = "No longer required to propagate values")] + PropagateGlobalValuesDown, + + /// Allows [`SubCommand`]s to override all requirements of the parent command. + /// For example if you had a subcommand or top level application with a required argument + /// that is only required as long as there is no subcommand present, + /// using this setting would allow you to set those arguments to [`Arg::required(true)`] + /// and yet receive no error so long as the user uses a valid subcommand instead. + /// + /// **NOTE:** This defaults to false (using subcommand does *not* negate requirements) + /// + /// # Examples + /// + /// This first example shows that it is an error to not use a required argument + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog" + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// # ; + /// ``` + /// + /// This next example shows that it is no longer error to not use a required argument if a + /// valid subcommand is used. + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, SubCommand, ErrorKind}; + /// let noerr = App::new("myprog") + /// .setting(AppSettings::SubcommandsNegateReqs) + /// .arg(Arg::with_name("opt").required(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test" + /// ]); + /// assert!(noerr.is_ok()); + /// # ; + /// ``` + /// [`Arg::required(true)`]: ./struct.Arg.html#method.required + /// [`SubCommand`]: ./struct.SubCommand.html + SubcommandsNegateReqs, + + /// Specifies that the help text should be displayed (before exiting gracefully) if no + /// [`SubCommand`]s are present at runtime (i.e. an empty run such as `$ myprog`). + /// + /// **NOTE:** This should *not* be used with [`AppSettings::SubcommandRequired`] as they do + /// nearly same thing; this prints the help text, and the other prints an error. + /// + /// **NOTE:** If the user specifies arguments at runtime, but no subcommand the help text will + /// still be displayed and exit. If this is *not* the desired result, consider using + /// [`AppSettings::ArgRequiredElseHelp`] instead. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::SubcommandRequiredElseHelp) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired + /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp + SubcommandRequiredElseHelp, + + /// Specifies that any invalid UTF-8 code points should be treated as an error and fail + /// with a [`ErrorKind::InvalidUtf8`] error. + /// + /// **NOTE:** This rule only applies to argument values; Things such as flags, options, and + /// [`SubCommand`]s themselves only allow valid UTF-8 code points. + /// + /// # Platform Specific + /// + /// Non Windows systems only + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, AppSettings, ErrorKind}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let m = App::new("myprog") + /// .setting(AppSettings::StrictUtf8) + /// .arg_from_usage(" 'some positional arg'") + /// .get_matches_from_safe( + /// vec![ + /// OsString::from("myprog"), + /// OsString::from_vec(vec![0xe9])]); + /// + /// assert!(m.is_err()); + /// assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidUtf8); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ErrorKind::InvalidUtf8`]: ./enum.ErrorKind.html#variant.InvalidUtf8 + StrictUtf8, + + /// Allows specifying that if no [`SubCommand`] is present at runtime, + /// error and exit gracefully. + /// + /// **NOTE:** This defaults to `false` (subcommands do *not* need to be present) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("myprog") + /// .setting(AppSettings::SubcommandRequired) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + SubcommandRequired, + + /// Specifies that the final positional argument is a "VarArg" and that `clap` should not + /// attempt to parse any further args. + /// + /// The values of the trailing positional argument will contain all args from itself on. + /// + /// **NOTE:** The final positional argument **must** have [`Arg::multiple(true)`] or the usage + /// string equivalent. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// let m = App::new("myprog") + /// .setting(AppSettings::TrailingVarArg) + /// .arg(Arg::from_usage("... 'commands to run'")) + /// .get_matches_from(vec!["myprog", "arg1", "-r", "val1"]); + /// + /// let trail: Vec<&str> = m.values_of("cmd").unwrap().collect(); + /// assert_eq!(trail, ["arg1", "-r", "val1"]); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + TrailingVarArg, + + /// Groups flags and options together, presenting a more unified help message + /// (a la `getopts` or `docopt` style). + /// + /// The default is that the auto-generated help message will group flags, and options + /// separately. + /// + /// **NOTE:** This setting is cosmetic only and does not affect any functionality. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::UnifiedHelpMessage) + /// .get_matches(); + /// // running `myprog --help` will display a unified "docopt" or "getopts" style help message + /// ``` + UnifiedHelpMessage, + + /// Disables `-V` and `--version` for all [`SubCommand`]s + /// (Defaults to `false`; subcommands *do* have version flags.) + /// + /// **NOTE:** This setting must be set **prior** to adding any subcommands. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, SubCommand, AppSettings, ErrorKind}; + /// let res = App::new("myprog") + /// .version("v1.1") + /// .setting(AppSettings::VersionlessSubcommands) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", "test", "-V" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + VersionlessSubcommands, + + /// Will display a message "Press \[ENTER\]/\[RETURN\] to continue..." and wait for user before + /// exiting + /// + /// This is most useful when writing an application which is run from a GUI shortcut, or on + /// Windows where a user tries to open the binary by double-clicking instead of using the + /// command line. + /// + /// **NOTE:** This setting is **not** recursive with [`SubCommand`]s, meaning if you wish this + /// behavior for all subcommands, you must set this on each command (needing this is extremely + /// rare) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings}; + /// App::new("myprog") + /// .setting(AppSettings::WaitOnError) + /// # ; + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + WaitOnError, + + #[doc(hidden)] NeedsLongVersion, + + #[doc(hidden)] NeedsLongHelp, + + #[doc(hidden)] NeedsSubcommandHelp, + + #[doc(hidden)] LowIndexMultiplePositional, + + #[doc(hidden)] TrailingValues, + + #[doc(hidden)] ValidNegNumFound, + + #[doc(hidden)] Propagated, + + #[doc(hidden)] ValidArgFound, + + #[doc(hidden)] ContainsLast, +} + +impl FromStr for AppSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + match &*s.to_ascii_lowercase() { + "disablehelpflags" => Ok(AppSettings::DisableHelpFlags), + "argrequiredelsehelp" => Ok(AppSettings::ArgRequiredElseHelp), + "argsnegatesubcommands" => Ok(AppSettings::ArgsNegateSubcommands), + "allowinvalidutf8" => Ok(AppSettings::AllowInvalidUtf8), + "allowleadinghyphen" => Ok(AppSettings::AllowLeadingHyphen), + "allowexternalsubcommands" => Ok(AppSettings::AllowExternalSubcommands), + "allownegativenumbers" => Ok(AppSettings::AllowNegativeNumbers), + "colorauto" => Ok(AppSettings::ColorAuto), + "coloralways" => Ok(AppSettings::ColorAlways), + "colornever" => Ok(AppSettings::ColorNever), + "coloredhelp" => Ok(AppSettings::ColoredHelp), + "derivedisplayorder" => Ok(AppSettings::DeriveDisplayOrder), + "dontcollapseargsinusage" => Ok(AppSettings::DontCollapseArgsInUsage), + "dontdelimittrailingvalues" => Ok(AppSettings::DontDelimitTrailingValues), + "disablehelpsubcommand" => Ok(AppSettings::DisableHelpSubcommand), + "disableversion" => Ok(AppSettings::DisableVersion), + "globalversion" => Ok(AppSettings::GlobalVersion), + "hidden" => Ok(AppSettings::Hidden), + "hidepossiblevaluesinhelp" => Ok(AppSettings::HidePossibleValuesInHelp), + "infersubcommands" => Ok(AppSettings::InferSubcommands), + "lowindexmultiplepositional" => Ok(AppSettings::LowIndexMultiplePositional), + "nobinaryname" => Ok(AppSettings::NoBinaryName), + "nextlinehelp" => Ok(AppSettings::NextLineHelp), + "strictutf8" => Ok(AppSettings::StrictUtf8), + "subcommandsnegatereqs" => Ok(AppSettings::SubcommandsNegateReqs), + "subcommandrequired" => Ok(AppSettings::SubcommandRequired), + "subcommandrequiredelsehelp" => Ok(AppSettings::SubcommandRequiredElseHelp), + "trailingvararg" => Ok(AppSettings::TrailingVarArg), + "unifiedhelpmessage" => Ok(AppSettings::UnifiedHelpMessage), + "versionlesssubcommands" => Ok(AppSettings::VersionlessSubcommands), + "waitonerror" => Ok(AppSettings::WaitOnError), + "validnegnumfound" => Ok(AppSettings::ValidNegNumFound), + "validargfound" => Ok(AppSettings::ValidArgFound), + "propagated" => Ok(AppSettings::Propagated), + "trailingvalues" => Ok(AppSettings::TrailingValues), + _ => Err("unknown AppSetting, cannot convert from str".to_owned()), + } + } +} + +#[cfg(test)] +mod test { + use super::AppSettings; + + #[test] + fn app_settings_fromstr() { + assert_eq!( + "disablehelpflags".parse::().unwrap(), + AppSettings::DisableHelpFlags + ); + assert_eq!( + "argsnegatesubcommands".parse::().unwrap(), + AppSettings::ArgsNegateSubcommands + ); + assert_eq!( + "argrequiredelsehelp".parse::().unwrap(), + AppSettings::ArgRequiredElseHelp + ); + assert_eq!( + "allowexternalsubcommands".parse::().unwrap(), + AppSettings::AllowExternalSubcommands + ); + assert_eq!( + "allowinvalidutf8".parse::().unwrap(), + AppSettings::AllowInvalidUtf8 + ); + assert_eq!( + "allowleadinghyphen".parse::().unwrap(), + AppSettings::AllowLeadingHyphen + ); + assert_eq!( + "allownegativenumbers".parse::().unwrap(), + AppSettings::AllowNegativeNumbers + ); + assert_eq!( + "coloredhelp".parse::().unwrap(), + AppSettings::ColoredHelp + ); + assert_eq!( + "colorauto".parse::().unwrap(), + AppSettings::ColorAuto + ); + assert_eq!( + "coloralways".parse::().unwrap(), + AppSettings::ColorAlways + ); + assert_eq!( + "colornever".parse::().unwrap(), + AppSettings::ColorNever + ); + assert_eq!( + "disablehelpsubcommand".parse::().unwrap(), + AppSettings::DisableHelpSubcommand + ); + assert_eq!( + "disableversion".parse::().unwrap(), + AppSettings::DisableVersion + ); + assert_eq!( + "dontcollapseargsinusage".parse::().unwrap(), + AppSettings::DontCollapseArgsInUsage + ); + assert_eq!( + "dontdelimittrailingvalues".parse::().unwrap(), + AppSettings::DontDelimitTrailingValues + ); + assert_eq!( + "derivedisplayorder".parse::().unwrap(), + AppSettings::DeriveDisplayOrder + ); + assert_eq!( + "globalversion".parse::().unwrap(), + AppSettings::GlobalVersion + ); + assert_eq!( + "hidden".parse::().unwrap(), + AppSettings::Hidden + ); + assert_eq!( + "hidepossiblevaluesinhelp".parse::().unwrap(), + AppSettings::HidePossibleValuesInHelp + ); + assert_eq!( + "lowindexmultiplePositional".parse::().unwrap(), + AppSettings::LowIndexMultiplePositional + ); + assert_eq!( + "nobinaryname".parse::().unwrap(), + AppSettings::NoBinaryName + ); + assert_eq!( + "nextlinehelp".parse::().unwrap(), + AppSettings::NextLineHelp + ); + assert_eq!( + "subcommandsnegatereqs".parse::().unwrap(), + AppSettings::SubcommandsNegateReqs + ); + assert_eq!( + "subcommandrequired".parse::().unwrap(), + AppSettings::SubcommandRequired + ); + assert_eq!( + "subcommandrequiredelsehelp".parse::().unwrap(), + AppSettings::SubcommandRequiredElseHelp + ); + assert_eq!( + "strictutf8".parse::().unwrap(), + AppSettings::StrictUtf8 + ); + assert_eq!( + "trailingvararg".parse::().unwrap(), + AppSettings::TrailingVarArg + ); + assert_eq!( + "unifiedhelpmessage".parse::().unwrap(), + AppSettings::UnifiedHelpMessage + ); + assert_eq!( + "versionlesssubcommands".parse::().unwrap(), + AppSettings::VersionlessSubcommands + ); + assert_eq!( + "waitonerror".parse::().unwrap(), + AppSettings::WaitOnError + ); + assert_eq!( + "validnegnumfound".parse::().unwrap(), + AppSettings::ValidNegNumFound + ); + assert_eq!( + "validargfound".parse::().unwrap(), + AppSettings::ValidArgFound + ); + assert_eq!( + "propagated".parse::().unwrap(), + AppSettings::Propagated + ); + assert_eq!( + "trailingvalues".parse::().unwrap(), + AppSettings::TrailingValues + ); + assert_eq!( + "infersubcommands".parse::().unwrap(), + AppSettings::InferSubcommands + ); + assert!("hahahaha".parse::().is_err()); + } +} diff --git a/clap/src/app/usage.rs b/clap/src/app/usage.rs new file mode 100644 index 000000000..609058843 --- /dev/null +++ b/clap/src/app/usage.rs @@ -0,0 +1,479 @@ +// std +use std::collections::{BTreeMap, VecDeque}; + +// Internal +use INTERNAL_ERROR_MSG; +use args::{AnyArg, ArgMatcher, PosBuilder}; +use args::settings::ArgSettings; +use app::settings::AppSettings as AS; +use app::parser::Parser; + +// Creates a usage string for display. This happens just after all arguments were parsed, but before +// any subcommands have been parsed (so as to give subcommands their own usage recursively) +pub fn create_usage_with_title(p: &Parser, used: &[&str]) -> String { + debugln!("usage::create_usage_with_title;"); + let mut usage = String::with_capacity(75); + usage.push_str("USAGE:\n "); + usage.push_str(&*create_usage_no_title(p, used)); + usage +} + +// Creates a usage string to be used in error message (i.e. one with currently used args) +pub fn create_error_usage<'a, 'b>( + p: &Parser<'a, 'b>, + matcher: &'b ArgMatcher<'a>, + extra: Option<&str>, +) -> String { + let mut args: Vec<_> = matcher + .arg_names() + .iter() + .filter(|n| { + if let Some(o) = find_by_name!(p, **n, opts, iter) { + !o.b.is_set(ArgSettings::Required) && !o.b.is_set(ArgSettings::Hidden) + } else if let Some(p) = find_by_name!(p, **n, positionals, values) { + !p.b.is_set(ArgSettings::Required) && p.b.is_set(ArgSettings::Hidden) + } else { + true // flags can't be required, so they're always true + } + }) + .map(|&n| n) + .collect(); + if let Some(r) = extra { + args.push(r); + } + create_usage_with_title(p, &*args) +} + +// Creates a usage string (*without title*) if one was not provided by the user manually. +pub fn create_usage_no_title(p: &Parser, used: &[&str]) -> String { + debugln!("usage::create_usage_no_title;"); + if let Some(u) = p.meta.usage_str { + String::from(&*u) + } else if used.is_empty() { + create_help_usage(p, true) + } else { + create_smart_usage(p, used) + } +} + +// Creates a usage string for display in help messages (i.e. not for errors) +pub fn create_help_usage(p: &Parser, incl_reqs: bool) -> String { + let mut usage = String::with_capacity(75); + let name = p.meta + .usage + .as_ref() + .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name)); + usage.push_str(&*name); + let req_string = if incl_reqs { + let mut reqs: Vec<&str> = p.required().map(|r| &**r).collect(); + reqs.sort(); + reqs.dedup(); + get_required_usage_from(p, &reqs, None, None, false) + .iter() + .fold(String::new(), |a, s| a + &format!(" {}", s)[..]) + } else { + String::new() + }; + + let flags = needs_flags_tag(p); + if flags && !p.is_set(AS::UnifiedHelpMessage) { + usage.push_str(" [FLAGS]"); + } else if flags { + usage.push_str(" [OPTIONS]"); + } + if !p.is_set(AS::UnifiedHelpMessage) && p.opts.iter().any(|o| { + !o.is_set(ArgSettings::Required) && !o.is_set(ArgSettings::Hidden) + }) { + usage.push_str(" [OPTIONS]"); + } + + usage.push_str(&req_string[..]); + + let has_last = p.positionals.values().any(|p| p.is_set(ArgSettings::Last)); + // places a '--' in the usage string if there are args and options + // supporting multiple values + if p.opts.iter().any(|o| o.is_set(ArgSettings::Multiple)) + && p.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Required)) + && !(p.has_visible_subcommands() || p.is_set(AS::AllowExternalSubcommands)) + && !has_last + { + usage.push_str(" [--]"); + } + let not_req_or_hidden = |p: &PosBuilder| { + (!p.is_set(ArgSettings::Required) || p.is_set(ArgSettings::Last)) + && !p.is_set(ArgSettings::Hidden) + }; + if p.has_positionals() && p.positionals.values().any(not_req_or_hidden) { + if let Some(args_tag) = get_args_tag(p, incl_reqs) { + usage.push_str(&*args_tag); + } else { + usage.push_str(" [ARGS]"); + } + if has_last && incl_reqs { + let pos = p.positionals + .values() + .find(|p| p.b.is_set(ArgSettings::Last)) + .expect(INTERNAL_ERROR_MSG); + debugln!("usage::create_help_usage: '{}' has .last(true)", pos.name()); + let req = pos.is_set(ArgSettings::Required); + if req + && p.positionals + .values() + .any(|p| !p.is_set(ArgSettings::Required)) + { + usage.push_str(" -- <"); + } else if req { + usage.push_str(" [--] <"); + } else { + usage.push_str(" [-- <"); + } + usage.push_str(&*pos.name_no_brackets()); + usage.push_str(">"); + usage.push_str(pos.multiple_str()); + if !req { + usage.push_str("]"); + } + } + } + + // incl_reqs is only false when this function is called recursively + if p.has_visible_subcommands() && incl_reqs || p.is_set(AS::AllowExternalSubcommands) { + if p.is_set(AS::SubcommandsNegateReqs) || p.is_set(AS::ArgsNegateSubcommands) { + if !p.is_set(AS::ArgsNegateSubcommands) { + usage.push_str("\n "); + usage.push_str(&*create_help_usage(p, false)); + usage.push_str(" "); + } else { + usage.push_str("\n "); + usage.push_str(&*name); + usage.push_str(" "); + } + } else if p.is_set(AS::SubcommandRequired) || p.is_set(AS::SubcommandRequiredElseHelp) { + usage.push_str(" "); + } else { + usage.push_str(" [SUBCOMMAND]"); + } + } + usage.shrink_to_fit(); + debugln!("usage::create_help_usage: usage={}", usage); + usage +} + +// Creates a context aware usage string, or "smart usage" from currently used +// args, and requirements +fn create_smart_usage(p: &Parser, used: &[&str]) -> String { + debugln!("usage::smart_usage;"); + let mut usage = String::with_capacity(75); + let mut hs: Vec<&str> = p.required().map(|s| &**s).collect(); + hs.extend_from_slice(used); + + let r_string = get_required_usage_from(p, &hs, None, None, false) + .iter() + .fold(String::new(), |acc, s| acc + &format!(" {}", s)[..]); + + usage.push_str( + &p.meta + .usage + .as_ref() + .unwrap_or_else(|| p.meta.bin_name.as_ref().unwrap_or(&p.meta.name))[..], + ); + usage.push_str(&*r_string); + if p.is_set(AS::SubcommandRequired) { + usage.push_str(" "); + } + usage.shrink_to_fit(); + usage +} + +// Gets the `[ARGS]` tag for the usage string +fn get_args_tag(p: &Parser, incl_reqs: bool) -> Option { + debugln!("usage::get_args_tag;"); + let mut count = 0; + 'outer: for pos in p.positionals + .values() + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + { + debugln!("usage::get_args_tag:iter:{}:", pos.b.name); + if let Some(g_vec) = p.groups_for_arg(pos.b.name) { + for grp_s in &g_vec { + debugln!("usage::get_args_tag:iter:{}:iter:{};", pos.b.name, grp_s); + // if it's part of a required group we don't want to count it + if p.groups.iter().any(|g| g.required && (&g.name == grp_s)) { + continue 'outer; + } + } + } + count += 1; + debugln!( + "usage::get_args_tag:iter: {} Args not required or hidden", + count + ); + } + if !p.is_set(AS::DontCollapseArgsInUsage) && count > 1 { + debugln!("usage::get_args_tag:iter: More than one, returning [ARGS]"); + return None; // [ARGS] + } else if count == 1 && incl_reqs { + let pos = p.positionals + .values() + .find(|pos| { + !pos.is_set(ArgSettings::Required) && !pos.is_set(ArgSettings::Hidden) + && !pos.is_set(ArgSettings::Last) + }) + .expect(INTERNAL_ERROR_MSG); + debugln!( + "usage::get_args_tag:iter: Exactly one, returning '{}'", + pos.name() + ); + return Some(format!( + " [{}]{}", + pos.name_no_brackets(), + pos.multiple_str() + )); + } else if p.is_set(AS::DontCollapseArgsInUsage) && !p.positionals.is_empty() && incl_reqs { + debugln!("usage::get_args_tag:iter: Don't collapse returning all"); + return Some( + p.positionals + .values() + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + .map(|pos| { + format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()) + }) + .collect::>() + .join(""), + ); + } else if !incl_reqs { + debugln!("usage::get_args_tag:iter: incl_reqs=false, building secondary usage string"); + let highest_req_pos = p.positionals + .iter() + .filter_map(|(idx, pos)| { + if pos.b.is_set(ArgSettings::Required) && !pos.b.is_set(ArgSettings::Last) { + Some(idx) + } else { + None + } + }) + .max() + .unwrap_or_else(|| p.positionals.len()); + return Some( + p.positionals + .iter() + .filter_map(|(idx, pos)| { + if idx <= highest_req_pos { + Some(pos) + } else { + None + } + }) + .filter(|pos| !pos.is_set(ArgSettings::Required)) + .filter(|pos| !pos.is_set(ArgSettings::Hidden)) + .filter(|pos| !pos.is_set(ArgSettings::Last)) + .map(|pos| { + format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str()) + }) + .collect::>() + .join(""), + ); + } + Some("".into()) +} + +// Determines if we need the `[FLAGS]` tag in the usage string +fn needs_flags_tag(p: &Parser) -> bool { + debugln!("usage::needs_flags_tag;"); + 'outer: for f in &p.flags { + debugln!("usage::needs_flags_tag:iter: f={};", f.b.name); + if let Some(l) = f.s.long { + if l == "help" || l == "version" { + // Don't print `[FLAGS]` just for help or version + continue; + } + } + if let Some(g_vec) = p.groups_for_arg(f.b.name) { + for grp_s in &g_vec { + debugln!("usage::needs_flags_tag:iter:iter: grp_s={};", grp_s); + if p.groups.iter().any(|g| &g.name == grp_s && g.required) { + debugln!("usage::needs_flags_tag:iter:iter: Group is required"); + continue 'outer; + } + } + } + if f.is_set(ArgSettings::Hidden) { + continue; + } + debugln!("usage::needs_flags_tag:iter: [FLAGS] required"); + return true; + } + + debugln!("usage::needs_flags_tag: [FLAGS] not required"); + false +} + +// Returns the required args in usage string form by fully unrolling all groups +pub fn get_required_usage_from<'a, 'b>( + p: &Parser<'a, 'b>, + reqs: &[&'a str], + matcher: Option<&ArgMatcher<'a>>, + extra: Option<&str>, + incl_last: bool, +) -> VecDeque { + debugln!( + "usage::get_required_usage_from: reqs={:?}, extra={:?}", + reqs, + extra + ); + let mut desc_reqs: Vec<&str> = vec![]; + desc_reqs.extend(extra); + let mut new_reqs: Vec<&str> = vec![]; + macro_rules! get_requires { + (@group $a: ident, $v:ident, $p:ident) => {{ + if let Some(rl) = p.groups.iter() + .filter(|g| g.requires.is_some()) + .find(|g| &g.name == $a) + .map(|g| g.requires.as_ref().unwrap()) { + for r in rl { + if !$p.contains(&r) { + debugln!("usage::get_required_usage_from:iter:{}: adding group req={:?}", + $a, r); + $v.push(r); + } + } + } + }}; + ($a:ident, $what:ident, $how:ident, $v:ident, $p:ident) => {{ + if let Some(rl) = p.$what.$how() + .filter(|a| a.b.requires.is_some()) + .find(|arg| &arg.b.name == $a) + .map(|a| a.b.requires.as_ref().unwrap()) { + for &(_, r) in rl.iter() { + if !$p.contains(&r) { + debugln!("usage::get_required_usage_from:iter:{}: adding arg req={:?}", + $a, r); + $v.push(r); + } + } + } + }}; + } + // initialize new_reqs + for a in reqs { + get_requires!(a, flags, iter, new_reqs, reqs); + get_requires!(a, opts, iter, new_reqs, reqs); + get_requires!(a, positionals, values, new_reqs, reqs); + get_requires!(@group a, new_reqs, reqs); + } + desc_reqs.extend_from_slice(&*new_reqs); + debugln!( + "usage::get_required_usage_from: after init desc_reqs={:?}", + desc_reqs + ); + loop { + let mut tmp = vec![]; + for a in &new_reqs { + get_requires!(a, flags, iter, tmp, desc_reqs); + get_requires!(a, opts, iter, tmp, desc_reqs); + get_requires!(a, positionals, values, tmp, desc_reqs); + get_requires!(@group a, tmp, desc_reqs); + } + if tmp.is_empty() { + debugln!("usage::get_required_usage_from: no more children"); + break; + } else { + debugln!("usage::get_required_usage_from: after iter tmp={:?}", tmp); + debugln!( + "usage::get_required_usage_from: after iter new_reqs={:?}", + new_reqs + ); + desc_reqs.extend_from_slice(&*new_reqs); + new_reqs.clear(); + new_reqs.extend_from_slice(&*tmp); + debugln!( + "usage::get_required_usage_from: after iter desc_reqs={:?}", + desc_reqs + ); + } + } + desc_reqs.extend_from_slice(reqs); + desc_reqs.sort(); + desc_reqs.dedup(); + debugln!( + "usage::get_required_usage_from: final desc_reqs={:?}", + desc_reqs + ); + let mut ret_val = VecDeque::new(); + let args_in_groups = p.groups + .iter() + .filter(|gn| desc_reqs.contains(&gn.name)) + .flat_map(|g| p.arg_names_in_group(g.name)) + .collect::>(); + + let pmap = if let Some(m) = matcher { + desc_reqs + .iter() + .filter(|a| p.positionals.values().any(|p| &&p.b.name == a)) + .filter(|&pos| !m.contains(pos)) + .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) + .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) + .filter(|pos| !args_in_groups.contains(&pos.b.name)) + .map(|pos| (pos.index, pos)) + .collect::>() // sort by index + } else { + desc_reqs + .iter() + .filter(|a| p.positionals.values().any(|pos| &&pos.b.name == a)) + .filter_map(|pos| p.positionals.values().find(|x| &x.b.name == pos)) + .filter(|&pos| incl_last || !pos.is_set(ArgSettings::Last)) + .filter(|pos| !args_in_groups.contains(&pos.b.name)) + .map(|pos| (pos.index, pos)) + .collect::>() // sort by index + }; + debugln!( + "usage::get_required_usage_from: args_in_groups={:?}", + args_in_groups + ); + for &p in pmap.values() { + let s = p.to_string(); + if args_in_groups.is_empty() || !args_in_groups.contains(&&*s) { + ret_val.push_back(s); + } + } + for a in desc_reqs + .iter() + .filter(|name| !p.positionals.values().any(|p| &&p.b.name == name)) + .filter(|name| !p.groups.iter().any(|g| &&g.name == name)) + .filter(|name| !args_in_groups.contains(name)) + .filter(|name| { + !(matcher.is_some() && matcher.as_ref().unwrap().contains(name)) + }) { + debugln!("usage::get_required_usage_from:iter:{}:", a); + let arg = find_by_name!(p, *a, flags, iter) + .map(|f| f.to_string()) + .unwrap_or_else(|| { + find_by_name!(p, *a, opts, iter) + .map(|o| o.to_string()) + .expect(INTERNAL_ERROR_MSG) + }); + ret_val.push_back(arg); + } + let mut g_vec: Vec = vec![]; + for g in desc_reqs + .iter() + .filter(|n| p.groups.iter().any(|g| &&g.name == n)) + { + let g_string = p.args_in_group(g).join("|"); + let elem = format!("<{}>", &g_string[..g_string.len()]); + if !g_vec.contains(&elem) { + g_vec.push(elem); + } + } + for g in g_vec { + ret_val.push_back(g); + } + + ret_val +} diff --git a/clap/src/app/validator.rs b/clap/src/app/validator.rs new file mode 100644 index 000000000..181b831d0 --- /dev/null +++ b/clap/src/app/validator.rs @@ -0,0 +1,573 @@ +// std +use std::fmt::Display; +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; + +// Internal +use INTERNAL_ERROR_MSG; +use INVALID_UTF8; +use args::{AnyArg, ArgMatcher, MatchedArg}; +use args::settings::ArgSettings; +use errors::{Error, ErrorKind}; +use errors::Result as ClapResult; +use app::settings::AppSettings as AS; +use app::parser::{ParseResult, Parser}; +use fmt::{Colorizer, ColorizerOption}; +use app::usage; + +pub struct Validator<'a, 'b, 'z>(&'z mut Parser<'a, 'b>) +where + 'a: 'b, + 'b: 'z; + +impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { + pub fn new(p: &'z mut Parser<'a, 'b>) -> Self { Validator(p) } + + pub fn validate( + &mut self, + needs_val_of: ParseResult<'a>, + subcmd_name: Option, + matcher: &mut ArgMatcher<'a>, + ) -> ClapResult<()> { + debugln!("Validator::validate;"); + let mut reqs_validated = false; + self.0.add_env(matcher)?; + self.0.add_defaults(matcher)?; + if let ParseResult::Opt(a) = needs_val_of { + debugln!("Validator::validate: needs_val_of={:?}", a); + let o = { + self.0 + .opts + .iter() + .find(|o| o.b.name == a) + .expect(INTERNAL_ERROR_MSG) + .clone() + }; + self.validate_required(matcher)?; + reqs_validated = true; + let should_err = if let Some(v) = matcher.0.args.get(&*o.b.name) { + v.vals.is_empty() && !(o.v.min_vals.is_some() && o.v.min_vals.unwrap() == 0) + } else { + true + }; + if should_err { + return Err(Error::empty_value( + &o, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + + if matcher.is_empty() && matcher.subcommand_name().is_none() + && self.0.is_set(AS::ArgRequiredElseHelp) + { + let mut out = vec![]; + self.0.write_help_err(&mut out)?; + return Err(Error { + message: String::from_utf8_lossy(&*out).into_owned(), + kind: ErrorKind::MissingArgumentOrSubcommand, + info: None, + }); + } + self.validate_blacklist(matcher)?; + if !(self.0.is_set(AS::SubcommandsNegateReqs) && subcmd_name.is_some()) && !reqs_validated { + self.validate_required(matcher)?; + } + self.validate_matched_args(matcher)?; + matcher.usage(usage::create_usage_with_title(self.0, &[])); + + Ok(()) + } + + fn validate_arg_values( + &self, + arg: &A, + ma: &MatchedArg, + matcher: &ArgMatcher<'a>, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_values: arg={:?}", arg.name()); + for val in &ma.vals { + if self.0.is_set(AS::StrictUtf8) && val.to_str().is_none() { + debugln!( + "Validator::validate_arg_values: invalid UTF-8 found in val {:?}", + val + ); + return Err(Error::invalid_utf8( + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + if let Some(p_vals) = arg.possible_vals() { + debugln!("Validator::validate_arg_values: possible_vals={:?}", p_vals); + let val_str = val.to_string_lossy(); + let ok = if arg.is_set(ArgSettings::CaseInsensitive) { + p_vals.iter().any(|pv| pv.eq_ignore_ascii_case(&*val_str)) + } else { + p_vals.contains(&&*val_str) + }; + if !ok { + return Err(Error::invalid_value( + val_str, + p_vals, + arg, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + if !arg.is_set(ArgSettings::EmptyValues) && val.is_empty() + && matcher.contains(&*arg.name()) + { + debugln!("Validator::validate_arg_values: illegal empty val found"); + return Err(Error::empty_value( + arg, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + if let Some(vtor) = arg.validator() { + debug!("Validator::validate_arg_values: checking validator..."); + if let Err(e) = vtor(val.to_string_lossy().into_owned()) { + sdebugln!("error"); + return Err(Error::value_validation(Some(arg), e, self.0.color())); + } else { + sdebugln!("good"); + } + } + if let Some(vtor) = arg.validator_os() { + debug!("Validator::validate_arg_values: checking validator_os..."); + if let Err(e) = vtor(val) { + sdebugln!("error"); + return Err(Error::value_validation( + Some(arg), + (*e).to_string_lossy().to_string(), + self.0.color(), + )); + } else { + sdebugln!("good"); + } + } + } + Ok(()) + } + + fn build_err(&self, name: &str, matcher: &ArgMatcher) -> ClapResult<()> { + debugln!("build_err!: name={}", name); + let mut c_with = find_from!(self.0, &name, blacklist, matcher); + c_with = c_with.or( + self.0.find_any_arg(name).map_or(None, |aa| aa.blacklist()) + .map_or(None, + |bl| bl.iter().find(|arg| matcher.contains(arg))) + .map_or(None, |an| self.0.find_any_arg(an)) + .map_or(None, |aa| Some(format!("{}", aa))) + ); + debugln!("build_err!: '{:?}' conflicts with '{}'", c_with, &name); +// matcher.remove(&name); + let usg = usage::create_error_usage(self.0, matcher, None); + if let Some(f) = find_by_name!(self.0, name, flags, iter) { + debugln!("build_err!: It was a flag..."); + Err(Error::argument_conflict(f, c_with, &*usg, self.0.color())) + } else if let Some(o) = find_by_name!(self.0, name, opts, iter) { + debugln!("build_err!: It was an option..."); + Err(Error::argument_conflict(o, c_with, &*usg, self.0.color())) + } else { + match find_by_name!(self.0, name, positionals, values) { + Some(p) => { + debugln!("build_err!: It was a positional..."); + Err(Error::argument_conflict(p, c_with, &*usg, self.0.color())) + }, + None => panic!(INTERNAL_ERROR_MSG) + } + } + } + + fn validate_blacklist(&self, matcher: &mut ArgMatcher) -> ClapResult<()> { + debugln!("Validator::validate_blacklist;"); + let mut conflicts: Vec<&str> = vec![]; + for (&name, _) in matcher.iter() { + debugln!("Validator::validate_blacklist:iter:{};", name); + if let Some(grps) = self.0.groups_for_arg(name) { + for grp in &grps { + if let Some(g) = self.0.groups.iter().find(|g| &g.name == grp) { + if !g.multiple { + for arg in &g.args { + if arg == &name { + continue; + } + conflicts.push(arg); + } + } + if let Some(ref gc) = g.conflicts { + conflicts.extend(&*gc); + } + } + } + } + if let Some(arg) = find_any_by_name!(self.0, name) { + if let Some(bl) = arg.blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } else { + debugln!("Validator::validate_blacklist:iter:{}:group;", name); + let args = self.0.arg_names_in_group(name); + for arg in &args { + debugln!("Validator::validate_blacklist:iter:{}:group:iter:{};", name, arg); + if let Some(bl) = find_any_by_name!(self.0, *arg).unwrap().blacklist() { + for conf in bl { + if matcher.get(conf).is_some() { + conflicts.push(conf); + } + } + } + } + } + } + + for name in &conflicts { + debugln!( + "Validator::validate_blacklist:iter:{}: Checking blacklisted arg", + name + ); + let mut should_err = false; + if self.0.groups.iter().any(|g| &g.name == name) { + debugln!( + "Validator::validate_blacklist:iter:{}: groups contains it...", + name + ); + for n in self.0.arg_names_in_group(name) { + debugln!( + "Validator::validate_blacklist:iter:{}:iter:{}: looking in group...", + name, + n + ); + if matcher.contains(n) { + debugln!( + "Validator::validate_blacklist:iter:{}:iter:{}: matcher contains it...", + name, + n + ); + return self.build_err(n, matcher); + } + } + } else if let Some(ma) = matcher.get(name) { + debugln!( + "Validator::validate_blacklist:iter:{}: matcher contains it...", + name + ); + should_err = ma.occurs > 0; + } + if should_err { + return self.build_err(*name, matcher); + } + } + Ok(()) + } + + fn validate_matched_args(&self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + debugln!("Validator::validate_matched_args;"); + for (name, ma) in matcher.iter() { + debugln!( + "Validator::validate_matched_args:iter:{}: vals={:#?}", + name, + ma.vals + ); + if let Some(opt) = find_by_name!(self.0, *name, opts, iter) { + self.validate_arg_num_vals(opt, ma, matcher)?; + self.validate_arg_values(opt, ma, matcher)?; + self.validate_arg_requires(opt, ma, matcher)?; + self.validate_arg_num_occurs(opt, ma, matcher)?; + } else if let Some(flag) = find_by_name!(self.0, *name, flags, iter) { + self.validate_arg_requires(flag, ma, matcher)?; + self.validate_arg_num_occurs(flag, ma, matcher)?; + } else if let Some(pos) = find_by_name!(self.0, *name, positionals, values) { + self.validate_arg_num_vals(pos, ma, matcher)?; + self.validate_arg_num_occurs(pos, ma, matcher)?; + self.validate_arg_values(pos, ma, matcher)?; + self.validate_arg_requires(pos, ma, matcher)?; + } else { + let grp = self.0 + .groups + .iter() + .find(|g| &g.name == name) + .expect(INTERNAL_ERROR_MSG); + if let Some(ref g_reqs) = grp.requires { + if g_reqs.iter().any(|&n| !matcher.contains(n)) { + return self.missing_required_error(matcher, None); + } + } + } + } + Ok(()) + } + + fn validate_arg_num_occurs( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_num_occurs: a={};", a.name()); + if ma.occurs > 1 && !a.is_set(ArgSettings::Multiple) { + // Not the first time, and we don't allow multiples + return Err(Error::unexpected_multiple_usage( + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + Ok(()) + } + + fn validate_arg_num_vals( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_num_vals:{}", a.name()); + if let Some(num) = a.num_vals() { + debugln!("Validator::validate_arg_num_vals: num_vals set...{}", num); + let should_err = if a.is_set(ArgSettings::Multiple) { + ((ma.vals.len() as u64) % num) != 0 + } else { + num != (ma.vals.len() as u64) + }; + if should_err { + debugln!("Validator::validate_arg_num_vals: Sending error WrongNumberOfValues"); + return Err(Error::wrong_number_of_values( + a, + num, + if a.is_set(ArgSettings::Multiple) { + (ma.vals.len() % num as usize) + } else { + ma.vals.len() + }, + if ma.vals.len() == 1 + || (a.is_set(ArgSettings::Multiple) && (ma.vals.len() % num as usize) == 1) + { + "as" + } else { + "ere" + }, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + if let Some(num) = a.max_vals() { + debugln!("Validator::validate_arg_num_vals: max_vals set...{}", num); + if (ma.vals.len() as u64) > num { + debugln!("Validator::validate_arg_num_vals: Sending error TooManyValues"); + return Err(Error::too_many_values( + ma.vals + .iter() + .last() + .expect(INTERNAL_ERROR_MSG) + .to_str() + .expect(INVALID_UTF8), + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + } + let min_vals_zero = if let Some(num) = a.min_vals() { + debugln!("Validator::validate_arg_num_vals: min_vals set: {}", num); + if (ma.vals.len() as u64) < num && num != 0 { + debugln!("Validator::validate_arg_num_vals: Sending error TooFewValues"); + return Err(Error::too_few_values( + a, + num, + ma.vals.len(), + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + num == 0 + } else { + false + }; + // Issue 665 (https://github.com/clap-rs/clap/issues/665) + // Issue 1105 (https://github.com/clap-rs/clap/issues/1105) + if a.takes_value() && !min_vals_zero && ma.vals.is_empty() { + return Err(Error::empty_value( + a, + &*usage::create_error_usage(self.0, matcher, None), + self.0.color(), + )); + } + Ok(()) + } + + fn validate_arg_requires( + &self, + a: &A, + ma: &MatchedArg, + matcher: &ArgMatcher, + ) -> ClapResult<()> + where + A: AnyArg<'a, 'b> + Display, + { + debugln!("Validator::validate_arg_requires:{};", a.name()); + if let Some(a_reqs) = a.requires() { + for &(val, name) in a_reqs.iter().filter(|&&(val, _)| val.is_some()) { + let missing_req = + |v| v == val.expect(INTERNAL_ERROR_MSG) && !matcher.contains(name); + if ma.vals.iter().any(missing_req) { + return self.missing_required_error(matcher, None); + } + } + for &(_, name) in a_reqs.iter().filter(|&&(val, _)| val.is_none()) { + if !matcher.contains(name) { + return self.missing_required_error(matcher, Some(name)); + } + } + } + Ok(()) + } + + fn validate_required(&mut self, matcher: &ArgMatcher) -> ClapResult<()> { + debugln!( + "Validator::validate_required: required={:?};", + self.0.required + ); + + let mut should_err = false; + let mut to_rem = Vec::new(); + for name in &self.0.required { + debugln!("Validator::validate_required:iter:{}:", name); + if matcher.contains(name) { + continue; + } + if to_rem.contains(name) { + continue; + } else if let Some(a) = find_any_by_name!(self.0, *name) { + if self.is_missing_required_ok(a, matcher) { + to_rem.push(a.name()); + if let Some(reqs) = a.requires() { + for r in reqs + .iter() + .filter(|&&(val, _)| val.is_none()) + .map(|&(_, name)| name) + { + to_rem.push(r); + } + } + continue; + } + } + should_err = true; + break; + } + if should_err { + for r in &to_rem { + 'inner: for i in (0 .. self.0.required.len()).rev() { + if &self.0.required[i] == r { + self.0.required.swap_remove(i); + break 'inner; + } + } + } + return self.missing_required_error(matcher, None); + } + + // Validate the conditionally required args + for &(a, v, r) in &self.0.r_ifs { + if let Some(ma) = matcher.get(a) { + if matcher.get(r).is_none() && ma.vals.iter().any(|val| val == v) { + return self.missing_required_error(matcher, Some(r)); + } + } + } + Ok(()) + } + + fn validate_arg_conflicts(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { + debugln!("Validator::validate_arg_conflicts: a={:?};", a.name()); + a.blacklist().map(|bl| { + bl.iter().any(|conf| { + matcher.contains(conf) + || self.0 + .groups + .iter() + .find(|g| &g.name == conf) + .map_or(false, |g| g.args.iter().any(|arg| matcher.contains(arg))) + }) + }) + } + + fn validate_required_unless(&self, a: &AnyArg, matcher: &ArgMatcher) -> Option { + debugln!("Validator::validate_required_unless: a={:?};", a.name()); + macro_rules! check { + ($how:ident, $_self:expr, $a:ident, $m:ident) => {{ + $a.required_unless().map(|ru| { + ru.iter().$how(|n| { + $m.contains(n) || { + if let Some(grp) = $_self.groups.iter().find(|g| &g.name == n) { + grp.args.iter().any(|arg| $m.contains(arg)) + } else { + false + } + } + }) + }) + }}; + } + if a.is_set(ArgSettings::RequiredUnlessAll) { + check!(all, self.0, a, matcher) + } else { + check!(any, self.0, a, matcher) + } + } + + fn missing_required_error(&self, matcher: &ArgMatcher, extra: Option<&str>) -> ClapResult<()> { + debugln!("Validator::missing_required_error: extra={:?}", extra); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: self.0.color(), + }); + let mut reqs = self.0.required.iter().map(|&r| &*r).collect::>(); + if let Some(r) = extra { + reqs.push(r); + } + reqs.retain(|n| !matcher.contains(n)); + reqs.dedup(); + debugln!("Validator::missing_required_error: reqs={:#?}", reqs); + let req_args = + usage::get_required_usage_from(self.0, &reqs[..], Some(matcher), extra, true) + .iter() + .fold(String::new(), |acc, s| { + acc + &format!("\n {}", c.error(s))[..] + }); + debugln!( + "Validator::missing_required_error: req_args={:#?}", + req_args + ); + Err(Error::missing_required_argument( + &*req_args, + &*usage::create_error_usage(self.0, matcher, extra), + self.0.color(), + )) + } + + #[inline] + fn is_missing_required_ok(&self, a: &AnyArg, matcher: &ArgMatcher) -> bool { + debugln!("Validator::is_missing_required_ok: a={}", a.name()); + self.validate_arg_conflicts(a, matcher).unwrap_or(false) + || self.validate_required_unless(a, matcher).unwrap_or(false) + } +} diff --git a/clap/src/args/any_arg.rs b/clap/src/args/any_arg.rs new file mode 100644 index 000000000..eee522833 --- /dev/null +++ b/clap/src/args/any_arg.rs @@ -0,0 +1,74 @@ +// Std +use std::rc::Rc; +use std::fmt as std_fmt; +use std::ffi::{OsStr, OsString}; + +// Internal +use args::settings::ArgSettings; +use map::{self, VecMap}; +use INTERNAL_ERROR_MSG; + +#[doc(hidden)] +pub trait AnyArg<'n, 'e>: std_fmt::Display { + fn name(&self) -> &'n str; + fn overrides(&self) -> Option<&[&'e str]>; + fn aliases(&self) -> Option>; + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]>; + fn blacklist(&self) -> Option<&[&'e str]>; + fn required_unless(&self) -> Option<&[&'e str]>; + fn is_set(&self, ArgSettings) -> bool; + fn set(&mut self, ArgSettings); + fn has_switch(&self) -> bool; + fn max_vals(&self) -> Option; + fn min_vals(&self) -> Option; + fn num_vals(&self) -> Option; + fn possible_vals(&self) -> Option<&[&'e str]>; + fn validator(&self) -> Option<&Rc Result<(), String>>>; + fn validator_os(&self) -> Option<&Rc Result<(), OsString>>>; + fn short(&self) -> Option; + fn long(&self) -> Option<&'e str>; + fn val_delim(&self) -> Option; + fn takes_value(&self) -> bool; + fn val_names(&self) -> Option<&VecMap<&'e str>>; + fn help(&self) -> Option<&'e str>; + fn long_help(&self) -> Option<&'e str>; + fn default_val(&self) -> Option<&'e OsStr>; + fn default_vals_ifs(&self) -> Option, &'e OsStr)>>; + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)>; + fn longest_filter(&self) -> bool; + fn val_terminator(&self) -> Option<&'e str>; +} + +pub trait DispOrder { + fn disp_ord(&self) -> usize; +} + +impl<'n, 'e, 'z, T: ?Sized> AnyArg<'n, 'e> for &'z T where T: AnyArg<'n, 'e> + 'z { + fn name(&self) -> &'n str { (*self).name() } + fn overrides(&self) -> Option<&[&'e str]> { (*self).overrides() } + fn aliases(&self) -> Option> { (*self).aliases() } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { (*self).requires() } + fn blacklist(&self) -> Option<&[&'e str]> { (*self).blacklist() } + fn required_unless(&self) -> Option<&[&'e str]> { (*self).required_unless() } + fn is_set(&self, a: ArgSettings) -> bool { (*self).is_set(a) } + fn set(&mut self, _: ArgSettings) { panic!(INTERNAL_ERROR_MSG) } + fn has_switch(&self) -> bool { (*self).has_switch() } + fn max_vals(&self) -> Option { (*self).max_vals() } + fn min_vals(&self) -> Option { (*self).min_vals() } + fn num_vals(&self) -> Option { (*self).num_vals() } + fn possible_vals(&self) -> Option<&[&'e str]> { (*self).possible_vals() } + fn validator(&self) -> Option<&Rc Result<(), String>>> { (*self).validator() } + fn validator_os(&self) -> Option<&Rc Result<(), OsString>>> { (*self).validator_os() } + fn short(&self) -> Option { (*self).short() } + fn long(&self) -> Option<&'e str> { (*self).long() } + fn val_delim(&self) -> Option { (*self).val_delim() } + fn takes_value(&self) -> bool { (*self).takes_value() } + fn val_names(&self) -> Option<&VecMap<&'e str>> { (*self).val_names() } + fn help(&self) -> Option<&'e str> { (*self).help() } + fn long_help(&self) -> Option<&'e str> { (*self).long_help() } + fn default_val(&self) -> Option<&'e OsStr> { (*self).default_val() } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { (*self).default_vals_ifs() } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { (*self).env() } + fn longest_filter(&self) -> bool { (*self).longest_filter() } + fn val_terminator(&self) -> Option<&'e str> { (*self).val_terminator() } +} diff --git a/clap/src/args/arg.rs b/clap/src/args/arg.rs new file mode 100644 index 000000000..50a30abb7 --- /dev/null +++ b/clap/src/args/arg.rs @@ -0,0 +1,3954 @@ +#[cfg(feature = "yaml")] +use std::collections::BTreeMap; +use std::rc::Rc; +use std::ffi::{OsStr, OsString}; +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +use osstringext::OsStrExt3; +#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] +use std::os::unix::ffi::OsStrExt; +use std::env; + +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; +use map::VecMap; + +use usage_parser::UsageParser; +use args::settings::ArgSettings; +use args::arg_builder::{Base, Switched, Valued}; + +/// The abstract representation of a command line argument. Used to set all the options and +/// relationships that define a valid argument for the program. +/// +/// There are two methods for constructing [`Arg`]s, using the builder pattern and setting options +/// manually, or using a usage string which is far less verbose but has fewer options. You can also +/// use a combination of the two methods to achieve the best of both worlds. +/// +/// # Examples +/// +/// ```rust +/// # use clap::Arg; +/// // Using the traditional builder pattern and setting each option manually +/// let cfg = Arg::with_name("config") +/// .short("c") +/// .long("config") +/// .takes_value(true) +/// .value_name("FILE") +/// .help("Provides a config file to myprog"); +/// // Using a usage string (setting a similar argument to the one above) +/// let input = Arg::from_usage("-i, --input=[FILE] 'Provides an input file to the program'"); +/// ``` +/// [`Arg`]: ./struct.Arg.html +#[allow(missing_debug_implementations)] +#[derive(Default, Clone)] +pub struct Arg<'a, 'b> +where + 'a: 'b, +{ + #[doc(hidden)] pub b: Base<'a, 'b>, + #[doc(hidden)] pub s: Switched<'b>, + #[doc(hidden)] pub v: Valued<'a, 'b>, + #[doc(hidden)] pub index: Option, + #[doc(hidden)] pub r_ifs: Option>, +} + +impl<'a, 'b> Arg<'a, 'b> { + /// Creates a new instance of [`Arg`] using a unique string name. The name will be used to get + /// information about whether or not the argument was used at runtime, get values, set + /// relationships with other args, etc.. + /// + /// **NOTE:** In the case of arguments that take values (i.e. [`Arg::takes_value(true)`]) + /// and positional arguments (i.e. those without a preceding `-` or `--`) the name will also + /// be displayed when the user prints the usage/help information of the program. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// # ; + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg`]: ./struct.Arg.html + pub fn with_name(n: &'a str) -> Self { + Arg { + b: Base::new(n), + ..Default::default() + } + } + + /// Creates a new instance of [`Arg`] from a .yml (YAML) file. + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::Arg; + /// # fn main() { + /// let yml = load_yaml!("arg.yml"); + /// let arg = Arg::from_yaml(yml); + /// # } + /// ``` + /// [`Arg`]: ./struct.Arg.html + #[cfg(feature = "yaml")] + pub fn from_yaml(y: &BTreeMap) -> Arg { + // We WANT this to panic on error...so expect() is good. + let name_yml = y.keys().nth(0).unwrap(); + let name_str = name_yml.as_str().unwrap(); + let mut a = Arg::with_name(name_str); + let arg_settings = y.get(name_yml).unwrap().as_hash().unwrap(); + + for (k, v) in arg_settings.iter() { + a = match k.as_str().unwrap() { + "short" => yaml_to_str!(a, v, short), + "long" => yaml_to_str!(a, v, long), + "aliases" => yaml_vec_or_str!(v, a, alias), + "help" => yaml_to_str!(a, v, help), + "long_help" => yaml_to_str!(a, v, long_help), + "required" => yaml_to_bool!(a, v, required), + "required_if" => yaml_tuple2!(a, v, required_if), + "required_ifs" => yaml_tuple2!(a, v, required_if), + "takes_value" => yaml_to_bool!(a, v, takes_value), + "index" => yaml_to_u64!(a, v, index), + "global" => yaml_to_bool!(a, v, global), + "multiple" => yaml_to_bool!(a, v, multiple), + "hidden" => yaml_to_bool!(a, v, hidden), + "next_line_help" => yaml_to_bool!(a, v, next_line_help), + "empty_values" => yaml_to_bool!(a, v, empty_values), + "group" => yaml_to_str!(a, v, group), + "number_of_values" => yaml_to_u64!(a, v, number_of_values), + "max_values" => yaml_to_u64!(a, v, max_values), + "min_values" => yaml_to_u64!(a, v, min_values), + "value_name" => yaml_to_str!(a, v, value_name), + "use_delimiter" => yaml_to_bool!(a, v, use_delimiter), + "allow_hyphen_values" => yaml_to_bool!(a, v, allow_hyphen_values), + "last" => yaml_to_bool!(a, v, last), + "require_delimiter" => yaml_to_bool!(a, v, require_delimiter), + "value_delimiter" => yaml_to_str!(a, v, value_delimiter), + "required_unless" => yaml_to_str!(a, v, required_unless), + "display_order" => yaml_to_usize!(a, v, display_order), + "default_value" => yaml_to_str!(a, v, default_value), + "default_value_if" => yaml_tuple3!(a, v, default_value_if), + "default_value_ifs" => yaml_tuple3!(a, v, default_value_if), + "env" => yaml_to_str!(a, v, env), + "value_names" => yaml_vec_or_str!(v, a, value_name), + "groups" => yaml_vec_or_str!(v, a, group), + "requires" => yaml_vec_or_str!(v, a, requires), + "requires_if" => yaml_tuple2!(a, v, requires_if), + "requires_ifs" => yaml_tuple2!(a, v, requires_if), + "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "overrides_with" => yaml_vec_or_str!(v, a, overrides_with), + "possible_values" => yaml_vec_or_str!(v, a, possible_value), + "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), + "required_unless_one" => yaml_vec_or_str!(v, a, required_unless), + "required_unless_all" => { + a = yaml_vec_or_str!(v, a, required_unless); + a.setb(ArgSettings::RequiredUnlessAll); + a + } + s => panic!( + "Unknown Arg setting '{}' in YAML file for arg '{}'", + s, name_str + ), + } + } + + a + } + + /// Creates a new instance of [`Arg`] from a usage string. Allows creation of basic settings + /// for the [`Arg`]. The syntax is flexible, but there are some rules to follow. + /// + /// **NOTE**: Not all settings may be set using the usage string method. Some properties are + /// only available via the builder pattern. + /// + /// **NOTE**: Only ASCII values are officially supported in [`Arg::from_usage`] strings. Some + /// UTF-8 codepoints may work just fine, but this is not guaranteed. + /// + /// # Syntax + /// + /// Usage strings typically following the form: + /// + /// ```notrust + /// [explicit name] [short] [long] [value names] [help string] + /// ``` + /// + /// This is not a hard rule as the attributes can appear in other orders. There are also + /// several additional sigils which denote additional settings. Below are the details of each + /// portion of the string. + /// + /// ### Explicit Name + /// + /// This is an optional field, if it's omitted the argument will use one of the additional + /// fields as the name using the following priority order: + /// + /// * Explicit Name (This always takes precedence when present) + /// * Long + /// * Short + /// * Value Name + /// + /// `clap` determines explicit names as the first string of characters between either `[]` or + /// `<>` where `[]` has the dual notation of meaning the argument is optional, and `<>` meaning + /// the argument is required. + /// + /// Explicit names may be followed by: + /// * The multiple denotation `...` + /// + /// Example explicit names as follows (`ename` for an optional argument, and `rname` for a + /// required argument): + /// + /// ```notrust + /// [ename] -s, --long 'some flag' + /// -r, --longer 'some other flag' + /// ``` + /// + /// ### Short + /// + /// This is set by placing a single character after a leading `-`. + /// + /// Shorts may be followed by + /// * The multiple denotation `...` + /// * An optional comma `,` which is cosmetic only + /// * Value notation + /// + /// Example shorts are as follows (`-s`, and `-r`): + /// + /// ```notrust + /// -s, --long 'some flag' + /// -r [val], --longer 'some option' + /// ``` + /// + /// ### Long + /// + /// This is set by placing a word (no spaces) after a leading `--`. + /// + /// Shorts may be followed by + /// * The multiple denotation `...` + /// * Value notation + /// + /// Example longs are as follows (`--some`, and `--rapid`): + /// + /// ```notrust + /// -s, --some 'some flag' + /// --rapid=[FILE] 'some option' + /// ``` + /// + /// ### Values (Value Notation) + /// + /// This is set by placing a word(s) between `[]` or `<>` optionally after `=` (although this + /// is cosmetic only and does not affect functionality). If an explicit name has **not** been + /// set, using `<>` will denote a required argument, and `[]` will denote an optional argument + /// + /// Values may be followed by + /// * The multiple denotation `...` + /// * More Value notation + /// + /// More than one value will also implicitly set the arguments number of values, i.e. having + /// two values, `--option [val1] [val2]` specifies that in order for option to be satisified it + /// must receive exactly two values + /// + /// Example values are as follows (`FILE`, and `SPEED`): + /// + /// ```notrust + /// -s, --some [FILE] 'some option' + /// --rapid=... 'some required multiple option' + /// ``` + /// + /// ### Help String + /// + /// The help string is denoted between a pair of single quotes `''` and may contain any + /// characters. + /// + /// Example help strings are as follows: + /// + /// ```notrust + /// -s, --some [FILE] 'some option' + /// --rapid=... 'some required multiple option' + /// ``` + /// + /// ### Additional Sigils + /// + /// Multiple notation `...` (three consecutive dots/periods) specifies that this argument may + /// be used multiple times. Do not confuse multiple occurrences (`...`) with multiple values. + /// `--option val1 val2` is a single occurrence with multiple values. `--flag --flag` is + /// multiple occurrences (and then you can obviously have instances of both as well) + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// App::new("prog") + /// .args(&[ + /// Arg::from_usage("--config 'a required file for the configuration and no short'"), + /// Arg::from_usage("-d, --debug... 'turns on debugging information and allows multiples'"), + /// Arg::from_usage("[input] 'an optional input file to use'") + /// ]) + /// # ; + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`Arg::from_usage`]: ./struct.Arg.html#method.from_usage + pub fn from_usage(u: &'a str) -> Self { + let parser = UsageParser::from_usage(u); + parser.parse() + } + + /// Sets the short version of the argument without the preceding `-`. + /// + /// By default `clap` automatically assigns `V` and `h` to the auto-generated `version` and + /// `help` arguments respectively. You may use the uppercase `V` or lowercase `h` for your own + /// arguments, in which case `clap` simply will not assign those to the auto-generated + /// `version` or `help` arguments. + /// + /// **NOTE:** Any leading `-` characters will be stripped, and only the first + /// non `-` character will be used as the [`short`] version + /// + /// # Examples + /// + /// To set [`short`] use a single valid UTF-8 code point. If you supply a leading `-` such as + /// `-c`, the `-` will be stripped. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .short("c") + /// # ; + /// ``` + /// + /// Setting [`short`] allows using the argument via a single hyphen (`-`) such as `-c` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .short("c")) + /// .get_matches_from(vec![ + /// "prog", "-c" + /// ]); + /// + /// assert!(m.is_present("config")); + /// ``` + /// [`short`]: ./struct.Arg.html#method.short + pub fn short>(mut self, s: S) -> Self { + self.s.short = s.as_ref().trim_left_matches(|c| c == '-').chars().nth(0); + self + } + + /// Sets the long version of the argument without the preceding `--`. + /// + /// By default `clap` automatically assigns `version` and `help` to the auto-generated + /// `version` and `help` arguments respectively. You may use the word `version` or `help` for + /// the long form of your own arguments, in which case `clap` simply will not assign those to + /// the auto-generated `version` or `help` arguments. + /// + /// **NOTE:** Any leading `-` characters will be stripped + /// + /// # Examples + /// + /// To set `long` use a word containing valid UTF-8 codepoints. If you supply a double leading + /// `--` such as `--config` they will be stripped. Hyphens in the middle of the word, however, + /// will *not* be stripped (i.e. `config-file` is allowed) + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("cfg") + /// .long("config") + /// # ; + /// ``` + /// + /// Setting `long` allows using the argument via a double hyphen (`--`) such as `--config` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config")) + /// .get_matches_from(vec![ + /// "prog", "--config" + /// ]); + /// + /// assert!(m.is_present("cfg")); + /// ``` + pub fn long(mut self, l: &'b str) -> Self { + self.s.long = Some(l.trim_left_matches(|c| c == '-')); + self + } + + /// Allows adding a [`Arg`] alias, which function as "hidden" arguments that + /// automatically dispatch as if this argument was used. This is more efficient, and easier + /// than creating multiple hidden arguments as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .alias("alias") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--alias", "cool" + /// ]); + /// assert!(m.is_present("test")); + /// assert_eq!(m.value_of("test"), Some("cool")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + pub fn alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.s.aliases { + als.push((name.into(), false)); + } else { + self.s.aliases = Some(vec![(name.into(), false)]); + } + self + } + + /// Allows adding [`Arg`] aliases, which function as "hidden" arguments that + /// automatically dispatch as if this argument was used. This is more efficient, and easier + /// than creating multiple hidden subcommands as one only needs to check for the existence of + /// this command, and not all variants. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .aliases(&["do-stuff", "do-tests", "tests"]) + /// .help("the file to add") + /// .required(false)) + /// .get_matches_from(vec![ + /// "prog", "--do-tests" + /// ]); + /// assert!(m.is_present("test")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + pub fn aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.s.aliases { + for n in names { + als.push((n, false)); + } + } else { + self.s.aliases = Some(names.iter().map(|n| (*n, false)).collect::>()); + } + self + } + + /// Allows adding a [`Arg`] alias that functions exactly like those defined with + /// [`Arg::alias`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .visible_alias("something-awesome") + /// .long("test") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--something-awesome", "coffee" + /// ]); + /// assert!(m.is_present("test")); + /// assert_eq!(m.value_of("test"), Some("coffee")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`App::alias`]: ./struct.Arg.html#method.alias + pub fn visible_alias>(mut self, name: S) -> Self { + if let Some(ref mut als) = self.s.aliases { + als.push((name.into(), true)); + } else { + self.s.aliases = Some(vec![(name.into(), true)]); + } + self + } + + /// Allows adding multiple [`Arg`] aliases that functions exactly like those defined + /// with [`Arg::aliases`], except that they are visible inside the help message. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("test") + /// .long("test") + /// .visible_aliases(&["something", "awesome", "cool"])) + /// .get_matches_from(vec![ + /// "prog", "--awesome" + /// ]); + /// assert!(m.is_present("test")); + /// ``` + /// [`Arg`]: ./struct.Arg.html + /// [`App::aliases`]: ./struct.Arg.html#method.aliases + pub fn visible_aliases(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut als) = self.s.aliases { + for n in names { + als.push((n, true)); + } + } else { + self.s.aliases = Some(names.iter().map(|n| (*n, true)).collect::>()); + } + self + } + + /// Sets the short help text of the argument that will be displayed to the user when they print + /// the help information with `-h`. Typically, this is a short (one line) description of the + /// arg. + /// + /// **NOTE:** If only `Arg::help` is provided, and not [`Arg::long_help`] but the user requests + /// `--help` clap will still display the contents of `help` appropriately + /// + /// **NOTE:** Only `Arg::help` is used in completion script generation in order to be concise + /// + /// # Examples + /// + /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to + /// include a newline in the help text and have the following text be properly aligned with all + /// the other help text. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .help("The config file used by the myprog") + /// # ; + /// ``` + /// + /// Setting `help` displays a short message to the side of the argument when the user passes + /// `-h` or `--help` (by default). + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// [`Arg::long_help`]: ./struct.Arg.html#method.long_help + pub fn help(mut self, h: &'b str) -> Self { + self.b.help = Some(h); + self + } + + /// Sets the long help text of the argument that will be displayed to the user when they print + /// the help information with `--help`. Typically this a more detailed (multi-line) message + /// that describes the arg. + /// + /// **NOTE:** If only `long_help` is provided, and not [`Arg::help`] but the user requests `-h` + /// clap will still display the contents of `long_help` appropriately + /// + /// **NOTE:** Only [`Arg::help`] is used in completion script generation in order to be concise + /// + /// # Examples + /// + /// Any valid UTF-8 is allowed in the help text. The one exception is when one wishes to + /// include a newline in the help text and have the following text be properly aligned with all + /// the other help text. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .long_help( + /// "The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now.") + /// # ; + /// ``` + /// + /// Setting `help` displays a short message to the side of the argument when the user passes + /// `-h` or `--help` (by default). + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .long_help( + /// "The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now.")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config + /// The config file used by the myprog must be in JSON format + /// with only valid keys and may not contain other nonsense + /// that cannot be read by this program. Obviously I'm going on + /// and on, so I'll stop now. + /// + /// -h, --help + /// Prints help information + /// + /// -V, --version + /// Prints version information + /// ``` + /// [`Arg::help`]: ./struct.Arg.html#method.help + pub fn long_help(mut self, h: &'b str) -> Self { + self.b.long_help = Some(h); + self + } + + /// Specifies that this arg is the last, or final, positional argument (i.e. has the highest + /// index) and is *only* able to be accessed via the `--` syntax (i.e. `$ prog args -- + /// last_arg`). Even, if no other arguments are left to parse, if the user omits the `--` syntax + /// they will receive an [`UnknownArgument`] error. Setting an argument to `.last(true)` also + /// allows one to access this arg early using the `--` syntax. Accessing an arg early, even with + /// the `--` syntax is otherwise not possible. + /// + /// **NOTE:** This will change the usage string to look like `$ prog [FLAGS] [-- ]` if + /// `ARG` is marked as `.last(true)`. + /// + /// **NOTE:** This setting will imply [`AppSettings::DontCollapseArgsInUsage`] because failing + /// to set this can make the usage string very confusing. + /// + /// **NOTE**: This setting only applies to positional arguments, and has no affect on FLAGS / + /// OPTIONS + /// + /// **CAUTION:** Setting an argument to `.last(true)` *and* having child subcommands is not + /// recommended with the exception of *also* using [`AppSettings::ArgsNegateSubcommands`] + /// (or [`AppSettings::SubcommandsNegateReqs`] if the argument marked `.last(true)` is also + /// marked [`.required(true)`]) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("args") + /// .last(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::last(true)`] ensures the arg has the highest [index] of all positional args + /// and requires that the `--` syntax be used to access it early. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third").last(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "one", "--", "three" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// assert_eq!(m.value_of("third"), Some("three")); + /// assert!(m.value_of("second").is_none()); + /// ``` + /// + /// Even if the positional argument marked `.last(true)` is the only argument left to parse, + /// failing to use the `--` syntax results in an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("first")) + /// .arg(Arg::with_name("second")) + /// .arg(Arg::with_name("third").last(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "one", "two", "three" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`Arg::last(true)`]: ./struct.Arg.html#method.last + /// [index]: ./struct.Arg.html#method.index + /// [`AppSettings::DontCollapseArgsInUsage`]: ./enum.AppSettings.html#variant.DontCollapseArgsInUsage + /// [`AppSettings::ArgsNegateSubcommands`]: ./enum.AppSettings.html#variant.ArgsNegateSubcommands + /// [`AppSettings::SubcommandsNegateReqs`]: ./enum.AppSettings.html#variant.SubcommandsNegateReqs + /// [`.required(true)`]: ./struct.Arg.html#method.required + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + pub fn last(self, l: bool) -> Self { + if l { + self.set(ArgSettings::Last) + } else { + self.unset(ArgSettings::Last) + } + } + + /// Sets whether or not the argument is required by default. Required by default means it is + /// required, when no other conflicting rules have been evaluated. Conflicting rules take + /// precedence over being required. **Default:** `false` + /// + /// **NOTE:** Flags (i.e. not positional, or arguments that take values) cannot be required by + /// default. This is simply because if a flag should be required, it should simply be implied + /// as no additional information is required from user. Flags by their very nature are simply + /// yes/no, or true/false. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::required(true)`] requires that the argument be used at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required(true)`] and *not* supplying that argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required(true)`]: ./struct.Arg.html#method.required + pub fn required(self, r: bool) -> Self { + if r { + self.set(ArgSettings::Required) + } else { + self.unset(ArgSettings::Required) + } + } + + /// Requires that options use the `--option=val` syntax (i.e. an equals between the option and + /// associated value) **Default:** `false` + /// + /// **NOTE:** This setting also removes the default of allowing empty values and implies + /// [`Arg::empty_values(false)`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .long("config") + /// .takes_value(true) + /// .require_equals(true) + /// # ; + /// ``` + /// + /// Setting [`Arg::require_equals(true)`] requires that the option have an equals sign between + /// it and the associated value. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .require_equals(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config=file.conf" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::require_equals(true)`] and *not* supplying the equals will cause an error + /// unless [`Arg::empty_values(true)`] is set. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .require_equals(true) + /// .takes_value(true) + /// .long("config")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// [`Arg::require_equals(true)`]: ./struct.Arg.html#method.require_equals + /// [`Arg::empty_values(true)`]: ./struct.Arg.html#method.empty_values + /// [`Arg::empty_values(false)`]: ./struct.Arg.html#method.empty_values + pub fn require_equals(mut self, r: bool) -> Self { + if r { + self.unsetb(ArgSettings::EmptyValues); + self.set(ArgSettings::RequireEquals) + } else { + self.unset(ArgSettings::RequireEquals) + } + } + + /// Allows values which start with a leading hyphen (`-`) + /// + /// **WARNING**: Take caution when using this setting combined with [`Arg::multiple(true)`], as + /// this becomes ambiguous `$ prog --arg -- -- val`. All three `--, --, val` will be values + /// when the user may have thought the second `--` would constitute the normal, "Only + /// positional args follow" idiom. To fix this, consider using [`Arg::number_of_values(1)`] + /// + /// **WARNING**: When building your CLIs, consider the effects of allowing leading hyphens and + /// the user passing in a value that matches a valid short. For example `prog -opt -F` where + /// `-F` is supposed to be a value, yet `-F` is *also* a valid short for another arg. Care should + /// should be taken when designing these args. This is compounded by the ability to "stack" + /// short args. I.e. if `-val` is supposed to be a value, but `-v`, `-a`, and `-l` are all valid + /// shorts. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("pattern") + /// .allow_hyphen_values(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .allow_hyphen_values(true) + /// .takes_value(true) + /// .long("pattern")) + /// .get_matches_from(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert_eq!(m.value_of("pat"), Some("-file")); + /// ``` + /// + /// Not setting [`Arg::allow_hyphen_values(true)`] and supplying a value which starts with a + /// hyphen is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("pat") + /// .takes_value(true) + /// .long("pattern")) + /// .get_matches_from_safe(vec![ + /// "prog", "--pattern", "-file" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + pub fn allow_hyphen_values(self, a: bool) -> Self { + if a { + self.set(ArgSettings::AllowLeadingHyphen) + } else { + self.unset(ArgSettings::AllowLeadingHyphen) + } + } + /// Sets an arg that override this arg's required setting. (i.e. this arg will be required + /// unless this other argument is present). + /// + /// **Pro Tip:** Using [`Arg::required_unless`] implies [`Arg::required`] and is therefore not + /// mandatory to also set. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless("debug") + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless(name)`] requires that the argument be used at runtime + /// *unless* `name` is present. In the following example, the required argument is *not* + /// provided, but it's not an error because the `unless` arg has been supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless("dbg") + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless(name)`] and *not* supplying `name` or this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless("dbg") + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless + /// [`Arg::required`]: ./struct.Arg.html#method.required + /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless + pub fn required_unless(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + vec.push(name); + } else { + self.b.r_unless = Some(vec![name]); + } + self.required(true) + } + + /// Sets args that override this arg's required setting. (i.e. this arg will be required unless + /// all these other arguments are present). + /// + /// **NOTE:** If you wish for this argument to only be required if *one of* these args are + /// present see [`Arg::required_unless_one`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless_all(&["cfg", "dbg"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless_all(names)`] requires that the argument be used at runtime + /// *unless* *all* the args in `names` are present. In the following example, the required + /// argument is *not* provided, but it's not an error because all the `unless` args have been + /// supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_all(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug", "-i", "file" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless_all(names)`] and *not* supplying *all* of `names` or this + /// arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_all(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all + pub fn required_unless_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + for s in names { + vec.push(s); + } + } else { + self.b.r_unless = Some(names.iter().map(|s| *s).collect::>()); + } + self.setb(ArgSettings::RequiredUnlessAll); + self.required(true) + } + + /// Sets args that override this arg's [required] setting. (i.e. this arg will be required + /// unless *at least one of* these other arguments are present). + /// + /// **NOTE:** If you wish for this argument to only be required if *all of* these args are + /// present see [`Arg::required_unless_all`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_unless_all(&["cfg", "dbg"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_unless_one(names)`] requires that the argument be used at runtime + /// *unless* *at least one of* the args in `names` are present. In the following example, the + /// required argument is *not* provided, but it's not an error because one the `unless` args + /// have been supplied. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_one(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug" + /// ]); + /// + /// assert!(res.is_ok()); + /// ``` + /// + /// Setting [`Arg::required_unless_one(names)`] and *not* supplying *at least one of* `names` + /// or this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_unless_one(&["dbg", "infile"]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("dbg") + /// .long("debug")) + /// .arg(Arg::with_name("infile") + /// .short("i") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required]: ./struct.Arg.html#method.required + /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all + pub fn required_unless_one(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.r_unless { + for s in names { + vec.push(s); + } + } else { + self.b.r_unless = Some(names.iter().map(|s| *s).collect::>()); + } + self.required(true) + } + + /// Sets a conflicting argument by name. I.e. when using this argument, + /// the following argument can't be present and vice versa. + /// + /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules + /// only need to be set for one of the two arguments, they do not need to be set for each. + /// + /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments + /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need + /// need to also do B.conflicts_with(A)) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .conflicts_with("debug") + /// # ; + /// ``` + /// + /// Setting conflicting argument, and having both arguments present at runtime is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .conflicts_with("debug") + /// .long("config")) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .get_matches_from_safe(vec![ + /// "prog", "--debug", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + pub fn conflicts_with(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.blacklist { + vec.push(name); + } else { + self.b.blacklist = Some(vec![name]); + } + self + } + + /// The same as [`Arg::conflicts_with`] but allows specifying multiple two-way conlicts per + /// argument. + /// + /// **NOTE:** Conflicting rules take precedence over being required by default. Conflict rules + /// only need to be set for one of the two arguments, they do not need to be set for each. + /// + /// **NOTE:** Defining a conflict is two-way, but does *not* need to defined for both arguments + /// (i.e. if A conflicts with B, defining A.conflicts_with(B) is sufficient. You do not need + /// need to also do B.conflicts_with(A)) + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .conflicts_with_all(&["debug", "input"]) + /// # ; + /// ``` + /// + /// Setting conflicting argument, and having any of the arguments present at runtime with a + /// conflicting argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .conflicts_with_all(&["debug", "input"]) + /// .long("config")) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf", "file.txt" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + /// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with + pub fn conflicts_with_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.blacklist { + for s in names { + vec.push(s); + } + } else { + self.b.blacklist = Some(names.iter().map(|s| *s).collect::>()); + } + self + } + + /// Sets a overridable argument by name. I.e. this argument and the following argument + /// will override each other in POSIX style (whichever argument was specified at runtime + /// **last** "wins") + /// + /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any + /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed + /// + /// **WARNING:** Positional arguments cannot override themselves (or we would never be able + /// to advance to the next positional). If a positional agument lists itself as an override, + /// it is simply ignored. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::from_usage("-f, --flag 'some flag'") + /// .conflicts_with("debug")) + /// .arg(Arg::from_usage("-d, --debug 'other flag'")) + /// .arg(Arg::from_usage("-c, --color 'third flag'") + /// .overrides_with("flag")) + /// .get_matches_from(vec![ + /// "prog", "-f", "-d", "-c"]); + /// // ^~~~~~~~~~~~^~~~~ flag is overridden by color + /// + /// assert!(m.is_present("color")); + /// assert!(m.is_present("debug")); // even though flag conflicts with debug, it's as if flag + /// // was never used because it was overridden with color + /// assert!(!m.is_present("flag")); + /// ``` + /// Care must be taken when using this setting, and having an arg override with itself. This + /// is common practice when supporting things like shell aliases, config files, etc. + /// However, when combined with multiple values, it can get dicy. + /// Here is how clap handles such situations: + /// + /// When a flag overrides itself, it's as if the flag was only ever used once (essentially + /// preventing a "Unexpected multiple usage" error): + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["posix", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 1); + /// ``` + /// Making a arg `multiple(true)` and override itself is essentially meaningless. Therefore + /// clap ignores an override of self if it's a flag and it already accepts multiple occurrences. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--flag... 'some flag'").overrides_with("flag")) + /// .get_matches_from(vec!["", "--flag", "--flag", "--flag", "--flag"]); + /// assert!(m.is_present("flag")); + /// assert_eq!(m.occurrences_of("flag"), 4); + /// ``` + /// Now notice with options (which *do not* set `multiple(true)`), it's as if only the last + /// occurrence happened. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val] 'some option'").overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt=some", "--opt=other"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.value_of("opt"), Some("other")); + /// ``` + /// + /// Just like flags, options with `multiple(true)` set, will ignore the "override self" setting. + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val]... 'some option'") + /// .overrides_with("opt")) + /// .get_matches_from(vec!["", "--opt", "first", "over", "--opt", "other", "val"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 2); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["first", "over", "other", "val"]); + /// ``` + /// + /// A safe thing to do if you'd like to support an option which supports multiple values, but + /// also is "overridable" by itself, is to use `use_delimiter(false)` and *not* use + /// `multiple(true)` while telling users to seperate values with a comma (i.e. `val1,val2`) + /// + /// ``` + /// # use clap::{App, Arg}; + /// let m = App::new("posix") + /// .arg(Arg::from_usage("--opt [val] 'some option'") + /// .overrides_with("opt") + /// .use_delimiter(false)) + /// .get_matches_from(vec!["", "--opt=some,other", "--opt=one,two"]); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// assert_eq!(m.values_of("opt").unwrap().collect::>(), &["one,two"]); + /// ``` + pub fn overrides_with(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.overrides { + vec.push(name); + } else { + self.b.overrides = Some(vec![name]); + } + self + } + + /// Sets multiple mutually overridable arguments by name. I.e. this argument and the following + /// argument will override each other in POSIX style (whichever argument was specified at + /// runtime **last** "wins") + /// + /// **NOTE:** When an argument is overridden it is essentially as if it never was used, any + /// conflicts, requirements, etc. are evaluated **after** all "overrides" have been removed + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::from_usage("-f, --flag 'some flag'") + /// .conflicts_with("color")) + /// .arg(Arg::from_usage("-d, --debug 'other flag'")) + /// .arg(Arg::from_usage("-c, --color 'third flag'") + /// .overrides_with_all(&["flag", "debug"])) + /// .get_matches_from(vec![ + /// "prog", "-f", "-d", "-c"]); + /// // ^~~~~~^~~~~~~~~ flag and debug are overridden by color + /// + /// assert!(m.is_present("color")); // even though flag conflicts with color, it's as if flag + /// // and debug were never used because they were overridden + /// // with color + /// assert!(!m.is_present("debug")); + /// assert!(!m.is_present("flag")); + /// ``` + pub fn overrides_with_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.overrides { + for s in names { + vec.push(s); + } + } else { + self.b.overrides = Some(names.iter().map(|s| *s).collect::>()); + } + self + } + + /// Sets an argument by name that is required when this one is present I.e. when + /// using this argument, the following argument *must* be present. + /// + /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires("input") + /// # ; + /// ``` + /// + /// Setting [`Arg::requires(name)`] requires that the argument be used at runtime if the + /// defining argument is used. If the defining argument isn't used, the other argument isn't + /// required + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use cfg, so input wasn't required + /// ``` + /// + /// Setting [`Arg::requires(name)`] and *not* supplying that argument is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.requires { + vec.push((None, name)); + } else { + let mut vec = vec![]; + vec.push((None, name)); + self.b.requires = Some(vec); + } + self + } + + /// Allows a conditional requirement. The requirement will only become valid if this arg's value + /// equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// requires_if: + /// - [val, arg] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_if("val", "arg") + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_if(val, arg)`] requires that the `arg` be used at runtime if the + /// defining argument's value is equal to `val`. If the defining argument is anything other than + /// `val`, the other argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_if("my.cfg", "other") + /// .long("config")) + /// .arg(Arg::with_name("other")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "some.cfg" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --config=my.cfg, so other wasn't required + /// ``` + /// + /// Setting [`Arg::requires_if(val, arg)`] and setting the value to `val` but *not* supplying + /// `arg` is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_if("my.cfg", "input") + /// .long("config")) + /// .arg(Arg::with_name("input")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "my.cfg" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires_if(mut self, val: &'b str, arg: &'a str) -> Self { + if let Some(ref mut vec) = self.b.requires { + vec.push((Some(val), arg)); + } else { + self.b.requires = Some(vec![(Some(val), arg)]); + } + self + } + + /// Allows multiple conditional requirements. The requirement will only become valid if this arg's value + /// equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// requires_if: + /// - [val, arg] + /// - [val2, arg2] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_ifs(&[ + /// ("val", "arg"), + /// ("other_val", "arg2"), + /// ]) + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_ifs(&["val", "arg"])`] requires that the `arg` be used at runtime if the + /// defining argument's value is equal to `val`. If the defining argument's value is anything other + /// than `val`, `arg` isn't required. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_ifs(&[ + /// ("special.conf", "opt"), + /// ("other.conf", "other"), + /// ]) + /// .long("config")) + /// .arg(Arg::with_name("opt") + /// .long("option") + /// .takes_value(true)) + /// .arg(Arg::with_name("other")) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "special.conf" + /// ]); + /// + /// assert!(res.is_err()); // We used --config=special.conf so --option is required + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + pub fn requires_ifs(mut self, ifs: &[(&'b str, &'a str)]) -> Self { + if let Some(ref mut vec) = self.b.requires { + for &(val, arg) in ifs { + vec.push((Some(val), arg)); + } + } else { + let mut vec = vec![]; + for &(val, arg) in ifs { + vec.push((Some(val), arg)); + } + self.b.requires = Some(vec); + } + self + } + + /// Allows specifying that an argument is [required] conditionally. The requirement will only + /// become valid if the specified `arg`'s value equals `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// required_if: + /// - [arg, val] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_if("other_arg", "value") + /// # ; + /// ``` + /// + /// Setting [`Arg::required_if(arg, val)`] makes this arg required if the `arg` is used at + /// runtime and it's value is equal to `val`. If the `arg`'s value is anything other than `val`, + /// this argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .required_if("other", "special") + /// .long("config")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--other", "not-special" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --other=special, so "cfg" wasn't required + /// ``` + /// + /// Setting [`Arg::required_if(arg, val)`] and having `arg` used with a value of `val` but *not* + /// using this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .required_if("other", "special") + /// .long("config")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "--other", "special" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [required]: ./struct.Arg.html#method.required + pub fn required_if(mut self, arg: &'a str, val: &'b str) -> Self { + if let Some(ref mut vec) = self.r_ifs { + vec.push((arg, val)); + } else { + self.r_ifs = Some(vec![(arg, val)]); + } + self + } + + /// Allows specifying that an argument is [required] based on multiple conditions. The + /// conditions are set up in a `(arg, val)` style tuple. The requirement will only become valid + /// if one of the specified `arg`'s value equals it's corresponding `val`. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// required_if: + /// - [arg, val] + /// - [arg2, val2] + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// # ; + /// ``` + /// + /// Setting [`Arg::required_ifs(&[(arg, val)])`] makes this arg required if any of the `arg`s + /// are used at runtime and it's corresponding value is equal to `val`. If the `arg`'s value is + /// anything other than `val`, this argument isn't required. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("extra") + /// .takes_value(true) + /// .long("extra")) + /// .arg(Arg::with_name("option") + /// .takes_value(true) + /// .long("option")) + /// .get_matches_from_safe(vec![ + /// "prog", "--option", "other" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use --option=spec, or --extra=val so "cfg" isn't required + /// ``` + /// + /// Setting [`Arg::required_ifs(&[(arg, val)])`] and having any of the `arg`s used with it's + /// value of `val` but *not* using this arg is an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .required_ifs(&[ + /// ("extra", "val"), + /// ("option", "spec") + /// ]) + /// .takes_value(true) + /// .long("config")) + /// .arg(Arg::with_name("extra") + /// .takes_value(true) + /// .long("extra")) + /// .arg(Arg::with_name("option") + /// .takes_value(true) + /// .long("option")) + /// .get_matches_from_safe(vec![ + /// "prog", "--option", "spec" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [required]: ./struct.Arg.html#method.required + pub fn required_ifs(mut self, ifs: &[(&'a str, &'b str)]) -> Self { + if let Some(ref mut vec) = self.r_ifs { + for r_if in ifs { + vec.push((r_if.0, r_if.1)); + } + } else { + let mut vec = vec![]; + for r_if in ifs { + vec.push((r_if.0, r_if.1)); + } + self.r_ifs = Some(vec); + } + self + } + + /// Sets multiple arguments by names that are required when this one is present I.e. when + /// using this argument, the following arguments *must* be present. + /// + /// **NOTE:** [Conflicting] rules and [override] rules take precedence over being required + /// by default. + /// + /// # Examples + /// + /// ```rust + /// # use clap::Arg; + /// Arg::with_name("config") + /// .requires_all(&["input", "output"]) + /// # ; + /// ``` + /// + /// Setting [`Arg::requires_all(&[arg, arg2])`] requires that all the arguments be used at + /// runtime if the defining argument is used. If the defining argument isn't used, the other + /// argument isn't required + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires("input") + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .arg(Arg::with_name("output") + /// .index(2)) + /// .get_matches_from_safe(vec![ + /// "prog" + /// ]); + /// + /// assert!(res.is_ok()); // We didn't use cfg, so input and output weren't required + /// ``` + /// + /// Setting [`Arg::requires_all(&[arg, arg2])`] and *not* supplying all the arguments is an + /// error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .takes_value(true) + /// .requires_all(&["input", "output"]) + /// .long("config")) + /// .arg(Arg::with_name("input") + /// .index(1)) + /// .arg(Arg::with_name("output") + /// .index(2)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config", "file.conf", "in.txt" + /// ]); + /// + /// assert!(res.is_err()); + /// // We didn't use output + /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [Conflicting]: ./struct.Arg.html#method.conflicts_with + /// [override]: ./struct.Arg.html#method.overrides_with + /// [`Arg::requires_all(&[arg, arg2])`]: ./struct.Arg.html#method.requires_all + pub fn requires_all(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.requires { + for s in names { + vec.push((None, s)); + } + } else { + let mut vec = vec![]; + for s in names { + vec.push((None, *s)); + } + self.b.requires = Some(vec); + } + self + } + + /// Specifies that the argument takes a value at run time. + /// + /// **NOTE:** values for arguments may be specified in any of the following methods + /// + /// * Using a space such as `-o value` or `--option value` + /// * Using an equals and no space such as `-o=value` or `--option=value` + /// * Use a short and no space such as `-ovalue` + /// + /// **NOTE:** By default, args which allow [multiple values] are delimited by commas, meaning + /// `--option=val1,val2,val3` is three values for the `--option` argument. If you wish to + /// change the delimiter to another character you can use [`Arg::value_delimiter(char)`], + /// alternatively you can turn delimiting values **OFF** by using [`Arg::use_delimiter(false)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .takes_value(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// [`Arg::value_delimiter(char)`]: ./struct.Arg.html#method.value_delimiter + /// [`Arg::use_delimiter(false)`]: ./struct.Arg.html#method.use_delimiter + /// [multiple values]: ./struct.Arg.html#method.multiple + pub fn takes_value(self, tv: bool) -> Self { + if tv { + self.set(ArgSettings::TakesValue) + } else { + self.unset(ArgSettings::TakesValue) + } + } + + /// Specifies if the possible values of an argument should be displayed in the help text or + /// not. Defaults to `false` (i.e. show possible values) + /// + /// This is useful for args with many values, or ones which are explained elsewhere in the + /// help text. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .hide_possible_values(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .possible_values(&["fast", "slow"]) + /// .takes_value(true) + /// .hide_possible_values(true)); + /// + /// ``` + /// + /// If we were to run the above program with `--help` the `[values: fast, slow]` portion of + /// the help text would be omitted. + pub fn hide_possible_values(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HidePossibleValues) + } else { + self.unset(ArgSettings::HidePossibleValues) + } + } + + /// Specifies if the default value of an argument should be displayed in the help text or + /// not. Defaults to `false` (i.e. show default value) + /// + /// This is useful when default behavior of an arg is explained elsewhere in the help text. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .hide_default_value(true) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("connect") + /// .arg(Arg::with_name("host") + /// .long("host") + /// .default_value("localhost") + /// .hide_default_value(true)); + /// + /// ``` + /// + /// If we were to run the above program with `--help` the `[default: localhost]` portion of + /// the help text would be omitted. + pub fn hide_default_value(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HideDefaultValue) + } else { + self.unset(ArgSettings::HideDefaultValue) + } + } + + /// Specifies the index of a positional argument **starting at** 1. + /// + /// **NOTE:** The index refers to position according to **other positional argument**. It does + /// not define position in the argument list as a whole. + /// + /// **NOTE:** If no [`Arg::short`], or [`Arg::long`] have been defined, you can optionally + /// leave off the `index` method, and the index will be assigned in order of evaluation. + /// Utilizing the `index` method allows for setting indexes out of order + /// + /// **NOTE:** When utilized with [`Arg::multiple(true)`], only the **last** positional argument + /// may be defined as multiple (i.e. with the highest index) + /// + /// # Panics + /// + /// Although not in this method directly, [`App`] will [`panic!`] if indexes are skipped (such + /// as defining `index(1)` and `index(3)` but not `index(2)`, or a positional argument is + /// defined as multiple and is not the highest index + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("config") + /// .index(1) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .index(1)) + /// .arg(Arg::with_name("debug") + /// .long("debug")) + /// .get_matches_from(vec![ + /// "prog", "--debug", "fast" + /// ]); + /// + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); // notice index(1) means "first positional" + /// // *not* first argument + /// ``` + /// [`Arg::short`]: ./struct.Arg.html#method.short + /// [`Arg::long`]: ./struct.Arg.html#method.long + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`App`]: ./struct.App.html + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + pub fn index(mut self, idx: u64) -> Self { + self.index = Some(idx); + self + } + + /// Specifies that the argument may appear more than once. For flags, this results + /// in the number of occurrences of the flag being recorded. For example `-ddd` or `-d -d -d` + /// would count as three occurrences. For options there is a distinct difference in multiple + /// occurrences vs multiple values. + /// + /// For example, `--opt val1 val2` is one occurrence, but two values. Whereas + /// `--opt val1 --opt val2` is two occurrences. + /// + /// **WARNING:** + /// + /// Setting `multiple(true)` for an [option] with no other details, allows multiple values + /// **and** multiple occurrences because it isn't possible to have more occurrences than values + /// for options. Because multiple values are allowed, `--option val1 val2 val3` is perfectly + /// valid, be careful when designing a CLI where positional arguments are expected after a + /// option which accepts multiple values, as `clap` will continue parsing *values* until it + /// reaches the max or specific number of values defined, or another flag or option. + /// + /// **Pro Tip**: + /// + /// It's possible to define an option which allows multiple occurrences, but only one value per + /// occurrence. To do this use [`Arg::number_of_values(1)`] in coordination with + /// [`Arg::multiple(true)`]. + /// + /// **WARNING:** + /// + /// When using args with `multiple(true)` on [options] or [positionals] (i.e. those args that + /// accept values) and [subcommands], one needs to consider the possibility of an argument value + /// being the same as a valid subcommand. By default `clap` will parse the argument in question + /// as a value *only if* a value is possible at that moment. Otherwise it will be parsed as a + /// subcommand. In effect, this means using `multiple(true)` with no additional parameters and + /// a possible value that coincides with a subcommand name, the subcommand cannot be called + /// unless another argument is passed first. + /// + /// As an example, consider a CLI with an option `--ui-paths=...` and subcommand `signer` + /// + /// The following would be parsed as values to `--ui-paths`. + /// + /// ```notrust + /// $ program --ui-paths path1 path2 signer + /// ``` + /// + /// This is because `--ui-paths` accepts multiple values. `clap` will continue parsing values + /// until another argument is reached and it knows `--ui-paths` is done. + /// + /// By adding additional parameters to `--ui-paths` we can solve this issue. Consider adding + /// [`Arg::number_of_values(1)`] as discussed above. The following are all valid, and `signer` + /// is parsed as both a subcommand and a value in the second case. + /// + /// ```notrust + /// $ program --ui-paths path1 signer + /// $ program --ui-paths path1 --ui-paths signer signer + /// ``` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .short("d") + /// .multiple(true) + /// # ; + /// ``` + /// An example with flags + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verbose") + /// .multiple(true) + /// .short("v")) + /// .get_matches_from(vec![ + /// "prog", "-v", "-v", "-v" // note, -vvv would have same result + /// ]); + /// + /// assert!(m.is_present("verbose")); + /// assert_eq!(m.occurrences_of("verbose"), 3); + /// ``` + /// + /// An example with options + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 1); // notice only one occurrence + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// This is functionally equivalent to the example above + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3" + /// ]); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// + /// assert!(m.is_present("file")); + /// assert_eq!(m.occurrences_of("file"), 3); // Notice 3 occurrences + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// + /// A common mistake is to define an option which allows multiples, and a positional argument + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3", "word"]); // wait...what?! + /// assert!(!m.is_present("word")); // but we clearly used word! + /// ``` + /// The problem is clap doesn't know when to stop parsing values for "files". This is further + /// compounded by if we'd said `word -F file1 file2` it would have worked fine, so it would + /// appear to only fail sometimes...not good! + /// + /// A solution for the example above is to specify that `-F` only accepts one value, but is + /// allowed to appear multiple times + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .number_of_values(1) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from(vec![ + /// "prog", "-F", "file1", "-F", "file2", "-F", "file3", "word" + /// ]); + /// + /// assert!(m.is_present("file")); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// assert!(m.is_present("word")); + /// assert_eq!(m.value_of("word"), Some("word")); + /// ``` + /// As a final example, notice if we define [`Arg::number_of_values(1)`] and try to run the + /// problem example above, it would have been a runtime error with a pretty message to the + /// user :) + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .multiple(true) + /// .takes_value(true) + /// .number_of_values(1) + /// .short("F")) + /// .arg(Arg::with_name("word") + /// .index(1)) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3", "word" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [options]: ./struct.Arg.html#method.takes_value + /// [subcommands]: ./struct.SubCommand.html + /// [positionals]: ./struct.Arg.html#method.index + /// [`Arg::number_of_values(1)`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn multiple(self, multi: bool) -> Self { + if multi { + self.set(ArgSettings::Multiple) + } else { + self.unset(ArgSettings::Multiple) + } + } + + /// Specifies a value that *stops* parsing multiple values of a give argument. By default when + /// one sets [`multiple(true)`] on an argument, clap will continue parsing values for that + /// argument until it reaches another valid argument, or one of the other more specific settings + /// for multiple values is used (such as [`min_values`], [`max_values`] or + /// [`number_of_values`]). + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// **NOTE:** When the terminator is passed in on the command line, it is **not** stored as one + /// of the values + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("vals") + /// .takes_value(true) + /// .multiple(true) + /// .value_terminator(";") + /// # ; + /// ``` + /// The following example uses two arguments, a sequence of commands, and the location in which + /// to perform them + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cmds") + /// .multiple(true) + /// .allow_hyphen_values(true) + /// .value_terminator(";")) + /// .arg(Arg::with_name("location")) + /// .get_matches_from(vec![ + /// "prog", "find", "-type", "f", "-name", "special", ";", "/home/clap" + /// ]); + /// let cmds: Vec<_> = m.values_of("cmds").unwrap().collect(); + /// assert_eq!(&cmds, &["find", "-type", "f", "-name", "special"]); + /// assert_eq!(m.value_of("location"), Some("/home/clap")); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + /// [`multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`min_values`]: ./struct.Arg.html#method.min_values + /// [`number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`max_values`]: ./struct.Arg.html#method.max_values + pub fn value_terminator(mut self, term: &'b str) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.terminator = Some(term); + self + } + + /// Specifies that an argument can be matched to all child [`SubCommand`]s. + /// + /// **NOTE:** Global arguments *only* propagate down, **not** up (to parent commands), however + /// their values once a user uses them will be propagated back up to parents. In effect, this + /// means one should *define* all global arguments at the top level, however it doesn't matter + /// where the user *uses* the global argument. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .short("d") + /// .global(true) + /// # ; + /// ``` + /// + /// For example, assume an application with two subcommands, and you'd like to define a + /// `--verbose` flag that can be called on any of the subcommands and parent, but you don't + /// want to clutter the source with three duplicate [`Arg`] definitions. + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("verb") + /// .long("verbose") + /// .short("v") + /// .global(true)) + /// .subcommand(SubCommand::with_name("test")) + /// .subcommand(SubCommand::with_name("do-stuff")) + /// .get_matches_from(vec![ + /// "prog", "do-stuff", "--verbose" + /// ]); + /// + /// assert_eq!(m.subcommand_name(), Some("do-stuff")); + /// let sub_m = m.subcommand_matches("do-stuff").unwrap(); + /// assert!(sub_m.is_present("verb")); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [required]: ./struct.Arg.html#method.required + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [`ArgMatches::is_present("flag")`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg`]: ./struct.Arg.html + pub fn global(self, g: bool) -> Self { + if g { + self.set(ArgSettings::Global) + } else { + self.unset(ArgSettings::Global) + } + } + + /// Allows an argument to accept explicitly empty values. An empty value must be specified at + /// the command line with an explicit `""`, or `''` + /// + /// **NOTE:** Defaults to `true` (Explicitly empty values are allowed) + /// + /// **NOTE:** Implicitly sets [`Arg::takes_value(true)`] when set to `false` + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .long("file") + /// .empty_values(false) + /// # ; + /// ``` + /// The default is to allow empty values, such as `--option ""` would be an empty value. But + /// we can change to make empty values become an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .short("v") + /// .empty_values(false)) + /// .get_matches_from_safe(vec![ + /// "prog", "--config=" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn empty_values(mut self, ev: bool) -> Self { + if ev { + self.set(ArgSettings::EmptyValues) + } else { + self = self.set(ArgSettings::TakesValue); + self.unset(ArgSettings::EmptyValues) + } + } + + /// Hides an argument from help message output. + /// + /// **NOTE:** Implicitly sets [`Arg::hidden_short_help(true)`] and [`Arg::hidden_long_help(true)`] + /// when set to true + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden(true) + /// # ; + /// ``` + /// Setting `hidden(true)` will hide the argument when displaying help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// [`Arg::hidden_short_help(true)`]: ./struct.Arg.html#method.hidden_short_help + /// [`Arg::hidden_long_help(true)`]: ./struct.Arg.html#method.hidden_long_help + pub fn hidden(self, h: bool) -> Self { + if h { + self.set(ArgSettings::Hidden) + } else { + self.unset(ArgSettings::Hidden) + } + } + + /// Specifies a list of possible values for this argument. At runtime, `clap` verifies that + /// only one of the specified values was used, or fails with an error message. + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"]) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"])) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// + /// The next example shows a failed parse from using a value which wasn't defined as one of the + /// possible values. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_values(&["fast", "slow", "medium"])) + /// .get_matches_from_safe(vec![ + /// "prog", "--mode", "wrong" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + pub fn possible_values(mut self, names: &[&'b str]) -> Self { + if let Some(ref mut vec) = self.v.possible_vals { + for s in names { + vec.push(s); + } + } else { + self.v.possible_vals = Some(names.iter().map(|s| *s).collect::>()); + } + self + } + + /// Specifies a possible value for this argument, one at a time. At runtime, `clap` verifies + /// that only one of the specified values was used, or fails with error message. + /// + /// **NOTE:** This setting only applies to [options] and [positional arguments] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium") + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium")) + /// .get_matches_from(vec![ + /// "prog", "--mode", "fast" + /// ]); + /// assert!(m.is_present("mode")); + /// assert_eq!(m.value_of("mode"), Some("fast")); + /// ``` + /// + /// The next example shows a failed parse from using a value which wasn't defined as one of the + /// possible values. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("mode") + /// .long("mode") + /// .takes_value(true) + /// .possible_value("fast") + /// .possible_value("slow") + /// .possible_value("medium")) + /// .get_matches_from_safe(vec![ + /// "prog", "--mode", "wrong" + /// ]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [options]: ./struct.Arg.html#method.takes_value + /// [positional arguments]: ./struct.Arg.html#method.index + pub fn possible_value(mut self, name: &'b str) -> Self { + if let Some(ref mut vec) = self.v.possible_vals { + vec.push(name); + } else { + self.v.possible_vals = Some(vec![name]); + } + self + } + + /// When used with [`Arg::possible_values`] it allows the argument value to pass validation even if + /// the case differs from that of the specified `possible_value`. + /// + /// **Pro Tip:** Use this setting with [`arg_enum!`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// # use std::ascii::AsciiExt; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .long("--option") + /// .takes_value(true) + /// .possible_value("test123") + /// .case_insensitive(true)) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", + /// ]); + /// + /// assert!(m.value_of("option").unwrap().eq_ignore_ascii_case("test123")); + /// ``` + /// + /// This setting also works when multiple values can be defined: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("pv") + /// .arg(Arg::with_name("option") + /// .short("-o") + /// .long("--option") + /// .takes_value(true) + /// .possible_value("test123") + /// .possible_value("test321") + /// .multiple(true) + /// .case_insensitive(true)) + /// .get_matches_from(vec![ + /// "pv", "--option", "TeSt123", "teST123", "tESt321" + /// ]); + /// + /// let matched_vals = m.values_of("option").unwrap().collect::>(); + /// assert_eq!(&*matched_vals, &["TeSt123", "teST123", "tESt321"]); + /// ``` + /// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.possible_values + /// [`arg_enum!`]: ./macro.arg_enum.html + pub fn case_insensitive(self, ci: bool) -> Self { + if ci { + self.set(ArgSettings::CaseInsensitive) + } else { + self.unset(ArgSettings::CaseInsensitive) + } + } + + /// Specifies the name of the [`ArgGroup`] the argument belongs to. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .long("debug") + /// .group("mode") + /// # ; + /// ``` + /// + /// Multiple arguments can be a member of a single group and then the group checked as if it + /// was one of said arguments. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .group("mode")) + /// .arg(Arg::with_name("verbose") + /// .long("verbose") + /// .group("mode")) + /// .get_matches_from(vec![ + /// "prog", "--debug" + /// ]); + /// assert!(m.is_present("mode")); + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn group(mut self, name: &'a str) -> Self { + if let Some(ref mut vec) = self.b.groups { + vec.push(name); + } else { + self.b.groups = Some(vec![name]); + } + self + } + + /// Specifies the names of multiple [`ArgGroup`]'s the argument belongs to. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .long("debug") + /// .groups(&["mode", "verbosity"]) + /// # ; + /// ``` + /// + /// Arguments can be members of multiple groups and then the group checked as if it + /// was one of said arguments. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .groups(&["mode", "verbosity"])) + /// .arg(Arg::with_name("verbose") + /// .long("verbose") + /// .groups(&["mode", "verbosity"])) + /// .get_matches_from(vec![ + /// "prog", "--debug" + /// ]); + /// assert!(m.is_present("mode")); + /// assert!(m.is_present("verbosity")); + /// ``` + /// [`ArgGroup`]: ./struct.ArgGroup.html + pub fn groups(mut self, names: &[&'a str]) -> Self { + if let Some(ref mut vec) = self.b.groups { + for s in names { + vec.push(s); + } + } else { + self.b.groups = Some(names.into_iter().map(|s| *s).collect::>()); + } + self + } + + /// Specifies how many values are required to satisfy this argument. For example, if you had a + /// `-f ` argument where you wanted exactly 3 'files' you would set + /// `.number_of_values(3)`, and this argument wouldn't be satisfied unless the user provided + /// 3 and only 3 values. + /// + /// **NOTE:** Does *not* require [`Arg::multiple(true)`] to be set. Setting + /// [`Arg::multiple(true)`] would allow `-f -f ` where + /// as *not* setting [`Arg::multiple(true)`] would only allow one occurrence of this argument. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .number_of_values(3) + /// # ; + /// ``` + /// + /// Not supplying the correct number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .number_of_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::WrongNumberOfValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn number_of_values(mut self, qty: u64) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.num_vals = Some(qty); + self + } + + /// Allows one to perform a custom validation on the argument value. You provide a closure + /// which accepts a [`String`] value, and return a [`Result`] where the [`Err(String)`] is a + /// message displayed to the user. + /// + /// **NOTE:** The error message does *not* need to contain the `error:` portion, only the + /// message as all errors will appear as + /// `error: Invalid value for '': ` where `` is replaced by the actual + /// arg, and `` is the `String` you return as the error. + /// + /// **NOTE:** There is a small performance hit for using validators, as they are implemented + /// with [`Rc`] pointers. And the value to be checked will be allocated an extra time in order + /// to to be passed to the closure. This performance hit is extremely minimal in the grand + /// scheme of things. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// fn has_at(v: String) -> Result<(), String> { + /// if v.contains("@") { return Ok(()); } + /// Err(String::from("The value did not contain the required @ sigil")) + /// } + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .index(1) + /// .validator(has_at)) + /// .get_matches_from_safe(vec![ + /// "prog", "some@file" + /// ]); + /// assert!(res.is_ok()); + /// assert_eq!(res.unwrap().value_of("file"), Some("some@file")); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html + pub fn validator(mut self, f: F) -> Self + where + F: Fn(String) -> Result<(), String> + 'static, + { + self.v.validator = Some(Rc::new(f)); + self + } + + /// Works identically to Validator but is intended to be used with values that could + /// contain non UTF-8 formatted strings. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```rust")] + /// # use clap::{App, Arg}; + /// # use std::ffi::{OsStr, OsString}; + /// # use std::os::unix::ffi::OsStrExt; + /// fn has_ampersand(v: &OsStr) -> Result<(), OsString> { + /// if v.as_bytes().iter().any(|b| *b == b'&') { return Ok(()); } + /// Err(OsString::from("The value did not contain the required & sigil")) + /// } + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .index(1) + /// .validator_os(has_ampersand)) + /// .get_matches_from_safe(vec![ + /// "prog", "Fish & chips" + /// ]); + /// assert!(res.is_ok()); + /// assert_eq!(res.unwrap().value_of("file"), Some("Fish & chips")); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html + /// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html + /// [`Err(String)`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err + /// [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html + pub fn validator_os(mut self, f: F) -> Self + where + F: Fn(&OsStr) -> Result<(), OsString> + 'static, + { + self.v.validator_os = Some(Rc::new(f)); + self + } + + /// Specifies the *maximum* number of values are for this argument. For example, if you had a + /// `-f ` argument where you wanted up to 3 'files' you would set `.max_values(3)`, and + /// this argument would be satisfied if the user provided, 1, 2, or 3 values. + /// + /// **NOTE:** This does *not* implicitly set [`Arg::multiple(true)`]. This is because + /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single + /// occurrence with multiple values. For positional arguments this **does** set + /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple + /// occurrences and multiple values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .max_values(3) + /// # ; + /// ``` + /// + /// Supplying less than the maximum number of values is allowed + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .max_values(3) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2"]); + /// ``` + /// + /// Supplying more than the maximum number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .max_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooManyValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn max_values(mut self, qty: u64) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.max_vals = Some(qty); + self + } + + /// Specifies the *minimum* number of values for this argument. For example, if you had a + /// `-f ` argument where you wanted at least 2 'files' you would set + /// `.min_values(2)`, and this argument would be satisfied if the user provided, 2 or more + /// values. + /// + /// **NOTE:** This does not implicitly set [`Arg::multiple(true)`]. This is because + /// `-o val -o val` is multiple occurrences but a single value and `-o val1 val2` is a single + /// occurrence with multiple values. For positional arguments this **does** set + /// [`Arg::multiple(true)`] because there is no way to determine the difference between multiple + /// occurrences and multiple values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("file") + /// .short("f") + /// .min_values(3) + /// # ; + /// ``` + /// + /// Supplying more than the minimum number of values is allowed + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .min_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1", "file2", "file3" + /// ]); + /// + /// assert!(res.is_ok()); + /// let m = res.unwrap(); + /// let files: Vec<_> = m.values_of("file").unwrap().collect(); + /// assert_eq!(files, ["file1", "file2", "file3"]); + /// ``` + /// + /// Supplying less than the minimum number of values is an error + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("file") + /// .takes_value(true) + /// .min_values(2) + /// .short("F")) + /// .get_matches_from_safe(vec![ + /// "prog", "-F", "file1" + /// ]); + /// + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::TooFewValues); + /// ``` + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn min_values(mut self, qty: u64) -> Self { + self.v.min_vals = Some(qty); + self.set(ArgSettings::TakesValue) + } + + /// Specifies whether or not an argument should allow grouping of multiple values via a + /// delimiter. I.e. should `--option=val1,val2,val3` be parsed as three values (`val1`, `val2`, + /// and `val3`) or as a single value (`val1,val2,val3`). Defaults to using `,` (comma) as the + /// value delimiter for all arguments that accept values (options and positional arguments) + /// + /// **NOTE:** The default is `false`. When set to `true` the default [`Arg::value_delimiter`] + /// is the comma `,`. + /// + /// # Examples + /// + /// The following example shows the default behavior. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .use_delimiter(true) + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("option")); + /// assert_eq!(delims.occurrences_of("option"), 1); + /// assert_eq!(delims.values_of("option").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// The next example shows the difference when turning delimiters off. This is the default + /// behavior + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let nodelims = App::new("prog") + /// .arg(Arg::with_name("option") + /// .long("option") + /// .use_delimiter(false) + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "prog", "--option=val1,val2,val3", + /// ]); + /// + /// assert!(nodelims.is_present("option")); + /// assert_eq!(nodelims.occurrences_of("option"), 1); + /// assert_eq!(nodelims.value_of("option").unwrap(), "val1,val2,val3"); + /// ``` + /// [`Arg::value_delimiter`]: ./struct.Arg.html#method.value_delimiter + pub fn use_delimiter(mut self, d: bool) -> Self { + if d { + if self.v.val_delim.is_none() { + self.v.val_delim = Some(','); + } + self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::UseValueDelimiter); + self.unset(ArgSettings::ValueDelimiterNotSet) + } else { + self.v.val_delim = None; + self.unsetb(ArgSettings::UseValueDelimiter); + self.unset(ArgSettings::ValueDelimiterNotSet) + } + } + + /// Specifies that *multiple values* may only be set using the delimiter. This means if an + /// if an option is encountered, and no delimiter is found, it automatically assumed that no + /// additional values for that option follow. This is unlike the default, where it is generally + /// assumed that more values will follow regardless of whether or not a delimiter is used. + /// + /// **NOTE:** The default is `false`. + /// + /// **NOTE:** Setting this to true implies [`Arg::use_delimiter(true)`] + /// + /// **NOTE:** It's a good idea to inform the user that use of a delimiter is required, either + /// through help text or other means. + /// + /// # Examples + /// + /// These examples demonstrate what happens when `require_delimiter(true)` is used. Notice + /// everything works in this first example, as we use a delimiter, as expected. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true) + /// .require_delimiter(true)) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1,val2,val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// In this next example, we will *not* use a delimiter. Notice it's now an error. + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true) + /// .require_delimiter(true)) + /// .get_matches_from_safe(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(res.is_err()); + /// let err = res.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::UnknownArgument); + /// ``` + /// What's happening is `-o` is getting `val1`, and because delimiters are required yet none + /// were present, it stops parsing `-o`. At this point it reaches `val2` and because no + /// positional arguments have been defined, it's an error of an unexpected argument. + /// + /// In this final example, we contrast the above with `clap`'s default behavior where the above + /// is *not* an error. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let delims = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec![ + /// "prog", "-o", "val1", "val2", "val3", + /// ]); + /// + /// assert!(delims.is_present("opt")); + /// assert_eq!(delims.values_of("opt").unwrap().collect::>(), ["val1", "val2", "val3"]); + /// ``` + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + pub fn require_delimiter(mut self, d: bool) -> Self { + if d { + self = self.use_delimiter(true); + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::UseValueDelimiter); + self.set(ArgSettings::RequireDelimiter) + } else { + self = self.use_delimiter(false); + self.unsetb(ArgSettings::UseValueDelimiter); + self.unset(ArgSettings::RequireDelimiter) + } + } + + /// Specifies the separator to use when values are clumped together, defaults to `,` (comma). + /// + /// **NOTE:** implicitly sets [`Arg::use_delimiter(true)`] + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .short("c") + /// .long("config") + /// .value_delimiter(";")) + /// .get_matches_from(vec![ + /// "prog", "--config=val1;val2;val3" + /// ]); + /// + /// assert_eq!(m.values_of("config").unwrap().collect::>(), ["val1", "val2", "val3"]) + /// ``` + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn value_delimiter(mut self, d: &str) -> Self { + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::TakesValue); + self.setb(ArgSettings::UseValueDelimiter); + self.v.val_delim = Some( + d.chars() + .nth(0) + .expect("Failed to get value_delimiter from arg"), + ); + self + } + + /// Specify multiple names for values of option arguments. These names are cosmetic only, used + /// for help and usage strings only. The names are **not** used to access arguments. The values + /// of the arguments are accessed in numeric order (i.e. if you specify two names `one` and + /// `two` `one` will be the first matched value, `two` will be the second). + /// + /// This setting can be very helpful when describing the type of input the user should be + /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to + /// use all capital letters for the value name. + /// + /// **Pro Tip:** It may help to use [`Arg::next_line_help(true)`] if there are long, or + /// multiple value names in order to not throw off the help text alignment of all options. + /// + /// **NOTE:** This implicitly sets [`Arg::number_of_values`] if the number of value names is + /// greater than one. I.e. be aware that the number of "names" you set for the values, will be + /// the *exact* number of values required to satisfy this argument + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// **NOTE:** Does *not* require or imply [`Arg::multiple(true)`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("speed") + /// .short("s") + /// .value_names(&["fast", "slow"]) + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("io") + /// .long("io-files") + /// .value_names(&["INFILE", "OUTFILE"])) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// Running the above program produces the following output + /// + /// ```notrust + /// valnames + /// + /// USAGE: + /// valnames [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// --io-files Some help text + /// ``` + /// [`Arg::next_line_help(true)`]: ./struct.Arg.html#method.next_line_help + /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + pub fn value_names(mut self, names: &[&'b str]) -> Self { + self.setb(ArgSettings::TakesValue); + if self.is_set(ArgSettings::ValueDelimiterNotSet) { + self.unsetb(ArgSettings::ValueDelimiterNotSet); + self.setb(ArgSettings::UseValueDelimiter); + } + if let Some(ref mut vals) = self.v.val_names { + let mut l = vals.len(); + for s in names { + vals.insert(l, s); + l += 1; + } + } else { + let mut vm = VecMap::new(); + for (i, n) in names.iter().enumerate() { + vm.insert(i, *n); + } + self.v.val_names = Some(vm); + } + self + } + + /// Specifies the name for value of [option] or [positional] arguments inside of help + /// documentation. This name is cosmetic only, the name is **not** used to access arguments. + /// This setting can be very helpful when describing the type of input the user should be + /// using, such as `FILE`, `INTERFACE`, etc. Although not required, it's somewhat convention to + /// use all capital letters for the value name. + /// + /// **NOTE:** implicitly sets [`Arg::takes_value(true)`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("cfg") + /// .long("config") + /// .value_name("FILE") + /// # ; + /// ``` + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("config") + /// .long("config") + /// .value_name("FILE")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// Running the above program produces the following output + /// + /// ```notrust + /// valnames + /// + /// USAGE: + /// valnames [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// --config Some help text + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [positional]: ./struct.Arg.html#method.index + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + pub fn value_name(mut self, name: &'b str) -> Self { + self.setb(ArgSettings::TakesValue); + if let Some(ref mut vals) = self.v.val_names { + let l = vals.len(); + vals.insert(l, name); + } else { + let mut vm = VecMap::new(); + vm.insert(0, name); + self.v.val_names = Some(vm); + } + self + } + + /// Specifies the value of the argument when *not* specified at runtime. + /// + /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`] + /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified. + /// + /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will + /// still return `true`. If you wish to determine whether the argument was used at runtime or + /// not, consider [`ArgMatches::occurrences_of`] which will return `0` if the argument was *not* + /// used at runtime. + /// + /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value_if`] but slightly + /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg + /// at runtime. `Arg::default_value_if` however only takes affect when the user has not provided + /// a value at runtime **and** these other conditions are met as well. If you have set + /// `Arg::default_value` and `Arg::default_value_if`, and the user **did not** provide a this + /// arg at runtime, nor did were the conditions met for `Arg::default_value_if`, the + /// `Arg::default_value` will be applied. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** This setting effectively disables `AppSettings::ArgRequiredElseHelp` if used in + /// conjunction as it ensures that some argument will always be present. + /// + /// # Examples + /// + /// First we use the default value without providing any value at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("myopt") + /// .default_value("myval")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("opt"), Some("myval")); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 0); + /// ``` + /// + /// Next we provide a value at runtime to override the default. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("myopt") + /// .default_value("myval")) + /// .get_matches_from(vec![ + /// "prog", "--myopt=non_default" + /// ]); + /// + /// assert_eq!(m.value_of("opt"), Some("non_default")); + /// assert!(m.is_present("opt")); + /// assert_eq!(m.occurrences_of("opt"), 1); + /// ``` + /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of + /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if + pub fn default_value(self, val: &'a str) -> Self { + self.default_value_os(OsStr::from_bytes(val.as_bytes())) + } + + /// Provides a default value in the exact same manner as [`Arg::default_value`] + /// only using [`OsStr`]s instead. + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + pub fn default_value_os(mut self, val: &'a OsStr) -> Self { + self.setb(ArgSettings::TakesValue); + self.v.default_val = Some(val); + self + } + + /// Specifies the value of the argument if `arg` has been used at runtime. If `val` is set to + /// `None`, `arg` only needs to be present. If `val` is set to `"some-val"` then `arg` must be + /// present at runtime **and** have the value `val`. + /// + /// **NOTE:** This setting is perfectly compatible with [`Arg::default_value`] but slightly + /// different. `Arg::default_value` *only* takes affect when the user has not provided this arg + /// at runtime. This setting however only takes affect when the user has not provided a value at + /// runtime **and** these other conditions are met as well. If you have set `Arg::default_value` + /// and `Arg::default_value_if`, and the user **did not** provide a this arg at runtime, nor did + /// were the conditions met for `Arg::default_value_if`, the `Arg::default_value` will be + /// applied. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** If using YAML the values should be laid out as follows (`None` can be represented + /// as `null` in YAML) + /// + /// ```yaml + /// default_value_if: + /// - [arg, val, default] + /// ``` + /// + /// # Examples + /// + /// First we use the default value only if another arg is present at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("flag", None, "default")) + /// .get_matches_from(vec![ + /// "prog", "--flag" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// + /// Next we run the same test, but without providing `--flag`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("flag", None, "default")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// + /// Now lets only use the default value if `--opt` contains the value `special`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .takes_value(true) + /// .long("opt")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("opt", Some("special"), "default")) + /// .get_matches_from(vec![ + /// "prog", "--opt", "special" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// + /// We can run the same test and provide any value *other than* `special` and we won't get a + /// default value. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .takes_value(true) + /// .long("opt")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_if("opt", Some("special"), "default")) + /// .get_matches_from(vec![ + /// "prog", "--opt", "hahaha" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + pub fn default_value_if(self, arg: &'a str, val: Option<&'b str>, default: &'b str) -> Self { + self.default_value_if_os( + arg, + val.map(str::as_bytes).map(OsStr::from_bytes), + OsStr::from_bytes(default.as_bytes()), + ) + } + + /// Provides a conditional default value in the exact same manner as [`Arg::default_value_if`] + /// only using [`OsStr`]s instead. + /// [`Arg::default_value_if`]: ./struct.Arg.html#method.default_value_if + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + pub fn default_value_if_os( + mut self, + arg: &'a str, + val: Option<&'b OsStr>, + default: &'b OsStr, + ) -> Self { + self.setb(ArgSettings::TakesValue); + if let Some(ref mut vm) = self.v.default_vals_ifs { + let l = vm.len(); + vm.insert(l, (arg, val, default)); + } else { + let mut vm = VecMap::new(); + vm.insert(0, (arg, val, default)); + self.v.default_vals_ifs = Some(vm); + } + self + } + + /// Specifies multiple values and conditions in the same manner as [`Arg::default_value_if`]. + /// The method takes a slice of tuples in the `(arg, Option, default)` format. + /// + /// **NOTE**: The conditions are stored in order and evaluated in the same order. I.e. the first + /// if multiple conditions are true, the first one found will be applied and the ultimate value. + /// + /// **NOTE:** If using YAML the values should be laid out as follows + /// + /// ```yaml + /// default_value_if: + /// - [arg, val, default] + /// - [arg2, null, default2] + /// ``` + /// + /// # Examples + /// + /// First we use the default value only if another arg is present at runtime. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("opt") + /// .long("opt") + /// .takes_value(true)) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog", "--opt", "channal" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("chan")); + /// ``` + /// + /// Next we run the same test, but without providing `--flag`. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("other"), None); + /// ``` + /// + /// We can also see that these values are applied in order, and if more than one condition is + /// true, only the first evaluated "wins" + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag")) + /// .arg(Arg::with_name("opt") + /// .long("opt") + /// .takes_value(true)) + /// .arg(Arg::with_name("other") + /// .long("other") + /// .default_value_ifs(&[ + /// ("flag", None, "default"), + /// ("opt", Some("channal"), "chan"), + /// ])) + /// .get_matches_from(vec![ + /// "prog", "--opt", "channal", "--flag" + /// ]); + /// + /// assert_eq!(m.value_of("other"), Some("default")); + /// ``` + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::default_value`]: ./struct.Arg.html#method.default_value + pub fn default_value_ifs(mut self, ifs: &[(&'a str, Option<&'b str>, &'b str)]) -> Self { + for &(arg, val, default) in ifs { + self = self.default_value_if_os( + arg, + val.map(str::as_bytes).map(OsStr::from_bytes), + OsStr::from_bytes(default.as_bytes()), + ); + } + self + } + + /// Provides multiple conditional default values in the exact same manner as + /// [`Arg::default_value_ifs`] only using [`OsStr`]s instead. + /// [`Arg::default_value_ifs`]: ./struct.Arg.html#method.default_value_ifs + /// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html + #[cfg_attr(feature = "lints", allow(explicit_counter_loop))] + pub fn default_value_ifs_os(mut self, ifs: &[(&'a str, Option<&'b OsStr>, &'b OsStr)]) -> Self { + for &(arg, val, default) in ifs { + self = self.default_value_if_os(arg, val, default); + } + self + } + + /// Specifies that if the value is not passed in as an argument, that it should be retrieved + /// from the environment, if available. If it is not present in the environment, then default + /// rules will apply. + /// + /// **NOTE:** If the user *does not* use this argument at runtime, [`ArgMatches::occurrences_of`] + /// will return `0` even though the [`ArgMatches::value_of`] will return the default specified. + /// + /// **NOTE:** If the user *does not* use this argument at runtime [`ArgMatches::is_present`] will + /// return `true` if the variable is present in the environment . If you wish to determine whether + /// the argument was used at runtime or not, consider [`ArgMatches::occurrences_of`] which will + /// return `0` if the argument was *not* used at runtime. + /// + /// **NOTE:** This implicitly sets [`Arg::takes_value(true)`]. + /// + /// **NOTE:** If [`Arg::multiple(true)`] is set then [`Arg::use_delimiter(true)`] should also be + /// set. Otherwise, only a single argument will be returned from the environment variable. The + /// default delimiter is `,` and follows all the other delimiter rules. + /// + /// # Examples + /// + /// In this example, we show the variable coming from the environment: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("env")); + /// ``` + /// + /// In this example, we show the variable coming from an option on the CLI: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG")) + /// .get_matches_from(vec![ + /// "prog", "--flag", "opt" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("opt")); + /// ``` + /// + /// In this example, we show the variable coming from the environment even with the + /// presence of a default: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG", "env"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG") + /// .default_value("default")) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.value_of("flag"), Some("env")); + /// ``` + /// + /// In this example, we show the use of multiple values in a single environment variable: + /// + /// ```rust + /// # use std::env; + /// # use clap::{App, Arg}; + /// + /// env::set_var("MY_FLAG_MULTI", "env1,env2"); + /// + /// let m = App::new("prog") + /// .arg(Arg::with_name("flag") + /// .long("flag") + /// .env("MY_FLAG_MULTI") + /// .multiple(true) + /// .use_delimiter(true)) + /// .get_matches_from(vec![ + /// "prog" + /// ]); + /// + /// assert_eq!(m.values_of("flag").unwrap().collect::>(), vec!["env1", "env2"]); + /// ``` + /// [`ArgMatches::occurrences_of`]: ./struct.ArgMatches.html#method.occurrences_of + /// [`ArgMatches::value_of`]: ./struct.ArgMatches.html#method.value_of + /// [`ArgMatches::is_present`]: ./struct.ArgMatches.html#method.is_present + /// [`Arg::takes_value(true)`]: ./struct.Arg.html#method.takes_value + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::use_delimiter(true)`]: ./struct.Arg.html#method.use_delimiter + pub fn env(self, name: &'a str) -> Self { + self.env_os(OsStr::new(name)) + } + + /// Specifies that if the value is not passed in as an argument, that it should be retrieved + /// from the environment if available in the exact same manner as [`Arg::env`] only using + /// [`OsStr`]s instead. + pub fn env_os(mut self, name: &'a OsStr) -> Self { + self.setb(ArgSettings::TakesValue); + + self.v.env = Some((name, env::var_os(name))); + self + } + + /// @TODO @p2 @docs @release: write docs + pub fn hide_env_values(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HideEnvValues) + } else { + self.unset(ArgSettings::HideEnvValues) + } + } + + /// When set to `true` the help string will be displayed on the line after the argument and + /// indented once. This can be helpful for arguments with very long or complex help messages. + /// This can also be helpful for arguments with very long flag names, or many/long value names. + /// + /// **NOTE:** To apply this setting to all arguments consider using + /// [`AppSettings::NextLineHelp`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("opt") + /// .long("long-option-flag") + /// .short("o") + /// .takes_value(true) + /// .value_names(&["value1", "value2"]) + /// .help("Some really long help and complex\n\ + /// help that makes more sense to be\n\ + /// on a line after the option") + /// .next_line_help(true)) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```notrust + /// nlh + /// + /// USAGE: + /// nlh [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// -o, --long-option-flag + /// Some really long help and complex + /// help that makes more sense to be + /// on a line after the option + /// ``` + /// [`AppSettings::NextLineHelp`]: ./enum.AppSettings.html#variant.NextLineHelp + pub fn next_line_help(mut self, nlh: bool) -> Self { + if nlh { + self.setb(ArgSettings::NextLineHelp); + } else { + self.unsetb(ArgSettings::NextLineHelp); + } + self + } + + /// Allows custom ordering of args within the help message. Args with a lower value will be + /// displayed first in the help message. This is helpful when one would like to emphasise + /// frequently used args, or prioritize those towards the top of the list. Duplicate values + /// **are** allowed. Args with duplicate display orders will be displayed in alphabetical + /// order. + /// + /// **NOTE:** The default is 999 for all arguments. + /// + /// **NOTE:** This setting is ignored for [positional arguments] which are always displayed in + /// [index] order. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("a") // Typically args are grouped alphabetically by name. + /// // Args without a display_order have a value of 999 and are + /// // displayed alphabetically with all other 999 valued args. + /// .long("long-option") + /// .short("o") + /// .takes_value(true) + /// .help("Some help and text")) + /// .arg(Arg::with_name("b") + /// .long("other-option") + /// .short("O") + /// .takes_value(true) + /// .display_order(1) // In order to force this arg to appear *first* + /// // all we have to do is give it a value lower than 999. + /// // Any other args with a value of 1 will be displayed + /// // alphabetically with this one...then 2 values, then 3, etc. + /// .help("I should be first!")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays the following help message + /// + /// ```notrust + /// cust-ord + /// + /// USAGE: + /// cust-ord [FLAGS] [OPTIONS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// + /// OPTIONS: + /// -O, --other-option I should be first! + /// -o, --long-option Some help and text + /// ``` + /// [positional arguments]: ./struct.Arg.html#method.index + /// [index]: ./struct.Arg.html#method.index + pub fn display_order(mut self, ord: usize) -> Self { + self.s.disp_ord = ord; + self + } + + /// Indicates that all parameters passed after this should not be parsed + /// individually, but rather passed in their entirety. It is worth noting + /// that setting this requires all values to come after a `--` to indicate they + /// should all be captured. For example: + /// + /// ```notrust + /// --foo something -- -v -v -v -b -b -b --baz -q -u -x + /// ``` + /// Will result in everything after `--` to be considered one raw argument. This behavior + /// may not be exactly what you are expecting and using [`AppSettings::TrailingVarArg`] + /// may be more appropriate. + /// + /// **NOTE:** Implicitly sets [`Arg::multiple(true)`], [`Arg::allow_hyphen_values(true)`], and + /// [`Arg::last(true)`] when set to `true` + /// + /// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple + /// [`Arg::allow_hyphen_values(true)`]: ./struct.Arg.html#method.allow_hyphen_values + /// [`Arg::last(true)`]: ./struct.Arg.html#method.last + /// [`AppSettings::TrailingVarArg`]: ./enum.AppSettings.html#variant.TrailingVarArg + pub fn raw(self, raw: bool) -> Self { + self.multiple(raw).allow_hyphen_values(raw).last(raw) + } + + /// Hides an argument from short help message output. + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// **NOTE:** Setting this option will cause next-line-help output style to be used + /// when long help (`--help`) is called. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden_short_help(true) + /// # ; + /// ``` + /// Setting `hidden_short_help(true)` will hide the argument when displaying short help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_short_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "-h" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// + /// However, when --help is called + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_short_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// Then the following would be displayed + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + pub fn hidden_short_help(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HiddenShortHelp) + } else { + self.unset(ArgSettings::HiddenShortHelp) + } + } + + /// Hides an argument from long help message output. + /// + /// **NOTE:** This does **not** hide the argument from usage strings on error + /// + /// **NOTE:** Setting this option will cause next-line-help output style to be used + /// when long help (`--help`) is called. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// Arg::with_name("debug") + /// .hidden_long_help(true) + /// # ; + /// ``` + /// Setting `hidden_long_help(true)` will hide the argument when displaying long help text + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_long_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "--help" + /// ]); + /// ``` + /// + /// The above example displays + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + /// + /// However, when -h is called + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("prog") + /// .arg(Arg::with_name("cfg") + /// .long("config") + /// .hidden_long_help(true) + /// .help("Some help text describing the --config arg")) + /// .get_matches_from(vec![ + /// "prog", "-h" + /// ]); + /// ``` + /// + /// Then the following would be displayed + /// + /// ```notrust + /// helptest + /// + /// USAGE: + /// helptest [FLAGS] + /// + /// FLAGS: + /// --config Some help text describing the --config arg + /// -h, --help Prints help information + /// -V, --version Prints version information + /// ``` + pub fn hidden_long_help(self, hide: bool) -> Self { + if hide { + self.set(ArgSettings::HiddenLongHelp) + } else { + self.unset(ArgSettings::HiddenLongHelp) + } + } + + /// Checks if one of the [`ArgSettings`] settings is set for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn is_set(&self, s: ArgSettings) -> bool { + self.b.is_set(s) + } + + /// Sets one of the [`ArgSettings`] settings for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn set(mut self, s: ArgSettings) -> Self { + self.setb(s); + self + } + + /// Unsets one of the [`ArgSettings`] settings for the argument. + /// + /// [`ArgSettings`]: ./enum.ArgSettings.html + pub fn unset(mut self, s: ArgSettings) -> Self { + self.unsetb(s); + self + } + + #[doc(hidden)] + pub fn setb(&mut self, s: ArgSettings) { + self.b.set(s); + } + + #[doc(hidden)] + pub fn unsetb(&mut self, s: ArgSettings) { + self.b.unset(s); + } +} + +impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> { + fn from(a: &'z Arg<'a, 'b>) -> Self { + Arg { + b: a.b.clone(), + v: a.v.clone(), + s: a.s.clone(), + index: a.index, + r_ifs: a.r_ifs.clone(), + } + } +} + +impl<'n, 'e> PartialEq for Arg<'n, 'e> { + fn eq(&self, other: &Arg<'n, 'e>) -> bool { + self.b == other.b + } +} diff --git a/clap/src/args/arg_builder/base.rs b/clap/src/args/arg_builder/base.rs new file mode 100644 index 000000000..fef9d8ab9 --- /dev/null +++ b/clap/src/args/arg_builder/base.rs @@ -0,0 +1,38 @@ +use args::{Arg, ArgFlags, ArgSettings}; + +#[derive(Debug, Clone, Default)] +pub struct Base<'a, 'b> +where + 'a: 'b, +{ + pub name: &'a str, + pub help: Option<&'b str>, + pub long_help: Option<&'b str>, + pub blacklist: Option>, + pub settings: ArgFlags, + pub r_unless: Option>, + pub overrides: Option>, + pub groups: Option>, + pub requires: Option, &'a str)>>, +} + +impl<'n, 'e> Base<'n, 'e> { + pub fn new(name: &'n str) -> Self { + Base { + name: name, + ..Default::default() + } + } + + pub fn set(&mut self, s: ArgSettings) { self.settings.set(s); } + pub fn unset(&mut self, s: ArgSettings) { self.settings.unset(s); } + pub fn is_set(&self, s: ArgSettings) -> bool { self.settings.is_set(s) } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Base<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { a.b.clone() } +} + +impl<'n, 'e> PartialEq for Base<'n, 'e> { + fn eq(&self, other: &Base<'n, 'e>) -> bool { self.name == other.name } +} diff --git a/clap/src/args/arg_builder/flag.rs b/clap/src/args/arg_builder/flag.rs new file mode 100644 index 000000000..641e7777e --- /dev/null +++ b/clap/src/args/arg_builder/flag.rs @@ -0,0 +1,159 @@ +// Std +use std::convert::From; +use std::fmt::{Display, Formatter, Result}; +use std::rc::Rc; +use std::result::Result as StdResult; +use std::ffi::{OsStr, OsString}; +use std::mem; + +// Internal +use Arg; +use args::{AnyArg, ArgSettings, Base, DispOrder, Switched}; +use map::{self, VecMap}; + +#[derive(Default, Clone, Debug)] +#[doc(hidden)] +pub struct FlagBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub s: Switched<'e>, +} + +impl<'n, 'e> FlagBuilder<'n, 'e> { + pub fn new(name: &'n str) -> Self { + FlagBuilder { + b: Base::new(name), + ..Default::default() + } + } +} + +impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for FlagBuilder<'a, 'b> { + fn from(a: &'z Arg<'a, 'b>) -> Self { + FlagBuilder { + b: Base::from(a), + s: Switched::from(a), + } + } +} + +impl<'a, 'b> From> for FlagBuilder<'a, 'b> { + fn from(mut a: Arg<'a, 'b>) -> Self { + FlagBuilder { + b: mem::replace(&mut a.b, Base::default()), + s: mem::replace(&mut a.s, Switched::default()), + } + } +} + +impl<'n, 'e> Display for FlagBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + if let Some(l) = self.s.long { + write!(f, "--{}", l)?; + } else { + write!(f, "-{}", self.s.short.unwrap())?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> { + fn name(&self) -> &'n str { self.b.name } + fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) } + fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) } + fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) } + fn has_switch(&self) -> bool { true } + fn takes_value(&self) -> bool { false } + fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) } + fn max_vals(&self) -> Option { None } + fn val_names(&self) -> Option<&VecMap<&'e str>> { None } + fn num_vals(&self) -> Option { None } + fn possible_vals(&self) -> Option<&[&'e str]> { None } + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { None } + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { None } + fn min_vals(&self) -> Option { None } + fn short(&self) -> Option { self.s.short } + fn long(&self) -> Option<&'e str> { self.s.long } + fn val_delim(&self) -> Option { None } + fn help(&self) -> Option<&'e str> { self.b.help } + fn long_help(&self) -> Option<&'e str> { self.b.long_help } + fn val_terminator(&self) -> Option<&'e str> { None } + fn default_val(&self) -> Option<&'e OsStr> { None } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + None + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { None } + fn longest_filter(&self) -> bool { self.s.long.is_some() } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.s.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> DispOrder for FlagBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { self.s.disp_ord } +} + +impl<'n, 'e> PartialEq for FlagBuilder<'n, 'e> { + fn eq(&self, other: &FlagBuilder<'n, 'e>) -> bool { self.b == other.b } +} + +#[cfg(test)] +mod test { + use args::settings::ArgSettings; + use super::FlagBuilder; + + #[test] + fn flagbuilder_display() { + let mut f = FlagBuilder::new("flg"); + f.b.settings.set(ArgSettings::Multiple); + f.s.long = Some("flag"); + + assert_eq!(&*format!("{}", f), "--flag"); + + let mut f2 = FlagBuilder::new("flg"); + f2.s.short = Some('f'); + + assert_eq!(&*format!("{}", f2), "-f"); + } + + #[test] + fn flagbuilder_display_single_alias() { + let mut f = FlagBuilder::new("flg"); + f.s.long = Some("flag"); + f.s.aliases = Some(vec![("als", true)]); + + assert_eq!(&*format!("{}", f), "--flag"); + } + + #[test] + fn flagbuilder_display_multiple_aliases() { + let mut f = FlagBuilder::new("flg"); + f.s.short = Some('f'); + f.s.aliases = Some(vec![ + ("alias_not_visible", false), + ("f2", true), + ("f3", true), + ("f4", true), + ]); + assert_eq!(&*format!("{}", f), "-f"); + } +} diff --git a/clap/src/args/arg_builder/mod.rs b/clap/src/args/arg_builder/mod.rs new file mode 100644 index 000000000..d1a7a6608 --- /dev/null +++ b/clap/src/args/arg_builder/mod.rs @@ -0,0 +1,13 @@ +pub use self::flag::FlagBuilder; +pub use self::option::OptBuilder; +pub use self::positional::PosBuilder; +pub use self::base::Base; +pub use self::switched::Switched; +pub use self::valued::Valued; + +mod flag; +mod positional; +mod option; +mod base; +mod valued; +mod switched; diff --git a/clap/src/args/arg_builder/option.rs b/clap/src/args/arg_builder/option.rs new file mode 100644 index 000000000..4bb147a7d --- /dev/null +++ b/clap/src/args/arg_builder/option.rs @@ -0,0 +1,244 @@ +// Std +use std::fmt::{Display, Formatter, Result}; +use std::rc::Rc; +use std::result::Result as StdResult; +use std::ffi::{OsStr, OsString}; +use std::mem; + +// Internal +use args::{AnyArg, Arg, ArgSettings, Base, DispOrder, Switched, Valued}; +use map::{self, VecMap}; +use INTERNAL_ERROR_MSG; + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Default, Clone)] +pub struct OptBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub s: Switched<'e>, + pub v: Valued<'n, 'e>, +} + +impl<'n, 'e> OptBuilder<'n, 'e> { + pub fn new(name: &'n str) -> Self { + OptBuilder { + b: Base::new(name), + ..Default::default() + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for OptBuilder<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + OptBuilder { + b: Base::from(a), + s: Switched::from(a), + v: Valued::from(a), + } + } +} + +impl<'n, 'e> From> for OptBuilder<'n, 'e> { + fn from(mut a: Arg<'n, 'e>) -> Self { + a.v.fill_in(); + OptBuilder { + b: mem::replace(&mut a.b, Base::default()), + s: mem::replace(&mut a.s, Switched::default()), + v: mem::replace(&mut a.v, Valued::default()), + } + } +} + +impl<'n, 'e> Display for OptBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + debugln!("OptBuilder::fmt:{}", self.b.name); + let sep = if self.b.is_set(ArgSettings::RequireEquals) { + "=" + } else { + " " + }; + // Write the name such --long or -l + if let Some(l) = self.s.long { + write!(f, "--{}{}", l, sep)?; + } else { + write!(f, "-{}{}", self.s.short.unwrap(), sep)?; + } + let delim = if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }; + + // Write the values such as + if let Some(ref vec) = self.v.val_names { + let mut it = vec.iter().peekable(); + while let Some((_, val)) = it.next() { + write!(f, "<{}>", val)?; + if it.peek().is_some() { + write!(f, "{}", delim)?; + } + } + let num = vec.len(); + if self.is_set(ArgSettings::Multiple) && num == 1 { + write!(f, "...")?; + } + } else if let Some(num) = self.v.num_vals { + let mut it = (0..num).peekable(); + while let Some(_) = it.next() { + write!(f, "<{}>", self.b.name)?; + if it.peek().is_some() { + write!(f, "{}", delim)?; + } + } + if self.is_set(ArgSettings::Multiple) && num == 1 { + write!(f, "...")?; + } + } else { + write!( + f, + "<{}>{}", + self.b.name, + if self.is_set(ArgSettings::Multiple) { + "..." + } else { + "" + } + )?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> { + fn name(&self) -> &'n str { self.b.name } + fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) } + fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) } + fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() } + fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) } + fn has_switch(&self) -> bool { true } + fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) } + fn max_vals(&self) -> Option { self.v.max_vals } + fn val_terminator(&self) -> Option<&'e str> { self.v.terminator } + fn num_vals(&self) -> Option { self.v.num_vals } + fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) } + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + self.v.validator.as_ref() + } + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + self.v.validator_os.as_ref() + } + fn min_vals(&self) -> Option { self.v.min_vals } + fn short(&self) -> Option { self.s.short } + fn long(&self) -> Option<&'e str> { self.s.long } + fn val_delim(&self) -> Option { self.v.val_delim } + fn takes_value(&self) -> bool { true } + fn help(&self) -> Option<&'e str> { self.b.help } + fn long_help(&self) -> Option<&'e str> { self.b.long_help } + fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) + } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + self.v + .env + .as_ref() + .map(|&(key, ref value)| (key, value.as_ref())) + } + fn longest_filter(&self) -> bool { true } + fn aliases(&self) -> Option> { + if let Some(ref aliases) = self.s.aliases { + let vis_aliases: Vec<_> = aliases + .iter() + .filter_map(|&(n, v)| if v { Some(n) } else { None }) + .collect(); + if vis_aliases.is_empty() { + None + } else { + Some(vis_aliases) + } + } else { + None + } + } +} + +impl<'n, 'e> DispOrder for OptBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { self.s.disp_ord } +} + +impl<'n, 'e> PartialEq for OptBuilder<'n, 'e> { + fn eq(&self, other: &OptBuilder<'n, 'e>) -> bool { self.b == other.b } +} + +#[cfg(test)] +mod test { + use args::settings::ArgSettings; + use super::OptBuilder; + use map::VecMap; + + #[test] + fn optbuilder_display1() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", o), "--option ..."); + } + + #[test] + fn optbuilder_display2() { + let mut v_names = VecMap::new(); + v_names.insert(0, "file"); + v_names.insert(1, "name"); + + let mut o2 = OptBuilder::new("opt"); + o2.s.short = Some('o'); + o2.v.val_names = Some(v_names); + + assert_eq!(&*format!("{}", o2), "-o "); + } + + #[test] + fn optbuilder_display3() { + let mut v_names = VecMap::new(); + v_names.insert(0, "file"); + v_names.insert(1, "name"); + + let mut o2 = OptBuilder::new("opt"); + o2.s.short = Some('o'); + o2.v.val_names = Some(v_names); + o2.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", o2), "-o "); + } + + #[test] + fn optbuilder_display_single_alias() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.s.aliases = Some(vec![("als", true)]); + + assert_eq!(&*format!("{}", o), "--option "); + } + + #[test] + fn optbuilder_display_multiple_aliases() { + let mut o = OptBuilder::new("opt"); + o.s.long = Some("option"); + o.s.aliases = Some(vec![ + ("als_not_visible", false), + ("als2", true), + ("als3", true), + ("als4", true), + ]); + assert_eq!(&*format!("{}", o), "--option "); + } +} diff --git a/clap/src/args/arg_builder/positional.rs b/clap/src/args/arg_builder/positional.rs new file mode 100644 index 000000000..43fdca4c5 --- /dev/null +++ b/clap/src/args/arg_builder/positional.rs @@ -0,0 +1,229 @@ +// Std +use std::borrow::Cow; +use std::fmt::{Display, Formatter, Result}; +use std::rc::Rc; +use std::result::Result as StdResult; +use std::ffi::{OsStr, OsString}; +use std::mem; + +// Internal +use Arg; +use args::{AnyArg, ArgSettings, Base, DispOrder, Valued}; +use INTERNAL_ERROR_MSG; +use map::{self, VecMap}; + +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[derive(Clone, Default)] +pub struct PosBuilder<'n, 'e> +where + 'n: 'e, +{ + pub b: Base<'n, 'e>, + pub v: Valued<'n, 'e>, + pub index: u64, +} + +impl<'n, 'e> PosBuilder<'n, 'e> { + pub fn new(name: &'n str, idx: u64) -> Self { + PosBuilder { + b: Base::new(name), + index: idx, + ..Default::default() + } + } + + pub fn from_arg_ref(a: &Arg<'n, 'e>, idx: u64) -> Self { + let mut pb = PosBuilder { + b: Base::from(a), + v: Valued::from(a), + index: idx, + }; + if a.v.max_vals.is_some() || a.v.min_vals.is_some() + || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) + { + pb.b.settings.set(ArgSettings::Multiple); + } + pb + } + + pub fn from_arg(mut a: Arg<'n, 'e>, idx: u64) -> Self { + if a.v.max_vals.is_some() || a.v.min_vals.is_some() + || (a.v.num_vals.is_some() && a.v.num_vals.unwrap() > 1) + { + a.b.settings.set(ArgSettings::Multiple); + } + PosBuilder { + b: mem::replace(&mut a.b, Base::default()), + v: mem::replace(&mut a.v, Valued::default()), + index: idx, + } + } + + pub fn multiple_str(&self) -> &str { + let mult_vals = self.v + .val_names + .as_ref() + .map_or(true, |names| names.len() < 2); + if self.is_set(ArgSettings::Multiple) && mult_vals { + "..." + } else { + "" + } + } + + pub fn name_no_brackets(&self) -> Cow { + debugln!("PosBuilder::name_no_brackets;"); + let mut delim = String::new(); + delim.push(if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }); + if let Some(ref names) = self.v.val_names { + debugln!("PosBuilder:name_no_brackets: val_names={:#?}", names); + if names.len() > 1 { + Cow::Owned( + names + .values() + .map(|n| format!("<{}>", n)) + .collect::>() + .join(&*delim), + ) + } else { + Cow::Borrowed(names.values().next().expect(INTERNAL_ERROR_MSG)) + } + } else { + debugln!("PosBuilder:name_no_brackets: just name"); + Cow::Borrowed(self.b.name) + } + } +} + +impl<'n, 'e> Display for PosBuilder<'n, 'e> { + fn fmt(&self, f: &mut Formatter) -> Result { + let mut delim = String::new(); + delim.push(if self.is_set(ArgSettings::RequireDelimiter) { + self.v.val_delim.expect(INTERNAL_ERROR_MSG) + } else { + ' ' + }); + if let Some(ref names) = self.v.val_names { + write!( + f, + "{}", + names + .values() + .map(|n| format!("<{}>", n)) + .collect::>() + .join(&*delim) + )?; + } else { + write!(f, "<{}>", self.b.name)?; + } + if self.b.settings.is_set(ArgSettings::Multiple) + && (self.v.val_names.is_none() || self.v.val_names.as_ref().unwrap().len() == 1) + { + write!(f, "...")?; + } + + Ok(()) + } +} + +impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> { + fn name(&self) -> &'n str { self.b.name } + fn overrides(&self) -> Option<&[&'e str]> { self.b.overrides.as_ref().map(|o| &o[..]) } + fn requires(&self) -> Option<&[(Option<&'e str>, &'n str)]> { + self.b.requires.as_ref().map(|o| &o[..]) + } + fn blacklist(&self) -> Option<&[&'e str]> { self.b.blacklist.as_ref().map(|o| &o[..]) } + fn required_unless(&self) -> Option<&[&'e str]> { self.b.r_unless.as_ref().map(|o| &o[..]) } + fn val_names(&self) -> Option<&VecMap<&'e str>> { self.v.val_names.as_ref() } + fn is_set(&self, s: ArgSettings) -> bool { self.b.settings.is_set(s) } + fn set(&mut self, s: ArgSettings) { self.b.settings.set(s) } + fn has_switch(&self) -> bool { false } + fn max_vals(&self) -> Option { self.v.max_vals } + fn val_terminator(&self) -> Option<&'e str> { self.v.terminator } + fn num_vals(&self) -> Option { self.v.num_vals } + fn possible_vals(&self) -> Option<&[&'e str]> { self.v.possible_vals.as_ref().map(|o| &o[..]) } + fn validator(&self) -> Option<&Rc StdResult<(), String>>> { + self.v.validator.as_ref() + } + fn validator_os(&self) -> Option<&Rc StdResult<(), OsString>>> { + self.v.validator_os.as_ref() + } + fn min_vals(&self) -> Option { self.v.min_vals } + fn short(&self) -> Option { None } + fn long(&self) -> Option<&'e str> { None } + fn val_delim(&self) -> Option { self.v.val_delim } + fn takes_value(&self) -> bool { true } + fn help(&self) -> Option<&'e str> { self.b.help } + fn long_help(&self) -> Option<&'e str> { self.b.long_help } + fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { + self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) + } + fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val } + fn env<'s>(&'s self) -> Option<(&'n OsStr, Option<&'s OsString>)> { + self.v + .env + .as_ref() + .map(|&(key, ref value)| (key, value.as_ref())) + } + fn longest_filter(&self) -> bool { true } + fn aliases(&self) -> Option> { None } +} + +impl<'n, 'e> DispOrder for PosBuilder<'n, 'e> { + fn disp_ord(&self) -> usize { self.index as usize } +} + +impl<'n, 'e> PartialEq for PosBuilder<'n, 'e> { + fn eq(&self, other: &PosBuilder<'n, 'e>) -> bool { self.b == other.b } +} + +#[cfg(test)] +mod test { + use args::settings::ArgSettings; + use super::PosBuilder; + use map::VecMap; + + #[test] + fn display_mult() { + let mut p = PosBuilder::new("pos", 1); + p.b.settings.set(ArgSettings::Multiple); + + assert_eq!(&*format!("{}", p), "..."); + } + + #[test] + fn display_required() { + let mut p2 = PosBuilder::new("pos", 1); + p2.b.settings.set(ArgSettings::Required); + + assert_eq!(&*format!("{}", p2), ""); + } + + #[test] + fn display_val_names() { + let mut p2 = PosBuilder::new("pos", 1); + let mut vm = VecMap::new(); + vm.insert(0, "file1"); + vm.insert(1, "file2"); + p2.v.val_names = Some(vm); + + assert_eq!(&*format!("{}", p2), " "); + } + + #[test] + fn display_val_names_req() { + let mut p2 = PosBuilder::new("pos", 1); + p2.b.settings.set(ArgSettings::Required); + let mut vm = VecMap::new(); + vm.insert(0, "file1"); + vm.insert(1, "file2"); + p2.v.val_names = Some(vm); + + assert_eq!(&*format!("{}", p2), " "); + } +} diff --git a/clap/src/args/arg_builder/switched.rs b/clap/src/args/arg_builder/switched.rs new file mode 100644 index 000000000..224b2f2b2 --- /dev/null +++ b/clap/src/args/arg_builder/switched.rs @@ -0,0 +1,38 @@ +use Arg; + +#[derive(Debug)] +pub struct Switched<'b> { + pub short: Option, + pub long: Option<&'b str>, + pub aliases: Option>, // (name, visible) + pub disp_ord: usize, + pub unified_ord: usize, +} + +impl<'e> Default for Switched<'e> { + fn default() -> Self { + Switched { + short: None, + long: None, + aliases: None, + disp_ord: 999, + unified_ord: 999, + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Switched<'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { a.s.clone() } +} + +impl<'e> Clone for Switched<'e> { + fn clone(&self) -> Self { + Switched { + short: self.short, + long: self.long, + aliases: self.aliases.clone(), + disp_ord: self.disp_ord, + unified_ord: self.unified_ord, + } + } +} diff --git a/clap/src/args/arg_builder/valued.rs b/clap/src/args/arg_builder/valued.rs new file mode 100644 index 000000000..d70854dc8 --- /dev/null +++ b/clap/src/args/arg_builder/valued.rs @@ -0,0 +1,67 @@ +use std::rc::Rc; +use std::ffi::{OsStr, OsString}; + +use map::VecMap; + +use Arg; + +#[allow(missing_debug_implementations)] +#[derive(Clone)] +pub struct Valued<'a, 'b> +where + 'a: 'b, +{ + pub possible_vals: Option>, + pub val_names: Option>, + pub num_vals: Option, + pub max_vals: Option, + pub min_vals: Option, + pub validator: Option Result<(), String>>>, + pub validator_os: Option Result<(), OsString>>>, + pub val_delim: Option, + pub default_val: Option<&'b OsStr>, + pub default_vals_ifs: Option, &'b OsStr)>>, + pub env: Option<(&'a OsStr, Option)>, + pub terminator: Option<&'b str>, +} + +impl<'n, 'e> Default for Valued<'n, 'e> { + fn default() -> Self { + Valued { + possible_vals: None, + num_vals: None, + min_vals: None, + max_vals: None, + val_names: None, + validator: None, + validator_os: None, + val_delim: None, + default_val: None, + default_vals_ifs: None, + env: None, + terminator: None, + } + } +} + +impl<'n, 'e> Valued<'n, 'e> { + pub fn fill_in(&mut self) { + if let Some(ref vec) = self.val_names { + if vec.len() > 1 { + self.num_vals = Some(vec.len() as u64); + } + } + } +} + +impl<'n, 'e, 'z> From<&'z Arg<'n, 'e>> for Valued<'n, 'e> { + fn from(a: &'z Arg<'n, 'e>) -> Self { + let mut v = a.v.clone(); + if let Some(ref vec) = a.v.val_names { + if vec.len() > 1 { + v.num_vals = Some(vec.len() as u64); + } + } + v + } +} diff --git a/clap/src/args/arg_matcher.rs b/clap/src/args/arg_matcher.rs new file mode 100644 index 000000000..e1d8067e6 --- /dev/null +++ b/clap/src/args/arg_matcher.rs @@ -0,0 +1,218 @@ +// Std +use std::collections::hash_map::{Entry, Iter}; +use std::collections::HashMap; +use std::ffi::OsStr; +use std::ops::Deref; +use std::mem; + +// Internal +use args::{ArgMatches, MatchedArg, SubCommand}; +use args::AnyArg; +use args::settings::ArgSettings; + +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub struct ArgMatcher<'a>(pub ArgMatches<'a>); + +impl<'a> Default for ArgMatcher<'a> { + fn default() -> Self { ArgMatcher(ArgMatches::default()) } +} + +impl<'a> ArgMatcher<'a> { + pub fn new() -> Self { ArgMatcher::default() } + + pub fn process_arg_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>, overrides: &mut Vec<(&'b str, &'a str)>, required: &mut Vec<&'a str>, check_all: bool) { + debugln!("ArgMatcher::process_arg_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); + if let Some(aa) = a { + let mut self_done = false; + if let Some(a_overrides) = aa.overrides() { + for overr in a_overrides { + debugln!("ArgMatcher::process_arg_overrides:iter:{};", overr); + if overr == &aa.name() { + self_done = true; + self.handle_self_overrides(a); + } else if self.is_present(overr) { + debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing from matches;", overr); + self.remove(overr); + for i in (0 .. required.len()).rev() { + if &required[i] == overr { + debugln!("ArgMatcher::process_arg_overrides:iter:{}: removing required;", overr); + required.swap_remove(i); + break; + } + } + overrides.push((overr, aa.name())); + } else { + overrides.push((overr, aa.name())); + } + } + } + if check_all && !self_done { + self.handle_self_overrides(a); + } + } + } + + pub fn handle_self_overrides<'b>(&mut self, a: Option<&AnyArg<'a, 'b>>) { + debugln!("ArgMatcher::handle_self_overrides:{:?};", a.map_or(None, |a| Some(a.name()))); + if let Some(aa) = a { + if !aa.has_switch() || aa.is_set(ArgSettings::Multiple) { + // positional args can't override self or else we would never advance to the next + + // Also flags with --multiple set are ignored otherwise we could never have more + // than one + return; + } + if let Some(ma) = self.get_mut(aa.name()) { + if ma.vals.len() > 1 { + // swap_remove(0) would be O(1) but does not preserve order, which + // we need + ma.vals.remove(0); + ma.occurs = 1; + } else if !aa.takes_value() && ma.occurs > 1 { + ma.occurs = 1; + } + } + } + } + + pub fn is_present(&self, name: &str) -> bool { + self.0.is_present(name) + } + + pub fn propagate_globals(&mut self, global_arg_vec: &[&'a str]) { + debugln!( "ArgMatcher::get_global_values: global_arg_vec={:?}", global_arg_vec ); + let mut vals_map = HashMap::new(); + self.fill_in_global_values(global_arg_vec, &mut vals_map); + } + + fn fill_in_global_values( + &mut self, + global_arg_vec: &[&'a str], + vals_map: &mut HashMap<&'a str, MatchedArg>, + ) { + for global_arg in global_arg_vec { + if let Some(ma) = self.get(global_arg) { + // We have to check if the parent's global arg wasn't used but still exists + // such as from a default value. + // + // For example, `myprog subcommand --global-arg=value` where --global-arg defines + // a default value of `other` myprog would have an existing MatchedArg for + // --global-arg where the value is `other`, however the occurs will be 0. + let to_update = if let Some(parent_ma) = vals_map.get(global_arg) { + if parent_ma.occurs > 0 && ma.occurs == 0 { + parent_ma.clone() + } else { + ma.clone() + } + } else { + ma.clone() + }; + vals_map.insert(global_arg, to_update); + } + } + if let Some(ref mut sc) = self.0.subcommand { + let mut am = ArgMatcher(mem::replace(&mut sc.matches, ArgMatches::new())); + am.fill_in_global_values(global_arg_vec, vals_map); + mem::swap(&mut am.0, &mut sc.matches); + } + + for (name, matched_arg) in vals_map.into_iter() { + self.0.args.insert(name, matched_arg.clone()); + } + } + + pub fn get_mut(&mut self, arg: &str) -> Option<&mut MatchedArg> { self.0.args.get_mut(arg) } + + pub fn get(&self, arg: &str) -> Option<&MatchedArg> { self.0.args.get(arg) } + + pub fn remove(&mut self, arg: &str) { self.0.args.remove(arg); } + + pub fn remove_all(&mut self, args: &[&str]) { + for &arg in args { + self.0.args.remove(arg); + } + } + + pub fn insert(&mut self, name: &'a str) { self.0.args.insert(name, MatchedArg::new()); } + + pub fn contains(&self, arg: &str) -> bool { self.0.args.contains_key(arg) } + + pub fn is_empty(&self) -> bool { self.0.args.is_empty() } + + pub fn usage(&mut self, usage: String) { self.0.usage = Some(usage); } + + pub fn arg_names(&'a self) -> Vec<&'a str> { self.0.args.keys().map(Deref::deref).collect() } + + pub fn entry(&mut self, arg: &'a str) -> Entry<&'a str, MatchedArg> { self.0.args.entry(arg) } + + pub fn subcommand(&mut self, sc: SubCommand<'a>) { self.0.subcommand = Some(Box::new(sc)); } + + pub fn subcommand_name(&self) -> Option<&str> { self.0.subcommand_name() } + + pub fn iter(&self) -> Iter<&str, MatchedArg> { self.0.args.iter() } + + pub fn inc_occurrence_of(&mut self, arg: &'a str) { + debugln!("ArgMatcher::inc_occurrence_of: arg={}", arg); + if let Some(a) = self.get_mut(arg) { + a.occurs += 1; + return; + } + debugln!("ArgMatcher::inc_occurrence_of: first instance"); + self.insert(arg); + } + + pub fn inc_occurrences_of(&mut self, args: &[&'a str]) { + debugln!("ArgMatcher::inc_occurrences_of: args={:?}", args); + for arg in args { + self.inc_occurrence_of(arg); + } + } + + pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) { + let ma = self.entry(arg).or_insert(MatchedArg { + occurs: 0, + indices: Vec::with_capacity(1), + vals: Vec::with_capacity(1), + }); + ma.vals.push(val.to_owned()); + } + + pub fn add_index_to(&mut self, arg: &'a str, idx: usize) { + let ma = self.entry(arg).or_insert(MatchedArg { + occurs: 0, + indices: Vec::with_capacity(1), + vals: Vec::new(), + }); + ma.indices.push(idx); + } + + pub fn needs_more_vals<'b, A>(&self, o: &A) -> bool + where + A: AnyArg<'a, 'b>, + { + debugln!("ArgMatcher::needs_more_vals: o={}", o.name()); + if let Some(ma) = self.get(o.name()) { + if let Some(num) = o.num_vals() { + debugln!("ArgMatcher::needs_more_vals: num_vals...{}", num); + return if o.is_set(ArgSettings::Multiple) { + ((ma.vals.len() as u64) % num) != 0 + } else { + num != (ma.vals.len() as u64) + }; + } else if let Some(num) = o.max_vals() { + debugln!("ArgMatcher::needs_more_vals: max_vals...{}", num); + return !((ma.vals.len() as u64) > num); + } else if o.min_vals().is_some() { + debugln!("ArgMatcher::needs_more_vals: min_vals...true"); + return true; + } + return o.is_set(ArgSettings::Multiple); + } + true + } +} + +impl<'a> Into> for ArgMatcher<'a> { + fn into(self) -> ArgMatches<'a> { self.0 } +} diff --git a/clap/src/args/arg_matches.rs b/clap/src/args/arg_matches.rs new file mode 100644 index 000000000..6cf70a49a --- /dev/null +++ b/clap/src/args/arg_matches.rs @@ -0,0 +1,963 @@ +// Std +use std::borrow::Cow; +use std::collections::HashMap; +use std::ffi::{OsStr, OsString}; +use std::iter::Map; +use std::slice::Iter; + +// Internal +use INVALID_UTF8; +use args::MatchedArg; +use args::SubCommand; + +/// Used to get information about the arguments that where supplied to the program at runtime by +/// the user. New instances of this struct are obtained by using the [`App::get_matches`] family of +/// methods. +/// +/// # Examples +/// +/// ```no_run +/// # use clap::{App, Arg}; +/// let matches = App::new("MyApp") +/// .arg(Arg::with_name("out") +/// .long("output") +/// .required(true) +/// .takes_value(true)) +/// .arg(Arg::with_name("debug") +/// .short("d") +/// .multiple(true)) +/// .arg(Arg::with_name("cfg") +/// .short("c") +/// .takes_value(true)) +/// .get_matches(); // builds the instance of ArgMatches +/// +/// // to get information about the "cfg" argument we created, such as the value supplied we use +/// // various ArgMatches methods, such as ArgMatches::value_of +/// if let Some(c) = matches.value_of("cfg") { +/// println!("Value for -c: {}", c); +/// } +/// +/// // The ArgMatches::value_of method returns an Option because the user may not have supplied +/// // that argument at runtime. But if we specified that the argument was "required" as we did +/// // with the "out" argument, we can safely unwrap because `clap` verifies that was actually +/// // used at runtime. +/// println!("Value for --output: {}", matches.value_of("out").unwrap()); +/// +/// // You can check the presence of an argument +/// if matches.is_present("out") { +/// // Another way to check if an argument was present, or if it occurred multiple times is to +/// // use occurrences_of() which returns 0 if an argument isn't found at runtime, or the +/// // number of times that it occurred, if it was. To allow an argument to appear more than +/// // once, you must use the .multiple(true) method, otherwise it will only return 1 or 0. +/// if matches.occurrences_of("debug") > 2 { +/// println!("Debug mode is REALLY on, don't be crazy"); +/// } else { +/// println!("Debug mode kind of on"); +/// } +/// } +/// ``` +/// [`App::get_matches`]: ./struct.App.html#method.get_matches +#[derive(Debug, Clone)] +pub struct ArgMatches<'a> { + #[doc(hidden)] pub args: HashMap<&'a str, MatchedArg>, + #[doc(hidden)] pub subcommand: Option>>, + #[doc(hidden)] pub usage: Option, +} + +impl<'a> Default for ArgMatches<'a> { + fn default() -> Self { + ArgMatches { + args: HashMap::new(), + subcommand: None, + usage: None, + } + } +} + +impl<'a> ArgMatches<'a> { + #[doc(hidden)] + pub fn new() -> Self { + ArgMatches { + ..Default::default() + } + } + + /// Gets the value of a specific [option] or [positional] argument (i.e. an argument that takes + /// an additional value at runtime). If the option wasn't present at runtime + /// it returns `None`. + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`ArgMatches::values_of`] as `ArgMatches::value_of` will only return the *first* + /// value. + /// + /// # Panics + /// + /// This method will [`panic!`] if the value contains invalid UTF-8 code points. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("output") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "something"]); + /// + /// assert_eq!(m.value_of("output"), Some("something")); + /// ``` + /// [option]: ./struct.Arg.html#method.takes_value + /// [positional]: ./struct.Arg.html#method.index + /// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of + /// [`panic!`]: https://doc.rust-lang.org/std/macro.panic!.html + pub fn value_of>(&self, name: S) -> Option<&str> { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(v) = arg.vals.get(0) { + return Some(v.to_str().expect(INVALID_UTF8)); + } + } + None + } + + /// Gets the lossy value of a specific argument. If the argument wasn't present at runtime + /// it returns `None`. A lossy value is one which contains invalid UTF-8 code points, those + /// invalid points will be replaced with `\u{FFFD}` + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`Arg::values_of_lossy`] as `value_of_lossy()` will only return the *first* value. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage(" 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi {0xe9}!" + /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); + /// assert_eq!(&*m.value_of_lossy("arg").unwrap(), "Hi \u{FFFD}!"); + /// ``` + /// [`Arg::values_of_lossy`]: ./struct.ArgMatches.html#method.values_of_lossy + pub fn value_of_lossy>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(v) = arg.vals.get(0) { + return Some(v.to_string_lossy()); + } + } + None + } + + /// Gets the OS version of a string value of a specific argument. If the option wasn't present + /// at runtime it returns `None`. An OS value on Unix-like systems is any series of bytes, + /// regardless of whether or not they contain valid UTF-8 code points. Since [`String`]s in + /// Rust are guaranteed to be valid UTF-8, a valid filename on a Unix system as an argument + /// value may contain invalid UTF-8 code points. + /// + /// *NOTE:* If getting a value for an option or positional argument that allows multiples, + /// prefer [`ArgMatches::values_of_os`] as `Arg::value_of_os` will only return the *first* + /// value. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage(" 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi {0xe9}!" + /// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); + /// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); + /// ``` + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os + pub fn value_of_os>(&self, name: S) -> Option<&OsStr> { + self.args + .get(name.as_ref()) + .and_then(|arg| arg.vals.get(0).map(|v| v.as_os_str())) + } + + /// Gets a [`Values`] struct which implements [`Iterator`] for values of a specific argument + /// (i.e. an argument that takes multiple values at runtime). If the option wasn't present at + /// runtime it returns `None` + /// + /// # Panics + /// + /// This method will panic if any of the values contain invalid UTF-8 code points. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("output") + /// .multiple(true) + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec![ + /// "myprog", "-o", "val1", "val2", "val3" + /// ]); + /// let vals: Vec<&str> = m.values_of("output").unwrap().collect(); + /// assert_eq!(vals, ["val1", "val2", "val3"]); + /// ``` + /// [`Values`]: ./struct.Values.html + /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html + pub fn values_of>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + fn to_str_slice(o: &OsString) -> &str { o.to_str().expect(INVALID_UTF8) } + let to_str_slice: fn(&OsString) -> &str = to_str_slice; // coerce to fn pointer + return Some(Values { + iter: arg.vals.iter().map(to_str_slice), + }); + } + None + } + + /// Gets the lossy values of a specific argument. If the option wasn't present at runtime + /// it returns `None`. A lossy value is one where if it contains invalid UTF-8 code points, + /// those invalid points will be replaced with `\u{FFFD}` + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::OsString; + /// use std::os::unix::ffi::OsStringExt; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage("... 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi" + /// OsString::from_vec(vec![b'H', b'i']), + /// // "{0xe9}!" + /// OsString::from_vec(vec![0xe9, b'!'])]); + /// let mut itr = m.values_of_lossy("arg").unwrap().into_iter(); + /// assert_eq!(&itr.next().unwrap()[..], "Hi"); + /// assert_eq!(&itr.next().unwrap()[..], "\u{FFFD}!"); + /// assert_eq!(itr.next(), None); + /// ``` + pub fn values_of_lossy>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + return Some( + arg.vals + .iter() + .map(|v| v.to_string_lossy().into_owned()) + .collect(), + ); + } + None + } + + /// Gets a [`OsValues`] struct which is implements [`Iterator`] for [`OsString`] values of a + /// specific argument. If the option wasn't present at runtime it returns `None`. An OS value + /// on Unix-like systems is any series of bytes, regardless of whether or not they contain + /// valid UTF-8 code points. Since [`String`]s in Rust are guaranteed to be valid UTF-8, a valid + /// filename as an argument value on Linux (for example) may contain invalid UTF-8 code points. + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg}; + /// use std::ffi::{OsStr,OsString}; + /// use std::os::unix::ffi::{OsStrExt,OsStringExt}; + /// + /// let m = App::new("utf8") + /// .arg(Arg::from_usage("... 'some arg'")) + /// .get_matches_from(vec![OsString::from("myprog"), + /// // "Hi" + /// OsString::from_vec(vec![b'H', b'i']), + /// // "{0xe9}!" + /// OsString::from_vec(vec![0xe9, b'!'])]); + /// + /// let mut itr = m.values_of_os("arg").unwrap().into_iter(); + /// assert_eq!(itr.next(), Some(OsStr::new("Hi"))); + /// assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!']))); + /// assert_eq!(itr.next(), None); + /// ``` + /// [`OsValues`]: ./struct.OsValues.html + /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html + /// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + pub fn values_of_os>(&'a self, name: S) -> Option> { + fn to_str_slice(o: &OsString) -> &OsStr { &*o } + let to_str_slice: fn(&'a OsString) -> &'a OsStr = to_str_slice; // coerce to fn pointer + if let Some(arg) = self.args.get(name.as_ref()) { + return Some(OsValues { + iter: arg.vals.iter().map(to_str_slice), + }); + } + None + } + + /// Returns `true` if an argument was present at runtime, otherwise `false`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .get_matches_from(vec![ + /// "myprog", "-d" + /// ]); + /// + /// assert!(m.is_present("debug")); + /// ``` + pub fn is_present>(&self, name: S) -> bool { + if let Some(ref sc) = self.subcommand { + if sc.name == name.as_ref() { + return true; + } + } + self.args.contains_key(name.as_ref()) + } + + /// Returns the number of times an argument was used at runtime. If an argument isn't present + /// it will return `0`. + /// + /// **NOTE:** This returns the number of times the argument was used, *not* the number of + /// values. For example, `-o val1 val2 val3 -o val4` would return `2` (2 occurrences, but 4 + /// values). + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d") + /// .multiple(true)) + /// .get_matches_from(vec![ + /// "myprog", "-d", "-d", "-d" + /// ]); + /// + /// assert_eq!(m.occurrences_of("debug"), 3); + /// ``` + /// + /// This next example shows that counts actual uses of the argument, not just `-`'s + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d") + /// .multiple(true)) + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .get_matches_from(vec![ + /// "myprog", "-ddfd" + /// ]); + /// + /// assert_eq!(m.occurrences_of("debug"), 3); + /// assert_eq!(m.occurrences_of("flag"), 1); + /// ``` + pub fn occurrences_of>(&self, name: S) -> u64 { + self.args.get(name.as_ref()).map_or(0, |a| a.occurs) + } + + /// Gets the starting index of the argument in respect to all other arguments. Indices are + /// similar to argv indices, but are not exactly 1:1. + /// + /// For flags (i.e. those arguments which don't have an associated value), indices refer + /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices + /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the + /// index for `val` would be recorded. This is by design. + /// + /// Besides the flag/option descrepancy, the primary difference between an argv index and clap + /// index, is that clap continues counting once all arguments have properly seperated, whereas + /// an argv index does not. + /// + /// The examples should clear this up. + /// + /// *NOTE:* If an argument is allowed multiple times, this method will only give the *first* + /// index. + /// + /// # Examples + /// + /// The argv indices are listed in the comments below. See how they correspond to the clap + /// indices. Note that if it's not listed in a clap index, this is becuase it's not saved in + /// in an `ArgMatches` struct for querying. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-f", "-o", "val"]); + /// // ARGV idices: ^0 ^1 ^2 ^3 + /// // clap idices: ^1 ^3 + /// + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("option"), Some(3)); + /// ``` + /// + /// Now notice, if we use one of the other styles of options: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-f", "-o=val"]); + /// // ARGV idices: ^0 ^1 ^2 + /// // clap idices: ^1 ^3 + /// + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("option"), Some(3)); + /// ``` + /// + /// Things become much more complicated, or clear if we look at a more complex combination of + /// flags. Let's also throw in the final option style for good measure. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("flag2") + /// .short("F")) + /// .arg(Arg::with_name("flag3") + /// .short("z")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true)) + /// .get_matches_from(vec!["myapp", "-fzF", "-oval"]); + /// // ARGV idices: ^0 ^1 ^2 + /// // clap idices: ^1,2,3 ^5 + /// // + /// // clap sees the above as 'myapp -f -z -F -o val' + /// // ^0 ^1 ^2 ^3 ^4 ^5 + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("flag2"), Some(3)); + /// assert_eq!(m.index_of("flag3"), Some(2)); + /// assert_eq!(m.index_of("option"), Some(5)); + /// ``` + /// + /// One final combination of flags/options to see how they combine: + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("flag2") + /// .short("F")) + /// .arg(Arg::with_name("flag3") + /// .short("z")) + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-fzFoval"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^1,2,3^5 + /// // + /// // clap sees the above as 'myapp -f -z -F -o val' + /// // ^0 ^1 ^2 ^3 ^4 ^5 + /// assert_eq!(m.index_of("flag"), Some(1)); + /// assert_eq!(m.index_of("flag2"), Some(3)); + /// assert_eq!(m.index_of("flag3"), Some(2)); + /// assert_eq!(m.index_of("option"), Some(5)); + /// ``` + /// + /// The last part to mention is when values are sent in multiple groups with a [delimiter]. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 ^3 ^4 + /// // + /// // clap sees the above as 'myapp -o val1 val2 val3' + /// // ^0 ^1 ^2 ^3 ^4 + /// assert_eq!(m.index_of("option"), Some(2)); + /// ``` + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [delimiter]: ./struct.Arg.html#method.value_delimiter + pub fn index_of>(&self, name: S) -> Option { + if let Some(arg) = self.args.get(name.as_ref()) { + if let Some(i) = arg.indices.get(0) { + return Some(*i); + } + } + None + } + + /// Gets all indices of the argument in respect to all other arguments. Indices are + /// similar to argv indices, but are not exactly 1:1. + /// + /// For flags (i.e. those arguments which don't have an associated value), indices refer + /// to occurrence of the switch, such as `-f`, or `--flag`. However, for options the indices + /// refer to the *values* `-o val` would therefore not represent two distinct indices, only the + /// index for `val` would be recorded. This is by design. + /// + /// *NOTE:* For more information about how clap indices compare to argv indices, see + /// [`ArgMatches::index_of`] + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .use_delimiter(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 ^3 ^4 + /// // + /// // clap sees the above as 'myapp -o val1 val2 val3' + /// // ^0 ^1 ^2 ^3 ^4 + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2, 3, 4]); + /// ``` + /// + /// Another quick example is when flags and options are used together + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .arg(Arg::with_name("flag") + /// .short("f") + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]); + /// // ARGV idices: ^0 ^1 ^2 ^3 ^4 ^5 ^6 + /// // clap idices: ^2 ^3 ^5 ^6 + /// + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2, 5]); + /// assert_eq!(m.indices_of("flag").unwrap().collect::>(), &[3, 6]); + /// ``` + /// + /// One final example, which is an odd case; if we *don't* use value delimiter as we did with + /// the first example above instead of `val1`, `val2` and `val3` all being distinc values, they + /// would all be a single value of `val1,val2,val3`, in which case case they'd only receive a + /// single index. + /// + /// ```rust + /// # use clap::{App, Arg}; + /// let m = App::new("myapp") + /// .arg(Arg::with_name("option") + /// .short("o") + /// .takes_value(true) + /// .multiple(true)) + /// .get_matches_from(vec!["myapp", "-o=val1,val2,val3"]); + /// // ARGV idices: ^0 ^1 + /// // clap idices: ^2 + /// // + /// // clap sees the above as 'myapp -o "val1,val2,val3"' + /// // ^0 ^1 ^2 + /// assert_eq!(m.indices_of("option").unwrap().collect::>(), &[2]); + /// ``` + /// [`ArgMatches`]: ./struct.ArgMatches.html + /// [`ArgMatches::index_of`]: ./struct.ArgMatches.html#method.index_of + /// [delimiter]: ./struct.Arg.html#method.value_delimiter + pub fn indices_of>(&'a self, name: S) -> Option> { + if let Some(arg) = self.args.get(name.as_ref()) { + fn to_usize(i: &usize) -> usize { *i } + let to_usize: fn(&usize) -> usize = to_usize; // coerce to fn pointer + return Some(Indices { + iter: arg.indices.iter().map(to_usize), + }); + } + None + } + + /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`] + /// as well. This method returns the [`ArgMatches`] for a particular subcommand or `None` if + /// the subcommand wasn't present at runtime. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("myprog") + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .subcommand(SubCommand::with_name("test") + /// .arg(Arg::with_name("opt") + /// .long("option") + /// .takes_value(true))) + /// .get_matches_from(vec![ + /// "myprog", "-d", "test", "--option", "val" + /// ]); + /// + /// // Both parent commands, and child subcommands can have arguments present at the same times + /// assert!(app_m.is_present("debug")); + /// + /// // Get the subcommand's ArgMatches instance + /// if let Some(sub_m) = app_m.subcommand_matches("test") { + /// // Use the struct like normal + /// assert_eq!(sub_m.value_of("opt"), Some("val")); + /// } + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + pub fn subcommand_matches>(&self, name: S) -> Option<&ArgMatches<'a>> { + if let Some(ref s) = self.subcommand { + if s.name == name.as_ref() { + return Some(&s.matches); + } + } + None + } + + /// Because [`Subcommand`]s are essentially "sub-[`App`]s" they have their own [`ArgMatches`] + /// as well.But simply getting the sub-[`ArgMatches`] doesn't help much if we don't also know + /// which subcommand was actually used. This method returns the name of the subcommand that was + /// used at runtime, or `None` if one wasn't. + /// + /// *NOTE*: Subcommands form a hierarchy, where multiple subcommands can be used at runtime, + /// but only a single subcommand from any group of sibling commands may used at once. + /// + /// An ASCII art depiction may help explain this better...Using a fictional version of `git` as + /// the demo subject. Imagine the following are all subcommands of `git` (note, the author is + /// aware these aren't actually all subcommands in the real `git` interface, but it makes + /// explanation easier) + /// + /// ```notrust + /// Top Level App (git) TOP + /// | + /// ----------------------------------------- + /// / | \ \ + /// clone push add commit LEVEL 1 + /// | / \ / \ | + /// url origin remote ref name message LEVEL 2 + /// / /\ + /// path remote local LEVEL 3 + /// ``` + /// + /// Given the above fictional subcommand hierarchy, valid runtime uses would be (not an all + /// inclusive list, and not including argument options per command for brevity and clarity): + /// + /// ```sh + /// $ git clone url + /// $ git push origin path + /// $ git add ref local + /// $ git commit message + /// ``` + /// + /// Notice only one command per "level" may be used. You could not, for example, do `$ git + /// clone url push origin path` + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("git") + /// .subcommand(SubCommand::with_name("clone")) + /// .subcommand(SubCommand::with_name("push")) + /// .subcommand(SubCommand::with_name("commit")) + /// .get_matches(); + /// + /// match app_m.subcommand_name() { + /// Some("clone") => {}, // clone was used + /// Some("push") => {}, // push was used + /// Some("commit") => {}, // commit was used + /// _ => {}, // Either no subcommand or one not tested for... + /// } + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + /// [`ArgMatches`]: ./struct.ArgMatches.html + pub fn subcommand_name(&self) -> Option<&str> { + self.subcommand.as_ref().map(|sc| &sc.name[..]) + } + + /// This brings together [`ArgMatches::subcommand_matches`] and [`ArgMatches::subcommand_name`] + /// by returning a tuple with both pieces of information. + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("git") + /// .subcommand(SubCommand::with_name("clone")) + /// .subcommand(SubCommand::with_name("push")) + /// .subcommand(SubCommand::with_name("commit")) + /// .get_matches(); + /// + /// match app_m.subcommand() { + /// ("clone", Some(sub_m)) => {}, // clone was used + /// ("push", Some(sub_m)) => {}, // push was used + /// ("commit", Some(sub_m)) => {}, // commit was used + /// _ => {}, // Either no subcommand or one not tested for... + /// } + /// ``` + /// + /// Another useful scenario is when you want to support third party, or external, subcommands. + /// In these cases you can't know the subcommand name ahead of time, so use a variable instead + /// with pattern matching! + /// + /// ```rust + /// # use clap::{App, AppSettings}; + /// // Assume there is an external subcommand named "subcmd" + /// let app_m = App::new("myprog") + /// .setting(AppSettings::AllowExternalSubcommands) + /// .get_matches_from(vec![ + /// "myprog", "subcmd", "--option", "value", "-fff", "--flag" + /// ]); + /// + /// // All trailing arguments will be stored under the subcommand's sub-matches using an empty + /// // string argument name + /// match app_m.subcommand() { + /// (external, Some(sub_m)) => { + /// let ext_args: Vec<&str> = sub_m.values_of("").unwrap().collect(); + /// assert_eq!(external, "subcmd"); + /// assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]); + /// }, + /// _ => {}, + /// } + /// ``` + /// [`ArgMatches::subcommand_matches`]: ./struct.ArgMatches.html#method.subcommand_matches + /// [`ArgMatches::subcommand_name`]: ./struct.ArgMatches.html#method.subcommand_name + pub fn subcommand(&self) -> (&str, Option<&ArgMatches<'a>>) { + self.subcommand + .as_ref() + .map_or(("", None), |sc| (&sc.name[..], Some(&sc.matches))) + } + + /// Returns a string slice of the usage statement for the [`App`] or [`SubCommand`] + /// + /// # Examples + /// + /// ```no_run + /// # use clap::{App, Arg, SubCommand}; + /// let app_m = App::new("myprog") + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches(); + /// + /// println!("{}", app_m.usage()); + /// ``` + /// [`Subcommand`]: ./struct.SubCommand.html + /// [`App`]: ./struct.App.html + pub fn usage(&self) -> &str { self.usage.as_ref().map_or("", |u| &u[..]) } +} + + +// The following were taken and adapated from vec_map source +// repo: https://github.com/contain-rs/vec-map +// commit: be5e1fa3c26e351761b33010ddbdaf5f05dbcc33 +// license: MIT - Copyright (c) 2015 The Rust Project Developers + +/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of`] +/// method. +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg}; +/// let m = App::new("myapp") +/// .arg(Arg::with_name("output") +/// .short("o") +/// .multiple(true) +/// .takes_value(true)) +/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); +/// +/// let mut values = m.values_of("output").unwrap(); +/// +/// assert_eq!(values.next(), Some("val1")); +/// assert_eq!(values.next(), Some("val2")); +/// assert_eq!(values.next(), None); +/// ``` +/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of +#[derive(Debug, Clone)] +pub struct Values<'a> { + iter: Map, fn(&'a OsString) -> &'a str>, +} + +impl<'a> Iterator for Values<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl<'a> DoubleEndedIterator for Values<'a> { + fn next_back(&mut self) -> Option<&'a str> { self.iter.next_back() } +} + +impl<'a> ExactSizeIterator for Values<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for Values<'a> { + fn default() -> Self { + static EMPTY: [OsString; 0] = []; + // This is never called because the iterator is empty: + fn to_str_slice(_: &OsString) -> &str { unreachable!() }; + Values { + iter: EMPTY[..].iter().map(to_str_slice), + } + } +} + +/// An iterator for getting multiple values out of an argument via the [`ArgMatches::values_of_os`] +/// method. Usage of this iterator allows values which contain invalid UTF-8 code points unlike +/// [`Values`]. +/// +/// # Examples +/// +#[cfg_attr(not(unix), doc = " ```ignore")] +#[cfg_attr(unix, doc = " ```")] +/// # use clap::{App, Arg}; +/// use std::ffi::OsString; +/// use std::os::unix::ffi::{OsStrExt,OsStringExt}; +/// +/// let m = App::new("utf8") +/// .arg(Arg::from_usage(" 'some arg'")) +/// .get_matches_from(vec![OsString::from("myprog"), +/// // "Hi {0xe9}!" +/// OsString::from_vec(vec![b'H', b'i', b' ', 0xe9, b'!'])]); +/// assert_eq!(&*m.value_of_os("arg").unwrap().as_bytes(), [b'H', b'i', b' ', 0xe9, b'!']); +/// ``` +/// [`ArgMatches::values_of_os`]: ./struct.ArgMatches.html#method.values_of_os +/// [`Values`]: ./struct.Values.html +#[derive(Debug, Clone)] +pub struct OsValues<'a> { + iter: Map, fn(&'a OsString) -> &'a OsStr>, +} + +impl<'a> Iterator for OsValues<'a> { + type Item = &'a OsStr; + + fn next(&mut self) -> Option<&'a OsStr> { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl<'a> DoubleEndedIterator for OsValues<'a> { + fn next_back(&mut self) -> Option<&'a OsStr> { self.iter.next_back() } +} + +impl<'a> ExactSizeIterator for OsValues<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for OsValues<'a> { + fn default() -> Self { + static EMPTY: [OsString; 0] = []; + // This is never called because the iterator is empty: + fn to_str_slice(_: &OsString) -> &OsStr { unreachable!() }; + OsValues { + iter: EMPTY[..].iter().map(to_str_slice), + } + } +} + +/// An iterator for getting multiple indices out of an argument via the [`ArgMatches::indices_of`] +/// method. +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg}; +/// let m = App::new("myapp") +/// .arg(Arg::with_name("output") +/// .short("o") +/// .multiple(true) +/// .takes_value(true)) +/// .get_matches_from(vec!["myapp", "-o", "val1", "val2"]); +/// +/// let mut indices = m.indices_of("output").unwrap(); +/// +/// assert_eq!(indices.next(), Some(2)); +/// assert_eq!(indices.next(), Some(3)); +/// assert_eq!(indices.next(), None); +/// ``` +/// [`ArgMatches::indices_of`]: ./struct.ArgMatches.html#method.indices_of +#[derive(Debug, Clone)] +pub struct Indices<'a> { // would rather use '_, but: https://github.com/rust-lang/rust/issues/48469 + iter: Map, fn(&'a usize) -> usize>, +} + +impl<'a> Iterator for Indices<'a> { + type Item = usize; + + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl<'a> DoubleEndedIterator for Indices<'a> { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +impl<'a> ExactSizeIterator for Indices<'a> {} + +/// Creates an empty iterator. +impl<'a> Default for Indices<'a> { + fn default() -> Self { + static EMPTY: [usize; 0] = []; + // This is never called because the iterator is empty: + fn to_usize(_: &usize) -> usize { unreachable!() }; + Indices { + iter: EMPTY[..].iter().map(to_usize), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default_values() { + let mut values: Values = Values::default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_values_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut values = matches.values_of("").unwrap_or_default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_osvalues() { + let mut values: OsValues = OsValues::default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_osvalues_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut values = matches.values_of_os("").unwrap_or_default(); + assert_eq!(values.next(), None); + } + + #[test] + fn test_default_indices() { + let mut indices: Indices = Indices::default(); + assert_eq!(indices.next(), None); + } + + #[test] + fn test_default_indices_with_shorter_lifetime() { + let matches = ArgMatches::new(); + let mut indices = matches.indices_of("").unwrap_or_default(); + assert_eq!(indices.next(), None); + } +} diff --git a/clap/src/args/group.rs b/clap/src/args/group.rs new file mode 100644 index 000000000..f8bfb7a08 --- /dev/null +++ b/clap/src/args/group.rs @@ -0,0 +1,635 @@ +#[cfg(feature = "yaml")] +use std::collections::BTreeMap; +use std::fmt::{Debug, Formatter, Result}; + +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +/// `ArgGroup`s are a family of related [arguments] and way for you to express, "Any of these +/// arguments". By placing arguments in a logical group, you can create easier requirement and +/// exclusion rules instead of having to list each argument individually, or when you want a rule +/// to apply "any but not all" arguments. +/// +/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is +/// set, this means that at least one argument from that group must be present. If +/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present. +/// +/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for +/// another argument, meaning any of the arguments that belong to that group will cause a failure +/// if present, or must present respectively. +/// +/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be +/// present out of a given set. Imagine that you had multiple arguments, and you want one of them +/// to be required, but making all of them required isn't feasible because perhaps they conflict +/// with each other. For example, lets say that you were building an application where one could +/// set a given version number by supplying a string with an option argument, i.e. +/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number +/// and simply incrementing one of the three numbers. So you create three flags `--major`, +/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to +/// specify that *at least one* of them is used. For this, you can create a group. +/// +/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care +/// exactly which argument was actually used at runtime. +/// +/// # Examples +/// +/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of +/// the arguments from the specified group is present at runtime. +/// +/// ```rust +/// # use clap::{App, ArgGroup, ErrorKind}; +/// let result = App::new("app") +/// .args_from_usage( +/// "--set-ver [ver] 'set the version manually' +/// --major 'auto increase major' +/// --minor 'auto increase minor' +/// --patch 'auto increase patch'") +/// .group(ArgGroup::with_name("vers") +/// .args(&["set-ver", "major", "minor", "patch"]) +/// .required(true)) +/// .get_matches_from_safe(vec!["app", "--major", "--patch"]); +/// // Because we used two args in the group it's an error +/// assert!(result.is_err()); +/// let err = result.unwrap_err(); +/// assert_eq!(err.kind, ErrorKind::ArgumentConflict); +/// ``` +/// This next example shows a passing parse of the same scenario +/// +/// ```rust +/// # use clap::{App, ArgGroup}; +/// let result = App::new("app") +/// .args_from_usage( +/// "--set-ver [ver] 'set the version manually' +/// --major 'auto increase major' +/// --minor 'auto increase minor' +/// --patch 'auto increase patch'") +/// .group(ArgGroup::with_name("vers") +/// .args(&["set-ver", "major", "minor","patch"]) +/// .required(true)) +/// .get_matches_from_safe(vec!["app", "--major"]); +/// assert!(result.is_ok()); +/// let matches = result.unwrap(); +/// // We may not know which of the args was used, so we can test for the group... +/// assert!(matches.is_present("vers")); +/// // we could also alternatively check each arg individually (not shown here) +/// ``` +/// [`ArgGroup::multiple(true)`]: ./struct.ArgGroup.html#method.multiple +/// [arguments]: ./struct.Arg.html +/// [conflict]: ./struct.Arg.html#method.conflicts_with +/// [requirement]: ./struct.Arg.html#method.requires +#[derive(Default)] +pub struct ArgGroup<'a> { + #[doc(hidden)] pub name: &'a str, + #[doc(hidden)] pub args: Vec<&'a str>, + #[doc(hidden)] pub required: bool, + #[doc(hidden)] pub requires: Option>, + #[doc(hidden)] pub conflicts: Option>, + #[doc(hidden)] pub multiple: bool, +} + +impl<'a> ArgGroup<'a> { + /// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to + /// get values from the group or refer to the group inside of conflict and requirement rules. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, ArgGroup}; + /// ArgGroup::with_name("config") + /// # ; + /// ``` + pub fn with_name(n: &'a str) -> Self { + ArgGroup { + name: n, + required: false, + args: vec![], + requires: None, + conflicts: None, + multiple: false, + } + } + + /// Creates a new instance of `ArgGroup` from a .yml (YAML) file. + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::ArgGroup; + /// # fn main() { + /// let yml = load_yaml!("group.yml"); + /// let ag = ArgGroup::from_yaml(yml); + /// # } + /// ``` + #[cfg(feature = "yaml")] + pub fn from_yaml(y: &'a Yaml) -> ArgGroup<'a> { ArgGroup::from(y.as_hash().unwrap()) } + + /// Adds an [argument] to this group by name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .arg("flag") + /// .arg("color")) + /// .get_matches_from(vec!["myprog", "-f"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// // but we can also check individually if needed + /// assert!(m.is_present("flag")); + /// ``` + /// [argument]: ./struct.Arg.html + #[cfg_attr(feature = "lints", allow(should_assert_eq))] + pub fn arg(mut self, n: &'a str) -> Self { + assert!( + self.name != n, + "ArgGroup '{}' can not have same name as arg inside it", + &*self.name + ); + self.args.push(n); + self + } + + /// Adds multiple [arguments] to this group by name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"])) + /// .get_matches_from(vec!["myprog", "-f"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// // but we can also check individually if needed + /// assert!(m.is_present("flag")); + /// ``` + /// [arguments]: ./struct.Arg.html + pub fn args(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.arg(n); + } + self + } + + /// Allows more than one of the ['Arg']s in this group to be used. (Default: `false`) + /// + /// # Examples + /// + /// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the + /// group + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup}; + /// let m = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .multiple(true)) + /// .get_matches_from(vec!["myprog", "-f", "-c"]); + /// // maybe we don't know which of the two flags was used... + /// assert!(m.is_present("req_flags")); + /// ``` + /// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw + /// an error if more than one of the args in the group was used. + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"])) + /// .get_matches_from_safe(vec!["myprog", "-f", "-c"]); + /// // Because we used both args in the group it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// ['Arg']: ./struct.Arg.html + pub fn multiple(mut self, m: bool) -> Self { + self.multiple = m; + self + } + + /// Sets the group as required or not. A required group will be displayed in the usage string + /// of the application in the format ``. A required `ArgGroup` simply states + /// that one argument from this group *must* be present at runtime (unless + /// conflicting with another argument). + /// + /// **NOTE:** This setting only applies to the current [`App`] / [`SubCommand`], and not + /// globally. + /// + /// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with + /// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group. + /// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which + /// states, '*At least* one arg from this group must be used. Using multiple is OK." + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .required(true)) + /// .get_matches_from_safe(vec!["myprog"]); + /// // Because we didn't use any of the args in the group, it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [`App`]: ./struct.App.html + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`ArgGroup::multiple`]: ./struct.ArgGroup.html#method.multiple + pub fn required(mut self, r: bool) -> Self { + self.required = r; + self + } + + /// Sets the requirement rules of this group. This is not to be confused with a + /// [required group]. Requirement rules function just like [argument requirement rules], you + /// can name other arguments or groups that must be present when any one of the arguments from + /// this group is used. + /// + /// **NOTE:** The name provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .requires("debug")) + /// .get_matches_from_safe(vec!["myprog", "-c"]); + /// // because we used an arg from the group, and the group requires "-d" to be used, it's an + /// // error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required group]: ./struct.ArgGroup.html#method.required + /// [argument requirement rules]: ./struct.Arg.html#method.requires + pub fn requires(mut self, n: &'a str) -> Self { + if let Some(ref mut reqs) = self.requires { + reqs.push(n); + } else { + self.requires = Some(vec![n]); + } + self + } + + /// Sets the requirement rules of this group. This is not to be confused with a + /// [required group]. Requirement rules function just like [argument requirement rules], you + /// can name other arguments or groups that must be present when one of the arguments from this + /// group is used. + /// + /// **NOTE:** The names provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .arg(Arg::with_name("verb") + /// .short("v")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .requires_all(&["debug", "verb"])) + /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]); + /// // because we used an arg from the group, and the group requires "-d" and "-v" to be used, + /// // yet we only used "-d" it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); + /// ``` + /// [required group]: ./struct.ArgGroup.html#method.required + /// [argument requirement rules]: ./struct.Arg.html#method.requires_all + pub fn requires_all(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.requires(n); + } + self + } + + /// Sets the exclusion rules of this group. Exclusion (aka conflict) rules function just like + /// [argument exclusion rules], you can name other arguments or groups that must *not* be + /// present when one of the arguments from this group are used. + /// + /// **NOTE:** The name provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .conflicts_with("debug")) + /// .get_matches_from_safe(vec!["myprog", "-c", "-d"]); + /// // because we used an arg from the group, and the group conflicts with "-d", it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with + pub fn conflicts_with(mut self, n: &'a str) -> Self { + if let Some(ref mut confs) = self.conflicts { + confs.push(n); + } else { + self.conflicts = Some(vec![n]); + } + self + } + + /// Sets the exclusion rules of this group. Exclusion rules function just like + /// [argument exclusion rules], you can name other arguments or groups that must *not* be + /// present when one of the arguments from this group are used. + /// + /// **NOTE:** The names provided may be an argument, or group name + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ArgGroup, ErrorKind}; + /// let result = App::new("myprog") + /// .arg(Arg::with_name("flag") + /// .short("f")) + /// .arg(Arg::with_name("color") + /// .short("c")) + /// .arg(Arg::with_name("debug") + /// .short("d")) + /// .arg(Arg::with_name("verb") + /// .short("v")) + /// .group(ArgGroup::with_name("req_flags") + /// .args(&["flag", "color"]) + /// .conflicts_with_all(&["debug", "verb"])) + /// .get_matches_from_safe(vec!["myprog", "-c", "-v"]); + /// // because we used an arg from the group, and the group conflicts with either "-v" or "-d" + /// // it's an error + /// assert!(result.is_err()); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind, ErrorKind::ArgumentConflict); + /// ``` + /// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with_all + pub fn conflicts_with_all(mut self, ns: &[&'a str]) -> Self { + for n in ns { + self = self.conflicts_with(n); + } + self + } +} + +impl<'a> Debug for ArgGroup<'a> { + fn fmt(&self, f: &mut Formatter) -> Result { + write!( + f, + "{{\n\ + \tname: {:?},\n\ + \targs: {:?},\n\ + \trequired: {:?},\n\ + \trequires: {:?},\n\ + \tconflicts: {:?},\n\ + }}", + self.name, + self.args, + self.required, + self.requires, + self.conflicts + ) + } +} + +impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> { + fn from(g: &'z ArgGroup<'a>) -> Self { + ArgGroup { + name: g.name, + required: g.required, + args: g.args.clone(), + requires: g.requires.clone(), + conflicts: g.conflicts.clone(), + multiple: g.multiple, + } + } +} + +#[cfg(feature = "yaml")] +impl<'a> From<&'a BTreeMap> for ArgGroup<'a> { + fn from(b: &'a BTreeMap) -> Self { + // We WANT this to panic on error...so expect() is good. + let mut a = ArgGroup::default(); + let group_settings = if b.len() == 1 { + let name_yml = b.keys().nth(0).expect("failed to get name"); + let name_str = name_yml + .as_str() + .expect("failed to convert arg YAML name to str"); + a.name = name_str; + b.get(name_yml) + .expect("failed to get name_str") + .as_hash() + .expect("failed to convert to a hash") + } else { + b + }; + + for (k, v) in group_settings { + a = match k.as_str().unwrap() { + "required" => a.required(v.as_bool().unwrap()), + "multiple" => a.multiple(v.as_bool().unwrap()), + "args" => yaml_vec_or_str!(v, a, arg), + "arg" => { + if let Some(ys) = v.as_str() { + a = a.arg(ys); + } + a + } + "requires" => yaml_vec_or_str!(v, a, requires), + "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "name" => { + if let Some(ys) = v.as_str() { + a.name = ys; + } + a + } + s => panic!( + "Unknown ArgGroup setting '{}' in YAML file for \ + ArgGroup '{}'", + s, + a.name + ), + } + } + + a + } +} + +#[cfg(test)] +mod test { + use super::ArgGroup; + #[cfg(feature = "yaml")] + use yaml_rust::YamlLoader; + + #[test] + fn groups() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + assert_eq!(g.args, args); + assert_eq!(g.requires, Some(reqs)); + assert_eq!(g.conflicts, Some(confs)); + } + + #[test] + fn test_debug() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + let debug_str = format!( + "{{\n\ + \tname: \"test\",\n\ + \targs: {:?},\n\ + \trequired: {:?},\n\ + \trequires: {:?},\n\ + \tconflicts: {:?},\n\ + }}", + args, + true, + Some(reqs), + Some(confs) + ); + assert_eq!(&*format!("{:?}", g), &*debug_str); + } + + #[test] + fn test_from() { + let g = ArgGroup::with_name("test") + .arg("a1") + .arg("a4") + .args(&["a2", "a3"]) + .required(true) + .conflicts_with("c1") + .conflicts_with_all(&["c2", "c3"]) + .conflicts_with("c4") + .requires("r1") + .requires_all(&["r2", "r3"]) + .requires("r4"); + + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + + let g2 = ArgGroup::from(&g); + assert_eq!(g2.args, args); + assert_eq!(g2.requires, Some(reqs)); + assert_eq!(g2.conflicts, Some(confs)); + } + + #[cfg(feature = "yaml")] + #[cfg_attr(feature = "yaml", test)] + fn test_yaml() { + let g_yaml = "name: test +args: +- a1 +- a4 +- a2 +- a3 +conflicts_with: +- c1 +- c2 +- c3 +- c4 +requires: +- r1 +- r2 +- r3 +- r4"; + let yml = &YamlLoader::load_from_str(g_yaml).expect("failed to load YAML file")[0]; + let g = ArgGroup::from_yaml(yml); + let args = vec!["a1", "a4", "a2", "a3"]; + let reqs = vec!["r1", "r2", "r3", "r4"]; + let confs = vec!["c1", "c2", "c3", "c4"]; + assert_eq!(g.args, args); + assert_eq!(g.requires, Some(reqs)); + assert_eq!(g.conflicts, Some(confs)); + } +} + +impl<'a> Clone for ArgGroup<'a> { + fn clone(&self) -> Self { + ArgGroup { + name: self.name, + required: self.required, + args: self.args.clone(), + requires: self.requires.clone(), + conflicts: self.conflicts.clone(), + multiple: self.multiple, + } + } +} diff --git a/clap/src/args/macros.rs b/clap/src/args/macros.rs new file mode 100644 index 000000000..1de12f4ec --- /dev/null +++ b/clap/src/args/macros.rs @@ -0,0 +1,109 @@ +#[cfg(feature = "yaml")] +macro_rules! yaml_tuple2 { + ($a:ident, $v:ident, $c:ident) => {{ + if let Some(vec) = $v.as_vec() { + for ys in vec { + if let Some(tup) = ys.as_vec() { + debug_assert_eq!(2, tup.len()); + $a = $a.$c(yaml_str!(tup[0]), yaml_str!(tup[1])); + } else { + panic!("Failed to convert YAML value to vec"); + } + } + } else { + panic!("Failed to convert YAML value to vec"); + } + $a + } + }; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_tuple3 { + ($a:ident, $v:ident, $c:ident) => {{ + if let Some(vec) = $v.as_vec() { + for ys in vec { + if let Some(tup) = ys.as_vec() { + debug_assert_eq!(3, tup.len()); + $a = $a.$c(yaml_str!(tup[0]), yaml_opt_str!(tup[1]), yaml_str!(tup[2])); + } else { + panic!("Failed to convert YAML value to vec"); + } + } + } else { + panic!("Failed to convert YAML value to vec"); + } + $a + } + }; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_vec_or_str { + ($v:ident, $a:ident, $c:ident) => {{ + let maybe_vec = $v.as_vec(); + if let Some(vec) = maybe_vec { + for ys in vec { + if let Some(s) = ys.as_str() { + $a = $a.$c(s); + } else { + panic!("Failed to convert YAML value {:?} to a string", ys); + } + } + } else { + if let Some(s) = $v.as_str() { + $a = $a.$c(s); + } else { + panic!("Failed to convert YAML value {:?} to either a vec or string", $v); + } + } + $a + } + }; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_opt_str { + ($v:expr) => {{ + if $v.is_null() { + Some($v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))) + } else { + None + } + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_str { + ($v:expr) => {{ + $v.as_str().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_str { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c(yaml_str!($v)) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_bool { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v.as_bool().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v))) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_u64 { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as u64) + }}; +} + +#[cfg(feature = "yaml")] +macro_rules! yaml_to_usize { + ($a:ident, $v:ident, $c:ident) => {{ + $a.$c($v.as_i64().unwrap_or_else(|| panic!("failed to convert YAML {:?} value to a string", $v)) as usize) + }}; +} diff --git a/clap/src/args/matched_arg.rs b/clap/src/args/matched_arg.rs new file mode 100644 index 000000000..eeda2611c --- /dev/null +++ b/clap/src/args/matched_arg.rs @@ -0,0 +1,24 @@ +// Std +use std::ffi::OsString; + +#[doc(hidden)] +#[derive(Debug, Clone)] +pub struct MatchedArg { + #[doc(hidden)] pub occurs: u64, + #[doc(hidden)] pub indices: Vec, + #[doc(hidden)] pub vals: Vec, +} + +impl Default for MatchedArg { + fn default() -> Self { + MatchedArg { + occurs: 1, + indices: Vec::new(), + vals: Vec::new(), + } + } +} + +impl MatchedArg { + pub fn new() -> Self { MatchedArg::default() } +} diff --git a/clap/src/args/mod.rs b/clap/src/args/mod.rs new file mode 100644 index 000000000..21f9b850d --- /dev/null +++ b/clap/src/args/mod.rs @@ -0,0 +1,21 @@ +pub use self::any_arg::{AnyArg, DispOrder}; +pub use self::arg::Arg; +pub use self::arg_builder::{Base, FlagBuilder, OptBuilder, PosBuilder, Switched, Valued}; +pub use self::arg_matcher::ArgMatcher; +pub use self::arg_matches::{ArgMatches, OsValues, Values}; +pub use self::group::ArgGroup; +pub use self::matched_arg::MatchedArg; +pub use self::settings::{ArgFlags, ArgSettings}; +pub use self::subcommand::SubCommand; + +#[macro_use] +mod macros; +mod arg; +pub mod any_arg; +mod arg_matches; +mod arg_matcher; +mod subcommand; +mod arg_builder; +mod matched_arg; +mod group; +pub mod settings; diff --git a/clap/src/args/settings.rs b/clap/src/args/settings.rs new file mode 100644 index 000000000..7b0e0a26c --- /dev/null +++ b/clap/src/args/settings.rs @@ -0,0 +1,231 @@ +// Std +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::str::FromStr; + +bitflags! { + struct Flags: u32 { + const REQUIRED = 1; + const MULTIPLE = 1 << 1; + const EMPTY_VALS = 1 << 2; + const GLOBAL = 1 << 3; + const HIDDEN = 1 << 4; + const TAKES_VAL = 1 << 5; + const USE_DELIM = 1 << 6; + const NEXT_LINE_HELP = 1 << 7; + const R_UNLESS_ALL = 1 << 8; + const REQ_DELIM = 1 << 9; + const DELIM_NOT_SET = 1 << 10; + const HIDE_POS_VALS = 1 << 11; + const ALLOW_TAC_VALS = 1 << 12; + const REQUIRE_EQUALS = 1 << 13; + const LAST = 1 << 14; + const HIDE_DEFAULT_VAL = 1 << 15; + const CASE_INSENSITIVE = 1 << 16; + const HIDE_ENV_VALS = 1 << 17; + const HIDDEN_SHORT_H = 1 << 18; + const HIDDEN_LONG_H = 1 << 19; + } +} + +#[doc(hidden)] +#[derive(Debug, Clone, Copy)] +pub struct ArgFlags(Flags); + +impl ArgFlags { + pub fn new() -> Self { ArgFlags::default() } + + impl_settings!{ArgSettings, + Required => Flags::REQUIRED, + Multiple => Flags::MULTIPLE, + EmptyValues => Flags::EMPTY_VALS, + Global => Flags::GLOBAL, + Hidden => Flags::HIDDEN, + TakesValue => Flags::TAKES_VAL, + UseValueDelimiter => Flags::USE_DELIM, + NextLineHelp => Flags::NEXT_LINE_HELP, + RequiredUnlessAll => Flags::R_UNLESS_ALL, + RequireDelimiter => Flags::REQ_DELIM, + ValueDelimiterNotSet => Flags::DELIM_NOT_SET, + HidePossibleValues => Flags::HIDE_POS_VALS, + AllowLeadingHyphen => Flags::ALLOW_TAC_VALS, + RequireEquals => Flags::REQUIRE_EQUALS, + Last => Flags::LAST, + CaseInsensitive => Flags::CASE_INSENSITIVE, + HideEnvValues => Flags::HIDE_ENV_VALS, + HideDefaultValue => Flags::HIDE_DEFAULT_VAL, + HiddenShortHelp => Flags::HIDDEN_SHORT_H, + HiddenLongHelp => Flags::HIDDEN_LONG_H + } +} + +impl Default for ArgFlags { + fn default() -> Self { ArgFlags(Flags::EMPTY_VALS | Flags::DELIM_NOT_SET) } +} + +/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter +/// methods [`Arg::set`], [`Arg::unset`], and [`Arg::is_set`] +/// +/// [`Arg::set`]: ./struct.Arg.html#method.set +/// [`Arg::unset`]: ./struct.Arg.html#method.unset +/// [`Arg::is_set`]: ./struct.Arg.html#method.is_set +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum ArgSettings { + /// The argument must be used + Required, + /// The argument may be used multiple times such as `--flag --flag` + Multiple, + /// The argument allows empty values such as `--option ""` + EmptyValues, + /// The argument should be propagated down through all child [`SubCommand`]s + /// + /// [`SubCommand`]: ./struct.SubCommand.html + Global, + /// The argument should **not** be shown in help text + Hidden, + /// The argument accepts a value, such as `--option ` + TakesValue, + /// Determines if the argument allows values to be grouped via a delimiter + UseValueDelimiter, + /// Prints the help text on the line after the argument + NextLineHelp, + /// Requires the use of a value delimiter for all multiple values + RequireDelimiter, + /// Hides the possible values from the help string + HidePossibleValues, + /// Allows vals that start with a '-' + AllowLeadingHyphen, + /// Require options use `--option=val` syntax + RequireEquals, + /// Specifies that the arg is the last positional argument and may be accessed early via `--` + /// syntax + Last, + /// Hides the default value from the help string + HideDefaultValue, + /// Makes `Arg::possible_values` case insensitive + CaseInsensitive, + /// Hides ENV values in the help message + HideEnvValues, + /// The argument should **not** be shown in short help text + HiddenShortHelp, + /// The argument should **not** be shown in long help text + HiddenLongHelp, + #[doc(hidden)] RequiredUnlessAll, + #[doc(hidden)] ValueDelimiterNotSet, +} + +impl FromStr for ArgSettings { + type Err = String; + fn from_str(s: &str) -> Result::Err> { + match &*s.to_ascii_lowercase() { + "required" => Ok(ArgSettings::Required), + "multiple" => Ok(ArgSettings::Multiple), + "global" => Ok(ArgSettings::Global), + "emptyvalues" => Ok(ArgSettings::EmptyValues), + "hidden" => Ok(ArgSettings::Hidden), + "takesvalue" => Ok(ArgSettings::TakesValue), + "usevaluedelimiter" => Ok(ArgSettings::UseValueDelimiter), + "nextlinehelp" => Ok(ArgSettings::NextLineHelp), + "requiredunlessall" => Ok(ArgSettings::RequiredUnlessAll), + "requiredelimiter" => Ok(ArgSettings::RequireDelimiter), + "valuedelimiternotset" => Ok(ArgSettings::ValueDelimiterNotSet), + "hidepossiblevalues" => Ok(ArgSettings::HidePossibleValues), + "allowleadinghyphen" => Ok(ArgSettings::AllowLeadingHyphen), + "requireequals" => Ok(ArgSettings::RequireEquals), + "last" => Ok(ArgSettings::Last), + "hidedefaultvalue" => Ok(ArgSettings::HideDefaultValue), + "caseinsensitive" => Ok(ArgSettings::CaseInsensitive), + "hideenvvalues" => Ok(ArgSettings::HideEnvValues), + "hiddenshorthelp" => Ok(ArgSettings::HiddenShortHelp), + "hiddenlonghelp" => Ok(ArgSettings::HiddenLongHelp), + _ => Err("unknown ArgSetting, cannot convert from str".to_owned()), + } + } +} + +#[cfg(test)] +mod test { + use super::ArgSettings; + + #[test] + fn arg_settings_fromstr() { + assert_eq!( + "allowleadinghyphen".parse::().unwrap(), + ArgSettings::AllowLeadingHyphen + ); + assert_eq!( + "emptyvalues".parse::().unwrap(), + ArgSettings::EmptyValues + ); + assert_eq!( + "global".parse::().unwrap(), + ArgSettings::Global + ); + assert_eq!( + "hidepossiblevalues".parse::().unwrap(), + ArgSettings::HidePossibleValues + ); + assert_eq!( + "hidden".parse::().unwrap(), + ArgSettings::Hidden + ); + assert_eq!( + "multiple".parse::().unwrap(), + ArgSettings::Multiple + ); + assert_eq!( + "nextlinehelp".parse::().unwrap(), + ArgSettings::NextLineHelp + ); + assert_eq!( + "requiredunlessall".parse::().unwrap(), + ArgSettings::RequiredUnlessAll + ); + assert_eq!( + "requiredelimiter".parse::().unwrap(), + ArgSettings::RequireDelimiter + ); + assert_eq!( + "required".parse::().unwrap(), + ArgSettings::Required + ); + assert_eq!( + "takesvalue".parse::().unwrap(), + ArgSettings::TakesValue + ); + assert_eq!( + "usevaluedelimiter".parse::().unwrap(), + ArgSettings::UseValueDelimiter + ); + assert_eq!( + "valuedelimiternotset".parse::().unwrap(), + ArgSettings::ValueDelimiterNotSet + ); + assert_eq!( + "requireequals".parse::().unwrap(), + ArgSettings::RequireEquals + ); + assert_eq!("last".parse::().unwrap(), ArgSettings::Last); + assert_eq!( + "hidedefaultvalue".parse::().unwrap(), + ArgSettings::HideDefaultValue + ); + assert_eq!( + "caseinsensitive".parse::().unwrap(), + ArgSettings::CaseInsensitive + ); + assert_eq!( + "hideenvvalues".parse::().unwrap(), + ArgSettings::HideEnvValues + ); + assert_eq!( + "hiddenshorthelp".parse::().unwrap(), + ArgSettings::HiddenShortHelp + ); + assert_eq!( + "hiddenlonghelp".parse::().unwrap(), + ArgSettings::HiddenLongHelp + ); + assert!("hahahaha".parse::().is_err()); + } +} diff --git a/clap/src/args/subcommand.rs b/clap/src/args/subcommand.rs new file mode 100644 index 000000000..eebbf827a --- /dev/null +++ b/clap/src/args/subcommand.rs @@ -0,0 +1,66 @@ +// Third Party +#[cfg(feature = "yaml")] +use yaml_rust::Yaml; + +// Internal +use App; +use ArgMatches; + +/// The abstract representation of a command line subcommand. +/// +/// This struct describes all the valid options of the subcommand for the program. Subcommands are +/// essentially "sub-[`App`]s" and contain all the same possibilities (such as their own +/// [arguments], subcommands, and settings). +/// +/// # Examples +/// +/// ```rust +/// # use clap::{App, Arg, SubCommand}; +/// App::new("myprog") +/// .subcommand( +/// SubCommand::with_name("config") +/// .about("Used for configuration") +/// .arg(Arg::with_name("config_file") +/// .help("The configuration file to use") +/// .index(1))) +/// # ; +/// ``` +/// [`App`]: ./struct.App.html +/// [arguments]: ./struct.Arg.html +#[derive(Debug, Clone)] +pub struct SubCommand<'a> { + #[doc(hidden)] pub name: String, + #[doc(hidden)] pub matches: ArgMatches<'a>, +} + +impl<'a> SubCommand<'a> { + /// Creates a new instance of a subcommand requiring a name. The name will be displayed + /// to the user when they print version or help and usage information. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, SubCommand}; + /// App::new("myprog") + /// .subcommand( + /// SubCommand::with_name("config")) + /// # ; + /// ``` + pub fn with_name<'b>(name: &str) -> App<'a, 'b> { App::new(name) } + + /// Creates a new instance of a subcommand from a YAML (.yml) document + /// + /// # Examples + /// + /// ```ignore + /// # #[macro_use] + /// # extern crate clap; + /// # use clap::Subcommand; + /// # fn main() { + /// let sc_yaml = load_yaml!("test_subcommand.yml"); + /// let sc = SubCommand::from_yaml(sc_yaml); + /// # } + /// ``` + #[cfg(feature = "yaml")] + pub fn from_yaml(yaml: &Yaml) -> App { App::from_yaml(yaml) } +} diff --git a/clap/src/completions/bash.rs b/clap/src/completions/bash.rs new file mode 100644 index 000000000..37dfa6698 --- /dev/null +++ b/clap/src/completions/bash.rs @@ -0,0 +1,219 @@ +// Std +use std::io::Write; + +// Internal +use app::parser::Parser; +use args::OptBuilder; +use completions; + +pub struct BashGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> BashGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } } + + pub fn generate_to(&self, buf: &mut W) { + w!( + buf, + format!( + r#"_{name}() {{ + local i cur prev opts cmds + COMPREPLY=() + cur="${{COMP_WORDS[COMP_CWORD]}}" + prev="${{COMP_WORDS[COMP_CWORD-1]}}" + cmd="" + opts="" + + for i in ${{COMP_WORDS[@]}} + do + case "${{i}}" in + {name}) + cmd="{name}" + ;; + {subcmds} + *) + ;; + esac + done + + case "${{cmd}}" in + {name}) + opts="{name_opts}" + if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + fi + case "${{prev}}" in + {name_opts_details} + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + ;; + {subcmd_details} + esac +}} + +complete -F _{name} -o bashdefault -o default {name} +"#, + name = self.p.meta.bin_name.as_ref().unwrap(), + name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()), + name_opts_details = + self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()), + subcmds = self.all_subcommands(), + subcmd_details = self.subcommand_details() + ).as_bytes() + ); + } + + fn all_subcommands(&self) -> String { + debugln!("BashGen::all_subcommands;"); + let mut subcmds = String::new(); + let scs = completions::all_subcommand_names(self.p); + + for sc in &scs { + subcmds = format!( + r#"{} + {name}) + cmd+="__{fn_name}" + ;;"#, + subcmds, + name = sc, + fn_name = sc.replace("-", "__") + ); + } + + subcmds + } + + fn subcommand_details(&self) -> String { + debugln!("BashGen::subcommand_details;"); + let mut subcmd_dets = String::new(); + let mut scs = completions::get_all_subcommand_paths(self.p, true); + scs.sort(); + scs.dedup(); + + for sc in &scs { + subcmd_dets = format!( + r#"{} + {subcmd}) + opts="{sc_opts}" + if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + fi + case "${{prev}}" in + {opts_details} + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) + return 0 + ;;"#, + subcmd_dets, + subcmd = sc.replace("-", "__"), + sc_opts = self.all_options_for_path(&*sc), + level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n), + opts_details = self.option_details_for_path(&*sc) + ); + } + + subcmd_dets + } + + fn option_details_for_path(&self, path: &str) -> String { + debugln!("BashGen::option_details_for_path: path={}", path); + let mut p = self.p; + for sc in path.split("__").skip(1) { + debugln!("BashGen::option_details_for_path:iter: sc={}", sc); + p = &find_subcmd!(p, sc).unwrap().p; + } + let mut opts = String::new(); + for o in p.opts() { + if let Some(l) = o.s.long { + opts = format!( + "{} + --{}) + COMPREPLY=({}) + return 0 + ;;", + opts, + l, + self.vals_for(o) + ); + } + if let Some(s) = o.s.short { + opts = format!( + "{} + -{}) + COMPREPLY=({}) + return 0 + ;;", + opts, + s, + self.vals_for(o) + ); + } + } + opts + } + + fn vals_for(&self, o: &OptBuilder) -> String { + debugln!("BashGen::vals_for: o={}", o.b.name); + use args::AnyArg; + if let Some(vals) = o.possible_vals() { + format!(r#"$(compgen -W "{}" -- "${{cur}}")"#, vals.join(" ")) + } else { + String::from(r#"$(compgen -f "${cur}")"#) + } + } + + fn all_options_for_path(&self, path: &str) -> String { + debugln!("BashGen::all_options_for_path: path={}", path); + let mut p = self.p; + for sc in path.split("__").skip(1) { + debugln!("BashGen::all_options_for_path:iter: sc={}", sc); + p = &find_subcmd!(p, sc).unwrap().p; + } + let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)); + opts = format!( + "{} {}", + opts, + longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)) + ); + opts = format!( + "{} {}", + opts, + p.positionals + .values() + .fold(String::new(), |acc, p| format!("{} {}", acc, p)) + ); + opts = format!( + "{} {}", + opts, + p.subcommands + .iter() + .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)) + ); + for sc in &p.subcommands { + if let Some(ref aliases) = sc.p.meta.aliases { + opts = format!( + "{} {}", + opts, + aliases + .iter() + .map(|&(n, _)| n) + .fold(String::new(), |acc, a| format!("{} {}", acc, a)) + ); + } + } + opts + } +} diff --git a/clap/src/completions/elvish.rs b/clap/src/completions/elvish.rs new file mode 100644 index 000000000..9a5f21a38 --- /dev/null +++ b/clap/src/completions/elvish.rs @@ -0,0 +1,126 @@ +// Std +use std::io::Write; + +// Internal +use app::parser::Parser; +use INTERNAL_ERROR_MSG; + +pub struct ElvishGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ElvishGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { ElvishGen { p: p } } + + pub fn generate_to(&self, buf: &mut W) { + let bin_name = self.p.meta.bin_name.as_ref().unwrap(); + + let mut names = vec![]; + let subcommands_cases = + generate_inner(self.p, "", &mut names); + + let result = format!(r#" +edit:completion:arg-completer[{bin_name}] = [@words]{{ + fn spaces [n]{{ + repeat $n ' ' | joins '' + }} + fn cand [text desc]{{ + edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc + }} + command = '{bin_name}' + for word $words[1:-1] {{ + if (has-prefix $word '-') {{ + break + }} + command = $command';'$word + }} + completions = [{subcommands_cases} + ] + $completions[$command] +}} +"#, + bin_name = bin_name, + subcommands_cases = subcommands_cases + ); + + w!(buf, result.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { string.replace("'", "''") } + +fn get_tooltip(help: Option<&str>, data: T) -> String { + match help { + Some(help) => escape_string(help), + _ => data.to_string() + } +} + +fn generate_inner<'a, 'b, 'p>( + p: &'p Parser<'a, 'b>, + previous_command_name: &str, + names: &mut Vec<&'p str>, +) -> String { + debugln!("ElvishGen::generate_inner;"); + let command_name = if previous_command_name.is_empty() { + p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() + } else { + format!("{};{}", previous_command_name, &p.meta.name) + }; + + let mut completions = String::new(); + let preamble = String::from("\n cand "); + + for option in p.opts() { + if let Some(data) = option.s.short { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); + } + if let Some(data) = option.s.long { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); + } + } + + for flag in p.flags() { + if let Some(data) = flag.s.short { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); + } + if let Some(data) = flag.s.long { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); + } + } + + for subcommand in &p.subcommands { + let data = &subcommand.p.meta.name; + let tooltip = get_tooltip(subcommand.p.meta.about, data); + completions.push_str(&preamble); + completions.push_str(format!("{} '{}'", data, tooltip).as_str()); + } + + let mut subcommands_cases = format!( + r" + &'{}'= {{{} + }}", + &command_name, + completions + ); + + for subcommand in &p.subcommands { + let subcommand_subcommands_cases = + generate_inner(&subcommand.p, &command_name, names); + subcommands_cases.push_str(&subcommand_subcommands_cases); + } + + subcommands_cases +} diff --git a/clap/src/completions/fish.rs b/clap/src/completions/fish.rs new file mode 100644 index 000000000..c2c5a5e70 --- /dev/null +++ b/clap/src/completions/fish.rs @@ -0,0 +1,99 @@ +// Std +use std::io::Write; + +// Internal +use app::parser::Parser; + +pub struct FishGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> FishGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { FishGen { p: p } } + + pub fn generate_to(&self, buf: &mut W) { + let command = self.p.meta.bin_name.as_ref().unwrap(); + let mut buffer = String::new(); + gen_fish_inner(command, self, command, &mut buffer); + w!(buf, buffer.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { string.replace("\\", "\\\\").replace("'", "\\'") } + +fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, subcommand: &str, buffer: &mut String) { + debugln!("FishGen::gen_fish_inner;"); + // example : + // + // complete + // -c {command} + // -d "{description}" + // -s {short} + // -l {long} + // -a "{possible_arguments}" + // -r # if require parameter + // -f # don't use file completion + // -n "__fish_use_subcommand" # complete for command "myprog" + // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1" + + let mut basic_template = format!("complete -c {} -n ", root_command); + if root_command == subcommand { + basic_template.push_str("\"__fish_use_subcommand\""); + } else { + basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", subcommand).as_str()); + } + + for option in comp_gen.p.opts() { + let mut template = basic_template.clone(); + if let Some(data) = option.s.short { + template.push_str(format!(" -s {}", data).as_str()); + } + if let Some(data) = option.s.long { + template.push_str(format!(" -l {}", data).as_str()); + } + if let Some(data) = option.b.help { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); + } + if let Some(ref data) = option.v.possible_vals { + template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str()); + } + buffer.push_str(template.as_str()); + buffer.push_str("\n"); + } + + for flag in comp_gen.p.flags() { + let mut template = basic_template.clone(); + if let Some(data) = flag.s.short { + template.push_str(format!(" -s {}", data).as_str()); + } + if let Some(data) = flag.s.long { + template.push_str(format!(" -l {}", data).as_str()); + } + if let Some(data) = flag.b.help { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); + } + buffer.push_str(template.as_str()); + buffer.push_str("\n"); + } + + for subcommand in &comp_gen.p.subcommands { + let mut template = basic_template.clone(); + template.push_str(" -f"); + template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str()); + if let Some(data) = subcommand.p.meta.about { + template.push_str(format!(" -d '{}'", escape_string(data)).as_str()) + } + buffer.push_str(template.as_str()); + buffer.push_str("\n"); + } + + // generate options of subcommands + for subcommand in &comp_gen.p.subcommands { + let sub_comp_gen = FishGen::new(&subcommand.p); + gen_fish_inner(root_command, &sub_comp_gen, &subcommand.to_string(), buffer); + } +} diff --git a/clap/src/completions/macros.rs b/clap/src/completions/macros.rs new file mode 100644 index 000000000..653c72c48 --- /dev/null +++ b/clap/src/completions/macros.rs @@ -0,0 +1,28 @@ +macro_rules! w { + ($buf:expr, $to_w:expr) => { + match $buf.write_all($to_w) { + Ok(..) => (), + Err(..) => panic!("Failed to write to completions file"), + } + }; +} + +macro_rules! get_zsh_arg_conflicts { + ($p:ident, $arg:ident, $msg:ident) => { + if let Some(conf_vec) = $arg.blacklist() { + let mut v = vec![]; + for arg_name in conf_vec { + let arg = $p.find_any_arg(arg_name).expect($msg); + if let Some(s) = arg.short() { + v.push(format!("-{}", s)); + } + if let Some(l) = arg.long() { + v.push(format!("--{}", l)); + } + } + v.join(" ") + } else { + String::new() + } + } +} diff --git a/clap/src/completions/mod.rs b/clap/src/completions/mod.rs new file mode 100644 index 000000000..a3306d72a --- /dev/null +++ b/clap/src/completions/mod.rs @@ -0,0 +1,179 @@ +#[macro_use] +mod macros; +mod bash; +mod fish; +mod zsh; +mod powershell; +mod elvish; +mod shell; + +// Std +use std::io::Write; + +// Internal +use app::parser::Parser; +use self::bash::BashGen; +use self::fish::FishGen; +use self::zsh::ZshGen; +use self::powershell::PowerShellGen; +use self::elvish::ElvishGen; +pub use self::shell::Shell; + +pub struct ComplGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ComplGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { ComplGen { p: p } } + + pub fn generate(&self, for_shell: Shell, buf: &mut W) { + match for_shell { + Shell::Bash => BashGen::new(self.p).generate_to(buf), + Shell::Fish => FishGen::new(self.p).generate_to(buf), + Shell::Zsh => ZshGen::new(self.p).generate_to(buf), + Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf), + Shell::Elvish => ElvishGen::new(self.p).generate_to(buf), + } + } +} + +// Gets all subcommands including child subcommands in the form of 'name' where the name +// is a single word (i.e. "install") of the path to said subcommand (i.e. +// "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn all_subcommand_names(p: &Parser) -> Vec { + debugln!("all_subcommand_names;"); + let mut subcmds: Vec<_> = subcommands_of(p) + .iter() + .map(|&(ref n, _)| n.clone()) + .collect(); + for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) { + subcmds.extend(sc_v); + } + subcmds.sort(); + subcmds.dedup(); + subcmds +} + +// Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name +// is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e. +// "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> { + debugln!("all_subcommands;"); + let mut subcmds: Vec<_> = subcommands_of(p); + for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) { + subcmds.extend(sc_v); + } + subcmds +} + +// Gets all subcommands excluding child subcommands in the form of (name, bin_name) where the name +// is a single word (i.e. "install") and the bin_name is a space delineated list of the path to said +// subcommand (i.e. "rustup toolchain install") +// +// Also note, aliases are treated as their own subcommands but duplicates of whatever they're +// aliasing. +pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> { + debugln!( + "subcommands_of: name={}, bin_name={}", + p.meta.name, + p.meta.bin_name.as_ref().unwrap() + ); + let mut subcmds = vec![]; + + debugln!( + "subcommands_of: Has subcommands...{:?}", + p.has_subcommands() + ); + if !p.has_subcommands() { + let mut ret = vec![]; + debugln!("subcommands_of: Looking for aliases..."); + if let Some(ref aliases) = p.meta.aliases { + for &(n, _) in aliases { + debugln!("subcommands_of:iter:iter: Found alias...{}", n); + let mut als_bin_name: Vec<_> = + p.meta.bin_name.as_ref().unwrap().split(' ').collect(); + als_bin_name.push(n); + let old = als_bin_name.len() - 2; + als_bin_name.swap_remove(old); + ret.push((n.to_owned(), als_bin_name.join(" "))); + } + } + return ret; + } + for sc in &p.subcommands { + debugln!( + "subcommands_of:iter: name={}, bin_name={}", + sc.p.meta.name, + sc.p.meta.bin_name.as_ref().unwrap() + ); + + debugln!("subcommands_of:iter: Looking for aliases..."); + if let Some(ref aliases) = sc.p.meta.aliases { + for &(n, _) in aliases { + debugln!("subcommands_of:iter:iter: Found alias...{}", n); + let mut als_bin_name: Vec<_> = + p.meta.bin_name.as_ref().unwrap().split(' ').collect(); + als_bin_name.push(n); + let old = als_bin_name.len() - 2; + als_bin_name.swap_remove(old); + subcmds.push((n.to_owned(), als_bin_name.join(" "))); + } + } + subcmds.push(( + sc.p.meta.name.clone(), + sc.p.meta.bin_name.as_ref().unwrap().clone(), + )); + } + subcmds +} + +pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec { + debugln!("get_all_subcommand_paths;"); + let mut subcmds = vec![]; + if !p.has_subcommands() { + if !first { + let name = &*p.meta.name; + let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__"); + let mut ret = vec![path.clone()]; + if let Some(ref aliases) = p.meta.aliases { + for &(n, _) in aliases { + ret.push(path.replace(name, n)); + } + } + return ret; + } + return vec![]; + } + for sc in &p.subcommands { + let name = &*sc.p.meta.name; + let path = sc.p + .meta + .bin_name + .as_ref() + .unwrap() + .clone() + .replace(" ", "__"); + subcmds.push(path.clone()); + if let Some(ref aliases) = sc.p.meta.aliases { + for &(n, _) in aliases { + subcmds.push(path.replace(name, n)); + } + } + } + for sc_v in p.subcommands + .iter() + .map(|s| get_all_subcommand_paths(&s.p, false)) + { + subcmds.extend(sc_v); + } + subcmds +} diff --git a/clap/src/completions/powershell.rs b/clap/src/completions/powershell.rs new file mode 100644 index 000000000..9fc77c72a --- /dev/null +++ b/clap/src/completions/powershell.rs @@ -0,0 +1,139 @@ +// Std +use std::io::Write; + +// Internal +use app::parser::Parser; +use INTERNAL_ERROR_MSG; + +pub struct PowerShellGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> PowerShellGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } } + + pub fn generate_to(&self, buf: &mut W) { + let bin_name = self.p.meta.bin_name.as_ref().unwrap(); + + let mut names = vec![]; + let subcommands_cases = + generate_inner(self.p, "", &mut names); + + let result = format!(r#" +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{ + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + '{bin_name}' + for ($i = 1; $i -lt $commandElements.Count; $i++) {{ + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-')) {{ + break + }} + $element.Value + }}) -join ';' + + $completions = @(switch ($command) {{{subcommands_cases} + }}) + + $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} | + Sort-Object -Property ListItemText +}} +"#, + bin_name = bin_name, + subcommands_cases = subcommands_cases + ); + + w!(buf, result.as_bytes()); + } +} + +// Escape string inside single quotes +fn escape_string(string: &str) -> String { string.replace("'", "''") } + +fn get_tooltip(help: Option<&str>, data: T) -> String { + match help { + Some(help) => escape_string(help), + _ => data.to_string() + } +} + +fn generate_inner<'a, 'b, 'p>( + p: &'p Parser<'a, 'b>, + previous_command_name: &str, + names: &mut Vec<&'p str>, +) -> String { + debugln!("PowerShellGen::generate_inner;"); + let command_name = if previous_command_name.is_empty() { + p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() + } else { + format!("{};{}", previous_command_name, &p.meta.name) + }; + + let mut completions = String::new(); + let preamble = String::from("\n [CompletionResult]::new("); + + for option in p.opts() { + if let Some(data) = option.s.short { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("'-{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); + } + if let Some(data) = option.s.long { + let tooltip = get_tooltip(option.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("'--{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); + } + } + + for flag in p.flags() { + if let Some(data) = flag.s.short { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("'-{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); + } + if let Some(data) = flag.s.long { + let tooltip = get_tooltip(flag.b.help, data); + completions.push_str(&preamble); + completions.push_str(format!("'--{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); + } + } + + for subcommand in &p.subcommands { + let data = &subcommand.p.meta.name; + let tooltip = get_tooltip(subcommand.p.meta.about, data); + completions.push_str(&preamble); + completions.push_str(format!("'{}', '{}', {}, '{}')", + data, data, "[CompletionResultType]::ParameterValue", tooltip).as_str()); + } + + let mut subcommands_cases = format!( + r" + '{}' {{{} + break + }}", + &command_name, + completions + ); + + for subcommand in &p.subcommands { + let subcommand_subcommands_cases = + generate_inner(&subcommand.p, &command_name, names); + subcommands_cases.push_str(&subcommand_subcommands_cases); + } + + subcommands_cases +} diff --git a/clap/src/completions/shell.rs b/clap/src/completions/shell.rs new file mode 100644 index 000000000..19aab8694 --- /dev/null +++ b/clap/src/completions/shell.rs @@ -0,0 +1,52 @@ +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; +use std::str::FromStr; +use std::fmt; + +/// Describes which shell to produce a completions file for +#[cfg_attr(feature = "lints", allow(enum_variant_names))] +#[derive(Debug, Copy, Clone)] +pub enum Shell { + /// Generates a .bash completion file for the Bourne Again SHell (BASH) + Bash, + /// Generates a .fish completion file for the Friendly Interactive SHell (fish) + Fish, + /// Generates a completion file for the Z SHell (ZSH) + Zsh, + /// Generates a completion file for PowerShell + PowerShell, + /// Generates a completion file for Elvish + Elvish, +} + +impl Shell { + /// A list of possible variants in `&'static str` form + pub fn variants() -> [&'static str; 5] { ["zsh", "bash", "fish", "powershell", "elvish"] } +} + +impl FromStr for Shell { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "ZSH" | _ if s.eq_ignore_ascii_case("zsh") => Ok(Shell::Zsh), + "FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish), + "BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash), + "POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell), + "ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish), + _ => Err(String::from("[valid values: bash, fish, zsh, powershell, elvish]")), + } + } +} + +impl fmt::Display for Shell { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Shell::Bash => write!(f, "BASH"), + Shell::Fish => write!(f, "FISH"), + Shell::Zsh => write!(f, "ZSH"), + Shell::PowerShell => write!(f, "POWERSHELL"), + Shell::Elvish => write!(f, "ELVISH"), + } + } +} diff --git a/clap/src/completions/zsh.rs b/clap/src/completions/zsh.rs new file mode 100644 index 000000000..5d23fd284 --- /dev/null +++ b/clap/src/completions/zsh.rs @@ -0,0 +1,472 @@ +// Std +use std::io::Write; +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; + +// Internal +use app::App; +use app::parser::Parser; +use args::{AnyArg, ArgSettings}; +use completions; +use INTERNAL_ERROR_MSG; + +pub struct ZshGen<'a, 'b> +where + 'a: 'b, +{ + p: &'b Parser<'a, 'b>, +} + +impl<'a, 'b> ZshGen<'a, 'b> { + pub fn new(p: &'b Parser<'a, 'b>) -> Self { + debugln!("ZshGen::new;"); + ZshGen { p: p } + } + + pub fn generate_to(&self, buf: &mut W) { + debugln!("ZshGen::generate_to;"); + w!( + buf, + format!( + "\ +#compdef {name} + +autoload -U is-at-least + +_{name}() {{ + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext=\"$curcontext\" state line + {initial_args} + {subcommands} +}} + +{subcommand_details} + +_{name} \"$@\"", + name = self.p.meta.bin_name.as_ref().unwrap(), + initial_args = get_args_of(self.p), + subcommands = get_subcommands_of(self.p), + subcommand_details = subcommand_details(self.p) + ).as_bytes() + ); + } +} + +// Displays the commands of a subcommand +// (( $+functions[_[bin_name_underscore]_commands] )) || +// _[bin_name_underscore]_commands() { +// local commands; commands=( +// '[arg_name]:[arg_help]' +// ) +// _describe -t commands '[bin_name] commands' commands "$@" +// +// Where the following variables are present: +// [bin_name_underscore]: The full space delineated bin_name, where spaces have been replaced by +// underscore characters +// [arg_name]: The name of the subcommand +// [arg_help]: The help message of the subcommand +// [bin_name]: The full space delineated bin_name +// +// Here's a snippet from rustup: +// +// (( $+functions[_rustup_commands] )) || +// _rustup_commands() { +// local commands; commands=( +// 'show:Show the active and installed toolchains' +// 'update:Update Rust toolchains' +// # ... snip for brevity +// 'help:Prints this message or the help of the given subcommand(s)' +// ) +// _describe -t commands 'rustup commands' commands "$@" +// +fn subcommand_details(p: &Parser) -> String { + debugln!("ZshGen::subcommand_details;"); + // First we do ourself + let mut ret = vec![ + format!( + "\ +(( $+functions[_{bin_name_underscore}_commands] )) || +_{bin_name_underscore}_commands() {{ + local commands; commands=( + {subcommands_and_args} + ) + _describe -t commands '{bin_name} commands' commands \"$@\" +}}", + bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"), + bin_name = p.meta.bin_name.as_ref().unwrap(), + subcommands_and_args = subcommands_of(p) + ), + ]; + + // Next we start looping through all the children, grandchildren, etc. + let mut all_subcommands = completions::all_subcommands(p); + all_subcommands.sort(); + all_subcommands.dedup(); + for &(_, ref bin_name) in &all_subcommands { + debugln!("ZshGen::subcommand_details:iter: bin_name={}", bin_name); + ret.push(format!( + "\ +(( $+functions[_{bin_name_underscore}_commands] )) || +_{bin_name_underscore}_commands() {{ + local commands; commands=( + {subcommands_and_args} + ) + _describe -t commands '{bin_name} commands' commands \"$@\" +}}", + bin_name_underscore = bin_name.replace(" ", "__"), + bin_name = bin_name, + subcommands_and_args = subcommands_of(parser_of(p, bin_name)) + )); + } + + ret.join("\n") +} + +// Generates subcommand completions in form of +// +// '[arg_name]:[arg_help]' +// +// Where: +// [arg_name]: the subcommand's name +// [arg_help]: the help message of the subcommand +// +// A snippet from rustup: +// 'show:Show the active and installed toolchains' +// 'update:Update Rust toolchains' +fn subcommands_of(p: &Parser) -> String { + debugln!("ZshGen::subcommands_of;"); + let mut ret = vec![]; + fn add_sc(sc: &App, n: &str, ret: &mut Vec) { + debugln!("ZshGen::add_sc;"); + let s = format!( + "\"{name}:{help}\" \\", + name = n, + help = sc.p + .meta + .about + .unwrap_or("") + .replace("[", "\\[") + .replace("]", "\\]") + ); + if !s.is_empty() { + ret.push(s); + } + } + + // The subcommands + for sc in p.subcommands() { + debugln!( + "ZshGen::subcommands_of:iter: subcommand={}", + sc.p.meta.name + ); + add_sc(sc, &sc.p.meta.name, &mut ret); + if let Some(ref v) = sc.p.meta.aliases { + for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) { + add_sc(sc, alias, &mut ret); + } + } + } + + ret.join("\n") +} + +// Get's the subcommand section of a completion file +// This looks roughly like: +// +// case $state in +// ([bin_name]_args) +// curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\" +// case $line[1] in +// +// ([name]) +// _arguments -C -s -S \ +// [subcommand_args] +// && ret=0 +// +// [RECURSIVE_CALLS] +// +// ;;", +// +// [repeat] +// +// esac +// ;; +// esac", +// +// Where the following variables are present: +// [name] = The subcommand name in the form of "install" for "rustup toolchain install" +// [bin_name] = The full space delineated bin_name such as "rustup toolchain install" +// [name_hyphen] = The full space delineated bin_name, but replace spaces with hyphens +// [repeat] = From the same recursive calls, but for all subcommands +// [subcommand_args] = The same as zsh::get_args_of +fn get_subcommands_of(p: &Parser) -> String { + debugln!("get_subcommands_of;"); + + debugln!( + "get_subcommands_of: Has subcommands...{:?}", + p.has_subcommands() + ); + if !p.has_subcommands() { + return String::new(); + } + + let sc_names = completions::subcommands_of(p); + + let mut subcmds = vec![]; + for &(ref name, ref bin_name) in &sc_names { + let mut v = vec![format!("({})", name)]; + let subcommand_args = get_args_of(parser_of(p, &*bin_name)); + if !subcommand_args.is_empty() { + v.push(subcommand_args); + } + let subcommands = get_subcommands_of(parser_of(p, &*bin_name)); + if !subcommands.is_empty() { + v.push(subcommands); + } + v.push(String::from(";;")); + subcmds.push(v.join("\n")); + } + + format!( + "case $state in + ({name}) + words=($line[{pos}] \"${{words[@]}}\") + (( CURRENT += 1 )) + curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\" + case $line[{pos}] in + {subcommands} + esac + ;; +esac", + name = p.meta.name, + name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"), + subcommands = subcmds.join("\n"), + pos = p.positionals().len() + 1 + ) +} + +fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> { + debugln!("parser_of: sc={}", sc); + if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) { + return p; + } + &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p +} + +// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to +// another ZSH function if there are subcommands. +// The structer works like this: +// ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)] +// ^-- list '-v -h' ^--'*' ^--'+' ^-- list 'one two three' +// +// An example from the rustup command: +// +// _arguments -C -s -S \ +// '(-h --help --verbose)-v[Enable verbose output]' \ +// '(-V -v --version --verbose --help)-h[Prints help information]' \ +// # ... snip for brevity +// ':: :_rustup_commands' \ # <-- displays subcommands +// '*::: :->rustup' \ # <-- displays subcommand args and child subcommands +// && ret=0 +// +// The args used for _arguments are as follows: +// -C: modify the $context internal variable +// -s: Allow stacking of short args (i.e. -a -b -c => -abc) +// -S: Do not complete anything after '--' and treat those as argument values +fn get_args_of(p: &Parser) -> String { + debugln!("get_args_of;"); + let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")]; + let opts = write_opts_of(p); + let flags = write_flags_of(p); + let positionals = write_positionals_of(p); + let sc_or_a = if p.has_subcommands() { + format!( + "\":: :_{name}_commands\" \\", + name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__") + ) + } else { + String::new() + }; + let sc = if p.has_subcommands() { + format!("\"*::: :->{name}\" \\", name = p.meta.name) + } else { + String::new() + }; + + if !opts.is_empty() { + ret.push(opts); + } + if !flags.is_empty() { + ret.push(flags); + } + if !positionals.is_empty() { + ret.push(positionals); + } + if !sc_or_a.is_empty() { + ret.push(sc_or_a); + } + if !sc.is_empty() { + ret.push(sc); + } + ret.push(String::from("&& ret=0")); + + ret.join("\n") +} + +// Escape help string inside single quotes and brackets +fn escape_help(string: &str) -> String { + string + .replace("\\", "\\\\") + .replace("'", "'\\''") + .replace("[", "\\[") + .replace("]", "\\]") +} + +// Escape value string inside single quotes and parentheses +fn escape_value(string: &str) -> String { + string + .replace("\\", "\\\\") + .replace("'", "'\\''") + .replace("(", "\\(") + .replace(")", "\\)") + .replace(" ", "\\ ") +} + +fn write_opts_of(p: &Parser) -> String { + debugln!("write_opts_of;"); + let mut ret = vec![]; + for o in p.opts() { + debugln!("write_opts_of:iter: o={}", o.name()); + let help = o.help().map_or(String::new(), escape_help); + let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG); + conflicts = if conflicts.is_empty() { + String::new() + } else { + format!("({})", conflicts) + }; + + let multiple = if o.is_set(ArgSettings::Multiple) { + "*" + } else { + "" + }; + let pv = if let Some(pv_vec) = o.possible_vals() { + format!(": :({})", pv_vec.iter().map( + |v| escape_value(*v)).collect::>().join(" ")) + } else { + String::new() + }; + if let Some(short) = o.short() { + let s = format!( + "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\", + conflicts = conflicts, + multiple = multiple, + arg = short, + possible_values = pv, + help = help + ); + + debugln!("write_opts_of:iter: Wrote...{}", &*s); + ret.push(s); + } + if let Some(long) = o.long() { + let l = format!( + "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\", + conflicts = conflicts, + multiple = multiple, + arg = long, + possible_values = pv, + help = help + ); + + debugln!("write_opts_of:iter: Wrote...{}", &*l); + ret.push(l); + } + } + + ret.join("\n") +} + +fn write_flags_of(p: &Parser) -> String { + debugln!("write_flags_of;"); + let mut ret = vec![]; + for f in p.flags() { + debugln!("write_flags_of:iter: f={}", f.name()); + let help = f.help().map_or(String::new(), escape_help); + let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG); + conflicts = if conflicts.is_empty() { + String::new() + } else { + format!("({})", conflicts) + }; + + let multiple = if f.is_set(ArgSettings::Multiple) { + "*" + } else { + "" + }; + if let Some(short) = f.short() { + let s = format!( + "'{conflicts}{multiple}-{arg}[{help}]' \\", + multiple = multiple, + conflicts = conflicts, + arg = short, + help = help + ); + + debugln!("write_flags_of:iter: Wrote...{}", &*s); + ret.push(s); + } + + if let Some(long) = f.long() { + let l = format!( + "'{conflicts}{multiple}--{arg}[{help}]' \\", + conflicts = conflicts, + multiple = multiple, + arg = long, + help = help + ); + + debugln!("write_flags_of:iter: Wrote...{}", &*l); + ret.push(l); + } + } + + ret.join("\n") +} + +fn write_positionals_of(p: &Parser) -> String { + debugln!("write_positionals_of;"); + let mut ret = vec![]; + for arg in p.positionals() { + debugln!("write_positionals_of:iter: arg={}", arg.b.name); + let a = format!( + "'{optional}:{name}{help}:{action}' \\", + optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" }, + name = arg.b.name, + help = arg.b + .help + .map_or("".to_owned(), |v| " -- ".to_owned() + v) + .replace("[", "\\[") + .replace("]", "\\]"), + action = arg.possible_vals().map_or("_files".to_owned(), |values| { + format!("({})", + values.iter().map(|v| escape_value(*v)).collect::>().join(" ")) + }) + ); + + debugln!("write_positionals_of:iter: Wrote...{}", a); + ret.push(a); + } + + ret.join("\n") +} diff --git a/clap/src/errors.rs b/clap/src/errors.rs new file mode 100644 index 000000000..c6087c00a --- /dev/null +++ b/clap/src/errors.rs @@ -0,0 +1,912 @@ +// Std +use std::convert::From; +use std::error::Error as StdError; +use std::fmt as std_fmt; +use std::fmt::Display; +use std::io::{self, Write}; +use std::process; +use std::result::Result as StdResult; + +// Internal +use args::AnyArg; +use fmt::{ColorWhen, Colorizer, ColorizerOption}; +use suggestions; + +/// Short hand for [`Result`] type +/// +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +pub type Result = StdResult; + +/// Command line argument parser kind of error +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ErrorKind { + /// Occurs when an [`Arg`] has a set of possible values, + /// and the user provides a value which isn't in that set. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("speed") + /// .possible_value("fast") + /// .possible_value("slow")) + /// .get_matches_from_safe(vec!["prog", "other"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidValue); + /// ``` + /// [`Arg`]: ./struct.Arg.html + InvalidValue, + + /// Occurs when a user provides a flag, option, argument or subcommand which isn't defined. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::from_usage("--flag 'some flag'")) + /// .get_matches_from_safe(vec!["prog", "--other"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnknownArgument); + /// ``` + UnknownArgument, + + /// Occurs when the user provides an unrecognized [`SubCommand`] which meets the threshold for + /// being similar enough to an existing subcommand. + /// If it doesn't meet the threshold, or the 'suggestions' feature is disabled, + /// the more general [`UnknownArgument`] error is returned. + /// + /// # Examples + /// + #[cfg_attr(not(feature = "suggestions"), doc = " ```no_run")] + #[cfg_attr(feature = "suggestions", doc = " ```")] + /// # use clap::{App, Arg, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use") + /// .index(1))) + /// .get_matches_from_safe(vec!["prog", "confi"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + InvalidSubcommand, + + /// Occurs when the user provides an unrecognized [`SubCommand`] which either + /// doesn't meet the threshold for being similar enough to an existing subcommand, + /// or the 'suggestions' feature is disabled. + /// Otherwise the more detailed [`InvalidSubcommand`] error is returned. + /// + /// This error typically happens when passing additional subcommand names to the `help` + /// subcommand. Otherwise, the more general [`UnknownArgument`] error is used. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use") + /// .index(1))) + /// .get_matches_from_safe(vec!["prog", "help", "nothing"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnrecognizedSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`InvalidSubcommand`]: ./enum.ErrorKind.html#variant.InvalidSubcommand + /// [`UnknownArgument`]: ./enum.ErrorKind.html#variant.UnknownArgument + UnrecognizedSubcommand, + + /// Occurs when the user provides an empty value for an option that does not allow empty + /// values. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let res = App::new("prog") + /// .arg(Arg::with_name("color") + /// .long("color") + /// .empty_values(false)) + /// .get_matches_from_safe(vec!["prog", "--color="]); + /// assert!(res.is_err()); + /// assert_eq!(res.unwrap_err().kind, ErrorKind::EmptyValue); + /// ``` + EmptyValue, + + /// Occurs when the user provides a value for an argument with a custom validation and the + /// value fails that validation. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// fn is_numeric(val: String) -> Result<(), String> { + /// match val.parse::() { + /// Ok(..) => Ok(()), + /// Err(..) => Err(String::from("Value wasn't a number!")), + /// } + /// } + /// + /// let result = App::new("prog") + /// .arg(Arg::with_name("num") + /// .validator(is_numeric)) + /// .get_matches_from_safe(vec!["prog", "NotANumber"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::ValueValidation); + /// ``` + ValueValidation, + + /// Occurs when a user provides more values for an argument than were defined by setting + /// [`Arg::max_values`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("arg") + /// .multiple(true) + /// .max_values(2)) + /// .get_matches_from_safe(vec!["prog", "too", "many", "values"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooManyValues); + /// ``` + /// [`Arg::max_values`]: ./struct.Arg.html#method.max_values + TooManyValues, + + /// Occurs when the user provides fewer values for an argument than were defined by setting + /// [`Arg::min_values`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("some_opt") + /// .long("opt") + /// .min_values(3)) + /// .get_matches_from_safe(vec!["prog", "--opt", "too", "few"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::TooFewValues); + /// ``` + /// [`Arg::min_values`]: ./struct.Arg.html#method.min_values + TooFewValues, + + /// Occurs when the user provides a different number of values for an argument than what's + /// been defined by setting [`Arg::number_of_values`] or than was implicitly set by + /// [`Arg::value_names`]. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("some_opt") + /// .long("opt") + /// .takes_value(true) + /// .number_of_values(2)) + /// .get_matches_from_safe(vec!["prog", "--opt", "wrong"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::WrongNumberOfValues); + /// ``` + /// + /// [`Arg::number_of_values`]: ./struct.Arg.html#method.number_of_values + /// [`Arg::value_names`]: ./struct.Arg.html#method.value_names + WrongNumberOfValues, + + /// Occurs when the user provides two values which conflict with each other and can't be used + /// together. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .conflicts_with("color")) + /// .arg(Arg::with_name("color") + /// .long("color")) + /// .get_matches_from_safe(vec!["prog", "--debug", "--color"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::ArgumentConflict); + /// ``` + ArgumentConflict, + + /// Occurs when the user does not provide one or more required arguments. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .required(true)) + /// .get_matches_from_safe(vec!["prog"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingRequiredArgument); + /// ``` + MissingRequiredArgument, + + /// Occurs when a subcommand is required (as defined by [`AppSettings::SubcommandRequired`]), + /// but the user does not provide one. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, AppSettings, SubCommand, ErrorKind}; + /// let err = App::new("prog") + /// .setting(AppSettings::SubcommandRequired) + /// .subcommand(SubCommand::with_name("test")) + /// .get_matches_from_safe(vec![ + /// "myprog", + /// ]); + /// assert!(err.is_err()); + /// assert_eq!(err.unwrap_err().kind, ErrorKind::MissingSubcommand); + /// # ; + /// ``` + /// [`AppSettings::SubcommandRequired`]: ./enum.AppSettings.html#variant.SubcommandRequired + MissingSubcommand, + + /// Occurs when either an argument or [`SubCommand`] is required, as defined by + /// [`AppSettings::ArgRequiredElseHelp`], but the user did not provide one. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, AppSettings, ErrorKind, SubCommand}; + /// let result = App::new("prog") + /// .setting(AppSettings::ArgRequiredElseHelp) + /// .subcommand(SubCommand::with_name("config") + /// .about("Used for configuration") + /// .arg(Arg::with_name("config_file") + /// .help("The configuration file to use"))) + /// .get_matches_from_safe(vec!["prog"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::MissingArgumentOrSubcommand); + /// ``` + /// [`SubCommand`]: ./struct.SubCommand.html + /// [`AppSettings::ArgRequiredElseHelp`]: ./enum.AppSettings.html#variant.ArgRequiredElseHelp + MissingArgumentOrSubcommand, + + /// Occurs when the user provides multiple values to an argument which doesn't allow that. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .arg(Arg::with_name("debug") + /// .long("debug") + /// .multiple(false)) + /// .get_matches_from_safe(vec!["prog", "--debug", "--debug"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::UnexpectedMultipleUsage); + /// ``` + UnexpectedMultipleUsage, + + /// Occurs when the user provides a value containing invalid UTF-8 for an argument and + /// [`AppSettings::StrictUtf8`] is set. + /// + /// # Platform Specific + /// + /// Non-Windows platforms only (such as Linux, Unix, macOS, etc.) + /// + /// # Examples + /// + #[cfg_attr(not(unix), doc = " ```ignore")] + #[cfg_attr(unix, doc = " ```")] + /// # use clap::{App, Arg, ErrorKind, AppSettings}; + /// # use std::os::unix::ffi::OsStringExt; + /// # use std::ffi::OsString; + /// let result = App::new("prog") + /// .setting(AppSettings::StrictUtf8) + /// .arg(Arg::with_name("utf8") + /// .short("u") + /// .takes_value(true)) + /// .get_matches_from_safe(vec![OsString::from("myprog"), + /// OsString::from("-u"), + /// OsString::from_vec(vec![0xE9])]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::InvalidUtf8); + /// ``` + /// [`AppSettings::StrictUtf8`]: ./enum.AppSettings.html#variant.StrictUtf8 + InvalidUtf8, + + /// Not a true "error" as it means `--help` or similar was used. + /// The help message will be sent to `stdout`. + /// + /// **Note**: If the help is displayed due to an error (such as missing subcommands) it will + /// be sent to `stderr` instead of `stdout`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .get_matches_from_safe(vec!["prog", "--help"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::HelpDisplayed); + /// ``` + HelpDisplayed, + + /// Not a true "error" as it means `--version` or similar was used. + /// The message will be sent to `stdout`. + /// + /// # Examples + /// + /// ```rust + /// # use clap::{App, Arg, ErrorKind}; + /// let result = App::new("prog") + /// .get_matches_from_safe(vec!["prog", "--version"]); + /// assert!(result.is_err()); + /// assert_eq!(result.unwrap_err().kind, ErrorKind::VersionDisplayed); + /// ``` + VersionDisplayed, + + /// Occurs when using the [`value_t!`] and [`values_t!`] macros to convert an argument value + /// into type `T`, but the argument you requested wasn't used. I.e. you asked for an argument + /// with name `config` to be converted, but `config` wasn't used by the user. + /// [`value_t!`]: ./macro.value_t!.html + /// [`values_t!`]: ./macro.values_t!.html + ArgumentNotFound, + + /// Represents an [I/O error]. + /// Can occur when writing to `stderr` or `stdout` or reading a configuration file. + /// [I/O error]: https://doc.rust-lang.org/std/io/struct.Error.html + Io, + + /// Represents a [Format error] (which is a part of [`Display`]). + /// Typically caused by writing to `stderr` or `stdout`. + /// + /// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html + /// [Format error]: https://doc.rust-lang.org/std/fmt/struct.Error.html + Format, +} + +/// Command Line Argument Parser Error +#[derive(Debug)] +pub struct Error { + /// Formatted error message + pub message: String, + /// The type of error + pub kind: ErrorKind, + /// Any additional information passed along, such as the argument name that caused the error + pub info: Option>, +} + +impl Error { + /// Should the message be written to `stdout` or not + pub fn use_stderr(&self) -> bool { + match self.kind { + ErrorKind::HelpDisplayed | ErrorKind::VersionDisplayed => false, + _ => true, + } + } + + /// Prints the error to `stderr` and exits with a status of `1` + pub fn exit(&self) -> ! { + if self.use_stderr() { + wlnerr!("{}", self.message); + process::exit(1); + } + let out = io::stdout(); + writeln!(&mut out.lock(), "{}", self.message).expect("Error writing Error to stdout"); + process::exit(0); + } + + #[doc(hidden)] + pub fn write_to(&self, w: &mut W) -> io::Result<()> { write!(w, "{}", self.message) } + + #[doc(hidden)] + pub fn argument_conflict( + arg: &AnyArg, + other: Option, + usage: U, + color: ColorWhen, + ) -> Self + where + O: Into, + U: Display, + { + let mut v = vec![arg.name().to_owned()]; + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' cannot be used with {}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*arg.to_string()), + match other { + Some(name) => { + let n = name.into(); + v.push(n.clone()); + c.warning(format!("'{}'", n)) + } + None => c.none("one or more of the other specified arguments".to_owned()), + }, + usage, + c.good("--help") + ), + kind: ErrorKind::ArgumentConflict, + info: Some(v), + } + } + + #[doc(hidden)] + pub fn empty_value(arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires a value but none was supplied\ + \n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::EmptyValue, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn invalid_value( + bad_val: B, + good_vals: &[G], + arg: &AnyArg, + usage: U, + color: ColorWhen, + ) -> Self + where + B: AsRef, + G: AsRef + Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + let suffix = suggestions::did_you_mean_value_suffix(bad_val.as_ref(), good_vals.iter()); + + let mut sorted = vec![]; + for v in good_vals { + let val = format!("{}", c.good(v)); + sorted.push(val); + } + sorted.sort(); + let valid_values = sorted.join(", "); + Error { + message: format!( + "{} '{}' isn't a valid value for '{}'\n\t\ + [possible values: {}]\n\ + {}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(bad_val.as_ref()), + c.warning(arg.to_string()), + valid_values, + suffix.0, + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidValue, + info: Some(vec![arg.name().to_owned(), bad_val.as_ref().to_owned()]), + } + } + + #[doc(hidden)] + pub fn invalid_subcommand( + subcmd: S, + did_you_mean: D, + name: N, + usage: U, + color: ColorWhen, + ) -> Self + where + S: Into, + D: AsRef + Display, + N: Display, + U: Display, + { + let s = subcmd.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The subcommand '{}' wasn't recognized\n\t\ + Did you mean '{}'?\n\n\ + If you believe you received this message in error, try \ + re-running with '{} {} {}'\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*s), + c.good(did_you_mean.as_ref()), + name, + c.good("--"), + &*s, + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidSubcommand, + info: Some(vec![s]), + } + } + + #[doc(hidden)] + pub fn unrecognized_subcommand(subcmd: S, name: N, color: ColorWhen) -> Self + where + S: Into, + N: Display, + { + let s = subcmd.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The subcommand '{}' wasn't recognized\n\n\ + {}\n\t\ + {} help ...\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*s), + c.warning("USAGE:"), + name, + c.good("--help") + ), + kind: ErrorKind::UnrecognizedSubcommand, + info: Some(vec![s]), + } + } + + #[doc(hidden)] + pub fn missing_required_argument(required: R, usage: U, color: ColorWhen) -> Self + where + R: Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The following required arguments were not provided:{}\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + required, + usage, + c.good("--help") + ), + kind: ErrorKind::MissingRequiredArgument, + info: None, + } + } + + #[doc(hidden)] + pub fn missing_subcommand(name: N, usage: U, color: ColorWhen) -> Self + where + N: AsRef + Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} '{}' requires a subcommand, but one was not provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(name), + usage, + c.good("--help") + ), + kind: ErrorKind::MissingSubcommand, + info: None, + } + } + + + #[doc(hidden)] + pub fn invalid_utf8(usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Invalid UTF-8 was detected in one or more arguments\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + usage, + c.good("--help") + ), + kind: ErrorKind::InvalidUtf8, + info: None, + } + } + + #[doc(hidden)] + pub fn too_many_values(val: V, arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + V: AsRef + Display + ToOwned, + U: Display, + { + let v = val.as_ref(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The value '{}' was provided to '{}', but it wasn't expecting \ + any more values\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(v), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::TooManyValues, + info: Some(vec![arg.name().to_owned(), v.to_owned()]), + } + } + + #[doc(hidden)] + pub fn too_few_values( + arg: &AnyArg, + min_vals: u64, + curr_vals: usize, + usage: U, + color: ColorWhen, + ) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires at least {} values, but only {} w{} \ + provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + c.warning(min_vals.to_string()), + c.warning(curr_vals.to_string()), + if curr_vals > 1 { "ere" } else { "as" }, + usage, + c.good("--help") + ), + kind: ErrorKind::TooFewValues, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn value_validation(arg: Option<&AnyArg>, err: String, color: ColorWhen) -> Self + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Invalid value{}: {}", + c.error("error:"), + if let Some(a) = arg { + format!(" for '{}'", c.warning(a.to_string())) + } else { + "".to_string() + }, + err + ), + kind: ErrorKind::ValueValidation, + info: None, + } + } + + #[doc(hidden)] + pub fn value_validation_auto(err: String) -> Self { + let n: Option<&AnyArg> = None; + Error::value_validation(n, err, ColorWhen::Auto) + } + + #[doc(hidden)] + pub fn wrong_number_of_values( + arg: &AnyArg, + num_vals: u64, + curr_vals: usize, + suffix: S, + usage: U, + color: ColorWhen, + ) -> Self + where + S: Display, + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' requires {} values, but {} w{} \ + provided\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + c.warning(num_vals.to_string()), + c.warning(curr_vals.to_string()), + suffix, + usage, + c.good("--help") + ), + kind: ErrorKind::WrongNumberOfValues, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn unexpected_multiple_usage(arg: &AnyArg, usage: U, color: ColorWhen) -> Self + where + U: Display, + { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} The argument '{}' was provided more than once, but cannot \ + be used multiple times\n\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(arg.to_string()), + usage, + c.good("--help") + ), + kind: ErrorKind::UnexpectedMultipleUsage, + info: Some(vec![arg.name().to_owned()]), + } + } + + #[doc(hidden)] + pub fn unknown_argument(arg: A, did_you_mean: &str, usage: U, color: ColorWhen) -> Self + where + A: Into, + U: Display, + { + let a = arg.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!( + "{} Found argument '{}' which wasn't expected, or isn't valid in \ + this context{}\n\ + {}\n\n\ + For more information try {}", + c.error("error:"), + c.warning(&*a), + if did_you_mean.is_empty() { + "\n".to_owned() + } else { + format!("{}\n", did_you_mean) + }, + usage, + c.good("--help") + ), + kind: ErrorKind::UnknownArgument, + info: Some(vec![a]), + } + } + + #[doc(hidden)] + pub fn io_error(e: &Error, color: ColorWhen) -> Self { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: color, + }); + Error { + message: format!("{} {}", c.error("error:"), e.description()), + kind: ErrorKind::Io, + info: None, + } + } + + #[doc(hidden)] + pub fn argument_not_found_auto(arg: A) -> Self + where + A: Into, + { + let a = arg.into(); + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }); + Error { + message: format!( + "{} The argument '{}' wasn't found", + c.error("error:"), + a.clone() + ), + kind: ErrorKind::ArgumentNotFound, + info: Some(vec![a]), + } + } + + /// Create an error with a custom description. + /// + /// This can be used in combination with `Error::exit` to exit your program + /// with a custom error message. + pub fn with_description(description: &str, kind: ErrorKind) -> Self { + let c = Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }); + Error { + message: format!("{} {}", c.error("error:"), description), + kind: kind, + info: None, + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { &*self.message } +} + +impl Display for Error { + fn fmt(&self, f: &mut std_fmt::Formatter) -> std_fmt::Result { writeln!(f, "{}", self.message) } +} + +impl From for Error { + fn from(e: io::Error) -> Self { Error::with_description(e.description(), ErrorKind::Io) } +} + +impl From for Error { + fn from(e: std_fmt::Error) -> Self { + Error::with_description(e.description(), ErrorKind::Format) + } +} diff --git a/clap/src/fmt.rs b/clap/src/fmt.rs new file mode 100644 index 000000000..108a6354b --- /dev/null +++ b/clap/src/fmt.rs @@ -0,0 +1,189 @@ +#[cfg(all(feature = "color", not(target_os = "windows")))] +use ansi_term::ANSIString; + +#[cfg(all(feature = "color", not(target_os = "windows")))] +use ansi_term::Colour::{Green, Red, Yellow}; + +#[cfg(feature = "color")] +use atty; +use std::fmt; +use std::env; + +#[doc(hidden)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum ColorWhen { + Auto, + Always, + Never, +} + +#[cfg(feature = "color")] +pub fn is_a_tty(stderr: bool) -> bool { + debugln!("is_a_tty: stderr={:?}", stderr); + let stream = if stderr { + atty::Stream::Stderr + } else { + atty::Stream::Stdout + }; + atty::is(stream) +} + +#[cfg(not(feature = "color"))] +pub fn is_a_tty(_: bool) -> bool { + debugln!("is_a_tty;"); + false +} + +pub fn is_term_dumb() -> bool { env::var("TERM").ok() == Some(String::from("dumb")) } + +#[doc(hidden)] +pub struct ColorizerOption { + pub use_stderr: bool, + pub when: ColorWhen, +} + +#[doc(hidden)] +pub struct Colorizer { + when: ColorWhen, +} + +macro_rules! color { + ($_self:ident, $c:ident, $m:expr) => { + match $_self.when { + ColorWhen::Auto => Format::$c($m), + ColorWhen::Always => Format::$c($m), + ColorWhen::Never => Format::None($m), + } + }; +} + +impl Colorizer { + pub fn new(option: ColorizerOption) -> Colorizer { + let is_a_tty = is_a_tty(option.use_stderr); + let is_term_dumb = is_term_dumb(); + Colorizer { + when: match option.when { + ColorWhen::Auto if is_a_tty && !is_term_dumb => ColorWhen::Auto, + ColorWhen::Auto => ColorWhen::Never, + when => when, + } + } + } + + pub fn good(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::good;"); + color!(self, Good, msg) + } + + pub fn warning(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::warning;"); + color!(self, Warning, msg) + } + + pub fn error(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::error;"); + color!(self, Error, msg) + } + + pub fn none(&self, msg: T) -> Format + where + T: fmt::Display + AsRef, + { + debugln!("Colorizer::none;"); + Format::None(msg) + } +} + +impl Default for Colorizer { + fn default() -> Self { + Colorizer::new(ColorizerOption { + use_stderr: true, + when: ColorWhen::Auto, + }) + } +} + +/// Defines styles for different types of error messages. Defaults to Error=Red, Warning=Yellow, +/// and Good=Green +#[derive(Debug)] +#[doc(hidden)] +pub enum Format { + /// Defines the style used for errors, defaults to Red + Error(T), + /// Defines the style used for warnings, defaults to Yellow + Warning(T), + /// Defines the style used for good values, defaults to Green + Good(T), + /// Defines no formatting style + None(T), +} + +#[cfg(all(feature = "color", not(target_os = "windows")))] +impl> Format { + fn format(&self) -> ANSIString { + match *self { + Format::Error(ref e) => Red.bold().paint(e.as_ref()), + Format::Warning(ref e) => Yellow.paint(e.as_ref()), + Format::Good(ref e) => Green.paint(e.as_ref()), + Format::None(ref e) => ANSIString::from(e.as_ref()), + } + } +} + +#[cfg(any(not(feature = "color"), target_os = "windows"))] +#[cfg_attr(feature = "lints", allow(match_same_arms))] +impl Format { + fn format(&self) -> &T { + match *self { + Format::Error(ref e) => e, + Format::Warning(ref e) => e, + Format::Good(ref e) => e, + Format::None(ref e) => e, + } + } +} + + +#[cfg(all(feature = "color", not(target_os = "windows")))] +impl> fmt::Display for Format { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) } +} + +#[cfg(any(not(feature = "color"), target_os = "windows"))] +impl fmt::Display for Format { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", &self.format()) } +} + +#[cfg(all(test, feature = "color", not(target_os = "windows")))] +mod test { + use ansi_term::ANSIString; + use ansi_term::Colour::{Green, Red, Yellow}; + use super::Format; + + #[test] + fn colored_output() { + let err = Format::Error("error"); + assert_eq!( + &*format!("{}", err), + &*format!("{}", Red.bold().paint("error")) + ); + let good = Format::Good("good"); + assert_eq!(&*format!("{}", good), &*format!("{}", Green.paint("good"))); + let warn = Format::Warning("warn"); + assert_eq!(&*format!("{}", warn), &*format!("{}", Yellow.paint("warn"))); + let none = Format::None("none"); + assert_eq!( + &*format!("{}", none), + &*format!("{}", ANSIString::from("none")) + ); + } +} diff --git a/clap/src/lib.rs b/clap/src/lib.rs new file mode 100644 index 000000000..0a3e1bb67 --- /dev/null +++ b/clap/src/lib.rs @@ -0,0 +1,629 @@ +// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/blob/master/CONTRIBUTORS.md). +// Licensed under the MIT license +// (see LICENSE or ) All files in the project carrying such +// notice may not be copied, modified, or distributed except according to those terms. + +//! `clap` is a simple-to-use, efficient, and full-featured library for parsing command line +//! arguments and subcommands when writing console/terminal applications. +//! +//! ## About +//! +//! `clap` is used to parse *and validate* the string of command line arguments provided by the user +//! at runtime. You provide the list of valid possibilities, and `clap` handles the rest. This means +//! you focus on your *applications* functionality, and less on the parsing and validating of +//! arguments. +//! +//! `clap` also provides the traditional version and help switches (or flags) 'for free' meaning +//! automatically with no configuration. It does this by checking list of valid possibilities you +//! supplied and adding only the ones you haven't already defined. If you are using subcommands, +//! `clap` will also auto-generate a `help` subcommand for you in addition to the traditional flags. +//! +//! Once `clap` parses the user provided string of arguments, it returns the matches along with any +//! applicable values. If the user made an error or typo, `clap` informs them of the mistake and +//! exits gracefully (or returns a `Result` type and allows you to perform any clean up prior to +//! exit). Because of this, you can make reasonable assumptions in your code about the validity of +//! the arguments. +//! +//! +//! ## Quick Example +//! +//! The following examples show a quick example of some of the very basic functionality of `clap`. +//! For more advanced usage, such as requirements, conflicts, groups, multiple values and +//! occurrences see the [documentation](https://docs.rs/clap/), [examples/] directory of +//! this repository or the [video tutorials]. +//! +//! **NOTE:** All of these examples are functionally the same, but show different styles in which to +//! use `clap` +//! +//! The first example shows a method that allows more advanced configuration options (not shown in +//! this small example), or even dynamically generating arguments when desired. The downside is it's +//! more verbose. +//! +//! ```no_run +//! // (Full example with detailed comments in examples/01b_quick_example.rs) +//! // +//! // This example demonstrates clap's full 'builder pattern' style of creating arguments which is +//! // more verbose, but allows easier editing, and at times more advanced options, or the possibility +//! // to generate arguments dynamically. +//! extern crate clap; +//! use clap::{Arg, App, SubCommand}; +//! +//! fn main() { +//! let matches = App::new("My Super Program") +//! .version("1.0") +//! .author("Kevin K. ") +//! .about("Does awesome things") +//! .arg(Arg::with_name("config") +//! .short("c") +//! .long("config") +//! .value_name("FILE") +//! .help("Sets a custom config file") +//! .takes_value(true)) +//! .arg(Arg::with_name("INPUT") +//! .help("Sets the input file to use") +//! .required(true) +//! .index(1)) +//! .arg(Arg::with_name("v") +//! .short("v") +//! .multiple(true) +//! .help("Sets the level of verbosity")) +//! .subcommand(SubCommand::with_name("test") +//! .about("controls testing features") +//! .version("1.3") +//! .author("Someone E. ") +//! .arg(Arg::with_name("debug") +//! .short("d") +//! .help("print debug information verbosely"))) +//! .get_matches(); +//! +//! // Gets a value for config if supplied by user, or defaults to "default.conf" +//! let config = matches.value_of("config").unwrap_or("default.conf"); +//! println!("Value for config: {}", config); +//! +//! // Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't +//! // required we could have used an 'if let' to conditionally get the value) +//! println!("Using input file: {}", matches.value_of("INPUT").unwrap()); +//! +//! // Vary the output based on how many times the user used the "verbose" flag +//! // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v' +//! match matches.occurrences_of("v") { +//! 0 => println!("No verbose info"), +//! 1 => println!("Some verbose info"), +//! 2 => println!("Tons of verbose info"), +//! 3 | _ => println!("Don't be crazy"), +//! } +//! +//! // You can handle information about subcommands by requesting their matches by name +//! // (as below), requesting just the name used, or both at the same time +//! if let Some(matches) = matches.subcommand_matches("test") { +//! if matches.is_present("debug") { +//! println!("Printing debug info..."); +//! } else { +//! println!("Printing normally..."); +//! } +//! } +//! +//! // more program logic goes here... +//! } +//! ``` +//! +//! The next example shows a far less verbose method, but sacrifices some of the advanced +//! configuration options (not shown in this small example). This method also takes a *very* minor +//! runtime penalty. +//! +//! ```no_run +//! // (Full example with detailed comments in examples/01a_quick_example.rs) +//! // +//! // This example demonstrates clap's "usage strings" method of creating arguments +//! // which is less verbose +//! extern crate clap; +//! use clap::{Arg, App, SubCommand}; +//! +//! fn main() { +//! let matches = App::new("myapp") +//! .version("1.0") +//! .author("Kevin K. ") +//! .about("Does awesome things") +//! .args_from_usage( +//! "-c, --config=[FILE] 'Sets a custom config file' +//! 'Sets the input file to use' +//! -v... 'Sets the level of verbosity'") +//! .subcommand(SubCommand::with_name("test") +//! .about("controls testing features") +//! .version("1.3") +//! .author("Someone E. ") +//! .arg_from_usage("-d, --debug 'Print debug information'")) +//! .get_matches(); +//! +//! // Same as previous example... +//! } +//! ``` +//! +//! This third method shows how you can use a YAML file to build your CLI and keep your Rust source +//! tidy or support multiple localized translations by having different YAML files for each +//! localization. +//! +//! First, create the `cli.yml` file to hold your CLI options, but it could be called anything we +//! like: +//! +//! ```yaml +//! name: myapp +//! version: "1.0" +//! author: Kevin K. +//! about: Does awesome things +//! args: +//! - config: +//! short: c +//! long: config +//! value_name: FILE +//! help: Sets a custom config file +//! takes_value: true +//! - INPUT: +//! help: Sets the input file to use +//! required: true +//! index: 1 +//! - verbose: +//! short: v +//! multiple: true +//! help: Sets the level of verbosity +//! subcommands: +//! - test: +//! about: controls testing features +//! version: "1.3" +//! author: Someone E. +//! args: +//! - debug: +//! short: d +//! help: print debug information +//! ``` +//! +//! Since this feature requires additional dependencies that not everyone may want, it is *not* +//! compiled in by default and we need to enable a feature flag in Cargo.toml: +//! +//! Simply change your `clap = "~2.27.0"` to `clap = {version = "~2.27.0", features = ["yaml"]}`. +//! +//! At last we create our `main.rs` file just like we would have with the previous two examples: +//! +//! ```ignore +//! // (Full example with detailed comments in examples/17_yaml.rs) +//! // +//! // This example demonstrates clap's building from YAML style of creating arguments which is far +//! // more clean, but takes a very small performance hit compared to the other two methods. +//! #[macro_use] +//! extern crate clap; +//! use clap::App; +//! +//! fn main() { +//! // The YAML file is found relative to the current file, similar to how modules are found +//! let yaml = load_yaml!("cli.yml"); +//! let matches = App::from_yaml(yaml).get_matches(); +//! +//! // Same as previous examples... +//! } +//! ``` +//! +//! Finally there is a macro version, which is like a hybrid approach offering the speed of the +//! builder pattern (the first example), but without all the verbosity. +//! +//! ```no_run +//! #[macro_use] +//! extern crate clap; +//! +//! fn main() { +//! let matches = clap_app!(myapp => +//! (version: "1.0") +//! (author: "Kevin K. ") +//! (about: "Does awesome things") +//! (@arg CONFIG: -c --config +takes_value "Sets a custom config file") +//! (@arg INPUT: +required "Sets the input file to use") +//! (@arg debug: -d ... "Sets the level of debugging information") +//! (@subcommand test => +//! (about: "controls testing features") +//! (version: "1.3") +//! (author: "Someone E. ") +//! (@arg verbose: -v --verbose "Print test information verbosely") +//! ) +//! ).get_matches(); +//! +//! // Same as before... +//! } +//! ``` +//! +//! If you were to compile any of the above programs and run them with the flag `--help` or `-h` (or +//! `help` subcommand, since we defined `test` as a subcommand) the following would be output +//! +//! ```text +//! $ myprog --help +//! My Super Program 1.0 +//! Kevin K. +//! Does awesome things +//! +//! USAGE: +//! MyApp [FLAGS] [OPTIONS] [SUBCOMMAND] +//! +//! FLAGS: +//! -h, --help Prints this message +//! -v Sets the level of verbosity +//! -V, --version Prints version information +//! +//! OPTIONS: +//! -c, --config Sets a custom config file +//! +//! ARGS: +//! INPUT The input file to use +//! +//! SUBCOMMANDS: +//! help Prints this message +//! test Controls testing features +//! ``` +//! +//! **NOTE:** You could also run `myapp test --help` to see similar output and options for the +//! `test` subcommand. +//! +//! ## Try it! +//! +//! ### Pre-Built Test +//! +//! To try out the pre-built example, use the following steps: +//! +//! * Clone the repository `$ git clone https://github.com/clap-rs/clap && cd clap-rs/tests` +//! * Compile the example `$ cargo build --release` +//! * Run the help info `$ ./target/release/claptests --help` +//! * Play with the arguments! +//! +//! ### BYOB (Build Your Own Binary) +//! +//! To test out `clap`'s default auto-generated help/version follow these steps: +//! +//! * Create a new cargo project `$ cargo new fake --bin && cd fake` +//! * Add `clap` to your `Cargo.toml` +//! +//! ```toml +//! [dependencies] +//! clap = "2" +//! ``` +//! +//! * Add the following to your `src/main.rs` +//! +//! ```no_run +//! extern crate clap; +//! use clap::App; +//! +//! fn main() { +//! App::new("fake").version("v1.0-beta").get_matches(); +//! } +//! ``` +//! +//! * Build your program `$ cargo build --release` +//! * Run with help or version `$ ./target/release/fake --help` or `$ ./target/release/fake +//! --version` +//! +//! ## Usage +//! +//! For full usage, add `clap` as a dependency in your `Cargo.toml` (it is **highly** recommended to +//! use the `~major.minor.patch` style versions in your `Cargo.toml`, for more information see +//! [Compatibility Policy](#compatibility-policy)) to use from crates.io: +//! +//! ```toml +//! [dependencies] +//! clap = "~2.27.0" +//! ``` +//! +//! Or get the latest changes from the master branch at github: +//! +//! ```toml +//! [dependencies.clap] +//! git = "https://github.com/clap-rs/clap.git" +//! ``` +//! +//! Add `extern crate clap;` to your crate root. +//! +//! Define a list of valid arguments for your program (see the +//! [documentation](https://docs.rs/clap/) or [examples/] directory of this repo) +//! +//! Then run `cargo build` or `cargo update && cargo build` for your project. +//! +//! ### Optional Dependencies / Features +//! +//! #### Features enabled by default +//! +//! * `suggestions`: Turns on the `Did you mean '--myoption'?` feature for when users make typos. (builds dependency `strsim`) +//! * `color`: Turns on colored error messages. This feature only works on non-Windows OSs. (builds dependency `ansi-term` and `atty`) +//! * `wrap_help`: Wraps the help at the actual terminal width when +//! available, instead of 120 characters. (builds dependency `textwrap` +//! with feature `term_size`) +//! +//! To disable these, add this to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies.clap] +//! version = "~2.27.0" +//! default-features = false +//! ``` +//! +//! You can also selectively enable only the features you'd like to include, by adding: +//! +//! ```toml +//! [dependencies.clap] +//! version = "~2.27.0" +//! default-features = false +//! +//! # Cherry-pick the features you'd like to use +//! features = [ "suggestions", "color" ] +//! ``` +//! +//! #### Opt-in features +//! +//! * **"yaml"**: Enables building CLIs from YAML documents. (builds dependency `yaml-rust`) +//! * **"unstable"**: Enables unstable `clap` features that may change from release to release +//! +//! ### Dependencies Tree +//! +//! The following graphic depicts `clap`s dependency graph (generated using +//! [cargo-graph](https://github.com/kbknapp/cargo-graph)). +//! +//! * **Dashed** Line: Optional dependency +//! * **Red** Color: **NOT** included by default (must use cargo `features` to enable) +//! * **Blue** Color: Dev dependency, only used while developing. +//! +//! ![clap dependencies](https://raw.githubusercontent.com/clap-rs/clap/master/clap_dep_graph.png) +//! +//! ### More Information +//! +//! You can find complete documentation on the [docs.rs](https://docs.rs/clap/) for this project. +//! +//! You can also find usage examples in the [examples/] directory of this repo. +//! +//! #### Video Tutorials +//! +//! There's also the video tutorial series [Argument Parsing with Rust v2][video tutorials]. +//! +//! These videos slowly trickle out as I finish them and currently a work in progress. +//! +//! ## How to Contribute +//! +//! Contributions are always welcome! And there is a multitude of ways in which you can help +//! depending on what you like to do, or are good at. Anything from documentation, code cleanup, +//! issue completion, new features, you name it, even filing issues is contributing and greatly +//! appreciated! +//! +//! Another really great way to help is if you find an interesting, or helpful way in which to use +//! `clap`. You can either add it to the [examples/] directory, or file an issue and tell +//! me. I'm all about giving credit where credit is due :) +//! +//! Please read [CONTRIBUTING.md](https://raw.githubusercontent.com/clap-rs/clap/master/.github/CONTRIBUTING.md) before you start contributing. +//! +//! +//! ### Testing Code +//! +//! To test with all features both enabled and disabled, you can run theese commands: +//! +//! ```text +//! $ cargo test --no-default-features +//! $ cargo test --features "yaml unstable" +//! ``` +//! +//! Alternatively, if you have [`just`](https://github.com/casey/just) installed you can run the +//! prebuilt recipes. *Not* using `just` is perfectly fine as well, it simply bundles commands +//! automatically. +//! +//! For example, to test the code, as above simply run: +//! +//! ```text +//! $ just run-tests +//! ``` +//! +//! From here on, I will list the appropriate `cargo` command as well as the `just` command. +//! +//! Sometimes it's helpful to only run a subset of the tests, which can be done via: +//! +//! ```text +//! $ cargo test --test +//! +//! # Or +//! +//! $ just run-test +//! ``` +//! +//! ### Linting Code +//! +//! During the CI process `clap` runs against many different lints using +//! [`clippy`](https://github.com/Manishearth/rust-clippy). In order to check if these lints pass on +//! your own computer prior to submitting a PR you'll need a nightly compiler. +//! +//! In order to check the code for lints run either: +//! +//! ```text +//! $ rustup override add nightly +//! $ cargo build --features lints +//! $ rustup override remove +//! +//! # Or +//! +//! $ just lint +//! ``` +//! +//! ### Debugging Code +//! +//! Another helpful technique is to see the `clap` debug output while developing features. In order +//! to see the debug output while running the full test suite or individual tests, run: +//! +//! ```text +//! $ cargo test --features debug +//! +//! # Or for individual tests +//! $ cargo test --test --features debug +//! +//! # The corresponding just command for individual debugging tests is: +//! $ just debug +//! ``` +//! +//! ### Goals +//! +//! There are a few goals of `clap` that I'd like to maintain throughout contributions. If your +//! proposed changes break, or go against any of these goals we'll discuss the changes further +//! before merging (but will *not* be ignored, all contributes are welcome!). These are by no means +//! hard-and-fast rules, as I'm no expert and break them myself from time to time (even if by +//! mistake or ignorance). +//! +//! * Remain backwards compatible when possible +//! - If backwards compatibility *must* be broken, use deprecation warnings if at all possible before +//! removing legacy code - This does not apply for security concerns +//! * Parse arguments quickly +//! - Parsing of arguments shouldn't slow down usage of the main program - This is also true of +//! generating help and usage information (although *slightly* less stringent, as the program is about +//! to exit) +//! * Try to be cognizant of memory usage +//! - Once parsing is complete, the memory footprint of `clap` should be low since the main program +//! is the star of the show +//! * `panic!` on *developer* error, exit gracefully on *end-user* error +//! +//! ### Compatibility Policy +//! +//! Because `clap` takes `SemVer` and compatibility seriously, this is the official policy regarding +//! breaking changes and previous versions of Rust. +//! +//! `clap` will pin the minimum required version of Rust to the CI builds. Bumping the minimum +//! version of Rust is considered a minor breaking change, meaning *at a minimum* the minor version +//! of `clap` will be bumped. +//! +//! In order to keep from being surprised by breaking changes, it is **highly** recommended to use +//! the `~major.minor.patch` style in your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] clap = "~2.27.0" +//! ``` +//! +//! This will cause *only* the patch version to be updated upon a `cargo update` call, and therefore +//! cannot break due to new features, or bumped minimum versions of Rust. +//! +//! #### Minimum Version of Rust +//! +//! `clap` will officially support current stable Rust, minus two releases, but may work with prior +//! releases as well. For example, current stable Rust at the time of this writing is 1.21.0, +//! meaning `clap` is guaranteed to compile with 1.19.0 and beyond. At the 1.22.0 release, `clap` +//! will be guaranteed to compile with 1.20.0 and beyond, etc. +//! +//! Upon bumping the minimum version of Rust (assuming it's within the stable-2 range), it *must* be +//! clearly annotated in the `CHANGELOG.md` +//! +//! ## License +//! +//! `clap` is licensed under the MIT license. Please read the [LICENSE-MIT][license] file in +//! this repository for more information. +//! +//! [examples/]: https://github.com/clap-rs/clap/tree/master/examples +//! [video tutorials]: https://www.youtube.com/playlist?list=PLza5oFLQGTl2Z5T8g1pRkIynR3E0_pc7U +//! [license]: https://raw.githubusercontent.com/clap-rs/clap/master/LICENSE-MIT + +#![crate_type = "lib"] +#![doc(html_root_url = "https://docs.rs/clap/2.33.0")] +#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, + unused_import_braces, unused_allocation)] +// Lints we'd like to deny but are currently failing for upstream crates +// unused_qualifications (bitflags, clippy) +// trivial_numeric_casts (bitflags) +#![cfg_attr(not(any(feature = "lints", feature = "nightly")), forbid(unstable_features))] +#![cfg_attr(feature = "lints", feature(plugin))] +#![cfg_attr(feature = "lints", plugin(clippy))] +// Need to disable deny(warnings) while deprecations are active +// #![cfg_attr(feature = "lints", deny(warnings))] +#![cfg_attr(feature = "lints", allow(cyclomatic_complexity))] +#![cfg_attr(feature = "lints", allow(doc_markdown))] +#![cfg_attr(feature = "lints", allow(explicit_iter_loop))] + +#[cfg(all(feature = "color", not(target_os = "windows")))] +extern crate ansi_term; +#[cfg(feature = "color")] +extern crate atty; +#[macro_use] +extern crate bitflags; +#[cfg(feature = "suggestions")] +extern crate strsim; +#[cfg(feature = "wrap_help")] +extern crate term_size; +extern crate textwrap; +extern crate unicode_width; +#[cfg(feature = "vec_map")] +extern crate vec_map; +#[cfg(feature = "yaml")] +extern crate yaml_rust; + +#[cfg(feature = "yaml")] +pub use yaml_rust::YamlLoader; +pub use args::{Arg, ArgGroup, ArgMatches, ArgSettings, OsValues, SubCommand, Values}; +pub use app::{App, AppSettings}; +pub use fmt::Format; +pub use errors::{Error, ErrorKind, Result}; +pub use completions::Shell; + +#[macro_use] +mod macros; +mod app; +mod args; +mod usage_parser; +mod fmt; +mod suggestions; +mod errors; +mod osstringext; +mod strext; +mod completions; +mod map; + +const INTERNAL_ERROR_MSG: &'static str = "Fatal internal error. Please consider filing a bug \ + report at https://github.com/clap-rs/clap/issues"; +const INVALID_UTF8: &'static str = "unexpected invalid UTF-8 code point"; + +#[cfg(unstable)] +pub use derive::{ArgEnum, ClapApp, FromArgMatches, IntoApp}; + +#[cfg(unstable)] +mod derive { + /// @TODO @release @docs + pub trait ClapApp: IntoApp + FromArgMatches + Sized { + /// @TODO @release @docs + fn parse() -> Self { Self::from_argmatches(Self::into_app().get_matches()) } + + /// @TODO @release @docs + fn parse_from(argv: I) -> Self + where + I: IntoIterator, + T: Into + Clone, + { + Self::from_argmatches(Self::into_app().get_matches_from(argv)) + } + + /// @TODO @release @docs + fn try_parse() -> Result { + Self::try_from_argmatches(Self::into_app().get_matches_safe()?) + } + + + /// @TODO @release @docs + fn try_parse_from(argv: I) -> Result + where + I: IntoIterator, + T: Into + Clone, + { + Self::try_from_argmatches(Self::into_app().get_matches_from_safe(argv)?) + } + } + + /// @TODO @release @docs + pub trait IntoApp { + /// @TODO @release @docs + fn into_app<'a, 'b>() -> clap::App<'a, 'b>; + } + + /// @TODO @release @docs + pub trait FromArgMatches: Sized { + /// @TODO @release @docs + fn from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Self; + + /// @TODO @release @docs + fn try_from_argmatches<'a>(matches: clap::ArgMatches<'a>) -> Result; + } + + /// @TODO @release @docs + pub trait ArgEnum {} +} diff --git a/clap/src/macros.rs b/clap/src/macros.rs new file mode 100644 index 000000000..8198e19ba --- /dev/null +++ b/clap/src/macros.rs @@ -0,0 +1,1108 @@ +/// A convenience macro for loading the YAML file at compile time (relative to the current file, +/// like modules work). That YAML object can then be passed to this function. +/// +/// # Panics +/// +/// The YAML file must be properly formatted or this function will panic!(). A good way to +/// ensure this doesn't happen is to run your program with the `--help` switch. If this passes +/// without error, you needn't worry because the YAML is properly formatted. +/// +/// # Examples +/// +/// The following example shows how to load a properly formatted YAML file to build an instance +/// of an `App` struct. +/// +/// ```ignore +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let yml = load_yaml!("app.yml"); +/// let app = App::from_yaml(yml); +/// +/// // continued logic goes here, such as `app.get_matches()` etc. +/// # } +/// ``` +#[cfg(feature = "yaml")] +#[macro_export] +macro_rules! load_yaml { + ($yml:expr) => ( + &::clap::YamlLoader::load_from_str(include_str!($yml)).expect("failed to load YAML file")[0] + ); +} + +/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] from an +/// argument value. This macro returns a `Result` which allows you as the developer to +/// decide what you'd like to do on a failed parse. There are two types of errors, parse failures +/// and those where the argument wasn't present (such as a non-required argument). You can use +/// it to get a single value, or a iterator as with the [`ArgMatches::values_of`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") +/// .get_matches(); +/// +/// let len = value_t!(matches.value_of("length"), u32).unwrap_or_else(|e| e.exit()); +/// let also_len = value_t!(matches, "length", u32).unwrap_or_else(|e| e.exit()); +/// +/// println!("{} + 2: {}", len, len + 2); +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`ArgMatches::values_of`]: ./struct.ArgMatches.html#method.values_of +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +#[macro_export] +macro_rules! value_t { + ($m:ident, $v:expr, $t:ty) => { + value_t!($m.value_of($v), $t) + }; + ($m:ident.value_of($v:expr), $t:ty) => { + if let Some(v) = $m.value_of($v) { + match v.parse::<$t>() { + Ok(val) => Ok(val), + Err(_) => + Err(::clap::Error::value_validation_auto( + format!("The argument '{}' isn't a valid value", v))), + } + } else { + Err(::clap::Error::argument_not_found_auto($v)) + } + }; +} + +/// Convenience macro getting a typed value `T` where `T` implements [`std::str::FromStr`] or +/// exiting upon error, instead of returning a [`Result`] type. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[length] 'Set the length to use as a pos whole num, i.e. 20'") +/// .get_matches(); +/// +/// let len = value_t_or_exit!(matches.value_of("length"), u32); +/// let also_len = value_t_or_exit!(matches, "length", u32); +/// +/// println!("{} + 2: {}", len, len + 2); +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +/// [`value_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.value_t!.html +#[macro_export] +macro_rules! value_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + value_t_or_exit!($m.value_of($v), $t) + }; + ($m:ident.value_of($v:expr), $t:ty) => { + if let Some(v) = $m.value_of($v) { + match v.parse::<$t>() { + Ok(val) => val, + Err(_) => + ::clap::Error::value_validation_auto( + format!("The argument '{}' isn't a valid value", v)).exit(), + } + } else { + ::clap::Error::argument_not_found_auto($v).exit() + } + }; +} + +/// Convenience macro getting a typed value [`Vec`] where `T` implements [`std::str::FromStr`] +/// This macro returns a [`clap::Result>`] which allows you as the developer to decide +/// what you'd like to do on a failed parse. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") +/// .get_matches(); +/// +/// let vals = values_t!(matches.values_of("seq"), u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// let vals = values_t!(matches, "seq", u32).unwrap_or_else(|e| e.exit()); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// # } +/// ``` +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +/// [`clap::Result>`]: ./type.Result.html +#[macro_export] +macro_rules! values_t { + ($m:ident, $v:expr, $t:ty) => { + values_t!($m.values_of($v), $t) + }; + ($m:ident.values_of($v:expr), $t:ty) => { + if let Some(vals) = $m.values_of($v) { + let mut tmp = vec![]; + let mut err = None; + for pv in vals { + match pv.parse::<$t>() { + Ok(rv) => tmp.push(rv), + Err(..) => { + err = Some(::clap::Error::value_validation_auto( + format!("The argument '{}' isn't a valid value", pv))); + break + } + } + } + match err { + Some(e) => Err(e), + None => Ok(tmp), + } + } else { + Err(::clap::Error::argument_not_found_auto($v)) + } + }; +} + +/// Convenience macro getting a typed value [`Vec`] where `T` implements [`std::str::FromStr`] +/// or exiting upon error. +/// +/// **NOTE:** This macro is for backwards compatibility sake. Prefer +/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`] +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let matches = App::new("myapp") +/// .arg_from_usage("[seq]... 'A sequence of pos whole nums, i.e. 20 45'") +/// .get_matches(); +/// +/// let vals = values_t_or_exit!(matches.values_of("seq"), u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// +/// // type for example only +/// let vals: Vec = values_t_or_exit!(matches, "seq", u32); +/// for v in &vals { +/// println!("{} + 2: {}", v, v + 2); +/// } +/// # } +/// ``` +/// [`values_t!(/* ... */).unwrap_or_else(|e| e.exit())`]: ./macro.values_t!.html +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html +#[macro_export] +macro_rules! values_t_or_exit { + ($m:ident, $v:expr, $t:ty) => { + values_t_or_exit!($m.values_of($v), $t) + }; + ($m:ident.values_of($v:expr), $t:ty) => { + if let Some(vals) = $m.values_of($v) { + vals.map(|v| v.parse::<$t>().unwrap_or_else(|_|{ + ::clap::Error::value_validation_auto( + format!("One or more arguments aren't valid values")).exit() + })).collect::>() + } else { + ::clap::Error::argument_not_found_auto($v).exit() + } + }; +} + +// _clap_count_exprs! is derived from https://github.com/DanielKeep/rust-grabbag +// commit: 82a35ca5d9a04c3b920622d542104e3310ee5b07 +// License: MIT +// Copyright ⓒ 2015 grabbag contributors. +// Licensed under the MIT license (see LICENSE or ) or the Apache License, Version 2.0 (see LICENSE of +// ), at your option. All +// files in the project carrying such notice may not be copied, modified, +// or distributed except according to those terms. +// +/// Counts the number of comma-delimited expressions passed to it. The result is a compile-time +/// evaluable expression, suitable for use as a static array size, or the value of a `const`. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate clap; +/// # fn main() { +/// const COUNT: usize = _clap_count_exprs!(a, 5+1, "hi there!".into_string()); +/// assert_eq!(COUNT, 3); +/// # } +/// ``` +#[macro_export] +macro_rules! _clap_count_exprs { + () => { 0 }; + ($e:expr) => { 1 }; + ($e:expr, $($es:expr),+) => { 1 + $crate::_clap_count_exprs!($($es),*) }; +} + +/// Convenience macro to generate more complete enums with variants to be used as a type when +/// parsing arguments. This enum also provides a `variants()` function which can be used to +/// retrieve a `Vec<&'static str>` of the variant names, as well as implementing [`FromStr`] and +/// [`Display`] automatically. +/// +/// **NOTE:** Case insensitivity is supported for ASCII characters only. It's highly recommended to +/// use [`Arg::case_insensitive(true)`] for args that will be used with these enums +/// +/// **NOTE:** This macro automatically implements [`std::str::FromStr`] and [`std::fmt::Display`] +/// +/// **NOTE:** These enums support pub (or not) and uses of the `#[derive()]` traits +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::{App, Arg}; +/// arg_enum!{ +/// #[derive(PartialEq, Debug)] +/// pub enum Foo { +/// Bar, +/// Baz, +/// Qux +/// } +/// } +/// // Foo enum can now be used via Foo::Bar, or Foo::Baz, etc +/// // and implements std::str::FromStr to use with the value_t! macros +/// fn main() { +/// let m = App::new("app") +/// .arg(Arg::from_usage(" 'the foo'") +/// .possible_values(&Foo::variants()) +/// .case_insensitive(true)) +/// .get_matches_from(vec![ +/// "app", "baz" +/// ]); +/// let f = value_t!(m, "foo", Foo).unwrap_or_else(|e| e.exit()); +/// +/// assert_eq!(f, Foo::Baz); +/// } +/// ``` +/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html +/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +/// [`std::fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html +/// [`Arg::case_insensitive(true)`]: ./struct.Arg.html#method.case_insensitive +#[macro_export] +macro_rules! arg_enum { + (@as_item $($i:item)*) => ($($i)*); + (@impls ( $($tts:tt)* ) -> ($e:ident, $($v:ident),+)) => { + arg_enum!(@as_item + $($tts)* + + impl ::std::str::FromStr for $e { + type Err = String; + + fn from_str(s: &str) -> ::std::result::Result { + #[allow(deprecated, unused_imports)] + use ::std::ascii::AsciiExt; + match s { + $(stringify!($v) | + _ if s.eq_ignore_ascii_case(stringify!($v)) => Ok($e::$v)),+, + _ => Err({ + let v = vec![ + $(stringify!($v),)+ + ]; + format!("valid values: {}", + v.join(", ")) + }), + } + } + } + impl ::std::fmt::Display for $e { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match *self { + $($e::$v => write!(f, stringify!($v)),)+ + } + } + } + impl $e { + #[allow(dead_code)] + pub fn variants() -> [&'static str; $crate::_clap_count_exprs!($(stringify!($v)),+)] { + [ + $(stringify!($v),)+ + ] + } + }); + }; + ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + ($(#[$($m:meta),+])+ enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + ($(#[$($m),+])+ + enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (pub enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + (pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (pub enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + (pub enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (enum $e:ident { $($v:ident $(=$val:expr)*,)+ } ) => { + arg_enum!(@impls + (enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; + (enum $e:ident { $($v:ident $(=$val:expr)*),+ } ) => { + arg_enum!(@impls + (enum $e { + $($v$(=$val)*),+ + }) -> ($e, $($v),+) + ); + }; +} + +/// Allows you to pull the version from your Cargo.toml at compile time as +/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .version(crate_version!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_version { + () => { + env!("CARGO_PKG_VERSION") + }; +} + +/// Allows you to pull the authors for the app from your Cargo.toml at +/// compile time in the form: +/// `"author1 lastname :author2 lastname "` +/// +/// You can replace the colons with a custom separator by supplying a +/// replacement string, so, for example, +/// `crate_authors!(",\n")` would become +/// `"author1 lastname ,\nauthor2 lastname ,\nauthor3 lastname "` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .author(crate_authors!("\n")) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_authors { + ($sep:expr) => {{ + use std::ops::Deref; + use std::sync::{ONCE_INIT, Once}; + + #[allow(missing_copy_implementations)] + #[allow(dead_code)] + struct CargoAuthors { __private_field: () }; + + impl Deref for CargoAuthors { + type Target = str; + + #[allow(unsafe_code)] + fn deref(&self) -> &'static str { + static ONCE: Once = ONCE_INIT; + static mut VALUE: *const String = 0 as *const String; + + unsafe { + ONCE.call_once(|| { + let s = env!("CARGO_PKG_AUTHORS").replace(':', $sep); + VALUE = Box::into_raw(Box::new(s)); + }); + + &(*VALUE)[..] + } + } + } + + &*CargoAuthors { __private_field: () } + }}; + () => { + env!("CARGO_PKG_AUTHORS") + }; +} + +/// Allows you to pull the description from your Cargo.toml at compile time. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new("app") +/// .about(crate_description!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_description { + () => { + env!("CARGO_PKG_DESCRIPTION") + }; +} + +/// Allows you to pull the name from your Cargo.toml at compile time. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # use clap::App; +/// # fn main() { +/// let m = App::new(crate_name!()) +/// .get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! crate_name { + () => { + env!("CARGO_PKG_NAME") + }; +} + +/// Allows you to build the `App` instance from your Cargo.toml at compile time. +/// +/// Equivalent to using the `crate_*!` macros with their respective fields. +/// +/// Provided separator is for the [`crate_authors!`](macro.crate_authors.html) macro, +/// refer to the documentation therefor. +/// +/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically, +/// and therefore won't change the generated output until you recompile. +/// +/// **Pro Tip:** In some cases you can "trick" the compiler into triggering a rebuild when your +/// `Cargo.toml` is changed by including this in your `src/main.rs` file +/// `include_str!("../Cargo.toml");` +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # fn main() { +/// let m = app_from_crate!().get_matches(); +/// # } +/// ``` +#[cfg(not(feature = "no_cargo"))] +#[macro_export] +macro_rules! app_from_crate { + () => { + $crate::App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!()) + .about(crate_description!()) + }; + ($sep:expr) => { + $crate::App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!($sep)) + .about(crate_description!()) + }; +} + +/// Build `App`, `Arg`s, `SubCommand`s and `Group`s with Usage-string like input +/// but without the associated parsing runtime cost. +/// +/// `clap_app!` also supports several shorthand syntaxes. +/// +/// # Examples +/// +/// ```no_run +/// # #[macro_use] +/// # extern crate clap; +/// # fn main() { +/// let matches = clap_app!(myapp => +/// (version: "1.0") +/// (author: "Kevin K. ") +/// (about: "Does awesome things") +/// (@arg CONFIG: -c --config +takes_value "Sets a custom config file") +/// (@arg INPUT: +required "Sets the input file to use") +/// (@arg debug: -d ... "Sets the level of debugging information") +/// (@group difficulty => +/// (@arg hard: -h --hard "Sets hard mode") +/// (@arg normal: -n --normal "Sets normal mode") +/// (@arg easy: -e --easy "Sets easy mode") +/// ) +/// (@subcommand test => +/// (about: "controls testing features") +/// (version: "1.3") +/// (author: "Someone E. ") +/// (@arg verbose: -v --verbose "Print test information verbosely") +/// ) +/// ) +/// .get_matches(); +/// # } +/// ``` +/// # Shorthand Syntax for Args +/// +/// * A single hyphen followed by a character (such as `-c`) sets the [`Arg::short`] +/// * A double hyphen followed by a character or word (such as `--config`) sets [`Arg::long`] +/// * If one wishes to use a [`Arg::long`] with a hyphen inside (i.e. `--config-file`), you +/// must use `--("config-file")` due to limitations of the Rust macro system. +/// * Three dots (`...`) sets [`Arg::multiple(true)`] +/// * Angled brackets after either a short or long will set [`Arg::value_name`] and +/// `Arg::required(true)` such as `--config ` = `Arg::value_name("FILE")` and +/// `Arg::required(true)` +/// * Square brackets after either a short or long will set [`Arg::value_name`] and +/// `Arg::required(false)` such as `--config [FILE]` = `Arg::value_name("FILE")` and +/// `Arg::required(false)` +/// * There are short hand syntaxes for Arg methods that accept booleans +/// * A plus sign will set that method to `true` such as `+required` = `Arg::required(true)` +/// * An exclamation will set that method to `false` such as `!required` = `Arg::required(false)` +/// * A `#{min, max}` will set [`Arg::min_values(min)`] and [`Arg::max_values(max)`] +/// * An asterisk (`*`) will set `Arg::required(true)` +/// * Curly brackets around a `fn` will set [`Arg::validator`] as in `{fn}` = `Arg::validator(fn)` +/// * An Arg method that accepts a string followed by square brackets will set that method such as +/// `conflicts_with[FOO]` will set `Arg::conflicts_with("FOO")` (note the lack of quotes around +/// `FOO` in the macro) +/// * An Arg method that takes a string and can be set multiple times (such as +/// [`Arg::conflicts_with`]) followed by square brackets and a list of values separated by spaces +/// will set that method such as `conflicts_with[FOO BAR BAZ]` will set +/// `Arg::conflicts_with("FOO")`, `Arg::conflicts_with("BAR")`, and `Arg::conflicts_with("BAZ")` +/// (note the lack of quotes around the values in the macro) +/// +/// # Shorthand Syntax for Groups +/// +/// * There are short hand syntaxes for `ArgGroup` methods that accept booleans +/// * A plus sign will set that method to `true` such as `+required` = `ArgGroup::required(true)` +/// * An exclamation will set that method to `false` such as `!required` = `ArgGroup::required(false)` +/// +/// [`Arg::short`]: ./struct.Arg.html#method.short +/// [`Arg::long`]: ./struct.Arg.html#method.long +/// [`Arg::multiple(true)`]: ./struct.Arg.html#method.multiple +/// [`Arg::value_name`]: ./struct.Arg.html#method.value_name +/// [`Arg::min_values(min)`]: ./struct.Arg.html#method.min_values +/// [`Arg::max_values(max)`]: ./struct.Arg.html#method.max_values +/// [`Arg::validator`]: ./struct.Arg.html#method.validator +/// [`Arg::conflicts_with`]: ./struct.Arg.html#method.conflicts_with +#[macro_export] +macro_rules! clap_app { + (@app ($builder:expr)) => { $builder }; + (@app ($builder:expr) (@arg ($name:expr): $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.arg( + clap_app!{ @arg ($crate::Arg::with_name($name)) (-) $($tail)* })) + $($tt)* + } + }; + (@app ($builder:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.arg( + clap_app!{ @arg ($crate::Arg::with_name(stringify!($name))) (-) $($tail)* })) + $($tt)* + } + }; + (@app ($builder:expr) (@setting $setting:ident) $($tt:tt)*) => { + clap_app!{ @app + ($builder.setting($crate::AppSettings::$setting)) + $($tt)* + } + }; +// Treat the application builder as an argument to set its attributes + (@app ($builder:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { + clap_app!{ @app (clap_app!{ @arg ($builder) $($attr)* }) $($tt)* } + }; + (@app ($builder:expr) (@group $name:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name))) $($tail)* }) + $($tt)* + } + }; + (@app ($builder:expr) (@group $name:ident !$ident:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(false)) $($tail)* }) + $($tt)* + } + }; + (@app ($builder:expr) (@group $name:ident +$ident:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + (clap_app!{ @group ($builder, $crate::ArgGroup::with_name(stringify!($name)).$ident(true)) $($tail)* }) + $($tt)* + } + }; +// Handle subcommand creation + (@app ($builder:expr) (@subcommand $name:ident => $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @app + ($builder.subcommand( + clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } + )) + $($tt)* + } + }; +// Yaml like function calls - used for setting various meta directly against the app + (@app ($builder:expr) ($ident:ident: $($v:expr),*) $($tt:tt)*) => { +// clap_app!{ @app ($builder.$ident($($v),*)) $($tt)* } + clap_app!{ @app + ($builder.$ident($($v),*)) + $($tt)* + } + }; + +// Add members to group and continue argument handling with the parent builder + (@group ($builder:expr, $group:expr)) => { $builder.group($group) }; + // Treat the group builder as an argument to set its attributes + (@group ($builder:expr, $group:expr) (@attributes $($attr:tt)*) $($tt:tt)*) => { + clap_app!{ @group ($builder, clap_app!{ @arg ($group) (-) $($attr)* }) $($tt)* } + }; + (@group ($builder:expr, $group:expr) (@arg $name:ident: $($tail:tt)*) $($tt:tt)*) => { + clap_app!{ @group + (clap_app!{ @app ($builder) (@arg $name: $($tail)*) }, + $group.arg(stringify!($name))) + $($tt)* + } + }; + +// No more tokens to munch + (@arg ($arg:expr) $modes:tt) => { $arg }; +// Shorthand tokens influenced by the usage_string + (@arg ($arg:expr) $modes:tt --($long:expr) $($tail:tt)*) => { + clap_app!{ @arg ($arg.long($long)) $modes $($tail)* } + }; + (@arg ($arg:expr) $modes:tt --$long:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.long(stringify!($long))) $modes $($tail)* } + }; + (@arg ($arg:expr) $modes:tt -$short:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.short(stringify!($short))) $modes $($tail)* } + }; + (@arg ($arg:expr) (-) <$var:ident> $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value +required $($tail)* } + }; + (@arg ($arg:expr) (+) <$var:ident> $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } + }; + (@arg ($arg:expr) (-) [$var:ident] $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) +takes_value $($tail)* } + }; + (@arg ($arg:expr) (+) [$var:ident] $($tail:tt)*) => { + clap_app!{ @arg ($arg.value_name(stringify!($var))) (+) $($tail)* } + }; + (@arg ($arg:expr) $modes:tt ... $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes +multiple $($tail)* } + }; +// Shorthand magic + (@arg ($arg:expr) $modes:tt #{$n:expr, $m:expr} $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes min_values($n) max_values($m) $($tail)* } + }; + (@arg ($arg:expr) $modes:tt * $($tail:tt)*) => { + clap_app!{ @arg ($arg) $modes +required $($tail)* } + }; +// !foo -> .foo(false) + (@arg ($arg:expr) $modes:tt !$ident:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident(false)) $modes $($tail)* } + }; +// +foo -> .foo(true) + (@arg ($arg:expr) $modes:tt +$ident:ident $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident(true)) $modes $($tail)* } + }; +// Validator + (@arg ($arg:expr) $modes:tt {$fn_:expr} $($tail:tt)*) => { + clap_app!{ @arg ($arg.validator($fn_)) $modes $($tail)* } + }; + (@as_expr $expr:expr) => { $expr }; +// Help + (@arg ($arg:expr) $modes:tt $desc:tt) => { $arg.help(clap_app!{ @as_expr $desc }) }; +// Handle functions that need to be called multiple times for each argument + (@arg ($arg:expr) $modes:tt $ident:ident[$($target:ident)*] $($tail:tt)*) => { + clap_app!{ @arg ($arg $( .$ident(stringify!($target)) )*) $modes $($tail)* } + }; +// Inherit builder's functions, e.g. `index(2)`, `requires_if("val", "arg")` + (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr),*) $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* } + }; +// Inherit builder's functions with trailing comma, e.g. `index(2,)`, `requires_if("val", "arg",)` + (@arg ($arg:expr) $modes:tt $ident:ident($($expr:expr,)*) $($tail:tt)*) => { + clap_app!{ @arg ($arg.$ident($($expr),*)) $modes $($tail)* } + }; + +// Build a subcommand outside of an app. + (@subcommand $name:ident => $($tail:tt)*) => { + clap_app!{ @app ($crate::SubCommand::with_name(stringify!($name))) $($tail)* } + }; +// Start the magic + (($name:expr) => $($tail:tt)*) => {{ + clap_app!{ @app ($crate::App::new($name)) $($tail)*} + }}; + + ($name:ident => $($tail:tt)*) => {{ + clap_app!{ @app ($crate::App::new(stringify!($name))) $($tail)*} + }}; +} + +macro_rules! impl_settings { + ($n:ident, $($v:ident => $c:path),+) => { + pub fn set(&mut self, s: $n) { + match s { + $($n::$v => self.0.insert($c)),+ + } + } + + pub fn unset(&mut self, s: $n) { + match s { + $($n::$v => self.0.remove($c)),+ + } + } + + pub fn is_set(&self, s: $n) -> bool { + match s { + $($n::$v => self.0.contains($c)),+ + } + } + }; +} + +// Convenience for writing to stderr thanks to https://github.com/BurntSushi +macro_rules! wlnerr( + ($($arg:tt)*) => ({ + use std::io::{Write, stderr}; + writeln!(&mut stderr(), $($arg)*).ok(); + }) +); + +#[cfg(feature = "debug")] +#[cfg_attr(feature = "debug", macro_use)] +#[cfg_attr(feature = "debug", allow(unused_macros))] +mod debug_macros { + macro_rules! debugln { + ($fmt:expr) => (println!(concat!("DEBUG:clap:", $fmt))); + ($fmt:expr, $($arg:tt)*) => (println!(concat!("DEBUG:clap:",$fmt), $($arg)*)); + } + macro_rules! sdebugln { + ($fmt:expr) => (println!($fmt)); + ($fmt:expr, $($arg:tt)*) => (println!($fmt, $($arg)*)); + } + macro_rules! debug { + ($fmt:expr) => (print!(concat!("DEBUG:clap:", $fmt))); + ($fmt:expr, $($arg:tt)*) => (print!(concat!("DEBUG:clap:",$fmt), $($arg)*)); + } + macro_rules! sdebug { + ($fmt:expr) => (print!($fmt)); + ($fmt:expr, $($arg:tt)*) => (print!($fmt, $($arg)*)); + } +} + +#[cfg(not(feature = "debug"))] +#[cfg_attr(not(feature = "debug"), macro_use)] +mod debug_macros { + macro_rules! debugln { + ($fmt:expr) => (); + ($fmt:expr, $($arg:tt)*) => (); + } + macro_rules! sdebugln { + ($fmt:expr) => (); + ($fmt:expr, $($arg:tt)*) => (); + } + macro_rules! debug { + ($fmt:expr) => (); + ($fmt:expr, $($arg:tt)*) => (); + } +} + +// Helper/deduplication macro for printing the correct number of spaces in help messages +// used in: +// src/args/arg_builder/*.rs +// src/app/mod.rs +macro_rules! write_nspaces { + ($dst:expr, $num:expr) => ({ + debugln!("write_spaces!: num={}", $num); + for _ in 0..$num { + $dst.write_all(b" ")?; + } + }) +} + +// convenience macro for remove an item from a vec +//macro_rules! vec_remove_all { +// ($vec:expr, $to_rem:expr) => { +// debugln!("vec_remove_all! to_rem={:?}", $to_rem); +// for i in (0 .. $vec.len()).rev() { +// let should_remove = $to_rem.any(|name| name == &$vec[i]); +// if should_remove { $vec.swap_remove(i); } +// } +// }; +//} +macro_rules! find_from { + ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ + let mut ret = None; + for k in $matcher.arg_names() { + if let Some(f) = find_by_name!($_self, k, flags, iter) { + if let Some(ref v) = f.$from() { + if v.contains($arg_name) { + ret = Some(f.to_string()); + } + } + } + if let Some(o) = find_by_name!($_self, k, opts, iter) { + if let Some(ref v) = o.$from() { + if v.contains(&$arg_name) { + ret = Some(o.to_string()); + } + } + } + if let Some(pos) = find_by_name!($_self, k, positionals, values) { + if let Some(ref v) = pos.$from() { + if v.contains($arg_name) { + ret = Some(pos.b.name.to_owned()); + } + } + } + } + ret + }}; +} + +//macro_rules! find_name_from { +// ($_self:expr, $arg_name:expr, $from:ident, $matcher:expr) => {{ +// let mut ret = None; +// for k in $matcher.arg_names() { +// if let Some(f) = find_by_name!($_self, k, flags, iter) { +// if let Some(ref v) = f.$from() { +// if v.contains($arg_name) { +// ret = Some(f.b.name); +// } +// } +// } +// if let Some(o) = find_by_name!($_self, k, opts, iter) { +// if let Some(ref v) = o.$from() { +// if v.contains(&$arg_name) { +// ret = Some(o.b.name); +// } +// } +// } +// if let Some(pos) = find_by_name!($_self, k, positionals, values) { +// if let Some(ref v) = pos.$from() { +// if v.contains($arg_name) { +// ret = Some(pos.b.name); +// } +// } +// } +// } +// ret +// }}; +//} + + +macro_rules! find_any_by_name { + ($p:expr, $name:expr) => { + { + fn as_trait_obj<'a, 'b, T: AnyArg<'a, 'b>>(x: &T) -> &AnyArg<'a, 'b> { x } + find_by_name!($p, $name, flags, iter).map(as_trait_obj).or( + find_by_name!($p, $name, opts, iter).map(as_trait_obj).or( + find_by_name!($p, $name, positionals, values).map(as_trait_obj) + ) + ) + } + } +} +// Finds an arg by name +macro_rules! find_by_name { + ($p:expr, $name:expr, $what:ident, $how:ident) => { + $p.$what.$how().find(|o| o.b.name == $name) + } +} + +// Finds an option including if it's aliased +macro_rules! find_opt_by_long { + (@os $_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, opts) + }}; + ($_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, opts) + }}; +} + +macro_rules! find_flag_by_long { + (@os $_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, flags) + }}; + ($_self:ident, $long:expr) => {{ + _find_by_long!($_self, $long, flags) + }}; +} + +macro_rules! _find_by_long { + ($_self:ident, $long:expr, $what:ident) => {{ + $_self.$what + .iter() + .filter(|a| a.s.long.is_some()) + .find(|a| { + a.s.long.unwrap() == $long || + (a.s.aliases.is_some() && + a.s + .aliases + .as_ref() + .unwrap() + .iter() + .any(|&(alias, _)| alias == $long)) + }) + }} +} + +// Finds an option +macro_rules! find_opt_by_short { + ($_self:ident, $short:expr) => {{ + _find_by_short!($_self, $short, opts) + }} +} + +macro_rules! find_flag_by_short { + ($_self:ident, $short:expr) => {{ + _find_by_short!($_self, $short, flags) + }} +} + +macro_rules! _find_by_short { + ($_self:ident, $short:expr, $what:ident) => {{ + $_self.$what + .iter() + .filter(|a| a.s.short.is_some()) + .find(|a| a.s.short.unwrap() == $short) + }} +} + +macro_rules! find_subcmd { + ($_self:expr, $sc:expr) => {{ + $_self.subcommands + .iter() + .find(|s| { + &*s.p.meta.name == $sc || + (s.p.meta.aliases.is_some() && + s.p + .meta + .aliases + .as_ref() + .unwrap() + .iter() + .any(|&(n, _)| n == $sc)) + }) + }}; +} + +macro_rules! shorts { + ($_self:ident) => {{ + _shorts_longs!($_self, short) + }}; +} + + +macro_rules! longs { + ($_self:ident) => {{ + _shorts_longs!($_self, long) + }}; +} + +macro_rules! _shorts_longs { + ($_self:ident, $what:ident) => {{ + $_self.flags + .iter() + .filter(|f| f.s.$what.is_some()) + .map(|f| f.s.$what.as_ref().unwrap()) + .chain($_self.opts.iter() + .filter(|o| o.s.$what.is_some()) + .map(|o| o.s.$what.as_ref().unwrap())) + }}; +} + +macro_rules! arg_names { + ($_self:ident) => {{ + _names!(@args $_self) + }}; +} + +macro_rules! sc_names { + ($_self:ident) => {{ + _names!(@sc $_self) + }}; +} + +macro_rules! _names { + (@args $_self:ident) => {{ + $_self.flags + .iter() + .map(|f| &*f.b.name) + .chain($_self.opts.iter() + .map(|o| &*o.b.name) + .chain($_self.positionals.values() + .map(|p| &*p.b.name))) + }}; + (@sc $_self:ident) => {{ + $_self.subcommands + .iter() + .map(|s| &*s.p.meta.name) + .chain($_self.subcommands + .iter() + .filter(|s| s.p.meta.aliases.is_some()) + .flat_map(|s| s.p.meta.aliases.as_ref().unwrap().iter().map(|&(n, _)| n))) + + }} +} diff --git a/clap/src/map.rs b/clap/src/map.rs new file mode 100644 index 000000000..063a86028 --- /dev/null +++ b/clap/src/map.rs @@ -0,0 +1,74 @@ +#[cfg(feature = "vec_map")] +pub use vec_map::{Values, VecMap}; + +#[cfg(not(feature = "vec_map"))] +pub use self::vec_map::{Values, VecMap}; + +#[cfg(not(feature = "vec_map"))] +mod vec_map { + use std::collections::BTreeMap; + use std::collections::btree_map; + use std::fmt::{self, Debug, Formatter}; + + #[derive(Clone, Default, Debug)] + pub struct VecMap { + inner: BTreeMap, + } + + impl VecMap { + pub fn new() -> Self { + VecMap { + inner: Default::default(), + } + } + + pub fn len(&self) -> usize { self.inner.len() } + + pub fn is_empty(&self) -> bool { self.inner.is_empty() } + + pub fn insert(&mut self, key: usize, value: V) -> Option { + self.inner.insert(key, value) + } + + pub fn values(&self) -> Values { self.inner.values() } + + pub fn iter(&self) -> Iter { + Iter { + inner: self.inner.iter(), + } + } + + pub fn contains_key(&self, key: usize) -> bool { self.inner.contains_key(&key) } + + pub fn entry(&mut self, key: usize) -> Entry { self.inner.entry(key) } + + pub fn get(&self, key: usize) -> Option<&V> { self.inner.get(&key) } + } + + pub type Values<'a, V> = btree_map::Values<'a, usize, V>; + + pub type Entry<'a, V> = btree_map::Entry<'a, usize, V>; + + #[derive(Clone)] + pub struct Iter<'a, V: 'a> { + inner: btree_map::Iter<'a, usize, V>, + } + + impl<'a, V: 'a + Debug> Debug for Iter<'a, V> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_list().entries(self.inner.clone()).finish() + } + } + + impl<'a, V: 'a> Iterator for Iter<'a, V> { + type Item = (usize, &'a V); + + fn next(&mut self) -> Option { self.inner.next().map(|(k, v)| (*k, v)) } + } + + impl<'a, V: 'a> DoubleEndedIterator for Iter<'a, V> { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|(k, v)| (*k, v)) + } + } +} diff --git a/clap/src/osstringext.rs b/clap/src/osstringext.rs new file mode 100644 index 000000000..061c01ddd --- /dev/null +++ b/clap/src/osstringext.rs @@ -0,0 +1,119 @@ +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +use INVALID_UTF8; +use std::ffi::OsStr; +#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))] +use std::os::unix::ffi::OsStrExt; + +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +pub trait OsStrExt3 { + fn from_bytes(b: &[u8]) -> &Self; + fn as_bytes(&self) -> &[u8]; +} + +#[doc(hidden)] +pub trait OsStrExt2 { + fn starts_with(&self, s: &[u8]) -> bool; + fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr); + fn split_at(&self, i: usize) -> (&OsStr, &OsStr); + fn trim_left_matches(&self, b: u8) -> &OsStr; + fn contains_byte(&self, b: u8) -> bool; + fn split(&self, b: u8) -> OsSplit; +} + +#[cfg(any(target_os = "windows", target_arch = "wasm32"))] +impl OsStrExt3 for OsStr { + fn from_bytes(b: &[u8]) -> &Self { + use std::mem; + unsafe { mem::transmute(b) } + } + fn as_bytes(&self) -> &[u8] { + self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8) + } +} + +impl OsStrExt2 for OsStr { + fn starts_with(&self, s: &[u8]) -> bool { + self.as_bytes().starts_with(s) + } + + fn contains_byte(&self, byte: u8) -> bool { + for b in self.as_bytes() { + if b == &byte { + return true; + } + } + false + } + + fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) { + for (i, b) in self.as_bytes().iter().enumerate() { + if b == &byte { + return ( + OsStr::from_bytes(&self.as_bytes()[..i]), + OsStr::from_bytes(&self.as_bytes()[i + 1..]), + ); + } + } + ( + &*self, + OsStr::from_bytes(&self.as_bytes()[self.len()..self.len()]), + ) + } + + fn trim_left_matches(&self, byte: u8) -> &OsStr { + let mut found = false; + for (i, b) in self.as_bytes().iter().enumerate() { + if b != &byte { + return OsStr::from_bytes(&self.as_bytes()[i..]); + } else { + found = true; + } + } + if found { + return OsStr::from_bytes(&self.as_bytes()[self.len()..]); + } + &*self + } + + fn split_at(&self, i: usize) -> (&OsStr, &OsStr) { + ( + OsStr::from_bytes(&self.as_bytes()[..i]), + OsStr::from_bytes(&self.as_bytes()[i..]), + ) + } + + fn split(&self, b: u8) -> OsSplit { + OsSplit { + sep: b, + val: self.as_bytes(), + pos: 0, + } + } +} + +#[doc(hidden)] +#[derive(Clone, Debug)] +pub struct OsSplit<'a> { + sep: u8, + val: &'a [u8], + pos: usize, +} + +impl<'a> Iterator for OsSplit<'a> { + type Item = &'a OsStr; + + fn next(&mut self) -> Option<&'a OsStr> { + debugln!("OsSplit::next: self={:?}", self); + if self.pos == self.val.len() { + return None; + } + let start = self.pos; + for b in &self.val[start..] { + self.pos += 1; + if *b == self.sep { + return Some(OsStr::from_bytes(&self.val[start..self.pos - 1])); + } + } + Some(OsStr::from_bytes(&self.val[start..])) + } +} diff --git a/clap/src/strext.rs b/clap/src/strext.rs new file mode 100644 index 000000000..6f81367ab --- /dev/null +++ b/clap/src/strext.rs @@ -0,0 +1,16 @@ +pub trait _StrExt { + fn _is_char_boundary(&self, index: usize) -> bool; +} + +impl _StrExt for str { + #[inline] + fn _is_char_boundary(&self, index: usize) -> bool { + if index == self.len() { + return true; + } + match self.as_bytes().get(index) { + None => false, + Some(&b) => b < 128 || b >= 192, + } + } +} diff --git a/clap/src/suggestions.rs b/clap/src/suggestions.rs new file mode 100644 index 000000000..06071d216 --- /dev/null +++ b/clap/src/suggestions.rs @@ -0,0 +1,147 @@ +use app::App; +// Third Party +#[cfg(feature = "suggestions")] +use strsim; + +// Internal +use fmt::Format; + +/// Produces a string from a given list of possible values which is similar to +/// the passed in value `v` with a certain confidence. +/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield +/// `Some("foo")`, whereas "blark" would yield `None`. +#[cfg(feature = "suggestions")] +#[cfg_attr(feature = "lints", allow(needless_lifetimes))] +pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str> +where + T: AsRef + 'a, + I: IntoIterator, +{ + let mut candidate: Option<(f64, &str)> = None; + for pv in possible_values { + let confidence = strsim::jaro_winkler(v, pv.as_ref()); + if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence)) + { + candidate = Some((confidence, pv.as_ref())); + } + } + match candidate { + None => None, + Some((_, candidate)) => Some(candidate), + } +} + +#[cfg(not(feature = "suggestions"))] +pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str> +where + T: AsRef + 'a, + I: IntoIterator, +{ + None +} + +/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase +#[cfg_attr(feature = "lints", allow(needless_lifetimes))] +pub fn did_you_mean_flag_suffix<'z, T, I>( + arg: &str, + args_rest: &'z [&str], + longs: I, + subcommands: &'z [App], +) -> (String, Option<&'z str>) +where + T: AsRef + 'z, + I: IntoIterator, +{ + if let Some(candidate) = did_you_mean(arg, longs) { + let suffix = format!( + "\n\tDid you mean {}{}?", + Format::Good("--"), + Format::Good(candidate) + ); + return (suffix, Some(candidate)); + } + + subcommands + .into_iter() + .filter_map(|subcommand| { + let opts = subcommand + .p + .flags + .iter() + .filter_map(|f| f.s.long) + .chain(subcommand.p.opts.iter().filter_map(|o| o.s.long)); + + let candidate = match did_you_mean(arg, opts) { + Some(candidate) => candidate, + None => return None + }; + let score = match args_rest.iter().position(|x| *x == subcommand.get_name()) { + Some(score) => score, + None => return None + }; + + let suffix = format!( + "\n\tDid you mean to put '{}{}' after the subcommand '{}'?", + Format::Good("--"), + Format::Good(candidate), + Format::Good(subcommand.get_name()) + ); + + Some((score, (suffix, Some(candidate)))) + }) + .min_by_key(|&(score, _)| score) + .map(|(_, suggestion)| suggestion) + .unwrap_or_else(|| (String::new(), None)) +} + +/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase +pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>) +where + T: AsRef + 'z, + I: IntoIterator, +{ + match did_you_mean(arg, values) { + Some(candidate) => { + let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate)); + (suffix, Some(candidate)) + } + None => (String::new(), None), + } +} + +#[cfg(all(test, features = "suggestions"))] +mod test { + use super::*; + + #[test] + fn possible_values_match() { + let p_vals = ["test", "possible", "values"]; + assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test")); + } + + #[test] + fn possible_values_nomatch() { + let p_vals = ["test", "possible", "values"]; + assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none()); + } + + #[test] + fn suffix_long() { + let p_vals = ["test", "possible", "values"]; + let suffix = "\n\tDid you mean \'--test\'?"; + assert_eq!( + did_you_mean_flag_suffix("tst", p_vals.iter(), []), + (suffix, Some("test")) + ); + } + + #[test] + fn suffix_enum() { + let p_vals = ["test", "possible", "values"]; + let suffix = "\n\tDid you mean \'test\'?"; + assert_eq!( + did_you_mean_value_suffix("tst", p_vals.iter()), + (suffix, Some("test")) + ); + } +} diff --git a/clap/src/usage_parser.rs b/clap/src/usage_parser.rs new file mode 100644 index 000000000..f6d5ac606 --- /dev/null +++ b/clap/src/usage_parser.rs @@ -0,0 +1,1347 @@ +// Internal +use INTERNAL_ERROR_MSG; +use args::Arg; +use args::settings::ArgSettings; +use map::VecMap; + +#[derive(PartialEq, Debug)] +enum UsageToken { + Name, + ValName, + Short, + Long, + Help, + Multiple, + Unknown, +} + +#[doc(hidden)] +#[derive(Debug)] +pub struct UsageParser<'a> { + usage: &'a str, + pos: usize, + start: usize, + prev: UsageToken, + explicit_name_set: bool, +} + +impl<'a> UsageParser<'a> { + fn new(usage: &'a str) -> Self { + debugln!("UsageParser::new: usage={:?}", usage); + UsageParser { + usage: usage, + pos: 0, + start: 0, + prev: UsageToken::Unknown, + explicit_name_set: false, + } + } + + pub fn from_usage(usage: &'a str) -> Self { + debugln!("UsageParser::from_usage;"); + UsageParser::new(usage) + } + + pub fn parse(mut self) -> Arg<'a, 'a> { + debugln!("UsageParser::parse;"); + let mut arg = Arg::default(); + loop { + debugln!("UsageParser::parse:iter: pos={};", self.pos); + self.stop_at(token); + if let Some(&c) = self.usage.as_bytes().get(self.pos) { + match c { + b'-' => self.short_or_long(&mut arg), + b'.' => self.multiple(&mut arg), + b'\'' => self.help(&mut arg), + _ => self.name(&mut arg), + } + } else { + break; + } + } + debug_assert!( + !arg.b.name.is_empty(), + format!( + "No name found for Arg when parsing usage string: {}", + self.usage + ) + ); + arg.v.num_vals = match arg.v.val_names { + Some(ref v) if v.len() >= 2 => Some(v.len() as u64), + _ => None, + }; + debugln!("UsageParser::parse: vals...{:?}", arg.v.val_names); + arg + } + + fn name(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::name;"); + if *self.usage + .as_bytes() + .get(self.pos) + .expect(INTERNAL_ERROR_MSG) == b'<' && !self.explicit_name_set + { + arg.setb(ArgSettings::Required); + } + self.pos += 1; + self.stop_at(name_end); + let name = &self.usage[self.start..self.pos]; + if self.prev == UsageToken::Unknown { + debugln!("UsageParser::name: setting name...{}", name); + arg.b.name = name; + if arg.s.long.is_none() && arg.s.short.is_none() { + debugln!("UsageParser::name: explicit name set..."); + self.explicit_name_set = true; + self.prev = UsageToken::Name; + } + } else { + debugln!("UsageParser::name: setting val name...{}", name); + if let Some(ref mut v) = arg.v.val_names { + let len = v.len(); + v.insert(len, name); + } else { + let mut v = VecMap::new(); + v.insert(0, name); + arg.v.val_names = Some(v); + arg.setb(ArgSettings::TakesValue); + } + self.prev = UsageToken::ValName; + } + } + + fn stop_at(&mut self, f: F) + where + F: Fn(u8) -> bool, + { + debugln!("UsageParser::stop_at;"); + self.start = self.pos; + self.pos += self.usage[self.start..] + .bytes() + .take_while(|&b| f(b)) + .count(); + } + + fn short_or_long(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::short_or_long;"); + self.pos += 1; + if *self.usage + .as_bytes() + .get(self.pos) + .expect(INTERNAL_ERROR_MSG) == b'-' + { + self.pos += 1; + self.long(arg); + return; + } + self.short(arg) + } + + fn long(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::long;"); + self.stop_at(long_end); + let name = &self.usage[self.start..self.pos]; + if !self.explicit_name_set { + debugln!("UsageParser::long: setting name...{}", name); + arg.b.name = name; + } + debugln!("UsageParser::long: setting long...{}", name); + arg.s.long = Some(name); + self.prev = UsageToken::Long; + } + + fn short(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::short;"); + let start = &self.usage[self.pos..]; + let short = start.chars().nth(0).expect(INTERNAL_ERROR_MSG); + debugln!("UsageParser::short: setting short...{}", short); + arg.s.short = Some(short); + if arg.b.name.is_empty() { + // --long takes precedence but doesn't set self.explicit_name_set + let name = &start[..short.len_utf8()]; + debugln!("UsageParser::short: setting name...{}", name); + arg.b.name = name; + } + self.prev = UsageToken::Short; + } + + // "something..." + fn multiple(&mut self, arg: &mut Arg) { + debugln!("UsageParser::multiple;"); + let mut dot_counter = 1; + let start = self.pos; + let mut bytes = self.usage[start..].bytes(); + while bytes.next() == Some(b'.') { + dot_counter += 1; + self.pos += 1; + if dot_counter == 3 { + debugln!("UsageParser::multiple: setting multiple"); + arg.setb(ArgSettings::Multiple); + if arg.is_set(ArgSettings::TakesValue) { + arg.setb(ArgSettings::UseValueDelimiter); + arg.unsetb(ArgSettings::ValueDelimiterNotSet); + if arg.v.val_delim.is_none() { + arg.v.val_delim = Some(','); + } + } + self.prev = UsageToken::Multiple; + self.pos += 1; + break; + } + } + } + + fn help(&mut self, arg: &mut Arg<'a, 'a>) { + debugln!("UsageParser::help;"); + self.stop_at(help_start); + self.start = self.pos + 1; + self.pos = self.usage.len() - 1; + debugln!( + "UsageParser::help: setting help...{}", + &self.usage[self.start..self.pos] + ); + arg.b.help = Some(&self.usage[self.start..self.pos]); + self.pos += 1; // Move to next byte to keep from thinking ending ' is a start + self.prev = UsageToken::Help; + } +} + +#[inline] +fn name_end(b: u8) -> bool { b != b']' && b != b'>' } + +#[inline] +fn token(b: u8) -> bool { b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'-' } + +#[inline] +fn long_end(b: u8) -> bool { + b != b'\'' && b != b'.' && b != b'<' && b != b'[' && b != b'=' && b != b' ' +} + +#[inline] +fn help_start(b: u8) -> bool { b != b'\'' } + +#[cfg(test)] +mod test { + use args::Arg; + use args::ArgSettings; + + #[test] + fn create_flag_usage() { + let a = Arg::from_usage("[flag] -f 'some help info'"); + assert_eq!(a.b.name, "flag"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let b = Arg::from_usage("[flag] --flag 'some help info'"); + assert_eq!(b.b.name, "flag"); + assert_eq!(b.s.long.unwrap(), "flag"); + assert!(b.s.short.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let b = Arg::from_usage("--flag 'some help info'"); + assert_eq!(b.b.name, "flag"); + assert_eq!(b.s.long.unwrap(), "flag"); + assert!(b.s.short.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(b.v.val_names.is_none()); + assert!(b.v.num_vals.is_none()); + + let c = Arg::from_usage("[flag] -f --flag 'some help info'"); + assert_eq!(c.b.name, "flag"); + assert_eq!(c.s.short.unwrap(), 'f'); + assert_eq!(c.s.long.unwrap(), "flag"); + assert_eq!(c.b.help.unwrap(), "some help info"); + assert!(!c.is_set(ArgSettings::Multiple)); + assert!(c.v.val_names.is_none()); + assert!(c.v.num_vals.is_none()); + + let d = Arg::from_usage("[flag] -f... 'some help info'"); + assert_eq!(d.b.name, "flag"); + assert_eq!(d.s.short.unwrap(), 'f'); + assert!(d.s.long.is_none()); + assert_eq!(d.b.help.unwrap(), "some help info"); + assert!(d.is_set(ArgSettings::Multiple)); + assert!(d.v.val_names.is_none()); + assert!(d.v.num_vals.is_none()); + + let e = Arg::from_usage("[flag] -f --flag... 'some help info'"); + assert_eq!(e.b.name, "flag"); + assert_eq!(e.s.long.unwrap(), "flag"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.b.help.unwrap(), "some help info"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("-f --flag... 'some help info'"); + assert_eq!(e.b.name, "flag"); + assert_eq!(e.s.long.unwrap(), "flag"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert_eq!(e.b.help.unwrap(), "some help info"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("--flags"); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.long.unwrap(), "flags"); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("--flags..."); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.long.unwrap(), "flags"); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("[flags] -f"); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("[flags] -f..."); + assert_eq!(e.b.name, "flags"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let a = Arg::from_usage("-f 'some help info'"); + assert_eq!(a.b.name, "f"); + assert_eq!(a.s.short.unwrap(), 'f'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.v.val_names.is_none()); + assert!(a.v.num_vals.is_none()); + + let e = Arg::from_usage("-f"); + assert_eq!(e.b.name, "f"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + + let e = Arg::from_usage("-f..."); + assert_eq!(e.b.name, "f"); + assert_eq!(e.s.short.unwrap(), 'f'); + assert!(e.is_set(ArgSettings::Multiple)); + assert!(e.v.val_names.is_none()); + assert!(e.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage0() { + // Short only + let a = Arg::from_usage("[option] -o [opt] 'some help info'"); + assert_eq!(a.b.name, "option"); + assert_eq!(a.s.short.unwrap(), 'o'); + assert!(a.s.long.is_none()); + assert_eq!(a.b.help.unwrap(), "some help info"); + assert!(!a.is_set(ArgSettings::Multiple)); + assert!(a.is_set(ArgSettings::TakesValue)); + assert!(!a.is_set(ArgSettings::Required)); + assert_eq!( + a.v.val_names.unwrap().values().collect::>(), + [&"opt"] + ); + assert!(a.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage1() { + let b = Arg::from_usage("-o [opt] 'some help info'"); + assert_eq!(b.b.name, "o"); + assert_eq!(b.s.short.unwrap(), 'o'); + assert!(b.s.long.is_none()); + assert_eq!(b.b.help.unwrap(), "some help info"); + assert!(!b.is_set(ArgSettings::Multiple)); + assert!(b.is_set(ArgSettings::TakesValue)); + assert!(!b.is_set(ArgSettings::Required)); + assert_eq!( + b.v.val_names.unwrap().values().collect::>(), + [&"opt"] + ); + assert!(b.v.num_vals.is_none()); + } + + #[test] + fn create_option_usage2() { + let c = Arg::from_usage("() == mem::size_of::() && mem::align_of::() >= mem::align_of::() +} + +/// A simple stamped lock. +struct Lock { + /// The current state of the lock. + /// + /// All bits except the least significant one hold the current stamp. When locked, the state + /// equals 1 and doesn't contain a valid stamp. + state: AtomicUsize, +} + +impl Lock { + /// If not locked, returns the current stamp. + /// + /// This method should be called before optimistic reads. + #[inline] + fn optimistic_read(&self) -> Option { + let state = self.state.load(Ordering::Acquire); + if state == 1 { + None + } else { + Some(state) + } + } + + /// Returns `true` if the current stamp is equal to `stamp`. + /// + /// This method should be called after optimistic reads to check whether they are valid. The + /// argument `stamp` should correspond to the one returned by method `optimistic_read`. + #[inline] + fn validate_read(&self, stamp: usize) -> bool { + atomic::fence(Ordering::Acquire); + self.state.load(Ordering::Relaxed) == stamp + } + + /// Grabs the lock for writing. + #[inline] + fn write(&'static self) -> WriteGuard { + let backoff = Backoff::new(); + loop { + let previous = self.state.swap(1, Ordering::Acquire); + + if previous != 1 { + atomic::fence(Ordering::Release); + + return WriteGuard { + lock: self, + state: previous, + }; + } + + backoff.snooze(); + } + } +} + +/// A RAII guard that releases the lock and increments the stamp when dropped. +struct WriteGuard { + /// The parent lock. + lock: &'static Lock, + + /// The stamp before locking. + state: usize, +} + +impl WriteGuard { + /// Releases the lock without incrementing the stamp. + #[inline] + fn abort(self) { + self.lock.state.store(self.state, Ordering::Release); + } +} + +impl Drop for WriteGuard { + #[inline] + fn drop(&mut self) { + // Release the lock and increment the stamp. + self.lock + .state + .store(self.state.wrapping_add(2), Ordering::Release); + } +} + +/// Returns a reference to the global lock associated with the `AtomicCell` at address `addr`. +/// +/// This function is used to protect atomic data which doesn't fit into any of the primitive atomic +/// types in `std::sync::atomic`. Operations on such atomics must therefore use a global lock. +/// +/// However, there is not only one global lock but an array of many locks, and one of them is +/// picked based on the given address. Having many locks reduces contention and improves +/// scalability. +#[inline] +#[must_use] +fn lock(addr: usize) -> &'static Lock { + // The number of locks is a prime number because we want to make sure `addr % LEN` gets + // dispersed across all locks. + // + // Note that addresses are always aligned to some power of 2, depending on type `T` in + // `AtomicCell`. If `LEN` was an even number, then `addr % LEN` would be an even number, + // too, which means only half of the locks would get utilized! + // + // It is also possible for addresses to accidentally get aligned to a number that is not a + // power of 2. Consider this example: + // + // ``` + // #[repr(C)] + // struct Foo { + // a: AtomicCell, + // b: u8, + // c: u8, + // } + // ``` + // + // Now, if we have a slice of type `&[Foo]`, it is possible that field `a` in all items gets + // stored at addresses that are multiples of 3. It'd be too bad if `LEN` was divisible by 3. + // In order to protect from such cases, we simply choose a large prime number for `LEN`. + const LEN: usize = 97; + + const L: Lock = Lock { + state: AtomicUsize::new(0), + }; + static LOCKS: [Lock; LEN] = [ + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, + L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, + L, L, L, L, L, L, L, + ]; + + // If the modulus is a constant number, the compiler will use crazy math to transform this into + // a sequence of cheap arithmetic operations rather than using the slow modulo instruction. + &LOCKS[addr % LEN] +} + +/// An atomic `()`. +/// +/// All operations are noops. +struct AtomicUnit; + +impl AtomicUnit { + #[inline] + fn load(&self, _order: Ordering) {} + + #[inline] + fn store(&self, _val: (), _order: Ordering) {} + + #[inline] + fn swap(&self, _val: (), _order: Ordering) {} + + #[inline] + fn compare_exchange_weak( + &self, + _current: (), + _new: (), + _success: Ordering, + _failure: Ordering, + ) -> Result<(), ()> { + Ok(()) + } +} + +macro_rules! atomic { + // If values of type `$t` can be transmuted into values of the primitive atomic type `$atomic`, + // declares variable `$a` of type `$atomic` and executes `$atomic_op`, breaking out of the loop. + (@check, $t:ty, $atomic:ty, $a:ident, $atomic_op:expr) => { + if can_transmute::<$t, $atomic>() { + let $a: &$atomic; + break $atomic_op; + } + }; + + // If values of type `$t` can be transmuted into values of a primitive atomic type, declares + // variable `$a` of that type and executes `$atomic_op`. Otherwise, just executes + // `$fallback_op`. + ($t:ty, $a:ident, $atomic_op:expr, $fallback_op:expr) => { + loop { + atomic!(@check, $t, AtomicUnit, $a, $atomic_op); + atomic!(@check, $t, atomic::AtomicUsize, $a, $atomic_op); + + #[cfg(feature = "nightly")] + { + #[cfg(target_has_atomic = "8")] + atomic!(@check, $t, atomic::AtomicU8, $a, $atomic_op); + #[cfg(target_has_atomic = "16")] + atomic!(@check, $t, atomic::AtomicU16, $a, $atomic_op); + #[cfg(target_has_atomic = "32")] + atomic!(@check, $t, atomic::AtomicU32, $a, $atomic_op); + #[cfg(target_has_atomic = "64")] + atomic!(@check, $t, atomic::AtomicU64, $a, $atomic_op); + } + + break $fallback_op; + } + }; +} + +/// Returns `true` if operations on `AtomicCell` are lock-free. +fn atomic_is_lock_free() -> bool { + atomic! { T, _a, true, false } +} + +/// Atomically reads data from `src`. +/// +/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_load(src: *mut T) -> T +where + T: Copy, +{ + atomic! { + T, a, + { + a = &*(src as *const _ as *const _); + mem::transmute_copy(&a.load(Ordering::SeqCst)) + }, + { + let lock = lock(src as usize); + + // Try doing an optimistic read first. + if let Some(stamp) = lock.optimistic_read() { + // We need a volatile read here because other threads might concurrently modify the + // value. In theory, data races are *always* UB, even if we use volatile reads and + // discard the data when a data race is detected. The proper solution would be to + // do atomic reads and atomic writes, but we can't atomically read and write all + // kinds of data since `AtomicU8` is not available on stable Rust yet. + let val = ptr::read_volatile(src); + + if lock.validate_read(stamp) { + return val; + } + } + + // Grab a regular write lock so that writers don't starve this load. + let guard = lock.write(); + let val = ptr::read(src); + // The value hasn't been changed. Drop the guard without incrementing the stamp. + guard.abort(); + val + } + } +} + +/// Atomically writes `val` to `dst`. +/// +/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_store(dst: *mut T, val: T) { + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + let res = a.store(mem::transmute_copy(&val), Ordering::SeqCst); + mem::forget(val); + res + }, + { + let _guard = lock(dst as usize).write(); + ptr::write(dst, val) + } + } +} + +/// Atomically swaps data at `dst` with `val`. +/// +/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_swap(dst: *mut T, val: T) -> T { + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + let res = mem::transmute_copy(&a.swap(mem::transmute_copy(&val), Ordering::SeqCst)); + mem::forget(val); + res + }, + { + let _guard = lock(dst as usize).write(); + ptr::replace(dst, val) + } + } +} + +/// Atomically compares data at `dst` to `current` and, if equal byte-for-byte, exchanges data at +/// `dst` with `new`. +/// +/// Returns the old value on success, or the current value at `dst` on failure. +/// +/// This operation uses the `SeqCst` ordering. If possible, an atomic instructions is used, and a +/// global lock otherwise. +unsafe fn atomic_compare_exchange_weak(dst: *mut T, current: T, new: T) -> Result +where + T: Copy, +{ + atomic! { + T, a, + { + a = &*(dst as *const _ as *const _); + let res = a.compare_exchange_weak( + mem::transmute_copy(¤t), + mem::transmute_copy(&new), + Ordering::SeqCst, + Ordering::SeqCst, + ); + match res { + Ok(v) => Ok(mem::transmute_copy(&v)), + Err(v) => Err(mem::transmute_copy(&v)), + } + }, + { + let guard = lock(dst as usize).write(); + + if byte_eq(&*dst, ¤t) { + Ok(ptr::replace(dst, new)) + } else { + let val = ptr::read(dst); + // The value hasn't been changed. Drop the guard without incrementing the stamp. + guard.abort(); + Err(val) + } + } + } +} diff --git a/crossbeam-utils/src/atomic/consume.rs b/crossbeam-utils/src/atomic/consume.rs new file mode 100644 index 000000000..9be5464fb --- /dev/null +++ b/crossbeam-utils/src/atomic/consume.rs @@ -0,0 +1,82 @@ +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +use core::sync::atomic::compiler_fence; +use core::sync::atomic::Ordering; + +/// Trait which allows reading from primitive atomic types with "consume" ordering. +pub trait AtomicConsume { + /// Type returned by `load_consume`. + type Val; + + /// Loads a value from the atomic using a "consume" memory ordering. + /// + /// This is similar to the "acquire" ordering, except that an ordering is + /// only guaranteed with operations that "depend on" the result of the load. + /// However consume loads are usually much faster than acquire loads on + /// architectures with a weak memory model since they don't require memory + /// fence instructions. + /// + /// The exact definition of "depend on" is a bit vague, but it works as you + /// would expect in practice since a lot of software, especially the Linux + /// kernel, rely on this behavior. + /// + /// This is currently only implemented on ARM and AArch64, where a fence + /// can be avoided. On other architectures this will fall back to a simple + /// `load(Ordering::Acquire)`. + fn load_consume(&self) -> Self::Val; +} + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +macro_rules! impl_consume { + () => { + #[inline] + fn load_consume(&self) -> Self::Val { + let result = self.load(Ordering::Relaxed); + compiler_fence(Ordering::Acquire); + result + } + }; +} + +#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] +macro_rules! impl_consume { + () => { + #[inline] + fn load_consume(&self) -> Self::Val { + self.load(Ordering::Acquire) + } + }; +} + +macro_rules! impl_atomic { + ($atomic:ident, $val:ty) => { + impl AtomicConsume for ::core::sync::atomic::$atomic { + type Val = $val; + impl_consume!(); + } + }; +} + +impl_atomic!(AtomicBool, bool); +impl_atomic!(AtomicUsize, usize); +impl_atomic!(AtomicIsize, isize); +#[cfg(all(feature = "nightly", target_has_atomic = "8"))] +impl_atomic!(AtomicU8, u8); +#[cfg(all(feature = "nightly", target_has_atomic = "8"))] +impl_atomic!(AtomicI8, i8); +#[cfg(all(feature = "nightly", target_has_atomic = "16"))] +impl_atomic!(AtomicU16, u16); +#[cfg(all(feature = "nightly", target_has_atomic = "16"))] +impl_atomic!(AtomicI16, i16); +#[cfg(all(feature = "nightly", target_has_atomic = "32"))] +impl_atomic!(AtomicU32, u32); +#[cfg(all(feature = "nightly", target_has_atomic = "32"))] +impl_atomic!(AtomicI32, i32); +#[cfg(all(feature = "nightly", target_has_atomic = "64"))] +impl_atomic!(AtomicU64, u64); +#[cfg(all(feature = "nightly", target_has_atomic = "64"))] +impl_atomic!(AtomicI64, i64); + +impl AtomicConsume for ::core::sync::atomic::AtomicPtr { + type Val = *mut T; + impl_consume!(); +} diff --git a/crossbeam-utils/src/atomic/mod.rs b/crossbeam-utils/src/atomic/mod.rs new file mode 100644 index 000000000..420599395 --- /dev/null +++ b/crossbeam-utils/src/atomic/mod.rs @@ -0,0 +1,7 @@ +//! Atomic types. + +mod atomic_cell; +mod consume; + +pub use self::atomic_cell::AtomicCell; +pub use self::consume::AtomicConsume; diff --git a/crossbeam-utils/src/backoff.rs b/crossbeam-utils/src/backoff.rs new file mode 100644 index 000000000..49619917b --- /dev/null +++ b/crossbeam-utils/src/backoff.rs @@ -0,0 +1,294 @@ +use core::cell::Cell; +use core::fmt; +use core::sync::atomic; + +const SPIN_LIMIT: u32 = 6; +const YIELD_LIMIT: u32 = 10; + +/// Performs exponential backoff in spin loops. +/// +/// Backing off in spin loops reduces contention and improves overall performance. +/// +/// This primitive can execute *YIELD* and *PAUSE* instructions, yield the current thread to the OS +/// scheduler, and tell when is a good time to block the thread using a different synchronization +/// mechanism. Each step of the back off procedure takes roughly twice as long as the previous +/// step. +/// +/// # Examples +/// +/// Backing off in a lock-free loop: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicUsize; +/// use std::sync::atomic::Ordering::SeqCst; +/// +/// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { +/// let backoff = Backoff::new(); +/// loop { +/// let val = a.load(SeqCst); +/// if a.compare_and_swap(val, val.wrapping_mul(b), SeqCst) == val { +/// return val; +/// } +/// backoff.spin(); +/// } +/// } +/// ``` +/// +/// Waiting for an [`AtomicBool`] to become `true`: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicBool; +/// use std::sync::atomic::Ordering::SeqCst; +/// +/// fn spin_wait(ready: &AtomicBool) { +/// let backoff = Backoff::new(); +/// while !ready.load(SeqCst) { +/// backoff.snooze(); +/// } +/// } +/// ``` +/// +/// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait. +/// Note that whoever sets the atomic variable to `true` must notify the parked thread by calling +/// [`unpark()`]: +/// +/// ``` +/// use crossbeam_utils::Backoff; +/// use std::sync::atomic::AtomicBool; +/// use std::sync::atomic::Ordering::SeqCst; +/// use std::thread; +/// +/// fn blocking_wait(ready: &AtomicBool) { +/// let backoff = Backoff::new(); +/// while !ready.load(SeqCst) { +/// if backoff.is_completed() { +/// thread::park(); +/// } else { +/// backoff.snooze(); +/// } +/// } +/// } +/// ``` +/// +/// [`is_completed`]: struct.Backoff.html#method.is_completed +/// [`std::thread::park()`]: https://doc.rust-lang.org/std/thread/fn.park.html +/// [`Condvar`]: https://doc.rust-lang.org/std/sync/struct.Condvar.html +/// [`AtomicBool`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html +/// [`unpark()`]: https://doc.rust-lang.org/std/thread/struct.Thread.html#method.unpark +pub struct Backoff { + step: Cell, +} + +impl Backoff { + /// Creates a new `Backoff`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// + /// let backoff = Backoff::new(); + /// ``` + #[inline] + pub fn new() -> Self { + Backoff { + step: Cell::new(0), + } + } + + /// Resets the `Backoff`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// + /// let backoff = Backoff::new(); + /// backoff.reset(); + /// ``` + #[inline] + pub fn reset(&self) { + self.step.set(0); + } + + /// Backs off in a lock-free loop. + /// + /// This method should be used when we need to retry an operation because another thread made + /// progress. + /// + /// The processor may yield using the *YIELD* or *PAUSE* instruction. + /// + /// # Examples + /// + /// Backing off in a lock-free loop: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::atomic::AtomicUsize; + /// use std::sync::atomic::Ordering::SeqCst; + /// + /// fn fetch_mul(a: &AtomicUsize, b: usize) -> usize { + /// let backoff = Backoff::new(); + /// loop { + /// let val = a.load(SeqCst); + /// if a.compare_and_swap(val, val.wrapping_mul(b), SeqCst) == val { + /// return val; + /// } + /// backoff.spin(); + /// } + /// } + /// + /// let a = AtomicUsize::new(7); + /// assert_eq!(fetch_mul(&a, 8), 7); + /// assert_eq!(a.load(SeqCst), 56); + /// ``` + #[inline] + pub fn spin(&self) { + for _ in 0..1 << self.step.get().min(SPIN_LIMIT) { + atomic::spin_loop_hint(); + } + + if self.step.get() <= SPIN_LIMIT { + self.step.set(self.step.get() + 1); + } + } + + /// Backs off in a blocking loop. + /// + /// This method should be used when we need to wait for another thread to make progress. + /// + /// The processor may yield using the *YIELD* or *PAUSE* instruction and the current thread + /// may yield by giving up a timeslice to the OS scheduler. + /// + /// In `#[no_std]` environments, this method is equivalent to [`spin`]. + /// + /// If possible, use [`is_completed`] to check when it is advised to stop using backoff and + /// block the current thread using a different synchronization mechanism instead. + /// + /// [`spin`]: struct.Backoff.html#method.spin + /// [`is_completed`]: struct.Backoff.html#method.is_completed + /// + /// # Examples + /// + /// Waiting for an [`AtomicBool`] to become `true`: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::Arc; + /// use std::sync::atomic::AtomicBool; + /// use std::sync::atomic::Ordering::SeqCst; + /// use std::thread; + /// use std::time::Duration; + /// + /// fn spin_wait(ready: &AtomicBool) { + /// let backoff = Backoff::new(); + /// while !ready.load(SeqCst) { + /// backoff.snooze(); + /// } + /// } + /// + /// let ready = Arc::new(AtomicBool::new(false)); + /// let ready2 = ready.clone(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// ready2.store(true, SeqCst); + /// }); + /// + /// assert_eq!(ready.load(SeqCst), false); + /// spin_wait(&ready); + /// assert_eq!(ready.load(SeqCst), true); + /// ``` + /// + /// [`AtomicBool`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html + #[inline] + pub fn snooze(&self) { + if self.step.get() <= SPIN_LIMIT { + for _ in 0..1 << self.step.get() { + atomic::spin_loop_hint(); + } + } else { + #[cfg(not(feature = "std"))] + for _ in 0..1 << self.step.get() { + atomic::spin_loop_hint(); + } + + #[cfg(feature = "std")] + ::std::thread::yield_now(); + } + + if self.step.get() <= YIELD_LIMIT { + self.step.set(self.step.get() + 1); + } + } + + /// Returns `true` if exponential backoff has completed and blocking the thread is advised. + /// + /// # Examples + /// + /// Waiting for an [`AtomicBool`] to become `true` and parking the thread after a long wait: + /// + /// ``` + /// use crossbeam_utils::Backoff; + /// use std::sync::Arc; + /// use std::sync::atomic::AtomicBool; + /// use std::sync::atomic::Ordering::SeqCst; + /// use std::thread; + /// use std::time::Duration; + /// + /// fn blocking_wait(ready: &AtomicBool) { + /// let backoff = Backoff::new(); + /// while !ready.load(SeqCst) { + /// if backoff.is_completed() { + /// thread::park(); + /// } else { + /// backoff.snooze(); + /// } + /// } + /// } + /// + /// let ready = Arc::new(AtomicBool::new(false)); + /// let ready2 = ready.clone(); + /// let waiter = thread::current(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(100)); + /// ready2.store(true, SeqCst); + /// waiter.unpark(); + /// }); + /// + /// assert_eq!(ready.load(SeqCst), false); + /// blocking_wait(&ready); + /// assert_eq!(ready.load(SeqCst), true); + /// ``` + /// + /// [`AtomicBool`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html + #[inline] + pub fn is_completed(&self) -> bool { + self.step.get() > YIELD_LIMIT + } + + #[inline] + #[doc(hidden)] + #[deprecated(note = "use `is_completed` instead")] + pub fn is_complete(&self) -> bool { + self.is_completed() + } +} + +impl fmt::Debug for Backoff { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Backoff") + .field("step", &self.step) + .field("is_completed", &self.is_completed()) + .finish() + } +} + +impl Default for Backoff { + fn default() -> Backoff { + Backoff::new() + } +} diff --git a/crossbeam-utils/src/cache_padded.rs b/crossbeam-utils/src/cache_padded.rs new file mode 100644 index 000000000..a5f3bbc1c --- /dev/null +++ b/crossbeam-utils/src/cache_padded.rs @@ -0,0 +1,116 @@ +use core::fmt; +use core::ops::{Deref, DerefMut}; + +/// Pads and aligns a value to the length of a cache line. +/// +/// In concurrent programming, sometimes it is desirable to make sure commonly accessed pieces of +/// data are not placed into the same cache line. Updating an atomic value invalides the whole +/// cache line it belongs to, which makes the next access to the same cache line slower for other +/// CPU cores. Use `CachePadded` to ensure updating one piece of data doesn't invalidate other +/// cached data. +/// +/// Cache lines are assumed to be 64 bytes on all architectures. +/// +/// # Size and alignment +/// +/// The size of `CachePadded` is the smallest multiple of 64 bytes large enough to accommodate +/// a value of type `T`. +/// +/// The alignment of `CachePadded` is the maximum of 64 bytes and the alignment of `T`. +/// +/// # Examples +/// +/// Alignment and padding: +/// +/// ``` +/// use crossbeam_utils::CachePadded; +/// +/// let array = [CachePadded::new(1i32), CachePadded::new(2i32)]; +/// let addr1 = &*array[0] as *const i32 as usize; +/// let addr2 = &*array[1] as *const i32 as usize; +/// +/// assert_eq!(addr2 - addr1, 64); +/// assert_eq!(addr1 % 64, 0); +/// assert_eq!(addr2 % 64, 0); +/// ``` +/// +/// When building a concurrent queue with a head and a tail index, it is wise to place them in +/// different cache lines so that concurrent threads pushing and popping elements don't invalidate +/// each other's cache lines: +/// +/// ``` +/// use crossbeam_utils::CachePadded; +/// use std::sync::atomic::AtomicUsize; +/// +/// struct Queue { +/// head: CachePadded, +/// tail: CachePadded, +/// buffer: *mut T, +/// } +/// ``` +#[derive(Clone, Copy, Default, Hash, PartialEq, Eq)] +#[repr(align(64))] +pub struct CachePadded { + value: T, +} + +unsafe impl Send for CachePadded {} +unsafe impl Sync for CachePadded {} + +impl CachePadded { + /// Pads and aligns a value to the length of a cache line. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::CachePadded; + /// + /// let padded_value = CachePadded::new(1); + /// ``` + pub fn new(t: T) -> CachePadded { + CachePadded:: { value: t } + } + + /// Returns the value value. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::CachePadded; + /// + /// let padded_value = CachePadded::new(7); + /// let value = padded_value.into_inner(); + /// assert_eq!(value, 7); + /// ``` + pub fn into_inner(self) -> T { + self.value + } +} + +impl Deref for CachePadded { + type Target = T; + + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for CachePadded { + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl fmt::Debug for CachePadded { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("CachePadded") + .field("value", &self.value) + .finish() + } +} + +impl From for CachePadded { + fn from(t: T) -> Self { + CachePadded::new(t) + } +} diff --git a/crossbeam-utils/src/lib.rs b/crossbeam-utils/src/lib.rs new file mode 100644 index 000000000..82b49aa5b --- /dev/null +++ b/crossbeam-utils/src/lib.rs @@ -0,0 +1,67 @@ +//! Miscellaneous tools for concurrent programming. +//! +//! ## Atomics +//! +//! * [`AtomicCell`], a thread-safe mutable memory location. +//! * [`AtomicConsume`], for reading from primitive atomic types with "consume" ordering. +//! +//! ## Thread synchronization +//! +//! * [`Parker`], a thread parking primitive. +//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. +//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. +//! +//! ## Utilities +//! +//! * [`Backoff`], for exponential backoff in spin loops. +//! * [`CachePadded`], for padding and aligning a value to the length of a cache line. +//! * [`scope`], for spawning threads that borrow local variables from the stack. +//! +//! [`AtomicCell`]: atomic/struct.AtomicCell.html +//! [`AtomicConsume`]: atomic/trait.AtomicConsume.html +//! [`Parker`]: sync/struct.Parker.html +//! [`ShardedLock`]: sync/struct.ShardedLock.html +//! [`WaitGroup`]: sync/struct.WaitGroup.html +//! [`Backoff`]: struct.Backoff.html +//! [`CachePadded`]: struct.CachePadded.html +//! [`scope`]: thread/fn.scope.html + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "nightly", feature(alloc))] +#![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] + +#[macro_use] +extern crate cfg_if; +#[cfg(feature = "std")] +extern crate core; + +cfg_if! { + if #[cfg(feature = "nightly")] { + extern crate alloc; + } else { + mod alloc { + extern crate std; + pub use self::std::*; + } + } +} + +pub mod atomic; + +mod cache_padded; +pub use cache_padded::CachePadded; + +mod backoff; +pub use backoff::Backoff; + +cfg_if! { + if #[cfg(feature = "std")] { + #[macro_use] + extern crate lazy_static; + + pub mod sync; + pub mod thread; + } +} diff --git a/crossbeam-utils/src/sync/mod.rs b/crossbeam-utils/src/sync/mod.rs new file mode 100644 index 000000000..31c8ffec4 --- /dev/null +++ b/crossbeam-utils/src/sync/mod.rs @@ -0,0 +1,17 @@ +//! Thread synchronization primitives. +//! +//! * [`Parker`], a thread parking primitive. +//! * [`ShardedLock`], a sharded reader-writer lock with fast concurrent reads. +//! * [`WaitGroup`], for synchronizing the beginning or end of some computation. +//! +//! [`Parker`]: struct.Parker.html +//! [`ShardedLock`]: struct.ShardedLock.html +//! [`WaitGroup`]: struct.WaitGroup.html + +mod parker; +mod sharded_lock; +mod wait_group; + +pub use self::sharded_lock::{ShardedLock, ShardedLockReadGuard, ShardedLockWriteGuard}; +pub use self::parker::{Parker, Unparker}; +pub use self::wait_group::WaitGroup; diff --git a/crossbeam-utils/src/sync/parker.rs b/crossbeam-utils/src/sync/parker.rs new file mode 100644 index 000000000..506db8e39 --- /dev/null +++ b/crossbeam-utils/src/sync/parker.rs @@ -0,0 +1,311 @@ +use std::fmt; +use std::marker::PhantomData; +use std::sync::{Arc, Condvar, Mutex}; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; +use std::time::Duration; + +/// A thread parking primitive. +/// +/// Conceptually, each `Parker` has an associated token which is initially not present: +/// +/// * The [`park`] method blocks the current thread unless or until the token is available, at +/// which point it automatically consumes the token. It may also return *spuriously*, without +/// consuming the token. +/// +/// * The [`park_timeout`] method works the same as [`park`], but blocks for a specified maximum +/// time. +/// +/// * The [`unpark`] method atomically makes the token available if it wasn't already. Because the +/// token is initially absent, [`unpark`] followed by [`park`] will result in the second call +/// returning immediately. +/// +/// In other words, each `Parker` acts a bit like a spinlock that can be locked and unlocked using +/// [`park`] and [`unpark`]. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_utils::sync::Parker; +/// +/// let mut p = Parker::new(); +/// let u = p.unparker().clone(); +/// +/// // Make the token available. +/// u.unpark(); +/// // Wakes up immediately and consumes the token. +/// p.park(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// u.unpark(); +/// }); +/// +/// // Wakes up when `u.unpark()` provides the token, but may also wake up +/// // spuriously before that without consuming the token. +/// p.park(); +/// ``` +/// +/// [`park`]: struct.Parker.html#method.park +/// [`park_timeout`]: struct.Parker.html#method.park_timeout +/// [`unpark`]: struct.Unparker.html#method.unpark +pub struct Parker { + unparker: Unparker, + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for Parker {} + +impl Parker { + /// Creates a new `Parker`. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let p = Parker::new(); + /// ``` + /// + pub fn new() -> Parker { + Parker { + unparker: Unparker { + inner: Arc::new(Inner { + state: AtomicUsize::new(EMPTY), + lock: Mutex::new(()), + cvar: Condvar::new(), + }), + }, + _marker: PhantomData, + } + } + + /// Blocks the current thread until the token is made available. + /// + /// A call to `park` may wake up spuriously without consuming the token, and callers should be + /// prepared for this possibility. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let mut p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// // Make the token available. + /// u.unpark(); + /// + /// // Wakes up immediately and consumes the token. + /// p.park(); + /// ``` + pub fn park(&self) { + self.unparker.inner.park(None); + } + + /// Blocks the current thread until the token is made available, but only for a limited time. + /// + /// A call to `park_timeout` may wake up spuriously without consuming the token, and callers + /// should be prepared for this possibility. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// use crossbeam_utils::sync::Parker; + /// + /// let mut p = Parker::new(); + /// + /// // Waits for the token to become available, but will not wait longer than 500 ms. + /// p.park_timeout(Duration::from_millis(500)); + /// ``` + pub fn park_timeout(&self, timeout: Duration) { + self.unparker.inner.park(Some(timeout)); + } + + /// Returns a reference to an associated [`Unparker`]. + /// + /// The returned [`Unparker`] doesn't have to be used by reference - it can also be cloned. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::Parker; + /// + /// let mut p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// // Make the token available. + /// u.unpark(); + /// // Wakes up immediately and consumes the token. + /// p.park(); + /// ``` + /// + /// [`park`]: struct.Parker.html#method.park + /// [`park_timeout`]: struct.Parker.html#method.park_timeout + /// + /// [`Unparker`]: struct.Unparker.html + pub fn unparker(&self) -> &Unparker { + &self.unparker + } +} + +impl fmt::Debug for Parker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Parker { .. }") + } +} + +/// Unparks a thread parked by the associated [`Parker`]. +/// +/// [`Parker`]: struct.Parker.html +pub struct Unparker { + inner: Arc, +} + +unsafe impl Send for Unparker {} +unsafe impl Sync for Unparker {} + +impl Unparker { + /// Atomically makes the token available if it is not already. + /// + /// This method will wake up the thread blocked on [`park`] or [`park_timeout`], if there is + /// any. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_utils::sync::Parker; + /// + /// let mut p = Parker::new(); + /// let u = p.unparker().clone(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(500)); + /// u.unpark(); + /// }); + /// + /// // Wakes up when `u.unpark()` provides the token, but may also wake up + /// // spuriously before that without consuming the token. + /// p.park(); + /// ``` + /// + /// [`park`]: struct.Parker.html#method.park + /// [`park_timeout`]: struct.Parker.html#method.park_timeout + pub fn unpark(&self) { + self.inner.unpark() + } +} + +impl fmt::Debug for Unparker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Unparker { .. }") + } +} + +impl Clone for Unparker { + fn clone(&self) -> Unparker { + Unparker { + inner: self.inner.clone(), + } + } +} + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +struct Inner { + state: AtomicUsize, + lock: Mutex<()>, + cvar: Condvar, +} + +impl Inner { + fn park(&self, timeout: Option) { + // If we were previously notified then we consume this notification and return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + // If the timeout is zero, then there is no need to actually block. + if let Some(ref dur) = timeout { + if *dur == Duration::from_millis(0) { + return; + } + } + + // Otherwise we need to coordinate going to sleep. + let mut m = self.lock.lock().unwrap(); + + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + // Consume this notification to avoid spurious wakeups in the next park. + Err(NOTIFIED) => { + // We must read `state` here, even though we know it will be `NOTIFIED`. This is + // because `unpark` may have been called again since we read `NOTIFIED` in the + // `compare_exchange` above. We must perform an acquire operation that synchronizes + // with that `unpark` to observe any writes it made before the call to `unpark`. To + // do that we must read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } + Err(n) => panic!("inconsistent park_timeout state: {}", n), + } + + match timeout { + None => { + loop { + // Block the current thread on the conditional variable. + m = self.cvar.wait(m).unwrap(); + + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => return, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + } + Some(timeout) => { + // Wait with a timeout, and if we spuriously wake up or otherwise wake up from a + // notification we just want to unconditionally set `state` back to `EMPTY`, either + // consuming a notification or un-flagging ourselves as parked. + let (_m, _result) = self.cvar.wait_timeout(m, timeout).unwrap(); + + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => {} // got a notification + PARKED => {} // no notification + n => panic!("inconsistent park_timeout state: {}", n), + } + } + } + } + + pub fn unpark(&self) { + // To ensure the unparked thread will observe any writes we made before this call, we must + // perform a release operation that `park` can synchronize with. To do that we must write + // `NOTIFIED` even if `state` is already `NOTIFIED`. That is why this must be a swap rather + // than a compare-and-swap that returns if it reads `NOTIFIED` on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to `PARKED` (or last + // checked `state` in the case of a spurious wakeup) and when it actually waits on `cvar`. + // If we were to notify during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has `lock` locked at this + // stage so we can acquire `lock` to wait until it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the parked thread wakes + // it doesn't get woken only to have to wait for us to release `lock`. + drop(self.lock.lock().unwrap()); + self.cvar.notify_one(); + } +} diff --git a/crossbeam-utils/src/sync/sharded_lock.rs b/crossbeam-utils/src/sync/sharded_lock.rs new file mode 100644 index 000000000..0fbb29175 --- /dev/null +++ b/crossbeam-utils/src/sync/sharded_lock.rs @@ -0,0 +1,600 @@ +use std::cell::UnsafeCell; +use std::collections::HashMap; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::sync::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{LockResult, PoisonError, TryLockError, TryLockResult}; +use std::thread::{self, ThreadId}; + +use CachePadded; + +/// The number of shards per sharded lock. Must be a power of two. +const NUM_SHARDS: usize = 8; + +/// A shard containing a single reader-writer lock. +struct Shard { + /// The inner reader-writer lock. + lock: RwLock<()>, + + /// The write-guard keeping this shard locked. + /// + /// Write operations will lock each shard and store the guard here. These guards get dropped at + /// the same time the big guard is dropped. + write_guard: UnsafeCell>>, +} + +/// A sharded reader-writer lock. +/// +/// This lock is equivalent to [`RwLock`], except read operations are faster and write operations +/// are slower. +/// +/// A `ShardedLock` is internally made of a list of *shards*, each being a [`RwLock`] occupying a +/// single cache line. Read operations will pick one of the shards depending on the current thread +/// and lock it. Write operations need to lock all shards in succession. +/// +/// By splitting the lock into shards, concurrent read operations will in most cases choose +/// different shards and thus update different cache lines, which is good for scalability. However, +/// write operations need to do more work and are therefore slower than usual. +/// +/// The priority policy of the lock is dependent on the underlying operating system's +/// implementation, and this type does not guarantee that any particular policy will be used. +/// +/// # Poisoning +/// +/// A `ShardedLock`, like [`RwLock`], will become poisoned on a panic. Note that it may only be +/// poisoned if a panic occurs while a write operation is in progress. If a panic occurs in any +/// read operation, the lock will not be poisoned. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::sync::ShardedLock; +/// +/// let lock = ShardedLock::new(5); +/// +/// // Any number of read locks can be held at once. +/// { +/// let r1 = lock.read().unwrap(); +/// let r2 = lock.read().unwrap(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // Read locks are dropped at this point. +/// +/// // However, only one write lock may be held. +/// { +/// let mut w = lock.write().unwrap(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // Write lock is dropped here. +/// ``` +/// +/// [`RwLock`]: https://doc.rust-lang.org/std/sync/struct.RwLock.html +pub struct ShardedLock { + /// A list of locks protecting the internal data. + shards: Box<[CachePadded]>, + + /// The internal data. + value: UnsafeCell, +} + +unsafe impl Send for ShardedLock {} +unsafe impl Sync for ShardedLock {} + +impl UnwindSafe for ShardedLock {} +impl RefUnwindSafe for ShardedLock {} + +impl ShardedLock { + /// Creates a new sharded reader-writer lock. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(5); + /// ``` + pub fn new(value: T) -> ShardedLock { + ShardedLock { + shards: (0..NUM_SHARDS) + .map(|_| CachePadded::new(Shard { + lock: RwLock::new(()), + write_guard: UnsafeCell::new(None), + })) + .collect::>() + .into_boxed_slice(), + value: UnsafeCell::new(value), + } + } + + /// Consumes this lock, returning the underlying data. + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(String::new()); + /// { + /// let mut s = lock.write().unwrap(); + /// *s = "modified".to_owned(); + /// } + /// assert_eq!(lock.into_inner().unwrap(), "modified"); + /// ``` + pub fn into_inner(self) -> LockResult { + let is_poisoned = self.is_poisoned(); + let inner = self.value.into_inner(); + + if is_poisoned { + Err(PoisonError::new(inner)) + } else { + Ok(inner) + } + } +} + +impl ShardedLock { + /// Returns `true` if the lock is poisoned. + /// + /// If another thread can still access the lock, it may become poisoned at any time. A `false` + /// result should not be trusted without additional synchronization. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let lock = Arc::new(ShardedLock::new(0)); + /// let c_lock = lock.clone(); + /// + /// let _ = thread::spawn(move || { + /// let _lock = c_lock.write().unwrap(); + /// panic!(); // the lock gets poisoned + /// }).join(); + /// assert_eq!(lock.is_poisoned(), true); + /// ``` + pub fn is_poisoned(&self) -> bool { + self.shards[0].lock.is_poisoned() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the lock mutably, no actual locking needs to take place. + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let mut lock = ShardedLock::new(0); + /// *lock.get_mut().unwrap() = 10; + /// assert_eq!(*lock.read().unwrap(), 10); + /// ``` + pub fn get_mut(&mut self) -> LockResult<&mut T> { + let is_poisoned = self.is_poisoned(); + let inner = unsafe { &mut *self.value.get() }; + + if is_poisoned { + Err(PoisonError::new(inner)) + } else { + Ok(inner) + } + } + + /// Attempts to acquire this lock with shared read access. + /// + /// If the access could not be granted at this time, an error is returned. Otherwise, a guard + /// is returned which will release the shared access when it is dropped. This method does not + /// provide any guarantees with respect to the ordering of whether contentious readers or + /// writers will acquire the lock first. + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// match lock.try_read() { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` + pub fn try_read(&self) -> TryLockResult> { + // Take the current thread index and map it to a shard index. Thread indices will tend to + // distribute shards among threads equally, thus reducing contention due to read-locking. + let current_index = current_index().unwrap_or(0); + let shard_index = current_index & (self.shards.len() - 1); + + match self.shards[shard_index].lock.try_read() { + Ok(guard) => Ok(ShardedLockReadGuard { + lock: self, + _guard: guard, + _marker: PhantomData, + }), + Err(TryLockError::Poisoned(err)) => { + let guard = ShardedLockReadGuard { + lock: self, + _guard: err.into_inner(), + _marker: PhantomData, + }; + Err(TryLockError::Poisoned(PoisonError::new(guard))) + }, + Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock), + } + } + + /// Locks with shared read access, blocking the current thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which hold the lock. + /// There may be other readers currently inside the lock when this method returns. This method + /// does not provide any guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// Returns a guard which will release the shared access when dropped. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// use std::sync::Arc; + /// use std::thread; + /// + /// let lock = Arc::new(ShardedLock::new(1)); + /// let c_lock = lock.clone(); + /// + /// let n = lock.read().unwrap(); + /// assert_eq!(*n, 1); + /// + /// thread::spawn(move || { + /// let r = c_lock.read(); + /// assert!(r.is_ok()); + /// }).join().unwrap(); + /// ``` + pub fn read(&self) -> LockResult> { + // Take the current thread index and map it to a shard index. Thread indices will tend to + // distribute shards among threads equally, thus reducing contention due to read-locking. + let current_index = current_index().unwrap_or(0); + let shard_index = current_index & (self.shards.len() - 1); + + match self.shards[shard_index].lock.read() { + Ok(guard) => Ok(ShardedLockReadGuard { + lock: self, + _guard: guard, + _marker: PhantomData, + }), + Err(err) => Err(PoisonError::new(ShardedLockReadGuard { + lock: self, + _guard: err.into_inner(), + _marker: PhantomData, + })), + } + } + + /// Attempts to acquire this lock with exclusive write access. + /// + /// If the access could not be granted at this time, an error is returned. Otherwise, a guard + /// is returned which will release the exclusive access when it is dropped. This method does + /// not provide any guarantees with respect to the ordering of whether contentious readers or + /// writers will acquire the lock first. + /// + /// This method will return an error if the lock is poisoned. A lock gets poisoned when a write + /// operation panics. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// let n = lock.read().unwrap(); + /// assert_eq!(*n, 1); + /// + /// assert!(lock.try_write().is_err()); + /// ``` + pub fn try_write(&self) -> TryLockResult> { + let mut poisoned = false; + let mut blocked = None; + + // Write-lock each shard in succession. + for (i, shard) in self.shards.iter().enumerate() { + let guard = match shard.lock.try_write() { + Ok(guard) => guard, + Err(TryLockError::Poisoned(err)) => { + poisoned = true; + err.into_inner() + }, + Err(TryLockError::WouldBlock) => { + blocked = Some(i); + break; + } + }; + + // Store the guard into the shard. + unsafe { + let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); + let dest: *mut _ = shard.write_guard.get(); + *dest = Some(guard); + } + } + + if let Some(i) = blocked { + // Unlock the shards in reverse order of locking. + for shard in self.shards[0..i].iter().rev() { + unsafe { + let dest: *mut _ = shard.write_guard.get(); + let guard = mem::replace(&mut *dest, None); + drop(guard); + } + } + Err(TryLockError::WouldBlock) + } else if poisoned { + let guard = ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }; + Err(TryLockError::Poisoned(PoisonError::new(guard))) + } else { + Ok(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }) + } + } + + /// Locks with exclusive write access, blocking the current thread until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which hold the lock. + /// There may be other readers currently inside the lock when this method returns. This method + /// does not provide any guarantees with respect to the ordering of whether contentious readers + /// or writers will acquire the lock first. + /// + /// Returns a guard which will release the exclusive access when dropped. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::ShardedLock; + /// + /// let lock = ShardedLock::new(1); + /// + /// let mut n = lock.write().unwrap(); + /// *n = 2; + /// + /// assert!(lock.try_read().is_err()); + /// ``` + pub fn write(&self) -> LockResult> { + let mut poisoned = false; + + // Write-lock each shard in succession. + for shard in self.shards.iter() { + let guard = match shard.lock.write() { + Ok(guard) => guard, + Err(err) => { + poisoned = true; + err.into_inner() + } + }; + + // Store the guard into the shard. + unsafe { + let guard: RwLockWriteGuard<'_, ()> = guard; + let guard: RwLockWriteGuard<'static, ()> = mem::transmute(guard); + let dest: *mut _ = shard.write_guard.get(); + *dest = Some(guard); + } + } + + if poisoned { + Err(PoisonError::new(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + })) + } else { + Ok(ShardedLockWriteGuard { + lock: self, + _marker: PhantomData, + }) + } + } +} + +impl fmt::Debug for ShardedLock { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.try_read() { + Ok(guard) => f.debug_struct("ShardedLock").field("data", &&*guard).finish(), + Err(TryLockError::Poisoned(err)) => { + f.debug_struct("ShardedLock").field("data", &&**err.get_ref()).finish() + }, + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("") + } + } + f.debug_struct("ShardedLock").field("data", &LockedPlaceholder).finish() + } + } + } +} + +impl Default for ShardedLock { + fn default() -> ShardedLock { + ShardedLock::new(Default::default()) + } +} + +impl From for ShardedLock { + fn from(t: T) -> Self { + ShardedLock::new(t) + } +} + +/// A guard used to release the shared read access of a [`ShardedLock`] when dropped. +/// +/// [`ShardedLock`]: struct.ShardedLock.html +pub struct ShardedLockReadGuard<'a, T: ?Sized + 'a> { + lock: &'a ShardedLock, + _guard: RwLockReadGuard<'a, ()>, + _marker: PhantomData>, +} + +unsafe impl<'a, T: ?Sized + Sync> Sync for ShardedLockReadGuard<'a, T> {} + +impl<'a, T: ?Sized> Deref for ShardedLockReadGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ShardedLockReadGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ShardedLockReadGuard") + .field("lock", &self.lock) + .finish() + } +} + +impl<'a, T: ?Sized + fmt::Display> fmt::Display for ShardedLockReadGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} + +/// A guard used to release the exclusive write access of a [`ShardedLock`] when dropped. +/// +/// [`ShardedLock`]: struct.ShardedLock.html +pub struct ShardedLockWriteGuard<'a, T: ?Sized + 'a> { + lock: &'a ShardedLock, + _marker: PhantomData>, +} + +unsafe impl<'a, T: ?Sized + Sync> Sync for ShardedLockWriteGuard<'a, T> {} + +impl<'a, T: ?Sized> Drop for ShardedLockWriteGuard<'a, T> { + fn drop(&mut self) { + // Unlock the shards in reverse order of locking. + for shard in self.lock.shards.iter().rev() { + unsafe { + let dest: *mut _ = shard.write_guard.get(); + let guard = mem::replace(&mut *dest, None); + drop(guard); + } + } + } +} + +impl<'a, T: fmt::Debug> fmt::Debug for ShardedLockWriteGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ShardedLockWriteGuard") + .field("lock", &self.lock) + .finish() + } +} + +impl<'a, T: ?Sized + fmt::Display> fmt::Display for ShardedLockWriteGuard<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} + +impl<'a, T: ?Sized> Deref for ShardedLockWriteGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.lock.value.get() } + } +} + +impl<'a, T: ?Sized> DerefMut for ShardedLockWriteGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.lock.value.get() } + } +} + +/// Returns a `usize` that identifies the current thread. +/// +/// Each thread is associated with an 'index'. While there are no particular guarantees, indices +/// usually tend to be consecutive numbers between 0 and the number of running threads. +/// +/// Since this function accesses TLS, `None` might be returned if the current thread's TLS is +/// tearing down. +#[inline] +fn current_index() -> Option { + REGISTRATION.try_with(|reg| reg.index).ok() +} + +/// The global registry keeping track of registered threads and indices. +struct ThreadIndices { + /// Mapping from `ThreadId` to thread index. + mapping: HashMap, + + /// A list of free indices. + free_list: Vec, + + /// The next index to allocate if the free list is empty. + next_index: usize, +} + +lazy_static! { + static ref THREAD_INDICES: Mutex = Mutex::new(ThreadIndices { + mapping: HashMap::new(), + free_list: Vec::new(), + next_index: 0, + }); +} + +/// A registration of a thread with an index. +/// +/// When dropped, unregisters the thread and frees the reserved index. +struct Registration { + index: usize, + thread_id: ThreadId, +} + +impl Drop for Registration { + fn drop(&mut self) { + let mut indices = THREAD_INDICES.lock().unwrap(); + indices.mapping.remove(&self.thread_id); + indices.free_list.push(self.index); + } +} + +thread_local! { + static REGISTRATION: Registration = { + let thread_id = thread::current().id(); + let mut indices = THREAD_INDICES.lock().unwrap(); + + let index = match indices.free_list.pop() { + Some(i) => i, + None => { + let i = indices.next_index; + indices.next_index += 1; + i + } + }; + indices.mapping.insert(thread_id, index); + + Registration { + index, + thread_id, + } + }; +} diff --git a/crossbeam-utils/src/sync/wait_group.rs b/crossbeam-utils/src/sync/wait_group.rs new file mode 100644 index 000000000..16ddc3091 --- /dev/null +++ b/crossbeam-utils/src/sync/wait_group.rs @@ -0,0 +1,139 @@ +use std::fmt; +use std::sync::{Arc, Condvar, Mutex}; + +/// Enables threads to synchronize the beginning or end of some computation. +/// +/// # Wait groups vs barriers +/// +/// `WaitGroup` is very similar to [`Barrier`], but there are a few differences: +/// +/// * `Barrier` needs to know the number of threads at construction, while `WaitGroup` is cloned to +/// register more threads. +/// +/// * A `Barrier` can be reused even after all threads have synchronized, while a `WaitGroup` +/// synchronizes threads only once. +/// +/// * All threads wait for others to reach the `Barrier`. With `WaitGroup`, each thread can choose +/// to either wait for other threads or to continue without blocking. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::sync::WaitGroup; +/// use std::thread; +/// +/// // Create a new wait group. +/// let wg = WaitGroup::new(); +/// +/// for _ in 0..4 { +/// // Create another reference to the wait group. +/// let wg = wg.clone(); +/// +/// thread::spawn(move || { +/// // Do some work. +/// +/// // Drop the reference to the wait group. +/// drop(wg); +/// }); +/// } +/// +/// // Block until all threads have finished their work. +/// wg.wait(); +/// ``` +/// +/// [`Barrier`]: https://doc.rust-lang.org/std/sync/struct.Barrier.html +pub struct WaitGroup { + inner: Arc, +} + +/// Inner state of a `WaitGroup`. +struct Inner { + cvar: Condvar, + count: Mutex, +} + +impl WaitGroup { + /// Creates a new wait group and returns the single reference to it. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::WaitGroup; + /// + /// let wg = WaitGroup::new(); + /// ``` + pub fn new() -> WaitGroup { + WaitGroup { + inner: Arc::new(Inner { + cvar: Condvar::new(), + count: Mutex::new(1), + }), + } + } + + /// Drops this reference and waits until all other references are dropped. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::sync::WaitGroup; + /// use std::thread; + /// + /// let wg = WaitGroup::new(); + /// + /// thread::spawn({ + /// let wg = wg.clone(); + /// move || { + /// // Block until both threads have reached `wait()`. + /// wg.wait(); + /// } + /// }); + /// + /// // Block until both threads have reached `wait()`. + /// wg.wait(); + /// ``` + pub fn wait(self) { + if *self.inner.count.lock().unwrap() == 1 { + return; + } + + let inner = self.inner.clone(); + drop(self); + + let mut count = inner.count.lock().unwrap(); + while *count > 0 { + count = inner.cvar.wait(count).unwrap(); + } + } +} + +impl Drop for WaitGroup { + fn drop(&mut self) { + let mut count = self.inner.count.lock().unwrap(); + *count -= 1; + + if *count == 0 { + self.inner.cvar.notify_all(); + } + } +} + +impl Clone for WaitGroup { + fn clone(&self) -> WaitGroup { + let mut count = self.inner.count.lock().unwrap(); + *count += 1; + + WaitGroup { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for WaitGroup { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let count: &usize = &*self.inner.count.lock().unwrap(); + f.debug_struct("WaitGroup") + .field("count", count) + .finish() + } +} diff --git a/crossbeam-utils/src/thread.rs b/crossbeam-utils/src/thread.rs new file mode 100644 index 000000000..495e9b1ca --- /dev/null +++ b/crossbeam-utils/src/thread.rs @@ -0,0 +1,529 @@ +//! Threads that can borrow variables from the stack. +//! +//! Create a scope when spawned threads need to access variables on the stack: +//! +//! ``` +//! use crossbeam_utils::thread; +//! +//! let people = vec![ +//! "Alice".to_string(), +//! "Bob".to_string(), +//! "Carol".to_string(), +//! ]; +//! +//! thread::scope(|s| { +//! for person in &people { +//! s.spawn(move |_| { +//! println!("Hello, {}!", person); +//! }); +//! } +//! }).unwrap(); +//! ``` +//! +//! # Why scoped threads? +//! +//! Suppose we wanted to re-write the previous example using plain threads: +//! +//! ```ignore +//! use std::thread; +//! +//! let people = vec![ +//! "Alice".to_string(), +//! "Bob".to_string(), +//! "Carol".to_string(), +//! ]; +//! +//! let mut threads = Vec::new(); +//! +//! for person in &people { +//! threads.push(thread::spawn(move |_| { +//! println!("Hello, {}!", person); +//! })); +//! } +//! +//! for thread in threads { +//! thread.join().unwrap(); +//! } +//! ``` +//! +//! This doesn't work because the borrow checker complains about `people` not living long enough: +//! +//! ```text +//! error[E0597]: `people` does not live long enough +//! --> src/main.rs:12:20 +//! | +//! 12 | for person in &people { +//! | ^^^^^^ borrowed value does not live long enough +//! ... +//! 21 | } +//! | - borrowed value only lives until here +//! | +//! = note: borrowed value must be valid for the static lifetime... +//! ``` +//! +//! The problem here is that spawned threads are not allowed to borrow variables on stack because +//! the compiler cannot prove they will be joined before `people` is destroyed. +//! +//! Scoped threads are a mechanism to guarantee to the compiler that spawned threads will be joined +//! before the scope ends. +//! +//! # How scoped threads work +//! +//! If a variable is borrowed by a thread, the thread must complete before the variable is +//! destroyed. Threads spawned using [`std::thread::spawn`] can only borrow variables with the +//! `'static` lifetime because the borrow checker cannot be sure when the thread will complete. +//! +//! A scope creates a clear boundary between variables outside the scope and threads inside the +//! scope. Whenever a s.spawns a thread, it promises to join the thread before the scope ends. +//! This way we guarantee to the borrow checker that scoped threads only live within the scope and +//! can safely access variables outside it. +//! +//! # Nesting scoped threads +//! +//! Sometimes scoped threads need to spawn more threads within the same scope. This is a little +//! tricky because argument `s` lives *inside* the invocation of `thread::scope()` and as such +//! cannot be borrowed by scoped threads: +//! +//! ```ignore +//! use crossbeam_utils::thread; +//! +//! thread::scope(|s| { +//! s.spawn(|_| { +//! // Not going to compile because we're trying to borrow `s`, +//! // which lives *inside* the scope! :( +//! s.spawn(|_| println!("nested thread")); +//! }}); +//! }); +//! ``` +//! +//! Fortunately, there is a solution. Every scoped thread is passed a reference to its scope as an +//! argument, which can be used for spawning nested threads: +//! +//! ```ignore +//! use crossbeam_utils::thread; +//! +//! thread::scope(|s| { +//! // Note the `|s|` here. +//! s.spawn(|s| { +//! // Yay, this works because we're using a fresh argument `s`! :) +//! s.spawn(|_| println!("nested thread")); +//! }}); +//! }); +//! ``` +//! +//! [`std::thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html + +use std::fmt; +use std::io; +use std::marker::PhantomData; +use std::mem; +use std::panic; +use std::sync::{Arc, Mutex}; +use std::thread; + +use sync::WaitGroup; + +type SharedVec = Arc>>; +type SharedOption = Arc>>; + +/// Creates a new scope for spawning threads. +/// +/// All child threads that haven't been manually joined will be automatically joined just before +/// this function invocation ends. If all joined threads have successfully completed, `Ok` is +/// returned with the return value of `f`. If any of the joined threads has panicked, an `Err` is +/// returned containing errors from panicked threads. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::thread; +/// +/// let var = vec![1, 2, 3]; +/// +/// thread::scope(|s| { +/// s.spawn(|_| { +/// println!("A child thread borrowing `var`: {:?}", var); +/// }); +/// }).unwrap(); +/// ``` +pub fn scope<'env, F, R>(f: F) -> thread::Result +where + F: FnOnce(&Scope<'env>) -> R, +{ + let wg = WaitGroup::new(); + let scope = Scope::<'env> { + handles: SharedVec::default(), + wait_group: wg.clone(), + _marker: PhantomData, + }; + + // Execute the scoped function, but catch any panics. + let result = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&scope))); + + // Wait until all nested scopes are dropped. + drop(scope.wait_group); + wg.wait(); + + // Join all remaining spawned threads. + let panics: Vec<_> = { + let mut handles = scope.handles.lock().unwrap(); + + // Filter handles that haven't been joined, join them, and collect errors. + let panics = handles + .drain(..) + .filter_map(|handle| handle.lock().unwrap().take()) + .filter_map(|handle| handle.join().err()) + .collect(); + + panics + }; + + // If `f` has panicked, resume unwinding. + // If any of the child threads have panicked, return the panic errors. + // Otherwise, everything is OK and return the result of `f`. + match result { + Err(err) => panic::resume_unwind(err), + Ok(res) => { + if panics.is_empty() { + Ok(res) + } else { + Err(Box::new(panics)) + } + } + } +} + +/// A scope for spawning threads. +pub struct Scope<'env> { + /// The list of the thread join handles. + handles: SharedVec>>, + + /// Used to wait until all subscopes all dropped. + wait_group: WaitGroup, + + /// Borrows data with invariant lifetime `'env`. + _marker: PhantomData<&'env mut &'env ()>, +} + +unsafe impl<'env> Sync for Scope<'env> {} + +impl<'env> Scope<'env> { + /// Spawns a scoped thread. + /// + /// This method is similar to the [`spawn`] function in Rust's standard library. The difference + /// is that this thread is scoped, meaning it's guaranteed to terminate before the scope exits, + /// allowing it to reference variables outside the scope. + /// + /// The scoped thread is passed a reference to this scope as an argument, which can be used for + /// spawning nested threads. + /// + /// The returned handle can be used to manually join the thread before the scope exits. + /// + /// [`spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.spawn(|_| { + /// println!("A child thread is running"); + /// 42 + /// }); + /// + /// // Join the thread and retrieve its result. + /// let res = handle.join().unwrap(); + /// assert_eq!(res, 42); + /// }).unwrap(); + /// ``` + pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> + where + F: FnOnce(&Scope<'env>) -> T, + F: Send + 'env, + T: Send + 'env, + { + self.builder().spawn(f).unwrap() + } + + /// Creates a builder that can configure a thread before spawning. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// use std::thread::current; + /// + /// thread::scope(|s| { + /// s.builder() + /// .spawn(|_| println!("A child thread is running")) + /// .unwrap(); + /// }).unwrap(); + /// ``` + pub fn builder<'scope>(&'scope self) -> ScopedThreadBuilder<'scope, 'env> { + ScopedThreadBuilder { + scope: self, + builder: thread::Builder::new(), + } + } +} + +impl<'env> fmt::Debug for Scope<'env> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Scope { .. }") + } +} + +/// Configures the properties of a new thread. +/// +/// The two configurable properties are: +/// +/// - [`name`]: Specifies an [associated name for the thread][naming-threads]. +/// - [`stack_size`]: Specifies the [desired stack size for the thread][stack-size]. +/// +/// The [`spawn`] method will take ownership of the builder and return an [`io::Result`] of the +/// thread handle with the given configuration. +/// +/// The [`Scope::spawn`] method uses a builder with default configuration and unwraps its return +/// value. You may want to use this builder when you want to recover from a failure to launch a +/// thread. +/// +/// # Examples +/// +/// ``` +/// use crossbeam_utils::thread; +/// +/// thread::scope(|s| { +/// s.builder() +/// .spawn(|_| println!("Running a child thread")) +/// .unwrap(); +/// }).unwrap(); +/// ``` +/// +/// [`name`]: struct.ScopedThreadBuilder.html#method.name +/// [`stack_size`]: struct.ScopedThreadBuilder.html#method.stack_size +/// [`spawn`]: struct.ScopedThreadBuilder.html#method.spawn +/// [`Scope::spawn`]: struct.Scope.html#method.spawn +/// [`io::Result`]: https://doc.rust-lang.org/std/io/type.Result.html +/// [naming-threads]: https://doc.rust-lang.org/std/thread/index.html#naming-threads +/// [stack-size]: https://doc.rust-lang.org/std/thread/index.html#stack-size +#[derive(Debug)] +pub struct ScopedThreadBuilder<'scope, 'env: 'scope> { + scope: &'scope Scope<'env>, + builder: thread::Builder, +} + +impl<'scope, 'env> ScopedThreadBuilder<'scope, 'env> { + /// Sets the name for the new thread. + /// + /// The name must not contain null bytes. For more information about named threads, see + /// [here][naming-threads]. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// use std::thread::current; + /// + /// thread::scope(|s| { + /// s.builder() + /// .name("my thread".to_string()) + /// .spawn(|_| assert_eq!(current().name(), Some("my thread"))) + /// .unwrap(); + /// }).unwrap(); + /// ``` + /// + /// [naming-threads]: https://doc.rust-lang.org/std/thread/index.html#naming-threads + pub fn name(mut self, name: String) -> ScopedThreadBuilder<'scope, 'env> { + self.builder = self.builder.name(name); + self + } + + /// Sets the size of the stack for the new thread. + /// + /// The stack size is measured in bytes. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// s.builder() + /// .stack_size(32 * 1024) + /// .spawn(|_| println!("Running a child thread")) + /// .unwrap(); + /// }).unwrap(); + /// ``` + pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'scope, 'env> { + self.builder = self.builder.stack_size(size); + self + } + + /// Spawns a scoped thread with this configuration. + /// + /// The scoped thread is passed a reference to this scope as an argument, which can be used for + /// spawning nested threads. + /// + /// The returned handle can be used to manually join the thread before the scope exits. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.builder() + /// .spawn(|_| { + /// println!("A child thread is running"); + /// 42 + /// }) + /// .unwrap(); + /// + /// // Join the thread and retrieve its result. + /// let res = handle.join().unwrap(); + /// assert_eq!(res, 42); + /// }).unwrap(); + /// ``` + pub fn spawn(self, f: F) -> io::Result> + where + F: FnOnce(&Scope<'env>) -> T, + F: Send + 'env, + T: Send + 'env, + { + // The result of `f` will be stored here. + let result = SharedOption::default(); + + // Spawn the thread and grab its join handle and thread handle. + let (handle, thread) = { + let result = Arc::clone(&result); + + // A clone of the scope that will be moved into the new thread. + let scope = Scope::<'env> { + handles: Arc::clone(&self.scope.handles), + wait_group: self.scope.wait_group.clone(), + _marker: PhantomData, + }; + + // Spawn the thread. + let handle = { + let closure = move || { + // Make sure the scope is inside the closure with the proper `'env` lifetime. + let scope: Scope<'env> = scope; + + // Run the closure. + let res = f(&scope); + + // Store the result if the closure didn't panic. + *result.lock().unwrap() = Some(res); + }; + + // Change the type of `closure` from `FnOnce() -> T` to `FnMut() -> T`. + let mut closure = Some(closure); + let closure = move || closure.take().unwrap()(); + + // Allocate `clsoure` on the heap and erase the `'env` bound. + let closure: Box = Box::new(closure); + let closure: Box = unsafe { mem::transmute(closure) }; + + // Finally, spawn the closure. + let mut closure = closure; + self.builder.spawn(move || closure())? + }; + + let thread = handle.thread().clone(); + let handle = Arc::new(Mutex::new(Some(handle))); + (handle, thread) + }; + + // Add the handle to the shared list of join handles. + self.scope.handles.lock().unwrap().push(Arc::clone(&handle)); + + Ok(ScopedJoinHandle { + handle, + result, + thread, + _marker: PhantomData, + }) + } +} + +unsafe impl<'scope, T> Send for ScopedJoinHandle<'scope, T> {} +unsafe impl<'scope, T> Sync for ScopedJoinHandle<'scope, T> {} + +/// A handle that can be used to join its scoped thread. +pub struct ScopedJoinHandle<'scope, T> { + /// A join handle to the spawned thread. + handle: SharedOption>, + + /// Holds the result of the inner closure. + result: SharedOption, + + /// A handle to the the spawned thread. + thread: thread::Thread, + + /// Borrows the parent scope with lifetime `'scope`. + _marker: PhantomData<&'scope ()>, +} + +impl<'scope, T> ScopedJoinHandle<'scope, T> { + /// Waits for the thread to finish and returns its result. + /// + /// If the child thread panics, an error is returned. + /// + /// # Panics + /// + /// This function may panic on some platforms if a thread attempts to join itself or otherwise + /// may create a deadlock with joining threads. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle1 = s.spawn(|_| println!("I'm a happy thread :)")); + /// let handle2 = s.spawn(|_| panic!("I'm a sad thread :(")); + /// + /// // Join the first thread and verify that it succeeded. + /// let res = handle1.join(); + /// assert!(res.is_ok()); + /// + /// // Join the second thread and verify that it panicked. + /// let res = handle2.join(); + /// assert!(res.is_err()); + /// }).unwrap(); + /// ``` + pub fn join(self) -> thread::Result { + // Take out the handle. The handle will surely be available because the root scope waits + // for nested scopes before joining remaining threads. + let handle = self.handle.lock().unwrap().take().unwrap(); + + // Join the thread and then take the result out of its inner closure. + handle + .join() + .map(|()| self.result.lock().unwrap().take().unwrap()) + } + + /// Returns a handle to the underlying thread. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_utils::thread; + /// + /// thread::scope(|s| { + /// let handle = s.spawn(|_| println!("A child thread is running")); + /// println!("The child thread ID: {:?}", handle.thread().id()); + /// }).unwrap(); + /// ``` + pub fn thread(&self) -> &thread::Thread { + &self.thread + } +} + +impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("ScopedJoinHandle { .. }") + } +} diff --git a/crossbeam-utils/tests/atomic_cell.rs b/crossbeam-utils/tests/atomic_cell.rs new file mode 100644 index 000000000..37c901f04 --- /dev/null +++ b/crossbeam-utils/tests/atomic_cell.rs @@ -0,0 +1,208 @@ +extern crate crossbeam_utils; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +use crossbeam_utils::atomic::AtomicCell; + +#[test] +fn is_lock_free() { + struct UsizeWrap(usize); + struct U8Wrap(bool); + + assert_eq!(AtomicCell::::is_lock_free(), true); + assert_eq!(AtomicCell::::is_lock_free(), true); + assert_eq!(AtomicCell::::is_lock_free(), true); + + assert_eq!(AtomicCell::::is_lock_free(), cfg!(feature = "nightly")); + assert_eq!( + AtomicCell::::is_lock_free(), + cfg!(feature = "nightly") + ); + assert_eq!( + AtomicCell::::is_lock_free(), + cfg!(feature = "nightly") + ); +} + +#[test] +fn drops_unit() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(); + + impl Foo { + fn new() -> Foo { + CNT.fetch_add(1, SeqCst); + Foo() + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new() + } + } + + let a = AtomicCell::new(Foo::new()); + + assert_eq!(a.swap(Foo::new()), Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new()); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn drops_u8() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(u8); + + impl Foo { + fn new(val: u8) -> Foo { + CNT.fetch_add(1, SeqCst); + Foo(val) + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new(0) + } + } + + let a = AtomicCell::new(Foo::new(5)); + + assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); + assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(0)); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn drops_usize() { + static CNT: AtomicUsize = AtomicUsize::new(0); + CNT.store(0, SeqCst); + + #[derive(Debug, PartialEq, Eq)] + struct Foo(usize); + + impl Foo { + fn new(val: usize) -> Foo { + CNT.fetch_add(1, SeqCst); + Foo(val) + } + } + + impl Drop for Foo { + fn drop(&mut self) { + CNT.fetch_sub(1, SeqCst); + } + } + + impl Default for Foo { + fn default() -> Foo { + Foo::new(0) + } + } + + let a = AtomicCell::new(Foo::new(5)); + + assert_eq!(a.swap(Foo::new(6)), Foo::new(5)); + assert_eq!(a.swap(Foo::new(1)), Foo::new(6)); + assert_eq!(CNT.load(SeqCst), 1); + + a.store(Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(2)); + assert_eq!(CNT.load(SeqCst), 1); + + assert_eq!(a.swap(Foo::default()), Foo::new(0)); + assert_eq!(CNT.load(SeqCst), 1); + + drop(a); + assert_eq!(CNT.load(SeqCst), 0); +} + +#[test] +fn modular_u8() { + #[derive(Clone, Copy, Eq, Debug, Default)] + struct Foo(u8); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 % 5 == other.0 % 5 + } + } + + let a = AtomicCell::new(Foo(1)); + + assert_eq!(a.load(), Foo(1)); + assert_eq!(a.swap(Foo(2)), Foo(11)); + assert_eq!(a.load(), Foo(52)); + + a.store(Foo(0)); + assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); + assert_eq!(a.load().0, 5); + assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); + assert_eq!(a.load().0, 15); +} + +#[test] +fn modular_usize() { + #[derive(Clone, Copy, Eq, Debug, Default)] + struct Foo(usize); + + impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.0 % 5 == other.0 % 5 + } + } + + let a = AtomicCell::new(Foo(1)); + + assert_eq!(a.load(), Foo(1)); + assert_eq!(a.swap(Foo(2)), Foo(11)); + assert_eq!(a.load(), Foo(52)); + + a.store(Foo(0)); + assert_eq!(a.compare_exchange(Foo(0), Foo(5)), Ok(Foo(100))); + assert_eq!(a.load().0, 5); + assert_eq!(a.compare_exchange(Foo(10), Foo(15)), Ok(Foo(100))); + assert_eq!(a.load().0, 15); +} diff --git a/crossbeam-utils/tests/cache_padded.rs b/crossbeam-utils/tests/cache_padded.rs new file mode 100644 index 000000000..8ad7d40a4 --- /dev/null +++ b/crossbeam-utils/tests/cache_padded.rs @@ -0,0 +1,112 @@ +extern crate crossbeam_utils; + +use std::cell::Cell; +use std::mem; + +use crossbeam_utils::CachePadded; + +#[test] +fn default() { + let x: CachePadded = Default::default(); + assert_eq!(*x, 0); +} + +#[test] +fn store_u64() { + let x: CachePadded = CachePadded::new(17); + assert_eq!(*x, 17); +} + +#[test] +fn store_pair() { + let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37)); + assert_eq!(x.0, 17); + assert_eq!(x.1, 37); +} + +#[test] +fn distance() { + let arr = [CachePadded::new(17u8), CachePadded::new(37u8)]; + let a = &*arr[0] as *const u8; + let b = &*arr[1] as *const u8; + assert!(unsafe { a.offset(64) } <= b); +} + +#[test] +fn different_sizes() { + CachePadded::new(17u8); + CachePadded::new(17u16); + CachePadded::new(17u32); + CachePadded::new([17u64; 0]); + CachePadded::new([17u64; 1]); + CachePadded::new([17u64; 2]); + CachePadded::new([17u64; 3]); + CachePadded::new([17u64; 4]); + CachePadded::new([17u64; 5]); + CachePadded::new([17u64; 6]); + CachePadded::new([17u64; 7]); + CachePadded::new([17u64; 8]); +} + +#[test] +fn large() { + let a = [17u64; 9]; + let b = CachePadded::new(a); + assert!(mem::size_of_val(&a) <= mem::size_of_val(&b)); +} + +#[test] +fn debug() { + assert_eq!( + format!("{:?}", CachePadded::new(17u64)), + "CachePadded { value: 17 }" + ); +} + +#[test] +fn drops() { + let count = Cell::new(0); + + struct Foo<'a>(&'a Cell); + + impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + let a = CachePadded::new(Foo(&count)); + let b = CachePadded::new(Foo(&count)); + + assert_eq!(count.get(), 0); + drop(a); + assert_eq!(count.get(), 1); + drop(b); + assert_eq!(count.get(), 2); +} + +#[test] +fn clone() { + let a = CachePadded::new(17); + let b = a.clone(); + assert_eq!(*a, *b); +} + +#[test] +fn runs_custom_clone() { + let count = Cell::new(0); + + struct Foo<'a>(&'a Cell); + + impl<'a> Clone for Foo<'a> { + fn clone(&self) -> Foo<'a> { + self.0.set(self.0.get() + 1); + Foo::<'a>(self.0) + } + } + + let a = CachePadded::new(Foo(&count)); + let _ = a.clone(); + + assert_eq!(count.get(), 1); +} diff --git a/crossbeam-utils/tests/parker.rs b/crossbeam-utils/tests/parker.rs new file mode 100644 index 000000000..fab07b3a3 --- /dev/null +++ b/crossbeam-utils/tests/parker.rs @@ -0,0 +1,42 @@ +extern crate crossbeam_utils; + +use std::thread::sleep; +use std::time::Duration; +use std::u32; + +use crossbeam_utils::sync::Parker; +use crossbeam_utils::thread; + +#[test] +fn park_timeout_unpark_before() { + let p = Parker::new(); + for _ in 0..10 { + p.unparker().unpark(); + p.park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn park_timeout_unpark_not_called() { + let p = Parker::new(); + for _ in 0..10 { + p.park_timeout(Duration::from_millis(10)); + } +} + +#[test] +fn park_timeout_unpark_called_other_thread() { + for _ in 0..10 { + let p = Parker::new(); + let u = p.unparker().clone(); + + thread::scope(|scope| { + scope.spawn(move |_| { + sleep(Duration::from_millis(50)); + u.unpark(); + }); + + p.park_timeout(Duration::from_millis(u32::MAX as u64)); + }).unwrap(); + } +} diff --git a/crossbeam-utils/tests/sharded_lock.rs b/crossbeam-utils/tests/sharded_lock.rs new file mode 100644 index 000000000..374c3c36c --- /dev/null +++ b/crossbeam-utils/tests/sharded_lock.rs @@ -0,0 +1,245 @@ +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::mpsc::channel; +use std::thread; +use std::sync::{Arc, TryLockError}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crossbeam_utils::sync::ShardedLock; +use rand::Rng; + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let l = ShardedLock::new(()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); +} + +#[test] +fn frob() { + const N: u32 = 10; + const M: usize = 1000; + + let r = Arc::new(ShardedLock::new(())); + + let (tx, rx) = channel::<()>(); + for _ in 0..N { + let tx = tx.clone(); + let r = r.clone(); + thread::spawn(move || { + let mut rng = rand::thread_rng(); + for _ in 0..M { + if rng.gen_bool(1.0 / (N as f64)) { + drop(r.write().unwrap()); + } else { + drop(r.read().unwrap()); + } + } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv(); +} + +#[test] +fn arc_poison_wr() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }).join(); + assert!(arc.read().is_err()); +} + +#[test] +fn arc_poison_ww() { + let arc = Arc::new(ShardedLock::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }).join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn arc_no_poison_rr() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!(); + }).join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} +#[test] +fn arc_no_poison_sl() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!() + }).join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +fn arc() { + let arc = Arc::new(ShardedLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = arc2.write().unwrap(); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; + } + tx.send(()).unwrap(); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = arc3.read().unwrap(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 10); +} + +#[test] +fn arc_access_in_unwind() { + let arc = Arc::new(ShardedLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write().unwrap(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }).join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn unsized_type() { + let sl: &ShardedLock<[i32]> = &ShardedLock::new([1, 2, 3]); + { + let b = &mut *sl.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*sl.read().unwrap(), comp); +} + +#[test] +fn try_write() { + let lock = ShardedLock::new(0isize); + let read_guard = lock.read().unwrap(); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), + Err(_) => assert!(false, "unexpected error"), + } + + drop(read_guard); +} + +#[test] +fn test_into_inner() { + let m = ShardedLock::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = ShardedLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(ShardedLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison ShardedLock"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned ShardedLock is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = ShardedLock::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(ShardedLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison ShardedLock"); + }).join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned ShardedLock is Ok: {:?}", x), + } +} diff --git a/crossbeam-utils/tests/thread.rs b/crossbeam-utils/tests/thread.rs new file mode 100644 index 000000000..ac7c2b2a7 --- /dev/null +++ b/crossbeam-utils/tests/thread.rs @@ -0,0 +1,175 @@ +extern crate crossbeam_utils; + +use std::any::Any; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::sleep; +use std::time::Duration; + +use crossbeam_utils::thread; + +const THREADS: usize = 10; +const SMALL_STACK_SIZE: usize = 20; + +#[test] +fn join() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + let handle = scope.spawn(|_| { + counter.store(1, Ordering::Relaxed); + }); + assert!(handle.join().is_ok()); + + let panic_handle = scope.spawn(|_| { + panic!("\"My honey is running out!\", said Pooh."); + }); + assert!(panic_handle.join().is_err()); + }).unwrap(); + + // There should be sufficient synchronization. + assert_eq!(1, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }).unwrap(); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter_builder() { + let counter = AtomicUsize::new(0); + thread::scope(|scope| { + for i in 0..THREADS { + scope + .builder() + .name(format!("child-{}", i)) + .stack_size(SMALL_STACK_SIZE) + .spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }).unwrap(); + } + }).unwrap(); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); +} + +#[test] +fn counter_panic() { + let counter = AtomicUsize::new(0); + let result = thread::scope(|scope| { + scope.spawn(|_| { + panic!("\"My honey is running out!\", said Pooh."); + }); + sleep(Duration::from_millis(100)); + + for _ in 0..THREADS { + scope.spawn(|_| { + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + + assert_eq!(THREADS, counter.load(Ordering::Relaxed)); + assert!(result.is_err()); +} + +#[test] +fn panic_twice() { + let result = thread::scope(|scope| { + scope.spawn(|_| { + sleep(Duration::from_millis(500)); + panic!("thread #1"); + }); + scope.spawn(|_| { + panic!("thread #2"); + }); + }); + + let err = result.unwrap_err(); + let vec = err + .downcast_ref::>>() + .unwrap(); + assert_eq!(2, vec.len()); + + let first = vec[0].downcast_ref::<&str>().unwrap(); + let second = vec[1].downcast_ref::<&str>().unwrap(); + assert_eq!("thread #1", *first); + assert_eq!("thread #2", *second) +} + +#[test] +fn panic_many() { + let result = thread::scope(|scope| { + scope.spawn(|_| panic!("deliberate panic #1")); + scope.spawn(|_| panic!("deliberate panic #2")); + scope.spawn(|_| panic!("deliberate panic #3")); + }); + + let err = result.unwrap_err(); + let vec = err + .downcast_ref::>>() + .unwrap(); + assert_eq!(3, vec.len()); + + for panic in vec.iter() { + let panic = panic.downcast_ref::<&str>().unwrap(); + assert!( + *panic == "deliberate panic #1" + || *panic == "deliberate panic #2" + || *panic == "deliberate panic #3" + ); + } +} + +#[test] +fn nesting() { + let var = "foo".to_string(); + + struct Wrapper<'a> { + var: &'a String, + } + + impl<'a> Wrapper<'a> { + fn recurse(&'a self, scope: &thread::Scope<'a>, depth: usize) { + assert_eq!(self.var, "foo"); + + if depth > 0 { + scope.spawn(move |scope| { + self.recurse(scope, depth - 1); + }); + } + } + } + + let wrapper = Wrapper { var: &var }; + + thread::scope(|scope| { + scope.spawn(|scope| { + scope.spawn(|scope| { + wrapper.recurse(scope, 5); + }); + }); + }).unwrap(); +} + +#[test] +fn join_nested() { + thread::scope(|scope| { + scope.spawn(|scope| { + let handle = scope.spawn(|_| 7); + + sleep(Duration::from_millis(200)); + handle.join().unwrap(); + }); + + sleep(Duration::from_millis(100)); + }).unwrap(); +} diff --git a/crossbeam-utils/tests/wait_group.rs b/crossbeam-utils/tests/wait_group.rs new file mode 100644 index 000000000..1aa91997a --- /dev/null +++ b/crossbeam-utils/tests/wait_group.rs @@ -0,0 +1,66 @@ +extern crate crossbeam_utils; + +use std::sync::mpsc; +use std::thread; +use std::time::Duration; + +use crossbeam_utils::sync::WaitGroup; + +const THREADS: usize = 10; + +#[test] +fn wait() { + let wg = WaitGroup::new(); + let (tx, rx) = mpsc::channel(); + + for _ in 0..THREADS { + let wg = wg.clone(); + let tx = tx.clone(); + + thread::spawn(move || { + wg.wait(); + tx.send(()).unwrap(); + }); + } + + thread::sleep(Duration::from_millis(100)); + + // At this point, all spawned threads should be blocked, so we shouldn't get anything from the + // channel. + assert!(rx.try_recv().is_err()); + + wg.wait(); + + // Now, the wait group is cleared and we should receive messages. + for _ in 0..THREADS { + rx.recv().unwrap(); + } +} + +#[test] +fn wait_and_drop() { + let wg = WaitGroup::new(); + let (tx, rx) = mpsc::channel(); + + for _ in 0..THREADS { + let wg = wg.clone(); + let tx = tx.clone(); + + thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + tx.send(()).unwrap(); + drop(wg); + }); + } + + // At this point, all spawned threads should be sleeping, so we shouldn't get anything from the + // channel. + assert!(rx.try_recv().is_err()); + + wg.wait(); + + // Now, the wait group is cleared and we should receive messages. + for _ in 0..THREADS { + rx.try_recv().unwrap(); + } +} diff --git a/crypto-hash/.cargo-checksum.json b/crypto-hash/.cargo-checksum.json new file mode 100644 index 000000000..a692916f6 --- /dev/null +++ b/crypto-hash/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"20ff87d28defc77c9980a5b81cae1a33c791dd0ead8af0cee0833eb98c8305b9"} \ No newline at end of file diff --git a/crypto-hash/CONTRIBUTING.md b/crypto-hash/CONTRIBUTING.md new file mode 100644 index 000000000..1b33a9ec1 --- /dev/null +++ b/crypto-hash/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing to `crypto-hash` + +`crypto-hash` is a part of the Rust ecosystem. As such, all contributions to this project follow the +[Rust language's code of conduct](https://www.rust-lang.org/conduct.html) where appropriate. + +This project is hosted at [GitHub](https://github.com/malept/crypto-hash). Both pull requests and +issues of many different kinds are accepted. + +## Filing Issues + +Issues include bugs, questions, feedback, and feature requests. Before you file a new issue, please +make sure that your issue has not already been filed by someone else. + +### Filing Bugs + +When filing a bug, please include the following information: + +* Operating system and version. If on Linux, please also include the distribution name. +* System architecture. Examples include: x86-64, x86, and ARMv7. +* Rust version that compiled `crypto-hash`. +* The version (and/or git revision) of `crypto-hash`. +* A detailed list of steps to reproduce the bug. A minimal testcase would be very helpful, + if possible. +* If there any any error messages in the console, copying them in the bug summary will be + very helpful. + +## Adding a new implementation + +If you are requesting or adding a new library source for hash algorithms, please make sure that it +supports all of the existing algorithms. For example, while the creator of this project supports the +efforts of the team writing LibreSSL, it does not support the MD5 algorithm. + +## Adding a new hash algorithm + +If you are requesting or adding a wrapper for a new hash algorithm, please make sure that it is +available in all of the supported implementations listed in the README. + +## Filing Pull Requests + +Here are some things to keep in mind as you file a pull request to fix a bug, add a new feature, +etc.: + +* Travis CI (for Linux and OS X) and AppVeyor (for Windows) are used to make sure that the project + builds as expected on the supported platforms, using the current stable and beta versions of Rust. + Make sure the testsuite passes locally by running `cargo test`. +* Unless it's impractical, please write tests for your changes. This will help spot regressions + much easier. +* If your PR changes the behavior of an existing feature, or adds a new feature, please add/edit + the `rustdoc` inline documentation. +* Please ensure that your changes follow the [rustfmt](https://github.com/rust-lang-nursery/rustfmt) + coding standard, and do not produce any warnings when running the + [clippy](https://github.com/Manishearth/rust-clippy) linter. +* If you are contributing a nontrivial change, please add an entry to `NEWS.md`. The format is + similar to the one described at [Keep a Changelog](http://keepachangelog.com/). +* Please make sure your commits are rebased onto the latest commit in the master branch, and that + you limit/squash the number of commits created to a "feature"-level. For instance: + +bad: + +``` +commit 1: add foo algorithm +commit 2: run rustfmt +commit 3: add test +commit 4: add docs +commit 5: add bar +commit 6: add test + docs +``` + +good: + +``` +commit 1: add foo algorithm +commit 2: add bar +``` + +If you are continuing the work of another person's PR and need to rebase/squash, please retain the +attribution of the original author(s) and continue the work in subsequent commits. diff --git a/crypto-hash/Cargo.toml b/crypto-hash/Cargo.toml new file mode 100644 index 000000000..ac9044d74 --- /dev/null +++ b/crypto-hash/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crypto-hash" +version = "0.3.3" +authors = ["Mark Lee"] +exclude = [".*.yml", "ci/*"] +description = "A wrapper for OS-level cryptographic hash functions" +documentation = "https://docs.rs/crypto-hash" +readme = "README.md" +keywords = ["crypto", "hash", "digest"] +license = "MIT" +repository = "https://github.com/malept/crypto-hash" +[dependencies.hex] +version = "0.3" +[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.commoncrypto] +version = "0.2" +[target."cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"ios\")))".dependencies.openssl] +version = "0.10" +[target."cfg(target_os = \"windows\")".dependencies.winapi] +version = "0.3" +features = ["minwindef", "wincrypt"] +[badges.appveyor] +repository = "malept/crypto-hash" + +[badges.travis-ci] +repository = "malept/crypto-hash" diff --git a/crypto-hash/LICENSE b/crypto-hash/LICENSE new file mode 100644 index 000000000..e3eb5500c --- /dev/null +++ b/crypto-hash/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015, 2016 Mark Lee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/crypto-hash/Makefile b/crypto-hash/Makefile new file mode 100644 index 000000000..ca429ef90 --- /dev/null +++ b/crypto-hash/Makefile @@ -0,0 +1,29 @@ +CARGO ?= cargo +CARGO_BUILD_TEST = $(CARGO) test --no-run +KCOV ?= kcov +TEST_APP = debug/crypto_hash-*.exe +WIN_TARGET = x86_64-pc-windows-gnu + +build-test: + $(CARGO_BUILD_TEST) + +check-i686: + PKG_CONFIG_LIBDIR=/usr/lib/i386-linux-gnu/pkgconfig \ + PKG_CONFIG_ALLOW_CROSS=1 \ + $(CARGO) test --target i686-unknown-linux-gnu --verbose + +check-wine64: + $(CARGO_BUILD_TEST) --target $(WIN_TARGET) + WINEPREFIX=$(HOME)/.local/share/wineprefixes/wine64 wine64 target/$(WIN_TARGET)/$(TEST_APP) + +cov: build-test + $(KCOV) --exclude-pattern=/.multirust,test.rs target/cov target/$(TEST_APP) + +debug: build-test + rust-gdb target/$(TEST_APP) + +fmt: + $(CARGO) fmt + +lint: + $(CARGO) +nightly clippy -- --allow clippy::pedantic diff --git a/crypto-hash/NEWS.md b/crypto-hash/NEWS.md new file mode 100644 index 000000000..c6ed34eef --- /dev/null +++ b/crypto-hash/NEWS.md @@ -0,0 +1,80 @@ +# `crypto-hash`: Changes by Version + +## [Unreleased](https://github.com/malept/crypto-hash/compare/v0.3.3...master) + +## [0.3.3] - 2018-12-20 + +[0.3.3]: https://github.com/malept/crypto-hash/compare/v0.3.2...v0.3.3 + +### Changed + +* Revert API change (#6) + +## [0.3.2] - 2018-12-20 + +[0.3.2]: https://github.com/malept/crypto-hash/compare/v0.3.1...v0.3.2 + +**Note: This release was yanked from Cargo due to #6.** + +### Added + +* iOS support + +## [0.3.1] - 2018-02-14 + +[0.3.1]: https://github.com/malept/crypto-hash/compare/v0.3.0...v0.3.1 + +### Changed + +* Upgrade to `openssl` 0.10.x (#1) +* Upgrade to `winapi` 0.3.x + +## [0.3.0] - 2017-06-18 + +[0.3.0]: https://github.com/malept/crypto-hash/compare/v0.2.1...v0.3.0 + +### Changed + +* Upgrade to `commoncrypto` 0.2.x +* Function signatures for `digest` and `hex_digest` changed to use `&[u8]`, per Clippy + +## [0.2.1] - 2016-12-12 + +[0.2.1]: https://github.com/malept/crypto-hash/compare/v0.2.0...v0.2.1 + +### Changed + +* Move CommonCrypto implementation to its own crate + +## [0.2.0] - 2016-11-06 + +[0.2.0]: https://github.com/malept/crypto-hash/compare/v0.1.0...v0.2.0 + +### Added + +* SHA-1 algorithm + +### Changed + +* Upgrade rust-openssl to 0.9 + +## [0.1.0] - 2016-06-26 + +[0.1.0]: https://github.com/malept/crypto-hash/releases/tag/v0.1.0 + +This release signifies the minimum amount of algorithms and implementations necessary for +[HTTP digest authentication](https://tools.ietf.org/html/rfc7616). + +### Added + +Algorithms: + +* MD5 +* SHA256 +* SHA512 + +Implementations: + +* CommonCrypto (OS X) +* CryptoAPI (Windows) +* OpenSSL (Linux/BSD/etc.) diff --git a/crypto-hash/README.md b/crypto-hash/README.md new file mode 100644 index 000000000..de70bb5be --- /dev/null +++ b/crypto-hash/README.md @@ -0,0 +1,54 @@ +# `crypto-hash` + +[![Linux/OS X Status](https://travis-ci.org/malept/crypto-hash.svg?branch=master)](https://travis-ci.org/malept/crypto-hash) +[![Windows status](https://ci.appveyor.com/api/projects/status/xwc9nb4633b5n67r/branch/master?svg=true)](https://ci.appveyor.com/project/malept/crypto-hash) +[![Crates.io](https://img.shields.io/crates/v/crypto-hash.svg?maxAge=2592000)](https://crates.io/crates/crypto-hash) + +`crypto-hash` is a Rust wrapper around OS-level implementations of cryptographic hash functions. + +The purpose of this crate is to provide access to hash algorithms with as few dependencies as +possible. This means that when possible, the library uses the hashing functions that are provided by +the given operating system's bundled cryptographic libraries. + +## Supported Implementations + +By operating system: + +* Windows: CryptoAPI +* OS X: [CommonCrypto](https://crates.io/crates/commoncrypto) +* Linux/BSD/etc.: [OpenSSL](https://crates.io/crates/openssl) + +## Supported Algorithms + +* MD5 +* SHA1 +* SHA256 +* SHA512 + +## Usage + +Add `crypto-hash` to your project's `Cargo.toml`. For more details, consult the +[Cargo guide](http://doc.crates.io/guide.html#adding-dependencies). + +Example: + +```rust +use crypto_hash::{Algorithm, hex_digest}; + +let digest = hex_digest(Algorithm::SHA256, b"crypto-hash"); +``` + +For more examples, consult the [documentation](https://malept.github.io/crypto-hash/). + +## [Release Notes](https://github.com/malept/crypto-hash/blob/master/NEWS.md) + +## [Contributing](https://github.com/malept/crypto-hash/blob/master/CONTRIBUTING.md) + +## Acknowledgements + +This crate was inspired by [rust-native-tls](https://github.com/sfackler/rust-native-tls) and +[crypto-bench](https://github.com/briansmith/crypto-bench). + +## Legal + +`crypto-hash` is copyrighted under the terms of the MIT license. See LICENSE for details. diff --git a/crypto-hash/src/imp/commoncrypto.rs b/crypto-hash/src/imp/commoncrypto.rs new file mode 100644 index 000000000..99f4766d3 --- /dev/null +++ b/crypto-hash/src/imp/commoncrypto.rs @@ -0,0 +1,81 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash generator dependent upon OSX's `CommonCrypto`. + +use super::Algorithm; +use commoncrypto::hash; +use std::io; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +#[derive(Debug)] +pub struct Hasher(hash::Hasher); + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let cc_algorithm = match algorithm { + Algorithm::MD5 => hash::CCDigestAlgorithm::kCCDigestMD5, + Algorithm::SHA1 => hash::CCDigestAlgorithm::kCCDigestSHA1, + Algorithm::SHA256 => hash::CCDigestAlgorithm::kCCDigestSHA256, + Algorithm::SHA512 => hash::CCDigestAlgorithm::kCCDigestSHA512, + }; + + Hasher(hash::Hasher::new(cc_algorithm)) + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + let Hasher(ref mut hasher) = *self; + match hasher.finish() { + Ok(digest) => digest, + Err(error) => panic!("CommonCrypto error: {}", error), + } + } +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + let Hasher(ref mut hasher) = *self; + hasher.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + let Hasher(ref mut hasher) = *self; + hasher.flush() + } +} diff --git a/crypto-hash/src/imp/cryptoapi.rs b/crypto-hash/src/imp/cryptoapi.rs new file mode 100644 index 000000000..160b38e84 --- /dev/null +++ b/crypto-hash/src/imp/cryptoapi.rs @@ -0,0 +1,169 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash generator dependent upon Windows's `CryptoAPI`. +//! +//! Originally based on: +//! https://github.com/rust-lang/cargo/blob/0.10.0/src/cargo/util/sha256.rs +//! which is copyright (c) 2014 The Rust Project Developers under the MIT license. + +use super::Algorithm; +use std::io; +use std::ptr; +use winapi::shared::minwindef::DWORD; +use winapi::um::wincrypt::{ + CryptAcquireContextW, CryptCreateHash, CryptDestroyHash, CryptGetHashParam, CryptHashData, + CryptReleaseContext, ALG_ID, CALG_MD5, CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CRYPT_SILENT, + CRYPT_VERIFYCONTEXT, HCRYPTHASH, HCRYPTPROV, HP_HASHVAL, PROV_RSA_AES, +}; + +macro_rules! call { + ($e:expr) => {{ + if $e == 0 { + panic!("failed {}: {}", stringify!($e), io::Error::last_os_error()) + } + }}; +} + +macro_rules! finish_algorithm { + ($func_name: ident, $size: ident) => { + fn $func_name(&mut self) -> Vec { + let mut len = $size as u32; + let mut hash = [0u8; $size]; + call!(unsafe { + CryptGetHashParam(self.hcrypthash, HP_HASHVAL, hash.as_mut_ptr(), &mut len, 0) + }); + assert_eq!(len as usize, hash.len()); + hash.to_vec() + } + } +} + +const MD5_LENGTH: usize = 16; +const SHA1_LENGTH: usize = 20; +const SHA256_LENGTH: usize = 32; +const SHA512_LENGTH: usize = 64; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub struct Hasher { + alg_id: ALG_ID, + hcryptprov: HCRYPTPROV, + hcrypthash: HCRYPTHASH, +} + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let mut hcp = 0; + call!(unsafe { + CryptAcquireContextW( + &mut hcp, + ptr::null(), + ptr::null(), + PROV_RSA_AES, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT, + ) + }); + + let alg_id = match algorithm { + Algorithm::MD5 => CALG_MD5, + Algorithm::SHA1 => CALG_SHA1, + Algorithm::SHA256 => CALG_SHA_256, + Algorithm::SHA512 => CALG_SHA_512, + }; + + let mut hasher = Hasher { + alg_id, + hcryptprov: hcp, + hcrypthash: 0, + }; + + call!(unsafe { + CryptCreateHash( + hasher.hcryptprov, + hasher.alg_id, + 0, + 0, + &mut hasher.hcrypthash, + ) + }); + hasher + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + match self.alg_id { + CALG_MD5 => self.finish_md5(), + CALG_SHA1 => self.finish_sha1(), + CALG_SHA_256 => self.finish_sha256(), + CALG_SHA_512 => self.finish_sha512(), + _ => panic!("Unknown algorithm {}", self.alg_id), + } + } + + finish_algorithm!(finish_md5, MD5_LENGTH); + finish_algorithm!(finish_sha1, SHA1_LENGTH); + finish_algorithm!(finish_sha256, SHA256_LENGTH); + finish_algorithm!(finish_sha512, SHA512_LENGTH); +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + call!(unsafe { + CryptHashData( + self.hcrypthash, + buf.as_ptr() as *mut _, + buf.len() as DWORD, + 0, + ) + }); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Drop for Hasher { + fn drop(&mut self) { + if self.hcrypthash != 0 { + call!(unsafe { CryptDestroyHash(self.hcrypthash) }); + } + call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) }); + } +} diff --git a/crypto-hash/src/imp/openssl.rs b/crypto-hash/src/imp/openssl.rs new file mode 100644 index 000000000..d58726be6 --- /dev/null +++ b/crypto-hash/src/imp/openssl.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2015, 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash digest generator dependent upon `OpenSSL`. + +#![warn(missing_docs)] + +use super::Algorithm; +use openssl::hash; +use std::io; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub struct Hasher(hash::Hasher); + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let hash_type = match algorithm { + Algorithm::MD5 => hash::MessageDigest::md5(), + Algorithm::SHA1 => hash::MessageDigest::sha1(), + Algorithm::SHA256 => hash::MessageDigest::sha256(), + Algorithm::SHA512 => hash::MessageDigest::sha512(), + }; + + match hash::Hasher::new(hash_type) { + Ok(hasher) => Hasher(hasher), + Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), + } + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + let Hasher(ref mut hasher) = *self; + match hasher.finish() { + Ok(digest) => digest.to_vec(), + Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), + } + } +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + let Hasher(ref mut hasher) = *self; + hasher.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + let Hasher(ref mut hasher) = *self; + hasher.flush() + } +} diff --git a/crypto-hash/src/lib.rs b/crypto-hash/src/lib.rs new file mode 100644 index 000000000..6828a1d80 --- /dev/null +++ b/crypto-hash/src/lib.rs @@ -0,0 +1,119 @@ +// Copyright (c) 2015, 2016, 2017 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A set of [cryptographic hash +//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating +//! system, when available. +//! +//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as +//! possible. This means that when possible, the library uses the hashing functions that are +//! provided by the given operating system's bundled cryptographic libraries. +//! +//! # Supported Implementations +//! +//! By operating system: +//! +//! * Windows: `CryptoAPI` +//! * Mac OS X: `CommonCrypto` +//! * Linux/BSD/etc.: `OpenSSL` +//! +//! # Supported Algorithms +//! +//! * MD5 +//! * SHA1 +//! * SHA256 +//! * SHA512 + +#![warn(missing_docs)] + +#[cfg(any(target_os = "macos", target_os = "ios"))] +extern crate commoncrypto; +extern crate hex; +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] +extern crate openssl; +#[cfg(target_os = "windows")] +extern crate winapi; + +use std::io::Write; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[path = "imp/commoncrypto.rs"] +mod imp; +#[cfg(target_os = "windows")] +#[path = "imp/cryptoapi.rs"] +mod imp; +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] +#[path = "imp/openssl.rs"] +mod imp; + +mod test; + +pub use imp::Hasher; + +/// Available cryptographic hash functions. +#[derive(Clone, Debug)] +pub enum Algorithm { + /// Popular message digest algorithm, only available for backwards compatibility purposes. + MD5, + /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes. + SHA1, + /// SHA-2 family algorithm (256 bits). + SHA256, + /// SHA-2 family algorithm (512 bits). + SHA512, +} + +/// Helper function for `Hasher` which generates a cryptographic digest from the given +/// data and algorithm. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, digest}; +/// +/// let data = b"crypto-hash"; +/// let result = digest(Algorithm::SHA256, data); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec { + let mut hasher = imp::Hasher::new(algorithm); + hasher.write_all(data).expect("Could not write hash data"); + hasher.finish() +} + +/// Helper function for `Hasher` which generates a cryptographic digest serialized in +/// hexadecimal from the given data and algorithm. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, hex_digest}; +/// +/// let data = b"crypto-hash"; +/// let result = hex_digest(Algorithm::SHA256, data); +/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27"; +/// assert_eq!(expected, result) +/// ``` +pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String { + hex::encode(digest(algorithm, data)) +} diff --git a/crypto-hash/src/test.rs b/crypto-hash/src/test.rs new file mode 100644 index 000000000..91ededb54 --- /dev/null +++ b/crypto-hash/src/test.rs @@ -0,0 +1,83 @@ +// Copyright (c) 2016, 2017 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#![cfg(test)] + +use super::{hex_digest, Algorithm, Hasher}; +use hex; +use std::io::Write; + +// From Wikipedia +const MD5_EMPTY_STRING: &'static str = "d41d8cd98f00b204e9800998ecf8427e"; +const SHA1_EMPTY_STRING: &'static str = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; +const SHA256_EMPTY_STRING: &'static str = concat!( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649", + "b934ca495991b7852b855" +); +const SHA512_EMPTY_STRING: &'static str = concat!( + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5", + "715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318", + "d2877eec2f63b931bd47417a81a538327af927da3e" +); +const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog"; +const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6"; + +#[test] +fn md5_empty_string() { + assert_hex_hashed_empty_string(Algorithm::MD5, MD5_EMPTY_STRING) +} + +#[test] +fn sha1_empty_string() { + assert_hex_hashed_empty_string(Algorithm::SHA1, SHA1_EMPTY_STRING) +} + +#[test] +fn sha256_empty_string() { + // From Wikipedia + assert_hex_hashed_empty_string(Algorithm::SHA256, SHA256_EMPTY_STRING) +} + +#[test] +fn sha512_empty_string() { + assert_hex_hashed_empty_string(Algorithm::SHA512, SHA512_EMPTY_STRING) +} + +#[test] +fn hasher_sans_write() { + let mut hasher = Hasher::new(Algorithm::MD5); + let actual = hex::encode(hasher.finish()); + assert_eq!(MD5_EMPTY_STRING, actual) +} + +#[test] +fn hasher_with_write() { + let mut hasher = Hasher::new(Algorithm::MD5); + hasher + .write_all(TO_HASH.as_bytes()) + .expect("Could not write to hasher"); + let actual = hex::encode(hasher.finish()); + assert_eq!(TO_HASH_MD5, actual) +} + +fn assert_hex_hashed_empty_string(algorithm: Algorithm, expected: &str) { + let vec = vec![]; + assert_eq!(expected, hex_digest(algorithm, vec.as_slice()).as_str()) +} diff --git a/curl-sys/.cargo-checksum.json b/curl-sys/.cargo-checksum.json new file mode 100644 index 000000000..4b7ca1c6a --- /dev/null +++ b/curl-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42"} \ No newline at end of file diff --git a/curl-sys/.pc/.quilt_patches b/curl-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/curl-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/curl-sys/.pc/.quilt_series b/curl-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/curl-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/curl-sys/.pc/.version b/curl-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/curl-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/curl-sys/.pc/applied-patches b/curl-sys/.pc/applied-patches new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/curl-sys/.pc/applied-patches @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/curl-sys/.pc/disable-vendor.patch/.timestamp b/curl-sys/.pc/disable-vendor.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/curl-sys/.pc/disable-vendor.patch/Cargo.toml b/curl-sys/.pc/disable-vendor.patch/Cargo.toml new file mode 100644 index 000000000..510c70c8d --- /dev/null +++ b/curl-sys/.pc/disable-vendor.patch/Cargo.toml @@ -0,0 +1,63 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl-sys" +version = "0.4.18" +authors = ["Alex Crichton "] +build = "build.rs" +links = "curl" +description = "Native bindings to the libcurl library" +documentation = "https://docs.rs/curl-sys" +categories = ["external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" + +[lib] +name = "curl_sys" +path = "lib.rs" +[dependencies.libc] +version = "0.2.2" + +[dependencies.libnghttp2-sys] +version = "0.1" +optional = true + +[dependencies.libz-sys] +version = "1.0.18" +[build-dependencies.cc] +version = "1.0" + +[build-dependencies.pkg-config] +version = "0.3.3" + +[features] +default = ["ssl"] +force-system-lib-on-osx = [] +http2 = ["libnghttp2-sys"] +spnego = [] +ssl = ["openssl-sys"] +static-curl = [] +static-ssl = ["openssl-sys/vendored"] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9" +optional = true +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["winsock2", "ws2def"] +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl-sys/Cargo.toml b/curl-sys/Cargo.toml new file mode 100644 index 000000000..4e5494e64 --- /dev/null +++ b/curl-sys/Cargo.toml @@ -0,0 +1,63 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl-sys" +version = "0.4.18" +authors = ["Alex Crichton "] +build = "build.rs" +links = "curl" +description = "Native bindings to the libcurl library" +documentation = "https://docs.rs/curl-sys" +categories = ["external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" + +[lib] +name = "curl_sys" +path = "lib.rs" +[dependencies.libc] +version = "0.2.2" + +[dependencies.libnghttp2-sys] +version = "0.1" +optional = true + +[dependencies.libz-sys] +version = "1.0.18" +[build-dependencies.cc] +version = "1.0" + +[build-dependencies.pkg-config] +version = "0.3.3" + +[features] +default = ["ssl"] +force-system-lib-on-osx = [] +http2 = ["libnghttp2-sys"] +spnego = [] +ssl = ["openssl-sys"] +static-curl = [] +static-ssl = ["openssl-sys"] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9" +optional = true +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["winsock2", "ws2def"] +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl-sys/LICENSE b/curl-sys/LICENSE new file mode 100644 index 000000000..5f5e4b09d --- /dev/null +++ b/curl-sys/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Carl Lerche + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/curl-sys/build.rs b/curl-sys/build.rs new file mode 100644 index 000000000..5f3cd06c8 --- /dev/null +++ b/curl-sys/build.rs @@ -0,0 +1,456 @@ +extern crate cc; +extern crate pkg_config; +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn main() { + let target = env::var("TARGET").unwrap(); + let windows = target.contains("windows"); + + // This feature trumps all others, and is largely set by rustbuild to force + // usage of the system library to ensure that we're always building an + // ABI-compatible Cargo. + if cfg!(feature = "force-system-lib-on-osx") && target.contains("apple") { + return println!("cargo:rustc-flags=-l curl"); + } + + // If the static-curl feature is disabled, probe for a system-wide libcurl. + if !cfg!(feature = "static-curl") { + // OSX and Haiku ships libcurl by default, so we just use that version + // so long as it has the right features enabled. + if target.contains("apple") || target.contains("haiku") { + if !cfg!(feature = "http2") || curl_config_reports_http2() { + return println!("cargo:rustc-flags=-l curl"); + } + } + + // Next, fall back and try to use pkg-config if its available. + if windows { + if try_vcpkg() { + return; + } + } else { + if try_pkg_config() { + return; + } + } + } + + if !Path::new("curl/.git").exists() { + let _ = Command::new("git") + .args(&["submodule", "update", "--init"]) + .status(); + } + + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let include = dst.join("include"); + let build = dst.join("build"); + println!("cargo:root={}", dst.display()); + println!("cargo:include={}", include.display()); + println!("cargo:static=1"); + fs::create_dir_all(include.join("curl")).unwrap(); + fs::copy("curl/include/curl/curl.h", include.join("curl/curl.h")).unwrap(); + fs::copy( + "curl/include/curl/curlver.h", + include.join("curl/curlver.h"), + ) + .unwrap(); + fs::copy("curl/include/curl/easy.h", include.join("curl/easy.h")).unwrap(); + fs::copy( + "curl/include/curl/mprintf.h", + include.join("curl/mprintf.h"), + ) + .unwrap(); + fs::copy("curl/include/curl/multi.h", include.join("curl/multi.h")).unwrap(); + fs::copy( + "curl/include/curl/stdcheaders.h", + include.join("curl/stdcheaders.h"), + ) + .unwrap(); + fs::copy("curl/include/curl/system.h", include.join("curl/system.h")).unwrap(); + fs::copy("curl/include/curl/urlapi.h", include.join("curl/urlapi.h")).unwrap(); + fs::copy( + "curl/include/curl/typecheck-gcc.h", + include.join("curl/typecheck-gcc.h"), + ) + .unwrap(); + + let pkgconfig = dst.join("lib/pkgconfig"); + fs::create_dir_all(&pkgconfig).unwrap(); + let contents = fs::read_to_string("curl/libcurl.pc.in").unwrap(); + fs::write( + pkgconfig.join("libcurl.pc"), + contents + .replace("@prefix@", dst.to_str().unwrap()) + .replace("@exec_prefix@", "") + .replace("@libdir@", dst.join("lib").to_str().unwrap()) + .replace("@includedir@", include.to_str().unwrap()) + .replace("@CPPFLAG_CURL_STATICLIB@", "-DCURL_STATICLIB") + .replace("@LIBCURL_LIBS@", "") + .replace("@SUPPORT_FEATURES@", "") + .replace("@SUPPORT_PROTOCOLS@", "") + .replace("@CURLVERSION@", "7.61.1"), + ) + .unwrap(); + + let mut cfg = cc::Build::new(); + cfg.out_dir(&build) + .include("curl/lib") + .include("curl/include") + .define("BUILDING_LIBCURL", None) + .define("CURL_DISABLE_CRYPTO_AUTH", None) + .define("CURL_DISABLE_DICT", None) + .define("CURL_DISABLE_FTP", None) + .define("CURL_DISABLE_GOPHER", None) + .define("CURL_DISABLE_IMAP", None) + .define("CURL_DISABLE_LDAP", None) + .define("CURL_DISABLE_LDAPS", None) + .define("CURL_DISABLE_NTLM", None) + .define("CURL_DISABLE_POP3", None) + .define("CURL_DISABLE_RTSP", None) + .define("CURL_DISABLE_SMB", None) + .define("CURL_DISABLE_SMTP", None) + .define("CURL_DISABLE_TELNET", None) + .define("CURL_DISABLE_TFTP", None) + .define("CURL_STATICLIB", None) + .define("ENABLE_IPV6", None) + .define("HAVE_ASSERT_H", None) + .define("OS", "\"unknown\"") // TODO + .define("HAVE_ZLIB_H", None) + .define("HAVE_LIBZ", None) + .file("curl/lib/asyn-thread.c") + .file("curl/lib/base64.c") + .file("curl/lib/conncache.c") + .file("curl/lib/connect.c") + .file("curl/lib/content_encoding.c") + .file("curl/lib/cookie.c") + .file("curl/lib/curl_addrinfo.c") + .file("curl/lib/curl_ctype.c") + .file("curl/lib/curl_memrchr.c") + .file("curl/lib/curl_range.c") + .file("curl/lib/curl_threads.c") + .file("curl/lib/dotdot.c") + .file("curl/lib/doh.c") + .file("curl/lib/easy.c") + .file("curl/lib/escape.c") + .file("curl/lib/file.c") + .file("curl/lib/fileinfo.c") + .file("curl/lib/formdata.c") + .file("curl/lib/getenv.c") + .file("curl/lib/getinfo.c") + .file("curl/lib/hash.c") + .file("curl/lib/hostasyn.c") + .file("curl/lib/hostcheck.c") + .file("curl/lib/hostip.c") + .file("curl/lib/hostip6.c") + .file("curl/lib/http.c") + .file("curl/lib/http2.c") + .file("curl/lib/http_chunks.c") + .file("curl/lib/http_proxy.c") + .file("curl/lib/if2ip.c") + .file("curl/lib/inet_ntop.c") + .file("curl/lib/inet_pton.c") + .file("curl/lib/llist.c") + .file("curl/lib/mime.c") + .file("curl/lib/mprintf.c") + .file("curl/lib/multi.c") + .file("curl/lib/netrc.c") + .file("curl/lib/nonblock.c") + .file("curl/lib/parsedate.c") + .file("curl/lib/pipeline.c") + .file("curl/lib/progress.c") + .file("curl/lib/rand.c") + .file("curl/lib/select.c") + .file("curl/lib/sendf.c") + .file("curl/lib/setopt.c") + .file("curl/lib/share.c") + .file("curl/lib/slist.c") + .file("curl/lib/socks.c") + .file("curl/lib/speedcheck.c") + .file("curl/lib/splay.c") + .file("curl/lib/strcase.c") + .file("curl/lib/strdup.c") + .file("curl/lib/strerror.c") + .file("curl/lib/strtok.c") + .file("curl/lib/strtoofft.c") + .file("curl/lib/timeval.c") + .file("curl/lib/transfer.c") + .file("curl/lib/url.c") + .file("curl/lib/urlapi.c") + .file("curl/lib/version.c") + .file("curl/lib/vtls/vtls.c") + .file("curl/lib/warnless.c") + .file("curl/lib/wildcard.c") + .define("HAVE_GETADDRINFO", None) + .warnings(false); + + if cfg!(feature = "http2") { + cfg.define("USE_NGHTTP2", None) + .define("NGHTTP2_STATICLIB", None); + + println!("cargo:rustc-cfg=link_libnghttp2"); + if let Some(path) = env::var_os("DEP_NGHTTP2_ROOT") { + let path = PathBuf::from(path); + cfg.include(path.join("include")); + } + } + + println!("cargo:rustc-cfg=link_libz"); + if let Some(path) = env::var_os("DEP_Z_INCLUDE") { + cfg.include(path); + } + + if cfg!(feature = "spnego") { + cfg.define("USE_SPNEGO", None) + .file("curl/lib/http_negotiate.c") + .file("curl/lib/vauth/vauth.c"); + } + + if windows { + cfg.define("USE_THREADS_WIN32", None) + .define("HAVE_IOCTLSOCKET_FIONBIO", None) + .define("USE_WINSOCK", None) + .file("curl/lib/system_win32.c"); + + if cfg!(feature = "ssl") { + cfg.define("USE_WINDOWS_SSPI", None) + .define("USE_SCHANNEL", None) + .file("curl/lib/x509asn1.c") + .file("curl/lib/curl_sspi.c") + .file("curl/lib/socks_sspi.c") + .file("curl/lib/vtls/schannel.c") + .file("curl/lib/vtls/schannel_verify.c"); + } + + if cfg!(feature = "spnego") { + cfg.file("curl/lib/vauth/spnego_sspi.c"); + } + } else { + cfg.define("RECV_TYPE_ARG1", "int") + .define("HAVE_PTHREAD_H", None) + .define("HAVE_ARPA_INET_H", None) + .define("HAVE_ERRNO_H", None) + .define("HAVE_FCNTL_H", None) + .define("HAVE_NETDB_H", None) + .define("HAVE_NETINET_IN_H", None) + .define("HAVE_POLL_FINE", None) + .define("HAVE_POLL_H", None) + .define("HAVE_FCNTL_O_NONBLOCK", None) + .define("HAVE_SYS_SELECT_H", None) + .define("HAVE_SYS_STAT_H", None) + .define("HAVE_UNISTD_H", None) + .define("HAVE_RECV", None) + .define("HAVE_SELECT", None) + .define("HAVE_SEND", None) + .define("HAVE_SOCKET", None) + .define("HAVE_STERRROR_R", None) + .define("HAVE_STRUCT_TIMEVAL", None) + .define("USE_THREADS_POSIX", None) + .define("RECV_TYPE_ARG2", "void*") + .define("RECV_TYPE_ARG3", "size_t") + .define("RECV_TYPE_ARG4", "int") + .define("RECV_TYPE_RETV", "ssize_t") + .define("SEND_QUAL_ARG2", "const") + .define("SEND_TYPE_ARG1", "int") + .define("SEND_TYPE_ARG2", "void*") + .define("SEND_TYPE_ARG3", "size_t") + .define("SEND_TYPE_ARG4", "int") + .define("SEND_TYPE_RETV", "ssize_t") + .define("SIZEOF_CURL_OFF_T", "8") + .define("SIZEOF_INT", "4") + .define("SIZEOF_SHORT", "2"); + + if cfg!(feature = "ssl") { + if target.contains("-apple-") { + cfg.define("USE_SECTRANSP", None) + .file("curl/lib/vtls/sectransp.c"); + if xcode_major_version().map_or(true, |v| v >= 9) { + // On earlier Xcode versions (<9), defining HAVE_BUILTIN_AVAILABLE + // would cause __bultin_available() to fail to compile due to + // unrecognized platform names, so we try to check for Xcode + // version first (if unknown, assume it's recent, as in >= 9). + cfg.define("HAVE_BUILTIN_AVAILABLE", "1"); + } + } else { + cfg.define("USE_OPENSSL", None) + .file("curl/lib/vtls/openssl.c"); + + println!("cargo:rustc-cfg=link_openssl"); + if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { + cfg.include(path); + } + } + } + + if cfg!(feature = "spnego") { + cfg.define("HAVE_GSSAPI", None) + .file("curl/lib/curl_gssapi.c") + .file("curl/lib/socks_gssapi.c") + .file("curl/lib/vauth/spnego_gssapi.c"); + + // Link against the MIT gssapi library. It might be desirable to add support for + // choosing between MIT and Heimdal libraries in the future. + println!("cargo:rustc-link-lib=gssapi_krb5"); + } + + let width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse::() + .unwrap(); + cfg.define("SIZEOF_SSIZE_T", Some(&(width / 8).to_string()[..])); + cfg.define("SIZEOF_SIZE_T", Some(&(width / 8).to_string()[..])); + cfg.define("SIZEOF_LONG", Some(&(width / 8).to_string()[..])); + + cfg.flag("-fvisibility=hidden"); + } + + cfg.compile("curl"); + + if windows { + println!("cargo:rustc-link-lib=ws2_32"); + println!("cargo:rustc-link-lib=crypt32"); + } + + // Illumos/Solaris requires explicit linking with libnsl + if target.contains("solaris") { + println!("cargo:rustc-link-lib=nsl"); + } + + if target.contains("-apple-") { + println!("cargo:rustc-link-lib=framework=Security"); + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + } +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> bool { + false +} + +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> bool { + // the import library for the dll is called libcurl_imp + let mut successful_probe_details = match vcpkg::Config::new() + .lib_names("libcurl_imp", "libcurl") + .emit_includes(true) + .probe("curl") + { + Ok(details) => Some(details), + Err(e) => { + println!("first run of vcpkg did not find libcurl: {}", e); + None + } + }; + + if successful_probe_details.is_none() { + match vcpkg::Config::new() + .lib_name("libcurl") + .emit_includes(true) + .probe("curl") + { + Ok(details) => successful_probe_details = Some(details), + Err(e) => println!("second run of vcpkg did not find libcurl: {}", e), + } + } + + if successful_probe_details.is_some() { + // Found libcurl which depends on openssl, libssh2 and zlib + // in the a default vcpkg installation. Probe for them + // but do not fail if they are not present as we may be working + // with a customized vcpkg installation. + vcpkg::Config::new() + .lib_name("libeay32") + .lib_name("ssleay32") + .probe("openssl") + .ok(); + + vcpkg::probe_package("libssh2").ok(); + + vcpkg::Config::new() + .lib_names("zlib", "zlib1") + .probe("zlib") + .ok(); + + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=user32"); + println!("cargo:rustc-link-lib=wldap32"); + return true; + } + false +} + +fn try_pkg_config() -> bool { + let mut cfg = pkg_config::Config::new(); + cfg.cargo_metadata(false); + let lib = match cfg.probe("libcurl") { + Ok(lib) => lib, + Err(e) => { + println!( + "Couldn't find libcurl from pkgconfig ({:?}), \ + compiling it from source...", + e + ); + return false; + } + }; + + // Not all system builds of libcurl have http2 features enabled, so if we've + // got a http2-requested build then we may fall back to a build from source. + if cfg!(feature = "http2") && !curl_config_reports_http2() { + return false; + } + + // Re-find the library to print cargo's metadata, then print some extra + // metadata as well. + cfg.cargo_metadata(true).probe("libcurl").unwrap(); + for path in lib.include_paths.iter() { + println!("cargo:include={}", path.display()); + } + return true; +} + +fn xcode_major_version() -> Option { + let output = Command::new("xcodebuild").arg("-version").output().ok()?; + if output.status.success() { + let stdout = String::from_utf8_lossy(&output.stdout); + println!("xcode version: {}", stdout); + let mut words = stdout.split_whitespace(); + if words.next()? == "Xcode" { + let version = words.next()?; + return version[..version.find('.')?].parse().ok(); + } + } + println!("unable to determine Xcode version, assuming >= 9"); + None +} + +fn curl_config_reports_http2() -> bool { + let output = Command::new("curl-config").arg("--features").output(); + let output = match output { + Ok(out) => out, + Err(e) => { + println!("failed to run curl-config ({}), building from source", e); + return false; + } + }; + if !output.status.success() { + println!("curl-config failed: {}", output.status); + return false; + } + let stdout = String::from_utf8_lossy(&output.stdout); + if !stdout.contains("HTTP2") { + println!( + "failed to find http-2 feature enabled in pkg-config-found \ + libcurl, building from source" + ); + return false; + } + + return true; +} diff --git a/curl-sys/debian/patches/disable-vendor.patch b/curl-sys/debian/patches/disable-vendor.patch new file mode 100644 index 000000000..ce6996fca --- /dev/null +++ b/curl-sys/debian/patches/disable-vendor.patch @@ -0,0 +1,11 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -47,7 +47,7 @@ + spnego = [] + ssl = ["openssl-sys"] + static-curl = [] +-static-ssl = ["openssl-sys/vendored"] ++static-ssl = ["openssl-sys"] + [target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] + version = "0.9" + optional = true diff --git a/curl-sys/debian/patches/series b/curl-sys/debian/patches/series new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/curl-sys/debian/patches/series @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/curl-sys/lib.rs b/curl-sys/lib.rs new file mode 100644 index 000000000..152889957 --- /dev/null +++ b/curl-sys/lib.rs @@ -0,0 +1,1052 @@ +#![allow(bad_style)] +#![doc(html_root_url = "https://docs.rs/curl-sys/0.3")] + +extern crate libc; +#[cfg(link_libnghttp2)] +extern crate libnghttp2_sys; +#[cfg(link_libz)] +extern crate libz_sys; +#[cfg(link_openssl)] +extern crate openssl_sys; +#[cfg(windows)] +extern crate winapi; + +use libc::c_ulong; +use libc::{c_char, c_double, c_int, c_long, c_short, c_uint, c_void, size_t, time_t}; + +#[cfg(unix)] +pub use libc::fd_set; +#[cfg(windows)] +use winapi::shared::ws2def::SOCKADDR; +#[cfg(windows)] +pub use winapi::um::winsock2::fd_set; + +#[cfg(target_env = "msvc")] +#[doc(hidden)] +pub type __enum_ty = libc::c_int; +#[cfg(not(target_env = "msvc"))] +#[doc(hidden)] +pub type __enum_ty = libc::c_uint; + +pub type CURLINFO = __enum_ty; +pub type CURLoption = __enum_ty; +pub type CURLcode = __enum_ty; +pub type CURLversion = __enum_ty; +pub type curl_off_t = i64; + +pub enum CURL {} + +#[cfg(unix)] +pub type curl_socket_t = libc::c_int; +#[cfg(unix)] +pub const CURL_SOCKET_BAD: curl_socket_t = -1; +#[cfg(all(windows, target_pointer_width = "32"))] +pub type curl_socket_t = libc::c_uint; +#[cfg(all(windows, target_pointer_width = "64"))] +pub type curl_socket_t = u64; +#[cfg(windows)] +pub const CURL_SOCKET_BAD: curl_socket_t = !0; + +pub enum curl_httppost { + // Note that this changed in some versions of libcurl, so we currently don't +// bind the fields as they're apparently not stable. +// pub next: *mut curl_httppost, +// pub name: *mut c_char, +// pub namelength: c_long, +// pub contents: *mut c_char, +// pub contentslength: c_long, +// pub buffer: *mut c_char, +// pub bufferlength: c_long, +// pub contenttype: *mut c_char, +// pub contentheader: *mut curl_slist, +// pub more: *mut curl_httppost, +// pub flags: c_long, +// pub showfilename: *mut c_char, +// pub userp: *mut c_void, +} + +// pub const HTTPPOST_FILENAME: c_long = 1 << 0; +// pub const HTTPPOST_READFILE: c_long = 1 << 1; +// pub const HTTPPOST_PTRNAME: c_long = 1 << 2; +// pub const HTTPPOST_PTRCONTENTS: c_long = 1 << 3; +// pub const HTTPPOST_BUFFER: c_long = 1 << 4; +// pub const HTTPPOST_PTRBUFFER: c_long = 1 << 5; +// pub const HTTPPOST_CALLBACK: c_long = 1 << 6; + +pub type curl_progress_callback = + extern "C" fn(*mut c_void, c_double, c_double, c_double, c_double) -> c_int; +// pub type curl_xferinfo_callback = extern fn(*mut c_void, +// curl_off_t, +// curl_off_t, +// curl_off_t, +// curl_off_t) -> c_int; + +pub const CURL_WRITEFUNC_PAUSE: size_t = 0x10000001; + +pub type curl_write_callback = extern "C" fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t; + +pub type curlfiletype = __enum_ty; +pub const CURLFILETYPE_FILE: curlfiletype = 0; +pub const CURLFILETYPE_DIRECTORY: curlfiletype = 1; +pub const CURLFILETYPE_SYMLINK: curlfiletype = 2; +pub const CURLFILETYPE_DEVICE_BLOCK: curlfiletype = 3; +pub const CURLFILETYPE_DEVICE_CHAR: curlfiletype = 4; +pub const CURLFILETYPE_NAMEDPIPE: curlfiletype = 5; +pub const CURLFILETYPE_SOCKET: curlfiletype = 6; +pub const CURLFILETYPE_DOOR: curlfiletype = 7; +pub const CURLFILETYPE_UNKNOWN: curlfiletype = 8; + +pub const CURLFINFOFLAG_KNOWN_FILENAME: c_uint = 1 << 0; +pub const CURLFINFOFLAG_KNOWN_FILETYPE: c_uint = 1 << 1; +pub const CURLFINFOFLAG_KNOWN_TIME: c_uint = 1 << 2; +pub const CURLFINFOFLAG_KNOWN_PERM: c_uint = 1 << 3; +pub const CURLFINFOFLAG_KNOWN_UID: c_uint = 1 << 4; +pub const CURLFINFOFLAG_KNOWN_GID: c_uint = 1 << 5; +pub const CURLFINFOFLAG_KNOWN_SIZE: c_uint = 1 << 6; +pub const CURLFINFOFLAG_KNOWN_HLINKCOUNT: c_uint = 1 << 7; + +#[repr(C)] +pub struct curl_fileinfo { + pub filename: *mut c_char, + pub filetype: curlfiletype, + pub time: time_t, + pub perm: c_uint, + pub uid: c_int, + pub gid: c_int, + pub size: curl_off_t, + pub hardlinks: c_long, + + pub strings_time: *mut c_char, + pub strings_perm: *mut c_char, + pub strings_user: *mut c_char, + pub strings_group: *mut c_char, + pub strings_target: *mut c_char, + + pub flags: c_uint, + pub b_data: *mut c_char, + pub b_size: size_t, + pub b_used: size_t, +} + +pub const CURL_CHUNK_BGN_FUNC_OK: c_long = 0; +pub const CURL_CHUNK_BGN_FUNC_FAIL: c_long = 1; +pub const CURL_CHUNK_BGN_FUNC_SKIP: c_long = 2; +pub type curl_chunk_bgn_callback = extern "C" fn(*const c_void, *mut c_void, c_int) -> c_long; + +pub const CURL_CHUNK_END_FUNC_OK: c_long = 0; +pub const CURL_CHUNK_END_FUNC_FAIL: c_long = 1; +pub type curl_chunk_end_callback = extern "C" fn(*mut c_void) -> c_long; + +pub const CURL_FNMATCHFUNC_MATCH: c_int = 0; +pub const CURL_FNMATCHFUNC_NOMATCH: c_int = 1; +pub const CURL_FNMATCHFUNC_FAIL: c_int = 2; +pub type curl_fnmatch_callback = extern "C" fn(*mut c_void, *const c_char, *const c_char) -> c_int; + +pub const CURL_SEEKFUNC_OK: c_int = 0; +pub const CURL_SEEKFUNC_FAIL: c_int = 1; +pub const CURL_SEEKFUNC_CANTSEEK: c_int = 2; +pub type curl_seek_callback = extern "C" fn(*mut c_void, curl_off_t, c_int) -> c_int; + +pub const CURL_READFUNC_ABORT: size_t = 0x10000000; +pub const CURL_READFUNC_PAUSE: size_t = 0x10000001; +pub type curl_read_callback = extern "C" fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t; + +// pub const CURL_SOCKOPT_OK: c_int = 0; +// pub const CURL_SOCKOPT_ERROR: c_int = 1; +// pub const CURL_SOCKOPT_ALREADY_CONNECTED: c_int = 2; +// pub type curl_sockopt_callback = extern fn(*mut c_void, +// curl_socket_t, +// curlsocktype) -> c_int; + +pub type curlioerr = __enum_ty; +pub const CURLIOE_OK: curlioerr = 0; +pub const CURLIOE_UNKNOWNCMD: curlioerr = 1; +pub const CURLIOE_FAILRESTART: curlioerr = 2; + +pub type curliocmd = __enum_ty; +pub const CURLIOCMD_NOP: curliocmd = 0; +pub const CURLIOCMD_RESTARTREAD: curliocmd = 1; + +pub type curl_ioctl_callback = extern "C" fn(*mut CURL, c_int, *mut c_void) -> curlioerr; + +pub type curl_malloc_callback = extern "C" fn(size_t) -> *mut c_void; +pub type curl_free_callback = extern "C" fn(*mut c_void); +pub type curl_realloc_callback = extern "C" fn(*mut c_void, size_t) -> *mut c_void; +pub type curl_strdup_callback = extern "C" fn(*const c_char) -> *mut c_char; +pub type curl_calloc_callback = extern "C" fn(size_t, size_t) -> *mut c_void; + +pub type curl_infotype = __enum_ty; +pub const CURLINFO_TEXT: curl_infotype = 0; +pub const CURLINFO_HEADER_IN: curl_infotype = 1; +pub const CURLINFO_HEADER_OUT: curl_infotype = 2; +pub const CURLINFO_DATA_IN: curl_infotype = 3; +pub const CURLINFO_DATA_OUT: curl_infotype = 4; +pub const CURLINFO_SSL_DATA_IN: curl_infotype = 5; +pub const CURLINFO_SSL_DATA_OUT: curl_infotype = 6; + +pub type curl_debug_callback = + extern "C" fn(*mut CURL, curl_infotype, *mut c_char, size_t, *mut c_void) -> c_int; + +pub const CURLE_OK: CURLcode = 0; +pub const CURLE_UNSUPPORTED_PROTOCOL: CURLcode = 1; +pub const CURLE_FAILED_INIT: CURLcode = 2; +pub const CURLE_URL_MALFORMAT: CURLcode = 3; +// pub const CURLE_NOT_BUILT_IN: CURLcode = 4; +pub const CURLE_COULDNT_RESOLVE_PROXY: CURLcode = 5; +pub const CURLE_COULDNT_RESOLVE_HOST: CURLcode = 6; +pub const CURLE_COULDNT_CONNECT: CURLcode = 7; +pub const CURLE_FTP_WEIRD_SERVER_REPLY: CURLcode = 8; +pub const CURLE_REMOTE_ACCESS_DENIED: CURLcode = 9; +// pub const CURLE_FTP_ACCEPT_FAILED: CURLcode = 10; +pub const CURLE_FTP_WEIRD_PASS_REPLY: CURLcode = 11; +// pub const CURLE_FTP_ACCEPT_TIMEOUT: CURLcode = 12; +pub const CURLE_FTP_WEIRD_PASV_REPLY: CURLcode = 13; +pub const CURLE_FTP_WEIRD_227_FORMAT: CURLcode = 14; +pub const CURLE_FTP_CANT_GET_HOST: CURLcode = 15; +pub const CURLE_HTTP2: CURLcode = 16; +pub const CURLE_FTP_COULDNT_SET_TYPE: CURLcode = 17; +pub const CURLE_PARTIAL_FILE: CURLcode = 18; +pub const CURLE_FTP_COULDNT_RETR_FILE: CURLcode = 19; +pub const CURLE_OBSOLETE20: CURLcode = 20; +pub const CURLE_QUOTE_ERROR: CURLcode = 21; +pub const CURLE_HTTP_RETURNED_ERROR: CURLcode = 22; +pub const CURLE_WRITE_ERROR: CURLcode = 23; +pub const CURLE_OBSOLETE24: CURLcode = 24; +pub const CURLE_UPLOAD_FAILED: CURLcode = 25; +pub const CURLE_READ_ERROR: CURLcode = 26; +pub const CURLE_OUT_OF_MEMORY: CURLcode = 27; +pub const CURLE_OPERATION_TIMEDOUT: CURLcode = 28; +pub const CURLE_OBSOLETE29: CURLcode = 29; +pub const CURLE_FTP_PORT_FAILED: CURLcode = 30; +pub const CURLE_FTP_COULDNT_USE_REST: CURLcode = 31; +pub const CURLE_OBSOLETE32: CURLcode = 32; +pub const CURLE_RANGE_ERROR: CURLcode = 33; +pub const CURLE_HTTP_POST_ERROR: CURLcode = 34; +pub const CURLE_SSL_CONNECT_ERROR: CURLcode = 35; +pub const CURLE_BAD_DOWNLOAD_RESUME: CURLcode = 36; +pub const CURLE_FILE_COULDNT_READ_FILE: CURLcode = 37; +pub const CURLE_LDAP_CANNOT_BIND: CURLcode = 38; +pub const CURLE_LDAP_SEARCH_FAILED: CURLcode = 39; +pub const CURLE_OBSOLETE40: CURLcode = 40; +pub const CURLE_FUNCTION_NOT_FOUND: CURLcode = 41; +pub const CURLE_ABORTED_BY_CALLBACK: CURLcode = 42; +pub const CURLE_BAD_FUNCTION_ARGUMENT: CURLcode = 43; +pub const CURLE_OBSOLETE44: CURLcode = 44; +pub const CURLE_INTERFACE_FAILED: CURLcode = 45; +pub const CURLE_OBSOLETE46: CURLcode = 46; +pub const CURLE_TOO_MANY_REDIRECTS: CURLcode = 47; +pub const CURLE_UNKNOWN_OPTION: CURLcode = 48; +pub const CURLE_TELNET_OPTION_SYNTAX: CURLcode = 49; +pub const CURLE_OBSOLETE50: CURLcode = 50; +pub const CURLE_PEER_FAILED_VERIFICATION: CURLcode = 60; +pub const CURLE_GOT_NOTHING: CURLcode = 52; +pub const CURLE_SSL_ENGINE_NOTFOUND: CURLcode = 53; +pub const CURLE_SSL_ENGINE_SETFAILED: CURLcode = 54; +pub const CURLE_SEND_ERROR: CURLcode = 55; +pub const CURLE_RECV_ERROR: CURLcode = 56; +pub const CURLE_OBSOLETE57: CURLcode = 57; +pub const CURLE_SSL_CERTPROBLEM: CURLcode = 58; +pub const CURLE_SSL_CIPHER: CURLcode = 59; +pub const CURLE_SSL_CACERT: CURLcode = 60; +pub const CURLE_BAD_CONTENT_ENCODING: CURLcode = 61; +pub const CURLE_LDAP_INVALID_URL: CURLcode = 62; +pub const CURLE_FILESIZE_EXCEEDED: CURLcode = 63; +pub const CURLE_USE_SSL_FAILED: CURLcode = 64; +pub const CURLE_SEND_FAIL_REWIND: CURLcode = 65; +pub const CURLE_SSL_ENGINE_INITFAILED: CURLcode = 66; +pub const CURLE_LOGIN_DENIED: CURLcode = 67; +pub const CURLE_TFTP_NOTFOUND: CURLcode = 68; +pub const CURLE_TFTP_PERM: CURLcode = 69; +pub const CURLE_REMOTE_DISK_FULL: CURLcode = 70; +pub const CURLE_TFTP_ILLEGAL: CURLcode = 71; +pub const CURLE_TFTP_UNKNOWNID: CURLcode = 72; +pub const CURLE_REMOTE_FILE_EXISTS: CURLcode = 73; +pub const CURLE_TFTP_NOSUCHUSER: CURLcode = 74; +pub const CURLE_CONV_FAILED: CURLcode = 75; +pub const CURLE_CONV_REQD: CURLcode = 76; +pub const CURLE_SSL_CACERT_BADFILE: CURLcode = 77; +pub const CURLE_REMOTE_FILE_NOT_FOUND: CURLcode = 78; +pub const CURLE_SSH: CURLcode = 79; +pub const CURLE_SSL_SHUTDOWN_FAILED: CURLcode = 80; +pub const CURLE_AGAIN: CURLcode = 81; +pub const CURLE_SSL_CRL_BADFILE: CURLcode = 82; +pub const CURLE_SSL_ISSUER_ERROR: CURLcode = 83; +pub const CURLE_FTP_PRET_FAILED: CURLcode = 84; +pub const CURLE_RTSP_CSEQ_ERROR: CURLcode = 85; +pub const CURLE_RTSP_SESSION_ERROR: CURLcode = 86; +pub const CURLE_FTP_BAD_FILE_LIST: CURLcode = 87; +pub const CURLE_CHUNK_FAILED: CURLcode = 88; +pub const CURLE_NO_CONNECTION_AVAILABLE: CURLcode = 89; +pub const CURLE_SSL_PINNEDPUBKEYNOTMATCH: CURLcode = 90; +pub const CURLE_SSL_INVALIDCERTSTATUS: CURLcode = 91; +pub const CURLE_HTTP2_STREAM: CURLcode = 92; +pub const CURLE_RECURSIVE_API_CALL: CURLcode = 93; + +pub type curl_conv_callback = extern "C" fn(*mut c_char, size_t) -> CURLcode; +pub type curl_ssl_ctx_callback = extern "C" fn(*mut CURL, *mut c_void, *mut c_void) -> CURLcode; + +pub type curl_proxytype = __enum_ty; +pub const CURLPROXY_HTTP: curl_proxytype = 0; +pub const CURLPROXY_HTTP_1_0: curl_proxytype = 1; +pub const CURLPROXY_SOCKS4: curl_proxytype = 4; +pub const CURLPROXY_SOCKS5: curl_proxytype = 5; +pub const CURLPROXY_SOCKS4A: curl_proxytype = 6; +pub const CURLPROXY_SOCKS5_HOSTNAME: curl_proxytype = 7; + +pub const CURLAUTH_NONE: c_ulong = 0; +pub const CURLAUTH_BASIC: c_ulong = 1 << 0; +pub const CURLAUTH_DIGEST: c_ulong = 1 << 1; +pub const CURLAUTH_GSSNEGOTIATE: c_ulong = 1 << 2; +pub const CURLAUTH_NTLM: c_ulong = 1 << 3; +pub const CURLAUTH_DIGEST_IE: c_ulong = 1 << 4; +pub const CURLAUTH_NTLM_WB: c_ulong = 1 << 5; +// pub const CURLAUTH_ONLY: c_ulong = 1 << 31; +pub const CURLAUTH_ANY: c_ulong = !CURLAUTH_DIGEST_IE; +pub const CURLAUTH_ANYSAFE: c_ulong = !(CURLAUTH_BASIC | CURLAUTH_DIGEST_IE); + +// pub const CURLSSH_AUTH_ANY: c_ulong = !0; +// pub const CURLSSH_AUTH_NONE: c_ulong = 0; +// pub const CURLSSH_AUTH_PUBLICKEY: c_ulong = 1 << 0; +// pub const CURLSSH_AUTH_PASSWORD: c_ulong = 1 << 1; +// pub const CURLSSH_AUTH_HOST: c_ulong = 1 << 2; +// pub const CURLSSH_AUTH_KEYBOARD: c_ulong = 1 << 3; +// pub const CURLSSH_AUTH_AGENT: c_ulong = 1 << 4; +// pub const CURLSSH_AUTH_DEFAULT: c_ulong = CURLSSH_AUTH_ANY; + +pub const CURLGSSAPI_DELEGATION_NONE: c_ulong = 0; +pub const CURLGSSAPI_DELEGATION_POLICY_FLAG: c_ulong = 1 << 0; +pub const CURLGSSAPI_DELEGATION_FLAG: c_ulong = 1 << 1; + +// pub type curl_khtype = __enum_ty; +// pub const CURLKHTYPE_UNKNOWN: curl_khtype = 0; +// pub const CURLKHTYPE_RSA1: curl_khtype = 1; +// pub const CURLKHTYPE_RSA: curl_khtype = 2; +// pub const CURLKHTYPE_DSS: curl_khtype = 3; + +// #[repr(C)] +// pub struct curl_khkey { +// pub key: *const c_char, +// pub len: size_t, +// pub keytype: curl_khtype, +// } + +// pub type curl_khstat = __enum_ty; +// pub const CURLKHSTAT_FINE_ADD_TO_FILE: curl_khstat = 0; +// pub const CURLKHSTAT_FINE: curl_khstat = 1; +// pub const CURLKHSTAT_REJECT: curl_khstat = 2; +// pub const CURLKHSTAT_DEFER: curl_khstat = 3; +// +// pub type curl_khmatch = __enum_ty; +// pub const CURLKHMATCH_OK: curl_khmatch = 0; +// pub const CURLKHMATCH_MISMATCH: curl_khmatch = 1; +// pub const CURLKHMATCH_MISSING: curl_khmatch = 2; + +// pub type curl_sshkeycallback = extern fn(*mut CURL, +// *const curl_khkey, +// *const curl_khkey, +// curl_khmatch, +// *mut c_void) -> c_int; + +pub const CURL_NETRC_IGNORED: c_ulong = 0; +pub const CURL_NETRC_OPTIONAL: c_ulong = 1; +pub const CURL_NETRC_REQUIRED: c_ulong = 2; + +pub type curl_usessl = __enum_ty; +pub const CURLUSESSL_NONE: curl_usessl = 0; +pub const CURLUSESSL_TRY: curl_usessl = 1; +pub const CURLUSESSL_CONTROL: curl_usessl = 2; +pub const CURLUSESSL_ALL: curl_usessl = 3; + +pub const CURLPROTO_HTTP: c_int = 1 << 0; +pub const CURLPROTO_HTTPS: c_int = 1 << 1; +pub const CURLPROTO_FILE: c_int = 1 << 10; + +pub const CURLOPTTYPE_LONG: CURLoption = 0; +pub const CURLOPTTYPE_OBJECTPOINT: CURLoption = 10_000; +pub const CURLOPTTYPE_FUNCTIONPOINT: CURLoption = 20_000; +pub const CURLOPTTYPE_OFF_T: CURLoption = 30_000; + +pub const CURLOPT_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 1; +pub const CURLOPT_URL: CURLoption = CURLOPTTYPE_OBJECTPOINT + 2; +pub const CURLOPT_PORT: CURLoption = CURLOPTTYPE_LONG + 3; +pub const CURLOPT_PROXY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 4; +pub const CURLOPT_USERPWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 5; +pub const CURLOPT_PROXYUSERPWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 6; +pub const CURLOPT_RANGE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 7; +pub const CURLOPT_INFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 9; +pub const CURLOPT_ERRORBUFFER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 10; +pub const CURLOPT_WRITEFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 11; +pub const CURLOPT_READFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 12; +pub const CURLOPT_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 13; +pub const CURLOPT_INFILESIZE: CURLoption = CURLOPTTYPE_LONG + 14; +pub const CURLOPT_POSTFIELDS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 15; +pub const CURLOPT_REFERER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 16; +pub const CURLOPT_FTPPORT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 17; +pub const CURLOPT_USERAGENT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 18; +pub const CURLOPT_LOW_SPEED_LIMIT: CURLoption = CURLOPTTYPE_LONG + 19; +pub const CURLOPT_LOW_SPEED_TIME: CURLoption = CURLOPTTYPE_LONG + 20; +pub const CURLOPT_RESUME_FROM: CURLoption = CURLOPTTYPE_LONG + 21; +pub const CURLOPT_COOKIE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 22; +pub const CURLOPT_HTTPHEADER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 23; +pub const CURLOPT_HTTPPOST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 24; +pub const CURLOPT_SSLCERT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 25; +pub const CURLOPT_KEYPASSWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 26; +pub const CURLOPT_CRLF: CURLoption = CURLOPTTYPE_LONG + 27; +pub const CURLOPT_QUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 28; +pub const CURLOPT_WRITEHEADER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 29; +pub const CURLOPT_COOKIEFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 31; +pub const CURLOPT_SSLVERSION: CURLoption = CURLOPTTYPE_LONG + 32; +pub const CURLOPT_TIMECONDITION: CURLoption = CURLOPTTYPE_LONG + 33; +pub const CURLOPT_TIMEVALUE: CURLoption = CURLOPTTYPE_LONG + 34; +pub const CURLOPT_CUSTOMREQUEST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 36; +pub const CURLOPT_STDERR: CURLoption = CURLOPTTYPE_OBJECTPOINT + 37; +pub const CURLOPT_POSTQUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 39; +pub const CURLOPT_WRITEINFO: CURLoption = CURLOPTTYPE_OBJECTPOINT + 40; +pub const CURLOPT_VERBOSE: CURLoption = CURLOPTTYPE_LONG + 41; +pub const CURLOPT_HEADER: CURLoption = CURLOPTTYPE_LONG + 42; +pub const CURLOPT_NOPROGRESS: CURLoption = CURLOPTTYPE_LONG + 43; +pub const CURLOPT_NOBODY: CURLoption = CURLOPTTYPE_LONG + 44; +pub const CURLOPT_FAILONERROR: CURLoption = CURLOPTTYPE_LONG + 45; +pub const CURLOPT_UPLOAD: CURLoption = CURLOPTTYPE_LONG + 46; +pub const CURLOPT_POST: CURLoption = CURLOPTTYPE_LONG + 47; +pub const CURLOPT_DIRLISTONLY: CURLoption = CURLOPTTYPE_LONG + 48; +pub const CURLOPT_APPEND: CURLoption = CURLOPTTYPE_LONG + 50; +pub const CURLOPT_NETRC: CURLoption = CURLOPTTYPE_LONG + 51; +pub const CURLOPT_FOLLOWLOCATION: CURLoption = CURLOPTTYPE_LONG + 52; +pub const CURLOPT_TRANSFERTEXT: CURLoption = CURLOPTTYPE_LONG + 53; +pub const CURLOPT_PUT: CURLoption = CURLOPTTYPE_LONG + 54; +pub const CURLOPT_PROGRESSFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 56; +pub const CURLOPT_PROGRESSDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 57; +pub const CURLOPT_AUTOREFERER: CURLoption = CURLOPTTYPE_LONG + 58; +pub const CURLOPT_PROXYPORT: CURLoption = CURLOPTTYPE_LONG + 59; +pub const CURLOPT_POSTFIELDSIZE: CURLoption = CURLOPTTYPE_LONG + 60; +pub const CURLOPT_HTTPPROXYTUNNEL: CURLoption = CURLOPTTYPE_LONG + 61; +pub const CURLOPT_INTERFACE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 62; +pub const CURLOPT_KRBLEVEL: CURLoption = CURLOPTTYPE_OBJECTPOINT + 63; +pub const CURLOPT_SSL_VERIFYPEER: CURLoption = CURLOPTTYPE_LONG + 64; +pub const CURLOPT_CAINFO: CURLoption = CURLOPTTYPE_OBJECTPOINT + 65; +pub const CURLOPT_MAXREDIRS: CURLoption = CURLOPTTYPE_LONG + 68; +pub const CURLOPT_FILETIME: CURLoption = CURLOPTTYPE_LONG + 69; +pub const CURLOPT_TELNETOPTIONS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 70; +pub const CURLOPT_MAXCONNECTS: CURLoption = CURLOPTTYPE_LONG + 71; +pub const CURLOPT_CLOSEPOLICY: CURLoption = CURLOPTTYPE_LONG + 72; +pub const CURLOPT_FRESH_CONNECT: CURLoption = CURLOPTTYPE_LONG + 74; +pub const CURLOPT_FORBID_REUSE: CURLoption = CURLOPTTYPE_LONG + 75; +pub const CURLOPT_RANDOM_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 76; +pub const CURLOPT_EGDSOCKET: CURLoption = CURLOPTTYPE_OBJECTPOINT + 77; +pub const CURLOPT_CONNECTTIMEOUT: CURLoption = CURLOPTTYPE_LONG + 78; +pub const CURLOPT_HEADERFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 79; +pub const CURLOPT_HTTPGET: CURLoption = CURLOPTTYPE_LONG + 80; +pub const CURLOPT_SSL_VERIFYHOST: CURLoption = CURLOPTTYPE_LONG + 81; +pub const CURLOPT_COOKIEJAR: CURLoption = CURLOPTTYPE_OBJECTPOINT + 82; +pub const CURLOPT_SSL_CIPHER_LIST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 83; +pub const CURLOPT_HTTP_VERSION: CURLoption = CURLOPTTYPE_LONG + 84; +pub const CURLOPT_FTP_USE_EPSV: CURLoption = CURLOPTTYPE_LONG + 85; +pub const CURLOPT_SSLCERTTYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 86; +pub const CURLOPT_SSLKEY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 87; +pub const CURLOPT_SSLKEYTYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 88; +pub const CURLOPT_SSLENGINE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 89; +pub const CURLOPT_SSLENGINE_DEFAULT: CURLoption = CURLOPTTYPE_LONG + 90; +pub const CURLOPT_DNS_USE_GLOBAL_CACHE: CURLoption = CURLOPTTYPE_LONG + 91; +pub const CURLOPT_DNS_CACHE_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 92; +pub const CURLOPT_PREQUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 93; +pub const CURLOPT_DEBUGFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 94; +pub const CURLOPT_DEBUGDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 95; +pub const CURLOPT_COOKIESESSION: CURLoption = CURLOPTTYPE_LONG + 96; +pub const CURLOPT_CAPATH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 97; +pub const CURLOPT_BUFFERSIZE: CURLoption = CURLOPTTYPE_LONG + 98; +pub const CURLOPT_NOSIGNAL: CURLoption = CURLOPTTYPE_LONG + 99; +pub const CURLOPT_SHARE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 100; +pub const CURLOPT_PROXYTYPE: CURLoption = CURLOPTTYPE_LONG + 101; +pub const CURLOPT_ACCEPT_ENCODING: CURLoption = CURLOPTTYPE_OBJECTPOINT + 102; +pub const CURLOPT_PRIVATE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 103; +pub const CURLOPT_HTTP200ALIASES: CURLoption = CURLOPTTYPE_OBJECTPOINT + 104; +pub const CURLOPT_UNRESTRICTED_AUTH: CURLoption = CURLOPTTYPE_LONG + 105; +pub const CURLOPT_FTP_USE_EPRT: CURLoption = CURLOPTTYPE_LONG + 106; +pub const CURLOPT_HTTPAUTH: CURLoption = CURLOPTTYPE_LONG + 107; +pub const CURLOPT_SSL_CTX_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 108; +pub const CURLOPT_SSL_CTX_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 109; +pub const CURLOPT_FTP_CREATE_MISSING_DIRS: CURLoption = CURLOPTTYPE_LONG + 110; +pub const CURLOPT_PROXYAUTH: CURLoption = CURLOPTTYPE_LONG + 111; +pub const CURLOPT_FTP_RESPONSE_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 112; +pub const CURLOPT_IPRESOLVE: CURLoption = CURLOPTTYPE_LONG + 113; +pub const CURLOPT_MAXFILESIZE: CURLoption = CURLOPTTYPE_LONG + 114; +pub const CURLOPT_INFILESIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 115; +pub const CURLOPT_RESUME_FROM_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 116; +pub const CURLOPT_MAXFILESIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 117; +pub const CURLOPT_NETRC_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 118; +pub const CURLOPT_USE_SSL: CURLoption = CURLOPTTYPE_LONG + 119; +pub const CURLOPT_POSTFIELDSIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 120; +pub const CURLOPT_TCP_NODELAY: CURLoption = CURLOPTTYPE_LONG + 121; +pub const CURLOPT_FTPSSLAUTH: CURLoption = CURLOPTTYPE_LONG + 129; +pub const CURLOPT_IOCTLFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 130; +pub const CURLOPT_IOCTLDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 131; +pub const CURLOPT_FTP_ACCOUNT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 134; +pub const CURLOPT_COOKIELIST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 135; +pub const CURLOPT_IGNORE_CONTENT_LENGTH: CURLoption = CURLOPTTYPE_LONG + 136; +pub const CURLOPT_FTP_SKIP_PASV_IP: CURLoption = CURLOPTTYPE_LONG + 137; +pub const CURLOPT_FTP_FILEMETHOD: CURLoption = CURLOPTTYPE_LONG + 138; +pub const CURLOPT_LOCALPORT: CURLoption = CURLOPTTYPE_LONG + 139; +pub const CURLOPT_LOCALPORTRANGE: CURLoption = CURLOPTTYPE_LONG + 140; +pub const CURLOPT_CONNECT_ONLY: CURLoption = CURLOPTTYPE_LONG + 141; +pub const CURLOPT_CONV_FROM_NETWORK_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 142; +pub const CURLOPT_CONV_TO_NETWORK_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 143; +pub const CURLOPT_CONV_FROM_UTF8_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 144; +pub const CURLOPT_MAX_SEND_SPEED_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 145; +pub const CURLOPT_MAX_RECV_SPEED_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 146; +pub const CURLOPT_FTP_ALTERNATIVE_TO_USER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 147; +pub const CURLOPT_SOCKOPTFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 148; +pub const CURLOPT_SOCKOPTDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 149; +pub const CURLOPT_SSL_SESSIONID_CACHE: CURLoption = CURLOPTTYPE_LONG + 150; +pub const CURLOPT_SSH_AUTH_TYPES: CURLoption = CURLOPTTYPE_LONG + 151; +pub const CURLOPT_SSH_PUBLIC_KEYFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 152; +pub const CURLOPT_SSH_PRIVATE_KEYFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 153; +pub const CURLOPT_FTP_SSL_CCC: CURLoption = CURLOPTTYPE_LONG + 154; +pub const CURLOPT_TIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 155; +pub const CURLOPT_CONNECTTIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 156; +pub const CURLOPT_HTTP_TRANSFER_DECODING: CURLoption = CURLOPTTYPE_LONG + 157; +pub const CURLOPT_HTTP_CONTENT_DECODING: CURLoption = CURLOPTTYPE_LONG + 158; +pub const CURLOPT_NEW_FILE_PERMS: CURLoption = CURLOPTTYPE_LONG + 159; +pub const CURLOPT_NEW_DIRECTORY_PERMS: CURLoption = CURLOPTTYPE_LONG + 160; +pub const CURLOPT_POSTREDIR: CURLoption = CURLOPTTYPE_LONG + 161; +pub const CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: CURLoption = CURLOPTTYPE_OBJECTPOINT + 162; +pub const CURLOPT_OPENSOCKETFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 163; +pub const CURLOPT_OPENSOCKETDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 164; +pub const CURLOPT_COPYPOSTFIELDS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 165; +pub const CURLOPT_PROXY_TRANSFER_MODE: CURLoption = CURLOPTTYPE_LONG + 166; +pub const CURLOPT_SEEKFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 167; +pub const CURLOPT_SEEKDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 168; +pub const CURLOPT_CRLFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 169; +pub const CURLOPT_ISSUERCERT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 170; +pub const CURLOPT_ADDRESS_SCOPE: CURLoption = CURLOPTTYPE_LONG + 171; +pub const CURLOPT_CERTINFO: CURLoption = CURLOPTTYPE_LONG + 172; +pub const CURLOPT_USERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 173; +pub const CURLOPT_PASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 174; +pub const CURLOPT_PROXYUSERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 175; +pub const CURLOPT_PROXYPASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 176; +pub const CURLOPT_NOPROXY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 177; +pub const CURLOPT_TFTP_BLKSIZE: CURLoption = CURLOPTTYPE_LONG + 178; +pub const CURLOPT_SOCKS5_GSSAPI_SERVICE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 179; +pub const CURLOPT_SOCKS5_GSSAPI_NEC: CURLoption = CURLOPTTYPE_LONG + 180; +pub const CURLOPT_PROTOCOLS: CURLoption = CURLOPTTYPE_LONG + 181; +pub const CURLOPT_REDIR_PROTOCOLS: CURLoption = CURLOPTTYPE_LONG + 182; +pub const CURLOPT_SSH_KNOWNHOSTS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 183; +pub const CURLOPT_SSH_KEYFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 184; +pub const CURLOPT_SSH_KEYDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 185; +pub const CURLOPT_MAIL_FROM: CURLoption = CURLOPTTYPE_OBJECTPOINT + 186; +pub const CURLOPT_MAIL_RCPT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 187; +pub const CURLOPT_FTP_USE_PRET: CURLoption = CURLOPTTYPE_LONG + 188; +pub const CURLOPT_RTSP_REQUEST: CURLoption = CURLOPTTYPE_LONG + 189; +pub const CURLOPT_RTSP_SESSION_ID: CURLoption = CURLOPTTYPE_OBJECTPOINT + 190; +pub const CURLOPT_RTSP_STREAM_URI: CURLoption = CURLOPTTYPE_OBJECTPOINT + 191; +pub const CURLOPT_RTSP_TRANSPORT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 192; +pub const CURLOPT_RTSP_CLIENT_CSEQ: CURLoption = CURLOPTTYPE_LONG + 193; +pub const CURLOPT_RTSP_SERVER_CSEQ: CURLoption = CURLOPTTYPE_LONG + 194; +pub const CURLOPT_INTERLEAVEDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 195; +pub const CURLOPT_INTERLEAVEFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 196; +pub const CURLOPT_WILDCARDMATCH: CURLoption = CURLOPTTYPE_LONG + 197; +pub const CURLOPT_CHUNK_BGN_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 198; +pub const CURLOPT_CHUNK_END_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 199; +pub const CURLOPT_FNMATCH_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 200; +pub const CURLOPT_CHUNK_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 201; +pub const CURLOPT_FNMATCH_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 202; +pub const CURLOPT_RESOLVE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 203; +pub const CURLOPT_TLSAUTH_USERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 204; +pub const CURLOPT_TLSAUTH_PASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 205; +pub const CURLOPT_TLSAUTH_TYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 206; +pub const CURLOPT_TRANSFER_ENCODING: CURLoption = CURLOPTTYPE_LONG + 207; +pub const CURLOPT_CLOSESOCKETFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 208; +pub const CURLOPT_CLOSESOCKETDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 209; +pub const CURLOPT_GSSAPI_DELEGATION: CURLoption = CURLOPTTYPE_LONG + 210; +pub const CURLOPT_DNS_SERVERS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 211; +// pub const CURLOPT_ACCEPTTIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 212; +pub const CURLOPT_TCP_KEEPALIVE: CURLoption = CURLOPTTYPE_LONG + 213; +pub const CURLOPT_TCP_KEEPIDLE: CURLoption = CURLOPTTYPE_LONG + 214; +pub const CURLOPT_TCP_KEEPINTVL: CURLoption = CURLOPTTYPE_LONG + 215; +pub const CURLOPT_SSL_OPTIONS: CURLoption = CURLOPTTYPE_LONG + 216; +// pub const CURLOPT_MAIL_AUTH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 217; +// pub const CURLOPT_SASL_IR: CURLoption = CURLOPTTYPE_LONG + 218; +// pub const CURLOPT_XFERINFOFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 219; +// pub const CURLOPT_XOAUTH2_BEARER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 220; +// pub const CURLOPT_DNS_INTERFACE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 221; +// pub const CURLOPT_DNS_LOCAL_IP4: CURLoption = CURLOPTTYPE_OBJECTPOINT + 222; +// pub const CURLOPT_DNS_LOCAL_IP6: CURLoption = CURLOPTTYPE_OBJECTPOINT + 223; +// pub const CURLOPT_LOGIN_OPTIONS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 224; +pub const CURLOPT_UNIX_SOCKET_PATH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 231; +pub const CURLOPT_PIPEWAIT: CURLoption = CURLOPTTYPE_LONG + 237; + +pub const CURL_IPRESOLVE_WHATEVER: c_int = 0; +pub const CURL_IPRESOLVE_V4: c_int = 1; +pub const CURL_IPRESOLVE_V6: c_int = 2; + +pub const CURLSSLOPT_ALLOW_BEAST: c_long = 1 << 0; +pub const CURLSSLOPT_NO_REVOKE: c_long = 1 << 1; + +/// These enums are for use with the CURLOPT_HTTP_VERSION option. +/// +/// Setting this means we don't care, and that we'd like the library to choose +/// the best possible for us! +pub const CURL_HTTP_VERSION_NONE: c_int = 0; +/// Please use HTTP 1.0 in the request +pub const CURL_HTTP_VERSION_1_0: c_int = 1; +/// Please use HTTP 1.1 in the request +pub const CURL_HTTP_VERSION_1_1: c_int = 2; +/// Please use HTTP 2 in the request +/// (Added in CURL 7.33.0) +pub const CURL_HTTP_VERSION_2_0: c_int = 3; +/// Use version 2 for HTTPS, version 1.1 for HTTP +/// (Added in CURL 7.47.0) +pub const CURL_HTTP_VERSION_2TLS: c_int = 4; +/// Please use HTTP 2 without HTTP/1.1 Upgrade +/// (Added in CURL 7.49.0) +pub const CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE: c_int = 5; + +// Note that the type here is wrong, it's just intended to just be an enum. +pub const CURL_SSLVERSION_DEFAULT: CURLoption = 0; +pub const CURL_SSLVERSION_TLSv1: CURLoption = 1; +pub const CURL_SSLVERSION_SSLv2: CURLoption = 2; +pub const CURL_SSLVERSION_SSLv3: CURLoption = 3; +pub const CURL_SSLVERSION_TLSv1_0: CURLoption = 4; +pub const CURL_SSLVERSION_TLSv1_1: CURLoption = 5; +pub const CURL_SSLVERSION_TLSv1_2: CURLoption = 6; +pub const CURL_SSLVERSION_TLSv1_3: CURLoption = 7; + +pub const CURLOPT_READDATA: CURLoption = CURLOPT_INFILE; +pub const CURLOPT_WRITEDATA: CURLoption = CURLOPT_FILE; +pub const CURLOPT_HEADERDATA: CURLoption = CURLOPT_WRITEHEADER; + +pub type curl_TimeCond = __enum_ty; +pub const CURL_TIMECOND_NONE: curl_TimeCond = 0; +pub const CURL_TIMECOND_IFMODSINCE: curl_TimeCond = 1; +pub const CURL_TIMECOND_IFUNMODSINCE: curl_TimeCond = 2; +pub const CURL_TIMECOND_LASTMOD: curl_TimeCond = 3; + +pub type CURLformoption = __enum_ty; +pub const CURLFORM_NOTHING: CURLformoption = 0; +pub const CURLFORM_COPYNAME: CURLformoption = 1; +pub const CURLFORM_PTRNAME: CURLformoption = 2; +pub const CURLFORM_NAMELENGTH: CURLformoption = 3; +pub const CURLFORM_COPYCONTENTS: CURLformoption = 4; +pub const CURLFORM_PTRCONTENTS: CURLformoption = 5; +pub const CURLFORM_CONTENTSLENGTH: CURLformoption = 6; +pub const CURLFORM_FILECONTENT: CURLformoption = 7; +pub const CURLFORM_ARRAY: CURLformoption = 8; +pub const CURLFORM_OBSOLETE: CURLformoption = 9; +pub const CURLFORM_FILE: CURLformoption = 10; +pub const CURLFORM_BUFFER: CURLformoption = 11; +pub const CURLFORM_BUFFERPTR: CURLformoption = 12; +pub const CURLFORM_BUFFERLENGTH: CURLformoption = 13; +pub const CURLFORM_CONTENTTYPE: CURLformoption = 14; +pub const CURLFORM_CONTENTHEADER: CURLformoption = 15; +pub const CURLFORM_FILENAME: CURLformoption = 16; +pub const CURLFORM_END: CURLformoption = 17; +pub const CURLFORM_STREAM: CURLformoption = 19; + +pub type CURLFORMcode = __enum_ty; +pub const CURL_FORMADD_OK: CURLFORMcode = 0; +pub const CURL_FORMADD_MEMORY: CURLFORMcode = 1; +pub const CURL_FORMADD_OPTION_TWICE: CURLFORMcode = 2; +pub const CURL_FORMADD_NULL: CURLFORMcode = 3; +pub const CURL_FORMADD_UNKNOWN_OPTION: CURLFORMcode = 4; +pub const CURL_FORMADD_INCOMPLETE: CURLFORMcode = 5; +pub const CURL_FORMADD_ILLEGAL_ARRAY: CURLFORMcode = 6; +pub const CURL_FORMADD_DISABLED: CURLFORMcode = 7; + +#[repr(C)] +pub struct curl_forms { + pub option: CURLformoption, + pub value: *const c_char, +} + +pub type curl_formget_callback = extern "C" fn(*mut c_void, *const c_char, size_t) -> size_t; + +#[repr(C)] +pub struct curl_slist { + pub data: *mut c_char, + pub next: *mut curl_slist, +} + +#[repr(C)] +pub struct curl_certinfo { + pub num_of_certs: c_int, + pub certinfo: *mut *mut curl_slist, +} + +// pub type curl_sslbackend = __enum_ty; +// pub const CURLSSLBACKEND_NONE: curl_sslbackend = 0; +// pub const CURLSSLBACKEND_OPENSSL: curl_sslbackend = 1; +// pub const CURLSSLBACKEND_GNUTLS: curl_sslbackend = 2; +// pub const CURLSSLBACKEND_NSS: curl_sslbackend = 3; +// pub const CURLSSLBACKEND_QSOSSL: curl_sslbackend = 4; +// pub const CURLSSLBACKEND_GSKIT: curl_sslbackend = 5; +// pub const CURLSSLBACKEND_POLARSSL: curl_sslbackend = 6; +// pub const CURLSSLBACKEND_CYASSL: curl_sslbackend = 7; +// pub const CURLSSLBACKEND_SCHANNEL: curl_sslbackend = 8; +// pub const CURLSSLBACKEND_DARWINSSL: curl_sslbackend = 9; + +// #[repr(C)] +// pub struct curl_tlssessioninfo { +// pub backend: curl_sslbackend, +// pub internals: *mut c_void, +// } + +pub const CURLINFO_STRING: CURLINFO = 0x100000; +pub const CURLINFO_LONG: CURLINFO = 0x200000; +pub const CURLINFO_DOUBLE: CURLINFO = 0x300000; +pub const CURLINFO_SLIST: CURLINFO = 0x400000; +pub const CURLINFO_MASK: CURLINFO = 0x0fffff; +pub const CURLINFO_TYPEMASK: CURLINFO = 0xf00000; + +pub const CURLINFO_EFFECTIVE_URL: CURLINFO = CURLINFO_STRING + 1; +pub const CURLINFO_RESPONSE_CODE: CURLINFO = CURLINFO_LONG + 2; +pub const CURLINFO_TOTAL_TIME: CURLINFO = CURLINFO_DOUBLE + 3; +pub const CURLINFO_NAMELOOKUP_TIME: CURLINFO = CURLINFO_DOUBLE + 4; +pub const CURLINFO_CONNECT_TIME: CURLINFO = CURLINFO_DOUBLE + 5; +pub const CURLINFO_PRETRANSFER_TIME: CURLINFO = CURLINFO_DOUBLE + 6; +pub const CURLINFO_SIZE_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 7; +pub const CURLINFO_SIZE_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 8; +pub const CURLINFO_SPEED_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 9; +pub const CURLINFO_SPEED_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 10; +pub const CURLINFO_HEADER_SIZE: CURLINFO = CURLINFO_LONG + 11; +pub const CURLINFO_REQUEST_SIZE: CURLINFO = CURLINFO_LONG + 12; +pub const CURLINFO_SSL_VERIFYRESULT: CURLINFO = CURLINFO_LONG + 13; +pub const CURLINFO_FILETIME: CURLINFO = CURLINFO_LONG + 14; +pub const CURLINFO_CONTENT_LENGTH_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 15; +pub const CURLINFO_CONTENT_LENGTH_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 16; +pub const CURLINFO_STARTTRANSFER_TIME: CURLINFO = CURLINFO_DOUBLE + 17; +pub const CURLINFO_CONTENT_TYPE: CURLINFO = CURLINFO_STRING + 18; +pub const CURLINFO_REDIRECT_TIME: CURLINFO = CURLINFO_DOUBLE + 19; +pub const CURLINFO_REDIRECT_COUNT: CURLINFO = CURLINFO_LONG + 20; +pub const CURLINFO_PRIVATE: CURLINFO = CURLINFO_STRING + 21; +pub const CURLINFO_HTTP_CONNECTCODE: CURLINFO = CURLINFO_LONG + 22; +pub const CURLINFO_HTTPAUTH_AVAIL: CURLINFO = CURLINFO_LONG + 23; +pub const CURLINFO_PROXYAUTH_AVAIL: CURLINFO = CURLINFO_LONG + 24; +pub const CURLINFO_OS_ERRNO: CURLINFO = CURLINFO_LONG + 25; +pub const CURLINFO_NUM_CONNECTS: CURLINFO = CURLINFO_LONG + 26; +pub const CURLINFO_SSL_ENGINES: CURLINFO = CURLINFO_SLIST + 27; +pub const CURLINFO_COOKIELIST: CURLINFO = CURLINFO_SLIST + 28; +pub const CURLINFO_LASTSOCKET: CURLINFO = CURLINFO_LONG + 29; +pub const CURLINFO_FTP_ENTRY_PATH: CURLINFO = CURLINFO_STRING + 30; +pub const CURLINFO_REDIRECT_URL: CURLINFO = CURLINFO_STRING + 31; +pub const CURLINFO_PRIMARY_IP: CURLINFO = CURLINFO_STRING + 32; +pub const CURLINFO_APPCONNECT_TIME: CURLINFO = CURLINFO_DOUBLE + 33; +pub const CURLINFO_CERTINFO: CURLINFO = CURLINFO_SLIST + 34; +pub const CURLINFO_CONDITION_UNMET: CURLINFO = CURLINFO_LONG + 35; +pub const CURLINFO_RTSP_SESSION_ID: CURLINFO = CURLINFO_STRING + 36; +pub const CURLINFO_RTSP_CLIENT_CSEQ: CURLINFO = CURLINFO_LONG + 37; +pub const CURLINFO_RTSP_SERVER_CSEQ: CURLINFO = CURLINFO_LONG + 38; +pub const CURLINFO_RTSP_CSEQ_RECV: CURLINFO = CURLINFO_LONG + 39; +pub const CURLINFO_PRIMARY_PORT: CURLINFO = CURLINFO_LONG + 40; +pub const CURLINFO_LOCAL_IP: CURLINFO = CURLINFO_STRING + 41; +pub const CURLINFO_LOCAL_PORT: CURLINFO = CURLINFO_LONG + 42; +// pub const CURLINFO_TLS_SESSION: CURLINFO = CURLINFO_SLIST + 43; + +pub type curl_closepolicy = __enum_ty; +pub const CURLCLOSEPOLICY_NONE: curl_closepolicy = 0; +pub const CURLCLOSEPOLICY_OLDEST: curl_closepolicy = 1; +pub const CURLCLOSEPOLICY_LEAST_RECENTLY_USED: curl_closepolicy = 2; +pub const CURLCLOSEPOLICY_LEAST_TRAFFIC: curl_closepolicy = 3; +pub const CURLCLOSEPOLICY_SLOWEST: curl_closepolicy = 4; +pub const CURLCLOSEPOLICY_CALLBACK: curl_closepolicy = 5; + +pub const CURL_GLOBAL_SSL: c_long = 1 << 0; +pub const CURL_GLOBAL_WIN32: c_long = 1 << 1; +pub const CURL_GLOBAL_ALL: c_long = CURL_GLOBAL_SSL | CURL_GLOBAL_WIN32; +pub const CURL_GLOBAL_NOTHING: c_long = 0; +pub const CURL_GLOBAL_DEFAULT: c_long = CURL_GLOBAL_ALL; +// pub const CURL_GLOBAL_ACK_EINTR: c_long = 1 << 2; + +pub type curl_lock_data = __enum_ty; +pub const CURL_LOCK_DATA_NONE: curl_lock_data = 0; +pub const CURL_LOCK_DATA_SHARE: curl_lock_data = 1; +pub const CURL_LOCK_DATA_COOKIE: curl_lock_data = 2; +pub const CURL_LOCK_DATA_DNS: curl_lock_data = 3; +pub const CURL_LOCK_DATA_SSL_SESSION: curl_lock_data = 4; +pub const CURL_LOCK_DATA_CONNECT: curl_lock_data = 5; + +pub type curl_lock_access = __enum_ty; +pub const CURL_LOCK_ACCESS_NONE: curl_lock_access = 0; +pub const CURL_LOCK_ACCESS_SHARED: curl_lock_access = 1; +pub const CURL_LOCK_ACCESS_SINGLE: curl_lock_access = 2; + +pub type curl_lock_function = + extern "C" fn(*mut CURL, curl_lock_data, curl_lock_access, *mut c_void); +pub type curl_unlock_function = extern "C" fn(*mut CURL, curl_lock_data, *mut c_void); + +pub enum CURLSH {} + +pub type CURLSHcode = __enum_ty; +pub const CURLSHE_OK: CURLSHcode = 0; +pub const CURLSHE_BAD_OPTION: CURLSHcode = 1; +pub const CURLSHE_IN_USE: CURLSHcode = 2; +pub const CURLSHE_INVALID: CURLSHcode = 3; +pub const CURLSHE_NOMEM: CURLSHcode = 4; +// pub const CURLSHE_NOT_BUILT_IN: CURLSHcode = 5; + +pub type CURLSHoption = __enum_ty; +pub const CURLSHOPT_NONE: CURLSHoption = 0; +pub const CURLSHOPT_SHARE: CURLSHoption = 1; +pub const CURLSHOPT_UNSHARE: CURLSHoption = 2; +pub const CURLSHOPT_LOCKFUNC: CURLSHoption = 3; +pub const CURLSHOPT_UNLOCKFUNC: CURLSHoption = 4; +pub const CURLSHOPT_USERDATA: CURLSHoption = 5; + +pub const CURLVERSION_FIRST: CURLversion = 0; +pub const CURLVERSION_SECOND: CURLversion = 1; +pub const CURLVERSION_THIRD: CURLversion = 2; +pub const CURLVERSION_FOURTH: CURLversion = 3; +pub const CURLVERSION_FIFTH: CURLversion = 4; +pub const CURLVERSION_NOW: CURLversion = CURLVERSION_FIFTH; + +#[repr(C)] +pub struct curl_version_info_data { + pub age: CURLversion, + pub version: *const c_char, + pub version_num: c_uint, + pub host: *const c_char, + pub features: c_int, + pub ssl_version: *const c_char, + pub ssl_version_num: c_long, + pub libz_version: *const c_char, + pub protocols: *const *const c_char, + pub ares: *const c_char, + pub ares_num: c_int, + pub libidn: *const c_char, + pub iconv_ver_num: c_int, + pub libssh_version: *const c_char, + pub brotli_ver_num: c_uint, + pub brotli_version: *const c_char, +} + +pub const CURL_VERSION_IPV6: c_int = 1 << 0; +pub const CURL_VERSION_KERBEROS4: c_int = 1 << 1; +pub const CURL_VERSION_SSL: c_int = 1 << 2; +pub const CURL_VERSION_LIBZ: c_int = 1 << 3; +pub const CURL_VERSION_NTLM: c_int = 1 << 4; +pub const CURL_VERSION_GSSNEGOTIATE: c_int = 1 << 5; +pub const CURL_VERSION_DEBUG: c_int = 1 << 6; +pub const CURL_VERSION_ASYNCHDNS: c_int = 1 << 7; +pub const CURL_VERSION_SPNEGO: c_int = 1 << 8; +pub const CURL_VERSION_LARGEFILE: c_int = 1 << 9; +pub const CURL_VERSION_IDN: c_int = 1 << 10; +pub const CURL_VERSION_SSPI: c_int = 1 << 11; +pub const CURL_VERSION_CONV: c_int = 1 << 12; +pub const CURL_VERSION_CURLDEBUG: c_int = 1 << 13; +pub const CURL_VERSION_TLSAUTH_SRP: c_int = 1 << 14; +pub const CURL_VERSION_NTLM_WB: c_int = 1 << 15; +pub const CURL_VERSION_HTTP2: c_int = 1 << 16; +pub const CURL_VERSION_UNIX_SOCKETS: c_int = 1 << 19; + +pub const CURLPAUSE_RECV: c_int = 1 << 0; +pub const CURLPAUSE_RECV_CONT: c_int = 0; +pub const CURLPAUSE_SEND: c_int = 1 << 2; +pub const CURLPAUSE_SEND_CONT: c_int = 0; + +pub enum CURLM {} + +pub type CURLMcode = c_int; +pub const CURLM_CALL_MULTI_PERFORM: CURLMcode = -1; +pub const CURLM_OK: CURLMcode = 0; +pub const CURLM_BAD_HANDLE: CURLMcode = 1; +pub const CURLM_BAD_EASY_HANDLE: CURLMcode = 2; +pub const CURLM_OUT_OF_MEMORY: CURLMcode = 3; +pub const CURLM_INTERNAL_ERROR: CURLMcode = 4; +pub const CURLM_BAD_SOCKET: CURLMcode = 5; +pub const CURLM_UNKNOWN_OPTION: CURLMcode = 6; +// pub const CURLM_ADDED_ALREADY: CURLMcode = 7; + +pub type CURLMSG = __enum_ty; +pub const CURLMSG_NONE: CURLMSG = 0; +pub const CURLMSG_DONE: CURLMSG = 1; + +#[repr(C)] +pub struct CURLMsg { + pub msg: CURLMSG, + pub easy_handle: *mut CURL, + pub data: *mut c_void, +} + +pub const CURL_WAIT_POLLIN: c_short = 0x1; +pub const CURL_WAIT_POLLPRI: c_short = 0x2; +pub const CURL_WAIT_POLLOUT: c_short = 0x4; + +#[repr(C)] +pub struct curl_waitfd { + pub fd: curl_socket_t, + pub events: c_short, + pub revents: c_short, +} + +pub const CURL_POLL_NONE: c_int = 0; +pub const CURL_POLL_IN: c_int = 1; +pub const CURL_POLL_OUT: c_int = 2; +pub const CURL_POLL_INOUT: c_int = 3; +pub const CURL_POLL_REMOVE: c_int = 4; +pub const CURL_CSELECT_IN: c_int = 1; +pub const CURL_CSELECT_OUT: c_int = 2; +pub const CURL_CSELECT_ERR: c_int = 4; +pub const CURL_SOCKET_TIMEOUT: curl_socket_t = CURL_SOCKET_BAD; + +pub type curl_socket_callback = + extern "C" fn(*mut CURL, curl_socket_t, c_int, *mut c_void, *mut c_void) -> c_int; +pub type curl_multi_timer_callback = extern "C" fn(*mut CURLM, c_long, *mut c_void) -> c_int; + +pub type CURLMoption = __enum_ty; +pub const CURLMOPT_SOCKETFUNCTION: CURLMoption = CURLOPTTYPE_FUNCTIONPOINT + 1; +pub const CURLMOPT_SOCKETDATA: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 2; +pub const CURLMOPT_PIPELINING: CURLMoption = CURLOPTTYPE_LONG + 3; +pub const CURLMOPT_TIMERFUNCTION: CURLMoption = CURLOPTTYPE_FUNCTIONPOINT + 4; +pub const CURLMOPT_TIMERDATA: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 5; +// pub const CURLMOPT_MAXCONNECTS: CURLMoption = CURLOPTTYPE_LONG + 6; +pub const CURLMOPT_MAX_HOST_CONNECTIONS: CURLMoption = CURLOPTTYPE_LONG + 7; +pub const CURLMOPT_MAX_PIPELINE_LENGTH: CURLMoption = CURLOPTTYPE_LONG + 8; +// pub const CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: CURLMoption = CURLOPTTYPE_OFF_T + 9; +// pub const CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: CURLMoption = CURLOPTTYPE_OFF_T + 10; +// pub const CURLMOPT_PIPELINING_SITE_BL: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 11; +// pub const CURLMOPT_PIPELINING_SERVER_BL: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 12; +// pub const CURLMOPT_MAX_TOTAL_CONNECTIONS: CURLMoption = CURLOPTTYPE_LONG + 13; + +// These enums are for use with the CURLMOPT_PIPELINING option. +pub const CURLPIPE_NOTHING: c_long = 0; +pub const CURLPIPE_HTTP1: c_long = 1; +pub const CURLPIPE_MULTIPLEX: c_long = 2; + +pub const CURL_ERROR_SIZE: usize = 256; + +pub type curl_opensocket_callback = + extern "C" fn(*mut c_void, curlsocktype, *mut curl_sockaddr) -> curl_socket_t; +pub type curlsocktype = __enum_ty; +pub const CURLSOCKTYPE_IPCXN: curlsocktype = 0; +pub const CURLSOCKTYPE_ACCEPT: curlsocktype = 1; +pub const CURLSOCKTYPE_LAST: curlsocktype = 2; + +#[repr(C)] +pub struct curl_sockaddr { + pub family: c_int, + pub socktype: c_int, + pub protocol: c_int, + pub addrlen: c_uint, + #[cfg(unix)] + pub addr: libc::sockaddr, + #[cfg(windows)] + pub addr: SOCKADDR, +} + +extern "C" { + pub fn curl_formadd( + httppost: *mut *mut curl_httppost, + last_post: *mut *mut curl_httppost, + ... + ) -> CURLFORMcode; + pub fn curl_formget( + form: *mut curl_httppost, + arg: *mut c_void, + append: curl_formget_callback, + ) -> c_int; + pub fn curl_formfree(form: *mut curl_httppost); + + pub fn curl_version() -> *mut c_char; + + pub fn curl_easy_escape(handle: *mut CURL, string: *const c_char, length: c_int) + -> *mut c_char; + pub fn curl_easy_unescape( + handle: *mut CURL, + string: *const c_char, + length: c_int, + outlength: *mut c_int, + ) -> *mut c_char; + pub fn curl_free(p: *mut c_void); + + pub fn curl_global_init(flags: c_long) -> CURLcode; + pub fn curl_global_init_mem( + flags: c_long, + m: curl_malloc_callback, + f: curl_free_callback, + r: curl_realloc_callback, + s: curl_strdup_callback, + c: curl_calloc_callback, + ) -> CURLcode; + pub fn curl_global_cleanup(); + + pub fn curl_slist_append(list: *mut curl_slist, val: *const c_char) -> *mut curl_slist; + pub fn curl_slist_free_all(list: *mut curl_slist); + + pub fn curl_getdate(p: *const c_char, _: *const time_t) -> time_t; + + pub fn curl_share_init() -> *mut CURLSH; + pub fn curl_share_setopt(sh: *mut CURLSH, opt: CURLSHoption, ...) -> CURLSHcode; + pub fn curl_share_cleanup(sh: *mut CURLSH) -> CURLSHcode; + + pub fn curl_version_info(t: CURLversion) -> *mut curl_version_info_data; + + pub fn curl_easy_strerror(code: CURLcode) -> *const c_char; + pub fn curl_share_strerror(code: CURLSHcode) -> *const c_char; + pub fn curl_easy_pause(handle: *mut CURL, bitmask: c_int) -> CURLcode; + + pub fn curl_easy_init() -> *mut CURL; + pub fn curl_easy_setopt(curl: *mut CURL, option: CURLoption, ...) -> CURLcode; + pub fn curl_easy_perform(curl: *mut CURL) -> CURLcode; + pub fn curl_easy_cleanup(curl: *mut CURL); + pub fn curl_easy_getinfo(curl: *mut CURL, info: CURLINFO, ...) -> CURLcode; + pub fn curl_easy_duphandle(curl: *mut CURL) -> *mut CURL; + pub fn curl_easy_reset(curl: *mut CURL); + pub fn curl_easy_recv( + curl: *mut CURL, + buffer: *mut c_void, + buflen: size_t, + n: *mut size_t, + ) -> CURLcode; + pub fn curl_easy_send( + curl: *mut CURL, + buffer: *const c_void, + buflen: size_t, + n: *mut size_t, + ) -> CURLcode; + + pub fn curl_multi_init() -> *mut CURLM; + pub fn curl_multi_add_handle(multi_handle: *mut CURLM, curl_handle: *mut CURL) -> CURLMcode; + pub fn curl_multi_remove_handle(multi_handle: *mut CURLM, curl_handle: *mut CURL) -> CURLMcode; + pub fn curl_multi_fdset( + multi_handle: *mut CURLM, + read_fd_set: *mut fd_set, + write_fd_set: *mut fd_set, + exc_fd_set: *mut fd_set, + max_fd: *mut c_int, + ) -> CURLMcode; + pub fn curl_multi_wait( + multi_handle: *mut CURLM, + extra_fds: *mut curl_waitfd, + extra_nfds: c_uint, + timeout_ms: c_int, + ret: *mut c_int, + ) -> CURLMcode; + pub fn curl_multi_perform(multi_handle: *mut CURLM, running_handles: *mut c_int) -> CURLMcode; + pub fn curl_multi_cleanup(multi_handle: *mut CURLM) -> CURLMcode; + pub fn curl_multi_info_read( + multi_handle: *mut CURLM, + msgs_in_queue: *mut c_int, + ) -> *mut CURLMsg; + pub fn curl_multi_strerror(code: CURLMcode) -> *const c_char; + pub fn curl_multi_socket( + multi_handle: *mut CURLM, + s: curl_socket_t, + running_handles: *mut c_int, + ) -> CURLMcode; + pub fn curl_multi_socket_action( + multi_handle: *mut CURLM, + s: curl_socket_t, + ev_bitmask: c_int, + running_handles: *mut c_int, + ) -> CURLMcode; + pub fn curl_multi_socket_all( + multi_handle: *mut CURLM, + running_handles: *mut c_int, + ) -> CURLMcode; + pub fn curl_multi_timeout(multi_handle: *mut CURLM, milliseconds: *mut c_long) -> CURLMcode; + pub fn curl_multi_setopt(multi_handle: *mut CURLM, option: CURLMoption, ...) -> CURLMcode; + pub fn curl_multi_assign( + multi_handle: *mut CURLM, + sockfd: curl_socket_t, + sockp: *mut c_void, + ) -> CURLMcode; +} diff --git a/curl/.cargo-checksum.json b/curl/.cargo-checksum.json new file mode 100644 index 000000000..5acd57ba6 --- /dev/null +++ b/curl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f8ed9a22aa8c4e49ac0c896279ef532a43a7df2f54fcd19fa36960de029f965f"} \ No newline at end of file diff --git a/curl/.pc/.quilt_patches b/curl/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/curl/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/curl/.pc/.quilt_series b/curl/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/curl/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/curl/.pc/.version b/curl/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/curl/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/curl/.pc/applied-patches b/curl/.pc/applied-patches new file mode 100644 index 000000000..204ee965a --- /dev/null +++ b/curl/.pc/applied-patches @@ -0,0 +1 @@ +winapi3.patch diff --git a/curl/.pc/winapi3.patch/.timestamp b/curl/.pc/winapi3.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/curl/.pc/winapi3.patch/Cargo.toml b/curl/.pc/winapi3.patch/Cargo.toml new file mode 100644 index 000000000..5e2f5eea9 --- /dev/null +++ b/curl/.pc/winapi3.patch/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl" +version = "0.4.22" +authors = ["Alex Crichton "] +autotests = true +description = "Rust bindings to libcurl for making HTTP requests" +homepage = "https://github.com/alexcrichton/curl-rust" +documentation = "https://docs.rs/curl" +categories = ["api-bindings", "web-programming::http-client"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" + +[[test]] +name = "atexit" +harness = false +[dependencies.curl-sys] +version = "0.4.18" +default-features = false + +[dependencies.libc] +version = "0.2.42" + +[dependencies.socket2] +version = "0.3.7" +[dev-dependencies.mio] +version = "0.6" + +[dev-dependencies.mio-extras] +version = "2.0.3" + +[features] +default = ["ssl"] +force-system-lib-on-osx = ["curl-sys/force-system-lib-on-osx"] +http2 = ["curl-sys/http2"] +ssl = ["openssl-sys", "openssl-probe", "curl-sys/ssl"] +static-curl = ["curl-sys/static-curl"] +static-ssl = ["curl-sys/static-ssl"] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] +version = "0.1.2" +optional = true + +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9.43" +optional = true +[target."cfg(target_env = \"msvc\")".dependencies.kernel32-sys] +version = "0.2.2" + +[target."cfg(target_env = \"msvc\")".dependencies.schannel] +version = "0.1.13" +[target."cfg(windows)".dependencies.winapi] +version = "0.2.7" +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl/.pc/winapi3.patch/src/easy/windows.rs b/curl/.pc/winapi3.patch/src/easy/windows.rs new file mode 100644 index 000000000..1eca3d8ed --- /dev/null +++ b/curl/.pc/winapi3.patch/src/easy/windows.rs @@ -0,0 +1,131 @@ +#![allow(non_camel_case_types, non_snake_case)] + +use libc::c_void; + +#[cfg(target_env = "msvc")] +mod win { + use kernel32; + use schannel::cert_context::ValidUses; + use schannel::cert_store::CertStore; + use std::ffi::CString; + use std::mem; + use std::ptr; + use winapi::{self, c_int, c_long, c_uchar, c_void}; + + fn lookup(module: &str, symbol: &str) -> Option<*const c_void> { + unsafe { + let symbol = CString::new(symbol).unwrap(); + let mut mod_buf: Vec = module.encode_utf16().collect(); + mod_buf.push(0); + let handle = kernel32::GetModuleHandleW(mod_buf.as_mut_ptr()); + let n = kernel32::GetProcAddress(handle, symbol.as_ptr()); + if n == ptr::null() { + None + } else { + Some(n) + } + } + } + + pub enum X509_STORE {} + pub enum X509 {} + pub enum SSL_CTX {} + + type d2i_X509_fn = unsafe extern "C" fn( + a: *mut *mut X509, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509; + type X509_free_fn = unsafe extern "C" fn(x: *mut X509); + type X509_STORE_add_cert_fn = + unsafe extern "C" fn(store: *mut X509_STORE, x: *mut X509) -> c_int; + type SSL_CTX_get_cert_store_fn = unsafe extern "C" fn(ctx: *const SSL_CTX) -> *mut X509_STORE; + + struct OpenSSL { + d2i_X509: d2i_X509_fn, + X509_free: X509_free_fn, + X509_STORE_add_cert: X509_STORE_add_cert_fn, + SSL_CTX_get_cert_store: SSL_CTX_get_cert_store_fn, + } + + unsafe fn lookup_functions(crypto_module: &str, ssl_module: &str) -> Option { + macro_rules! get { + ($(let $sym:ident in $module:expr;)*) => ($( + let $sym = match lookup($module, stringify!($sym)) { + Some(p) => p, + None => return None, + }; + )*) + } + get! { + let d2i_X509 in crypto_module; + let X509_free in crypto_module; + let X509_STORE_add_cert in crypto_module; + let SSL_CTX_get_cert_store in ssl_module; + } + Some(OpenSSL { + d2i_X509: mem::transmute(d2i_X509), + X509_free: mem::transmute(X509_free), + X509_STORE_add_cert: mem::transmute(X509_STORE_add_cert), + SSL_CTX_get_cert_store: mem::transmute(SSL_CTX_get_cert_store), + }) + } + + pub unsafe fn add_certs_to_context(ssl_ctx: *mut c_void) { + // check the runtime version of OpenSSL + let openssl = match ::version::Version::get().ssl_version() { + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.1.0") => { + lookup_functions("libcrypto", "libssl") + } + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.0.2") => { + lookup_functions("libeay32", "ssleay32") + } + _ => return, + }; + let openssl = match openssl { + Some(s) => s, + None => return, + }; + + let openssl_store = (openssl.SSL_CTX_get_cert_store)(ssl_ctx as *const SSL_CTX); + let mut store = match CertStore::open_current_user("ROOT") { + Ok(s) => s, + Err(_) => return, + }; + + for cert in store.certs() { + let valid_uses = match cert.valid_uses() { + Ok(v) => v, + Err(_) => continue, + }; + + // check the extended key usage for the "Server Authentication" OID + match valid_uses { + ValidUses::All => {} + ValidUses::Oids(ref oids) => { + let oid = winapi::wincrypt::szOID_PKIX_KP_SERVER_AUTH.to_owned(); + if !oids.contains(&oid) { + continue; + } + } + } + + let der = cert.to_der(); + let x509 = (openssl.d2i_X509)(ptr::null_mut(), &mut der.as_ptr(), der.len() as c_long); + if !x509.is_null() { + (openssl.X509_STORE_add_cert)(openssl_store, x509); + (openssl.X509_free)(x509); + } + } + } +} + +#[cfg(target_env = "msvc")] +pub fn add_certs_to_context(ssl_ctx: *mut c_void) { + unsafe { + win::add_certs_to_context(ssl_ctx as *mut _); + } +} + +#[cfg(not(target_env = "msvc"))] +pub fn add_certs_to_context(_: *mut c_void) {} diff --git a/curl/.pc/winapi3.patch/src/lib.rs b/curl/.pc/winapi3.patch/src/lib.rs new file mode 100644 index 000000000..8a4b72501 --- /dev/null +++ b/curl/.pc/winapi3.patch/src/lib.rs @@ -0,0 +1,130 @@ +//! Rust bindings to the libcurl C library +//! +//! This crate contains bindings for an HTTP/HTTPS client which is powered by +//! [libcurl], the same library behind the `curl` command line tool. The API +//! currently closely matches that of libcurl itself, except that a Rustic layer +//! of safety is applied on top. +//! +//! [libcurl]: https://curl.haxx.se/libcurl/ +//! +//! # The "Easy" API +//! +//! The easiest way to send a request is to use the `Easy` api which corresponds +//! to `CURL` in libcurl. This handle supports a wide variety of options and can +//! be used to make a single blocking request in a thread. Callbacks can be +//! specified to deal with data as it arrives and a handle can be reused to +//! cache connections and such. +//! +//! ```rust,no_run +//! use std::io::{stdout, Write}; +//! +//! use curl::easy::Easy; +//! +//! // Write the contents of rust-lang.org to stdout +//! let mut easy = Easy::new(); +//! easy.url("https://www.rust-lang.org/").unwrap(); +//! easy.write_function(|data| { +//! stdout().write_all(data).unwrap(); +//! Ok(data.len()) +//! }).unwrap(); +//! easy.perform().unwrap(); +//! ``` +//! +//! # What about multiple concurrent HTTP requests? +//! +//! One option you have currently is to send multiple requests in multiple +//! threads, but otherwise libcurl has a "multi" interface for doing this +//! operation. Initial bindings of this interface can be found in the `multi` +//! module, but feedback is welcome! +//! +//! # Where does libcurl come from? +//! +//! This crate links to the `curl-sys` crate which is in turn responsible for +//! acquiring and linking to the libcurl library. Currently this crate will +//! build libcurl from source if one is not already detected on the system. +//! +//! There is a large number of releases for libcurl, all with different sets of +//! capabilities. Robust programs may wish to inspect `Version::get()` to test +//! what features are implemented in the linked build of libcurl at runtime. + +#![deny(missing_docs, missing_debug_implementations)] +#![doc(html_root_url = "https://docs.rs/curl/0.4")] + +extern crate curl_sys; +extern crate libc; +extern crate socket2; + +#[cfg(need_openssl_probe)] +extern crate openssl_probe; +#[cfg(need_openssl_init)] +extern crate openssl_sys; + +#[cfg(windows)] +extern crate winapi; + +#[cfg(target_env = "msvc")] +extern crate kernel32; +#[cfg(target_env = "msvc")] +extern crate schannel; + +use std::ffi::CStr; +use std::str; +use std::sync::{Once, ONCE_INIT}; + +pub use error::{Error, FormError, MultiError, ShareError}; +mod error; + +pub use version::{Protocols, Version}; +mod version; + +pub mod easy; +pub mod multi; +mod panic; + +/// Initializes the underlying libcurl library. +/// +/// It's not required to call this before the library is used, but it's +/// recommended to do so as soon as the program starts. +pub fn init() { + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + platform_init(); + unsafe { + assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0); + } + + // Note that we explicitly don't schedule a call to + // `curl_global_cleanup`. The documentation for that function says + // + // > You must not call it when any other thread in the program (i.e. a + // > thread sharing the same memory) is running. This doesn't just mean + // > no other thread that is using libcurl. + // + // We can't ever be sure of that, so unfortunately we can't call the + // function. + }); + + #[cfg(need_openssl_init)] + fn platform_init() { + openssl_sys::init(); + } + + #[cfg(not(need_openssl_init))] + fn platform_init() {} +} + +unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> { + if ptr.is_null() { + None + } else { + Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap()) + } +} + +fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> { + if r == curl_sys::CURLE_OK { + Ok(()) + } else { + Err(Error::new(r)) + } +} diff --git a/curl/.pc/winapi3.patch/src/multi.rs b/curl/.pc/winapi3.patch/src/multi.rs new file mode 100644 index 000000000..7b1a74cca --- /dev/null +++ b/curl/.pc/winapi3.patch/src/multi.rs @@ -0,0 +1,1102 @@ +//! Multi - initiating multiple requests simultaneously + +use std::fmt; +use std::marker; +use std::time::Duration; + +use curl_sys; +use libc::{c_char, c_int, c_long, c_short, c_void}; + +#[cfg(unix)] +use libc::{fd_set, pollfd, POLLIN, POLLOUT, POLLPRI}; +#[cfg(windows)] +use winapi::winsock2::fd_set; + +use easy::{Easy, Easy2}; +use panic; +use {Error, MultiError}; + +/// A multi handle for initiating multiple connections simultaneously. +/// +/// This structure corresponds to `CURLM` in libcurl and provides the ability to +/// have multiple transfers in flight simultaneously. This handle is then used +/// to manage each transfer. The main purpose of a `CURLM` is for the +/// *application* to drive the I/O rather than libcurl itself doing all the +/// blocking. Methods like `action` allow the application to inform libcurl of +/// when events have happened. +/// +/// Lots more documentation can be found on the libcurl [multi tutorial] where +/// the APIs correspond pretty closely with this crate. +/// +/// [multi tutorial]: https://curl.haxx.se/libcurl/c/libcurl-multi.html +pub struct Multi { + raw: *mut curl_sys::CURLM, + data: Box, +} + +struct MultiData { + socket: Box, + timer: Box) -> bool + Send>, +} + +/// Message from the `messages` function of a multi handle. +/// +/// Currently only indicates whether a transfer is done. +pub struct Message<'multi> { + ptr: *mut curl_sys::CURLMsg, + _multi: &'multi Multi, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct EasyHandle { + easy: Easy, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct Easy2Handle { + easy: Easy2, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Notification of the events that have happened on a socket. +/// +/// This type is passed as an argument to the `action` method on a multi handle +/// to indicate what events have occurred on a socket. +pub struct Events { + bits: c_int, +} + +/// Notification of events that are requested on a socket. +/// +/// This type is yielded to the `socket_function` callback to indicate what +/// events are requested on a socket. +pub struct SocketEvents { + bits: c_int, +} + +/// Raw underlying socket type that the multi handles use +pub type Socket = curl_sys::curl_socket_t; + +/// File descriptor to wait on for use with the `wait` method on a multi handle. +pub struct WaitFd { + inner: curl_sys::curl_waitfd, +} + +impl Multi { + /// Creates a new multi session through which multiple HTTP transfers can be + /// initiated. + pub fn new() -> Multi { + unsafe { + ::init(); + let ptr = curl_sys::curl_multi_init(); + assert!(!ptr.is_null()); + Multi { + raw: ptr, + data: Box::new(MultiData { + socket: Box::new(|_, _, _| ()), + timer: Box::new(|_| true), + }), + } + } + } + + /// Set the callback informed about what to wait for + /// + /// When the `action` function runs, it informs the application about + /// updates in the socket (file descriptor) status by doing none, one, or + /// multiple calls to the socket callback. The callback gets status updates + /// with changes since the previous time the callback was called. See + /// `action` for more details on how the callback is used and should work. + /// + /// The `SocketEvents` parameter informs the callback on the status of the + /// given socket, and the methods on that type can be used to learn about + /// what's going on with the socket. + /// + /// The third `usize` parameter is a custom value set by the `assign` method + /// below. + pub fn socket_function(&mut self, f: F) -> Result<(), MultiError> + where + F: FnMut(Socket, SocketEvents, usize) + Send + 'static, + { + self._socket_function(Box::new(f)) + } + + fn _socket_function( + &mut self, + f: Box, + ) -> Result<(), MultiError> { + self.data.socket = f; + let cb: curl_sys::curl_socket_callback = cb; + try!(self.setopt_ptr( + curl_sys::CURLMOPT_SOCKETFUNCTION, + cb as usize as *const c_char + )); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_SOCKETDATA, ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_easy` + extern "C" fn cb( + _easy: *mut curl_sys::CURL, + socket: curl_sys::curl_socket_t, + what: c_int, + userptr: *mut c_void, + socketp: *mut c_void, + ) -> c_int { + panic::catch(|| unsafe { + let f = &mut (*(userptr as *mut MultiData)).socket; + f(socket, SocketEvents { bits: what }, socketp as usize) + }); + 0 + } + } + + /// Set data to associate with an internal socket + /// + /// This function creates an association in the multi handle between the + /// given socket and a private token of the application. This is designed + /// for `action` uses. + /// + /// When set, the token will be passed to all future socket callbacks for + /// the specified socket. + /// + /// If the given socket isn't already in use by libcurl, this function will + /// return an error. + /// + /// libcurl only keeps one single token associated with a socket, so + /// calling this function several times for the same socket will make the + /// last set token get used. + /// + /// The idea here being that this association (socket to token) is something + /// that just about every application that uses this API will need and then + /// libcurl can just as well do it since it already has an internal hash + /// table lookup for this. + /// + /// # Typical Usage + /// + /// In a typical application you allocate a struct or at least use some kind + /// of semi-dynamic data for each socket that we must wait for action on + /// when using the `action` approach. + /// + /// When our socket-callback gets called by libcurl and we get to know about + /// yet another socket to wait for, we can use `assign` to point out the + /// particular data so that when we get updates about this same socket + /// again, we don't have to find the struct associated with this socket by + /// ourselves. + pub fn assign(&self, socket: Socket, token: usize) -> Result<(), MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_assign( + self.raw, + socket, + token as *mut _ + ))); + Ok(()) + } + } + + /// Set callback to receive timeout values + /// + /// Certain features, such as timeouts and retries, require you to call + /// libcurl even when there is no activity on the file descriptors. + /// + /// Your callback function should install a non-repeating timer with the + /// interval specified. Each time that timer fires, call either `action` or + /// `perform`, depending on which interface you use. + /// + /// A timeout value of `None` means you should delete your timer. + /// + /// A timeout value of 0 means you should call `action` or `perform` (once) + /// as soon as possible. + /// + /// This callback will only be called when the timeout changes. + /// + /// The timer callback should return `true` on success, and `false` on + /// error. This callback can be used instead of, or in addition to, + /// `get_timeout`. + pub fn timer_function(&mut self, f: F) -> Result<(), MultiError> + where + F: FnMut(Option) -> bool + Send + 'static, + { + self._timer_function(Box::new(f)) + } + + fn _timer_function( + &mut self, + f: Box) -> bool + Send>, + ) -> Result<(), MultiError> { + self.data.timer = f; + let cb: curl_sys::curl_multi_timer_callback = cb; + try!(self.setopt_ptr( + curl_sys::CURLMOPT_TIMERFUNCTION, + cb as usize as *const c_char + )); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_TIMERDATA, ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_multi` + extern "C" fn cb( + _multi: *mut curl_sys::CURLM, + timeout_ms: c_long, + user: *mut c_void, + ) -> c_int { + let keep_going = panic::catch(|| unsafe { + let f = &mut (*(user as *mut MultiData)).timer; + if timeout_ms == -1 { + f(None) + } else { + f(Some(Duration::from_millis(timeout_ms as u64))) + } + }) + .unwrap_or(false); + if keep_going { + 0 + } else { + -1 + } + } + } + + /// Enable or disable HTTP pipelining and multiplexing. + /// + /// When http_1 is true, enable HTTP/1.1 pipelining, which means that if + /// you add a second request that can use an already existing connection, + /// the second request will be "piped" on the same connection rather than + /// being executed in parallel. + /// + /// When multiplex is true, enable HTTP/2 multiplexing, which means that + /// follow-up requests can re-use an existing connection and send the new + /// request multiplexed over that at the same time as other transfers are + /// already using that single connection. + pub fn pipelining(&mut self, http_1: bool, multiplex: bool) -> Result<(), MultiError> { + let bitmask = if http_1 { curl_sys::CURLPIPE_HTTP1 } else { 0 } + | if multiplex { + curl_sys::CURLPIPE_MULTIPLEX + } else { + 0 + }; + self.setopt_long(curl_sys::CURLMOPT_PIPELINING, bitmask) + } + + /// Sets the max number of connections to a single host. + /// + /// Pass a long to indicate the max number of simultaneously open connections + /// to a single host (a host being the same as a host name + port number pair). + /// For each new session to a host, libcurl will open up a new connection up to the + /// limit set by the provided value. When the limit is reached, the sessions will + /// be pending until a connection becomes available. If pipelining is enabled, + /// libcurl will try to pipeline if the host is capable of it. + pub fn set_max_host_connections(&mut self, val: usize) -> Result<(), MultiError> { + self.setopt_long(curl_sys::CURLMOPT_MAX_HOST_CONNECTIONS, val as c_long) + } + + /// Sets the pipeline length. + /// + /// This sets the max number that will be used as the maximum amount of + /// outstanding reuqests in an HTTP/1.1 pipelined connection. This option + /// is only used for HTTP/1.1 pipelining, and not HTTP/2 multiplexing. + pub fn set_pipeline_length(&mut self, val: usize) -> Result<(), MultiError> { + self.setopt_long(curl_sys::CURLMOPT_MAX_PIPELINE_LENGTH, val as c_long) + } + + fn setopt_long(&mut self, opt: curl_sys::CURLMoption, val: c_long) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) } + } + + fn setopt_ptr( + &mut self, + opt: curl_sys::CURLMoption, + val: *const c_char, + ) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) } + } + + /// Add an easy handle to a multi session + /// + /// Adds a standard easy handle to the multi stack. This function call will + /// make this multi handle control the specified easy handle. + /// + /// When an easy interface is added to a multi handle, it will use a shared + /// connection cache owned by the multi handle. Removing and adding new easy + /// handles will not affect the pool of connections or the ability to do + /// connection re-use. + /// + /// If you have `timer_function` set in the multi handle (and you really + /// should if you're working event-based with `action` and friends), that + /// callback will be called from within this function to ask for an updated + /// timer so that your main event loop will get the activity on this handle + /// to get started. + /// + /// The easy handle will remain added to the multi handle until you remove + /// it again with `remove` on the returned handle - even when a transfer + /// with that specific easy handle is completed. + pub fn add(&self, mut easy: Easy) -> Result { + // Clear any configuration set by previous transfers because we're + // moving this into a `Send+'static` situation now basically. + easy.transfer(); + + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(EasyHandle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Same as `add`, but works with the `Easy2` type. + pub fn add2(&self, easy: Easy2) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(Easy2Handle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Remove an easy handle from this multi session + /// + /// Removes the easy handle from this multi handle. This will make the + /// returned easy handle be removed from this multi handle's control. + /// + /// When the easy handle has been removed from a multi stack, it is again + /// perfectly legal to invoke `perform` on it. + /// + /// Removing an easy handle while being used is perfectly legal and will + /// effectively halt the transfer in progress involving that easy handle. + /// All other easy handles and transfers will remain unaffected. + pub fn remove(&self, easy: EasyHandle) -> Result { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle( + self.raw, + easy.easy.raw() + ))); + } + Ok(easy.easy) + } + + /// Same as `remove`, but for `Easy2Handle`. + pub fn remove2(&self, easy: Easy2Handle) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle( + self.raw, + easy.easy.raw() + ))); + } + Ok(easy.easy) + } + + /// Read multi stack informationals + /// + /// Ask the multi handle if there are any messages/informationals from the + /// individual transfers. Messages may include informationals such as an + /// error code from the transfer or just the fact that a transfer is + /// completed. More details on these should be written down as well. + pub fn messages(&self, mut f: F) + where + F: FnMut(Message), + { + self._messages(&mut f) + } + + fn _messages(&self, f: &mut FnMut(Message)) { + let mut queue = 0; + unsafe { + loop { + let ptr = curl_sys::curl_multi_info_read(self.raw, &mut queue); + if ptr.is_null() { + break; + } + f(Message { + ptr: ptr, + _multi: self, + }) + } + } + } + + /// Inform of reads/writes available data given an action + /// + /// When the application has detected action on a socket handled by libcurl, + /// it should call this function with the sockfd argument set to + /// the socket with the action. When the events on a socket are known, they + /// can be passed `events`. When the events on a socket are unknown, pass + /// `Events::new()` instead, and libcurl will test the descriptor + /// internally. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// The `action` function informs the application about updates in the + /// socket (file descriptor) status by doing none, one, or multiple calls to + /// the socket callback function set with the `socket_function` method. They + /// update the status with changes since the previous time the callback was + /// called. + pub fn action(&self, socket: Socket, events: &Events) -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action( + self.raw, + socket, + events.bits, + &mut remaining + ))); + Ok(remaining as u32) + } + } + + /// Inform libcurl that a timeout has expired and sockets should be tested. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// Get the timeout time by calling the `timer_function` method. Your + /// application will then get called with information on how long to wait + /// for socket actions at most before doing the timeout action: call the + /// `timeout` method. You can also use the `get_timeout` function to + /// poll the value at any given time, but for an event-based system using + /// the callback is far better than relying on polling the timeout value. + pub fn timeout(&self) -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action( + self.raw, + curl_sys::CURL_SOCKET_BAD, + 0, + &mut remaining + ))); + Ok(remaining as u32) + } + } + + /// Get how long to wait for action before proceeding + /// + /// An application using the libcurl multi interface should call + /// `get_timeout` to figure out how long it should wait for socket actions - + /// at most - before proceeding. + /// + /// Proceeding means either doing the socket-style timeout action: call the + /// `timeout` function, or call `perform` if you're using the simpler and + /// older multi interface approach. + /// + /// The timeout value returned is the duration at this very moment. If 0, it + /// means you should proceed immediately without waiting for anything. If it + /// returns `None`, there's no timeout at all set. + /// + /// Note: if libcurl returns a `None` timeout here, it just means that + /// libcurl currently has no stored timeout value. You must not wait too + /// long (more than a few seconds perhaps) before you call `perform` again. + pub fn get_timeout(&self) -> Result, MultiError> { + let mut ms = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_timeout(self.raw, &mut ms))); + if ms == -1 { + Ok(None) + } else { + Ok(Some(Duration::from_millis(ms as u64))) + } + } + } + + /// Block until activity is detected or a timeout passes. + /// + /// The timeout is used in millisecond-precision. Large durations are + /// clamped at the maximum value curl accepts. + /// + /// The returned integer will contain the number of internal file + /// descriptors on which interesting events occured. + /// + /// This function is a simpler alternative to using `fdset()` and `select()` + /// and does not suffer from file descriptor limits. + /// + /// # Example + /// + /// ``` + /// use curl::multi::Multi; + /// use std::time::Duration; + /// + /// let m = Multi::new(); + /// + /// // Add some Easy handles... + /// + /// while m.perform().unwrap() > 0 { + /// m.wait(&mut [], Duration::from_secs(1)).unwrap(); + /// } + /// ``` + pub fn wait(&self, waitfds: &mut [WaitFd], timeout: Duration) -> Result { + let timeout_ms = { + let secs = timeout.as_secs(); + if secs > (i32::max_value() / 1000) as u64 { + // Duration too large, clamp at maximum value. + i32::max_value() + } else { + secs as i32 * 1000 + timeout.subsec_nanos() as i32 / 1000_000 + } + }; + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_wait( + self.raw, + waitfds.as_mut_ptr() as *mut _, + waitfds.len() as u32, + timeout_ms, + &mut ret + ))); + Ok(ret as u32) + } + } + + /// Reads/writes available data from each easy handle. + /// + /// This function handles transfers on all the added handles that need + /// attention in an non-blocking fashion. + /// + /// When an application has found out there's data available for this handle + /// or a timeout has elapsed, the application should call this function to + /// read/write whatever there is to read or write right now etc. This + /// method returns as soon as the reads/writes are done. This function does + /// not require that there actually is any data available for reading or + /// that data can be written, it can be called just in case. It will return + /// the number of handles that still transfer data. + /// + /// If the amount of running handles is changed from the previous call (or + /// is less than the amount of easy handles you've added to the multi + /// handle), you know that there is one or more transfers less "running". + /// You can then call `info` to get information about each individual + /// completed transfer, and that returned info includes `Error` and more. + /// If an added handle fails very quickly, it may never be counted as a + /// running handle. + /// + /// When running_handles is set to zero (0) on the return of this function, + /// there is no longer any transfers in progress. + /// + /// # Return + /// + /// Before libcurl version 7.20.0: If you receive `is_call_perform`, this + /// basically means that you should call `perform` again, before you select + /// on more actions. You don't have to do it immediately, but the return + /// code means that libcurl may have more data available to return or that + /// there may be more data to send off before it is "satisfied". Do note + /// that `perform` will return `is_call_perform` only when it wants to be + /// called again immediately. When things are fine and there is nothing + /// immediate it wants done, it'll return `Ok` and you need to wait for + /// "action" and then call this function again. + /// + /// This function only returns errors etc regarding the whole multi stack. + /// Problems still might have occurred on individual transfers even when + /// this function returns `Ok`. Use `info` to figure out how individual + /// transfers did. + pub fn perform(&self) -> Result { + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_perform(self.raw, &mut ret))); + Ok(ret as u32) + } + } + + /// Extracts file descriptor information from a multi handle + /// + /// This function extracts file descriptor information from a given + /// handle, and libcurl returns its `fd_set` sets. The application can use + /// these to `select()` on, but be sure to `FD_ZERO` them before calling + /// this function as curl_multi_fdset only adds its own descriptors, it + /// doesn't zero or otherwise remove any others. The curl_multi_perform + /// function should be called as soon as one of them is ready to be read + /// from or written to. + /// + /// If no file descriptors are set by libcurl, this function will return + /// `Ok(None)`. Otherwise `Ok(Some(n))` will be returned where `n` the + /// highest descriptor number libcurl set. When `Ok(None)` is returned it + /// is because libcurl currently does something that isn't possible for + /// your application to monitor with a socket and unfortunately you can + /// then not know exactly when the current action is completed using + /// `select()`. You then need to wait a while before you proceed and call + /// `perform` anyway. + /// + /// When doing `select()`, you should use `get_timeout` to figure out + /// how long to wait for action. Call `perform` even if no activity has + /// been seen on the `fd_set`s after the timeout expires as otherwise + /// internal retries and timeouts may not work as you'd think and want. + /// + /// If one of the sockets used by libcurl happens to be larger than what + /// can be set in an `fd_set`, which on POSIX systems means that the file + /// descriptor is larger than `FD_SETSIZE`, then libcurl will try to not + /// set it. Setting a too large file descriptor in an `fd_set` implies an out + /// of bounds write which can cause crashes, or worse. The effect of NOT + /// storing it will possibly save you from the crash, but will make your + /// program NOT wait for sockets it should wait for... + pub fn fdset2( + &self, + read: Option<&mut curl_sys::fd_set>, + write: Option<&mut curl_sys::fd_set>, + except: Option<&mut curl_sys::fd_set>, + ) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset( + self.raw, read, write, except, &mut ret + ))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + #[doc(hidden)] + #[deprecated(note = "renamed to fdset2")] + pub fn fdset( + &self, + read: Option<&mut fd_set>, + write: Option<&mut fd_set>, + except: Option<&mut fd_set>, + ) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset( + self.raw, + read as *mut _, + write as *mut _, + except as *mut _, + &mut ret + ))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + /// Attempt to close the multi handle and clean up all associated resources. + /// + /// Cleans up and removes a whole multi stack. It does not free or touch any + /// individual easy handles in any way - they still need to be closed + /// individually. + pub fn close(&self) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_cleanup(self.raw)) } + } +} + +fn cvt(code: curl_sys::CURLMcode) -> Result<(), MultiError> { + if code == curl_sys::CURLM_OK { + Ok(()) + } else { + Err(MultiError::new(code)) + } +} + +impl fmt::Debug for Multi { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Multi").field("raw", &self.raw).finish() + } +} + +impl Drop for Multi { + fn drop(&mut self) { + let _ = self.close(); + } +} + +impl EasyHandle { + /// Sets an internal private token for this `EasyHandle`. + /// + /// This function will set the `CURLOPT_PRIVATE` field on the underlying + /// easy handle. + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt( + self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token, + )) + } + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl fmt::Debug for EasyHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl Easy2Handle { + /// Acquires a reference to the underlying handler for events. + pub fn get_ref(&self) -> &H { + self.easy.get_ref() + } + + /// Acquires a reference to the underlying handler for events. + pub fn get_mut(&mut self) -> &mut H { + self.easy.get_mut() + } + + /// Same as `EasyHandle::set_token` + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt( + self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token, + )) + } + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl fmt::Debug for Easy2Handle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl<'multi> Message<'multi> { + /// If this message indicates that a transfer has finished, returns the + /// result of the transfer in `Some`. + /// + /// If the message doesn't indicate that a transfer has finished, then + /// `None` is returned. + /// + /// Note that the `result*_for` methods below should be preferred as they + /// provide better error messages as the associated error data on the + /// handle can be associated with the error type. + pub fn result(&self) -> Option> { + unsafe { + if (*self.ptr).msg == curl_sys::CURLMSG_DONE { + Some(::cvt((*self.ptr).data as curl_sys::CURLcode)) + } else { + None + } + } + } + + /// Same as `result`, except only returns `Some` for the specified handle. + /// + /// Note that this function produces better error messages than `result` as + /// it uses `take_error_buf` to associate error information with the + /// returned error. + pub fn result_for(&self, handle: &EasyHandle) -> Option> { + if !self.is_for(handle) { + return None; + } + let mut err = self.result(); + if let Some(Err(e)) = &mut err { + if let Some(s) = handle.easy.take_error_buf() { + e.set_extra(s); + } + } + return err; + } + + /// Same as `result`, except only returns `Some` for the specified handle. + /// + /// Note that this function produces better error messages than `result` as + /// it uses `take_error_buf` to associate error information with the + /// returned error. + pub fn result_for2(&self, handle: &Easy2Handle) -> Option> { + if !self.is_for2(handle) { + return None; + } + let mut err = self.result(); + if let Some(Err(e)) = &mut err { + if let Some(s) = handle.easy.take_error_buf() { + e.set_extra(s); + } + } + return err; + } + + /// Returns whether this easy message was for the specified easy handle or + /// not. + pub fn is_for(&self, handle: &EasyHandle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Same as `is_for`, but for `Easy2Handle`. + pub fn is_for2(&self, handle: &Easy2Handle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Returns the token associated with the easy handle that this message + /// represents a completion for. + /// + /// This function will return the token assigned with + /// `EasyHandle::set_token`. This reads the `CURLINFO_PRIVATE` field of the + /// underlying `*mut CURL`. + pub fn token(&self) -> Result { + unsafe { + let mut p = 0usize; + try!(::cvt(curl_sys::curl_easy_getinfo( + (*self.ptr).easy_handle, + curl_sys::CURLINFO_PRIVATE, + &mut p + ))); + Ok(p) + } + } +} + +impl<'a> fmt::Debug for Message<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Message").field("ptr", &self.ptr).finish() + } +} + +impl Events { + /// Creates a new blank event bit mask. + pub fn new() -> Events { + Events { bits: 0 } + } + + /// Set or unset the whether these events indicate that input is ready. + pub fn input(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_IN, val) + } + + /// Set or unset the whether these events indicate that output is ready. + pub fn output(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_OUT, val) + } + + /// Set or unset the whether these events indicate that an error has + /// happened. + pub fn error(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_ERR, val) + } + + fn flag(&mut self, flag: c_int, val: bool) -> &mut Events { + if val { + self.bits |= flag; + } else { + self.bits &= !flag; + } + self + } +} + +impl fmt::Debug for Events { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("output", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("error", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .finish() + } +} + +impl SocketEvents { + /// Wait for incoming data. For the socket to become readable. + pub fn input(&self) -> bool { + self.bits & curl_sys::CURL_POLL_IN == curl_sys::CURL_POLL_IN + } + + /// Wait for outgoing data. For the socket to become writable. + pub fn output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_OUT == curl_sys::CURL_POLL_OUT + } + + /// Wait for incoming and outgoing data. For the socket to become readable + /// or writable. + pub fn input_and_output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_INOUT == curl_sys::CURL_POLL_INOUT + } + + /// The specified socket/file descriptor is no longer used by libcurl. + pub fn remove(&self) -> bool { + self.bits & curl_sys::CURL_POLL_REMOVE == curl_sys::CURL_POLL_REMOVE + } +} + +impl fmt::Debug for SocketEvents { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &self.input()) + .field("output", &self.output()) + .field("remove", &self.remove()) + .finish() + } +} + +impl WaitFd { + /// Constructs an empty (invalid) WaitFd. + pub fn new() -> WaitFd { + WaitFd { + inner: curl_sys::curl_waitfd { + fd: 0, + events: 0, + revents: 0, + }, + } + } + + /// Set the file descriptor to wait for. + pub fn set_fd(&mut self, fd: Socket) { + self.inner.fd = fd; + } + + /// Indicate that the socket should poll on read events such as new data + /// received. + /// + /// Corresponds to `CURL_WAIT_POLLIN`. + pub fn poll_on_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLIN, val) + } + + /// Indicate that the socket should poll on high priority read events such + /// as out of band data. + /// + /// Corresponds to `CURL_WAIT_POLLPRI`. + pub fn poll_on_priority_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLPRI, val) + } + + /// Indicate that the socket should poll on write events such as the socket + /// being clear to write without blocking. + /// + /// Corresponds to `CURL_WAIT_POLLOUT`. + pub fn poll_on_write(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLOUT, val) + } + + fn flag(&mut self, flag: c_short, val: bool) -> &mut WaitFd { + if val { + self.inner.events |= flag; + } else { + self.inner.events &= !flag; + } + self + } + + /// After a call to `wait`, returns `true` if `poll_on_read` was set and a + /// read event occured. + pub fn received_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLIN == curl_sys::CURL_WAIT_POLLIN + } + + /// After a call to `wait`, returns `true` if `poll_on_priority_read` was set and a + /// priority read event occured. + pub fn received_priority_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLPRI == curl_sys::CURL_WAIT_POLLPRI + } + + /// After a call to `wait`, returns `true` if `poll_on_write` was set and a + /// write event occured. + pub fn received_write(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLOUT == curl_sys::CURL_WAIT_POLLOUT + } +} + +#[cfg(unix)] +impl From for WaitFd { + fn from(pfd: pollfd) -> WaitFd { + let mut events = 0; + if pfd.events & POLLIN == POLLIN { + events |= curl_sys::CURL_WAIT_POLLIN; + } + if pfd.events & POLLPRI == POLLPRI { + events |= curl_sys::CURL_WAIT_POLLPRI; + } + if pfd.events & POLLOUT == POLLOUT { + events |= curl_sys::CURL_WAIT_POLLOUT; + } + WaitFd { + inner: curl_sys::curl_waitfd { + fd: pfd.fd, + events: events, + revents: 0, + }, + } + } +} + +impl fmt::Debug for WaitFd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("WaitFd") + .field("fd", &self.inner.fd) + .field("events", &self.inner.fd) + .field("revents", &self.inner.fd) + .finish() + } +} diff --git a/curl/Cargo.toml b/curl/Cargo.toml new file mode 100644 index 000000000..786622a97 --- /dev/null +++ b/curl/Cargo.toml @@ -0,0 +1,67 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl" +version = "0.4.22" +authors = ["Alex Crichton "] +autotests = true +description = "Rust bindings to libcurl for making HTTP requests" +homepage = "https://github.com/alexcrichton/curl-rust" +documentation = "https://docs.rs/curl" +categories = ["api-bindings", "web-programming::http-client"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" + +[[test]] +name = "atexit" +harness = false +[dependencies.curl-sys] +version = "0.4.18" +default-features = false + +[dependencies.libc] +version = "0.2.42" + +[dependencies.socket2] +version = "0.3.7" +[dev-dependencies.mio] +version = "0.6" + +[dev-dependencies.mio-extras] +version = "2.0.3" + +[features] +default = ["ssl"] +force-system-lib-on-osx = ["curl-sys/force-system-lib-on-osx"] +http2 = ["curl-sys/http2"] +ssl = ["openssl-sys", "openssl-probe", "curl-sys/ssl"] +static-curl = ["curl-sys/static-curl"] +static-ssl = ["curl-sys/static-ssl"] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] +version = "0.1.2" +optional = true + +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9.43" +optional = true + +[target."cfg(target_env = \"msvc\")".dependencies.schannel] +version = "0.1.13" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["winsock2", "wincrypt", "libloaderapi"] +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl/LICENSE b/curl/LICENSE new file mode 100644 index 000000000..5f5e4b09d --- /dev/null +++ b/curl/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Carl Lerche + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/curl/README.md b/curl/README.md new file mode 100644 index 000000000..5507004f8 --- /dev/null +++ b/curl/README.md @@ -0,0 +1,171 @@ +# curl-rust + +libcurl bindings for Rust + +[![Build Status](https://dev.azure.com/alexcrichton/curl-rust/_apis/build/status/alexcrichton.curl-rust?branchName=master)](https://dev.azure.com/alexcrichton/curl-rust/_build/latest?definitionId=6&branchName=master) + +[Documentation](https://docs.rs/curl) + +## Quick Start + +```rust +extern crate curl; + +use std::io::{stdout, Write}; + +use curl::easy::Easy; + +// Print a web page onto stdout +fn main() { + let mut easy = Easy::new(); + easy.url("https://www.rust-lang.org/").unwrap(); + easy.write_function(|data| { + stdout().write_all(data).unwrap(); + Ok(data.len()) + }).unwrap(); + easy.perform().unwrap(); + + println!("{}", easy.response_code().unwrap()); +} +``` + +```rust +extern crate curl; + +use curl::easy::Easy; + +// Capture output into a local `Vec`. +fn main() { + let mut dst = Vec::new(); + let mut easy = Easy::new(); + easy.url("https://www.rust-lang.org/").unwrap(); + + let mut transfer = easy.transfer(); + transfer.write_function(|data| { + dst.extend_from_slice(data); + Ok(data.len()) + }).unwrap(); + transfer.perform().unwrap(); +} +``` + +## Post / Put requests + +The `put` and `post` methods on `Easy` can configure the method of the HTTP +request, and then `read_function` can be used to specify how data is filled in. +This interface works particularly well with types that implement `Read`. + +```rust,no_run +extern crate curl; + +use std::io::Read; +use curl::easy::Easy; + +fn main() { + let mut data = "this is the body".as_bytes(); + + let mut easy = Easy::new(); + easy.url("http://www.example.com/upload").unwrap(); + easy.post(true).unwrap(); + easy.post_field_size(data.len() as u64).unwrap(); + + let mut transfer = easy.transfer(); + transfer.read_function(|buf| { + Ok(data.read(buf).unwrap_or(0)) + }).unwrap(); + transfer.perform().unwrap(); +} +``` + +## Custom headers + +Custom headers can be specified as part of the request: + +```rust,no_run +extern crate curl; + +use curl::easy::{Easy, List}; + +fn main() { + let mut easy = Easy::new(); + easy.url("http://www.example.com").unwrap(); + + let mut list = List::new(); + list.append("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").unwrap(); + easy.http_headers(list).unwrap(); + easy.perform().unwrap(); +} +``` + +## Keep alive + +The handle can be re-used across multiple requests. Curl will attempt to +keep the connections alive. + +```rust,no_run +extern crate curl; + +use curl::easy::Easy; + +fn main() { + let mut handle = Easy::new(); + + handle.url("http://www.example.com/foo").unwrap(); + handle.perform().unwrap(); + + handle.url("http://www.example.com/bar").unwrap(); + handle.perform().unwrap(); +} +``` + +## Multiple requests + +The libcurl library provides support for sending multiple requests +simultaneously through the "multi" interface. This is currently bound in the +`multi` module of this crate and provides the ability to execute multiple +transfers simultaneously. For more information, see that module. + +## Building + +By default, this crate will attempt to dynamically link to the system-wide +libcurl and the system-wide SSL library. Some of this behavior can be customized +with various Cargo features: + +- `ssl`: Enable SSL support. Enabled by default. +- `http2`: Enable HTTP/2 support via libnghttp2. Disabled by default. +- `static-curl`: Use a bundled libcurl version and statically link to it. Disabled by default. +- `static-ssl`: Use a bundled OpenSSL version and statically link to it. Only applies on platforms that use OpenSSL. Disabled by default. +- `spnego`: Enable SPNEGO support. Disabled by default. + +## Version Support + +The bindings have been developed using curl version 7.24.0. They should +work with any newer version of curl and possibly with older versions, +but this has not been tested. + +## Troubleshooting + +### Curl built against the NSS SSL library + +If you encounter the following error message: + +``` + [77] Problem with the SSL CA cert (path? access rights?) +``` + +That means most likely, that curl was linked against `libcurl-nss.so` due to +installed libcurl NSS development files, and that the required library +`libnsspem.so` is missing. See also the curl man page: "If curl is built +against the NSS SSL library, the NSS PEM PKCS#11 module (libnsspem.so) needs to +be available for this option to work properly." + +In order to avoid this failure you can either + + * install the missing library (e.g. Debian: `nss-plugin-pem`), or + * remove the libcurl NSS development files (e.g. Debian: `libcurl4-nss-dev`) and + rebuild curl-rust. + +## License + +The `curl-rust` crate is licensed under the MIT license, see `LICENSE` for more +details. diff --git a/curl/azure-pipelines.yml b/curl/azure-pipelines.yml new file mode 100644 index 000000000..a46bbcbbf --- /dev/null +++ b/curl/azure-pipelines.yml @@ -0,0 +1,101 @@ +trigger: + - master + +jobs: + - job: Linux + pool: + vmImage: ubuntu-16.04 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-unknown-linux-gnu + DOCKER: linux64 + i686: + TARGET: i686-unknown-linux-gnu + DOCKER: linux32 + x86_64-musl: + TARGET: x86_64-unknown-linux-musl + DOCKER: musl + mingw: + TARGET: x86_64-pc-windows-gnu + DOCKER: mingw + NO_RUN: 1 + TOOLCHAIN: nightly + system-curl: + TARGET: x86_64-unknown-linux-gnu + DOCKER: linux64-curl + openssl-110: + TARGET: x86_64-unknown-linux-gnu + DOCKER: centos7 + x86_64-beta: + TARGET: x86_64-unknown-linux-gnu + DOCKER: linux64 + TOOLCHAIN: beta + x86_64-nightly: + TARGET: x86_64-unknown-linux-gnu + DOCKER: linux64 + TOOLCHAIN: nightly + + - job: macOS + pool: + vmImage: macos-10.13 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64: + TARGET: x86_64-apple-darwin + i686: + TARGET: i686-apple-darwin + + - job: macOS_static + pool: + vmImage: macos-10.13 + steps: + - checkout: self + submodules: true + - template: ci/azure-install-rust.yml + - script: cargo test --features curl-sys/static-curl -vvv + + - job: Windows_vs2019 + pool: + vmImage: windows-2019 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + + - job: Windows_vs2017 + pool: + vmImage: vs2017-win2016 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + i686-msvc: + TARGET: i686-pc-windows-msvc + + - job: Windows_vs2015 + pool: + vmImage: vs2015-win2012r2 + steps: + - template: ci/azure-steps.yml + strategy: + matrix: + x86_64-msvc: + TARGET: x86_64-pc-windows-msvc + + - job: docs + steps: + - template: ci/azure-install-rust.yml + - script: cargo doc --no-deps --all-features + - script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + env: + GITHUB_DEPLOY_KEY: $(GITHUB_DEPLOY_KEY) diff --git a/curl/build.rs b/curl/build.rs new file mode 100644 index 000000000..5dad28402 --- /dev/null +++ b/curl/build.rs @@ -0,0 +1,24 @@ +use std::env; +use std::str::FromStr; + +fn main() { + // OpenSSL >= 1.1.0 can be initialized concurrently and is initialized correctly by libcurl. + // <= 1.0.2 need locking callbacks, which are provided by openssl_sys::init(). + let use_openssl = match env::var("DEP_OPENSSL_VERSION") { + Ok(ver) => { + let ver = u32::from_str(&ver).unwrap(); + if ver < 110 { + println!("cargo:rustc-cfg=need_openssl_init"); + } + true + } + Err(_) => false, + }; + + if use_openssl { + // The system libcurl should have the default certificate paths configured. + if env::var_os("DEP_CURL_STATIC").is_some() { + println!("cargo:rustc-cfg=need_openssl_probe"); + } + } +} diff --git a/curl/ci/Dockerfile-centos7 b/curl/ci/Dockerfile-centos7 new file mode 100644 index 000000000..3af7dbbd3 --- /dev/null +++ b/curl/ci/Dockerfile-centos7 @@ -0,0 +1,7 @@ +FROM centos:7 + +RUN yum update -y +RUN yum install -y \ + gcc ca-certificates make \ + openssl-devel \ + pkgconfig diff --git a/curl/ci/Dockerfile-linux32 b/curl/ci/Dockerfile-linux32 new file mode 100644 index 000000000..4d55dcf04 --- /dev/null +++ b/curl/ci/Dockerfile-linux32 @@ -0,0 +1,14 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib \ + ca-certificates \ + make \ + libc6-dev \ + libssl-dev:i386 \ + pkg-config + +ENV PKG_CONFIG=i686-linux-gnu-pkg-config \ + PKG_CONFIG_ALLOW_CROSS=1 diff --git a/curl/ci/Dockerfile-linux64 b/curl/ci/Dockerfile-linux64 new file mode 100644 index 000000000..0acd1223a --- /dev/null +++ b/curl/ci/Dockerfile-linux64 @@ -0,0 +1,7 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + libssl-dev \ + pkg-config diff --git a/curl/ci/Dockerfile-linux64-curl b/curl/ci/Dockerfile-linux64-curl new file mode 100644 index 000000000..be03c24da --- /dev/null +++ b/curl/ci/Dockerfile-linux64-curl @@ -0,0 +1,6 @@ +FROM ubuntu:14.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + libssl-dev libcurl4-openssl-dev pkg-config diff --git a/curl/ci/Dockerfile-mingw b/curl/ci/Dockerfile-mingw new file mode 100644 index 000000000..ee5926c8d --- /dev/null +++ b/curl/ci/Dockerfile-mingw @@ -0,0 +1,6 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + gcc-mingw-w64-x86-64 libz-mingw-w64-dev diff --git a/curl/ci/Dockerfile-musl b/curl/ci/Dockerfile-musl new file mode 100644 index 000000000..47d211fdf --- /dev/null +++ b/curl/ci/Dockerfile-musl @@ -0,0 +1,18 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev curl \ + musl-tools + +RUN \ + curl https://www.openssl.org/source/old/1.0.2/openssl-1.0.2g.tar.gz | tar xzf - && \ + cd openssl-1.0.2g && \ + CC=musl-gcc ./Configure --prefix=/openssl no-dso linux-x86_64 -fPIC && \ + make -j10 && \ + make install && \ + cd .. && \ + rm -rf openssl-1.0.2g + +ENV OPENSSL_STATIC=1 \ + OPENSSL_DIR=/openssl diff --git a/curl/ci/azure-install-rust.yml b/curl/ci/azure-install-rust.yml new file mode 100644 index 000000000..fa7eae459 --- /dev/null +++ b/curl/ci/azure-install-rust.yml @@ -0,0 +1,23 @@ +steps: + - bash: | + set -e + toolchain=$TOOLCHAIN + if [ "$toolchain" = "" ]; then + toolchain=stable + fi + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $toolchain + echo "##vso[task.prependpath]$HOME/.cargo/bin" + displayName: Install rust (unix) + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain stable-%TARGET% + echo ##vso[task.prependpath]%USERPROFILE%\.cargo\bin + displayName: Install rust (windows) + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/curl/ci/azure-steps.yml b/curl/ci/azure-steps.yml new file mode 100644 index 000000000..bbd670f9e --- /dev/null +++ b/curl/ci/azure-steps.yml @@ -0,0 +1,31 @@ +steps: + - checkout: self + submodules: true + + - template: azure-install-rust.yml + + - bash: rustup target add $TARGET + displayName: Install Rust target + + - bash: ./ci/run.sh + condition: ne( variables['Agent.OS'], 'Linux' ) + displayName: Run test script + + - bash: | + set -e + cargo generate-lockfile + mkdir .cargo target + docker build -t rust -f ci/Dockerfile-$DOCKER ci + docker run \ + -w /src \ + -v `pwd`:/src:ro \ + -v `pwd`/target:/src/target \ + -v `pwd`/ci/.cargo:/src/.cargo:ro \ + -v `rustc --print sysroot`:/usr/local:ro \ + -e TARGET \ + -e NO_RUN \ + -e CARGO_TARGET_DIR=/src/target \ + rust \ + sh ci/run.sh \ + condition: eq( variables['Agent.OS'], 'Linux' ) + displayName: Run docker test script diff --git a/curl/ci/run.sh b/curl/ci/run.sh new file mode 100755 index 000000000..e22c62da2 --- /dev/null +++ b/curl/ci/run.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +set -ex + +cargo test --target $TARGET --no-run +if [ -z "$NO_RUN" ]; then + cargo test --target $TARGET + cargo run --manifest-path systest/Cargo.toml --target $TARGET + cargo doc --no-deps --target $TARGET + cargo doc --no-deps -p curl-sys --target $TARGET +fi diff --git a/curl/debian/patches/series b/curl/debian/patches/series new file mode 100644 index 000000000..204ee965a --- /dev/null +++ b/curl/debian/patches/series @@ -0,0 +1 @@ +winapi3.patch diff --git a/curl/debian/patches/winapi3.patch b/curl/debian/patches/winapi3.patch new file mode 100644 index 000000000..55e81865d --- /dev/null +++ b/curl/debian/patches/winapi3.patch @@ -0,0 +1,67 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -54,13 +54,12 @@ + [target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] + version = "0.9.43" + optional = true +-[target."cfg(target_env = \"msvc\")".dependencies.kernel32-sys] +-version = "0.2.2" + + [target."cfg(target_env = \"msvc\")".dependencies.schannel] + version = "0.1.13" + [target."cfg(windows)".dependencies.winapi] +-version = "0.2.7" ++version = "0.3" ++features = ["winsock2", "wincrypt", "libloaderapi"] + [badges.appveyor] + repository = "alexcrichton/curl-rust" + +--- a/src/easy/windows.rs ++++ b/src/easy/windows.rs +@@ -4,21 +4,21 @@ + + #[cfg(target_env = "msvc")] + mod win { +- use kernel32; + use schannel::cert_context::ValidUses; + use schannel::cert_store::CertStore; + use std::ffi::CString; + use std::mem; + use std::ptr; + use winapi::{self, c_int, c_long, c_uchar, c_void}; ++ use winapi::um::libloaderapi::{GetModuleHandleW, GetProcAddress}; + + fn lookup(module: &str, symbol: &str) -> Option<*const c_void> { + unsafe { + let symbol = CString::new(symbol).unwrap(); + let mut mod_buf: Vec = module.encode_utf16().collect(); + mod_buf.push(0); +- let handle = kernel32::GetModuleHandleW(mod_buf.as_mut_ptr()); +- let n = kernel32::GetProcAddress(handle, symbol.as_ptr()); ++ let handle = GetModuleHandleW(mod_buf.as_mut_ptr()); ++ let n = GetProcAddress(handle, symbol.as_ptr()); + if n == ptr::null() { + None + } else { +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -63,8 +63,6 @@ + extern crate winapi; + + #[cfg(target_env = "msvc")] +-extern crate kernel32; +-#[cfg(target_env = "msvc")] + extern crate schannel; + + use std::ffi::CStr; +--- a/src/multi.rs ++++ b/src/multi.rs +@@ -10,7 +10,7 @@ + #[cfg(unix)] + use libc::{fd_set, pollfd, POLLIN, POLLOUT, POLLPRI}; + #[cfg(windows)] +-use winapi::winsock2::fd_set; ++use winapi::um::winsock2::fd_set; + + use easy::{Easy, Easy2}; + use panic; diff --git a/curl/src/easy/form.rs b/curl/src/easy/form.rs new file mode 100644 index 000000000..126283010 --- /dev/null +++ b/curl/src/easy/form.rs @@ -0,0 +1,375 @@ +use std::ffi::CString; +use std::fmt; +use std::path::Path; + +use curl_sys; +use easy::{list, List}; +use FormError; + +/// Multipart/formdata for an HTTP POST request. +/// +/// This structure is built up and then passed to the `Easy::httppost` method to +/// be sent off with a request. +pub struct Form { + head: *mut curl_sys::curl_httppost, + tail: *mut curl_sys::curl_httppost, + headers: Vec, + buffers: Vec>, + strings: Vec, +} + +/// One part in a multipart upload, added to a `Form`. +pub struct Part<'form, 'data> { + form: &'form mut Form, + name: &'data str, + array: Vec, + error: Option, +} + +pub fn raw(form: &Form) -> *mut curl_sys::curl_httppost { + form.head +} + +impl Form { + /// Creates a new blank form ready for the addition of new data. + pub fn new() -> Form { + Form { + head: 0 as *mut _, + tail: 0 as *mut _, + headers: Vec::new(), + buffers: Vec::new(), + strings: Vec::new(), + } + } + + /// Prepares adding a new part to this `Form` + /// + /// Note that the part is not actually added to the form until the `add` + /// method is called on `Part`, which may or may not fail. + pub fn part<'a, 'data>(&'a mut self, name: &'data str) -> Part<'a, 'data> { + Part { + error: None, + form: self, + name: name, + array: vec![curl_sys::curl_forms { + option: curl_sys::CURLFORM_END, + value: 0 as *mut _, + }], + } + } +} + +impl fmt::Debug for Form { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: fill this out more + f.debug_struct("Form").field("fields", &"...").finish() + } +} + +impl Drop for Form { + fn drop(&mut self) { + unsafe { + curl_sys::curl_formfree(self.head); + } + } +} + +impl<'form, 'data> Part<'form, 'data> { + /// A pointer to the contents of this part, the actual data to send away. + pub fn contents(&mut self, contents: &'data [u8]) -> &mut Self { + let pos = self.array.len() - 1; + + // curl has an oddity where if the length if 0 it will call strlen + // on the value. This means that if someone wants to add empty form + // contents we need to make sure the buffer contains a null byte. + let ptr = if contents.is_empty() { + b"\x00" + } else { + contents + } + .as_ptr(); + + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_COPYCONTENTS, + value: ptr as *mut _, + }, + ); + self.array.insert( + pos + 1, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTSLENGTH, + value: contents.len() as *mut _, + }, + ); + self + } + + /// Causes this file to be read and its contents used as data in this part + /// + /// This part does not automatically become a file upload part simply + /// because its data was read from a file. + /// + /// # Errors + /// + /// If the filename has any internal nul bytes or if on Windows it does not + /// contain a unicode filename then the `add` function will eventually + /// return an error. + pub fn file_content

(&mut self, file: P) -> &mut Self + where + P: AsRef, + { + self._file_content(file.as_ref()) + } + + fn _file_content(&mut self, file: &Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(file) { + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILECONTENT, + value: bytes.as_ptr() as *mut _, + }, + ); + self.form.strings.push(bytes); + } + self + } + + /// Makes this part a file upload part of the given file. + /// + /// Sets the filename field to the basename of the provided file name, and + /// it reads the contents of the file and passes them as data and sets the + /// content type if the given file matches one of the internally known file + /// extensions. + /// + /// The given upload file must exist entirely on the filesystem before the + /// upload is started because libcurl needs to read the size of it + /// beforehand. + /// + /// Multiple files can be uploaded by calling this method multiple times and + /// content types can also be configured for each file (by calling that + /// next). + /// + /// # Errors + /// + /// If the filename has any internal nul bytes or if on Windows it does not + /// contain a unicode filename then this function will cause `add` to return + /// an error when called. + pub fn file(&mut self, file: &'data P) -> &mut Self + where + P: AsRef, + { + self._file(file.as_ref()) + } + + fn _file(&mut self, file: &'data Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(file) { + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILE, + value: bytes.as_ptr() as *mut _, + }, + ); + self.form.strings.push(bytes); + } + self + } + + /// Used in combination with `Part::file`, provides the content-type for + /// this part, possibly instead of choosing an internal one. + /// + /// # Panics + /// + /// This function will panic if `content_type` contains an internal nul + /// byte. + pub fn content_type(&mut self, content_type: &'data str) -> &mut Self { + if let Some(bytes) = self.bytes2cstr(content_type.as_bytes()) { + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTTYPE, + value: bytes.as_ptr() as *mut _, + }, + ); + self.form.strings.push(bytes); + } + self + } + + /// Used in combination with `Part::file`, provides the filename for + /// this part instead of the actual one. + /// + /// # Errors + /// + /// If `name` contains an internal nul byte, or if on Windows the path is + /// not valid unicode then this function will return an error when `add` is + /// called. + pub fn filename(&mut self, name: &'data P) -> &mut Self + where + P: AsRef, + { + self._filename(name.as_ref()) + } + + fn _filename(&mut self, name: &'data Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(name) { + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILENAME, + value: bytes.as_ptr() as *mut _, + }, + ); + self.form.strings.push(bytes); + } + self + } + + /// This is used to provide a custom file upload part without using the + /// `file` method above. + /// + /// The first parameter is for the filename field and the second is the + /// in-memory contents. + /// + /// # Errors + /// + /// If `name` contains an internal nul byte, or if on Windows the path is + /// not valid unicode then this function will return an error when `add` is + /// called. + pub fn buffer(&mut self, name: &'data P, data: Vec) -> &mut Self + where + P: AsRef, + { + self._buffer(name.as_ref(), data) + } + + fn _buffer(&mut self, name: &'data Path, mut data: Vec) -> &mut Self { + if let Some(bytes) = self.path2cstr(name) { + // If `CURLFORM_BUFFERLENGTH` is set to `0`, libcurl will instead do a strlen() on the + // contents to figure out the size so we need to make sure the buffer is actually + // zero terminated. + let length = data.len(); + if length == 0 { + data.push(0); + } + + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFER, + value: bytes.as_ptr() as *mut _, + }, + ); + self.form.strings.push(bytes); + self.array.insert( + pos + 1, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFERPTR, + value: data.as_ptr() as *mut _, + }, + ); + self.array.insert( + pos + 2, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFERLENGTH, + value: length as *mut _, + }, + ); + self.form.buffers.push(data); + } + self + } + + /// Specifies extra headers for the form POST section. + /// + /// Appends the list of headers to those libcurl automatically generates. + pub fn content_header(&mut self, headers: List) -> &mut Self { + let pos = self.array.len() - 1; + self.array.insert( + pos, + curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTHEADER, + value: list::raw(&headers) as *mut _, + }, + ); + self.form.headers.push(headers); + self + } + + /// Attempts to add this part to the `Form` that it was created from. + /// + /// If any error happens while adding, that error is returned, otherwise + /// `Ok(())` is returned. + pub fn add(&mut self) -> Result<(), FormError> { + if let Some(err) = self.error.clone() { + return Err(err); + } + let rc = unsafe { + curl_sys::curl_formadd( + &mut self.form.head, + &mut self.form.tail, + curl_sys::CURLFORM_COPYNAME, + self.name.as_ptr(), + curl_sys::CURLFORM_NAMELENGTH, + self.name.len(), + curl_sys::CURLFORM_ARRAY, + self.array.as_ptr(), + curl_sys::CURLFORM_END, + ) + }; + if rc == curl_sys::CURL_FORMADD_OK { + Ok(()) + } else { + Err(FormError::new(rc)) + } + } + + #[cfg(unix)] + fn path2cstr(&mut self, p: &Path) -> Option { + use std::os::unix::prelude::*; + self.bytes2cstr(p.as_os_str().as_bytes()) + } + + #[cfg(windows)] + fn path2cstr(&mut self, p: &Path) -> Option { + match p.to_str() { + Some(bytes) => self.bytes2cstr(bytes.as_bytes()), + None if self.error.is_none() => { + // TODO: better error code + self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE)); + None + } + None => None, + } + } + + fn bytes2cstr(&mut self, bytes: &[u8]) -> Option { + match CString::new(bytes) { + Ok(c) => Some(c), + Err(..) if self.error.is_none() => { + // TODO: better error code + self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE)); + None + } + Err(..) => None, + } + } +} + +impl<'form, 'data> fmt::Debug for Part<'form, 'data> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: fill this out more + f.debug_struct("Part") + .field("name", &self.name) + .field("form", &self.form) + .finish() + } +} diff --git a/curl/src/easy/handle.rs b/curl/src/easy/handle.rs new file mode 100644 index 000000000..0fc8e0afd --- /dev/null +++ b/curl/src/easy/handle.rs @@ -0,0 +1,1487 @@ +use std::cell::Cell; +use std::fmt; +use std::io::SeekFrom; +use std::path::Path; +use std::ptr; +use std::str; +use std::time::Duration; + +use curl_sys; +use libc::c_void; + +use easy::handler::{self, InfoType, ReadError, SeekResult, WriteError}; +use easy::handler::{Auth, NetRc, ProxyType, SslOpt}; +use easy::handler::{HttpVersion, IpResolve, SslVersion, TimeCondition}; +use easy::{Easy2, Handler}; +use easy::{Form, List}; +use Error; + +/// Raw bindings to a libcurl "easy session". +/// +/// This type is the same as the `Easy2` type in this library except that it +/// does not contain a type parameter. Callbacks from curl are all controlled +/// via closures on this `Easy` type, and this type namely has a `transfer` +/// method as well for ergonomic management of these callbacks. +/// +/// There's not necessarily a right answer for which type is correct to use, but +/// as a general rule of thumb `Easy` is typically a reasonable choice for +/// synchronous I/O and `Easy2` is a good choice for asynchronous I/O. +/// +/// ## Examples +/// +/// Creating a handle which can be used later +/// +/// ``` +/// use curl::easy::Easy; +/// +/// let handle = Easy::new(); +/// ``` +/// +/// Send an HTTP request, writing the response to stdout. +/// +/// ``` +/// use std::io::{stdout, Write}; +/// +/// use curl::easy::Easy; +/// +/// let mut handle = Easy::new(); +/// handle.url("https://www.rust-lang.org/").unwrap(); +/// handle.write_function(|data| { +/// stdout().write_all(data).unwrap(); +/// Ok(data.len()) +/// }).unwrap(); +/// handle.perform().unwrap(); +/// ``` +/// +/// Collect all output of an HTTP request to a vector. +/// +/// ``` +/// use curl::easy::Easy; +/// +/// let mut data = Vec::new(); +/// let mut handle = Easy::new(); +/// handle.url("https://www.rust-lang.org/").unwrap(); +/// { +/// let mut transfer = handle.transfer(); +/// transfer.write_function(|new_data| { +/// data.extend_from_slice(new_data); +/// Ok(new_data.len()) +/// }).unwrap(); +/// transfer.perform().unwrap(); +/// } +/// println!("{:?}", data); +/// ``` +/// +/// More examples of various properties of an HTTP request can be found on the +/// specific methods as well. +#[derive(Debug)] +pub struct Easy { + inner: Easy2, +} + +/// A scoped transfer of information which borrows an `Easy` and allows +/// referencing stack-local data of the lifetime `'data`. +/// +/// Usage of `Easy` requires the `'static` and `Send` bounds on all callbacks +/// registered, but that's not often wanted if all you need is to collect a +/// bunch of data in memory to a vector, for example. The `Transfer` structure, +/// created by the `Easy::transfer` method, is used for this sort of request. +/// +/// The callbacks attached to a `Transfer` are only active for that one transfer +/// object, and they allow to elide both the `Send` and `'static` bounds to +/// close over stack-local information. +pub struct Transfer<'easy, 'data> { + easy: &'easy mut Easy, + data: Box>, +} + +pub struct EasyData { + running: Cell, + owned: Callbacks<'static>, + borrowed: Cell<*mut Callbacks<'static>>, +} + +unsafe impl Send for EasyData {} + +#[derive(Default)] +struct Callbacks<'a> { + write: Option Result + 'a>>, + read: Option Result + 'a>>, + seek: Option SeekResult + 'a>>, + debug: Option>, + header: Option bool + 'a>>, + progress: Option bool + 'a>>, + ssl_ctx: Option Result<(), Error> + 'a>>, +} + +impl Easy { + /// Creates a new "easy" handle which is the core of almost all operations + /// in libcurl. + /// + /// To use a handle, applications typically configure a number of options + /// followed by a call to `perform`. Options are preserved across calls to + /// `perform` and need to be reset manually (or via the `reset` method) if + /// this is not desired. + pub fn new() -> Easy { + Easy { + inner: Easy2::new(EasyData { + running: Cell::new(false), + owned: Callbacks::default(), + borrowed: Cell::new(ptr::null_mut()), + }), + } + } + + // ========================================================================= + // Behavior options + + /// Same as [`Easy2::verbose`](struct.Easy2.html#method.verbose) + pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> { + self.inner.verbose(verbose) + } + + /// Same as [`Easy2::show_header`](struct.Easy2.html#method.show_header) + pub fn show_header(&mut self, show: bool) -> Result<(), Error> { + self.inner.show_header(show) + } + + /// Same as [`Easy2::progress`](struct.Easy2.html#method.progress) + pub fn progress(&mut self, progress: bool) -> Result<(), Error> { + self.inner.progress(progress) + } + + /// Same as [`Easy2::signal`](struct.Easy2.html#method.signal) + pub fn signal(&mut self, signal: bool) -> Result<(), Error> { + self.inner.signal(signal) + } + + /// Same as [`Easy2::wildcard_match`](struct.Easy2.html#method.wildcard_match) + pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> { + self.inner.wildcard_match(m) + } + + /// Same as [`Easy2::unix_socket`](struct.Easy2.html#method.unix_socket) + pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> { + self.inner.unix_socket(unix_domain_socket) + } + + // ========================================================================= + // Callback options + + /// Set callback for writing received data. + /// + /// This callback function gets called by libcurl as soon as there is data + /// received that needs to be saved. + /// + /// The callback function will be passed as much data as possible in all + /// invokes, but you must not make any assumptions. It may be one byte, it + /// may be thousands. If `show_header` is enabled, which makes header data + /// get passed to the write callback, you can get up to + /// `CURL_MAX_HTTP_HEADER` bytes of header data passed into it. This + /// usually means 100K. + /// + /// This function may be called with zero bytes data if the transferred file + /// is empty. + /// + /// The callback should return the number of bytes actually taken care of. + /// If that amount differs from the amount passed to your callback function, + /// it'll signal an error condition to the library. This will cause the + /// transfer to get aborted and the libcurl function used will return + /// an error with `is_write_error`. + /// + /// If your callback function returns `Err(WriteError::Pause)` it will cause + /// this transfer to become paused. See `unpause_write` for further details. + /// + /// By default data is sent into the void, and this corresponds to the + /// `CURLOPT_WRITEFUNCTION` and `CURLOPT_WRITEDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `write_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{stdout, Write}; + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.write_function(|data| { + /// Ok(stdout().write(data).unwrap()) + /// }).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Writing to a stack-local buffer + /// + /// ``` + /// use std::io::{stdout, Write}; + /// use curl::easy::Easy; + /// + /// let mut buf = Vec::new(); + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// + /// let mut transfer = handle.transfer(); + /// transfer.write_function(|data| { + /// buf.extend_from_slice(data); + /// Ok(data.len()) + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// ``` + pub fn write_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&[u8]) -> Result + Send + 'static, + { + self.inner.get_mut().owned.write = Some(Box::new(f)); + Ok(()) + } + + /// Read callback for data uploads. + /// + /// This callback function gets called by libcurl as soon as it needs to + /// read data in order to send it to the peer - like if you ask it to upload + /// or post data to the server. + /// + /// Your function must then return the actual number of bytes that it stored + /// in that memory area. Returning 0 will signal end-of-file to the library + /// and cause it to stop the current transfer. + /// + /// If you stop the current transfer by returning 0 "pre-maturely" (i.e + /// before the server expected it, like when you've said you will upload N + /// bytes and you upload less than N bytes), you may experience that the + /// server "hangs" waiting for the rest of the data that won't come. + /// + /// The read callback may return `Err(ReadError::Abort)` to stop the + /// current operation immediately, resulting in a `is_aborted_by_callback` + /// error code from the transfer. + /// + /// The callback can return `Err(ReadError::Pause)` to cause reading from + /// this connection to pause. See `unpause_read` for further details. + /// + /// By default data not input, and this corresponds to the + /// `CURLOPT_READFUNCTION` and `CURLOPT_READDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `read_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// Read input from stdin + /// + /// ```no_run + /// use std::io::{stdin, Read}; + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://example.com/login").unwrap(); + /// handle.read_function(|into| { + /// Ok(stdin().read(into).unwrap()) + /// }).unwrap(); + /// handle.post(true).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Reading from stack-local data: + /// + /// ```no_run + /// use std::io::{stdin, Read}; + /// use curl::easy::Easy; + /// + /// let mut data_to_upload = &b"foobar"[..]; + /// let mut handle = Easy::new(); + /// handle.url("https://example.com/login").unwrap(); + /// handle.post(true).unwrap(); + /// + /// let mut transfer = handle.transfer(); + /// transfer.read_function(|into| { + /// Ok(data_to_upload.read(into).unwrap()) + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// ``` + pub fn read_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&mut [u8]) -> Result + Send + 'static, + { + self.inner.get_mut().owned.read = Some(Box::new(f)); + Ok(()) + } + + /// User callback for seeking in input stream. + /// + /// This function gets called by libcurl to seek to a certain position in + /// the input stream and can be used to fast forward a file in a resumed + /// upload (instead of reading all uploaded bytes with the normal read + /// function/callback). It is also called to rewind a stream when data has + /// already been sent to the server and needs to be sent again. This may + /// happen when doing a HTTP PUT or POST with a multi-pass authentication + /// method, or when an existing HTTP connection is reused too late and the + /// server closes the connection. + /// + /// The callback function must return `SeekResult::Ok` on success, + /// `SeekResult::Fail` to cause the upload operation to fail or + /// `SeekResult::CantSeek` to indicate that while the seek failed, libcurl + /// is free to work around the problem if possible. The latter can sometimes + /// be done by instead reading from the input or similar. + /// + /// By default data this option is not set, and this corresponds to the + /// `CURLOPT_SEEKFUNCTION` and `CURLOPT_SEEKDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `seek_function` to configure a + /// callback that can reference stack-local data. + pub fn seek_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(SeekFrom) -> SeekResult + Send + 'static, + { + self.inner.get_mut().owned.seek = Some(Box::new(f)); + Ok(()) + } + + /// Callback to progress meter function + /// + /// This function gets called by libcurl instead of its internal equivalent + /// with a frequent interval. While data is being transferred it will be + /// called very frequently, and during slow periods like when nothing is + /// being transferred it can slow down to about one call per second. + /// + /// The callback gets told how much data libcurl will transfer and has + /// transferred, in number of bytes. The first argument is the total number + /// of bytes libcurl expects to download in this transfer. The second + /// argument is the number of bytes downloaded so far. The third argument is + /// the total number of bytes libcurl expects to upload in this transfer. + /// The fourth argument is the number of bytes uploaded so far. + /// + /// Unknown/unused argument values passed to the callback will be set to + /// zero (like if you only download data, the upload size will remain 0). + /// Many times the callback will be called one or more times first, before + /// it knows the data sizes so a program must be made to handle that. + /// + /// Returning `false` from this callback will cause libcurl to abort the + /// transfer and return `is_aborted_by_callback`. + /// + /// If you transfer data with the multi interface, this function will not be + /// called during periods of idleness unless you call the appropriate + /// libcurl function that performs transfers. + /// + /// `progress` must be set to `true` to make this function actually get + /// called. + /// + /// By default this function calls an internal method and corresponds to + /// `CURLOPT_PROGRESSFUNCTION` and `CURLOPT_PROGRESSDATA`. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `progress_function` to configure a + /// callback that can reference stack-local data. + pub fn progress_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(f64, f64, f64, f64) -> bool + Send + 'static, + { + self.inner.get_mut().owned.progress = Some(Box::new(f)); + Ok(()) + } + + /// Callback to SSL context + /// + /// This callback function gets called by libcurl just before the + /// initialization of an SSL connection after having processed all + /// other SSL related options to give a last chance to an + /// application to modify the behaviour of the SSL + /// initialization. The `ssl_ctx` parameter is actually a pointer + /// to the SSL library's SSL_CTX. If an error is returned from the + /// callback no attempt to establish a connection is made and the + /// perform operation will return the callback's error code. + /// + /// This function will get called on all new connections made to a + /// server, during the SSL negotiation. The SSL_CTX pointer will + /// be a new one every time. + /// + /// To use this properly, a non-trivial amount of knowledge of + /// your SSL library is necessary. For example, you can use this + /// function to call library-specific callbacks to add additional + /// validation code for certificates, and even to change the + /// actual URI of a HTTPS request. + /// + /// By default this function calls an internal method and + /// corresponds to `CURLOPT_SSL_CTX_FUNCTION` and + /// `CURLOPT_SSL_CTX_DATA`. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `progress_function` to configure a + /// callback that can reference stack-local data. + pub fn ssl_ctx_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(*mut c_void) -> Result<(), Error> + Send + 'static, + { + self.inner.get_mut().owned.ssl_ctx = Some(Box::new(f)); + Ok(()) + } + + /// Specify a debug callback + /// + /// `debug_function` replaces the standard debug function used when + /// `verbose` is in effect. This callback receives debug information, + /// as specified in the type argument. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_DEBUGFUNCTION` and `CURLOPT_DEBUGDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `debug_function` to configure a + /// callback that can reference stack-local data. + pub fn debug_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(InfoType, &[u8]) + Send + 'static, + { + self.inner.get_mut().owned.debug = Some(Box::new(f)); + Ok(()) + } + + /// Callback that receives header data + /// + /// This function gets called by libcurl as soon as it has received header + /// data. The header callback will be called once for each header and only + /// complete header lines are passed on to the callback. Parsing headers is + /// very easy using this. If this callback returns `false` it'll signal an + /// error to the library. This will cause the transfer to get aborted and + /// the libcurl function in progress will return `is_write_error`. + /// + /// A complete HTTP header that is passed to this function can be up to + /// CURL_MAX_HTTP_HEADER (100K) bytes. + /// + /// It's important to note that the callback will be invoked for the headers + /// of all responses received after initiating a request and not just the + /// final response. This includes all responses which occur during + /// authentication negotiation. If you need to operate on only the headers + /// from the final response, you will need to collect headers in the + /// callback yourself and use HTTP status lines, for example, to delimit + /// response boundaries. + /// + /// When a server sends a chunked encoded transfer, it may contain a + /// trailer. That trailer is identical to a HTTP header and if such a + /// trailer is received it is passed to the application using this callback + /// as well. There are several ways to detect it being a trailer and not an + /// ordinary header: 1) it comes after the response-body. 2) it comes after + /// the final header line (CR LF) 3) a Trailer: header among the regular + /// response-headers mention what header(s) to expect in the trailer. + /// + /// For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function will + /// get called with the server responses to the commands that libcurl sends. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_HEADERFUNCTION` and `CURLOPT_HEADERDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `header_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// ``` + /// use std::str; + /// + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.header_function(|header| { + /// print!("header: {}", str::from_utf8(header).unwrap()); + /// true + /// }).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Collecting headers to a stack local vector + /// + /// ``` + /// use std::str; + /// + /// use curl::easy::Easy; + /// + /// let mut headers = Vec::new(); + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// + /// { + /// let mut transfer = handle.transfer(); + /// transfer.header_function(|header| { + /// headers.push(str::from_utf8(header).unwrap().to_string()); + /// true + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// } + /// + /// println!("{:?}", headers); + /// ``` + pub fn header_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&[u8]) -> bool + Send + 'static, + { + self.inner.get_mut().owned.header = Some(Box::new(f)); + Ok(()) + } + + // ========================================================================= + // Error options + + // TODO: error buffer and stderr + + /// Same as [`Easy2::fail_on_error`](struct.Easy2.html#method.fail_on_error) + pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> { + self.inner.fail_on_error(fail) + } + + // ========================================================================= + // Network options + + /// Same as [`Easy2::url`](struct.Easy2.html#method.url) + pub fn url(&mut self, url: &str) -> Result<(), Error> { + self.inner.url(url) + } + + /// Same as [`Easy2::port`](struct.Easy2.html#method.port) + pub fn port(&mut self, port: u16) -> Result<(), Error> { + self.inner.port(port) + } + + /// Same as [`Easy2::proxy`](struct.Easy2.html#method.proxy) + pub fn proxy(&mut self, url: &str) -> Result<(), Error> { + self.inner.proxy(url) + } + + /// Same as [`Easy2::proxy_port`](struct.Easy2.html#method.proxy_port) + pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> { + self.inner.proxy_port(port) + } + + /// Same as [`Easy2::proxy_type`](struct.Easy2.html#method.proxy_type) + pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> { + self.inner.proxy_type(kind) + } + + /// Same as [`Easy2::noproxy`](struct.Easy2.html#method.noproxy) + pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> { + self.inner.noproxy(skip) + } + + /// Same as [`Easy2::http_proxy_tunnel`](struct.Easy2.html#method.http_proxy_tunnel) + pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> { + self.inner.http_proxy_tunnel(tunnel) + } + + /// Same as [`Easy2::interface`](struct.Easy2.html#method.interface) + pub fn interface(&mut self, interface: &str) -> Result<(), Error> { + self.inner.interface(interface) + } + + /// Same as [`Easy2::set_local_port`](struct.Easy2.html#method.set_local_port) + pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> { + self.inner.set_local_port(port) + } + + /// Same as [`Easy2::local_port_range`](struct.Easy2.html#method.local_port_range) + pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> { + self.inner.local_port_range(range) + } + + /// Same as [`Easy2::dns_servers`](struct.Easy2.html#method.dns_servers) + pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { + self.inner.dns_servers(servers) + } + + /// Same as [`Easy2::dns_cache_timeout`](struct.Easy2.html#method.dns_cache_timeout) + pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.dns_cache_timeout(dur) + } + + /// Same as [`Easy2::buffer_size`](struct.Easy2.html#method.buffer_size) + pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> { + self.inner.buffer_size(size) + } + + /// Same as [`Easy2::tcp_nodelay`](struct.Easy2.html#method.tcp_nodelay) + pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> { + self.inner.tcp_nodelay(enable) + } + + /// Same as [`Easy2::tcp_keepalive`](struct.Easy2.html#method.tcp_keepalive) + pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> { + self.inner.tcp_keepalive(enable) + } + + /// Same as [`Easy2::tcp_keepintvl`](struct.Easy2.html#method.tcp_keepalive) + pub fn tcp_keepintvl(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.tcp_keepintvl(dur) + } + + /// Same as [`Easy2::tcp_keepidle`](struct.Easy2.html#method.tcp_keepidle) + pub fn tcp_keepidle(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.tcp_keepidle(dur) + } + + /// Same as [`Easy2::address_scope`](struct.Easy2.html#method.address_scope) + pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> { + self.inner.address_scope(scope) + } + + // ========================================================================= + // Names and passwords + + /// Same as [`Easy2::username`](struct.Easy2.html#method.username) + pub fn username(&mut self, user: &str) -> Result<(), Error> { + self.inner.username(user) + } + + /// Same as [`Easy2::password`](struct.Easy2.html#method.password) + pub fn password(&mut self, pass: &str) -> Result<(), Error> { + self.inner.password(pass) + } + + /// Same as [`Easy2::http_auth`](struct.Easy2.html#method.http_auth) + pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.inner.http_auth(auth) + } + + /// Same as [`Easy2::proxy_username`](struct.Easy2.html#method.proxy_username) + pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> { + self.inner.proxy_username(user) + } + + /// Same as [`Easy2::proxy_password`](struct.Easy2.html#method.proxy_password) + pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> { + self.inner.proxy_password(pass) + } + + /// Same as [`Easy2::proxy_auth`](struct.Easy2.html#method.proxy_auth) + pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.inner.proxy_auth(auth) + } + + /// Same as [`Easy2::netrc`](struct.Easy2.html#method.netrc) + pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> { + self.inner.netrc(netrc) + } + + // ========================================================================= + // HTTP Options + + /// Same as [`Easy2::autoreferer`](struct.Easy2.html#method.autoreferer) + pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> { + self.inner.autoreferer(enable) + } + + /// Same as [`Easy2::accept_encoding`](struct.Easy2.html#method.accept_encoding) + pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> { + self.inner.accept_encoding(encoding) + } + + /// Same as [`Easy2::transfer_encoding`](struct.Easy2.html#method.transfer_encoding) + pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.transfer_encoding(enable) + } + + /// Same as [`Easy2::follow_location`](struct.Easy2.html#method.follow_location) + pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> { + self.inner.follow_location(enable) + } + + /// Same as [`Easy2::unrestricted_auth`](struct.Easy2.html#method.unrestricted_auth) + pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> { + self.inner.unrestricted_auth(enable) + } + + /// Same as [`Easy2::max_redirections`](struct.Easy2.html#method.max_redirections) + pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> { + self.inner.max_redirections(max) + } + + /// Same as [`Easy2::put`](struct.Easy2.html#method.put) + pub fn put(&mut self, enable: bool) -> Result<(), Error> { + self.inner.put(enable) + } + + /// Same as [`Easy2::post`](struct.Easy2.html#method.post) + pub fn post(&mut self, enable: bool) -> Result<(), Error> { + self.inner.post(enable) + } + + /// Same as [`Easy2::post_field_copy`](struct.Easy2.html#method.post_field_copy) + pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> { + self.inner.post_fields_copy(data) + } + + /// Same as [`Easy2::post_field_size`](struct.Easy2.html#method.post_field_size) + pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> { + self.inner.post_field_size(size) + } + + /// Same as [`Easy2::httppost`](struct.Easy2.html#method.httppost) + pub fn httppost(&mut self, form: Form) -> Result<(), Error> { + self.inner.httppost(form) + } + + /// Same as [`Easy2::referer`](struct.Easy2.html#method.referer) + pub fn referer(&mut self, referer: &str) -> Result<(), Error> { + self.inner.referer(referer) + } + + /// Same as [`Easy2::useragent`](struct.Easy2.html#method.useragent) + pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> { + self.inner.useragent(useragent) + } + + /// Same as [`Easy2::http_headers`](struct.Easy2.html#method.http_headers) + pub fn http_headers(&mut self, list: List) -> Result<(), Error> { + self.inner.http_headers(list) + } + + /// Same as [`Easy2::cookie`](struct.Easy2.html#method.cookie) + pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> { + self.inner.cookie(cookie) + } + + /// Same as [`Easy2::cookie_file`](struct.Easy2.html#method.cookie_file) + pub fn cookie_file>(&mut self, file: P) -> Result<(), Error> { + self.inner.cookie_file(file) + } + + /// Same as [`Easy2::cookie_jar`](struct.Easy2.html#method.cookie_jar) + pub fn cookie_jar>(&mut self, file: P) -> Result<(), Error> { + self.inner.cookie_jar(file) + } + + /// Same as [`Easy2::cookie_session`](struct.Easy2.html#method.cookie_session) + pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> { + self.inner.cookie_session(session) + } + + /// Same as [`Easy2::cookie_list`](struct.Easy2.html#method.cookie_list) + pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> { + self.inner.cookie_list(cookie) + } + + /// Same as [`Easy2::get`](struct.Easy2.html#method.get) + pub fn get(&mut self, enable: bool) -> Result<(), Error> { + self.inner.get(enable) + } + + /// Same as [`Easy2::ignore_content_length`](struct.Easy2.html#method.ignore_content_length) + pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> { + self.inner.ignore_content_length(ignore) + } + + /// Same as [`Easy2::http_content_decoding`](struct.Easy2.html#method.http_content_decoding) + pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.http_content_decoding(enable) + } + + /// Same as [`Easy2::http_transfer_decoding`](struct.Easy2.html#method.http_transfer_decoding) + pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.http_transfer_decoding(enable) + } + + // ========================================================================= + // Protocol Options + + /// Same as [`Easy2::range`](struct.Easy2.html#method.range) + pub fn range(&mut self, range: &str) -> Result<(), Error> { + self.inner.range(range) + } + + /// Same as [`Easy2::resume_from`](struct.Easy2.html#method.resume_from) + pub fn resume_from(&mut self, from: u64) -> Result<(), Error> { + self.inner.resume_from(from) + } + + /// Same as [`Easy2::custom_request`](struct.Easy2.html#method.custom_request) + pub fn custom_request(&mut self, request: &str) -> Result<(), Error> { + self.inner.custom_request(request) + } + + /// Same as [`Easy2::fetch_filetime`](struct.Easy2.html#method.fetch_filetime) + pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> { + self.inner.fetch_filetime(fetch) + } + + /// Same as [`Easy2::nobody`](struct.Easy2.html#method.nobody) + pub fn nobody(&mut self, enable: bool) -> Result<(), Error> { + self.inner.nobody(enable) + } + + /// Same as [`Easy2::in_filesize`](struct.Easy2.html#method.in_filesize) + pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> { + self.inner.in_filesize(size) + } + + /// Same as [`Easy2::upload`](struct.Easy2.html#method.upload) + pub fn upload(&mut self, enable: bool) -> Result<(), Error> { + self.inner.upload(enable) + } + + /// Same as [`Easy2::max_filesize`](struct.Easy2.html#method.max_filesize) + pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> { + self.inner.max_filesize(size) + } + + /// Same as [`Easy2::time_condition`](struct.Easy2.html#method.time_condition) + pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> { + self.inner.time_condition(cond) + } + + /// Same as [`Easy2::time_value`](struct.Easy2.html#method.time_value) + pub fn time_value(&mut self, val: i64) -> Result<(), Error> { + self.inner.time_value(val) + } + + // ========================================================================= + // Connection Options + + /// Same as [`Easy2::timeout`](struct.Easy2.html#method.timeout) + pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.timeout(timeout) + } + + /// Same as [`Easy2::low_speed_limit`](struct.Easy2.html#method.low_speed_limit) + pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> { + self.inner.low_speed_limit(limit) + } + + /// Same as [`Easy2::low_speed_time`](struct.Easy2.html#method.low_speed_time) + pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.low_speed_time(dur) + } + + /// Same as [`Easy2::max_send_speed`](struct.Easy2.html#method.max_send_speed) + pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> { + self.inner.max_send_speed(speed) + } + + /// Same as [`Easy2::max_recv_speed`](struct.Easy2.html#method.max_recv_speed) + pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> { + self.inner.max_recv_speed(speed) + } + + /// Same as [`Easy2::max_connects`](struct.Easy2.html#method.max_connects) + pub fn max_connects(&mut self, max: u32) -> Result<(), Error> { + self.inner.max_connects(max) + } + + /// Same as [`Easy2::fresh_connect`](struct.Easy2.html#method.fresh_connect) + pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> { + self.inner.fresh_connect(enable) + } + + /// Same as [`Easy2::forbid_reuse`](struct.Easy2.html#method.forbid_reuse) + pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> { + self.inner.forbid_reuse(enable) + } + + /// Same as [`Easy2::connect_timeout`](struct.Easy2.html#method.connect_timeout) + pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.connect_timeout(timeout) + } + + /// Same as [`Easy2::ip_resolve`](struct.Easy2.html#method.ip_resolve) + pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> { + self.inner.ip_resolve(resolve) + } + + /// Same as [`Easy2::resolve`](struct.Easy2.html#method.resolve) + pub fn resolve(&mut self, list: List) -> Result<(), Error> { + self.inner.resolve(list) + } + + /// Same as [`Easy2::connect_only`](struct.Easy2.html#method.connect_only) + pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> { + self.inner.connect_only(enable) + } + + // ========================================================================= + // SSL/Security Options + + /// Same as [`Easy2::ssl_cert`](struct.Easy2.html#method.ssl_cert) + pub fn ssl_cert>(&mut self, cert: P) -> Result<(), Error> { + self.inner.ssl_cert(cert) + } + + /// Same as [`Easy2::ssl_cert_type`](struct.Easy2.html#method.ssl_cert_type) + pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> { + self.inner.ssl_cert_type(kind) + } + + /// Same as [`Easy2::ssl_key`](struct.Easy2.html#method.ssl_key) + pub fn ssl_key>(&mut self, key: P) -> Result<(), Error> { + self.inner.ssl_key(key) + } + + /// Same as [`Easy2::ssl_key_type`](struct.Easy2.html#method.ssl_key_type) + pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> { + self.inner.ssl_key_type(kind) + } + + /// Same as [`Easy2::key_password`](struct.Easy2.html#method.key_password) + pub fn key_password(&mut self, password: &str) -> Result<(), Error> { + self.inner.key_password(password) + } + + /// Same as [`Easy2::ssl_engine`](struct.Easy2.html#method.ssl_engine) + pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> { + self.inner.ssl_engine(engine) + } + + /// Same as [`Easy2::ssl_engine_default`](struct.Easy2.html#method.ssl_engine_default) + pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> { + self.inner.ssl_engine_default(enable) + } + + /// Same as [`Easy2::http_version`](struct.Easy2.html#method.http_version) + pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> { + self.inner.http_version(version) + } + + /// Same as [`Easy2::ssl_version`](struct.Easy2.html#method.ssl_version) + pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { + self.inner.ssl_version(version) + } + + /// Same as [`Easy2::ssl_verify_host`](struct.Easy2.html#method.ssl_verify_host) + pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { + self.inner.ssl_verify_host(verify) + } + + /// Same as [`Easy2::ssl_verify_peer`](struct.Easy2.html#method.ssl_verify_peer) + pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { + self.inner.ssl_verify_peer(verify) + } + + /// Same as [`Easy2::cainfo`](struct.Easy2.html#method.cainfo) + pub fn cainfo>(&mut self, path: P) -> Result<(), Error> { + self.inner.cainfo(path) + } + + /// Same as [`Easy2::issuer_cert`](struct.Easy2.html#method.issuer_cert) + pub fn issuer_cert>(&mut self, path: P) -> Result<(), Error> { + self.inner.issuer_cert(path) + } + + /// Same as [`Easy2::capath`](struct.Easy2.html#method.capath) + pub fn capath>(&mut self, path: P) -> Result<(), Error> { + self.inner.capath(path) + } + + /// Same as [`Easy2::crlfile`](struct.Easy2.html#method.crlfile) + pub fn crlfile>(&mut self, path: P) -> Result<(), Error> { + self.inner.crlfile(path) + } + + /// Same as [`Easy2::certinfo`](struct.Easy2.html#method.certinfo) + pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> { + self.inner.certinfo(enable) + } + + /// Same as [`Easy2::random_file`](struct.Easy2.html#method.random_file) + pub fn random_file>(&mut self, p: P) -> Result<(), Error> { + self.inner.random_file(p) + } + + /// Same as [`Easy2::egd_socket`](struct.Easy2.html#method.egd_socket) + pub fn egd_socket>(&mut self, p: P) -> Result<(), Error> { + self.inner.egd_socket(p) + } + + /// Same as [`Easy2::ssl_cipher_list`](struct.Easy2.html#method.ssl_cipher_list) + pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { + self.inner.ssl_cipher_list(ciphers) + } + + /// Same as [`Easy2::ssl_sessionid_cache`](struct.Easy2.html#method.ssl_sessionid_cache) + pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> { + self.inner.ssl_sessionid_cache(enable) + } + + /// Same as [`Easy2::ssl_options`](struct.Easy2.html#method.ssl_options) + pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + self.inner.ssl_options(bits) + } + + // ========================================================================= + // getters + + /// Same as [`Easy2::time_condition_unmet`](struct.Easy2.html#method.time_condition_unmet) + pub fn time_condition_unmet(&mut self) -> Result { + self.inner.time_condition_unmet() + } + + /// Same as [`Easy2::effective_url`](struct.Easy2.html#method.effective_url) + pub fn effective_url(&mut self) -> Result, Error> { + self.inner.effective_url() + } + + /// Same as [`Easy2::effective_url_bytes`](struct.Easy2.html#method.effective_url_bytes) + pub fn effective_url_bytes(&mut self) -> Result, Error> { + self.inner.effective_url_bytes() + } + + /// Same as [`Easy2::response_code`](struct.Easy2.html#method.response_code) + pub fn response_code(&mut self) -> Result { + self.inner.response_code() + } + + /// Same as [`Easy2::http_connectcode`](struct.Easy2.html#method.http_connectcode) + pub fn http_connectcode(&mut self) -> Result { + self.inner.http_connectcode() + } + + /// Same as [`Easy2::filetime`](struct.Easy2.html#method.filetime) + pub fn filetime(&mut self) -> Result, Error> { + self.inner.filetime() + } + + /// Same as [`Easy2::download_size`](struct.Easy2.html#method.download_size) + pub fn download_size(&mut self) -> Result { + self.inner.download_size() + } + /// Same as [`Easy2::content_length_download`](struct.Easy2.html#method.content_length_download) + pub fn content_length_download(&mut self) -> Result { + self.inner.content_length_download() + } + + /// Same as [`Easy2::total_time`](struct.Easy2.html#method.total_time) + pub fn total_time(&mut self) -> Result { + self.inner.total_time() + } + + /// Same as [`Easy2::namelookup_time`](struct.Easy2.html#method.namelookup_time) + pub fn namelookup_time(&mut self) -> Result { + self.inner.namelookup_time() + } + + /// Same as [`Easy2::connect_time`](struct.Easy2.html#method.connect_time) + pub fn connect_time(&mut self) -> Result { + self.inner.connect_time() + } + + /// Same as [`Easy2::appconnect_time`](struct.Easy2.html#method.appconnect_time) + pub fn appconnect_time(&mut self) -> Result { + self.inner.appconnect_time() + } + + /// Same as [`Easy2::pretransfer_time`](struct.Easy2.html#method.pretransfer_time) + pub fn pretransfer_time(&mut self) -> Result { + self.inner.pretransfer_time() + } + + /// Same as [`Easy2::starttransfer_time`](struct.Easy2.html#method.starttransfer_time) + pub fn starttransfer_time(&mut self) -> Result { + self.inner.starttransfer_time() + } + + /// Same as [`Easy2::redirect_time`](struct.Easy2.html#method.redirect_time) + pub fn redirect_time(&mut self) -> Result { + self.inner.redirect_time() + } + + /// Same as [`Easy2::redirect_count`](struct.Easy2.html#method.redirect_count) + pub fn redirect_count(&mut self) -> Result { + self.inner.redirect_count() + } + + /// Same as [`Easy2::redirect_url`](struct.Easy2.html#method.redirect_url) + pub fn redirect_url(&mut self) -> Result, Error> { + self.inner.redirect_url() + } + + /// Same as [`Easy2::redirect_url_bytes`](struct.Easy2.html#method.redirect_url_bytes) + pub fn redirect_url_bytes(&mut self) -> Result, Error> { + self.inner.redirect_url_bytes() + } + + /// Same as [`Easy2::header_size`](struct.Easy2.html#method.header_size) + pub fn header_size(&mut self) -> Result { + self.inner.header_size() + } + + /// Same as [`Easy2::request_size`](struct.Easy2.html#method.request_size) + pub fn request_size(&mut self) -> Result { + self.inner.request_size() + } + + /// Same as [`Easy2::content_type`](struct.Easy2.html#method.content_type) + pub fn content_type(&mut self) -> Result, Error> { + self.inner.content_type() + } + + /// Same as [`Easy2::content_type_bytes`](struct.Easy2.html#method.content_type_bytes) + pub fn content_type_bytes(&mut self) -> Result, Error> { + self.inner.content_type_bytes() + } + + /// Same as [`Easy2::os_errno`](struct.Easy2.html#method.os_errno) + pub fn os_errno(&mut self) -> Result { + self.inner.os_errno() + } + + /// Same as [`Easy2::primary_ip`](struct.Easy2.html#method.primary_ip) + pub fn primary_ip(&mut self) -> Result, Error> { + self.inner.primary_ip() + } + + /// Same as [`Easy2::primary_port`](struct.Easy2.html#method.primary_port) + pub fn primary_port(&mut self) -> Result { + self.inner.primary_port() + } + + /// Same as [`Easy2::local_ip`](struct.Easy2.html#method.local_ip) + pub fn local_ip(&mut self) -> Result, Error> { + self.inner.local_ip() + } + + /// Same as [`Easy2::local_port`](struct.Easy2.html#method.local_port) + pub fn local_port(&mut self) -> Result { + self.inner.local_port() + } + + /// Same as [`Easy2::cookies`](struct.Easy2.html#method.cookies) + pub fn cookies(&mut self) -> Result { + self.inner.cookies() + } + + /// Same as [`Easy2::pipewait`](struct.Easy2.html#method.pipewait) + pub fn pipewait(&mut self, wait: bool) -> Result<(), Error> { + self.inner.pipewait(wait) + } + + // ========================================================================= + // Other methods + + /// Same as [`Easy2::perform`](struct.Easy2.html#method.perform) + pub fn perform(&self) -> Result<(), Error> { + assert!(self.inner.get_ref().borrowed.get().is_null()); + self.do_perform() + } + + fn do_perform(&self) -> Result<(), Error> { + // We don't allow recursive invocations of `perform` because we're + // invoking `FnMut`closures behind a `&self` pointer. This flag acts as + // our own `RefCell` borrow flag sorta. + if self.inner.get_ref().running.get() { + return Err(Error::new(curl_sys::CURLE_FAILED_INIT)); + } + + self.inner.get_ref().running.set(true); + struct Reset<'a>(&'a Cell); + impl<'a> Drop for Reset<'a> { + fn drop(&mut self) { + self.0.set(false); + } + } + let _reset = Reset(&self.inner.get_ref().running); + + self.inner.perform() + } + + /// Creates a new scoped transfer which can be used to set callbacks and + /// data which only live for the scope of the returned object. + /// + /// An `Easy` handle is often reused between different requests to cache + /// connections to servers, but often the lifetime of the data as part of + /// each transfer is unique. This function serves as an ability to share an + /// `Easy` across many transfers while ergonomically using possibly + /// stack-local data as part of each transfer. + /// + /// Configuration can be set on the `Easy` and then a `Transfer` can be + /// created to set scoped configuration (like callbacks). Finally, the + /// `perform` method on the `Transfer` function can be used. + /// + /// When the `Transfer` option is dropped then all configuration set on the + /// transfer itself will be reset. + pub fn transfer<'data, 'easy>(&'easy mut self) -> Transfer<'easy, 'data> { + assert!(!self.inner.get_ref().running.get()); + Transfer { + data: Box::new(Callbacks::default()), + easy: self, + } + } + + /// Same as [`Easy2::unpause_read`](struct.Easy2.html#method.unpause_read) + pub fn unpause_read(&self) -> Result<(), Error> { + self.inner.unpause_read() + } + + /// Same as [`Easy2::unpause_write`](struct.Easy2.html#method.unpause_write) + pub fn unpause_write(&self) -> Result<(), Error> { + self.inner.unpause_write() + } + + /// Same as [`Easy2::url_encode`](struct.Easy2.html#method.url_encode) + pub fn url_encode(&mut self, s: &[u8]) -> String { + self.inner.url_encode(s) + } + + /// Same as [`Easy2::url_decode`](struct.Easy2.html#method.url_decode) + pub fn url_decode(&mut self, s: &str) -> Vec { + self.inner.url_decode(s) + } + + /// Same as [`Easy2::reset`](struct.Easy2.html#method.reset) + pub fn reset(&mut self) { + self.inner.reset() + } + + /// Same as [`Easy2::recv`](struct.Easy2.html#method.recv) + pub fn recv(&mut self, data: &mut [u8]) -> Result { + self.inner.recv(data) + } + + /// Same as [`Easy2::send`](struct.Easy2.html#method.send) + pub fn send(&mut self, data: &[u8]) -> Result { + self.inner.send(data) + } + + /// Same as [`Easy2::raw`](struct.Easy2.html#method.raw) + pub fn raw(&self) -> *mut curl_sys::CURL { + self.inner.raw() + } + + /// Same as [`Easy2::take_error_buf`](struct.Easy2.html#method.take_error_buf) + pub fn take_error_buf(&self) -> Option { + self.inner.take_error_buf() + } +} + +impl EasyData { + /// An unsafe function to get the appropriate callback field. + /// + /// We can have callbacks configured from one of two different sources. + /// We could either have a callback from the `borrowed` field, callbacks on + /// an ephemeral `Transfer`, or the `owned` field which are `'static` + /// callbacks that live for the lifetime of this `EasyData`. + /// + /// The first set of callbacks are unsafe to access because they're actually + /// owned elsewhere and we're just aliasing. Additionally they don't + /// technically live long enough for us to access them, so they're hidden + /// behind unsafe pointers and casts. + /// + /// This function returns `&'a mut T` but that's actually somewhat of a lie. + /// The value should **not be stored to** nor should it be used for the full + /// lifetime of `'a`, but rather immediately in the local scope. + /// + /// Basically this is just intended to acquire a callback, invoke it, and + /// then stop. Nothing else. Super unsafe. + unsafe fn callback<'a, T, F>(&'a mut self, f: F) -> Option<&'a mut T> + where + F: for<'b> Fn(&'b mut Callbacks<'static>) -> &'b mut Option, + { + let ptr = self.borrowed.get(); + if !ptr.is_null() { + let val = f(&mut *ptr); + if val.is_some() { + return val.as_mut(); + } + } + f(&mut self.owned).as_mut() + } +} + +impl Handler for EasyData { + fn write(&mut self, data: &[u8]) -> Result { + unsafe { + match self.callback(|s| &mut s.write) { + Some(write) => write(data), + None => Ok(data.len()), + } + } + } + + fn read(&mut self, data: &mut [u8]) -> Result { + unsafe { + match self.callback(|s| &mut s.read) { + Some(read) => read(data), + None => Ok(0), + } + } + } + + fn seek(&mut self, whence: SeekFrom) -> SeekResult { + unsafe { + match self.callback(|s| &mut s.seek) { + Some(seek) => seek(whence), + None => SeekResult::CantSeek, + } + } + } + + fn debug(&mut self, kind: InfoType, data: &[u8]) { + unsafe { + match self.callback(|s| &mut s.debug) { + Some(debug) => debug(kind, data), + None => handler::debug(kind, data), + } + } + } + + fn header(&mut self, data: &[u8]) -> bool { + unsafe { + match self.callback(|s| &mut s.header) { + Some(header) => header(data), + None => true, + } + } + } + + fn progress(&mut self, dltotal: f64, dlnow: f64, ultotal: f64, ulnow: f64) -> bool { + unsafe { + match self.callback(|s| &mut s.progress) { + Some(progress) => progress(dltotal, dlnow, ultotal, ulnow), + None => true, + } + } + } + + fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> { + unsafe { + match self.callback(|s| &mut s.ssl_ctx) { + Some(ssl_ctx) => ssl_ctx(cx), + None => handler::ssl_ctx(cx), + } + } + } +} + +impl fmt::Debug for EasyData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "callbacks ...".fmt(f) + } +} + +impl<'easy, 'data> Transfer<'easy, 'data> { + /// Same as `Easy::write_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn write_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&[u8]) -> Result + 'data, + { + self.data.write = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::read_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn read_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&mut [u8]) -> Result + 'data, + { + self.data.read = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::seek_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn seek_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(SeekFrom) -> SeekResult + 'data, + { + self.data.seek = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::progress_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn progress_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(f64, f64, f64, f64) -> bool + 'data, + { + self.data.progress = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::ssl_ctx_function`, just takes a non `'static` + /// lifetime corresponding to the lifetime of this transfer. + pub fn ssl_ctx_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(*mut c_void) -> Result<(), Error> + Send + 'data, + { + self.data.ssl_ctx = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::debug_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn debug_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(InfoType, &[u8]) + 'data, + { + self.data.debug = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::header_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn header_function(&mut self, f: F) -> Result<(), Error> + where + F: FnMut(&[u8]) -> bool + 'data, + { + self.data.header = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::perform`. + pub fn perform(&self) -> Result<(), Error> { + let inner = self.easy.inner.get_ref(); + + // Note that we're casting a `&self` pointer to a `*mut`, and then + // during the invocation of this call we're going to invoke `FnMut` + // closures that we ourselves own. + // + // This should be ok, however, because `do_perform` checks for recursive + // invocations of `perform` and disallows them. Our type also isn't + // `Sync`. + inner.borrowed.set(&*self.data as *const _ as *mut _); + + // Make sure to reset everything back to the way it was before when + // we're done. + struct Reset<'a>(&'a Cell<*mut Callbacks<'static>>); + impl<'a> Drop for Reset<'a> { + fn drop(&mut self) { + self.0.set(ptr::null_mut()); + } + } + let _reset = Reset(&inner.borrowed); + + self.easy.do_perform() + } + + /// Same as `Easy::unpause_read`. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Same as `Easy::unpause_write` + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl<'easy, 'data> fmt::Debug for Transfer<'easy, 'data> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Transfer") + .field("easy", &self.easy) + .finish() + } +} + +impl<'easy, 'data> Drop for Transfer<'easy, 'data> { + fn drop(&mut self) { + // Extra double check to make sure we don't leak a pointer to ourselves. + assert!(self.easy.inner.get_ref().borrowed.get().is_null()); + } +} diff --git a/curl/src/easy/handler.rs b/curl/src/easy/handler.rs new file mode 100644 index 000000000..22cec75da --- /dev/null +++ b/curl/src/easy/handler.rs @@ -0,0 +1,3265 @@ +use std::cell::RefCell; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::io::{self, SeekFrom, Write}; +use std::path::Path; +use std::slice; +use std::str; +use std::time::Duration; + +use curl_sys; +use libc::{self, c_char, c_double, c_int, c_long, c_ulong, c_void, size_t}; +use socket2::Socket; + +use easy::form; +use easy::list; +use easy::windows; +use easy::{Form, List}; +use panic; +use Error; + +/// A trait for the various callbacks used by libcurl to invoke user code. +/// +/// This trait represents all operations that libcurl can possibly invoke a +/// client for code during an HTTP transaction. Each callback has a default +/// "noop" implementation, the same as in libcurl. Types implementing this trait +/// may simply override the relevant functions to learn about the callbacks +/// they're interested in. +/// +/// # Examples +/// +/// ``` +/// use curl::easy::{Easy2, Handler, WriteError}; +/// +/// struct Collector(Vec); +/// +/// impl Handler for Collector { +/// fn write(&mut self, data: &[u8]) -> Result { +/// self.0.extend_from_slice(data); +/// Ok(data.len()) +/// } +/// } +/// +/// let mut easy = Easy2::new(Collector(Vec::new())); +/// easy.get(true).unwrap(); +/// easy.url("https://www.rust-lang.org/").unwrap(); +/// easy.perform().unwrap(); +/// +/// assert_eq!(easy.response_code().unwrap(), 200); +/// let contents = easy.get_ref(); +/// println!("{}", String::from_utf8_lossy(&contents.0)); +/// ``` +pub trait Handler { + /// Callback invoked whenever curl has downloaded data for the application. + /// + /// This callback function gets called by libcurl as soon as there is data + /// received that needs to be saved. + /// + /// The callback function will be passed as much data as possible in all + /// invokes, but you must not make any assumptions. It may be one byte, it + /// may be thousands. If `show_header` is enabled, which makes header data + /// get passed to the write callback, you can get up to + /// `CURL_MAX_HTTP_HEADER` bytes of header data passed into it. This + /// usually means 100K. + /// + /// This function may be called with zero bytes data if the transferred file + /// is empty. + /// + /// The callback should return the number of bytes actually taken care of. + /// If that amount differs from the amount passed to your callback function, + /// it'll signal an error condition to the library. This will cause the + /// transfer to get aborted and the libcurl function used will return + /// an error with `is_write_error`. + /// + /// If your callback function returns `Err(WriteError::Pause)` it will cause + /// this transfer to become paused. See `unpause_write` for further details. + /// + /// By default data is sent into the void, and this corresponds to the + /// `CURLOPT_WRITEFUNCTION` and `CURLOPT_WRITEDATA` options. + fn write(&mut self, data: &[u8]) -> Result { + Ok(data.len()) + } + + /// Read callback for data uploads. + /// + /// This callback function gets called by libcurl as soon as it needs to + /// read data in order to send it to the peer - like if you ask it to upload + /// or post data to the server. + /// + /// Your function must then return the actual number of bytes that it stored + /// in that memory area. Returning 0 will signal end-of-file to the library + /// and cause it to stop the current transfer. + /// + /// If you stop the current transfer by returning 0 "pre-maturely" (i.e + /// before the server expected it, like when you've said you will upload N + /// bytes and you upload less than N bytes), you may experience that the + /// server "hangs" waiting for the rest of the data that won't come. + /// + /// The read callback may return `Err(ReadError::Abort)` to stop the + /// current operation immediately, resulting in a `is_aborted_by_callback` + /// error code from the transfer. + /// + /// The callback can return `Err(ReadError::Pause)` to cause reading from + /// this connection to pause. See `unpause_read` for further details. + /// + /// By default data not input, and this corresponds to the + /// `CURLOPT_READFUNCTION` and `CURLOPT_READDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `read_function` to configure a + /// callback that can reference stack-local data. + fn read(&mut self, data: &mut [u8]) -> Result { + drop(data); + Ok(0) + } + + /// User callback for seeking in input stream. + /// + /// This function gets called by libcurl to seek to a certain position in + /// the input stream and can be used to fast forward a file in a resumed + /// upload (instead of reading all uploaded bytes with the normal read + /// function/callback). It is also called to rewind a stream when data has + /// already been sent to the server and needs to be sent again. This may + /// happen when doing a HTTP PUT or POST with a multi-pass authentication + /// method, or when an existing HTTP connection is reused too late and the + /// server closes the connection. + /// + /// The callback function must return `SeekResult::Ok` on success, + /// `SeekResult::Fail` to cause the upload operation to fail or + /// `SeekResult::CantSeek` to indicate that while the seek failed, libcurl + /// is free to work around the problem if possible. The latter can sometimes + /// be done by instead reading from the input or similar. + /// + /// By default data this option is not set, and this corresponds to the + /// `CURLOPT_SEEKFUNCTION` and `CURLOPT_SEEKDATA` options. + fn seek(&mut self, whence: SeekFrom) -> SeekResult { + drop(whence); + SeekResult::CantSeek + } + + /// Specify a debug callback + /// + /// `debug_function` replaces the standard debug function used when + /// `verbose` is in effect. This callback receives debug information, + /// as specified in the type argument. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_DEBUGFUNCTION` and `CURLOPT_DEBUGDATA` options. + fn debug(&mut self, kind: InfoType, data: &[u8]) { + debug(kind, data) + } + + /// Callback that receives header data + /// + /// This function gets called by libcurl as soon as it has received header + /// data. The header callback will be called once for each header and only + /// complete header lines are passed on to the callback. Parsing headers is + /// very easy using this. If this callback returns `false` it'll signal an + /// error to the library. This will cause the transfer to get aborted and + /// the libcurl function in progress will return `is_write_error`. + /// + /// A complete HTTP header that is passed to this function can be up to + /// CURL_MAX_HTTP_HEADER (100K) bytes. + /// + /// It's important to note that the callback will be invoked for the headers + /// of all responses received after initiating a request and not just the + /// final response. This includes all responses which occur during + /// authentication negotiation. If you need to operate on only the headers + /// from the final response, you will need to collect headers in the + /// callback yourself and use HTTP status lines, for example, to delimit + /// response boundaries. + /// + /// When a server sends a chunked encoded transfer, it may contain a + /// trailer. That trailer is identical to a HTTP header and if such a + /// trailer is received it is passed to the application using this callback + /// as well. There are several ways to detect it being a trailer and not an + /// ordinary header: 1) it comes after the response-body. 2) it comes after + /// the final header line (CR LF) 3) a Trailer: header among the regular + /// response-headers mention what header(s) to expect in the trailer. + /// + /// For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function will + /// get called with the server responses to the commands that libcurl sends. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_HEADERFUNCTION` and `CURLOPT_HEADERDATA` options. + fn header(&mut self, data: &[u8]) -> bool { + drop(data); + true + } + + /// Callback to progress meter function + /// + /// This function gets called by libcurl instead of its internal equivalent + /// with a frequent interval. While data is being transferred it will be + /// called very frequently, and during slow periods like when nothing is + /// being transferred it can slow down to about one call per second. + /// + /// The callback gets told how much data libcurl will transfer and has + /// transferred, in number of bytes. The first argument is the total number + /// of bytes libcurl expects to download in this transfer. The second + /// argument is the number of bytes downloaded so far. The third argument is + /// the total number of bytes libcurl expects to upload in this transfer. + /// The fourth argument is the number of bytes uploaded so far. + /// + /// Unknown/unused argument values passed to the callback will be set to + /// zero (like if you only download data, the upload size will remain 0). + /// Many times the callback will be called one or more times first, before + /// it knows the data sizes so a program must be made to handle that. + /// + /// Returning `false` from this callback will cause libcurl to abort the + /// transfer and return `is_aborted_by_callback`. + /// + /// If you transfer data with the multi interface, this function will not be + /// called during periods of idleness unless you call the appropriate + /// libcurl function that performs transfers. + /// + /// `progress` must be set to `true` to make this function actually get + /// called. + /// + /// By default this function calls an internal method and corresponds to + /// `CURLOPT_PROGRESSFUNCTION` and `CURLOPT_PROGRESSDATA`. + fn progress(&mut self, dltotal: f64, dlnow: f64, ultotal: f64, ulnow: f64) -> bool { + drop((dltotal, dlnow, ultotal, ulnow)); + true + } + + /// Callback to SSL context + /// + /// This callback function gets called by libcurl just before the + /// initialization of an SSL connection after having processed all + /// other SSL related options to give a last chance to an + /// application to modify the behaviour of the SSL + /// initialization. The `ssl_ctx` parameter is actually a pointer + /// to the SSL library's SSL_CTX. If an error is returned from the + /// callback no attempt to establish a connection is made and the + /// perform operation will return the callback's error code. + /// + /// This function will get called on all new connections made to a + /// server, during the SSL negotiation. The SSL_CTX pointer will + /// be a new one every time. + /// + /// To use this properly, a non-trivial amount of knowledge of + /// your SSL library is necessary. For example, you can use this + /// function to call library-specific callbacks to add additional + /// validation code for certificates, and even to change the + /// actual URI of a HTTPS request. + /// + /// By default this function calls an internal method and + /// corresponds to `CURLOPT_SSL_CTX_FUNCTION` and + /// `CURLOPT_SSL_CTX_DATA`. + /// + /// Note that this callback is not guaranteed to be called, not all versions + /// of libcurl support calling this callback. + fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> { + // By default, if we're on an OpenSSL enabled libcurl and we're on + // Windows, add the system's certificate store to OpenSSL's certificate + // store. + ssl_ctx(cx) + } + + /// Callback to open sockets for libcurl. + /// + /// This callback function gets called by libcurl instead of the socket(2) + /// call. The callback function should return the newly created socket + /// or `None` in case no connection could be established or another + /// error was detected. Any additional `setsockopt(2)` calls can of course + /// be done on the socket at the user's discretion. A `None` return + /// value from the callback function will signal an unrecoverable error to + /// libcurl and it will return `is_couldnt_connect` from the function that + /// triggered this callback. + /// + /// By default this function opens a standard socket and + /// corresponds to `CURLOPT_OPENSOCKETFUNCTION `. + fn open_socket( + &mut self, + family: c_int, + socktype: c_int, + protocol: c_int, + ) -> Option { + // Note that we override this to calling a function in `socket2` to + // ensure that we open all sockets with CLOEXEC. Otherwise if we rely on + // libcurl to open sockets it won't use CLOEXEC. + return Socket::new(family.into(), socktype.into(), Some(protocol.into())) + .ok() + .map(cvt); + + #[cfg(unix)] + fn cvt(socket: Socket) -> curl_sys::curl_socket_t { + use std::os::unix::prelude::*; + socket.into_raw_fd() + } + + #[cfg(windows)] + fn cvt(socket: Socket) -> curl_sys::curl_socket_t { + use std::os::windows::prelude::*; + socket.into_raw_socket() + } + } +} + +pub fn debug(kind: InfoType, data: &[u8]) { + let out = io::stderr(); + let prefix = match kind { + InfoType::Text => "*", + InfoType::HeaderIn => "<", + InfoType::HeaderOut => ">", + InfoType::DataIn | InfoType::SslDataIn => "{", + InfoType::DataOut | InfoType::SslDataOut => "}", + InfoType::__Nonexhaustive => " ", + }; + let mut out = out.lock(); + drop(write!(out, "{} ", prefix)); + match str::from_utf8(data) { + Ok(s) => drop(out.write_all(s.as_bytes())), + Err(_) => drop(write!(out, "({} bytes of data)\n", data.len())), + } +} + +pub fn ssl_ctx(cx: *mut c_void) -> Result<(), Error> { + windows::add_certs_to_context(cx); + Ok(()) +} + +/// Raw bindings to a libcurl "easy session". +/// +/// This type corresponds to the `CURL` type in libcurl, and is probably what +/// you want for just sending off a simple HTTP request and fetching a response. +/// Each easy handle can be thought of as a large builder before calling the +/// final `perform` function. +/// +/// There are many many configuration options for each `Easy2` handle, and they +/// should all have their own documentation indicating what it affects and how +/// it interacts with other options. Some implementations of libcurl can use +/// this handle to interact with many different protocols, although by default +/// this crate only guarantees the HTTP/HTTPS protocols working. +/// +/// Note that almost all methods on this structure which configure various +/// properties return a `Result`. This is largely used to detect whether the +/// underlying implementation of libcurl actually implements the option being +/// requested. If you're linked to a version of libcurl which doesn't support +/// the option, then an error will be returned. Some options also perform some +/// validation when they're set, and the error is returned through this vector. +/// +/// Note that historically this library contained an `Easy` handle so this one's +/// called `Easy2`. The major difference between the `Easy` type is that an +/// `Easy2` structure uses a trait instead of closures for all of the callbacks +/// that curl can invoke. The `Easy` type is actually built on top of this +/// `Easy` type, and this `Easy2` type can be more flexible in some situations +/// due to the generic parameter. +/// +/// There's not necessarily a right answer for which type is correct to use, but +/// as a general rule of thumb `Easy` is typically a reasonable choice for +/// synchronous I/O and `Easy2` is a good choice for asynchronous I/O. +/// +/// # Examples +/// +/// ``` +/// use curl::easy::{Easy2, Handler, WriteError}; +/// +/// struct Collector(Vec); +/// +/// impl Handler for Collector { +/// fn write(&mut self, data: &[u8]) -> Result { +/// self.0.extend_from_slice(data); +/// Ok(data.len()) +/// } +/// } +/// +/// let mut easy = Easy2::new(Collector(Vec::new())); +/// easy.get(true).unwrap(); +/// easy.url("https://www.rust-lang.org/").unwrap(); +/// easy.perform().unwrap(); +/// +/// assert_eq!(easy.response_code().unwrap(), 200); +/// let contents = easy.get_ref(); +/// println!("{}", String::from_utf8_lossy(&contents.0)); +/// ``` +pub struct Easy2 { + inner: Box>, +} + +struct Inner { + handle: *mut curl_sys::CURL, + header_list: Option, + resolve_list: Option, + form: Option

, + error_buf: RefCell>, + handler: H, +} + +unsafe impl Send for Inner {} + +/// Possible proxy types that libcurl currently understands. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum ProxyType { + Http = curl_sys::CURLPROXY_HTTP as isize, + Http1 = curl_sys::CURLPROXY_HTTP_1_0 as isize, + Socks4 = curl_sys::CURLPROXY_SOCKS4 as isize, + Socks5 = curl_sys::CURLPROXY_SOCKS5 as isize, + Socks4a = curl_sys::CURLPROXY_SOCKS4A as isize, + Socks5Hostname = curl_sys::CURLPROXY_SOCKS5_HOSTNAME as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible conditions for the `time_condition` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum TimeCondition { + None = curl_sys::CURL_TIMECOND_NONE as isize, + IfModifiedSince = curl_sys::CURL_TIMECOND_IFMODSINCE as isize, + IfUnmodifiedSince = curl_sys::CURL_TIMECOND_IFUNMODSINCE as isize, + LastModified = curl_sys::CURL_TIMECOND_LASTMOD as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible values to pass to the `ip_resolve` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum IpResolve { + V4 = curl_sys::CURL_IPRESOLVE_V4 as isize, + V6 = curl_sys::CURL_IPRESOLVE_V6 as isize, + Any = curl_sys::CURL_IPRESOLVE_WHATEVER as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible values to pass to the `http_version` method. +#[derive(Debug)] +pub enum HttpVersion { + /// We don't care what http version to use, and we'd like the library to + /// choose the best possible for us. + Any = curl_sys::CURL_HTTP_VERSION_NONE as isize, + + /// Please use HTTP 1.0 in the request + V10 = curl_sys::CURL_HTTP_VERSION_1_0 as isize, + + /// Please use HTTP 1.1 in the request + V11 = curl_sys::CURL_HTTP_VERSION_1_1 as isize, + + /// Please use HTTP 2 in the request + /// (Added in CURL 7.33.0) + V2 = curl_sys::CURL_HTTP_VERSION_2_0 as isize, + + /// Use version 2 for HTTPS, version 1.1 for HTTP + /// (Added in CURL 7.47.0) + V2TLS = curl_sys::CURL_HTTP_VERSION_2TLS as isize, + + /// Please use HTTP 2 without HTTP/1.1 Upgrade + /// (Added in CURL 7.49.0) + V2PriorKnowledge = curl_sys::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible values to pass to the `ip_resolve` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum SslVersion { + Default = curl_sys::CURL_SSLVERSION_DEFAULT as isize, + Tlsv1 = curl_sys::CURL_SSLVERSION_TLSv1 as isize, + Sslv2 = curl_sys::CURL_SSLVERSION_SSLv2 as isize, + Sslv3 = curl_sys::CURL_SSLVERSION_SSLv3 as isize, + Tlsv10 = curl_sys::CURL_SSLVERSION_TLSv1_0 as isize, + Tlsv11 = curl_sys::CURL_SSLVERSION_TLSv1_1 as isize, + Tlsv12 = curl_sys::CURL_SSLVERSION_TLSv1_2 as isize, + Tlsv13 = curl_sys::CURL_SSLVERSION_TLSv1_3 as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible return values from the `seek_function` callback. +#[derive(Debug)] +pub enum SeekResult { + /// Indicates that the seek operation was a success + Ok = curl_sys::CURL_SEEKFUNC_OK as isize, + + /// Indicates that the seek operation failed, and the entire request should + /// fail as a result. + Fail = curl_sys::CURL_SEEKFUNC_FAIL as isize, + + /// Indicates that although the seek failed libcurl should attempt to keep + /// working if possible (for example "seek" through reading). + CantSeek = curl_sys::CURL_SEEKFUNC_CANTSEEK as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible data chunks that can be witnessed as part of the `debug_function` +/// callback. +#[derive(Debug)] +pub enum InfoType { + /// The data is informational text. + Text, + + /// The data is header (or header-like) data received from the peer. + HeaderIn, + + /// The data is header (or header-like) data sent to the peer. + HeaderOut, + + /// The data is protocol data received from the peer. + DataIn, + + /// The data is protocol data sent to the peer. + DataOut, + + /// The data is SSL/TLS (binary) data received from the peer. + SslDataIn, + + /// The data is SSL/TLS (binary) data sent to the peer. + SslDataOut, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible error codes that can be returned from the `read_function` callback. +#[derive(Debug)] +pub enum ReadError { + /// Indicates that the connection should be aborted immediately + Abort, + + /// Indicates that reading should be paused until `unpause` is called. + Pause, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible error codes that can be returned from the `write_function` callback. +#[derive(Debug)] +pub enum WriteError { + /// Indicates that reading should be paused until `unpause` is called. + Pause, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Options for `.netrc` parsing. +#[derive(Debug)] +pub enum NetRc { + /// Ignoring `.netrc` file and use information from url + /// + /// This option is default + Ignored = curl_sys::CURL_NETRC_IGNORED as isize, + + /// The use of your `~/.netrc` file is optional, and information in the URL is to be + /// preferred. The file will be scanned for the host and user name (to find the password only) + /// or for the host only, to find the first user name and password after that machine, which + /// ever information is not specified in the URL. + Optional = curl_sys::CURL_NETRC_OPTIONAL as isize, + + /// This value tells the library that use of the file is required, to ignore the information in + /// the URL, and to search the file for the host only. + Required = curl_sys::CURL_NETRC_REQUIRED as isize, +} + +/// Structure which stores possible authentication methods to get passed to +/// `http_auth` and `proxy_auth`. +#[derive(Clone)] +pub struct Auth { + bits: c_long, +} + +/// Structure which stores possible ssl options to pass to `ssl_options`. +#[derive(Clone)] +pub struct SslOpt { + bits: c_long, +} + +impl Easy2 { + /// Creates a new "easy" handle which is the core of almost all operations + /// in libcurl. + /// + /// To use a handle, applications typically configure a number of options + /// followed by a call to `perform`. Options are preserved across calls to + /// `perform` and need to be reset manually (or via the `reset` method) if + /// this is not desired. + pub fn new(handler: H) -> Easy2 { + ::init(); + unsafe { + let handle = curl_sys::curl_easy_init(); + assert!(!handle.is_null()); + let mut ret = Easy2 { + inner: Box::new(Inner { + handle: handle, + header_list: None, + resolve_list: None, + form: None, + error_buf: RefCell::new(vec![0; curl_sys::CURL_ERROR_SIZE]), + handler: handler, + }), + }; + ret.default_configure(); + return ret; + } + } + + /// Re-initializes this handle to the default values. + /// + /// This puts the handle to the same state as it was in when it was just + /// created. This does, however, keep live connections, the session id + /// cache, the dns cache, and cookies. + pub fn reset(&mut self) { + unsafe { + curl_sys::curl_easy_reset(self.inner.handle); + } + self.default_configure(); + } + + fn default_configure(&mut self) { + self.setopt_ptr( + curl_sys::CURLOPT_ERRORBUFFER, + self.inner.error_buf.borrow().as_ptr() as *const _, + ) + .expect("failed to set error buffer"); + let _ = self.signal(false); + self.ssl_configure(); + + let ptr = &*self.inner as *const _ as *const _; + + let cb: extern "C" fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t = header_cb::; + self.setopt_ptr(curl_sys::CURLOPT_HEADERFUNCTION, cb as *const _) + .expect("failed to set header callback"); + self.setopt_ptr(curl_sys::CURLOPT_HEADERDATA, ptr) + .expect("failed to set header callback"); + + let cb: curl_sys::curl_write_callback = write_cb::; + self.setopt_ptr(curl_sys::CURLOPT_WRITEFUNCTION, cb as *const _) + .expect("failed to set write callback"); + self.setopt_ptr(curl_sys::CURLOPT_WRITEDATA, ptr) + .expect("failed to set write callback"); + + let cb: curl_sys::curl_read_callback = read_cb::; + self.setopt_ptr(curl_sys::CURLOPT_READFUNCTION, cb as *const _) + .expect("failed to set read callback"); + self.setopt_ptr(curl_sys::CURLOPT_READDATA, ptr) + .expect("failed to set read callback"); + + let cb: curl_sys::curl_seek_callback = seek_cb::; + self.setopt_ptr(curl_sys::CURLOPT_SEEKFUNCTION, cb as *const _) + .expect("failed to set seek callback"); + self.setopt_ptr(curl_sys::CURLOPT_SEEKDATA, ptr) + .expect("failed to set seek callback"); + + let cb: curl_sys::curl_progress_callback = progress_cb::; + self.setopt_ptr(curl_sys::CURLOPT_PROGRESSFUNCTION, cb as *const _) + .expect("failed to set progress callback"); + self.setopt_ptr(curl_sys::CURLOPT_PROGRESSDATA, ptr) + .expect("failed to set progress callback"); + + let cb: curl_sys::curl_debug_callback = debug_cb::; + self.setopt_ptr(curl_sys::CURLOPT_DEBUGFUNCTION, cb as *const _) + .expect("failed to set debug callback"); + self.setopt_ptr(curl_sys::CURLOPT_DEBUGDATA, ptr) + .expect("failed to set debug callback"); + + let cb: curl_sys::curl_ssl_ctx_callback = ssl_ctx_cb::; + drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_FUNCTION, cb as *const _)); + drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_DATA, ptr)); + + let cb: curl_sys::curl_opensocket_callback = opensocket_cb::; + self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETFUNCTION, cb as *const _) + .expect("failed to set open socket callback"); + self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETDATA, ptr) + .expect("failed to set open socket callback"); + } + + #[cfg(need_openssl_probe)] + fn ssl_configure(&mut self) { + let probe = ::openssl_probe::probe(); + if let Some(ref path) = probe.cert_file { + let _ = self.cainfo(path); + } + if let Some(ref path) = probe.cert_dir { + let _ = self.capath(path); + } + } + + #[cfg(not(need_openssl_probe))] + fn ssl_configure(&mut self) {} +} + +impl Easy2 { + // ========================================================================= + // Behavior options + + /// Configures this handle to have verbose output to help debug protocol + /// information. + /// + /// By default output goes to stderr, but the `stderr` function on this type + /// can configure that. You can also use the `debug_function` method to get + /// all protocol data sent and received. + /// + /// By default, this option is `false`. + pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_VERBOSE, verbose as c_long) + } + + /// Indicates whether header information is streamed to the output body of + /// this request. + /// + /// This option is only relevant for protocols which have header metadata + /// (like http or ftp). It's not generally possible to extract headers + /// from the body if using this method, that use case should be intended for + /// the `header_function` method. + /// + /// To set HTTP headers, use the `http_header` method. + /// + /// By default, this option is `false` and corresponds to + /// `CURLOPT_HEADER`. + pub fn show_header(&mut self, show: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HEADER, show as c_long) + } + + /// Indicates whether a progress meter will be shown for requests done with + /// this handle. + /// + /// This will also prevent the `progress_function` from being called. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_NOPROGRESS`. + pub fn progress(&mut self, progress: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOPROGRESS, (!progress) as c_long) + } + + /// Inform libcurl whether or not it should install signal handlers or + /// attempt to use signals to perform library functions. + /// + /// If this option is disabled then timeouts during name resolution will not + /// work unless libcurl is built against c-ares. Note that enabling this + /// option, however, may not cause libcurl to work with multiple threads. + /// + /// By default this option is `false` and corresponds to `CURLOPT_NOSIGNAL`. + /// Note that this default is **different than libcurl** as it is intended + /// that this library is threadsafe by default. See the [libcurl docs] for + /// some more information. + /// + /// [libcurl docs]: https://curl.haxx.se/libcurl/c/threadsafe.html + pub fn signal(&mut self, signal: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOSIGNAL, (!signal) as c_long) + } + + /// Indicates whether multiple files will be transferred based on the file + /// name pattern. + /// + /// The last part of a filename uses fnmatch-like pattern matching. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_WILDCARDMATCH`. + pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_WILDCARDMATCH, m as c_long) + } + + /// Provides the unix domain socket which this handle will work with. + /// + /// The string provided must be unix domain socket -encoded with the format: + /// + /// ```text + /// /path/file.sock + /// ``` + pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> { + let socket = try!(CString::new(unix_domain_socket)); + self.setopt_str(curl_sys::CURLOPT_UNIX_SOCKET_PATH, &socket) + } + + // ========================================================================= + // Internal accessors + + /// Acquires a reference to the underlying handler for events. + pub fn get_ref(&self) -> &H { + &self.inner.handler + } + + /// Acquires a reference to the underlying handler for events. + pub fn get_mut(&mut self) -> &mut H { + &mut self.inner.handler + } + + // ========================================================================= + // Error options + + // TODO: error buffer and stderr + + /// Indicates whether this library will fail on HTTP response codes >= 400. + /// + /// This method is not fail-safe especially when authentication is involved. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FAILONERROR`. + pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FAILONERROR, fail as c_long) + } + + // ========================================================================= + // Network options + + /// Provides the URL which this handle will work with. + /// + /// The string provided must be URL-encoded with the format: + /// + /// ```text + /// scheme://host:port/path + /// ``` + /// + /// The syntax is not validated as part of this function and that is + /// deferred until later. + /// + /// By default this option is not set and `perform` will not work until it + /// is set. This option corresponds to `CURLOPT_URL`. + pub fn url(&mut self, url: &str) -> Result<(), Error> { + let url = try!(CString::new(url)); + self.setopt_str(curl_sys::CURLOPT_URL, &url) + } + + /// Configures the port number to connect to, instead of the one specified + /// in the URL or the default of the protocol. + pub fn port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PORT, port as c_long) + } + + // /// Indicates whether sequences of `/../` and `/./` will be squashed or not. + // /// + // /// By default this option is `false` and corresponds to + // /// `CURLOPT_PATH_AS_IS`. + // pub fn path_as_is(&mut self, as_is: bool) -> Result<(), Error> { + // } + + /// Provide the URL of a proxy to use. + /// + /// By default this option is not set and corresponds to `CURLOPT_PROXY`. + pub fn proxy(&mut self, url: &str) -> Result<(), Error> { + let url = try!(CString::new(url)); + self.setopt_str(curl_sys::CURLOPT_PROXY, &url) + } + + /// Provide port number the proxy is listening on. + /// + /// By default this option is not set (the default port for the proxy + /// protocol is used) and corresponds to `CURLOPT_PROXYPORT`. + pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYPORT, port as c_long) + } + + /// Indicates the type of proxy being used. + /// + /// By default this option is `ProxyType::Http` and corresponds to + /// `CURLOPT_PROXYTYPE`. + pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYTYPE, kind as c_long) + } + + /// Provide a list of hosts that should not be proxied to. + /// + /// This string is a comma-separated list of hosts which should not use the + /// proxy specified for connections. A single `*` character is also accepted + /// as a wildcard for all hosts. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_NOPROXY`. + pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> { + let skip = try!(CString::new(skip)); + self.setopt_str(curl_sys::CURLOPT_NOPROXY, &skip) + } + + /// Inform curl whether it should tunnel all operations through the proxy. + /// + /// This essentially means that a `CONNECT` is sent to the proxy for all + /// outbound requests. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_HTTPPROXYTUNNEL`. + pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPPROXYTUNNEL, tunnel as c_long) + } + + /// Tell curl which interface to bind to for an outgoing network interface. + /// + /// The interface name, IP address, or host name can be specified here. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_INTERFACE`. + pub fn interface(&mut self, interface: &str) -> Result<(), Error> { + let s = try!(CString::new(interface)); + self.setopt_str(curl_sys::CURLOPT_INTERFACE, &s) + } + + /// Indicate which port should be bound to locally for this connection. + /// + /// By default this option is 0 (any port) and corresponds to + /// `CURLOPT_LOCALPORT`. + pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOCALPORT, port as c_long) + } + + /// Indicates the number of attempts libcurl will perform to find a working + /// port number. + /// + /// By default this option is 1 and corresponds to + /// `CURLOPT_LOCALPORTRANGE`. + pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOCALPORTRANGE, range as c_long) + } + + /// Sets the DNS servers that wil be used. + /// + /// Provide a comma separated list, for example: `8.8.8.8,8.8.4.4`. + /// + /// By default this option is not set and the OS's DNS resolver is used. + /// This option can only be used if libcurl is linked against + /// [c-ares](https://c-ares.haxx.se), otherwise setting it will return + /// an error. + pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { + let s = try!(CString::new(servers)); + self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &s) + } + + /// Sets the timeout of how long name resolves will be kept in memory. + /// + /// This is distinct from DNS TTL options and is entirely speculative. + /// + /// By default this option is 60s and corresponds to + /// `CURLOPT_DNS_CACHE_TIMEOUT`. + pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, dur.as_secs() as c_long) + } + + /// Specify the preferred receive buffer size, in bytes. + /// + /// This is treated as a request, not an order, and the main point of this + /// is that the write callback may get called more often with smaller + /// chunks. + /// + /// By default this option is the maximum write size and corresopnds to + /// `CURLOPT_BUFFERSIZE`. + pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_BUFFERSIZE, size as c_long) + } + + // /// Enable or disable TCP Fast Open + // /// + // /// By default this options defaults to `false` and corresponds to + // /// `CURLOPT_TCP_FASTOPEN` + // pub fn fast_open(&mut self, enable: bool) -> Result<(), Error> { + // } + + /// Configures whether the TCP_NODELAY option is set, or Nagle's algorithm + /// is disabled. + /// + /// The purpose of Nagle's algorithm is to minimize the number of small + /// packet's on the network, and disabling this may be less efficient in + /// some situations. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TCP_NODELAY`. + pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_NODELAY, enable as c_long) + } + + /// Configures whether TCP keepalive probes will be sent. + /// + /// The delay and frequency of these probes is controlled by `tcp_keepidle` + /// and `tcp_keepintvl`. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TCP_KEEPALIVE`. + pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPALIVE, enable as c_long) + } + + /// Configures the TCP keepalive idle time wait. + /// + /// This is the delay, after which the connection is idle, keepalive probes + /// will be sent. Not all operating systems support this. + /// + /// By default this corresponds to `CURLOPT_TCP_KEEPIDLE`. + pub fn tcp_keepidle(&mut self, amt: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPIDLE, amt.as_secs() as c_long) + } + + /// Configures the delay between keepalive probes. + /// + /// By default this corresponds to `CURLOPT_TCP_KEEPINTVL`. + pub fn tcp_keepintvl(&mut self, amt: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPINTVL, amt.as_secs() as c_long) + } + + /// Configures the scope for local IPv6 addresses. + /// + /// Sets the scope_id value to use when connecting to IPv6 or link-local + /// addresses. + /// + /// By default this value is 0 and corresponds to `CURLOPT_ADDRESS_SCOPE` + pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_ADDRESS_SCOPE, scope as c_long) + } + + // ========================================================================= + // Names and passwords + + /// Configures the username to pass as authentication for this connection. + /// + /// By default this value is not set and corresponds to `CURLOPT_USERNAME`. + pub fn username(&mut self, user: &str) -> Result<(), Error> { + let user = try!(CString::new(user)); + self.setopt_str(curl_sys::CURLOPT_USERNAME, &user) + } + + /// Configures the password to pass as authentication for this connection. + /// + /// By default this value is not set and corresponds to `CURLOPT_PASSWORD`. + pub fn password(&mut self, pass: &str) -> Result<(), Error> { + let pass = try!(CString::new(pass)); + self.setopt_str(curl_sys::CURLOPT_PASSWORD, &pass) + } + + /// Set HTTP server authentication methods to try + /// + /// If more than one method is set, libcurl will first query the site to see + /// which authentication methods it supports and then pick the best one you + /// allow it to use. For some methods, this will induce an extra network + /// round-trip. Set the actual name and password with the `password` and + /// `username` methods. + /// + /// For authentication with a proxy, see `proxy_auth`. + /// + /// By default this value is basic and corresponds to `CURLOPT_HTTPAUTH`. + pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPAUTH, auth.bits) + } + + /// Configures the proxy username to pass as authentication for this + /// connection. + /// + /// By default this value is not set and corresponds to + /// `CURLOPT_PROXYUSERNAME`. + pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> { + let user = try!(CString::new(user)); + self.setopt_str(curl_sys::CURLOPT_PROXYUSERNAME, &user) + } + + /// Configures the proxy password to pass as authentication for this + /// connection. + /// + /// By default this value is not set and corresponds to + /// `CURLOPT_PROXYPASSWORD`. + pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> { + let pass = try!(CString::new(pass)); + self.setopt_str(curl_sys::CURLOPT_PROXYPASSWORD, &pass) + } + + /// Set HTTP proxy authentication methods to try + /// + /// If more than one method is set, libcurl will first query the site to see + /// which authentication methods it supports and then pick the best one you + /// allow it to use. For some methods, this will induce an extra network + /// round-trip. Set the actual name and password with the `proxy_password` + /// and `proxy_username` methods. + /// + /// By default this value is basic and corresponds to `CURLOPT_PROXYAUTH`. + pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYAUTH, auth.bits) + } + + /// Enable .netrc parsing + /// + /// By default the .netrc file is ignored and corresponds to `CURL_NETRC_IGNORED`. + pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NETRC, netrc as c_long) + } + + // ========================================================================= + // HTTP Options + + /// Indicates whether the referer header is automatically updated + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_AUTOREFERER`. + pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_AUTOREFERER, enable as c_long) + } + + /// Enables automatic decompression of HTTP downloads. + /// + /// Sets the contents of the Accept-Encoding header sent in an HTTP request. + /// This enables decoding of a response with Content-Encoding. + /// + /// Currently supported encoding are `identity`, `zlib`, and `gzip`. A + /// zero-length string passed in will send all accepted encodings. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_ACCEPT_ENCODING`. + pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> { + let encoding = try!(CString::new(encoding)); + self.setopt_str(curl_sys::CURLOPT_ACCEPT_ENCODING, &encoding) + } + + /// Request the HTTP Transfer Encoding. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TRANSFER_ENCODING`. + pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TRANSFER_ENCODING, enable as c_long) + } + + /// Follow HTTP 3xx redirects. + /// + /// Indicates whether any `Location` headers in the response should get + /// followed. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FOLLOWLOCATION`. + pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FOLLOWLOCATION, enable as c_long) + } + + /// Send credentials to hosts other than the first as well. + /// + /// Sends username/password credentials even when the host changes as part + /// of a redirect. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_UNRESTRICTED_AUTH`. + pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_UNRESTRICTED_AUTH, enable as c_long) + } + + /// Set the maximum number of redirects allowed. + /// + /// A value of 0 will refuse any redirect. + /// + /// By default this option is `-1` (unlimited) and corresponds to + /// `CURLOPT_MAXREDIRS`. + pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_MAXREDIRS, max as c_long) + } + + // TODO: post_redirections + + /// Make an HTTP PUT request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_PUT`. + pub fn put(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PUT, enable as c_long) + } + + /// Make an HTTP POST request. + /// + /// This will also make the library use the + /// `Content-Type: application/x-www-form-urlencoded` header. + /// + /// POST data can be specified through `post_fields` or by specifying a read + /// function. + /// + /// By default this option is `false` and corresponds to `CURLOPT_POST`. + pub fn post(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_POST, enable as c_long) + } + + /// Configures the data that will be uploaded as part of a POST. + /// + /// Note that the data is copied into this handle and if that's not desired + /// then the read callbacks can be used instead. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COPYPOSTFIELDS`. + pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> { + // Set the length before the pointer so libcurl knows how much to read + try!(self.post_field_size(data.len() as u64)); + self.setopt_ptr(curl_sys::CURLOPT_COPYPOSTFIELDS, data.as_ptr() as *const _) + } + + /// Configures the size of data that's going to be uploaded as part of a + /// POST operation. + /// + /// This is called automatically as part of `post_fields` and should only + /// be called if data is being provided in a read callback (and even then + /// it's optional). + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_POSTFIELDSIZE_LARGE`. + pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> { + // Clear anything previous to ensure we don't read past a buffer + try!(self.setopt_ptr(curl_sys::CURLOPT_POSTFIELDS, 0 as *const _)); + self.setopt_off_t( + curl_sys::CURLOPT_POSTFIELDSIZE_LARGE, + size as curl_sys::curl_off_t, + ) + } + + /// Tells libcurl you want a multipart/formdata HTTP POST to be made and you + /// instruct what data to pass on to the server in the `form` argument. + /// + /// By default this option is set to null and corresponds to + /// `CURLOPT_HTTPPOST`. + pub fn httppost(&mut self, form: Form) -> Result<(), Error> { + try!(self.setopt_ptr(curl_sys::CURLOPT_HTTPPOST, form::raw(&form) as *const _)); + self.inner.form = Some(form); + Ok(()) + } + + /// Sets the HTTP referer header + /// + /// By default this option is not set and corresponds to `CURLOPT_REFERER`. + pub fn referer(&mut self, referer: &str) -> Result<(), Error> { + let referer = try!(CString::new(referer)); + self.setopt_str(curl_sys::CURLOPT_REFERER, &referer) + } + + /// Sets the HTTP user-agent header + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_USERAGENT`. + pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> { + let useragent = try!(CString::new(useragent)); + self.setopt_str(curl_sys::CURLOPT_USERAGENT, &useragent) + } + + /// Add some headers to this HTTP request. + /// + /// If you add a header that is otherwise used internally, the value here + /// takes precedence. If a header is added with no content (like `Accept:`) + /// the internally the header will get disabled. To add a header with no + /// content, use the form `MyHeader;` (not the trailing semicolon). + /// + /// Headers must not be CRLF terminated. Many replaced headers have common + /// shortcuts which should be prefered. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_HTTPHEADER` + /// + /// # Examples + /// + /// ``` + /// use curl::easy::{Easy, List}; + /// + /// let mut list = List::new(); + /// list.append("Foo: bar").unwrap(); + /// list.append("Bar: baz").unwrap(); + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.http_headers(list).unwrap(); + /// handle.perform().unwrap(); + /// ``` + pub fn http_headers(&mut self, list: List) -> Result<(), Error> { + let ptr = list::raw(&list); + self.inner.header_list = Some(list); + self.setopt_ptr(curl_sys::CURLOPT_HTTPHEADER, ptr as *const _) + } + + // /// Add some headers to send to the HTTP proxy. + // /// + // /// This function is essentially the same as `http_headers`. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_PROXYHEADER` + // pub fn proxy_headers(&mut self, list: &'a List) -> Result<(), Error> { + // self.setopt_ptr(curl_sys::CURLOPT_PROXYHEADER, list.raw as *const _) + // } + + /// Set the contents of the HTTP Cookie header. + /// + /// Pass a string of the form `name=contents` for one cookie value or + /// `name1=val1; name2=val2` for multiple values. + /// + /// Using this option multiple times will only make the latest string + /// override the previous ones. This option will not enable the cookie + /// engine, use `cookie_file` or `cookie_jar` to do that. + /// + /// By default this option is not set and corresponds to `CURLOPT_COOKIE`. + pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> { + let cookie = try!(CString::new(cookie)); + self.setopt_str(curl_sys::CURLOPT_COOKIE, &cookie) + } + + /// Set the file name to read cookies from. + /// + /// The cookie data can be in either the old Netscape / Mozilla cookie data + /// format or just regular HTTP headers (Set-Cookie style) dumped to a file. + /// + /// This also enables the cookie engine, making libcurl parse and send + /// cookies on subsequent requests with this handle. + /// + /// Given an empty or non-existing file or by passing the empty string ("") + /// to this option, you can enable the cookie engine without reading any + /// initial cookies. + /// + /// If you use this option multiple times, you just add more files to read. + /// Subsequent files will add more cookies. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COOKIEFILE`. + pub fn cookie_file>(&mut self, file: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_COOKIEFILE, file.as_ref()) + } + + /// Set the file name to store cookies to. + /// + /// This will make libcurl write all internally known cookies to the file + /// when this handle is dropped. If no cookies are known, no file will be + /// created. Specify "-" as filename to instead have the cookies written to + /// stdout. Using this option also enables cookies for this session, so if + /// you for example follow a location it will make matching cookies get sent + /// accordingly. + /// + /// Note that libcurl doesn't read any cookies from the cookie jar. If you + /// want to read cookies from a file, use `cookie_file`. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COOKIEJAR`. + pub fn cookie_jar>(&mut self, file: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_COOKIEJAR, file.as_ref()) + } + + /// Start a new cookie session + /// + /// Marks this as a new cookie "session". It will force libcurl to ignore + /// all cookies it is about to load that are "session cookies" from the + /// previous session. By default, libcurl always stores and loads all + /// cookies, independent if they are session cookies or not. Session cookies + /// are cookies without expiry date and they are meant to be alive and + /// existing for this "session" only. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_COOKIESESSION`. + pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_COOKIESESSION, session as c_long) + } + + /// Add to or manipulate cookies held in memory. + /// + /// Such a cookie can be either a single line in Netscape / Mozilla format + /// or just regular HTTP-style header (Set-Cookie: ...) format. This will + /// also enable the cookie engine. This adds that single cookie to the + /// internal cookie store. + /// + /// Exercise caution if you are using this option and multiple transfers may + /// occur. If you use the Set-Cookie format and don't specify a domain then + /// the cookie is sent for any domain (even after redirects are followed) + /// and cannot be modified by a server-set cookie. If a server sets a cookie + /// of the same name (or maybe you've imported one) then both will be sent + /// on a future transfer to that server, likely not what you intended. + /// address these issues set a domain in Set-Cookie or use the Netscape + /// format. + /// + /// Additionally, there are commands available that perform actions if you + /// pass in these exact strings: + /// + /// * "ALL" - erases all cookies held in memory + /// * "SESS" - erases all session cookies held in memory + /// * "FLUSH" - write all known cookies to the specified cookie jar + /// * "RELOAD" - reread all cookies from the cookie file + /// + /// By default this options corresponds to `CURLOPT_COOKIELIST` + pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> { + let cookie = try!(CString::new(cookie)); + self.setopt_str(curl_sys::CURLOPT_COOKIELIST, &cookie) + } + + /// Ask for a HTTP GET request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. + pub fn get(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) + } + + // /// Ask for a HTTP GET request. + // /// + // /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. + // pub fn http_version(&mut self, vers: &str) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) + // } + + /// Ignore the content-length header. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_IGNORE_CONTENT_LENGTH`. + pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_IGNORE_CONTENT_LENGTH, ignore as c_long) + } + + /// Enable or disable HTTP content decoding. + /// + /// By default this option is `true` and corresponds to + /// `CURLOPT_HTTP_CONTENT_DECODING`. + pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_CONTENT_DECODING, enable as c_long) + } + + /// Enable or disable HTTP transfer decoding. + /// + /// By default this option is `true` and corresponds to + /// `CURLOPT_HTTP_TRANSFER_DECODING`. + pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, enable as c_long) + } + + // /// Timeout for the Expect: 100-continue response + // /// + // /// By default this option is 1s and corresponds to + // /// `CURLOPT_EXPECT_100_TIMEOUT_MS`. + // pub fn expect_100_timeout(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, + // enable as c_long) + // } + + // /// Wait for pipelining/multiplexing. + // /// + // /// Tells libcurl to prefer to wait for a connection to confirm or deny that + // /// it can do pipelining or multiplexing before continuing. + // /// + // /// When about to perform a new transfer that allows pipelining or + // /// multiplexing, libcurl will check for existing connections to re-use and + // /// pipeline on. If no such connection exists it will immediately continue + // /// and create a fresh new connection to use. + // /// + // /// By setting this option to `true` - having `pipeline` enabled for the + // /// multi handle this transfer is associated with - libcurl will instead + // /// wait for the connection to reveal if it is possible to + // /// pipeline/multiplex on before it continues. This enables libcurl to much + // /// better keep the number of connections to a minimum when using pipelining + // /// or multiplexing protocols. + // /// + // /// The effect thus becomes that with this option set, libcurl prefers to + // /// wait and re-use an existing connection for pipelining rather than the + // /// opposite: prefer to open a new connection rather than waiting. + // /// + // /// The waiting time is as long as it takes for the connection to get up and + // /// for libcurl to get the necessary response back that informs it about its + // /// protocol and support level. + // pub fn http_pipewait(&mut self, enable: bool) -> Result<(), Error> { + // } + + // ========================================================================= + // Protocol Options + + /// Indicates the range that this request should retrieve. + /// + /// The string provided should be of the form `N-M` where either `N` or `M` + /// can be left out. For HTTP transfers multiple ranges separated by commas + /// are also accepted. + /// + /// By default this option is not set and corresponds to `CURLOPT_RANGE`. + pub fn range(&mut self, range: &str) -> Result<(), Error> { + let range = try!(CString::new(range)); + self.setopt_str(curl_sys::CURLOPT_RANGE, &range) + } + + /// Set a point to resume transfer from + /// + /// Specify the offset in bytes you want the transfer to start from. + /// + /// By default this option is 0 and corresponds to + /// `CURLOPT_RESUME_FROM_LARGE`. + pub fn resume_from(&mut self, from: u64) -> Result<(), Error> { + self.setopt_off_t( + curl_sys::CURLOPT_RESUME_FROM_LARGE, + from as curl_sys::curl_off_t, + ) + } + + /// Set a custom request string + /// + /// Specifies that a custom request will be made (e.g. a custom HTTP + /// method). This does not change how libcurl performs internally, just + /// changes the string sent to the server. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_CUSTOMREQUEST`. + pub fn custom_request(&mut self, request: &str) -> Result<(), Error> { + let request = try!(CString::new(request)); + self.setopt_str(curl_sys::CURLOPT_CUSTOMREQUEST, &request) + } + + /// Get the modification time of the remote resource + /// + /// If true, libcurl will attempt to get the modification time of the + /// remote document in this operation. This requires that the remote server + /// sends the time or replies to a time querying command. The `filetime` + /// function can be used after a transfer to extract the received time (if + /// any). + /// + /// By default this option is `false` and corresponds to `CURLOPT_FILETIME` + pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FILETIME, fetch as c_long) + } + + /// Indicate whether to download the request without getting the body + /// + /// This is useful, for example, for doing a HEAD request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_NOBODY`. + pub fn nobody(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOBODY, enable as c_long) + } + + /// Set the size of the input file to send off. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_INFILESIZE_LARGE`. + pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> { + self.setopt_off_t( + curl_sys::CURLOPT_INFILESIZE_LARGE, + size as curl_sys::curl_off_t, + ) + } + + /// Enable or disable data upload. + /// + /// This means that a PUT request will be made for HTTP and probably wants + /// to be combined with the read callback as well as the `in_filesize` + /// method. + /// + /// By default this option is `false` and corresponds to `CURLOPT_UPLOAD`. + pub fn upload(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_UPLOAD, enable as c_long) + } + + /// Configure the maximum file size to download. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_MAXFILESIZE_LARGE`. + pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> { + self.setopt_off_t( + curl_sys::CURLOPT_MAXFILESIZE_LARGE, + size as curl_sys::curl_off_t, + ) + } + + /// Selects a condition for a time request. + /// + /// This value indicates how the `time_value` option is interpreted. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMECONDITION`. + pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TIMECONDITION, cond as c_long) + } + + /// Sets the time value for a conditional request. + /// + /// The value here should be the number of seconds elapsed since January 1, + /// 1970. To pass how to interpret this value, use `time_condition`. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMEVALUE`. + pub fn time_value(&mut self, val: i64) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TIMEVALUE, val as c_long) + } + + // ========================================================================= + // Connection Options + + /// Set maximum time the request is allowed to take. + /// + /// Normally, name lookups can take a considerable time and limiting + /// operations to less than a few minutes risk aborting perfectly normal + /// operations. + /// + /// If libcurl is built to use the standard system name resolver, that + /// portion of the transfer will still use full-second resolution for + /// timeouts with a minimum timeout allowed of one second. + /// + /// In unix-like systems, this might cause signals to be used unless + /// `nosignal` is set. + /// + /// Since this puts a hard limit for how long a request is allowed to + /// take, it has limited use in dynamic use cases with varying transfer + /// times. You are then advised to explore `low_speed_limit`, + /// `low_speed_time` or using `progress_function` to implement your own + /// timeout logic. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMEOUT_MS`. + pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> { + // TODO: checked arithmetic and casts + // TODO: use CURLOPT_TIMEOUT if the timeout is too great + let ms = timeout.as_secs() * 1000 + (timeout.subsec_nanos() / 1_000_000) as u64; + self.setopt_long(curl_sys::CURLOPT_TIMEOUT_MS, ms as c_long) + } + + /// Set the low speed limit in bytes per second. + /// + /// This specifies the average transfer speed in bytes per second that the + /// transfer should be below during `low_speed_time` for libcurl to consider + /// it to be too slow and abort. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_LOW_SPEED_LIMIT`. + pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_LIMIT, limit as c_long) + } + + /// Set the low speed time period. + /// + /// Specifies the window of time for which if the transfer rate is below + /// `low_speed_limit` the request will be aborted. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_LOW_SPEED_TIME`. + pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_TIME, dur.as_secs() as c_long) + } + + /// Rate limit data upload speed + /// + /// If an upload exceeds this speed (counted in bytes per second) on + /// cumulative average during the transfer, the transfer will pause to keep + /// the average rate less than or equal to the parameter value. + /// + /// By default this option is not set (unlimited speed) and corresponds to + /// `CURLOPT_MAX_SEND_SPEED_LARGE`. + pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> { + self.setopt_off_t( + curl_sys::CURLOPT_MAX_SEND_SPEED_LARGE, + speed as curl_sys::curl_off_t, + ) + } + + /// Rate limit data download speed + /// + /// If a download exceeds this speed (counted in bytes per second) on + /// cumulative average during the transfer, the transfer will pause to keep + /// the average rate less than or equal to the parameter value. + /// + /// By default this option is not set (unlimited speed) and corresponds to + /// `CURLOPT_MAX_RECV_SPEED_LARGE`. + pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> { + self.setopt_off_t( + curl_sys::CURLOPT_MAX_RECV_SPEED_LARGE, + speed as curl_sys::curl_off_t, + ) + } + + /// Set the maximum connection cache size. + /// + /// The set amount will be the maximum number of simultaneously open + /// persistent connections that libcurl may cache in the pool associated + /// with this handle. The default is 5, and there isn't much point in + /// changing this value unless you are perfectly aware of how this works and + /// changes libcurl's behaviour. This concerns connections using any of the + /// protocols that support persistent connections. + /// + /// When reaching the maximum limit, curl closes the oldest one in the cache + /// to prevent increasing the number of open connections. + /// + /// By default this option is set to 5 and corresponds to + /// `CURLOPT_MAXCONNECTS` + pub fn max_connects(&mut self, max: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_MAXCONNECTS, max as c_long) + } + + /// Force a new connection to be used. + /// + /// Makes the next transfer use a new (fresh) connection by force instead of + /// trying to re-use an existing one. This option should be used with + /// caution and only if you understand what it does as it may seriously + /// impact performance. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FRESH_CONNECT`. + pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FRESH_CONNECT, enable as c_long) + } + + /// Make connection get closed at once after use. + /// + /// Makes libcurl explicitly close the connection when done with the + /// transfer. Normally, libcurl keeps all connections alive when done with + /// one transfer in case a succeeding one follows that can re-use them. + /// This option should be used with caution and only if you understand what + /// it does as it can seriously impact performance. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FORBID_REUSE`. + pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FORBID_REUSE, enable as c_long) + } + + /// Timeout for the connect phase + /// + /// This is the maximum time that you allow the connection phase to the + /// server to take. This only limits the connection phase, it has no impact + /// once it has connected. + /// + /// By default this value is 300 seconds and corresponds to + /// `CURLOPT_CONNECTTIMEOUT_MS`. + pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> { + let ms = timeout.as_secs() * 1000 + (timeout.subsec_nanos() / 1_000_000) as u64; + self.setopt_long(curl_sys::CURLOPT_CONNECTTIMEOUT_MS, ms as c_long) + } + + /// Specify which IP protocol version to use + /// + /// Allows an application to select what kind of IP addresses to use when + /// resolving host names. This is only interesting when using host names + /// that resolve addresses using more than one version of IP. + /// + /// By default this value is "any" and corresponds to `CURLOPT_IPRESOLVE`. + pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_IPRESOLVE, resolve as c_long) + } + + /// Specify custom host name to IP address resolves. + /// + /// Allows specifying hostname to IP mappins to use before trying the + /// system resolver. + /// + /// # Examples + /// + /// ```no_run + /// use curl::easy::{Easy, List}; + /// + /// let mut list = List::new(); + /// list.append("www.rust-lang.org:443:185.199.108.153").unwrap(); + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.resolve(list).unwrap(); + /// handle.perform().unwrap(); + /// ``` + pub fn resolve(&mut self, list: List) -> Result<(), Error> { + let ptr = list::raw(&list); + self.inner.resolve_list = Some(list); + self.setopt_ptr(curl_sys::CURLOPT_RESOLVE, ptr as *const _) + } + + /// Configure whether to stop when connected to target server + /// + /// When enabled it tells the library to perform all the required proxy + /// authentication and connection setup, but no data transfer, and then + /// return. + /// + /// The option can be used to simply test a connection to a server. + /// + /// By default this value is `false` and corresponds to + /// `CURLOPT_CONNECT_ONLY`. + pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_CONNECT_ONLY, enable as c_long) + } + + // /// Set interface to speak DNS over. + // /// + // /// Set the name of the network interface that the DNS resolver should bind + // /// to. This must be an interface name (not an address). + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_INTERFACE`. + // pub fn dns_interface(&mut self, interface: &str) -> Result<(), Error> { + // let interface = try!(CString::new(interface)); + // self.setopt_str(curl_sys::CURLOPT_DNS_INTERFACE, &interface) + // } + // + // /// IPv4 address to bind DNS resolves to + // /// + // /// Set the local IPv4 address that the resolver should bind to. The + // /// argument should be of type char * and contain a single numerical IPv4 + // /// address as a string. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_LOCAL_IP4`. + // pub fn dns_local_ip4(&mut self, ip: &str) -> Result<(), Error> { + // let ip = try!(CString::new(ip)); + // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP4, &ip) + // } + // + // /// IPv6 address to bind DNS resolves to + // /// + // /// Set the local IPv6 address that the resolver should bind to. The + // /// argument should be of type char * and contain a single numerical IPv6 + // /// address as a string. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_LOCAL_IP6`. + // pub fn dns_local_ip6(&mut self, ip: &str) -> Result<(), Error> { + // let ip = try!(CString::new(ip)); + // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP6, &ip) + // } + // + // /// Set preferred DNS servers. + // /// + // /// Provides a list of DNS servers to be used instead of the system default. + // /// The format of the dns servers option is: + // /// + // /// ```text + // /// host[:port],[host[:port]]... + // /// ``` + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_SERVERS`. + // pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { + // let servers = try!(CString::new(servers)); + // self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &servers) + // } + + // ========================================================================= + // SSL/Security Options + + /// Sets the SSL client certificate. + /// + /// The string should be the file name of your client certificate. The + /// default format is "P12" on Secure Transport and "PEM" on other engines, + /// and can be changed with `ssl_cert_type`. + /// + /// With NSS or Secure Transport, this can also be the nickname of the + /// certificate you wish to authenticate with as it is named in the security + /// database. If you want to use a file from the current directory, please + /// precede it with "./" prefix, in order to avoid confusion with a + /// nickname. + /// + /// When using a client certificate, you most likely also need to provide a + /// private key with `ssl_key`. + /// + /// By default this option is not set and corresponds to `CURLOPT_SSLCERT`. + pub fn ssl_cert>(&mut self, cert: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_SSLCERT, cert.as_ref()) + } + + /// Specify type of the client SSL certificate. + /// + /// The string should be the format of your certificate. Supported formats + /// are "PEM" and "DER", except with Secure Transport. OpenSSL (versions + /// 0.9.3 and later) and Secure Transport (on iOS 5 or later, or OS X 10.7 + /// or later) also support "P12" for PKCS#12-encoded files. + /// + /// By default this option is "PEM" and corresponds to + /// `CURLOPT_SSLCERTTYPE`. + pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> { + let kind = try!(CString::new(kind)); + self.setopt_str(curl_sys::CURLOPT_SSLCERTTYPE, &kind) + } + + /// Specify private keyfile for TLS and SSL client cert. + /// + /// The string should be the file name of your private key. The default + /// format is "PEM" and can be changed with `ssl_key_type`. + /// + /// (iOS and Mac OS X only) This option is ignored if curl was built against + /// Secure Transport. Secure Transport expects the private key to be already + /// present in the keychain or PKCS#12 file containing the certificate. + /// + /// By default this option is not set and corresponds to `CURLOPT_SSLKEY`. + pub fn ssl_key>(&mut self, key: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_SSLKEY, key.as_ref()) + } + + /// Set type of the private key file. + /// + /// The string should be the format of your private key. Supported formats + /// are "PEM", "DER" and "ENG". + /// + /// The format "ENG" enables you to load the private key from a crypto + /// engine. In this case `ssl_key` is used as an identifier passed to + /// the engine. You have to set the crypto engine with `ssl_engine`. + /// "DER" format key file currently does not work because of a bug in + /// OpenSSL. + /// + /// By default this option is "PEM" and corresponds to + /// `CURLOPT_SSLKEYTYPE`. + pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> { + let kind = try!(CString::new(kind)); + self.setopt_str(curl_sys::CURLOPT_SSLKEYTYPE, &kind) + } + + /// Set passphrase to private key. + /// + /// This will be used as the password required to use the `ssl_key`. + /// You never needed a pass phrase to load a certificate but you need one to + /// load your private key. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_KEYPASSWD`. + pub fn key_password(&mut self, password: &str) -> Result<(), Error> { + let password = try!(CString::new(password)); + self.setopt_str(curl_sys::CURLOPT_KEYPASSWD, &password) + } + + /// Set the SSL engine identifier. + /// + /// This will be used as the identifier for the crypto engine you want to + /// use for your private key. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLENGINE`. + pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> { + let engine = try!(CString::new(engine)); + self.setopt_str(curl_sys::CURLOPT_SSLENGINE, &engine) + } + + /// Make this handle's SSL engine the default. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLENGINE_DEFAULT`. + pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) + } + + // /// Enable TLS false start. + // /// + // /// This option determines whether libcurl should use false start during the + // /// TLS handshake. False start is a mode where a TLS client will start + // /// sending application data before verifying the server's Finished message, + // /// thus saving a round trip when performing a full handshake. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_SSL_FALSESTARTE`. + // pub fn ssl_false_start(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) + // } + + /// Set preferred HTTP version. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_HTTP_VERSION`. + pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_VERSION, version as c_long) + } + + /// Set preferred TLS/SSL version. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLVERSION`. + pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version as c_long) + } + + /// Verify the certificate's name against host. + /// + /// This should be disabled with great caution! It basically disables the + /// security features of SSL if it is disabled. + /// + /// By default this option is set to `true` and corresponds to + /// `CURLOPT_SSL_VERIFYHOST`. + pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { + let val = if verify { 2 } else { 0 }; + self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYHOST, val) + } + + /// Verify the peer's SSL certificate. + /// + /// This should be disabled with great caution! It basically disables the + /// security features of SSL if it is disabled. + /// + /// By default this option is set to `true` and corresponds to + /// `CURLOPT_SSL_VERIFYPEER`. + pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYPEER, verify as c_long) + } + + // /// Verify the certificate's status. + // /// + // /// This option determines whether libcurl verifies the status of the server + // /// cert using the "Certificate Status Request" TLS extension (aka. OCSP + // /// stapling). + // /// + // /// By default this option is set to `false` and corresponds to + // /// `CURLOPT_SSL_VERIFYSTATUS`. + // pub fn ssl_verify_status(&mut self, verify: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYSTATUS, verify as c_long) + // } + + /// Specify the path to Certificate Authority (CA) bundle + /// + /// The file referenced should hold one or more certificates to verify the + /// peer with. + /// + /// This option is by default set to the system path where libcurl's cacert + /// bundle is assumed to be stored, as established at build time. + /// + /// If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module + /// (libnsspem.so) needs to be available for this option to work properly. + /// + /// By default this option is the system defaults, and corresponds to + /// `CURLOPT_CAINFO`. + pub fn cainfo>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CAINFO, path.as_ref()) + } + + /// Set the issuer SSL certificate filename + /// + /// Specifies a file holding a CA certificate in PEM format. If the option + /// is set, an additional check against the peer certificate is performed to + /// verify the issuer is indeed the one associated with the certificate + /// provided by the option. This additional check is useful in multi-level + /// PKI where one needs to enforce that the peer certificate is from a + /// specific branch of the tree. + /// + /// This option makes sense only when used in combination with the + /// `ssl_verify_peer` option. Otherwise, the result of the check is not + /// considered as failure. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_ISSUERCERT`. + pub fn issuer_cert>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_ISSUERCERT, path.as_ref()) + } + + /// Specify directory holding CA certificates + /// + /// Names a directory holding multiple CA certificates to verify the peer + /// with. If libcurl is built against OpenSSL, the certificate directory + /// must be prepared using the openssl c_rehash utility. This makes sense + /// only when used in combination with the `ssl_verify_peer` option. + /// + /// By default this option is not set and corresponds to `CURLOPT_CAPATH`. + pub fn capath>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CAPATH, path.as_ref()) + } + + /// Specify a Certificate Revocation List file + /// + /// Names a file with the concatenation of CRL (in PEM format) to use in the + /// certificate validation that occurs during the SSL exchange. + /// + /// When curl is built to use NSS or GnuTLS, there is no way to influence + /// the use of CRL passed to help in the verification process. When libcurl + /// is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and + /// X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all + /// the elements of the certificate chain if a CRL file is passed. + /// + /// This option makes sense only when used in combination with the + /// `ssl_verify_peer` option. + /// + /// A specific error code (`is_ssl_crl_badfile`) is defined with the + /// option. It is returned when the SSL exchange fails because the CRL file + /// cannot be loaded. A failure in certificate verification due to a + /// revocation information found in the CRL does not trigger this specific + /// error. + /// + /// By default this option is not set and corresponds to `CURLOPT_CRLFILE`. + pub fn crlfile>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CRLFILE, path.as_ref()) + } + + /// Request SSL certificate information + /// + /// Enable libcurl's certificate chain info gatherer. With this enabled, + /// libcurl will extract lots of information and data about the certificates + /// in the certificate chain used in the SSL connection. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_CERTINFO`. + pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long) + } + + // /// Set pinned public key. + // /// + // /// Pass a pointer to a zero terminated string as parameter. The string can + // /// be the file name of your pinned public key. The file format expected is + // /// "PEM" or "DER". The string can also be any number of base64 encoded + // /// sha256 hashes preceded by "sha256//" and separated by ";" + // /// + // /// When negotiating a TLS or SSL connection, the server sends a certificate + // /// indicating its identity. A public key is extracted from this certificate + // /// and if it does not exactly match the public key provided to this option, + // /// curl will abort the connection before sending or receiving any data. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_PINNEDPUBLICKEY`. + // pub fn pinned_public_key(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long) + // } + + /// Specify a source for random data + /// + /// The file will be used to read from to seed the random engine for SSL and + /// more. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_RANDOM_FILE`. + pub fn random_file>(&mut self, p: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_RANDOM_FILE, p.as_ref()) + } + + /// Specify EGD socket path. + /// + /// Indicates the path name to the Entropy Gathering Daemon socket. It will + /// be used to seed the random engine for SSL. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_EGDSOCKET`. + pub fn egd_socket>(&mut self, p: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_EGDSOCKET, p.as_ref()) + } + + /// Specify ciphers to use for TLS. + /// + /// Holds the list of ciphers to use for the SSL connection. The list must + /// be syntactically correct, it consists of one or more cipher strings + /// separated by colons. Commas or spaces are also acceptable separators + /// but colons are normally used, !, - and + can be used as operators. + /// + /// For OpenSSL and GnuTLS valid examples of cipher lists include 'RC4-SHA', + /// ´SHA1+DES´, 'TLSv1' and 'DEFAULT'. The default list is normally set when + /// you compile OpenSSL. + /// + /// You'll find more details about cipher lists on this URL: + /// + /// https://www.openssl.org/docs/apps/ciphers.html + /// + /// For NSS, valid examples of cipher lists include 'rsa_rc4_128_md5', + /// ´rsa_aes_128_sha´, etc. With NSS you don't add/remove ciphers. If one + /// uses this option then all known ciphers are disabled and only those + /// passed in are enabled. + /// + /// You'll find more details about the NSS cipher lists on this URL: + /// + /// http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSL_CIPHER_LIST`. + pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { + let ciphers = try!(CString::new(ciphers)); + self.setopt_str(curl_sys::CURLOPT_SSL_CIPHER_LIST, &ciphers) + } + + /// Enable or disable use of the SSL session-ID cache + /// + /// By default all transfers are done using the cache enabled. While nothing + /// ever should get hurt by attempting to reuse SSL session-IDs, there seem + /// to be or have been broken SSL implementations in the wild that may + /// require you to disable this in order for you to succeed. + /// + /// This corresponds to the `CURLOPT_SSL_SESSIONID_CACHE` option. + pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_SESSIONID_CACHE, enable as c_long) + } + + /// Set SSL behavior options + /// + /// Inform libcurl about SSL specific behaviors. + /// + /// This corresponds to the `CURLOPT_SSL_OPTIONS` option. + pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_OPTIONS, bits.bits) + } + + // /// Set SSL behavior options for proxies + // /// + // /// Inform libcurl about SSL specific behaviors. + // /// + // /// This corresponds to the `CURLOPT_PROXY_SSL_OPTIONS` option. + // pub fn proxy_ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_OPTIONS, bits.bits) + // } + + // /// Stores a private pointer-sized piece of data. + // /// + // /// This can be retrieved through the `private` function and otherwise + // /// libcurl does not tamper with this value. This corresponds to + // /// `CURLOPT_PRIVATE` and defaults to 0. + // pub fn set_private(&mut self, private: usize) -> Result<(), Error> { + // self.setopt_ptr(curl_sys::CURLOPT_PRIVATE, private as *const _) + // } + // + // /// Fetches this handle's private pointer-sized piece of data. + // /// + // /// This corresponds to `CURLINFO_PRIVATE` and defaults to 0. + // pub fn private(&mut self) -> Result { + // self.getopt_ptr(curl_sys::CURLINFO_PRIVATE).map(|p| p as usize) + // } + + // ========================================================================= + // getters + + /// Get info on unmet time conditional + /// + /// Returns if the condition provided in the previous request didn't match + /// + //// This corresponds to `CURLINFO_CONDITION_UNMET` and may return an error if the + /// option is not supported + pub fn time_condition_unmet(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_CONDITION_UNMET).map( + |r| { + if r == 0 { + false + } else { + true + } + }, + ) + } + + /// Get the last used URL + /// + /// In cases when you've asked libcurl to follow redirects, it may + /// not be the same value you set with `url`. + /// + /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. + /// + /// Returns `Ok(None)` if no effective url is listed or `Err` if an error + /// happens or the underlying bytes aren't valid utf-8. + pub fn effective_url(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_EFFECTIVE_URL) + } + + /// Get the last used URL, in bytes + /// + /// In cases when you've asked libcurl to follow redirects, it may + /// not be the same value you set with `url`. + /// + /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. + /// + /// Returns `Ok(None)` if no effective url is listed or `Err` if an error + /// happens or the underlying bytes aren't valid utf-8. + pub fn effective_url_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_EFFECTIVE_URL) + } + + /// Get the last response code + /// + /// The stored value will be zero if no server response code has been + /// received. Note that a proxy's CONNECT response should be read with + /// `http_connectcode` and not this. + /// + /// Corresponds to `CURLINFO_RESPONSE_CODE` and returns an error if this + /// option is not supported. + pub fn response_code(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_RESPONSE_CODE) + .map(|c| c as u32) + } + + /// Get the CONNECT response code + /// + /// Returns the last received HTTP proxy response code to a CONNECT request. + /// The returned value will be zero if no such response code was available. + /// + /// Corresponds to `CURLINFO_HTTP_CONNECTCODE` and returns an error if this + /// option is not supported. + pub fn http_connectcode(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_HTTP_CONNECTCODE) + .map(|c| c as u32) + } + + /// Get the remote time of the retrieved document + /// + /// Returns the remote time of the retrieved document (in number of seconds + /// since 1 Jan 1970 in the GMT/UTC time zone). If you get `None`, it can be + /// because of many reasons (it might be unknown, the server might hide it + /// or the server doesn't support the command that tells document time etc) + /// and the time of the document is unknown. + /// + /// Note that you must tell the server to collect this information before + /// the transfer is made, by using the `filetime` method to + /// or you will unconditionally get a `None` back. + /// + /// This corresponds to `CURLINFO_FILETIME` and may return an error if the + /// option is not supported + pub fn filetime(&mut self) -> Result, Error> { + self.getopt_long(curl_sys::CURLINFO_FILETIME).map(|r| { + if r == -1 { + None + } else { + Some(r as i64) + } + }) + } + + /// Get the number of downloaded bytes + /// + /// Returns the total amount of bytes that were downloaded. + /// The amount is only for the latest transfer and will be reset again for each new transfer. + /// This counts actual payload data, what's also commonly called body. + /// All meta and header data are excluded and will not be counted in this number. + /// + /// This corresponds to `CURLINFO_SIZE_DOWNLOAD` and may return an error if the + /// option is not supported + pub fn download_size(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_SIZE_DOWNLOAD) + .map(|r| r as f64) + } + + /// Get the content-length of the download + /// + /// Returns the content-length of the download. + /// This is the value read from the Content-Length: field + /// + /// This corresponds to `CURLINFO_CONTENT_LENGTH_DOWNLOAD` and may return an error if the + /// option is not supported + pub fn content_length_download(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_CONTENT_LENGTH_DOWNLOAD) + .map(|r| r as f64) + } + + /// Get total time of previous transfer + /// + /// Returns the total time for the previous transfer, + /// including name resolving, TCP connect etc. + /// + /// Corresponds to `CURLINFO_TOTAL_TIME` and may return an error if the + /// option isn't supported. + pub fn total_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_TOTAL_TIME) + .map(double_seconds_to_duration) + } + + /// Get the name lookup time + /// + /// Returns the total time from the start + /// until the name resolving was completed. + /// + /// Corresponds to `CURLINFO_NAMELOOKUP_TIME` and may return an error if the + /// option isn't supported. + pub fn namelookup_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_NAMELOOKUP_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until connect + /// + /// Returns the total time from the start + /// until the connection to the remote host (or proxy) was completed. + /// + /// Corresponds to `CURLINFO_CONNECT_TIME` and may return an error if the + /// option isn't supported. + pub fn connect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_CONNECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the SSL/SSH handshake is completed + /// + /// Returns the total time it took from the start until the SSL/SSH + /// connect/handshake to the remote host was completed. This time is most often + /// very near to the `pretransfer_time` time, except for cases such as + /// HTTP pipelining where the pretransfer time can be delayed due to waits in + /// line for the pipeline and more. + /// + /// Corresponds to `CURLINFO_APPCONNECT_TIME` and may return an error if the + /// option isn't supported. + pub fn appconnect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_APPCONNECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the file transfer start + /// + /// Returns the total time it took from the start until the file + /// transfer is just about to begin. This includes all pre-transfer commands + /// and negotiations that are specific to the particular protocol(s) involved. + /// It does not involve the sending of the protocol- specific request that + /// triggers a transfer. + /// + /// Corresponds to `CURLINFO_PRETRANSFER_TIME` and may return an error if the + /// option isn't supported. + pub fn pretransfer_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_PRETRANSFER_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the first byte is received + /// + /// Returns the total time it took from the start until the first + /// byte is received by libcurl. This includes `pretransfer_time` and + /// also the time the server needs to calculate the result. + /// + /// Corresponds to `CURLINFO_STARTTRANSFER_TIME` and may return an error if the + /// option isn't supported. + pub fn starttransfer_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_STARTTRANSFER_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time for all redirection steps + /// + /// Returns the total time it took for all redirection steps + /// include name lookup, connect, pretransfer and transfer before final + /// transaction was started. `redirect_time` contains the complete + /// execution time for multiple redirections. + /// + /// Corresponds to `CURLINFO_REDIRECT_TIME` and may return an error if the + /// option isn't supported. + pub fn redirect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_REDIRECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the number of redirects + /// + /// Corresponds to `CURLINFO_REDIRECT_COUNT` and may return an error if the + /// option isn't supported. + pub fn redirect_count(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_REDIRECT_COUNT) + .map(|c| c as u32) + } + + /// Get the URL a redirect would go to + /// + /// Returns the URL a redirect would take you to if you would enable + /// `follow_location`. This can come very handy if you think using the + /// built-in libcurl redirect logic isn't good enough for you but you would + /// still prefer to avoid implementing all the magic of figuring out the new + /// URL. + /// + /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error if the + /// url isn't valid utf-8 or an error happens. + pub fn redirect_url(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_REDIRECT_URL) + } + + /// Get the URL a redirect would go to, in bytes + /// + /// Returns the URL a redirect would take you to if you would enable + /// `follow_location`. This can come very handy if you think using the + /// built-in libcurl redirect logic isn't good enough for you but you would + /// still prefer to avoid implementing all the magic of figuring out the new + /// URL. + /// + /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error. + pub fn redirect_url_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_REDIRECT_URL) + } + + /// Get size of retrieved headers + /// + /// Corresponds to `CURLINFO_HEADER_SIZE` and may return an error if the + /// option isn't supported. + pub fn header_size(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_HEADER_SIZE) + .map(|c| c as u64) + } + + /// Get size of sent request. + /// + /// Corresponds to `CURLINFO_REQUEST_SIZE` and may return an error if the + /// option isn't supported. + pub fn request_size(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_REQUEST_SIZE) + .map(|c| c as u64) + } + + /// Get Content-Type + /// + /// Returns the content-type of the downloaded object. This is the value + /// read from the Content-Type: field. If you get `None`, it means that the + /// server didn't send a valid Content-Type header or that the protocol + /// used doesn't support this. + /// + /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the + /// option isn't supported. + pub fn content_type(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_CONTENT_TYPE) + } + + /// Get Content-Type, in bytes + /// + /// Returns the content-type of the downloaded object. This is the value + /// read from the Content-Type: field. If you get `None`, it means that the + /// server didn't send a valid Content-Type header or that the protocol + /// used doesn't support this. + /// + /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the + /// option isn't supported. + pub fn content_type_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_CONTENT_TYPE) + } + + /// Get errno number from last connect failure. + /// + /// Note that the value is only set on failure, it is not reset upon a + /// successful operation. The number is OS and system specific. + /// + /// Corresponds to `CURLINFO_OS_ERRNO` and may return an error if the + /// option isn't supported. + pub fn os_errno(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_OS_ERRNO) + .map(|c| c as i32) + } + + /// Get IP address of last connection. + /// + /// Returns a string holding the IP address of the most recent connection + /// done with this curl handle. This string may be IPv6 when that is + /// enabled. + /// + /// Corresponds to `CURLINFO_PRIMARY_IP` and may return an error if the + /// option isn't supported. + pub fn primary_ip(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_PRIMARY_IP) + } + + /// Get the latest destination port number + /// + /// Corresponds to `CURLINFO_PRIMARY_PORT` and may return an error if the + /// option isn't supported. + pub fn primary_port(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_PRIMARY_PORT) + .map(|c| c as u16) + } + + /// Get local IP address of last connection + /// + /// Returns a string holding the IP address of the local end of most recent + /// connection done with this curl handle. This string may be IPv6 when that + /// is enabled. + /// + /// Corresponds to `CURLINFO_LOCAL_IP` and may return an error if the + /// option isn't supported. + pub fn local_ip(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_LOCAL_IP) + } + + /// Get the latest local port number + /// + /// Corresponds to `CURLINFO_LOCAL_PORT` and may return an error if the + /// option isn't supported. + pub fn local_port(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_LOCAL_PORT) + .map(|c| c as u16) + } + + /// Get all known cookies + /// + /// Returns a linked-list of all cookies cURL knows (expired ones, too). + /// + /// Corresponds to the `CURLINFO_COOKIELIST` option and may return an error + /// if the option isn't supported. + pub fn cookies(&mut self) -> Result { + unsafe { + let mut list = 0 as *mut _; + let rc = curl_sys::curl_easy_getinfo( + self.inner.handle, + curl_sys::CURLINFO_COOKIELIST, + &mut list, + ); + try!(self.cvt(rc)); + Ok(list::from_raw(list)) + } + } + + /// Wait for pipelining/multiplexing + /// + /// Set wait to `true` to tell libcurl to prefer to wait for a connection to + /// confirm or deny that it can do pipelining or multiplexing before + /// continuing. + /// + /// When about to perform a new transfer that allows pipelining or + /// multiplexing, libcurl will check for existing connections to re-use and + /// pipeline on. If no such connection exists it will immediately continue + /// and create a fresh new connection to use. + /// + /// By setting this option to `true` - and having `pipelining(true, true)` + /// enabled for the multi handle this transfer is associated with - libcurl + /// will instead wait for the connection to reveal if it is possible to + /// pipeline/multiplex on before it continues. This enables libcurl to much + /// better keep the number of connections to a minimum when using pipelining + /// or multiplexing protocols. + /// + /// The effect thus becomes that with this option set, libcurl prefers to + /// wait and re-use an existing connection for pipelining rather than the + /// opposite: prefer to open a new connection rather than waiting. + /// + /// The waiting time is as long as it takes for the connection to get up and + /// for libcurl to get the necessary response back that informs it about its + /// protocol and support level. + /// + /// This corresponds to the `CURLOPT_PIPEWAIT` option. + pub fn pipewait(&mut self, wait: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PIPEWAIT, wait as c_long) + } + + // ========================================================================= + // Other methods + + /// After options have been set, this will perform the transfer described by + /// the options. + /// + /// This performs the request in a synchronous fashion. This can be used + /// multiple times for one easy handle and libcurl will attempt to re-use + /// the same connection for all transfers. + /// + /// This method will preserve all options configured in this handle for the + /// next request, and if that is not desired then the options can be + /// manually reset or the `reset` method can be called. + /// + /// Note that this method takes `&self`, which is quite important! This + /// allows applications to close over the handle in various callbacks to + /// call methods like `unpause_write` and `unpause_read` while a transfer is + /// in progress. + pub fn perform(&self) -> Result<(), Error> { + let ret = unsafe { self.cvt(curl_sys::curl_easy_perform(self.inner.handle)) }; + panic::propagate(); + return ret; + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// To unpause, you may for example call this from the progress callback + /// which gets called at least once per second, even if the connection is + /// paused. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_RECV_CONT); + self.cvt(rc) + } + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + /// + /// To unpause, you may for example call this from the progress callback + /// which gets called at least once per second, even if the connection is + /// paused. + pub fn unpause_write(&self) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_SEND_CONT); + self.cvt(rc) + } + } + + /// URL encodes a string `s` + pub fn url_encode(&mut self, s: &[u8]) -> String { + if s.len() == 0 { + return String::new(); + } + unsafe { + let p = curl_sys::curl_easy_escape( + self.inner.handle, + s.as_ptr() as *const _, + s.len() as c_int, + ); + assert!(!p.is_null()); + let ret = str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap(); + let ret = String::from(ret); + curl_sys::curl_free(p as *mut _); + return ret; + } + } + + /// URL decodes a string `s`, returning `None` if it fails + pub fn url_decode(&mut self, s: &str) -> Vec { + if s.len() == 0 { + return Vec::new(); + } + + // Work around https://curl.haxx.se/docs/adv_20130622.html, a bug where + // if the last few characters are a bad escape then curl will have a + // buffer overrun. + let mut iter = s.chars().rev(); + let orig_len = s.len(); + let mut data; + let mut s = s; + if iter.next() == Some('%') || iter.next() == Some('%') || iter.next() == Some('%') { + data = s.to_string(); + data.push(0u8 as char); + s = &data[..]; + } + unsafe { + let mut len = 0; + let p = curl_sys::curl_easy_unescape( + self.inner.handle, + s.as_ptr() as *const _, + orig_len as c_int, + &mut len, + ); + assert!(!p.is_null()); + let slice = slice::from_raw_parts(p as *const u8, len as usize); + let ret = slice.to_vec(); + curl_sys::curl_free(p as *mut _); + return ret; + } + } + + // TODO: I don't think this is safe, you can drop this which has all the + // callback data and then the next is use-after-free + // + // /// Attempts to clone this handle, returning a new session handle with the + // /// same options set for this handle. + // /// + // /// Internal state info and things like persistent connections ccannot be + // /// transferred. + // /// + // /// # Errors + // /// + // /// If a new handle could not be allocated or another error happens, `None` + // /// is returned. + // pub fn try_clone<'b>(&mut self) -> Option> { + // unsafe { + // let handle = curl_sys::curl_easy_duphandle(self.handle); + // if handle.is_null() { + // None + // } else { + // Some(Easy { + // handle: handle, + // data: blank_data(), + // _marker: marker::PhantomData, + // }) + // } + // } + // } + + /// Receives data from a connected socket. + /// + /// Only useful after a successful `perform` with the `connect_only` option + /// set as well. + pub fn recv(&mut self, data: &mut [u8]) -> Result { + unsafe { + let mut n = 0; + let r = curl_sys::curl_easy_recv( + self.inner.handle, + data.as_mut_ptr() as *mut _, + data.len(), + &mut n, + ); + if r == curl_sys::CURLE_OK { + Ok(n) + } else { + Err(Error::new(r)) + } + } + } + + /// Sends data over the connected socket. + /// + /// Only useful after a successful `perform` with the `connect_only` option + /// set as well. + pub fn send(&mut self, data: &[u8]) -> Result { + unsafe { + let mut n = 0; + let rc = curl_sys::curl_easy_send( + self.inner.handle, + data.as_ptr() as *const _, + data.len(), + &mut n, + ); + try!(self.cvt(rc)); + Ok(n) + } + } + + /// Get a pointer to the raw underlying CURL handle. + pub fn raw(&self) -> *mut curl_sys::CURL { + self.inner.handle + } + + #[cfg(unix)] + fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> { + use std::os::unix::prelude::*; + let s = try!(CString::new(val.as_os_str().as_bytes())); + self.setopt_str(opt, &s) + } + + #[cfg(windows)] + fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> { + match val.to_str() { + Some(s) => self.setopt_str(opt, &try!(CString::new(s))), + None => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), + } + } + + fn setopt_long(&mut self, opt: curl_sys::CURLoption, val: c_long) -> Result<(), Error> { + unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) } + } + + fn setopt_str(&mut self, opt: curl_sys::CURLoption, val: &CStr) -> Result<(), Error> { + self.setopt_ptr(opt, val.as_ptr()) + } + + fn setopt_ptr(&self, opt: curl_sys::CURLoption, val: *const c_char) -> Result<(), Error> { + unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) } + } + + fn setopt_off_t( + &mut self, + opt: curl_sys::CURLoption, + val: curl_sys::curl_off_t, + ) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_setopt(self.inner.handle, opt, val); + self.cvt(rc) + } + } + + fn getopt_bytes(&mut self, opt: curl_sys::CURLINFO) -> Result, Error> { + unsafe { + let p = try!(self.getopt_ptr(opt)); + if p.is_null() { + Ok(None) + } else { + Ok(Some(CStr::from_ptr(p).to_bytes())) + } + } + } + + fn getopt_ptr(&mut self, opt: curl_sys::CURLINFO) -> Result<*const c_char, Error> { + unsafe { + let mut p = 0 as *const c_char; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + fn getopt_str(&mut self, opt: curl_sys::CURLINFO) -> Result, Error> { + match self.getopt_bytes(opt) { + Ok(None) => Ok(None), + Err(e) => Err(e), + Ok(Some(bytes)) => match str::from_utf8(bytes) { + Ok(s) => Ok(Some(s)), + Err(_) => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), + }, + } + } + + fn getopt_long(&mut self, opt: curl_sys::CURLINFO) -> Result { + unsafe { + let mut p = 0; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + fn getopt_double(&mut self, opt: curl_sys::CURLINFO) -> Result { + unsafe { + let mut p = 0 as c_double; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + /// Returns the contents of the internal error buffer, if available. + /// + /// When an easy handle is created it configured the `CURLOPT_ERRORBUFFER` + /// parameter and instructs libcurl to store more error information into a + /// buffer for better error messages and better debugging. The contents of + /// that buffer are automatically coupled with all errors for methods on + /// this type, but if manually invoking APIs the contents will need to be + /// extracted with this method. + /// + /// Put another way, you probably don't need this, you're probably already + /// getting nice error messages! + /// + /// This function will clear the internal buffer, so this is an operation + /// that mutates the handle internally. + pub fn take_error_buf(&self) -> Option { + let mut buf = self.inner.error_buf.borrow_mut(); + if buf[0] == 0 { + return None; + } + let pos = buf.iter().position(|i| *i == 0).unwrap_or(buf.len()); + let msg = String::from_utf8_lossy(&buf[..pos]).into_owned(); + buf[0] = 0; + Some(msg) + } + + fn cvt(&self, rc: curl_sys::CURLcode) -> Result<(), Error> { + if rc == curl_sys::CURLE_OK { + return Ok(()); + } + let mut err = Error::new(rc); + if let Some(msg) = self.take_error_buf() { + err.set_extra(msg); + } + Err(Error::new(rc)) + } +} + +impl fmt::Debug for Easy2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Easy") + .field("handle", &self.inner.handle) + .field("handler", &self.inner.handle) + .finish() + } +} + +impl Drop for Easy2 { + fn drop(&mut self) { + unsafe { + curl_sys::curl_easy_cleanup(self.inner.handle); + } + } +} + +extern "C" fn header_cb( + buffer: *mut c_char, + size: size_t, + nitems: size_t, + userptr: *mut c_void, +) -> size_t { + let keep_going = panic::catch(|| unsafe { + let data = slice::from_raw_parts(buffer as *const u8, size * nitems); + (*(userptr as *mut Inner)).handler.header(data) + }) + .unwrap_or(false); + if keep_going { + size * nitems + } else { + !0 + } +} + +extern "C" fn write_cb( + ptr: *mut c_char, + size: size_t, + nmemb: size_t, + data: *mut c_void, +) -> size_t { + panic::catch(|| unsafe { + let input = slice::from_raw_parts(ptr as *const u8, size * nmemb); + match (*(data as *mut Inner)).handler.write(input) { + Ok(s) => s, + Err(WriteError::Pause) | Err(WriteError::__Nonexhaustive) => { + curl_sys::CURL_WRITEFUNC_PAUSE + } + } + }) + .unwrap_or(!0) +} + +extern "C" fn read_cb( + ptr: *mut c_char, + size: size_t, + nmemb: size_t, + data: *mut c_void, +) -> size_t { + panic::catch(|| unsafe { + let input = slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); + match (*(data as *mut Inner)).handler.read(input) { + Ok(s) => s, + Err(ReadError::Pause) => curl_sys::CURL_READFUNC_PAUSE, + Err(ReadError::__Nonexhaustive) | Err(ReadError::Abort) => { + curl_sys::CURL_READFUNC_ABORT + } + } + }) + .unwrap_or(!0) +} + +extern "C" fn seek_cb( + data: *mut c_void, + offset: curl_sys::curl_off_t, + origin: c_int, +) -> c_int { + panic::catch(|| unsafe { + let from = if origin == libc::SEEK_SET { + SeekFrom::Start(offset as u64) + } else { + panic!("unknown origin from libcurl: {}", origin); + }; + (*(data as *mut Inner)).handler.seek(from) as c_int + }) + .unwrap_or(!0) +} + +extern "C" fn progress_cb( + data: *mut c_void, + dltotal: c_double, + dlnow: c_double, + ultotal: c_double, + ulnow: c_double, +) -> c_int { + let keep_going = panic::catch(|| unsafe { + (*(data as *mut Inner)) + .handler + .progress(dltotal, dlnow, ultotal, ulnow) + }) + .unwrap_or(false); + if keep_going { + 0 + } else { + 1 + } +} + +// TODO: expose `handle`? is that safe? +extern "C" fn debug_cb( + _handle: *mut curl_sys::CURL, + kind: curl_sys::curl_infotype, + data: *mut c_char, + size: size_t, + userptr: *mut c_void, +) -> c_int { + panic::catch(|| unsafe { + let data = slice::from_raw_parts(data as *const u8, size); + let kind = match kind { + curl_sys::CURLINFO_TEXT => InfoType::Text, + curl_sys::CURLINFO_HEADER_IN => InfoType::HeaderIn, + curl_sys::CURLINFO_HEADER_OUT => InfoType::HeaderOut, + curl_sys::CURLINFO_DATA_IN => InfoType::DataIn, + curl_sys::CURLINFO_DATA_OUT => InfoType::DataOut, + curl_sys::CURLINFO_SSL_DATA_IN => InfoType::SslDataIn, + curl_sys::CURLINFO_SSL_DATA_OUT => InfoType::SslDataOut, + _ => return, + }; + (*(userptr as *mut Inner)).handler.debug(kind, data) + }); + return 0; +} + +extern "C" fn ssl_ctx_cb( + _handle: *mut curl_sys::CURL, + ssl_ctx: *mut c_void, + data: *mut c_void, +) -> curl_sys::CURLcode { + let res = panic::catch(|| unsafe { + match (*(data as *mut Inner)).handler.ssl_ctx(ssl_ctx) { + Ok(()) => curl_sys::CURLE_OK, + Err(e) => e.code(), + } + }); + // Default to a generic SSL error in case of panic. This + // shouldn't really matter since the error should be + // propagated later on but better safe than sorry... + res.unwrap_or(curl_sys::CURLE_SSL_CONNECT_ERROR) +} + +// TODO: expose `purpose` and `sockaddr` inside of `address` +extern "C" fn opensocket_cb( + data: *mut c_void, + _purpose: curl_sys::curlsocktype, + address: *mut curl_sys::curl_sockaddr, +) -> curl_sys::curl_socket_t { + let res = panic::catch(|| unsafe { + (*(data as *mut Inner)) + .handler + .open_socket((*address).family, (*address).socktype, (*address).protocol) + .unwrap_or(curl_sys::CURL_SOCKET_BAD) + }); + res.unwrap_or(curl_sys::CURL_SOCKET_BAD) +} + +fn double_seconds_to_duration(seconds: f64) -> Duration { + let whole_seconds = seconds.trunc() as u64; + let nanos = seconds.fract() * 1_000_000_000f64; + Duration::new(whole_seconds, nanos as u32) +} + +#[test] +fn double_seconds_to_duration_whole_second() { + let dur = double_seconds_to_duration(1.0); + assert_eq!(dur.as_secs(), 1); + assert_eq!(dur.subsec_nanos(), 0); +} + +#[test] +fn double_seconds_to_duration_sub_second1() { + let dur = double_seconds_to_duration(0.0); + assert_eq!(dur.as_secs(), 0); + assert_eq!(dur.subsec_nanos(), 0); +} + +#[test] +fn double_seconds_to_duration_sub_second2() { + let dur = double_seconds_to_duration(0.5); + assert_eq!(dur.as_secs(), 0); + assert_eq!(dur.subsec_nanos(), 500_000_000); +} + +impl Auth { + /// Creates a new set of authentications with no members. + /// + /// An `Auth` structure is used to configure which forms of authentication + /// are attempted when negotiating connections with servers. + pub fn new() -> Auth { + Auth { bits: 0 } + } + + /// HTTP Basic authentication. + /// + /// This is the default choice, and the only method that is in wide-spread + /// use and supported virtually everywhere. This sends the user name and + /// password over the network in plain text, easily captured by others. + pub fn basic(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_BASIC, on) + } + + /// HTTP Digest authentication. + /// + /// Digest authentication is defined in RFC 2617 and is a more secure way to + /// do authentication over public networks than the regular old-fashioned + /// Basic method. + pub fn digest(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_DIGEST, on) + } + + /// HTTP Digest authentication with an IE flavor. + /// + /// Digest authentication is defined in RFC 2617 and is a more secure way to + /// do authentication over public networks than the regular old-fashioned + /// Basic method. The IE flavor is simply that libcurl will use a special + /// "quirk" that IE is known to have used before version 7 and that some + /// servers require the client to use. + pub fn digest_ie(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_DIGEST_IE, on) + } + + /// HTTP Negotiate (SPNEGO) authentication. + /// + /// Negotiate authentication is defined in RFC 4559 and is the most secure + /// way to perform authentication over HTTP. + /// + /// You need to build libcurl with a suitable GSS-API library or SSPI on + /// Windows for this to work. + pub fn gssnegotiate(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_GSSNEGOTIATE, on) + } + + /// HTTP NTLM authentication. + /// + /// A proprietary protocol invented and used by Microsoft. It uses a + /// challenge-response and hash concept similar to Digest, to prevent the + /// password from being eavesdropped. + /// + /// You need to build libcurl with either OpenSSL, GnuTLS or NSS support for + /// this option to work, or build libcurl on Windows with SSPI support. + pub fn ntlm(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_NTLM, on) + } + + /// NTLM delegating to winbind helper. + /// + /// Authentication is performed by a separate binary application that is + /// executed when needed. The name of the application is specified at + /// compile time but is typically /usr/bin/ntlm_auth + /// + /// Note that libcurl will fork when necessary to run the winbind + /// application and kill it when complete, calling waitpid() to await its + /// exit when done. On POSIX operating systems, killing the process will + /// cause a SIGCHLD signal to be raised (regardless of whether + /// CURLOPT_NOSIGNAL is set), which must be handled intelligently by the + /// application. In particular, the application must not unconditionally + /// call wait() in its SIGCHLD signal handler to avoid being subject to a + /// race condition. This behavior is subject to change in future versions of + /// libcurl. + /// + /// A proprietary protocol invented and used by Microsoft. It uses a + /// challenge-response and hash concept similar to Digest, to prevent the + /// password from being eavesdropped. + pub fn ntlm_wb(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_NTLM_WB, on) + } + + fn flag(&mut self, bit: c_ulong, on: bool) -> &mut Auth { + if on { + self.bits |= bit as c_long; + } else { + self.bits &= !bit as c_long; + } + self + } +} + +impl fmt::Debug for Auth { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bits = self.bits as c_ulong; + f.debug_struct("Auth") + .field("basic", &(bits & curl_sys::CURLAUTH_BASIC != 0)) + .field("digest", &(bits & curl_sys::CURLAUTH_DIGEST != 0)) + .field("digest_ie", &(bits & curl_sys::CURLAUTH_DIGEST_IE != 0)) + .field( + "gssnegotiate", + &(bits & curl_sys::CURLAUTH_GSSNEGOTIATE != 0), + ) + .field("ntlm", &(bits & curl_sys::CURLAUTH_NTLM != 0)) + .field("ntlm_wb", &(bits & curl_sys::CURLAUTH_NTLM_WB != 0)) + .finish() + } +} + +impl SslOpt { + /// Creates a new set of SSL options. + pub fn new() -> SslOpt { + SslOpt { bits: 0 } + } + + /// Tells libcurl to disable certificate revocation checks for those SSL + /// backends where such behavior is present. + /// + /// Currently this option is only supported for WinSSL (the native Windows + /// SSL library), with an exception in the case of Windows' Untrusted + /// Publishers blacklist which it seems can't be bypassed. This option may + /// have broader support to accommodate other SSL backends in the future. + /// https://curl.haxx.se/docs/ssl-compared.html + pub fn no_revoke(&mut self, on: bool) -> &mut SslOpt { + self.flag(curl_sys::CURLSSLOPT_NO_REVOKE, on) + } + + /// Tells libcurl to not attempt to use any workarounds for a security flaw + /// in the SSL3 and TLS1.0 protocols. + /// + /// If this option isn't used or this bit is set to 0, the SSL layer libcurl + /// uses may use a work-around for this flaw although it might cause + /// interoperability problems with some (older) SSL implementations. + /// + /// > WARNING: avoiding this work-around lessens the security, and by + /// > setting this option to 1 you ask for exactly that. This option is only + /// > supported for DarwinSSL, NSS and OpenSSL. + pub fn allow_beast(&mut self, on: bool) -> &mut SslOpt { + self.flag(curl_sys::CURLSSLOPT_ALLOW_BEAST, on) + } + + fn flag(&mut self, bit: c_long, on: bool) -> &mut SslOpt { + if on { + self.bits |= bit as c_long; + } else { + self.bits &= !bit as c_long; + } + self + } +} + +impl fmt::Debug for SslOpt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SslOpt") + .field( + "no_revoke", + &(self.bits & curl_sys::CURLSSLOPT_NO_REVOKE != 0), + ) + .field( + "allow_beast", + &(self.bits & curl_sys::CURLSSLOPT_ALLOW_BEAST != 0), + ) + .finish() + } +} diff --git a/curl/src/easy/list.rs b/curl/src/easy/list.rs new file mode 100644 index 000000000..6d56cb25b --- /dev/null +++ b/curl/src/easy/list.rs @@ -0,0 +1,100 @@ +use std::ffi::{CStr, CString}; +use std::fmt; + +use curl_sys; +use Error; + +/// A linked list of a strings +pub struct List { + raw: *mut curl_sys::curl_slist, +} + +/// An iterator over `List` +#[derive(Clone)] +pub struct Iter<'a> { + _me: &'a List, + cur: *mut curl_sys::curl_slist, +} + +pub fn raw(list: &List) -> *mut curl_sys::curl_slist { + list.raw +} + +pub unsafe fn from_raw(raw: *mut curl_sys::curl_slist) -> List { + List { raw: raw } +} + +unsafe impl Send for List {} + +impl List { + /// Creates a new empty list of strings. + pub fn new() -> List { + List { raw: 0 as *mut _ } + } + + /// Appends some data into this list. + pub fn append(&mut self, data: &str) -> Result<(), Error> { + let data = try!(CString::new(data)); + unsafe { + let raw = curl_sys::curl_slist_append(self.raw, data.as_ptr()); + assert!(!raw.is_null()); + self.raw = raw; + Ok(()) + } + } + + /// Returns an iterator over the nodes in this list. + pub fn iter(&self) -> Iter { + Iter { + _me: self, + cur: self.raw, + } + } +} + +impl fmt::Debug for List { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.iter().map(String::from_utf8_lossy)) + .finish() + } +} + +impl<'a> IntoIterator for &'a List { + type IntoIter = Iter<'a>; + type Item = &'a [u8]; + + fn into_iter(self) -> Iter<'a> { + self.iter() + } +} + +impl Drop for List { + fn drop(&mut self) { + unsafe { curl_sys::curl_slist_free_all(self.raw) } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option<&'a [u8]> { + if self.cur.is_null() { + return None; + } + + unsafe { + let ret = Some(CStr::from_ptr((*self.cur).data).to_bytes()); + self.cur = (*self.cur).next; + return ret; + } + } +} + +impl<'a> fmt::Debug for Iter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone().map(String::from_utf8_lossy)) + .finish() + } +} diff --git a/curl/src/easy/mod.rs b/curl/src/easy/mod.rs new file mode 100644 index 000000000..988309946 --- /dev/null +++ b/curl/src/easy/mod.rs @@ -0,0 +1,22 @@ +//! Bindings to the "easy" libcurl API. +//! +//! This module contains some simple types like `Easy` and `List` which are just +//! wrappers around the corresponding libcurl types. There's also a few enums +//! scattered about for various options here and there. +//! +//! Most simple usage of libcurl will likely use the `Easy` structure here, and +//! you can find more docs about its usage on that struct. + +mod form; +mod handle; +mod handler; +mod list; +mod windows; + +pub use self::form::{Form, Part}; +pub use self::handle::{Easy, Transfer}; +pub use self::handler::{Auth, NetRc, ProxyType, SslOpt}; +pub use self::handler::{Easy2, Handler}; +pub use self::handler::{HttpVersion, IpResolve, SslVersion, TimeCondition}; +pub use self::handler::{InfoType, ReadError, SeekResult, WriteError}; +pub use self::list::{Iter, List}; diff --git a/curl/src/easy/windows.rs b/curl/src/easy/windows.rs new file mode 100644 index 000000000..cc2d8890c --- /dev/null +++ b/curl/src/easy/windows.rs @@ -0,0 +1,131 @@ +#![allow(non_camel_case_types, non_snake_case)] + +use libc::c_void; + +#[cfg(target_env = "msvc")] +mod win { + use schannel::cert_context::ValidUses; + use schannel::cert_store::CertStore; + use std::ffi::CString; + use std::mem; + use std::ptr; + use winapi::{self, c_int, c_long, c_uchar, c_void}; + use winapi::um::libloaderapi::{GetModuleHandleW, GetProcAddress}; + + fn lookup(module: &str, symbol: &str) -> Option<*const c_void> { + unsafe { + let symbol = CString::new(symbol).unwrap(); + let mut mod_buf: Vec = module.encode_utf16().collect(); + mod_buf.push(0); + let handle = GetModuleHandleW(mod_buf.as_mut_ptr()); + let n = GetProcAddress(handle, symbol.as_ptr()); + if n == ptr::null() { + None + } else { + Some(n) + } + } + } + + pub enum X509_STORE {} + pub enum X509 {} + pub enum SSL_CTX {} + + type d2i_X509_fn = unsafe extern "C" fn( + a: *mut *mut X509, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509; + type X509_free_fn = unsafe extern "C" fn(x: *mut X509); + type X509_STORE_add_cert_fn = + unsafe extern "C" fn(store: *mut X509_STORE, x: *mut X509) -> c_int; + type SSL_CTX_get_cert_store_fn = unsafe extern "C" fn(ctx: *const SSL_CTX) -> *mut X509_STORE; + + struct OpenSSL { + d2i_X509: d2i_X509_fn, + X509_free: X509_free_fn, + X509_STORE_add_cert: X509_STORE_add_cert_fn, + SSL_CTX_get_cert_store: SSL_CTX_get_cert_store_fn, + } + + unsafe fn lookup_functions(crypto_module: &str, ssl_module: &str) -> Option { + macro_rules! get { + ($(let $sym:ident in $module:expr;)*) => ($( + let $sym = match lookup($module, stringify!($sym)) { + Some(p) => p, + None => return None, + }; + )*) + } + get! { + let d2i_X509 in crypto_module; + let X509_free in crypto_module; + let X509_STORE_add_cert in crypto_module; + let SSL_CTX_get_cert_store in ssl_module; + } + Some(OpenSSL { + d2i_X509: mem::transmute(d2i_X509), + X509_free: mem::transmute(X509_free), + X509_STORE_add_cert: mem::transmute(X509_STORE_add_cert), + SSL_CTX_get_cert_store: mem::transmute(SSL_CTX_get_cert_store), + }) + } + + pub unsafe fn add_certs_to_context(ssl_ctx: *mut c_void) { + // check the runtime version of OpenSSL + let openssl = match ::version::Version::get().ssl_version() { + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.1.0") => { + lookup_functions("libcrypto", "libssl") + } + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.0.2") => { + lookup_functions("libeay32", "ssleay32") + } + _ => return, + }; + let openssl = match openssl { + Some(s) => s, + None => return, + }; + + let openssl_store = (openssl.SSL_CTX_get_cert_store)(ssl_ctx as *const SSL_CTX); + let mut store = match CertStore::open_current_user("ROOT") { + Ok(s) => s, + Err(_) => return, + }; + + for cert in store.certs() { + let valid_uses = match cert.valid_uses() { + Ok(v) => v, + Err(_) => continue, + }; + + // check the extended key usage for the "Server Authentication" OID + match valid_uses { + ValidUses::All => {} + ValidUses::Oids(ref oids) => { + let oid = winapi::wincrypt::szOID_PKIX_KP_SERVER_AUTH.to_owned(); + if !oids.contains(&oid) { + continue; + } + } + } + + let der = cert.to_der(); + let x509 = (openssl.d2i_X509)(ptr::null_mut(), &mut der.as_ptr(), der.len() as c_long); + if !x509.is_null() { + (openssl.X509_STORE_add_cert)(openssl_store, x509); + (openssl.X509_free)(x509); + } + } + } +} + +#[cfg(target_env = "msvc")] +pub fn add_certs_to_context(ssl_ctx: *mut c_void) { + unsafe { + win::add_certs_to_context(ssl_ctx as *mut _); + } +} + +#[cfg(not(target_env = "msvc"))] +pub fn add_certs_to_context(_: *mut c_void) {} diff --git a/curl/src/error.rs b/curl/src/error.rs new file mode 100644 index 000000000..d9cc353c6 --- /dev/null +++ b/curl/src/error.rs @@ -0,0 +1,621 @@ +use std::error; +use std::ffi::{self, CStr}; +use std::fmt; +use std::io; +use std::str; + +use curl_sys; + +/// An error returned from various "easy" operations. +/// +/// This structure wraps a `CURLcode`. +#[derive(Clone, PartialEq)] +pub struct Error { + code: curl_sys::CURLcode, + extra: Option>, +} + +impl Error { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLcode) -> Error { + Error { + code: code, + extra: None, + } + } + + /// Stores some extra information about this error inside this error. + /// + /// This is typically used with `take_error_buf` on the easy handles to + /// couple the extra `CURLOPT_ERRORBUFFER` information with an `Error` being + /// returned. + pub fn set_extra(&mut self, extra: String) { + self.extra = Some(extra.into()); + } + + /// Returns whether this error corresponds to CURLE_UNSUPPORTED_PROTOCOL. + pub fn is_unsupported_protocol(&self) -> bool { + self.code == curl_sys::CURLE_UNSUPPORTED_PROTOCOL + } + + /// Returns whether this error corresponds to CURLE_FAILED_INIT. + pub fn is_failed_init(&self) -> bool { + self.code == curl_sys::CURLE_FAILED_INIT + } + + /// Returns whether this error corresponds to CURLE_URL_MALFORMAT. + pub fn is_url_malformed(&self) -> bool { + self.code == curl_sys::CURLE_URL_MALFORMAT + } + + // /// Returns whether this error corresponds to CURLE_NOT_BUILT_IN. + // pub fn is_not_built_in(&self) -> bool { + // self.code == curl_sys::CURLE_NOT_BUILT_IN + // } + + /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_PROXY. + pub fn is_couldnt_resolve_proxy(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_RESOLVE_PROXY + } + + /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_HOST. + pub fn is_couldnt_resolve_host(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_RESOLVE_HOST + } + + /// Returns whether this error corresponds to CURLE_COULDNT_CONNECT. + pub fn is_couldnt_connect(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_CONNECT + } + + /// Returns whether this error corresponds to CURLE_REMOTE_ACCESS_DENIED. + pub fn is_remote_access_denied(&self) -> bool { + self.code == curl_sys::CURLE_REMOTE_ACCESS_DENIED + } + + /// Returns whether this error corresponds to CURLE_PARTIAL_FILE. + pub fn is_partial_file(&self) -> bool { + self.code == curl_sys::CURLE_PARTIAL_FILE + } + + /// Returns whether this error corresponds to CURLE_QUOTE_ERROR. + pub fn is_quote_error(&self) -> bool { + self.code == curl_sys::CURLE_QUOTE_ERROR + } + + /// Returns whether this error corresponds to CURLE_HTTP_RETURNED_ERROR. + pub fn is_http_returned_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP_RETURNED_ERROR + } + + /// Returns whether this error corresponds to CURLE_READ_ERROR. + pub fn is_read_error(&self) -> bool { + self.code == curl_sys::CURLE_READ_ERROR + } + + /// Returns whether this error corresponds to CURLE_WRITE_ERROR. + pub fn is_write_error(&self) -> bool { + self.code == curl_sys::CURLE_WRITE_ERROR + } + + /// Returns whether this error corresponds to CURLE_UPLOAD_FAILED. + pub fn is_upload_failed(&self) -> bool { + self.code == curl_sys::CURLE_UPLOAD_FAILED + } + + /// Returns whether this error corresponds to CURLE_OUT_OF_MEMORY. + pub fn is_out_of_memory(&self) -> bool { + self.code == curl_sys::CURLE_OUT_OF_MEMORY + } + + /// Returns whether this error corresponds to CURLE_OPERATION_TIMEDOUT. + pub fn is_operation_timedout(&self) -> bool { + self.code == curl_sys::CURLE_OPERATION_TIMEDOUT + } + + /// Returns whether this error corresponds to CURLE_RANGE_ERROR. + pub fn is_range_error(&self) -> bool { + self.code == curl_sys::CURLE_RANGE_ERROR + } + + /// Returns whether this error corresponds to CURLE_HTTP_POST_ERROR. + pub fn is_http_post_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP_POST_ERROR + } + + /// Returns whether this error corresponds to CURLE_SSL_CONNECT_ERROR. + pub fn is_ssl_connect_error(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CONNECT_ERROR + } + + /// Returns whether this error corresponds to CURLE_BAD_DOWNLOAD_RESUME. + pub fn is_bad_download_resume(&self) -> bool { + self.code == curl_sys::CURLE_BAD_DOWNLOAD_RESUME + } + + /// Returns whether this error corresponds to CURLE_FILE_COULDNT_READ_FILE. + pub fn is_file_couldnt_read_file(&self) -> bool { + self.code == curl_sys::CURLE_FILE_COULDNT_READ_FILE + } + + /// Returns whether this error corresponds to CURLE_FUNCTION_NOT_FOUND. + pub fn is_function_not_found(&self) -> bool { + self.code == curl_sys::CURLE_FUNCTION_NOT_FOUND + } + + /// Returns whether this error corresponds to CURLE_ABORTED_BY_CALLBACK. + pub fn is_aborted_by_callback(&self) -> bool { + self.code == curl_sys::CURLE_ABORTED_BY_CALLBACK + } + + /// Returns whether this error corresponds to CURLE_BAD_FUNCTION_ARGUMENT. + pub fn is_bad_function_argument(&self) -> bool { + self.code == curl_sys::CURLE_BAD_FUNCTION_ARGUMENT + } + + /// Returns whether this error corresponds to CURLE_INTERFACE_FAILED. + pub fn is_interface_failed(&self) -> bool { + self.code == curl_sys::CURLE_INTERFACE_FAILED + } + + /// Returns whether this error corresponds to CURLE_TOO_MANY_REDIRECTS. + pub fn is_too_many_redirects(&self) -> bool { + self.code == curl_sys::CURLE_TOO_MANY_REDIRECTS + } + + /// Returns whether this error corresponds to CURLE_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURLE_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURLE_PEER_FAILED_VERIFICATION. + pub fn is_peer_failed_verification(&self) -> bool { + self.code == curl_sys::CURLE_PEER_FAILED_VERIFICATION + } + + /// Returns whether this error corresponds to CURLE_GOT_NOTHING. + pub fn is_got_nothing(&self) -> bool { + self.code == curl_sys::CURLE_GOT_NOTHING + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_NOTFOUND. + pub fn is_ssl_engine_notfound(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_NOTFOUND + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_SETFAILED. + pub fn is_ssl_engine_setfailed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_SETFAILED + } + + /// Returns whether this error corresponds to CURLE_SEND_ERROR. + pub fn is_send_error(&self) -> bool { + self.code == curl_sys::CURLE_SEND_ERROR + } + + /// Returns whether this error corresponds to CURLE_RECV_ERROR. + pub fn is_recv_error(&self) -> bool { + self.code == curl_sys::CURLE_RECV_ERROR + } + + /// Returns whether this error corresponds to CURLE_SSL_CERTPROBLEM. + pub fn is_ssl_certproblem(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CERTPROBLEM + } + + /// Returns whether this error corresponds to CURLE_SSL_CIPHER. + pub fn is_ssl_cipher(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CIPHER + } + + /// Returns whether this error corresponds to CURLE_SSL_CACERT. + pub fn is_ssl_cacert(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CACERT + } + + /// Returns whether this error corresponds to CURLE_BAD_CONTENT_ENCODING. + pub fn is_bad_content_encoding(&self) -> bool { + self.code == curl_sys::CURLE_BAD_CONTENT_ENCODING + } + + /// Returns whether this error corresponds to CURLE_FILESIZE_EXCEEDED. + pub fn is_filesize_exceeded(&self) -> bool { + self.code == curl_sys::CURLE_FILESIZE_EXCEEDED + } + + /// Returns whether this error corresponds to CURLE_USE_SSL_FAILED. + pub fn is_use_ssl_failed(&self) -> bool { + self.code == curl_sys::CURLE_USE_SSL_FAILED + } + + /// Returns whether this error corresponds to CURLE_SEND_FAIL_REWIND. + pub fn is_send_fail_rewind(&self) -> bool { + self.code == curl_sys::CURLE_SEND_FAIL_REWIND + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_INITFAILED. + pub fn is_ssl_engine_initfailed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_INITFAILED + } + + /// Returns whether this error corresponds to CURLE_LOGIN_DENIED. + pub fn is_login_denied(&self) -> bool { + self.code == curl_sys::CURLE_LOGIN_DENIED + } + + /// Returns whether this error corresponds to CURLE_CONV_FAILED. + pub fn is_conv_failed(&self) -> bool { + self.code == curl_sys::CURLE_CONV_FAILED + } + + /// Returns whether this error corresponds to CURLE_CONV_REQD. + pub fn is_conv_required(&self) -> bool { + self.code == curl_sys::CURLE_CONV_REQD + } + + /// Returns whether this error corresponds to CURLE_SSL_CACERT_BADFILE. + pub fn is_ssl_cacert_badfile(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CACERT_BADFILE + } + + /// Returns whether this error corresponds to CURLE_SSL_CRL_BADFILE. + pub fn is_ssl_crl_badfile(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CRL_BADFILE + } + + /// Returns whether this error corresponds to CURLE_SSL_SHUTDOWN_FAILED. + pub fn is_ssl_shutdown_failed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_SHUTDOWN_FAILED + } + + /// Returns whether this error corresponds to CURLE_AGAIN. + pub fn is_again(&self) -> bool { + self.code == curl_sys::CURLE_AGAIN + } + + /// Returns whether this error corresponds to CURLE_SSL_ISSUER_ERROR. + pub fn is_ssl_issuer_error(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ISSUER_ERROR + } + + /// Returns whether this error corresponds to CURLE_CHUNK_FAILED. + pub fn is_chunk_failed(&self) -> bool { + self.code == curl_sys::CURLE_CHUNK_FAILED + } + + /// Returns whether this error corresponds to CURLE_HTTP2. + pub fn is_http2_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP2 + } + + /// Returns whether this error corresponds to CURLE_HTTP2_STREAM. + pub fn is_http2_stream_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP2_STREAM + } + + // /// Returns whether this error corresponds to CURLE_NO_CONNECTION_AVAILABLE. + // pub fn is_no_connection_available(&self) -> bool { + // self.code == curl_sys::CURLE_NO_CONNECTION_AVAILABLE + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLcode { + self.code + } + + /// Returns the extra description of this error, if any is available. + pub fn extra_description(&self) -> Option<&str> { + self.extra.as_ref().map(|s| &**s) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let desc = error::Error::description(self); + match self.extra { + Some(ref s) => write!(f, "[{}] {} ({})", self.code(), desc, s), + None => write!(f, "[{}] {}", self.code(), desc), + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Error") + .field("description", &error::Error::description(self)) + .field("code", &self.code) + .field("extra", &self.extra) + .finish() + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_easy_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + +/// An error returned from "share" operations. +/// +/// This structure wraps a `CURLSHcode`. +#[derive(Clone, PartialEq)] +pub struct ShareError { + code: curl_sys::CURLSHcode, +} + +impl ShareError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLSHcode) -> ShareError { + ShareError { code: code } + } + + /// Returns whether this error corresponds to CURLSHE_BAD_OPTION. + pub fn is_bad_option(&self) -> bool { + self.code == curl_sys::CURLSHE_BAD_OPTION + } + + /// Returns whether this error corresponds to CURLSHE_IN_USE. + pub fn is_in_use(&self) -> bool { + self.code == curl_sys::CURLSHE_IN_USE + } + + /// Returns whether this error corresponds to CURLSHE_INVALID. + pub fn is_invalid(&self) -> bool { + self.code == curl_sys::CURLSHE_INVALID + } + + /// Returns whether this error corresponds to CURLSHE_NOMEM. + pub fn is_nomem(&self) -> bool { + self.code == curl_sys::CURLSHE_NOMEM + } + + // /// Returns whether this error corresponds to CURLSHE_NOT_BUILT_IN. + // pub fn is_not_built_in(&self) -> bool { + // self.code == curl_sys::CURLSHE_NOT_BUILT_IN + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLSHcode { + self.code + } +} + +impl fmt::Display for ShareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for ShareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "ShareError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code + ) + } +} + +impl error::Error for ShareError { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_share_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + +/// An error from "multi" operations. +/// +/// THis structure wraps a `CURLMcode`. +#[derive(Clone, PartialEq)] +pub struct MultiError { + code: curl_sys::CURLMcode, +} + +impl MultiError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLMcode) -> MultiError { + MultiError { code: code } + } + + /// Returns whether this error corresponds to CURLM_BAD_HANDLE. + pub fn is_bad_handle(&self) -> bool { + self.code == curl_sys::CURLM_BAD_HANDLE + } + + /// Returns whether this error corresponds to CURLM_BAD_EASY_HANDLE. + pub fn is_bad_easy_handle(&self) -> bool { + self.code == curl_sys::CURLM_BAD_EASY_HANDLE + } + + /// Returns whether this error corresponds to CURLM_OUT_OF_MEMORY. + pub fn is_out_of_memory(&self) -> bool { + self.code == curl_sys::CURLM_OUT_OF_MEMORY + } + + /// Returns whether this error corresponds to CURLM_INTERNAL_ERROR. + pub fn is_internal_error(&self) -> bool { + self.code == curl_sys::CURLM_INTERNAL_ERROR + } + + /// Returns whether this error corresponds to CURLM_BAD_SOCKET. + pub fn is_bad_socket(&self) -> bool { + self.code == curl_sys::CURLM_BAD_SOCKET + } + + /// Returns whether this error corresponds to CURLM_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURLM_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURLM_CALL_MULTI_PERFORM. + pub fn is_call_perform(&self) -> bool { + self.code == curl_sys::CURLM_CALL_MULTI_PERFORM + } + + // /// Returns whether this error corresponds to CURLM_ADDED_ALREADY. + // pub fn is_added_already(&self) -> bool { + // self.code == curl_sys::CURLM_ADDED_ALREADY + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLMcode { + self.code + } +} + +impl fmt::Display for MultiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for MultiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "MultiError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code + ) + } +} + +impl error::Error for MultiError { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_multi_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + +/// An error from "form add" operations. +/// +/// THis structure wraps a `CURLFORMcode`. +#[derive(Clone, PartialEq)] +pub struct FormError { + code: curl_sys::CURLFORMcode, +} + +impl FormError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLFORMcode) -> FormError { + FormError { code: code } + } + + /// Returns whether this error corresponds to CURL_FORMADD_MEMORY. + pub fn is_memory(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_MEMORY + } + + /// Returns whether this error corresponds to CURL_FORMADD_OPTION_TWICE. + pub fn is_option_twice(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_OPTION_TWICE + } + + /// Returns whether this error corresponds to CURL_FORMADD_NULL. + pub fn is_null(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_NULL + } + + /// Returns whether this error corresponds to CURL_FORMADD_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURL_FORMADD_INCOMPLETE. + pub fn is_incomplete(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_INCOMPLETE + } + + /// Returns whether this error corresponds to CURL_FORMADD_ILLEGAL_ARRAY. + pub fn is_illegal_array(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_ILLEGAL_ARRAY + } + + /// Returns whether this error corresponds to CURL_FORMADD_DISABLED. + pub fn is_disabled(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_DISABLED + } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLFORMcode { + self.code + } +} + +impl fmt::Display for FormError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for FormError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "FormError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code + ) + } +} + +impl error::Error for FormError { + fn description(&self) -> &str { + match self.code { + curl_sys::CURL_FORMADD_MEMORY => "allocation failure", + curl_sys::CURL_FORMADD_OPTION_TWICE => "one option passed twice", + curl_sys::CURL_FORMADD_NULL => "null pointer given for string", + curl_sys::CURL_FORMADD_UNKNOWN_OPTION => "unknown option", + curl_sys::CURL_FORMADD_INCOMPLETE => "form information not complete", + curl_sys::CURL_FORMADD_ILLEGAL_ARRAY => "illegal array in option", + curl_sys::CURL_FORMADD_DISABLED => { + "libcurl does not have support for this option compiled in" + } + _ => "unknown form error", + } + } +} + +impl From for Error { + fn from(_: ffi::NulError) -> Error { + Error { + code: curl_sys::CURLE_CONV_FAILED, + extra: None, + } + } +} + +impl From for io::Error { + fn from(e: Error) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: ShareError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: MultiError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: FormError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} diff --git a/curl/src/lib.rs b/curl/src/lib.rs new file mode 100644 index 000000000..886ddaf77 --- /dev/null +++ b/curl/src/lib.rs @@ -0,0 +1,128 @@ +//! Rust bindings to the libcurl C library +//! +//! This crate contains bindings for an HTTP/HTTPS client which is powered by +//! [libcurl], the same library behind the `curl` command line tool. The API +//! currently closely matches that of libcurl itself, except that a Rustic layer +//! of safety is applied on top. +//! +//! [libcurl]: https://curl.haxx.se/libcurl/ +//! +//! # The "Easy" API +//! +//! The easiest way to send a request is to use the `Easy` api which corresponds +//! to `CURL` in libcurl. This handle supports a wide variety of options and can +//! be used to make a single blocking request in a thread. Callbacks can be +//! specified to deal with data as it arrives and a handle can be reused to +//! cache connections and such. +//! +//! ```rust,no_run +//! use std::io::{stdout, Write}; +//! +//! use curl::easy::Easy; +//! +//! // Write the contents of rust-lang.org to stdout +//! let mut easy = Easy::new(); +//! easy.url("https://www.rust-lang.org/").unwrap(); +//! easy.write_function(|data| { +//! stdout().write_all(data).unwrap(); +//! Ok(data.len()) +//! }).unwrap(); +//! easy.perform().unwrap(); +//! ``` +//! +//! # What about multiple concurrent HTTP requests? +//! +//! One option you have currently is to send multiple requests in multiple +//! threads, but otherwise libcurl has a "multi" interface for doing this +//! operation. Initial bindings of this interface can be found in the `multi` +//! module, but feedback is welcome! +//! +//! # Where does libcurl come from? +//! +//! This crate links to the `curl-sys` crate which is in turn responsible for +//! acquiring and linking to the libcurl library. Currently this crate will +//! build libcurl from source if one is not already detected on the system. +//! +//! There is a large number of releases for libcurl, all with different sets of +//! capabilities. Robust programs may wish to inspect `Version::get()` to test +//! what features are implemented in the linked build of libcurl at runtime. + +#![deny(missing_docs, missing_debug_implementations)] +#![doc(html_root_url = "https://docs.rs/curl/0.4")] + +extern crate curl_sys; +extern crate libc; +extern crate socket2; + +#[cfg(need_openssl_probe)] +extern crate openssl_probe; +#[cfg(need_openssl_init)] +extern crate openssl_sys; + +#[cfg(windows)] +extern crate winapi; + +#[cfg(target_env = "msvc")] +extern crate schannel; + +use std::ffi::CStr; +use std::str; +use std::sync::{Once, ONCE_INIT}; + +pub use error::{Error, FormError, MultiError, ShareError}; +mod error; + +pub use version::{Protocols, Version}; +mod version; + +pub mod easy; +pub mod multi; +mod panic; + +/// Initializes the underlying libcurl library. +/// +/// It's not required to call this before the library is used, but it's +/// recommended to do so as soon as the program starts. +pub fn init() { + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + platform_init(); + unsafe { + assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0); + } + + // Note that we explicitly don't schedule a call to + // `curl_global_cleanup`. The documentation for that function says + // + // > You must not call it when any other thread in the program (i.e. a + // > thread sharing the same memory) is running. This doesn't just mean + // > no other thread that is using libcurl. + // + // We can't ever be sure of that, so unfortunately we can't call the + // function. + }); + + #[cfg(need_openssl_init)] + fn platform_init() { + openssl_sys::init(); + } + + #[cfg(not(need_openssl_init))] + fn platform_init() {} +} + +unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> { + if ptr.is_null() { + None + } else { + Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap()) + } +} + +fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> { + if r == curl_sys::CURLE_OK { + Ok(()) + } else { + Err(Error::new(r)) + } +} diff --git a/curl/src/multi.rs b/curl/src/multi.rs new file mode 100644 index 000000000..1b71642f9 --- /dev/null +++ b/curl/src/multi.rs @@ -0,0 +1,1102 @@ +//! Multi - initiating multiple requests simultaneously + +use std::fmt; +use std::marker; +use std::time::Duration; + +use curl_sys; +use libc::{c_char, c_int, c_long, c_short, c_void}; + +#[cfg(unix)] +use libc::{fd_set, pollfd, POLLIN, POLLOUT, POLLPRI}; +#[cfg(windows)] +use winapi::um::winsock2::fd_set; + +use easy::{Easy, Easy2}; +use panic; +use {Error, MultiError}; + +/// A multi handle for initiating multiple connections simultaneously. +/// +/// This structure corresponds to `CURLM` in libcurl and provides the ability to +/// have multiple transfers in flight simultaneously. This handle is then used +/// to manage each transfer. The main purpose of a `CURLM` is for the +/// *application* to drive the I/O rather than libcurl itself doing all the +/// blocking. Methods like `action` allow the application to inform libcurl of +/// when events have happened. +/// +/// Lots more documentation can be found on the libcurl [multi tutorial] where +/// the APIs correspond pretty closely with this crate. +/// +/// [multi tutorial]: https://curl.haxx.se/libcurl/c/libcurl-multi.html +pub struct Multi { + raw: *mut curl_sys::CURLM, + data: Box, +} + +struct MultiData { + socket: Box, + timer: Box) -> bool + Send>, +} + +/// Message from the `messages` function of a multi handle. +/// +/// Currently only indicates whether a transfer is done. +pub struct Message<'multi> { + ptr: *mut curl_sys::CURLMsg, + _multi: &'multi Multi, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct EasyHandle { + easy: Easy, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct Easy2Handle { + easy: Easy2, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Notification of the events that have happened on a socket. +/// +/// This type is passed as an argument to the `action` method on a multi handle +/// to indicate what events have occurred on a socket. +pub struct Events { + bits: c_int, +} + +/// Notification of events that are requested on a socket. +/// +/// This type is yielded to the `socket_function` callback to indicate what +/// events are requested on a socket. +pub struct SocketEvents { + bits: c_int, +} + +/// Raw underlying socket type that the multi handles use +pub type Socket = curl_sys::curl_socket_t; + +/// File descriptor to wait on for use with the `wait` method on a multi handle. +pub struct WaitFd { + inner: curl_sys::curl_waitfd, +} + +impl Multi { + /// Creates a new multi session through which multiple HTTP transfers can be + /// initiated. + pub fn new() -> Multi { + unsafe { + ::init(); + let ptr = curl_sys::curl_multi_init(); + assert!(!ptr.is_null()); + Multi { + raw: ptr, + data: Box::new(MultiData { + socket: Box::new(|_, _, _| ()), + timer: Box::new(|_| true), + }), + } + } + } + + /// Set the callback informed about what to wait for + /// + /// When the `action` function runs, it informs the application about + /// updates in the socket (file descriptor) status by doing none, one, or + /// multiple calls to the socket callback. The callback gets status updates + /// with changes since the previous time the callback was called. See + /// `action` for more details on how the callback is used and should work. + /// + /// The `SocketEvents` parameter informs the callback on the status of the + /// given socket, and the methods on that type can be used to learn about + /// what's going on with the socket. + /// + /// The third `usize` parameter is a custom value set by the `assign` method + /// below. + pub fn socket_function(&mut self, f: F) -> Result<(), MultiError> + where + F: FnMut(Socket, SocketEvents, usize) + Send + 'static, + { + self._socket_function(Box::new(f)) + } + + fn _socket_function( + &mut self, + f: Box, + ) -> Result<(), MultiError> { + self.data.socket = f; + let cb: curl_sys::curl_socket_callback = cb; + try!(self.setopt_ptr( + curl_sys::CURLMOPT_SOCKETFUNCTION, + cb as usize as *const c_char + )); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_SOCKETDATA, ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_easy` + extern "C" fn cb( + _easy: *mut curl_sys::CURL, + socket: curl_sys::curl_socket_t, + what: c_int, + userptr: *mut c_void, + socketp: *mut c_void, + ) -> c_int { + panic::catch(|| unsafe { + let f = &mut (*(userptr as *mut MultiData)).socket; + f(socket, SocketEvents { bits: what }, socketp as usize) + }); + 0 + } + } + + /// Set data to associate with an internal socket + /// + /// This function creates an association in the multi handle between the + /// given socket and a private token of the application. This is designed + /// for `action` uses. + /// + /// When set, the token will be passed to all future socket callbacks for + /// the specified socket. + /// + /// If the given socket isn't already in use by libcurl, this function will + /// return an error. + /// + /// libcurl only keeps one single token associated with a socket, so + /// calling this function several times for the same socket will make the + /// last set token get used. + /// + /// The idea here being that this association (socket to token) is something + /// that just about every application that uses this API will need and then + /// libcurl can just as well do it since it already has an internal hash + /// table lookup for this. + /// + /// # Typical Usage + /// + /// In a typical application you allocate a struct or at least use some kind + /// of semi-dynamic data for each socket that we must wait for action on + /// when using the `action` approach. + /// + /// When our socket-callback gets called by libcurl and we get to know about + /// yet another socket to wait for, we can use `assign` to point out the + /// particular data so that when we get updates about this same socket + /// again, we don't have to find the struct associated with this socket by + /// ourselves. + pub fn assign(&self, socket: Socket, token: usize) -> Result<(), MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_assign( + self.raw, + socket, + token as *mut _ + ))); + Ok(()) + } + } + + /// Set callback to receive timeout values + /// + /// Certain features, such as timeouts and retries, require you to call + /// libcurl even when there is no activity on the file descriptors. + /// + /// Your callback function should install a non-repeating timer with the + /// interval specified. Each time that timer fires, call either `action` or + /// `perform`, depending on which interface you use. + /// + /// A timeout value of `None` means you should delete your timer. + /// + /// A timeout value of 0 means you should call `action` or `perform` (once) + /// as soon as possible. + /// + /// This callback will only be called when the timeout changes. + /// + /// The timer callback should return `true` on success, and `false` on + /// error. This callback can be used instead of, or in addition to, + /// `get_timeout`. + pub fn timer_function(&mut self, f: F) -> Result<(), MultiError> + where + F: FnMut(Option) -> bool + Send + 'static, + { + self._timer_function(Box::new(f)) + } + + fn _timer_function( + &mut self, + f: Box) -> bool + Send>, + ) -> Result<(), MultiError> { + self.data.timer = f; + let cb: curl_sys::curl_multi_timer_callback = cb; + try!(self.setopt_ptr( + curl_sys::CURLMOPT_TIMERFUNCTION, + cb as usize as *const c_char + )); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_TIMERDATA, ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_multi` + extern "C" fn cb( + _multi: *mut curl_sys::CURLM, + timeout_ms: c_long, + user: *mut c_void, + ) -> c_int { + let keep_going = panic::catch(|| unsafe { + let f = &mut (*(user as *mut MultiData)).timer; + if timeout_ms == -1 { + f(None) + } else { + f(Some(Duration::from_millis(timeout_ms as u64))) + } + }) + .unwrap_or(false); + if keep_going { + 0 + } else { + -1 + } + } + } + + /// Enable or disable HTTP pipelining and multiplexing. + /// + /// When http_1 is true, enable HTTP/1.1 pipelining, which means that if + /// you add a second request that can use an already existing connection, + /// the second request will be "piped" on the same connection rather than + /// being executed in parallel. + /// + /// When multiplex is true, enable HTTP/2 multiplexing, which means that + /// follow-up requests can re-use an existing connection and send the new + /// request multiplexed over that at the same time as other transfers are + /// already using that single connection. + pub fn pipelining(&mut self, http_1: bool, multiplex: bool) -> Result<(), MultiError> { + let bitmask = if http_1 { curl_sys::CURLPIPE_HTTP1 } else { 0 } + | if multiplex { + curl_sys::CURLPIPE_MULTIPLEX + } else { + 0 + }; + self.setopt_long(curl_sys::CURLMOPT_PIPELINING, bitmask) + } + + /// Sets the max number of connections to a single host. + /// + /// Pass a long to indicate the max number of simultaneously open connections + /// to a single host (a host being the same as a host name + port number pair). + /// For each new session to a host, libcurl will open up a new connection up to the + /// limit set by the provided value. When the limit is reached, the sessions will + /// be pending until a connection becomes available. If pipelining is enabled, + /// libcurl will try to pipeline if the host is capable of it. + pub fn set_max_host_connections(&mut self, val: usize) -> Result<(), MultiError> { + self.setopt_long(curl_sys::CURLMOPT_MAX_HOST_CONNECTIONS, val as c_long) + } + + /// Sets the pipeline length. + /// + /// This sets the max number that will be used as the maximum amount of + /// outstanding reuqests in an HTTP/1.1 pipelined connection. This option + /// is only used for HTTP/1.1 pipelining, and not HTTP/2 multiplexing. + pub fn set_pipeline_length(&mut self, val: usize) -> Result<(), MultiError> { + self.setopt_long(curl_sys::CURLMOPT_MAX_PIPELINE_LENGTH, val as c_long) + } + + fn setopt_long(&mut self, opt: curl_sys::CURLMoption, val: c_long) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) } + } + + fn setopt_ptr( + &mut self, + opt: curl_sys::CURLMoption, + val: *const c_char, + ) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) } + } + + /// Add an easy handle to a multi session + /// + /// Adds a standard easy handle to the multi stack. This function call will + /// make this multi handle control the specified easy handle. + /// + /// When an easy interface is added to a multi handle, it will use a shared + /// connection cache owned by the multi handle. Removing and adding new easy + /// handles will not affect the pool of connections or the ability to do + /// connection re-use. + /// + /// If you have `timer_function` set in the multi handle (and you really + /// should if you're working event-based with `action` and friends), that + /// callback will be called from within this function to ask for an updated + /// timer so that your main event loop will get the activity on this handle + /// to get started. + /// + /// The easy handle will remain added to the multi handle until you remove + /// it again with `remove` on the returned handle - even when a transfer + /// with that specific easy handle is completed. + pub fn add(&self, mut easy: Easy) -> Result { + // Clear any configuration set by previous transfers because we're + // moving this into a `Send+'static` situation now basically. + easy.transfer(); + + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(EasyHandle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Same as `add`, but works with the `Easy2` type. + pub fn add2(&self, easy: Easy2) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(Easy2Handle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Remove an easy handle from this multi session + /// + /// Removes the easy handle from this multi handle. This will make the + /// returned easy handle be removed from this multi handle's control. + /// + /// When the easy handle has been removed from a multi stack, it is again + /// perfectly legal to invoke `perform` on it. + /// + /// Removing an easy handle while being used is perfectly legal and will + /// effectively halt the transfer in progress involving that easy handle. + /// All other easy handles and transfers will remain unaffected. + pub fn remove(&self, easy: EasyHandle) -> Result { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle( + self.raw, + easy.easy.raw() + ))); + } + Ok(easy.easy) + } + + /// Same as `remove`, but for `Easy2Handle`. + pub fn remove2(&self, easy: Easy2Handle) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle( + self.raw, + easy.easy.raw() + ))); + } + Ok(easy.easy) + } + + /// Read multi stack informationals + /// + /// Ask the multi handle if there are any messages/informationals from the + /// individual transfers. Messages may include informationals such as an + /// error code from the transfer or just the fact that a transfer is + /// completed. More details on these should be written down as well. + pub fn messages(&self, mut f: F) + where + F: FnMut(Message), + { + self._messages(&mut f) + } + + fn _messages(&self, f: &mut FnMut(Message)) { + let mut queue = 0; + unsafe { + loop { + let ptr = curl_sys::curl_multi_info_read(self.raw, &mut queue); + if ptr.is_null() { + break; + } + f(Message { + ptr: ptr, + _multi: self, + }) + } + } + } + + /// Inform of reads/writes available data given an action + /// + /// When the application has detected action on a socket handled by libcurl, + /// it should call this function with the sockfd argument set to + /// the socket with the action. When the events on a socket are known, they + /// can be passed `events`. When the events on a socket are unknown, pass + /// `Events::new()` instead, and libcurl will test the descriptor + /// internally. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// The `action` function informs the application about updates in the + /// socket (file descriptor) status by doing none, one, or multiple calls to + /// the socket callback function set with the `socket_function` method. They + /// update the status with changes since the previous time the callback was + /// called. + pub fn action(&self, socket: Socket, events: &Events) -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action( + self.raw, + socket, + events.bits, + &mut remaining + ))); + Ok(remaining as u32) + } + } + + /// Inform libcurl that a timeout has expired and sockets should be tested. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// Get the timeout time by calling the `timer_function` method. Your + /// application will then get called with information on how long to wait + /// for socket actions at most before doing the timeout action: call the + /// `timeout` method. You can also use the `get_timeout` function to + /// poll the value at any given time, but for an event-based system using + /// the callback is far better than relying on polling the timeout value. + pub fn timeout(&self) -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action( + self.raw, + curl_sys::CURL_SOCKET_BAD, + 0, + &mut remaining + ))); + Ok(remaining as u32) + } + } + + /// Get how long to wait for action before proceeding + /// + /// An application using the libcurl multi interface should call + /// `get_timeout` to figure out how long it should wait for socket actions - + /// at most - before proceeding. + /// + /// Proceeding means either doing the socket-style timeout action: call the + /// `timeout` function, or call `perform` if you're using the simpler and + /// older multi interface approach. + /// + /// The timeout value returned is the duration at this very moment. If 0, it + /// means you should proceed immediately without waiting for anything. If it + /// returns `None`, there's no timeout at all set. + /// + /// Note: if libcurl returns a `None` timeout here, it just means that + /// libcurl currently has no stored timeout value. You must not wait too + /// long (more than a few seconds perhaps) before you call `perform` again. + pub fn get_timeout(&self) -> Result, MultiError> { + let mut ms = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_timeout(self.raw, &mut ms))); + if ms == -1 { + Ok(None) + } else { + Ok(Some(Duration::from_millis(ms as u64))) + } + } + } + + /// Block until activity is detected or a timeout passes. + /// + /// The timeout is used in millisecond-precision. Large durations are + /// clamped at the maximum value curl accepts. + /// + /// The returned integer will contain the number of internal file + /// descriptors on which interesting events occured. + /// + /// This function is a simpler alternative to using `fdset()` and `select()` + /// and does not suffer from file descriptor limits. + /// + /// # Example + /// + /// ``` + /// use curl::multi::Multi; + /// use std::time::Duration; + /// + /// let m = Multi::new(); + /// + /// // Add some Easy handles... + /// + /// while m.perform().unwrap() > 0 { + /// m.wait(&mut [], Duration::from_secs(1)).unwrap(); + /// } + /// ``` + pub fn wait(&self, waitfds: &mut [WaitFd], timeout: Duration) -> Result { + let timeout_ms = { + let secs = timeout.as_secs(); + if secs > (i32::max_value() / 1000) as u64 { + // Duration too large, clamp at maximum value. + i32::max_value() + } else { + secs as i32 * 1000 + timeout.subsec_nanos() as i32 / 1000_000 + } + }; + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_wait( + self.raw, + waitfds.as_mut_ptr() as *mut _, + waitfds.len() as u32, + timeout_ms, + &mut ret + ))); + Ok(ret as u32) + } + } + + /// Reads/writes available data from each easy handle. + /// + /// This function handles transfers on all the added handles that need + /// attention in an non-blocking fashion. + /// + /// When an application has found out there's data available for this handle + /// or a timeout has elapsed, the application should call this function to + /// read/write whatever there is to read or write right now etc. This + /// method returns as soon as the reads/writes are done. This function does + /// not require that there actually is any data available for reading or + /// that data can be written, it can be called just in case. It will return + /// the number of handles that still transfer data. + /// + /// If the amount of running handles is changed from the previous call (or + /// is less than the amount of easy handles you've added to the multi + /// handle), you know that there is one or more transfers less "running". + /// You can then call `info` to get information about each individual + /// completed transfer, and that returned info includes `Error` and more. + /// If an added handle fails very quickly, it may never be counted as a + /// running handle. + /// + /// When running_handles is set to zero (0) on the return of this function, + /// there is no longer any transfers in progress. + /// + /// # Return + /// + /// Before libcurl version 7.20.0: If you receive `is_call_perform`, this + /// basically means that you should call `perform` again, before you select + /// on more actions. You don't have to do it immediately, but the return + /// code means that libcurl may have more data available to return or that + /// there may be more data to send off before it is "satisfied". Do note + /// that `perform` will return `is_call_perform` only when it wants to be + /// called again immediately. When things are fine and there is nothing + /// immediate it wants done, it'll return `Ok` and you need to wait for + /// "action" and then call this function again. + /// + /// This function only returns errors etc regarding the whole multi stack. + /// Problems still might have occurred on individual transfers even when + /// this function returns `Ok`. Use `info` to figure out how individual + /// transfers did. + pub fn perform(&self) -> Result { + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_perform(self.raw, &mut ret))); + Ok(ret as u32) + } + } + + /// Extracts file descriptor information from a multi handle + /// + /// This function extracts file descriptor information from a given + /// handle, and libcurl returns its `fd_set` sets. The application can use + /// these to `select()` on, but be sure to `FD_ZERO` them before calling + /// this function as curl_multi_fdset only adds its own descriptors, it + /// doesn't zero or otherwise remove any others. The curl_multi_perform + /// function should be called as soon as one of them is ready to be read + /// from or written to. + /// + /// If no file descriptors are set by libcurl, this function will return + /// `Ok(None)`. Otherwise `Ok(Some(n))` will be returned where `n` the + /// highest descriptor number libcurl set. When `Ok(None)` is returned it + /// is because libcurl currently does something that isn't possible for + /// your application to monitor with a socket and unfortunately you can + /// then not know exactly when the current action is completed using + /// `select()`. You then need to wait a while before you proceed and call + /// `perform` anyway. + /// + /// When doing `select()`, you should use `get_timeout` to figure out + /// how long to wait for action. Call `perform` even if no activity has + /// been seen on the `fd_set`s after the timeout expires as otherwise + /// internal retries and timeouts may not work as you'd think and want. + /// + /// If one of the sockets used by libcurl happens to be larger than what + /// can be set in an `fd_set`, which on POSIX systems means that the file + /// descriptor is larger than `FD_SETSIZE`, then libcurl will try to not + /// set it. Setting a too large file descriptor in an `fd_set` implies an out + /// of bounds write which can cause crashes, or worse. The effect of NOT + /// storing it will possibly save you from the crash, but will make your + /// program NOT wait for sockets it should wait for... + pub fn fdset2( + &self, + read: Option<&mut curl_sys::fd_set>, + write: Option<&mut curl_sys::fd_set>, + except: Option<&mut curl_sys::fd_set>, + ) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset( + self.raw, read, write, except, &mut ret + ))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + #[doc(hidden)] + #[deprecated(note = "renamed to fdset2")] + pub fn fdset( + &self, + read: Option<&mut fd_set>, + write: Option<&mut fd_set>, + except: Option<&mut fd_set>, + ) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset( + self.raw, + read as *mut _, + write as *mut _, + except as *mut _, + &mut ret + ))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + /// Attempt to close the multi handle and clean up all associated resources. + /// + /// Cleans up and removes a whole multi stack. It does not free or touch any + /// individual easy handles in any way - they still need to be closed + /// individually. + pub fn close(&self) -> Result<(), MultiError> { + unsafe { cvt(curl_sys::curl_multi_cleanup(self.raw)) } + } +} + +fn cvt(code: curl_sys::CURLMcode) -> Result<(), MultiError> { + if code == curl_sys::CURLM_OK { + Ok(()) + } else { + Err(MultiError::new(code)) + } +} + +impl fmt::Debug for Multi { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Multi").field("raw", &self.raw).finish() + } +} + +impl Drop for Multi { + fn drop(&mut self) { + let _ = self.close(); + } +} + +impl EasyHandle { + /// Sets an internal private token for this `EasyHandle`. + /// + /// This function will set the `CURLOPT_PRIVATE` field on the underlying + /// easy handle. + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt( + self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token, + )) + } + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl fmt::Debug for EasyHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl Easy2Handle { + /// Acquires a reference to the underlying handler for events. + pub fn get_ref(&self) -> &H { + self.easy.get_ref() + } + + /// Acquires a reference to the underlying handler for events. + pub fn get_mut(&mut self) -> &mut H { + self.easy.get_mut() + } + + /// Same as `EasyHandle::set_token` + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt( + self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token, + )) + } + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl fmt::Debug for Easy2Handle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl<'multi> Message<'multi> { + /// If this message indicates that a transfer has finished, returns the + /// result of the transfer in `Some`. + /// + /// If the message doesn't indicate that a transfer has finished, then + /// `None` is returned. + /// + /// Note that the `result*_for` methods below should be preferred as they + /// provide better error messages as the associated error data on the + /// handle can be associated with the error type. + pub fn result(&self) -> Option> { + unsafe { + if (*self.ptr).msg == curl_sys::CURLMSG_DONE { + Some(::cvt((*self.ptr).data as curl_sys::CURLcode)) + } else { + None + } + } + } + + /// Same as `result`, except only returns `Some` for the specified handle. + /// + /// Note that this function produces better error messages than `result` as + /// it uses `take_error_buf` to associate error information with the + /// returned error. + pub fn result_for(&self, handle: &EasyHandle) -> Option> { + if !self.is_for(handle) { + return None; + } + let mut err = self.result(); + if let Some(Err(e)) = &mut err { + if let Some(s) = handle.easy.take_error_buf() { + e.set_extra(s); + } + } + return err; + } + + /// Same as `result`, except only returns `Some` for the specified handle. + /// + /// Note that this function produces better error messages than `result` as + /// it uses `take_error_buf` to associate error information with the + /// returned error. + pub fn result_for2(&self, handle: &Easy2Handle) -> Option> { + if !self.is_for2(handle) { + return None; + } + let mut err = self.result(); + if let Some(Err(e)) = &mut err { + if let Some(s) = handle.easy.take_error_buf() { + e.set_extra(s); + } + } + return err; + } + + /// Returns whether this easy message was for the specified easy handle or + /// not. + pub fn is_for(&self, handle: &EasyHandle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Same as `is_for`, but for `Easy2Handle`. + pub fn is_for2(&self, handle: &Easy2Handle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Returns the token associated with the easy handle that this message + /// represents a completion for. + /// + /// This function will return the token assigned with + /// `EasyHandle::set_token`. This reads the `CURLINFO_PRIVATE` field of the + /// underlying `*mut CURL`. + pub fn token(&self) -> Result { + unsafe { + let mut p = 0usize; + try!(::cvt(curl_sys::curl_easy_getinfo( + (*self.ptr).easy_handle, + curl_sys::CURLINFO_PRIVATE, + &mut p + ))); + Ok(p) + } + } +} + +impl<'a> fmt::Debug for Message<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Message").field("ptr", &self.ptr).finish() + } +} + +impl Events { + /// Creates a new blank event bit mask. + pub fn new() -> Events { + Events { bits: 0 } + } + + /// Set or unset the whether these events indicate that input is ready. + pub fn input(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_IN, val) + } + + /// Set or unset the whether these events indicate that output is ready. + pub fn output(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_OUT, val) + } + + /// Set or unset the whether these events indicate that an error has + /// happened. + pub fn error(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_ERR, val) + } + + fn flag(&mut self, flag: c_int, val: bool) -> &mut Events { + if val { + self.bits |= flag; + } else { + self.bits &= !flag; + } + self + } +} + +impl fmt::Debug for Events { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("output", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("error", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .finish() + } +} + +impl SocketEvents { + /// Wait for incoming data. For the socket to become readable. + pub fn input(&self) -> bool { + self.bits & curl_sys::CURL_POLL_IN == curl_sys::CURL_POLL_IN + } + + /// Wait for outgoing data. For the socket to become writable. + pub fn output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_OUT == curl_sys::CURL_POLL_OUT + } + + /// Wait for incoming and outgoing data. For the socket to become readable + /// or writable. + pub fn input_and_output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_INOUT == curl_sys::CURL_POLL_INOUT + } + + /// The specified socket/file descriptor is no longer used by libcurl. + pub fn remove(&self) -> bool { + self.bits & curl_sys::CURL_POLL_REMOVE == curl_sys::CURL_POLL_REMOVE + } +} + +impl fmt::Debug for SocketEvents { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &self.input()) + .field("output", &self.output()) + .field("remove", &self.remove()) + .finish() + } +} + +impl WaitFd { + /// Constructs an empty (invalid) WaitFd. + pub fn new() -> WaitFd { + WaitFd { + inner: curl_sys::curl_waitfd { + fd: 0, + events: 0, + revents: 0, + }, + } + } + + /// Set the file descriptor to wait for. + pub fn set_fd(&mut self, fd: Socket) { + self.inner.fd = fd; + } + + /// Indicate that the socket should poll on read events such as new data + /// received. + /// + /// Corresponds to `CURL_WAIT_POLLIN`. + pub fn poll_on_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLIN, val) + } + + /// Indicate that the socket should poll on high priority read events such + /// as out of band data. + /// + /// Corresponds to `CURL_WAIT_POLLPRI`. + pub fn poll_on_priority_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLPRI, val) + } + + /// Indicate that the socket should poll on write events such as the socket + /// being clear to write without blocking. + /// + /// Corresponds to `CURL_WAIT_POLLOUT`. + pub fn poll_on_write(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLOUT, val) + } + + fn flag(&mut self, flag: c_short, val: bool) -> &mut WaitFd { + if val { + self.inner.events |= flag; + } else { + self.inner.events &= !flag; + } + self + } + + /// After a call to `wait`, returns `true` if `poll_on_read` was set and a + /// read event occured. + pub fn received_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLIN == curl_sys::CURL_WAIT_POLLIN + } + + /// After a call to `wait`, returns `true` if `poll_on_priority_read` was set and a + /// priority read event occured. + pub fn received_priority_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLPRI == curl_sys::CURL_WAIT_POLLPRI + } + + /// After a call to `wait`, returns `true` if `poll_on_write` was set and a + /// write event occured. + pub fn received_write(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLOUT == curl_sys::CURL_WAIT_POLLOUT + } +} + +#[cfg(unix)] +impl From for WaitFd { + fn from(pfd: pollfd) -> WaitFd { + let mut events = 0; + if pfd.events & POLLIN == POLLIN { + events |= curl_sys::CURL_WAIT_POLLIN; + } + if pfd.events & POLLPRI == POLLPRI { + events |= curl_sys::CURL_WAIT_POLLPRI; + } + if pfd.events & POLLOUT == POLLOUT { + events |= curl_sys::CURL_WAIT_POLLOUT; + } + WaitFd { + inner: curl_sys::curl_waitfd { + fd: pfd.fd, + events: events, + revents: 0, + }, + } + } +} + +impl fmt::Debug for WaitFd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("WaitFd") + .field("fd", &self.inner.fd) + .field("events", &self.inner.fd) + .field("revents", &self.inner.fd) + .finish() + } +} diff --git a/curl/src/panic.rs b/curl/src/panic.rs new file mode 100644 index 000000000..b587c2be5 --- /dev/null +++ b/curl/src/panic.rs @@ -0,0 +1,34 @@ +use std::any::Any; +use std::cell::RefCell; +use std::panic::{self, AssertUnwindSafe}; + +thread_local!(static LAST_ERROR: RefCell>> = { + RefCell::new(None) +}); + +pub fn catch T>(f: F) -> Option { + match LAST_ERROR.try_with(|slot| slot.borrow().is_some()) { + Ok(true) => return None, + Ok(false) => {} + // we're in thread shutdown, so we're for sure not panicking and + // panicking again will abort, so no need to worry! + Err(_) => {} + } + + // Note that `AssertUnwindSafe` is used here as we prevent reentering + // arbitrary code due to the `LAST_ERROR` check above plus propagation of a + // panic after we return back to user code from C. + match panic::catch_unwind(AssertUnwindSafe(f)) { + Ok(ret) => Some(ret), + Err(e) => { + LAST_ERROR.with(|slot| *slot.borrow_mut() = Some(e)); + None + } + } +} + +pub fn propagate() { + if let Ok(Some(t)) = LAST_ERROR.try_with(|slot| slot.borrow_mut().take()) { + panic::resume_unwind(t) + } +} diff --git a/curl/src/version.rs b/curl/src/version.rs new file mode 100644 index 000000000..3d64b1dd4 --- /dev/null +++ b/curl/src/version.rs @@ -0,0 +1,315 @@ +use std::ffi::CStr; +use std::fmt; +use std::str; + +use curl_sys; +use libc::{c_char, c_int}; + +/// Version information about libcurl and the capabilities that it supports. +pub struct Version { + inner: *mut curl_sys::curl_version_info_data, +} + +unsafe impl Send for Version {} +unsafe impl Sync for Version {} + +/// An iterator over the list of protocols a version supports. +#[derive(Clone)] +pub struct Protocols<'a> { + cur: *const *const c_char, + _inner: &'a Version, +} + +impl Version { + /// Returns the libcurl version that this library is currently linked against. + pub fn num() -> &'static str { + unsafe { + let s = CStr::from_ptr(curl_sys::curl_version() as *const _); + str::from_utf8(s.to_bytes()).unwrap() + } + } + + /// Returns the libcurl version that this library is currently linked against. + pub fn get() -> Version { + unsafe { + let ptr = curl_sys::curl_version_info(curl_sys::CURLVERSION_FOURTH); + assert!(!ptr.is_null()); + Version { inner: ptr } + } + } + + /// Returns the human readable version string, + pub fn version(&self) -> &str { + unsafe { ::opt_str((*self.inner).version).unwrap() } + } + + /// Returns a numeric representation of the version number + /// + /// This is a 24 bit number made up of the major number, minor, and then + /// patch number. For example 7.9.8 will return 0x070908. + pub fn version_num(&self) -> u32 { + unsafe { (*self.inner).version_num as u32 } + } + + /// Returns a human readable string of the host libcurl is built for. + /// + /// This is discovered as part of the build environment. + pub fn host(&self) -> &str { + unsafe { ::opt_str((*self.inner).host).unwrap() } + } + + /// Returns whether libcurl supports IPv6 + pub fn feature_ipv6(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_IPV6) + } + + /// Returns whether libcurl supports SSL + pub fn feature_ssl(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SSL) + } + + /// Returns whether libcurl supports HTTP deflate via libz + pub fn feature_libz(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_LIBZ) + } + + /// Returns whether libcurl supports HTTP NTLM + pub fn feature_ntlm(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_NTLM) + } + + /// Returns whether libcurl supports HTTP GSSNEGOTIATE + pub fn feature_gss_negotiate(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_GSSNEGOTIATE) + } + + /// Returns whether libcurl was built with debug capabilities + pub fn feature_debug(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_DEBUG) + } + + /// Returns whether libcurl was built with SPNEGO authentication + pub fn feature_spnego(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SPNEGO) + } + + /// Returns whether libcurl was built with large file support + pub fn feature_largefile(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_LARGEFILE) + } + + /// Returns whether libcurl was built with support for IDNA, domain names + /// with international letters. + pub fn feature_idn(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_IDN) + } + + /// Returns whether libcurl was built with support for SSPI. + pub fn feature_sspi(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SSPI) + } + + /// Returns whether libcurl was built with asynchronous name lookups. + pub fn feature_async_dns(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_ASYNCHDNS) + } + + /// Returns whether libcurl was built with support for character + /// conversions. + pub fn feature_conv(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_CONV) + } + + /// Returns whether libcurl was built with support for TLS-SRP. + pub fn feature_tlsauth_srp(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_TLSAUTH_SRP) + } + + /// Returns whether libcurl was built with support for NTLM delegation to + /// winbind helper. + pub fn feature_ntlm_wb(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_NTLM_WB) + } + + /// Returns whether libcurl was built with support for unix domain socket + pub fn feature_unix_domain_socket(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_UNIX_SOCKETS) + } + + /// Returns whether libcurl was built with support for HTTP2. + pub fn feature_http2(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_HTTP2) + } + + fn flag(&self, flag: c_int) -> bool { + unsafe { (*self.inner).features & flag != 0 } + } + + /// Returns the version of OpenSSL that is used, or None if there is no SSL + /// support. + pub fn ssl_version(&self) -> Option<&str> { + unsafe { ::opt_str((*self.inner).ssl_version) } + } + + /// Returns the version of libz that is used, or None if there is no libz + /// support. + pub fn libz_version(&self) -> Option<&str> { + unsafe { ::opt_str((*self.inner).libz_version) } + } + + /// Returns an iterator over the list of protocols that this build of + /// libcurl supports. + pub fn protocols(&self) -> Protocols { + unsafe { + Protocols { + _inner: self, + cur: (*self.inner).protocols, + } + } + } + + /// If available, the human readable version of ares that libcurl is linked + /// against. + pub fn ares_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_SECOND { + ::opt_str((*self.inner).ares) + } else { + None + } + } + } + + /// If available, the version of ares that libcurl is linked against. + pub fn ares_version_num(&self) -> Option { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_SECOND { + Some((*self.inner).ares_num as u32) + } else { + None + } + } + } + + /// If available, the version of libidn that libcurl is linked against. + pub fn libidn_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_THIRD { + ::opt_str((*self.inner).libidn) + } else { + None + } + } + } + + /// If available, the version of iconv libcurl is linked against. + pub fn iconv_version_num(&self) -> Option { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_FOURTH { + Some((*self.inner).iconv_ver_num as u32) + } else { + None + } + } + } + + /// If available, the version of libssh that libcurl is linked against. + pub fn libssh_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_FOURTH { + ::opt_str((*self.inner).libssh_version) + } else { + None + } + } + } + + /// If available, the version of brotli libcurl is linked against. + pub fn brotli_version_num(&self) -> Option { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_FIFTH { + Some((*self.inner).brotli_ver_num) + } else { + None + } + } + } + + /// If available, the version of brotli libcurl is linked against. + pub fn brotli_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= curl_sys::CURLVERSION_FIFTH { + ::opt_str((*self.inner).brotli_version) + } else { + None + } + } + } +} + +impl fmt::Debug for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Version"); + f.field("version", &self.version()) + .field("host", &self.host()) + .field("feature_ipv6", &self.feature_ipv6()) + .field("feature_ssl", &self.feature_ssl()) + .field("feature_libz", &self.feature_libz()) + .field("feature_ntlm", &self.feature_ntlm()) + .field("feature_gss_negotiate", &self.feature_gss_negotiate()) + .field("feature_debug", &self.feature_debug()) + .field("feature_spnego", &self.feature_debug()) + .field("feature_largefile", &self.feature_debug()) + .field("feature_idn", &self.feature_debug()) + .field("feature_sspi", &self.feature_debug()) + .field("feature_async_dns", &self.feature_debug()) + .field("feature_conv", &self.feature_debug()) + .field("feature_tlsauth_srp", &self.feature_debug()) + .field("feature_ntlm_wb", &self.feature_debug()) + .field("feature_unix_domain_socket", &self.feature_debug()); + + if let Some(s) = self.ssl_version() { + f.field("ssl_version", &s); + } + if let Some(s) = self.libz_version() { + f.field("libz_version", &s); + } + if let Some(s) = self.ares_version() { + f.field("ares_version", &s); + } + if let Some(s) = self.libidn_version() { + f.field("libidn_version", &s); + } + if let Some(s) = self.iconv_version_num() { + f.field("iconv_version_num", &format!("{:x}", s)); + } + if let Some(s) = self.libssh_version() { + f.field("libssh_version", &s); + } + + f.field("protocols", &self.protocols().collect::>()); + + f.finish() + } +} + +impl<'a> Iterator for Protocols<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + unsafe { + if (*self.cur).is_null() { + return None; + } + let ret = ::opt_str(*self.cur).unwrap(); + self.cur = self.cur.offset(1); + Some(ret) + } + } +} + +impl<'a> fmt::Debug for Protocols<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} diff --git a/curl/tests/atexit.rs b/curl/tests/atexit.rs new file mode 100644 index 000000000..6373c20c7 --- /dev/null +++ b/curl/tests/atexit.rs @@ -0,0 +1,20 @@ +extern crate curl; +extern crate libc; + +use curl::easy::Easy; + +pub extern "C" fn hook() { + let mut easy = Easy::new(); + easy.url("google.com").unwrap(); + easy.write_function(|data| Ok(data.len())).unwrap(); + easy.perform().unwrap(); +} + +fn main() { + curl::init(); + hook(); + unsafe { + libc::atexit(hook); + } + println!("Finishing...") +} diff --git a/curl/tests/easy.rs b/curl/tests/easy.rs new file mode 100644 index 000000000..3096e5267 --- /dev/null +++ b/curl/tests/easy.rs @@ -0,0 +1,809 @@ +extern crate curl; + +use std::cell::{Cell, RefCell}; +use std::io::Read; +use std::rc::Rc; +use std::str; +use std::time::Duration; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + } + }; +} + +use curl::easy::{Easy, List, ReadError, Transfer, WriteError}; + +use server::Server; +mod server; + +fn handle() -> Easy { + let mut e = Easy::new(); + t!(e.timeout(Duration::new(20, 0))); + return e; +} + +fn sink(data: &[u8]) -> Result { + Ok(data.len()) +} + +#[test] +fn get_smoke() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + t!(handle.perform()); +} + +#[test] +fn get_path() { + let s = Server::new(); + s.receive( + "\ + GET /foo HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + t!(handle.url(&s.url("/foo"))); + t!(handle.perform()); +} + +#[test] +fn write_callback() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\nhello!"); + + let mut all = Vec::::new(); + { + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + let mut handle = handle.transfer(); + t!(handle.write_function(|data| { + all.extend(data); + Ok(data.len()) + })); + t!(handle.perform()); + } + assert_eq!(all, b"hello!"); +} + +#[test] +fn resolve() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: example.com:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut list = List::new(); + t!(list.append(&format!("example.com:{}:127.0.0.1", s.addr().port()))); + let mut handle = handle(); + t!(handle.url(&format!("http://example.com:{}/", s.addr().port()))); + t!(handle.resolve(list)); + t!(handle.perform()); +} + +#[test] +fn progress() { + let s = Server::new(); + s.receive( + "\ + GET /foo HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\nHello!"); + + let mut hits = 0; + let mut dl = 0.0; + { + let mut handle = handle(); + t!(handle.url(&s.url("/foo"))); + t!(handle.progress(true)); + t!(handle.write_function(sink)); + + let mut handle = handle.transfer(); + t!(handle.progress_function(|_, a, _, _| { + hits += 1; + dl = a; + true + })); + t!(handle.perform()); + } + assert!(hits > 0); + assert_eq!(dl, 6.0); +} + +#[test] +fn headers() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ +HTTP/1.1 200 OK\r\n\ +Foo: bar\r\n\ +Bar: baz\r\n\ +\r\n +Hello!", + ); + + let mut headers = Vec::new(); + { + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + + let mut handle = handle.transfer(); + t!(handle.header_function(|h| { + headers.push(str::from_utf8(h).unwrap().to_string()); + true + })); + t!(handle.write_function(sink)); + t!(handle.perform()); + } + assert_eq!( + headers, + vec![ + "HTTP/1.1 200 OK\r\n".to_string(), + "Foo: bar\r\n".to_string(), + "Bar: baz\r\n".to_string(), + "\r\n".to_string(), + ] + ); +} + +#[test] +fn fail_on_error() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 401 Not so good\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.fail_on_error(true)); + assert!(h.perform().is_err()); + + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 401 Not so good\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.fail_on_error(false)); + t!(h.perform()); +} + +#[test] +fn port() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: localhost:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url("http://localhost/")); + t!(h.port(s.addr().port())); + t!(h.perform()); +} + +#[test] +fn proxy() { + let s = Server::new(); + s.receive( + "\ + GET http://example.com/ HTTP/1.1\r\n\ + Host: example.com\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url("http://example.com/")); + t!(h.proxy(&s.url("/"))); + t!(h.perform()); +} + +#[test] +#[ignore] // fails on newer curl versions? seems benign +fn noproxy() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.proxy(&s.url("/"))); + t!(h.noproxy("127.0.0.1")); + t!(h.perform()); +} + +#[test] +fn misc() { + let mut h = handle(); + t!(h.tcp_nodelay(true)); + // t!(h.tcp_keepalive(true)); + // t!(h.tcp_keepidle(Duration::new(3, 0))); + // t!(h.tcp_keepintvl(Duration::new(3, 0))); + t!(h.buffer_size(10)); + t!(h.dns_cache_timeout(Duration::new(1, 0))); +} + +#[test] +fn dns_servers() { + let mut h = handle(); + // Tests are not using a libcurl with c-ares, so this + // always fails. Test anyway to make sure it returns + // an error instead of panicing. + assert!(h.dns_servers("").is_err()); + assert!(h.dns_servers("nonsense").is_err()); + assert!(h.dns_servers("8.8.8.8,8.8.4.4").is_err()); +} + +#[test] +fn userpass() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Authorization: Basic YmFyOg==\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.username("foo")); + t!(h.username("bar")); + t!(h.perform()); +} + +#[test] +fn accept_encoding() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Accept-Encoding: gzip\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.accept_encoding("gzip")); + t!(h.perform()); +} + +#[test] +fn follow_location() { + let s1 = Server::new(); + let s2 = Server::new(); + s1.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s1.send(&format!( + "\ + HTTP/1.1 301 Moved Permanently\r\n\ + Location: http://{}/foo\r\n\ + \r\n", + s2.addr() + )); + + s2.receive( + "\ + GET /foo HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s2.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s1.url("/"))); + t!(h.follow_location(true)); + t!(h.perform()); +} + +#[test] +fn put() { + let s = Server::new(); + s.receive( + "\ + PUT / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 5\r\n\ + \r\n\ + data\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut data = "data\n".as_bytes(); + let mut list = List::new(); + t!(list.append("Expect:")); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.put(true)); + t!(h.in_filesize(5)); + t!(h.upload(true)); + t!(h.http_headers(list)); + let mut h = h.transfer(); + t!(h.read_function(|buf| Ok(data.read(buf).unwrap()))); + t!(h.perform()); +} + +#[test] +fn post1() { + let s = Server::new(); + s.receive( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 5\r\n\ + Content-Type: application/x-www-form-urlencoded\r\n\ + \r\n\ + data\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_fields_copy(b"data\n")); + t!(h.perform()); +} + +#[test] +fn post2() { + let s = Server::new(); + s.receive( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 5\r\n\ + Content-Type: application/x-www-form-urlencoded\r\n\ + \r\n\ + data\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_fields_copy(b"data\n")); + t!(h.write_function(sink)); + t!(h.perform()); +} + +#[test] +fn post3() { + let s = Server::new(); + s.receive( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 5\r\n\ + Content-Type: application/x-www-form-urlencoded\r\n\ + \r\n\ + data\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut data = "data\n".as_bytes(); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_field_size(5)); + let mut h = h.transfer(); + t!(h.read_function(|buf| Ok(data.read(buf).unwrap()))); + t!(h.perform()); +} + +#[test] +fn referer() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Referer: foo\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.referer("foo")); + t!(h.perform()); +} + +#[test] +fn useragent() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + User-Agent: foo\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.useragent("foo")); + t!(h.perform()); +} + +#[test] +fn custom_headers() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Foo: bar\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut custom = List::new(); + t!(custom.append("Foo: bar")); + t!(custom.append("Accept:")); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.http_headers(custom)); + t!(h.perform()); +} + +#[test] +fn cookie() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Cookie: foo\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.cookie("foo")); + t!(h.perform()); +} + +#[test] +fn url_encoding() { + let mut h = handle(); + assert_eq!(h.url_encode(b"foo"), "foo"); + assert_eq!(h.url_encode(b"foo bar"), "foo%20bar"); + assert_eq!(h.url_encode(b"foo bar\xff"), "foo%20bar%FF"); + assert_eq!(h.url_encode(b""), ""); + assert_eq!(h.url_decode("foo"), b"foo"); + assert_eq!(h.url_decode("foo%20bar"), b"foo bar"); + assert_eq!(h.url_decode("foo%2"), b"foo%2"); + assert_eq!(h.url_decode("foo%xx"), b"foo%xx"); + assert_eq!(h.url_decode("foo%ff"), b"foo\xff"); + assert_eq!(h.url_decode(""), b""); +} + +#[test] +fn getters() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.cookie_file("/dev/null")); + t!(h.perform()); + assert_eq!(t!(h.response_code()), 200); + assert_eq!(t!(h.redirect_count()), 0); + assert_eq!(t!(h.redirect_url()), None); + assert_eq!(t!(h.content_type()), None); + + let addr = format!("http://{}/", s.addr()); + assert_eq!(t!(h.effective_url()), Some(&addr[..])); + + // TODO: test this + // let cookies = t!(h.cookies()).iter() + // .map(|s| s.to_vec()) + // .collect::>(); + // assert_eq!(cookies.len(), 1); +} + +#[test] +#[should_panic] +fn panic_in_callback() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.header_function(|_| panic!())); + t!(h.perform()); +} + +#[test] +fn abort_read() { + let s = Server::new(); + s.receive( + "\ + PUT / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 2\r\n\ + \r\n", + ); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.read_function(|_| Err(ReadError::Abort))); + t!(h.put(true)); + t!(h.in_filesize(2)); + let mut list = List::new(); + t!(list.append("Expect:")); + t!(h.http_headers(list)); + let err = h.perform().unwrap_err(); + assert!(err.is_aborted_by_callback()); +} + +#[test] +fn pause_write_then_resume() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ +HTTP/1.1 200 OK\r\n\ +\r\n +a\n +b", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.progress(true)); + + struct State<'a, 'b> { + paused: Cell, + unpaused: Cell, + transfer: RefCell>, + } + + let h = Rc::new(State { + paused: Cell::new(false), + unpaused: Cell::new(false), + transfer: RefCell::new(h.transfer()), + }); + + let h2 = h.clone(); + t!(h.transfer + .borrow_mut() + .write_function(move |data| if h2.unpaused.get() { + h2.unpaused.set(false); + Ok(data.len()) + } else { + h2.paused.set(true); + Err(WriteError::Pause) + })); + let h2 = h.clone(); + t!(h.transfer + .borrow_mut() + .progress_function(move |_, _, _, _| { + if h2.paused.get() { + h2.paused.set(false); + h2.unpaused.set(true); + t!(h2.transfer.borrow().unpause_write()); + } + true + })); + t!(h.transfer.borrow().perform()); +} + +#[test] +fn perform_in_perform_is_bad() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send( + "\ +HTTP/1.1 200 OK\r\n\ +\r\n +a\n +b", + ); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.progress(true)); + + let h = Rc::new(RefCell::new(h.transfer())); + + let h2 = h.clone(); + t!(h.borrow_mut().write_function(move |data| { + assert!(h2.borrow().perform().is_err()); + Ok(data.len()) + })); + t!(h.borrow().perform()); +} + +// Stupid test to check if unix_socket is callable +#[test] +fn check_unix_socket() { + let mut h = handle(); + h.unix_socket("/var/something.socks").is_ok(); +} diff --git a/curl/tests/formdata b/curl/tests/formdata new file mode 100644 index 000000000..ce0136250 --- /dev/null +++ b/curl/tests/formdata @@ -0,0 +1 @@ +hello diff --git a/curl/tests/multi.rs b/curl/tests/multi.rs new file mode 100644 index 000000000..e084a1fd7 --- /dev/null +++ b/curl/tests/multi.rs @@ -0,0 +1,269 @@ +#![cfg(unix)] + +extern crate curl; +extern crate mio; +extern crate mio_extras; + +use std::collections::HashMap; +use std::io::{Cursor, Read}; +use std::time::Duration; + +use curl::easy::{Easy, List}; +use curl::multi::Multi; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + } + }; +} + +use server::Server; +mod server; + +#[test] +fn smoke() { + let m = Multi::new(); + let mut e = Easy::new(); + + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + t!(e.url(&s.url("/"))); + let _e = t!(m.add(e)); + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } +} + +#[test] +fn smoke2() { + let m = Multi::new(); + + let s1 = Server::new(); + s1.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s1.send("HTTP/1.1 200 OK\r\n\r\n"); + + let s2 = Server::new(); + s2.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s2.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut e1 = Easy::new(); + t!(e1.url(&s1.url("/"))); + let _e1 = t!(m.add(e1)); + let mut e2 = Easy::new(); + t!(e2.url(&s2.url("/"))); + let _e2 = t!(m.add(e2)); + + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } + + let mut done = 0; + m.messages(|msg| { + msg.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 2); +} + +#[test] +fn upload_lots() { + use curl::multi::{Events, Socket, SocketEvents}; + + #[derive(Debug)] + enum Message { + Timeout(Option), + Wait(Socket, SocketEvents, usize), + } + + let mut m = Multi::new(); + let poll = t!(mio::Poll::new()); + let (tx, rx) = mio_extras::channel::channel(); + let tx2 = tx.clone(); + t!(m.socket_function(move |socket, events, token| { + t!(tx2.send(Message::Wait(socket, events, token))); + })); + t!(m.timer_function(move |dur| { + t!(tx.send(Message::Timeout(dur))); + true + })); + + let s = Server::new(); + s.receive(&format!( + "\ + PUT / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 131072\r\n\ + \r\n\ + {}\n", + vec!["a"; 128 * 1024 - 1].join("") + )); + s.send( + "\ + HTTP/1.1 200 OK\r\n\ + \r\n", + ); + + let mut data = vec![b'a'; 128 * 1024 - 1]; + data.push(b'\n'); + let mut data = Cursor::new(data); + let mut list = List::new(); + t!(list.append("Expect:")); + let mut h = Easy::new(); + t!(h.url(&s.url("/"))); + t!(h.put(true)); + t!(h.read_function(move |buf| Ok(data.read(buf).unwrap()))); + t!(h.in_filesize(128 * 1024)); + t!(h.upload(true)); + t!(h.http_headers(list)); + + t!(poll.register(&rx, mio::Token(0), mio::Ready::all(), mio::PollOpt::level())); + + let e = t!(m.add(h)); + + assert!(t!(m.perform()) > 0); + let mut next_token = 1; + let mut token_map = HashMap::new(); + let mut cur_timeout = None; + let mut events = mio::Events::with_capacity(128); + let mut running = true; + + while running { + let n = t!(poll.poll(&mut events, cur_timeout)); + + if n == 0 { + if t!(m.timeout()) == 0 { + running = false; + } + } + + for event in events.iter() { + while event.token() == mio::Token(0) { + match rx.try_recv() { + Ok(Message::Timeout(dur)) => cur_timeout = dur, + Ok(Message::Wait(socket, events, token)) => { + let evented = mio::unix::EventedFd(&socket); + if events.remove() { + token_map.remove(&token).unwrap(); + } else { + let mut e = mio::Ready::none(); + if events.input() { + e = e | mio::Ready::readable(); + } + if events.output() { + e = e | mio::Ready::writable(); + } + if token == 0 { + let token = next_token; + next_token += 1; + t!(m.assign(socket, token)); + token_map.insert(token, socket); + t!(poll.register( + &evented, + mio::Token(token), + e, + mio::PollOpt::level() + )); + } else { + t!(poll.reregister( + &evented, + mio::Token(token), + e, + mio::PollOpt::level() + )); + } + } + } + Err(_) => break, + } + } + + if event.token() == mio::Token(0) { + continue; + } + + let token = event.token(); + let socket = token_map[&token.into()]; + let mut e = Events::new(); + if event.kind().is_readable() { + e.input(true); + } + if event.kind().is_writable() { + e.output(true); + } + if event.kind().is_error() { + e.error(true); + } + let remaining = t!(m.action(socket, &e)); + if remaining == 0 { + running = false; + } + } + } + + let mut done = 0; + m.messages(|m| { + m.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 1); + + let mut e = t!(m.remove(e)); + assert_eq!(t!(e.response_code()), 200); +} + +// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the +// semantics of the underlying poll(2) system call used by curl apparently differ on other +// platforms, making the test fail. +#[cfg(target_os = "linux")] +#[test] +fn waitfds() { + use curl::multi::WaitFd; + use std::fs::File; + use std::os::unix::io::AsRawFd; + + let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"]; + let files: Vec = filenames + .iter() + .map(|filename| File::open(filename).unwrap()) + .collect(); + let mut waitfds: Vec = files + .iter() + .map(|f| { + let mut waitfd = WaitFd::new(); + waitfd.set_fd(f.as_raw_fd()); + waitfd.poll_on_read(true); + waitfd + }) + .collect(); + + let m = Multi::new(); + let events = t!(m.wait(&mut waitfds, Duration::from_secs(1))); + assert_eq!(events, 3); + for waitfd in waitfds { + assert!(waitfd.received_read()); + } +} diff --git a/curl/tests/post.rs b/curl/tests/post.rs new file mode 100644 index 000000000..eb1082eb5 --- /dev/null +++ b/curl/tests/post.rs @@ -0,0 +1,120 @@ +extern crate curl; + +use std::time::Duration; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + } + }; +} + +use curl::easy::{Easy, Form, List}; + +use server::Server; +mod server; + +fn handle() -> Easy { + let mut e = Easy::new(); + t!(e.timeout(Duration::new(20, 0))); + let mut list = List::new(); + t!(list.append("Expect:")); + t!(e.http_headers(list)); + return e; +} + +#[test] +fn custom() { + let s = Server::new(); + s.receive( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 142\r\n\ + Content-Type: multipart/form-data; boundary=--[..]\r\n\ + \r\n\ + --[..]\r\n\ + Content-Disposition: form-data; name=\"foo\"\r\n\ + \r\n\ + 1234\r\n\ + --[..]\r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form.part("foo").contents(b"1234").add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} + +#[test] +fn buffer() { + let s = Server::new(); + s.receive( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: 181\r\n\ + Content-Type: multipart/form-data; boundary=--[..]\r\n\ + \r\n\ + --[..]\r\n\ + Content-Disposition: form-data; name=\"foo\"; filename=\"bar\"\r\n\ + Content-Type: foo/bar\r\n\ + \r\n\ + 1234\r\n\ + --[..]\r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form + .part("foo") + .buffer("bar", b"1234".to_vec()) + .content_type("foo/bar") + .add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} + +#[test] +fn file() { + let s = Server::new(); + let formdata = include_str!("formdata"); + s.receive( + format!( + "\ + POST / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + Content-Length: {}\r\n\ + Content-Type: multipart/form-data; boundary=--[..]\r\n\ + \r\n\ + --[..]\r\n\ + Content-Disposition: form-data; name=\"foo\"; filename=\"formdata\"\r\n\ + Content-Type: application/octet-stream\r\n\ + \r\n\ + {}\ + \r\n\ + --[..]\r\n", + 199 + formdata.len(), + formdata + ) + .as_str(), + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form.part("foo").file("tests/formdata").add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} diff --git a/curl/tests/server/mod.rs b/curl/tests/server/mod.rs new file mode 100644 index 000000000..17eb34005 --- /dev/null +++ b/curl/tests/server/mod.rs @@ -0,0 +1,178 @@ +#![allow(dead_code)] + +use std::collections::HashSet; +use std::io::prelude::*; +use std::io::BufReader; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::thread; + +pub struct Server { + messages: Option>, + addr: SocketAddr, + thread: Option>, +} + +enum Message { + Read(String), + Write(String), +} + +fn run(listener: &TcpListener, rx: &Receiver) { + let mut socket = BufReader::new(listener.accept().unwrap().0); + for msg in rx.iter() { + match msg { + Message::Read(ref expected) => { + let mut expected = &expected[..]; + let mut expected_headers = HashSet::new(); + while let Some(i) = expected.find("\n") { + let line = &expected[..i + 1]; + expected = &expected[i + 1..]; + expected_headers.insert(line); + if line == "\r\n" { + break; + } + } + + let mut expected_len = None; + while expected_headers.len() > 0 { + let mut actual = String::new(); + t!(socket.read_line(&mut actual)); + if actual.starts_with("Content-Length") { + let len = actual.split(": ").skip(1).next().unwrap(); + expected_len = len.trim().parse().ok(); + } + // various versions of libcurl do different things here + if actual == "Proxy-Connection: Keep-Alive\r\n" { + continue; + } + if expected_headers.remove(&actual[..]) { + continue; + } + + let mut found = None; + for header in expected_headers.iter() { + if lines_match(header, &actual) { + found = Some(header.clone()); + break; + } + } + if let Some(found) = found { + expected_headers.remove(&found); + continue; + } + panic!( + "unexpected header: {:?} (remaining headers {:?})", + actual, expected_headers + ); + } + for header in expected_headers { + panic!("expected header but not found: {:?}", header); + } + + let mut line = String::new(); + let mut socket = match expected_len { + Some(amt) => socket.by_ref().take(amt), + None => socket.by_ref().take(expected.len() as u64), + }; + while socket.limit() > 0 { + line.truncate(0); + t!(socket.read_line(&mut line)); + if line.len() == 0 { + break; + } + if expected.len() == 0 { + panic!("unexpected line: {:?}", line); + } + let i = expected.find("\n").unwrap_or(expected.len() - 1); + let expected_line = &expected[..i + 1]; + expected = &expected[i + 1..]; + if lines_match(expected_line, &line) { + continue; + } + panic!( + "lines didn't match:\n\ + expected: {:?}\n\ + actual: {:?}\n", + expected_line, line + ) + } + if expected.len() != 0 { + println!("didn't get expected data: {:?}", expected); + } + } + Message::Write(ref to_write) => { + t!(socket.get_mut().write_all(to_write.as_bytes())); + return; + } + } + } + + let mut dst = Vec::new(); + t!(socket.read_to_end(&mut dst)); + assert!(dst.len() == 0); +} + +fn lines_match(expected: &str, mut actual: &str) -> bool { + for (i, part) in expected.split("[..]").enumerate() { + match actual.find(part) { + Some(j) => { + if i == 0 && j != 0 { + return false; + } + actual = &actual[j + part.len()..]; + } + None => return false, + } + } + actual.is_empty() || expected.ends_with("[..]") +} + +impl Server { + pub fn new() -> Server { + let listener = t!(TcpListener::bind("127.0.0.1:0")); + let addr = t!(listener.local_addr()); + let (tx, rx) = channel(); + let thread = thread::spawn(move || run(&listener, &rx)); + Server { + messages: Some(tx), + addr: addr, + thread: Some(thread), + } + } + + pub fn receive(&self, msg: &str) { + let msg = msg.replace("$PORT", &self.addr.port().to_string()); + self.msg(Message::Read(msg)); + } + + pub fn send(&self, msg: &str) { + let msg = msg.replace("$PORT", &self.addr.port().to_string()); + self.msg(Message::Write(msg)); + } + + fn msg(&self, msg: Message) { + t!(self.messages.as_ref().unwrap().send(msg)); + } + + pub fn addr(&self) -> &SocketAddr { + &self.addr + } + + pub fn url(&self, path: &str) -> String { + format!("http://{}{}", self.addr, path) + } +} + +impl Drop for Server { + fn drop(&mut self) { + drop(TcpStream::connect(&self.addr)); + drop(self.messages.take()); + let res = self.thread.take().unwrap().join(); + if !thread::panicking() { + t!(res); + } else if let Err(e) = res { + println!("child server thread also failed: {:?}", e); + } + } +} diff --git a/env_logger/.cargo-checksum.json b/env_logger/.cargo-checksum.json new file mode 100644 index 000000000..02ac20b3d --- /dev/null +++ b/env_logger/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"} \ No newline at end of file diff --git a/env_logger/Cargo.toml b/env_logger/Cargo.toml new file mode 100644 index 000000000..19508769e --- /dev/null +++ b/env_logger/Cargo.toml @@ -0,0 +1,57 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "env_logger" +version = "0.6.1" +authors = ["The Rust Project Developers"] +description = "A logging implementation for `log` which is configured via an environment\nvariable.\n" +documentation = "https://docs.rs/env_logger" +readme = "README.md" +keywords = ["logging", "log", "logger"] +categories = ["development-tools::debugging"] +license = "MIT/Apache-2.0" +repository = "https://github.com/sebasmagri/env_logger/" + +[[test]] +name = "regexp_filter" +harness = false + +[[test]] +name = "log-in-log" +harness = false + +[[test]] +name = "init-twice-retains-filter" +harness = false +[dependencies.atty] +version = "0.2.5" +optional = true + +[dependencies.humantime] +version = "1.1" +optional = true + +[dependencies.log] +version = "0.4" +features = ["std"] + +[dependencies.regex] +version = "1.0.3" +optional = true + +[dependencies.termcolor] +version = "1.0.2" +optional = true + +[features] +default = ["termcolor", "atty", "humantime", "regex"] diff --git a/env_logger/LICENSE-APACHE b/env_logger/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/env_logger/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/env_logger/LICENSE-MIT b/env_logger/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/env_logger/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/env_logger/README.md b/env_logger/README.md new file mode 100644 index 000000000..d824f00cc --- /dev/null +++ b/env_logger/README.md @@ -0,0 +1,150 @@ +env_logger [![Build Status](https://travis-ci.org/sebasmagri/env_logger.svg?branch=master)](https://travis-ci.org/sebasmagri/env_logger) [![Maintenance](https://img.shields.io/badge/maintenance-actively%20maintained-brightgreen.svg)](https://github.com/sebasmagri/env_logger) [![crates.io](https://img.shields.io/crates/v/env_logger.svg)](https://crates.io/crates/env_logger) [![Documentation](https://img.shields.io/badge/docs-current-blue.svg)](https://docs.rs/env_logger) +========== + +Implements a logger that can be configured via environment variables. + +## Usage + +### In libraries + +`env_logger` makes sense when used in executables (binary projects). Libraries should use the [`log`](https://doc.rust-lang.org/log) crate instead. + +### In executables + +It must be added along with `log` to the project dependencies: + +```toml +[dependencies] +log = "0.4.0" +env_logger = "0.6.1" +``` + +`env_logger` must be initialized as early as possible in the project. After it's initialized, you can use the `log` macros to do actual logging. + +```rust +#[macro_use] +extern crate log; +extern crate env_logger; + +fn main() { + env_logger::init(); + + info!("starting up"); + + // ... +} +``` + +Then when running the executable, specify a value for the `RUST_LOG` +environment variable that corresponds with the log messages you want to show. + +```bash +$ RUST_LOG=info ./main +[2018-11-03T06:09:06Z INFO default] starting up +``` + +### In tests + +Tests can use the `env_logger` crate to see log messages generated during that test: + +```toml +[dependencies] +log = "0.4.0" + +[dev-dependencies] +env_logger = "0.6.1" +``` + +```rust +#[macro_use] +extern crate log; + +fn add_one(num: i32) -> i32 { + info!("add_one called with {}", num); + num + 1 +} + +#[cfg(test)] +mod tests { + use super::*; + extern crate env_logger; + + fn init() { + let _ = env_logger::builder().is_test(true).try_init(); + } + + #[test] + fn it_adds_one() { + init(); + + info!("can log from the test too"); + assert_eq!(3, add_one(2)); + } + + #[test] + fn it_handles_negative_numbers() { + init(); + + info!("logging from another test"); + assert_eq!(-7, add_one(-8)); + } +} +``` + +Assuming the module under test is called `my_lib`, running the tests with the +`RUST_LOG` filtering to info messages from this module looks like: + +```bash +$ RUST_LOG=my_lib=info cargo test + Running target/debug/my_lib-... + +running 2 tests +[INFO my_lib::tests] logging from another test +[INFO my_lib] add_one called with -8 +test tests::it_handles_negative_numbers ... ok +[INFO my_lib::tests] can log from the test too +[INFO my_lib] add_one called with 2 +test tests::it_adds_one ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured +``` + +Note that `env_logger::try_init()` needs to be called in each test in which you +want to enable logging. Additionally, the default behavior of tests to +run in parallel means that logging output may be interleaved with test output. +Either run tests in a single thread by specifying `RUST_TEST_THREADS=1` or by +running one test by specifying its name as an argument to the test binaries as +directed by the `cargo test` help docs: + +```bash +$ RUST_LOG=my_lib=info cargo test it_adds_one + Running target/debug/my_lib-... + +running 1 test +[INFO my_lib::tests] can log from the test too +[INFO my_lib] add_one called with 2 +test tests::it_adds_one ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured +``` + +## Configuring log target + +By default, `env_logger` logs to stderr. If you want to log to stdout instead, +you can use the `Builder` to change the log target: + +```rust +use std::env; +use env_logger::{Builder, Target}; + +let mut builder = Builder::from_default_env(); +builder.target(Target::Stdout); + +builder.init(); +``` + +## Stability of the default format + +The default format won't optimise for long-term stability, and explicitly makes no guarantees about the stability of its output across major, minor or patch version bumps during `0.x`. + +If you want to capture or interpret the output of `env_logger` programmatically then you should use a custom format. \ No newline at end of file diff --git a/env_logger/examples/custom_default_format.rs b/env_logger/examples/custom_default_format.rs new file mode 100644 index 000000000..d1a45b608 --- /dev/null +++ b/env_logger/examples/custom_default_format.rs @@ -0,0 +1,44 @@ +/*! +Disabling parts of the default format. + +Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`: + +```no_run,shell +$ export MY_LOG_LEVEL='info' +``` + +Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors +or `auto` to enable them: + +```no_run,shell +$ export MY_LOG_STYLE=never +``` + +If you want to control the logging output completely, see the `custom_logger` example. +*/ + +#[macro_use] +extern crate log; +extern crate env_logger; + +use env_logger::{Env, Builder}; + +fn init_logger() { + let env = Env::default() + .filter("MY_LOG_LEVEL") + .write_style("MY_LOG_STYLE"); + + let mut builder = Builder::from_env(env); + + builder + .default_format_level(false) + .default_format_timestamp_nanos(true); + + builder.init(); +} + +fn main() { + init_logger(); + + info!("a log from `MyLogger`"); +} diff --git a/env_logger/examples/custom_format.rs b/env_logger/examples/custom_format.rs new file mode 100644 index 000000000..c4563f50d --- /dev/null +++ b/env_logger/examples/custom_format.rs @@ -0,0 +1,54 @@ +/*! +Changing the default logging format. + +Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`: + +```no_run,shell +$ export MY_LOG_LEVEL='info' +``` + +Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors +or `auto` to enable them: + +```no_run,shell +$ export MY_LOG_STYLE=never +``` + +If you want to control the logging output completely, see the `custom_logger` example. +*/ + +#[macro_use] +extern crate log; +extern crate env_logger; + +use std::io::Write; + +use env_logger::{Env, Builder, fmt}; + +fn init_logger() { + let env = Env::default() + .filter("MY_LOG_LEVEL") + .write_style("MY_LOG_STYLE"); + + let mut builder = Builder::from_env(env); + + // Use a different format for writing log records + // The colors are only available when the `termcolor` dependency is (which it is by default) + #[cfg(feature = "termcolor")] + builder.format(|buf, record| { + let mut style = buf.style(); + style.set_bg(fmt::Color::Yellow).set_bold(true); + + let timestamp = buf.timestamp(); + + writeln!(buf, "My formatted log ({}): {}", timestamp, style.value(record.args())) + }); + + builder.init(); +} + +fn main() { + init_logger(); + + info!("a log from `MyLogger`"); +} diff --git a/env_logger/examples/custom_logger.rs b/env_logger/examples/custom_logger.rs new file mode 100644 index 000000000..792c9c8e5 --- /dev/null +++ b/env_logger/examples/custom_logger.rs @@ -0,0 +1,60 @@ +/*! +Using `env_logger` to drive a custom logger. + +Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`: + +```no_run,shell +$ export MY_LOG_LEVEL='info' +``` + +If you only want to change the way logs are formatted, look at the `custom_format` example. +*/ + +#[macro_use] +extern crate log; +extern crate env_logger; +use env_logger::filter::Filter; +use log::{Log, Metadata, Record, SetLoggerError}; + +struct MyLogger { + inner: Filter +} + +impl MyLogger { + fn new() -> MyLogger { + use env_logger::filter::Builder; + let mut builder = Builder::from_env("MY_LOG_LEVEL"); + + MyLogger { + inner: builder.build() + } + } + + fn init() -> Result<(), SetLoggerError> { + let logger = Self::new(); + + log::set_max_level(logger.inner.filter()); + log::set_boxed_logger(Box::new(logger)) + } +} + +impl Log for MyLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + self.inner.enabled(metadata) + } + + fn log(&self, record: &Record) { + // Check if the record is matched by the logger before logging + if self.inner.matches(record) { + println!("{} - {}", record.level(), record.args()); + } + } + + fn flush(&self) { } +} + +fn main() { + MyLogger::init().unwrap(); + + info!("a log from `MyLogger`"); +} diff --git a/env_logger/examples/default.rs b/env_logger/examples/default.rs new file mode 100644 index 000000000..5d799fe05 --- /dev/null +++ b/env_logger/examples/default.rs @@ -0,0 +1,36 @@ +/*! +Using `env_logger`. + +Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`: + +```no_run,shell +$ export MY_LOG_LEVEL='info' +``` + +Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors +or `auto` to enable them: + +```no_run,shell +$ export MY_LOG_STYLE=never +``` +*/ + +#[macro_use] +extern crate log; +extern crate env_logger; + +use env_logger::Env; + +fn main() { + let env = Env::default() + .filter_or("MY_LOG_LEVEL", "trace") + .write_style_or("MY_LOG_STYLE", "always"); + + env_logger::init_from_env(env); + + trace!("some trace log"); + debug!("some debug log"); + info!("some information log"); + warn!("some warning log"); + error!("some error log"); +} diff --git a/env_logger/examples/direct_logger.rs b/env_logger/examples/direct_logger.rs new file mode 100644 index 000000000..410230bcd --- /dev/null +++ b/env_logger/examples/direct_logger.rs @@ -0,0 +1,40 @@ +/*! +Using `env_logger::Logger` and the `log::Log` trait directly. + +This example doesn't rely on environment variables, or having a static logger installed. +*/ + +extern crate log; +extern crate env_logger; + +fn record() -> log::Record<'static> { + let error_metadata = log::MetadataBuilder::new() + .target("myApp") + .level(log::Level::Error) + .build(); + + log::Record::builder() + .metadata(error_metadata) + .args(format_args!("Error!")) + .line(Some(433)) + .file(Some("app.rs")) + .module_path(Some("server")) + .build() +} + +fn main() { + use log::Log; + + let stylish_logger = env_logger::Builder::new() + .filter(None, log::LevelFilter::Error) + .write_style(env_logger::WriteStyle::Always) + .build(); + + let unstylish_logger = env_logger::Builder::new() + .filter(None, log::LevelFilter::Error) + .write_style(env_logger::WriteStyle::Never) + .build(); + + stylish_logger.log(&record()); + unstylish_logger.log(&record()); +} \ No newline at end of file diff --git a/env_logger/src/filter/mod.rs b/env_logger/src/filter/mod.rs new file mode 100644 index 000000000..a0fe6a250 --- /dev/null +++ b/env_logger/src/filter/mod.rs @@ -0,0 +1,579 @@ +//! Filtering for log records. +//! +//! This module contains the log filtering used by `env_logger` to match records. +//! You can use the `Filter` type in your own logger implementation to use the same +//! filter parsing and matching as `env_logger`. For more details about the format +//! for directive strings see [Enabling Logging]. +//! +//! ## Using `env_logger` in your own logger +//! +//! You can use `env_logger`'s filtering functionality with your own logger. +//! Call [`Builder::parse`] to parse directives from a string when constructing +//! your logger. Call [`Filter::matches`] to check whether a record should be +//! logged based on the parsed filters when log records are received. +//! +//! ``` +//! extern crate log; +//! extern crate env_logger; +//! use env_logger::filter::Filter; +//! use log::{Log, Metadata, Record}; +//! +//! struct MyLogger { +//! filter: Filter +//! } +//! +//! impl MyLogger { +//! fn new() -> MyLogger { +//! use env_logger::filter::Builder; +//! let mut builder = Builder::new(); +//! +//! // Parse a directives string from an environment variable +//! if let Ok(ref filter) = std::env::var("MY_LOG_LEVEL") { +//! builder.parse(filter); +//! } +//! +//! MyLogger { +//! filter: builder.build() +//! } +//! } +//! } +//! +//! impl Log for MyLogger { +//! fn enabled(&self, metadata: &Metadata) -> bool { +//! self.filter.enabled(metadata) +//! } +//! +//! fn log(&self, record: &Record) { +//! // Check if the record is matched by the filter +//! if self.filter.matches(record) { +//! println!("{:?}", record); +//! } +//! } +//! +//! fn flush(&self) {} +//! } +//! # fn main() {} +//! ``` +//! +//! [Enabling Logging]: ../index.html#enabling-logging +//! [`Builder::parse`]: struct.Builder.html#method.parse +//! [`Filter::matches`]: struct.Filter.html#method.matches + +use std::env; +use std::mem; +use std::fmt; +use log::{Level, LevelFilter, Record, Metadata}; + +#[cfg(feature = "regex")] +#[path = "regex.rs"] +mod inner; + +#[cfg(not(feature = "regex"))] +#[path = "string.rs"] +mod inner; + +/// A log filter. +/// +/// This struct can be used to determine whether or not a log record +/// should be written to the output. +/// Use the [`Builder`] type to parse and construct a `Filter`. +/// +/// [`Builder`]: struct.Builder.html +pub struct Filter { + directives: Vec, + filter: Option, +} + +/// A builder for a log filter. +/// +/// It can be used to parse a set of directives from a string before building +/// a [`Filter`] instance. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] +/// extern crate log; +/// extern crate env_logger; +/// +/// use std::env; +/// use std::io; +/// use env_logger::filter::Builder; +/// +/// fn main() { +/// let mut builder = Builder::new(); +/// +/// // Parse a logging filter from an environment variable. +/// if let Ok(rust_log) = env::var("RUST_LOG") { +/// builder.parse(&rust_log); +/// } +/// +/// let filter = builder.build(); +/// } +/// ``` +/// +/// [`Filter`]: struct.Filter.html +pub struct Builder { + directives: Vec, + filter: Option, + built: bool, +} + +#[derive(Debug)] +struct Directive { + name: Option, + level: LevelFilter, +} + +impl Filter { + /// Returns the maximum `LevelFilter` that this filter instance is + /// configured to output. + /// + /// # Example + /// + /// ```rust + /// extern crate log; + /// extern crate env_logger; + /// + /// use log::LevelFilter; + /// use env_logger::filter::Builder; + /// + /// fn main() { + /// let mut builder = Builder::new(); + /// builder.filter(Some("module1"), LevelFilter::Info); + /// builder.filter(Some("module2"), LevelFilter::Error); + /// + /// let filter = builder.build(); + /// assert_eq!(filter.filter(), LevelFilter::Info); + /// } + /// ``` + pub fn filter(&self) -> LevelFilter { + self.directives.iter() + .map(|d| d.level) + .max() + .unwrap_or(LevelFilter::Off) + } + + /// Checks if this record matches the configured filter. + pub fn matches(&self, record: &Record) -> bool { + if !self.enabled(record.metadata()) { + return false; + } + + if let Some(filter) = self.filter.as_ref() { + if !filter.is_match(&*record.args().to_string()) { + return false; + } + } + + true + } + + /// Determines if a log message with the specified metadata would be logged. + pub fn enabled(&self, metadata: &Metadata) -> bool { + let level = metadata.level(); + let target = metadata.target(); + + enabled(&self.directives, level, target) + } +} + +impl Builder { + /// Initializes the filter builder with defaults. + pub fn new() -> Builder { + Builder { + directives: Vec::new(), + filter: None, + built: false, + } + } + + /// Initializes the filter builder from an environment. + pub fn from_env(env: &str) -> Builder { + let mut builder = Builder::new(); + + if let Ok(s) = env::var(env) { + builder.parse(&s); + } + + builder + } + + /// Adds a directive to the filter for a specific module. + pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self { + self.filter(Some(module), level) + } + + /// Adds a directive to the filter for all modules. + pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self { + self.filter(None, level) + } + + /// Adds a directive to the filter. + /// + /// The given module (if any) will log at most the specified level provided. + /// If no module is provided then the filter will apply to all log messages. + pub fn filter(&mut self, + module: Option<&str>, + level: LevelFilter) -> &mut Self { + self.directives.push(Directive { + name: module.map(|s| s.to_string()), + level, + }); + self + } + + /// Parses the directives string. + /// + /// See the [Enabling Logging] section for more details. + /// + /// [Enabling Logging]: ../index.html#enabling-logging + pub fn parse(&mut self, filters: &str) -> &mut Self { + let (directives, filter) = parse_spec(filters); + + self.filter = filter; + + for directive in directives { + self.directives.push(directive); + } + self + } + + /// Build a log filter. + pub fn build(&mut self) -> Filter { + assert!(!self.built, "attempt to re-use consumed builder"); + self.built = true; + + if self.directives.is_empty() { + // Adds the default filter if none exist + self.directives.push(Directive { + name: None, + level: LevelFilter::Error, + }); + } else { + // Sort the directives by length of their name, this allows a + // little more efficient lookup at runtime. + self.directives.sort_by(|a, b| { + let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); + let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); + alen.cmp(&blen) + }); + } + + Filter { + directives: mem::replace(&mut self.directives, Vec::new()), + filter: mem::replace(&mut self.filter, None), + } + } +} + +impl Default for Builder { + fn default() -> Self { + Builder::new() + } +} + +impl fmt::Debug for Filter { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Filter") + .field("filter", &self.filter) + .field("directives", &self.directives) + .finish() + } +} + +impl fmt::Debug for Builder { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + if self.built { + f.debug_struct("Filter") + .field("built", &true) + .finish() + } else { + f.debug_struct("Filter") + .field("filter", &self.filter) + .field("directives", &self.directives) + .finish() + } + } +} + +/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo") +/// and return a vector with log directives. +fn parse_spec(spec: &str) -> (Vec, Option) { + let mut dirs = Vec::new(); + + let mut parts = spec.split('/'); + let mods = parts.next(); + let filter = parts.next(); + if parts.next().is_some() { + eprintln!("warning: invalid logging spec '{}', \ + ignoring it (too many '/'s)", spec); + return (dirs, None); + } + mods.map(|m| { for s in m.split(',') { + if s.len() == 0 { continue } + let mut parts = s.split('='); + let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { + (Some(part0), None, None) => { + // if the single argument is a log-level string or number, + // treat that as a global fallback + match part0.parse() { + Ok(num) => (num, None), + Err(_) => (LevelFilter::max(), Some(part0)), + } + } + (Some(part0), Some(""), None) => (LevelFilter::max(), Some(part0)), + (Some(part0), Some(part1), None) => { + match part1.parse() { + Ok(num) => (num, Some(part0)), + _ => { + eprintln!("warning: invalid logging spec '{}', \ + ignoring it", part1); + continue + } + } + }, + _ => { + eprintln!("warning: invalid logging spec '{}', \ + ignoring it", s); + continue + } + }; + dirs.push(Directive { + name: name.map(|s| s.to_string()), + level: log_level, + }); + }}); + + let filter = filter.map_or(None, |filter| { + match inner::Filter::new(filter) { + Ok(re) => Some(re), + Err(e) => { + eprintln!("warning: invalid regex filter - {}", e); + None + } + } + }); + + return (dirs, filter); +} + + +// Check whether a level and target are enabled by the set of directives. +fn enabled(directives: &[Directive], level: Level, target: &str) -> bool { + // Search for the longest match, the vector is assumed to be pre-sorted. + for directive in directives.iter().rev() { + match directive.name { + Some(ref name) if !target.starts_with(&**name) => {}, + Some(..) | None => { + return level <= directive.level + } + } + } + false +} + +#[cfg(test)] +mod tests { + use log::{Level, LevelFilter}; + + use super::{Builder, Filter, Directive, parse_spec, enabled}; + + fn make_logger_filter(dirs: Vec) -> Filter { + let mut logger = Builder::new().build(); + logger.directives = dirs; + logger + } + + #[test] + fn filter_info() { + let logger = Builder::new().filter(None, LevelFilter::Info).build(); + assert!(enabled(&logger.directives, Level::Info, "crate1")); + assert!(!enabled(&logger.directives, Level::Debug, "crate1")); + } + + #[test] + fn filter_beginning_longest_match() { + let logger = Builder::new() + .filter(Some("crate2"), LevelFilter::Info) + .filter(Some("crate2::mod"), LevelFilter::Debug) + .filter(Some("crate1::mod1"), LevelFilter::Warn) + .build(); + assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1")); + assert!(!enabled(&logger.directives, Level::Debug, "crate2")); + } + + #[test] + fn parse_default() { + let logger = Builder::new().parse("info,crate1::mod1=warn").build(); + assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1")); + assert!(enabled(&logger.directives, Level::Info, "crate2::mod2")); + } + + #[test] + fn match_full_path() { + let logger = make_logger_filter(vec![ + Directive { + name: Some("crate2".to_string()), + level: LevelFilter::Info + }, + Directive { + name: Some("crate1::mod1".to_string()), + level: LevelFilter::Warn + } + ]); + assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1")); + assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1")); + assert!(enabled(&logger.directives, Level::Info, "crate2")); + assert!(!enabled(&logger.directives, Level::Debug, "crate2")); + } + + #[test] + fn no_match() { + let logger = make_logger_filter(vec![ + Directive { name: Some("crate2".to_string()), level: LevelFilter::Info }, + Directive { name: Some("crate1::mod1".to_string()), level: LevelFilter::Warn } + ]); + assert!(!enabled(&logger.directives, Level::Warn, "crate3")); + } + + #[test] + fn match_beginning() { + let logger = make_logger_filter(vec![ + Directive { name: Some("crate2".to_string()), level: LevelFilter::Info }, + Directive { name: Some("crate1::mod1".to_string()), level: LevelFilter::Warn } + ]); + assert!(enabled(&logger.directives, Level::Info, "crate2::mod1")); + } + + #[test] + fn match_beginning_longest_match() { + let logger = make_logger_filter(vec![ + Directive { name: Some("crate2".to_string()), level: LevelFilter::Info }, + Directive { name: Some("crate2::mod".to_string()), level: LevelFilter::Debug }, + Directive { name: Some("crate1::mod1".to_string()), level: LevelFilter::Warn } + ]); + assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1")); + assert!(!enabled(&logger.directives, Level::Debug, "crate2")); + } + + #[test] + fn match_default() { + let logger = make_logger_filter(vec![ + Directive { name: None, level: LevelFilter::Info }, + Directive { name: Some("crate1::mod1".to_string()), level: LevelFilter::Warn } + ]); + assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1")); + assert!(enabled(&logger.directives, Level::Info, "crate2::mod2")); + } + + #[test] + fn zero_level() { + let logger = make_logger_filter(vec![ + Directive { name: None, level: LevelFilter::Info }, + Directive { name: Some("crate1::mod1".to_string()), level: LevelFilter::Off } + ]); + assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1")); + assert!(enabled(&logger.directives, Level::Info, "crate2::mod2")); + } + + #[test] + fn parse_spec_valid() { + let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_invalid_crate() { + // test parse_spec with multiple = in specification + let (dirs, filter) = parse_spec("crate1::mod1=warn=info,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_invalid_level() { + // test parse_spec with 'noNumber' as log level + let (dirs, filter) = parse_spec("crate1::mod1=noNumber,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_string_level() { + // test parse_spec with 'warn' as log level + let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=warn"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Warn); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_empty_level() { + // test parse_spec with '' as log level + let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2="); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LevelFilter::max()); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_global() { + // test parse_spec with no crate + let (dirs, filter) = parse_spec("warn,crate2=debug"); + assert_eq!(dirs.len(), 2); + assert_eq!(dirs[0].name, None); + assert_eq!(dirs[0].level, LevelFilter::Warn); + assert_eq!(dirs[1].name, Some("crate2".to_string())); + assert_eq!(dirs[1].level, LevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_spec_valid_filter() { + let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "abc"); + } + + #[test] + fn parse_spec_invalid_crate_filter() { + let (dirs, filter) = parse_spec("crate1::mod1=error=warn,crate2=debug/a.c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "a.c"); + } + + #[test] + fn parse_spec_empty_with_filter() { + let (dirs, filter) = parse_spec("crate1/a*c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate1".to_string())); + assert_eq!(dirs[0].level, LevelFilter::max()); + assert!(filter.is_some() && filter.unwrap().to_string() == "a*c"); + } +} diff --git a/env_logger/src/filter/regex.rs b/env_logger/src/filter/regex.rs new file mode 100644 index 000000000..a04265413 --- /dev/null +++ b/env_logger/src/filter/regex.rs @@ -0,0 +1,29 @@ +extern crate regex; + +use std::fmt; + +use self::regex::Regex; + +#[derive(Debug)] +pub struct Filter { + inner: Regex, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + match Regex::new(spec){ + Ok(r) => Ok(Filter { inner: r }), + Err(e) => Err(e.to_string()), + } + } + + pub fn is_match(&self, s: &str) -> bool { + self.inner.is_match(s) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/env_logger/src/filter/string.rs b/env_logger/src/filter/string.rs new file mode 100644 index 000000000..96d7ecca1 --- /dev/null +++ b/env_logger/src/filter/string.rs @@ -0,0 +1,22 @@ +use std::fmt; + +#[derive(Debug)] +pub struct Filter { + inner: String, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + Ok(Filter { inner: spec.to_string() }) + } + + pub fn is_match(&self, s: &str) -> bool { + s.contains(&self.inner) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/env_logger/src/fmt/humantime/extern_impl.rs b/env_logger/src/fmt/humantime/extern_impl.rs new file mode 100644 index 000000000..596a28195 --- /dev/null +++ b/env_logger/src/fmt/humantime/extern_impl.rs @@ -0,0 +1,84 @@ +use std::fmt; +use std::time::SystemTime; + +use humantime::{format_rfc3339_nanos, format_rfc3339_seconds}; + +use ::fmt::Formatter; + +pub(in ::fmt) mod glob { + pub use super::*; +} + +impl Formatter { + /// Get a [`Timestamp`] for the current date and time in UTC. + /// + /// # Examples + /// + /// Include the current timestamp with the log record: + /// + /// ``` + /// use std::io::Write; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let ts = buf.timestamp(); + /// + /// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args()) + /// }); + /// ``` + /// + /// [`Timestamp`]: struct.Timestamp.html + pub fn timestamp(&self) -> Timestamp { + Timestamp(SystemTime::now()) + } + + /// Get a [`PreciseTimestamp`] for the current date and time in UTC with nanos. + pub fn precise_timestamp(&self) -> PreciseTimestamp { + PreciseTimestamp(SystemTime::now()) + } +} + +/// An [RFC3339] formatted timestamp. +/// +/// The timestamp implements [`Display`] and can be written to a [`Formatter`]. +/// +/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt +/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html +/// [`Formatter`]: struct.Formatter.html +pub struct Timestamp(SystemTime); + +/// An [RFC3339] formatted timestamp with nanos. +/// +/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt +#[derive(Debug)] +pub struct PreciseTimestamp(SystemTime); + +impl fmt::Debug for Timestamp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation. + struct TimestampValue<'a>(&'a Timestamp); + + impl<'a> fmt::Debug for TimestampValue<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + f.debug_tuple("Timestamp") + .field(&TimestampValue(&self)) + .finish() + } +} + +impl fmt::Display for Timestamp { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + format_rfc3339_seconds(self.0).fmt(f) + } +} + +impl fmt::Display for PreciseTimestamp { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + format_rfc3339_nanos(self.0).fmt(f) + } +} \ No newline at end of file diff --git a/env_logger/src/fmt/humantime/mod.rs b/env_logger/src/fmt/humantime/mod.rs new file mode 100644 index 000000000..c4f7599c9 --- /dev/null +++ b/env_logger/src/fmt/humantime/mod.rs @@ -0,0 +1,11 @@ +/* +This internal module contains the timestamp implementation. + +Its public API is available when the `humantime` crate is available. +*/ + +#[cfg_attr(feature = "humantime", path = "extern_impl.rs")] +#[cfg_attr(not(feature = "humantime"), path = "shim_impl.rs")] +mod imp; + +pub(in ::fmt) use self::imp::*; diff --git a/env_logger/src/fmt/humantime/shim_impl.rs b/env_logger/src/fmt/humantime/shim_impl.rs new file mode 100644 index 000000000..0f7534000 --- /dev/null +++ b/env_logger/src/fmt/humantime/shim_impl.rs @@ -0,0 +1,7 @@ +/* +Timestamps aren't available when we don't have a `humantime` dependency. +*/ + +pub(in ::fmt) mod glob { + +} diff --git a/env_logger/src/fmt/mod.rs b/env_logger/src/fmt/mod.rs new file mode 100644 index 000000000..635995e22 --- /dev/null +++ b/env_logger/src/fmt/mod.rs @@ -0,0 +1,356 @@ +//! Formatting for log records. +//! +//! This module contains a [`Formatter`] that can be used to format log records +//! into without needing temporary allocations. Usually you won't need to worry +//! about the contents of this module and can use the `Formatter` like an ordinary +//! [`Write`]. +//! +//! # Formatting log records +//! +//! The format used to print log records can be customised using the [`Builder::format`] +//! method. +//! Custom formats can apply different color and weight to printed values using +//! [`Style`] builders. +//! +//! ``` +//! use std::io::Write; +//! +//! let mut builder = env_logger::Builder::new(); +//! +//! builder.format(|buf, record| { +//! writeln!(buf, "{}: {}", +//! record.level(), +//! record.args()) +//! }); +//! ``` +//! +//! [`Formatter`]: struct.Formatter.html +//! [`Style`]: struct.Style.html +//! [`Builder::format`]: ../struct.Builder.html#method.format +//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html + +use std::io::prelude::*; +use std::{io, fmt, mem}; +use std::rc::Rc; +use std::cell::RefCell; +use std::fmt::Display; + +use log::Record; + +pub(crate) mod writer; +mod humantime; + +pub use self::humantime::glob::*; +pub use self::writer::glob::*; + +use self::writer::{Writer, Buffer}; + +pub(crate) mod glob { + pub use super::{Target, WriteStyle}; +} + +/// A formatter to write logs into. +/// +/// `Formatter` implements the standard [`Write`] trait for writing log records. +/// It also supports terminal colors, through the [`style`] method. +/// +/// # Examples +/// +/// Use the [`writeln`] macro to format a log record. +/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`: +/// +/// ``` +/// use std::io::Write; +/// +/// let mut builder = env_logger::Builder::new(); +/// +/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args())); +/// ``` +/// +/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html +/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html +/// [`style`]: #method.style +pub struct Formatter { + buf: Rc>, + write_style: WriteStyle, +} + +impl Formatter { + pub(crate) fn new(writer: &Writer) -> Self { + Formatter { + buf: Rc::new(RefCell::new(writer.buffer())), + write_style: writer.write_style(), + } + } + + pub(crate) fn write_style(&self) -> WriteStyle { + self.write_style + } + + pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> { + writer.print(&self.buf.borrow()) + } + + pub(crate) fn clear(&mut self) { + self.buf.borrow_mut().clear() + } +} + +impl Write for Formatter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buf.borrow_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.buf.borrow_mut().flush() + } +} + +impl fmt::Debug for Formatter { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Formatter").finish() + } +} + +pub(crate) struct Builder { + pub default_format_timestamp: bool, + pub default_format_timestamp_nanos: bool, + pub default_format_module_path: bool, + pub default_format_level: bool, + pub custom_format: Option io::Result<()> + Sync + Send>>, + built: bool, +} + +impl Default for Builder { + fn default() -> Self { + Builder { + default_format_timestamp: true, + default_format_timestamp_nanos: false, + default_format_module_path: true, + default_format_level: true, + custom_format: None, + built: false, + } + } +} + +impl Builder { + /// Convert the format into a callable function. + /// + /// If the `custom_format` is `Some`, then any `default_format` switches are ignored. + /// If the `custom_format` is `None`, then a default format is returned. + /// Any `default_format` switches set to `false` won't be written by the format. + pub fn build(&mut self) -> Box io::Result<()> + Sync + Send> { + assert!(!self.built, "attempt to re-use consumed builder"); + + let built = mem::replace(self, Builder { + built: true, + ..Default::default() + }); + + if let Some(fmt) = built.custom_format { + fmt + } + else { + Box::new(move |buf, record| { + let fmt = DefaultFormat { + timestamp: built.default_format_timestamp, + timestamp_nanos: built.default_format_timestamp_nanos, + module_path: built.default_format_module_path, + level: built.default_format_level, + written_header_value: false, + buf, + }; + + fmt.write(record) + }) + } + } +} + +#[cfg(feature = "termcolor")] +type SubtleStyle = StyledValue<'static, &'static str>; +#[cfg(not(feature = "termcolor"))] +type SubtleStyle = &'static str; + +/// The default format. +/// +/// This format needs to work with any combination of crate features. +struct DefaultFormat<'a> { + timestamp: bool, + module_path: bool, + level: bool, + timestamp_nanos: bool, + written_header_value: bool, + buf: &'a mut Formatter, +} + +impl<'a> DefaultFormat<'a> { + fn write(mut self, record: &Record) -> io::Result<()> { + self.write_timestamp()?; + self.write_level(record)?; + self.write_module_path(record)?; + self.finish_header()?; + + self.write_args(record) + } + + fn subtle_style(&self, text: &'static str) -> SubtleStyle { + #[cfg(feature = "termcolor")] + { + self.buf.style() + .set_color(Color::Black) + .set_intense(true) + .into_value(text) + } + #[cfg(not(feature = "termcolor"))] + { + text + } + } + + fn write_header_value(&mut self, value: T) -> io::Result<()> + where + T: Display, + { + if !self.written_header_value { + self.written_header_value = true; + + let open_brace = self.subtle_style("["); + write!(self.buf, "{}{}", open_brace, value) + } else { + write!(self.buf, " {}", value) + } + } + + fn write_level(&mut self, record: &Record) -> io::Result<()> { + if !self.level { + return Ok(()) + } + + let level = { + #[cfg(feature = "termcolor")] + { + self.buf.default_styled_level(record.level()) + } + #[cfg(not(feature = "termcolor"))] + { + record.level() + } + }; + + self.write_header_value(format_args!("{:<5}", level)) + } + + fn write_timestamp(&mut self) -> io::Result<()> { + #[cfg(feature = "humantime")] + { + if !self.timestamp { + return Ok(()) + } + + if self.timestamp_nanos { + let ts_nanos = self.buf.precise_timestamp(); + self.write_header_value(ts_nanos) + } else { + let ts = self.buf.timestamp(); + self.write_header_value(ts) + } + } + #[cfg(not(feature = "humantime"))] + { + let _ = self.timestamp; + let _ = self.timestamp_nanos; + Ok(()) + } + } + + fn write_module_path(&mut self, record: &Record) -> io::Result<()> { + if !self.module_path { + return Ok(()) + } + + if let Some(module_path) = record.module_path() { + self.write_header_value(module_path) + } else { + Ok(()) + } + } + + fn finish_header(&mut self) -> io::Result<()> { + if self.written_header_value { + let close_brace = self.subtle_style("]"); + write!(self.buf, "{} ", close_brace) + } else { + Ok(()) + } + } + + fn write_args(&mut self, record: &Record) -> io::Result<()> { + writeln!(self.buf, "{}", record.args()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use log::{Level, Record}; + + fn write(fmt: DefaultFormat) -> String { + let buf = fmt.buf.buf.clone(); + + let record = Record::builder() + .args(format_args!("log message")) + .level(Level::Info) + .file(Some("test.rs")) + .line(Some(144)) + .module_path(Some("test::path")) + .build(); + + fmt.write(&record).expect("failed to write record"); + + let buf = buf.borrow(); + String::from_utf8(buf.bytes().to_vec()).expect("failed to read record") + } + + #[test] + fn default_format_with_header() { + let writer = writer::Builder::new() + .write_style(WriteStyle::Never) + .build(); + + let mut f = Formatter::new(&writer); + + let written = write(DefaultFormat { + timestamp: false, + timestamp_nanos: false, + module_path: true, + level: true, + written_header_value: false, + buf: &mut f, + }); + + assert_eq!("[INFO test::path] log message\n", written); + } + + #[test] + fn default_format_no_header() { + let writer = writer::Builder::new() + .write_style(WriteStyle::Never) + .build(); + + let mut f = Formatter::new(&writer); + + let written = write(DefaultFormat { + timestamp: false, + timestamp_nanos: false, + module_path: false, + level: false, + written_header_value: false, + buf: &mut f, + }); + + assert_eq!("log message\n", written); + } +} \ No newline at end of file diff --git a/env_logger/src/fmt/writer/atty.rs b/env_logger/src/fmt/writer/atty.rs new file mode 100644 index 000000000..c441cf089 --- /dev/null +++ b/env_logger/src/fmt/writer/atty.rs @@ -0,0 +1,34 @@ +/* +This internal module contains the terminal detection implementation. + +If the `atty` crate is available then we use it to detect whether we're +attached to a particular TTY. If the `atty` crate is not available we +assume we're not attached to anything. This effectively prevents styles +from being printed. +*/ + +#[cfg(feature = "atty")] +mod imp { + use atty; + + pub(in ::fmt) fn is_stdout() -> bool { + atty::is(atty::Stream::Stdout) + } + + pub(in ::fmt) fn is_stderr() -> bool { + atty::is(atty::Stream::Stderr) + } +} + +#[cfg(not(feature = "atty"))] +mod imp { + pub(in ::fmt) fn is_stdout() -> bool { + false + } + + pub(in ::fmt) fn is_stderr() -> bool { + false + } +} + +pub(in ::fmt) use self::imp::*; diff --git a/env_logger/src/fmt/writer/mod.rs b/env_logger/src/fmt/writer/mod.rs new file mode 100644 index 000000000..d84e41467 --- /dev/null +++ b/env_logger/src/fmt/writer/mod.rs @@ -0,0 +1,206 @@ +mod termcolor; +mod atty; + +use std::{fmt, io}; +use self::termcolor::BufferWriter; +use self::atty::{is_stdout, is_stderr}; + +pub(in ::fmt) mod glob { + pub use super::termcolor::glob::*; + pub use super::*; +} + +pub(in ::fmt) use self::termcolor::Buffer; + +/// Log target, either `stdout` or `stderr`. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Target { + /// Logs will be sent to standard output. + Stdout, + /// Logs will be sent to standard error. + Stderr, +} + +impl Default for Target { + fn default() -> Self { + Target::Stderr + } +} + +/// Whether or not to print styles to the target. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum WriteStyle { + /// Try to print styles, but don't force the issue. + Auto, + /// Try very hard to print styles. + Always, + /// Never print styles. + Never, +} + +impl Default for WriteStyle { + fn default() -> Self { + WriteStyle::Auto + } +} + +/// A terminal target with color awareness. +pub(crate) struct Writer { + inner: BufferWriter, + write_style: WriteStyle, +} + +impl Writer { + pub fn write_style(&self) -> WriteStyle { + self.write_style + } + + pub(in ::fmt) fn buffer(&self) -> Buffer { + self.inner.buffer() + } + + pub(in ::fmt) fn print(&self, buf: &Buffer) -> io::Result<()> { + self.inner.print(buf) + } +} + +/// A builder for a terminal writer. +/// +/// The target and style choice can be configured before building. +pub(crate) struct Builder { + target: Target, + write_style: WriteStyle, + is_test: bool, + built: bool, +} + +impl Builder { + /// Initialize the writer builder with defaults. + pub(crate) fn new() -> Self { + Builder { + target: Default::default(), + write_style: Default::default(), + is_test: false, + built: false, + } + } + + /// Set the target to write to. + pub(crate) fn target(&mut self, target: Target) -> &mut Self { + self.target = target; + self + } + + /// Parses a style choice string. + /// + /// See the [Disabling colors] section for more details. + /// + /// [Disabling colors]: ../index.html#disabling-colors + pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self { + self.write_style(parse_write_style(write_style)) + } + + /// Whether or not to print style characters when writing. + pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self { + self.write_style = write_style; + self + } + + /// Whether or not to capture logs for `cargo test`. + pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self { + self.is_test = is_test; + self + } + + /// Build a terminal writer. + pub(crate) fn build(&mut self) -> Writer { + assert!(!self.built, "attempt to re-use consumed builder"); + self.built = true; + + let color_choice = match self.write_style { + WriteStyle::Auto => { + if match self.target { + Target::Stderr => is_stderr(), + Target::Stdout => is_stdout(), + } { + WriteStyle::Auto + } else { + WriteStyle::Never + } + }, + color_choice => color_choice, + }; + + let writer = match self.target { + Target::Stderr => BufferWriter::stderr(self.is_test, color_choice), + Target::Stdout => BufferWriter::stdout(self.is_test, color_choice), + }; + + Writer { + inner: writer, + write_style: self.write_style, + } + } +} + +impl Default for Builder { + fn default() -> Self { + Builder::new() + } +} + +impl fmt::Debug for Builder { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Logger") + .field("target", &self.target) + .field("write_style", &self.write_style) + .finish() + } +} + +impl fmt::Debug for Writer { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Writer").finish() + } +} + +fn parse_write_style(spec: &str) -> WriteStyle { + match spec { + "auto" => WriteStyle::Auto, + "always" => WriteStyle::Always, + "never" => WriteStyle::Never, + _ => Default::default(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_write_style_valid() { + let inputs = vec![ + ("auto", WriteStyle::Auto), + ("always", WriteStyle::Always), + ("never", WriteStyle::Never), + ]; + + for (input, expected) in inputs { + assert_eq!(expected, parse_write_style(input)); + } + } + + #[test] + fn parse_write_style_invalid() { + let inputs = vec![ + "", + "true", + "false", + "NEVER!!" + ]; + + for input in inputs { + assert_eq!(WriteStyle::Auto, parse_write_style(input)); + } + } +} diff --git a/env_logger/src/fmt/writer/termcolor/extern_impl.rs b/env_logger/src/fmt/writer/termcolor/extern_impl.rs new file mode 100644 index 000000000..0c2d13879 --- /dev/null +++ b/env_logger/src/fmt/writer/termcolor/extern_impl.rs @@ -0,0 +1,490 @@ +use std::borrow::Cow; +use std::fmt; +use std::io::{self, Write}; +use std::cell::RefCell; +use std::rc::Rc; + +use log::Level; +use termcolor::{self, ColorChoice, ColorSpec, WriteColor}; + +use ::WriteStyle; +use ::fmt::{Formatter, Target}; + +pub(in ::fmt::writer) mod glob { + pub use super::*; +} + +impl Formatter { + /// Begin a new [`Style`]. + /// + /// # Examples + /// + /// Create a bold, red colored style and use it to print the log level: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::fmt::Color; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut level_style = buf.style(); + /// + /// level_style.set_color(Color::Red).set_bold(true); + /// + /// writeln!(buf, "{}: {}", + /// level_style.value(record.level()), + /// record.args()) + /// }); + /// ``` + /// + /// [`Style`]: struct.Style.html + pub fn style(&self) -> Style { + Style { + buf: self.buf.clone(), + spec: ColorSpec::new(), + } + } + + /// Get the default [`Style`] for the given level. + /// + /// The style can be used to print other values besides the level. + pub fn default_level_style(&self, level: Level) -> Style { + let mut level_style = self.style(); + match level { + Level::Trace => level_style.set_color(Color::Black).set_intense(true), + Level::Debug => level_style.set_color(Color::White), + Level::Info => level_style.set_color(Color::Green), + Level::Warn => level_style.set_color(Color::Yellow), + Level::Error => level_style.set_color(Color::Red).set_bold(true), + }; + level_style + } + + /// Get a printable [`Style`] for the given level. + /// + /// The style can only be used to print the level. + pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> { + self.default_level_style(level).into_value(level) + } +} + +pub(in ::fmt::writer) struct BufferWriter { + inner: termcolor::BufferWriter, + test_target: Option, +} + +pub(in ::fmt) struct Buffer { + inner: termcolor::Buffer, + test_target: Option, +} + +impl BufferWriter { + pub(in ::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self { + BufferWriter { + inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()), + test_target: if is_test { + Some(Target::Stderr) + } else { + None + }, + } + } + + pub(in ::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self { + BufferWriter { + inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()), + test_target: if is_test { + Some(Target::Stdout) + } else { + None + }, + } + } + + pub(in ::fmt::writer) fn buffer(&self) -> Buffer { + Buffer { + inner: self.inner.buffer(), + test_target: self.test_target, + } + } + + pub(in ::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> { + if let Some(target) = self.test_target { + // This impl uses the `eprint` and `print` macros + // instead of `termcolor`'s buffer. + // This is so their output can be captured by `cargo test` + let log = String::from_utf8_lossy(buf.bytes()); + + match target { + Target::Stderr => eprint!("{}", log), + Target::Stdout => print!("{}", log), + } + + Ok(()) + } else { + self.inner.print(&buf.inner) + } + } +} + +impl Buffer { + pub(in ::fmt) fn clear(&mut self) { + self.inner.clear() + } + + pub(in ::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + pub(in ::fmt) fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } + + pub(in ::fmt) fn bytes(&self) -> &[u8] { + self.inner.as_slice() + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + // Ignore styles for test captured logs because they can't be printed + if self.test_target.is_none() { + self.inner.set_color(spec) + } else { + Ok(()) + } + } + + fn reset(&mut self) -> io::Result<()> { + // Ignore styles for test captured logs because they can't be printed + if self.test_target.is_none() { + self.inner.reset() + } else { + Ok(()) + } + } +} + +impl WriteStyle { + fn into_color_choice(self) -> ColorChoice { + match self { + WriteStyle::Always => ColorChoice::Always, + WriteStyle::Auto => ColorChoice::Auto, + WriteStyle::Never => ColorChoice::Never, + } + } +} + +/// A set of styles to apply to the terminal output. +/// +/// Call [`Formatter::style`] to get a `Style` and use the builder methods to +/// set styling properties, like [color] and [weight]. +/// To print a value using the style, wrap it in a call to [`value`] when the log +/// record is formatted. +/// +/// # Examples +/// +/// Create a bold, red colored style and use it to print the log level: +/// +/// ``` +/// use std::io::Write; +/// use env_logger::fmt::Color; +/// +/// let mut builder = env_logger::Builder::new(); +/// +/// builder.format(|buf, record| { +/// let mut level_style = buf.style(); +/// +/// level_style.set_color(Color::Red).set_bold(true); +/// +/// writeln!(buf, "{}: {}", +/// level_style.value(record.level()), +/// record.args()) +/// }); +/// ``` +/// +/// Styles can be re-used to output multiple values: +/// +/// ``` +/// use std::io::Write; +/// use env_logger::fmt::Color; +/// +/// let mut builder = env_logger::Builder::new(); +/// +/// builder.format(|buf, record| { +/// let mut bold = buf.style(); +/// +/// bold.set_bold(true); +/// +/// writeln!(buf, "{}: {} {}", +/// bold.value(record.level()), +/// bold.value("some bold text"), +/// record.args()) +/// }); +/// ``` +/// +/// [`Formatter::style`]: struct.Formatter.html#method.style +/// [color]: #method.set_color +/// [weight]: #method.set_bold +/// [`value`]: #method.value +#[derive(Clone)] +pub struct Style { + buf: Rc>, + spec: ColorSpec, +} + +/// A value that can be printed using the given styles. +/// +/// It is the result of calling [`Style::value`]. +/// +/// [`Style::value`]: struct.Style.html#method.value +pub struct StyledValue<'a, T> { + style: Cow<'a, Style>, + value: T, +} + +impl Style { + /// Set the text color. + /// + /// # Examples + /// + /// Create a style with red text: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::fmt::Color; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut style = buf.style(); + /// + /// style.set_color(Color::Red); + /// + /// writeln!(buf, "{}", style.value(record.args())) + /// }); + /// ``` + pub fn set_color(&mut self, color: Color) -> &mut Style { + self.spec.set_fg(color.into_termcolor()); + self + } + + /// Set the text weight. + /// + /// If `yes` is true then text will be written in bold. + /// If `yes` is false then text will be written in the default weight. + /// + /// # Examples + /// + /// Create a style with bold text: + /// + /// ``` + /// use std::io::Write; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut style = buf.style(); + /// + /// style.set_bold(true); + /// + /// writeln!(buf, "{}", style.value(record.args())) + /// }); + /// ``` + pub fn set_bold(&mut self, yes: bool) -> &mut Style { + self.spec.set_bold(yes); + self + } + + /// Set the text intensity. + /// + /// If `yes` is true then text will be written in a brighter color. + /// If `yes` is false then text will be written in the default color. + /// + /// # Examples + /// + /// Create a style with intense text: + /// + /// ``` + /// use std::io::Write; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut style = buf.style(); + /// + /// style.set_intense(true); + /// + /// writeln!(buf, "{}", style.value(record.args())) + /// }); + /// ``` + pub fn set_intense(&mut self, yes: bool) -> &mut Style { + self.spec.set_intense(yes); + self + } + + /// Set the background color. + /// + /// # Examples + /// + /// Create a style with a yellow background: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::fmt::Color; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut style = buf.style(); + /// + /// style.set_bg(Color::Yellow); + /// + /// writeln!(buf, "{}", style.value(record.args())) + /// }); + /// ``` + pub fn set_bg(&mut self, color: Color) -> &mut Style { + self.spec.set_bg(color.into_termcolor()); + self + } + + /// Wrap a value in the style. + /// + /// The same `Style` can be used to print multiple different values. + /// + /// # Examples + /// + /// Create a bold, red colored style and use it to print the log level: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::fmt::Color; + /// + /// let mut builder = env_logger::Builder::new(); + /// + /// builder.format(|buf, record| { + /// let mut style = buf.style(); + /// + /// style.set_color(Color::Red).set_bold(true); + /// + /// writeln!(buf, "{}: {}", + /// style.value(record.level()), + /// record.args()) + /// }); + /// ``` + pub fn value(&self, value: T) -> StyledValue { + StyledValue { + style: Cow::Borrowed(self), + value + } + } + + /// Wrap a value in the style by taking ownership of it. + pub(crate) fn into_value(&mut self, value: T) -> StyledValue<'static, T> { + StyledValue { + style: Cow::Owned(self.clone()), + value + } + } +} + +impl<'a, T> StyledValue<'a, T> { + fn write_fmt(&self, f: F) -> fmt::Result + where + F: FnOnce() -> fmt::Result, + { + self.style.buf.borrow_mut().set_color(&self.style.spec).map_err(|_| fmt::Error)?; + + // Always try to reset the terminal style, even if writing failed + let write = f(); + let reset = self.style.buf.borrow_mut().reset().map_err(|_| fmt::Error); + + write.and(reset) + } +} + +impl fmt::Debug for Style { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Style").field("spec", &self.spec).finish() + } +} + +macro_rules! impl_styled_value_fmt { + ($($fmt_trait:path),*) => { + $( + impl<'a, T: $fmt_trait> $fmt_trait for StyledValue<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + self.write_fmt(|| T::fmt(&self.value, f)) + } + } + )* + }; +} + +impl_styled_value_fmt!( + fmt::Debug, + fmt::Display, + fmt::Pointer, + fmt::Octal, + fmt::Binary, + fmt::UpperHex, + fmt::LowerHex, + fmt::UpperExp, + fmt::LowerExp); + +// The `Color` type is copied from https://github.com/BurntSushi/ripgrep/tree/master/termcolor + +/// The set of available colors for the terminal foreground/background. +/// +/// The `Ansi256` and `Rgb` colors will only output the correct codes when +/// paired with the `Ansi` `WriteColor` implementation. +/// +/// The `Ansi256` and `Rgb` color types are not supported when writing colors +/// on Windows using the console. If they are used on Windows, then they are +/// silently ignored and no colors will be emitted. +/// +/// This set may expand over time. +/// +/// This type has a `FromStr` impl that can parse colors from their human +/// readable form. The format is as follows: +/// +/// 1. Any of the explicitly listed colors in English. They are matched +/// case insensitively. +/// 2. A single 8-bit integer, in either decimal or hexadecimal format. +/// 3. A triple of 8-bit integers separated by a comma, where each integer is +/// in decimal or hexadecimal format. +/// +/// Hexadecimal numbers are written with a `0x` prefix. +#[allow(missing_docs)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Color { + Black, + Blue, + Green, + Red, + Cyan, + Magenta, + Yellow, + White, + Ansi256(u8), + Rgb(u8, u8, u8), + #[doc(hidden)] + __Nonexhaustive, +} + +impl Color { + fn into_termcolor(self) -> Option { + match self { + Color::Black => Some(termcolor::Color::Black), + Color::Blue => Some(termcolor::Color::Blue), + Color::Green => Some(termcolor::Color::Green), + Color::Red => Some(termcolor::Color::Red), + Color::Cyan => Some(termcolor::Color::Cyan), + Color::Magenta => Some(termcolor::Color::Magenta), + Color::Yellow => Some(termcolor::Color::Yellow), + Color::White => Some(termcolor::Color::White), + Color::Ansi256(value) => Some(termcolor::Color::Ansi256(value)), + Color::Rgb(r, g, b) => Some(termcolor::Color::Rgb(r, g, b)), + _ => None, + } + } +} diff --git a/env_logger/src/fmt/writer/termcolor/mod.rs b/env_logger/src/fmt/writer/termcolor/mod.rs new file mode 100644 index 000000000..df0f78591 --- /dev/null +++ b/env_logger/src/fmt/writer/termcolor/mod.rs @@ -0,0 +1,12 @@ +/* +This internal module contains the style and terminal writing implementation. + +Its public API is available when the `termcolor` crate is available. +The terminal printing is shimmed when the `termcolor` crate is not available. +*/ + +#[cfg_attr(feature = "termcolor", path = "extern_impl.rs")] +#[cfg_attr(not(feature = "termcolor"), path = "shim_impl.rs")] +mod imp; + +pub(in ::fmt) use self::imp::*; diff --git a/env_logger/src/fmt/writer/termcolor/shim_impl.rs b/env_logger/src/fmt/writer/termcolor/shim_impl.rs new file mode 100644 index 000000000..fb4735902 --- /dev/null +++ b/env_logger/src/fmt/writer/termcolor/shim_impl.rs @@ -0,0 +1,65 @@ +use std::io; + +use fmt::{WriteStyle, Target}; + +pub(in ::fmt::writer) mod glob { + +} + +pub(in ::fmt::writer) struct BufferWriter { + target: Target, +} + +pub(in ::fmt) struct Buffer(Vec); + +impl BufferWriter { + pub(in ::fmt::writer) fn stderr(_is_test: bool, _write_style: WriteStyle) -> Self { + BufferWriter { + target: Target::Stderr, + } + } + + pub(in ::fmt::writer) fn stdout(_is_test: bool, _write_style: WriteStyle) -> Self { + BufferWriter { + target: Target::Stdout, + } + } + + pub(in ::fmt::writer) fn buffer(&self) -> Buffer { + Buffer(Vec::new()) + } + + pub(in ::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> { + // This impl uses the `eprint` and `print` macros + // instead of using the streams directly. + // This is so their output can be captured by `cargo test` + let log = String::from_utf8_lossy(&buf.0); + + match self.target { + Target::Stderr => eprint!("{}", log), + Target::Stdout => print!("{}", log), + } + + Ok(()) + } +} + +impl Buffer { + pub(in ::fmt) fn clear(&mut self) { + self.0.clear(); + } + + pub(in ::fmt) fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.extend(buf); + Ok(buf.len()) + } + + pub(in ::fmt) fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + + #[cfg(test)] + pub(in ::fmt) fn bytes(&self) -> &[u8] { + &self.0 + } +} \ No newline at end of file diff --git a/env_logger/src/lib.rs b/env_logger/src/lib.rs new file mode 100644 index 000000000..185b4dc39 --- /dev/null +++ b/env_logger/src/lib.rs @@ -0,0 +1,1170 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A simple logger configured via environment variables which writes +//! to stdout or stderr, for use with the logging facade exposed by the +//! [`log` crate][log-crate-url]. +//! +//! ## Example +//! +//! ``` +//! #[macro_use] extern crate log; +//! extern crate env_logger; +//! +//! use log::Level; +//! +//! fn main() { +//! env_logger::init(); +//! +//! debug!("this is a debug {}", "message"); +//! error!("this is printed by default"); +//! +//! if log_enabled!(Level::Info) { +//! let x = 3 * 4; // expensive computation +//! info!("the answer was: {}", x); +//! } +//! } +//! ``` +//! +//! Assumes the binary is `main`: +//! +//! ```{.bash} +//! $ RUST_LOG=error ./main +//! [2017-11-09T02:12:24Z ERROR main] this is printed by default +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=info ./main +//! [2017-11-09T02:12:24Z ERROR main] this is printed by default +//! [2017-11-09T02:12:24Z INFO main] the answer was: 12 +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=debug ./main +//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message +//! [2017-11-09T02:12:24Z ERROR main] this is printed by default +//! [2017-11-09T02:12:24Z INFO main] the answer was: 12 +//! ``` +//! +//! You can also set the log level on a per module basis: +//! +//! ```{.bash} +//! $ RUST_LOG=main=info ./main +//! [2017-11-09T02:12:24Z ERROR main] this is printed by default +//! [2017-11-09T02:12:24Z INFO main] the answer was: 12 +//! ``` +//! +//! And enable all logging: +//! +//! ```{.bash} +//! $ RUST_LOG=main ./main +//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message +//! [2017-11-09T02:12:24Z ERROR main] this is printed by default +//! [2017-11-09T02:12:24Z INFO main] the answer was: 12 +//! ``` +//! +//! If the binary name contains hyphens, you will need to replace +//! them with underscores: +//! +//! ```{.bash} +//! $ RUST_LOG=my_app ./my-app +//! [2017-11-09T02:12:24Z DEBUG my_app] this is a debug message +//! [2017-11-09T02:12:24Z ERROR my_app] this is printed by default +//! [2017-11-09T02:12:24Z INFO my_app] the answer was: 12 +//! ``` +//! +//! This is because Rust modules and crates cannot contain hyphens +//! in their name, although `cargo` continues to accept them. +//! +//! See the documentation for the [`log` crate][log-crate-url] for more +//! information about its API. +//! +//! ## Enabling logging +//! +//! Log levels are controlled on a per-module basis, and by default all logging +//! is disabled except for `error!`. Logging is controlled via the `RUST_LOG` +//! environment variable. The value of this environment variable is a +//! comma-separated list of logging directives. A logging directive is of the +//! form: +//! +//! ```text +//! path::to::module=level +//! ``` +//! +//! The path to the module is rooted in the name of the crate it was compiled +//! for, so if your program is contained in a file `hello.rs`, for example, to +//! turn on logging for this file you would use a value of `RUST_LOG=hello`. +//! Furthermore, this path is a prefix-search, so all modules nested in the +//! specified module will also have logging enabled. +//! +//! The actual `level` is optional to specify. If omitted, all logging will +//! be enabled. If specified, it must be one of the strings `debug`, `error`, +//! `info`, `warn`, or `trace`. +//! +//! As the log level for a module is optional, the module to enable logging for +//! is also optional. If only a `level` is provided, then the global log +//! level for all modules is set to this value. +//! +//! Some examples of valid values of `RUST_LOG` are: +//! +//! * `hello` turns on all logging for the 'hello' module +//! * `info` turns on all info logging +//! * `hello=debug` turns on debug logging for 'hello' +//! * `hello,std::option` turns on hello, and std's option logging +//! * `error,hello=warn` turn on global error logging and also warn for hello +//! +//! ## Filtering results +//! +//! A `RUST_LOG` directive may include a regex filter. The syntax is to append `/` +//! followed by a regex. Each message is checked against the regex, and is only +//! logged if it matches. Note that the matching is done after formatting the +//! log string but before adding any logging meta-data. There is a single filter +//! for all modules. +//! +//! Some examples: +//! +//! * `hello/foo` turns on all logging for the 'hello' module where the log +//! message includes 'foo'. +//! * `info/f.o` turns on all info logging where the log message includes 'foo', +//! 'f1o', 'fao', etc. +//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log +//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. +//! * `error,hello=warn/[0-9]scopes` turn on global error logging and also +//! warn for hello. In both cases the log message must include a single digit +//! number followed by 'scopes'. +//! +//! ## Capturing logs in tests +//! +//! Records logged during `cargo test` will not be captured by the test harness by default. +//! The [`Builder::is_test`] method can be used in unit tests to ensure logs will be captured: +//! +//! ``` +//! # #[macro_use] extern crate log; +//! # extern crate env_logger; +//! # fn main() {} +//! #[cfg(test)] +//! mod tests { +//! fn init() { +//! let _ = env_logger::builder().is_test(true).try_init(); +//! } +//! +//! #[test] +//! fn it_works() { +//! info!("This record will be captured by `cargo test`"); +//! +//! assert_eq!(2, 1 + 1); +//! } +//! } +//! ``` +//! +//! Enabling test capturing comes at the expense of color and other style support +//! and may have performance implications. +//! +//! ## Disabling colors +//! +//! Colors and other styles can be configured with the `RUST_LOG_STYLE` +//! environment variable. It accepts the following values: +//! +//! * `auto` (default) will attempt to print style characters, but don't force the issue. +//! If the console isn't available on Windows, or if TERM=dumb, for example, then don't print colors. +//! * `always` will always print style characters even if they aren't supported by the terminal. +//! This includes emitting ANSI colors on Windows if the console API is unavailable. +//! * `never` will never print style characters. +//! +//! ## Tweaking the default format +//! +//! Parts of the default format can be excluded from the log output using the [`Builder`]. +//! The following example excludes the timestamp from the log output: +//! +//! ``` +//! env_logger::builder() +//! .default_format_timestamp(false) +//! .init(); +//! ``` +//! +//! ### Stability of the default format +//! +//! The default format won't optimise for long-term stability, and explicitly makes no +//! guarantees about the stability of its output across major, minor or patch version +//! bumps during `0.x`. +//! +//! If you want to capture or interpret the output of `env_logger` programmatically +//! then you should use a custom format. +//! +//! ### Using a custom format +//! +//! Custom formats can be provided as closures to the [`Builder`]. +//! These closures take a [`Formatter`] and `log::Record` as arguments: +//! +//! ``` +//! use std::io::Write; +//! +//! env_logger::builder() +//! .format(|buf, record| { +//! writeln!(buf, "{}: {}", record.level(), record.args()) +//! }) +//! .init(); +//! ``` +//! +//! See the [`fmt`] module for more details about custom formats. +//! +//! ## Specifying defaults for environment variables +//! +//! `env_logger` can read configuration from environment variables. +//! If these variables aren't present, the default value to use can be tweaked with the [`Env`] type. +//! The following example defaults to log `warn` and above if the `RUST_LOG` environment variable +//! isn't set: +//! +//! ``` +//! use env_logger::Env; +//! +//! env_logger::from_env(Env::default().default_filter_or("warn")).init(); +//! ``` +//! +//! [log-crate-url]: https://docs.rs/log/ +//! [`Builder`]: struct.Builder.html +//! [`Builder::is_test`]: struct.Builder.html#method.is_test +//! [`Env`]: struct.Env.html +//! [`fmt`]: fmt/index.html + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/static/images/favicon.ico", + html_root_url = "https://docs.rs/env_logger/0.6.1")] +#![cfg_attr(test, deny(warnings))] + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +#![deny(missing_debug_implementations, missing_docs, warnings)] + +extern crate log; + +#[cfg(feature = "termcolor")] +extern crate termcolor; +#[cfg(feature = "humantime")] +extern crate humantime; +#[cfg(feature = "atty")] +extern crate atty; + +use std::{env, io}; +use std::borrow::Cow; +use std::cell::RefCell; + +use log::{Log, LevelFilter, Record, SetLoggerError, Metadata}; + +pub mod filter; +pub mod fmt; + +pub use self::fmt::glob::*; + +use self::filter::Filter; +use self::fmt::Formatter; +use self::fmt::writer::{self, Writer}; + +/// The default name for the environment variable to read filters from. +pub const DEFAULT_FILTER_ENV: &'static str = "RUST_LOG"; + +/// The default name for the environment variable to read style preferences from. +pub const DEFAULT_WRITE_STYLE_ENV: &'static str = "RUST_LOG_STYLE"; + +/// Set of environment variables to configure from. +/// +/// # Default environment variables +/// +/// By default, the `Env` will read the following environment variables: +/// +/// - `RUST_LOG`: the level filter +/// - `RUST_LOG_STYLE`: whether or not to print styles with records. +/// +/// These sources can be configured using the builder methods on `Env`. +#[derive(Debug)] +pub struct Env<'a> { + filter: Var<'a>, + write_style: Var<'a>, +} + +#[derive(Debug)] +struct Var<'a> { + name: Cow<'a, str>, + default: Option>, +} + +/// The env logger. +/// +/// This struct implements the `Log` trait from the [`log` crate][log-crate-url], +/// which allows it to act as a logger. +/// +/// The [`init()`], [`try_init()`], [`Builder::init()`] and [`Builder::try_init()`] +/// methods will each construct a `Logger` and immediately initialize it as the +/// default global logger. +/// +/// If you'd instead need access to the constructed `Logger`, you can use +/// the associated [`Builder`] and install it with the +/// [`log` crate][log-crate-url] directly. +/// +/// [log-crate-url]: https://docs.rs/log/ +/// [`init()`]: fn.init.html +/// [`try_init()`]: fn.try_init.html +/// [`Builder::init()`]: struct.Builder.html#method.init +/// [`Builder::try_init()`]: struct.Builder.html#method.try_init +/// [`Builder`]: struct.Builder.html +pub struct Logger { + writer: Writer, + filter: Filter, + format: Box io::Result<()> + Sync + Send>, +} + +/// `Builder` acts as builder for initializing a `Logger`. +/// +/// It can be used to customize the log format, change the environment variable used +/// to provide the logging directives and also set the default log level filter. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate log; +/// extern crate env_logger; +/// +/// use std::env; +/// use std::io::Write; +/// use log::LevelFilter; +/// use env_logger::Builder; +/// +/// fn main() { +/// let mut builder = Builder::from_default_env(); +/// +/// builder.format(|buf, record| writeln!(buf, "{} - {}", record.level(), record.args())) +/// .filter(None, LevelFilter::Info) +/// .init(); +/// +/// error!("error message"); +/// info!("info message"); +/// } +/// ``` +#[derive(Default)] +pub struct Builder { + filter: filter::Builder, + writer: writer::Builder, + format: fmt::Builder, + built: bool, +} + +impl Builder { + /// Initializes the log builder with defaults. + /// + /// **NOTE:** This method won't read from any environment variables. + /// Use the [`filter`] and [`write_style`] methods to configure the builder + /// or use [`from_env`] or [`from_default_env`] instead. + /// + /// # Examples + /// + /// Create a new builder and configure filters and style: + /// + /// ``` + /// # extern crate log; + /// # extern crate env_logger; + /// # fn main() { + /// use log::LevelFilter; + /// use env_logger::{Builder, WriteStyle}; + /// + /// let mut builder = Builder::new(); + /// + /// builder.filter(None, LevelFilter::Info) + /// .write_style(WriteStyle::Always) + /// .init(); + /// # } + /// ``` + /// + /// [`filter`]: #method.filter + /// [`write_style`]: #method.write_style + /// [`from_env`]: #method.from_env + /// [`from_default_env`]: #method.from_default_env + pub fn new() -> Builder { + Default::default() + } + + /// Initializes the log builder from the environment. + /// + /// The variables used to read configuration from can be tweaked before + /// passing in. + /// + /// # Examples + /// + /// Initialise a logger reading the log filter from an environment variable + /// called `MY_LOG`: + /// + /// ``` + /// use env_logger::Builder; + /// + /// let mut builder = Builder::from_env("MY_LOG"); + /// builder.init(); + /// ``` + /// + /// Initialise a logger using the `MY_LOG` variable for filtering and + /// `MY_LOG_STYLE` for whether or not to write styles: + /// + /// ``` + /// use env_logger::{Builder, Env}; + /// + /// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE"); + /// + /// let mut builder = Builder::from_env(env); + /// builder.init(); + /// ``` + pub fn from_env<'a, E>(env: E) -> Self + where + E: Into> + { + let mut builder = Builder::new(); + let env = env.into(); + + if let Some(s) = env.get_filter() { + builder.parse_filters(&s); + } + + if let Some(s) = env.get_write_style() { + builder.parse_write_style(&s); + } + + builder + } + + /// Initializes the log builder from the environment using default variable names. + /// + /// This method is a convenient way to call `from_env(Env::default())` without + /// having to use the `Env` type explicitly. The builder will use the + /// [default environment variables]. + /// + /// # Examples + /// + /// Initialise a logger using the default environment variables: + /// + /// ``` + /// use env_logger::Builder; + /// + /// let mut builder = Builder::from_default_env(); + /// builder.init(); + /// ``` + /// + /// [default environment variables]: struct.Env.html#default-environment-variables + pub fn from_default_env() -> Self { + Self::from_env(Env::default()) + } + + /// Sets the format function for formatting the log output. + /// + /// This function is called on each record logged and should format the + /// log record and output it to the given [`Formatter`]. + /// + /// The format function is expected to output the string directly to the + /// `Formatter` so that implementations can use the [`std::fmt`] macros + /// to format and output without intermediate heap allocations. The default + /// `env_logger` formatter takes advantage of this. + /// + /// # Examples + /// + /// Use a custom format to write only the log message: + /// + /// ``` + /// use std::io::Write; + /// use env_logger::Builder; + /// + /// let mut builder = Builder::new(); + /// + /// builder.format(|buf, record| writeln!(buf, "{}", record.args())); + /// ``` + /// + /// [`Formatter`]: fmt/struct.Formatter.html + /// [`String`]: https://doc.rust-lang.org/stable/std/string/struct.String.html + /// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html + pub fn format(&mut self, format: F) -> &mut Self + where F: Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send + { + self.format.custom_format = Some(Box::new(format)); + self + } + + /// Use the default format. + /// + /// This method will clear any custom format set on the builder. + pub fn default_format(&mut self) -> &mut Self { + self.format.custom_format = None; + self + } + + /// Whether or not to write the level in the default format. + pub fn default_format_level(&mut self, write: bool) -> &mut Self { + self.format.default_format_level = write; + self + } + + /// Whether or not to write the module path in the default format. + pub fn default_format_module_path(&mut self, write: bool) -> &mut Self { + self.format.default_format_module_path = write; + self + } + + /// Whether or not to write the timestamp in the default format. + pub fn default_format_timestamp(&mut self, write: bool) -> &mut Self { + self.format.default_format_timestamp = write; + self + } + + /// Whether or not to write the timestamp with nanos. + pub fn default_format_timestamp_nanos(&mut self, write: bool) -> &mut Self { + self.format.default_format_timestamp_nanos = write; + self + } + + /// Adds a directive to the filter for a specific module. + /// + /// # Examples + /// + /// Only include messages for warning and above for logs in `path::to::module`: + /// + /// ``` + /// # extern crate log; + /// # extern crate env_logger; + /// # fn main() { + /// use log::LevelFilter; + /// use env_logger::Builder; + /// + /// let mut builder = Builder::new(); + /// + /// builder.filter_module("path::to::module", LevelFilter::Info); + /// # } + /// ``` + pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self { + self.filter.filter_module(module, level); + self + } + + /// Adds a directive to the filter for all modules. + /// + /// # Examples + /// + /// Only include messages for warning and above for logs in `path::to::module`: + /// + /// ``` + /// # extern crate log; + /// # extern crate env_logger; + /// # fn main() { + /// use log::LevelFilter; + /// use env_logger::Builder; + /// + /// let mut builder = Builder::new(); + /// + /// builder.filter_level(LevelFilter::Info); + /// # } + /// ``` + pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self { + self.filter.filter_level(level); + self + } + + /// Adds filters to the logger. + /// + /// The given module (if any) will log at most the specified level provided. + /// If no module is provided then the filter will apply to all log messages. + /// + /// # Examples + /// + /// Only include messages for warning and above for logs in `path::to::module`: + /// + /// ``` + /// # extern crate log; + /// # extern crate env_logger; + /// # fn main() { + /// use log::LevelFilter; + /// use env_logger::Builder; + /// + /// let mut builder = Builder::new(); + /// + /// builder.filter(Some("path::to::module"), LevelFilter::Info); + /// # } + /// ``` + pub fn filter(&mut self, + module: Option<&str>, + level: LevelFilter) -> &mut Self { + self.filter.filter(module, level); + self + } + + /// Parses the directives string in the same form as the `RUST_LOG` + /// environment variable. + /// + /// See the module documentation for more details. + #[deprecated(since = "0.6.1", note = "use `parse_filters` instead.")] + pub fn parse(&mut self, filters: &str) -> &mut Self { + self.parse_filters(filters) + } + + /// Parses the directives string in the same form as the `RUST_LOG` + /// environment variable. + /// + /// See the module documentation for more details. + pub fn parse_filters(&mut self, filters: &str) -> &mut Self { + self.filter.parse(filters); + self + } + + /// Sets the target for the log output. + /// + /// Env logger can log to either stdout or stderr. The default is stderr. + /// + /// # Examples + /// + /// Write log message to `stdout`: + /// + /// ``` + /// use env_logger::{Builder, Target}; + /// + /// let mut builder = Builder::new(); + /// + /// builder.target(Target::Stdout); + /// ``` + pub fn target(&mut self, target: fmt::Target) -> &mut Self { + self.writer.target(target); + self + } + + /// Sets whether or not styles will be written. + /// + /// This can be useful in environments that don't support control characters + /// for setting colors. + /// + /// # Examples + /// + /// Never attempt to write styles: + /// + /// ``` + /// use env_logger::{Builder, WriteStyle}; + /// + /// let mut builder = Builder::new(); + /// + /// builder.write_style(WriteStyle::Never); + /// ``` + pub fn write_style(&mut self, write_style: fmt::WriteStyle) -> &mut Self { + self.writer.write_style(write_style); + self + } + + /// Parses whether or not to write styles in the same form as the `RUST_LOG_STYLE` + /// environment variable. + /// + /// See the module documentation for more details. + pub fn parse_write_style(&mut self, write_style: &str) -> &mut Self { + self.writer.parse_write_style(write_style); + self + } + + /// Sets whether or not the logger will be used in unit tests. + /// + /// If `is_test` is `true` then the logger will allow the testing framework to + /// capture log records rather than printing them to the terminal directly. + pub fn is_test(&mut self, is_test: bool) -> &mut Self { + self.writer.is_test(is_test); + self + } + + /// Initializes the global logger with the built env logger. + /// + /// This should be called early in the execution of a Rust program. Any log + /// events that occur before initialization will be ignored. + /// + /// # Errors + /// + /// This function will fail if it is called more than once, or if another + /// library has already initialized a global logger. + pub fn try_init(&mut self) -> Result<(), SetLoggerError> { + let logger = self.build(); + + let max_level = logger.filter(); + let r = log::set_boxed_logger(Box::new(logger)); + + if r.is_ok() { + log::set_max_level(max_level); + } + + r + } + + /// Initializes the global logger with the built env logger. + /// + /// This should be called early in the execution of a Rust program. Any log + /// events that occur before initialization will be ignored. + /// + /// # Panics + /// + /// This function will panic if it is called more than once, or if another + /// library has already initialized a global logger. + pub fn init(&mut self) { + self.try_init().expect("Builder::init should not be called after logger initialized"); + } + + /// Build an env logger. + /// + /// The returned logger implements the `Log` trait and can be installed manually + /// or nested within another logger. + pub fn build(&mut self) -> Logger { + assert!(!self.built, "attempt to re-use consumed builder"); + self.built = true; + + Logger { + writer: self.writer.build(), + filter: self.filter.build(), + format: self.format.build(), + } + } +} + +impl Logger { + /// Creates the logger from the environment. + /// + /// The variables used to read configuration from can be tweaked before + /// passing in. + /// + /// # Examples + /// + /// Create a logger reading the log filter from an environment variable + /// called `MY_LOG`: + /// + /// ``` + /// use env_logger::Logger; + /// + /// let logger = Logger::from_env("MY_LOG"); + /// ``` + /// + /// Create a logger using the `MY_LOG` variable for filtering and + /// `MY_LOG_STYLE` for whether or not to write styles: + /// + /// ``` + /// use env_logger::{Logger, Env}; + /// + /// let env = Env::new().filter_or("MY_LOG", "info").write_style_or("MY_LOG_STYLE", "always"); + /// + /// let logger = Logger::from_env(env); + /// ``` + pub fn from_env<'a, E>(env: E) -> Self + where + E: Into> + { + Builder::from_env(env).build() + } + + /// Creates the logger from the environment using default variable names. + /// + /// This method is a convenient way to call `from_env(Env::default())` without + /// having to use the `Env` type explicitly. The logger will use the + /// [default environment variables]. + /// + /// # Examples + /// + /// Creates a logger using the default environment variables: + /// + /// ``` + /// use env_logger::Logger; + /// + /// let logger = Logger::from_default_env(); + /// ``` + /// + /// [default environment variables]: struct.Env.html#default-environment-variables + pub fn from_default_env() -> Self { + Builder::from_default_env().build() + } + + /// Returns the maximum `LevelFilter` that this env logger instance is + /// configured to output. + pub fn filter(&self) -> LevelFilter { + self.filter.filter() + } + + /// Checks if this record matches the configured filter. + pub fn matches(&self, record: &Record) -> bool { + self.filter.matches(record) + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &Metadata) -> bool { + self.filter.enabled(metadata) + } + + fn log(&self, record: &Record) { + if self.matches(record) { + // Log records are written to a thread-local buffer before being printed + // to the terminal. We clear these buffers afterwards, but they aren't shrinked + // so will always at least have capacity for the largest log record formatted + // on that thread. + // + // If multiple `Logger`s are used by the same threads then the thread-local + // formatter might have different color support. If this is the case the + // formatter and its buffer are discarded and recreated. + + thread_local! { + static FORMATTER: RefCell> = RefCell::new(None); + } + + FORMATTER.with(|tl_buf| { + // It's possible for implementations to sometimes + // log-while-logging (e.g. a `std::fmt` implementation logs + // internally) but it's super rare. If this happens make sure we + // at least don't panic and ship some output to the screen. + let mut a; + let mut b = None; + let tl_buf = match tl_buf.try_borrow_mut() { + Ok(f) => { + a = f; + &mut *a + } + Err(_) => &mut b, + }; + + // Check the buffer style. If it's different from the logger's + // style then drop the buffer and recreate it. + match *tl_buf { + Some(ref mut formatter) => { + if formatter.write_style() != self.writer.write_style() { + *formatter = Formatter::new(&self.writer) + } + }, + ref mut tl_buf => *tl_buf = Some(Formatter::new(&self.writer)) + } + + // The format is guaranteed to be `Some` by this point + let mut formatter = tl_buf.as_mut().unwrap(); + + let _ = (self.format)(&mut formatter, record).and_then(|_| formatter.print(&self.writer)); + + // Always clear the buffer afterwards + formatter.clear(); + }); + } + } + + fn flush(&self) {} +} + +impl<'a> Env<'a> { + /// Get a default set of environment variables. + pub fn new() -> Self { + Self::default() + } + + /// Specify an environment variable to read the filter from. + pub fn filter(mut self, filter_env: E) -> Self + where + E: Into> + { + self.filter = Var::new(filter_env); + + self + } + + /// Specify an environment variable to read the filter from. + /// + /// If the variable is not set, the default value will be used. + pub fn filter_or(mut self, filter_env: E, default: V) -> Self + where + E: Into>, + V: Into>, + { + self.filter = Var::new_with_default(filter_env, default); + + self + } + + /// Use the default environment variable to read the filter from. + /// + /// If the variable is not set, the default value will be used. + pub fn default_filter_or(mut self, default: V) -> Self + where + V: Into>, + { + self.filter = Var::new_with_default(DEFAULT_FILTER_ENV, default); + + self + } + + fn get_filter(&self) -> Option { + self.filter.get() + } + + /// Specify an environment variable to read the style from. + pub fn write_style(mut self, write_style_env: E) -> Self + where + E: Into> + { + self.write_style = Var::new(write_style_env); + + self + } + + /// Specify an environment variable to read the style from. + /// + /// If the variable is not set, the default value will be used. + pub fn write_style_or(mut self, write_style_env: E, default: V) -> Self + where + E: Into>, + V: Into>, + { + self.write_style = Var::new_with_default(write_style_env, default); + + self + } + + /// Use the default environment variable to read the style from. + /// + /// If the variable is not set, the default value will be used. + pub fn default_write_style_or(mut self, default: V) -> Self + where + V: Into>, + { + self.write_style = Var::new_with_default(DEFAULT_WRITE_STYLE_ENV, default); + + self + } + + fn get_write_style(&self) -> Option { + self.write_style.get() + } +} + +impl<'a> Var<'a> { + fn new(name: E) -> Self + where + E: Into>, + { + Var { + name: name.into(), + default: None, + } + } + + fn new_with_default(name: E, default: V) -> Self + where + E: Into>, + V: Into>, + { + Var { + name: name.into(), + default: Some(default.into()), + } + } + + fn get(&self) -> Option { + env::var(&*self.name) + .ok() + .or_else(|| self.default + .to_owned() + .map(|v| v.into_owned())) + } +} + +impl<'a, T> From for Env<'a> +where + T: Into> +{ + fn from(filter_env: T) -> Self { + Env::default().filter(filter_env.into()) + } +} + +impl<'a> Default for Env<'a> { + fn default() -> Self { + Env { + filter: Var::new(DEFAULT_FILTER_ENV), + write_style: Var::new(DEFAULT_WRITE_STYLE_ENV), + } + } +} + +mod std_fmt_impls { + use std::fmt; + use super::*; + + impl fmt::Debug for Logger{ + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + f.debug_struct("Logger") + .field("filter", &self.filter) + .finish() + } + } + + impl fmt::Debug for Builder{ + fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result { + if self.built { + f.debug_struct("Logger") + .field("built", &true) + .finish() + } else { + f.debug_struct("Logger") + .field("filter", &self.filter) + .field("writer", &self.writer) + .finish() + } + } + } +} + +/// Attempts to initialize the global logger with an env logger. +/// +/// This should be called early in the execution of a Rust program. Any log +/// events that occur before initialization will be ignored. +/// +/// # Errors +/// +/// This function will fail if it is called more than once, or if another +/// library has already initialized a global logger. +pub fn try_init() -> Result<(), SetLoggerError> { + try_init_from_env(Env::default()) +} + +/// Initializes the global logger with an env logger. +/// +/// This should be called early in the execution of a Rust program. Any log +/// events that occur before initialization will be ignored. +/// +/// # Panics +/// +/// This function will panic if it is called more than once, or if another +/// library has already initialized a global logger. +pub fn init() { + try_init().expect("env_logger::init should not be called after logger initialized"); +} + +/// Attempts to initialize the global logger with an env logger from the given +/// environment variables. +/// +/// This should be called early in the execution of a Rust program. Any log +/// events that occur before initialization will be ignored. +/// +/// # Examples +/// +/// Initialise a logger using the `MY_LOG` environment variable for filters +/// and `MY_LOG_STYLE` for writing colors: +/// +/// ``` +/// # extern crate env_logger; +/// use env_logger::{Builder, Env}; +/// +/// # fn run() -> Result<(), Box<::std::error::Error>> { +/// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE"); +/// +/// env_logger::try_init_from_env(env)?; +/// +/// Ok(()) +/// # } +/// # fn main() { run().unwrap(); } +/// ``` +/// +/// # Errors +/// +/// This function will fail if it is called more than once, or if another +/// library has already initialized a global logger. +pub fn try_init_from_env<'a, E>(env: E) -> Result<(), SetLoggerError> +where + E: Into> +{ + let mut builder = Builder::from_env(env); + + builder.try_init() +} + +/// Initializes the global logger with an env logger from the given environment +/// variables. +/// +/// This should be called early in the execution of a Rust program. Any log +/// events that occur before initialization will be ignored. +/// +/// # Examples +/// +/// Initialise a logger using the `MY_LOG` environment variable for filters +/// and `MY_LOG_STYLE` for writing colors: +/// +/// ``` +/// use env_logger::{Builder, Env}; +/// +/// let env = Env::new().filter("MY_LOG").write_style("MY_LOG_STYLE"); +/// +/// env_logger::init_from_env(env); +/// ``` +/// +/// # Panics +/// +/// This function will panic if it is called more than once, or if another +/// library has already initialized a global logger. +pub fn init_from_env<'a, E>(env: E) +where + E: Into> +{ + try_init_from_env(env).expect("env_logger::init_from_env should not be called after logger initialized"); +} + +/// Create a new builder with the default environment variables. +/// +/// The builder can be configured before being initialized. +pub fn builder() -> Builder { + Builder::from_default_env() +} + +/// Create a builder from the given environment variables. +/// +/// The builder can be configured before being initialized. +pub fn from_env<'a, E>(env: E) -> Builder +where + E: Into> +{ + Builder::from_env(env) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn env_get_filter_reads_from_var_if_set() { + env::set_var("env_get_filter_reads_from_var_if_set", "from var"); + + let env = Env::new().filter_or("env_get_filter_reads_from_var_if_set", "from default"); + + assert_eq!(Some("from var".to_owned()), env.get_filter()); + } + + #[test] + fn env_get_filter_reads_from_default_if_var_not_set() { + env::remove_var("env_get_filter_reads_from_default_if_var_not_set"); + + let env = Env::new().filter_or("env_get_filter_reads_from_default_if_var_not_set", "from default"); + + assert_eq!(Some("from default".to_owned()), env.get_filter()); + } + + #[test] + fn env_get_write_style_reads_from_var_if_set() { + env::set_var("env_get_write_style_reads_from_var_if_set", "from var"); + + let env = Env::new().write_style_or("env_get_write_style_reads_from_var_if_set", "from default"); + + assert_eq!(Some("from var".to_owned()), env.get_write_style()); + } + + #[test] + fn env_get_write_style_reads_from_default_if_var_not_set() { + env::remove_var("env_get_write_style_reads_from_default_if_var_not_set"); + + let env = Env::new().write_style_or("env_get_write_style_reads_from_default_if_var_not_set", "from default"); + + assert_eq!(Some("from default".to_owned()), env.get_write_style()); + } +} diff --git a/env_logger/tests/init-twice-retains-filter.rs b/env_logger/tests/init-twice-retains-filter.rs new file mode 100644 index 000000000..c1256ef6d --- /dev/null +++ b/env_logger/tests/init-twice-retains-filter.rs @@ -0,0 +1,40 @@ +extern crate log; +extern crate env_logger; + +use std::process; +use std::env; +use std::str; + +fn main() { + if env::var("YOU_ARE_TESTING_NOW").is_ok() { + // Init from the env (which should set the max level to `Debug`) + env_logger::init(); + + assert_eq!(log::LevelFilter::Debug, log::max_level()); + + // Init again using a different max level + // This shouldn't clobber the level that was previously set + env_logger::Builder::new() + .parse_filters("info") + .try_init() + .unwrap_err(); + + assert_eq!(log::LevelFilter::Debug, log::max_level()); + return + } + + let exe = env::current_exe().unwrap(); + let out = process::Command::new(exe) + .env("YOU_ARE_TESTING_NOW", "1") + .env("RUST_LOG", "debug") + .output() + .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); + if out.status.success() { + return + } + + println!("test failed: {}", out.status); + println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap()); + println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap()); + process::exit(1); +} diff --git a/env_logger/tests/log-in-log.rs b/env_logger/tests/log-in-log.rs new file mode 100644 index 000000000..6b2c47e7a --- /dev/null +++ b/env_logger/tests/log-in-log.rs @@ -0,0 +1,38 @@ +#[macro_use] extern crate log; +extern crate env_logger; + +use std::process; +use std::fmt; +use std::env; +use std::str; + +struct Foo; + +impl fmt::Display for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + info!("test"); + f.write_str("bar") + } +} + +fn main() { + env_logger::init(); + if env::var("YOU_ARE_TESTING_NOW").is_ok() { + return info!("{}", Foo); + } + + let exe = env::current_exe().unwrap(); + let out = process::Command::new(exe) + .env("YOU_ARE_TESTING_NOW", "1") + .env("RUST_LOG", "debug") + .output() + .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); + if out.status.success() { + return + } + + println!("test failed: {}", out.status); + println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap()); + println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap()); + process::exit(1); +} diff --git a/env_logger/tests/regexp_filter.rs b/env_logger/tests/regexp_filter.rs new file mode 100644 index 000000000..d23e9223e --- /dev/null +++ b/env_logger/tests/regexp_filter.rs @@ -0,0 +1,51 @@ +#[macro_use] extern crate log; +extern crate env_logger; + +use std::process; +use std::env; +use std::str; + +fn main() { + if env::var("LOG_REGEXP_TEST").ok() == Some(String::from("1")) { + child_main(); + } else { + parent_main() + } +} + +fn child_main() { + env_logger::init(); + info!("XYZ Message"); +} + +fn run_child(rust_log: String) -> bool { + let exe = env::current_exe().unwrap(); + let out = process::Command::new(exe) + .env("LOG_REGEXP_TEST", "1") + .env("RUST_LOG", rust_log) + .output() + .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); + str::from_utf8(out.stderr.as_ref()).unwrap().contains("XYZ Message") +} + +fn assert_message_printed(rust_log: &str) { + if !run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should allow the test log message", rust_log) + } +} + +fn assert_message_not_printed(rust_log: &str) { + if run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should not allow the test log message", rust_log) + } +} + +fn parent_main() { + // test normal log severity levels + assert_message_printed("info"); + assert_message_not_printed("warn"); + + // test of regular expression filters + assert_message_printed("info/XYZ"); + assert_message_not_printed("info/XXX"); +} diff --git a/failure/.cargo-checksum.json b/failure/.cargo-checksum.json new file mode 100644 index 000000000..6b53cd006 --- /dev/null +++ b/failure/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"} \ No newline at end of file diff --git a/failure/CODE_OF_CONDUCT.md b/failure/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..a2161d0d4 --- /dev/null +++ b/failure/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at boats@mozilla.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/failure/Cargo.lock.ci b/failure/Cargo.lock.ci new file mode 100644 index 000000000..8ff4d1e1b --- /dev/null +++ b/failure/Cargo.lock.ci @@ -0,0 +1,136 @@ +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "failure" +version = "0.1.4" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.4", +] + +[[package]] +name = "failure_derive" +version = "0.1.4" +dependencies = [ + "failure 0.1.4", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.43" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "syn" +version = "0.15.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" +"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" +"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" +"checksum rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "01b90379b8664dd83460d59bdc5dd1fd3172b8913788db483ed1325171eab2f7" +"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/failure/Cargo.toml b/failure/Cargo.toml new file mode 100644 index 000000000..dd448d3c6 --- /dev/null +++ b/failure/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "failure" +version = "0.1.5" +authors = ["Without Boats "] +description = "Experimental error handling abstraction." +homepage = "https://rust-lang-nursery.github.io/failure/" +documentation = "https://docs.rs/failure" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang-nursery/failure" +[dependencies.backtrace] +version = "0.3.3" +optional = true + +[dependencies.failure_derive] +version = "0.1.5" +optional = true + +[features] +default = ["std", "derive"] +derive = ["failure_derive"] +std = ["backtrace"] diff --git a/failure/LICENSE-APACHE b/failure/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/failure/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/failure/LICENSE-MIT b/failure/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/failure/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/failure/Makefile b/failure/Makefile new file mode 100644 index 000000000..6ff732985 --- /dev/null +++ b/failure/Makefile @@ -0,0 +1,15 @@ +all: test +.PHONY: all + +test: + @echo TEST DEFAULT FEATURES + @cargo test --all + @echo TEST WITH BACKTRACE + @cargo test --features backtrace --all + @echo TEST NO DEFAULT FEATURES + @cargo check --no-default-features --all +.PHONY: test + +check: + @cargo check --all +.PHONY: check diff --git a/failure/README.md b/failure/README.md new file mode 100644 index 000000000..2f228321b --- /dev/null +++ b/failure/README.md @@ -0,0 +1,119 @@ +# failure - a new error management story + +[![Build Status](https://travis-ci.org/rust-lang-nursery/failure.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/failure) +[![Latest Version](https://img.shields.io/crates/v/failure.svg)](https://crates.io/crates/failure) +[![docs](https://docs.rs/failure/badge.svg)](https://docs.rs/failure) + +`failure` is designed to make it easier to manage errors in Rust. It is +intended to replace error management based on `std::error::Error` with a new +system based on lessons learned over the past several years, including those +learned from experience with quick-error and error-chain. + +`failure` provides two core components: + +* `Fail`: A new trait for custom error types. +* `Error`: A struct which any type that implements `Fail` can be cast into. + +## Evolution + +Failure is currently evolving as a library. First of all there is work going +on in Rust itself to [fix the error trait](https://github.com/rust-lang/rfcs/pull/2504) +secondarily the original plan for Failure towards 1.0 is unlikely to happen +in the current form. + +As such the original master branch towards 1.0 of failure was removed and +master now represents the future iteration steps of 0.1 until it's clear +what happens in the stdlib. + +The original 1.0 branch can be found in [evolution/1.0](https://github.com/rust-lang-nursery/failure/tree/evolution/1.0). + +## Example + +```rust +extern crate serde; +extern crate toml; + +#[macro_use] extern crate failure; +#[macro_use] extern crate serde_derive; + +use std::collections::HashMap; +use std::path::PathBuf; +use std::str::FromStr; + +use failure::Error; + +// This is a new error type that you've created. It represents the ways a +// toolchain could be invalid. +// +// The custom derive for Fail derives an impl of both Fail and Display. +// We don't do any other magic like creating new types. +#[derive(Debug, Fail)] +enum ToolchainError { + #[fail(display = "invalid toolchain name: {}", name)] + InvalidToolchainName { + name: String, + }, + #[fail(display = "unknown toolchain version: {}", version)] + UnknownToolchainVersion { + version: String, + } +} + +pub struct ToolchainId { + // ... etc +} + +impl FromStr for ToolchainId { + type Err = ToolchainError; + + fn from_str(s: &str) -> Result { + // ... etc + } +} + +pub type Toolchains = HashMap; + +// This opens a toml file containing associations between ToolchainIds and +// Paths (the roots of those toolchains). +// +// This could encounter an io Error, a toml parsing error, or a ToolchainError, +// all of them will be thrown into the special Error type +pub fn read_toolchains(path: PathBuf) -> Result +{ + use std::fs::File; + use std::io::Read; + + let mut string = String::new(); + File::open(path)?.read_to_string(&mut string)?; + + let toml: HashMap = toml::from_str(&string)?; + + let toolchains = toml.iter().map(|(key, path)| { + let toolchain_id = key.parse()?; + Ok((toolchain_id, path)) + }).collect::>()?; + + Ok(toolchains) +} +``` + +## Requirements + +Both failure and failure_derive are intended to compile on all stable versions +of Rust newer than 1.18.0, as well as the latest beta and the latest nightly. +If either crate fails to compile on any version newer than 1.18.0, please open +an issue. + +failure is **no_std** compatible, though some aspects of it (primarily the +`Error` type) will not be available in no_std mode. + +## License + +failure is licensed under the terms of the MIT License or the Apache License +2.0, at your choosing. + +## Code of Conduct + +Contribution to the failure crate is organized under the terms of the +Contributor Covenant, the maintainer of failure, @withoutboats, promises to +intervene to uphold that code of conduct. diff --git a/failure/RELEASES.md b/failure/RELEASES.md new file mode 100644 index 000000000..a02c10a88 --- /dev/null +++ b/failure/RELEASES.md @@ -0,0 +1,56 @@ +# Version 0.1.5 + +- Resolve a regression with error conversions (#290) +- Added `name()` to `Fail` and `Error` + +# Version 0.1.4 + +- Improved error reporting of the derive feature +- Resolved a potential internal ambiguity when using the backtrace feature + that prevented backtrace from improving an upstream API. +- Changed the bounds on std error compat conversions through the From trait + to take Sync and Send into account. + +# Version 0.1.3 + +- Added `Context::map` +- Fixed a memory leak for older rust versions on error downcast + +# Version 0.1.2 + +The original plan to release 1.0.0 was changed so that version 0.1.1 is released and a related [RFC to fix the error trait](https://github.com/rust-lang/rfcs/pull/2504) is submitted. See README for details. + +- Fix `failure_derive` to work with Rust 2018. +- Add `#[fail(cause)]` that works similarly with `#[cause]`. The new form is preferred. +- Fix `"backtrace"` feature to work without `"std"` feature. +- Add `Compat::get_ref`. +- Add `Fallible`. +- Deprecate `Fail::causes` and `::causes` in favor of newly added `::iter_causes`. +- Deprecate `Fail::root_cause` and `::root_cause` in favor of newly added `::find_root_cause`. +- Add `::iter_chain`. +- Implement `Box: Fail`. +- Add `Error::from_boxed_compat`. +- Deprecate `Error::cause` in favor of newly added `Error::as_fail`. +- Deprecate `Error::causes` in favor of newly added `Error::iter_chain`. +- Deprecate `Error::root_cause` in favor of newly added `Error::find_root_cause`. +- Add `Error::iter_causes`. +- Implement `Error: AsRef`. +- Fix `Debug` implementation of `SyncFailure`. + +# Version 0.1.1 + +- Add a `Causes` iterator, which iterates over the causes of a failure. Can be + accessed through the `Fail::causes` or `Error::causes` methods. +- Add the `bail!` macro, which "throws" from the function. +- Add the `ensure!` macro, which is like an "assert" which throws instead of + panicking. +- The derive now supports a no_std mode. +- The derive is re-exported from `failure` by default, so that users do not + have to directly depend on `failure_derive`. +- Add a impl of `From for Context`, allowing users to `?` the `D` type to + produce a `Context` (for cases where there is no further underlying + error). + +# Version 0.1.0 + +- Initial version. diff --git a/failure/book/src/SUMMARY.md b/failure/book/src/SUMMARY.md new file mode 100644 index 000000000..e5c8a3b43 --- /dev/null +++ b/failure/book/src/SUMMARY.md @@ -0,0 +1,14 @@ +# Summary + +- [failure](./intro.md) +- [How to use failure](./howto.md) + - [The Fail trait](./fail.md) + - [Deriving Fail](./derive-fail.md) + - [The Error type](./error.md) + - [`bail!` and `ensure!`](./bail-and-ensure.md) +- [Patterns & Guidance](./guidance.md) + - [Strings as errors](./error-msg.md) + - [A Custom Fail type](./custom-fail.md) + - [Using the Error type](./use-error.md) + - [An Error and ErrorKind pair](./error-errorkind.md) + - [Strings and custom fail type](./string-custom-error.md) diff --git a/failure/book/src/bail-and-ensure.md b/failure/book/src/bail-and-ensure.md new file mode 100644 index 000000000..1326f0e05 --- /dev/null +++ b/failure/book/src/bail-and-ensure.md @@ -0,0 +1,18 @@ +# `bail!` and `ensure!` + +If you were a fan of the `bail!` and ensure! macros from error-chain, good news. failure has a version of these macros as well. + +The `bail!` macro returns an error immediately, based on a format string. The `ensure!` macro additionally takes a conditional, and returns the error only if that conditional is false. You can think of `bail!` and `ensure!` as being analogous to `panic!` and `assert!`, but throwing errors instead of panicking. + +`bail!` and `ensure!` macros are useful when you are prototyping and you want to write your custom errors later. It is also the simplest example of using the failure crate. + +## Example +```rust +#[macro_use] extern crate failure; + +fn safe_cast_to_unsigned(n:i32) -> Result +{ + ensure!(n>=0, "number cannot be smaller than 0!"); + (u32) n +} +``` \ No newline at end of file diff --git a/failure/book/src/custom-fail.md b/failure/book/src/custom-fail.md new file mode 100644 index 000000000..324c0417b --- /dev/null +++ b/failure/book/src/custom-fail.md @@ -0,0 +1,75 @@ +# A Custom Fail type + +This pattern is a way to define a new kind of failure. Defining a new kind of +failure can be an effective way of representing an error for which you control +all of the possible failure cases. It has several advantages: + +1. You can enumerate exactly all of the possible failures that can occur in +this context. +2. You have total control over the representation of the failure type. +3. Callers can destructure your error without any sort of downcasting. + +To implement this pattern, you should define your own type that implements +`Fail`. You can use the [custom derive][derive-fail] to make this easier. For +example: + +```rust +#[derive(Fail, Debug)] +#[fail(display = "Input was invalid UTF-8")] +pub struct Utf8Error; +``` + +This type can become as large and complicated as is appropriate to your use +case. It can be an enum with a different variant for each possible error, and +it can carry data with more precise information about the error. For example: + +```rust +#[derive(Fail, Debug)] +#[fail(display = "Input was invalid UTF-8 at index {}", index)] +pub struct Utf8Error { + index: usize, +} +``` + +## When might you use this pattern? + +If you need to raise an error that doesn't come from one of your dependencies, +this is a great pattern to use. + +You can also use this pattern in conjunction with [using `Error`][use-error] or +defining an [Error and ErrorKind pair][error-errorkind]. Those functions which +are "pure logic" and have a very constrained set of errors (such as parsing +simple formats) might each return a different custom Fail type, and then the +function which merges them all together, does IO, and so on, would return a +more complex type like `Error` or your custom Error/ErrorKind. + +## Caveats on this pattern + +When you have a dependency which returns a different error type, often you will +be inclined to add it as a variant on your own error type. When you do that, +you should tag the underlying error as the `#[fail(cause)]` of your error: + +```rust +#[derive(Fail, Debug)] +pub enum MyError { + #[fail(display = "Input was invalid UTF-8 at index {}", _0)] + Utf8Error(usize), + #[fail(display = "{}", _0)] + Io(#[fail(cause)] io::Error), +} +``` + +Up to a limit, this design can work. However, it has some problems: + +- It can be hard to be forward compatible with new dependencies that raise + their own kinds of errors in the future. +- It defines a 1-1 relationship between a variant of the error and an + underlying error. + +Depending on your use case, as your function grows in complexity, it can be +better to transition to [using Error][use-error] or [defining an Error & +ErrorKind pair][error-errorkind]. + +[derive-fail]: ./derive-fail.html +[use-error]: ./use-error.html +[error-errorkind]: ./error-errorkind.html diff --git a/failure/book/src/derive-fail.md b/failure/book/src/derive-fail.md new file mode 100644 index 000000000..6fffd9918 --- /dev/null +++ b/failure/book/src/derive-fail.md @@ -0,0 +1,177 @@ +# Deriving `Fail` + +Though you can implement `Fail` yourself, we also provide a derive macro to +generate the impl for you. To get access to this macro, you must tag the extern +crate declaration with `#[macro_use]`, as in: + +```rust +#[macro_use] extern crate failure; +``` + +In its smallest form, deriving Fail looks like this: + +```rust +#[macro_use] extern crate failure; + +use std::fmt; + +#[derive(Fail, Debug)] +struct MyError; + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "An error occurred.") + } +} +``` + +All failures need to implement `Display`, so we have added an impl of +Display. However, implementing `Display` is much more boilerplate than +implementing `Fail` - this is why we support deriving `Display` for you. + +## Deriving `Display` + +You can derive an implementation of `Display` with a special attribute: + +```rust +#[macro_use] extern crate failure; + +#[derive(Fail, Debug)] +#[fail(display = "An error occurred.")] +struct MyError; +``` + +This attribute will cause the `Fail` derive to also generate an impl of +`Display`, so that you don't have to implement one yourself. + +### String interpolation + +String literals are not enough for error messages in many cases. Often, you +want to include parts of the error value interpolated into the message. You can +do this with failure using the same string interpolation syntax as Rust's +formatting and printing macros: + +```rust +#[macro_use] extern crate failure; + +#[derive(Fail, Debug)] +#[fail(display = "An error occurred with error code {}. ({})", code, message)] +struct MyError { + code: i32, + message: String, +} +``` + +Note that unlike code that would appear in a method, this does not use +something like `self.code` or `self.message`; it just uses the field names +directly. This is because of a limitation in Rust's current attribute syntax. +As a result, you can only interpolate fields through the derivation; you cannot +perform method calls or use other arbitrary expressions. + +### Tuple structs + +With regular structs, you can use the name of the field in string +interpolation. When deriving Fail for a tuple struct, you might expect to use +the numeric index to refer to fields `0`, `1`, et cetera. However, a compiler +limitation prevents this from parsing today. + +For the time being, tuple field accesses in the display attribute need to be +prefixed with an underscore: + +```rust +#[macro_use] extern crate failure; + +#[derive(Fail, Debug)] +#[fail(display = "An error occurred with error code {}.", _0)] +struct MyError(i32); + + +#[derive(Fail, Debug)] +#[fail(display = "An error occurred with error code {} ({}).", _0, _1)] +struct MyOtherError(i32, String); +``` + +### Enums + +Implementing Display is also supported for enums by applying the attribute to +each variant of the enum, rather than to the enum as a whole. The Display impl +will match over the enum to generate the correct error message. For example: + +```rust +#[macro_use] extern crate failure; + +#[derive(Fail, Debug)] +enum MyError { + #[fail(display = "{} is not a valid version.", _0)] + InvalidVersion(u32), + #[fail(display = "IO error: {}", error)] + IoError { error: io::Error }, + #[fail(display = "An unknown error has occurred.")] + UnknownError, +} +``` + +## Overriding `backtrace` + +The backtrace method will be automatically overridden if the type contains a +field with the type `Backtrace`. This works for both structs and enums. + +```rust +#[macro_use] extern crate failure; + +use failure::Backtrace; + +/// MyError::backtrace will return a reference to the backtrace field +#[derive(Fail, Debug)] +#[fail(display = "An error occurred.")] +struct MyError { + backtrace: Backtrace, +} + +/// MyEnumError::backtrace will return a reference to the backtrace only if it +/// is Variant2, otherwise it will return None. +#[derive(Fail, Debug)] +enum MyEnumError { + #[fail(display = "An error occurred.")] + Variant1, + #[fail(display = "A different error occurred.")] + Variant2(Backtrace), +} +``` + +This happens automatically; no other annotations are necessary. It only works +if the type is named Backtrace, and not if you have created an alias for the +Backtrace type. + +## Overriding `cause` + +In contrast to `backtrace`, the cause cannot be determined by type name alone +because it could be any type which implements `Fail`. For this reason, if your +error has an underlying cause field, you need to annotate that field with +the `#[fail(cause)]` attribute. + +This can be used in fields of enums as well as structs. + + +```rust +#[macro_use] extern crate failure; + +use std::io; + +/// MyError::cause will return a reference to the io_error field +#[derive(Fail, Debug)] +#[fail(display = "An error occurred.")] +struct MyError { + #[fail(cause)] io_error: io::Error, +} + +/// MyEnumError::cause will return a reference only if it is Variant2, +/// otherwise it will return None. +#[derive(Fail, Debug)] +enum MyEnumError { + #[fail(display = "An error occurred.")] + Variant1, + #[fail(display = "A different error occurred.")] + Variant2(#[fail(cause)] io::Error), +} +``` diff --git a/failure/book/src/error-errorkind.md b/failure/book/src/error-errorkind.md new file mode 100644 index 000000000..4f1cc4c31 --- /dev/null +++ b/failure/book/src/error-errorkind.md @@ -0,0 +1,147 @@ +# An Error and ErrorKind pair + +This pattern is the most robust way to manage errors - and also the most high +maintenance. It combines some of the advantages of the [using Error][use-error] +pattern and the [custom failure][custom-fail] patterns, while avoiding some of +the disadvantages each of those patterns has: + +1. Like `Error`, this is forward compatible with new underlying kinds of +errors from your dependencies. +2. Like custom failures, this pattern allows you to specify additional information about the error that your dependencies don't give you. +3. Like `Error`, it can be easier to convert underlying errors from dependency +into this type than for custom failures. +4. Like custom failures, users can gain some information about the error +without downcasting. + +The pattern is to create two new failure types: an `Error` and an `ErrorKind`, +and to leverage [the `Context` type][context-api] provided by failure. + +```rust +#[derive(Debug)] +struct MyError { + inner: Context, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] +enum MyErrorKind { + // A plain enum with no data in any of its variants + // + // For example: + #[fail(display = "A contextual error message.")] + OneVariant, + // ... +} +``` + +Unfortunately, it is not easy to correctly derive `Fail` for `MyError` so that +it delegates things to its inner `Context`. You should write those impls +yourself: + +```rust +impl Fail for MyError { + fn name(&self) -> Option<&str> { + self.inner.name() + } + + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} +``` + +You should also provide some conversions and accessors, to go between a +Context, your ErrorKind, and your Error: + +```rust +impl MyError { + pub fn kind(&self) -> MyErrorKind { + *self.inner.get_context() + } +} + +impl From for MyError { + fn from(kind: MyErrorKind) -> MyError { + MyError { inner: Context::new(kind) } + } +} + +impl From> for MyError { + fn from(inner: Context) -> MyError { + MyError { inner: inner } + } +} +``` + +With this code set up, you can use the context method from failure to apply +your ErrorKind to `Result`s in underlying libraries: + +```rust +use failure::ResultExt; +perform_some_io().context(ErrorKind::NetworkFailure)?; +``` + +You can also directly throw `ErrorKind` without an underlying error when +appropriate: + +```rust +Err(ErrorKind::DomainSpecificError)? +``` + +### What should your ErrorKind contain? + +Your error kind probably should not carry data - and if it does, it should only +carry stateless data types that provide additional information about what the +`ErrorKind` means. This way, your `ErrorKind` can be `Eq`, making it +easy to use as a way of comparing errors. + +Your ErrorKind is a way of providing information about what errors mean +appropriate to the level of abstraction that your library operates at. As some +examples: + +- If your library expects to read from the user's `Cargo.toml`, you might have + a `InvalidCargoToml` variant, to capture what `io::Error` and `toml::Error` + mean in the context of your library. +- If your library does both file system activity and network activity, you + might have `Filesystem` and `Network` variants, to divide up the `io::Error`s + between which system in particular failed. + +Exactly what semantic information is appropriate depends entirely on what this +bit of code is intended to do. + +## When might you use this pattern? + +The most likely use cases for this pattern are mid-layer which perform a +function that requires many dependencies, and that are intended to be used in +production. Libraries with few dependencies do not need to manage many +underlying error types and can probably suffice with a simpler [custom +failure][custom-fail]. Applications that know they are almost always just going +to log these errors can get away with [using the Error type][use-error] rather +than managing extra context information. + +That said, when you need to provide the most expressive information about an +error possible, this can be a good approach. + +## Caveats on this pattern + +This pattern is the most involved pattern documented in this book. It involves +a lot of boilerplate to set up (which may be automated away eventually), and it +requires you to apply a contextual message to every underlying error that is +thrown inside your code. It can be a lot of work to maintain this pattern. + +Additionally, like the Error type, the Context type may use an allocation and a +dynamic dispatch internally. If you know this is too expensive for your use +case, you should not use this pattern. + +[use-error]: ./use-error.html +[custom-fail]: ./custom-fail.html +[context-api]: https://docs.rs/failure/latest/failure/struct.Context.html diff --git a/failure/book/src/error-msg.md b/failure/book/src/error-msg.md new file mode 100644 index 000000000..61bde143b --- /dev/null +++ b/failure/book/src/error-msg.md @@ -0,0 +1,59 @@ +# Strings as errors + +This pattern is a way to create new errors without doing much set up. It is +definitely the sloppiest way to throw errors. It can be great to use this +during prototyping, but maybe not in the final product. + +String types do not implement `Fail`, which is why there are two adapters to +create failures from a string: + +- [`failure::err_msg`][err-msg-api] - a function that takes a displayable + type and creates a failure from it. This can take a String or a string + literal. +- [`format_err!`][format-err-api] - a macro with string interpolation, similar + to `format!` or `println!`. + +```rust +fn check_range(x: usize, range: Range) -> Result { + if x < range.start { + return Err(format_err!("{} is below {}", x, range.start)); + } + if x >= range.end { + return Err(format_err!("{} is above {}", x, range.end)); + } + Ok(x) +} +``` + +If you're going to use strings as errors, we recommend [using +`Error`][use-error] as your error type, rather than `ErrorMessage`; this way, +if some of your strings are `String` and some are `&'static str`, you don't +need worry about merging them into a single string type. + +## When might you use this pattern? + +This pattern is the easiest to set up and get going with, so it can be great +when prototyping or spiking out an early design. It can also be great when you +know that an error variant is extremely uncommon, and that there is really no +way to handle it other than to log the error and move on. + +## Caveats on this pattern + +If you are writing a library you plan to publish to crates.io, this is probably +not a good way to handle errors, because it doesn't give your clients very much +control. For public, open source libraries, we'd recommend using [custom +failures][custom-fail] in the cases where you would use a string as an error. + +This pattern can also be very brittle. If you ever want to branch over which +error was returned, you would have to match on the exact contents of the +string. If you ever change the string contents, that will silently break that +match. + +For these reasons, we strongly recommend against using this pattern except for +prototyping and when you know the error is just going to get logged or reported +to the users. + +[custom-fail]: ./custom-fail.html +[use-error]: ./use-error.html +[err-msg-api]: https://docs.rs/failure/latest/failure/fn.err_msg.html +[format-err-api]: https://docs.rs/failure/latest/failure/macro.format_err.html diff --git a/failure/book/src/error.md b/failure/book/src/error.md new file mode 100644 index 000000000..f37e4c3fc --- /dev/null +++ b/failure/book/src/error.md @@ -0,0 +1,100 @@ +# The `Error` type + +In addition to the trait `Fail`, failure provides a type called `Error`. Any +type that implements `Fail` can be cast into `Error` using From and Into, which +allows users to throw errors using `?` which have different types, if the +function returns an `Error`. + +For example: + +```rust +// Something you can deserialize +#[derive(Deserialize)] +struct Object { + ... +} + +impl Object { + // This throws both IO Errors and JSON Errors, but they both get converted + // into the Error type. + fn from_file(path: &Path) -> Result { + let mut string = String::new(); + File::open(path)?.read_to_string(&mut string)?; + let object = json::from_str(&string)?; + Ok(object) + } +} +``` + +## Causes and Backtraces + +The Error type has all of the methods from the Fail trait, with a few notable +differences. Most importantly, the cause and backtrace methods on Error do not +return Options - an Error is *guaranteed* to have a cause and a backtrace. + +```rust +// Both methods are guaranteed to return an &Fail and an &Backtrace +println!("{}, {}", error.cause(), error.backtrace()) +``` + +An `Error`'s cause is always the failure that was cast into this `Error`. +That failure may have further underlying causes. Unlike Fail, this means that +the cause of an Error will have the same Display representation as the Error +itself. + +As to the error's guaranteed backtrace, when the conversion into the Error type +happens, if the underlying failure does not provide a backtrace, a new +backtrace is constructed pointing to that conversion point (rather than the +origin of the error). This construction only happens if there is no underlying +backtrace; if it does have a backtrace no new backtrace is constructed. + +## Downcasting + +The Error type also supports downcasting into any concrete Fail type. It can be +downcast by reference or by value - when downcasting by value, the return type +is `Result`, allowing you to get the error back out of it. + +```rust +match error.downcast::() { + Ok(io_error) => { ... } + Err(error) => { ... } +} +``` + +## Implementation details + +`Error` is essentially a trait object, but with some fanciness it may generate +and store the backtrace if the underlying failure did not have one. In +particular, we use a custom dynamically sized type to store the backtrace +information inline with the trait object data. + +```rust +struct Error { + // Inner is a dynamically sized type + inner: Box>, +} + +struct Inner { + backtrace: Backtrace, + failure: F, +} +``` + +By storing the backtrace in the heap this way, we avoid increasing the size of +the Error type beyond that of two non-nullable pointers. This keeps the size of +the `Result` type from getting too large, avoiding having a negative impact on +the "happy path" of returning Ok. For example, a `Result<(), Error>` should be +represented as a pair of nullable pointers, with the null case representing +`Ok`. Similar optimizations can be applied to values up to at least a pointer +in size. + +To emphasize: Error is intended for use cases where the error case is +considered relatively uncommon. This optimization makes the overhead of an +error less than it otherwise would be for the Ok branch. In cases where errors +are going to be returned extremely frequently, returning this Error type is +probably not appropriate, but you should benchmark in those cases. + +(As a rule of thumb: if you're not sure if you can afford to have a trait +object, you probably *can* afford it. Heap allocations are not nearly as cheap +as stack allocations, but they're cheap enough that you can almost always +afford them.) diff --git a/failure/book/src/fail.md b/failure/book/src/fail.md new file mode 100644 index 000000000..720b52e6d --- /dev/null +++ b/failure/book/src/fail.md @@ -0,0 +1,152 @@ +# The `Fail` trait + +The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has +been designed to support a number of operations: + +- Because it is bound by both `Debug` and `Display`, any failure can be + printed in two ways. +- It has both a `backtrace` and a `cause` method, allowing users to get + information about how the error occurred. +- It supports wrapping failures in additional contextual information. +- Because it is bound by `Send` and `Sync`, failures can be moved and shared + between threads easily. +- Because it is bound by `'static`, the abstract `Fail` trait object can be + downcast into concrete types. + +Every new error type in your code should implement `Fail`, so it can be +integrated into the entire system built around this trait. You can manually +implement `Fail` yourself, or you can use the derive for `Fail` defined +in a separate crate and documented [here][derive-docs]. + +Implementors of this trait are called 'failures'. + +## Cause + +Often, an error type contains (or could contain) another underlying error type +which represents the "cause" of this error - for example, if your custom error +contains an `io::Error`, that is the cause of your error. + +The cause method on the `Fail` trait allows all errors to expose their underlying +cause - if they have one - in a consistent way. Users can loop over the chain +of causes, for example, getting the entire series of causes for an error: + +```rust +// Assume err is a type that implements `Fail` +let mut fail: &Fail = err; + +while let Some(cause) = fail.cause() { + println!("{}", cause); + + // Make `fail` the reference to the cause of the previous fail, making the + // loop "dig deeper" into the cause chain. + fail = cause; +} +``` + +Because `&Fail` supports downcasting, you can also inspect causes in more +detail if you are expecting a certain failure: + +```rust +while let Some(cause) = fail.cause() { + + if let Some(err) = cause.downcast_ref::() { + // treat io::Error specially + } else { + // fallback case + } + + fail = cause; +} +``` + +For convenience an iterator is also provided: + +```rust +// Assume err is a type that implements `Fail` +let mut fail: &Fail = err; + +for cause in fail.iter_causes() { + println!("{}", cause); +} +``` + +## Backtraces + +Errors can also generate a backtrace when they are constructed, helping you +determine the place the error was generated and the function chain that called into +that. Like causes, this is entirely optional - the authors of each failure +have to decide if generating a backtrace is appropriate in their use case. + +The backtrace method allows all errors to expose their backtrace if they have +one. This enables a consistent method for getting the backtrace from an error: + +```rust +// We don't even know the type of the cause, but we can still get its +// backtrace. +if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) { + println!("{}", bt) +} +``` + +The `Backtrace` type exposed by `failure` is different from the `Backtrace` exposed +by the [backtrace crate][backtrace-crate], in that it has several optimizations: + +- It has a `no_std` compatible form which will never be generated (because + backtraces require heap allocation), and should be entirely compiled out. +- It will not be generated unless the `RUST_BACKTRACE` environment variable has + been set at runtime. +- Symbol resolution is delayed until the backtrace is actually printed, because + this is the most expensive part of generating a backtrace. + +## Context + +Often, the libraries you are using will present error messages that don't +provide very helpful information about what exactly has gone wrong. For +example, if an `io::Error` says that an entity was "Not Found," that doesn't +communicate much about what specific file was missing - if it even was a file +(as opposed to a directory for example). + +You can inject additional context to be carried with this error value, +providing semantic information about the nature of the error appropriate to the +level of abstraction that the code you are writing operates at. The `context` +method on `Fail` takes any displayable value (such as a string) to act as +context for this error. + +Using the `ResultExt` trait, you can also get `context` as a convenient method on +`Result` directly. For example, suppose that your code attempted to read from a +Cargo.toml. You can wrap the `io::Error`s that occur with additional context +about what operation has failed: + +```rust +use failure::ResultExt; + +let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?; +file.read_to_end(&buffer).context("Could not read Cargo.toml")?; +``` + +The `Context` object also has a constructor that does not take an underlying +error, allowing you to create ad hoc Context errors alongside those created by +applying the `context` method to an underlying error. + +## Backwards compatibility + +We've taken several steps to make transitioning from `std::error` to `failure` as +painless as possible. + +First, there is a blanket implementation of `Fail` for all types that implement +`std::error::Error`, as long as they are `Send + Sync + 'static`. If you are +dealing with a library that hasn't shifted to `Fail`, it is automatically +compatible with `failure` already. + +Second, `Fail` contains a method called `compat`, which produces a type that +implements `std::error::Error`. If you have a type that implements `Fail`, but +not the older `Error` trait, you can call `compat` to get a type that does +implement that trait (for example, if you need to return a `Box`). + +The biggest hole in our backwards compatibility story is that you cannot +implement `std::error::Error` and also override the backtrace and cause methods +on `Fail`. We intend to enable this with specialization when it becomes stable. + +[derive-docs]: ./derive-fail.html +[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html +[backtrace-crate]: http://alexcrichton.com/backtrace-rs diff --git a/failure/book/src/guidance.md b/failure/book/src/guidance.md new file mode 100644 index 000000000..7023ca40d --- /dev/null +++ b/failure/book/src/guidance.md @@ -0,0 +1,24 @@ +# Patterns & Guidance + +failure is not a "one size fits all" approach to error management. There are +multiple patterns that emerge from the API this library provides, and users +need to determine which pattern makes sense for them. This section documents +some patterns and how users might use them. + +In brief, these are the patterns documented here: + +- **[Strings as errors](./error-msg.md):** Using strings as your error + type. Good for prototyping. +- **[A Custom Fail type](./custom-fail.md):** Defining a custom type to be + your error type. Good for APIs where you control all or more of the + possible failures. +- **[Using the Error type](./use-error.md):** Using the Error type to pull + together multiple failures of different types. Good for applications and + APIs that know the error won't be inspected much more. +- **[An Error and ErrorKind pair](./error-errorkind.md):** Using both a + custom error type and an ErrorKind enum to create a very robust error + type. Good for public APIs in large crates. + +(Though each of these items identifies a use case which this pattern would be +good for, in truth each of them can be applied in various contexts. Its up to +you to decide what makes the most sense for your particular use case.) diff --git a/failure/book/src/howto.md b/failure/book/src/howto.md new file mode 100644 index 000000000..5c8135b7a --- /dev/null +++ b/failure/book/src/howto.md @@ -0,0 +1,8 @@ +# How to use failure + +This section of the documentation is about how the APIs exposed in failure can +be used. It is organized around the major APIs of failure: + +- **[The Fail trait](./fail.md):** The primary abstraction provided by failure. +- **[Deriving Fail](./derive-fail.md):** A custom derive for the Fail trait. +- **[The Error type](./error.md):** A convenient wrapper around any Fail type. diff --git a/failure/book/src/intro.md b/failure/book/src/intro.md new file mode 100644 index 000000000..318477a72 --- /dev/null +++ b/failure/book/src/intro.md @@ -0,0 +1,77 @@ +# failure + +This is the documentation for the failure crate, which provides a system for +creating and managing errors in Rust. Additional documentation is found here: + +* [API documentation][api] +* [failure source code][repo] + +[api]: https://docs.rs/failure +[repo]: https://github.com/rust-lang-nursery/failure + +```rust +extern crate serde; +extern crate toml; + +#[macro_use] extern crate failure; +#[macro_use] extern crate serde_derive; + +use std::collections::HashMap; +use std::path::PathBuf; +use std::str::FromStr; + +use failure::Error; + +// This is a new error type that you've created. It represents the ways a +// toolchain could be invalid. +// +// The custom derive for Fail derives an impl of both Fail and Display. +// We don't do any other magic like creating new types. +#[derive(Debug, Fail)] +enum ToolchainError { + #[fail(display = "invalid toolchain name: {}", name)] + InvalidToolchainName { + name: String, + }, + #[fail(display = "unknown toolchain version: {}", version)] + UnknownToolchainVersion { + version: String, + } +} + +pub struct ToolchainId { + // ... etc +} + +impl FromStr for ToolchainId { + type Err = ToolchainError; + + fn from_str(s: &str) -> Result { + // ... etc + } +} + +pub type Toolchains = HashMap; + +// This opens a toml file containing associations between ToolchainIds and +// Paths (the roots of those toolchains). +// +// This could encounter an io Error, a toml parsing error, or a ToolchainError, +// all of them will be thrown into the special Error type +pub fn read_toolchains(path: PathBuf) -> Result +{ + use std::fs::File; + use std::io::Read; + + let mut string = String::new(); + File::open(path)?.read_to_string(&mut string)?; + + let toml: HashMap = toml::from_str(&string)?; + + let toolchains = toml.iter().map(|(key, path)| { + let toolchain_id = key.parse()?; + Ok((toolchain_id, path)) + }).collect::>()?; + + Ok(toolchains) +} diff --git a/failure/book/src/string-custom-error.md b/failure/book/src/string-custom-error.md new file mode 100644 index 000000000..5ea7b8fc8 --- /dev/null +++ b/failure/book/src/string-custom-error.md @@ -0,0 +1,168 @@ +# Strings and custom fail type + +This pattern is an hybrid between the [_An Error and ErrorKind pair_](./error-errorkind.md) and +[_Using the Error type_](./use-error.md). + +Such an error type can be implemented in the same way that what was shown in +the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern, but here, the context is a +simple string: + +```rust +extern crate core; +extern crate failure; + +use core::fmt::{self, Display}; +use failure::{Backtrace, Context, Fail, ResultExt}; + +#[derive(Debug)] +pub struct MyError { + inner: Context, +} + +impl Fail for MyError { + fn name(&self) -> Option<&str> { + self.inner.name() + } + + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} +``` + +To make the type easier to use, a few impls can be added: + +```rust +// Allows writing `MyError::from("oops"))?` +impl From<&'static str> for MyError { + fn from(msg: &'static str) -> MyError { + MyError { + inner: Context::new(msg), + } + } +} + +// Allows adding more context via a String +impl From> for MyError { + fn from(inner: Context) -> MyError { + MyError { inner } + } +} + +// Allows adding more context via a &str +impl From> for MyError { + fn from(inner: Context<&'static str>) -> MyError { + MyError { + inner: inner.map(|s| s.to_string()), + } + } +} +``` + +Here is how it is used: + +```rust +fn main() { + println!("{:?}", err2()); +} + +// Unlike the "Using the Error type" pattern, functions return our own error +// type here. +fn err1() -> Result<(), MyError> { + Ok(Err(MyError::from("err1"))?) +} + +fn err2() -> Result<(), MyError> { + // Unlike the "An Error and ErrorKind pair" pattern, our context is a + // simple string. We can chain errors and provide detailed error messages, + // but we don't have to deal with the complexity of an error kind type + Ok(err1().context("err2")?) +} +``` + +## Variant with `&'static str` + +If you don't need to format strings, you can avoid an +allocation by using a `Context<&'static str>` instead of a +`Context`. + +```rust +extern crate core; +extern crate failure; + +use core::fmt::{self, Display}; +use failure::{Backtrace, Context, Fail, ResultExt}; + +#[derive(Debug)] +pub struct MyError { + inner: Context<&'static str>, +} + +impl Fail for MyError { + fn name(&self) -> Option<&str> { + self.inner.name() + } + + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +impl From<&'static str> for MyError { + fn from(msg: &'static str) -> MyError { + MyError { + inner: Context::new(msg.into()), + } + } +} + +impl From> for MyError { + fn from(inner: Context<&'static str>) -> MyError { + MyError { + inner, + } + } +} +``` + +## When might you use this pattern? + +Sometimes, you don't want to use the [_Using the Error type_](./use-error.md) +pattern, because you want to expose a few different error types. But you don't +want to use the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern +either, because there is no need to provide the context as an enum or because +it would be too much work, if the error can occur in many different contexts. + +For instance, if you're writing a library that decodes/encodes a complex binary +format, you might want to expose a `DecodeError` and an `EncodeError` error +type, but provide the context as a simple string instead of an error kind, because: + +- users may not care too much about the context in which a `DecodeError` or + `EncodeError` was encountered, they just want a nice message to explain it +- your binary format is really complex, errors can occur in many different + places, and you don't want to end up with a giant `ErrorKind` enum + + +## Caveats on this pattern + +If using the `Context` variant, an extra allocation is used for the string. diff --git a/failure/book/src/use-error.md b/failure/book/src/use-error.md new file mode 100644 index 000000000..a0a294402 --- /dev/null +++ b/failure/book/src/use-error.md @@ -0,0 +1,66 @@ +# Use the `Error` type + +This pattern is a way to manage errors when you have multiple kinds of failure +that could occur during a single function. It has several distinct advantages: + +1. You can start using it without defining any of your own failure types. +2. All types that implement `Fail` can be thrown into the `Error` type using +the `?` operator. +3. As you start adding new dependencies with their own failure types, you can +start throwing them without making a breaking change. + +To use this pattern, all you need to do is return `Result<_, Error>` from your +functions: + +```rust +use std::io; +use std::io::BufRead; + +use failure::Error; +use failure::err_msg; + +fn my_function() -> Result<(), Error> { + let stdin = io::stdin(); + + for line in stdin.lock().lines() { + let line = line?; + + if line.chars().all(|c| c.is_whitespace()) { + break + } + + if !line.starts_with("$") { + return Err(format_err!("Input did not begin with `$`")); + } + + println!("{}", &line[1..]); + } + + Ok(()) +} +``` + +## When might you use this pattern? + +This pattern is very effective when you know you will usually not need to +destructure the error this function returns. For example: + +- When prototyping. +- When you know you are going to log this error, or display it to the user, + either all of the time or nearly all of the time. +- When it would be impractical for this API to report more custom context for + the error (e.g. because it is a trait that doesn't want to add a new Error + associated type). + +## Caveats on this pattern + +There are two primary downsides to this pattern: + +- The `Error` type allocates. There are cases where this would be too + expensive. In those cases you should use a [custom failure][custom-fail]. +- You cannot recover more information about this error without downcasting. If + your API needs to express more contextual information about the error, use + the [Error and ErrorKind][error-errorkind] pattern. + +[custom-fail]: ./custom-fail.html +[error-errorkind]: ./error-errorkind.html diff --git a/failure/build-docs.sh b/failure/build-docs.sh new file mode 100755 index 000000000..fe2039fbf --- /dev/null +++ b/failure/build-docs.sh @@ -0,0 +1,8 @@ +#!/bin/bash +mkdir public +cargo doc --no-deps +cargo install mdbook --no-default-features +mdbook build ./book +cp -r ./target/doc/ ./public +cp -r ./book/book/* ./public +find $PWD/public | grep "\.html\$" diff --git a/failure/examples/bail_ensure.rs b/failure/examples/bail_ensure.rs new file mode 100644 index 000000000..05c399b5d --- /dev/null +++ b/failure/examples/bail_ensure.rs @@ -0,0 +1,26 @@ +#[macro_use] +extern crate failure; + +use failure::Error; + +fn bailer() -> Result<(), Error> { + // bail!("ruh roh"); + bail!("ruh {}", "roh"); +} + +fn ensures() -> Result<(), Error> { + ensure!(true, "true is false"); + ensure!(false, "false is false"); + Ok(()) +} + +fn main() { + match bailer() { + Ok(_) => println!("ok"), + Err(e) => println!("{}", e), + } + match ensures() { + Ok(_) => println!("ok"), + Err(e) => println!("{}", e), + } +} diff --git a/failure/examples/error_as_cause.rs b/failure/examples/error_as_cause.rs new file mode 100644 index 000000000..24e5b063d --- /dev/null +++ b/failure/examples/error_as_cause.rs @@ -0,0 +1,18 @@ +#[macro_use] +extern crate failure; + +use failure::{err_msg, Error, Fail}; + +#[derive(Debug, Fail)] +#[fail(display = "my wrapping error")] +struct WrappingError(#[fail(cause)] Error); + +fn bad_function() -> Result<(), WrappingError> { + Err(WrappingError(err_msg("this went bad"))) +} + +fn main() { + for cause in Fail::iter_causes(&bad_function().unwrap_err()) { + println!("{}", cause); + } +} diff --git a/failure/examples/simple.rs b/failure/examples/simple.rs new file mode 100644 index 000000000..fc39601dc --- /dev/null +++ b/failure/examples/simple.rs @@ -0,0 +1,22 @@ +#[macro_use] +extern crate failure; + +use failure::Fail; + +#[derive(Debug, Fail)] +#[fail(display = "my error")] +struct MyError; + +#[derive(Debug, Fail)] +#[fail(display = "my wrapping error")] +struct WrappingError(#[fail(cause)] MyError); + +fn bad_function() -> Result<(), WrappingError> { + Err(WrappingError(MyError)) +} + +fn main() { + for cause in Fail::iter_chain(&bad_function().unwrap_err()) { + println!("{}: {}", cause.name().unwrap_or("Error"), cause); + } +} diff --git a/failure/examples/string_custom_error_pattern.rs b/failure/examples/string_custom_error_pattern.rs new file mode 100644 index 000000000..72cf65103 --- /dev/null +++ b/failure/examples/string_custom_error_pattern.rs @@ -0,0 +1,76 @@ +//! This example show the pattern "Strings and custom fail type" described in the book +extern crate core; +extern crate failure; + +use core::fmt::{self, Display}; +use failure::{Backtrace, Context, Fail, ResultExt}; + +fn main() { + let err = err1().unwrap_err(); + // Print the error itself + println!("error: {}", err); + // Print the chain of errors that caused it + for cause in Fail::iter_causes(&err) { + println!("caused by: {}", cause); + } +} + +fn err1() -> Result<(), MyError> { + // The context can be a String + Ok(err2().context("err1".to_string())?) +} + +fn err2() -> Result<(), MyError> { + // The context can be a &'static str + Ok(err3().context("err2")?) +} + +fn err3() -> Result<(), MyError> { + Ok(Err(MyError::from("err3"))?) +} + +#[derive(Debug)] +pub struct MyError { + inner: Context, +} + +impl Fail for MyError { + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + +// Allows writing `MyError::from("oops"))?` +impl From<&'static str> for MyError { + fn from(msg: &'static str) -> MyError { + MyError { + inner: Context::new(msg.into()), + } + } +} + +// Allows adding more context via a String +impl From> for MyError { + fn from(inner: Context) -> MyError { + MyError { inner } + } +} + +// Allows adding more context via a &str +impl From> for MyError { + fn from(inner: Context<&'static str>) -> MyError { + MyError { + inner: inner.map(|s| s.to_string()), + } + } +} diff --git a/failure/src/as_fail.rs b/failure/src/as_fail.rs new file mode 100644 index 000000000..dd53a46c6 --- /dev/null +++ b/failure/src/as_fail.rs @@ -0,0 +1,37 @@ +use Fail; + +/// The `AsFail` trait +/// +/// This trait is similar to `AsRef`, but it is specialized to handle +/// the dynamic object of `Fail`. Implementors of `Fail` have a blanket +/// implementation. It is used in `failure_derive` in order to generate a +/// custom cause. +pub trait AsFail { + /// Converts a reference to `Self` into a dynamic trait object of `Fail`. + fn as_fail(&self) -> &Fail; +} + +impl AsFail for T +where + T: Fail, +{ + fn as_fail(&self) -> &Fail { + self + } +} + +impl AsFail for Fail { + fn as_fail(&self) -> &Fail { + self + } +} + +with_std! { + use error::Error; + + impl AsFail for Error { + fn as_fail(&self) -> &Fail { + self.as_fail() + } + } +} diff --git a/failure/src/backtrace/internal.rs b/failure/src/backtrace/internal.rs new file mode 100644 index 000000000..7be137b75 --- /dev/null +++ b/failure/src/backtrace/internal.rs @@ -0,0 +1,130 @@ +use std::cell::UnsafeCell; +use std::env; +use std::ffi::OsString; +use std::fmt; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::Mutex; + +pub use super::backtrace::Backtrace; + +const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE"; +const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE"; + +pub(super) struct InternalBacktrace { + backtrace: Option, +} + +struct MaybeResolved { + resolved: Mutex, + backtrace: UnsafeCell, +} + +unsafe impl Send for MaybeResolved {} +unsafe impl Sync for MaybeResolved {} + +impl InternalBacktrace { + pub(super) fn new() -> InternalBacktrace { + static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT; + + match ENABLED.load(Ordering::SeqCst) { + 0 => { + let enabled = is_backtrace_enabled(|var| env::var_os(var)); + ENABLED.store(enabled as usize + 1, Ordering::SeqCst); + if !enabled { + return InternalBacktrace { backtrace: None } + } + } + 1 => return InternalBacktrace { backtrace: None }, + _ => {} + } + + InternalBacktrace { + backtrace: Some(MaybeResolved { + resolved: Mutex::new(false), + backtrace: UnsafeCell::new(Backtrace::new_unresolved()), + }), + } + } + + pub(super) fn none() -> InternalBacktrace { + InternalBacktrace { backtrace: None } + } + + pub(super) fn as_backtrace(&self) -> Option<&Backtrace> { + let bt = match self.backtrace { + Some(ref bt) => bt, + None => return None, + }; + let mut resolved = bt.resolved.lock().unwrap(); + unsafe { + if !*resolved { + (*bt.backtrace.get()).resolve(); + *resolved = true; + } + Some(&*bt.backtrace.get()) + } + } + + pub(super) fn is_none(&self) -> bool { + self.backtrace.is_none() + } +} + +impl fmt::Debug for InternalBacktrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InternalBacktrace") + .field("backtrace", &self.as_backtrace()) + .finish() + } +} + +fn is_backtrace_enabled Option>(get_var: F) -> bool { + match get_var(FAILURE_BACKTRACE) { + Some(ref val) if val != "0" => true, + Some(ref val) if val == "0" => false, + _ => match get_var(GENERAL_BACKTRACE) { + Some(ref val) if val != "0" => true, + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const YEA: Option<&str> = Some("1"); + const NAY: Option<&str> = Some("0"); + const NOT_SET: Option<&str> = None; + + macro_rules! test_enabled { + (failure: $failure:ident, general: $general:ident => $result:expr) => {{ + assert_eq!(is_backtrace_enabled(|var| match var { + FAILURE_BACKTRACE => $failure.map(OsString::from), + GENERAL_BACKTRACE => $general.map(OsString::from), + _ => panic!() + }), $result); + }} + } + + #[test] + fn always_enabled_if_failure_is_set_to_yes() { + test_enabled!(failure: YEA, general: YEA => true); + test_enabled!(failure: YEA, general: NOT_SET => true); + test_enabled!(failure: YEA, general: NAY => true); + } + + #[test] + fn never_enabled_if_failure_is_set_to_no() { + test_enabled!(failure: NAY, general: YEA => false); + test_enabled!(failure: NAY, general: NOT_SET => false); + test_enabled!(failure: NAY, general: NAY => false); + } + + #[test] + fn follows_general_if_failure_is_not_set() { + test_enabled!(failure: NOT_SET, general: YEA => true); + test_enabled!(failure: NOT_SET, general: NOT_SET => false); + test_enabled!(failure: NOT_SET, general: NAY => false); + } +} diff --git a/failure/src/backtrace/mod.rs b/failure/src/backtrace/mod.rs new file mode 100644 index 000000000..2d3ab8d24 --- /dev/null +++ b/failure/src/backtrace/mod.rs @@ -0,0 +1,144 @@ +use core::fmt::{self, Debug, Display}; + +macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) } +macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) } + +without_backtrace! { + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub struct Backtrace { + _secret: (), + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub fn new() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn none() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn is_none(&self) -> bool { + true + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } + + impl Display for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } +} + +with_backtrace! { + extern crate backtrace; + + mod internal; + + use self::internal::InternalBacktrace; + + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + pub struct Backtrace { + internal: InternalBacktrace + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + pub fn new() -> Backtrace { + Backtrace { internal: InternalBacktrace::new() } + } + + pub(crate) fn none() -> Backtrace { + Backtrace { internal: InternalBacktrace::none() } + } + + pub(crate) fn is_none(&self) -> bool { + self.internal.is_none() + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } + + impl Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } +} diff --git a/failure/src/box_std.rs b/failure/src/box_std.rs new file mode 100644 index 000000000..a58ae6666 --- /dev/null +++ b/failure/src/box_std.rs @@ -0,0 +1,19 @@ +use std::error::Error; +use std::fmt; +use Fail; + +pub struct BoxStd(pub Box); + +impl fmt::Display for BoxStd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl fmt::Debug for BoxStd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl Fail for BoxStd {} diff --git a/failure/src/compat.rs b/failure/src/compat.rs new file mode 100644 index 000000000..c0fc0454a --- /dev/null +++ b/failure/src/compat.rs @@ -0,0 +1,53 @@ +use core::fmt::{self, Display}; + +/// A compatibility wrapper around an error type from this crate. +/// +/// `Compat` implements `std::error::Error`, allowing the types from this +/// crate to be passed to interfaces that expect a type of that trait. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] +pub struct Compat { + pub(crate) error: E, +} + +impl Display for Compat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.error, f) + } +} + +impl Compat { + /// Unwraps this into the inner error. + pub fn into_inner(self) -> E { + self.error + } + + /// Gets a reference to the inner error. + pub fn get_ref(&self) -> &E { + &self.error + } +} + +with_std! { + use std::fmt::Debug; + use std::error::Error as StdError; + + use Error; + + impl StdError for Compat { + fn description(&self) -> &'static str { + "An error has occurred." + } + } + + impl From for Box { + fn from(error: Error) -> Box { + Box::new(Compat { error }) + } + } + + impl From for Box { + fn from(error: Error) -> Box { + Box::new(Compat { error }) + } + } +} diff --git a/failure/src/context.rs b/failure/src/context.rs new file mode 100644 index 000000000..9ab0cc4b3 --- /dev/null +++ b/failure/src/context.rs @@ -0,0 +1,180 @@ +use core::fmt::{self, Debug, Display}; + +use Fail; + +without_std! { + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context { + context: D, + } + + impl Context { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context { + Context { context } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context` to `Context` by applying a function to the contained context. + pub fn map(self, op: F) -> Context + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + } + } + + pub(crate) fn with_err(context: D, _: E) -> Context { + Context { context } + } + } + + impl Fail for Context { } + + impl Debug for Context { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + impl Display for Context { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +with_std! { + use {Error, Backtrace}; + + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context { + context: D, + failure: Either, + } + + impl Context { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context { + let failure = Either::This(Backtrace::new()); + Context { context, failure } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context` to `Context` by applying a function to the contained context. + pub fn map(self, op: F) -> Context + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + failure: self.failure, + } + } + + pub(crate) fn with_err>(context: D, error: E) -> Context { + let failure = Either::That(error.into()); + Context { context, failure } + } + } + + impl Fail for Context { + fn name(&self) -> Option<&str> { + self.failure.as_cause().and_then(|x| x.name()) + } + + fn cause(&self) -> Option<&Fail> { + self.failure.as_cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + Some(self.failure.backtrace()) + } + } + + impl Debug for Context { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}\n\n{}", self.failure, self.context) + } + } + + impl Display for Context { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + enum Either { + This(A), + That(B), + } + + impl Either { + fn backtrace(&self) -> &Backtrace { + match *self { + Either::This(ref backtrace) => backtrace, + Either::That(ref error) => error.backtrace(), + } + } + + fn as_cause(&self) -> Option<&Fail> { + match *self { + Either::This(_) => None, + Either::That(ref error) => Some(error.as_fail()) + } + } + } + + impl Debug for Either { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Either::This(ref backtrace) => write!(f, "{:?}", backtrace), + Either::That(ref error) => write!(f, "{:?}", error), + } + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +impl From for Context +where + D: Display + Send + Sync + 'static, +{ + fn from(display: D) -> Context { + Context::new(display) + } +} diff --git a/failure/src/error/error_impl.rs b/failure/src/error/error_impl.rs new file mode 100644 index 000000000..d1644caf0 --- /dev/null +++ b/failure/src/error/error_impl.rs @@ -0,0 +1,50 @@ +use core::any::TypeId; + +use Fail; +use backtrace::Backtrace; + +pub(crate) struct ErrorImpl { + inner: Box>, +} + +struct Inner { + backtrace: Backtrace, + pub(crate) failure: F, +} + +impl From for ErrorImpl { + fn from(failure: F) -> ErrorImpl { + let inner: Inner = { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { Backtrace::none() }; + Inner { failure, backtrace } + }; + ErrorImpl { inner: Box::new(inner) } + } +} + +impl ErrorImpl { + pub(crate) fn failure(&self) -> &Fail { + &self.inner.failure + } + + pub(crate) fn failure_mut(&mut self) -> &mut Fail { + &mut self.inner.failure + } + + pub(crate) fn backtrace(&self) -> &Backtrace { + &self.inner.backtrace + } + + pub(crate) fn downcast(self) -> Result { + if self.failure().__private_get_type_id__() == TypeId::of::() { + let ErrorImpl { inner } = self; + let casted = unsafe { Box::from_raw(Box::into_raw(inner) as *mut Inner) }; + let Inner { backtrace:_, failure } = *casted; + Ok(failure) + } else { + Err(self) + } + } +} diff --git a/failure/src/error/error_impl_small.rs b/failure/src/error/error_impl_small.rs new file mode 100644 index 000000000..6ff7c78ec --- /dev/null +++ b/failure/src/error/error_impl_small.rs @@ -0,0 +1,132 @@ +use std::heap::{Heap, Alloc, Layout}; + +use core::mem; +use core::ptr; + +use Fail; +use backtrace::Backtrace; + +pub(crate) struct ErrorImpl { + inner: &'static mut Inner, +} + +// Dynamically sized inner value +struct Inner { + backtrace: Backtrace, + vtable: *const VTable, + failure: FailData, +} + +unsafe impl Send for Inner { } +unsafe impl Sync for Inner { } + +extern { + type VTable; + type FailData; +} + +#[allow(dead_code)] +struct InnerRaw { + header: InnerHeader, + failure: F, +} + +#[allow(dead_code)] +struct InnerHeader { + backtrace: Backtrace, + vtable: *const VTable, +} + +struct TraitObject { + #[allow(dead_code)] + data: *const FailData, + vtable: *const VTable, +} + +impl From for ErrorImpl { + fn from(failure: F) -> ErrorImpl { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { + Backtrace::none() + }; + + unsafe { + let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; + + let ptr: *mut InnerRaw = match Heap.alloc(Layout::new::>()) { + Ok(p) => p as *mut InnerRaw, + Err(e) => Heap.oom(e), + }; + + // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` + ptr::write(ptr, InnerRaw { + header: InnerHeader { + backtrace, + vtable, + }, + failure, + }); + + let inner: &'static mut Inner = mem::transmute(ptr); + + ErrorImpl { inner } + } + } +} + +impl ErrorImpl { + pub(crate) fn failure(&self) -> &Fail { + unsafe { + mem::transmute::(TraitObject { + data: &self.inner.failure as *const FailData, + vtable: self.inner.vtable, + }) + } + } + + pub(crate) fn failure_mut(&mut self) -> &mut Fail { + unsafe { + mem::transmute::(TraitObject { + data: &mut self.inner.failure as *const FailData, + vtable: self.inner.vtable, + }) + } + } + + pub(crate) fn backtrace(&self) -> &Backtrace { + &self.inner.backtrace + } + + pub(crate) fn downcast(self) -> Result { + let ret: Option = self.failure().downcast_ref().map(|fail| { + unsafe { + // drop the backtrace + let _ = ptr::read(&self.inner.backtrace as *const Backtrace); + // read out the fail type + ptr::read(fail as *const T) + } + }); + match ret { + Some(ret) => { + // forget self (backtrace is dropped, failure is moved + mem::forget(self); + Ok(ret) + } + _ => Err(self) + } + } +} + + +#[cfg(test)] +mod test { + use std::mem::size_of; + + use super::ErrorImpl; + + #[test] + fn assert_is_one_word() { + assert_eq!(size_of::(), size_of::()); + } +} diff --git a/failure/src/error/mod.rs b/failure/src/error/mod.rs new file mode 100644 index 000000000..152807bd9 --- /dev/null +++ b/failure/src/error/mod.rs @@ -0,0 +1,248 @@ +use core::fmt::{self, Display, Debug}; + +use {Causes, Fail}; +use backtrace::Backtrace; +use context::Context; +use compat::Compat; + +#[cfg(feature = "std")] +use box_std::BoxStd; + +#[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")] +mod error_impl; +use self::error_impl::ErrorImpl; + +#[cfg(feature = "std")] +use std::error::Error as StdError; + + +/// The `Error` type, which can contain any failure. +/// +/// Functions which accumulate many kinds of errors should return this type. +/// All failures can be converted into it, so functions which catch those +/// errors can be tried with `?` inside of a function that returns this kind +/// of error. +/// +/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` +/// information, and can be downcast into the failure that underlies it for +/// more detailed inspection. +pub struct Error { + imp: ErrorImpl, +} + +impl From for Error { + fn from(failure: F) -> Error { + Error { + imp: ErrorImpl::from(failure) + } + } +} + +impl Error { + /// Creates an `Error` from `Box`. + /// + /// This method is useful for comparability with code, + /// which does not use the `Fail` trait. + /// + /// # Example + /// + /// ``` + /// use std::error::Error as StdError; + /// use failure::Error; + /// + /// fn app_fn() -> Result { + /// let x = library_fn().map_err(Error::from_boxed_compat)?; + /// Ok(x * 2) + /// } + /// + /// fn library_fn() -> Result> { + /// Ok(92) + /// } + /// ``` + #[cfg(feature = "std")] + pub fn from_boxed_compat(err: Box) -> Error { + Error::from(BoxStd(err)) + } + + /// Return a reference to the underlying failure that this `Error` + /// contains. + pub fn as_fail(&self) -> &Fail { + self.imp.failure() + } + + /// Returns the name of the underlying fail. + pub fn name(&self) -> Option<&str> { + self.as_fail().name() + } + + /// Returns a reference to the underlying cause of this `Error`. Unlike the + /// method on `Fail`, this does not return an `Option`. The `Error` type + /// always has an underlying failure. + /// + /// This method has been deprecated in favor of the [Error::as_fail] method, + /// which does the same thing. + #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")] + pub fn cause(&self) -> &Fail { + self.as_fail() + } + + /// Gets a reference to the `Backtrace` for this `Error`. + /// + /// If the failure this wrapped carried a backtrace, that backtrace will + /// be returned. Otherwise, the backtrace will have been constructed at + /// the point that failure was cast into the `Error` type. + pub fn backtrace(&self) -> &Backtrace { + self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace()) + } + + /// Provides context for this `Error`. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or a failure, or some other custom context-carrying + /// type. + pub fn context(self, context: D) -> Context { + Context::with_err(context, self) + } + + /// Wraps `Error` in a compatibility type. + /// + /// This type implements the `Error` trait from `std::error`. If you need + /// to pass failure's `Error` to an interface that takes any `Error`, you + /// can use this method to get a compatible type. + pub fn compat(self) -> Compat { + Compat { error: self } + } + + /// Attempts to downcast this `Error` to a particular `Fail` type. + /// + /// This downcasts by value, returning an owned `T` if the underlying + /// failure is of the type `T`. For this reason it returns a `Result` - in + /// the case that the underlying error is of a different type, the + /// original `Error` is returned. + pub fn downcast(self) -> Result { + self.imp.downcast().map_err(|imp| Error { imp }) + } + + /// Returns the "root cause" of this error - the last value in the + /// cause chain which does not return an underlying `cause`. + pub fn find_root_cause(&self) -> &Fail { + self.as_fail().find_root_cause() + } + + /// Returns a iterator over the causes of this error with the cause + /// of the fail as the first item and the `root_cause` as the final item. + /// + /// Use `iter_chain` to also include the fail of this error itself. + pub fn iter_causes(&self) -> Causes { + self.as_fail().iter_causes() + } + + /// Returns a iterator over all fails up the chain from the current + /// as the first item up to the `root_cause` as the final item. + /// + /// This means that the chain also includes the fail itself which + /// means that it does *not* start with `cause`. To skip the outermost + /// fail use `iter_causes` instead. + pub fn iter_chain(&self) -> Causes { + self.as_fail().iter_chain() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref(&self) -> Option<&T> { + self.imp.failure().downcast_ref() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// mutable reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut(&mut self) -> Option<&mut T> { + self.imp.failure_mut().downcast_mut() + } + + /// Deprecated alias to `find_root_cause`. + #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")] + pub fn root_cause(&self) -> &Fail { + ::find_root_cause(self.as_fail()) + } + + /// Deprecated alias to `iter_causes`. + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + pub fn causes(&self) -> Causes { + Causes { fail: Some(self.as_fail()) } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.imp.failure(), f) + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let backtrace = self.imp.backtrace(); + if backtrace.is_none() { + Debug::fmt(&self.imp.failure(), f) + } else { + write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace) + } + } +} + +impl AsRef for Error { + fn as_ref(&self) -> &Fail { + self.as_fail() + } +} + +#[cfg(test)] +mod test { + use std::io; + use super::Error; + + fn assert_just_data() { } + + #[test] + fn assert_error_is_just_data() { + assert_just_data::(); + } + + #[test] + fn methods_seem_to_work() { + let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); + let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + assert!(error.downcast_ref::().is_some()); + let _: ::Backtrace = *error.backtrace(); + assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); + assert_eq!(format!("{}", io_error), format!("{}", error)); + drop(error); + assert!(true); + } + + #[test] + fn downcast_can_be_used() { + let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + { + let real_io_error_ref = error.downcast_ref::().unwrap(); + assert_eq!(real_io_error_ref.to_string(), "test"); + } + { + let real_io_error_mut = error.downcast_mut::().unwrap(); + assert_eq!(real_io_error_mut.to_string(), "test"); + } + let real_io_error = error.downcast::().unwrap(); + assert_eq!(real_io_error.to_string(), "test"); + } +} diff --git a/failure/src/error_message.rs b/failure/src/error_message.rs new file mode 100644 index 000000000..560d317b4 --- /dev/null +++ b/failure/src/error_message.rs @@ -0,0 +1,32 @@ +use core::fmt::{self, Display, Debug}; + +use Fail; +use Error; + +/// Constructs a `Fail` type from a string. +/// +/// This is a convenient way to turn a string into an error value that +/// can be passed around, if you do not want to create a new `Fail` type for +/// this use case. +pub fn err_msg(msg: D) -> Error { + Error::from(ErrorMessage { msg }) +} + +/// A `Fail` type that just contains an error message. You can construct +/// this from the `err_msg` function. +#[derive(Debug)] +struct ErrorMessage { + msg: D, +} + +impl Fail for ErrorMessage { + fn name(&self) -> Option<&str> { + Some("failure::ErrorMessage") + } +} + +impl Display for ErrorMessage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.msg, f) + } +} diff --git a/failure/src/lib.rs b/failure/src/lib.rs new file mode 100644 index 000000000..02c239f3a --- /dev/null +++ b/failure/src/lib.rs @@ -0,0 +1,307 @@ +//! An experimental new error-handling library. Guide-style introduction +//! is available [here](https://boats.gitlab.io/failure/). +//! +//! The primary items exported by this library are: +//! +//! - `Fail`: a new trait for custom error types in Rust. +//! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them +//! at higher levels. +//! +//! As a general rule, library authors should create their own error types and +//! implement `Fail` for them, whereas application authors should primarily +//! deal with the `Error` type. There are exceptions to this rule, though, in +//! both directions, and users should do whatever seems most appropriate to +//! their situation. +//! +//! ## Backtraces +//! +//! Backtraces are disabled by default. To turn backtraces on, enable +//! the `backtrace` Cargo feature and set the `RUST_BACKTRACE` environment +//! variable to a non-zero value (this also enables backtraces for panics). +//! Use the `RUST_FAILURE_BACKTRACE` variable to enable or disable backtraces +//! for `failure` specifically. +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] +#![deny(warnings)] +#![cfg_attr(feature = "small-error", feature(extern_types, allocator_api))] + +macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } +macro_rules! without_std { ($($i:item)*) => ($(#[cfg(not(feature = "std"))]$i)*) } + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +mod as_fail; +mod backtrace; +#[cfg(feature = "std")] +mod box_std; +mod compat; +mod context; +mod result_ext; + +use core::any::TypeId; +use core::fmt::{Debug, Display}; + +pub use as_fail::AsFail; +pub use backtrace::Backtrace; +pub use compat::Compat; +pub use context::Context; +pub use result_ext::ResultExt; + +#[cfg(feature = "failure_derive")] +#[allow(unused_imports)] +#[macro_use] +extern crate failure_derive; + +#[cfg(feature = "failure_derive")] +#[doc(hidden)] +pub use failure_derive::*; + +with_std! { + extern crate core; + + mod sync_failure; + pub use sync_failure::SyncFailure; + + mod error; + + use std::error::Error as StdError; + + pub use error::Error; + + /// A common result with an `Error`. + pub type Fallible = Result; + + mod macros; + mod error_message; + pub use error_message::err_msg; +} + +/// The `Fail` trait. +/// +/// Implementors of this trait are called 'failures'. +/// +/// All error types should implement `Fail`, which provides a baseline of +/// functionality that they all share. +/// +/// `Fail` has no required methods, but it does require that your type +/// implement several other traits: +/// +/// - `Display`: to print a user-friendly representation of the error. +/// - `Debug`: to print a verbose, developer-focused representation of the +/// error. +/// - `Send + Sync`: Your error type is required to be safe to transfer to and +/// reference from another thread +/// +/// Additionally, all failures must be `'static`. This enables downcasting. +/// +/// `Fail` provides several methods with default implementations. Two of these +/// may be appropriate to override depending on the definition of your +/// particular failure: the `cause` and `backtrace` methods. +/// +/// The `failure_derive` crate provides a way to derive the `Fail` trait for +/// your type. Additionally, all types that already implement +/// `std::error::Error`, and are also `Send`, `Sync`, and `'static`, implement +/// `Fail` by a blanket impl. +pub trait Fail: Display + Debug + Send + Sync + 'static { + /// Returns the "name" of the error. + /// + /// This is typically the type name. Not all errors will implement + /// this. This method is expected to be most useful in situations + /// where errors need to be reported to external instrumentation systems + /// such as crash reporters. + fn name(&self) -> Option<&str> { + None + } + + /// Returns a reference to the underlying cause of this failure, if it + /// is an error that wraps other errors. + /// + /// Returns `None` if this failure does not have another error as its + /// underlying cause. By default, this returns `None`. + /// + /// This should **never** return a reference to `self`, but only return + /// `Some` when it can return a **different** failure. Users may loop + /// over the cause chain, and returning `self` would result in an infinite + /// loop. + fn cause(&self) -> Option<&Fail> { + None + } + + /// Returns a reference to the `Backtrace` carried by this failure, if it + /// carries one. + /// + /// Returns `None` if this failure does not carry a backtrace. By + /// default, this returns `None`. + fn backtrace(&self) -> Option<&Backtrace> { + None + } + + /// Provides context for this failure. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or another failure, or some other custom context-carrying + /// type. + fn context(self, context: D) -> Context + where + D: Display + Send + Sync + 'static, + Self: Sized, + { + Context::with_err(context, self) + } + + /// Wraps this failure in a compatibility wrapper that implements + /// `std::error::Error`. + /// + /// This allows failures to be compatible with older crates that + /// expect types that implement the `Error` trait from `std::error`. + fn compat(self) -> Compat + where + Self: Sized, + { + Compat { error: self } + } + + #[doc(hidden)] + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + fn causes(&self) -> Causes + where + Self: Sized, + { + Causes { fail: Some(self) } + } + + #[doc(hidden)] + #[deprecated( + since = "0.1.2", + note = "please use the 'find_root_cause()' method instead" + )] + fn root_cause(&self) -> &Fail + where + Self: Sized, + { + find_root_cause(self) + } + + #[doc(hidden)] + fn __private_get_type_id__(&self) -> TypeId { + TypeId::of::() + } +} + +impl Fail { + /// Attempts to downcast this failure to a concrete type by reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref(&self) -> Option<&T> { + if self.__private_get_type_id__() == TypeId::of::() { + unsafe { Some(&*(self as *const Fail as *const T)) } + } else { + None + } + } + + /// Attempts to downcast this failure to a concrete type by mutable + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.__private_get_type_id__() == TypeId::of::() { + unsafe { Some(&mut *(self as *mut Fail as *mut T)) } + } else { + None + } + } + + /// Returns the "root cause" of this `Fail` - the last value in the + /// cause chain which does not return an underlying `cause`. + /// + /// If this type does not have a cause, `self` is returned, because + /// it is its own root cause. + /// + /// This is equivalent to iterating over `iter_causes()` and taking + /// the last item. + pub fn find_root_cause(&self) -> &Fail { + find_root_cause(self) + } + + /// Returns a iterator over the causes of this `Fail` with the cause + /// of this fail as the first item and the `root_cause` as the final item. + /// + /// Use `iter_chain` to also include the fail itself. + pub fn iter_causes(&self) -> Causes { + Causes { fail: self.cause() } + } + + /// Returns a iterator over all fails up the chain from the current + /// as the first item up to the `root_cause` as the final item. + /// + /// This means that the chain also includes the fail itself which + /// means that it does *not* start with `cause`. To skip the outermost + /// fail use `iter_causes` instead. + pub fn iter_chain(&self) -> Causes { + Causes { fail: Some(self) } + } + + /// Deprecated alias to `find_root_cause`. + #[deprecated( + since = "0.1.2", + note = "please use the 'find_root_cause()' method instead" + )] + pub fn root_cause(&self) -> &Fail { + find_root_cause(self) + } + + /// Deprecated alias to `iter_chain`. + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + pub fn causes(&self) -> Causes { + Causes { fail: Some(self) } + } +} + +#[cfg(feature = "std")] +impl Fail for E {} + +#[cfg(feature = "std")] +impl Fail for Box { + fn cause(&self) -> Option<&Fail> { + (**self).cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + (**self).backtrace() + } +} + +/// A iterator over the causes of a `Fail` +pub struct Causes<'f> { + fail: Option<&'f Fail>, +} + +impl<'f> Iterator for Causes<'f> { + type Item = &'f Fail; + fn next(&mut self) -> Option<&'f Fail> { + self.fail.map(|fail| { + self.fail = fail.cause(); + fail + }) + } +} + +fn find_root_cause(mut fail: &Fail) -> &Fail { + while let Some(cause) = fail.cause() { + fail = cause; + } + + fail +} diff --git a/failure/src/macros.rs b/failure/src/macros.rs new file mode 100644 index 000000000..decea204f --- /dev/null +++ b/failure/src/macros.rs @@ -0,0 +1,51 @@ +/// Exits a function early with an `Error`. +/// +/// The `bail!` macro provides an easy way to exit a function. `bail!(X)` is +/// equivalent to writing: +/// +/// ```rust,ignore +/// return Err(format_err!(X)) +/// ``` +#[macro_export] +macro_rules! bail { + ($e:expr) => { + return Err($crate::err_msg($e)); + }; + ($fmt:expr, $($arg:tt)*) => { + return Err($crate::err_msg(format!($fmt, $($arg)*))); + }; +} + +/// Exits a function early with an `Error` if the condition is not satisfied. +/// +/// Similar to `assert!`, `ensure!` takes a condition and exits the function +/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`, +/// it does not panic. +#[macro_export(local_inner_macros)] +macro_rules! ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + bail!($e); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if !($cond) { + bail!($fmt, $($arg)*); + } + }; +} + +/// Constructs an `Error` using the standard string interpolation syntax. +/// +/// ```rust +/// #[macro_use] extern crate failure; +/// +/// fn main() { +/// let code = 101; +/// let err = format_err!("Error code: {}", code); +/// } +/// ``` +#[macro_export] +macro_rules! format_err { + ($($arg:tt)*) => { $crate::err_msg(format!($($arg)*)) } +} diff --git a/failure/src/result_ext.rs b/failure/src/result_ext.rs new file mode 100644 index 000000000..f4125cdd6 --- /dev/null +++ b/failure/src/result_ext.rs @@ -0,0 +1,203 @@ +use core::fmt::Display; + +use {Compat, Context, Fail}; + +/// Extension methods for `Result`. +pub trait ResultExt { + /// Wraps the error in `Compat` to make it compatible with older error + /// handling APIs that expect `std::error::Error`. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// use std::error::Error; + /// # use std::fmt; + /// # + /// # extern crate failure; + /// # + /// # use tests::failure::ResultExt; + /// # + /// # #[derive(Debug)] + /// struct CustomError; + /// + /// impl Error for CustomError { + /// fn description(&self) -> &str { + /// "My custom error message" + /// } + /// + /// fn cause(&self) -> Option<&Error> { + /// None + /// } + /// } + /// # + /// # impl fmt::Display for CustomError { + /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// # write!(f, "{}", self.description()) + /// # } + /// # } + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError).compat()? + /// })().with_context(|e| { + /// format!("An error occured: {}", e) + /// }).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured: My custom error message"); + /// # } + /// + /// # } + /// ``` + fn compat(self) -> Result>; + + /// Wraps the error type in a context type. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure; + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure_derive; + /// # + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// # + /// # use failure::{self, ResultExt}; + /// # + /// #[derive(Fail, Debug)] + /// #[fail(display = "")] + /// struct CustomError; + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError)? + /// })().context(format!("An error occured")).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured"); + /// # } + /// + /// # } + /// ``` + fn context(self, context: D) -> Result> + where + D: Display + Send + Sync + 'static; + + /// Wraps the error type in a context type generated by looking at the + /// error value. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure; + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure_derive; + /// # + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// # + /// # use failure::{self, ResultExt}; + /// # + /// #[derive(Fail, Debug)] + /// #[fail(display = "My custom error message")] + /// struct CustomError; + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError)? + /// })().with_context(|e| { + /// format!("An error occured: {}", e) + /// }).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured: My custom error message"); + /// # } + /// + /// # } + /// ``` + fn with_context(self, f: F) -> Result> + where + F: FnOnce(&E) -> D, + D: Display + Send + Sync + 'static; +} + +impl ResultExt for Result +where + E: Fail, +{ + fn compat(self) -> Result> { + self.map_err(|err| err.compat()) + } + + fn context(self, context: D) -> Result> + where + D: Display + Send + Sync + 'static, + { + self.map_err(|failure| failure.context(context)) + } + + fn with_context(self, f: F) -> Result> + where + F: FnOnce(&E) -> D, + D: Display + Send + Sync + 'static, + { + self.map_err(|failure| { + let context = f(&failure); + failure.context(context) + }) + } +} + +with_std! { + use Error; + + impl ResultExt for Result { + fn compat(self) -> Result> { + self.map_err(|err| err.compat()) + } + + fn context(self, context: D) -> Result> where + D: Display + Send + Sync + 'static + { + self.map_err(|failure| failure.context(context)) + } + + fn with_context(self, f: F) -> Result> where + F: FnOnce(&Error) -> D, + D: Display + Send + Sync + 'static + { + self.map_err(|failure| { + let context = f(&failure); + failure.context(context) + }) + } + } +} diff --git a/failure/src/small_error.rs b/failure/src/small_error.rs new file mode 100644 index 000000000..09646e391 --- /dev/null +++ b/failure/src/small_error.rs @@ -0,0 +1,264 @@ +use core::fmt::{self, Display, Debug}; +use std::heap::{Heap, Alloc, Layout}; + +use core::mem; +use core::ptr; + +use {Causes, Fail}; +use backtrace::Backtrace; +use context::Context; +use compat::Compat; + +/// The `Error` type, which can contain any failure. +/// +/// Functions which accumulate many kinds of errors should return this type. +/// All failures can be converted into it, so functions which catch those +/// errors can be tried with `?` inside of a function that returns this kind +/// of error. +/// +/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` +/// information, and can be downcast into the failure that underlies it for +/// more detailed inspection. +pub struct Error { + inner: &'static mut Inner, +} + +// Dynamically sized inner value +struct Inner { + backtrace: Backtrace, + vtable: *const VTable, + failure: FailData, +} + +unsafe impl Send for Inner { } +unsafe impl Sync for Inner { } + +extern { + type VTable; + type FailData; +} + +struct InnerRaw { + header: InnerHeader, + failure: F, +} + +struct InnerHeader { + backtrace: Backtrace, + vtable: *const VTable, +} + +struct TraitObject { + #[allow(dead_code)] + data: *const FailData, + vtable: *const VTable, +} + +impl From for Error { + fn from(failure: F) -> Error { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { + Backtrace::none() + }; + + unsafe { + let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; + + let ptr: *mut InnerRaw = match Heap.alloc(Layout::new::>()) { + Ok(p) => p as *mut InnerRaw, + Err(e) => Heap.oom(e), + }; + + // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` + ptr::write(ptr, InnerRaw { + header: InnerHeader { + backtrace, + vtable, + }, + failure, + }); + + let inner: &'static mut Inner = mem::transmute(ptr); + + Error { inner } + } + } +} + +impl Inner { + fn failure(&self) -> &Fail { + unsafe { + mem::transmute::(TraitObject { + data: &self.failure as *const FailData, + vtable: self.vtable, + }) + } + } + + fn failure_mut(&mut self) -> &mut Fail { + unsafe { + mem::transmute::(TraitObject { + data: &mut self.failure as *const FailData, + vtable: self.vtable, + }) + } + } +} + +impl Error { + /// Returns a reference to the underlying cause of this `Error`. Unlike the + /// method on `Fail`, this does not return an `Option`. The `Error` type + /// always has an underlying failure. + pub fn cause(&self) -> &Fail { + self.inner.failure() + } + + /// Gets a reference to the `Backtrace` for this `Error`. + /// + /// If the failure this wrapped carried a backtrace, that backtrace will + /// be returned. Otherwise, the backtrace will have been constructed at + /// the point that failure was cast into the `Error` type. + pub fn backtrace(&self) -> &Backtrace { + self.inner.failure().backtrace().unwrap_or(&self.inner.backtrace) + } + + /// Provides context for this `Error`. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or a failure, or some other custom context-carrying + /// type. + pub fn context(self, context: D) -> Context { + Context::with_err(context, self) + } + + /// Wraps `Error` in a compatibility type. + /// + /// This type implements the `Error` trait from `std::error`. If you need + /// to pass failure's `Error` to an interface that takes any `Error`, you + /// can use this method to get a compatible type. + pub fn compat(self) -> Compat { + Compat { error: self } + } + + /// Attempts to downcast this `Error` to a particular `Fail` type. + /// + /// This downcasts by value, returning an owned `T` if the underlying + /// failure is of the type `T`. For this reason it returns a `Result` - in + /// the case that the underlying error is of a different type, the + /// original `Error` is returned. + pub fn downcast(self) -> Result { + let ret: Option = self.downcast_ref().map(|fail| { + unsafe { + // drop the backtrace + let _ = ptr::read(&self.inner.backtrace as *const Backtrace); + // read out the fail type + ptr::read(fail as *const T) + } + }); + match ret { + Some(ret) => { + // forget self (backtrace is dropped, failure is moved + mem::forget(self); + Ok(ret) + } + _ => Err(self) + } + } + + /// Returns the "root cause" of this error - the last value in the + /// cause chain which does not return an underlying `cause`. + pub fn root_cause(&self) -> &Fail { + ::find_root_cause(self.cause()) + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref(&self) -> Option<&T> { + self.inner.failure().downcast_ref() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// mutable reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut(&mut self) -> Option<&mut T> { + self.inner.failure_mut().downcast_mut() + } + + /// Returns a iterator over the causes of the `Error`, beginning with + /// the failure returned by the `cause` method and ending with the failure + /// returned by `root_cause`. + pub fn causes(&self) -> Causes { + Causes { fail: Some(self.cause()) } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.inner.failure(), f) + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.inner.backtrace.is_none() { + Debug::fmt(self.inner.failure(), f) + } else { + write!(f, "{:?}\n\n{:?}", self.inner.failure(), self.inner.backtrace) + } + } +} + +impl Drop for Error { + fn drop(&mut self) { + unsafe { + let layout = { + let header = Layout::new::(); + header.extend(Layout::for_value(self.inner.failure())).unwrap().0 + }; + Heap.dealloc(self.inner as *const _ as *const u8 as *mut u8, layout); + } + } +} + +#[cfg(test)] +mod test { + use std::mem::size_of; + use std::io; + + use super::Error; + + #[test] + fn assert_error_is_just_data() { + fn assert_just_data() { } + assert_just_data::(); + } + + #[test] + fn assert_is_one_word() { + assert_eq!(size_of::(), size_of::()); + } + + #[test] + fn methods_seem_to_work() { + let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); + let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + assert!(error.downcast_ref::().is_some()); + let _: ::Backtrace = *error.backtrace(); + assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); + assert_eq!(format!("{}", io_error), format!("{}", error)); + drop(error); + assert!(true); + } +} diff --git a/failure/src/sync_failure.rs b/failure/src/sync_failure.rs new file mode 100644 index 000000000..63e966cdd --- /dev/null +++ b/failure/src/sync_failure.rs @@ -0,0 +1,97 @@ +use Fail; +use std::error::Error; +use std::fmt::{self, Debug, Display}; +use std::sync::Mutex; + +/// Wrapper for `std` errors to make them `Sync`. +/// +/// This exists to coerce existing types that are only `Error + Send + +/// 'static` into a `Fail`-compatible representation, most notably for +/// types generated by `error-chain`. +/// +/// Unfortunately, this requires wrapping the error in a `Mutex`, which must +/// be locked for every `Debug`/`Display`. Therefore, this should be +/// something of a last resort in making the error work with `failure`. +/// +pub struct SyncFailure { + inner: Mutex, +} + +impl SyncFailure { + /// Wraps a non-`Sync` `Error` in order to make it implement `Fail`. + /// + /// # Example + /// + /// ```rust + /// extern crate failure; + /// + /// # use std::error::Error as StdError; + /// # use std::fmt::{self, Display}; + /// use failure::{Error, SyncFailure}; + /// use std::cell::RefCell; + /// + /// #[derive(Debug)] + /// struct NonSyncError { + /// // RefCells are non-Sync, so structs containing them will be + /// // non-Sync as well. + /// count: RefCell, + /// } + /// + /// // implement Display/Error for NonSyncError... + /// # + /// # impl StdError for NonSyncError { + /// # fn description(&self) -> &str { + /// # "oops!" + /// # } + /// # } + /// # + /// # impl Display for NonSyncError { + /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// # write!(f, "oops!") + /// # } + /// # } + /// + /// fn returns_error() -> Result<(), NonSyncError> { + /// // Do stuff + /// # Ok(()) + /// } + /// + /// fn my_function() -> Result<(), Error> { + /// // without the map_err here, we end up with a compile error + /// // complaining that NonSyncError doesn't implement Sync. + /// returns_error().map_err(SyncFailure::new)?; + /// // Do more stuff + /// # Ok(()) + /// } + /// # + /// # fn main() { + /// # my_function().unwrap(); + /// # } + /// ``` + /// + pub fn new(err: E) -> Self { + SyncFailure { + inner: Mutex::new(err), + } + } +} + +impl Display for SyncFailure +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.lock().unwrap().fmt(f) + } +} + +impl Debug for SyncFailure +where + T: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (*self.inner.lock().unwrap()).fmt(f) + } +} + +impl Fail for SyncFailure {} diff --git a/failure/tests/basic_fail.rs b/failure/tests/basic_fail.rs new file mode 100644 index 000000000..574886db7 --- /dev/null +++ b/failure/tests/basic_fail.rs @@ -0,0 +1,21 @@ +#[macro_use] +extern crate failure; + +use failure::Fail; + +#[test] +fn test_name() { + #[derive(Fail, Debug)] + #[fail(display = "my error")] + struct MyError; + + let err = MyError; + + assert_eq!(err.to_string(), "my error"); + assert_eq!(err.name(), Some("basic_fail::MyError")); + + let ctx = err.context("whatever"); + + assert_eq!(ctx.to_string(), "whatever"); + assert_eq!(ctx.name(), Some("basic_fail::MyError")); +} \ No newline at end of file diff --git a/failure/tests/fail_compat.rs b/failure/tests/fail_compat.rs new file mode 100644 index 000000000..1b3bc7c39 --- /dev/null +++ b/failure/tests/fail_compat.rs @@ -0,0 +1,35 @@ +#[macro_use] +extern crate failure; + +use failure::Fail; + +fn return_failure() -> Result<(), failure::Error> { + #[derive(Fail, Debug)] + #[fail(display = "my error")] + struct MyError; + + let err = MyError; + Err(err.into()) +} + +fn return_error() -> Result<(), Box> { + return_failure()?; + Ok(()) +} + +fn return_error_send_sync() -> Result<(), Box> { + return_failure()?; + Ok(()) +} + +#[test] +fn smoke_default_compat() { + let err = return_error(); + assert!(err.is_err()); +} + +#[test] +fn smoke_compat_send_sync() { + let err = return_error_send_sync(); + assert!(err.is_err()); +} diff --git a/failure/tests/macro_trailing_comma.rs b/failure/tests/macro_trailing_comma.rs new file mode 100644 index 000000000..6d8b80ee5 --- /dev/null +++ b/failure/tests/macro_trailing_comma.rs @@ -0,0 +1,54 @@ +#[macro_use] +extern crate failure; + +// NOTE: +// +// This test is in a separate file due to the fact that ensure! cannot be used +// from within failure. +// +// (you get: 'macro-expanded `macro_export` macros from the current crate cannot +// be referred to by absolute paths') + +// Encloses an early-returning macro in an IIFE so that we +// can treat it as a Result-returning function. +macro_rules! wrap_early_return { + ($expr:expr) => {{ + fn func() -> Result<(), failure::Error> { + let _ = $expr; + + #[allow(unreachable_code)] + Ok(()) + } + func().map_err(|e| e.to_string()) + }}; +} + +#[test] +fn bail() { + assert_eq!( + wrap_early_return!(bail!("test")), + wrap_early_return!(bail!("test",))); + assert_eq!( + wrap_early_return!(bail!("test {}", 4)), + wrap_early_return!(bail!("test {}", 4,))); +} + +#[test] +fn ensure() { + assert_eq!( + wrap_early_return!(ensure!(false, "test")), + wrap_early_return!(ensure!(false, "test",))); + assert_eq!( + wrap_early_return!(ensure!(false, "test {}", 4)), + wrap_early_return!(ensure!(false, "test {}", 4,))); +} + +#[test] +fn format_err() { + assert_eq!( + format_err!("test").to_string(), + format_err!("test",).to_string()); + assert_eq!( + format_err!("test {}", 4).to_string(), + format_err!("test {}", 4,).to_string()); +} diff --git a/failure/travis.sh b/failure/travis.sh new file mode 100644 index 000000000..6c621ca5d --- /dev/null +++ b/failure/travis.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +cargo_test() { + cargo test "$@" || { exit 101; } +} + +test_failure_in() { + cd $1 + cargo_test + cargo_test --no-default-features + cargo_test --features backtrace + test_derive_in "$1/failure_derive" + cd $DIR +} + +test_derive_in() { + cd $1 + cargo_test + cd $DIR +} + +test_nightly_features_in() { + cd $1 + #cargo_test --features small-error + cargo_test --all-features + cd $DIR +} + +main() { + test_failure_in "$DIR/failure-1.X" + test_failure_in "$DIR/failure-0.1.X" + if [ "${TRAVIS_RUST_VERSION}" = "nightly" ]; then + test_nightly_features_in "$DIR/failure-1.X" + fi +} + +main diff --git a/failure_derive/.cargo-checksum.json b/failure_derive/.cargo-checksum.json new file mode 100644 index 000000000..d65cd7d0e --- /dev/null +++ b/failure_derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"} \ No newline at end of file diff --git a/failure_derive/Cargo.toml b/failure_derive/Cargo.toml new file mode 100644 index 000000000..6691a222f --- /dev/null +++ b/failure_derive/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "failure_derive" +version = "0.1.5" +authors = ["Without Boats "] +build = "build.rs" +description = "derives for the failure crate" +homepage = "https://rust-lang-nursery.github.io/failure/" +documentation = "https://docs.rs/failure" +license = "MIT OR Apache-2.0" +repository = "https://github.com/withoutboats/failure_derive" + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "0.4.8" + +[dependencies.quote] +version = "0.6.3" + +[dependencies.syn] +version = "0.15.0" + +[dependencies.synstructure] +version = "0.10.0" +[dev-dependencies.failure] +version = "0.1.0" + +[features] +std = [] diff --git a/failure_derive/build.rs b/failure_derive/build.rs new file mode 100644 index 000000000..8f220458d --- /dev/null +++ b/failure_derive/build.rs @@ -0,0 +1,39 @@ +use std::env; +use std::process::Command; +use std::str; +use std::str::FromStr; + +fn main() { + if rustc_has_dyn_trait() { + println!("cargo:rustc-cfg=has_dyn_trait"); + } +} + +fn rustc_has_dyn_trait() -> bool { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return false, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return false, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return false, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return true; + } + + let next = match pieces.next() { + Some(next) => next, + None => return false, + }; + + u32::from_str(next).unwrap_or(0) >= 27 +} diff --git a/failure_derive/src/lib.rs b/failure_derive/src/lib.rs new file mode 100644 index 000000000..7df10d17e --- /dev/null +++ b/failure_derive/src/lib.rs @@ -0,0 +1,259 @@ +extern crate proc_macro2; +extern crate syn; + +#[macro_use] +extern crate synstructure; +#[macro_use] +extern crate quote; + +use proc_macro2::{TokenStream, Span}; +use syn::LitStr; +use syn::spanned::Spanned; + +#[derive(Debug)] +struct Error(TokenStream); + +impl Error { + fn new(span: Span, message: &str) -> Error { + Error(quote_spanned! { span => + compile_error!(#message); + }) + } + + fn into_tokens(self) -> TokenStream { + self.0 + } +} + +decl_derive!([Fail, attributes(fail, cause)] => fail_derive); + +fn fail_derive(s: synstructure::Structure) -> TokenStream { + match fail_derive_impl(s) { + Err(err) => err.into_tokens(), + Ok(tokens) => tokens, + } +} + +fn fail_derive_impl(s: synstructure::Structure) -> Result { + let make_dyn = if cfg!(has_dyn_trait) { + quote! { &dyn } + } else { + quote! { & } + }; + + let ty_name = LitStr::new(&s.ast().ident.to_string(), Span::call_site()); + + let cause_body = s.each_variant(|v| { + if let Some(cause) = v.bindings().iter().find(is_cause) { + quote!(return Some(::failure::AsFail::as_fail(#cause))) + } else { + quote!(return None) + } + }); + + let bt_body = s.each_variant(|v| { + if let Some(bi) = v.bindings().iter().find(is_backtrace) { + quote!(return Some(#bi)) + } else { + quote!(return None) + } + }); + + let fail = s.unbound_impl( + quote!(::failure::Fail), + quote! { + fn name(&self) -> Option<&str> { + Some(concat!(module_path!(), "::", #ty_name)) + } + + #[allow(unreachable_code)] + fn cause(&self) -> ::failure::_core::option::Option<#make_dyn(::failure::Fail)> { + match *self { #cause_body } + None + } + + #[allow(unreachable_code)] + fn backtrace(&self) -> ::failure::_core::option::Option<&::failure::Backtrace> { + match *self { #bt_body } + None + } + }, + ); + let display = display_body(&s)?.map(|display_body| { + s.unbound_impl( + quote!(::failure::_core::fmt::Display), + quote! { + #[allow(unreachable_code)] + fn fmt(&self, f: &mut ::failure::_core::fmt::Formatter) -> ::failure::_core::fmt::Result { + match *self { #display_body } + write!(f, "An error has occurred.") + } + }, + ) + }); + + Ok(quote! { + #fail + #display + }) +} + +fn display_body(s: &synstructure::Structure) -> Result, Error> { + let mut msgs = s.variants().iter().map(|v| find_error_msg(&v.ast().attrs)); + if msgs.all(|msg| msg.map(|m| m.is_none()).unwrap_or(true)) { + return Ok(None); + } + + let mut tokens = TokenStream::new(); + for v in s.variants() { + let msg = + find_error_msg(&v.ast().attrs)? + .ok_or_else(|| Error::new( + v.ast().ident.span(), + "All variants must have display attribute." + ))?; + if msg.nested.is_empty() { + return Err(Error::new( + msg.span(), + "Expected at least one argument to fail attribute" + )); + } + + let format_string = match msg.nested[0] { + syn::NestedMeta::Meta(syn::Meta::NameValue(ref nv)) if nv.ident == "display" => { + nv.lit.clone() + } + _ => { + return Err(Error::new( + msg.span(), + "Fail attribute must begin `display = \"\"` to control the Display message." + )); + } + }; + let args = msg.nested.iter().skip(1).map(|arg| match *arg { + syn::NestedMeta::Literal(syn::Lit::Int(ref i)) => { + let bi = &v.bindings()[i.value() as usize]; + Ok(quote!(#bi)) + } + syn::NestedMeta::Meta(syn::Meta::Word(ref id)) => { + let id_s = id.to_string(); + if id_s.starts_with("_") { + if let Ok(idx) = id_s[1..].parse::() { + let bi = match v.bindings().get(idx) { + Some(bi) => bi, + None => { + return Err(Error::new( + arg.span(), + &format!( + "display attempted to access field `{}` in `{}::{}` which \ + does not exist (there are {} field{})", + idx, + s.ast().ident, + v.ast().ident, + v.bindings().len(), + if v.bindings().len() != 1 { "s" } else { "" } + ) + )); + } + }; + return Ok(quote!(#bi)); + } + } + for bi in v.bindings() { + if bi.ast().ident.as_ref() == Some(id) { + return Ok(quote!(#bi)); + } + } + return Err(Error::new( + arg.span(), + &format!( + "Couldn't find field `{}` in `{}::{}`", + id, + s.ast().ident, + v.ast().ident + ) + )); + } + ref arg => { + return Err(Error::new( + arg.span(), + "Invalid argument to fail attribute!" + )); + }, + }); + let args = args.collect::, _>>()?; + + let pat = v.pat(); + tokens.extend(quote!(#pat => { return write!(f, #format_string #(, #args)*) })); + } + Ok(Some(tokens)) +} + +fn find_error_msg(attrs: &[syn::Attribute]) -> Result, Error> { + let mut error_msg = None; + for attr in attrs { + if let Some(meta) = attr.interpret_meta() { + if meta.name() == "fail" { + if error_msg.is_some() { + return Err(Error::new( + meta.span(), + "Cannot have two display attributes" + )); + } else { + if let syn::Meta::List(list) = meta { + error_msg = Some(list); + } else { + return Err(Error::new( + meta.span(), + "fail attribute must take a list in parentheses" + )); + } + } + } + } + } + Ok(error_msg) +} + +fn is_backtrace(bi: &&synstructure::BindingInfo) -> bool { + match bi.ast().ty { + syn::Type::Path(syn::TypePath { + qself: None, + path: syn::Path { + segments: ref path, .. + }, + }) => path.last().map_or(false, |s| { + s.value().ident == "Backtrace" && s.value().arguments.is_empty() + }), + _ => false, + } +} + +fn is_cause(bi: &&synstructure::BindingInfo) -> bool { + let mut found_cause = false; + for attr in &bi.ast().attrs { + if let Some(meta) = attr.interpret_meta() { + if meta.name() == "cause" { + if found_cause { + panic!("Cannot have two `cause` attributes"); + } + found_cause = true; + } + if meta.name() == "fail" { + if let syn::Meta::List(ref list) = meta { + if let Some(ref pair) = list.nested.first() { + if let &&syn::NestedMeta::Meta(syn::Meta::Word(ref word)) = pair.value() { + if word == "cause" { + if found_cause { + panic!("Cannot have two `cause` attributes"); + } + found_cause = true; + } + } + } + } + } + } + } + found_cause +} diff --git a/failure_derive/tests/backtrace.rs b/failure_derive/tests/backtrace.rs new file mode 100644 index 000000000..a30718411 --- /dev/null +++ b/failure_derive/tests/backtrace.rs @@ -0,0 +1,64 @@ +extern crate failure; +#[macro_use] +extern crate failure_derive; + +use failure::{Backtrace, Fail}; + +#[derive(Fail, Debug)] +#[fail(display = "Error code: {}", code)] +struct BacktraceError { + backtrace: Backtrace, + code: u32, +} + +#[test] +fn backtrace_error() { + let err = BacktraceError { + backtrace: Backtrace::new(), + code: 7, + }; + let s = format!("{}", err); + assert_eq!(&s[..], "Error code: 7"); + assert!(err.backtrace().is_some()); +} + +#[derive(Fail, Debug)] +#[fail(display = "An error has occurred.")] +struct BacktraceTupleError(Backtrace); + +#[test] +fn backtrace_tuple_error() { + let err = BacktraceTupleError(Backtrace::new()); + let s = format!("{}", err); + assert_eq!(&s[..], "An error has occurred."); + assert!(err.backtrace().is_some()); +} + +#[derive(Fail, Debug)] +enum BacktraceEnumError { + #[fail(display = "Error code: {}", code)] + StructVariant { code: i32, backtrace: Backtrace }, + #[fail(display = "Error: {}", _0)] + TupleVariant(&'static str, Backtrace), + #[fail(display = "An error has occurred.")] + UnitVariant, +} + +#[test] +fn backtrace_enum_error() { + let err = BacktraceEnumError::StructVariant { + code: 2, + backtrace: Backtrace::new(), + }; + let s = format!("{}", err); + assert_eq!(&s[..], "Error code: 2"); + assert!(err.backtrace().is_some()); + let err = BacktraceEnumError::TupleVariant("foobar", Backtrace::new()); + let s = format!("{}", err); + assert_eq!(&s[..], "Error: foobar"); + assert!(err.backtrace().is_some()); + let err = BacktraceEnumError::UnitVariant; + let s = format!("{}", err); + assert_eq!(&s[..], "An error has occurred."); + assert!(err.backtrace().is_none()); +} diff --git a/failure_derive/tests/custom_type_bounds.rs b/failure_derive/tests/custom_type_bounds.rs new file mode 100644 index 000000000..fd1c8b975 --- /dev/null +++ b/failure_derive/tests/custom_type_bounds.rs @@ -0,0 +1,45 @@ +#[macro_use] +extern crate failure; + +use std::fmt::Debug; + +use failure::Fail; + +#[derive(Debug, Fail)] +#[fail(display = "An error has occurred.")] +pub struct UnboundedGenericTupleError(T); + +#[test] +fn unbounded_generic_tuple_error() { + let s = format!("{}", UnboundedGenericTupleError(())); + assert_eq!(&s[..], "An error has occurred."); +} + +#[derive(Debug, Fail)] +#[fail(display = "An error has occurred: {}", _0)] +pub struct FailBoundsGenericTupleError(T); + +#[test] +fn fail_bounds_generic_tuple_error() { + let error = FailBoundsGenericTupleError(UnboundedGenericTupleError(())); + let s = format!("{}", error); + assert_eq!(&s[..], "An error has occurred: An error has occurred."); +} + +pub trait NoDisplay: 'static + Debug + Send + Sync {} + +impl NoDisplay for &'static str {} + +#[derive(Debug, Fail)] +#[fail(display = "An error has occurred: {:?}", _0)] +pub struct CustomBoundsGenericTupleError(T); + +#[test] +fn custom_bounds_generic_tuple_error() { + let error = CustomBoundsGenericTupleError("more details unavailable."); + let s = format!("{}", error); + assert_eq!( + &s[..], + "An error has occurred: \"more details unavailable.\"" + ); +} diff --git a/failure_derive/tests/no_derive_display.rs b/failure_derive/tests/no_derive_display.rs new file mode 100644 index 000000000..20eeb308c --- /dev/null +++ b/failure_derive/tests/no_derive_display.rs @@ -0,0 +1,21 @@ +extern crate failure; +#[macro_use] +extern crate failure_derive; + +use failure::Fail; +use std::fmt::{self, Display}; + +#[derive(Debug, Fail)] +struct Foo; + +impl Display for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("An error occurred.") + } +} + +#[test] +fn handwritten_display() { + assert!(Foo.cause().is_none()); + assert_eq!(&format!("{}", Foo)[..], "An error occurred."); +} diff --git a/failure_derive/tests/tests.rs b/failure_derive/tests/tests.rs new file mode 100644 index 000000000..4e73255ef --- /dev/null +++ b/failure_derive/tests/tests.rs @@ -0,0 +1,55 @@ +extern crate failure; +#[macro_use] +extern crate failure_derive; + +#[derive(Fail, Debug)] +#[fail(display = "An error has occurred.")] +struct UnitError; + +#[test] +fn unit_struct() { + let s = format!("{}", UnitError); + assert_eq!(&s[..], "An error has occurred."); +} + +#[derive(Fail, Debug)] +#[fail(display = "Error code: {}", code)] +struct RecordError { + code: u32, +} + +#[test] +fn record_struct() { + let s = format!("{}", RecordError { code: 0 }); + assert_eq!(&s[..], "Error code: 0"); +} + +#[derive(Fail, Debug)] +#[fail(display = "Error code: {}", _0)] +struct TupleError(i32); + +#[test] +fn tuple_struct() { + let s = format!("{}", TupleError(2)); + assert_eq!(&s[..], "Error code: 2"); +} + +#[derive(Fail, Debug)] +enum EnumError { + #[fail(display = "Error code: {}", code)] + StructVariant { code: i32 }, + #[fail(display = "Error: {}", _0)] + TupleVariant(&'static str), + #[fail(display = "An error has occurred.")] + UnitVariant, +} + +#[test] +fn enum_error() { + let s = format!("{}", EnumError::StructVariant { code: 2 }); + assert_eq!(&s[..], "Error code: 2"); + let s = format!("{}", EnumError::TupleVariant("foobar")); + assert_eq!(&s[..], "Error: foobar"); + let s = format!("{}", EnumError::UnitVariant); + assert_eq!(&s[..], "An error has occurred."); +} diff --git a/failure_derive/tests/wraps.rs b/failure_derive/tests/wraps.rs new file mode 100644 index 000000000..38218a23b --- /dev/null +++ b/failure_derive/tests/wraps.rs @@ -0,0 +1,94 @@ +extern crate failure; +#[macro_use] +extern crate failure_derive; + +use std::fmt; +use std::io; + +use failure::{Backtrace, Fail}; + +#[derive(Fail, Debug)] +#[fail(display = "An error has occurred: {}", inner)] +struct WrapError { + #[fail(cause)] + inner: io::Error, +} + +#[test] +fn wrap_error() { + let inner = io::Error::from_raw_os_error(98); + let err = WrapError { inner }; + assert!(err + .cause() + .and_then(|err| err.downcast_ref::()) + .is_some()); +} + +#[derive(Fail, Debug)] +#[fail(display = "An error has occurred: {}", _0)] +struct WrapTupleError(#[fail(cause)] io::Error); + +#[test] +fn wrap_tuple_error() { + let io_error = io::Error::from_raw_os_error(98); + let err: WrapTupleError = WrapTupleError(io_error); + assert!(err + .cause() + .and_then(|err| err.downcast_ref::()) + .is_some()); +} + +#[derive(Fail, Debug)] +#[fail(display = "An error has occurred: {}", inner)] +struct WrapBacktraceError { + #[fail(cause)] + inner: io::Error, + backtrace: Backtrace, +} + +#[test] +fn wrap_backtrace_error() { + let inner = io::Error::from_raw_os_error(98); + let err: WrapBacktraceError = WrapBacktraceError { + inner, + backtrace: Backtrace::new(), + }; + assert!(err + .cause() + .and_then(|err| err.downcast_ref::()) + .is_some()); + assert!(err.backtrace().is_some()); +} + +#[derive(Fail, Debug)] +enum WrapEnumError { + #[fail(display = "An error has occurred: {}", _0)] + Io(#[fail(cause)] io::Error), + #[fail(display = "An error has occurred: {}", inner)] + Fmt { + #[fail(cause)] + inner: fmt::Error, + backtrace: Backtrace, + }, +} + +#[test] +fn wrap_enum_error() { + let io_error = io::Error::from_raw_os_error(98); + let err: WrapEnumError = WrapEnumError::Io(io_error); + assert!(err + .cause() + .and_then(|err| err.downcast_ref::()) + .is_some()); + assert!(err.backtrace().is_none()); + let fmt_error = fmt::Error::default(); + let err: WrapEnumError = WrapEnumError::Fmt { + inner: fmt_error, + backtrace: Backtrace::new(), + }; + assert!(err + .cause() + .and_then(|err| err.downcast_ref::()) + .is_some()); + assert!(err.backtrace().is_some()); +} diff --git a/filetime/.cargo-checksum.json b/filetime/.cargo-checksum.json new file mode 100644 index 000000000..7d7aa60c2 --- /dev/null +++ b/filetime/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"450537dc346f0c4d738dda31e790da1da5d4bd12145aad4da0d03d713cb3794f"} \ No newline at end of file diff --git a/filetime/Cargo.toml b/filetime/Cargo.toml new file mode 100644 index 000000000..0ed79b623 --- /dev/null +++ b/filetime/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "filetime" +version = "0.2.6" +authors = ["Alex Crichton "] +description = "Platform-agnostic accessors of timestamps in File metadata\n" +homepage = "https://github.com/alexcrichton/filetime" +documentation = "https://docs.rs/filetime" +readme = "README.md" +keywords = ["timestamp", "mtime"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/filetime" +[dependencies.cfg-if] +version = "0.1" +[dev-dependencies.tempdir] +version = "0.3" +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["fileapi", "minwindef", "winbase"] diff --git a/filetime/LICENSE-APACHE b/filetime/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/filetime/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/filetime/LICENSE-MIT b/filetime/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/filetime/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/filetime/README.md b/filetime/README.md new file mode 100644 index 000000000..e2a5dceae --- /dev/null +++ b/filetime/README.md @@ -0,0 +1,40 @@ +# filetime + +[![Build Status](https://travis-ci.org/alexcrichton/filetime.svg?branch=master)](https://travis-ci.org/alexcrichton/filetime) +[![Build status](https://ci.appveyor.com/api/projects/status/9tatexq47i3ee13k?svg=true)](https://ci.appveyor.com/project/alexcrichton/filetime) + +[Documentation](https://docs.rs/filetime) + +A helper library for inspecting and setting the various timestamps of files in Rust. This +library takes into account cross-platform differences in terms of where the +timestamps are located, what they are called, and how to convert them into a +platform-independent representation. + +```toml +# Cargo.toml +[dependencies] +filetime = "0.2" +``` + +# Advantages over using `std::fs::Metadata` + +This library includes the ability to set this data, which std does not. + +This library, when built with `RUSTFLAGS=--cfg emulate_second_only_system` set, will return all times rounded down to the second. This emulates the behavior of some file systems, mostly [HFS](https://en.wikipedia.org/wiki/HFS_Plus), allowing debugging on other hardware. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Filetime by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/filetime/appveyor.yml b/filetime/appveyor.yml new file mode 100644 index 000000000..4a6104291 --- /dev/null +++ b/filetime/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose --target %TARGET% diff --git a/filetime/src/lib.rs b/filetime/src/lib.rs new file mode 100644 index 000000000..28b810834 --- /dev/null +++ b/filetime/src/lib.rs @@ -0,0 +1,553 @@ +//! Timestamps for files in Rust +//! +//! This library provides platform-agnostic inspection of the various timestamps +//! present in the standard `fs::Metadata` structure. +//! +//! # Installation +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! filetime = "0.1" +//! ``` +//! +//! # Usage +//! +//! ```no_run +//! use std::fs; +//! use filetime::FileTime; +//! +//! let metadata = fs::metadata("foo.txt").unwrap(); +//! +//! let mtime = FileTime::from_last_modification_time(&metadata); +//! println!("{}", mtime); +//! +//! let atime = FileTime::from_last_access_time(&metadata); +//! assert!(mtime < atime); +//! +//! // Inspect values that can be interpreted across platforms +//! println!("{}", mtime.unix_seconds()); +//! println!("{}", mtime.nanoseconds()); +//! +//! // Print the platform-specific value of seconds +//! println!("{}", mtime.seconds()); +//! ``` + +use std::fmt; +use std::fs; +use std::io; +use std::path::Path; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +cfg_if::cfg_if! { + if #[cfg(target_os = "redox")] { + #[path = "redox.rs"] + mod imp; + } else if #[cfg(windows)] { + #[path = "windows.rs"] + mod imp; + } else if #[cfg(target_arch = "wasm32")] { + #[path = "wasm.rs"] + mod imp; + } else { + #[path = "unix/mod.rs"] + mod imp; + } +} + +/// A helper structure to represent a timestamp for a file. +/// +/// The actual value contined within is platform-specific and does not have the +/// same meaning across platforms, but comparisons and stringification can be +/// significant among the same platform. +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone, Hash)] +pub struct FileTime { + seconds: i64, + nanos: u32, +} + +impl FileTime { + /// Creates a new timestamp representing a 0 time. + /// + /// Useful for creating the base of a cmp::max chain of times. + pub fn zero() -> FileTime { + FileTime { + seconds: 0, + nanos: 0, + } + } + + fn emulate_second_only_system(self) -> FileTime { + if cfg!(emulate_second_only_system) { + FileTime { + seconds: self.seconds, + nanos: 0, + } + } else { + self + } + } + + /// Creates a new instance of `FileTime` with a number of seconds and + /// nanoseconds relative to the Unix epoch, 1970-01-01T00:00:00Z. + /// + /// Negative seconds represent times before the Unix epoch, and positive + /// values represent times after it. Nanos always count forwards in time. + /// + /// Note that this is typically the relative point that Unix time stamps are + /// from, but on Windows the native time stamp is relative to January 1, + /// 1601 so the return value of `seconds` from the returned `FileTime` + /// instance may not be the same as that passed in. + pub fn from_unix_time(seconds: i64, nanos: u32) -> FileTime { + FileTime { + seconds: seconds + if cfg!(windows) { 11644473600 } else { 0 }, + nanos, + } + .emulate_second_only_system() + } + + /// Creates a new timestamp from the last modification time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `mtime` field of `stat` on Unix + /// platforms and the `ftLastWriteTime` field on Windows platforms. + pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + imp::from_last_modification_time(meta).emulate_second_only_system() + } + + /// Creates a new timestamp from the last access time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `atime` field of `stat` on Unix + /// platforms and the `ftLastAccessTime` field on Windows platforms. + pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + imp::from_last_access_time(meta).emulate_second_only_system() + } + + /// Creates a new timestamp from the creation time listed in the specified + /// metadata. + /// + /// The returned value corresponds to the `birthtime` field of `stat` on + /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note + /// that not all Unix platforms have this field available and may return + /// `None` in some circumstances. + pub fn from_creation_time(meta: &fs::Metadata) -> Option { + imp::from_creation_time(meta).map(|x| x.emulate_second_only_system()) + } + + /// Creates a new timestamp from the given SystemTime. + /// + /// Windows counts file times since 1601-01-01T00:00:00Z, and cannot + /// represent times before this, but it's possible to create a SystemTime + /// that does. This function will error if passed such a SystemTime. + pub fn from_system_time(time: SystemTime) -> FileTime { + let epoch = if cfg!(windows) { + UNIX_EPOCH - Duration::from_secs(11644473600) + } else { + UNIX_EPOCH + }; + + time.duration_since(epoch) + .map(|d| FileTime { + seconds: d.as_secs() as i64, + nanos: d.subsec_nanos(), + }) + .unwrap_or_else(|e| { + let until_epoch = e.duration(); + let (sec_offset, nanos) = if until_epoch.subsec_nanos() == 0 { + (0, 0) + } else { + (-1, 1_000_000_000 - until_epoch.subsec_nanos()) + }; + + FileTime { + seconds: -1 * until_epoch.as_secs() as i64 + sec_offset, + nanos, + } + }) + .emulate_second_only_system() + } + + /// Returns the whole number of seconds represented by this timestamp. + /// + /// Note that this value's meaning is **platform specific**. On Unix + /// platform time stamps are typically relative to January 1, 1970, but on + /// Windows platforms time stamps are relative to January 1, 1601. + pub fn seconds(&self) -> i64 { + self.seconds + } + + /// Returns the whole number of seconds represented by this timestamp, + /// relative to the Unix epoch start of January 1, 1970. + /// + /// Note that this does not return the same value as `seconds` for Windows + /// platforms as seconds are relative to a different date there. + pub fn unix_seconds(&self) -> i64 { + self.seconds - if cfg!(windows) { 11644473600 } else { 0 } + } + + /// Returns the nanosecond precision of this timestamp. + /// + /// The returned value is always less than one billion and represents a + /// portion of a second forward from the seconds returned by the `seconds` + /// method. + pub fn nanoseconds(&self) -> u32 { + self.nanos + } +} + +impl fmt::Display for FileTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.{:09}s", self.seconds, self.nanos) + } +} + +impl From for FileTime { + fn from(time: SystemTime) -> FileTime { + FileTime::from_system_time(time) + } +} + +/// Set the last access and modification times for a file on the filesystem. +/// +/// This function will set the `atime` and `mtime` metadata fields for a file +/// on the local filesystem, returning any error encountered. +pub fn set_file_times

(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> +where + P: AsRef, +{ + imp::set_file_times(p.as_ref(), atime, mtime) +} + +/// Set the last access and modification times for a file handle. +/// +/// This function will either or both of the `atime` and `mtime` metadata +/// fields for a file handle , returning any error encountered. If `None` is +/// specified then the time won't be updated. If `None` is specified for both +/// options then no action is taken. +pub fn set_file_handle_times( + f: &fs::File, + atime: Option, + mtime: Option, +) -> io::Result<()> { + imp::set_file_handle_times(f, atime, mtime) +} + +/// Set the last access and modification times for a file on the filesystem. +/// This function does not follow symlink. +/// +/// This function will set the `atime` and `mtime` metadata fields for a file +/// on the local filesystem, returning any error encountered. +pub fn set_symlink_file_times

(p: P, atime: FileTime, mtime: FileTime) -> io::Result<()> +where + P: AsRef, +{ + imp::set_symlink_file_times(p.as_ref(), atime, mtime) +} + +/// Set the last modification time for a file on the filesystem. +/// +/// This function will set the `mtime` metadata field for a file on the local +/// filesystem, returning any error encountered. +/// +/// # Platform support +/// +/// Where supported this will attempt to issue just one syscall to update only +/// the `mtime`, but where not supported this may issue one syscall to learn the +/// existing `atime` so only the `mtime` can be configured. +pub fn set_file_mtime

(p: P, mtime: FileTime) -> io::Result<()> +where + P: AsRef, +{ + imp::set_file_mtime(p.as_ref(), mtime) +} + +/// Set the last access time for a file on the filesystem. +/// +/// This function will set the `atime` metadata field for a file on the local +/// filesystem, returning any error encountered. +/// +/// # Platform support +/// +/// Where supported this will attempt to issue just one syscall to update only +/// the `atime`, but where not supported this may issue one syscall to learn the +/// existing `mtime` so only the `atime` can be configured. +pub fn set_file_atime

(p: P, atime: FileTime) -> io::Result<()> +where + P: AsRef, +{ + imp::set_file_atime(p.as_ref(), atime) +} + +#[cfg(test)] +mod tests { + use tempdir::TempDir; + use super::{set_file_handle_times, set_file_times, set_symlink_file_times, FileTime}; + use std::fs::{self, File}; + use std::io; + use std::path::Path; + use std::time::{Duration, UNIX_EPOCH}; + + #[cfg(unix)] + fn make_symlink(src: P, dst: Q) -> io::Result<()> + where + P: AsRef, + Q: AsRef, + { + use std::os::unix::fs::symlink; + symlink(src, dst) + } + + #[cfg(windows)] + fn make_symlink(src: P, dst: Q) -> io::Result<()> + where + P: AsRef, + Q: AsRef, + { + use std::os::windows::fs::symlink_file; + symlink_file(src, dst) + } + + #[test] + #[cfg(windows)] + fn from_unix_time_test() { + let time = FileTime::from_unix_time(10, 100_000_000); + assert_eq!(11644473610, time.seconds); + assert_eq!(100_000_000, time.nanos); + + let time = FileTime::from_unix_time(-10, 100_000_000); + assert_eq!(11644473590, time.seconds); + assert_eq!(100_000_000, time.nanos); + + let time = FileTime::from_unix_time(-12_000_000_000, 0); + assert_eq!(-355526400, time.seconds); + assert_eq!(0, time.nanos); + } + + #[test] + #[cfg(not(windows))] + fn from_unix_time_test() { + let time = FileTime::from_unix_time(10, 100_000_000); + assert_eq!(10, time.seconds); + assert_eq!(100_000_000, time.nanos); + + let time = FileTime::from_unix_time(-10, 100_000_000); + assert_eq!(-10, time.seconds); + assert_eq!(100_000_000, time.nanos); + + let time = FileTime::from_unix_time(-12_000_000_000, 0); + assert_eq!(-12_000_000_000, time.seconds); + assert_eq!(0, time.nanos); + } + + #[test] + #[cfg(windows)] + fn from_system_time_test() { + let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); + assert_eq!(11644473610, time.seconds); + assert_eq!(0, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); + assert_eq!(11644473590, time.seconds); + assert_eq!(0, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); + assert_eq!(11644473598, time.seconds); + assert_eq!(900_000_000, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000_000)); + assert_eq!(-355526400, time.seconds); + assert_eq!(0, time.nanos); + } + + #[test] + #[cfg(not(windows))] + fn from_system_time_test() { + let time = FileTime::from_system_time(UNIX_EPOCH + Duration::from_secs(10)); + assert_eq!(10, time.seconds); + assert_eq!(0, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(10)); + assert_eq!(-10, time.seconds); + assert_eq!(0, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_millis(1100)); + assert_eq!(-2, time.seconds); + assert_eq!(900_000_000, time.nanos); + + let time = FileTime::from_system_time(UNIX_EPOCH - Duration::from_secs(12_000_000)); + assert_eq!(-12_000_000, time.seconds); + assert_eq!(0, time.nanos); + } + + #[test] + fn set_file_times_test() -> io::Result<()> { + let td = TempDir::new("filetime")?; + let path = td.path().join("foo.txt"); + let mut f = File::create(&path)?; + + let metadata = fs::metadata(&path)?; + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime)?; + + let new_mtime = FileTime::from_unix_time(10_000, 0); + set_file_times(&path, atime, new_mtime)?; + + let metadata = fs::metadata(&path)?; + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + // Update just mtime + let new_mtime = FileTime::from_unix_time(20_000, 0); + set_file_handle_times(&mut f, None, Some(new_mtime))?; + let metadata = f.metadata()?; + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + let new_atime = FileTime::from_last_access_time(&metadata); + assert_eq!(atime, new_atime); + + // Update just atime + let new_atime = FileTime::from_unix_time(30_000, 0); + set_file_handle_times(&mut f, Some(new_atime), None)?; + let metadata = f.metadata()?; + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + let atime = FileTime::from_last_access_time(&metadata); + assert_eq!(atime, new_atime); + + let spath = td.path().join("bar.txt"); + make_symlink(&path, &spath)?; + let metadata = fs::symlink_metadata(&spath)?; + let smtime = FileTime::from_last_modification_time(&metadata); + + set_file_times(&spath, atime, mtime)?; + + let metadata = fs::metadata(&path)?; + let cur_mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, cur_mtime); + + let metadata = fs::symlink_metadata(&spath)?; + let cur_mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(smtime, cur_mtime); + + set_file_times(&spath, atime, new_mtime)?; + + let metadata = fs::metadata(&path)?; + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let metadata = fs::symlink_metadata(&spath)?; + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, smtime); + Ok(()) + } + + #[test] + fn set_file_times_pre_unix_epoch_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_unix_time(-10_000, 0); + set_file_times(&path, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + } + + #[test] + #[cfg(windows)] + fn set_file_times_pre_windows_epoch_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_unix_time(-12_000_000_000, 0); + assert!(set_file_times(&path, atime, new_mtime).is_err()); + } + + #[test] + fn set_symlink_file_times_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_symlink_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_unix_time(10_000, 0); + set_symlink_file_times(&path, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let spath = td.path().join("bar.txt"); + make_symlink(&path, &spath).unwrap(); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let smtime = FileTime::from_last_modification_time(&metadata); + let satime = FileTime::from_last_access_time(&metadata); + set_symlink_file_times(&spath, smtime, satime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let new_smtime = FileTime::from_unix_time(20_000, 0); + set_symlink_file_times(&spath, atime, new_smtime).unwrap(); + + let metadata = fs::metadata(&spath).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_smtime); + } + + #[test] + fn set_single_time_test() { + use super::{set_file_atime, set_file_mtime}; + + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_unix_time(10_000, 0); + set_file_mtime(&path, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + assert_eq!(atime, FileTime::from_last_access_time(&metadata)); + + let new_atime = FileTime::from_unix_time(20_000, 0); + set_file_atime(&path, new_atime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let atime = FileTime::from_last_access_time(&metadata); + assert_eq!(atime, new_atime); + assert_eq!(mtime, FileTime::from_last_modification_time(&metadata)); + } +} diff --git a/filetime/src/redox.rs b/filetime/src/redox.rs new file mode 100644 index 000000000..da2408a4c --- /dev/null +++ b/filetime/src/redox.rs @@ -0,0 +1,70 @@ +use std::fs::{self, File}; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; +use crate::FileTime; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + let fd = syscall::open(p.as_os_str().as_bytes(), 0) + .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + set_file_times_redox(fd, atime, mtime) +} + +pub fn set_file_mtime(_p: &Path, _mtime: FileTime) -> io::Result<()> { + unimplemented!() +} + +pub fn set_file_atime(_p: &Path, _atime: FileTime) -> io::Result<()> { + unimplemented!() +} + +pub fn set_file_handle_times( + _f: &File, + _atime: Option, + _mtime: Option, +) -> io::Result<()> { + unimplemented!() +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + let fd = syscall::open(p.as_os_str().as_bytes(), syscall::O_NOFOLLOW) + .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + set_file_times_redox(fd, atime, mtime) +} + +fn set_file_times_redox(fd: usize, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use syscall::TimeSpec; + + fn to_timespec(ft: &FileTime) -> TimeSpec { + TimeSpec { + tv_sec: ft.seconds(), + tv_nsec: ft.nanoseconds() as i32 + } + } + + let times = [to_timespec(&atime), to_timespec(&mtime)]; + let res = syscall::futimens(fd, ×); + let _ = syscall::close(fd); + match res { + Ok(_) => Ok(()), + Err(err) => Err(io::Error::from_raw_os_error(err.errno)) + } +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.mtime(), + nanos: meta.mtime_nsec() as u32, + } +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.atime(), + nanos: meta.atime_nsec() as u32, + } +} + +pub fn from_creation_time(_meta: &fs::Metadata) -> Option { + None +} diff --git a/filetime/src/unix/linux.rs b/filetime/src/unix/linux.rs new file mode 100644 index 000000000..c803e0217 --- /dev/null +++ b/filetime/src/unix/linux.rs @@ -0,0 +1,102 @@ +//! On Linux we try to use the more accurate `utimensat` syscall but this isn't +//! always available so we also fall back to `utimes` if we couldn't find +//! `utimensat` at runtime. + +use crate::FileTime; +use std::ffi::CString; +use std::fs; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; +use std::ptr; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::SeqCst; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), false) +} + +pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { + set_times(p, None, Some(mtime), false) +} + +pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), None, false) +} + +pub fn set_file_handle_times( + f: &fs::File, + atime: Option, + mtime: Option, +) -> io::Result<()> { + // Attempt to use the `utimensat` syscall, but if it's not supported by the + // current kernel then fall back to an older syscall. + static INVALID: AtomicBool = AtomicBool::new(false); + if !INVALID.load(SeqCst) { + let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; + let rc = unsafe { + libc::syscall( + libc::SYS_utimensat, + f.as_raw_fd(), + ptr::null::(), + times.as_ptr(), + 0, + ) + }; + if rc == 0 { + return Ok(()); + } + let err = io::Error::last_os_error(); + if err.raw_os_error() == Some(libc::ENOSYS) { + INVALID.store(true, SeqCst); + } else { + return Err(err); + } + } + + super::utimes::set_file_handle_times(f, atime, mtime) +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), true) +} + +fn set_times( + p: &Path, + atime: Option, + mtime: Option, + symlink: bool, +) -> io::Result<()> { + let flags = if symlink { + libc::AT_SYMLINK_NOFOLLOW + } else { + 0 + }; + + // Same as the `if` statement above. + static INVALID: AtomicBool = AtomicBool::new(false); + if !INVALID.load(SeqCst) { + let p = CString::new(p.as_os_str().as_bytes())?; + let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; + let rc = unsafe { + libc::syscall( + libc::SYS_utimensat, + libc::AT_FDCWD, + p.as_ptr(), + times.as_ptr(), + flags, + ) + }; + if rc == 0 { + return Ok(()); + } + let err = io::Error::last_os_error(); + if err.raw_os_error() == Some(libc::ENOSYS) { + INVALID.store(true, SeqCst); + } else { + return Err(err); + } + } + + super::utimes::set_times(p, atime, mtime, symlink) +} diff --git a/filetime/src/unix/mod.rs b/filetime/src/unix/mod.rs new file mode 100644 index 000000000..3a7bbbbcf --- /dev/null +++ b/filetime/src/unix/mod.rs @@ -0,0 +1,87 @@ +use crate::FileTime; +use libc::{time_t, timespec}; +use std::fs; +use std::os::unix::prelude::*; + +cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + mod utimes; + mod linux; + pub use self::linux::*; + } else if #[cfg(any(target_os = "android", + target_os = "solaris", + target_os = "emscripten", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd"))] { + mod utimensat; + pub use self::utimensat::*; + } else { + mod utimes; + pub use self::utimes::*; + } +} + +#[allow(dead_code)] +fn to_timespec(ft: &Option) -> timespec { + const UTIME_OMIT: i64 = 1073741822; + + if let &Some(ft) = ft { + timespec { + tv_sec: ft.seconds() as time_t, + tv_nsec: ft.nanoseconds() as _, + } + } else { + timespec { + tv_sec: 0, + tv_nsec: UTIME_OMIT as _, + } + } +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.mtime(), + nanos: meta.mtime_nsec() as u32, + } +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.atime(), + nanos: meta.atime_nsec() as u32, + } +} + +pub fn from_creation_time(meta: &fs::Metadata) -> Option { + macro_rules! birthtim { + ($(($e:expr, $i:ident)),*) => { + #[cfg(any($(target_os = $e),*))] + fn imp(meta: &fs::Metadata) -> Option { + $( + #[cfg(target_os = $e)] + use std::os::$i::fs::MetadataExt; + )* + Some(FileTime { + seconds: meta.st_birthtime(), + nanos: meta.st_birthtime_nsec() as u32, + }) + } + + #[cfg(all($(not(target_os = $e)),*))] + fn imp(_meta: &fs::Metadata) -> Option { + None + } + } + } + + birthtim! { + ("bitrig", bitrig), + ("freebsd", freebsd), + ("ios", ios), + ("macos", macos), + ("openbsd", openbsd) + } + + imp(meta) +} diff --git a/filetime/src/unix/utimensat.rs b/filetime/src/unix/utimensat.rs new file mode 100644 index 000000000..42a1ada2c --- /dev/null +++ b/filetime/src/unix/utimensat.rs @@ -0,0 +1,58 @@ +use crate::FileTime; +use std::ffi::CString; +use std::fs::File; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), false) +} + +pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { + set_times(p, None, Some(mtime), false) +} + +pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), None, false) +} + +pub fn set_file_handle_times( + f: &File, + atime: Option, + mtime: Option, +) -> io::Result<()> { + let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; + let rc = unsafe { libc::futimens(f.as_raw_fd(), times.as_ptr()) }; + if rc == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), false) +} + +fn set_times( + p: &Path, + atime: Option, + mtime: Option, + symlink: bool, +) -> io::Result<()> { + let flags = if symlink { + libc::AT_SYMLINK_NOFOLLOW + } else { + 0 + }; + + let p = CString::new(p.as_os_str().as_bytes())?; + let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; + let rc = unsafe { libc::utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) }; + if rc == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } +} diff --git a/filetime/src/unix/utimes.rs b/filetime/src/unix/utimes.rs new file mode 100644 index 000000000..c3de5fd87 --- /dev/null +++ b/filetime/src/unix/utimes.rs @@ -0,0 +1,98 @@ +use crate::FileTime; +use std::ffi::CString; +use std::fs; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; + +#[allow(dead_code)] +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), false) +} + +#[allow(dead_code)] +pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { + set_times(p, None, Some(mtime), false) +} + +#[allow(dead_code)] +pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), None, false) +} + +#[allow(dead_code)] +pub fn set_file_handle_times( + f: &fs::File, + atime: Option, + mtime: Option, +) -> io::Result<()> { + let (atime, mtime) = match get_times(atime, mtime, || f.metadata())? { + Some(pair) => pair, + None => return Ok(()), + }; + let times = [to_timeval(&atime), to_timeval(&mtime)]; + let rc = unsafe { libc::futimes(f.as_raw_fd(), times.as_ptr()) }; + return if rc == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + }; +} + +fn get_times( + atime: Option, + mtime: Option, + current: impl FnOnce() -> io::Result, +) -> io::Result> { + let pair = match (atime, mtime) { + (Some(a), Some(b)) => (a, b), + (None, None) => return Ok(None), + (Some(a), None) => { + let meta = current()?; + (a, FileTime::from_last_modification_time(&meta)) + } + (None, Some(b)) => { + let meta = current()?; + (FileTime::from_last_access_time(&meta), b) + } + }; + Ok(Some(pair)) +} + +#[allow(dead_code)] +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_times(p, Some(atime), Some(mtime), true) +} + +pub fn set_times( + p: &Path, + atime: Option, + mtime: Option, + symlink: bool, +) -> io::Result<()> { + let (atime, mtime) = match get_times(atime, mtime, || p.metadata())? { + Some(pair) => pair, + None => return Ok(()), + }; + let p = CString::new(p.as_os_str().as_bytes())?; + let times = [to_timeval(&atime), to_timeval(&mtime)]; + let rc = unsafe { + if symlink { + libc::lutimes(p.as_ptr(), times.as_ptr()) + } else { + libc::utimes(p.as_ptr(), times.as_ptr()) + } + }; + return if rc == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + }; +} + +fn to_timeval(ft: &FileTime) -> libc::timeval { + libc::timeval { + tv_sec: ft.seconds() as libc::time_t, + tv_usec: (ft.nanoseconds() / 1000) as libc::suseconds_t, + } +} diff --git a/filetime/src/wasm.rs b/filetime/src/wasm.rs new file mode 100644 index 000000000..4a7a5bbb7 --- /dev/null +++ b/filetime/src/wasm.rs @@ -0,0 +1,40 @@ +use crate::FileTime; +use std::fs::{self, File}; +use std::io; +use std::path::Path; + +pub fn set_file_times(_p: &Path, _atime: FileTime, _mtime: FileTime) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Wasm not implemented")) +} + +pub fn set_symlink_file_times(_p: &Path, _atime: FileTime, _mtime: FileTime) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Wasm not implemented")) +} + +pub fn set_file_mtime(_p: &Path, _mtime: FileTime) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Wasm not implemented")) +} + +pub fn set_file_atime(_p: &Path, _atime: FileTime) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Wasm not implemented")) +} + +pub fn from_last_modification_time(_meta: &fs::Metadata) -> FileTime { + unimplemented!() +} + +pub fn from_last_access_time(_meta: &fs::Metadata) -> FileTime { + unimplemented!() +} + +pub fn from_creation_time(_meta: &fs::Metadata) -> Option { + unimplemented!() +} + +pub fn set_file_handle_times( + _f: &File, + _atime: Option, + _mtime: Option, +) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Wasm not implemented")) +} diff --git a/filetime/src/windows.rs b/filetime/src/windows.rs new file mode 100644 index 000000000..acd4792fa --- /dev/null +++ b/filetime/src/windows.rs @@ -0,0 +1,91 @@ +use crate::FileTime; +use std::fs::{self, File, OpenOptions}; +use std::io; +use std::os::windows::prelude::*; +use std::path::Path; +use std::ptr; +use winapi::shared::minwindef::*; +use winapi::um::fileapi::*; +use winapi::um::winbase::*; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + let f = OpenOptions::new().write(true).open(p)?; + set_file_handle_times(&f, Some(atime), Some(mtime)) +} + +pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { + let f = OpenOptions::new().write(true).open(p)?; + set_file_handle_times(&f, None, Some(mtime)) +} + +pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { + let f = OpenOptions::new().write(true).open(p)?; + set_file_handle_times(&f, Some(atime), None) +} + +pub fn set_file_handle_times( + f: &File, + atime: Option, + mtime: Option, +) -> io::Result<()> { + let atime = atime.map(to_filetime); + let mtime = mtime.map(to_filetime); + return unsafe { + let ret = SetFileTime( + f.as_raw_handle() as *mut _, + ptr::null(), + atime + .as_ref() + .map(|p| p as *const FILETIME) + .unwrap_or(ptr::null()), + mtime + .as_ref() + .map(|p| p as *const FILETIME) + .unwrap_or(ptr::null()), + ); + if ret != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + }; + + fn to_filetime(ft: FileTime) -> FILETIME { + let intervals = ft.seconds() * (1_000_000_000 / 100) + ((ft.nanoseconds() as i64) / 100); + FILETIME { + dwLowDateTime: intervals as DWORD, + dwHighDateTime: (intervals >> 32) as DWORD, + } + } +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use std::os::windows::fs::OpenOptionsExt; + + let f = OpenOptions::new() + .write(true) + .custom_flags(FILE_FLAG_OPEN_REPARSE_POINT) + .open(p)?; + set_file_handle_times(&f, Some(atime), Some(mtime)) +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + from_intervals(meta.last_write_time()) +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + from_intervals(meta.last_access_time()) +} + +pub fn from_creation_time(meta: &fs::Metadata) -> Option { + Some(from_intervals(meta.creation_time())) +} + +fn from_intervals(ticks: u64) -> FileTime { + // Windows write times are in 100ns intervals, so do a little math to + // get it into the right representation. + FileTime { + seconds: (ticks / (1_000_000_000 / 100)) as i64, + nanos: ((ticks % (1_000_000_000 / 100)) * 100) as u32, + } +} diff --git a/flate2/.cargo-checksum.json b/flate2/.cargo-checksum.json new file mode 100644 index 000000000..c0154dbc2 --- /dev/null +++ b/flate2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa"} \ No newline at end of file diff --git a/flate2/.pc/.quilt_patches b/flate2/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/flate2/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/flate2/.pc/.quilt_series b/flate2/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/flate2/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/flate2/.pc/.version b/flate2/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/flate2/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/flate2/.pc/applied-patches b/flate2/.pc/applied-patches new file mode 100644 index 000000000..d42c26703 --- /dev/null +++ b/flate2/.pc/applied-patches @@ -0,0 +1 @@ +disable-miniz.patch diff --git a/flate2/.pc/disable-miniz.patch/.timestamp b/flate2/.pc/disable-miniz.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/flate2/.pc/disable-miniz.patch/Cargo.toml b/flate2/.pc/disable-miniz.patch/Cargo.toml new file mode 100644 index 000000000..a62d28066 --- /dev/null +++ b/flate2/.pc/disable-miniz.patch/Cargo.toml @@ -0,0 +1,82 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "flate2" +version = "1.0.7" +authors = ["Alex Crichton "] +description = "Bindings to miniz.c for DEFLATE compression and decompression exposed as\nReader/Writer streams. Contains bindings for zlib, deflate, and gzip-based\nstreams.\n" +homepage = "https://github.com/alexcrichton/flate2-rs" +documentation = "https://docs.rs/flate2" +readme = "README.md" +keywords = ["gzip", "flate", "zlib", "encoding"] +categories = ["compression", "api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/flate2-rs" +[dependencies.crc32fast] +version = "1.1" + +[dependencies.futures] +version = "0.1.25" +optional = true + +[dependencies.libc] +version = "0.2" + +[dependencies.libz-sys] +version = "1.0" +optional = true + +[dependencies.miniz-sys] +version = "0.1.11" +optional = true + +[dependencies.miniz_oxide_c_api] +version = "0.2" +features = ["no_c_export"] +optional = true + +[dependencies.tokio-io] +version = "0.1.11" +optional = true +[dev-dependencies.futures] +version = "0.1" + +[dev-dependencies.quickcheck] +version = "0.7" +default-features = false + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.tokio-io] +version = "0.1.11" + +[dev-dependencies.tokio-tcp] +version = "0.1.3" + +[dev-dependencies.tokio-threadpool] +version = "0.1.10" + +[features] +default = ["miniz-sys"] +rust_backend = ["miniz_oxide_c_api"] +tokio = ["tokio-io", "futures"] +zlib = ["libz-sys"] +[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"emscripten\")))".dependencies.miniz_oxide_c_api] +version = "0.2" +features = ["no_c_export"] +[badges.appveyor] +repository = "alexcrichton/flate2-rs" + +[badges.travis-ci] +repository = "alexcrichton/flate2-rs" diff --git a/flate2/Cargo.toml b/flate2/Cargo.toml new file mode 100644 index 000000000..df5aa852d --- /dev/null +++ b/flate2/Cargo.toml @@ -0,0 +1,72 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "flate2" +version = "1.0.7" +authors = ["Alex Crichton "] +description = "Bindings to miniz.c for DEFLATE compression and decompression exposed as\nReader/Writer streams. Contains bindings for zlib, deflate, and gzip-based\nstreams.\n" +homepage = "https://github.com/alexcrichton/flate2-rs" +documentation = "https://docs.rs/flate2" +readme = "README.md" +keywords = ["gzip", "flate", "zlib", "encoding"] +categories = ["compression", "api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/flate2-rs" +[dependencies.crc32fast] +version = "1.1" + +[dependencies.futures] +version = "0.1.25" +optional = true + +[dependencies.libc] +version = "0.2" + +[dependencies.libz-sys] +version = "1.0" +optional = true + +[dependencies.tokio-io] +version = "0.1.11" +optional = true +[dev-dependencies.futures] +version = "0.1" + +[dev-dependencies.quickcheck] +version = "0.7" +default-features = false + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.tokio-io] +version = "0.1.11" + +[dev-dependencies.tokio-tcp] +version = "0.1.3" + +[dev-dependencies.tokio-threadpool] +version = "0.1.10" + +[features] +default = ["zlib"] +miniz-sys = ["zlib"] +miniz_oxide_c_api = ["zlib"] +rust_backend = ["zlib"] +tokio = ["tokio-io", "futures"] +zlib = ["libz-sys"] +[badges.appveyor] +repository = "alexcrichton/flate2-rs" + +[badges.travis-ci] +repository = "alexcrichton/flate2-rs" diff --git a/flate2/LICENSE-APACHE b/flate2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/flate2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/flate2/LICENSE-MIT b/flate2/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/flate2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/flate2/README.md b/flate2/README.md new file mode 100644 index 000000000..06d803257 --- /dev/null +++ b/flate2/README.md @@ -0,0 +1,89 @@ +# flate2 + +[![Build Status](https://dev.azure.com/alexcrichton/flate2-rs/_apis/build/status/alexcrichton.flate2-rs?branchName=master)](https://dev.azure.com/alexcrichton/flate2-rs/_build/latest?definitionId=1&branchName=master) +[![Crates.io](https://img.shields.io/crates/v/flate2.svg?maxAge=2592000)](https://crates.io/crates/flate2) +[![Documentation](https://docs.rs/flate2/badge.svg)](https://docs.rs/flate2) + +A streaming compression/decompression library for Rust. The underlying +implementation by default uses [`miniz`](https://github.com/richgel999/miniz) but +can optionally be configured to use the system zlib, if available. + +There is also an experimental rust backend that uses the +[`miniz_oxide`](https://crates.io/crates/miniz_oxide) crate. This avoids the need +to build C code, but hasn't gone through as much testing as the other backends. + +Supported formats: + +* deflate +* zlib +* gzip + +```toml +# Cargo.toml +[dependencies] +flate2 = "1.0" +``` + +Using zlib instead of miniz: + +```toml +[dependencies] +flate2 = { version = "1.0", features = ["zlib"], default-features = false } +``` + +Using the rust back-end: + +```toml +[dependencies] +flate2 = { version = "1.0", features = ["rust_backend"], default-features = false } +``` + +## Compression + +```rust +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::write::ZlibEncoder; + +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"foo"); + e.write_all(b"bar"); + let compressed_bytes = e.finish(); +} +``` + +## Decompression + +```rust,no_run +extern crate flate2; + +use std::io::prelude::*; +use flate2::read::GzDecoder; + +fn main() { + let mut d = GzDecoder::new("...".as_bytes()); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + println!("{}", s); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/flate2/azure-pipelines.yml b/flate2/azure-pipelines.yml new file mode 100644 index 000000000..359553372 --- /dev/null +++ b/flate2/azure-pipelines.yml @@ -0,0 +1,52 @@ +trigger: + - master + +jobs: +- template: ci/azure-job-test-all.yml + parameters: + name: Linux_stable +- template: ci/azure-job-test-all.yml + parameters: + vmImage: macOS-10.13 + name: Darwin_stable +- template: ci/azure-job-test-all.yml + parameters: + toolchain: beta + name: Linux_beta +- template: ci/azure-job-test-all.yml + parameters: + toolchain: nightly + name: Linux_nightly +- template: ci/azure-job-test-all.yml + parameters: + vmImage: vs2017-win2016 + name: Windows_stable +- template: ci/azure-job-test-all.yml + parameters: + vmImage: vs2017-win2016 + toolchain: stable-x86_64-gnu + name: Windows_stable_MinGW +- job: systest + steps: + - template: ci/azure-install-rust.yml + - script: cargo run --manifest-path systest/Cargo.toml +- job: wasm + steps: + - template: ci/azure-install-rust.yml + - script: rustup target add wasm32-unknown-unknown + - script: cargo build --target wasm32-unknown-unknown +- job: rust_backend + steps: + - template: ci/azure-install-rust.yml + - script: cargo test --features rust_backend + continueOnError: true + - script: cargo test --features rust_backend --no-default-features + continueOnError: true +- job: docs + steps: + - template: ci/azure-install-rust.yml + - script: cargo doc --no-deps --all-features + - script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) + env: + GITHUB_DEPLOY_KEY: $(GITHUB_DEPLOY_KEY) diff --git a/flate2/ci/azure-install-rust.yml b/flate2/ci/azure-install-rust.yml new file mode 100644 index 000000000..214da7214 --- /dev/null +++ b/flate2/ci/azure-install-rust.yml @@ -0,0 +1,25 @@ +parameters: + toolchain: 'stable' + +steps: + - bash: | + curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN + echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" + displayName: Install rust + condition: ne( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + curl -sSf -o rustup-init.exe https://win.rustup.rs + rustup-init.exe -y --default-toolchain %TOOLCHAIN% + echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" + displayName: Install rust + condition: eq( variables['Agent.OS'], 'Windows_NT' ) + env: + TOOLCHAIN: ${{ parameters.toolchain }} + + - script: | + rustc -Vv + cargo -V + displayName: Query rust and cargo versions diff --git a/flate2/ci/azure-job-test-all.yml b/flate2/ci/azure-job-test-all.yml new file mode 100644 index 000000000..e07395d33 --- /dev/null +++ b/flate2/ci/azure-job-test-all.yml @@ -0,0 +1,20 @@ +parameters: + toolchain: 'stable' + vmImage: 'ubuntu-16.04' + name: '' + +jobs: +- job: ${{ parameters.name }} + pool: + vmImage: ${{ parameters.vmImage }} + steps: + - template: azure-install-rust.yml + parameters: + toolchain: ${{ parameters.toolchain }} + - script: cargo build + - script: rustdoc --test README.md -L target/debug/deps --extern flate2=target/debug/libflate2.rlib + - script: cargo test + - script: cargo test --features zlib + - script: cargo test --features tokio + - script: cargo test --features "tokio zlib" + - script: cargo test --features zlib --no-default-features diff --git a/flate2/debian/patches/disable-miniz.patch b/flate2/debian/patches/disable-miniz.patch new file mode 100644 index 000000000..4a6dee0d4 --- /dev/null +++ b/flate2/debian/patches/disable-miniz.patch @@ -0,0 +1,36 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -36,15 +36,6 @@ + version = "1.0" + optional = true + +-[dependencies.miniz-sys] +-version = "0.1.11" +-optional = true +- +-[dependencies.miniz_oxide_c_api] +-version = "0.2" +-features = ["no_c_export"] +-optional = true +- + [dependencies.tokio-io] + version = "0.1" + optional = true +@@ -59,13 +50,12 @@ + version = "0.1" + + [features] +-default = ["miniz-sys"] +-rust_backend = ["miniz_oxide_c_api"] ++default = ["zlib"] ++miniz-sys = ["zlib"] ++miniz_oxide_c_api = ["zlib"] ++rust_backend = ["zlib"] + tokio = ["tokio-io", "futures"] + zlib = ["libz-sys"] +-[target."cfg(all(target_arch = \"wasm32\", not(target_os = \"emscripten\")))".dependencies.miniz_oxide_c_api] +-version = "0.2" +-features = ["no_c_export"] + [badges.appveyor] + repository = "alexcrichton/flate2-rs" + diff --git a/flate2/debian/patches/series b/flate2/debian/patches/series new file mode 100644 index 000000000..d42c26703 --- /dev/null +++ b/flate2/debian/patches/series @@ -0,0 +1 @@ +disable-miniz.patch diff --git a/flate2/examples/deflatedecoder-bufread.rs b/flate2/examples/deflatedecoder-bufread.rs new file mode 100644 index 000000000..7d1cb6fd9 --- /dev/null +++ b/flate2/examples/deflatedecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::DeflateDecoder; +use flate2::write::DeflateEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut deflater = DeflateDecoder::new(&bytes[..]); + let mut s = String::new(); + deflater.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/deflatedecoder-read.rs b/flate2/examples/deflatedecoder-read.rs new file mode 100644 index 000000000..cc5d435be --- /dev/null +++ b/flate2/examples/deflatedecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::read::DeflateDecoder; +use flate2::write::DeflateEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut deflater = DeflateDecoder::new(&bytes[..]); + let mut s = String::new(); + deflater.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/deflatedecoder-write.rs b/flate2/examples/deflatedecoder-write.rs new file mode 100644 index 000000000..276490bac --- /dev/null +++ b/flate2/examples/deflatedecoder-write.rs @@ -0,0 +1,26 @@ +extern crate flate2; + +use flate2::write::DeflateDecoder; +use flate2::write::DeflateEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here Vec implements Write +fn decode_reader(bytes: Vec) -> io::Result { + let mut writer = Vec::new(); + let mut deflater = DeflateDecoder::new(writer); + deflater.write_all(&bytes[..])?; + writer = deflater.finish()?; + let return_string = String::from_utf8(writer).expect("String parsing error"); + Ok(return_string) +} diff --git a/flate2/examples/deflateencoder-bufread.rs b/flate2/examples/deflateencoder-bufread.rs new file mode 100644 index 000000000..6240f3997 --- /dev/null +++ b/flate2/examples/deflateencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::DeflateEncoder; +use flate2::Compression; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::io::BufReader; + +// Open file and debug print the contents compressed with Deflate +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut deflater = DeflateEncoder::new(b, Compression::fast()); + let mut buffer = Vec::new(); + deflater.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2/examples/deflateencoder-read.rs b/flate2/examples/deflateencoder-read.rs new file mode 100644 index 000000000..d22777f51 --- /dev/null +++ b/flate2/examples/deflateencoder-read.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use flate2::read::DeflateEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Print the Deflate compressed representation of hello world +fn main() { + println!("{:?}", deflateencoder_read_hello_world().unwrap()); +} + +// Return a vector containing the Defalte compressed version of hello world +fn deflateencoder_read_hello_world() -> io::Result> { + let mut ret_vec = [0; 100]; + let c = b"hello world"; + let mut deflater = DeflateEncoder::new(&c[..], Compression::fast()); + let count = deflater.read(&mut ret_vec)?; + Ok(ret_vec[0..count].to_vec()) +} diff --git a/flate2/examples/deflateencoder-write.rs b/flate2/examples/deflateencoder-write.rs new file mode 100644 index 000000000..243b9dfdd --- /dev/null +++ b/flate2/examples/deflateencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use flate2::write::DeflateEncoder; +use flate2::Compression; +use std::io::prelude::*; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2/examples/gzbuilder.rs b/flate2/examples/gzbuilder.rs new file mode 100644 index 000000000..031683dec --- /dev/null +++ b/flate2/examples/gzbuilder.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::Compression; +use flate2::GzBuilder; +use std::fs::File; +use std::io; +use std::io::prelude::*; + +// Open file and debug print the contents compressed with gzip +fn main() { + sample_builder().unwrap(); +} + +// GzBuilder opens a file and writes a sample string using Builder pattern +fn sample_builder() -> Result<(), io::Error> { + let f = File::create("examples/hello_world.gz")?; + let mut gz = GzBuilder::new() + .filename("hello_world.txt") + .comment("test file, please delete") + .write(f, Compression::default()); + gz.write_all(b"hello world")?; + gz.finish()?; + Ok(()) +} diff --git a/flate2/examples/gzdecoder-bufread.rs b/flate2/examples/gzdecoder-bufread.rs new file mode 100644 index 000000000..0702c174c --- /dev/null +++ b/flate2/examples/gzdecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::GzDecoder; +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = GzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/gzdecoder-read.rs b/flate2/examples/gzdecoder-read.rs new file mode 100644 index 000000000..d8dcba367 --- /dev/null +++ b/flate2/examples/gzdecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::read::GzDecoder; +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = GzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/gzdecoder-write.rs b/flate2/examples/gzdecoder-write.rs new file mode 100644 index 000000000..766bb5e75 --- /dev/null +++ b/flate2/examples/gzdecoder-write.rs @@ -0,0 +1,26 @@ +extern crate flate2; + +use flate2::write::{GzDecoder, GzEncoder}; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_writer(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_writer(bytes: Vec) -> io::Result { + let mut writer = Vec::new(); + let mut decoder = GzDecoder::new(writer); + decoder.write_all(&bytes[..])?; + decoder.try_finish()?; + writer = decoder.finish()?; + let return_string = String::from_utf8(writer).expect("String parsing error"); + Ok(return_string) +} diff --git a/flate2/examples/gzencoder-bufread.rs b/flate2/examples/gzencoder-bufread.rs new file mode 100644 index 000000000..015ae0a82 --- /dev/null +++ b/flate2/examples/gzencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::GzEncoder; +use flate2::Compression; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::io::BufReader; + +// Open file and debug print the contents compressed with gzip +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut gz = GzEncoder::new(b, Compression::fast()); + let mut buffer = Vec::new(); + gz.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2/examples/gzencoder-read.rs b/flate2/examples/gzencoder-read.rs new file mode 100644 index 000000000..a9657aca1 --- /dev/null +++ b/flate2/examples/gzencoder-read.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use flate2::read::GzEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Print the GZ compressed representation of hello world +fn main() { + println!("{:?}", gzencoder_read_hello_world().unwrap()); +} + +// Return a vector containing the GZ compressed version of hello world +fn gzencoder_read_hello_world() -> io::Result> { + let mut ret_vec = [0; 100]; + let c = b"hello world"; + let mut z = GzEncoder::new(&c[..], Compression::fast()); + let count = z.read(&mut ret_vec)?; + Ok(ret_vec[0..count].to_vec()) +} diff --git a/flate2/examples/gzencoder-write.rs b/flate2/examples/gzencoder-write.rs new file mode 100644 index 000000000..275b010c5 --- /dev/null +++ b/flate2/examples/gzencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io::prelude::*; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2/examples/gzmultidecoder-bufread.rs b/flate2/examples/gzmultidecoder-bufread.rs new file mode 100644 index 000000000..c6bb2c550 --- /dev/null +++ b/flate2/examples/gzmultidecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::MultiGzDecoder; +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = MultiGzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/gzmultidecoder-read.rs b/flate2/examples/gzmultidecoder-read.rs new file mode 100644 index 000000000..7c8a8e316 --- /dev/null +++ b/flate2/examples/gzmultidecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::read::MultiGzDecoder; +use flate2::write::GzEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = MultiGzDecoder::new(&bytes[..]); + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/hello_world.txt b/flate2/examples/hello_world.txt new file mode 100644 index 000000000..557db03de --- /dev/null +++ b/flate2/examples/hello_world.txt @@ -0,0 +1 @@ +Hello World diff --git a/flate2/examples/zlibdecoder-bufread.rs b/flate2/examples/zlibdecoder-bufread.rs new file mode 100644 index 000000000..30f168a7b --- /dev/null +++ b/flate2/examples/zlibdecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::ZlibDecoder; +use flate2::write::ZlibEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_bufreader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_bufreader(bytes: Vec) -> io::Result { + let mut z = ZlibDecoder::new(&bytes[..]); + let mut s = String::new(); + z.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/zlibdecoder-read.rs b/flate2/examples/zlibdecoder-read.rs new file mode 100644 index 000000000..f7e5fb0af --- /dev/null +++ b/flate2/examples/zlibdecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::read::ZlibDecoder; +use flate2::write::ZlibEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut z = ZlibDecoder::new(&bytes[..]); + let mut s = String::new(); + z.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2/examples/zlibdecoder-write.rs b/flate2/examples/zlibdecoder-write.rs new file mode 100644 index 000000000..358e9035b --- /dev/null +++ b/flate2/examples/zlibdecoder-write.rs @@ -0,0 +1,26 @@ +extern crate flate2; + +use flate2::write::ZlibDecoder; +use flate2::write::ZlibEncoder; +use flate2::Compression; +use std::io; +use std::io::prelude::*; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here Vec implements Write +fn decode_reader(bytes: Vec) -> io::Result { + let mut writer = Vec::new(); + let mut z = ZlibDecoder::new(writer); + z.write_all(&bytes[..])?; + writer = z.finish()?; + let return_string = String::from_utf8(writer).expect("String parsing error"); + Ok(return_string) +} diff --git a/flate2/examples/zlibencoder-bufread.rs b/flate2/examples/zlibencoder-bufread.rs new file mode 100644 index 000000000..0321d8d38 --- /dev/null +++ b/flate2/examples/zlibencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use flate2::bufread::ZlibEncoder; +use flate2::Compression; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::io::BufReader; + +// Open file and debug print the contents compressed with zlib +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut z = ZlibEncoder::new(b, Compression::fast()); + let mut buffer = Vec::new(); + z.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2/examples/zlibencoder-read.rs b/flate2/examples/zlibencoder-read.rs new file mode 100644 index 000000000..b0ae50a97 --- /dev/null +++ b/flate2/examples/zlibencoder-read.rs @@ -0,0 +1,21 @@ +extern crate flate2; + +use flate2::read::ZlibEncoder; +use flate2::Compression; +use std::fs::File; +use std::io::prelude::*; + +// Open file and debug print the compressed contents +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File implements Read +fn open_hello_world() -> std::io::Result> { + let f = File::open("examples/hello_world.txt")?; + let mut z = ZlibEncoder::new(f, Compression::fast()); + let mut buffer = [0; 50]; + let byte_count = z.read(&mut buffer)?; + Ok(buffer[0..byte_count].to_vec()) +} diff --git a/flate2/examples/zlibencoder-write.rs b/flate2/examples/zlibencoder-write.rs new file mode 100644 index 000000000..76bcf17b1 --- /dev/null +++ b/flate2/examples/zlibencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use flate2::write::ZlibEncoder; +use flate2::Compression; +use std::io::prelude::*; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2/src/bufreader.rs b/flate2/src/bufreader.rs new file mode 100644 index 000000000..9aa6a3ae9 --- /dev/null +++ b/flate2/src/bufreader.rs @@ -0,0 +1,104 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::io; +use std::io::prelude::*; +use std::mem; + +pub struct BufReader { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl ::std::fmt::Debug for BufReader +where + R: ::std::fmt::Debug, +{ + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field( + "buffer", + &format_args!("{}/{}", self.cap - self.pos, self.buf.len()), + ) + .finish() + } +} + +impl BufReader { + pub fn new(inner: R) -> BufReader { + BufReader::with_buf(vec![0; 32 * 1024], inner) + } + + pub fn with_buf(buf: Vec, inner: R) -> BufReader { + BufReader { + inner: inner, + buf: buf.into_boxed_slice(), + pos: 0, + cap: 0, + } + } +} + +impl BufReader { + pub fn get_ref(&self) -> &R { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + pub fn into_inner(self) -> R { + self.inner + } + + pub fn reset(&mut self, inner: R) -> R { + self.pos = 0; + self.cap = 0; + mem::replace(&mut self.inner, inner) + } +} + +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + return self.inner.read(buf); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read(buf)? + }; + self.consume(nread); + Ok(nread) + } +} + +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + if self.pos == self.cap { + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} diff --git a/flate2/src/crc.rs b/flate2/src/crc.rs new file mode 100644 index 000000000..9e60e97cd --- /dev/null +++ b/flate2/src/crc.rs @@ -0,0 +1,178 @@ +//! Simple CRC bindings backed by miniz.c + +use std::io; +use std::io::prelude::*; + +use crc32fast::Hasher; + +/// The CRC calculated by a [`CrcReader`]. +/// +/// [`CrcReader`]: struct.CrcReader.html +#[derive(Debug)] +pub struct Crc { + amt: u32, + hasher: Hasher, +} + +/// A wrapper around a [`Read`] that calculates the CRC. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +#[derive(Debug)] +pub struct CrcReader { + inner: R, + crc: Crc, +} + +impl Crc { + /// Create a new CRC. + pub fn new() -> Crc { + Crc { + amt: 0, + hasher: Hasher::new(), + } + } + + /// Returns the current crc32 checksum. + pub fn sum(&self) -> u32 { + self.hasher.clone().finalize() + } + + /// The number of bytes that have been used to calculate the CRC. + /// This value is only accurate if the amount is lower than 232. + pub fn amount(&self) -> u32 { + self.amt + } + + /// Update the CRC with the bytes in `data`. + pub fn update(&mut self, data: &[u8]) { + self.amt = self.amt.wrapping_add(data.len() as u32); + self.hasher.update(data); + } + + /// Reset the CRC. + pub fn reset(&mut self) { + self.amt = 0; + self.hasher.reset(); + } + + /// Combine the CRC with the CRC for the subsequent block of bytes. + pub fn combine(&mut self, additional_crc: &Crc) { + self.amt += additional_crc.amt; + self.hasher.combine(&additional_crc.hasher); + } +} + +impl CrcReader { + /// Create a new CrcReader. + pub fn new(r: R) -> CrcReader { + CrcReader { + inner: r, + crc: Crc::new(), + } + } +} + +impl CrcReader { + /// Get the Crc for this CrcReader. + pub fn crc(&self) -> &Crc { + &self.crc + } + + /// Get the reader that is wrapped by this CrcReader. + pub fn into_inner(self) -> R { + self.inner + } + + /// Get the reader that is wrapped by this CrcReader by reference. + pub fn get_ref(&self) -> &R { + &self.inner + } + + /// Get a mutable reference to the reader that is wrapped by this CrcReader. + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + /// Reset the Crc in this CrcReader. + pub fn reset(&mut self) { + self.crc.reset(); + } +} + +impl Read for CrcReader { + fn read(&mut self, into: &mut [u8]) -> io::Result { + let amt = self.inner.read(into)?; + self.crc.update(&into[..amt]); + Ok(amt) + } +} + +impl BufRead for CrcReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + self.inner.fill_buf() + } + fn consume(&mut self, amt: usize) { + if let Ok(data) = self.inner.fill_buf() { + self.crc.update(&data[..amt]); + } + self.inner.consume(amt); + } +} + +/// A wrapper around a [`Write`] that calculates the CRC. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +#[derive(Debug)] +pub struct CrcWriter { + inner: W, + crc: Crc, +} + +impl CrcWriter { + /// Get the Crc for this CrcWriter. + pub fn crc(&self) -> &Crc { + &self.crc + } + + /// Get the writer that is wrapped by this CrcWriter. + pub fn into_inner(self) -> W { + self.inner + } + + /// Get the writer that is wrapped by this CrcWriter by reference. + pub fn get_ref(&self) -> &W { + &self.inner + } + + /// Get a mutable reference to the writer that is wrapped by this CrcWriter. + pub fn get_mut(&mut self) -> &mut W { + &mut self.inner + } + + /// Reset the Crc in this CrcWriter. + pub fn reset(&mut self) { + self.crc.reset(); + } +} + +impl CrcWriter { + /// Create a new CrcWriter. + pub fn new(w: W) -> CrcWriter { + CrcWriter { + inner: w, + crc: Crc::new(), + } + } +} + +impl Write for CrcWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + let amt = try!(self.inner.write(buf)); + self.crc.update(&buf[..amt]); + Ok(amt) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} diff --git a/flate2/src/deflate/bufread.rs b/flate2/src/deflate/bufread.rs new file mode 100644 index 000000000..4511ba95b --- /dev/null +++ b/flate2/src/deflate/bufread.rs @@ -0,0 +1,268 @@ +use std::io; +use std::io::prelude::*; +use std::mem; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`BufRead`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::bufread::DeflateEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// # fn main() { +/// # println!("{:?}", open_hello_world().unwrap()); +/// # } +/// # +/// // Opens sample file, compresses the contents and returns a Vector +/// fn open_hello_world() -> io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut deflater = DeflateEncoder::new(b, Compression::fast()); +/// let mut buffer = Vec::new(); +/// deflater.read_to_end(&mut buffer)?; +/// Ok(buffer) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + obj: R, + data: Compress, +} + +impl DeflateEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + obj: r, + data: Compress::new(level, false), + } + } +} + +pub fn reset_encoder_data(zlib: &mut DeflateEncoder) { + zlib.data.reset(); +} + +impl DeflateEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_encoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this encoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`BufRead`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::bufread::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut deflater = DeflateDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// deflater.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + obj: R, + data: Decompress, +} + +pub fn reset_decoder_data(zlib: &mut DeflateDecoder) { + zlib.data = Decompress::new(false); +} + +impl DeflateDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> DeflateDecoder { + DeflateDecoder { + obj: r, + data: Decompress::new(false), + } + } +} + +impl DeflateDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_decoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Resets the state of this decoder's data + /// + /// This will reset the internal state of this decoder. It will continue + /// reading from the same stream. + pub fn reset_data(&mut self) { + reset_decoder_data(self); + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/deflate/mod.rs b/flate2/src/deflate/mod.rs new file mode 100644 index 000000000..9ea81dcc6 --- /dev/null +++ b/flate2/src/deflate/mod.rs @@ -0,0 +1,193 @@ +pub mod bufread; +pub mod read; +pub mod write; + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + + use rand::{thread_rng, Rng}; + + use super::{read, write}; + use Compression; + + #[test] + fn roundtrip() { + let mut real = Vec::new(); + let mut w = write::DeflateEncoder::new(Vec::new(), Compression::default()); + let v = ::random_bytes().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::DeflateDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + } + + #[test] + fn drop_writes() { + let mut data = Vec::new(); + write::DeflateEncoder::new(&mut data, Compression::default()) + .write_all(b"foo") + .unwrap(); + let mut r = read::DeflateDecoder::new(&data[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == b"foo"); + } + + #[test] + fn total_in() { + let mut real = Vec::new(); + let mut w = write::DeflateEncoder::new(Vec::new(), Compression::default()); + let v = ::random_bytes().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let mut result = w.finish().unwrap(); + + let result_len = result.len(); + + for _ in 0..200 { + result.extend(v.iter().map(|x| *x)); + } + + let mut r = read::DeflateDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + assert_eq!(r.total_in(), result_len as u64); + } + + #[test] + fn roundtrip2() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut r = + read::DeflateDecoder::new(read::DeflateEncoder::new(&v[..], Compression::default())); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert_eq!(ret, v); + } + + #[test] + fn roundtrip3() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut w = write::DeflateEncoder::new( + write::DeflateDecoder::new(Vec::new()), + Compression::default(), + ); + w.write_all(&v).unwrap(); + let w = w.finish().unwrap().finish().unwrap(); + assert!(w == v); + } + + #[test] + fn reset_writer() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut w = write::DeflateEncoder::new(Vec::new(), Compression::default()); + w.write_all(&v).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&v).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::DeflateEncoder::new(Vec::new(), Compression::default()); + w.write_all(&v).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c); + } + + #[test] + fn reset_reader() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::DeflateEncoder::new(&v[..], Compression::default()); + r.read_to_end(&mut a).unwrap(); + r.reset(&v[..]); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::DeflateEncoder::new(&v[..], Compression::default()); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c); + } + + #[test] + fn reset_decoder() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut w = write::DeflateEncoder::new(Vec::new(), Compression::default()); + w.write_all(&v).unwrap(); + let data = w.finish().unwrap(); + + { + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::DeflateDecoder::new(&data[..]); + r.read_to_end(&mut a).unwrap(); + r.reset(&data); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::DeflateDecoder::new(&data[..]); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c && c == v); + } + + { + let mut w = write::DeflateDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&data).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::DeflateDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c && c == v); + } + } + + #[test] + fn zero_length_read_with_data() { + let m = vec![3u8; 128 * 1024 + 1]; + let mut c = read::DeflateEncoder::new(&m[..], Compression::default()); + + let mut result = Vec::new(); + c.read_to_end(&mut result).unwrap(); + + let mut d = read::DeflateDecoder::new(&result[..]); + let mut data = Vec::new(); + assert!(d.read(&mut data).unwrap() == 0); + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut r = read::DeflateDecoder::new(read::DeflateEncoder::new( + &v[..], + Compression::default(), + )); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn qc_writer() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut w = write::DeflateEncoder::new( + write::DeflateDecoder::new(Vec::new()), + Compression::default(), + ); + w.write_all(&v).unwrap(); + v == w.finish().unwrap().finish().unwrap() + } + } +} diff --git a/flate2/src/deflate/read.rs b/flate2/src/deflate/read.rs new file mode 100644 index 000000000..d25f2be65 --- /dev/null +++ b/flate2/src/deflate/read.rs @@ -0,0 +1,266 @@ +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::bufread; +use bufreader::BufReader; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`Read`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::read::DeflateEncoder; +/// +/// # fn main() { +/// # println!("{:?}", deflateencoder_read_hello_world().unwrap()); +/// # } +/// # +/// // Return a vector containing the Deflate compressed version of hello world +/// fn deflateencoder_read_hello_world() -> io::Result> { +/// let mut ret_vec = [0;100]; +/// let c = b"hello world"; +/// let mut deflater = DeflateEncoder::new(&c[..], Compression::fast()); +/// let count = deflater.read(&mut ret_vec)?; +/// Ok(ret_vec[0..count].to_vec()) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + inner: bufread::DeflateEncoder>, +} + +impl DeflateEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + inner: bufread::DeflateEncoder::new(BufReader::new(r), level), + } + } +} + +impl DeflateEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_encoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this encoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`Read`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::read::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut deflater = DeflateDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// deflater.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + inner: bufread::DeflateDecoder>, +} + +impl DeflateDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> DeflateDecoder { + DeflateDecoder::new_with_buf(r, vec![0; 32 * 1024]) + } + + /// Same as `new`, but the intermediate buffer for data is specified. + /// + /// Note that the capacity of the intermediate buffer is never increased, + /// and it is recommended for it to be large. + pub fn new_with_buf(r: R, buf: Vec) -> DeflateDecoder { + DeflateDecoder { + inner: bufread::DeflateDecoder::new(BufReader::with_buf(buf, r)), + } + } +} + +impl DeflateDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_decoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/deflate/write.rs b/flate2/src/deflate/write.rs new file mode 100644 index 000000000..3ba4feb2d --- /dev/null +++ b/flate2/src/deflate/write.rs @@ -0,0 +1,349 @@ +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`Write`] interface and takes a stream of +/// uncompressed data, writing the compressed data to the wrapped writer. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::DeflateEncoder; +/// +/// // Vec implements Write to print the compressed bytes of sample string +/// # fn main() { +/// +/// let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); +/// e.write_all(b"Hello World").unwrap(); +/// println!("{:?}", e.finish().unwrap()); +/// # } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + inner: zio::Writer, +} + +impl DeflateEncoder { + /// Creates a new encoder which will write compressed data to the stream + /// given at the given compression level. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + inner: zio::Writer::new(w, Compress::new(level, false)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this encoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. If the stream + /// cannot be finished an error is returned. + /// + /// After the current stream has been finished, this will reset the internal + /// state of this encoder and replace the output stream with the one + /// provided, returning the previous output stream. Future data written to + /// this encoder will be the compressed into the stream `w` provided. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + self.inner.finish()?; + self.inner.data.reset(); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream, close off the compressed + /// stream and, if successful, return the contained writer. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.inner.finish()?; + Ok(self.inner.take_inner()) + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// The compressed stream will not closed but only flushed. This + /// means that obtained byte array can by extended by another deflated + /// stream. To close the stream add the two bytes 0x3 and 0x0. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn flush_finish(mut self) -> io::Result { + self.inner.flush()?; + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that have been written to this compresor. + /// + /// Note that not all bytes written to this object may be accounted for, + /// there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been written yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.inner.finish()?; + self.inner.get_mut().shutdown() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`Write`] and will emit a stream of decompressed +/// data when fed a stream of compressed data. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::write::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_writer(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here Vec implements Write +/// fn decode_writer(bytes: Vec) -> io::Result { +/// let mut writer = Vec::new(); +/// let mut deflater = DeflateDecoder::new(writer); +/// deflater.write_all(&bytes[..])?; +/// writer = deflater.finish()?; +/// let return_string = String::from_utf8(writer).expect("String parsing error"); +/// Ok(return_string) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + inner: zio::Writer, +} + +impl DeflateDecoder { + /// Creates a new decoder which will write uncompressed data to the stream. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W) -> DeflateDecoder { + DeflateDecoder { + inner: zio::Writer::new(w, Decompress::new(false)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this decoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. + /// + /// This will then reset the internal state of this decoder and replace the + /// output stream with the one provided, returning the previous output + /// stream. Future data written to this decoder will be decompressed into + /// the output stream `w`. + /// + /// # Errors + /// + /// This function will perform I/O to finish the stream, and if that I/O + /// returns an error then that will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + self.inner.finish()?; + self.inner.data = Decompress::new(false); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to finish the stream, returning any + /// errors which happen. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.inner.finish()?; + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that the decompressor has consumed for + /// decompression. + /// + /// Note that this will likely be smaller than the number of bytes + /// successfully written to this stream due to internal buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the decompressor has written to its + /// output stream. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.inner.finish()?; + self.inner.get_mut().shutdown() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} diff --git a/flate2/src/ffi.rs b/flate2/src/ffi.rs new file mode 100644 index 000000000..b7cb3263a --- /dev/null +++ b/flate2/src/ffi.rs @@ -0,0 +1,173 @@ +pub use self::imp::*; + +#[cfg(feature = "zlib")] +#[allow(bad_style)] +mod imp { + extern crate libz_sys as z; + use libc::{c_char, c_int}; + use std::mem; + use std::ops::{Deref, DerefMut}; + + pub use self::z::deflate as mz_deflate; + pub use self::z::deflateEnd as mz_deflateEnd; + pub use self::z::deflateReset as mz_deflateReset; + pub use self::z::inflate as mz_inflate; + pub use self::z::inflateEnd as mz_inflateEnd; + pub use self::z::z_stream as mz_stream; + pub use self::z::*; + + pub use self::z::Z_BLOCK as MZ_BLOCK; + pub use self::z::Z_BUF_ERROR as MZ_BUF_ERROR; + pub use self::z::Z_DATA_ERROR as MZ_DATA_ERROR; + pub use self::z::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY; + pub use self::z::Z_DEFLATED as MZ_DEFLATED; + pub use self::z::Z_FINISH as MZ_FINISH; + pub use self::z::Z_FULL_FLUSH as MZ_FULL_FLUSH; + pub use self::z::Z_NEED_DICT as MZ_NEED_DICT; + pub use self::z::Z_NO_FLUSH as MZ_NO_FLUSH; + pub use self::z::Z_OK as MZ_OK; + pub use self::z::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH; + pub use self::z::Z_STREAM_END as MZ_STREAM_END; + pub use self::z::Z_STREAM_ERROR as MZ_STREAM_ERROR; + pub use self::z::Z_SYNC_FLUSH as MZ_SYNC_FLUSH; + + pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15; + + const ZLIB_VERSION: &'static str = "1.2.8\0"; + + pub unsafe extern "C" fn mz_deflateInit2( + stream: *mut mz_stream, + level: c_int, + method: c_int, + window_bits: c_int, + mem_level: c_int, + strategy: c_int, + ) -> c_int { + z::deflateInit2_( + stream, + level, + method, + window_bits, + mem_level, + strategy, + ZLIB_VERSION.as_ptr() as *const c_char, + mem::size_of::() as c_int, + ) + } + pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int { + z::inflateInit2_( + stream, + window_bits, + ZLIB_VERSION.as_ptr() as *const c_char, + mem::size_of::() as c_int, + ) + } + + pub struct StreamWrapper { + inner: Box, + } + + impl ::std::fmt::Debug for StreamWrapper { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "StreamWrapper") + } + } + + impl Default for StreamWrapper { + fn default() -> StreamWrapper { + StreamWrapper { + inner: Box::new(unsafe { mem::zeroed() }), + } + } + } + + impl Deref for StreamWrapper { + type Target = mz_stream; + + fn deref(&self) -> &Self::Target { + &*self.inner + } + } + + impl DerefMut for StreamWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.inner + } + } +} + +#[cfg(any( + all(not(feature = "zlib"), feature = "rust_backend"), + all(target_arch = "wasm32", not(target_os = "emscripten")) +))] +mod imp { + extern crate miniz_oxide_c_api; + use std::ops::{Deref, DerefMut}; + + pub use self::miniz_oxide_c_api::lib_oxide::*; + pub use self::miniz_oxide_c_api::*; + + #[derive(Debug, Default)] + pub struct StreamWrapper { + inner: mz_stream, + } + + impl Deref for StreamWrapper { + type Target = mz_stream; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl DerefMut for StreamWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } + } +} + +#[cfg(all( + not(feature = "zlib"), + not(feature = "rust_backend"), + not(all(target_arch = "wasm32", not(target_os = "emscripten"))) +))] +mod imp { + extern crate miniz_sys; + use std::mem; + use std::ops::{Deref, DerefMut}; + + pub use self::miniz_sys::*; + + pub struct StreamWrapper { + inner: mz_stream, + } + + impl ::std::fmt::Debug for StreamWrapper { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(f, "StreamWrapper") + } + } + + impl Default for StreamWrapper { + fn default() -> StreamWrapper { + StreamWrapper { + inner: unsafe { mem::zeroed() }, + } + } + } + + impl Deref for StreamWrapper { + type Target = mz_stream; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl DerefMut for StreamWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } + } +} diff --git a/flate2/src/gz/bufread.rs b/flate2/src/gz/bufread.rs new file mode 100644 index 000000000..a6d1d416f --- /dev/null +++ b/flate2/src/gz/bufread.rs @@ -0,0 +1,631 @@ +use std::cmp; +use std::io; +use std::io::prelude::*; +use std::mem; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::{GzBuilder, GzHeader}; +use super::{FCOMMENT, FEXTRA, FHCRC, FNAME}; +use crc::CrcReader; +use deflate; +use Compression; + +fn copy(into: &mut [u8], from: &[u8], pos: &mut usize) -> usize { + let min = cmp::min(into.len(), from.len() - *pos); + for (slot, val) in into.iter_mut().zip(from[*pos..*pos + min].iter()) { + *slot = *val; + } + *pos += min; + return min; +} + +pub(crate) fn corrupt() -> io::Error { + io::Error::new( + io::ErrorKind::InvalidInput, + "corrupt gzip stream does not have a matching checksum", + ) +} + +fn bad_header() -> io::Error { + io::Error::new(io::ErrorKind::InvalidInput, "invalid gzip header") +} + +fn read_le_u16(r: &mut R) -> io::Result { + let mut b = [0; 2]; + r.read_exact(&mut b)?; + Ok((b[0] as u16) | ((b[1] as u16) << 8)) +} + +pub(crate) fn read_gz_header(r: &mut R) -> io::Result { + let mut crc_reader = CrcReader::new(r); + let mut header = [0; 10]; + crc_reader.read_exact(&mut header)?; + + let id1 = header[0]; + let id2 = header[1]; + if id1 != 0x1f || id2 != 0x8b { + return Err(bad_header()); + } + let cm = header[2]; + if cm != 8 { + return Err(bad_header()); + } + + let flg = header[3]; + let mtime = ((header[4] as u32) << 0) + | ((header[5] as u32) << 8) + | ((header[6] as u32) << 16) + | ((header[7] as u32) << 24); + let _xfl = header[8]; + let os = header[9]; + + let extra = if flg & FEXTRA != 0 { + let xlen = read_le_u16(&mut crc_reader)?; + let mut extra = vec![0; xlen as usize]; + crc_reader.read_exact(&mut extra)?; + Some(extra) + } else { + None + }; + let filename = if flg & FNAME != 0 { + // wow this is slow + let mut b = Vec::new(); + for byte in crc_reader.by_ref().bytes() { + let byte = byte?; + if byte == 0 { + break; + } + b.push(byte); + } + Some(b) + } else { + None + }; + let comment = if flg & FCOMMENT != 0 { + // wow this is slow + let mut b = Vec::new(); + for byte in crc_reader.by_ref().bytes() { + let byte = byte?; + if byte == 0 { + break; + } + b.push(byte); + } + Some(b) + } else { + None + }; + + if flg & FHCRC != 0 { + let calced_crc = crc_reader.crc().sum() as u16; + let stored_crc = read_le_u16(&mut crc_reader)?; + if calced_crc != stored_crc { + return Err(corrupt()); + } + } + + Ok(GzHeader { + extra: extra, + filename: filename, + comment: comment, + operating_system: os, + mtime: mtime, + }) +} + +/// A gzip streaming encoder +/// +/// This structure exposes a [`BufRead`] interface that will read uncompressed data +/// from the underlying reader and expose the compressed version as a [`BufRead`] +/// interface. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::bufread::GzEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// // Opens sample file, compresses the contents and returns a Vector or error +/// // File wrapped in a BufReader implements BufRead +/// +/// fn open_hello_world() -> io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut gz = GzEncoder::new(b, Compression::fast()); +/// let mut buffer = Vec::new(); +/// gz.read_to_end(&mut buffer)?; +/// Ok(buffer) +/// } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: deflate::bufread::DeflateEncoder>, + header: Vec, + pos: usize, + eof: bool, +} + +pub fn gz_encoder(header: Vec, r: R, lvl: Compression) -> GzEncoder { + let crc = CrcReader::new(r); + GzEncoder { + inner: deflate::bufread::DeflateEncoder::new(crc, lvl), + header: header, + pos: 0, + eof: false, + } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `GzBuilder` type. + /// + /// The data read from the stream `r` will be compressed and available + /// through the returned reader. + pub fn new(r: R, level: Compression) -> GzEncoder { + GzBuilder::new().buf_read(r, level) + } + + fn read_footer(&mut self, into: &mut [u8]) -> io::Result { + if self.pos == 8 { + return Ok(0); + } + let crc = self.inner.get_ref().crc(); + let ref arr = [ + (crc.sum() >> 0) as u8, + (crc.sum() >> 8) as u8, + (crc.sum() >> 16) as u8, + (crc.sum() >> 24) as u8, + (crc.amount() >> 0) as u8, + (crc.amount() >> 8) as u8, + (crc.amount() >> 16) as u8, + (crc.amount() >> 24) as u8, + ]; + Ok(copy(into, arr, &mut self.pos)) + } +} + +impl GzEncoder { + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying reader. + /// + /// Note that mutation of the reader may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Returns the underlying stream, consuming this encoder + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +#[inline] +fn finish(buf: &[u8; 8]) -> (u32, u32) { + let crc = ((buf[0] as u32) << 0) + | ((buf[1] as u32) << 8) + | ((buf[2] as u32) << 16) + | ((buf[3] as u32) << 24); + let amt = ((buf[4] as u32) << 0) + | ((buf[5] as u32) << 8) + | ((buf[6] as u32) << 16) + | ((buf[7] as u32) << 24); + (crc, amt) +} + +impl Read for GzEncoder { + fn read(&mut self, mut into: &mut [u8]) -> io::Result { + let mut amt = 0; + if self.eof { + return self.read_footer(into); + } else if self.pos < self.header.len() { + amt += copy(into, &self.header, &mut self.pos); + if amt == into.len() { + return Ok(amt); + } + let tmp = into; + into = &mut tmp[amt..]; + } + match self.inner.read(into)? { + 0 => { + self.eof = true; + self.pos = 0; + self.read_footer(into) + } + n => Ok(amt + n), + } + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +/// A gzip streaming decoder +/// +/// This structure exposes a [`ReadBuf`] interface that will consume compressed +/// data from the underlying reader and emit uncompressed data. +/// +/// [`ReadBuf`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::bufread::GzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = GzDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct GzDecoder { + inner: GzState, + header: Option, + reader: CrcReader>, + multi: bool +} + +#[derive(Debug)] +enum GzState { + Header(Vec), + Body, + Finished(usize, [u8; 8]), + Err(io::Error), + End +} + +/// A small adapter which reads data originally from `buf` and then reads all +/// further data from `reader`. This will also buffer all data read from +/// `reader` into `buf` for reuse on a further call. +struct Buffer<'a, T: 'a> { + buf: &'a mut Vec, + buf_cur: usize, + buf_max: usize, + reader: &'a mut T +} + +impl<'a, T> Buffer<'a, T> { + fn new(buf: &'a mut Vec, reader: &'a mut T) -> Buffer<'a, T> { + Buffer { + reader, + buf_cur: 0, + buf_max: buf.len(), + buf, + } + } +} + +impl<'a, T: Read> Read for Buffer<'a, T> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.buf_cur == self.buf_max { + let len = self.reader.read(buf)?; + self.buf.extend_from_slice(&buf[..len]); + Ok(len) + } else { + let len = (&self.buf[self.buf_cur..self.buf_max]).read(buf)?; + self.buf_cur += len; + Ok(len) + } + } +} + +impl GzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// gzip header. + pub fn new(mut r: R) -> GzDecoder { + let mut buf = Vec::with_capacity(10); // minimum header length + let mut header = None; + + let result = { + let mut reader = Buffer::new(&mut buf, &mut r); + read_gz_header(&mut reader) + }; + + let state = match result { + Ok(hdr) => { + header = Some(hdr); + GzState::Body + }, + Err(ref err) if io::ErrorKind::WouldBlock == err.kind() + => GzState::Header(buf), + Err(err) => GzState::Err(err) + }; + + GzDecoder { + inner: state, + reader: CrcReader::new(deflate::bufread::DeflateDecoder::new(r)), + multi: false, + header + } + } + + fn multi(mut self, flag: bool) -> GzDecoder { + self.multi = flag; + self + } +} + +impl GzDecoder { + /// Returns the header associated with this stream, if it was valid + pub fn header(&self) -> Option<&GzHeader> { + self.header.as_ref() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.reader.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.reader.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.reader.into_inner().into_inner() + } +} + +impl Read for GzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + let GzDecoder { inner, header, reader, multi } = self; + + loop { + *inner = match mem::replace(inner, GzState::End) { + GzState::Header(mut buf) => { + let result = { + let mut reader = Buffer::new(&mut buf, reader.get_mut().get_mut()); + read_gz_header(&mut reader) + }; + let hdr = result + .map_err(|err| { + if io::ErrorKind::WouldBlock == err.kind() { + *inner = GzState::Header(buf); + } + + err + })?; + *header = Some(hdr); + GzState::Body + }, + GzState::Body => { + if into.is_empty() { + *inner = GzState::Body; + return Ok(0); + } + + let n = reader.read(into) + .map_err(|err| { + if io::ErrorKind::WouldBlock == err.kind() { + *inner = GzState::Body; + } + + err + })?; + + match n { + 0 => GzState::Finished(0, [0; 8]), + n => { + *inner = GzState::Body; + return Ok(n); + } + } + }, + GzState::Finished(pos, mut buf) => if pos < buf.len() { + let n = reader.get_mut().get_mut() + .read(&mut buf[pos..]) + .and_then(|n| if n == 0 { + Err(io::ErrorKind::UnexpectedEof.into()) + } else { + Ok(n) + }) + .map_err(|err| { + if io::ErrorKind::WouldBlock == err.kind() { + *inner = GzState::Finished(pos, buf); + } + + err + })?; + + GzState::Finished(pos + n, buf) + } else { + let (crc, amt) = finish(&buf); + + if crc != reader.crc().sum() || amt != reader.crc().amount() { + return Err(corrupt()); + } else if *multi { + let is_eof = reader.get_mut().get_mut() + .fill_buf() + .map(|buf| buf.is_empty()) + .map_err(|err| { + if io::ErrorKind::WouldBlock == err.kind() { + *inner = GzState::Finished(pos, buf); + } + + err + })?; + + if is_eof { + GzState::End + } else { + reader.reset(); + reader.get_mut().reset_data(); + header.take(); + GzState::Header(Vec::with_capacity(10)) + } + } else { + GzState::End + } + }, + GzState::Err(err) => return Err(err), + GzState::End => return Ok(0) + }; + } + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for GzDecoder {} + +impl Write for GzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for GzDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A gzip streaming decoder that decodes all members of a multistream +/// +/// A gzip member consists of a header, compressed data and a trailer. The [gzip +/// specification](https://tools.ietf.org/html/rfc1952), however, allows multiple +/// gzip members to be joined in a single stream. `MultiGzDecoder` will +/// decode all consecutive members while `GzDecoder` will only decompress +/// the first gzip member. The multistream format is commonly used in +/// bioinformatics, for example when using the BGZF compressed data. +/// +/// This structure exposes a [`BufRead`] interface that will consume all gzip members +/// from the underlying reader and emit uncompressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::bufread::MultiGzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = MultiGzDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct MultiGzDecoder(GzDecoder); + +impl MultiGzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// (first) gzip header. If the gzip stream contains multiple members all will + /// be decoded. + pub fn new(r: R) -> MultiGzDecoder { + MultiGzDecoder(GzDecoder::new(r).multi(true)) + } +} + +impl MultiGzDecoder { + /// Returns the current header associated with this stream, if it's valid + pub fn header(&self) -> Option<&GzHeader> { + self.0.header() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.0.get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.0.get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.0.into_inner() + } +} + +impl Read for MultiGzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.0.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for MultiGzDecoder {} + +impl Write for MultiGzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for MultiGzDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/gz/mod.rs b/flate2/src/gz/mod.rs new file mode 100644 index 000000000..b9043b7d3 --- /dev/null +++ b/flate2/src/gz/mod.rs @@ -0,0 +1,359 @@ +use std::ffi::CString; +use std::io::prelude::*; +use std::time; + +use bufreader::BufReader; +use Compression; + +pub static FHCRC: u8 = 1 << 1; +pub static FEXTRA: u8 = 1 << 2; +pub static FNAME: u8 = 1 << 3; +pub static FCOMMENT: u8 = 1 << 4; + +pub mod bufread; +pub mod read; +pub mod write; + +/// A structure representing the header of a gzip stream. +/// +/// The header can contain metadata about the file that was compressed, if +/// present. +#[derive(PartialEq, Clone, Debug, Default)] +pub struct GzHeader { + extra: Option>, + filename: Option>, + comment: Option>, + operating_system: u8, + mtime: u32, +} + +impl GzHeader { + /// Returns the `filename` field of this gzip stream's header, if present. + pub fn filename(&self) -> Option<&[u8]> { + self.filename.as_ref().map(|s| &s[..]) + } + + /// Returns the `extra` field of this gzip stream's header, if present. + pub fn extra(&self) -> Option<&[u8]> { + self.extra.as_ref().map(|s| &s[..]) + } + + /// Returns the `comment` field of this gzip stream's header, if present. + pub fn comment(&self) -> Option<&[u8]> { + self.comment.as_ref().map(|s| &s[..]) + } + + /// Returns the `operating_system` field of this gzip stream's header. + /// + /// There are predefined values for various operating systems. + /// 255 means that the value is unknown. + pub fn operating_system(&self) -> u8 { + self.operating_system + } + + /// This gives the most recent modification time of the original file being compressed. + /// + /// The time is in Unix format, i.e., seconds since 00:00:00 GMT, Jan. 1, 1970. + /// (Note that this may cause problems for MS-DOS and other systems that use local + /// rather than Universal time.) If the compressed data did not come from a file, + /// `mtime` is set to the time at which compression started. + /// `mtime` = 0 means no time stamp is available. + /// + /// The usage of `mtime` is discouraged because of Year 2038 problem. + pub fn mtime(&self) -> u32 { + self.mtime + } + + /// Returns the most recent modification time represented by a date-time type. + /// Returns `None` if the value of the underlying counter is 0, + /// indicating no time stamp is available. + /// + /// + /// The time is measured as seconds since 00:00:00 GMT, Jan. 1 1970. + /// See [`mtime`](#method.mtime) for more detail. + pub fn mtime_as_datetime(&self) -> Option { + if self.mtime == 0 { + None + } else { + let duration = time::Duration::new(u64::from(self.mtime), 0); + let datetime = time::UNIX_EPOCH + duration; + Some(datetime) + } + } +} + +/// A builder structure to create a new gzip Encoder. +/// +/// This structure controls header configuration options such as the filename. +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// # use std::io; +/// use std::fs::File; +/// use flate2::GzBuilder; +/// use flate2::Compression; +/// +/// // GzBuilder opens a file and writes a sample string using GzBuilder pattern +/// +/// # fn sample_builder() -> Result<(), io::Error> { +/// let f = File::create("examples/hello_world.gz")?; +/// let mut gz = GzBuilder::new() +/// .filename("hello_world.txt") +/// .comment("test file, please delete") +/// .write(f, Compression::default()); +/// gz.write_all(b"hello world")?; +/// gz.finish()?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +pub struct GzBuilder { + extra: Option>, + filename: Option, + comment: Option, + operating_system: Option, + mtime: u32, +} + +impl GzBuilder { + /// Create a new blank builder with no header by default. + pub fn new() -> GzBuilder { + GzBuilder { + extra: None, + filename: None, + comment: None, + operating_system: None, + mtime: 0, + } + } + + /// Configure the `mtime` field in the gzip header. + pub fn mtime(mut self, mtime: u32) -> GzBuilder { + self.mtime = mtime; + self + } + + /// Configure the `operating_system` field in the gzip header. + pub fn operating_system(mut self, os: u8) -> GzBuilder { + self.operating_system = Some(os); + self + } + + /// Configure the `extra` field in the gzip header. + pub fn extra>>(mut self, extra: T) -> GzBuilder { + self.extra = Some(extra.into()); + self + } + + /// Configure the `filename` field in the gzip header. + /// + /// # Panics + /// + /// Panics if the `filename` slice contains a zero. + pub fn filename>>(mut self, filename: T) -> GzBuilder { + self.filename = Some(CString::new(filename.into()).unwrap()); + self + } + + /// Configure the `comment` field in the gzip header. + /// + /// # Panics + /// + /// Panics if the `comment` slice contains a zero. + pub fn comment>>(mut self, comment: T) -> GzBuilder { + self.comment = Some(CString::new(comment.into()).unwrap()); + self + } + + /// Consume this builder, creating a writer encoder in the process. + /// + /// The data written to the returned encoder will be compressed and then + /// written out to the supplied parameter `w`. + pub fn write(self, w: W, lvl: Compression) -> write::GzEncoder { + write::gz_encoder(self.into_header(lvl), w, lvl) + } + + /// Consume this builder, creating a reader encoder in the process. + /// + /// Data read from the returned encoder will be the compressed version of + /// the data read from the given reader. + pub fn read(self, r: R, lvl: Compression) -> read::GzEncoder { + read::gz_encoder(self.buf_read(BufReader::new(r), lvl)) + } + + /// Consume this builder, creating a reader encoder in the process. + /// + /// Data read from the returned encoder will be the compressed version of + /// the data read from the given reader. + pub fn buf_read(self, r: R, lvl: Compression) -> bufread::GzEncoder + where + R: BufRead, + { + bufread::gz_encoder(self.into_header(lvl), r, lvl) + } + + fn into_header(self, lvl: Compression) -> Vec { + let GzBuilder { + extra, + filename, + comment, + operating_system, + mtime, + } = self; + let mut flg = 0; + let mut header = vec![0u8; 10]; + match extra { + Some(v) => { + flg |= FEXTRA; + header.push((v.len() >> 0) as u8); + header.push((v.len() >> 8) as u8); + header.extend(v); + } + None => {} + } + match filename { + Some(filename) => { + flg |= FNAME; + header.extend(filename.as_bytes_with_nul().iter().map(|x| *x)); + } + None => {} + } + match comment { + Some(comment) => { + flg |= FCOMMENT; + header.extend(comment.as_bytes_with_nul().iter().map(|x| *x)); + } + None => {} + } + header[0] = 0x1f; + header[1] = 0x8b; + header[2] = 8; + header[3] = flg; + header[4] = (mtime >> 0) as u8; + header[5] = (mtime >> 8) as u8; + header[6] = (mtime >> 16) as u8; + header[7] = (mtime >> 24) as u8; + header[8] = if lvl.0 >= Compression::best().0 { + 2 + } else if lvl.0 <= Compression::fast().0 { + 4 + } else { + 0 + }; + + // Typically this byte indicates what OS the gz stream was created on, + // but in an effort to have cross-platform reproducible streams just + // default this value to 255. I'm not sure that if we "correctly" set + // this it'd do anything anyway... + header[9] = operating_system.unwrap_or(255); + return header; + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + + use super::{read, write, GzBuilder}; + use rand::{thread_rng, Rng}; + use Compression; + + #[test] + fn roundtrip() { + let mut e = write::GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"foo bar baz").unwrap(); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + } + + #[test] + fn roundtrip_zero() { + let e = write::GzEncoder::new(Vec::new(), Compression::default()); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, ""); + } + + #[test] + fn roundtrip_big() { + let mut real = Vec::new(); + let mut w = write::GzEncoder::new(Vec::new(), Compression::default()); + let v = ::random_bytes().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::GzDecoder::new(&result[..]); + let mut v = Vec::new(); + r.read_to_end(&mut v).unwrap(); + assert!(v == real); + } + + #[test] + fn roundtrip_big2() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut r = read::GzDecoder::new(read::GzEncoder::new(&v[..], Compression::default())); + let mut res = Vec::new(); + r.read_to_end(&mut res).unwrap(); + assert!(res == v); + } + + #[test] + fn fields() { + let r = vec![0, 2, 4, 6]; + let e = GzBuilder::new() + .filename("foo.rs") + .comment("bar") + .extra(vec![0, 1, 2, 3]) + .read(&r[..], Compression::default()); + let mut d = read::GzDecoder::new(e); + assert_eq!(d.header().unwrap().filename(), Some(&b"foo.rs"[..])); + assert_eq!(d.header().unwrap().comment(), Some(&b"bar"[..])); + assert_eq!(d.header().unwrap().extra(), Some(&b"\x00\x01\x02\x03"[..])); + let mut res = Vec::new(); + d.read_to_end(&mut res).unwrap(); + assert_eq!(res, vec![0, 2, 4, 6]); + } + + #[test] + fn keep_reading_after_end() { + let mut e = write::GzEncoder::new(Vec::new(), Compression::default()); + e.write_all(b"foo bar baz").unwrap(); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let r = read::GzEncoder::new(&v[..], Compression::default()); + let mut r = read::GzDecoder::new(r); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn flush_after_write() { + let mut f = write::GzEncoder::new(Vec::new(), Compression::default()); + write!(f, "Hello world").unwrap(); + f.flush().unwrap(); + } +} diff --git a/flate2/src/gz/read.rs b/flate2/src/gz/read.rs new file mode 100644 index 000000000..774f4f381 --- /dev/null +++ b/flate2/src/gz/read.rs @@ -0,0 +1,303 @@ +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::bufread; +use super::{GzBuilder, GzHeader}; +use bufreader::BufReader; +use Compression; + +/// A gzip streaming encoder +/// +/// This structure exposes a [`Read`] interface that will read uncompressed data +/// from the underlying reader and expose the compressed version as a [`Read`] +/// interface. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::read::GzEncoder; +/// +/// // Return a vector containing the GZ compressed version of hello world +/// +/// fn gzencode_hello_world() -> io::Result> { +/// let mut ret_vec = [0;100]; +/// let bytestring = b"hello world"; +/// let mut gz = GzEncoder::new(&bytestring[..], Compression::fast()); +/// let count = gz.read(&mut ret_vec)?; +/// Ok(ret_vec[0..count].to_vec()) +/// } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: bufread::GzEncoder>, +} + +pub fn gz_encoder(inner: bufread::GzEncoder>) -> GzEncoder { + GzEncoder { inner: inner } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `GzBuilder` type. + /// + /// The data read from the stream `r` will be compressed and available + /// through the returned reader. + pub fn new(r: R, level: Compression) -> GzEncoder { + GzBuilder::new().read(r, level) + } +} + +impl GzEncoder { + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying reader. + /// + /// Note that mutation of the reader may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Returns the underlying stream, consuming this encoder + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzEncoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +/// A gzip streaming decoder +/// +/// This structure exposes a [`Read`] interface that will consume compressed +/// data from the underlying reader and emit uncompressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::read::GzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = GzDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct GzDecoder { + inner: bufread::GzDecoder>, +} + +impl GzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// gzip header. + pub fn new(r: R) -> GzDecoder { + GzDecoder { + inner: bufread::GzDecoder::new(BufReader::new(r)), + } + } +} + +impl GzDecoder { + /// Returns the header associated with this stream, if it was valid. + pub fn header(&self) -> Option<&GzHeader> { + self.inner.header() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for GzDecoder {} + +impl Write for GzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for GzDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A gzip streaming decoder that decodes all members of a multistream +/// +/// A gzip member consists of a header, compressed data and a trailer. The [gzip +/// specification](https://tools.ietf.org/html/rfc1952), however, allows multiple +/// gzip members to be joined in a single stream. `MultiGzDecoder` will +/// decode all consecutive members while `GzDecoder` will only decompress the +/// first gzip member. The multistream format is commonly used in bioinformatics, +/// for example when using the BGZF compressed data. +/// +/// This structure exposes a [`Read`] interface that will consume all gzip members +/// from the underlying reader and emit uncompressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::read::MultiGzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = MultiGzDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct MultiGzDecoder { + inner: bufread::MultiGzDecoder>, +} + +impl MultiGzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// (first) gzip header. If the gzip stream contains multiple members all will + /// be decoded. + pub fn new(r: R) -> MultiGzDecoder { + MultiGzDecoder { + inner: bufread::MultiGzDecoder::new(BufReader::new(r)), + } + } +} + +impl MultiGzDecoder { + /// Returns the current header associated with this stream, if it's valid. + pub fn header(&self) -> Option<&GzHeader> { + self.inner.header() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for MultiGzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for MultiGzDecoder {} + +impl Write for MultiGzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for MultiGzDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/gz/write.rs b/flate2/src/gz/write.rs new file mode 100644 index 000000000..bc4ba0375 --- /dev/null +++ b/flate2/src/gz/write.rs @@ -0,0 +1,480 @@ +use std::cmp; +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::bufread::{corrupt, read_gz_header}; +use super::{GzBuilder, GzHeader}; +use crc::{Crc, CrcWriter}; +use zio; +use {Compress, Compression, Decompress, Status}; + +/// A gzip streaming encoder +/// +/// This structure exposes a [`Write`] interface that will emit compressed data +/// to the underlying writer `W`. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::GzEncoder; +/// +/// // Vec implements Write to print the compressed bytes of sample string +/// # fn main() { +/// +/// let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// e.write_all(b"Hello World").unwrap(); +/// println!("{:?}", e.finish().unwrap()); +/// # } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: zio::Writer, + crc: Crc, + crc_bytes_written: usize, + header: Vec, +} + +pub fn gz_encoder(header: Vec, w: W, lvl: Compression) -> GzEncoder { + GzEncoder { + inner: zio::Writer::new(w, Compress::new(lvl, false)), + crc: Crc::new(), + header: header, + crc_bytes_written: 0, + } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `GzBuilder` type. + /// + /// The data written to the returned encoder will be compressed and then + /// written to the stream `w`. + pub fn new(w: W, level: Compression) -> GzEncoder { + GzBuilder::new().write(w, level) + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutation of the writer may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.write_header()?; + self.inner.finish()?; + + while self.crc_bytes_written < 8 { + let (sum, amt) = (self.crc.sum() as u32, self.crc.amount()); + let buf = [ + (sum >> 0) as u8, + (sum >> 8) as u8, + (sum >> 16) as u8, + (sum >> 24) as u8, + (amt >> 0) as u8, + (amt >> 8) as u8, + (amt >> 16) as u8, + (amt >> 24) as u8, + ]; + let inner = self.inner.get_mut(); + let n = inner.write(&buf[self.crc_bytes_written..])?; + self.crc_bytes_written += n; + } + Ok(()) + } + + /// Finish encoding this stream, returning the underlying writer once the + /// encoding is done. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.try_finish()?; + Ok(self.inner.take_inner()) + } + + fn write_header(&mut self) -> io::Result<()> { + while self.header.len() > 0 { + let n = self.inner.get_mut().write(&self.header)?; + self.header.drain(..n); + } + Ok(()) + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + assert_eq!(self.crc_bytes_written, 0); + self.write_header()?; + let n = self.inner.write(buf)?; + self.crc.update(&buf[..n]); + Ok(n) + } + + fn flush(&mut self) -> io::Result<()> { + assert_eq!(self.crc_bytes_written, 0); + self.write_header()?; + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for GzEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.try_finish()?; + self.get_mut().shutdown() + } +} + +impl Read for GzEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for GzEncoder {} + +impl Drop for GzEncoder { + fn drop(&mut self) { + if self.inner.is_present() { + let _ = self.try_finish(); + } + } +} + +/// A gzip streaming decoder +/// +/// This structure exposes a [`Write`] interface that will emit compressed data +/// to the underlying writer `W`. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::write::{GzEncoder, GzDecoder}; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # assert_eq!("Hello World", decode_writer(bytes).unwrap()); +/// # } +/// // Uncompresses a gzip encoded vector of bytes and returns a string or error +/// // Here Vec implements Write +/// fn decode_writer(bytes: Vec) -> io::Result { +/// let mut writer = Vec::new(); +/// let mut decoder = GzDecoder::new(writer); +/// decoder.write_all(&bytes[..])?; +/// writer = decoder.finish()?; +/// let return_string = String::from_utf8(writer).expect("String parsing error"); +/// Ok(return_string) +/// } +/// ``` +#[derive(Debug)] +pub struct GzDecoder { + inner: zio::Writer, Decompress>, + crc_bytes: Vec, + header: Option, + header_buf: Vec, +} + +const CRC_BYTES_LEN: usize = 8; + +impl GzDecoder { + /// Creates a new decoder which will write uncompressed data to the stream. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W) -> GzDecoder { + GzDecoder { + inner: zio::Writer::new(CrcWriter::new(w), Decompress::new(false)), + crc_bytes: Vec::with_capacity(CRC_BYTES_LEN), + header: None, + header_buf: Vec::new(), + } + } + + /// Returns the header associated with this stream. + pub fn header(&self) -> Option<&GzHeader> { + self.header.as_ref() + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut().get_mut() + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to finish the stream, returning any + /// errors which happen. + pub fn try_finish(&mut self) -> io::Result<()> { + self.finish_and_check_crc()?; + Ok(()) + } + + /// Consumes this decoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.finish_and_check_crc()?; + Ok(self.inner.take_inner().into_inner()) + } + + fn finish_and_check_crc(&mut self) -> io::Result<()> { + self.inner.finish()?; + + if self.crc_bytes.len() != 8 { + return Err(corrupt()); + } + + let crc = ((self.crc_bytes[0] as u32) << 0) + | ((self.crc_bytes[1] as u32) << 8) + | ((self.crc_bytes[2] as u32) << 16) + | ((self.crc_bytes[3] as u32) << 24); + let amt = ((self.crc_bytes[4] as u32) << 0) + | ((self.crc_bytes[5] as u32) << 8) + | ((self.crc_bytes[6] as u32) << 16) + | ((self.crc_bytes[7] as u32) << 24); + if crc != self.inner.get_ref().crc().sum() as u32 { + return Err(corrupt()); + } + if amt != self.inner.get_ref().crc().amount() { + return Err(corrupt()); + } + Ok(()) + } +} + +struct Counter { + inner: T, + pos: usize, +} + +impl Read for Counter { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let pos = self.inner.read(buf)?; + self.pos += pos; + Ok(pos) + } +} + +impl Write for GzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.header.is_none() { + // trying to avoid buffer usage + let (res, pos) = { + let mut counter = Counter { + inner: self.header_buf.chain(buf), + pos: 0, + }; + let res = read_gz_header(&mut counter); + (res, counter.pos) + }; + + match res { + Err(err) => { + if err.kind() == io::ErrorKind::UnexpectedEof { + // not enough data for header, save to the buffer + self.header_buf.extend(buf); + Ok(buf.len()) + } else { + Err(err) + } + } + Ok(header) => { + self.header = Some(header); + let pos = pos - self.header_buf.len(); + self.header_buf.truncate(0); + Ok(pos) + } + } + } else { + let (n, status) = self.inner.write_with_status(buf)?; + + if status == Status::StreamEnd { + if n < buf.len() && self.crc_bytes.len() < 8 { + let remaining = buf.len() - n; + let crc_bytes = cmp::min(remaining, CRC_BYTES_LEN - self.crc_bytes.len()); + self.crc_bytes.extend(&buf[n..n + crc_bytes]); + return Ok(n + crc_bytes); + } + } + Ok(n) + } + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for GzDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.try_finish()?; + self.inner.get_mut().get_mut().shutdown() + } +} + +impl Read for GzDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for GzDecoder {} + +#[cfg(test)] +mod tests { + use super::*; + + const STR: &'static str = "Hello World Hello World Hello World Hello World Hello World \ + Hello World Hello World Hello World Hello World Hello World \ + Hello World Hello World Hello World Hello World Hello World \ + Hello World Hello World Hello World Hello World Hello World \ + Hello World Hello World Hello World Hello World Hello World"; + + #[test] + fn decode_writer_one_chunk() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write(STR.as_ref()).unwrap(); + let bytes = e.finish().unwrap(); + + let mut writer = Vec::new(); + let mut decoder = GzDecoder::new(writer); + let n = decoder.write(&bytes[..]).unwrap(); + decoder.write(&bytes[n..]).unwrap(); + decoder.try_finish().unwrap(); + writer = decoder.finish().unwrap(); + let return_string = String::from_utf8(writer).expect("String parsing error"); + assert_eq!(return_string, STR); + } + + #[test] + fn decode_writer_partial_header() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write(STR.as_ref()).unwrap(); + let bytes = e.finish().unwrap(); + + let mut writer = Vec::new(); + let mut decoder = GzDecoder::new(writer); + assert_eq!(decoder.write(&bytes[..5]).unwrap(), 5); + let n = decoder.write(&bytes[5..]).unwrap(); + if n < bytes.len() - 5 { + decoder.write(&bytes[n + 5..]).unwrap(); + } + writer = decoder.finish().unwrap(); + let return_string = String::from_utf8(writer).expect("String parsing error"); + assert_eq!(return_string, STR); + } + + #[test] + fn decode_writer_exact_header() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write(STR.as_ref()).unwrap(); + let bytes = e.finish().unwrap(); + + let mut writer = Vec::new(); + let mut decoder = GzDecoder::new(writer); + assert_eq!(decoder.write(&bytes[..10]).unwrap(), 10); + decoder.write(&bytes[10..]).unwrap(); + writer = decoder.finish().unwrap(); + let return_string = String::from_utf8(writer).expect("String parsing error"); + assert_eq!(return_string, STR); + } + + #[test] + fn decode_writer_partial_crc() { + let mut e = GzEncoder::new(Vec::new(), Compression::default()); + e.write(STR.as_ref()).unwrap(); + let bytes = e.finish().unwrap(); + + let mut writer = Vec::new(); + let mut decoder = GzDecoder::new(writer); + let l = bytes.len() - 5; + let n = decoder.write(&bytes[..l]).unwrap(); + decoder.write(&bytes[n..]).unwrap(); + writer = decoder.finish().unwrap(); + let return_string = String::from_utf8(writer).expect("String parsing error"); + assert_eq!(return_string, STR); + } + +} diff --git a/flate2/src/lib.rs b/flate2/src/lib.rs new file mode 100644 index 000000000..33836ed99 --- /dev/null +++ b/flate2/src/lib.rs @@ -0,0 +1,234 @@ +//! A DEFLATE-based stream compression/decompression library +//! +//! This library is meant to supplement/replace the +//! `flate` library that was previously part of the standard rust distribution +//! providing a streaming encoder/decoder rather than purely +//! an in-memory encoder/decoder. +//! +//! Like with [`flate`], flate2 is based on [`miniz.c`][1] +//! +//! [1]: https://github.com/richgel999/miniz +//! [`flate`]: https://github.com/rust-lang/rust/tree/1.19.0/src/libflate +//! +//! # Organization +//! +//! This crate consists mainly of three modules, [`read`], [`write`], and +//! [`bufread`]. Each module contains a number of types used to encode and +//! decode various streams of data. +//! +//! All types in the [`write`] module work on instances of [`Write`][write], +//! whereas all types in the [`read`] module work on instances of +//! [`Read`][read] and [`bufread`] works with [`BufRead`][bufread]. If you +//! are decoding directly from a `&[u8]`, use the [`bufread`] types. +//! +//! ``` +//! use flate2::write::GzEncoder; +//! use flate2::Compression; +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn main() { let _ = run(); } +//! # fn run() -> io::Result<()> { +//! let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); +//! encoder.write_all(b"Example")?; +//! # Ok(()) +//! # } +//! ``` +//! +//! +//! Other various types are provided at the top-level of the crate for +//! management and dealing with encoders/decoders. Also note that types which +//! operate over a specific trait often implement the mirroring trait as well. +//! For example a `flate2::read::DeflateDecoder` *also* implements the +//! `Write` trait if `T: Write`. That is, the "dual trait" is forwarded directly +//! to the underlying object if available. +//! +//! [`read`]: read/index.html +//! [`bufread`]: bufread/index.html +//! [`write`]: write/index.html +//! [read]: https://doc.rust-lang.org/std/io/trait.Read.html +//! [write]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [bufread]: https://doc.rust-lang.org/std/io/trait.BufRead.html +//! +//! # Async I/O +//! +//! This crate optionally can support async I/O streams with the [Tokio stack] via +//! the `tokio` feature of this crate: +//! +//! [Tokio stack]: https://tokio.rs/ +//! +//! ```toml +//! flate2 = { version = "0.2", features = ["tokio"] } +//! ``` +//! +//! All methods are internally capable of working with streams that may return +//! [`ErrorKind::WouldBlock`] when they're not ready to perform the particular +//! operation. +//! +//! [`ErrorKind::WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html +//! +//! Note that care needs to be taken when using these objects, however. The +//! Tokio runtime, in particular, requires that data is fully flushed before +//! dropping streams. For compatibility with blocking streams all streams are +//! flushed/written when they are dropped, and this is not always a suitable +//! time to perform I/O. If I/O streams are flushed before drop, however, then +//! these operations will be a noop. +#![doc(html_root_url = "https://docs.rs/flate2/0.2")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![allow(trivial_numeric_casts)] +#![cfg_attr(test, deny(warnings))] + +extern crate crc32fast; +#[cfg(feature = "tokio")] +extern crate futures; +#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] +extern crate libc; +#[cfg(test)] +extern crate quickcheck; +#[cfg(test)] +extern crate rand; +#[cfg(feature = "tokio")] +extern crate tokio_io; + +// These must currently agree with here -- +// https://github.com/Frommi/miniz_oxide/blob/e6c214efd253491ac072c2c9adba87ef5b4cd5cb/src/lib.rs#L14-L19 +// +// Eventually we'll want to actually move these into `libc` itself for wasm, or +// otherwise not use the capi crate for miniz_oxide but rather use the +// underlying types. +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +mod libc { + #![allow(non_camel_case_types)] + pub type c_ulong = u64; + pub type off_t = i64; + pub type c_int = i32; + pub type c_uint = u32; + pub type size_t = usize; +} + +pub use crc::{Crc, CrcReader, CrcWriter}; +pub use gz::GzBuilder; +pub use gz::GzHeader; +pub use mem::{Compress, CompressError, Decompress, DecompressError, Status}; +pub use mem::{FlushCompress, FlushDecompress}; + +mod bufreader; +mod crc; +mod deflate; +mod ffi; +mod gz; +mod mem; +mod zio; +mod zlib; + +/// Types which operate over [`Read`] streams, both encoders and decoders for +/// various formats. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +pub mod read { + pub use deflate::read::DeflateDecoder; + pub use deflate::read::DeflateEncoder; + pub use gz::read::GzDecoder; + pub use gz::read::GzEncoder; + pub use gz::read::MultiGzDecoder; + pub use zlib::read::ZlibDecoder; + pub use zlib::read::ZlibEncoder; +} + +/// Types which operate over [`Write`] streams, both encoders and decoders for +/// various formats. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +pub mod write { + pub use deflate::write::DeflateDecoder; + pub use deflate::write::DeflateEncoder; + pub use gz::write::GzDecoder; + pub use gz::write::GzEncoder; + pub use zlib::write::ZlibDecoder; + pub use zlib::write::ZlibEncoder; +} + +/// Types which operate over [`BufRead`] streams, both encoders and decoders for +/// various formats. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +pub mod bufread { + pub use deflate::bufread::DeflateDecoder; + pub use deflate::bufread::DeflateEncoder; + pub use gz::bufread::GzDecoder; + pub use gz::bufread::GzEncoder; + pub use gz::bufread::MultiGzDecoder; + pub use zlib::bufread::ZlibDecoder; + pub use zlib::bufread::ZlibEncoder; +} + +fn _assert_send_sync() { + fn _assert_send_sync() {} + + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); +} + +/// When compressing data, the compression level can be specified by a value in +/// this enum. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Compression(u32); + +impl Compression { + /// Creates a new description of the compression level with an explicitly + /// specified integer. + /// + /// The integer here is typically on a scale of 0-9 where 0 means "no + /// compression" and 9 means "take as long as you'd like". + pub fn new(level: u32) -> Compression { + Compression(level) + } + + /// No compression is to be performed, this may actually inflate data + /// slightly when encoding. + pub fn none() -> Compression { + Compression(0) + } + + /// Optimize for the best speed of encoding. + pub fn fast() -> Compression { + Compression(1) + } + + /// Optimize for the size of data being encoded. + pub fn best() -> Compression { + Compression(9) + } + + /// Returns an integer representing the compression level, typically on a + /// scale of 0-9 + pub fn level(&self) -> u32 { + self.0 + } +} + +impl Default for Compression { + fn default() -> Compression { + Compression(6) + } +} + +#[cfg(test)] +fn random_bytes() -> impl Iterator { + use rand::Rng; + use std::iter; + + iter::repeat(()).map(|_| rand::thread_rng().gen()) +} diff --git a/flate2/src/mem.rs b/flate2/src/mem.rs new file mode 100644 index 000000000..497e7c25d --- /dev/null +++ b/flate2/src/mem.rs @@ -0,0 +1,736 @@ +use std::error::Error; +use std::fmt; +use std::io; +use std::marker; +use std::slice; + +use libc::{c_int, c_uint}; + +use ffi; +use Compression; + +/// Raw in-memory compression stream for blocks of data. +/// +/// This type is the building block for the I/O streams in the rest of this +/// crate. It requires more management than the [`Read`]/[`Write`] API but is +/// maximally flexible in terms of accepting input from any source and being +/// able to produce output to any memory location. +/// +/// It is recommended to use the I/O stream adaptors over this type as they're +/// easier to use. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +#[derive(Debug)] +pub struct Compress { + inner: Stream, +} + +/// Raw in-memory decompression stream for blocks of data. +/// +/// This type is the building block for the I/O streams in the rest of this +/// crate. It requires more management than the [`Read`]/[`Write`] API but is +/// maximally flexible in terms of accepting input from any source and being +/// able to produce output to any memory location. +/// +/// It is recommended to use the I/O stream adaptors over this type as they're +/// easier to use. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +#[derive(Debug)] +pub struct Decompress { + inner: Stream, +} + +#[derive(Debug)] +struct Stream { + stream_wrapper: ffi::StreamWrapper, + total_in: u64, + total_out: u64, + _marker: marker::PhantomData, +} + +unsafe impl Send for Stream {} +unsafe impl Sync for Stream {} + +trait Direction { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int; +} + +#[derive(Debug)] +enum DirCompress {} +#[derive(Debug)] +enum DirDecompress {} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +/// Values which indicate the form of flushing to be used when compressing +/// in-memory data. +pub enum FlushCompress { + /// A typical parameter for passing to compression/decompression functions, + /// this indicates that the underlying stream to decide how much data to + /// accumulate before producing output in order to maximize compression. + None = ffi::MZ_NO_FLUSH as isize, + + /// All pending output is flushed to the output buffer and the output is + /// aligned on a byte boundary so that the decompressor can get all input + /// data available so far. + /// + /// Flushing may degrade compression for some compression algorithms and so + /// it should only be used when necessary. This will complete the current + /// deflate block and follow it with an empty stored block. + Sync = ffi::MZ_SYNC_FLUSH as isize, + + /// All pending output is flushed to the output buffer, but the output is + /// not aligned to a byte boundary. + /// + /// All of the input data so far will be available to the decompressor (as + /// with `Flush::Sync`. This completes the current deflate block and follows + /// it with an empty fixed codes block that is 10 bites long, and it assures + /// that enough bytes are output in order for the decompessor to finish the + /// block before the empty fixed code block. + Partial = ffi::MZ_PARTIAL_FLUSH as isize, + + /// All output is flushed as with `Flush::Sync` and the compression state is + /// reset so decompression can restart from this point if previous + /// compressed data has been damaged or if random access is desired. + /// + /// Using this option too often can seriously degrade compression. + Full = ffi::MZ_FULL_FLUSH as isize, + + /// Pending input is processed and pending output is flushed. + /// + /// The return value may indicate that the stream is not yet done and more + /// data has yet to be processed. + Finish = ffi::MZ_FINISH as isize, + + #[doc(hidden)] + _Nonexhaustive, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +/// Values which indicate the form of flushing to be used when +/// decompressing in-memory data. +pub enum FlushDecompress { + /// A typical parameter for passing to compression/decompression functions, + /// this indicates that the underlying stream to decide how much data to + /// accumulate before producing output in order to maximize compression. + None = ffi::MZ_NO_FLUSH as isize, + + /// All pending output is flushed to the output buffer and the output is + /// aligned on a byte boundary so that the decompressor can get all input + /// data available so far. + /// + /// Flushing may degrade compression for some compression algorithms and so + /// it should only be used when necessary. This will complete the current + /// deflate block and follow it with an empty stored block. + Sync = ffi::MZ_SYNC_FLUSH as isize, + + /// Pending input is processed and pending output is flushed. + /// + /// The return value may indicate that the stream is not yet done and more + /// data has yet to be processed. + Finish = ffi::MZ_FINISH as isize, + + #[doc(hidden)] + _Nonexhaustive, +} + +/// The inner state for an error when decompressing +#[derive(Debug, Default)] +struct DecompressErrorInner { + needs_dictionary: Option, +} + +/// Error returned when a decompression object finds that the input stream of +/// bytes was not a valid input stream of bytes. +#[derive(Debug)] +pub struct DecompressError(DecompressErrorInner); + +impl DecompressError { + /// Indicates whether decompression failed due to requiring a dictionary. + /// + /// The resulting integer is the Adler-32 checksum of the dictionary + /// required. + pub fn needs_dictionary(&self) -> Option { + self.0.needs_dictionary + } +} + +/// Error returned when a compression object is used incorrectly or otherwise +/// generates an error. +#[derive(Debug)] +pub struct CompressError(()); + +/// Possible status results of compressing some data or successfully +/// decompressing a block of data. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Status { + /// Indicates success. + /// + /// Means that more input may be needed but isn't available + /// and/or there's more output to be written but the output buffer is full. + Ok, + + /// Indicates that forward progress is not possible due to input or output + /// buffers being empty. + /// + /// For compression it means the input buffer needs some more data or the + /// output buffer needs to be freed up before trying again. + /// + /// For decompression this means that more input is needed to continue or + /// the output buffer isn't large enough to contain the result. The function + /// can be called again after fixing both. + BufError, + + /// Indicates that all input has been consumed and all output bytes have + /// been written. Decompression/compression should not be called again. + /// + /// For decompression with zlib streams the adler-32 of the decompressed + /// data has also been verified. + StreamEnd, +} + +impl Compress { + /// Creates a new object ready for compressing data that it's given. + /// + /// The `level` argument here indicates what level of compression is going + /// to be performed, and the `zlib_header` argument indicates whether the + /// output data should have a zlib header or not. + pub fn new(level: Compression, zlib_header: bool) -> Compress { + unsafe { + let mut state = ffi::StreamWrapper::default(); + let ret = ffi::mz_deflateInit2( + &mut *state, + level.0 as c_int, + ffi::MZ_DEFLATED, + if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }, + 9, + ffi::MZ_DEFAULT_STRATEGY, + ); + debug_assert_eq!(ret, 0); + Compress { + inner: Stream { + stream_wrapper: state, + total_in: 0, + total_out: 0, + _marker: marker::PhantomData, + }, + } + } + } + + /// Returns the total number of input bytes which have been processed by + /// this compression object. + pub fn total_in(&self) -> u64 { + self.inner.total_in + } + + /// Returns the total number of output bytes which have been produced by + /// this compression object. + pub fn total_out(&self) -> u64 { + self.inner.total_out + } + + /// Specifies the compression dictionary to use. + /// + /// Returns the Adler-32 checksum of the dictionary. + #[cfg(feature = "zlib")] + pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result { + let stream = &mut *self.inner.stream_wrapper; + let rc = unsafe { + ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt) + }; + + match rc { + ffi::MZ_STREAM_ERROR => Err(CompressError(())), + ffi::MZ_OK => Ok(stream.adler as u32), + c => panic!("unknown return code: {}", c), + } + } + + /// Quickly resets this compressor without having to reallocate anything. + /// + /// This is equivalent to dropping this object and then creating a new one. + pub fn reset(&mut self) { + let rc = unsafe { ffi::mz_deflateReset(&mut *self.inner.stream_wrapper) }; + assert_eq!(rc, ffi::MZ_OK); + + self.inner.total_in = 0; + self.inner.total_out = 0; + } + + /// Dynamically updates the compression level. + /// + /// This can be used to switch between compression levels for different + /// kinds of data, or it can be used in conjunction with a call to reset + /// to reuse the compressor. + /// + /// This may return an error if there wasn't enough output space to complete + /// the compression of the available input data before changing the + /// compression level. Flushing the stream before calling this method + /// ensures that the function will succeed on the first call. + #[cfg(feature = "zlib")] + pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> { + let stream = &mut *self.inner.stream_wrapper; + + let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) }; + + match rc { + ffi::MZ_OK => Ok(()), + ffi::MZ_BUF_ERROR => Err(CompressError(())), + c => panic!("unknown return code: {}", c), + } + } + + /// Compresses the input data into the output, consuming only as much + /// input as needed and writing as much output as possible. + /// + /// The flush option can be any of the available `FlushCompress` parameters. + /// + /// To learn how much data was consumed or how much output was produced, use + /// the `total_in` and `total_out` functions before/after this is called. + pub fn compress( + &mut self, + input: &[u8], + output: &mut [u8], + flush: FlushCompress, + ) -> Result { + let raw = &mut *self.inner.stream_wrapper; + raw.next_in = input.as_ptr() as *mut _; + raw.avail_in = input.len() as c_uint; + raw.next_out = output.as_mut_ptr(); + raw.avail_out = output.len() as c_uint; + + let rc = unsafe { ffi::mz_deflate(raw, flush as c_int) }; + + // Unfortunately the total counters provided by zlib might be only + // 32 bits wide and overflow while processing large amounts of data. + self.inner.total_in += (raw.next_in as usize - input.as_ptr() as usize) as u64; + self.inner.total_out += (raw.next_out as usize - output.as_ptr() as usize) as u64; + + match rc { + ffi::MZ_OK => Ok(Status::Ok), + ffi::MZ_BUF_ERROR => Ok(Status::BufError), + ffi::MZ_STREAM_END => Ok(Status::StreamEnd), + ffi::MZ_STREAM_ERROR => Err(CompressError(())), + c => panic!("unknown return code: {}", c), + } + } + + /// Compresses the input data into the extra space of the output, consuming + /// only as much input as needed and writing as much output as possible. + /// + /// This function has the same semantics as `compress`, except that the + /// length of `vec` is managed by this function. This will not reallocate + /// the vector provided or attempt to grow it, so space for the output must + /// be reserved in the output vector by the caller before calling this + /// function. + pub fn compress_vec( + &mut self, + input: &[u8], + output: &mut Vec, + flush: FlushCompress, + ) -> Result { + let cap = output.capacity(); + let len = output.len(); + + unsafe { + let before = self.total_out(); + let ret = { + let ptr = output.as_mut_ptr().offset(len as isize); + let out = slice::from_raw_parts_mut(ptr, cap - len); + self.compress(input, out, flush) + }; + output.set_len((self.total_out() - before) as usize + len); + return ret; + } + } +} + +impl Decompress { + /// Creates a new object ready for decompressing data that it's given. + /// + /// The `zlib_header` argument indicates whether the input data is expected + /// to have a zlib header or not. + pub fn new(zlib_header: bool) -> Decompress { + unsafe { + let mut state = ffi::StreamWrapper::default(); + let ret = ffi::mz_inflateInit2( + &mut *state, + if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }, + ); + debug_assert_eq!(ret, 0); + Decompress { + inner: Stream { + stream_wrapper: state, + total_in: 0, + total_out: 0, + _marker: marker::PhantomData, + }, + } + } + } + + /// Returns the total number of input bytes which have been processed by + /// this decompression object. + pub fn total_in(&self) -> u64 { + self.inner.total_in + } + + /// Returns the total number of output bytes which have been produced by + /// this decompression object. + pub fn total_out(&self) -> u64 { + self.inner.total_out + } + + /// Decompresses the input data into the output, consuming only as much + /// input as needed and writing as much output as possible. + /// + /// The flush option can be any of the available `FlushDecompress` parameters. + /// + /// If the first call passes `FlushDecompress::Finish` it is assumed that + /// the input and output buffers are both sized large enough to decompress + /// the entire stream in a single call. + /// + /// A flush value of `FlushDecompress::Finish` indicates that there are no + /// more source bytes available beside what's already in the input buffer, + /// and the output buffer is large enough to hold the rest of the + /// decompressed data. + /// + /// To learn how much data was consumed or how much output was produced, use + /// the `total_in` and `total_out` functions before/after this is called. + /// + /// # Errors + /// + /// If the input data to this instance of `Decompress` is not a valid + /// zlib/deflate stream then this function may return an instance of + /// `DecompressError` to indicate that the stream of input bytes is corrupted. + pub fn decompress( + &mut self, + input: &[u8], + output: &mut [u8], + flush: FlushDecompress, + ) -> Result { + let raw = &mut *self.inner.stream_wrapper; + raw.next_in = input.as_ptr() as *mut u8; + raw.avail_in = input.len() as c_uint; + raw.next_out = output.as_mut_ptr(); + raw.avail_out = output.len() as c_uint; + + let rc = unsafe { ffi::mz_inflate(raw, flush as c_int) }; + + // Unfortunately the total counters provided by zlib might be only + // 32 bits wide and overflow while processing large amounts of data. + self.inner.total_in += (raw.next_in as usize - input.as_ptr() as usize) as u64; + self.inner.total_out += (raw.next_out as usize - output.as_ptr() as usize) as u64; + + match rc { + ffi::MZ_DATA_ERROR | ffi::MZ_STREAM_ERROR => Err(DecompressError(Default::default())), + ffi::MZ_OK => Ok(Status::Ok), + ffi::MZ_BUF_ERROR => Ok(Status::BufError), + ffi::MZ_STREAM_END => Ok(Status::StreamEnd), + ffi::MZ_NEED_DICT => Err(DecompressError(DecompressErrorInner { + needs_dictionary: Some(raw.adler as u32), + })), + c => panic!("unknown return code: {}", c), + } + } + + /// Decompresses the input data into the extra space in the output vector + /// specified by `output`. + /// + /// This function has the same semantics as `decompress`, except that the + /// length of `vec` is managed by this function. This will not reallocate + /// the vector provided or attempt to grow it, so space for the output must + /// be reserved in the output vector by the caller before calling this + /// function. + /// + /// # Errors + /// + /// If the input data to this instance of `Decompress` is not a valid + /// zlib/deflate stream then this function may return an instance of + /// `DecompressError` to indicate that the stream of input bytes is corrupted. + pub fn decompress_vec( + &mut self, + input: &[u8], + output: &mut Vec, + flush: FlushDecompress, + ) -> Result { + let cap = output.capacity(); + let len = output.len(); + + unsafe { + let before = self.total_out(); + let ret = { + let ptr = output.as_mut_ptr().offset(len as isize); + let out = slice::from_raw_parts_mut(ptr, cap - len); + self.decompress(input, out, flush) + }; + output.set_len((self.total_out() - before) as usize + len); + return ret; + } + } + + /// Specifies the decompression dictionary to use. + #[cfg(feature = "zlib")] + pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result { + let stream = &mut *self.inner.stream_wrapper; + let rc = unsafe { + ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt) + }; + + match rc { + ffi::MZ_STREAM_ERROR => Err(DecompressError(Default::default())), + ffi::MZ_DATA_ERROR => Err(DecompressError(DecompressErrorInner { + needs_dictionary: Some(stream.adler as u32), + })), + ffi::MZ_OK => Ok(stream.adler as u32), + c => panic!("unknown return code: {}", c), + } + } + + /// Performs the equivalent of replacing this decompression state with a + /// freshly allocated copy. + /// + /// This function may not allocate memory, though, and attempts to reuse any + /// previously existing resources. + /// + /// The argument provided here indicates whether the reset state will + /// attempt to decode a zlib header first or not. + pub fn reset(&mut self, zlib_header: bool) { + self._reset(zlib_header); + } + + #[cfg(feature = "zlib")] + fn _reset(&mut self, zlib_header: bool) { + let bits = if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }; + unsafe { + ffi::inflateReset2(&mut *self.inner.stream_wrapper, bits); + } + self.inner.total_out = 0; + self.inner.total_in = 0; + } + + #[cfg(not(feature = "zlib"))] + fn _reset(&mut self, zlib_header: bool) { + *self = Decompress::new(zlib_header); + } +} + +impl Error for DecompressError { + fn description(&self) -> &str { + "deflate decompression error" + } +} + +impl From for io::Error { + fn from(data: DecompressError) -> io::Error { + io::Error::new(io::ErrorKind::Other, data) + } +} + +impl fmt::Display for DecompressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for CompressError { + fn description(&self) -> &str { + "deflate compression error" + } +} + +impl From for io::Error { + fn from(data: CompressError) -> io::Error { + io::Error::new(io::ErrorKind::Other, data) + } +} + +impl fmt::Display for CompressError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Direction for DirCompress { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int { + ffi::mz_deflateEnd(stream) + } +} +impl Direction for DirDecompress { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int { + ffi::mz_inflateEnd(stream) + } +} + +impl Drop for Stream { + fn drop(&mut self) { + unsafe { + let _ = D::destroy(&mut *self.stream_wrapper); + } + } +} + +#[cfg(test)] +mod tests { + use std::io::Write; + + use write; + use {Compression, Decompress, FlushDecompress}; + + #[cfg(feature = "zlib")] + use {Compress, FlushCompress}; + + #[test] + fn issue51() { + let data = vec![ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9, + 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c, + 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f, + 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5, + 0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67, + 0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3, + 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54, + 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21, + 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb, + 0xe4, 0xa8, 0x00, 0x00, 0x00, + ]; + + let mut decoded = Vec::with_capacity(data.len() * 2); + + let mut d = Decompress::new(false); + // decompressed whole deflate stream + assert!(d + .decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish) + .is_ok()); + + // decompress data that has nothing to do with the deflate stream (this + // used to panic) + drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None)); + } + + #[test] + fn reset() { + let string = "hello world".as_bytes(); + let mut zlib = Vec::new(); + let mut deflate = Vec::new(); + + let comp = Compression::default(); + write::ZlibEncoder::new(&mut zlib, comp) + .write_all(string) + .unwrap(); + write::DeflateEncoder::new(&mut deflate, comp) + .write_all(string) + .unwrap(); + + let mut dst = [0; 1024]; + let mut decoder = Decompress::new(true); + decoder + .decompress(&zlib, &mut dst, FlushDecompress::Finish) + .unwrap(); + assert_eq!(decoder.total_out(), string.len() as u64); + assert!(dst.starts_with(string)); + + decoder.reset(false); + decoder + .decompress(&deflate, &mut dst, FlushDecompress::Finish) + .unwrap(); + assert_eq!(decoder.total_out(), string.len() as u64); + assert!(dst.starts_with(string)); + } + + #[cfg(feature = "zlib")] + #[test] + fn set_dictionary_with_zlib_header() { + let string = "hello, hello!".as_bytes(); + let dictionary = "hello".as_bytes(); + + let mut encoded = Vec::with_capacity(1024); + + let mut encoder = Compress::new(Compression::default(), true); + + let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap(); + + encoder + .compress_vec(string, &mut encoded, FlushCompress::Finish) + .unwrap(); + + assert_eq!(encoder.total_in(), string.len() as u64); + assert_eq!(encoder.total_out(), encoded.len() as u64); + + let mut decoder = Decompress::new(true); + let mut decoded = [0; 1024]; + let decompress_error = decoder + .decompress(&encoded, &mut decoded, FlushDecompress::Finish) + .expect_err("decompression should fail due to requiring a dictionary"); + + let required_adler = decompress_error.needs_dictionary() + .expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum"); + + assert_eq!(required_adler, dictionary_adler, + "the Adler-32 checksum should match the value when the dictionary was set on the compressor"); + + let actual_adler = decoder.set_dictionary(&dictionary).unwrap(); + + assert_eq!(required_adler, actual_adler); + + // Decompress the rest of the input to the remainder of the output buffer + let total_in = decoder.total_in(); + let total_out = decoder.total_out(); + + let decompress_result = decoder.decompress( + &encoded[total_in as usize..], + &mut decoded[total_out as usize..], + FlushDecompress::Finish, + ); + assert!(decompress_result.is_ok()); + + assert_eq!(&decoded[..decoder.total_out() as usize], string); + } + + #[cfg(feature = "zlib")] + #[test] + fn set_dictionary_raw() { + let string = "hello, hello!".as_bytes(); + let dictionary = "hello".as_bytes(); + + let mut encoded = Vec::with_capacity(1024); + + let mut encoder = Compress::new(Compression::default(), false); + + encoder.set_dictionary(&dictionary).unwrap(); + + encoder + .compress_vec(string, &mut encoded, FlushCompress::Finish) + .unwrap(); + + assert_eq!(encoder.total_in(), string.len() as u64); + assert_eq!(encoder.total_out(), encoded.len() as u64); + + let mut decoder = Decompress::new(false); + + decoder.set_dictionary(&dictionary).unwrap(); + + let mut decoded = [0; 1024]; + let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish); + + assert!(decompress_result.is_ok()); + + assert_eq!(&decoded[..decoder.total_out() as usize], string); + } + +} diff --git a/flate2/src/zio.rs b/flate2/src/zio.rs new file mode 100644 index 000000000..1222a6c3e --- /dev/null +++ b/flate2/src/zio.rs @@ -0,0 +1,290 @@ +use std::io; +use std::io::prelude::*; +use std::mem; + +use {Compress, Decompress, DecompressError, FlushCompress, FlushDecompress, Status}; + +#[derive(Debug)] +pub struct Writer { + obj: Option, + pub data: D, + buf: Vec, +} + +pub trait Ops { + type Flush: Flush; + fn total_in(&self) -> u64; + fn total_out(&self) -> u64; + fn run( + &mut self, + input: &[u8], + output: &mut [u8], + flush: Self::Flush, + ) -> Result; + fn run_vec( + &mut self, + input: &[u8], + output: &mut Vec, + flush: Self::Flush, + ) -> Result; +} + +impl Ops for Compress { + type Flush = FlushCompress; + fn total_in(&self) -> u64 { + self.total_in() + } + fn total_out(&self) -> u64 { + self.total_out() + } + fn run( + &mut self, + input: &[u8], + output: &mut [u8], + flush: FlushCompress, + ) -> Result { + Ok(self.compress(input, output, flush).unwrap()) + } + fn run_vec( + &mut self, + input: &[u8], + output: &mut Vec, + flush: FlushCompress, + ) -> Result { + Ok(self.compress_vec(input, output, flush).unwrap()) + } +} + +impl Ops for Decompress { + type Flush = FlushDecompress; + fn total_in(&self) -> u64 { + self.total_in() + } + fn total_out(&self) -> u64 { + self.total_out() + } + fn run( + &mut self, + input: &[u8], + output: &mut [u8], + flush: FlushDecompress, + ) -> Result { + self.decompress(input, output, flush) + } + fn run_vec( + &mut self, + input: &[u8], + output: &mut Vec, + flush: FlushDecompress, + ) -> Result { + self.decompress_vec(input, output, flush) + } +} + +pub trait Flush { + fn none() -> Self; + fn sync() -> Self; + fn finish() -> Self; +} + +impl Flush for FlushCompress { + fn none() -> Self { + FlushCompress::None + } + + fn sync() -> Self { + FlushCompress::Sync + } + + fn finish() -> Self { + FlushCompress::Finish + } +} + +impl Flush for FlushDecompress { + fn none() -> Self { + FlushDecompress::None + } + + fn sync() -> Self { + FlushDecompress::Sync + } + + fn finish() -> Self { + FlushDecompress::Finish + } +} + +pub fn read(obj: &mut R, data: &mut D, dst: &mut [u8]) -> io::Result +where + R: BufRead, + D: Ops, +{ + loop { + let (read, consumed, ret, eof); + { + let input = obj.fill_buf()?; + eof = input.is_empty(); + let before_out = data.total_out(); + let before_in = data.total_in(); + let flush = if eof { + D::Flush::finish() + } else { + D::Flush::none() + }; + ret = data.run(input, dst, flush); + read = (data.total_out() - before_out) as usize; + consumed = (data.total_in() - before_in) as usize; + } + obj.consume(consumed); + + match ret { + // If we haven't ready any data and we haven't hit EOF yet, + // then we need to keep asking for more data because if we + // return that 0 bytes of data have been read then it will + // be interpreted as EOF. + Ok(Status::Ok) | Ok(Status::BufError) if read == 0 && !eof && dst.len() > 0 => continue, + Ok(Status::Ok) | Ok(Status::BufError) | Ok(Status::StreamEnd) => return Ok(read), + + Err(..) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "corrupt deflate stream", + )) + } + } + } +} + +impl Writer { + pub fn new(w: W, d: D) -> Writer { + Writer { + obj: Some(w), + data: d, + buf: Vec::with_capacity(32 * 1024), + } + } + + pub fn finish(&mut self) -> io::Result<()> { + loop { + self.dump()?; + + let before = self.data.total_out(); + self.data.run_vec(&[], &mut self.buf, D::Flush::finish())?; + if before == self.data.total_out() { + return Ok(()); + } + } + } + + pub fn replace(&mut self, w: W) -> W { + self.buf.truncate(0); + mem::replace(self.get_mut(), w) + } + + pub fn get_ref(&self) -> &W { + self.obj.as_ref().unwrap() + } + + pub fn get_mut(&mut self) -> &mut W { + self.obj.as_mut().unwrap() + } + + // Note that this should only be called if the outer object is just about + // to be consumed! + // + // (e.g. an implementation of `into_inner`) + pub fn take_inner(&mut self) -> W { + self.obj.take().unwrap() + } + + pub fn is_present(&self) -> bool { + self.obj.is_some() + } + + // Returns total written bytes and status of underlying codec + pub(crate) fn write_with_status(&mut self, buf: &[u8]) -> io::Result<(usize, Status)> { + // miniz isn't guaranteed to actually write any of the buffer provided, + // it may be in a flushing mode where it's just giving us data before + // we're actually giving it any data. We don't want to spuriously return + // `Ok(0)` when possible as it will cause calls to write_all() to fail. + // As a result we execute this in a loop to ensure that we try our + // darndest to write the data. + loop { + self.dump()?; + + let before_in = self.data.total_in(); + let ret = self.data.run_vec(buf, &mut self.buf, D::Flush::none()); + let written = (self.data.total_in() - before_in) as usize; + + let is_stream_end = match ret { + Ok(Status::StreamEnd) => true, + _ => false, + }; + + if buf.len() > 0 && written == 0 && ret.is_ok() && !is_stream_end { + continue; + } + return match ret { + Ok(st) => match st { + Status::Ok | Status::BufError | Status::StreamEnd => Ok((written, st)), + }, + Err(..) => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "corrupt deflate stream", + )), + }; + } + } + + fn dump(&mut self) -> io::Result<()> { + // TODO: should manage this buffer not with `drain` but probably more of + // a deque-like strategy. + while self.buf.len() > 0 { + let n = try!(self.obj.as_mut().unwrap().write(&self.buf)); + if n == 0 { + return Err(io::ErrorKind::WriteZero.into()); + } + self.buf.drain(..n); + } + Ok(()) + } +} + +impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_with_status(buf).map(|res| res.0) + } + + fn flush(&mut self) -> io::Result<()> { + self.data + .run_vec(&[], &mut self.buf, D::Flush::sync()) + .unwrap(); + + // Unfortunately miniz doesn't actually tell us when we're done with + // pulling out all the data from the internal stream. To remedy this we + // have to continually ask the stream for more memory until it doesn't + // give us a chunk of memory the same size as our own internal buffer, + // at which point we assume it's reached the end. + loop { + self.dump()?; + let before = self.data.total_out(); + self.data + .run_vec(&[], &mut self.buf, D::Flush::none()) + .unwrap(); + if before == self.data.total_out() { + break; + } + } + + self.obj.as_mut().unwrap().flush() + } +} + +impl Drop for Writer { + fn drop(&mut self) { + if self.obj.is_some() { + let _ = self.finish(); + } + } +} diff --git a/flate2/src/zlib/bufread.rs b/flate2/src/zlib/bufread.rs new file mode 100644 index 000000000..39bd4bf5e --- /dev/null +++ b/flate2/src/zlib/bufread.rs @@ -0,0 +1,258 @@ +use std::io; +use std::io::prelude::*; +use std::mem; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`BufRead`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::bufread::ZlibEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// // Use a buffered file to compress contents into a Vec +/// +/// # fn open_hello_world() -> std::io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut z = ZlibEncoder::new(b, Compression::fast()); +/// let mut buffer = Vec::new(); +/// z.read_to_end(&mut buffer)?; +/// # Ok(buffer) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + obj: R, + data: Compress, +} + +impl ZlibEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + obj: r, + data: Compress::new(level, true), + } + } +} + +pub fn reset_encoder_data(zlib: &mut ZlibEncoder) { + zlib.data.reset() +} + +impl ZlibEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_encoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this encoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`BufRead`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::bufread::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_bufreader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_bufreader(bytes: Vec) -> io::Result { +/// let mut z = ZlibDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// z.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + obj: R, + data: Decompress, +} + +impl ZlibDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> ZlibDecoder { + ZlibDecoder { + obj: r, + data: Decompress::new(true), + } + } +} + +pub fn reset_decoder_data(zlib: &mut ZlibDecoder) { + zlib.data = Decompress::new(true); +} + +impl ZlibDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_decoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/zlib/mod.rs b/flate2/src/zlib/mod.rs new file mode 100644 index 000000000..93faf4235 --- /dev/null +++ b/flate2/src/zlib/mod.rs @@ -0,0 +1,159 @@ +pub mod bufread; +pub mod read; +pub mod write; + +#[cfg(test)] +mod tests { + use std::io; + use std::io::prelude::*; + + use rand::{thread_rng, Rng}; + + use zlib::{read, write}; + use Compression; + + #[test] + fn roundtrip() { + let mut real = Vec::new(); + let mut w = write::ZlibEncoder::new(Vec::new(), Compression::default()); + let v = ::random_bytes().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::ZlibDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + } + + #[test] + fn drop_writes() { + let mut data = Vec::new(); + write::ZlibEncoder::new(&mut data, Compression::default()) + .write_all(b"foo") + .unwrap(); + let mut r = read::ZlibDecoder::new(&data[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == b"foo"); + } + + #[test] + fn total_in() { + let mut real = Vec::new(); + let mut w = write::ZlibEncoder::new(Vec::new(), Compression::default()); + let v = ::random_bytes().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let mut result = w.finish().unwrap(); + + let result_len = result.len(); + + for _ in 0..200 { + result.extend(v.iter().map(|x| *x)); + } + + let mut r = read::ZlibDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + assert_eq!(r.total_in(), result_len as u64); + } + + #[test] + fn roundtrip2() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut r = read::ZlibDecoder::new(read::ZlibEncoder::new(&v[..], Compression::default())); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert_eq!(ret, v); + } + + #[test] + fn roundtrip3() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut w = + write::ZlibEncoder::new(write::ZlibDecoder::new(Vec::new()), Compression::default()); + w.write_all(&v).unwrap(); + let w = w.finish().unwrap().finish().unwrap(); + assert!(w == v); + } + + #[test] + fn reset_decoder() { + let v = ::random_bytes().take(1024 * 1024).collect::>(); + let mut w = write::ZlibEncoder::new(Vec::new(), Compression::default()); + w.write_all(&v).unwrap(); + let data = w.finish().unwrap(); + + { + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::ZlibDecoder::new(&data[..]); + r.read_to_end(&mut a).unwrap(); + r.reset(&data); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::ZlibDecoder::new(&data[..]); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c && c == v); + } + + { + let mut w = write::ZlibDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&data).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::ZlibDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c && c == v); + } + } + + #[test] + fn bad_input() { + // regress tests: previously caused a panic on drop + let mut out: Vec = Vec::new(); + let data: Vec = (0..255).cycle().take(1024).collect(); + let mut w = write::ZlibDecoder::new(&mut out); + match w.write_all(&data[..]) { + Ok(_) => panic!("Expected an error to be returned!"), + Err(e) => assert_eq!(e.kind(), io::ErrorKind::InvalidInput), + } + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut r = + read::ZlibDecoder::new(read::ZlibEncoder::new(&v[..], Compression::default())); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn qc_writer() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut w = write::ZlibEncoder::new( + write::ZlibDecoder::new(Vec::new()), + Compression::default(), + ); + w.write_all(&v).unwrap(); + v == w.finish().unwrap().finish().unwrap() + } + } +} diff --git a/flate2/src/zlib/read.rs b/flate2/src/zlib/read.rs new file mode 100644 index 000000000..c9d846c57 --- /dev/null +++ b/flate2/src/zlib/read.rs @@ -0,0 +1,265 @@ +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::bufread; +use bufreader::BufReader; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`Read`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::read::ZlibEncoder; +/// use std::fs::File; +/// +/// // Open example file and compress the contents using Read interface +/// +/// # fn open_hello_world() -> std::io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let mut z = ZlibEncoder::new(f, Compression::fast()); +/// let mut buffer = [0;50]; +/// let byte_count = z.read(&mut buffer)?; +/// # Ok(buffer[0..byte_count].to_vec()) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + inner: bufread::ZlibEncoder>, +} + +impl ZlibEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + inner: bufread::ZlibEncoder::new(BufReader::new(r), level), + } + } +} + +impl ZlibEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_encoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this encoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`Read`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::read::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut z = ZlibDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// z.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + inner: bufread::ZlibDecoder>, +} + +impl ZlibDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> ZlibDecoder { + ZlibDecoder::new_with_buf(r, vec![0; 32 * 1024]) + } + + /// Same as `new`, but the intermediate buffer for data is specified. + /// + /// Note that the specified buffer will only be used up to its current + /// length. The buffer's capacity will also not grow over time. + pub fn new_with_buf(r: R, buf: Vec) -> ZlibDecoder { + ZlibDecoder { + inner: bufread::ZlibDecoder::new(BufReader::with_buf(buf, r)), + } + } +} + +impl ZlibDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_decoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2/src/zlib/write.rs b/flate2/src/zlib/write.rs new file mode 100644 index 000000000..3512c2c7d --- /dev/null +++ b/flate2/src/zlib/write.rs @@ -0,0 +1,348 @@ +use std::io; +use std::io::prelude::*; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`Write`] interface and takes a stream of +/// uncompressed data, writing the compressed data to the wrapped writer. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::ZlibEncoder; +/// +/// // Vec implements Write, assigning the compressed bytes of sample string +/// +/// # fn zlib_encoding() -> std::io::Result<()> { +/// let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); +/// e.write_all(b"Hello World")?; +/// let compressed = e.finish()?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + inner: zio::Writer, +} + +impl ZlibEncoder { + /// Creates a new encoder which will write compressed data to the stream + /// given at the given compression level. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + inner: zio::Writer::new(w, Compress::new(level, true)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this encoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. + /// + /// After the current stream has been finished, this will reset the internal + /// state of this encoder and replace the output stream with the one + /// provided, returning the previous output stream. Future data written to + /// this encoder will be the compressed into the stream `w` provided. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + self.inner.finish()?; + self.inner.data.reset(); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream, close off the compressed + /// stream and, if successful, return the contained writer. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.inner.finish()?; + Ok(self.inner.take_inner()) + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// The compressed stream will not closed but only flushed. This + /// means that obtained byte array can by extended by another deflated + /// stream. To close the stream add the two bytes 0x3 and 0x0. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn flush_finish(mut self) -> io::Result { + self.inner.flush()?; + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that have been written to this compresor. + /// + /// Note that not all bytes written to this object may be accounted for, + /// there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been written yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.try_finish()?; + self.get_mut().shutdown() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`Write`] and will emit a stream of decompressed +/// data when fed a stream of compressed data. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::write::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); +/// # e.write_all(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here Vec implements Write +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut writer = Vec::new(); +/// let mut z = ZlibDecoder::new(writer); +/// z.write_all(&bytes[..])?; +/// writer = z.finish()?; +/// let return_string = String::from_utf8(writer).expect("String parsing error"); +/// Ok(return_string) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + inner: zio::Writer, +} + +impl ZlibDecoder { + /// Creates a new decoder which will write uncompressed data to the stream. + /// + /// When this decoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W) -> ZlibDecoder { + ZlibDecoder { + inner: zio::Writer::new(w, Decompress::new(true)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this decoder entirely, swapping out the output + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// output stream with the one provided, returning the previous output + /// stream. Future data written to this decoder will be decompressed into + /// the output stream `w`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + self.inner.finish()?; + self.inner.data = Decompress::new(true); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + self.inner.finish()?; + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that the decompressor has consumed for + /// decompression. + /// + /// Note that this will likely be smaller than the number of bytes + /// successfully written to this stream due to internal buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the decompressor has written to its + /// output stream. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.inner.finish()?; + self.inner.get_mut().shutdown() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} diff --git a/flate2/tests/async-reader.rs b/flate2/tests/async-reader.rs new file mode 100644 index 000000000..b95e4a19b --- /dev/null +++ b/flate2/tests/async-reader.rs @@ -0,0 +1,94 @@ +extern crate flate2; +extern crate tokio_io; +extern crate futures; + +use flate2::read::{GzDecoder, MultiGzDecoder}; +use std::cmp; +use std::fs::File; +use std::io::{self, Read}; +use tokio_io::AsyncRead; +use tokio_io::io::read_to_end; +use futures::prelude::*; +use futures::task; + + +struct BadReader { + reader: T, + x: bool +} + +impl BadReader { + fn new(reader: T) -> BadReader { + BadReader { reader, x: true } + } +} + +impl Read for BadReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.x { + self.x = false; + let len = cmp::min(buf.len(), 1); + self.reader.read(&mut buf[..len]) + } else { + self.x = true; + Err(io::ErrorKind::WouldBlock.into()) + } + } +} + +struct AssertAsync(T); + +impl Read for AssertAsync { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } +} + +impl AsyncRead for AssertAsync {} + +struct AlwaysNotify(T); + +impl Future for AlwaysNotify { + type Item = T::Item; + type Error = T::Error; + + fn poll(&mut self) -> Poll { + let ret = self.0.poll(); + if let Ok(Async::NotReady) = &ret { + task::current().notify(); + } + ret + } +} + +#[test] +fn test_gz_asyncread() { + let f = File::open("tests/good-file.gz").unwrap(); + + let fut = read_to_end(AssertAsync(GzDecoder::new(BadReader::new(f))), Vec::new()); + let (_, content) = AlwaysNotify(fut).wait().unwrap(); + + let mut expected = Vec::new(); + File::open("tests/good-file.txt") + .unwrap() + .read_to_end(&mut expected) + .unwrap(); + + assert_eq!(content, expected); +} + +#[test] +fn test_multi_gz_asyncread() { + let f = File::open("tests/multi.gz").unwrap(); + + let fut = read_to_end(AssertAsync(MultiGzDecoder::new(BadReader::new(f))), Vec::new()); + let (_, content) = AlwaysNotify(fut).wait().unwrap(); + + let mut expected = Vec::new(); + File::open("tests/multi.txt") + .unwrap() + .read_to_end(&mut expected) + .unwrap(); + + assert_eq!(content, expected); +} diff --git a/flate2/tests/corrupt-file.gz b/flate2/tests/corrupt-file.gz new file mode 100644 index 0000000000000000000000000000000000000000..159333b032751969263eeb152e7e94782ab2cd39 GIT binary patch literal 7128 zcmeH}3`T8Bd^E~*{sR93UWTs`tIH^whgwc1l%>Czl5mp~aWyj6i8WXLt$movJ+e~8!|2g5T~UafXuTIJu# zoS~3m6PA$4Q;uFDI8m7>q+XZ&N^Gjzdn>6v%OFv?Go}67YjH_mY)Uz#0=%;*6Dqa? z?t{I-75TdNvQ}L~-ONn8cU`PXs{TyB{yv!8>iJf!Mw89_!sc@KR`fbp5@X0!>iZ}E zYU7oHq?2~Nqnbz5>o@hi;+AB%A0ZXE_WY~7dEqw&4lqG@d->r>wd4=; z_frA~ie+z1GGz$%NHbFmqzZ;Zze*!6^g;4%q)jqg+Pi9@i+61o#ucZn*BT|$yF=?n zI(#41LL^L85hEST#S{Ul8y5^~C_dtxGu%Vf%`QdZ1+nISvfpcr5x%!uN!98-In?; z3fFx^x(n8gMKWrpOZArTc=w&9$UJ!Y0p|Nj7B<3J2=mswps}|MMm&;^SQEYYn5xD!=rxs7sS`MxHsb6xrd7*UOdwC zan!!BbV|cCVea9d$fT_s^Zg&A|HtV6az^bG`rbnOYI*L7wz+)T)WX#YfJ93Jj5fl& zS0bt*EfBpC7)nF13u-+2opxJ zmoG1tJWIpk1HB&#KMXZrn329jVpn`EB~2e|6Nc?ymZ-pjzQU6Fx|7jFWYleZ@8s)! z7K$HI5y>px!wb)u6~hrYar4SjhrDM^;^t4#2QygOu~w2a zJR7mAb!$X;S_vCs!AwmB+|5PvS(igNfgT(oYb~V4E0S0xf7U9UjrMt0 z%+}w!%GY%tt?CUA&@(&Y+TPCMW5Z2DglRF}sgkg0cI@edoUkuPmzIy=_Xvv_qvKi`y5Us;0F?Br zGFciYoHX26hX2)0;V}h&W4f@hyo8>z()gpJtp^|RMn|m|@fnH9ZGgnACk%3N=>_J) z6nZx|pL4>qEeRgKmO+(Yh-~TeJ*4%1gogF|u7EoJJ5k z9abxxtAP}LUe`ddQGx_NJ7suR@}1HdsW{B=i$RRXBZ`&Prw(iegqQbUy6?ZyD%)x$ zQax!hmr0f|W=FafQP{Pz0>E3X-!kk`BlEx86iHDSWk_nAiHpRH&DEC;cGR&h>-Tcf z?VYuDYYCbkt>kt-Hd@hNYB%b}-`L)ljeetz(ZRb& zvVUcpY(xMGf6@G%mQ|E^B@}A33uh}r>8%cmyDcY&3`MiCN`o z*nz~wRPFAf9NVoa` zMUCVE$tLl!(Py!({W$r}&{IdAEI-1I1Duqrs<$SZ(=L?_(%VNrU0%Hu;if+CU|_VD z&4`;IZ|3v~36GK2Ze|^6TXcEYtTGBP2zebNKO~v_0+;=%U*-7%>GA}4CLmZ^1Dj>R zcDGz2d3g)}Y84ubi-8gLTDt$Fp-GojwmHuLlGHC4Z=uar6jHlNzW|V`hGqLSA8&yK zj}{>ZRBZbXU;eEUN@k#5ESk3=9-T(ZRk_^U@9CCa6QegMF+kI`3MX@z36@39ET(8| zaCntuc*d3l+T6G#RyM%HI2~$QoBh-rl~v}=g&gXOv+qvDaZFfcqT>MfkRK`z?N#2c zPnXN(&0K05QDOAk97_rWL@}&`$bXV+rl?ZHw@{x0P$F4rMImDlV!Mc2fk#8SfzSwD0G;ShnlK?Ei-PTybHhVDw=-qP&3!7Jcd1*ws`YANBfnu$!J@G)) z%l;wHSObFhxB(hSlN*Aq#U)p_>TLtPtbUN8(`Q3|)t@=Pf|>d&SK;dVc4KW`z%>lh z1D6f`dNgWW|O1iRD_&F;;S|n_|+d$TH3pxmfwsY7*fG)I_&$#jK72o)^3$V z<%X5(^fw$Wm58T5<4U(8-=smD3Y6D5(QL&@g&P3SpOYq}>Cu5ystYC6zciA1W6`U0 zqaR38UH1q6DCN`GX$BgE!}x(HM-ry*i(k#Tg}h$eH`0`k<qq${E>m!BjEW zTl=KdJ&a`eI&Ds3^&UpYe`GnAd@FF7vU8c^!~_->k-#;9@9kZ zbhBxQ#s3d0ACFaE$t~pu7bn29;^L7?#6iB{J65VS*7@>#HS(Oq1S=Qr!HjC)vrU3s zdADdKB(}#TVl~C(g(~uxcrKC{7o0xOdvGK8{YOs|8=x&D`m+#ulC5&DU(+PqRqS-} z!ByF14mlMEbds>!glW4Q6$lb9i&s(fK$~Ax-C0v9&&KjhaMBSPnz71IAnl0>XRFPt z)zx4?q3)2_b8d?28haZ54wLg70B;TJ^xWN;-KEd76#&|vB?8kS4K6-cDO+!tYmTbl z_B=_GW{tX;$+*Ln#{BL-1NjBT0=Q(F6~>O$&K!nGCCV@tG_NoNzrb^PK%MBZv@}PS zvrZJPcXhVx6f2!DEfuH^R8IqlsPohoC%unUFMQ!GR85Ax?#cseqDNy}6-L3>KwcS* ze57)@uOhaH0&n@>=SrYombbDxSWGBz^UoP*Vp?4S1`6UZ_8mmYyc@}76j@^vo$pm0 zb*bZI^ogAE+v5NTJHMoBD#-iJ5yhA`Yw^>bx)`PU>Lf%v`+f`dAoN-FC+-!`ysW~t z`^c?gB{N_BDd6Vy&vvS*U3Zgg4;hgT+!2)%Hip6SX7BydSJ%}E$^G5u=yX!Gji;H| zir)rN)h++kVmlvpAON;tdoS)Myur}@gFv2vOz7y{q~%QbL+VIype{pkAsG$rL6@nv zUGvT9a>qYuAMSe}y?hs|!LKnO(zfF`EPXS*7NJNJ1rAK?kjgSvN&{`0I7x1f^@KN& zVT}ez)@)!?ZucD1gYpaBG;=oNmjJGJ&X764I>u+iEesH-zW#0r)EzrBlYrqIo3|dD z_?(E5SQ@Y%!<%A zTw67eF_U;Ye5iWun6BtXDi-3Aw-fO@2F&TS_Rpl9_Y*Ciikp9Vs~&UYHHbPz0;#Iy zK?=Wh!l}FySFiSaKVP{MuYt3fWY{pSxru!2Pf~1GZq(6g!=3B4p&6%kdTS^- z)(?Na{IMI(QOze5IW;#?`W_?qQ!L5$Ijik*`_uAC%x=a`0Wld11rt#b^2~ zhrY-ycsx*m4!vM4!=fU-Y%o9)KY>W*=t9*oOL4JZcP;7IPN zv+_PYO>Z7|7ew}4SdjXd?=+iM;WdkKjXYDbsKLIugwQT-&X&h%mS8uPE@r4XOK@O& zYZJlIdPzXcS-to0=ury*F+n~4RY$$hG96B?Y?{q$#O)$61Sl-U7^!inPi>o`Uh8Qm zy{}Kb2@VP$EKc2{D;~jKxFYt3FcrH**2dXiCY7WxfiL56#CW_ zfDjntb2K%%(Hcmj!|h<%L3G~NGXHbi&3~&c&*lYu^KCgYaYQgwJ77$f9+OW5*h)-x ziUknR!aIHf#4j8kbB=|?8WkRdw$AuwS`IKImREzK-w6z_qR71rQP@4i8r*x@3eN#E1?i7+pm1^ud3V*FKH**wPf8@W}cz z)~~Wk=M6n<(Wex?6MX+!f__J&A^IsWWa7(|%^2q*U8(A52|B7LP;=LBbtY)$K2<;R zj#USgu~n+t<_n6EKbdRIr7O2e?X=*zyf;HO#nb06JBQCAXcN%1t%(@eO~z z*;cm$Q5FIe3>~(cL=}=VFM_|E%M5qH3E~eqIH)41%{KBJS&1J+$#6*EDC%tEl8=_@ zvWzM;r@|qWw@8TF+8cT!1qGYsKB);p@>}0Bf^PWBUo}sjJyJFbL=fQikll@tYWX~Q z@rAE*X3RFRuAGjv4SBMb{QbQL3W0kl`Z7Rsv4SwdBoRfs6rCjEb+@T%kE_;yV%WU< zo#P#vSv`y8Aq z8*X>ztqX);Ffmt z1o*B~%hjB%bU!?lGB1HH$CN*84aM~6c_p<6s9k0OQr{OGd zNxyZQ;+_QjCnb)vrVH`~K78Is3|rG!ph)gStC>K;Ovn=<8y*llPUG$f*eVgv(v$Bt z7IM4M@(MEf0dyN#r14C)Bj_QC2wrE@Jsq;Mu3Nl+(cUD4W|YJ6T>O*DxP?9OWF^(#!Ob+-EC%bHeisX2K`|~;B>p^I`r`OuxmZ975&80 zCceZo?YLoWvISWZxi+?-Z9t0yOE>XWCQiv&rS~+B{m`bnh+lf0QX-A;G9fM}7azE` zE?ZG4+h6uqY~+@UtVX6&gH2Ijjni`{7M*X6_Nl3~5=&YSbR6 zzvmcFD6N56{3LOdxg^7~LgRg>l;*9)xAX)$eF|?QXs-*Zf#yBBOWLOS8z;vR+shu9 zB<_qLG-h~9$SJ>06J63(zL$o~A z>zAX+)N;!t6r>WV1>9VUI!kd}O}aRC{_&u8-6x?gQ9Byw>+ajtvEr_w8>_g_G>0P> zvZVUggA}WZ-vxU0Z3dTlywC>OYIGU52PTQW6Ose!BvVvZ#;ND;tKI$XtK~!TA zm71(3{tX|x(k-M;7Fvx|$7pnXABLlO+~u3EbNrvTb1Ur1iE^7!l;2R3*5bFl#Ta^| zDF*$OifQakLq7ilRUJ$F%q=J+>MtQLw0~i&6FD#sT+!uo>)lELS>@!ypZd{t(wK$R zJPrI-*wVk$NZ3x+w%Jx9!os{o`zLxHj+m2)kJ>yODHD|71ifL%i1+_N)!d>_wYgnr z5DSbfK%m6t0w1!qZ+q_sslBpIlrK3PunDEhPaVDkR@)$%Lc`!M$Su}6Qql`Trp*C(~rdCId~1;;f?28aCcFVxBT|gpd(4CR{1^lVJ_WQ{|8`uM_fH)`BKH)i18)lVjMZnVD?|)u`HlQ2u z?zne}#@nT0El~fAqS=k)omrtV6OP;i-!qAjk%i(7rIW4N*RY8 zv+xu4N?D*qbsf!;Xwm4M+B`Lm^a;m5sWmk3_%-fny>M0>_XBHsWFV@=DE03P#J@dd zwSL^YEsSYfdm4ZsG32i~xf|45QD+Ux;unIol(f_clHUyj_?mwW;yZ@#H4 zXz$K1RyzXfoN%mvSxnP~5&Un)(iEb0$=-51EI@PXxj_vzflSsEv0ht#qA@VZ_sy!# zdsY734fuyd-f}zGudC7xMIh< zKhwwdw7E%xNskh~(&rw7t9Cx=jm)bLWa-#h>l?qz>SOWM?A#_+SsAbOx>TQ{Fm;BH zlN$10+O(#c9J2e0Y&`bcmKVP)?N+w}WE)0rJTWB3`Og1*P+g&%b$83cWWK;mOq|5E z_WtaiPks#ille$Zx!BBe`$TnqebIq@;n4Ej1lcY&=iQ0$EZ|k-81`{+l~7BQP(@qQ#Bg-$mdb)J>nF% zUOVO}tdb1;#3-iVIp-209%K|l@ugP=n~cE^OFTlrTOa0KqWa4`d&as3Vrtha{xDjW LalHo10|5UIqgUPt literal 0 HcmV?d00001 diff --git a/flate2/tests/early-flush.rs b/flate2/tests/early-flush.rs new file mode 100644 index 000000000..e717adaa5 --- /dev/null +++ b/flate2/tests/early-flush.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use std::io::{Read, Write}; + +use flate2::read::GzDecoder; +use flate2::write::GzEncoder; + +#[test] +fn smoke() { + let mut w = GzEncoder::new(Vec::new(), flate2::Compression::default()); + w.flush().unwrap(); + w.write_all(b"hello").unwrap(); + + let bytes = w.finish().unwrap(); + + let mut r = GzDecoder::new(&bytes[..]); + let mut s = String::new(); + r.read_to_string(&mut s).unwrap(); + assert_eq!(s, "hello"); +} diff --git a/flate2/tests/empty-read.rs b/flate2/tests/empty-read.rs new file mode 100644 index 000000000..755123833 --- /dev/null +++ b/flate2/tests/empty-read.rs @@ -0,0 +1,82 @@ +extern crate flate2; + +use std::io::{Read, Write}; + +#[test] +fn deflate_decoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = + flate2::write::DeflateEncoder::new(Vec::new(), flate2::Compression::default()); + encoder.write_all(original).unwrap(); + let encoded: Vec = encoder.finish().unwrap(); + let mut decoder = flate2::read::DeflateDecoder::new(encoded.as_slice()); + assert_eq!(decoder.read(&mut []).unwrap(), 0); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} + +#[test] +fn deflate_encoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = flate2::read::DeflateEncoder::new(original, flate2::Compression::default()); + assert_eq!(encoder.read(&mut []).unwrap(), 0); + let mut encoded = Vec::new(); + encoder.read_to_end(&mut encoded).unwrap(); + let mut decoder = flate2::read::DeflateDecoder::new(encoded.as_slice()); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} + +#[test] +fn gzip_decoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default()); + encoder.write_all(original).unwrap(); + let encoded: Vec = encoder.finish().unwrap(); + let mut decoder = flate2::read::GzDecoder::new(encoded.as_slice()); + assert_eq!(decoder.read(&mut []).unwrap(), 0); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} + +#[test] +fn gzip_encoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = flate2::read::GzEncoder::new(original, flate2::Compression::default()); + assert_eq!(encoder.read(&mut []).unwrap(), 0); + let mut encoded = Vec::new(); + encoder.read_to_end(&mut encoded).unwrap(); + let mut decoder = flate2::read::GzDecoder::new(encoded.as_slice()); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} + +#[test] +fn zlib_decoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default()); + encoder.write_all(original).unwrap(); + let encoded: Vec = encoder.finish().unwrap(); + let mut decoder = flate2::read::ZlibDecoder::new(encoded.as_slice()); + assert_eq!(decoder.read(&mut []).unwrap(), 0); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} + +#[test] +fn zlib_encoder_empty_read() { + let original: &[u8] = b"Lorem ipsum dolor sit amet."; + let mut encoder = flate2::read::ZlibEncoder::new(original, flate2::Compression::default()); + assert_eq!(encoder.read(&mut []).unwrap(), 0); + let mut encoded = Vec::new(); + encoder.read_to_end(&mut encoded).unwrap(); + let mut decoder = flate2::read::ZlibDecoder::new(encoded.as_slice()); + let mut decoded = Vec::new(); + decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(decoded.as_slice(), original); +} diff --git a/flate2/tests/good-file.gz b/flate2/tests/good-file.gz new file mode 100644 index 0000000000000000000000000000000000000000..f968689cce01efba445a1d33eb4a21aabf551981 GIT binary patch literal 6766 zcmV-!8j4BrBZ80f#~(j`{PFzy`#=8t>(`(E{Q2we|MR%S-so-X+CFp76$KCKQf!GXY>F2 zD7LX!-%n+!rR~wD@zCr~WwE8M?%wpBUG!87Q!T|XS<_Q2xD>Z;T}vLL+EaVj%xht?Phd?WN4ohCb7(_4d@2#?goIcInlhx?iJLZM1G5 z^J(Qi8ArT|KdpW?9dlhe?WeVCTzmc0ID}^RlT)9sKDKVCzs6}gVO@#tpp9$X+G8E2 z18aVbUi_!(AA0g^NS~TI+S*%fPdgjhzN^bzID8*cO6xo zx;mTTqqCLC8rph{<+tiuDI4I%L_VhS*YimrGY07zf z9D4QbT^7aD)APhvuS0j&w$<{CJn>#O5xB}&&&VUMdlO-prgYke6?>XI%H`4K&cNJ>&HrnOxD##XsYQLme(Z+gAEB zZaCD{aDBPk<2M|1DY|rhV?2K2q3)&YnhMLu&xZ6wBOcszhn^b}J}rSk9XgH2b3by? zBJhx7O}(7k(PApL&Mmp8Pmb2Z>lKJT6Hs&m`1j-&Vk`1ti!kWIDo=3Qx<;NdZDYnZ zsQM9n5<0s9Q3xHJ zQs2A*QKn8?S6r58?v04G46hLMiAu`Z(;h<5aKsHIwgbo>A831Gw1ddjbe^>hNUQV{ z0JFm|I@l@Wxge2g14;$KwRpmE34)L-v!sM7mk$EDf?3&;vBh@aGL)^0P6q?_6bZVr z8l)`@Sc~O(t1{I9P#qwf(@DsbDBHs45f(C8K=BZG>aMhKnR=M|273h9I+fsTy%=zW z3XsVY`8&Qe%VH5p52M22iduxjItaZ1+Q~z48S+7efoyy0Tgla?YghpJmb2F6YGI0) z35?cJ9Hw4Eb^TYx2Qum~wGga78gIj*(0PKnSIE6e)&mPAG+EShPR zm#ar*#X7OVv#)mvQ~0qaVwd%GuVE{MN=4CFxz^cHDvcwuH)MeJMRYWtePd>f5{Nyv zuEy+IxAv>};6&|>8euH4Fso!yhM;lZww_On)0usr&*i|JqWYd1N&R}x|K@Fj0(j&6Pjs~=g39k)8moqNBR&VN> zg3)!|-Pm7`7)Vanae?N-3oR~4UF+t41c8gE!qr3)x&|Ep4iltaB{)PWz%k-;C&r_E zz%iM|5#kPt@kyCNic5$Nw8w5bqagJPV8G~;XirLCgT14r7jO2TqoxHA3J(EqO+p6{ zwd^(r5tV!{hvh~jfY7YtP@qAm2psJy>0I&MU;qb<>tS=LYUu@>mOwsiE~JpiMpxtX zhs~ST&E7g5aL8P{^UWFbg4nhf%y&o@T{PC~SPCJ~yyFA@;<5Z>01*Ki$Li`n6fVHJ~#^16Xg+NO9pl zi|@{}H|H4fDXFA7`>WAJua4lr(`If>KWe&W1tHEb{X_>*q^lwi$!(1(-qdpqVy^SO zDq=_;C=UtV7v^YrpuFR{$^7!OAqW++O0U#I{UVm?A;`7Dl@2H2ifl(1*5H1mJv7ud zkrv!9)B&F4)=TSHiOh~D<`8+2Ef_q_eT{f=h6$NMc2!u#$`?aS3jSF{NOwI`@KWQV zck;>xX0--s(;BP~`^ewK5}l{wDjXpv{1#y7V@df6DlMPIU`pvS#g}0E0KO03FX_c# z4d*lt-wV@I>o-W^@I9DbP*KXZWK8F(xH!=_^s%#~w*92Q2Fi8)0nczzaWi!$wHDfvC>2H*7pmTF14XR&Ll#goYe@ zVLf3pcd4OyTru9tei3~Jhm!=f`lg09z)?|)R!~oNxH@|T7nOmYti33>KzSwovROj9 z5^*wB{a4vCLFD8jTnyVtNS|Ccd8!U7^LDw4^gf^-w%E>AG_q_QU$zvK_8}6_q_7MZ|JB)0iel1T;&GZ zXv=JIy5l~$cT4hD=BBI=5bpeBtlx16l#OUwww0j1_`!${$)IBQYXpphRAA%>>FB~TFDU6wZrw=T$YB0(6Ak< z*Y1`>fE%}F88E1VmE4repX<>Ci@K(Z`AY_&bYX@?k}V(iwR8UX!?9Hy+zzv zKD%B_A0beLNHXTmjLH}QzNM?%$?nI3-(~Cs=y>l6ttqq=cD79L<$R6h*NBA_16s~9 zV12~9DF#N1_#iZ8OP6z^NLW>$7E(a}aSc+2O{9hrkPpXiipu%T1m{hGLfi#V?lPN1g z0;ysl)U}`FeIZ3xU~-;3mqJDW*AefIHy+N{m8?+e@-rFti|PUOx;MGUVf+Tz1gaCf zhwv+Qve!;|^yB-4YArz@ou5di3Z~fNa_0xiVpatY!8xyYDMJC&ji0)ZoKR8Zu(IB` z8D3MS^X!cq=g1Z2Mpf^|jfWVRsO+|G;LI8!A}W=&UQj0#264CA3+ZEoNEcPM_2!mx zZYqt4@3#62=_4vB%Kx7BCjXKkL=4G#%j{o%xT#%Q_|H0JFl$jb!8cNXyqdPs1@ zZSS}4GPx?lRrXQ*2G1J#U<>+Jmy0kT9+h)T>X#bbP`ob09!uiaVN-yV z7f3c)(taNj&}bd<087@_;}cJuLr7=I`C7Y<7eJ?Ynv9Q_3Y8A_+2MQPzLn4+g%2Jr zDS=6(31M8uBV&Y3;jc({J7f=EdC2t2Z|@h8o#E9aTph?y*uQZTeXRp=PPsfBbl?dSrU(keh*MZCUaZL{y!sXg6 z*pJCBVfQ8Lej#1p2Iv*7_O00O9k~;{s&$>3eG~%lTxDr8wu9(O83RY-eLLYX`61y0 z51zX!QBi3qQ_DI4m6;iZ?M~S|fo+N=0r|l>y+XiI=dvw+BVA7ZLY<}1r3oFN7^ifk zm9V^!0rX{}B1uAQmcYC>gyF)^$3g}e)hG~s;2a?Ww5x$vHrU=m0_a731w@}tR+%g_GsW1++%_cEeT= zqytn4b#aRw%I^@8JakdvvBUU+(vd+(d*LPgy|Z?zQ|0|z?b|FwA) z(0=_(AXOuc;k#dUIVZY@GK=+#$+!WzY}2oeFLWrF)Ezf7zU)%61DqOii1B5Yi-L5N z|80Ds(=B^NSkK<3_%5#3I-1<7XKYUL5*-HZ}DHNTp+V9 zL`yi;f9liW%nf2W)d1=REDN%h(NB0#InfYR>oB4>I>mAQu)Z>2r=7kjTJ=NvVsUD_LiNtC_(An< ziRyHA59e2Iydito?nn89dbb31eDq5%bsXZI)`{HJX#Mxo}iZUP;N}Uh9(+6vn)an!K(P>%%#z76L zpZdS_BTBv?vl5`B6#%3CI#Pbv!qufL>`akg^F3%WC-w4#Y|OsmIJ{?!^K0 zGqw_adMd&)rR>kHrLbFH3I!lYpJ4icIeRwm%h=JPM2Gbxe+9*&GBO!(IqmzN<01j+ zJ$b)JKQZbotSn<)%f^)^a;+!lD}GSWqA8h@@GBDzf#^iRp?lX>=x&A%>4)t_Pf#Ys z7oM~i(Kq>~s8NePTrYV^{ZsBb7(;lwFG^oYSZPo`{dVz3u@23=CG%A781#X;DfKo9s zn+ilceV*IOCan%#o6Smqa{3Zo((ta-0ytO9vn)(01q2tQ1C=UU&j!B^eMKn;q|6S# z*Jw9uCE7^{0cn%Sd33v&0-HsjG!R@@_w!j^BtX;oGYT*& z5g!78`a{+Yl^pae^^X;Jw~+}wOa0=!l-n#dnco?sX@I(88wu+2_l<39mnYR1_HU+J zv^Ux23+kI>bRz)!p?s>rDB>m2^Yp{`R9}d3U##X3KGheCIWC;}H@=VIm6#sr`?r!G z^~nmf?5`vfwHG{jfAv1Pj>Ht!3&`eCd@(%ccKa399x}Z!pmXC!{@w$kwAK9^*D$~m zK=#%Do$?QOFF)K2gK^Wb6yqJ?PBS5N25YUmdfE;N6DAqkA%K??~rxi7I zY&~I}`bdEKNHL%jjc!#mMaNMC68k%<>;k8ejsGGzL*#GnDI5Q^GH8_MlB1KUTiCfb z=Ij!jm1Nh`niwO;5T~QwH$9>eLO`Y!@&>OA6~L_HUNM=-d!hOzq@$z`zKtyOOH4%l zMVoy_R{BenFqnPO`6Ty8Yr4jqi&me^Z$`ZgP;aa?rOc$GZc;M(+F|{rnygh1>-mu=dkun`I`J&a{27punmq@o% z)_0g;#z2iTP%}>bUv3mmCryO$3?A0O2t8WHARPmpVWc5uO@C162db>BmyeJvD}sDwJ;s?8fJJ#RCuEF)B1HnUwo>zppkqG7Y<2Upfbk;goepGC#RdjcPeQpUkgRXE8#+tg>v$ zkfM^2vovz0eWpZbj5>M@%pT5nvO0GE599oJ&PwzxZ7{X zU-(M7LA=bf^ICfp4&?M+ZrGG;s!Uy@m;G5ADJP{WzfFK%f>@M+=*MmoV2vorNc%qi z_5c`=?J>{DlV_aQM*y`nCm%ht`f-d*5lU!yeFu7_qEPDcR2k1*Idgs5kpjuH6hMWF z)|i3@TVflN%`1i%wV|U1Zn>J4KDfgi*!i{51ZfX4RM$^^gLMaEUR6$wPt7 zO6G$aX?=MJ0VRel`yHYT4;dg+l=bQiQ>cFT9pj9Hq300&G3z&#V?Umi{!ycEuJGX7 zM~E$_Nvd??@#K9uz7GrOu3g)ihnqE!U+P}A)G`nr~JGKvJcIDQ-c)@e95=As|J z9e=D9jmURz$KU#hF)%7(emnlCs2TI4SZ~yL3#Hz;tK0Dx{6*R-7?<@%jmLL= zKq+>i)9Dl%{4@Y)A(1!_rd<8h|D_|Nw#dYxj3>Qh3X#PKH>f|vJ9N&xmOkGusz9`OQi`~$iCmD%JQcoG6z$Yx?k3)Q% zA##`!RVDuzSt{>6I;G019v}N)dUQ$|{B_TQOt_>V9ZQP-PP|CVnvOL1pE&{UpT9JD zJRAOk6#!4{rmrXUuMV~%qJgl}@u%O~qlCijz9*zd$toe;ll7%R(D;+dSogz@7JtN` zJd$61$46(>>`}RX_}=*gk(g#At`6PXh}2N2IDa7Usu&NSxA@`1^#b?eQA*|S2Hsx3 z6bvNY5@v3*U%$YFJ=HW>uZk&@l_f$pzjcFVEs#$M2wzyAwMMZ}$8nqeO4>q$H1Pa3 z`(^c^s*Vf%QW+IJJKDKc%eT154YHuFCSG3S8Y}?{D<^lD^c&TK1;mK1 io::Result> { + let mut v = Vec::new(); + let f = File::open(path_compressed)?; + GzDecoder::new(f).read_to_end(&mut v)?; + Ok(v) +} + +// Tries to extract path into memory (decompressing all members in case +// of a multi member .gz file). +fn extract_file_multi(path_compressed: &Path) -> io::Result> { + let mut v = Vec::new(); + let f = File::open(path_compressed)?; + MultiGzDecoder::new(f).read_to_end(&mut v)?; + Ok(v) +} + +#[test] +fn empty_error_once() { + let data: &[u8] = &[]; + let cbjson = GzDecoder::new(data); + let reader = BufReader::new(cbjson); + let mut stream = reader.lines(); + assert!(stream.next().unwrap().is_err()); + assert!(stream.next().is_none()); +} diff --git a/flate2/tests/multi.gz b/flate2/tests/multi.gz new file mode 100644 index 0000000000000000000000000000000000000000..cabc89630fe00d6a611e16fdad958ecfd479cd8d GIT binary patch literal 53 zcmb2|=3qED)ij)e+55DPmfk}q2CdCr$JrPd803L6C%`h=e!l0()) + .collect::>(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let v2 = v.clone(); + let t = thread::spawn(move || { + let a = listener.accept().unwrap().0; + let b = a.try_clone().unwrap(); + + let mut v3 = v2.clone(); + let t = thread::spawn(move || { + let mut b = read::DeflateDecoder::new(b); + let mut buf = [0; 1024]; + while v3.len() > 0 { + let n = b.read(&mut buf).unwrap(); + for (actual, expected) in buf[..n].iter().zip(&v3) { + assert_eq!(*actual, *expected); + } + v3.drain(..n); + } + + assert_eq!(b.read(&mut buf).unwrap(), 0); + }); + + let mut a = write::ZlibEncoder::new(a, Compression::default()); + a.write_all(&v2).unwrap(); + a.finish().unwrap().shutdown(Shutdown::Write).unwrap(); + + t.join().unwrap(); + }); + + let stream = TcpStream::connect(&addr); + let copy = stream + .and_then(|s| { + let (a, b) = s.split(); + let a = read::ZlibDecoder::new(a); + let b = write::DeflateEncoder::new(b, Compression::default()); + copy(a, b) + }) + .then(move |result| { + let (amt, _a, b) = result.unwrap(); + assert_eq!(amt, v.len() as u64); + shutdown(b).map(|_| ()) + }) + .map_err(|err| panic!("{}", err)); + + let threadpool = tokio_threadpool::Builder::new().build(); + threadpool.spawn(copy); + threadpool.shutdown().wait().unwrap(); + t.join().unwrap(); +} diff --git a/flate2/tests/zero-write.rs b/flate2/tests/zero-write.rs new file mode 100644 index 000000000..f0db86cb8 --- /dev/null +++ b/flate2/tests/zero-write.rs @@ -0,0 +1,8 @@ +extern crate flate2; + +#[test] +fn zero_write_is_error() { + let mut buf = [0u8]; + let writer = flate2::write::DeflateEncoder::new(&mut buf[..], flate2::Compression::default()); + assert!(writer.finish().is_err()); +} diff --git a/fnv/.cargo-checksum.json b/fnv/.cargo-checksum.json new file mode 100644 index 000000000..19ad74848 --- /dev/null +++ b/fnv/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"} \ No newline at end of file diff --git a/fnv/Cargo.toml b/fnv/Cargo.toml new file mode 100644 index 000000000..115779985 --- /dev/null +++ b/fnv/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fnv" +version = "1.0.6" +authors = ["Alex Crichton "] +description = "Fowler–Noll–Vo hash function" +documentation = "https://doc.servo.org/fnv/" +readme = "README.md" +license = "Apache-2.0 / MIT" +repository = "https://github.com/servo/rust-fnv" + +[lib] +name = "fnv" +path = "lib.rs" diff --git a/fnv/LICENSE-APACHE b/fnv/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/fnv/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/fnv/LICENSE-MIT b/fnv/LICENSE-MIT new file mode 100644 index 000000000..bc976a272 --- /dev/null +++ b/fnv/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/fnv/README.md b/fnv/README.md new file mode 100644 index 000000000..6a4c4aeeb --- /dev/null +++ b/fnv/README.md @@ -0,0 +1,81 @@ +# rust-fnv + +An implementation of the [Fowler–Noll–Vo hash function][chongo]. + +### [Read the documentation](https://doc.servo.org/fnv/) + + +## About + +The FNV hash function is a custom `Hasher` implementation that is more +efficient for smaller hash keys. + +[The Rust FAQ states that][faq] while the default `Hasher` implementation, +SipHash, is good in many cases, it is notably slower than other algorithms +with short keys, such as when you have a map of integers to other values. +In cases like these, [FNV is demonstrably faster][graphs]. + +Its disadvantages are that it performs badly on larger inputs, and +provides no protection against collision attacks, where a malicious user +can craft specific keys designed to slow a hasher down. Thus, it is +important to profile your program to ensure that you are using small hash +keys, and be certain that your program could not be exposed to malicious +inputs (including being a networked server). + +The Rust compiler itself uses FNV, as it is not worried about +denial-of-service attacks, and can assume that its inputs are going to be +small—a perfect use case for FNV. + + +## Usage + +To include this crate in your program, add the following to your `Cargo.toml`: + +```toml +[dependencies] +fnv = "1.0.3" +``` + + +## Using FNV in a HashMap + +The `FnvHashMap` type alias is the easiest way to use the standard library’s +`HashMap` with FNV. + +```rust +use fnv::FnvHashMap; + +let mut map = FnvHashMap::default(); +map.insert(1, "one"); +map.insert(2, "two"); + +map = FnvHashMap::with_capacity_and_hasher(10, Default::default()); +map.insert(1, "one"); +map.insert(2, "two"); +``` + +Note, the standard library’s `HashMap::new` and `HashMap::with_capacity` +are only implemented for the `RandomState` hasher, so using `Default` to +get the hasher is the next best option. + + +## Using FNV in a HashSet + +Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet` +with FNV. + +```rust +use fnv::FnvHashSet; + +let mut set = FnvHashSet::default(); +set.insert(1); +set.insert(2); + +set = FnvHashSet::with_capacity_and_hasher(10, Default::default()); +set.insert(1); +set.insert(2); +``` + +[chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html +[faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow +[graphs]: http://cglab.ca/~abeinges/blah/hash-rs/ diff --git a/fnv/lib.rs b/fnv/lib.rs new file mode 100644 index 000000000..eaf3d44a3 --- /dev/null +++ b/fnv/lib.rs @@ -0,0 +1,349 @@ +//! An implementation of the [Fowler–Noll–Vo hash function][chongo]. +//! +//! ## About +//! +//! The FNV hash function is a custom `Hasher` implementation that is more +//! efficient for smaller hash keys. +//! +//! [The Rust FAQ states that][faq] while the default `Hasher` implementation, +//! SipHash, is good in many cases, it is notably slower than other algorithms +//! with short keys, such as when you have a map of integers to other values. +//! In cases like these, [FNV is demonstrably faster][graphs]. +//! +//! Its disadvantages are that it performs badly on larger inputs, and +//! provides no protection against collision attacks, where a malicious user +//! can craft specific keys designed to slow a hasher down. Thus, it is +//! important to profile your program to ensure that you are using small hash +//! keys, and be certain that your program could not be exposed to malicious +//! inputs (including being a networked server). +//! +//! The Rust compiler itself uses FNV, as it is not worried about +//! denial-of-service attacks, and can assume that its inputs are going to be +//! small—a perfect use case for FNV. +//! +//! +//! ## Using FNV in a `HashMap` +//! +//! The `FnvHashMap` type alias is the easiest way to use the standard library’s +//! `HashMap` with FNV. +//! +//! ```rust +//! use fnv::FnvHashMap; +//! +//! let mut map = FnvHashMap::default(); +//! map.insert(1, "one"); +//! map.insert(2, "two"); +//! +//! map = FnvHashMap::with_capacity_and_hasher(10, Default::default()); +//! map.insert(1, "one"); +//! map.insert(2, "two"); +//! ``` +//! +//! Note, the standard library’s `HashMap::new` and `HashMap::with_capacity` +//! are only implemented for the `RandomState` hasher, so using `Default` to +//! get the hasher is the next best option. +//! +//! ## Using FNV in a `HashSet` +//! +//! Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet` +//! with FNV. +//! +//! ```rust +//! use fnv::FnvHashSet; +//! +//! let mut set = FnvHashSet::default(); +//! set.insert(1); +//! set.insert(2); +//! +//! set = FnvHashSet::with_capacity_and_hasher(10, Default::default()); +//! set.insert(1); +//! set.insert(2); +//! ``` +//! +//! [chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html +//! [faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow +//! [graphs]: http://cglab.ca/~abeinges/blah/hash-rs/ + + +use std::default::Default; +use std::hash::{Hasher, BuildHasherDefault}; +use std::collections::{HashMap, HashSet}; + +/// An implementation of the Fowler–Noll–Vo hash function. +/// +/// See the [crate documentation](index.html) for more details. +#[allow(missing_copy_implementations)] +pub struct FnvHasher(u64); + +impl Default for FnvHasher { + + #[inline] + fn default() -> FnvHasher { + FnvHasher(0xcbf29ce484222325) + } +} + +impl FnvHasher { + /// Create an FNV hasher starting with a state corresponding + /// to the hash `key`. + #[inline] + pub fn with_key(key: u64) -> FnvHasher { + FnvHasher(key) + } +} + +impl Hasher for FnvHasher { + #[inline] + fn finish(&self) -> u64 { + self.0 + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + let FnvHasher(mut hash) = *self; + + for byte in bytes.iter() { + hash = hash ^ (*byte as u64); + hash = hash.wrapping_mul(0x100000001b3); + } + + *self = FnvHasher(hash); + } +} + +/// A builder for default FNV hashers. +pub type FnvBuildHasher = BuildHasherDefault; + +/// A `HashMap` using a default FNV hasher. +pub type FnvHashMap = HashMap; + +/// A `HashSet` using a default FNV hasher. +pub type FnvHashSet = HashSet; + + +#[cfg(test)] +mod test { + use super::*; + use std::hash::Hasher; + + fn fnv1a(bytes: &[u8]) -> u64 { + let mut hasher = FnvHasher::default(); + hasher.write(bytes); + hasher.finish() + } + + fn repeat_10(bytes: &[u8]) -> Vec { + (0..10).flat_map(|_| bytes.iter().cloned()).collect() + } + + fn repeat_500(bytes: &[u8]) -> Vec { + (0..500).flat_map(|_| bytes.iter().cloned()).collect() + } + + #[test] + fn basic_tests() { + assert_eq!(fnv1a(b""), 0xcbf29ce484222325); + assert_eq!(fnv1a(b"a"), 0xaf63dc4c8601ec8c); + assert_eq!(fnv1a(b"b"), 0xaf63df4c8601f1a5); + assert_eq!(fnv1a(b"c"), 0xaf63de4c8601eff2); + assert_eq!(fnv1a(b"d"), 0xaf63d94c8601e773); + assert_eq!(fnv1a(b"e"), 0xaf63d84c8601e5c0); + assert_eq!(fnv1a(b"f"), 0xaf63db4c8601ead9); + assert_eq!(fnv1a(b"fo"), 0x08985907b541d342); + assert_eq!(fnv1a(b"foo"), 0xdcb27518fed9d577); + assert_eq!(fnv1a(b"foob"), 0xdd120e790c2512af); + assert_eq!(fnv1a(b"fooba"), 0xcac165afa2fef40a); + assert_eq!(fnv1a(b"foobar"), 0x85944171f73967e8); + assert_eq!(fnv1a(b"\0"), 0xaf63bd4c8601b7df); + assert_eq!(fnv1a(b"a\0"), 0x089be207b544f1e4); + assert_eq!(fnv1a(b"b\0"), 0x08a61407b54d9b5f); + assert_eq!(fnv1a(b"c\0"), 0x08a2ae07b54ab836); + assert_eq!(fnv1a(b"d\0"), 0x0891b007b53c4869); + assert_eq!(fnv1a(b"e\0"), 0x088e4a07b5396540); + assert_eq!(fnv1a(b"f\0"), 0x08987c07b5420ebb); + assert_eq!(fnv1a(b"fo\0"), 0xdcb28a18fed9f926); + assert_eq!(fnv1a(b"foo\0"), 0xdd1270790c25b935); + assert_eq!(fnv1a(b"foob\0"), 0xcac146afa2febf5d); + assert_eq!(fnv1a(b"fooba\0"), 0x8593d371f738acfe); + assert_eq!(fnv1a(b"foobar\0"), 0x34531ca7168b8f38); + assert_eq!(fnv1a(b"ch"), 0x08a25607b54a22ae); + assert_eq!(fnv1a(b"cho"), 0xf5faf0190cf90df3); + assert_eq!(fnv1a(b"chon"), 0xf27397910b3221c7); + assert_eq!(fnv1a(b"chong"), 0x2c8c2b76062f22e0); + assert_eq!(fnv1a(b"chongo"), 0xe150688c8217b8fd); + assert_eq!(fnv1a(b"chongo "), 0xf35a83c10e4f1f87); + assert_eq!(fnv1a(b"chongo w"), 0xd1edd10b507344d0); + assert_eq!(fnv1a(b"chongo wa"), 0x2a5ee739b3ddb8c3); + assert_eq!(fnv1a(b"chongo was"), 0xdcfb970ca1c0d310); + assert_eq!(fnv1a(b"chongo was "), 0x4054da76daa6da90); + assert_eq!(fnv1a(b"chongo was h"), 0xf70a2ff589861368); + assert_eq!(fnv1a(b"chongo was he"), 0x4c628b38aed25f17); + assert_eq!(fnv1a(b"chongo was her"), 0x9dd1f6510f78189f); + assert_eq!(fnv1a(b"chongo was here"), 0xa3de85bd491270ce); + assert_eq!(fnv1a(b"chongo was here!"), 0x858e2fa32a55e61d); + assert_eq!(fnv1a(b"chongo was here!\n"), 0x46810940eff5f915); + assert_eq!(fnv1a(b"ch\0"), 0xf5fadd190cf8edaa); + assert_eq!(fnv1a(b"cho\0"), 0xf273ed910b32b3e9); + assert_eq!(fnv1a(b"chon\0"), 0x2c8c5276062f6525); + assert_eq!(fnv1a(b"chong\0"), 0xe150b98c821842a0); + assert_eq!(fnv1a(b"chongo\0"), 0xf35aa3c10e4f55e7); + assert_eq!(fnv1a(b"chongo \0"), 0xd1ed680b50729265); + assert_eq!(fnv1a(b"chongo w\0"), 0x2a5f0639b3dded70); + assert_eq!(fnv1a(b"chongo wa\0"), 0xdcfbaa0ca1c0f359); + assert_eq!(fnv1a(b"chongo was\0"), 0x4054ba76daa6a430); + assert_eq!(fnv1a(b"chongo was \0"), 0xf709c7f5898562b0); + assert_eq!(fnv1a(b"chongo was h\0"), 0x4c62e638aed2f9b8); + assert_eq!(fnv1a(b"chongo was he\0"), 0x9dd1a8510f779415); + assert_eq!(fnv1a(b"chongo was her\0"), 0xa3de2abd4911d62d); + assert_eq!(fnv1a(b"chongo was here\0"), 0x858e0ea32a55ae0a); + assert_eq!(fnv1a(b"chongo was here!\0"), 0x46810f40eff60347); + assert_eq!(fnv1a(b"chongo was here!\n\0"), 0xc33bce57bef63eaf); + assert_eq!(fnv1a(b"cu"), 0x08a24307b54a0265); + assert_eq!(fnv1a(b"cur"), 0xf5b9fd190cc18d15); + assert_eq!(fnv1a(b"curd"), 0x4c968290ace35703); + assert_eq!(fnv1a(b"curds"), 0x07174bd5c64d9350); + assert_eq!(fnv1a(b"curds "), 0x5a294c3ff5d18750); + assert_eq!(fnv1a(b"curds a"), 0x05b3c1aeb308b843); + assert_eq!(fnv1a(b"curds an"), 0xb92a48da37d0f477); + assert_eq!(fnv1a(b"curds and"), 0x73cdddccd80ebc49); + assert_eq!(fnv1a(b"curds and "), 0xd58c4c13210a266b); + assert_eq!(fnv1a(b"curds and w"), 0xe78b6081243ec194); + assert_eq!(fnv1a(b"curds and wh"), 0xb096f77096a39f34); + assert_eq!(fnv1a(b"curds and whe"), 0xb425c54ff807b6a3); + assert_eq!(fnv1a(b"curds and whey"), 0x23e520e2751bb46e); + assert_eq!(fnv1a(b"curds and whey\n"), 0x1a0b44ccfe1385ec); + assert_eq!(fnv1a(b"cu\0"), 0xf5ba4b190cc2119f); + assert_eq!(fnv1a(b"cur\0"), 0x4c962690ace2baaf); + assert_eq!(fnv1a(b"curd\0"), 0x0716ded5c64cda19); + assert_eq!(fnv1a(b"curds\0"), 0x5a292c3ff5d150f0); + assert_eq!(fnv1a(b"curds \0"), 0x05b3e0aeb308ecf0); + assert_eq!(fnv1a(b"curds a\0"), 0xb92a5eda37d119d9); + assert_eq!(fnv1a(b"curds an\0"), 0x73ce41ccd80f6635); + assert_eq!(fnv1a(b"curds and\0"), 0xd58c2c132109f00b); + assert_eq!(fnv1a(b"curds and \0"), 0xe78baf81243f47d1); + assert_eq!(fnv1a(b"curds and w\0"), 0xb0968f7096a2ee7c); + assert_eq!(fnv1a(b"curds and wh\0"), 0xb425a84ff807855c); + assert_eq!(fnv1a(b"curds and whe\0"), 0x23e4e9e2751b56f9); + assert_eq!(fnv1a(b"curds and whey\0"), 0x1a0b4eccfe1396ea); + assert_eq!(fnv1a(b"curds and whey\n\0"), 0x54abd453bb2c9004); + assert_eq!(fnv1a(b"hi"), 0x08ba5f07b55ec3da); + assert_eq!(fnv1a(b"hi\0"), 0x337354193006cb6e); + assert_eq!(fnv1a(b"hello"), 0xa430d84680aabd0b); + assert_eq!(fnv1a(b"hello\0"), 0xa9bc8acca21f39b1); + assert_eq!(fnv1a(b"\xff\x00\x00\x01"), 0x6961196491cc682d); + assert_eq!(fnv1a(b"\x01\x00\x00\xff"), 0xad2bb1774799dfe9); + assert_eq!(fnv1a(b"\xff\x00\x00\x02"), 0x6961166491cc6314); + assert_eq!(fnv1a(b"\x02\x00\x00\xff"), 0x8d1bb3904a3b1236); + assert_eq!(fnv1a(b"\xff\x00\x00\x03"), 0x6961176491cc64c7); + assert_eq!(fnv1a(b"\x03\x00\x00\xff"), 0xed205d87f40434c7); + assert_eq!(fnv1a(b"\xff\x00\x00\x04"), 0x6961146491cc5fae); + assert_eq!(fnv1a(b"\x04\x00\x00\xff"), 0xcd3baf5e44f8ad9c); + assert_eq!(fnv1a(b"\x40\x51\x4e\x44"), 0xe3b36596127cd6d8); + assert_eq!(fnv1a(b"\x44\x4e\x51\x40"), 0xf77f1072c8e8a646); + assert_eq!(fnv1a(b"\x40\x51\x4e\x4a"), 0xe3b36396127cd372); + assert_eq!(fnv1a(b"\x4a\x4e\x51\x40"), 0x6067dce9932ad458); + assert_eq!(fnv1a(b"\x40\x51\x4e\x54"), 0xe3b37596127cf208); + assert_eq!(fnv1a(b"\x54\x4e\x51\x40"), 0x4b7b10fa9fe83936); + assert_eq!(fnv1a(b"127.0.0.1"), 0xaabafe7104d914be); + assert_eq!(fnv1a(b"127.0.0.1\0"), 0xf4d3180b3cde3eda); + assert_eq!(fnv1a(b"127.0.0.2"), 0xaabafd7104d9130b); + assert_eq!(fnv1a(b"127.0.0.2\0"), 0xf4cfb20b3cdb5bb1); + assert_eq!(fnv1a(b"127.0.0.3"), 0xaabafc7104d91158); + assert_eq!(fnv1a(b"127.0.0.3\0"), 0xf4cc4c0b3cd87888); + assert_eq!(fnv1a(b"64.81.78.68"), 0xe729bac5d2a8d3a7); + assert_eq!(fnv1a(b"64.81.78.68\0"), 0x74bc0524f4dfa4c5); + assert_eq!(fnv1a(b"64.81.78.74"), 0xe72630c5d2a5b352); + assert_eq!(fnv1a(b"64.81.78.74\0"), 0x6b983224ef8fb456); + assert_eq!(fnv1a(b"64.81.78.84"), 0xe73042c5d2ae266d); + assert_eq!(fnv1a(b"64.81.78.84\0"), 0x8527e324fdeb4b37); + assert_eq!(fnv1a(b"feedface"), 0x0a83c86fee952abc); + assert_eq!(fnv1a(b"feedface\0"), 0x7318523267779d74); + assert_eq!(fnv1a(b"feedfacedaffdeed"), 0x3e66d3d56b8caca1); + assert_eq!(fnv1a(b"feedfacedaffdeed\0"), 0x956694a5c0095593); + assert_eq!(fnv1a(b"feedfacedeadbeef"), 0xcac54572bb1a6fc8); + assert_eq!(fnv1a(b"feedfacedeadbeef\0"), 0xa7a4c9f3edebf0d8); + assert_eq!(fnv1a(b"line 1\nline 2\nline 3"), 0x7829851fac17b143); + assert_eq!(fnv1a(b"chongo /\\../\\"), 0x2c8f4c9af81bcf06); + assert_eq!(fnv1a(b"chongo /\\../\\\0"), 0xd34e31539740c732); + assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\"), 0x3605a2ac253d2db1); + assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\\0"), 0x08c11b8346f4a3c3); + assert_eq!(fnv1a(b"http://antwrp.gsfc.nasa.gov/apod/astropix.html"), 0x6be396289ce8a6da); + assert_eq!(fnv1a(b"http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash"), 0xd9b957fb7fe794c5); + assert_eq!(fnv1a(b"http://epod.usra.edu/"), 0x05be33da04560a93); + assert_eq!(fnv1a(b"http://exoplanet.eu/"), 0x0957f1577ba9747c); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cam3/"), 0xda2cc3acc24fba57); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cams/HMcam/"), 0x74136f185b29e7f0); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/deformation.html"), 0xb2f2b4590edb93b2); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/images.html"), 0xb3608fce8b86ae04); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/maps.html"), 0x4a3a865079359063); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/volcanowatch/current_issue.html"), 0x5b3a7ef496880a50); + assert_eq!(fnv1a(b"http://neo.jpl.nasa.gov/risk/"), 0x48fae3163854c23b); + assert_eq!(fnv1a(b"http://norvig.com/21-days.html"), 0x07aaa640476e0b9a); + assert_eq!(fnv1a(b"http://primes.utm.edu/curios/home.php"), 0x2f653656383a687d); + assert_eq!(fnv1a(b"http://slashdot.org/"), 0xa1031f8e7599d79c); + assert_eq!(fnv1a(b"http://tux.wr.usgs.gov/Maps/155.25-19.5.html"), 0xa31908178ff92477); + assert_eq!(fnv1a(b"http://volcano.wr.usgs.gov/kilaueastatus.php"), 0x097edf3c14c3fb83); + assert_eq!(fnv1a(b"http://www.avo.alaska.edu/activity/Redoubt.php"), 0xb51ca83feaa0971b); + assert_eq!(fnv1a(b"http://www.dilbert.com/fast/"), 0xdd3c0d96d784f2e9); + assert_eq!(fnv1a(b"http://www.fourmilab.ch/gravitation/orbits/"), 0x86cd26a9ea767d78); + assert_eq!(fnv1a(b"http://www.fpoa.net/"), 0xe6b215ff54a30c18); + assert_eq!(fnv1a(b"http://www.ioccc.org/index.html"), 0xec5b06a1c5531093); + assert_eq!(fnv1a(b"http://www.isthe.com/cgi-bin/number.cgi"), 0x45665a929f9ec5e5); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/bio.html"), 0x8c7609b4a9f10907); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/index.html"), 0x89aac3a491f0d729); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/src/calc/lucas-calc"), 0x32ce6b26e0f4a403); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/venus2004.html"), 0x614ab44e02b53e01); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/vita.html"), 0xfa6472eb6eef3290); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/c/expert.html"), 0x9e5d75eb1948eb6a); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/calc/index.html"), 0xb6d12ad4a8671852); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/fnv/index.html"), 0x88826f56eba07af1); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/howhigh.html"), 0x44535bf2645bc0fd); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/number.html"), 0x169388ffc21e3728); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html"), 0xf68aac9e396d8224); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html#largest"), 0x8e87d7e7472b3883); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/corpspeak.cgi"), 0x295c26caa8b423de); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/haiku.cgi"), 0x322c814292e72176); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/rand-none.cgi"), 0x8a06550eb8af7268); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/randdist.cgi"), 0xef86d60e661bcf71); + assert_eq!(fnv1a(b"http://www.lavarnd.org/index.html"), 0x9e5426c87f30ee54); + assert_eq!(fnv1a(b"http://www.lavarnd.org/what/nist-test.html"), 0xf1ea8aa826fd047e); + assert_eq!(fnv1a(b"http://www.macosxhints.com/"), 0x0babaf9a642cb769); + assert_eq!(fnv1a(b"http://www.mellis.com/"), 0x4b3341d4068d012e); + assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/havoalert.cfm"), 0xd15605cbc30a335c); + assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/timelines_24.cfm"), 0x5b21060aed8412e5); + assert_eq!(fnv1a(b"http://www.paulnoll.com/"), 0x45e2cda1ce6f4227); + assert_eq!(fnv1a(b"http://www.pepysdiary.com/"), 0x50ae3745033ad7d4); + assert_eq!(fnv1a(b"http://www.sciencenews.org/index/home/activity/view"), 0xaa4588ced46bf414); + assert_eq!(fnv1a(b"http://www.skyandtelescope.com/"), 0xc1b0056c4a95467e); + assert_eq!(fnv1a(b"http://www.sput.nl/~rob/sirius.html"), 0x56576a71de8b4089); + assert_eq!(fnv1a(b"http://www.systemexperts.com/"), 0xbf20965fa6dc927e); + assert_eq!(fnv1a(b"http://www.tq-international.com/phpBB3/index.php"), 0x569f8383c2040882); + assert_eq!(fnv1a(b"http://www.travelquesttours.com/index.htm"), 0xe1e772fba08feca0); + assert_eq!(fnv1a(b"http://www.wunderground.com/global/stations/89606.html"), 0x4ced94af97138ac4); + assert_eq!(fnv1a(&repeat_10(b"21701")), 0xc4112ffb337a82fb); + assert_eq!(fnv1a(&repeat_10(b"M21701")), 0xd64a4fd41de38b7d); + assert_eq!(fnv1a(&repeat_10(b"2^21701-1")), 0x4cfc32329edebcbb); + assert_eq!(fnv1a(&repeat_10(b"\x54\xc5")), 0x0803564445050395); + assert_eq!(fnv1a(&repeat_10(b"\xc5\x54")), 0xaa1574ecf4642ffd); + assert_eq!(fnv1a(&repeat_10(b"23209")), 0x694bc4e54cc315f9); + assert_eq!(fnv1a(&repeat_10(b"M23209")), 0xa3d7cb273b011721); + assert_eq!(fnv1a(&repeat_10(b"2^23209-1")), 0x577c2f8b6115bfa5); + assert_eq!(fnv1a(&repeat_10(b"\x5a\xa9")), 0xb7ec8c1a769fb4c1); + assert_eq!(fnv1a(&repeat_10(b"\xa9\x5a")), 0x5d5cfce63359ab19); + assert_eq!(fnv1a(&repeat_10(b"391581216093")), 0x33b96c3cd65b5f71); + assert_eq!(fnv1a(&repeat_10(b"391581*2^216093-1")), 0xd845097780602bb9); + assert_eq!(fnv1a(&repeat_10(b"\x05\xf9\x9d\x03\x4c\x81")), 0x84d47645d02da3d5); + assert_eq!(fnv1a(&repeat_10(b"FEDCBA9876543210")), 0x83544f33b58773a5); + assert_eq!(fnv1a(&repeat_10(b"\xfe\xdc\xba\x98\x76\x54\x32\x10")), 0x9175cbb2160836c5); + assert_eq!(fnv1a(&repeat_10(b"EFCDAB8967452301")), 0xc71b3bc175e72bc5); + assert_eq!(fnv1a(&repeat_10(b"\xef\xcd\xab\x89\x67\x45\x23\x01")), 0x636806ac222ec985); + assert_eq!(fnv1a(&repeat_10(b"0123456789ABCDEF")), 0xb6ef0e6950f52ed5); + assert_eq!(fnv1a(&repeat_10(b"\x01\x23\x45\x67\x89\xab\xcd\xef")), 0xead3d8a0f3dfdaa5); + assert_eq!(fnv1a(&repeat_10(b"1032547698BADCFE")), 0x922908fe9a861ba5); + assert_eq!(fnv1a(&repeat_10(b"\x10\x32\x54\x76\x98\xba\xdc\xfe")), 0x6d4821de275fd5c5); + assert_eq!(fnv1a(&repeat_500(b"\x00")), 0x1fe3fce62bd816b5); + assert_eq!(fnv1a(&repeat_500(b"\x07")), 0xc23e9fccd6f70591); + assert_eq!(fnv1a(&repeat_500(b"~")), 0xc1af12bdfe16b5b5); + assert_eq!(fnv1a(&repeat_500(b"\x7f")), 0x39e9f18f2f85e221); + } +} diff --git a/foreign-types-shared/.cargo-checksum.json b/foreign-types-shared/.cargo-checksum.json new file mode 100644 index 000000000..5fc4da45f --- /dev/null +++ b/foreign-types-shared/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"} \ No newline at end of file diff --git a/foreign-types-shared/Cargo.toml b/foreign-types-shared/Cargo.toml new file mode 100644 index 000000000..e2cb783b9 --- /dev/null +++ b/foreign-types-shared/Cargo.toml @@ -0,0 +1,21 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "foreign-types-shared" +version = "0.1.1" +authors = ["Steven Fackler "] +description = "An internal crate used by foreign-types" +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/foreign-types" + +[dependencies] diff --git a/foreign-types-shared/LICENSE-APACHE b/foreign-types-shared/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/foreign-types-shared/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/foreign-types-shared/LICENSE-MIT b/foreign-types-shared/LICENSE-MIT new file mode 100644 index 000000000..bb76d0146 --- /dev/null +++ b/foreign-types-shared/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2017 The foreign-types Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/foreign-types-shared/src/lib.rs b/foreign-types-shared/src/lib.rs new file mode 100644 index 000000000..cbebc3353 --- /dev/null +++ b/foreign-types-shared/src/lib.rs @@ -0,0 +1,51 @@ +//! Internal crate used by foreign-types + +#![no_std] +#![warn(missing_docs)] +#![doc(html_root_url="https://docs.rs/foreign-types-shared/0.1")] + +use core::cell::UnsafeCell; + +/// An opaque type used to define `ForeignTypeRef` types. +/// +/// A type implementing `ForeignTypeRef` should simply be a newtype wrapper around this type. +pub struct Opaque(UnsafeCell<()>); + +/// A type implemented by wrappers over foreign types. +pub trait ForeignType: Sized { + /// The raw C type. + type CType; + + /// The type representing a reference to this type. + type Ref: ForeignTypeRef; + + /// Constructs an instance of this type from its raw type. + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self; + + /// Returns a raw pointer to the wrapped value. + fn as_ptr(&self) -> *mut Self::CType; +} + +/// A trait implemented by types which reference borrowed foreign types. +pub trait ForeignTypeRef: Sized { + /// The raw C type. + type CType; + + /// Constructs a shared instance of this type from its raw type. + #[inline] + unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self { + &*(ptr as *mut _) + } + + /// Constructs a mutable reference of this type from its raw type. + #[inline] + unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self { + &mut *(ptr as *mut _) + } + + /// Returns a raw pointer to the wrapped value. + #[inline] + fn as_ptr(&self) -> *mut Self::CType { + self as *const _ as *mut _ + } +} diff --git a/foreign-types/.cargo-checksum.json b/foreign-types/.cargo-checksum.json new file mode 100644 index 000000000..4ba7de062 --- /dev/null +++ b/foreign-types/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"} \ No newline at end of file diff --git a/foreign-types/Cargo.toml b/foreign-types/Cargo.toml new file mode 100644 index 000000000..6ff5567de --- /dev/null +++ b/foreign-types/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "foreign-types" +version = "0.3.2" +authors = ["Steven Fackler "] +description = "A framework for Rust wrappers over C APIs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/foreign-types" +[dependencies.foreign-types-shared] +version = "0.1" diff --git a/foreign-types/LICENSE-APACHE b/foreign-types/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/foreign-types/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/foreign-types/LICENSE-MIT b/foreign-types/LICENSE-MIT new file mode 100644 index 000000000..bb76d0146 --- /dev/null +++ b/foreign-types/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2017 The foreign-types Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/foreign-types/README.md b/foreign-types/README.md new file mode 100644 index 000000000..cd15965fa --- /dev/null +++ b/foreign-types/README.md @@ -0,0 +1,23 @@ +# foreign-types + +[![CircleCI](https://circleci.com/gh/sfackler/foreign-types.svg?style=shield)](https://circleci.com/gh/sfackler/foreign-types) + +[Documentation](https://docs.rs/foreign-types) + +A framework for Rust wrappers over C APIs. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/foreign-types/src/lib.rs b/foreign-types/src/lib.rs new file mode 100644 index 000000000..6ce959207 --- /dev/null +++ b/foreign-types/src/lib.rs @@ -0,0 +1,306 @@ +//! A framework for Rust wrappers over C APIs. +//! +//! Ownership is as important in C as it is in Rust, but the semantics are often implicit. In +//! particular, pointer-to-value is commonly used to pass C values both when transferring ownership +//! or a borrow. +//! +//! This crate provides a framework to define a Rust wrapper over these kinds of raw C APIs in a way +//! that allows ownership semantics to be expressed in an ergonomic manner. The framework takes a +//! dual-type approach similar to APIs in the standard library such as `PathBuf`/`Path` or `String`/ +//! `str`. One type represents an owned value and references to the other represent borrowed +//! values. +//! +//! # Examples +//! +//! ``` +//! use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +//! use std::ops::{Deref, DerefMut}; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! } +//! } +//! +//! // The borrowed type is a newtype wrapper around an `Opaque` value. +//! // +//! // `FooRef` values never exist; we instead create references to `FooRef`s +//! // from raw C pointers. +//! pub struct FooRef(Opaque); +//! +//! impl ForeignTypeRef for FooRef { +//! type CType = foo_sys::FOO; +//! } +//! +//! // The owned type is simply a newtype wrapper around the raw C type. +//! // +//! // It dereferences to `FooRef`, so methods that do not require ownership +//! // should be defined there. +//! pub struct Foo(*mut foo_sys::FOO); +//! +//! impl Drop for Foo { +//! fn drop(&mut self) { +//! unsafe { foo_sys::FOO_free(self.0) } +//! } +//! } +//! +//! impl ForeignType for Foo { +//! type CType = foo_sys::FOO; +//! type Ref = FooRef; +//! +//! unsafe fn from_ptr(ptr: *mut foo_sys::FOO) -> Foo { +//! Foo(ptr) +//! } +//! +//! fn as_ptr(&self) -> *mut foo_sys::FOO { +//! self.0 +//! } +//! } +//! +//! impl Deref for Foo { +//! type Target = FooRef; +//! +//! fn deref(&self) -> &FooRef { +//! unsafe { FooRef::from_ptr(self.0) } +//! } +//! } +//! +//! impl DerefMut for Foo { +//! fn deref_mut(&mut self) -> &mut FooRef { +//! unsafe { FooRef::from_ptr_mut(self.0) } +//! } +//! } +//! ``` +//! +//! The `foreign_type!` macro can generate this boilerplate for you: +//! +//! ``` +//! #[macro_use] +//! extern crate foreign_types; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn FOO_duplicate(foo: *mut FOO) -> *mut FOO; // Optional +//! } +//! } +//! +//! foreign_type! { +//! type CType = foo_sys::FOO; +//! fn drop = foo_sys::FOO_free; +//! fn clone = foo_sys::FOO_duplicate; // Optional +//! /// A Foo. +//! pub struct Foo; +//! /// A borrowed Foo. +//! pub struct FooRef; +//! } +//! +//! # fn main() {} +//! ``` +//! +//! If `fn clone` is specified, then it must take `CType` as an argument and return a copy of it as `CType`. +//! It will be used to implement `ToOwned` and `Clone`. +//! +//! `#[derive(…)] is permitted before the lines with `pub struct`. +//! `#[doc(hidden)]` before the `type CType` line will hide the `foreign_type!` implementations from documentation. +//! +//! Say we then have a separate type in our C API that contains a `FOO`: +//! +//! ``` +//! mod foo_sys { +//! pub enum FOO {} +//! pub enum BAR {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn BAR_free(bar: *mut BAR); +//! pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO; +//! } +//! } +//! ``` +//! +//! The documentation for the C library states that `BAR_get_foo` returns a reference into the `BAR` +//! passed to it, which translates into a reference in Rust. It also says that we're allowed to +//! modify the `FOO`, so we'll define a pair of accessor methods, one immutable and one mutable: +//! +//! ``` +//! #[macro_use] +//! extern crate foreign_types; +//! +//! use foreign_types::ForeignTypeRef; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! pub enum BAR {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn BAR_free(bar: *mut BAR); +//! pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO; +//! } +//! } +//! +//! foreign_type! { +//! #[doc(hidden)] +//! type CType = foo_sys::FOO; +//! fn drop = foo_sys::FOO_free; +//! /// A Foo. +//! pub struct Foo; +//! /// A borrowed Foo. +//! pub struct FooRef; +//! } +//! +//! foreign_type! { +//! type CType = foo_sys::BAR; +//! fn drop = foo_sys::BAR_free; +//! /// A Foo. +//! pub struct Bar; +//! /// A borrowed Bar. +//! pub struct BarRef; +//! } +//! +//! impl BarRef { +//! fn foo(&self) -> &FooRef { +//! unsafe { FooRef::from_ptr(foo_sys::BAR_get_foo(self.as_ptr())) } +//! } +//! +//! fn foo_mut(&mut self) -> &mut FooRef { +//! unsafe { FooRef::from_ptr_mut(foo_sys::BAR_get_foo(self.as_ptr())) } +//! } +//! } +//! +//! # fn main() {} +//! ``` +#![no_std] +#![warn(missing_docs)] +#![doc(html_root_url="https://docs.rs/foreign-types/0.3")] +extern crate foreign_types_shared; + +#[doc(inline)] +pub use foreign_types_shared::*; + +/// A macro to easily define wrappers for foreign types. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate foreign_types; +/// +/// # mod openssl_sys { pub type SSL = (); pub unsafe fn SSL_free(_: *mut SSL) {} pub unsafe fn SSL_dup(x: *mut SSL) -> *mut SSL {x} } +/// foreign_type! { +/// type CType = openssl_sys::SSL; +/// fn drop = openssl_sys::SSL_free; +/// fn clone = openssl_sys::SSL_dup; +/// /// Documentation for the owned type. +/// pub struct Ssl; +/// /// Documentation for the borrowed type. +/// pub struct SslRef; +/// } +/// +/// # fn main() {} +/// ``` +#[macro_export] +macro_rules! foreign_type { + ( + $(#[$impl_attr:meta])* + type CType = $ctype:ty; + fn drop = $drop:expr; + $(fn clone = $clone:expr;)* + $(#[$owned_attr:meta])* + pub struct $owned:ident; + $(#[$borrowed_attr:meta])* + pub struct $borrowed:ident; + ) => { + $(#[$owned_attr])* + pub struct $owned(*mut $ctype); + + $(#[$impl_attr])* + impl $crate::ForeignType for $owned { + type CType = $ctype; + type Ref = $borrowed; + + #[inline] + unsafe fn from_ptr(ptr: *mut $ctype) -> $owned { + $owned(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut $ctype { + self.0 + } + } + + impl Drop for $owned { + #[inline] + fn drop(&mut self) { + unsafe { $drop(self.0) } + } + } + + $( + impl Clone for $owned { + #[inline] + fn clone(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone(self.0); + $crate::ForeignType::from_ptr(handle) + } + } + } + + impl ::std::borrow::ToOwned for $borrowed { + type Owned = $owned; + #[inline] + fn to_owned(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone($crate::ForeignTypeRef::as_ptr(self)); + $crate::ForeignType::from_ptr(handle) + } + } + } + )* + + impl ::std::ops::Deref for $owned { + type Target = $borrowed; + + #[inline] + fn deref(&self) -> &$borrowed { + unsafe { $crate::ForeignTypeRef::from_ptr(self.0) } + } + } + + impl ::std::ops::DerefMut for $owned { + #[inline] + fn deref_mut(&mut self) -> &mut $borrowed { + unsafe { $crate::ForeignTypeRef::from_ptr_mut(self.0) } + } + } + + impl ::std::borrow::Borrow<$borrowed> for $owned { + #[inline] + fn borrow(&self) -> &$borrowed { + &**self + } + } + + impl ::std::convert::AsRef<$borrowed> for $owned { + #[inline] + fn as_ref(&self) -> &$borrowed { + &**self + } + } + + $(#[$borrowed_attr])* + pub struct $borrowed($crate::Opaque); + + $(#[$impl_attr])* + impl $crate::ForeignTypeRef for $borrowed { + type CType = $ctype; + } + } +} diff --git a/fs2/.cargo-checksum.json b/fs2/.cargo-checksum.json new file mode 100644 index 000000000..b5f1e1d84 --- /dev/null +++ b/fs2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"} \ No newline at end of file diff --git a/fs2/Cargo.toml b/fs2/Cargo.toml new file mode 100644 index 000000000..4c6aded51 --- /dev/null +++ b/fs2/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fs2" +version = "0.4.3" +authors = ["Dan Burkert "] +description = "Cross-platform file locks and file duplication." +documentation = "https://docs.rs/fs2" +keywords = ["file", "file-system", "lock", "duplicate", "flock"] +license = "MIT/Apache-2.0" +repository = "https://github.com/danburkert/fs2-rs" +[dev-dependencies.tempdir] +version = "0.3" +[target."cfg(unix)".dependencies.libc] +version = "0.2.30" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["handleapi", "processthreadsapi", "winerror", "fileapi", "winbase", "std"] +[badges.appveyor] +repository = "danburkert/fs2-rs" + +[badges.travis-ci] +repository = "danburkert/fs2-rs" diff --git a/fs2/LICENSE-APACHE b/fs2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/fs2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/fs2/LICENSE-MIT b/fs2/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/fs2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/fs2/README.md b/fs2/README.md new file mode 100644 index 000000000..c10459a68 --- /dev/null +++ b/fs2/README.md @@ -0,0 +1,50 @@ +# fs2 + +Extended utilities for working with files and filesystems in Rust. `fs2` +requires Rust stable 1.8 or greater. + +[![Build Status](https://travis-ci.org/danburkert/fs2-rs.svg?branch=master)](https://travis-ci.org/danburkert/fs2-rs) +[![Windows Build status](https://ci.appveyor.com/api/projects/status/iuvjv1aaaml0rntt/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/fs2-rs/branch/master) +[![Documentation](https://docs.rs/fs2/badge.svg)](https://docs.rs/memmap) +[![Crate](https://img.shields.io/crates/v/fs2.svg)](https://crates.io/crates/memmap) + +## Features + +- [x] file descriptor duplication. +- [x] file locks. +- [x] file (pre)allocation. +- [x] file allocation information. +- [x] filesystem space usage information. + +## Platforms + +`fs2` should work on any platform supported by +[`libc`](https://github.com/rust-lang-nursery/libc#platforms-and-documentation). + +`fs2` is continuously tested on: + * `x86_64-unknown-linux-gnu` (Linux) + * `i686-unknown-linux-gnu` + * `x86_64-apple-darwin` (OSX) + * `i686-apple-darwin` + * `x86_64-pc-windows-msvc` (Windows) + * `i686-pc-windows-msvc` + * `x86_64-pc-windows-gnu` + * `i686-pc-windows-gnu` + +## Benchmarks + +Simple benchmarks are provided for the methods provided. Many of these +benchmarks use files in a temporary directory. On many modern Linux distros the +default temporary directory, `/tmp`, is mounted on a tempfs filesystem, which +will have different performance characteristics than a disk-backed filesystem. +The temporary directory is configurable at runtime through the environment (see +[`env::temp_dir`](https://doc.rust-lang.org/stable/std/env/fn.temp_dir.html)). + +## License + +`fs2` is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +Copyright (c) 2015 Dan Burkert. diff --git a/fs2/src/lib.rs b/fs2/src/lib.rs new file mode 100644 index 000000000..51b22db6a --- /dev/null +++ b/fs2/src/lib.rs @@ -0,0 +1,458 @@ +//! Extended utilities for working with files and filesystems in Rust. + +#![doc(html_root_url = "https://docs.rs/fs2/0.4.3")] + +#![cfg_attr(test, feature(test))] + +#[cfg(windows)] +extern crate winapi; + +#[cfg(unix)] +mod unix; +#[cfg(unix)] +use unix as sys; + +#[cfg(windows)] +mod windows; +#[cfg(windows)] +use windows as sys; + +use std::fs::File; +use std::io::{Error, Result}; +use std::path::Path; + +/// Extension trait for `std::fs::File` which provides allocation, duplication and locking methods. +/// +/// ## Notes on File Locks +/// +/// This library provides whole-file locks in both shared (read) and exclusive +/// (read-write) varieties. +/// +/// File locks are a cross-platform hazard since the file lock APIs exposed by +/// operating system kernels vary in subtle and not-so-subtle ways. +/// +/// The API exposed by this library can be safely used across platforms as long +/// as the following rules are followed: +/// +/// * Multiple locks should not be created on an individual `File` instance +/// concurrently. +/// * Duplicated files should not be locked without great care. +/// * Files to be locked should be opened with at least read or write +/// permissions. +/// * File locks may only be relied upon to be advisory. +/// +/// See the tests in `lib.rs` for cross-platform lock behavior that may be +/// relied upon; see the tests in `unix.rs` and `windows.rs` for examples of +/// platform-specific behavior. File locks are implemented with +/// [`flock(2)`](http://man7.org/linux/man-pages/man2/flock.2.html) on Unix and +/// [`LockFile`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365202(v=vs.85).aspx) +/// on Windows. +pub trait FileExt { + + /// Returns a duplicate instance of the file. + /// + /// The returned file will share the same file position as the original + /// file. + /// + /// If using rustc version 1.9 or later, prefer using `File::try_clone` to this. + /// + /// # Notes + /// + /// This is implemented with + /// [`dup(2)`](http://man7.org/linux/man-pages/man2/dup.2.html) on Unix and + /// [`DuplicateHandle`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx) + /// on Windows. + fn duplicate(&self) -> Result; + + /// Returns the amount of physical space allocated for a file. + fn allocated_size(&self) -> Result; + + /// Ensures that at least `len` bytes of disk space are allocated for the + /// file, and the file size is at least `len` bytes. After a successful call + /// to `allocate`, subsequent writes to the file within the specified length + /// are guaranteed not to fail because of lack of disk space. + fn allocate(&self, len: u64) -> Result<()>; + + /// Locks the file for shared usage, blocking if the file is currently + /// locked exclusively. + fn lock_shared(&self) -> Result<()>; + + /// Locks the file for exclusive usage, blocking if the file is currently + /// locked. + fn lock_exclusive(&self) -> Result<()>; + + /// Locks the file for shared usage, or returns a an error if the file is + /// currently locked (see `lock_contended_error`). + fn try_lock_shared(&self) -> Result<()>; + + /// Locks the file for shared usage, or returns a an error if the file is + /// currently locked (see `lock_contended_error`). + fn try_lock_exclusive(&self) -> Result<()>; + + /// Unlocks the file. + fn unlock(&self) -> Result<()>; +} + +impl FileExt for File { + fn duplicate(&self) -> Result { + sys::duplicate(self) + } + fn allocated_size(&self) -> Result { + sys::allocated_size(self) + } + fn allocate(&self, len: u64) -> Result<()> { + sys::allocate(self, len) + } + fn lock_shared(&self) -> Result<()> { + sys::lock_shared(self) + } + fn lock_exclusive(&self) -> Result<()> { + sys::lock_exclusive(self) + } + fn try_lock_shared(&self) -> Result<()> { + sys::try_lock_shared(self) + } + fn try_lock_exclusive(&self) -> Result<()> { + sys::try_lock_exclusive(self) + } + fn unlock(&self) -> Result<()> { + sys::unlock(self) + } +} + +/// Returns the error that a call to a try lock method on a contended file will +/// return. +pub fn lock_contended_error() -> Error { + sys::lock_error() +} + +/// `FsStats` contains some common stats about a file system. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FsStats { + free_space: u64, + available_space: u64, + total_space: u64, + allocation_granularity: u64, +} + +impl FsStats { + /// Returns the number of free bytes in the file system containing the provided + /// path. + pub fn free_space(&self) -> u64 { + self.free_space + } + + /// Returns the available space in bytes to non-priveleged users in the file + /// system containing the provided path. + pub fn available_space(&self) -> u64 { + self.available_space + } + + /// Returns the total space in bytes in the file system containing the provided + /// path. + pub fn total_space(&self) -> u64 { + self.total_space + } + + /// Returns the filesystem's disk space allocation granularity in bytes. + /// The provided path may be for any file in the filesystem. + /// + /// On Posix, this is equivalent to the filesystem's block size. + /// On Windows, this is equivalent to the filesystem's cluster size. + pub fn allocation_granularity(&self) -> u64 { + self.allocation_granularity + } +} + +/// Get the stats of the file system containing the provided path. +pub fn statvfs

(path: P) -> Result where P: AsRef { + sys::statvfs(path.as_ref()) +} + +/// Returns the number of free bytes in the file system containing the provided +/// path. +pub fn free_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.free_space) +} + +/// Returns the available space in bytes to non-priveleged users in the file +/// system containing the provided path. +pub fn available_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.available_space) +} + +/// Returns the total space in bytes in the file system containing the provided +/// path. +pub fn total_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.total_space) +} + +/// Returns the filesystem's disk space allocation granularity in bytes. +/// The provided path may be for any file in the filesystem. +/// +/// On Posix, this is equivalent to the filesystem's block size. +/// On Windows, this is equivalent to the filesystem's cluster size. +pub fn allocation_granularity

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.allocation_granularity) +} + +#[cfg(test)] +mod test { + + extern crate tempdir; + extern crate test; + + use std::fs; + use super::*; + use std::io::{Read, Seek, SeekFrom, Write}; + + /// Tests file duplication. + #[test] + fn duplicate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let mut file1 = + fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let mut file2 = file1.duplicate().unwrap(); + + // Write into the first file and then drop it. + file1.write_all(b"foo").unwrap(); + drop(file1); + + let mut buf = vec![]; + + // Read from the second file; since the position is shared it will already be at EOF. + file2.read_to_end(&mut buf).unwrap(); + assert_eq!(0, buf.len()); + + // Rewind and read. + file2.seek(SeekFrom::Start(0)).unwrap(); + file2.read_to_end(&mut buf).unwrap(); + assert_eq!(&buf, &b"foo"); + } + + /// Tests shared file lock operations. + #[test] + fn lock_shared() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file3 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Concurrent shared access is OK, but not shared and exclusive. + file1.lock_shared().unwrap(); + file2.lock_shared().unwrap(); + assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + file1.unlock().unwrap(); + assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + + // Once all shared file locks are dropped, an exclusive lock may be created; + file2.unlock().unwrap(); + file3.lock_exclusive().unwrap(); + } + + /// Tests exclusive file lock operations. + #[test] + fn lock_exclusive() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // No other access is possible once an exclusive lock is created. + file1.lock_exclusive().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + assert_eq!(file2.try_lock_shared().unwrap_err().kind(), + lock_contended_error().kind()); + + // Once the exclusive lock is dropped, the second file is able to create a lock. + file1.unlock().unwrap(); + file2.lock_exclusive().unwrap(); + } + + /// Tests that a lock is released after the file that owns it is dropped. + #[test] + fn lock_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + file1.lock_exclusive().unwrap(); + assert_eq!(file2.try_lock_shared().unwrap_err().kind(), + lock_contended_error().kind()); + + // Drop file1; the lock should be released. + drop(file1); + file2.lock_shared().unwrap(); + } + + /// Tests file allocation. + #[test] + fn allocate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let blksize = allocation_granularity(&path).unwrap(); + + // New files are created with no allocated size. + assert_eq!(0, file.allocated_size().unwrap()); + assert_eq!(0, file.metadata().unwrap().len()); + + // Allocate space for the file, checking that the allocated size steps + // up by block size, and the file length matches the allocated size. + + file.allocate(2 * blksize - 1).unwrap(); + assert_eq!(2 * blksize, file.allocated_size().unwrap()); + assert_eq!(2 * blksize - 1, file.metadata().unwrap().len()); + + // Truncate the file, checking that the allocated size steps down by + // block size. + + file.set_len(blksize + 1).unwrap(); + assert_eq!(2 * blksize, file.allocated_size().unwrap()); + assert_eq!(blksize + 1, file.metadata().unwrap().len()); + } + + /// Checks filesystem space methods. + #[test] + fn filesystem_space() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let total_space = total_space(&tempdir.path()).unwrap(); + let free_space = free_space(&tempdir.path()).unwrap(); + let available_space = available_space(&tempdir.path()).unwrap(); + + assert!(total_space > free_space); + assert!(total_space > available_space); + assert!(available_space <= free_space); + } + + /// Benchmarks creating and removing a file. This is a baseline benchmark + /// for comparing against the truncate and allocate benchmarks. + #[bench] + fn bench_file_create(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, truncating it to 32MiB, and deleting it. + #[bench] + fn bench_file_truncate(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.set_len(size).unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, allocating 32MiB for it, and deleting it. + #[bench] + fn bench_file_allocate(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.allocate(size).unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, allocating 32MiB for it, and deleting it. + #[bench] + fn bench_allocated_size(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.allocate(size).unwrap(); + + b.iter(|| { + file.allocated_size().unwrap(); + }); + } + + /// Benchmarks duplicating a file descriptor or handle. + #[bench] + fn bench_duplicate(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + b.iter(|| test::black_box(file.duplicate().unwrap())); + } + + /// Benchmarks locking and unlocking a file lock. + #[bench] + fn bench_lock_unlock(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + b.iter(|| { + file.lock_exclusive().unwrap(); + file.unlock().unwrap(); + }); + } + + /// Benchmarks the free space method. + #[bench] + fn bench_free_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(free_space(&tempdir.path()).unwrap()); + }); + } + + /// Benchmarks the available space method. + #[bench] + fn bench_available_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(available_space(&tempdir.path()).unwrap()); + }); + } + + /// Benchmarks the total space method. + #[bench] + fn bench_total_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(total_space(&tempdir.path()).unwrap()); + }); + } +} diff --git a/fs2/src/unix.rs b/fs2/src/unix.rs new file mode 100644 index 000000000..91867f7e3 --- /dev/null +++ b/fs2/src/unix.rs @@ -0,0 +1,250 @@ +extern crate libc; + +use std::ffi::CString; +use std::fs::File; +use std::io::{Error, ErrorKind, Result}; +use std::mem; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::fs::MetadataExt; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::path::Path; + +use FsStats; + +pub fn duplicate(file: &File) -> Result { + unsafe { + let fd = libc::dup(file.as_raw_fd()); + + if fd < 0 { + Err(Error::last_os_error()) + } else { + Ok(File::from_raw_fd(fd)) + } + } +} + +pub fn lock_shared(file: &File) -> Result<()> { + flock(file, libc::LOCK_SH) +} + +pub fn lock_exclusive(file: &File) -> Result<()> { + flock(file, libc::LOCK_EX) +} + +pub fn try_lock_shared(file: &File) -> Result<()> { + flock(file, libc::LOCK_SH | libc::LOCK_NB) +} + +pub fn try_lock_exclusive(file: &File) -> Result<()> { + flock(file, libc::LOCK_EX | libc::LOCK_NB) +} + +pub fn unlock(file: &File) -> Result<()> { + flock(file, libc::LOCK_UN) +} + +pub fn lock_error() -> Error { + Error::from_raw_os_error(libc::EWOULDBLOCK) +} + +#[cfg(not(target_os = "solaris"))] +fn flock(file: &File, flag: libc::c_int) -> Result<()> { + let ret = unsafe { libc::flock(file.as_raw_fd(), flag) }; + if ret < 0 { Err(Error::last_os_error()) } else { Ok(()) } +} + +/// Simulate flock() using fcntl(); primarily for Oracle Solaris. +#[cfg(target_os = "solaris")] +fn flock(file: &File, flag: libc::c_int) -> Result<()> { + let mut fl = libc::flock { + l_whence: 0, + l_start: 0, + l_len: 0, + l_type: 0, + l_pad: [0; 4], + l_pid: 0, + l_sysid: 0, + }; + + // In non-blocking mode, use F_SETLK for cmd, F_SETLKW otherwise, and don't forget to clear + // LOCK_NB. + let (cmd, operation) = match flag & libc::LOCK_NB { + 0 => (libc::F_SETLKW, flag), + _ => (libc::F_SETLK, flag & !libc::LOCK_NB), + }; + + match operation { + libc::LOCK_SH => fl.l_type |= libc::F_RDLCK, + libc::LOCK_EX => fl.l_type |= libc::F_WRLCK, + libc::LOCK_UN => fl.l_type |= libc::F_UNLCK, + _ => return Err(Error::from_raw_os_error(libc::EINVAL)), + } + + let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &fl) }; + match ret { + // Translate EACCES to EWOULDBLOCK + -1 => match Error::last_os_error().raw_os_error() { + Some(libc::EACCES) => return Err(lock_error()), + _ => return Err(Error::last_os_error()) + }, + _ => Ok(()) + } +} + +pub fn allocated_size(file: &File) -> Result { + file.metadata().map(|m| m.blocks() as u64 * 512) +} + +#[cfg(any(target_os = "linux", + target_os = "freebsd", + target_os = "android", + target_os = "nacl"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + let ret = unsafe { libc::posix_fallocate(file.as_raw_fd(), 0, len as libc::off_t) }; + if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) } +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + let stat = try!(file.metadata()); + + if len > stat.blocks() as u64 * 512 { + let mut fstore = libc::fstore_t { + fst_flags: libc::F_ALLOCATECONTIG, + fst_posmode: libc::F_PEOFPOSMODE, + fst_offset: 0, + fst_length: len as libc::off_t, + fst_bytesalloc: 0, + }; + + let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) }; + if ret == -1 { + // Unable to allocate contiguous disk space; attempt to allocate non-contiguously. + fstore.fst_flags = libc::F_ALLOCATEALL; + let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) }; + if ret == -1 { + return Err(Error::last_os_error()); + } + } + } + + if len > stat.size() as u64 { + file.set_len(len) + } else { + Ok(()) + } +} + +#[cfg(any(target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "solaris", + target_os = "haiku"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + // No file allocation API available, just set the length if necessary. + if len > try!(file.metadata()).len() as u64 { + file.set_len(len) + } else { + Ok(()) + } +} + +pub fn statvfs(path: &Path) -> Result { + let cstr = match CString::new(path.as_os_str().as_bytes()) { + Ok(cstr) => cstr, + Err(..) => return Err(Error::new(ErrorKind::InvalidInput, "path contained a null")), + }; + + unsafe { + let mut stat: libc::statvfs = mem::zeroed(); + // danburkert/fs2-rs#1: cast is necessary for platforms where c_char != u8. + if libc::statvfs(cstr.as_ptr() as *const _, &mut stat) != 0 { + Err(Error::last_os_error()) + } else { + Ok(FsStats { + free_space: stat.f_frsize as u64 * stat.f_bfree as u64, + available_space: stat.f_frsize as u64 * stat.f_bavail as u64, + total_space: stat.f_frsize as u64 * stat.f_blocks as u64, + allocation_granularity: stat.f_frsize as u64, + }) + } + } +} + +#[cfg(test)] +mod test { + extern crate tempdir; + extern crate libc; + + use std::fs::{self, File}; + use std::os::unix::io::AsRawFd; + + use {FileExt, lock_contended_error}; + + /// The duplicate method returns a file with a new file descriptor. + #[test] + fn duplicate_new_fd() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + assert!(file1.as_raw_fd() != file2.as_raw_fd()); + } + + /// The duplicate method should preservesthe close on exec flag. + #[test] + fn duplicate_cloexec() { + + fn flags(file: &File) -> libc::c_int { + unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL, 0) } + } + + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + assert_eq!(flags(&file1), flags(&file2)); + } + + /// Tests that locking a file descriptor will replace any existing locks + /// held on the file descriptor. + #[test] + fn lock_replace() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Creating a shared lock will drop an exclusive lock. + file1.lock_exclusive().unwrap(); + file1.lock_shared().unwrap(); + file2.lock_shared().unwrap(); + + // Attempting to replace a shared lock with an exclusive lock will fail + // with multiple lock holders, and remove the original shared lock. + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + file1.lock_shared().unwrap(); + } + + /// Tests that locks are shared among duplicated file descriptors. + #[test] + fn lock_duplicate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + let file3 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Create a lock through fd1, then replace it through fd2. + file1.lock_shared().unwrap(); + file2.lock_exclusive().unwrap(); + assert_eq!(file3.try_lock_shared().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Either of the file descriptors should be able to unlock. + file1.unlock().unwrap(); + file3.lock_shared().unwrap(); + } +} diff --git a/fs2/src/windows.rs b/fs2/src/windows.rs new file mode 100644 index 000000000..0e37c6657 --- /dev/null +++ b/fs2/src/windows.rs @@ -0,0 +1,279 @@ +use std::fs::File; +use std::io::{Error, Result}; +use std::mem; +use std::os::windows::ffi::OsStrExt; +use std::os::windows::io::{AsRawHandle, FromRawHandle}; +use std::path::Path; +use std::ptr; + +use winapi::shared::minwindef::{BOOL, DWORD}; +use winapi::shared::winerror::ERROR_LOCK_VIOLATION; +use winapi::um::fileapi::{FILE_ALLOCATION_INFO, FILE_STANDARD_INFO, GetDiskFreeSpaceW}; +use winapi::um::fileapi::{GetVolumePathNameW, LockFileEx, UnlockFile, SetFileInformationByHandle}; +use winapi::um::handleapi::DuplicateHandle; +use winapi::um::minwinbase::{FileAllocationInfo, FileStandardInfo}; +use winapi::um::minwinbase::{LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; +use winapi::um::processthreadsapi::GetCurrentProcess; +use winapi::um::winbase::GetFileInformationByHandleEx; +use winapi::um::winnt::DUPLICATE_SAME_ACCESS; + +use FsStats; + +pub fn duplicate(file: &File) -> Result { + unsafe { + let mut handle = ptr::null_mut(); + let current_process = GetCurrentProcess(); + let ret = DuplicateHandle(current_process, + file.as_raw_handle(), + current_process, + &mut handle, + 0, + true as BOOL, + DUPLICATE_SAME_ACCESS); + if ret == 0 { + Err(Error::last_os_error()) + } else { + Ok(File::from_raw_handle(handle)) + } + } +} + +pub fn allocated_size(file: &File) -> Result { + unsafe { + let mut info: FILE_STANDARD_INFO = mem::zeroed(); + + let ret = GetFileInformationByHandleEx( + file.as_raw_handle(), + FileStandardInfo, + &mut info as *mut _ as *mut _, + mem::size_of::() as DWORD); + + if ret == 0 { + Err(Error::last_os_error()) + } else { + Ok(*info.AllocationSize.QuadPart() as u64) + } + } +} + +pub fn allocate(file: &File, len: u64) -> Result<()> { + if try!(allocated_size(file)) < len { + unsafe { + let mut info: FILE_ALLOCATION_INFO = mem::zeroed(); + *info.AllocationSize.QuadPart_mut() = len as i64; + let ret = SetFileInformationByHandle( + file.as_raw_handle(), + FileAllocationInfo, + &mut info as *mut _ as *mut _, + mem::size_of::() as DWORD); + if ret == 0 { + return Err(Error::last_os_error()); + } + } + } + if try!(file.metadata()).len() < len { + file.set_len(len) + } else { + Ok(()) + } +} + +pub fn lock_shared(file: &File) -> Result<()> { + lock_file(file, 0) +} + +pub fn lock_exclusive(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_EXCLUSIVE_LOCK) +} + +pub fn try_lock_shared(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_FAIL_IMMEDIATELY) +} + +pub fn try_lock_exclusive(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY) +} + +pub fn unlock(file: &File) -> Result<()> { + unsafe { + let ret = UnlockFile(file.as_raw_handle(), 0, 0, !0, !0); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) } + } +} + +pub fn lock_error() -> Error { + Error::from_raw_os_error(ERROR_LOCK_VIOLATION as i32) +} + +fn lock_file(file: &File, flags: DWORD) -> Result<()> { + unsafe { + let mut overlapped = mem::zeroed(); + let ret = LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) } + } +} + +fn volume_path(path: &Path, volume_path: &mut [u16]) -> Result<()> { + let path_utf8: Vec = path.as_os_str().encode_wide().chain(Some(0)).collect(); + unsafe { + let ret = GetVolumePathNameW(path_utf8.as_ptr(), + volume_path.as_mut_ptr(), + volume_path.len() as DWORD); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) + } + } +} + +pub fn statvfs(path: &Path) -> Result { + let root_path: &mut [u16] = &mut [0; 261]; + try!(volume_path(path, root_path)); + unsafe { + + let mut sectors_per_cluster = 0; + let mut bytes_per_sector = 0; + let mut number_of_free_clusters = 0; + let mut total_number_of_clusters = 0; + let ret = GetDiskFreeSpaceW(root_path.as_ptr(), + &mut sectors_per_cluster, + &mut bytes_per_sector, + &mut number_of_free_clusters, + &mut total_number_of_clusters); + if ret == 0 { + Err(Error::last_os_error()) + } else { + let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64; + let free_space = bytes_per_cluster * number_of_free_clusters as u64; + let total_space = bytes_per_cluster * total_number_of_clusters as u64; + Ok(FsStats { + free_space: free_space, + available_space: free_space, + total_space: total_space, + allocation_granularity: bytes_per_cluster, + }) + } + } +} + +#[cfg(test)] +mod test { + + extern crate tempdir; + + use std::fs; + use std::os::windows::io::AsRawHandle; + + use {FileExt, lock_contended_error}; + + /// The duplicate method returns a file with a new file handle. + #[test] + fn duplicate_new_handle() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + assert!(file1.as_raw_handle() != file2.as_raw_handle()); + } + + /// A duplicated file handle does not have access to the original handle's locks. + #[test] + fn lock_duplicate_handle_independence() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + // Locking the original file handle will block the duplicate file handle from opening a lock. + file1.lock_shared().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Once the original file handle is unlocked, the duplicate handle can proceed with a lock. + file1.unlock().unwrap(); + file2.lock_exclusive().unwrap(); + } + + /// A file handle may not be exclusively locked multiple times, or exclusively locked and then + /// shared locked. + #[test] + fn lock_non_reentrant() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Multiple exclusive locks fails. + file.lock_exclusive().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + file.unlock().unwrap(); + + // Shared then Exclusive locks fails. + file.lock_shared().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + } + + /// A file handle can hold an exclusive lock and any number of shared locks, all of which must + /// be unlocked independently. + #[test] + fn lock_layering() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Open two shared locks on the file, and then try and fail to open an exclusive lock. + file.lock_exclusive().unwrap(); + file.lock_shared().unwrap(); + file.lock_shared().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop one of the shared locks and try again. + file.unlock().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop the second shared lock and try again. + file.unlock().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop the exclusive lock and finally succeed. + file.unlock().unwrap(); + file.lock_exclusive().unwrap(); + } + + /// A file handle with multiple open locks will have all locks closed on drop. + #[test] + fn lock_layering_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Open two shared locks on the file, and then try and fail to open an exclusive lock. + file1.lock_shared().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + drop(file1); + file2.lock_exclusive().unwrap(); + } + + /// A file handle's locks will not be released until the original handle and all of its + /// duplicates have been closed. This on really smells like a bug in Windows. + #[test] + fn lock_duplicate_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + // Open a lock on the original handle, then close it. + file1.lock_shared().unwrap(); + drop(file1); + + // Attempting to create a lock on the file with the duplicate handle will fail. + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + } +} diff --git a/fuchsia-cprng/.cargo-checksum.json b/fuchsia-cprng/.cargo-checksum.json new file mode 100644 index 000000000..ff6abc382 --- /dev/null +++ b/fuchsia-cprng/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"} \ No newline at end of file diff --git a/fuchsia-cprng/AUTHORS b/fuchsia-cprng/AUTHORS new file mode 100644 index 000000000..61ae30280 --- /dev/null +++ b/fuchsia-cprng/AUTHORS @@ -0,0 +1,10 @@ +# This is the list of Fuchsia Authors. + +# Names should be added to this file as one of +# Organization's name +# Individual's name +# Individual's name + +Google Inc. +The Chromium Authors +The Go Authors diff --git a/fuchsia-cprng/Cargo.toml b/fuchsia-cprng/Cargo.toml new file mode 100644 index 000000000..917b43096 --- /dev/null +++ b/fuchsia-cprng/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "fuchsia-cprng" +version = "0.1.1" +authors = ["Erick Tryzelaar "] +include = ["src/*.rs", "Cargo.toml", "AUTHORS", "LICENSE", "PATENTS"] +description = "Rust crate for the Fuchsia cryptographically secure pseudorandom number generator" +readme = "README.md" +license-file = "LICENSE" +repository = "https://fuchsia.googlesource.com/fuchsia/+/master/garnet/public/rust/fuchsia-cprng" diff --git a/fuchsia-cprng/LICENSE b/fuchsia-cprng/LICENSE new file mode 100644 index 000000000..87f152cc5 --- /dev/null +++ b/fuchsia-cprng/LICENSE @@ -0,0 +1,27 @@ +Copyright 2019 The Fuchsia Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/fuchsia-cprng/PATENTS b/fuchsia-cprng/PATENTS new file mode 100644 index 000000000..2746e78d1 --- /dev/null +++ b/fuchsia-cprng/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Fuchsia project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this +section) patent license to make, have made, use, offer to sell, sell, +import, transfer, and otherwise run, modify and propagate the contents +of this implementation of Fuchsia, where such license applies only to +those patent claims, both currently owned by Google and acquired in +the future, licensable by Google that are necessarily infringed by +this implementation. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute +or order or agree to the institution of patent litigation or any other +patent enforcement activity against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that this +implementation of Fuchsia constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of +Fuchsia shall terminate as of the date such litigation is filed. diff --git a/fuchsia-cprng/src/lib.rs b/fuchsia-cprng/src/lib.rs new file mode 100644 index 000000000..5074690c9 --- /dev/null +++ b/fuchsia-cprng/src/lib.rs @@ -0,0 +1,57 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for the Zircon kernel's CPRNG. + +#![no_std] +#![deny(warnings)] + +/// Draw random bytes from the kernel's CPRNG to fill the given buffer. +/// +/// Wraps the +/// [zx_cprng_draw](https://fuchsia.googlesource.com/fuchsia/+/master/zircon/docs/syscalls/cprng_draw.md) +/// syscall. +pub fn cprng_draw(buffer: &mut [u8]) { + unsafe { zx_cprng_draw(buffer.as_mut_ptr(), buffer.len()) }; +} + +#[link(name = "zircon")] +extern "C" { + fn zx_cprng_draw(buffer: *mut u8, length: usize); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cprng() { + let mut buffer = [0; 20]; + cprng_draw(&mut buffer); + let mut first_zero = 0; + let mut last_zero = 0; + for _ in 0..30 { + let mut buffer = [0; 20]; + cprng_draw(&mut buffer); + if buffer[0] == 0 { + first_zero += 1; + } + if buffer[19] == 0 { + last_zero += 1; + } + } + assert_ne!(first_zero, 30); + assert_ne!(last_zero, 30); + } + + #[test] + fn cprng_large() { + let mut buffer = [0; 1024]; + cprng_draw(&mut buffer); + + for mut s in buffer.chunks_mut(256) { + cprng_draw(&mut s); + } + } +} diff --git a/fwdansi/.cargo-checksum.json b/fwdansi/.cargo-checksum.json new file mode 100644 index 000000000..e20d120fe --- /dev/null +++ b/fwdansi/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3"} \ No newline at end of file diff --git a/fwdansi/Cargo.toml b/fwdansi/Cargo.toml new file mode 100644 index 000000000..03f35a7db --- /dev/null +++ b/fwdansi/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fwdansi" +version = "1.0.1" +authors = ["kennytm "] +description = "Forwards a byte string with ANSI escape code to a termcolor terminal" +keywords = ["ansi", "windows", "console", "terminal", "color"] +categories = ["command-line-interface"] +license = "MIT" +repository = "https://github.com/kennytm/fwdansi" +[dependencies.memchr] +version = "2" + +[dependencies.termcolor] +version = "1" +[dev-dependencies.proptest] +version = "0.8" +[badges.appveyor] +repository = "kennytm/fwdansi" + +[badges.maintenance] +status = "passively-maintained" + +[badges.travis-ci] +repository = "kennytm/fwdansi" diff --git a/fwdansi/appveyor.yml b/fwdansi/appveyor.yml new file mode 100644 index 000000000..dc3d893c8 --- /dev/null +++ b/fwdansi/appveyor.yml @@ -0,0 +1,20 @@ +environment: + matrix: + - TOOLCHAIN: 1.27.2 + - TOOLCHAIN: stable + - TOOLCHAIN: beta + - TOOLCHAIN: nightly + +install: + - appveyor DownloadFile https://win.rustup.rs/x86_64 -FileName rustup-init.exe + - rustup-init -y --default-toolchain %TOOLCHAIN% + - SET PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -vV + - cargo -vV + +test_script: + - cargo build + - cargo test + - cargo run --example run-rustc + +build: false diff --git a/fwdansi/examples/run-rustc.rs b/fwdansi/examples/run-rustc.rs new file mode 100644 index 000000000..3bc303a0d --- /dev/null +++ b/fwdansi/examples/run-rustc.rs @@ -0,0 +1,17 @@ +extern crate termcolor; +extern crate fwdansi; + +use termcolor::*; +use std::io; +use std::process::Command; +use fwdansi::write_ansi; + +fn main() -> io::Result<()> { + let output = Command::new("rustc").args(&["--color", "always"]).output()?; + + let mut stderr = StandardStream::stderr(ColorChoice::Always); + write_ansi(&mut stderr, &output.stderr)?; + //^ should print "error: no input filename given" with appropriate color everywhere. + + Ok(()) +} diff --git a/fwdansi/src/lib.rs b/fwdansi/src/lib.rs new file mode 100644 index 000000000..d5dcdbc5c --- /dev/null +++ b/fwdansi/src/lib.rs @@ -0,0 +1,235 @@ +//! Write colored strings with ANSI escape code into a `termcolor` terminal. +//! +//! This package provides a single function, [`write_ansi`], which parses ANSI +//! escape codes in the provided byte string and transforms them into the +//! corresponding `termcolor` commands. The colors will be supported even on a +//! Windows console. +//! +//! The main purpose of this package is to forward colored output from a child +//! process. +//! +//! ```rust +// #![doc(include = "../examples/rustc.rs")] // still unstable, see issue 44732 +//! extern crate termcolor; +//! extern crate fwdansi; +//! +//! use termcolor::*; +//! use std::io; +//! use std::process::Command; +//! use fwdansi::write_ansi; +//! +//! fn main() -> io::Result<()> { +//! let output = Command::new("rustc").args(&["--color", "always"]).output()?; +//! +//! let mut stderr = StandardStream::stderr(ColorChoice::Always); +//! write_ansi(&mut stderr, &output.stderr)?; +//! //^ should print "error: no input filename given" with appropriate color everywhere. +//! +//! Ok(()) +//! } +//! ``` + +extern crate termcolor; +extern crate memchr; + +use memchr::memchr; +use termcolor::{Color, ColorSpec, WriteColor}; + +use std::io; +use std::mem; + +/// Writes a string with ANSI escape code into the colored output stream. +/// +/// Only SGR (`\x1b[…m`) is supported. Other input will be printed as-is. +pub fn write_ansi(mut writer: W, mut ansi: &[u8]) -> io::Result<()> { + while let Some(index) = memchr(0x1b, ansi) { + let (left, right) = ansi.split_at(index); + writer.write_all(left)?; + if right.is_empty() { + return Ok(()); + } + + let mut parser = ColorSpecParser::new(right); + parser.parse(); + if parser.ansi.as_ptr() == right.as_ptr() { + writer.write_all(&right[..1])?; + ansi = &right[1..]; + } else { + writer.set_color(&parser.spec)?; + ansi = parser.ansi; + } + } + writer.write_all(ansi) +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum State { + Normal, + PrepareCustomColor, + Ansi256, + Rgb, +} +struct ColorSpecParser<'a> { + spec: ColorSpec, + ansi: &'a [u8], + reset: bool, + state: State, + is_bg: bool, + red: Option, + green: Option, +} +impl<'a> ColorSpecParser<'a> { + fn new(ansi: &'a [u8]) -> Self { + Self { + spec: ColorSpec::new(), + ansi, + reset: false, + state: State::Normal, + is_bg: false, + red: None, + green: None, + } + } + + fn parse(&mut self) { + #[derive(PartialEq, Eq)] + enum Expected { + Escape, + OpenBracket, + Number(u8), + } + + while !self.ansi.is_empty() { + let mut expected = Expected::Escape; + let mut it = self.ansi.iter(); + for b in &mut it { + match (*b, expected) { + (0x1b, Expected::Escape) => { + expected = Expected::OpenBracket; + continue; + } + (b'[', Expected::OpenBracket) => { + expected = Expected::Number(0); + continue; + } + (b'0'..=b'9', Expected::Number(number)) => { + if let Some(n) = number.checked_mul(10).and_then(|n| n.checked_add(b - b'0')) { + expected = Expected::Number(n); + continue; + } + } + (b':', Expected::Number(number)) + | (b';', Expected::Number(number)) + | (b'm', Expected::Number(number)) => { + if self.apply_number(number) { + if *b == b'm' { + expected = Expected::Escape; + break; + } else { + expected = Expected::Number(0); + continue; + } + } + } + _ => {} + } + return; + } + if let Expected::Escape = expected { + self.ansi = it.as_slice(); + } else { + break; + } + } + } + + fn set_color(&mut self, color: Color) { + if self.is_bg { + self.spec.set_bg(Some(color)); + } else { + self.spec.set_fg(Some(color)); + } + } + + fn apply_number(&mut self, number: u8) -> bool { + match (number, self.state) { + (0, State::Normal) => { + if mem::replace(&mut self.reset, true) { + return false; + } + } + (1, State::Normal) => { + self.spec.set_bold(true); + } + (4, State::Normal) => { + self.spec.set_underline(true); + } + (21, State::Normal) => { + self.spec.set_bold(false); + } + (24, State::Normal) => { + self.spec.set_underline(false); + } + (38, State::Normal) | (48, State::Normal) => { + self.is_bg = number == 48; + self.state = State::PrepareCustomColor; + } + (30..=39, State::Normal) => { + self.spec.set_fg(parse_color(number - 30)); + } + (40..=49, State::Normal) => { + self.spec.set_bg(parse_color(number - 40)); + } + (90..=97, State::Normal) => { + self.spec.set_intense(true).set_fg(parse_color(number - 90)); + } + (100..=107, State::Normal) => { + self.spec.set_intense(true).set_bg(parse_color(number - 100)); + } + (5, State::PrepareCustomColor) => { + self.state = State::Ansi256; + } + (2, State::PrepareCustomColor) => { + self.state = State::Rgb; + self.red = None; + self.green = None; + } + (n, State::Ansi256) => { + self.set_color(Color::Ansi256(n)); + self.state = State::Normal; + } + (b, State::Rgb) => { + match (self.red, self.green) { + (None, _) => { + self.red = Some(b); + } + (Some(_), None) => { + self.green = Some(b); + } + (Some(r), Some(g)) => { + self.set_color(Color::Rgb(r, g, b)); + self.state = State::Normal; + } + } + } + _ => { + self.state = State::Normal; + } + } + true + } +} + +fn parse_color(digit: u8) -> Option { + match digit { + 0 => Some(Color::Black), + 1 => Some(Color::Red), + 2 => Some(Color::Green), + 3 => Some(Color::Yellow), + 4 => Some(Color::Blue), + 5 => Some(Color::Magenta), + 6 => Some(Color::Cyan), + 7 => Some(Color::White), + _ => None, + } +} diff --git a/fwdansi/tests/tests.proptest-regressions b/fwdansi/tests/tests.proptest-regressions new file mode 100644 index 000000000..ad5349d13 --- /dev/null +++ b/fwdansi/tests/tests.proptest-regressions @@ -0,0 +1,11 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 3335351554 386647235 3584534272 266266105 # shrinks to ref elements = [Reset] +xs 1928044643 2253320966 2424427606 448028530 # shrinks to ref ansi_string = [27] +xs 1984785545 2043478319 191885995 1442765875 # shrinks to ref elements = [Text([27])] +xs 4274884889 8924921 2258884976 859679705 # shrinks to ref elements = [Text([27, 91, 109])] +xs 428132133 722552347 3851126282 1913029940 # shrinks to ref elements = [Text([27, 91, 58])] diff --git a/fwdansi/tests/tests.rs b/fwdansi/tests/tests.rs new file mode 100644 index 000000000..5ecaecee0 --- /dev/null +++ b/fwdansi/tests/tests.rs @@ -0,0 +1,99 @@ +#[macro_use] +extern crate proptest; +extern crate fwdansi; +extern crate termcolor; + +use fwdansi::write_ansi; +use proptest::prelude::*; +use std::io; +use termcolor::{Ansi, Color, ColorSpec, WriteColor}; + +proptest! { + #[test] + fn check_no_crash(ref ansi_string in any::>()) { + let mut ansi = Ansi::new(Vec::with_capacity(ansi_string.len())); + prop_assert!(write_ansi(&mut ansi, &ansi_string).is_ok()); + } + + #[test] + fn ansi_idempotent(ref elements in prop::collection::vec(Element::any(), 0..100)) { + // first, write the test string into an ANSI buffer. + let mut original = Ansi::new(Vec::new()); + for e in elements { + e.write(&mut original).unwrap(); + } + + // recover the original string, and forward it using `write_ansi`. + let original = original.into_inner(); + let mut forwarded = Ansi::new(Vec::with_capacity(original.len())); + prop_assert!(write_ansi(&mut forwarded, &original).is_ok()); + prop_assert_eq!(original, forwarded.into_inner()); + } +} + +#[derive(Debug, Clone)] +enum Element { + ColorSpec(ColorSpec), + Reset, + Text(Vec), +} + +fn any_opt_color() -> impl Strategy> { + let color = prop_oneof![ + Just(Color::Black), + Just(Color::Red), + Just(Color::Green), + Just(Color::Yellow), + Just(Color::Blue), + Just(Color::Magenta), + Just(Color::Cyan), + Just(Color::White), + any::().prop_map(Color::Ansi256), + any::<[u8; 3]>().prop_map(|[r, g, b]| Color::Rgb(r, g, b)), + ]; + prop::option::weighted(0.9, color) +} + +prop_compose! { + fn any_color_spec()( + bold in any::(), + underline in any::(), + intense in any::(), + fg_color in any_opt_color(), + bg_color in any_opt_color(), + ) -> ColorSpec { + let mut spec = ColorSpec::new(); + spec.set_bold(bold) + .set_underline(underline) + .set_intense(intense) + .set_fg(fg_color) + .set_bg(bg_color); + spec + } +} + +impl Element { + fn any() -> impl Strategy { + prop_oneof![ + Just(Element::Reset), + any_color_spec().prop_map(Element::ColorSpec), + any::>() + .prop_filter_map( + "ignored empty SGR", + |v| if v.windows(3).find(|w| w == b"\x1b[m").is_some() { + None + } else { + Some(Element::Text(v)) + } + ), + ] + } + + fn write(&self, mut w: W) -> io::Result<()> { + match self { + Element::ColorSpec(cs) => w.set_color(cs), + Element::Reset => w.reset(), + Element::Text(text) => w.write_all(text), + } + } +} diff --git a/git2-curl/.cargo-checksum.json b/git2-curl/.cargo-checksum.json new file mode 100644 index 000000000..89dd24cc9 --- /dev/null +++ b/git2-curl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd"} \ No newline at end of file diff --git a/git2-curl/Cargo.toml b/git2-curl/Cargo.toml new file mode 100644 index 000000000..3b3b752b7 --- /dev/null +++ b/git2-curl/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "git2-curl" +version = "0.9.0" +authors = ["Alex Crichton "] +description = "Backend for an HTTP transport in libgit2 powered by libcurl.\n\nIntended to be used with the git2 crate.\n" +homepage = "https://github.com/alexcrichton/git2-rs" +documentation = "https://docs.rs/git2-curl" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/git2-rs" + +[[test]] +name = "all" +harness = false +[dependencies.curl] +version = "0.4" + +[dependencies.git2] +version = "0.8" +default-features = false + +[dependencies.log] +version = "0.4" + +[dependencies.url] +version = "1.0" +[dev-dependencies.civet] +version = "0.11" + +[dev-dependencies.conduit] +version = "0.8" + +[dev-dependencies.conduit-git-http-backend] +version = "0.8" + +[dev-dependencies.tempfile] +version = "3.0" diff --git a/git2-curl/LICENSE-APACHE b/git2-curl/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/git2-curl/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/git2-curl/LICENSE-MIT b/git2-curl/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/git2-curl/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/git2-curl/src/lib.rs b/git2-curl/src/lib.rs new file mode 100644 index 000000000..90fe412b7 --- /dev/null +++ b/git2-curl/src/lib.rs @@ -0,0 +1,280 @@ +//! A crate for using libcurl as a backend for HTTP git requests with git2-rs. +//! +//! This crate provides one public function, `register`, which will register +//! a custom HTTP transport with libcurl for any HTTP requests made by libgit2. +//! At this time the `register` function is unsafe for the same reasons that +//! `git2::transport::register` is also unsafe. +//! +//! It is not recommended to use this crate wherever possible. The current +//! libcurl backend used, `curl-rust`, only supports executing a request in one +//! method call implying no streaming support. This consequently means that +//! when a repository is cloned the entire contents of the repo are downloaded +//! into memory, and *then* written off to disk by libgit2 afterwards. It +//! should be possible to alleviate this problem in the future. +//! +//! > **NOTE**: At this time this crate likely does not support a `git push` +//! > operation, only clones. + +#![doc(html_root_url = "http://alexcrichton.com/git2-rs")] + +extern crate git2; +extern crate curl; +extern crate url; +#[macro_use] extern crate log; + +use std::error; +use std::io::prelude::*; +use std::io::{self, Cursor}; +use std::str; +use std::sync::{Once, ONCE_INIT, Arc, Mutex}; + +use curl::easy::{Easy, List}; +use git2::Error; +use git2::transport::{SmartSubtransportStream}; +use git2::transport::{Transport, SmartSubtransport, Service}; +use url::Url; + +struct CurlTransport { + handle: Arc>, + /// The URL of the remote server, e.g. "https://github.com/user/repo" + /// + /// This is an empty string until the first action is performed. + /// If there is an HTTP redirect, this will be updated with the new URL. + base_url: Arc> +} + +struct CurlSubtransport { + handle: Arc>, + service: &'static str, + url_path: &'static str, + base_url: Arc>, + method: &'static str, + reader: Option>>, + sent_request: bool, +} + +/// Register the libcurl backend for HTTP requests made by libgit2. +/// +/// This function takes one parameter, a `handle`, which is used to perform all +/// future HTTP requests. The handle can be previously configured with +/// information such as proxies, SSL information, etc. +/// +/// This function is unsafe largely for the same reasons as +/// `git2::transport::register`: +/// +/// * The function needs to be synchronized against all other creations of +/// transport (any API calls to libgit2). +/// * The function will leak `handle` as once registered it is not currently +/// possible to unregister the backend. +/// +/// This function may be called concurrently, but only the first `handle` will +/// be used. All others will be discarded. +pub unsafe fn register(handle: Easy) { + static INIT: Once = ONCE_INIT; + + let handle = Arc::new(Mutex::new(handle)); + let handle2 = handle.clone(); + INIT.call_once(move || { + git2::transport::register("http", move |remote| { + factory(remote, handle.clone()) + }).unwrap(); + git2::transport::register("https", move |remote| { + factory(remote, handle2.clone()) + }).unwrap(); + }); +} + +fn factory(remote: &git2::Remote, handle: Arc>) + -> Result { + Transport::smart(remote, true, CurlTransport { + handle: handle, + base_url: Arc::new(Mutex::new(String::new())) + }) +} + +impl SmartSubtransport for CurlTransport { + fn action(&self, url: &str, action: Service) + -> Result, Error> { + let mut base_url = self.base_url.lock().unwrap(); + if base_url.len() == 0 { + *base_url = url.to_string(); + } + let (service, path, method) = match action { + Service::UploadPackLs => { + ("upload-pack", "/info/refs?service=git-upload-pack", "GET") + } + Service::UploadPack => { + ("upload-pack", "/git-upload-pack", "POST") + } + Service::ReceivePackLs => { + ("receive-pack", "/info/refs?service=git-receive-pack", "GET") + } + Service::ReceivePack => { + ("receive-pack", "/git-receive-pack", "POST") + } + }; + info!("action {} {}", service, path); + Ok(Box::new(CurlSubtransport { + handle: self.handle.clone(), + service: service, + url_path: path, + base_url: self.base_url.clone(), + method: method, + reader: None, + sent_request: false, + })) + } + + fn close(&self) -> Result<(), Error> { + Ok(()) // ... + } +} + +impl CurlSubtransport { + fn err>>(&self, err: E) -> io::Error { + io::Error::new(io::ErrorKind::Other, err) + } + + fn execute(&mut self, data: &[u8]) -> io::Result<()> { + if self.sent_request { + return Err(self.err("already sent HTTP request")) + } + let agent = format!("git/1.0 (git2-curl {})", env!("CARGO_PKG_VERSION")); + + // Parse our input URL to figure out the host + let url = format!("{}{}", self.base_url.lock().unwrap(), self.url_path); + let parsed = try!(Url::parse(&url).map_err(|_| { + self.err("invalid url, failed to parse") + })); + let host = match parsed.host_str() { + Some(host) => host, + None => return Err(self.err("invalid url, did not have a host")), + }; + + // Prep the request + debug!("request to {}", url); + let mut h = self.handle.lock().unwrap(); + try!(h.url(&url)); + try!(h.useragent(&agent)); + try!(h.follow_location(true)); + match self.method { + "GET" => try!(h.get(true)), + "PUT" => try!(h.put(true)), + "POST" => try!(h.post(true)), + other => try!(h.custom_request(other)), + } + + let mut headers = List::new(); + try!(headers.append(&format!("Host: {}", host))); + if data.len() > 0 { + try!(h.post_fields_copy(data)); + try!(headers.append(&format!("Accept: application/x-git-{}-result", + self.service))); + try!(headers.append(&format!("Content-Type: \ + application/x-git-{}-request", + self.service))); + } else { + try!(headers.append("Accept: */*")); + } + try!(headers.append("Expect:")); + try!(h.http_headers(headers)); + + let mut content_type = None; + let mut data = Vec::new(); + { + let mut h = h.transfer(); + + // Look for the Content-Type header + try!(h.header_function(|header| { + let header = match str::from_utf8(header) { + Ok(s) => s, + Err(..) => return true, + }; + let mut parts = header.splitn(2, ": "); + let name = parts.next().unwrap(); + let value = match parts.next() { + Some(value) => value, + None => return true, + }; + if name.eq_ignore_ascii_case("Content-Type") { + content_type = Some(value.trim().to_string()); + } + + true + })); + + // Collect the request's response in-memory + try!(h.write_function(|buf| { + data.extend_from_slice(buf); + Ok(buf.len()) + })); + + // Send the request + try!(h.perform()); + } + + let code = try!(h.response_code()); + if code != 200 { + return Err(self.err(&format!("failed to receive HTTP 200 response: \ + got {}", code)[..])) + } + + // Check returned headers + let expected = match self.method { + "GET" => format!("application/x-git-{}-advertisement", + self.service), + _ => format!("application/x-git-{}-result", self.service), + }; + match content_type { + Some(ref content_type) if *content_type != expected => { + return Err(self.err(&format!("expected a Content-Type header \ + with `{}` but found `{}`", + expected, content_type)[..])) + } + Some(..) => {} + None => { + return Err(self.err(&format!("expected a Content-Type header \ + with `{}` but didn't find one", + expected)[..])) + } + } + + // Ok, time to read off some data. + let rdr = Cursor::new(data); + self.reader = Some(rdr); + + // If there was a redirect, update the `CurlTransport` with the new base. + if let Ok(Some(effective_url)) = h.effective_url() { + let new_base = if effective_url.ends_with(self.url_path) { + // Strip the action from the end. + &effective_url[..effective_url.len() - self.url_path.len()] + } else { + // I'm not sure if this code path makes sense, but it's what + // libgit does. + effective_url + }; + *self.base_url.lock().unwrap() = new_base.to_string(); + } + + Ok(()) + } +} + +impl Read for CurlSubtransport { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if self.reader.is_none() { + try!(self.execute(&[])); + } + self.reader.as_mut().unwrap().read(buf) + } +} + +impl Write for CurlSubtransport { + fn write(&mut self, data: &[u8]) -> io::Result { + if self.reader.is_none() { + try!(self.execute(data)); + } + Ok(data.len()) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} diff --git a/git2-curl/tests/all.rs b/git2-curl/tests/all.rs new file mode 100644 index 000000000..941020e18 --- /dev/null +++ b/git2-curl/tests/all.rs @@ -0,0 +1,68 @@ +extern crate conduit_git_http_backend as git_backend; +extern crate git2_curl; +extern crate civet; +extern crate conduit; +extern crate curl; +extern crate git2; +extern crate tempfile; + +use civet::{Server, Config}; +use std::fs::File; +use std::path::Path; +use tempfile::TempDir; + +const PORT: u16 = 7848; + +fn main() { + unsafe { + git2_curl::register(curl::easy::Easy::new()); + } + + // Spin up a server for git-http-backend + let td = TempDir::new().unwrap(); + let mut cfg = Config::new(); + cfg.port(PORT).threads(1); + let _a = Server::start(cfg, git_backend::Serve(td.path().to_path_buf())); + + // Prep a repo with one file called `foo` + let sig = git2::Signature::now("foo", "bar").unwrap(); + let r1 = git2::Repository::init(td.path()).unwrap(); + File::create(&td.path().join(".git").join("git-daemon-export-ok")).unwrap(); + { + let mut index = r1.index().unwrap(); + File::create(&td.path().join("foo")).unwrap(); + index.add_path(Path::new("foo")).unwrap(); + index.write().unwrap(); + let tree_id = index.write_tree().unwrap(); + r1.commit(Some("HEAD"), &sig, &sig, "test", + &r1.find_tree(tree_id).unwrap(), + &[]).unwrap(); + } + + // Clone through the git-http-backend + let td2 = TempDir::new().unwrap(); + let r = git2::Repository::clone(&format!("http://localhost:{}", PORT), + td2.path()).unwrap(); + assert!(File::open(&td2.path().join("foo")).is_ok()); + { + File::create(&td.path().join("bar")).unwrap(); + let mut index = r1.index().unwrap(); + index.add_path(&Path::new("bar")).unwrap(); + index.write().unwrap(); + let tree_id = index.write_tree().unwrap(); + let parent = r1.head().ok().and_then(|h| h.target()).unwrap(); + let parent = r1.find_commit(parent).unwrap(); + r1.commit(Some("HEAD"), &sig, &sig, "test", + &r1.find_tree(tree_id).unwrap(), + &[&parent]).unwrap(); + } + + let mut remote = r.find_remote("origin").unwrap(); + remote.fetch(&["refs/heads/*:refs/heads/*"], None, None).unwrap(); + let b = r.find_branch("master", git2::BranchType::Local).unwrap(); + let id = b.get().target().unwrap(); + let obj = r.find_object(id, None).unwrap(); + r.reset(&obj, git2::ResetType::Hard, None).unwrap();; + + assert!(File::open(&td2.path().join("bar")).is_ok()); +} diff --git a/git2/.cargo-checksum.json b/git2/.cargo-checksum.json new file mode 100644 index 000000000..abb7852b7 --- /dev/null +++ b/git2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0"} \ No newline at end of file diff --git a/git2/.pc/.quilt_patches b/git2/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/git2/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/git2/.pc/.quilt_series b/git2/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/git2/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/git2/.pc/.version b/git2/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/git2/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/git2/.pc/applied-patches b/git2/.pc/applied-patches new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/git2/.pc/applied-patches @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/git2/.pc/disable-vendor.patch/.timestamp b/git2/.pc/disable-vendor.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/git2/.pc/disable-vendor.patch/Cargo.toml b/git2/.pc/disable-vendor.patch/Cargo.toml new file mode 100644 index 000000000..f3f58fc42 --- /dev/null +++ b/git2/.pc/disable-vendor.patch/Cargo.toml @@ -0,0 +1,76 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "git2" +version = "0.8.0" +authors = ["Alex Crichton "] +description = "Bindings to libgit2 for interoperating with git repositories. This library is\nboth threadsafe and memory safe and allows both reading and writing git\nrepositories.\n" +homepage = "https://github.com/alexcrichton/git2-rs" +documentation = "https://docs.rs/git2" +readme = "README.md" +keywords = ["git"] +categories = ["api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/git2-rs" +[dependencies.bitflags] +version = "1.0" + +[dependencies.libc] +version = "0.2" + +[dependencies.libgit2-sys] +version = "0.7.11" + +[dependencies.log] +version = "0.4" + +[dependencies.url] +version = "1.0" +[dev-dependencies.docopt] +version = "1.0" + +[dev-dependencies.serde] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3.7" + +[dev-dependencies.thread-id] +version = "3.3.0" + +[dev-dependencies.time] +version = "0.1.39" + +[features] +curl = ["libgit2-sys/curl"] +default = ["ssh", "https", "curl", "ssh_key_from_memory"] +https = ["libgit2-sys/https", "openssl-sys", "openssl-probe"] +ssh = ["libgit2-sys/ssh"] +ssh_key_from_memory = ["libgit2-sys/ssh_key_from_memory"] +unstable = [] +vendored-openssl = ["openssl-sys/vendored"] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] +version = "0.1" +optional = true + +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9.0" +optional = true +[badges.appveyor] +repository = "alexcrichton/git2-rs" + +[badges.travis-ci] +repository = "alexcrichton/git2-rs" diff --git a/git2/Cargo.toml b/git2/Cargo.toml new file mode 100644 index 000000000..8b8bae62c --- /dev/null +++ b/git2/Cargo.toml @@ -0,0 +1,75 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "git2" +version = "0.8.0" +authors = ["Alex Crichton "] +description = "Bindings to libgit2 for interoperating with git repositories. This library is\nboth threadsafe and memory safe and allows both reading and writing git\nrepositories.\n" +homepage = "https://github.com/alexcrichton/git2-rs" +documentation = "https://docs.rs/git2" +readme = "README.md" +keywords = ["git"] +categories = ["api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/git2-rs" +[dependencies.bitflags] +version = "1.0" + +[dependencies.libc] +version = "0.2" + +[dependencies.libgit2-sys] +version = "0.7.11" + +[dependencies.log] +version = "0.4" + +[dependencies.url] +version = "1.0" +[dev-dependencies.docopt] +version = "1.0" + +[dev-dependencies.serde] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3.7" + +[dev-dependencies.thread-id] +version = "3.3.0" + +[dev-dependencies.time] +version = "0.1.39" + +[features] +curl = ["libgit2-sys/curl"] +default = ["ssh", "https", "curl", "ssh_key_from_memory"] +https = ["libgit2-sys/https", "openssl-sys", "openssl-probe"] +ssh = ["libgit2-sys/ssh"] +ssh_key_from_memory = ["libgit2-sys/ssh_key_from_memory"] +unstable = [] +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] +version = "0.1" +optional = true + +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9.0" +optional = true +[badges.appveyor] +repository = "alexcrichton/git2-rs" + +[badges.travis-ci] +repository = "alexcrichton/git2-rs" diff --git a/git2/LICENSE-APACHE b/git2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/git2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/git2/LICENSE-MIT b/git2/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/git2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/git2/README.md b/git2/README.md new file mode 100644 index 000000000..83c158607 --- /dev/null +++ b/git2/README.md @@ -0,0 +1,64 @@ +# git2-rs + +[![Build Status](https://travis-ci.org/alexcrichton/git2-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/git2-rs) +[![Build Status](https://ci.appveyor.com/api/projects/status/6vem3xgno2kuxnfm?svg=true)](https://ci.appveyor.com/project/alexcrichton/git2-rs) + +[Documentation](https://docs.rs/git2) + +libgit2 bindings for Rust + +```toml +[dependencies] +git2 = "0.7" +``` + +## Version of libgit2 + +Currently this library requires libgit2 0.25.1. The source for libgit2 is +included in the libgit2-sys crate so there's no need to pre-install the libgit2 +library, the libgit2-sys crate will figure that and/or build that for you. + +## Building git2-rs + +```sh +$ git clone https://github.com/alexcrichton/git2-rs +$ cd git2-rs +$ cargo build +``` + +### Automating Testing + +Running tests and handling all of the associated edge cases on every commit +proves tedious very quickly. To automate tests and handle proper stashing and +unstashing of unstaged changes and thus avoid nasty surprises, use the +pre-commit hook found [here][pre-commit-hook] and place it into the +`.git/hooks/` with the name `pre-commit`. You may need to add execution +permissions with `chmod +x`. + + +To skip tests on a simple commit or doc-fixes, use `git commit --no-verify`. + +## Building on OSX 10.10+ + +If the `ssh` feature is enabled (and it is by default) then this library depends +on libssh2 which depends on OpenSSL. To get OpenSSL working follow the +[`openssl` crate's instructions](https://github.com/sfackler/rust-openssl#macos). + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in git2-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[pre-commit-hook]: https://gist.github.com/glfmn/0c5e9e2b41b48007ed3497d11e3dbbfa diff --git a/git2/appveyor.yml b/git2/appveyor.yml new file mode 100644 index 000000000..0182bfd8b --- /dev/null +++ b/git2/appveyor.yml @@ -0,0 +1,19 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + - set CARGO_TARGET_DIR=%APPVEYOR_BUILD_FOLDER%\target + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo test --no-default-features --target %TARGET% + - cargo run --manifest-path systest/Cargo.toml --target %TARGET% diff --git a/git2/debian/patches/disable-vendor.patch b/git2/debian/patches/disable-vendor.patch new file mode 100644 index 000000000..6b7b66909 --- /dev/null +++ b/git2/debian/patches/disable-vendor.patch @@ -0,0 +1,10 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -61,7 +61,6 @@ + ssh = ["libgit2-sys/ssh"] + ssh_key_from_memory = ["libgit2-sys/ssh_key_from_memory"] + unstable = [] +-vendored-openssl = ["openssl-sys/vendored"] + [target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] + version = "0.1" + optional = true diff --git a/git2/debian/patches/series b/git2/debian/patches/series new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/git2/debian/patches/series @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/git2/examples/add.rs b/git2/examples/add.rs new file mode 100644 index 000000000..3167cb074 --- /dev/null +++ b/git2/examples/add.rs @@ -0,0 +1,85 @@ +/* + * libgit2 "add" example - shows how to modify the index + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] +#![allow(trivial_casts)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use std::path::Path; +use docopt::Docopt; +use git2::Repository; + +#[derive(Deserialize)] +struct Args { + arg_spec: Vec, + flag_dry_run: bool, + flag_verbose: bool, + flag_update: bool, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let repo = try!(Repository::open(&Path::new("."))); + let mut index = try!(repo.index()); + + let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 { + let status = repo.status_file(path).unwrap(); + + let ret = if status.contains(git2::Status::WT_MODIFIED) || + status.contains(git2::Status::WT_NEW) { + println!("add '{}'", path.display()); + 0 + } else { + 1 + }; + + if args.flag_dry_run {1} else {ret} + }; + let cb = if args.flag_verbose || args.flag_update { + Some(cb as &mut git2::IndexMatchedPath) + } else { + None + }; + + if args.flag_update { + try!(index.update_all(args.arg_spec.iter(), cb)); + } else { + try!(index.add_all(args.arg_spec.iter(), git2::IndexAddOption::DEFAULT, cb)); + } + + try!(index.write()); + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: add [options] [--] [..] + +Options: + -n, --dry-run dry run + -v, --verbose be verbose + -u, --update update tracked files + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/blame.rs b/git2/examples/blame.rs new file mode 100644 index 000000000..5f7bee368 --- /dev/null +++ b/git2/examples/blame.rs @@ -0,0 +1,106 @@ +/* + * libgit2 "blame" example - shows how to use the blame API + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::{Repository, BlameOptions}; +use std::path::Path; +use std::io::{BufReader, BufRead}; + +#[derive(Deserialize)] #[allow(non_snake_case)] +struct Args { + arg_path: String, + arg_spec: Option, + flag_M: bool, + flag_C: bool, + flag_F: bool, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let repo = try!(Repository::open(".")); + let path = Path::new(&args.arg_path[..]); + + // Prepare our blame options + let mut opts = BlameOptions::new(); + opts.track_copies_same_commit_moves(args.flag_M) + .track_copies_same_commit_copies(args.flag_C) + .first_parent(args.flag_F); + + let mut commit_id = "HEAD".to_string(); + + // Parse spec + if let Some(spec) = args.arg_spec.as_ref() { + + let revspec = try!(repo.revparse(spec)); + + let (oldest, newest) = if revspec.mode().contains(git2::RevparseMode::SINGLE) { + (None, revspec.from()) + } else if revspec.mode().contains(git2::RevparseMode::RANGE) { + (revspec.from(), revspec.to()) + } else { + (None, None) + }; + + if let Some(commit) = oldest { + opts.oldest_commit(commit.id()); + } + + if let Some(commit) = newest { + opts.newest_commit(commit.id()); + if !commit.id().is_zero() { + commit_id = format!("{}", commit.id()) + } + } + + } + + let spec = format!("{}:{}", commit_id, path.display()); + let blame = try!(repo.blame_file(path, Some(&mut opts))); + let object = try!(repo.revparse_single(&spec[..])); + let blob = try!(repo.find_blob(object.id())); + let reader = BufReader::new(blob.content()); + + for (i, line) in reader.lines().enumerate() { + if let (Ok(line), Some(hunk)) = (line, blame.get_line(i+1)) { + let sig = hunk.final_signature(); + println!("{} {} <{}> {}", hunk.final_commit_id(), + String::from_utf8_lossy(sig.name_bytes()), + String::from_utf8_lossy(sig.email_bytes()), line); + } + } + + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: blame [options] [] + +Options: + -M find line moves within and across files + -C find line copies within and across files + -F follow only the first parent commits +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/cat-file.rs b/git2/examples/cat-file.rs new file mode 100644 index 000000000..68117bd88 --- /dev/null +++ b/git2/examples/cat-file.rs @@ -0,0 +1,142 @@ +/* + * libgit2 "cat-file" example - shows how to print data from the ODB + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use std::io::{self, Write}; + +use docopt::Docopt; +use git2::{Repository, ObjectType, Blob, Commit, Signature, Tag, Tree}; + +#[derive(Deserialize)] +struct Args { + arg_object: String, + flag_t: bool, + flag_s: bool, + flag_e: bool, + flag_p: bool, + flag_q: bool, + flag_v: bool, + flag_git_dir: Option, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or("."); + let repo = try!(Repository::open(path)); + + let obj = try!(repo.revparse_single(&args.arg_object)); + if args.flag_v && !args.flag_q { + println!("{} {}\n--", obj.kind().unwrap().str(), obj.id()); + } + + if args.flag_t { + println!("{}", obj.kind().unwrap().str()); + } else if args.flag_s || args.flag_e { + /* ... */ + } else if args.flag_p { + match obj.kind() { + Some(ObjectType::Blob) => { + show_blob(obj.as_blob().unwrap()); + } + Some(ObjectType::Commit) => { + show_commit(obj.as_commit().unwrap()); + } + Some(ObjectType::Tag) => { + show_tag(obj.as_tag().unwrap()); + } + Some(ObjectType::Tree) => { + show_tree(obj.as_tree().unwrap()); + } + Some(ObjectType::Any) | None => { + println!("unknown {}", obj.id()) + } + } + } + Ok(()) +} + +fn show_blob(blob: &Blob) { + io::stdout().write_all(blob.content()).unwrap(); +} + +fn show_commit(commit: &Commit) { + println!("tree {}", commit.tree_id()); + for parent in commit.parent_ids() { + println!("parent {}", parent); + } + show_sig("author", Some(commit.author())); + show_sig("committer", Some(commit.committer())); + if let Some(msg) = commit.message() { + println!("\n{}", msg); + } +} + +fn show_tag(tag: &Tag) { + println!("object {}", tag.target_id()); + println!("type {}", tag.target_type().unwrap().str()); + println!("tag {}", tag.name().unwrap()); + show_sig("tagger", tag.tagger()); + + if let Some(msg) = tag.message() { + println!("\n{}", msg); + } +} + +fn show_tree(tree: &Tree) { + for entry in tree.iter() { + println!("{:06o} {} {}\t{}", + entry.filemode(), + entry.kind().unwrap().str(), + entry.id(), + entry.name().unwrap()); + } +} + +fn show_sig(header: &str, sig: Option) { + let sig = match sig { Some(s) => s, None => return }; + let offset = sig.when().offset_minutes(); + let (sign, offset) = if offset < 0 {('-', -offset)} else {('+', offset)}; + let (hours, minutes) = (offset / 60, offset % 60); + println!("{} {} {} {}{:02}{:02}", + header, sig, sig.when().seconds(), sign, hours, minutes); + +} + +fn main() { + const USAGE: &'static str = " +usage: cat-file (-t | -s | -e | -p) [options] + +Options: + -t show the object type + -s show the object size + -e suppress all output + -p pretty print the contents of the object + -q suppress output + -v use verbose output + --git-dir use the specified directory as the base directory + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/clone.rs b/git2/examples/clone.rs new file mode 100644 index 000000000..3bd72bc2e --- /dev/null +++ b/git2/examples/clone.rs @@ -0,0 +1,124 @@ +/* + * libgit2 "clone" example + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::build::{RepoBuilder, CheckoutBuilder}; +use git2::{RemoteCallbacks, Progress, FetchOptions}; +use std::cell::RefCell; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; + +#[derive(Deserialize)] +struct Args { + arg_url: String, + arg_path: String, +} + +struct State { + progress: Option>, + total: usize, + current: usize, + path: Option, + newline: bool, +} + +fn print(state: &mut State) { + let stats = state.progress.as_ref().unwrap(); + let network_pct = (100 * stats.received_objects()) / stats.total_objects(); + let index_pct = (100 * stats.indexed_objects()) / stats.total_objects(); + let co_pct = if state.total > 0 { + (100 * state.current) / state.total + } else { + 0 + }; + let kbytes = stats.received_bytes() / 1024; + if stats.received_objects() == stats.total_objects() { + if !state.newline { + println!(""); + state.newline = true; + } + print!("Resolving deltas {}/{}\r", stats.indexed_deltas(), + stats.total_deltas()); + } else { + print!("net {:3}% ({:4} kb, {:5}/{:5}) / idx {:3}% ({:5}/{:5}) \ + / chk {:3}% ({:4}/{:4}) {}\r", + network_pct, kbytes, stats.received_objects(), + stats.total_objects(), + index_pct, stats.indexed_objects(), stats.total_objects(), + co_pct, state.current, state.total, + state.path + .as_ref() + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_default()) + } + io::stdout().flush().unwrap(); +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let state = RefCell::new(State { + progress: None, + total: 0, + current: 0, + path: None, + newline: false, + }); + let mut cb = RemoteCallbacks::new(); + cb.transfer_progress(|stats| { + let mut state = state.borrow_mut(); + state.progress = Some(stats.to_owned()); + print(&mut *state); + true + }); + + let mut co = CheckoutBuilder::new(); + co.progress(|path, cur, total| { + let mut state = state.borrow_mut(); + state.path = path.map(|p| p.to_path_buf()); + state.current = cur; + state.total = total; + print(&mut *state); + }); + + let mut fo = FetchOptions::new(); + fo.remote_callbacks(cb); + try!(RepoBuilder::new().fetch_options(fo).with_checkout(co) + .clone(&args.arg_url, Path::new(&args.arg_path))); + println!(""); + + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: add [options] + +Options: + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} + diff --git a/git2/examples/diff.rs b/git2/examples/diff.rs new file mode 100644 index 000000000..8664a0e30 --- /dev/null +++ b/git2/examples/diff.rs @@ -0,0 +1,284 @@ +/* + * libgit2 "diff" example - shows how to use the diff API + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use std::str; + +use docopt::Docopt; +use git2::{Repository, Error, Object, ObjectType, DiffOptions, Diff}; +use git2::{DiffFindOptions, DiffFormat}; + +#[derive(Deserialize)] #[allow(non_snake_case)] +struct Args { + arg_from_oid: Option, + arg_to_oid: Option, + flag_patch: bool, + flag_cached: bool, + flag_nocached: bool, + flag_name_only: bool, + flag_name_status: bool, + flag_raw: bool, + flag_format: Option, + flag_color: bool, + flag_no_color: bool, + flag_R: bool, + flag_text: bool, + flag_ignore_space_at_eol: bool, + flag_ignore_space_change: bool, + flag_ignore_all_space: bool, + flag_ignored: bool, + flag_untracked: bool, + flag_patience: bool, + flag_minimal: bool, + flag_stat: bool, + flag_numstat: bool, + flag_shortstat: bool, + flag_summary: bool, + flag_find_renames: Option, + flag_find_copies: Option, + flag_find_copies_harder: bool, + flag_break_rewrites: bool, + flag_unified: Option, + flag_inter_hunk_context: Option, + flag_abbrev: Option, + flag_src_prefix: Option, + flag_dst_prefix: Option, + flag_git_dir: Option, +} + +const RESET: &'static str = "\u{1b}[m"; +const BOLD: &'static str = "\u{1b}[1m"; +const RED: &'static str = "\u{1b}[31m"; +const GREEN: &'static str = "\u{1b}[32m"; +const CYAN: &'static str = "\u{1b}[36m"; + +#[derive(PartialEq, Eq, Copy, Clone)] +enum Cache { Normal, Only, None } + +fn run(args: &Args) -> Result<(), Error> { + let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or("."); + let repo = try!(Repository::open(path)); + + // Prepare our diff options based on the arguments given + let mut opts = DiffOptions::new(); + opts.reverse(args.flag_R) + .force_text(args.flag_text) + .ignore_whitespace_eol(args.flag_ignore_space_at_eol) + .ignore_whitespace_change(args.flag_ignore_space_change) + .ignore_whitespace(args.flag_ignore_all_space) + .include_ignored(args.flag_ignored) + .include_untracked(args.flag_untracked) + .patience(args.flag_patience) + .minimal(args.flag_minimal); + if let Some(amt) = args.flag_unified { opts.context_lines(amt); } + if let Some(amt) = args.flag_inter_hunk_context { opts.interhunk_lines(amt); } + if let Some(amt) = args.flag_abbrev { opts.id_abbrev(amt); } + if let Some(ref s) = args.flag_src_prefix { opts.old_prefix(&s); } + if let Some(ref s) = args.flag_dst_prefix { opts.new_prefix(&s); } + if let Some("diff-index") = args.flag_format.as_ref().map(|s| &s[..]) { + opts.id_abbrev(40); + } + + // Prepare the diff to inspect + let t1 = try!(tree_to_treeish(&repo, args.arg_from_oid.as_ref())); + let t2 = try!(tree_to_treeish(&repo, args.arg_to_oid.as_ref())); + let head = try!(tree_to_treeish(&repo, Some(&"HEAD".to_string()))).unwrap(); + let mut diff = match (t1, t2, args.cache()) { + (Some(t1), Some(t2), _) => { + try!(repo.diff_tree_to_tree(t1.as_tree(), t2.as_tree(), + Some(&mut opts))) + } + (t1, None, Cache::None) => { + let t1 = t1.unwrap_or(head); + try!(repo.diff_tree_to_workdir(t1.as_tree(), Some(&mut opts))) + } + (t1, None, Cache::Only) => { + let t1 = t1.unwrap_or(head); + try!(repo.diff_tree_to_index(t1.as_tree(), None, Some(&mut opts))) + } + (Some(t1), None, _) => { + try!(repo.diff_tree_to_workdir_with_index(t1.as_tree(), + Some(&mut opts))) + } + (None, None, _) => { + try!(repo.diff_index_to_workdir(None, Some(&mut opts))) + } + (None, Some(_), _) => unreachable!(), + }; + + // Apply rename and copy detection if requested + if args.flag_break_rewrites || args.flag_find_copies_harder || + args.flag_find_renames.is_some() || args.flag_find_copies.is_some() + { + let mut opts = DiffFindOptions::new(); + if let Some(t) = args.flag_find_renames { + opts.rename_threshold(t); + opts.renames(true); + } + if let Some(t) = args.flag_find_copies { + opts.copy_threshold(t); + opts.copies(true); + } + opts.copies_from_unmodified(args.flag_find_copies_harder) + .rewrites(args.flag_break_rewrites); + try!(diff.find_similar(Some(&mut opts))); + } + + // Generate simple output + let stats = args.flag_stat | args.flag_numstat | args.flag_shortstat | + args.flag_summary; + if stats { + try!(print_stats(&diff, args)); + } + if args.flag_patch || !stats { + if args.color() { print!("{}", RESET); } + let mut last_color = None; + try!(diff.print(args.diff_format(), |_delta, _hunk, line| { + if args.color() { + let next = match line.origin() { + '+' => Some(GREEN), + '-' => Some(RED), + '>' => Some(GREEN), + '<' => Some(RED), + 'F' => Some(BOLD), + 'H' => Some(CYAN), + _ => None + }; + if args.color() && next != last_color { + if last_color == Some(BOLD) || next == Some(BOLD) { + print!("{}", RESET); + } + print!("{}", next.unwrap_or(RESET)); + last_color = next; + } + } + + match line.origin() { + '+' | '-' | ' ' => print!("{}", line.origin()), + _ => {} + } + print!("{}", str::from_utf8(line.content()).unwrap()); + true + })); + if args.color() { print!("{}", RESET); } + } + + Ok(()) +} + +fn print_stats(diff: &Diff, args: &Args) -> Result<(), Error> { + let stats = try!(diff.stats()); + let mut format = git2::DiffStatsFormat::NONE; + if args.flag_stat { + format |= git2::DiffStatsFormat::FULL; + } + if args.flag_shortstat { + format |= git2::DiffStatsFormat::SHORT; + } + if args.flag_numstat { + format |= git2::DiffStatsFormat::NUMBER; + } + if args.flag_summary { + format |= git2::DiffStatsFormat::INCLUDE_SUMMARY; + } + let buf = try!(stats.to_buf(format, 80)); + print!("{}", str::from_utf8(&*buf).unwrap()); + Ok(()) +} + +fn tree_to_treeish<'a>(repo: &'a Repository, arg: Option<&String>) + -> Result>, Error> { + let arg = match arg { Some(s) => s, None => return Ok(None) }; + let obj = try!(repo.revparse_single(arg)); + let tree = try!(obj.peel(ObjectType::Tree)); + Ok(Some(tree)) +} + +impl Args { + fn cache(&self) -> Cache { + if self.flag_cached {Cache::Only} + else if self.flag_nocached {Cache::None} + else {Cache::Normal} + } + fn color(&self) -> bool { self.flag_color && !self.flag_no_color } + fn diff_format(&self) -> DiffFormat { + if self.flag_patch {DiffFormat::Patch} + else if self.flag_name_only {DiffFormat::NameOnly} + else if self.flag_name_status {DiffFormat::NameStatus} + else if self.flag_raw {DiffFormat::Raw} + else { + match self.flag_format.as_ref().map(|s| &s[..]) { + Some("name") => DiffFormat::NameOnly, + Some("name-status") => DiffFormat::NameStatus, + Some("raw") => DiffFormat::Raw, + Some("diff-index") => DiffFormat::Raw, + _ => DiffFormat::Patch, + } + } + } +} + +fn main() { + const USAGE: &'static str = " +usage: diff [options] [ []] + +Options: + -p, --patch show output in patch format + --cached use staged changes as diff + --nocached do not use staged changes + --name-only show only names of changed files + --name-status show only names and status changes + --raw generate the raw format + --format= specify format for stat summary + --color use color output + --no-color never use color output + -R swap two inputs + -a, --text treat all files as text + --ignore-space-at-eol ignore changes in whitespace at EOL + -b, --ignore-space-change ignore changes in amount of whitespace + -w, --ignore-all-space ignore whitespace when comparing lines + --ignored show ignored files as well + --untracked show untracked files + --patience generate diff using the patience algorithm + --minimal spend extra time to find smallest diff + --stat generate a diffstat + --numstat similar to --stat, but more machine friendly + --shortstat only output last line of --stat + --summary output condensed summary of header info + -M, --find-renames set threshold for findind renames (default 50) + -C, --find-copies set threshold for finding copies (default 50) + --find-copies-harder inspect unmodified files for sources of copies + -B, --break-rewrites break complete rewrite changes into pairs + -U, --unified lints of context to show + --inter-hunk-context maximum lines of change between hunks + --abbrev length to abbreviate commits to + --src-prefix show given source prefix instead of 'a/' + --dst-prefix show given destinction prefix instead of 'b/' + --git-dir path to git repository to use + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/fetch.rs b/git2/examples/fetch.rs new file mode 100644 index 000000000..c667d7b63 --- /dev/null +++ b/git2/examples/fetch.rs @@ -0,0 +1,128 @@ +/* + * libgit2 "fetch" example - shows how to fetch remote data + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::{Repository, RemoteCallbacks, AutotagOption, FetchOptions}; +use std::io::{self, Write}; +use std::str; + +#[derive(Deserialize)] +struct Args { + arg_remote: Option, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let repo = try!(Repository::open(".")); + let remote = args.arg_remote.as_ref().map(|s| &s[..]).unwrap_or("origin"); + + // Figure out whether it's a named remote or a URL + println!("Fetching {} for repo", remote); + let mut cb = RemoteCallbacks::new(); + let mut remote = try!(repo.find_remote(remote).or_else(|_| { + repo.remote_anonymous(remote) + })); + cb.sideband_progress(|data| { + print!("remote: {}", str::from_utf8(data).unwrap()); + io::stdout().flush().unwrap(); + true + }); + + // This callback gets called for each remote-tracking branch that gets + // updated. The message we output depends on whether it's a new one or an + // update. + cb.update_tips(|refname, a, b| { + if a.is_zero() { + println!("[new] {:20} {}", b, refname); + } else { + println!("[updated] {:10}..{:10} {}", a, b, refname); + } + true + }); + + // Here we show processed and total objects in the pack and the amount of + // received data. Most frontends will probably want to show a percentage and + // the download rate. + cb.transfer_progress(|stats| { + if stats.received_objects() == stats.total_objects() { + print!("Resolving deltas {}/{}\r", stats.indexed_deltas(), + stats.total_deltas()); + } else if stats.total_objects() > 0 { + print!("Received {}/{} objects ({}) in {} bytes\r", + stats.received_objects(), + stats.total_objects(), + stats.indexed_objects(), + stats.received_bytes()); + } + io::stdout().flush().unwrap(); + true + }); + + // Download the packfile and index it. This function updates the amount of + // received data and the indexer stats which lets you inform the user about + // progress. + let mut fo = FetchOptions::new(); + fo.remote_callbacks(cb); + try!(remote.download(&[], Some(&mut fo))); + + { + // If there are local objects (we got a thin pack), then tell the user + // how many objects we saved from having to cross the network. + let stats = remote.stats(); + if stats.local_objects() > 0 { + println!("\rReceived {}/{} objects in {} bytes (used {} local \ + objects)", stats.indexed_objects(), + stats.total_objects(), stats.received_bytes(), + stats.local_objects()); + } else { + println!("\rReceived {}/{} objects in {} bytes", + stats.indexed_objects(), stats.total_objects(), + stats.received_bytes()); + } + } + + // Disconnect the underlying connection to prevent from idling. + remote.disconnect(); + + // Update the references in the remote's namespace to point to the right + // commits. This may be needed even if there was no packfile to download, + // which can happen e.g. when the branches have been changed but all the + // needed objects are available locally. + try!(remote.update_tips(None, true, + AutotagOption::Unspecified, None)); + + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: fetch [options] [] + +Options: + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/init.rs b/git2/examples/init.rs new file mode 100644 index 000000000..0f6b83809 --- /dev/null +++ b/git2/examples/init.rs @@ -0,0 +1,152 @@ +/* + * libgit2 "init" example - shows how to initialize a new repo + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::{Repository, RepositoryInitOptions, RepositoryInitMode, Error}; +use std::path::{PathBuf, Path}; + +#[derive(Deserialize)] +struct Args { + arg_directory: String, + flag_quiet: bool, + flag_bare: bool, + flag_template: Option, + flag_separate_git_dir: Option, + flag_initial_commit: bool, + flag_shared: Option, +} + +fn run(args: &Args) -> Result<(), Error> { + let mut path = PathBuf::from(&args.arg_directory); + let repo = if !args.flag_bare && args.flag_template.is_none() && + args.flag_shared.is_none() && + args.flag_separate_git_dir.is_none() { + try!(Repository::init(&path)) + } else { + let mut opts = RepositoryInitOptions::new(); + opts.bare(args.flag_bare); + if let Some(ref s) = args.flag_template { + opts.template_path(Path::new(s)); + } + + // If you specified a separate git directory, then initialize + // the repository at that path and use the second path as the + // working directory of the repository (with a git-link file) + if let Some(ref s) = args.flag_separate_git_dir { + opts.workdir_path(&path); + path = PathBuf::from(s); + } + + if let Some(ref s) = args.flag_shared { + opts.mode(try!(parse_shared(s))); + } + try!(Repository::init_opts(&path, &opts)) + }; + + // Print a message to stdout like "git init" does + if !args.flag_quiet { + if args.flag_bare || args.flag_separate_git_dir.is_some() { + path = repo.path().to_path_buf(); + } else { + path = repo.workdir().unwrap().to_path_buf(); + } + println!("Initialized empty Git repository in {}", path.display()); + } + + if args.flag_initial_commit { + try!(create_initial_commit(&repo)); + println!("Created empty initial commit"); + } + + Ok(()) +} + +/// Unlike regular "git init", this example shows how to create an initial empty +/// commit in the repository. This is the helper function that does that. +fn create_initial_commit(repo: &Repository) -> Result<(), Error> { + // First use the config to initialize a commit signature for the user. + let sig = try!(repo.signature()); + + // Now let's create an empty tree for this commit + let tree_id = { + let mut index = try!(repo.index()); + + // Outside of this example, you could call index.add_path() + // here to put actual files into the index. For our purposes, we'll + // leave it empty for now. + + try!(index.write_tree()) + }; + + let tree = try!(repo.find_tree(tree_id)); + + // Ready to create the initial commit. + // + // Normally creating a commit would involve looking up the current HEAD + // commit and making that be the parent of the initial commit, but here this + // is the first commit so there will be no parent. + try!(repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])); + + Ok(()) +} + +fn parse_shared(shared: &str) -> Result { + match shared { + "false" | "umask" => Ok(git2::RepositoryInitMode::SHARED_UMASK), + "true" | "group" => Ok(git2::RepositoryInitMode::SHARED_GROUP), + "all" | "world" => Ok(git2::RepositoryInitMode::SHARED_ALL), + _ => { + if shared.starts_with('0') { + match u32::from_str_radix(&shared[1..], 8).ok() { + Some(n) => { + Ok(RepositoryInitMode::from_bits_truncate(n)) + } + None => { + Err(Error::from_str("invalid octal value for --shared")) + } + } + } else { + Err(Error::from_str("unknown value for --shared")) + } + } + } +} + +fn main() { + const USAGE: &'static str = " +usage: init [options] + +Options: + -q, --quiet don't print information to stdout + --bare initialize a new bare repository + --template use as an initialization template + --separate-git-dir use as the .git directory + --initial-commit create an initial empty commit + --shared permissions to create the repository with +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/log.rs b/git2/examples/log.rs new file mode 100644 index 000000000..70e8145da --- /dev/null +++ b/git2/examples/log.rs @@ -0,0 +1,263 @@ +/* + * libgit2 "log" example - shows how to walk history and get commit info + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +#[macro_use] +extern crate serde_derive; +extern crate docopt; +extern crate git2; +extern crate time; + +use std::str; +use docopt::Docopt; +use git2::{Repository, Signature, Commit, ObjectType, Time, DiffOptions}; +use git2::{Pathspec, Error, DiffFormat}; + +#[derive(Deserialize)] +struct Args { + arg_commit: Vec, + arg_spec: Vec, + flag_topo_order: bool, + flag_date_order: bool, + flag_reverse: bool, + flag_author: Option, + flag_committer: Option, + flag_grep: Option, + flag_git_dir: Option, + flag_skip: Option, + flag_max_count: Option, + flag_merges: bool, + flag_no_merges: bool, + flag_no_min_parents: bool, + flag_no_max_parents: bool, + flag_max_parents: Option, + flag_min_parents: Option, + flag_patch: bool, +} + +fn run(args: &Args) -> Result<(), Error> { + let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or("."); + let repo = try!(Repository::open(path)); + let mut revwalk = try!(repo.revwalk()); + + // Prepare the revwalk based on CLI parameters + let base = if args.flag_reverse {git2::Sort::REVERSE} else {git2::Sort::NONE}; + revwalk.set_sorting(base | if args.flag_topo_order { + git2::Sort::TOPOLOGICAL + } else if args.flag_date_order { + git2::Sort::TIME + } else { + git2::Sort::NONE + }); + for commit in &args.arg_commit { + if commit.starts_with('^') { + let obj = try!(repo.revparse_single(&commit[1..])); + try!(revwalk.hide(obj.id())); + continue + } + let revspec = try!(repo.revparse(commit)); + if revspec.mode().contains(git2::RevparseMode::SINGLE) { + try!(revwalk.push(revspec.from().unwrap().id())); + } else { + let from = revspec.from().unwrap().id(); + let to = revspec.to().unwrap().id(); + try!(revwalk.push(to)); + if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) { + let base = try!(repo.merge_base(from, to)); + let o = try!(repo.find_object(base, Some(ObjectType::Commit))); + try!(revwalk.push(o.id())); + } + try!(revwalk.hide(from)); + } + } + if args.arg_commit.is_empty() { + try!(revwalk.push_head()); + } + + // Prepare our diff options and pathspec matcher + let (mut diffopts, mut diffopts2) = (DiffOptions::new(), DiffOptions::new()); + for spec in &args.arg_spec { + diffopts.pathspec(spec); + diffopts2.pathspec(spec); + } + let ps = try!(Pathspec::new(args.arg_spec.iter())); + + // Filter our revwalk based on the CLI parameters + macro_rules! filter_try { + ($e:expr) => (match $e { Ok(t) => t, Err(e) => return Some(Err(e)) }) + } + let revwalk = revwalk.filter_map(|id| { + let id = filter_try!(id); + let commit = filter_try!(repo.find_commit(id)); + let parents = commit.parents().len(); + if parents < args.min_parents() { return None } + if let Some(n) = args.max_parents() { + if parents >= n { return None } + } + if !args.arg_spec.is_empty() { + match commit.parents().len() { + 0 => { + let tree = filter_try!(commit.tree()); + let flags = git2::PathspecFlags::NO_MATCH_ERROR; + if ps.match_tree(&tree, flags).is_err() { return None } + } + _ => { + let m = commit.parents().all(|parent| { + match_with_parent(&repo, &commit, &parent, &mut diffopts) + .unwrap_or(false) + }); + if !m { return None } + } + } + } + if !sig_matches(&commit.author(), &args.flag_author) { return None } + if !sig_matches(&commit.committer(), &args.flag_committer) { return None } + if !log_message_matches(commit.message(), &args.flag_grep) { return None } + Some(Ok(commit)) + }).skip(args.flag_skip.unwrap_or(0)).take(args.flag_max_count.unwrap_or(!0)); + + // print! + for commit in revwalk { + let commit = try!(commit); + print_commit(&commit); + if !args.flag_patch || commit.parents().len() > 1 { continue } + let a = if commit.parents().len() == 1 { + let parent = try!(commit.parent(0)); + Some(try!(parent.tree())) + } else { + None + }; + let b = try!(commit.tree()); + let diff = try!(repo.diff_tree_to_tree(a.as_ref(), Some(&b), + Some(&mut diffopts2))); + try!(diff.print(DiffFormat::Patch, |_delta, _hunk, line| { + match line.origin() { + ' ' | '+' | '-' => print!("{}", line.origin()), + _ => {} + } + print!("{}", str::from_utf8(line.content()).unwrap()); + true + })); + } + + Ok(()) +} + +fn sig_matches(sig: &Signature, arg: &Option) -> bool { + match *arg { + Some(ref s) => { + sig.name().map(|n| n.contains(s)).unwrap_or(false) || + sig.email().map(|n| n.contains(s)).unwrap_or(false) + } + None => true + } +} + +fn log_message_matches(msg: Option<&str>, grep: &Option) -> bool { + match (grep, msg) { + (&None, _) => true, + (&Some(_), None) => false, + (&Some(ref s), Some(msg)) => msg.contains(s), + } +} + +fn print_commit(commit: &Commit) { + println!("commit {}", commit.id()); + + if commit.parents().len() > 1 { + print!("Merge:"); + for id in commit.parent_ids() { + print!(" {:.8}", id); + } + println!(""); + } + + let author = commit.author(); + println!("Author: {}", author); + print_time(&author.when(), "Date: "); + println!(""); + + for line in String::from_utf8_lossy(commit.message_bytes()).lines() { + println!(" {}", line); + } + println!(""); +} + +fn print_time(time: &Time, prefix: &str) { + let (offset, sign) = match time.offset_minutes() { + n if n < 0 => (-n, '-'), + n => (n, '+'), + }; + let (hours, minutes) = (offset / 60, offset % 60); + let ts = time::Timespec::new(time.seconds() + + (time.offset_minutes() as i64) * 60, 0); + let time = time::at(ts); + + println!("{}{} {}{:02}{:02}", prefix, + time.strftime("%a %b %e %T %Y").unwrap(), sign, hours, minutes); + +} + +fn match_with_parent(repo: &Repository, commit: &Commit, parent: &Commit, + opts: &mut DiffOptions) -> Result { + let a = try!(parent.tree()); + let b = try!(commit.tree()); + let diff = try!(repo.diff_tree_to_tree(Some(&a), Some(&b), Some(opts))); + Ok(diff.deltas().len() > 0) +} + +impl Args { + fn min_parents(&self) -> usize { + if self.flag_no_min_parents { return 0 } + self.flag_min_parents.unwrap_or(if self.flag_merges {2} else {0}) + } + + fn max_parents(&self) -> Option { + if self.flag_no_max_parents { return None } + self.flag_max_parents.or(if self.flag_no_merges {Some(1)} else {None}) + } +} + +fn main() { + const USAGE: &'static str = " +usage: log [options] [..] [--] [..] + +Options: + --topo-order sort commits in topological order + --date-order sort commits in date order + --reverse sort commits in reverse + --author author to sort by + --committer committer to sort by + --grep pattern to filter commit messages by + --git-dir alternative git directory to use + --skip number of commits to skip + -n, --max-count maximum number of commits to show + --merges only show merge commits + --no-merges don't show merge commits + --no-min-parents don't require a minimum number of parents + --no-max-parents don't require a maximum number of parents + --max-parents specify a maximum number of parents for a commit + --min-parents specify a minimum number of parents for a commit + -p, --patch show commit diff + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/ls-remote.rs b/git2/examples/ls-remote.rs new file mode 100644 index 000000000..5da9575f7 --- /dev/null +++ b/git2/examples/ls-remote.rs @@ -0,0 +1,63 @@ +/* + * libgit2 "ls-remote" example + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::{Repository, Direction}; + +#[derive(Deserialize)] +struct Args { + arg_remote: String, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let repo = try!(Repository::open(".")); + let remote = &args.arg_remote; + let mut remote = try!(repo.find_remote(remote).or_else(|_| { + repo.remote_anonymous(remote) + })); + + // Connect to the remote and call the printing function for each of the + // remote references. + let connection = try!(remote.connect_auth(Direction::Fetch, None, None)); + + // Get the list of references on the remote and print out their name next to + // what they point to. + for head in try!(connection.list()).iter() { + println!("{}\t{}", head.oid(), head.name()); + } + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: ls-remote [option] + +Options: + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/rev-list.rs b/git2/examples/rev-list.rs new file mode 100644 index 000000000..db9bd82ca --- /dev/null +++ b/git2/examples/rev-list.rs @@ -0,0 +1,97 @@ +/* + * libgit2 "rev-list" example - shows how to transform a rev-spec into a list + * of commit ids + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::{Repository, Error, Revwalk, Oid}; + +#[derive(Deserialize)] +struct Args { + arg_spec: Vec, + flag_topo_order: bool, + flag_date_order: bool, + flag_reverse: bool, + flag_not: Vec, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let repo = try!(Repository::open(".")); + let mut revwalk = try!(repo.revwalk()); + + let base = if args.flag_reverse {git2::Sort::REVERSE} else {git2::Sort::NONE}; + revwalk.set_sorting(base | if args.flag_topo_order { + git2::Sort::TOPOLOGICAL + } else if args.flag_date_order { + git2::Sort::TIME + } else { + git2::Sort::NONE + }); + + let specs = args.flag_not.iter().map(|s| (s, true)) + .chain(args.arg_spec.iter().map(|s| (s, false))) + .map(|(spec, hide)| { + if spec.starts_with('^') {(&spec[1..], !hide)} else {(&spec[..], hide)} + }); + for (spec, hide) in specs { + let id = if spec.contains("..") { + let revspec = try!(repo.revparse(spec)); + if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) { + return Err(Error::from_str("merge bases not implemented")) + } + try!(push(&mut revwalk, revspec.from().unwrap().id(), !hide)); + revspec.to().unwrap().id() + } else { + try!(repo.revparse_single(spec)).id() + }; + try!(push(&mut revwalk, id, hide)); + } + + for id in revwalk { + let id = try!(id); + println!("{}", id); + } + Ok(()) +} + +fn push(revwalk: &mut Revwalk, id: Oid, hide: bool) -> Result<(), Error> { + if hide {revwalk.hide(id)} else {revwalk.push(id)} +} + +fn main() { + const USAGE: &'static str = " +usage: rev-list [options] [--] ... + +Options: + --topo-order sort commits in topological order + --date-order sort commits in date order + --reverse sort commits in reverse + --not don't show + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} + diff --git a/git2/examples/rev-parse.rs b/git2/examples/rev-parse.rs new file mode 100644 index 000000000..f2416f7b4 --- /dev/null +++ b/git2/examples/rev-parse.rs @@ -0,0 +1,70 @@ +/* + * libgit2 "rev-parse" example - shows how to parse revspecs + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use docopt::Docopt; +use git2::Repository; + +#[derive(Deserialize)] +struct Args { + arg_spec: String, + flag_git_dir: Option, +} + +fn run(args: &Args) -> Result<(), git2::Error> { + let path = args.flag_git_dir.as_ref().map(|s| &s[..]).unwrap_or("."); + let repo = try!(Repository::open(path)); + + let revspec = try!(repo.revparse(&args.arg_spec)); + + if revspec.mode().contains(git2::RevparseMode::SINGLE) { + println!("{}", revspec.from().unwrap().id()); + } else if revspec.mode().contains(git2::RevparseMode::RANGE) { + let to = revspec.to().unwrap(); + let from = revspec.from().unwrap(); + println!("{}", to.id()); + + if revspec.mode().contains(git2::RevparseMode::MERGE_BASE) { + let base = try!(repo.merge_base(from.id(), to.id())); + println!("{}", base); + } + + println!("^{}", from.id()); + } else { + return Err(git2::Error::from_str("invalid results from revparse")) + } + Ok(()) +} + +fn main() { + const USAGE: &'static str = " +usage: rev-parse [options] + +Options: + --git-dir directory for the git repository to check +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/status.rs b/git2/examples/status.rs new file mode 100644 index 000000000..87ca6ec31 --- /dev/null +++ b/git2/examples/status.rs @@ -0,0 +1,369 @@ +/* + * libgit2 "status" example - shows how to use the status APIs + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use std::str; +use std::time::Duration; +use docopt::Docopt; +use git2::{Repository, Error, StatusOptions, ErrorCode, SubmoduleIgnore}; + +#[derive(Deserialize)] +struct Args { + arg_spec: Vec, + flag_short: bool, + flag_porcelain: bool, + flag_branch: bool, + flag_z: bool, + flag_ignored: bool, + flag_untracked_files: Option, + flag_ignore_submodules: Option, + flag_git_dir: Option, + flag_repeat: bool, + flag_list_submodules: bool, +} + +#[derive(Eq, PartialEq)] +enum Format { Long, Short, Porcelain } + +fn run(args: &Args) -> Result<(), Error> { + let path = args.flag_git_dir.clone().unwrap_or_else(|| ".".to_string()); + let repo = try!(Repository::open(&path)); + if repo.is_bare() { + return Err(Error::from_str("cannot report status on bare repository")) + } + + let mut opts = StatusOptions::new(); + opts.include_ignored(args.flag_ignored); + match args.flag_untracked_files.as_ref().map(|s| &s[..]) { + Some("no") => { opts.include_untracked(false); } + Some("normal") => { opts.include_untracked(true); } + Some("all") => { + opts.include_untracked(true).recurse_untracked_dirs(true); + } + Some(_) => return Err(Error::from_str("invalid untracked-files value")), + None => {} + } + match args.flag_ignore_submodules.as_ref().map(|s| &s[..]) { + Some("all") => { opts.exclude_submodules(true); } + Some(_) => return Err(Error::from_str("invalid ignore-submodules value")), + None => {} + } + opts.include_untracked(!args.flag_ignored); + for spec in &args.arg_spec { + opts.pathspec(spec); + } + + loop { + if args.flag_repeat { + println!("\u{1b}[H\u{1b}[2J"); + } + + let statuses = try!(repo.statuses(Some(&mut opts))); + + if args.flag_branch { + try!(show_branch(&repo, &args.format())); + } + if args.flag_list_submodules { + try!(print_submodules(&repo)); + } + + if args.format() == Format::Long { + print_long(&statuses); + } else { + print_short(&repo, &statuses); + } + + if args.flag_repeat { + std::thread::sleep(Duration::new(10, 0)); + } else { + return Ok(()) + } + } +} + +fn show_branch(repo: &Repository, format: &Format) -> Result<(), Error> { + let head = match repo.head() { + Ok(head) => Some(head), + Err(ref e) if e.code() == ErrorCode::UnbornBranch || + e.code() == ErrorCode::NotFound => None, + Err(e) => return Err(e), + }; + let head = head.as_ref().and_then(|h| h.shorthand()); + + if format == &Format::Long { + println!("# On branch {}", + head.unwrap_or("Not currently on any branch")); + } else { + println!("## {}", head.unwrap_or("HEAD (no branch)")); + } + Ok(()) +} + +fn print_submodules(repo: &Repository) -> Result<(), Error> { + let modules = try!(repo.submodules()); + println!("# Submodules"); + for sm in &modules { + println!("# - submodule '{}' at {}", sm.name().unwrap(), + sm.path().display()); + } + Ok(()) +} + +// This function print out an output similar to git's status command in long +// form, including the command-line hints. +fn print_long(statuses: &git2::Statuses) { + let mut header = false; + let mut rm_in_workdir = false; + let mut changes_in_index = false; + let mut changed_in_workdir = false; + + // Print index changes + for entry in statuses.iter().filter(|e| e.status() != git2::Status::CURRENT) { + if entry.status().contains(git2::Status::WT_DELETED) { + rm_in_workdir = true; + } + let istatus = match entry.status() { + s if s.contains(git2::Status::INDEX_NEW) => "new file: ", + s if s.contains(git2::Status::INDEX_MODIFIED) => "modified: ", + s if s.contains(git2::Status::INDEX_DELETED) => "deleted: ", + s if s.contains(git2::Status::INDEX_RENAMED) => "renamed: ", + s if s.contains(git2::Status::INDEX_TYPECHANGE) => "typechange:", + _ => continue, + }; + if !header { + println!("\ +# Changes to be committed: +# (use \"git reset HEAD ...\" to unstage) +#"); + header = true; + } + + let old_path = entry.head_to_index().unwrap().old_file().path(); + let new_path = entry.head_to_index().unwrap().new_file().path(); + match (old_path, new_path) { + (Some(old), Some(new)) if old != new => { + println!("#\t{} {} -> {}", istatus, old.display(), + new.display()); + } + (old, new) => { + println!("#\t{} {}", istatus, old.or(new).unwrap().display()); + } + } + } + + if header { + changes_in_index = true; + println!("#"); + } + header = false; + + // Print workdir changes to tracked files + for entry in statuses.iter() { + // With `Status::OPT_INCLUDE_UNMODIFIED` (not used in this example) + // `index_to_workdir` may not be `None` even if there are no differences, + // in which case it will be a `Delta::Unmodified`. + if entry.status() == git2::Status::CURRENT || + entry.index_to_workdir().is_none() { + continue + } + + let istatus = match entry.status() { + s if s.contains(git2::Status::WT_MODIFIED) => "modified: ", + s if s.contains(git2::Status::WT_DELETED) => "deleted: ", + s if s.contains(git2::Status::WT_RENAMED) => "renamed: ", + s if s.contains(git2::Status::WT_TYPECHANGE) => "typechange:", + _ => continue, + }; + + if !header { + println!("\ +# Changes not staged for commit: +# (use \"git add{} ...\" to update what will be committed) +# (use \"git checkout -- ...\" to discard changes in working directory) +#\ + ", if rm_in_workdir {"/rm"} else {""}); + header = true; + } + + let old_path = entry.index_to_workdir().unwrap().old_file().path(); + let new_path = entry.index_to_workdir().unwrap().new_file().path(); + match (old_path, new_path) { + (Some(old), Some(new)) if old != new => { + println!("#\t{} {} -> {}", istatus, old.display(), + new.display()); + } + (old, new) => { + println!("#\t{} {}", istatus, old.or(new).unwrap().display()); + } + } + } + + if header { + changed_in_workdir = true; + println!("#"); + } + header = false; + + // Print untracked files + for entry in statuses.iter().filter(|e| e.status() == git2::Status::WT_NEW) { + if !header { + println!("\ +# Untracked files +# (use \"git add ...\" to include in what will be committed) +#"); + header = true; + } + let file = entry.index_to_workdir().unwrap().old_file().path().unwrap(); + println!("#\t{}", file.display()); + } + header = false; + + // Print ignored files + for entry in statuses.iter().filter(|e| e.status() == git2::Status::IGNORED) { + if !header { + println!("\ +# Ignored files +# (use \"git add -f ...\" to include in what will be committed) +#"); + header = true; + } + let file = entry.index_to_workdir().unwrap().old_file().path().unwrap(); + println!("#\t{}", file.display()); + } + + if !changes_in_index && changed_in_workdir { + println!("no changes added to commit (use \"git add\" and/or \ + \"git commit -a\")"); + } +} + +// This version of the output prefixes each path with two status columns and +// shows submodule status information. +fn print_short(repo: &Repository, statuses: &git2::Statuses) { + for entry in statuses.iter().filter(|e| e.status() != git2::Status::CURRENT) { + let mut istatus = match entry.status() { + s if s.contains(git2::Status::INDEX_NEW) => 'A', + s if s.contains(git2::Status::INDEX_MODIFIED) => 'M', + s if s.contains(git2::Status::INDEX_DELETED) => 'D', + s if s.contains(git2::Status::INDEX_RENAMED) => 'R', + s if s.contains(git2::Status::INDEX_TYPECHANGE) => 'T', + _ => ' ', + }; + let mut wstatus = match entry.status() { + s if s.contains(git2::Status::WT_NEW) => { + if istatus == ' ' { istatus = '?'; } '?' + } + s if s.contains(git2::Status::WT_MODIFIED) => 'M', + s if s.contains(git2::Status::WT_DELETED) => 'D', + s if s.contains(git2::Status::WT_RENAMED) => 'R', + s if s.contains(git2::Status::WT_TYPECHANGE) => 'T', + _ => ' ', + }; + + if entry.status().contains(git2::Status::IGNORED) { + istatus = '!'; + wstatus = '!'; + } + if istatus == '?' && wstatus == '?' { continue } + let mut extra = ""; + + // A commit in a tree is how submodules are stored, so let's go take a + // look at its status. + // + // TODO: check for GIT_FILEMODE_COMMIT + let status = entry.index_to_workdir().and_then(|diff| { + let ignore = SubmoduleIgnore::Unspecified; + diff.new_file().path_bytes() + .and_then(|s| str::from_utf8(s).ok()) + .and_then(|name| repo.submodule_status(name, ignore).ok()) + }); + if let Some(status) = status { + if status.contains(git2::SubmoduleStatus::WD_MODIFIED) { + extra = " (new commits)"; + } else if status.contains(git2::SubmoduleStatus::WD_INDEX_MODIFIED) || status.contains(git2::SubmoduleStatus::WD_WD_MODIFIED) { + extra = " (modified content)"; + } else if status.contains(git2::SubmoduleStatus::WD_UNTRACKED) { + extra = " (untracked content)"; + } + } + + let (mut a, mut b, mut c) = (None, None, None); + if let Some(diff) = entry.head_to_index() { + a = diff.old_file().path(); + b = diff.new_file().path(); + } + if let Some(diff) = entry.index_to_workdir() { + a = a.or_else(|| diff.old_file().path()); + b = b.or_else(|| diff.old_file().path()); + c = diff.new_file().path(); + } + + match (istatus, wstatus) { + ('R', 'R') => println!("RR {} {} {}{}", a.unwrap().display(), + b.unwrap().display(), c.unwrap().display(), + extra), + ('R', w) => println!("R{} {} {}{}", w, a.unwrap().display(), + b.unwrap().display(), extra), + (i, 'R') => println!("{}R {} {}{}", i, a.unwrap().display(), + c.unwrap().display(), extra), + (i, w) => println!("{}{} {}{}", i, w, a.unwrap().display(), extra), + } + } + + for entry in statuses.iter().filter(|e| e.status() == git2::Status::WT_NEW) { + println!("?? {}", entry.index_to_workdir().unwrap().old_file() + .path().unwrap().display()); + } +} + +impl Args { + fn format(&self) -> Format { + if self.flag_short { Format::Short } + else if self.flag_porcelain || self.flag_z { Format::Porcelain } + else { Format::Long } + } +} + +fn main() { + const USAGE: &'static str = " +usage: status [options] [--] [..] + +Options: + -s, --short show short statuses + --long show longer statuses (default) + --porcelain ?? + -b, --branch show branch information + -z ?? + --ignored show ignored files as well + --untracked-files setting for showing untracked files [no|normal|all] + --ignore-submodules setting for ignoring submodules [all] + --git-dir git directory to analyze + --repeat repeatedly show status, sleeping inbetween + --list-submodules show submodules + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/examples/tag.rs b/git2/examples/tag.rs new file mode 100644 index 000000000..f0ff3a219 --- /dev/null +++ b/git2/examples/tag.rs @@ -0,0 +1,134 @@ +/* + * libgit2 "tag" example - shows how to list, create and delete tags + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ + +#![deny(warnings)] + +extern crate git2; +extern crate docopt; +#[macro_use] +extern crate serde_derive; + +use std::str; +use docopt::Docopt; +use git2::{Repository, Error, Tag, Commit}; + +#[derive(Deserialize)] +struct Args { + arg_tagname: Option, + arg_object: Option, + arg_pattern: Option, + flag_n: Option, + flag_force: bool, + flag_list: bool, + flag_delete: Option, + flag_message: Option, +} + +fn run(args: &Args) -> Result<(), Error> { + let repo = try!(Repository::open(".")); + + if let Some(ref name) = args.arg_tagname { + let target = args.arg_object.as_ref().map(|s| &s[..]).unwrap_or("HEAD"); + let obj = try!(repo.revparse_single(target)); + + if let Some(ref message) = args.flag_message { + let sig = try!(repo.signature()); + try!(repo.tag(name, &obj, &sig, message, args.flag_force)); + } else { + try!(repo.tag_lightweight(name, &obj, args.flag_force)); + } + + } else if let Some(ref name) = args.flag_delete { + let obj = try!(repo.revparse_single(name)); + let id = try!(obj.short_id()); + try!(repo.tag_delete(name)); + println!("Deleted tag '{}' (was {})", name, + str::from_utf8(&*id).unwrap()); + + } else if args.flag_list { + let pattern = args.arg_pattern.as_ref().map(|s| &s[..]).unwrap_or("*"); + for name in try!(repo.tag_names(Some(pattern))).iter() { + let name = name.unwrap(); + let obj = try!(repo.revparse_single(name)); + + if let Some(tag) = obj.as_tag() { + print_tag(tag, args); + } else if let Some(commit) = obj.as_commit() { + print_commit(commit, name, args); + } else { + print_name(name); + } + } + } + Ok(()) +} + +fn print_tag(tag: &Tag, args: &Args) { + print!("{:<16}", tag.name().unwrap()); + if args.flag_n.is_some() { + print_list_lines(tag.message(), args); + } else { + println!(""); + } +} + +fn print_commit(commit: &Commit, name: &str, args: &Args) { + print!("{:<16}", name); + if args.flag_n.is_some() { + print_list_lines(commit.message(), args); + } else { + println!(""); + } +} + +fn print_name(name: &str) { + println!("{}", name); +} + +fn print_list_lines(message: Option<&str>, args: &Args) { + let message = match message { Some(s) => s, None => return }; + let mut lines = message.lines().filter(|l| !l.trim().is_empty()); + if let Some(first) = lines.next() { + print!("{}", first); + } + println!(""); + + for line in lines.take(args.flag_n.unwrap_or(0) as usize) { + print!(" {}", line); + } +} + +fn main() { + const USAGE: &'static str = " +usage: + tag [-a] [-f] [-m ] [] + tag -d + tag [-n ] -l [] + +Options: + -n specify number of lines from teh annotation to print + -f, --force replace an existing tag with the given name + -l, --list list tags with names matching the pattern given + -d, --delete delete the tag specified + -m, --message message for a new tag + -h, --help show this message +"; + + let args = Docopt::new(USAGE).and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(e) => println!("error: {}", e), + } +} diff --git a/git2/src/blame.rs b/git2/src/blame.rs new file mode 100644 index 000000000..9f6b15571 --- /dev/null +++ b/git2/src/blame.rs @@ -0,0 +1,315 @@ +use std::marker; +use {raw, Repository, Oid, signature, Signature}; +use util::{self, Binding}; +use std::path::Path; +use std::ops::Range; +use std::mem; + +/// Opaque structure to hold blame results. +pub struct Blame<'repo> { + raw: *mut raw::git_blame, + _marker: marker::PhantomData<&'repo Repository>, +} + +/// Structure that represents a blame hunk. +pub struct BlameHunk<'blame> { + raw: *mut raw::git_blame_hunk, + _marker: marker::PhantomData<&'blame raw::git_blame>, +} + +/// Blame options +pub struct BlameOptions { + raw: raw::git_blame_options, +} + +/// An iterator over the hunks in a blame. +pub struct BlameIter<'blame> { + range: Range, + blame: &'blame Blame<'blame>, +} + +impl<'repo> Blame<'repo> { + + /// Gets the number of hunks that exist in the blame structure. + pub fn len(&self) -> usize { + unsafe { raw::git_blame_get_hunk_count(self.raw) as usize } + } + + /// Return `true` is there is no hunk in the blame structure. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Gets the blame hunk at the given index. + pub fn get_index(&self, index: usize) -> Option { + unsafe { + let ptr = raw::git_blame_get_hunk_byindex(self.raw(), index as u32); + if ptr.is_null() { + None + } else { + Some(BlameHunk::from_raw_const(ptr)) + } + } + } + + /// Gets the hunk that relates to the given line number in the newest + /// commit. + pub fn get_line(&self, lineno: usize) -> Option { + unsafe { + let ptr = raw::git_blame_get_hunk_byline(self.raw(), lineno); + if ptr.is_null() { + None + } else { + Some(BlameHunk::from_raw_const(ptr)) + } + } + } + + /// Returns an iterator over the hunks in this blame. + pub fn iter(&self) -> BlameIter { + BlameIter { range: 0..self.len(), blame: self } + } + +} + +impl<'blame> BlameHunk<'blame> { + + unsafe fn from_raw_const(raw: *const raw::git_blame_hunk) + -> BlameHunk<'blame> { + BlameHunk { + raw: raw as *mut raw::git_blame_hunk, + _marker: marker::PhantomData, + } + } + + /// Returns OID of the commit where this line was last changed + pub fn final_commit_id(&self) -> Oid { + unsafe { Oid::from_raw(&(*self.raw).final_commit_id) } + } + + /// Returns signature of the commit. + pub fn final_signature(&self) -> Signature { + unsafe { signature::from_raw_const(self, (*self.raw).final_signature) } + } + + /// Returns line number where this hunk begins. + /// + /// Note that the start line is counting from 1. + pub fn final_start_line(&self) -> usize { + unsafe { (*self.raw).final_start_line_number } + } + + /// Returns the OID of the commit where this hunk was found. + /// + /// This will usually be the same as `final_commit_id`, + /// except when `BlameOptions::track_copies_any_commit_copies` has been + /// turned on + pub fn orig_commit_id(&self) -> Oid { + unsafe { Oid::from_raw(&(*self.raw).orig_commit_id) } + } + + /// Returns signature of the commit. + pub fn orig_signature(&self) -> Signature { + unsafe { signature::from_raw_const(self, (*self.raw).orig_signature) } + } + + /// Returns line number where this hunk begins. + /// + /// Note that the start line is counting from 1. + pub fn orig_start_line(&self) -> usize { + unsafe { (*self.raw).orig_start_line_number} + } + + /// Returns path to the file where this hunk originated. + /// + /// Note: `None` could be returned for non-unicode paths on Widnows. + pub fn path(&self) -> Option<&Path> { + unsafe { + if let Some(bytes) = ::opt_bytes(self, (*self.raw).orig_path) { + Some(util::bytes2path(bytes)) + } else { + None + } + } + } + + /// Tests whether this hunk has been tracked to a boundary commit + /// (the root, or the commit specified in git_blame_options.oldest_commit). + pub fn is_boundary(&self) -> bool { + unsafe { (*self.raw).boundary == 1 } + } + + /// Returns number of lines in this hunk. + pub fn lines_in_hunk(&self) -> usize { + unsafe { (*self.raw).lines_in_hunk as usize } + } +} + + +impl Default for BlameOptions { + fn default() -> Self { + Self::new() + } +} + +impl BlameOptions { + + /// Initialize options + pub fn new() -> BlameOptions { + unsafe { + let mut raw: raw::git_blame_options = mem::zeroed(); + assert_eq!( + raw::git_blame_init_options(&mut raw, + raw::GIT_BLAME_OPTIONS_VERSION) + , 0); + + Binding::from_raw(&raw as *const _ as *mut _) + } + } + + fn flag(&mut self, opt: u32, val: bool) -> &mut BlameOptions { + if val { + self.raw.flags |= opt; + } else { + self.raw.flags &= !opt; + } + self + } + + /// Track lines that have moved within a file. + pub fn track_copies_same_file(&mut self, opt: bool) -> &mut BlameOptions { + self.flag(raw::GIT_BLAME_TRACK_COPIES_SAME_FILE, opt) + } + + /// Track lines that have moved across files in the same commit. + pub fn track_copies_same_commit_moves(&mut self, opt: bool) -> &mut BlameOptions { + self.flag(raw::GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES, opt) + } + + /// Track lines that have been copied from another file that exists + /// in the same commit. + pub fn track_copies_same_commit_copies(&mut self, opt: bool) -> &mut BlameOptions { + self.flag(raw::GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES, opt) + } + + /// Track lines that have been copied from another file that exists + /// in any commit. + pub fn track_copies_any_commit_copies(&mut self, opt: bool) -> &mut BlameOptions { + self.flag(raw::GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES, opt) + } + + /// Restrict the search of commits to those reachable following only + /// the first parents. + pub fn first_parent(&mut self, opt: bool) -> &mut BlameOptions { + self.flag(raw::GIT_BLAME_FIRST_PARENT, opt) + } + + /// Setter for the id of the newest commit to consider. + pub fn newest_commit(&mut self, id: Oid) -> &mut BlameOptions { + unsafe { self.raw.newest_commit = *id.raw(); } + self + } + + /// Setter for the id of the oldest commit to consider. + pub fn oldest_commit(&mut self, id: Oid) -> &mut BlameOptions { + unsafe { self.raw.oldest_commit = *id.raw(); } + self + } + +} + +impl<'repo> Binding for Blame<'repo> { + type Raw = *mut raw::git_blame; + + unsafe fn from_raw(raw: *mut raw::git_blame) -> Blame<'repo> { + Blame { raw: raw, _marker: marker::PhantomData } + } + + fn raw(&self) -> *mut raw::git_blame { self.raw } +} + +impl<'repo> Drop for Blame<'repo> { + fn drop(&mut self) { + unsafe { raw::git_blame_free(self.raw) } + } +} + +impl<'blame> Binding for BlameHunk<'blame> { + type Raw = *mut raw::git_blame_hunk; + + unsafe fn from_raw(raw: *mut raw::git_blame_hunk) -> BlameHunk<'blame> { + BlameHunk { raw: raw, _marker: marker::PhantomData } + } + + fn raw(&self) -> *mut raw::git_blame_hunk { self.raw } +} + +impl Binding for BlameOptions { + type Raw = *mut raw::git_blame_options; + + unsafe fn from_raw(opts: *mut raw::git_blame_options) -> BlameOptions { + BlameOptions { raw: *opts } + } + + fn raw(&self) -> *mut raw::git_blame_options { + &self.raw as *const _ as *mut _ + } +} + +impl<'blame> Iterator for BlameIter<'blame> { + type Item = BlameHunk<'blame>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.blame.get_index(i)) + } + + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} + +impl<'blame> DoubleEndedIterator for BlameIter<'blame> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.blame.get_index(i)) + } +} + +impl<'blame> ExactSizeIterator for BlameIter<'blame> {} + +#[cfg(test)] +mod tests { + use std::fs::{self, File}; + use std::path::Path; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let mut index = repo.index().unwrap(); + + let root = repo.path().parent().unwrap(); + fs::create_dir(&root.join("foo")).unwrap(); + File::create(&root.join("foo/bar")).unwrap(); + index.add_path(Path::new("foo/bar")).unwrap(); + + let id = index.write_tree().unwrap(); + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + let id = repo.refname_to_id("HEAD").unwrap(); + let parent = repo.find_commit(id).unwrap(); + let commit = repo.commit(Some("HEAD"), &sig, &sig, "commit", + &tree, &[&parent]).unwrap(); + + let blame = repo.blame_file(Path::new("foo/bar"), None).unwrap(); + + assert_eq!(blame.len(), 1); + assert_eq!(blame.iter().count(), 1); + + let hunk = blame.get_index(0).unwrap(); + assert_eq!(hunk.final_commit_id(), commit); + assert_eq!(hunk.final_signature().name(), sig.name()); + assert_eq!(hunk.final_signature().email(), sig.email()); + assert_eq!(hunk.final_start_line(), 1); + assert_eq!(hunk.path(), Some(Path::new("foo/bar"))); + assert_eq!(hunk.lines_in_hunk(), 0); + assert!(!hunk.is_boundary()) + } + +} + diff --git a/git2/src/blob.rs b/git2/src/blob.rs new file mode 100644 index 000000000..5e255eb6d --- /dev/null +++ b/git2/src/blob.rs @@ -0,0 +1,186 @@ +use std::marker; +use std::mem; +use std::slice; +use std::io; + +use {raw, Oid, Object, Error}; +use util::Binding; + +/// A structure to represent a git [blob][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects +pub struct Blob<'repo> { + raw: *mut raw::git_blob, + _marker: marker::PhantomData>, +} + +impl<'repo> Blob<'repo> { + /// Get the id (SHA1) of a repository blob + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_blob_id(&*self.raw)) } + } + + /// Determine if the blob content is most certainly binary or not. + pub fn is_binary(&self) -> bool { + unsafe { raw::git_blob_is_binary(&*self.raw) == 1 } + } + + /// Get the content of this blob. + pub fn content(&self) -> &[u8] { + unsafe { + let data = raw::git_blob_rawcontent(&*self.raw) as *const u8; + let len = raw::git_blob_rawsize(&*self.raw) as usize; + slice::from_raw_parts(data, len) + } + } + + /// Casts this Blob to be usable as an `Object` + pub fn as_object(&self) -> &Object<'repo> { + unsafe { + &*(self as *const _ as *const Object<'repo>) + } + } + + /// Consumes Blob to be returned as an `Object` + pub fn into_object(self) -> Object<'repo> { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + unsafe { + mem::transmute(self) + } + } +} + +impl<'repo> Binding for Blob<'repo> { + type Raw = *mut raw::git_blob; + + unsafe fn from_raw(raw: *mut raw::git_blob) -> Blob<'repo> { + Blob { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_blob { self.raw } +} + +impl<'repo> ::std::fmt::Debug for Blob<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + f.debug_struct("Blob").field("id", &self.id()).finish() + } +} + +impl<'repo> Clone for Blob<'repo> { + fn clone(&self) -> Self { + self.as_object().clone().into_blob().ok().unwrap() + } +} + +impl<'repo> Drop for Blob<'repo> { + fn drop(&mut self) { + unsafe { raw::git_blob_free(self.raw) } + } +} + +/// A structure to represent a git writestream for blobs +pub struct BlobWriter<'repo> { + raw: *mut raw::git_writestream, + need_cleanup: bool, + _marker: marker::PhantomData>, +} + +impl<'repo> BlobWriter<'repo> { + /// Finalize blob writing stream and write the blob to the object db + pub fn commit(mut self) -> Result { + // After commit we already doesn't need cleanup on drop + self.need_cleanup = false; + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_blob_create_fromstream_commit(&mut raw, self.raw)); + Ok(Binding::from_raw(&raw as *const _)) + } + } +} + +impl<'repo> Binding for BlobWriter<'repo> { + type Raw = *mut raw::git_writestream; + + unsafe fn from_raw(raw: *mut raw::git_writestream) -> BlobWriter<'repo> { + BlobWriter { + raw: raw, + need_cleanup: true, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_writestream { self.raw } +} + +impl<'repo> Drop for BlobWriter<'repo> { + fn drop(&mut self) { + // We need cleanup in case the stream has not been committed + if self.need_cleanup { + unsafe { ((*self.raw).free)(self.raw) } + } + } +} + +impl<'repo> io::Write for BlobWriter<'repo> { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { + let res = ((*self.raw).write)(self.raw, buf.as_ptr() as *const _, buf.len()); + if res < 0 { + Err(io::Error::new(io::ErrorKind::Other, "Write error")) + } else { + Ok(buf.len()) + } + } + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::fs::File; + use std::path::Path; + use tempdir::TempDir; + use Repository; + + #[test] + fn buffer() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let id = repo.blob(&[5, 4, 6]).unwrap(); + let blob = repo.find_blob(id).unwrap(); + + assert_eq!(blob.id(), id); + assert_eq!(blob.content(), [5, 4, 6]); + assert!(blob.is_binary()); + + repo.find_object(id, None).unwrap().as_blob().unwrap(); + repo.find_object(id, None).unwrap().into_blob().ok().unwrap(); + } + + #[test] + fn path() { + let td = TempDir::new("test").unwrap(); + let path = td.path().join("foo"); + File::create(&path).unwrap().write_all(&[7, 8, 9]).unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let id = repo.blob_path(&path).unwrap(); + let blob = repo.find_blob(id).unwrap(); + assert_eq!(blob.content(), [7, 8, 9]); + blob.into_object(); + } + + #[test] + fn stream() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let mut ws = repo.blob_writer(Some(Path::new("foo"))).unwrap(); + let wl = ws.write(&[10, 11, 12]).unwrap(); + assert_eq!(wl, 3); + let id = ws.commit().unwrap(); + let blob = repo.find_blob(id).unwrap(); + assert_eq!(blob.content(), [10, 11, 12]); + blob.into_object(); + } +} diff --git a/git2/src/branch.rs b/git2/src/branch.rs new file mode 100644 index 000000000..3f035ed0d --- /dev/null +++ b/git2/src/branch.rs @@ -0,0 +1,162 @@ +use std::ffi::CString; +use std::marker; +use std::ptr; +use std::str; + +use {raw, Error, Reference, BranchType, References}; +use util::Binding; + +/// A structure to represent a git [branch][1] +/// +/// A branch is currently just a wrapper to an underlying `Reference`. The +/// reference can be accessed through the `get` and `unwrap` methods. +/// +/// [1]: http://git-scm.com/book/en/Git-Branching-What-a-Branch-Is +pub struct Branch<'repo> { + inner: Reference<'repo>, +} + +/// An iterator over the branches inside of a repository. +pub struct Branches<'repo> { + raw: *mut raw::git_branch_iterator, + _marker: marker::PhantomData>, +} + +impl<'repo> Branch<'repo> { + /// Creates Branch type from a Reference + pub fn wrap(reference: Reference) -> Branch { Branch { inner: reference } } + + /// Gain access to the reference that is this branch + pub fn get(&self) -> &Reference<'repo> { &self.inner } + + /// Take ownership of the underlying reference. + pub fn into_reference(self) -> Reference<'repo> { self.inner } + + /// Delete an existing branch reference. + pub fn delete(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_branch_delete(self.get().raw())); } + Ok(()) + } + + /// Determine if the current local branch is pointed at by HEAD. + pub fn is_head(&self) -> bool { + unsafe { raw::git_branch_is_head(&*self.get().raw()) == 1 } + } + + /// Move/rename an existing local branch reference. + pub fn rename(&mut self, new_branch_name: &str, force: bool) + -> Result, Error> { + let mut ret = ptr::null_mut(); + let new_branch_name = try!(CString::new(new_branch_name)); + unsafe { + try_call!(raw::git_branch_move(&mut ret, self.get().raw(), + new_branch_name, force)); + Ok(Branch::wrap(Binding::from_raw(ret))) + } + } + + /// Return the name of the given local or remote branch. + /// + /// May return `Ok(None)` if the name is not valid utf-8. + pub fn name(&self) -> Result, Error> { + self.name_bytes().map(|s| str::from_utf8(s).ok()) + } + + /// Return the name of the given local or remote branch. + pub fn name_bytes(&self) -> Result<&[u8], Error> { + let mut ret = ptr::null(); + unsafe { + try_call!(raw::git_branch_name(&mut ret, &*self.get().raw())); + Ok(::opt_bytes(self, ret).unwrap()) + } + } + + /// Return the reference supporting the remote tracking branch, given a + /// local branch reference. + pub fn upstream<'a>(&'a self) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_branch_upstream(&mut ret, &*self.get().raw())); + Ok(Branch::wrap(Binding::from_raw(ret))) + } + } + + /// Set the upstream configuration for a given local branch. + /// + /// If `None` is specified, then the upstream branch is unset. The name + /// provided is the name of the branch to set as upstream. + pub fn set_upstream(&mut self, + upstream_name: Option<&str>) -> Result<(), Error> { + let upstream_name = try!(::opt_cstr(upstream_name)); + unsafe { + try_call!(raw::git_branch_set_upstream(self.get().raw(), + upstream_name)); + Ok(()) + } + } +} + +impl<'repo> Branches<'repo> { + /// Creates a new iterator from the raw pointer given. + /// + /// This function is unsafe as it is not guaranteed that `raw` is a valid + /// pointer. + pub unsafe fn from_raw(raw: *mut raw::git_branch_iterator) + -> Branches<'repo> { + Branches { + raw: raw, + _marker: marker::PhantomData, + } + } +} + +impl<'repo> Iterator for Branches<'repo> { + type Item = Result<(Branch<'repo>, BranchType), Error>; + fn next(&mut self) -> Option, BranchType), Error>> { + let mut ret = ptr::null_mut(); + let mut typ = raw::GIT_BRANCH_LOCAL; + unsafe { + try_call_iter!(raw::git_branch_next(&mut ret, &mut typ, self.raw)); + let typ = match typ { + raw::GIT_BRANCH_LOCAL => BranchType::Local, + raw::GIT_BRANCH_REMOTE => BranchType::Remote, + n => panic!("unexected branch type: {}", n), + }; + Some(Ok((Branch::wrap(Binding::from_raw(ret)), typ))) + } + } +} + +impl<'repo> Drop for Branches<'repo> { + fn drop(&mut self) { + unsafe { raw::git_branch_iterator_free(self.raw) } + } +} + +#[cfg(test)] +mod tests { + use BranchType; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + let commit = repo.find_commit(target).unwrap(); + + let mut b1 = repo.branch("foo", &commit, false).unwrap(); + assert!(!b1.is_head()); + repo.branch("foo2", &commit, false).unwrap(); + + assert_eq!(repo.branches(None).unwrap().count(), 3); + repo.find_branch("foo", BranchType::Local).unwrap(); + let mut b1 = b1.rename("bar", false).unwrap(); + assert_eq!(b1.name().unwrap(), Some("bar")); + assert!(b1.upstream().is_err()); + b1.set_upstream(Some("master")).unwrap(); + b1.upstream().unwrap(); + b1.set_upstream(None).unwrap(); + + b1.delete().unwrap(); + } +} diff --git a/git2/src/buf.rs b/git2/src/buf.rs new file mode 100644 index 000000000..78e958e2e --- /dev/null +++ b/git2/src/buf.rs @@ -0,0 +1,73 @@ +use std::slice; +use std::str; +use std::ptr; +use std::ops::{Deref, DerefMut}; + +use raw; +use util::Binding; + +/// A structure to wrap an intermediate buffer used by libgit2. +/// +/// A buffer can be thought of a `Vec`, but the `Vec` type is not used to +/// avoid copying data back and forth. +pub struct Buf { + raw: raw::git_buf, +} + +impl Default for Buf { + fn default() -> Self { + Self::new() + } +} + +impl Buf { + /// Creates a new empty buffer. + pub fn new() -> Buf { + ::init(); + unsafe { + Binding::from_raw(&mut raw::git_buf { + ptr: ptr::null_mut(), + size: 0, + asize: 0, + } as *mut _) + } + } + + /// Attempt to view this buffer as a string slice. + /// + /// Returns `None` if the buffer is not valid utf-8. + pub fn as_str(&self) -> Option<&str> { str::from_utf8(&**self).ok() } +} + +impl Deref for Buf { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.raw.ptr as *const u8, + self.raw.size as usize) + } + } +} + +impl DerefMut for Buf { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.raw.ptr as *mut u8, + self.raw.size as usize) + } + } +} + +impl Binding for Buf { + type Raw = *mut raw::git_buf; + unsafe fn from_raw(raw: *mut raw::git_buf) -> Buf { + Buf { raw: *raw } + } + fn raw(&self) -> *mut raw::git_buf { &self.raw as *const _ as *mut _ } +} + +impl Drop for Buf { + fn drop(&mut self) { + unsafe { raw::git_buf_free(&mut self.raw) } + } +} diff --git a/git2/src/build.rs b/git2/src/build.rs new file mode 100644 index 000000000..29b66d69c --- /dev/null +++ b/git2/src/build.rs @@ -0,0 +1,701 @@ +//! Builder-pattern objects for configuration various git operations. + +use std::ffi::{CStr, CString}; +use std::mem; +use std::path::Path; +use std::ptr; +use libc::{c_char, size_t, c_void, c_uint, c_int}; + +use {raw, panic, Error, Repository, FetchOptions, IntoCString}; +use {CheckoutNotificationType, DiffFile, Remote}; +use util::{self, Binding}; + +/// A builder struct which is used to build configuration for cloning a new git +/// repository. +pub struct RepoBuilder<'cb> { + bare: bool, + branch: Option, + local: bool, + hardlinks: bool, + checkout: Option>, + fetch_opts: Option>, + clone_local: Option, + remote_create: Option>>, +} + +/// Type of callback passed to `RepoBuilder::remote_create`. +/// +/// The second and third arguments are the remote's name and the remote's url. +pub type RemoteCreate<'cb> = for<'a> FnMut(&'a Repository, &str, &str) + -> Result, Error> + 'cb; + +/// A builder struct for configuring checkouts of a repository. +pub struct CheckoutBuilder<'cb> { + their_label: Option, + our_label: Option, + ancestor_label: Option, + target_dir: Option, + paths: Vec, + path_ptrs: Vec<*const c_char>, + file_perm: Option, + dir_perm: Option, + disable_filters: bool, + checkout_opts: u32, + progress: Option>>, + notify: Option>>, + notify_flags: CheckoutNotificationType, +} + +/// Checkout progress notification callback. +/// +/// The first argument is the path for the notification, the next is the numver +/// of completed steps so far, and the final is the total number of steps. +pub type Progress<'a> = FnMut(Option<&Path>, usize, usize) + 'a; + +/// Checkout notifications callback. +/// +/// The first argument is the notification type, the next is the path for the +/// the notification, followed by the baseline diff, target diff, and workdir diff. +/// +/// The callback must return a bool specifying whether the checkout should +/// continue. +pub type Notify<'a> = FnMut(CheckoutNotificationType, Option<&Path>, + Option, Option, + Option) -> bool + 'a; + + +impl<'cb> Default for RepoBuilder<'cb> { + fn default() -> Self { + Self::new() + } +} + +/// Options that can be passed to `RepoBuilder::clone_local`. +#[derive(Clone, Copy)] +pub enum CloneLocal { + /// Auto-detect (default) + /// + /// Here libgit2 will bypass the git-aware transport for local paths, but + /// use a normal fetch for `file://` urls. + Auto = raw::GIT_CLONE_LOCAL_AUTO as isize, + + /// Bypass the git-aware transport even for `file://` urls. + Local = raw::GIT_CLONE_LOCAL as isize, + + /// Never bypass the git-aware transport + None = raw::GIT_CLONE_NO_LOCAL as isize, + + /// Bypass the git-aware transport, but don't try to use hardlinks. + NoLinks = raw::GIT_CLONE_LOCAL_NO_LINKS as isize, + + #[doc(hidden)] + __Nonexhaustive = 0xff, +} + +impl<'cb> RepoBuilder<'cb> { + /// Creates a new repository builder with all of the default configuration. + /// + /// When ready, the `clone()` method can be used to clone a new repository + /// using this configuration. + pub fn new() -> RepoBuilder<'cb> { + ::init(); + RepoBuilder { + bare: false, + branch: None, + local: true, + clone_local: None, + hardlinks: true, + checkout: None, + fetch_opts: None, + remote_create: None, + } + } + + /// Indicate whether the repository will be cloned as a bare repository or + /// not. + pub fn bare(&mut self, bare: bool) -> &mut RepoBuilder<'cb> { + self.bare = bare; + self + } + + /// Specify the name of the branch to check out after the clone. + /// + /// If not specified, the remote's default branch will be used. + pub fn branch(&mut self, branch: &str) -> &mut RepoBuilder<'cb> { + self.branch = Some(CString::new(branch).unwrap()); + self + } + + /// Configures options for bypassing the git-aware transport on clone. + /// + /// Bypassing it means that instead of a fetch libgit2 will copy the object + /// database directory instead of figuring out what it needs, which is + /// faster. If possible, it will hardlink the files to save space. + pub fn clone_local(&mut self, clone_local: CloneLocal) -> &mut RepoBuilder<'cb> { + self.clone_local = Some(clone_local); + self + } + + /// Set the flag for bypassing the git aware transport mechanism for local + /// paths. + /// + /// If `true`, the git-aware transport will be bypassed for local paths. If + /// `false`, the git-aware transport will not be bypassed. + #[deprecated(note = "use `clone_local` instead")] + #[doc(hidden)] + pub fn local(&mut self, local: bool) -> &mut RepoBuilder<'cb> { + self.local = local; + self + } + + /// Set the flag for whether hardlinks are used when using a local git-aware + /// transport mechanism. + #[deprecated(note = "use `clone_local` instead")] + #[doc(hidden)] + pub fn hardlinks(&mut self, links: bool) -> &mut RepoBuilder<'cb> { + self.hardlinks = links; + self + } + + /// Configure the checkout which will be performed by consuming a checkout + /// builder. + pub fn with_checkout(&mut self, checkout: CheckoutBuilder<'cb>) + -> &mut RepoBuilder<'cb> { + self.checkout = Some(checkout); + self + } + + /// Options which control the fetch, including callbacks. + /// + /// The callbacks are used for reporting fetch progress, and for acquiring + /// credentials in the event they are needed. + pub fn fetch_options(&mut self, fetch_opts: FetchOptions<'cb>) + -> &mut RepoBuilder<'cb> { + self.fetch_opts = Some(fetch_opts); + self + } + + /// Configures a callback used to create the git remote, prior to its being + /// used to perform the clone operation. + pub fn remote_create(&mut self, f: F) -> &mut RepoBuilder<'cb> + where F: for<'a> FnMut(&'a Repository, &str, &str) + -> Result, Error> + 'cb, + { + self.remote_create = Some(Box::new(f)); + self + } + + /// Clone a remote repository. + /// + /// This will use the options configured so far to clone the specified url + /// into the specified local path. + pub fn clone(&mut self, url: &str, into: &Path) -> Result { + let mut opts: raw::git_clone_options = unsafe { mem::zeroed() }; + unsafe { + try_call!(raw::git_clone_init_options(&mut opts, + raw::GIT_CLONE_OPTIONS_VERSION)); + } + opts.bare = self.bare as c_int; + opts.checkout_branch = self.branch.as_ref().map(|s| { + s.as_ptr() + }).unwrap_or(ptr::null()); + + if let Some(ref local) = self.clone_local { + opts.local = *local as raw::git_clone_local_t; + } else { + opts.local = match (self.local, self.hardlinks) { + (true, false) => raw::GIT_CLONE_LOCAL_NO_LINKS, + (false, _) => raw::GIT_CLONE_NO_LOCAL, + (true, _) => raw::GIT_CLONE_LOCAL_AUTO, + }; + } + + if let Some(ref mut cbs) = self.fetch_opts { + opts.fetch_opts = cbs.raw(); + } + + if let Some(ref mut c) = self.checkout { + unsafe { + c.configure(&mut opts.checkout_opts); + } + } + + if let Some(ref mut callback) = self.remote_create { + opts.remote_cb = Some(remote_create_cb); + opts.remote_cb_payload = callback as *mut _ as *mut _; + } + + let url = try!(CString::new(url)); + let into = try!(into.into_c_string()); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_clone(&mut raw, url, into, &opts)); + Ok(Binding::from_raw(raw)) + } + } +} + +extern fn remote_create_cb(out: *mut *mut raw::git_remote, + repo: *mut raw::git_repository, + name: *const c_char, + url: *const c_char, + payload: *mut c_void) -> c_int { + unsafe { + let repo = Repository::from_raw(repo); + let code = panic::wrap(|| { + let name = CStr::from_ptr(name).to_str().unwrap(); + let url = CStr::from_ptr(url).to_str().unwrap(); + let f = payload as *mut Box; + match (*f)(&repo, name, url) { + Ok(remote) => { + *out = ::remote::remote_into_raw(remote); + 0 + } + Err(e) => e.raw_code(), + } + }); + mem::forget(repo); + code.unwrap_or(-1) + } +} + +impl<'cb> Default for CheckoutBuilder<'cb> { + fn default() -> Self { + Self::new() + } +} + +impl<'cb> CheckoutBuilder<'cb> { + /// Creates a new builder for checkouts with all of its default + /// configuration. + pub fn new() -> CheckoutBuilder<'cb> { + ::init(); + CheckoutBuilder { + disable_filters: false, + dir_perm: None, + file_perm: None, + path_ptrs: Vec::new(), + paths: Vec::new(), + target_dir: None, + ancestor_label: None, + our_label: None, + their_label: None, + checkout_opts: raw::GIT_CHECKOUT_SAFE as u32, + progress: None, + notify: None, + notify_flags: CheckoutNotificationType::empty(), + } + } + + /// Indicate that this checkout should perform a dry run by checking for + /// conflicts but not make any actual changes. + pub fn dry_run(&mut self) -> &mut CheckoutBuilder<'cb> { + self.checkout_opts &= !((1 << 4) - 1); + self.checkout_opts |= raw::GIT_CHECKOUT_NONE as u32; + self + } + + /// Take any action necessary to get the working directory to match the + /// target including potentially discarding modified files. + pub fn force(&mut self) -> &mut CheckoutBuilder<'cb> { + self.checkout_opts &= !((1 << 4) - 1); + self.checkout_opts |= raw::GIT_CHECKOUT_FORCE as u32; + self + } + + /// Indicate that the checkout should be performed safely, allowing new + /// files to be created but not overwriting extisting files or changes. + /// + /// This is the default. + pub fn safe(&mut self) -> &mut CheckoutBuilder<'cb> { + self.checkout_opts &= !((1 << 4) - 1); + self.checkout_opts |= raw::GIT_CHECKOUT_SAFE as u32; + self + } + + fn flag(&mut self, bit: raw::git_checkout_strategy_t, + on: bool) -> &mut CheckoutBuilder<'cb> { + if on { + self.checkout_opts |= bit as u32; + } else { + self.checkout_opts &= !(bit as u32); + } + self + } + + /// In safe mode, create files that don't exist. + /// + /// Defaults to false. + pub fn recreate_missing(&mut self, allow: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_RECREATE_MISSING, allow) + } + + /// In safe mode, apply safe file updates even when there are conflicts + /// instead of canceling the checkout. + /// + /// Defaults to false. + pub fn allow_conflicts(&mut self, allow: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_ALLOW_CONFLICTS, allow) + } + + /// Remove untracked files from the working dir. + /// + /// Defaults to false. + pub fn remove_untracked(&mut self, remove: bool) + -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_REMOVE_UNTRACKED, remove) + } + + /// Remove ignored files from the working dir. + /// + /// Defaults to false. + pub fn remove_ignored(&mut self, remove: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_REMOVE_IGNORED, remove) + } + + /// Only update the contents of files that already exist. + /// + /// If set, files will not be created or deleted. + /// + /// Defaults to false. + pub fn update_only(&mut self, update: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_UPDATE_ONLY, update) + } + + /// Prevents checkout from writing the updated files' information to the + /// index. + /// + /// Defaults to true. + pub fn update_index(&mut self, update: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_DONT_UPDATE_INDEX, !update) + } + + /// Indicate whether the index and git attributes should be refreshed from + /// disk before any operations. + /// + /// Defaults to true, + pub fn refresh(&mut self, refresh: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_NO_REFRESH, !refresh) + } + + /// Skip files with unmerged index entries. + /// + /// Defaults to false. + pub fn skip_unmerged(&mut self, skip: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_SKIP_UNMERGED, skip) + } + + /// Indicate whether the checkout should proceed on conflicts by using the + /// stage 2 version of the file ("ours"). + /// + /// Defaults to false. + pub fn use_ours(&mut self, ours: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_USE_OURS, ours) + } + + /// Indicate whether the checkout should proceed on conflicts by using the + /// stage 3 version of the file ("theirs"). + /// + /// Defaults to false. + pub fn use_theirs(&mut self, theirs: bool) -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_USE_THEIRS, theirs) + } + + /// Indicate whether ignored files should be overwritten during the checkout. + /// + /// Defaults to true. + pub fn overwrite_ignored(&mut self, overwrite: bool) + -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, !overwrite) + } + + /// Indicate whether a normal merge file should be written for conflicts. + /// + /// Defaults to false. + pub fn conflict_style_merge(&mut self, on: bool) + -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_CONFLICT_STYLE_MERGE, on) + } + + /// Specify for which notification types to invoke the notification + /// callback. + /// + /// Defaults to none. + pub fn notify_on(&mut self, notification_types: CheckoutNotificationType) + -> &mut CheckoutBuilder<'cb> { + self.notify_flags = notification_types; + self + } + + /// Indicates whether to include common ancestor data in diff3 format files + /// for conflicts. + /// + /// Defaults to false. + pub fn conflict_style_diff3(&mut self, on: bool) + -> &mut CheckoutBuilder<'cb> { + self.flag(raw::GIT_CHECKOUT_CONFLICT_STYLE_DIFF3, on) + } + + /// Indicate whether to apply filters like CRLF conversion. + pub fn disable_filters(&mut self, disable: bool) + -> &mut CheckoutBuilder<'cb> { + self.disable_filters = disable; + self + } + + /// Set the mode with which new directories are created. + /// + /// Default is 0755 + pub fn dir_perm(&mut self, perm: i32) -> &mut CheckoutBuilder<'cb> { + self.dir_perm = Some(perm); + self + } + + /// Set the mode with which new files are created. + /// + /// The default is 0644 or 0755 as dictated by the blob. + pub fn file_perm(&mut self, perm: i32) -> &mut CheckoutBuilder<'cb> { + self.file_perm = Some(perm); + self + } + + /// Add a path to be checked out. + /// + /// If no paths are specified, then all files are checked out. Otherwise + /// only these specified paths are checked out. + pub fn path(&mut self, path: T) + -> &mut CheckoutBuilder<'cb> { + let path = path.into_c_string().unwrap(); + self.path_ptrs.push(path.as_ptr()); + self.paths.push(path); + self + } + + /// Set the directory to check out to + pub fn target_dir(&mut self, dst: &Path) -> &mut CheckoutBuilder<'cb> { + self.target_dir = Some(dst.into_c_string().unwrap()); + self + } + + /// The name of the common ancestor side of conflicts + pub fn ancestor_label(&mut self, label: &str) -> &mut CheckoutBuilder<'cb> { + self.ancestor_label = Some(CString::new(label).unwrap()); + self + } + + /// The name of the common our side of conflicts + pub fn our_label(&mut self, label: &str) -> &mut CheckoutBuilder<'cb> { + self.our_label = Some(CString::new(label).unwrap()); + self + } + + /// The name of the common their side of conflicts + pub fn their_label(&mut self, label: &str) -> &mut CheckoutBuilder<'cb> { + self.their_label = Some(CString::new(label).unwrap()); + self + } + + /// Set a callback to receive notifications of checkout progress. + pub fn progress(&mut self, cb: F) -> &mut CheckoutBuilder<'cb> + where F: FnMut(Option<&Path>, usize, usize) + 'cb { + self.progress = Some(Box::new(cb) as Box>); + self + } + + /// Set a callback to receive checkout notifications. + /// + /// Callbacks are invoked prior to modifying any files on disk. + /// Returning `false` from the callback will cancel the checkout. + pub fn notify(&mut self, cb: F) -> &mut CheckoutBuilder<'cb> + where F: FnMut(CheckoutNotificationType, Option<&Path>, Option, + Option, Option) -> bool + 'cb + { + self.notify = Some(Box::new(cb) as Box>); + self + } + + /// Configure a raw checkout options based on this configuration. + /// + /// This method is unsafe as there is no guarantee that this structure will + /// outlive the provided checkout options. + pub unsafe fn configure(&mut self, opts: &mut raw::git_checkout_options) { + opts.version = raw::GIT_CHECKOUT_OPTIONS_VERSION; + opts.disable_filters = self.disable_filters as c_int; + opts.dir_mode = self.dir_perm.unwrap_or(0) as c_uint; + opts.file_mode = self.file_perm.unwrap_or(0) as c_uint; + + if !self.path_ptrs.is_empty() { + opts.paths.strings = self.path_ptrs.as_ptr() as *mut _; + opts.paths.count = self.path_ptrs.len() as size_t; + } + + if let Some(ref c) = self.target_dir { + opts.target_directory = c.as_ptr(); + } + if let Some(ref c) = self.ancestor_label { + opts.ancestor_label = c.as_ptr(); + } + if let Some(ref c) = self.our_label { + opts.our_label = c.as_ptr(); + } + if let Some(ref c) = self.their_label { + opts.their_label = c.as_ptr(); + } + if self.progress.is_some() { + let f: raw::git_checkout_progress_cb = progress_cb; + opts.progress_cb = Some(f); + opts.progress_payload = self as *mut _ as *mut _; + } + if self.notify.is_some() { + let f: raw::git_checkout_notify_cb = notify_cb; + opts.notify_cb = Some(f); + opts.notify_payload = self as *mut _ as *mut _; + opts.notify_flags = self.notify_flags.bits() as c_uint; + } + opts.checkout_strategy = self.checkout_opts as c_uint; + } +} + +extern fn progress_cb(path: *const c_char, + completed: size_t, + total: size_t, + data: *mut c_void) { + panic::wrap(|| unsafe { + let payload = &mut *(data as *mut CheckoutBuilder); + let callback = match payload.progress { + Some(ref mut c) => c, + None => return, + }; + let path = if path.is_null() { + None + } else { + Some(util::bytes2path(CStr::from_ptr(path).to_bytes())) + }; + callback(path, completed as usize, total as usize) + }); +} + +extern fn notify_cb(why: raw::git_checkout_notify_t, + path: *const c_char, + baseline: *const raw::git_diff_file, + target: *const raw::git_diff_file, + workdir: *const raw::git_diff_file, + data: *mut c_void) -> c_int { + // pack callback etc + panic::wrap(|| unsafe { + let payload = &mut *(data as *mut CheckoutBuilder); + let callback = match payload.notify { + Some(ref mut c) => c, + None => return 0, + }; + let path = if path.is_null() { + None + } else { + Some(util::bytes2path(CStr::from_ptr(path).to_bytes())) + }; + + let baseline = if baseline.is_null() { + None + } else { + Some(DiffFile::from_raw(baseline)) + }; + + let target = if target.is_null() { + None + } else { + Some(DiffFile::from_raw(target)) + }; + + let workdir = if workdir.is_null() { + None + } else { + Some(DiffFile::from_raw(workdir)) + }; + + let why = CheckoutNotificationType::from_bits_truncate(why as u32); + let keep_going = callback(why, path, baseline, target, workdir); + if keep_going {0} else {1} + }).unwrap_or(2) +} + +#[cfg(test)] +mod tests { + use std::fs; + use std::path::Path; + use tempdir::TempDir; + use super::{CheckoutBuilder, RepoBuilder}; + use {CheckoutNotificationType, Repository}; + + #[test] + fn smoke() { + let r = RepoBuilder::new().clone("/path/to/nowhere", Path::new("foo")); + assert!(r.is_err()); + } + + #[test] + fn smoke2() { + let td = TempDir::new("test").unwrap(); + Repository::init_bare(&td.path().join("bare")).unwrap(); + let url = if cfg!(unix) { + format!("file://{}/bare", td.path().display()) + } else { + format!("file:///{}/bare", td.path().display().to_string() + .replace("\\", "/")) + }; + + let dst = td.path().join("foo"); + RepoBuilder::new().clone(&url, &dst).unwrap(); + fs::remove_dir_all(&dst).unwrap(); + assert!(RepoBuilder::new().branch("foo") + .clone(&url, &dst).is_err()); + } + + /// Issue regression test #365 + #[test] + fn notify_callback() { + let td = TempDir::new("test").unwrap(); + let cd = TempDir::new("external-checkout").unwrap(); + + { + let repo = Repository::init(&td.path()).unwrap(); + + let mut config = repo.config().unwrap(); + config.set_str("user.name", "name").unwrap(); + config.set_str("user.email", "email").unwrap(); + + let mut index = repo.index().unwrap(); + let p = Path::new(td.path()).join("file"); + println!("using path {:?}", p); + fs::File::create(&p).unwrap(); + index.add_path(&Path::new("file")).unwrap(); + let id = index.write_tree().unwrap(); + + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, "initial", + &tree, &[]).unwrap(); + } + + let repo = Repository::open_bare(&td.path().join(".git")).unwrap(); + let tree = repo + .revparse_single(&"master") + .unwrap() + .peel_to_tree() + .unwrap(); + let mut index = repo.index().unwrap(); + index.read_tree(&tree).unwrap(); + + let mut checkout_opts = CheckoutBuilder::new(); + checkout_opts.target_dir(&cd.path()); + checkout_opts.notify_on(CheckoutNotificationType::all()); + checkout_opts.notify(|_notif, _path, baseline, target, workdir| { + assert!(baseline.is_none()); + assert_eq!(target.unwrap().path(), Some(Path::new("file"))); + assert!(workdir.is_none()); + true + }); + repo.checkout_index(Some(&mut index), Some(&mut checkout_opts)) + .unwrap(); + } + +} diff --git a/git2/src/call.rs b/git2/src/call.rs new file mode 100644 index 000000000..3367275bf --- /dev/null +++ b/git2/src/call.rs @@ -0,0 +1,217 @@ +#![macro_use] +use libc; + +use Error; + +macro_rules! call { + (raw::$p:ident ($($e:expr),*)) => ( + raw::$p($(::call::convert(&$e)),*) + ) +} + +macro_rules! try_call { + (raw::$p:ident ($($e:expr),*)) => ({ + match ::call::try(raw::$p($(::call::convert(&$e)),*)) { + Ok(o) => o, + Err(e) => { ::panic::check(); return Err(e) } + } + }) +} + +macro_rules! try_call_iter { + ($($f:tt)*) => { + match call!($($f)*) { + 0 => {} + raw::GIT_ITEROVER => return None, + e => return Some(Err(::call::last_error(e))) + } + } +} + +#[doc(hidden)] +pub trait Convert { + fn convert(&self) -> T; +} + +pub fn convert>(u: &U) -> T { u.convert() } + +pub fn try(ret: libc::c_int) -> Result { + match ret { + n if n < 0 => Err(last_error(n)), + n => Ok(n), + } +} + +pub fn last_error(code: libc::c_int) -> Error { + // nowadays this unwrap is safe as `Error::last_error` always returns + // `Some`. + Error::last_error(code).unwrap() +} + +mod impls { + use std::ffi::CString; + use std::ptr; + + use libc; + + use {raw, ConfigLevel, ResetType, ObjectType, BranchType, Direction}; + use {DiffFormat, FileFavor, SubmoduleIgnore, AutotagOption, FetchPrune}; + use call::Convert; + + impl Convert for T { + fn convert(&self) -> T { *self } + } + + impl Convert for bool { + fn convert(&self) -> libc::c_int { *self as libc::c_int } + } + impl<'a, T> Convert<*const T> for &'a T { + fn convert(&self) -> *const T { *self as *const T } + } + impl<'a, T> Convert<*mut T> for &'a mut T { + fn convert(&self) -> *mut T { &**self as *const T as *mut T } + } + impl Convert<*const T> for *mut T { + fn convert(&self) -> *const T { *self as *const T } + } + + impl Convert<*const libc::c_char> for CString { + fn convert(&self) -> *const libc::c_char { self.as_ptr() } + } + + impl> Convert<*const T> for Option { + fn convert(&self) -> *const T { + self.as_ref().map(|s| s.convert()).unwrap_or(ptr::null()) + } + } + + impl> Convert<*mut T> for Option { + fn convert(&self) -> *mut T { + self.as_ref().map(|s| s.convert()).unwrap_or(ptr::null_mut()) + } + } + + impl Convert for ResetType { + fn convert(&self) -> raw::git_reset_t { + match *self { + ResetType::Soft => raw::GIT_RESET_SOFT, + ResetType::Hard => raw::GIT_RESET_HARD, + ResetType::Mixed => raw::GIT_RESET_MIXED, + } + } + } + + impl Convert for Direction { + fn convert(&self) -> raw::git_direction { + match *self { + Direction::Push => raw::GIT_DIRECTION_PUSH, + Direction::Fetch => raw::GIT_DIRECTION_FETCH, + } + } + } + + impl Convert for ObjectType { + fn convert(&self) -> raw::git_otype { + match *self { + ObjectType::Any => raw::GIT_OBJ_ANY, + ObjectType::Commit => raw::GIT_OBJ_COMMIT, + ObjectType::Tree => raw::GIT_OBJ_TREE, + ObjectType::Blob => raw::GIT_OBJ_BLOB, + ObjectType::Tag => raw::GIT_OBJ_TAG, + } + } + } + + impl Convert for Option { + fn convert(&self) -> raw::git_otype { + self.unwrap_or(ObjectType::Any).convert() + } + } + + impl Convert for BranchType { + fn convert(&self) -> raw::git_branch_t { + match *self { + BranchType::Remote => raw::GIT_BRANCH_REMOTE, + BranchType::Local => raw::GIT_BRANCH_LOCAL, + } + } + } + + impl Convert for Option { + fn convert(&self) -> raw::git_branch_t { + self.map(|s| s.convert()).unwrap_or(raw::GIT_BRANCH_ALL) + } + } + + impl Convert for ConfigLevel { + fn convert(&self) -> raw::git_config_level_t { + match *self { + ConfigLevel::ProgramData => raw::GIT_CONFIG_LEVEL_PROGRAMDATA, + ConfigLevel::System => raw::GIT_CONFIG_LEVEL_SYSTEM, + ConfigLevel::XDG => raw::GIT_CONFIG_LEVEL_XDG, + ConfigLevel::Global => raw::GIT_CONFIG_LEVEL_GLOBAL, + ConfigLevel::Local => raw::GIT_CONFIG_LEVEL_LOCAL, + ConfigLevel::App => raw::GIT_CONFIG_LEVEL_APP, + ConfigLevel::Highest => raw::GIT_CONFIG_HIGHEST_LEVEL, + } + } + } + + impl Convert for DiffFormat { + fn convert(&self) -> raw::git_diff_format_t { + match *self { + DiffFormat::Patch => raw::GIT_DIFF_FORMAT_PATCH, + DiffFormat::PatchHeader => raw::GIT_DIFF_FORMAT_PATCH_HEADER, + DiffFormat::Raw => raw::GIT_DIFF_FORMAT_RAW, + DiffFormat::NameOnly => raw::GIT_DIFF_FORMAT_NAME_ONLY, + DiffFormat::NameStatus => raw::GIT_DIFF_FORMAT_NAME_STATUS, + } + } + } + + impl Convert for FileFavor { + fn convert(&self) -> raw::git_merge_file_favor_t { + match *self { + FileFavor::Normal => raw::GIT_MERGE_FILE_FAVOR_NORMAL, + FileFavor::Ours => raw::GIT_MERGE_FILE_FAVOR_OURS, + FileFavor::Theirs => raw::GIT_MERGE_FILE_FAVOR_THEIRS, + FileFavor::Union => raw::GIT_MERGE_FILE_FAVOR_UNION, + } + } + } + + impl Convert for SubmoduleIgnore { + fn convert(&self) -> raw::git_submodule_ignore_t { + match *self { + SubmoduleIgnore::Unspecified => + raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED, + SubmoduleIgnore::None => raw::GIT_SUBMODULE_IGNORE_NONE, + SubmoduleIgnore::Untracked => raw::GIT_SUBMODULE_IGNORE_UNTRACKED, + SubmoduleIgnore::Dirty => raw::GIT_SUBMODULE_IGNORE_DIRTY, + SubmoduleIgnore::All => raw::GIT_SUBMODULE_IGNORE_ALL, + } + } + } + + impl Convert for AutotagOption { + fn convert(&self) -> raw::git_remote_autotag_option_t { + match *self { + AutotagOption::Unspecified => + raw::GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, + AutotagOption::None => raw::GIT_REMOTE_DOWNLOAD_TAGS_NONE, + AutotagOption::Auto => raw::GIT_REMOTE_DOWNLOAD_TAGS_AUTO, + AutotagOption::All => raw::GIT_REMOTE_DOWNLOAD_TAGS_ALL, + } + } + } + + impl Convert for FetchPrune { + fn convert(&self) -> raw::git_fetch_prune_t { + match *self { + FetchPrune::Unspecified => raw::GIT_FETCH_PRUNE_UNSPECIFIED, + FetchPrune::On => raw::GIT_FETCH_PRUNE, + FetchPrune::Off => raw::GIT_FETCH_NO_PRUNE, + } + } + } +} diff --git a/git2/src/cert.rs b/git2/src/cert.rs new file mode 100644 index 000000000..70ab9498f --- /dev/null +++ b/git2/src/cert.rs @@ -0,0 +1,97 @@ +//! Certificate types which are passed to `CertificateCheck` in +//! `RemoteCallbacks`. + +use std::marker; +use std::mem; +use std::slice; + +use raw; +use util::Binding; + +/// A certificate for a remote connection, viewable as one of `CertHostkey` or +/// `CertX509` currently. +pub struct Cert<'a> { + raw: *mut raw::git_cert, + _marker: marker::PhantomData<&'a raw::git_cert>, +} + +/// Hostkey information taken from libssh2 +pub struct CertHostkey<'a> { + raw: *mut raw::git_cert_hostkey, + _marker: marker::PhantomData<&'a raw::git_cert>, +} + +/// X.509 certificate information +pub struct CertX509<'a> { + raw: *mut raw::git_cert_x509, + _marker: marker::PhantomData<&'a raw::git_cert>, +} + +impl<'a> Cert<'a> { + /// Attempt to view this certificate as an SSH hostkey. + /// + /// Returns `None` if this is not actually an SSH hostkey. + pub fn as_hostkey(&self) -> Option<&CertHostkey<'a>> { + self.cast(raw::GIT_CERT_HOSTKEY_LIBSSH2) + } + + /// Attempt to view this certificate as an X.509 certificate. + /// + /// Returns `None` if this is not actually an X.509 certificate. + pub fn as_x509(&self) -> Option<&CertX509<'a>> { + self.cast(raw::GIT_CERT_X509) + } + + fn cast(&self, kind: raw::git_cert_t) -> Option<&T> { + assert_eq!(mem::size_of::>(), mem::size_of::()); + unsafe { + if kind == (*self.raw).cert_type { + Some(&*(self as *const Cert<'a> as *const T)) + } else { + None + } + } + } +} + +impl<'a> CertHostkey<'a> { + /// Returns the md5 hash of the hostkey, if available. + pub fn hash_md5(&self) -> Option<&[u8; 16]> { + unsafe { + if (*self.raw).kind as u32 & raw::GIT_CERT_SSH_MD5 as u32 == 0 { + None + } else { + Some(&(*self.raw).hash_md5) + } + } + } + + /// Returns the SHA-1 hash of the hostkey, if available. + pub fn hash_sha1(&self) -> Option<&[u8; 20]> { + unsafe { + if (*self.raw).kind as u32 & raw::GIT_CERT_SSH_SHA1 as u32 == 0 { + None + } else { + Some(&(*self.raw).hash_sha1) + } + } + } +} + +impl<'a> CertX509<'a> { + /// Return the X.509 certificate data as a byte slice + pub fn data(&self) -> &[u8] { + unsafe { + slice::from_raw_parts((*self.raw).data as *const u8, + (*self.raw).len as usize) + } + } +} + +impl<'a> Binding for Cert<'a> { + type Raw = *mut raw::git_cert; + unsafe fn from_raw(raw: *mut raw::git_cert) -> Cert<'a> { + Cert { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_cert { self.raw } +} diff --git a/git2/src/commit.rs b/git2/src/commit.rs new file mode 100644 index 000000000..4cf52bd6c --- /dev/null +++ b/git2/src/commit.rs @@ -0,0 +1,372 @@ +use std::marker; +use std::mem; +use std::ops::Range; +use std::ptr; +use std::str; +use libc; + +use {raw, signature, Oid, Error, Signature, Tree, Time, Object}; +use util::Binding; + +/// A structure to represent a git [commit][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects +pub struct Commit<'repo> { + raw: *mut raw::git_commit, + _marker: marker::PhantomData>, +} + +/// An iterator over the parent commits of a commit. +/// +/// Aborts iteration when a commit cannot be found +pub struct Parents<'commit, 'repo: 'commit> { + range: Range, + commit: &'commit Commit<'repo>, +} + +/// An iterator over the parent commits' ids of a commit. +/// +/// Aborts iteration when a commit cannot be found +pub struct ParentIds<'commit> { + range: Range, + commit: &'commit Commit<'commit>, +} + +impl<'repo> Commit<'repo> { + /// Get the id (SHA1) of a repository commit + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_commit_id(&*self.raw)) } + } + + /// Get the id of the tree pointed to by this commit. + /// + /// No attempts are made to fetch an object from the ODB. + pub fn tree_id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_commit_tree_id(&*self.raw)) } + } + + /// Get the tree pointed to by a commit. + pub fn tree(&self) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_commit_tree(&mut ret, &*self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Get access to the underlying raw pointer. + pub fn raw(&self) -> *mut raw::git_commit { self.raw } + + /// Get the full message of a commit. + /// + /// The returned message will be slightly prettified by removing any + /// potential leading newlines. + /// + /// `None` will be returned if the message is not valid utf-8 + pub fn message(&self) -> Option<&str> { + str::from_utf8(self.message_bytes()).ok() + } + + /// Get the full message of a commit as a byte slice. + /// + /// The returned message will be slightly prettified by removing any + /// potential leading newlines. + pub fn message_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_commit_message(&*self.raw)).unwrap() + } + } + + /// Get the encoding for the message of a commit, as a string representing a + /// standard encoding name. + /// + /// `None` will be returned if the encoding is not known + pub fn message_encoding(&self) -> Option<&str> { + let bytes = unsafe { + ::opt_bytes(self, raw::git_commit_message_encoding(&*self.raw)) + }; + bytes.and_then(|b| str::from_utf8(b).ok()) + } + + /// Get the full raw message of a commit. + /// + /// `None` will be returned if the message is not valid utf-8 + pub fn message_raw(&self) -> Option<&str> { + str::from_utf8(self.message_raw_bytes()).ok() + } + + /// Get the full raw message of a commit. + pub fn message_raw_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_commit_message_raw(&*self.raw)).unwrap() + } + } + + /// Get the full raw text of the commit header. + /// + /// `None` will be returned if the message is not valid utf-8 + pub fn raw_header(&self) -> Option<&str> { + str::from_utf8(self.raw_header_bytes()).ok() + } + + /// Get the full raw text of the commit header. + pub fn raw_header_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_commit_raw_header(&*self.raw)).unwrap() + } + } + + /// Get the short "summary" of the git commit message. + /// + /// The returned message is the summary of the commit, comprising the first + /// paragraph of the message with whitespace trimmed and squashed. + /// + /// `None` may be returned if an error occurs or if the summary is not valid + /// utf-8. + pub fn summary(&self) -> Option<&str> { + self.summary_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the short "summary" of the git commit message. + /// + /// The returned message is the summary of the commit, comprising the first + /// paragraph of the message with whitespace trimmed and squashed. + /// + /// `None` may be returned if an error occurs + pub fn summary_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_commit_summary(self.raw)) } + } + + /// Get the commit time (i.e. committer time) of a commit. + /// + /// The first element of the tuple is the time, in seconds, since the epoch. + /// The second element is the offset, in minutes, of the time zone of the + /// committer's preferred time zone. + pub fn time(&self) -> Time { + unsafe { + Time::new(raw::git_commit_time(&*self.raw) as i64, + raw::git_commit_time_offset(&*self.raw) as i32) + } + } + + /// Creates a new iterator over the parents of this commit. + pub fn parents<'a>(&'a self) -> Parents<'a, 'repo> { + Parents { range: 0..self.parent_count(), commit: self } + } + + /// Creates a new iterator over the parents of this commit. + pub fn parent_ids(&self) -> ParentIds { + ParentIds { range: 0..self.parent_count(), commit: self } + } + + /// Get the author of this commit. + pub fn author(&self) -> Signature { + unsafe { + let ptr = raw::git_commit_author(&*self.raw); + signature::from_raw_const(self, ptr) + } + } + + /// Get the committer of this commit. + pub fn committer(&self) -> Signature { + unsafe { + let ptr = raw::git_commit_committer(&*self.raw); + signature::from_raw_const(self, ptr) + } + } + + /// Amend this existing commit with all non-`None` values + /// + /// This creates a new commit that is exactly the same as the old commit, + /// except that any non-`None` values will be updated. The new commit has + /// the same parents as the old commit. + /// + /// For information about `update_ref`, see [`Repository::commit`]. + /// + /// [`Repository::commit`]: struct.Repository.html#method.commit + pub fn amend(&self, + update_ref: Option<&str>, + author: Option<&Signature>, + committer: Option<&Signature>, + message_encoding: Option<&str>, + message: Option<&str>, + tree: Option<&Tree<'repo>>) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + let update_ref = try!(::opt_cstr(update_ref)); + let encoding = try!(::opt_cstr(message_encoding)); + let message = try!(::opt_cstr(message)); + unsafe { + try_call!(raw::git_commit_amend(&mut raw, + self.raw(), + update_ref, + author.map(|s| s.raw()), + committer.map(|s| s.raw()), + encoding, + message, + tree.map(|t| t.raw()))); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Get the number of parents of this commit. + /// + /// Use the `parents` iterator to return an iterator over all parents. + pub fn parent_count(&self) -> usize { + unsafe { raw::git_commit_parentcount(&*self.raw) as usize } + } + + /// Get the specified parent of the commit. + /// + /// Use the `parents` iterator to return an iterator over all parents. + pub fn parent(&self, i: usize) -> Result, Error> { + unsafe { + let mut raw = ptr::null_mut(); + try_call!(raw::git_commit_parent(&mut raw, &*self.raw, + i as libc::c_uint)); + Ok(Binding::from_raw(raw)) + } + } + + /// Get the specified parent id of the commit. + /// + /// This is different from `parent`, which will attempt to load the + /// parent commit from the ODB. + /// + /// Use the `parent_ids` iterator to return an iterator over all parents. + pub fn parent_id(&self, i: usize) -> Result { + unsafe { + let id = raw::git_commit_parent_id(self.raw, i as libc::c_uint); + if id.is_null() { + Err(Error::from_str("parent index out of bounds")) + } else { + Ok(Binding::from_raw(id)) + } + } + } + + /// Casts this Commit to be usable as an `Object` + pub fn as_object(&self) -> &Object<'repo> { + unsafe { + &*(self as *const _ as *const Object<'repo>) + } + } + + /// Consumes Commit to be returned as an `Object` + pub fn into_object(self) -> Object<'repo> { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + unsafe { + mem::transmute(self) + } + } +} + +impl<'repo> Binding for Commit<'repo> { + type Raw = *mut raw::git_commit; + unsafe fn from_raw(raw: *mut raw::git_commit) -> Commit<'repo> { + Commit { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_commit { self.raw } +} + +impl<'repo> ::std::fmt::Debug for Commit<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let mut ds = f.debug_struct("Commit"); + ds.field("id", &self.id()); + if let Some(summary) = self.summary() { + ds.field("summary", &summary); + } + ds.finish() + } +} + +/// Aborts iteration when a commit cannot be found +impl<'repo, 'commit> Iterator for Parents<'commit, 'repo> { + type Item = Commit<'repo>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.commit.parent(i).ok()) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} + +/// Aborts iteration when a commit cannot be found +impl<'repo, 'commit> DoubleEndedIterator for Parents<'commit, 'repo> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.commit.parent(i).ok()) + } +} + +impl<'repo, 'commit> ExactSizeIterator for Parents<'commit, 'repo> {} + +/// Aborts iteration when a commit cannot be found +impl<'commit> Iterator for ParentIds<'commit> { + type Item = Oid; + fn next(&mut self) -> Option { + self.range.next().and_then(|i| self.commit.parent_id(i).ok()) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} + +/// Aborts iteration when a commit cannot be found +impl<'commit> DoubleEndedIterator for ParentIds<'commit> { + fn next_back(&mut self) -> Option { + self.range.next_back().and_then(|i| self.commit.parent_id(i).ok()) + } +} + +impl<'commit> ExactSizeIterator for ParentIds<'commit> {} + +impl<'repo> Clone for Commit<'repo> { + fn clone(&self) -> Self { + self.as_object().clone().into_commit().ok().unwrap() + } +} + +impl<'repo> Drop for Commit<'repo> { + fn drop(&mut self) { + unsafe { raw::git_commit_free(self.raw) } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + let commit = repo.find_commit(target).unwrap(); + assert_eq!(commit.message(), Some("initial")); + assert_eq!(commit.id(), target); + commit.message_raw().unwrap(); + commit.raw_header().unwrap(); + commit.message_encoding(); + commit.summary().unwrap(); + commit.tree_id(); + commit.tree().unwrap(); + assert_eq!(commit.parents().count(), 0); + + assert_eq!(commit.author().name(), Some("name")); + assert_eq!(commit.author().email(), Some("email")); + assert_eq!(commit.committer().name(), Some("name")); + assert_eq!(commit.committer().email(), Some("email")); + + let sig = repo.signature().unwrap(); + let tree = repo.find_tree(commit.tree_id()).unwrap(); + let id = repo.commit(Some("HEAD"), &sig, &sig, "bar", &tree, + &[&commit]).unwrap(); + let head = repo.find_commit(id).unwrap(); + + let new_head = head.amend(Some("HEAD"), None, None, None, + Some("new message"), None).unwrap(); + let new_head = repo.find_commit(new_head).unwrap(); + assert_eq!(new_head.message(), Some("new message")); + new_head.into_object(); + + repo.find_object(target, None).unwrap().as_commit().unwrap(); + repo.find_object(target, None).unwrap().into_commit().ok().unwrap(); + } +} + diff --git a/git2/src/config.rs b/git2/src/config.rs new file mode 100644 index 000000000..b01729aeb --- /dev/null +++ b/git2/src/config.rs @@ -0,0 +1,628 @@ +use std::ffi::CString; +use std::marker; +use std::path::{Path, PathBuf}; +use std::ptr; +use std::str; +use libc; + +use {raw, Error, ConfigLevel, Buf, IntoCString}; +use util::{self, Binding}; + +/// A structure representing a git configuration key/value store +pub struct Config { + raw: *mut raw::git_config, +} + +/// A struct representing a certain entry owned by a `Config` instance. +/// +/// An entry has a name, a value, and a level it applies to. +pub struct ConfigEntry<'cfg> { + raw: *mut raw::git_config_entry, + _marker: marker::PhantomData<&'cfg Config>, + owned: bool, +} + +/// An iterator over the `ConfigEntry` values of a `Config` structure. +pub struct ConfigEntries<'cfg> { + raw: *mut raw::git_config_iterator, + _marker: marker::PhantomData<&'cfg Config>, +} + +impl Config { + /// Allocate a new configuration object + /// + /// This object is empty, so you have to add a file to it before you can do + /// anything with it. + pub fn new() -> Result { + ::init(); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_config_new(&mut raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new config instance containing a single on-disk file + pub fn open(path: &Path) -> Result { + ::init(); + let mut raw = ptr::null_mut(); + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_config_open_ondisk(&mut raw, path)); + Ok(Binding::from_raw(raw)) + } + } + + /// Open the global, XDG and system configuration files + /// + /// Utility wrapper that finds the global, XDG and system configuration + /// files and opens them into a single prioritized config object that can + /// be used when accessing default config data outside a repository. + pub fn open_default() -> Result { + ::init(); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_config_open_default(&mut raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Locate the path to the global configuration file + /// + /// The user or global configuration file is usually located in + /// `$HOME/.gitconfig`. + /// + /// This method will try to guess the full path to that file, if the file + /// exists. The returned path may be used on any method call to load + /// the global configuration file. + /// + /// This method will not guess the path to the xdg compatible config file + /// (`.config/git/config`). + pub fn find_global() -> Result { + ::init(); + let buf = Buf::new(); + unsafe { try_call!(raw::git_config_find_global(buf.raw())); } + Ok(util::bytes2path(&buf).to_path_buf()) + } + + /// Locate the path to the system configuration file + /// + /// If /etc/gitconfig doesn't exist, it will look for %PROGRAMFILES% + pub fn find_system() -> Result { + ::init(); + let buf = Buf::new(); + unsafe { try_call!(raw::git_config_find_system(buf.raw())); } + Ok(util::bytes2path(&buf).to_path_buf()) + } + + /// Locate the path to the global xdg compatible configuration file + /// + /// The xdg compatible configuration file is usually located in + /// `$HOME/.config/git/config`. + pub fn find_xdg() -> Result { + ::init(); + let buf = Buf::new(); + unsafe { try_call!(raw::git_config_find_xdg(buf.raw())); } + Ok(util::bytes2path(&buf).to_path_buf()) + } + + /// Add an on-disk config file instance to an existing config + /// + /// The on-disk file pointed at by path will be opened and parsed; it's + /// expected to be a native Git config file following the default Git config + /// syntax (see man git-config). + /// + /// Further queries on this config object will access each of the config + /// file instances in order (instances with a higher priority level will be + /// accessed first). + pub fn add_file(&mut self, path: &Path, level: ConfigLevel, + force: bool) -> Result<(), Error> { + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_config_add_file_ondisk(self.raw, path, level, + ptr::null(), force)); + Ok(()) + } + } + + /// Delete a config variable from the config file with the highest level + /// (usually the local one). + pub fn remove(&mut self, name: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_delete_entry(self.raw, name)); + Ok(()) + } + } + + /// Remove multivar config variables in the config file with the highest level (usually the + /// local one). + pub fn remove_multivar(&mut self, name: &str, regexp: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + let regexp = try!(CString::new(regexp)); + unsafe { + try_call!(raw::git_config_delete_multivar(self.raw, name, regexp)); + } + Ok(()) + } + + /// Get the value of a boolean config variable. + /// + /// All config files will be looked into, in the order of their defined + /// level. A higher level means a higher priority. The first occurrence of + /// the variable will be returned here. + pub fn get_bool(&self, name: &str) -> Result { + let mut out = 0 as libc::c_int; + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_bool(&mut out, &*self.raw, name)); + + } + Ok(!(out == 0)) + } + + /// Get the value of an integer config variable. + /// + /// All config files will be looked into, in the order of their defined + /// level. A higher level means a higher priority. The first occurrence of + /// the variable will be returned here. + pub fn get_i32(&self, name: &str) -> Result { + let mut out = 0i32; + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_int32(&mut out, &*self.raw, name)); + + } + Ok(out) + } + + /// Get the value of an integer config variable. + /// + /// All config files will be looked into, in the order of their defined + /// level. A higher level means a higher priority. The first occurrence of + /// the variable will be returned here. + pub fn get_i64(&self, name: &str) -> Result { + let mut out = 0i64; + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_int64(&mut out, &*self.raw, name)); + } + Ok(out) + } + + /// Get the value of a string config variable. + /// + /// This is the same as `get_bytes` except that it may return `Err` if + /// the bytes are not valid utf-8. + pub fn get_str(&self, name: &str) -> Result<&str, Error> { + str::from_utf8(try!(self.get_bytes(name))).map_err(|_| { + Error::from_str("configuration value is not valid utf8") + }) + } + + /// Get the value of a string config variable as a byte slice. + /// + /// This method will return an error if this `Config` is not a snapshot. + pub fn get_bytes(&self, name: &str) -> Result<&[u8], Error> { + let mut ret = ptr::null(); + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_string(&mut ret, &*self.raw, name)); + Ok(::opt_bytes(self, ret).unwrap()) + } + } + + /// Get the value of a string config variable as an owned string. + /// + /// An error will be returned if the config value is not valid utf-8. + pub fn get_string(&self, name: &str) -> Result { + let ret = Buf::new(); + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_string_buf(ret.raw(), self.raw, name)); + } + str::from_utf8(&ret).map(|s| s.to_string()).map_err(|_| { + Error::from_str("configuration value is not valid utf8") + }) + } + + /// Get the value of a path config variable as an owned . + pub fn get_path(&self, name: &str) -> Result { + let ret = Buf::new(); + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_path(ret.raw(), self.raw, name)); + } + Ok(::util::bytes2path(&ret).to_path_buf()) + } + + /// Get the ConfigEntry for a config variable. + pub fn get_entry(&self, name: &str) -> Result { + let mut ret = ptr::null_mut(); + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_get_entry(&mut ret, self.raw, name)); + Ok(Binding::from_raw(ret)) + } + } + + /// Iterate over all the config variables + /// + /// If `glob` is `Some`, then the iterator will only iterate over all + /// variables whose name matches the pattern. + /// + /// # Example + /// + /// ``` + /// # #![allow(unstable)] + /// use git2::Config; + /// + /// let cfg = Config::new().unwrap(); + /// + /// for entry in &cfg.entries(None).unwrap() { + /// let entry = entry.unwrap(); + /// println!("{} => {}", entry.name().unwrap(), entry.value().unwrap()); + /// } + /// ``` + pub fn entries(&self, glob: Option<&str>) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + match glob { + Some(s) => { + let s = try!(CString::new(s)); + try_call!(raw::git_config_iterator_glob_new(&mut ret, + &*self.raw, + s)); + } + None => { + try_call!(raw::git_config_iterator_new(&mut ret, &*self.raw)); + } + } + Ok(Binding::from_raw(ret)) + } + } + + /// Open the global/XDG configuration file according to git's rules + /// + /// Git allows you to store your global configuration at `$HOME/.config` or + /// `$XDG_CONFIG_HOME/git/config`. For backwards compatability, the XDG file + /// shouldn't be used unless the use has created it explicitly. With this + /// function you'll open the correct one to write to. + pub fn open_global(&mut self) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_config_open_global(&mut raw, self.raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Build a single-level focused config object from a multi-level one. + /// + /// The returned config object can be used to perform get/set/delete + /// operations on a single specific level. + pub fn open_level(&self, level: ConfigLevel) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_config_open_level(&mut raw, &*self.raw, level)); + Ok(Binding::from_raw(raw)) + } + } + + /// Set the value of a boolean config variable in the config file with the + /// highest level (usually the local one). + pub fn set_bool(&mut self, name: &str, value: bool) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_set_bool(self.raw, name, value)); + } + Ok(()) + } + + /// Set the value of an integer config variable in the config file with the + /// highest level (usually the local one). + pub fn set_i32(&mut self, name: &str, value: i32) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_set_int32(self.raw, name, value)); + } + Ok(()) + } + + /// Set the value of an integer config variable in the config file with the + /// highest level (usually the local one). + pub fn set_i64(&mut self, name: &str, value: i64) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_config_set_int64(self.raw, name, value)); + } + Ok(()) + } + + /// Set the value of an multivar config variable in the config file with the + /// highest level (usually the local one). + pub fn set_multivar(&mut self, name: &str, regexp: &str, value: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + let regexp = try!(CString::new(regexp)); + let value = try!(CString::new(value)); + unsafe { + try_call!(raw::git_config_set_multivar(self.raw, name, regexp, value)); + } + Ok(()) + } + + /// Set the value of a string config variable in the config file with the + /// highest level (usually the local one). + pub fn set_str(&mut self, name: &str, value: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + let value = try!(CString::new(value)); + unsafe { + try_call!(raw::git_config_set_string(self.raw, name, value)); + } + Ok(()) + } + + /// Create a snapshot of the configuration + /// + /// Create a snapshot of the current state of a configuration, which allows + /// you to look into a consistent view of the configuration for looking up + /// complex values (e.g. a remote, submodule). + pub fn snapshot(&mut self) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_config_snapshot(&mut ret, self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Parse a string as a bool. + /// Interprets "true", "yes", "on", 1, or any non-zero number as true. + /// Interprets "false", "no", "off", 0, or an empty string as false. + pub fn parse_bool(s: S) -> Result { + let s = try!(s.into_c_string()); + let mut out = 0; + ::init(); + unsafe { + try_call!(raw::git_config_parse_bool(&mut out, s)); + } + Ok(out != 0) + } + + /// Parse a string as an i32; handles suffixes like k, M, or G, and + /// multiplies by the appropriate power of 1024. + pub fn parse_i32(s: S) -> Result { + let s = try!(s.into_c_string()); + let mut out = 0; + ::init(); + unsafe { + try_call!(raw::git_config_parse_int32(&mut out, s)); + } + Ok(out) + } + + /// Parse a string as an i64; handles suffixes like k, M, or G, and + /// multiplies by the appropriate power of 1024. + pub fn parse_i64(s: S) -> Result { + let s = try!(s.into_c_string()); + let mut out = 0; + ::init(); + unsafe { + try_call!(raw::git_config_parse_int64(&mut out, s)); + } + Ok(out) + } +} + +impl Binding for Config { + type Raw = *mut raw::git_config; + unsafe fn from_raw(raw: *mut raw::git_config) -> Config { + Config { raw: raw } + } + fn raw(&self) -> *mut raw::git_config { self.raw } +} + +impl Drop for Config { + fn drop(&mut self) { + unsafe { raw::git_config_free(self.raw) } + } +} + +impl<'cfg> ConfigEntry<'cfg> { + /// Gets the name of this entry. + /// + /// May return `None` if the name is not valid utf-8 + pub fn name(&self) -> Option<&str> { str::from_utf8(self.name_bytes()).ok() } + + /// Gets the name of this entry as a byte slice. + pub fn name_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, (*self.raw).name).unwrap() } + } + + /// Gets the value of this entry. + /// + /// May return `None` if the value is not valid utf-8 + pub fn value(&self) -> Option<&str> { str::from_utf8(self.value_bytes()).ok() } + + /// Gets the value of this entry as a byte slice. + pub fn value_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, (*self.raw).value).unwrap() } + } + + /// Gets the configuration level of this entry. + pub fn level(&self) -> ConfigLevel { + unsafe { ConfigLevel::from_raw((*self.raw).level) } + } + + /// Depth of includes where this variable was found + pub fn include_depth(&self) -> u32 { + unsafe { (*self.raw).include_depth as u32 } + } +} + +impl<'cfg> Binding for ConfigEntry<'cfg> { + type Raw = *mut raw::git_config_entry; + + unsafe fn from_raw(raw: *mut raw::git_config_entry) + -> ConfigEntry<'cfg> { + ConfigEntry { + raw: raw, + _marker: marker::PhantomData, + owned: true, + } + } + fn raw(&self) -> *mut raw::git_config_entry { self.raw } +} + +impl<'cfg> Binding for ConfigEntries<'cfg> { + type Raw = *mut raw::git_config_iterator; + + unsafe fn from_raw(raw: *mut raw::git_config_iterator) + -> ConfigEntries<'cfg> { + ConfigEntries { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_config_iterator { self.raw } +} + +// entries are only valid until the iterator is freed, so this impl is for +// `&'b T` instead of `T` to have a lifetime to tie them to. +// +// It's also not implemented for `&'b mut T` so we can have multiple entries +// (ok). +impl<'cfg, 'b> Iterator for &'b ConfigEntries<'cfg> { + type Item = Result, Error>; + fn next(&mut self) -> Option, Error>> { + let mut raw = ptr::null_mut(); + unsafe { + try_call_iter!(raw::git_config_next(&mut raw, self.raw)); + Some(Ok(ConfigEntry { + owned: false, + raw: raw, + _marker: marker::PhantomData, + })) + } + } +} + +impl<'cfg> Drop for ConfigEntries<'cfg> { + fn drop(&mut self) { + unsafe { raw::git_config_iterator_free(self.raw) } + } +} + +impl<'cfg> Drop for ConfigEntry<'cfg> { + fn drop(&mut self) { + if self.owned { + unsafe { raw::git_config_entry_free(self.raw) } + } + } +} + +#[cfg(test)] +mod tests { + use std::fs::File; + use tempdir::TempDir; + + use Config; + + #[test] + fn smoke() { + let _cfg = Config::new().unwrap(); + let _ = Config::find_global(); + let _ = Config::find_system(); + let _ = Config::find_xdg(); + } + + #[test] + fn persisted() { + let td = TempDir::new("test").unwrap(); + let path = td.path().join("foo"); + File::create(&path).unwrap(); + + let mut cfg = Config::open(&path).unwrap(); + assert!(cfg.get_bool("foo.bar").is_err()); + cfg.set_bool("foo.k1", true).unwrap(); + cfg.set_i32("foo.k2", 1).unwrap(); + cfg.set_i64("foo.k3", 2).unwrap(); + cfg.set_str("foo.k4", "bar").unwrap(); + cfg.snapshot().unwrap(); + drop(cfg); + + let cfg = Config::open(&path).unwrap().snapshot().unwrap(); + assert_eq!(cfg.get_bool("foo.k1").unwrap(), true); + assert_eq!(cfg.get_i32("foo.k2").unwrap(), 1); + assert_eq!(cfg.get_i64("foo.k3").unwrap(), 2); + assert_eq!(cfg.get_str("foo.k4").unwrap(), "bar"); + + for entry in &cfg.entries(None).unwrap() { + let entry = entry.unwrap(); + entry.name(); + entry.value(); + entry.level(); + } + } + + #[test] + fn multivar() { + let td = TempDir::new("test").unwrap(); + let path = td.path().join("foo"); + File::create(&path).unwrap(); + + let mut cfg = Config::open(&path).unwrap(); + cfg.set_multivar("foo.bar", "^$", "baz").unwrap(); + cfg.set_multivar("foo.bar", "^$", "qux").unwrap(); + + let mut values: Vec = cfg.entries(None) + .unwrap() + .into_iter() + .map(|entry| entry.unwrap().value().unwrap().into()) + .collect(); + values.sort(); + assert_eq!(values, ["baz", "qux"]); + + cfg.remove_multivar("foo.bar", ".*").unwrap(); + + assert_eq!(cfg.entries(None).unwrap().count(), 0); + } + + #[test] + fn parse() { + assert_eq!(Config::parse_bool("").unwrap(), false); + assert_eq!(Config::parse_bool("false").unwrap(), false); + assert_eq!(Config::parse_bool("no").unwrap(), false); + assert_eq!(Config::parse_bool("off").unwrap(), false); + assert_eq!(Config::parse_bool("0").unwrap(), false); + + assert_eq!(Config::parse_bool("true").unwrap(), true); + assert_eq!(Config::parse_bool("yes").unwrap(), true); + assert_eq!(Config::parse_bool("on").unwrap(), true); + assert_eq!(Config::parse_bool("1").unwrap(), true); + assert_eq!(Config::parse_bool("42").unwrap(), true); + + assert!(Config::parse_bool(" ").is_err()); + assert!(Config::parse_bool("some-string").is_err()); + assert!(Config::parse_bool("-").is_err()); + + assert_eq!(Config::parse_i32("0").unwrap(), 0); + assert_eq!(Config::parse_i32("1").unwrap(), 1); + assert_eq!(Config::parse_i32("100").unwrap(), 100); + assert_eq!(Config::parse_i32("-1").unwrap(), -1); + assert_eq!(Config::parse_i32("-100").unwrap(), -100); + assert_eq!(Config::parse_i32("1k").unwrap(), 1024); + assert_eq!(Config::parse_i32("4k").unwrap(), 4096); + assert_eq!(Config::parse_i32("1M").unwrap(), 1048576); + assert_eq!(Config::parse_i32("1G").unwrap(), 1024*1024*1024); + + assert_eq!(Config::parse_i64("0").unwrap(), 0); + assert_eq!(Config::parse_i64("1").unwrap(), 1); + assert_eq!(Config::parse_i64("100").unwrap(), 100); + assert_eq!(Config::parse_i64("-1").unwrap(), -1); + assert_eq!(Config::parse_i64("-100").unwrap(), -100); + assert_eq!(Config::parse_i64("1k").unwrap(), 1024); + assert_eq!(Config::parse_i64("4k").unwrap(), 4096); + assert_eq!(Config::parse_i64("1M").unwrap(), 1048576); + assert_eq!(Config::parse_i64("1G").unwrap(), 1024*1024*1024); + assert_eq!(Config::parse_i64("100G").unwrap(), 100*1024*1024*1024); + } +} diff --git a/git2/src/cred.rs b/git2/src/cred.rs new file mode 100644 index 000000000..e7cf81c00 --- /dev/null +++ b/git2/src/cred.rs @@ -0,0 +1,577 @@ +use std::ffi::CString; +use std::io::Write; +use std::mem; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::ptr; +use url; + +use {raw, Error, Config, IntoCString}; +use util::Binding; + +/// A structure to represent git credentials in libgit2. +pub struct Cred { + raw: *mut raw::git_cred, +} + +/// Management of the gitcredentials(7) interface. +pub struct CredentialHelper { + /// A public field representing the currently discovered username from + /// configuration. + pub username: Option, + protocol: Option, + host: Option, + url: String, + commands: Vec, +} + +impl Cred { + /// Create a "default" credential usable for Negotiate mechanisms like NTLM + /// or Kerberos authentication. + pub fn default() -> Result { + ::init(); + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_cred_default_new(&mut out)); + Ok(Binding::from_raw(out)) + } + } + + /// Create a new ssh key credential object used for querying an ssh-agent. + /// + /// The username specified is the username to authenticate. + pub fn ssh_key_from_agent(username: &str) -> Result { + ::init(); + let mut out = ptr::null_mut(); + let username = try!(CString::new(username)); + unsafe { + try_call!(raw::git_cred_ssh_key_from_agent(&mut out, username)); + Ok(Binding::from_raw(out)) + } + } + + /// Create a new passphrase-protected ssh key credential object. + pub fn ssh_key(username: &str, + publickey: Option<&Path>, + privatekey: &Path, + passphrase: Option<&str>) -> Result { + ::init(); + let username = try!(CString::new(username)); + let publickey = try!(::opt_cstr(publickey)); + let privatekey = try!(privatekey.into_c_string()); + let passphrase = try!(::opt_cstr(passphrase)); + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_cred_ssh_key_new(&mut out, username, publickey, + privatekey, passphrase)); + Ok(Binding::from_raw(out)) + } + } + + /// Create a new ssh key credential object reading the keys from memory. + pub fn ssh_key_from_memory(username: &str, + publickey: Option<&str>, + privatekey: &str, + passphrase: Option<&str>) -> Result { + ::init(); + let username = try!(CString::new(username)); + let publickey = try!(::opt_cstr(publickey)); + let privatekey = try!(CString::new(privatekey)); + let passphrase = try!(::opt_cstr(passphrase)); + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_cred_ssh_key_memory_new(&mut out, username, publickey, + privatekey, passphrase)); + Ok(Binding::from_raw(out)) + } + } + + /// Create a new plain-text username and password credential object. + pub fn userpass_plaintext(username: &str, + password: &str) -> Result { + ::init(); + let username = try!(CString::new(username)); + let password = try!(CString::new(password)); + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_cred_userpass_plaintext_new(&mut out, username, + password)); + Ok(Binding::from_raw(out)) + } + } + + /// Attempt to read `credential.helper` according to gitcredentials(7) [1] + /// + /// This function will attempt to parse the user's `credential.helper` + /// configuration, invoke the necessary processes, and read off what the + /// username/password should be for a particular url. + /// + /// The returned credential type will be a username/password credential if + /// successful. + /// + /// [1]: https://www.kernel.org/pub/software/scm/git/docs/gitcredentials.html + pub fn credential_helper(config: &Config, + url: &str, + username: Option<&str>) + -> Result { + match CredentialHelper::new(url).config(config).username(username) + .execute() { + Some((username, password)) => { + Cred::userpass_plaintext(&username, &password) + } + None => Err(Error::from_str("failed to acquire username/password \ + from local configuration")) + } + } + + /// Create a credential to specify a username. + /// + /// THis is used with ssh authentication to query for the username if non is + /// specified in the url. + pub fn username(username: &str) -> Result { + ::init(); + let username = try!(CString::new(username)); + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_cred_username_new(&mut out, username)); + Ok(Binding::from_raw(out)) + } + } + + /// Check whether a credential object contains username information. + pub fn has_username(&self) -> bool { + unsafe { raw::git_cred_has_username(self.raw) == 1 } + } + + /// Return the type of credentials that this object represents. + pub fn credtype(&self) -> raw::git_credtype_t { + unsafe { (*self.raw).credtype } + } + + /// Unwrap access to the underlying raw pointer, canceling the destructor + pub unsafe fn unwrap(mut self) -> *mut raw::git_cred { + mem::replace(&mut self.raw, ptr::null_mut()) + } +} + +impl Binding for Cred { + type Raw = *mut raw::git_cred; + + unsafe fn from_raw(raw: *mut raw::git_cred) -> Cred { + Cred { raw: raw } + } + fn raw(&self) -> *mut raw::git_cred { self.raw } +} + +impl Drop for Cred { + fn drop(&mut self) { + if !self.raw.is_null() { + unsafe { ((*self.raw).free)(self.raw) } + } + } +} + +impl CredentialHelper { + /// Create a new credential helper object which will be used to probe git's + /// local credential configuration. + /// + /// The url specified is the namespace on which this will query credentials. + /// Invalid urls are currently ignored. + pub fn new(url: &str) -> CredentialHelper { + let mut ret = CredentialHelper { + protocol: None, + host: None, + username: None, + url: url.to_string(), + commands: Vec::new(), + }; + + // Parse out the (protocol, host) if one is available + if let Ok(url) = url::Url::parse(url) { + if let Some(url::Host::Domain(s)) = url.host() { + ret.host = Some(s.to_string()); + } + ret.protocol = Some(url.scheme().to_string()) + } + ret + } + + /// Set the username that this credential helper will query with. + /// + /// By default the username is `None`. + pub fn username(&mut self, username: Option<&str>) -> &mut CredentialHelper { + self.username = username.map(|s| s.to_string()); + self + } + + /// Query the specified configuration object to discover commands to + /// execute, usernames to query, etc. + pub fn config(&mut self, config: &Config) -> &mut CredentialHelper { + // Figure out the configured username/helper program. + // + // see http://git-scm.com/docs/gitcredentials.html#_configuration_options + // + // TODO: implement useHttpPath + if self.username.is_none() { + self.config_username(config); + } + self.config_helper(config); + self + } + + // Configure the queried username from `config` + fn config_username(&mut self, config: &Config) { + let key = self.exact_key("username"); + self.username = config.get_string(&key).ok().or_else(|| { + self.url_key("username").and_then(|s| { + config.get_string(&s).ok() + }) + }).or_else(|| { + config.get_string("credential.username").ok() + }) + } + + // Discover all `helper` directives from `config` + fn config_helper(&mut self, config: &Config) { + let exact = config.get_string(&self.exact_key("helper")); + self.add_command(exact.as_ref().ok().map(|s| &s[..])); + if let Some(key) = self.url_key("helper") { + let url = config.get_string(&key); + self.add_command(url.as_ref().ok().map(|s| &s[..])); + } + let global = config.get_string("credential.helper"); + self.add_command(global.as_ref().ok().map(|s| &s[..])); + } + + // Add a `helper` configured command to the list of commands to execute. + // + // see https://www.kernel.org/pub/software/scm/git/docs/technical + // /api-credentials.html#_credential_helpers + fn add_command(&mut self, cmd: Option<&str>) { + let cmd = match cmd { + Some("") | None => return, + Some(s) => s, + }; + + if cmd.starts_with('!') { + self.commands.push(cmd[1..].to_string()); + } else if cmd.starts_with('/') || cmd.starts_with('\\') || + cmd[1..].starts_with(":\\") { + self.commands.push(format!("\"{}\"", cmd)); + } else { + self.commands.push(format!("git credential-{}", cmd)); + } + } + + fn exact_key(&self, name: &str) -> String { + format!("credential.{}.{}", self.url, name) + } + + fn url_key(&self, name: &str) -> Option { + match (&self.host, &self.protocol) { + (&Some(ref host), &Some(ref protocol)) => { + Some(format!("credential.{}://{}.{}", protocol, host, name)) + } + _ => None + } + } + + /// Execute this helper, attempting to discover a username/password pair. + /// + /// All I/O errors are ignored, (to match git behavior), and this function + /// only succeeds if both a username and a password were found + pub fn execute(&self) -> Option<(String, String)> { + let mut username = self.username.clone(); + let mut password = None; + for cmd in &self.commands { + let (u, p) = self.execute_cmd(cmd, &username); + if u.is_some() && username.is_none() { + username = u; + } + if p.is_some() && password.is_none() { + password = p; + } + if username.is_some() && password.is_some() { break } + } + + match (username, password) { + (Some(u), Some(p)) => Some((u, p)), + _ => None, + } + } + + // Execute the given `cmd`, providing the appropriate variables on stdin and + // then afterwards parsing the output into the username/password on stdout. + fn execute_cmd(&self, cmd: &str, username: &Option) + -> (Option, Option) { + macro_rules! my_try( ($e:expr) => ( + match $e { + Ok(e) => e, + Err(e) => { + debug!("{} failed with {}", stringify!($e), e); + return (None, None) + } + } + ) ); + + // It looks like the `cmd` specification is typically bourne-shell-like + // syntax, so try that first. If that fails, though, we may be on a + // Windows machine for example where `sh` isn't actually available by + // default. Most credential helper configurations though are pretty + // simple (aka one or two space-separated strings) so also try to invoke + // the process directly. + // + // If that fails then it's up to the user to put `sh` in path and make + // sure it works. + let mut c = Command::new("sh"); + c.arg("-c") + .arg(&format!("{} get", cmd)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let mut p = match c.spawn() { + Ok(p) => p, + Err(e) => { + debug!("`sh` failed to spawn: {}", e); + let mut parts = cmd.split_whitespace(); + let mut c = Command::new(parts.next().unwrap()); + for arg in parts { + c.arg(arg); + } + c.arg("get") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + match c.spawn() { + Ok(p) => p, + Err(e) => { + debug!("fallback of {:?} failed with {}", cmd, e); + return (None, None); + } + } + } + }; + + // Ignore write errors as the command may not actually be listening for + // stdin + { + let stdin = p.stdin.as_mut().unwrap(); + if let Some(ref p) = self.protocol { + let _ = writeln!(stdin, "protocol={}", p); + } + if let Some(ref p) = self.host { + let _ = writeln!(stdin, "host={}", p); + } + if let Some(ref p) = *username { + let _ = writeln!(stdin, "username={}", p); + } + } + let output = my_try!(p.wait_with_output()); + if !output.status.success() { + debug!("credential helper failed: {}\nstdout ---\n{}\nstdout ---\n{}", + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr)); + return (None, None) + } + trace!("credential helper stderr ---\n{}", + String::from_utf8_lossy(&output.stderr)); + self.parse_output(output.stdout) + } + + // Parse the output of a command into the username/password found + fn parse_output(&self, output: Vec) -> (Option, Option) { + // Parse the output of the command, looking for username/password + let mut username = None; + let mut password = None; + for line in output.split(|t| *t == b'\n') { + let mut parts = line.splitn(2, |t| *t == b'='); + let key = parts.next().unwrap(); + let value = match parts.next() { + Some(s) => s, + None => { + trace!("ignoring output line: {}", String::from_utf8_lossy(line)); + continue + } + }; + let value = match String::from_utf8(value.to_vec()) { + Ok(s) => s, + Err(..) => continue, + }; + match key { + b"username" => username = Some(value), + b"password" => password = Some(value), + _ => {} + } + } + (username, password) + } +} + +#[cfg(all(test, feature = "unstable"))] +mod test { + use std::env; + use std::fs::File; + use std::io::prelude::*; + use std::path::Path; + use tempdir::TempDir; + + use {Cred, Config, CredentialHelper, ConfigLevel}; + + macro_rules! test_cfg( ($($k:expr => $v:expr),*) => ({ + let td = TempDir::new("git2-rs").unwrap(); + let mut cfg = Config::new().unwrap(); + cfg.add_file(&td.path().join("cfg"), ConfigLevel::Highest, false).unwrap(); + $(cfg.set_str($k, $v).unwrap();)* + cfg + }) ); + + #[test] + fn smoke() { + Cred::default().unwrap(); + } + + #[test] + fn credential_helper1() { + let cfg = test_cfg! { + "credential.helper" => "!f() { echo username=a; echo password=b; }; f" + }; + let (u, p) = CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().unwrap(); + assert_eq!(u, "a"); + assert_eq!(p, "b"); + } + + #[test] + fn credential_helper2() { + let cfg = test_cfg! {}; + assert!(CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().is_none()); + } + + #[test] + fn credential_helper3() { + let cfg = test_cfg! { + "credential.https://example.com.helper" => + "!f() { echo username=c; }; f", + "credential.helper" => "!f() { echo username=a; echo password=b; }; f" + }; + let (u, p) = CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().unwrap(); + assert_eq!(u, "c"); + assert_eq!(p, "b"); + } + + #[test] + fn credential_helper4() { + let td = TempDir::new("git2-rs").unwrap(); + let path = td.path().join("script"); + File::create(&path).unwrap().write(br"\ +#!/bin/sh +echo username=c +").unwrap(); + chmod(&path); + let cfg = test_cfg! { + "credential.https://example.com.helper" => + &path.display().to_string()[..], + "credential.helper" => "!f() { echo username=a; echo password=b; }; f" + }; + let (u, p) = CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().unwrap(); + assert_eq!(u, "c"); + assert_eq!(p, "b"); + } + + #[test] + fn credential_helper5() { + let td = TempDir::new("git2-rs").unwrap(); + let path = td.path().join("git-credential-script"); + File::create(&path).unwrap().write(br"\ +#!/bin/sh +echo username=c +").unwrap(); + chmod(&path); + + let paths = env::var("PATH").unwrap(); + let paths = env::split_paths(&paths) + .chain(path.parent().map(|p| p.to_path_buf()).into_iter()); + env::set_var("PATH", &env::join_paths(paths).unwrap()); + + let cfg = test_cfg! { + "credential.https://example.com.helper" => "script", + "credential.helper" => "!f() { echo username=a; echo password=b; }; f" + }; + let (u, p) = CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().unwrap(); + assert_eq!(u, "c"); + assert_eq!(p, "b"); + } + + #[test] + fn credential_helper6() { + let cfg = test_cfg! { + "credential.helper" => "" + }; + assert!(CredentialHelper::new("https://example.com/foo/bar") + .config(&cfg) + .execute().is_none()); + } + + #[test] + fn ssh_key_from_memory() { + let cred = Cred::ssh_key_from_memory( + "test", + Some("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDByAO8uj+kXicj6C2ODMspgmUoVyl5eaw8vR6a1yEnFuJFzevabNlN6Ut+CPT3TRnYk5BW73pyXBtnSL2X95BOnbjMDXc4YIkgs3YYHWnxbqsD4Pj/RoGqhf+gwhOBtL0poh8tT8WqXZYxdJQKLQC7oBqf3ykCEYulE4oeRUmNh4IzEE+skD/zDkaJ+S1HRD8D8YCiTO01qQnSmoDFdmIZTi8MS8Cw+O/Qhym1271ThMlhD6PubSYJXfE6rVbE7A9RzH73A6MmKBlzK8VTb4SlNSrr/DOk+L0uq+wPkv+pm+D9WtxoqQ9yl6FaK1cPawa3+7yRNle3m+72KCtyMkQv"), + r#" + -----BEGIN RSA PRIVATE KEY----- + Proc-Type: 4,ENCRYPTED + DEK-Info: AES-128-CBC,818C7722D3B01F2161C2ACF6A5BBAAE8 + + 3Cht4QB3PcoQ0I55j1B3m2ZzIC/mrh+K5nQeA1Vy2GBTMyM7yqGHqTOv7qLhJscd + H+cB0Pm6yCr3lYuNrcKWOCUto+91P7ikyARruHVwyIxKdNx15uNulOzQJHQWNbA4 + RQHlhjON4atVo2FyJ6n+ujK6QiBg2PR5Vbbw/AtV6zBCFW3PhzDn+qqmHjpBFqj2 + vZUUe+MkDQcaF5J45XMHahhSdo/uKCDhfbylExp/+ACWkvxdPpsvcARM6X434ucD + aPY+4i0/JyLkdbm0GFN9/q3i53qf4kCBhojFl4AYJdGI0AzAgbdTXZ7EJHbAGZHS + os5K0oTwDVXMI0sSE2I/qHxaZZsDP1dOKq6di6SFPUp8liYimm7rNintRX88Gl2L + g1ko9abp/NlgD0YY/3mad+NNAISDL/YfXq2fklH3En3/7ZrOVZFKfZXwQwas5g+p + VQPKi3+ae74iOjLyuPDSc1ePmhUNYeP+9rLSc0wiaiHqls+2blPPDxAGMEo63kbz + YPVjdmuVX4VWnyEsfTxxJdFDYGSNh6rlrrO1RFrex7kJvpg5gTX4M/FT8TfCd7Hn + M6adXsLMqwu5tz8FuDmAtVdq8zdSrgZeAbpJ9D3EDOmZ70xz4XBL19ImxDp+Qqs2 + kQX7kobRzeeP2URfRoGr7XZikQWyQ2UASfPcQULY8R58QoZWWsQ4w51GZHg7TDnw + 1DRo/0OgkK7Gqf215nFmMpB4uyi58cq3WFwWQa1IqslkObpVgBQZcNZb/hKUYPGk + g4zehfIgAfCdnQHwZvQ6Fdzhcs3SZeO+zVyuiZN3Gsi9HU0/1vpAKiuuOzcG02vF + b6Y6hwsAA9yphF3atI+ARD4ZwXdDfzuGb3yJglMT3Fr/xuLwAvdchRo1spANKA0E + tT5okLrK0H4wnHvf2SniVVWRhmJis0lQo9LjGGwRIdsPpVnJSDvaISIVF+fHT90r + HvxN8zXI93x9jcPtwp7puQ1C7ehKJK10sZ71OLIZeuUgwt+5DRunqg6evPco9Go7 + UOGwcVhLY200KT+1k7zWzCS0yVQp2HRm6cxsZXAp4ClBSwIx15eIoLIrjZdJRjCq + COp6pZx1fnvJ9ERIvl5hon+Ty+renMcFKz2HmchC7egpcqIxW9Dsv6zjhHle6pxb + 37GaEKHF2KA3RN+dSV/K8n+C9Yent5tx5Y9a/pMcgRGtgu+G+nyFmkPKn5Zt39yX + qDpyM0LtbRVZPs+MgiqoGIwYc/ujoCq7GL38gezsBQoHaTt79yYBqCp6UR0LMuZ5 + f/7CtWqffgySfJ/0wjGidDAumDv8CK45AURpL/Z+tbFG3M9ar/LZz/Y6EyBcLtGY + Wwb4zs8zXIA0qHrjNTnPqHDvezziArYfgPjxCIHMZzms9Yn8+N02p39uIytqg434 + BAlCqZ7GYdDFfTpWIwX+segTK9ux0KdBqcQv+9Fwwjkq9KySnRKqNl7ZJcefFZJq + c6PA1iinZWBjuaO1HKx3PFulrl0bcpR9Kud1ZIyfnh5rwYN8UQkkcR/wZPla04TY + 8l5dq/LI/3G5sZXwUHKOcuQWTj7Saq7Q6gkKoMfqt0wC5bpZ1m17GHPoMz6GtX9O + -----END RSA PRIVATE KEY----- + "#, + Some("test123")); + assert!(cred.is_ok()); + } + + + #[cfg(unix)] + fn chmod(path: &Path) { + use std::os::unix::prelude::*; + use std::fs; + let mut perms = fs::metadata(path).unwrap().permissions(); + perms.set_mode(0o755); + fs::set_permissions(path, perms).unwrap(); + } + #[cfg(windows)] + fn chmod(_path: &Path) {} +} diff --git a/git2/src/describe.rs b/git2/src/describe.rs new file mode 100644 index 000000000..a894c5742 --- /dev/null +++ b/git2/src/describe.rs @@ -0,0 +1,199 @@ +use std::marker; +use std::mem; +use std::ffi::CString; +use std::ptr; + +use libc::{c_uint, c_int}; + +use {raw, Repository, Error, Buf}; +use util::Binding; + +/// The result of a `describe` operation on either an `Describe` or a +/// `Repository`. +pub struct Describe<'repo> { + raw: *mut raw::git_describe_result, + _marker: marker::PhantomData<&'repo Repository>, +} + +/// Options which indicate how a `Describe` is created. +pub struct DescribeOptions { + raw: raw::git_describe_options, + pattern: CString, +} + +/// Options which can be used to customize how a description is formatted. +pub struct DescribeFormatOptions { + raw: raw::git_describe_format_options, + dirty_suffix: CString, +} + +impl<'repo> Describe<'repo> { + /// Prints this describe result, returning the result as a string. + pub fn format(&self, opts: Option<&DescribeFormatOptions>) + -> Result { + let buf = Buf::new(); + let opts = opts.map(|o| &o.raw as *const _).unwrap_or(ptr::null()); + unsafe { + try_call!(raw::git_describe_format(buf.raw(), self.raw, opts)); + } + Ok(String::from_utf8(buf.to_vec()).unwrap()) + } +} + +impl<'repo> Binding for Describe<'repo> { + type Raw = *mut raw::git_describe_result; + + unsafe fn from_raw(raw: *mut raw::git_describe_result) -> Describe<'repo> { + Describe { raw: raw, _marker: marker::PhantomData, } + } + fn raw(&self) -> *mut raw::git_describe_result { self.raw } +} + +impl<'repo> Drop for Describe<'repo> { + fn drop(&mut self) { + unsafe { raw::git_describe_result_free(self.raw) } + } +} + +impl Default for DescribeFormatOptions { + fn default() -> Self { + Self::new() + } +} + +impl DescribeFormatOptions { + /// Creates a new blank set of formatting options for a description. + pub fn new() -> DescribeFormatOptions { + let mut opts = DescribeFormatOptions { + raw: unsafe { mem::zeroed() }, + dirty_suffix: CString::new(Vec::new()).unwrap(), + }; + opts.raw.version = 1; + opts.raw.abbreviated_size = 7; + opts + } + + /// Sets the size of the abbreviated commit id to use. + /// + /// The value is the lower bound for the length of the abbreviated string, + /// and the default is 7. + pub fn abbreviated_size(&mut self, size: u32) -> &mut Self { + self.raw.abbreviated_size = size as c_uint; + self + } + + /// Sets whether or not the long format is used even when a shorter name + /// could be used. + pub fn always_use_long_format(&mut self, long: bool) -> &mut Self { + self.raw.always_use_long_format = long as c_int; + self + } + + /// If the workdir is dirty and this is set, this string will be appended to + /// the description string. + pub fn dirty_suffix(&mut self, suffix: &str) -> &mut Self { + self.dirty_suffix = CString::new(suffix).unwrap(); + self.raw.dirty_suffix = self.dirty_suffix.as_ptr(); + self + } +} + +impl Default for DescribeOptions { + fn default() -> Self { + Self::new() + } +} + +impl DescribeOptions { + /// Creates a new blank set of formatting options for a description. + pub fn new() -> DescribeOptions { + let mut opts = DescribeOptions { + raw: unsafe { mem::zeroed() }, + pattern: CString::new(Vec::new()).unwrap(), + }; + opts.raw.version = 1; + opts.raw.max_candidates_tags = 10; + opts + } + + #[allow(missing_docs)] + pub fn max_candidates_tags(&mut self, max: u32) -> &mut Self { + self.raw.max_candidates_tags = max as c_uint; + self + } + + /// Sets the reference lookup strategy + /// + /// This behaves like the `--tags` option to git-describe. + pub fn describe_tags(&mut self) -> &mut Self { + self.raw.describe_strategy = raw::GIT_DESCRIBE_TAGS as c_uint; + self + } + + /// Sets the reference lookup strategy + /// + /// This behaves like the `--all` option to git-describe. + pub fn describe_all(&mut self) -> &mut Self { + self.raw.describe_strategy = raw::GIT_DESCRIBE_ALL as c_uint; + self + } + + /// Indicates when calculating the distance from the matching tag or + /// reference whether to only walk down the first-parent ancestry. + pub fn only_follow_first_parent(&mut self, follow: bool) -> &mut Self { + self.raw.only_follow_first_parent = follow as c_int; + self + } + + /// If no matching tag or reference is found whether a describe option would + /// normally fail. This option indicates, however, that it will instead fall + /// back to showing the full id of the commit. + pub fn show_commit_oid_as_fallback(&mut self, show: bool) -> &mut Self { + self.raw.show_commit_oid_as_fallback = show as c_int; + self + } + + #[allow(missing_docs)] + pub fn pattern(&mut self, pattern: &str) -> &mut Self { + self.pattern = CString::new(pattern).unwrap(); + self.raw.pattern = self.pattern.as_ptr(); + self + } +} + +impl Binding for DescribeOptions { + type Raw = *mut raw::git_describe_options; + + unsafe fn from_raw(_raw: *mut raw::git_describe_options) + -> DescribeOptions { + panic!("unimplemened") + } + fn raw(&self) -> *mut raw::git_describe_options { + &self.raw as *const _ as *mut _ + } +} + +#[cfg(test)] +mod tests { + use DescribeOptions; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head = t!(repo.head()).target().unwrap(); + + let d = t!(repo.describe(DescribeOptions::new() + .show_commit_oid_as_fallback(true))); + let id = head.to_string(); + assert_eq!(t!(d.format(None)), &id[..7]); + + let obj = t!(repo.find_object(head, None)); + let sig = t!(repo.signature()); + t!(repo.tag("foo", &obj, &sig, "message", true)); + let d = t!(repo.describe(&DescribeOptions::new())); + assert_eq!(t!(d.format(None)), "foo"); + + let d = t!(obj.describe(&DescribeOptions::new())); + assert_eq!(t!(d.format(None)), "foo"); + } +} diff --git a/git2/src/diff.rs b/git2/src/diff.rs new file mode 100644 index 000000000..dffd6117c --- /dev/null +++ b/git2/src/diff.rs @@ -0,0 +1,1258 @@ +use std::ffi::CString; +use std::marker; +use std::mem; +use std::ops::Range; +use std::path::Path; +use std::ptr; +use std::slice; +use libc::{c_char, size_t, c_void, c_int}; + +use {raw, panic, Buf, Delta, Oid, Repository, Error, DiffFormat}; +use {DiffStatsFormat, IntoCString}; +use util::{self, Binding}; + +/// The diff object that contains all individual file deltas. +/// +/// This is an opaque structure which will be allocated by one of the diff +/// generator functions on the `Repository` structure (e.g. `diff_tree_to_tree` +/// or other `diff_*` functions). +pub struct Diff<'repo> { + raw: *mut raw::git_diff, + _marker: marker::PhantomData<&'repo Repository>, +} + +unsafe impl<'repo> Send for Diff<'repo> {} + +/// Description of changes to one entry. +pub struct DiffDelta<'a> { + raw: *mut raw::git_diff_delta, + _marker: marker::PhantomData<&'a raw::git_diff_delta>, +} + +/// Description of one side of a delta. +/// +/// Although this is called a "file" it could represent a file, a symbolic +/// link, a submodule commit id, or even a tree (although that only happens if +/// you are tracking type changes or ignored/untracked directories). +pub struct DiffFile<'a> { + raw: *const raw::git_diff_file, + _marker: marker::PhantomData<&'a raw::git_diff_file>, +} + +/// Structure describing options about how the diff should be executed. +pub struct DiffOptions { + pathspec: Vec, + pathspec_ptrs: Vec<*const c_char>, + old_prefix: Option, + new_prefix: Option, + raw: raw::git_diff_options, +} + +/// Control behavior of rename and copy detection +pub struct DiffFindOptions { + raw: raw::git_diff_find_options, +} + +/// An iterator over the diffs in a delta +pub struct Deltas<'diff> { + range: Range, + diff: &'diff Diff<'diff>, +} + +/// Structure describing a line (or data span) of a diff. +pub struct DiffLine<'a> { + raw: *const raw::git_diff_line, + _marker: marker::PhantomData<&'a raw::git_diff_line>, +} + +/// Structure describing a hunk of a diff. +pub struct DiffHunk<'a> { + raw: *const raw::git_diff_hunk, + _marker: marker::PhantomData<&'a raw::git_diff_hunk>, +} + +/// Structure describing a hunk of a diff. +pub struct DiffStats { + raw: *mut raw::git_diff_stats, +} + +/// Structure describing the binary contents of a diff. +pub struct DiffBinary<'a> { + raw: *const raw::git_diff_binary, + _marker: marker::PhantomData<&'a raw::git_diff_binary>, +} + +/// The contents of one of the files in a binary diff. +pub struct DiffBinaryFile<'a> { + raw: *const raw::git_diff_binary_file, + _marker: marker::PhantomData<&'a raw::git_diff_binary_file>, +} + +/// When producing a binary diff, the binary data returned will be +/// either the deflated full ("literal") contents of the file, or +/// the deflated binary delta between the two sides (whichever is +/// smaller). +#[derive(Copy, Clone, Debug)] +pub enum DiffBinaryKind { + /// There is no binary delta + None, + /// The binary data is the literal contents of the file + Literal, + /// The binary data is the delta from one side to the other + Delta, +} + +type PrintCb<'a> = FnMut(DiffDelta, Option, DiffLine) -> bool + 'a; + +pub type FileCb<'a> = FnMut(DiffDelta, f32) -> bool + 'a; +pub type BinaryCb<'a> = FnMut(DiffDelta, DiffBinary) -> bool + 'a; +pub type HunkCb<'a> = FnMut(DiffDelta, DiffHunk) -> bool + 'a; +pub type LineCb<'a> = FnMut(DiffDelta, Option, DiffLine) -> bool + 'a; + +struct ForeachCallbacks<'a, 'b: 'a, 'c, 'd: 'c, 'e, 'f: 'e, 'g, 'h: 'g> { + file: &'a mut FileCb<'b>, + binary: Option<&'c mut BinaryCb<'d>>, + hunk: Option<&'e mut HunkCb<'f>>, + line: Option<&'g mut LineCb<'h>>, +} + +impl<'repo> Diff<'repo> { + /// Merge one diff into another. + /// + /// This merges items from the "from" list into the "self" list. The + /// resulting diff will have all items that appear in either list. + /// If an item appears in both lists, then it will be "merged" to appear + /// as if the old version was from the "onto" list and the new version + /// is from the "from" list (with the exception that if the item has a + /// pending DELETE in the middle, then it will show as deleted). + pub fn merge(&mut self, from: &Diff<'repo>) -> Result<(), Error> { + unsafe { try_call!(raw::git_diff_merge(self.raw, &*from.raw)); } + Ok(()) + } + + /// Returns an iterator over the deltas in this diff. + pub fn deltas(&self) -> Deltas { + let num_deltas = unsafe { raw::git_diff_num_deltas(&*self.raw) }; + Deltas { range: 0..(num_deltas as usize), diff: self } + } + + /// Return the diff delta for an entry in the diff list. + pub fn get_delta(&self, i: usize) -> Option { + unsafe { + let ptr = raw::git_diff_get_delta(&*self.raw, i as size_t); + Binding::from_raw_opt(ptr as *mut _) + } + } + + /// Check if deltas are sorted case sensitively or insensitively. + pub fn is_sorted_icase(&self) -> bool { + unsafe { raw::git_diff_is_sorted_icase(&*self.raw) == 1 } + } + + /// Iterate over a diff generating formatted text output. + /// + /// Returning `false` from the callback will terminate the iteration and + /// return an error from this function. + pub fn print(&self, format: DiffFormat, mut cb: F) -> Result<(), Error> + where F: FnMut(DiffDelta, + Option, + DiffLine) -> bool { + let mut cb: &mut PrintCb = &mut cb; + let ptr = &mut cb as *mut _; + unsafe { + try_call!(raw::git_diff_print(self.raw, format, print_cb, + ptr as *mut _)); + Ok(()) + } + } + + /// Loop over all deltas in a diff issuing callbacks. + /// + /// Returning `false` from any callback will terminate the iteration and + /// return an error from this function. + pub fn foreach(&self, + file_cb: &mut FileCb, + binary_cb: Option<&mut BinaryCb>, + hunk_cb: Option<&mut HunkCb>, + line_cb: Option<&mut LineCb>) -> Result<(), Error> { + let mut cbs = ForeachCallbacks { + file: file_cb, + binary: binary_cb, + hunk: hunk_cb, + line: line_cb, + }; + let ptr = &mut cbs as *mut _; + unsafe { + let binary_cb_c = if cbs.binary.is_some() { + Some(binary_cb_c as raw::git_diff_binary_cb) + } else { + None + }; + let hunk_cb_c = if cbs.hunk.is_some() { + Some(hunk_cb_c as raw::git_diff_hunk_cb) + } else { + None + }; + let line_cb_c = if cbs.line.is_some() { + Some(line_cb_c as raw::git_diff_line_cb) + } else { + None + }; + try_call!(raw::git_diff_foreach(self.raw, file_cb_c, binary_cb_c, + hunk_cb_c, line_cb_c, + ptr as *mut _)); + Ok(()) + } + } + + /// Accumulate diff statistics for all patches. + pub fn stats(&self) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_get_stats(&mut ret, self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Transform a diff marking file renames, copies, etc. + /// + /// This modifies a diff in place, replacing old entries that look like + /// renames or copies with new entries reflecting those changes. This also + /// will, if requested, break modified files into add/remove pairs if the + /// amount of change is above a threshold. + pub fn find_similar(&mut self, opts: Option<&mut DiffFindOptions>) + -> Result<(), Error> { + let opts = opts.map(|opts| &opts.raw); + unsafe { try_call!(raw::git_diff_find_similar(self.raw, opts)); } + Ok(()) + } + + // TODO: num_deltas_of_type, format_email, find_similar +} + +pub extern fn print_cb(delta: *const raw::git_diff_delta, + hunk: *const raw::git_diff_hunk, + line: *const raw::git_diff_line, + data: *mut c_void) -> c_int { + unsafe { + let delta = Binding::from_raw(delta as *mut _); + let hunk = Binding::from_raw_opt(hunk); + let line = Binding::from_raw(line); + + let r = panic::wrap(|| { + let data = data as *mut &mut PrintCb; + (*data)(delta, hunk, line) + }); + if r == Some(true) {0} else {-1} + } +} + +extern fn file_cb_c(delta: *const raw::git_diff_delta, + progress: f32, + data: *mut c_void) -> c_int { + unsafe { + let delta = Binding::from_raw(delta as *mut _); + + let r = panic::wrap(|| { + let cbs = data as *mut ForeachCallbacks; + ((*cbs).file)(delta, progress) + }); + if r == Some(true) {0} else {-1} + } +} + +extern fn binary_cb_c(delta: *const raw::git_diff_delta, + binary: *const raw::git_diff_binary, + data: *mut c_void) -> c_int { + unsafe { + let delta = Binding::from_raw(delta as *mut _); + let binary = Binding::from_raw(binary); + + let r = panic::wrap(|| { + let cbs = data as *mut ForeachCallbacks; + match (*cbs).binary { + Some(ref mut cb) => cb(delta, binary), + None => false, + } + }); + if r == Some(true) {0} else {-1} + } +} + +extern fn hunk_cb_c(delta: *const raw::git_diff_delta, + hunk: *const raw::git_diff_hunk, + data: *mut c_void) -> c_int { + unsafe { + let delta = Binding::from_raw(delta as *mut _); + let hunk = Binding::from_raw(hunk); + + let r = panic::wrap(|| { + let cbs = data as *mut ForeachCallbacks; + match (*cbs).hunk { + Some(ref mut cb) => cb(delta, hunk), + None => false, + } + }); + if r == Some(true) {0} else {-1} + } +} + +extern fn line_cb_c(delta: *const raw::git_diff_delta, + hunk: *const raw::git_diff_hunk, + line: *const raw::git_diff_line, + data: *mut c_void) -> c_int { + unsafe { + let delta = Binding::from_raw(delta as *mut _); + let hunk = Binding::from_raw_opt(hunk); + let line = Binding::from_raw(line); + + let r = panic::wrap(|| { + let cbs = data as *mut ForeachCallbacks; + match (*cbs).line { + Some(ref mut cb) => cb(delta, hunk, line), + None => false, + } + }); + if r == Some(true) {0} else {-1} + } +} + + +impl<'repo> Binding for Diff<'repo> { + type Raw = *mut raw::git_diff; + unsafe fn from_raw(raw: *mut raw::git_diff) -> Diff<'repo> { + Diff { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_diff { self.raw } +} + +impl<'repo> Drop for Diff<'repo> { + fn drop(&mut self) { + unsafe { raw::git_diff_free(self.raw) } + } +} + +impl<'a> DiffDelta<'a> { + // TODO: expose when diffs are more exposed + // pub fn similarity(&self) -> u16 { + // unsafe { (*self.raw).similarity } + // } + + /// Returns the number of files in this delta. + pub fn nfiles(&self) -> u16 { + unsafe { (*self.raw).nfiles } + } + + /// Returns the status of this entry + /// + /// For more information, see `Delta`'s documentation + pub fn status(&self) -> Delta { + match unsafe { (*self.raw).status } { + raw::GIT_DELTA_UNMODIFIED => Delta::Unmodified, + raw::GIT_DELTA_ADDED => Delta::Added, + raw::GIT_DELTA_DELETED => Delta::Deleted, + raw::GIT_DELTA_MODIFIED => Delta::Modified, + raw::GIT_DELTA_RENAMED => Delta::Renamed, + raw::GIT_DELTA_COPIED => Delta::Copied, + raw::GIT_DELTA_IGNORED => Delta::Ignored, + raw::GIT_DELTA_UNTRACKED => Delta::Untracked, + raw::GIT_DELTA_TYPECHANGE => Delta::Typechange, + raw::GIT_DELTA_UNREADABLE => Delta::Unreadable, + raw::GIT_DELTA_CONFLICTED => Delta::Conflicted, + n => panic!("unknown diff status: {}", n), + } + } + + /// Return the file which represents the "from" side of the diff. + /// + /// What side this means depends on the function that was used to generate + /// the diff and will be documented on the function itself. + pub fn old_file(&self) -> DiffFile<'a> { + unsafe { Binding::from_raw(&(*self.raw).old_file as *const _) } + } + + /// Return the file which represents the "to" side of the diff. + /// + /// What side this means depends on the function that was used to generate + /// the diff and will be documented on the function itself. + pub fn new_file(&self) -> DiffFile<'a> { + unsafe { Binding::from_raw(&(*self.raw).new_file as *const _) } + } +} + +impl<'a> Binding for DiffDelta<'a> { + type Raw = *mut raw::git_diff_delta; + unsafe fn from_raw(raw: *mut raw::git_diff_delta) -> DiffDelta<'a> { + DiffDelta { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_diff_delta { self.raw } +} + +impl<'a> DiffFile<'a> { + /// Returns the Oid of this item. + /// + /// If this entry represents an absent side of a diff (e.g. the `old_file` + /// of a `Added` delta), then the oid returned will be zeroes. + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(&(*self.raw).id as *const _) } + } + + /// Returns the path, in bytes, of the entry relative to the working + /// directory of the repository. + pub fn path_bytes(&self) -> Option<&'a [u8]> { + static FOO: () = (); + unsafe { ::opt_bytes(&FOO, (*self.raw).path) } + } + + /// Returns the path of the entry relative to the working directory of the + /// repository. + pub fn path(&self) -> Option<&'a Path> { + self.path_bytes().map(util::bytes2path) + } + + /// Returns the size of this entry, in bytes + pub fn size(&self) -> u64 { unsafe { (*self.raw).size as u64 } } + + // TODO: expose flags/mode +} + +impl<'a> Binding for DiffFile<'a> { + type Raw = *const raw::git_diff_file; + unsafe fn from_raw(raw: *const raw::git_diff_file) -> DiffFile<'a> { + DiffFile { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_diff_file { self.raw } +} + +impl Default for DiffOptions { + fn default() -> Self { + Self::new() + } +} + +impl DiffOptions { + /// Creates a new set of empty diff options. + /// + /// All flags and other options are defaulted to false or their otherwise + /// zero equivalents. + pub fn new() -> DiffOptions { + let mut opts = DiffOptions { + pathspec: Vec::new(), + pathspec_ptrs: Vec::new(), + raw: unsafe { mem::zeroed() }, + old_prefix: None, + new_prefix: None, + }; + assert_eq!(unsafe { + raw::git_diff_init_options(&mut opts.raw, 1) + }, 0); + opts + } + + fn flag(&mut self, opt: i32, val: bool) -> &mut DiffOptions { + let opt = opt as u32; + if val { + self.raw.flags |= opt; + } else { + self.raw.flags &= !opt; + } + self + } + + /// Flag indicating whether the sides of the diff will be reversed. + pub fn reverse(&mut self, reverse: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_REVERSE, reverse) + } + + /// Flag indicating whether ignored files are included. + pub fn include_ignored(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_IGNORED, include) + } + + /// Flag indicating whether ignored directories are traversed deeply or not. + pub fn recurse_ignored_dirs(&mut self, recurse: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_RECURSE_IGNORED_DIRS, recurse) + } + + /// Flag indicating whether untracked files are in the diff + pub fn include_untracked(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_UNTRACKED, include) + } + + /// Flag indicating whether untracked directories are deeply traversed or + /// not. + pub fn recurse_untracked_dirs(&mut self, recurse: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_RECURSE_UNTRACKED_DIRS, recurse) + } + + /// Flag indicating whether unmodified files are in the diff. + pub fn include_unmodified(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_UNMODIFIED, include) + } + + /// If entrabled, then Typechange delta records are generated. + pub fn include_typechange(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_TYPECHANGE, include) + } + + /// Event with `include_typechange`, the tree treturned generally shows a + /// deleted blow. This flag correctly labels the tree transitions as a + /// typechange record with the `new_file`'s mode set to tree. + /// + /// Note that the tree SHA will not be available. + pub fn include_typechange_trees(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_TYPECHANGE_TREES, include) + } + + /// Flag indicating whether file mode changes are ignored. + pub fn ignore_filemode(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_FILEMODE, ignore) + } + + /// Flag indicating whether all submodules should be treated as unmodified. + pub fn ignore_submodules(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_SUBMODULES, ignore) + } + + /// Flag indicating whether case insensitive filenames should be used. + pub fn ignore_case(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_CASE, ignore) + } + + /// If pathspecs are specified, this flag means that they should be applied + /// as an exact match instead of a fnmatch pattern. + pub fn disable_pathspec_match(&mut self, disable: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_DISABLE_PATHSPEC_MATCH, disable) + } + + /// Disable updating the `binary` flag in delta records. This is useful when + /// iterating over a diff if you don't need hunk and data callbacks and want + /// to avoid having to load a file completely. + pub fn skip_binary_check(&mut self, skip: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_SKIP_BINARY_CHECK, skip) + } + + /// When diff finds an untracked directory, to match the behavior of core + /// Git, it scans the contents for ignored and untracked files. If all + /// contents are ignored, then the directory is ignored; if any contents are + /// not ignored, then the directory is untracked. This is extra work that + /// may not matter in many cases. + /// + /// This flag turns off that scan and immediately labels an untracked + /// directory as untracked (changing the behavior to not match core git). + pub fn enable_fast_untracked_dirs(&mut self, enable: bool) + -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS, enable) + } + + /// When diff finds a file in the working directory with stat information + /// different from the index, but the OID ends up being the same, write the + /// correct stat information into the index. Note: without this flag, diff + /// will always leave the index untouched. + pub fn update_index(&mut self, update: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_UPDATE_INDEX, update) + } + + /// Include unreadable files in the diff + pub fn include_unreadable(&mut self, include: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_UNREADABLE, include) + } + + /// Include unreadable files in the diff + pub fn include_unreadable_as_untracked(&mut self, include: bool) + -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED, include) + } + + /// Treat all files as text, disabling binary attributes and detection. + pub fn force_text(&mut self, force: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_FORCE_TEXT, force) + } + + /// Treat all files as binary, disabling text diffs + pub fn force_binary(&mut self, force: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_FORCE_TEXT, force) + } + + /// Ignore all whitespace + pub fn ignore_whitespace(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_WHITESPACE, ignore) + } + + /// Ignore changes in the amount of whitespace + pub fn ignore_whitespace_change(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_WHITESPACE_CHANGE, ignore) + } + + /// Ignore whitespace at tend of line + pub fn ignore_whitespace_eol(&mut self, ignore: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_IGNORE_WHITESPACE_EOL, ignore) + } + + /// When generating patch text, include the content of untracked files. + /// + /// This automatically turns on `include_untracked` but it does not turn on + /// `recurse_untracked_dirs`. Add that flag if you want the content of every + /// single untracked file. + pub fn show_untracked_content(&mut self, show: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_SHOW_UNTRACKED_CONTENT, show) + } + + /// When generating output, include the names of unmodified files if they + /// are included in the `Diff`. Normally these are skipped in the formats + /// that list files (e.g. name-only, name-status, raw). Even with this these + /// will not be included in the patch format. + pub fn show_unmodified(&mut self, show: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_SHOW_UNMODIFIED, show) + } + + /// Use the "patience diff" algorithm + pub fn patience(&mut self, patience: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_PATIENCE, patience) + } + + /// Take extra time to find the minimal diff + pub fn minimal(&mut self, minimal: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_MINIMAL, minimal) + } + + /// Include the necessary deflate/delta information so that `git-apply` can + /// apply given diff information to binary files. + pub fn show_binary(&mut self, show: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_SHOW_BINARY, show) + } + + /// Use a heuristic that takes indentation and whitespace into account + /// which generally can produce better diffs when dealing with ambiguous + /// diff hunks. + pub fn indent_heuristic(&mut self, heuristic: bool) -> &mut DiffOptions { + self.flag(raw::GIT_DIFF_INDENT_HEURISTIC, heuristic) + } + + /// Set the number of unchanged lines that define the boundary of a hunk + /// (and to display before and after). + /// + /// The default value for this is 3. + pub fn context_lines(&mut self, lines: u32) -> &mut DiffOptions { + self.raw.context_lines = lines; + self + } + + /// Set the maximum number of unchanged lines between hunk boundaries before + /// the hunks will be merged into one. + /// + /// The default value for this is 0. + pub fn interhunk_lines(&mut self, lines: u32) -> &mut DiffOptions { + self.raw.interhunk_lines = lines; + self + } + + /// The default value for this is `core.abbrev` or 7 if unset. + pub fn id_abbrev(&mut self, abbrev: u16) -> &mut DiffOptions { + self.raw.id_abbrev = abbrev; + self + } + + /// Maximum size (in bytes) above which a blob will be marked as binary + /// automatically. + /// + /// A negative value will disable this entirely. + /// + /// The default value for this is 512MB. + pub fn max_size(&mut self, size: i64) -> &mut DiffOptions { + self.raw.max_size = size as raw::git_off_t; + self + } + + /// The virtual "directory" to prefix old file names with in hunk headers. + /// + /// The default value for this is "a". + pub fn old_prefix(&mut self, t: T) -> &mut DiffOptions { + self.old_prefix = Some(t.into_c_string().unwrap()); + self + } + + /// The virtual "directory" to prefix new file names with in hunk headers. + /// + /// The default value for this is "b". + pub fn new_prefix(&mut self, t: T) -> &mut DiffOptions { + self.new_prefix = Some(t.into_c_string().unwrap()); + self + } + + /// Add to the array of paths/fnmatch patterns to constrain the diff. + pub fn pathspec(&mut self, pathspec: T) + -> &mut DiffOptions { + let s = pathspec.into_c_string().unwrap(); + self.pathspec_ptrs.push(s.as_ptr()); + self.pathspec.push(s); + self + } + + /// Acquire a pointer to the underlying raw options. + /// + /// This function is unsafe as the pointer is only valid so long as this + /// structure is not moved, modified, or used elsewhere. + pub unsafe fn raw(&mut self) -> *const raw::git_diff_options { + self.raw.old_prefix = self.old_prefix.as_ref().map(|s| s.as_ptr()) + .unwrap_or(ptr::null()); + self.raw.new_prefix = self.new_prefix.as_ref().map(|s| s.as_ptr()) + .unwrap_or(ptr::null()); + self.raw.pathspec.count = self.pathspec_ptrs.len() as size_t; + self.raw.pathspec.strings = self.pathspec_ptrs.as_ptr() as *mut _; + &self.raw as *const _ + } + + // TODO: expose ignore_submodules, notify_cb/notify_payload +} + +impl<'diff> Iterator for Deltas<'diff> { + type Item = DiffDelta<'diff>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.diff.get_delta(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'diff> DoubleEndedIterator for Deltas<'diff> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.diff.get_delta(i)) + } +} +impl<'diff> ExactSizeIterator for Deltas<'diff> {} + +impl<'a> DiffLine<'a> { + /// Line number in old file or `None` for added line + pub fn old_lineno(&self) -> Option { + match unsafe { (*self.raw).old_lineno } { + n if n < 0 => None, + n => Some(n as u32), + } + } + + /// Line number in new file or `None` for deleted line + pub fn new_lineno(&self) -> Option { + match unsafe { (*self.raw).new_lineno } { + n if n < 0 => None, + n => Some(n as u32), + } + } + + /// Number of newline characters in content + pub fn num_lines(&self) -> u32 { + unsafe { (*self.raw).num_lines as u32 } + } + + /// Offset in the original file to the content + pub fn content_offset(&self) -> i64 { + unsafe { (*self.raw).content_offset as i64 } + } + + /// Content of this line as bytes. + pub fn content(&self) -> &[u8] { + unsafe { + slice::from_raw_parts((*self.raw).content as *const u8, + (*self.raw).content_len as usize) + } + } + + /// Sigil showing the origin of this `DiffLine`. + /// + /// * ` ` - Line context + /// * `+` - Line addition + /// * `-` - Line deletion + /// * `=` - Context (End of file) + /// * `>` - Add (End of file) + /// * `<` - Remove (End of file) + /// * `F` - File header + /// * `H` - Hunk header + /// * `B` - Line binary + pub fn origin(&self) -> char { + match unsafe { (*self.raw).origin as raw::git_diff_line_t } { + raw::GIT_DIFF_LINE_CONTEXT => ' ', + raw::GIT_DIFF_LINE_ADDITION => '+', + raw::GIT_DIFF_LINE_DELETION => '-', + raw::GIT_DIFF_LINE_CONTEXT_EOFNL => '=', + raw::GIT_DIFF_LINE_ADD_EOFNL => '>', + raw::GIT_DIFF_LINE_DEL_EOFNL => '<', + raw::GIT_DIFF_LINE_FILE_HDR => 'F', + raw::GIT_DIFF_LINE_HUNK_HDR => 'H', + raw::GIT_DIFF_LINE_BINARY => 'B', + _ => ' ', + } + } +} + +impl<'a> Binding for DiffLine<'a> { + type Raw = *const raw::git_diff_line; + unsafe fn from_raw(raw: *const raw::git_diff_line) -> DiffLine<'a> { + DiffLine { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_diff_line { self.raw } +} + +impl<'a> DiffHunk<'a> { + /// Starting line number in old_file + pub fn old_start(&self) -> u32 { + unsafe { (*self.raw).old_start as u32 } + } + + /// Number of lines in old_file + pub fn old_lines(&self) -> u32 { + unsafe { (*self.raw).old_lines as u32 } + } + + /// Starting line number in new_file + pub fn new_start(&self) -> u32 { + unsafe { (*self.raw).new_start as u32 } + } + + /// Number of lines in new_file + pub fn new_lines(&self) -> u32 { + unsafe { (*self.raw).new_lines as u32 } + } + + /// Header text + pub fn header(&self) -> &[u8] { + unsafe { + slice::from_raw_parts((*self.raw).header.as_ptr() as *const u8, + (*self.raw).header_len as usize) + } + } +} + +impl<'a> Binding for DiffHunk<'a> { + type Raw = *const raw::git_diff_hunk; + unsafe fn from_raw(raw: *const raw::git_diff_hunk) -> DiffHunk<'a> { + DiffHunk { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_diff_hunk { self.raw } +} + +impl DiffStats { + /// Get the total number of files chaned in a diff. + pub fn files_changed(&self) -> usize { + unsafe { raw::git_diff_stats_files_changed(&*self.raw) as usize } + } + + /// Get the total number of insertions in a diff + pub fn insertions(&self) -> usize { + unsafe { raw::git_diff_stats_insertions(&*self.raw) as usize } + } + + /// Get the total number of deletions in a diff + pub fn deletions(&self) -> usize { + unsafe { raw::git_diff_stats_deletions(&*self.raw) as usize } + } + + /// Print diff statistics to a Buf + pub fn to_buf(&self, format: DiffStatsFormat, width: usize) + -> Result { + let buf = Buf::new(); + unsafe { + try_call!(raw::git_diff_stats_to_buf(buf.raw(), self.raw, + format.bits(), + width as size_t)); + } + Ok(buf) + } +} + +impl Binding for DiffStats { + type Raw = *mut raw::git_diff_stats; + + unsafe fn from_raw(raw: *mut raw::git_diff_stats) -> DiffStats { + DiffStats { raw: raw } + } + fn raw(&self) -> *mut raw::git_diff_stats { self.raw } +} + +impl Drop for DiffStats { + fn drop(&mut self) { + unsafe { raw::git_diff_stats_free(self.raw) } + } +} + +impl<'a> DiffBinary<'a> { + /// Returns whether there is data in this binary structure or not. + /// + /// If this is `true`, then this was produced and included binary content. + /// If this is `false` then this was generated knowing only that a binary + /// file changed but without providing the data, probably from a patch that + /// said `Binary files a/file.txt and b/file.txt differ`. + pub fn contains_data(&self) -> bool { + unsafe { (*self.raw).contains_data == 1 } + } + + /// The contents of the old file. + pub fn old_file(&self) -> DiffBinaryFile<'a> { + unsafe { Binding::from_raw(&(*self.raw).old_file as *const _) } + } + + /// The contents of the new file. + pub fn new_file(&self) -> DiffBinaryFile<'a> { + unsafe { Binding::from_raw(&(*self.raw).new_file as *const _) } + } +} + +impl<'a> Binding for DiffBinary<'a> { + type Raw = *const raw::git_diff_binary; + unsafe fn from_raw(raw: *const raw::git_diff_binary) -> DiffBinary<'a> { + DiffBinary { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_diff_binary { self.raw } +} + +impl<'a> DiffBinaryFile<'a> { + /// The type of binary data for this file + pub fn kind(&self) -> DiffBinaryKind { + unsafe { Binding::from_raw((*self.raw).kind) } + } + + /// The binary data, deflated + pub fn data(&self) -> &[u8] { + unsafe { + slice::from_raw_parts((*self.raw).data as *const u8, + (*self.raw).datalen as usize) + } + } + + /// The length of the binary data after inflation + pub fn inflated_len(&self) -> usize { + unsafe { (*self.raw).inflatedlen as usize } + } + +} + +impl<'a> Binding for DiffBinaryFile<'a> { + type Raw = *const raw::git_diff_binary_file; + unsafe fn from_raw(raw: *const raw::git_diff_binary_file) -> DiffBinaryFile<'a> { + DiffBinaryFile { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_diff_binary_file { self.raw } +} + +impl Binding for DiffBinaryKind { + type Raw = raw::git_diff_binary_t; + unsafe fn from_raw(raw: raw::git_diff_binary_t) -> DiffBinaryKind { + match raw { + raw::GIT_DIFF_BINARY_NONE => DiffBinaryKind::None, + raw::GIT_DIFF_BINARY_LITERAL => DiffBinaryKind::Literal, + raw::GIT_DIFF_BINARY_DELTA => DiffBinaryKind::Delta, + _ => panic!("Unknown git diff binary kind"), + } + } + fn raw(&self) -> raw::git_diff_binary_t { + match *self { + DiffBinaryKind::None => raw::GIT_DIFF_BINARY_NONE, + DiffBinaryKind::Literal => raw::GIT_DIFF_BINARY_LITERAL, + DiffBinaryKind::Delta => raw::GIT_DIFF_BINARY_DELTA, + } + } +} + +impl Default for DiffFindOptions { + fn default() -> Self { + Self::new() + } +} + +impl DiffFindOptions { + /// Creates a new set of empty diff find options. + /// + /// All flags and other options are defaulted to false or their otherwise + /// zero equivalents. + pub fn new() -> DiffFindOptions { + let mut opts = DiffFindOptions { + raw: unsafe { mem::zeroed() }, + }; + assert_eq!(unsafe { + raw::git_diff_find_init_options(&mut opts.raw, 1) + }, 0); + opts + } + + fn flag(&mut self, opt: u32, val: bool) -> &mut DiffFindOptions { + if val { + self.raw.flags |= opt; + } else { + self.raw.flags &= !opt; + } + self + } + + /// Reset all flags back to their unset state, indicating that + /// `diff.renames` should be used instead. This is overridden once any flag + /// is set. + pub fn by_config(&mut self) -> &mut DiffFindOptions { + self.flag(0xffffffff, false) + } + + /// Look for renames? + pub fn renames(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_RENAMES, find) + } + + /// Consider old side of modified for renames? + pub fn renames_from_rewrites(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_RENAMES_FROM_REWRITES, find) + } + + /// Look for copies? + pub fn copies(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_COPIES, find) + } + + /// Consider unmodified as copy sources? + /// + /// For this to work correctly, use `include_unmodified` when the initial + /// diff is being generated. + pub fn copies_from_unmodified(&mut self, find: bool) + -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED, find) + } + + /// Mark significant rewrites for split. + pub fn rewrites(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_REWRITES, find) + } + + /// Actually split large rewrites into delete/add pairs + pub fn break_rewrites(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_BREAK_REWRITES, find) + } + + #[doc(hidden)] + pub fn break_rewries(&mut self, find: bool) -> &mut DiffFindOptions { + self.break_rewrites(find) + } + + /// Find renames/copies for untracked items in working directory. + /// + /// For this to work correctly use the `include_untracked` option when the + /// initial diff is being generated. + pub fn for_untracked(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_FOR_UNTRACKED, find) + } + + /// Turn on all finding features. + pub fn all(&mut self, find: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_ALL, find) + } + + /// Measure similarity ignoring leading whitespace (default) + pub fn ignore_leading_whitespace(&mut self, ignore: bool) + -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE, ignore) + } + + /// Measure similarity ignoring all whitespace + pub fn ignore_whitespace(&mut self, ignore: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_IGNORE_WHITESPACE, ignore) + } + + /// Measure similarity including all data + pub fn dont_ignore_whitespace(&mut self, dont: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE, dont) + } + + /// Measure similarity only by comparing SHAs (fast and cheap) + pub fn exact_match_only(&mut self, exact: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_EXACT_MATCH_ONLY, exact) + } + + /// Do not break rewrites unless they contribute to a rename. + /// + /// Normally, `break_rewrites` and `rewrites` will measure the + /// self-similarity of modified files and split the ones that have changed a + /// lot into a delete/add pair. Then the sides of that pair will be + /// considered candidates for rename and copy detection + /// + /// If you add this flag in and the split pair is not used for an actual + /// rename or copy, then the modified record will be restored to a regular + /// modified record instead of being split. + pub fn break_rewrites_for_renames_only(&mut self, b: bool) + -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY, b) + } + + /// Remove any unmodified deltas after find_similar is done. + /// + /// Using `copies_from_unmodified` to emulate the `--find-copies-harder` + /// behavior requires building a diff with the `include_unmodified` flag. If + /// you do not want unmodified records in the final result, pas this flag to + /// have them removed. + pub fn remove_unmodified(&mut self, remove: bool) -> &mut DiffFindOptions { + self.flag(raw::GIT_DIFF_FIND_REMOVE_UNMODIFIED, remove) + } + + /// Similarity to consider a file renamed (default 50) + pub fn rename_threshold(&mut self, thresh: u16) -> &mut DiffFindOptions { + self.raw.rename_threshold = thresh; + self + } + + /// Similarity of modified to be glegible rename source (default 50) + pub fn rename_from_rewrite_threshold(&mut self, thresh: u16) + -> &mut DiffFindOptions { + self.raw.rename_from_rewrite_threshold = thresh; + self + } + + /// Similarity to consider a file copy (default 50) + pub fn copy_threshold(&mut self, thresh: u16) -> &mut DiffFindOptions { + self.raw.copy_threshold = thresh; + self + } + + /// Similarity to split modify into delete/add pair (default 60) + pub fn break_rewrite_threshold(&mut self, thresh: u16) + -> &mut DiffFindOptions { + self.raw.break_rewrite_threshold = thresh; + self + } + + /// Maximum similarity sources to examine for a file (somewhat like + /// git-diff's `-l` option or `diff.renameLimit` config) + /// + /// Defaults to 200 + pub fn rename_limit(&mut self, limit: usize) -> &mut DiffFindOptions { + self.raw.rename_limit = limit as size_t; + self + } + + // TODO: expose git_diff_similarity_metric +} + +#[cfg(test)] +mod tests { + use DiffOptions; + use std::fs::File; + use std::path::Path; + use std::borrow::Borrow; + use std::io::Write; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let diff = repo.diff_tree_to_workdir(None, None).unwrap(); + assert_eq!(diff.deltas().len(), 0); + let stats = diff.stats().unwrap(); + assert_eq!(stats.insertions(), 0); + assert_eq!(stats.deletions(), 0); + assert_eq!(stats.files_changed(), 0); + } + + #[test] + fn foreach_smoke() { + let (_td, repo) = ::test::repo_init(); + let diff = t!(repo.diff_tree_to_workdir(None, None)); + let mut count = 0; + t!(diff.foreach(&mut |_file, _progress| { count = count + 1; true }, + None, None, None)); + assert_eq!(count, 0); + } + + #[test] + fn foreach_file_only() { + let path = Path::new("foo"); + let (td, repo) = ::test::repo_init(); + t!(t!(File::create(&td.path().join(path))).write_all(b"bar")); + let mut opts = DiffOptions::new(); + opts.include_untracked(true); + let diff = t!(repo.diff_tree_to_workdir(None, Some(&mut opts))); + let mut count = 0; + let mut result = None; + t!(diff.foreach(&mut |file, _progress| { + count = count + 1; + result = file.new_file().path().map(ToOwned::to_owned); + true + }, None, None, None)); + assert_eq!(result.as_ref().map(Borrow::borrow), Some(path)); + assert_eq!(count, 1); + } + + #[test] + fn foreach_file_and_hunk() { + let path = Path::new("foo"); + let (td, repo) = ::test::repo_init(); + t!(t!(File::create(&td.path().join(path))).write_all(b"bar")); + let mut index = t!(repo.index()); + t!(index.add_path(path)); + let mut opts = DiffOptions::new(); + opts.include_untracked(true); + let diff = t!(repo.diff_tree_to_index(None, Some(&index), + Some(&mut opts))); + let mut new_lines = 0; + t!(diff.foreach( + &mut |_file, _progress| { true }, + None, + Some(&mut |_file, hunk| { + new_lines = hunk.new_lines(); + true + }), + None)); + assert_eq!(new_lines, 1); + } + + #[test] + fn foreach_all_callbacks() { + let fib = vec![0, 1, 1, 2, 3, 5, 8]; + // Verified with a node implementation of deflate, might be worth + // adding a deflate lib to do this inline here. + let deflated_fib = vec![120, 156, 99, 96, 100, 100, 98, 102, 229, 0, 0, + 0, 53, 0, 21]; + let foo_path = Path::new("foo"); + let bin_path = Path::new("bin"); + let (td, repo) = ::test::repo_init(); + t!(t!(File::create(&td.path().join(foo_path))).write_all(b"bar\n")); + t!(t!(File::create(&td.path().join(bin_path))).write_all(&fib)); + let mut index = t!(repo.index()); + t!(index.add_path(foo_path)); + t!(index.add_path(bin_path)); + let mut opts = DiffOptions::new(); + opts.include_untracked(true).show_binary(true); + let diff = t!(repo.diff_tree_to_index(None, Some(&index), + Some(&mut opts))); + let mut bin_content = None; + let mut new_lines = 0; + let mut line_content = None; + t!(diff.foreach( + &mut |_file, _progress| { true }, + Some(&mut |_file, binary| { + bin_content = Some(binary.new_file().data().to_owned()); + true + }), + Some(&mut |_file, hunk| { + new_lines = hunk.new_lines(); + true + }), + Some(&mut |_file, _hunk, line| { + line_content = String::from_utf8(line.content().into()).ok(); + true + }))); + assert_eq!(bin_content, Some(deflated_fib)); + assert_eq!(new_lines, 1); + assert_eq!(line_content, Some("bar\n".to_string())); + } +} diff --git a/git2/src/error.rs b/git2/src/error.rs new file mode 100644 index 000000000..1e92b23a0 --- /dev/null +++ b/git2/src/error.rs @@ -0,0 +1,284 @@ +use std::env::JoinPathsError; +use std::ffi::{CStr, NulError}; +use std::error; +use std::fmt; +use std::str; +use libc::c_int; + +use {raw, ErrorClass, ErrorCode}; + +/// A structure to represent errors coming out of libgit2. +#[derive(Debug,PartialEq)] +pub struct Error { + code: c_int, + klass: c_int, + message: String, +} + +impl Error { + /// Returns the last error that happened with the code specified by `code`. + /// + /// The `code` argument typically comes from the return value of a function + /// call. This code will later be returned from the `code` function. + /// + /// Historically this function returned `Some` or `None` based on the return + /// value of `giterr_last` but nowadays it always returns `Some` so it's + /// safe to unwrap the return value. This API will change in the next major + /// version. + pub fn last_error(code: c_int) -> Option { + ::init(); + unsafe { + // Note that whenever libgit2 returns an error any negative value + // indicates that an error happened. Auxiliary information is + // *usually* in `giterr_last` but unfortunately that's not always + // the case. Sometimes a negative error code is returned from + // libgit2 *without* calling `giterr_set` internally to configure + // the error. + // + // To handle this case and hopefully provide better error messages + // on our end we unconditionally call `giterr_clear` when we're done + // with an error. This is an attempt to clear it as aggressively as + // possible when we can to ensure that error information from one + // api invocation doesn't leak over to the next api invocation. + // + // Additionally if `giterr_last` returns null then we returned a + // canned error out. + let ptr = raw::giterr_last(); + let err = if ptr.is_null() { + let mut error = Error::from_str("an unknown git error occurred"); + error.code = code; + error + } else { + Error::from_raw(code, ptr) + }; + raw::giterr_clear(); + Some(err) + } + } + + unsafe fn from_raw(code: c_int, ptr: *const raw::git_error) -> Error { + let msg = CStr::from_ptr((*ptr).message as *const _).to_bytes(); + let msg = String::from_utf8_lossy(msg).into_owned(); + Error { code: code, klass: (*ptr).klass, message: msg } + } + + /// Creates a new error from the given string as the error. + /// + /// The error returned will have the code `GIT_ERROR` and the class + /// `GITERR_NONE`. + pub fn from_str(s: &str) -> Error { + Error { + code: raw::GIT_ERROR as c_int, + klass: raw::GITERR_NONE as c_int, + message: s.to_string(), + } + } + + /// Return the error code associated with this error. + /// + /// An error code is intended to be programmatically actionable most of the + /// time. For example the code `GIT_EAGAIN` indicates that an error could be + /// fixed by trying again, while the code `GIT_ERROR` is more bland and + /// doesn't convey anything in particular. + pub fn code(&self) -> ErrorCode { + match self.raw_code() { + raw::GIT_OK => super::ErrorCode::GenericError, + raw::GIT_ERROR => super::ErrorCode::GenericError, + raw::GIT_ENOTFOUND => super::ErrorCode::NotFound, + raw::GIT_EEXISTS => super::ErrorCode::Exists, + raw::GIT_EAMBIGUOUS => super::ErrorCode::Ambiguous, + raw::GIT_EBUFS => super::ErrorCode::BufSize, + raw::GIT_EUSER => super::ErrorCode::User, + raw::GIT_EBAREREPO => super::ErrorCode::BareRepo, + raw::GIT_EUNBORNBRANCH => super::ErrorCode::UnbornBranch, + raw::GIT_EUNMERGED => super::ErrorCode::Unmerged, + raw::GIT_ENONFASTFORWARD => super::ErrorCode::NotFastForward, + raw::GIT_EINVALIDSPEC => super::ErrorCode::InvalidSpec, + raw::GIT_ECONFLICT => super::ErrorCode::Conflict, + raw::GIT_ELOCKED => super::ErrorCode::Locked, + raw::GIT_EMODIFIED => super::ErrorCode::Modified, + raw::GIT_PASSTHROUGH => super::ErrorCode::GenericError, + raw::GIT_ITEROVER => super::ErrorCode::GenericError, + raw::GIT_EAUTH => super::ErrorCode::Auth, + raw::GIT_ECERTIFICATE => super::ErrorCode::Certificate, + raw::GIT_EAPPLIED => super::ErrorCode::Applied, + raw::GIT_EPEEL => super::ErrorCode::Peel, + raw::GIT_EEOF => super::ErrorCode::Eof, + raw::GIT_EINVALID => super::ErrorCode::Invalid, + raw::GIT_EUNCOMMITTED => super::ErrorCode::Uncommitted, + raw::GIT_EDIRECTORY => super::ErrorCode::Directory, + _ => super::ErrorCode::GenericError, + } + } + + /// Return the error class associated with this error. + /// + /// Error classes are in general mostly just informative. For example the + /// class will show up in the error message but otherwise an error class is + /// typically not directly actionable. + pub fn class(&self) -> ErrorClass { + match self.raw_class() { + raw::GITERR_NONE => super::ErrorClass::None, + raw::GITERR_NOMEMORY => super::ErrorClass::NoMemory, + raw::GITERR_OS => super::ErrorClass::Os, + raw::GITERR_INVALID => super::ErrorClass::Invalid, + raw::GITERR_REFERENCE => super::ErrorClass::Reference, + raw::GITERR_ZLIB => super::ErrorClass::Zlib, + raw::GITERR_REPOSITORY => super::ErrorClass::Repository, + raw::GITERR_CONFIG => super::ErrorClass::Config, + raw::GITERR_REGEX => super::ErrorClass::Regex, + raw::GITERR_ODB => super::ErrorClass::Odb, + raw::GITERR_INDEX => super::ErrorClass::Index, + raw::GITERR_OBJECT => super::ErrorClass::Object, + raw::GITERR_NET => super::ErrorClass::Net, + raw::GITERR_TAG => super::ErrorClass::Tag, + raw::GITERR_TREE => super::ErrorClass::Tree, + raw::GITERR_INDEXER => super::ErrorClass::Indexer, + raw::GITERR_SSL => super::ErrorClass::Ssl, + raw::GITERR_SUBMODULE => super::ErrorClass::Submodule, + raw::GITERR_THREAD => super::ErrorClass::Thread, + raw::GITERR_STASH => super::ErrorClass::Stash, + raw::GITERR_CHECKOUT => super::ErrorClass::Checkout, + raw::GITERR_FETCHHEAD => super::ErrorClass::FetchHead, + raw::GITERR_MERGE => super::ErrorClass::Merge, + raw::GITERR_SSH => super::ErrorClass::Ssh, + raw::GITERR_FILTER => super::ErrorClass::Filter, + raw::GITERR_REVERT => super::ErrorClass::Revert, + raw::GITERR_CALLBACK => super::ErrorClass::Callback, + raw::GITERR_CHERRYPICK => super::ErrorClass::CherryPick, + raw::GITERR_DESCRIBE => super::ErrorClass::Describe, + raw::GITERR_REBASE => super::ErrorClass::Rebase, + raw::GITERR_FILESYSTEM => super::ErrorClass::Filesystem, + _ => super::ErrorClass::None, + } + } + + /// Return the raw error code associated with this error. + pub fn raw_code(&self) -> raw::git_error_code { + macro_rules! check( ($($e:ident,)*) => ( + $(if self.code == raw::$e as c_int { raw::$e }) else * + else { + raw::GIT_ERROR + } + ) ); + check!( + GIT_OK, + GIT_ERROR, + GIT_ENOTFOUND, + GIT_EEXISTS, + GIT_EAMBIGUOUS, + GIT_EBUFS, + GIT_EUSER, + GIT_EBAREREPO, + GIT_EUNBORNBRANCH, + GIT_EUNMERGED, + GIT_ENONFASTFORWARD, + GIT_EINVALIDSPEC, + GIT_ECONFLICT, + GIT_ELOCKED, + GIT_EMODIFIED, + GIT_EAUTH, + GIT_ECERTIFICATE, + GIT_EAPPLIED, + GIT_EPEEL, + GIT_EEOF, + GIT_EINVALID, + GIT_EUNCOMMITTED, + GIT_PASSTHROUGH, + GIT_ITEROVER, + ) + } + + /// Return the raw error class associated with this error. + pub fn raw_class(&self) -> raw::git_error_t { + macro_rules! check( ($($e:ident,)*) => ( + $(if self.klass == raw::$e as c_int { raw::$e }) else * + else { + raw::GITERR_NONE + } + ) ); + check!( + GITERR_NONE, + GITERR_NOMEMORY, + GITERR_OS, + GITERR_INVALID, + GITERR_REFERENCE, + GITERR_ZLIB, + GITERR_REPOSITORY, + GITERR_CONFIG, + GITERR_REGEX, + GITERR_ODB, + GITERR_INDEX, + GITERR_OBJECT, + GITERR_NET, + GITERR_TAG, + GITERR_TREE, + GITERR_INDEXER, + GITERR_SSL, + GITERR_SUBMODULE, + GITERR_THREAD, + GITERR_STASH, + GITERR_CHECKOUT, + GITERR_FETCHHEAD, + GITERR_MERGE, + GITERR_SSH, + GITERR_FILTER, + GITERR_REVERT, + GITERR_CALLBACK, + GITERR_CHERRYPICK, + GITERR_DESCRIBE, + GITERR_REBASE, + GITERR_FILESYSTEM, + ) + } + + /// Return the message associated with this error + pub fn message(&self) -> &str { &self.message } +} + +impl error::Error for Error { + fn description(&self) -> &str { &self.message } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message)?; + match self.class() { + ErrorClass::None => {} + other => write!(f, "; class={:?} ({})", other, self.klass)?, + } + match self.code() { + ErrorCode::GenericError => {} + other => write!(f, "; code={:?} ({})", other, self.code)?, + } + Ok(()) + } +} + +impl From for Error { + fn from(_: NulError) -> Error { + Error::from_str("data contained a nul byte that could not be \ + represented as a string") + } +} + +impl From for Error { + fn from(e: JoinPathsError) -> Error { + Error::from_str(error::Error::description(&e)) + } +} + + +#[cfg(test)] +mod tests { + use {ErrorClass, ErrorCode}; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + + let err = repo.find_submodule("does_not_exist").err().unwrap(); + assert_eq!(err.code(), ErrorCode::NotFound); + assert_eq!(err.class(), ErrorClass::Submodule); + } +} diff --git a/git2/src/index.rs b/git2/src/index.rs new file mode 100644 index 000000000..6867a3d68 --- /dev/null +++ b/git2/src/index.rs @@ -0,0 +1,710 @@ +use std::ffi::{CStr, OsString, CString}; +use std::ops::Range; +use std::path::Path; +use std::ptr; +use std::slice; + +use libc::{c_int, c_uint, size_t, c_void, c_char}; + +use {raw, panic, Repository, Error, Tree, Oid, IndexAddOption, IndexTime}; +use IntoCString; +use util::{self, Binding}; + +/// A structure to represent a git [index][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects +pub struct Index { + raw: *mut raw::git_index, +} + +/// An iterator over the entries in an index +pub struct IndexEntries<'index> { + range: Range, + index: &'index Index, +} + +/// A callback function to filter index matches. +/// +/// Used by `Index::{add_all,remove_all,update_all}`. The first argument is the +/// path, and the second is the patchspec that matched it. Return 0 to confirm +/// the operation on the item, > 0 to skip the item, and < 0 to abort the scan. +pub type IndexMatchedPath<'a> = FnMut(&Path, &[u8]) -> i32 + 'a; + +/// A structure to represent an entry or a file inside of an index. +/// +/// All fields of an entry are public for modification and inspection. This is +/// also how a new index entry is created. +#[allow(missing_docs)] +pub struct IndexEntry { + pub ctime: IndexTime, + pub mtime: IndexTime, + pub dev: u32, + pub ino: u32, + pub mode: u32, + pub uid: u32, + pub gid: u32, + pub file_size: u32, + pub id: Oid, + pub flags: u16, + pub flags_extended: u16, + pub path: Vec, +} + +impl Index { + /// Creates a new in-memory index. + /// + /// This index object cannot be read/written to the filesystem, but may be + /// used to perform in-memory index operations. + pub fn new() -> Result { + ::init(); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_index_new(&mut raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new bare Git index object as a memory representation of the Git + /// index file in 'index_path', without a repository to back it. + /// + /// Since there is no ODB or working directory behind this index, any Index + /// methods which rely on these (e.g. add_path) will fail. + /// + /// If you need an index attached to a repository, use the `index()` method + /// on `Repository`. + pub fn open(index_path: &Path) -> Result { + ::init(); + let mut raw = ptr::null_mut(); + let index_path = try!(index_path.into_c_string()); + unsafe { + try_call!(raw::git_index_open(&mut raw, index_path)); + Ok(Binding::from_raw(raw)) + } + } + + /// Add or update an index entry from an in-memory struct + /// + /// If a previous index entry exists that has the same path and stage as the + /// given 'source_entry', it will be replaced. Otherwise, the 'source_entry' + /// will be added. + pub fn add(&mut self, entry: &IndexEntry) -> Result<(), Error> { + let path = try!(CString::new(&entry.path[..])); + + // libgit2 encodes the length of the path in the lower bits of the + // `flags` entry, so mask those out and recalculate here to ensure we + // don't corrupt anything. + let mut flags = entry.flags & !raw::GIT_IDXENTRY_NAMEMASK; + + if entry.path.len() < raw::GIT_IDXENTRY_NAMEMASK as usize { + flags |= entry.path.len() as u16; + } else { + flags |= raw::GIT_IDXENTRY_NAMEMASK; + } + + unsafe { + let raw = raw::git_index_entry { + dev: entry.dev, + ino: entry.ino, + mode: entry.mode, + uid: entry.uid, + gid: entry.gid, + file_size: entry.file_size, + id: *entry.id.raw(), + flags: flags, + flags_extended: entry.flags_extended, + path: path.as_ptr(), + mtime: raw::git_index_time { + seconds: entry.mtime.seconds(), + nanoseconds: entry.mtime.nanoseconds(), + }, + ctime: raw::git_index_time { + seconds: entry.ctime.seconds(), + nanoseconds: entry.ctime.nanoseconds(), + }, + }; + try_call!(raw::git_index_add(self.raw, &raw)); + Ok(()) + } + } + + /// Add or update an index entry from a buffer in memory + /// + /// This method will create a blob in the repository that owns the index and + /// then add the index entry to the index. The path of the entry represents + /// the position of the blob relative to the repository's root folder. + /// + /// If a previous index entry exists that has the same path as the given + /// 'entry', it will be replaced. Otherwise, the 'entry' will be added. + /// The id and the file_size of the 'entry' are updated with the real value + /// of the blob. + /// + /// This forces the file to be added to the index, not looking at gitignore + /// rules. + /// + /// If this file currently is the result of a merge conflict, this file will + /// no longer be marked as conflicting. The data about the conflict will be + /// moved to the "resolve undo" (REUC) section. + pub fn add_frombuffer(&mut self, entry: &IndexEntry, data: &[u8]) -> Result<(), Error> { + let path = try!(CString::new(&entry.path[..])); + + // libgit2 encodes the length of the path in the lower bits of the + // `flags` entry, so mask those out and recalculate here to ensure we + // don't corrupt anything. + let mut flags = entry.flags & !raw::GIT_IDXENTRY_NAMEMASK; + + if entry.path.len() < raw::GIT_IDXENTRY_NAMEMASK as usize { + flags |= entry.path.len() as u16; + } else { + flags |= raw::GIT_IDXENTRY_NAMEMASK; + } + + unsafe { + let raw = raw::git_index_entry { + dev: entry.dev, + ino: entry.ino, + mode: entry.mode, + uid: entry.uid, + gid: entry.gid, + file_size: entry.file_size, + id: *entry.id.raw(), + flags: flags, + flags_extended: entry.flags_extended, + path: path.as_ptr(), + mtime: raw::git_index_time { + seconds: entry.mtime.seconds(), + nanoseconds: entry.mtime.nanoseconds(), + }, + ctime: raw::git_index_time { + seconds: entry.ctime.seconds(), + nanoseconds: entry.ctime.nanoseconds(), + }, + }; + + let ptr = data.as_ptr() as *const c_void; + let len = data.len() as size_t; + try_call!(raw::git_index_add_frombuffer(self.raw, &raw, ptr, len)); + Ok(()) + } + } + + /// Add or update an index entry from a file on disk + /// + /// The file path must be relative to the repository's working folder and + /// must be readable. + /// + /// This method will fail in bare index instances. + /// + /// This forces the file to be added to the index, not looking at gitignore + /// rules. + /// + /// If this file currently is the result of a merge conflict, this file will + /// no longer be marked as conflicting. The data about the conflict will be + /// moved to the "resolve undo" (REUC) section. + pub fn add_path(&mut self, path: &Path) -> Result<(), Error> { + // Git apparently expects '/' to be separators for paths + let mut posix_path = OsString::new(); + for (i, comp) in path.components().enumerate() { + if i != 0 { posix_path.push("/"); } + posix_path.push(comp.as_os_str()); + } + let posix_path = try!(posix_path.into_c_string()); + unsafe { + try_call!(raw::git_index_add_bypath(self.raw, posix_path)); + Ok(()) + } + } + + /// Add or update index entries matching files in the working directory. + /// + /// This method will fail in bare index instances. + /// + /// The `pathspecs` are a list of file names or shell glob patterns that + /// will matched against files in the repository's working directory. Each + /// file that matches will be added to the index (either updating an + /// existing entry or adding a new entry). You can disable glob expansion + /// and force exact matching with the `AddDisablePathspecMatch` flag. + /// + /// Files that are ignored will be skipped (unlike `add_path`). If a file is + /// already tracked in the index, then it will be updated even if it is + /// ignored. Pass the `AddForce` flag to skip the checking of ignore rules. + /// + /// To emulate `git add -A` and generate an error if the pathspec contains + /// the exact path of an ignored file (when not using `AddForce`), add the + /// `AddCheckPathspec` flag. This checks that each entry in `pathspecs` + /// that is an exact match to a filename on disk is either not ignored or + /// already in the index. If this check fails, the function will return + /// an error. + /// + /// To emulate `git add -A` with the "dry-run" option, just use a callback + /// function that always returns a positive value. See below for details. + /// + /// If any files are currently the result of a merge conflict, those files + /// will no longer be marked as conflicting. The data about the conflicts + /// will be moved to the "resolve undo" (REUC) section. + /// + /// If you provide a callback function, it will be invoked on each matching + /// item in the working directory immediately before it is added to / + /// updated in the index. Returning zero will add the item to the index, + /// greater than zero will skip the item, and less than zero will abort the + /// scan an return an error to the caller. + pub fn add_all(&mut self, + pathspecs: I, + flag: IndexAddOption, + mut cb: Option<&mut IndexMatchedPath>) + -> Result<(), Error> + where T: IntoCString, I: IntoIterator, + { + let (_a, _b, raw_strarray) = try!(::util::iter2cstrs(pathspecs)); + let ptr = cb.as_mut(); + let callback = ptr.as_ref().map(|_| { + index_matched_path_cb as raw::git_index_matched_path_cb + }); + unsafe { + try_call!(raw::git_index_add_all(self.raw, + &raw_strarray, + flag.bits() as c_uint, + callback, + ptr.map(|p| p as *mut _) + .unwrap_or(ptr::null_mut()) + as *mut c_void)); + } + Ok(()) + } + + /// Clear the contents (all the entries) of an index object. + /// + /// This clears the index object in memory; changes must be explicitly + /// written to disk for them to take effect persistently via `write_*`. + pub fn clear(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_index_clear(self.raw)); } + Ok(()) + } + + /// Get the count of entries currently in the index + pub fn len(&self) -> usize { + unsafe { raw::git_index_entrycount(&*self.raw) as usize } + } + + /// Return `true` is there is no entry in the index + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get one of the entries in the index by its position. + pub fn get(&self, n: usize) -> Option { + unsafe { + let ptr = raw::git_index_get_byindex(self.raw, n as size_t); + if ptr.is_null() {None} else {Some(Binding::from_raw(*ptr))} + } + } + + /// Get an iterator over the entries in this index. + pub fn iter(&self) -> IndexEntries { + IndexEntries { range: 0..self.len(), index: self } + } + + /// Get one of the entries in the index by its path. + pub fn get_path(&self, path: &Path, stage: i32) -> Option { + let path = path.into_c_string().unwrap(); + unsafe { + let ptr = call!(raw::git_index_get_bypath(self.raw, path, + stage as c_int)); + if ptr.is_null() {None} else {Some(Binding::from_raw(*ptr))} + } + } + + /// Does this index have conflicts? + /// + /// Returns `true` if the index contains conflicts, `false` if it does not. + pub fn has_conflicts(&self) -> bool { + unsafe { + raw::git_index_has_conflicts(self.raw) == 1 + } + } + + /// Get the full path to the index file on disk. + /// + /// Returns `None` if this is an in-memory index. + pub fn path(&self) -> Option<&Path> { + unsafe { + ::opt_bytes(self, raw::git_index_path(&*self.raw)).map(util::bytes2path) + } + } + + /// Update the contents of an existing index object in memory by reading + /// from the hard disk. + /// + /// If force is true, this performs a "hard" read that discards in-memory + /// changes and always reloads the on-disk index data. If there is no + /// on-disk version, the index will be cleared. + /// + /// If force is false, this does a "soft" read that reloads the index data + /// from disk only if it has changed since the last time it was loaded. + /// Purely in-memory index data will be untouched. Be aware: if there are + /// changes on disk, unwritten in-memory changes are discarded. + pub fn read(&mut self, force: bool) -> Result<(), Error> { + unsafe { try_call!(raw::git_index_read(self.raw, force)); } + Ok(()) + } + + /// Read a tree into the index file with stats + /// + /// The current index contents will be replaced by the specified tree. + pub fn read_tree(&mut self, tree: &Tree) -> Result<(), Error> { + unsafe { try_call!(raw::git_index_read_tree(self.raw, &*tree.raw())); } + Ok(()) + } + + /// Remove an entry from the index + pub fn remove(&mut self, path: &Path, stage: i32) -> Result<(), Error> { + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_index_remove(self.raw, path, stage as c_int)); + } + Ok(()) + } + + /// Remove an index entry corresponding to a file on disk. + /// + /// The file path must be relative to the repository's working folder. It + /// may exist. + /// + /// If this file currently is the result of a merge conflict, this file will + /// no longer be marked as conflicting. The data about the conflict will be + /// moved to the "resolve undo" (REUC) section. + pub fn remove_path(&mut self, path: &Path) -> Result<(), Error> { + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_index_remove_bypath(self.raw, path)); + } + Ok(()) + } + + /// Remove all entries from the index under a given directory. + pub fn remove_dir(&mut self, path: &Path, stage: i32) -> Result<(), Error> { + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_index_remove_directory(self.raw, path, + stage as c_int)); + } + Ok(()) + } + + /// Remove all matching index entries. + /// + /// If you provide a callback function, it will be invoked on each matching + /// item in the index immediately before it is removed. Return 0 to remove + /// the item, > 0 to skip the item, and < 0 to abort the scan. + pub fn remove_all(&mut self, + pathspecs: I, + mut cb: Option<&mut IndexMatchedPath>) + -> Result<(), Error> + where T: IntoCString, I: IntoIterator, + { + let (_a, _b, raw_strarray) = try!(::util::iter2cstrs(pathspecs)); + let ptr = cb.as_mut(); + let callback = ptr.as_ref().map(|_| { + index_matched_path_cb as raw::git_index_matched_path_cb + }); + unsafe { + try_call!(raw::git_index_remove_all(self.raw, + &raw_strarray, + callback, + ptr.map(|p| p as *mut _) + .unwrap_or(ptr::null_mut()) + as *mut c_void)); + } + Ok(()) + } + + /// Update all index entries to match the working directory + /// + /// This method will fail in bare index instances. + /// + /// This scans the existing index entries and synchronizes them with the + /// working directory, deleting them if the corresponding working directory + /// file no longer exists otherwise updating the information (including + /// adding the latest version of file to the ODB if needed). + /// + /// If you provide a callback function, it will be invoked on each matching + /// item in the index immediately before it is updated (either refreshed or + /// removed depending on working directory state). Return 0 to proceed with + /// updating the item, > 0 to skip the item, and < 0 to abort the scan. + pub fn update_all(&mut self, + pathspecs: I, + mut cb: Option<&mut IndexMatchedPath>) + -> Result<(), Error> + where T: IntoCString, I: IntoIterator, + { + let (_a, _b, raw_strarray) = try!(::util::iter2cstrs(pathspecs)); + let ptr = cb.as_mut(); + let callback = ptr.as_ref().map(|_| { + index_matched_path_cb as raw::git_index_matched_path_cb + }); + unsafe { + try_call!(raw::git_index_update_all(self.raw, + &raw_strarray, + callback, + ptr.map(|p| p as *mut _) + .unwrap_or(ptr::null_mut()) + as *mut c_void)); + } + Ok(()) + } + + /// Write an existing index object from memory back to disk using an atomic + /// file lock. + pub fn write(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_index_write(self.raw)); } + Ok(()) + } + + /// Write the index as a tree. + /// + /// This method will scan the index and write a representation of its + /// current state back to disk; it recursively creates tree objects for each + /// of the subtrees stored in the index, but only returns the OID of the + /// root tree. This is the OID that can be used e.g. to create a commit. + /// + /// The index instance cannot be bare, and needs to be associated to an + /// existing repository. + /// + /// The index must not contain any file in conflict. + pub fn write_tree(&mut self) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_index_write_tree(&mut raw, self.raw)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Write the index as a tree to the given repository + /// + /// This is the same as `write_tree` except that the destination repository + /// can be chosen. + pub fn write_tree_to(&mut self, repo: &Repository) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_index_write_tree_to(&mut raw, self.raw, + repo.raw())); + Ok(Binding::from_raw(&raw as *const _)) + } + } +} + +impl Binding for Index { + type Raw = *mut raw::git_index; + unsafe fn from_raw(raw: *mut raw::git_index) -> Index { + Index { raw: raw } + } + fn raw(&self) -> *mut raw::git_index { self.raw } +} + +extern fn index_matched_path_cb(path: *const c_char, + matched_pathspec: *const c_char, + payload: *mut c_void) -> c_int { + unsafe { + let path = CStr::from_ptr(path).to_bytes(); + let matched_pathspec = CStr::from_ptr(matched_pathspec).to_bytes(); + + panic::wrap(|| { + let payload = payload as *mut &mut IndexMatchedPath; + (*payload)(util::bytes2path(path), matched_pathspec) as c_int + }).unwrap_or(-1) + } +} + +impl Drop for Index { + fn drop(&mut self) { + unsafe { raw::git_index_free(self.raw) } + } +} + +impl<'index> Iterator for IndexEntries<'index> { + type Item = IndexEntry; + fn next(&mut self) -> Option { + self.range.next().map(|i| self.index.get(i).unwrap()) + } +} + +impl Binding for IndexEntry { + type Raw = raw::git_index_entry; + + unsafe fn from_raw(raw: raw::git_index_entry) -> IndexEntry { + let raw::git_index_entry { + ctime, mtime, dev, ino, mode, uid, gid, file_size, id, flags, + flags_extended, path + } = raw; + + // libgit2 encodes the length of the path in the lower bits of `flags`, + // but if the length exceeds the number of bits then the path is + // nul-terminated. + let mut pathlen = (flags & raw::GIT_IDXENTRY_NAMEMASK) as usize; + if pathlen == raw::GIT_IDXENTRY_NAMEMASK as usize { + pathlen = CStr::from_ptr(path).to_bytes().len(); + } + + let path = slice::from_raw_parts(path as *const u8, pathlen); + + IndexEntry { + dev: dev, + ino: ino, + mode: mode, + uid: uid, + gid: gid, + file_size: file_size, + id: Binding::from_raw(&id as *const _), + flags: flags, + flags_extended: flags_extended, + path: path.to_vec(), + mtime: Binding::from_raw(mtime), + ctime: Binding::from_raw(ctime), + } + } + + fn raw(&self) -> raw::git_index_entry { + // not implemented, may require a CString in storage + panic!() + } +} + +#[cfg(test)] +mod tests { + use std::fs::{self, File}; + use std::path::Path; + use tempdir::TempDir; + + use {Index, IndexEntry, Repository, ResetType, Oid, IndexTime}; + + #[test] + fn smoke() { + let mut index = Index::new().unwrap(); + assert!(index.add_path(&Path::new(".")).is_err()); + index.clear().unwrap(); + assert_eq!(index.len(), 0); + assert!(index.get(0).is_none()); + assert!(index.path().is_none()); + assert!(index.read(true).is_err()); + } + + #[test] + fn smoke_from_repo() { + let (_td, repo) = ::test::repo_init(); + let mut index = repo.index().unwrap(); + assert_eq!(index.path().map(|s| s.to_path_buf()), + Some(repo.path().join("index"))); + Index::open(&repo.path().join("index")).unwrap(); + + index.clear().unwrap(); + index.read(true).unwrap(); + index.write().unwrap(); + index.write_tree().unwrap(); + index.write_tree_to(&repo).unwrap(); + } + + #[test] + fn add_all() { + let (_td, repo) = ::test::repo_init(); + let mut index = repo.index().unwrap(); + + let root = repo.path().parent().unwrap(); + fs::create_dir(&root.join("foo")).unwrap(); + File::create(&root.join("foo/bar")).unwrap(); + let mut called = false; + index.add_all(["foo"].iter(), ::IndexAddOption::DEFAULT, + Some(&mut |a: &Path, b: &[u8]| { + assert!(!called); + called = true; + assert_eq!(b, b"foo"); + assert_eq!(a, Path::new("foo/bar")); + 0 + })).unwrap(); + assert!(called); + + called = false; + index.remove_all(["."].iter(), Some(&mut |a: &Path, b: &[u8]| { + assert!(!called); + called = true; + assert_eq!(b, b"."); + assert_eq!(a, Path::new("foo/bar")); + 0 + })).unwrap(); + assert!(called); + } + + #[test] + fn smoke_add() { + let (_td, repo) = ::test::repo_init(); + let mut index = repo.index().unwrap(); + + let root = repo.path().parent().unwrap(); + fs::create_dir(&root.join("foo")).unwrap(); + File::create(&root.join("foo/bar")).unwrap(); + index.add_path(Path::new("foo/bar")).unwrap(); + index.write().unwrap(); + assert_eq!(index.iter().count(), 1); + + // Make sure we can use this repo somewhere else now. + let id = index.write_tree().unwrap(); + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + let id = repo.refname_to_id("HEAD").unwrap(); + let parent = repo.find_commit(id).unwrap(); + let commit = repo.commit(Some("HEAD"), &sig, &sig, "commit", + &tree, &[&parent]).unwrap(); + let obj = repo.find_object(commit, None).unwrap(); + repo.reset(&obj, ResetType::Hard, None).unwrap(); + + let td2 = TempDir::new("git").unwrap(); + let url = ::test::path2url(&root); + let repo = Repository::clone(&url, td2.path()).unwrap(); + let obj = repo.find_object(commit, None).unwrap(); + repo.reset(&obj, ResetType::Hard, None).unwrap(); + } + + #[test] + fn add_then_read() { + let mut index = Index::new().unwrap(); + assert!(index.add(&entry()).is_err()); + + let mut index = Index::new().unwrap(); + let mut e = entry(); + e.path = b"foobar".to_vec(); + index.add(&e).unwrap(); + let e = index.get(0).unwrap(); + assert_eq!(e.path.len(), 6); + } + + #[test] + fn add_frombuffer_then_read() { + let (_td, repo) = ::test::repo_init(); + let mut index = repo.index().unwrap(); + + let mut e = entry(); + e.path = b"foobar".to_vec(); + let content = b"the contents"; + index.add_frombuffer(&e, content).unwrap(); + let e = index.get(0).unwrap(); + assert_eq!(e.path.len(), 6); + + let b = repo.find_blob(e.id).unwrap(); + assert_eq!(b.content(), content); + } + + fn entry() -> IndexEntry { + IndexEntry { + ctime: IndexTime::new(0, 0), + mtime: IndexTime::new(0, 0), + dev: 0, + ino: 0, + mode: 0o100644, + uid: 0, + gid: 0, + file_size: 0, + id: Oid::from_bytes(&[0; 20]).unwrap(), + flags: 0, + flags_extended: 0, + path: Vec::new(), + } + } +} diff --git a/git2/src/lib.rs b/git2/src/lib.rs new file mode 100644 index 000000000..b2c1b0900 --- /dev/null +++ b/git2/src/lib.rs @@ -0,0 +1,1339 @@ +//! # libgit2 bindings for Rust +//! +//! This library contains bindings to the [libgit2][1] C library which is used +//! to manage git repositories. The library itself is a work in progress and is +//! likely lacking some bindings here and there, so be warned. +//! +//! [1]: https://libgit2.github.com/ +//! +//! The git2-rs library strives to be as close to libgit2 as possible, but also +//! strives to make using libgit2 as safe as possible. All resource management +//! is automatic as well as adding strong types to all interfaces (including +//! `Result`) +//! +//! ## Creating a `Repository` +//! +//! The `Repository` is the source from which almost all other objects in git-rs +//! are spawned. A repository can be created through opening, initializing, or +//! cloning. +//! +//! ### Initializing a new repository +//! +//! The `init` method will create a new repository, assuming one does not +//! already exist. +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let repo = match Repository::init("/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to init: {}", e), +//! }; +//! ``` +//! +//! ### Opening an existing repository +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let repo = match Repository::open("/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to open: {}", e), +//! }; +//! ``` +//! +//! ### Cloning an existing repository +//! +//! ```no_run +//! # #![allow(unstable)] +//! use git2::Repository; +//! +//! let url = "https://github.com/alexcrichton/git2-rs"; +//! let repo = match Repository::clone(url, "/path/to/a/repo") { +//! Ok(repo) => repo, +//! Err(e) => panic!("failed to clone: {}", e), +//! }; +//! ``` +//! +//! ## Working with a `Repository` +//! +//! All deriviative objects, references, etc are attached to the lifetime of the +//! source `Repository`, to ensure that they do not outlive the repository +//! itself. + +#![doc(html_root_url = "https://docs.rs/git2/0.6")] +#![allow(trivial_numeric_casts, trivial_casts)] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +extern crate libc; +extern crate url; +extern crate libgit2_sys as raw; +#[macro_use] extern crate bitflags; +#[macro_use] extern crate log; +#[cfg(test)] extern crate tempdir; + +use std::ffi::{CStr, CString}; +use std::fmt; +use std::str; +use std::sync::{Once, ONCE_INIT}; + +pub use blame::{Blame, BlameHunk, BlameIter, BlameOptions}; +pub use blob::{Blob, BlobWriter}; +pub use branch::{Branch, Branches}; +pub use buf::Buf; +pub use commit::{Commit, Parents}; +pub use config::{Config, ConfigEntry, ConfigEntries}; +pub use cred::{Cred, CredentialHelper}; +pub use describe::{Describe, DescribeFormatOptions, DescribeOptions}; +pub use diff::{Diff, DiffDelta, DiffFile, DiffOptions, Deltas}; +pub use diff::{DiffBinary, DiffBinaryFile, DiffBinaryKind}; +pub use diff::{DiffLine, DiffHunk, DiffStats, DiffFindOptions}; +pub use error::Error; +pub use index::{Index, IndexEntry, IndexEntries, IndexMatchedPath}; +pub use merge::{AnnotatedCommit, MergeOptions}; +pub use message::{message_prettify, DEFAULT_COMMENT_CHAR}; +pub use note::{Note, Notes}; +pub use object::Object; +pub use oid::Oid; +pub use packbuilder::{PackBuilder, PackBuilderStage}; +pub use pathspec::{Pathspec, PathspecMatchList, PathspecFailedEntries}; +pub use pathspec::{PathspecDiffEntries, PathspecEntries}; +pub use patch::Patch; +pub use proxy_options::ProxyOptions; +pub use rebase::{Rebase, RebaseOptions, RebaseOperation, RebaseOperationType}; +pub use reference::{Reference, References, ReferenceNames}; +pub use reflog::{Reflog, ReflogEntry, ReflogIter}; +pub use refspec::Refspec; +pub use remote::{Remote, RemoteConnection, Refspecs, RemoteHead, FetchOptions, PushOptions}; +pub use remote_callbacks::{RemoteCallbacks, Credentials, TransferProgress}; +pub use remote_callbacks::{TransportMessage, Progress, UpdateTips}; +pub use repo::{Repository, RepositoryInitOptions}; +pub use revspec::Revspec; +pub use revwalk::Revwalk; +pub use signature::Signature; +pub use status::{StatusOptions, Statuses, StatusIter, StatusEntry, StatusShow}; +pub use stash::{StashApplyOptions, StashCb, StashApplyProgressCb}; +pub use submodule::{Submodule, SubmoduleUpdateOptions}; +pub use tag::Tag; +pub use time::{Time, IndexTime}; +pub use tree::{Tree, TreeEntry, TreeIter, TreeWalkMode, TreeWalkResult}; +pub use treebuilder::TreeBuilder; +pub use odb::{Odb, OdbObject, OdbReader, OdbWriter}; +pub use util::IntoCString; + +// Create a convinience method on bitflag struct which checks the given flag +macro_rules! is_bit_set { + ($name:ident, $flag:expr) => ( + #[allow(missing_docs)] + pub fn $name(&self) -> bool { + self.intersects($flag) + } + ) +} + +/// An enumeration of possible errors that can happen when working with a git +/// repository. +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +pub enum ErrorCode { + /// Generic error + GenericError, + /// Requested object could not be found + NotFound, + /// Object exists preventing operation + Exists, + /// More than one object matches + Ambiguous, + /// Output buffer too short to hold data + BufSize, + /// User-generated error + User, + /// Operation not allowed on bare repository + BareRepo, + /// HEAD refers to branch with no commits + UnbornBranch, + /// Merge in progress prevented operation + Unmerged, + /// Reference was not fast-forwardable + NotFastForward, + /// Name/ref spec was not in a valid format + InvalidSpec, + /// Checkout conflicts prevented operation + Conflict, + /// Lock file prevented operation + Locked, + /// Reference value does not match expected + Modified, + /// Authentication error + Auth, + /// Server certificate is invalid + Certificate, + /// Patch/merge has already been applied + Applied, + /// The requested peel operation is not possible + Peel, + /// Unexpected EOF + Eof, + /// Invalid operation or input + Invalid, + /// Uncommitted changes in index prevented operation + Uncommitted, + /// Operation was not valid for a directory, + Directory, +} + +/// An enumeration of possible categories of things that can have +/// errors when working with a git repository. +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +pub enum ErrorClass { + /// Uncategorized + None, + /// Out of memory or insufficient allocated space + NoMemory, + /// Syscall or standard system library error + Os, + /// Invalid input + Invalid, + /// Error resolving or manipulating a reference + Reference, + /// ZLib failure + Zlib, + /// Bad repository state + Repository, + /// Bad configuration + Config, + /// Regex failure + Regex, + /// Bad object + Odb, + /// Invalid index data + Index, + /// Error creating or obtaining an object + Object, + /// Network error + Net, + /// Error manpulating a tag + Tag, + /// Invalid value in tree + Tree, + /// Hashing or packing error + Indexer, + /// Error from SSL + Ssl, + /// Error involing submodules + Submodule, + /// Threading error + Thread, + /// Error manipulating a stash + Stash, + /// Checkout failure + Checkout, + /// Invalid FETCH_HEAD + FetchHead, + /// Merge failure + Merge, + /// SSH failure + Ssh, + /// Error manipulating filters + Filter, + /// Error reverting commit + Revert, + /// Error from a user callback + Callback, + /// Error cherry-picking commit + CherryPick, + /// Can't describe object + Describe, + /// Error during rebase + Rebase, + /// Filesystem-related error + Filesystem, +} + +/// A listing of the possible states that a repository can be in. +#[derive(PartialEq, Eq, Clone, Debug, Copy)] +#[allow(missing_docs)] +pub enum RepositoryState { + Clean, + Merge, + Revert, + RevertSequence, + CherryPick, + CherryPickSequence, + Bisect, + Rebase, + RebaseInteractive, + RebaseMerge, + ApplyMailbox, + ApplyMailboxOrRebase, +} + +/// An enumeration of the possible directions for a remote. +#[derive(Copy, Clone)] +pub enum Direction { + /// Data will be fetched (read) from this remote. + Fetch, + /// Data will be pushed (written) to this remote. + Push, +} + +/// An enumeration of the operations that can be performed for the `reset` +/// method on a `Repository`. +#[derive(Copy, Clone)] +pub enum ResetType { + /// Move the head to the given commit. + Soft, + /// Soft plus reset the index to the commit. + Mixed, + /// Mixed plus changes in the working tree are discarded. + Hard, +} + +/// An enumeration all possible kinds objects may have. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum ObjectType { + /// Any kind of git object + Any, + /// An object which corresponds to a git commit + Commit, + /// An object which corresponds to a git tree + Tree, + /// An object which corresponds to a git blob + Blob, + /// An object which corresponds to a git tag + Tag, +} + +/// An enumeration of all possile kinds of references. +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +pub enum ReferenceType { + /// A reference which points at an object id. + Oid, + + /// A reference which points at another reference. + Symbolic, +} + +/// An enumeration for the possible types of branches +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum BranchType { + /// A local branch not on a remote. + Local, + /// A branch for a remote. + Remote, +} + +/// An enumeration of the possible priority levels of a config file. +/// +/// The levels corresponding to the escalation logic (higher to lower) when +/// searching for config entries. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ConfigLevel { + /// System-wide on Windows, for compatibility with portable git + ProgramData, + /// System-wide configuration file, e.g. /etc/gitconfig + System, + /// XDG-compatible configuration file, e.g. ~/.config/git/config + XDG, + /// User-specific configuration, e.g. ~/.gitconfig + Global, + /// Repository specific config, e.g. $PWD/.git/config + Local, + /// Application specific configuration file + App, + /// Highest level available + Highest, +} + +/// Merge file favor options for `MergeOptions` instruct the file-level +/// merging functionality how to deal with conflicting regions of the files. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum FileFavor { + /// When a region of a file is changed in both branches, a conflict will be + /// recorded in the index so that git_checkout can produce a merge file with + /// conflict markers in the working directory. This is the default. + Normal, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain the "ours" side of any conflicting region. + /// The index will not record a conflict. + Ours, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain the "theirs" side of any conflicting region. + /// The index will not record a conflict. + Theirs, + /// When a region of a file is changed in both branches, the file created + /// in the index will contain each unique line from each side, which has + /// the result of combining both files. The index will not record a conflict. + Union, +} + +bitflags! { + /// Orderings that may be specified for Revwalk iteration. + pub struct Sort: u32 { + /// Sort the repository contents in no particular ordering. + /// + /// This sorting is arbitrary, implementation-specific, and subject to + /// change at any time. This is the default sorting for new walkers. + const NONE = raw::GIT_SORT_NONE as u32; + + /// Sort the repository contents in topological order (children before + /// parents). + /// + /// This sorting mode can be combined with time sorting. + const TOPOLOGICAL = raw::GIT_SORT_TOPOLOGICAL as u32; + + /// Sort the repository contents by commit time. + /// + /// This sorting mode can be combined with topological sorting. + const TIME = raw::GIT_SORT_TIME as u32; + + /// Iterate through the repository contents in reverse order. + /// + /// This sorting mode can be combined with any others. + const REVERSE = raw::GIT_SORT_REVERSE as u32; + } +} + +impl Sort { + is_bit_set!(is_none, Sort::NONE); + is_bit_set!(is_topological, Sort::TOPOLOGICAL); + is_bit_set!(is_time, Sort::TIME); + is_bit_set!(is_reverse, Sort::REVERSE); +} + +bitflags! { + /// Types of credentials that can be requested by a credential callback. + pub struct CredentialType: u32 { + #[allow(missing_docs)] + const USER_PASS_PLAINTEXT = raw::GIT_CREDTYPE_USERPASS_PLAINTEXT as u32; + #[allow(missing_docs)] + const SSH_KEY = raw::GIT_CREDTYPE_SSH_KEY as u32; + #[allow(missing_docs)] + const SSH_MEMORY = raw::GIT_CREDTYPE_SSH_MEMORY as u32; + #[allow(missing_docs)] + const SSH_CUSTOM = raw::GIT_CREDTYPE_SSH_CUSTOM as u32; + #[allow(missing_docs)] + const DEFAULT = raw::GIT_CREDTYPE_DEFAULT as u32; + #[allow(missing_docs)] + const SSH_INTERACTIVE = raw::GIT_CREDTYPE_SSH_INTERACTIVE as u32; + #[allow(missing_docs)] + const USERNAME = raw::GIT_CREDTYPE_USERNAME as u32; + } +} + +impl CredentialType { + is_bit_set!(is_user_pass_plaintext, CredentialType::USER_PASS_PLAINTEXT); + is_bit_set!(is_ssh_key, CredentialType::SSH_KEY); + is_bit_set!(is_ssh_memory, CredentialType::SSH_MEMORY); + is_bit_set!(is_ssh_custom, CredentialType::SSH_CUSTOM); + is_bit_set!(is_default, CredentialType::DEFAULT); + is_bit_set!(is_ssh_interactive, CredentialType::SSH_INTERACTIVE); + is_bit_set!(is_username, CredentialType::USERNAME); +} + +impl Default for CredentialType { + fn default() -> Self { + CredentialType::DEFAULT + } +} + +bitflags! { + /// Flags for the `flags` field of an IndexEntry. + pub struct IndexEntryFlag: u16 { + /// Set when the `extended_flags` field is valid. + const EXTENDED = raw::GIT_IDXENTRY_EXTENDED as u16; + /// "Assume valid" flag + const VALID = raw::GIT_IDXENTRY_VALID as u16; + } +} + +impl IndexEntryFlag { + is_bit_set!(is_extended, IndexEntryFlag::EXTENDED); + is_bit_set!(is_valid, IndexEntryFlag::VALID); +} + +bitflags! { + /// Flags for the `extended_flags` field of an IndexEntry. + pub struct IndexEntryExtendedFlag: u16 { + /// An "intent to add" entry from "git add -N" + const INTENT_TO_ADD = raw::GIT_IDXENTRY_INTENT_TO_ADD as u16; + /// Skip the associated worktree file, for sparse checkouts + const SKIP_WORKTREE = raw::GIT_IDXENTRY_SKIP_WORKTREE as u16; + /// Reserved for a future on-disk extended flag + const EXTENDED2 = raw::GIT_IDXENTRY_EXTENDED2 as u16; + + #[allow(missing_docs)] + const UPDATE = raw::GIT_IDXENTRY_UPDATE as u16; + #[allow(missing_docs)] + const REMOVE = raw::GIT_IDXENTRY_REMOVE as u16; + #[allow(missing_docs)] + const UPTODATE = raw::GIT_IDXENTRY_UPTODATE as u16; + #[allow(missing_docs)] + const ADDED = raw::GIT_IDXENTRY_ADDED as u16; + + #[allow(missing_docs)] + const HASHED = raw::GIT_IDXENTRY_HASHED as u16; + #[allow(missing_docs)] + const UNHASHED = raw::GIT_IDXENTRY_UNHASHED as u16; + #[allow(missing_docs)] + const WT_REMOVE = raw::GIT_IDXENTRY_WT_REMOVE as u16; + #[allow(missing_docs)] + const CONFLICTED = raw::GIT_IDXENTRY_CONFLICTED as u16; + + #[allow(missing_docs)] + const UNPACKED = raw::GIT_IDXENTRY_UNPACKED as u16; + #[allow(missing_docs)] + const NEW_SKIP_WORKTREE = raw::GIT_IDXENTRY_NEW_SKIP_WORKTREE as u16; + } +} + +impl IndexEntryExtendedFlag { + is_bit_set!(is_intent_to_add, IndexEntryExtendedFlag::INTENT_TO_ADD); + is_bit_set!(is_skip_worktree, IndexEntryExtendedFlag::SKIP_WORKTREE); + is_bit_set!(is_extended2, IndexEntryExtendedFlag::EXTENDED2); + is_bit_set!(is_update, IndexEntryExtendedFlag::UPDATE); + is_bit_set!(is_remove, IndexEntryExtendedFlag::REMOVE); + is_bit_set!(is_up_to_date, IndexEntryExtendedFlag::UPTODATE); + is_bit_set!(is_added, IndexEntryExtendedFlag::ADDED); + is_bit_set!(is_hashed, IndexEntryExtendedFlag::HASHED); + is_bit_set!(is_unhashed, IndexEntryExtendedFlag::UNHASHED); + is_bit_set!(is_wt_remove, IndexEntryExtendedFlag::WT_REMOVE); + is_bit_set!(is_conflicted, IndexEntryExtendedFlag::CONFLICTED); + is_bit_set!(is_unpacked, IndexEntryExtendedFlag::UNPACKED); + is_bit_set!(is_new_skip_worktree, IndexEntryExtendedFlag::NEW_SKIP_WORKTREE); +} + +bitflags! { + /// Flags for APIs that add files matching pathspec + pub struct IndexAddOption: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_INDEX_ADD_DEFAULT as u32; + #[allow(missing_docs)] + const FORCE = raw::GIT_INDEX_ADD_FORCE as u32; + #[allow(missing_docs)] + const DISABLE_PATHSPEC_MATCH = + raw::GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH as u32; + #[allow(missing_docs)] + const CHECK_PATHSPEC = raw::GIT_INDEX_ADD_CHECK_PATHSPEC as u32; + } +} + +impl IndexAddOption { + is_bit_set!(is_default, IndexAddOption::DEFAULT); + is_bit_set!(is_force, IndexAddOption::FORCE); + is_bit_set!(is_disable_pathspec_match, IndexAddOption::DISABLE_PATHSPEC_MATCH); + is_bit_set!(is_check_pathspec, IndexAddOption::CHECK_PATHSPEC); +} + +impl Default for IndexAddOption { + fn default() -> Self { + IndexAddOption::DEFAULT + } +} + +bitflags! { + /// Flags for `Repository::open_ext` + pub struct RepositoryOpenFlags: u32 { + /// Only open the specified path; don't walk upward searching. + const NO_SEARCH = raw::GIT_REPOSITORY_OPEN_NO_SEARCH as u32; + /// Search across filesystem boundaries. + const CROSS_FS = raw::GIT_REPOSITORY_OPEN_CROSS_FS as u32; + /// Force opening as bare repository, and defer loading its config. + const BARE = raw::GIT_REPOSITORY_OPEN_BARE as u32; + /// Don't try appending `/.git` to the specified repository path. + const NO_DOTGIT = raw::GIT_REPOSITORY_OPEN_NO_DOTGIT as u32; + /// Respect environment variables like `$GIT_DIR`. + const FROM_ENV = raw::GIT_REPOSITORY_OPEN_FROM_ENV as u32; + } +} + +impl RepositoryOpenFlags { + is_bit_set!(is_no_search, RepositoryOpenFlags::NO_SEARCH); + is_bit_set!(is_cross_fs, RepositoryOpenFlags::CROSS_FS); + is_bit_set!(is_bare, RepositoryOpenFlags::BARE); + is_bit_set!(is_no_dotgit, RepositoryOpenFlags::NO_DOTGIT); + is_bit_set!(is_from_env, RepositoryOpenFlags::FROM_ENV); +} + +bitflags! { + /// Flags for the return value of `Repository::revparse` + pub struct RevparseMode: u32 { + /// The spec targeted a single object + const SINGLE = raw::GIT_REVPARSE_SINGLE as u32; + /// The spec targeted a range of commits + const RANGE = raw::GIT_REVPARSE_RANGE as u32; + /// The spec used the `...` operator, which invokes special semantics. + const MERGE_BASE = raw::GIT_REVPARSE_MERGE_BASE as u32; + } +} + +impl RevparseMode { + is_bit_set!(is_no_single, RevparseMode::SINGLE); + is_bit_set!(is_range, RevparseMode::RANGE); + is_bit_set!(is_merge_base, RevparseMode::MERGE_BASE); +} + +bitflags! { + /// The results of `merge_analysis` indicating the merge opportunities. + pub struct MergeAnalysis: u32 { + /// No merge is possible. + const ANALYSIS_NONE = raw::GIT_MERGE_ANALYSIS_NONE as u32; + /// A "normal" merge; both HEAD and the given merge input have diverged + /// from their common ancestor. The divergent commits must be merged. + const ANALYSIS_NORMAL = raw::GIT_MERGE_ANALYSIS_NORMAL as u32; + /// All given merge inputs are reachable from HEAD, meaning the + /// repository is up-to-date and no merge needs to be performed. + const ANALYSIS_UP_TO_DATE = raw::GIT_MERGE_ANALYSIS_UP_TO_DATE as u32; + /// The given merge input is a fast-forward from HEAD and no merge + /// needs to be performed. Instead, the client can check out the + /// given merge input. + const ANALYSIS_FASTFORWARD = raw::GIT_MERGE_ANALYSIS_FASTFORWARD as u32; + /// The HEAD of the current repository is "unborn" and does not point to + /// a valid commit. No merge can be performed, but the caller may wish + /// to simply set HEAD to the target commit(s). + const ANALYSIS_UNBORN = raw::GIT_MERGE_ANALYSIS_UNBORN as u32; + } +} + +impl MergeAnalysis { + is_bit_set!(is_none, MergeAnalysis::ANALYSIS_NONE); + is_bit_set!(is_normal, MergeAnalysis::ANALYSIS_NORMAL); + is_bit_set!(is_up_to_date, MergeAnalysis::ANALYSIS_UP_TO_DATE); + is_bit_set!(is_fast_forward, MergeAnalysis::ANALYSIS_FASTFORWARD); + is_bit_set!(is_unborn, MergeAnalysis::ANALYSIS_UNBORN); +} + +bitflags! { + /// The user's stated preference for merges. + pub struct MergePreference: u32 { + /// No configuration was found that suggests a preferred behavior for + /// merge. + const NONE = raw::GIT_MERGE_PREFERENCE_NONE as u32; + /// There is a `merge.ff=false` configuration setting, suggesting that + /// the user does not want to allow a fast-forward merge. + const NO_FAST_FORWARD = raw::GIT_MERGE_PREFERENCE_NO_FASTFORWARD as u32; + /// There is a `merge.ff=only` configuration setting, suggesting that + /// the user only wants fast-forward merges. + const FASTFORWARD_ONLY = raw::GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY as u32; + } +} + +impl MergePreference { + is_bit_set!(is_none, MergePreference::NONE); + is_bit_set!(is_no_fast_forward, MergePreference::NO_FAST_FORWARD); + is_bit_set!(is_fastforward_only, MergePreference::FASTFORWARD_ONLY); +} + +#[cfg(test)] #[macro_use] mod test; +#[macro_use] mod panic; +mod call; +mod util; + +pub mod build; +pub mod cert; +pub mod string_array; +pub mod oid_array; +pub mod transport; + +mod blame; +mod blob; +mod branch; +mod buf; +mod commit; +mod config; +mod cred; +mod describe; +mod diff; +mod error; +mod index; +mod merge; +mod message; +mod note; +mod object; +mod odb; +mod oid; +mod packbuilder; +mod pathspec; +mod patch; +mod proxy_options; +mod rebase; +mod reference; +mod reflog; +mod refspec; +mod remote; +mod remote_callbacks; +mod repo; +mod revspec; +mod revwalk; +mod signature; +mod status; +mod submodule; +mod stash; +mod tag; +mod time; +mod tree; +mod treebuilder; + +fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + openssl_env_init(); + }); + + raw::init(); +} + +#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), feature = "https"))] +fn openssl_env_init() { + extern crate openssl_probe; + + // Currently, libgit2 leverages OpenSSL for SSL support when cloning + // repositories over HTTPS. This means that we're picking up an OpenSSL + // dependency on non-Windows platforms (where it has its own HTTPS + // subsystem). As a result, we need to link to OpenSSL. + // + // Now actually *linking* to OpenSSL isn't so hard. We just need to make + // sure to use pkg-config to discover any relevant system dependencies for + // differences between distributions like CentOS and Ubuntu. The actual + // trickiness comes about when we start *distributing* the resulting + // binaries. Currently Cargo is distributed in binary form as nightlies, + // which means we're distributing a binary with OpenSSL linked in. + // + // For historical reasons, the Linux nightly builder is running a CentOS + // distribution in order to have as much ABI compatibility with other + // distributions as possible. Sadly, however, this compatibility does not + // extend to OpenSSL. Currently OpenSSL has two major versions, 0.9 and 1.0, + // which are incompatible (many ABI differences). The CentOS builder we + // build on has version 1.0, as do most distributions today. Some still have + // 0.9, however. This means that if we are to distribute the binaries built + // by the CentOS machine, we would only be compatible with OpenSSL 1.0 and + // we would fail to run (a dynamic linker error at runtime) on systems with + // only 9.8 installed (hopefully). + // + // But wait, the plot thickens! Apparently CentOS has dubbed their OpenSSL + // library as `libssl.so.10`, notably the `10` is included at the end. On + // the other hand Ubuntu, for example, only distributes `libssl.so`. This + // means that the binaries created at CentOS are hard-wired to probe for a + // file called `libssl.so.10` at runtime (using the LD_LIBRARY_PATH), which + // will not be found on ubuntu. The conclusion of this is that binaries + // built on CentOS cannot be distributed to Ubuntu and run successfully. + // + // There are a number of sneaky things we could do, including, but not + // limited to: + // + // 1. Create a shim program which runs "just before" cargo runs. The + // responsibility of this shim program would be to locate `libssl.so`, + // whatever it's called, on the current system, make sure there's a + // symlink *somewhere* called `libssl.so.10`, and then set up + // LD_LIBRARY_PATH and run the actual cargo. + // + // This approach definitely seems unconventional, and is borderline + // overkill for this problem. It's also dubious if we can find a + // libssl.so reliably on the target system. + // + // 2. Somehow re-work the CentOS installation so that the linked-against + // library is called libssl.so instead of libssl.so.10 + // + // The problem with this approach is that systems with 0.9 installed will + // start to silently fail, due to also having libraries called libssl.so + // (probably symlinked under a more appropriate version). + // + // 3. Compile Cargo against both OpenSSL 1.0 *and* OpenSSL 0.9, and + // distribute both. Also make sure that the linked-against name of the + // library is `libssl.so`. At runtime we determine which version is + // installed, and we then the appropriate binary. + // + // This approach clearly has drawbacks in terms of infrastructure and + // feasibility. + // + // 4. Build a nightly of Cargo for each distribution we'd like to support. + // You would then pick the appropriate Cargo nightly to install locally. + // + // So, with all this in mind, the decision was made to *statically* link + // OpenSSL. This solves any problem of relying on a downstream OpenSSL + // version being available. This does, however, open a can of worms related + // to security issues. It's generally a good idea to dynamically link + // OpenSSL as you'll get security updates over time without having to do + // anything (the system administrator will update the local openssl + // package). By statically linking, we're forfeiting this feature. + // + // The conclusion was made it is likely appropriate for the Cargo nightlies + // to statically link OpenSSL, but highly encourage distributions and + // packagers of Cargo to dynamically link OpenSSL. Packagers are targeting + // one system and are distributing to only that system, so none of the + // problems mentioned above would arise. + // + // In order to support this, a new package was made: openssl-static-sys. + // This package currently performs a fairly simple task: + // + // 1. Run pkg-config to discover where openssl is installed. + // 2. If openssl is installed in a nonstandard location, *and* static copies + // of the libraries are available, copy them to $OUT_DIR. + // + // This library will bring in libssl.a and libcrypto.a into the local build, + // allowing them to be picked up by this crate. This allows us to configure + // our own buildbots to have pkg-config point to these local pre-built + // copies of a static OpenSSL (with very few dependencies) while allowing + // most other builds of Cargo to naturally dynamically link OpenSSL. + // + // So in summary, if you're with me so far, we've statically linked OpenSSL + // to the Cargo binary (or any binary, for that matter) and we're ready to + // distribute it to *all* linux distributions. Remember that our original + // intent for openssl was for HTTPS support, which implies that we need some + // for of CA certificate store to validate certificates. This is normally + // installed in a standard system location. + // + // Unfortunately, as one might imagine, OpenSSL is configured for where this + // standard location is at *build time*, but it often varies widely + // per-system. Consequently, it was discovered that OpenSSL will respect the + // SSL_CERT_FILE and SSL_CERT_DIR environment variables in order to assist + // in discovering the location of this file (hurray!). + // + // So, finally getting to the point, this function solely exists to support + // our static builds of OpenSSL by probing for the "standard system + // location" of certificates and setting relevant environment variable to + // point to them. + // + // Ah, and as a final note, this is only a problem on Linux, not on OS X. On + // OS X the OpenSSL binaries are stable enough that we can just rely on + // dynamic linkage (plus they have some weird modifications to OpenSSL which + // means we wouldn't want to link statically). + openssl_probe::init_ssl_cert_env_vars(); +} + +#[cfg(any(windows, target_os = "macos", target_os = "ios", not(feature = "https")))] +fn openssl_env_init() {} + +unsafe fn opt_bytes<'a, T>(_anchor: &'a T, + c: *const libc::c_char) -> Option<&'a [u8]> { + if c.is_null() { + None + } else { + Some(CStr::from_ptr(c).to_bytes()) + } +} + +fn opt_cstr(o: Option) -> Result, Error> { + match o { + Some(s) => s.into_c_string().map(Some), + None => Ok(None) + } +} + +impl ObjectType { + /// Convert an object type to its string representation. + pub fn str(&self) -> &'static str { + unsafe { + let ptr = call!(raw::git_object_type2string(*self)) as *const _; + let data = CStr::from_ptr(ptr).to_bytes(); + str::from_utf8(data).unwrap() + } + } + + /// Determine if the given git_otype is a valid loose object type. + pub fn is_loose(&self) -> bool { + unsafe { (call!(raw::git_object_typeisloose(*self)) == 1) } + } + + /// Convert a raw git_otype to an ObjectType + pub fn from_raw(raw: raw::git_otype) -> Option { + match raw { + raw::GIT_OBJ_ANY => Some(ObjectType::Any), + raw::GIT_OBJ_COMMIT => Some(ObjectType::Commit), + raw::GIT_OBJ_TREE => Some(ObjectType::Tree), + raw::GIT_OBJ_BLOB => Some(ObjectType::Blob), + raw::GIT_OBJ_TAG => Some(ObjectType::Tag), + _ => None, + } + } + + /// Convert this kind into its raw representation + pub fn raw(&self) -> raw::git_otype { + call::convert(self) + } + + /// Convert a string object type representation to its object type. + pub fn from_str(s: &str) -> Option { + let raw = unsafe { call!(raw::git_object_string2type(CString::new(s).unwrap())) }; + ObjectType::from_raw(raw) + } +} + +impl fmt::Display for ObjectType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.str().fmt(f) + } +} + +impl ReferenceType { + /// Convert an object type to its string representation. + pub fn str(&self) -> &'static str { + match self { + &ReferenceType::Oid => "oid", + &ReferenceType::Symbolic => "symbolic", + } + } + + /// Convert a raw git_ref_t to a ReferenceType. + pub fn from_raw(raw: raw::git_ref_t) -> Option { + match raw { + raw::GIT_REF_OID => Some(ReferenceType::Oid), + raw::GIT_REF_SYMBOLIC => Some(ReferenceType::Symbolic), + _ => None, + } + } +} + +impl fmt::Display for ReferenceType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.str().fmt(f) + } +} + +impl ConfigLevel { + /// Converts a raw configuration level to a ConfigLevel + pub fn from_raw(raw: raw::git_config_level_t) -> ConfigLevel { + match raw { + raw::GIT_CONFIG_LEVEL_PROGRAMDATA => ConfigLevel::ProgramData, + raw::GIT_CONFIG_LEVEL_SYSTEM => ConfigLevel::System, + raw::GIT_CONFIG_LEVEL_XDG => ConfigLevel::XDG, + raw::GIT_CONFIG_LEVEL_GLOBAL => ConfigLevel::Global, + raw::GIT_CONFIG_LEVEL_LOCAL => ConfigLevel::Local, + raw::GIT_CONFIG_LEVEL_APP => ConfigLevel::App, + raw::GIT_CONFIG_HIGHEST_LEVEL => ConfigLevel::Highest, + n => panic!("unknown config level: {}", n), + } + } +} + +bitflags! { + /// Status flags for a single file + /// + /// A combination of these values will be returned to indicate the status of + /// a file. Status compares the working directory, the index, and the + /// current HEAD of the repository. The `STATUS_INDEX_*` set of flags + /// represents the status of file in the index relative to the HEAD, and the + /// `STATUS_WT_*` set of flags represent the status of the file in the + /// working directory relative to the index. + pub struct Status: u32 { + #[allow(missing_docs)] + const CURRENT = raw::GIT_STATUS_CURRENT as u32; + + #[allow(missing_docs)] + const INDEX_NEW = raw::GIT_STATUS_INDEX_NEW as u32; + #[allow(missing_docs)] + const INDEX_MODIFIED = raw::GIT_STATUS_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const INDEX_DELETED = raw::GIT_STATUS_INDEX_DELETED as u32; + #[allow(missing_docs)] + const INDEX_RENAMED = raw::GIT_STATUS_INDEX_RENAMED as u32; + #[allow(missing_docs)] + const INDEX_TYPECHANGE = raw::GIT_STATUS_INDEX_TYPECHANGE as u32; + + #[allow(missing_docs)] + const WT_NEW = raw::GIT_STATUS_WT_NEW as u32; + #[allow(missing_docs)] + const WT_MODIFIED = raw::GIT_STATUS_WT_MODIFIED as u32; + #[allow(missing_docs)] + const WT_DELETED = raw::GIT_STATUS_WT_DELETED as u32; + #[allow(missing_docs)] + const WT_TYPECHANGE = raw::GIT_STATUS_WT_TYPECHANGE as u32; + #[allow(missing_docs)] + const WT_RENAMED = raw::GIT_STATUS_WT_RENAMED as u32; + + #[allow(missing_docs)] + const IGNORED = raw::GIT_STATUS_IGNORED as u32; + #[allow(missing_docs)] + const CONFLICTED = raw::GIT_STATUS_CONFLICTED as u32; + } +} + +impl Status { + is_bit_set!(is_index_new, Status::INDEX_NEW); + is_bit_set!(is_index_modified, Status::INDEX_MODIFIED); + is_bit_set!(is_index_deleted, Status::INDEX_DELETED); + is_bit_set!(is_index_renamed, Status::INDEX_RENAMED); + is_bit_set!(is_index_typechange, Status::INDEX_TYPECHANGE); + is_bit_set!(is_wt_new, Status::WT_NEW); + is_bit_set!(is_wt_modified, Status::WT_MODIFIED); + is_bit_set!(is_wt_deleted, Status::WT_DELETED); + is_bit_set!(is_wt_typechange, Status::WT_TYPECHANGE); + is_bit_set!(is_wt_renamed, Status::WT_RENAMED); + is_bit_set!(is_ignored, Status::IGNORED); + is_bit_set!(is_conflicted, Status::CONFLICTED); +} + +bitflags! { + /// Mode options for RepositoryInitOptions + pub struct RepositoryInitMode: u32 { + /// Use permissions configured by umask - the default + const SHARED_UMASK = raw::GIT_REPOSITORY_INIT_SHARED_UMASK as u32; + /// Use `--shared=group` behavior, chmod'ing the new repo to be + /// group writable and \"g+sx\" for sticky group assignment + const SHARED_GROUP = raw::GIT_REPOSITORY_INIT_SHARED_GROUP as u32; + /// Use `--shared=all` behavior, adding world readability. + const SHARED_ALL = raw::GIT_REPOSITORY_INIT_SHARED_ALL as u32; + } +} + +impl RepositoryInitMode { + is_bit_set!(is_shared_umask, RepositoryInitMode::SHARED_UMASK); + is_bit_set!(is_shared_group, RepositoryInitMode::SHARED_GROUP); + is_bit_set!(is_shared_all, RepositoryInitMode::SHARED_ALL); +} + +/// What type of change is described by a `DiffDelta`? +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Delta { + /// No changes + Unmodified, + /// Entry does not exist in old version + Added, + /// Entry does not exist in new version + Deleted, + /// Entry content changed between old and new + Modified, + /// Entry was renamed between old and new + Renamed, + /// Entry was copied from another old entry + Copied, + /// Entry is ignored item in workdir + Ignored, + /// Entry is untracked item in workdir + Untracked, + /// Type of entry changed between old and new + Typechange, + /// Entry is unreadable + Unreadable, + /// Entry in the index is conflicted + Conflicted, +} + +bitflags! { + /// Return codes for submodule status. + /// + /// A combination of these flags will be returned to describe the status of a + /// submodule. Depending on the "ignore" property of the submodule, some of + /// the flags may never be returned because they indicate changes that are + /// supposed to be ignored. + /// + /// Submodule info is contained in 4 places: the HEAD tree, the index, config + /// files (both .git/config and .gitmodules), and the working directory. Any + /// or all of those places might be missing information about the submodule + /// depending on what state the repo is in. We consider all four places to + /// build the combination of status flags. + /// + /// There are four values that are not really status, but give basic info + /// about what sources of submodule data are available. These will be + /// returned even if ignore is set to "ALL". + /// + /// * IN_HEAD - superproject head contains submodule + /// * IN_INDEX - superproject index contains submodule + /// * IN_CONFIG - superproject gitmodules has submodule + /// * IN_WD - superproject workdir has submodule + /// + /// The following values will be returned so long as ignore is not "ALL". + /// + /// * INDEX_ADDED - in index, not in head + /// * INDEX_DELETED - in head, not in index + /// * INDEX_MODIFIED - index and head don't match + /// * WD_UNINITIALIZED - workdir contains empty directory + /// * WD_ADDED - in workdir, not index + /// * WD_DELETED - in index, not workdir + /// * WD_MODIFIED - index and workdir head don't match + /// + /// The following can only be returned if ignore is "NONE" or "UNTRACKED". + /// + /// * WD_INDEX_MODIFIED - submodule workdir index is dirty + /// * WD_WD_MODIFIED - submodule workdir has modified files + /// + /// Lastly, the following will only be returned for ignore "NONE". + /// + /// * WD_UNTRACKED - wd contains untracked files + pub struct SubmoduleStatus: u32 { + #[allow(missing_docs)] + const IN_HEAD = raw::GIT_SUBMODULE_STATUS_IN_HEAD as u32; + #[allow(missing_docs)] + const IN_INDEX = raw::GIT_SUBMODULE_STATUS_IN_INDEX as u32; + #[allow(missing_docs)] + const IN_CONFIG = raw::GIT_SUBMODULE_STATUS_IN_CONFIG as u32; + #[allow(missing_docs)] + const IN_WD = raw::GIT_SUBMODULE_STATUS_IN_WD as u32; + #[allow(missing_docs)] + const INDEX_ADDED = raw::GIT_SUBMODULE_STATUS_INDEX_ADDED as u32; + #[allow(missing_docs)] + const INDEX_DELETED = raw::GIT_SUBMODULE_STATUS_INDEX_DELETED as u32; + #[allow(missing_docs)] + const INDEX_MODIFIED = raw::GIT_SUBMODULE_STATUS_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const WD_UNINITIALIZED = + raw::GIT_SUBMODULE_STATUS_WD_UNINITIALIZED as u32; + #[allow(missing_docs)] + const WD_ADDED = raw::GIT_SUBMODULE_STATUS_WD_ADDED as u32; + #[allow(missing_docs)] + const WD_DELETED = raw::GIT_SUBMODULE_STATUS_WD_DELETED as u32; + #[allow(missing_docs)] + const WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_MODIFIED as u32; + #[allow(missing_docs)] + const WD_INDEX_MODIFIED = + raw::GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED as u32; + #[allow(missing_docs)] + const WD_WD_MODIFIED = raw::GIT_SUBMODULE_STATUS_WD_WD_MODIFIED as u32; + #[allow(missing_docs)] + const WD_UNTRACKED = raw::GIT_SUBMODULE_STATUS_WD_UNTRACKED as u32; + } +} + +impl SubmoduleStatus { + is_bit_set!(is_in_head, SubmoduleStatus::IN_HEAD); + is_bit_set!(is_in_index, SubmoduleStatus::IN_INDEX); + is_bit_set!(is_in_config, SubmoduleStatus::IN_CONFIG); + is_bit_set!(is_in_wd, SubmoduleStatus::IN_WD); + is_bit_set!(is_index_added, SubmoduleStatus::INDEX_ADDED); + is_bit_set!(is_index_deleted, SubmoduleStatus::INDEX_DELETED); + is_bit_set!(is_index_modified, SubmoduleStatus::INDEX_MODIFIED); + is_bit_set!(is_wd_uninitialized, SubmoduleStatus::WD_UNINITIALIZED); + is_bit_set!(is_wd_added, SubmoduleStatus::WD_ADDED); + is_bit_set!(is_wd_deleted, SubmoduleStatus::WD_DELETED); + is_bit_set!(is_wd_modified, SubmoduleStatus::WD_MODIFIED); + is_bit_set!(is_wd_wd_modified, SubmoduleStatus::WD_WD_MODIFIED); + is_bit_set!(is_wd_untracked, SubmoduleStatus::WD_UNTRACKED); +} + +/// Submodule ignore values +/// +/// These values represent settings for the `submodule.$name.ignore` +/// configuration value which says how deeply to look at the working +/// directory when getting the submodule status. +pub enum SubmoduleIgnore { + /// Use the submodule's configuration + Unspecified, + /// Any change or untracked file is considered dirty + None, + /// Only dirty if tracked files have changed + Untracked, + /// Only dirty if HEAD has moved + Dirty, + /// Never dirty + All, +} + +bitflags! { + /// ... + pub struct PathspecFlags: u32 { + /// Use the default pathspec matching configuration. + const DEFAULT = raw::GIT_PATHSPEC_DEFAULT as u32; + /// Force matching to ignore case, otherwise matching will use native + /// case sensitivity fo the platform filesystem. + const IGNORE_CASE = raw::GIT_PATHSPEC_IGNORE_CASE as u32; + /// Force case sensitive matches, otherwise match will use the native + /// case sensitivity of the platform filesystem. + const USE_CASE = raw::GIT_PATHSPEC_USE_CASE as u32; + /// Disable glob patterns and just use simple string comparison for + /// matching. + const NO_GLOB = raw::GIT_PATHSPEC_NO_GLOB as u32; + /// Means that match functions return the error code `NotFound` if no + /// matches are found. By default no matches is a success. + const NO_MATCH_ERROR = raw::GIT_PATHSPEC_NO_MATCH_ERROR as u32; + /// Means that the list returned should track which patterns matched + /// which files so that at the end of the match we can identify patterns + /// that did not match any files. + const FIND_FAILURES = raw::GIT_PATHSPEC_FIND_FAILURES as u32; + /// Means that the list returned does not need to keep the actual + /// matching filenames. Use this to just test if there were any matches + /// at all or in combination with `PATHSPEC_FAILURES` to validate a + /// pathspec. + const FAILURES_ONLY = raw::GIT_PATHSPEC_FAILURES_ONLY as u32; + } +} + +impl PathspecFlags { + is_bit_set!(is_default, PathspecFlags::DEFAULT); + is_bit_set!(is_ignore_case, PathspecFlags::IGNORE_CASE); + is_bit_set!(is_use_case, PathspecFlags::USE_CASE); + is_bit_set!(is_no_glob, PathspecFlags::NO_GLOB); + is_bit_set!(is_no_match_error, PathspecFlags::NO_MATCH_ERROR); + is_bit_set!(is_find_failures, PathspecFlags::FIND_FAILURES); + is_bit_set!(is_failures_only, PathspecFlags::FAILURES_ONLY); +} + +impl Default for PathspecFlags { + fn default() -> Self { + PathspecFlags::DEFAULT + } +} + +bitflags! { + /// Types of notifications emitted from checkouts. + pub struct CheckoutNotificationType: u32 { + /// Notification about a conflict. + const CONFLICT = raw::GIT_CHECKOUT_NOTIFY_CONFLICT as u32; + /// Notification about a dirty file. + const DIRTY = raw::GIT_CHECKOUT_NOTIFY_DIRTY as u32; + /// Notification about an updated file. + const UPDATED = raw::GIT_CHECKOUT_NOTIFY_UPDATED as u32; + /// Notification about an untracked file. + const UNTRACKED = raw::GIT_CHECKOUT_NOTIFY_UNTRACKED as u32; + /// Notification about an ignored file. + const IGNORED = raw::GIT_CHECKOUT_NOTIFY_IGNORED as u32; + } +} + +impl CheckoutNotificationType { + is_bit_set!(is_conflict, CheckoutNotificationType::CONFLICT); + is_bit_set!(is_dirty, CheckoutNotificationType::DIRTY); + is_bit_set!(is_updated, CheckoutNotificationType::UPDATED); + is_bit_set!(is_untracked, CheckoutNotificationType::UNTRACKED); + is_bit_set!(is_ignored, CheckoutNotificationType::IGNORED); +} + +/// Possible output formats for diff data +#[derive(Copy, Clone)] +pub enum DiffFormat { + /// full git diff + Patch, + /// just the headers of the patch + PatchHeader, + /// like git diff --raw + Raw, + /// like git diff --name-only + NameOnly, + /// like git diff --name-status + NameStatus, +} + +bitflags! { + /// Formatting options for diff stats + pub struct DiffStatsFormat: raw::git_diff_stats_format_t { + /// Don't generate any stats + const NONE = raw::GIT_DIFF_STATS_NONE; + /// Equivalent of `--stat` in git + const FULL = raw::GIT_DIFF_STATS_FULL; + /// Equivalent of `--shortstat` in git + const SHORT = raw::GIT_DIFF_STATS_SHORT; + /// Equivalent of `--numstat` in git + const NUMBER = raw::GIT_DIFF_STATS_NUMBER; + /// Extended header information such as creations, renames and mode + /// changes, equivalent of `--summary` in git + const INCLUDE_SUMMARY = raw::GIT_DIFF_STATS_INCLUDE_SUMMARY; + } +} + +impl DiffStatsFormat { + is_bit_set!(is_none, DiffStatsFormat::NONE); + is_bit_set!(is_full, DiffStatsFormat::FULL); + is_bit_set!(is_short, DiffStatsFormat::SHORT); + is_bit_set!(is_number, DiffStatsFormat::NUMBER); + is_bit_set!(is_include_summary, DiffStatsFormat::INCLUDE_SUMMARY); +} + +/// Automatic tag following options. +pub enum AutotagOption { + /// Use the setting from the remote's configuration + Unspecified, + /// Ask the server for tags pointing to objects we're already downloading + Auto, + /// Don't ask for any tags beyond the refspecs + None, + /// Ask for all the tags + All, +} + +/// Configuration for how pruning is done on a fetch +pub enum FetchPrune { + /// Use the setting from the configuration + Unspecified, + /// Force pruning on + On, + /// Force pruning off + Off, +} + +#[allow(missing_docs)] +#[derive(Debug)] +pub enum StashApplyProgress { + /// None + None, + /// Loading the stashed data from the object database + LoadingStash, + /// The stored index is being analyzed + AnalyzeIndex, + /// The modified files are being analyzed + AnalyzeModified, + /// The untracked and ignored files are being analyzed + AnalyzeUntracked, + /// The untracked files are being written to disk + CheckoutUntracked, + /// The modified files are being written to disk + CheckoutModified, + /// The stash was applied successfully + Done, +} + +bitflags! { + #[allow(missing_docs)] + pub struct StashApplyFlags: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_STASH_APPLY_DEFAULT as u32; + /// Try to reinstate not only the working tree's changes, + /// but also the index's changes. + const REINSTATE_INDEX = raw::GIT_STASH_APPLY_REINSTATE_INDEX as u32; + } +} + +impl StashApplyFlags { + is_bit_set!(is_default, StashApplyFlags::DEFAULT); + is_bit_set!(is_reinstate_index, StashApplyFlags::REINSTATE_INDEX); +} + +impl Default for StashApplyFlags { + fn default() -> Self { + StashApplyFlags::DEFAULT + } +} + +bitflags! { + #[allow(missing_docs)] + pub struct StashFlags: u32 { + #[allow(missing_docs)] + const DEFAULT = raw::GIT_STASH_DEFAULT as u32; + /// All changes already added to the index are left intact in + /// the working directory + const KEEP_INDEX = raw::GIT_STASH_KEEP_INDEX as u32; + /// All untracked files are also stashed and then cleaned up + /// from the working directory + const INCLUDE_UNTRACKED = raw::GIT_STASH_INCLUDE_UNTRACKED as u32; + /// All ignored files are also stashed and then cleaned up from + /// the working directory + const INCLUDE_IGNORED = raw::GIT_STASH_INCLUDE_IGNORED as u32; + } +} + +impl StashFlags { + is_bit_set!(is_default, StashFlags::DEFAULT); + is_bit_set!(is_keep_index, StashFlags::KEEP_INDEX); + is_bit_set!(is_include_untracked, StashFlags::INCLUDE_UNTRACKED); + is_bit_set!(is_include_ignored, StashFlags::INCLUDE_IGNORED); +} + +impl Default for StashFlags { + fn default() -> Self { + StashFlags::DEFAULT + } +} + +#[cfg(test)] +mod tests { + use super::ObjectType; + + #[test] + fn convert() { + assert_eq!(ObjectType::Blob.str(), "blob"); + assert_eq!(ObjectType::from_str("blob"), Some(ObjectType::Blob)); + assert!(ObjectType::Blob.is_loose()); + } + +} diff --git a/git2/src/merge.rs b/git2/src/merge.rs new file mode 100644 index 000000000..c66ccfd3f --- /dev/null +++ b/git2/src/merge.rs @@ -0,0 +1,182 @@ +use std::marker; +use std::mem; +use libc::c_uint; + +use {raw, Oid, Commit, FileFavor}; +use util::Binding; +use call::Convert; + +/// A structure to represent an annotated commit, the input to merge and rebase. +/// +/// An annotated commit contains information about how it was looked up, which +/// may be useful for functions like merge or rebase to provide context to the +/// operation. +pub struct AnnotatedCommit<'repo> { + raw: *mut raw::git_annotated_commit, + _marker: marker::PhantomData>, +} + +/// Options to specify when merging. +pub struct MergeOptions { + raw: raw::git_merge_options, +} + +impl<'repo> AnnotatedCommit<'repo> { + /// Gets the commit ID that the given git_annotated_commit refers to + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_annotated_commit_id(self.raw)) } + } +} + +impl Default for MergeOptions { + fn default() -> Self { + Self::new() + } +} + +impl MergeOptions { + /// Creates a default set of merge options. + pub fn new() -> MergeOptions { + let mut opts = MergeOptions { + raw: unsafe { mem::zeroed() }, + }; + assert_eq!(unsafe { + raw::git_merge_init_options(&mut opts.raw, 1) + }, 0); + opts + } + + fn flag(&mut self, opt: raw::git_merge_flag_t, val: bool) -> &mut MergeOptions { + if val { + self.raw.flags |= opt; + } else { + self.raw.flags &= !opt; + } + self + } + + /// Detect file renames + pub fn find_renames(&mut self, find: bool) -> &mut MergeOptions { + self.flag(raw::GIT_MERGE_FIND_RENAMES, find) + } + + /// If a conflict occurs, exit immediately instead of attempting to continue + /// resolving conflicts + pub fn fail_on_conflict(&mut self, fail: bool) -> &mut MergeOptions { + self.flag(raw::GIT_MERGE_FAIL_ON_CONFLICT, fail) + } + + /// Do not write the REUC extension on the generated index + pub fn skip_reuc(&mut self, skip: bool) -> &mut MergeOptions { + self.flag(raw::GIT_MERGE_FAIL_ON_CONFLICT, skip) + } + + /// If the commits being merged have multiple merge bases, do not build a + /// recursive merge base (by merging the multiple merge bases), instead + /// simply use the first base. + pub fn no_recursive(&mut self, disable: bool) -> &mut MergeOptions { + self.flag(raw::GIT_MERGE_NO_RECURSIVE, disable) + } + + /// Similarity to consider a file renamed (default 50) + pub fn rename_threshold(&mut self, thresh: u32) -> &mut MergeOptions { + self.raw.rename_threshold = thresh; + self + } + + /// Maximum similarity sources to examine for renames (default 200). + /// If the number of rename candidates (add / delete pairs) is greater + /// than this value, inexact rename detection is aborted. This setting + /// overrides the `merge.renameLimit` configuration value. + pub fn target_limit(&mut self, limit: u32) -> &mut MergeOptions { + self.raw.target_limit = limit as c_uint; + self + } + + /// Maximum number of times to merge common ancestors to build a + /// virtual merge base when faced with criss-cross merges. When + /// this limit is reached, the next ancestor will simply be used + /// instead of attempting to merge it. The default is unlimited. + pub fn recursion_limit(&mut self, limit: u32) -> &mut MergeOptions { + self.raw.recursion_limit = limit as c_uint; + self + } + + /// Specify a side to favor for resolving conflicts + pub fn file_favor(&mut self, favor: FileFavor) -> &mut MergeOptions { + self.raw.file_favor = favor.convert(); + self + } + + fn file_flag(&mut self, opt: raw::git_merge_file_flag_t, val: bool) -> &mut MergeOptions { + if val { + self.raw.file_flags |= opt; + } else { + self.raw.file_flags &= !opt; + } + self + } + + /// Create standard conflicted merge files + pub fn standard_style(&mut self, standard: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_STYLE_MERGE, standard) + } + + /// Create diff3-style file + pub fn diff3_style(&mut self, diff3: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_STYLE_DIFF3, diff3) + } + + /// Condense non-alphanumeric regions for simplified diff file + pub fn simplify_alnum(&mut self, simplify: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_SIMPLIFY_ALNUM, simplify) + } + + /// Ignore all whitespace + pub fn ignore_whitespace(&mut self, ignore: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE, ignore) + } + + /// Ignore changes in amount of whitespace + pub fn ignore_whitespace_change(&mut self, ignore: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE, ignore) + } + + /// Ignore whitespace at end of line + pub fn ignore_whitespace_eol(&mut self, ignore: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL, ignore) + } + + /// Use the "patience diff" algorithm + pub fn patience(&mut self, patience: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_DIFF_PATIENCE, patience) + } + + /// Take extra time to find minimal diff + pub fn minimal(&mut self, minimal: bool) -> &mut MergeOptions { + self.file_flag(raw::GIT_MERGE_FILE_DIFF_MINIMAL, minimal) + } + + /// Acquire a pointer to the underlying raw options. + pub unsafe fn raw(&self) -> *const raw::git_merge_options { + &self.raw as *const _ + } +} + +impl<'repo> Binding for AnnotatedCommit<'repo> { + type Raw = *mut raw::git_annotated_commit; + unsafe fn from_raw(raw: *mut raw::git_annotated_commit) + -> AnnotatedCommit<'repo> { + AnnotatedCommit { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_annotated_commit { self.raw } +} + +impl<'repo> Drop for AnnotatedCommit<'repo> { + fn drop(&mut self) { + unsafe { raw::git_annotated_commit_free(self.raw) } + } +} diff --git a/git2/src/message.rs b/git2/src/message.rs new file mode 100644 index 000000000..96cdd589c --- /dev/null +++ b/git2/src/message.rs @@ -0,0 +1,52 @@ +use std::ffi::CString; + +use libc::{c_char, c_int}; + +use {raw, Buf, Error, IntoCString}; +use util::Binding; + +/// Clean up a message, removing extraneous whitespace, and ensure that the +/// message ends with a newline. If `comment_char` is `Some`, also remove comment +/// lines starting with that character. +pub fn message_prettify(message: T, comment_char: Option) + -> Result { + _message_prettify(try!(message.into_c_string()), comment_char) +} + +fn _message_prettify(message: CString, comment_char: Option) + -> Result { + let ret = Buf::new(); + unsafe { + try_call!(raw::git_message_prettify(ret.raw(), message, + comment_char.is_some() as c_int, + comment_char.unwrap_or(0) as c_char)); + } + Ok(ret.as_str().unwrap().to_string()) +} + +/// The default comment character for `message_prettify` ('#') +pub const DEFAULT_COMMENT_CHAR: Option = Some(b'#'); + +#[cfg(test)] +mod tests { + use {message_prettify, DEFAULT_COMMENT_CHAR}; + + #[test] + fn prettify() { + // This does not attempt to duplicate the extensive tests for + // git_message_prettify in libgit2, just a few representative values to + // make sure the interface works as expected. + assert_eq!(message_prettify("1\n\n\n2", None).unwrap(), + "1\n\n2\n"); + assert_eq!(message_prettify("1\n\n\n2\n\n\n3", None).unwrap(), + "1\n\n2\n\n3\n"); + assert_eq!(message_prettify("1\n# comment\n# more", None).unwrap(), + "1\n# comment\n# more\n"); + assert_eq!(message_prettify("1\n# comment\n# more", + DEFAULT_COMMENT_CHAR).unwrap(), + "1\n"); + assert_eq!(message_prettify("1\n; comment\n; more", + Some(';' as u8)).unwrap(), + "1\n"); + } +} diff --git a/git2/src/note.rs b/git2/src/note.rs new file mode 100644 index 000000000..5295e5988 --- /dev/null +++ b/git2/src/note.rs @@ -0,0 +1,130 @@ +use std::marker; +use std::str; + +use {raw, signature, Signature, Oid, Repository, Error}; +use util::Binding; + +/// A structure representing a [note][note] in git. +/// +/// [note]: http://git-scm.com/blog/2010/08/25/notes.html +pub struct Note<'repo> { + raw: *mut raw::git_note, + + // Hmm, the current libgit2 version does not have this inside of it, but + // perhaps it's a good idea to keep it around? Can always remove it later I + // suppose... + _marker: marker::PhantomData<&'repo Repository>, +} + +/// An iterator over all of the notes within a repository. +pub struct Notes<'repo> { + raw: *mut raw::git_note_iterator, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> Note<'repo> { + /// Get the note author + pub fn author(&self) -> Signature { + unsafe { + signature::from_raw_const(self, raw::git_note_author(&*self.raw)) + } + } + + /// Get the note committer + pub fn committer(&self) -> Signature { + unsafe { + signature::from_raw_const(self, raw::git_note_committer(&*self.raw)) + } + } + + /// Get the note message, in bytes. + pub fn message_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_note_message(&*self.raw)).unwrap() } + } + + /// Get the note message as a string, returning `None` if it is not UTF-8. + pub fn message(&self) -> Option<&str> { + str::from_utf8(self.message_bytes()).ok() + } + + /// Get the note object's id + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_note_id(&*self.raw)) } + } +} + +impl<'repo> Binding for Note<'repo> { + type Raw = *mut raw::git_note; + unsafe fn from_raw(raw: *mut raw::git_note) -> Note<'repo> { + Note { raw: raw, _marker: marker::PhantomData, } + } + fn raw(&self) -> *mut raw::git_note { self.raw } +} + +impl<'repo> ::std::fmt::Debug for Note<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + f.debug_struct("Note").field("id", &self.id()).finish() + } +} + +impl<'repo> Drop for Note<'repo> { + fn drop(&mut self) { + unsafe { raw::git_note_free(self.raw); } + } +} + +impl<'repo> Binding for Notes<'repo> { + type Raw = *mut raw::git_note_iterator; + unsafe fn from_raw(raw: *mut raw::git_note_iterator) -> Notes<'repo> { + Notes { raw: raw, _marker: marker::PhantomData, } + } + fn raw(&self) -> *mut raw::git_note_iterator { self.raw } +} + +impl<'repo> Iterator for Notes<'repo> { + type Item = Result<(Oid, Oid), Error>; + fn next(&mut self) -> Option> { + let mut note_id = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + let mut annotated_id = note_id; + unsafe { + try_call_iter!(raw::git_note_next(&mut note_id, &mut annotated_id, + self.raw)); + Some(Ok((Binding::from_raw(¬e_id as *const _), + Binding::from_raw(&annotated_id as *const _)))) + } + } +} + +impl<'repo> Drop for Notes<'repo> { + fn drop(&mut self) { + unsafe { raw::git_note_iterator_free(self.raw); } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + assert!(repo.notes(None).is_err()); + + let sig = repo.signature().unwrap(); + let head = repo.head().unwrap().target().unwrap(); + let note = repo.note(&sig, &sig, None, head, "foo", false).unwrap(); + assert_eq!(repo.notes(None).unwrap().count(), 1); + + let note_obj = repo.find_note(None, head).unwrap(); + assert_eq!(note_obj.id(), note); + assert_eq!(note_obj.message(), Some("foo")); + + let (a, b) = repo.notes(None).unwrap().next().unwrap().unwrap(); + assert_eq!(a, note); + assert_eq!(b, head); + + assert_eq!(repo.note_default_ref().unwrap(), "refs/notes/commits"); + + assert_eq!(sig.name(), note_obj.author().name()); + assert_eq!(sig.name(), note_obj.committer().name()); + assert!(sig.when() == note_obj.committer().when()); + } +} diff --git a/git2/src/object.rs b/git2/src/object.rs new file mode 100644 index 000000000..725e4c77f --- /dev/null +++ b/git2/src/object.rs @@ -0,0 +1,234 @@ +use std::marker; +use std::mem; +use std::ptr; + +use {raw, Oid, ObjectType, Error, Buf, Commit, Tag, Blob, Tree, Repository}; +use {Describe, DescribeOptions}; +use util::Binding; + +/// A structure to represent a git [object][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects +pub struct Object<'repo> { + raw: *mut raw::git_object, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> Object<'repo> { + /// Get the id (SHA1) of a repository object + pub fn id(&self) -> Oid { + unsafe { + Binding::from_raw(raw::git_object_id(&*self.raw)) + } + } + + /// Get the object type of an object. + /// + /// If the type is unknown, then `None` is returned. + pub fn kind(&self) -> Option { + ObjectType::from_raw(unsafe { raw::git_object_type(&*self.raw) }) + } + + /// Recursively peel an object until an object of the specified type is met. + /// + /// If you pass `Any` as the target type, then the object will be + /// peeled until the type changes (e.g. a tag will be chased until the + /// referenced object is no longer a tag). + pub fn peel(&self, kind: ObjectType) -> Result, Error> { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_object_peel(&mut raw, &*self.raw(), kind)); + Ok(Binding::from_raw(raw)) + } + } + + /// Recursively peel an object until a blob is found + pub fn peel_to_blob(&self) -> Result, Error> { + self.peel(ObjectType::Blob).map(|o| o.cast_or_panic(ObjectType::Blob)) + } + + /// Recursively peel an object until a commit is found + pub fn peel_to_commit(&self) -> Result, Error> { + self.peel(ObjectType::Commit).map(|o| o.cast_or_panic(ObjectType::Commit)) + } + + /// Recursively peel an object until a tag is found + pub fn peel_to_tag(&self) -> Result, Error> { + self.peel(ObjectType::Tag).map(|o| o.cast_or_panic(ObjectType::Tag)) + } + + /// Recursively peel an object until a tree is found + pub fn peel_to_tree(&self) -> Result, Error> { + self.peel(ObjectType::Tree).map(|o| o.cast_or_panic(ObjectType::Tree)) + } + + /// Get a short abbreviated OID string for the object + /// + /// This starts at the "core.abbrev" length (default 7 characters) and + /// iteratively extends to a longer string if that length is ambiguous. The + /// result will be unambiguous (at least until new objects are added to the + /// repository). + pub fn short_id(&self) -> Result { + unsafe { + let buf = Buf::new(); + try_call!(raw::git_object_short_id(buf.raw(), &*self.raw())); + Ok(buf) + } + } + + /// Attempt to view this object as a commit. + /// + /// Returns `None` if the object is not actually a commit. + pub fn as_commit(&self) -> Option<&Commit<'repo>> { + self.cast(ObjectType::Commit) + } + + /// Attempt to consume this object and return a commit. + /// + /// Returns `Err(self)` if this object is not actually a commit. + pub fn into_commit(self) -> Result, Object<'repo>> { + self.cast_into(ObjectType::Commit) + } + + /// Attempt to view this object as a tag. + /// + /// Returns `None` if the object is not actually a tag. + pub fn as_tag(&self) -> Option<&Tag<'repo>> { + self.cast(ObjectType::Tag) + } + + /// Attempt to consume this object and return a tag. + /// + /// Returns `Err(self)` if this object is not actually a tag. + pub fn into_tag(self) -> Result, Object<'repo>> { + self.cast_into(ObjectType::Tag) + } + + /// Attempt to view this object as a tree. + /// + /// Returns `None` if the object is not actually a tree. + pub fn as_tree(&self) -> Option<&Tree<'repo>> { + self.cast(ObjectType::Tree) + } + + /// Attempt to consume this object and return a tree. + /// + /// Returns `Err(self)` if this object is not actually a tree. + pub fn into_tree(self) -> Result, Object<'repo>> { + self.cast_into(ObjectType::Tree) + } + + /// Attempt to view this object as a blob. + /// + /// Returns `None` if the object is not actually a blob. + pub fn as_blob(&self) -> Option<&Blob<'repo>> { + self.cast(ObjectType::Blob) + } + + /// Attempt to consume this object and return a blob. + /// + /// Returns `Err(self)` if this object is not actually a blob. + pub fn into_blob(self) -> Result, Object<'repo>> { + self.cast_into(ObjectType::Blob) + } + + /// Describes a commit + /// + /// Performs a describe operation on this commitish object. + pub fn describe(&self, opts: &DescribeOptions) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_describe_commit(&mut ret, self.raw, opts.raw())); + Ok(Binding::from_raw(ret)) + } + } + + fn cast(&self, kind: ObjectType) -> Option<&T> { + assert_eq!(mem::size_of::(), mem::size_of::()); + if self.kind() == Some(kind) { + unsafe { Some(&*(self as *const _ as *const T)) } + } else { + None + } + } + + fn cast_into(self, kind: ObjectType) -> Result> { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + if self.kind() == Some(kind) { + Ok(unsafe { + let other = ptr::read(&self as *const _ as *const T); + mem::forget(self); + other + }) + } else { + Err(self) + } + } +} + +/// This trait is useful to export cast_or_panic into crate but not outside +pub trait CastOrPanic { + fn cast_or_panic(self, kind: ObjectType) -> T; +} + +impl<'repo> CastOrPanic for Object<'repo> { + fn cast_or_panic(self, kind: ObjectType) -> T { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + if self.kind() == Some(kind) { + unsafe { + let other = ptr::read(&self as *const _ as *const T); + mem::forget(self); + other + } + } else { + let buf; + let akind = match self.kind() { + Some(akind) => akind.str(), + None => { + buf = format!("unknown ({})", unsafe { raw::git_object_type(&*self.raw) }); + &buf + } + }; + panic!("Expected object {} to be {} but it is {}", self.id(), kind.str(), akind) + } + } +} + +impl<'repo> Clone for Object<'repo> { + fn clone(&self) -> Object<'repo> { + let mut raw = ptr::null_mut(); + unsafe { + let rc = raw::git_object_dup(&mut raw, self.raw); + assert_eq!(rc, 0); + Binding::from_raw(raw) + } + } +} + +impl<'repo> ::std::fmt::Debug for Object<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let mut ds = f.debug_struct("Object"); + match self.kind() { + Some(kind) => ds.field("kind", &kind), + None => ds.field("kind", &format!("Unknow ({})", unsafe { raw::git_object_type(&*self.raw) })) + }; + ds.field("id", &self.id()); + ds.finish() + } +} + +impl<'repo> Binding for Object<'repo> { + type Raw = *mut raw::git_object; + + unsafe fn from_raw(raw: *mut raw::git_object) -> Object<'repo> { + Object { raw: raw, _marker: marker::PhantomData, } + } + fn raw(&self) -> *mut raw::git_object { self.raw } +} + +impl<'repo> Drop for Object<'repo> { + fn drop(&mut self) { + unsafe { raw::git_object_free(self.raw) } + } +} diff --git a/git2/src/odb.rs b/git2/src/odb.rs new file mode 100644 index 000000000..c3a07a474 --- /dev/null +++ b/git2/src/odb.rs @@ -0,0 +1,419 @@ +use std::marker; +use std::io; +use std::ptr; +use std::slice; + +use std::ffi::CString; + +use libc::{c_char, c_int, c_void, size_t}; + +use {raw, Oid, Object, ObjectType, Error}; +use panic; +use util::Binding; + +/// A structure to represent a git object database +pub struct Odb<'repo> { + raw: *mut raw::git_odb, + _marker: marker::PhantomData>, +} + +impl<'repo> Binding for Odb<'repo> { + type Raw = *mut raw::git_odb; + + unsafe fn from_raw(raw: *mut raw::git_odb) -> Odb<'repo> { + Odb { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_odb { self.raw } +} + +impl<'repo> Drop for Odb<'repo> { + fn drop(&mut self) { + unsafe { raw::git_odb_free(self.raw) } + } +} + +impl<'repo> Odb<'repo> { + /// Creates an object database without any backends. + pub fn new<'a>() -> Result, Error> { + unsafe { + let mut out = ptr::null_mut(); + try_call!(raw::git_odb_new(&mut out)); + Ok(Odb::from_raw(out)) + } + } + + /// Create object database reading stream. + /// + /// Note that most backends do not support streaming reads because they store their objects as compressed/delta'ed blobs. + /// If the backend does not support streaming reads, use the `read` method instead. + pub fn reader(&self, oid: Oid) -> Result<(OdbReader, usize, ObjectType), Error> { + let mut out = ptr::null_mut(); + let mut size = 0usize; + let mut otype: raw::git_otype = ObjectType::Any.raw(); + unsafe { + try_call!(raw::git_odb_open_rstream(&mut out, &mut size, &mut otype, self.raw, oid.raw())); + Ok((OdbReader::from_raw(out), size, ObjectType::from_raw(otype).unwrap())) + } + } + + /// Create object database writing stream. + /// + /// The type and final length of the object must be specified when opening the stream. + /// If the backend does not support streaming writes, use the `write` method instead. + pub fn writer(&self, size: usize, obj_type: ObjectType) -> Result { + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_odb_open_wstream(&mut out, self.raw, size as raw::git_off_t, obj_type.raw())); + Ok(OdbWriter::from_raw(out)) + } + } + + /// Iterate over all objects in the object database.s + pub fn foreach(&self, mut callback: C) -> Result<(), Error> + where C: FnMut(&Oid) -> bool + { + unsafe { + let mut data = ForeachCbData { callback: &mut callback }; + try_call!(raw::git_odb_foreach(self.raw(), + foreach_cb, + &mut data as *mut _ as *mut _)); + Ok(()) + } + } + + /// Read an object from the database. + pub fn read(&self, oid: Oid) -> Result { + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_odb_read(&mut out, self.raw, oid.raw())); + Ok(OdbObject::from_raw(out)) + } + } + + /// Reads the header of an object from the database + /// without reading the full content. + pub fn read_header(&self, oid: Oid) -> Result<(usize, ObjectType), Error> { + let mut size: usize = 0; + let mut kind_id: i32 = ObjectType::Any.raw(); + + unsafe { + try_call!(raw::git_odb_read_header(&mut size + as *mut size_t, + &mut kind_id + as *mut raw::git_otype, + self.raw, + oid.raw())); + + Ok((size, ObjectType::from_raw(kind_id).unwrap())) + } + } + + /// Write an object to the database. + pub fn write(&self, kind: ObjectType, data: &[u8]) -> Result { + unsafe { + let mut out = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + try_call!(raw::git_odb_write(&mut out, + self.raw, + data.as_ptr() + as *const c_void, + data.len(), + kind.raw())); + Ok(Oid::from_raw(&mut out)) + } + } + + /// Checks if the object database has an object. + pub fn exists(&self, oid: Oid) -> bool { + unsafe { raw::git_odb_exists(self.raw, oid.raw()) != -1 } + } + + /// Potentially finds an object that starts with the given prefix. + pub fn exists_prefix(&self, short_oid: Oid, len: usize) -> Result { + unsafe { + let mut out = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + try_call!(raw::git_odb_exists_prefix(&mut out, + self.raw, + short_oid.raw(), + len)); + Ok(Oid::from_raw(&out)) + } + } + + /// Refresh the object database. + /// This should never be needed, and is + /// provided purely for convenience. + /// The object database will automatically + /// refresh when an object is not found when + /// requested. + pub fn refresh(&self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_odb_refresh(self.raw)); + Ok(()) + } + } + + /// Adds an alternate disk backend to the object database. + pub fn add_disk_alternate(&self, path: &str) -> Result<(), Error> { + unsafe { + let path = try!(CString::new(path)); + try_call!(raw::git_odb_add_disk_alternate(self.raw, path)); + Ok(()) + } + } +} + +/// An object from the Object Database. +pub struct OdbObject<'a> { + raw: *mut raw::git_odb_object, + _marker: marker::PhantomData>, +} + +impl<'a> Binding for OdbObject<'a> { + type Raw = *mut raw::git_odb_object; + + unsafe fn from_raw(raw: *mut raw::git_odb_object) -> OdbObject<'a> { + OdbObject { + raw: raw, + _marker: marker::PhantomData, + } + } + + fn raw(&self) -> *mut raw::git_odb_object { self.raw } +} + +impl<'a> Drop for OdbObject<'a> { + fn drop(&mut self) { + unsafe { raw::git_odb_object_free(self.raw) } + } +} + +impl<'a> OdbObject<'a> { + /// Get the object type. + pub fn kind(&self) -> ObjectType { + unsafe { ObjectType::from_raw(raw::git_odb_object_type(self.raw)).unwrap() } + } + + /// Get the object size. + pub fn len(&self) -> usize { + unsafe { raw::git_odb_object_size(self.raw) } + } + + /// Get the object data. + pub fn data(&self) -> &[u8] { + unsafe { + let size = self.len(); + let ptr : *const u8 = raw::git_odb_object_data(self.raw) as *const u8; + let buffer = slice::from_raw_parts(ptr, size); + return buffer; + } + } + + /// Get the object id. + pub fn id(&self) -> Oid { + unsafe { Oid::from_raw(raw::git_odb_object_id(self.raw)) } + } +} + +/// A structure to represent a git ODB rstream +pub struct OdbReader<'repo> { + raw: *mut raw::git_odb_stream, + _marker: marker::PhantomData>, +} + +impl<'repo> Binding for OdbReader<'repo> { + type Raw = *mut raw::git_odb_stream; + + unsafe fn from_raw(raw: *mut raw::git_odb_stream) -> OdbReader<'repo> { + OdbReader { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_odb_stream { self.raw } +} + +impl<'repo> Drop for OdbReader<'repo> { + fn drop(&mut self) { + unsafe { raw::git_odb_stream_free(self.raw) } + } +} + +impl<'repo> io::Read for OdbReader<'repo> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unsafe { + let ptr = buf.as_ptr() as *mut c_char; + let len = buf.len(); + let res = raw::git_odb_stream_read(self.raw, ptr, len); + if res < 0 { + Err(io::Error::new(io::ErrorKind::Other, "Read error")) + } else { + Ok(len) + } + } + } +} + +/// A structure to represent a git ODB wstream +pub struct OdbWriter<'repo> { + raw: *mut raw::git_odb_stream, + _marker: marker::PhantomData>, +} + +impl<'repo> OdbWriter<'repo> { + /// Finish writing to an ODB stream + /// + /// This method can be used to finalize writing object to the database and get an identifier. + /// The object will take its final name and will be available to the odb. + /// This method will fail if the total number of received bytes differs from the size declared with odb_writer() + /// Attepting write after finishing will be ignored. + pub fn finalize(&mut self) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_odb_stream_finalize_write(&mut raw, self.raw)); + Ok(Binding::from_raw(&raw as *const _)) + } + } +} + +impl<'repo> Binding for OdbWriter<'repo> { + type Raw = *mut raw::git_odb_stream; + + unsafe fn from_raw(raw: *mut raw::git_odb_stream) -> OdbWriter<'repo> { + OdbWriter { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_odb_stream { self.raw } +} + +impl<'repo> Drop for OdbWriter<'repo> { + fn drop(&mut self) { + unsafe { raw::git_odb_stream_free(self.raw) } + } +} + +impl<'repo> io::Write for OdbWriter<'repo> { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { + let ptr = buf.as_ptr() as *const c_char; + let len = buf.len(); + let res = raw::git_odb_stream_write(self.raw, ptr, len); + if res < 0 { + Err(io::Error::new(io::ErrorKind::Other, "Write error")) + } else { + Ok(buf.len()) + } + } + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +pub type ForeachCb<'a> = FnMut(&Oid) -> bool + 'a; + +struct ForeachCbData<'a> { + pub callback: &'a mut ForeachCb<'a> +} + +extern fn foreach_cb(id: *const raw::git_oid, + payload: *mut c_void) + -> c_int +{ + panic::wrap(|| unsafe { + let data = &mut *(payload as *mut ForeachCbData); + let res = { + let callback = &mut data.callback; + callback(&Binding::from_raw(id)) + }; + + if res { 0 } else { 1 } + }).unwrap_or(1) +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use tempdir::TempDir; + use {Repository, ObjectType, Oid}; + + #[test] + fn read() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let id = repo.blob(&dat).unwrap(); + let db = repo.odb().unwrap(); + let obj = db.read(id).unwrap(); + let data = obj.data(); + let size = obj.len(); + assert_eq!(size, 5); + assert_eq!(dat, data); + assert_eq!(id, obj.id()); + } + + #[test] + fn read_header() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let id = repo.blob(&dat).unwrap(); + let db = repo.odb().unwrap(); + let (size, kind) = db.read_header(id).unwrap(); + + assert_eq!(size, 5); + assert_eq!(kind, ObjectType::Blob); + } + + #[test] + fn write() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let db = repo.odb().unwrap(); + let id = db.write(ObjectType::Blob, &dat).unwrap(); + let blob = repo.find_blob(id).unwrap(); + assert_eq!(blob.content(), dat); + } + + #[test] + fn writer() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let db = repo.odb().unwrap(); + let mut ws = db.writer(dat.len(), ObjectType::Blob).unwrap(); + let wl = ws.write(&dat[0..3]).unwrap(); + assert_eq!(wl, 3); + let wl = ws.write(&dat[3..5]).unwrap(); + assert_eq!(wl, 2); + let id = ws.finalize().unwrap(); + let blob = repo.find_blob(id).unwrap(); + assert_eq!(blob.content(), dat); + } + + #[test] + fn exists() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let db = repo.odb().unwrap(); + let id = db.write(ObjectType::Blob, &dat).unwrap(); + assert!(db.exists(id)); + } + + #[test] + fn exists_prefix() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let dat = [4, 3, 5, 6, 9]; + let db = repo.odb().unwrap(); + let id = db.write(ObjectType::Blob, &dat).unwrap(); + let id_prefix_str = &id.to_string()[0..10]; + let id_prefix = Oid::from_str(id_prefix_str).unwrap(); + let found_oid = db.exists_prefix(id_prefix, 10).unwrap(); + assert_eq!(found_oid, id); + } +} diff --git a/git2/src/oid.rs b/git2/src/oid.rs new file mode 100644 index 000000000..b63fe3451 --- /dev/null +++ b/git2/src/oid.rs @@ -0,0 +1,214 @@ +use std::fmt; +use std::cmp::Ordering; +use std::hash::{Hasher, Hash}; +use std::str; +use std::path::Path; +use libc; + +use {raw, Error, ObjectType, IntoCString}; + +use util::Binding; + +/// Unique identity of any object (commit, tree, blob, tag). +#[derive(Copy, Clone)] +pub struct Oid { + raw: raw::git_oid +} + +impl Oid { + /// Parse a hex-formatted object id into an Oid structure. + /// + /// # Errors + /// + /// Returns an error if the string is empty, is longer than 40 hex + /// characters, or contains any non-hex characters. + pub fn from_str(s: &str) -> Result { + ::init(); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_oid_fromstrn(&mut raw, + s.as_bytes().as_ptr() + as *const libc::c_char, + s.len() as libc::size_t)); + } + Ok(Oid { raw: raw }) + } + + /// Parse a raw object id into an Oid structure. + /// + /// If the array given is not 20 bytes in length, an error is returned. + pub fn from_bytes(bytes: &[u8]) -> Result { + ::init(); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + if bytes.len() != raw::GIT_OID_RAWSZ { + Err(Error::from_str("raw byte array must be 20 bytes")) + } else { + unsafe { raw::git_oid_fromraw(&mut raw, bytes.as_ptr()) } + Ok(Oid { raw: raw }) + } + } + + /// Creates an all zero Oid structure. + pub fn zero() -> Oid { + let out = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + Oid { raw: out } + } + + /// Hashes the provided data as an object of the provided type, and returns + /// an Oid corresponding to the result. This does not store the object + /// inside any object database or repository. + pub fn hash_object(kind: ObjectType, bytes: &[u8]) -> Result { + ::init(); + + let mut out = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_odb_hash(&mut out, + bytes.as_ptr() + as *const libc::c_void, + bytes.len(), + kind.raw())); + } + + Ok(Oid { raw: out }) + } + + /// Hashes the content of the provided file as an object of the provided type, + /// and returns an Oid corresponding to the result. This does not store the object + /// inside any object database or repository. + pub fn hash_file>(kind: ObjectType, path: P) -> Result { + ::init(); + + let rpath = try!(path.as_ref().into_c_string()); + + let mut out = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_odb_hashfile(&mut out, + rpath, + kind.raw())); + } + + Ok(Oid { raw: out }) + } + + /// View this OID as a byte-slice 20 bytes in length. + pub fn as_bytes(&self) -> &[u8] { &self.raw.id } + + /// Test if this OID is all zeros. + pub fn is_zero(&self) -> bool { + unsafe { raw::git_oid_iszero(&self.raw) == 1 } + } +} + +impl Binding for Oid { + type Raw = *const raw::git_oid; + + unsafe fn from_raw(oid: *const raw::git_oid) -> Oid { + Oid { raw: *oid } + } + fn raw(&self) -> *const raw::git_oid { &self.raw as *const _ } +} + +impl fmt::Debug for Oid { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for Oid { + /// Hex-encode this Oid into a formatter. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1]; + unsafe { + raw::git_oid_tostr(dst.as_mut_ptr() as *mut libc::c_char, + dst.len() as libc::size_t, &self.raw); + } + let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()]; + str::from_utf8(s).unwrap().fmt(f) + } +} + +impl str::FromStr for Oid { + type Err = Error; + + /// Parse a hex-formatted object id into an Oid structure. + /// + /// # Errors + /// + /// Returns an error if the string is empty, is longer than 40 hex + /// characters, or contains any non-hex characters. + fn from_str(s: &str) -> Result { + Oid::from_str(s) + } +} + +impl PartialEq for Oid { + fn eq(&self, other: &Oid) -> bool { + unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 } + } +} +impl Eq for Oid {} + +impl PartialOrd for Oid { + fn partial_cmp(&self, other: &Oid) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Oid { + fn cmp(&self, other: &Oid) -> Ordering { + match unsafe { raw::git_oid_cmp(&self.raw, &other.raw) } { + 0 => Ordering::Equal, + n if n < 0 => Ordering::Less, + _ => Ordering::Greater, + } + } +} + +impl Hash for Oid { + fn hash(&self, into: &mut H) { + self.raw.id.hash(into) + } +} + +impl AsRef<[u8]> for Oid { + fn as_ref(&self) -> &[u8] { self.as_bytes() } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::fs::File; + + use tempdir::TempDir; + use {ObjectType}; + use super::Oid; + + #[test] + fn conversions() { + assert!(Oid::from_str("foo").is_err()); + assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok()); + assert!(Oid::from_bytes(b"foo").is_err()); + assert!(Oid::from_bytes(b"00000000000000000000").is_ok()); + } + + #[test] + fn zero_is_zero() { + assert!(Oid::zero().is_zero()); + } + + #[test] + fn hash_object() { + let bytes = "Hello".as_bytes(); + assert!(Oid::hash_object(ObjectType::Blob, bytes).is_ok()); + } + + #[test] + fn hash_file() { + let td = TempDir::new("test").unwrap(); + let path = td.path().join("hello.txt"); + let mut file = File::create(&path).unwrap(); + file.write_all("Hello".as_bytes()).unwrap(); + assert!(Oid::hash_file(ObjectType::Blob, &path).is_ok()); + } +} + diff --git a/git2/src/oid_array.rs b/git2/src/oid_array.rs new file mode 100644 index 000000000..d1108e6c5 --- /dev/null +++ b/git2/src/oid_array.rs @@ -0,0 +1,50 @@ +//! Bindings to libgit2's raw `git_oidarray` type + +use std::ops::Deref; + +use oid::Oid; +use raw; +use util::Binding; +use std::slice; +use std::mem; + +/// An oid array structure used by libgit2 +/// +/// Some apis return arrays of oids which originate from libgit2. This +/// wrapper type behaves a little like `Vec<&Oid>` but does so without copying +/// the underlying Oids until necessary. +pub struct OidArray { + raw: raw::git_oidarray, +} + +impl Deref for OidArray { + type Target = [Oid]; + + fn deref(&self) -> &[Oid] { + unsafe { + debug_assert_eq!(mem::size_of::(), mem::size_of_val(&*self.raw.ids)); + + slice::from_raw_parts(self.raw.ids as *const Oid, self.raw.count as usize) + } + } +} + +impl Binding for OidArray { + type Raw = raw::git_oidarray; + unsafe fn from_raw(raw: raw::git_oidarray) -> OidArray { + OidArray { raw: raw } + } + fn raw(&self) -> raw::git_oidarray { self.raw } +} + +impl<'repo> ::std::fmt::Debug for OidArray { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + f.debug_tuple("OidArray").field(&self.deref()).finish() + } +} + +impl Drop for OidArray { + fn drop(&mut self) { + unsafe { raw::git_oidarray_free(&mut self.raw) } + } +} diff --git a/git2/src/packbuilder.rs b/git2/src/packbuilder.rs new file mode 100644 index 000000000..e3ed5132b --- /dev/null +++ b/git2/src/packbuilder.rs @@ -0,0 +1,386 @@ +use std::marker; +use std::ptr; +use std::slice; +use libc::{c_int, c_uint, c_void, size_t}; + +use {raw, panic, Repository, Error, Oid, Revwalk, Buf}; +use util::Binding; + +/// Stages that are reported by the `PackBuilder` progress callback. +pub enum PackBuilderStage { + /// Adding objects to the pack + AddingObjects, + /// Deltafication of the pack + Deltafication, +} + +pub type ProgressCb<'a> = FnMut(PackBuilderStage, u32, u32) -> bool + 'a; +pub type ForEachCb<'a> = FnMut(&[u8]) -> bool + 'a; + +/// A builder for creating a packfile +pub struct PackBuilder<'repo> { + raw: *mut raw::git_packbuilder, + progress: Option>>>, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> PackBuilder<'repo> { + /// Insert a single object. For an optimal pack it's mandatory to insert + /// objects in recency order, commits followed by trees and blobs. + pub fn insert_object(&mut self, id: Oid, name: Option<&str>) + -> Result<(), Error> { + let name = try!(::opt_cstr(name)); + unsafe { + try_call!(raw::git_packbuilder_insert(self.raw, id.raw(), name)); + } + Ok(()) + } + + /// Insert a root tree object. This will add the tree as well as all + /// referenced trees and blobs. + pub fn insert_tree(&mut self, id: Oid) -> Result<(), Error> { + unsafe { + try_call!(raw::git_packbuilder_insert_tree(self.raw, id.raw())); + } + Ok(()) + } + + /// Insert a commit object. This will add a commit as well as the completed + /// referenced tree. + pub fn insert_commit(&mut self, id: Oid) -> Result<(), Error> { + unsafe { + try_call!(raw::git_packbuilder_insert_commit(self.raw, id.raw())); + } + Ok(()) + } + + /// Insert objects as given by the walk. Those commits and all objects they + /// reference will be inserted into the packbuilder. + pub fn insert_walk(&mut self, walk: &mut Revwalk) -> Result<(), Error> { + unsafe { + try_call!(raw::git_packbuilder_insert_walk(self.raw, walk.raw())); + } + Ok(()) + } + + /// Recursively insert an object and its referenced objects. Insert the + /// object as well as any object it references. + pub fn insert_recursive(&mut self, id: Oid, name: Option<&str>) + -> Result<(), Error> { + let name = try!(::opt_cstr(name)); + unsafe { + try_call!(raw::git_packbuilder_insert_recur(self.raw, + id.raw(), + name)); + } + Ok(()) + } + + /// Write the contents of the packfile to an in-memory buffer. The contents + /// of the buffer will become a valid packfile, even though there will be + /// no attached index. + pub fn write_buf(&mut self, buf: &mut Buf) -> Result<(), Error> { + unsafe { + try_call!(raw::git_packbuilder_write_buf(buf.raw(), self.raw)); + } + Ok(()) + } + + /// Create the new pack and pass each object to the callback. + pub fn foreach(&mut self, mut cb: F) -> Result<(), Error> + where F: FnMut(&[u8]) -> bool + { + let mut cb = &mut cb as &mut ForEachCb; + let ptr = &mut cb as *mut _; + unsafe { + try_call!(raw::git_packbuilder_foreach(self.raw, + foreach_c, + ptr as *mut _)); + } + Ok(()) + } + + /// `progress` will be called with progress information during pack + /// building. Be aware that this is called inline with pack building + /// operations, so performance may be affected. + /// + /// There can only be one progress callback attached, this will replace any + /// existing one. See `unset_progress_callback` to remove the current + /// progress callback without attaching a new one. + pub fn set_progress_callback(&mut self, progress: F) -> Result<(), Error> + where F: FnMut(PackBuilderStage, u32, u32) -> bool + 'repo + { + let mut progress = Box::new(Box::new(progress) as Box); + let ptr = &mut *progress as *mut _; + let progress_c = Some(progress_c as raw::git_packbuilder_progress); + unsafe { + try_call!(raw::git_packbuilder_set_callbacks(self.raw, + progress_c, + ptr as *mut _)); + } + self.progress = Some(progress); + Ok(()) + } + + /// Remove the current progress callback. See `set_progress_callback` to + /// set the progress callback. + pub fn unset_progress_callback(&mut self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_packbuilder_set_callbacks(self.raw, + None, + ptr::null_mut())); + self.progress = None; + } + Ok(()) + } + + /// Get the total number of objects the packbuilder will write out. + pub fn object_count(&self) -> usize { + unsafe { raw::git_packbuilder_object_count(self.raw) } + } + + /// Get the number of objects the packbuilder has already written out. + pub fn written(&self) -> usize { + unsafe { raw::git_packbuilder_written(self.raw) } + } + + /// Get the packfile's hash. A packfile's name is derived from the sorted + /// hashing of all object names. This is only correct after the packfile + /// has been written. + pub fn hash(&self) -> Option { + if self.object_count() == 0 { + unsafe { + Some(Binding::from_raw(raw::git_packbuilder_hash(self.raw))) + } + } else { + None + } + } +} + +impl<'repo> Binding for PackBuilder<'repo> { + type Raw = *mut raw::git_packbuilder; + unsafe fn from_raw(ptr: *mut raw::git_packbuilder) -> PackBuilder<'repo> { + PackBuilder { + raw: ptr, + progress: None, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_packbuilder { + self.raw + } +} + +impl<'repo> Drop for PackBuilder<'repo> { + fn drop(&mut self) { + unsafe { + raw::git_packbuilder_set_callbacks(self.raw, None, ptr::null_mut()); + raw::git_packbuilder_free(self.raw); + } + } +} + +impl Binding for PackBuilderStage { + type Raw = raw::git_packbuilder_stage_t; + unsafe fn from_raw(raw: raw::git_packbuilder_stage_t) -> PackBuilderStage { + match raw { + raw::GIT_PACKBUILDER_ADDING_OBJECTS => PackBuilderStage::AddingObjects, + raw::GIT_PACKBUILDER_DELTAFICATION => PackBuilderStage::Deltafication, + _ => panic!("Unknown git diff binary kind"), + } + } + fn raw(&self) -> raw::git_packbuilder_stage_t { + match *self { + PackBuilderStage::AddingObjects => raw::GIT_PACKBUILDER_ADDING_OBJECTS, + PackBuilderStage::Deltafication => raw::GIT_PACKBUILDER_DELTAFICATION, + } + } +} + +extern fn foreach_c(buf: *const c_void, + size: size_t, + data: *mut c_void) + -> c_int { + unsafe { + let buf = slice::from_raw_parts(buf as *const u8, size as usize); + + let r = panic::wrap(|| { + let data = data as *mut &mut ForEachCb; + (*data)(buf) + }); + if r == Some(true) { + 0 + } else { + -1 + } + } +} + +extern fn progress_c(stage: raw::git_packbuilder_stage_t, + current: c_uint, + total: c_uint, + data: *mut c_void) + -> c_int { + unsafe { + let stage = Binding::from_raw(stage); + + let r = panic::wrap(|| { + let data = data as *mut Box; + (*data)(stage, current, total) + }); + if r == Some(true) { + 0 + } else { + -1 + } + } +} + +#[cfg(test)] +mod tests { + use std::fs::File; + use std::path::Path; + use {Buf, Repository, Oid}; + + fn commit(repo: &Repository) -> (Oid, Oid) { + let mut index = t!(repo.index()); + let root = repo.path().parent().unwrap(); + t!(File::create(&root.join("foo"))); + t!(index.add_path(Path::new("foo"))); + + let tree_id = t!(index.write_tree()); + let tree = t!(repo.find_tree(tree_id)); + let sig = t!(repo.signature()); + let head_id = t!(repo.refname_to_id("HEAD")); + let parent = t!(repo.find_commit(head_id)); + let commit = t!(repo.commit(Some("HEAD"), + &sig, + &sig, + "commit", + &tree, + &[&parent])); + (commit, tree_id) + } + + fn pack_header(len: u8) -> Vec { + [].into_iter() + .chain(b"PACK") // signature + .chain(&[0, 0, 0, 2]) // version number + .chain(&[0, 0, 0, len]) // number of objects + .cloned().collect::>() + } + + fn empty_pack_header() -> Vec { + pack_header(0).iter() + .chain(&[0x02, 0x9d, 0x08, 0x82, 0x3b, // ^ + 0xd8, 0xa8, 0xea, 0xb5, 0x10, // | SHA-1 of the zero + 0xad, 0x6a, 0xc7, 0x5c, 0x82, // | object pack header + 0x3c, 0xfd, 0x3e, 0xd3, 0x1e]) // v + .cloned().collect::>() + } + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let _builder = t!(repo.packbuilder()); + } + + #[test] + fn smoke_write_buf() { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let mut buf = Buf::new(); + t!(builder.write_buf(&mut buf)); + assert!(builder.hash().unwrap().is_zero()); + assert_eq!(&*buf, &*empty_pack_header()); + } + + #[test] + fn smoke_foreach() { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let mut buf = Vec::::new(); + t!(builder.foreach(|bytes| { + buf.extend(bytes); + true + })); + assert_eq!(&*buf, &*empty_pack_header()); + } + + #[test] + fn insert_write_buf() { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let mut buf = Buf::new(); + let (commit, _tree) = commit(&repo); + t!(builder.insert_object(commit, None)); + assert_eq!(builder.object_count(), 1); + t!(builder.write_buf(&mut buf)); + // Just check that the correct number of objects are written + assert_eq!(&buf[0..12], &*pack_header(1)); + } + + #[test] + fn insert_tree_write_buf() { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let mut buf = Buf::new(); + let (_commit, tree) = commit(&repo); + // will insert the tree itself and the blob, 2 objects + t!(builder.insert_tree(tree)); + assert_eq!(builder.object_count(), 2); + t!(builder.write_buf(&mut buf)); + // Just check that the correct number of objects are written + assert_eq!(&buf[0..12], &*pack_header(2)); + } + + #[test] + fn insert_commit_write_buf() { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let mut buf = Buf::new(); + let (commit, _tree) = commit(&repo); + // will insert the commit, its tree and the blob, 3 objects + t!(builder.insert_commit(commit)); + assert_eq!(builder.object_count(), 3); + t!(builder.write_buf(&mut buf)); + // Just check that the correct number of objects are written + assert_eq!(&buf[0..12], &*pack_header(3)); + } + + #[test] + fn progress_callback() { + let mut progress_called = false; + { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let (commit, _tree) = commit(&repo); + t!(builder.set_progress_callback(|_, _, _| { + progress_called = true; + true + })); + t!(builder.insert_commit(commit)); + t!(builder.write_buf(&mut Buf::new())); + } + assert_eq!(progress_called, true); + } + + #[test] + fn clear_progress_callback() { + let mut progress_called = false; + { + let (_td, repo) = ::test::repo_init(); + let mut builder = t!(repo.packbuilder()); + let (commit, _tree) = commit(&repo); + t!(builder.set_progress_callback(|_, _, _| { + progress_called = true; + true + })); + t!(builder.unset_progress_callback()); + t!(builder.insert_commit(commit)); + t!(builder.write_buf(&mut Buf::new())); + } + assert_eq!(progress_called, false); + } +} diff --git a/git2/src/panic.rs b/git2/src/panic.rs new file mode 100644 index 000000000..35f2c0939 --- /dev/null +++ b/git2/src/panic.rs @@ -0,0 +1,55 @@ +use std::any::Any; +use std::cell::RefCell; + +thread_local!(static LAST_ERROR: RefCell>> = { + RefCell::new(None) +}); + +#[cfg(feature = "unstable")] +pub fn wrap T + ::std::panic::UnwindSafe>(f: F) -> Option { + use std::panic; + if LAST_ERROR.with(|slot| slot.borrow().is_some()) { + return None + } + match panic::catch_unwind(f) { + Ok(ret) => Some(ret), + Err(e) => { + LAST_ERROR.with(move |slot| { + *slot.borrow_mut() = Some(e); + }); + None + } + } +} + +#[cfg(not(feature = "unstable"))] +pub fn wrap T>(f: F) -> Option { + struct Bomb { + enabled: bool, + } + impl Drop for Bomb { + fn drop(&mut self) { + if !self.enabled { + return + } + panic!("callback has panicked, and continuing to unwind into C \ + is not safe, so aborting the process"); + + } + } + let mut bomb = Bomb { enabled: true }; + let ret = Some(f()); + bomb.enabled = false; + ret +} + +pub fn check() { + let err = LAST_ERROR.with(|slot| slot.borrow_mut().take()); + if let Some(err) = err { + panic!(err) + } +} + +pub fn panicked() -> bool { + LAST_ERROR.with(|slot| slot.borrow().is_some()) +} diff --git a/git2/src/patch.rs b/git2/src/patch.rs new file mode 100644 index 000000000..af7e74ac1 --- /dev/null +++ b/git2/src/patch.rs @@ -0,0 +1,202 @@ +use std::path::Path; +use std::ptr; +use libc::{c_int, c_void}; + +use {raw, Blob, Buf, Diff, DiffDelta, DiffHunk, DiffLine, DiffOptions, Error}; +use diff::{LineCb, print_cb}; +use util::{Binding, into_opt_c_string}; + +/// A structure representing the text changes in a single diff delta. +/// +/// This is an opaque structure. +pub struct Patch { + raw: *mut raw::git_patch, +} + +unsafe impl Send for Patch {} + +impl Binding for Patch { + type Raw = *mut raw::git_patch; + unsafe fn from_raw(raw: Self::Raw) -> Patch { + Patch { raw: raw } + } + fn raw(&self) -> Self::Raw { self.raw } +} + +impl Drop for Patch { + fn drop(&mut self) { + unsafe { raw::git_patch_free(self.raw) } + } +} + +impl Patch { + /// Return a Patch for one file in a Diff. + /// + /// Returns Ok(None) for an unchanged or binary file. + pub fn from_diff(diff: &Diff, idx: usize) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_patch_from_diff(&mut ret, diff.raw(), idx)); + Ok(Binding::from_raw_opt(ret)) + } + } + + /// Generate a Patch by diffing two blobs. + pub fn from_blobs(old_blob: &Blob, + old_path: Option<&Path>, + new_blob: &Blob, + new_path: Option<&Path>, + opts: Option<&mut DiffOptions>) + -> Result + { + let mut ret = ptr::null_mut(); + let old_path = try!(into_opt_c_string(old_path)); + let new_path = try!(into_opt_c_string(new_path)); + unsafe { + try_call!(raw::git_patch_from_blobs(&mut ret, + old_blob.raw(), + old_path, + new_blob.raw(), + new_path, + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Generate a Patch by diffing a blob and a buffer. + pub fn from_blob_and_buffer(old_blob: &Blob, + old_path: Option<&Path>, + new_buffer: &[u8], + new_path: Option<&Path>, + opts: Option<&mut DiffOptions>) + -> Result + { + let mut ret = ptr::null_mut(); + let old_path = try!(into_opt_c_string(old_path)); + let new_path = try!(into_opt_c_string(new_path)); + unsafe { + try_call!(raw::git_patch_from_blob_and_buffer(&mut ret, + old_blob.raw(), + old_path, + new_buffer.as_ptr() as *const c_void, + new_buffer.len(), + new_path, + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Generate a Patch by diffing two buffers. + pub fn from_buffers(old_buffer: &[u8], + old_path: Option<&Path>, + new_buffer: &[u8], + new_path: Option<&Path>, + opts: Option<&mut DiffOptions>) + -> Result + { + let mut ret = ptr::null_mut(); + let old_path = try!(into_opt_c_string(old_path)); + let new_path = try!(into_opt_c_string(new_path)); + unsafe { + try_call!(raw::git_patch_from_buffers(&mut ret, + old_buffer.as_ptr() as *const c_void, + old_buffer.len(), + old_path, + new_buffer.as_ptr() as *const c_void, + new_buffer.len(), + new_path, + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Get the DiffDelta associated with the Patch. + pub fn delta(&self) -> DiffDelta { + unsafe { + Binding::from_raw(raw::git_patch_get_delta(self.raw) as *mut _) + } + } + + /// Get the number of hunks in the Patch. + pub fn num_hunks(&self) -> usize { + unsafe { + raw::git_patch_num_hunks(self.raw) + } + } + + /// Get the number of lines of context, additions, and deletions in the Patch. + pub fn line_stats(&self) -> Result<(usize, usize, usize), Error> { + let mut context = 0; + let mut additions = 0; + let mut deletions = 0; + unsafe { + try_call!(raw::git_patch_line_stats(&mut context, + &mut additions, + &mut deletions, + self.raw)); + } + Ok((context, additions, deletions)) + } + + /// Get a DiffHunk and its total line count from the Patch. + pub fn hunk(&self, hunk_idx: usize) -> Result<(DiffHunk, usize), Error> { + let mut ret = ptr::null(); + let mut lines = 0; + unsafe { + try_call!(raw::git_patch_get_hunk(&mut ret, &mut lines, self.raw, hunk_idx)); + Ok((Binding::from_raw(ret), lines)) + } + } + + /// Get the number of lines in a hunk. + pub fn num_lines_in_hunk(&self, hunk_idx: usize) -> Result { + unsafe { + Ok(try_call!(raw::git_patch_num_lines_in_hunk(self.raw, hunk_idx)) as usize) + } + } + + /// Get a DiffLine from a hunk of the Patch. + pub fn line_in_hunk(&self, + hunk_idx: usize, + line_of_hunk: usize) -> Result { + let mut ret = ptr::null(); + unsafe { + try_call!(raw::git_patch_get_line_in_hunk(&mut ret, + self.raw, + hunk_idx, + line_of_hunk)); + Ok(Binding::from_raw(ret)) + } + } + + /// Get the size of a Patch's diff data in bytes. + pub fn size(&self, + include_context: bool, + include_hunk_headers: bool, + include_file_headers: bool) -> usize { + unsafe { + raw::git_patch_size(self.raw, + include_context as c_int, + include_hunk_headers as c_int, + include_file_headers as c_int) + } + } + + /// Print the Patch to text via a callback. + pub fn print(&mut self, mut line_cb: &mut LineCb) -> Result<(), Error> { + let ptr = &mut line_cb as *mut _ as *mut c_void; + unsafe { + try_call!(raw::git_patch_print(self.raw, print_cb, ptr)); + Ok(()) + } + } + + /// Get the Patch text as a Buf. + pub fn to_buf(&mut self) -> Result { + let buf = Buf::new(); + unsafe { + try_call!(raw::git_patch_to_buf(buf.raw(), self.raw)); + } + Ok(buf) + } +} diff --git a/git2/src/pathspec.rs b/git2/src/pathspec.rs new file mode 100644 index 000000000..5cc03ab3b --- /dev/null +++ b/git2/src/pathspec.rs @@ -0,0 +1,301 @@ +use std::iter::IntoIterator; +use std::marker; +use std::ops::Range; +use std::path::Path; +use std::ptr; +use libc::size_t; + +use {raw, Error, Diff, Tree, PathspecFlags, Index, Repository, DiffDelta, IntoCString}; +use util::Binding; + +/// Structure representing a compiled pathspec used for matching against various +/// structures. +pub struct Pathspec { + raw: *mut raw::git_pathspec, +} + +/// List of filenames matching a pathspec. +pub struct PathspecMatchList<'ps> { + raw: *mut raw::git_pathspec_match_list, + _marker: marker::PhantomData<&'ps Pathspec>, +} + +/// Iterator over the matched paths in a pathspec. +pub struct PathspecEntries<'list> { + range: Range, + list: &'list PathspecMatchList<'list>, +} + +/// Iterator over the matching diff deltas. +pub struct PathspecDiffEntries<'list> { + range: Range, + list: &'list PathspecMatchList<'list>, +} + +/// Iterator over the failed list of pathspec items that did not match. +pub struct PathspecFailedEntries<'list> { + range: Range, + list: &'list PathspecMatchList<'list>, +} + +impl Pathspec { + /// Creates a new pathspec from a list of specs to match against. + pub fn new(specs: I) -> Result + where T: IntoCString, I: IntoIterator { + let (_a, _b, arr) = try!(::util::iter2cstrs(specs)); + unsafe { + let mut ret = ptr::null_mut(); + try_call!(raw::git_pathspec_new(&mut ret, &arr)); + Ok(Binding::from_raw(ret)) + } + } + + /// Match a pathspec against files in a diff. + /// + /// The list returned contains the list of all matched filenames (unless you + /// pass `PATHSPEC_FAILURES_ONLY` in the flags) and may also contain the + /// list of pathspecs with no match if the `PATHSPEC_FIND_FAILURES` flag is + /// specified. + pub fn match_diff(&self, diff: &Diff, flags: PathspecFlags) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_pathspec_match_diff(&mut ret, diff.raw(), + flags.bits(), self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Match a pathspec against files in a tree. + /// + /// The list returned contains the list of all matched filenames (unless you + /// pass `PATHSPEC_FAILURES_ONLY` in the flags) and may also contain the + /// list of pathspecs with no match if the `PATHSPEC_FIND_FAILURES` flag is + /// specified. + pub fn match_tree(&self, tree: &Tree, flags: PathspecFlags) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_pathspec_match_tree(&mut ret, tree.raw(), + flags.bits(), self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// This matches the pathspec against the files in the repository index. + /// + /// The list returned contains the list of all matched filenames (unless you + /// pass `PATHSPEC_FAILURES_ONLY` in the flags) and may also contain the + /// list of pathspecs with no match if the `PATHSPEC_FIND_FAILURES` flag is + /// specified. + pub fn match_index(&self, index: &Index, flags: PathspecFlags) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_pathspec_match_index(&mut ret, index.raw(), + flags.bits(), self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Match a pathspec against the working directory of a repository. + /// + /// This matches the pathspec against the current files in the working + /// directory of the repository. It is an error to invoke this on a bare + /// repo. This handles git ignores (i.e. ignored files will not be + /// considered to match the pathspec unless the file is tracked in the + /// index). + /// + /// The list returned contains the list of all matched filenames (unless you + /// pass `PATHSPEC_FAILURES_ONLY` in the flags) and may also contain the + /// list of pathspecs with no match if the `PATHSPEC_FIND_FAILURES` flag is + /// specified. + pub fn match_workdir(&self, repo: &Repository, flags: PathspecFlags) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_pathspec_match_workdir(&mut ret, repo.raw(), + flags.bits(), self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Try to match a path against a pathspec + /// + /// Unlike most of the other pathspec matching functions, this will not fall + /// back on the native case-sensitivity for your platform. You must + /// explicitly pass flags to control case sensitivity or else this will fall + /// back on being case sensitive. + pub fn matches_path(&self, path: &Path, flags: PathspecFlags) -> bool { + let path = path.into_c_string().unwrap(); + unsafe { + raw::git_pathspec_matches_path(&*self.raw, flags.bits(), + path.as_ptr()) == 1 + } + } +} + +impl Binding for Pathspec { + type Raw = *mut raw::git_pathspec; + + unsafe fn from_raw(raw: *mut raw::git_pathspec) -> Pathspec { + Pathspec { raw: raw } + } + fn raw(&self) -> *mut raw::git_pathspec { self.raw } +} + +impl Drop for Pathspec { + fn drop(&mut self) { + unsafe { raw::git_pathspec_free(self.raw) } + } +} + +impl<'ps> PathspecMatchList<'ps> { + fn entrycount(&self) -> usize { + unsafe { raw::git_pathspec_match_list_entrycount(&*self.raw) as usize } + } + + fn failed_entrycount(&self) -> usize { + unsafe { raw::git_pathspec_match_list_failed_entrycount(&*self.raw) as usize } + } + + /// Returns an iterator over the matching filenames in this list. + pub fn entries(&self) -> PathspecEntries { + let n = self.entrycount(); + let n = if n > 0 && self.entry(0).is_none() {0} else {n}; + PathspecEntries { range: 0..n, list: self } + } + + /// Get a matching filename by position. + /// + /// If this list was generated from a diff, then the return value will + /// always be `None. + pub fn entry(&self, i: usize) -> Option<&[u8]> { + unsafe { + let ptr = raw::git_pathspec_match_list_entry(&*self.raw, i as size_t); + ::opt_bytes(self, ptr) + } + } + + /// Returns an iterator over the matching diff entries in this list. + pub fn diff_entries(&self) -> PathspecDiffEntries { + let n = self.entrycount(); + let n = if n > 0 && self.diff_entry(0).is_none() {0} else {n}; + PathspecDiffEntries { range: 0..n, list: self } + } + + /// Get a matching diff delta by position. + /// + /// If the list was not generated from a diff, then the return value will + /// always be `None`. + pub fn diff_entry(&self, i: usize) -> Option { + unsafe { + let ptr = raw::git_pathspec_match_list_diff_entry(&*self.raw, + i as size_t); + Binding::from_raw_opt(ptr as *mut _) + } + } + + /// Returns an iterator over the non-matching entries in this list. + pub fn failed_entries(&self) -> PathspecFailedEntries { + let n = self.failed_entrycount(); + let n = if n > 0 && self.failed_entry(0).is_none() {0} else {n}; + PathspecFailedEntries { range: 0..n, list: self } + } + + /// Get an original pathspec string that had no matches. + pub fn failed_entry(&self, i: usize) -> Option<&[u8]> { + unsafe { + let ptr = raw::git_pathspec_match_list_failed_entry(&*self.raw, + i as size_t); + ::opt_bytes(self, ptr) + } + } +} + +impl<'ps> Binding for PathspecMatchList<'ps> { + type Raw = *mut raw::git_pathspec_match_list; + + unsafe fn from_raw(raw: *mut raw::git_pathspec_match_list) + -> PathspecMatchList<'ps> { + PathspecMatchList { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_pathspec_match_list { self.raw } +} + +impl<'ps> Drop for PathspecMatchList<'ps> { + fn drop(&mut self) { + unsafe { raw::git_pathspec_match_list_free(self.raw) } + } +} + +impl<'list> Iterator for PathspecEntries<'list> { + type Item = &'list [u8]; + fn next(&mut self) -> Option<&'list [u8]> { + self.range.next().and_then(|i| self.list.entry(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'list> DoubleEndedIterator for PathspecEntries<'list> { + fn next_back(&mut self) -> Option<&'list [u8]> { + self.range.next_back().and_then(|i| self.list.entry(i)) + } +} +impl<'list> ExactSizeIterator for PathspecEntries<'list> {} + +impl<'list> Iterator for PathspecDiffEntries<'list> { + type Item = DiffDelta<'list>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.list.diff_entry(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'list> DoubleEndedIterator for PathspecDiffEntries<'list> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.list.diff_entry(i)) + } +} +impl<'list> ExactSizeIterator for PathspecDiffEntries<'list> {} + +impl<'list> Iterator for PathspecFailedEntries<'list> { + type Item = &'list [u8]; + fn next(&mut self) -> Option<&'list [u8]> { + self.range.next().and_then(|i| self.list.failed_entry(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'list> DoubleEndedIterator for PathspecFailedEntries<'list> { + fn next_back(&mut self) -> Option<&'list [u8]> { + self.range.next_back().and_then(|i| self.list.failed_entry(i)) + } +} +impl<'list> ExactSizeIterator for PathspecFailedEntries<'list> {} + +#[cfg(test)] +mod tests { + use PathspecFlags; + use super::Pathspec; + use std::fs::File; + use std::path::Path; + + #[test] + fn smoke() { + let ps = Pathspec::new(["a"].iter()).unwrap(); + assert!(ps.matches_path(Path::new("a"), PathspecFlags::DEFAULT)); + assert!(ps.matches_path(Path::new("a/b"), PathspecFlags::DEFAULT)); + assert!(!ps.matches_path(Path::new("b"), PathspecFlags::DEFAULT)); + assert!(!ps.matches_path(Path::new("ab/c"), PathspecFlags::DEFAULT)); + + let (td, repo) = ::test::repo_init(); + let list = ps.match_workdir(&repo, PathspecFlags::DEFAULT).unwrap(); + assert_eq!(list.entries().len(), 0); + assert_eq!(list.diff_entries().len(), 0); + assert_eq!(list.failed_entries().len(), 0); + + File::create(&td.path().join("a")).unwrap(); + + let list = ps.match_workdir(&repo, ::PathspecFlags::FIND_FAILURES).unwrap(); + assert_eq!(list.entries().len(), 1); + assert_eq!(list.entries().next(), Some("a".as_bytes())); + } +} diff --git a/git2/src/proxy_options.rs b/git2/src/proxy_options.rs new file mode 100644 index 000000000..e1601749b --- /dev/null +++ b/git2/src/proxy_options.rs @@ -0,0 +1,56 @@ +use std::ffi::CString; +use std::marker; +use std::ptr; + +use raw; +use util::Binding; + +/// Options which can be specified to various fetch operations. +#[derive(Default)] +pub struct ProxyOptions<'a> { + url: Option, + proxy_kind: raw::git_proxy_t, + _marker: marker::PhantomData<&'a i32>, +} + +impl<'a> ProxyOptions<'a> { + /// Creates a new set of proxy options ready to be configured. + pub fn new() -> ProxyOptions<'a> { + Default::default() + } + + /// Try to auto-detect the proxy from the git configuration. + /// + /// Note that this will override `url` specified before. + pub fn auto(&mut self) -> &mut Self { + self.proxy_kind = raw::GIT_PROXY_AUTO; + self + } + + /// Specify the exact URL of the proxy to use. + /// + /// Note that this will override `auto` specified before. + pub fn url(&mut self, url: &str) -> &mut Self { + self.proxy_kind = raw::GIT_PROXY_SPECIFIED; + self.url = Some(CString::new(url).unwrap()); + self + } +} + +impl<'a> Binding for ProxyOptions<'a> { + type Raw = raw::git_proxy_options; + unsafe fn from_raw(_raw: raw::git_proxy_options) -> ProxyOptions<'a> { + panic!("can't create proxy from raw options") + } + + fn raw(&self) -> raw::git_proxy_options { + raw::git_proxy_options { + version: raw::GIT_PROXY_OPTIONS_VERSION, + kind: self.proxy_kind, + url: self.url.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()), + credentials: None, + certificate_check: None, + payload: ptr::null_mut(), + } + } +} diff --git a/git2/src/rebase.rs b/git2/src/rebase.rs new file mode 100644 index 000000000..b10ec310f --- /dev/null +++ b/git2/src/rebase.rs @@ -0,0 +1,354 @@ +use std::{marker, ptr, mem, str}; +use std::ffi::CString; + +use {raw, Oid, Error, Signature, MergeOptions, Index}; +use build::CheckoutBuilder; +use util::Binding; + +/// Rebase options +/// +/// Use to tell the rebase machinery how to operate. +pub struct RebaseOptions<'cb> { + raw: raw::git_rebase_options, + merge_options: Option, + checkout_options: Option>, +} + +impl<'cb> Default for RebaseOptions<'cb> { + fn default() -> Self { + Self::new() + } +} + +impl<'cb> RebaseOptions<'cb> { + /// Creates a new default set of rebase options. + pub fn new() -> RebaseOptions<'cb> { + let mut opts = RebaseOptions { + raw: unsafe { mem::zeroed() }, + merge_options: None, + checkout_options: None, + }; + assert_eq!(unsafe { + raw::git_rebase_init_options(&mut opts.raw, 1) + }, 0); + opts + } + + /// Used by `Repository::rebase`, this will instruct other clients working on this + /// rebase that you want a quiet rebase experience, which they may choose to + /// provide in an application-specific manner. This has no effect upon + /// libgit2 directly, but is provided for interoperability between Git + /// tools. + pub fn quiet(&mut self, quiet: bool) -> &mut RebaseOptions<'cb> { + self.raw.quiet = quiet as i32; + self + } + + /// Used by `Repository::rebase`, this will begin an in-memory rebase, + /// which will allow callers to step through the rebase operations and + /// commit the rebased changes, but will not rewind HEAD or update the + /// repository to be in a rebasing state. This will not interfere with + /// the working directory (if there is one). + pub fn inmemory(&mut self, inmemory: bool) -> &mut RebaseOptions<'cb> { + self.raw.inmemory = inmemory as i32; + self + } + + /// Used by `finish()`, this is the name of the notes reference + /// used to rewrite notes for rebased commits when finishing the rebase; + /// if NULL, the contents of the configuration option `notes.rewriteRef` + /// is examined, unless the configuration option `notes.rewrite.rebase` + /// is set to false. If `notes.rewriteRef` is also NULL, notes will + /// not be rewritten. + pub fn rewrite_notes_ref(&mut self, rewrite_notes_ref: &str) -> &mut RebaseOptions<'cb> { + let s = CString::new(rewrite_notes_ref).unwrap().as_ptr(); + self.raw.rewrite_notes_ref = s; + self + } + + /// Options to control how trees are merged during `next()`. + pub fn merge_options(&mut self, opts: MergeOptions) -> &mut RebaseOptions<'cb> { + self.merge_options = Some(opts); + self + } + + /// Options to control how files are written during `Repository::rebase`, + /// `next()` and `abort()`. Note that a minimum strategy of + /// `GIT_CHECKOUT_SAFE` is defaulted in `init` and `next`, and a minimum + /// strategy of `GIT_CHECKOUT_FORCE` is defaulted in `abort` to match git + /// semantics. + pub fn checkout_options(&mut self, opts: CheckoutBuilder<'cb>) -> &mut RebaseOptions<'cb> { + self.checkout_options = Some(opts); + self + } + + /// Acquire a pointer to the underlying raw options. + pub fn raw(&mut self) -> *const raw::git_rebase_options { + unsafe { + if let Some(opts) = self.merge_options.as_mut().take() { + ptr::copy_nonoverlapping(opts.raw(), &mut self.raw.merge_options, 1); + mem::forget(opts); + } + if let Some(opts) = self.checkout_options.as_mut() { + opts.configure(&mut self.raw.checkout_options); + } + } + &self.raw + } + +} + +/// Representation of a rebase +pub struct Rebase<'repo> { + raw: *mut raw::git_rebase, + _marker: marker::PhantomData<&'repo raw::git_rebase>, +} + +impl <'repo> Rebase<'repo> { + /// Gets the count of rebase operations that are to be applied. + pub fn len(&self) -> usize { + unsafe { raw::git_rebase_operation_entrycount(self.raw) } + } + + /// Gets the rebase operation specified by the given index. + pub fn nth(&mut self, n: usize) -> Option { + unsafe { + let op = raw::git_rebase_operation_byindex(self.raw, n); + if op.is_null() { + None + } else { + Some(RebaseOperation::from_raw(op)) + } + } + } + + /// Gets the index of the rebase operation that is currently being applied. + /// If the first operation has not yet been applied (because you have called + /// `init` but not yet `next`) then this returns None. + pub fn operation_current(&mut self) -> Option { + let cur = unsafe { raw::git_rebase_operation_current(self.raw) }; + if cur == raw::GIT_REBASE_NO_OPERATION { + None + } else { + Some(cur) + } + } + + /// Gets the index produced by the last operation, which is the result of + /// `next()` and which will be committed by the next invocation of + /// `commit()`. This is useful for resolving conflicts in an in-memory + /// rebase before committing them. + /// + /// This is only applicable for in-memory rebases; for rebases within a + /// working directory, the changes were applied to the repository's index. + pub fn inmemory_index(&mut self) -> Result { + let mut idx = ptr::null_mut(); + unsafe { + try_call!(raw::git_rebase_inmemory_index(&mut idx, self.raw)); + Ok(Binding::from_raw(idx)) + } + } + + /// Commits the current patch. You must have resolved any conflicts that + /// were introduced during the patch application from the `git_rebase_next` + /// invocation. + pub fn commit(&mut self, author: &Signature, committer: &Signature, message: &str) -> Result { + let mut id: raw::git_oid = unsafe { mem::zeroed() }; + let message = try!(CString::new(message)); + unsafe { + try_call!(raw::git_rebase_commit(&mut id, self.raw, author.raw(), committer.raw(), ptr::null(), message)); + Ok(Binding::from_raw(&id as *const _)) + } + } + + /// Aborts a rebase that is currently in progress, resetting the repository + /// and working directory to their state before rebase began. + pub fn abort(&mut self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_rebase_abort(self.raw)); + } + + Ok(()) + } + + /// Finishes a rebase that is currently in progress once all patches have + /// been applied. + pub fn finish(&mut self, signature: &Signature) -> Result<(), Error> { + unsafe { + try_call!(raw::git_rebase_finish(self.raw, signature.raw())); + } + + Ok(()) + } +} + +impl <'rebase> Iterator for Rebase<'rebase> { + type Item = Result, Error>; + + /// Performs the next rebase operation and returns the information about it. + /// If the operation is one that applies a patch (which is any operation except + /// GitRebaseOperation::Exec) then the patch will be applied and the index and + /// working directory will be updated with the changes. If there are conflicts, + /// you will need to address those before committing the changes. + fn next(&mut self) -> Option, Error>> { + let mut out = ptr::null_mut(); + unsafe { + try_call_iter!(raw::git_rebase_next(&mut out, self.raw)); + Some(Ok(RebaseOperation::from_raw(out))) + } + } +} + + +impl<'repo> Binding for Rebase<'repo> { + type Raw = *mut raw::git_rebase; + unsafe fn from_raw(raw: *mut raw::git_rebase) + -> Rebase<'repo> { + Rebase { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_rebase { self.raw } +} + + +impl<'repo> Drop for Rebase<'repo> { + fn drop(&mut self) { + unsafe { raw::git_rebase_free(self.raw) } + } +} + +/// A rebase operation +/// +/// Describes a single instruction/operation to be performed during the +/// rebase. +#[derive(Debug, PartialEq)] +pub enum RebaseOperationType { + /// The given commit is to be cherry-picked. The client should commit the + /// changes and continue if there are no conflicts. + Pick, + + /// The given commit is to be cherry-picked, but the client should prompt + /// the user to provide an updated commit message. + Reword, + + /// The given commit is to be cherry-picked, but the client should stop to + /// allow the user to edit the changes before committing them. + Edit, + + /// The given commit is to be squashed into the previous commit. The commit + /// message will be merged with the previous message. + Squash, + + /// The given commit is to be squashed into the previous commit. The commit + /// message from this commit will be discarded. + Fixup, + + /// No commit will be cherry-picked. The client should run the given command + /// and (if successful) continue. + Exec, +} + +impl RebaseOperationType { + /// Convert from the int into an enum. Returns None if invalid. + pub fn from_raw(raw: raw::git_rebase_operation_t) -> Option { + match raw { + raw::GIT_REBASE_OPERATION_PICK => Some(RebaseOperationType::Pick), + raw::GIT_REBASE_OPERATION_REWORD => Some(RebaseOperationType::Reword), + raw::GIT_REBASE_OPERATION_EDIT => Some(RebaseOperationType::Edit), + raw::GIT_REBASE_OPERATION_SQUASH => Some(RebaseOperationType::Squash), + raw::GIT_REBASE_OPERATION_FIXUP => Some(RebaseOperationType::Fixup), + raw::GIT_REBASE_OPERATION_EXEC => Some(RebaseOperationType::Exec), + _ => None, + } + } +} + +/// A rebase operation +/// +/// Describes a single instruction/operation to be performed during the +/// rebase. +#[derive(Debug)] +pub struct RebaseOperation<'rebase> { + raw: *const raw::git_rebase_operation, + _marker: marker::PhantomData>, +} + +impl<'rebase> RebaseOperation<'rebase> { + /// The type of rebase operation + pub fn kind(&self) -> Option { + unsafe { + RebaseOperationType::from_raw((*self.raw).kind) + } + } + + /// The commit ID being cherry-picked. This will be populated for all + /// operations except those of type `GIT_REBASE_OPERATION_EXEC`. + pub fn id(&self) -> Oid { + unsafe { + Binding::from_raw(&(*self.raw).id as *const _) + } + } + + ///The executable the user has requested be run. This will only + /// be populated for operations of type RebaseOperationType::Exec + pub fn exec(&self) -> Option<&str> { + unsafe { + str::from_utf8(::opt_bytes(self, (*self.raw).exec).unwrap()).ok() + } + } +} + +impl<'rebase> Binding for RebaseOperation<'rebase> { + type Raw = *const raw::git_rebase_operation; + unsafe fn from_raw(raw: *const raw::git_rebase_operation) -> RebaseOperation<'rebase> { + RebaseOperation { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *const raw::git_rebase_operation { self.raw } +} + +#[cfg(test)] +mod tests { + use {RebaseOptions, RebaseOperationType}; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head_target = repo.head().unwrap().target().unwrap(); + let tip = repo.find_commit(head_target).unwrap(); + let sig = tip.author(); + let tree = tip.tree().unwrap(); + + // We just want to see the iteration work so we can create commits with + // no changes + let c1 = repo.commit(Some("refs/heads/master"), &sig, &sig, "foo", &tree, &[&tip]).unwrap(); + let c1 = repo.find_commit(c1).unwrap(); + let c2 = repo.commit(Some("refs/heads/master"), &sig, &sig, "foo", &tree, &[&c1]).unwrap(); + + let branch = repo.find_annotated_commit(c2).unwrap(); + let upstream = repo .find_annotated_commit(tip.id()).unwrap(); + let mut opts: RebaseOptions = Default::default(); + opts.inmemory(true); + let mut rebase = repo.rebase(Some(&branch), Some(&upstream), None, Some(&mut opts)).unwrap(); + + assert_eq!(rebase.len(), 2); + { + let op = rebase.next().unwrap().unwrap(); + assert_eq!(op.kind(), Some(RebaseOperationType::Pick)); + assert_eq!(op.id(), c1.id()); + } + { + let op = rebase.next().unwrap().unwrap(); + assert_eq!(op.kind(), Some(RebaseOperationType::Pick)); + assert_eq!(op.id(), c2); + } + { + let op = rebase.next(); + assert!(op.is_none()); + } + } +} diff --git a/git2/src/reference.rs b/git2/src/reference.rs new file mode 100644 index 000000000..265d76614 --- /dev/null +++ b/git2/src/reference.rs @@ -0,0 +1,401 @@ +use std::cmp::Ordering; +use std::ffi::CString; +use std::marker; +use std::mem; +use std::ptr; +use std::str; + +use {raw, Error, Oid, Repository, ReferenceType, Object, ObjectType, Blob, Commit, Tree, Tag}; +use object::CastOrPanic; +use util::Binding; + +struct Refdb<'repo>(&'repo Repository); + +/// A structure to represent a git [reference][1]. +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-References +pub struct Reference<'repo> { + raw: *mut raw::git_reference, + _marker: marker::PhantomData>, +} + +/// An iterator over the references in a repository. +pub struct References<'repo> { + raw: *mut raw::git_reference_iterator, + _marker: marker::PhantomData>, +} + +/// An iterator over the names of references in a repository. +pub struct ReferenceNames<'repo: 'references, 'references> { + inner: &'references mut References<'repo>, +} + +impl<'repo> Reference<'repo> { + /// Ensure the reference name is well-formed. + pub fn is_valid_name(refname: &str) -> bool { + ::init(); + let refname = CString::new(refname).unwrap(); + unsafe { raw::git_reference_is_valid_name(refname.as_ptr()) == 1 } + } + + /// Get access to the underlying raw pointer. + pub fn raw(&self) -> *mut raw::git_reference { self.raw } + + /// Delete an existing reference. + /// + /// This method works for both direct and symbolic references. The reference + /// will be immediately removed on disk. + /// + /// This function will return an error if the reference has changed from the + /// time it was looked up. + pub fn delete(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_reference_delete(self.raw)); } + Ok(()) + } + + /// Check if a reference is a local branch. + pub fn is_branch(&self) -> bool { + unsafe { raw::git_reference_is_branch(&*self.raw) == 1 } + } + + /// Check if a reference is a note. + pub fn is_note(&self) -> bool { + unsafe { raw::git_reference_is_note(&*self.raw) == 1 } + } + + /// Check if a reference is a remote tracking branch + pub fn is_remote(&self) -> bool { + unsafe { raw::git_reference_is_remote(&*self.raw) == 1 } + } + + /// Check if a reference is a tag + pub fn is_tag(&self) -> bool { + unsafe { raw::git_reference_is_tag(&*self.raw) == 1 } + } + + /// Get the reference type of a reference. + /// + /// If the type is unknown, then `None` is returned. + pub fn kind(&self) -> Option { + ReferenceType::from_raw(unsafe { raw::git_reference_type(&*self.raw) }) + } + + /// Get the full name of a reference. + /// + /// Returns `None` if the name is not valid utf-8. + pub fn name(&self) -> Option<&str> { str::from_utf8(self.name_bytes()).ok() } + + /// Get the full name of a reference. + pub fn name_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_reference_name(&*self.raw)).unwrap() } + } + + /// Get the full shorthand of a reference. + /// + /// This will transform the reference name into a name "human-readable" + /// version. If no shortname is appropriate, it will return the full name. + /// + /// Returns `None` if the shorthand is not valid utf-8. + pub fn shorthand(&self) -> Option<&str> { + str::from_utf8(self.shorthand_bytes()).ok() + } + + /// Get the full shorthand of a reference. + pub fn shorthand_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_reference_shorthand(&*self.raw)).unwrap() + } + } + + /// Get the OID pointed to by a direct reference. + /// + /// Only available if the reference is direct (i.e. an object id reference, + /// not a symbolic one). + pub fn target(&self) -> Option { + unsafe { + Binding::from_raw_opt(raw::git_reference_target(&*self.raw)) + } + } + + /// Return the peeled OID target of this reference. + /// + /// This peeled OID only applies to direct references that point to a hard + /// Tag object: it is the result of peeling such Tag. + pub fn target_peel(&self) -> Option { + unsafe { + Binding::from_raw_opt(raw::git_reference_target_peel(&*self.raw)) + } + } + + /// Get full name to the reference pointed to by a symbolic reference. + /// + /// May return `None` if the reference is either not symbolic or not a + /// valid utf-8 string. + pub fn symbolic_target(&self) -> Option<&str> { + self.symbolic_target_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get full name to the reference pointed to by a symbolic reference. + /// + /// Only available if the reference is symbolic. + pub fn symbolic_target_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_reference_symbolic_target(&*self.raw)) } + } + + /// Resolve a symbolic reference to a direct reference. + /// + /// This method iteratively peels a symbolic reference until it resolves to + /// a direct reference to an OID. + /// + /// If a direct reference is passed as an argument, a copy of that + /// reference is returned. + pub fn resolve(&self) -> Result, Error> { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_resolve(&mut raw, &*self.raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Peel a reference to an object + /// + /// This method recursively peels the reference until it reaches + /// an object of the specified type. + pub fn peel(&self, kind: ObjectType) -> Result, Error> { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_peel(&mut raw, self.raw, kind)); + Ok(Binding::from_raw(raw)) + } + } + + /// Peel a reference to a blob + /// + /// This method recursively peels the reference until it reaches + /// a blob. + pub fn peel_to_blob(&self) -> Result, Error> { + Ok(try!(self.peel(ObjectType::Blob)).cast_or_panic(ObjectType::Blob)) + } + + /// Peel a reference to a commit + /// + /// This method recursively peels the reference until it reaches + /// a blob. + pub fn peel_to_commit(&self) -> Result, Error> { + Ok(try!(self.peel(ObjectType::Commit)).cast_or_panic(ObjectType::Commit)) + } + + /// Peel a reference to a tree + /// + /// This method recursively peels the reference until it reaches + /// a blob. + pub fn peel_to_tree(&self) -> Result, Error> { + Ok(try!(self.peel(ObjectType::Tree)).cast_or_panic(ObjectType::Tree)) + } + + /// Peel a reference to a tag + /// + /// This method recursively peels the reference until it reaches + /// a tag. + pub fn peel_to_tag(&self) -> Result, Error> { + Ok(try!(self.peel(ObjectType::Tag)).cast_or_panic(ObjectType::Tag)) + } + + /// Rename an existing reference. + /// + /// This method works for both direct and symbolic references. + /// + /// If the force flag is not enabled, and there's already a reference with + /// the given name, the renaming will fail. + pub fn rename(&mut self, new_name: &str, force: bool, + msg: &str) -> Result, Error> { + let mut raw = ptr::null_mut(); + let new_name = try!(CString::new(new_name)); + let msg = try!(CString::new(msg)); + unsafe { + try_call!(raw::git_reference_rename(&mut raw, self.raw, new_name, + force, msg)); + Ok(Binding::from_raw(raw)) + } + } + + /// Conditionally create a new reference with the same name as the given + /// reference but a different OID target. The reference must be a direct + /// reference, otherwise this will fail. + /// + /// The new reference will be written to disk, overwriting the given + /// reference. + pub fn set_target(&mut self, id: Oid, reflog_msg: &str) + -> Result, Error> { + let mut raw = ptr::null_mut(); + let msg = try!(CString::new(reflog_msg)); + unsafe { + try_call!(raw::git_reference_set_target(&mut raw, self.raw, + id.raw(), msg)); + Ok(Binding::from_raw(raw)) + } + } + +} + +impl<'repo> PartialOrd for Reference<'repo> { + fn partial_cmp(&self, other: &Reference<'repo>) -> Option { + Some(self.cmp(other)) + } +} + +impl<'repo> Ord for Reference<'repo> { + fn cmp(&self, other: &Reference<'repo>) -> Ordering { + match unsafe { raw::git_reference_cmp(&*self.raw, &*other.raw) } { + 0 => Ordering::Equal, + n if n < 0 => Ordering::Less, + _ => Ordering::Greater, + } + } +} + +impl<'repo> PartialEq for Reference<'repo> { + fn eq(&self, other: &Reference<'repo>) -> bool { + self.cmp(other) == Ordering::Equal + } +} + +impl<'repo> Eq for Reference<'repo> {} + +impl<'repo> Binding for Reference<'repo> { + type Raw = *mut raw::git_reference; + unsafe fn from_raw(raw: *mut raw::git_reference) -> Reference<'repo> { + Reference { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_reference { self.raw } +} + +impl<'repo> Drop for Reference<'repo> { + fn drop(&mut self) { + unsafe { raw::git_reference_free(self.raw) } + } +} + +impl<'repo> References<'repo> { + /// Consumes a `References` iterator to create an iterator over just the + /// name of some references. + /// + /// This is more efficient if only the names are desired of references as + /// the references themselves don't have to be allocated and deallocated. + /// + /// The returned iterator will yield strings as opposed to a `Reference`. + pub fn names<'a>(&'a mut self) -> ReferenceNames<'repo, 'a> { + ReferenceNames { inner: self } + } +} + +impl<'repo> Binding for References<'repo> { + type Raw = *mut raw::git_reference_iterator; + unsafe fn from_raw(raw: *mut raw::git_reference_iterator) + -> References<'repo> { + References { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_reference_iterator { self.raw } +} + +impl<'repo> Iterator for References<'repo> { + type Item = Result, Error>; + fn next(&mut self) -> Option, Error>> { + let mut out = ptr::null_mut(); + unsafe { + try_call_iter!(raw::git_reference_next(&mut out, self.raw)); + Some(Ok(Binding::from_raw(out))) + } + } +} + +impl<'repo> Drop for References<'repo> { + fn drop(&mut self) { + unsafe { raw::git_reference_iterator_free(self.raw) } + } +} + +impl<'repo, 'references> Iterator for ReferenceNames<'repo, 'references> { + type Item = Result<&'references str, Error>; + fn next(&mut self) -> Option> { + let mut out = ptr::null(); + unsafe { + try_call_iter!(raw::git_reference_next_name(&mut out, + self.inner.raw)); + let bytes = ::opt_bytes(self, out).unwrap(); + let s = str::from_utf8(bytes).unwrap(); + Some(Ok(mem::transmute::<&str, &'references str>(s))) + } + } +} + +#[cfg(test)] +mod tests { + use {Reference, ObjectType, ReferenceType}; + + #[test] + fn smoke() { + assert!(Reference::is_valid_name("refs/foo")); + assert!(!Reference::is_valid_name("foo")); + } + + #[test] + fn smoke2() { + let (_td, repo) = ::test::repo_init(); + let mut head = repo.head().unwrap(); + assert!(head.is_branch()); + assert!(!head.is_remote()); + assert!(!head.is_tag()); + assert!(!head.is_note()); + + // HEAD is a symbolic reference but git_repository_head resolves it + // so it is a GIT_REF_OID. + assert_eq!(head.kind().unwrap(), ReferenceType::Oid); + + assert!(head == repo.head().unwrap()); + assert_eq!(head.name(), Some("refs/heads/master")); + + assert!(head == repo.find_reference("refs/heads/master").unwrap()); + assert_eq!(repo.refname_to_id("refs/heads/master").unwrap(), + head.target().unwrap()); + + assert!(head.symbolic_target().is_none()); + assert!(head.target_peel().is_none()); + + assert_eq!(head.shorthand(), Some("master")); + assert!(head.resolve().unwrap() == head); + + let mut tag1 = repo.reference("refs/tags/tag1", + head.target().unwrap(), + false, "test").unwrap(); + assert!(tag1.is_tag()); + assert_eq!(tag1.kind().unwrap(), ReferenceType::Oid); + + let peeled_commit = tag1.peel(ObjectType::Commit).unwrap(); + assert_eq!(ObjectType::Commit, peeled_commit.kind().unwrap()); + assert_eq!(tag1.target().unwrap(), peeled_commit.id()); + + tag1.delete().unwrap(); + + let mut sym1 = repo.reference_symbolic("refs/tags/tag1", + "refs/heads/master", false, + "test").unwrap(); + assert_eq!(sym1.kind().unwrap(), ReferenceType::Symbolic); + sym1.delete().unwrap(); + + { + assert!(repo.references().unwrap().count() == 1); + assert!(repo.references().unwrap().next().unwrap().unwrap() == head); + let mut names = repo.references().unwrap(); + let mut names = names.names(); + assert_eq!(names.next().unwrap().unwrap(), "refs/heads/master"); + assert!(names.next().is_none()); + assert!(repo.references_glob("foo").unwrap().count() == 0); + assert!(repo.references_glob("refs/heads/*").unwrap().count() == 1); + } + + let mut head = head.rename("refs/foo", true, "test").unwrap(); + head.delete().unwrap(); + + } +} diff --git a/git2/src/reflog.rs b/git2/src/reflog.rs new file mode 100644 index 000000000..b4ff7a037 --- /dev/null +++ b/git2/src/reflog.rs @@ -0,0 +1,172 @@ +use std::ops::Range; +use std::marker; +use std::str; +use libc::size_t; + +use {raw, signature, Oid, Error, Signature}; +use util::Binding; + +/// A reference log of a git repository. +pub struct Reflog { + raw: *mut raw::git_reflog, +} + +/// An entry inside the reflog of a repository +pub struct ReflogEntry<'reflog> { + raw: *const raw::git_reflog_entry, + _marker: marker::PhantomData<&'reflog Reflog>, +} + +/// An iterator over the entries inside of a reflog. +pub struct ReflogIter<'reflog> { + range: Range, + reflog: &'reflog Reflog, +} + +impl Reflog { + /// Add a new entry to the in-memory reflog. + pub fn append(&mut self, new_oid: Oid, committer: &Signature, + msg: Option<&str>) -> Result<(), Error> { + let msg = try!(::opt_cstr(msg)); + unsafe { + try_call!(raw::git_reflog_append(self.raw, new_oid.raw(), + committer.raw(), msg)); + } + Ok(()) + } + + /// Remove an entry from the reflog by its index + /// + /// To ensure there's no gap in the log history, set rewrite_previous_entry + /// param value to `true`. When deleting entry n, member old_oid of entry + /// n-1 (if any) will be updated with the value of member new_oid of entry + /// n+1. + pub fn remove(&mut self, i: usize, rewrite_previous_entry: bool) + -> Result<(), Error> { + unsafe { + try_call!(raw::git_reflog_drop(self.raw, i as size_t, + rewrite_previous_entry)); + } + Ok(()) + } + + /// Lookup an entry by its index + /// + /// Requesting the reflog entry with an index of 0 (zero) will return the + /// most recently created entry. + pub fn get(&self, i: usize) -> Option { + unsafe { + let ptr = raw::git_reflog_entry_byindex(self.raw, i as size_t); + Binding::from_raw_opt(ptr) + } + } + + /// Get the number of log entries in a reflog + pub fn len(&self) -> usize { + unsafe { raw::git_reflog_entrycount(self.raw) as usize } + } + + /// Return `true ` is there is no log entry in a reflog + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get an iterator to all entries inside of this reflog + pub fn iter(&self) -> ReflogIter { + ReflogIter { range: 0..self.len(), reflog: self } + } + + /// Write an existing in-memory reflog object back to disk using an atomic + /// file lock. + pub fn write(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_reflog_write(self.raw)); } + Ok(()) + } +} + +impl Binding for Reflog { + type Raw = *mut raw::git_reflog; + + unsafe fn from_raw(raw: *mut raw::git_reflog) -> Reflog { + Reflog { raw: raw } + } + fn raw(&self) -> *mut raw::git_reflog { self.raw } +} + +impl Drop for Reflog { + fn drop(&mut self) { + unsafe { raw::git_reflog_free(self.raw) } + } +} + +impl<'reflog> ReflogEntry<'reflog> { + /// Get the committer of this entry + pub fn committer(&self) -> Signature { + unsafe { + let ptr = raw::git_reflog_entry_committer(self.raw); + signature::from_raw_const(self, ptr) + } + } + + /// Get the new oid + pub fn id_new(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_reflog_entry_id_new(self.raw)) } + } + + /// Get the old oid + pub fn id_old(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_reflog_entry_id_old(self.raw)) } + } + + /// Get the log message, returning `None` on invalid UTF-8. + pub fn message(&self) -> Option<&str> { + self.message_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the log message as a byte array. + pub fn message_bytes(&self) -> Option<&[u8]> { + unsafe { + ::opt_bytes(self, raw::git_reflog_entry_message(self.raw)) + } + } +} + +impl<'reflog> Binding for ReflogEntry<'reflog> { + type Raw = *const raw::git_reflog_entry; + + unsafe fn from_raw(raw: *const raw::git_reflog_entry) -> ReflogEntry<'reflog> { + ReflogEntry { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *const raw::git_reflog_entry { self.raw } +} + +impl<'reflog> Iterator for ReflogIter<'reflog> { + type Item = ReflogEntry<'reflog>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.reflog.get(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'reflog> DoubleEndedIterator for ReflogIter<'reflog> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.reflog.get(i)) + } +} +impl<'reflog> ExactSizeIterator for ReflogIter<'reflog> {} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let mut reflog = repo.reflog("HEAD").unwrap(); + assert_eq!(reflog.iter().len(), 1); + reflog.write().unwrap(); + + let entry = reflog.iter().next().unwrap(); + assert!(entry.message().is_some()); + + repo.reflog_rename("HEAD", "refs/heads/foo").unwrap(); + repo.reflog_delete("refs/heads/foo").unwrap(); + } +} diff --git a/git2/src/refspec.rs b/git2/src/refspec.rs new file mode 100644 index 000000000..c814d23e5 --- /dev/null +++ b/git2/src/refspec.rs @@ -0,0 +1,89 @@ +use std::ffi::CString; +use std::marker; +use std::str; + +use {raw, Direction}; +use util::Binding; + +/// A structure to represent a git [refspec][1]. +/// +/// Refspecs are currently mainly accessed/created through a `Remote`. +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-The-Refspec +pub struct Refspec<'remote> { + raw: *const raw::git_refspec, + _marker: marker::PhantomData<&'remote raw::git_remote>, +} + +impl<'remote> Refspec<'remote> { + /// Get the refspec's direction. + pub fn direction(&self) -> Direction { + match unsafe { raw::git_refspec_direction(self.raw) } { + raw::GIT_DIRECTION_FETCH => Direction::Fetch, + raw::GIT_DIRECTION_PUSH => Direction::Push, + n => panic!("unknown refspec direction: {}", n), + } + } + + /// Get the destination specifier. + /// + /// If the destination is not utf-8, None is returned. + pub fn dst(&self) -> Option<&str> { + str::from_utf8(self.dst_bytes()).ok() + } + + /// Get the destination specifier, in bytes. + pub fn dst_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_refspec_dst(self.raw)).unwrap() } + } + + /// Check if a refspec's destination descriptor matches a reference + pub fn dst_matches(&self, refname: &str) -> bool { + let refname = CString::new(refname).unwrap(); + unsafe { raw::git_refspec_dst_matches(self.raw, refname.as_ptr()) == 1 } + } + + /// Get the source specifier. + /// + /// If the source is not utf-8, None is returned. + pub fn src(&self) -> Option<&str> { + str::from_utf8(self.src_bytes()).ok() + } + + /// Get the source specifier, in bytes. + pub fn src_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_refspec_src(self.raw)).unwrap() } + } + + /// Check if a refspec's source descriptor matches a reference + pub fn src_matches(&self, refname: &str) -> bool { + let refname = CString::new(refname).unwrap(); + unsafe { raw::git_refspec_src_matches(self.raw, refname.as_ptr()) == 1 } + } + + /// Get the force update setting. + pub fn is_force(&self) -> bool { + unsafe { raw::git_refspec_force(self.raw) == 1 } + } + + /// Get the refspec's string. + /// + /// Returns None if the string is not valid utf8. + pub fn str(&self) -> Option<&str> { + str::from_utf8(self.bytes()).ok() + } + + /// Get the refspec's string as a byte array + pub fn bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_refspec_string(self.raw)).unwrap() } + } +} + +impl<'remote> Binding for Refspec<'remote> { + type Raw = *const raw::git_refspec; + + unsafe fn from_raw(raw: *const raw::git_refspec) -> Refspec<'remote> { + Refspec { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *const raw::git_refspec { self.raw } +} diff --git a/git2/src/remote.rs b/git2/src/remote.rs new file mode 100644 index 000000000..b385a1dfa --- /dev/null +++ b/git2/src/remote.rs @@ -0,0 +1,753 @@ +use std::ffi::CString; +use std::ops::Range; +use std::marker; +use std::mem; +use std::ptr; +use std::slice; +use std::str; +use libc; + +use {raw, Direction, Error, Refspec, Oid, FetchPrune, ProxyOptions}; +use {RemoteCallbacks, Progress, Repository, AutotagOption}; +use string_array::StringArray; +use util::Binding; + +/// A structure representing a [remote][1] of a git repository. +/// +/// [1]: http://git-scm.com/book/en/Git-Basics-Working-with-Remotes +/// +/// The lifetime is the lifetime of the repository that it is attached to. The +/// remote is used to manage fetches and pushes as well as refspecs. +pub struct Remote<'repo> { + raw: *mut raw::git_remote, + _marker: marker::PhantomData<&'repo Repository>, +} + +/// An iterator over the refspecs that a remote contains. +pub struct Refspecs<'remote> { + range: Range, + remote: &'remote Remote<'remote>, +} + +/// Description of a reference advertised bya remote server, given out on calls +/// to `list`. +pub struct RemoteHead<'remote> { + raw: *const raw::git_remote_head, + _marker: marker::PhantomData<&'remote str>, +} + +/// Options which can be specified to various fetch operations. +pub struct FetchOptions<'cb> { + callbacks: Option>, + proxy: Option>, + prune: FetchPrune, + update_fetchhead: bool, + download_tags: AutotagOption, +} + +/// Options to control the behavior of a git push. +pub struct PushOptions<'cb> { + callbacks: Option>, + proxy: Option>, + pb_parallelism: u32, +} + +/// Holds callbacks for a connection to a `Remote`. Disconnects when dropped +pub struct RemoteConnection<'repo, 'connection, 'cb> where 'repo: 'connection { + _callbacks: Box>, + _proxy: ProxyOptions<'cb>, + remote: &'connection mut Remote<'repo>, +} + +pub fn remote_into_raw(remote: Remote) -> *mut raw::git_remote { + let ret = remote.raw; + mem::forget(remote); + return ret +} + +impl<'repo> Remote<'repo> { + /// Ensure the remote name is well-formed. + pub fn is_valid_name(remote_name: &str) -> bool { + ::init(); + let remote_name = CString::new(remote_name).unwrap(); + unsafe { raw::git_remote_is_valid_name(remote_name.as_ptr()) == 1 } + } + + /// Get the remote's name. + /// + /// Returns `None` if this remote has not yet been named or if the name is + /// not valid utf-8 + pub fn name(&self) -> Option<&str> { + self.name_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the remote's name, in bytes. + /// + /// Returns `None` if this remote has not yet been named + pub fn name_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_remote_name(&*self.raw)) } + } + + /// Get the remote's url. + /// + /// Returns `None` if the url is not valid utf-8 + pub fn url(&self) -> Option<&str> { + str::from_utf8(self.url_bytes()).ok() + } + + /// Get the remote's url as a byte array. + pub fn url_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_remote_url(&*self.raw)).unwrap() } + } + + /// Get the remote's pushurl. + /// + /// Returns `None` if the pushurl is not valid utf-8 + pub fn pushurl(&self) -> Option<&str> { + self.pushurl_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the remote's pushurl as a byte array. + pub fn pushurl_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_remote_pushurl(&*self.raw)) } + } + + /// Open a connection to a remote. + pub fn connect(&mut self, dir: Direction) -> Result<(), Error> { + // TODO: can callbacks be exposed safely? + unsafe { + try_call!(raw::git_remote_connect(self.raw, dir, + ptr::null(), + ptr::null(), + ptr::null())); + } + Ok(()) + } + + /// Open a connection to a remote with callbacks and proxy settings + /// + /// Returns a `RemoteConnection` that will disconnect once dropped + pub fn connect_auth<'connection, 'cb>(&'connection mut self, + dir: Direction, + cb: Option>, + proxy_options: Option>) + -> Result, Error> { + + let cb = Box::new(cb.unwrap_or_else(RemoteCallbacks::new)); + let proxy_options = proxy_options.unwrap_or_else(ProxyOptions::new); + unsafe { + try_call!(raw::git_remote_connect(self.raw, dir, + &cb.raw(), + &proxy_options.raw(), + ptr::null())); + } + + Ok(RemoteConnection { + _callbacks: cb, + _proxy: proxy_options, + remote: self, + }) + } + + /// Check whether the remote is connected + pub fn connected(&mut self) -> bool { + unsafe { raw::git_remote_connected(self.raw) == 1 } + } + + /// Disconnect from the remote + pub fn disconnect(&mut self) { + unsafe { raw::git_remote_disconnect(self.raw) } + } + + /// Download and index the packfile + /// + /// Connect to the remote if it hasn't been done yet, negotiate with the + /// remote git which objects are missing, download and index the packfile. + /// + /// The .idx file will be created and both it and the packfile with be + /// renamed to their final name. + /// + /// The `specs` argument is a list of refspecs to use for this negotiation + /// and download. Use an empty array to use the base refspecs. + pub fn download(&mut self, specs: &[&str], opts: Option<&mut FetchOptions>) + -> Result<(), Error> { + let (_a, _b, arr) = try!(::util::iter2cstrs(specs.iter())); + let raw = opts.map(|o| o.raw()); + unsafe { + try_call!(raw::git_remote_download(self.raw, &arr, raw.as_ref())); + } + Ok(()) + } + + /// Get the number of refspecs for a remote + pub fn refspecs<'a>(&'a self) -> Refspecs<'a> { + let cnt = unsafe { raw::git_remote_refspec_count(&*self.raw) as usize }; + Refspecs { range: 0..cnt, remote: self } + } + + /// Get the `nth` refspec from this remote. + /// + /// The `refspecs` iterator can be used to iterate over all refspecs. + pub fn get_refspec(&self, i: usize) -> Option> { + unsafe { + let ptr = raw::git_remote_get_refspec(&*self.raw, + i as libc::size_t); + Binding::from_raw_opt(ptr) + } + } + + /// Download new data and update tips + /// + /// Convenience function to connect to a remote, download the data, + /// disconnect and update the remote-tracking branches. + /// + /// # Examples + /// + /// Example of functionality similar to `git fetch origin/master`: + /// + /// ```no_run + /// fn fetch_origin_master(repo: git2::Repository) -> Result<(), git2::Error> { + /// repo.find_remote("origin")?.fetch(&["master"], None, None) + /// } + /// + /// let repo = git2::Repository::discover("rust").unwrap(); + /// fetch_origin_master(repo).unwrap(); + /// ``` + pub fn fetch(&mut self, + refspecs: &[&str], + opts: Option<&mut FetchOptions>, + reflog_msg: Option<&str>) -> Result<(), Error> { + let (_a, _b, arr) = try!(::util::iter2cstrs(refspecs.iter())); + let msg = try!(::opt_cstr(reflog_msg)); + let raw = opts.map(|o| o.raw()); + unsafe { + try_call!(raw::git_remote_fetch(self.raw, &arr, raw.as_ref(), msg)); + } + Ok(()) + } + + /// Update the tips to the new state + pub fn update_tips(&mut self, + callbacks: Option<&mut RemoteCallbacks>, + update_fetchhead: bool, + download_tags: AutotagOption, + msg: Option<&str>) -> Result<(), Error> { + let msg = try!(::opt_cstr(msg)); + let cbs = callbacks.map(|cb| cb.raw()); + unsafe { + try_call!(raw::git_remote_update_tips(self.raw, cbs.as_ref(), + update_fetchhead, + download_tags, msg)); + } + Ok(()) + } + + /// Perform a push + /// + /// Perform all the steps for a push. If no refspecs are passed then the + /// configured refspecs will be used. + /// + /// Note that you'll likely want to use `RemoteCallbacks` and set + /// `push_update_reference` to test whether all the references were pushed + /// successfully. + pub fn push(&mut self, + refspecs: &[&str], + opts: Option<&mut PushOptions>) -> Result<(), Error> { + let (_a, _b, arr) = try!(::util::iter2cstrs(refspecs.iter())); + let raw = opts.map(|o| o.raw()); + unsafe { + try_call!(raw::git_remote_push(self.raw, &arr, raw.as_ref())); + } + Ok(()) + } + + /// Get the statistics structure that is filled in by the fetch operation. + pub fn stats(&self) -> Progress { + unsafe { + Binding::from_raw(raw::git_remote_stats(self.raw)) + } + } + + /// Get the remote repository's reference advertisement list. + /// + /// Get the list of references with which the server responds to a new + /// connection. + /// + /// The remote (or more exactly its transport) must have connected to the + /// remote repository. This list is available as soon as the connection to + /// the remote is initiated and it remains available after disconnecting. + pub fn list(&self) -> Result<&[RemoteHead], Error> { + let mut size = 0; + let mut base = ptr::null_mut(); + unsafe { + try_call!(raw::git_remote_ls(&mut base, &mut size, self.raw)); + assert_eq!(mem::size_of::(), + mem::size_of::<*const raw::git_remote_head>()); + let slice = slice::from_raw_parts(base as *const _, size as usize); + Ok(mem::transmute::<&[*const raw::git_remote_head], + &[RemoteHead]>(slice)) + } + } + + /// Get the remote's list of fetch refspecs + pub fn fetch_refspecs(&self) -> Result { + unsafe { + let mut raw: raw::git_strarray = mem::zeroed(); + try_call!(raw::git_remote_get_fetch_refspecs(&mut raw, self.raw)); + Ok(StringArray::from_raw(raw)) + } + } + + /// Get the remote's list of push refspecs + pub fn push_refspecs(&self) -> Result { + unsafe { + let mut raw: raw::git_strarray = mem::zeroed(); + try_call!(raw::git_remote_get_push_refspecs(&mut raw, self.raw)); + Ok(StringArray::from_raw(raw)) + } + } +} + +impl<'repo> Clone for Remote<'repo> { + fn clone(&self) -> Remote<'repo> { + let mut ret = ptr::null_mut(); + let rc = unsafe { call!(raw::git_remote_dup(&mut ret, self.raw)) }; + assert_eq!(rc, 0); + Remote { + raw: ret, + _marker: marker::PhantomData, + } + } +} + +impl<'repo> Binding for Remote<'repo> { + type Raw = *mut raw::git_remote; + + unsafe fn from_raw(raw: *mut raw::git_remote) -> Remote<'repo> { + Remote { + raw: raw, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_remote { self.raw } +} + +impl<'repo> Drop for Remote<'repo> { + fn drop(&mut self) { + unsafe { raw::git_remote_free(self.raw) } + } +} + +impl<'repo> Iterator for Refspecs<'repo> { + type Item = Refspec<'repo>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.remote.get_refspec(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'repo> DoubleEndedIterator for Refspecs<'repo> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.remote.get_refspec(i)) + } +} +impl<'repo> ExactSizeIterator for Refspecs<'repo> {} + +#[allow(missing_docs)] // not documented in libgit2 :( +impl<'remote> RemoteHead<'remote> { + /// Flag if this is available locally. + pub fn is_local(&self) -> bool { + unsafe { (*self.raw).local != 0 } + } + + pub fn oid(&self) -> Oid { + unsafe { Binding::from_raw(&(*self.raw).oid as *const _) } + } + pub fn loid(&self) -> Oid { + unsafe { Binding::from_raw(&(*self.raw).loid as *const _) } + } + + pub fn name(&self) -> &str { + let b = unsafe { ::opt_bytes(self, (*self.raw).name).unwrap() }; + str::from_utf8(b).unwrap() + } + + pub fn symref_target(&self) -> Option<&str> { + let b = unsafe { ::opt_bytes(self, (*self.raw).symref_target) }; + b.map(|b| str::from_utf8(b).unwrap()) + } +} + +impl<'cb> Default for FetchOptions<'cb> { + fn default() -> Self { + Self::new() + } +} + +impl<'cb> FetchOptions<'cb> { + /// Creates a new blank set of fetch options + pub fn new() -> FetchOptions<'cb> { + FetchOptions { + callbacks: None, + proxy: None, + prune: FetchPrune::Unspecified, + update_fetchhead: true, + download_tags: AutotagOption::Unspecified, + } + } + + /// Set the callbacks to use for the fetch operation. + pub fn remote_callbacks(&mut self, cbs: RemoteCallbacks<'cb>) -> &mut Self { + self.callbacks = Some(cbs); + self + } + + /// Set the proxy options to use for the fetch operation. + pub fn proxy_options(&mut self, opts: ProxyOptions<'cb>) -> &mut Self { + self.proxy = Some(opts); + self + } + + /// Set whether to perform a prune after the fetch. + pub fn prune(&mut self, prune: FetchPrune) -> &mut Self { + self.prune = prune; + self + } + + /// Set whether to write the results to FETCH_HEAD. + /// + /// Defaults to `true`. + pub fn update_fetchhead(&mut self, update: bool) -> &mut Self { + self.update_fetchhead = update; + self + } + + /// Set how to behave regarding tags on the remote, such as auto-downloading + /// tags for objects we're downloading or downloading all of them. + /// + /// The default is to auto-follow tags. + pub fn download_tags(&mut self, opt: AutotagOption) -> &mut Self { + self.download_tags = opt; + self + } +} + +impl<'cb> Binding for FetchOptions<'cb> { + type Raw = raw::git_fetch_options; + + unsafe fn from_raw(_raw: raw::git_fetch_options) -> FetchOptions<'cb> { + panic!("unimplemented"); + } + fn raw(&self) -> raw::git_fetch_options { + raw::git_fetch_options { + version: 1, + callbacks: self.callbacks.as_ref().map(|m| m.raw()) + .unwrap_or_else(|| RemoteCallbacks::new().raw()), + proxy_opts: self.proxy.as_ref().map(|m| m.raw()) + .unwrap_or_else(|| ProxyOptions::new().raw()), + prune: ::call::convert(&self.prune), + update_fetchhead: ::call::convert(&self.update_fetchhead), + download_tags: ::call::convert(&self.download_tags), + // TODO: expose this as a builder option + custom_headers: raw::git_strarray { + count: 0, + strings: ptr::null_mut(), + }, + } + } +} + + +impl<'cb> Default for PushOptions<'cb> { + fn default() -> Self { + Self::new() + } +} + +impl<'cb> PushOptions<'cb> { + /// Creates a new blank set of push options + pub fn new() -> PushOptions<'cb> { + PushOptions { + callbacks: None, + proxy: None, + pb_parallelism: 1, + } + } + + /// Set the callbacks to use for the fetch operation. + pub fn remote_callbacks(&mut self, cbs: RemoteCallbacks<'cb>) -> &mut Self { + self.callbacks = Some(cbs); + self + } + + /// Set the proxy options to use for the fetch operation. + pub fn proxy_options(&mut self, opts: ProxyOptions<'cb>) -> &mut Self { + self.proxy = Some(opts); + self + } + + /// If the transport being used to push to the remote requires the creation + /// of a pack file, this controls the number of worker threads used by the + /// packbuilder when creating that pack file to be sent to the remote. + /// + /// if set to 0 the packbuilder will auto-detect the number of threads to + /// create, and the default value is 1. + pub fn packbuilder_parallelism(&mut self, parallel: u32) -> &mut Self { + self.pb_parallelism = parallel; + self + } +} + +impl<'cb> Binding for PushOptions<'cb> { + type Raw = raw::git_push_options; + + unsafe fn from_raw(_raw: raw::git_push_options) -> PushOptions<'cb> { + panic!("unimplemented"); + } + fn raw(&self) -> raw::git_push_options { + raw::git_push_options { + version: 1, + callbacks: self.callbacks.as_ref() + .map(|m| m.raw()) + .unwrap_or_else(|| RemoteCallbacks::new().raw()), + proxy_opts: self.proxy.as_ref().map(|m| m.raw()) + .unwrap_or_else(|| ProxyOptions::new().raw()), + pb_parallelism: self.pb_parallelism as libc::c_uint, + // TODO: expose this as a builder option + custom_headers: raw::git_strarray { + count: 0, + strings: ptr::null_mut(), + }, + } + } +} + +impl<'repo, 'connection, 'cb> RemoteConnection<'repo, 'connection, 'cb> { + /// Check whether the remote is (still) connected + pub fn connected(&mut self) -> bool { + self.remote.connected() + } + + /// Get the remote repository's reference advertisement list. + /// + /// This list is available as soon as the connection to + /// the remote is initiated and it remains available after disconnecting. + pub fn list(&self) -> Result<&[RemoteHead], Error> { + self.remote.list() + } +} + +impl<'repo, 'connection, 'cb> Drop for RemoteConnection<'repo, 'connection, 'cb> { + fn drop(&mut self) { + self.remote.disconnect() + } +} + +#[cfg(test)] +mod tests { + use std::cell::Cell; + use tempdir::TempDir; + use {Repository, Remote, RemoteCallbacks, Direction, FetchOptions}; + use {AutotagOption, PushOptions}; + + #[test] + fn smoke() { + let (td, repo) = ::test::repo_init(); + t!(repo.remote("origin", "/path/to/nowhere")); + drop(repo); + + let repo = t!(Repository::init(td.path())); + let origin = t!(repo.find_remote("origin")); + assert_eq!(origin.name(), Some("origin")); + assert_eq!(origin.url(), Some("/path/to/nowhere")); + assert_eq!(origin.pushurl(), None); + + t!(repo.remote_set_url("origin", "/path/to/elsewhere")); + t!(repo.remote_set_pushurl("origin", Some("/path/to/elsewhere"))); + + let stats = origin.stats(); + assert_eq!(stats.total_objects(), 0); + } + + #[test] + fn create_remote() { + let td = TempDir::new("test").unwrap(); + let remote = td.path().join("remote"); + Repository::init_bare(&remote).unwrap(); + + let (_td, repo) = ::test::repo_init(); + let url = if cfg!(unix) { + format!("file://{}", remote.display()) + } else { + format!("file:///{}", remote.display().to_string() + .replace("\\", "/")) + }; + + let mut origin = repo.remote("origin", &url).unwrap(); + assert_eq!(origin.name(), Some("origin")); + assert_eq!(origin.url(), Some(&url[..])); + assert_eq!(origin.pushurl(), None); + + { + let mut specs = origin.refspecs(); + let spec = specs.next().unwrap(); + assert!(specs.next().is_none()); + assert_eq!(spec.str(), Some("+refs/heads/*:refs/remotes/origin/*")); + assert_eq!(spec.dst(), Some("refs/remotes/origin/*")); + assert_eq!(spec.src(), Some("refs/heads/*")); + assert!(spec.is_force()); + } + assert!(origin.refspecs().next_back().is_some()); + { + let remotes = repo.remotes().unwrap(); + assert_eq!(remotes.len(), 1); + assert_eq!(remotes.get(0), Some("origin")); + assert_eq!(remotes.iter().count(), 1); + assert_eq!(remotes.iter().next().unwrap(), Some("origin")); + } + + origin.connect(Direction::Push).unwrap(); + assert!(origin.connected()); + origin.disconnect(); + + origin.connect(Direction::Fetch).unwrap(); + assert!(origin.connected()); + origin.download(&[], None).unwrap(); + origin.disconnect(); + + { + let mut connection = origin.connect_auth(Direction::Push, None, None).unwrap(); + assert!(connection.connected()); + } + assert!(!origin.connected()); + + { + let mut connection = origin.connect_auth(Direction::Fetch, None, None).unwrap(); + assert!(connection.connected()); + } + assert!(!origin.connected()); + + origin.fetch(&[], None, None).unwrap(); + origin.fetch(&[], None, Some("foo")).unwrap(); + origin.update_tips(None, true, AutotagOption::Unspecified, None).unwrap(); + origin.update_tips(None, true, AutotagOption::All, Some("foo")).unwrap(); + + t!(repo.remote_add_fetch("origin", "foo")); + t!(repo.remote_add_fetch("origin", "bar")); + } + + #[test] + fn rename_remote() { + let (_td, repo) = ::test::repo_init(); + repo.remote("origin", "foo").unwrap(); + drop(repo.remote_rename("origin", "foo")); + drop(repo.remote_delete("foo")); + } + + #[test] + fn create_remote_anonymous() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + + let origin = repo.remote_anonymous("/path/to/nowhere").unwrap(); + assert_eq!(origin.name(), None); + drop(origin.clone()); + } + + #[test] + fn is_valid() { + assert!(Remote::is_valid_name("foobar")); + assert!(!Remote::is_valid_name("\x01")); + } + + #[test] + fn transfer_cb() { + let (td, _repo) = ::test::repo_init(); + let td2 = TempDir::new("git").unwrap(); + let url = ::test::path2url(&td.path()); + + let repo = Repository::init(td2.path()).unwrap(); + let progress_hit = Cell::new(false); + { + let mut callbacks = RemoteCallbacks::new(); + let mut origin = repo.remote("origin", &url).unwrap(); + + callbacks.transfer_progress(|_progress| { + progress_hit.set(true); + true + }); + origin.fetch(&[], + Some(FetchOptions::new().remote_callbacks(callbacks)), + None).unwrap(); + + let list = t!(origin.list()); + assert_eq!(list.len(), 2); + assert_eq!(list[0].name(), "HEAD"); + assert!(!list[0].is_local()); + assert_eq!(list[1].name(), "refs/heads/master"); + assert!(!list[1].is_local()); + } + assert!(progress_hit.get()); + } + + /// This test is meant to assure that the callbacks provided to connect will not cause + /// segfaults + #[test] + fn connect_list() { + let (td, _repo) = ::test::repo_init(); + let td2 = TempDir::new("git").unwrap(); + let url = ::test::path2url(&td.path()); + + let repo = Repository::init(td2.path()).unwrap(); + let mut callbacks = RemoteCallbacks::new(); + callbacks.sideband_progress(|_progress| { + // no-op + true + }); + + let mut origin = repo.remote("origin", &url).unwrap(); + + { + let mut connection = origin.connect_auth(Direction::Fetch, Some(callbacks), None).unwrap(); + assert!(connection.connected()); + + let list = t!(connection.list()); + assert_eq!(list.len(), 2); + assert_eq!(list[0].name(), "HEAD"); + assert!(!list[0].is_local()); + assert_eq!(list[1].name(), "refs/heads/master"); + assert!(!list[1].is_local()); + } + assert!(!origin.connected()); + } + + #[test] + fn push() { + let (_td, repo) = ::test::repo_init(); + let td2 = TempDir::new("git1").unwrap(); + let td3 = TempDir::new("git2").unwrap(); + let url = ::test::path2url(&td2.path()); + + Repository::init_bare(td2.path()).unwrap(); + // git push + let mut remote = repo.remote("origin", &url).unwrap(); + let mut updated = false; + { + let mut callbacks = RemoteCallbacks::new(); + callbacks.push_update_reference(|refname, status| { + updated = true; + assert_eq!(refname, "refs/heads/master"); + assert_eq!(status, None); + Ok(()) + }); + let mut options = PushOptions::new(); + options.remote_callbacks(callbacks); + remote.push(&["refs/heads/master"], Some(&mut options)).unwrap(); + } + assert!(updated); + + let repo = Repository::clone(&url, td3.path()).unwrap(); + let commit = repo.head().unwrap().target().unwrap(); + let commit = repo.find_commit(commit).unwrap(); + assert_eq!(commit.message(), Some("initial")); + } +} diff --git a/git2/src/remote_callbacks.rs b/git2/src/remote_callbacks.rs new file mode 100644 index 000000000..562d3a2d6 --- /dev/null +++ b/git2/src/remote_callbacks.rs @@ -0,0 +1,391 @@ +use std::ffi::{CStr, CString}; +use std::marker; +use std::mem; +use std::slice; +use std::ptr; +use std::str; +use libc::{c_void, c_int, c_char, c_uint}; + +use {raw, panic, Error, Cred, CredentialType, Oid}; +use cert::Cert; +use util::Binding; + +/// A structure to contain the callbacks which are invoked when a repository is +/// being updated or downloaded. +/// +/// These callbacks are used to manage facilities such as authentication, +/// transfer progress, etc. +pub struct RemoteCallbacks<'a> { + progress: Option>>, + credentials: Option>>, + sideband_progress: Option>>, + update_tips: Option>>, + certificate_check: Option>>, + push_update_reference: Option>>, +} + +/// Struct representing the progress by an in-flight transfer. +pub struct Progress<'a> { + raw: ProgressState, + _marker: marker::PhantomData<&'a raw::git_transfer_progress>, +} + +enum ProgressState { + Borrowed(*const raw::git_transfer_progress), + Owned(raw::git_transfer_progress), +} + +/// Callback used to acquire credentials for when a remote is fetched. +/// +/// * `url` - the resource for which the credentials are required. +/// * `username_from_url` - the username that was embedded in the url, or `None` +/// if it was not included. +/// * `allowed_types` - a bitmask stating which cred types are ok to return. +pub type Credentials<'a> = FnMut(&str, Option<&str>, CredentialType) + -> Result + 'a; + +/// Callback to be invoked while a transfer is in progress. +/// +/// This callback will be periodically called with updates to the progress of +/// the transfer so far. The return value indicates whether the transfer should +/// continue. A return value of `false` will cancel the transfer. +/// +/// * `progress` - the progress being made so far. +pub type TransferProgress<'a> = FnMut(Progress) -> bool + 'a; + +/// Callback for receiving messages delivered by the transport. +/// +/// The return value indicates whether the network operation should continue. +pub type TransportMessage<'a> = FnMut(&[u8]) -> bool + 'a; + +/// Callback for whenever a reference is updated locally. +pub type UpdateTips<'a> = FnMut(&str, Oid, Oid) -> bool + 'a; + +/// Callback for a custom certificate check. +/// +/// The first argument is the certificate receved on the connection. +/// Certificates are typically either an SSH or X509 certificate. +/// +/// The second argument is the hostname for the connection is passed as the last +/// argument. +pub type CertificateCheck<'a> = FnMut(&Cert, &str) -> bool + 'a; + +/// Callback for each updated reference on push. +/// +/// The first argument here is the `refname` of the reference, and the second is +/// the status message sent by a server. If the status is `Some` then the update +/// was rejected by the remote server with a reason why. +pub type PushUpdateReference<'a> = FnMut(&str, Option<&str>) -> Result<(), Error> + 'a; + +impl<'a> Default for RemoteCallbacks<'a> { + fn default() -> Self { + Self::new() + } +} + +impl<'a> RemoteCallbacks<'a> { + /// Creates a new set of empty callbacks + pub fn new() -> RemoteCallbacks<'a> { + RemoteCallbacks { + credentials: None, + progress: None, + sideband_progress: None, + update_tips: None, + certificate_check: None, + push_update_reference: None, + } + } + + /// The callback through which to fetch credentials if required. + pub fn credentials(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(&str, Option<&str>, CredentialType) + -> Result + 'a + { + self.credentials = Some(Box::new(cb) as Box>); + self + } + + /// The callback through which progress is monitored. + pub fn transfer_progress(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(Progress) -> bool + 'a { + self.progress = Some(Box::new(cb) as Box>); + self + } + + /// Textual progress from the remote. + /// + /// Text sent over the progress side-band will be passed to this function + /// (this is the 'counting objects' output). + pub fn sideband_progress(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(&[u8]) -> bool + 'a { + self.sideband_progress = Some(Box::new(cb) as Box>); + self + } + + /// Each time a reference is updated locally, the callback will be called + /// with information about it. + pub fn update_tips(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(&str, Oid, Oid) -> bool + 'a { + self.update_tips = Some(Box::new(cb) as Box>); + self + } + + /// If certificate verification fails, then this callback will be invoked to + /// let the caller make the final decision of whether to allow the + /// connection to proceed. + pub fn certificate_check(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(&Cert, &str) -> bool + 'a + { + self.certificate_check = Some(Box::new(cb) as Box>); + self + } + + /// Set a callback to get invoked for each updated reference on a push. + /// + /// The first argument to the callback is the name of the reference and the + /// second is a status message sent by the server. If the status is `Some` + /// then the push was rejected. + pub fn push_update_reference(&mut self, cb: F) -> &mut RemoteCallbacks<'a> + where F: FnMut(&str, Option<&str>) -> Result<(), Error> + 'a, + { + self.push_update_reference = Some(Box::new(cb) as Box>); + self + } +} + +impl<'a> Binding for RemoteCallbacks<'a> { + type Raw = raw::git_remote_callbacks; + unsafe fn from_raw(_raw: raw::git_remote_callbacks) -> RemoteCallbacks<'a> { + panic!("unimplemented"); + } + + fn raw(&self) -> raw::git_remote_callbacks { + unsafe { + let mut callbacks: raw::git_remote_callbacks = mem::zeroed(); + assert_eq!(raw::git_remote_init_callbacks(&mut callbacks, + raw::GIT_REMOTE_CALLBACKS_VERSION), 0); + if self.progress.is_some() { + let f: raw::git_transfer_progress_cb = transfer_progress_cb; + callbacks.transfer_progress = Some(f); + } + if self.credentials.is_some() { + let f: raw::git_cred_acquire_cb = credentials_cb; + callbacks.credentials = Some(f); + } + if self.sideband_progress.is_some() { + let f: raw::git_transport_message_cb = sideband_progress_cb; + callbacks.sideband_progress = Some(f); + } + if self.certificate_check.is_some() { + let f: raw::git_transport_certificate_check_cb = + certificate_check_cb; + callbacks.certificate_check = Some(f); + } + if self.push_update_reference.is_some() { + let f: extern fn(_, _, _) -> c_int = push_update_reference_cb; + callbacks.push_update_reference = Some(f); + } + if self.update_tips.is_some() { + let f: extern fn(*const c_char, *const raw::git_oid, + *const raw::git_oid, *mut c_void) -> c_int + = update_tips_cb; + callbacks.update_tips = Some(f); + } + callbacks.payload = self as *const _ as *mut _; + callbacks + } + } +} + +impl<'a> Progress<'a> { + /// Number of objects in the packfile being downloaded + pub fn total_objects(&self) -> usize { + unsafe { (*self.raw()).total_objects as usize } + } + /// Received objects that have been hashed + pub fn indexed_objects(&self) -> usize { + unsafe { (*self.raw()).indexed_objects as usize } + } + /// Objects which have been downloaded + pub fn received_objects(&self) -> usize { + unsafe { (*self.raw()).received_objects as usize } + } + /// Locally-available objects that have been injected in order to fix a thin + /// pack. + pub fn local_objects(&self) -> usize { + unsafe { (*self.raw()).local_objects as usize } + } + /// Number of deltas in the packfile being downloaded + pub fn total_deltas(&self) -> usize { + unsafe { (*self.raw()).total_deltas as usize } + } + /// Received deltas that have been hashed. + pub fn indexed_deltas(&self) -> usize { + unsafe { (*self.raw()).indexed_deltas as usize } + } + /// Size of the packfile received up to now + pub fn received_bytes(&self) -> usize { + unsafe { (*self.raw()).received_bytes as usize } + } + + /// Convert this to an owned version of `Progress`. + pub fn to_owned(&self) -> Progress<'static> { + Progress { + raw: ProgressState::Owned(unsafe { *self.raw() }), + _marker: marker::PhantomData, + } + } +} + +impl<'a> Binding for Progress<'a> { + type Raw = *const raw::git_transfer_progress; + unsafe fn from_raw(raw: *const raw::git_transfer_progress) + -> Progress<'a> { + Progress { + raw: ProgressState::Borrowed(raw), + _marker: marker::PhantomData, + } + } + + fn raw(&self) -> *const raw::git_transfer_progress { + match self.raw { + ProgressState::Borrowed(raw) => raw, + ProgressState::Owned(ref raw) => raw as *const _, + } + } +} + +extern fn credentials_cb(ret: *mut *mut raw::git_cred, + url: *const c_char, + username_from_url: *const c_char, + allowed_types: c_uint, + payload: *mut c_void) -> c_int { + unsafe { + let ok = panic::wrap(|| { + let payload = &mut *(payload as *mut RemoteCallbacks); + let callback = try!(payload.credentials.as_mut() + .ok_or(raw::GIT_PASSTHROUGH as c_int)); + *ret = ptr::null_mut(); + let url = try!(str::from_utf8(CStr::from_ptr(url).to_bytes()) + .map_err(|_| raw::GIT_PASSTHROUGH as c_int)); + let username_from_url = match ::opt_bytes(&url, username_from_url) { + Some(username) => { + Some(try!(str::from_utf8(username) + .map_err(|_| raw::GIT_PASSTHROUGH as c_int))) + } + None => None, + }; + + let cred_type = CredentialType::from_bits_truncate(allowed_types as u32); + + callback(url, username_from_url, cred_type).map_err(|e| { + let s = CString::new(e.to_string()).unwrap(); + raw::giterr_set_str(e.raw_code() as c_int, s.as_ptr()); + e.raw_code() as c_int + }) + }); + match ok { + Some(Ok(cred)) => { + // Turns out it's a memory safety issue if we pass through any + // and all credentials into libgit2 + if allowed_types & (cred.credtype() as c_uint) != 0 { + *ret = cred.unwrap(); + 0 + } else { + raw::GIT_PASSTHROUGH as c_int + } + } + Some(Err(e)) => e, + None => -1, + } + } +} + +extern fn transfer_progress_cb(stats: *const raw::git_transfer_progress, + payload: *mut c_void) -> c_int { + let ok = panic::wrap(|| unsafe { + let payload = &mut *(payload as *mut RemoteCallbacks); + let callback = match payload.progress { + Some(ref mut c) => c, + None => return true, + }; + let progress = Binding::from_raw(stats); + callback(progress) + }); + if ok == Some(true) {0} else {-1} +} + +extern fn sideband_progress_cb(str: *const c_char, + len: c_int, + payload: *mut c_void) -> c_int { + let ok = panic::wrap(|| unsafe { + let payload = &mut *(payload as *mut RemoteCallbacks); + let callback = match payload.sideband_progress { + Some(ref mut c) => c, + None => return true, + }; + let buf = slice::from_raw_parts(str as *const u8, len as usize); + callback(buf) + }); + if ok == Some(true) {0} else {-1} +} + +extern fn update_tips_cb(refname: *const c_char, + a: *const raw::git_oid, + b: *const raw::git_oid, + data: *mut c_void) -> c_int { + let ok = panic::wrap(|| unsafe { + let payload = &mut *(data as *mut RemoteCallbacks); + let callback = match payload.update_tips { + Some(ref mut c) => c, + None => return true, + }; + let refname = str::from_utf8(CStr::from_ptr(refname).to_bytes()) + .unwrap(); + let a = Binding::from_raw(a); + let b = Binding::from_raw(b); + callback(refname, a, b) + }); + if ok == Some(true) {0} else {-1} +} + +extern fn certificate_check_cb(cert: *mut raw::git_cert, + _valid: c_int, + hostname: *const c_char, + data: *mut c_void) -> c_int { + let ok = panic::wrap(|| unsafe { + let payload = &mut *(data as *mut RemoteCallbacks); + let callback = match payload.certificate_check { + Some(ref mut c) => c, + None => return true, + }; + let cert = Binding::from_raw(cert); + let hostname = str::from_utf8(CStr::from_ptr(hostname).to_bytes()) + .unwrap(); + callback(&cert, hostname) + }); + if ok == Some(true) {0} else {-1} +} + +extern fn push_update_reference_cb(refname: *const c_char, + status: *const c_char, + data: *mut c_void) -> c_int { + panic::wrap(|| unsafe { + let payload = &mut *(data as *mut RemoteCallbacks); + let callback = match payload.push_update_reference { + Some(ref mut c) => c, + None => return 0, + }; + let refname = str::from_utf8(CStr::from_ptr(refname).to_bytes()) + .unwrap(); + let status = if status.is_null() { + None + } else { + Some(str::from_utf8(CStr::from_ptr(status).to_bytes()).unwrap()) + }; + match callback(refname, status) { + Ok(()) => 0, + Err(e) => e.raw_code(), + } + }).unwrap_or(-1) +} diff --git a/git2/src/repo.rs b/git2/src/repo.rs new file mode 100644 index 000000000..a3348bd86 --- /dev/null +++ b/git2/src/repo.rs @@ -0,0 +1,2599 @@ +use std::env; +use std::ffi::{CStr, CString, OsStr}; +use std::iter::IntoIterator; +use std::mem; +use std::path::Path; +use std::ptr; +use std::str; +use libc::{c_int, c_char, size_t, c_void, c_uint}; + +use {raw, Revspec, Error, init, Object, RepositoryOpenFlags, RepositoryState, Remote, Buf, StashFlags}; +use {ResetType, Signature, Reference, References, Submodule, Blame, BlameOptions}; +use {Branches, BranchType, Index, Config, Oid, Blob, BlobWriter, Branch, Commit, Tree}; +use {AnnotatedCommit, MergeOptions, SubmoduleIgnore, SubmoduleStatus, MergeAnalysis, MergePreference}; +use {ObjectType, Tag, Note, Notes, StatusOptions, Statuses, Status, Revwalk}; +use {RevparseMode, RepositoryInitMode, Reflog, IntoCString, Describe}; +use {DescribeOptions, TreeBuilder, Diff, DiffOptions, PackBuilder, Odb}; +use {Rebase, RebaseOptions}; +use build::{RepoBuilder, CheckoutBuilder}; +use stash::{StashApplyOptions, StashCbData, stash_cb}; +use string_array::StringArray; +use oid_array::OidArray; +use util::{self, Binding}; + +/// An owned git repository, representing all state associated with the +/// underlying filesystem. +/// +/// This structure corresponds to a `git_repository` in libgit2. Many other +/// types in git2-rs are derivative from this structure and are attached to its +/// lifetime. +/// +/// When a repository goes out of scope it is freed in memory but not deleted +/// from the filesystem. +pub struct Repository { + raw: *mut raw::git_repository, +} + +// It is the current belief that a `Repository` can be sent among threads, or +// even shared among threads in a mutex. +unsafe impl Send for Repository {} + +/// Options which can be used to configure how a repository is initialized +pub struct RepositoryInitOptions { + flags: u32, + mode: u32, + workdir_path: Option, + description: Option, + template_path: Option, + initial_head: Option, + origin_url: Option, +} + +impl Repository { + /// Attempt to open an already-existing repository at `path`. + /// + /// The path can point to either a normal or bare repository. + pub fn open>(path: P) -> Result { + init(); + let path = try!(path.as_ref().into_c_string()); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_open(&mut ret, path)); + Ok(Binding::from_raw(ret)) + } + } + + /// Attempt to open an already-existing bare repository at `path`. + /// + /// The path can point to only a bare repository. + pub fn open_bare>(path: P) -> Result { + init(); + let path = try!(path.as_ref().into_c_string()); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_open_bare(&mut ret, path)); + Ok(Binding::from_raw(ret)) + } + } + + /// Find and open an existing repository, respecting git environment + /// variables. This acts like `open_ext` with the + /// `REPOSITORY_OPEN_FROM_ENV` flag, but additionally respects `$GIT_DIR`. + /// With `$GIT_DIR` unset, this will search for a repository starting in + /// the current directory. + pub fn open_from_env() -> Result { + init(); + let mut ret = ptr::null_mut(); + let flags = raw::GIT_REPOSITORY_OPEN_FROM_ENV; + unsafe { + try_call!(raw::git_repository_open_ext(&mut ret, + ptr::null(), + flags as c_uint, + ptr::null())); + Ok(Binding::from_raw(ret)) + } + } + + /// Find and open an existing repository, with additional options. + /// + /// If flags contains REPOSITORY_OPEN_NO_SEARCH, the path must point + /// directly to a repository; otherwise, this may point to a subdirectory + /// of a repository, and `open_ext` will search up through parent + /// directories. + /// + /// If flags contains REPOSITORY_OPEN_CROSS_FS, the search through parent + /// directories will not cross a filesystem boundary (detected when the + /// stat st_dev field changes). + /// + /// If flags contains REPOSITORY_OPEN_BARE, force opening the repository as + /// bare even if it isn't, ignoring any working directory, and defer + /// loading the repository configuration for performance. + /// + /// If flags contains REPOSITORY_OPEN_NO_DOTGIT, don't try appending + /// `/.git` to `path`. + /// + /// If flags contains REPOSITORY_OPEN_FROM_ENV, `open_ext` will ignore + /// other flags and `ceiling_dirs`, and respect the same environment + /// variables git does. Note, however, that `path` overrides `$GIT_DIR`; to + /// respect `$GIT_DIR` as well, use `open_from_env`. + /// + /// ceiling_dirs specifies a list of paths that the search through parent + /// directories will stop before entering. Use the functions in std::env + /// to construct or manipulate such a path list. + pub fn open_ext(path: P, + flags: RepositoryOpenFlags, + ceiling_dirs: I) + -> Result + where P: AsRef, O: AsRef, I: IntoIterator + { + init(); + let path = try!(path.as_ref().into_c_string()); + let ceiling_dirs_os = try!(env::join_paths(ceiling_dirs)); + let ceiling_dirs = try!(ceiling_dirs_os.into_c_string()); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_open_ext(&mut ret, + path, + flags.bits() as c_uint, + ceiling_dirs)); + Ok(Binding::from_raw(ret)) + } + } + + /// Attempt to open an already-existing repository at or above `path` + /// + /// This starts at `path` and looks up the filesystem hierarchy + /// until it finds a repository. + pub fn discover>(path: P) -> Result { + // TODO: this diverges significantly from the libgit2 API + init(); + let buf = Buf::new(); + let path = try!(path.as_ref().into_c_string()); + unsafe { + try_call!(raw::git_repository_discover(buf.raw(), path, 1, + ptr::null())); + } + Repository::open(util::bytes2path(&*buf)) + } + + /// Creates a new repository in the specified folder. + /// + /// This by default will create any necessary directories to create the + /// repository, and it will read any user-specified templates when creating + /// the repository. This behavior can be configured through `init_opts`. + pub fn init>(path: P) -> Result { + Repository::init_opts(path, &RepositoryInitOptions::new()) + } + + /// Creates a new `--bare` repository in the specified folder. + /// + /// The folder must exist prior to invoking this function. + pub fn init_bare>(path: P) -> Result { + Repository::init_opts(path, RepositoryInitOptions::new().bare(true)) + } + + /// Creates a new repository in the specified folder with the given options. + /// + /// See `RepositoryInitOptions` struct for more information. + pub fn init_opts>(path: P, opts: &RepositoryInitOptions) + -> Result { + init(); + let path = try!(path.as_ref().into_c_string()); + let mut ret = ptr::null_mut(); + unsafe { + let mut opts = opts.raw(); + try_call!(raw::git_repository_init_ext(&mut ret, path, &mut opts)); + Ok(Binding::from_raw(ret)) + } + } + + /// Clone a remote repository. + /// + /// See the `RepoBuilder` struct for more information. This function will + /// delegate to a fresh `RepoBuilder` + pub fn clone>(url: &str, into: P) + -> Result { + ::init(); + RepoBuilder::new().clone(url, into.as_ref()) + } + + /// Clone a remote repository, initialize and update its submodules + /// recursively. + /// + /// This is similar to `git clone --recursive`. + pub fn clone_recurse>(url: &str, into: P) + -> Result { + let repo = Repository::clone(url, into)?; + repo.update_submodules()?; + Ok(repo) + } + + /// Attempt to wrap an object database as a repository. + pub fn from_odb(odb: Odb) -> Result { + init(); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_wrap_odb(&mut ret, odb.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Update submodules recursively. + /// + /// Uninitialized submodules will be initialized. + fn update_submodules(&self) -> Result<(), Error> { + + fn add_subrepos(repo: &Repository, list: &mut Vec) + -> Result<(), Error> { + for mut subm in repo.submodules()? { + subm.update(true, None)?; + list.push(subm.open()?); + } + Ok(()) + } + + let mut repos = Vec::new(); + add_subrepos(self, &mut repos)?; + while let Some(repo) = repos.pop() { + add_subrepos(&repo, &mut repos)?; + } + Ok(()) + } + + /// Execute a rev-parse operation against the `spec` listed. + /// + /// The resulting revision specification is returned, or an error is + /// returned if one occurs. + pub fn revparse(&self, spec: &str) -> Result { + let mut raw = raw::git_revspec { + from: ptr::null_mut(), + to: ptr::null_mut(), + flags: 0, + }; + let spec = try!(CString::new(spec)); + unsafe { + try_call!(raw::git_revparse(&mut raw, self.raw, spec)); + let to = Binding::from_raw_opt(raw.to); + let from = Binding::from_raw_opt(raw.from); + let mode = RevparseMode::from_bits_truncate(raw.flags as u32); + Ok(Revspec::from_objects(from, to, mode)) + } + } + + /// Find a single object, as specified by a revision string. + pub fn revparse_single(&self, spec: &str) -> Result { + let spec = try!(CString::new(spec)); + let mut obj = ptr::null_mut(); + unsafe { + try_call!(raw::git_revparse_single(&mut obj, self.raw, spec)); + assert!(!obj.is_null()); + Ok(Binding::from_raw(obj)) + } + } + + /// Find a single object and intermediate reference by a revision string. + /// + /// See `man gitrevisions`, or + /// http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for + /// information on the syntax accepted. + /// + /// In some cases (`@{<-n>}` or `@{upstream}`), the expression + /// may point to an intermediate reference. When such expressions are being + /// passed in, this intermediate reference is returned. + pub fn revparse_ext(&self, spec: &str) + -> Result<(Object, Option), Error> { + let spec = try!(CString::new(spec)); + let mut git_obj = ptr::null_mut(); + let mut git_ref = ptr::null_mut(); + unsafe { + try_call!(raw::git_revparse_ext(&mut git_obj, &mut git_ref, + self.raw, spec)); + assert!(!git_obj.is_null()); + Ok((Binding::from_raw(git_obj), Binding::from_raw_opt(git_ref))) + } + } + + /// Tests whether this repository is a bare repository or not. + pub fn is_bare(&self) -> bool { + unsafe { raw::git_repository_is_bare(self.raw) == 1 } + } + + /// Tests whether this repository is a shallow clone. + pub fn is_shallow(&self) -> bool { + unsafe { raw::git_repository_is_shallow(self.raw) == 1 } + } + + /// Tests whether this repository is a worktree. + pub fn is_worktree(&self) -> bool { + unsafe { raw::git_repository_is_worktree(self.raw) == 1 } + } + + /// Tests whether this repository is empty. + pub fn is_empty(&self) -> Result { + let empty = unsafe { + try_call!(raw::git_repository_is_empty(self.raw)) + }; + Ok(empty == 1) + } + + /// Returns the path to the `.git` folder for normal repositories or the + /// repository itself for bare repositories. + pub fn path(&self) -> &Path { + unsafe { + let ptr = raw::git_repository_path(self.raw); + util::bytes2path(::opt_bytes(self, ptr).unwrap()) + } + } + + /// Returns the current state of this repository + pub fn state(&self) -> RepositoryState { + let state = unsafe { raw::git_repository_state(self.raw) }; + macro_rules! check( ($($raw:ident => $real:ident),*) => ( + $(if state == raw::$raw as c_int { + super::RepositoryState::$real + }) else * + else { + panic!("unknown repository state: {}", state) + } + ) ); + + check!( + GIT_REPOSITORY_STATE_NONE => Clean, + GIT_REPOSITORY_STATE_MERGE => Merge, + GIT_REPOSITORY_STATE_REVERT => Revert, + GIT_REPOSITORY_STATE_REVERT_SEQUENCE => RevertSequence, + GIT_REPOSITORY_STATE_CHERRYPICK => CherryPick, + GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE => CherryPickSequence, + GIT_REPOSITORY_STATE_BISECT => Bisect, + GIT_REPOSITORY_STATE_REBASE => Rebase, + GIT_REPOSITORY_STATE_REBASE_INTERACTIVE => RebaseInteractive, + GIT_REPOSITORY_STATE_REBASE_MERGE => RebaseMerge, + GIT_REPOSITORY_STATE_APPLY_MAILBOX => ApplyMailbox, + GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE => ApplyMailboxOrRebase + ) + } + + /// Get the path of the working directory for this repository. + /// + /// If this repository is bare, then `None` is returned. + pub fn workdir(&self) -> Option<&Path> { + unsafe { + let ptr = raw::git_repository_workdir(self.raw); + if ptr.is_null() { + None + } else { + Some(util::bytes2path(CStr::from_ptr(ptr).to_bytes())) + } + } + } + + /// Set the path to the working directory for this repository. + /// + /// If `update_link` is true, create/update the gitlink file in the workdir + /// and set config "core.worktree" (if workdir is not the parent of the .git + /// directory). + pub fn set_workdir(&self, path: &Path, update_gitlink: bool) + -> Result<(), Error> { + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_repository_set_workdir(self.raw(), path, + update_gitlink)); + } + Ok(()) + } + + /// Get the currently active namespace for this repository. + /// + /// If there is no namespace, or the namespace is not a valid utf8 string, + /// `None` is returned. + pub fn namespace(&self) -> Option<&str> { + self.namespace_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the currently active namespace for this repository as a byte array. + /// + /// If there is no namespace, `None` is returned. + pub fn namespace_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_repository_get_namespace(self.raw)) } + } + + /// Set the active namespace for this repository. + pub fn set_namespace(&self, namespace: &str) -> Result<(), Error> { + self.set_namespace_bytes(namespace.as_bytes()) + } + + /// Set the active namespace for this repository as a byte array. + pub fn set_namespace_bytes(&self, namespace: &[u8]) -> Result<(), Error> { + unsafe { + let namespace = try!(CString::new(namespace)); + try_call!(raw::git_repository_set_namespace(self.raw, + namespace)); + Ok(()) + } + } + + /// Remove the active namespace for this repository. + pub fn remove_namespace(&self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_repository_set_namespace(self.raw, + ptr::null())); + Ok(()) + } + } + + /// Retrieves the Git merge message. + /// Remember to remove the message when finished. + pub fn message(&self) -> Result { + unsafe { + let buf = Buf::new(); + try_call!(raw::git_repository_message(buf.raw(), self.raw)); + Ok(str::from_utf8(&buf).unwrap().to_string()) + } + } + + /// Remove the Git merge message. + pub fn remove_message(&self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_repository_message_remove(self.raw)); + Ok(()) + } + } + + /// List all remotes for a given repository + pub fn remotes(&self) -> Result { + let mut arr = raw::git_strarray { + strings: 0 as *mut *mut c_char, + count: 0, + }; + unsafe { + try_call!(raw::git_remote_list(&mut arr, self.raw)); + Ok(Binding::from_raw(arr)) + } + } + + /// Get the information for a particular remote + pub fn find_remote(&self, name: &str) -> Result { + let mut ret = ptr::null_mut(); + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_remote_lookup(&mut ret, self.raw, name)); + Ok(Binding::from_raw(ret)) + } + } + + /// Add a remote with the default fetch refspec to the repository's + /// configuration. + pub fn remote(&self, name: &str, url: &str) -> Result { + let mut ret = ptr::null_mut(); + let name = try!(CString::new(name)); + let url = try!(CString::new(url)); + unsafe { + try_call!(raw::git_remote_create(&mut ret, self.raw, name, url)); + Ok(Binding::from_raw(ret)) + } + } + + /// Create an anonymous remote + /// + /// Create a remote with the given url and refspec in memory. You can use + /// this when you have a URL instead of a remote's name. Note that anonymous + /// remotes cannot be converted to persisted remotes. + pub fn remote_anonymous(&self, url: &str) -> Result { + let mut ret = ptr::null_mut(); + let url = try!(CString::new(url)); + unsafe { + try_call!(raw::git_remote_create_anonymous(&mut ret, self.raw, url)); + Ok(Binding::from_raw(ret)) + } + } + + /// Give a remote a new name + /// + /// All remote-tracking branches and configuration settings for the remote + /// are updated. + /// + /// A temporary in-memory remote cannot be given a name with this method. + /// + /// No loaded instances of the remote with the old name will change their + /// name or their list of refspecs. + /// + /// The returned array of strings is a list of the non-default refspecs + /// which cannot be renamed and are returned for further processing by the + /// caller. + pub fn remote_rename(&self, name: &str, + new_name: &str) -> Result { + let name = try!(CString::new(name)); + let new_name = try!(CString::new(new_name)); + let mut problems = raw::git_strarray { + count: 0, + strings: 0 as *mut *mut c_char, + }; + unsafe { + try_call!(raw::git_remote_rename(&mut problems, self.raw, name, + new_name)); + Ok(Binding::from_raw(problems)) + } + } + + /// Delete an existing persisted remote. + /// + /// All remote-tracking branches and configuration settings for the remote + /// will be removed. + pub fn remote_delete(&self, name: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { try_call!(raw::git_remote_delete(self.raw, name)); } + Ok(()) + } + + /// Add a fetch refspec to the remote's configuration + /// + /// Add the given refspec to the fetch list in the configuration. No loaded + /// remote instances will be affected. + pub fn remote_add_fetch(&self, name: &str, spec: &str) + -> Result<(), Error> { + let name = try!(CString::new(name)); + let spec = try!(CString::new(spec)); + unsafe { + try_call!(raw::git_remote_add_fetch(self.raw, name, spec)); + } + Ok(()) + } + + /// Add a push refspec to the remote's configuration. + /// + /// Add the given refspec to the push list in the configuration. No + /// loaded remote instances will be affected. + pub fn remote_add_push(&self, name: &str, spec: &str) + -> Result<(), Error> { + let name = try!(CString::new(name)); + let spec = try!(CString::new(spec)); + unsafe { + try_call!(raw::git_remote_add_push(self.raw, name, spec)); + } + Ok(()) + } + + /// Set the remote's url in the configuration + /// + /// Remote objects already in memory will not be affected. This assumes + /// the common case of a single-url remote and will otherwise return an + /// error. + pub fn remote_set_url(&self, name: &str, url: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + let url = try!(CString::new(url)); + unsafe { try_call!(raw::git_remote_set_url(self.raw, name, url)); } + Ok(()) + } + + /// Set the remote's url for pushing in the configuration. + /// + /// Remote objects already in memory will not be affected. This assumes + /// the common case of a single-url remote and will otherwise return an + /// error. + /// + /// `None` indicates that it should be cleared. + pub fn remote_set_pushurl(&self, name: &str, pushurl: Option<&str>) + -> Result<(), Error> { + let name = try!(CString::new(name)); + let pushurl = try!(::opt_cstr(pushurl)); + unsafe { + try_call!(raw::git_remote_set_pushurl(self.raw, name, pushurl)); + } + Ok(()) + } + + /// Sets the current head to the specified object and optionally resets + /// the index and working tree to match. + /// + /// A soft reset means the head will be moved to the commit. + /// + /// A mixed reset will trigger a soft reset, plus the index will be + /// replaced with the content of the commit tree. + /// + /// A hard reset will trigger a mixed reset and the working directory will + /// be replaced with the content of the index. (Untracked and ignored files + /// will be left alone, however.) + /// + /// The `target` is a commit-ish to which the head should be moved to. The + /// object can either be a commit or a tag, but tags must be dereferenceable + /// to a commit. + /// + /// The `checkout` options will only be used for a hard reset. + pub fn reset(&self, + target: &Object, + kind: ResetType, + checkout: Option<&mut CheckoutBuilder>) + -> Result<(), Error> { + unsafe { + let mut opts: raw::git_checkout_options = mem::zeroed(); + try_call!(raw::git_checkout_init_options(&mut opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION)); + let opts = checkout.map(|c| { + c.configure(&mut opts); &mut opts + }); + try_call!(raw::git_reset(self.raw, target.raw(), kind, opts)); + } + Ok(()) + } + + /// Updates some entries in the index from the target commit tree. + /// + /// The scope of the updated entries is determined by the paths being + /// in the iterator provided. + /// + /// Passing a `None` target will result in removing entries in the index + /// matching the provided pathspecs. + pub fn reset_default(&self, + target: Option<&Object>, + paths: I) -> Result<(), Error> + where T: IntoCString, I: IntoIterator, + { + let (_a, _b, mut arr) = try!(::util::iter2cstrs(paths)); + let target = target.map(|t| t.raw()); + unsafe { + try_call!(raw::git_reset_default(self.raw, target, &mut arr)); + } + Ok(()) + } + + /// Retrieve and resolve the reference pointed at by HEAD. + pub fn head(&self) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_head(&mut ret, self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Make the repository HEAD point to the specified reference. + /// + /// If the provided reference points to a tree or a blob, the HEAD is + /// unaltered and an error is returned. + /// + /// If the provided reference points to a branch, the HEAD will point to + /// that branch, staying attached, or become attached if it isn't yet. If + /// the branch doesn't exist yet, no error will be returned. The HEAD will + /// then be attached to an unborn branch. + /// + /// Otherwise, the HEAD will be detached and will directly point to the + /// commit. + pub fn set_head(&self, refname: &str) -> Result<(), Error> { + let refname = try!(CString::new(refname)); + unsafe { + try_call!(raw::git_repository_set_head(self.raw, refname)); + } + Ok(()) + } + + /// Determines whether the repository HEAD is detached. + pub fn head_detached(&self) -> Result { + unsafe { + let value = raw::git_repository_head_detached(self.raw); + match value { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(Error::last_error(value).unwrap()) + } + } + } + + /// Make the repository HEAD directly point to the commit. + /// + /// If the provided committish cannot be found in the repository, the HEAD + /// is unaltered and an error is returned. + /// + /// If the provided commitish cannot be peeled into a commit, the HEAD is + /// unaltered and an error is returned. + /// + /// Otherwise, the HEAD will eventually be detached and will directly point + /// to the peeled commit. + pub fn set_head_detached(&self, commitish: Oid) -> Result<(), Error> { + unsafe { + try_call!(raw::git_repository_set_head_detached(self.raw, + commitish.raw())); + } + Ok(()) + } + + /// Create an iterator for the repo's references + pub fn references(&self) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_iterator_new(&mut ret, self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Create an iterator for the repo's references that match the specified + /// glob + pub fn references_glob(&self, glob: &str) -> Result { + let mut ret = ptr::null_mut(); + let glob = try!(CString::new(glob)); + unsafe { + try_call!(raw::git_reference_iterator_glob_new(&mut ret, self.raw, + glob)); + + Ok(Binding::from_raw(ret)) + } + } + + /// Load all submodules for this repository and return them. + pub fn submodules(&self) -> Result, Error> { + struct Data<'a, 'b:'a> { + repo: &'b Repository, + ret: &'a mut Vec>, + } + let mut ret = Vec::new(); + + unsafe { + let mut data = Data { + repo: self, + ret: &mut ret, + }; + try_call!(raw::git_submodule_foreach(self.raw, append, + &mut data as *mut _ + as *mut c_void)); + } + + return Ok(ret); + + extern fn append(_repo: *mut raw::git_submodule, + name: *const c_char, + data: *mut c_void) -> c_int { + unsafe { + let data = &mut *(data as *mut Data); + let mut raw = ptr::null_mut(); + let rc = raw::git_submodule_lookup(&mut raw, data.repo.raw(), + name); + assert_eq!(rc, 0); + data.ret.push(Binding::from_raw(raw)); + } + 0 + } + } + + /// Gather file status information and populate the returned structure. + /// + /// Note that if a pathspec is given in the options to filter the + /// status, then the results from rename detection (if you enable it) may + /// not be accurate. To do rename detection properly, this must be called + /// with no pathspec so that all files can be considered. + pub fn statuses(&self, options: Option<&mut StatusOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_status_list_new(&mut ret, self.raw, + options.map(|s| s.raw()) + .unwrap_or(ptr::null()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Test if the ignore rules apply to a given file. + /// + /// This function checks the ignore rules to see if they would apply to the + /// given file. This indicates if the file would be ignored regardless of + /// whether the file is already in the index or committed to the repository. + /// + /// One way to think of this is if you were to do "git add ." on the + /// directory containing the file, would it be added or not? + pub fn status_should_ignore(&self, path: &Path) -> Result { + let mut ret = 0 as c_int; + let path = try!(path.into_c_string()); + unsafe { + try_call!(raw::git_status_should_ignore(&mut ret, self.raw, + path)); + } + Ok(ret != 0) + } + + /// Get file status for a single file. + /// + /// This tries to get status for the filename that you give. If no files + /// match that name (in either the HEAD, index, or working directory), this + /// returns NotFound. + /// + /// If the name matches multiple files (for example, if the path names a + /// directory or if running on a case- insensitive filesystem and yet the + /// HEAD has two entries that both match the path), then this returns + /// Ambiguous because it cannot give correct results. + /// + /// This does not do any sort of rename detection. Renames require a set of + /// targets and because of the path filtering, there is not enough + /// information to check renames correctly. To check file status with rename + /// detection, there is no choice but to do a full `statuses` and scan + /// through looking for the path that you are interested in. + pub fn status_file(&self, path: &Path) -> Result { + let mut ret = 0 as c_uint; + let path = if cfg!(windows) { + // `git_status_file` dose not work with windows path separator + // so we convert \ to / + try!(::std::ffi::CString::new(path.to_string_lossy().replace('\\', "/"))) + } else { + try!(path.into_c_string()) + }; + unsafe { + try_call!(raw::git_status_file(&mut ret, self.raw, + path)); + } + Ok(Status::from_bits_truncate(ret as u32)) + } + + /// Create an iterator which loops over the requested branches. + pub fn branches(&self, filter: Option) + -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_branch_iterator_new(&mut raw, self.raw(), filter)); + Ok(Branches::from_raw(raw)) + } + } + + /// Get the Index file for this repository. + /// + /// If a custom index has not been set, the default index for the repository + /// will be returned (the one located in .git/index). + pub fn index(&self) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_index(&mut raw, self.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Set the Index file for this repository. + pub fn set_index(&self, index: &mut Index) { + unsafe { + raw::git_repository_set_index(self.raw(), index.raw()); + } + } + + /// Get the configuration file for this repository. + /// + /// If a configuration file has not been set, the default config set for the + /// repository will be returned, including global and system configurations + /// (if they are available). + pub fn config(&self) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_config(&mut raw, self.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Write an in-memory buffer to the ODB as a blob. + /// + /// The Oid returned can in turn be passed to `find_blob` to get a handle to + /// the blob. + pub fn blob(&self, data: &[u8]) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + let ptr = data.as_ptr() as *const c_void; + let len = data.len() as size_t; + try_call!(raw::git_blob_create_frombuffer(&mut raw, self.raw(), + ptr, len)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Read a file from the filesystem and write its content to the Object + /// Database as a loose blob + /// + /// The Oid returned can in turn be passed to `find_blob` to get a handle to + /// the blob. + pub fn blob_path(&self, path: &Path) -> Result { + let path = try!(path.into_c_string()); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_blob_create_fromdisk(&mut raw, self.raw(), + path)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Create a stream to write blob + /// + /// This function may need to buffer the data on disk and will in general + /// not be the right choice if you know the size of the data to write. + /// + /// Use `BlobWriter::commit()` to commit the write to the object db + /// and get the object id. + /// + /// If the `hintpath` parameter is filled, it will be used to determine + /// what git filters should be applied to the object before it is written + /// to the object database. + pub fn blob_writer(&self, hintpath: Option<&Path>) -> Result { + let path_str = match hintpath { + Some(path) => Some(try!(path.into_c_string())), + None => None, + }; + let path = match path_str { + Some(ref path) => path.as_ptr(), + None => ptr::null(), + }; + let mut out = ptr::null_mut(); + unsafe { + try_call!(raw::git_blob_create_fromstream(&mut out, self.raw(), path)); + Ok(BlobWriter::from_raw(out)) + } + } + + /// Lookup a reference to one of the objects in a repository. + pub fn find_blob(&self, oid: Oid) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_blob_lookup(&mut raw, self.raw(), oid.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Get the object database for this repository + pub fn odb(&self) -> Result { + let mut odb = ptr::null_mut(); + unsafe { + try_call!(raw::git_repository_odb(&mut odb, self.raw())); + Ok(Odb::from_raw(odb)) + } + } + + /// Create a new branch pointing at a target commit + /// + /// A new direct reference will be created pointing to this target commit. + /// If `force` is true and a reference already exists with the given name, + /// it'll be replaced. + pub fn branch(&self, + branch_name: &str, + target: &Commit, + force: bool) -> Result { + let branch_name = try!(CString::new(branch_name)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_branch_create(&mut raw, + self.raw(), + branch_name, + target.raw(), + force)); + Ok(Branch::wrap(Binding::from_raw(raw))) + } + } + + /// Lookup a branch by its name in a repository. + pub fn find_branch(&self, name: &str, branch_type: BranchType) + -> Result { + let name = try!(CString::new(name)); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_branch_lookup(&mut ret, self.raw(), name, + branch_type)); + Ok(Branch::wrap(Binding::from_raw(ret))) + } + } + + /// Create new commit in the repository + /// + /// If the `update_ref` is not `None`, name of the reference that will be + /// updated to point to this commit. If the reference is not direct, it will + /// be resolved to a direct reference. Use "HEAD" to update the HEAD of the + /// current branch and make it point to this commit. If the reference + /// doesn't exist yet, it will be created. If it does exist, the first + /// parent must be the tip of this branch. + pub fn commit(&self, + update_ref: Option<&str>, + author: &Signature, + committer: &Signature, + message: &str, + tree: &Tree, + parents: &[&Commit]) -> Result { + let update_ref = try!(::opt_cstr(update_ref)); + let mut parent_ptrs = parents.iter().map(|p| { + p.raw() as *const raw::git_commit + }).collect::>(); + let message = try!(CString::new(message)); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_commit_create(&mut raw, + self.raw(), + update_ref, + author.raw(), + committer.raw(), + ptr::null(), + message, + tree.raw(), + parents.len() as size_t, + parent_ptrs.as_mut_ptr())); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Create a commit object from the given buffer and signature + /// + /// Given the unsigned commit object's contents, its signature and the + /// header field in which to store the signature, attach the signature to + /// the commit and write it into the given repository. + /// + /// Use `None` in `signature_field` to use the default of `gpgsig`, which is + /// almost certainly what you want. + /// + /// Returns the resulting (signed) commit id. + pub fn commit_signed(&self, + commit_content: &str, + signature: &str, + signature_field: Option<&str>) -> Result { + let commit_content = try!(CString::new(commit_content)); + let signature = try!(CString::new(signature)); + let signature_field = try!(::opt_cstr(signature_field)); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_commit_create_with_signature(&mut raw, + self.raw(), + commit_content, + signature, + signature_field)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + + /// Extract the signature from a commit + /// + /// Returns a tuple containing the signature in the first value and the + /// signed data in the second. + pub fn extract_signature(&self, + commit_id: &Oid, + signature_field: Option<&str>) + -> Result<(Buf, Buf), Error> { + let signature_field = try!(::opt_cstr(signature_field)); + let signature = Buf::new(); + let content = Buf::new(); + unsafe { + try_call!(raw::git_commit_extract_signature(signature.raw(), + content.raw(), + self.raw(), + commit_id.raw() as *mut _, + signature_field)); + Ok((signature, content)) + } + } + + + /// Lookup a reference to one of the commits in a repository. + pub fn find_commit(&self, oid: Oid) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_commit_lookup(&mut raw, self.raw(), oid.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Creates a `AnnotatedCommit` from the given commit id. + pub fn find_annotated_commit(&self, id: Oid) -> Result { + unsafe { + let mut raw = 0 as *mut raw::git_annotated_commit; + try_call!(raw::git_annotated_commit_lookup(&mut raw, self.raw(), id.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Lookup a reference to one of the objects in a repository. + pub fn find_object(&self, oid: Oid, + kind: Option) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_object_lookup(&mut raw, self.raw(), oid.raw(), + kind)); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new direct reference. + /// + /// This function will return an error if a reference already exists with + /// the given name unless force is true, in which case it will be + /// overwritten. + pub fn reference(&self, name: &str, id: Oid, force: bool, + log_message: &str) -> Result { + let name = try!(CString::new(name)); + let log_message = try!(CString::new(log_message)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_create(&mut raw, self.raw(), name, + id.raw(), force, + log_message)); + Ok(Binding::from_raw(raw)) + } + } + + /// Conditionally create new direct reference. + /// + /// A direct reference (also called an object id reference) refers directly + /// to a specific object id (a.k.a. OID or SHA) in the repository. The id + /// permanently refers to the object (although the reference itself can be + /// moved). For example, in libgit2 the direct ref "refs/tags/v0.17.0" + /// refers to OID 5b9fac39d8a76b9139667c26a63e6b3f204b3977. + /// + /// The direct reference will be created in the repository and written to + /// the disk. + /// + /// Valid reference names must follow one of two patterns: + /// + /// 1. Top-level names must contain only capital letters and underscores, + /// and must begin and end with a letter. (e.g. "HEAD", "ORIG_HEAD"). + /// 2. Names prefixed with "refs/" can be almost anything. You must avoid + /// the characters `~`, `^`, `:`, `\\`, `?`, `[`, and `*`, and the + /// sequences ".." and "@{" which have special meaning to revparse. + /// + /// This function will return an error if a reference already exists with + /// the given name unless `force` is true, in which case it will be + /// overwritten. + /// + /// The message for the reflog will be ignored if the reference does not + /// belong in the standard set (HEAD, branches and remote-tracking + /// branches) and it does not have a reflog. + /// + /// It will return GIT_EMODIFIED if the reference's value at the time of + /// updating does not match the one passed through `current_id` (i.e. if the + /// ref has changed since the user read it). + pub fn reference_matching(&self, + name: &str, + id: Oid, + force: bool, + current_id: Oid, + log_message: &str) -> Result { + let name = try!(CString::new(name)); + let log_message = try!(CString::new(log_message)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_create_matching(&mut raw, + self.raw(), + name, + id.raw(), + force, + current_id.raw(), + log_message)); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new symbolic reference. + /// + /// This function will return an error if a reference already exists with + /// the given name unless force is true, in which case it will be + /// overwritten. + pub fn reference_symbolic(&self, name: &str, target: &str, + force: bool, + log_message: &str) + -> Result { + let name = try!(CString::new(name)); + let target = try!(CString::new(target)); + let log_message = try!(CString::new(log_message)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_symbolic_create(&mut raw, self.raw(), + name, target, force, + log_message)); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new symbolic reference. + /// + /// This function will return an error if a reference already exists with + /// the given name unless force is true, in which case it will be + /// overwritten. + /// + /// It will return GIT_EMODIFIED if the reference's value at the time of + /// updating does not match the one passed through current_value (i.e. if + /// the ref has changed since the user read it). + pub fn reference_symbolic_matching(&self, + name: &str, + target: &str, + force: bool, + current_value: &str, + log_message: &str) + -> Result { + let name = try!(CString::new(name)); + let target = try!(CString::new(target)); + let current_value = try!(CString::new(current_value)); + let log_message = try!(CString::new(log_message)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_symbolic_create_matching(&mut raw, + self.raw(), + name, + target, + force, + current_value, + log_message)); + Ok(Binding::from_raw(raw)) + } + } + + /// Lookup a reference to one of the objects in a repository. + pub fn find_reference(&self, name: &str) -> Result { + let name = try!(CString::new(name)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_reference_lookup(&mut raw, self.raw(), name)); + Ok(Binding::from_raw(raw)) + } + } + + /// Lookup a reference by name and resolve immediately to OID. + /// + /// This function provides a quick way to resolve a reference name straight + /// through to the object id that it refers to. This avoids having to + /// allocate or free any `Reference` objects for simple situations. + pub fn refname_to_id(&self, name: &str) -> Result { + let name = try!(CString::new(name)); + let mut ret = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_reference_name_to_id(&mut ret, self.raw(), name)); + Ok(Binding::from_raw(&ret as *const _)) + } + } + + /// Creates a git_annotated_commit from the given reference. + pub fn reference_to_annotated_commit(&self, reference: &Reference) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_annotated_commit_from_ref(&mut ret, + self.raw(), + reference.raw())); + Ok(AnnotatedCommit::from_raw(ret)) + } + } + + /// Create a new action signature with default user and now timestamp. + /// + /// This looks up the user.name and user.email from the configuration and + /// uses the current time as the timestamp, and creates a new signature + /// based on that information. It will return `NotFound` if either the + /// user.name or user.email are not set. + pub fn signature(&self) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_signature_default(&mut ret, self.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Set up a new git submodule for checkout. + /// + /// This does "git submodule add" up to the fetch and checkout of the + /// submodule contents. It preps a new submodule, creates an entry in + /// `.gitmodules` and creates an empty initialized repository either at the + /// given path in the working directory or in `.git/modules` with a gitlink + /// from the working directory to the new repo. + /// + /// To fully emulate "git submodule add" call this function, then `open()` + /// the submodule repo and perform the clone step as needed. Lastly, call + /// `add_finalize()` to wrap up adding the new submodule and `.gitmodules` + /// to the index to be ready to commit. + pub fn submodule(&self, url: &str, path: &Path, + use_gitlink: bool) -> Result { + let url = try!(CString::new(url)); + let path = try!(path.into_c_string()); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_submodule_add_setup(&mut raw, self.raw(), + url, path, use_gitlink)); + Ok(Binding::from_raw(raw)) + } + } + + /// Lookup submodule information by name or path. + /// + /// Given either the submodule name or path (they are usually the same), + /// this returns a structure describing the submodule. + pub fn find_submodule(&self, name: &str) -> Result { + let name = try!(CString::new(name)); + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_submodule_lookup(&mut raw, self.raw(), name)); + Ok(Binding::from_raw(raw)) + } + } + + /// Get the status for a submodule. + /// + /// This looks at a submodule and tries to determine the status. It + /// will return a combination of the `SubmoduleStatus` values. + pub fn submodule_status(&self, name: &str, ignore: SubmoduleIgnore) + -> Result { + let mut ret = 0; + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_submodule_status(&mut ret, self.raw, name, + ignore)); + } + Ok(SubmoduleStatus::from_bits_truncate(ret as u32)) + } + + /// Lookup a reference to one of the objects in a repository. + pub fn find_tree(&self, oid: Oid) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_tree_lookup(&mut raw, self.raw(), oid.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Create a new TreeBuilder, optionally initialized with the + /// entries of the given Tree. + /// + /// The tree builder can be used to create or modify trees in memory and + /// write them as tree objects to the database. + pub fn treebuilder(&self, tree: Option<&Tree>) -> Result { + unsafe { + let mut ret = ptr::null_mut(); + let tree = match tree { + Some(tree) => tree.raw(), + None => ptr::null_mut(), + }; + try_call!(raw::git_treebuilder_new(&mut ret, self.raw, tree)); + Ok(Binding::from_raw(ret)) + } + } + + + /// Create a new tag in the repository from an object + /// + /// A new reference will also be created pointing to this tag object. If + /// `force` is true and a reference already exists with the given name, + /// it'll be replaced. + /// + /// The message will not be cleaned up. + /// + /// The tag name will be checked for validity. You must avoid the characters + /// '~', '^', ':', ' \ ', '?', '[', and '*', and the sequences ".." and " @ + /// {" which have special meaning to revparse. + pub fn tag(&self, name: &str, target: &Object, + tagger: &Signature, message: &str, + force: bool) -> Result { + let name = try!(CString::new(name)); + let message = try!(CString::new(message)); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_tag_create(&mut raw, self.raw, name, + target.raw(), tagger.raw(), + message, force)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Create a new lightweight tag pointing at a target object + /// + /// A new direct reference will be created pointing to this target object. + /// If force is true and a reference already exists with the given name, + /// it'll be replaced. + pub fn tag_lightweight(&self, + name: &str, + target: &Object, + force: bool) -> Result { + let name = try!(CString::new(name)); + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_tag_create_lightweight(&mut raw, self.raw, name, + target.raw(), force)); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Lookup a tag object from the repository. + pub fn find_tag(&self, id: Oid) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_tag_lookup(&mut raw, self.raw, id.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Delete an existing tag reference. + /// + /// The tag name will be checked for validity, see `tag` for some rules + /// about valid names. + pub fn tag_delete(&self, name: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_tag_delete(self.raw, name)); + Ok(()) + } + } + + /// Get a list with all the tags in the repository. + /// + /// An optional fnmatch pattern can also be specified. + pub fn tag_names(&self, pattern: Option<&str>) -> Result { + let mut arr = raw::git_strarray { + strings: 0 as *mut *mut c_char, + count: 0, + }; + unsafe { + match pattern { + Some(s) => { + let s = try!(CString::new(s)); + try_call!(raw::git_tag_list_match(&mut arr, s, self.raw)); + } + None => { try_call!(raw::git_tag_list(&mut arr, self.raw)); } + } + Ok(Binding::from_raw(arr)) + } + } + + /// Updates files in the index and the working tree to match the content of + /// the commit pointed at by HEAD. + pub fn checkout_head(&self, opts: Option<&mut CheckoutBuilder>) + -> Result<(), Error> { + unsafe { + let mut raw_opts = mem::zeroed(); + try_call!(raw::git_checkout_init_options(&mut raw_opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION)); + if let Some(c) = opts { + c.configure(&mut raw_opts); + } + + try_call!(raw::git_checkout_head(self.raw, &raw_opts)); + } + Ok(()) + } + + /// Updates files in the working tree to match the content of the index. + /// + /// If the index is `None`, the repository's index will be used. + pub fn checkout_index(&self, + index: Option<&mut Index>, + opts: Option<&mut CheckoutBuilder>) -> Result<(), Error> { + unsafe { + let mut raw_opts = mem::zeroed(); + try_call!(raw::git_checkout_init_options(&mut raw_opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION)); + if let Some(c) = opts { + c.configure(&mut raw_opts); + } + + try_call!(raw::git_checkout_index(self.raw, + index.map(|i| &mut *i.raw()), + &raw_opts)); + } + Ok(()) + } + + /// Updates files in the index and working tree to match the content of the + /// tree pointed at by the treeish. + pub fn checkout_tree(&self, + treeish: &Object, + opts: Option<&mut CheckoutBuilder>) -> Result<(), Error> { + unsafe { + let mut raw_opts = mem::zeroed(); + try_call!(raw::git_checkout_init_options(&mut raw_opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION)); + if let Some(c) = opts { + c.configure(&mut raw_opts); + } + + try_call!(raw::git_checkout_tree(self.raw, &*treeish.raw(), + &raw_opts)); + } + Ok(()) + } + + /// Merges the given commit(s) into HEAD, writing the results into the + /// working directory. Any changes are staged for commit and any conflicts + /// are written to the index. Callers should inspect the repository's index + /// after this completes, resolve any conflicts and prepare a commit. + /// + /// For compatibility with git, the repository is put into a merging state. + /// Once the commit is done (or if the uses wishes to abort), you should + /// clear this state by calling git_repository_state_cleanup(). + pub fn merge(&self, + annotated_commits: &[&AnnotatedCommit], + merge_opts: Option<&mut MergeOptions>, + checkout_opts: Option<&mut CheckoutBuilder>) + -> Result<(), Error> + { + unsafe { + let mut raw_checkout_opts = mem::zeroed(); + try_call!(raw::git_checkout_init_options(&mut raw_checkout_opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION)); + if let Some(c) = checkout_opts { + c.configure(&mut raw_checkout_opts); + } + + let mut commit_ptrs = annotated_commits.iter().map(|c| { + c.raw() as *const raw::git_annotated_commit + }).collect::>(); + + try_call!(raw::git_merge(self.raw, + commit_ptrs.as_mut_ptr(), + annotated_commits.len() as size_t, + merge_opts.map(|o| o.raw()) + .unwrap_or(ptr::null()), + &raw_checkout_opts)); + } + Ok(()) + } + + /// Merge two commits, producing an index that reflects the result of + /// the merge. The index may be written as-is to the working directory or + /// checked out. If the index is to be converted to a tree, the caller + /// should resolve any conflicts that arose as part of the merge. + pub fn merge_commits(&self, our_commit: &Commit, their_commit: &Commit, + opts: Option<&MergeOptions>) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_merge_commits(&mut raw, self.raw, + our_commit.raw(), + their_commit.raw(), + opts.map(|o| o.raw()))); + Ok(Binding::from_raw(raw)) + } + } + + /// Merge two trees, producing an index that reflects the result of + /// the merge. The index may be written as-is to the working directory or + /// checked out. If the index is to be converted to a tree, the caller + /// should resolve any conflicts that arose as part of the merge. + pub fn merge_trees(&self, ancestor_tree: &Tree, our_tree: &Tree, + their_tree: &Tree, opts: Option<&MergeOptions>) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_merge_trees(&mut raw, self.raw, ancestor_tree.raw(), + our_tree.raw(), their_tree.raw(), + opts.map(|o| o.raw()))); + Ok(Binding::from_raw(raw)) + } + } + + /// Remove all the metadata associated with an ongoing command like merge, + /// revert, cherry-pick, etc. For example: MERGE_HEAD, MERGE_MSG, etc. + pub fn cleanup_state(&self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_repository_state_cleanup(self.raw)); + } + Ok(()) + } + + /// Analyzes the given branch(es) and determines the opportunities for + /// merging them into the HEAD of the repository. + pub fn merge_analysis(&self, + their_heads: &[&AnnotatedCommit]) + -> Result<(MergeAnalysis, MergePreference), Error> { + unsafe { + let mut raw_merge_analysis = 0 as raw::git_merge_analysis_t; + let mut raw_merge_preference = 0 as raw::git_merge_preference_t; + let mut their_heads = their_heads + .iter() + .map(|v| v.raw() as *const _) + .collect::>(); + try_call!(raw::git_merge_analysis(&mut raw_merge_analysis, + &mut raw_merge_preference, + self.raw, + their_heads.as_mut_ptr() as *mut _, + their_heads.len())); + Ok((MergeAnalysis::from_bits_truncate(raw_merge_analysis as u32), MergePreference::from_bits_truncate(raw_merge_preference as u32))) + } + } + + /// Initializes a rebase operation to rebase the changes in `branch` + /// relative to `upstream` onto another branch. To begin the rebase process, + /// call `next()`. + pub fn rebase(&self, + branch: Option<&AnnotatedCommit>, + upstream: Option<&AnnotatedCommit>, + onto: Option<&AnnotatedCommit>, + opts: Option<&mut RebaseOptions>) -> Result { + + let mut rebase: *mut raw::git_rebase = ptr::null_mut(); + unsafe { + try_call!(raw::git_rebase_init( + &mut rebase, + self.raw(), + branch.map(|c| c.raw()), + upstream.map(|c| c.raw()), + onto.map(|c| c.raw()), + opts.map(|o| o.raw()).unwrap_or(ptr::null()))); + + Ok(Rebase::from_raw(rebase)) + } + } + + /// Opens an existing rebase that was previously started by either an + /// invocation of `rebase()` or by another client. + pub fn open_rebase(&self, opts: Option<&mut RebaseOptions>) -> Result { + let mut rebase: *mut raw::git_rebase = ptr::null_mut(); + unsafe { + try_call!(raw::git_rebase_open(&mut rebase, self.raw(), opts.map(|o| o.raw()).unwrap_or(ptr::null()))); + Ok(Rebase::from_raw(rebase)) + + } + } + + + + /// Add a note for an object + /// + /// The `notes_ref` argument is the canonical name of the reference to use, + /// defaulting to "refs/notes/commits". If `force` is specified then + /// previous notes are overwritten. + pub fn note(&self, + author: &Signature, + committer: &Signature, + notes_ref: Option<&str>, + oid: Oid, + note: &str, + force: bool) -> Result { + let notes_ref = try!(::opt_cstr(notes_ref)); + let note = try!(CString::new(note)); + let mut ret = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_note_create(&mut ret, + self.raw, + notes_ref, + author.raw(), + committer.raw(), + oid.raw(), + note, + force)); + Ok(Binding::from_raw(&ret as *const _)) + } + } + + /// Get the default notes reference for this repository + pub fn note_default_ref(&self) -> Result { + let ret = Buf::new(); + unsafe { + try_call!(raw::git_note_default_ref(ret.raw(), self.raw)); + } + Ok(str::from_utf8(&ret).unwrap().to_string()) + } + + /// Creates a new iterator for notes in this repository. + /// + /// The `notes_ref` argument is the canonical name of the reference to use, + /// defaulting to "refs/notes/commits". + /// + /// The iterator returned yields pairs of (Oid, Oid) where the first element + /// is the id of the note and the second id is the id the note is + /// annotating. + pub fn notes(&self, notes_ref: Option<&str>) -> Result { + let notes_ref = try!(::opt_cstr(notes_ref)); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_note_iterator_new(&mut ret, self.raw, notes_ref)); + Ok(Binding::from_raw(ret)) + } + } + + /// Read the note for an object. + /// + /// The `notes_ref` argument is the canonical name of the reference to use, + /// defaulting to "refs/notes/commits". + /// + /// The id specified is the Oid of the git object to read the note from. + pub fn find_note(&self, notes_ref: Option<&str>, id: Oid) + -> Result { + let notes_ref = try!(::opt_cstr(notes_ref)); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_note_read(&mut ret, self.raw, notes_ref, + id.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Remove the note for an object. + /// + /// The `notes_ref` argument is the canonical name of the reference to use, + /// defaulting to "refs/notes/commits". + /// + /// The id specified is the Oid of the git object to remove the note from. + pub fn note_delete(&self, + id: Oid, + notes_ref: Option<&str>, + author: &Signature, + committer: &Signature) -> Result<(), Error> { + let notes_ref = try!(::opt_cstr(notes_ref)); + unsafe { + try_call!(raw::git_note_remove(self.raw, notes_ref, author.raw(), + committer.raw(), id.raw())); + Ok(()) + } + } + + /// Create a revwalk that can be used to traverse the commit graph. + pub fn revwalk(&self) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_revwalk_new(&mut raw, self.raw())); + Ok(Binding::from_raw(raw)) + } + } + + /// Get the blame for a single file. + pub fn blame_file(&self, path: &Path, opts: Option<&mut BlameOptions>) + -> Result { + let path = try!(path.into_c_string()); + let mut raw = ptr::null_mut(); + + unsafe { + try_call!(raw::git_blame_file(&mut raw, + self.raw(), + path, + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(raw)) + } + } + + /// Find a merge base between two commits + pub fn merge_base(&self, one: Oid, two: Oid) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_merge_base(&mut raw, self.raw, + one.raw(), two.raw())); + Ok(Binding::from_raw(&raw as *const _)) + } + } + + /// Find all merge bases between two commits + pub fn merge_bases(&self, one: Oid, two: Oid) -> Result { + let mut arr = raw::git_oidarray { + ids: ptr::null_mut(), + count: 0, + }; + unsafe { + try_call!(raw::git_merge_bases(&mut arr, self.raw, + one.raw(), two.raw())); + Ok(Binding::from_raw(arr)) + } + } + + /// Count the number of unique commits between two commit objects + /// + /// There is no need for branches containing the commits to have any + /// upstream relationship, but it helps to think of one as a branch and the + /// other as its upstream, the ahead and behind values will be what git + /// would report for the branches. + pub fn graph_ahead_behind(&self, local: Oid, upstream: Oid) + -> Result<(usize, usize), Error> { + unsafe { + let mut ahead: size_t = 0; + let mut behind: size_t = 0; + try_call!(raw::git_graph_ahead_behind(&mut ahead, &mut behind, + self.raw(), local.raw(), + upstream.raw())); + Ok((ahead as usize, behind as usize)) + } + } + + /// Determine if a commit is the descendant of another commit + pub fn graph_descendant_of(&self, commit: Oid, ancestor: Oid) + -> Result { + unsafe { + let rv = try_call!(raw::git_graph_descendant_of(self.raw(), + commit.raw(), + ancestor.raw())); + Ok(rv != 0) + } + } + + /// Read the reflog for the given reference + /// + /// If there is no reflog file for the given reference yet, an empty reflog + /// object will be returned. + pub fn reflog(&self, name: &str) -> Result { + let name = try!(CString::new(name)); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_reflog_read(&mut ret, self.raw, name)); + Ok(Binding::from_raw(ret)) + } + } + + /// Delete the reflog for the given reference + pub fn reflog_delete(&self, name: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { try_call!(raw::git_reflog_delete(self.raw, name)); } + Ok(()) + } + + /// Rename a reflog + /// + /// The reflog to be renamed is expected to already exist. + pub fn reflog_rename(&self, old_name: &str, new_name: &str) + -> Result<(), Error> { + let old_name = try!(CString::new(old_name)); + let new_name = try!(CString::new(new_name)); + unsafe { + try_call!(raw::git_reflog_rename(self.raw, old_name, new_name)); + } + Ok(()) + } + + /// Check if the given reference has a reflog. + pub fn reference_has_log(&self, name: &str) -> Result { + let name = try!(CString::new(name)); + let ret = unsafe { + try_call!(raw::git_reference_has_log(self.raw, name)) + }; + Ok(ret != 0) + } + + /// Ensure that the given reference has a reflog. + pub fn reference_ensure_log(&self, name: &str) -> Result<(), Error> { + let name = try!(CString::new(name)); + unsafe { + try_call!(raw::git_reference_ensure_log(self.raw, name)); + } + Ok(()) + } + + /// Describes a commit + /// + /// Performs a describe operation on the current commit and the worktree. + /// After performing a describe on HEAD, a status is run and description is + /// considered to be dirty if there are. + pub fn describe(&self, opts: &DescribeOptions) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_describe_workdir(&mut ret, self.raw, opts.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff with the difference between two tree objects. + /// + /// This is equivalent to `git diff ` + /// + /// The first tree will be used for the "old_file" side of the delta and the + /// second tree will be used for the "new_file" side of the delta. You can + /// pass `None` to indicate an empty tree, although it is an error to pass + /// `None` for both the `old_tree` and `new_tree`. + pub fn diff_tree_to_tree(&self, + old_tree: Option<&Tree>, + new_tree: Option<&Tree>, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_tree_to_tree(&mut ret, + self.raw(), + old_tree.map(|s| s.raw()), + new_tree.map(|s| s.raw()), + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff between a tree and repository index. + /// + /// This is equivalent to `git diff --cached ` or if you pass + /// the HEAD tree, then like `git diff --cached`. + /// + /// The tree you pass will be used for the "old_file" side of the delta, and + /// the index will be used for the "new_file" side of the delta. + /// + /// If you pass `None` for the index, then the existing index of the `repo` + /// will be used. In this case, the index will be refreshed from disk + /// (if it has changed) before the diff is generated. + /// + /// If the tree is `None`, then it is considered an empty tree. + pub fn diff_tree_to_index(&self, + old_tree: Option<&Tree>, + index: Option<&Index>, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_tree_to_index(&mut ret, + self.raw(), + old_tree.map(|s| s.raw()), + index.map(|s| s.raw()), + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff between two index objects. + /// + /// The first index will be used for the "old_file" side of the delta, and + /// the second index will be used for the "new_file" side of the delta. + pub fn diff_index_to_index(&self, + old_index: &Index, + new_index: &Index, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_index_to_index(&mut ret, + self.raw(), + old_index.raw(), + new_index.raw(), + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff between the repository index and the workdir directory. + /// + /// This matches the `git diff` command. See the note below on + /// `tree_to_workdir` for a discussion of the difference between + /// `git diff` and `git diff HEAD` and how to emulate a `git diff ` + /// using libgit2. + /// + /// The index will be used for the "old_file" side of the delta, and the + /// working directory will be used for the "new_file" side of the delta. + /// + /// If you pass `None` for the index, then the existing index of the `repo` + /// will be used. In this case, the index will be refreshed from disk + /// (if it has changed) before the diff is generated. + pub fn diff_index_to_workdir(&self, + index: Option<&Index>, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_index_to_workdir(&mut ret, + self.raw(), + index.map(|s| s.raw()), + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff between a tree and the working directory. + /// + /// The tree you provide will be used for the "old_file" side of the delta, + /// and the working directory will be used for the "new_file" side. + /// + /// This is not the same as `git diff ` or `git diff-index + /// `. Those commands use information from the index, whereas this + /// function strictly returns the differences between the tree and the files + /// in the working directory, regardless of the state of the index. Use + /// `tree_to_workdir_with_index` to emulate those commands. + /// + /// To see difference between this and `tree_to_workdir_with_index`, + /// consider the example of a staged file deletion where the file has then + /// been put back into the working dir and further modified. The + /// tree-to-workdir diff for that file is 'modified', but `git diff` would + /// show status 'deleted' since there is a staged delete. + /// + /// If `None` is passed for `tree`, then an empty tree is used. + pub fn diff_tree_to_workdir(&self, + old_tree: Option<&Tree>, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_tree_to_workdir(&mut ret, + self.raw(), + old_tree.map(|s| s.raw()), + opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a diff between a tree and the working directory using index data + /// to account for staged deletes, tracked files, etc. + /// + /// This emulates `git diff ` by diffing the tree to the index and + /// the index to the working directory and blending the results into a + /// single diff that includes staged deleted, etc. + pub fn diff_tree_to_workdir_with_index(&self, + old_tree: Option<&Tree>, + opts: Option<&mut DiffOptions>) + -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_diff_tree_to_workdir_with_index(&mut ret, + self.raw(), old_tree.map(|s| s.raw()), opts.map(|s| s.raw()))); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a PackBuilder + pub fn packbuilder(&self) -> Result { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_packbuilder_new(&mut ret, self.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Save the local modifications to a new stash. + pub fn stash_save(&mut self, + stasher: &Signature, + message: &str, + flags: Option) + -> Result { + unsafe { + let mut raw_oid = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + let message = try!(CString::new(message)); + let flags = flags.unwrap_or_else(StashFlags::empty); + try_call!(raw::git_stash_save(&mut raw_oid, + self.raw(), + stasher.raw(), + message, + flags.bits() as c_uint)); + Ok(Binding::from_raw(&raw_oid as *const _)) + } + } + + /// Apply a single stashed state from the stash list. + pub fn stash_apply(&mut self, + index: usize, + opts: Option<&mut StashApplyOptions>) + -> Result<(), Error> { + unsafe { + let opts = opts.map(|opts| opts.raw()); + try_call!(raw::git_stash_apply(self.raw(), index, opts)); + Ok(()) + } + } + + /// Loop over all the stashed states and issue a callback for each one. + /// + /// Return `true` to continue iterating or `false` to stop. + pub fn stash_foreach(&mut self, mut callback: C) -> Result<(), Error> + where C: FnMut(usize, &str, &Oid) -> bool + { + unsafe { + let mut data = StashCbData { callback: &mut callback }; + try_call!(raw::git_stash_foreach(self.raw(), + stash_cb, + &mut data as *mut _ as *mut _)); + Ok(()) + } + } + + /// Remove a single stashed state from the stash list. + pub fn stash_drop(&mut self, index: usize) -> Result<(), Error> { + unsafe { + try_call!(raw::git_stash_drop(self.raw(), index)); + Ok(()) + } + } + + /// Apply a single stashed state from the stash list and remove it from the list if successful. + pub fn stash_pop(&mut self, + index: usize, + opts: Option<&mut StashApplyOptions>) + -> Result<(), Error> { + unsafe { + let opts = opts.map(|opts| opts.raw()); + try_call!(raw::git_stash_pop(self.raw(), index, opts)); + Ok(()) + } + } + + /// Add ignore rules for a repository. + /// + /// The format of the rules is the same one of the .gitignore file. + pub fn add_ignore_rule(&self, rules: &str) -> Result<(), Error> { + let rules = CString::new(rules)?; + unsafe { + try_call!(raw::git_ignore_add_rule(self.raw, rules)); + } + Ok(()) + } + + /// Clear ignore rules that were explicitly added. + pub fn clear_ignore_rules(&self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_ignore_clear_internal_rules(self.raw)); + } + Ok(()) + } + + /// Test if the ignore rules apply to a given path. + pub fn is_path_ignored>(&self, path: P) -> Result { + let path = if cfg!(windows) { + // `git_ignore_path_is_ignored` dose not work with windows path separator + // so we convert \ to / + try!(::std::ffi::CString::new(path.as_ref().to_string_lossy().replace('\\', "/"))) + } else { + try!(path.as_ref().into_c_string()) + }; + let mut ignored: c_int = 0; + unsafe { + try_call!(raw::git_ignore_path_is_ignored(&mut ignored, self.raw, path)); + } + Ok(ignored == 1) + } +} + +impl Binding for Repository { + type Raw = *mut raw::git_repository; + unsafe fn from_raw(ptr: *mut raw::git_repository) -> Repository { + Repository { raw: ptr } + } + fn raw(&self) -> *mut raw::git_repository { self.raw } +} + +impl Drop for Repository { + fn drop(&mut self) { + unsafe { raw::git_repository_free(self.raw) } + } +} + +impl RepositoryInitOptions { + /// Creates a default set of initialization options. + /// + /// By default this will set flags for creating all necessary directories + /// and initializing a directory from the user-configured templates path. + pub fn new() -> RepositoryInitOptions { + RepositoryInitOptions { + flags: raw::GIT_REPOSITORY_INIT_MKDIR as u32 | + raw::GIT_REPOSITORY_INIT_MKPATH as u32 | + raw::GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE as u32, + mode: 0, + workdir_path: None, + description: None, + template_path: None, + initial_head: None, + origin_url: None, + } + } + + /// Create a bare repository with no working directory. + /// + /// Defaults to false. + pub fn bare(&mut self, bare: bool) -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_BARE, bare) + } + + /// Return an error if the repository path appears to already be a git + /// repository. + /// + /// Defaults to false. + pub fn no_reinit(&mut self, enabled: bool) -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_NO_REINIT, enabled) + } + + /// Normally a '/.git/' will be appended to the repo path for non-bare repos + /// (if it is not already there), but passing this flag prevents that + /// behavior. + /// + /// Defaults to false. + pub fn no_dotgit_dir(&mut self, enabled: bool) -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_NO_DOTGIT_DIR, enabled) + } + + /// Make the repo path (and workdir path) as needed. The ".git" directory + /// will always be created regardless of this flag. + /// + /// Defaults to true. + pub fn mkdir(&mut self, enabled: bool) -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_MKDIR, enabled) + } + + /// Recursively make all components of the repo and workdir path sas + /// necessary. + /// + /// Defaults to true. + pub fn mkpath(&mut self, enabled: bool) -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_MKPATH, enabled) + } + + /// Set to one of the `RepositoryInit` constants, or a custom value. + pub fn mode(&mut self, mode: RepositoryInitMode) + -> &mut RepositoryInitOptions { + self.mode = mode.bits(); + self + } + + /// Enable or disable using external templates. + /// + /// If enabled, then the `template_path` option will be queried first, then + /// `init.templatedir` from the global config, and finally + /// `/usr/share/git-core-templates` will be used (if it exists). + /// + /// Defaults to true. + pub fn external_template(&mut self, enabled: bool) + -> &mut RepositoryInitOptions { + self.flag(raw::GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE, enabled) + } + + fn flag(&mut self, flag: raw::git_repository_init_flag_t, on: bool) + -> &mut RepositoryInitOptions { + if on { + self.flags |= flag as u32; + } else { + self.flags &= !(flag as u32); + } + self + } + + /// The path do the working directory. + /// + /// If this is a relative path it will be evaulated relative to the repo + /// path. If this is not the "natural" working directory, a .git gitlink + /// file will be created here linking to the repo path. + pub fn workdir_path(&mut self, path: &Path) -> &mut RepositoryInitOptions { + self.workdir_path = Some(path.into_c_string().unwrap()); + self + } + + /// If set, this will be used to initialize the "description" file in the + /// repository instead of using the template content. + pub fn description(&mut self, desc: &str) -> &mut RepositoryInitOptions { + self.description = Some(CString::new(desc).unwrap()); + self + } + + /// When the `external_template` option is set, this is the first location + /// to check for the template directory. + /// + /// If this is not configured, then the default locations will be searched + /// instead. + pub fn template_path(&mut self, path: &Path) -> &mut RepositoryInitOptions { + self.template_path = Some(path.into_c_string().unwrap()); + self + } + + /// The name of the head to point HEAD at. + /// + /// If not configured, this will be treated as `master` and the HEAD ref + /// will be set to `refs/heads/master`. If this begins with `refs/` it will + /// be used verbatim; otherwise `refs/heads/` will be prefixed + pub fn initial_head(&mut self, head: &str) -> &mut RepositoryInitOptions { + self.initial_head = Some(CString::new(head).unwrap()); + self + } + + /// If set, then after the rest of the repository initialization is + /// completed an `origin` remote will be added pointing to this URL. + pub fn origin_url(&mut self, url: &str) -> &mut RepositoryInitOptions { + self.origin_url = Some(CString::new(url).unwrap()); + self + } + + /// Creates a set of raw init options to be used with + /// `git_repository_init_ext`. + /// + /// This method is unsafe as the returned value may have pointers to the + /// interior of this structure. + pub unsafe fn raw(&self) -> raw::git_repository_init_options { + let mut opts = mem::zeroed(); + assert_eq!(raw::git_repository_init_init_options(&mut opts, + raw::GIT_REPOSITORY_INIT_OPTIONS_VERSION), 0); + opts.flags = self.flags; + opts.mode = self.mode; + opts.workdir_path = ::call::convert(&self.workdir_path); + opts.description = ::call::convert(&self.description); + opts.template_path = ::call::convert(&self.template_path); + opts.initial_head = ::call::convert(&self.initial_head); + opts.origin_url = ::call::convert(&self.origin_url); + opts + } +} + +#[cfg(test)] +mod tests { + use std::ffi::OsStr; + use std::fs; + use std::path::Path; + use tempdir::TempDir; + use {Repository, Oid, ObjectType, ResetType}; + use build::CheckoutBuilder; + + #[test] + fn smoke_init() { + let td = TempDir::new("test").unwrap(); + let path = td.path(); + + let repo = Repository::init(path).unwrap(); + assert!(!repo.is_bare()); + } + + #[test] + fn smoke_init_bare() { + let td = TempDir::new("test").unwrap(); + let path = td.path(); + + let repo = Repository::init_bare(path).unwrap(); + assert!(repo.is_bare()); + assert!(repo.namespace().is_none()); + } + + #[test] + fn smoke_open() { + let td = TempDir::new("test").unwrap(); + let path = td.path(); + Repository::init(td.path()).unwrap(); + let repo = Repository::open(path).unwrap(); + assert!(!repo.is_bare()); + assert!(!repo.is_shallow()); + assert!(repo.is_empty().unwrap()); + assert_eq!(::test::realpath(&repo.path()).unwrap(), + ::test::realpath(&td.path().join(".git/")).unwrap()); + assert_eq!(repo.state(), ::RepositoryState::Clean); + } + + #[test] + fn smoke_open_bare() { + let td = TempDir::new("test").unwrap(); + let path = td.path(); + Repository::init_bare(td.path()).unwrap(); + + let repo = Repository::open(path).unwrap(); + assert!(repo.is_bare()); + assert_eq!(::test::realpath(&repo.path()).unwrap(), + ::test::realpath(&td.path().join("")).unwrap()); + } + + #[test] + fn smoke_checkout() { + let (_td, repo) = ::test::repo_init(); + repo.checkout_head(None).unwrap(); + } + + #[test] + fn smoke_revparse() { + let (_td, repo) = ::test::repo_init(); + let rev = repo.revparse("HEAD").unwrap(); + assert!(rev.to().is_none()); + let from = rev.from().unwrap(); + assert!(rev.from().is_some()); + + assert_eq!(repo.revparse_single("HEAD").unwrap().id(), from.id()); + let obj = repo.find_object(from.id(), None).unwrap().clone(); + obj.peel(ObjectType::Any).unwrap(); + obj.short_id().unwrap(); + repo.reset(&obj, ResetType::Hard, None).unwrap(); + let mut opts = CheckoutBuilder::new(); + t!(repo.reset(&obj, ResetType::Soft, Some(&mut opts))); + } + + #[test] + fn makes_dirs() { + let td = TempDir::new("foo").unwrap(); + Repository::init(&td.path().join("a/b/c/d")).unwrap(); + } + + #[test] + fn smoke_discover() { + let td = TempDir::new("test").unwrap(); + let subdir = td.path().join("subdi"); + fs::create_dir(&subdir).unwrap(); + Repository::init_bare(td.path()).unwrap(); + let repo = Repository::discover(&subdir).unwrap(); + assert_eq!(::test::realpath(&repo.path()).unwrap(), + ::test::realpath(&td.path().join("")).unwrap()); + } + + #[test] + fn smoke_open_ext() { + let td = TempDir::new("test").unwrap(); + let subdir = td.path().join("subdir"); + fs::create_dir(&subdir).unwrap(); + Repository::init(td.path()).unwrap(); + + let repo = Repository::open_ext(&subdir, ::RepositoryOpenFlags::empty(), &[] as &[&OsStr]).unwrap(); + assert!(!repo.is_bare()); + assert_eq!(::test::realpath(&repo.path()).unwrap(), + ::test::realpath(&td.path().join(".git")).unwrap()); + + let repo = Repository::open_ext(&subdir, ::RepositoryOpenFlags::BARE, &[] as &[&OsStr]).unwrap(); + assert!(repo.is_bare()); + assert_eq!(::test::realpath(&repo.path()).unwrap(), + ::test::realpath(&td.path().join(".git")).unwrap()); + + let err = Repository::open_ext(&subdir, ::RepositoryOpenFlags::NO_SEARCH, &[] as &[&OsStr]).err().unwrap(); + assert_eq!(err.code(), ::ErrorCode::NotFound); + + assert!(Repository::open_ext(&subdir, + ::RepositoryOpenFlags::empty(), + &[&subdir]).is_ok()); + } + + fn graph_repo_init() -> (TempDir, Repository) { + let (_td, repo) = ::test::repo_init(); + { + let head = repo.head().unwrap().target().unwrap(); + let head = repo.find_commit(head).unwrap(); + + let mut index = repo.index().unwrap(); + let id = index.write_tree().unwrap(); + + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, "second", + &tree, &[&head]).unwrap(); + } + (_td, repo) + } + + #[test] + fn smoke_graph_ahead_behind() { + let (_td, repo) = graph_repo_init(); + let head = repo.head().unwrap().target().unwrap(); + let head = repo.find_commit(head).unwrap(); + let head_id = head.id(); + let head_parent_id = head.parent(0).unwrap().id(); + let (ahead, behind) = repo.graph_ahead_behind(head_id, + head_parent_id).unwrap(); + assert_eq!(ahead, 1); + assert_eq!(behind, 0); + let (ahead, behind) = repo.graph_ahead_behind(head_parent_id, + head_id).unwrap(); + assert_eq!(ahead, 0); + assert_eq!(behind, 1); + } + + #[test] + fn smoke_graph_descendant_of() { + let (_td, repo) = graph_repo_init(); + let head = repo.head().unwrap().target().unwrap(); + let head = repo.find_commit(head).unwrap(); + let head_id = head.id(); + let head_parent_id = head.parent(0).unwrap().id(); + assert!(repo.graph_descendant_of(head_id, head_parent_id).unwrap()); + assert!(!repo.graph_descendant_of(head_parent_id, head_id).unwrap()); + } + + #[test] + fn smoke_reference_has_log_ensure_log() { + let (_td, repo) = ::test::repo_init(); + + assert_eq!(repo.reference_has_log("HEAD").unwrap(), true); + assert_eq!(repo.reference_has_log("refs/heads/master").unwrap(), true); + assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), false); + let master_oid = repo.revparse_single("master").unwrap().id(); + assert!(repo.reference("NOT_HEAD", master_oid, false, "creating a new branch").is_ok()); + assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), false); + assert!(repo.reference_ensure_log("NOT_HEAD").is_ok()); + assert_eq!(repo.reference_has_log("NOT_HEAD").unwrap(), true); + } + + #[test] + fn smoke_set_head() { + let (_td, repo) = ::test::repo_init(); + + assert!(repo.set_head("refs/heads/does-not-exist").is_ok()); + assert!(repo.head().is_err()); + + assert!(repo.set_head("refs/heads/master").is_ok()); + assert!(repo.head().is_ok()); + + assert!(repo.set_head("*").is_err()); + } + + #[test] + fn smoke_set_head_detached() { + let (_td, repo) = ::test::repo_init(); + + let void_oid = Oid::from_bytes(b"00000000000000000000").unwrap(); + assert!(repo.set_head_detached(void_oid).is_err()); + + let master_oid = repo.revparse_single("master").unwrap().id(); + assert!(repo.set_head_detached(master_oid).is_ok()); + assert_eq!(repo.head().unwrap().target().unwrap(), master_oid); + } + + /// create an octopus: + /// /---o2-o4 + /// o1 X + /// \---o3-o5 + /// and checks that the merge bases of (o4,o5) are (o2,o3) + #[test] + fn smoke_merge_bases() { + let (_td, repo) = graph_repo_init(); + let sig = repo.signature().unwrap(); + + // let oid1 = head + let oid1 = repo.head().unwrap().target().unwrap(); + let commit1 = repo.find_commit(oid1).unwrap(); + println!("created oid1 {:?}", oid1); + + repo.branch("branch_a", &commit1, true).unwrap(); + repo.branch("branch_b", &commit1, true).unwrap(); + + // create commit oid2 on branchA + let mut index = repo.index().unwrap(); + let p = Path::new(repo.workdir().unwrap()).join("file_a"); + println!("using path {:?}", p); + fs::File::create(&p).unwrap(); + index.add_path(Path::new("file_a")).unwrap(); + let id_a = index.write_tree().unwrap(); + let tree_a = repo.find_tree(id_a).unwrap(); + let oid2 = repo.commit(Some("refs/heads/branch_a"), &sig, &sig, + "commit 2", &tree_a, &[&commit1]).unwrap(); + let commit2 = repo.find_commit(oid2).unwrap(); + println!("created oid2 {:?}", oid2); + + t!(repo.reset(commit1.as_object(), ResetType::Hard, None)); + + // create commit oid3 on branchB + let mut index = repo.index().unwrap(); + let p = Path::new(repo.workdir().unwrap()).join("file_b"); + fs::File::create(&p).unwrap(); + index.add_path(Path::new("file_b")).unwrap(); + let id_b = index.write_tree().unwrap(); + let tree_b = repo.find_tree(id_b).unwrap(); + let oid3 = repo.commit(Some("refs/heads/branch_b"), &sig, &sig, + "commit 3", &tree_b, &[&commit1]).unwrap(); + let commit3 = repo.find_commit(oid3).unwrap(); + println!("created oid3 {:?}", oid3); + + // create merge commit oid4 on branchA with parents oid2 and oid3 + //let mut index4 = repo.merge_commits(&commit2, &commit3, None).unwrap(); + repo.set_head("refs/heads/branch_a").unwrap(); + repo.checkout_head(None).unwrap(); + let oid4 = repo.commit(Some("refs/heads/branch_a"), &sig, &sig, + "commit 4", &tree_a, + &[&commit2, &commit3]).unwrap(); + //index4.write_tree_to(&repo).unwrap(); + println!("created oid4 {:?}", oid4); + + // create merge commit oid5 on branchB with parents oid2 and oid3 + //let mut index5 = repo.merge_commits(&commit3, &commit2, None).unwrap(); + repo.set_head("refs/heads/branch_b").unwrap(); + repo.checkout_head(None).unwrap(); + let oid5 = repo.commit(Some("refs/heads/branch_b"), &sig, &sig, + "commit 5", &tree_a, + &[&commit3, &commit2]).unwrap(); + //index5.write_tree_to(&repo).unwrap(); + println!("created oid5 {:?}", oid5); + + // merge bases of (oid4,oid5) should be (oid2,oid3) + let merge_bases = repo.merge_bases(oid4, oid5).unwrap(); + let mut found_oid2 = false; + let mut found_oid3 = false; + for mg in merge_bases.iter() { + println!("found merge base {:?}", mg); + if mg == &oid2 { + found_oid2 = true; + } else if mg == &oid3 { + found_oid3 = true; + } else { + assert!(false); + } + } + assert!(found_oid2); + assert!(found_oid3); + assert_eq!(merge_bases.len(), 2); + } + + #[test] + fn smoke_revparse_ext() { + let (_td, repo) = graph_repo_init(); + + { + let short_refname = "master"; + let expected_refname = "refs/heads/master"; + let (obj, reference) = repo.revparse_ext(short_refname).unwrap(); + let expected_obj = repo.revparse_single(expected_refname).unwrap(); + assert_eq!(obj.id(), expected_obj.id()); + assert_eq!(reference.unwrap().name().unwrap(), expected_refname); + } + { + let missing_refname = "refs/heads/does-not-exist"; + assert!(repo.revparse_ext(missing_refname).is_err()); + } + { + let (_obj, reference) = repo.revparse_ext("HEAD^").unwrap(); + assert!(reference.is_none()); + } + } + + #[test] + fn smoke_is_path_ignored() { + let (_td, repo) = graph_repo_init(); + + assert!(!repo.is_path_ignored(Path::new("/foo")).unwrap()); + + let _ = repo.add_ignore_rule("/foo"); + assert!(repo.is_path_ignored(Path::new("/foo")).unwrap()); + if cfg!(windows){ + assert!(repo.is_path_ignored(Path::new("\\foo\\thing")).unwrap()); + } + + + let _ = repo.clear_ignore_rules(); + assert!(!repo.is_path_ignored(Path::new("/foo")).unwrap()); + if cfg!(windows){ + assert!(!repo.is_path_ignored(Path::new("\\foo\\thing")).unwrap()); + } + } +} diff --git a/git2/src/revspec.rs b/git2/src/revspec.rs new file mode 100644 index 000000000..eb18492ef --- /dev/null +++ b/git2/src/revspec.rs @@ -0,0 +1,26 @@ +use {Object, RevparseMode}; + +/// A revspec represents a range of revisions within a repository. +pub struct Revspec<'repo> { + from: Option>, + to: Option>, + mode: RevparseMode, +} + +impl<'repo> Revspec<'repo> { + /// Assembles a new revspec from the from/to components. + pub fn from_objects(from: Option>, + to: Option>, + mode: RevparseMode) -> Revspec<'repo> { + Revspec { from: from, to: to, mode: mode } + } + + /// Access the `from` range of this revspec. + pub fn from(&self) -> Option<&Object<'repo>> { self.from.as_ref() } + + /// Access the `to` range of this revspec. + pub fn to(&self) -> Option<&Object<'repo>> { self.to.as_ref() } + + /// Returns the intent of the revspec. + pub fn mode(&self) -> RevparseMode { self.mode } +} diff --git a/git2/src/revwalk.rs b/git2/src/revwalk.rs new file mode 100644 index 000000000..1e661db52 --- /dev/null +++ b/git2/src/revwalk.rs @@ -0,0 +1,203 @@ +use std::marker; +use std::ffi::CString; +use libc::c_uint; + +use {raw, Error, Sort, Oid, Repository}; +use util::Binding; + +/// A revwalk allows traversal of the commit graph defined by including one or +/// more leaves and excluding one or more roots. +pub struct Revwalk<'repo> { + raw: *mut raw::git_revwalk, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> Revwalk<'repo> { + /// Reset a revwalk to allow re-configuring it. + /// + /// The revwalk is automatically reset when iteration of its commits + /// completes. + pub fn reset(&mut self) { + unsafe { raw::git_revwalk_reset(self.raw()) } + } + + /// Set the order in which commits are visited. + pub fn set_sorting(&mut self, sort_mode: Sort) { + unsafe { + raw::git_revwalk_sorting(self.raw(), sort_mode.bits() as c_uint) + } + } + + /// Simplify the history by first-parent + /// + /// No parents other than the first for each commit will be enqueued. + pub fn simplify_first_parent(&mut self) { + unsafe { raw::git_revwalk_simplify_first_parent(self.raw) } + } + + /// Mark a commit to start traversal from. + /// + /// The given OID must belong to a committish on the walked repository. + /// + /// The given commit will be used as one of the roots when starting the + /// revision walk. At least one commit must be pushed onto the walker before + /// a walk can be started. + pub fn push(&mut self, oid: Oid) -> Result<(), Error> { + unsafe { + try_call!(raw::git_revwalk_push(self.raw(), oid.raw())); + } + Ok(()) + } + + /// Push the repository's HEAD + /// + /// For more information, see `push`. + pub fn push_head(&mut self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_revwalk_push_head(self.raw())); + } + Ok(()) + } + + /// Push matching references + /// + /// The OIDs pointed to by the references that match the given glob pattern + /// will be pushed to the revision walker. + /// + /// A leading 'refs/' is implied if not present as well as a trailing `/ \ + /// *` if the glob lacks '?', ' \ *' or '['. + /// + /// Any references matching this glob which do not point to a committish + /// will be ignored. + pub fn push_glob(&mut self, glob: &str) -> Result<(), Error> { + let glob = try!(CString::new(glob)); + unsafe { + try_call!(raw::git_revwalk_push_glob(self.raw, glob)); + } + Ok(()) + } + + /// Push and hide the respective endpoints of the given range. + /// + /// The range should be of the form `..` where each + /// `` is in the form accepted by `revparse_single`. The left-hand + /// commit will be hidden and the right-hand commit pushed. + pub fn push_range(&mut self, range: &str) -> Result<(), Error> { + let range = try!(CString::new(range)); + unsafe { + try_call!(raw::git_revwalk_push_range(self.raw, range)); + } + Ok(()) + } + + /// Push the OID pointed to by a reference + /// + /// The reference must point to a committish. + pub fn push_ref(&mut self, reference: &str) -> Result<(), Error> { + let reference = try!(CString::new(reference)); + unsafe { + try_call!(raw::git_revwalk_push_ref(self.raw, reference)); + } + Ok(()) + } + + /// Mark a commit as not of interest to this revwalk. + pub fn hide(&mut self, oid: Oid) -> Result<(), Error> { + unsafe { + try_call!(raw::git_revwalk_hide(self.raw(), oid.raw())); + } + Ok(()) + } + + /// Hide the repository's HEAD + /// + /// For more information, see `hide`. + pub fn hide_head(&mut self) -> Result<(), Error> { + unsafe { + try_call!(raw::git_revwalk_hide_head(self.raw())); + } + Ok(()) + } + + /// Hide matching references. + /// + /// The OIDs pointed to by the references that match the given glob pattern + /// and their ancestors will be hidden from the output on the revision walk. + /// + /// A leading 'refs/' is implied if not present as well as a trailing `/ \ + /// *` if the glob lacks '?', ' \ *' or '['. + /// + /// Any references matching this glob which do not point to a committish + /// will be ignored. + pub fn hide_glob(&mut self, glob: &str) -> Result<(), Error> { + let glob = try!(CString::new(glob)); + unsafe { + try_call!(raw::git_revwalk_hide_glob(self.raw, glob)); + } + Ok(()) + } + + /// Hide the OID pointed to by a reference. + /// + /// The reference must point to a committish. + pub fn hide_ref(&mut self, reference: &str) -> Result<(), Error> { + let reference = try!(CString::new(reference)); + unsafe { + try_call!(raw::git_revwalk_hide_ref(self.raw, reference)); + } + Ok(()) + } +} + +impl<'repo> Binding for Revwalk<'repo> { + type Raw = *mut raw::git_revwalk; + unsafe fn from_raw(raw: *mut raw::git_revwalk) -> Revwalk<'repo> { + Revwalk { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_revwalk { self.raw } +} + +impl<'repo> Drop for Revwalk<'repo> { + fn drop(&mut self) { + unsafe { raw::git_revwalk_free(self.raw) } + } +} + +impl<'repo> Iterator for Revwalk<'repo> { + type Item = Result; + fn next(&mut self) -> Option> { + let mut out: raw::git_oid = raw::git_oid{ id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call_iter!(raw::git_revwalk_next(&mut out, self.raw())); + Some(Ok(Binding::from_raw(&out as *const _))) + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + + let mut walk = repo.revwalk().unwrap(); + walk.push(target).unwrap(); + + let oids: Vec<::Oid> = walk.by_ref().collect::, _>>() + .unwrap(); + + assert_eq!(oids.len(), 1); + assert_eq!(oids[0], target); + + walk.reset(); + walk.push_head().unwrap(); + assert_eq!(walk.by_ref().count(), 1); + + walk.reset(); + walk.push_head().unwrap(); + walk.hide_head().unwrap(); + assert_eq!(walk.by_ref().count(), 0); + } +} diff --git a/git2/src/signature.rs b/git2/src/signature.rs new file mode 100644 index 000000000..61e7a8948 --- /dev/null +++ b/git2/src/signature.rs @@ -0,0 +1,175 @@ +use std::ffi::CString; +use std::marker; +use std::mem; +use std::ptr; +use std::str; +use std::fmt; +use libc; + +use {raw, Error, Time}; +use util::Binding; + +/// A Signature is used to indicate authorship of various actions throughout the +/// library. +/// +/// Signatures contain a name, email, and timestamp. All fields can be specified +/// with `new` while the `now` constructor omits the timestamp. The +/// [`Repository::signature`] method can be used to create a default signature +/// with name and email values read from the configuration. +/// +/// [`Repository::signature`]: struct.Repository.html#method.signature +pub struct Signature<'a> { + raw: *mut raw::git_signature, + _marker: marker::PhantomData<&'a str>, + owned: bool, +} + +impl<'a> Signature<'a> { + /// Create a new action signature with a timestamp of 'now'. + /// + /// See `new` for more information + pub fn now(name: &str, email: &str) -> Result, Error> { + ::init(); + let mut ret = ptr::null_mut(); + let name = try!(CString::new(name)); + let email = try!(CString::new(email)); + unsafe { + try_call!(raw::git_signature_now(&mut ret, name, email)); + Ok(Binding::from_raw(ret)) + } + } + + /// Create a new action signature. + /// + /// The `time` specified is in seconds since the epoch, and the `offset` is + /// the time zone offset in minutes. + /// + /// Returns error if either `name` or `email` contain angle brackets. + pub fn new(name: &str, email: &str, time: &Time) + -> Result, Error> { + ::init(); + let mut ret = ptr::null_mut(); + let name = try!(CString::new(name)); + let email = try!(CString::new(email)); + unsafe { + try_call!(raw::git_signature_new(&mut ret, name, email, + time.seconds() as raw::git_time_t, + time.offset_minutes() as libc::c_int)); + Ok(Binding::from_raw(ret)) + } + } + + /// Gets the name on the signature. + /// + /// Returns `None` if the name is not valid utf-8 + pub fn name(&self) -> Option<&str> { + str::from_utf8(self.name_bytes()).ok() + } + + /// Gets the name on the signature as a byte slice. + pub fn name_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, (*self.raw).name).unwrap() } + } + + /// Gets the email on the signature. + /// + /// Returns `None` if the email is not valid utf-8 + pub fn email(&self) -> Option<&str> { + str::from_utf8(self.email_bytes()).ok() + } + + /// Gets the email on the signature as a byte slice. + pub fn email_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, (*self.raw).email).unwrap() } + } + + /// Get the `when` of this signature. + pub fn when(&self) -> Time { + unsafe { Binding::from_raw((*self.raw).when) } + } + + /// Convert a signature of any lifetime into an owned signature with a + /// static lifetime. + pub fn to_owned(&self) -> Signature<'static> { + unsafe { + let me = mem::transmute::<&Signature<'a>, &Signature<'static>>(self); + me.clone() + } + } +} + +impl<'a> Binding for Signature<'a> { + type Raw = *mut raw::git_signature; + unsafe fn from_raw(raw: *mut raw::git_signature) -> Signature<'a> { + Signature { + raw: raw, + _marker: marker::PhantomData, + owned: true, + } + } + fn raw(&self) -> *mut raw::git_signature { self.raw } +} + +/// Creates a new signature from the give raw pointer, tied to the lifetime +/// of the given object. +/// +/// This function is unsafe as there is no guarantee that `raw` is valid for +/// `'a` nor if it's a valid pointer. +pub unsafe fn from_raw_const<'b, T>(_lt: &'b T, + raw: *const raw::git_signature) + -> Signature<'b> { + Signature { + raw: raw as *mut raw::git_signature, + _marker: marker::PhantomData, + owned: false, + } +} + +impl Clone for Signature<'static> { + fn clone(&self) -> Signature<'static> { + // TODO: can this be defined for 'a and just do a plain old copy if the + // lifetime isn't static? + let mut raw = ptr::null_mut(); + let rc = unsafe { raw::git_signature_dup(&mut raw, &*self.raw) }; + assert_eq!(rc, 0); + unsafe { Binding::from_raw(raw) } + } +} + +impl<'a> Drop for Signature<'a> { + fn drop(&mut self) { + if self.owned { + unsafe { raw::git_signature_free(self.raw) } + } + } +} + +impl<'a> fmt::Display for Signature<'a> { + + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} <{}>", + String::from_utf8_lossy(self.name_bytes()), + String::from_utf8_lossy(self.email_bytes())) + } + +} + +#[cfg(test)] +mod tests { + use {Signature, Time}; + + #[test] + fn smoke() { + Signature::new("foo", "bar", &Time::new(89, 0)).unwrap(); + Signature::now("foo", "bar").unwrap(); + assert!(Signature::new("", "bar", &Time::new(89, 0)).is_err()); + assert!(Signature::now("", "bar").is_err()); + + let s = Signature::now("foo", "bar").unwrap(); + assert_eq!(s.name(), Some("foo")); + assert_eq!(s.email(), Some("bar")); + + drop(s.clone()); + drop(s.to_owned()); + } +} diff --git a/git2/src/stash.rs b/git2/src/stash.rs new file mode 100644 index 000000000..3d07465a3 --- /dev/null +++ b/git2/src/stash.rs @@ -0,0 +1,210 @@ +use {raw, panic, Oid, StashApplyProgress}; +use std::ffi::{CStr}; +use util::{Binding}; +use libc::{c_int, c_char, size_t, c_void}; +use build::{CheckoutBuilder}; +use std::mem; + +/// Stash application progress notification function. +/// +/// Return `true` to continue processing, or `false` to +/// abort the stash application. +pub type StashApplyProgressCb<'a> = FnMut(StashApplyProgress) -> bool + 'a; + +/// This is a callback function you can provide to iterate over all the +/// stashed states that will be invoked per entry. +pub type StashCb<'a> = FnMut(usize, &str, &Oid) -> bool + 'a; + +#[allow(unused)] +/// Stash application options structure +pub struct StashApplyOptions<'cb> { + progress: Option>>, + checkout_options: Option>, + raw_opts: raw::git_stash_apply_options +} + +impl<'cb> Default for StashApplyOptions<'cb> { + fn default() -> Self { + Self::new() + } +} + +impl<'cb> StashApplyOptions<'cb> { + /// Creates a default set of merge options. + pub fn new() -> StashApplyOptions<'cb> { + let mut opts = StashApplyOptions { + progress: None, + checkout_options: None, + raw_opts: unsafe { mem::zeroed() }, + }; + assert_eq!(unsafe { + raw::git_stash_apply_init_options(&mut opts.raw_opts, 1) + }, 0); + opts + } + + /// Set stash application flag to GIT_STASH_APPLY_REINSTATE_INDEX + pub fn reinstantiate_index(&mut self) -> &mut StashApplyOptions<'cb> { + self.raw_opts.flags = raw::GIT_STASH_APPLY_REINSTATE_INDEX; + self + } + + /// Options to use when writing files to the working directory + pub fn checkout_options(&mut self, opts: CheckoutBuilder<'cb>) -> &mut StashApplyOptions<'cb> { + self.checkout_options = Some(opts); + self + } + + /// Optional callback to notify the consumer of application progress. + /// + /// Return `true` to continue processing, or `false` to + /// abort the stash application. + pub fn progress_cb(&mut self, callback: C) -> &mut StashApplyOptions<'cb> + where C: FnMut(StashApplyProgress) -> bool + 'cb + { + self.progress = Some(Box::new(callback) as Box>); + self.raw_opts.progress_cb = stash_apply_progress_cb; + self.raw_opts.progress_payload = self as *mut _ as *mut _; + self + } + + /// Pointer to a raw git_stash_apply_options + pub fn raw(&mut self) -> &raw::git_stash_apply_options { + unsafe { + if let Some(opts) = self.checkout_options.as_mut() { + opts.configure(&mut self.raw_opts.checkout_options); + } + } + &self.raw_opts + } +} + +#[allow(unused)] +pub struct StashCbData<'a> { + pub callback: &'a mut StashCb<'a> +} + +#[allow(unused)] +pub extern fn stash_cb(index: size_t, + message: *const c_char, + stash_id: *const raw::git_oid, + payload: *mut c_void) + -> c_int +{ + panic::wrap(|| unsafe { + let mut data = &mut *(payload as *mut StashCbData); + let res = { + let mut callback = &mut data.callback; + callback(index, + CStr::from_ptr(message).to_str().unwrap(), + &Binding::from_raw(stash_id)) + }; + + if res { 0 } else { 1 } + }).unwrap_or(1) +} + +fn convert_progress(progress: raw::git_stash_apply_progress_t) -> StashApplyProgress { + match progress { + raw::GIT_STASH_APPLY_PROGRESS_NONE => StashApplyProgress::None, + raw::GIT_STASH_APPLY_PROGRESS_LOADING_STASH => StashApplyProgress::LoadingStash, + raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX => StashApplyProgress::AnalyzeIndex, + raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED => StashApplyProgress::AnalyzeModified, + raw::GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED => StashApplyProgress::AnalyzeUntracked, + raw::GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED => StashApplyProgress::CheckoutUntracked, + raw::GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED => StashApplyProgress::CheckoutModified, + raw::GIT_STASH_APPLY_PROGRESS_DONE => StashApplyProgress::Done, + + _ => StashApplyProgress::None + } +} + +#[allow(unused)] +extern fn stash_apply_progress_cb(progress: raw::git_stash_apply_progress_t, + payload: *mut c_void) + -> c_int +{ + panic::wrap(|| unsafe { + let mut options = &mut *(payload as *mut StashApplyOptions); + let res = { + let mut callback = options.progress.as_mut().unwrap(); + callback(convert_progress(progress)) + }; + + if res { 0 } else { -1 } + }).unwrap_or(-1) +} + +#[cfg(test)] +mod tests { + use stash::{StashApplyOptions}; + use std::io::{Write}; + use std::fs; + use std::path::Path; + use test::{repo_init}; + use {Repository, Status, StashFlags}; + + fn make_stash(next: C) where C: FnOnce(&mut Repository) { + let (_td, mut repo) = repo_init(); + let signature = repo.signature().unwrap(); + + let p = Path::new(repo.workdir().unwrap()).join("file_b.txt"); + println!("using path {:?}", p); + fs::File::create(&p).unwrap() + .write("data".as_bytes()).unwrap(); + + let rel_p = Path::new("file_b.txt"); + assert!(repo.status_file(&rel_p).unwrap() == Status::WT_NEW); + + repo.stash_save(&signature, "msg1", Some(StashFlags::INCLUDE_UNTRACKED)).unwrap(); + + assert!(repo.status_file(&rel_p).is_err()); + + let mut count = 0; + repo.stash_foreach(|index, name, _oid| { + count += 1; + assert!(index == 0); + assert!(name == "On master: msg1"); + true + }).unwrap(); + + assert!(count == 1); + next(&mut repo); + } + + fn count_stash(repo: &mut Repository) -> usize { + let mut count = 0; + repo.stash_foreach(|_, _, _| { count += 1; true }).unwrap(); + count + } + + #[test] + fn smoke_stash_save_drop() { + make_stash(|repo| { + repo.stash_drop(0).unwrap(); + assert!(count_stash(repo) == 0) + }) + } + + #[test] + fn smoke_stash_save_pop() { + make_stash(|repo| { + repo.stash_pop(0, None).unwrap(); + assert!(count_stash(repo) == 0) + }) + } + + #[test] + fn smoke_stash_save_apply() { + make_stash(|repo| { + let mut options = StashApplyOptions::new(); + options.progress_cb(|progress| { + println!("{:?}", progress); + true + }); + + repo.stash_apply(0, Some(&mut options)).unwrap(); + assert!(count_stash(repo) == 1) + }) + } +} diff --git a/git2/src/status.rs b/git2/src/status.rs new file mode 100644 index 000000000..cb67305e4 --- /dev/null +++ b/git2/src/status.rs @@ -0,0 +1,418 @@ +use std::ffi::CString; +use std::ops::Range; +use std::marker; +use std::mem; +use std::str; +use libc::{c_char, size_t, c_uint}; + +use {raw, Status, DiffDelta, IntoCString, Repository}; +use util::Binding; + +/// Options that can be provided to `repo.statuses()` to control how the status +/// information is gathered. +pub struct StatusOptions { + raw: raw::git_status_options, + pathspec: Vec, + ptrs: Vec<*const c_char>, +} + +/// Enumeration of possible methods of what can be shown through a status +/// operation. +#[derive(Copy, Clone)] +pub enum StatusShow { + /// Only gives status based on HEAD to index comparison, not looking at + /// working directory changes. + Index, + + /// Only gives status based on index to working directory comparison, not + /// comparing the index to the HEAD. + Workdir, + + /// The default, this roughly matches `git status --porcelain` regarding + /// which files are included and in what order. + IndexAndWorkdir, +} + +/// A container for a list of status information about a repository. +/// +/// Each instance appears as if it were a collection, having a length and +/// allowing indexing, as well as providing an iterator. +pub struct Statuses<'repo> { + raw: *mut raw::git_status_list, + + // Hm, not currently present, but can't hurt? + _marker: marker::PhantomData<&'repo Repository>, +} + +/// An iterator over the statuses in a `Statuses` instance. +pub struct StatusIter<'statuses> { + statuses: &'statuses Statuses<'statuses>, + range: Range, +} + +/// A structure representing an entry in the `Statuses` structure. +/// +/// Instances are created through the `.iter()` method or the `.get()` method. +pub struct StatusEntry<'statuses> { + raw: *const raw::git_status_entry, + _marker: marker::PhantomData<&'statuses DiffDelta<'statuses>>, +} + +impl Default for StatusOptions { + fn default() -> Self { + Self::new() + } +} + +impl StatusOptions { + /// Creates a new blank set of status options. + pub fn new() -> StatusOptions { + unsafe { + let mut raw = mem::zeroed(); + let r = raw::git_status_init_options(&mut raw, + raw::GIT_STATUS_OPTIONS_VERSION); + assert_eq!(r, 0); + StatusOptions { + raw: raw, + pathspec: Vec::new(), + ptrs: Vec::new(), + } + } + } + + /// Select the files on which to report status. + /// + /// The default, if unspecified, is to show the index and the working + /// directory. + pub fn show(&mut self, show: StatusShow) -> &mut StatusOptions { + self.raw.show = match show { + StatusShow::Index => raw::GIT_STATUS_SHOW_INDEX_ONLY, + StatusShow::Workdir => raw::GIT_STATUS_SHOW_WORKDIR_ONLY, + StatusShow::IndexAndWorkdir => raw::GIT_STATUS_SHOW_INDEX_AND_WORKDIR, + }; + self + } + + /// Add a path pattern to match (using fnmatch-style matching). + /// + /// If the `disable_pathspec_match` option is given, then this is a literal + /// path to match. If this is not called, then there will be no patterns to + /// match and the entire directory will be used. + pub fn pathspec(&mut self, pathspec: T) + -> &mut StatusOptions { + let s = pathspec.into_c_string().unwrap(); + self.ptrs.push(s.as_ptr()); + self.pathspec.push(s); + self + } + + fn flag(&mut self, flag: raw::git_status_opt_t, val: bool) + -> &mut StatusOptions { + if val { + self.raw.flags |= flag as c_uint; + } else { + self.raw.flags &= !(flag as c_uint); + } + self + } + + /// Flag whether untracked files will be included. + /// + /// Untracked files will only be included if the workdir files are included + /// in the status "show" option. + pub fn include_untracked(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_INCLUDE_UNTRACKED, include) + } + + /// Flag whether ignored files will be included. + /// + /// The files will only be included if the workdir files are included + /// in the status "show" option. + pub fn include_ignored(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_INCLUDE_IGNORED, include) + } + + /// Flag to include unmodified files. + pub fn include_unmodified(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_INCLUDE_UNMODIFIED, include) + } + + /// Flag that submodules should be skipped. + /// + /// This only applies if there are no pending typechanges to the submodule + /// (either from or to another type). + pub fn exclude_submodules(&mut self, exclude: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_EXCLUDE_SUBMODULES, exclude) + } + + /// Flag that all files in untracked directories should be included. + /// + /// Normally if an entire directory is new then just the top-level directory + /// is included (with a trailing slash on the entry name). + pub fn recurse_untracked_dirs(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS, include) + } + + /// Indicates that the given paths should be treated as literals paths, note + /// patterns. + pub fn disable_pathspec_match(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH, include) + } + + /// Indicates that the contents of ignored directories should be included in + /// the status. + pub fn recurse_ignored_dirs(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_RECURSE_IGNORED_DIRS, include) + } + + /// Indicates that rename detection should be processed between the head. + pub fn renames_head_to_index(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX, include) + } + + /// Indicates that rename detection should be run between the index and the + /// working directory. + pub fn renames_index_to_workdir(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR, include) + } + + /// Override the native case sensitivity for the file system and force the + /// output to be in case sensitive order. + pub fn sort_case_sensitively(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_SORT_CASE_SENSITIVELY, include) + } + + /// Override the native case sensitivity for the file system and force the + /// output to be in case-insensitive order. + pub fn sort_case_insensitively(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY, include) + } + + /// Indicates that rename detection should include rewritten files. + pub fn renames_from_rewrites(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_RENAMES_FROM_REWRITES, include) + } + + /// Bypasses the default status behavior of doing a "soft" index reload. + pub fn no_refresh(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_NO_REFRESH, include) + } + + /// Refresh the stat cache in the index for files are unchanged but have + /// out of date stat information in the index. + /// + /// This will result in less work being done on subsequent calls to fetching + /// the status. + pub fn update_index(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_UPDATE_INDEX, include) + } + + // erm... + #[allow(missing_docs)] + pub fn include_unreadable(&mut self, include: bool) -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_INCLUDE_UNREADABLE, include) + } + + // erm... + #[allow(missing_docs)] + pub fn include_unreadable_as_untracked(&mut self, include: bool) + -> &mut StatusOptions { + self.flag(raw::GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED, include) + } + + /// Get a pointer to the inner list of status options. + /// + /// This function is unsafe as the returned structure has interior pointers + /// and may no longer be valid if these options continue to be mutated. + pub unsafe fn raw(&mut self) -> *const raw::git_status_options { + self.raw.pathspec.strings = self.ptrs.as_ptr() as *mut _; + self.raw.pathspec.count = self.ptrs.len() as size_t; + &self.raw + } +} + +impl<'repo> Statuses<'repo> { + /// Gets a status entry from this list at the specified index. + /// + /// Returns `None` if the index is out of bounds. + pub fn get(&self, index: usize) -> Option { + unsafe { + let p = raw::git_status_byindex(self.raw, index as size_t); + Binding::from_raw_opt(p) + } + } + + /// Gets the count of status entries in this list. + /// + /// If there are no changes in status (according to the options given + /// when the status list was created), this should return 0. + pub fn len(&self) -> usize { + unsafe { raw::git_status_list_entrycount(self.raw) as usize } + } + + /// Return `true` if there is no status entry in this list. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator over the statuses in this list. + pub fn iter(&self) -> StatusIter { + StatusIter { + statuses: self, + range: 0..self.len(), + } + } +} + +impl<'repo> Binding for Statuses<'repo> { + type Raw = *mut raw::git_status_list; + unsafe fn from_raw(raw: *mut raw::git_status_list) -> Statuses<'repo> { + Statuses { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_status_list { self.raw } +} + +impl<'repo> Drop for Statuses<'repo> { + fn drop(&mut self) { + unsafe { raw::git_status_list_free(self.raw); } + } +} + +impl<'a> Iterator for StatusIter<'a> { + type Item = StatusEntry<'a>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.statuses.get(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'a> DoubleEndedIterator for StatusIter<'a> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.statuses.get(i)) + } +} +impl<'a> ExactSizeIterator for StatusIter<'a> {} + +impl<'statuses> StatusEntry<'statuses> { + /// Access the bytes for this entry's corresponding pathname + pub fn path_bytes(&self) -> &[u8] { + unsafe { + if (*self.raw).head_to_index.is_null() { + ::opt_bytes(self, (*(*self.raw).index_to_workdir).old_file.path) + } else { + ::opt_bytes(self, (*(*self.raw).head_to_index).old_file.path) + }.unwrap() + } + } + + /// Access this entry's path name as a string. + /// + /// Returns `None` if the path is not valid utf-8. + pub fn path(&self) -> Option<&str> { str::from_utf8(self.path_bytes()).ok() } + + /// Access the status flags for this file + pub fn status(&self) -> Status { + Status::from_bits_truncate(unsafe { (*self.raw).status as u32 }) + } + + /// Access detailed information about the differences between the file in + /// HEAD and the file in the index. + pub fn head_to_index(&self) -> Option> { + unsafe { + Binding::from_raw_opt((*self.raw).head_to_index) + } + } + + /// Access detailed information about the differences between the file in + /// the index and the file in the working directory. + pub fn index_to_workdir(&self) -> Option> { + unsafe { + Binding::from_raw_opt((*self.raw).index_to_workdir) + } + } +} + +impl<'statuses> Binding for StatusEntry<'statuses> { + type Raw = *const raw::git_status_entry; + + unsafe fn from_raw(raw: *const raw::git_status_entry) + -> StatusEntry<'statuses> { + StatusEntry { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *const raw::git_status_entry { self.raw } +} + +#[cfg(test)] +mod tests { + use std::fs::File; + use std::path::Path; + use std::io::prelude::*; + use super::StatusOptions; + + #[test] + fn smoke() { + let (td, repo) = ::test::repo_init(); + assert_eq!(repo.statuses(None).unwrap().len(), 0); + File::create(&td.path().join("foo")).unwrap(); + let statuses = repo.statuses(None).unwrap(); + assert_eq!(statuses.iter().count(), 1); + let status = statuses.iter().next().unwrap(); + assert_eq!(status.path(), Some("foo")); + assert!(status.status().contains(::Status::WT_NEW)); + assert!(!status.status().contains(::Status::INDEX_NEW)); + assert!(status.head_to_index().is_none()); + let diff = status.index_to_workdir().unwrap(); + assert_eq!(diff.old_file().path_bytes().unwrap(), b"foo"); + assert_eq!(diff.new_file().path_bytes().unwrap(), b"foo"); + } + + #[test] + fn filter() { + let (td, repo) = ::test::repo_init(); + t!(File::create(&td.path().join("foo"))); + t!(File::create(&td.path().join("bar"))); + let mut opts = StatusOptions::new(); + opts.include_untracked(true) + .pathspec("foo"); + + let statuses = t!(repo.statuses(Some(&mut opts))); + assert_eq!(statuses.iter().count(), 1); + let status = statuses.iter().next().unwrap(); + assert_eq!(status.path(), Some("foo")); + } + + #[test] + fn gitignore() { + let (td, repo) = ::test::repo_init(); + t!(t!(File::create(td.path().join(".gitignore"))).write_all(b"foo\n")); + assert!(!t!(repo.status_should_ignore(Path::new("bar")))); + assert!(t!(repo.status_should_ignore(Path::new("foo")))); + } + + #[test] + fn status_file() { + let (td, repo) = ::test::repo_init(); + assert!(repo.status_file(Path::new("foo")).is_err()); + if cfg!(windows) { + assert!(repo.status_file(Path::new("bar\\foo.txt")).is_err()); + } + t!(File::create(td.path().join("foo"))); + if cfg!(windows) { + t!(::std::fs::create_dir_all(td.path().join("bar"))); + t!(File::create(td.path().join("bar").join("foo.txt"))); + } + let status = t!(repo.status_file(Path::new("foo"))); + assert!(status.contains(::Status::WT_NEW)); + if cfg!(windows) { + let status = t!(repo.status_file(Path::new("bar\\foo.txt"))); + assert!(status.contains(::Status::WT_NEW)); + } + } +} diff --git a/git2/src/string_array.rs b/git2/src/string_array.rs new file mode 100644 index 000000000..97af2090e --- /dev/null +++ b/git2/src/string_array.rs @@ -0,0 +1,117 @@ +//! Bindings to libgit2's raw `git_strarray` type + +use std::str; +use std::ops::Range; + +use raw; +use util::Binding; + +/// A string array structure used by libgit2 +/// +/// Some apis return arrays of strings which originate from libgit2. This +/// wrapper type behaves a little like `Vec<&str>` but does so without copying +/// the underlying strings until necessary. +pub struct StringArray { + raw: raw::git_strarray, +} + +/// A forward iterator over the strings of an array, casted to `&str`. +pub struct Iter<'a> { + range: Range, + arr: &'a StringArray, +} + +/// A forward iterator over the strings of an array, casted to `&[u8]`. +pub struct IterBytes<'a> { + range: Range, + arr: &'a StringArray, +} + +impl StringArray { + /// Returns None if the i'th string is not utf8 or if i is out of bounds. + pub fn get(&self, i: usize) -> Option<&str> { + self.get_bytes(i).and_then(|s| str::from_utf8(s).ok()) + } + + /// Returns None if `i` is out of bounds. + pub fn get_bytes(&self, i: usize) -> Option<&[u8]> { + if i < self.raw.count as usize { + unsafe { + let ptr = *self.raw.strings.offset(i as isize) as *const _; + Some(::opt_bytes(self, ptr).unwrap()) + } + } else { + None + } + } + + /// Returns an iterator over the strings contained within this array. + /// + /// The iterator yields `Option<&str>` as it is unknown whether the contents + /// are utf-8 or not. + pub fn iter(&self) -> Iter { + Iter { range: 0..self.len(), arr: self } + } + + /// Returns an iterator over the strings contained within this array, + /// yielding byte slices. + pub fn iter_bytes(&self) -> IterBytes { + IterBytes { range: 0..self.len(), arr: self } + } + + /// Returns the number of strings in this array. + pub fn len(&self) -> usize { self.raw.count as usize } + + /// Return `true` if this array is empty. + pub fn is_empty(&self) -> bool { self.len() == 0 } +} + +impl Binding for StringArray { + type Raw = raw::git_strarray; + unsafe fn from_raw(raw: raw::git_strarray) -> StringArray { + StringArray { raw: raw } + } + fn raw(&self) -> raw::git_strarray { self.raw } +} + +impl<'a> IntoIterator for &'a StringArray { + type Item = Option<&'a str>; + type IntoIter = Iter<'a>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = Option<&'a str>; + fn next(&mut self) -> Option> { + self.range.next().map(|i| self.arr.get(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'a> DoubleEndedIterator for Iter<'a> { + fn next_back(&mut self) -> Option> { + self.range.next_back().map(|i| self.arr.get(i)) + } +} +impl<'a> ExactSizeIterator for Iter<'a> {} + +impl<'a> Iterator for IterBytes<'a> { + type Item = &'a [u8]; + fn next(&mut self) -> Option<&'a [u8]> { + self.range.next().and_then(|i| self.arr.get_bytes(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'a> DoubleEndedIterator for IterBytes<'a> { + fn next_back(&mut self) -> Option<&'a [u8]> { + self.range.next_back().and_then(|i| self.arr.get_bytes(i)) + } +} +impl<'a> ExactSizeIterator for IterBytes<'a> {} + +impl Drop for StringArray { + fn drop(&mut self) { + unsafe { raw::git_strarray_free(&mut self.raw) } + } +} diff --git a/git2/src/submodule.rs b/git2/src/submodule.rs new file mode 100644 index 000000000..64c7ec87e --- /dev/null +++ b/git2/src/submodule.rs @@ -0,0 +1,357 @@ +use std::marker; +use std::mem; +use std::ptr; +use std::str; +use std::os::raw::c_int; +use std::path::Path; + +use {raw, Oid, Repository, Error, FetchOptions}; +use build::CheckoutBuilder; +use util::{self, Binding}; + +/// A structure to represent a git [submodule][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Tools-Submodules +pub struct Submodule<'repo> { + raw: *mut raw::git_submodule, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> Submodule<'repo> { + /// Get the submodule's branch. + /// + /// Returns `None` if the branch is not valid utf-8 or if the branch is not + /// yet available. + pub fn branch(&self) -> Option<&str> { + self.branch_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the branch for the submodule. + /// + /// Returns `None` if the branch is not yet available. + pub fn branch_bytes(&self) -> Option<&[u8]> { + unsafe { + ::opt_bytes(self, raw::git_submodule_branch(self.raw)) + } + } + + /// Get the submodule's url. + /// + /// Returns `None` if the url is not valid utf-8 or if the URL isn't present + pub fn url(&self) -> Option<&str> { + self.opt_url_bytes().and_then(|b| str::from_utf8(b).ok()) + } + + /// Get the url for the submodule. + #[doc(hidden)] + #[deprecated(note = "renamed to `opt_url_bytes`")] + pub fn url_bytes(&self) -> &[u8] { + self.opt_url_bytes().unwrap() + } + + /// Get the url for the submodule. + /// + /// Returns `None` if the URL isn't present + // TODO: delete this method and fix the signature of `url_bytes` on next + // major version bump + pub fn opt_url_bytes(&self) -> Option<&[u8]> { + unsafe { + ::opt_bytes(self, raw::git_submodule_url(self.raw)) + } + } + + /// Get the submodule's name. + /// + /// Returns `None` if the name is not valid utf-8 + pub fn name(&self) -> Option<&str> { str::from_utf8(self.name_bytes()).ok() } + + /// Get the name for the submodule. + pub fn name_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_submodule_name(self.raw)).unwrap() + } + } + + /// Get the path for the submodule. + pub fn path(&self) -> &Path { + util::bytes2path(unsafe { + ::opt_bytes(self, raw::git_submodule_path(self.raw)).unwrap() + }) + } + + /// Get the OID for the submodule in the current HEAD tree. + pub fn head_id(&self) -> Option { + unsafe { + Binding::from_raw_opt(raw::git_submodule_head_id(self.raw)) + } + } + + /// Get the OID for the submodule in the index. + pub fn index_id(&self) -> Option { + unsafe { + Binding::from_raw_opt(raw::git_submodule_index_id(self.raw)) + } + } + + /// Get the OID for the submodule in the current working directory. + /// + /// This returns the OID that corresponds to looking up 'HEAD' in the + /// checked out submodule. If there are pending changes in the index or + /// anything else, this won't notice that. + pub fn workdir_id(&self) -> Option { + unsafe { + Binding::from_raw_opt(raw::git_submodule_wd_id(self.raw)) + } + } + + /// Copy submodule info into ".git/config" file. + /// + /// Just like "git submodule init", this copies information about the + /// submodule into ".git/config". You can use the accessor functions above + /// to alter the in-memory git_submodule object and control what is written + /// to the config, overriding what is in .gitmodules. + /// + /// By default, existing entries will not be overwritten, but passing `true` + /// for `overwrite` forces them to be updated. + pub fn init(&mut self, overwrite: bool) -> Result<(), Error> { + unsafe { + try_call!(raw::git_submodule_init(self.raw, overwrite)); + } + Ok(()) + } + + /// Open the repository for a submodule. + /// + /// This will only work if the submodule is checked out into the working + /// directory. + pub fn open(&self) -> Result { + let mut raw = ptr::null_mut(); + unsafe { + try_call!(raw::git_submodule_open(&mut raw, self.raw)); + Ok(Binding::from_raw(raw)) + } + } + + /// Reread submodule info from config, index, and HEAD. + /// + /// Call this to reread cached submodule information for this submodule if + /// you have reason to believe that it has changed. + /// + /// If `force` is `true`, then data will be reloaded even if it doesn't seem + /// out of date + pub fn reload(&mut self, force: bool) -> Result<(), Error> { + unsafe { + try_call!(raw::git_submodule_reload(self.raw, force)); + } + Ok(()) + } + + /// Copy submodule remote info into submodule repo. + /// + /// This copies the information about the submodules URL into the checked + /// out submodule config, acting like "git submodule sync". This is useful + /// if you have altered the URL for the submodule (or it has been altered + /// by a fetch of upstream changes) and you need to update your local repo. + pub fn sync(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_submodule_sync(self.raw)); } + Ok(()) + } + + /// Add current submodule HEAD commit to index of superproject. + /// + /// If `write_index` is true, then the index file will be immediately + /// written. Otherwise you must explicitly call `write()` on an `Index` + /// later on. + pub fn add_to_index(&mut self, write_index: bool) -> Result<(), Error> { + unsafe { + try_call!(raw::git_submodule_add_to_index(self.raw, write_index)); + } + Ok(()) + } + + /// Resolve the setup of a new git submodule. + /// + /// This should be called on a submodule once you have called add setup and + /// done the clone of the submodule. This adds the .gitmodules file and the + /// newly cloned submodule to the index to be ready to be committed (but + /// doesn't actually do the commit). + pub fn add_finalize(&mut self) -> Result<(), Error> { + unsafe { try_call!(raw::git_submodule_add_finalize(self.raw)); } + Ok(()) + } + + /// Update submodule. + /// + /// This will clone a missing submodule and check out the subrepository to + /// the commit specified in the index of the containing repository. If + /// the submodule repository doesn't contain the target commit, then the + /// submodule is fetched using the fetch options supplied in `opts`. + /// + /// `init` indicates if the submodule should be initialized first if it has + /// not been initialized yet. + pub fn update(&mut self, init: bool, + opts: Option<&mut SubmoduleUpdateOptions>) + -> Result<(), Error> { + unsafe { + let mut raw_opts = opts.map(|o| o.raw()); + try_call!(raw::git_submodule_update(self.raw, init as c_int, + raw_opts.as_mut().map_or(ptr::null_mut(), |o| o))); + } + Ok(()) + } +} + +impl<'repo> Binding for Submodule<'repo> { + type Raw = *mut raw::git_submodule; + unsafe fn from_raw(raw: *mut raw::git_submodule) -> Submodule<'repo> { + Submodule { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_submodule { self.raw } +} + +impl<'repo> Drop for Submodule<'repo> { + fn drop(&mut self) { + unsafe { raw::git_submodule_free(self.raw) } + } +} + +/// Options to update a submodule. +pub struct SubmoduleUpdateOptions<'cb> { + checkout_builder: CheckoutBuilder<'cb>, + fetch_opts: FetchOptions<'cb>, + allow_fetch: bool, +} + +impl<'cb> SubmoduleUpdateOptions<'cb> { + /// Return default options. + pub fn new() -> Self { + SubmoduleUpdateOptions { + checkout_builder: CheckoutBuilder::new(), + fetch_opts: FetchOptions::new(), + allow_fetch: true, + } + } + + unsafe fn raw(&mut self) -> raw::git_submodule_update_options { + let mut checkout_opts: raw::git_checkout_options = mem::zeroed(); + let init_res = raw::git_checkout_init_options(&mut checkout_opts, + raw::GIT_CHECKOUT_OPTIONS_VERSION); + assert_eq!(0, init_res); + self.checkout_builder.configure(&mut checkout_opts); + let opts = raw::git_submodule_update_options { + version: raw::GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, + checkout_opts, + fetch_opts: self.fetch_opts.raw(), + allow_fetch: self.allow_fetch as c_int, + }; + opts + } + + /// Set checkout options. + pub fn checkout(&mut self, opts: CheckoutBuilder<'cb>) -> &mut Self { + self.checkout_builder = opts; + self + } + + /// Set fetch options and allow fetching. + pub fn fetch(&mut self, opts: FetchOptions<'cb>) -> &mut Self { + self.fetch_opts = opts; + self.allow_fetch = true; + self + } + + /// Allow or disallow fetching. + pub fn allow_fetch(&mut self, b: bool) -> &mut Self { + self.allow_fetch = b; + self + } +} + +impl<'cb> Default for SubmoduleUpdateOptions<'cb> { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use std::path::Path; + use std::fs; + use tempdir::TempDir; + use url::Url; + + use Repository; + use SubmoduleUpdateOptions; + + #[test] + fn smoke() { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + let mut s1 = repo.submodule("/path/to/nowhere", + Path::new("foo"), true).unwrap(); + s1.init(false).unwrap(); + s1.sync().unwrap(); + + let s2 = repo.submodule("/path/to/nowhere", + Path::new("bar"), true).unwrap(); + drop((s1, s2)); + + let mut submodules = repo.submodules().unwrap(); + assert_eq!(submodules.len(), 2); + let mut s = submodules.remove(0); + assert_eq!(s.name(), Some("bar")); + assert_eq!(s.url(), Some("/path/to/nowhere")); + assert_eq!(s.branch(), None); + assert!(s.head_id().is_none()); + assert!(s.index_id().is_none()); + assert!(s.workdir_id().is_none()); + + repo.find_submodule("bar").unwrap(); + s.open().unwrap(); + assert!(s.path() == Path::new("bar")); + s.reload(true).unwrap(); + } + + #[test] + fn add_a_submodule() { + let (_td, repo1) = ::test::repo_init(); + let (td, repo2) = ::test::repo_init(); + + let url = Url::from_file_path(&repo1.workdir().unwrap()).unwrap(); + let mut s = repo2.submodule(&url.to_string(), Path::new("bar"), + true).unwrap(); + t!(fs::remove_dir_all(td.path().join("bar"))); + t!(Repository::clone(&url.to_string(), + td.path().join("bar"))); + t!(s.add_to_index(false)); + t!(s.add_finalize()); + } + + #[test] + fn update_submodule() { + // ----------------------------------- + // Same as `add_a_submodule()` + let (_td, repo1) = ::test::repo_init(); + let (td, repo2) = ::test::repo_init(); + + let url = Url::from_file_path(&repo1.workdir().unwrap()).unwrap(); + let mut s = repo2.submodule(&url.to_string(), Path::new("bar"), + true).unwrap(); + t!(fs::remove_dir_all(td.path().join("bar"))); + t!(Repository::clone(&url.to_string(), + td.path().join("bar"))); + t!(s.add_to_index(false)); + t!(s.add_finalize()); + // ----------------------------------- + + // Attempt to update submodule + let submodules = t!(repo1.submodules()); + for mut submodule in submodules { + let mut submodule_options = SubmoduleUpdateOptions::new(); + let init = true; + let opts = Some(&mut submodule_options); + + t!(submodule.update(init, opts)); + } + } +} diff --git a/git2/src/tag.rs b/git2/src/tag.rs new file mode 100644 index 000000000..8041f3546 --- /dev/null +++ b/git2/src/tag.rs @@ -0,0 +1,191 @@ +use std::marker; +use std::mem; +use std::ptr; +use std::str; + +use {raw, signature, Error, Oid, Object, Signature, ObjectType}; +use util::Binding; + +/// A structure to represent a git [tag][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Basics-Tagging +pub struct Tag<'repo> { + raw: *mut raw::git_tag, + _marker: marker::PhantomData>, +} + +impl<'repo> Tag<'repo> { + /// Get the id (SHA1) of a repository tag + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_tag_id(&*self.raw)) } + } + + /// Get the message of a tag + /// + /// Returns None if there is no message or if it is not valid utf8 + pub fn message(&self) -> Option<&str> { + self.message_bytes().and_then(|s| str::from_utf8(s).ok()) + } + + /// Get the message of a tag + /// + /// Returns None if there is no message + pub fn message_bytes(&self) -> Option<&[u8]> { + unsafe { ::opt_bytes(self, raw::git_tag_message(&*self.raw)) } + } + + /// Get the name of a tag + /// + /// Returns None if it is not valid utf8 + pub fn name(&self) -> Option<&str> { + str::from_utf8(self.name_bytes()).ok() + } + + /// Get the name of a tag + pub fn name_bytes(&self) -> &[u8] { + unsafe { ::opt_bytes(self, raw::git_tag_name(&*self.raw)).unwrap() } + } + + /// Recursively peel a tag until a non tag git_object is found + pub fn peel(&self) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_tag_peel(&mut ret, &*self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Get the tagger (author) of a tag + /// + /// If the author is unspecified, then `None` is returned. + pub fn tagger(&self) -> Option { + unsafe { + let ptr = raw::git_tag_tagger(&*self.raw); + if ptr.is_null() { + None + } else { + Some(signature::from_raw_const(self, ptr)) + } + } + } + + /// Get the tagged object of a tag + /// + /// This method performs a repository lookup for the given object and + /// returns it + pub fn target(&self) -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_tag_target(&mut ret, &*self.raw)); + Ok(Binding::from_raw(ret)) + } + } + + /// Get the OID of the tagged object of a tag + pub fn target_id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_tag_target_id(&*self.raw)) } + } + + /// Get the OID of the tagged object of a tag + pub fn target_type(&self) -> Option { + unsafe { ObjectType::from_raw(raw::git_tag_target_type(&*self.raw)) } + } + + /// Casts this Tag to be usable as an `Object` + pub fn as_object(&self) -> &Object<'repo> { + unsafe { + &*(self as *const _ as *const Object<'repo>) + } + } + + /// Consumes Tag to be returned as an `Object` + pub fn into_object(self) -> Object<'repo> { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + unsafe { + mem::transmute(self) + } + } +} + +impl<'repo> ::std::fmt::Debug for Tag<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let mut ds = f.debug_struct("Tag"); + if let Some(name) = self.name() { + ds.field("name", &name); + } + ds.field("id", &self.id()); + ds.finish() + } +} + +impl<'repo> Binding for Tag<'repo> { + type Raw = *mut raw::git_tag; + unsafe fn from_raw(raw: *mut raw::git_tag) -> Tag<'repo> { + Tag { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_tag { self.raw } +} + +impl<'repo> Clone for Tag<'repo> { + fn clone(&self) -> Self { + self.as_object().clone().into_tag().ok().unwrap() + } +} + +impl<'repo> Drop for Tag<'repo> { + fn drop(&mut self) { + unsafe { raw::git_tag_free(self.raw) } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + let head = repo.head().unwrap(); + let id = head.target().unwrap(); + assert!(repo.find_tag(id).is_err()); + + let obj = repo.find_object(id, None).unwrap(); + let sig = repo.signature().unwrap(); + let tag_id = repo.tag("foo", &obj, &sig, "msg", false).unwrap(); + let tag = repo.find_tag(tag_id).unwrap(); + assert_eq!(tag.id(), tag_id); + + let tags = repo.tag_names(None).unwrap(); + assert_eq!(tags.len(), 1); + assert_eq!(tags.get(0), Some("foo")); + + assert_eq!(tag.name(), Some("foo")); + assert_eq!(tag.message(), Some("msg")); + assert_eq!(tag.peel().unwrap().id(), obj.id()); + assert_eq!(tag.target_id(), obj.id()); + assert_eq!(tag.target_type(), Some(::ObjectType::Commit)); + + assert_eq!(tag.tagger().unwrap().name(), sig.name()); + tag.target().unwrap(); + tag.into_object(); + + repo.find_object(tag_id, None).unwrap().as_tag().unwrap(); + repo.find_object(tag_id, None).unwrap().into_tag().ok().unwrap(); + + repo.tag_delete("foo").unwrap(); + } + + #[test] + fn lite() { + let (_td, repo) = ::test::repo_init(); + let head = t!(repo.head()); + let id = head.target().unwrap(); + let obj = t!(repo.find_object(id, None)); + let tag_id = t!(repo.tag_lightweight("foo", &obj, false)); + assert!(repo.find_tag(tag_id).is_err()); + assert_eq!(t!(repo.refname_to_id("refs/tags/foo")), id); + + let tags = t!(repo.tag_names(Some("f*"))); + assert_eq!(tags.len(), 1); + let tags = t!(repo.tag_names(Some("b*"))); + assert_eq!(tags.len(), 0); + } +} diff --git a/git2/src/test.rs b/git2/src/test.rs new file mode 100644 index 000000000..4f8813fda --- /dev/null +++ b/git2/src/test.rs @@ -0,0 +1,61 @@ +use std::path::{Path, PathBuf}; +use std::io; +#[cfg(unix)] +use std::ptr; +use tempdir::TempDir; +use url::Url; + +use Repository; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +pub fn repo_init() -> (TempDir, Repository) { + let td = TempDir::new("test").unwrap(); + let repo = Repository::init(td.path()).unwrap(); + { + let mut config = repo.config().unwrap(); + config.set_str("user.name", "name").unwrap(); + config.set_str("user.email", "email").unwrap(); + let mut index = repo.index().unwrap(); + let id = index.write_tree().unwrap(); + + let tree = repo.find_tree(id).unwrap(); + let sig = repo.signature().unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, "initial", + &tree, &[]).unwrap(); + } + (td, repo) +} + +pub fn path2url(path: &Path) -> String { + Url::from_file_path(path).unwrap().to_string() +} + +#[cfg(windows)] +pub fn realpath(original: &Path) -> io::Result { + Ok(original.to_path_buf()) +} +#[cfg(unix)] +pub fn realpath(original: &Path) -> io::Result { + use std::ffi::{CStr, OsString, CString}; + use std::os::unix::prelude::*; + use libc::{self, c_char}; + extern { + fn realpath(name: *const c_char, resolved: *mut c_char) -> *mut c_char; + } + unsafe { + let cstr = try!(CString::new(original.as_os_str().as_bytes())); + let ptr = realpath(cstr.as_ptr(), ptr::null_mut()); + if ptr.is_null() { + return Err(io::Error::last_os_error()) + } + let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); + libc::free(ptr as *mut _); + Ok(PathBuf::from(OsString::from_vec(bytes))) + } +} diff --git a/git2/src/time.rs b/git2/src/time.rs new file mode 100644 index 000000000..57a5a70a3 --- /dev/null +++ b/git2/src/time.rs @@ -0,0 +1,100 @@ +use std::cmp::Ordering; + +use libc::{c_int, c_char}; + +use raw; +use util::Binding; + +/// Time in a signature +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Time { + raw: raw::git_time, +} + +/// Time structure used in a git index entry. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct IndexTime { + raw: raw::git_index_time, +} + +impl Time { + /// Creates a new time structure from its components. + pub fn new(time: i64, offset: i32) -> Time { + unsafe { + Binding::from_raw(raw::git_time { + time: time as raw::git_time_t, + offset: offset as c_int, + sign: if offset < 0 { '-' } else { '+' } as c_char, + }) + } + } + + /// Return the time, in seconds, from epoch + pub fn seconds(&self) -> i64 { self.raw.time as i64 } + + /// Return the timezone offset, in minutes + pub fn offset_minutes(&self) -> i32 { self.raw.offset as i32 } + + /// Return whether the offset was positive or negative. Primarily useful + /// in case the offset is specified as a negative zero. + pub fn sign(&self) -> char { self.raw.offset as u8 as char } +} + +impl PartialOrd for Time { + fn partial_cmp(&self, other: &Time) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Time { + fn cmp(&self, other: &Time) -> Ordering { + (self.raw.time, self.raw.offset).cmp(&(other.raw.time, other.raw.offset)) + } +} + +impl Binding for Time { + type Raw = raw::git_time; + unsafe fn from_raw(raw: raw::git_time) -> Time { + Time { raw: raw } + } + fn raw(&self) -> raw::git_time { self.raw } +} + +impl IndexTime { + /// Creates a new time structure from its components. + pub fn new(seconds: i32, nanoseconds: u32) -> IndexTime { + unsafe { + Binding::from_raw(raw::git_index_time { + seconds: seconds, + nanoseconds: nanoseconds, + }) + } + } + + /// Returns the number of seconds in the second component of this time. + pub fn seconds(&self) -> i32 { self.raw.seconds } + /// Returns the nanosecond component of this time. + pub fn nanoseconds(&self) -> u32 { self.raw.nanoseconds } +} + +impl Binding for IndexTime { + type Raw = raw::git_index_time; + unsafe fn from_raw(raw: raw::git_index_time) -> IndexTime { + IndexTime { raw: raw } + } + fn raw(&self) -> raw::git_index_time { self.raw } +} + +impl PartialOrd for IndexTime { + fn partial_cmp(&self, other: &IndexTime) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for IndexTime { + fn cmp(&self, other: &IndexTime) -> Ordering { + let me = (self.raw.seconds, self.raw.nanoseconds); + let other = (other.raw.seconds, other.raw.nanoseconds); + me.cmp(&other) + } +} diff --git a/git2/src/transport.rs b/git2/src/transport.rs new file mode 100644 index 000000000..d34db9f88 --- /dev/null +++ b/git2/src/transport.rs @@ -0,0 +1,326 @@ +//! Interfaces for adding custom transports to libgit2 + +use std::ffi::{CStr, CString}; +use std::io::prelude::*; +use std::io; +use std::mem; +use std::slice; +use std::ptr; +use std::str; +use libc::{c_int, c_void, c_uint, c_char, size_t}; + +use {raw, panic, Error, Remote}; +use util::Binding; + +/// A transport is a structure which knows how to transfer data to and from a +/// remote. +/// +/// This transport is a representation of the raw transport underneath it, which +/// is similar to a trait object in Rust. +#[allow(missing_copy_implementations)] +pub struct Transport { + raw: *mut raw::git_transport, + owned: bool, +} + +/// Interface used by smart transports. +/// +/// The full-fledged definiton of transports has to deal with lots of +/// nitty-gritty details of the git protocol, but "smart transports" largely +/// only need to deal with read() and write() of data over a channel. +/// +/// A smart subtransport is contained within an instance of a smart transport +/// and is delegated to in order to actually conduct network activity to push or +/// pull data from a remote. +pub trait SmartSubtransport: Send + 'static { + /// Indicates that this subtransport will be performing the specified action + /// on the specified URL. + /// + /// This function is responsible for making any network connections and + /// returns a stream which can be read and written from in order to + /// negotiate the git protocol. + fn action(&self, url: &str, action: Service) + -> Result, Error>; + + /// Terminates a connection with the remote. + /// + /// Each subtransport is guaranteed a call to close() between calls to + /// action(), except for the following two natural progressions of actions + /// against a constant URL. + /// + /// 1. UploadPackLs -> UploadPack + /// 2. ReceivePackLs -> ReceivePack + fn close(&self) -> Result<(), Error>; +} + +/// Actions that a smart transport can ask a subtransport to perform +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub enum Service { + UploadPackLs, + UploadPack, + ReceivePackLs, + ReceivePack, +} + +/// An instance of a stream over which a smart transport will communicate with a +/// remote. +/// +/// Currently this only requires the standard `Read` and `Write` traits. This +/// trait also does not need to be implemented manually as long as the `Read` +/// and `Write` traits are implemented. +pub trait SmartSubtransportStream: Read + Write + Send + 'static {} + +impl SmartSubtransportStream for T {} + +type TransportFactory = Fn(&Remote) -> Result + Send + Sync + + 'static; + +/// Boxed data payload used for registering new transports. +/// +/// Currently only contains a field which knows how to create transports. +struct TransportData { + factory: Box, +} + +/// Instance of a `git_smart_subtransport`, must use `#[repr(C)]` to ensure that +/// the C fields come first. +#[repr(C)] +struct RawSmartSubtransport { + raw: raw::git_smart_subtransport, + obj: Box, +} + +/// Instance of a `git_smart_subtransport_stream`, must use `#[repr(C)]` to +/// ensure that the C fields come first. +#[repr(C)] +struct RawSmartSubtransportStream { + raw: raw::git_smart_subtransport_stream, + obj: Box, +} + +/// Add a custom transport definition, to be used in addition to the built-in +/// set of transports that come with libgit2. +/// +/// This function is unsafe as it needs to be externally synchronized with calls +/// to creation of other transports. +pub unsafe fn register(prefix: &str, factory: F) -> Result<(), Error> + where F: Fn(&Remote) -> Result + Send + Sync + 'static +{ + let mut data = Box::new(TransportData { + factory: Box::new(factory), + }); + let prefix = try!(CString::new(prefix)); + let datap = (&mut *data) as *mut TransportData as *mut c_void; + try_call!(raw::git_transport_register(prefix, + transport_factory, + datap)); + mem::forget(data); + Ok(()) +} + +impl Transport { + /// Creates a new transport which will use the "smart" transport protocol + /// for transferring data. + /// + /// A smart transport requires a *subtransport* over which data is actually + /// communicated, but this subtransport largely just needs to be able to + /// read() and write(). The subtransport provided will be used to make + /// connections which can then be read/written from. + /// + /// The `rpc` argument is `true` if the protocol is stateless, false + /// otherwise. For example `http://` is stateless but `git://` is not. + pub fn smart(remote: &Remote, + rpc: bool, + subtransport: S) -> Result + where S: SmartSubtransport + { + let mut ret = ptr::null_mut(); + + let mut raw = Box::new(RawSmartSubtransport { + raw: raw::git_smart_subtransport { + action: subtransport_action, + close: subtransport_close, + free: subtransport_free, + }, + obj: Box::new(subtransport), + }); + let mut defn = raw::git_smart_subtransport_definition { + callback: smart_factory, + rpc: rpc as c_uint, + param: &mut *raw as *mut _ as *mut _, + }; + + // Currently there's no way to pass a payload via the + // git_smart_subtransport_definition structure, but it's only used as a + // configuration for the initial creation of the smart transport (verified + // by reading the current code, hopefully it doesn't change!). + // + // We, however, need some state (gotta pass in our + // `RawSmartSubtransport`). This also means that this block must be + // entirely synchronized with a lock (boo!) + unsafe { + try_call!(raw::git_transport_smart(&mut ret, remote.raw(), + &mut defn as *mut _ as *mut _)); + mem::forget(raw); // ownership transport to `ret` + } + return Ok(Transport { raw: ret, owned: true }); + + extern fn smart_factory(out: *mut *mut raw::git_smart_subtransport, + _owner: *mut raw::git_transport, + ptr: *mut c_void) -> c_int { + unsafe { + *out = ptr as *mut raw::git_smart_subtransport; + 0 + } + } + } +} + +impl Drop for Transport { + fn drop(&mut self) { + if self.owned { + unsafe { + ((*self.raw).free)(self.raw) + } + } + } +} + +// callback used by register() to create new transports +extern fn transport_factory(out: *mut *mut raw::git_transport, + owner: *mut raw::git_remote, + param: *mut c_void) -> c_int { + struct Bomb<'a> { remote: Option> } + impl<'a> Drop for Bomb<'a> { + fn drop(&mut self) { + // TODO: maybe a method instead? + mem::forget(self.remote.take()); + } + } + + panic::wrap(|| unsafe { + let remote = Bomb { remote: Some(Binding::from_raw(owner)) }; + let data = &mut *(param as *mut TransportData); + match (data.factory)(remote.remote.as_ref().unwrap()) { + Ok(mut transport) => { + *out = transport.raw; + transport.owned = false; + 0 + } + Err(e) => e.raw_code() as c_int, + } + }).unwrap_or(-1) +} + +// callback used by smart transports to delegate an action to a +// `SmartSubtransport` trait object. +extern fn subtransport_action(stream: *mut *mut raw::git_smart_subtransport_stream, + raw_transport: *mut raw::git_smart_subtransport, + url: *const c_char, + action: raw::git_smart_service_t) -> c_int { + panic::wrap(|| unsafe { + let url = CStr::from_ptr(url).to_bytes(); + let url = match str::from_utf8(url).ok() { + Some(s) => s, + None => return -1, + }; + let action = match action { + raw::GIT_SERVICE_UPLOADPACK_LS => Service::UploadPackLs, + raw::GIT_SERVICE_UPLOADPACK => Service::UploadPack, + raw::GIT_SERVICE_RECEIVEPACK_LS => Service::ReceivePackLs, + raw::GIT_SERVICE_RECEIVEPACK => Service::ReceivePack, + n => panic!("unknown action: {}", n), + }; + let transport = &mut *(raw_transport as *mut RawSmartSubtransport); + let obj = match transport.obj.action(url, action) { + Ok(s) => s, + Err(e) => return e.raw_code() as c_int, + }; + *stream = mem::transmute(Box::new(RawSmartSubtransportStream { + raw: raw::git_smart_subtransport_stream { + subtransport: raw_transport, + read: stream_read, + write: stream_write, + free: stream_free, + }, + obj: obj, + })); + 0 + }).unwrap_or(-1) +} + +// callback used by smart transports to close a `SmartSubtransport` trait +// object. +extern fn subtransport_close(transport: *mut raw::git_smart_subtransport) + -> c_int { + let ret = panic::wrap(|| unsafe { + let transport = &mut *(transport as *mut RawSmartSubtransport); + transport.obj.close() + }); + match ret { + Some(Ok(())) => 0, + Some(Err(e)) => e.raw_code() as c_int, + None => -1, + } +} + +// callback used by smart transports to free a `SmartSubtransport` trait +// object. +extern fn subtransport_free(transport: *mut raw::git_smart_subtransport) { + let _ = panic::wrap(|| unsafe { + mem::transmute::<_, Box>(transport); + }); +} + +// callback used by smart transports to read from a `SmartSubtransportStream` +// object. +extern fn stream_read(stream: *mut raw::git_smart_subtransport_stream, + buffer: *mut c_char, + buf_size: size_t, + bytes_read: *mut size_t) -> c_int { + let ret = panic::wrap(|| unsafe { + let transport = &mut *(stream as *mut RawSmartSubtransportStream); + let buf = slice::from_raw_parts_mut(buffer as *mut u8, + buf_size as usize); + match transport.obj.read(buf) { + Ok(n) => { *bytes_read = n as size_t; Ok(n) } + e => e, + } + }); + match ret { + Some(Ok(_)) => 0, + Some(Err(e)) => unsafe { set_err(&e); -2 }, + None => -1, + } +} + +// callback used by smart transports to write to a `SmartSubtransportStream` +// object. +extern fn stream_write(stream: *mut raw::git_smart_subtransport_stream, + buffer: *const c_char, + len: size_t) -> c_int { + let ret = panic::wrap(|| unsafe { + let transport = &mut *(stream as *mut RawSmartSubtransportStream); + let buf = slice::from_raw_parts(buffer as *const u8, len as usize); + transport.obj.write_all(buf) + }); + match ret { + Some(Ok(())) => 0, + Some(Err(e)) => unsafe { set_err(&e); -2 }, + None => -1, + } +} + +unsafe fn set_err(e: &io::Error) { + let s = CString::new(e.to_string()).unwrap(); + raw::giterr_set_str(raw::GITERR_NET as c_int, s.as_ptr()) +} + +// callback used by smart transports to free a `SmartSubtransportStream` +// object. +extern fn stream_free(stream: *mut raw::git_smart_subtransport_stream) { + let _ = panic::wrap(|| unsafe { + mem::transmute::<_, Box>(stream); + }); +} diff --git a/git2/src/tree.rs b/git2/src/tree.rs new file mode 100644 index 000000000..6a0f4975e --- /dev/null +++ b/git2/src/tree.rs @@ -0,0 +1,532 @@ +use std::mem; +use std::cmp::Ordering; +use std::ffi::{CStr, CString}; +use std::ops::Range; +use std::marker; +use std::path::Path; +use std::ptr; +use std::str; +use libc::{self, c_int, c_char, c_void}; + +use {panic, raw, Oid, Repository, Error, Object, ObjectType}; +use util::{Binding, IntoCString}; + +/// A structure to represent a git [tree][1] +/// +/// [1]: http://git-scm.com/book/en/Git-Internals-Git-Objects +pub struct Tree<'repo> { + raw: *mut raw::git_tree, + _marker: marker::PhantomData>, +} + +/// A structure representing an entry inside of a tree. An entry is borrowed +/// from a tree. +pub struct TreeEntry<'tree> { + raw: *mut raw::git_tree_entry, + owned: bool, + _marker: marker::PhantomData<&'tree raw::git_tree_entry>, +} + +/// An iterator over the entries in a tree. +pub struct TreeIter<'tree> { + range: Range, + tree: &'tree Tree<'tree>, +} + +/// A binary indicator of whether a tree walk should be performed in pre-order +/// or post-order. +pub enum TreeWalkMode { + /// Runs the traversal in pre order. + PreOrder = 0, + /// Runs the traversal in post order. + PostOrder = 1, +} + +/// Possible return codes for tree walking callback functions. +#[repr(i32)] +pub enum TreeWalkResult { + /// Continue with the traversal as normal. + Ok = 0, + /// Skip the current node (in pre-order mode). + Skip = 1, + /// Completely stop the traversal. + Abort = raw::GIT_EUSER, +} + +impl Into for TreeWalkResult { + fn into(self) -> i32 { + self as i32 + } +} + +impl Into for TreeWalkMode { + #[cfg(target_env = "msvc")] + fn into(self) -> raw::git_treewalk_mode { + self as i32 + } + #[cfg(not(target_env = "msvc"))] + fn into(self) -> raw::git_treewalk_mode { + self as u32 + } +} + +impl<'repo> Tree<'repo> { + /// Get the id (SHA1) of a repository object + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_tree_id(&*self.raw)) } + } + + /// Get the number of entries listed in this tree. + pub fn len(&self) -> usize { + unsafe { raw::git_tree_entrycount(&*self.raw) as usize } + } + + /// Return `true` if there is not entry + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator over the entries in this tree. + pub fn iter(&self) -> TreeIter { + TreeIter { range: 0..self.len(), tree: self } + } + + /// Traverse the entries in a tree and its subtrees in post or pre order. + /// The callback function will be run on each node of the tree that's + /// walked. The return code of this function will determine how the walk + /// continues. + /// + /// libgit requires that the callback be an integer, where 0 indicates a + /// successful visit, 1 skips the node, and -1 aborts the traversal completely. + /// You may opt to use the enum [`TreeWalkResult`](TreeWalkResult) instead. + /// + /// ```ignore + /// let mut ct = 0; + /// tree.walk(TreeWalkMode::PreOrder, |_, entry| { + /// assert_eq!(entry.name(), Some("foo")); + /// ct += 1; + /// TreeWalkResult::Ok + /// }).unwrap(); + /// assert_eq!(ct, 1); + /// ``` + /// + /// See [libgit documentation][1] for more information. + /// + /// [1]: https://libgit2.org/libgit2/#HEAD/group/tree/git_tree_walk + pub fn walk(&self, mode: TreeWalkMode, mut callback: C) -> Result<(), Error> + where + C: FnMut(&str, &TreeEntry) -> T, + T: Into, + { + #[allow(unused)] + struct TreeWalkCbData<'a, T: 'a> { + pub callback: &'a mut TreeWalkCb<'a, T> + } + unsafe { + let mut data = TreeWalkCbData { callback: &mut callback }; + raw::git_tree_walk( + self.raw(), + mode.into(), + treewalk_cb::, + &mut data as *mut _ as *mut c_void, + ); + Ok(()) + } + } + + /// Lookup a tree entry by SHA value. + pub fn get_id(&self, id: Oid) -> Option { + unsafe { + let ptr = raw::git_tree_entry_byid(&*self.raw(), &*id.raw()); + if ptr.is_null() { + None + } else { + Some(entry_from_raw_const(ptr)) + } + } + } + + /// Lookup a tree entry by its position in the tree + pub fn get(&self, n: usize) -> Option { + unsafe { + let ptr = raw::git_tree_entry_byindex(&*self.raw(), + n as libc::size_t); + if ptr.is_null() { + None + } else { + Some(entry_from_raw_const(ptr)) + } + } + } + + /// Lookup a tree entry by its filename + pub fn get_name(&self, filename: &str) -> Option { + let filename = CString::new(filename).unwrap(); + unsafe { + let ptr = call!(raw::git_tree_entry_byname(&*self.raw(), filename)); + if ptr.is_null() { + None + } else { + Some(entry_from_raw_const(ptr)) + } + } + } + + /// Retrieve a tree entry contained in a tree or in any of its subtrees, + /// given its relative path. + pub fn get_path(&self, path: &Path) -> Result, Error> { + let path = try!(path.into_c_string()); + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_tree_entry_bypath(&mut ret, &*self.raw(), path)); + Ok(Binding::from_raw(ret)) + } + } + + /// Casts this Tree to be usable as an `Object` + pub fn as_object(&self) -> &Object<'repo> { + unsafe { + &*(self as *const _ as *const Object<'repo>) + } + } + + /// Consumes Commit to be returned as an `Object` + pub fn into_object(self) -> Object<'repo> { + assert_eq!(mem::size_of_val(&self), mem::size_of::()); + unsafe { + mem::transmute(self) + } + } +} + +type TreeWalkCb<'a, T> = FnMut(&str, &TreeEntry) -> T + 'a; + +extern fn treewalk_cb>(root: *const c_char, entry: *const raw::git_tree_entry, payload: *mut c_void) -> c_int { + match panic::wrap(|| unsafe { + let root = match CStr::from_ptr(root).to_str() { + Ok(value) => value, + _ => return -1, + }; + let entry = entry_from_raw_const(entry); + let payload = payload as *mut &mut TreeWalkCb; + (*payload)(root, &entry).into() + }) { + Some(value) => value, + None => -1, + } +} + +impl<'repo> Binding for Tree<'repo> { + type Raw = *mut raw::git_tree; + + unsafe fn from_raw(raw: *mut raw::git_tree) -> Tree<'repo> { + Tree { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_tree { self.raw } +} + +impl<'repo> ::std::fmt::Debug for Tree<'repo> { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + f.debug_struct("Tree").field("id", &self.id()).finish() + } +} + +impl<'repo> Clone for Tree<'repo> { + fn clone(&self) -> Self { + self.as_object().clone().into_tree().ok().unwrap() + } +} + +impl<'repo> Drop for Tree<'repo> { + fn drop(&mut self) { + unsafe { raw::git_tree_free(self.raw) } + } +} + +impl<'repo, 'iter> IntoIterator for &'iter Tree<'repo> { + type Item = TreeEntry<'iter>; + type IntoIter = TreeIter<'iter>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// Create a new tree entry from the raw pointer provided. +/// +/// The lifetime of the entry is tied to the tree provided and the function +/// is unsafe because the validity of the pointer cannot be guaranteed. +pub unsafe fn entry_from_raw_const<'tree>(raw: *const raw::git_tree_entry) + -> TreeEntry<'tree> { + TreeEntry { + raw: raw as *mut raw::git_tree_entry, + owned: false, + _marker: marker::PhantomData, + } +} + +impl<'tree> TreeEntry<'tree> { + /// Get the id of the object pointed by the entry + pub fn id(&self) -> Oid { + unsafe { Binding::from_raw(raw::git_tree_entry_id(&*self.raw)) } + } + + /// Get the filename of a tree entry + /// + /// Returns `None` if the name is not valid utf-8 + pub fn name(&self) -> Option<&str> { + str::from_utf8(self.name_bytes()).ok() + } + + /// Get the filename of a tree entry + pub fn name_bytes(&self) -> &[u8] { + unsafe { + ::opt_bytes(self, raw::git_tree_entry_name(&*self.raw())).unwrap() + } + } + + /// Convert a tree entry to the object it points to. + pub fn to_object<'a>(&self, repo: &'a Repository) + -> Result, Error> { + let mut ret = ptr::null_mut(); + unsafe { + try_call!(raw::git_tree_entry_to_object(&mut ret, repo.raw(), + &*self.raw())); + Ok(Binding::from_raw(ret)) + } + } + + /// Get the type of the object pointed by the entry + pub fn kind(&self) -> Option { + ObjectType::from_raw(unsafe { raw::git_tree_entry_type(&*self.raw) }) + } + + /// Get the UNIX file attributes of a tree entry + pub fn filemode(&self) -> i32 { + unsafe { raw::git_tree_entry_filemode(&*self.raw) as i32 } + } + + /// Get the raw UNIX file attributes of a tree entry + pub fn filemode_raw(&self) -> i32 { + unsafe { raw::git_tree_entry_filemode_raw(&*self.raw) as i32 } + } + + /// Convert this entry of any lifetime into an owned signature with a static + /// lifetime. + /// + /// This will use the `Clone::clone` implementation under the hood. + pub fn to_owned(&self) -> TreeEntry<'static> { + unsafe { + let me = mem::transmute::<&TreeEntry<'tree>, &TreeEntry<'static>>(self); + me.clone() + } + } +} + +impl<'a> Binding for TreeEntry<'a> { + type Raw = *mut raw::git_tree_entry; + unsafe fn from_raw(raw: *mut raw::git_tree_entry) -> TreeEntry<'a> { + TreeEntry { + raw: raw, + owned: true, + _marker: marker::PhantomData, + } + } + fn raw(&self) -> *mut raw::git_tree_entry { self.raw } +} + +impl<'a> Clone for TreeEntry<'a> { + fn clone(&self) -> TreeEntry<'a> { + let mut ret = ptr::null_mut(); + unsafe { + assert_eq!(raw::git_tree_entry_dup(&mut ret, &*self.raw()), 0); + Binding::from_raw(ret) + } + } +} + +impl<'a> PartialOrd for TreeEntry<'a> { + fn partial_cmp(&self, other: &TreeEntry<'a>) -> Option { + Some(self.cmp(other)) + } +} +impl<'a> Ord for TreeEntry<'a> { + fn cmp(&self, other: &TreeEntry<'a>) -> Ordering { + match unsafe { raw::git_tree_entry_cmp(&*self.raw(), &*other.raw()) } { + 0 => Ordering::Equal, + n if n < 0 => Ordering::Less, + _ => Ordering::Greater, + } + } +} + +impl<'a> PartialEq for TreeEntry<'a> { + fn eq(&self, other: &TreeEntry<'a>) -> bool { + self.cmp(other) == Ordering::Equal + } +} +impl<'a> Eq for TreeEntry<'a> {} + +impl<'a> Drop for TreeEntry<'a> { + fn drop(&mut self) { + if self.owned { + unsafe { raw::git_tree_entry_free(self.raw) } + } + } +} + +impl<'tree> Iterator for TreeIter<'tree> { + type Item = TreeEntry<'tree>; + fn next(&mut self) -> Option> { + self.range.next().and_then(|i| self.tree.get(i)) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} +impl<'tree> DoubleEndedIterator for TreeIter<'tree> { + fn next_back(&mut self) -> Option> { + self.range.next_back().and_then(|i| self.tree.get(i)) + } +} +impl<'tree> ExactSizeIterator for TreeIter<'tree> {} + +#[cfg(test)] +mod tests { + use {Repository,Tree,TreeEntry,ObjectType,Object}; + use super::{TreeWalkMode, TreeWalkResult}; + use tempdir::TempDir; + use std::fs::File; + use std::io::prelude::*; + use std::path::Path; + + pub struct TestTreeIter<'a> { + entries: Vec>, + repo: &'a Repository, + } + + impl<'a> Iterator for TestTreeIter<'a> { + type Item = TreeEntry<'a>; + + fn next(&mut self) -> Option > { + if self.entries.is_empty() { + None + } else { + let entry = self.entries.remove(0); + + match entry.kind() { + Some(ObjectType::Tree) => { + let obj: Object<'a> = entry.to_object(self.repo).unwrap(); + + let tree: &Tree<'a> = obj.as_tree().unwrap(); + + for entry in tree.iter() { + self.entries.push(entry.to_owned()); + } + } + _ => {} + } + + Some(entry) + } + } + } + + fn tree_iter<'repo>(tree: &Tree<'repo>, repo: &'repo Repository) + -> TestTreeIter<'repo> { + let mut initial = vec![]; + + for entry in tree.iter() { + initial.push(entry.to_owned()); + } + + TestTreeIter { + entries: initial, + repo: repo, + } + } + + #[test] + fn smoke_tree_iter() { + let (td, repo) = ::test::repo_init(); + + setup_repo(&td, &repo); + + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + let commit = repo.find_commit(target).unwrap(); + + let tree = repo.find_tree(commit.tree_id()).unwrap(); + assert_eq!(tree.id(), commit.tree_id()); + assert_eq!(tree.len(), 1); + + for entry in tree_iter(&tree, &repo) { + println!("iter entry {:?}", entry.name()); + } + } + + fn setup_repo(td: &TempDir, repo: &Repository) { + let mut index = repo.index().unwrap(); + File::create(&td.path().join("foo")).unwrap().write_all(b"foo").unwrap(); + index.add_path(Path::new("foo")).unwrap(); + let id = index.write_tree().unwrap(); + let sig = repo.signature().unwrap(); + let tree = repo.find_tree(id).unwrap(); + let parent = repo.find_commit(repo.head().unwrap().target() + .unwrap()).unwrap(); + repo.commit(Some("HEAD"), &sig, &sig, "another commit", + &tree, &[&parent]).unwrap(); + } + + #[test] + fn smoke() { + let (td, repo) = ::test::repo_init(); + + setup_repo(&td, &repo); + + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + let commit = repo.find_commit(target).unwrap(); + + let tree = repo.find_tree(commit.tree_id()).unwrap(); + assert_eq!(tree.id(), commit.tree_id()); + assert_eq!(tree.len(), 1); + { + let e1 = tree.get(0).unwrap(); + assert!(e1 == tree.get_id(e1.id()).unwrap()); + assert!(e1 == tree.get_name("foo").unwrap()); + assert!(e1 == tree.get_path(Path::new("foo")).unwrap()); + assert_eq!(e1.name(), Some("foo")); + e1.to_object(&repo).unwrap(); + } + tree.into_object(); + + repo.find_object(commit.tree_id(), None).unwrap().as_tree().unwrap(); + repo.find_object(commit.tree_id(), None).unwrap().into_tree().ok().unwrap(); + } + + #[test] + fn tree_walk() { + let (td, repo) = ::test::repo_init(); + + setup_repo(&td, &repo); + + let head = repo.head().unwrap(); + let target = head.target().unwrap(); + let commit = repo.find_commit(target).unwrap(); + let tree = repo.find_tree(commit.tree_id()).unwrap(); + + let mut ct = 0; + tree.walk(TreeWalkMode::PreOrder, |_, entry| { + assert_eq!(entry.name(), Some("foo")); + ct += 1; + 0 + }).unwrap(); + assert_eq!(ct, 1); + + let mut ct = 0; + tree.walk(TreeWalkMode::PreOrder, |_, entry| { + assert_eq!(entry.name(), Some("foo")); + ct += 1; + TreeWalkResult::Ok + }).unwrap(); + assert_eq!(ct, 1); + } +} diff --git a/git2/src/treebuilder.rs b/git2/src/treebuilder.rs new file mode 100644 index 000000000..e8ea1057c --- /dev/null +++ b/git2/src/treebuilder.rs @@ -0,0 +1,199 @@ +use std::marker; +use std::ptr; + +use libc::{c_int, c_void}; + +use {panic, raw, tree, Error, Oid, Repository, TreeEntry}; +use util::{Binding, IntoCString}; + +/// Constructor for in-memory trees +pub struct TreeBuilder<'repo> { + raw: *mut raw::git_treebuilder, + _marker: marker::PhantomData<&'repo Repository>, +} + +impl<'repo> TreeBuilder<'repo> { + /// Clear all the entries in the builder + pub fn clear(&mut self) { + unsafe { raw::git_treebuilder_clear(self.raw) } + } + + /// Get the number of entries + pub fn len(&self) -> usize { + unsafe { raw::git_treebuilder_entrycount(self.raw) as usize } + } + + /// Return `true` if there is no entry + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get en entry from the builder from its filename + pub fn get

(&self, filename: P) -> Result, Error> + where P: IntoCString + { + let filename = try!(filename.into_c_string()); + unsafe { + let ret = raw::git_treebuilder_get(self.raw, filename.as_ptr()); + if ret.is_null() { + Ok(None) + } else { + Ok(Some(tree::entry_from_raw_const(ret))) + } + } + } + + /// Add or update an entry in the builder + /// + /// No attempt is made to ensure that the provided Oid points to + /// an object of a reasonable type (or any object at all). + /// + /// The mode given must be one of 0o040000, 0o100644, 0o100755, 0o120000 or + /// 0o160000 currently. + pub fn insert(&mut self, filename: P, oid: Oid, + filemode: i32) -> Result { + let filename = try!(filename.into_c_string()); + let filemode = filemode as raw::git_filemode_t; + + let mut ret = ptr::null(); + unsafe { + try_call!(raw::git_treebuilder_insert(&mut ret, self.raw, filename, + oid.raw(), filemode)); + Ok(tree::entry_from_raw_const(ret)) + } + } + + /// Remove an entry from the builder by its filename + pub fn remove(&mut self, filename: P) -> Result<(), Error> { + let filename = try!(filename.into_c_string()); + unsafe { + try_call!(raw::git_treebuilder_remove(self.raw, filename)); + } + Ok(()) + } + + /// Selectively remove entries from the tree + /// + /// Values for which the filter returns `true` will be kept. Note + /// that this behavior is different from the libgit2 C interface. + pub fn filter(&mut self, mut filter: F) + where F: FnMut(&TreeEntry) -> bool + { + let mut cb: &mut FilterCb = &mut filter; + let ptr = &mut cb as *mut _; + unsafe { + raw::git_treebuilder_filter(self.raw, filter_cb, ptr as *mut _); + panic::check(); + } + } + + /// Write the contents of the TreeBuilder as a Tree object and + /// return its Oid + pub fn write(&self) -> Result { + let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] }; + unsafe { + try_call!(raw::git_treebuilder_write(&mut raw, self.raw())); + Ok(Binding::from_raw(&raw as *const _)) + } + } +} + +type FilterCb<'a> = FnMut(&TreeEntry) -> bool + 'a; + +extern fn filter_cb(entry: *const raw::git_tree_entry, + payload: *mut c_void) -> c_int { + let ret = panic::wrap(|| unsafe { + // There's no way to return early from git_treebuilder_filter. + if panic::panicked() { + true + } else { + let entry = tree::entry_from_raw_const(entry); + let payload = payload as *mut &mut FilterCb; + (*payload)(&entry) + } + }); + if ret == Some(false) {1} else {0} +} + +impl<'repo> Binding for TreeBuilder<'repo> { + type Raw = *mut raw::git_treebuilder; + + unsafe fn from_raw(raw: *mut raw::git_treebuilder) -> TreeBuilder<'repo> { + TreeBuilder { raw: raw, _marker: marker::PhantomData } + } + fn raw(&self) -> *mut raw::git_treebuilder { self.raw } +} + +impl<'repo> Drop for TreeBuilder<'repo> { + fn drop(&mut self) { + unsafe { raw::git_treebuilder_free(self.raw) } + } +} + +#[cfg(test)] +mod tests { + use ObjectType; + + #[test] + fn smoke() { + let (_td, repo) = ::test::repo_init(); + + let mut builder = repo.treebuilder(None).unwrap(); + assert_eq!(builder.len(), 0); + let blob = repo.blob(b"data").unwrap(); + { + let entry = builder.insert("a", blob, 0o100644).unwrap(); + assert_eq!(entry.kind(), Some(ObjectType::Blob)); + } + builder.insert("b", blob, 0o100644).unwrap(); + assert_eq!(builder.len(), 2); + builder.remove("a").unwrap(); + assert_eq!(builder.len(), 1); + assert_eq!(builder.get("b").unwrap().unwrap().id(), blob); + builder.clear(); + assert_eq!(builder.len(), 0); + } + + #[test] + fn write() { + let (_td, repo) = ::test::repo_init(); + + let mut builder = repo.treebuilder(None).unwrap(); + let data = repo.blob(b"data").unwrap(); + builder.insert("name", data, 0o100644).unwrap(); + let tree = builder.write().unwrap(); + let tree = repo.find_tree(tree).unwrap(); + let entry = tree.get(0).unwrap(); + assert_eq!(entry.name(), Some("name")); + let blob = entry.to_object(&repo).unwrap(); + let blob = blob.as_blob().unwrap(); + assert_eq!(blob.content(), b"data"); + + let builder = repo.treebuilder(Some(&tree)).unwrap(); + assert_eq!(builder.len(), 1); + } + + #[test] + fn filter() { + let (_td, repo) = ::test::repo_init(); + + let mut builder = repo.treebuilder(None).unwrap(); + let blob = repo.blob(b"data").unwrap(); + let tree = { + let head = repo.head().unwrap() + .peel(ObjectType::Commit).unwrap(); + let head = head.as_commit().unwrap(); + head.tree_id() + }; + builder.insert("blob", blob, 0o100644).unwrap(); + builder.insert("dir", tree, 0o040000).unwrap(); + builder.insert("dir2", tree, 0o040000).unwrap(); + + builder.filter(|_| true); + assert_eq!(builder.len(), 3); + builder.filter(|e| e.kind().unwrap() != ObjectType::Blob); + assert_eq!(builder.len(), 2); + builder.filter(|_| false); + assert_eq!(builder.len(), 0); + } +} diff --git a/git2/src/util.rs b/git2/src/util.rs new file mode 100644 index 000000000..e111628ea --- /dev/null +++ b/git2/src/util.rs @@ -0,0 +1,152 @@ +use std::ffi::{CString, OsStr, OsString}; +use std::iter::IntoIterator; +use std::path::{Path, PathBuf}; +use libc::{c_char, size_t}; + +use {raw, Error}; + +#[doc(hidden)] +pub trait IsNull { + fn is_ptr_null(&self) -> bool; +} +impl IsNull for *const T { + fn is_ptr_null(&self) -> bool { + self.is_null() + } +} +impl IsNull for *mut T { + fn is_ptr_null(&self) -> bool { + self.is_null() + } +} + +#[doc(hidden)] +pub trait Binding: Sized { + type Raw; + + unsafe fn from_raw(raw: Self::Raw) -> Self; + fn raw(&self) -> Self::Raw; + + unsafe fn from_raw_opt(raw: T) -> Option + where T: Copy + IsNull, Self: Binding + { + if raw.is_ptr_null() { + None + } else { + Some(Binding::from_raw(raw)) + } + } +} + +pub fn iter2cstrs(iter: I) -> Result<(Vec, Vec<*const c_char>, + raw::git_strarray), Error> + where T: IntoCString, I: IntoIterator +{ + let cstrs: Vec<_> = try!(iter.into_iter().map(|i| i.into_c_string()).collect()); + let ptrs = cstrs.iter().map(|i| i.as_ptr()).collect::>(); + let raw = raw::git_strarray { + strings: ptrs.as_ptr() as *mut _, + count: ptrs.len() as size_t, + }; + Ok((cstrs, ptrs, raw)) +} + +#[cfg(unix)] +pub fn bytes2path(b: &[u8]) -> &Path { + use std::os::unix::prelude::*; + Path::new(OsStr::from_bytes(b)) +} +#[cfg(windows)] +pub fn bytes2path(b: &[u8]) -> &Path { + use std::str; + Path::new(str::from_utf8(b).unwrap()) +} + +/// A class of types that can be converted to C strings. +/// +/// These types are represented internally as byte slices and it is quite rare +/// for them to contain an interior 0 byte. +pub trait IntoCString { + /// Consume this container, converting it into a CString + fn into_c_string(self) -> Result; +} + +impl<'a, T: IntoCString + Clone> IntoCString for &'a T { + fn into_c_string(self) -> Result { + self.clone().into_c_string() + } +} + +impl<'a> IntoCString for &'a str { + fn into_c_string(self) -> Result { + Ok(try!(CString::new(self))) + } +} + +impl IntoCString for String { + fn into_c_string(self) -> Result { + Ok(try!(CString::new(self.into_bytes()))) + } +} + +impl IntoCString for CString { + fn into_c_string(self) -> Result { Ok(self) } +} + +impl<'a> IntoCString for &'a Path { + fn into_c_string(self) -> Result { + let s: &OsStr = self.as_ref(); + s.into_c_string() + } +} + +impl IntoCString for PathBuf { + fn into_c_string(self) -> Result { + let s: OsString = self.into(); + s.into_c_string() + } +} + +impl<'a> IntoCString for &'a OsStr { + fn into_c_string(self) -> Result { + self.to_os_string().into_c_string() + } +} + +impl IntoCString for OsString { + #[cfg(unix)] + fn into_c_string(self) -> Result { + use std::os::unix::prelude::*; + let s: &OsStr = self.as_ref(); + Ok(try!(CString::new(s.as_bytes()))) + } + #[cfg(windows)] + fn into_c_string(self) -> Result { + match self.to_str() { + Some(s) => s.into_c_string(), + None => Err(Error::from_str("only valid unicode paths are accepted \ + on windows")), + } + } +} + +impl<'a> IntoCString for &'a [u8] { + fn into_c_string(self) -> Result { + Ok(try!(CString::new(self))) + } +} + +impl IntoCString for Vec { + fn into_c_string(self) -> Result { + Ok(try!(CString::new(self))) + } +} + +pub fn into_opt_c_string(opt_s: Option) -> Result, Error> + where S: IntoCString +{ + match opt_s { + None => Ok(None), + Some(s) => Ok(Some(try!(s.into_c_string()))), + } +} diff --git a/glob/.cargo-checksum.json b/glob/.cargo-checksum.json new file mode 100644 index 000000000..9a6ec5217 --- /dev/null +++ b/glob/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"} \ No newline at end of file diff --git a/glob/Cargo.toml b/glob/Cargo.toml new file mode 100644 index 000000000..48ba71906 --- /dev/null +++ b/glob/Cargo.toml @@ -0,0 +1,15 @@ +[package] + +name = "glob" +version = "0.2.11" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +homepage = "https://github.com/rust-lang/glob" +repository = "https://github.com/rust-lang/glob" +documentation = "https://doc.rust-lang.org/glob" +description = """ +Support for matching file paths against Unix shell style patterns. +""" + +[dev-dependencies] +tempdir = "0.3" diff --git a/glob/LICENSE-APACHE b/glob/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/glob/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/glob/LICENSE-MIT b/glob/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/glob/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/glob/README.md b/glob/README.md new file mode 100644 index 000000000..86b112da6 --- /dev/null +++ b/glob/README.md @@ -0,0 +1,24 @@ +glob +==== + +Support for matching file paths against Unix shell style patterns. + +[![Build Status](https://travis-ci.org/rust-lang-nursery/glob.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/glob) + +[Documentation](https://doc.rust-lang.org/glob) + +## Usage + +To use `glob`, add this to your `Cargo.toml`: + +```toml +[dependencies] +glob = "*" +``` + +And add this to your crate root: + +```rust +extern crate glob; +``` + diff --git a/glob/src/lib.rs b/glob/src/lib.rs new file mode 100644 index 000000000..a26b99689 --- /dev/null +++ b/glob/src/lib.rs @@ -0,0 +1,1312 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for matching file paths against Unix shell style patterns. +//! +//! The `glob` and `glob_with` functions, in concert with the `Paths` +//! type, allow querying the filesystem for all files that match a particular +//! pattern - just like the libc `glob` function (for an example see the `glob` +//! documentation). The methods on the `Pattern` type provide functionality +//! for checking if individual paths match a particular pattern - in a similar +//! manner to the libc `fnmatch` function +//! For consistency across platforms, and for Windows support, this module +//! is implemented entirely in Rust rather than deferring to the libc +//! `glob`/`fnmatch` functions. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/glob/")] +#![cfg_attr(all(test, windows), feature(std_misc))] + +use std::ascii::AsciiExt; +use std::cmp; +use std::fmt; +use std::fs; +use std::io::prelude::*; +use std::io; +use std::path::{self, Path, PathBuf, Component}; +use std::str::FromStr; +use std::error::Error; + +use PatternToken::{Char, AnyChar, AnySequence, AnyRecursiveSequence, AnyWithin}; +use PatternToken::AnyExcept; +use CharSpecifier::{SingleChar, CharRange}; +use MatchResult::{Match, SubPatternDoesntMatch, EntirePatternDoesntMatch}; + +/// An iterator that yields `Path`s from the filesystem that match a particular +/// pattern. +/// +/// Note that it yields `GlobResult` in order to report any `IoErrors` that may +/// arise during iteration. If a directory matches but is unreadable, +/// thereby preventing its contents from being checked for matches, a +/// `GlobError` is returned to express this. +/// +/// See the `glob` function for more details. +pub struct Paths { + dir_patterns: Vec, + require_dir: bool, + options: MatchOptions, + todo: Vec>, + scope: Option, +} + +/// Return an iterator that produces all the Paths that match the given pattern, +/// which may be absolute or relative to the current working directory. +/// +/// This may return an error if the pattern is invalid. +/// +/// This method uses the default match options and is equivalent to calling +/// `glob_with(pattern, MatchOptions::new())`. Use `glob_with` directly if you +/// want to use non-default match options. +/// +/// When iterating, each result is a `GlobResult` which expresses the +/// possibility that there was an `IoError` when attempting to read the contents +/// of the matched path. In other words, each item returned by the iterator +/// will either be an `Ok(Path)` if the path matched, or an `Err(GlobError)` if +/// the path (partially) matched _but_ its contents could not be read in order +/// to determine if its contents matched. +/// +/// See the `Paths` documentation for more information. +/// +/// # Example +/// +/// Consider a directory `/media/pictures` containing only the files +/// `kittens.jpg`, `puppies.jpg` and `hamsters.gif`: +/// +/// ```rust +/// use glob::glob; +/// +/// for entry in glob("/media/pictures/*.jpg").unwrap() { +/// match entry { +/// Ok(path) => println!("{:?}", path.display()), +/// +/// // if the path matched but was unreadable, +/// // thereby preventing its contents from matching +/// Err(e) => println!("{:?}", e), +/// } +/// } +/// ``` +/// +/// The above code will print: +/// +/// ```ignore +/// /media/pictures/kittens.jpg +/// /media/pictures/puppies.jpg +/// ``` +/// +/// If you want to ignore unreadable paths, you can use something like +/// `filter_map`: +/// +/// ```rust +/// use glob::glob; +/// use std::result::Result; +/// +/// for path in glob("/media/pictures/*.jpg").unwrap().filter_map(Result::ok) { +/// println!("{}", path.display()); +/// } +/// ``` +/// +pub fn glob(pattern: &str) -> Result { + glob_with(pattern, &MatchOptions::new()) +} + +/// Return an iterator that produces all the Paths that match the given pattern, +/// which may be absolute or relative to the current working directory. +/// +/// This may return an error if the pattern is invalid. +/// +/// This function accepts Unix shell style patterns as described by +/// `Pattern::new(..)`. The options given are passed through unchanged to +/// `Pattern::matches_with(..)` with the exception that +/// `require_literal_separator` is always set to `true` regardless of the value +/// passed to this function. +/// +/// Paths are yielded in alphabetical order. +pub fn glob_with(pattern: &str, options: &MatchOptions) -> Result { + // make sure that the pattern is valid first, else early return with error + let _compiled = try!(Pattern::new(pattern)); + + #[cfg(windows)] + fn check_windows_verbatim(p: &Path) -> bool { + use std::path::Prefix; + match p.components().next() { + Some(Component::Prefix(ref p)) => p.kind().is_verbatim(), + _ => false, + } + } + #[cfg(not(windows))] + fn check_windows_verbatim(_: &Path) -> bool { + false + } + + #[cfg(windows)] + fn to_scope(p: &Path) -> PathBuf { + // FIXME handle volume relative paths here + p.to_path_buf() + } + #[cfg(not(windows))] + fn to_scope(p: &Path) -> PathBuf { + p.to_path_buf() + } + + let mut components = Path::new(pattern).components().peekable(); + loop { + match components.peek() { + Some(&Component::Prefix(..)) | + Some(&Component::RootDir) => { + components.next(); + } + _ => break, + } + } + let rest = components.map(|s| s.as_os_str()).collect::(); + let normalized_pattern = Path::new(pattern).iter().collect::(); + let root_len = normalized_pattern.to_str().unwrap().len() - rest.to_str().unwrap().len(); + let root = if root_len > 0 { + Some(Path::new(&pattern[..root_len])) + } else { + None + }; + + if root_len > 0 && check_windows_verbatim(root.unwrap()) { + // FIXME: How do we want to handle verbatim paths? I'm inclined to + // return nothing, since we can't very well find all UNC shares with a + // 1-letter server name. + return Ok(Paths { + dir_patterns: Vec::new(), + require_dir: false, + options: options.clone(), + todo: Vec::new(), + scope: None, + }); + } + + let scope = root.map(to_scope).unwrap_or_else(|| PathBuf::from(".")); + + let mut dir_patterns = Vec::new(); + let components = pattern[cmp::min(root_len, pattern.len())..] + .split_terminator(path::is_separator); + + for component in components { + let compiled = try!(Pattern::new(component)); + dir_patterns.push(compiled); + } + + if root_len == pattern.len() { + dir_patterns.push(Pattern { + original: "".to_string(), + tokens: Vec::new(), + is_recursive: false, + }); + } + + let require_dir = pattern.chars().next_back().map(path::is_separator) == Some(true); + let todo = Vec::new(); + + Ok(Paths { + dir_patterns: dir_patterns, + require_dir: require_dir, + options: options.clone(), + todo: todo, + scope: Some(scope), + }) +} + +/// A glob iteration error. +/// +/// This is typically returned when a particular path cannot be read +/// to determine if its contents match the glob pattern. This is possible +/// if the program lacks the permissions, for example. +#[derive(Debug)] +pub struct GlobError { + path: PathBuf, + error: io::Error, +} + +impl GlobError { + /// The Path that the error corresponds to. + pub fn path(&self) -> &Path { + &self.path + } + + /// The error in question. + pub fn error(&self) -> &io::Error { + &self.error + } +} + +impl Error for GlobError { + fn description(&self) -> &str { + self.error.description() + } + fn cause(&self) -> Option<&Error> { + Some(&self.error) + } +} + +impl fmt::Display for GlobError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, + "attempting to read `{}` resulted in an error: {}", + self.path.display(), + self.error) + } +} + +fn is_dir(p: &Path) -> bool { + fs::metadata(p).map(|m| m.is_dir()).unwrap_or(false) +} + +/// An alias for a glob iteration result. +/// +/// This represents either a matched path or a glob iteration error, +/// such as failing to read a particular directory's contents. +pub type GlobResult = Result; + +impl Iterator for Paths { + type Item = GlobResult; + + fn next(&mut self) -> Option { + // the todo buffer hasn't been initialized yet, so it's done at this + // point rather than in glob() so that the errors are unified that is, + // failing to fill the buffer is an iteration error construction of the + // iterator (i.e. glob()) only fails if it fails to compile the Pattern + if let Some(scope) = self.scope.take() { + if self.dir_patterns.len() > 0 { + // Shouldn't happen, but we're using -1 as a special index. + assert!(self.dir_patterns.len() < !0 as usize); + + fill_todo(&mut self.todo, &self.dir_patterns, 0, &scope, &self.options); + } + } + + loop { + if self.dir_patterns.is_empty() || self.todo.is_empty() { + return None; + } + + let (path, mut idx) = match self.todo.pop().unwrap() { + Ok(pair) => pair, + Err(e) => return Some(Err(e)), + }; + + // idx -1: was already checked by fill_todo, maybe path was '.' or + // '..' that we can't match here because of normalization. + if idx == !0 as usize { + if self.require_dir && !is_dir(&path) { + continue; + } + return Some(Ok(path)); + } + + if self.dir_patterns[idx].is_recursive { + let mut next = idx; + + // collapse consecutive recursive patterns + while (next + 1) < self.dir_patterns.len() && + self.dir_patterns[next + 1].is_recursive { + next += 1; + } + + if is_dir(&path) { + // the path is a directory, so it's a match + + // push this directory's contents + fill_todo(&mut self.todo, + &self.dir_patterns, + next, + &path, + &self.options); + + if next == self.dir_patterns.len() - 1 { + // pattern ends in recursive pattern, so return this + // directory as a result + return Some(Ok(path)); + } else { + // advanced to the next pattern for this path + idx = next + 1; + } + } else if next != self.dir_patterns.len() - 1 { + // advanced to the next pattern for this path + idx = next + 1; + } else { + // not a directory and it's the last pattern, meaning no match + continue; + } + } + + // not recursive, so match normally + if self.dir_patterns[idx].matches_with({ + match path.file_name().and_then(|s| s.to_str()) { + // FIXME (#9639): How do we handle non-utf8 filenames? + // Ignore them for now Ideally we'd still match them + // against a * + None => continue, + Some(x) => x + } + }, &self.options) { + if idx == self.dir_patterns.len() - 1 { + // it is not possible for a pattern to match a directory + // *AND* its children so we don't need to check the + // children + + if !self.require_dir || is_dir(&path) { + return Some(Ok(path)); + } + } else { + fill_todo(&mut self.todo, &self.dir_patterns, + idx + 1, &path, &self.options); + } + } + } + } +} + +/// A pattern parsing error. +#[derive(Debug)] +#[allow(missing_copy_implementations)] +pub struct PatternError { + /// The approximate character index of where the error occurred. + pub pos: usize, + + /// A message describing the error. + pub msg: &'static str, +} + +impl Error for PatternError { + fn description(&self) -> &str { + self.msg + } +} + +impl fmt::Display for PatternError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, + "Pattern syntax error near position {}: {}", + self.pos, + self.msg) + } +} + +/// A compiled Unix shell style pattern. +/// +/// `?` matches any single character +/// +/// `*` matches any (possibly empty) sequence of characters +/// +/// `**` matches the current directory and arbitrary subdirectories. This +/// sequence **must** form a single path component, so both `**a` and `b**` are +/// invalid and will result in an error. A sequence of more than two +/// consecutive `*` characters is also invalid. +/// +/// `[...]` matches any character inside the brackets. +/// Character sequences can also specify ranges +/// of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any +/// character between 0 and 9 inclusive. An unclosed bracket is invalid. +/// +/// `[!...]` is the negation of `[...]`, i.e. it matches any characters **not** +/// in the brackets. +/// +/// The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets +/// (e.g. `[?]`). When a `]` occurs immediately following `[` or `[!` then +/// it is interpreted as being part of, rather then ending, the character +/// set, so `]` and NOT `]` can be matched by `[]]` and `[!]]` respectively. +/// The `-` character can be specified inside a character sequence pattern by +/// placing it at the start or the end, e.g. `[abc-]`. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] +pub struct Pattern { + original: String, + tokens: Vec, + is_recursive: bool, +} + +/// Show the original glob pattern. +impl fmt::Display for Pattern { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.original.fmt(f) + } +} + +impl FromStr for Pattern { + type Err = PatternError; + + fn from_str(s: &str) -> Result { + Pattern::new(s) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum PatternToken { + Char(char), + AnyChar, + AnySequence, + AnyRecursiveSequence, + AnyWithin(Vec), + AnyExcept(Vec), +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum CharSpecifier { + SingleChar(char), + CharRange(char, char), +} + +#[derive(Copy, Clone, PartialEq)] +enum MatchResult { + Match, + SubPatternDoesntMatch, + EntirePatternDoesntMatch, +} + +const ERROR_WILDCARDS: &'static str = "wildcards are either regular `*` or recursive `**`"; +const ERROR_RECURSIVE_WILDCARDS: &'static str = "recursive wildcards must form a single path \ + component"; +const ERROR_INVALID_RANGE: &'static str = "invalid range pattern"; + +impl Pattern { + /// This function compiles Unix shell style patterns. + /// + /// An invalid glob pattern will yield an error. + pub fn new(pattern: &str) -> Result { + + let chars = pattern.chars().collect::>(); + let mut tokens = Vec::new(); + let mut is_recursive = false; + let mut i = 0; + + while i < chars.len() { + match chars[i] { + '?' => { + tokens.push(AnyChar); + i += 1; + } + '*' => { + let old = i; + + while i < chars.len() && chars[i] == '*' { + i += 1; + } + + let count = i - old; + + if count > 2 { + return Err(PatternError { + pos: old + 2, + msg: ERROR_WILDCARDS, + }); + } else if count == 2 { + // ** can only be an entire path component + // i.e. a/**/b is valid, but a**/b or a/**b is not + // invalid matches are treated literally + let is_valid = if i == 2 || path::is_separator(chars[i - count - 1]) { + // it ends in a '/' + if i < chars.len() && path::is_separator(chars[i]) { + i += 1; + true + // or the pattern ends here + // this enables the existing globbing mechanism + } else if i == chars.len() { + true + // `**` ends in non-separator + } else { + return Err(PatternError { + pos: i, + msg: ERROR_RECURSIVE_WILDCARDS, + }); + } + // `**` begins with non-separator + } else { + return Err(PatternError { + pos: old - 1, + msg: ERROR_RECURSIVE_WILDCARDS, + }); + }; + + let tokens_len = tokens.len(); + + if is_valid { + // collapse consecutive AnyRecursiveSequence to a + // single one + if !(tokens_len > 1 && tokens[tokens_len - 1] == AnyRecursiveSequence) { + is_recursive = true; + tokens.push(AnyRecursiveSequence); + } + } + } else { + tokens.push(AnySequence); + } + } + '[' => { + + if i + 4 <= chars.len() && chars[i + 1] == '!' { + match chars[i + 3..].iter().position(|x| *x == ']') { + None => (), + Some(j) => { + let chars = &chars[i + 2..i + 3 + j]; + let cs = parse_char_specifiers(chars); + tokens.push(AnyExcept(cs)); + i += j + 4; + continue; + } + } + } else if i + 3 <= chars.len() && chars[i + 1] != '!' { + match chars[i + 2..].iter().position(|x| *x == ']') { + None => (), + Some(j) => { + let cs = parse_char_specifiers(&chars[i + 1..i + 2 + j]); + tokens.push(AnyWithin(cs)); + i += j + 3; + continue; + } + } + } + + // if we get here then this is not a valid range pattern + return Err(PatternError { + pos: i, + msg: ERROR_INVALID_RANGE, + }); + } + c => { + tokens.push(Char(c)); + i += 1; + } + } + } + + Ok(Pattern { + tokens: tokens, + original: pattern.to_string(), + is_recursive: is_recursive, + }) + } + + /// Escape metacharacters within the given string by surrounding them in + /// brackets. The resulting string will, when compiled into a `Pattern`, + /// match the input string and nothing else. + pub fn escape(s: &str) -> String { + let mut escaped = String::new(); + for c in s.chars() { + match c { + // note that ! does not need escaping because it is only special + // inside brackets + '?' | '*' | '[' | ']' => { + escaped.push('['); + escaped.push(c); + escaped.push(']'); + } + c => { + escaped.push(c); + } + } + } + escaped + } + + /// Return if the given `str` matches this `Pattern` using the default + /// match options (i.e. `MatchOptions::new()`). + /// + /// # Example + /// + /// ```rust + /// use glob::Pattern; + /// + /// assert!(Pattern::new("c?t").unwrap().matches("cat")); + /// assert!(Pattern::new("k[!e]tteh").unwrap().matches("kitteh")); + /// assert!(Pattern::new("d*g").unwrap().matches("doog")); + /// ``` + pub fn matches(&self, str: &str) -> bool { + self.matches_with(str, &MatchOptions::new()) + } + + /// Return if the given `Path`, when converted to a `str`, matches this + /// `Pattern` using the default match options (i.e. `MatchOptions::new()`). + pub fn matches_path(&self, path: &Path) -> bool { + // FIXME (#9639): This needs to handle non-utf8 paths + path.to_str().map_or(false, |s| self.matches(s)) + } + + /// Return if the given `str` matches this `Pattern` using the specified + /// match options. + pub fn matches_with(&self, str: &str, options: &MatchOptions) -> bool { + self.matches_from(true, str.chars(), 0, options) == Match + } + + /// Return if the given `Path`, when converted to a `str`, matches this + /// `Pattern` using the specified match options. + pub fn matches_path_with(&self, path: &Path, options: &MatchOptions) -> bool { + // FIXME (#9639): This needs to handle non-utf8 paths + path.to_str().map_or(false, |s| self.matches_with(s, options)) + } + + /// Access the original glob pattern. + pub fn as_str<'a>(&'a self) -> &'a str { + &self.original + } + + fn matches_from(&self, + mut follows_separator: bool, + mut file: std::str::Chars, + i: usize, + options: &MatchOptions) + -> MatchResult { + + for (ti, token) in self.tokens[i..].iter().enumerate() { + match *token { + AnySequence | AnyRecursiveSequence => { + // ** must be at the start. + debug_assert!(match *token { + AnyRecursiveSequence => follows_separator, + _ => true, + }); + + // Empty match + match self.matches_from(follows_separator, file.clone(), i + ti + 1, options) { + SubPatternDoesntMatch => (), // keep trying + m => return m, + }; + + while let Some(c) = file.next() { + if follows_separator && options.require_literal_leading_dot && c == '.' { + return SubPatternDoesntMatch; + } + follows_separator = path::is_separator(c); + match *token { + AnyRecursiveSequence if !follows_separator => continue, + AnySequence if options.require_literal_separator && + follows_separator => return SubPatternDoesntMatch, + _ => (), + } + match self.matches_from(follows_separator, + file.clone(), + i + ti + 1, + options) { + SubPatternDoesntMatch => (), // keep trying + m => return m, + } + } + } + _ => { + let c = match file.next() { + Some(c) => c, + None => return EntirePatternDoesntMatch, + }; + + let is_sep = path::is_separator(c); + + if !match *token { + AnyChar | AnyWithin(..) | AnyExcept(..) + if (options.require_literal_separator && is_sep) || + (follows_separator && options.require_literal_leading_dot && + c == '.') => false, + AnyChar => true, + AnyWithin(ref specifiers) => in_char_specifiers(&specifiers, c, options), + AnyExcept(ref specifiers) => !in_char_specifiers(&specifiers, c, options), + Char(c2) => chars_eq(c, c2, options.case_sensitive), + AnySequence | AnyRecursiveSequence => unreachable!(), + } { + return SubPatternDoesntMatch; + } + follows_separator = is_sep; + } + } + } + + // Iter is fused. + if file.next().is_none() { + Match + } else { + SubPatternDoesntMatch + } + } +} + +// Fills `todo` with paths under `path` to be matched by `patterns[idx]`, +// special-casing patterns to match `.` and `..`, and avoiding `readdir()` +// calls when there are no metacharacters in the pattern. +fn fill_todo(todo: &mut Vec>, + patterns: &[Pattern], + idx: usize, + path: &Path, + options: &MatchOptions) { + // convert a pattern that's just many Char(_) to a string + fn pattern_as_str(pattern: &Pattern) -> Option { + let mut s = String::new(); + for token in pattern.tokens.iter() { + match *token { + Char(c) => s.push(c), + _ => return None, + } + } + return Some(s); + } + + let add = |todo: &mut Vec<_>, next_path: PathBuf| { + if idx + 1 == patterns.len() { + // We know it's good, so don't make the iterator match this path + // against the pattern again. In particular, it can't match + // . or .. globs since these never show up as path components. + todo.push(Ok((next_path, !0 as usize))); + } else { + fill_todo(todo, patterns, idx + 1, &next_path, options); + } + }; + + let pattern = &patterns[idx]; + let is_dir = is_dir(path); + let curdir = path == Path::new("."); + match pattern_as_str(pattern) { + Some(s) => { + // This pattern component doesn't have any metacharacters, so we + // don't need to read the current directory to know where to + // continue. So instead of passing control back to the iterator, + // we can just check for that one entry and potentially recurse + // right away. + let special = "." == s || ".." == s; + let next_path = if curdir { + PathBuf::from(s) + } else { + path.join(&s) + }; + if (special && is_dir) || (!special && fs::metadata(&next_path).is_ok()) { + add(todo, next_path); + } + } + None if is_dir => { + let dirs = fs::read_dir(path).and_then(|d| { + d.map(|e| { + e.map(|e| { + if curdir { + PathBuf::from(e.path().file_name().unwrap()) + } else { + e.path() + } + }) + }) + .collect::, _>>() + }); + match dirs { + Ok(mut children) => { + children.sort_by(|p1, p2| p2.file_name().cmp(&p1.file_name())); + todo.extend(children.into_iter().map(|x| Ok((x, idx)))); + + // Matching the special directory entries . and .. that + // refer to the current and parent directory respectively + // requires that the pattern has a leading dot, even if the + // `MatchOptions` field `require_literal_leading_dot` is not + // set. + if pattern.tokens.len() > 0 && pattern.tokens[0] == Char('.') { + for &special in [".", ".."].iter() { + if pattern.matches_with(special, options) { + add(todo, path.join(special)); + } + } + } + } + Err(e) => { + todo.push(Err(GlobError { + path: path.to_path_buf(), + error: e, + })); + } + } + } + None => { + // not a directory, nothing more to find + } + } +} + +fn parse_char_specifiers(s: &[char]) -> Vec { + let mut cs = Vec::new(); + let mut i = 0; + while i < s.len() { + if i + 3 <= s.len() && s[i + 1] == '-' { + cs.push(CharRange(s[i], s[i + 2])); + i += 3; + } else { + cs.push(SingleChar(s[i])); + i += 1; + } + } + cs +} + +fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: &MatchOptions) -> bool { + + for &specifier in specifiers.iter() { + match specifier { + SingleChar(sc) => { + if chars_eq(c, sc, options.case_sensitive) { + return true; + } + } + CharRange(start, end) => { + + // FIXME: work with non-ascii chars properly (issue #1347) + if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() { + + let start = start.to_ascii_lowercase(); + let end = end.to_ascii_lowercase(); + + let start_up = start.to_uppercase().next().unwrap(); + let end_up = end.to_uppercase().next().unwrap(); + + // only allow case insensitive matching when + // both start and end are within a-z or A-Z + if start != start_up && end != end_up { + let c = c.to_ascii_lowercase(); + if c >= start && c <= end { + return true; + } + } + } + + if c >= start && c <= end { + return true; + } + } + } + } + + false +} + +/// A helper function to determine if two chars are (possibly case-insensitively) equal. +fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool { + if cfg!(windows) && path::is_separator(a) && path::is_separator(b) { + true + } else if !case_sensitive && a.is_ascii() && b.is_ascii() { + // FIXME: work with non-ascii chars properly (issue #9084) + a.to_ascii_lowercase() == b.to_ascii_lowercase() + } else { + a == b + } +} + + +/// Configuration options to modify the behaviour of `Pattern::matches_with(..)` +#[allow(missing_copy_implementations)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct MatchOptions { + /// Whether or not patterns should be matched in a case-sensitive manner. + /// This currently only considers upper/lower case relationships between + /// ASCII characters, but in future this might be extended to work with + /// Unicode. + pub case_sensitive: bool, + + /// If this is true then path-component separator characters (e.g. `/` on + /// Posix) must be matched by a literal `/`, rather than by `*` or `?` or + /// `[...]` + pub require_literal_separator: bool, + + /// If this is true then paths that contain components that start with a `.` + /// will not match unless the `.` appears literally in the pattern: `*`, `?`, `**`, + /// or `[...]` will not match. This is useful because such files are + /// conventionally considered hidden on Unix systems and it might be + /// desirable to skip them when listing files. + pub require_literal_leading_dot: bool, +} + +impl MatchOptions { + /// Constructs a new `MatchOptions` with default field values. This is used + /// when calling functions that do not take an explicit `MatchOptions` + /// parameter. + /// + /// This function always returns this value: + /// + /// ```rust,ignore + /// MatchOptions { + /// case_sensitive: true, + /// require_literal_separator: false. + /// require_literal_leading_dot: false + /// } + /// ``` + pub fn new() -> MatchOptions { + MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: false, + } + } +} + +#[cfg(test)] +mod test { + use std::path::Path; + use super::{glob, Pattern, MatchOptions}; + + #[test] + fn test_pattern_from_str() { + assert!("a*b".parse::().unwrap().matches("a_b")); + assert!("a/**b".parse::().unwrap_err().pos == 4); + } + + #[test] + fn test_wildcard_errors() { + assert!(Pattern::new("a/**b").unwrap_err().pos == 4); + assert!(Pattern::new("a/bc**").unwrap_err().pos == 3); + assert!(Pattern::new("a/*****").unwrap_err().pos == 4); + assert!(Pattern::new("a/b**c**d").unwrap_err().pos == 2); + assert!(Pattern::new("a**b").unwrap_err().pos == 0); + } + + #[test] + fn test_unclosed_bracket_errors() { + assert!(Pattern::new("abc[def").unwrap_err().pos == 3); + assert!(Pattern::new("abc[!def").unwrap_err().pos == 3); + assert!(Pattern::new("abc[").unwrap_err().pos == 3); + assert!(Pattern::new("abc[!").unwrap_err().pos == 3); + assert!(Pattern::new("abc[d").unwrap_err().pos == 3); + assert!(Pattern::new("abc[!d").unwrap_err().pos == 3); + assert!(Pattern::new("abc[]").unwrap_err().pos == 3); + assert!(Pattern::new("abc[!]").unwrap_err().pos == 3); + } + + #[test] + fn test_glob_errors() { + assert!(glob("a/**b").err().unwrap().pos == 4); + assert!(glob("abc[def").err().unwrap().pos == 3); + } + + // this test assumes that there is a /root directory and that + // the user running this test is not root or otherwise doesn't + // have permission to read its contents + #[cfg(unix)] + #[test] + fn test_iteration_errors() { + use std::io; + let mut iter = glob("/root/*").unwrap(); + + // GlobErrors shouldn't halt iteration + let next = iter.next(); + assert!(next.is_some()); + + let err = next.unwrap(); + assert!(err.is_err()); + + let err = err.err().unwrap(); + assert!(err.path() == Path::new("/root")); + assert!(err.error().kind() == io::ErrorKind::PermissionDenied); + } + + #[test] + fn test_absolute_pattern() { + assert!(glob("/").unwrap().next().is_some()); + assert!(glob("//").unwrap().next().is_some()); + + // assume that the filesystem is not empty! + assert!(glob("/*").unwrap().next().is_some()); + + #[cfg(not(windows))] + fn win() {} + + #[cfg(windows)] + fn win() { + use std::env::current_dir; + use std::ffi::AsOsStr; + + // check windows absolute paths with host/device components + let root_with_device = current_dir() + .ok() + .and_then(|p| p.prefix().map(|p| p.join("*"))) + .unwrap(); + // FIXME (#9639): This needs to handle non-utf8 paths + assert!(glob(root_with_device.as_os_str().to_str().unwrap()).unwrap().next().is_some()); + } + win() + } + + #[test] + fn test_wildcards() { + assert!(Pattern::new("a*b").unwrap().matches("a_b")); + assert!(Pattern::new("a*b*c").unwrap().matches("abc")); + assert!(!Pattern::new("a*b*c").unwrap().matches("abcd")); + assert!(Pattern::new("a*b*c").unwrap().matches("a_b_c")); + assert!(Pattern::new("a*b*c").unwrap().matches("a___b___c")); + assert!(Pattern::new("abc*abc*abc").unwrap().matches("abcabcabcabcabcabcabc")); + assert!(!Pattern::new("abc*abc*abc").unwrap().matches("abcabcabcabcabcabcabca")); + assert!(Pattern::new("a*a*a*a*a*a*a*a*a") + .unwrap() + .matches("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + assert!(Pattern::new("a*b[xyz]c*d").unwrap().matches("abxcdbxcddd")); + } + + #[test] + fn test_recursive_wildcards() { + let pat = Pattern::new("some/**/needle.txt").unwrap(); + assert!(pat.matches("some/needle.txt")); + assert!(pat.matches("some/one/needle.txt")); + assert!(pat.matches("some/one/two/needle.txt")); + assert!(pat.matches("some/other/needle.txt")); + assert!(!pat.matches("some/other/notthis.txt")); + + // a single ** should be valid, for globs + // Should accept anything + let pat = Pattern::new("**").unwrap(); + assert!(pat.is_recursive); + assert!(pat.matches("abcde")); + assert!(pat.matches("")); + assert!(pat.matches(".asdf")); + assert!(pat.matches("/x/.asdf")); + + + // collapse consecutive wildcards + let pat = Pattern::new("some/**/**/needle.txt").unwrap(); + assert!(pat.matches("some/needle.txt")); + assert!(pat.matches("some/one/needle.txt")); + assert!(pat.matches("some/one/two/needle.txt")); + assert!(pat.matches("some/other/needle.txt")); + assert!(!pat.matches("some/other/notthis.txt")); + + // ** can begin the pattern + let pat = Pattern::new("**/test").unwrap(); + assert!(pat.matches("one/two/test")); + assert!(pat.matches("one/test")); + assert!(pat.matches("test")); + + // /** can begin the pattern + let pat = Pattern::new("/**/test").unwrap(); + assert!(pat.matches("/one/two/test")); + assert!(pat.matches("/one/test")); + assert!(pat.matches("/test")); + assert!(!pat.matches("/one/notthis")); + assert!(!pat.matches("/notthis")); + + // Only start sub-patterns on start of path segment. + let pat = Pattern::new("**/.*").unwrap(); + assert!(pat.matches(".abc")); + assert!(pat.matches("abc/.abc")); + assert!(!pat.matches("ab.c")); + assert!(!pat.matches("abc/ab.c")); + } + + #[test] + fn test_lots_of_files() { + // this is a good test because it touches lots of differently named files + glob("/*/*/*/*").unwrap().skip(10000).next(); + } + + #[test] + fn test_range_pattern() { + + let pat = Pattern::new("a[0-9]b").unwrap(); + for i in 0..10 { + assert!(pat.matches(&format!("a{}b", i))); + } + assert!(!pat.matches("a_b")); + + let pat = Pattern::new("a[!0-9]b").unwrap(); + for i in 0..10 { + assert!(!pat.matches(&format!("a{}b", i))); + } + assert!(pat.matches("a_b")); + + let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"]; + for &p in pats.iter() { + let pat = Pattern::new(p).unwrap(); + for c in "abcdefghijklmnopqrstuvwxyz".chars() { + assert!(pat.matches(&c.to_string())); + } + for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars() { + let options = MatchOptions { case_sensitive: false, ..MatchOptions::new() }; + assert!(pat.matches_with(&c.to_string(), &options)); + } + assert!(pat.matches("1")); + assert!(pat.matches("2")); + assert!(pat.matches("3")); + } + + let pats = ["[abc-]", "[-abc]", "[a-c-]"]; + for &p in pats.iter() { + let pat = Pattern::new(p).unwrap(); + assert!(pat.matches("a")); + assert!(pat.matches("b")); + assert!(pat.matches("c")); + assert!(pat.matches("-")); + assert!(!pat.matches("d")); + } + + let pat = Pattern::new("[2-1]").unwrap(); + assert!(!pat.matches("1")); + assert!(!pat.matches("2")); + + assert!(Pattern::new("[-]").unwrap().matches("-")); + assert!(!Pattern::new("[!-]").unwrap().matches("-")); + } + + #[test] + fn test_pattern_matches() { + let txt_pat = Pattern::new("*hello.txt").unwrap(); + assert!(txt_pat.matches("hello.txt")); + assert!(txt_pat.matches("gareth_says_hello.txt")); + assert!(txt_pat.matches("some/path/to/hello.txt")); + assert!(txt_pat.matches("some\\path\\to\\hello.txt")); + assert!(txt_pat.matches("/an/absolute/path/to/hello.txt")); + assert!(!txt_pat.matches("hello.txt-and-then-some")); + assert!(!txt_pat.matches("goodbye.txt")); + + let dir_pat = Pattern::new("*some/path/to/hello.txt").unwrap(); + assert!(dir_pat.matches("some/path/to/hello.txt")); + assert!(dir_pat.matches("a/bigger/some/path/to/hello.txt")); + assert!(!dir_pat.matches("some/path/to/hello.txt-and-then-some")); + assert!(!dir_pat.matches("some/other/path/to/hello.txt")); + } + + #[test] + fn test_pattern_escape() { + let s = "_[_]_?_*_!_"; + assert_eq!(Pattern::escape(s), "_[[]_[]]_[?]_[*]_!_".to_string()); + assert!(Pattern::new(&Pattern::escape(s)).unwrap().matches(s)); + } + + #[test] + fn test_pattern_matches_case_insensitive() { + + let pat = Pattern::new("aBcDeFg").unwrap(); + let options = MatchOptions { + case_sensitive: false, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + assert!(pat.matches_with("aBcDeFg", &options)); + assert!(pat.matches_with("abcdefg", &options)); + assert!(pat.matches_with("ABCDEFG", &options)); + assert!(pat.matches_with("AbCdEfG", &options)); + } + + #[test] + fn test_pattern_matches_case_insensitive_range() { + + let pat_within = Pattern::new("[a]").unwrap(); + let pat_except = Pattern::new("[!a]").unwrap(); + + let options_case_insensitive = MatchOptions { + case_sensitive: false, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + let options_case_sensitive = MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + assert!(pat_within.matches_with("a", &options_case_insensitive)); + assert!(pat_within.matches_with("A", &options_case_insensitive)); + assert!(!pat_within.matches_with("A", &options_case_sensitive)); + + assert!(!pat_except.matches_with("a", &options_case_insensitive)); + assert!(!pat_except.matches_with("A", &options_case_insensitive)); + assert!(pat_except.matches_with("A", &options_case_sensitive)); + } + + #[test] + fn test_pattern_matches_require_literal_separator() { + + let options_require_literal = MatchOptions { + case_sensitive: true, + require_literal_separator: true, + require_literal_leading_dot: false, + }; + let options_not_require_literal = MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + assert!(Pattern::new("abc/def").unwrap().matches_with("abc/def", &options_require_literal)); + assert!(!Pattern::new("abc?def") + .unwrap() + .matches_with("abc/def", &options_require_literal)); + assert!(!Pattern::new("abc*def") + .unwrap() + .matches_with("abc/def", &options_require_literal)); + assert!(!Pattern::new("abc[/]def") + .unwrap() + .matches_with("abc/def", &options_require_literal)); + + assert!(Pattern::new("abc/def") + .unwrap() + .matches_with("abc/def", &options_not_require_literal)); + assert!(Pattern::new("abc?def") + .unwrap() + .matches_with("abc/def", &options_not_require_literal)); + assert!(Pattern::new("abc*def") + .unwrap() + .matches_with("abc/def", &options_not_require_literal)); + assert!(Pattern::new("abc[/]def") + .unwrap() + .matches_with("abc/def", &options_not_require_literal)); + } + + #[test] + fn test_pattern_matches_require_literal_leading_dot() { + + let options_require_literal_leading_dot = MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: true, + }; + let options_not_require_literal_leading_dot = MatchOptions { + case_sensitive: true, + require_literal_separator: false, + require_literal_leading_dot: false, + }; + + let f = |options| Pattern::new("*.txt").unwrap().matches_with(".hello.txt", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(!f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new(".*.*").unwrap().matches_with(".hello.txt", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/.ccc", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(!f(&options_require_literal_leading_dot)); + + let f = |options| { + Pattern::new("aaa/bbb/*").unwrap().matches_with("aaa/bbb/c.c.c.", options) + }; + assert!(f(&options_not_require_literal_leading_dot)); + assert!(f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new("aaa/bbb/.*").unwrap().matches_with("aaa/bbb/.ccc", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new("aaa/?bbb").unwrap().matches_with("aaa/.bbb", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(!f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new("aaa/[.]bbb").unwrap().matches_with("aaa/.bbb", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(!f(&options_require_literal_leading_dot)); + + let f = |options| Pattern::new("**/*").unwrap().matches_with(".bbb", options); + assert!(f(&options_not_require_literal_leading_dot)); + assert!(!f(&options_require_literal_leading_dot)); + } + + #[test] + fn test_matches_path() { + // on windows, (Path::new("a/b").as_str().unwrap() == "a\\b"), so this + // tests that / and \ are considered equivalent on windows + assert!(Pattern::new("a/b").unwrap().matches_path(&Path::new("a/b"))); + } + + #[test] + fn test_path_join() { + let pattern = Path::new("one").join(&Path::new("**/*.rs")); + assert!(Pattern::new(pattern.to_str().unwrap()).is_ok()); + } +} diff --git a/glob/tests/glob-std.rs b/glob/tests/glob-std.rs new file mode 100644 index 000000000..c42641850 --- /dev/null +++ b/glob/tests/glob-std.rs @@ -0,0 +1,278 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-windows TempDir may cause IoError on windows: #10462 + +#![cfg_attr(test, deny(warnings))] + +extern crate glob; +extern crate tempdir; + +use glob::glob; +use std::env; +use std::path::PathBuf; +use std::fs; +use tempdir::TempDir; + +#[test] +fn main() { + fn mk_file(path: &str, directory: bool) { + if directory { + fs::create_dir(path).unwrap(); + } else { + fs::File::create(path).unwrap(); + } + } + + fn glob_vec(pattern: &str) -> Vec { + glob(pattern).unwrap().map(|r| r.unwrap()).collect() + } + + let root = TempDir::new("glob-tests"); + let root = root.ok().expect("Should have created a temp directory"); + assert!(env::set_current_dir(root.path()).is_ok()); + + mk_file("aaa", true); + mk_file("aaa/apple", true); + mk_file("aaa/orange", true); + mk_file("aaa/tomato", true); + mk_file("aaa/tomato/tomato.txt", false); + mk_file("aaa/tomato/tomoto.txt", false); + mk_file("bbb", true); + mk_file("bbb/specials", true); + mk_file("bbb/specials/!", false); + + // windows does not allow `*` or `?` characters to exist in filenames + if env::consts::FAMILY != "windows" { + mk_file("bbb/specials/*", false); + mk_file("bbb/specials/?", false); + } + + mk_file("bbb/specials/[", false); + mk_file("bbb/specials/]", false); + mk_file("ccc", true); + mk_file("xyz", true); + mk_file("xyz/x", false); + mk_file("xyz/y", false); + mk_file("xyz/z", false); + + mk_file("r", true); + mk_file("r/current_dir.md", false); + mk_file("r/one", true); + mk_file("r/one/a.md", false); + mk_file("r/one/another", true); + mk_file("r/one/another/a.md", false); + mk_file("r/one/another/deep", true); + mk_file("r/one/another/deep/spelunking.md", false); + mk_file("r/another", true); + mk_file("r/another/a.md", false); + mk_file("r/two", true); + mk_file("r/two/b.md", false); + mk_file("r/three", true); + mk_file("r/three/c.md", false); + + // all recursive entities + assert_eq!(glob_vec("r/**"), vec!( + PathBuf::from("r/another"), + PathBuf::from("r/one"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/three"), + PathBuf::from("r/two"))); + + // collapse consecutive recursive patterns + assert_eq!(glob_vec("r/**/**"), vec!( + PathBuf::from("r/another"), + PathBuf::from("r/one"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/three"), + PathBuf::from("r/two"))); + + assert_eq!(glob_vec("r/**/*"), vec!( + PathBuf::from("r/another"), + PathBuf::from("r/another/a.md"), + PathBuf::from("r/current_dir.md"), + PathBuf::from("r/one"), + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another"), + PathBuf::from("r/one/another/a.md"), + PathBuf::from("r/one/another/deep"), + PathBuf::from("r/one/another/deep/spelunking.md"), + PathBuf::from("r/three"), + PathBuf::from("r/three/c.md"), + PathBuf::from("r/two"), + PathBuf::from("r/two/b.md"))); + + // followed by a wildcard + assert_eq!(glob_vec("r/**/*.md"), vec!( + PathBuf::from("r/another/a.md"), + PathBuf::from("r/current_dir.md"), + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md"), + PathBuf::from("r/one/another/deep/spelunking.md"), + PathBuf::from("r/three/c.md"), + PathBuf::from("r/two/b.md"))); + + // followed by a precise pattern + assert_eq!(glob_vec("r/one/**/a.md"), vec!( + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md"))); + + // followed by another recursive pattern + // collapses consecutive recursives into one + assert_eq!(glob_vec("r/one/**/**/a.md"), vec!( + PathBuf::from("r/one/a.md"), + PathBuf::from("r/one/another/a.md"))); + + // followed by two precise patterns + assert_eq!(glob_vec("r/**/another/a.md"), vec!( + PathBuf::from("r/another/a.md"), + PathBuf::from("r/one/another/a.md"))); + + assert_eq!(glob_vec(""), Vec::::new()); + assert_eq!(glob_vec("."), vec!(PathBuf::from("."))); + assert_eq!(glob_vec(".."), vec!(PathBuf::from(".."))); + + assert_eq!(glob_vec("aaa"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aaa/"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("a"), Vec::::new()); + assert_eq!(glob_vec("aa"), Vec::::new()); + assert_eq!(glob_vec("aaaa"), Vec::::new()); + + assert_eq!(glob_vec("aaa/apple"), vec!(PathBuf::from("aaa/apple"))); + assert_eq!(glob_vec("aaa/apple/nope"), Vec::::new()); + + // windows should support both / and \ as directory separators + if env::consts::FAMILY == "windows" { + assert_eq!(glob_vec("aaa\\apple"), vec!(PathBuf::from("aaa/apple"))); + } + + assert_eq!(glob_vec("???/"), vec!( + PathBuf::from("aaa"), + PathBuf::from("bbb"), + PathBuf::from("ccc"), + PathBuf::from("xyz"))); + + assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt"))); + + assert_eq!(glob_vec("xyz/?"), vec!( + PathBuf::from("xyz/x"), + PathBuf::from("xyz/y"), + PathBuf::from("xyz/z"))); + + assert_eq!(glob_vec("a*"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("*a*"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("a*a"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aaa*"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("*aaa"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("*aaa*"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("*a*a*a*"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aaa*/"), vec!(PathBuf::from("aaa"))); + + assert_eq!(glob_vec("aaa/*"), vec!( + PathBuf::from("aaa/apple"), + PathBuf::from("aaa/orange"), + PathBuf::from("aaa/tomato"))); + + assert_eq!(glob_vec("aaa/*a*"), vec!( + PathBuf::from("aaa/apple"), + PathBuf::from("aaa/orange"), + PathBuf::from("aaa/tomato"))); + + assert_eq!(glob_vec("*/*/*.txt"), vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt"))); + + assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!( + PathBuf::from("aaa/tomato/tomato.txt"), + PathBuf::from("aaa/tomato/tomoto.txt"))); + + assert_eq!(glob_vec("./aaa"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("./*"), glob_vec("*")); + assert_eq!(glob_vec("*/..").pop().unwrap(), PathBuf::from("xyz/..")); + assert_eq!(glob_vec("aaa/../bbb"), vec!(PathBuf::from("aaa/../bbb"))); + assert_eq!(glob_vec("nonexistent/../bbb"), Vec::::new()); + assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::::new()); + + assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::::new()); + + assert_eq!(glob_vec("aa[a]"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aa[abc]"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("a[bca]a"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aa[b]"), Vec::::new()); + assert_eq!(glob_vec("aa[xyz]"), Vec::::new()); + assert_eq!(glob_vec("aa[]]"), Vec::::new()); + + assert_eq!(glob_vec("aa[!b]"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aa[!bcd]"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("a[!bcd]a"), vec!(PathBuf::from("aaa"))); + assert_eq!(glob_vec("aa[!a]"), Vec::::new()); + assert_eq!(glob_vec("aa[!abc]"), Vec::::new()); + + assert_eq!(glob_vec("bbb/specials/[[]"), vec!(PathBuf::from("bbb/specials/["))); + assert_eq!(glob_vec("bbb/specials/!"), vec!(PathBuf::from("bbb/specials/!"))); + assert_eq!(glob_vec("bbb/specials/[]]"), vec!(PathBuf::from("bbb/specials/]"))); + + if env::consts::FAMILY != "windows" { + assert_eq!(glob_vec("bbb/specials/[*]"), vec!(PathBuf::from("bbb/specials/*"))); + assert_eq!(glob_vec("bbb/specials/[?]"), vec!(PathBuf::from("bbb/specials/?"))); + } + + if env::consts::FAMILY == "windows" { + + assert_eq!(glob_vec("bbb/specials/[![]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/]"))); + + assert_eq!(glob_vec("bbb/specials/[!]]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/["))); + + assert_eq!(glob_vec("bbb/specials/[!!]"), vec!( + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]"))); + + } else { + + assert_eq!(glob_vec("bbb/specials/[![]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/]"))); + + assert_eq!(glob_vec("bbb/specials/[!]]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/["))); + + assert_eq!(glob_vec("bbb/specials/[!!]"), vec!( + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]"))); + + assert_eq!(glob_vec("bbb/specials/[!*]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/?"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]"))); + + assert_eq!(glob_vec("bbb/specials/[!?]"), vec!( + PathBuf::from("bbb/specials/!"), + PathBuf::from("bbb/specials/*"), + PathBuf::from("bbb/specials/["), + PathBuf::from("bbb/specials/]"))); + + } +} diff --git a/globset/.cargo-checksum.json b/globset/.cargo-checksum.json new file mode 100644 index 000000000..a0739793e --- /dev/null +++ b/globset/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"} \ No newline at end of file diff --git a/globset/COPYING b/globset/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/globset/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/globset/Cargo.toml b/globset/Cargo.toml new file mode 100644 index 000000000..f01d1843a --- /dev/null +++ b/globset/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "globset" +version = "0.4.3" +authors = ["Andrew Gallant "] +description = "Cross platform single glob and glob set matching. Glob set matching is the\nprocess of matching one or more glob patterns against a single candidate path\nsimultaneously, and returning all of the globs that matched.\n" +homepage = "https://github.com/BurntSushi/ripgrep/tree/master/globset" +documentation = "https://docs.rs/globset" +readme = "README.md" +keywords = ["regex", "glob", "multiple", "set", "pattern"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/ripgrep/tree/master/globset" + +[lib] +name = "globset" +bench = false +[dependencies.aho-corasick] +version = "0.7.3" + +[dependencies.bstr] +version = "0.1.2" +features = ["std"] +default-features = false + +[dependencies.fnv] +version = "1.0.6" + +[dependencies.log] +version = "0.4.5" + +[dependencies.regex] +version = "1.1.5" +[dev-dependencies.glob] +version = "0.3.0" + +[features] +simd-accel = [] diff --git a/globset/LICENSE-MIT b/globset/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/globset/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/globset/README.md b/globset/README.md new file mode 100644 index 000000000..5d54172aa --- /dev/null +++ b/globset/README.md @@ -0,0 +1,122 @@ +globset +======= +Cross platform single glob and glob set matching. Glob set matching is the +process of matching one or more glob patterns against a single candidate path +simultaneously, and returning all of the globs that matched. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.svg)](https://travis-ci.org/BurntSushi/ripgrep) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) +[![](https://img.shields.io/crates/v/globset.svg)](https://crates.io/crates/globset) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +[https://docs.rs/globset](https://docs.rs/globset) + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +globset = "0.3" +``` + +and this to your crate root: + +```rust +extern crate globset; +``` + +### Example: one glob + +This example shows how to match a single glob against a single file path. + +```rust +use globset::Glob; + +let glob = Glob::new("*.rs")?.compile_matcher(); + +assert!(glob.is_match("foo.rs")); +assert!(glob.is_match("foo/bar.rs")); +assert!(!glob.is_match("Cargo.toml")); +``` + +### Example: configuring a glob matcher + +This example shows how to use a `GlobBuilder` to configure aspects of match +semantics. In this example, we prevent wildcards from matching path separators. + +```rust +use globset::GlobBuilder; + +let glob = GlobBuilder::new("*.rs") + .literal_separator(true).build()?.compile_matcher(); + +assert!(glob.is_match("foo.rs")); +assert!(!glob.is_match("foo/bar.rs")); // no longer matches +assert!(!glob.is_match("Cargo.toml")); +``` + +### Example: match multiple globs at once + +This example shows how to match multiple glob patterns at once. + +```rust +use globset::{Glob, GlobSetBuilder}; + +let mut builder = GlobSetBuilder::new(); +// A GlobBuilder can be used to configure each glob's match semantics +// independently. +builder.add(Glob::new("*.rs")?); +builder.add(Glob::new("src/lib.rs")?); +builder.add(Glob::new("src/**/foo.rs")?); +let set = builder.build()?; + +assert_eq!(set.matches("src/bar/baz/foo.rs"), vec![0, 2]); +``` + +### Performance + +This crate implements globs by converting them to regular expressions, and +executing them with the +[`regex`](https://github.com/rust-lang-nursery/regex) +crate. + +For single glob matching, performance of this crate should be roughly on par +with the performance of the +[`glob`](https://github.com/rust-lang-nursery/glob) +crate. (`*_regex` correspond to benchmarks for this library while `*_glob` +correspond to benchmarks for the `glob` library.) +Optimizations in the `regex` crate may propel this library past `glob`, +particularly when matching longer paths. + +``` +test ext_glob ... bench: 425 ns/iter (+/- 21) +test ext_regex ... bench: 175 ns/iter (+/- 10) +test long_glob ... bench: 182 ns/iter (+/- 11) +test long_regex ... bench: 173 ns/iter (+/- 10) +test short_glob ... bench: 69 ns/iter (+/- 4) +test short_regex ... bench: 83 ns/iter (+/- 2) +``` + +The primary performance advantage of this crate is when matching multiple +globs against a single path. With the `glob` crate, one must match each glob +synchronously, one after the other. In this crate, many can be matched +simultaneously. For example: + +``` +test many_short_glob ... bench: 1,063 ns/iter (+/- 47) +test many_short_regex_set ... bench: 186 ns/iter (+/- 11) +``` + +### Comparison with the [`glob`](https://github.com/rust-lang-nursery/glob) crate + +* Supports alternate "or" globs, e.g., `*.{foo,bar}`. +* Can match non-UTF-8 file paths correctly. +* Supports matching multiple globs at once. +* Doesn't provide a recursive directory iterator of matching file paths, + although I believe this crate should grow one eventually. +* Supports case insensitive and require-literal-separator match options, but + **doesn't** support the require-literal-leading-dot option. diff --git a/globset/UNLICENSE b/globset/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/globset/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/globset/benches/bench.rs b/globset/benches/bench.rs new file mode 100644 index 000000000..e142ed72e --- /dev/null +++ b/globset/benches/bench.rs @@ -0,0 +1,121 @@ +/*! +This module benchmarks the glob implementation. For benchmarks on the ripgrep +tool itself, see the benchsuite directory. +*/ +#![feature(test)] + +extern crate glob; +extern crate globset; +#[macro_use] +extern crate lazy_static; +extern crate regex; +extern crate test; + +use std::ffi::OsStr; +use std::path::Path; + +use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder}; + +const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt"; +const EXT_PAT: &'static str = "*.txt"; + +const SHORT: &'static str = "some/needle.txt"; +const SHORT_PAT: &'static str = "some/**/needle.txt"; + +const LONG: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt"; +const LONG_PAT: &'static str = "some/**/needle.txt"; + +fn new_glob(pat: &str) -> glob::Pattern { + glob::Pattern::new(pat).unwrap() +} + +fn new_reglob(pat: &str) -> GlobMatcher { + Glob::new(pat).unwrap().compile_matcher() +} + +fn new_reglob_many(pats: &[&str]) -> GlobSet { + let mut builder = GlobSetBuilder::new(); + for pat in pats { + builder.add(Glob::new(pat).unwrap()); + } + builder.build().unwrap() +} + +#[bench] +fn ext_glob(b: &mut test::Bencher) { + let pat = new_glob(EXT_PAT); + b.iter(|| assert!(pat.matches(EXT))); +} + +#[bench] +fn ext_regex(b: &mut test::Bencher) { + let set = new_reglob(EXT_PAT); + let cand = Candidate::new(EXT); + b.iter(|| assert!(set.is_match_candidate(&cand))); +} + +#[bench] +fn short_glob(b: &mut test::Bencher) { + let pat = new_glob(SHORT_PAT); + b.iter(|| assert!(pat.matches(SHORT))); +} + +#[bench] +fn short_regex(b: &mut test::Bencher) { + let set = new_reglob(SHORT_PAT); + let cand = Candidate::new(SHORT); + b.iter(|| assert!(set.is_match_candidate(&cand))); +} + +#[bench] +fn long_glob(b: &mut test::Bencher) { + let pat = new_glob(LONG_PAT); + b.iter(|| assert!(pat.matches(LONG))); +} + +#[bench] +fn long_regex(b: &mut test::Bencher) { + let set = new_reglob(LONG_PAT); + let cand = Candidate::new(LONG); + b.iter(|| assert!(set.is_match_candidate(&cand))); +} + +const MANY_SHORT_GLOBS: &'static [&'static str] = &[ + // Taken from a random .gitignore on my system. + ".*.swp", + "tags", + "target", + "*.lock", + "tmp", + "*.csv", + "*.fst", + "*-got", + "*.csv.idx", + "words", + "98m*", + "dict", + "test", + "months", +]; + +const MANY_SHORT_SEARCH: &'static str = "98m-blah.csv.idx"; + +#[bench] +fn many_short_glob(b: &mut test::Bencher) { + let pats: Vec<_> = MANY_SHORT_GLOBS.iter().map(|&s| new_glob(s)).collect(); + b.iter(|| { + let mut count = 0; + for pat in &pats { + if pat.matches(MANY_SHORT_SEARCH) { + count += 1; + } + } + assert_eq!(2, count); + }) +} + +#[bench] +fn many_short_regex_set(b: &mut test::Bencher) { + let set = new_reglob_many(MANY_SHORT_GLOBS); + b.iter(|| assert_eq!(2, set.matches(MANY_SHORT_SEARCH).iter().count())); +} diff --git a/globset/src/glob.rs b/globset/src/glob.rs new file mode 100644 index 000000000..5e635a205 --- /dev/null +++ b/globset/src/glob.rs @@ -0,0 +1,1497 @@ +use std::fmt; +use std::hash; +use std::iter; +use std::ops::{Deref, DerefMut}; +use std::path::{Path, is_separator}; +use std::str; + +use regex; +use regex::bytes::Regex; + +use {Candidate, Error, ErrorKind, new_regex}; + +/// Describes a matching strategy for a particular pattern. +/// +/// This provides a way to more quickly determine whether a pattern matches +/// a particular file path in a way that scales with a large number of +/// patterns. For example, if many patterns are of the form `*.ext`, then it's +/// possible to test whether any of those patterns matches by looking up a +/// file path's extension in a hash table. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum MatchStrategy { + /// A pattern matches if and only if the entire file path matches this + /// literal string. + Literal(String), + /// A pattern matches if and only if the file path's basename matches this + /// literal string. + BasenameLiteral(String), + /// A pattern matches if and only if the file path's extension matches this + /// literal string. + Extension(String), + /// A pattern matches if and only if this prefix literal is a prefix of the + /// candidate file path. + Prefix(String), + /// A pattern matches if and only if this prefix literal is a prefix of the + /// candidate file path. + /// + /// An exception: if `component` is true, then `suffix` must appear at the + /// beginning of a file path or immediately following a `/`. + Suffix { + /// The actual suffix. + suffix: String, + /// Whether this must start at the beginning of a path component. + component: bool, + }, + /// A pattern matches only if the given extension matches the file path's + /// extension. Note that this is a necessary but NOT sufficient criterion. + /// Namely, if the extension matches, then a full regex search is still + /// required. + RequiredExtension(String), + /// A regex needs to be used for matching. + Regex, +} + +impl MatchStrategy { + /// Returns a matching strategy for the given pattern. + pub fn new(pat: &Glob) -> MatchStrategy { + if let Some(lit) = pat.basename_literal() { + MatchStrategy::BasenameLiteral(lit) + } else if let Some(lit) = pat.literal() { + MatchStrategy::Literal(lit) + } else if let Some(ext) = pat.ext() { + MatchStrategy::Extension(ext) + } else if let Some(prefix) = pat.prefix() { + MatchStrategy::Prefix(prefix) + } else if let Some((suffix, component)) = pat.suffix() { + MatchStrategy::Suffix { suffix: suffix, component: component } + } else if let Some(ext) = pat.required_ext() { + MatchStrategy::RequiredExtension(ext) + } else { + MatchStrategy::Regex + } + } +} + +/// Glob represents a successfully parsed shell glob pattern. +/// +/// It cannot be used directly to match file paths, but it can be converted +/// to a regular expression string or a matcher. +#[derive(Clone, Debug, Eq)] +pub struct Glob { + glob: String, + re: String, + opts: GlobOptions, + tokens: Tokens, +} + +impl PartialEq for Glob { + fn eq(&self, other: &Glob) -> bool { + self.glob == other.glob && self.opts == other.opts + } +} + +impl hash::Hash for Glob { + fn hash(&self, state: &mut H) { + self.glob.hash(state); + self.opts.hash(state); + } +} + +impl fmt::Display for Glob { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.glob.fmt(f) + } +} + +/// A matcher for a single pattern. +#[derive(Clone, Debug)] +pub struct GlobMatcher { + /// The underlying pattern. + pat: Glob, + /// The pattern, as a compiled regex. + re: Regex, +} + +impl GlobMatcher { + /// Tests whether the given path matches this pattern or not. + pub fn is_match>(&self, path: P) -> bool { + self.is_match_candidate(&Candidate::new(path.as_ref())) + } + + /// Tests whether the given path matches this pattern or not. + pub fn is_match_candidate(&self, path: &Candidate) -> bool { + self.re.is_match(path.path.as_bytes()) + } +} + +/// A strategic matcher for a single pattern. +#[cfg(test)] +#[derive(Clone, Debug)] +struct GlobStrategic { + /// The match strategy to use. + strategy: MatchStrategy, + /// The underlying pattern. + pat: Glob, + /// The pattern, as a compiled regex. + re: Regex, +} + +#[cfg(test)] +impl GlobStrategic { + /// Tests whether the given path matches this pattern or not. + fn is_match>(&self, path: P) -> bool { + self.is_match_candidate(&Candidate::new(path.as_ref())) + } + + /// Tests whether the given path matches this pattern or not. + fn is_match_candidate(&self, candidate: &Candidate) -> bool { + let byte_path = candidate.path.as_bytes(); + + match self.strategy { + MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path, + MatchStrategy::BasenameLiteral(ref lit) => { + lit.as_bytes() == &*candidate.basename + } + MatchStrategy::Extension(ref ext) => { + ext.as_bytes() == &*candidate.ext + } + MatchStrategy::Prefix(ref pre) => { + starts_with(pre.as_bytes(), byte_path) + } + MatchStrategy::Suffix { ref suffix, component } => { + if component && byte_path == &suffix.as_bytes()[1..] { + return true; + } + ends_with(suffix.as_bytes(), byte_path) + } + MatchStrategy::RequiredExtension(ref ext) => { + let ext = ext.as_bytes(); + &*candidate.ext == ext && self.re.is_match(byte_path) + } + MatchStrategy::Regex => self.re.is_match(byte_path), + } + } +} + +/// A builder for a pattern. +/// +/// This builder enables configuring the match semantics of a pattern. For +/// example, one can make matching case insensitive. +/// +/// The lifetime `'a` refers to the lifetime of the pattern string. +#[derive(Clone, Debug)] +pub struct GlobBuilder<'a> { + /// The glob pattern to compile. + glob: &'a str, + /// Options for the pattern. + opts: GlobOptions, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +struct GlobOptions { + /// Whether to match case insensitively. + case_insensitive: bool, + /// Whether to require a literal separator to match a separator in a file + /// path. e.g., when enabled, `*` won't match `/`. + literal_separator: bool, + /// Whether or not to use `\` to escape special characters. + /// e.g., when enabled, `\*` will match a literal `*`. + backslash_escape: bool, +} + +impl GlobOptions { + fn default() -> GlobOptions { + GlobOptions { + case_insensitive: false, + literal_separator: false, + backslash_escape: !is_separator('\\'), + } + } +} + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +struct Tokens(Vec); + +impl Deref for Tokens { + type Target = Vec; + fn deref(&self) -> &Vec { &self.0 } +} + +impl DerefMut for Tokens { + fn deref_mut(&mut self) -> &mut Vec { &mut self.0 } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +enum Token { + Literal(char), + Any, + ZeroOrMore, + RecursivePrefix, + RecursiveSuffix, + RecursiveZeroOrMore, + Class { + negated: bool, + ranges: Vec<(char, char)>, + }, + Alternates(Vec), +} + +impl Glob { + /// Builds a new pattern with default options. + pub fn new(glob: &str) -> Result { + GlobBuilder::new(glob).build() + } + + /// Returns a matcher for this pattern. + pub fn compile_matcher(&self) -> GlobMatcher { + let re = new_regex(&self.re) + .expect("regex compilation shouldn't fail"); + GlobMatcher { + pat: self.clone(), + re: re, + } + } + + /// Returns a strategic matcher. + /// + /// This isn't exposed because it's not clear whether it's actually + /// faster than just running a regex for a *single* pattern. If it + /// is faster, then GlobMatcher should do it automatically. + #[cfg(test)] + fn compile_strategic_matcher(&self) -> GlobStrategic { + let strategy = MatchStrategy::new(self); + let re = new_regex(&self.re) + .expect("regex compilation shouldn't fail"); + GlobStrategic { + strategy: strategy, + pat: self.clone(), + re: re, + } + } + + /// Returns the original glob pattern used to build this pattern. + pub fn glob(&self) -> &str { + &self.glob + } + + /// Returns the regular expression string for this glob. + /// + /// Note that regular expressions for globs are intended to be matched on + /// arbitrary bytes (`&[u8]`) instead of Unicode strings (`&str`). In + /// particular, globs are frequently used on file paths, where there is no + /// general guarantee that file paths are themselves valid UTF-8. As a + /// result, callers will need to ensure that they are using a regex API + /// that can match on arbitrary bytes. For example, the + /// [`regex`](https://crates.io/regex) + /// crate's + /// [`Regex`](https://docs.rs/regex/*/regex/struct.Regex.html) + /// API is not suitable for this since it matches on `&str`, but its + /// [`bytes::Regex`](https://docs.rs/regex/*/regex/bytes/struct.Regex.html) + /// API is suitable for this. + pub fn regex(&self) -> &str { + &self.re + } + + /// Returns the pattern as a literal if and only if the pattern must match + /// an entire path exactly. + /// + /// The basic format of these patterns is `{literal}`. + fn literal(&self) -> Option { + if self.opts.case_insensitive { + return None; + } + let mut lit = String::new(); + for t in &*self.tokens { + match *t { + Token::Literal(c) => lit.push(c), + _ => return None, + } + } + if lit.is_empty() { + None + } else { + Some(lit) + } + } + + /// Returns an extension if this pattern matches a file path if and only + /// if the file path has the extension returned. + /// + /// Note that this extension returned differs from the extension that + /// std::path::Path::extension returns. Namely, this extension includes + /// the '.'. Also, paths like `.rs` are considered to have an extension + /// of `.rs`. + fn ext(&self) -> Option { + if self.opts.case_insensitive { + return None; + } + let start = match self.tokens.get(0) { + Some(&Token::RecursivePrefix) => 1, + Some(_) => 0, + _ => return None, + }; + match self.tokens.get(start) { + Some(&Token::ZeroOrMore) => { + // If there was no recursive prefix, then we only permit + // `*` if `*` can match a `/`. For example, if `*` can't + // match `/`, then `*.c` doesn't match `foo/bar.c`. + if start == 0 && self.opts.literal_separator { + return None; + } + } + _ => return None, + } + match self.tokens.get(start + 1) { + Some(&Token::Literal('.')) => {} + _ => return None, + } + let mut lit = ".".to_string(); + for t in self.tokens[start + 2..].iter() { + match *t { + Token::Literal('.') | Token::Literal('/') => return None, + Token::Literal(c) => lit.push(c), + _ => return None, + } + } + if lit.is_empty() { + None + } else { + Some(lit) + } + } + + /// This is like `ext`, but returns an extension even if it isn't sufficent + /// to imply a match. Namely, if an extension is returned, then it is + /// necessary but not sufficient for a match. + fn required_ext(&self) -> Option { + if self.opts.case_insensitive { + return None; + } + // We don't care at all about the beginning of this pattern. All we + // need to check for is if it ends with a literal of the form `.ext`. + let mut ext: Vec = vec![]; // built in reverse + for t in self.tokens.iter().rev() { + match *t { + Token::Literal('/') => return None, + Token::Literal(c) => { + ext.push(c); + if c == '.' { + break; + } + } + _ => return None, + } + } + if ext.last() != Some(&'.') { + None + } else { + ext.reverse(); + Some(ext.into_iter().collect()) + } + } + + /// Returns a literal prefix of this pattern if the entire pattern matches + /// if the literal prefix matches. + fn prefix(&self) -> Option { + if self.opts.case_insensitive { + return None; + } + let end = match self.tokens.last() { + Some(&Token::ZeroOrMore) => { + if self.opts.literal_separator { + // If a trailing `*` can't match a `/`, then we can't + // assume a match of the prefix corresponds to a match + // of the overall pattern. e.g., `foo/*` with + // `literal_separator` enabled matches `foo/bar` but not + // `foo/bar/baz`, even though `foo/bar/baz` has a `foo/` + // literal prefix. + return None; + } + self.tokens.len() - 1 + } + _ => self.tokens.len(), + }; + let mut lit = String::new(); + for t in &self.tokens[0..end] { + match *t { + Token::Literal(c) => lit.push(c), + _ => return None, + } + } + if lit.is_empty() { + None + } else { + Some(lit) + } + } + + /// Returns a literal suffix of this pattern if the entire pattern matches + /// if the literal suffix matches. + /// + /// If a literal suffix is returned and it must match either the entire + /// file path or be preceded by a `/`, then also return true. This happens + /// with a pattern like `**/foo/bar`. Namely, this pattern matches + /// `foo/bar` and `baz/foo/bar`, but not `foofoo/bar`. In this case, the + /// suffix returned is `/foo/bar` (but should match the entire path + /// `foo/bar`). + /// + /// When this returns true, the suffix literal is guaranteed to start with + /// a `/`. + fn suffix(&self) -> Option<(String, bool)> { + if self.opts.case_insensitive { + return None; + } + let mut lit = String::new(); + let (start, entire) = match self.tokens.get(0) { + Some(&Token::RecursivePrefix) => { + // We only care if this follows a path component if the next + // token is a literal. + if let Some(&Token::Literal(_)) = self.tokens.get(1) { + lit.push('/'); + (1, true) + } else { + (1, false) + } + } + _ => (0, false), + }; + let start = match self.tokens.get(start) { + Some(&Token::ZeroOrMore) => { + // If literal_separator is enabled, then a `*` can't + // necessarily match everything, so reporting a suffix match + // as a match of the pattern would be a false positive. + if self.opts.literal_separator { + return None; + } + start + 1 + } + _ => start, + }; + for t in &self.tokens[start..] { + match *t { + Token::Literal(c) => lit.push(c), + _ => return None, + } + } + if lit.is_empty() || lit == "/" { + None + } else { + Some((lit, entire)) + } + } + + /// If this pattern only needs to inspect the basename of a file path, + /// then the tokens corresponding to only the basename match are returned. + /// + /// For example, given a pattern of `**/*.foo`, only the tokens + /// corresponding to `*.foo` are returned. + /// + /// Note that this will return None if any match of the basename tokens + /// doesn't correspond to a match of the entire pattern. For example, the + /// glob `foo` only matches when a file path has a basename of `foo`, but + /// doesn't *always* match when a file path has a basename of `foo`. e.g., + /// `foo` doesn't match `abc/foo`. + fn basename_tokens(&self) -> Option<&[Token]> { + if self.opts.case_insensitive { + return None; + } + let start = match self.tokens.get(0) { + Some(&Token::RecursivePrefix) => 1, + _ => { + // With nothing to gobble up the parent portion of a path, + // we can't assume that matching on only the basename is + // correct. + return None; + } + }; + if self.tokens[start..].is_empty() { + return None; + } + for t in &self.tokens[start..] { + match *t { + Token::Literal('/') => return None, + Token::Literal(_) => {} // OK + Token::Any | Token::ZeroOrMore => { + if !self.opts.literal_separator { + // In this case, `*` and `?` can match a path + // separator, which means this could reach outside + // the basename. + return None; + } + } + Token::RecursivePrefix + | Token::RecursiveSuffix + | Token::RecursiveZeroOrMore => { + return None; + } + Token::Class{..} | Token::Alternates(..) => { + // We *could* be a little smarter here, but either one + // of these is going to prevent our literal optimizations + // anyway, so give up. + return None; + } + } + } + Some(&self.tokens[start..]) + } + + /// Returns the pattern as a literal if and only if the pattern exclusively + /// matches the basename of a file path *and* is a literal. + /// + /// The basic format of these patterns is `**/{literal}`, where `{literal}` + /// does not contain a path separator. + fn basename_literal(&self) -> Option { + let tokens = match self.basename_tokens() { + None => return None, + Some(tokens) => tokens, + }; + let mut lit = String::new(); + for t in tokens { + match *t { + Token::Literal(c) => lit.push(c), + _ => return None, + } + } + Some(lit) + } +} + +impl<'a> GlobBuilder<'a> { + /// Create a new builder for the pattern given. + /// + /// The pattern is not compiled until `build` is called. + pub fn new(glob: &'a str) -> GlobBuilder<'a> { + GlobBuilder { + glob: glob, + opts: GlobOptions::default(), + } + } + + /// Parses and builds the pattern. + pub fn build(&self) -> Result { + let mut p = Parser { + glob: &self.glob, + stack: vec![Tokens::default()], + chars: self.glob.chars().peekable(), + prev: None, + cur: None, + opts: &self.opts, + }; + p.parse()?; + if p.stack.is_empty() { + Err(Error { + glob: Some(self.glob.to_string()), + kind: ErrorKind::UnopenedAlternates, + }) + } else if p.stack.len() > 1 { + Err(Error { + glob: Some(self.glob.to_string()), + kind: ErrorKind::UnclosedAlternates, + }) + } else { + let tokens = p.stack.pop().unwrap(); + Ok(Glob { + glob: self.glob.to_string(), + re: tokens.to_regex_with(&self.opts), + opts: self.opts, + tokens: tokens, + }) + } + } + + /// Toggle whether the pattern matches case insensitively or not. + /// + /// This is disabled by default. + pub fn case_insensitive(&mut self, yes: bool) -> &mut GlobBuilder<'a> { + self.opts.case_insensitive = yes; + self + } + + /// Toggle whether a literal `/` is required to match a path separator. + pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> { + self.opts.literal_separator = yes; + self + } + + /// When enabled, a back slash (`\`) may be used to escape + /// special characters in a glob pattern. Additionally, this will + /// prevent `\` from being interpreted as a path separator on all + /// platforms. + /// + /// This is enabled by default on platforms where `\` is not a + /// path separator and disabled by default on platforms where `\` + /// is a path separator. + pub fn backslash_escape(&mut self, yes: bool) -> &mut GlobBuilder<'a> { + self.opts.backslash_escape = yes; + self + } +} + +impl Tokens { + /// Convert this pattern to a string that is guaranteed to be a valid + /// regular expression and will represent the matching semantics of this + /// glob pattern and the options given. + fn to_regex_with(&self, options: &GlobOptions) -> String { + let mut re = String::new(); + re.push_str("(?-u)"); + if options.case_insensitive { + re.push_str("(?i)"); + } + re.push('^'); + // Special case. If the entire glob is just `**`, then it should match + // everything. + if self.len() == 1 && self[0] == Token::RecursivePrefix { + re.push_str(".*"); + re.push('$'); + return re; + } + self.tokens_to_regex(options, &self, &mut re); + re.push('$'); + re + } + + fn tokens_to_regex( + &self, + options: &GlobOptions, + tokens: &[Token], + re: &mut String, + ) { + for tok in tokens { + match *tok { + Token::Literal(c) => { + re.push_str(&char_to_escaped_literal(c)); + } + Token::Any => { + if options.literal_separator { + re.push_str("[^/]"); + } else { + re.push_str("."); + } + } + Token::ZeroOrMore => { + if options.literal_separator { + re.push_str("[^/]*"); + } else { + re.push_str(".*"); + } + } + Token::RecursivePrefix => { + re.push_str("(?:/?|.*/)"); + } + Token::RecursiveSuffix => { + re.push_str("(?:/?|/.*)"); + } + Token::RecursiveZeroOrMore => { + re.push_str("(?:/|/.*/)"); + } + Token::Class { negated, ref ranges } => { + re.push('['); + if negated { + re.push('^'); + } + for r in ranges { + if r.0 == r.1 { + // Not strictly necessary, but nicer to look at. + re.push_str(&char_to_escaped_literal(r.0)); + } else { + re.push_str(&char_to_escaped_literal(r.0)); + re.push('-'); + re.push_str(&char_to_escaped_literal(r.1)); + } + } + re.push(']'); + } + Token::Alternates(ref patterns) => { + let mut parts = vec![]; + for pat in patterns { + let mut altre = String::new(); + self.tokens_to_regex(options, &pat, &mut altre); + if !altre.is_empty() { + parts.push(altre); + } + } + + // It is possible to have an empty set in which case the + // resulting alternation '()' would be an error. + if !parts.is_empty() { + re.push('('); + re.push_str(&parts.join("|")); + re.push(')'); + } + } + } + } + } +} + +/// Convert a Unicode scalar value to an escaped string suitable for use as +/// a literal in a non-Unicode regex. +fn char_to_escaped_literal(c: char) -> String { + bytes_to_escaped_literal(&c.to_string().into_bytes()) +} + +/// Converts an arbitrary sequence of bytes to a UTF-8 string. All non-ASCII +/// code units are converted to their escaped form. +fn bytes_to_escaped_literal(bs: &[u8]) -> String { + let mut s = String::with_capacity(bs.len()); + for &b in bs { + if b <= 0x7F { + s.push_str(®ex::escape(&(b as char).to_string())); + } else { + s.push_str(&format!("\\x{:02x}", b)); + } + } + s +} + +struct Parser<'a> { + glob: &'a str, + stack: Vec, + chars: iter::Peekable>, + prev: Option, + cur: Option, + opts: &'a GlobOptions, +} + +impl<'a> Parser<'a> { + fn error(&self, kind: ErrorKind) -> Error { + Error { glob: Some(self.glob.to_string()), kind: kind } + } + + fn parse(&mut self) -> Result<(), Error> { + while let Some(c) = self.bump() { + match c { + '?' => self.push_token(Token::Any)?, + '*' => self.parse_star()?, + '[' => self.parse_class()?, + '{' => self.push_alternate()?, + '}' => self.pop_alternate()?, + ',' => self.parse_comma()?, + '\\' => self.parse_backslash()?, + c => self.push_token(Token::Literal(c))?, + } + } + Ok(()) + } + + fn push_alternate(&mut self) -> Result<(), Error> { + if self.stack.len() > 1 { + return Err(self.error(ErrorKind::NestedAlternates)); + } + Ok(self.stack.push(Tokens::default())) + } + + fn pop_alternate(&mut self) -> Result<(), Error> { + let mut alts = vec![]; + while self.stack.len() >= 2 { + alts.push(self.stack.pop().unwrap()); + } + self.push_token(Token::Alternates(alts)) + } + + fn push_token(&mut self, tok: Token) -> Result<(), Error> { + if let Some(ref mut pat) = self.stack.last_mut() { + return Ok(pat.push(tok)); + } + Err(self.error(ErrorKind::UnopenedAlternates)) + } + + fn pop_token(&mut self) -> Result { + if let Some(ref mut pat) = self.stack.last_mut() { + return Ok(pat.pop().unwrap()); + } + Err(self.error(ErrorKind::UnopenedAlternates)) + } + + fn have_tokens(&self) -> Result { + match self.stack.last() { + None => Err(self.error(ErrorKind::UnopenedAlternates)), + Some(ref pat) => Ok(!pat.is_empty()), + } + } + + fn parse_comma(&mut self) -> Result<(), Error> { + // If we aren't inside a group alternation, then don't + // treat commas specially. Otherwise, we need to start + // a new alternate. + if self.stack.len() <= 1 { + self.push_token(Token::Literal(',')) + } else { + Ok(self.stack.push(Tokens::default())) + } + } + + fn parse_backslash(&mut self) -> Result<(), Error> { + if self.opts.backslash_escape { + match self.bump() { + None => Err(self.error(ErrorKind::DanglingEscape)), + Some(c) => self.push_token(Token::Literal(c)), + } + } else if is_separator('\\') { + // Normalize all patterns to use / as a separator. + self.push_token(Token::Literal('/')) + } else { + self.push_token(Token::Literal('\\')) + } + } + + fn parse_star(&mut self) -> Result<(), Error> { + let prev = self.prev; + if self.peek() != Some('*') { + self.push_token(Token::ZeroOrMore)?; + return Ok(()); + } + assert!(self.bump() == Some('*')); + if !self.have_tokens()? { + if !self.peek().map_or(true, is_separator) { + self.push_token(Token::ZeroOrMore)?; + self.push_token(Token::ZeroOrMore)?; + } else { + self.push_token(Token::RecursivePrefix)?; + assert!(self.bump().map_or(true, is_separator)); + } + return Ok(()); + } + + if !prev.map(is_separator).unwrap_or(false) { + if self.stack.len() <= 1 + || (prev != Some(',') && prev != Some('{')) + { + self.push_token(Token::ZeroOrMore)?; + self.push_token(Token::ZeroOrMore)?; + return Ok(()); + } + } + let is_suffix = + match self.peek() { + None => { + assert!(self.bump().is_none()); + true + } + Some(',') | Some('}') if self.stack.len() >= 2 => { + true + } + Some(c) if is_separator(c) => { + assert!(self.bump().map(is_separator).unwrap_or(false)); + false + } + _ => { + self.push_token(Token::ZeroOrMore)?; + self.push_token(Token::ZeroOrMore)?; + return Ok(()); + } + }; + match self.pop_token()? { + Token::RecursivePrefix => { + self.push_token(Token::RecursivePrefix)?; + } + Token::RecursiveSuffix => { + self.push_token(Token::RecursiveSuffix)?; + } + _ => { + if is_suffix { + self.push_token(Token::RecursiveSuffix)?; + } else { + self.push_token(Token::RecursiveZeroOrMore)?; + } + } + } + Ok(()) + } + + fn parse_class(&mut self) -> Result<(), Error> { + fn add_to_last_range( + glob: &str, + r: &mut (char, char), + add: char, + ) -> Result<(), Error> { + r.1 = add; + if r.1 < r.0 { + Err(Error { + glob: Some(glob.to_string()), + kind: ErrorKind::InvalidRange(r.0, r.1), + }) + } else { + Ok(()) + } + } + let mut ranges = vec![]; + let negated = match self.chars.peek() { + Some(&'!') | Some(&'^') => { + let bump = self.bump(); + assert!(bump == Some('!') || bump == Some('^')); + true + } + _ => false, + }; + let mut first = true; + let mut in_range = false; + loop { + let c = match self.bump() { + Some(c) => c, + // The only way to successfully break this loop is to observe + // a ']'. + None => return Err(self.error(ErrorKind::UnclosedClass)), + }; + match c { + ']' => { + if first { + ranges.push((']', ']')); + } else { + break; + } + } + '-' => { + if first { + ranges.push(('-', '-')); + } else if in_range { + // invariant: in_range is only set when there is + // already at least one character seen. + let r = ranges.last_mut().unwrap(); + add_to_last_range(&self.glob, r, '-')?; + in_range = false; + } else { + assert!(!ranges.is_empty()); + in_range = true; + } + } + c => { + if in_range { + // invariant: in_range is only set when there is + // already at least one character seen. + add_to_last_range( + &self.glob, ranges.last_mut().unwrap(), c)?; + } else { + ranges.push((c, c)); + } + in_range = false; + } + } + first = false; + } + if in_range { + // Means that the last character in the class was a '-', so add + // it as a literal. + ranges.push(('-', '-')); + } + self.push_token(Token::Class { + negated: negated, + ranges: ranges, + }) + } + + fn bump(&mut self) -> Option { + self.prev = self.cur; + self.cur = self.chars.next(); + self.cur + } + + fn peek(&mut self) -> Option { + self.chars.peek().map(|&ch| ch) + } +} + +#[cfg(test)] +fn starts_with(needle: &[u8], haystack: &[u8]) -> bool { + needle.len() <= haystack.len() && needle == &haystack[..needle.len()] +} + +#[cfg(test)] +fn ends_with(needle: &[u8], haystack: &[u8]) -> bool { + if needle.len() > haystack.len() { + return false; + } + needle == &haystack[haystack.len() - needle.len()..] +} + +#[cfg(test)] +mod tests { + use {GlobSetBuilder, ErrorKind}; + use super::{Glob, GlobBuilder, Token}; + use super::Token::*; + + #[derive(Clone, Copy, Debug, Default)] + struct Options { + casei: Option, + litsep: Option, + bsesc: Option, + } + + macro_rules! syntax { + ($name:ident, $pat:expr, $tokens:expr) => { + #[test] + fn $name() { + let pat = Glob::new($pat).unwrap(); + assert_eq!($tokens, pat.tokens.0); + } + } + } + + macro_rules! syntaxerr { + ($name:ident, $pat:expr, $err:expr) => { + #[test] + fn $name() { + let err = Glob::new($pat).unwrap_err(); + assert_eq!(&$err, err.kind()); + } + } + } + + macro_rules! toregex { + ($name:ident, $pat:expr, $re:expr) => { + toregex!($name, $pat, $re, Options::default()); + }; + ($name:ident, $pat:expr, $re:expr, $options:expr) => { + #[test] + fn $name() { + let mut builder = GlobBuilder::new($pat); + if let Some(casei) = $options.casei { + builder.case_insensitive(casei); + } + if let Some(litsep) = $options.litsep { + builder.literal_separator(litsep); + } + if let Some(bsesc) = $options.bsesc { + builder.backslash_escape(bsesc); + } + let pat = builder.build().unwrap(); + assert_eq!(format!("(?-u){}", $re), pat.regex()); + } + }; + } + + macro_rules! matches { + ($name:ident, $pat:expr, $path:expr) => { + matches!($name, $pat, $path, Options::default()); + }; + ($name:ident, $pat:expr, $path:expr, $options:expr) => { + #[test] + fn $name() { + let mut builder = GlobBuilder::new($pat); + if let Some(casei) = $options.casei { + builder.case_insensitive(casei); + } + if let Some(litsep) = $options.litsep { + builder.literal_separator(litsep); + } + if let Some(bsesc) = $options.bsesc { + builder.backslash_escape(bsesc); + } + let pat = builder.build().unwrap(); + let matcher = pat.compile_matcher(); + let strategic = pat.compile_strategic_matcher(); + let set = GlobSetBuilder::new().add(pat).build().unwrap(); + assert!(matcher.is_match($path)); + assert!(strategic.is_match($path)); + assert!(set.is_match($path)); + } + }; + } + + macro_rules! nmatches { + ($name:ident, $pat:expr, $path:expr) => { + nmatches!($name, $pat, $path, Options::default()); + }; + ($name:ident, $pat:expr, $path:expr, $options:expr) => { + #[test] + fn $name() { + let mut builder = GlobBuilder::new($pat); + if let Some(casei) = $options.casei { + builder.case_insensitive(casei); + } + if let Some(litsep) = $options.litsep { + builder.literal_separator(litsep); + } + if let Some(bsesc) = $options.bsesc { + builder.backslash_escape(bsesc); + } + let pat = builder.build().unwrap(); + let matcher = pat.compile_matcher(); + let strategic = pat.compile_strategic_matcher(); + let set = GlobSetBuilder::new().add(pat).build().unwrap(); + assert!(!matcher.is_match($path)); + assert!(!strategic.is_match($path)); + assert!(!set.is_match($path)); + } + }; + } + + fn s(string: &str) -> String { string.to_string() } + + fn class(s: char, e: char) -> Token { + Class { negated: false, ranges: vec![(s, e)] } + } + + fn classn(s: char, e: char) -> Token { + Class { negated: true, ranges: vec![(s, e)] } + } + + fn rclass(ranges: &[(char, char)]) -> Token { + Class { negated: false, ranges: ranges.to_vec() } + } + + fn rclassn(ranges: &[(char, char)]) -> Token { + Class { negated: true, ranges: ranges.to_vec() } + } + + syntax!(literal1, "a", vec![Literal('a')]); + syntax!(literal2, "ab", vec![Literal('a'), Literal('b')]); + syntax!(any1, "?", vec![Any]); + syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]); + syntax!(seq1, "*", vec![ZeroOrMore]); + syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]); + syntax!(seq3, "*a*b*", vec![ + ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore, + ]); + syntax!(rseq1, "**", vec![RecursivePrefix]); + syntax!(rseq2, "**/", vec![RecursivePrefix]); + syntax!(rseq3, "/**", vec![RecursiveSuffix]); + syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]); + syntax!(rseq5, "a/**/b", vec![ + Literal('a'), RecursiveZeroOrMore, Literal('b'), + ]); + syntax!(cls1, "[a]", vec![class('a', 'a')]); + syntax!(cls2, "[!a]", vec![classn('a', 'a')]); + syntax!(cls3, "[a-z]", vec![class('a', 'z')]); + syntax!(cls4, "[!a-z]", vec![classn('a', 'z')]); + syntax!(cls5, "[-]", vec![class('-', '-')]); + syntax!(cls6, "[]]", vec![class(']', ']')]); + syntax!(cls7, "[*]", vec![class('*', '*')]); + syntax!(cls8, "[!!]", vec![classn('!', '!')]); + syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]); + syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]); + syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]); + syntax!(cls12, "[-a-z-]", vec![ + rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]), + ]); + syntax!(cls13, "[]-z]", vec![class(']', 'z')]); + syntax!(cls14, "[--z]", vec![class('-', 'z')]); + syntax!(cls15, "[ --]", vec![class(' ', '-')]); + syntax!(cls16, "[0-9a-z]", vec![rclass(&[('0', '9'), ('a', 'z')])]); + syntax!(cls17, "[a-z0-9]", vec![rclass(&[('a', 'z'), ('0', '9')])]); + syntax!(cls18, "[!0-9a-z]", vec![rclassn(&[('0', '9'), ('a', 'z')])]); + syntax!(cls19, "[!a-z0-9]", vec![rclassn(&[('a', 'z'), ('0', '9')])]); + syntax!(cls20, "[^a]", vec![classn('a', 'a')]); + syntax!(cls21, "[^a-z]", vec![classn('a', 'z')]); + + syntaxerr!(err_unclosed1, "[", ErrorKind::UnclosedClass); + syntaxerr!(err_unclosed2, "[]", ErrorKind::UnclosedClass); + syntaxerr!(err_unclosed3, "[!", ErrorKind::UnclosedClass); + syntaxerr!(err_unclosed4, "[!]", ErrorKind::UnclosedClass); + syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a')); + syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-')); + + const CASEI: Options = Options { + casei: Some(true), + litsep: None, + bsesc: None, + }; + const SLASHLIT: Options = Options { + casei: None, + litsep: Some(true), + bsesc: None, + }; + const NOBSESC: Options = Options { + casei: None, + litsep: None, + bsesc: Some(false), + }; + const BSESC: Options = Options { + casei: None, + litsep: None, + bsesc: Some(true), + }; + + toregex!(re_casei, "a", "(?i)^a$", &CASEI); + + toregex!(re_slash1, "?", r"^[^/]$", SLASHLIT); + toregex!(re_slash2, "*", r"^[^/]*$", SLASHLIT); + + toregex!(re1, "a", "^a$"); + toregex!(re2, "?", "^.$"); + toregex!(re3, "*", "^.*$"); + toregex!(re4, "a?", "^a.$"); + toregex!(re5, "?a", "^.a$"); + toregex!(re6, "a*", "^a.*$"); + toregex!(re7, "*a", "^.*a$"); + toregex!(re8, "[*]", r"^[\*]$"); + toregex!(re9, "[+]", r"^[\+]$"); + toregex!(re10, "+", r"^\+$"); + toregex!(re11, "☃", r"^\xe2\x98\x83$"); + toregex!(re12, "**", r"^.*$"); + toregex!(re13, "**/", r"^.*$"); + toregex!(re14, "**/*", r"^(?:/?|.*/).*$"); + toregex!(re15, "**/**", r"^.*$"); + toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$"); + toregex!(re17, "**/**/**", r"^.*$"); + toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$"); + toregex!(re19, "a/**", r"^a(?:/?|/.*)$"); + toregex!(re20, "a/**/**", r"^a(?:/?|/.*)$"); + toregex!(re21, "a/**/**/**", r"^a(?:/?|/.*)$"); + toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$"); + toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$"); + toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$"); + toregex!(re25, "**/b", r"^(?:/?|.*/)b$"); + toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$"); + toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$"); + toregex!(re28, "a**", r"^a.*.*$"); + toregex!(re29, "**a", r"^.*.*a$"); + toregex!(re30, "a**b", r"^a.*.*b$"); + toregex!(re31, "***", r"^.*.*.*$"); + toregex!(re32, "/a**", r"^/a.*.*$"); + toregex!(re33, "/**a", r"^/.*.*a$"); + toregex!(re34, "/a**b", r"^/a.*.*b$"); + + matches!(match1, "a", "a"); + matches!(match2, "a*b", "a_b"); + matches!(match3, "a*b*c", "abc"); + matches!(match4, "a*b*c", "a_b_c"); + matches!(match5, "a*b*c", "a___b___c"); + matches!(match6, "abc*abc*abc", "abcabcabcabcabcabcabc"); + matches!(match7, "a*a*a*a*a*a*a*a*a", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + matches!(match8, "a*b[xyz]c*d", "abxcdbxcddd"); + matches!(match9, "*.rs", ".rs"); + matches!(match10, "☃", "☃"); + + matches!(matchrec1, "some/**/needle.txt", "some/needle.txt"); + matches!(matchrec2, "some/**/needle.txt", "some/one/needle.txt"); + matches!(matchrec3, "some/**/needle.txt", "some/one/two/needle.txt"); + matches!(matchrec4, "some/**/needle.txt", "some/other/needle.txt"); + matches!(matchrec5, "**", "abcde"); + matches!(matchrec6, "**", ""); + matches!(matchrec7, "**", ".asdf"); + matches!(matchrec8, "**", "/x/.asdf"); + matches!(matchrec9, "some/**/**/needle.txt", "some/needle.txt"); + matches!(matchrec10, "some/**/**/needle.txt", "some/one/needle.txt"); + matches!(matchrec11, "some/**/**/needle.txt", "some/one/two/needle.txt"); + matches!(matchrec12, "some/**/**/needle.txt", "some/other/needle.txt"); + matches!(matchrec13, "**/test", "one/two/test"); + matches!(matchrec14, "**/test", "one/test"); + matches!(matchrec15, "**/test", "test"); + matches!(matchrec16, "/**/test", "/one/two/test"); + matches!(matchrec17, "/**/test", "/one/test"); + matches!(matchrec18, "/**/test", "/test"); + matches!(matchrec19, "**/.*", ".abc"); + matches!(matchrec20, "**/.*", "abc/.abc"); + matches!(matchrec21, ".*/**", ".abc"); + matches!(matchrec22, ".*/**", ".abc/abc"); + matches!(matchrec23, "foo/**", "foo"); + matches!(matchrec24, "**/foo/bar", "foo/bar"); + matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt"); + + matches!(matchrange1, "a[0-9]b", "a0b"); + matches!(matchrange2, "a[0-9]b", "a9b"); + matches!(matchrange3, "a[!0-9]b", "a_b"); + matches!(matchrange4, "[a-z123]", "1"); + matches!(matchrange5, "[1a-z23]", "1"); + matches!(matchrange6, "[123a-z]", "1"); + matches!(matchrange7, "[abc-]", "-"); + matches!(matchrange8, "[-abc]", "-"); + matches!(matchrange9, "[-a-c]", "b"); + matches!(matchrange10, "[a-c-]", "b"); + matches!(matchrange11, "[-]", "-"); + matches!(matchrange12, "a[^0-9]b", "a_b"); + + matches!(matchpat1, "*hello.txt", "hello.txt"); + matches!(matchpat2, "*hello.txt", "gareth_says_hello.txt"); + matches!(matchpat3, "*hello.txt", "some/path/to/hello.txt"); + matches!(matchpat4, "*hello.txt", "some\\path\\to\\hello.txt"); + matches!(matchpat5, "*hello.txt", "/an/absolute/path/to/hello.txt"); + matches!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt"); + matches!(matchpat7, "*some/path/to/hello.txt", + "a/bigger/some/path/to/hello.txt"); + + matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_"); + + matches!(matchcasei1, "aBcDeFg", "aBcDeFg", CASEI); + matches!(matchcasei2, "aBcDeFg", "abcdefg", CASEI); + matches!(matchcasei3, "aBcDeFg", "ABCDEFG", CASEI); + matches!(matchcasei4, "aBcDeFg", "AbCdEfG", CASEI); + + matches!(matchalt1, "a,b", "a,b"); + matches!(matchalt2, ",", ","); + matches!(matchalt3, "{a,b}", "a"); + matches!(matchalt4, "{a,b}", "b"); + matches!(matchalt5, "{**/src/**,foo}", "abc/src/bar"); + matches!(matchalt6, "{**/src/**,foo}", "foo"); + matches!(matchalt7, "{[}],foo}", "}"); + matches!(matchalt8, "{foo}", "foo"); + matches!(matchalt9, "{}", ""); + matches!(matchalt10, "{,}", ""); + matches!(matchalt11, "{*.foo,*.bar,*.wat}", "test.foo"); + matches!(matchalt12, "{*.foo,*.bar,*.wat}", "test.bar"); + matches!(matchalt13, "{*.foo,*.bar,*.wat}", "test.wat"); + + matches!(matchslash1, "abc/def", "abc/def", SLASHLIT); + #[cfg(unix)] + nmatches!(matchslash2, "abc?def", "abc/def", SLASHLIT); + #[cfg(not(unix))] + nmatches!(matchslash2, "abc?def", "abc\\def", SLASHLIT); + nmatches!(matchslash3, "abc*def", "abc/def", SLASHLIT); + matches!(matchslash4, "abc[/]def", "abc/def", SLASHLIT); // differs + #[cfg(unix)] + nmatches!(matchslash5, "abc\\def", "abc/def", SLASHLIT); + #[cfg(not(unix))] + matches!(matchslash5, "abc\\def", "abc/def", SLASHLIT); + + matches!(matchbackslash1, "\\[", "[", BSESC); + matches!(matchbackslash2, "\\?", "?", BSESC); + matches!(matchbackslash3, "\\*", "*", BSESC); + matches!(matchbackslash4, "\\[a-z]", "\\a", NOBSESC); + matches!(matchbackslash5, "\\?", "\\a", NOBSESC); + matches!(matchbackslash6, "\\*", "\\\\", NOBSESC); + #[cfg(unix)] + matches!(matchbackslash7, "\\a", "a"); + #[cfg(not(unix))] + matches!(matchbackslash8, "\\a", "/a"); + + nmatches!(matchnot1, "a*b*c", "abcd"); + nmatches!(matchnot2, "abc*abc*abc", "abcabcabcabcabcabcabca"); + nmatches!(matchnot3, "some/**/needle.txt", "some/other/notthis.txt"); + nmatches!(matchnot4, "some/**/**/needle.txt", "some/other/notthis.txt"); + nmatches!(matchnot5, "/**/test", "test"); + nmatches!(matchnot6, "/**/test", "/one/notthis"); + nmatches!(matchnot7, "/**/test", "/notthis"); + nmatches!(matchnot8, "**/.*", "ab.c"); + nmatches!(matchnot9, "**/.*", "abc/ab.c"); + nmatches!(matchnot10, ".*/**", "a.bc"); + nmatches!(matchnot11, ".*/**", "abc/a.bc"); + nmatches!(matchnot12, "a[0-9]b", "a_b"); + nmatches!(matchnot13, "a[!0-9]b", "a0b"); + nmatches!(matchnot14, "a[!0-9]b", "a9b"); + nmatches!(matchnot15, "[!-]", "-"); + nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some"); + nmatches!(matchnot17, "*hello.txt", "goodbye.txt"); + nmatches!(matchnot18, "*some/path/to/hello.txt", + "some/path/to/hello.txt-and-then-some"); + nmatches!(matchnot19, "*some/path/to/hello.txt", + "some/other/path/to/hello.txt"); + nmatches!(matchnot20, "a", "foo/a"); + nmatches!(matchnot21, "./foo", "foo"); + nmatches!(matchnot22, "**/foo", "foofoo"); + nmatches!(matchnot23, "**/foo/bar", "foofoo/bar"); + nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c"); + nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT); + nmatches!(matchnot26, "**/m4/ltoptions.m4", + "csharp/src/packages/repositories.config", SLASHLIT); + nmatches!(matchnot27, "a[^0-9]b", "a0b"); + nmatches!(matchnot28, "a[^0-9]b", "a9b"); + nmatches!(matchnot29, "[^-]", "-"); + nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt"); + nmatches!( + matchrec31, + "some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT); + nmatches!( + matchrec32, + "some/*/needle.txt", "some/one/two/three/needle.txt", SLASHLIT); + + macro_rules! extract { + ($which:ident, $name:ident, $pat:expr, $expect:expr) => { + extract!($which, $name, $pat, $expect, Options::default()); + }; + ($which:ident, $name:ident, $pat:expr, $expect:expr, $options:expr) => { + #[test] + fn $name() { + let mut builder = GlobBuilder::new($pat); + if let Some(casei) = $options.casei { + builder.case_insensitive(casei); + } + if let Some(litsep) = $options.litsep { + builder.literal_separator(litsep); + } + if let Some(bsesc) = $options.bsesc { + builder.backslash_escape(bsesc); + } + let pat = builder.build().unwrap(); + assert_eq!($expect, pat.$which()); + } + }; + } + + macro_rules! literal { + ($($tt:tt)*) => { extract!(literal, $($tt)*); } + } + + macro_rules! basetokens { + ($($tt:tt)*) => { extract!(basename_tokens, $($tt)*); } + } + + macro_rules! ext { + ($($tt:tt)*) => { extract!(ext, $($tt)*); } + } + + macro_rules! required_ext { + ($($tt:tt)*) => { extract!(required_ext, $($tt)*); } + } + + macro_rules! prefix { + ($($tt:tt)*) => { extract!(prefix, $($tt)*); } + } + + macro_rules! suffix { + ($($tt:tt)*) => { extract!(suffix, $($tt)*); } + } + + macro_rules! baseliteral { + ($($tt:tt)*) => { extract!(basename_literal, $($tt)*); } + } + + literal!(extract_lit1, "foo", Some(s("foo"))); + literal!(extract_lit2, "foo", None, CASEI); + literal!(extract_lit3, "/foo", Some(s("/foo"))); + literal!(extract_lit4, "/foo/", Some(s("/foo/"))); + literal!(extract_lit5, "/foo/bar", Some(s("/foo/bar"))); + literal!(extract_lit6, "*.foo", None); + literal!(extract_lit7, "foo/bar", Some(s("foo/bar"))); + literal!(extract_lit8, "**/foo/bar", None); + + basetokens!(extract_basetoks1, "**/foo", Some(&*vec![ + Literal('f'), Literal('o'), Literal('o'), + ])); + basetokens!(extract_basetoks2, "**/foo", None, CASEI); + basetokens!(extract_basetoks3, "**/foo", Some(&*vec![ + Literal('f'), Literal('o'), Literal('o'), + ]), SLASHLIT); + basetokens!(extract_basetoks4, "*foo", None, SLASHLIT); + basetokens!(extract_basetoks5, "*foo", None); + basetokens!(extract_basetoks6, "**/fo*o", None); + basetokens!(extract_basetoks7, "**/fo*o", Some(&*vec![ + Literal('f'), Literal('o'), ZeroOrMore, Literal('o'), + ]), SLASHLIT); + + ext!(extract_ext1, "**/*.rs", Some(s(".rs"))); + ext!(extract_ext2, "**/*.rs.bak", None); + ext!(extract_ext3, "*.rs", Some(s(".rs"))); + ext!(extract_ext4, "a*.rs", None); + ext!(extract_ext5, "/*.c", None); + ext!(extract_ext6, "*.c", None, SLASHLIT); + ext!(extract_ext7, "*.c", Some(s(".c"))); + + required_ext!(extract_req_ext1, "*.rs", Some(s(".rs"))); + required_ext!(extract_req_ext2, "/foo/bar/*.rs", Some(s(".rs"))); + required_ext!(extract_req_ext3, "/foo/bar/*.rs", Some(s(".rs"))); + required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(s(".rs"))); + required_ext!(extract_req_ext5, ".rs", Some(s(".rs"))); + required_ext!(extract_req_ext6, "./rs", None); + required_ext!(extract_req_ext7, "foo", None); + required_ext!(extract_req_ext8, ".foo/", None); + required_ext!(extract_req_ext9, "foo/", None); + + prefix!(extract_prefix1, "/foo", Some(s("/foo"))); + prefix!(extract_prefix2, "/foo/*", Some(s("/foo/"))); + prefix!(extract_prefix3, "**/foo", None); + prefix!(extract_prefix4, "foo/**", None); + + suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true))); + suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false))); + suffix!(extract_suffix3, "*/foo/bar", None, SLASHLIT); + suffix!(extract_suffix4, "foo/bar", Some((s("foo/bar"), false))); + suffix!(extract_suffix5, "*.foo", Some((s(".foo"), false))); + suffix!(extract_suffix6, "*.foo", None, SLASHLIT); + suffix!(extract_suffix7, "**/*_test", Some((s("_test"), false))); + + baseliteral!(extract_baselit1, "**/foo", Some(s("foo"))); + baseliteral!(extract_baselit2, "foo", None); + baseliteral!(extract_baselit3, "*foo", None); + baseliteral!(extract_baselit4, "*/foo", None); +} diff --git a/globset/src/lib.rs b/globset/src/lib.rs new file mode 100644 index 000000000..6b3ca85c6 --- /dev/null +++ b/globset/src/lib.rs @@ -0,0 +1,871 @@ +/*! +The globset crate provides cross platform single glob and glob set matching. + +Glob set matching is the process of matching one or more glob patterns against +a single candidate path simultaneously, and returning all of the globs that +matched. For example, given this set of globs: + +```ignore +*.rs +src/lib.rs +src/**/foo.rs +``` + +and a path `src/bar/baz/foo.rs`, then the set would report the first and third +globs as matching. + +# Example: one glob + +This example shows how to match a single glob against a single file path. + +``` +# fn example() -> Result<(), globset::Error> { +use globset::Glob; + +let glob = Glob::new("*.rs")?.compile_matcher(); + +assert!(glob.is_match("foo.rs")); +assert!(glob.is_match("foo/bar.rs")); +assert!(!glob.is_match("Cargo.toml")); +# Ok(()) } example().unwrap(); +``` + +# Example: configuring a glob matcher + +This example shows how to use a `GlobBuilder` to configure aspects of match +semantics. In this example, we prevent wildcards from matching path separators. + +``` +# fn example() -> Result<(), globset::Error> { +use globset::GlobBuilder; + +let glob = GlobBuilder::new("*.rs") + .literal_separator(true).build()?.compile_matcher(); + +assert!(glob.is_match("foo.rs")); +assert!(!glob.is_match("foo/bar.rs")); // no longer matches +assert!(!glob.is_match("Cargo.toml")); +# Ok(()) } example().unwrap(); +``` + +# Example: match multiple globs at once + +This example shows how to match multiple glob patterns at once. + +``` +# fn example() -> Result<(), globset::Error> { +use globset::{Glob, GlobSetBuilder}; + +let mut builder = GlobSetBuilder::new(); +// A GlobBuilder can be used to configure each glob's match semantics +// independently. +builder.add(Glob::new("*.rs")?); +builder.add(Glob::new("src/lib.rs")?); +builder.add(Glob::new("src/**/foo.rs")?); +let set = builder.build()?; + +assert_eq!(set.matches("src/bar/baz/foo.rs"), vec![0, 2]); +# Ok(()) } example().unwrap(); +``` + +# Syntax + +Standard Unix-style glob syntax is supported: + +* `?` matches any single character. (If the `literal_separator` option is + enabled, then `?` can never match a path separator.) +* `*` matches zero or more characters. (If the `literal_separator` option is + enabled, then `*` can never match a path separator.) +* `**` recursively matches directories but are only legal in three situations. + First, if the glob starts with \*\*/, then it matches + all directories. For example, \*\*/foo matches `foo` + and `bar/foo` but not `foo/bar`. Secondly, if the glob ends with + /\*\*, then it matches all sub-entries. For example, + foo/\*\* matches `foo/a` and `foo/a/b`, but not `foo`. + Thirdly, if the glob contains /\*\*/ anywhere within + the pattern, then it matches zero or more directories. Using `**` anywhere + else is illegal (N.B. the glob `**` is allowed and means "match everything"). +* `{a,b}` matches `a` or `b` where `a` and `b` are arbitrary glob patterns. + (N.B. Nesting `{...}` is not currently allowed.) +* `[ab]` matches `a` or `b` where `a` and `b` are characters. Use + `[!ab]` to match any character except for `a` and `b`. +* Metacharacters such as `*` and `?` can be escaped with character class + notation. e.g., `[*]` matches `*`. +* When backslash escapes are enabled, a backslash (`\`) will escape all meta + characters in a glob. If it precedes a non-meta character, then the slash is + ignored. A `\\` will match a literal `\\`. Note that this mode is only + enabled on Unix platforms by default, but can be enabled on any platform + via the `backslash_escape` setting on `Glob`. + +A `GlobBuilder` can be used to prevent wildcards from matching path separators, +or to enable case insensitive matching. +*/ + +#![deny(missing_docs)] + +extern crate aho_corasick; +extern crate bstr; +extern crate fnv; +#[macro_use] +extern crate log; +extern crate regex; + +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap}; +use std::error::Error as StdError; +use std::fmt; +use std::hash; +use std::path::Path; +use std::str; + +use aho_corasick::AhoCorasick; +use bstr::{B, BStr, BString}; +use regex::bytes::{Regex, RegexBuilder, RegexSet}; + +use pathutil::{file_name, file_name_ext, normalize_path}; +use glob::MatchStrategy; +pub use glob::{Glob, GlobBuilder, GlobMatcher}; + +mod glob; +mod pathutil; + +/// Represents an error that can occur when parsing a glob pattern. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Error { + /// The original glob provided by the caller. + glob: Option, + /// The kind of error. + kind: ErrorKind, +} + +/// The kind of error that can occur when parsing a glob pattern. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ErrorKind { + /// **DEPRECATED**. + /// + /// This error used to occur for consistency with git's glob specification, + /// but the specification now accepts all uses of `**`. When `**` does not + /// appear adjacent to a path separator or at the beginning/end of a glob, + /// it is now treated as two consecutive `*` patterns. As such, this error + /// is no longer used. + InvalidRecursive, + /// Occurs when a character class (e.g., `[abc]`) is not closed. + UnclosedClass, + /// Occurs when a range in a character (e.g., `[a-z]`) is invalid. For + /// example, if the range starts with a lexicographically larger character + /// than it ends with. + InvalidRange(char, char), + /// Occurs when a `}` is found without a matching `{`. + UnopenedAlternates, + /// Occurs when a `{` is found without a matching `}`. + UnclosedAlternates, + /// Occurs when an alternating group is nested inside another alternating + /// group, e.g., `{{a,b},{c,d}}`. + NestedAlternates, + /// Occurs when an unescaped '\' is found at the end of a glob. + DanglingEscape, + /// An error associated with parsing or compiling a regex. + Regex(String), + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +impl StdError for Error { + fn description(&self) -> &str { + self.kind.description() + } +} + +impl Error { + /// Return the glob that caused this error, if one exists. + pub fn glob(&self) -> Option<&str> { + self.glob.as_ref().map(|s| &**s) + } + + /// Return the kind of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } +} + +impl ErrorKind { + fn description(&self) -> &str { + match *self { + ErrorKind::InvalidRecursive => { + "invalid use of **; must be one path component" + } + ErrorKind::UnclosedClass => { + "unclosed character class; missing ']'" + } + ErrorKind::InvalidRange(_, _) => { + "invalid character range" + } + ErrorKind::UnopenedAlternates => { + "unopened alternate group; missing '{' \ + (maybe escape '}' with '[}]'?)" + } + ErrorKind::UnclosedAlternates => { + "unclosed alternate group; missing '}' \ + (maybe escape '{' with '[{]'?)" + } + ErrorKind::NestedAlternates => { + "nested alternate groups are not allowed" + } + ErrorKind::DanglingEscape => { + "dangling '\\'" + } + ErrorKind::Regex(ref err) => err, + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.glob { + None => self.kind.fmt(f), + Some(ref glob) => { + write!(f, "error parsing glob '{}': {}", glob, self.kind) + } + } + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ErrorKind::InvalidRecursive + | ErrorKind::UnclosedClass + | ErrorKind::UnopenedAlternates + | ErrorKind::UnclosedAlternates + | ErrorKind::NestedAlternates + | ErrorKind::DanglingEscape + | ErrorKind::Regex(_) => { + write!(f, "{}", self.description()) + } + ErrorKind::InvalidRange(s, e) => { + write!(f, "invalid range; '{}' > '{}'", s, e) + } + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + +fn new_regex(pat: &str) -> Result { + RegexBuilder::new(pat) + .dot_matches_new_line(true) + .size_limit(10 * (1 << 20)) + .dfa_size_limit(10 * (1 << 20)) + .build() + .map_err(|err| { + Error { + glob: Some(pat.to_string()), + kind: ErrorKind::Regex(err.to_string()), + } + }) +} + +fn new_regex_set(pats: I) -> Result + where S: AsRef, I: IntoIterator { + RegexSet::new(pats).map_err(|err| { + Error { + glob: None, + kind: ErrorKind::Regex(err.to_string()), + } + }) +} + +type Fnv = hash::BuildHasherDefault; + +/// GlobSet represents a group of globs that can be matched together in a +/// single pass. +#[derive(Clone, Debug)] +pub struct GlobSet { + len: usize, + strats: Vec, +} + +impl GlobSet { + /// Create an empty `GlobSet`. An empty set matches nothing. + #[inline] + pub fn empty() -> GlobSet { + GlobSet { + len: 0, + strats: vec![], + } + } + + /// Returns true if this set is empty, and therefore matches nothing. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns the number of globs in this set. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns true if any glob in this set matches the path given. + pub fn is_match>(&self, path: P) -> bool { + self.is_match_candidate(&Candidate::new(path.as_ref())) + } + + /// Returns true if any glob in this set matches the path given. + /// + /// This takes a Candidate as input, which can be used to amortize the + /// cost of preparing a path for matching. + pub fn is_match_candidate(&self, path: &Candidate) -> bool { + if self.is_empty() { + return false; + } + for strat in &self.strats { + if strat.is_match(path) { + return true; + } + } + false + } + + /// Returns the sequence number of every glob pattern that matches the + /// given path. + pub fn matches>(&self, path: P) -> Vec { + self.matches_candidate(&Candidate::new(path.as_ref())) + } + + /// Returns the sequence number of every glob pattern that matches the + /// given path. + /// + /// This takes a Candidate as input, which can be used to amortize the + /// cost of preparing a path for matching. + pub fn matches_candidate(&self, path: &Candidate) -> Vec { + let mut into = vec![]; + if self.is_empty() { + return into; + } + self.matches_candidate_into(path, &mut into); + into + } + + /// Adds the sequence number of every glob pattern that matches the given + /// path to the vec given. + /// + /// `into` is is cleared before matching begins, and contains the set of + /// sequence numbers (in ascending order) after matching ends. If no globs + /// were matched, then `into` will be empty. + pub fn matches_into>( + &self, + path: P, + into: &mut Vec, + ) { + self.matches_candidate_into(&Candidate::new(path.as_ref()), into); + } + + /// Adds the sequence number of every glob pattern that matches the given + /// path to the vec given. + /// + /// `into` is is cleared before matching begins, and contains the set of + /// sequence numbers (in ascending order) after matching ends. If no globs + /// were matched, then `into` will be empty. + /// + /// This takes a Candidate as input, which can be used to amortize the + /// cost of preparing a path for matching. + pub fn matches_candidate_into( + &self, + path: &Candidate, + into: &mut Vec, + ) { + into.clear(); + if self.is_empty() { + return; + } + for strat in &self.strats { + strat.matches_into(path, into); + } + into.sort(); + into.dedup(); + } + + fn new(pats: &[Glob]) -> Result { + if pats.is_empty() { + return Ok(GlobSet { len: 0, strats: vec![] }); + } + let mut lits = LiteralStrategy::new(); + let mut base_lits = BasenameLiteralStrategy::new(); + let mut exts = ExtensionStrategy::new(); + let mut prefixes = MultiStrategyBuilder::new(); + let mut suffixes = MultiStrategyBuilder::new(); + let mut required_exts = RequiredExtensionStrategyBuilder::new(); + let mut regexes = MultiStrategyBuilder::new(); + for (i, p) in pats.iter().enumerate() { + match MatchStrategy::new(p) { + MatchStrategy::Literal(lit) => { + lits.add(i, lit); + } + MatchStrategy::BasenameLiteral(lit) => { + base_lits.add(i, lit); + } + MatchStrategy::Extension(ext) => { + exts.add(i, ext); + } + MatchStrategy::Prefix(prefix) => { + prefixes.add(i, prefix); + } + MatchStrategy::Suffix { suffix, component } => { + if component { + lits.add(i, suffix[1..].to_string()); + } + suffixes.add(i, suffix); + } + MatchStrategy::RequiredExtension(ext) => { + required_exts.add(i, ext, p.regex().to_owned()); + } + MatchStrategy::Regex => { + debug!("glob converted to regex: {:?}", p); + regexes.add(i, p.regex().to_owned()); + } + } + } + debug!("built glob set; {} literals, {} basenames, {} extensions, \ + {} prefixes, {} suffixes, {} required extensions, {} regexes", + lits.0.len(), base_lits.0.len(), exts.0.len(), + prefixes.literals.len(), suffixes.literals.len(), + required_exts.0.len(), regexes.literals.len()); + Ok(GlobSet { + len: pats.len(), + strats: vec![ + GlobSetMatchStrategy::Extension(exts), + GlobSetMatchStrategy::BasenameLiteral(base_lits), + GlobSetMatchStrategy::Literal(lits), + GlobSetMatchStrategy::Suffix(suffixes.suffix()), + GlobSetMatchStrategy::Prefix(prefixes.prefix()), + GlobSetMatchStrategy::RequiredExtension( + required_exts.build()?), + GlobSetMatchStrategy::Regex(regexes.regex_set()?), + ], + }) + } +} + +/// GlobSetBuilder builds a group of patterns that can be used to +/// simultaneously match a file path. +#[derive(Clone, Debug)] +pub struct GlobSetBuilder { + pats: Vec, +} + +impl GlobSetBuilder { + /// Create a new GlobSetBuilder. A GlobSetBuilder can be used to add new + /// patterns. Once all patterns have been added, `build` should be called + /// to produce a `GlobSet`, which can then be used for matching. + pub fn new() -> GlobSetBuilder { + GlobSetBuilder { pats: vec![] } + } + + /// Builds a new matcher from all of the glob patterns added so far. + /// + /// Once a matcher is built, no new patterns can be added to it. + pub fn build(&self) -> Result { + GlobSet::new(&self.pats) + } + + /// Add a new pattern to this set. + pub fn add(&mut self, pat: Glob) -> &mut GlobSetBuilder { + self.pats.push(pat); + self + } +} + +/// A candidate path for matching. +/// +/// All glob matching in this crate operates on `Candidate` values. +/// Constructing candidates has a very small cost associated with it, so +/// callers may find it beneficial to amortize that cost when matching a single +/// path against multiple globs or sets of globs. +#[derive(Clone, Debug)] +pub struct Candidate<'a> { + path: Cow<'a, BStr>, + basename: Cow<'a, BStr>, + ext: Cow<'a, BStr>, +} + +impl<'a> Candidate<'a> { + /// Create a new candidate for matching from the given path. + pub fn new + ?Sized>(path: &'a P) -> Candidate<'a> { + let path = normalize_path(BString::from_path_lossy(path.as_ref())); + let basename = file_name(&path).unwrap_or(Cow::Borrowed(B(""))); + let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B(""))); + Candidate { + path: path, + basename: basename, + ext: ext, + } + } + + fn path_prefix(&self, max: usize) -> &BStr { + if self.path.len() <= max { + &*self.path + } else { + &self.path[..max] + } + } + + fn path_suffix(&self, max: usize) -> &BStr { + if self.path.len() <= max { + &*self.path + } else { + &self.path[self.path.len() - max..] + } + } +} + +#[derive(Clone, Debug)] +enum GlobSetMatchStrategy { + Literal(LiteralStrategy), + BasenameLiteral(BasenameLiteralStrategy), + Extension(ExtensionStrategy), + Prefix(PrefixStrategy), + Suffix(SuffixStrategy), + RequiredExtension(RequiredExtensionStrategy), + Regex(RegexSetStrategy), +} + +impl GlobSetMatchStrategy { + fn is_match(&self, candidate: &Candidate) -> bool { + use self::GlobSetMatchStrategy::*; + match *self { + Literal(ref s) => s.is_match(candidate), + BasenameLiteral(ref s) => s.is_match(candidate), + Extension(ref s) => s.is_match(candidate), + Prefix(ref s) => s.is_match(candidate), + Suffix(ref s) => s.is_match(candidate), + RequiredExtension(ref s) => s.is_match(candidate), + Regex(ref s) => s.is_match(candidate), + } + } + + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + use self::GlobSetMatchStrategy::*; + match *self { + Literal(ref s) => s.matches_into(candidate, matches), + BasenameLiteral(ref s) => s.matches_into(candidate, matches), + Extension(ref s) => s.matches_into(candidate, matches), + Prefix(ref s) => s.matches_into(candidate, matches), + Suffix(ref s) => s.matches_into(candidate, matches), + RequiredExtension(ref s) => s.matches_into(candidate, matches), + Regex(ref s) => s.matches_into(candidate, matches), + } + } +} + +#[derive(Clone, Debug)] +struct LiteralStrategy(BTreeMap, Vec>); + +impl LiteralStrategy { + fn new() -> LiteralStrategy { + LiteralStrategy(BTreeMap::new()) + } + + fn add(&mut self, global_index: usize, lit: String) { + self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index); + } + + fn is_match(&self, candidate: &Candidate) -> bool { + self.0.contains_key(candidate.path.as_bytes()) + } + + #[inline(never)] + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + if let Some(hits) = self.0.get(candidate.path.as_bytes()) { + matches.extend(hits); + } + } +} + +#[derive(Clone, Debug)] +struct BasenameLiteralStrategy(BTreeMap, Vec>); + +impl BasenameLiteralStrategy { + fn new() -> BasenameLiteralStrategy { + BasenameLiteralStrategy(BTreeMap::new()) + } + + fn add(&mut self, global_index: usize, lit: String) { + self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index); + } + + fn is_match(&self, candidate: &Candidate) -> bool { + if candidate.basename.is_empty() { + return false; + } + self.0.contains_key(candidate.basename.as_bytes()) + } + + #[inline(never)] + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + if candidate.basename.is_empty() { + return; + } + if let Some(hits) = self.0.get(candidate.basename.as_bytes()) { + matches.extend(hits); + } + } +} + +#[derive(Clone, Debug)] +struct ExtensionStrategy(HashMap, Vec, Fnv>); + +impl ExtensionStrategy { + fn new() -> ExtensionStrategy { + ExtensionStrategy(HashMap::with_hasher(Fnv::default())) + } + + fn add(&mut self, global_index: usize, ext: String) { + self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index); + } + + fn is_match(&self, candidate: &Candidate) -> bool { + if candidate.ext.is_empty() { + return false; + } + self.0.contains_key(candidate.ext.as_bytes()) + } + + #[inline(never)] + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + if candidate.ext.is_empty() { + return; + } + if let Some(hits) = self.0.get(candidate.ext.as_bytes()) { + matches.extend(hits); + } + } +} + +#[derive(Clone, Debug)] +struct PrefixStrategy { + matcher: AhoCorasick, + map: Vec, + longest: usize, +} + +impl PrefixStrategy { + fn is_match(&self, candidate: &Candidate) -> bool { + let path = candidate.path_prefix(self.longest); + for m in self.matcher.find_overlapping_iter(path) { + if m.start() == 0 { + return true; + } + } + false + } + + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + let path = candidate.path_prefix(self.longest); + for m in self.matcher.find_overlapping_iter(path) { + if m.start() == 0 { + matches.push(self.map[m.pattern()]); + } + } + } +} + +#[derive(Clone, Debug)] +struct SuffixStrategy { + matcher: AhoCorasick, + map: Vec, + longest: usize, +} + +impl SuffixStrategy { + fn is_match(&self, candidate: &Candidate) -> bool { + let path = candidate.path_suffix(self.longest); + for m in self.matcher.find_overlapping_iter(path) { + if m.end() == path.len() { + return true; + } + } + false + } + + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + let path = candidate.path_suffix(self.longest); + for m in self.matcher.find_overlapping_iter(path) { + if m.end() == path.len() { + matches.push(self.map[m.pattern()]); + } + } + } +} + +#[derive(Clone, Debug)] +struct RequiredExtensionStrategy(HashMap, Vec<(usize, Regex)>, Fnv>); + +impl RequiredExtensionStrategy { + fn is_match(&self, candidate: &Candidate) -> bool { + if candidate.ext.is_empty() { + return false; + } + match self.0.get(candidate.ext.as_bytes()) { + None => false, + Some(regexes) => { + for &(_, ref re) in regexes { + if re.is_match(candidate.path.as_bytes()) { + return true; + } + } + false + } + } + } + + #[inline(never)] + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + if candidate.ext.is_empty() { + return; + } + if let Some(regexes) = self.0.get(candidate.ext.as_bytes()) { + for &(global_index, ref re) in regexes { + if re.is_match(candidate.path.as_bytes()) { + matches.push(global_index); + } + } + } + } +} + +#[derive(Clone, Debug)] +struct RegexSetStrategy { + matcher: RegexSet, + map: Vec, +} + +impl RegexSetStrategy { + fn is_match(&self, candidate: &Candidate) -> bool { + self.matcher.is_match(candidate.path.as_bytes()) + } + + fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { + for i in self.matcher.matches(candidate.path.as_bytes()) { + matches.push(self.map[i]); + } + } +} + +#[derive(Clone, Debug)] +struct MultiStrategyBuilder { + literals: Vec, + map: Vec, + longest: usize, +} + +impl MultiStrategyBuilder { + fn new() -> MultiStrategyBuilder { + MultiStrategyBuilder { + literals: vec![], + map: vec![], + longest: 0, + } + } + + fn add(&mut self, global_index: usize, literal: String) { + if literal.len() > self.longest { + self.longest = literal.len(); + } + self.map.push(global_index); + self.literals.push(literal); + } + + fn prefix(self) -> PrefixStrategy { + PrefixStrategy { + matcher: AhoCorasick::new_auto_configured(&self.literals), + map: self.map, + longest: self.longest, + } + } + + fn suffix(self) -> SuffixStrategy { + SuffixStrategy { + matcher: AhoCorasick::new_auto_configured(&self.literals), + map: self.map, + longest: self.longest, + } + } + + fn regex_set(self) -> Result { + Ok(RegexSetStrategy { + matcher: new_regex_set(self.literals)?, + map: self.map, + }) + } +} + +#[derive(Clone, Debug)] +struct RequiredExtensionStrategyBuilder( + HashMap, Vec<(usize, String)>>, +); + +impl RequiredExtensionStrategyBuilder { + fn new() -> RequiredExtensionStrategyBuilder { + RequiredExtensionStrategyBuilder(HashMap::new()) + } + + fn add(&mut self, global_index: usize, ext: String, regex: String) { + self.0 + .entry(ext.into_bytes()) + .or_insert(vec![]) + .push((global_index, regex)); + } + + fn build(self) -> Result { + let mut exts = HashMap::with_hasher(Fnv::default()); + for (ext, regexes) in self.0.into_iter() { + exts.insert(ext.clone(), vec![]); + for (global_index, regex) in regexes { + let compiled = new_regex(®ex)?; + exts.get_mut(&ext).unwrap().push((global_index, compiled)); + } + } + Ok(RequiredExtensionStrategy(exts)) + } +} + +#[cfg(test)] +mod tests { + use super::GlobSetBuilder; + use glob::Glob; + + #[test] + fn set_works() { + let mut builder = GlobSetBuilder::new(); + builder.add(Glob::new("src/**/*.rs").unwrap()); + builder.add(Glob::new("*.c").unwrap()); + builder.add(Glob::new("src/lib.rs").unwrap()); + let set = builder.build().unwrap(); + + assert!(set.is_match("foo.c")); + assert!(set.is_match("src/foo.c")); + assert!(!set.is_match("foo.rs")); + assert!(!set.is_match("tests/foo.rs")); + assert!(set.is_match("src/foo.rs")); + assert!(set.is_match("src/grep/src/main.rs")); + + let matches = set.matches("src/lib.rs"); + assert_eq!(2, matches.len()); + assert_eq!(0, matches[0]); + assert_eq!(2, matches[1]); + } + + #[test] + fn empty_set_works() { + let set = GlobSetBuilder::new().build().unwrap(); + assert!(!set.is_match("")); + assert!(!set.is_match("a")); + } +} diff --git a/globset/src/pathutil.rs b/globset/src/pathutil.rs new file mode 100644 index 000000000..6c2fb1e99 --- /dev/null +++ b/globset/src/pathutil.rs @@ -0,0 +1,129 @@ +use std::borrow::Cow; + +use bstr::BStr; + +/// The final component of the path, if it is a normal file. +/// +/// If the path terminates in ., .., or consists solely of a root of prefix, +/// file_name will return None. +pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option> { + if path.is_empty() { + return None; + } else if path.last() == Some(b'.') { + return None; + } + let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0); + Some(match *path { + Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]), + Cow::Owned(ref path) => { + let mut path = path.clone(); + path.drain_bytes(..last_slash); + Cow::Owned(path) + } + }) +} + +/// Return a file extension given a path's file name. +/// +/// Note that this does NOT match the semantics of std::path::Path::extension. +/// Namely, the extension includes the `.` and matching is otherwise more +/// liberal. Specifically, the extenion is: +/// +/// * None, if the file name given is empty; +/// * None, if there is no embedded `.`; +/// * Otherwise, the portion of the file name starting with the final `.`. +/// +/// e.g., A file name of `.rs` has an extension `.rs`. +/// +/// N.B. This is done to make certain glob match optimizations easier. Namely, +/// a pattern like `*.rs` is obviously trying to match files with a `rs` +/// extension, but it also matches files like `.rs`, which doesn't have an +/// extension according to std::path::Path::extension. +pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option> { + if name.is_empty() { + return None; + } + let last_dot_at = match name.rfind_byte(b'.') { + None => return None, + Some(i) => i, + }; + Some(match *name { + Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]), + Cow::Owned(ref name) => { + let mut name = name.clone(); + name.drain_bytes(..last_dot_at); + Cow::Owned(name) + } + }) +} + +/// Normalizes a path to use `/` as a separator everywhere, even on platforms +/// that recognize other characters as separators. +#[cfg(unix)] +pub fn normalize_path(path: Cow) -> Cow { + // UNIX only uses /, so we're good. + path +} + +/// Normalizes a path to use `/` as a separator everywhere, even on platforms +/// that recognize other characters as separators. +#[cfg(not(unix))] +pub fn normalize_path(mut path: Cow) -> Cow { + use std::path::is_separator; + + for i in 0..path.len() { + if path[i] == b'/' || !is_separator(path[i] as char) { + continue; + } + path.to_mut()[i] = b'/'; + } + path +} + +#[cfg(test)] +mod tests { + use std::borrow::Cow; + + use bstr::{B, BString}; + + use super::{file_name_ext, normalize_path}; + + macro_rules! ext { + ($name:ident, $file_name:expr, $ext:expr) => { + #[test] + fn $name() { + let bs = BString::from($file_name); + let got = file_name_ext(&Cow::Owned(bs)); + assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got); + } + }; + } + + ext!(ext1, "foo.rs", Some(".rs")); + ext!(ext2, ".rs", Some(".rs")); + ext!(ext3, "..rs", Some(".rs")); + ext!(ext4, "", None::<&str>); + ext!(ext5, "foo", None::<&str>); + + macro_rules! normalize { + ($name:ident, $path:expr, $expected:expr) => { + #[test] + fn $name() { + let bs = BString::from_slice($path); + let got = normalize_path(Cow::Owned(bs)); + assert_eq!($expected.to_vec(), got.into_owned()); + } + }; + } + + normalize!(normal1, b"foo", b"foo"); + normalize!(normal2, b"foo/bar", b"foo/bar"); + #[cfg(unix)] + normalize!(normal3, b"foo\\bar", b"foo\\bar"); + #[cfg(not(unix))] + normalize!(normal3, b"foo\\bar", b"foo/bar"); + #[cfg(unix)] + normalize!(normal4, b"foo\\bar/baz", b"foo\\bar/baz"); + #[cfg(not(unix))] + normalize!(normal4, b"foo\\bar/baz", b"foo/bar/baz"); +} diff --git a/hex/.cargo-checksum.json b/hex/.cargo-checksum.json new file mode 100644 index 000000000..88fd6de0d --- /dev/null +++ b/hex/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"} \ No newline at end of file diff --git a/hex/Cargo.toml b/hex/Cargo.toml new file mode 100644 index 000000000..0b19db4b2 --- /dev/null +++ b/hex/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "hex" +version = "0.3.2" +authors = ["KokaKiwi "] +description = "Encoding and decoding data into/from hexadecimal representation." +documentation = "https://docs.rs/hex/" +license = "MIT OR Apache-2.0" +repository = "https://github.com/KokaKiwi/rust-hex" + +[features] +benchmarks = [] diff --git a/hex/Dockerfile b/hex/Dockerfile new file mode 100644 index 000000000..63970aa41 --- /dev/null +++ b/hex/Dockerfile @@ -0,0 +1 @@ +FROM rust:latest diff --git a/hex/LICENSE-APACHE b/hex/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/hex/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/hex/LICENSE-MIT b/hex/LICENSE-MIT new file mode 100644 index 000000000..d4568f5ca --- /dev/null +++ b/hex/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2013-2014 The Rust Project Developers. +Copyright (c) 2015-2016 The rust-hex Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/hex/README.md b/hex/README.md new file mode 100644 index 000000000..b86e2b551 --- /dev/null +++ b/hex/README.md @@ -0,0 +1,17 @@ +Documentation: https://docs.rs/hex + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/hex/src/lib.rs b/hex/src/lib.rs new file mode 100644 index 000000000..3b51e242e --- /dev/null +++ b/hex/src/lib.rs @@ -0,0 +1,406 @@ +#![cfg_attr(feature = "benchmarks", feature(test))] + +// Copyright (c) 2013-2014 The Rust Project Developers. +// Copyright (c) 2015-2018 The rust-hex Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Encoding and decoding hex strings. +//! +//! For most cases, you can simply use the `decode()`, `encode()` and +//! `encode_upper()` functions. If you need a bit more control, use the traits +//! `ToHex` and `FromHex` instead. +//! +//! # Example +//! +//! ``` +//! extern crate hex; +//! +//! fn main() { +//! let hex_string = hex::encode("Hello world!"); +//! println!("{}", hex_string); // Prints '48656c6c6f20776f726c6421' +//! } +//! ``` + +use std::error; +use std::fmt; + +/// Encoding values as hex string. +/// +/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This +/// includes `String`, `str`, `Vec` and `[u8]`. +/// +/// # Example +/// +/// ``` +/// use hex::ToHex; +/// +/// let mut s = String::new(); +/// "Hello world!".write_hex(&mut s).unwrap(); +/// println!("{}", s); +/// ``` +/// +/// *Note*: instead of using this trait, you might want to use `encode()`. +pub trait ToHex { + /// Writes the hex string representing `self` into `w`. Lower case letters + /// are used (e.g. `f9b4ca`). + fn write_hex(&self, w: &mut W) -> fmt::Result; + + /// Writes the hex string representing `self` into `w`. Upper case letters + /// are used (e.g. `F9B4CA`). + fn write_hex_upper(&self, w: &mut W) -> fmt::Result; +} + +fn hex_write(table: &[u8; 16], src: &[u8], w: &mut W) -> fmt::Result { + let hex = |byte: u8| table[byte as usize]; + + for &b in src.iter() { + w.write_char(hex((b >> 4) & 0xf) as char)?; + w.write_char(hex(b & 0xf) as char)?; + } + + Ok(()) +} + +impl> ToHex for T { + fn write_hex(&self, w: &mut W) -> fmt::Result { + static CHARS: &'static [u8; 16] = b"0123456789abcdef"; + + hex_write(&CHARS, self.as_ref(), w) + } + + fn write_hex_upper(&self, w: &mut W) -> fmt::Result { + static CHARS: &'static [u8; 16] = b"0123456789ABCDEF"; + + hex_write(&CHARS, self.as_ref(), w) + } +} + +/// The error type for decoding a hex string into `Vec` or `[u8; N]`. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FromHexError { + /// An invalid character was found. Valid ones are: `0...9`, `a...f` + /// or `A...F`. + InvalidHexCharacter { + c: char, + index: usize, + }, + + /// A hex string's length needs to be even, as two digits correspond to + /// one byte. + OddLength, + + /// If the hex string is decoded into a fixed sized container, such as an + /// array, the hex string's length * 2 has to match the container's + /// length. + InvalidStringLength, +} + +impl error::Error for FromHexError { + fn description(&self) -> &str { + match *self { + FromHexError::InvalidHexCharacter { .. } => "invalid character", + FromHexError::OddLength => "odd number of digits", + FromHexError::InvalidStringLength => "invalid string length", + + } + } +} + +impl fmt::Display for FromHexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + FromHexError::InvalidHexCharacter { c, index } => + write!(f, "Invalid character '{}' at position {}", c, index), + FromHexError::OddLength => + write!(f, "Odd number of digits"), + FromHexError::InvalidStringLength => + write!(f, "Invalid string length"), + } + } +} + +/// Types that can be decoded from a hex string. +/// +/// This trait is implemented for `Vec` and small `u8`-arrays. +/// +/// # Example +/// +/// ``` +/// use hex::FromHex; +/// +/// match Vec::from_hex("48656c6c6f20776f726c6421") { +/// Ok(vec) => { +/// for b in vec { +/// println!("{}", b as char); +/// } +/// } +/// Err(e) => { +/// // Deal with the error ... +/// } +/// } +/// ``` +pub trait FromHex: Sized { + type Error; + + /// Creates an instance of type `Self` from the given hex string, or fails + /// with a custom error type. + /// + /// Both, upper and lower case characters are valid and can even be + /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). + fn from_hex>(hex: T) -> Result; +} + +fn val(c: u8, idx: usize) -> Result { + match c { + b'A'...b'F' => Ok(c - b'A' + 10), + b'a'...b'f' => Ok(c - b'a' + 10), + b'0'...b'9' => Ok(c - b'0'), + _ => { + Err(FromHexError::InvalidHexCharacter { + c: c as char, + index: idx, + }) + } + } +} + +impl FromHex for Vec { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + + hex.chunks(2).enumerate().map(|(i, pair)| { + Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?) + }).collect() + } +} + +// Helper macro to implement the trait for a few fixed sized arrays. Once Rust +// has type level integers, this should be removed. +macro_rules! from_hex_array_impl { + ($($len:expr)+) => {$( + impl FromHex for [u8; $len] { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + if hex.len() / 2 != $len { + return Err(FromHexError::InvalidStringLength); + } + + let mut out = [0; $len]; + for (i, byte) in out.iter_mut().enumerate() { + *byte = val(hex[2 * i], 2 * i)? << 4 + | val(hex[2 * i + 1], 2 * i + 1)?; + } + + Ok(out) + } + } + )+} +} + +from_hex_array_impl! { + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 + 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 + 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 + 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 + 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 + 160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768 +} + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +from_hex_array_impl! { + 65536 131072 262144 524288 1048576 2097152 4194304 8388608 + 16777216 33554432 67108864 134217728 268435456 536870912 + 1073741824 2147483648 +} + +#[cfg(target_pointer_width = "64")] +from_hex_array_impl! { + 4294967296 +} + +/// Encodes `data` as hex string using lowercase characters. +/// +/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's +/// length is always even, each byte in `data` is always encoded using two hex +/// digits. Thus, the resulting string contains exactly twice as many bytes as +/// the input data. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421"); +/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10"); +/// ``` +pub fn encode>(data: T) -> String { + let mut s = String::with_capacity(data.as_ref().len() * 2); + + // Writing to a string never errors, so we can unwrap here. + data.write_hex(&mut s).unwrap(); + s +} + +/// Encodes `data` as hex string using uppercase characters. +/// +/// Apart from the characters' casing, this works exactly like `encode()`. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421"); +/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10"); +/// ``` +pub fn encode_upper>(data: T) -> String { + let mut s = String::with_capacity(data.as_ref().len() * 2); + + // Writing to a string never errors, so we can unwrap here. + data.write_hex_upper(&mut s).unwrap(); + s +} + +/// Decodes a hex string into raw bytes. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +/// +/// # Example +/// ``` +/// assert_eq!( +/// hex::decode("48656c6c6f20776f726c6421"), +/// Ok("Hello world!".to_owned().into_bytes()) +/// ); +/// +/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength)); +/// assert!(hex::decode("foo").is_err()); +/// ``` +pub fn decode>(data: T) -> Result, FromHexError> { + FromHex::from_hex(data) +} + + +#[cfg(test)] +mod test { + use super::{encode, decode, FromHex, FromHexError}; + + #[test] + fn test_encode() { + assert_eq!(encode("foobar"), "666f6f626172"); + } + + #[test] + fn test_decode() { + assert_eq!(decode("666f6f626172"), Ok("foobar".to_owned().into_bytes())); + } + + #[test] + pub fn test_from_hex_okay_str() { + assert_eq!( + Vec::from_hex("666f6f626172").unwrap(), + b"foobar" + ); + assert_eq!( + Vec::from_hex("666F6F626172").unwrap(), + b"foobar" + ); + } + + #[test] + pub fn test_from_hex_okay_bytes() { + assert_eq!( + Vec::from_hex(b"666f6f626172").unwrap(), + b"foobar" + ); + assert_eq!( + Vec::from_hex(b"666F6F626172").unwrap(), + b"foobar" + ); + } + + #[test] + pub fn test_invalid_length() { + assert_eq!( + Vec::from_hex("1").unwrap_err(), + FromHexError::OddLength + ); + assert_eq!( + Vec::from_hex("666f6f6261721").unwrap_err(), + FromHexError::OddLength + ); + } + + #[test] + pub fn test_invalid_char() { + assert_eq!( + Vec::from_hex("66ag").unwrap_err(), + FromHexError::InvalidHexCharacter { + c: 'g', + index: 3 + } + ); + } + + #[test] + pub fn test_empty() { + assert_eq!(Vec::from_hex("").unwrap(), b""); + } + + #[test] + pub fn test_from_hex_whitespace() { + assert_eq!( + Vec::from_hex("666f 6f62617").unwrap_err(), + FromHexError::InvalidHexCharacter { + c: ' ', + index: 4 + } + ); + } + + #[test] + pub fn test_from_hex_array() { + assert_eq!( + <[u8; 6] as FromHex>::from_hex("666f6f626172"), + Ok([0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]) + ); + + assert_eq!( + <[u8; 5] as FromHex>::from_hex("666f6f626172"), + Err(FromHexError::InvalidStringLength) + ); + } +} + + +#[cfg(all(feature = "benchmarks", test))] +mod bench { + extern crate test; + use self::test::Bencher; + + use super::*; + + const MY_OWN_SOURCE: &[u8] = include_bytes!("lib.rs"); + + #[bench] + fn a_bench(b: &mut Bencher) { + b.bytes = MY_OWN_SOURCE.len() as u64; + + b.iter(|| { + encode(MY_OWN_SOURCE) + }); + } +} diff --git a/home/.cargo-checksum.json b/home/.cargo-checksum.json new file mode 100644 index 000000000..04ca01e3f --- /dev/null +++ b/home/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"29302b90cfa76231a757a887d1e3153331a63c7f80b6c75f86366334cbe70708"} \ No newline at end of file diff --git a/home/Cargo.toml b/home/Cargo.toml new file mode 100644 index 000000000..68860c0e1 --- /dev/null +++ b/home/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "home" +version = "0.3.4" +authors = ["Brian Anderson "] +description = "Shared definitions of home directories" +documentation = "https://docs.rs/home" +license = "MIT/Apache-2.0" +repository = "https://github.com/brson/home" +[target."cfg(windows)".dependencies.scopeguard] +version = "0.3" + +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["errhandlingapi", "handleapi", "processthreadsapi", "std", "winerror", "winnt", "userenv"] diff --git a/home/README.md b/home/README.md new file mode 100644 index 000000000..2ff22423e --- /dev/null +++ b/home/README.md @@ -0,0 +1,24 @@ +Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. + +This provides the definition of `home_dir` used by Cargo and rustup, +as well functions to find the correct value of `CARGO_HOME` and +`RUSTUP_HOME`. + +The definition of `home_dir` provided by the standard library is +incorrect because it considers the `HOME` environment variable on +Windows. This causes surprising situations where a Rust program will +behave differently depending on whether it is run under a Unix +emulation environment like Cygwin or MinGW. Neither Cargo nor rustup +use the standard libraries definition - they use the definition here. + +This crate further provides two functions, `cargo_home` and +`rustup_home`, which are the canonical way to determine the location +that Cargo and rustup store their data. + +See [rust-lang/rust#43321]. + +[rust-lang/rust#43321]: https://github.com/rust-lang/rust/issues/43321 + +## License + +MIT/Apache-2.0 diff --git a/home/src/lib.rs b/home/src/lib.rs new file mode 100644 index 000000000..9e31a3e97 --- /dev/null +++ b/home/src/lib.rs @@ -0,0 +1,297 @@ +/// Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. +/// +/// This provides the definition of `home_dir` used by Cargo and +/// rustup, as well functions to find the correct value of +/// `CARGO_HOME` and `RUSTUP_HOME`. +/// +/// The definition of `home_dir` provided by the standard library is +/// incorrect because it considers the `HOME` environment variable on +/// Windows. This causes surprising situations where a Rust program +/// will behave differently depending on whether it is run under a +/// Unix emulation environment like Cygwin or MinGW. Neither Cargo nor +/// rustup use the standard libraries definition - they use the +/// definition here. +/// +/// This crate further provides two functions, `cargo_home` and +/// `rustup_home`, which are the canonical way to determine the +/// location that Cargo and rustup store their data. +/// +/// See [rust-lang/rust#43321]. +/// +/// [rust-lang/rust#43321]: https://github.com/rust-lang/rust/issues/43321 + +#[cfg(windows)] +extern crate scopeguard; +#[cfg(windows)] +extern crate winapi; + +#[cfg(windows)] +use winapi::shared::minwindef::DWORD; +use std::path::{PathBuf, Path}; +use std::io; +use std::env; + +/// Returns the path of the current user's home directory if known. +/// +/// # Unix +/// +/// Returns the value of the 'HOME' environment variable if it is set +/// and not equal to the empty string. Otherwise, it tries to determine the +/// home directory by invoking the `getpwuid_r` function on the UID of the +/// current user. +/// +/// # Windows +/// +/// Returns the value of the 'USERPROFILE' environment variable if it +/// is set and not equal to the empty string. If both do not exist, +/// [`GetUserProfileDirectory`][msdn] is used to return the +/// appropriate path. +/// +/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx +/// +/// # Examples +/// +/// ``` +/// use std::env; +/// +/// match env::home_dir() { +/// Some(path) => println!("{}", path.display()), +/// None => println!("Impossible to get your home dir!"), +/// } +/// ``` +pub fn home_dir() -> Option { + home_dir_() +} + +#[cfg(windows)] +fn home_dir_() -> Option { + use std::ptr; + use winapi::um::userenv::GetUserProfileDirectoryW; + use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::handleapi::CloseHandle; + use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; + use winapi::um::winnt::TOKEN_READ; + use scopeguard; + + ::std::env::var_os("USERPROFILE").map(PathBuf::from).or_else(|| unsafe { + let me = GetCurrentProcess(); + let mut token = ptr::null_mut(); + if OpenProcessToken(me, TOKEN_READ, &mut token) == 0 { + return None; + } + let _g = scopeguard::guard(token, |h| { let _ = CloseHandle(*h); }); + fill_utf16_buf(|buf, mut sz| { + match GetUserProfileDirectoryW(token, buf, &mut sz) { + 0 if GetLastError() != ERROR_INSUFFICIENT_BUFFER => 0, + 0 => sz, + _ => sz - 1, // sz includes the null terminator + } + }, os2path).ok() + }) +} + +#[cfg(windows)] +fn os2path(s: &[u16]) -> PathBuf { + use std::ffi::OsString; + use std::os::windows::ffi::OsStringExt; + PathBuf::from(OsString::from_wide(s)) +} + +#[cfg(windows)] +fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result + where F1: FnMut(*mut u16, DWORD) -> DWORD, + F2: FnOnce(&[u16]) -> T +{ + use winapi::um::errhandlingapi::{GetLastError, SetLastError}; + use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER; + + // Start off with a stack buf but then spill over to the heap if we end up + // needing more space. + let mut stack_buf = [0u16; 512]; + let mut heap_buf = Vec::new(); + unsafe { + let mut n = stack_buf.len(); + loop { + let buf = if n <= stack_buf.len() { + &mut stack_buf[..] + } else { + let extra = n - heap_buf.len(); + heap_buf.reserve(extra); + heap_buf.set_len(n); + &mut heap_buf[..] + }; + + // This function is typically called on windows API functions which + // will return the correct length of the string, but these functions + // also return the `0` on error. In some cases, however, the + // returned "correct length" may actually be 0! + // + // To handle this case we call `SetLastError` to reset it to 0 and + // then check it again if we get the "0 error value". If the "last + // error" is still 0 then we interpret it as a 0 length buffer and + // not an actual error. + SetLastError(0); + let k = match f1(buf.as_mut_ptr(), n as DWORD) { + 0 if GetLastError() == 0 => 0, + 0 => return Err(io::Error::last_os_error()), + n => n, + } as usize; + if k == n && GetLastError() == ERROR_INSUFFICIENT_BUFFER { + n *= 2; + } else if k >= n { + n = k; + } else { + return Ok(f2(&buf[..k])) + } + } + } +} + +#[cfg(any(unix, target_os = "redox"))] +fn home_dir_() -> Option { + ::std::env::home_dir() +} + +/// Returns the storage directory used by Cargo, often knowns as +/// `.cargo` or `CARGO_HOME`. +/// +/// It returns one of the following values, in this order of +/// preference: +/// +/// - The value of the `CARGO_HOME` environment variable, if it is +/// an absolute path. +/// - The value of the current working directory joined with the value +/// of the `CARGO_HOME` environment variable, if `CARGO_HOME` is a +/// relative directory. +/// - The `.cargo` directory in the user's home directory, as reported +/// by the `home_dir` function. +/// +/// # Errors +/// +/// This function fails if it fails to retrieve the current directory, +/// or if the home directory cannot be determined. +pub fn cargo_home() -> io::Result { + let cwd = env::current_dir()?; + cargo_home_with_cwd(&cwd) +} + +pub fn cargo_home_with_cwd(cwd: &Path) -> io::Result { + let env_var = env::var_os("CARGO_HOME"); + + // NB: During the multirust-rs -> rustup transition the install + // dir changed from ~/.multirust/bin to ~/.cargo/bin. Because + // multirust used to explicitly set CARGO_HOME it's possible to + // get here when e.g. installing under `cargo run` and decide to + // install to the wrong place. This check is to make the + // multirust-rs to rustup upgrade seamless. + let env_var = if let Some(v) = env_var { + let vv = v.to_string_lossy().to_string(); + if vv.contains(".multirust/cargo") || + vv.contains(r".multirust\cargo") || + vv.trim().is_empty() { + None + } else { + Some(v) + } + } else { + None + }; + + let env_cargo_home = env_var.map(|home| cwd.join(home)); + let home_dir = home_dir() + .ok_or(io::Error::new(io::ErrorKind::Other, "couldn't find home dir")); + let user_home = home_dir.map(|p| p.join(".cargo")); + + // Compatibility with old cargo that used the std definition of home_dir + let compat_home_dir = ::std::env::home_dir(); + let compat_user_home = compat_home_dir.map(|p| p.join(".cargo")); + + if let Some(p) = env_cargo_home { + Ok(p) + } else { + if let Some(d) = compat_user_home { + if d.exists() { + Ok(d) + } else { + user_home + } + } else { + user_home + } + } +} + +/// Returns the storage directory used by rustup, often knowns as +/// `.rustup` or `RUSTUP_HOME`. +/// +/// It returns one of the following values, in this order of +/// preference: +/// +/// - The value of the `RUSTUP_HOME` environment variable, if it is +/// an absolute path. +/// - The value of the current working directory joined with the value +/// of the `RUSTUP_HOME` environment variable, if `RUSTUP_HOME` is a +/// relative directory. +/// - The `.rustup` directory in the user's home directory, as reported +/// by the `home_dir` function. +/// +/// As a matter of backwards compatibility, this function _may_ return +/// the `.multirust` directory in the user's home directory, only if +/// it determines that the user is running an old version of rustup +/// where that is necessary. +/// +/// # Errors +/// +/// This function fails if it fails to retrieve the current directory, +/// or if the home directory cannot be determined. +pub fn rustup_home() -> io::Result { + let cwd = env::current_dir()?; + rustup_home_with_cwd(&cwd) +} + +pub fn rustup_home_with_cwd(cwd: &Path) -> io::Result { + let env_var = env::var_os("RUSTUP_HOME"); + let env_rustup_home = env_var.map(|home| cwd.join(home)); + let home_dir = home_dir() + .ok_or(io::Error::new(io::ErrorKind::Other, "couldn't find home dir")); + + let user_home = if use_rustup_dir() { + home_dir.map(|d| d.join(".rustup")) + } else { + home_dir.map(|d| d.join(".multirust")) + }; + + if let Some(p) = env_rustup_home { + Ok(p) + } else { + user_home + } +} + +fn use_rustup_dir() -> bool { + fn rustup_dir() -> Option { + home_dir().map(|p| p.join(".rustup")) + } + + fn multirust_dir() -> Option { + home_dir().map(|p| p.join(".multirust")) + } + + fn rustup_dir_exists() -> bool { + rustup_dir().map(|p| p.exists()).unwrap_or(false) + } + + fn multirust_dir_exists() -> bool { + multirust_dir().map(|p| p.exists()).unwrap_or(false) + } + + fn rustup_old_version_exists() -> bool { + rustup_dir() + .map(|p| p.join("rustup-version").exists()) + .unwrap_or(false) + } + + !rustup_old_version_exists() + && (rustup_dir_exists() || !multirust_dir_exists()) +} diff --git a/http/.cargo-checksum.json b/http/.cargo-checksum.json new file mode 100644 index 000000000..c6e991a2e --- /dev/null +++ b/http/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a"} \ No newline at end of file diff --git a/http/CHANGELOG.md b/http/CHANGELOG.md new file mode 100644 index 000000000..2dfedc211 --- /dev/null +++ b/http/CHANGELOG.md @@ -0,0 +1,106 @@ +# 0.1.17 (April 5, 2019) + +* Add `Error::inner_ref()` to view the kind of error (#303) +* Add `headers_ref()` and `headers_mut()` methods to `request::Builder` and `response::Builder` (#293) + +# 0.1.16 (February 19, 2019) + +* Fix `Uri` to permit more characters in the `path` (#296) + +# 0.1.15 (January 22, 2019) + +* Fix `Uri::host()` to include brackets of IPv6 literals (#292) +* Add `scheme_str` and `port_u16` methods to `Uri` (#287) +* Add `method_ref`, `uri_ref`, and `headers_ref` to `request::Builder` (#284) + +# 0.1.14 (November 21, 2018) + +* Add `Port` struct (#252, #255, #265) +* Introduce `Uri` builder (#219) +* Empty `Method` no longer considered valid (#262) +* Fix `Uri` equality when terminating question mark is present (#270) +* Allow % character in userinfo (#269) +* Support additional tokens for header names (#271) +* Export `http::headers::{IterMut, ValuesMut}` (#278) + +# 0.1.13 (September 14, 2018) + +* impl `fmt::Display` for `HeaderName` (#249) +* Fix `uri::Authority` parsing when there is no host after an `@` (#248) +* Fix `Uri` parsing to allow more characters in query strings (#247) + +# 0.1.12 (September 7, 2018) + +* Fix `HeaderValue` parsing to allow HTABs (#244) + +# 0.1.11 (September 5, 2018) + +* Add `From<&Self>` for `HeaderValue`, `Method`, and `StatusCode` (#238) +* Add `Uri::from_static` (#240) + +# 0.1.10 (August 8, 2018) + +* impl HttpTryFrom for HeaderValue (#236) + +# 0.1.9 (August 7, 2018) + +* Fix double percent encoding (#233) +* Add additional HttpTryFrom impls (#234) + +# 0.1.8 (July 23, 2018) + +* Add fuller set of `PartialEq` for `Method` (#221) +* Reduce size of `HeaderMap` by using `Box<[Entry]>` instea of `Vec` (#224) +* Reduce size of `Extensions` by storing as `Option>` (#227) +* Implement `Iterator::size_hint` for most iterators in `header` (#226) + +# 0.1.7 (June 22, 2018) + +* Add `From for HeaderValue` for most integer types (#218). +* Add `Uri::into_parts()` inherent method (same as `Parts::from(uri)`) (#214). +* Fix converting `Uri`s in authority-form to `Parts` and then back into `Uri` (#216). +* Fix `Authority` parsing to reject multiple port sections (#215). +* Fix parsing 1 character authority-form `Uri`s into illegal forms (#220). + +# 0.1.6 (June 13, 2018) + +* Add `HeaderName::from_static()` constructor (#195). +* Add `Authority::from_static()` constructor (#186). +* Implement `From` for `HeaderValue` (#184). +* Fix duplicate keys when iterating over `header::Keys` (#201). + +# 0.1.5 (February 28, 2018) + +* Add websocket handshake related header constants (#162). +* Parsing `Authority` with an empty string now returns an error (#164). +* Implement `PartialEq` for `StatusCode` (#153). +* Implement `HttpTryFrom<&Uri>` for `Uri` (#165). +* Implement `FromStr` for `Method` (#167). +* Implement `HttpTryFrom` for `Uri` (#171). +* Add `into_body` fns to `Request` and `Response` (#172). +* Fix `Request::options` (#177). + +# 0.1.4 (January 4, 2018) + +* Add PathAndQuery::from_static (#148). +* Impl PartialOrd / PartialEq for Authority and PathAndQuery (#150). +* Add `map` fn to `Request` and `Response` (#151). + +# 0.1.3 (December 11, 2017) + +* Add `Scheme` associated consts for common protos. + +# 0.1.2 (November 29, 2017) + +* Add Uri accessor for scheme part. +* Fix Uri parsing bug (#134) + +# 0.1.1 (October 9, 2017) + +* Provide Uri accessors for parts (#129) +* Add Request builder helpers. (#123) +* Misc performance improvements (#126) + +# 0.1.0 (September 8, 2017) + +* Initial release. diff --git a/http/Cargo.toml b/http/Cargo.toml new file mode 100644 index 000000000..fba2458f6 --- /dev/null +++ b/http/Cargo.toml @@ -0,0 +1,61 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "http" +version = "0.1.17" +authors = ["Alex Crichton ", "Carl Lerche ", "Sean McArthur "] +description = "A set of types for representing HTTP requests and responses.\n" +homepage = "https://github.com/hyperium/http" +documentation = "https://docs.rs/http" +readme = "README.md" +keywords = ["http"] +categories = ["web-programming"] +license = "MIT/Apache-2.0" +repository = "https://github.com/hyperium/http" + +[[bench]] +name = "header_map" +path = "benches/header_map/mod.rs" + +[[bench]] +name = "header_value" +path = "benches/header_value.rs" + +[[bench]] +name = "uri" +path = "benches/uri.rs" +[dependencies.bytes] +version = "0.4" + +[dependencies.fnv] +version = "1.0.5" + +[dependencies.itoa] +version = "0.4.1" +[dev-dependencies.indexmap] +version = "1.0" + +[dev-dependencies.quickcheck] +version = "0.6" + +[dev-dependencies.rand] +version = "0.4" + +[dev-dependencies.seahash] +version = "3.0.5" + +[dev-dependencies.serde] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" diff --git a/http/LICENSE-APACHE b/http/LICENSE-APACHE new file mode 100644 index 000000000..80176c2b2 --- /dev/null +++ b/http/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 http-rs authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/http/LICENSE-MIT b/http/LICENSE-MIT new file mode 100644 index 000000000..0cbc55049 --- /dev/null +++ b/http/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 http-rs authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/http/README.md b/http/README.md new file mode 100644 index 000000000..1669761c3 --- /dev/null +++ b/http/README.md @@ -0,0 +1,80 @@ +# HTTP + +A general purpose library of common HTTP types + +[![Build Status](https://travis-ci.org/hyperium/http.svg?branch=master)](https://travis-ci.org/hyperium/http) +[![Crates.io](https://img.shields.io/crates/v/http.svg)](https://crates.io/crates/http) +[![Documentation](https://docs.rs/http/badge.svg)][dox] + +More information about this crate can be found in the [crate +documentation][dox]. + +[dox]: https://docs.rs/http + +## Usage + +To use `http`, first add this to your `Cargo.toml`: + +```toml +[dependencies] +http = "0.1" +``` + +Next, add this to your crate: + +```rust +extern crate http; + +use http::{Request, Response}; + +fn main() { + // ... +} +``` + +## Examples + +Create an HTTP request: + +```rust +extern crate http; + +use http::Request; + +fn main() { + let request = Request::builder() + .uri("https://www.rust-lang.org/") + .header("User-Agent", "awesome/1.0") + .body(()) + .unwrap(); +} +``` + +Create an HTTP response: + +```rust +extern crate http; + +use http::{Response, StatusCode}; + +fn main() { + let response = Response::builder() + .status(StatusCode::MOVED_PERMANENTLY) + .header("Location", "https://www.rust-lang.org/install.html") + .body(()) + .unwrap(); +} +``` + +# License + +Licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/http/benches/header_map/basic.rs b/http/benches/header_map/basic.rs new file mode 100644 index 000000000..4ce7ed628 --- /dev/null +++ b/http/benches/header_map/basic.rs @@ -0,0 +1,586 @@ +macro_rules! bench { + ($name:ident($map:ident, $b:ident) $body:expr) => { + mod $name { + #[allow(unused_imports)] + use test::{self, Bencher}; + use seahash::SeaHasher; + use fnv::FnvHasher; + use std::hash::BuildHasherDefault; + use http::header::*; + #[allow(unused_imports)] + use super::custom_hdr; + + #[bench] + fn header_map($b: &mut Bencher) { + let $map = || HeaderMap::default(); + $body + } + + #[bench] + fn order_map_fnv($b: &mut Bencher) { + use indexmap::IndexMap; + let $map = || IndexMap::<_, _, BuildHasherDefault>::default(); + $body + } + + #[bench] + fn vec_map($b: &mut Bencher) { + use vec_map::VecMap; + + let $map = || VecMap::with_capacity(0); + $body + } + + #[bench] + fn order_map_seahash($b: &mut Bencher) { + use indexmap::IndexMap; + let $map = || IndexMap::<_, _, BuildHasherDefault>::default(); + $body + } + + /* + #[bench] + fn order_map_siphash($b: &mut Bencher) { + use indexmap::IndexMap; + let $map = || IndexMap::new(); + $body + } + + #[bench] + fn std_map_siphash($b: &mut Bencher) { + use std::collections::HashMap; + let $map = || HashMap::new(); + $body + } + */ + } + }; +} + +bench!(new_insert_get_host(new_map, b) { + b.iter(|| { + let mut h = new_map(); + h.insert(HOST, "hyper.rs"); + test::black_box(h.get(&HOST)); + }) +}); + +bench!(insert_4_std_get_30(new_map, b) { + + b.iter(|| { + let mut h = new_map(); + + for i in 0..4 { + h.insert(super::STD[i].clone(), "foo"); + } + + for i in 0..30 { + test::black_box(h.get(&super::STD[i % 4])); + } + }) +}); + +bench!(insert_6_std_get_6(new_map, b) { + + b.iter(|| { + let mut h = new_map(); + + for i in 0..6 { + h.insert(super::STD[i].clone(), "foo"); + } + + for i in 0..6 { + test::black_box(h.get(&super::STD[i % 4])); + } + }) +}); + +/* +bench!(insert_remove_host(new_map, b) { + let mut h = new_map(); + + b.iter(|| { + test::black_box(h.insert(HOST, "hyper.rs")); + test::black_box(h.remove(&HOST)); + }) +}); + +bench!(insert_insert_host(new_map, b) { + let mut h = new_map(); + + b.iter(|| { + test::black_box(h.insert(HOST, "hyper.rs")); + test::black_box(h.insert(HOST, "hyper.rs")); + }) +}); +*/ + +bench!(get_10_of_20_std(new_map, b) { + let mut h = new_map(); + + for hdr in super::STD[10..30].iter() { + h.insert(hdr.clone(), hdr.as_str().to_string()); + } + + b.iter(|| { + for hdr in &super::STD[10..20] { + test::black_box(h.get(hdr)); + } + }) +}); + +bench!(get_100_std(new_map, b) { + let mut h = new_map(); + + for hdr in super::STD.iter() { + h.insert(hdr.clone(), hdr.as_str().to_string()); + } + + b.iter(|| { + for i in 0..100 { + test::black_box(h.get(&super::STD[i % super::STD.len()])); + } + }) +}); + +bench!(set_8_get_1_std(new_map, b) { + b.iter(|| { + let mut h = new_map(); + + for hdr in &super::STD[0..8] { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&super::STD[0])); + }) +}); + +bench!(set_10_get_1_std(new_map, b) { + b.iter(|| { + let mut h = new_map(); + + for hdr in &super::STD[0..10] { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&super::STD[0])); + }) +}); + +bench!(set_20_get_1_std(new_map, b) { + b.iter(|| { + let mut h = new_map(); + + for hdr in &super::STD[0..20] { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&super::STD[0])); + }) +}); + +bench!(get_10_custom_short(new_map, b) { + let hdrs = custom_hdr(20); + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), hdr.as_str().to_string()); + } + + b.iter(|| { + for hdr in &hdrs[..10] { + test::black_box(h.get(hdr)); + } + }) +}); + +bench!(set_10_get_1_custom_short(new_map, b) { + let hdrs = custom_hdr(10); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + + +bench!(set_10_get_1_custom_med(new_map, b) { + let hdrs = super::med_custom_hdr(10); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_10_get_1_custom_long(new_map, b) { + let hdrs = super::long_custom_hdr(10); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_10_get_1_custom_very_long(new_map, b) { + let hdrs = super::very_long_custom_hdr(10); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_20_get_1_custom_short(new_map, b) { + let hdrs = custom_hdr(20); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_20_get_1_custom_med(new_map, b) { + let hdrs = super::med_custom_hdr(20); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_20_get_1_custom_long(new_map, b) { + let hdrs = super::long_custom_hdr(20); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(set_20_get_1_custom_very_long(new_map, b) { + let hdrs = super::very_long_custom_hdr(20); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + + test::black_box(h.get(&hdrs[0])); + }) +}); + +bench!(insert_all_std_headers(new_map, b) { + b.iter(|| { + let mut h = new_map(); + + for hdr in super::STD { + test::black_box(h.insert(hdr.clone(), "foo")); + } + }) +}); + +bench!(insert_79_custom_std_headers(new_map, b) { + let hdrs = super::custom_std(79); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + h.insert(hdr.clone(), "foo"); + } + }) +}); + +bench!(insert_100_custom_headers(new_map, b) { + let hdrs = custom_hdr(100); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + test::black_box(h.insert(hdr.clone(), "foo")); + } + }) +}); + +bench!(insert_500_custom_headers(new_map, b) { + let hdrs = custom_hdr(500); + + b.iter(|| { + let mut h = new_map(); + + for hdr in &hdrs { + test::black_box(h.insert(hdr.clone(), "foo")); + } + }) +}); + +bench!(insert_one_15_char_header(new_map, b) { + let hdr: HeaderName = "abcd-abcd-abcde" + .parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + h.insert(hdr.clone(), "hello"); + test::black_box(h); + }) +}); + +bench!(insert_one_25_char_header(new_map, b) { + let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcde" + .parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + h.insert(hdr.clone(), "hello"); + test::black_box(h); + }) +}); + +bench!(insert_one_50_char_header(new_map, b) { + let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde" + .parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + h.insert(hdr.clone(), "hello"); + test::black_box(h); + }) +}); + +bench!(insert_one_100_char_header(new_map, b) { + let hdr: HeaderName = "abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcdeabcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcde" + .parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + h.insert(hdr.clone(), "hello"); + test::black_box(h); + }) +}); + +const HN_HDRS: [(&'static str, &'static str); 11] = [ + ("Date", "Fri, 27 Jan 2017 23:00:00 GMT"), + ("Content-Type", "text/html; charset=utf-8"), + ("Transfer-Encoding", "chunked"), + ("Connection", "keep-alive"), + ("Set-Cookie", "__cfduid=dbdfbbe3822b61cb8750ba37d894022151485558000; expires=Sat, 27-Jan-18 23:00:00 GMT; path=/; domain=.ycombinator.com; HttpOnly"), + ("Vary", "Accept-Encoding"), + ("Cache-Control", "private"), + ("X-Frame-Options", "DENY"), + ("Strict-Transport-Security", "max-age=31556900; includeSubDomains"), + ("Server", "cloudflare-nginx"), + ("CF-RAY", "327fd1809f3c1baf-SEA"), +]; + +bench!(hn_hdrs_set_8_get_many(new_map, b) { + let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter() + .map(|&(name, val)| (name.parse().unwrap(), val)) + .collect(); + + b.iter(|| { + let mut h = new_map(); + + for &(ref name, val) in hdrs.iter() { + h.insert(name.clone(), val); + } + + for _ in 0..15 { + test::black_box(h.get(&CONTENT_LENGTH)); + test::black_box(h.get(&VARY)); + } + }); +}); + +bench!(hn_hdrs_set_8_get_miss(new_map, b) { + let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS[..8].iter() + .map(|&(name, val)| (name.parse().unwrap(), val)) + .collect(); + + let miss: HeaderName = "x-wat".parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + + for &(ref name, val) in hdrs.iter() { + h.insert(name.clone(), val); + } + + test::black_box(h.get(&CONTENT_LENGTH)); + test::black_box(h.get(&miss)); + }); +}); + +bench!(hn_hdrs_set_11_get_with_miss(new_map, b) { + let hdrs: Vec<(HeaderName, &'static str)> = super::HN_HDRS.iter() + .map(|&(name, val)| (name.parse().unwrap(), val)) + .collect(); + + let miss: HeaderName = "x-wat".parse().unwrap(); + + b.iter(|| { + let mut h = new_map(); + + for &(ref name, val) in hdrs.iter() { + h.insert(name.clone(), val); + } + + for _ in 0..10 { + test::black_box(h.get(&CONTENT_LENGTH)); + test::black_box(h.get(&VARY)); + test::black_box(h.get(&miss)); + } + }); +}); + +use http::header::*; + +fn custom_hdr(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("x-custom-{}", i); + s.parse().unwrap() + }).collect() +} + +fn med_custom_hdr(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("content-length-{}", i); + s.parse().unwrap() + }).collect() +} + +fn long_custom_hdr(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("access-control-allow-headers-{}", i); + s.parse().unwrap() + }).collect() +} + +fn very_long_custom_hdr(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("access-control-allow-access-control-allow-headers-{}", i); + s.parse().unwrap() + }).collect() +} + +fn custom_std(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("{}-{}", STD[i % STD.len()].as_str(), i); + s.parse().unwrap() + }).collect() +} + +const STD: &'static [HeaderName] = &[ + ACCEPT, + ACCEPT_CHARSET, + ACCEPT_ENCODING, + ACCEPT_LANGUAGE, + ACCEPT_RANGES, + ACCESS_CONTROL_ALLOW_CREDENTIALS, + ACCESS_CONTROL_ALLOW_HEADERS, + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_ORIGIN, + ACCESS_CONTROL_EXPOSE_HEADERS, + ACCESS_CONTROL_MAX_AGE, + ACCESS_CONTROL_REQUEST_HEADERS, + ACCESS_CONTROL_REQUEST_METHOD, + AGE, + ALLOW, + ALT_SVC, + AUTHORIZATION, + CACHE_CONTROL, + CONNECTION, + CONTENT_DISPOSITION, + CONTENT_ENCODING, + CONTENT_LANGUAGE, + CONTENT_LENGTH, + CONTENT_LOCATION, + CONTENT_RANGE, + CONTENT_SECURITY_POLICY, + CONTENT_SECURITY_POLICY_REPORT_ONLY, + CONTENT_TYPE, + COOKIE, + DNT, + DATE, + ETAG, + EXPECT, + EXPIRES, + FORWARDED, + FROM, + HOST, + IF_MATCH, + IF_MODIFIED_SINCE, + IF_NONE_MATCH, + IF_RANGE, + IF_UNMODIFIED_SINCE, + LAST_MODIFIED, + LINK, + LOCATION, + MAX_FORWARDS, + ORIGIN, + PRAGMA, + PROXY_AUTHENTICATE, + PROXY_AUTHORIZATION, + PUBLIC_KEY_PINS, + PUBLIC_KEY_PINS_REPORT_ONLY, + RANGE, + REFERER, + REFERRER_POLICY, + REFRESH, + RETRY_AFTER, + SERVER, + SET_COOKIE, + STRICT_TRANSPORT_SECURITY, + TE, + TRAILER, + TRANSFER_ENCODING, + USER_AGENT, + UPGRADE, + UPGRADE_INSECURE_REQUESTS, + VARY, + VIA, + WARNING, + WWW_AUTHENTICATE, + X_CONTENT_TYPE_OPTIONS, + X_DNS_PREFETCH_CONTROL, + X_FRAME_OPTIONS, + X_XSS_PROTECTION, +]; diff --git a/http/benches/header_map/mod.rs b/http/benches/header_map/mod.rs new file mode 100644 index 000000000..50a97f7a4 --- /dev/null +++ b/http/benches/header_map/mod.rs @@ -0,0 +1,10 @@ +#![feature(test)] + +extern crate http; +extern crate test; +extern crate indexmap; +extern crate seahash; +extern crate fnv; + +mod basic; +mod vec_map; diff --git a/http/benches/header_map/vec_map.rs b/http/benches/header_map/vec_map.rs new file mode 100644 index 000000000..995e80623 --- /dev/null +++ b/http/benches/header_map/vec_map.rs @@ -0,0 +1,103 @@ +#![allow(dead_code)] + +#[derive(Clone)] +pub struct VecMap { + vec: Vec<(K, V)>, +} + +impl VecMap { + #[inline] + pub fn with_capacity(cap: usize) -> VecMap { + VecMap { + vec: Vec::with_capacity(cap) + } + } + + #[inline] + pub fn insert(&mut self, key: K, value: V) { + match self.find(&key) { + Some(pos) => self.vec[pos] = (key, value), + None => self.vec.push((key, value)) + } + } + + #[inline] + pub fn entry(&mut self, key: K) -> Entry { + match self.find(&key) { + Some(pos) => Entry::Occupied(OccupiedEntry { + vec: self, + pos: pos, + }), + None => Entry::Vacant(VacantEntry { + vec: self, + key: key, + }) + } + } + + #[inline] + pub fn get + ?Sized>(&self, key: &K2) -> Option<&V> { + self.find(key).map(move |pos| &self.vec[pos].1) + } + + #[inline] + pub fn get_mut + ?Sized>(&mut self, key: &K2) -> Option<&mut V> { + self.find(key).map(move |pos| &mut self.vec[pos].1) + } + + #[inline] + pub fn contains_key + ?Sized>(&self, key: &K2) -> bool { + self.find(key).is_some() + } + + #[inline] + pub fn len(&self) -> usize { self.vec.len() } + + #[inline] + pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { + self.vec.iter() + } + #[inline] + pub fn remove + ?Sized>(&mut self, key: &K2) -> Option { + self.find(key).map(|pos| self.vec.remove(pos)).map(|(_, v)| v) + } + #[inline] + pub fn clear(&mut self) { + self.vec.clear(); + } + + #[inline] + fn find + ?Sized>(&self, key: &K2) -> Option { + self.vec.iter().position(|entry| key == &entry.0) + } +} + +pub enum Entry<'a, K: 'a, V: 'a> { + Vacant(VacantEntry<'a, K, V>), + Occupied(OccupiedEntry<'a, K, V>) +} + +pub struct VacantEntry<'a, K: 'a, V: 'a> { + vec: &'a mut VecMap, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + pub fn insert(self, val: V) -> &'a mut V { + let vec = self.vec; + vec.vec.push((self.key, val)); + let pos = vec.vec.len() - 1; + &mut vec.vec[pos].1 + } +} + +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + vec: &'a mut VecMap, + pos: usize, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + pub fn into_mut(self) -> &'a mut V { + &mut self.vec.vec[self.pos].1 + } +} diff --git a/http/benches/header_value.rs b/http/benches/header_value.rs new file mode 100644 index 000000000..d9d2055c1 --- /dev/null +++ b/http/benches/header_value.rs @@ -0,0 +1,54 @@ +#![feature(test)] + +extern crate bytes; +extern crate http; +extern crate test; + +use bytes::Bytes; +use http::header::HeaderValue; +use test::Bencher; + +static SHORT: &'static [u8] = b"localhost"; +static LONG: &'static [u8] = b"Mozilla/5.0 (X11; CrOS x86_64 9592.71.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.80 Safari/537.36"; + + +#[bench] +fn from_shared_short(b: &mut Bencher) { + b.bytes = SHORT.len() as u64; + let bytes = Bytes::from_static(SHORT); + b.iter(|| { + HeaderValue::from_shared(bytes.clone()).unwrap(); + }); +} + +#[bench] +fn from_shared_long(b: &mut Bencher) { + b.bytes = LONG.len() as u64; + let bytes = Bytes::from_static(LONG); + b.iter(|| { + HeaderValue::from_shared(bytes.clone()).unwrap(); + }); +} + + +#[bench] +fn from_shared_unchecked_short(b: &mut Bencher) { + b.bytes = SHORT.len() as u64; + let bytes = Bytes::from_static(SHORT); + b.iter(|| { + unsafe { + HeaderValue::from_shared_unchecked(bytes.clone()); + } + }); +} + +#[bench] +fn from_shared_unchecked_long(b: &mut Bencher) { + b.bytes = LONG.len() as u64; + let bytes = Bytes::from_static(LONG); + b.iter(|| { + unsafe { + HeaderValue::from_shared_unchecked(bytes.clone()); + } + }); +} diff --git a/http/benches/uri.rs b/http/benches/uri.rs new file mode 100644 index 000000000..bf2e3f488 --- /dev/null +++ b/http/benches/uri.rs @@ -0,0 +1,33 @@ +#![feature(test)] + +extern crate http; +extern crate test; + +use http::Uri; +use test::Bencher; + +#[bench] +fn uri_parse_slash(b: &mut Bencher) { + b.bytes = 1; + b.iter(|| { + "/".parse::().unwrap(); + }); +} + +#[bench] +fn uri_parse_relative_medium(b: &mut Bencher) { + let s = "/wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg"; + b.bytes = s.len() as u64; + b.iter(|| { + s.parse::().unwrap(); + }); +} + +#[bench] +fn uri_parse_relative_query(b: &mut Bencher) { + let s = "/wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg?foo={bar}|baz%13%11quux"; + b.bytes = s.len() as u64; + b.iter(|| { + s.parse::().unwrap(); + }); +} diff --git a/http/src/byte_str.rs b/http/src/byte_str.rs new file mode 100644 index 000000000..00d9a2314 --- /dev/null +++ b/http/src/byte_str.rs @@ -0,0 +1,61 @@ +use bytes::Bytes; + +use std::{ops, str}; + +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub(crate) struct ByteStr { + bytes: Bytes, +} + +impl ByteStr { + #[inline] + pub fn new() -> ByteStr { + ByteStr { bytes: Bytes::new() } + } + + #[inline] + pub fn from_static(val: &'static str) -> ByteStr { + ByteStr { bytes: Bytes::from_static(val.as_bytes()) } + } + + #[inline] + pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr { + if cfg!(debug_assertions) { + match str::from_utf8(&bytes) { + Ok(_) => (), + Err(err) => panic!("ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}", err, bytes), + } + } + ByteStr { bytes: bytes } + } +} + +impl ops::Deref for ByteStr { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + let b: &[u8] = self.bytes.as_ref(); + unsafe { str::from_utf8_unchecked(b) } + } +} + +impl From for ByteStr { + #[inline] + fn from(src: String) -> ByteStr { + ByteStr { bytes: Bytes::from(src) } + } +} + +impl<'a> From<&'a str> for ByteStr { + #[inline] + fn from(src: &'a str) -> ByteStr { + ByteStr { bytes: Bytes::from(src) } + } +} + +impl From for Bytes { + fn from(src: ByteStr) -> Self { + src.bytes + } +} diff --git a/http/src/convert.rs b/http/src/convert.rs new file mode 100644 index 000000000..7f61c8ca4 --- /dev/null +++ b/http/src/convert.rs @@ -0,0 +1,64 @@ +use Error; +use header::{HeaderName, HeaderValue}; +use method::Method; +use sealed::Sealed; +use status::StatusCode; +use uri::{Scheme, Authority, PathAndQuery, Uri}; + +/// Private trait for the `http` crate to have generic methods with fallible +/// conversions. +/// +/// This trait is similar to the `TryFrom` trait proposed in the standard +/// library, except this is specialized for the `http` crate and isn't intended +/// for general consumption. +/// +/// This trait cannot be implemented types outside of the `http` crate, and is +/// only intended for use as a generic bound on methods in the `http` crate. +pub trait HttpTryFrom: Sized + Sealed { + /// Associated error with the conversion this implementation represents. + type Error: Into; + + #[doc(hidden)] + fn try_from(t: T) -> Result; +} + +pub(crate) trait HttpTryInto: Sized { + fn http_try_into(self) -> Result; +} + +#[doc(hidden)] +impl HttpTryInto for T +where + U: HttpTryFrom, + T: Sized, +{ + fn http_try_into(self) -> Result { + HttpTryFrom::try_from(self) + .map_err(|e: U::Error| e.into()) + } +} + +macro_rules! reflexive { + ($($t:ty,)*) => ($( + impl HttpTryFrom<$t> for $t { + type Error = Error; + + fn try_from(t: Self) -> Result { + Ok(t) + } + } + + impl Sealed for $t {} + )*) +} + +reflexive! { + Uri, + Method, + StatusCode, + HeaderName, + HeaderValue, + Scheme, + Authority, + PathAndQuery, +} diff --git a/http/src/error.rs b/http/src/error.rs new file mode 100644 index 000000000..21b5526ff --- /dev/null +++ b/http/src/error.rs @@ -0,0 +1,195 @@ +use std::error; +use std::fmt; +use std::result; + +use header; +use method; +use status; +use uri; + +/// A generic "error" for HTTP connections +/// +/// This error type is less specific than the error returned from other +/// functions in this crate, but all other errors can be converted to this +/// error. Consumers of this crate can typically consume and work with this form +/// of error for conversions with the `?` operator. +#[derive(Debug)] +pub struct Error { + inner: ErrorKind, +} + +/// A `Result` typedef to use with the `http::Error` type +pub type Result = result::Result; + +#[derive(Debug)] +enum ErrorKind { + StatusCode(status::InvalidStatusCode), + Method(method::InvalidMethod), + Uri(uri::InvalidUri), + UriShared(uri::InvalidUriBytes), + UriParts(uri::InvalidUriParts), + HeaderName(header::InvalidHeaderName), + HeaderNameShared(header::InvalidHeaderNameBytes), + HeaderValue(header::InvalidHeaderValue), + HeaderValueShared(header::InvalidHeaderValueBytes), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl Error { + /// Return true if the underlying error has the same type as T. + pub fn is(&self) -> bool { + self.get_ref().is::() + } + + /// Return a reference to the lower level, inner error. + pub fn get_ref(&self) -> &(error::Error + 'static) { + use self::ErrorKind::*; + + match self.inner { + StatusCode(ref e) => e, + Method(ref e) => e, + Uri(ref e) => e, + UriShared(ref e) => e, + UriParts(ref e) => e, + HeaderName(ref e) => e, + HeaderNameShared(ref e) => e, + HeaderValue(ref e) => e, + HeaderValueShared(ref e) => e, + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + use self::ErrorKind::*; + + match self.inner { + StatusCode(ref e) => e.description(), + Method(ref e) => e.description(), + Uri(ref e) => e.description(), + UriShared(ref e) => e.description(), + UriParts(ref e) => e.description(), + HeaderName(ref e) => e.description(), + HeaderNameShared(ref e) => e.description(), + HeaderValue(ref e) => e.description(), + HeaderValueShared(ref e) => e.description(), + } + } + + // Return any available cause from the inner error. Note the inner error is + // not itself the cause. + #[allow(deprecated)] + fn cause(&self) -> Option<&error::Error> { + self.get_ref().cause() + } +} + +impl From for Error { + fn from(err: status::InvalidStatusCode) -> Error { + Error { inner: ErrorKind::StatusCode(err) } + } +} + +impl From for Error { + fn from(err: method::InvalidMethod) -> Error { + Error { inner: ErrorKind::Method(err) } + } +} + +impl From for Error { + fn from(err: uri::InvalidUri) -> Error { + Error { inner: ErrorKind::Uri(err) } + } +} + +impl From for Error { + fn from(err: uri::InvalidUriBytes) -> Error { + Error { inner: ErrorKind::UriShared(err) } + } +} + +impl From for Error { + fn from(err: uri::InvalidUriParts) -> Error { + Error { inner: ErrorKind::UriParts(err) } + } +} + +impl From for Error { + fn from(err: header::InvalidHeaderName) -> Error { + Error { inner: ErrorKind::HeaderName(err) } + } +} + +impl From for Error { + fn from(err: header::InvalidHeaderNameBytes) -> Error { + Error { inner: ErrorKind::HeaderNameShared(err) } + } +} + +impl From for Error { + fn from(err: header::InvalidHeaderValue) -> Error { + Error { inner: ErrorKind::HeaderValue(err) } + } +} + +impl From for Error { + fn from(err: header::InvalidHeaderValueBytes) -> Error { + Error { inner: ErrorKind::HeaderValueShared(err) } + } +} + +// A crate-private type until we can use !. +// +// Being crate-private, we should be able to swap the type out in a +// backwards compatible way. +pub enum Never {} + +impl From for Error { + fn from(never: Never) -> Error { + match never {} + } +} + +impl fmt::Debug for Never { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match *self {} + } +} + +impl fmt::Display for Never { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + match *self {} + } +} + +impl error::Error for Never { + fn description(&self) -> &str { + match *self {} + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn inner_error_is_invalid_status_code() { + if let Err(e) = status::StatusCode::from_u16(6666) { + let err: Error = e.into(); + let ie = err.get_ref(); + assert!(!ie.is::()); + assert!( ie.is::()); + ie.downcast_ref::().unwrap(); + + assert!(!err.is::()); + assert!( err.is::()); + } else { + panic!("Bad status allowed!"); + } + } +} diff --git a/http/src/extensions.rs b/http/src/extensions.rs new file mode 100644 index 000000000..6cbf1e3ae --- /dev/null +++ b/http/src/extensions.rs @@ -0,0 +1,195 @@ +use std::any::{Any, TypeId}; +use std::collections::HashMap; +use std::hash::{BuildHasherDefault, Hasher}; +use std::fmt; + +type AnyMap = HashMap, BuildHasherDefault>; + +// With TypeIds as keys, there's no need to hash them. They are already hashes +// themselves, coming from the compiler. The IdHasher just holds the u64 of +// the TypeId, and then returns it, instead of doing any bit fiddling. +#[derive(Default)] +struct IdHasher(u64); + +impl Hasher for IdHasher { + fn write(&mut self, _: &[u8]) { + unreachable!("TypeId calls write_u64"); + } + + #[inline] + fn write_u64(&mut self, id: u64) { + self.0 = id; + } + + #[inline] + fn finish(&self) -> u64 { + self.0 + } +} + + + +/// A type map of protocol extensions. +/// +/// `Extensions` can be used by `Request` and `Response` to store +/// extra data derived from the underlying protocol. +#[derive(Default)] +pub struct Extensions { + // If extensions are never used, no need to carry around an empty HashMap. + // That's 3 words. Instead, this is only 1 word. + map: Option>, +} + +impl Extensions { + /// Create an empty `Extensions`. + #[inline] + pub fn new() -> Extensions { + Extensions { + map: None, + } + } + + /// Insert a type into this `Extensions`. + /// + /// If a extension of this type already existed, it will + /// be returned. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// assert!(ext.insert(5i32).is_none()); + /// assert!(ext.insert(4u8).is_none()); + /// assert_eq!(ext.insert(9i32), Some(5i32)); + /// ``` + pub fn insert(&mut self, val: T) -> Option { + self + .map + .get_or_insert_with(|| Box::new(HashMap::default())) + .insert(TypeId::of::(), Box::new(val)) + .and_then(|boxed| { + //TODO: we can use unsafe and remove double checking the type id + (boxed as Box) + .downcast() + .ok() + .map(|boxed| *boxed) + }) + } + + /// Get a reference to a type previously inserted on this `Extensions`. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// assert!(ext.get::().is_none()); + /// ext.insert(5i32); + /// + /// assert_eq!(ext.get::(), Some(&5i32)); + /// ``` + pub fn get(&self) -> Option<&T> { + self + .map + .as_ref() + .and_then(|map| map.get(&TypeId::of::())) + //TODO: we can use unsafe and remove double checking the type id + .and_then(|boxed| (&**boxed as &(Any + 'static)).downcast_ref()) + } + + /// Get a mutable reference to a type previously inserted on this `Extensions`. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(String::from("Hello")); + /// ext.get_mut::().unwrap().push_str(" World"); + /// + /// assert_eq!(ext.get::().unwrap(), "Hello World"); + /// ``` + pub fn get_mut(&mut self) -> Option<&mut T> { + self + .map + .as_mut() + .and_then(|map| map.get_mut(&TypeId::of::())) + //TODO: we can use unsafe and remove double checking the type id + .and_then(|boxed| (&mut **boxed as &mut (Any + 'static)).downcast_mut()) + } + + + /// Remove a type from this `Extensions`. + /// + /// If a extension of this type existed, it will be returned. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(5i32); + /// assert_eq!(ext.remove::(), Some(5i32)); + /// assert!(ext.get::().is_none()); + /// ``` + pub fn remove(&mut self) -> Option { + self + .map + .as_mut() + .and_then(|map| map.remove(&TypeId::of::())) + .and_then(|boxed| { + //TODO: we can use unsafe and remove double checking the type id + (boxed as Box) + .downcast() + .ok() + .map(|boxed| *boxed) + }) + } + + /// Clear the `Extensions` of all inserted extensions. + /// + /// # Example + /// + /// ``` + /// # use http::Extensions; + /// let mut ext = Extensions::new(); + /// ext.insert(5i32); + /// ext.clear(); + /// + /// assert!(ext.get::().is_none()); + /// ``` + #[inline] + pub fn clear(&mut self) { + if let Some(ref mut map) = self.map { + map.clear(); + } + } +} + +impl fmt::Debug for Extensions { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Extensions") + .finish() + } +} + +#[test] +fn test_extensions() { + #[derive(Debug, PartialEq)] + struct MyType(i32); + + let mut extensions = Extensions::new(); + + extensions.insert(5i32); + extensions.insert(MyType(10)); + + assert_eq!(extensions.get(), Some(&5i32)); + assert_eq!(extensions.get_mut(), Some(&mut 5i32)); + + assert_eq!(extensions.remove::(), Some(5i32)); + assert!(extensions.get::().is_none()); + + assert_eq!(extensions.get::(), None); + assert_eq!(extensions.get(), Some(&MyType(10))); +} diff --git a/http/src/header/map.rs b/http/src/header/map.rs new file mode 100644 index 000000000..66f987cc9 --- /dev/null +++ b/http/src/header/map.rs @@ -0,0 +1,3321 @@ +use super::HeaderValue; +use super::name::{HeaderName, HdrName, InvalidHeaderName}; + +use std::{fmt, mem, ops, ptr, vec}; +use std::collections::hash_map::RandomState; +use std::hash::{BuildHasher, Hasher, Hash}; +use std::iter::FromIterator; +use std::marker::PhantomData; + +pub use self::as_header_name::AsHeaderName; +pub use self::into_header_name::IntoHeaderName; + +/// A set of HTTP headers +/// +/// `HeaderMap` is an multimap of [`HeaderName`] to values. +/// +/// [`HeaderName`]: struct.HeaderName.html +/// +/// # Examples +/// +/// Basic usage +/// +/// ``` +/// # use http::HeaderMap; +/// # use http::header::{CONTENT_LENGTH, HOST, LOCATION}; +/// let mut headers = HeaderMap::new(); +/// +/// headers.insert(HOST, "example.com".parse().unwrap()); +/// headers.insert(CONTENT_LENGTH, "123".parse().unwrap()); +/// +/// assert!(headers.contains_key(HOST)); +/// assert!(!headers.contains_key(LOCATION)); +/// +/// assert_eq!(headers[HOST], "example.com"); +/// +/// headers.remove(HOST); +/// +/// assert!(!headers.contains_key(HOST)); +/// ``` +#[derive(Clone)] +pub struct HeaderMap { + // Used to mask values to get an index + mask: Size, + indices: Box<[Pos]>, + entries: Vec>, + extra_values: Vec>, + danger: Danger, +} + +// # Implementation notes +// +// Below, you will find a fairly large amount of code. Most of this is to +// provide the necessary functions to efficiently manipulate the header +// multimap. The core hashing table is based on robin hood hashing [1]. While +// this is the same hashing algorithm used as part of Rust's `HashMap` in +// stdlib, many implementation details are different. The two primary reasons +// for this divergence are that `HeaderMap` is a multimap and the structure has +// been optimized to take advantage of the characteristics of HTTP headers. +// +// ## Structure Layout +// +// Most of the data contained by `HeaderMap` is *not* stored in the hash table. +// Instead, pairs of header name and *first* associated header value are stored +// in the `entries` vector. If the header name has more than one associated +// header value, then additional values are stored in `extra_values`. The actual +// hash table (`indices`) only maps hash codes to indices in `entries`. This +// means that, when an eviction happens, the actual header name and value stay +// put and only a tiny amount of memory has to be copied. +// +// Extra values associated with a header name are tracked using a linked list. +// Links are formed with offsets into `extra_values` and not pointers. +// +// [1]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing + +/// `HeaderMap` entry iterator. +/// +/// Yields `(&HeaderName, &value)` tuples. The same header name may be yielded +/// more than once if it has more than one associated value. +#[derive(Debug)] +pub struct Iter<'a, T: 'a> { + inner: IterMut<'a, T>, +} + +/// `HeaderMap` mutable entry iterator +/// +/// Yields `(&HeaderName, &mut value)` tuples. The same header name may be +/// yielded more than once if it has more than one associated value. +#[derive(Debug)] +pub struct IterMut<'a, T: 'a> { + map: *mut HeaderMap, + entry: usize, + cursor: Option, + lt: PhantomData<&'a mut HeaderMap>, +} + +/// An owning iterator over the entries of a `HeaderMap`. +/// +/// This struct is created by the `into_iter` method on `HeaderMap`. +#[derive(Debug)] +pub struct IntoIter { + // If None, pull from `entries` + next: Option, + entries: vec::IntoIter>, + extra_values: Vec>, +} + +/// An iterator over `HeaderMap` keys. +/// +/// Each header name is yielded only once, even if it has more than one +/// associated value. +#[derive(Debug)] +pub struct Keys<'a, T: 'a> { + inner: ::std::slice::Iter<'a, Bucket>, +} + +/// `HeaderMap` value iterator. +/// +/// Each value contained in the `HeaderMap` will be yielded. +#[derive(Debug)] +pub struct Values<'a, T: 'a> { + inner: Iter<'a, T>, +} + +/// `HeaderMap` mutable value iterator +#[derive(Debug)] +pub struct ValuesMut<'a, T: 'a> { + inner: IterMut<'a, T>, +} + +/// A drain iterator for `HeaderMap`. +#[derive(Debug)] +pub struct Drain<'a, T: 'a> { + idx: usize, + map: *mut HeaderMap, + lt: PhantomData<&'a mut HeaderMap>, +} + +/// A view to all values stored in a single entry. +/// +/// This struct is returned by `HeaderMap::get_all`. +#[derive(Debug)] +pub struct GetAll<'a, T: 'a> { + map: &'a HeaderMap, + index: Option, +} + +/// A view into a single location in a `HeaderMap`, which may be vacant or occupied. +#[derive(Debug)] +pub enum Entry<'a, T: 'a> { + /// An occupied entry + Occupied(OccupiedEntry<'a, T>), + + /// A vacant entry + Vacant(VacantEntry<'a, T>), +} + +/// A view into a single empty location in a `HeaderMap`. +/// +/// This struct is returned as part of the `Entry` enum. +#[derive(Debug)] +pub struct VacantEntry<'a, T: 'a> { + map: &'a mut HeaderMap, + key: HeaderName, + hash: HashValue, + probe: usize, + danger: bool, +} + +/// A view into a single occupied location in a `HeaderMap`. +/// +/// This struct is returned as part of the `Entry` enum. +#[derive(Debug)] +pub struct OccupiedEntry<'a, T: 'a> { + map: &'a mut HeaderMap, + probe: usize, + index: usize, +} + +/// An iterator of all values associated with a single header name. +#[derive(Debug)] +pub struct ValueIter<'a, T: 'a> { + map: &'a HeaderMap, + index: usize, + front: Option, + back: Option, +} + +/// A mutable iterator of all values associated with a single header name. +#[derive(Debug)] +pub struct ValueIterMut<'a, T: 'a> { + map: *mut HeaderMap, + index: usize, + front: Option, + back: Option, + lt: PhantomData<&'a mut HeaderMap>, +} + +/// An drain iterator of all values associated with a single header name. +#[derive(Debug)] +pub struct ValueDrain<'a, T: 'a> { + map: *mut HeaderMap, + first: Option, + next: Option, + lt: PhantomData<&'a mut HeaderMap>, +} + +/// Tracks the value iterator state +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum Cursor { + Head, + Values(usize), +} + +/// Type used for representing the size of a HeaderMap value. +/// +/// 32,768 is more than enough entries for a single header map. Setting this +/// limit enables using `u16` to represent all offsets, which takes 2 bytes +/// instead of 8 on 64 bit processors. +/// +/// Setting this limit is especially benificial for `indices`, making it more +/// cache friendly. More hash codes can fit in a cache line. +/// +/// You may notice that `u16` may represent more than 32,768 values. This is +/// true, but 32,768 should be plenty and it allows us to reserve the top bit +/// for future usage. +type Size = usize; + +/// This limit falls out from above. +const MAX_SIZE: usize = (1 << 15); + +/// An entry in the hash table. This represents the full hash code for an entry +/// as well as the position of the entry in the `entries` vector. +#[derive(Copy, Clone)] +struct Pos { + // Index in the `entries` vec + index: Size, + // Full hash value for the entry. + hash: HashValue, +} + +/// Hash values are limited to u16 as well. While `fast_hash` and `Hasher` +/// return `usize` hash codes, limiting the effective hash code to the lower 16 +/// bits is fine since we know that the `indices` vector will never grow beyond +/// that size. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +struct HashValue(usize); + +/// Stores the data associated with a `HeaderMap` entry. Only the first value is +/// included in this struct. If a header name has more than one associated +/// value, all extra values are stored in the `extra_values` vector. A doubly +/// linked list of entries is maintained. The doubly linked list is used so that +/// removing a value is constant time. This also has the nice property of +/// enabling double ended iteration. +#[derive(Debug, Clone)] +struct Bucket { + hash: HashValue, + key: HeaderName, + value: T, + links: Option, +} + +/// The head and tail of the value linked list. +#[derive(Debug, Copy, Clone)] +struct Links { + next: usize, + tail: usize, +} + +/// Node in doubly-linked list of header value entries +#[derive(Debug, Clone)] +struct ExtraValue { + value: T, + prev: Link, + next: Link, +} + +/// A header value node is either linked to another node in the `extra_values` +/// list or it points to an entry in `entries`. The entry in `entries` is the +/// start of the list and holds the associated header name. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum Link { + Entry(usize), + Extra(usize), +} + +/// Tracks the header map danger level! This relates to the adaptive hashing +/// algorithm. A HeaderMap starts in the "green" state, when a large number of +/// collisions are detected, it transitions to the yellow state. At this point, +/// the header map will either grow and switch back to the green state OR it +/// will transition to the red state. +/// +/// When in the red state, a safe hashing algorithm is used and all values in +/// the header map have to be rehashed. +#[derive(Clone)] +enum Danger { + Green, + Yellow, + Red(RandomState), +} + +// Constants related to detecting DOS attacks. +// +// Displacement is the number of entries that get shifted when inserting a new +// value. Forward shift is how far the entry gets stored from the ideal +// position. +// +// The current constant values were picked from another implementation. It could +// be that there are different values better suited to the header map case. +const DISPLACEMENT_THRESHOLD: usize = 128; +const FORWARD_SHIFT_THRESHOLD: usize = 512; + +// The default strategy for handling the yellow danger state is to increase the +// header map capacity in order to (hopefully) reduce the number of collisions. +// If growing the hash map would cause the load factor to drop bellow this +// threshold, then instead of growing, the headermap is switched to the red +// danger state and safe hashing is used instead. +const LOAD_FACTOR_THRESHOLD: f32 = 0.2; + +// Macro used to iterate the hash table starting at a given point, looping when +// the end is hit. +macro_rules! probe_loop { + ($label:tt: $probe_var: ident < $len: expr, $body: expr) => { + debug_assert!($len > 0); + $label: + loop { + if $probe_var < $len { + $body + $probe_var += 1; + } else { + $probe_var = 0; + } + } + }; + ($probe_var: ident < $len: expr, $body: expr) => { + debug_assert!($len > 0); + loop { + if $probe_var < $len { + $body + $probe_var += 1; + } else { + $probe_var = 0; + } + } + }; +} + +// First part of the robinhood algorithm. Given a key, find the slot in which it +// will be inserted. This is done by starting at the "ideal" spot. Then scanning +// until the destination slot is found. A destination slot is either the next +// empty slot or the next slot that is occupied by an entry that has a lower +// displacement (displacement is the distance from the ideal spot). +// +// This is implemented as a macro instead of a function that takes a closure in +// order to guarantee that it is "inlined". There is no way to annotate closures +// to guarantee inlining. +macro_rules! insert_phase_one { + ($map:ident, + $key:expr, + $probe:ident, + $pos:ident, + $hash:ident, + $danger:ident, + $vacant:expr, + $occupied:expr, + $robinhood:expr) => + {{ + let $hash = hash_elem_using(&$map.danger, &$key); + let mut $probe = desired_pos($map.mask, $hash); + let mut dist = 0; + let ret; + + // Start at the ideal position, checking all slots + probe_loop!('probe: $probe < $map.indices.len(), { + if let Some(($pos, entry_hash)) = $map.indices[$probe].resolve() { + // The slot is already occupied, but check if it has a lower + // displacement. + let their_dist = probe_distance($map.mask, entry_hash, $probe); + + if their_dist < dist { + // The new key's distance is larger, so claim this spot and + // displace the current entry. + // + // Check if this insertion is above the danger threshold. + let $danger = + dist >= FORWARD_SHIFT_THRESHOLD && !$map.danger.is_red(); + + ret = $robinhood; + break 'probe; + } else if entry_hash == $hash && $map.entries[$pos].key == $key { + // There already is an entry with the same key. + ret = $occupied; + break 'probe; + } + } else { + // The entry is vacant, use it for this key. + let $danger = + dist >= FORWARD_SHIFT_THRESHOLD && !$map.danger.is_red(); + + ret = $vacant; + break 'probe; + } + + dist += 1; + }); + + ret + }} +} + +// ===== impl HeaderMap ===== + +impl HeaderMap { + /// Create an empty `HeaderMap`. + /// + /// The map will be created without any capacity. This function will not + /// allocate. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let map = HeaderMap::new(); + /// + /// assert!(map.is_empty()); + /// assert_eq!(0, map.capacity()); + /// ``` + pub fn new() -> Self { + HeaderMap::with_capacity(0) + } +} + +impl HeaderMap { + /// Create an empty `HeaderMap` with the specified capacity. + /// + /// The returned map will allocate internal storage in order to hold about + /// `capacity` elements without reallocating. However, this is a "best + /// effort" as there are usage patterns that could cause additional + /// allocations before `capacity` headers are stored in the map. + /// + /// More capacity than requested may be allocated. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let map: HeaderMap = HeaderMap::with_capacity(10); + /// + /// assert!(map.is_empty()); + /// assert_eq!(12, map.capacity()); + /// ``` + pub fn with_capacity(capacity: usize) -> HeaderMap { + assert!(capacity <= MAX_SIZE, "requested capacity too large"); + + if capacity == 0 { + HeaderMap { + mask: 0, + indices: Box::new([]), // as a ZST, this doesn't actually allocate anything + entries: Vec::new(), + extra_values: Vec::new(), + danger: Danger::Green, + } + } else { + let raw_cap = to_raw_capacity(capacity).next_power_of_two(); + debug_assert!(raw_cap > 0); + + HeaderMap { + mask: (raw_cap - 1) as Size, + indices: vec![Pos::none(); raw_cap].into_boxed_slice(), + entries: Vec::with_capacity(raw_cap), + extra_values: Vec::new(), + danger: Danger::Green, + } + } + } + + /// Returns the number of headers stored in the map. + /// + /// This number represents the total number of **values** stored in the map. + /// This number can be greater than or equal to the number of **keys** + /// stored given that a single key may have more than one associated value. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{ACCEPT, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// assert_eq!(0, map.len()); + /// + /// map.insert(ACCEPT, "text/plain".parse().unwrap()); + /// map.insert(HOST, "localhost".parse().unwrap()); + /// + /// assert_eq!(2, map.len()); + /// + /// map.append(ACCEPT, "text/html".parse().unwrap()); + /// + /// assert_eq!(3, map.len()); + /// ``` + pub fn len(&self) -> usize { + self.entries.len() + self.extra_values.len() + } + + /// Returns the number of keys stored in the map. + /// + /// This number will be less than or equal to `len()` as each key may have + /// more than one associated value. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{ACCEPT, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// assert_eq!(0, map.keys_len()); + /// + /// map.insert(ACCEPT, "text/plain".parse().unwrap()); + /// map.insert(HOST, "localhost".parse().unwrap()); + /// + /// assert_eq!(2, map.keys_len()); + /// + /// map.insert(ACCEPT, "text/html".parse().unwrap()); + /// + /// assert_eq!(2, map.keys_len()); + /// ``` + pub fn keys_len(&self) -> usize { + self.entries.len() + } + + /// Returns true if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// + /// assert!(map.is_empty()); + /// + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// assert!(!map.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.entries.len() == 0 + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// map.clear(); + /// assert!(map.is_empty()); + /// assert!(map.capacity() > 0); + /// ``` + pub fn clear(&mut self) { + self.entries.clear(); + self.extra_values.clear(); + self.danger = Danger::Green; + + for e in self.indices.iter_mut() { + *e = Pos::none(); + } + } + + /// Returns the number of headers the map can hold without reallocating. + /// + /// This number is an approximation as certain usage patterns could cause + /// additional allocations before the returned capacity is filled. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// + /// assert_eq!(0, map.capacity()); + /// + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// assert_eq!(6, map.capacity()); + /// ``` + pub fn capacity(&self) -> usize { + usable_capacity(self.indices.len()) + } + + /// Reserves capacity for at least `additional` more headers to be inserted + /// into the `HeaderMap`. + /// + /// The header map may reserve more space to avoid frequent reallocations. + /// Like with `with_capacity`, this will be a "best effort" to avoid + /// allocations until `additional` more headers are inserted. Certain usage + /// patterns could cause additional allocations before the number is + /// reached. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows `usize`. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// map.reserve(10); + /// # map.insert(HOST, "bar".parse().unwrap()); + /// ``` + pub fn reserve(&mut self, additional: usize) { + // TODO: This can't overflow if done properly... since the max # of + // elements is u16::MAX. + let cap = self.entries.len() + .checked_add(additional) + .expect("reserve overflow"); + + if cap > self.indices.len() { + let cap = cap.next_power_of_two(); + + if self.entries.len() == 0 { + self.mask = cap - 1; + self.indices = vec![Pos::none(); cap].into_boxed_slice(); + self.entries = Vec::with_capacity(usable_capacity(cap)); + } else { + self.grow(cap); + } + } + } + + /// Returns a reference to the value associated with the key. + /// + /// If there are multiple values associated with the key, then the first one + /// is returned. Use `get_all` to get all values associated with a given + /// key. Returns `None` if there are no values associated with the key. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// assert!(map.get("host").is_none()); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// assert_eq!(map.get(HOST).unwrap(), &"hello"); + /// assert_eq!(map.get("host").unwrap(), &"hello"); + /// + /// map.append(HOST, "world".parse().unwrap()); + /// assert_eq!(map.get("host").unwrap(), &"hello"); + /// ``` + pub fn get(&self, key: K) -> Option<&T> + where K: AsHeaderName + { + self.get2(&key) + } + + fn get2(&self, key: &K) -> Option<&T> + where K: AsHeaderName + { + match key.find(self) { + Some((_, found)) => { + let entry = &self.entries[found]; + Some(&entry.value) + } + None => None, + } + } + + /// Returns a mutable reference to the value associated with the key. + /// + /// If there are multiple values associated with the key, then the first one + /// is returned. Use `entry` to get all values associated with a given + /// key. Returns `None` if there are no values associated with the key. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::default(); + /// map.insert(HOST, "hello".to_string()); + /// map.get_mut("host").unwrap().push_str("-world"); + /// + /// assert_eq!(map.get(HOST).unwrap(), &"hello-world"); + /// ``` + pub fn get_mut(&mut self, key: K) -> Option<&mut T> + where K: AsHeaderName + { + match key.find(self) { + Some((_, found)) => { + let entry = &mut self.entries[found]; + Some(&mut entry.value) + } + None => None, + } + } + + /// Returns a view of all values associated with a key. + /// + /// The returned view does not incur any allocations and allows iterating + /// the values associated with the key. See [`GetAll`] for more details. + /// Returns `None` if there are no values associated with the key. + /// + /// [`GetAll`]: struct.GetAll.html + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// map.append(HOST, "goodbye".parse().unwrap()); + /// + /// let view = map.get_all("host"); + /// + /// let mut iter = view.iter(); + /// assert_eq!(&"hello", iter.next().unwrap()); + /// assert_eq!(&"goodbye", iter.next().unwrap()); + /// assert!(iter.next().is_none()); + /// ``` + pub fn get_all(&self, key: K) -> GetAll + where K: AsHeaderName + { + GetAll { + map: self, + index: key.find(self).map(|(_, i)| i), + } + } + + /// Returns true if the map contains a value for the specified key. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// assert!(!map.contains_key(HOST)); + /// + /// map.insert(HOST, "world".parse().unwrap()); + /// assert!(map.contains_key("host")); + /// ``` + pub fn contains_key(&self, key: K) -> bool + where K: AsHeaderName + { + key.find(self).is_some() + } + + /// An iterator visiting all key-value pairs. + /// + /// The iteration order is arbitrary, but consistent across platforms for + /// the same crate version. Each key will be yielded once per associated + /// value. So, if a key has 3 associated values, it will be yielded 3 times. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// map.append(HOST, "goodbye".parse().unwrap()); + /// map.insert(CONTENT_LENGTH, "123".parse().unwrap()); + /// + /// for (key, value) in map.iter() { + /// println!("{:?}: {:?}", key, value); + /// } + /// ``` + pub fn iter(&self) -> Iter { + Iter { + inner: IterMut { + map: self as *const _ as *mut _, + entry: 0, + cursor: self.entries.first().map(|_| Cursor::Head), + lt: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs, with mutable value references. + /// + /// The iterator order is arbitrary, but consistent across platforms for the + /// same crate version. Each key will be yielded once per associated value, + /// so if a key has 3 associated values, it will be yielded 3 times. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::default(); + /// + /// map.insert(HOST, "hello".to_string()); + /// map.append(HOST, "goodbye".to_string()); + /// map.insert(CONTENT_LENGTH, "123".to_string()); + /// + /// for (key, value) in map.iter_mut() { + /// value.push_str("-boop"); + /// } + /// ``` + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + map: self as *mut _, + entry: 0, + cursor: self.entries.first().map(|_| Cursor::Head), + lt: PhantomData, + } + } + + /// An iterator visiting all keys. + /// + /// The iteration order is arbitrary, but consistent across platforms for + /// the same crate version. Each key will be yielded only once even if it + /// has multiple associated values. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// map.append(HOST, "goodbye".parse().unwrap()); + /// map.insert(CONTENT_LENGTH, "123".parse().unwrap()); + /// + /// for key in map.keys() { + /// println!("{:?}", key); + /// } + /// ``` + pub fn keys(&self) -> Keys { + Keys { inner: self.entries.iter() } + } + + /// An iterator visiting all values. + /// + /// The iteration order is arbitrary, but consistent across platforms for + /// the same crate version. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// map.append(HOST, "goodbye".parse().unwrap()); + /// map.insert(CONTENT_LENGTH, "123".parse().unwrap()); + /// + /// for value in map.values() { + /// println!("{:?}", value); + /// } + /// ``` + pub fn values(&self) -> Values { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably. + /// + /// The iteration order is arbitrary, but consistent across platforms for + /// the same crate version. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::default(); + /// + /// map.insert(HOST, "hello".to_string()); + /// map.append(HOST, "goodbye".to_string()); + /// map.insert(CONTENT_LENGTH, "123".to_string()); + /// + /// for value in map.values_mut() { + /// value.push_str("-boop"); + /// } + /// ``` + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut { inner: self.iter_mut() } + } + + /// Clears the map, returning all entries as an iterator. + /// + /// The internal memory is kept for reuse. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::{CONTENT_LENGTH, HOST}; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(HOST, "hello".parse().unwrap()); + /// map.append(HOST, "goodbye".parse().unwrap()); + /// map.insert(CONTENT_LENGTH, "123".parse().unwrap()); + /// + /// let mut drain = map.drain(); + /// + /// let (key, mut vals) = drain.next().unwrap(); + /// + /// assert_eq!("host", key); + /// assert_eq!("hello", vals.next().unwrap()); + /// assert_eq!("goodbye", vals.next().unwrap()); + /// assert!(vals.next().is_none()); + /// + /// let (key, mut vals) = drain.next().unwrap(); + /// + /// assert_eq!("content-length", key); + /// assert_eq!("123", vals.next().unwrap()); + /// assert!(vals.next().is_none()); + /// ``` + pub fn drain(&mut self) -> Drain { + for i in self.indices.iter_mut() { + *i = Pos::none(); + } + + Drain { + idx: 0, + map: self as *mut _, + lt: PhantomData, + } + } + + fn value_iter(&self, idx: Option) -> ValueIter { + use self::Cursor::*; + + if let Some(idx) = idx { + let back = { + let entry = &self.entries[idx]; + + entry.links + .map(|l| Values(l.tail)) + .unwrap_or(Head) + }; + + ValueIter { + map: self, + index: idx, + front: Some(Head), + back: Some(back), + } + } else { + ValueIter { + map: self, + index: ::std::usize::MAX, + front: None, + back: None, + } + } + } + + fn value_iter_mut(&mut self, idx: usize) -> ValueIterMut { + use self::Cursor::*; + + let back = { + let entry = &self.entries[idx]; + + entry.links + .map(|l| Values(l.tail)) + .unwrap_or(Head) + }; + + ValueIterMut { + map: self as *mut _, + index: idx, + front: Some(Head), + back: Some(back), + lt: PhantomData, + } + } + + /// Gets the given key's corresponding entry in the map for in-place + /// manipulation. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let mut map: HeaderMap = HeaderMap::default(); + /// + /// let headers = &[ + /// "content-length", + /// "x-hello", + /// "Content-Length", + /// "x-world", + /// ]; + /// + /// for &header in headers { + /// let counter = map.entry(header).unwrap().or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(map["content-length"], 2); + /// assert_eq!(map["x-hello"], 1); + /// ``` + pub fn entry(&mut self, key: K) -> Result, InvalidHeaderName> + where K: AsHeaderName, + { + key.entry(self) + } + + fn entry2(&mut self, key: K) -> Entry + where K: Hash + Into, + HeaderName: PartialEq, + { + // Ensure that there is space in the map + self.reserve_one(); + + insert_phase_one!( + self, + key, + probe, + pos, + hash, + danger, + Entry::Vacant(VacantEntry { + map: self, + hash: hash, + key: key.into(), + probe: probe, + danger: danger, + }), + Entry::Occupied(OccupiedEntry { + map: self, + index: pos, + probe: probe, + }), + Entry::Vacant(VacantEntry { + map: self, + hash: hash, + key: key.into(), + probe: probe, + danger: danger, + })) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not previously have this key present, then `None` is + /// returned. + /// + /// If the map did have this key present, the new value is associated with + /// the key and all previous values are removed. **Note** that only a single + /// one of the previous values is returned. If there are multiple values + /// that have been previously associated with the key, then the first one is + /// returned. See `insert_mult` on `OccupiedEntry` for an API that returns + /// all values. + /// + /// The key is not updated, though; this matters for types that can be `==` + /// without being identical. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none()); + /// assert!(!map.is_empty()); + /// + /// let mut prev = map.insert(HOST, "earth".parse().unwrap()).unwrap(); + /// assert_eq!("world", prev); + /// ``` + pub fn insert(&mut self, key: K, val: T) -> Option + where K: IntoHeaderName, + { + key.insert(self, val) + } + + #[inline] + fn insert2(&mut self, key: K, value: T) -> Option + where K: Hash + Into, + HeaderName: PartialEq, + { + self.reserve_one(); + + insert_phase_one!( + self, key, probe, pos, hash, danger, + // Vacant + { + drop(danger); // Make lint happy + let index = self.entries.len(); + self.insert_entry(hash, key.into(), value); + self.indices[probe] = Pos::new(index, hash); + None + }, + // Occupied + Some(self.insert_occupied(pos, value)), + // Robinhood + { + self.insert_phase_two( + key.into(), + value, + hash, + probe, + danger); + None + }) + } + + /// Set an occupied bucket to the given value + #[inline] + fn insert_occupied(&mut self, index: usize, value: T) -> T { + if let Some(links) = self.entries[index].links { + self.remove_all_extra_values(links.next); + } + + let entry = &mut self.entries[index]; + mem::replace(&mut entry.value, value) + } + + fn insert_occupied_mult(&mut self, index: usize, value: T) -> ValueDrain { + let old; + let links; + + { + let entry = &mut self.entries[index]; + + old = mem::replace(&mut entry.value, value); + links = entry.links.take(); + } + + ValueDrain { + map: self as *mut _, + first: Some(old), + next: links.map(|l| l.next), + lt: PhantomData, + } + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not previously have this key present, then `false` is + /// returned. + /// + /// If the map did have this key present, the new value is pushed to the end + /// of the list of values currently associated with the key. The key is not + /// updated, though; this matters for types that can be `==` without being + /// identical. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// assert!(map.insert(HOST, "world".parse().unwrap()).is_none()); + /// assert!(!map.is_empty()); + /// + /// map.append(HOST, "earth".parse().unwrap()); + /// + /// let values = map.get_all("host"); + /// let mut i = values.iter(); + /// assert_eq!("world", *i.next().unwrap()); + /// assert_eq!("earth", *i.next().unwrap()); + /// ``` + pub fn append(&mut self, key: K, value: T) -> bool + where K: IntoHeaderName, + { + key.append(self, value) + } + + #[inline] + fn append2(&mut self, key: K, value: T) -> bool + where K: Hash + Into, + HeaderName: PartialEq, + { + self.reserve_one(); + + insert_phase_one!( + self, key, probe, pos, hash, danger, + // Vacant + { + drop(danger); + let index = self.entries.len(); + self.insert_entry(hash, key.into(), value); + self.indices[probe] = Pos::new(index, hash); + false + }, + // Occupied + { + append_value(pos, &mut self.entries[pos], &mut self.extra_values, value); + true + }, + // Robinhood + { + self.insert_phase_two( + key.into(), + value, + hash, + probe, + danger); + + false + }) + } + + #[inline] + fn find(&self, key: &K) -> Option<(usize, usize)> + where K: Hash + Into, + HeaderName: PartialEq, + { + if self.entries.is_empty() { + return None; + } + + let hash = hash_elem_using(&self.danger, key); + let mask = self.mask; + let mut probe = desired_pos(mask, hash); + let mut dist = 0; + + probe_loop!(probe < self.indices.len(), { + if let Some((i, entry_hash)) = self.indices[probe].resolve() { + if dist > probe_distance(mask, entry_hash, probe) { + // give up when probe distance is too long + return None; + } else if entry_hash == hash && self.entries[i].key == *key { + return Some((probe, i)); + } + } else { + return None; + } + + dist += 1; + }); + } + + /// phase 2 is post-insert where we forward-shift `Pos` in the indices. + #[inline] + fn insert_phase_two(&mut self, + key: HeaderName, + value: T, + hash: HashValue, + probe: usize, + danger: bool) -> usize + { + // Push the value and get the index + let index = self.entries.len(); + self.insert_entry(hash, key, value); + + let num_displaced = do_insert_phase_two( + &mut self.indices, + probe, + Pos::new(index, hash)); + + if danger || num_displaced >= DISPLACEMENT_THRESHOLD { + // Increase danger level + self.danger.to_yellow(); + } + + index + } + + /// Removes a key from the map, returning the value associated with the key. + /// + /// Returns `None` if the map does not contain the key. If there are + /// multiple values associated with the key, then the first one is returned. + /// See `remove_entry_mult` on `OccupiedEntry` for an API that yields all + /// values. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// let prev = map.remove(HOST).unwrap(); + /// assert_eq!("hello.world", prev); + /// + /// assert!(map.remove(HOST).is_none()); + /// ``` + pub fn remove(&mut self, key: K) -> Option + where K: AsHeaderName + { + match key.find(self) { + Some((probe, idx)) => { + if let Some(links) = self.entries[idx].links { + self.remove_all_extra_values(links.next); + } + + let entry = self.remove_found(probe, idx); + + Some(entry.value) + } + None => None, + } + } + + /// Remove an entry from the map. + #[inline] + fn remove_found(&mut self, probe: usize, found: usize) -> Bucket { + // index `probe` and entry `found` is to be removed + // use swap_remove, but then we need to update the index that points + // to the other entry that has to move + self.indices[probe] = Pos::none(); + let entry = self.entries.swap_remove(found); + + // correct index that points to the entry that had to swap places + if let Some(entry) = self.entries.get(found) { + // was not last element + // examine new element in `found` and find it in indices + let mut probe = desired_pos(self.mask, entry.hash); + + probe_loop!(probe < self.indices.len(), { + if let Some((i, _)) = self.indices[probe].resolve() { + if i >= self.entries.len() { + // found it + self.indices[probe] = Pos::new(found, entry.hash); + break; + } + } + }); + + // Update links + if let Some(links) = entry.links { + self.extra_values[links.next].prev = Link::Entry(found); + self.extra_values[links.tail].next = Link::Entry(found); + } + } + + // backward shift deletion in self.indices + // after probe, shift all non-ideally placed indices backward + if self.entries.len() > 0 { + let mut last_probe = probe; + let mut probe = probe + 1; + + probe_loop!(probe < self.indices.len(), { + if let Some((_, entry_hash)) = self.indices[probe].resolve() { + if probe_distance(self.mask, entry_hash, probe) > 0 { + self.indices[last_probe] = self.indices[probe]; + self.indices[probe] = Pos::none(); + } else { + break; + } + } else { + break; + } + + last_probe = probe; + }); + } + + entry + } + + /// Removes the `ExtraValue` at the given index. + #[inline] + fn remove_extra_value(&mut self, idx: usize) -> ExtraValue { + let prev; + let next; + + { + debug_assert!(self.extra_values.len() > idx); + let extra = &self.extra_values[idx]; + prev = extra.prev; + next = extra.next; + } + + // First unlink the extra value + match (prev, next) { + (Link::Entry(prev), Link::Entry(next)) => { + debug_assert_eq!(prev, next); + debug_assert!(self.entries.len() > prev); + + self.entries[prev].links = None; + } + (Link::Entry(prev), Link::Extra(next)) => { + debug_assert!(self.entries.len() > prev); + debug_assert!(self.entries[prev].links.is_some()); + + self.entries[prev].links.as_mut().unwrap() + .next = next; + + debug_assert!(self.extra_values.len() > next); + self.extra_values[next].prev = Link::Entry(prev); + } + (Link::Extra(prev), Link::Entry(next)) => { + debug_assert!(self.entries.len() > next); + debug_assert!(self.entries[next].links.is_some()); + + self.entries[next].links.as_mut().unwrap() + .tail = prev; + + debug_assert!(self.extra_values.len() > prev); + self.extra_values[prev].next = Link::Entry(next); + } + (Link::Extra(prev), Link::Extra(next)) => { + debug_assert!(self.extra_values.len() > next); + debug_assert!(self.extra_values.len() > prev); + + self.extra_values[prev].next = Link::Extra(next); + self.extra_values[next].prev = Link::Extra(prev); + } + } + + // Remove the extra value + let mut extra = self.extra_values.swap_remove(idx); + + // This is the index of the value that was moved (possibly `extra`) + let old_idx = self.extra_values.len(); + + // Update the links + if extra.prev == Link::Extra(old_idx) { + extra.prev = Link::Extra(idx); + } + + if extra.next == Link::Extra(old_idx) { + extra.next = Link::Extra(idx); + } + + // Check if another entry was displaced. If it was, then the links + // need to be fixed. + if idx != old_idx { + let next; + let prev; + + { + debug_assert!(self.extra_values.len() > idx); + let moved = &self.extra_values[idx]; + next = moved.next; + prev = moved.prev; + } + + // An entry was moved, we have to the links + match prev { + Link::Entry(entry_idx) => { + // It is critical that we do not attempt to read the + // header name or value as that memory may have been + // "released" already. + debug_assert!(self.entries.len() > entry_idx); + debug_assert!(self.entries[entry_idx].links.is_some()); + + let links = self.entries[entry_idx].links.as_mut().unwrap(); + links.next = idx; + } + Link::Extra(extra_idx) => { + debug_assert!(self.extra_values.len() > extra_idx); + self.extra_values[extra_idx].next = Link::Extra(idx); + } + } + + match next { + Link::Entry(entry_idx) => { + debug_assert!(self.entries.len() > entry_idx); + debug_assert!(self.entries[entry_idx].links.is_some()); + + let links = self.entries[entry_idx].links.as_mut().unwrap(); + links.tail = idx; + } + Link::Extra(extra_idx) => { + debug_assert!(self.extra_values.len() > extra_idx); + self.extra_values[extra_idx].prev = Link::Extra(idx); + } + } + } + + debug_assert!({ + for v in &self.extra_values { + assert!(v.next != Link::Extra(old_idx)); + assert!(v.prev != Link::Extra(old_idx)); + } + + true + }); + + extra + } + + fn remove_all_extra_values(&mut self, mut head: usize) { + loop { + let extra = self.remove_extra_value(head); + + if let Link::Extra(idx) = extra.next { + head = idx; + } else { + break; + } + } + } + + #[inline] + fn insert_entry(&mut self, hash: HashValue, key: HeaderName, value: T) { + assert!(self.entries.len() < MAX_SIZE, "header map at capacity"); + + self.entries.push(Bucket { + hash: hash, + key: key, + value: value, + links: None, + }); + } + + fn rebuild(&mut self) { + // Loop over all entries and re-insert them into the map + 'outer: + for (index, entry) in self.entries.iter_mut().enumerate() { + let hash = hash_elem_using(&self.danger, &entry.key); + let mut probe = desired_pos(self.mask, hash); + let mut dist = 0; + + // Update the entry's hash code + entry.hash = hash; + + probe_loop!(probe < self.indices.len(), { + if let Some((_, entry_hash)) = self.indices[probe].resolve() { + // if existing element probed less than us, swap + let their_dist = probe_distance(self.mask, entry_hash, probe); + + if their_dist < dist { + // Robinhood + break; + } + } else { + // Vacant slot + self.indices[probe] = Pos::new(index, hash); + continue 'outer; + } + + dist += 1; + }); + + do_insert_phase_two( + &mut self.indices, + probe, + Pos::new(index, hash)); + } + } + + fn reinsert_entry_in_order(&mut self, pos: Pos) { + if let Some((_, entry_hash)) = pos.resolve() { + // Find first empty bucket and insert there + let mut probe = desired_pos(self.mask, entry_hash); + + probe_loop!(probe < self.indices.len(), { + if self.indices[probe].resolve().is_none() { + // empty bucket, insert here + self.indices[probe] = pos; + return; + } + }); + } + } + + fn reserve_one(&mut self) { + let len = self.entries.len(); + + if self.danger.is_yellow() { + let load_factor = self.entries.len() as f32 / self.indices.len() as f32; + + if load_factor >= LOAD_FACTOR_THRESHOLD { + // Transition back to green danger level + self.danger.to_green(); + + // Double the capacity + let new_cap = self.indices.len() * 2; + + // Grow the capacity + self.grow(new_cap); + } else { + self.danger.to_red(); + + // Rebuild hash table + for index in self.indices.iter_mut() { + *index = Pos::none(); + } + + self.rebuild(); + } + } else if len == self.capacity() { + if len == 0 { + let new_raw_cap = 8; + self.mask = 8 - 1; + self.indices = vec![Pos::none(); new_raw_cap].into_boxed_slice(); + self.entries = Vec::with_capacity(usable_capacity(new_raw_cap)); + } else { + let raw_cap = self.indices.len(); + self.grow(raw_cap << 1); + } + } + } + + #[inline] + fn grow(&mut self, new_raw_cap: usize) { + // This path can never be reached when handling the first allocation in + // the map. + + // find first ideally placed element -- start of cluster + let mut first_ideal = 0; + + for (i, pos) in self.indices.iter().enumerate() { + if let Some((_, entry_hash)) = pos.resolve() { + if 0 == probe_distance(self.mask, entry_hash, i) { + first_ideal = i; + break; + } + } + } + + // visit the entries in an order where we can simply reinsert them + // into self.indices without any bucket stealing. + let old_indices = mem::replace(&mut self.indices, vec![Pos::none(); new_raw_cap].into_boxed_slice()); + self.mask = new_raw_cap.wrapping_sub(1) as Size; + + for &pos in &old_indices[first_ideal..] { + self.reinsert_entry_in_order(pos); + } + + for &pos in &old_indices[..first_ideal] { + self.reinsert_entry_in_order(pos); + } + + // Reserve additional entry slots + let more = self.capacity() - self.entries.len(); + self.entries.reserve_exact(more); + } +} + +impl<'a, T> IntoIterator for &'a HeaderMap { + type Item = (&'a HeaderName, &'a T); + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut HeaderMap { + type Item = (&'a HeaderName, &'a mut T); + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl IntoIterator for HeaderMap { + type Item = (Option, T); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves keys and values + /// out of the map in arbitrary order. The map cannot be used after calling + /// this. + /// + /// For each yielded item that has `None` provided for the `HeaderName`, + /// then the associated header name is the same as that of the previously + /// yielded item. The first yielded item will have `HeaderName` set. + /// + /// # Examples + /// + /// Basic usage. + /// + /// ``` + /// # use http::header; + /// # use http::header::*; + /// let mut map = HeaderMap::new(); + /// map.insert(header::CONTENT_LENGTH, "123".parse().unwrap()); + /// map.insert(header::CONTENT_TYPE, "json".parse().unwrap()); + /// + /// let mut iter = map.into_iter(); + /// assert_eq!(iter.next(), Some((Some(header::CONTENT_LENGTH), "123".parse().unwrap()))); + /// assert_eq!(iter.next(), Some((Some(header::CONTENT_TYPE), "json".parse().unwrap()))); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// Multiple values per key. + /// + /// ``` + /// # use http::header; + /// # use http::header::*; + /// let mut map = HeaderMap::new(); + /// + /// map.append(header::CONTENT_LENGTH, "123".parse().unwrap()); + /// map.append(header::CONTENT_LENGTH, "456".parse().unwrap()); + /// + /// map.append(header::CONTENT_TYPE, "json".parse().unwrap()); + /// map.append(header::CONTENT_TYPE, "html".parse().unwrap()); + /// map.append(header::CONTENT_TYPE, "xml".parse().unwrap()); + /// + /// let mut iter = map.into_iter(); + /// + /// assert_eq!(iter.next(), Some((Some(header::CONTENT_LENGTH), "123".parse().unwrap()))); + /// assert_eq!(iter.next(), Some((None, "456".parse().unwrap()))); + /// + /// assert_eq!(iter.next(), Some((Some(header::CONTENT_TYPE), "json".parse().unwrap()))); + /// assert_eq!(iter.next(), Some((None, "html".parse().unwrap()))); + /// assert_eq!(iter.next(), Some((None, "xml".parse().unwrap()))); + /// assert!(iter.next().is_none()); + /// ``` + fn into_iter(self) -> IntoIter { + IntoIter { + next: None, + entries: self.entries.into_iter(), + extra_values: self.extra_values, + } + } +} + +impl FromIterator<(HeaderName, T)> for HeaderMap +{ + fn from_iter(iter: I) -> Self + where I: IntoIterator + { + let mut map = HeaderMap::default(); + map.extend(iter); + map + } +} + +impl Extend<(Option, T)> for HeaderMap { + /// Extend a `HeaderMap` with the contents of another `HeaderMap`. + /// + /// This function expects the yielded items to follow the same structure as + /// `IntoIter`. + /// + /// # Panics + /// + /// This panics if the first yielded item does not have a `HeaderName`. + /// + /// # Examples + /// + /// ``` + /// # use http::header::*; + /// let mut map = HeaderMap::new(); + /// + /// map.insert(ACCEPT, "text/plain".parse().unwrap()); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// let mut extra = HeaderMap::new(); + /// + /// extra.insert(HOST, "foo.bar".parse().unwrap()); + /// extra.insert(COOKIE, "hello".parse().unwrap()); + /// extra.append(COOKIE, "world".parse().unwrap()); + /// + /// map.extend(extra); + /// + /// assert_eq!(map["host"], "foo.bar"); + /// assert_eq!(map["accept"], "text/plain"); + /// assert_eq!(map["cookie"], "hello"); + /// + /// let v = map.get_all("host"); + /// assert_eq!(1, v.iter().count()); + /// + /// let v = map.get_all("cookie"); + /// assert_eq!(2, v.iter().count()); + /// ``` + fn extend, T)>>(&mut self, iter: I) { + let mut iter = iter.into_iter(); + + // The structure of this is a bit weird, but it is mostly to make the + // borrow checker happy. + let (mut key, mut val) = match iter.next() { + Some((Some(key), val)) => (key, val), + Some((None, _)) => panic!("expected a header name, but got None"), + None => return, + }; + + 'outer: + loop { + let mut entry = match self.entry2(key) { + Entry::Occupied(mut e) => { + // Replace all previous values while maintaining a handle to + // the entry. + e.insert(val); + e + } + Entry::Vacant(e) => { + e.insert_entry(val) + } + }; + + // As long as `HeaderName` is none, keep inserting the value into + // the current entry + 'inner: + loop { + match iter.next() { + Some((Some(k), v)) => { + key = k; + val = v; + continue 'outer; + } + Some((None, v)) => { + entry.append(v); + } + None => { + return; + } + } + } + } + } +} + +impl Extend<(HeaderName, T)> for HeaderMap +{ + fn extend>(&mut self, iter: I) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + + self.reserve(reserve); + + for (k, v) in iter { + self.append(k, v); + } + } +} + +impl PartialEq for HeaderMap { + fn eq(&self, other: &HeaderMap) -> bool { + if self.len() != other.len() { + return false; + } + + self.keys().all(|key| { + self.get_all(key) == other.get_all(key) + }) + } +} + +impl Eq for HeaderMap {} + +impl fmt::Debug for HeaderMap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HeaderMap { + fn default() -> Self { + HeaderMap::with_capacity(0) + } +} + +impl<'a, K, T> ops::Index for HeaderMap + where K: AsHeaderName, +{ + type Output = T; + + /// # Panics + /// Using the index operator will cause a panic if the header you're querying isn't set. + #[inline] + fn index(&self, index: K) -> &T { + match self.get2(&index) { + Some(val) => val, + None => panic!("no entry found for key {:?}", index.as_str()), + } + } +} + +/// phase 2 is post-insert where we forward-shift `Pos` in the indices. +/// +/// returns the number of displaced elements +#[inline] +fn do_insert_phase_two(indices: &mut [Pos], + mut probe: usize, + mut old_pos: Pos) + -> usize +{ + let mut num_displaced = 0; + + probe_loop!(probe < indices.len(), { + let pos = &mut indices[probe]; + + if pos.is_none() { + *pos = old_pos; + break; + } else { + num_displaced += 1; + old_pos = mem::replace(pos, old_pos); + } + }); + + num_displaced +} + +#[inline] +fn append_value(entry_idx: usize, + entry: &mut Bucket, + extra: &mut Vec>, + value: T) +{ + match entry.links { + Some(links) => { + let idx = extra.len(); + extra.push(ExtraValue { + value: value, + prev: Link::Extra(links.tail), + next: Link::Entry(entry_idx), + }); + + extra[links.tail].next = Link::Extra(idx); + + entry.links = Some(Links { + tail: idx, + .. links + }); + } + None => { + let idx = extra.len(); + extra.push(ExtraValue { + value: value, + prev: Link::Entry(entry_idx), + next: Link::Entry(entry_idx), + }); + + entry.links = Some(Links { + next: idx, + tail: idx, + }); + } + } +} + +// ===== impl Iter ===== + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = (&'a HeaderName, &'a T); + + fn next(&mut self) -> Option { + self.inner.next_unsafe().map(|(key, ptr)| { + (key, unsafe { &*ptr }) + }) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} +unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} + +// ===== impl IterMut ===== + +impl<'a, T> IterMut<'a, T> { + fn next_unsafe(&mut self) -> Option<(&'a HeaderName, *mut T)> { + use self::Cursor::*; + + if self.cursor.is_none() { + if (self.entry + 1) >= unsafe { &*self.map }.entries.len() { + return None; + } + + self.entry += 1; + self.cursor = Some(Cursor::Head); + } + + let entry = unsafe { &(*self.map).entries[self.entry] }; + + match self.cursor.unwrap() { + Head => { + self.cursor = entry.links.map(|l| Values(l.next)); + Some((&entry.key, &entry.value as *const _ as *mut _)) + } + Values(idx) => { + let extra = unsafe { &(*self.map).extra_values[idx] }; + + match extra.next { + Link::Entry(_) => self.cursor = None, + Link::Extra(i) => self.cursor = Some(Values(i)), + } + + Some((&entry.key, &extra.value as *const _ as *mut _)) + } + } + } +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = (&'a HeaderName, &'a mut T); + + fn next(&mut self) -> Option { + self.next_unsafe().map(|(key, ptr)| { + (key, unsafe { &mut *ptr }) + }) + } + + fn size_hint(&self) -> (usize, Option) { + let map = unsafe { &*self.map }; + debug_assert!(map.entries.len() >= self.entry); + + let lower = map.entries.len() - self.entry; + // We could pessimistically guess at the upper bound, saying + // that its lower + map.extra_values.len(). That could be + // way over though, such as if we're near the end, and have + // already gone through several extra values... + (lower, None) + } +} + +unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} +unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} + +// ===== impl Keys ===== + +impl<'a, T> Iterator for Keys<'a, T> { + type Item = &'a HeaderName; + + fn next(&mut self) -> Option { + self.inner.next().map(|b| &b.key) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +impl<'a, T> ExactSizeIterator for Keys<'a, T> {} + +// ===== impl Values ==== + +impl<'a, T> Iterator for Values<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +// ===== impl ValuesMut ==== + +impl<'a, T> Iterator for ValuesMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +// ===== impl Drain ===== + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = (HeaderName, ValueDrain<'a, T>); + + fn next(&mut self) -> Option { + let idx = self.idx; + + if idx == unsafe { (*self.map).entries.len() } { + return None; + } + + self.idx += 1; + + let key; + let value; + let next; + + unsafe { + let entry = &(*self.map).entries[idx]; + + // Read the header name + key = ptr::read(&entry.key as *const _); + value = ptr::read(&entry.value as *const _); + next = entry.links.map(|l| l.next); + }; + + let values = ValueDrain { + map: self.map, + first: Some(value), + next: next, + lt: PhantomData, + }; + + Some((key, values)) + } + + fn size_hint(&self) -> (usize, Option) { + let lower = unsafe { (*self.map).entries.len() } - self.idx; + (lower, Some(lower)) + } +} + +impl<'a, T> Drop for Drain<'a, T> { + fn drop(&mut self) { + unsafe { + let map = &mut *self.map; + debug_assert!(map.extra_values.is_empty()); + map.entries.set_len(0); + } + } +} + +unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl<'a, T: Send> Send for Drain<'a, T> {} + +// ===== impl Entry ===== + +impl<'a, T> Entry<'a, T> { + /// Ensures a value is in the entry by inserting the default if empty. + /// + /// Returns a mutable reference to the **first** value in the entry. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let mut map: HeaderMap = HeaderMap::default(); + /// + /// let headers = &[ + /// "content-length", + /// "x-hello", + /// "Content-Length", + /// "x-world", + /// ]; + /// + /// for &header in headers { + /// let counter = map.entry(header) + /// .expect("valid header names") + /// .or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(map["content-length"], 2); + /// assert_eq!(map["x-hello"], 1); + /// ``` + pub fn or_insert(self, default: T) -> &'a mut T { + use self::Entry::*; + + match self { + Occupied(e) => e.into_mut(), + Vacant(e) => e.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty. + /// + /// The default function is not called if the entry exists in the map. + /// Returns a mutable reference to the **first** value in the entry. + /// + /// # Examples + /// + /// Basic usage. + /// + /// ``` + /// # use http::HeaderMap; + /// let mut map = HeaderMap::new(); + /// + /// let res = map.entry("x-hello").unwrap() + /// .or_insert_with(|| "world".parse().unwrap()); + /// + /// assert_eq!(res, "world"); + /// ``` + /// + /// The default function is not called if the entry exists in the map. + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// + /// let res = map.entry("host") + /// .expect("host is a valid string") + /// .or_insert_with(|| unreachable!()); + /// + /// + /// assert_eq!(res, "world"); + /// ``` + pub fn or_insert_with T>(self, default: F) -> &'a mut T { + use self::Entry::*; + + match self { + Occupied(e) => e.into_mut(), + Vacant(e) => e.insert(default()), + } + } + + /// Returns a reference to the entry's key + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let mut map = HeaderMap::new(); + /// + /// assert_eq!(map.entry("x-hello").unwrap().key(), "x-hello"); + /// ``` + pub fn key(&self) -> &HeaderName { + use self::Entry::*; + + match *self { + Vacant(ref e) => e.key(), + Occupied(ref e) => e.key(), + } + } +} + +// ===== impl VacantEntry ===== + +impl<'a, T> VacantEntry<'a, T> { + /// Returns a reference to the entry's key + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// let mut map = HeaderMap::new(); + /// + /// assert_eq!(map.entry("x-hello").unwrap().key().as_str(), "x-hello"); + /// ``` + pub fn key(&self) -> &HeaderName { + &self.key + } + + /// Take ownership of the key + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry}; + /// let mut map = HeaderMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { + /// assert_eq!(v.into_key().as_str(), "x-hello"); + /// } + /// ``` + pub fn into_key(self) -> HeaderName { + self.key + } + + /// Insert the value into the entry. + /// + /// The value will be associated with this entry's key. A mutable reference + /// to the inserted value will be returned. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry}; + /// let mut map = HeaderMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { + /// v.insert("world".parse().unwrap()); + /// } + /// + /// assert_eq!(map["x-hello"], "world"); + /// ``` + pub fn insert(self, value: T) -> &'a mut T { + // Ensure that there is space in the map + let index = self.map.insert_phase_two( + self.key, + value.into(), + self.hash, + self.probe, + self.danger); + + &mut self.map.entries[index].value + } + + /// Insert the value into the entry. + /// + /// The value will be associated with this entry's key. The new + /// `OccupiedEntry` is returned, allowing for further manipulation. + /// + /// # Examples + /// + /// ``` + /// # use http::header::*; + /// let mut map = HeaderMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("x-hello").unwrap() { + /// let mut e = v.insert_entry("world".parse().unwrap()); + /// e.insert("world2".parse().unwrap()); + /// } + /// + /// assert_eq!(map["x-hello"], "world2"); + /// ``` + pub fn insert_entry(self, value: T) -> OccupiedEntry<'a, T> { + // Ensure that there is space in the map + let index = self.map.insert_phase_two( + self.key, + value.into(), + self.hash, + self.probe, + self.danger); + + OccupiedEntry { + map: self.map, + index: index, + probe: self.probe, + } + } +} + + +// ===== impl GetAll ===== + +impl<'a, T: 'a> GetAll<'a, T> { + /// Returns an iterator visiting all values associated with the entry. + /// + /// Values are iterated in insertion order. + /// + /// # Examples + /// + /// ``` + /// # use http::HeaderMap; + /// # use http::header::HOST; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// map.append(HOST, "hello.earth".parse().unwrap()); + /// + /// let values = map.get_all("host"); + /// let mut iter = values.iter(); + /// assert_eq!(&"hello.world", iter.next().unwrap()); + /// assert_eq!(&"hello.earth", iter.next().unwrap()); + /// assert!(iter.next().is_none()); + /// ``` + pub fn iter(&self) -> ValueIter<'a, T> { + // This creates a new GetAll struct so that the lifetime + // isn't bound to &self. + GetAll { + map: self.map, + index: self.index, + }.into_iter() + } +} + +impl<'a, T: PartialEq> PartialEq for GetAll<'a, T> { + fn eq(&self, other: &Self) -> bool { + self.iter().eq(other.iter()) + } +} + +impl<'a, T> IntoIterator for GetAll<'a, T> { + type Item = &'a T; + type IntoIter = ValueIter<'a, T>; + + fn into_iter(self) -> ValueIter<'a, T> { + self.map.value_iter(self.index) + } +} + +impl<'a, 'b: 'a, T> IntoIterator for &'b GetAll<'a, T> { + type Item = &'a T; + type IntoIter = ValueIter<'a, T>; + + fn into_iter(self) -> ValueIter<'a, T> { + self.map.value_iter(self.index) + } +} + +// ===== impl ValueIter ===== + +impl<'a, T: 'a> Iterator for ValueIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + use self::Cursor::*; + + + match self.front { + Some(Head) => { + let entry = &self.map.entries[self.index]; + + if self.back == Some(Head) { + self.front = None; + self.back = None; + } else { + // Update the iterator state + match entry.links { + Some(links) => { + self.front = Some(Values(links.next)); + } + None => unreachable!(), + } + } + + Some(&entry.value) + } + Some(Values(idx)) => { + let extra = &self.map.extra_values[idx]; + + if self.front == self.back { + self.front = None; + self.back = None; + } else { + match extra.next { + Link::Entry(_) => self.front = None, + Link::Extra(i) => self.front = Some(Values(i)), + } + } + + Some(&extra.value) + } + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + match (self.front, self.back) { + // Exactly 1 value... + (Some(Cursor::Head), Some(Cursor::Head)) => (1, Some(1)), + // At least 1... + (Some(_), _) => (1, None), + // No more values... + (None, _) => (0, Some(0)), + } + } +} + +impl<'a, T: 'a> DoubleEndedIterator for ValueIter<'a, T> { + fn next_back(&mut self) -> Option { + use self::Cursor::*; + + + match self.back { + Some(Head) => { + self.front = None; + self.back = None; + Some(&self.map.entries[self.index].value) + } + Some(Values(idx)) => { + let extra = &self.map.extra_values[idx]; + + if self.front == self.back { + self.front = None; + self.back = None; + } else { + match extra.prev { + Link::Entry(_) => self.back = Some(Head), + Link::Extra(idx) => self.back = Some(Values(idx)), + } + } + + Some(&extra.value) + } + None => None, + } + } +} + +// ===== impl ValueIterMut ===== + +impl<'a, T: 'a> Iterator for ValueIterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + use self::Cursor::*; + + let entry = unsafe { &mut (*self.map).entries[self.index] }; + + match self.front { + Some(Head) => { + if self.back == Some(Head) { + self.front = None; + self.back = None; + } else { + // Update the iterator state + match entry.links { + Some(links) => { + self.front = Some(Values(links.next)); + } + None => unreachable!(), + } + } + + Some(&mut entry.value) + } + Some(Values(idx)) => { + let extra = unsafe { &mut (*self.map).extra_values[idx] }; + + if self.front == self.back { + self.front = None; + self.back = None; + } else { + match extra.next { + Link::Entry(_) => self.front = None, + Link::Extra(i) => self.front = Some(Values(i)), + } + } + + Some(&mut extra.value) + } + None => None, + } + } +} + +impl<'a, T: 'a> DoubleEndedIterator for ValueIterMut<'a, T> { + fn next_back(&mut self) -> Option { + use self::Cursor::*; + + let entry = unsafe { &mut (*self.map).entries[self.index] }; + + match self.back { + Some(Head) => { + self.front = None; + self.back = None; + Some(&mut entry.value) + } + Some(Values(idx)) => { + let extra = unsafe { &mut (*self.map).extra_values[idx] }; + + if self.front == self.back { + self.front = None; + self.back = None; + } else { + match extra.prev { + Link::Entry(_) => self.back = Some(Head), + Link::Extra(idx) => self.back = Some(Values(idx)), + } + } + + Some(&mut extra.value) + } + None => None, + } + } +} + +unsafe impl<'a, T: Sync> Sync for ValueIterMut<'a, T> {} +unsafe impl<'a, T: Send> Send for ValueIterMut<'a, T> {} + +// ===== impl IntoIter ===== + +impl Iterator for IntoIter { + type Item = (Option, T); + + fn next(&mut self) -> Option { + if let Some(next) = self.next { + self.next = match self.extra_values[next].next { + Link::Entry(_) => None, + Link::Extra(v) => Some(v), + }; + + let value = unsafe { ptr::read(&self.extra_values[next].value) }; + + return Some((None, value)); + } + + if let Some(bucket) = self.entries.next() { + self.next = bucket.links.map(|l| l.next); + let name = Some(bucket.key); + let value = bucket.value; + + return Some((name, value)); + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + let (lower, _) = self.entries.size_hint(); + // There could be more than just the entries upper, as there + // could be items in the `extra_values`. We could guess, saying + // `upper + extra_values.len()`, but that could overestimate by a lot. + (lower, None) + } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + // Ensure the iterator is consumed + for _ in self.by_ref() { } + + // All the values have already been yielded out. + unsafe { self.extra_values.set_len(0); } + } +} + +// ===== impl OccupiedEntry ===== + +impl<'a, T> OccupiedEntry<'a, T> { + /// Returns a reference to the entry's key. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// + /// if let Entry::Occupied(e) = map.entry("host").unwrap() { + /// assert_eq!("host", e.key()); + /// } + /// ``` + pub fn key(&self) -> &HeaderName { + &self.map.entries[self.index].key + } + + /// Get a reference to the first value in the entry. + /// + /// Values are stored in insertion order. + /// + /// # Panics + /// + /// `get` panics if there are no values associated with the entry. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// assert_eq!(e.get(), &"hello.world"); + /// + /// e.append("hello.earth".parse().unwrap()); + /// + /// assert_eq!(e.get(), &"hello.world"); + /// } + /// ``` + pub fn get(&self) -> &T { + &self.map.entries[self.index].value + } + + /// Get a mutable reference to the first value in the entry. + /// + /// Values are stored in insertion order. + /// + /// # Panics + /// + /// `get_mut` panics if there are no values associated with the entry. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::default(); + /// map.insert(HOST, "hello.world".to_string()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// e.get_mut().push_str("-2"); + /// assert_eq!(e.get(), &"hello.world-2"); + /// } + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.map.entries[self.index].value + } + + /// Converts the `OccupiedEntry` into a mutable reference to the **first** + /// value. + /// + /// The lifetime of the returned reference is bound to the original map. + /// + /// # Panics + /// + /// `into_mut` panics if there are no values associated with the entry. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::default(); + /// map.insert(HOST, "hello.world".to_string()); + /// map.append(HOST, "hello.earth".to_string()); + /// + /// if let Entry::Occupied(e) = map.entry("host").unwrap() { + /// e.into_mut().push_str("-2"); + /// } + /// + /// assert_eq!("hello.world-2", map["host"]); + /// ``` + pub fn into_mut(self) -> &'a mut T { + &mut self.map.entries[self.index].value + } + + /// Sets the value of the entry. + /// + /// All previous values associated with the entry are removed and the first + /// one is returned. See `insert_mult` for an API that returns all values. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "hello.world".parse().unwrap()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// let mut prev = e.insert("earth".parse().unwrap()); + /// assert_eq!("hello.world", prev); + /// } + /// + /// assert_eq!("earth", map["host"]); + /// ``` + pub fn insert(&mut self, value: T) -> T { + self.map.insert_occupied(self.index, value.into()) + } + + /// Sets the value of the entry. + /// + /// This function does the same as `insert` except it returns an iterator + /// that yields all values previously associated with the key. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// map.append(HOST, "world2".parse().unwrap()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// let mut prev = e.insert_mult("earth".parse().unwrap()); + /// assert_eq!("world", prev.next().unwrap()); + /// assert_eq!("world2", prev.next().unwrap()); + /// assert!(prev.next().is_none()); + /// } + /// + /// assert_eq!("earth", map["host"]); + /// ``` + pub fn insert_mult(&mut self, value: T) -> ValueDrain { + self.map.insert_occupied_mult(self.index, value.into()) + } + + /// Insert the value into the entry. + /// + /// The new value is appended to the end of the entry's value list. All + /// previous values associated with the entry are retained. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// e.append("earth".parse().unwrap()); + /// } + /// + /// let values = map.get_all("host"); + /// let mut i = values.iter(); + /// assert_eq!("world", *i.next().unwrap()); + /// assert_eq!("earth", *i.next().unwrap()); + /// ``` + pub fn append(&mut self, value: T) { + let idx = self.index; + let entry = &mut self.map.entries[idx]; + append_value(idx, entry, &mut self.map.extra_values, value.into()); + } + + /// Remove the entry from the map. + /// + /// All values associated with the entry are removed and the first one is + /// returned. See `remove_entry_mult` for an API that returns all values. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// + /// if let Entry::Occupied(e) = map.entry("host").unwrap() { + /// let mut prev = e.remove(); + /// assert_eq!("world", prev); + /// } + /// + /// assert!(!map.contains_key("host")); + /// ``` + pub fn remove(self) -> T { + self.remove_entry().1 + } + + /// Remove the entry from the map. + /// + /// The key and all values associated with the entry are removed and the + /// first one is returned. See `remove_entry_mult` for an API that returns + /// all values. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// + /// if let Entry::Occupied(e) = map.entry("host").unwrap() { + /// let (key, mut prev) = e.remove_entry(); + /// assert_eq!("host", key.as_str()); + /// assert_eq!("world", prev); + /// } + /// + /// assert!(!map.contains_key("host")); + /// ``` + pub fn remove_entry(self) -> (HeaderName, T) { + let entry = self.map.remove_found(self.probe, self.index); + + if let Some(links) = entry.links { + self.map.remove_all_extra_values(links.next); + } + + (entry.key, entry.value) + } + + /// Remove the entry from the map. + /// + /// The key and all values associated with the entry are removed and + /// returned. + pub fn remove_entry_mult(self) -> (HeaderName, ValueDrain<'a, T>) { + let entry = self.map.remove_found(self.probe, self.index); + let drain = ValueDrain { + map: self.map as *mut _, + first: Some(entry.value), + next: entry.links.map(|l| l.next), + lt: PhantomData, + }; + (entry.key, drain) + } + + /// Returns an iterator visiting all values associated with the entry. + /// + /// Values are iterated in insertion order. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::new(); + /// map.insert(HOST, "world".parse().unwrap()); + /// map.append(HOST, "earth".parse().unwrap()); + /// + /// if let Entry::Occupied(e) = map.entry("host").unwrap() { + /// let mut iter = e.iter(); + /// assert_eq!(&"world", iter.next().unwrap()); + /// assert_eq!(&"earth", iter.next().unwrap()); + /// assert!(iter.next().is_none()); + /// } + /// ``` + pub fn iter(&self) -> ValueIter { + self.map.value_iter(Some(self.index)) + } + + /// Returns an iterator mutably visiting all values associated with the + /// entry. + /// + /// Values are iterated in insertion order. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderMap, Entry, HOST}; + /// let mut map = HeaderMap::default(); + /// map.insert(HOST, "world".to_string()); + /// map.append(HOST, "earth".to_string()); + /// + /// if let Entry::Occupied(mut e) = map.entry("host").unwrap() { + /// for e in e.iter_mut() { + /// e.push_str("-boop"); + /// } + /// } + /// + /// let mut values = map.get_all("host"); + /// let mut i = values.iter(); + /// assert_eq!(&"world-boop", i.next().unwrap()); + /// assert_eq!(&"earth-boop", i.next().unwrap()); + /// ``` + pub fn iter_mut(&mut self) -> ValueIterMut { + self.map.value_iter_mut(self.index) + } +} + +impl<'a, T> IntoIterator for OccupiedEntry<'a, T> { + type Item = &'a mut T; + type IntoIter = ValueIterMut<'a, T>; + + fn into_iter(self) -> ValueIterMut<'a, T> { + self.map.value_iter_mut(self.index) + } +} + +impl<'a, 'b: 'a, T> IntoIterator for &'b OccupiedEntry<'a, T> { + type Item = &'a T; + type IntoIter = ValueIter<'a, T>; + + fn into_iter(self) -> ValueIter<'a, T> { + self.iter() + } +} + +impl<'a, 'b: 'a, T> IntoIterator for &'b mut OccupiedEntry<'a, T> { + type Item = &'a mut T; + type IntoIter = ValueIterMut<'a, T>; + + fn into_iter(self) -> ValueIterMut<'a, T> { + self.iter_mut() + } +} + +// ===== impl ValueDrain ===== + +impl<'a, T> Iterator for ValueDrain<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if self.first.is_some() { + self.first.take() + } else if let Some(next) = self.next { + // Remove the extra value + let extra = unsafe { &mut (*self.map) }.remove_extra_value(next); + + match extra.next { + Link::Extra(idx) => self.next = Some(idx), + Link::Entry(_) => self.next = None, + } + + Some(extra.value) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + match (&self.first, self.next) { + // Exactly 1 + (&Some(_), None) => (1, Some(1)), + // At least 1 + (&_, Some(_)) => (1, None), + // No more + (&None, None) => (0, Some(0)), + } + } +} + +impl<'a, T> Drop for ValueDrain<'a, T> { + fn drop(&mut self) { + while let Some(_) = self.next() { + } + } +} + +unsafe impl<'a, T: Sync> Sync for ValueDrain<'a, T> {} +unsafe impl<'a, T: Send> Send for ValueDrain<'a, T> {} + +// ===== impl Pos ===== + +impl Pos { + #[inline] + fn new(index: usize, hash: HashValue) -> Self { + Pos { + index: index as Size, + hash: hash, + } + } + + #[inline] + fn none() -> Self { + Pos { + index: !0, + hash: HashValue(0), + } + } + + #[inline] + fn is_some(&self) -> bool { + !self.is_none() + } + + #[inline] + fn is_none(&self) -> bool { + self.index == !0 + } + + #[inline] + fn resolve(&self) -> Option<(usize, HashValue)> { + if self.is_some() { + Some((self.index, self.hash)) + } else { + None + } + } +} + +impl Danger { + fn is_red(&self) -> bool { + match *self { + Danger::Red(_) => true, + _ => false, + } + } + + fn to_red(&mut self) { + debug_assert!(self.is_yellow()); + *self = Danger::Red(RandomState::new()); + } + + fn is_yellow(&self) -> bool { + match *self { + Danger::Yellow => true, + _ => false, + } + } + + fn to_yellow(&mut self) { + match *self { + Danger::Green => { + *self = Danger::Yellow; + } + _ => {} + } + } + + fn to_green(&mut self) { + debug_assert!(self.is_yellow()); + *self = Danger::Green; + } +} + +// ===== impl Utils ===== + +#[inline] +fn usable_capacity(cap: usize) -> usize { + cap - cap / 4 +} + +#[inline] +fn to_raw_capacity(n: usize) -> usize { + n + n / 3 +} + +#[inline] +fn desired_pos(mask: Size, hash: HashValue) -> usize { + (hash.0 & mask) +} + +/// The number of steps that `current` is forward of the desired position for hash +#[inline] +fn probe_distance(mask: Size, hash: HashValue, current: usize) -> usize { + current.wrapping_sub(desired_pos(mask, hash)) & mask +} + +fn hash_elem_using(danger: &Danger, k: &K) -> HashValue + where K: Hash +{ + use fnv::FnvHasher; + + const MASK: u64 = (MAX_SIZE as u64) - 1; + + let hash = match *danger { + // Safe hash + Danger::Red(ref hasher) => { + let mut h = hasher.build_hasher(); + k.hash(&mut h); + h.finish() + } + // Fast hash + _ => { + let mut h = FnvHasher::default(); + k.hash(&mut h); + h.finish() + } + }; + + HashValue((hash & MASK) as usize) +} + +/* + * + * ===== impl IntoHeaderName / AsHeaderName ===== + * + */ + + +mod into_header_name { + use super::{HdrName, HeaderMap, HeaderName}; + + /// A marker trait used to identify values that can be used as insert keys + /// to a `HeaderMap`. + pub trait IntoHeaderName: Sealed {} + + // All methods are on this pub(super) trait, instead of `IntoHeaderName`, + // so that they aren't publicly exposed to the world. + // + // Being on the `IntoHeaderName` trait would mean users could call + // `"host".insert(&mut map, "localhost")`. + // + // Ultimately, this allows us to adjust the signatures of these methods + // without breaking any external crate. + pub trait Sealed { + #[doc(hidden)] + fn insert(self, map: &mut HeaderMap, val: T) -> Option; + + #[doc(hidden)] + fn append(self, map: &mut HeaderMap, val: T) -> bool; + } + + // ==== impls ==== + + impl Sealed for HeaderName { + #[doc(hidden)] + #[inline] + fn insert(self, map: &mut HeaderMap, val: T) -> Option { + map.insert2(self, val) + } + + #[doc(hidden)] + #[inline] + fn append(self, map: &mut HeaderMap, val: T) -> bool { + map.append2(self, val) + } + } + + impl IntoHeaderName for HeaderName {} + + impl<'a> Sealed for &'a HeaderName { + #[doc(hidden)] + #[inline] + fn insert(self, map: &mut HeaderMap, val: T) -> Option { + map.insert2(self, val) + } + #[doc(hidden)] + #[inline] + fn append(self, map: &mut HeaderMap, val: T) -> bool { + map.append2(self, val) + } + } + + impl<'a> IntoHeaderName for &'a HeaderName {} + + impl Sealed for &'static str { + #[doc(hidden)] + #[inline] + fn insert(self, map: &mut HeaderMap, val: T) -> Option { + HdrName::from_static(self, move |hdr| map.insert2(hdr, val)) + } + #[doc(hidden)] + #[inline] + fn append(self, map: &mut HeaderMap, val: T) -> bool { + HdrName::from_static(self, move |hdr| map.append2(hdr, val)) + } + } + + impl IntoHeaderName for &'static str {} +} + +mod as_header_name { + use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName}; + + /// A marker trait used to identify values that can be used as search keys + /// to a `HeaderMap`. + pub trait AsHeaderName: Sealed {} + + // All methods are on this pub(super) trait, instead of `AsHeaderName`, + // so that they aren't publicly exposed to the world. + // + // Being on the `AsHeaderName` trait would mean users could call + // `"host".find(&map)`. + // + // Ultimately, this allows us to adjust the signatures of these methods + // without breaking any external crate. + pub trait Sealed { + #[doc(hidden)] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName>; + + #[doc(hidden)] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)>; + + #[doc(hidden)] + fn as_str(&self) -> &str; + } + + // ==== impls ==== + + impl Sealed for HeaderName { + #[doc(hidden)] + #[inline] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName> { + Ok(map.entry2(self)) + } + + #[doc(hidden)] + #[inline] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)> { + map.find(self) + } + + #[doc(hidden)] + fn as_str(&self) -> &str { + ::as_str(self) + } + } + + impl AsHeaderName for HeaderName {} + + impl<'a> Sealed for &'a HeaderName { + #[doc(hidden)] + #[inline] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName> { + Ok(map.entry2(self)) + } + + #[doc(hidden)] + #[inline] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)> { + map.find(*self) + } + + #[doc(hidden)] + fn as_str(&self) -> &str { + ::as_str(*self) + } + } + + impl<'a> AsHeaderName for &'a HeaderName {} + + impl<'a> Sealed for &'a str { + #[doc(hidden)] + #[inline] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName> { + HdrName::from_bytes(self.as_bytes(), move |hdr| map.entry2(hdr)) + } + + #[doc(hidden)] + #[inline] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)> { + HdrName::from_bytes(self.as_bytes(), move |hdr| map.find(&hdr)).unwrap_or(None) + } + + #[doc(hidden)] + fn as_str(&self) -> &str { + self + } + } + + impl<'a> AsHeaderName for &'a str {} + + impl Sealed for String { + #[doc(hidden)] + #[inline] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName> { + self.as_str().entry(map) + } + + #[doc(hidden)] + #[inline] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)> { + Sealed::find(&self.as_str(), map) + } + + #[doc(hidden)] + fn as_str(&self) -> &str { + self + } + } + + impl AsHeaderName for String {} + + impl<'a> Sealed for &'a String { + #[doc(hidden)] + #[inline] + fn entry(self, map: &mut HeaderMap) -> Result, InvalidHeaderName> { + self.as_str().entry(map) + } + + #[doc(hidden)] + #[inline] + fn find(&self, map: &HeaderMap) -> Option<(usize, usize)> { + Sealed::find(*self, map) + } + + #[doc(hidden)] + fn as_str(&self) -> &str { + *self + } + } + + impl<'a> AsHeaderName for &'a String {} +} + + +#[test] +fn test_bounds() { + fn check_bounds() {} + + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); + check_bounds::>(); +} + +#[test] +fn skip_duplicates_during_key_iteration() { + let mut map = HeaderMap::new(); + map.append("a", HeaderValue::from_static("a")); + map.append("a", HeaderValue::from_static("b")); + assert_eq!(map.keys().count(), map.keys_len()); +} diff --git a/http/src/header/mod.rs b/http/src/header/mod.rs new file mode 100644 index 000000000..2b8582146 --- /dev/null +++ b/http/src/header/mod.rs @@ -0,0 +1,196 @@ +//! HTTP header types +//! +//! The module provides [`HeaderName`], [`HeaderMap`], and a number of types +//! used for interacting with `HeaderMap`. These types allow representing both +//! HTTP/1 and HTTP/2 headers. +//! +//! # `HeaderName` +//! +//! The `HeaderName` type represents both standard header names as well as +//! custom header names. The type handles the case insensitive nature of header +//! names and is used as the key portion of `HeaderMap`. Header names are +//! normalized to lower case. In other words, when creating a `HeaderName` with +//! a string, even if upper case characters are included, when getting a string +//! representation of the `HeaderName`, it will be all lower case. This allows +//! for faster `HeaderMap` comparison operations. +//! +//! The internal representation is optimized to efficiently handle the cases +//! most commonly encountered when working with HTTP. Standard header names are +//! special cased and are represented internally as an enum. Short custom +//! headers will be stored directly in the `HeaderName` struct and will not +//! incur any allocation overhead, however longer strings will require an +//! allocation for storage. +//! +//! ## Limitations +//! +//! `HeaderName` has a max length of 32,768 for header names. Attempting to +//! parse longer names will result in a panic. +//! +//! # `HeaderMap` +//! +//! `HeaderMap` is a map structure of header names highly optimized for use +//! cases common with HTTP. It is a [multimap] structure, where each header name +//! may have multiple associated header values. Given this, some of the APIs +//! diverge from [`HashMap`]. +//! +//! ## Overview +//! +//! Just like `HashMap` in Rust's stdlib, `HeaderMap` is based on [Robin Hood +//! hashing]. This algorithm tends to reduce the worst case search times in the +//! table and enables high load factors without seriously affecting performance. +//! Internally, keys and values are stored in vectors. As such, each insertion +//! will not incur allocation overhead. However, once the underlying vector +//! storage is full, a larger vector must be allocated and all values copied. +//! +//! ## Deterministic ordering +//! +//! Unlike Rust's `HashMap`, values in `HeaderMap` are deterministically +//! ordered. Roughly, values are ordered by insertion. This means that a +//! function that deterministically operates on a header map can rely on the +//! iteration order to remain consistent across processes and platforms. +//! +//! ## Adaptive hashing +//! +//! `HeaderMap` uses an adaptive hashing strategy in order to efficiently handle +//! most common cases. All standard headers have statically computed hash values +//! which removes the need to perform any hashing of these headers at runtime. +//! The default hash function emphasizes performance over robustness. However, +//! `HeaderMap` detects high collision rates and switches to a secure hash +//! function in those events. The threshold is set such that only denial of +//! service attacks should trigger it. +//! +//! ## Limitations +//! +//! `HeaderMap` can store a maximum of 32,768 headers (header name / value +//! pairs). Attempting to insert more will result in a panic. +//! +//! [`HeaderName`]: struct.HeaderName.html +//! [`HeaderMap`]: struct.HeaderMap.html +//! [multimap]: https://en.wikipedia.org/wiki/Multimap +//! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html +//! [Robin Hood hashing]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing + +mod map; +mod name; +mod value; + +pub use self::map::{ + HeaderMap, + AsHeaderName, + IntoHeaderName, + Iter, + IterMut, + Keys, + Values, + ValuesMut, + Drain, + GetAll, + Entry, + VacantEntry, + OccupiedEntry, + ValueIter, + ValueIterMut, + ValueDrain, + IntoIter, +}; +pub use self::name::{ + HeaderName, + InvalidHeaderName, + InvalidHeaderNameBytes, +}; +pub use self::value::{ + HeaderValue, + InvalidHeaderValue, + InvalidHeaderValueBytes, + ToStrError, +}; + +// Use header name constants +pub use self::name::{ + ACCEPT, + ACCEPT_CHARSET, + ACCEPT_ENCODING, + ACCEPT_LANGUAGE, + ACCEPT_RANGES, + ACCESS_CONTROL_ALLOW_CREDENTIALS, + ACCESS_CONTROL_ALLOW_HEADERS, + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_ORIGIN, + ACCESS_CONTROL_EXPOSE_HEADERS, + ACCESS_CONTROL_MAX_AGE, + ACCESS_CONTROL_REQUEST_HEADERS, + ACCESS_CONTROL_REQUEST_METHOD, + AGE, + ALLOW, + ALT_SVC, + AUTHORIZATION, + CACHE_CONTROL, + CONNECTION, + CONTENT_DISPOSITION, + CONTENT_ENCODING, + CONTENT_LANGUAGE, + CONTENT_LENGTH, + CONTENT_LOCATION, + CONTENT_RANGE, + CONTENT_SECURITY_POLICY, + CONTENT_SECURITY_POLICY_REPORT_ONLY, + CONTENT_TYPE, + COOKIE, + DNT, + DATE, + ETAG, + EXPECT, + EXPIRES, + FORWARDED, + FROM, + HOST, + IF_MATCH, + IF_MODIFIED_SINCE, + IF_NONE_MATCH, + IF_RANGE, + IF_UNMODIFIED_SINCE, + LAST_MODIFIED, + LINK, + LOCATION, + MAX_FORWARDS, + ORIGIN, + PRAGMA, + PROXY_AUTHENTICATE, + PROXY_AUTHORIZATION, + PUBLIC_KEY_PINS, + PUBLIC_KEY_PINS_REPORT_ONLY, + RANGE, + REFERER, + REFERRER_POLICY, + REFRESH, + RETRY_AFTER, + SEC_WEBSOCKET_ACCEPT, + SEC_WEBSOCKET_EXTENSIONS, + SEC_WEBSOCKET_KEY, + SEC_WEBSOCKET_PROTOCOL, + SEC_WEBSOCKET_VERSION, + SERVER, + SET_COOKIE, + STRICT_TRANSPORT_SECURITY, + TE, + TRAILER, + TRANSFER_ENCODING, + UPGRADE, + UPGRADE_INSECURE_REQUESTS, + USER_AGENT, + VARY, + VIA, + WARNING, + WWW_AUTHENTICATE, + X_CONTENT_TYPE_OPTIONS, + X_DNS_PREFETCH_CONTROL, + X_FRAME_OPTIONS, + X_XSS_PROTECTION, +}; + +/// Maximum length of a header name +/// +/// Generally, 64kb for a header name is WAY too much than would ever be needed +/// in practice. Restricting it to this size enables using `u16` values to +/// represent offsets when dealing with header names. +const MAX_HEADER_NAME_LEN: usize = 1 << 16; diff --git a/http/src/header/name.rs b/http/src/header/name.rs new file mode 100644 index 000000000..28b1469e8 --- /dev/null +++ b/http/src/header/name.rs @@ -0,0 +1,2206 @@ +use HttpTryFrom; +use byte_str::ByteStr; +use bytes::{Bytes, BytesMut}; + +use std::{fmt, mem}; +use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; +use std::error::Error; + +/// Represents an HTTP header field name +/// +/// Header field names identify the header. Header sets may include multiple +/// headers with the same name. The HTTP specification defines a number of +/// standard headers, but HTTP messages may include non-standard header names as +/// well as long as they adhere to the specification. +/// +/// `HeaderName` is used as the [`HeaderMap`] key. Constants are available for +/// all standard header names in the [`header`] module. +/// +/// # Representation +/// +/// `HeaderName` represents standard header names using an `enum`, as such they +/// will not require an allocation for storage. All custom header names are +/// lower cased upon conversion to a `HeaderName` value. This avoids the +/// overhead of dynamically doing lower case conversion during the hash code +/// computation and the comparison operation. +/// +/// [`HeaderMap`]: struct.HeaderMap.html +/// [`header`]: index.html +#[derive(Clone, Eq, PartialEq, Hash)] +pub struct HeaderName { + inner: Repr, +} + +// Almost a full `HeaderName` +#[derive(Debug, Hash)] +pub struct HdrName<'a> { + inner: Repr>, +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +enum Repr { + Standard(StandardHeader), + Custom(T), +} + +// Used to hijack the Hash impl +#[derive(Debug, Clone, Eq, PartialEq)] +struct Custom(ByteStr); + +#[derive(Debug, Clone)] +struct MaybeLower<'a> { + buf: &'a [u8], + lower: bool, +} + +/// A possible error when converting a `HeaderName` from another type. +#[derive(Debug)] +pub struct InvalidHeaderName { + _priv: (), +} + +/// A possible error when converting a `HeaderName` from another type. +#[derive(Debug)] +pub struct InvalidHeaderNameBytes(InvalidHeaderName) ; + +macro_rules! standard_headers { + ( + $( + $(#[$docs:meta])* + ($konst:ident, $upcase:ident, $name:expr); + )+ + ) => { + #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] + enum StandardHeader { + $( + $konst, + )+ + } + + $( + $(#[$docs])* + pub const $upcase: HeaderName = HeaderName { + inner: Repr::Standard(StandardHeader::$konst), + }; + )+ + + impl StandardHeader { + #[inline] + fn as_str(&self) -> &'static str { + match *self { + $( + StandardHeader::$konst => $name, + )+ + } + } + } + + #[cfg(test)] + const TEST_HEADERS: &'static [(StandardHeader, &'static str)] = &[ + $( + (StandardHeader::$konst, $name), + )+ + ]; + + #[test] + fn test_parse_standard_headers() { + for &(std, name) in TEST_HEADERS { + // Test lower case + assert_eq!(HeaderName::from_bytes(name.as_bytes()).unwrap(), HeaderName::from(std)); + + // Test upper case + let upper = name.to_uppercase().to_string(); + assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std)); + } + } + + #[test] + fn test_standard_headers_into_bytes() { + for &(std, name) in TEST_HEADERS { + let std = HeaderName::from(std); + // Test lower case + let name_bytes = name.as_bytes(); + let bytes: Bytes = + HeaderName::from_bytes(name_bytes).unwrap().into(); + assert_eq!(bytes, name_bytes); + assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), std); + + // Test upper case + let upper = name.to_uppercase().to_string(); + let bytes: Bytes = + HeaderName::from_bytes(upper.as_bytes()).unwrap().into(); + assert_eq!(bytes, name.as_bytes()); + assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), + std); + + + } + + } + } +} + +// Generate constants for all standard HTTP headers. This includes a static hash +// code for the "fast hash" path. The hash code for static headers *do not* have +// to match the text representation of those headers. This is because header +// strings are always converted to the static values (when they match) before +// being hashed. This means that it is impossible to compare the static hash +// code of CONTENT_LENGTH with "content-length". +standard_headers! { + /// Advertises which content types the client is able to understand. + /// + /// The Accept request HTTP header advertises which content types, expressed + /// as MIME types, the client is able to understand. Using content + /// negotiation, the server then selects one of the proposals, uses it and + /// informs the client of its choice with the Content-Type response header. + /// Browsers set adequate values for this header depending of the context + /// where the request is done: when fetching a CSS stylesheet a different + /// value is set for the request than when fetching an image, video or a + /// script. + (Accept, ACCEPT, "accept"); + + /// Advertises which character set the client is able to understand. + /// + /// The Accept-Charset request HTTP header advertises which character set + /// the client is able to understand. Using content negotiation, the server + /// then selects one of the proposals, uses it and informs the client of its + /// choice within the Content-Type response header. Browsers usually don't + /// set this header as the default value for each content type is usually + /// correct and transmitting it would allow easier fingerprinting. + /// + /// If the server cannot serve any matching character set, it can + /// theoretically send back a 406 (Not Acceptable) error code. But, for a + /// better user experience, this is rarely done and the more common way is + /// to ignore the Accept-Charset header in this case. + (AcceptCharset, ACCEPT_CHARSET, "accept-charset"); + + /// Advertises which content encoding the client is able to understand. + /// + /// The Accept-Encoding request HTTP header advertises which content + /// encoding, usually a compression algorithm, the client is able to + /// understand. Using content negotiation, the server selects one of the + /// proposals, uses it and informs the client of its choice with the + /// Content-Encoding response header. + /// + /// Even if both the client and the server supports the same compression + /// algorithms, the server may choose not to compress the body of a + /// response, if the identity value is also acceptable. Two common cases + /// lead to this: + /// + /// * The data to be sent is already compressed and a second compression + /// won't lead to smaller data to be transmitted. This may the case with + /// some image formats; + /// + /// * The server is overloaded and cannot afford the computational overhead + /// induced by the compression requirement. Typically, Microsoft recommends + /// not to compress if a server use more than 80 % of its computational + /// power. + /// + /// As long as the identity value, meaning no encryption, is not explicitly + /// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set + /// value for identity, the server must never send back a 406 Not Acceptable + /// error. + (AcceptEncoding, ACCEPT_ENCODING, "accept-encoding"); + + /// Advertises which languages the client is able to understand. + /// + /// The Accept-Language request HTTP header advertises which languages the + /// client is able to understand, and which locale variant is preferred. + /// Using content negotiation, the server then selects one of the proposals, + /// uses it and informs the client of its choice with the Content-Language + /// response header. Browsers set adequate values for this header according + /// their user interface language and even if a user can change it, this + /// happens rarely (and is frown upon as it leads to fingerprinting). + /// + /// This header is a hint to be used when the server has no way of + /// determining the language via another way, like a specific URL, that is + /// controlled by an explicit user decision. It is recommended that the + /// server never overrides an explicit decision. The content of the + /// Accept-Language is often out of the control of the user (like when + /// traveling and using an Internet Cafe in a different country); the user + /// may also want to visit a page in another language than the locale of + /// their user interface. + /// + /// If the server cannot serve any matching language, it can theoretically + /// send back a 406 (Not Acceptable) error code. But, for a better user + /// experience, this is rarely done and more common way is to ignore the + /// Accept-Language header in this case. + (AcceptLanguage, ACCEPT_LANGUAGE, "accept-language"); + + /// Marker used by the server to advertise partial request support. + /// + /// The Accept-Ranges response HTTP header is a marker used by the server to + /// advertise its support of partial requests. The value of this field + /// indicates the unit that can be used to define a range. + /// + /// In presence of an Accept-Ranges header, the browser may try to resume an + /// interrupted download, rather than to start it from the start again. + (AcceptRanges, ACCEPT_RANGES, "accept-ranges"); + + /// Preflight response indicating if the response to the request can be + /// exposed to the page. + /// + /// The Access-Control-Allow-Credentials response header indicates whether + /// or not the response to the request can be exposed to the page. It can be + /// exposed when the true value is returned; it can't in other cases. + /// + /// Credentials are cookies, authorization headers or TLS client + /// certificates. + /// + /// When used as part of a response to a preflight request, this indicates + /// whether or not the actual request can be made using credentials. Note + /// that simple GET requests are not preflighted, and so if a request is + /// made for a resource with credentials, if this header is not returned + /// with the resource, the response is ignored by the browser and not + /// returned to web content. + /// + /// The Access-Control-Allow-Credentials header works in conjunction with + /// the XMLHttpRequest.withCredentials property or with the credentials + /// option in the Request() constructor of the Fetch API. Credentials must + /// be set on both sides (the Access-Control-Allow-Credentials header and in + /// the XHR or Fetch request) in order for the CORS request with credentials + /// to succeed. + (AccessControlAllowCredentials, ACCESS_CONTROL_ALLOW_CREDENTIALS, "access-control-allow-credentials"); + + /// Preflight response indicating permitted HTTP headers. + /// + /// The Access-Control-Allow-Headers response header is used in response to + /// a preflight request to indicate which HTTP headers will be available via + /// Access-Control-Expose-Headers when making the actual request. + /// + /// The simple headers, Accept, Accept-Language, Content-Language, + /// Content-Type (but only with a MIME type of its parsed value (ignoring + /// parameters) of either application/x-www-form-urlencoded, + /// multipart/form-data, or text/plain), are always available and don't need + /// to be listed by this header. + /// + /// This header is required if the request has an + /// Access-Control-Request-Headers header. + (AccessControlAllowHeaders, ACCESS_CONTROL_ALLOW_HEADERS, "access-control-allow-headers"); + + /// Preflight header response indicating permitted access methods. + /// + /// The Access-Control-Allow-Methods response header specifies the method or + /// methods allowed when accessing the resource in response to a preflight + /// request. + (AccessControlAllowMethods, ACCESS_CONTROL_ALLOW_METHODS, "access-control-allow-methods"); + + /// Indicates whether the response can be shared with resources with the + /// given origin. + (AccessControlAllowOrigin, ACCESS_CONTROL_ALLOW_ORIGIN, "access-control-allow-origin"); + + /// Indicates which headers can be exposed as part of the response by + /// listing their names. + (AccessControlExposeHeaders, ACCESS_CONTROL_EXPOSE_HEADERS, "access-control-expose-headers"); + + /// Indicates how long the results of a preflight request can be cached. + (AccessControlMaxAge, ACCESS_CONTROL_MAX_AGE, "access-control-max-age"); + + /// Informs the server which HTTP headers will be used when an actual + /// request is made. + (AccessControlRequestHeaders, ACCESS_CONTROL_REQUEST_HEADERS, "access-control-request-headers"); + + /// Informs the server know which HTTP method will be used when the actual + /// request is made. + (AccessControlRequestMethod, ACCESS_CONTROL_REQUEST_METHOD, "access-control-request-method"); + + /// Indicates the time in seconds the object has been in a proxy cache. + /// + /// The Age header is usually close to zero. If it is Age: 0, it was + /// probably just fetched from the origin server; otherwise It is usually + /// calculated as a difference between the proxy's current date and the Date + /// general header included in the HTTP response. + (Age, AGE, "age"); + + /// Lists the set of methods support by a resource. + /// + /// This header must be sent if the server responds with a 405 Method Not + /// Allowed status code to indicate which request methods can be used. An + /// empty Allow header indicates that the resource allows no request + /// methods, which might occur temporarily for a given resource, for + /// example. + (Allow, ALLOW, "allow"); + + /// Advertises the availability of alternate services to clients. + (AltSvc, ALT_SVC, "alt-svc"); + + /// Contains the credentials to authenticate a user agent with a server. + /// + /// Usually this header is included after the server has responded with a + /// 401 Unauthorized status and the WWW-Authenticate header. + (Authorization, AUTHORIZATION, "authorization"); + + /// Specifies directives for caching mechanisms in both requests and + /// responses. + /// + /// Caching directives are unidirectional, meaning that a given directive in + /// a request is not implying that the same directive is to be given in the + /// response. + (CacheControl, CACHE_CONTROL, "cache-control"); + + /// Controls whether or not the network connection stays open after the + /// current transaction finishes. + /// + /// If the value sent is keep-alive, the connection is persistent and not + /// closed, allowing for subsequent requests to the same server to be done. + /// + /// Except for the standard hop-by-hop headers (Keep-Alive, + /// Transfer-Encoding, TE, Connection, Trailer, Upgrade, Proxy-Authorization + /// and Proxy-Authenticate), any hop-by-hop headers used by the message must + /// be listed in the Connection header, so that the first proxy knows he has + /// to consume them and not to forward them further. Standard hop-by-hop + /// headers can be listed too (it is often the case of Keep-Alive, but this + /// is not mandatory. + (Connection, CONNECTION, "connection"); + + /// Indicates if the content is expected to be displayed inline. + /// + /// In a regular HTTP response, the Content-Disposition response header is a + /// header indicating if the content is expected to be displayed inline in + /// the browser, that is, as a Web page or as part of a Web page, or as an + /// attachment, that is downloaded and saved locally. + /// + /// In a multipart/form-data body, the HTTP Content-Disposition general + /// header is a header that can be used on the subpart of a multipart body + /// to give information about the field it applies to. The subpart is + /// delimited by the boundary defined in the Content-Type header. Used on + /// the body itself, Content-Disposition has no effect. + /// + /// The Content-Disposition header is defined in the larger context of MIME + /// messages for e-mail, but only a subset of the possible parameters apply + /// to HTTP forms and POST requests. Only the value form-data, as well as + /// the optional directive name and filename, can be used in the HTTP + /// context. + (ContentDisposition, CONTENT_DISPOSITION, "content-disposition"); + + /// Used to compress the media-type. + /// + /// When present, its value indicates what additional content encoding has + /// been applied to the entity-body. It lets the client know, how to decode + /// in order to obtain the media-type referenced by the Content-Type header. + /// + /// It is recommended to compress data as much as possible and therefore to + /// use this field, but some types of resources, like jpeg images, are + /// already compressed. Sometimes using additional compression doesn't + /// reduce payload size and can even make the payload longer. + (ContentEncoding, CONTENT_ENCODING, "content-encoding"); + + /// Used to describe the languages intended for the audience. + /// + /// This header allows a user to differentiate according to the users' own + /// preferred language. For example, if "Content-Language: de-DE" is set, it + /// says that the document is intended for German language speakers + /// (however, it doesn't indicate the document is written in German. For + /// example, it might be written in English as part of a language course for + /// German speakers). + /// + /// If no Content-Language is specified, the default is that the content is + /// intended for all language audiences. Multiple language tags are also + /// possible, as well as applying the Content-Language header to various + /// media types and not only to textual documents. + (ContentLanguage, CONTENT_LANGUAGE, "content-language"); + + /// Indicates the size fo the entity-body. + /// + /// The header value must be a decimal indicating the number of octets sent + /// to the recipient. + (ContentLength, CONTENT_LENGTH, "content-length"); + + /// Indicates an alternate location for the returned data. + /// + /// The principal use case is to indicate the URL of the resource + /// transmitted as the result of content negotiation. + /// + /// Location and Content-Location are different: Location indicates the + /// target of a redirection (or the URL of a newly created document), while + /// Content-Location indicates the direct URL to use to access the resource, + /// without the need of further content negotiation. Location is a header + /// associated with the response, while Content-Location is associated with + /// the entity returned. + (ContentLocation, CONTENT_LOCATION, "content-location"); + + /// Indicates where in a full body message a partial message belongs. + (ContentRange, CONTENT_RANGE, "content-range"); + + /// Allows controlling resources the user agent is allowed to load for a + /// given page. + /// + /// With a few exceptions, policies mostly involve specifying server origins + /// and script endpoints. This helps guard against cross-site scripting + /// attacks (XSS). + (ContentSecurityPolicy, CONTENT_SECURITY_POLICY, "content-security-policy"); + + /// Allows experimenting with policies by monitoring their effects. + /// + /// The HTTP Content-Security-Policy-Report-Only response header allows web + /// developers to experiment with policies by monitoring (but not enforcing) + /// their effects. These violation reports consist of JSON documents sent + /// via an HTTP POST request to the specified URI. + (ContentSecurityPolicyReportOnly, CONTENT_SECURITY_POLICY_REPORT_ONLY, "content-security-policy-report-only"); + + /// Used to indicate the media type of the resource. + /// + /// In responses, a Content-Type header tells the client what the content + /// type of the returned content actually is. Browsers will do MIME sniffing + /// in some cases and will not necessarily follow the value of this header; + /// to prevent this behavior, the header X-Content-Type-Options can be set + /// to nosniff. + /// + /// In requests, (such as POST or PUT), the client tells the server what + /// type of data is actually sent. + (ContentType, CONTENT_TYPE, "content-type"); + + /// Contains stored HTTP cookies previously sent by the server with the + /// Set-Cookie header. + /// + /// The Cookie header might be omitted entirely, if the privacy setting of + /// the browser are set to block them, for example. + (Cookie, COOKIE, "cookie"); + + /// Indicates the client's tracking preference. + /// + /// This header lets users indicate whether they would prefer privacy rather + /// than personalized content. + (Dnt, DNT, "dnt"); + + /// Contains the date and time at which the message was originated. + (Date, DATE, "date"); + + /// Identifier for a specific version of a resource. + /// + /// This header allows caches to be more efficient, and saves bandwidth, as + /// a web server does not need to send a full response if the content has + /// not changed. On the other side, if the content has changed, etags are + /// useful to help prevent simultaneous updates of a resource from + /// overwriting each other ("mid-air collisions"). + /// + /// If the resource at a given URL changes, a new Etag value must be + /// generated. Etags are therefore similar to fingerprints and might also be + /// used for tracking purposes by some servers. A comparison of them allows + /// to quickly determine whether two representations of a resource are the + /// same, but they might also be set to persist indefinitely by a tracking + /// server. + (Etag, ETAG, "etag"); + + /// Indicates expectations that need to be fulfilled by the server in order + /// to properly handle the request. + /// + /// The only expectation defined in the specification is Expect: + /// 100-continue, to which the server shall respond with: + /// + /// * 100 if the information contained in the header is sufficient to cause + /// an immediate success, + /// + /// * 417 (Expectation Failed) if it cannot meet the expectation; or any + /// other 4xx status otherwise. + /// + /// For example, the server may reject a request if its Content-Length is + /// too large. + /// + /// No common browsers send the Expect header, but some other clients such + /// as cURL do so by default. + (Expect, EXPECT, "expect"); + + /// Contains the date/time after which the response is considered stale. + /// + /// Invalid dates, like the value 0, represent a date in the past and mean + /// that the resource is already expired. + /// + /// If there is a Cache-Control header with the "max-age" or "s-max-age" + /// directive in the response, the Expires header is ignored. + (Expires, EXPIRES, "expires"); + + /// Contains information from the client-facing side of proxy servers that + /// is altered or lost when a proxy is involved in the path of the request. + /// + /// The alternative and de-facto standard versions of this header are the + /// X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto headers. + /// + /// This header is used for debugging, statistics, and generating + /// location-dependent content and by design it exposes privacy sensitive + /// information, such as the IP address of the client. Therefore the user's + /// privacy must be kept in mind when deploying this header. + (Forwarded, FORWARDED, "forwarded"); + + /// Contains an Internet email address for a human user who controls the + /// requesting user agent. + /// + /// If you are running a robotic user agent (e.g. a crawler), the From + /// header should be sent, so you can be contacted if problems occur on + /// servers, such as if the robot is sending excessive, unwanted, or invalid + /// requests. + (From, FROM, "from"); + + /// Specifies the domain name of the server and (optionally) the TCP port + /// number on which the server is listening. + /// + /// If no port is given, the default port for the service requested (e.g., + /// "80" for an HTTP URL) is implied. + /// + /// A Host header field must be sent in all HTTP/1.1 request messages. A 400 + /// (Bad Request) status code will be sent to any HTTP/1.1 request message + /// that lacks a Host header field or contains more than one. + (Host, HOST, "host"); + + /// Makes a request conditional based on the E-Tag. + /// + /// For GET and HEAD methods, the server will send back the requested + /// resource only if it matches one of the listed ETags. For PUT and other + /// non-safe methods, it will only upload the resource in this case. + /// + /// The comparison with the stored ETag uses the strong comparison + /// algorithm, meaning two files are considered identical byte to byte only. + /// This is weakened when the W/ prefix is used in front of the ETag. + /// + /// There are two common use cases: + /// + /// * For GET and HEAD methods, used in combination with an Range header, it + /// can guarantee that the new ranges requested comes from the same resource + /// than the previous one. If it doesn't match, then a 416 (Range Not + /// Satisfiable) response is returned. + /// + /// * For other methods, and in particular for PUT, If-Match can be used to + /// prevent the lost update problem. It can check if the modification of a + /// resource that the user wants to upload will not override another change + /// that has been done since the original resource was fetched. If the + /// request cannot be fulfilled, the 412 (Precondition Failed) response is + /// returned. + (IfMatch, IF_MATCH, "if-match"); + + /// Makes a request conditional based on the modification date. + /// + /// The If-Modified-Since request HTTP header makes the request conditional: + /// the server will send back the requested resource, with a 200 status, + /// only if it has been last modified after the given date. If the request + /// has not been modified since, the response will be a 304 without any + /// body; the Last-Modified header will contain the date of last + /// modification. Unlike If-Unmodified-Since, If-Modified-Since can only be + /// used with a GET or HEAD. + /// + /// When used in combination with If-None-Match, it is ignored, unless the + /// server doesn't support If-None-Match. + /// + /// The most common use case is to update a cached entity that has no + /// associated ETag. + (IfModifiedSince, IF_MODIFIED_SINCE, "if-modified-since"); + + /// Makes a request conditional based on the E-Tag. + /// + /// The If-None-Match HTTP request header makes the request conditional. For + /// GET and HEAD methods, the server will send back the requested resource, + /// with a 200 status, only if it doesn't have an ETag matching the given + /// ones. For other methods, the request will be processed only if the + /// eventually existing resource's ETag doesn't match any of the values + /// listed. + /// + /// When the condition fails for GET and HEAD methods, then the server must + /// return HTTP status code 304 (Not Modified). For methods that apply + /// server-side changes, the status code 412 (Precondition Failed) is used. + /// Note that the server generating a 304 response MUST generate any of the + /// following header fields that would have been sent in a 200 (OK) response + /// to the same request: Cache-Control, Content-Location, Date, ETag, + /// Expires, and Vary. + /// + /// The comparison with the stored ETag uses the weak comparison algorithm, + /// meaning two files are considered identical not only if they are + /// identical byte to byte, but if the content is equivalent. For example, + /// two pages that would differ only by the date of generation in the footer + /// would be considered as identical. + /// + /// When used in combination with If-Modified-Since, it has precedence (if + /// the server supports it). + /// + /// There are two common use cases: + /// + /// * For `GET` and `HEAD` methods, to update a cached entity that has an associated ETag. + /// * For other methods, and in particular for `PUT`, `If-None-Match` used with + /// the `*` value can be used to save a file not known to exist, + /// guaranteeing that another upload didn't happen before, losing the data + /// of the previous put; this problems is the variation of the lost update + /// problem. + (IfNoneMatch, IF_NONE_MATCH, "if-none-match"); + + /// Makes a request conditional based on range. + /// + /// The If-Range HTTP request header makes a range request conditional: if + /// the condition is fulfilled, the range request will be issued and the + /// server sends back a 206 Partial Content answer with the appropriate + /// body. If the condition is not fulfilled, the full resource is sent back, + /// with a 200 OK status. + /// + /// This header can be used either with a Last-Modified validator, or with + /// an ETag, but not with both. + /// + /// The most common use case is to resume a download, to guarantee that the + /// stored resource has not been modified since the last fragment has been + /// received. + (IfRange, IF_RANGE, "if-range"); + + /// Makes the request conditional based on the last modification date. + /// + /// The If-Unmodified-Since request HTTP header makes the request + /// conditional: the server will send back the requested resource, or accept + /// it in the case of a POST or another non-safe method, only if it has not + /// been last modified after the given date. If the request has been + /// modified after the given date, the response will be a 412 (Precondition + /// Failed) error. + /// + /// There are two common use cases: + /// + /// * In conjunction non-safe methods, like POST, it can be used to + /// implement an optimistic concurrency control, like done by some wikis: + /// editions are rejected if the stored document has been modified since the + /// original has been retrieved. + /// + /// * In conjunction with a range request with a If-Range header, it can be + /// used to ensure that the new fragment requested comes from an unmodified + /// document. + (IfUnmodifiedSince, IF_UNMODIFIED_SINCE, "if-unmodified-since"); + + /// Content-Types that are acceptable for the response. + (LastModified, LAST_MODIFIED, "last-modified"); + + /// Allows the server to point an interested client to another resource + /// containing metadata about the requested resource. + (Link, LINK, "link"); + + /// Indicates the URL to redirect a page to. + /// + /// The Location response header indicates the URL to redirect a page to. It + /// only provides a meaning when served with a 3xx status response. + /// + /// The HTTP method used to make the new request to fetch the page pointed + /// to by Location depends of the original method and of the kind of + /// redirection: + /// + /// * If 303 (See Also) responses always lead to the use of a GET method, + /// 307 (Temporary Redirect) and 308 (Permanent Redirect) don't change the + /// method used in the original request; + /// + /// * 301 (Permanent Redirect) and 302 (Found) doesn't change the method + /// most of the time, though older user-agents may (so you basically don't + /// know). + /// + /// All responses with one of these status codes send a Location header. + /// + /// Beside redirect response, messages with 201 (Created) status also + /// include the Location header. It indicates the URL to the newly created + /// resource. + /// + /// Location and Content-Location are different: Location indicates the + /// target of a redirection (or the URL of a newly created resource), while + /// Content-Location indicates the direct URL to use to access the resource + /// when content negotiation happened, without the need of further content + /// negotiation. Location is a header associated with the response, while + /// Content-Location is associated with the entity returned. + (Location, LOCATION, "location"); + + /// Indicates the max number of intermediaries the request should be sent + /// through. + (MaxForwards, MAX_FORWARDS, "max-forwards"); + + /// Indicates where a fetch originates from. + /// + /// It doesn't include any path information, but only the server name. It is + /// sent with CORS requests, as well as with POST requests. It is similar to + /// the Referer header, but, unlike this header, it doesn't disclose the + /// whole path. + (Origin, ORIGIN, "origin"); + + /// HTTP/1.0 header usually used for backwards compatibility. + /// + /// The Pragma HTTP/1.0 general header is an implementation-specific header + /// that may have various effects along the request-response chain. It is + /// used for backwards compatibility with HTTP/1.0 caches where the + /// Cache-Control HTTP/1.1 header is not yet present. + (Pragma, PRAGMA, "pragma"); + + /// Defines the authentication method that should be used to gain access to + /// a proxy. + /// + /// Unlike `www-authenticate`, the `proxy-authenticate` header field applies + /// only to the next outbound client on the response chain. This is because + /// only the client that chose a given proxy is likely to have the + /// credentials necessary for authentication. However, when multiple proxies + /// are used within the same administrative domain, such as office and + /// regional caching proxies within a large corporate network, it is common + /// for credentials to be generated by the user agent and passed through the + /// hierarchy until consumed. Hence, in such a configuration, it will appear + /// as if Proxy-Authenticate is being forwarded because each proxy will send + /// the same challenge set. + /// + /// The `proxy-authenticate` header is sent along with a `407 Proxy + /// Authentication Required`. + (ProxyAuthenticate, PROXY_AUTHENTICATE, "proxy-authenticate"); + + /// Contains the credentials to authenticate a user agent to a proxy server. + /// + /// This header is usually included after the server has responded with a + /// 407 Proxy Authentication Required status and the Proxy-Authenticate + /// header. + (ProxyAuthorization, PROXY_AUTHORIZATION, "proxy-authorization"); + + /// Associates a specific cryptographic public key with a certain server. + /// + /// This decreases the risk of MITM attacks with forged certificates. If one + /// or several keys are pinned and none of them are used by the server, the + /// browser will not accept the response as legitimate, and will not display + /// it. + (PublicKeyPins, PUBLIC_KEY_PINS, "public-key-pins"); + + /// Sends reports of pinning violation to the report-uri specified in the + /// header. + /// + /// Unlike `Public-Key-Pins`, this header still allows browsers to connect + /// to the server if the pinning is violated. + (PublicKeyPinsReportOnly, PUBLIC_KEY_PINS_REPORT_ONLY, "public-key-pins-report-only"); + + /// Indicates the part of a document that the server should return. + /// + /// Several parts can be requested with one Range header at once, and the + /// server may send back these ranges in a multipart document. If the server + /// sends back ranges, it uses the 206 Partial Content for the response. If + /// the ranges are invalid, the server returns the 416 Range Not Satisfiable + /// error. The server can also ignore the Range header and return the whole + /// document with a 200 status code. + (Range, RANGE, "range"); + + /// Contains the address of the previous web page from which a link to the + /// currently requested page was followed. + /// + /// The Referer header allows servers to identify where people are visiting + /// them from and may use that data for analytics, logging, or optimized + /// caching, for example. + (Referer, REFERER, "referer"); + + /// Governs which referrer information should be included with requests + /// made. + (ReferrerPolicy, REFERRER_POLICY, "referrer-policy"); + + /// Informs the web browser that the current page or frame should be + /// refreshed. + (Refresh, REFRESH, "refresh"); + + /// The Retry-After response HTTP header indicates how long the user agent + /// should wait before making a follow-up request. There are two main cases + /// this header is used: + /// + /// * When sent with a 503 (Service Unavailable) response, it indicates how + /// long the service is expected to be unavailable. + /// + /// * When sent with a redirect response, such as 301 (Moved Permanently), + /// it indicates the minimum time that the user agent is asked to wait + /// before issuing the redirected request. + (RetryAfter, RETRY_AFTER, "retry-after"); + + /// The |Sec-WebSocket-Accept| header field is used in the WebSocket + /// opening handshake. It is sent from the server to the client to + /// confirm that the server is willing to initiate the WebSocket + /// connection. + (SecWebSocketAccept, SEC_WEBSOCKET_ACCEPT, "sec-websocket-accept"); + + /// The |Sec-WebSocket-Extensions| header field is used in the WebSocket + /// opening handshake. It is initially sent from the client to the + /// server, and then subsequently sent from the server to the client, to + /// agree on a set of protocol-level extensions to use for the duration + /// of the connection. + (SecWebSocketExtensions, SEC_WEBSOCKET_EXTENSIONS, "sec-websocket-extensions"); + + /// The |Sec-WebSocket-Key| header field is used in the WebSocket opening + /// handshake. It is sent from the client to the server to provide part + /// of the information used by the server to prove that it received a + /// valid WebSocket opening handshake. This helps ensure that the server + /// does not accept connections from non-WebSocket clients (e.g., HTTP + /// clients) that are being abused to send data to unsuspecting WebSocket + /// servers. + (SecWebSocketKey, SEC_WEBSOCKET_KEY, "sec-websocket-key"); + + /// The |Sec-WebSocket-Protocol| header field is used in the WebSocket + /// opening handshake. It is sent from the client to the server and back + /// from the server to the client to confirm the subprotocol of the + /// connection. This enables scripts to both select a subprotocol and be + /// sure that the server agreed to serve that subprotocol. + (SecWebSocketProtocol, SEC_WEBSOCKET_PROTOCOL, "sec-websocket-protocol"); + + /// The |Sec-WebSocket-Version| header field is used in the WebSocket + /// opening handshake. It is sent from the client to the server to + /// indicate the protocol version of the connection. This enables + /// servers to correctly interpret the opening handshake and subsequent + /// data being sent from the data, and close the connection if the server + /// cannot interpret that data in a safe manner. + (SecWebSocketVersion, SEC_WEBSOCKET_VERSION, "sec-websocket-version"); + + /// Contains information about the software used by the origin server to + /// handle the request. + /// + /// Overly long and detailed Server values should be avoided as they + /// potentially reveal internal implementation details that might make it + /// (slightly) easier for attackers to find and exploit known security + /// holes. + (Server, SERVER, "server"); + + /// Used to send cookies from the server to the user agent. + (SetCookie, SET_COOKIE, "set-cookie"); + + /// Tells the client to communicate with HTTPS instead of using HTTP. + (StrictTransportSecurity, STRICT_TRANSPORT_SECURITY, "strict-transport-security"); + + /// Informs the server of transfer encodings willing to be accepted as part + /// of the response. + /// + /// See also the Transfer-Encoding response header for more details on + /// transfer encodings. Note that chunked is always acceptable for HTTP/1.1 + /// recipients and you that don't have to specify "chunked" using the TE + /// header. However, it is useful for setting if the client is accepting + /// trailer fields in a chunked transfer coding using the "trailers" value. + (Te, TE, "te"); + + /// Allows the sender to include additional fields at the end of chunked + /// messages. + (Trailer, TRAILER, "trailer"); + + /// Specifies the form of encoding used to safely transfer the entity to the + /// client. + /// + /// `transfer-encoding` is a hop-by-hop header, that is applying to a + /// message between two nodes, not to a resource itself. Each segment of a + /// multi-node connection can use different `transfer-encoding` values. If + /// you want to compress data over the whole connection, use the end-to-end + /// header `content-encoding` header instead. + /// + /// When present on a response to a `HEAD` request that has no body, it + /// indicates the value that would have applied to the corresponding `GET` + /// message. + (TransferEncoding, TRANSFER_ENCODING, "transfer-encoding"); + + /// Contains a string that allows identifying the requesting client's + /// software. + (UserAgent, USER_AGENT, "user-agent"); + + /// Used as part of the exchange to upgrade the protocol. + (Upgrade, UPGRADE, "upgrade"); + + /// Sends a signal to the server expressing the client’s preference for an + /// encrypted and authenticated response. + (UpgradeInsecureRequests, UPGRADE_INSECURE_REQUESTS, "upgrade-insecure-requests"); + + /// Determines how to match future requests with cached responses. + /// + /// The `vary` HTTP response header determines how to match future request + /// headers to decide whether a cached response can be used rather than + /// requesting a fresh one from the origin server. It is used by the server + /// to indicate which headers it used when selecting a representation of a + /// resource in a content negotiation algorithm. + /// + /// The `vary` header should be set on a 304 Not Modified response exactly + /// like it would have been set on an equivalent 200 OK response. + (Vary, VARY, "vary"); + + /// Added by proxies to track routing. + /// + /// The `via` general header is added by proxies, both forward and reverse + /// proxies, and can appear in the request headers and the response headers. + /// It is used for tracking message forwards, avoiding request loops, and + /// identifying the protocol capabilities of senders along the + /// request/response chain. + (Via, VIA, "via"); + + /// General HTTP header contains information about possible problems with + /// the status of the message. + /// + /// More than one `warning` header may appear in a response. Warning header + /// fields can in general be applied to any message, however some warn-codes + /// are specific to caches and can only be applied to response messages. + (Warning, WARNING, "warning"); + + /// Defines the authentication method that should be used to gain access to + /// a resource. + (WwwAuthenticate, WWW_AUTHENTICATE, "www-authenticate"); + + /// Marker used by the server to indicate that the MIME types advertised in + /// the `content-type` headers should not be changed and be followed. + /// + /// This allows to opt-out of MIME type sniffing, or, in other words, it is + /// a way to say that the webmasters knew what they were doing. + /// + /// This header was introduced by Microsoft in IE 8 as a way for webmasters + /// to block content sniffing that was happening and could transform + /// non-executable MIME types into executable MIME types. Since then, other + /// browsers have introduced it, even if their MIME sniffing algorithms were + /// less aggressive. + /// + /// Site security testers usually expect this header to be set. + (XContentTypeOptions, X_CONTENT_TYPE_OPTIONS, "x-content-type-options"); + + /// Controls DNS prefetching. + /// + /// The `x-dns-prefetch-control` HTTP response header controls DNS + /// prefetching, a feature by which browsers proactively perform domain name + /// resolution on both links that the user may choose to follow as well as + /// URLs for items referenced by the document, including images, CSS, + /// JavaScript, and so forth. + /// + /// This prefetching is performed in the background, so that the DNS is + /// likely to have been resolved by the time the referenced items are + /// needed. This reduces latency when the user clicks a link. + (XDnsPrefetchControl, X_DNS_PREFETCH_CONTROL, "x-dns-prefetch-control"); + + /// Indicates whether or not a browser should be allowed to render a page in + /// a frame. + /// + /// Sites can use this to avoid clickjacking attacks, by ensuring that their + /// content is not embedded into other sites. + /// + /// The added security is only provided if the user accessing the document + /// is using a browser supporting `x-frame-options`. + (XFrameOptions, X_FRAME_OPTIONS, "x-frame-options"); + + /// Stop pages from loading when an XSS attack is detected. + /// + /// The HTTP X-XSS-Protection response header is a feature of Internet + /// Explorer, Chrome and Safari that stops pages from loading when they + /// detect reflected cross-site scripting (XSS) attacks. Although these + /// protections are largely unnecessary in modern browsers when sites + /// implement a strong Content-Security-Policy that disables the use of + /// inline JavaScript ('unsafe-inline'), they can still provide protections + /// for users of older web browsers that don't yet support CSP. + (XXssProtection, X_XSS_PROTECTION, "x-xss-protection"); +} + +/// Valid header name characters +/// +/// ```not_rust +/// field-name = token +/// separators = "(" | ")" | "<" | ">" | "@" +/// | "," | ";" | ":" | "\" | <"> +/// | "/" | "[" | "]" | "?" | "=" +/// | "{" | "}" | SP | HT +/// token = 1*tchar +/// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +/// / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +/// / DIGIT / ALPHA +/// ; any VCHAR, except delimiters +/// ``` +const HEADER_CHARS: [u8; 256] = [ + // 0 1 2 3 4 5 6 7 8 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x + 0, 0, 0, b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // 3x + 0, 0, b'*', b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x + b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, 0, // 5x + 0, 0, 0, 0, 0, b'a', b'b', b'c', b'd', b'e', // 6x + b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', // 7x + b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', // 8x + b'z', 0, 0, 0, b'^', b'_', b'`', b'a', b'b', b'c', // 9x + b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x + b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x + b'x', b'y', b'z', 0, b'|', 0, b'~', 0, 0, 0, // 12x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x + 0, 0, 0, 0, 0, 0 // 25x +]; + +const HEADER_CHARS_H2: [u8; 256] = [ + // 0 1 2 3 4 5 6 7 8 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x + 0, 0, 0, b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // 3x + 0, 0, b'*', b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x + b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, 0, // 5x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x + 0, 0, 0, 0, b'^', b'_', b'`', b'a', b'b', b'c', // 9x + b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x + b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x + b'x', b'y', b'z', 0, b'|', 0, b'~', 0, 0, 0, // 12x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x + 0, 0, 0, 0, 0, 0 // 25x +]; + +macro_rules! eq { + (($($cmp:expr,)*) $v:ident[$n:expr] ==) => { + $($cmp) && * + }; + (($($cmp:expr,)*) $v:ident[$n:expr] == $a:tt $($rest:tt)*) => { + eq!(($($cmp,)* $v[$n] == $a,) $v[$n+1] == $($rest)*) + }; + ($v:ident == $($rest:tt)+) => { + eq!(() $v[0] == $($rest)+) + }; + ($v:ident[$n:expr] == $($rest:tt)+) => { + eq!(() $v[$n] == $($rest)+) + }; +} + +fn parse_hdr<'a>(data: &'a [u8], b: &'a mut [u8; 64], table: &[u8; 256]) + -> Result, InvalidHeaderName> +{ + use self::StandardHeader::*; + + let len = data.len(); + + let validate = |buf: &'a [u8], len: usize| { + let buf = &buf[..len]; + if buf.iter().any(|&b| b == 0) { + Err(InvalidHeaderName::new()) + } else { + Ok(HdrName::custom(buf, true)) + } + }; + + + macro_rules! to_lower { + ($d:ident, $src:ident, 1) => { $d[0] = table[$src[0] as usize]; }; + ($d:ident, $src:ident, 2) => { to_lower!($d, $src, 1); $d[1] = table[$src[1] as usize]; }; + ($d:ident, $src:ident, 3) => { to_lower!($d, $src, 2); $d[2] = table[$src[2] as usize]; }; + ($d:ident, $src:ident, 4) => { to_lower!($d, $src, 3); $d[3] = table[$src[3] as usize]; }; + ($d:ident, $src:ident, 5) => { to_lower!($d, $src, 4); $d[4] = table[$src[4] as usize]; }; + ($d:ident, $src:ident, 6) => { to_lower!($d, $src, 5); $d[5] = table[$src[5] as usize]; }; + ($d:ident, $src:ident, 7) => { to_lower!($d, $src, 6); $d[6] = table[$src[6] as usize]; }; + ($d:ident, $src:ident, 8) => { to_lower!($d, $src, 7); $d[7] = table[$src[7] as usize]; }; + ($d:ident, $src:ident, 9) => { to_lower!($d, $src, 8); $d[8] = table[$src[8] as usize]; }; + ($d:ident, $src:ident, 10) => { to_lower!($d, $src, 9); $d[9] = table[$src[9] as usize]; }; + ($d:ident, $src:ident, 11) => { to_lower!($d, $src, 10); $d[10] = table[$src[10] as usize]; }; + ($d:ident, $src:ident, 12) => { to_lower!($d, $src, 11); $d[11] = table[$src[11] as usize]; }; + ($d:ident, $src:ident, 13) => { to_lower!($d, $src, 12); $d[12] = table[$src[12] as usize]; }; + ($d:ident, $src:ident, 14) => { to_lower!($d, $src, 13); $d[13] = table[$src[13] as usize]; }; + ($d:ident, $src:ident, 15) => { to_lower!($d, $src, 14); $d[14] = table[$src[14] as usize]; }; + ($d:ident, $src:ident, 16) => { to_lower!($d, $src, 15); $d[15] = table[$src[15] as usize]; }; + ($d:ident, $src:ident, 17) => { to_lower!($d, $src, 16); $d[16] = table[$src[16] as usize]; }; + ($d:ident, $src:ident, 18) => { to_lower!($d, $src, 17); $d[17] = table[$src[17] as usize]; }; + ($d:ident, $src:ident, 19) => { to_lower!($d, $src, 18); $d[18] = table[$src[18] as usize]; }; + ($d:ident, $src:ident, 20) => { to_lower!($d, $src, 19); $d[19] = table[$src[19] as usize]; }; + ($d:ident, $src:ident, 21) => { to_lower!($d, $src, 20); $d[20] = table[$src[20] as usize]; }; + ($d:ident, $src:ident, 22) => { to_lower!($d, $src, 21); $d[21] = table[$src[21] as usize]; }; + ($d:ident, $src:ident, 23) => { to_lower!($d, $src, 22); $d[22] = table[$src[22] as usize]; }; + ($d:ident, $src:ident, 24) => { to_lower!($d, $src, 23); $d[23] = table[$src[23] as usize]; }; + ($d:ident, $src:ident, 25) => { to_lower!($d, $src, 24); $d[24] = table[$src[24] as usize]; }; + ($d:ident, $src:ident, 26) => { to_lower!($d, $src, 25); $d[25] = table[$src[25] as usize]; }; + ($d:ident, $src:ident, 27) => { to_lower!($d, $src, 26); $d[26] = table[$src[26] as usize]; }; + ($d:ident, $src:ident, 28) => { to_lower!($d, $src, 27); $d[27] = table[$src[27] as usize]; }; + ($d:ident, $src:ident, 29) => { to_lower!($d, $src, 28); $d[28] = table[$src[28] as usize]; }; + ($d:ident, $src:ident, 30) => { to_lower!($d, $src, 29); $d[29] = table[$src[29] as usize]; }; + ($d:ident, $src:ident, 31) => { to_lower!($d, $src, 30); $d[30] = table[$src[30] as usize]; }; + ($d:ident, $src:ident, 32) => { to_lower!($d, $src, 31); $d[31] = table[$src[31] as usize]; }; + ($d:ident, $src:ident, 33) => { to_lower!($d, $src, 32); $d[32] = table[$src[32] as usize]; }; + ($d:ident, $src:ident, 34) => { to_lower!($d, $src, 33); $d[33] = table[$src[33] as usize]; }; + ($d:ident, $src:ident, 35) => { to_lower!($d, $src, 34); $d[34] = table[$src[34] as usize]; }; + } + + assert!(len < super::MAX_HEADER_NAME_LEN, + "header name too long -- max length is {}", + super::MAX_HEADER_NAME_LEN); + + match len { + 0 => { + Err(InvalidHeaderName::new()) + } + 2 => { + to_lower!(b, data, 2); + + if eq!(b == b't' b'e') { + Ok(Te.into()) + } else { + validate(b, len) + } + } + 3 => { + to_lower!(b, data, 3); + + if eq!(b == b'a' b'g' b'e') { + Ok(Age.into()) + } else if eq!(b == b'v' b'i' b'a') { + Ok(Via.into()) + } else if eq!(b == b'd' b'n' b't') { + Ok(Dnt.into()) + } else { + validate(b, len) + } + } + 4 => { + to_lower!(b, data, 4); + + if eq!(b == b'd' b'a' b't' b'e') { + Ok(Date.into()) + } else if eq!(b == b'e' b't' b'a' b'g') { + Ok(Etag.into()) + } else if eq!(b == b'f' b'r' b'o' b'm') { + Ok(From.into()) + } else if eq!(b == b'h' b'o' b's' b't') { + Ok(Host.into()) + } else if eq!(b == b'l' b'i' b'n' b'k') { + Ok(Link.into()) + } else if eq!(b == b'v' b'a' b'r' b'y') { + Ok(Vary.into()) + } else { + validate(b, len) + } + } + 5 => { + to_lower!(b, data, 5); + + if eq!(b == b'a' b'l' b'l' b'o' b'w') { + Ok(Allow.into()) + } else if eq!(b == b'r' b'a' b'n' b'g' b'e') { + Ok(Range.into()) + } else { + validate(b, len) + } + } + 6 => { + to_lower!(b, data, 6); + + if eq!(b == b'a' b'c' b'c' b'e' b'p' b't') { + return Ok(Accept.into()) + } else if eq!(b == b'c' b'o' b'o' b'k' b'i' b'e') { + return Ok(Cookie.into()) + } else if eq!(b == b'e' b'x' b'p' b'e' b'c' b't') { + return Ok(Expect.into()) + } else if eq!(b == b'o' b'r' b'i' b'g' b'i' b'n') { + return Ok(Origin.into()) + } else if eq!(b == b'p' b'r' b'a' b'g' b'm' b'a') { + return Ok(Pragma.into()) + } else if b[0] == b's' { + if eq!(b[1] == b'e' b'r' b'v' b'e' b'r') { + return Ok(Server.into()) + } + } + + validate(b, len) + } + 7 => { + to_lower!(b, data, 7); + + if eq!(b == b'a' b'l' b't' b'-' b's' b'v' b'c') { + Ok(AltSvc.into()) + } else if eq!(b == b'e' b'x' b'p' b'i' b'r' b'e' b's') { + Ok(Expires.into()) + } else if eq!(b == b'r' b'e' b'f' b'e' b'r' b'e' b'r') { + Ok(Referer.into()) + } else if eq!(b == b'r' b'e' b'f' b'r' b'e' b's' b'h') { + Ok(Refresh.into()) + } else if eq!(b == b't' b'r' b'a' b'i' b'l' b'e' b'r') { + Ok(Trailer.into()) + } else if eq!(b == b'u' b'p' b'g' b'r' b'a' b'd' b'e') { + Ok(Upgrade.into()) + } else if eq!(b == b'w' b'a' b'r' b'n' b'i' b'n' b'g') { + Ok(Warning.into()) + } else { + validate(b, len) + } + } + 8 => { + to_lower!(b, data, 8); + + if eq!(b == b'i' b'f' b'-') { + if eq!(b[3] == b'm' b'a' b't' b'c' b'h') { + return Ok(IfMatch.into()) + } else if eq!(b[3] == b'r' b'a' b'n' b'g' b'e') { + return Ok(IfRange.into()) + } + } else if eq!(b == b'l' b'o' b'c' b'a' b't' b'i' b'o' b'n') { + return Ok(Location.into()) + } + + validate(b, len) + } + 9 => { + to_lower!(b, data, 9); + + if eq!(b == b'f' b'o' b'r' b'w' b'a' b'r' b'd' b'e' b'd') { + Ok(Forwarded.into()) + } else { + validate(b, len) + } + } + 10 => { + to_lower!(b, data, 10); + + if eq!(b == b'c' b'o' b'n' b'n' b'e' b'c' b't' b'i' b'o' b'n') { + Ok(Connection.into()) + } else if eq!(b == b's' b'e' b't' b'-' b'c' b'o' b'o' b'k' b'i' b'e') { + Ok(SetCookie.into()) + } else if eq!(b == b'u' b's' b'e' b'r' b'-' b'a' b'g' b'e' b'n' b't') { + Ok(UserAgent.into()) + } else { + validate(b, len) + } + } + 11 => { + to_lower!(b, data, 11); + + if eq!(b == b'r' b'e' b't' b'r' b'y' b'-' b'a' b'f' b't' b'e' b'r') { + Ok(RetryAfter.into()) + } else { + validate(b, len) + } + } + 12 => { + to_lower!(b, data, 12); + + if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b't' b'y' b'p' b'e') { + Ok(ContentType.into()) + } else if eq!(b == b'm' b'a' b'x' b'-' b'f' b'o' b'r' b'w' b'a' b'r' b'd' b's') { + Ok(MaxForwards.into()) + } else { + validate(b, len) + } + } + 13 => { + to_lower!(b, data, 13); + + if b[0] == b'a' { + if eq!(b[1] == b'c' b'c' b'e' b'p' b't' b'-' b'r' b'a' b'n' b'g' b'e' b's') { + return Ok(AcceptRanges.into()) + } else if eq!(b[1] == b'u' b't' b'h' b'o' b'r' b'i' b'z' b'a' b't' b'i' b'o' b'n') { + return Ok(Authorization.into()) + } + } else if b[0] == b'c' { + if eq!(b[1] == b'a' b'c' b'h' b'e' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l') { + return Ok(CacheControl.into()) + } else if eq!(b[1] == b'o' b'n' b't' b'e' b'n' b't' b'-' b'r' b'a' b'n' b'g' b'e' ) { + return Ok(ContentRange.into()) + } + } else if eq!(b == b'i' b'f' b'-' b'n' b'o' b'n' b'e' b'-' b'm' b'a' b't' b'c' b'h') { + return Ok(IfNoneMatch.into()) + } else if eq!(b == b'l' b'a' b's' b't' b'-' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd') { + return Ok(LastModified.into()) + } + + validate(b, len) + } + 14 => { + to_lower!(b, data, 14); + + if eq!(b == b'a' b'c' b'c' b'e' b'p' b't' b'-' b'c' b'h' b'a' b'r' b's' b'e' b't') { + Ok(AcceptCharset.into()) + } else if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b'l' b'e' b'n' b'g' b't' b'h') { + Ok(ContentLength.into()) + } else { + validate(b, len) + } + } + 15 => { + to_lower!(b, data, 15); + + if eq!(b == b'a' b'c' b'c' b'e' b'p' b't' b'-') { // accept- + if eq!(b[7] == b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') { + return Ok(AcceptEncoding.into()) + } else if eq!(b[7] == b'l' b'a' b'n' b'g' b'u' b'a' b'g' b'e') { + return Ok(AcceptLanguage.into()) + } + } else if eq!(b == b'p' b'u' b'b' b'l' b'i' b'c' b'-' b'k' b'e' b'y' b'-' b'p' b'i' b'n' b's') { + return Ok(PublicKeyPins.into()) + } else if eq!(b == b'x' b'-' b'f' b'r' b'a' b'm' b'e' b'-' b'o' b'p' b't' b'i' b'o' b'n' b's') { + return Ok(XFrameOptions.into()) + } + else if eq!(b == b'r' b'e' b'f' b'e' b'r' b'r' b'e' b'r' b'-' b'p' b'o' b'l' b'i' b'c' b'y') { + return Ok(ReferrerPolicy.into()) + } + + validate(b, len) + } + 16 => { + to_lower!(b, data, 16); + + if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-') { + if eq!(b[8] == b'l' b'a' b'n' b'g' b'u' b'a' b'g' b'e') { + return Ok(ContentLanguage.into()) + } else if eq!(b[8] == b'l' b'o' b'c' b'a' b't' b'i' b'o' b'n') { + return Ok(ContentLocation.into()) + } else if eq!(b[8] == b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') { + return Ok(ContentEncoding.into()) + } + } else if eq!(b == b'w' b'w' b'w' b'-' b'a' b'u' b't' b'h' b'e' b'n' b't' b'i' b'c' b'a' b't' b'e') { + return Ok(WwwAuthenticate.into()) + } else if eq!(b == b'x' b'-' b'x' b's' b's' b'-' b'p' b'r' b'o' b't' b'e' b'c' b't' b'i' b'o' b'n') { + return Ok(XXssProtection.into()) + } + + validate(b, len) + } + 17 => { + to_lower!(b, data, 17); + + if eq!(b == b't' b'r' b'a' b'n' b's' b'f' b'e' b'r' b'-' b'e' b'n' b'c' b'o' b'd' b'i' b'n' b'g') { + Ok(TransferEncoding.into()) + } else if eq!(b == b'i' b'f' b'-' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd' b'-' b's' b'i' b'n' b'c' b'e') { + Ok(IfModifiedSince.into()) + } else if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'k' b'e' b'y') { + Ok(SecWebSocketKey.into()) + } else { + validate(b, len) + } + } + 18 => { + to_lower!(b, data, 18); + + if eq!(b == b'p' b'r' b'o' b'x' b'y' b'-' b'a' b'u' b't' b'h' b'e' b'n' b't' b'i' b'c' b'a' b't' b'e') { + Ok(ProxyAuthenticate.into()) + } else { + validate(b, len) + } + } + 19 => { + to_lower!(b, data, 19); + + if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b'd' b'i' b's' b'p' b'o' b's' b'i' b't' b'i' b'o' b'n') { + Ok(ContentDisposition.into()) + } else if eq!(b == b'i' b'f' b'-' b'u' b'n' b'm' b'o' b'd' b'i' b'f' b'i' b'e' b'd' b'-' b's' b'i' b'n' b'c' b'e') { + Ok(IfUnmodifiedSince.into()) + } else if eq!(b == b'p' b'r' b'o' b'x' b'y' b'-' b'a' b'u' b't' b'h' b'o' b'r' b'i' b'z' b'a' b't' b'i' b'o' b'n') { + Ok(ProxyAuthorization.into()) + } else { + validate(b, len) + } + } + 20 => { + to_lower!(b, data, 20); + + if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'a' b'c' b'c' b'e' b'p' b't') { + Ok(SecWebSocketAccept.into()) + } else { + validate(b, len) + } + } + 21 => { + to_lower!(b, data, 21); + + if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'v' b'e' b'r' b's' b'i' b'o' b'n') { + Ok(SecWebSocketVersion.into()) + } else { + validate(b, len) + } + } + 22 => { + to_lower!(b, data, 22); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'm' b'a' b'x' b'-' b'a' b'g' b'e') { + Ok(AccessControlMaxAge.into()) + } else if eq!(b == b'x' b'-' b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b't' b'y' b'p' b'e' b'-' b'o' b'p' b't' b'i' b'o' b'n' b's') { + Ok(XContentTypeOptions.into()) + } else if eq!(b == b'x' b'-' b'd' b'n' b's' b'-' b'p' b'r' b'e' b'f' b'e' b't' b'c' b'h' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l') { + Ok(XDnsPrefetchControl.into()) + } else if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'p' b'r' b'o' b't' b'o' b'c' b'o' b'l') { + Ok(SecWebSocketProtocol.into()) + } else { + validate(b, len) + } + } + 23 => { + to_lower!(b, data, 23); + + if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y' b'-' b'p' b'o' b'l' b'i' b'c' b'y') { + Ok(ContentSecurityPolicy.into()) + } else { + validate(b, len) + } + } + 24 => { + to_lower!(b, data, 24); + + if eq!(b == b's' b'e' b'c' b'-' b'w' b'e' b'b' b's' b'o' b'c' b'k' b'e' b't' b'-' b'e' b'x' b't' b'e' b'n' b's' b'i' b'o' b'n' b's') { + Ok(SecWebSocketExtensions.into()) + } else { + validate(b, len) + } + } + 25 => { + to_lower!(b, data, 25); + + if eq!(b == b's' b't' b'r' b'i' b'c' b't' b'-' b't' b'r' b'a' b'n' b's' b'p' b'o' b'r' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y') { + Ok(StrictTransportSecurity.into()) + } else if eq!(b == b'u' b'p' b'g' b'r' b'a' b'd' b'e' b'-' b'i' b'n' b's' b'e' b'c' b'u' b'r' b'e' b'-' b'r' b'e' b'q' b'u' b'e' b's' b't' b's') { + Ok(UpgradeInsecureRequests.into()) + } else { + validate(b, len) + } + } + 27 => { + to_lower!(b, data, 27); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-' b'o' b'r' b'i' b'g' b'i' b'n') { + Ok(AccessControlAllowOrigin.into()) + } else if eq!(b == b'p' b'u' b'b' b'l' b'i' b'c' b'-' b'k' b'e' b'y' b'-' b'p' b'i' b'n' b's' b'-' b'r' b'e' b'p' b'o' b'r' b't' b'-' b'o' b'n' b'l' b'y') { + Ok(PublicKeyPinsReportOnly.into()) + } else { + validate(b, len) + } + } + 28 => { + to_lower!(b, data, 28); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-') { + if eq!(b[21] == b'h' b'e' b'a' b'd' b'e' b'r' b's') { + return Ok(AccessControlAllowHeaders.into()) + } else if eq!(b[21] == b'm' b'e' b't' b'h' b'o' b'd' b's') { + return Ok(AccessControlAllowMethods.into()) + } + } + + validate(b, len) + } + 29 => { + to_lower!(b, data, 29); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-') { + if eq!(b[15] == b'e' b'x' b'p' b'o' b's' b'e' b'-' b'h' b'e' b'a' b'd' b'e' b'r' b's') { + return Ok(AccessControlExposeHeaders.into()) + } else if eq!(b[15] == b'r' b'e' b'q' b'u' b'e' b's' b't' b'-' b'm' b'e' b't' b'h' b'o' b'd') { + return Ok(AccessControlRequestMethod.into()) + } + } + + validate(b, len) + } + 30 => { + to_lower!(b, data, 30); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'r' b'e' b'q' b'u' b'e' b's' b't' b'-' b'h' b'e' b'a' b'd' b'e' b'r' b's') { + Ok(AccessControlRequestHeaders.into()) + } else { + validate(b, len) + } + } + 32 => { + to_lower!(b, data, 32); + + if eq!(b == b'a' b'c' b'c' b'e' b's' b's' b'-' b'c' b'o' b'n' b't' b'r' b'o' b'l' b'-' b'a' b'l' b'l' b'o' b'w' b'-' b'c' b'r' b'e' b'd' b'e' b'n' b't' b'i' b'a' b'l' b's') { + Ok(AccessControlAllowCredentials.into()) + } else { + validate(b, len) + } + } + 35 => { + to_lower!(b, data, 35); + + if eq!(b == b'c' b'o' b'n' b't' b'e' b'n' b't' b'-' b's' b'e' b'c' b'u' b'r' b'i' b't' b'y' b'-' b'p' b'o' b'l' b'i' b'c' b'y' b'-' b'r' b'e' b'p' b'o' b'r' b't' b'-' b'o' b'n' b'l' b'y') { + Ok(ContentSecurityPolicyReportOnly.into()) + } else { + validate(b, len) + } + } + _ => { + if len < 64 { + for i in 0..len { + b[i] = table[data[i] as usize]; + } + + validate(b, len) + } else { + Ok(HdrName::custom(data, false)) + } + } + } +} + +impl<'a> From for HdrName<'a> { + fn from(hdr: StandardHeader) -> HdrName<'a> { + HdrName { inner: Repr::Standard(hdr) } + } +} + +impl HeaderName { + /// Converts a slice of bytes to an HTTP header name. + /// + /// This function normalizes the input. + pub fn from_bytes(src: &[u8]) -> Result { + let mut buf = unsafe { mem::uninitialized() }; + match parse_hdr(src, &mut buf, &HEADER_CHARS)?.inner { + Repr::Standard(std) => Ok(std.into()), + Repr::Custom(MaybeLower { buf, lower: true }) => { + let buf = Bytes::from(buf); + let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; + Ok(Custom(val).into()) + } + Repr::Custom(MaybeLower { buf, lower: false }) => { + use bytes::{BufMut}; + let mut dst = BytesMut::with_capacity(buf.len()); + + for b in buf.iter() { + let b = HEADER_CHARS[*b as usize]; + + if b == 0 { + return Err(InvalidHeaderName::new()); + } + + dst.put(b); + } + + let val = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) }; + + Ok(Custom(val).into()) + } + } + } + + /// Converts a slice of bytes to an HTTP header name. + /// + /// This function expects the input to only contain lowercase characters. + /// This is useful when decoding HTTP/2.0 headers. The HTTP/2.0 + /// specification requires that all headers be represented in lower case. + /// + /// # Examples + /// + /// ``` + /// # use http::header::*; + /// + /// // Parsing a lower case header + /// let hdr = HeaderName::from_lowercase(b"content-length").unwrap(); + /// assert_eq!(CONTENT_LENGTH, hdr); + /// + /// // Parsing a header that contains uppercase characters + /// assert!(HeaderName::from_lowercase(b"Content-Length").is_err()); + /// ``` + pub fn from_lowercase(src: &[u8]) -> Result { + let mut buf = unsafe { mem::uninitialized() }; + match parse_hdr(src, &mut buf, &HEADER_CHARS_H2)?.inner { + Repr::Standard(std) => Ok(std.into()), + Repr::Custom(MaybeLower { buf, lower: true }) => { + let buf = Bytes::from(buf); + let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; + Ok(Custom(val).into()) + } + Repr::Custom(MaybeLower { buf, lower: false }) => { + for &b in buf.iter() { + if b != HEADER_CHARS[b as usize] { + return Err(InvalidHeaderName::new()); + } + } + + let buf = Bytes::from(buf); + let val = unsafe { ByteStr::from_utf8_unchecked(buf) }; + Ok(Custom(val).into()) + } + } + } + + /// Converts a static string to a HTTP header name. + /// + /// This function panics when the static string is a invalid header. + /// + /// This function requires the static string to only contain lowercase + /// characters, numerals and symbols, as per the HTTP/2.0 specification + /// and header names internal representation within this library. + /// + /// + /// # Examples + /// + /// ``` + /// # use http::header::*; + /// // Parsing a standard header + /// let hdr = HeaderName::from_static("content-length"); + /// assert_eq!(CONTENT_LENGTH, hdr); + /// + /// // Parsing a custom header + /// let CUSTOM_HEADER: &'static str = "custom-header"; + /// + /// let a = HeaderName::from_lowercase(b"custom-header").unwrap(); + /// let b = HeaderName::from_static(CUSTOM_HEADER); + /// assert_eq!(a, b); + /// ``` + /// + /// ```should_panic + /// # use http::header::*; + /// # + /// // Parsing a header that contains invalid symbols(s): + /// HeaderName::from_static("content{}{}length"); // This line panics! + /// + /// // Parsing a header that contains invalid uppercase characters. + /// let a = HeaderName::from_static("foobar"); + /// let b = HeaderName::from_static("FOOBAR"); // This line panics! + /// ``` + pub fn from_static(src: &'static str) -> HeaderName { + let bytes = src.as_bytes(); + let mut buf = unsafe { mem::uninitialized() }; + match parse_hdr(bytes, &mut buf, &HEADER_CHARS_H2) { + Ok(hdr_name) => match hdr_name.inner { + Repr::Standard(std) => std.into(), + Repr::Custom(MaybeLower { buf: _, lower: true }) => { + let val = ByteStr::from_static(src); + Custom(val).into() + }, + Repr::Custom(MaybeLower { buf: _, lower: false }) => { + // With lower false, the string is left unchecked by + // parse_hdr and must be validated manually. + for &b in bytes.iter() { + if HEADER_CHARS_H2[b as usize] == 0 { + panic!("invalid header name") + } + } + + let val = ByteStr::from_static(src); + Custom(val).into() + } + }, + + Err(_) => panic!("invalid header name") + } + } + + /// Returns a `str` representation of the header. + /// + /// The returned string will always be lower case. + #[inline] + pub fn as_str(&self) -> &str { + match self.inner { + Repr::Standard(v) => v.as_str(), + Repr::Custom(ref v) => &*v.0, + } + } +} + +impl FromStr for HeaderName { + type Err = InvalidHeaderName; + + fn from_str(s: &str) -> Result { + HeaderName::from_bytes(s.as_bytes()) + .map_err(|_| InvalidHeaderName { + _priv: (), + }) + } +} + +impl AsRef for HeaderName { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl AsRef<[u8]> for HeaderName { + fn as_ref(&self) -> &[u8] { + self.as_str().as_bytes() + } +} + +impl Borrow for HeaderName { + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl fmt::Debug for HeaderName { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_str(), fmt) + } +} + +impl fmt::Display for HeaderName { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_str(), fmt) + } +} + +impl InvalidHeaderName { + fn new() -> InvalidHeaderName { + InvalidHeaderName { _priv: () } + } +} + +impl<'a> From<&'a HeaderName> for HeaderName { + fn from(src: &'a HeaderName) -> HeaderName { + src.clone() + } +} + +#[doc(hidden)] +impl From> for Bytes +where T: Into { + fn from(repr: Repr) -> Bytes { + match repr { + Repr::Standard(header) => + Bytes::from_static(header.as_str().as_bytes()), + Repr::Custom(header) => header.into() + } + } +} + +impl From for Bytes { + #[inline] + fn from(Custom(inner): Custom) -> Bytes { + Bytes::from(inner) + } +} + +impl From for Bytes { + #[inline] + fn from(name: HeaderName) -> Bytes { + name.inner.into() + } +} + +impl<'a> HttpTryFrom<&'a HeaderName> for HeaderName { + type Error = ::error::Never; + + #[inline] + fn try_from(t: &'a HeaderName) -> Result { + Ok(t.clone()) + } +} + +impl<'a> HttpTryFrom<&'a str> for HeaderName { + type Error = InvalidHeaderName; + #[inline] + fn try_from(s: &'a str) -> Result { + Self::from_bytes(s.as_bytes()) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for HeaderName { + type Error = InvalidHeaderName; + #[inline] + fn try_from(s: &'a [u8]) -> Result { + Self::from_bytes(s) + } +} + +impl HttpTryFrom for HeaderName { + type Error = InvalidHeaderNameBytes; + #[inline] + fn try_from(bytes: Bytes) -> Result { + Self::from_bytes(bytes.as_ref()).map_err(InvalidHeaderNameBytes) + } +} + +#[doc(hidden)] +impl From for HeaderName { + fn from(src: StandardHeader) -> HeaderName { + HeaderName { + inner: Repr::Standard(src), + } + } +} + +#[doc(hidden)] +impl From for HeaderName { + fn from(src: Custom) -> HeaderName { + HeaderName { inner: Repr::Custom(src) } + } +} + +impl<'a> PartialEq<&'a HeaderName> for HeaderName { + #[inline] + fn eq(&self, other: &&'a HeaderName) -> bool { + *self == **other + } +} + + +impl<'a> PartialEq for &'a HeaderName { + #[inline] + fn eq(&self, other: &HeaderName) -> bool { + *other == *self + } +} + +impl PartialEq for HeaderName { + /// Performs a case-insensitive comparison of the string against the header + /// name + /// + /// # Examples + /// + /// ``` + /// use http::header::CONTENT_LENGTH; + /// + /// assert_eq!(CONTENT_LENGTH, "content-length"); + /// assert_eq!(CONTENT_LENGTH, "Content-Length"); + /// assert_ne!(CONTENT_LENGTH, "content length"); + /// ``` + #[inline] + fn eq(&self, other: &str) -> bool { + eq_ignore_ascii_case(self.as_ref(), other.as_bytes()) + } +} + + +impl PartialEq for str { + /// Performs a case-insensitive comparison of the string against the header + /// name + /// + /// # Examples + /// + /// ``` + /// use http::header::CONTENT_LENGTH; + /// + /// assert_eq!(CONTENT_LENGTH, "content-length"); + /// assert_eq!(CONTENT_LENGTH, "Content-Length"); + /// assert_ne!(CONTENT_LENGTH, "content length"); + /// ``` + #[inline] + fn eq(&self, other: &HeaderName) -> bool { + *other == *self + } +} + +impl<'a> PartialEq<&'a str> for HeaderName { + /// Performs a case-insensitive comparison of the string against the header + /// name + #[inline] + fn eq(&self, other: &&'a str) -> bool { + *self == **other + } +} + + +impl<'a> PartialEq for &'a str { + /// Performs a case-insensitive comparison of the string against the header + /// name + #[inline] + fn eq(&self, other: &HeaderName) -> bool { + *other == *self + } +} + +impl fmt::Display for InvalidHeaderName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for InvalidHeaderName { + fn description(&self) -> &str { + "invalid HTTP header name" + } +} + +impl fmt::Display for InvalidHeaderNameBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidHeaderNameBytes { + fn description(&self) -> &str { + self.0.description() + } +} + +// ===== HdrName ===== + +impl<'a> HdrName<'a> { + fn custom(buf: &'a [u8], lower: bool) -> HdrName<'a> { + HdrName { + inner: Repr::Custom(MaybeLower { + buf: buf, + lower: lower, + }), + } + } + + pub fn from_bytes(hdr: &[u8], f: F) -> Result + where F: FnOnce(HdrName) -> U, + { + let mut buf = unsafe { mem::uninitialized() }; + let hdr = parse_hdr(hdr, &mut buf, &HEADER_CHARS)?; + Ok(f(hdr)) + } + + pub fn from_static(hdr: &'static str, f: F) -> U + where F: FnOnce(HdrName) -> U, + { + let mut buf = unsafe { mem::uninitialized() }; + let hdr = parse_hdr(hdr.as_bytes(), &mut buf, &HEADER_CHARS) + .expect("static str is invalid name"); + f(hdr) + } +} + +#[doc(hidden)] +impl<'a> From> for HeaderName { + fn from(src: HdrName<'a>) -> HeaderName { + match src.inner { + Repr::Standard(s) => { + HeaderName { + inner: Repr::Standard(s), + } + } + Repr::Custom(maybe_lower) => { + if maybe_lower.lower { + let buf = Bytes::from(&maybe_lower.buf[..]); + let byte_str = unsafe { ByteStr::from_utf8_unchecked(buf) }; + + HeaderName { + inner: Repr::Custom(Custom(byte_str)), + } + } else { + use bytes::{BufMut}; + let mut dst = BytesMut::with_capacity(maybe_lower.buf.len()); + + for b in maybe_lower.buf.iter() { + dst.put(HEADER_CHARS[*b as usize]); + } + + let buf = unsafe { ByteStr::from_utf8_unchecked(dst.freeze()) }; + + HeaderName { + inner: Repr::Custom(Custom(buf)), + } + } + } + } + } +} + +#[doc(hidden)] +impl<'a> PartialEq> for HeaderName { + #[inline] + fn eq(&self, other: &HdrName<'a>) -> bool { + match self.inner { + Repr::Standard(a) => { + match other.inner { + Repr::Standard(b) => a == b, + _ => false, + } + } + Repr::Custom(Custom(ref a)) => { + match other.inner { + Repr::Custom(ref b) => { + if b.lower { + a.as_bytes() == b.buf + } else { + eq_ignore_ascii_case(a.as_bytes(), b.buf) + } + } + _ => false, + } + } + } + } +} + +// ===== Custom ===== + +impl Hash for Custom { + #[inline] + fn hash(&self, hasher: &mut H) { + hasher.write(self.0.as_bytes()) + } +} + +// ===== MaybeLower ===== + +impl<'a> Hash for MaybeLower<'a> { + #[inline] + fn hash(&self, hasher: &mut H) { + if self.lower { + hasher.write(self.buf); + } else { + for &b in self.buf { + hasher.write(&[HEADER_CHARS[b as usize]]); + } + } + } +} + +// Assumes that the left hand side is already lower case +#[inline] +fn eq_ignore_ascii_case(lower: &[u8], s: &[u8]) -> bool { + if lower.len() != s.len() { + return false; + } + + lower.iter().zip(s).all(|(a, b)| { + *a == HEADER_CHARS[*b as usize] + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use self::StandardHeader::Vary; + + #[test] + fn test_bounds() { + fn check_bounds() {} + check_bounds::(); + } + + #[test] + fn test_parse_invalid_headers() { + for i in 0..128 { + let hdr = vec![1u8; i]; + assert!(HeaderName::from_bytes(&hdr).is_err(), "{} invalid header chars did not fail", i); + } + } + + #[test] + fn test_from_hdr_name() { + use self::StandardHeader::Vary; + + let name = HeaderName::from(HdrName { + inner: Repr::Standard(Vary), + }); + + assert_eq!(name.inner, Repr::Standard(Vary)); + + let name = HeaderName::from(HdrName { + inner: Repr::Custom(MaybeLower { + buf: b"hello-world", + lower: true, + }), + }); + + assert_eq!(name.inner, Repr::Custom(Custom(ByteStr::from_static("hello-world")))); + + let name = HeaderName::from(HdrName { + inner: Repr::Custom(MaybeLower { + buf: b"Hello-World", + lower: false, + }), + }); + + assert_eq!(name.inner, Repr::Custom(Custom(ByteStr::from_static("hello-world")))); + } + + #[test] + fn test_eq_hdr_name() { + use self::StandardHeader::Vary; + + let a = HeaderName { inner: Repr::Standard(Vary) }; + let b = HdrName { inner: Repr::Standard(Vary) }; + + assert_eq!(a, b); + + let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("vaary"))) }; + assert_ne!(a, b); + + let b = HdrName { inner: Repr::Custom(MaybeLower { + buf: b"vaary", + lower: true, + })}; + + assert_eq!(a, b); + + let b = HdrName { inner: Repr::Custom(MaybeLower { + buf: b"vaary", + lower: false, + })}; + + assert_eq!(a, b); + + let b = HdrName { inner: Repr::Custom(MaybeLower { + buf: b"VAARY", + lower: false, + })}; + + assert_eq!(a, b); + + let a = HeaderName { inner: Repr::Standard(Vary) }; + assert_ne!(a, b); + } + + #[test] + fn test_from_static_std() { + let a = HeaderName { inner: Repr::Standard(Vary) }; + + let b = HeaderName::from_static("vary"); + assert_eq!(a, b); + + let b = HeaderName::from_static("vaary"); + assert_ne!(a, b); + } + + #[test] + #[should_panic] + fn test_from_static_std_uppercase() { + HeaderName::from_static("Vary"); + } + + #[test] + #[should_panic] + fn test_from_static_std_symbol() { + HeaderName::from_static("vary{}"); + } + + // MaybeLower { lower: true } + #[test] + fn test_from_static_custom_short() { + let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("customheader"))) }; + let b = HeaderName::from_static("customheader"); + assert_eq!(a, b); + } + + #[test] + #[should_panic] + fn test_from_static_custom_short_uppercase() { + HeaderName::from_static("custom header"); + } + + #[test] + #[should_panic] + fn test_from_static_custom_short_symbol() { + HeaderName::from_static("CustomHeader"); + } + + // MaybeLower { lower: false } + #[test] + fn test_from_static_custom_long() { + let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static( + "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent" + ))) }; + let b = HeaderName::from_static( + "longer-than-63--thisheaderislongerthansixtythreecharactersandthushandleddifferent" + ); + assert_eq!(a, b); + } + + #[test] + #[should_panic] + fn test_from_static_custom_long_uppercase() { + HeaderName::from_static( + "Longer-Than-63--ThisHeaderIsLongerThanSixtyThreeCharactersAndThusHandledDifferent" + ); + } + + #[test] + #[should_panic] + fn test_from_static_custom_long_symbol() { + HeaderName::from_static( + "longer-than-63--thisheader{}{}{}{}islongerthansixtythreecharactersandthushandleddifferent" + ); + } + + #[test] + fn test_from_static_custom_single_char() { + let a = HeaderName { inner: Repr::Custom(Custom(ByteStr::from_static("a"))) }; + let b = HeaderName::from_static("a"); + assert_eq!(a, b); + } + + #[test] + #[should_panic] + fn test_from_static_empty() { + HeaderName::from_static(""); + } + + #[test] + fn test_all_tokens() { + HeaderName::from_static("!#$%&'*+-.^_`|~0123456789abcdefghijklmnopqrstuvwxyz"); + } +} diff --git a/http/src/header/value.rs b/http/src/header/value.rs new file mode 100644 index 000000000..a56baf790 --- /dev/null +++ b/http/src/header/value.rs @@ -0,0 +1,797 @@ +use bytes::{Bytes, BytesMut}; + +use std::{cmp, fmt, mem, str}; +use std::error::Error; +use std::str::FromStr; + +use ::convert::HttpTryFrom; +use ::error::Never; +use header::name::HeaderName; + +/// Represents an HTTP header field value. +/// +/// In practice, HTTP header field values are usually valid ASCII. However, the +/// HTTP spec allows for a header value to contain opaque bytes as well. In this +/// case, the header field value is not able to be represented as a string. +/// +/// To handle this, the `HeaderValue` is useable as a type and can be compared +/// with strings and implements `Debug`. A `to_str` fn is provided that returns +/// an `Err` if the header value contains non visible ascii characters. +#[derive(Clone, Hash)] +pub struct HeaderValue { + inner: Bytes, + is_sensitive: bool, +} + +/// A possible error when converting a `HeaderValue` from a string or byte +/// slice. +#[derive(Debug)] +pub struct InvalidHeaderValue { + _priv: (), +} + +/// A possible error when converting a `HeaderValue` from a string or byte +/// slice. +#[derive(Debug)] +pub struct InvalidHeaderValueBytes(InvalidHeaderValue); + +/// A possible error when converting a `HeaderValue` to a string representation. +/// +/// Header field values may contain opaque bytes, in which case it is not +/// possible to represent the value as a string. +#[derive(Debug)] +pub struct ToStrError { + _priv: (), +} + +impl HeaderValue { + /// Convert a static string to a `HeaderValue`. + /// + /// This function will not perform any copying, however the string is + /// checked to ensure that no invalid characters are present. Only visible + /// ASCII characters (32-127) are permitted. + /// + /// # Panics + /// + /// This function panics if the argument contains invalid header value + /// characters. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_static("hello"); + /// assert_eq!(val, "hello"); + /// ``` + #[inline] + pub fn from_static(src: &'static str) -> HeaderValue { + let bytes = src.as_bytes(); + for &b in bytes { + if !is_visible_ascii(b) { + panic!("invalid header value"); + } + } + + HeaderValue { + inner: Bytes::from_static(bytes), + is_sensitive: false, + } + } + + /// Attempt to convert a string to a `HeaderValue`. + /// + /// If the argument contains invalid header value characters, an error is + /// returned. Only visible ASCII characters (32-127) are permitted. Use + /// `from_bytes` to create a `HeaderValue` that includes opaque octets + /// (128-255). + /// + /// This function is intended to be replaced in the future by a `TryFrom` + /// implementation once the trait is stabilized in std. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_str("hello").unwrap(); + /// assert_eq!(val, "hello"); + /// ``` + /// + /// An invalid value + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_str("\n"); + /// assert!(val.is_err()); + /// ``` + #[inline] + pub fn from_str(src: &str) -> Result { + HeaderValue::try_from(src) + } + + /// Converts a HeaderName into a HeaderValue + /// + /// Since every valid HeaderName is a valid HeaderValue this is done infallibly. + /// + /// # Examples + /// + /// ``` + /// # use http::header::{HeaderValue, HeaderName}; + /// # use http::header::ACCEPT; + /// let val = HeaderValue::from_name(ACCEPT); + /// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap()); + /// ``` + #[inline] + pub fn from_name(name: HeaderName) -> HeaderValue { + name.into() + } + + /// Attempt to convert a byte slice to a `HeaderValue`. + /// + /// If the argument contains invalid header value bytes, an error is + /// returned. Only byte values between 32 and 255 (inclusive) are permitted, + /// excluding byte 127 (DEL). + /// + /// This function is intended to be replaced in the future by a `TryFrom` + /// implementation once the trait is stabilized in std. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap(); + /// assert_eq!(val, &b"hello\xfa"[..]); + /// ``` + /// + /// An invalid value + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_bytes(b"\n"); + /// assert!(val.is_err()); + /// ``` + #[inline] + pub fn from_bytes(src: &[u8]) -> Result { + HeaderValue::try_from(src) + } + + /// Attempt to convert a `Bytes` buffer to a `HeaderValue`. + /// + /// If the argument contains invalid header value bytes, an error is + /// returned. Only byte values between 32 and 255 (inclusive) are permitted, + /// excluding byte 127 (DEL). + /// + /// This function is intended to be replaced in the future by a `TryFrom` + /// implementation once the trait is stabilized in std. + #[inline] + pub fn from_shared(src: Bytes) -> Result { + HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes) + } + + /// Convert a `Bytes` directly into a `HeaderValue` without validating. + /// + /// This function does NOT validate that illegal bytes are not contained + /// within the buffer. + #[inline] + pub unsafe fn from_shared_unchecked(src: Bytes) -> HeaderValue { + if cfg!(debug_assertions) { + match HeaderValue::from_shared(src) { + Ok(val) => val, + Err(_err) => { + //TODO: if the Bytes were part of the InvalidHeaderValueBytes, + //this message could include the invalid bytes. + panic!("HeaderValue::from_shared_unchecked() with invalid bytes"); + }, + } + } else { + HeaderValue { + inner: src, + is_sensitive: false, + } + } + } + + fn try_from + Into>(src: T) -> Result { + for &b in src.as_ref() { + if !is_valid(b) { + return Err(InvalidHeaderValue { + _priv: (), + }); + } + } + Ok(HeaderValue { + inner: src.into(), + is_sensitive: false, + }) + } + + /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII + /// chars. + /// + /// This function will perform a scan of the header value, checking all the + /// characters. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_static("hello"); + /// assert_eq!(val.to_str().unwrap(), "hello"); + /// ``` + pub fn to_str(&self) -> Result<&str, ToStrError> { + let bytes = self.as_ref(); + + for &b in bytes { + if !is_visible_ascii(b) { + return Err(ToStrError { _priv: () }); + } + } + + unsafe { Ok(str::from_utf8_unchecked(bytes)) } + } + + /// Returns the length of `self`. + /// + /// This length is in bytes. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_static("hello"); + /// assert_eq!(val.len(), 5); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.as_ref().len() + } + + /// Returns true if the `HeaderValue` has a length of zero bytes. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_static(""); + /// assert!(val.is_empty()); + /// + /// let val = HeaderValue::from_static("hello"); + /// assert!(!val.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Converts a `HeaderValue` to a byte slice. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let val = HeaderValue::from_static("hello"); + /// assert_eq!(val.as_bytes(), b"hello"); + /// ``` + #[inline] + pub fn as_bytes(&self) -> &[u8] { + self.as_ref() + } + + /// Mark that the header value represents sensitive information. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let mut val = HeaderValue::from_static("my secret"); + /// + /// val.set_sensitive(true); + /// assert!(val.is_sensitive()); + /// + /// val.set_sensitive(false); + /// assert!(!val.is_sensitive()); + /// ``` + #[inline] + pub fn set_sensitive(&mut self, val: bool) { + self.is_sensitive = val; + } + + /// Returns `true` if the value represents sensitive data. + /// + /// Sensitive data could represent passwords or other data that should not + /// be stored on disk or in memory. This setting can be used by components + /// like caches to avoid storing the value. HPACK encoders must set the + /// header field to never index when `is_sensitive` returns true. + /// + /// Note that sensitivity is not factored into equality or ordering. + /// + /// # Examples + /// + /// ``` + /// # use http::header::HeaderValue; + /// let mut val = HeaderValue::from_static("my secret"); + /// + /// val.set_sensitive(true); + /// assert!(val.is_sensitive()); + /// + /// val.set_sensitive(false); + /// assert!(!val.is_sensitive()); + /// ``` + #[inline] + pub fn is_sensitive(&self) -> bool { + self.is_sensitive + } +} + +impl AsRef<[u8]> for HeaderValue { + #[inline] + fn as_ref(&self) -> &[u8] { + self.inner.as_ref() + } +} + +impl fmt::Debug for HeaderValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_sensitive { + f.write_str("Sensitive") + } else { + f.write_str("\"")?; + let mut from = 0; + let bytes = self.as_bytes(); + for (i, &b) in bytes.iter().enumerate() { + if !is_visible_ascii(b) || b == b'"' { + if from != i { + f.write_str(unsafe { + str::from_utf8_unchecked(&bytes[from..i]) + })?; + } + if b == b'"' { + f.write_str("\\\"")?; + } else { + write!(f, "\\x{:x}", b)?; + } + from = i + 1; + } + } + + f.write_str(unsafe { + str::from_utf8_unchecked(&bytes[from..]) + })?; + f.write_str("\"") + } + } +} + +impl From for HeaderValue { + #[inline] + fn from(h: HeaderName) -> HeaderValue { + HeaderValue { + inner: h.into(), + is_sensitive: false, + } + } +} + +macro_rules! from_integers { + ($($name:ident: $t:ident => $max_len:expr),*) => {$( + impl From<$t> for HeaderValue { + fn from(num: $t) -> HeaderValue { + let mut buf = if mem::size_of::() - 1 < $max_len { + // On 32bit platforms, BytesMut max inline size + // is 15 bytes, but the $max_len could be bigger. + // + // The likelihood of the number *actually* being + // that big is very small, so only allocate + // if the number needs that space. + // + // The largest decimal number in 15 digits: + // It wold be 10.pow(15) - 1, but this is a constant + // version. + if num as u64 > 999_999_999_999_999_999 { + BytesMut::with_capacity($max_len) + } else { + // fits inline... + BytesMut::new() + } + } else { + // full value fits inline, so don't allocate! + BytesMut::new() + }; + let _ = ::itoa::fmt(&mut buf, num); + HeaderValue { + inner: buf.freeze(), + is_sensitive: false, + } + } + } + + impl HttpTryFrom<$t> for HeaderValue { + type Error = Never; + + #[inline] + fn try_from(num: $t) -> Result { + Ok(num.into()) + } + } + + #[test] + fn $name() { + let n: $t = 55; + let val = HeaderValue::from(n); + assert_eq!(val, &n.to_string()); + + let n = ::std::$t::MAX; + let val = HeaderValue::from(n); + assert_eq!(val, &n.to_string()); + } + )*}; +} + +from_integers! { + // integer type => maximum decimal length + + // u8 purposely left off... HeaderValue::from(b'3') could be confusing + from_u16: u16 => 5, + from_i16: i16 => 6, + from_u32: u32 => 10, + from_i32: i32 => 11, + from_u64: u64 => 20, + from_i64: i64 => 20 +} + +#[cfg(target_pointer_width = "16")] +from_integers! { + from_usize: usize => 5, + from_isize: isize => 6 +} + +#[cfg(target_pointer_width = "32")] +from_integers! { + from_usize: usize => 10, + from_isize: isize => 11 +} + +#[cfg(target_pointer_width = "64")] +from_integers! { + from_usize: usize => 20, + from_isize: isize => 20 +} + +#[cfg(test)] +mod from_header_name_tests { + use super::*; + use header::map::HeaderMap; + use header::name; + + #[test] + fn it_can_insert_header_name_as_header_value() { + let mut map = HeaderMap::new(); + map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into()); + map.insert(name::ACCEPT, name::HeaderName::from_bytes(b"hello-world").unwrap().into()); + + assert_eq!( + map.get(name::UPGRADE).unwrap(), + HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap() + ); + + assert_eq!( + map.get(name::ACCEPT).unwrap(), + HeaderValue::from_bytes(b"hello-world").unwrap() + ); + } +} + +impl FromStr for HeaderValue { + type Err = InvalidHeaderValue; + + #[inline] + fn from_str(s: &str) -> Result { + HeaderValue::from_str(s) + } +} + +impl From for Bytes { + #[inline] + fn from(value: HeaderValue) -> Bytes { + value.inner + } +} + +impl<'a> From<&'a HeaderValue> for HeaderValue { + #[inline] + fn from(t: &'a HeaderValue) -> Self { + t.clone() + } +} + +impl<'a> HttpTryFrom<&'a HeaderValue> for HeaderValue { + type Error = ::error::Never; + + #[inline] + fn try_from(t: &'a HeaderValue) -> Result { + Ok(t.clone()) + } +} + +impl<'a> HttpTryFrom<&'a str> for HeaderValue { + type Error = InvalidHeaderValue; + + #[inline] + fn try_from(t: &'a str) -> Result { + t.parse() + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue { + type Error = InvalidHeaderValue; + + #[inline] + fn try_from(t: &'a [u8]) -> Result { + HeaderValue::from_bytes(t) + } +} + +impl HttpTryFrom for HeaderValue { + type Error = InvalidHeaderValueBytes; + + #[inline] + fn try_from(t: String) -> Result { + HeaderValue::from_shared(t.into()) + } +} + +impl HttpTryFrom for HeaderValue { + type Error = InvalidHeaderValueBytes; + + #[inline] + fn try_from(bytes: Bytes) -> Result { + HeaderValue::from_shared(bytes) + } +} + +impl HttpTryFrom for HeaderValue { + type Error = InvalidHeaderValue; + + #[inline] + fn try_from(name: HeaderName) -> Result { + // Infallable as header names have the same validations + Ok(name.into()) + } +} + +#[cfg(test)] +mod try_from_header_name_tests { + use super::*; + use header::name; + + #[test] + fn it_converts_using_try_from() { + assert_eq!( + HeaderValue::try_from(name::UPGRADE).unwrap(), + HeaderValue::from_bytes(b"upgrade").unwrap() + ); + } +} + +fn is_visible_ascii(b: u8) -> bool { + b >= 32 && b < 127 || b == b'\t' +} + +#[inline] +fn is_valid(b: u8) -> bool { + b >= 32 && b != 127 || b == b'\t' +} + +impl fmt::Display for InvalidHeaderValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for InvalidHeaderValue { + fn description(&self) -> &str { + "failed to parse header value" + } +} + +impl fmt::Display for InvalidHeaderValueBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidHeaderValueBytes { + fn description(&self) -> &str { + self.0.description() + } +} + +impl fmt::Display for ToStrError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ToStrError { + fn description(&self) -> &str { + "failed to convert header to a str" + } +} + +// ===== PartialEq / PartialOrd ===== + +impl PartialEq for HeaderValue { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + self.inner == other.inner + } +} + +impl Eq for HeaderValue {} + +impl PartialOrd for HeaderValue { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +impl Ord for HeaderValue { + #[inline] + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.inner.cmp(&other.inner) + } +} + +impl PartialEq for HeaderValue { + #[inline] + fn eq(&self, other: &str) -> bool { + self.inner == other.as_bytes() + } +} + +impl PartialEq<[u8]> for HeaderValue { + #[inline] + fn eq(&self, other: &[u8]) -> bool { + self.inner == other + } +} + +impl PartialOrd for HeaderValue { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + (*self.inner).partial_cmp(other.as_bytes()) + } +} + +impl PartialOrd<[u8]> for HeaderValue { + #[inline] + fn partial_cmp(&self, other: &[u8]) -> Option { + (*self.inner).partial_cmp(other) + } +} + +impl PartialEq for str { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + *other == *self + } +} + +impl PartialEq for [u8] { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + *other == *self + } +} + +impl PartialOrd for str { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + self.as_bytes().partial_cmp(other.as_bytes()) + } +} + +impl PartialOrd for [u8] { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + self.partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for HeaderValue { + #[inline] + fn eq(&self, other: &String) -> bool { + *self == &other[..] + } +} + +impl PartialOrd for HeaderValue { + #[inline] + fn partial_cmp(&self, other: &String) -> Option { + self.inner.partial_cmp(other.as_bytes()) + } +} + +impl PartialEq for String { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + *other == *self + } +} + +impl PartialOrd for String { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + self.as_bytes().partial_cmp(other.as_bytes()) + } +} + +impl<'a> PartialEq for &'a HeaderValue { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + **self == *other + } +} + +impl<'a> PartialOrd for &'a HeaderValue { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + (**self).partial_cmp(other) + } +} + +impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue + where HeaderValue: PartialEq +{ + #[inline] + fn eq(&self, other: &&'a T) -> bool { + *self == **other + } +} + +impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue + where HeaderValue: PartialOrd +{ + #[inline] + fn partial_cmp(&self, other: &&'a T) -> Option { + self.partial_cmp(*other) + } +} + +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &HeaderValue) -> bool { + *other == *self + } +} + +impl<'a> PartialOrd for &'a str { + #[inline] + fn partial_cmp(&self, other: &HeaderValue) -> Option { + self.as_bytes().partial_cmp(other.as_bytes()) + } +} + +#[test] +fn test_try_from() { + HeaderValue::try_from(vec![127]).unwrap_err(); +} + +#[test] +fn test_debug() { + let cases = &[ + ("hello", "\"hello\""), + ("hello \"world\"", "\"hello \\\"world\\\"\""), + ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""), + ]; + + for &(value, expected) in cases { + let val = HeaderValue::from_bytes(value.as_bytes()).unwrap(); + let actual = format!("{:?}", val); + assert_eq!(expected, actual); + } + + let mut sensitive = HeaderValue::from_static("password"); + sensitive.set_sensitive(true); + assert_eq!("Sensitive", format!("{:?}", sensitive)); +} diff --git a/http/src/lib.rs b/http/src/lib.rs new file mode 100644 index 000000000..7af843f89 --- /dev/null +++ b/http/src/lib.rs @@ -0,0 +1,206 @@ +#![doc(html_root_url = "https://docs.rs/http/0.1.17")] + +//! A general purpose library of common HTTP types +//! +//! This crate is a general purpose library for common types found when working +//! with the HTTP protocol. You'll find `Request` and `Response` types for +//! working as either a client or a server as well as all of their components. +//! Notably you'll find `Uri` for what a `Request` is requesting, a `Method` +//! for how it's being requested, a `StatusCode` for what sort of response came +//! back, a `Version` for how this was communicated, and +//! `HeaderName`/`HeaderValue` definitions to get grouped in a `HeaderMap` to +//! work with request/response headers. +//! +//! You will notably *not* find an implementation of sending requests or +//! spinning up a server in this crate. It's intended that this crate is the +//! "standard library" for HTTP clients and servers without dictating any +//! particular implementation. Note that this crate is still early on in its +//! lifecycle so the support libraries that integrate with the `http` crate are +//! a work in progress! Stay tuned and we'll be sure to highlight crates here +//! in the future. +//! +//! ## Requests and Responses +//! +//! Perhaps the main two types in this crate are the `Request` and `Response` +//! types. A `Request` could either be constructed to get sent off as a client +//! or it can also be received to generate a `Response` for a server. Similarly +//! as a client a `Response` is what you get after sending a `Request`, whereas +//! on a server you'll be manufacturing a `Response` to send back to the client. +//! +//! Each type has a number of accessors for the component fields. For as a +//! server you might want to inspect a requests URI to dispatch it: +//! +//! ``` +//! use http::{Request, Response}; +//! +//! fn response(req: Request<()>) -> http::Result> { +//! match req.uri().path() { +//! "/" => index(req), +//! "/foo" => foo(req), +//! "/bar" => bar(req), +//! _ => not_found(req), +//! } +//! } +//! # fn index(_req: Request<()>) -> http::Result> { panic!() } +//! # fn foo(_req: Request<()>) -> http::Result> { panic!() } +//! # fn bar(_req: Request<()>) -> http::Result> { panic!() } +//! # fn not_found(_req: Request<()>) -> http::Result> { panic!() } +//! ``` +//! +//! On a `Request` you'll also find accessors like `method` to return a +//! `Method` and `headers` to inspect the various headers. A `Response` +//! has similar methods for headers, the status code, etc. +//! +//! In addition to getters, request/response types also have mutable accessors +//! to edit the request/response: +//! +//! ``` +//! use http::{Response, StatusCode}; +//! use http::header::{CONTENT_TYPE, HeaderValue}; +//! +//! fn add_server_headers(response: &mut Response) { +//! response.headers_mut() +//! .insert(CONTENT_TYPE, HeaderValue::from_static("text/html")); +//! *response.status_mut() = StatusCode::OK; +//! } +//! ``` +//! +//! And finally, one of the most important aspects of requests/responses, the +//! body! The `Request` and `Response` types in this crate are *generic* in +//! what their body is. This allows downstream libraries to use different +//! representations such as `Request>`, `Response`, +//! `Request, Error = _>>`, or even +//! `Response` where the custom type was deserialized from JSON. +//! +//! The body representation is intentionally flexible to give downstream +//! libraries maximal flexibility in implementing the body as appropriate. +//! +//! ## HTTP Headers +//! +//! Another major piece of functionality in this library is HTTP header +//! interpretation and generation. The `HeaderName` type serves as a way to +//! define header *names*, or what's to the left of the colon. A `HeaderValue` +//! conversely is the header *value*, or what's to the right of a colon. +//! +//! For example, if you have an HTTP request that looks like: +//! +//! ```http +//! GET /foo HTTP/1.1 +//! Accept: text/html +//! ``` +//! +//! Then `"Accept"` is a `HeaderName` while `"text/html"` is a `HeaderValue`. +//! Each of these is a dedicated type to allow for a number of interesting +//! optimizations and to also encode the static guarantees of each type. For +//! example a `HeaderName` is always a valid `&str`, but a `HeaderValue` may +//! not be valid UTF-8. +//! +//! The most common header names are already defined for you as constant values +//! in the `header` module of this crate. For example: +//! +//! ``` +//! use http::header::{self, HeaderName}; +//! +//! let name: HeaderName = header::ACCEPT; +//! assert_eq!(name.as_str(), "accept"); +//! ``` +//! +//! You can, however, also parse header names from strings: +//! +//! ``` +//! use http::header::{self, HeaderName}; +//! +//! let name = "Accept".parse::().unwrap(); +//! assert_eq!(name, header::ACCEPT); +//! ``` +//! +//! Header values can be created from string literals through the `from_static` +//! function: +//! +//! ``` +//! use http::header::HeaderValue; +//! +//! let value = HeaderValue::from_static("text/html"); +//! assert_eq!(value.as_bytes(), b"text/html"); +//! ``` +//! +//! And header values can also be parsed like names: +//! +//! ``` +//! use http::header::HeaderValue; +//! +//! let value = "text/html"; +//! let value = value.parse::().unwrap(); +//! ``` +//! +//! Most HTTP requests and responses tend to come with more than one header, so +//! it's not too useful to just work with names and values only! This crate also +//! provides a `HeaderMap` type which is a specialized hash map for keys as +//! `HeaderName` and generic values. This type, like header names, is optimized +//! for common usage but should continue to scale with your needs over time. +//! +//! # URIs +//! +//! Each HTTP `Request` has an associated URI with it. This may just be a path +//! like `/index.html` but it could also be an absolute URL such as +//! `https://www.rust-lang.org/index.html`. A `URI` has a number of accessors to +//! interpret it: +//! +//! ``` +//! use http::Uri; +//! +//! let uri = "https://www.rust-lang.org/index.html".parse::().unwrap(); +//! +//! assert_eq!(uri.scheme(), Some("https")); +//! assert_eq!(uri.host(), Some("www.rust-lang.org")); +//! assert_eq!(uri.path(), "/index.html"); +//! assert_eq!(uri.query(), None); +//! ``` + +#![deny(warnings, missing_docs, missing_debug_implementations)] + +extern crate bytes; +extern crate fnv; +extern crate itoa; + +pub mod header; +pub mod method; +pub mod request; +pub mod response; +pub mod status; +pub mod version; +pub mod uri; + +mod byte_str; +mod convert; +mod error; +mod extensions; + +pub use convert::HttpTryFrom; +pub use error::{Error, Result}; +pub use extensions::Extensions; +#[doc(no_inline)] +pub use header::HeaderMap; +pub use method::Method; +pub use request::Request; +pub use response::Response; +pub use status::StatusCode; +pub use uri::Uri; +pub use version::Version; + +fn _assert_types() { + fn assert_send() {} + fn assert_sync() {} + + assert_send::>(); + assert_send::>(); + + assert_sync::>(); + assert_sync::>(); +} + +mod sealed { + /// Private trait to this crate to prevent traits from being implemented in + /// downstream crates. + pub trait Sealed {} +} diff --git a/http/src/method.rs b/http/src/method.rs new file mode 100644 index 000000000..7ba5ebf3e --- /dev/null +++ b/http/src/method.rs @@ -0,0 +1,422 @@ +//! The HTTP request method +//! +//! This module contains HTTP-method related structs and errors and such. The +//! main type of this module, `Method`, is also reexported at the root of the +//! crate as `http::Method` and is intended for import through that location +//! primarily. +//! +//! # Examples +//! +//! ``` +//! use http::Method; +//! +//! assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap()); +//! assert!(Method::GET.is_idempotent()); +//! assert_eq!(Method::POST.as_str(), "POST"); +//! ``` + +use HttpTryFrom; +use self::Inner::*; + +use std::{fmt, str}; +use std::convert::AsRef; +use std::error::Error; +use std::str::FromStr; + +/// The Request Method (VERB) +/// +/// This type also contains constants for a number of common HTTP methods such +/// as GET, POST, etc. +/// +/// Currently includes 8 variants representing the 8 methods defined in +/// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH, +/// and an Extension variant for all extensions. +/// +/// # Examples +/// +/// ``` +/// use http::Method; +/// +/// assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap()); +/// assert!(Method::GET.is_idempotent()); +/// assert_eq!(Method::POST.as_str(), "POST"); +/// ``` +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Method(Inner); + +/// A possible error value when converting `Method` from bytes. +#[derive(Debug)] +pub struct InvalidMethod { + _priv: (), +} + +#[derive(Clone, PartialEq, Eq, Hash)] +enum Inner { + Options, + Get, + Post, + Put, + Delete, + Head, + Trace, + Connect, + Patch, + // If the extension is short enough, store it inline + ExtensionInline([u8; MAX_INLINE], u8), + // Otherwise, allocate it + ExtensionAllocated(Box<[u8]>), +} + +const MAX_INLINE: usize = 15; + +// From the HTTP spec section 5.1.1, the HTTP method is case-sensitive and can +// contain the following characters: +// +// ``` +// method = token +// token = 1*tchar +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +// ``` +// +// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method +// +const METHOD_CHARS: [u8; 256] = [ + // 0 1 2 3 4 5 6 7 8 9 + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 1x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 2x + b'\0', b'\0', b'\0', b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 3x + b'\0', b'\0', b'*', b'+', b'\0', b'-', b'.', b'\0', b'0', b'1', // 4x + b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'\0', b'\0', // 5x + b'\0', b'\0', b'\0', b'\0', b'\0', b'A', b'B', b'C', b'D', b'E', // 6x + b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x + b'Z', b'\0', b'\0', b'\0', b'^', b'_', b'`', b'a', b'b', b'c', // 9x + b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x + b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x + b'x', b'y', b'z', b'\0', b'|', b'\0', b'~', b'\0', b'\0', b'\0', // 12x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 13x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 14x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 15x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 16x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 17x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 18x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 19x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 20x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 21x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 22x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 23x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 24x + b'\0', b'\0', b'\0', b'\0', b'\0', b'\0' // 25x +]; + + +impl Method { + /// GET + pub const GET: Method = Method(Get); + + /// POST + pub const POST: Method = Method(Post); + + /// PUT + pub const PUT: Method = Method(Put); + + /// DELETE + pub const DELETE: Method = Method(Delete); + + /// HEAD + pub const HEAD: Method = Method(Head); + + /// OPTIONS + pub const OPTIONS: Method = Method(Options); + + /// CONNECT + pub const CONNECT: Method = Method(Connect); + + /// PATCH + pub const PATCH: Method = Method(Patch); + + /// TRACE + pub const TRACE: Method = Method(Trace); + + /// Converts a slice of bytes to an HTTP method. + pub fn from_bytes(src: &[u8]) -> Result { + match src.len() { + 0 => { + Err(InvalidMethod::new()) + } + 3 => { + match src { + b"GET" => Ok(Method(Get)), + b"PUT" => Ok(Method(Put)), + _ => Method::extension_inline(src), + } + } + 4 => { + match src { + b"POST" => Ok(Method(Post)), + b"HEAD" => Ok(Method(Head)), + _ => Method::extension_inline(src), + } + } + 5 => { + match src { + b"PATCH" => Ok(Method(Patch)), + b"TRACE" => Ok(Method(Trace)), + _ => Method::extension_inline(src), + } + } + 6 => { + match src { + b"DELETE" => Ok(Method(Delete)), + _ => Method::extension_inline(src), + } + } + 7 => { + match src { + b"OPTIONS" => Ok(Method(Options)), + b"CONNECT" => Ok(Method(Connect)), + _ => Method::extension_inline(src), + } + } + _ => { + if src.len() < MAX_INLINE { + Method::extension_inline(src) + } else { + let mut data: Vec = vec![0; src.len()]; + + write_checked(src, &mut data)?; + + Ok(Method(ExtensionAllocated(data.into_boxed_slice()))) + } + } + } + } + + fn extension_inline(src: &[u8]) -> Result { + let mut data: [u8; MAX_INLINE] = Default::default(); + + write_checked(src, &mut data)?; + + Ok(Method(ExtensionInline(data, src.len() as u8))) + } + + /// Whether a method is considered "safe", meaning the request is + /// essentially read-only. + /// + /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1) + /// for more words. + pub fn is_safe(&self) -> bool { + match self.0 { + Get | Head | Options | Trace => true, + _ => false + } + } + + /// Whether a method is considered "idempotent", meaning the request has + /// the same result if executed multiple times. + /// + /// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for + /// more words. + pub fn is_idempotent(&self) -> bool { + if self.is_safe() { + true + } else { + match self.0 { + Put | Delete => true, + _ => false + } + } + } + + /// Return a &str representation of the HTTP method + #[inline] + pub fn as_str(&self) -> &str { + match self.0 { + Options => "OPTIONS", + Get => "GET", + Post => "POST", + Put => "PUT", + Delete => "DELETE", + Head => "HEAD", + Trace => "TRACE", + Connect => "CONNECT", + Patch => "PATCH", + ExtensionInline(ref data, len) => { + unsafe { + str::from_utf8_unchecked(&data[..len as usize]) + } + } + ExtensionAllocated(ref data) => { + unsafe { + str::from_utf8_unchecked(data) + } + } + } + } +} + +fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> { + for (i, &b) in src.iter().enumerate() { + let b = METHOD_CHARS[b as usize]; + + if b == 0 { + return Err(InvalidMethod::new()); + } + + dst[i] = b; + } + + Ok(()) +} + +impl AsRef for Method { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'a> PartialEq<&'a Method> for Method { + #[inline] + fn eq(&self, other: & &'a Method) -> bool { + self == *other + } +} + +impl<'a> PartialEq for &'a Method { + #[inline] + fn eq(&self, other: &Method) -> bool { + *self == other + } +} + +impl PartialEq for Method { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_ref() == other + } +} + +impl PartialEq for str { + #[inline] + fn eq(&self, other: &Method) -> bool { + self == other.as_ref() + } +} + +impl<'a> PartialEq<&'a str> for Method { + #[inline] + fn eq(&self, other: &&'a str) -> bool { + self.as_ref() == *other + } +} + +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &Method) -> bool { + *self == other.as_ref() + } +} + +impl fmt::Debug for Method { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_ref()) + } +} + +impl fmt::Display for Method { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.as_ref()) + } +} + +impl Default for Method { + #[inline] + fn default() -> Method { + Method::GET + } +} + +impl<'a> From<&'a Method> for Method { + #[inline] + fn from(t: &'a Method) -> Self { + t.clone() + } +} + +impl<'a> HttpTryFrom<&'a Method> for Method { + type Error = ::error::Never; + + #[inline] + fn try_from(t: &'a Method) -> Result { + Ok(t.clone()) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for Method { + type Error = InvalidMethod; + + #[inline] + fn try_from(t: &'a [u8]) -> Result { + Method::from_bytes(t) + } +} + +impl<'a> HttpTryFrom<&'a str> for Method { + type Error = InvalidMethod; + + #[inline] + fn try_from(t: &'a str) -> Result { + HttpTryFrom::try_from(t.as_bytes()) + } +} + +impl FromStr for Method { + type Err = InvalidMethod; + + #[inline] + fn from_str(t: &str) -> Result { + HttpTryFrom::try_from(t) + } +} + +impl InvalidMethod { + fn new() -> InvalidMethod { + InvalidMethod { + _priv: (), + } + } +} + +impl fmt::Display for InvalidMethod { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl Error for InvalidMethod { + fn description(&self) -> &str { + "invalid HTTP method" + } +} + +#[test] +fn test_method_eq() { + assert_eq!(Method::GET, Method::GET); + assert_eq!(Method::GET, "GET"); + assert_eq!(&Method::GET, "GET"); + + assert_eq!("GET", Method::GET); + assert_eq!("GET", &Method::GET); + + assert_eq!(&Method::GET, Method::GET); + assert_eq!(Method::GET, &Method::GET); +} + +#[test] +fn test_invalid_method() { + assert!(Method::from_str("").is_err()); + assert!(Method::from_bytes(b"").is_err()); +} diff --git a/http/src/request.rs b/http/src/request.rs new file mode 100644 index 000000000..ac76470e1 --- /dev/null +++ b/http/src/request.rs @@ -0,0 +1,1069 @@ +//! HTTP request types. +//! +//! This module contains structs related to HTTP requests, notably the +//! `Request` type itself as well as a builder to create requests. Typically +//! you'll import the `http::Request` type rather than reaching into this +//! module itself. +//! +//! # Examples +//! +//! Creating a `Request` to send +//! +//! ```no_run +//! use http::{Request, Response}; +//! +//! let mut request = Request::builder(); +//! request.uri("https://www.rust-lang.org/") +//! .header("User-Agent", "my-awesome-agent/1.0"); +//! +//! if needs_awesome_header() { +//! request.header("Awesome", "yes"); +//! } +//! +//! let response = send(request.body(()).unwrap()); +//! +//! # fn needs_awesome_header() -> bool { +//! # true +//! # } +//! # +//! fn send(req: Request<()>) -> Response<()> { +//! // ... +//! # panic!() +//! } +//! ``` +//! +//! Inspecting a request to see what was sent. +//! +//! ``` +//! use http::{Request, Response, StatusCode}; +//! +//! fn respond_to(req: Request<()>) -> http::Result> { +//! if req.uri() != "/awesome-url" { +//! return Response::builder() +//! .status(StatusCode::NOT_FOUND) +//! .body(()) +//! } +//! +//! let has_awesome_header = req.headers().contains_key("Awesome"); +//! let body = req.body(); +//! +//! // ... +//! # panic!() +//! } +//! ``` + +use std::any::Any; +use std::fmt; + +use {Uri, Error, Result, HttpTryFrom, Extensions}; +use header::{HeaderMap, HeaderName, HeaderValue}; +use method::Method; +use version::Version; + +/// Represents an HTTP request. +/// +/// An HTTP request consists of a head and a potentially optional body. The body +/// component is generic, enabling arbitrary types to represent the HTTP body. +/// For example, the body could be `Vec`, a `Stream` of byte chunks, or a +/// value that has been deserialized. +/// +/// # Examples +/// +/// Creating a `Request` to send +/// +/// ```no_run +/// use http::{Request, Response}; +/// +/// let mut request = Request::builder(); +/// request.uri("https://www.rust-lang.org/") +/// .header("User-Agent", "my-awesome-agent/1.0"); +/// +/// if needs_awesome_header() { +/// request.header("Awesome", "yes"); +/// } +/// +/// let response = send(request.body(()).unwrap()); +/// +/// # fn needs_awesome_header() -> bool { +/// # true +/// # } +/// # +/// fn send(req: Request<()>) -> Response<()> { +/// // ... +/// # panic!() +/// } +/// ``` +/// +/// Inspecting a request to see what was sent. +/// +/// ``` +/// use http::{Request, Response, StatusCode}; +/// +/// fn respond_to(req: Request<()>) -> http::Result> { +/// if req.uri() != "/awesome-url" { +/// return Response::builder() +/// .status(StatusCode::NOT_FOUND) +/// .body(()) +/// } +/// +/// let has_awesome_header = req.headers().contains_key("Awesome"); +/// let body = req.body(); +/// +/// // ... +/// # panic!() +/// } +/// ``` +/// +/// Deserialize a request of bytes via json: +/// +/// ``` +/// # extern crate serde; +/// # extern crate serde_json; +/// # extern crate http; +/// use http::Request; +/// use serde::de; +/// +/// fn deserialize(req: Request>) -> serde_json::Result> +/// where for<'de> T: de::Deserialize<'de>, +/// { +/// let (parts, body) = req.into_parts(); +/// let body = serde_json::from_slice(&body)?; +/// Ok(Request::from_parts(parts, body)) +/// } +/// # +/// # fn main() {} +/// ``` +/// +/// Or alternatively, serialize the body of a request to json +/// +/// ``` +/// # extern crate serde; +/// # extern crate serde_json; +/// # extern crate http; +/// use http::Request; +/// use serde::ser; +/// +/// fn serialize(req: Request) -> serde_json::Result>> +/// where T: ser::Serialize, +/// { +/// let (parts, body) = req.into_parts(); +/// let body = serde_json::to_vec(&body)?; +/// Ok(Request::from_parts(parts, body)) +/// } +/// # +/// # fn main() {} +/// ``` +pub struct Request { + head: Parts, + body: T, +} + +/// Component parts of an HTTP `Request` +/// +/// The HTTP request head consists of a method, uri, version, and a set of +/// header fields. +pub struct Parts { + /// The request's method + pub method: Method, + + /// The request's URI + pub uri: Uri, + + /// The request's version + pub version: Version, + + /// The request's headers + pub headers: HeaderMap, + + /// The request's extensions + pub extensions: Extensions, + + _priv: (), +} + +/// An HTTP request builder +/// +/// This type can be used to construct an instance or `Request` +/// through a builder-like pattern. +#[derive(Debug)] +pub struct Builder { + head: Option, + err: Option, +} + +impl Request<()> { + /// Creates a new builder-style object to manufacture a `Request` + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request = Request::builder() + /// .method("GET") + /// .uri("https://www.rust-lang.org/") + /// .header("X-Custom-Foo", "Bar") + /// .body(()) + /// .unwrap(); + /// ``` + #[inline] + pub fn builder() -> Builder { + Builder::new() + } + + + /// Creates a new `Builder` initialized with a GET method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::get("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn get(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::GET).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a PUT method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::put("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn put(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::PUT).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a POST method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::post("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn post(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::POST).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a DELETE method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::delete("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn delete(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::DELETE).uri(uri); + b + } + + /// Creates a new `Builder` initialized with an OPTIONS method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::options("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// # assert_eq!(*request.method(), Method::OPTIONS); + /// ``` + pub fn options(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::OPTIONS).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a HEAD method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::head("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn head(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::HEAD).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a CONNECT method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::connect("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn connect(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::CONNECT).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a PATCH method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::patch("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn patch(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::PATCH).uri(uri); + b + } + + /// Creates a new `Builder` initialized with a TRACE method and the given URI. + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Request`. + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::trace("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn trace(uri: T) -> Builder + where Uri: HttpTryFrom { + let mut b = Builder::new(); + b.method(Method::TRACE).uri(uri); + b + } +} + +impl Request { + /// Creates a new blank `Request` with the body + /// + /// The component parts of this request will be set to their default, e.g. + /// the GET method, no headers, etc. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request = Request::new("hello world"); + /// + /// assert_eq!(*request.method(), Method::GET); + /// assert_eq!(*request.body(), "hello world"); + /// ``` + #[inline] + pub fn new(body: T) -> Request { + Request { + head: Parts::new(), + body: body, + } + } + + /// Creates a new `Request` with the given components parts and body. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request = Request::new("hello world"); + /// let (mut parts, body) = request.into_parts(); + /// parts.method = Method::POST; + /// + /// let request = Request::from_parts(parts, body); + /// ``` + #[inline] + pub fn from_parts(parts: Parts, body: T) -> Request { + Request { + head: parts, + body: body, + } + } + + /// Returns a reference to the associated HTTP method. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request<()> = Request::default(); + /// assert_eq!(*request.method(), Method::GET); + /// ``` + #[inline] + pub fn method(&self) -> &Method { + &self.head.method + } + + /// Returns a mutable reference to the associated HTTP method. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut request: Request<()> = Request::default(); + /// *request.method_mut() = Method::PUT; + /// assert_eq!(*request.method(), Method::PUT); + /// ``` + #[inline] + pub fn method_mut(&mut self) -> &mut Method { + &mut self.head.method + } + + /// Returns a reference to the associated URI. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request<()> = Request::default(); + /// assert_eq!(*request.uri(), *"/"); + /// ``` + #[inline] + pub fn uri(&self) -> &Uri { + &self.head.uri + } + + /// Returns a mutable reference to the associated URI. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut request: Request<()> = Request::default(); + /// *request.uri_mut() = "/hello".parse().unwrap(); + /// assert_eq!(*request.uri(), *"/hello"); + /// ``` + #[inline] + pub fn uri_mut(&mut self) -> &mut Uri { + &mut self.head.uri + } + + /// Returns the associated version. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request<()> = Request::default(); + /// assert_eq!(request.version(), Version::HTTP_11); + /// ``` + #[inline] + pub fn version(&self) -> Version { + self.head.version + } + + /// Returns a mutable reference to the associated version. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut request: Request<()> = Request::default(); + /// *request.version_mut() = Version::HTTP_2; + /// assert_eq!(request.version(), Version::HTTP_2); + /// ``` + #[inline] + pub fn version_mut(&mut self) -> &mut Version { + &mut self.head.version + } + + /// Returns a reference to the associated header field map. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request<()> = Request::default(); + /// assert!(request.headers().is_empty()); + /// ``` + #[inline] + pub fn headers(&self) -> &HeaderMap { + &self.head.headers + } + + /// Returns a mutable reference to the associated header field map. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::*; + /// let mut request: Request<()> = Request::default(); + /// request.headers_mut().insert(HOST, HeaderValue::from_static("world")); + /// assert!(!request.headers().is_empty()); + /// ``` + #[inline] + pub fn headers_mut(&mut self) -> &mut HeaderMap { + &mut self.head.headers + } + + /// Returns a reference to the associated extensions. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request<()> = Request::default(); + /// assert!(request.extensions().get::().is_none()); + /// ``` + #[inline] + pub fn extensions(&self) -> &Extensions { + &self.head.extensions + } + + /// Returns a mutable reference to the associated extensions. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::*; + /// let mut request: Request<()> = Request::default(); + /// request.extensions_mut().insert("hello"); + /// assert_eq!(request.extensions().get(), Some(&"hello")); + /// ``` + #[inline] + pub fn extensions_mut(&mut self) -> &mut Extensions { + &mut self.head.extensions + } + + /// Returns a reference to the associated HTTP body. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request: Request = Request::default(); + /// assert!(request.body().is_empty()); + /// ``` + #[inline] + pub fn body(&self) -> &T { + &self.body + } + + /// Returns a mutable reference to the associated HTTP body. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut request: Request = Request::default(); + /// request.body_mut().push_str("hello world"); + /// assert!(!request.body().is_empty()); + /// ``` + #[inline] + pub fn body_mut(&mut self) -> &mut T { + &mut self.body + } + + + /// Consumes the request, returning just the body. + /// + /// # Examples + /// + /// ``` + /// # use http::Request; + /// let request = Request::new(10); + /// let body = request.into_body(); + /// assert_eq!(body, 10); + /// ``` + #[inline] + pub fn into_body(self) -> T { + self.body + } + + /// Consumes the request returning the head and body parts. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request = Request::new(()); + /// let (parts, body) = request.into_parts(); + /// assert_eq!(parts.method, Method::GET); + /// ``` + #[inline] + pub fn into_parts(self) -> (Parts, T) { + (self.head, self.body) + } + + /// Consumes the request returning a new request with body mapped to the + /// return type of the passed in function. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let request = Request::builder().body("some string").unwrap(); + /// let mapped_request: Request<&[u8]> = request.map(|b| { + /// assert_eq!(b, "some string"); + /// b.as_bytes() + /// }); + /// assert_eq!(mapped_request.body(), &"some string".as_bytes()); + /// ``` + #[inline] + pub fn map(self, f: F) -> Request + where F: FnOnce(T) -> U + { + Request { body: f(self.body), head: self.head } + } +} + +impl Default for Request { + fn default() -> Request { + Request::new(T::default()) + } +} + +impl fmt::Debug for Request { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Request") + .field("method", self.method()) + .field("uri", self.uri()) + .field("version", &self.version()) + .field("headers", self.headers()) + // omits Extensions because not useful + .field("body", self.body()) + .finish() + } +} + +impl Parts { + /// Creates a new default instance of `Parts` + fn new() -> Parts { + Parts{ + method: Method::default(), + uri: Uri::default(), + version: Version::default(), + headers: HeaderMap::default(), + extensions: Extensions::default(), + _priv: (), + } + } +} + +impl fmt::Debug for Parts { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Parts") + .field("method", &self.method) + .field("uri", &self.uri) + .field("version", &self.version) + .field("headers", &self.headers) + // omits Extensions because not useful + // omits _priv because not useful + .finish() + } +} + +impl Builder { + /// Creates a new default instance of `Builder` to construct a `Request`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let req = request::Builder::new() + /// .method("POST") + /// .body(()) + /// .unwrap(); + /// ``` + #[inline] + pub fn new() -> Builder { + Builder::default() + } + + /// Set the HTTP method for this request. + /// + /// This function will configure the HTTP method of the `Request` that will + /// be returned from `Builder::build`. + /// + /// By default this is `GET`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let req = Request::builder() + /// .method("POST") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn method(&mut self, method: T) -> &mut Builder + where Method: HttpTryFrom, + { + if let Some(head) = head(&mut self.head, &self.err) { + match HttpTryFrom::try_from(method) { + Ok(s) => head.method = s, + Err(e) => self.err = Some(e.into()), + } + } + self + } + + /// Get the HTTP Method for this request. + /// + /// By default this is `GET`. + /// if builder has error, returns None. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let mut req = Request::builder(); + /// assert_eq!(req.method_ref(),Some(&Method::GET)); + /// req.method("POST"); + /// assert_eq!(req.method_ref(),Some(&Method::POST)); + /// req.method("DELETE"); + /// assert_eq!(req.method_ref(),Some(&Method::DELETE)); + /// ``` + pub fn method_ref(&self) -> Option<&Method> + { + if self.err.is_some() { + return None + } + match self.head { + Some(ref head) => Some(&head.method), + None => None + } + } + + /// Set the URI for this request. + /// + /// This function will configure the URI of the `Request` that will + /// be returned from `Builder::build`. + /// + /// By default this is `/`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let req = Request::builder() + /// .uri("https://www.rust-lang.org/") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn uri(&mut self, uri: T) -> &mut Builder + where Uri: HttpTryFrom, + { + if let Some(head) = head(&mut self.head, &self.err) { + match HttpTryFrom::try_from(uri) { + Ok(s) => head.uri = s, + Err(e) => self.err = Some(e.into()), + } + } + self + } + + /// Get the URI for this request + /// + /// By default this is `/` + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let mut req = Request::builder(); + /// assert_eq!(req.uri_ref().unwrap().to_string(), "/" ); + /// req.uri("https://www.rust-lang.org/"); + /// assert_eq!(req.uri_ref().unwrap().to_string(), "https://www.rust-lang.org/" ); + /// ``` + pub fn uri_ref(&self) -> Option<&Uri> + { + if self.err.is_some() { + return None; + } + match self.head + { + Some(ref head) => Some(&head.uri), + None => None + } + } + + /// Set the HTTP version for this request. + /// + /// This function will configure the HTTP version of the `Request` that + /// will be returned from `Builder::build`. + /// + /// By default this is HTTP/1.1 + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let req = Request::builder() + /// .version(Version::HTTP_2) + /// .body(()) + /// .unwrap(); + /// ``` + pub fn version(&mut self, version: Version) -> &mut Builder { + if let Some(head) = head(&mut self.head, &self.err) { + head.version = version; + } + self + } + + /// Appends a header to this request builder. + /// + /// This function will append the provided key/value as a header to the + /// internal `HeaderMap` being constructed. Essentially this is equivalent + /// to calling `HeaderMap::append`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// + /// let req = Request::builder() + /// .header("Accept", "text/html") + /// .header("X-Custom-Foo", "bar") + /// .body(()) + /// .unwrap(); + /// ``` + pub fn header(&mut self, key: K, value: V) -> &mut Builder + where HeaderName: HttpTryFrom, + HeaderValue: HttpTryFrom + { + if let Some(head) = head(&mut self.head, &self.err) { + match >::try_from(key) { + Ok(key) => { + match >::try_from(value) { + Ok(value) => { head.headers.append(key, value); } + Err(e) => self.err = Some(e.into()), + } + }, + Err(e) => self.err = Some(e.into()), + }; + } + self + } + + /// Get header on this request builder. + /// when builder has error returns None + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// # use http::request::Builder; + /// let mut req = Request::builder(); + /// req.header("Accept", "text/html") + /// .header("X-Custom-Foo", "bar"); + /// let headers = req.headers_ref().unwrap(); + /// assert_eq!( headers["Accept"], "text/html" ); + /// assert_eq!( headers["X-Custom-Foo"], "bar" ); + /// ``` + pub fn headers_ref(&self) -> Option<&HeaderMap> { + if self.err.is_some() { + return None; + } + match self.head + { + Some(ref head) => Some(&head.headers), + None => None + } + } + + /// Get header on this request builder. + /// when builder has error returns None + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// # use http::request::Builder; + /// let mut req = Request::builder(); + /// { + /// let headers = req.headers_mut().unwrap(); + /// headers.insert("Accept", HeaderValue::from_static("text/html")); + /// headers.insert("X-Custom-Foo", HeaderValue::from_static("bar")); + /// } + /// let headers = req.headers_ref().unwrap(); + /// assert_eq!( headers["Accept"], "text/html" ); + /// assert_eq!( headers["X-Custom-Foo"], "bar" ); + /// ``` + pub fn headers_mut(&mut self) -> Option<&mut HeaderMap> { + if self.err.is_some() { + return None; + } + match self.head + { + Some(ref mut head) => Some(&mut head.headers), + None => None + } + } + + /// Adds an extension to this builder + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let req = Request::builder() + /// .extension("My Extension") + /// .body(()) + /// .unwrap(); + /// + /// assert_eq!(req.extensions().get::<&'static str>(), + /// Some(&"My Extension")); + /// ``` + pub fn extension(&mut self, extension: T) -> &mut Builder + where T: Any + Send + Sync + 'static, + { + if let Some(head) = head(&mut self.head, &self.err) { + head.extensions.insert(extension); + } + self + } + + fn take_parts(&mut self) -> Result { + let ret = self.head.take().expect("cannot reuse request builder"); + if let Some(e) = self.err.take() { + return Err(e) + } + Ok(ret) + } + + /// "Consumes" this builder, using the provided `body` to return a + /// constructed `Request`. + /// + /// # Errors + /// + /// This function may return an error if any previously configured argument + /// failed to parse or get converted to the internal representation. For + /// example if an invalid `head` was specified via `header("Foo", + /// "Bar\r\n")` the error will be returned when this function is called + /// rather than when `header` was called. + /// + /// # Panics + /// + /// This method will panic if the builder is reused. The `body` function can + /// only be called once. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let request = Request::builder() + /// .body(()) + /// .unwrap(); + /// ``` + pub fn body(&mut self, body: T) -> Result> { + Ok(Request { + head: self.take_parts()?, + body: body, + }) + } +} + +fn head<'a>(head: &'a mut Option, err: &Option) + -> Option<&'a mut Parts> +{ + if err.is_some() { + return None + } + head.as_mut() +} + +impl Default for Builder { + #[inline] + fn default() -> Builder { + Builder { + head: Some(Parts::new()), + err: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_can_map_a_body_from_one_type_to_another() { + let request= Request::builder().body("some string").unwrap(); + let mapped_request = request.map(|s| { + assert_eq!(s, "some string"); + 123u32 + }); + assert_eq!(mapped_request.body(), &123u32); + } +} diff --git a/http/src/response.rs b/http/src/response.rs new file mode 100644 index 000000000..fc877509f --- /dev/null +++ b/http/src/response.rs @@ -0,0 +1,787 @@ +//! HTTP response types. +//! +//! This module contains structs related to HTTP responses, notably the +//! `Response` type itself as well as a builder to create responses. Typically +//! you'll import the `http::Response` type rather than reaching into this +//! module itself. +//! +//! # Examples +//! +//! Creating a `Response` to return +//! +//! ``` +//! use http::{Request, Response, StatusCode}; +//! +//! fn respond_to(req: Request<()>) -> http::Result> { +//! let mut response = Response::builder(); +//! response.header("Foo", "Bar") +//! .status(StatusCode::OK); +//! +//! if req.headers().contains_key("Another-Header") { +//! response.header("Another-Header", "Ack"); +//! } +//! +//! response.body(()) +//! } +//! ``` +//! +//! A simple 404 handler +//! +//! ``` +//! use http::{Request, Response, StatusCode}; +//! +//! fn not_found(_req: Request<()>) -> http::Result> { +//! Response::builder() +//! .status(StatusCode::NOT_FOUND) +//! .body(()) +//! } +//! ``` +//! +//! Or otherwise inspecting the result of a request: +//! +//! ```no_run +//! use http::{Request, Response}; +//! +//! fn get(url: &str) -> http::Result> { +//! // ... +//! # panic!() +//! } +//! +//! let response = get("https://www.rust-lang.org/").unwrap(); +//! +//! if !response.status().is_success() { +//! panic!("failed to get a successful response status!"); +//! } +//! +//! if let Some(date) = response.headers().get("Date") { +//! // we've got a `Date` header! +//! } +//! +//! let body = response.body(); +//! // ... +//! ``` + +use std::any::Any; +use std::fmt; + +use {Error, Result, HttpTryFrom, Extensions}; +use header::{HeaderMap, HeaderName, HeaderValue}; +use status::StatusCode; +use version::Version; + +/// Represents an HTTP response +/// +/// An HTTP response consists of a head and a potentially optional body. The body +/// component is generic, enabling arbitrary types to represent the HTTP body. +/// For example, the body could be `Vec`, a `Stream` of byte chunks, or a +/// value that has been deserialized. +/// +/// Typically you'll work with responses on the client side as the result of +/// sending a `Request` and on the server you'll be generating a `Request` to +/// send back to the client. +/// +/// # Examples +/// +/// Creating a `Response` to return +/// +/// ``` +/// use http::{Request, Response, StatusCode}; +/// +/// fn respond_to(req: Request<()>) -> http::Result> { +/// let mut response = Response::builder(); +/// response.header("Foo", "Bar") +/// .status(StatusCode::OK); +/// +/// if req.headers().contains_key("Another-Header") { +/// response.header("Another-Header", "Ack"); +/// } +/// +/// response.body(()) +/// } +/// ``` +/// +/// A simple 404 handler +/// +/// ``` +/// use http::{Request, Response, StatusCode}; +/// +/// fn not_found(_req: Request<()>) -> http::Result> { +/// Response::builder() +/// .status(StatusCode::NOT_FOUND) +/// .body(()) +/// } +/// ``` +/// +/// Or otherwise inspecting the result of a request: +/// +/// ```no_run +/// use http::{Request, Response}; +/// +/// fn get(url: &str) -> http::Result> { +/// // ... +/// # panic!() +/// } +/// +/// let response = get("https://www.rust-lang.org/").unwrap(); +/// +/// if !response.status().is_success() { +/// panic!("failed to get a successful response status!"); +/// } +/// +/// if let Some(date) = response.headers().get("Date") { +/// // we've got a `Date` header! +/// } +/// +/// let body = response.body(); +/// // ... +/// ``` +/// +/// Deserialize a response of bytes via json: +/// +/// ``` +/// # extern crate serde; +/// # extern crate serde_json; +/// # extern crate http; +/// use http::Response; +/// use serde::de; +/// +/// fn deserialize(req: Response>) -> serde_json::Result> +/// where for<'de> T: de::Deserialize<'de>, +/// { +/// let (parts, body) = req.into_parts(); +/// let body = serde_json::from_slice(&body)?; +/// Ok(Response::from_parts(parts, body)) +/// } +/// # +/// # fn main() {} +/// ``` +/// +/// Or alternatively, serialize the body of a response to json +/// +/// ``` +/// # extern crate serde; +/// # extern crate serde_json; +/// # extern crate http; +/// use http::Response; +/// use serde::ser; +/// +/// fn serialize(req: Response) -> serde_json::Result>> +/// where T: ser::Serialize, +/// { +/// let (parts, body) = req.into_parts(); +/// let body = serde_json::to_vec(&body)?; +/// Ok(Response::from_parts(parts, body)) +/// } +/// # +/// # fn main() {} +/// ``` +pub struct Response { + head: Parts, + body: T, +} + +/// Component parts of an HTTP `Response` +/// +/// The HTTP response head consists of a status, version, and a set of +/// header fields. +pub struct Parts { + /// The response's status + pub status: StatusCode, + + /// The response's version + pub version: Version, + + /// The response's headers + pub headers: HeaderMap, + + /// The response's extensions + pub extensions: Extensions, + + _priv: (), +} + +/// An HTTP response builder +/// +/// This type can be used to construct an instance of `Response` through a +/// builder-like pattern. +#[derive(Debug)] +pub struct Builder { + head: Option, + err: Option, +} + +impl Response<()> { + /// Creates a new builder-style object to manufacture a `Response` + /// + /// This method returns an instance of `Builder` which can be used to + /// create a `Response`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response = Response::builder() + /// .status(200) + /// .header("X-Custom-Foo", "Bar") + /// .body(()) + /// .unwrap(); + /// ``` + #[inline] + pub fn builder() -> Builder { + Builder::new() + } +} + +impl Response { + /// Creates a new blank `Response` with the body + /// + /// The component ports of this response will be set to their default, e.g. + /// the ok status, no headers, etc. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response = Response::new("hello world"); + /// + /// assert_eq!(response.status(), StatusCode::OK); + /// assert_eq!(*response.body(), "hello world"); + /// ``` + #[inline] + pub fn new(body: T) -> Response { + Response { + head: Parts::new(), + body: body, + } + } + + /// Creates a new `Response` with the given head and body + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response = Response::new("hello world"); + /// let (mut parts, body) = response.into_parts(); + /// + /// parts.status = StatusCode::BAD_REQUEST; + /// let response = Response::from_parts(parts, body); + /// + /// assert_eq!(response.status(), StatusCode::BAD_REQUEST); + /// assert_eq!(*response.body(), "hello world"); + /// ``` + #[inline] + pub fn from_parts(parts: Parts, body: T) -> Response { + Response { + head: parts, + body: body, + } + } + + /// Returns the `StatusCode`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response<()> = Response::default(); + /// assert_eq!(response.status(), StatusCode::OK); + /// ``` + #[inline] + pub fn status(&self) -> StatusCode { + self.head.status + } + + /// Returns a mutable reference to the associated `StatusCode`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut response: Response<()> = Response::default(); + /// *response.status_mut() = StatusCode::CREATED; + /// assert_eq!(response.status(), StatusCode::CREATED); + /// ``` + #[inline] + pub fn status_mut(&mut self) -> &mut StatusCode { + &mut self.head.status + } + + /// Returns a reference to the associated version. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response<()> = Response::default(); + /// assert_eq!(response.version(), Version::HTTP_11); + /// ``` + #[inline] + pub fn version(&self) -> Version { + self.head.version + } + + /// Returns a mutable reference to the associated version. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut response: Response<()> = Response::default(); + /// *response.version_mut() = Version::HTTP_2; + /// assert_eq!(response.version(), Version::HTTP_2); + /// ``` + #[inline] + pub fn version_mut(&mut self) -> &mut Version { + &mut self.head.version + } + + /// Returns a reference to the associated header field map. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response<()> = Response::default(); + /// assert!(response.headers().is_empty()); + /// ``` + #[inline] + pub fn headers(&self) -> &HeaderMap { + &self.head.headers + } + + /// Returns a mutable reference to the associated header field map. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::*; + /// let mut response: Response<()> = Response::default(); + /// response.headers_mut().insert(HOST, HeaderValue::from_static("world")); + /// assert!(!response.headers().is_empty()); + /// ``` + #[inline] + pub fn headers_mut(&mut self) -> &mut HeaderMap { + &mut self.head.headers + } + + /// Returns a reference to the associated extensions. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response<()> = Response::default(); + /// assert!(response.extensions().get::().is_none()); + /// ``` + #[inline] + pub fn extensions(&self) -> &Extensions { + &self.head.extensions + } + + /// Returns a mutable reference to the associated extensions. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::*; + /// let mut response: Response<()> = Response::default(); + /// response.extensions_mut().insert("hello"); + /// assert_eq!(response.extensions().get(), Some(&"hello")); + /// ``` + #[inline] + pub fn extensions_mut(&mut self) -> &mut Extensions { + &mut self.head.extensions + } + + /// Returns a reference to the associated HTTP body. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response = Response::default(); + /// assert!(response.body().is_empty()); + /// ``` + #[inline] + pub fn body(&self) -> &T { + &self.body + } + + /// Returns a mutable reference to the associated HTTP body. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let mut response: Response = Response::default(); + /// response.body_mut().push_str("hello world"); + /// assert!(!response.body().is_empty()); + /// ``` + #[inline] + pub fn body_mut(&mut self) -> &mut T { + &mut self.body + } + + /// Consumes the response, returning just the body. + /// + /// # Examples + /// + /// ``` + /// # use http::Response; + /// let response = Response::new(10); + /// let body = response.into_body(); + /// assert_eq!(body, 10); + /// ``` + #[inline] + pub fn into_body(self) -> T { + self.body + } + + /// Consumes the response returning the head and body parts. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response: Response<()> = Response::default(); + /// let (parts, body) = response.into_parts(); + /// assert_eq!(parts.status, StatusCode::OK); + /// ``` + #[inline] + pub fn into_parts(self) -> (Parts, T) { + (self.head, self.body) + } + + /// Consumes the response returning a new response with body mapped to the + /// return type of the passed in function. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// let response = Response::builder().body("some string").unwrap(); + /// let mapped_response: Response<&[u8]> = response.map(|b| { + /// assert_eq!(b, "some string"); + /// b.as_bytes() + /// }); + /// assert_eq!(mapped_response.body(), &"some string".as_bytes()); + /// ``` + #[inline] + pub fn map(self, f: F) -> Response + where F: FnOnce(T) -> U + { + Response { body: f(self.body), head: self.head } + } +} + +impl Default for Response { + #[inline] + fn default() -> Response { + Response::new(T::default()) + } +} + +impl fmt::Debug for Response { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Response") + .field("status", &self.status()) + .field("version", &self.version()) + .field("headers", self.headers()) + // omits Extensions because not useful + .field("body", self.body()) + .finish() + } +} + +impl Parts { + /// Creates a new default instance of `Parts` + fn new() -> Parts { + Parts{ + status: StatusCode::default(), + version: Version::default(), + headers: HeaderMap::default(), + extensions: Extensions::default(), + _priv: (), + } + } +} + +impl fmt::Debug for Parts { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Parts") + .field("status", &self.status) + .field("version", &self.version) + .field("headers", &self.headers) + // omits Extensions because not useful + // omits _priv because not useful + .finish() + } +} + +impl Builder { + /// Creates a new default instance of `Builder` to construct either a + /// `Head` or a `Response`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let response = response::Builder::new() + /// .status(200) + /// .body(()) + /// .unwrap(); + /// ``` + #[inline] + pub fn new() -> Builder { + Builder::default() + } + + /// Set the HTTP status for this response. + /// + /// This function will configure the HTTP status code of the `Response` that + /// will be returned from `Builder::build`. + /// + /// By default this is `200`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let response = Response::builder() + /// .status(200) + /// .body(()) + /// .unwrap(); + /// ``` + pub fn status(&mut self, status: T) -> &mut Builder + where StatusCode: HttpTryFrom, + { + if let Some(head) = head(&mut self.head, &self.err) { + match HttpTryFrom::try_from(status) { + Ok(s) => head.status = s, + Err(e) => self.err = Some(e.into()), + } + } + self + } + + /// Set the HTTP version for this response. + /// + /// This function will configure the HTTP version of the `Response` that + /// will be returned from `Builder::build`. + /// + /// By default this is HTTP/1.1 + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let response = Response::builder() + /// .version(Version::HTTP_2) + /// .body(()) + /// .unwrap(); + /// ``` + pub fn version(&mut self, version: Version) -> &mut Builder { + if let Some(head) = head(&mut self.head, &self.err) { + head.version = version; + } + self + } + + /// Appends a header to this response builder. + /// + /// This function will append the provided key/value as a header to the + /// internal `HeaderMap` being constructed. Essentially this is equivalent + /// to calling `HeaderMap::append`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// + /// let response = Response::builder() + /// .header("Content-Type", "text/html") + /// .header("X-Custom-Foo", "bar") + /// .header("content-length", 0) + /// .body(()) + /// .unwrap(); + /// ``` + pub fn header(&mut self, key: K, value: V) -> &mut Builder + where HeaderName: HttpTryFrom, + HeaderValue: HttpTryFrom + { + if let Some(head) = head(&mut self.head, &self.err) { + match >::try_from(key) { + Ok(key) => { + match >::try_from(value) { + Ok(value) => { head.headers.append(key, value); } + Err(e) => self.err = Some(e.into()), + } + }, + Err(e) => self.err = Some(e.into()), + }; + } + self + } + + /// Get header on this response builder. + /// when builder has error returns None + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// # use http::response::Builder; + /// let mut res = Response::builder(); + /// res.header("Accept", "text/html") + /// .header("X-Custom-Foo", "bar"); + /// let headers = res.headers_ref().unwrap(); + /// assert_eq!( headers["Accept"], "text/html" ); + /// assert_eq!( headers["X-Custom-Foo"], "bar" ); + /// ``` + pub fn headers_ref(&self) -> Option<&HeaderMap> { + if self.err.is_some() { + return None; + } + match self.head + { + Some(ref head) => Some(&head.headers), + None => None + } + } + + /// Get header on this response builder. + /// when builder has error returns None + /// + /// # Example + /// + /// ``` + /// # use http::*; + /// # use http::header::HeaderValue; + /// # use http::response::Builder; + /// let mut res = Response::builder(); + /// { + /// let headers = res.headers_mut().unwrap(); + /// headers.insert("Accept", HeaderValue::from_static("text/html")); + /// headers.insert("X-Custom-Foo", HeaderValue::from_static("bar")); + /// } + /// let headers = res.headers_ref().unwrap(); + /// assert_eq!( headers["Accept"], "text/html" ); + /// assert_eq!( headers["X-Custom-Foo"], "bar" ); + /// ``` + pub fn headers_mut(&mut self) -> Option<&mut HeaderMap> { + if self.err.is_some() { + return None; + } + match self.head + { + Some(ref mut head) => Some(&mut head.headers), + None => None + } + } + + /// Adds an extension to this builder + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let response = Response::builder() + /// .extension("My Extension") + /// .body(()) + /// .unwrap(); + /// + /// assert_eq!(response.extensions().get::<&'static str>(), + /// Some(&"My Extension")); + /// ``` + pub fn extension(&mut self, extension: T) -> &mut Builder + where T: Any + Send + Sync + 'static, + { + if let Some(head) = head(&mut self.head, &self.err) { + head.extensions.insert(extension); + } + self + } + + fn take_parts(&mut self) -> Result { + let ret = self.head.take().expect("cannot reuse response builder"); + if let Some(e) = self.err.take() { + return Err(e) + } + Ok(ret) + } + + /// "Consumes" this builder, using the provided `body` to return a + /// constructed `Response`. + /// + /// # Errors + /// + /// This function may return an error if any previously configured argument + /// failed to parse or get converted to the internal representation. For + /// example if an invalid `head` was specified via `header("Foo", + /// "Bar\r\n")` the error will be returned when this function is called + /// rather than when `header` was called. + /// + /// # Panics + /// + /// This method will panic if the builder is reused. The `body` function can + /// only be called once. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let response = Response::builder() + /// .body(()) + /// .unwrap(); + /// ``` + pub fn body(&mut self, body: T) -> Result> { + Ok(Response { + head: self.take_parts()?, + body: body, + }) + } +} + +fn head<'a>(head: &'a mut Option, err: &Option) + -> Option<&'a mut Parts> +{ + if err.is_some() { + return None + } + head.as_mut() +} + +impl Default for Builder { + #[inline] + fn default() -> Builder { + Builder { + head: Some(Parts::new()), + err: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_can_map_a_body_from_one_type_to_another() { + let response = Response::builder().body("some string").unwrap(); + let mapped_response = response.map(|s| { + assert_eq!(s, "some string"); + 123u32 + }); + assert_eq!(mapped_response.body(), &123u32); + } +} diff --git a/http/src/status.rs b/http/src/status.rs new file mode 100644 index 000000000..162e8ce94 --- /dev/null +++ b/http/src/status.rs @@ -0,0 +1,563 @@ +//! HTTP status codes +//! +//! This module contains HTTP-status code related structs an errors. The main +//! type in this module is `StatusCode` which is not intended to be used through +//! this module but rather the `http::StatusCode` type. +//! +//! # Examples +//! +//! ``` +//! use http::StatusCode; +//! +//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK); +//! assert_eq!(StatusCode::NOT_FOUND, 404); +//! assert!(StatusCode::OK.is_success()); +//! ``` + +use std::fmt; +use std::error::Error; +use std::str::FromStr; + +use HttpTryFrom; + +/// An HTTP status code (`status-code` in RFC 7230 et al.). +/// +/// This type contains constants for all common status codes. +/// It allows status codes in the range [100, 599]. +/// +/// IANA maintain the [Hypertext Transfer Protocol (HTTP) Status Code +/// Registry](http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) which is +/// the source for this enum (with one exception, 418 I'm a teapot, which is +/// inexplicably not in the register). +/// +/// # Examples +/// +/// ``` +/// use http::StatusCode; +/// +/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK); +/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404); +/// assert!(StatusCode::OK.is_success()); +/// ``` +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct StatusCode(u16); + +/// A possible error value when converting a `StatusCode` from a `u16` or `&str` +/// +/// This error indicates that the supplied input was not a valid number, was less +/// than 100, or was greater than 599. +#[derive(Debug)] +pub struct InvalidStatusCode { + _priv: (), +} + +impl StatusCode { + /// Converts a u16 to a status code. + /// + /// The function validates the correctness of the supplied u16. It must be + /// greater or equal to 100 but less than 600. + /// + /// # Example + /// + /// ``` + /// use http::StatusCode; + /// + /// let ok = StatusCode::from_u16(200).unwrap(); + /// assert_eq!(ok, StatusCode::OK); + /// + /// let err = StatusCode::from_u16(99); + /// assert!(err.is_err()); + /// ``` + #[inline] + pub fn from_u16(src: u16) -> Result { + if src < 100 || src >= 600 { + return Err(InvalidStatusCode::new()); + } + + Ok(StatusCode(src)) + } + + /// Converts a &[u8] to a status code + pub fn from_bytes(src: &[u8]) -> Result { + if src.len() != 3 { + return Err(InvalidStatusCode::new()); + } + + let a = src[0].wrapping_sub(b'0') as u16; + let b = src[1].wrapping_sub(b'0') as u16; + let c = src[2].wrapping_sub(b'0') as u16; + + if a == 0 || a > 5 || b > 9 || c > 9 { + return Err(InvalidStatusCode::new()); + } + + let status = (a * 100) + (b * 10) + c; + Ok(StatusCode(status)) + } + + /// Returns the `u16` corresponding to this `StatusCode`. + /// + /// # Note + /// + /// This is the same as the `From` implementation, but + /// included as an inherent method because that implementation doesn't + /// appear in rustdocs, as well as a way to force the type instead of + /// relying on inference. + /// + /// # Example + /// + /// ``` + /// let status = http::StatusCode::OK; + /// assert_eq!(status.as_u16(), 200); + /// ``` + #[inline] + pub fn as_u16(&self) -> u16 { + (*self).into() + } + + /// Returns a &str representation of the `StatusCode` + /// + /// The return value only includes a numerical representation of the + /// status code. The canonical reason is not included. + /// + /// # Example + /// + /// ``` + /// let status = http::StatusCode::OK; + /// assert_eq!(status.as_str(), "200"); + /// ``` + #[inline] + pub fn as_str(&self) -> &str { + CODES_AS_STR[(self.0 - 100) as usize] + } + + /// Get the standardised `reason-phrase` for this status code. + /// + /// This is mostly here for servers writing responses, but could potentially have application + /// at other times. + /// + /// The reason phrase is defined as being exclusively for human readers. You should avoid + /// deriving any meaning from it at all costs. + /// + /// Bear in mind also that in HTTP/2.0 the reason phrase is abolished from transmission, and so + /// this canonical reason phrase really is the only reason phrase you’ll find. + /// + /// # Example + /// + /// ``` + /// let status = http::StatusCode::OK; + /// assert_eq!(status.canonical_reason(), Some("OK")); + /// ``` + pub fn canonical_reason(&self) -> Option<&'static str> { + canonical_reason(self.0) + } + + + /// Check if status is within 100-199. + #[inline] + pub fn is_informational(&self) -> bool { + 200 > self.0 && self.0 >= 100 + } + + /// Check if status is within 200-299. + #[inline] + pub fn is_success(&self) -> bool { + 300 > self.0 && self.0 >= 200 + } + + /// Check if status is within 300-399. + #[inline] + pub fn is_redirection(&self) -> bool { + 400 > self.0 && self.0 >= 300 + } + + /// Check if status is within 400-499. + #[inline] + pub fn is_client_error(&self) -> bool { + 500 > self.0 && self.0 >= 400 + } + + /// Check if status is within 500-599. + #[inline] + pub fn is_server_error(&self) -> bool { + 600 > self.0 && self.0 >= 500 + } +} + +impl fmt::Debug for StatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +/// Formats the status code, *including* the canonical reason. +/// +/// # Example +/// +/// ``` +/// # use http::StatusCode; +/// assert_eq!(format!("{}", StatusCode::OK), "200 OK"); +/// ``` +impl fmt::Display for StatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", u16::from(*self), + self.canonical_reason().unwrap_or("")) + } +} + +impl Default for StatusCode { + #[inline] + fn default() -> StatusCode { + StatusCode::OK + } +} + +impl PartialEq for StatusCode { + #[inline] + fn eq(&self, other: &u16) -> bool { + self.as_u16() == *other + } +} + +impl PartialEq for u16 { + #[inline] + fn eq(&self, other: &StatusCode) -> bool { + *self == other.as_u16() + } +} + +impl From for u16 { + #[inline] + fn from(status: StatusCode) -> u16 { + status.0 + } +} + +impl FromStr for StatusCode { + type Err = InvalidStatusCode; + + fn from_str(s: &str) -> Result { + StatusCode::from_bytes(s.as_ref()) + } +} + +impl<'a> From<&'a StatusCode> for StatusCode { + #[inline] + fn from(t: &'a StatusCode) -> Self { + t.clone() + } +} + +impl<'a> HttpTryFrom<&'a StatusCode> for StatusCode { + type Error = ::error::Never; + + #[inline] + fn try_from(t: &'a StatusCode) -> Result { + Ok(t.clone()) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for StatusCode { + type Error = InvalidStatusCode; + + #[inline] + fn try_from(t: &'a [u8]) -> Result { + StatusCode::from_bytes(t) + } +} + +impl<'a> HttpTryFrom<&'a str> for StatusCode { + type Error = InvalidStatusCode; + + #[inline] + fn try_from(t: &'a str) -> Result { + t.parse() + } +} + +impl HttpTryFrom for StatusCode { + type Error = InvalidStatusCode; + + #[inline] + fn try_from(t: u16) -> Result { + StatusCode::from_u16(t) + } +} + +impl InvalidStatusCode { + fn new() -> InvalidStatusCode { + InvalidStatusCode { + _priv: (), + } + } +} + +macro_rules! status_codes { + ( + $( + $(#[$docs:meta])* + ($num:expr, $konst:ident, $phrase:expr); + )+ + ) => { + impl StatusCode { + $( + $(#[$docs])* + pub const $konst: StatusCode = StatusCode($num); + )+ + + } + + fn canonical_reason(num: u16) -> Option<&'static str> { + match num { + $( + $num => Some($phrase), + )+ + _ => None + } + } + } +} + +status_codes! { + /// 100 Continue + /// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)] + (100, CONTINUE, "Continue"); + /// 101 Switching Protocols + /// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)] + (101, SWITCHING_PROTOCOLS, "Switching Protocols"); + /// 102 Processing + /// [[RFC2518](https://tools.ietf.org/html/rfc2518)] + (102, PROCESSING, "Processing"); + + /// 200 OK + /// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)] + (200, OK, "OK"); + /// 201 Created + /// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)] + (201, CREATED, "Created"); + /// 202 Accepted + /// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)] + (202, ACCEPTED, "Accepted"); + /// 203 Non-Authoritative Information + /// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)] + (203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information"); + /// 204 No Content + /// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)] + (204, NO_CONTENT, "No Content"); + /// 205 Reset Content + /// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)] + (205, RESET_CONTENT, "Reset Content"); + /// 206 Partial Content + /// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)] + (206, PARTIAL_CONTENT, "Partial Content"); + /// 207 Multi-Status + /// [[RFC4918](https://tools.ietf.org/html/rfc4918)] + (207, MULTI_STATUS, "Multi-Status"); + /// 208 Already Reported + /// [[RFC5842](https://tools.ietf.org/html/rfc5842)] + (208, ALREADY_REPORTED, "Already Reported"); + + /// 226 IM Used + /// [[RFC3229](https://tools.ietf.org/html/rfc3229)] + (226, IM_USED, "IM Used"); + + /// 300 Multiple Choices + /// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)] + (300, MULTIPLE_CHOICES, "Multiple Choices"); + /// 301 Moved Permanently + /// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)] + (301, MOVED_PERMANENTLY, "Moved Permanently"); + /// 302 Found + /// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)] + (302, FOUND, "Found"); + /// 303 See Other + /// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)] + (303, SEE_OTHER, "See Other"); + /// 304 Not Modified + /// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)] + (304, NOT_MODIFIED, "Not Modified"); + /// 305 Use Proxy + /// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)] + (305, USE_PROXY, "Use Proxy"); + /// 307 Temporary Redirect + /// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)] + (307, TEMPORARY_REDIRECT, "Temporary Redirect"); + /// 308 Permanent Redirect + /// [[RFC7238](https://tools.ietf.org/html/rfc7238)] + (308, PERMANENT_REDIRECT, "Permanent Redirect"); + + /// 400 Bad Request + /// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)] + (400, BAD_REQUEST, "Bad Request"); + /// 401 Unauthorized + /// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)] + (401, UNAUTHORIZED, "Unauthorized"); + /// 402 Payment Required + /// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)] + (402, PAYMENT_REQUIRED, "Payment Required"); + /// 403 Forbidden + /// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)] + (403, FORBIDDEN, "Forbidden"); + /// 404 Not Found + /// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)] + (404, NOT_FOUND, "Not Found"); + /// 405 Method Not Allowed + /// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)] + (405, METHOD_NOT_ALLOWED, "Method Not Allowed"); + /// 406 Not Acceptable + /// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)] + (406, NOT_ACCEPTABLE, "Not Acceptable"); + /// 407 Proxy Authentication Required + /// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)] + (407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required"); + /// 408 Request Timeout + /// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)] + (408, REQUEST_TIMEOUT, "Request Timeout"); + /// 409 Conflict + /// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)] + (409, CONFLICT, "Conflict"); + /// 410 Gone + /// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)] + (410, GONE, "Gone"); + /// 411 Length Required + /// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)] + (411, LENGTH_REQUIRED, "Length Required"); + /// 412 Precondition Failed + /// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)] + (412, PRECONDITION_FAILED, "Precondition Failed"); + /// 413 Payload Too Large + /// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)] + (413, PAYLOAD_TOO_LARGE, "Payload Too Large"); + /// 414 URI Too Long + /// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)] + (414, URI_TOO_LONG, "URI Too Long"); + /// 415 Unsupported Media Type + /// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)] + (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"); + /// 416 Range Not Satisfiable + /// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)] + (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable"); + /// 417 Expectation Failed + /// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)] + (417, EXPECTATION_FAILED, "Expectation Failed"); + /// 418 I'm a teapot + /// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)] + (418, IM_A_TEAPOT, "I'm a teapot"); + + /// 421 Misdirected Request + /// [RFC7540, Section 9.1.2](http://tools.ietf.org/html/rfc7540#section-9.1.2) + (421, MISDIRECTED_REQUEST, "Misdirected Request"); + /// 422 Unprocessable Entity + /// [[RFC4918](https://tools.ietf.org/html/rfc4918)] + (422, UNPROCESSABLE_ENTITY, "Unprocessable Entity"); + /// 423 Locked + /// [[RFC4918](https://tools.ietf.org/html/rfc4918)] + (423, LOCKED, "Locked"); + /// 424 Failed Dependency + /// [[RFC4918](https://tools.ietf.org/html/rfc4918)] + (424, FAILED_DEPENDENCY, "Failed Dependency"); + + /// 426 Upgrade Required + /// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)] + (426, UPGRADE_REQUIRED, "Upgrade Required"); + + /// 428 Precondition Required + /// [[RFC6585](https://tools.ietf.org/html/rfc6585)] + (428, PRECONDITION_REQUIRED, "Precondition Required"); + /// 429 Too Many Requests + /// [[RFC6585](https://tools.ietf.org/html/rfc6585)] + (429, TOO_MANY_REQUESTS, "Too Many Requests"); + + /// 431 Request Header Fields Too Large + /// [[RFC6585](https://tools.ietf.org/html/rfc6585)] + (431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large"); + + /// 451 Unavailable For Legal Reasons + /// [[RFC7725](http://tools.ietf.org/html/rfc7725)] + (451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons"); + + /// 500 Internal Server Error + /// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)] + (500, INTERNAL_SERVER_ERROR, "Internal Server Error"); + /// 501 Not Implemented + /// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)] + (501, NOT_IMPLEMENTED, "Not Implemented"); + /// 502 Bad Gateway + /// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)] + (502, BAD_GATEWAY, "Bad Gateway"); + /// 503 Service Unavailable + /// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)] + (503, SERVICE_UNAVAILABLE, "Service Unavailable"); + /// 504 Gateway Timeout + /// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)] + (504, GATEWAY_TIMEOUT, "Gateway Timeout"); + /// 505 HTTP Version Not Supported + /// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)] + (505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported"); + /// 506 Variant Also Negotiates + /// [[RFC2295](https://tools.ietf.org/html/rfc2295)] + (506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates"); + /// 507 Insufficient Storage + /// [[RFC4918](https://tools.ietf.org/html/rfc4918)] + (507, INSUFFICIENT_STORAGE, "Insufficient Storage"); + /// 508 Loop Detected + /// [[RFC5842](https://tools.ietf.org/html/rfc5842)] + (508, LOOP_DETECTED, "Loop Detected"); + + /// 510 Not Extended + /// [[RFC2774](https://tools.ietf.org/html/rfc2774)] + (510, NOT_EXTENDED, "Not Extended"); + /// 511 Network Authentication Required + /// [[RFC6585](https://tools.ietf.org/html/rfc6585)] + (511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required"); +} + +impl fmt::Display for InvalidStatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.description()) + } +} + +impl Error for InvalidStatusCode { + fn description(&self) -> &str { + "invalid status code" + } +} + +macro_rules! status_code_strs { + ($($num:expr,)+) => { + const CODES_AS_STR: [&'static str; 500] = [ $( stringify!($num), )+ ]; + } +} + +status_code_strs!( + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, + 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, + 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, + 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, + ); diff --git a/http/src/uri/authority.rs b/http/src/uri/authority.rs new file mode 100644 index 000000000..724712ccb --- /dev/null +++ b/http/src/uri/authority.rs @@ -0,0 +1,615 @@ +// Deprecated in 1.26, needed until our minimum version is >=1.23. +#[allow(unused, deprecated)] +use std::ascii::AsciiExt; +use std::{cmp, fmt, str}; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; + +use bytes::Bytes; + +use byte_str::ByteStr; +use convert::HttpTryFrom; +use super::{ErrorKind, InvalidUri, InvalidUriBytes, URI_CHARS, Port}; + +/// Represents the authority component of a URI. +#[derive(Clone)] +pub struct Authority { + pub(super) data: ByteStr, +} + +impl Authority { + pub(super) fn empty() -> Self { + Authority { data: ByteStr::new() } + } + + /// Attempt to convert an `Authority` from `Bytes`. + /// + /// This function will be replaced by a `TryFrom` implementation once the + /// trait lands in stable. + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("example.com"); + /// let authority = Authority::from_shared(bytes).unwrap(); + /// + /// assert_eq!(authority.host(), "example.com"); + /// # } + /// ``` + pub fn from_shared(s: Bytes) -> Result { + let authority_end = Authority::parse_non_empty(&s[..]).map_err(InvalidUriBytes)?; + + if authority_end != s.len() { + return Err(ErrorKind::InvalidUriChar.into()); + } + + Ok(Authority { + data: unsafe { ByteStr::from_utf8_unchecked(s) }, + }) + } + + /// Attempt to convert an `Authority` from a static string. + /// + /// This function will not perform any copying, and the string will be + /// checked if it is empty or contains an invalid character. + /// + /// # Panics + /// + /// This function panics if the argument contains invalid characters or + /// is empty. + /// + /// # Examples + /// + /// ``` + /// # use http::uri::Authority; + /// let authority = Authority::from_static("example.com"); + /// assert_eq!(authority.host(), "example.com"); + /// ``` + pub fn from_static(src: &'static str) -> Self { + let s = src.as_bytes(); + let b = Bytes::from_static(s); + let authority_end = Authority::parse_non_empty(&b[..]).expect("static str is not valid authority"); + + if authority_end != b.len() { + panic!("static str is not valid authority"); + } + + Authority { + data: unsafe { ByteStr::from_utf8_unchecked(b) }, + } + } + + // Note: this may return an *empty* Authority. You might want `parse_non_empty`. + pub(super) fn parse(s: &[u8]) -> Result { + let mut colon_cnt = 0; + let mut start_bracket = false; + let mut end_bracket = false; + let mut has_percent = false; + let mut end = s.len(); + let mut at_sign_pos = None; + + for (i, &b) in s.iter().enumerate() { + match URI_CHARS[b as usize] { + b'/' | b'?' | b'#' => { + end = i; + break; + } + b':' => { + colon_cnt += 1; + }, + b'[' => { + start_bracket = true; + } + b']' => { + end_bracket = true; + + // Those were part of an IPv6 hostname, so forget them... + colon_cnt = 0; + } + b'@' => { + at_sign_pos = Some(i); + + // Those weren't a port colon, but part of the + // userinfo, so it needs to be forgotten. + colon_cnt = 0; + has_percent = false; + } + 0 if b == b'%' => { + // Per https://tools.ietf.org/html/rfc3986#section-3.2.1 and + // https://url.spec.whatwg.org/#authority-state + // the userinfo can have a percent-encoded username and password, + // so record that a `%` was found. If this turns out to be + // part of the userinfo, this flag will be cleared. + // If the flag hasn't been cleared at the end, that means this + // was part of the hostname, and will fail with an error. + has_percent = true; + } + 0 => { + return Err(ErrorKind::InvalidUriChar.into()); + } + _ => {} + } + } + + if start_bracket ^ end_bracket { + return Err(ErrorKind::InvalidAuthority.into()); + } + + if colon_cnt > 1 { + // Things like 'localhost:8080:3030' are rejected. + return Err(ErrorKind::InvalidAuthority.into()); + } + + if end > 0 && at_sign_pos == Some(end - 1) { + // If there's nothing after an `@`, this is bonkers. + return Err(ErrorKind::InvalidAuthority.into()); + } + + if has_percent { + // Something after the userinfo has a `%`, so reject it. + return Err(ErrorKind::InvalidAuthority.into()); + } + + Ok(end) + } + + // Parse bytes as an Authority, not allowing an empty string. + // + // This should be used by functions that allow a user to parse + // an `Authority` by itself. + fn parse_non_empty(s: &[u8]) -> Result { + if s.is_empty() { + return Err(ErrorKind::Empty.into()); + } + Authority::parse(s) + } + + /// Get the host of this `Authority`. + /// + /// The host subcomponent of authority is identified by an IP literal + /// encapsulated within square brackets, an IPv4 address in dotted- decimal + /// form, or a registered name. The host subcomponent is **case-insensitive**. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |---------| + /// | + /// host + /// ``` + /// + /// # Examples + /// + /// ``` + /// # use http::uri::*; + /// let authority: Authority = "example.org:80".parse().unwrap(); + /// + /// assert_eq!(authority.host(), "example.org"); + /// ``` + #[inline] + pub fn host(&self) -> &str { + host(self.as_str()) + } + + #[deprecated(since="0.1.14", note="use `port_part` or `port_u16` instead")] + #[doc(hidden)] + pub fn port(&self) -> Option { + self.port_u16() + } + + /// Get the port part of this `Authority`. + /// + /// The port subcomponent of authority is designated by an optional port + /// number following the host and delimited from it by a single colon (":") + /// character. It can be turned into a decimal port number with the `as_u16` + /// method or as a `str` with the `as_str` method. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-| + /// | + /// port + /// ``` + /// + /// # Examples + /// + /// Authority with port + /// + /// ``` + /// # use http::uri::Authority; + /// let authority: Authority = "example.org:80".parse().unwrap(); + /// + /// let port = authority.port_part().unwrap(); + /// assert_eq!(port.as_u16(), 80); + /// assert_eq!(port.as_str(), "80"); + /// ``` + /// + /// Authority without port + /// + /// ``` + /// # use http::uri::Authority; + /// let authority: Authority = "example.org".parse().unwrap(); + /// + /// assert!(authority.port_part().is_none()); + /// ``` + pub fn port_part(&self) -> Option> { + let bytes = self.as_str(); + bytes + .rfind(":") + .and_then(|i| Port::from_str(&bytes[i + 1..]).ok()) + } + + /// Get the port of this `Authority` as a `u16`. + /// + /// # Example + /// + /// ``` + /// # use http::uri::Authority; + /// let authority: Authority = "example.org:80".parse().unwrap(); + /// + /// assert_eq!(authority.port_u16(), Some(80)); + /// ``` + pub fn port_u16(&self) -> Option { + self.port_part().and_then(|p| Some(p.as_u16())) + } + + /// Return a str representation of the authority + #[inline] + pub fn as_str(&self) -> &str { + &self.data[..] + } + + /// Converts this `Authority` back to a sequence of bytes + #[inline] + pub fn into_bytes(self) -> Bytes { + self.into() + } +} + +impl AsRef for Authority { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl PartialEq for Authority { + fn eq(&self, other: &Authority) -> bool { + self.data.eq_ignore_ascii_case(&other.data) + } +} + +impl Eq for Authority {} + +/// Case-insensitive equality +/// +/// # Examples +/// +/// ``` +/// # use http::uri::Authority; +/// let authority: Authority = "HELLO.com".parse().unwrap(); +/// assert_eq!(authority, "hello.coM"); +/// assert_eq!("hello.com", authority); +/// ``` +impl PartialEq for Authority { + fn eq(&self, other: &str) -> bool { + self.data.eq_ignore_ascii_case(other) + } +} + +impl PartialEq for str { + fn eq(&self, other: &Authority) -> bool { + self.eq_ignore_ascii_case(other.as_str()) + } +} + +impl<'a> PartialEq for &'a str { + fn eq(&self, other: &Authority) -> bool { + self.eq_ignore_ascii_case(other.as_str()) + } +} + +impl<'a> PartialEq<&'a str> for Authority { + fn eq(&self, other: &&'a str) -> bool { + self.data.eq_ignore_ascii_case(other) + } +} + +impl PartialEq for Authority { + fn eq(&self, other: &String) -> bool { + self.data.eq_ignore_ascii_case(other.as_str()) + } +} + +impl PartialEq for String { + fn eq(&self, other: &Authority) -> bool { + self.as_str().eq_ignore_ascii_case(other.as_str()) + } +} + +/// Case-insensitive ordering +/// +/// # Examples +/// +/// ``` +/// # use http::uri::Authority; +/// let authority: Authority = "DEF.com".parse().unwrap(); +/// assert!(authority < "ghi.com"); +/// assert!(authority > "abc.com"); +/// ``` +impl PartialOrd for Authority { + fn partial_cmp(&self, other: &Authority) -> Option { + let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl PartialOrd for Authority { + fn partial_cmp(&self, other: &str) -> Option { + let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl PartialOrd for str { + fn partial_cmp(&self, other: &Authority) -> Option { + let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl<'a> PartialOrd for &'a str { + fn partial_cmp(&self, other: &Authority) -> Option { + let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl<'a> PartialOrd<&'a str> for Authority { + fn partial_cmp(&self, other: &&'a str) -> Option { + let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl PartialOrd for Authority { + fn partial_cmp(&self, other: &String) -> Option { + let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +impl PartialOrd for String { + fn partial_cmp(&self, other: &Authority) -> Option { + let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase()); + left.partial_cmp(right) + } +} + +/// Case-insensitive hashing +/// +/// # Examples +/// +/// ``` +/// # use http::uri::Authority; +/// # use std::hash::{Hash, Hasher}; +/// # use std::collections::hash_map::DefaultHasher; +/// +/// let a: Authority = "HELLO.com".parse().unwrap(); +/// let b: Authority = "hello.coM".parse().unwrap(); +/// +/// let mut s = DefaultHasher::new(); +/// a.hash(&mut s); +/// let a = s.finish(); +/// +/// let mut s = DefaultHasher::new(); +/// b.hash(&mut s); +/// let b = s.finish(); +/// +/// assert_eq!(a, b); +/// ``` +impl Hash for Authority { + fn hash(&self, state: &mut H) where H: Hasher { + self.data.len().hash(state); + for &b in self.data.as_bytes() { + state.write_u8(b.to_ascii_lowercase()); + } + } +} + +impl HttpTryFrom for Authority { + type Error = InvalidUriBytes; + #[inline] + fn try_from(bytes: Bytes) -> Result { + Authority::from_shared(bytes) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for Authority { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a [u8]) -> Result { + // parse first, and only turn into Bytes if valid + let end = Authority::parse_non_empty(s)?; + + if end != s.len() { + return Err(ErrorKind::InvalidAuthority.into()); + } + + Ok(Authority { + data: unsafe { ByteStr::from_utf8_unchecked(s.into()) }, + }) + } +} + +impl<'a> HttpTryFrom<&'a str> for Authority { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a str) -> Result { + HttpTryFrom::try_from(s.as_bytes()) + } +} + +impl FromStr for Authority { + type Err = InvalidUri; + + fn from_str(s: &str) -> Result { + HttpTryFrom::try_from(s) + } +} + +impl From for Bytes { + #[inline] + fn from(src: Authority) -> Bytes { + src.data.into() + } +} + +impl fmt::Debug for Authority { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl fmt::Display for Authority { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +fn host(auth: &str) -> &str { + let host_port = auth.rsplitn(2, '@') + .next() + .expect("split always has at least 1 item"); + + if host_port.as_bytes()[0] == b'[' { + let i = host_port.find(']') + .expect("parsing should validate brackets"); + // ..= ranges aren't available in 1.20, our minimum Rust version... + &host_port[0 .. i + 1] + } else { + host_port.split(':') + .next() + .expect("split always has at least 1 item") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_empty_string_is_error() { + let err = Authority::parse_non_empty(b"").unwrap_err(); + assert_eq!(err.0, ErrorKind::Empty); + } + + #[test] + fn equal_to_self_of_same_authority() { + let authority1: Authority = "example.com".parse().unwrap(); + let authority2: Authority = "EXAMPLE.COM".parse().unwrap(); + assert_eq!(authority1, authority2); + assert_eq!(authority2, authority1); + } + + #[test] + fn not_equal_to_self_of_different_authority() { + let authority1: Authority = "example.com".parse().unwrap(); + let authority2: Authority = "test.com".parse().unwrap(); + assert_ne!(authority1, authority2); + assert_ne!(authority2, authority1); + } + + #[test] + fn equates_with_a_str() { + let authority: Authority = "example.com".parse().unwrap(); + assert_eq!(&authority, "EXAMPLE.com"); + assert_eq!("EXAMPLE.com", &authority); + assert_eq!(authority, "EXAMPLE.com"); + assert_eq!("EXAMPLE.com", authority); + } + + #[test] + fn not_equal_with_a_str_of_a_different_authority() { + let authority: Authority = "example.com".parse().unwrap(); + assert_ne!(&authority, "test.com"); + assert_ne!("test.com", &authority); + assert_ne!(authority, "test.com"); + assert_ne!("test.com", authority); + } + + #[test] + fn equates_with_a_string() { + let authority: Authority = "example.com".parse().unwrap(); + assert_eq!(authority, "EXAMPLE.com".to_string()); + assert_eq!("EXAMPLE.com".to_string(), authority); + } + + #[test] + fn equates_with_a_string_of_a_different_authority() { + let authority: Authority = "example.com".parse().unwrap(); + assert_ne!(authority, "test.com".to_string()); + assert_ne!("test.com".to_string(), authority); + } + + #[test] + fn compares_to_self() { + let authority1: Authority = "abc.com".parse().unwrap(); + let authority2: Authority = "def.com".parse().unwrap(); + assert!(authority1 < authority2); + assert!(authority2 > authority1); + } + + #[test] + fn compares_with_a_str() { + let authority: Authority = "def.com".parse().unwrap(); + // with ref + assert!(&authority < "ghi.com"); + assert!("ghi.com" > &authority); + assert!(&authority > "abc.com"); + assert!("abc.com" < &authority); + + // no ref + assert!(authority < "ghi.com"); + assert!("ghi.com" > authority); + assert!(authority > "abc.com"); + assert!("abc.com" < authority); + } + + #[test] + fn compares_with_a_string() { + let authority: Authority = "def.com".parse().unwrap(); + assert!(authority < "ghi.com".to_string()); + assert!("ghi.com".to_string() > authority); + assert!(authority > "abc.com".to_string()); + assert!("abc.com".to_string() < authority); + } + + #[test] + fn allows_percent_in_userinfo() { + let authority_str = "a%2f:b%2f@example.com"; + let authority: Authority = authority_str.parse().unwrap(); + assert_eq!(authority, authority_str); + } + + #[test] + fn rejects_percent_in_hostname() { + let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + + let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err(); + assert_eq!(err.0, ErrorKind::InvalidAuthority); + } +} diff --git a/http/src/uri/builder.rs b/http/src/uri/builder.rs new file mode 100644 index 000000000..c6d0c93be --- /dev/null +++ b/http/src/uri/builder.rs @@ -0,0 +1,156 @@ +use {Uri, Result}; +use convert::{HttpTryFrom, HttpTryInto}; +use super::{Authority, Scheme, Parts, PathAndQuery}; + +/// A builder for `Uri`s. +/// +/// This type can be used to construct an instance of `Uri` +/// through a builder pattern. +#[derive(Debug)] +pub struct Builder { + parts: Option>, +} + +impl Builder { + /// Creates a new default instance of `Builder` to construct a `Uri`. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let uri = uri::Builder::new() + /// .scheme("https") + /// .authority("hyper.rs") + /// .path_and_query("/") + /// .build() + /// .unwrap(); + /// ``` + #[inline] + pub fn new() -> Builder { + Builder::default() + } + + /// Set the `Scheme` for this URI. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let mut builder = uri::Builder::new(); + /// builder.scheme("https"); + /// ``` + pub fn scheme(&mut self, scheme: T) -> &mut Self + where + Scheme: HttpTryFrom, + { + self.map(|parts| { + parts.scheme = Some(scheme.http_try_into()?); + Ok(()) + }) + } + + /// Set the `Authority` for this URI. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let uri = uri::Builder::new() + /// .authority("tokio.rs") + /// .build() + /// .unwrap(); + /// ``` + pub fn authority(&mut self, auth: T) -> &mut Self + where + Authority: HttpTryFrom, + { + self.map(|parts| { + parts.authority = Some(auth.http_try_into()?); + Ok(()) + }) + } + + /// Set the `PathAndQuery` for this URI. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let uri = uri::Builder::new() + /// .path_and_query("/hello?foo=bar") + /// .build() + /// .unwrap(); + /// ``` + pub fn path_and_query(&mut self, p_and_q: T) -> &mut Self + where + PathAndQuery: HttpTryFrom, + { + self.map(|parts| { + parts.path_and_query = Some(p_and_q.http_try_into()?); + Ok(()) + }) + } + + /// Consumes this builder, and tries to construct a valid `Uri` from + /// the configured pieces. + /// + /// # Errors + /// + /// This function may return an error if any previously configured argument + /// failed to parse or get converted to the internal representation. For + /// example if an invalid `scheme` was specified via `scheme("!@#%/^")` + /// the error will be returned when this function is called rather than + /// when `scheme` was called. + /// + /// Additionally, the various forms of URI require certain combinations of + /// parts to be set to be valid. If the parts don't fit into any of the + /// valid forms of URI, a new error is returned. + /// + /// # Examples + /// + /// ``` + /// # use http::*; + /// + /// let uri = Uri::builder() + /// .build() + /// .unwrap(); + /// ``` + pub fn build(&mut self) -> Result { + self + .parts + .take() + .expect("cannot reuse Uri builder") + .and_then(|parts| parts.http_try_into()) + } + + fn map(&mut self, f: F) -> &mut Self + where + F: FnOnce(&mut Parts) -> Result<()>, + { + let res = if let Some(Ok(ref mut parts)) = self.parts { + f(parts) + } else { + return self; + }; + + if let Err(err) = res { + self.parts = Some(Err(err)); + } + + self + } +} + +impl Default for Builder { + #[inline] + fn default() -> Builder { + Builder { + parts: Some(Ok(Parts::default())), + } + } +} + diff --git a/http/src/uri/mod.rs b/http/src/uri/mod.rs new file mode 100644 index 000000000..0d2f34b86 --- /dev/null +++ b/http/src/uri/mod.rs @@ -0,0 +1,1138 @@ +//! URI component of request and response lines +//! +//! This module primarily contains the `Uri` type which is a component of all +//! HTTP requests and also reexports this type at the root of the crate. A URI +//! is not always a "full URL" in the sense of something you'd type into a web +//! browser, but HTTP requests may only have paths on servers but may have full +//! schemes and hostnames on clients. +//! +//! # Examples +//! +//! ``` +//! use http::Uri; +//! +//! let uri = "/foo/bar?baz".parse::().unwrap(); +//! assert_eq!(uri.path(), "/foo/bar"); +//! assert_eq!(uri.query(), Some("baz")); +//! assert_eq!(uri.host(), None); +//! +//! let uri = "https://www.rust-lang.org/install.html".parse::().unwrap(); +//! assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("https")); +//! assert_eq!(uri.host(), Some("www.rust-lang.org")); +//! assert_eq!(uri.path(), "/install.html"); +//! ``` + +use HttpTryFrom; +use byte_str::ByteStr; + +use bytes::Bytes; + +use std::{fmt, u8, u16}; +// Deprecated in 1.26, needed until our minimum version is >=1.23. +#[allow(unused, deprecated)] +use std::ascii::AsciiExt; +use std::hash::{Hash, Hasher}; +use std::str::{self, FromStr}; +use std::error::Error; + +use self::scheme::Scheme2; + +pub use self::authority::Authority; +pub use self::builder::Builder; +pub use self::path::PathAndQuery; +pub use self::scheme::Scheme; +pub use self::port::Port; + +mod authority; +mod builder; +mod path; +mod port; +mod scheme; +#[cfg(test)] +mod tests; + +/// The URI component of a request. +/// +/// For HTTP 1, this is included as part of the request line. From Section 5.3, +/// Request Target: +/// +/// > Once an inbound connection is obtained, the client sends an HTTP +/// > request message (Section 3) with a request-target derived from the +/// > target URI. There are four distinct formats for the request-target, +/// > depending on both the method being requested and whether the request +/// > is to a proxy. +/// > +/// > ```notrust +/// > request-target = origin-form +/// > / absolute-form +/// > / authority-form +/// > / asterisk-form +/// > ``` +/// +/// The URI is structured as follows: +/// +/// ```notrust +/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 +/// |-| |-------------------------------||--------| |-------------------| |-----| +/// | | | | | +/// scheme authority path query fragment +/// ``` +/// +/// For HTTP 2.0, the URI is encoded using pseudoheaders. +/// +/// # Examples +/// +/// ``` +/// use http::Uri; +/// +/// let uri = "/foo/bar?baz".parse::().unwrap(); +/// assert_eq!(uri.path(), "/foo/bar"); +/// assert_eq!(uri.query(), Some("baz")); +/// assert_eq!(uri.host(), None); +/// +/// let uri = "https://www.rust-lang.org/install.html".parse::().unwrap(); +/// assert_eq!(uri.scheme_part().map(|s| s.as_str()), Some("https")); +/// assert_eq!(uri.host(), Some("www.rust-lang.org")); +/// assert_eq!(uri.path(), "/install.html"); +/// ``` +#[derive(Clone)] +pub struct Uri { + scheme: Scheme, + authority: Authority, + path_and_query: PathAndQuery, +} + +/// The various parts of a URI. +/// +/// This struct is used to provide to and retrieve from a URI. +#[derive(Debug, Default)] +pub struct Parts { + /// The scheme component of a URI + pub scheme: Option, + + /// The authority component of a URI + pub authority: Option, + + /// The origin-form component of a URI + pub path_and_query: Option, + + /// Allow extending in the future + _priv: (), +} + +/// An error resulting from a failed attempt to construct a URI. +#[derive(Debug)] +pub struct InvalidUri(ErrorKind); + +/// An error resulting from a failed attempt to construct a URI. +#[derive(Debug)] +pub struct InvalidUriBytes(InvalidUri); + +/// An error resulting from a failed attempt to construct a URI. +#[derive(Debug)] +pub struct InvalidUriParts(InvalidUri); + +#[derive(Debug, Eq, PartialEq)] +enum ErrorKind { + InvalidUriChar, + InvalidScheme, + InvalidAuthority, + InvalidPort, + InvalidFormat, + SchemeMissing, + AuthorityMissing, + PathAndQueryMissing, + TooLong, + Empty, + SchemeTooLong, +} + +// u16::MAX is reserved for None +const MAX_LEN: usize = (u16::MAX - 1) as usize; + +const URI_CHARS: [u8; 256] = [ + // 0 1 2 3 4 5 6 7 8 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x + 0, 0, 0, b'!', 0, b'#', b'$', 0, b'&', b'\'', // 3x + b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', b'0', b'1', // 4x + b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', b';', // 5x + 0, b'=', 0, b'?', b'@', b'A', b'B', b'C', b'D', b'E', // 6x + b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x + b'Z', b'[', 0, b']', 0, b'_', 0, b'a', b'b', b'c', // 9x + b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x + b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x + b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x + 0, 0, 0, 0, 0, 0 // 25x +]; + +impl Uri { + /// Creates a new builder-style object to manufacture a `Uri`. + /// + /// This method returns an instance of `Builder` which can be usd to + /// create a `Uri`. + /// + /// # Examples + /// + /// ``` + /// use http::Uri; + /// + /// let uri = Uri::builder() + /// .scheme("https") + /// .authority("hyper.rs") + /// .path_and_query("/") + /// .build() + /// .unwrap(); + /// ``` + pub fn builder() -> Builder { + Builder::new() + } + + /// Attempt to convert a `Uri` from `Parts` + pub fn from_parts(src: Parts) -> Result { + if src.scheme.is_some() { + if src.authority.is_none() { + return Err(ErrorKind::AuthorityMissing.into()); + } + + if src.path_and_query.is_none() { + return Err(ErrorKind::PathAndQueryMissing.into()); + } + } else { + if src.authority.is_some() && src.path_and_query.is_some() { + return Err(ErrorKind::SchemeMissing.into()); + } + } + + let scheme = match src.scheme { + Some(scheme) => scheme, + None => Scheme { inner: Scheme2::None }, + }; + + let authority = match src.authority { + Some(authority) => authority, + None => Authority::empty(), + }; + + let path_and_query = match src.path_and_query { + Some(path_and_query) => path_and_query, + None => PathAndQuery::empty(), + }; + + Ok(Uri { + scheme: scheme, + authority: authority, + path_and_query: path_and_query, + }) + } + + /// Attempt to convert a `Uri` from `Bytes` + /// + /// This function will be replaced by a `TryFrom` implementation once the + /// trait lands in stable. + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("http://example.com/foo"); + /// let uri = Uri::from_shared(bytes).unwrap(); + /// + /// assert_eq!(uri.host().unwrap(), "example.com"); + /// assert_eq!(uri.path(), "/foo"); + /// # } + /// ``` + pub fn from_shared(s: Bytes) -> Result { + use self::ErrorKind::*; + + if s.len() > MAX_LEN { + return Err(TooLong.into()); + } + + match s.len() { + 0 => { + return Err(Empty.into()); + } + 1 => { + match s[0] { + b'/' => { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::slash(), + }); + } + b'*' => { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::star(), + }); + } + _ => { + let authority = Authority::from_shared(s)?; + + return Ok(Uri { + scheme: Scheme::empty(), + authority: authority, + path_and_query: PathAndQuery::empty(), + }); + } + } + } + _ => {} + } + + if s[0] == b'/' { + return Ok(Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::from_shared(s)?, + }); + } + + parse_full(s) + } + + /// Convert a `Uri` from a static string. + /// + /// This function will not perform any copying, however the string is + /// checked to ensure that it is valid. + /// + /// # Panics + /// + /// This function panics if the argument is an invalid URI. + /// + /// # Examples + /// + /// ``` + /// # use http::uri::Uri; + /// let uri = Uri::from_static("http://example.com/foo"); + /// + /// assert_eq!(uri.host().unwrap(), "example.com"); + /// assert_eq!(uri.path(), "/foo"); + /// ``` + pub fn from_static(src: &'static str) -> Self { + let s = Bytes::from_static(src.as_bytes()); + match Uri::from_shared(s) { + Ok(uri) => uri, + Err(e) => panic!("static str is not valid URI: {}", e), + } + } + + /// Convert a `Uri` into `Parts`. + /// + /// # Note + /// + /// This is just an inherent method providing the same functionality as + /// `let parts: Parts = uri.into()` + /// + /// # Examples + /// + /// ``` + /// # use http::uri::*; + /// let uri: Uri = "/foo".parse().unwrap(); + /// + /// let parts = uri.into_parts(); + /// + /// assert_eq!(parts.path_and_query.unwrap(), "/foo"); + /// + /// assert!(parts.scheme.is_none()); + /// assert!(parts.authority.is_none()); + /// ``` + #[inline] + pub fn into_parts(self) -> Parts { + self.into() + } + + /// Returns the path & query components of the Uri + #[inline] + pub fn path_and_query(&self) -> Option<&PathAndQuery> { + if !self.scheme.inner.is_none() || self.authority.data.is_empty() { + Some(&self.path_and_query) + } else { + None + } + } + + /// Get the path of this `Uri`. + /// + /// Both relative and absolute URIs contain a path component, though it + /// might be the empty string. The path component is **case sensitive**. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |--------| + /// | + /// path + /// ``` + /// + /// If the URI is `*` then the path component is equal to `*`. + /// + /// # Examples + /// + /// A relative URI + /// + /// ``` + /// # use http::Uri; + /// + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.path(), "/hello/world"); + /// ``` + /// + /// An absolute URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.path(), "/hello/world"); + /// ``` + #[inline] + pub fn path(&self) -> &str { + if self.has_path() { + self.path_and_query.path() + } else { + "" + } + } + + /// Get the scheme of this `Uri`. + /// + /// The URI scheme refers to a specification for assigning identifiers + /// within that scheme. Only absolute URIs contain a scheme component, but + /// not all absolute URIs will contain a scheme component. Although scheme + /// names are case-insensitive, the canonical form is lowercase. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-| + /// | + /// scheme + /// ``` + /// + /// # Examples + /// + /// Absolute URI + /// + /// ``` + /// use http::uri::{Scheme, Uri}; + /// + /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.scheme_part(), Some(&Scheme::HTTP)); + /// ``` + /// + /// + /// Relative URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert!(uri.scheme_part().is_none()); + /// ``` + #[inline] + pub fn scheme_part(&self) -> Option<&Scheme> { + if self.scheme.inner.is_none() { + None + } else { + Some(&self.scheme) + } + } + + #[deprecated(since = "0.1.2", note = "use scheme_part or scheme_str instead")] + #[doc(hidden)] + #[inline] + pub fn scheme(&self) -> Option<&str> { + self.scheme_str() + } + + /// Get the scheme of this `Uri` as a `&str`. + /// + /// # Example + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.scheme_str(), Some("http")); + /// ``` + #[inline] + pub fn scheme_str(&self) -> Option<&str> { + if self.scheme.inner.is_none() { + None + } else { + Some(self.scheme.as_str()) + } + } + + /// Get the authority of this `Uri`. + /// + /// The authority is a hierarchical element for naming authority such that + /// the remainder of the URI is delegated to that authority. For HTTP, the + /// authority consists of the host and port. The host portion of the + /// authority is **case-insensitive**. + /// + /// The authority also includes a `username:password` component, however + /// the use of this is deprecated and should be avoided. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-------------------------------| + /// | + /// authority + /// ``` + /// + /// This function will be renamed to `authority` in the next semver release. + /// + /// # Examples + /// + /// Absolute URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.authority_part().map(|a| a.as_str()), Some("example.org:80")); + /// ``` + /// + /// + /// Relative URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert!(uri.authority_part().is_none()); + /// ``` + #[inline] + pub fn authority_part(&self) -> Option<&Authority> { + if self.authority.data.is_empty() { + None + } else { + Some(&self.authority) + } + } + + #[deprecated(since = "0.1.1", note = "use authority_part instead")] + #[doc(hidden)] + #[inline] + pub fn authority(&self) -> Option<&str> { + if self.authority.data.is_empty() { + None + } else { + Some(self.authority.as_str()) + } + } + + /// Get the host of this `Uri`. + /// + /// The host subcomponent of authority is identified by an IP literal + /// encapsulated within square brackets, an IPv4 address in dotted- decimal + /// form, or a registered name. The host subcomponent is **case-insensitive**. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |---------| + /// | + /// host + /// ``` + /// + /// # Examples + /// + /// Absolute URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.host(), Some("example.org")); + /// ``` + /// + /// + /// Relative URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert!(uri.host().is_none()); + /// ``` + #[inline] + pub fn host(&self) -> Option<&str> { + self.authority_part().map(|a| a.host()) + } + + #[deprecated(since="0.1.14", note="use `port_part` or `port_u16` instead")] + #[doc(hidden)] + pub fn port(&self) -> Option { + self.port_u16() + } + + /// Get the port part of this `Uri`. + /// + /// The port subcomponent of authority is designated by an optional port + /// number following the host and delimited from it by a single colon (":") + /// character. It can be turned into a decimal port number with the `as_u16` + /// method or as a `str` with the `as_str` method. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-| + /// | + /// port + /// ``` + /// + /// # Examples + /// + /// Absolute URI with port + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); + /// + /// let port = uri.port_part().unwrap(); + /// assert_eq!(port.as_u16(), 80); + /// ``` + /// + /// Absolute URI without port + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org/hello/world".parse().unwrap(); + /// + /// assert!(uri.port_part().is_none()); + /// ``` + /// + /// Relative URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert!(uri.port_part().is_none()); + /// ``` + pub fn port_part(&self) -> Option> { + self.authority_part() + .and_then(|a| a.port_part()) + } + + /// Get the port of this `Uri` as a `u16`. + /// + /// + /// # Example + /// + /// ``` + /// # use http::{Uri, uri::Port}; + /// let uri: Uri = "http://example.org:80/hello/world".parse().unwrap(); + /// + /// assert_eq!(uri.port_u16(), Some(80)); + /// ``` + pub fn port_u16(&self) -> Option { + self.port_part().and_then(|p| Some(p.as_u16())) + } + + /// Get the query string of this `Uri`, starting after the `?`. + /// + /// The query component contains non-hierarchical data that, along with data + /// in the path component, serves to identify a resource within the scope of + /// the URI's scheme and naming authority (if any). The query component is + /// indicated by the first question mark ("?") character and terminated by a + /// number sign ("#") character or by the end of the URI. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-------------------| + /// | + /// query + /// ``` + /// + /// # Examples + /// + /// Absolute URI + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "http://example.org/hello/world?key=value".parse().unwrap(); + /// + /// assert_eq!(uri.query(), Some("key=value")); + /// ``` + /// + /// Relative URI with a query string component + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world?key=value&foo=bar".parse().unwrap(); + /// + /// assert_eq!(uri.query(), Some("key=value&foo=bar")); + /// ``` + /// + /// Relative URI without a query string component + /// + /// ``` + /// # use http::Uri; + /// let uri: Uri = "/hello/world".parse().unwrap(); + /// + /// assert!(uri.query().is_none()); + /// ``` + #[inline] + pub fn query(&self) -> Option<&str> { + self.path_and_query.query() + } + + fn has_path(&self) -> bool { + !self.path_and_query.data.is_empty() || !self.scheme.inner.is_none() + } +} + +impl<'a> HttpTryFrom<&'a str> for Uri { + type Error = InvalidUri; + + #[inline] + fn try_from(t: &'a str) -> Result { + t.parse() + } +} + +impl<'a> HttpTryFrom<&'a String> for Uri { + type Error = InvalidUri; + + #[inline] + fn try_from(t: &'a String) -> Result { + t.parse() + } +} + +impl HttpTryFrom for Uri { + type Error = InvalidUriBytes; + + #[inline] + fn try_from(t: String) -> Result { + Uri::from_shared(Bytes::from(t)) + } +} + +impl HttpTryFrom for Uri { + type Error = InvalidUriBytes; + + #[inline] + fn try_from(t: Bytes) -> Result { + Uri::from_shared(t) + } +} + +impl HttpTryFrom for Uri { + type Error = InvalidUriParts; + + #[inline] + fn try_from(src: Parts) -> Result { + Uri::from_parts(src) + } +} + +impl<'a> HttpTryFrom<&'a Uri> for Uri { + type Error = ::Error; + + #[inline] + fn try_from(src: &'a Uri) -> Result { + Ok(src.clone()) + } +} + +/// Convert a `Uri` from parts +/// +/// # Examples +/// +/// Relative URI +/// +/// ``` +/// # use http::uri::*; +/// let mut parts = Parts::default(); +/// parts.path_and_query = Some("/foo".parse().unwrap()); +/// +/// let uri = Uri::from_parts(parts).unwrap(); +/// +/// assert_eq!(uri.path(), "/foo"); +/// +/// assert!(uri.scheme_part().is_none()); +/// assert!(uri.authority().is_none()); +/// ``` +/// +/// Absolute URI +/// +/// ``` +/// # use http::uri::*; +/// let mut parts = Parts::default(); +/// parts.scheme = Some("http".parse().unwrap()); +/// parts.authority = Some("foo.com".parse().unwrap()); +/// parts.path_and_query = Some("/foo".parse().unwrap()); +/// +/// let uri = Uri::from_parts(parts).unwrap(); +/// +/// assert_eq!(uri.scheme_part().unwrap().as_str(), "http"); +/// assert_eq!(uri.authority().unwrap(), "foo.com"); +/// assert_eq!(uri.path(), "/foo"); +/// ``` +impl From for Parts { + fn from(src: Uri) -> Self { + let path_and_query = if src.has_path() { + Some(src.path_and_query) + } else { + None + }; + + let scheme = match src.scheme.inner { + Scheme2::None => None, + _ => Some(src.scheme), + }; + + let authority = if src.authority.data.is_empty() { + None + } else { + Some(src.authority) + }; + + Parts { + scheme: scheme, + authority: authority, + path_and_query: path_and_query, + _priv: (), + } + } +} + +fn parse_full(mut s: Bytes) -> Result { + // Parse the scheme + let scheme = match Scheme2::parse(&s[..]).map_err(InvalidUriBytes)? { + Scheme2::None => Scheme2::None, + Scheme2::Standard(p) => { + // TODO: use truncate + let _ = s.split_to(p.len() + 3); + Scheme2::Standard(p) + } + Scheme2::Other(n) => { + // Grab the protocol + let mut scheme = s.split_to(n + 3); + + // Strip ://, TODO: truncate + let _ = scheme.split_off(n); + + // Allocate the ByteStr + let val = unsafe { ByteStr::from_utf8_unchecked(scheme) }; + + Scheme2::Other(Box::new(val)) + } + }; + + // Find the end of the authority. The scheme will already have been + // extracted. + let authority_end = Authority::parse(&s[..]).map_err(InvalidUriBytes)?; + + if scheme.is_none() { + if authority_end != s.len() { + return Err(ErrorKind::InvalidFormat.into()); + } + + let authority = Authority { + data: unsafe { ByteStr::from_utf8_unchecked(s) }, + }; + + return Ok(Uri { + scheme: scheme.into(), + authority: authority, + path_and_query: PathAndQuery::empty(), + }); + } + + // Authority is required when absolute + if authority_end == 0 { + return Err(ErrorKind::InvalidFormat.into()); + } + + let authority = s.split_to(authority_end); + let authority = Authority { + data: unsafe { ByteStr::from_utf8_unchecked(authority) }, + }; + + Ok(Uri { + scheme: scheme.into(), + authority: authority, + path_and_query: PathAndQuery::from_shared(s)?, + }) +} + +impl FromStr for Uri { + type Err = InvalidUri; + + #[inline] + fn from_str(s: &str) -> Result { + Uri::from_shared(s.into()).map_err(|e| e.0) + } +} + +impl PartialEq for Uri { + fn eq(&self, other: &Uri) -> bool { + if self.scheme_part() != other.scheme_part() { + return false; + } + + if self.authority_part() != other.authority_part() { + return false; + } + + if self.path() != other.path() { + return false; + } + + if self.query() != other.query() { + return false; + } + + true + } +} + +impl PartialEq for Uri { + fn eq(&self, other: &str) -> bool { + let mut other = other.as_bytes(); + let mut absolute = false; + + if let Some(scheme) = self.scheme_part() { + let scheme = scheme.as_str().as_bytes(); + absolute = true; + + if other.len() < scheme.len() + 3 { + return false; + } + + if !scheme.eq_ignore_ascii_case(&other[..scheme.len()]) { + return false; + } + + other = &other[scheme.len()..]; + + if &other[..3] != b"://" { + return false; + } + + other = &other[3..]; + } + + if let Some(auth) = self.authority_part() { + let len = auth.data.len(); + absolute = true; + + if other.len() < len { + return false; + } + + if !auth.data.as_bytes().eq_ignore_ascii_case(&other[..len]) { + return false; + } + + other = &other[len..]; + } + + let path = self.path(); + + if other.len() < path.len() || path.as_bytes() != &other[..path.len()] { + if absolute && path == "/" { + // PathAndQuery can be ommitted, fall through + } else { + return false; + } + } else { + other = &other[path.len()..]; + } + + if let Some(query) = self.query() { + if other.len() == 0 { + return query.len() == 0; + } + + if other[0] != b'?' { + return false; + } + + other = &other[1..]; + + if other.len() < query.len() { + return false; + } + + if query.as_bytes() != &other[..query.len()] { + return false; + } + + other = &other[query.len()..]; + } + + other.is_empty() || other[0] == b'#' + } +} + +impl PartialEq for str { + fn eq(&self, uri: &Uri) -> bool { + uri == self + } +} + +impl<'a> PartialEq<&'a str> for Uri { + fn eq(&self, other: & &'a str) -> bool { + self == *other + } +} + +impl<'a> PartialEq for &'a str { + fn eq(&self, uri: &Uri) -> bool { + uri == *self + } +} + +impl Eq for Uri {} + +/// Returns a `Uri` representing `/` +impl Default for Uri { + #[inline] + fn default() -> Uri { + Uri { + scheme: Scheme::empty(), + authority: Authority::empty(), + path_and_query: PathAndQuery::slash(), + } + } +} + +impl fmt::Display for Uri { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(scheme) = self.scheme_part() { + write!(f, "{}://", scheme)?; + } + + if let Some(authority) = self.authority_part() { + write!(f, "{}", authority)?; + } + + write!(f, "{}", self.path())?; + + if let Some(query) = self.query() { + write!(f, "?{}", query)?; + } + + Ok(()) + } +} + +impl fmt::Debug for Uri { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl From for InvalidUri { + fn from(src: ErrorKind) -> InvalidUri { + InvalidUri(src) + } +} + +impl From for InvalidUriBytes { + fn from(src: ErrorKind) -> InvalidUriBytes { + InvalidUriBytes(src.into()) + } +} + +impl From for InvalidUriParts { + fn from(src: ErrorKind) -> InvalidUriParts { + InvalidUriParts(src.into()) + } +} + +impl fmt::Display for InvalidUri { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for InvalidUri { + fn description(&self) -> &str { + match self.0 { + ErrorKind::InvalidUriChar => "invalid uri character", + ErrorKind::InvalidScheme => "invalid scheme", + ErrorKind::InvalidAuthority => "invalid authority", + ErrorKind::InvalidPort => "invalid port", + ErrorKind::InvalidFormat => "invalid format", + ErrorKind::SchemeMissing => "scheme missing", + ErrorKind::AuthorityMissing => "authority missing", + ErrorKind::PathAndQueryMissing => "path missing", + ErrorKind::TooLong => "uri too long", + ErrorKind::Empty => "empty string", + ErrorKind::SchemeTooLong => "scheme too long", + } + } +} + +impl fmt::Display for InvalidUriBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl fmt::Display for InvalidUriParts { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InvalidUriBytes { + fn description(&self) -> &str { + self.0.description() + } +} + +impl Error for InvalidUriParts { + fn description(&self) -> &str { + self.0.description() + } +} + +impl Hash for Uri { + fn hash(&self, state: &mut H) where H: Hasher { + if !self.scheme.inner.is_none() { + self.scheme.hash(state); + state.write_u8(0xff); + } + + if let Some(auth) = self.authority_part() { + auth.hash(state); + } + + Hash::hash_slice(self.path().as_bytes(), state); + + if let Some(query) = self.query() { + b'?'.hash(state); + Hash::hash_slice(query.as_bytes(), state); + } + } +} diff --git a/http/src/uri/path.rs b/http/src/uri/path.rs new file mode 100644 index 000000000..803dd7144 --- /dev/null +++ b/http/src/uri/path.rs @@ -0,0 +1,544 @@ +use std::{cmp, fmt, str}; +use std::str::FromStr; + +use bytes::Bytes; + +use byte_str::ByteStr; +use convert::HttpTryFrom; +use super::{ErrorKind, InvalidUri, InvalidUriBytes}; + +/// Represents the path component of a URI +#[derive(Clone)] +pub struct PathAndQuery { + pub(super) data: ByteStr, + pub(super) query: u16, +} + +const NONE: u16 = ::std::u16::MAX; + +impl PathAndQuery { + /// Attempt to convert a `PathAndQuery` from `Bytes`. + /// + /// This function will be replaced by a `TryFrom` implementation once the + /// trait lands in stable. + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("/hello?world"); + /// let path_and_query = PathAndQuery::from_shared(bytes).unwrap(); + /// + /// assert_eq!(path_and_query.path(), "/hello"); + /// assert_eq!(path_and_query.query(), Some("world")); + /// # } + /// ``` + pub fn from_shared(mut src: Bytes) -> Result { + let mut query = NONE; + let mut fragment = None; + + // block for iterator borrow + { + let mut iter = src.as_ref().iter().enumerate(); + + // path ... + for (i, &b) in &mut iter { + // See https://url.spec.whatwg.org/#path-state + match b { + b'?' => { + debug_assert_eq!(query, NONE); + query = i as u16; + break; + } + b'#' => { + fragment = Some(i); + break; + }, + + // This is the range of bytes that don't need to be + // percent-encoded in the path. If it should have been + // percent-encoded, then error. + 0x21 | + 0x24...0x3B | + 0x3D | + 0x40...0x5F | + 0x61...0x7A | + 0x7C | + 0x7E => {}, + + _ => return Err(ErrorKind::InvalidUriChar.into()), + } + } + + // query ... + if query != NONE { + for (i, &b) in iter { + match b { + // While queries *should* be percent-encoded, most + // bytes are actually allowed... + // See https://url.spec.whatwg.org/#query-state + // + // Allowed: 0x21 / 0x24 - 0x3B / 0x3D / 0x3F - 0x7E + 0x21 | + 0x24...0x3B | + 0x3D | + 0x3F...0x7E => {}, + + b'#' => { + fragment = Some(i); + break; + }, + + _ => return Err(ErrorKind::InvalidUriChar.into()), + } + } + } + } + + if let Some(i) = fragment { + src.truncate(i); + } + + Ok(PathAndQuery { + data: unsafe { ByteStr::from_utf8_unchecked(src) }, + query: query, + }) + } + + /// Convert a `PathAndQuery` from a static string. + /// + /// This function will not perform any copying, however the string is + /// checked to ensure that it is valid. + /// + /// # Panics + /// + /// This function panics if the argument is an invalid path and query. + /// + /// # Examples + /// + /// ``` + /// # use http::uri::*; + /// let v = PathAndQuery::from_static("/hello?world"); + /// + /// assert_eq!(v.path(), "/hello"); + /// assert_eq!(v.query(), Some("world")); + /// ``` + #[inline] + pub fn from_static(src: &'static str) -> Self { + let src = Bytes::from_static(src.as_bytes()); + + PathAndQuery::from_shared(src) + .unwrap() + } + + pub(super) fn empty() -> Self { + PathAndQuery { + data: ByteStr::new(), + query: NONE, + } + } + + pub(super) fn slash() -> Self { + PathAndQuery { + data: ByteStr::from_static("/"), + query: NONE, + } + } + + pub(super) fn star() -> Self { + PathAndQuery { + data: ByteStr::from_static("*"), + query: NONE, + } + } + + /// Returns the path component + /// + /// The path component is **case sensitive**. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |--------| + /// | + /// path + /// ``` + /// + /// If the URI is `*` then the path component is equal to `*`. + /// + /// # Examples + /// + /// ``` + /// # use http::uri::*; + /// + /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap(); + /// + /// assert_eq!(path_and_query.path(), "/hello/world"); + /// ``` + #[inline] + pub fn path(&self) -> &str { + let ret = if self.query == NONE { + &self.data[..] + } else { + &self.data[..self.query as usize] + }; + + if ret.is_empty() { + return "/"; + } + + ret + } + + /// Returns the query string component + /// + /// The query component contains non-hierarchical data that, along with data + /// in the path component, serves to identify a resource within the scope of + /// the URI's scheme and naming authority (if any). The query component is + /// indicated by the first question mark ("?") character and terminated by a + /// number sign ("#") character or by the end of the URI. + /// + /// ```notrust + /// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1 + /// |-------------------| + /// | + /// query + /// ``` + /// + /// # Examples + /// + /// With a query string component + /// + /// ``` + /// # use http::uri::*; + /// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap(); + /// + /// assert_eq!(path_and_query.query(), Some("key=value&foo=bar")); + /// ``` + /// + /// Without a query string component + /// + /// ``` + /// # use http::uri::*; + /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap(); + /// + /// assert!(path_and_query.query().is_none()); + /// ``` + #[inline] + pub fn query(&self) -> Option<&str> { + if self.query == NONE { + None + } else { + let i = self.query + 1; + Some(&self.data[i as usize..]) + } + } + + /// Returns the path and query as a string component. + /// + /// # Examples + /// + /// With a query string component + /// + /// ``` + /// # use http::uri::*; + /// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap(); + /// + /// assert_eq!(path_and_query.as_str(), "/hello/world?key=value&foo=bar"); + /// ``` + /// + /// Without a query string component + /// + /// ``` + /// # use http::uri::*; + /// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap(); + /// + /// assert_eq!(path_and_query.as_str(), "/hello/world"); + /// ``` + #[inline] + pub fn as_str(&self) -> &str { + let ret = &self.data[..]; + if ret.is_empty() { + return "/"; + } + ret + } + + /// Converts this `PathAndQuery` back to a sequence of bytes + #[inline] + pub fn into_bytes(self) -> Bytes { + self.into() + } +} + +impl HttpTryFrom for PathAndQuery { + type Error = InvalidUriBytes; + #[inline] + fn try_from(bytes: Bytes) -> Result { + PathAndQuery::from_shared(bytes) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for PathAndQuery { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a [u8]) -> Result { + PathAndQuery::from_shared(s.into()).map_err(|e| e.0) + } +} + +impl<'a> HttpTryFrom<&'a str> for PathAndQuery { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a str) -> Result { + HttpTryFrom::try_from(s.as_bytes()) + } +} + +impl FromStr for PathAndQuery { + type Err = InvalidUri; + #[inline] + fn from_str(s: &str) -> Result { + HttpTryFrom::try_from(s) + } +} + +impl From for Bytes { + fn from(src: PathAndQuery) -> Bytes { + src.data.into() + } +} + +impl fmt::Debug for PathAndQuery { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for PathAndQuery { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if !self.data.is_empty() { + match self.data.as_bytes()[0] { + b'/' | b'*' => write!(fmt, "{}", &self.data[..]), + _ => write!(fmt, "/{}", &self.data[..]), + } + } else { + write!(fmt, "/") + } + } +} + +// ===== PartialEq / PartialOrd ===== + +impl PartialEq for PathAndQuery { + #[inline] + fn eq(&self, other: &PathAndQuery) -> bool { + self.data == other.data + } +} + +impl Eq for PathAndQuery {} + +impl PartialEq for PathAndQuery { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_str() == other + } +} + +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &PathAndQuery) -> bool { + self == &other.as_str() + } +} + +impl<'a> PartialEq<&'a str> for PathAndQuery { + #[inline] + fn eq(&self, other: &&'a str) -> bool { + self.as_str() == *other + } +} + +impl PartialEq for str { + #[inline] + fn eq(&self, other: &PathAndQuery) -> bool { + self == other.as_str() + } +} + +impl PartialEq for PathAndQuery { + #[inline] + fn eq(&self, other: &String) -> bool { + self.as_str() == other.as_str() + } +} + +impl PartialEq for String { + #[inline] + fn eq(&self, other: &PathAndQuery) -> bool { + self.as_str() == other.as_str() + } +} + +impl PartialOrd for PathAndQuery { + #[inline] + fn partial_cmp(&self, other: &PathAndQuery) -> Option { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl PartialOrd for PathAndQuery { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + self.as_str().partial_cmp(other) + } +} + +impl PartialOrd for str { + #[inline] + fn partial_cmp(&self, other: &PathAndQuery) -> Option { + self.partial_cmp(other.as_str()) + } +} + +impl<'a> PartialOrd<&'a str> for PathAndQuery { + #[inline] + fn partial_cmp(&self, other: &&'a str) -> Option { + self.as_str().partial_cmp(*other) + } +} + +impl<'a> PartialOrd for &'a str { + #[inline] + fn partial_cmp(&self, other: &PathAndQuery) -> Option { + self.partial_cmp(&other.as_str()) + } +} + +impl PartialOrd for PathAndQuery { + #[inline] + fn partial_cmp(&self, other: &String) -> Option { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl PartialOrd for String { + #[inline] + fn partial_cmp(&self, other: &PathAndQuery) -> Option { + self.as_str().partial_cmp(other.as_str()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn equal_to_self_of_same_path() { + let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + let p2: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + assert_eq!(p1, p2); + assert_eq!(p2, p1); + } + + #[test] + fn not_equal_to_self_of_different_path() { + let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + let p2: PathAndQuery = "/world&foo=bar".parse().unwrap(); + assert_ne!(p1, p2); + assert_ne!(p2, p1); + } + + #[test] + fn equates_with_a_str() { + let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + assert_eq!(&path_and_query, "/hello/world&foo=bar"); + assert_eq!("/hello/world&foo=bar", &path_and_query); + assert_eq!(path_and_query, "/hello/world&foo=bar"); + assert_eq!("/hello/world&foo=bar", path_and_query); + } + + #[test] + fn not_equal_with_a_str_of_a_different_path() { + let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + // as a reference + assert_ne!(&path_and_query, "/hello&foo=bar"); + assert_ne!("/hello&foo=bar", &path_and_query); + // without reference + assert_ne!(path_and_query, "/hello&foo=bar"); + assert_ne!("/hello&foo=bar", path_and_query); + } + + #[test] + fn equates_with_a_string() { + let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + assert_eq!(path_and_query, "/hello/world&foo=bar".to_string()); + assert_eq!("/hello/world&foo=bar".to_string(), path_and_query); + } + + #[test] + fn not_equal_with_a_string_of_a_different_path() { + let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap(); + assert_ne!(path_and_query, "/hello&foo=bar".to_string()); + assert_ne!("/hello&foo=bar".to_string(), path_and_query); + } + + #[test] + fn compares_to_self() { + let p1: PathAndQuery = "/a/world&foo=bar".parse().unwrap(); + let p2: PathAndQuery = "/b/world&foo=bar".parse().unwrap(); + assert!(p1 < p2); + assert!(p2 > p1); + } + + #[test] + fn compares_with_a_str() { + let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap(); + // by ref + assert!(&path_and_query < "/c/world&foo=bar"); + assert!("/c/world&foo=bar" > &path_and_query); + assert!(&path_and_query > "/a/world&foo=bar"); + assert!("/a/world&foo=bar" < &path_and_query); + + // by val + assert!(path_and_query < "/c/world&foo=bar"); + assert!("/c/world&foo=bar" > path_and_query); + assert!(path_and_query > "/a/world&foo=bar"); + assert!("/a/world&foo=bar" < path_and_query); + } + + #[test] + fn compares_with_a_string() { + let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap(); + assert!(path_and_query < "/c/world&foo=bar".to_string()); + assert!("/c/world&foo=bar".to_string() > path_and_query); + assert!(path_and_query > "/a/world&foo=bar".to_string()); + assert!("/a/world&foo=bar".to_string() < path_and_query); + } + + #[test] + fn ignores_valid_percent_encodings() { + assert_eq!("/a%20b", pq("/a%20b?r=1").path()); + assert_eq!("qr=%31", pq("/a/b?qr=%31").query().unwrap()); + } + + #[test] + fn ignores_invalid_percent_encodings() { + assert_eq!("/a%%b", pq("/a%%b?r=1").path()); + assert_eq!("/aaa%", pq("/aaa%").path()); + assert_eq!("/aaa%", pq("/aaa%?r=1").path()); + assert_eq!("/aa%2", pq("/aa%2").path()); + assert_eq!("/aa%2", pq("/aa%2?r=1").path()); + assert_eq!("qr=%3", pq("/a/b?qr=%3").query().unwrap()); + } + + fn pq(s: &str) -> PathAndQuery { + s.parse().expect(&format!("parsing {}", s)) + } +} diff --git a/http/src/uri/port.rs b/http/src/uri/port.rs new file mode 100644 index 000000000..d3177a7aa --- /dev/null +++ b/http/src/uri/port.rs @@ -0,0 +1,158 @@ +use std::fmt; + +use super::{ErrorKind, InvalidUri}; + +/// The port component of a URI. +pub struct Port { + port: u16, + repr: T, +} + +impl Port { + /// Returns the port number as a `u16`. + /// + /// # Examples + /// + /// Port as `u16`. + /// + /// ``` + /// # use http::uri::Authority; + /// let authority: Authority = "example.org:80".parse().unwrap(); + /// + /// let port = authority.port_part().unwrap(); + /// assert_eq!(port.as_u16(), 80); + /// ``` + pub fn as_u16(&self) -> u16 { + self.port + } +} + +impl Port +where + T: AsRef, +{ + /// Converts a `str` to a port number. + /// + /// The supplied `str` must be a valid u16. + pub(crate) fn from_str(bytes: T) -> Result { + bytes + .as_ref() + .parse::() + .map(|port| Port { + port, + repr: bytes, + }) + .map_err(|_| { + ErrorKind::InvalidPort.into() + }) + } + + /// Returns the port number as a `str`. + /// + /// # Examples + /// + /// Port as `str`. + /// + /// ``` + /// # use http::uri::Authority; + /// let authority: Authority = "example.org:80".parse().unwrap(); + /// + /// let port = authority.port_part().unwrap(); + /// assert_eq!(port.as_str(), "80"); + /// ``` + pub fn as_str(&self) -> &str { + self.repr.as_ref() + } +} + +impl fmt::Debug for Port +where + T: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Port") + .field(&self.port) + .finish() + } +} + +impl fmt::Display for Port { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Use `u16::fmt` so that it respects any formatting flags that + // may have been set (like padding, align, etc). + fmt::Display::fmt(&self.port, f) + } +} + +impl From> for u16 { + fn from(port: Port) -> Self { + port.as_u16() + } +} + +impl AsRef for Port +where + T: AsRef, +{ + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl PartialEq> for Port { + fn eq(&self, other: &Port) -> bool { + self.port == other.port + } +} + +impl PartialEq for Port { + fn eq(&self, other: &u16) -> bool { + self.port == *other + } +} + +impl PartialEq> for u16 { + fn eq(&self, other: &Port) -> bool { + other.port == *self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn partialeq_port() { + let port_a = Port::from_str("8080").unwrap(); + let port_b = Port::from_str("8080").unwrap(); + assert_eq!(port_a, port_b); + } + + #[test] + fn partialeq_port_different_reprs() { + let port_a = Port { + repr: "8081", + port: 8081, + }; + let port_b = Port { + repr: String::from("8081"), + port: 8081, + }; + assert_eq!(port_a, port_b); + assert_eq!(port_b, port_a); + } + + #[test] + fn partialeq_u16() { + let port = Port::from_str("8080").unwrap(); + // test equals in both directions + assert_eq!(port, 8080); + assert_eq!(8080, port); + } + + #[test] + fn u16_from_port() { + let port = Port::from_str("8080").unwrap(); + assert_eq!(8080, u16::from(port)); + } +} diff --git a/http/src/uri/scheme.rs b/http/src/uri/scheme.rs new file mode 100644 index 000000000..78e59fc65 --- /dev/null +++ b/http/src/uri/scheme.rs @@ -0,0 +1,389 @@ +// Deprecated in 1.26, needed until our minimum version is >=1.23. +#[allow(unused, deprecated)] +use std::ascii::AsciiExt; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::str::FromStr; + +use bytes::Bytes; + +use byte_str::ByteStr; +use convert::HttpTryFrom; +use super::{ErrorKind, InvalidUri, InvalidUriBytes}; + +/// Represents the scheme component of a URI +#[derive(Clone)] +pub struct Scheme { + pub(super) inner: Scheme2, +} + +#[derive(Clone, Debug)] +pub(super) enum Scheme2> { + None, + Standard(Protocol), + Other(T), +} + +#[derive(Copy, Clone, Debug)] +pub(super) enum Protocol { + Http, + Https, +} + +impl Scheme { + /// HTTP protocol scheme + pub const HTTP: Scheme = Scheme { + inner: Scheme2::Standard(Protocol::Http), + }; + + /// HTTP protocol over TLS. + pub const HTTPS: Scheme = Scheme { + inner: Scheme2::Standard(Protocol::Https), + }; + + /// Attempt to convert a `Scheme` from `Bytes` + /// + /// This function will be replaced by a `TryFrom` implementation once the + /// trait lands in stable. + /// + /// # Examples + /// + /// ``` + /// # extern crate http; + /// # use http::uri::*; + /// extern crate bytes; + /// + /// use bytes::Bytes; + /// + /// # pub fn main() { + /// let bytes = Bytes::from("http"); + /// let scheme = Scheme::from_shared(bytes).unwrap(); + /// + /// assert_eq!(scheme.as_str(), "http"); + /// # } + /// ``` + pub fn from_shared(s: Bytes) -> Result { + use self::Scheme2::*; + + match Scheme2::parse_exact(&s[..]).map_err(InvalidUriBytes)? { + None => Err(ErrorKind::InvalidScheme.into()), + Standard(p) => Ok(Standard(p).into()), + Other(_) => { + let b = unsafe { ByteStr::from_utf8_unchecked(s) }; + Ok(Other(Box::new(b)).into()) + } + } + } + + pub(super) fn empty() -> Self { + Scheme { + inner: Scheme2::None, + } + } + + /// Return a str representation of the scheme + /// + /// # Examples + /// + /// ``` + /// # use http::uri::*; + /// let scheme: Scheme = "http".parse().unwrap(); + /// assert_eq!(scheme.as_str(), "http"); + /// ``` + #[inline] + pub fn as_str(&self) -> &str { + use self::Scheme2::*; + use self::Protocol::*; + + match self.inner { + Standard(Http) => "http", + Standard(Https) => "https", + Other(ref v) => &v[..], + None => unreachable!(), + } + } + + /// Converts this `Scheme` back to a sequence of bytes + #[inline] + pub fn into_bytes(self) -> Bytes { + self.into() + } +} + +impl HttpTryFrom for Scheme { + type Error = InvalidUriBytes; + #[inline] + fn try_from(bytes: Bytes) -> Result { + Scheme::from_shared(bytes) + } +} + +impl<'a> HttpTryFrom<&'a [u8]> for Scheme { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a [u8]) -> Result { + use self::Scheme2::*; + + match Scheme2::parse_exact(s)? { + None => Err(ErrorKind::InvalidScheme.into()), + Standard(p) => Ok(Standard(p).into()), + Other(_) => { + // Unsafe: parse_exact already checks for a strict subset of UTF-8 + Ok(Other(Box::new(unsafe { + ByteStr::from_utf8_unchecked(s.into()) + })).into()) + } + } + } +} + +impl<'a> HttpTryFrom<&'a str> for Scheme { + type Error = InvalidUri; + #[inline] + fn try_from(s: &'a str) -> Result { + HttpTryFrom::try_from(s.as_bytes()) + } +} + +impl FromStr for Scheme { + type Err = InvalidUri; + + fn from_str(s: &str) -> Result { + HttpTryFrom::try_from(s) + } +} + +impl From for Bytes { + #[inline] + fn from(src: Scheme) -> Self { + use self::Scheme2::*; + use self::Protocol::*; + + match src.inner { + None => Bytes::new(), + Standard(Http) => Bytes::from_static(b"http"), + Standard(Https) => Bytes::from_static(b"https"), + Other(v) => (*v).into(), + } + } +} + +impl fmt::Debug for Scheme { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_str(), f) + } +} + +impl fmt::Display for Scheme { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl AsRef for Scheme { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl PartialEq for Scheme { + fn eq(&self, other: &Scheme) -> bool { + use self::Protocol::*; + use self::Scheme2::*; + + match (&self.inner, &other.inner) { + (&Standard(Http), &Standard(Http)) => true, + (&Standard(Https), &Standard(Https)) => true, + (&Other(ref a), &Other(ref b)) => a.eq_ignore_ascii_case(b), + (&None, _) | (_, &None) => unreachable!(), + _ => false, + } + } +} + +impl Eq for Scheme {} + +/// Case-insensitive equality +/// +/// # Examples +/// +/// ``` +/// # use http::uri::Scheme; +/// let scheme: Scheme = "HTTP".parse().unwrap(); +/// assert_eq!(scheme, *"http"); +/// ``` +impl PartialEq for Scheme { + fn eq(&self, other: &str) -> bool { + self.as_str().eq_ignore_ascii_case(other) + } +} + +/// Case-insensitive equality +impl PartialEq for str { + fn eq(&self, other: &Scheme) -> bool { + other == self + } +} + +/// Case-insensitive hashing +impl Hash for Scheme { + fn hash(&self, state: &mut H) where H: Hasher { + match self.inner { + Scheme2::None => (), + Scheme2::Standard(Protocol::Http) => state.write_u8(1), + Scheme2::Standard(Protocol::Https) => state.write_u8(2), + Scheme2::Other(ref other) => { + other.len().hash(state); + for &b in other.as_bytes() { + state.write_u8(b.to_ascii_lowercase()); + } + } + } + } +} + +impl Scheme2 { + pub(super) fn is_none(&self) -> bool { + match *self { + Scheme2::None => true, + _ => false, + } + } +} + +// Require the scheme to not be too long in order to enable further +// optimizations later. +const MAX_SCHEME_LEN: usize = 64; + +// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +// +const SCHEME_CHARS: [u8; 256] = [ + // 0 1 2 3 4 5 6 7 8 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x + 0, 0, 0, b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x + b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', 0, // 5x + 0, 0, 0, 0, 0, b'A', b'B', b'C', b'D', b'E', // 6x + b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x + b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x + b'Z', 0, 0, 0, 0, 0, 0, b'a', b'b', b'c', // 9x + b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x + b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x + b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x + 0, 0, 0, 0, 0, 0 // 25x +]; + +impl Scheme2 { + fn parse_exact(s: &[u8]) -> Result, InvalidUri> { + match s { + b"http" => Ok(Protocol::Http.into()), + b"https" => Ok(Protocol::Https.into()), + _ => { + if s.len() > MAX_SCHEME_LEN { + return Err(ErrorKind::SchemeTooLong.into()); + } + + for &b in s { + match SCHEME_CHARS[b as usize] { + b':' => { + // Don't want :// here + return Err(ErrorKind::InvalidScheme.into()); + } + 0 => { + return Err(ErrorKind::InvalidScheme.into()); + } + _ => {} + } + } + + Ok(Scheme2::Other(())) + } + } + } + + pub(super) fn parse(s: &[u8]) -> Result, InvalidUri> { + if s.len() >= 7 { + // Check for HTTP + if s[..7].eq_ignore_ascii_case(b"http://") { + // Prefix will be striped + return Ok(Protocol::Http.into()); + } + } + + if s.len() >= 8 { + // Check for HTTPs + if s[..8].eq_ignore_ascii_case(b"https://") { + return Ok(Protocol::Https.into()); + } + } + + if s.len() > 3 { + for i in 0..s.len() { + let b = s[i]; + + if i == MAX_SCHEME_LEN { + return Err(ErrorKind::SchemeTooLong.into()); + } + + match SCHEME_CHARS[b as usize] { + b':' => { + // Not enough data remaining + if s.len() < i + 3 { + break; + } + + // Not a scheme + if &s[i+1..i+3] != b"//" { + break; + } + + // Return scheme + return Ok(Scheme2::Other(i)); + } + // Invald scheme character, abort + 0 => break, + _ => {} + } + } + } + + Ok(Scheme2::None) + } +} + +impl Protocol { + pub(super) fn len(&self) -> usize { + match *self { + Protocol::Http => 4, + Protocol::Https => 5, + } + } +} + +impl From for Scheme2 { + fn from(src: Protocol) -> Self { + Scheme2::Standard(src) + } +} + +#[doc(hidden)] +impl From for Scheme { + fn from(src: Scheme2) -> Self { + Scheme { inner: src } + } +} diff --git a/http/src/uri/tests.rs b/http/src/uri/tests.rs new file mode 100644 index 000000000..71f935153 --- /dev/null +++ b/http/src/uri/tests.rs @@ -0,0 +1,484 @@ +use std::str::FromStr; + +use super::{ErrorKind, InvalidUri, Uri, URI_CHARS, Port}; + +#[test] +fn test_char_table() { + for (i, &v) in URI_CHARS.iter().enumerate() { + if v != 0 { + assert_eq!(i, v as usize); + } + } +} + +macro_rules! part { + ($s:expr) => ( + Some(&$s.parse().unwrap()) + ) +} + +macro_rules! test_parse { + ( + $test_name:ident, + $str:expr, + $alt:expr, + $($method:ident = $value:expr,)* + ) => ( + #[test] + fn $test_name() { + let orig_str = $str; + let uri = match Uri::from_str(orig_str) { + Ok(uri) => uri, + Err(err) => { + panic!("parse error {:?} from {:?}", err, orig_str); + }, + }; + $( + assert_eq!(uri.$method(), $value, "{}: uri = {:?}", stringify!($method), uri); + )+ + assert_eq!(uri, orig_str, "partial eq to original str"); + assert_eq!(uri, uri.clone(), "clones are equal"); + + let new_str = uri.to_string(); + let new_uri = Uri::from_str(&new_str).expect("to_string output parses again as a Uri"); + assert_eq!(new_uri, orig_str, "round trip still equals original str"); + + const ALT: &'static [&'static str] = &$alt; + + for &alt in ALT.iter() { + let other: Uri = alt.parse().unwrap(); + assert_eq!(uri, *alt); + assert_eq!(uri, other); + } + } + ); +} + +test_parse! { + test_uri_parse_path_and_query, + "/some/path/here?and=then&hello#and-bye", + [], + + scheme_part = None, + authority_part = None, + path = "/some/path/here", + query = Some("and=then&hello"), + host = None, +} + +test_parse! { + test_uri_parse_absolute_form, + "http://127.0.0.1:61761/chunks", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1:61761"), + path = "/chunks", + query = None, + host = Some("127.0.0.1"), + port_part = Port::from_str("61761").ok(), +} + +test_parse! { + test_uri_parse_absolute_form_without_path, + "https://127.0.0.1:61761", + ["https://127.0.0.1:61761/"], + + scheme_part = part!("https"), + authority_part = part!("127.0.0.1:61761"), + path = "/", + query = None, + host = Some("127.0.0.1"), + port_part = Port::from_str("61761").ok(), +} + +test_parse! { + test_uri_parse_asterisk_form, + "*", + [], + + scheme_part = None, + authority_part = None, + path = "*", + query = None, + host = None, +} + +test_parse! { + test_uri_parse_authority_no_port, + "localhost", + ["LOCALHOST", "LocaLHOSt"], + + scheme_part = None, + authority_part = part!("localhost"), + path = "", + query = None, + port_part = None, + host = Some("localhost"), +} + +test_parse! { + test_uri_authority_only_one_character_issue_197, + "S", + [], + + scheme_part = None, + authority_part = part!("S"), + path = "", + query = None, + port_part = None, + host = Some("S"), +} + +test_parse! { + test_uri_parse_authority_form, + "localhost:3000", + ["localhosT:3000"], + + scheme_part = None, + authority_part = part!("localhost:3000"), + path = "", + query = None, + host = Some("localhost"), + port_part = Port::from_str("3000").ok(), +} + + +test_parse! { + test_uri_parse_absolute_with_default_port_http, + "http://127.0.0.1:80", + ["http://127.0.0.1:80/"], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1:80"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = Port::from_str("80").ok(), +} + +test_parse! { + test_uri_parse_absolute_with_default_port_https, + "https://127.0.0.1:443", + ["https://127.0.0.1:443/"], + + scheme_part = part!("https"), + authority_part = part!("127.0.0.1:443"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = Port::from_str("443").ok(), +} + +test_parse! { + test_uri_parse_fragment_questionmark, + "http://127.0.0.1/#?", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_uri_parse_path_with_terminating_questionmark, + "http://127.0.0.1/path?", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1"), + path = "/path", + query = Some(""), + port_part = None, +} + +test_parse! { + test_uri_parse_absolute_form_with_empty_path_and_nonempty_query, + "http://127.0.0.1?foo=bar", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1"), + path = "/", + query = Some("foo=bar"), + port_part = None, +} + +test_parse! { + test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash, + "http://127.0.0.1#foo/bar", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark, + "http://127.0.0.1#foo?bar", + [], + + scheme_part = part!("http"), + authority_part = part!("127.0.0.1"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_userinfo1, + "http://a:b@127.0.0.1:1234/", + [], + + scheme_part = part!("http"), + authority_part = part!("a:b@127.0.0.1:1234"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = Port::from_str("1234").ok(), +} + +test_parse! { + test_userinfo2, + "http://a:b@127.0.0.1/", + [], + + scheme_part = part!("http"), + authority_part = part!("a:b@127.0.0.1"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_userinfo3, + "http://a@127.0.0.1/", + [], + + scheme_part = part!("http"), + authority_part = part!("a@127.0.0.1"), + host = Some("127.0.0.1"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_userinfo_with_port, + "user@localhost:3000", + [], + + scheme_part = None, + authority_part = part!("user@localhost:3000"), + path = "", + query = None, + host = Some("localhost"), + port_part = Port::from_str("3000").ok(), +} + +test_parse! { + test_userinfo_pass_with_port, + "user:pass@localhost:3000", + [], + + scheme_part = None, + authority_part = part!("user:pass@localhost:3000"), + path = "", + query = None, + host = Some("localhost"), + port_part = Port::from_str("3000").ok(), +} + +test_parse! { + test_ipv6, + "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/", + [], + + scheme_part = part!("http"), + authority_part = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"), + host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_ipv6_shorthand, + "http://[::1]/", + [], + + scheme_part = part!("http"), + authority_part = part!("[::1]"), + host = Some("[::1]"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_ipv6_shorthand2, + "http://[::]/", + [], + + scheme_part = part!("http"), + authority_part = part!("[::]"), + host = Some("[::]"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_ipv6_shorthand3, + "http://[2001:db8::2:1]/", + [], + + scheme_part = part!("http"), + authority_part = part!("[2001:db8::2:1]"), + host = Some("[2001:db8::2:1]"), + path = "/", + query = None, + port_part = None, +} + +test_parse! { + test_ipv6_with_port, + "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008/", + [], + + scheme_part = part!("http"), + authority_part = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"), + host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"), + path = "/", + query = None, + port_part = Port::from_str("8008").ok(), +} + +test_parse! { + test_percentage_encoded_path, + "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478", + [], + + scheme_part = None, + authority_part = None, + host = None, + path = "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478", + query = None, + port_part = None, +} + +test_parse! { + test_path_permissive, + "/foo=bar|baz\\^~%", + [], + + path = "/foo=bar|baz\\^~%", +} + +test_parse! { + test_query_permissive, + "/?foo={bar|baz}\\^`", + [], + + query = Some("foo={bar|baz}\\^`"), +} + +#[test] +fn test_uri_parse_error() { + fn err(s: &str) { + Uri::from_str(s).unwrap_err(); + } + + err("http://"); + err("htt:p//host"); + err("hyper.rs/"); + err("hyper.rs?key=val"); + err("?key=val"); + err("localhost/"); + err("localhost?key=val"); + err("\0"); + err("http://[::1"); + err("http://::1]"); + err("localhost:8080:3030"); + err("@"); + err("http://username:password@/wut"); + + // illegal queries + err("/?foo\rbar"); + err("/?foo\nbar"); + err("/?<"); + err("/?>"); +} + +#[test] +fn test_max_uri_len() { + let mut uri = vec![]; + uri.extend(b"http://localhost/"); + uri.extend(vec![b'a'; 70 * 1024]); + + let uri = String::from_utf8(uri).unwrap(); + let res: Result = uri.parse(); + + assert_eq!(res.unwrap_err().0, ErrorKind::TooLong); +} + +#[test] +fn test_long_scheme() { + let mut uri = vec![]; + uri.extend(vec![b'a'; 256]); + uri.extend(b"://localhost/"); + + let uri = String::from_utf8(uri).unwrap(); + let res: Result = uri.parse(); + + assert_eq!(res.unwrap_err().0, ErrorKind::SchemeTooLong); +} + +#[test] +fn test_uri_to_path_and_query() { + let cases = vec![ + ("/", "/"), + ("/foo?bar", "/foo?bar"), + ("/foo?bar#nope", "/foo?bar"), + ("http://hyper.rs", "/"), + ("http://hyper.rs/", "/"), + ("http://hyper.rs/path", "/path"), + ("http://hyper.rs?query", "/?query"), + ("*", "*"), + ]; + + for case in cases { + let uri = Uri::from_str(case.0).unwrap(); + let s = uri.path_and_query().unwrap().to_string(); + + assert_eq!(s, case.1); + } +} + +#[test] +fn test_authority_uri_parts_round_trip() { + let s = "hyper.rs"; + let uri = Uri::from_str(s).expect("first parse"); + assert_eq!(uri, s); + assert_eq!(uri.to_string(), s); + + let parts = uri.into_parts(); + let uri2 = Uri::from_parts(parts).expect("from_parts"); + assert_eq!(uri2, s); + assert_eq!(uri2.to_string(), s); +} + +#[test] +fn test_partial_eq_path_with_terminating_questionmark() { + let a = "/path"; + let uri = Uri::from_str("/path?").expect("first parse"); + + assert_eq!(uri, a); +} diff --git a/http/src/version.rs b/http/src/version.rs new file mode 100644 index 000000000..3229dc326 --- /dev/null +++ b/http/src/version.rs @@ -0,0 +1,68 @@ +//! HTTP version +//! +//! This module contains a definition of the `Version` type. The `Version` +//! type is intended to be accessed through the root of the crate +//! (`http::Version`) rather than this module. +//! +//! The `Version` type contains constants that represent the various versions +//! of the HTTP protocol. +//! +//! # Examples +//! +//! ``` +//! use http::Version; +//! +//! let http11 = Version::HTTP_11; +//! let http2 = Version::HTTP_2; +//! assert!(http11 != http2); +//! +//! println!("{:?}", http2); +//! ``` + +use std::fmt; + +/// Represents a version of the HTTP spec. +#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)] +pub struct Version(Http); + +impl Version { + /// `HTTP/0.9` + pub const HTTP_09: Version = Version(Http::Http09); + + /// `HTTP/1.0` + pub const HTTP_10: Version = Version(Http::Http10); + + /// `HTTP/1.1` + pub const HTTP_11: Version = Version(Http::Http11); + + /// `HTTP/2.0` + pub const HTTP_2: Version = Version(Http::H2); +} + +#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)] +enum Http { + Http09, + Http10, + Http11, + H2, +} + +impl Default for Version { + #[inline] + fn default() -> Version { + Version::HTTP_11 + } +} + +impl fmt::Debug for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Http::*; + + f.write_str(match self.0 { + Http09 => "HTTP/0.9", + Http10 => "HTTP/1.0", + Http11 => "HTTP/1.1", + H2 => "HTTP/2.0", + }) + } +} diff --git a/http/tests/header_map.rs b/http/tests/header_map.rs new file mode 100644 index 000000000..70ee72f2a --- /dev/null +++ b/http/tests/header_map.rs @@ -0,0 +1,329 @@ +extern crate http; + +use http::*; +use http::header::*; + +#[test] +fn smoke() { + let mut headers = HeaderMap::new(); + + assert!(headers.get("hello").is_none()); + + let name: HeaderName = "hello".parse().unwrap(); + + match headers.entry(&name).unwrap() { + Entry::Vacant(e) => { + e.insert("world".parse().unwrap()); + } + _ => panic!(), + } + + assert!(headers.get("hello").is_some()); + + match headers.entry(&name).unwrap() { + Entry::Occupied(mut e) => { + assert_eq!(e.get(), &"world"); + + // Push another value + e.append("zomg".parse().unwrap()); + + let mut i = e.iter(); + + assert_eq!(*i.next().unwrap(), "world"); + assert_eq!(*i.next().unwrap(), "zomg"); + assert!(i.next().is_none()); + } + _ => panic!(), + } +} + +#[test] +fn drain() { + let mut headers = HeaderMap::new(); + + // Insert a single value + let name: HeaderName = "hello".parse().unwrap(); + headers.insert(name, "world".parse().unwrap()); + + { + let mut iter = headers.drain(); + let (name, values) = iter.next().unwrap(); + assert_eq!(name.as_str(), "hello"); + + let values: Vec<_> = values.collect(); + assert_eq!(values.len(), 1); + assert_eq!(values[0], "world"); + + assert!(iter.next().is_none()); + } + + assert!(headers.is_empty()); + + // Insert two sequential values + headers.insert("hello".parse::().unwrap(), "world".parse().unwrap()); + headers.insert("zomg".parse::().unwrap(), "bar".parse().unwrap()); + headers.append("hello".parse::().unwrap(), "world2".parse().unwrap()); + + // Drain... + { + let mut iter = headers.drain(); + let (name, values) = iter.next().unwrap(); + assert_eq!(name.as_str(), "hello"); + + let values: Vec<_> = values.collect(); + assert_eq!(values.len(), 2); + assert_eq!(values[0], "world"); + assert_eq!(values[1], "world2"); + + let (name, values) = iter.next().unwrap(); + assert_eq!(name.as_str(), "zomg"); + + let values: Vec<_> = values.collect(); + assert_eq!(values.len(), 1); + assert_eq!(values[0], "bar"); + + assert!(iter.next().is_none()); + } +} + +#[test] +fn drain_entry() { + let mut headers = HeaderMap::new(); + + headers.insert("hello".parse::().unwrap(), "world".parse().unwrap()); + headers.insert("zomg".parse::().unwrap(), "foo".parse().unwrap()); + headers.append("hello".parse::().unwrap(), "world2".parse().unwrap()); + headers.insert("more".parse::().unwrap(), "words".parse().unwrap()); + headers.append("more".parse::().unwrap(), "insertions".parse().unwrap()); + + // Using insert + { + let mut e = match headers.entry("hello").unwrap() { + Entry::Occupied(e) => e, + _ => panic!(), + }; + + let vals: Vec<_> = e.insert_mult("wat".parse().unwrap()).collect(); + assert_eq!(2, vals.len()); + assert_eq!(vals[0], "world"); + assert_eq!(vals[1], "world2"); + } +} + +#[test] +fn eq() { + let mut a = HeaderMap::new(); + let mut b = HeaderMap::new(); + + assert_eq!(a, b); + + a.insert("hello".parse::().unwrap(), "world".parse().unwrap()); + assert_ne!(a, b); + + b.insert("hello".parse::().unwrap(), "world".parse().unwrap()); + assert_eq!(a, b); + + a.insert("foo".parse::().unwrap(), "bar".parse().unwrap()); + a.append("foo".parse::().unwrap(), "baz".parse().unwrap()); + assert_ne!(a, b); + + b.insert("foo".parse::().unwrap(), "bar".parse().unwrap()); + assert_ne!(a, b); + + b.append("foo".parse::().unwrap(), "baz".parse().unwrap()); + assert_eq!(a, b); + + a.append("a".parse::().unwrap(), "a".parse().unwrap()); + a.append("a".parse::().unwrap(), "b".parse().unwrap()); + b.append("a".parse::().unwrap(), "b".parse().unwrap()); + b.append("a".parse::().unwrap(), "a".parse().unwrap()); + + assert_ne!(a, b); +} + +#[test] +fn into_header_name() { + let mut m = HeaderMap::new(); + m.insert(HOST, "localhost".parse().unwrap()); + m.insert(&ACCEPT, "*/*".parse().unwrap()); + m.insert("connection", "keep-alive".parse().unwrap()); + + m.append(LOCATION, "/".parse().unwrap()); + m.append(&VIA, "bob".parse().unwrap()); + m.append("transfer-encoding", "chunked".parse().unwrap()); + + assert_eq!(m.len(), 6); +} + +#[test] +fn as_header_name() { + let mut m = HeaderMap::new(); + let v: HeaderValue = "localhost".parse().unwrap(); + m.insert(HOST, v.clone()); + + let expected = Some(&v); + + assert_eq!(m.get("host"), expected); + assert_eq!(m.get(&HOST), expected); + + let s = String::from("host"); + assert_eq!(m.get(&s), expected); + assert_eq!(m.get(s.as_str()), expected); +} + +#[test] +fn insert_all_std_headers() { + let mut m = HeaderMap::new(); + + for (i, hdr) in STD.iter().enumerate() { + m.insert(hdr.clone(), hdr.as_str().parse().unwrap()); + + for j in 0..(i+1) { + assert_eq!(m[&STD[j]], STD[j].as_str()); + } + + if i != 0 { + for j in (i+1)..STD.len() { + assert!(m.get(&STD[j]).is_none(), "contained {}; j={}", STD[j].as_str(), j); + } + } + } +} + +#[test] +fn insert_79_custom_std_headers() { + let mut h = HeaderMap::new(); + let hdrs = custom_std(79); + + for (i, hdr) in hdrs.iter().enumerate() { + h.insert(hdr.clone(), hdr.as_str().parse().unwrap()); + + for j in 0..(i+1) { + assert_eq!(h[&hdrs[j]], hdrs[j].as_str()); + } + + for j in (i+1)..hdrs.len() { + assert!(h.get(&hdrs[j]).is_none()); + } + } +} + +#[test] +fn append_multiple_values() { + let mut map = HeaderMap::new(); + + map.append(header::CONTENT_TYPE, "json".parse().unwrap()); + map.append(header::CONTENT_TYPE, "html".parse().unwrap()); + map.append(header::CONTENT_TYPE, "xml".parse().unwrap()); + + let vals = map.get_all(&header::CONTENT_TYPE) + .iter() + .collect::>(); + + assert_eq!(&vals, &[&"json", &"html", &"xml"]); +} + +fn custom_std(n: usize) -> Vec { + (0..n).map(|i| { + let s = format!("{}-{}", STD[i % STD.len()].as_str(), i); + s.parse().unwrap() + }).collect() +} + +const STD: &'static [HeaderName] = &[ + ACCEPT, + ACCEPT_CHARSET, + ACCEPT_ENCODING, + ACCEPT_LANGUAGE, + ACCEPT_RANGES, + ACCESS_CONTROL_ALLOW_CREDENTIALS, + ACCESS_CONTROL_ALLOW_HEADERS, + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_ORIGIN, + ACCESS_CONTROL_EXPOSE_HEADERS, + ACCESS_CONTROL_MAX_AGE, + ACCESS_CONTROL_REQUEST_HEADERS, + ACCESS_CONTROL_REQUEST_METHOD, + AGE, + ALLOW, + ALT_SVC, + AUTHORIZATION, + CACHE_CONTROL, + CONNECTION, + CONTENT_DISPOSITION, + CONTENT_ENCODING, + CONTENT_LANGUAGE, + CONTENT_LENGTH, + CONTENT_LOCATION, + CONTENT_RANGE, + CONTENT_SECURITY_POLICY, + CONTENT_SECURITY_POLICY_REPORT_ONLY, + CONTENT_TYPE, + COOKIE, + DNT, + DATE, + ETAG, + EXPECT, + EXPIRES, + FORWARDED, + FROM, + HOST, + IF_MATCH, + IF_MODIFIED_SINCE, + IF_NONE_MATCH, + IF_RANGE, + IF_UNMODIFIED_SINCE, + LAST_MODIFIED, + LINK, + LOCATION, + MAX_FORWARDS, + ORIGIN, + PRAGMA, + PROXY_AUTHENTICATE, + PROXY_AUTHORIZATION, + PUBLIC_KEY_PINS, + PUBLIC_KEY_PINS_REPORT_ONLY, + RANGE, + REFERER, + REFERRER_POLICY, + RETRY_AFTER, + SERVER, + SET_COOKIE, + STRICT_TRANSPORT_SECURITY, + TE, + TRAILER, + TRANSFER_ENCODING, + USER_AGENT, + UPGRADE, + UPGRADE_INSECURE_REQUESTS, + VARY, + VIA, + WARNING, + WWW_AUTHENTICATE, + X_CONTENT_TYPE_OPTIONS, + X_DNS_PREFETCH_CONTROL, + X_FRAME_OPTIONS, + X_XSS_PROTECTION, +]; + +#[test] +fn get_invalid() { + let mut headers = HeaderMap::new(); + headers.insert("foo", "bar".parse().unwrap()); + assert!(headers.get("Evil\r\nKey").is_none()); +} + +#[test] +#[should_panic] +fn insert_invalid() { + let mut headers = HeaderMap::new(); + headers.insert("evil\r\nfoo", "bar".parse().unwrap()); +} + +#[test] +fn value_htab() { + // RFC 7230 Section 3.2: + // > field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + HeaderValue::from_static("hello\tworld"); + HeaderValue::from_str("hello\tworld").unwrap(); +} diff --git a/http/tests/header_map_fuzz.rs b/http/tests/header_map_fuzz.rs new file mode 100644 index 000000000..b3b658812 --- /dev/null +++ b/http/tests/header_map_fuzz.rs @@ -0,0 +1,365 @@ +extern crate http; +extern crate rand; +extern crate quickcheck; + +use http::*; +use http::header::*; + +use quickcheck::{Arbitrary, Gen, QuickCheck, TestResult}; +use rand::{StdRng, SeedableRng, Rng}; + +use std::collections::HashMap; + +#[test] +fn header_map_fuzz() { + fn prop(fuzz: Fuzz) -> TestResult { + fuzz.run(); + TestResult::from_bool(true) + } + + QuickCheck::new() + .quickcheck(prop as fn(Fuzz) -> TestResult) +} + +#[derive(Debug, Clone)] +struct Fuzz { + // The magic seed that makes the test case reproducible + seed: [usize; 4], + + // Actions to perform + steps: Vec, + + // Number of steps to drop + reduce: usize, +} + +#[derive(Debug)] +struct Weight { + insert: usize, + remove: usize, + append: usize, +} + +#[derive(Debug, Clone)] +struct Step { + action: Action, + expect: AltMap, +} + +#[derive(Debug, Clone)] +enum Action { + Insert { + name: HeaderName, // Name to insert + val: HeaderValue, // Value to insert + old: Option, // Old value + }, + Append { + name: HeaderName, + val: HeaderValue, + ret: bool, + }, + Remove { + name: HeaderName, // Name to remove + val: Option, // Value to get + }, +} + +// An alternate implementation of HeaderMap backed by HashMap +#[derive(Debug, Clone, Default)] +struct AltMap { + map: HashMap>, +} + +impl Fuzz { + fn new(seed: [usize; 4]) -> Fuzz { + // Seed the RNG + let mut rng = StdRng::from_seed(&seed); + + let mut steps = vec![]; + let mut expect = AltMap::default(); + let num = rng.gen_range(5, 500); + + let weight = Weight { + insert: rng.gen_range(1, 10), + remove: rng.gen_range(1, 10), + append: rng.gen_range(1, 10), + }; + + while steps.len() < num { + steps.push(expect.gen_step(&weight, &mut rng)); + } + + Fuzz { + seed: seed, + steps: steps, + reduce: 0, + } + } + + fn run(self) { + // Create a new header map + let mut map = HeaderMap::new(); + + // Number of steps to perform + let take = self.steps.len() - self.reduce; + + for step in self.steps.into_iter().take(take) { + step.action.apply(&mut map); + + step.expect.assert_identical(&map); + } + } +} + +impl Arbitrary for Fuzz { + fn arbitrary(g: &mut G) -> Self { + Fuzz::new(quickcheck::Rng::gen(g)) + } +} + +impl AltMap { + fn gen_step(&mut self, weight: &Weight, rng: &mut StdRng) -> Step { + let action = self.gen_action(weight, rng); + + Step { + action: action, + expect: self.clone(), + } + } + + /// This will also apply the action against `self` + fn gen_action(&mut self, weight: &Weight, rng: &mut StdRng) -> Action { + let sum = weight.insert + + weight.remove + + weight.append; + + let mut num = rng.gen_range(0, sum); + + if num < weight.insert { + return self.gen_insert(rng); + } + + num -= weight.insert; + + if num < weight.remove { + return self.gen_remove(rng); + } + + num -= weight.remove; + + if num < weight.append { + return self.gen_append(rng); + } + + unreachable!(); + } + + fn gen_insert(&mut self, rng: &mut StdRng) -> Action { + let name = self.gen_name(4, rng); + let val = gen_header_value(rng); + let old = self.insert(name.clone(), val.clone()); + + Action::Insert { + name: name, + val: val, + old: old, + } + } + + fn gen_remove(&mut self, rng: &mut StdRng) -> Action { + let name = self.gen_name(-4, rng); + let val = self.remove(&name); + + Action::Remove { + name: name, + val: val, + } + } + + fn gen_append(&mut self, rng: &mut StdRng) -> Action { + let name = self.gen_name(-5, rng); + let val = gen_header_value(rng); + + let vals = self.map.entry(name.clone()) + .or_insert(vec![]); + + let ret = !vals.is_empty(); + vals.push(val.clone()); + + Action::Append { + name: name, + val: val, + ret: ret, + } + } + + /// Negative numbers weigh finding an existing header higher + fn gen_name(&self, weight: i32, rng: &mut StdRng) -> HeaderName { + let mut existing = rng.gen_weighted_bool(weight.abs() as u32); + + if weight < 0 { + existing = !existing; + } + + if existing { + // Existing header + if let Some(name) = self.find_random_name(rng) { + name + } else { + gen_header_name(rng) + } + } else { + gen_header_name(rng) + } + } + + fn find_random_name(&self, rng: &mut StdRng) -> Option { + if self.map.is_empty() { + None + } else { + let n = rng.gen_range(0, self.map.len()); + self.map.keys().nth(n).map(Clone::clone) + } + } + + fn insert(&mut self, name: HeaderName, val: HeaderValue) -> Option { + let old = self.map.insert(name, vec![val]); + old.and_then(|v| v.into_iter().next()) + } + + fn remove(&mut self, name: &HeaderName) -> Option { + self.map.remove(name).and_then(|v| v.into_iter().next()) + } + + fn assert_identical(&self, other: &HeaderMap) { + assert_eq!(self.map.len(), other.keys_len()); + + for (key, val) in &self.map { + // Test get + assert_eq!(other.get(key), val.get(0)); + + // Test get_all + let vals = other.get_all(key); + let actual: Vec<_> = vals.iter().collect(); + assert_eq!(&actual[..], &val[..]); + } + } +} + +impl Action { + fn apply(self, map: &mut HeaderMap) { + match self { + Action::Insert { name, val, old } => { + let actual = map.insert(name, val); + assert_eq!(actual, old); + } + Action::Remove { name, val } => { + // Just to help track the state, load all associated values. + map.get_all(&name).iter().collect::>(); + + let actual = map.remove(&name); + assert_eq!(actual, val); + } + Action::Append { name, val, ret } => { + assert_eq!(ret, map.append(name, val)); + } + } + } +} + +fn gen_header_name(g: &mut StdRng) -> HeaderName { + if g.gen_weighted_bool(2) { + g.choose(&[ + header::ACCEPT, + header::ACCEPT_CHARSET, + header::ACCEPT_ENCODING, + header::ACCEPT_LANGUAGE, + header::ACCEPT_RANGES, + header::ACCESS_CONTROL_ALLOW_CREDENTIALS, + header::ACCESS_CONTROL_ALLOW_HEADERS, + header::ACCESS_CONTROL_ALLOW_METHODS, + header::ACCESS_CONTROL_ALLOW_ORIGIN, + header::ACCESS_CONTROL_EXPOSE_HEADERS, + header::ACCESS_CONTROL_MAX_AGE, + header::ACCESS_CONTROL_REQUEST_HEADERS, + header::ACCESS_CONTROL_REQUEST_METHOD, + header::AGE, + header::ALLOW, + header::ALT_SVC, + header::AUTHORIZATION, + header::CACHE_CONTROL, + header::CONNECTION, + header::CONTENT_DISPOSITION, + header::CONTENT_ENCODING, + header::CONTENT_LANGUAGE, + header::CONTENT_LENGTH, + header::CONTENT_LOCATION, + header::CONTENT_RANGE, + header::CONTENT_SECURITY_POLICY, + header::CONTENT_SECURITY_POLICY_REPORT_ONLY, + header::CONTENT_TYPE, + header::COOKIE, + header::DNT, + header::DATE, + header::ETAG, + header::EXPECT, + header::EXPIRES, + header::FORWARDED, + header::FROM, + header::HOST, + header::IF_MATCH, + header::IF_MODIFIED_SINCE, + header::IF_NONE_MATCH, + header::IF_RANGE, + header::IF_UNMODIFIED_SINCE, + header::LAST_MODIFIED, + header::LINK, + header::LOCATION, + header::MAX_FORWARDS, + header::ORIGIN, + header::PRAGMA, + header::PROXY_AUTHENTICATE, + header::PROXY_AUTHORIZATION, + header::PUBLIC_KEY_PINS, + header::PUBLIC_KEY_PINS_REPORT_ONLY, + header::RANGE, + header::REFERER, + header::REFERRER_POLICY, + header::RETRY_AFTER, + header::SERVER, + header::SET_COOKIE, + header::STRICT_TRANSPORT_SECURITY, + header::TE, + header::TRAILER, + header::TRANSFER_ENCODING, + header::USER_AGENT, + header::UPGRADE, + header::UPGRADE_INSECURE_REQUESTS, + header::VARY, + header::VIA, + header::WARNING, + header::WWW_AUTHENTICATE, + header::X_CONTENT_TYPE_OPTIONS, + header::X_DNS_PREFETCH_CONTROL, + header::X_FRAME_OPTIONS, + header::X_XSS_PROTECTION, + ]).unwrap().clone() + } else { + let value = gen_string(g, 1, 25); + HeaderName::from_bytes(value.as_bytes()).unwrap() + } +} + +fn gen_header_value(g: &mut StdRng) -> HeaderValue { + let value = gen_string(g, 0, 70); + HeaderValue::from_bytes(value.as_bytes()).unwrap() +} + +fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String { + let bytes: Vec<_> = (min..max).map(|_| { + // Chars to pick from + g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----").unwrap().clone() + }).collect(); + + String::from_utf8(bytes).unwrap() +} diff --git a/http/tests/status_code.rs b/http/tests/status_code.rs new file mode 100644 index 000000000..72ba810ca --- /dev/null +++ b/http/tests/status_code.rs @@ -0,0 +1,67 @@ +extern crate http; + +use http::*; + +#[test] +fn from_bytes() { + for ok in &["100", "101", "199", "200", "250", "299", "321", "399", "499", "599"] { + assert!(StatusCode::from_bytes(ok.as_bytes()).is_ok()); + } + + for not_ok in &["0", "00", "10", "40", "99", "000", "010", "099", "600", "610", "999"] { + assert!(StatusCode::from_bytes(not_ok.as_bytes()).is_err()); + } +} + +#[test] +fn equates_with_u16() { + let status = StatusCode::from_u16(200u16).unwrap(); + assert_eq!(200u16, status); + assert_eq!(status, 200u16); +} + +macro_rules! test_round_trip { + ($($num:expr,)+) => { + #[test] + fn roundtrip() { + $( + let status = StatusCode::from_bytes(stringify!($num).as_bytes()).unwrap(); + let expect = $num; + + assert_eq!(u16::from(status), expect); + )+ + } + } +} + +test_round_trip!( + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + + 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + + 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, + 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, + 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, + 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, + 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, + 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, + ); diff --git a/humantime/.cargo-checksum.json b/humantime/.cargo-checksum.json new file mode 100644 index 000000000..b1d184586 --- /dev/null +++ b/humantime/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"} \ No newline at end of file diff --git a/humantime/Cargo.toml b/humantime/Cargo.toml new file mode 100644 index 000000000..1ed79d78a --- /dev/null +++ b/humantime/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "humantime" +version = "1.2.0" +authors = ["Paul Colomiets "] +description = " A parser and formatter for std::time::{Duration, SystemTime}\n" +homepage = "https://github.com/tailhook/humantime" +documentation = "https://docs.rs/humantime" +readme = "README.md" +keywords = ["time", "human", "human-friendly", "parser", "duration"] +categories = ["date-and-time"] +license = "MIT/Apache-2.0" + +[lib] +name = "humantime" +path = "src/lib.rs" +[dependencies.quick-error] +version = "1.0.0" +[dev-dependencies.chrono] +version = "0.4.0" + +[dev-dependencies.rand] +version = "0.4.2" + +[dev-dependencies.time] +version = "0.1.39" diff --git a/humantime/LICENSE-APACHE b/humantime/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/humantime/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/humantime/LICENSE-MIT b/humantime/LICENSE-MIT new file mode 100644 index 000000000..a099fbade --- /dev/null +++ b/humantime/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2016 The humantime Developers + +Includes parts of http date with the following copyright: +Copyright (c) 2016 Pyfisch + +Includes portions of musl libc with the following copyright: +Copyright © 2005-2013 Rich Felker + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/humantime/README.md b/humantime/README.md new file mode 100644 index 000000000..703fc4c54 --- /dev/null +++ b/humantime/README.md @@ -0,0 +1,67 @@ +Human Time +========== + +**Status: stable** + +[Documentation](https://docs.rs/humantime) | +[Github](https://github.com/tailhook/humantime) | +[Crate](https://crates.io/crates/humantime) + + +Features: + +* Parses durations in free form like `15days 2min 2s` +* Formats durations in similar form `2years 2min 12us` +* Parses and formats timestamp in `rfc3339` format: `2018-01-01T12:53:00Z` +* Parses timestamps in a weaker format: `2018-01-01 12:53:00` + +Timestamp parsing/formatting is super-fast because format is basically +fixed. + +Here are some micro-benchmarks: + +``` +test result: ok. 0 passed; 0 failed; 26 ignored; 0 measured; 0 filtered out + + Running target/release/deps/datetime_format-8facb4ac832d9770 + +running 2 tests +test rfc3339_chrono ... bench: 737 ns/iter (+/- 37) +test rfc3339_humantime_seconds ... bench: 73 ns/iter (+/- 2) + +test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured; 0 filtered out + + Running target/release/deps/datetime_parse-342628f877d7867c + +running 6 tests +test datetime_utc_parse_millis ... bench: 228 ns/iter (+/- 11) +test datetime_utc_parse_nanos ... bench: 236 ns/iter (+/- 10) +test datetime_utc_parse_seconds ... bench: 204 ns/iter (+/- 18) +test rfc3339_humantime_millis ... bench: 28 ns/iter (+/- 1) +test rfc3339_humantime_nanos ... bench: 36 ns/iter (+/- 2) +test rfc3339_humantime_seconds ... bench: 24 ns/iter (+/- 1) + +test result: ok. 0 passed; 0 failed; 0 ignored; 6 measured; 0 filtered out +``` + +See [serde-humantime] for serde integration. + +[serde-humantime]: https://docs.rs/serde-humantime/0.1.1/serde_humantime/ + +License +======= + +Licensed under either of + +* Apache License, Version 2.0, (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) +* MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT) + +at your option. + +Contribution +------------ + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/humantime/benches/datetime_format.rs b/humantime/benches/datetime_format.rs new file mode 100644 index 000000000..7f6dca79c --- /dev/null +++ b/humantime/benches/datetime_format.rs @@ -0,0 +1,58 @@ +#![feature(test)] +extern crate chrono; +extern crate humantime; +extern crate test; + +use std::io::Write; +use std::time::{Duration, UNIX_EPOCH}; +use humantime::format_rfc3339; + + +#[bench] +fn rfc3339_humantime_seconds(b: &mut test::Bencher) { + let time = UNIX_EPOCH + Duration::new(1483228799, 0); + let mut buf = Vec::with_capacity(100); + b.iter(|| { + buf.truncate(0); + write!(&mut buf, "{}", format_rfc3339(time)).unwrap() + }); +} + +#[bench] +fn rfc3339_chrono(b: &mut test::Bencher) { + use chrono::{DateTime, NaiveDateTime, Utc}; + use chrono::format::Item; + use chrono::format::Item::*; + use chrono::format::Numeric::*; + use chrono::format::Fixed::*; + use chrono::format::Pad::*; + + let time = DateTime::::from_utc( + NaiveDateTime::from_timestamp(1483228799, 0), Utc); + let mut buf = Vec::with_capacity(100); + + // formatting code from env_logger + const ITEMS: &'static [Item<'static>] = { + &[ + Numeric(Year, Zero), + Literal("-"), + Numeric(Month, Zero), + Literal("-"), + Numeric(Day, Zero), + Literal("T"), + Numeric(Hour, Zero), + Literal(":"), + Numeric(Minute, Zero), + Literal(":"), + Numeric(Second, Zero), + Fixed(TimezoneOffsetZ), + ] + }; + + + b.iter(|| { + buf.truncate(0); + write!(&mut buf, "{}", time.format_with_items(ITEMS.iter().cloned())) + .unwrap() + }); +} diff --git a/humantime/benches/datetime_parse.rs b/humantime/benches/datetime_parse.rs new file mode 100644 index 000000000..785d713d3 --- /dev/null +++ b/humantime/benches/datetime_parse.rs @@ -0,0 +1,50 @@ +#![feature(test)] +extern crate chrono; +extern crate humantime; +extern crate test; + +use chrono::{DateTime}; +use humantime::parse_rfc3339; + + +#[bench] +fn rfc3339_humantime_seconds(b: &mut test::Bencher) { + b.iter(|| { + parse_rfc3339("2018-02-13T23:08:32Z").unwrap() + }); +} + +#[bench] +fn datetime_utc_parse_seconds(b: &mut test::Bencher) { + b.iter(|| { + DateTime::parse_from_rfc3339("2018-02-13T23:08:32Z").unwrap() + }); +} + +#[bench] +fn rfc3339_humantime_millis(b: &mut test::Bencher) { + b.iter(|| { + parse_rfc3339("2018-02-13T23:08:32.123Z").unwrap() + }); +} + +#[bench] +fn datetime_utc_parse_millis(b: &mut test::Bencher) { + b.iter(|| { + DateTime::parse_from_rfc3339("2018-02-13T23:08:32.123Z").unwrap() + }); +} + +#[bench] +fn rfc3339_humantime_nanos(b: &mut test::Bencher) { + b.iter(|| { + parse_rfc3339("2018-02-13T23:08:32.123456983Z").unwrap() + }); +} + +#[bench] +fn datetime_utc_parse_nanos(b: &mut test::Bencher) { + b.iter(|| { + DateTime::parse_from_rfc3339("2018-02-13T23:08:32.123456983Z").unwrap() + }); +} diff --git a/humantime/bulk.yaml b/humantime/bulk.yaml new file mode 100644 index 000000000..cdb9763b6 --- /dev/null +++ b/humantime/bulk.yaml @@ -0,0 +1,8 @@ +minimum-bulk: v0.4.5 + +versions: + +- file: Cargo.toml + block-start: ^\[package\] + block-end: ^\[.*\] + regex: ^version\s*=\s*"(\S+)" diff --git a/humantime/src/date.rs b/humantime/src/date.rs new file mode 100644 index 000000000..40cd6dd12 --- /dev/null +++ b/humantime/src/date.rs @@ -0,0 +1,530 @@ +use std::fmt; +use std::str; +use std::time::{SystemTime, Duration, UNIX_EPOCH}; + +#[cfg(target_os="cloudabi")] +mod max { + pub const SECONDS: u64 = ::std::u64::MAX / 1_000_000_000; + #[allow(unused)] + pub const TIMESTAMP: &'static str = "2554-07-21T23:34:33Z"; +} +#[cfg(all( + target_pointer_width="32", + not(target_os="cloudabi"), + not(target_os="windows"), + not(all(target_arch="wasm32", not(target_os="emscripten"))) +))] +mod max { + pub const SECONDS: u64 = ::std::i32::MAX as u64; + #[allow(unused)] + pub const TIMESTAMP: &'static str = "2038-01-19T03:14:07Z"; +} + +#[cfg(any( + target_pointer_width="64", + target_os="windows", + all(target_arch="wasm32", not(target_os="emscripten")), +))] +mod max { + pub const SECONDS: u64 = 253402300800-1; // last second of year 9999 + #[allow(unused)] + pub const TIMESTAMP: &'static str = "9999-12-31T23:59:59Z"; +} + +quick_error! { + /// Error parsing datetime (timestamp) + #[derive(Debug, PartialEq, Clone, Copy)] + pub enum Error { + /// Numeric component is out of range + OutOfRange { + display("numeric component is out of range") + } + /// Bad character where digit is expected + InvalidDigit { + display("bad character where digit is expected") + } + /// Other formatting errors + InvalidFormat { + display("timestamp format is invalid") + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Precision { + Smart, + Seconds, + Nanos, +} + +/// A wrapper type that allows you to Display a SystemTime +#[derive(Debug, Clone)] +pub struct Rfc3339Timestamp(SystemTime, Precision); + +#[inline] +fn two_digits(b1: u8, b2: u8) -> Result { + if b1 < b'0' || b2 < b'0' || b1 > b'9' || b2 > b'9' { + return Err(Error::InvalidDigit); + } + Ok(((b1 - b'0')*10 + (b2 - b'0')) as u64) +} + +/// Parse RFC3339 timestamp `2018-02-14T00:28:07Z` +/// +/// Supported feature: any precision of fractional +/// digits `2018-02-14T00:28:07.133Z`. +/// +/// Unsupported feature: localized timestamps. Only UTC is supported. +pub fn parse_rfc3339(s: &str) -> Result { + if s.len() < "2018-02-14T00:28:07Z".len() { + return Err(Error::InvalidFormat); + } + let b = s.as_bytes(); + if b[10] != b'T' || b[b.len()-1] != b'Z' { + return Err(Error::InvalidFormat); + } + return parse_rfc3339_weak(s); +} + +/// Parse RFC3339-like timestamp `2018-02-14 00:28:07` +/// +/// Supported features: +/// +/// 1. Any precision of fractional digits `2018-02-14 00:28:07.133`. +/// 2. Supports timestamp with or without either of `T` or `Z` +/// 3. Anything valid for `parse_3339` is valid for this function +/// +/// Unsupported feature: localized timestamps. Only UTC is supported, even if +/// `Z` is not specified. +/// +/// This function is intended to use for parsing human input. Whereas +/// `parse_rfc3339` is for strings generated programmatically. +pub fn parse_rfc3339_weak(s: &str) -> Result { + if s.len() < "2018-02-14T00:28:07".len() { + return Err(Error::InvalidFormat); + } + let b = s.as_bytes(); // for careless slicing + if b[4] != b'-' || b[7] != b'-' || (b[10] != b'T' && b[10] != b' ') || + b[13] != b':' || b[16] != b':' + { + return Err(Error::InvalidFormat); + } + let year = two_digits(b[0], b[1])? * 100 + two_digits(b[2], b[3])?; + let month = two_digits(b[5], b[6])?; + let day = two_digits(b[8], b[9])?; + let hour = two_digits(b[11], b[12])?; + let minute = two_digits(b[14], b[15])?; + let mut second = two_digits(b[17], b[18])?; + + if year < 1970 || hour > 23 || minute > 59 || second > 60 { + return Err(Error::OutOfRange); + } + // TODO(tailhook) should we check that leaps second is only on midnight ? + if second == 60 { + second = 59 + }; + let leap_years = ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100 + + ((year - 1) - 1600) / 400; + let leap = is_leap_year(year); + let (mut ydays, mdays) = match month { + 1 => (0, 31), + 2 if leap => (31, 29), + 2 => (31, 28), + 3 => (59, 31), + 4 => (90, 30), + 5 => (120, 31), + 6 => (151, 30), + 7 => (181, 31), + 8 => (212, 31), + 9 => (243, 30), + 10 => (273, 31), + 11 => (304, 30), + 12 => (334, 31), + _ => return Err(Error::OutOfRange), + }; + if day > mdays || day == 0 { + return Err(Error::OutOfRange); + } + ydays += day - 1; + if leap && month > 2 { + ydays += 1; + } + let days = (year - 1970) * 365 + leap_years + ydays; + + let time = second + minute * 60 + hour * 3600; + + let mut nanos = 0; + let mut mult = 100_000_000; + if b.get(19) == Some(&b'.') { + for idx in 20..b.len() { + if b[idx] == b'Z' { + if idx == b.len()-1 { + break; + } else { + return Err(Error::InvalidDigit); + } + } + if b[idx] < b'0' || b[idx] > b'9' { + return Err(Error::InvalidDigit); + } + nanos += mult * (b[idx] - b'0') as u32; + mult /= 10; + } + } else { + if b.len() != 19 && (b.len() > 20 || b[19] != b'Z') { + return Err(Error::InvalidFormat); + } + } + + let total_seconds = time + days * 86400; + if total_seconds > max::SECONDS { + return Err(Error::OutOfRange); + } + + return Ok(UNIX_EPOCH + Duration::new(total_seconds, nanos)); +} + +fn is_leap_year(y: u64) -> bool { + y % 4 == 0 && (!(y % 100 == 0) || y % 400 == 0) +} + +/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z` +/// +/// This function formats timestamp with smart precision: i.e. if it has no +/// fractional seconds, they aren't written at all. And up to nine digits if +/// they are. +/// +/// The value is always UTC and ignores system timezone. +pub fn format_rfc3339(system_time: SystemTime) -> Rfc3339Timestamp { + return Rfc3339Timestamp(system_time, Precision::Smart); +} + +/// Format an RFC3339 timestamp `2018-02-14T00:28:07Z` +/// +/// This format always shows timestamp without fractional seconds. +/// +/// The value is always UTC and ignores system timezone. +pub fn format_rfc3339_seconds(system_time: SystemTime) -> Rfc3339Timestamp { + return Rfc3339Timestamp(system_time, Precision::Seconds); +} + +/// Format an RFC3339 timestamp `2018-02-14T00:28:07.000000000Z` +/// +/// This format always shows nanoseconds even if nanosecond value is zero. +/// +/// The value is always UTC and ignores system timezone. +pub fn format_rfc3339_nanos(system_time: SystemTime) -> Rfc3339Timestamp { + return Rfc3339Timestamp(system_time, Precision::Nanos); +} + +impl fmt::Display for Rfc3339Timestamp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Precision::*; + + let dur = self.0.duration_since(UNIX_EPOCH) + .expect("all times should be after the epoch"); + let secs_since_epoch = dur.as_secs(); + let nanos = dur.subsec_nanos(); + + if secs_since_epoch >= 253402300800 { // year 9999 + return Err(fmt::Error); + } + + /* 2000-03-01 (mod 400 year, immediately after feb29 */ + const LEAPOCH: i64 = 11017; + const DAYS_PER_400Y: i64 = 365*400 + 97; + const DAYS_PER_100Y: i64 = 365*100 + 24; + const DAYS_PER_4Y: i64 = 365*4 + 1; + + let days = (secs_since_epoch / 86400) as i64 - LEAPOCH; + let secs_of_day = secs_since_epoch % 86400; + + let mut qc_cycles = days / DAYS_PER_400Y; + let mut remdays = days % DAYS_PER_400Y; + + if remdays < 0 { + remdays += DAYS_PER_400Y; + qc_cycles -= 1; + } + + let mut c_cycles = remdays / DAYS_PER_100Y; + if c_cycles == 4 { c_cycles -= 1; } + remdays -= c_cycles * DAYS_PER_100Y; + + let mut q_cycles = remdays / DAYS_PER_4Y; + if q_cycles == 25 { q_cycles -= 1; } + remdays -= q_cycles * DAYS_PER_4Y; + + let mut remyears = remdays / 365; + if remyears == 4 { remyears -= 1; } + remdays -= remyears * 365; + + let mut year = 2000 + + remyears + 4*q_cycles + 100*c_cycles + 400*qc_cycles; + + let months = [31,30,31,30,31,31,30,31,30,31,31,29]; + let mut mon = 0; + for mon_len in months.iter() { + mon += 1; + if remdays < *mon_len { + break; + } + remdays -= *mon_len; + } + let mday = remdays+1; + let mon = if mon + 2 > 12 { + year += 1; + mon - 10 + } else { + mon + 2 + }; + + let mut buf: [u8; 30] = [ + // Too long to write as: b"0000-00-00T00:00:00.000000000Z" + b'0', b'0', b'0', b'0', b'-', b'0', b'0', b'-', b'0', b'0', b'T', + b'0', b'0', b':', b'0', b'0', b':', b'0', b'0', + b'.', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'0', b'Z', + ]; + buf[0] = b'0' + (year / 1000) as u8; + buf[1] = b'0' + (year / 100 % 10) as u8; + buf[2] = b'0' + (year / 10 % 10) as u8; + buf[3] = b'0' + (year % 10) as u8; + buf[5] = b'0' + (mon / 10) as u8; + buf[6] = b'0' + (mon % 10) as u8; + buf[8] = b'0' + (mday / 10) as u8; + buf[9] = b'0' + (mday % 10) as u8; + buf[11] = b'0' + (secs_of_day / 3600 / 10) as u8; + buf[12] = b'0' + (secs_of_day / 3600 % 10) as u8; + buf[14] = b'0' + (secs_of_day / 60 / 10 % 6) as u8; + buf[15] = b'0' + (secs_of_day / 60 % 10) as u8; + buf[17] = b'0' + (secs_of_day / 10 % 6) as u8; + buf[18] = b'0' + (secs_of_day % 10) as u8; + + if self.1 == Seconds || nanos == 0 && self.1 == Smart { + buf[19] = b'Z'; + f.write_str(unsafe { str::from_utf8_unchecked(&buf[..20]) }) + } else { + buf[20] = b'0' + (nanos / 100_000_000) as u8; + buf[21] = b'0' + (nanos / 10_000_000 % 10) as u8; + buf[22] = b'0' + (nanos / 1_000_000 % 10) as u8; + buf[23] = b'0' + (nanos / 100_000 % 10) as u8; + buf[24] = b'0' + (nanos / 10_000 % 10) as u8; + buf[25] = b'0' + (nanos / 1_000 % 10) as u8; + buf[26] = b'0' + (nanos / 100 % 10) as u8; + buf[27] = b'0' + (nanos / 10 % 10) as u8; + buf[28] = b'0' + (nanos / 1 % 10) as u8; + // we know our chars are all ascii + f.write_str(unsafe { str::from_utf8_unchecked(&buf[..]) }) + } + } +} + +#[cfg(test)] +mod test { + extern crate time; + extern crate rand; + + use std::str::from_utf8; + use self::rand::Rng; + use std::time::{UNIX_EPOCH, SystemTime, Duration}; + use super::{parse_rfc3339, parse_rfc3339_weak, format_rfc3339}; + use super::max; + + fn from_sec(sec: u64) -> (String, SystemTime) { + let s = time::at_utc(time::Timespec { sec: sec as i64, nsec: 0 }) + .rfc3339().to_string(); + let time = UNIX_EPOCH + Duration::new(sec, 0); + return (s, time) + } + + #[test] + #[cfg(all(target_pointer_width="32", target_os="linux"))] + fn year_after_2038_fails_gracefully() { + // next second + assert_eq!(parse_rfc3339("2038-01-19T03:14:08Z").unwrap_err(), + super::Error::OutOfRange); + assert_eq!(parse_rfc3339("9999-12-31T23:59:59Z").unwrap_err(), + super::Error::OutOfRange); + } + + #[test] + fn smoke_tests_parse() { + assert_eq!(parse_rfc3339("1970-01-01T00:00:00Z").unwrap(), + UNIX_EPOCH + Duration::new(0, 0)); + assert_eq!(parse_rfc3339("1970-01-01T00:00:01Z").unwrap(), + UNIX_EPOCH + Duration::new(1, 0)); + assert_eq!(parse_rfc3339("2018-02-13T23:08:32Z").unwrap(), + UNIX_EPOCH + Duration::new(1518563312, 0)); + assert_eq!(parse_rfc3339("2012-01-01T00:00:00Z").unwrap(), + UNIX_EPOCH + Duration::new(1325376000, 0)); + } + + #[test] + fn smoke_tests_format() { + assert_eq!( + format_rfc3339(UNIX_EPOCH + Duration::new(0, 0)).to_string(), + "1970-01-01T00:00:00Z"); + assert_eq!( + format_rfc3339(UNIX_EPOCH + Duration::new(1, 0)).to_string(), + "1970-01-01T00:00:01Z"); + assert_eq!( + format_rfc3339(UNIX_EPOCH + Duration::new(1518563312, 0)).to_string(), + "2018-02-13T23:08:32Z"); + assert_eq!( + format_rfc3339(UNIX_EPOCH + Duration::new(1325376000, 0)).to_string(), + "2012-01-01T00:00:00Z"); + } + + #[test] + fn upper_bound() { + let max = UNIX_EPOCH + Duration::new(max::SECONDS, 0); + assert_eq!(parse_rfc3339(&max::TIMESTAMP).unwrap(), max); + assert_eq!(format_rfc3339(max).to_string(), max::TIMESTAMP); + } + + #[test] + fn leap_second() { + assert_eq!(parse_rfc3339("2016-12-31T23:59:60Z").unwrap(), + UNIX_EPOCH + Duration::new(1483228799, 0)); + } + + #[test] + fn first_731_days() { + let year_start = 0; // 1970 + for day in 0.. (365 * 2 + 1) { // scan leap year and non-leap year + let (s, time) = from_sec(year_start + day * 86400); + assert_eq!(parse_rfc3339(&s).unwrap(), time); + assert_eq!(format_rfc3339(time).to_string(), s); + } + } + + #[test] + fn the_731_consecutive_days() { + let year_start = 1325376000; // 2012 + for day in 0.. (365 * 2 + 1) { // scan leap year and non-leap year + let (s, time) = from_sec(year_start + day * 86400); + assert_eq!(parse_rfc3339(&s).unwrap(), time); + assert_eq!(format_rfc3339(time).to_string(), s); + } + } + + #[test] + fn all_86400_seconds() { + let day_start = 1325376000; + for second in 0..86400 { // scan leap year and non-leap year + let (s, time) = from_sec(day_start + second); + assert_eq!(parse_rfc3339(&s).unwrap(), time); + assert_eq!(format_rfc3339(time).to_string(), s); + } + } + + #[test] + fn random_past() { + let upper = SystemTime::now().duration_since(UNIX_EPOCH).unwrap() + .as_secs(); + for _ in 0..10000 { + let sec = rand::thread_rng().gen_range(0, upper); + let (s, time) = from_sec(sec); + assert_eq!(parse_rfc3339(&s).unwrap(), time); + assert_eq!(format_rfc3339(time).to_string(), s); + } + } + + #[test] + fn random_wide_range() { + for _ in 0..100000 { + let sec = rand::thread_rng().gen_range(0, max::SECONDS); + let (s, time) = from_sec(sec); + assert_eq!(parse_rfc3339(&s).unwrap(), time); + assert_eq!(format_rfc3339(time).to_string(), s); + } + } + + #[test] + fn milliseconds() { + assert_eq!(parse_rfc3339("1970-01-01T00:00:00.123Z").unwrap(), + UNIX_EPOCH + Duration::new(0, 123000000)); + assert_eq!(format_rfc3339(UNIX_EPOCH + Duration::new(0, 123000000)) + .to_string(), "1970-01-01T00:00:00.123000000Z"); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn zero_month() { + parse_rfc3339("1970-00-01T00:00:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_month() { + parse_rfc3339("1970-32-01T00:00:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn zero_day() { + parse_rfc3339("1970-01-00T00:00:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_day() { + parse_rfc3339("1970-12-35T00:00:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_day2() { + parse_rfc3339("1970-02-30T00:00:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_second() { + parse_rfc3339("1970-12-30T00:00:78Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_minute() { + parse_rfc3339("1970-12-30T00:78:00Z").unwrap(); + } + + #[test] + #[should_panic(expected="OutOfRange")] + fn big_hour() { + parse_rfc3339("1970-12-30T24:00:00Z").unwrap(); + } + + #[test] + fn break_data() { + for pos in 0.."2016-12-31T23:59:60Z".len() { + let mut s = b"2016-12-31T23:59:60Z".to_vec(); + s[pos] = b'x'; + parse_rfc3339(from_utf8(&s).unwrap()).unwrap_err(); + } + } + + #[test] + fn weak_smoke_tests() { + assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00").unwrap(), + UNIX_EPOCH + Duration::new(0, 0)); + parse_rfc3339("1970-01-01 00:00:00").unwrap_err(); + + assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123").unwrap(), + UNIX_EPOCH + Duration::new(0, 123000)); + parse_rfc3339("1970-01-01 00:00:00.000123").unwrap_err(); + + assert_eq!(parse_rfc3339_weak("1970-01-01T00:00:00.000123").unwrap(), + UNIX_EPOCH + Duration::new(0, 123000)); + parse_rfc3339("1970-01-01T00:00:00.000123").unwrap_err(); + + assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00.000123Z").unwrap(), + UNIX_EPOCH + Duration::new(0, 123000)); + parse_rfc3339("1970-01-01 00:00:00.000123Z").unwrap_err(); + + assert_eq!(parse_rfc3339_weak("1970-01-01 00:00:00Z").unwrap(), + UNIX_EPOCH + Duration::new(0, 0)); + parse_rfc3339("1970-01-01 00:00:00Z").unwrap_err(); + } +} diff --git a/humantime/src/duration.rs b/humantime/src/duration.rs new file mode 100644 index 000000000..9fafa84bd --- /dev/null +++ b/humantime/src/duration.rs @@ -0,0 +1,411 @@ +use std::fmt; +use std::str::Chars; +use std::time::Duration; +use std::error::Error as StdError; + +quick_error! { + /// Error parsing human-friendly duration + #[derive(Debug, PartialEq, Clone, Copy)] + pub enum Error { + /// Invalid character during parsing + /// + /// More specifically anything that is not alphanumeric is prohibited + /// + /// The field is an byte offset of the character in the string. + InvalidCharacter(offset: usize) { + display("invalid character at {}", offset) + description("invalid character") + } + /// Non-numeric value where number is expected + /// + /// This usually means that either time unit is broken into words, + /// e.g. `m sec` instead of `msec`, or just number is omitted, + /// for example `2 hours min` instead of `2 hours 1 min` + /// + /// The field is an byte offset of the errorneous character + /// in the string. + NumberExpected(offset: usize) { + display("expected number at {}", offset) + description("expected number") + } + /// Unit in the number is not one of allowed units + /// + /// See documentation of `parse_duration` for the list of supported + /// time units. + /// + /// The two fields are start and end (exclusive) of the slice from + /// the original string, containing errorneous value + UnknownUnit(start: usize, end: usize) { + display("unknown unit at {}-{}", start, end) + description("unknown unit") + } + /// The numeric value is too large + /// + /// Usually this means value is too large to be useful. If user writes + /// data in subsecond units, then the maximum is about 3k years. When + /// using seconds, or larger units, the limit is even larger. + NumberOverflow { + display(self_) -> ("{}", self_.description()) + description("number is too large") + } + /// The value was an empty string (or consists only whitespace) + Empty { + display(self_) -> ("{}", self_.description()) + description("value was empty") + } + } + +} + +/// A wrapper type that allows you to Display a Duration +#[derive(Debug, Clone)] +pub struct FormattedDuration(Duration); + +trait OverflowOp: Sized { + fn mul(self, other: Self) -> Result; + fn add(self, other: Self) -> Result; +} + +impl OverflowOp for u64 { + fn mul(self, other: Self) -> Result { + self.checked_mul(other).ok_or(Error::NumberOverflow) + } + fn add(self, other: Self) -> Result { + self.checked_add(other).ok_or(Error::NumberOverflow) + } +} + +struct Parser<'a> { + iter: Chars<'a>, + src: &'a str, + current: (u64, u64), +} + +impl<'a> Parser<'a> { + fn off(&self) -> usize { + self.src.len() - self.iter.as_str().len() + } + + fn parse_first_char(&mut self) -> Result, Error> { + let off = self.off(); + for c in self.iter.by_ref() { + match c { + '0'...'9' => { + return Ok(Some(c as u64 - '0' as u64)); + } + c if c.is_whitespace() => continue, + _ => { + return Err(Error::NumberExpected(off)); + } + } + } + return Ok(None); + } + fn parse_unit(&mut self, n: u64, start: usize, end: usize) + -> Result<(), Error> + { + let (mut sec, nsec) = match &self.src[start..end] { + "nanos" | "nsec" | "ns" => (0u64, n), + "usec" | "us" => (0u64, try!(n.mul(1000))), + "millis" | "msec" | "ms" => (0u64, try!(n.mul(1000_000))), + "seconds" | "second" | "secs" | "sec" | "s" => (n, 0), + "minutes" | "minute" | "min" | "mins" | "m" + => (try!(n.mul(60)), 0), + "hours" | "hour" | "hr" | "hrs" | "h" => (try!(n.mul(3600)), 0), + "days" | "day" | "d" => (try!(n.mul(86400)), 0), + "weeks" | "week" | "w" => (try!(n.mul(86400*7)), 0), + "months" | "month" | "M" => (try!(n.mul(2630016)), 0), // 30.44d + "years" | "year" | "y" => (try!(n.mul(31557600)), 0), // 365.25d + _ => return Err(Error::UnknownUnit(start, end)), + }; + let mut nsec = try!(self.current.1.add(nsec)); + if nsec > 1000_000_000 { + sec = try!(sec.add(nsec / 1000_000_000)); + nsec %= 1000_000_000; + } + sec = try!(self.current.0.add(sec)); + self.current = (sec, nsec); + Ok(()) + } + + fn parse(mut self) -> Result { + let mut n = try!(try!(self.parse_first_char()).ok_or(Error::Empty)); + 'outer: loop { + let mut off = self.off(); + while let Some(c) = self.iter.next() { + match c { + '0'...'9' => { + n = try!(n.checked_mul(10) + .and_then(|x| x.checked_add(c as u64 - '0' as u64)) + .ok_or(Error::NumberOverflow)); + } + c if c.is_whitespace() => {} + 'a'...'z' | 'A'...'Z' => { + break; + } + _ => { + return Err(Error::InvalidCharacter(off)); + } + } + off = self.off(); + } + let start = off; + let mut off = self.off(); + while let Some(c) = self.iter.next() { + match c { + '0'...'9' => { + try!(self.parse_unit(n, start, off)); + n = c as u64 - '0' as u64; + continue 'outer; + } + c if c.is_whitespace() => break, + 'a'...'z' | 'A'...'Z' => {} + _ => { + return Err(Error::InvalidCharacter(off)); + } + } + off = self.off(); + } + try!(self.parse_unit(n, start, off)); + n = match try!(self.parse_first_char()) { + Some(n) => n, + None => return Ok( + Duration::new(self.current.0, self.current.1 as u32)), + }; + } + } + +} + +/// Parse duration object `1hour 12min 5s` +/// +/// The duration object is a concatenation of time spans. Where each time +/// span is an integer number and a suffix. Supported suffixes: +/// +/// * `nsec`, `ns` -- microseconds +/// * `usec`, `us` -- microseconds +/// * `msec`, `ms` -- milliseconds +/// * `seconds`, `second`, `sec`, `s` +/// * `minutes`, `minute`, `min`, `m` +/// * `hours`, `hour`, `hr`, `h` +/// * `days`, `day`, `d` +/// * `weeks`, `week`, `w` +/// * `months`, `month`, `M` -- defined as 30.44 days +/// * `years`, `year`, `y` -- defined as 365.25 days +/// +/// # Examples +/// +/// ``` +/// use std::time::Duration; +/// use humantime::parse_duration; +/// +/// assert_eq!(parse_duration("2h 37min"), Ok(Duration::new(9420, 0))); +/// assert_eq!(parse_duration("32ms"), Ok(Duration::new(0, 32_000_000))); +/// ``` +pub fn parse_duration(s: &str) -> Result { + Parser { + iter: s.chars(), + src: s, + current: (0, 0), + }.parse() +} + +/// Formats duration into a human-readable string +/// +/// Note: this format is guaranteed to have same value when using +/// parse_duration, but we can change some details of the exact composition +/// of the value. +/// +/// # Examples +/// +/// ``` +/// use std::time::Duration; +/// use humantime::format_duration; +/// +/// let val1 = Duration::new(9420, 0); +/// assert_eq!(format_duration(val1).to_string(), "2h 37m"); +/// let val2 = Duration::new(0, 32_000_000); +/// assert_eq!(format_duration(val2).to_string(), "32ms"); +/// ``` +pub fn format_duration(val: Duration) -> FormattedDuration { + FormattedDuration(val) +} + +fn item_plural(f: &mut fmt::Formatter, started: &mut bool, + name: &str, value: u64) + -> fmt::Result +{ + if value > 0 { + if *started { + f.write_str(" ")?; + } + write!(f, "{}{}", value, name)?; + if value > 1 { + f.write_str("s")?; + } + *started = true; + } + Ok(()) +} +fn item(f: &mut fmt::Formatter, started: &mut bool, name: &str, value: u32) + -> fmt::Result +{ + if value > 0 { + if *started { + f.write_str(" ")?; + } + write!(f, "{}{}", value, name)?; + *started = true; + } + Ok(()) +} + +impl fmt::Display for FormattedDuration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let secs = self.0.as_secs(); + let nanos = self.0.subsec_nanos(); + + if secs == 0 && nanos == 0 { + f.write_str("0s")?; + return Ok(()); + } + + let years = secs / 31557600; // 365.25d + let ydays = secs % 31557600; + let months = ydays / 2630016; // 30.44d + let mdays = ydays % 2630016; + let days = mdays / 86400; + let day_secs = mdays % 86400; + let hours = day_secs / 3600; + let minutes = day_secs % 3600 / 60; + let seconds = day_secs % 60; + + let millis = nanos / 1_000_000; + let micros = nanos / 1000 % 1000; + let nanosec = nanos % 1000; + + let ref mut started = false; + item_plural(f, started, "year", years)?; + item_plural(f, started, "month", months)?; + item_plural(f, started, "day", days)?; + item(f, started, "h", hours as u32)?; + item(f, started, "m", minutes as u32)?; + item(f, started, "s", seconds as u32)?; + item(f, started, "ms", millis)?; + item(f, started, "us", micros)?; + item(f, started, "ns", nanosec)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + extern crate rand; + + use std::time::Duration; + use self::rand::Rng; + use super::{parse_duration, format_duration}; + use super::Error; + + #[test] + fn test_units() { + assert_eq!(parse_duration("17nsec"), Ok(Duration::new(0, 17))); + assert_eq!(parse_duration("17nanos"), Ok(Duration::new(0, 17))); + assert_eq!(parse_duration("33ns"), Ok(Duration::new(0, 33))); + assert_eq!(parse_duration("3usec"), Ok(Duration::new(0, 3000))); + assert_eq!(parse_duration("78us"), Ok(Duration::new(0, 78000))); + assert_eq!(parse_duration("31msec"), Ok(Duration::new(0, 31000000))); + assert_eq!(parse_duration("31millis"), Ok(Duration::new(0, 31000000))); + assert_eq!(parse_duration("6ms"), Ok(Duration::new(0, 6000000))); + assert_eq!(parse_duration("3000s"), Ok(Duration::new(3000, 0))); + assert_eq!(parse_duration("300sec"), Ok(Duration::new(300, 0))); + assert_eq!(parse_duration("300secs"), Ok(Duration::new(300, 0))); + assert_eq!(parse_duration("50seconds"), Ok(Duration::new(50, 0))); + assert_eq!(parse_duration("1second"), Ok(Duration::new(1, 0))); + assert_eq!(parse_duration("100m"), Ok(Duration::new(6000, 0))); + assert_eq!(parse_duration("12min"), Ok(Duration::new(720, 0))); + assert_eq!(parse_duration("12mins"), Ok(Duration::new(720, 0))); + assert_eq!(parse_duration("1minute"), Ok(Duration::new(60, 0))); + assert_eq!(parse_duration("7minutes"), Ok(Duration::new(420, 0))); + assert_eq!(parse_duration("2h"), Ok(Duration::new(7200, 0))); + assert_eq!(parse_duration("7hr"), Ok(Duration::new(25200, 0))); + assert_eq!(parse_duration("7hrs"), Ok(Duration::new(25200, 0))); + assert_eq!(parse_duration("1hour"), Ok(Duration::new(3600, 0))); + assert_eq!(parse_duration("24hours"), Ok(Duration::new(86400, 0))); + assert_eq!(parse_duration("1day"), Ok(Duration::new(86400, 0))); + assert_eq!(parse_duration("2days"), Ok(Duration::new(172800, 0))); + assert_eq!(parse_duration("365d"), Ok(Duration::new(31536000, 0))); + assert_eq!(parse_duration("1week"), Ok(Duration::new(604800, 0))); + assert_eq!(parse_duration("7weeks"), Ok(Duration::new(4233600, 0))); + assert_eq!(parse_duration("52w"), Ok(Duration::new(31449600, 0))); + assert_eq!(parse_duration("1month"), Ok(Duration::new(2630016, 0))); + assert_eq!(parse_duration("3months"), Ok(Duration::new(3*2630016, 0))); + assert_eq!(parse_duration("12M"), Ok(Duration::new(31560192, 0))); + assert_eq!(parse_duration("1year"), Ok(Duration::new(31557600, 0))); + assert_eq!(parse_duration("7years"), Ok(Duration::new(7*31557600, 0))); + assert_eq!(parse_duration("17y"), Ok(Duration::new(536479200, 0))); + } + + #[test] + fn test_combo() { + assert_eq!(parse_duration("20 min 17 nsec "), Ok(Duration::new(1200, 17))); + assert_eq!(parse_duration("2h 15m"), Ok(Duration::new(8100, 0))); + } + + #[test] + fn all_86400_seconds() { + for second in 0..86400 { // scan leap year and non-leap year + let d = Duration::new(second, 0); + assert_eq!(d, + parse_duration(&format_duration(d).to_string()).unwrap()); + } + } + + #[test] + fn random_second() { + for _ in 0..10000 { + let sec = rand::thread_rng().gen_range(0, 253370764800); + let d = Duration::new(sec, 0); + assert_eq!(d, + parse_duration(&format_duration(d).to_string()).unwrap()); + } + } + + #[test] + fn random_any() { + for _ in 0..10000 { + let sec = rand::thread_rng().gen_range(0, 253370764800); + let nanos = rand::thread_rng().gen_range(0, 1_000_000_000); + let d = Duration::new(sec, nanos); + assert_eq!(d, + parse_duration(&format_duration(d).to_string()).unwrap()); + } + } + + #[test] + fn test_overlow() { + // Overflow on subseconds is earlier because of how we do conversion + // we could fix it, but I don't see any good reason for this + assert_eq!(parse_duration("100000000000000000000ns"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("100000000000000000us"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("100000000000000ms"), + Err(Error::NumberOverflow)); + + assert_eq!(parse_duration("100000000000000000000s"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("10000000000000000000m"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("1000000000000000000h"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("100000000000000000d"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("10000000000000000w"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("1000000000000000M"), + Err(Error::NumberOverflow)); + assert_eq!(parse_duration("10000000000000y"), + Err(Error::NumberOverflow)); + } +} diff --git a/humantime/src/lib.rs b/humantime/src/lib.rs new file mode 100644 index 000000000..1ab7cf4ea --- /dev/null +++ b/humantime/src/lib.rs @@ -0,0 +1,30 @@ +//! Human-friendly time parser and formatter +//! +//! Features: +//! +//! * Parses durations in free form like `15days 2min 2s` +//! * Formats durations in similar form `2years 2min 12us` +//! * Parses and formats timestamp in `rfc3339` format: `2018-01-01T12:53:00Z` +//! * Parses timestamps in a weaker format: `2018-01-01 12:53:00` +//! +//! Timestamp parsing/formatting is super-fast because format is basically +//! fixed. +//! +//! See [serde-humantime] for serde integration. +//! +//! [serde-humantime]: https://docs.rs/serde-humantime/0.1.1/serde_humantime/ +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] + +#[macro_use] extern crate quick_error; + +mod duration; +mod wrapper; +mod date; + +pub use duration::{parse_duration, Error as DurationError}; +pub use duration::{format_duration, FormattedDuration}; +pub use wrapper::{Duration, Timestamp}; +pub use date::{parse_rfc3339, parse_rfc3339_weak, Error as TimestampError}; +pub use date::{format_rfc3339, format_rfc3339_seconds, format_rfc3339_nanos}; +pub use date::{Rfc3339Timestamp}; diff --git a/humantime/src/wrapper.rs b/humantime/src/wrapper.rs new file mode 100644 index 000000000..df01d791a --- /dev/null +++ b/humantime/src/wrapper.rs @@ -0,0 +1,107 @@ +use std::str::FromStr; +use std::ops::Deref; +use std::fmt; +use std::time::{Duration as StdDuration, SystemTime}; + +use duration::{self, parse_duration, format_duration}; +use date::{self, parse_rfc3339_weak, format_rfc3339}; + +/// A wrapper for duration that has `FromStr` implementation +/// +/// This is useful if you want to use it somewhere where `FromStr` is +/// expected. +/// +/// See `parse_duration` for the description of the format. +/// +/// # Example +/// +/// ``` +/// use std::time::Duration; +/// let x: Duration; +/// x = "12h 5min 2ns".parse::().unwrap().into(); +/// assert_eq!(x, Duration::new(12*3600 + 5*60, 2)) +/// ``` +/// +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct Duration(StdDuration); + +/// A wrapper for SystemTime that has `FromStr` implementation +/// +/// This is useful if you want to use it somewhere where `FromStr` is +/// expected. +/// +/// See `parse_rfc3339_weak` for the description of the format. The "weak" +/// format is used as it's more pemissive for human input as this is the +/// expected use of the type (e.g. command-line parsing). +/// +/// # Example +/// +/// ``` +/// use std::time::SystemTime; +/// let x: SystemTime; +/// x = "2018-02-16T00:31:37Z".parse::().unwrap().into(); +/// assert_eq!(humantime::format_rfc3339(x).to_string(), "2018-02-16T00:31:37Z"); +/// ``` +/// +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Timestamp(SystemTime); + +impl AsRef for Duration { + fn as_ref(&self) -> &StdDuration { &self.0 } +} + +impl Deref for Duration { + type Target = StdDuration; + fn deref(&self) -> &StdDuration { &self.0 } +} + +impl Into for Duration { + fn into(self) -> StdDuration { self.0 } +} + +impl From for Duration { + fn from(dur: StdDuration) -> Duration { Duration(dur) } +} + +impl FromStr for Duration { + type Err = duration::Error; + fn from_str(s: &str) -> Result { + parse_duration(s).map(Duration) + } +} + +impl fmt::Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_duration(self.0).fmt(f) + } +} + +impl AsRef for Timestamp { + fn as_ref(&self) -> &SystemTime { &self.0 } +} + +impl Deref for Timestamp { + type Target = SystemTime; + fn deref(&self) -> &SystemTime { &self.0 } +} + +impl Into for Timestamp { + fn into(self) -> SystemTime { self.0 } +} + +impl From for Timestamp { + fn from(dur: SystemTime) -> Timestamp { Timestamp(dur) } +} + +impl FromStr for Timestamp { + type Err = date::Error; + fn from_str(s: &str) -> Result { + parse_rfc3339_weak(s).map(Timestamp) + } +} + +impl fmt::Display for Timestamp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_rfc3339(self.0).fmt(f) + } +} diff --git a/humantime/vagga.yaml b/humantime/vagga.yaml new file mode 100644 index 000000000..b5d6b8b7c --- /dev/null +++ b/humantime/vagga.yaml @@ -0,0 +1,92 @@ +commands: + + cargo: !Command + description: Run any cargo command + container: ubuntu + run: [cargo] + + make: !Command + description: Build the library + container: ubuntu + run: [cargo, build] + + test64: !Command + description: Test the 64bit library + container: ubuntu + environ: { RUST_BACKTRACE: 1 } + run: [cargo, test] + + test32: !Command + description: Test the 32bit library + container: ubuntu32 + environ: { RUST_BACKTRACE: 1 } + run: [cargo, test] + + test: !Command + description: Test the 64bit library + container: ubuntu + environ: { RUST_BACKTRACE: 1 } + prerequisites: [test64, test32] + run: [echo, okay] + + bench: !Command + description: Run benchmarks + container: bench + environ: { RUST_BACKTRACE: 1 } + run: [cargo, bench] + + _bulk: !Command + description: Run `bulk` command (for version bookkeeping) + container: ubuntu + run: [bulk] + +containers: + + ubuntu: + setup: + - !Ubuntu xenial + - !UbuntuUniverse + - !Install [ca-certificates, build-essential, vim] + + - !TarInstall + url: "https://static.rust-lang.org/dist/rust-1.24.0-x86_64-unknown-linux-gnu.tar.gz" + script: "./install.sh --prefix=/usr \ + --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo" + - &bulk !Tar + url: "https://github.com/tailhook/bulk/releases/download/v0.4.10/bulk-v0.4.10.tar.gz" + sha256: 481513f8a0306a9857d045497fb5b50b50a51e9ff748909ecf7d2bda1de275ab + path: / + + environ: + HOME: /work/target + USER: pc + + ubuntu32: + setup: + - !UbuntuRelease + codename: xenial + arch: i386 + - !UbuntuUniverse + - !Install [ca-certificates, build-essential, vim] + + - !TarInstall + url: "https://static.rust-lang.org/dist/rust-1.24.0-i686-unknown-linux-gnu.tar.gz" + script: "./install.sh --prefix=/usr \ + --components=rustc,rust-std-i686-unknown-linux-gnu,cargo" + + environ: + HOME: /work/target + USER: pc + + bench: + setup: + - !Ubuntu xenial + - !Install [ca-certificates, wget, build-essential] + - !TarInstall + url: https://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz + script: | + ./install.sh --prefix=/usr \ + --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo + environ: + HOME: /work/target + USER: pc diff --git a/idna/.cargo-checksum.json b/idna/.cargo-checksum.json new file mode 100644 index 000000000..220d3a920 --- /dev/null +++ b/idna/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"} \ No newline at end of file diff --git a/idna/Cargo.toml b/idna/Cargo.toml new file mode 100644 index 000000000..8e6c0215e --- /dev/null +++ b/idna/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "idna" +version = "0.1.5" +authors = ["The rust-url developers"] +description = "IDNA (Internationalizing Domain Names in Applications) and Punycode." +license = "MIT/Apache-2.0" +repository = "https://github.com/servo/rust-url/" + +[lib] +test = false +doctest = false + +[[test]] +name = "tests" +harness = false + +[[test]] +name = "unit" +[dependencies.matches] +version = "0.1" + +[dependencies.unicode-bidi] +version = "0.3" + +[dependencies.unicode-normalization] +version = "0.1.5" +[dev-dependencies.rustc-serialize] +version = "0.3" + +[dev-dependencies.rustc-test] +version = "0.3" diff --git a/idna/LICENSE-APACHE b/idna/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/idna/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/idna/LICENSE-MIT b/idna/LICENSE-MIT new file mode 100644 index 000000000..24de6b418 --- /dev/null +++ b/idna/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2013-2016 The rust-url developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/idna/src/IdnaMappingTable.txt b/idna/src/IdnaMappingTable.txt new file mode 100644 index 000000000..295606447 --- /dev/null +++ b/idna/src/IdnaMappingTable.txt @@ -0,0 +1,8405 @@ +# IdnaMappingTable-10.0.0.txt +# Date: 2017-02-23, 14:18:32 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode IDNA Compatible Preprocessing (UTS #46) +# For documentation, see http://www.unicode.org/reports/tr46/ + +0000..002C ; disallowed_STD3_valid # 1.1 ..COMMA +002D..002E ; valid # 1.1 HYPHEN-MINUS..FULL STOP +002F ; disallowed_STD3_valid # 1.1 SOLIDUS +0030..0039 ; valid # 1.1 DIGIT ZERO..DIGIT NINE +003A..0040 ; disallowed_STD3_valid # 1.1 COLON..COMMERCIAL AT +0041 ; mapped ; 0061 # 1.1 LATIN CAPITAL LETTER A +0042 ; mapped ; 0062 # 1.1 LATIN CAPITAL LETTER B +0043 ; mapped ; 0063 # 1.1 LATIN CAPITAL LETTER C +0044 ; mapped ; 0064 # 1.1 LATIN CAPITAL LETTER D +0045 ; mapped ; 0065 # 1.1 LATIN CAPITAL LETTER E +0046 ; mapped ; 0066 # 1.1 LATIN CAPITAL LETTER F +0047 ; mapped ; 0067 # 1.1 LATIN CAPITAL LETTER G +0048 ; mapped ; 0068 # 1.1 LATIN CAPITAL LETTER H +0049 ; mapped ; 0069 # 1.1 LATIN CAPITAL LETTER I +004A ; mapped ; 006A # 1.1 LATIN CAPITAL LETTER J +004B ; mapped ; 006B # 1.1 LATIN CAPITAL LETTER K +004C ; mapped ; 006C # 1.1 LATIN CAPITAL LETTER L +004D ; mapped ; 006D # 1.1 LATIN CAPITAL LETTER M +004E ; mapped ; 006E # 1.1 LATIN CAPITAL LETTER N +004F ; mapped ; 006F # 1.1 LATIN CAPITAL LETTER O +0050 ; mapped ; 0070 # 1.1 LATIN CAPITAL LETTER P +0051 ; mapped ; 0071 # 1.1 LATIN CAPITAL LETTER Q +0052 ; mapped ; 0072 # 1.1 LATIN CAPITAL LETTER R +0053 ; mapped ; 0073 # 1.1 LATIN CAPITAL LETTER S +0054 ; mapped ; 0074 # 1.1 LATIN CAPITAL LETTER T +0055 ; mapped ; 0075 # 1.1 LATIN CAPITAL LETTER U +0056 ; mapped ; 0076 # 1.1 LATIN CAPITAL LETTER V +0057 ; mapped ; 0077 # 1.1 LATIN CAPITAL LETTER W +0058 ; mapped ; 0078 # 1.1 LATIN CAPITAL LETTER X +0059 ; mapped ; 0079 # 1.1 LATIN CAPITAL LETTER Y +005A ; mapped ; 007A # 1.1 LATIN CAPITAL LETTER Z +005B..0060 ; disallowed_STD3_valid # 1.1 LEFT SQUARE BRACKET..GRAVE ACCENT +0061..007A ; valid # 1.1 LATIN SMALL LETTER A..LATIN SMALL LETTER Z +007B..007F ; disallowed_STD3_valid # 1.1 LEFT CURLY BRACKET.. +0080..009F ; disallowed # 1.1 .. +00A0 ; disallowed_STD3_mapped ; 0020 # 1.1 NO-BREAK SPACE +00A1..00A7 ; valid ; ; NV8 # 1.1 INVERTED EXCLAMATION MARK..SECTION SIGN +00A8 ; disallowed_STD3_mapped ; 0020 0308 # 1.1 DIAERESIS +00A9 ; valid ; ; NV8 # 1.1 COPYRIGHT SIGN +00AA ; mapped ; 0061 # 1.1 FEMININE ORDINAL INDICATOR +00AB..00AC ; valid ; ; NV8 # 1.1 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK..NOT SIGN +00AD ; ignored # 1.1 SOFT HYPHEN +00AE ; valid ; ; NV8 # 1.1 REGISTERED SIGN +00AF ; disallowed_STD3_mapped ; 0020 0304 # 1.1 MACRON +00B0..00B1 ; valid ; ; NV8 # 1.1 DEGREE SIGN..PLUS-MINUS SIGN +00B2 ; mapped ; 0032 # 1.1 SUPERSCRIPT TWO +00B3 ; mapped ; 0033 # 1.1 SUPERSCRIPT THREE +00B4 ; disallowed_STD3_mapped ; 0020 0301 # 1.1 ACUTE ACCENT +00B5 ; mapped ; 03BC # 1.1 MICRO SIGN +00B6 ; valid ; ; NV8 # 1.1 PILCROW SIGN +00B7 ; valid # 1.1 MIDDLE DOT +00B8 ; disallowed_STD3_mapped ; 0020 0327 # 1.1 CEDILLA +00B9 ; mapped ; 0031 # 1.1 SUPERSCRIPT ONE +00BA ; mapped ; 006F # 1.1 MASCULINE ORDINAL INDICATOR +00BB ; valid ; ; NV8 # 1.1 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BC ; mapped ; 0031 2044 0034 #1.1 VULGAR FRACTION ONE QUARTER +00BD ; mapped ; 0031 2044 0032 #1.1 VULGAR FRACTION ONE HALF +00BE ; mapped ; 0033 2044 0034 #1.1 VULGAR FRACTION THREE QUARTERS +00BF ; valid ; ; NV8 # 1.1 INVERTED QUESTION MARK +00C0 ; mapped ; 00E0 # 1.1 LATIN CAPITAL LETTER A WITH GRAVE +00C1 ; mapped ; 00E1 # 1.1 LATIN CAPITAL LETTER A WITH ACUTE +00C2 ; mapped ; 00E2 # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3 ; mapped ; 00E3 # 1.1 LATIN CAPITAL LETTER A WITH TILDE +00C4 ; mapped ; 00E4 # 1.1 LATIN CAPITAL LETTER A WITH DIAERESIS +00C5 ; mapped ; 00E5 # 1.1 LATIN CAPITAL LETTER A WITH RING ABOVE +00C6 ; mapped ; 00E6 # 1.1 LATIN CAPITAL LETTER AE +00C7 ; mapped ; 00E7 # 1.1 LATIN CAPITAL LETTER C WITH CEDILLA +00C8 ; mapped ; 00E8 # 1.1 LATIN CAPITAL LETTER E WITH GRAVE +00C9 ; mapped ; 00E9 # 1.1 LATIN CAPITAL LETTER E WITH ACUTE +00CA ; mapped ; 00EA # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB ; mapped ; 00EB # 1.1 LATIN CAPITAL LETTER E WITH DIAERESIS +00CC ; mapped ; 00EC # 1.1 LATIN CAPITAL LETTER I WITH GRAVE +00CD ; mapped ; 00ED # 1.1 LATIN CAPITAL LETTER I WITH ACUTE +00CE ; mapped ; 00EE # 1.1 LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF ; mapped ; 00EF # 1.1 LATIN CAPITAL LETTER I WITH DIAERESIS +00D0 ; mapped ; 00F0 # 1.1 LATIN CAPITAL LETTER ETH +00D1 ; mapped ; 00F1 # 1.1 LATIN CAPITAL LETTER N WITH TILDE +00D2 ; mapped ; 00F2 # 1.1 LATIN CAPITAL LETTER O WITH GRAVE +00D3 ; mapped ; 00F3 # 1.1 LATIN CAPITAL LETTER O WITH ACUTE +00D4 ; mapped ; 00F4 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5 ; mapped ; 00F5 # 1.1 LATIN CAPITAL LETTER O WITH TILDE +00D6 ; mapped ; 00F6 # 1.1 LATIN CAPITAL LETTER O WITH DIAERESIS +00D7 ; valid ; ; NV8 # 1.1 MULTIPLICATION SIGN +00D8 ; mapped ; 00F8 # 1.1 LATIN CAPITAL LETTER O WITH STROKE +00D9 ; mapped ; 00F9 # 1.1 LATIN CAPITAL LETTER U WITH GRAVE +00DA ; mapped ; 00FA # 1.1 LATIN CAPITAL LETTER U WITH ACUTE +00DB ; mapped ; 00FB # 1.1 LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC ; mapped ; 00FC # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS +00DD ; mapped ; 00FD # 1.1 LATIN CAPITAL LETTER Y WITH ACUTE +00DE ; mapped ; 00FE # 1.1 LATIN CAPITAL LETTER THORN +00DF ; deviation ; 0073 0073 # 1.1 LATIN SMALL LETTER SHARP S +00E0..00F6 ; valid # 1.1 LATIN SMALL LETTER A WITH GRAVE..LATIN SMALL LETTER O WITH DIAERESIS +00F7 ; valid ; ; NV8 # 1.1 DIVISION SIGN +00F8..00FF ; valid # 1.1 LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS +0100 ; mapped ; 0101 # 1.1 LATIN CAPITAL LETTER A WITH MACRON +0101 ; valid # 1.1 LATIN SMALL LETTER A WITH MACRON +0102 ; mapped ; 0103 # 1.1 LATIN CAPITAL LETTER A WITH BREVE +0103 ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE +0104 ; mapped ; 0105 # 1.1 LATIN CAPITAL LETTER A WITH OGONEK +0105 ; valid # 1.1 LATIN SMALL LETTER A WITH OGONEK +0106 ; mapped ; 0107 # 1.1 LATIN CAPITAL LETTER C WITH ACUTE +0107 ; valid # 1.1 LATIN SMALL LETTER C WITH ACUTE +0108 ; mapped ; 0109 # 1.1 LATIN CAPITAL LETTER C WITH CIRCUMFLEX +0109 ; valid # 1.1 LATIN SMALL LETTER C WITH CIRCUMFLEX +010A ; mapped ; 010B # 1.1 LATIN CAPITAL LETTER C WITH DOT ABOVE +010B ; valid # 1.1 LATIN SMALL LETTER C WITH DOT ABOVE +010C ; mapped ; 010D # 1.1 LATIN CAPITAL LETTER C WITH CARON +010D ; valid # 1.1 LATIN SMALL LETTER C WITH CARON +010E ; mapped ; 010F # 1.1 LATIN CAPITAL LETTER D WITH CARON +010F ; valid # 1.1 LATIN SMALL LETTER D WITH CARON +0110 ; mapped ; 0111 # 1.1 LATIN CAPITAL LETTER D WITH STROKE +0111 ; valid # 1.1 LATIN SMALL LETTER D WITH STROKE +0112 ; mapped ; 0113 # 1.1 LATIN CAPITAL LETTER E WITH MACRON +0113 ; valid # 1.1 LATIN SMALL LETTER E WITH MACRON +0114 ; mapped ; 0115 # 1.1 LATIN CAPITAL LETTER E WITH BREVE +0115 ; valid # 1.1 LATIN SMALL LETTER E WITH BREVE +0116 ; mapped ; 0117 # 1.1 LATIN CAPITAL LETTER E WITH DOT ABOVE +0117 ; valid # 1.1 LATIN SMALL LETTER E WITH DOT ABOVE +0118 ; mapped ; 0119 # 1.1 LATIN CAPITAL LETTER E WITH OGONEK +0119 ; valid # 1.1 LATIN SMALL LETTER E WITH OGONEK +011A ; mapped ; 011B # 1.1 LATIN CAPITAL LETTER E WITH CARON +011B ; valid # 1.1 LATIN SMALL LETTER E WITH CARON +011C ; mapped ; 011D # 1.1 LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011D ; valid # 1.1 LATIN SMALL LETTER G WITH CIRCUMFLEX +011E ; mapped ; 011F # 1.1 LATIN CAPITAL LETTER G WITH BREVE +011F ; valid # 1.1 LATIN SMALL LETTER G WITH BREVE +0120 ; mapped ; 0121 # 1.1 LATIN CAPITAL LETTER G WITH DOT ABOVE +0121 ; valid # 1.1 LATIN SMALL LETTER G WITH DOT ABOVE +0122 ; mapped ; 0123 # 1.1 LATIN CAPITAL LETTER G WITH CEDILLA +0123 ; valid # 1.1 LATIN SMALL LETTER G WITH CEDILLA +0124 ; mapped ; 0125 # 1.1 LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0125 ; valid # 1.1 LATIN SMALL LETTER H WITH CIRCUMFLEX +0126 ; mapped ; 0127 # 1.1 LATIN CAPITAL LETTER H WITH STROKE +0127 ; valid # 1.1 LATIN SMALL LETTER H WITH STROKE +0128 ; mapped ; 0129 # 1.1 LATIN CAPITAL LETTER I WITH TILDE +0129 ; valid # 1.1 LATIN SMALL LETTER I WITH TILDE +012A ; mapped ; 012B # 1.1 LATIN CAPITAL LETTER I WITH MACRON +012B ; valid # 1.1 LATIN SMALL LETTER I WITH MACRON +012C ; mapped ; 012D # 1.1 LATIN CAPITAL LETTER I WITH BREVE +012D ; valid # 1.1 LATIN SMALL LETTER I WITH BREVE +012E ; mapped ; 012F # 1.1 LATIN CAPITAL LETTER I WITH OGONEK +012F ; valid # 1.1 LATIN SMALL LETTER I WITH OGONEK +0130 ; mapped ; 0069 0307 # 1.1 LATIN CAPITAL LETTER I WITH DOT ABOVE +0131 ; valid # 1.1 LATIN SMALL LETTER DOTLESS I +0132..0133 ; mapped ; 0069 006A # 1.1 LATIN CAPITAL LIGATURE IJ..LATIN SMALL LIGATURE IJ +0134 ; mapped ; 0135 # 1.1 LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0135 ; valid # 1.1 LATIN SMALL LETTER J WITH CIRCUMFLEX +0136 ; mapped ; 0137 # 1.1 LATIN CAPITAL LETTER K WITH CEDILLA +0137..0138 ; valid # 1.1 LATIN SMALL LETTER K WITH CEDILLA..LATIN SMALL LETTER KRA +0139 ; mapped ; 013A # 1.1 LATIN CAPITAL LETTER L WITH ACUTE +013A ; valid # 1.1 LATIN SMALL LETTER L WITH ACUTE +013B ; mapped ; 013C # 1.1 LATIN CAPITAL LETTER L WITH CEDILLA +013C ; valid # 1.1 LATIN SMALL LETTER L WITH CEDILLA +013D ; mapped ; 013E # 1.1 LATIN CAPITAL LETTER L WITH CARON +013E ; valid # 1.1 LATIN SMALL LETTER L WITH CARON +013F..0140 ; mapped ; 006C 00B7 # 1.1 LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH MIDDLE DOT +0141 ; mapped ; 0142 # 1.1 LATIN CAPITAL LETTER L WITH STROKE +0142 ; valid # 1.1 LATIN SMALL LETTER L WITH STROKE +0143 ; mapped ; 0144 # 1.1 LATIN CAPITAL LETTER N WITH ACUTE +0144 ; valid # 1.1 LATIN SMALL LETTER N WITH ACUTE +0145 ; mapped ; 0146 # 1.1 LATIN CAPITAL LETTER N WITH CEDILLA +0146 ; valid # 1.1 LATIN SMALL LETTER N WITH CEDILLA +0147 ; mapped ; 0148 # 1.1 LATIN CAPITAL LETTER N WITH CARON +0148 ; valid # 1.1 LATIN SMALL LETTER N WITH CARON +0149 ; mapped ; 02BC 006E # 1.1 LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014A ; mapped ; 014B # 1.1 LATIN CAPITAL LETTER ENG +014B ; valid # 1.1 LATIN SMALL LETTER ENG +014C ; mapped ; 014D # 1.1 LATIN CAPITAL LETTER O WITH MACRON +014D ; valid # 1.1 LATIN SMALL LETTER O WITH MACRON +014E ; mapped ; 014F # 1.1 LATIN CAPITAL LETTER O WITH BREVE +014F ; valid # 1.1 LATIN SMALL LETTER O WITH BREVE +0150 ; mapped ; 0151 # 1.1 LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0151 ; valid # 1.1 LATIN SMALL LETTER O WITH DOUBLE ACUTE +0152 ; mapped ; 0153 # 1.1 LATIN CAPITAL LIGATURE OE +0153 ; valid # 1.1 LATIN SMALL LIGATURE OE +0154 ; mapped ; 0155 # 1.1 LATIN CAPITAL LETTER R WITH ACUTE +0155 ; valid # 1.1 LATIN SMALL LETTER R WITH ACUTE +0156 ; mapped ; 0157 # 1.1 LATIN CAPITAL LETTER R WITH CEDILLA +0157 ; valid # 1.1 LATIN SMALL LETTER R WITH CEDILLA +0158 ; mapped ; 0159 # 1.1 LATIN CAPITAL LETTER R WITH CARON +0159 ; valid # 1.1 LATIN SMALL LETTER R WITH CARON +015A ; mapped ; 015B # 1.1 LATIN CAPITAL LETTER S WITH ACUTE +015B ; valid # 1.1 LATIN SMALL LETTER S WITH ACUTE +015C ; mapped ; 015D # 1.1 LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015D ; valid # 1.1 LATIN SMALL LETTER S WITH CIRCUMFLEX +015E ; mapped ; 015F # 1.1 LATIN CAPITAL LETTER S WITH CEDILLA +015F ; valid # 1.1 LATIN SMALL LETTER S WITH CEDILLA +0160 ; mapped ; 0161 # 1.1 LATIN CAPITAL LETTER S WITH CARON +0161 ; valid # 1.1 LATIN SMALL LETTER S WITH CARON +0162 ; mapped ; 0163 # 1.1 LATIN CAPITAL LETTER T WITH CEDILLA +0163 ; valid # 1.1 LATIN SMALL LETTER T WITH CEDILLA +0164 ; mapped ; 0165 # 1.1 LATIN CAPITAL LETTER T WITH CARON +0165 ; valid # 1.1 LATIN SMALL LETTER T WITH CARON +0166 ; mapped ; 0167 # 1.1 LATIN CAPITAL LETTER T WITH STROKE +0167 ; valid # 1.1 LATIN SMALL LETTER T WITH STROKE +0168 ; mapped ; 0169 # 1.1 LATIN CAPITAL LETTER U WITH TILDE +0169 ; valid # 1.1 LATIN SMALL LETTER U WITH TILDE +016A ; mapped ; 016B # 1.1 LATIN CAPITAL LETTER U WITH MACRON +016B ; valid # 1.1 LATIN SMALL LETTER U WITH MACRON +016C ; mapped ; 016D # 1.1 LATIN CAPITAL LETTER U WITH BREVE +016D ; valid # 1.1 LATIN SMALL LETTER U WITH BREVE +016E ; mapped ; 016F # 1.1 LATIN CAPITAL LETTER U WITH RING ABOVE +016F ; valid # 1.1 LATIN SMALL LETTER U WITH RING ABOVE +0170 ; mapped ; 0171 # 1.1 LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0171 ; valid # 1.1 LATIN SMALL LETTER U WITH DOUBLE ACUTE +0172 ; mapped ; 0173 # 1.1 LATIN CAPITAL LETTER U WITH OGONEK +0173 ; valid # 1.1 LATIN SMALL LETTER U WITH OGONEK +0174 ; mapped ; 0175 # 1.1 LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0175 ; valid # 1.1 LATIN SMALL LETTER W WITH CIRCUMFLEX +0176 ; mapped ; 0177 # 1.1 LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0177 ; valid # 1.1 LATIN SMALL LETTER Y WITH CIRCUMFLEX +0178 ; mapped ; 00FF # 1.1 LATIN CAPITAL LETTER Y WITH DIAERESIS +0179 ; mapped ; 017A # 1.1 LATIN CAPITAL LETTER Z WITH ACUTE +017A ; valid # 1.1 LATIN SMALL LETTER Z WITH ACUTE +017B ; mapped ; 017C # 1.1 LATIN CAPITAL LETTER Z WITH DOT ABOVE +017C ; valid # 1.1 LATIN SMALL LETTER Z WITH DOT ABOVE +017D ; mapped ; 017E # 1.1 LATIN CAPITAL LETTER Z WITH CARON +017E ; valid # 1.1 LATIN SMALL LETTER Z WITH CARON +017F ; mapped ; 0073 # 1.1 LATIN SMALL LETTER LONG S +0180 ; valid # 1.1 LATIN SMALL LETTER B WITH STROKE +0181 ; mapped ; 0253 # 1.1 LATIN CAPITAL LETTER B WITH HOOK +0182 ; mapped ; 0183 # 1.1 LATIN CAPITAL LETTER B WITH TOPBAR +0183 ; valid # 1.1 LATIN SMALL LETTER B WITH TOPBAR +0184 ; mapped ; 0185 # 1.1 LATIN CAPITAL LETTER TONE SIX +0185 ; valid # 1.1 LATIN SMALL LETTER TONE SIX +0186 ; mapped ; 0254 # 1.1 LATIN CAPITAL LETTER OPEN O +0187 ; mapped ; 0188 # 1.1 LATIN CAPITAL LETTER C WITH HOOK +0188 ; valid # 1.1 LATIN SMALL LETTER C WITH HOOK +0189 ; mapped ; 0256 # 1.1 LATIN CAPITAL LETTER AFRICAN D +018A ; mapped ; 0257 # 1.1 LATIN CAPITAL LETTER D WITH HOOK +018B ; mapped ; 018C # 1.1 LATIN CAPITAL LETTER D WITH TOPBAR +018C..018D ; valid # 1.1 LATIN SMALL LETTER D WITH TOPBAR..LATIN SMALL LETTER TURNED DELTA +018E ; mapped ; 01DD # 1.1 LATIN CAPITAL LETTER REVERSED E +018F ; mapped ; 0259 # 1.1 LATIN CAPITAL LETTER SCHWA +0190 ; mapped ; 025B # 1.1 LATIN CAPITAL LETTER OPEN E +0191 ; mapped ; 0192 # 1.1 LATIN CAPITAL LETTER F WITH HOOK +0192 ; valid # 1.1 LATIN SMALL LETTER F WITH HOOK +0193 ; mapped ; 0260 # 1.1 LATIN CAPITAL LETTER G WITH HOOK +0194 ; mapped ; 0263 # 1.1 LATIN CAPITAL LETTER GAMMA +0195 ; valid # 1.1 LATIN SMALL LETTER HV +0196 ; mapped ; 0269 # 1.1 LATIN CAPITAL LETTER IOTA +0197 ; mapped ; 0268 # 1.1 LATIN CAPITAL LETTER I WITH STROKE +0198 ; mapped ; 0199 # 1.1 LATIN CAPITAL LETTER K WITH HOOK +0199..019B ; valid # 1.1 LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE +019C ; mapped ; 026F # 1.1 LATIN CAPITAL LETTER TURNED M +019D ; mapped ; 0272 # 1.1 LATIN CAPITAL LETTER N WITH LEFT HOOK +019E ; valid # 1.1 LATIN SMALL LETTER N WITH LONG RIGHT LEG +019F ; mapped ; 0275 # 1.1 LATIN CAPITAL LETTER O WITH MIDDLE TILDE +01A0 ; mapped ; 01A1 # 1.1 LATIN CAPITAL LETTER O WITH HORN +01A1 ; valid # 1.1 LATIN SMALL LETTER O WITH HORN +01A2 ; mapped ; 01A3 # 1.1 LATIN CAPITAL LETTER OI +01A3 ; valid # 1.1 LATIN SMALL LETTER OI +01A4 ; mapped ; 01A5 # 1.1 LATIN CAPITAL LETTER P WITH HOOK +01A5 ; valid # 1.1 LATIN SMALL LETTER P WITH HOOK +01A6 ; mapped ; 0280 # 1.1 LATIN LETTER YR +01A7 ; mapped ; 01A8 # 1.1 LATIN CAPITAL LETTER TONE TWO +01A8 ; valid # 1.1 LATIN SMALL LETTER TONE TWO +01A9 ; mapped ; 0283 # 1.1 LATIN CAPITAL LETTER ESH +01AA..01AB ; valid # 1.1 LATIN LETTER REVERSED ESH LOOP..LATIN SMALL LETTER T WITH PALATAL HOOK +01AC ; mapped ; 01AD # 1.1 LATIN CAPITAL LETTER T WITH HOOK +01AD ; valid # 1.1 LATIN SMALL LETTER T WITH HOOK +01AE ; mapped ; 0288 # 1.1 LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +01AF ; mapped ; 01B0 # 1.1 LATIN CAPITAL LETTER U WITH HORN +01B0 ; valid # 1.1 LATIN SMALL LETTER U WITH HORN +01B1 ; mapped ; 028A # 1.1 LATIN CAPITAL LETTER UPSILON +01B2 ; mapped ; 028B # 1.1 LATIN CAPITAL LETTER V WITH HOOK +01B3 ; mapped ; 01B4 # 1.1 LATIN CAPITAL LETTER Y WITH HOOK +01B4 ; valid # 1.1 LATIN SMALL LETTER Y WITH HOOK +01B5 ; mapped ; 01B6 # 1.1 LATIN CAPITAL LETTER Z WITH STROKE +01B6 ; valid # 1.1 LATIN SMALL LETTER Z WITH STROKE +01B7 ; mapped ; 0292 # 1.1 LATIN CAPITAL LETTER EZH +01B8 ; mapped ; 01B9 # 1.1 LATIN CAPITAL LETTER EZH REVERSED +01B9..01BB ; valid # 1.1 LATIN SMALL LETTER EZH REVERSED..LATIN LETTER TWO WITH STROKE +01BC ; mapped ; 01BD # 1.1 LATIN CAPITAL LETTER TONE FIVE +01BD..01C3 ; valid # 1.1 LATIN SMALL LETTER TONE FIVE..LATIN LETTER RETROFLEX CLICK +01C4..01C6 ; mapped ; 0064 017E # 1.1 LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER DZ WITH CARON +01C7..01C9 ; mapped ; 006C 006A # 1.1 LATIN CAPITAL LETTER LJ..LATIN SMALL LETTER LJ +01CA..01CC ; mapped ; 006E 006A # 1.1 LATIN CAPITAL LETTER NJ..LATIN SMALL LETTER NJ +01CD ; mapped ; 01CE # 1.1 LATIN CAPITAL LETTER A WITH CARON +01CE ; valid # 1.1 LATIN SMALL LETTER A WITH CARON +01CF ; mapped ; 01D0 # 1.1 LATIN CAPITAL LETTER I WITH CARON +01D0 ; valid # 1.1 LATIN SMALL LETTER I WITH CARON +01D1 ; mapped ; 01D2 # 1.1 LATIN CAPITAL LETTER O WITH CARON +01D2 ; valid # 1.1 LATIN SMALL LETTER O WITH CARON +01D3 ; mapped ; 01D4 # 1.1 LATIN CAPITAL LETTER U WITH CARON +01D4 ; valid # 1.1 LATIN SMALL LETTER U WITH CARON +01D5 ; mapped ; 01D6 # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D6 ; valid # 1.1 LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D7 ; mapped ; 01D8 # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D8 ; valid # 1.1 LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01D9 ; mapped ; 01DA # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DA ; valid # 1.1 LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DB ; mapped ; 01DC # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DC..01DD ; valid # 1.1 LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E +01DE ; mapped ; 01DF # 1.1 LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01DF ; valid # 1.1 LATIN SMALL LETTER A WITH DIAERESIS AND MACRON +01E0 ; mapped ; 01E1 # 1.1 LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E1 ; valid # 1.1 LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON +01E2 ; mapped ; 01E3 # 1.1 LATIN CAPITAL LETTER AE WITH MACRON +01E3 ; valid # 1.1 LATIN SMALL LETTER AE WITH MACRON +01E4 ; mapped ; 01E5 # 1.1 LATIN CAPITAL LETTER G WITH STROKE +01E5 ; valid # 1.1 LATIN SMALL LETTER G WITH STROKE +01E6 ; mapped ; 01E7 # 1.1 LATIN CAPITAL LETTER G WITH CARON +01E7 ; valid # 1.1 LATIN SMALL LETTER G WITH CARON +01E8 ; mapped ; 01E9 # 1.1 LATIN CAPITAL LETTER K WITH CARON +01E9 ; valid # 1.1 LATIN SMALL LETTER K WITH CARON +01EA ; mapped ; 01EB # 1.1 LATIN CAPITAL LETTER O WITH OGONEK +01EB ; valid # 1.1 LATIN SMALL LETTER O WITH OGONEK +01EC ; mapped ; 01ED # 1.1 LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01ED ; valid # 1.1 LATIN SMALL LETTER O WITH OGONEK AND MACRON +01EE ; mapped ; 01EF # 1.1 LATIN CAPITAL LETTER EZH WITH CARON +01EF..01F0 ; valid # 1.1 LATIN SMALL LETTER EZH WITH CARON..LATIN SMALL LETTER J WITH CARON +01F1..01F3 ; mapped ; 0064 007A # 1.1 LATIN CAPITAL LETTER DZ..LATIN SMALL LETTER DZ +01F4 ; mapped ; 01F5 # 1.1 LATIN CAPITAL LETTER G WITH ACUTE +01F5 ; valid # 1.1 LATIN SMALL LETTER G WITH ACUTE +01F6 ; mapped ; 0195 # 3.0 LATIN CAPITAL LETTER HWAIR +01F7 ; mapped ; 01BF # 3.0 LATIN CAPITAL LETTER WYNN +01F8 ; mapped ; 01F9 # 3.0 LATIN CAPITAL LETTER N WITH GRAVE +01F9 ; valid # 3.0 LATIN SMALL LETTER N WITH GRAVE +01FA ; mapped ; 01FB # 1.1 LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FB ; valid # 1.1 LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +01FC ; mapped ; 01FD # 1.1 LATIN CAPITAL LETTER AE WITH ACUTE +01FD ; valid # 1.1 LATIN SMALL LETTER AE WITH ACUTE +01FE ; mapped ; 01FF # 1.1 LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +01FF ; valid # 1.1 LATIN SMALL LETTER O WITH STROKE AND ACUTE +0200 ; mapped ; 0201 # 1.1 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0201 ; valid # 1.1 LATIN SMALL LETTER A WITH DOUBLE GRAVE +0202 ; mapped ; 0203 # 1.1 LATIN CAPITAL LETTER A WITH INVERTED BREVE +0203 ; valid # 1.1 LATIN SMALL LETTER A WITH INVERTED BREVE +0204 ; mapped ; 0205 # 1.1 LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0205 ; valid # 1.1 LATIN SMALL LETTER E WITH DOUBLE GRAVE +0206 ; mapped ; 0207 # 1.1 LATIN CAPITAL LETTER E WITH INVERTED BREVE +0207 ; valid # 1.1 LATIN SMALL LETTER E WITH INVERTED BREVE +0208 ; mapped ; 0209 # 1.1 LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +0209 ; valid # 1.1 LATIN SMALL LETTER I WITH DOUBLE GRAVE +020A ; mapped ; 020B # 1.1 LATIN CAPITAL LETTER I WITH INVERTED BREVE +020B ; valid # 1.1 LATIN SMALL LETTER I WITH INVERTED BREVE +020C ; mapped ; 020D # 1.1 LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020D ; valid # 1.1 LATIN SMALL LETTER O WITH DOUBLE GRAVE +020E ; mapped ; 020F # 1.1 LATIN CAPITAL LETTER O WITH INVERTED BREVE +020F ; valid # 1.1 LATIN SMALL LETTER O WITH INVERTED BREVE +0210 ; mapped ; 0211 # 1.1 LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0211 ; valid # 1.1 LATIN SMALL LETTER R WITH DOUBLE GRAVE +0212 ; mapped ; 0213 # 1.1 LATIN CAPITAL LETTER R WITH INVERTED BREVE +0213 ; valid # 1.1 LATIN SMALL LETTER R WITH INVERTED BREVE +0214 ; mapped ; 0215 # 1.1 LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0215 ; valid # 1.1 LATIN SMALL LETTER U WITH DOUBLE GRAVE +0216 ; mapped ; 0217 # 1.1 LATIN CAPITAL LETTER U WITH INVERTED BREVE +0217 ; valid # 1.1 LATIN SMALL LETTER U WITH INVERTED BREVE +0218 ; mapped ; 0219 # 3.0 LATIN CAPITAL LETTER S WITH COMMA BELOW +0219 ; valid # 3.0 LATIN SMALL LETTER S WITH COMMA BELOW +021A ; mapped ; 021B # 3.0 LATIN CAPITAL LETTER T WITH COMMA BELOW +021B ; valid # 3.0 LATIN SMALL LETTER T WITH COMMA BELOW +021C ; mapped ; 021D # 3.0 LATIN CAPITAL LETTER YOGH +021D ; valid # 3.0 LATIN SMALL LETTER YOGH +021E ; mapped ; 021F # 3.0 LATIN CAPITAL LETTER H WITH CARON +021F ; valid # 3.0 LATIN SMALL LETTER H WITH CARON +0220 ; mapped ; 019E # 3.2 LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +0221 ; valid # 4.0 LATIN SMALL LETTER D WITH CURL +0222 ; mapped ; 0223 # 3.0 LATIN CAPITAL LETTER OU +0223 ; valid # 3.0 LATIN SMALL LETTER OU +0224 ; mapped ; 0225 # 3.0 LATIN CAPITAL LETTER Z WITH HOOK +0225 ; valid # 3.0 LATIN SMALL LETTER Z WITH HOOK +0226 ; mapped ; 0227 # 3.0 LATIN CAPITAL LETTER A WITH DOT ABOVE +0227 ; valid # 3.0 LATIN SMALL LETTER A WITH DOT ABOVE +0228 ; mapped ; 0229 # 3.0 LATIN CAPITAL LETTER E WITH CEDILLA +0229 ; valid # 3.0 LATIN SMALL LETTER E WITH CEDILLA +022A ; mapped ; 022B # 3.0 LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022B ; valid # 3.0 LATIN SMALL LETTER O WITH DIAERESIS AND MACRON +022C ; mapped ; 022D # 3.0 LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022D ; valid # 3.0 LATIN SMALL LETTER O WITH TILDE AND MACRON +022E ; mapped ; 022F # 3.0 LATIN CAPITAL LETTER O WITH DOT ABOVE +022F ; valid # 3.0 LATIN SMALL LETTER O WITH DOT ABOVE +0230 ; mapped ; 0231 # 3.0 LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0231 ; valid # 3.0 LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON +0232 ; mapped ; 0233 # 3.0 LATIN CAPITAL LETTER Y WITH MACRON +0233 ; valid # 3.0 LATIN SMALL LETTER Y WITH MACRON +0234..0236 ; valid # 4.0 LATIN SMALL LETTER L WITH CURL..LATIN SMALL LETTER T WITH CURL +0237..0239 ; valid # 4.1 LATIN SMALL LETTER DOTLESS J..LATIN SMALL LETTER QP DIGRAPH +023A ; mapped ; 2C65 # 4.1 LATIN CAPITAL LETTER A WITH STROKE +023B ; mapped ; 023C # 4.1 LATIN CAPITAL LETTER C WITH STROKE +023C ; valid # 4.1 LATIN SMALL LETTER C WITH STROKE +023D ; mapped ; 019A # 4.1 LATIN CAPITAL LETTER L WITH BAR +023E ; mapped ; 2C66 # 4.1 LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +023F..0240 ; valid # 4.1 LATIN SMALL LETTER S WITH SWASH TAIL..LATIN SMALL LETTER Z WITH SWASH TAIL +0241 ; mapped ; 0242 # 4.1 LATIN CAPITAL LETTER GLOTTAL STOP +0242 ; valid # 5.0 LATIN SMALL LETTER GLOTTAL STOP +0243 ; mapped ; 0180 # 5.0 LATIN CAPITAL LETTER B WITH STROKE +0244 ; mapped ; 0289 # 5.0 LATIN CAPITAL LETTER U BAR +0245 ; mapped ; 028C # 5.0 LATIN CAPITAL LETTER TURNED V +0246 ; mapped ; 0247 # 5.0 LATIN CAPITAL LETTER E WITH STROKE +0247 ; valid # 5.0 LATIN SMALL LETTER E WITH STROKE +0248 ; mapped ; 0249 # 5.0 LATIN CAPITAL LETTER J WITH STROKE +0249 ; valid # 5.0 LATIN SMALL LETTER J WITH STROKE +024A ; mapped ; 024B # 5.0 LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +024B ; valid # 5.0 LATIN SMALL LETTER Q WITH HOOK TAIL +024C ; mapped ; 024D # 5.0 LATIN CAPITAL LETTER R WITH STROKE +024D ; valid # 5.0 LATIN SMALL LETTER R WITH STROKE +024E ; mapped ; 024F # 5.0 LATIN CAPITAL LETTER Y WITH STROKE +024F ; valid # 5.0 LATIN SMALL LETTER Y WITH STROKE +0250..02A8 ; valid # 1.1 LATIN SMALL LETTER TURNED A..LATIN SMALL LETTER TC DIGRAPH WITH CURL +02A9..02AD ; valid # 3.0 LATIN SMALL LETTER FENG DIGRAPH..LATIN LETTER BIDENTAL PERCUSSIVE +02AE..02AF ; valid # 4.0 LATIN SMALL LETTER TURNED H WITH FISHHOOK..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +02B0 ; mapped ; 0068 # 1.1 MODIFIER LETTER SMALL H +02B1 ; mapped ; 0266 # 1.1 MODIFIER LETTER SMALL H WITH HOOK +02B2 ; mapped ; 006A # 1.1 MODIFIER LETTER SMALL J +02B3 ; mapped ; 0072 # 1.1 MODIFIER LETTER SMALL R +02B4 ; mapped ; 0279 # 1.1 MODIFIER LETTER SMALL TURNED R +02B5 ; mapped ; 027B # 1.1 MODIFIER LETTER SMALL TURNED R WITH HOOK +02B6 ; mapped ; 0281 # 1.1 MODIFIER LETTER SMALL CAPITAL INVERTED R +02B7 ; mapped ; 0077 # 1.1 MODIFIER LETTER SMALL W +02B8 ; mapped ; 0079 # 1.1 MODIFIER LETTER SMALL Y +02B9..02C1 ; valid # 1.1 MODIFIER LETTER PRIME..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C5 ; valid ; ; NV8 # 1.1 MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD +02C6..02D1 ; valid # 1.1 MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7 ; valid ; ; NV8 # 1.1 MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02D8 ; disallowed_STD3_mapped ; 0020 0306 # 1.1 BREVE +02D9 ; disallowed_STD3_mapped ; 0020 0307 # 1.1 DOT ABOVE +02DA ; disallowed_STD3_mapped ; 0020 030A # 1.1 RING ABOVE +02DB ; disallowed_STD3_mapped ; 0020 0328 # 1.1 OGONEK +02DC ; disallowed_STD3_mapped ; 0020 0303 # 1.1 SMALL TILDE +02DD ; disallowed_STD3_mapped ; 0020 030B # 1.1 DOUBLE ACUTE ACCENT +02DE ; valid ; ; NV8 # 1.1 MODIFIER LETTER RHOTIC HOOK +02DF ; valid ; ; NV8 # 3.0 MODIFIER LETTER CROSS ACCENT +02E0 ; mapped ; 0263 # 1.1 MODIFIER LETTER SMALL GAMMA +02E1 ; mapped ; 006C # 1.1 MODIFIER LETTER SMALL L +02E2 ; mapped ; 0073 # 1.1 MODIFIER LETTER SMALL S +02E3 ; mapped ; 0078 # 1.1 MODIFIER LETTER SMALL X +02E4 ; mapped ; 0295 # 1.1 MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02E9 ; valid ; ; NV8 # 1.1 MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER EXTRA-LOW TONE BAR +02EA..02EB ; valid ; ; NV8 # 3.0 MODIFIER LETTER YIN DEPARTING TONE MARK..MODIFIER LETTER YANG DEPARTING TONE MARK +02EC ; valid # 3.0 MODIFIER LETTER VOICING +02ED ; valid ; ; NV8 # 3.0 MODIFIER LETTER UNASPIRATED +02EE ; valid # 3.0 MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF ; valid ; ; NV8 # 4.0 MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW +0300..033F ; valid # 1.1 COMBINING GRAVE ACCENT..COMBINING DOUBLE OVERLINE +0340 ; mapped ; 0300 # 1.1 COMBINING GRAVE TONE MARK +0341 ; mapped ; 0301 # 1.1 COMBINING ACUTE TONE MARK +0342 ; valid # 1.1 COMBINING GREEK PERISPOMENI +0343 ; mapped ; 0313 # 1.1 COMBINING GREEK KORONIS +0344 ; mapped ; 0308 0301 # 1.1 COMBINING GREEK DIALYTIKA TONOS +0345 ; mapped ; 03B9 # 1.1 COMBINING GREEK YPOGEGRAMMENI +0346..034E ; valid # 3.0 COMBINING BRIDGE ABOVE..COMBINING UPWARDS ARROW BELOW +034F ; ignored # 3.2 COMBINING GRAPHEME JOINER +0350..0357 ; valid # 4.0 COMBINING RIGHT ARROWHEAD ABOVE..COMBINING RIGHT HALF RING ABOVE +0358..035C ; valid # 4.1 COMBINING DOT ABOVE RIGHT..COMBINING DOUBLE BREVE BELOW +035D..035F ; valid # 4.0 COMBINING DOUBLE BREVE..COMBINING DOUBLE MACRON BELOW +0360..0361 ; valid # 1.1 COMBINING DOUBLE TILDE..COMBINING DOUBLE INVERTED BREVE +0362 ; valid # 3.0 COMBINING DOUBLE RIGHTWARDS ARROW BELOW +0363..036F ; valid # 3.2 COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X +0370 ; mapped ; 0371 # 5.1 GREEK CAPITAL LETTER HETA +0371 ; valid # 5.1 GREEK SMALL LETTER HETA +0372 ; mapped ; 0373 # 5.1 GREEK CAPITAL LETTER ARCHAIC SAMPI +0373 ; valid # 5.1 GREEK SMALL LETTER ARCHAIC SAMPI +0374 ; mapped ; 02B9 # 1.1 GREEK NUMERAL SIGN +0375 ; valid # 1.1 GREEK LOWER NUMERAL SIGN +0376 ; mapped ; 0377 # 5.1 GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA +0377 ; valid # 5.1 GREEK SMALL LETTER PAMPHYLIAN DIGAMMA +0378..0379 ; disallowed # NA .. +037A ; disallowed_STD3_mapped ; 0020 03B9 # 1.1 GREEK YPOGEGRAMMENI +037B..037D ; valid # 5.0 GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +037E ; disallowed_STD3_mapped ; 003B # 1.1 GREEK QUESTION MARK +037F ; mapped ; 03F3 # 7.0 GREEK CAPITAL LETTER YOT +0380..0383 ; disallowed # NA .. +0384 ; disallowed_STD3_mapped ; 0020 0301 # 1.1 GREEK TONOS +0385 ; disallowed_STD3_mapped ; 0020 0308 0301 #1.1 GREEK DIALYTIKA TONOS +0386 ; mapped ; 03AC # 1.1 GREEK CAPITAL LETTER ALPHA WITH TONOS +0387 ; mapped ; 00B7 # 1.1 GREEK ANO TELEIA +0388 ; mapped ; 03AD # 1.1 GREEK CAPITAL LETTER EPSILON WITH TONOS +0389 ; mapped ; 03AE # 1.1 GREEK CAPITAL LETTER ETA WITH TONOS +038A ; mapped ; 03AF # 1.1 GREEK CAPITAL LETTER IOTA WITH TONOS +038B ; disallowed # NA +038C ; mapped ; 03CC # 1.1 GREEK CAPITAL LETTER OMICRON WITH TONOS +038D ; disallowed # NA +038E ; mapped ; 03CD # 1.1 GREEK CAPITAL LETTER UPSILON WITH TONOS +038F ; mapped ; 03CE # 1.1 GREEK CAPITAL LETTER OMEGA WITH TONOS +0390 ; valid # 1.1 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0391 ; mapped ; 03B1 # 1.1 GREEK CAPITAL LETTER ALPHA +0392 ; mapped ; 03B2 # 1.1 GREEK CAPITAL LETTER BETA +0393 ; mapped ; 03B3 # 1.1 GREEK CAPITAL LETTER GAMMA +0394 ; mapped ; 03B4 # 1.1 GREEK CAPITAL LETTER DELTA +0395 ; mapped ; 03B5 # 1.1 GREEK CAPITAL LETTER EPSILON +0396 ; mapped ; 03B6 # 1.1 GREEK CAPITAL LETTER ZETA +0397 ; mapped ; 03B7 # 1.1 GREEK CAPITAL LETTER ETA +0398 ; mapped ; 03B8 # 1.1 GREEK CAPITAL LETTER THETA +0399 ; mapped ; 03B9 # 1.1 GREEK CAPITAL LETTER IOTA +039A ; mapped ; 03BA # 1.1 GREEK CAPITAL LETTER KAPPA +039B ; mapped ; 03BB # 1.1 GREEK CAPITAL LETTER LAMDA +039C ; mapped ; 03BC # 1.1 GREEK CAPITAL LETTER MU +039D ; mapped ; 03BD # 1.1 GREEK CAPITAL LETTER NU +039E ; mapped ; 03BE # 1.1 GREEK CAPITAL LETTER XI +039F ; mapped ; 03BF # 1.1 GREEK CAPITAL LETTER OMICRON +03A0 ; mapped ; 03C0 # 1.1 GREEK CAPITAL LETTER PI +03A1 ; mapped ; 03C1 # 1.1 GREEK CAPITAL LETTER RHO +03A2 ; disallowed # NA +03A3 ; mapped ; 03C3 # 1.1 GREEK CAPITAL LETTER SIGMA +03A4 ; mapped ; 03C4 # 1.1 GREEK CAPITAL LETTER TAU +03A5 ; mapped ; 03C5 # 1.1 GREEK CAPITAL LETTER UPSILON +03A6 ; mapped ; 03C6 # 1.1 GREEK CAPITAL LETTER PHI +03A7 ; mapped ; 03C7 # 1.1 GREEK CAPITAL LETTER CHI +03A8 ; mapped ; 03C8 # 1.1 GREEK CAPITAL LETTER PSI +03A9 ; mapped ; 03C9 # 1.1 GREEK CAPITAL LETTER OMEGA +03AA ; mapped ; 03CA # 1.1 GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB ; mapped ; 03CB # 1.1 GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03AC..03C1 ; valid # 1.1 GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER RHO +03C2 ; deviation ; 03C3 # 1.1 GREEK SMALL LETTER FINAL SIGMA +03C3..03CE ; valid # 1.1 GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA WITH TONOS +03CF ; mapped ; 03D7 # 5.1 GREEK CAPITAL KAI SYMBOL +03D0 ; mapped ; 03B2 # 1.1 GREEK BETA SYMBOL +03D1 ; mapped ; 03B8 # 1.1 GREEK THETA SYMBOL +03D2 ; mapped ; 03C5 # 1.1 GREEK UPSILON WITH HOOK SYMBOL +03D3 ; mapped ; 03CD # 1.1 GREEK UPSILON WITH ACUTE AND HOOK SYMBOL +03D4 ; mapped ; 03CB # 1.1 GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL +03D5 ; mapped ; 03C6 # 1.1 GREEK PHI SYMBOL +03D6 ; mapped ; 03C0 # 1.1 GREEK PI SYMBOL +03D7 ; valid # 3.0 GREEK KAI SYMBOL +03D8 ; mapped ; 03D9 # 3.2 GREEK LETTER ARCHAIC KOPPA +03D9 ; valid # 3.2 GREEK SMALL LETTER ARCHAIC KOPPA +03DA ; mapped ; 03DB # 1.1 GREEK LETTER STIGMA +03DB ; valid # 3.0 GREEK SMALL LETTER STIGMA +03DC ; mapped ; 03DD # 1.1 GREEK LETTER DIGAMMA +03DD ; valid # 3.0 GREEK SMALL LETTER DIGAMMA +03DE ; mapped ; 03DF # 1.1 GREEK LETTER KOPPA +03DF ; valid # 3.0 GREEK SMALL LETTER KOPPA +03E0 ; mapped ; 03E1 # 1.1 GREEK LETTER SAMPI +03E1 ; valid # 3.0 GREEK SMALL LETTER SAMPI +03E2 ; mapped ; 03E3 # 1.1 COPTIC CAPITAL LETTER SHEI +03E3 ; valid # 1.1 COPTIC SMALL LETTER SHEI +03E4 ; mapped ; 03E5 # 1.1 COPTIC CAPITAL LETTER FEI +03E5 ; valid # 1.1 COPTIC SMALL LETTER FEI +03E6 ; mapped ; 03E7 # 1.1 COPTIC CAPITAL LETTER KHEI +03E7 ; valid # 1.1 COPTIC SMALL LETTER KHEI +03E8 ; mapped ; 03E9 # 1.1 COPTIC CAPITAL LETTER HORI +03E9 ; valid # 1.1 COPTIC SMALL LETTER HORI +03EA ; mapped ; 03EB # 1.1 COPTIC CAPITAL LETTER GANGIA +03EB ; valid # 1.1 COPTIC SMALL LETTER GANGIA +03EC ; mapped ; 03ED # 1.1 COPTIC CAPITAL LETTER SHIMA +03ED ; valid # 1.1 COPTIC SMALL LETTER SHIMA +03EE ; mapped ; 03EF # 1.1 COPTIC CAPITAL LETTER DEI +03EF ; valid # 1.1 COPTIC SMALL LETTER DEI +03F0 ; mapped ; 03BA # 1.1 GREEK KAPPA SYMBOL +03F1 ; mapped ; 03C1 # 1.1 GREEK RHO SYMBOL +03F2 ; mapped ; 03C3 # 1.1 GREEK LUNATE SIGMA SYMBOL +03F3 ; valid # 1.1 GREEK LETTER YOT +03F4 ; mapped ; 03B8 # 3.1 GREEK CAPITAL THETA SYMBOL +03F5 ; mapped ; 03B5 # 3.1 GREEK LUNATE EPSILON SYMBOL +03F6 ; valid ; ; NV8 # 3.2 GREEK REVERSED LUNATE EPSILON SYMBOL +03F7 ; mapped ; 03F8 # 4.0 GREEK CAPITAL LETTER SHO +03F8 ; valid # 4.0 GREEK SMALL LETTER SHO +03F9 ; mapped ; 03C3 # 4.0 GREEK CAPITAL LUNATE SIGMA SYMBOL +03FA ; mapped ; 03FB # 4.0 GREEK CAPITAL LETTER SAN +03FB ; valid # 4.0 GREEK SMALL LETTER SAN +03FC ; valid # 4.1 GREEK RHO WITH STROKE SYMBOL +03FD ; mapped ; 037B # 4.1 GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +03FE ; mapped ; 037C # 4.1 GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +03FF ; mapped ; 037D # 4.1 GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400 ; mapped ; 0450 # 3.0 CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401 ; mapped ; 0451 # 1.1 CYRILLIC CAPITAL LETTER IO +0402 ; mapped ; 0452 # 1.1 CYRILLIC CAPITAL LETTER DJE +0403 ; mapped ; 0453 # 1.1 CYRILLIC CAPITAL LETTER GJE +0404 ; mapped ; 0454 # 1.1 CYRILLIC CAPITAL LETTER UKRAINIAN IE +0405 ; mapped ; 0455 # 1.1 CYRILLIC CAPITAL LETTER DZE +0406 ; mapped ; 0456 # 1.1 CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0407 ; mapped ; 0457 # 1.1 CYRILLIC CAPITAL LETTER YI +0408 ; mapped ; 0458 # 1.1 CYRILLIC CAPITAL LETTER JE +0409 ; mapped ; 0459 # 1.1 CYRILLIC CAPITAL LETTER LJE +040A ; mapped ; 045A # 1.1 CYRILLIC CAPITAL LETTER NJE +040B ; mapped ; 045B # 1.1 CYRILLIC CAPITAL LETTER TSHE +040C ; mapped ; 045C # 1.1 CYRILLIC CAPITAL LETTER KJE +040D ; mapped ; 045D # 3.0 CYRILLIC CAPITAL LETTER I WITH GRAVE +040E ; mapped ; 045E # 1.1 CYRILLIC CAPITAL LETTER SHORT U +040F ; mapped ; 045F # 1.1 CYRILLIC CAPITAL LETTER DZHE +0410 ; mapped ; 0430 # 1.1 CYRILLIC CAPITAL LETTER A +0411 ; mapped ; 0431 # 1.1 CYRILLIC CAPITAL LETTER BE +0412 ; mapped ; 0432 # 1.1 CYRILLIC CAPITAL LETTER VE +0413 ; mapped ; 0433 # 1.1 CYRILLIC CAPITAL LETTER GHE +0414 ; mapped ; 0434 # 1.1 CYRILLIC CAPITAL LETTER DE +0415 ; mapped ; 0435 # 1.1 CYRILLIC CAPITAL LETTER IE +0416 ; mapped ; 0436 # 1.1 CYRILLIC CAPITAL LETTER ZHE +0417 ; mapped ; 0437 # 1.1 CYRILLIC CAPITAL LETTER ZE +0418 ; mapped ; 0438 # 1.1 CYRILLIC CAPITAL LETTER I +0419 ; mapped ; 0439 # 1.1 CYRILLIC CAPITAL LETTER SHORT I +041A ; mapped ; 043A # 1.1 CYRILLIC CAPITAL LETTER KA +041B ; mapped ; 043B # 1.1 CYRILLIC CAPITAL LETTER EL +041C ; mapped ; 043C # 1.1 CYRILLIC CAPITAL LETTER EM +041D ; mapped ; 043D # 1.1 CYRILLIC CAPITAL LETTER EN +041E ; mapped ; 043E # 1.1 CYRILLIC CAPITAL LETTER O +041F ; mapped ; 043F # 1.1 CYRILLIC CAPITAL LETTER PE +0420 ; mapped ; 0440 # 1.1 CYRILLIC CAPITAL LETTER ER +0421 ; mapped ; 0441 # 1.1 CYRILLIC CAPITAL LETTER ES +0422 ; mapped ; 0442 # 1.1 CYRILLIC CAPITAL LETTER TE +0423 ; mapped ; 0443 # 1.1 CYRILLIC CAPITAL LETTER U +0424 ; mapped ; 0444 # 1.1 CYRILLIC CAPITAL LETTER EF +0425 ; mapped ; 0445 # 1.1 CYRILLIC CAPITAL LETTER HA +0426 ; mapped ; 0446 # 1.1 CYRILLIC CAPITAL LETTER TSE +0427 ; mapped ; 0447 # 1.1 CYRILLIC CAPITAL LETTER CHE +0428 ; mapped ; 0448 # 1.1 CYRILLIC CAPITAL LETTER SHA +0429 ; mapped ; 0449 # 1.1 CYRILLIC CAPITAL LETTER SHCHA +042A ; mapped ; 044A # 1.1 CYRILLIC CAPITAL LETTER HARD SIGN +042B ; mapped ; 044B # 1.1 CYRILLIC CAPITAL LETTER YERU +042C ; mapped ; 044C # 1.1 CYRILLIC CAPITAL LETTER SOFT SIGN +042D ; mapped ; 044D # 1.1 CYRILLIC CAPITAL LETTER E +042E ; mapped ; 044E # 1.1 CYRILLIC CAPITAL LETTER YU +042F ; mapped ; 044F # 1.1 CYRILLIC CAPITAL LETTER YA +0430..044F ; valid # 1.1 CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER YA +0450 ; valid # 3.0 CYRILLIC SMALL LETTER IE WITH GRAVE +0451..045C ; valid # 1.1 CYRILLIC SMALL LETTER IO..CYRILLIC SMALL LETTER KJE +045D ; valid # 3.0 CYRILLIC SMALL LETTER I WITH GRAVE +045E..045F ; valid # 1.1 CYRILLIC SMALL LETTER SHORT U..CYRILLIC SMALL LETTER DZHE +0460 ; mapped ; 0461 # 1.1 CYRILLIC CAPITAL LETTER OMEGA +0461 ; valid # 1.1 CYRILLIC SMALL LETTER OMEGA +0462 ; mapped ; 0463 # 1.1 CYRILLIC CAPITAL LETTER YAT +0463 ; valid # 1.1 CYRILLIC SMALL LETTER YAT +0464 ; mapped ; 0465 # 1.1 CYRILLIC CAPITAL LETTER IOTIFIED E +0465 ; valid # 1.1 CYRILLIC SMALL LETTER IOTIFIED E +0466 ; mapped ; 0467 # 1.1 CYRILLIC CAPITAL LETTER LITTLE YUS +0467 ; valid # 1.1 CYRILLIC SMALL LETTER LITTLE YUS +0468 ; mapped ; 0469 # 1.1 CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +0469 ; valid # 1.1 CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS +046A ; mapped ; 046B # 1.1 CYRILLIC CAPITAL LETTER BIG YUS +046B ; valid # 1.1 CYRILLIC SMALL LETTER BIG YUS +046C ; mapped ; 046D # 1.1 CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046D ; valid # 1.1 CYRILLIC SMALL LETTER IOTIFIED BIG YUS +046E ; mapped ; 046F # 1.1 CYRILLIC CAPITAL LETTER KSI +046F ; valid # 1.1 CYRILLIC SMALL LETTER KSI +0470 ; mapped ; 0471 # 1.1 CYRILLIC CAPITAL LETTER PSI +0471 ; valid # 1.1 CYRILLIC SMALL LETTER PSI +0472 ; mapped ; 0473 # 1.1 CYRILLIC CAPITAL LETTER FITA +0473 ; valid # 1.1 CYRILLIC SMALL LETTER FITA +0474 ; mapped ; 0475 # 1.1 CYRILLIC CAPITAL LETTER IZHITSA +0475 ; valid # 1.1 CYRILLIC SMALL LETTER IZHITSA +0476 ; mapped ; 0477 # 1.1 CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0477 ; valid # 1.1 CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0478 ; mapped ; 0479 # 1.1 CYRILLIC CAPITAL LETTER UK +0479 ; valid # 1.1 CYRILLIC SMALL LETTER UK +047A ; mapped ; 047B # 1.1 CYRILLIC CAPITAL LETTER ROUND OMEGA +047B ; valid # 1.1 CYRILLIC SMALL LETTER ROUND OMEGA +047C ; mapped ; 047D # 1.1 CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047D ; valid # 1.1 CYRILLIC SMALL LETTER OMEGA WITH TITLO +047E ; mapped ; 047F # 1.1 CYRILLIC CAPITAL LETTER OT +047F ; valid # 1.1 CYRILLIC SMALL LETTER OT +0480 ; mapped ; 0481 # 1.1 CYRILLIC CAPITAL LETTER KOPPA +0481 ; valid # 1.1 CYRILLIC SMALL LETTER KOPPA +0482 ; valid ; ; NV8 # 1.1 CYRILLIC THOUSANDS SIGN +0483..0486 ; valid # 1.1 COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PSILI PNEUMATA +0487 ; valid # 5.1 COMBINING CYRILLIC POKRYTIE +0488..0489 ; valid ; ; NV8 # 3.0 COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN +048A ; mapped ; 048B # 3.2 CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +048B ; valid # 3.2 CYRILLIC SMALL LETTER SHORT I WITH TAIL +048C ; mapped ; 048D # 3.0 CYRILLIC CAPITAL LETTER SEMISOFT SIGN +048D ; valid # 3.0 CYRILLIC SMALL LETTER SEMISOFT SIGN +048E ; mapped ; 048F # 3.0 CYRILLIC CAPITAL LETTER ER WITH TICK +048F ; valid # 3.0 CYRILLIC SMALL LETTER ER WITH TICK +0490 ; mapped ; 0491 # 1.1 CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0491 ; valid # 1.1 CYRILLIC SMALL LETTER GHE WITH UPTURN +0492 ; mapped ; 0493 # 1.1 CYRILLIC CAPITAL LETTER GHE WITH STROKE +0493 ; valid # 1.1 CYRILLIC SMALL LETTER GHE WITH STROKE +0494 ; mapped ; 0495 # 1.1 CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +0495 ; valid # 1.1 CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK +0496 ; mapped ; 0497 # 1.1 CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0497 ; valid # 1.1 CYRILLIC SMALL LETTER ZHE WITH DESCENDER +0498 ; mapped ; 0499 # 1.1 CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +0499 ; valid # 1.1 CYRILLIC SMALL LETTER ZE WITH DESCENDER +049A ; mapped ; 049B # 1.1 CYRILLIC CAPITAL LETTER KA WITH DESCENDER +049B ; valid # 1.1 CYRILLIC SMALL LETTER KA WITH DESCENDER +049C ; mapped ; 049D # 1.1 CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +049D ; valid # 1.1 CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE +049E ; mapped ; 049F # 1.1 CYRILLIC CAPITAL LETTER KA WITH STROKE +049F ; valid # 1.1 CYRILLIC SMALL LETTER KA WITH STROKE +04A0 ; mapped ; 04A1 # 1.1 CYRILLIC CAPITAL LETTER BASHKIR KA +04A1 ; valid # 1.1 CYRILLIC SMALL LETTER BASHKIR KA +04A2 ; mapped ; 04A3 # 1.1 CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04A3 ; valid # 1.1 CYRILLIC SMALL LETTER EN WITH DESCENDER +04A4 ; mapped ; 04A5 # 1.1 CYRILLIC CAPITAL LIGATURE EN GHE +04A5 ; valid # 1.1 CYRILLIC SMALL LIGATURE EN GHE +04A6 ; mapped ; 04A7 # 1.1 CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +04A7 ; valid # 1.1 CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK +04A8 ; mapped ; 04A9 # 1.1 CYRILLIC CAPITAL LETTER ABKHASIAN HA +04A9 ; valid # 1.1 CYRILLIC SMALL LETTER ABKHASIAN HA +04AA ; mapped ; 04AB # 1.1 CYRILLIC CAPITAL LETTER ES WITH DESCENDER +04AB ; valid # 1.1 CYRILLIC SMALL LETTER ES WITH DESCENDER +04AC ; mapped ; 04AD # 1.1 CYRILLIC CAPITAL LETTER TE WITH DESCENDER +04AD ; valid # 1.1 CYRILLIC SMALL LETTER TE WITH DESCENDER +04AE ; mapped ; 04AF # 1.1 CYRILLIC CAPITAL LETTER STRAIGHT U +04AF ; valid # 1.1 CYRILLIC SMALL LETTER STRAIGHT U +04B0 ; mapped ; 04B1 # 1.1 CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +04B1 ; valid # 1.1 CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE +04B2 ; mapped ; 04B3 # 1.1 CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04B3 ; valid # 1.1 CYRILLIC SMALL LETTER HA WITH DESCENDER +04B4 ; mapped ; 04B5 # 1.1 CYRILLIC CAPITAL LIGATURE TE TSE +04B5 ; valid # 1.1 CYRILLIC SMALL LIGATURE TE TSE +04B6 ; mapped ; 04B7 # 1.1 CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04B7 ; valid # 1.1 CYRILLIC SMALL LETTER CHE WITH DESCENDER +04B8 ; mapped ; 04B9 # 1.1 CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +04B9 ; valid # 1.1 CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE +04BA ; mapped ; 04BB # 1.1 CYRILLIC CAPITAL LETTER SHHA +04BB ; valid # 1.1 CYRILLIC SMALL LETTER SHHA +04BC ; mapped ; 04BD # 1.1 CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BD ; valid # 1.1 CYRILLIC SMALL LETTER ABKHASIAN CHE +04BE ; mapped ; 04BF # 1.1 CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +04BF ; valid # 1.1 CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER +04C0 ; disallowed # 1.1 CYRILLIC LETTER PALOCHKA +04C1 ; mapped ; 04C2 # 1.1 CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C2 ; valid # 1.1 CYRILLIC SMALL LETTER ZHE WITH BREVE +04C3 ; mapped ; 04C4 # 1.1 CYRILLIC CAPITAL LETTER KA WITH HOOK +04C4 ; valid # 1.1 CYRILLIC SMALL LETTER KA WITH HOOK +04C5 ; mapped ; 04C6 # 3.2 CYRILLIC CAPITAL LETTER EL WITH TAIL +04C6 ; valid # 3.2 CYRILLIC SMALL LETTER EL WITH TAIL +04C7 ; mapped ; 04C8 # 1.1 CYRILLIC CAPITAL LETTER EN WITH HOOK +04C8 ; valid # 1.1 CYRILLIC SMALL LETTER EN WITH HOOK +04C9 ; mapped ; 04CA # 3.2 CYRILLIC CAPITAL LETTER EN WITH TAIL +04CA ; valid # 3.2 CYRILLIC SMALL LETTER EN WITH TAIL +04CB ; mapped ; 04CC # 1.1 CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04CC ; valid # 1.1 CYRILLIC SMALL LETTER KHAKASSIAN CHE +04CD ; mapped ; 04CE # 3.2 CYRILLIC CAPITAL LETTER EM WITH TAIL +04CE ; valid # 3.2 CYRILLIC SMALL LETTER EM WITH TAIL +04CF ; valid # 5.0 CYRILLIC SMALL LETTER PALOCHKA +04D0 ; mapped ; 04D1 # 1.1 CYRILLIC CAPITAL LETTER A WITH BREVE +04D1 ; valid # 1.1 CYRILLIC SMALL LETTER A WITH BREVE +04D2 ; mapped ; 04D3 # 1.1 CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D3 ; valid # 1.1 CYRILLIC SMALL LETTER A WITH DIAERESIS +04D4 ; mapped ; 04D5 # 1.1 CYRILLIC CAPITAL LIGATURE A IE +04D5 ; valid # 1.1 CYRILLIC SMALL LIGATURE A IE +04D6 ; mapped ; 04D7 # 1.1 CYRILLIC CAPITAL LETTER IE WITH BREVE +04D7 ; valid # 1.1 CYRILLIC SMALL LETTER IE WITH BREVE +04D8 ; mapped ; 04D9 # 1.1 CYRILLIC CAPITAL LETTER SCHWA +04D9 ; valid # 1.1 CYRILLIC SMALL LETTER SCHWA +04DA ; mapped ; 04DB # 1.1 CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DB ; valid # 1.1 CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DC ; mapped ; 04DD # 1.1 CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DD ; valid # 1.1 CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DE ; mapped ; 04DF # 1.1 CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04DF ; valid # 1.1 CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04E0 ; mapped ; 04E1 # 1.1 CYRILLIC CAPITAL LETTER ABKHASIAN DZE +04E1 ; valid # 1.1 CYRILLIC SMALL LETTER ABKHASIAN DZE +04E2 ; mapped ; 04E3 # 1.1 CYRILLIC CAPITAL LETTER I WITH MACRON +04E3 ; valid # 1.1 CYRILLIC SMALL LETTER I WITH MACRON +04E4 ; mapped ; 04E5 # 1.1 CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E5 ; valid # 1.1 CYRILLIC SMALL LETTER I WITH DIAERESIS +04E6 ; mapped ; 04E7 # 1.1 CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E7 ; valid # 1.1 CYRILLIC SMALL LETTER O WITH DIAERESIS +04E8 ; mapped ; 04E9 # 1.1 CYRILLIC CAPITAL LETTER BARRED O +04E9 ; valid # 1.1 CYRILLIC SMALL LETTER BARRED O +04EA ; mapped ; 04EB # 1.1 CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EB ; valid # 1.1 CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04EC ; mapped ; 04ED # 3.0 CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04ED ; valid # 3.0 CYRILLIC SMALL LETTER E WITH DIAERESIS +04EE ; mapped ; 04EF # 1.1 CYRILLIC CAPITAL LETTER U WITH MACRON +04EF ; valid # 1.1 CYRILLIC SMALL LETTER U WITH MACRON +04F0 ; mapped ; 04F1 # 1.1 CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F1 ; valid # 1.1 CYRILLIC SMALL LETTER U WITH DIAERESIS +04F2 ; mapped ; 04F3 # 1.1 CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F3 ; valid # 1.1 CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F4 ; mapped ; 04F5 # 1.1 CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F5 ; valid # 1.1 CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F6 ; mapped ; 04F7 # 4.1 CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +04F7 ; valid # 4.1 CYRILLIC SMALL LETTER GHE WITH DESCENDER +04F8 ; mapped ; 04F9 # 1.1 CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04F9 ; valid # 1.1 CYRILLIC SMALL LETTER YERU WITH DIAERESIS +04FA ; mapped ; 04FB # 5.0 CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +04FB ; valid # 5.0 CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK +04FC ; mapped ; 04FD # 5.0 CYRILLIC CAPITAL LETTER HA WITH HOOK +04FD ; valid # 5.0 CYRILLIC SMALL LETTER HA WITH HOOK +04FE ; mapped ; 04FF # 5.0 CYRILLIC CAPITAL LETTER HA WITH STROKE +04FF ; valid # 5.0 CYRILLIC SMALL LETTER HA WITH STROKE +0500 ; mapped ; 0501 # 3.2 CYRILLIC CAPITAL LETTER KOMI DE +0501 ; valid # 3.2 CYRILLIC SMALL LETTER KOMI DE +0502 ; mapped ; 0503 # 3.2 CYRILLIC CAPITAL LETTER KOMI DJE +0503 ; valid # 3.2 CYRILLIC SMALL LETTER KOMI DJE +0504 ; mapped ; 0505 # 3.2 CYRILLIC CAPITAL LETTER KOMI ZJE +0505 ; valid # 3.2 CYRILLIC SMALL LETTER KOMI ZJE +0506 ; mapped ; 0507 # 3.2 CYRILLIC CAPITAL LETTER KOMI DZJE +0507 ; valid # 3.2 CYRILLIC SMALL LETTER KOMI DZJE +0508 ; mapped ; 0509 # 3.2 CYRILLIC CAPITAL LETTER KOMI LJE +0509 ; valid # 3.2 CYRILLIC SMALL LETTER KOMI LJE +050A ; mapped ; 050B # 3.2 CYRILLIC CAPITAL LETTER KOMI NJE +050B ; valid # 3.2 CYRILLIC SMALL LETTER KOMI NJE +050C ; mapped ; 050D # 3.2 CYRILLIC CAPITAL LETTER KOMI SJE +050D ; valid # 3.2 CYRILLIC SMALL LETTER KOMI SJE +050E ; mapped ; 050F # 3.2 CYRILLIC CAPITAL LETTER KOMI TJE +050F ; valid # 3.2 CYRILLIC SMALL LETTER KOMI TJE +0510 ; mapped ; 0511 # 5.0 CYRILLIC CAPITAL LETTER REVERSED ZE +0511 ; valid # 5.0 CYRILLIC SMALL LETTER REVERSED ZE +0512 ; mapped ; 0513 # 5.0 CYRILLIC CAPITAL LETTER EL WITH HOOK +0513 ; valid # 5.0 CYRILLIC SMALL LETTER EL WITH HOOK +0514 ; mapped ; 0515 # 5.1 CYRILLIC CAPITAL LETTER LHA +0515 ; valid # 5.1 CYRILLIC SMALL LETTER LHA +0516 ; mapped ; 0517 # 5.1 CYRILLIC CAPITAL LETTER RHA +0517 ; valid # 5.1 CYRILLIC SMALL LETTER RHA +0518 ; mapped ; 0519 # 5.1 CYRILLIC CAPITAL LETTER YAE +0519 ; valid # 5.1 CYRILLIC SMALL LETTER YAE +051A ; mapped ; 051B # 5.1 CYRILLIC CAPITAL LETTER QA +051B ; valid # 5.1 CYRILLIC SMALL LETTER QA +051C ; mapped ; 051D # 5.1 CYRILLIC CAPITAL LETTER WE +051D ; valid # 5.1 CYRILLIC SMALL LETTER WE +051E ; mapped ; 051F # 5.1 CYRILLIC CAPITAL LETTER ALEUT KA +051F ; valid # 5.1 CYRILLIC SMALL LETTER ALEUT KA +0520 ; mapped ; 0521 # 5.1 CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK +0521 ; valid # 5.1 CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK +0522 ; mapped ; 0523 # 5.1 CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK +0523 ; valid # 5.1 CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK +0524 ; mapped ; 0525 # 5.2 CYRILLIC CAPITAL LETTER PE WITH DESCENDER +0525 ; valid # 5.2 CYRILLIC SMALL LETTER PE WITH DESCENDER +0526 ; mapped ; 0527 # 6.0 CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER +0527 ; valid # 6.0 CYRILLIC SMALL LETTER SHHA WITH DESCENDER +0528 ; mapped ; 0529 # 7.0 CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK +0529 ; valid # 7.0 CYRILLIC SMALL LETTER EN WITH LEFT HOOK +052A ; mapped ; 052B # 7.0 CYRILLIC CAPITAL LETTER DZZHE +052B ; valid # 7.0 CYRILLIC SMALL LETTER DZZHE +052C ; mapped ; 052D # 7.0 CYRILLIC CAPITAL LETTER DCHE +052D ; valid # 7.0 CYRILLIC SMALL LETTER DCHE +052E ; mapped ; 052F # 7.0 CYRILLIC CAPITAL LETTER EL WITH DESCENDER +052F ; valid # 7.0 CYRILLIC SMALL LETTER EL WITH DESCENDER +0530 ; disallowed # NA +0531 ; mapped ; 0561 # 1.1 ARMENIAN CAPITAL LETTER AYB +0532 ; mapped ; 0562 # 1.1 ARMENIAN CAPITAL LETTER BEN +0533 ; mapped ; 0563 # 1.1 ARMENIAN CAPITAL LETTER GIM +0534 ; mapped ; 0564 # 1.1 ARMENIAN CAPITAL LETTER DA +0535 ; mapped ; 0565 # 1.1 ARMENIAN CAPITAL LETTER ECH +0536 ; mapped ; 0566 # 1.1 ARMENIAN CAPITAL LETTER ZA +0537 ; mapped ; 0567 # 1.1 ARMENIAN CAPITAL LETTER EH +0538 ; mapped ; 0568 # 1.1 ARMENIAN CAPITAL LETTER ET +0539 ; mapped ; 0569 # 1.1 ARMENIAN CAPITAL LETTER TO +053A ; mapped ; 056A # 1.1 ARMENIAN CAPITAL LETTER ZHE +053B ; mapped ; 056B # 1.1 ARMENIAN CAPITAL LETTER INI +053C ; mapped ; 056C # 1.1 ARMENIAN CAPITAL LETTER LIWN +053D ; mapped ; 056D # 1.1 ARMENIAN CAPITAL LETTER XEH +053E ; mapped ; 056E # 1.1 ARMENIAN CAPITAL LETTER CA +053F ; mapped ; 056F # 1.1 ARMENIAN CAPITAL LETTER KEN +0540 ; mapped ; 0570 # 1.1 ARMENIAN CAPITAL LETTER HO +0541 ; mapped ; 0571 # 1.1 ARMENIAN CAPITAL LETTER JA +0542 ; mapped ; 0572 # 1.1 ARMENIAN CAPITAL LETTER GHAD +0543 ; mapped ; 0573 # 1.1 ARMENIAN CAPITAL LETTER CHEH +0544 ; mapped ; 0574 # 1.1 ARMENIAN CAPITAL LETTER MEN +0545 ; mapped ; 0575 # 1.1 ARMENIAN CAPITAL LETTER YI +0546 ; mapped ; 0576 # 1.1 ARMENIAN CAPITAL LETTER NOW +0547 ; mapped ; 0577 # 1.1 ARMENIAN CAPITAL LETTER SHA +0548 ; mapped ; 0578 # 1.1 ARMENIAN CAPITAL LETTER VO +0549 ; mapped ; 0579 # 1.1 ARMENIAN CAPITAL LETTER CHA +054A ; mapped ; 057A # 1.1 ARMENIAN CAPITAL LETTER PEH +054B ; mapped ; 057B # 1.1 ARMENIAN CAPITAL LETTER JHEH +054C ; mapped ; 057C # 1.1 ARMENIAN CAPITAL LETTER RA +054D ; mapped ; 057D # 1.1 ARMENIAN CAPITAL LETTER SEH +054E ; mapped ; 057E # 1.1 ARMENIAN CAPITAL LETTER VEW +054F ; mapped ; 057F # 1.1 ARMENIAN CAPITAL LETTER TIWN +0550 ; mapped ; 0580 # 1.1 ARMENIAN CAPITAL LETTER REH +0551 ; mapped ; 0581 # 1.1 ARMENIAN CAPITAL LETTER CO +0552 ; mapped ; 0582 # 1.1 ARMENIAN CAPITAL LETTER YIWN +0553 ; mapped ; 0583 # 1.1 ARMENIAN CAPITAL LETTER PIWR +0554 ; mapped ; 0584 # 1.1 ARMENIAN CAPITAL LETTER KEH +0555 ; mapped ; 0585 # 1.1 ARMENIAN CAPITAL LETTER OH +0556 ; mapped ; 0586 # 1.1 ARMENIAN CAPITAL LETTER FEH +0557..0558 ; disallowed # NA .. +0559 ; valid # 1.1 ARMENIAN MODIFIER LETTER LEFT HALF RING +055A..055F ; valid ; ; NV8 # 1.1 ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK +0560 ; disallowed # NA +0561..0586 ; valid # 1.1 ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LETTER FEH +0587 ; mapped ; 0565 0582 # 1.1 ARMENIAN SMALL LIGATURE ECH YIWN +0588 ; disallowed # NA +0589 ; valid ; ; NV8 # 1.1 ARMENIAN FULL STOP +058A ; valid ; ; NV8 # 3.0 ARMENIAN HYPHEN +058B..058C ; disallowed # NA .. +058D..058E ; valid ; ; NV8 # 7.0 RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN +058F ; valid ; ; NV8 # 6.1 ARMENIAN DRAM SIGN +0590 ; disallowed # NA +0591..05A1 ; valid # 2.0 HEBREW ACCENT ETNAHTA..HEBREW ACCENT PAZER +05A2 ; valid # 4.1 HEBREW ACCENT ATNAH HAFUKH +05A3..05AF ; valid # 2.0 HEBREW ACCENT MUNAH..HEBREW MARK MASORA CIRCLE +05B0..05B9 ; valid # 1.1 HEBREW POINT SHEVA..HEBREW POINT HOLAM +05BA ; valid # 5.0 HEBREW POINT HOLAM HASER FOR VAV +05BB..05BD ; valid # 1.1 HEBREW POINT QUBUTS..HEBREW POINT METEG +05BE ; valid ; ; NV8 # 1.1 HEBREW PUNCTUATION MAQAF +05BF ; valid # 1.1 HEBREW POINT RAFE +05C0 ; valid ; ; NV8 # 1.1 HEBREW PUNCTUATION PASEQ +05C1..05C2 ; valid # 1.1 HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C3 ; valid ; ; NV8 # 1.1 HEBREW PUNCTUATION SOF PASUQ +05C4 ; valid # 2.0 HEBREW MARK UPPER DOT +05C5 ; valid # 4.1 HEBREW MARK LOWER DOT +05C6 ; valid ; ; NV8 # 4.1 HEBREW PUNCTUATION NUN HAFUKHA +05C7 ; valid # 4.1 HEBREW POINT QAMATS QATAN +05C8..05CF ; disallowed # NA .. +05D0..05EA ; valid # 1.1 HEBREW LETTER ALEF..HEBREW LETTER TAV +05EB..05EF ; disallowed # NA .. +05F0..05F4 ; valid # 1.1 HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW PUNCTUATION GERSHAYIM +05F5..05FF ; disallowed # NA .. +0600..0603 ; disallowed # 4.0 ARABIC NUMBER SIGN..ARABIC SIGN SAFHA +0604 ; disallowed # 6.1 ARABIC SIGN SAMVAT +0605 ; disallowed # 7.0 ARABIC NUMBER MARK ABOVE +0606..060A ; valid ; ; NV8 # 5.1 ARABIC-INDIC CUBE ROOT..ARABIC-INDIC PER TEN THOUSAND SIGN +060B ; valid ; ; NV8 # 4.1 AFGHANI SIGN +060C ; valid ; ; NV8 # 1.1 ARABIC COMMA +060D..060F ; valid ; ; NV8 # 4.0 ARABIC DATE SEPARATOR..ARABIC SIGN MISRA +0610..0615 ; valid # 4.0 ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL HIGH TAH +0616..061A ; valid # 5.1 ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH..ARABIC SMALL KASRA +061B ; valid ; ; NV8 # 1.1 ARABIC SEMICOLON +061C ; disallowed # 6.3 ARABIC LETTER MARK +061D ; disallowed # NA +061E ; valid ; ; NV8 # 4.1 ARABIC TRIPLE DOT PUNCTUATION MARK +061F ; valid ; ; NV8 # 1.1 ARABIC QUESTION MARK +0620 ; valid # 6.0 ARABIC LETTER KASHMIRI YEH +0621..063A ; valid # 1.1 ARABIC LETTER HAMZA..ARABIC LETTER GHAIN +063B..063F ; valid # 5.1 ARABIC LETTER KEHEH WITH TWO DOTS ABOVE..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0640 ; valid ; ; NV8 # 1.1 ARABIC TATWEEL +0641..0652 ; valid # 1.1 ARABIC LETTER FEH..ARABIC SUKUN +0653..0655 ; valid # 3.0 ARABIC MADDAH ABOVE..ARABIC HAMZA BELOW +0656..0658 ; valid # 4.0 ARABIC SUBSCRIPT ALEF..ARABIC MARK NOON GHUNNA +0659..065E ; valid # 4.1 ARABIC ZWARAKAY..ARABIC FATHA WITH TWO DOTS +065F ; valid # 6.0 ARABIC WAVY HAMZA BELOW +0660..0669 ; valid # 1.1 ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +066A..066D ; valid ; ; NV8 # 1.1 ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR +066E..066F ; valid # 3.2 ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF +0670..0674 ; valid # 1.1 ARABIC LETTER SUPERSCRIPT ALEF..ARABIC LETTER HIGH HAMZA +0675 ; mapped ; 0627 0674 # 1.1 ARABIC LETTER HIGH HAMZA ALEF +0676 ; mapped ; 0648 0674 # 1.1 ARABIC LETTER HIGH HAMZA WAW +0677 ; mapped ; 06C7 0674 # 1.1 ARABIC LETTER U WITH HAMZA ABOVE +0678 ; mapped ; 064A 0674 # 1.1 ARABIC LETTER HIGH HAMZA YEH +0679..06B7 ; valid # 1.1 ARABIC LETTER TTEH..ARABIC LETTER LAM WITH THREE DOTS ABOVE +06B8..06B9 ; valid # 3.0 ARABIC LETTER LAM WITH THREE DOTS BELOW..ARABIC LETTER NOON WITH DOT BELOW +06BA..06BE ; valid # 1.1 ARABIC LETTER NOON GHUNNA..ARABIC LETTER HEH DOACHASHMEE +06BF ; valid # 3.0 ARABIC LETTER TCHEH WITH DOT ABOVE +06C0..06CE ; valid # 1.1 ARABIC LETTER HEH WITH YEH ABOVE..ARABIC LETTER YEH WITH SMALL V +06CF ; valid # 3.0 ARABIC LETTER WAW WITH DOT ABOVE +06D0..06D3 ; valid # 1.1 ARABIC LETTER E..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D4 ; valid ; ; NV8 # 1.1 ARABIC FULL STOP +06D5..06DC ; valid # 1.1 ARABIC LETTER AE..ARABIC SMALL HIGH SEEN +06DD ; disallowed # 1.1 ARABIC END OF AYAH +06DE ; valid ; ; NV8 # 1.1 ARABIC START OF RUB EL HIZB +06DF..06E8 ; valid # 1.1 ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH NOON +06E9 ; valid ; ; NV8 # 1.1 ARABIC PLACE OF SAJDAH +06EA..06ED ; valid # 1.1 ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +06EE..06EF ; valid # 4.0 ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V +06F0..06F9 ; valid # 1.1 EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE +06FA..06FE ; valid # 3.0 ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC SIGN SINDHI POSTPOSITION MEN +06FF ; valid # 4.0 ARABIC LETTER HEH WITH INVERTED V +0700..070D ; valid ; ; NV8 # 3.0 SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS +070E ; disallowed # NA +070F ; disallowed # 3.0 SYRIAC ABBREVIATION MARK +0710..072C ; valid # 3.0 SYRIAC LETTER ALAPH..SYRIAC LETTER TAW +072D..072F ; valid # 4.0 SYRIAC LETTER PERSIAN BHETH..SYRIAC LETTER PERSIAN DHALATH +0730..074A ; valid # 3.0 SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +074B..074C ; disallowed # NA .. +074D..074F ; valid # 4.0 SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE +0750..076D ; valid # 4.1 ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE +076E..077F ; valid # 5.1 ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE +0780..07B0 ; valid # 3.0 THAANA LETTER HAA..THAANA SUKUN +07B1 ; valid # 3.2 THAANA LETTER NAA +07B2..07BF ; disallowed # NA .. +07C0..07F5 ; valid # 5.0 NKO DIGIT ZERO..NKO LOW TONE APOSTROPHE +07F6..07FA ; valid ; ; NV8 # 5.0 NKO SYMBOL OO DENNEN..NKO LAJANYALAN +07FB..07FF ; disallowed # NA .. +0800..082D ; valid # 5.2 SAMARITAN LETTER ALAF..SAMARITAN MARK NEQUDAA +082E..082F ; disallowed # NA .. +0830..083E ; valid ; ; NV8 # 5.2 SAMARITAN PUNCTUATION NEQUDAA..SAMARITAN PUNCTUATION ANNAAU +083F ; disallowed # NA +0840..085B ; valid # 6.0 MANDAIC LETTER HALQA..MANDAIC GEMINATION MARK +085C..085D ; disallowed # NA .. +085E ; valid ; ; NV8 # 6.0 MANDAIC PUNCTUATION +085F ; disallowed # NA +0860..086A ; valid # 10.0 SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +086B..089F ; disallowed # NA .. +08A0 ; valid # 6.1 ARABIC LETTER BEH WITH SMALL V BELOW +08A1 ; valid # 7.0 ARABIC LETTER BEH WITH HAMZA ABOVE +08A2..08AC ; valid # 6.1 ARABIC LETTER JEEM WITH TWO DOTS ABOVE..ARABIC LETTER ROHINGYA YEH +08AD..08B2 ; valid # 7.0 ARABIC LETTER LOW ALEF..ARABIC LETTER ZAIN WITH INVERTED V ABOVE +08B3..08B4 ; valid # 8.0 ARABIC LETTER AIN WITH THREE DOTS BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B5 ; disallowed # NA +08B6..08BD ; valid # 9.0 ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08BE..08D3 ; disallowed # NA .. +08D4..08E1 ; valid # 9.0 ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +08E2 ; disallowed # 9.0 ARABIC DISPUTED END OF AYAH +08E3 ; valid # 8.0 ARABIC TURNED DAMMA BELOW +08E4..08FE ; valid # 6.1 ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT +08FF ; valid # 7.0 ARABIC MARK SIDEWAYS NOON GHUNNA +0900 ; valid # 5.2 DEVANAGARI SIGN INVERTED CANDRABINDU +0901..0903 ; valid # 1.1 DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN VISARGA +0904 ; valid # 4.0 DEVANAGARI LETTER SHORT A +0905..0939 ; valid # 1.1 DEVANAGARI LETTER A..DEVANAGARI LETTER HA +093A..093B ; valid # 6.0 DEVANAGARI VOWEL SIGN OE..DEVANAGARI VOWEL SIGN OOE +093C..094D ; valid # 1.1 DEVANAGARI SIGN NUKTA..DEVANAGARI SIGN VIRAMA +094E ; valid # 5.2 DEVANAGARI VOWEL SIGN PRISHTHAMATRA E +094F ; valid # 6.0 DEVANAGARI VOWEL SIGN AW +0950..0954 ; valid # 1.1 DEVANAGARI OM..DEVANAGARI ACUTE ACCENT +0955 ; valid # 5.2 DEVANAGARI VOWEL SIGN CANDRA LONG E +0956..0957 ; valid # 6.0 DEVANAGARI VOWEL SIGN UE..DEVANAGARI VOWEL SIGN UUE +0958 ; mapped ; 0915 093C # 1.1 DEVANAGARI LETTER QA +0959 ; mapped ; 0916 093C # 1.1 DEVANAGARI LETTER KHHA +095A ; mapped ; 0917 093C # 1.1 DEVANAGARI LETTER GHHA +095B ; mapped ; 091C 093C # 1.1 DEVANAGARI LETTER ZA +095C ; mapped ; 0921 093C # 1.1 DEVANAGARI LETTER DDDHA +095D ; mapped ; 0922 093C # 1.1 DEVANAGARI LETTER RHA +095E ; mapped ; 092B 093C # 1.1 DEVANAGARI LETTER FA +095F ; mapped ; 092F 093C # 1.1 DEVANAGARI LETTER YYA +0960..0963 ; valid # 1.1 DEVANAGARI LETTER VOCALIC RR..DEVANAGARI VOWEL SIGN VOCALIC LL +0964..0965 ; valid ; ; NV8 # 1.1 DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +0966..096F ; valid # 1.1 DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +0970 ; valid ; ; NV8 # 1.1 DEVANAGARI ABBREVIATION SIGN +0971..0972 ; valid # 5.1 DEVANAGARI SIGN HIGH SPACING DOT..DEVANAGARI LETTER CANDRA A +0973..0977 ; valid # 6.0 DEVANAGARI LETTER OE..DEVANAGARI LETTER UUE +0978 ; valid # 7.0 DEVANAGARI LETTER MARWARI DDA +0979..097A ; valid # 5.2 DEVANAGARI LETTER ZHA..DEVANAGARI LETTER HEAVY YA +097B..097C ; valid # 5.0 DEVANAGARI LETTER GGA..DEVANAGARI LETTER JJA +097D ; valid # 4.1 DEVANAGARI LETTER GLOTTAL STOP +097E..097F ; valid # 5.0 DEVANAGARI LETTER DDDA..DEVANAGARI LETTER BBA +0980 ; valid # 7.0 BENGALI ANJI +0981..0983 ; valid # 1.1 BENGALI SIGN CANDRABINDU..BENGALI SIGN VISARGA +0984 ; disallowed # NA +0985..098C ; valid # 1.1 BENGALI LETTER A..BENGALI LETTER VOCALIC L +098D..098E ; disallowed # NA .. +098F..0990 ; valid # 1.1 BENGALI LETTER E..BENGALI LETTER AI +0991..0992 ; disallowed # NA .. +0993..09A8 ; valid # 1.1 BENGALI LETTER O..BENGALI LETTER NA +09A9 ; disallowed # NA +09AA..09B0 ; valid # 1.1 BENGALI LETTER PA..BENGALI LETTER RA +09B1 ; disallowed # NA +09B2 ; valid # 1.1 BENGALI LETTER LA +09B3..09B5 ; disallowed # NA .. +09B6..09B9 ; valid # 1.1 BENGALI LETTER SHA..BENGALI LETTER HA +09BA..09BB ; disallowed # NA .. +09BC ; valid # 1.1 BENGALI SIGN NUKTA +09BD ; valid # 4.0 BENGALI SIGN AVAGRAHA +09BE..09C4 ; valid # 1.1 BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN VOCALIC RR +09C5..09C6 ; disallowed # NA .. +09C7..09C8 ; valid # 1.1 BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09C9..09CA ; disallowed # NA .. +09CB..09CD ; valid # 1.1 BENGALI VOWEL SIGN O..BENGALI SIGN VIRAMA +09CE ; valid # 4.1 BENGALI LETTER KHANDA TA +09CF..09D6 ; disallowed # NA .. +09D7 ; valid # 1.1 BENGALI AU LENGTH MARK +09D8..09DB ; disallowed # NA .. +09DC ; mapped ; 09A1 09BC # 1.1 BENGALI LETTER RRA +09DD ; mapped ; 09A2 09BC # 1.1 BENGALI LETTER RHA +09DE ; disallowed # NA +09DF ; mapped ; 09AF 09BC # 1.1 BENGALI LETTER YYA +09E0..09E3 ; valid # 1.1 BENGALI LETTER VOCALIC RR..BENGALI VOWEL SIGN VOCALIC LL +09E4..09E5 ; disallowed # NA .. +09E6..09F1 ; valid # 1.1 BENGALI DIGIT ZERO..BENGALI LETTER RA WITH LOWER DIAGONAL +09F2..09FA ; valid ; ; NV8 # 1.1 BENGALI RUPEE MARK..BENGALI ISSHAR +09FB ; valid ; ; NV8 # 5.2 BENGALI GANDA MARK +09FC ; valid # 10.0 BENGALI LETTER VEDIC ANUSVARA +09FD ; valid ; ; NV8 # 10.0 BENGALI ABBREVIATION SIGN +09FE..0A00 ; disallowed # NA .. +0A01 ; valid # 4.0 GURMUKHI SIGN ADAK BINDI +0A02 ; valid # 1.1 GURMUKHI SIGN BINDI +0A03 ; valid # 4.0 GURMUKHI SIGN VISARGA +0A04 ; disallowed # NA +0A05..0A0A ; valid # 1.1 GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0B..0A0E ; disallowed # NA .. +0A0F..0A10 ; valid # 1.1 GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A11..0A12 ; disallowed # NA .. +0A13..0A28 ; valid # 1.1 GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A29 ; disallowed # NA +0A2A..0A30 ; valid # 1.1 GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A31 ; disallowed # NA +0A32 ; valid # 1.1 GURMUKHI LETTER LA +0A33 ; mapped ; 0A32 0A3C # 1.1 GURMUKHI LETTER LLA +0A34 ; disallowed # NA +0A35 ; valid # 1.1 GURMUKHI LETTER VA +0A36 ; mapped ; 0A38 0A3C # 1.1 GURMUKHI LETTER SHA +0A37 ; disallowed # NA +0A38..0A39 ; valid # 1.1 GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A3A..0A3B ; disallowed # NA .. +0A3C ; valid # 1.1 GURMUKHI SIGN NUKTA +0A3D ; disallowed # NA +0A3E..0A42 ; valid # 1.1 GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN UU +0A43..0A46 ; disallowed # NA .. +0A47..0A48 ; valid # 1.1 GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A49..0A4A ; disallowed # NA .. +0A4B..0A4D ; valid # 1.1 GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A4E..0A50 ; disallowed # NA .. +0A51 ; valid # 5.1 GURMUKHI SIGN UDAAT +0A52..0A58 ; disallowed # NA .. +0A59 ; mapped ; 0A16 0A3C # 1.1 GURMUKHI LETTER KHHA +0A5A ; mapped ; 0A17 0A3C # 1.1 GURMUKHI LETTER GHHA +0A5B ; mapped ; 0A1C 0A3C # 1.1 GURMUKHI LETTER ZA +0A5C ; valid # 1.1 GURMUKHI LETTER RRA +0A5D ; disallowed # NA +0A5E ; mapped ; 0A2B 0A3C # 1.1 GURMUKHI LETTER FA +0A5F..0A65 ; disallowed # NA .. +0A66..0A74 ; valid # 1.1 GURMUKHI DIGIT ZERO..GURMUKHI EK ONKAR +0A75 ; valid # 5.1 GURMUKHI SIGN YAKASH +0A76..0A80 ; disallowed # NA .. +0A81..0A83 ; valid # 1.1 GUJARATI SIGN CANDRABINDU..GUJARATI SIGN VISARGA +0A84 ; disallowed # NA +0A85..0A8B ; valid # 1.1 GUJARATI LETTER A..GUJARATI LETTER VOCALIC R +0A8C ; valid # 4.0 GUJARATI LETTER VOCALIC L +0A8D ; valid # 1.1 GUJARATI VOWEL CANDRA E +0A8E ; disallowed # NA +0A8F..0A91 ; valid # 1.1 GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A92 ; disallowed # NA +0A93..0AA8 ; valid # 1.1 GUJARATI LETTER O..GUJARATI LETTER NA +0AA9 ; disallowed # NA +0AAA..0AB0 ; valid # 1.1 GUJARATI LETTER PA..GUJARATI LETTER RA +0AB1 ; disallowed # NA +0AB2..0AB3 ; valid # 1.1 GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB4 ; disallowed # NA +0AB5..0AB9 ; valid # 1.1 GUJARATI LETTER VA..GUJARATI LETTER HA +0ABA..0ABB ; disallowed # NA .. +0ABC..0AC5 ; valid # 1.1 GUJARATI SIGN NUKTA..GUJARATI VOWEL SIGN CANDRA E +0AC6 ; disallowed # NA +0AC7..0AC9 ; valid # 1.1 GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN CANDRA O +0ACA ; disallowed # NA +0ACB..0ACD ; valid # 1.1 GUJARATI VOWEL SIGN O..GUJARATI SIGN VIRAMA +0ACE..0ACF ; disallowed # NA .. +0AD0 ; valid # 1.1 GUJARATI OM +0AD1..0ADF ; disallowed # NA .. +0AE0 ; valid # 1.1 GUJARATI LETTER VOCALIC RR +0AE1..0AE3 ; valid # 4.0 GUJARATI LETTER VOCALIC LL..GUJARATI VOWEL SIGN VOCALIC LL +0AE4..0AE5 ; disallowed # NA .. +0AE6..0AEF ; valid # 1.1 GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0AF0 ; valid ; ; NV8 # 6.1 GUJARATI ABBREVIATION SIGN +0AF1 ; valid ; ; NV8 # 4.0 GUJARATI RUPEE SIGN +0AF2..0AF8 ; disallowed # NA .. +0AF9 ; valid # 8.0 GUJARATI LETTER ZHA +0AFA..0AFF ; valid # 10.0 GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B00 ; disallowed # NA +0B01..0B03 ; valid # 1.1 ORIYA SIGN CANDRABINDU..ORIYA SIGN VISARGA +0B04 ; disallowed # NA +0B05..0B0C ; valid # 1.1 ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0D..0B0E ; disallowed # NA .. +0B0F..0B10 ; valid # 1.1 ORIYA LETTER E..ORIYA LETTER AI +0B11..0B12 ; disallowed # NA .. +0B13..0B28 ; valid # 1.1 ORIYA LETTER O..ORIYA LETTER NA +0B29 ; disallowed # NA +0B2A..0B30 ; valid # 1.1 ORIYA LETTER PA..ORIYA LETTER RA +0B31 ; disallowed # NA +0B32..0B33 ; valid # 1.1 ORIYA LETTER LA..ORIYA LETTER LLA +0B34 ; disallowed # NA +0B35 ; valid # 4.0 ORIYA LETTER VA +0B36..0B39 ; valid # 1.1 ORIYA LETTER SHA..ORIYA LETTER HA +0B3A..0B3B ; disallowed # NA .. +0B3C..0B43 ; valid # 1.1 ORIYA SIGN NUKTA..ORIYA VOWEL SIGN VOCALIC R +0B44 ; valid # 5.1 ORIYA VOWEL SIGN VOCALIC RR +0B45..0B46 ; disallowed # NA .. +0B47..0B48 ; valid # 1.1 ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B49..0B4A ; disallowed # NA .. +0B4B..0B4D ; valid # 1.1 ORIYA VOWEL SIGN O..ORIYA SIGN VIRAMA +0B4E..0B55 ; disallowed # NA .. +0B56..0B57 ; valid # 1.1 ORIYA AI LENGTH MARK..ORIYA AU LENGTH MARK +0B58..0B5B ; disallowed # NA .. +0B5C ; mapped ; 0B21 0B3C # 1.1 ORIYA LETTER RRA +0B5D ; mapped ; 0B22 0B3C # 1.1 ORIYA LETTER RHA +0B5E ; disallowed # NA +0B5F..0B61 ; valid # 1.1 ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B62..0B63 ; valid # 5.1 ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL +0B64..0B65 ; disallowed # NA .. +0B66..0B6F ; valid # 1.1 ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0B70 ; valid ; ; NV8 # 1.1 ORIYA ISSHAR +0B71 ; valid # 4.0 ORIYA LETTER WA +0B72..0B77 ; valid ; ; NV8 # 6.0 ORIYA FRACTION ONE QUARTER..ORIYA FRACTION THREE SIXTEENTHS +0B78..0B81 ; disallowed # NA .. +0B82..0B83 ; valid # 1.1 TAMIL SIGN ANUSVARA..TAMIL SIGN VISARGA +0B84 ; disallowed # NA +0B85..0B8A ; valid # 1.1 TAMIL LETTER A..TAMIL LETTER UU +0B8B..0B8D ; disallowed # NA .. +0B8E..0B90 ; valid # 1.1 TAMIL LETTER E..TAMIL LETTER AI +0B91 ; disallowed # NA +0B92..0B95 ; valid # 1.1 TAMIL LETTER O..TAMIL LETTER KA +0B96..0B98 ; disallowed # NA .. +0B99..0B9A ; valid # 1.1 TAMIL LETTER NGA..TAMIL LETTER CA +0B9B ; disallowed # NA +0B9C ; valid # 1.1 TAMIL LETTER JA +0B9D ; disallowed # NA +0B9E..0B9F ; valid # 1.1 TAMIL LETTER NYA..TAMIL LETTER TTA +0BA0..0BA2 ; disallowed # NA .. +0BA3..0BA4 ; valid # 1.1 TAMIL LETTER NNA..TAMIL LETTER TA +0BA5..0BA7 ; disallowed # NA .. +0BA8..0BAA ; valid # 1.1 TAMIL LETTER NA..TAMIL LETTER PA +0BAB..0BAD ; disallowed # NA .. +0BAE..0BB5 ; valid # 1.1 TAMIL LETTER MA..TAMIL LETTER VA +0BB6 ; valid # 4.1 TAMIL LETTER SHA +0BB7..0BB9 ; valid # 1.1 TAMIL LETTER SSA..TAMIL LETTER HA +0BBA..0BBD ; disallowed # NA .. +0BBE..0BC2 ; valid # 1.1 TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN UU +0BC3..0BC5 ; disallowed # NA .. +0BC6..0BC8 ; valid # 1.1 TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BC9 ; disallowed # NA +0BCA..0BCD ; valid # 1.1 TAMIL VOWEL SIGN O..TAMIL SIGN VIRAMA +0BCE..0BCF ; disallowed # NA .. +0BD0 ; valid # 5.1 TAMIL OM +0BD1..0BD6 ; disallowed # NA .. +0BD7 ; valid # 1.1 TAMIL AU LENGTH MARK +0BD8..0BE5 ; disallowed # NA .. +0BE6 ; valid # 4.1 TAMIL DIGIT ZERO +0BE7..0BEF ; valid # 1.1 TAMIL DIGIT ONE..TAMIL DIGIT NINE +0BF0..0BF2 ; valid ; ; NV8 # 1.1 TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND +0BF3..0BFA ; valid ; ; NV8 # 4.0 TAMIL DAY SIGN..TAMIL NUMBER SIGN +0BFB..0BFF ; disallowed # NA .. +0C00 ; valid # 7.0 TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01..0C03 ; valid # 1.1 TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C04 ; disallowed # NA +0C05..0C0C ; valid # 1.1 TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0D ; disallowed # NA +0C0E..0C10 ; valid # 1.1 TELUGU LETTER E..TELUGU LETTER AI +0C11 ; disallowed # NA +0C12..0C28 ; valid # 1.1 TELUGU LETTER O..TELUGU LETTER NA +0C29 ; disallowed # NA +0C2A..0C33 ; valid # 1.1 TELUGU LETTER PA..TELUGU LETTER LLA +0C34 ; valid # 7.0 TELUGU LETTER LLLA +0C35..0C39 ; valid # 1.1 TELUGU LETTER VA..TELUGU LETTER HA +0C3A..0C3C ; disallowed # NA .. +0C3D ; valid # 5.1 TELUGU SIGN AVAGRAHA +0C3E..0C44 ; valid # 1.1 TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN VOCALIC RR +0C45 ; disallowed # NA +0C46..0C48 ; valid # 1.1 TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C49 ; disallowed # NA +0C4A..0C4D ; valid # 1.1 TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C4E..0C54 ; disallowed # NA .. +0C55..0C56 ; valid # 1.1 TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C57 ; disallowed # NA +0C58..0C59 ; valid # 5.1 TELUGU LETTER TSA..TELUGU LETTER DZA +0C5A ; valid # 8.0 TELUGU LETTER RRRA +0C5B..0C5F ; disallowed # NA .. +0C60..0C61 ; valid # 1.1 TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C62..0C63 ; valid # 5.1 TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +0C64..0C65 ; disallowed # NA .. +0C66..0C6F ; valid # 1.1 TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0C70..0C77 ; disallowed # NA .. +0C78..0C7F ; valid ; ; NV8 # 5.1 TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU SIGN TUUMU +0C80 ; valid # 9.0 KANNADA SIGN SPACING CANDRABINDU +0C81 ; valid # 7.0 KANNADA SIGN CANDRABINDU +0C82..0C83 ; valid # 1.1 KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0C84 ; disallowed # NA +0C85..0C8C ; valid # 1.1 KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8D ; disallowed # NA +0C8E..0C90 ; valid # 1.1 KANNADA LETTER E..KANNADA LETTER AI +0C91 ; disallowed # NA +0C92..0CA8 ; valid # 1.1 KANNADA LETTER O..KANNADA LETTER NA +0CA9 ; disallowed # NA +0CAA..0CB3 ; valid # 1.1 KANNADA LETTER PA..KANNADA LETTER LLA +0CB4 ; disallowed # NA +0CB5..0CB9 ; valid # 1.1 KANNADA LETTER VA..KANNADA LETTER HA +0CBA..0CBB ; disallowed # NA .. +0CBC..0CBD ; valid # 4.0 KANNADA SIGN NUKTA..KANNADA SIGN AVAGRAHA +0CBE..0CC4 ; valid # 1.1 KANNADA VOWEL SIGN AA..KANNADA VOWEL SIGN VOCALIC RR +0CC5 ; disallowed # NA +0CC6..0CC8 ; valid # 1.1 KANNADA VOWEL SIGN E..KANNADA VOWEL SIGN AI +0CC9 ; disallowed # NA +0CCA..0CCD ; valid # 1.1 KANNADA VOWEL SIGN O..KANNADA SIGN VIRAMA +0CCE..0CD4 ; disallowed # NA .. +0CD5..0CD6 ; valid # 1.1 KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0CD7..0CDD ; disallowed # NA .. +0CDE ; valid # 1.1 KANNADA LETTER FA +0CDF ; disallowed # NA +0CE0..0CE1 ; valid # 1.1 KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0CE2..0CE3 ; valid # 5.0 KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL +0CE4..0CE5 ; disallowed # NA .. +0CE6..0CEF ; valid # 1.1 KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0CF0 ; disallowed # NA +0CF1..0CF2 ; valid # 5.0 KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA +0CF3..0CFF ; disallowed # NA .. +0D00 ; valid # 10.0 MALAYALAM SIGN COMBINING ANUSVARA ABOVE +0D01 ; valid # 7.0 MALAYALAM SIGN CANDRABINDU +0D02..0D03 ; valid # 1.1 MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D04 ; disallowed # NA +0D05..0D0C ; valid # 1.1 MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L +0D0D ; disallowed # NA +0D0E..0D10 ; valid # 1.1 MALAYALAM LETTER E..MALAYALAM LETTER AI +0D11 ; disallowed # NA +0D12..0D28 ; valid # 1.1 MALAYALAM LETTER O..MALAYALAM LETTER NA +0D29 ; valid # 6.0 MALAYALAM LETTER NNNA +0D2A..0D39 ; valid # 1.1 MALAYALAM LETTER PA..MALAYALAM LETTER HA +0D3A ; valid # 6.0 MALAYALAM LETTER TTTA +0D3B..0D3C ; valid # 10.0 MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +0D3D ; valid # 5.1 MALAYALAM SIGN AVAGRAHA +0D3E..0D43 ; valid # 1.1 MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN VOCALIC R +0D44 ; valid # 5.1 MALAYALAM VOWEL SIGN VOCALIC RR +0D45 ; disallowed # NA +0D46..0D48 ; valid # 1.1 MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D49 ; disallowed # NA +0D4A..0D4D ; valid # 1.1 MALAYALAM VOWEL SIGN O..MALAYALAM SIGN VIRAMA +0D4E ; valid # 6.0 MALAYALAM LETTER DOT REPH +0D4F ; valid ; ; NV8 # 9.0 MALAYALAM SIGN PARA +0D50..0D53 ; disallowed # NA .. +0D54..0D56 ; valid # 9.0 MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL +0D57 ; valid # 1.1 MALAYALAM AU LENGTH MARK +0D58..0D5E ; valid ; ; NV8 # 9.0 MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH +0D5F ; valid # 8.0 MALAYALAM LETTER ARCHAIC II +0D60..0D61 ; valid # 1.1 MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL +0D62..0D63 ; valid # 5.1 MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL +0D64..0D65 ; disallowed # NA .. +0D66..0D6F ; valid # 1.1 MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0D70..0D75 ; valid ; ; NV8 # 5.1 MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D76..0D78 ; valid ; ; NV8 # 9.0 MALAYALAM FRACTION ONE SIXTEENTH..MALAYALAM FRACTION THREE SIXTEENTHS +0D79 ; valid ; ; NV8 # 5.1 MALAYALAM DATE MARK +0D7A..0D7F ; valid # 5.1 MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K +0D80..0D81 ; disallowed # NA .. +0D82..0D83 ; valid # 3.0 SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0D84 ; disallowed # NA +0D85..0D96 ; valid # 3.0 SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D97..0D99 ; disallowed # NA .. +0D9A..0DB1 ; valid # 3.0 SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB2 ; disallowed # NA +0DB3..0DBB ; valid # 3.0 SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBC ; disallowed # NA +0DBD ; valid # 3.0 SINHALA LETTER DANTAJA LAYANNA +0DBE..0DBF ; disallowed # NA .. +0DC0..0DC6 ; valid # 3.0 SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0DC7..0DC9 ; disallowed # NA .. +0DCA ; valid # 3.0 SINHALA SIGN AL-LAKUNA +0DCB..0DCE ; disallowed # NA .. +0DCF..0DD4 ; valid # 3.0 SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD5 ; disallowed # NA +0DD6 ; valid # 3.0 SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD7 ; disallowed # NA +0DD8..0DDF ; valid # 3.0 SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DE0..0DE5 ; disallowed # NA .. +0DE6..0DEF ; valid # 7.0 SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE +0DF0..0DF1 ; disallowed # NA .. +0DF2..0DF3 ; valid # 3.0 SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0DF4 ; valid ; ; NV8 # 3.0 SINHALA PUNCTUATION KUNDDALIYA +0DF5..0E00 ; disallowed # NA .. +0E01..0E32 ; valid # 1.1 THAI CHARACTER KO KAI..THAI CHARACTER SARA AA +0E33 ; mapped ; 0E4D 0E32 # 1.1 THAI CHARACTER SARA AM +0E34..0E3A ; valid # 1.1 THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E3B..0E3E ; disallowed # NA .. +0E3F ; valid ; ; NV8 # 1.1 THAI CURRENCY SYMBOL BAHT +0E40..0E4E ; valid # 1.1 THAI CHARACTER SARA E..THAI CHARACTER YAMAKKAN +0E4F ; valid ; ; NV8 # 1.1 THAI CHARACTER FONGMAN +0E50..0E59 ; valid # 1.1 THAI DIGIT ZERO..THAI DIGIT NINE +0E5A..0E5B ; valid ; ; NV8 # 1.1 THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT +0E5C..0E80 ; disallowed # NA .. +0E81..0E82 ; valid # 1.1 LAO LETTER KO..LAO LETTER KHO SUNG +0E83 ; disallowed # NA +0E84 ; valid # 1.1 LAO LETTER KHO TAM +0E85..0E86 ; disallowed # NA .. +0E87..0E88 ; valid # 1.1 LAO LETTER NGO..LAO LETTER CO +0E89 ; disallowed # NA +0E8A ; valid # 1.1 LAO LETTER SO TAM +0E8B..0E8C ; disallowed # NA .. +0E8D ; valid # 1.1 LAO LETTER NYO +0E8E..0E93 ; disallowed # NA .. +0E94..0E97 ; valid # 1.1 LAO LETTER DO..LAO LETTER THO TAM +0E98 ; disallowed # NA +0E99..0E9F ; valid # 1.1 LAO LETTER NO..LAO LETTER FO SUNG +0EA0 ; disallowed # NA +0EA1..0EA3 ; valid # 1.1 LAO LETTER MO..LAO LETTER LO LING +0EA4 ; disallowed # NA +0EA5 ; valid # 1.1 LAO LETTER LO LOOT +0EA6 ; disallowed # NA +0EA7 ; valid # 1.1 LAO LETTER WO +0EA8..0EA9 ; disallowed # NA .. +0EAA..0EAB ; valid # 1.1 LAO LETTER SO SUNG..LAO LETTER HO SUNG +0EAC ; disallowed # NA +0EAD..0EB2 ; valid # 1.1 LAO LETTER O..LAO VOWEL SIGN AA +0EB3 ; mapped ; 0ECD 0EB2 # 1.1 LAO VOWEL SIGN AM +0EB4..0EB9 ; valid # 1.1 LAO VOWEL SIGN I..LAO VOWEL SIGN UU +0EBA ; disallowed # NA +0EBB..0EBD ; valid # 1.1 LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN NYO +0EBE..0EBF ; disallowed # NA .. +0EC0..0EC4 ; valid # 1.1 LAO VOWEL SIGN E..LAO VOWEL SIGN AI +0EC5 ; disallowed # NA +0EC6 ; valid # 1.1 LAO KO LA +0EC7 ; disallowed # NA +0EC8..0ECD ; valid # 1.1 LAO TONE MAI EK..LAO NIGGAHITA +0ECE..0ECF ; disallowed # NA .. +0ED0..0ED9 ; valid # 1.1 LAO DIGIT ZERO..LAO DIGIT NINE +0EDA..0EDB ; disallowed # NA .. +0EDC ; mapped ; 0EAB 0E99 # 1.1 LAO HO NO +0EDD ; mapped ; 0EAB 0EA1 # 1.1 LAO HO MO +0EDE..0EDF ; valid # 6.1 LAO LETTER KHMU GO..LAO LETTER KHMU NYO +0EE0..0EFF ; disallowed # NA .. +0F00 ; valid # 2.0 TIBETAN SYLLABLE OM +0F01..0F0A ; valid ; ; NV8 # 2.0 TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK BKA- SHOG YIG MGO +0F0B ; valid # 2.0 TIBETAN MARK INTERSYLLABIC TSHEG +0F0C ; mapped ; 0F0B # 2.0 TIBETAN MARK DELIMITER TSHEG BSTAR +0F0D..0F17 ; valid ; ; NV8 # 2.0 TIBETAN MARK SHAD..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F18..0F19 ; valid # 2.0 TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F1A..0F1F ; valid ; ; NV8 # 2.0 TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG +0F20..0F29 ; valid # 2.0 TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +0F2A..0F34 ; valid ; ; NV8 # 2.0 TIBETAN DIGIT HALF ONE..TIBETAN MARK BSDUS RTAGS +0F35 ; valid # 2.0 TIBETAN MARK NGAS BZUNG NYI ZLA +0F36 ; valid ; ; NV8 # 2.0 TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F37 ; valid # 2.0 TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F38 ; valid ; ; NV8 # 2.0 TIBETAN MARK CHE MGO +0F39 ; valid # 2.0 TIBETAN MARK TSA -PHRU +0F3A..0F3D ; valid ; ; NV8 # 2.0 TIBETAN MARK GUG RTAGS GYON..TIBETAN MARK ANG KHANG GYAS +0F3E..0F42 ; valid # 2.0 TIBETAN SIGN YAR TSHES..TIBETAN LETTER GA +0F43 ; mapped ; 0F42 0FB7 # 2.0 TIBETAN LETTER GHA +0F44..0F47 ; valid # 2.0 TIBETAN LETTER NGA..TIBETAN LETTER JA +0F48 ; disallowed # NA +0F49..0F4C ; valid # 2.0 TIBETAN LETTER NYA..TIBETAN LETTER DDA +0F4D ; mapped ; 0F4C 0FB7 # 2.0 TIBETAN LETTER DDHA +0F4E..0F51 ; valid # 2.0 TIBETAN LETTER NNA..TIBETAN LETTER DA +0F52 ; mapped ; 0F51 0FB7 # 2.0 TIBETAN LETTER DHA +0F53..0F56 ; valid # 2.0 TIBETAN LETTER NA..TIBETAN LETTER BA +0F57 ; mapped ; 0F56 0FB7 # 2.0 TIBETAN LETTER BHA +0F58..0F5B ; valid # 2.0 TIBETAN LETTER MA..TIBETAN LETTER DZA +0F5C ; mapped ; 0F5B 0FB7 # 2.0 TIBETAN LETTER DZHA +0F5D..0F68 ; valid # 2.0 TIBETAN LETTER WA..TIBETAN LETTER A +0F69 ; mapped ; 0F40 0FB5 # 2.0 TIBETAN LETTER KSSA +0F6A ; valid # 3.0 TIBETAN LETTER FIXED-FORM RA +0F6B..0F6C ; valid # 5.1 TIBETAN LETTER KKA..TIBETAN LETTER RRA +0F6D..0F70 ; disallowed # NA .. +0F71..0F72 ; valid # 2.0 TIBETAN VOWEL SIGN AA..TIBETAN VOWEL SIGN I +0F73 ; mapped ; 0F71 0F72 # 2.0 TIBETAN VOWEL SIGN II +0F74 ; valid # 2.0 TIBETAN VOWEL SIGN U +0F75 ; mapped ; 0F71 0F74 # 2.0 TIBETAN VOWEL SIGN UU +0F76 ; mapped ; 0FB2 0F80 # 2.0 TIBETAN VOWEL SIGN VOCALIC R +0F77 ; mapped ; 0FB2 0F71 0F80 #2.0 TIBETAN VOWEL SIGN VOCALIC RR +0F78 ; mapped ; 0FB3 0F80 # 2.0 TIBETAN VOWEL SIGN VOCALIC L +0F79 ; mapped ; 0FB3 0F71 0F80 #2.0 TIBETAN VOWEL SIGN VOCALIC LL +0F7A..0F80 ; valid # 2.0 TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN REVERSED I +0F81 ; mapped ; 0F71 0F80 # 2.0 TIBETAN VOWEL SIGN REVERSED II +0F82..0F84 ; valid # 2.0 TIBETAN SIGN NYI ZLA NAA DA..TIBETAN MARK HALANTA +0F85 ; valid ; ; NV8 # 2.0 TIBETAN MARK PALUTA +0F86..0F8B ; valid # 2.0 TIBETAN SIGN LCI RTAGS..TIBETAN SIGN GRU MED RGYINGS +0F8C..0F8F ; valid # 6.0 TIBETAN SIGN INVERTED MCHU CAN..TIBETAN SUBJOINED SIGN INVERTED MCHU CAN +0F90..0F92 ; valid # 2.0 TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER GA +0F93 ; mapped ; 0F92 0FB7 # 2.0 TIBETAN SUBJOINED LETTER GHA +0F94..0F95 ; valid # 2.0 TIBETAN SUBJOINED LETTER NGA..TIBETAN SUBJOINED LETTER CA +0F96 ; valid # 3.0 TIBETAN SUBJOINED LETTER CHA +0F97 ; valid # 2.0 TIBETAN SUBJOINED LETTER JA +0F98 ; disallowed # NA +0F99..0F9C ; valid # 2.0 TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER DDA +0F9D ; mapped ; 0F9C 0FB7 # 2.0 TIBETAN SUBJOINED LETTER DDHA +0F9E..0FA1 ; valid # 2.0 TIBETAN SUBJOINED LETTER NNA..TIBETAN SUBJOINED LETTER DA +0FA2 ; mapped ; 0FA1 0FB7 # 2.0 TIBETAN SUBJOINED LETTER DHA +0FA3..0FA6 ; valid # 2.0 TIBETAN SUBJOINED LETTER NA..TIBETAN SUBJOINED LETTER BA +0FA7 ; mapped ; 0FA6 0FB7 # 2.0 TIBETAN SUBJOINED LETTER BHA +0FA8..0FAB ; valid # 2.0 TIBETAN SUBJOINED LETTER MA..TIBETAN SUBJOINED LETTER DZA +0FAC ; mapped ; 0FAB 0FB7 # 2.0 TIBETAN SUBJOINED LETTER DZHA +0FAD ; valid # 2.0 TIBETAN SUBJOINED LETTER WA +0FAE..0FB0 ; valid # 3.0 TIBETAN SUBJOINED LETTER ZHA..TIBETAN SUBJOINED LETTER -A +0FB1..0FB7 ; valid # 2.0 TIBETAN SUBJOINED LETTER YA..TIBETAN SUBJOINED LETTER HA +0FB8 ; valid # 3.0 TIBETAN SUBJOINED LETTER A +0FB9 ; mapped ; 0F90 0FB5 # 2.0 TIBETAN SUBJOINED LETTER KSSA +0FBA..0FBC ; valid # 3.0 TIBETAN SUBJOINED LETTER FIXED-FORM WA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FBD ; disallowed # NA +0FBE..0FC5 ; valid ; ; NV8 # 3.0 TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE +0FC6 ; valid # 3.0 TIBETAN SYMBOL PADMA GDAN +0FC7..0FCC ; valid ; ; NV8 # 3.0 TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCD ; disallowed # NA +0FCE ; valid ; ; NV8 # 5.1 TIBETAN SIGN RDEL NAG RDEL DKAR +0FCF ; valid ; ; NV8 # 3.0 TIBETAN SIGN RDEL NAG GSUM +0FD0..0FD1 ; valid ; ; NV8 # 4.1 TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK MNYAM YIG GI MGO RGYAN +0FD2..0FD4 ; valid ; ; NV8 # 5.1 TIBETAN MARK NYIS TSHEG..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA +0FD5..0FD8 ; valid ; ; NV8 # 5.2 RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS +0FD9..0FDA ; valid ; ; NV8 # 6.0 TIBETAN MARK LEADING MCHAN RTAGS..TIBETAN MARK TRAILING MCHAN RTAGS +0FDB..0FFF ; disallowed # NA .. +1000..1021 ; valid # 3.0 MYANMAR LETTER KA..MYANMAR LETTER A +1022 ; valid # 5.1 MYANMAR LETTER SHAN A +1023..1027 ; valid # 3.0 MYANMAR LETTER I..MYANMAR LETTER E +1028 ; valid # 5.1 MYANMAR LETTER MON E +1029..102A ; valid # 3.0 MYANMAR LETTER O..MYANMAR LETTER AU +102B ; valid # 5.1 MYANMAR VOWEL SIGN TALL AA +102C..1032 ; valid # 3.0 MYANMAR VOWEL SIGN AA..MYANMAR VOWEL SIGN AI +1033..1035 ; valid # 5.1 MYANMAR VOWEL SIGN MON II..MYANMAR VOWEL SIGN E ABOVE +1036..1039 ; valid # 3.0 MYANMAR SIGN ANUSVARA..MYANMAR SIGN VIRAMA +103A..103F ; valid # 5.1 MYANMAR SIGN ASAT..MYANMAR LETTER GREAT SA +1040..1049 ; valid # 3.0 MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +104A..104F ; valid ; ; NV8 # 3.0 MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE +1050..1059 ; valid # 3.0 MYANMAR LETTER SHA..MYANMAR VOWEL SIGN VOCALIC LL +105A..1099 ; valid # 5.1 MYANMAR LETTER MON NGA..MYANMAR SHAN DIGIT NINE +109A..109D ; valid # 5.2 MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON AI +109E..109F ; valid ; ; NV8 # 5.1 MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION +10A0..10C5 ; disallowed # 1.1 GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10C6 ; disallowed # NA +10C7 ; mapped ; 2D27 # 6.1 GEORGIAN CAPITAL LETTER YN +10C8..10CC ; disallowed # NA .. +10CD ; mapped ; 2D2D # 6.1 GEORGIAN CAPITAL LETTER AEN +10CE..10CF ; disallowed # NA .. +10D0..10F6 ; valid # 1.1 GEORGIAN LETTER AN..GEORGIAN LETTER FI +10F7..10F8 ; valid # 3.2 GEORGIAN LETTER YN..GEORGIAN LETTER ELIFI +10F9..10FA ; valid # 4.1 GEORGIAN LETTER TURNED GAN..GEORGIAN LETTER AIN +10FB ; valid ; ; NV8 # 1.1 GEORGIAN PARAGRAPH SEPARATOR +10FC ; mapped ; 10DC # 4.1 MODIFIER LETTER GEORGIAN NAR +10FD..10FF ; valid # 6.1 GEORGIAN LETTER AEN..GEORGIAN LETTER LABIAL SIGN +1100..1159 ; valid ; ; NV8 # 1.1 HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH +115A..115E ; valid ; ; NV8 # 5.2 HANGUL CHOSEONG KIYEOK-TIKEUT..HANGUL CHOSEONG TIKEUT-RIEUL +115F..1160 ; disallowed # 1.1 HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER +1161..11A2 ; valid ; ; NV8 # 1.1 HANGUL JUNGSEONG A..HANGUL JUNGSEONG SSANGARAEA +11A3..11A7 ; valid ; ; NV8 # 5.2 HANGUL JUNGSEONG A-EU..HANGUL JUNGSEONG O-YAE +11A8..11F9 ; valid ; ; NV8 # 1.1 HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH +11FA..11FF ; valid ; ; NV8 # 5.2 HANGUL JONGSEONG KIYEOK-NIEUN..HANGUL JONGSEONG SSANGNIEUN +1200..1206 ; valid # 3.0 ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE HO +1207 ; valid # 4.1 ETHIOPIC SYLLABLE HOA +1208..1246 ; valid # 3.0 ETHIOPIC SYLLABLE LA..ETHIOPIC SYLLABLE QO +1247 ; valid # 4.1 ETHIOPIC SYLLABLE QOA +1248 ; valid # 3.0 ETHIOPIC SYLLABLE QWA +1249 ; disallowed # NA +124A..124D ; valid # 3.0 ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +124E..124F ; disallowed # NA .. +1250..1256 ; valid # 3.0 ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1257 ; disallowed # NA +1258 ; valid # 3.0 ETHIOPIC SYLLABLE QHWA +1259 ; disallowed # NA +125A..125D ; valid # 3.0 ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +125E..125F ; disallowed # NA .. +1260..1286 ; valid # 3.0 ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XO +1287 ; valid # 4.1 ETHIOPIC SYLLABLE XOA +1288 ; valid # 3.0 ETHIOPIC SYLLABLE XWA +1289 ; disallowed # NA +128A..128D ; valid # 3.0 ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +128E..128F ; disallowed # NA .. +1290..12AE ; valid # 3.0 ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KO +12AF ; valid # 4.1 ETHIOPIC SYLLABLE KOA +12B0 ; valid # 3.0 ETHIOPIC SYLLABLE KWA +12B1 ; disallowed # NA +12B2..12B5 ; valid # 3.0 ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B6..12B7 ; disallowed # NA .. +12B8..12BE ; valid # 3.0 ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12BF ; disallowed # NA +12C0 ; valid # 3.0 ETHIOPIC SYLLABLE KXWA +12C1 ; disallowed # NA +12C2..12C5 ; valid # 3.0 ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C6..12C7 ; disallowed # NA .. +12C8..12CE ; valid # 3.0 ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE WO +12CF ; valid # 4.1 ETHIOPIC SYLLABLE WOA +12D0..12D6 ; valid # 3.0 ETHIOPIC SYLLABLE PHARYNGEAL A..ETHIOPIC SYLLABLE PHARYNGEAL O +12D7 ; disallowed # NA +12D8..12EE ; valid # 3.0 ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE YO +12EF ; valid # 4.1 ETHIOPIC SYLLABLE YOA +12F0..130E ; valid # 3.0 ETHIOPIC SYLLABLE DA..ETHIOPIC SYLLABLE GO +130F ; valid # 4.1 ETHIOPIC SYLLABLE GOA +1310 ; valid # 3.0 ETHIOPIC SYLLABLE GWA +1311 ; disallowed # NA +1312..1315 ; valid # 3.0 ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1316..1317 ; disallowed # NA .. +1318..131E ; valid # 3.0 ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE GGO +131F ; valid # 4.1 ETHIOPIC SYLLABLE GGWAA +1320..1346 ; valid # 3.0 ETHIOPIC SYLLABLE THA..ETHIOPIC SYLLABLE TZO +1347 ; valid # 4.1 ETHIOPIC SYLLABLE TZOA +1348..135A ; valid # 3.0 ETHIOPIC SYLLABLE FA..ETHIOPIC SYLLABLE FYA +135B..135C ; disallowed # NA .. +135D..135E ; valid # 6.0 ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING VOWEL LENGTH MARK +135F ; valid # 4.1 ETHIOPIC COMBINING GEMINATION MARK +1360 ; valid ; ; NV8 # 4.1 ETHIOPIC SECTION MARK +1361..137C ; valid ; ; NV8 # 3.0 ETHIOPIC WORDSPACE..ETHIOPIC NUMBER TEN THOUSAND +137D..137F ; disallowed # NA .. +1380..138F ; valid # 4.1 ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE +1390..1399 ; valid ; ; NV8 # 4.1 ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT +139A..139F ; disallowed # NA .. +13A0..13F4 ; valid # 3.0 CHEROKEE LETTER A..CHEROKEE LETTER YV +13F5 ; valid # 8.0 CHEROKEE LETTER MV +13F6..13F7 ; disallowed # NA .. +13F8 ; mapped ; 13F0 # 8.0 CHEROKEE SMALL LETTER YE +13F9 ; mapped ; 13F1 # 8.0 CHEROKEE SMALL LETTER YI +13FA ; mapped ; 13F2 # 8.0 CHEROKEE SMALL LETTER YO +13FB ; mapped ; 13F3 # 8.0 CHEROKEE SMALL LETTER YU +13FC ; mapped ; 13F4 # 8.0 CHEROKEE SMALL LETTER YV +13FD ; mapped ; 13F5 # 8.0 CHEROKEE SMALL LETTER MV +13FE..13FF ; disallowed # NA .. +1400 ; valid ; ; NV8 # 5.2 CANADIAN SYLLABICS HYPHEN +1401..166C ; valid # 3.0 CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166D..166E ; valid ; ; NV8 # 3.0 CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP +166F..1676 ; valid # 3.0 CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA +1677..167F ; valid # 5.2 CANADIAN SYLLABICS WOODS-CREE THWEE..CANADIAN SYLLABICS BLACKFOOT W +1680 ; disallowed # 3.0 OGHAM SPACE MARK +1681..169A ; valid # 3.0 OGHAM LETTER BEITH..OGHAM LETTER PEITH +169B..169C ; valid ; ; NV8 # 3.0 OGHAM FEATHER MARK..OGHAM REVERSED FEATHER MARK +169D..169F ; disallowed # NA .. +16A0..16EA ; valid # 3.0 RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X +16EB..16F0 ; valid ; ; NV8 # 3.0 RUNIC SINGLE PUNCTUATION..RUNIC BELGTHOR SYMBOL +16F1..16F8 ; valid # 7.0 RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC +16F9..16FF ; disallowed # NA .. +1700..170C ; valid # 3.2 TAGALOG LETTER A..TAGALOG LETTER YA +170D ; disallowed # NA +170E..1714 ; valid # 3.2 TAGALOG LETTER LA..TAGALOG SIGN VIRAMA +1715..171F ; disallowed # NA .. +1720..1734 ; valid # 3.2 HANUNOO LETTER A..HANUNOO SIGN PAMUDPOD +1735..1736 ; valid ; ; NV8 # 3.2 PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +1737..173F ; disallowed # NA .. +1740..1753 ; valid # 3.2 BUHID LETTER A..BUHID VOWEL SIGN U +1754..175F ; disallowed # NA .. +1760..176C ; valid # 3.2 TAGBANWA LETTER A..TAGBANWA LETTER YA +176D ; disallowed # NA +176E..1770 ; valid # 3.2 TAGBANWA LETTER LA..TAGBANWA LETTER SA +1771 ; disallowed # NA +1772..1773 ; valid # 3.2 TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +1774..177F ; disallowed # NA .. +1780..17B3 ; valid # 3.0 KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU +17B4..17B5 ; disallowed # 3.0 KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA +17B6..17D3 ; valid # 3.0 KHMER VOWEL SIGN AA..KHMER SIGN BATHAMASAT +17D4..17D6 ; valid ; ; NV8 # 3.0 KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH +17D7 ; valid # 3.0 KHMER SIGN LEK TOO +17D8..17DB ; valid ; ; NV8 # 3.0 KHMER SIGN BEYYAL..KHMER CURRENCY SYMBOL RIEL +17DC ; valid # 3.0 KHMER SIGN AVAKRAHASANYA +17DD ; valid # 4.0 KHMER SIGN ATTHACAN +17DE..17DF ; disallowed # NA .. +17E0..17E9 ; valid # 3.0 KHMER DIGIT ZERO..KHMER DIGIT NINE +17EA..17EF ; disallowed # NA .. +17F0..17F9 ; valid ; ; NV8 # 4.0 KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON +17FA..17FF ; disallowed # NA .. +1800..1805 ; valid ; ; NV8 # 3.0 MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS +1806 ; disallowed # 3.0 MONGOLIAN TODO SOFT HYPHEN +1807..180A ; valid ; ; NV8 # 3.0 MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU +180B..180D ; ignored # 3.0 MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +180E ; disallowed # 3.0 MONGOLIAN VOWEL SEPARATOR +180F ; disallowed # NA +1810..1819 ; valid # 3.0 MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +181A..181F ; disallowed # NA .. +1820..1877 ; valid # 3.0 MONGOLIAN LETTER A..MONGOLIAN LETTER MANCHU ZHA +1878..187F ; disallowed # NA .. +1880..18A9 ; valid # 3.0 MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI DAGALGA +18AA ; valid # 5.1 MONGOLIAN LETTER MANCHU ALI GALI LHA +18AB..18AF ; disallowed # NA .. +18B0..18F5 ; valid # 5.2 CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S +18F6..18FF ; disallowed # NA .. +1900..191C ; valid # 4.0 LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA +191D..191E ; valid # 7.0 LIMBU LETTER GYAN..LIMBU LETTER TRA +191F ; disallowed # NA +1920..192B ; valid # 4.0 LIMBU VOWEL SIGN A..LIMBU SUBJOINED LETTER WA +192C..192F ; disallowed # NA .. +1930..193B ; valid # 4.0 LIMBU SMALL LETTER KA..LIMBU SIGN SA-I +193C..193F ; disallowed # NA .. +1940 ; valid ; ; NV8 # 4.0 LIMBU SIGN LOO +1941..1943 ; disallowed # NA .. +1944..1945 ; valid ; ; NV8 # 4.0 LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1946..196D ; valid # 4.0 LIMBU DIGIT ZERO..TAI LE LETTER AI +196E..196F ; disallowed # NA .. +1970..1974 ; valid # 4.0 TAI LE LETTER TONE-2..TAI LE LETTER TONE-6 +1975..197F ; disallowed # NA .. +1980..19A9 ; valid # 4.1 NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW XVA +19AA..19AB ; valid # 5.2 NEW TAI LUE LETTER HIGH SUA..NEW TAI LUE LETTER LOW SUA +19AC..19AF ; disallowed # NA .. +19B0..19C9 ; valid # 4.1 NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE TONE MARK-2 +19CA..19CF ; disallowed # NA .. +19D0..19D9 ; valid # 4.1 NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE +19DA ; valid ; ; XV8 # 5.2 NEW TAI LUE THAM DIGIT ONE +19DB..19DD ; disallowed # NA .. +19DE..19DF ; valid ; ; NV8 # 4.1 NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV +19E0..19FF ; valid ; ; NV8 # 4.0 KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC +1A00..1A1B ; valid # 4.1 BUGINESE LETTER KA..BUGINESE VOWEL SIGN AE +1A1C..1A1D ; disallowed # NA .. +1A1E..1A1F ; valid ; ; NV8 # 4.1 BUGINESE PALLAWA..BUGINESE END OF SECTION +1A20..1A5E ; valid # 5.2 TAI THAM LETTER HIGH KA..TAI THAM CONSONANT SIGN SA +1A5F ; disallowed # NA +1A60..1A7C ; valid # 5.2 TAI THAM SIGN SAKOT..TAI THAM SIGN KHUEN-LUE KARAN +1A7D..1A7E ; disallowed # NA .. +1A7F..1A89 ; valid # 5.2 TAI THAM COMBINING CRYPTOGRAMMIC DOT..TAI THAM HORA DIGIT NINE +1A8A..1A8F ; disallowed # NA .. +1A90..1A99 ; valid # 5.2 TAI THAM THAM DIGIT ZERO..TAI THAM THAM DIGIT NINE +1A9A..1A9F ; disallowed # NA .. +1AA0..1AA6 ; valid ; ; NV8 # 5.2 TAI THAM SIGN WIANG..TAI THAM SIGN REVERSED ROTATED RANA +1AA7 ; valid # 5.2 TAI THAM SIGN MAI YAMOK +1AA8..1AAD ; valid ; ; NV8 # 5.2 TAI THAM SIGN KAAN..TAI THAM SIGN CAANG +1AAE..1AAF ; disallowed # NA .. +1AB0..1ABD ; valid # 7.0 COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW +1ABE ; valid ; ; NV8 # 7.0 COMBINING PARENTHESES OVERLAY +1ABF..1AFF ; disallowed # NA .. +1B00..1B4B ; valid # 5.0 BALINESE SIGN ULU RICEM..BALINESE LETTER ASYURA SASAK +1B4C..1B4F ; disallowed # NA .. +1B50..1B59 ; valid # 5.0 BALINESE DIGIT ZERO..BALINESE DIGIT NINE +1B5A..1B6A ; valid ; ; NV8 # 5.0 BALINESE PANTI..BALINESE MUSICAL SYMBOL DANG GEDE +1B6B..1B73 ; valid # 5.0 BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +1B74..1B7C ; valid ; ; NV8 # 5.0 BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING +1B7D..1B7F ; disallowed # NA .. +1B80..1BAA ; valid # 5.1 SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PAMAAEH +1BAB..1BAD ; valid # 6.1 SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA +1BAE..1BB9 ; valid # 5.1 SUNDANESE LETTER KHA..SUNDANESE DIGIT NINE +1BBA..1BBF ; valid # 6.1 SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M +1BC0..1BF3 ; valid # 6.0 BATAK LETTER A..BATAK PANONGONAN +1BF4..1BFB ; disallowed # NA .. +1BFC..1BFF ; valid ; ; NV8 # 6.0 BATAK SYMBOL BINDU NA METEK..BATAK SYMBOL BINDU PANGOLAT +1C00..1C37 ; valid # 5.1 LEPCHA LETTER KA..LEPCHA SIGN NUKTA +1C38..1C3A ; disallowed # NA .. +1C3B..1C3F ; valid ; ; NV8 # 5.1 LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK +1C40..1C49 ; valid # 5.1 LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE +1C4A..1C4C ; disallowed # NA .. +1C4D..1C7D ; valid # 5.1 LEPCHA LETTER TTA..OL CHIKI AHAD +1C7E..1C7F ; valid ; ; NV8 # 5.1 OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80 ; mapped ; 0432 # 9.0 CYRILLIC SMALL LETTER ROUNDED VE +1C81 ; mapped ; 0434 # 9.0 CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82 ; mapped ; 043E # 9.0 CYRILLIC SMALL LETTER NARROW O +1C83 ; mapped ; 0441 # 9.0 CYRILLIC SMALL LETTER WIDE ES +1C84..1C85 ; mapped ; 0442 # 9.0 CYRILLIC SMALL LETTER TALL TE..CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86 ; mapped ; 044A # 9.0 CYRILLIC SMALL LETTER TALL HARD SIGN +1C87 ; mapped ; 0463 # 9.0 CYRILLIC SMALL LETTER TALL YAT +1C88 ; mapped ; A64B # 9.0 CYRILLIC SMALL LETTER UNBLENDED UK +1C89..1CBF ; disallowed # NA .. +1CC0..1CC7 ; valid ; ; NV8 # 6.1 SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA +1CC8..1CCF ; disallowed # NA .. +1CD0..1CD2 ; valid # 5.2 VEDIC TONE KARSHANA..VEDIC TONE PRENKHA +1CD3 ; valid ; ; NV8 # 5.2 VEDIC SIGN NIHSHVASA +1CD4..1CF2 ; valid # 5.2 VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC SIGN ARDHAVISARGA +1CF3..1CF6 ; valid # 6.1 VEDIC SIGN ROTATED ARDHAVISARGA..VEDIC SIGN UPADHMANIYA +1CF7 ; valid # 10.0 VEDIC SIGN ATIKRAMA +1CF8..1CF9 ; valid # 7.0 VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE +1CFA..1CFF ; disallowed # NA .. +1D00..1D2B ; valid # 4.0 LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL +1D2C ; mapped ; 0061 # 4.0 MODIFIER LETTER CAPITAL A +1D2D ; mapped ; 00E6 # 4.0 MODIFIER LETTER CAPITAL AE +1D2E ; mapped ; 0062 # 4.0 MODIFIER LETTER CAPITAL B +1D2F ; valid # 4.0 MODIFIER LETTER CAPITAL BARRED B +1D30 ; mapped ; 0064 # 4.0 MODIFIER LETTER CAPITAL D +1D31 ; mapped ; 0065 # 4.0 MODIFIER LETTER CAPITAL E +1D32 ; mapped ; 01DD # 4.0 MODIFIER LETTER CAPITAL REVERSED E +1D33 ; mapped ; 0067 # 4.0 MODIFIER LETTER CAPITAL G +1D34 ; mapped ; 0068 # 4.0 MODIFIER LETTER CAPITAL H +1D35 ; mapped ; 0069 # 4.0 MODIFIER LETTER CAPITAL I +1D36 ; mapped ; 006A # 4.0 MODIFIER LETTER CAPITAL J +1D37 ; mapped ; 006B # 4.0 MODIFIER LETTER CAPITAL K +1D38 ; mapped ; 006C # 4.0 MODIFIER LETTER CAPITAL L +1D39 ; mapped ; 006D # 4.0 MODIFIER LETTER CAPITAL M +1D3A ; mapped ; 006E # 4.0 MODIFIER LETTER CAPITAL N +1D3B ; valid # 4.0 MODIFIER LETTER CAPITAL REVERSED N +1D3C ; mapped ; 006F # 4.0 MODIFIER LETTER CAPITAL O +1D3D ; mapped ; 0223 # 4.0 MODIFIER LETTER CAPITAL OU +1D3E ; mapped ; 0070 # 4.0 MODIFIER LETTER CAPITAL P +1D3F ; mapped ; 0072 # 4.0 MODIFIER LETTER CAPITAL R +1D40 ; mapped ; 0074 # 4.0 MODIFIER LETTER CAPITAL T +1D41 ; mapped ; 0075 # 4.0 MODIFIER LETTER CAPITAL U +1D42 ; mapped ; 0077 # 4.0 MODIFIER LETTER CAPITAL W +1D43 ; mapped ; 0061 # 4.0 MODIFIER LETTER SMALL A +1D44 ; mapped ; 0250 # 4.0 MODIFIER LETTER SMALL TURNED A +1D45 ; mapped ; 0251 # 4.0 MODIFIER LETTER SMALL ALPHA +1D46 ; mapped ; 1D02 # 4.0 MODIFIER LETTER SMALL TURNED AE +1D47 ; mapped ; 0062 # 4.0 MODIFIER LETTER SMALL B +1D48 ; mapped ; 0064 # 4.0 MODIFIER LETTER SMALL D +1D49 ; mapped ; 0065 # 4.0 MODIFIER LETTER SMALL E +1D4A ; mapped ; 0259 # 4.0 MODIFIER LETTER SMALL SCHWA +1D4B ; mapped ; 025B # 4.0 MODIFIER LETTER SMALL OPEN E +1D4C ; mapped ; 025C # 4.0 MODIFIER LETTER SMALL TURNED OPEN E +1D4D ; mapped ; 0067 # 4.0 MODIFIER LETTER SMALL G +1D4E ; valid # 4.0 MODIFIER LETTER SMALL TURNED I +1D4F ; mapped ; 006B # 4.0 MODIFIER LETTER SMALL K +1D50 ; mapped ; 006D # 4.0 MODIFIER LETTER SMALL M +1D51 ; mapped ; 014B # 4.0 MODIFIER LETTER SMALL ENG +1D52 ; mapped ; 006F # 4.0 MODIFIER LETTER SMALL O +1D53 ; mapped ; 0254 # 4.0 MODIFIER LETTER SMALL OPEN O +1D54 ; mapped ; 1D16 # 4.0 MODIFIER LETTER SMALL TOP HALF O +1D55 ; mapped ; 1D17 # 4.0 MODIFIER LETTER SMALL BOTTOM HALF O +1D56 ; mapped ; 0070 # 4.0 MODIFIER LETTER SMALL P +1D57 ; mapped ; 0074 # 4.0 MODIFIER LETTER SMALL T +1D58 ; mapped ; 0075 # 4.0 MODIFIER LETTER SMALL U +1D59 ; mapped ; 1D1D # 4.0 MODIFIER LETTER SMALL SIDEWAYS U +1D5A ; mapped ; 026F # 4.0 MODIFIER LETTER SMALL TURNED M +1D5B ; mapped ; 0076 # 4.0 MODIFIER LETTER SMALL V +1D5C ; mapped ; 1D25 # 4.0 MODIFIER LETTER SMALL AIN +1D5D ; mapped ; 03B2 # 4.0 MODIFIER LETTER SMALL BETA +1D5E ; mapped ; 03B3 # 4.0 MODIFIER LETTER SMALL GREEK GAMMA +1D5F ; mapped ; 03B4 # 4.0 MODIFIER LETTER SMALL DELTA +1D60 ; mapped ; 03C6 # 4.0 MODIFIER LETTER SMALL GREEK PHI +1D61 ; mapped ; 03C7 # 4.0 MODIFIER LETTER SMALL CHI +1D62 ; mapped ; 0069 # 4.0 LATIN SUBSCRIPT SMALL LETTER I +1D63 ; mapped ; 0072 # 4.0 LATIN SUBSCRIPT SMALL LETTER R +1D64 ; mapped ; 0075 # 4.0 LATIN SUBSCRIPT SMALL LETTER U +1D65 ; mapped ; 0076 # 4.0 LATIN SUBSCRIPT SMALL LETTER V +1D66 ; mapped ; 03B2 # 4.0 GREEK SUBSCRIPT SMALL LETTER BETA +1D67 ; mapped ; 03B3 # 4.0 GREEK SUBSCRIPT SMALL LETTER GAMMA +1D68 ; mapped ; 03C1 # 4.0 GREEK SUBSCRIPT SMALL LETTER RHO +1D69 ; mapped ; 03C6 # 4.0 GREEK SUBSCRIPT SMALL LETTER PHI +1D6A ; mapped ; 03C7 # 4.0 GREEK SUBSCRIPT SMALL LETTER CHI +1D6B ; valid # 4.0 LATIN SMALL LETTER UE +1D6C..1D77 ; valid # 4.1 LATIN SMALL LETTER B WITH MIDDLE TILDE..LATIN SMALL LETTER TURNED G +1D78 ; mapped ; 043D # 4.1 MODIFIER LETTER CYRILLIC EN +1D79..1D9A ; valid # 4.1 LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +1D9B ; mapped ; 0252 # 4.1 MODIFIER LETTER SMALL TURNED ALPHA +1D9C ; mapped ; 0063 # 4.1 MODIFIER LETTER SMALL C +1D9D ; mapped ; 0255 # 4.1 MODIFIER LETTER SMALL C WITH CURL +1D9E ; mapped ; 00F0 # 4.1 MODIFIER LETTER SMALL ETH +1D9F ; mapped ; 025C # 4.1 MODIFIER LETTER SMALL REVERSED OPEN E +1DA0 ; mapped ; 0066 # 4.1 MODIFIER LETTER SMALL F +1DA1 ; mapped ; 025F # 4.1 MODIFIER LETTER SMALL DOTLESS J WITH STROKE +1DA2 ; mapped ; 0261 # 4.1 MODIFIER LETTER SMALL SCRIPT G +1DA3 ; mapped ; 0265 # 4.1 MODIFIER LETTER SMALL TURNED H +1DA4 ; mapped ; 0268 # 4.1 MODIFIER LETTER SMALL I WITH STROKE +1DA5 ; mapped ; 0269 # 4.1 MODIFIER LETTER SMALL IOTA +1DA6 ; mapped ; 026A # 4.1 MODIFIER LETTER SMALL CAPITAL I +1DA7 ; mapped ; 1D7B # 4.1 MODIFIER LETTER SMALL CAPITAL I WITH STROKE +1DA8 ; mapped ; 029D # 4.1 MODIFIER LETTER SMALL J WITH CROSSED-TAIL +1DA9 ; mapped ; 026D # 4.1 MODIFIER LETTER SMALL L WITH RETROFLEX HOOK +1DAA ; mapped ; 1D85 # 4.1 MODIFIER LETTER SMALL L WITH PALATAL HOOK +1DAB ; mapped ; 029F # 4.1 MODIFIER LETTER SMALL CAPITAL L +1DAC ; mapped ; 0271 # 4.1 MODIFIER LETTER SMALL M WITH HOOK +1DAD ; mapped ; 0270 # 4.1 MODIFIER LETTER SMALL TURNED M WITH LONG LEG +1DAE ; mapped ; 0272 # 4.1 MODIFIER LETTER SMALL N WITH LEFT HOOK +1DAF ; mapped ; 0273 # 4.1 MODIFIER LETTER SMALL N WITH RETROFLEX HOOK +1DB0 ; mapped ; 0274 # 4.1 MODIFIER LETTER SMALL CAPITAL N +1DB1 ; mapped ; 0275 # 4.1 MODIFIER LETTER SMALL BARRED O +1DB2 ; mapped ; 0278 # 4.1 MODIFIER LETTER SMALL PHI +1DB3 ; mapped ; 0282 # 4.1 MODIFIER LETTER SMALL S WITH HOOK +1DB4 ; mapped ; 0283 # 4.1 MODIFIER LETTER SMALL ESH +1DB5 ; mapped ; 01AB # 4.1 MODIFIER LETTER SMALL T WITH PALATAL HOOK +1DB6 ; mapped ; 0289 # 4.1 MODIFIER LETTER SMALL U BAR +1DB7 ; mapped ; 028A # 4.1 MODIFIER LETTER SMALL UPSILON +1DB8 ; mapped ; 1D1C # 4.1 MODIFIER LETTER SMALL CAPITAL U +1DB9 ; mapped ; 028B # 4.1 MODIFIER LETTER SMALL V WITH HOOK +1DBA ; mapped ; 028C # 4.1 MODIFIER LETTER SMALL TURNED V +1DBB ; mapped ; 007A # 4.1 MODIFIER LETTER SMALL Z +1DBC ; mapped ; 0290 # 4.1 MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK +1DBD ; mapped ; 0291 # 4.1 MODIFIER LETTER SMALL Z WITH CURL +1DBE ; mapped ; 0292 # 4.1 MODIFIER LETTER SMALL EZH +1DBF ; mapped ; 03B8 # 4.1 MODIFIER LETTER SMALL THETA +1DC0..1DC3 ; valid # 4.1 COMBINING DOTTED GRAVE ACCENT..COMBINING SUSPENSION MARK +1DC4..1DCA ; valid # 5.0 COMBINING MACRON-ACUTE..COMBINING LATIN SMALL LETTER R BELOW +1DCB..1DE6 ; valid # 5.1 COMBINING BREVE-MACRON..COMBINING LATIN SMALL LETTER Z +1DE7..1DF5 ; valid # 7.0 COMBINING LATIN SMALL LETTER ALPHA..COMBINING UP TACK ABOVE +1DF6..1DF9 ; valid # 10.0 COMBINING KAVYKA ABOVE RIGHT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFA ; disallowed # NA +1DFB ; valid # 9.0 COMBINING DELETION MARK +1DFC ; valid # 6.0 COMBINING DOUBLE INVERTED BREVE BELOW +1DFD ; valid # 5.2 COMBINING ALMOST EQUAL TO BELOW +1DFE..1DFF ; valid # 5.0 COMBINING LEFT ARROWHEAD ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1E00 ; mapped ; 1E01 # 1.1 LATIN CAPITAL LETTER A WITH RING BELOW +1E01 ; valid # 1.1 LATIN SMALL LETTER A WITH RING BELOW +1E02 ; mapped ; 1E03 # 1.1 LATIN CAPITAL LETTER B WITH DOT ABOVE +1E03 ; valid # 1.1 LATIN SMALL LETTER B WITH DOT ABOVE +1E04 ; mapped ; 1E05 # 1.1 LATIN CAPITAL LETTER B WITH DOT BELOW +1E05 ; valid # 1.1 LATIN SMALL LETTER B WITH DOT BELOW +1E06 ; mapped ; 1E07 # 1.1 LATIN CAPITAL LETTER B WITH LINE BELOW +1E07 ; valid # 1.1 LATIN SMALL LETTER B WITH LINE BELOW +1E08 ; mapped ; 1E09 # 1.1 LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E09 ; valid # 1.1 LATIN SMALL LETTER C WITH CEDILLA AND ACUTE +1E0A ; mapped ; 1E0B # 1.1 LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0B ; valid # 1.1 LATIN SMALL LETTER D WITH DOT ABOVE +1E0C ; mapped ; 1E0D # 1.1 LATIN CAPITAL LETTER D WITH DOT BELOW +1E0D ; valid # 1.1 LATIN SMALL LETTER D WITH DOT BELOW +1E0E ; mapped ; 1E0F # 1.1 LATIN CAPITAL LETTER D WITH LINE BELOW +1E0F ; valid # 1.1 LATIN SMALL LETTER D WITH LINE BELOW +1E10 ; mapped ; 1E11 # 1.1 LATIN CAPITAL LETTER D WITH CEDILLA +1E11 ; valid # 1.1 LATIN SMALL LETTER D WITH CEDILLA +1E12 ; mapped ; 1E13 # 1.1 LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E13 ; valid # 1.1 LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW +1E14 ; mapped ; 1E15 # 1.1 LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E15 ; valid # 1.1 LATIN SMALL LETTER E WITH MACRON AND GRAVE +1E16 ; mapped ; 1E17 # 1.1 LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E17 ; valid # 1.1 LATIN SMALL LETTER E WITH MACRON AND ACUTE +1E18 ; mapped ; 1E19 # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E19 ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW +1E1A ; mapped ; 1E1B # 1.1 LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1B ; valid # 1.1 LATIN SMALL LETTER E WITH TILDE BELOW +1E1C ; mapped ; 1E1D # 1.1 LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1D ; valid # 1.1 LATIN SMALL LETTER E WITH CEDILLA AND BREVE +1E1E ; mapped ; 1E1F # 1.1 LATIN CAPITAL LETTER F WITH DOT ABOVE +1E1F ; valid # 1.1 LATIN SMALL LETTER F WITH DOT ABOVE +1E20 ; mapped ; 1E21 # 1.1 LATIN CAPITAL LETTER G WITH MACRON +1E21 ; valid # 1.1 LATIN SMALL LETTER G WITH MACRON +1E22 ; mapped ; 1E23 # 1.1 LATIN CAPITAL LETTER H WITH DOT ABOVE +1E23 ; valid # 1.1 LATIN SMALL LETTER H WITH DOT ABOVE +1E24 ; mapped ; 1E25 # 1.1 LATIN CAPITAL LETTER H WITH DOT BELOW +1E25 ; valid # 1.1 LATIN SMALL LETTER H WITH DOT BELOW +1E26 ; mapped ; 1E27 # 1.1 LATIN CAPITAL LETTER H WITH DIAERESIS +1E27 ; valid # 1.1 LATIN SMALL LETTER H WITH DIAERESIS +1E28 ; mapped ; 1E29 # 1.1 LATIN CAPITAL LETTER H WITH CEDILLA +1E29 ; valid # 1.1 LATIN SMALL LETTER H WITH CEDILLA +1E2A ; mapped ; 1E2B # 1.1 LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2B ; valid # 1.1 LATIN SMALL LETTER H WITH BREVE BELOW +1E2C ; mapped ; 1E2D # 1.1 LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2D ; valid # 1.1 LATIN SMALL LETTER I WITH TILDE BELOW +1E2E ; mapped ; 1E2F # 1.1 LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E2F ; valid # 1.1 LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE +1E30 ; mapped ; 1E31 # 1.1 LATIN CAPITAL LETTER K WITH ACUTE +1E31 ; valid # 1.1 LATIN SMALL LETTER K WITH ACUTE +1E32 ; mapped ; 1E33 # 1.1 LATIN CAPITAL LETTER K WITH DOT BELOW +1E33 ; valid # 1.1 LATIN SMALL LETTER K WITH DOT BELOW +1E34 ; mapped ; 1E35 # 1.1 LATIN CAPITAL LETTER K WITH LINE BELOW +1E35 ; valid # 1.1 LATIN SMALL LETTER K WITH LINE BELOW +1E36 ; mapped ; 1E37 # 1.1 LATIN CAPITAL LETTER L WITH DOT BELOW +1E37 ; valid # 1.1 LATIN SMALL LETTER L WITH DOT BELOW +1E38 ; mapped ; 1E39 # 1.1 LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E39 ; valid # 1.1 LATIN SMALL LETTER L WITH DOT BELOW AND MACRON +1E3A ; mapped ; 1E3B # 1.1 LATIN CAPITAL LETTER L WITH LINE BELOW +1E3B ; valid # 1.1 LATIN SMALL LETTER L WITH LINE BELOW +1E3C ; mapped ; 1E3D # 1.1 LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3D ; valid # 1.1 LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW +1E3E ; mapped ; 1E3F # 1.1 LATIN CAPITAL LETTER M WITH ACUTE +1E3F ; valid # 1.1 LATIN SMALL LETTER M WITH ACUTE +1E40 ; mapped ; 1E41 # 1.1 LATIN CAPITAL LETTER M WITH DOT ABOVE +1E41 ; valid # 1.1 LATIN SMALL LETTER M WITH DOT ABOVE +1E42 ; mapped ; 1E43 # 1.1 LATIN CAPITAL LETTER M WITH DOT BELOW +1E43 ; valid # 1.1 LATIN SMALL LETTER M WITH DOT BELOW +1E44 ; mapped ; 1E45 # 1.1 LATIN CAPITAL LETTER N WITH DOT ABOVE +1E45 ; valid # 1.1 LATIN SMALL LETTER N WITH DOT ABOVE +1E46 ; mapped ; 1E47 # 1.1 LATIN CAPITAL LETTER N WITH DOT BELOW +1E47 ; valid # 1.1 LATIN SMALL LETTER N WITH DOT BELOW +1E48 ; mapped ; 1E49 # 1.1 LATIN CAPITAL LETTER N WITH LINE BELOW +1E49 ; valid # 1.1 LATIN SMALL LETTER N WITH LINE BELOW +1E4A ; mapped ; 1E4B # 1.1 LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4B ; valid # 1.1 LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW +1E4C ; mapped ; 1E4D # 1.1 LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4D ; valid # 1.1 LATIN SMALL LETTER O WITH TILDE AND ACUTE +1E4E ; mapped ; 1E4F # 1.1 LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E4F ; valid # 1.1 LATIN SMALL LETTER O WITH TILDE AND DIAERESIS +1E50 ; mapped ; 1E51 # 1.1 LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E51 ; valid # 1.1 LATIN SMALL LETTER O WITH MACRON AND GRAVE +1E52 ; mapped ; 1E53 # 1.1 LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E53 ; valid # 1.1 LATIN SMALL LETTER O WITH MACRON AND ACUTE +1E54 ; mapped ; 1E55 # 1.1 LATIN CAPITAL LETTER P WITH ACUTE +1E55 ; valid # 1.1 LATIN SMALL LETTER P WITH ACUTE +1E56 ; mapped ; 1E57 # 1.1 LATIN CAPITAL LETTER P WITH DOT ABOVE +1E57 ; valid # 1.1 LATIN SMALL LETTER P WITH DOT ABOVE +1E58 ; mapped ; 1E59 # 1.1 LATIN CAPITAL LETTER R WITH DOT ABOVE +1E59 ; valid # 1.1 LATIN SMALL LETTER R WITH DOT ABOVE +1E5A ; mapped ; 1E5B # 1.1 LATIN CAPITAL LETTER R WITH DOT BELOW +1E5B ; valid # 1.1 LATIN SMALL LETTER R WITH DOT BELOW +1E5C ; mapped ; 1E5D # 1.1 LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5D ; valid # 1.1 LATIN SMALL LETTER R WITH DOT BELOW AND MACRON +1E5E ; mapped ; 1E5F # 1.1 LATIN CAPITAL LETTER R WITH LINE BELOW +1E5F ; valid # 1.1 LATIN SMALL LETTER R WITH LINE BELOW +1E60 ; mapped ; 1E61 # 1.1 LATIN CAPITAL LETTER S WITH DOT ABOVE +1E61 ; valid # 1.1 LATIN SMALL LETTER S WITH DOT ABOVE +1E62 ; mapped ; 1E63 # 1.1 LATIN CAPITAL LETTER S WITH DOT BELOW +1E63 ; valid # 1.1 LATIN SMALL LETTER S WITH DOT BELOW +1E64 ; mapped ; 1E65 # 1.1 LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E65 ; valid # 1.1 LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE +1E66 ; mapped ; 1E67 # 1.1 LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E67 ; valid # 1.1 LATIN SMALL LETTER S WITH CARON AND DOT ABOVE +1E68 ; mapped ; 1E69 # 1.1 LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E69 ; valid # 1.1 LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A ; mapped ; 1E6B # 1.1 LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6B ; valid # 1.1 LATIN SMALL LETTER T WITH DOT ABOVE +1E6C ; mapped ; 1E6D # 1.1 LATIN CAPITAL LETTER T WITH DOT BELOW +1E6D ; valid # 1.1 LATIN SMALL LETTER T WITH DOT BELOW +1E6E ; mapped ; 1E6F # 1.1 LATIN CAPITAL LETTER T WITH LINE BELOW +1E6F ; valid # 1.1 LATIN SMALL LETTER T WITH LINE BELOW +1E70 ; mapped ; 1E71 # 1.1 LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E71 ; valid # 1.1 LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW +1E72 ; mapped ; 1E73 # 1.1 LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E73 ; valid # 1.1 LATIN SMALL LETTER U WITH DIAERESIS BELOW +1E74 ; mapped ; 1E75 # 1.1 LATIN CAPITAL LETTER U WITH TILDE BELOW +1E75 ; valid # 1.1 LATIN SMALL LETTER U WITH TILDE BELOW +1E76 ; mapped ; 1E77 # 1.1 LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E77 ; valid # 1.1 LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW +1E78 ; mapped ; 1E79 # 1.1 LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E79 ; valid # 1.1 LATIN SMALL LETTER U WITH TILDE AND ACUTE +1E7A ; mapped ; 1E7B # 1.1 LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7B ; valid # 1.1 LATIN SMALL LETTER U WITH MACRON AND DIAERESIS +1E7C ; mapped ; 1E7D # 1.1 LATIN CAPITAL LETTER V WITH TILDE +1E7D ; valid # 1.1 LATIN SMALL LETTER V WITH TILDE +1E7E ; mapped ; 1E7F # 1.1 LATIN CAPITAL LETTER V WITH DOT BELOW +1E7F ; valid # 1.1 LATIN SMALL LETTER V WITH DOT BELOW +1E80 ; mapped ; 1E81 # 1.1 LATIN CAPITAL LETTER W WITH GRAVE +1E81 ; valid # 1.1 LATIN SMALL LETTER W WITH GRAVE +1E82 ; mapped ; 1E83 # 1.1 LATIN CAPITAL LETTER W WITH ACUTE +1E83 ; valid # 1.1 LATIN SMALL LETTER W WITH ACUTE +1E84 ; mapped ; 1E85 # 1.1 LATIN CAPITAL LETTER W WITH DIAERESIS +1E85 ; valid # 1.1 LATIN SMALL LETTER W WITH DIAERESIS +1E86 ; mapped ; 1E87 # 1.1 LATIN CAPITAL LETTER W WITH DOT ABOVE +1E87 ; valid # 1.1 LATIN SMALL LETTER W WITH DOT ABOVE +1E88 ; mapped ; 1E89 # 1.1 LATIN CAPITAL LETTER W WITH DOT BELOW +1E89 ; valid # 1.1 LATIN SMALL LETTER W WITH DOT BELOW +1E8A ; mapped ; 1E8B # 1.1 LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8B ; valid # 1.1 LATIN SMALL LETTER X WITH DOT ABOVE +1E8C ; mapped ; 1E8D # 1.1 LATIN CAPITAL LETTER X WITH DIAERESIS +1E8D ; valid # 1.1 LATIN SMALL LETTER X WITH DIAERESIS +1E8E ; mapped ; 1E8F # 1.1 LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E8F ; valid # 1.1 LATIN SMALL LETTER Y WITH DOT ABOVE +1E90 ; mapped ; 1E91 # 1.1 LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E91 ; valid # 1.1 LATIN SMALL LETTER Z WITH CIRCUMFLEX +1E92 ; mapped ; 1E93 # 1.1 LATIN CAPITAL LETTER Z WITH DOT BELOW +1E93 ; valid # 1.1 LATIN SMALL LETTER Z WITH DOT BELOW +1E94 ; mapped ; 1E95 # 1.1 LATIN CAPITAL LETTER Z WITH LINE BELOW +1E95..1E99 ; valid # 1.1 LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER Y WITH RING ABOVE +1E9A ; mapped ; 0061 02BE # 1.1 LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B ; mapped ; 1E61 # 2.0 LATIN SMALL LETTER LONG S WITH DOT ABOVE +1E9C..1E9D ; valid # 5.1 LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE..LATIN SMALL LETTER LONG S WITH HIGH STROKE +1E9E ; mapped ; 0073 0073 # 5.1 LATIN CAPITAL LETTER SHARP S +1E9F ; valid # 5.1 LATIN SMALL LETTER DELTA +1EA0 ; mapped ; 1EA1 # 1.1 LATIN CAPITAL LETTER A WITH DOT BELOW +1EA1 ; valid # 1.1 LATIN SMALL LETTER A WITH DOT BELOW +1EA2 ; mapped ; 1EA3 # 1.1 LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA3 ; valid # 1.1 LATIN SMALL LETTER A WITH HOOK ABOVE +1EA4 ; mapped ; 1EA5 # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA5 ; valid # 1.1 LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6 ; mapped ; 1EA7 # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA7 ; valid # 1.1 LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8 ; mapped ; 1EA9 # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EA9 ; valid # 1.1 LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA ; mapped ; 1EAB # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAB ; valid # 1.1 LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC ; mapped ; 1EAD # 1.1 LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAD ; valid # 1.1 LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE ; mapped ; 1EAF # 1.1 LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EAF ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE AND ACUTE +1EB0 ; mapped ; 1EB1 # 1.1 LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB1 ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE AND GRAVE +1EB2 ; mapped ; 1EB3 # 1.1 LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB3 ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE +1EB4 ; mapped ; 1EB5 # 1.1 LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB5 ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE AND TILDE +1EB6 ; mapped ; 1EB7 # 1.1 LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB7 ; valid # 1.1 LATIN SMALL LETTER A WITH BREVE AND DOT BELOW +1EB8 ; mapped ; 1EB9 # 1.1 LATIN CAPITAL LETTER E WITH DOT BELOW +1EB9 ; valid # 1.1 LATIN SMALL LETTER E WITH DOT BELOW +1EBA ; mapped ; 1EBB # 1.1 LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBB ; valid # 1.1 LATIN SMALL LETTER E WITH HOOK ABOVE +1EBC ; mapped ; 1EBD # 1.1 LATIN CAPITAL LETTER E WITH TILDE +1EBD ; valid # 1.1 LATIN SMALL LETTER E WITH TILDE +1EBE ; mapped ; 1EBF # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EBF ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0 ; mapped ; 1EC1 # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC1 ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2 ; mapped ; 1EC3 # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC3 ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4 ; mapped ; 1EC5 # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC5 ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6 ; mapped ; 1EC7 # 1.1 LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC7 ; valid # 1.1 LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8 ; mapped ; 1EC9 # 1.1 LATIN CAPITAL LETTER I WITH HOOK ABOVE +1EC9 ; valid # 1.1 LATIN SMALL LETTER I WITH HOOK ABOVE +1ECA ; mapped ; 1ECB # 1.1 LATIN CAPITAL LETTER I WITH DOT BELOW +1ECB ; valid # 1.1 LATIN SMALL LETTER I WITH DOT BELOW +1ECC ; mapped ; 1ECD # 1.1 LATIN CAPITAL LETTER O WITH DOT BELOW +1ECD ; valid # 1.1 LATIN SMALL LETTER O WITH DOT BELOW +1ECE ; mapped ; 1ECF # 1.1 LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ECF ; valid # 1.1 LATIN SMALL LETTER O WITH HOOK ABOVE +1ED0 ; mapped ; 1ED1 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED1 ; valid # 1.1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2 ; mapped ; 1ED3 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED3 ; valid # 1.1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4 ; mapped ; 1ED5 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED5 ; valid # 1.1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6 ; mapped ; 1ED7 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED7 ; valid # 1.1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8 ; mapped ; 1ED9 # 1.1 LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1ED9 ; valid # 1.1 LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA ; mapped ; 1EDB # 1.1 LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDB ; valid # 1.1 LATIN SMALL LETTER O WITH HORN AND ACUTE +1EDC ; mapped ; 1EDD # 1.1 LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDD ; valid # 1.1 LATIN SMALL LETTER O WITH HORN AND GRAVE +1EDE ; mapped ; 1EDF # 1.1 LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EDF ; valid # 1.1 LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE +1EE0 ; mapped ; 1EE1 # 1.1 LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE1 ; valid # 1.1 LATIN SMALL LETTER O WITH HORN AND TILDE +1EE2 ; mapped ; 1EE3 # 1.1 LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE3 ; valid # 1.1 LATIN SMALL LETTER O WITH HORN AND DOT BELOW +1EE4 ; mapped ; 1EE5 # 1.1 LATIN CAPITAL LETTER U WITH DOT BELOW +1EE5 ; valid # 1.1 LATIN SMALL LETTER U WITH DOT BELOW +1EE6 ; mapped ; 1EE7 # 1.1 LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE7 ; valid # 1.1 LATIN SMALL LETTER U WITH HOOK ABOVE +1EE8 ; mapped ; 1EE9 # 1.1 LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EE9 ; valid # 1.1 LATIN SMALL LETTER U WITH HORN AND ACUTE +1EEA ; mapped ; 1EEB # 1.1 LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEB ; valid # 1.1 LATIN SMALL LETTER U WITH HORN AND GRAVE +1EEC ; mapped ; 1EED # 1.1 LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EED ; valid # 1.1 LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE +1EEE ; mapped ; 1EEF # 1.1 LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EEF ; valid # 1.1 LATIN SMALL LETTER U WITH HORN AND TILDE +1EF0 ; mapped ; 1EF1 # 1.1 LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF1 ; valid # 1.1 LATIN SMALL LETTER U WITH HORN AND DOT BELOW +1EF2 ; mapped ; 1EF3 # 1.1 LATIN CAPITAL LETTER Y WITH GRAVE +1EF3 ; valid # 1.1 LATIN SMALL LETTER Y WITH GRAVE +1EF4 ; mapped ; 1EF5 # 1.1 LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF5 ; valid # 1.1 LATIN SMALL LETTER Y WITH DOT BELOW +1EF6 ; mapped ; 1EF7 # 1.1 LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF7 ; valid # 1.1 LATIN SMALL LETTER Y WITH HOOK ABOVE +1EF8 ; mapped ; 1EF9 # 1.1 LATIN CAPITAL LETTER Y WITH TILDE +1EF9 ; valid # 1.1 LATIN SMALL LETTER Y WITH TILDE +1EFA ; mapped ; 1EFB # 5.1 LATIN CAPITAL LETTER MIDDLE-WELSH LL +1EFB ; valid # 5.1 LATIN SMALL LETTER MIDDLE-WELSH LL +1EFC ; mapped ; 1EFD # 5.1 LATIN CAPITAL LETTER MIDDLE-WELSH V +1EFD ; valid # 5.1 LATIN SMALL LETTER MIDDLE-WELSH V +1EFE ; mapped ; 1EFF # 5.1 LATIN CAPITAL LETTER Y WITH LOOP +1EFF ; valid # 5.1 LATIN SMALL LETTER Y WITH LOOP +1F00..1F07 ; valid # 1.1 GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F08 ; mapped ; 1F00 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09 ; mapped ; 1F01 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A ; mapped ; 1F02 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B ; mapped ; 1F03 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C ; mapped ; 1F04 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D ; mapped ; 1F05 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E ; mapped ; 1F06 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F ; mapped ; 1F07 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F10..1F15 ; valid # 1.1 GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F16..1F17 ; disallowed # NA .. +1F18 ; mapped ; 1F10 # 1.1 GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19 ; mapped ; 1F11 # 1.1 GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A ; mapped ; 1F12 # 1.1 GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B ; mapped ; 1F13 # 1.1 GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C ; mapped ; 1F14 # 1.1 GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D ; mapped ; 1F15 # 1.1 GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F1E..1F1F ; disallowed # NA .. +1F20..1F27 ; valid # 1.1 GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI +1F28 ; mapped ; 1F20 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI +1F29 ; mapped ; 1F21 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA +1F2A ; mapped ; 1F22 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B ; mapped ; 1F23 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C ; mapped ; 1F24 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D ; mapped ; 1F25 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E ; mapped ; 1F26 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F ; mapped ; 1F27 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F30..1F37 ; valid # 1.1 GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI +1F38 ; mapped ; 1F30 # 1.1 GREEK CAPITAL LETTER IOTA WITH PSILI +1F39 ; mapped ; 1F31 # 1.1 GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A ; mapped ; 1F32 # 1.1 GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B ; mapped ; 1F33 # 1.1 GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C ; mapped ; 1F34 # 1.1 GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D ; mapped ; 1F35 # 1.1 GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E ; mapped ; 1F36 # 1.1 GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F ; mapped ; 1F37 # 1.1 GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F40..1F45 ; valid # 1.1 GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F46..1F47 ; disallowed # NA .. +1F48 ; mapped ; 1F40 # 1.1 GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49 ; mapped ; 1F41 # 1.1 GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A ; mapped ; 1F42 # 1.1 GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B ; mapped ; 1F43 # 1.1 GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C ; mapped ; 1F44 # 1.1 GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D ; mapped ; 1F45 # 1.1 GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F4E..1F4F ; disallowed # NA .. +1F50..1F57 ; valid # 1.1 GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F58 ; disallowed # NA +1F59 ; mapped ; 1F51 # 1.1 GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5A ; disallowed # NA +1F5B ; mapped ; 1F53 # 1.1 GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5C ; disallowed # NA +1F5D ; mapped ; 1F55 # 1.1 GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5E ; disallowed # NA +1F5F ; mapped ; 1F57 # 1.1 GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F60..1F67 ; valid # 1.1 GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F68 ; mapped ; 1F60 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69 ; mapped ; 1F61 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A ; mapped ; 1F62 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B ; mapped ; 1F63 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C ; mapped ; 1F64 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D ; mapped ; 1F65 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E ; mapped ; 1F66 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F ; mapped ; 1F67 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F70 ; valid # 1.1 GREEK SMALL LETTER ALPHA WITH VARIA +1F71 ; mapped ; 03AC # 1.1 GREEK SMALL LETTER ALPHA WITH OXIA +1F72 ; valid # 1.1 GREEK SMALL LETTER EPSILON WITH VARIA +1F73 ; mapped ; 03AD # 1.1 GREEK SMALL LETTER EPSILON WITH OXIA +1F74 ; valid # 1.1 GREEK SMALL LETTER ETA WITH VARIA +1F75 ; mapped ; 03AE # 1.1 GREEK SMALL LETTER ETA WITH OXIA +1F76 ; valid # 1.1 GREEK SMALL LETTER IOTA WITH VARIA +1F77 ; mapped ; 03AF # 1.1 GREEK SMALL LETTER IOTA WITH OXIA +1F78 ; valid # 1.1 GREEK SMALL LETTER OMICRON WITH VARIA +1F79 ; mapped ; 03CC # 1.1 GREEK SMALL LETTER OMICRON WITH OXIA +1F7A ; valid # 1.1 GREEK SMALL LETTER UPSILON WITH VARIA +1F7B ; mapped ; 03CD # 1.1 GREEK SMALL LETTER UPSILON WITH OXIA +1F7C ; valid # 1.1 GREEK SMALL LETTER OMEGA WITH VARIA +1F7D ; mapped ; 03CE # 1.1 GREEK SMALL LETTER OMEGA WITH OXIA +1F7E..1F7F ; disallowed # NA .. +1F80 ; mapped ; 1F00 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81 ; mapped ; 1F01 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82 ; mapped ; 1F02 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83 ; mapped ; 1F03 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84 ; mapped ; 1F04 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85 ; mapped ; 1F05 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86 ; mapped ; 1F06 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87 ; mapped ; 1F07 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88 ; mapped ; 1F00 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89 ; mapped ; 1F01 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A ; mapped ; 1F02 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B ; mapped ; 1F03 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C ; mapped ; 1F04 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D ; mapped ; 1F05 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E ; mapped ; 1F06 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F ; mapped ; 1F07 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90 ; mapped ; 1F20 03B9 # 1.1 GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91 ; mapped ; 1F21 03B9 # 1.1 GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92 ; mapped ; 1F22 03B9 # 1.1 GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93 ; mapped ; 1F23 03B9 # 1.1 GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94 ; mapped ; 1F24 03B9 # 1.1 GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95 ; mapped ; 1F25 03B9 # 1.1 GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96 ; mapped ; 1F26 03B9 # 1.1 GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97 ; mapped ; 1F27 03B9 # 1.1 GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98 ; mapped ; 1F20 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99 ; mapped ; 1F21 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A ; mapped ; 1F22 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B ; mapped ; 1F23 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C ; mapped ; 1F24 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D ; mapped ; 1F25 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E ; mapped ; 1F26 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F ; mapped ; 1F27 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0 ; mapped ; 1F60 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1 ; mapped ; 1F61 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2 ; mapped ; 1F62 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3 ; mapped ; 1F63 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4 ; mapped ; 1F64 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5 ; mapped ; 1F65 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6 ; mapped ; 1F66 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7 ; mapped ; 1F67 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8 ; mapped ; 1F60 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9 ; mapped ; 1F61 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA ; mapped ; 1F62 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB ; mapped ; 1F63 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC ; mapped ; 1F64 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD ; mapped ; 1F65 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE ; mapped ; 1F66 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF ; mapped ; 1F67 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB0..1FB1 ; valid # 1.1 GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH MACRON +1FB2 ; mapped ; 1F70 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3 ; mapped ; 03B1 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4 ; mapped ; 03AC 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB5 ; disallowed # NA +1FB6 ; valid # 1.1 GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7 ; mapped ; 1FB6 03B9 # 1.1 GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8 ; mapped ; 1FB0 # 1.1 GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9 ; mapped ; 1FB1 # 1.1 GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA ; mapped ; 1F70 # 1.1 GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB ; mapped ; 03AC # 1.1 GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC ; mapped ; 03B1 03B9 # 1.1 GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD ; disallowed_STD3_mapped ; 0020 0313 # 1.1 GREEK KORONIS +1FBE ; mapped ; 03B9 # 1.1 GREEK PROSGEGRAMMENI +1FBF ; disallowed_STD3_mapped ; 0020 0313 # 1.1 GREEK PSILI +1FC0 ; disallowed_STD3_mapped ; 0020 0342 # 1.1 GREEK PERISPOMENI +1FC1 ; disallowed_STD3_mapped ; 0020 0308 0342 #1.1 GREEK DIALYTIKA AND PERISPOMENI +1FC2 ; mapped ; 1F74 03B9 # 1.1 GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3 ; mapped ; 03B7 03B9 # 1.1 GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4 ; mapped ; 03AE 03B9 # 1.1 GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC5 ; disallowed # NA +1FC6 ; valid # 1.1 GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7 ; mapped ; 1FC6 03B9 # 1.1 GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8 ; mapped ; 1F72 # 1.1 GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9 ; mapped ; 03AD # 1.1 GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA ; mapped ; 1F74 # 1.1 GREEK CAPITAL LETTER ETA WITH VARIA +1FCB ; mapped ; 03AE # 1.1 GREEK CAPITAL LETTER ETA WITH OXIA +1FCC ; mapped ; 03B7 03B9 # 1.1 GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD ; disallowed_STD3_mapped ; 0020 0313 0300 #1.1 GREEK PSILI AND VARIA +1FCE ; disallowed_STD3_mapped ; 0020 0313 0301 #1.1 GREEK PSILI AND OXIA +1FCF ; disallowed_STD3_mapped ; 0020 0313 0342 #1.1 GREEK PSILI AND PERISPOMENI +1FD0..1FD2 ; valid # 1.1 GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3 ; mapped ; 0390 # 1.1 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD4..1FD5 ; disallowed # NA .. +1FD6..1FD7 ; valid # 1.1 GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8 ; mapped ; 1FD0 # 1.1 GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9 ; mapped ; 1FD1 # 1.1 GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA ; mapped ; 1F76 # 1.1 GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB ; mapped ; 03AF # 1.1 GREEK CAPITAL LETTER IOTA WITH OXIA +1FDC ; disallowed # NA +1FDD ; disallowed_STD3_mapped ; 0020 0314 0300 #1.1 GREEK DASIA AND VARIA +1FDE ; disallowed_STD3_mapped ; 0020 0314 0301 #1.1 GREEK DASIA AND OXIA +1FDF ; disallowed_STD3_mapped ; 0020 0314 0342 #1.1 GREEK DASIA AND PERISPOMENI +1FE0..1FE2 ; valid # 1.1 GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3 ; mapped ; 03B0 # 1.1 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4..1FE7 ; valid # 1.1 GREEK SMALL LETTER RHO WITH PSILI..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8 ; mapped ; 1FE0 # 1.1 GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9 ; mapped ; 1FE1 # 1.1 GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA ; mapped ; 1F7A # 1.1 GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB ; mapped ; 03CD # 1.1 GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC ; mapped ; 1FE5 # 1.1 GREEK CAPITAL LETTER RHO WITH DASIA +1FED ; disallowed_STD3_mapped ; 0020 0308 0300 #1.1 GREEK DIALYTIKA AND VARIA +1FEE ; disallowed_STD3_mapped ; 0020 0308 0301 #1.1 GREEK DIALYTIKA AND OXIA +1FEF ; disallowed_STD3_mapped ; 0060 # 1.1 GREEK VARIA +1FF0..1FF1 ; disallowed # NA .. +1FF2 ; mapped ; 1F7C 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3 ; mapped ; 03C9 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4 ; mapped ; 03CE 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF5 ; disallowed # NA +1FF6 ; valid # 1.1 GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7 ; mapped ; 1FF6 03B9 # 1.1 GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8 ; mapped ; 1F78 # 1.1 GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9 ; mapped ; 03CC # 1.1 GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA ; mapped ; 1F7C # 1.1 GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB ; mapped ; 03CE # 1.1 GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC ; mapped ; 03C9 03B9 # 1.1 GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD ; disallowed_STD3_mapped ; 0020 0301 # 1.1 GREEK OXIA +1FFE ; disallowed_STD3_mapped ; 0020 0314 # 1.1 GREEK DASIA +1FFF ; disallowed # NA +2000..200A ; disallowed_STD3_mapped ; 0020 # 1.1 EN QUAD..HAIR SPACE +200B ; ignored # 1.1 ZERO WIDTH SPACE +200C..200D ; deviation ; # 1.1 ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER +200E..200F ; disallowed # 1.1 LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK +2010 ; valid ; ; NV8 # 1.1 HYPHEN +2011 ; mapped ; 2010 # 1.1 NON-BREAKING HYPHEN +2012..2016 ; valid ; ; NV8 # 1.1 FIGURE DASH..DOUBLE VERTICAL LINE +2017 ; disallowed_STD3_mapped ; 0020 0333 # 1.1 DOUBLE LOW LINE +2018..2023 ; valid ; ; NV8 # 1.1 LEFT SINGLE QUOTATION MARK..TRIANGULAR BULLET +2024..2026 ; disallowed # 1.1 ONE DOT LEADER..HORIZONTAL ELLIPSIS +2027 ; valid ; ; NV8 # 1.1 HYPHENATION POINT +2028..202E ; disallowed # 1.1 LINE SEPARATOR..RIGHT-TO-LEFT OVERRIDE +202F ; disallowed_STD3_mapped ; 0020 # 3.0 NARROW NO-BREAK SPACE +2030..2032 ; valid ; ; NV8 # 1.1 PER MILLE SIGN..PRIME +2033 ; mapped ; 2032 2032 # 1.1 DOUBLE PRIME +2034 ; mapped ; 2032 2032 2032 #1.1 TRIPLE PRIME +2035 ; valid ; ; NV8 # 1.1 REVERSED PRIME +2036 ; mapped ; 2035 2035 # 1.1 REVERSED DOUBLE PRIME +2037 ; mapped ; 2035 2035 2035 #1.1 REVERSED TRIPLE PRIME +2038..203B ; valid ; ; NV8 # 1.1 CARET..REFERENCE MARK +203C ; disallowed_STD3_mapped ; 0021 0021 # 1.1 DOUBLE EXCLAMATION MARK +203D ; valid ; ; NV8 # 1.1 INTERROBANG +203E ; disallowed_STD3_mapped ; 0020 0305 # 1.1 OVERLINE +203F..2046 ; valid ; ; NV8 # 1.1 UNDERTIE..RIGHT SQUARE BRACKET WITH QUILL +2047 ; disallowed_STD3_mapped ; 003F 003F # 3.2 DOUBLE QUESTION MARK +2048 ; disallowed_STD3_mapped ; 003F 0021 # 3.0 QUESTION EXCLAMATION MARK +2049 ; disallowed_STD3_mapped ; 0021 003F # 3.0 EXCLAMATION QUESTION MARK +204A..204D ; valid ; ; NV8 # 3.0 TIRONIAN SIGN ET..BLACK RIGHTWARDS BULLET +204E..2052 ; valid ; ; NV8 # 3.2 LOW ASTERISK..COMMERCIAL MINUS SIGN +2053..2054 ; valid ; ; NV8 # 4.0 SWUNG DASH..INVERTED UNDERTIE +2055..2056 ; valid ; ; NV8 # 4.1 FLOWER PUNCTUATION MARK..THREE DOT PUNCTUATION +2057 ; mapped ; 2032 2032 2032 2032 #3.2 QUADRUPLE PRIME +2058..205E ; valid ; ; NV8 # 4.1 FOUR DOT PUNCTUATION..VERTICAL FOUR DOTS +205F ; disallowed_STD3_mapped ; 0020 # 3.2 MEDIUM MATHEMATICAL SPACE +2060 ; ignored # 3.2 WORD JOINER +2061..2063 ; disallowed # 3.2 FUNCTION APPLICATION..INVISIBLE SEPARATOR +2064 ; ignored # 5.1 INVISIBLE PLUS +2065 ; disallowed # NA +2066..2069 ; disallowed # 6.3 LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE +206A..206F ; disallowed # 1.1 INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES +2070 ; mapped ; 0030 # 1.1 SUPERSCRIPT ZERO +2071 ; mapped ; 0069 # 3.2 SUPERSCRIPT LATIN SMALL LETTER I +2072..2073 ; disallowed # NA .. +2074 ; mapped ; 0034 # 1.1 SUPERSCRIPT FOUR +2075 ; mapped ; 0035 # 1.1 SUPERSCRIPT FIVE +2076 ; mapped ; 0036 # 1.1 SUPERSCRIPT SIX +2077 ; mapped ; 0037 # 1.1 SUPERSCRIPT SEVEN +2078 ; mapped ; 0038 # 1.1 SUPERSCRIPT EIGHT +2079 ; mapped ; 0039 # 1.1 SUPERSCRIPT NINE +207A ; disallowed_STD3_mapped ; 002B # 1.1 SUPERSCRIPT PLUS SIGN +207B ; mapped ; 2212 # 1.1 SUPERSCRIPT MINUS +207C ; disallowed_STD3_mapped ; 003D # 1.1 SUPERSCRIPT EQUALS SIGN +207D ; disallowed_STD3_mapped ; 0028 # 1.1 SUPERSCRIPT LEFT PARENTHESIS +207E ; disallowed_STD3_mapped ; 0029 # 1.1 SUPERSCRIPT RIGHT PARENTHESIS +207F ; mapped ; 006E # 1.1 SUPERSCRIPT LATIN SMALL LETTER N +2080 ; mapped ; 0030 # 1.1 SUBSCRIPT ZERO +2081 ; mapped ; 0031 # 1.1 SUBSCRIPT ONE +2082 ; mapped ; 0032 # 1.1 SUBSCRIPT TWO +2083 ; mapped ; 0033 # 1.1 SUBSCRIPT THREE +2084 ; mapped ; 0034 # 1.1 SUBSCRIPT FOUR +2085 ; mapped ; 0035 # 1.1 SUBSCRIPT FIVE +2086 ; mapped ; 0036 # 1.1 SUBSCRIPT SIX +2087 ; mapped ; 0037 # 1.1 SUBSCRIPT SEVEN +2088 ; mapped ; 0038 # 1.1 SUBSCRIPT EIGHT +2089 ; mapped ; 0039 # 1.1 SUBSCRIPT NINE +208A ; disallowed_STD3_mapped ; 002B # 1.1 SUBSCRIPT PLUS SIGN +208B ; mapped ; 2212 # 1.1 SUBSCRIPT MINUS +208C ; disallowed_STD3_mapped ; 003D # 1.1 SUBSCRIPT EQUALS SIGN +208D ; disallowed_STD3_mapped ; 0028 # 1.1 SUBSCRIPT LEFT PARENTHESIS +208E ; disallowed_STD3_mapped ; 0029 # 1.1 SUBSCRIPT RIGHT PARENTHESIS +208F ; disallowed # NA +2090 ; mapped ; 0061 # 4.1 LATIN SUBSCRIPT SMALL LETTER A +2091 ; mapped ; 0065 # 4.1 LATIN SUBSCRIPT SMALL LETTER E +2092 ; mapped ; 006F # 4.1 LATIN SUBSCRIPT SMALL LETTER O +2093 ; mapped ; 0078 # 4.1 LATIN SUBSCRIPT SMALL LETTER X +2094 ; mapped ; 0259 # 4.1 LATIN SUBSCRIPT SMALL LETTER SCHWA +2095 ; mapped ; 0068 # 6.0 LATIN SUBSCRIPT SMALL LETTER H +2096 ; mapped ; 006B # 6.0 LATIN SUBSCRIPT SMALL LETTER K +2097 ; mapped ; 006C # 6.0 LATIN SUBSCRIPT SMALL LETTER L +2098 ; mapped ; 006D # 6.0 LATIN SUBSCRIPT SMALL LETTER M +2099 ; mapped ; 006E # 6.0 LATIN SUBSCRIPT SMALL LETTER N +209A ; mapped ; 0070 # 6.0 LATIN SUBSCRIPT SMALL LETTER P +209B ; mapped ; 0073 # 6.0 LATIN SUBSCRIPT SMALL LETTER S +209C ; mapped ; 0074 # 6.0 LATIN SUBSCRIPT SMALL LETTER T +209D..209F ; disallowed # NA .. +20A0..20A7 ; valid ; ; NV8 # 1.1 EURO-CURRENCY SIGN..PESETA SIGN +20A8 ; mapped ; 0072 0073 # 1.1 RUPEE SIGN +20A9..20AA ; valid ; ; NV8 # 1.1 WON SIGN..NEW SHEQEL SIGN +20AB ; valid ; ; NV8 # 2.0 DONG SIGN +20AC ; valid ; ; NV8 # 2.1 EURO SIGN +20AD..20AF ; valid ; ; NV8 # 3.0 KIP SIGN..DRACHMA SIGN +20B0..20B1 ; valid ; ; NV8 # 3.2 GERMAN PENNY SIGN..PESO SIGN +20B2..20B5 ; valid ; ; NV8 # 4.1 GUARANI SIGN..CEDI SIGN +20B6..20B8 ; valid ; ; NV8 # 5.2 LIVRE TOURNOIS SIGN..TENGE SIGN +20B9 ; valid ; ; NV8 # 6.0 INDIAN RUPEE SIGN +20BA ; valid ; ; NV8 # 6.2 TURKISH LIRA SIGN +20BB..20BD ; valid ; ; NV8 # 7.0 NORDIC MARK SIGN..RUBLE SIGN +20BE ; valid ; ; NV8 # 8.0 LARI SIGN +20BF ; valid ; ; NV8 # 10.0 BITCOIN SIGN +20C0..20CF ; disallowed # NA .. +20D0..20E1 ; valid ; ; NV8 # 1.1 COMBINING LEFT HARPOON ABOVE..COMBINING LEFT RIGHT ARROW ABOVE +20E2..20E3 ; valid ; ; NV8 # 3.0 COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING KEYCAP +20E4..20EA ; valid ; ; NV8 # 3.2 COMBINING ENCLOSING UPWARD POINTING TRIANGLE..COMBINING LEFTWARDS ARROW OVERLAY +20EB ; valid ; ; NV8 # 4.1 COMBINING LONG DOUBLE SOLIDUS OVERLAY +20EC..20EF ; valid ; ; NV8 # 5.0 COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS..COMBINING RIGHT ARROW BELOW +20F0 ; valid ; ; NV8 # 5.1 COMBINING ASTERISK ABOVE +20F1..20FF ; disallowed # NA .. +2100 ; disallowed_STD3_mapped ; 0061 002F 0063 #1.1 ACCOUNT OF +2101 ; disallowed_STD3_mapped ; 0061 002F 0073 #1.1 ADDRESSED TO THE SUBJECT +2102 ; mapped ; 0063 # 1.1 DOUBLE-STRUCK CAPITAL C +2103 ; mapped ; 00B0 0063 # 1.1 DEGREE CELSIUS +2104 ; valid ; ; NV8 # 1.1 CENTRE LINE SYMBOL +2105 ; disallowed_STD3_mapped ; 0063 002F 006F #1.1 CARE OF +2106 ; disallowed_STD3_mapped ; 0063 002F 0075 #1.1 CADA UNA +2107 ; mapped ; 025B # 1.1 EULER CONSTANT +2108 ; valid ; ; NV8 # 1.1 SCRUPLE +2109 ; mapped ; 00B0 0066 # 1.1 DEGREE FAHRENHEIT +210A ; mapped ; 0067 # 1.1 SCRIPT SMALL G +210B..210E ; mapped ; 0068 # 1.1 SCRIPT CAPITAL H..PLANCK CONSTANT +210F ; mapped ; 0127 # 1.1 PLANCK CONSTANT OVER TWO PI +2110..2111 ; mapped ; 0069 # 1.1 SCRIPT CAPITAL I..BLACK-LETTER CAPITAL I +2112..2113 ; mapped ; 006C # 1.1 SCRIPT CAPITAL L..SCRIPT SMALL L +2114 ; valid ; ; NV8 # 1.1 L B BAR SYMBOL +2115 ; mapped ; 006E # 1.1 DOUBLE-STRUCK CAPITAL N +2116 ; mapped ; 006E 006F # 1.1 NUMERO SIGN +2117..2118 ; valid ; ; NV8 # 1.1 SOUND RECORDING COPYRIGHT..SCRIPT CAPITAL P +2119 ; mapped ; 0070 # 1.1 DOUBLE-STRUCK CAPITAL P +211A ; mapped ; 0071 # 1.1 DOUBLE-STRUCK CAPITAL Q +211B..211D ; mapped ; 0072 # 1.1 SCRIPT CAPITAL R..DOUBLE-STRUCK CAPITAL R +211E..211F ; valid ; ; NV8 # 1.1 PRESCRIPTION TAKE..RESPONSE +2120 ; mapped ; 0073 006D # 1.1 SERVICE MARK +2121 ; mapped ; 0074 0065 006C #1.1 TELEPHONE SIGN +2122 ; mapped ; 0074 006D # 1.1 TRADE MARK SIGN +2123 ; valid ; ; NV8 # 1.1 VERSICLE +2124 ; mapped ; 007A # 1.1 DOUBLE-STRUCK CAPITAL Z +2125 ; valid ; ; NV8 # 1.1 OUNCE SIGN +2126 ; mapped ; 03C9 # 1.1 OHM SIGN +2127 ; valid ; ; NV8 # 1.1 INVERTED OHM SIGN +2128 ; mapped ; 007A # 1.1 BLACK-LETTER CAPITAL Z +2129 ; valid ; ; NV8 # 1.1 TURNED GREEK SMALL LETTER IOTA +212A ; mapped ; 006B # 1.1 KELVIN SIGN +212B ; mapped ; 00E5 # 1.1 ANGSTROM SIGN +212C ; mapped ; 0062 # 1.1 SCRIPT CAPITAL B +212D ; mapped ; 0063 # 1.1 BLACK-LETTER CAPITAL C +212E ; valid ; ; NV8 # 1.1 ESTIMATED SYMBOL +212F..2130 ; mapped ; 0065 # 1.1 SCRIPT SMALL E..SCRIPT CAPITAL E +2131 ; mapped ; 0066 # 1.1 SCRIPT CAPITAL F +2132 ; disallowed # 1.1 TURNED CAPITAL F +2133 ; mapped ; 006D # 1.1 SCRIPT CAPITAL M +2134 ; mapped ; 006F # 1.1 SCRIPT SMALL O +2135 ; mapped ; 05D0 # 1.1 ALEF SYMBOL +2136 ; mapped ; 05D1 # 1.1 BET SYMBOL +2137 ; mapped ; 05D2 # 1.1 GIMEL SYMBOL +2138 ; mapped ; 05D3 # 1.1 DALET SYMBOL +2139 ; mapped ; 0069 # 3.0 INFORMATION SOURCE +213A ; valid ; ; NV8 # 3.0 ROTATED CAPITAL Q +213B ; mapped ; 0066 0061 0078 #4.0 FACSIMILE SIGN +213C ; mapped ; 03C0 # 4.1 DOUBLE-STRUCK SMALL PI +213D..213E ; mapped ; 03B3 # 3.2 DOUBLE-STRUCK SMALL GAMMA..DOUBLE-STRUCK CAPITAL GAMMA +213F ; mapped ; 03C0 # 3.2 DOUBLE-STRUCK CAPITAL PI +2140 ; mapped ; 2211 # 3.2 DOUBLE-STRUCK N-ARY SUMMATION +2141..2144 ; valid ; ; NV8 # 3.2 TURNED SANS-SERIF CAPITAL G..TURNED SANS-SERIF CAPITAL Y +2145..2146 ; mapped ; 0064 # 3.2 DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL D +2147 ; mapped ; 0065 # 3.2 DOUBLE-STRUCK ITALIC SMALL E +2148 ; mapped ; 0069 # 3.2 DOUBLE-STRUCK ITALIC SMALL I +2149 ; mapped ; 006A # 3.2 DOUBLE-STRUCK ITALIC SMALL J +214A..214B ; valid ; ; NV8 # 3.2 PROPERTY LINE..TURNED AMPERSAND +214C ; valid ; ; NV8 # 4.1 PER SIGN +214D ; valid ; ; NV8 # 5.0 AKTIESELSKAB +214E ; valid # 5.0 TURNED SMALL F +214F ; valid ; ; NV8 # 5.1 SYMBOL FOR SAMARITAN SOURCE +2150 ; mapped ; 0031 2044 0037 #5.2 VULGAR FRACTION ONE SEVENTH +2151 ; mapped ; 0031 2044 0039 #5.2 VULGAR FRACTION ONE NINTH +2152 ; mapped ; 0031 2044 0031 0030 #5.2 VULGAR FRACTION ONE TENTH +2153 ; mapped ; 0031 2044 0033 #1.1 VULGAR FRACTION ONE THIRD +2154 ; mapped ; 0032 2044 0033 #1.1 VULGAR FRACTION TWO THIRDS +2155 ; mapped ; 0031 2044 0035 #1.1 VULGAR FRACTION ONE FIFTH +2156 ; mapped ; 0032 2044 0035 #1.1 VULGAR FRACTION TWO FIFTHS +2157 ; mapped ; 0033 2044 0035 #1.1 VULGAR FRACTION THREE FIFTHS +2158 ; mapped ; 0034 2044 0035 #1.1 VULGAR FRACTION FOUR FIFTHS +2159 ; mapped ; 0031 2044 0036 #1.1 VULGAR FRACTION ONE SIXTH +215A ; mapped ; 0035 2044 0036 #1.1 VULGAR FRACTION FIVE SIXTHS +215B ; mapped ; 0031 2044 0038 #1.1 VULGAR FRACTION ONE EIGHTH +215C ; mapped ; 0033 2044 0038 #1.1 VULGAR FRACTION THREE EIGHTHS +215D ; mapped ; 0035 2044 0038 #1.1 VULGAR FRACTION FIVE EIGHTHS +215E ; mapped ; 0037 2044 0038 #1.1 VULGAR FRACTION SEVEN EIGHTHS +215F ; mapped ; 0031 2044 # 1.1 FRACTION NUMERATOR ONE +2160 ; mapped ; 0069 # 1.1 ROMAN NUMERAL ONE +2161 ; mapped ; 0069 0069 # 1.1 ROMAN NUMERAL TWO +2162 ; mapped ; 0069 0069 0069 #1.1 ROMAN NUMERAL THREE +2163 ; mapped ; 0069 0076 # 1.1 ROMAN NUMERAL FOUR +2164 ; mapped ; 0076 # 1.1 ROMAN NUMERAL FIVE +2165 ; mapped ; 0076 0069 # 1.1 ROMAN NUMERAL SIX +2166 ; mapped ; 0076 0069 0069 #1.1 ROMAN NUMERAL SEVEN +2167 ; mapped ; 0076 0069 0069 0069 #1.1 ROMAN NUMERAL EIGHT +2168 ; mapped ; 0069 0078 # 1.1 ROMAN NUMERAL NINE +2169 ; mapped ; 0078 # 1.1 ROMAN NUMERAL TEN +216A ; mapped ; 0078 0069 # 1.1 ROMAN NUMERAL ELEVEN +216B ; mapped ; 0078 0069 0069 #1.1 ROMAN NUMERAL TWELVE +216C ; mapped ; 006C # 1.1 ROMAN NUMERAL FIFTY +216D ; mapped ; 0063 # 1.1 ROMAN NUMERAL ONE HUNDRED +216E ; mapped ; 0064 # 1.1 ROMAN NUMERAL FIVE HUNDRED +216F ; mapped ; 006D # 1.1 ROMAN NUMERAL ONE THOUSAND +2170 ; mapped ; 0069 # 1.1 SMALL ROMAN NUMERAL ONE +2171 ; mapped ; 0069 0069 # 1.1 SMALL ROMAN NUMERAL TWO +2172 ; mapped ; 0069 0069 0069 #1.1 SMALL ROMAN NUMERAL THREE +2173 ; mapped ; 0069 0076 # 1.1 SMALL ROMAN NUMERAL FOUR +2174 ; mapped ; 0076 # 1.1 SMALL ROMAN NUMERAL FIVE +2175 ; mapped ; 0076 0069 # 1.1 SMALL ROMAN NUMERAL SIX +2176 ; mapped ; 0076 0069 0069 #1.1 SMALL ROMAN NUMERAL SEVEN +2177 ; mapped ; 0076 0069 0069 0069 #1.1 SMALL ROMAN NUMERAL EIGHT +2178 ; mapped ; 0069 0078 # 1.1 SMALL ROMAN NUMERAL NINE +2179 ; mapped ; 0078 # 1.1 SMALL ROMAN NUMERAL TEN +217A ; mapped ; 0078 0069 # 1.1 SMALL ROMAN NUMERAL ELEVEN +217B ; mapped ; 0078 0069 0069 #1.1 SMALL ROMAN NUMERAL TWELVE +217C ; mapped ; 006C # 1.1 SMALL ROMAN NUMERAL FIFTY +217D ; mapped ; 0063 # 1.1 SMALL ROMAN NUMERAL ONE HUNDRED +217E ; mapped ; 0064 # 1.1 SMALL ROMAN NUMERAL FIVE HUNDRED +217F ; mapped ; 006D # 1.1 SMALL ROMAN NUMERAL ONE THOUSAND +2180..2182 ; valid ; ; NV8 # 1.1 ROMAN NUMERAL ONE THOUSAND C D..ROMAN NUMERAL TEN THOUSAND +2183 ; disallowed # 3.0 ROMAN NUMERAL REVERSED ONE HUNDRED +2184 ; valid # 5.0 LATIN SMALL LETTER REVERSED C +2185..2188 ; valid ; ; NV8 # 5.1 ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND +2189 ; mapped ; 0030 2044 0033 #5.2 VULGAR FRACTION ZERO THIRDS +218A..218B ; valid ; ; NV8 # 8.0 TURNED DIGIT TWO..TURNED DIGIT THREE +218C..218F ; disallowed # NA .. +2190..21EA ; valid ; ; NV8 # 1.1 LEFTWARDS ARROW..UPWARDS WHITE ARROW FROM BAR +21EB..21F3 ; valid ; ; NV8 # 3.0 UPWARDS WHITE ARROW ON PEDESTAL..UP DOWN WHITE ARROW +21F4..21FF ; valid ; ; NV8 # 3.2 RIGHT ARROW WITH SMALL CIRCLE..LEFT RIGHT OPEN-HEADED ARROW +2200..222B ; valid ; ; NV8 # 1.1 FOR ALL..INTEGRAL +222C ; mapped ; 222B 222B # 1.1 DOUBLE INTEGRAL +222D ; mapped ; 222B 222B 222B #1.1 TRIPLE INTEGRAL +222E ; valid ; ; NV8 # 1.1 CONTOUR INTEGRAL +222F ; mapped ; 222E 222E # 1.1 SURFACE INTEGRAL +2230 ; mapped ; 222E 222E 222E #1.1 VOLUME INTEGRAL +2231..225F ; valid ; ; NV8 # 1.1 CLOCKWISE INTEGRAL..QUESTIONED EQUAL TO +2260 ; disallowed_STD3_valid # 1.1 NOT EQUAL TO +2261..226D ; valid ; ; NV8 # 1.1 IDENTICAL TO..NOT EQUIVALENT TO +226E..226F ; disallowed_STD3_valid # 1.1 NOT LESS-THAN..NOT GREATER-THAN +2270..22F1 ; valid ; ; NV8 # 1.1 NEITHER LESS-THAN NOR EQUAL TO..DOWN RIGHT DIAGONAL ELLIPSIS +22F2..22FF ; valid ; ; NV8 # 3.2 ELEMENT OF WITH LONG HORIZONTAL STROKE..Z NOTATION BAG MEMBERSHIP +2300 ; valid ; ; NV8 # 1.1 DIAMETER SIGN +2301 ; valid ; ; NV8 # 3.0 ELECTRIC ARROW +2302..2328 ; valid ; ; NV8 # 1.1 HOUSE..KEYBOARD +2329 ; mapped ; 3008 # 1.1 LEFT-POINTING ANGLE BRACKET +232A ; mapped ; 3009 # 1.1 RIGHT-POINTING ANGLE BRACKET +232B..237A ; valid ; ; NV8 # 1.1 ERASE TO THE LEFT..APL FUNCTIONAL SYMBOL ALPHA +237B ; valid ; ; NV8 # 3.0 NOT CHECK MARK +237C ; valid ; ; NV8 # 3.2 RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D..239A ; valid ; ; NV8 # 3.0 SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL +239B..23CE ; valid ; ; NV8 # 3.2 LEFT PARENTHESIS UPPER HOOK..RETURN SYMBOL +23CF..23D0 ; valid ; ; NV8 # 4.0 EJECT SYMBOL..VERTICAL LINE EXTENSION +23D1..23DB ; valid ; ; NV8 # 4.1 METRICAL BREVE..FUSE +23DC..23E7 ; valid ; ; NV8 # 5.0 TOP PARENTHESIS..ELECTRICAL INTERSECTION +23E8 ; valid ; ; NV8 # 5.2 DECIMAL EXPONENT SYMBOL +23E9..23F3 ; valid ; ; NV8 # 6.0 BLACK RIGHT-POINTING DOUBLE TRIANGLE..HOURGLASS WITH FLOWING SAND +23F4..23FA ; valid ; ; NV8 # 7.0 BLACK MEDIUM LEFT-POINTING TRIANGLE..BLACK CIRCLE FOR RECORD +23FB..23FE ; valid ; ; NV8 # 9.0 POWER SYMBOL..POWER SLEEP SYMBOL +23FF ; valid ; ; NV8 # 10.0 OBSERVER EYE SYMBOL +2400..2424 ; valid ; ; NV8 # 1.1 SYMBOL FOR NULL..SYMBOL FOR NEWLINE +2425..2426 ; valid ; ; NV8 # 3.0 SYMBOL FOR DELETE FORM TWO..SYMBOL FOR SUBSTITUTE FORM TWO +2427..243F ; disallowed # NA .. +2440..244A ; valid ; ; NV8 # 1.1 OCR HOOK..OCR DOUBLE BACKSLASH +244B..245F ; disallowed # NA .. +2460 ; mapped ; 0031 # 1.1 CIRCLED DIGIT ONE +2461 ; mapped ; 0032 # 1.1 CIRCLED DIGIT TWO +2462 ; mapped ; 0033 # 1.1 CIRCLED DIGIT THREE +2463 ; mapped ; 0034 # 1.1 CIRCLED DIGIT FOUR +2464 ; mapped ; 0035 # 1.1 CIRCLED DIGIT FIVE +2465 ; mapped ; 0036 # 1.1 CIRCLED DIGIT SIX +2466 ; mapped ; 0037 # 1.1 CIRCLED DIGIT SEVEN +2467 ; mapped ; 0038 # 1.1 CIRCLED DIGIT EIGHT +2468 ; mapped ; 0039 # 1.1 CIRCLED DIGIT NINE +2469 ; mapped ; 0031 0030 # 1.1 CIRCLED NUMBER TEN +246A ; mapped ; 0031 0031 # 1.1 CIRCLED NUMBER ELEVEN +246B ; mapped ; 0031 0032 # 1.1 CIRCLED NUMBER TWELVE +246C ; mapped ; 0031 0033 # 1.1 CIRCLED NUMBER THIRTEEN +246D ; mapped ; 0031 0034 # 1.1 CIRCLED NUMBER FOURTEEN +246E ; mapped ; 0031 0035 # 1.1 CIRCLED NUMBER FIFTEEN +246F ; mapped ; 0031 0036 # 1.1 CIRCLED NUMBER SIXTEEN +2470 ; mapped ; 0031 0037 # 1.1 CIRCLED NUMBER SEVENTEEN +2471 ; mapped ; 0031 0038 # 1.1 CIRCLED NUMBER EIGHTEEN +2472 ; mapped ; 0031 0039 # 1.1 CIRCLED NUMBER NINETEEN +2473 ; mapped ; 0032 0030 # 1.1 CIRCLED NUMBER TWENTY +2474 ; disallowed_STD3_mapped ; 0028 0031 0029 #1.1 PARENTHESIZED DIGIT ONE +2475 ; disallowed_STD3_mapped ; 0028 0032 0029 #1.1 PARENTHESIZED DIGIT TWO +2476 ; disallowed_STD3_mapped ; 0028 0033 0029 #1.1 PARENTHESIZED DIGIT THREE +2477 ; disallowed_STD3_mapped ; 0028 0034 0029 #1.1 PARENTHESIZED DIGIT FOUR +2478 ; disallowed_STD3_mapped ; 0028 0035 0029 #1.1 PARENTHESIZED DIGIT FIVE +2479 ; disallowed_STD3_mapped ; 0028 0036 0029 #1.1 PARENTHESIZED DIGIT SIX +247A ; disallowed_STD3_mapped ; 0028 0037 0029 #1.1 PARENTHESIZED DIGIT SEVEN +247B ; disallowed_STD3_mapped ; 0028 0038 0029 #1.1 PARENTHESIZED DIGIT EIGHT +247C ; disallowed_STD3_mapped ; 0028 0039 0029 #1.1 PARENTHESIZED DIGIT NINE +247D ; disallowed_STD3_mapped ; 0028 0031 0030 0029 #1.1 PARENTHESIZED NUMBER TEN +247E ; disallowed_STD3_mapped ; 0028 0031 0031 0029 #1.1 PARENTHESIZED NUMBER ELEVEN +247F ; disallowed_STD3_mapped ; 0028 0031 0032 0029 #1.1 PARENTHESIZED NUMBER TWELVE +2480 ; disallowed_STD3_mapped ; 0028 0031 0033 0029 #1.1 PARENTHESIZED NUMBER THIRTEEN +2481 ; disallowed_STD3_mapped ; 0028 0031 0034 0029 #1.1 PARENTHESIZED NUMBER FOURTEEN +2482 ; disallowed_STD3_mapped ; 0028 0031 0035 0029 #1.1 PARENTHESIZED NUMBER FIFTEEN +2483 ; disallowed_STD3_mapped ; 0028 0031 0036 0029 #1.1 PARENTHESIZED NUMBER SIXTEEN +2484 ; disallowed_STD3_mapped ; 0028 0031 0037 0029 #1.1 PARENTHESIZED NUMBER SEVENTEEN +2485 ; disallowed_STD3_mapped ; 0028 0031 0038 0029 #1.1 PARENTHESIZED NUMBER EIGHTEEN +2486 ; disallowed_STD3_mapped ; 0028 0031 0039 0029 #1.1 PARENTHESIZED NUMBER NINETEEN +2487 ; disallowed_STD3_mapped ; 0028 0032 0030 0029 #1.1 PARENTHESIZED NUMBER TWENTY +2488..249B ; disallowed # 1.1 DIGIT ONE FULL STOP..NUMBER TWENTY FULL STOP +249C ; disallowed_STD3_mapped ; 0028 0061 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER A +249D ; disallowed_STD3_mapped ; 0028 0062 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER B +249E ; disallowed_STD3_mapped ; 0028 0063 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER C +249F ; disallowed_STD3_mapped ; 0028 0064 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER D +24A0 ; disallowed_STD3_mapped ; 0028 0065 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER E +24A1 ; disallowed_STD3_mapped ; 0028 0066 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER F +24A2 ; disallowed_STD3_mapped ; 0028 0067 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER G +24A3 ; disallowed_STD3_mapped ; 0028 0068 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER H +24A4 ; disallowed_STD3_mapped ; 0028 0069 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER I +24A5 ; disallowed_STD3_mapped ; 0028 006A 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER J +24A6 ; disallowed_STD3_mapped ; 0028 006B 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER K +24A7 ; disallowed_STD3_mapped ; 0028 006C 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER L +24A8 ; disallowed_STD3_mapped ; 0028 006D 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER M +24A9 ; disallowed_STD3_mapped ; 0028 006E 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER N +24AA ; disallowed_STD3_mapped ; 0028 006F 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER O +24AB ; disallowed_STD3_mapped ; 0028 0070 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER P +24AC ; disallowed_STD3_mapped ; 0028 0071 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER Q +24AD ; disallowed_STD3_mapped ; 0028 0072 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER R +24AE ; disallowed_STD3_mapped ; 0028 0073 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER S +24AF ; disallowed_STD3_mapped ; 0028 0074 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER T +24B0 ; disallowed_STD3_mapped ; 0028 0075 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER U +24B1 ; disallowed_STD3_mapped ; 0028 0076 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER V +24B2 ; disallowed_STD3_mapped ; 0028 0077 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER W +24B3 ; disallowed_STD3_mapped ; 0028 0078 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER X +24B4 ; disallowed_STD3_mapped ; 0028 0079 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER Y +24B5 ; disallowed_STD3_mapped ; 0028 007A 0029 #1.1 PARENTHESIZED LATIN SMALL LETTER Z +24B6 ; mapped ; 0061 # 1.1 CIRCLED LATIN CAPITAL LETTER A +24B7 ; mapped ; 0062 # 1.1 CIRCLED LATIN CAPITAL LETTER B +24B8 ; mapped ; 0063 # 1.1 CIRCLED LATIN CAPITAL LETTER C +24B9 ; mapped ; 0064 # 1.1 CIRCLED LATIN CAPITAL LETTER D +24BA ; mapped ; 0065 # 1.1 CIRCLED LATIN CAPITAL LETTER E +24BB ; mapped ; 0066 # 1.1 CIRCLED LATIN CAPITAL LETTER F +24BC ; mapped ; 0067 # 1.1 CIRCLED LATIN CAPITAL LETTER G +24BD ; mapped ; 0068 # 1.1 CIRCLED LATIN CAPITAL LETTER H +24BE ; mapped ; 0069 # 1.1 CIRCLED LATIN CAPITAL LETTER I +24BF ; mapped ; 006A # 1.1 CIRCLED LATIN CAPITAL LETTER J +24C0 ; mapped ; 006B # 1.1 CIRCLED LATIN CAPITAL LETTER K +24C1 ; mapped ; 006C # 1.1 CIRCLED LATIN CAPITAL LETTER L +24C2 ; mapped ; 006D # 1.1 CIRCLED LATIN CAPITAL LETTER M +24C3 ; mapped ; 006E # 1.1 CIRCLED LATIN CAPITAL LETTER N +24C4 ; mapped ; 006F # 1.1 CIRCLED LATIN CAPITAL LETTER O +24C5 ; mapped ; 0070 # 1.1 CIRCLED LATIN CAPITAL LETTER P +24C6 ; mapped ; 0071 # 1.1 CIRCLED LATIN CAPITAL LETTER Q +24C7 ; mapped ; 0072 # 1.1 CIRCLED LATIN CAPITAL LETTER R +24C8 ; mapped ; 0073 # 1.1 CIRCLED LATIN CAPITAL LETTER S +24C9 ; mapped ; 0074 # 1.1 CIRCLED LATIN CAPITAL LETTER T +24CA ; mapped ; 0075 # 1.1 CIRCLED LATIN CAPITAL LETTER U +24CB ; mapped ; 0076 # 1.1 CIRCLED LATIN CAPITAL LETTER V +24CC ; mapped ; 0077 # 1.1 CIRCLED LATIN CAPITAL LETTER W +24CD ; mapped ; 0078 # 1.1 CIRCLED LATIN CAPITAL LETTER X +24CE ; mapped ; 0079 # 1.1 CIRCLED LATIN CAPITAL LETTER Y +24CF ; mapped ; 007A # 1.1 CIRCLED LATIN CAPITAL LETTER Z +24D0 ; mapped ; 0061 # 1.1 CIRCLED LATIN SMALL LETTER A +24D1 ; mapped ; 0062 # 1.1 CIRCLED LATIN SMALL LETTER B +24D2 ; mapped ; 0063 # 1.1 CIRCLED LATIN SMALL LETTER C +24D3 ; mapped ; 0064 # 1.1 CIRCLED LATIN SMALL LETTER D +24D4 ; mapped ; 0065 # 1.1 CIRCLED LATIN SMALL LETTER E +24D5 ; mapped ; 0066 # 1.1 CIRCLED LATIN SMALL LETTER F +24D6 ; mapped ; 0067 # 1.1 CIRCLED LATIN SMALL LETTER G +24D7 ; mapped ; 0068 # 1.1 CIRCLED LATIN SMALL LETTER H +24D8 ; mapped ; 0069 # 1.1 CIRCLED LATIN SMALL LETTER I +24D9 ; mapped ; 006A # 1.1 CIRCLED LATIN SMALL LETTER J +24DA ; mapped ; 006B # 1.1 CIRCLED LATIN SMALL LETTER K +24DB ; mapped ; 006C # 1.1 CIRCLED LATIN SMALL LETTER L +24DC ; mapped ; 006D # 1.1 CIRCLED LATIN SMALL LETTER M +24DD ; mapped ; 006E # 1.1 CIRCLED LATIN SMALL LETTER N +24DE ; mapped ; 006F # 1.1 CIRCLED LATIN SMALL LETTER O +24DF ; mapped ; 0070 # 1.1 CIRCLED LATIN SMALL LETTER P +24E0 ; mapped ; 0071 # 1.1 CIRCLED LATIN SMALL LETTER Q +24E1 ; mapped ; 0072 # 1.1 CIRCLED LATIN SMALL LETTER R +24E2 ; mapped ; 0073 # 1.1 CIRCLED LATIN SMALL LETTER S +24E3 ; mapped ; 0074 # 1.1 CIRCLED LATIN SMALL LETTER T +24E4 ; mapped ; 0075 # 1.1 CIRCLED LATIN SMALL LETTER U +24E5 ; mapped ; 0076 # 1.1 CIRCLED LATIN SMALL LETTER V +24E6 ; mapped ; 0077 # 1.1 CIRCLED LATIN SMALL LETTER W +24E7 ; mapped ; 0078 # 1.1 CIRCLED LATIN SMALL LETTER X +24E8 ; mapped ; 0079 # 1.1 CIRCLED LATIN SMALL LETTER Y +24E9 ; mapped ; 007A # 1.1 CIRCLED LATIN SMALL LETTER Z +24EA ; mapped ; 0030 # 1.1 CIRCLED DIGIT ZERO +24EB..24FE ; valid ; ; NV8 # 3.2 NEGATIVE CIRCLED NUMBER ELEVEN..DOUBLE CIRCLED NUMBER TEN +24FF ; valid ; ; NV8 # 4.0 NEGATIVE CIRCLED DIGIT ZERO +2500..2595 ; valid ; ; NV8 # 1.1 BOX DRAWINGS LIGHT HORIZONTAL..RIGHT ONE EIGHTH BLOCK +2596..259F ; valid ; ; NV8 # 3.2 QUADRANT LOWER LEFT..QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT +25A0..25EF ; valid ; ; NV8 # 1.1 BLACK SQUARE..LARGE CIRCLE +25F0..25F7 ; valid ; ; NV8 # 3.0 WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8..25FF ; valid ; ; NV8 # 3.2 UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE +2600..2613 ; valid ; ; NV8 # 1.1 BLACK SUN WITH RAYS..SALTIRE +2614..2615 ; valid ; ; NV8 # 4.0 UMBRELLA WITH RAIN DROPS..HOT BEVERAGE +2616..2617 ; valid ; ; NV8 # 3.2 WHITE SHOGI PIECE..BLACK SHOGI PIECE +2618 ; valid ; ; NV8 # 4.1 SHAMROCK +2619 ; valid ; ; NV8 # 3.0 REVERSED ROTATED FLORAL HEART BULLET +261A..266F ; valid ; ; NV8 # 1.1 BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN +2670..2671 ; valid ; ; NV8 # 3.0 WEST SYRIAC CROSS..EAST SYRIAC CROSS +2672..267D ; valid ; ; NV8 # 3.2 UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL +267E..267F ; valid ; ; NV8 # 4.1 PERMANENT PAPER SIGN..WHEELCHAIR SYMBOL +2680..2689 ; valid ; ; NV8 # 3.2 DIE FACE-1..BLACK CIRCLE WITH TWO WHITE DOTS +268A..2691 ; valid ; ; NV8 # 4.0 MONOGRAM FOR YANG..BLACK FLAG +2692..269C ; valid ; ; NV8 # 4.1 HAMMER AND PICK..FLEUR-DE-LIS +269D ; valid ; ; NV8 # 5.1 OUTLINED WHITE STAR +269E..269F ; valid ; ; NV8 # 5.2 THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT +26A0..26A1 ; valid ; ; NV8 # 4.0 WARNING SIGN..HIGH VOLTAGE SIGN +26A2..26B1 ; valid ; ; NV8 # 4.1 DOUBLED FEMALE SIGN..FUNERAL URN +26B2 ; valid ; ; NV8 # 5.0 NEUTER +26B3..26BC ; valid ; ; NV8 # 5.1 CERES..SESQUIQUADRATE +26BD..26BF ; valid ; ; NV8 # 5.2 SOCCER BALL..SQUARED KEY +26C0..26C3 ; valid ; ; NV8 # 5.1 WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING +26C4..26CD ; valid ; ; NV8 # 5.2 SNOWMAN WITHOUT SNOW..DISABLED CAR +26CE ; valid ; ; NV8 # 6.0 OPHIUCHUS +26CF..26E1 ; valid ; ; NV8 # 5.2 PICK..RESTRICTED LEFT ENTRY-2 +26E2 ; valid ; ; NV8 # 6.0 ASTRONOMICAL SYMBOL FOR URANUS +26E3 ; valid ; ; NV8 # 5.2 HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE +26E4..26E7 ; valid ; ; NV8 # 6.0 PENTAGRAM..INVERTED PENTAGRAM +26E8..26FF ; valid ; ; NV8 # 5.2 BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700 ; valid ; ; NV8 # 7.0 BLACK SAFETY SCISSORS +2701..2704 ; valid ; ; NV8 # 1.1 UPPER BLADE SCISSORS..WHITE SCISSORS +2705 ; valid ; ; NV8 # 6.0 WHITE HEAVY CHECK MARK +2706..2709 ; valid ; ; NV8 # 1.1 TELEPHONE LOCATION SIGN..ENVELOPE +270A..270B ; valid ; ; NV8 # 6.0 RAISED FIST..RAISED HAND +270C..2727 ; valid ; ; NV8 # 1.1 VICTORY HAND..WHITE FOUR POINTED STAR +2728 ; valid ; ; NV8 # 6.0 SPARKLES +2729..274B ; valid ; ; NV8 # 1.1 STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274C ; valid ; ; NV8 # 6.0 CROSS MARK +274D ; valid ; ; NV8 # 1.1 SHADOWED WHITE CIRCLE +274E ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED CROSS MARK +274F..2752 ; valid ; ; NV8 # 1.1 LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE +2753..2755 ; valid ; ; NV8 # 6.0 BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT +2756 ; valid ; ; NV8 # 1.1 BLACK DIAMOND MINUS WHITE X +2757 ; valid ; ; NV8 # 5.2 HEAVY EXCLAMATION MARK SYMBOL +2758..275E ; valid ; ; NV8 # 1.1 LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +275F..2760 ; valid ; ; NV8 # 6.0 HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT..HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT +2761..2767 ; valid ; ; NV8 # 1.1 CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET +2768..2775 ; valid ; ; NV8 # 3.2 MEDIUM LEFT PARENTHESIS ORNAMENT..MEDIUM RIGHT CURLY BRACKET ORNAMENT +2776..2794 ; valid ; ; NV8 # 1.1 DINGBAT NEGATIVE CIRCLED DIGIT ONE..HEAVY WIDE-HEADED RIGHTWARDS ARROW +2795..2797 ; valid ; ; NV8 # 6.0 HEAVY PLUS SIGN..HEAVY DIVISION SIGN +2798..27AF ; valid ; ; NV8 # 1.1 HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B0 ; valid ; ; NV8 # 6.0 CURLY LOOP +27B1..27BE ; valid ; ; NV8 # 1.1 NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW +27BF ; valid ; ; NV8 # 6.0 DOUBLE CURLY LOOP +27C0..27C6 ; valid ; ; NV8 # 4.1 THREE DIMENSIONAL ANGLE..RIGHT S-SHAPED BAG DELIMITER +27C7..27CA ; valid ; ; NV8 # 5.0 OR WITH DOT INSIDE..VERTICAL BAR WITH HORIZONTAL STROKE +27CB ; valid ; ; NV8 # 6.1 MATHEMATICAL RISING DIAGONAL +27CC ; valid ; ; NV8 # 5.1 LONG DIVISION +27CD ; valid ; ; NV8 # 6.1 MATHEMATICAL FALLING DIAGONAL +27CE..27CF ; valid ; ; NV8 # 6.0 SQUARED LOGICAL AND..SQUARED LOGICAL OR +27D0..27EB ; valid ; ; NV8 # 3.2 WHITE DIAMOND WITH CENTRED DOT..MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC..27EF ; valid ; ; NV8 # 5.1 MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET..MATHEMATICAL RIGHT FLATTENED PARENTHESIS +27F0..27FF ; valid ; ; NV8 # 3.2 UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW +2800..28FF ; valid ; ; NV8 # 3.0 BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 +2900..2A0B ; valid ; ; NV8 # 3.2 RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..SUMMATION WITH INTEGRAL +2A0C ; mapped ; 222B 222B 222B 222B #3.2 QUADRUPLE INTEGRAL OPERATOR +2A0D..2A73 ; valid ; ; NV8 # 3.2 FINITE PART INTEGRAL..EQUALS SIGN ABOVE TILDE OPERATOR +2A74 ; disallowed_STD3_mapped ; 003A 003A 003D #3.2 DOUBLE COLON EQUAL +2A75 ; disallowed_STD3_mapped ; 003D 003D # 3.2 TWO CONSECUTIVE EQUALS SIGNS +2A76 ; disallowed_STD3_mapped ; 003D 003D 003D #3.2 THREE CONSECUTIVE EQUALS SIGNS +2A77..2ADB ; valid ; ; NV8 # 3.2 EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW..TRANSVERSAL INTERSECTION +2ADC ; mapped ; 2ADD 0338 # 3.2 FORKING +2ADD..2AFF ; valid ; ; NV8 # 3.2 NONFORKING..N-ARY WHITE VERTICAL BAR +2B00..2B0D ; valid ; ; NV8 # 4.0 NORTH EAST WHITE ARROW..UP DOWN BLACK ARROW +2B0E..2B13 ; valid ; ; NV8 # 4.1 RIGHTWARDS ARROW WITH TIP DOWNWARDS..SQUARE WITH BOTTOM HALF BLACK +2B14..2B1A ; valid ; ; NV8 # 5.0 SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK..DOTTED SQUARE +2B1B..2B1F ; valid ; ; NV8 # 5.1 BLACK LARGE SQUARE..BLACK PENTAGON +2B20..2B23 ; valid ; ; NV8 # 5.0 WHITE PENTAGON..HORIZONTAL BLACK HEXAGON +2B24..2B4C ; valid ; ; NV8 # 5.1 BLACK LARGE CIRCLE..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4D..2B4F ; valid ; ; NV8 # 7.0 DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW +2B50..2B54 ; valid ; ; NV8 # 5.1 WHITE MEDIUM STAR..WHITE RIGHT-POINTING PENTAGON +2B55..2B59 ; valid ; ; NV8 # 5.2 HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE +2B5A..2B73 ; valid ; ; NV8 # 7.0 SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B74..2B75 ; disallowed # NA .. +2B76..2B95 ; valid ; ; NV8 # 7.0 NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW +2B96..2B97 ; disallowed # NA .. +2B98..2BB9 ; valid ; ; NV8 # 7.0 THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX +2BBA..2BBC ; disallowed # NA .. +2BBD..2BC8 ; valid ; ; NV8 # 7.0 BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BC9 ; disallowed # NA +2BCA..2BD1 ; valid ; ; NV8 # 7.0 TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BD2 ; valid ; ; NV8 # 10.0 GROUP MARK +2BD3..2BEB ; disallowed # NA .. +2BEC..2BEF ; valid ; ; NV8 # 8.0 LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2BF0..2BFF ; disallowed # NA .. +2C00 ; mapped ; 2C30 # 4.1 GLAGOLITIC CAPITAL LETTER AZU +2C01 ; mapped ; 2C31 # 4.1 GLAGOLITIC CAPITAL LETTER BUKY +2C02 ; mapped ; 2C32 # 4.1 GLAGOLITIC CAPITAL LETTER VEDE +2C03 ; mapped ; 2C33 # 4.1 GLAGOLITIC CAPITAL LETTER GLAGOLI +2C04 ; mapped ; 2C34 # 4.1 GLAGOLITIC CAPITAL LETTER DOBRO +2C05 ; mapped ; 2C35 # 4.1 GLAGOLITIC CAPITAL LETTER YESTU +2C06 ; mapped ; 2C36 # 4.1 GLAGOLITIC CAPITAL LETTER ZHIVETE +2C07 ; mapped ; 2C37 # 4.1 GLAGOLITIC CAPITAL LETTER DZELO +2C08 ; mapped ; 2C38 # 4.1 GLAGOLITIC CAPITAL LETTER ZEMLJA +2C09 ; mapped ; 2C39 # 4.1 GLAGOLITIC CAPITAL LETTER IZHE +2C0A ; mapped ; 2C3A # 4.1 GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C0B ; mapped ; 2C3B # 4.1 GLAGOLITIC CAPITAL LETTER I +2C0C ; mapped ; 2C3C # 4.1 GLAGOLITIC CAPITAL LETTER DJERVI +2C0D ; mapped ; 2C3D # 4.1 GLAGOLITIC CAPITAL LETTER KAKO +2C0E ; mapped ; 2C3E # 4.1 GLAGOLITIC CAPITAL LETTER LJUDIJE +2C0F ; mapped ; 2C3F # 4.1 GLAGOLITIC CAPITAL LETTER MYSLITE +2C10 ; mapped ; 2C40 # 4.1 GLAGOLITIC CAPITAL LETTER NASHI +2C11 ; mapped ; 2C41 # 4.1 GLAGOLITIC CAPITAL LETTER ONU +2C12 ; mapped ; 2C42 # 4.1 GLAGOLITIC CAPITAL LETTER POKOJI +2C13 ; mapped ; 2C43 # 4.1 GLAGOLITIC CAPITAL LETTER RITSI +2C14 ; mapped ; 2C44 # 4.1 GLAGOLITIC CAPITAL LETTER SLOVO +2C15 ; mapped ; 2C45 # 4.1 GLAGOLITIC CAPITAL LETTER TVRIDO +2C16 ; mapped ; 2C46 # 4.1 GLAGOLITIC CAPITAL LETTER UKU +2C17 ; mapped ; 2C47 # 4.1 GLAGOLITIC CAPITAL LETTER FRITU +2C18 ; mapped ; 2C48 # 4.1 GLAGOLITIC CAPITAL LETTER HERU +2C19 ; mapped ; 2C49 # 4.1 GLAGOLITIC CAPITAL LETTER OTU +2C1A ; mapped ; 2C4A # 4.1 GLAGOLITIC CAPITAL LETTER PE +2C1B ; mapped ; 2C4B # 4.1 GLAGOLITIC CAPITAL LETTER SHTA +2C1C ; mapped ; 2C4C # 4.1 GLAGOLITIC CAPITAL LETTER TSI +2C1D ; mapped ; 2C4D # 4.1 GLAGOLITIC CAPITAL LETTER CHRIVI +2C1E ; mapped ; 2C4E # 4.1 GLAGOLITIC CAPITAL LETTER SHA +2C1F ; mapped ; 2C4F # 4.1 GLAGOLITIC CAPITAL LETTER YERU +2C20 ; mapped ; 2C50 # 4.1 GLAGOLITIC CAPITAL LETTER YERI +2C21 ; mapped ; 2C51 # 4.1 GLAGOLITIC CAPITAL LETTER YATI +2C22 ; mapped ; 2C52 # 4.1 GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C23 ; mapped ; 2C53 # 4.1 GLAGOLITIC CAPITAL LETTER YU +2C24 ; mapped ; 2C54 # 4.1 GLAGOLITIC CAPITAL LETTER SMALL YUS +2C25 ; mapped ; 2C55 # 4.1 GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C26 ; mapped ; 2C56 # 4.1 GLAGOLITIC CAPITAL LETTER YO +2C27 ; mapped ; 2C57 # 4.1 GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C28 ; mapped ; 2C58 # 4.1 GLAGOLITIC CAPITAL LETTER BIG YUS +2C29 ; mapped ; 2C59 # 4.1 GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C2A ; mapped ; 2C5A # 4.1 GLAGOLITIC CAPITAL LETTER FITA +2C2B ; mapped ; 2C5B # 4.1 GLAGOLITIC CAPITAL LETTER IZHITSA +2C2C ; mapped ; 2C5C # 4.1 GLAGOLITIC CAPITAL LETTER SHTAPIC +2C2D ; mapped ; 2C5D # 4.1 GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C2E ; mapped ; 2C5E # 4.1 GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C2F ; disallowed # NA +2C30..2C5E ; valid # 4.1 GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE +2C5F ; disallowed # NA +2C60 ; mapped ; 2C61 # 5.0 LATIN CAPITAL LETTER L WITH DOUBLE BAR +2C61 ; valid # 5.0 LATIN SMALL LETTER L WITH DOUBLE BAR +2C62 ; mapped ; 026B # 5.0 LATIN CAPITAL LETTER L WITH MIDDLE TILDE +2C63 ; mapped ; 1D7D # 5.0 LATIN CAPITAL LETTER P WITH STROKE +2C64 ; mapped ; 027D # 5.0 LATIN CAPITAL LETTER R WITH TAIL +2C65..2C66 ; valid # 5.0 LATIN SMALL LETTER A WITH STROKE..LATIN SMALL LETTER T WITH DIAGONAL STROKE +2C67 ; mapped ; 2C68 # 5.0 LATIN CAPITAL LETTER H WITH DESCENDER +2C68 ; valid # 5.0 LATIN SMALL LETTER H WITH DESCENDER +2C69 ; mapped ; 2C6A # 5.0 LATIN CAPITAL LETTER K WITH DESCENDER +2C6A ; valid # 5.0 LATIN SMALL LETTER K WITH DESCENDER +2C6B ; mapped ; 2C6C # 5.0 LATIN CAPITAL LETTER Z WITH DESCENDER +2C6C ; valid # 5.0 LATIN SMALL LETTER Z WITH DESCENDER +2C6D ; mapped ; 0251 # 5.1 LATIN CAPITAL LETTER ALPHA +2C6E ; mapped ; 0271 # 5.1 LATIN CAPITAL LETTER M WITH HOOK +2C6F ; mapped ; 0250 # 5.1 LATIN CAPITAL LETTER TURNED A +2C70 ; mapped ; 0252 # 5.2 LATIN CAPITAL LETTER TURNED ALPHA +2C71 ; valid # 5.1 LATIN SMALL LETTER V WITH RIGHT HOOK +2C72 ; mapped ; 2C73 # 5.1 LATIN CAPITAL LETTER W WITH HOOK +2C73 ; valid # 5.1 LATIN SMALL LETTER W WITH HOOK +2C74 ; valid # 5.0 LATIN SMALL LETTER V WITH CURL +2C75 ; mapped ; 2C76 # 5.0 LATIN CAPITAL LETTER HALF H +2C76..2C77 ; valid # 5.0 LATIN SMALL LETTER HALF H..LATIN SMALL LETTER TAILLESS PHI +2C78..2C7B ; valid # 5.1 LATIN SMALL LETTER E WITH NOTCH..LATIN LETTER SMALL CAPITAL TURNED E +2C7C ; mapped ; 006A # 5.1 LATIN SUBSCRIPT SMALL LETTER J +2C7D ; mapped ; 0076 # 5.1 MODIFIER LETTER CAPITAL V +2C7E ; mapped ; 023F # 5.2 LATIN CAPITAL LETTER S WITH SWASH TAIL +2C7F ; mapped ; 0240 # 5.2 LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80 ; mapped ; 2C81 # 4.1 COPTIC CAPITAL LETTER ALFA +2C81 ; valid # 4.1 COPTIC SMALL LETTER ALFA +2C82 ; mapped ; 2C83 # 4.1 COPTIC CAPITAL LETTER VIDA +2C83 ; valid # 4.1 COPTIC SMALL LETTER VIDA +2C84 ; mapped ; 2C85 # 4.1 COPTIC CAPITAL LETTER GAMMA +2C85 ; valid # 4.1 COPTIC SMALL LETTER GAMMA +2C86 ; mapped ; 2C87 # 4.1 COPTIC CAPITAL LETTER DALDA +2C87 ; valid # 4.1 COPTIC SMALL LETTER DALDA +2C88 ; mapped ; 2C89 # 4.1 COPTIC CAPITAL LETTER EIE +2C89 ; valid # 4.1 COPTIC SMALL LETTER EIE +2C8A ; mapped ; 2C8B # 4.1 COPTIC CAPITAL LETTER SOU +2C8B ; valid # 4.1 COPTIC SMALL LETTER SOU +2C8C ; mapped ; 2C8D # 4.1 COPTIC CAPITAL LETTER ZATA +2C8D ; valid # 4.1 COPTIC SMALL LETTER ZATA +2C8E ; mapped ; 2C8F # 4.1 COPTIC CAPITAL LETTER HATE +2C8F ; valid # 4.1 COPTIC SMALL LETTER HATE +2C90 ; mapped ; 2C91 # 4.1 COPTIC CAPITAL LETTER THETHE +2C91 ; valid # 4.1 COPTIC SMALL LETTER THETHE +2C92 ; mapped ; 2C93 # 4.1 COPTIC CAPITAL LETTER IAUDA +2C93 ; valid # 4.1 COPTIC SMALL LETTER IAUDA +2C94 ; mapped ; 2C95 # 4.1 COPTIC CAPITAL LETTER KAPA +2C95 ; valid # 4.1 COPTIC SMALL LETTER KAPA +2C96 ; mapped ; 2C97 # 4.1 COPTIC CAPITAL LETTER LAULA +2C97 ; valid # 4.1 COPTIC SMALL LETTER LAULA +2C98 ; mapped ; 2C99 # 4.1 COPTIC CAPITAL LETTER MI +2C99 ; valid # 4.1 COPTIC SMALL LETTER MI +2C9A ; mapped ; 2C9B # 4.1 COPTIC CAPITAL LETTER NI +2C9B ; valid # 4.1 COPTIC SMALL LETTER NI +2C9C ; mapped ; 2C9D # 4.1 COPTIC CAPITAL LETTER KSI +2C9D ; valid # 4.1 COPTIC SMALL LETTER KSI +2C9E ; mapped ; 2C9F # 4.1 COPTIC CAPITAL LETTER O +2C9F ; valid # 4.1 COPTIC SMALL LETTER O +2CA0 ; mapped ; 2CA1 # 4.1 COPTIC CAPITAL LETTER PI +2CA1 ; valid # 4.1 COPTIC SMALL LETTER PI +2CA2 ; mapped ; 2CA3 # 4.1 COPTIC CAPITAL LETTER RO +2CA3 ; valid # 4.1 COPTIC SMALL LETTER RO +2CA4 ; mapped ; 2CA5 # 4.1 COPTIC CAPITAL LETTER SIMA +2CA5 ; valid # 4.1 COPTIC SMALL LETTER SIMA +2CA6 ; mapped ; 2CA7 # 4.1 COPTIC CAPITAL LETTER TAU +2CA7 ; valid # 4.1 COPTIC SMALL LETTER TAU +2CA8 ; mapped ; 2CA9 # 4.1 COPTIC CAPITAL LETTER UA +2CA9 ; valid # 4.1 COPTIC SMALL LETTER UA +2CAA ; mapped ; 2CAB # 4.1 COPTIC CAPITAL LETTER FI +2CAB ; valid # 4.1 COPTIC SMALL LETTER FI +2CAC ; mapped ; 2CAD # 4.1 COPTIC CAPITAL LETTER KHI +2CAD ; valid # 4.1 COPTIC SMALL LETTER KHI +2CAE ; mapped ; 2CAF # 4.1 COPTIC CAPITAL LETTER PSI +2CAF ; valid # 4.1 COPTIC SMALL LETTER PSI +2CB0 ; mapped ; 2CB1 # 4.1 COPTIC CAPITAL LETTER OOU +2CB1 ; valid # 4.1 COPTIC SMALL LETTER OOU +2CB2 ; mapped ; 2CB3 # 4.1 COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB3 ; valid # 4.1 COPTIC SMALL LETTER DIALECT-P ALEF +2CB4 ; mapped ; 2CB5 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC AIN +2CB5 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC AIN +2CB6 ; mapped ; 2CB7 # 4.1 COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2CB7 ; valid # 4.1 COPTIC SMALL LETTER CRYPTOGRAMMIC EIE +2CB8 ; mapped ; 2CB9 # 4.1 COPTIC CAPITAL LETTER DIALECT-P KAPA +2CB9 ; valid # 4.1 COPTIC SMALL LETTER DIALECT-P KAPA +2CBA ; mapped ; 2CBB # 4.1 COPTIC CAPITAL LETTER DIALECT-P NI +2CBB ; valid # 4.1 COPTIC SMALL LETTER DIALECT-P NI +2CBC ; mapped ; 2CBD # 4.1 COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2CBD ; valid # 4.1 COPTIC SMALL LETTER CRYPTOGRAMMIC NI +2CBE ; mapped ; 2CBF # 4.1 COPTIC CAPITAL LETTER OLD COPTIC OOU +2CBF ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC OOU +2CC0 ; mapped ; 2CC1 # 4.1 COPTIC CAPITAL LETTER SAMPI +2CC1 ; valid # 4.1 COPTIC SMALL LETTER SAMPI +2CC2 ; mapped ; 2CC3 # 4.1 COPTIC CAPITAL LETTER CROSSED SHEI +2CC3 ; valid # 4.1 COPTIC SMALL LETTER CROSSED SHEI +2CC4 ; mapped ; 2CC5 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC5 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC SHEI +2CC6 ; mapped ; 2CC7 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC ESH +2CC7 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC ESH +2CC8 ; mapped ; 2CC9 # 4.1 COPTIC CAPITAL LETTER AKHMIMIC KHEI +2CC9 ; valid # 4.1 COPTIC SMALL LETTER AKHMIMIC KHEI +2CCA ; mapped ; 2CCB # 4.1 COPTIC CAPITAL LETTER DIALECT-P HORI +2CCB ; valid # 4.1 COPTIC SMALL LETTER DIALECT-P HORI +2CCC ; mapped ; 2CCD # 4.1 COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCD ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC HORI +2CCE ; mapped ; 2CCF # 4.1 COPTIC CAPITAL LETTER OLD COPTIC HA +2CCF ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC HA +2CD0 ; mapped ; 2CD1 # 4.1 COPTIC CAPITAL LETTER L-SHAPED HA +2CD1 ; valid # 4.1 COPTIC SMALL LETTER L-SHAPED HA +2CD2 ; mapped ; 2CD3 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD3 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC HEI +2CD4 ; mapped ; 2CD5 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC HAT +2CD5 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC HAT +2CD6 ; mapped ; 2CD7 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC GANGIA +2CD7 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC GANGIA +2CD8 ; mapped ; 2CD9 # 4.1 COPTIC CAPITAL LETTER OLD COPTIC DJA +2CD9 ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC DJA +2CDA ; mapped ; 2CDB # 4.1 COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDB ; valid # 4.1 COPTIC SMALL LETTER OLD COPTIC SHIMA +2CDC ; mapped ; 2CDD # 4.1 COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +2CDD ; valid # 4.1 COPTIC SMALL LETTER OLD NUBIAN SHIMA +2CDE ; mapped ; 2CDF # 4.1 COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CDF ; valid # 4.1 COPTIC SMALL LETTER OLD NUBIAN NGI +2CE0 ; mapped ; 2CE1 # 4.1 COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE1 ; valid # 4.1 COPTIC SMALL LETTER OLD NUBIAN NYI +2CE2 ; mapped ; 2CE3 # 4.1 COPTIC CAPITAL LETTER OLD NUBIAN WAU +2CE3..2CE4 ; valid # 4.1 COPTIC SMALL LETTER OLD NUBIAN WAU..COPTIC SYMBOL KAI +2CE5..2CEA ; valid ; ; NV8 # 4.1 COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA +2CEB ; mapped ; 2CEC # 5.2 COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI +2CEC ; valid # 5.2 COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI +2CED ; mapped ; 2CEE # 5.2 COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA +2CEE..2CF1 ; valid # 5.2 COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA..COPTIC COMBINING SPIRITUS LENIS +2CF2 ; mapped ; 2CF3 # 6.1 COPTIC CAPITAL LETTER BOHAIRIC KHEI +2CF3 ; valid # 6.1 COPTIC SMALL LETTER BOHAIRIC KHEI +2CF4..2CF8 ; disallowed # NA .. +2CF9..2CFF ; valid ; ; NV8 # 4.1 COPTIC OLD NUBIAN FULL STOP..COPTIC MORPHOLOGICAL DIVIDER +2D00..2D25 ; valid # 4.1 GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE +2D26 ; disallowed # NA +2D27 ; valid # 6.1 GEORGIAN SMALL LETTER YN +2D28..2D2C ; disallowed # NA .. +2D2D ; valid # 6.1 GEORGIAN SMALL LETTER AEN +2D2E..2D2F ; disallowed # NA .. +2D30..2D65 ; valid # 4.1 TIFINAGH LETTER YA..TIFINAGH LETTER YAZZ +2D66..2D67 ; valid # 6.1 TIFINAGH LETTER YE..TIFINAGH LETTER YO +2D68..2D6E ; disallowed # NA .. +2D6F ; mapped ; 2D61 # 4.1 TIFINAGH MODIFIER LETTER LABIALIZATION MARK +2D70 ; valid ; ; NV8 # 6.0 TIFINAGH SEPARATOR MARK +2D71..2D7E ; disallowed # NA .. +2D7F ; valid # 6.0 TIFINAGH CONSONANT JOINER +2D80..2D96 ; valid # 4.1 ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE +2D97..2D9F ; disallowed # NA .. +2DA0..2DA6 ; valid # 4.1 ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO +2DA7 ; disallowed # NA +2DA8..2DAE ; valid # 4.1 ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO +2DAF ; disallowed # NA +2DB0..2DB6 ; valid # 4.1 ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO +2DB7 ; disallowed # NA +2DB8..2DBE ; valid # 4.1 ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO +2DBF ; disallowed # NA +2DC0..2DC6 ; valid # 4.1 ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO +2DC7 ; disallowed # NA +2DC8..2DCE ; valid # 4.1 ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO +2DCF ; disallowed # NA +2DD0..2DD6 ; valid # 4.1 ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO +2DD7 ; disallowed # NA +2DD8..2DDE ; valid # 4.1 ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO +2DDF ; disallowed # NA +2DE0..2DFF ; valid # 5.1 COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +2E00..2E17 ; valid ; ; NV8 # 4.1 RIGHT ANGLE SUBSTITUTION MARKER..DOUBLE OBLIQUE HYPHEN +2E18..2E1B ; valid ; ; NV8 # 5.1 INVERTED INTERROBANG..TILDE WITH RING ABOVE +2E1C..2E1D ; valid ; ; NV8 # 4.1 LEFT LOW PARAPHRASE BRACKET..RIGHT LOW PARAPHRASE BRACKET +2E1E..2E2E ; valid ; ; NV8 # 5.1 TILDE WITH DOT ABOVE..REVERSED QUESTION MARK +2E2F ; valid # 5.1 VERTICAL TILDE +2E30 ; valid ; ; NV8 # 5.1 RING POINT +2E31 ; valid ; ; NV8 # 5.2 WORD SEPARATOR MIDDLE DOT +2E32..2E3B ; valid ; ; NV8 # 6.1 TURNED COMMA..THREE-EM DASH +2E3C..2E42 ; valid ; ; NV8 # 7.0 STENOGRAPHIC FULL STOP..DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E44 ; valid ; ; NV8 # 9.0 DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK +2E45..2E49 ; valid ; ; NV8 # 10.0 INVERTED LOW KAVYKA..DOUBLE STACKED COMMA +2E4A..2E7F ; disallowed # NA .. +2E80..2E99 ; valid ; ; NV8 # 3.0 CJK RADICAL REPEAT..CJK RADICAL RAP +2E9A ; disallowed # NA +2E9B..2E9E ; valid ; ; NV8 # 3.0 CJK RADICAL CHOKE..CJK RADICAL DEATH +2E9F ; mapped ; 6BCD # 3.0 CJK RADICAL MOTHER +2EA0..2EF2 ; valid ; ; NV8 # 3.0 CJK RADICAL CIVILIAN..CJK RADICAL J-SIMPLIFIED TURTLE +2EF3 ; mapped ; 9F9F # 3.0 CJK RADICAL C-SIMPLIFIED TURTLE +2EF4..2EFF ; disallowed # NA .. +2F00 ; mapped ; 4E00 # 3.0 KANGXI RADICAL ONE +2F01 ; mapped ; 4E28 # 3.0 KANGXI RADICAL LINE +2F02 ; mapped ; 4E36 # 3.0 KANGXI RADICAL DOT +2F03 ; mapped ; 4E3F # 3.0 KANGXI RADICAL SLASH +2F04 ; mapped ; 4E59 # 3.0 KANGXI RADICAL SECOND +2F05 ; mapped ; 4E85 # 3.0 KANGXI RADICAL HOOK +2F06 ; mapped ; 4E8C # 3.0 KANGXI RADICAL TWO +2F07 ; mapped ; 4EA0 # 3.0 KANGXI RADICAL LID +2F08 ; mapped ; 4EBA # 3.0 KANGXI RADICAL MAN +2F09 ; mapped ; 513F # 3.0 KANGXI RADICAL LEGS +2F0A ; mapped ; 5165 # 3.0 KANGXI RADICAL ENTER +2F0B ; mapped ; 516B # 3.0 KANGXI RADICAL EIGHT +2F0C ; mapped ; 5182 # 3.0 KANGXI RADICAL DOWN BOX +2F0D ; mapped ; 5196 # 3.0 KANGXI RADICAL COVER +2F0E ; mapped ; 51AB # 3.0 KANGXI RADICAL ICE +2F0F ; mapped ; 51E0 # 3.0 KANGXI RADICAL TABLE +2F10 ; mapped ; 51F5 # 3.0 KANGXI RADICAL OPEN BOX +2F11 ; mapped ; 5200 # 3.0 KANGXI RADICAL KNIFE +2F12 ; mapped ; 529B # 3.0 KANGXI RADICAL POWER +2F13 ; mapped ; 52F9 # 3.0 KANGXI RADICAL WRAP +2F14 ; mapped ; 5315 # 3.0 KANGXI RADICAL SPOON +2F15 ; mapped ; 531A # 3.0 KANGXI RADICAL RIGHT OPEN BOX +2F16 ; mapped ; 5338 # 3.0 KANGXI RADICAL HIDING ENCLOSURE +2F17 ; mapped ; 5341 # 3.0 KANGXI RADICAL TEN +2F18 ; mapped ; 535C # 3.0 KANGXI RADICAL DIVINATION +2F19 ; mapped ; 5369 # 3.0 KANGXI RADICAL SEAL +2F1A ; mapped ; 5382 # 3.0 KANGXI RADICAL CLIFF +2F1B ; mapped ; 53B6 # 3.0 KANGXI RADICAL PRIVATE +2F1C ; mapped ; 53C8 # 3.0 KANGXI RADICAL AGAIN +2F1D ; mapped ; 53E3 # 3.0 KANGXI RADICAL MOUTH +2F1E ; mapped ; 56D7 # 3.0 KANGXI RADICAL ENCLOSURE +2F1F ; mapped ; 571F # 3.0 KANGXI RADICAL EARTH +2F20 ; mapped ; 58EB # 3.0 KANGXI RADICAL SCHOLAR +2F21 ; mapped ; 5902 # 3.0 KANGXI RADICAL GO +2F22 ; mapped ; 590A # 3.0 KANGXI RADICAL GO SLOWLY +2F23 ; mapped ; 5915 # 3.0 KANGXI RADICAL EVENING +2F24 ; mapped ; 5927 # 3.0 KANGXI RADICAL BIG +2F25 ; mapped ; 5973 # 3.0 KANGXI RADICAL WOMAN +2F26 ; mapped ; 5B50 # 3.0 KANGXI RADICAL CHILD +2F27 ; mapped ; 5B80 # 3.0 KANGXI RADICAL ROOF +2F28 ; mapped ; 5BF8 # 3.0 KANGXI RADICAL INCH +2F29 ; mapped ; 5C0F # 3.0 KANGXI RADICAL SMALL +2F2A ; mapped ; 5C22 # 3.0 KANGXI RADICAL LAME +2F2B ; mapped ; 5C38 # 3.0 KANGXI RADICAL CORPSE +2F2C ; mapped ; 5C6E # 3.0 KANGXI RADICAL SPROUT +2F2D ; mapped ; 5C71 # 3.0 KANGXI RADICAL MOUNTAIN +2F2E ; mapped ; 5DDB # 3.0 KANGXI RADICAL RIVER +2F2F ; mapped ; 5DE5 # 3.0 KANGXI RADICAL WORK +2F30 ; mapped ; 5DF1 # 3.0 KANGXI RADICAL ONESELF +2F31 ; mapped ; 5DFE # 3.0 KANGXI RADICAL TURBAN +2F32 ; mapped ; 5E72 # 3.0 KANGXI RADICAL DRY +2F33 ; mapped ; 5E7A # 3.0 KANGXI RADICAL SHORT THREAD +2F34 ; mapped ; 5E7F # 3.0 KANGXI RADICAL DOTTED CLIFF +2F35 ; mapped ; 5EF4 # 3.0 KANGXI RADICAL LONG STRIDE +2F36 ; mapped ; 5EFE # 3.0 KANGXI RADICAL TWO HANDS +2F37 ; mapped ; 5F0B # 3.0 KANGXI RADICAL SHOOT +2F38 ; mapped ; 5F13 # 3.0 KANGXI RADICAL BOW +2F39 ; mapped ; 5F50 # 3.0 KANGXI RADICAL SNOUT +2F3A ; mapped ; 5F61 # 3.0 KANGXI RADICAL BRISTLE +2F3B ; mapped ; 5F73 # 3.0 KANGXI RADICAL STEP +2F3C ; mapped ; 5FC3 # 3.0 KANGXI RADICAL HEART +2F3D ; mapped ; 6208 # 3.0 KANGXI RADICAL HALBERD +2F3E ; mapped ; 6236 # 3.0 KANGXI RADICAL DOOR +2F3F ; mapped ; 624B # 3.0 KANGXI RADICAL HAND +2F40 ; mapped ; 652F # 3.0 KANGXI RADICAL BRANCH +2F41 ; mapped ; 6534 # 3.0 KANGXI RADICAL RAP +2F42 ; mapped ; 6587 # 3.0 KANGXI RADICAL SCRIPT +2F43 ; mapped ; 6597 # 3.0 KANGXI RADICAL DIPPER +2F44 ; mapped ; 65A4 # 3.0 KANGXI RADICAL AXE +2F45 ; mapped ; 65B9 # 3.0 KANGXI RADICAL SQUARE +2F46 ; mapped ; 65E0 # 3.0 KANGXI RADICAL NOT +2F47 ; mapped ; 65E5 # 3.0 KANGXI RADICAL SUN +2F48 ; mapped ; 66F0 # 3.0 KANGXI RADICAL SAY +2F49 ; mapped ; 6708 # 3.0 KANGXI RADICAL MOON +2F4A ; mapped ; 6728 # 3.0 KANGXI RADICAL TREE +2F4B ; mapped ; 6B20 # 3.0 KANGXI RADICAL LACK +2F4C ; mapped ; 6B62 # 3.0 KANGXI RADICAL STOP +2F4D ; mapped ; 6B79 # 3.0 KANGXI RADICAL DEATH +2F4E ; mapped ; 6BB3 # 3.0 KANGXI RADICAL WEAPON +2F4F ; mapped ; 6BCB # 3.0 KANGXI RADICAL DO NOT +2F50 ; mapped ; 6BD4 # 3.0 KANGXI RADICAL COMPARE +2F51 ; mapped ; 6BDB # 3.0 KANGXI RADICAL FUR +2F52 ; mapped ; 6C0F # 3.0 KANGXI RADICAL CLAN +2F53 ; mapped ; 6C14 # 3.0 KANGXI RADICAL STEAM +2F54 ; mapped ; 6C34 # 3.0 KANGXI RADICAL WATER +2F55 ; mapped ; 706B # 3.0 KANGXI RADICAL FIRE +2F56 ; mapped ; 722A # 3.0 KANGXI RADICAL CLAW +2F57 ; mapped ; 7236 # 3.0 KANGXI RADICAL FATHER +2F58 ; mapped ; 723B # 3.0 KANGXI RADICAL DOUBLE X +2F59 ; mapped ; 723F # 3.0 KANGXI RADICAL HALF TREE TRUNK +2F5A ; mapped ; 7247 # 3.0 KANGXI RADICAL SLICE +2F5B ; mapped ; 7259 # 3.0 KANGXI RADICAL FANG +2F5C ; mapped ; 725B # 3.0 KANGXI RADICAL COW +2F5D ; mapped ; 72AC # 3.0 KANGXI RADICAL DOG +2F5E ; mapped ; 7384 # 3.0 KANGXI RADICAL PROFOUND +2F5F ; mapped ; 7389 # 3.0 KANGXI RADICAL JADE +2F60 ; mapped ; 74DC # 3.0 KANGXI RADICAL MELON +2F61 ; mapped ; 74E6 # 3.0 KANGXI RADICAL TILE +2F62 ; mapped ; 7518 # 3.0 KANGXI RADICAL SWEET +2F63 ; mapped ; 751F # 3.0 KANGXI RADICAL LIFE +2F64 ; mapped ; 7528 # 3.0 KANGXI RADICAL USE +2F65 ; mapped ; 7530 # 3.0 KANGXI RADICAL FIELD +2F66 ; mapped ; 758B # 3.0 KANGXI RADICAL BOLT OF CLOTH +2F67 ; mapped ; 7592 # 3.0 KANGXI RADICAL SICKNESS +2F68 ; mapped ; 7676 # 3.0 KANGXI RADICAL DOTTED TENT +2F69 ; mapped ; 767D # 3.0 KANGXI RADICAL WHITE +2F6A ; mapped ; 76AE # 3.0 KANGXI RADICAL SKIN +2F6B ; mapped ; 76BF # 3.0 KANGXI RADICAL DISH +2F6C ; mapped ; 76EE # 3.0 KANGXI RADICAL EYE +2F6D ; mapped ; 77DB # 3.0 KANGXI RADICAL SPEAR +2F6E ; mapped ; 77E2 # 3.0 KANGXI RADICAL ARROW +2F6F ; mapped ; 77F3 # 3.0 KANGXI RADICAL STONE +2F70 ; mapped ; 793A # 3.0 KANGXI RADICAL SPIRIT +2F71 ; mapped ; 79B8 # 3.0 KANGXI RADICAL TRACK +2F72 ; mapped ; 79BE # 3.0 KANGXI RADICAL GRAIN +2F73 ; mapped ; 7A74 # 3.0 KANGXI RADICAL CAVE +2F74 ; mapped ; 7ACB # 3.0 KANGXI RADICAL STAND +2F75 ; mapped ; 7AF9 # 3.0 KANGXI RADICAL BAMBOO +2F76 ; mapped ; 7C73 # 3.0 KANGXI RADICAL RICE +2F77 ; mapped ; 7CF8 # 3.0 KANGXI RADICAL SILK +2F78 ; mapped ; 7F36 # 3.0 KANGXI RADICAL JAR +2F79 ; mapped ; 7F51 # 3.0 KANGXI RADICAL NET +2F7A ; mapped ; 7F8A # 3.0 KANGXI RADICAL SHEEP +2F7B ; mapped ; 7FBD # 3.0 KANGXI RADICAL FEATHER +2F7C ; mapped ; 8001 # 3.0 KANGXI RADICAL OLD +2F7D ; mapped ; 800C # 3.0 KANGXI RADICAL AND +2F7E ; mapped ; 8012 # 3.0 KANGXI RADICAL PLOW +2F7F ; mapped ; 8033 # 3.0 KANGXI RADICAL EAR +2F80 ; mapped ; 807F # 3.0 KANGXI RADICAL BRUSH +2F81 ; mapped ; 8089 # 3.0 KANGXI RADICAL MEAT +2F82 ; mapped ; 81E3 # 3.0 KANGXI RADICAL MINISTER +2F83 ; mapped ; 81EA # 3.0 KANGXI RADICAL SELF +2F84 ; mapped ; 81F3 # 3.0 KANGXI RADICAL ARRIVE +2F85 ; mapped ; 81FC # 3.0 KANGXI RADICAL MORTAR +2F86 ; mapped ; 820C # 3.0 KANGXI RADICAL TONGUE +2F87 ; mapped ; 821B # 3.0 KANGXI RADICAL OPPOSE +2F88 ; mapped ; 821F # 3.0 KANGXI RADICAL BOAT +2F89 ; mapped ; 826E # 3.0 KANGXI RADICAL STOPPING +2F8A ; mapped ; 8272 # 3.0 KANGXI RADICAL COLOR +2F8B ; mapped ; 8278 # 3.0 KANGXI RADICAL GRASS +2F8C ; mapped ; 864D # 3.0 KANGXI RADICAL TIGER +2F8D ; mapped ; 866B # 3.0 KANGXI RADICAL INSECT +2F8E ; mapped ; 8840 # 3.0 KANGXI RADICAL BLOOD +2F8F ; mapped ; 884C # 3.0 KANGXI RADICAL WALK ENCLOSURE +2F90 ; mapped ; 8863 # 3.0 KANGXI RADICAL CLOTHES +2F91 ; mapped ; 897E # 3.0 KANGXI RADICAL WEST +2F92 ; mapped ; 898B # 3.0 KANGXI RADICAL SEE +2F93 ; mapped ; 89D2 # 3.0 KANGXI RADICAL HORN +2F94 ; mapped ; 8A00 # 3.0 KANGXI RADICAL SPEECH +2F95 ; mapped ; 8C37 # 3.0 KANGXI RADICAL VALLEY +2F96 ; mapped ; 8C46 # 3.0 KANGXI RADICAL BEAN +2F97 ; mapped ; 8C55 # 3.0 KANGXI RADICAL PIG +2F98 ; mapped ; 8C78 # 3.0 KANGXI RADICAL BADGER +2F99 ; mapped ; 8C9D # 3.0 KANGXI RADICAL SHELL +2F9A ; mapped ; 8D64 # 3.0 KANGXI RADICAL RED +2F9B ; mapped ; 8D70 # 3.0 KANGXI RADICAL RUN +2F9C ; mapped ; 8DB3 # 3.0 KANGXI RADICAL FOOT +2F9D ; mapped ; 8EAB # 3.0 KANGXI RADICAL BODY +2F9E ; mapped ; 8ECA # 3.0 KANGXI RADICAL CART +2F9F ; mapped ; 8F9B # 3.0 KANGXI RADICAL BITTER +2FA0 ; mapped ; 8FB0 # 3.0 KANGXI RADICAL MORNING +2FA1 ; mapped ; 8FB5 # 3.0 KANGXI RADICAL WALK +2FA2 ; mapped ; 9091 # 3.0 KANGXI RADICAL CITY +2FA3 ; mapped ; 9149 # 3.0 KANGXI RADICAL WINE +2FA4 ; mapped ; 91C6 # 3.0 KANGXI RADICAL DISTINGUISH +2FA5 ; mapped ; 91CC # 3.0 KANGXI RADICAL VILLAGE +2FA6 ; mapped ; 91D1 # 3.0 KANGXI RADICAL GOLD +2FA7 ; mapped ; 9577 # 3.0 KANGXI RADICAL LONG +2FA8 ; mapped ; 9580 # 3.0 KANGXI RADICAL GATE +2FA9 ; mapped ; 961C # 3.0 KANGXI RADICAL MOUND +2FAA ; mapped ; 96B6 # 3.0 KANGXI RADICAL SLAVE +2FAB ; mapped ; 96B9 # 3.0 KANGXI RADICAL SHORT TAILED BIRD +2FAC ; mapped ; 96E8 # 3.0 KANGXI RADICAL RAIN +2FAD ; mapped ; 9751 # 3.0 KANGXI RADICAL BLUE +2FAE ; mapped ; 975E # 3.0 KANGXI RADICAL WRONG +2FAF ; mapped ; 9762 # 3.0 KANGXI RADICAL FACE +2FB0 ; mapped ; 9769 # 3.0 KANGXI RADICAL LEATHER +2FB1 ; mapped ; 97CB # 3.0 KANGXI RADICAL TANNED LEATHER +2FB2 ; mapped ; 97ED # 3.0 KANGXI RADICAL LEEK +2FB3 ; mapped ; 97F3 # 3.0 KANGXI RADICAL SOUND +2FB4 ; mapped ; 9801 # 3.0 KANGXI RADICAL LEAF +2FB5 ; mapped ; 98A8 # 3.0 KANGXI RADICAL WIND +2FB6 ; mapped ; 98DB # 3.0 KANGXI RADICAL FLY +2FB7 ; mapped ; 98DF # 3.0 KANGXI RADICAL EAT +2FB8 ; mapped ; 9996 # 3.0 KANGXI RADICAL HEAD +2FB9 ; mapped ; 9999 # 3.0 KANGXI RADICAL FRAGRANT +2FBA ; mapped ; 99AC # 3.0 KANGXI RADICAL HORSE +2FBB ; mapped ; 9AA8 # 3.0 KANGXI RADICAL BONE +2FBC ; mapped ; 9AD8 # 3.0 KANGXI RADICAL TALL +2FBD ; mapped ; 9ADF # 3.0 KANGXI RADICAL HAIR +2FBE ; mapped ; 9B25 # 3.0 KANGXI RADICAL FIGHT +2FBF ; mapped ; 9B2F # 3.0 KANGXI RADICAL SACRIFICIAL WINE +2FC0 ; mapped ; 9B32 # 3.0 KANGXI RADICAL CAULDRON +2FC1 ; mapped ; 9B3C # 3.0 KANGXI RADICAL GHOST +2FC2 ; mapped ; 9B5A # 3.0 KANGXI RADICAL FISH +2FC3 ; mapped ; 9CE5 # 3.0 KANGXI RADICAL BIRD +2FC4 ; mapped ; 9E75 # 3.0 KANGXI RADICAL SALT +2FC5 ; mapped ; 9E7F # 3.0 KANGXI RADICAL DEER +2FC6 ; mapped ; 9EA5 # 3.0 KANGXI RADICAL WHEAT +2FC7 ; mapped ; 9EBB # 3.0 KANGXI RADICAL HEMP +2FC8 ; mapped ; 9EC3 # 3.0 KANGXI RADICAL YELLOW +2FC9 ; mapped ; 9ECD # 3.0 KANGXI RADICAL MILLET +2FCA ; mapped ; 9ED1 # 3.0 KANGXI RADICAL BLACK +2FCB ; mapped ; 9EF9 # 3.0 KANGXI RADICAL EMBROIDERY +2FCC ; mapped ; 9EFD # 3.0 KANGXI RADICAL FROG +2FCD ; mapped ; 9F0E # 3.0 KANGXI RADICAL TRIPOD +2FCE ; mapped ; 9F13 # 3.0 KANGXI RADICAL DRUM +2FCF ; mapped ; 9F20 # 3.0 KANGXI RADICAL RAT +2FD0 ; mapped ; 9F3B # 3.0 KANGXI RADICAL NOSE +2FD1 ; mapped ; 9F4A # 3.0 KANGXI RADICAL EVEN +2FD2 ; mapped ; 9F52 # 3.0 KANGXI RADICAL TOOTH +2FD3 ; mapped ; 9F8D # 3.0 KANGXI RADICAL DRAGON +2FD4 ; mapped ; 9F9C # 3.0 KANGXI RADICAL TURTLE +2FD5 ; mapped ; 9FA0 # 3.0 KANGXI RADICAL FLUTE +2FD6..2FEF ; disallowed # NA .. +2FF0..2FFB ; disallowed # 3.0 IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +2FFC..2FFF ; disallowed # NA .. +3000 ; disallowed_STD3_mapped ; 0020 # 1.1 IDEOGRAPHIC SPACE +3001 ; valid ; ; NV8 # 1.1 IDEOGRAPHIC COMMA +3002 ; mapped ; 002E # 1.1 IDEOGRAPHIC FULL STOP +3003..3004 ; valid ; ; NV8 # 1.1 DITTO MARK..JAPANESE INDUSTRIAL STANDARD SYMBOL +3005..3007 ; valid # 1.1 IDEOGRAPHIC ITERATION MARK..IDEOGRAPHIC NUMBER ZERO +3008..3029 ; valid ; ; NV8 # 1.1 LEFT ANGLE BRACKET..HANGZHOU NUMERAL NINE +302A..302D ; valid # 1.1 IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK +302E..3035 ; valid ; ; NV8 # 1.1 HANGUL SINGLE DOT TONE MARK..VERTICAL KANA REPEAT MARK LOWER HALF +3036 ; mapped ; 3012 # 1.1 CIRCLED POSTAL MARK +3037 ; valid ; ; NV8 # 1.1 IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +3038 ; mapped ; 5341 # 3.0 HANGZHOU NUMERAL TEN +3039 ; mapped ; 5344 # 3.0 HANGZHOU NUMERAL TWENTY +303A ; mapped ; 5345 # 3.0 HANGZHOU NUMERAL THIRTY +303B ; valid ; ; NV8 # 3.2 VERTICAL IDEOGRAPHIC ITERATION MARK +303C ; valid # 3.2 MASU MARK +303D ; valid ; ; NV8 # 3.2 PART ALTERNATION MARK +303E ; valid ; ; NV8 # 3.0 IDEOGRAPHIC VARIATION INDICATOR +303F ; valid ; ; NV8 # 1.1 IDEOGRAPHIC HALF FILL SPACE +3040 ; disallowed # NA +3041..3094 ; valid # 1.1 HIRAGANA LETTER SMALL A..HIRAGANA LETTER VU +3095..3096 ; valid # 3.2 HIRAGANA LETTER SMALL KA..HIRAGANA LETTER SMALL KE +3097..3098 ; disallowed # NA .. +3099..309A ; valid # 1.1 COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309B ; disallowed_STD3_mapped ; 0020 3099 # 1.1 KATAKANA-HIRAGANA VOICED SOUND MARK +309C ; disallowed_STD3_mapped ; 0020 309A # 1.1 KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D..309E ; valid # 1.1 HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +309F ; mapped ; 3088 308A # 3.2 HIRAGANA DIGRAPH YORI +30A0 ; valid ; ; NV8 # 3.2 KATAKANA-HIRAGANA DOUBLE HYPHEN +30A1..30FE ; valid # 1.1 KATAKANA LETTER SMALL A..KATAKANA VOICED ITERATION MARK +30FF ; mapped ; 30B3 30C8 # 3.2 KATAKANA DIGRAPH KOTO +3100..3104 ; disallowed # NA .. +3105..312C ; valid # 1.1 BOPOMOFO LETTER B..BOPOMOFO LETTER GN +312D ; valid # 5.1 BOPOMOFO LETTER IH +312E ; valid # 10.0 BOPOMOFO LETTER O WITH DOT ABOVE +312F..3130 ; disallowed # NA .. +3131 ; mapped ; 1100 # 1.1 HANGUL LETTER KIYEOK +3132 ; mapped ; 1101 # 1.1 HANGUL LETTER SSANGKIYEOK +3133 ; mapped ; 11AA # 1.1 HANGUL LETTER KIYEOK-SIOS +3134 ; mapped ; 1102 # 1.1 HANGUL LETTER NIEUN +3135 ; mapped ; 11AC # 1.1 HANGUL LETTER NIEUN-CIEUC +3136 ; mapped ; 11AD # 1.1 HANGUL LETTER NIEUN-HIEUH +3137 ; mapped ; 1103 # 1.1 HANGUL LETTER TIKEUT +3138 ; mapped ; 1104 # 1.1 HANGUL LETTER SSANGTIKEUT +3139 ; mapped ; 1105 # 1.1 HANGUL LETTER RIEUL +313A ; mapped ; 11B0 # 1.1 HANGUL LETTER RIEUL-KIYEOK +313B ; mapped ; 11B1 # 1.1 HANGUL LETTER RIEUL-MIEUM +313C ; mapped ; 11B2 # 1.1 HANGUL LETTER RIEUL-PIEUP +313D ; mapped ; 11B3 # 1.1 HANGUL LETTER RIEUL-SIOS +313E ; mapped ; 11B4 # 1.1 HANGUL LETTER RIEUL-THIEUTH +313F ; mapped ; 11B5 # 1.1 HANGUL LETTER RIEUL-PHIEUPH +3140 ; mapped ; 111A # 1.1 HANGUL LETTER RIEUL-HIEUH +3141 ; mapped ; 1106 # 1.1 HANGUL LETTER MIEUM +3142 ; mapped ; 1107 # 1.1 HANGUL LETTER PIEUP +3143 ; mapped ; 1108 # 1.1 HANGUL LETTER SSANGPIEUP +3144 ; mapped ; 1121 # 1.1 HANGUL LETTER PIEUP-SIOS +3145 ; mapped ; 1109 # 1.1 HANGUL LETTER SIOS +3146 ; mapped ; 110A # 1.1 HANGUL LETTER SSANGSIOS +3147 ; mapped ; 110B # 1.1 HANGUL LETTER IEUNG +3148 ; mapped ; 110C # 1.1 HANGUL LETTER CIEUC +3149 ; mapped ; 110D # 1.1 HANGUL LETTER SSANGCIEUC +314A ; mapped ; 110E # 1.1 HANGUL LETTER CHIEUCH +314B ; mapped ; 110F # 1.1 HANGUL LETTER KHIEUKH +314C ; mapped ; 1110 # 1.1 HANGUL LETTER THIEUTH +314D ; mapped ; 1111 # 1.1 HANGUL LETTER PHIEUPH +314E ; mapped ; 1112 # 1.1 HANGUL LETTER HIEUH +314F ; mapped ; 1161 # 1.1 HANGUL LETTER A +3150 ; mapped ; 1162 # 1.1 HANGUL LETTER AE +3151 ; mapped ; 1163 # 1.1 HANGUL LETTER YA +3152 ; mapped ; 1164 # 1.1 HANGUL LETTER YAE +3153 ; mapped ; 1165 # 1.1 HANGUL LETTER EO +3154 ; mapped ; 1166 # 1.1 HANGUL LETTER E +3155 ; mapped ; 1167 # 1.1 HANGUL LETTER YEO +3156 ; mapped ; 1168 # 1.1 HANGUL LETTER YE +3157 ; mapped ; 1169 # 1.1 HANGUL LETTER O +3158 ; mapped ; 116A # 1.1 HANGUL LETTER WA +3159 ; mapped ; 116B # 1.1 HANGUL LETTER WAE +315A ; mapped ; 116C # 1.1 HANGUL LETTER OE +315B ; mapped ; 116D # 1.1 HANGUL LETTER YO +315C ; mapped ; 116E # 1.1 HANGUL LETTER U +315D ; mapped ; 116F # 1.1 HANGUL LETTER WEO +315E ; mapped ; 1170 # 1.1 HANGUL LETTER WE +315F ; mapped ; 1171 # 1.1 HANGUL LETTER WI +3160 ; mapped ; 1172 # 1.1 HANGUL LETTER YU +3161 ; mapped ; 1173 # 1.1 HANGUL LETTER EU +3162 ; mapped ; 1174 # 1.1 HANGUL LETTER YI +3163 ; mapped ; 1175 # 1.1 HANGUL LETTER I +3164 ; disallowed # 1.1 HANGUL FILLER +3165 ; mapped ; 1114 # 1.1 HANGUL LETTER SSANGNIEUN +3166 ; mapped ; 1115 # 1.1 HANGUL LETTER NIEUN-TIKEUT +3167 ; mapped ; 11C7 # 1.1 HANGUL LETTER NIEUN-SIOS +3168 ; mapped ; 11C8 # 1.1 HANGUL LETTER NIEUN-PANSIOS +3169 ; mapped ; 11CC # 1.1 HANGUL LETTER RIEUL-KIYEOK-SIOS +316A ; mapped ; 11CE # 1.1 HANGUL LETTER RIEUL-TIKEUT +316B ; mapped ; 11D3 # 1.1 HANGUL LETTER RIEUL-PIEUP-SIOS +316C ; mapped ; 11D7 # 1.1 HANGUL LETTER RIEUL-PANSIOS +316D ; mapped ; 11D9 # 1.1 HANGUL LETTER RIEUL-YEORINHIEUH +316E ; mapped ; 111C # 1.1 HANGUL LETTER MIEUM-PIEUP +316F ; mapped ; 11DD # 1.1 HANGUL LETTER MIEUM-SIOS +3170 ; mapped ; 11DF # 1.1 HANGUL LETTER MIEUM-PANSIOS +3171 ; mapped ; 111D # 1.1 HANGUL LETTER KAPYEOUNMIEUM +3172 ; mapped ; 111E # 1.1 HANGUL LETTER PIEUP-KIYEOK +3173 ; mapped ; 1120 # 1.1 HANGUL LETTER PIEUP-TIKEUT +3174 ; mapped ; 1122 # 1.1 HANGUL LETTER PIEUP-SIOS-KIYEOK +3175 ; mapped ; 1123 # 1.1 HANGUL LETTER PIEUP-SIOS-TIKEUT +3176 ; mapped ; 1127 # 1.1 HANGUL LETTER PIEUP-CIEUC +3177 ; mapped ; 1129 # 1.1 HANGUL LETTER PIEUP-THIEUTH +3178 ; mapped ; 112B # 1.1 HANGUL LETTER KAPYEOUNPIEUP +3179 ; mapped ; 112C # 1.1 HANGUL LETTER KAPYEOUNSSANGPIEUP +317A ; mapped ; 112D # 1.1 HANGUL LETTER SIOS-KIYEOK +317B ; mapped ; 112E # 1.1 HANGUL LETTER SIOS-NIEUN +317C ; mapped ; 112F # 1.1 HANGUL LETTER SIOS-TIKEUT +317D ; mapped ; 1132 # 1.1 HANGUL LETTER SIOS-PIEUP +317E ; mapped ; 1136 # 1.1 HANGUL LETTER SIOS-CIEUC +317F ; mapped ; 1140 # 1.1 HANGUL LETTER PANSIOS +3180 ; mapped ; 1147 # 1.1 HANGUL LETTER SSANGIEUNG +3181 ; mapped ; 114C # 1.1 HANGUL LETTER YESIEUNG +3182 ; mapped ; 11F1 # 1.1 HANGUL LETTER YESIEUNG-SIOS +3183 ; mapped ; 11F2 # 1.1 HANGUL LETTER YESIEUNG-PANSIOS +3184 ; mapped ; 1157 # 1.1 HANGUL LETTER KAPYEOUNPHIEUPH +3185 ; mapped ; 1158 # 1.1 HANGUL LETTER SSANGHIEUH +3186 ; mapped ; 1159 # 1.1 HANGUL LETTER YEORINHIEUH +3187 ; mapped ; 1184 # 1.1 HANGUL LETTER YO-YA +3188 ; mapped ; 1185 # 1.1 HANGUL LETTER YO-YAE +3189 ; mapped ; 1188 # 1.1 HANGUL LETTER YO-I +318A ; mapped ; 1191 # 1.1 HANGUL LETTER YU-YEO +318B ; mapped ; 1192 # 1.1 HANGUL LETTER YU-YE +318C ; mapped ; 1194 # 1.1 HANGUL LETTER YU-I +318D ; mapped ; 119E # 1.1 HANGUL LETTER ARAEA +318E ; mapped ; 11A1 # 1.1 HANGUL LETTER ARAEAE +318F ; disallowed # NA +3190..3191 ; valid ; ; NV8 # 1.1 IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK +3192 ; mapped ; 4E00 # 1.1 IDEOGRAPHIC ANNOTATION ONE MARK +3193 ; mapped ; 4E8C # 1.1 IDEOGRAPHIC ANNOTATION TWO MARK +3194 ; mapped ; 4E09 # 1.1 IDEOGRAPHIC ANNOTATION THREE MARK +3195 ; mapped ; 56DB # 1.1 IDEOGRAPHIC ANNOTATION FOUR MARK +3196 ; mapped ; 4E0A # 1.1 IDEOGRAPHIC ANNOTATION TOP MARK +3197 ; mapped ; 4E2D # 1.1 IDEOGRAPHIC ANNOTATION MIDDLE MARK +3198 ; mapped ; 4E0B # 1.1 IDEOGRAPHIC ANNOTATION BOTTOM MARK +3199 ; mapped ; 7532 # 1.1 IDEOGRAPHIC ANNOTATION FIRST MARK +319A ; mapped ; 4E59 # 1.1 IDEOGRAPHIC ANNOTATION SECOND MARK +319B ; mapped ; 4E19 # 1.1 IDEOGRAPHIC ANNOTATION THIRD MARK +319C ; mapped ; 4E01 # 1.1 IDEOGRAPHIC ANNOTATION FOURTH MARK +319D ; mapped ; 5929 # 1.1 IDEOGRAPHIC ANNOTATION HEAVEN MARK +319E ; mapped ; 5730 # 1.1 IDEOGRAPHIC ANNOTATION EARTH MARK +319F ; mapped ; 4EBA # 1.1 IDEOGRAPHIC ANNOTATION MAN MARK +31A0..31B7 ; valid # 3.0 BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H +31B8..31BA ; valid # 6.0 BOPOMOFO LETTER GH..BOPOMOFO LETTER ZY +31BB..31BF ; disallowed # NA .. +31C0..31CF ; valid ; ; NV8 # 4.1 CJK STROKE T..CJK STROKE N +31D0..31E3 ; valid ; ; NV8 # 5.1 CJK STROKE H..CJK STROKE Q +31E4..31EF ; disallowed # NA .. +31F0..31FF ; valid # 3.2 KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO +3200 ; disallowed_STD3_mapped ; 0028 1100 0029 #1.1 PARENTHESIZED HANGUL KIYEOK +3201 ; disallowed_STD3_mapped ; 0028 1102 0029 #1.1 PARENTHESIZED HANGUL NIEUN +3202 ; disallowed_STD3_mapped ; 0028 1103 0029 #1.1 PARENTHESIZED HANGUL TIKEUT +3203 ; disallowed_STD3_mapped ; 0028 1105 0029 #1.1 PARENTHESIZED HANGUL RIEUL +3204 ; disallowed_STD3_mapped ; 0028 1106 0029 #1.1 PARENTHESIZED HANGUL MIEUM +3205 ; disallowed_STD3_mapped ; 0028 1107 0029 #1.1 PARENTHESIZED HANGUL PIEUP +3206 ; disallowed_STD3_mapped ; 0028 1109 0029 #1.1 PARENTHESIZED HANGUL SIOS +3207 ; disallowed_STD3_mapped ; 0028 110B 0029 #1.1 PARENTHESIZED HANGUL IEUNG +3208 ; disallowed_STD3_mapped ; 0028 110C 0029 #1.1 PARENTHESIZED HANGUL CIEUC +3209 ; disallowed_STD3_mapped ; 0028 110E 0029 #1.1 PARENTHESIZED HANGUL CHIEUCH +320A ; disallowed_STD3_mapped ; 0028 110F 0029 #1.1 PARENTHESIZED HANGUL KHIEUKH +320B ; disallowed_STD3_mapped ; 0028 1110 0029 #1.1 PARENTHESIZED HANGUL THIEUTH +320C ; disallowed_STD3_mapped ; 0028 1111 0029 #1.1 PARENTHESIZED HANGUL PHIEUPH +320D ; disallowed_STD3_mapped ; 0028 1112 0029 #1.1 PARENTHESIZED HANGUL HIEUH +320E ; disallowed_STD3_mapped ; 0028 AC00 0029 #1.1 PARENTHESIZED HANGUL KIYEOK A +320F ; disallowed_STD3_mapped ; 0028 B098 0029 #1.1 PARENTHESIZED HANGUL NIEUN A +3210 ; disallowed_STD3_mapped ; 0028 B2E4 0029 #1.1 PARENTHESIZED HANGUL TIKEUT A +3211 ; disallowed_STD3_mapped ; 0028 B77C 0029 #1.1 PARENTHESIZED HANGUL RIEUL A +3212 ; disallowed_STD3_mapped ; 0028 B9C8 0029 #1.1 PARENTHESIZED HANGUL MIEUM A +3213 ; disallowed_STD3_mapped ; 0028 BC14 0029 #1.1 PARENTHESIZED HANGUL PIEUP A +3214 ; disallowed_STD3_mapped ; 0028 C0AC 0029 #1.1 PARENTHESIZED HANGUL SIOS A +3215 ; disallowed_STD3_mapped ; 0028 C544 0029 #1.1 PARENTHESIZED HANGUL IEUNG A +3216 ; disallowed_STD3_mapped ; 0028 C790 0029 #1.1 PARENTHESIZED HANGUL CIEUC A +3217 ; disallowed_STD3_mapped ; 0028 CC28 0029 #1.1 PARENTHESIZED HANGUL CHIEUCH A +3218 ; disallowed_STD3_mapped ; 0028 CE74 0029 #1.1 PARENTHESIZED HANGUL KHIEUKH A +3219 ; disallowed_STD3_mapped ; 0028 D0C0 0029 #1.1 PARENTHESIZED HANGUL THIEUTH A +321A ; disallowed_STD3_mapped ; 0028 D30C 0029 #1.1 PARENTHESIZED HANGUL PHIEUPH A +321B ; disallowed_STD3_mapped ; 0028 D558 0029 #1.1 PARENTHESIZED HANGUL HIEUH A +321C ; disallowed_STD3_mapped ; 0028 C8FC 0029 #1.1 PARENTHESIZED HANGUL CIEUC U +321D ; disallowed_STD3_mapped ; 0028 C624 C804 0029 #4.0 PARENTHESIZED KOREAN CHARACTER OJEON +321E ; disallowed_STD3_mapped ; 0028 C624 D6C4 0029 #4.0 PARENTHESIZED KOREAN CHARACTER O HU +321F ; disallowed # NA +3220 ; disallowed_STD3_mapped ; 0028 4E00 0029 #1.1 PARENTHESIZED IDEOGRAPH ONE +3221 ; disallowed_STD3_mapped ; 0028 4E8C 0029 #1.1 PARENTHESIZED IDEOGRAPH TWO +3222 ; disallowed_STD3_mapped ; 0028 4E09 0029 #1.1 PARENTHESIZED IDEOGRAPH THREE +3223 ; disallowed_STD3_mapped ; 0028 56DB 0029 #1.1 PARENTHESIZED IDEOGRAPH FOUR +3224 ; disallowed_STD3_mapped ; 0028 4E94 0029 #1.1 PARENTHESIZED IDEOGRAPH FIVE +3225 ; disallowed_STD3_mapped ; 0028 516D 0029 #1.1 PARENTHESIZED IDEOGRAPH SIX +3226 ; disallowed_STD3_mapped ; 0028 4E03 0029 #1.1 PARENTHESIZED IDEOGRAPH SEVEN +3227 ; disallowed_STD3_mapped ; 0028 516B 0029 #1.1 PARENTHESIZED IDEOGRAPH EIGHT +3228 ; disallowed_STD3_mapped ; 0028 4E5D 0029 #1.1 PARENTHESIZED IDEOGRAPH NINE +3229 ; disallowed_STD3_mapped ; 0028 5341 0029 #1.1 PARENTHESIZED IDEOGRAPH TEN +322A ; disallowed_STD3_mapped ; 0028 6708 0029 #1.1 PARENTHESIZED IDEOGRAPH MOON +322B ; disallowed_STD3_mapped ; 0028 706B 0029 #1.1 PARENTHESIZED IDEOGRAPH FIRE +322C ; disallowed_STD3_mapped ; 0028 6C34 0029 #1.1 PARENTHESIZED IDEOGRAPH WATER +322D ; disallowed_STD3_mapped ; 0028 6728 0029 #1.1 PARENTHESIZED IDEOGRAPH WOOD +322E ; disallowed_STD3_mapped ; 0028 91D1 0029 #1.1 PARENTHESIZED IDEOGRAPH METAL +322F ; disallowed_STD3_mapped ; 0028 571F 0029 #1.1 PARENTHESIZED IDEOGRAPH EARTH +3230 ; disallowed_STD3_mapped ; 0028 65E5 0029 #1.1 PARENTHESIZED IDEOGRAPH SUN +3231 ; disallowed_STD3_mapped ; 0028 682A 0029 #1.1 PARENTHESIZED IDEOGRAPH STOCK +3232 ; disallowed_STD3_mapped ; 0028 6709 0029 #1.1 PARENTHESIZED IDEOGRAPH HAVE +3233 ; disallowed_STD3_mapped ; 0028 793E 0029 #1.1 PARENTHESIZED IDEOGRAPH SOCIETY +3234 ; disallowed_STD3_mapped ; 0028 540D 0029 #1.1 PARENTHESIZED IDEOGRAPH NAME +3235 ; disallowed_STD3_mapped ; 0028 7279 0029 #1.1 PARENTHESIZED IDEOGRAPH SPECIAL +3236 ; disallowed_STD3_mapped ; 0028 8CA1 0029 #1.1 PARENTHESIZED IDEOGRAPH FINANCIAL +3237 ; disallowed_STD3_mapped ; 0028 795D 0029 #1.1 PARENTHESIZED IDEOGRAPH CONGRATULATION +3238 ; disallowed_STD3_mapped ; 0028 52B4 0029 #1.1 PARENTHESIZED IDEOGRAPH LABOR +3239 ; disallowed_STD3_mapped ; 0028 4EE3 0029 #1.1 PARENTHESIZED IDEOGRAPH REPRESENT +323A ; disallowed_STD3_mapped ; 0028 547C 0029 #1.1 PARENTHESIZED IDEOGRAPH CALL +323B ; disallowed_STD3_mapped ; 0028 5B66 0029 #1.1 PARENTHESIZED IDEOGRAPH STUDY +323C ; disallowed_STD3_mapped ; 0028 76E3 0029 #1.1 PARENTHESIZED IDEOGRAPH SUPERVISE +323D ; disallowed_STD3_mapped ; 0028 4F01 0029 #1.1 PARENTHESIZED IDEOGRAPH ENTERPRISE +323E ; disallowed_STD3_mapped ; 0028 8CC7 0029 #1.1 PARENTHESIZED IDEOGRAPH RESOURCE +323F ; disallowed_STD3_mapped ; 0028 5354 0029 #1.1 PARENTHESIZED IDEOGRAPH ALLIANCE +3240 ; disallowed_STD3_mapped ; 0028 796D 0029 #1.1 PARENTHESIZED IDEOGRAPH FESTIVAL +3241 ; disallowed_STD3_mapped ; 0028 4F11 0029 #1.1 PARENTHESIZED IDEOGRAPH REST +3242 ; disallowed_STD3_mapped ; 0028 81EA 0029 #1.1 PARENTHESIZED IDEOGRAPH SELF +3243 ; disallowed_STD3_mapped ; 0028 81F3 0029 #1.1 PARENTHESIZED IDEOGRAPH REACH +3244 ; mapped ; 554F # 5.2 CIRCLED IDEOGRAPH QUESTION +3245 ; mapped ; 5E7C # 5.2 CIRCLED IDEOGRAPH KINDERGARTEN +3246 ; mapped ; 6587 # 5.2 CIRCLED IDEOGRAPH SCHOOL +3247 ; mapped ; 7B8F # 5.2 CIRCLED IDEOGRAPH KOTO +3248..324F ; valid ; ; NV8 # 5.2 CIRCLED NUMBER TEN ON BLACK SQUARE..CIRCLED NUMBER EIGHTY ON BLACK SQUARE +3250 ; mapped ; 0070 0074 0065 #4.0 PARTNERSHIP SIGN +3251 ; mapped ; 0032 0031 # 3.2 CIRCLED NUMBER TWENTY ONE +3252 ; mapped ; 0032 0032 # 3.2 CIRCLED NUMBER TWENTY TWO +3253 ; mapped ; 0032 0033 # 3.2 CIRCLED NUMBER TWENTY THREE +3254 ; mapped ; 0032 0034 # 3.2 CIRCLED NUMBER TWENTY FOUR +3255 ; mapped ; 0032 0035 # 3.2 CIRCLED NUMBER TWENTY FIVE +3256 ; mapped ; 0032 0036 # 3.2 CIRCLED NUMBER TWENTY SIX +3257 ; mapped ; 0032 0037 # 3.2 CIRCLED NUMBER TWENTY SEVEN +3258 ; mapped ; 0032 0038 # 3.2 CIRCLED NUMBER TWENTY EIGHT +3259 ; mapped ; 0032 0039 # 3.2 CIRCLED NUMBER TWENTY NINE +325A ; mapped ; 0033 0030 # 3.2 CIRCLED NUMBER THIRTY +325B ; mapped ; 0033 0031 # 3.2 CIRCLED NUMBER THIRTY ONE +325C ; mapped ; 0033 0032 # 3.2 CIRCLED NUMBER THIRTY TWO +325D ; mapped ; 0033 0033 # 3.2 CIRCLED NUMBER THIRTY THREE +325E ; mapped ; 0033 0034 # 3.2 CIRCLED NUMBER THIRTY FOUR +325F ; mapped ; 0033 0035 # 3.2 CIRCLED NUMBER THIRTY FIVE +3260 ; mapped ; 1100 # 1.1 CIRCLED HANGUL KIYEOK +3261 ; mapped ; 1102 # 1.1 CIRCLED HANGUL NIEUN +3262 ; mapped ; 1103 # 1.1 CIRCLED HANGUL TIKEUT +3263 ; mapped ; 1105 # 1.1 CIRCLED HANGUL RIEUL +3264 ; mapped ; 1106 # 1.1 CIRCLED HANGUL MIEUM +3265 ; mapped ; 1107 # 1.1 CIRCLED HANGUL PIEUP +3266 ; mapped ; 1109 # 1.1 CIRCLED HANGUL SIOS +3267 ; mapped ; 110B # 1.1 CIRCLED HANGUL IEUNG +3268 ; mapped ; 110C # 1.1 CIRCLED HANGUL CIEUC +3269 ; mapped ; 110E # 1.1 CIRCLED HANGUL CHIEUCH +326A ; mapped ; 110F # 1.1 CIRCLED HANGUL KHIEUKH +326B ; mapped ; 1110 # 1.1 CIRCLED HANGUL THIEUTH +326C ; mapped ; 1111 # 1.1 CIRCLED HANGUL PHIEUPH +326D ; mapped ; 1112 # 1.1 CIRCLED HANGUL HIEUH +326E ; mapped ; AC00 # 1.1 CIRCLED HANGUL KIYEOK A +326F ; mapped ; B098 # 1.1 CIRCLED HANGUL NIEUN A +3270 ; mapped ; B2E4 # 1.1 CIRCLED HANGUL TIKEUT A +3271 ; mapped ; B77C # 1.1 CIRCLED HANGUL RIEUL A +3272 ; mapped ; B9C8 # 1.1 CIRCLED HANGUL MIEUM A +3273 ; mapped ; BC14 # 1.1 CIRCLED HANGUL PIEUP A +3274 ; mapped ; C0AC # 1.1 CIRCLED HANGUL SIOS A +3275 ; mapped ; C544 # 1.1 CIRCLED HANGUL IEUNG A +3276 ; mapped ; C790 # 1.1 CIRCLED HANGUL CIEUC A +3277 ; mapped ; CC28 # 1.1 CIRCLED HANGUL CHIEUCH A +3278 ; mapped ; CE74 # 1.1 CIRCLED HANGUL KHIEUKH A +3279 ; mapped ; D0C0 # 1.1 CIRCLED HANGUL THIEUTH A +327A ; mapped ; D30C # 1.1 CIRCLED HANGUL PHIEUPH A +327B ; mapped ; D558 # 1.1 CIRCLED HANGUL HIEUH A +327C ; mapped ; CC38 ACE0 # 4.0 CIRCLED KOREAN CHARACTER CHAMKO +327D ; mapped ; C8FC C758 # 4.0 CIRCLED KOREAN CHARACTER JUEUI +327E ; mapped ; C6B0 # 4.1 CIRCLED HANGUL IEUNG U +327F ; valid ; ; NV8 # 1.1 KOREAN STANDARD SYMBOL +3280 ; mapped ; 4E00 # 1.1 CIRCLED IDEOGRAPH ONE +3281 ; mapped ; 4E8C # 1.1 CIRCLED IDEOGRAPH TWO +3282 ; mapped ; 4E09 # 1.1 CIRCLED IDEOGRAPH THREE +3283 ; mapped ; 56DB # 1.1 CIRCLED IDEOGRAPH FOUR +3284 ; mapped ; 4E94 # 1.1 CIRCLED IDEOGRAPH FIVE +3285 ; mapped ; 516D # 1.1 CIRCLED IDEOGRAPH SIX +3286 ; mapped ; 4E03 # 1.1 CIRCLED IDEOGRAPH SEVEN +3287 ; mapped ; 516B # 1.1 CIRCLED IDEOGRAPH EIGHT +3288 ; mapped ; 4E5D # 1.1 CIRCLED IDEOGRAPH NINE +3289 ; mapped ; 5341 # 1.1 CIRCLED IDEOGRAPH TEN +328A ; mapped ; 6708 # 1.1 CIRCLED IDEOGRAPH MOON +328B ; mapped ; 706B # 1.1 CIRCLED IDEOGRAPH FIRE +328C ; mapped ; 6C34 # 1.1 CIRCLED IDEOGRAPH WATER +328D ; mapped ; 6728 # 1.1 CIRCLED IDEOGRAPH WOOD +328E ; mapped ; 91D1 # 1.1 CIRCLED IDEOGRAPH METAL +328F ; mapped ; 571F # 1.1 CIRCLED IDEOGRAPH EARTH +3290 ; mapped ; 65E5 # 1.1 CIRCLED IDEOGRAPH SUN +3291 ; mapped ; 682A # 1.1 CIRCLED IDEOGRAPH STOCK +3292 ; mapped ; 6709 # 1.1 CIRCLED IDEOGRAPH HAVE +3293 ; mapped ; 793E # 1.1 CIRCLED IDEOGRAPH SOCIETY +3294 ; mapped ; 540D # 1.1 CIRCLED IDEOGRAPH NAME +3295 ; mapped ; 7279 # 1.1 CIRCLED IDEOGRAPH SPECIAL +3296 ; mapped ; 8CA1 # 1.1 CIRCLED IDEOGRAPH FINANCIAL +3297 ; mapped ; 795D # 1.1 CIRCLED IDEOGRAPH CONGRATULATION +3298 ; mapped ; 52B4 # 1.1 CIRCLED IDEOGRAPH LABOR +3299 ; mapped ; 79D8 # 1.1 CIRCLED IDEOGRAPH SECRET +329A ; mapped ; 7537 # 1.1 CIRCLED IDEOGRAPH MALE +329B ; mapped ; 5973 # 1.1 CIRCLED IDEOGRAPH FEMALE +329C ; mapped ; 9069 # 1.1 CIRCLED IDEOGRAPH SUITABLE +329D ; mapped ; 512A # 1.1 CIRCLED IDEOGRAPH EXCELLENT +329E ; mapped ; 5370 # 1.1 CIRCLED IDEOGRAPH PRINT +329F ; mapped ; 6CE8 # 1.1 CIRCLED IDEOGRAPH ATTENTION +32A0 ; mapped ; 9805 # 1.1 CIRCLED IDEOGRAPH ITEM +32A1 ; mapped ; 4F11 # 1.1 CIRCLED IDEOGRAPH REST +32A2 ; mapped ; 5199 # 1.1 CIRCLED IDEOGRAPH COPY +32A3 ; mapped ; 6B63 # 1.1 CIRCLED IDEOGRAPH CORRECT +32A4 ; mapped ; 4E0A # 1.1 CIRCLED IDEOGRAPH HIGH +32A5 ; mapped ; 4E2D # 1.1 CIRCLED IDEOGRAPH CENTRE +32A6 ; mapped ; 4E0B # 1.1 CIRCLED IDEOGRAPH LOW +32A7 ; mapped ; 5DE6 # 1.1 CIRCLED IDEOGRAPH LEFT +32A8 ; mapped ; 53F3 # 1.1 CIRCLED IDEOGRAPH RIGHT +32A9 ; mapped ; 533B # 1.1 CIRCLED IDEOGRAPH MEDICINE +32AA ; mapped ; 5B97 # 1.1 CIRCLED IDEOGRAPH RELIGION +32AB ; mapped ; 5B66 # 1.1 CIRCLED IDEOGRAPH STUDY +32AC ; mapped ; 76E3 # 1.1 CIRCLED IDEOGRAPH SUPERVISE +32AD ; mapped ; 4F01 # 1.1 CIRCLED IDEOGRAPH ENTERPRISE +32AE ; mapped ; 8CC7 # 1.1 CIRCLED IDEOGRAPH RESOURCE +32AF ; mapped ; 5354 # 1.1 CIRCLED IDEOGRAPH ALLIANCE +32B0 ; mapped ; 591C # 1.1 CIRCLED IDEOGRAPH NIGHT +32B1 ; mapped ; 0033 0036 # 3.2 CIRCLED NUMBER THIRTY SIX +32B2 ; mapped ; 0033 0037 # 3.2 CIRCLED NUMBER THIRTY SEVEN +32B3 ; mapped ; 0033 0038 # 3.2 CIRCLED NUMBER THIRTY EIGHT +32B4 ; mapped ; 0033 0039 # 3.2 CIRCLED NUMBER THIRTY NINE +32B5 ; mapped ; 0034 0030 # 3.2 CIRCLED NUMBER FORTY +32B6 ; mapped ; 0034 0031 # 3.2 CIRCLED NUMBER FORTY ONE +32B7 ; mapped ; 0034 0032 # 3.2 CIRCLED NUMBER FORTY TWO +32B8 ; mapped ; 0034 0033 # 3.2 CIRCLED NUMBER FORTY THREE +32B9 ; mapped ; 0034 0034 # 3.2 CIRCLED NUMBER FORTY FOUR +32BA ; mapped ; 0034 0035 # 3.2 CIRCLED NUMBER FORTY FIVE +32BB ; mapped ; 0034 0036 # 3.2 CIRCLED NUMBER FORTY SIX +32BC ; mapped ; 0034 0037 # 3.2 CIRCLED NUMBER FORTY SEVEN +32BD ; mapped ; 0034 0038 # 3.2 CIRCLED NUMBER FORTY EIGHT +32BE ; mapped ; 0034 0039 # 3.2 CIRCLED NUMBER FORTY NINE +32BF ; mapped ; 0035 0030 # 3.2 CIRCLED NUMBER FIFTY +32C0 ; mapped ; 0031 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY +32C1 ; mapped ; 0032 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY +32C2 ; mapped ; 0033 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH +32C3 ; mapped ; 0034 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL +32C4 ; mapped ; 0035 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY +32C5 ; mapped ; 0036 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE +32C6 ; mapped ; 0037 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY +32C7 ; mapped ; 0038 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST +32C8 ; mapped ; 0039 6708 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER +32C9 ; mapped ; 0031 0030 6708 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER +32CA ; mapped ; 0031 0031 6708 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER +32CB ; mapped ; 0031 0032 6708 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER +32CC ; mapped ; 0068 0067 # 4.0 SQUARE HG +32CD ; mapped ; 0065 0072 0067 #4.0 SQUARE ERG +32CE ; mapped ; 0065 0076 # 4.0 SQUARE EV +32CF ; mapped ; 006C 0074 0064 #4.0 LIMITED LIABILITY SIGN +32D0 ; mapped ; 30A2 # 1.1 CIRCLED KATAKANA A +32D1 ; mapped ; 30A4 # 1.1 CIRCLED KATAKANA I +32D2 ; mapped ; 30A6 # 1.1 CIRCLED KATAKANA U +32D3 ; mapped ; 30A8 # 1.1 CIRCLED KATAKANA E +32D4 ; mapped ; 30AA # 1.1 CIRCLED KATAKANA O +32D5 ; mapped ; 30AB # 1.1 CIRCLED KATAKANA KA +32D6 ; mapped ; 30AD # 1.1 CIRCLED KATAKANA KI +32D7 ; mapped ; 30AF # 1.1 CIRCLED KATAKANA KU +32D8 ; mapped ; 30B1 # 1.1 CIRCLED KATAKANA KE +32D9 ; mapped ; 30B3 # 1.1 CIRCLED KATAKANA KO +32DA ; mapped ; 30B5 # 1.1 CIRCLED KATAKANA SA +32DB ; mapped ; 30B7 # 1.1 CIRCLED KATAKANA SI +32DC ; mapped ; 30B9 # 1.1 CIRCLED KATAKANA SU +32DD ; mapped ; 30BB # 1.1 CIRCLED KATAKANA SE +32DE ; mapped ; 30BD # 1.1 CIRCLED KATAKANA SO +32DF ; mapped ; 30BF # 1.1 CIRCLED KATAKANA TA +32E0 ; mapped ; 30C1 # 1.1 CIRCLED KATAKANA TI +32E1 ; mapped ; 30C4 # 1.1 CIRCLED KATAKANA TU +32E2 ; mapped ; 30C6 # 1.1 CIRCLED KATAKANA TE +32E3 ; mapped ; 30C8 # 1.1 CIRCLED KATAKANA TO +32E4 ; mapped ; 30CA # 1.1 CIRCLED KATAKANA NA +32E5 ; mapped ; 30CB # 1.1 CIRCLED KATAKANA NI +32E6 ; mapped ; 30CC # 1.1 CIRCLED KATAKANA NU +32E7 ; mapped ; 30CD # 1.1 CIRCLED KATAKANA NE +32E8 ; mapped ; 30CE # 1.1 CIRCLED KATAKANA NO +32E9 ; mapped ; 30CF # 1.1 CIRCLED KATAKANA HA +32EA ; mapped ; 30D2 # 1.1 CIRCLED KATAKANA HI +32EB ; mapped ; 30D5 # 1.1 CIRCLED KATAKANA HU +32EC ; mapped ; 30D8 # 1.1 CIRCLED KATAKANA HE +32ED ; mapped ; 30DB # 1.1 CIRCLED KATAKANA HO +32EE ; mapped ; 30DE # 1.1 CIRCLED KATAKANA MA +32EF ; mapped ; 30DF # 1.1 CIRCLED KATAKANA MI +32F0 ; mapped ; 30E0 # 1.1 CIRCLED KATAKANA MU +32F1 ; mapped ; 30E1 # 1.1 CIRCLED KATAKANA ME +32F2 ; mapped ; 30E2 # 1.1 CIRCLED KATAKANA MO +32F3 ; mapped ; 30E4 # 1.1 CIRCLED KATAKANA YA +32F4 ; mapped ; 30E6 # 1.1 CIRCLED KATAKANA YU +32F5 ; mapped ; 30E8 # 1.1 CIRCLED KATAKANA YO +32F6 ; mapped ; 30E9 # 1.1 CIRCLED KATAKANA RA +32F7 ; mapped ; 30EA # 1.1 CIRCLED KATAKANA RI +32F8 ; mapped ; 30EB # 1.1 CIRCLED KATAKANA RU +32F9 ; mapped ; 30EC # 1.1 CIRCLED KATAKANA RE +32FA ; mapped ; 30ED # 1.1 CIRCLED KATAKANA RO +32FB ; mapped ; 30EF # 1.1 CIRCLED KATAKANA WA +32FC ; mapped ; 30F0 # 1.1 CIRCLED KATAKANA WI +32FD ; mapped ; 30F1 # 1.1 CIRCLED KATAKANA WE +32FE ; mapped ; 30F2 # 1.1 CIRCLED KATAKANA WO +32FF ; disallowed # NA +3300 ; mapped ; 30A2 30D1 30FC 30C8 #1.1 SQUARE APAATO +3301 ; mapped ; 30A2 30EB 30D5 30A1 #1.1 SQUARE ARUHUA +3302 ; mapped ; 30A2 30F3 30DA 30A2 #1.1 SQUARE ANPEA +3303 ; mapped ; 30A2 30FC 30EB #1.1 SQUARE AARU +3304 ; mapped ; 30A4 30CB 30F3 30B0 #1.1 SQUARE ININGU +3305 ; mapped ; 30A4 30F3 30C1 #1.1 SQUARE INTI +3306 ; mapped ; 30A6 30A9 30F3 #1.1 SQUARE UON +3307 ; mapped ; 30A8 30B9 30AF 30FC 30C9 #1.1 SQUARE ESUKUUDO +3308 ; mapped ; 30A8 30FC 30AB 30FC #1.1 SQUARE EEKAA +3309 ; mapped ; 30AA 30F3 30B9 #1.1 SQUARE ONSU +330A ; mapped ; 30AA 30FC 30E0 #1.1 SQUARE OOMU +330B ; mapped ; 30AB 30A4 30EA #1.1 SQUARE KAIRI +330C ; mapped ; 30AB 30E9 30C3 30C8 #1.1 SQUARE KARATTO +330D ; mapped ; 30AB 30ED 30EA 30FC #1.1 SQUARE KARORII +330E ; mapped ; 30AC 30ED 30F3 #1.1 SQUARE GARON +330F ; mapped ; 30AC 30F3 30DE #1.1 SQUARE GANMA +3310 ; mapped ; 30AE 30AC # 1.1 SQUARE GIGA +3311 ; mapped ; 30AE 30CB 30FC #1.1 SQUARE GINII +3312 ; mapped ; 30AD 30E5 30EA 30FC #1.1 SQUARE KYURII +3313 ; mapped ; 30AE 30EB 30C0 30FC #1.1 SQUARE GIRUDAA +3314 ; mapped ; 30AD 30ED # 1.1 SQUARE KIRO +3315 ; mapped ; 30AD 30ED 30B0 30E9 30E0 #1.1 SQUARE KIROGURAMU +3316 ; mapped ; 30AD 30ED 30E1 30FC 30C8 30EB #1.1 SQUARE KIROMEETORU +3317 ; mapped ; 30AD 30ED 30EF 30C3 30C8 #1.1 SQUARE KIROWATTO +3318 ; mapped ; 30B0 30E9 30E0 #1.1 SQUARE GURAMU +3319 ; mapped ; 30B0 30E9 30E0 30C8 30F3 #1.1 SQUARE GURAMUTON +331A ; mapped ; 30AF 30EB 30BC 30A4 30ED #1.1 SQUARE KURUZEIRO +331B ; mapped ; 30AF 30ED 30FC 30CD #1.1 SQUARE KUROONE +331C ; mapped ; 30B1 30FC 30B9 #1.1 SQUARE KEESU +331D ; mapped ; 30B3 30EB 30CA #1.1 SQUARE KORUNA +331E ; mapped ; 30B3 30FC 30DD #1.1 SQUARE KOOPO +331F ; mapped ; 30B5 30A4 30AF 30EB #1.1 SQUARE SAIKURU +3320 ; mapped ; 30B5 30F3 30C1 30FC 30E0 #1.1 SQUARE SANTIIMU +3321 ; mapped ; 30B7 30EA 30F3 30B0 #1.1 SQUARE SIRINGU +3322 ; mapped ; 30BB 30F3 30C1 #1.1 SQUARE SENTI +3323 ; mapped ; 30BB 30F3 30C8 #1.1 SQUARE SENTO +3324 ; mapped ; 30C0 30FC 30B9 #1.1 SQUARE DAASU +3325 ; mapped ; 30C7 30B7 # 1.1 SQUARE DESI +3326 ; mapped ; 30C9 30EB # 1.1 SQUARE DORU +3327 ; mapped ; 30C8 30F3 # 1.1 SQUARE TON +3328 ; mapped ; 30CA 30CE # 1.1 SQUARE NANO +3329 ; mapped ; 30CE 30C3 30C8 #1.1 SQUARE NOTTO +332A ; mapped ; 30CF 30A4 30C4 #1.1 SQUARE HAITU +332B ; mapped ; 30D1 30FC 30BB 30F3 30C8 #1.1 SQUARE PAASENTO +332C ; mapped ; 30D1 30FC 30C4 #1.1 SQUARE PAATU +332D ; mapped ; 30D0 30FC 30EC 30EB #1.1 SQUARE BAARERU +332E ; mapped ; 30D4 30A2 30B9 30C8 30EB #1.1 SQUARE PIASUTORU +332F ; mapped ; 30D4 30AF 30EB #1.1 SQUARE PIKURU +3330 ; mapped ; 30D4 30B3 # 1.1 SQUARE PIKO +3331 ; mapped ; 30D3 30EB # 1.1 SQUARE BIRU +3332 ; mapped ; 30D5 30A1 30E9 30C3 30C9 #1.1 SQUARE HUARADDO +3333 ; mapped ; 30D5 30A3 30FC 30C8 #1.1 SQUARE HUIITO +3334 ; mapped ; 30D6 30C3 30B7 30A7 30EB #1.1 SQUARE BUSSYERU +3335 ; mapped ; 30D5 30E9 30F3 #1.1 SQUARE HURAN +3336 ; mapped ; 30D8 30AF 30BF 30FC 30EB #1.1 SQUARE HEKUTAARU +3337 ; mapped ; 30DA 30BD # 1.1 SQUARE PESO +3338 ; mapped ; 30DA 30CB 30D2 #1.1 SQUARE PENIHI +3339 ; mapped ; 30D8 30EB 30C4 #1.1 SQUARE HERUTU +333A ; mapped ; 30DA 30F3 30B9 #1.1 SQUARE PENSU +333B ; mapped ; 30DA 30FC 30B8 #1.1 SQUARE PEEZI +333C ; mapped ; 30D9 30FC 30BF #1.1 SQUARE BEETA +333D ; mapped ; 30DD 30A4 30F3 30C8 #1.1 SQUARE POINTO +333E ; mapped ; 30DC 30EB 30C8 #1.1 SQUARE BORUTO +333F ; mapped ; 30DB 30F3 # 1.1 SQUARE HON +3340 ; mapped ; 30DD 30F3 30C9 #1.1 SQUARE PONDO +3341 ; mapped ; 30DB 30FC 30EB #1.1 SQUARE HOORU +3342 ; mapped ; 30DB 30FC 30F3 #1.1 SQUARE HOON +3343 ; mapped ; 30DE 30A4 30AF 30ED #1.1 SQUARE MAIKURO +3344 ; mapped ; 30DE 30A4 30EB #1.1 SQUARE MAIRU +3345 ; mapped ; 30DE 30C3 30CF #1.1 SQUARE MAHHA +3346 ; mapped ; 30DE 30EB 30AF #1.1 SQUARE MARUKU +3347 ; mapped ; 30DE 30F3 30B7 30E7 30F3 #1.1 SQUARE MANSYON +3348 ; mapped ; 30DF 30AF 30ED 30F3 #1.1 SQUARE MIKURON +3349 ; mapped ; 30DF 30EA # 1.1 SQUARE MIRI +334A ; mapped ; 30DF 30EA 30D0 30FC 30EB #1.1 SQUARE MIRIBAARU +334B ; mapped ; 30E1 30AC # 1.1 SQUARE MEGA +334C ; mapped ; 30E1 30AC 30C8 30F3 #1.1 SQUARE MEGATON +334D ; mapped ; 30E1 30FC 30C8 30EB #1.1 SQUARE MEETORU +334E ; mapped ; 30E4 30FC 30C9 #1.1 SQUARE YAADO +334F ; mapped ; 30E4 30FC 30EB #1.1 SQUARE YAARU +3350 ; mapped ; 30E6 30A2 30F3 #1.1 SQUARE YUAN +3351 ; mapped ; 30EA 30C3 30C8 30EB #1.1 SQUARE RITTORU +3352 ; mapped ; 30EA 30E9 # 1.1 SQUARE RIRA +3353 ; mapped ; 30EB 30D4 30FC #1.1 SQUARE RUPII +3354 ; mapped ; 30EB 30FC 30D6 30EB #1.1 SQUARE RUUBURU +3355 ; mapped ; 30EC 30E0 # 1.1 SQUARE REMU +3356 ; mapped ; 30EC 30F3 30C8 30B2 30F3 #1.1 SQUARE RENTOGEN +3357 ; mapped ; 30EF 30C3 30C8 #1.1 SQUARE WATTO +3358 ; mapped ; 0030 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO +3359 ; mapped ; 0031 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE +335A ; mapped ; 0032 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO +335B ; mapped ; 0033 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE +335C ; mapped ; 0034 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR +335D ; mapped ; 0035 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE +335E ; mapped ; 0036 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX +335F ; mapped ; 0037 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN +3360 ; mapped ; 0038 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT +3361 ; mapped ; 0039 70B9 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE +3362 ; mapped ; 0031 0030 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN +3363 ; mapped ; 0031 0031 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN +3364 ; mapped ; 0031 0032 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE +3365 ; mapped ; 0031 0033 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN +3366 ; mapped ; 0031 0034 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN +3367 ; mapped ; 0031 0035 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN +3368 ; mapped ; 0031 0036 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN +3369 ; mapped ; 0031 0037 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN +336A ; mapped ; 0031 0038 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN +336B ; mapped ; 0031 0039 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN +336C ; mapped ; 0032 0030 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY +336D ; mapped ; 0032 0031 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE +336E ; mapped ; 0032 0032 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO +336F ; mapped ; 0032 0033 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE +3370 ; mapped ; 0032 0034 70B9 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR +3371 ; mapped ; 0068 0070 0061 #1.1 SQUARE HPA +3372 ; mapped ; 0064 0061 # 1.1 SQUARE DA +3373 ; mapped ; 0061 0075 # 1.1 SQUARE AU +3374 ; mapped ; 0062 0061 0072 #1.1 SQUARE BAR +3375 ; mapped ; 006F 0076 # 1.1 SQUARE OV +3376 ; mapped ; 0070 0063 # 1.1 SQUARE PC +3377 ; mapped ; 0064 006D # 4.0 SQUARE DM +3378 ; mapped ; 0064 006D 0032 #4.0 SQUARE DM SQUARED +3379 ; mapped ; 0064 006D 0033 #4.0 SQUARE DM CUBED +337A ; mapped ; 0069 0075 # 4.0 SQUARE IU +337B ; mapped ; 5E73 6210 # 1.1 SQUARE ERA NAME HEISEI +337C ; mapped ; 662D 548C # 1.1 SQUARE ERA NAME SYOUWA +337D ; mapped ; 5927 6B63 # 1.1 SQUARE ERA NAME TAISYOU +337E ; mapped ; 660E 6CBB # 1.1 SQUARE ERA NAME MEIZI +337F ; mapped ; 682A 5F0F 4F1A 793E #1.1 SQUARE CORPORATION +3380 ; mapped ; 0070 0061 # 1.1 SQUARE PA AMPS +3381 ; mapped ; 006E 0061 # 1.1 SQUARE NA +3382 ; mapped ; 03BC 0061 # 1.1 SQUARE MU A +3383 ; mapped ; 006D 0061 # 1.1 SQUARE MA +3384 ; mapped ; 006B 0061 # 1.1 SQUARE KA +3385 ; mapped ; 006B 0062 # 1.1 SQUARE KB +3386 ; mapped ; 006D 0062 # 1.1 SQUARE MB +3387 ; mapped ; 0067 0062 # 1.1 SQUARE GB +3388 ; mapped ; 0063 0061 006C #1.1 SQUARE CAL +3389 ; mapped ; 006B 0063 0061 006C #1.1 SQUARE KCAL +338A ; mapped ; 0070 0066 # 1.1 SQUARE PF +338B ; mapped ; 006E 0066 # 1.1 SQUARE NF +338C ; mapped ; 03BC 0066 # 1.1 SQUARE MU F +338D ; mapped ; 03BC 0067 # 1.1 SQUARE MU G +338E ; mapped ; 006D 0067 # 1.1 SQUARE MG +338F ; mapped ; 006B 0067 # 1.1 SQUARE KG +3390 ; mapped ; 0068 007A # 1.1 SQUARE HZ +3391 ; mapped ; 006B 0068 007A #1.1 SQUARE KHZ +3392 ; mapped ; 006D 0068 007A #1.1 SQUARE MHZ +3393 ; mapped ; 0067 0068 007A #1.1 SQUARE GHZ +3394 ; mapped ; 0074 0068 007A #1.1 SQUARE THZ +3395 ; mapped ; 03BC 006C # 1.1 SQUARE MU L +3396 ; mapped ; 006D 006C # 1.1 SQUARE ML +3397 ; mapped ; 0064 006C # 1.1 SQUARE DL +3398 ; mapped ; 006B 006C # 1.1 SQUARE KL +3399 ; mapped ; 0066 006D # 1.1 SQUARE FM +339A ; mapped ; 006E 006D # 1.1 SQUARE NM +339B ; mapped ; 03BC 006D # 1.1 SQUARE MU M +339C ; mapped ; 006D 006D # 1.1 SQUARE MM +339D ; mapped ; 0063 006D # 1.1 SQUARE CM +339E ; mapped ; 006B 006D # 1.1 SQUARE KM +339F ; mapped ; 006D 006D 0032 #1.1 SQUARE MM SQUARED +33A0 ; mapped ; 0063 006D 0032 #1.1 SQUARE CM SQUARED +33A1 ; mapped ; 006D 0032 # 1.1 SQUARE M SQUARED +33A2 ; mapped ; 006B 006D 0032 #1.1 SQUARE KM SQUARED +33A3 ; mapped ; 006D 006D 0033 #1.1 SQUARE MM CUBED +33A4 ; mapped ; 0063 006D 0033 #1.1 SQUARE CM CUBED +33A5 ; mapped ; 006D 0033 # 1.1 SQUARE M CUBED +33A6 ; mapped ; 006B 006D 0033 #1.1 SQUARE KM CUBED +33A7 ; mapped ; 006D 2215 0073 #1.1 SQUARE M OVER S +33A8 ; mapped ; 006D 2215 0073 0032 #1.1 SQUARE M OVER S SQUARED +33A9 ; mapped ; 0070 0061 # 1.1 SQUARE PA +33AA ; mapped ; 006B 0070 0061 #1.1 SQUARE KPA +33AB ; mapped ; 006D 0070 0061 #1.1 SQUARE MPA +33AC ; mapped ; 0067 0070 0061 #1.1 SQUARE GPA +33AD ; mapped ; 0072 0061 0064 #1.1 SQUARE RAD +33AE ; mapped ; 0072 0061 0064 2215 0073 #1.1 SQUARE RAD OVER S +33AF ; mapped ; 0072 0061 0064 2215 0073 0032 #1.1 SQUARE RAD OVER S SQUARED +33B0 ; mapped ; 0070 0073 # 1.1 SQUARE PS +33B1 ; mapped ; 006E 0073 # 1.1 SQUARE NS +33B2 ; mapped ; 03BC 0073 # 1.1 SQUARE MU S +33B3 ; mapped ; 006D 0073 # 1.1 SQUARE MS +33B4 ; mapped ; 0070 0076 # 1.1 SQUARE PV +33B5 ; mapped ; 006E 0076 # 1.1 SQUARE NV +33B6 ; mapped ; 03BC 0076 # 1.1 SQUARE MU V +33B7 ; mapped ; 006D 0076 # 1.1 SQUARE MV +33B8 ; mapped ; 006B 0076 # 1.1 SQUARE KV +33B9 ; mapped ; 006D 0076 # 1.1 SQUARE MV MEGA +33BA ; mapped ; 0070 0077 # 1.1 SQUARE PW +33BB ; mapped ; 006E 0077 # 1.1 SQUARE NW +33BC ; mapped ; 03BC 0077 # 1.1 SQUARE MU W +33BD ; mapped ; 006D 0077 # 1.1 SQUARE MW +33BE ; mapped ; 006B 0077 # 1.1 SQUARE KW +33BF ; mapped ; 006D 0077 # 1.1 SQUARE MW MEGA +33C0 ; mapped ; 006B 03C9 # 1.1 SQUARE K OHM +33C1 ; mapped ; 006D 03C9 # 1.1 SQUARE M OHM +33C2 ; disallowed # 1.1 SQUARE AM +33C3 ; mapped ; 0062 0071 # 1.1 SQUARE BQ +33C4 ; mapped ; 0063 0063 # 1.1 SQUARE CC +33C5 ; mapped ; 0063 0064 # 1.1 SQUARE CD +33C6 ; mapped ; 0063 2215 006B 0067 #1.1 SQUARE C OVER KG +33C7 ; disallowed # 1.1 SQUARE CO +33C8 ; mapped ; 0064 0062 # 1.1 SQUARE DB +33C9 ; mapped ; 0067 0079 # 1.1 SQUARE GY +33CA ; mapped ; 0068 0061 # 1.1 SQUARE HA +33CB ; mapped ; 0068 0070 # 1.1 SQUARE HP +33CC ; mapped ; 0069 006E # 1.1 SQUARE IN +33CD ; mapped ; 006B 006B # 1.1 SQUARE KK +33CE ; mapped ; 006B 006D # 1.1 SQUARE KM CAPITAL +33CF ; mapped ; 006B 0074 # 1.1 SQUARE KT +33D0 ; mapped ; 006C 006D # 1.1 SQUARE LM +33D1 ; mapped ; 006C 006E # 1.1 SQUARE LN +33D2 ; mapped ; 006C 006F 0067 #1.1 SQUARE LOG +33D3 ; mapped ; 006C 0078 # 1.1 SQUARE LX +33D4 ; mapped ; 006D 0062 # 1.1 SQUARE MB SMALL +33D5 ; mapped ; 006D 0069 006C #1.1 SQUARE MIL +33D6 ; mapped ; 006D 006F 006C #1.1 SQUARE MOL +33D7 ; mapped ; 0070 0068 # 1.1 SQUARE PH +33D8 ; disallowed # 1.1 SQUARE PM +33D9 ; mapped ; 0070 0070 006D #1.1 SQUARE PPM +33DA ; mapped ; 0070 0072 # 1.1 SQUARE PR +33DB ; mapped ; 0073 0072 # 1.1 SQUARE SR +33DC ; mapped ; 0073 0076 # 1.1 SQUARE SV +33DD ; mapped ; 0077 0062 # 1.1 SQUARE WB +33DE ; mapped ; 0076 2215 006D #4.0 SQUARE V OVER M +33DF ; mapped ; 0061 2215 006D #4.0 SQUARE A OVER M +33E0 ; mapped ; 0031 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE +33E1 ; mapped ; 0032 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO +33E2 ; mapped ; 0033 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE +33E3 ; mapped ; 0034 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR +33E4 ; mapped ; 0035 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE +33E5 ; mapped ; 0036 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX +33E6 ; mapped ; 0037 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN +33E7 ; mapped ; 0038 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT +33E8 ; mapped ; 0039 65E5 # 1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE +33E9 ; mapped ; 0031 0030 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN +33EA ; mapped ; 0031 0031 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN +33EB ; mapped ; 0031 0032 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE +33EC ; mapped ; 0031 0033 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN +33ED ; mapped ; 0031 0034 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN +33EE ; mapped ; 0031 0035 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN +33EF ; mapped ; 0031 0036 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN +33F0 ; mapped ; 0031 0037 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN +33F1 ; mapped ; 0031 0038 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN +33F2 ; mapped ; 0031 0039 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN +33F3 ; mapped ; 0032 0030 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY +33F4 ; mapped ; 0032 0031 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE +33F5 ; mapped ; 0032 0032 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO +33F6 ; mapped ; 0032 0033 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE +33F7 ; mapped ; 0032 0034 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR +33F8 ; mapped ; 0032 0035 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE +33F9 ; mapped ; 0032 0036 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX +33FA ; mapped ; 0032 0037 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN +33FB ; mapped ; 0032 0038 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT +33FC ; mapped ; 0032 0039 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE +33FD ; mapped ; 0033 0030 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY +33FE ; mapped ; 0033 0031 65E5 #1.1 IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE +33FF ; mapped ; 0067 0061 006C #4.0 SQUARE GAL +3400..4DB5 ; valid # 3.0 CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 +4DB6..4DBF ; disallowed # NA .. +4DC0..4DFF ; valid ; ; NV8 # 4.0 HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION +4E00..9FA5 ; valid # 1.1 CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FA5 +9FA6..9FBB ; valid # 4.1 CJK UNIFIED IDEOGRAPH-9FA6..CJK UNIFIED IDEOGRAPH-9FBB +9FBC..9FC3 ; valid # 5.1 CJK UNIFIED IDEOGRAPH-9FBC..CJK UNIFIED IDEOGRAPH-9FC3 +9FC4..9FCB ; valid # 5.2 CJK UNIFIED IDEOGRAPH-9FC4..CJK UNIFIED IDEOGRAPH-9FCB +9FCC ; valid # 6.1 CJK UNIFIED IDEOGRAPH-9FCC +9FCD..9FD5 ; valid # 8.0 CJK UNIFIED IDEOGRAPH-9FCD..CJK UNIFIED IDEOGRAPH-9FD5 +9FD6..9FEA ; valid # 10.0 CJK UNIFIED IDEOGRAPH-9FD6..CJK UNIFIED IDEOGRAPH-9FEA +9FEB..9FFF ; disallowed # NA .. +A000..A48C ; valid # 3.0 YI SYLLABLE IT..YI SYLLABLE YYR +A48D..A48F ; disallowed # NA .. +A490..A4A1 ; valid ; ; NV8 # 3.0 YI RADICAL QOT..YI RADICAL GA +A4A2..A4A3 ; valid ; ; NV8 # 3.2 YI RADICAL ZUP..YI RADICAL CYT +A4A4..A4B3 ; valid ; ; NV8 # 3.0 YI RADICAL DDUR..YI RADICAL JO +A4B4 ; valid ; ; NV8 # 3.2 YI RADICAL NZUP +A4B5..A4C0 ; valid ; ; NV8 # 3.0 YI RADICAL JJY..YI RADICAL SHAT +A4C1 ; valid ; ; NV8 # 3.2 YI RADICAL ZUR +A4C2..A4C4 ; valid ; ; NV8 # 3.0 YI RADICAL SHOP..YI RADICAL ZZIET +A4C5 ; valid ; ; NV8 # 3.2 YI RADICAL NBIE +A4C6 ; valid ; ; NV8 # 3.0 YI RADICAL KE +A4C7..A4CF ; disallowed # NA .. +A4D0..A4FD ; valid # 5.2 LISU LETTER BA..LISU LETTER TONE MYA JEU +A4FE..A4FF ; valid ; ; NV8 # 5.2 LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP +A500..A60C ; valid # 5.1 VAI SYLLABLE EE..VAI SYLLABLE LENGTHENER +A60D..A60F ; valid ; ; NV8 # 5.1 VAI COMMA..VAI QUESTION MARK +A610..A62B ; valid # 5.1 VAI SYLLABLE NDOLE FA..VAI SYLLABLE NDOLE DO +A62C..A63F ; disallowed # NA .. +A640 ; mapped ; A641 # 5.1 CYRILLIC CAPITAL LETTER ZEMLYA +A641 ; valid # 5.1 CYRILLIC SMALL LETTER ZEMLYA +A642 ; mapped ; A643 # 5.1 CYRILLIC CAPITAL LETTER DZELO +A643 ; valid # 5.1 CYRILLIC SMALL LETTER DZELO +A644 ; mapped ; A645 # 5.1 CYRILLIC CAPITAL LETTER REVERSED DZE +A645 ; valid # 5.1 CYRILLIC SMALL LETTER REVERSED DZE +A646 ; mapped ; A647 # 5.1 CYRILLIC CAPITAL LETTER IOTA +A647 ; valid # 5.1 CYRILLIC SMALL LETTER IOTA +A648 ; mapped ; A649 # 5.1 CYRILLIC CAPITAL LETTER DJERV +A649 ; valid # 5.1 CYRILLIC SMALL LETTER DJERV +A64A ; mapped ; A64B # 5.1 CYRILLIC CAPITAL LETTER MONOGRAPH UK +A64B ; valid # 5.1 CYRILLIC SMALL LETTER MONOGRAPH UK +A64C ; mapped ; A64D # 5.1 CYRILLIC CAPITAL LETTER BROAD OMEGA +A64D ; valid # 5.1 CYRILLIC SMALL LETTER BROAD OMEGA +A64E ; mapped ; A64F # 5.1 CYRILLIC CAPITAL LETTER NEUTRAL YER +A64F ; valid # 5.1 CYRILLIC SMALL LETTER NEUTRAL YER +A650 ; mapped ; A651 # 5.1 CYRILLIC CAPITAL LETTER YERU WITH BACK YER +A651 ; valid # 5.1 CYRILLIC SMALL LETTER YERU WITH BACK YER +A652 ; mapped ; A653 # 5.1 CYRILLIC CAPITAL LETTER IOTIFIED YAT +A653 ; valid # 5.1 CYRILLIC SMALL LETTER IOTIFIED YAT +A654 ; mapped ; A655 # 5.1 CYRILLIC CAPITAL LETTER REVERSED YU +A655 ; valid # 5.1 CYRILLIC SMALL LETTER REVERSED YU +A656 ; mapped ; A657 # 5.1 CYRILLIC CAPITAL LETTER IOTIFIED A +A657 ; valid # 5.1 CYRILLIC SMALL LETTER IOTIFIED A +A658 ; mapped ; A659 # 5.1 CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS +A659 ; valid # 5.1 CYRILLIC SMALL LETTER CLOSED LITTLE YUS +A65A ; mapped ; A65B # 5.1 CYRILLIC CAPITAL LETTER BLENDED YUS +A65B ; valid # 5.1 CYRILLIC SMALL LETTER BLENDED YUS +A65C ; mapped ; A65D # 5.1 CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS +A65D ; valid # 5.1 CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS +A65E ; mapped ; A65F # 5.1 CYRILLIC CAPITAL LETTER YN +A65F ; valid # 5.1 CYRILLIC SMALL LETTER YN +A660 ; mapped ; A661 # 6.0 CYRILLIC CAPITAL LETTER REVERSED TSE +A661 ; valid # 6.0 CYRILLIC SMALL LETTER REVERSED TSE +A662 ; mapped ; A663 # 5.1 CYRILLIC CAPITAL LETTER SOFT DE +A663 ; valid # 5.1 CYRILLIC SMALL LETTER SOFT DE +A664 ; mapped ; A665 # 5.1 CYRILLIC CAPITAL LETTER SOFT EL +A665 ; valid # 5.1 CYRILLIC SMALL LETTER SOFT EL +A666 ; mapped ; A667 # 5.1 CYRILLIC CAPITAL LETTER SOFT EM +A667 ; valid # 5.1 CYRILLIC SMALL LETTER SOFT EM +A668 ; mapped ; A669 # 5.1 CYRILLIC CAPITAL LETTER MONOCULAR O +A669 ; valid # 5.1 CYRILLIC SMALL LETTER MONOCULAR O +A66A ; mapped ; A66B # 5.1 CYRILLIC CAPITAL LETTER BINOCULAR O +A66B ; valid # 5.1 CYRILLIC SMALL LETTER BINOCULAR O +A66C ; mapped ; A66D # 5.1 CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O +A66D..A66F ; valid # 5.1 CYRILLIC SMALL LETTER DOUBLE MONOCULAR O..COMBINING CYRILLIC VZMET +A670..A673 ; valid ; ; NV8 # 5.1 COMBINING CYRILLIC TEN MILLIONS SIGN..SLAVONIC ASTERISK +A674..A67B ; valid # 6.1 COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA +A67C..A67D ; valid # 5.1 COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK +A67E ; valid ; ; NV8 # 5.1 CYRILLIC KAVYKA +A67F ; valid # 5.1 CYRILLIC PAYEROK +A680 ; mapped ; A681 # 5.1 CYRILLIC CAPITAL LETTER DWE +A681 ; valid # 5.1 CYRILLIC SMALL LETTER DWE +A682 ; mapped ; A683 # 5.1 CYRILLIC CAPITAL LETTER DZWE +A683 ; valid # 5.1 CYRILLIC SMALL LETTER DZWE +A684 ; mapped ; A685 # 5.1 CYRILLIC CAPITAL LETTER ZHWE +A685 ; valid # 5.1 CYRILLIC SMALL LETTER ZHWE +A686 ; mapped ; A687 # 5.1 CYRILLIC CAPITAL LETTER CCHE +A687 ; valid # 5.1 CYRILLIC SMALL LETTER CCHE +A688 ; mapped ; A689 # 5.1 CYRILLIC CAPITAL LETTER DZZE +A689 ; valid # 5.1 CYRILLIC SMALL LETTER DZZE +A68A ; mapped ; A68B # 5.1 CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK +A68B ; valid # 5.1 CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK +A68C ; mapped ; A68D # 5.1 CYRILLIC CAPITAL LETTER TWE +A68D ; valid # 5.1 CYRILLIC SMALL LETTER TWE +A68E ; mapped ; A68F # 5.1 CYRILLIC CAPITAL LETTER TSWE +A68F ; valid # 5.1 CYRILLIC SMALL LETTER TSWE +A690 ; mapped ; A691 # 5.1 CYRILLIC CAPITAL LETTER TSSE +A691 ; valid # 5.1 CYRILLIC SMALL LETTER TSSE +A692 ; mapped ; A693 # 5.1 CYRILLIC CAPITAL LETTER TCHE +A693 ; valid # 5.1 CYRILLIC SMALL LETTER TCHE +A694 ; mapped ; A695 # 5.1 CYRILLIC CAPITAL LETTER HWE +A695 ; valid # 5.1 CYRILLIC SMALL LETTER HWE +A696 ; mapped ; A697 # 5.1 CYRILLIC CAPITAL LETTER SHWE +A697 ; valid # 5.1 CYRILLIC SMALL LETTER SHWE +A698 ; mapped ; A699 # 7.0 CYRILLIC CAPITAL LETTER DOUBLE O +A699 ; valid # 7.0 CYRILLIC SMALL LETTER DOUBLE O +A69A ; mapped ; A69B # 7.0 CYRILLIC CAPITAL LETTER CROSSED O +A69B ; valid # 7.0 CYRILLIC SMALL LETTER CROSSED O +A69C ; mapped ; 044A # 7.0 MODIFIER LETTER CYRILLIC HARD SIGN +A69D ; mapped ; 044C # 7.0 MODIFIER LETTER CYRILLIC SOFT SIGN +A69E ; valid # 8.0 COMBINING CYRILLIC LETTER EF +A69F ; valid # 6.1 COMBINING CYRILLIC LETTER IOTIFIED E +A6A0..A6E5 ; valid # 5.2 BAMUM LETTER A..BAMUM LETTER KI +A6E6..A6EF ; valid ; ; NV8 # 5.2 BAMUM LETTER MO..BAMUM LETTER KOGHOM +A6F0..A6F1 ; valid # 5.2 BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS +A6F2..A6F7 ; valid ; ; NV8 # 5.2 BAMUM NJAEMLI..BAMUM QUESTION MARK +A6F8..A6FF ; disallowed # NA .. +A700..A716 ; valid ; ; NV8 # 4.1 MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717..A71A ; valid # 5.0 MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOWER RIGHT CORNER ANGLE +A71B..A71F ; valid # 5.1 MODIFIER LETTER RAISED UP ARROW..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721 ; valid ; ; NV8 # 5.0 MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE +A722 ; mapped ; A723 # 5.1 LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF +A723 ; valid # 5.1 LATIN SMALL LETTER EGYPTOLOGICAL ALEF +A724 ; mapped ; A725 # 5.1 LATIN CAPITAL LETTER EGYPTOLOGICAL AIN +A725 ; valid # 5.1 LATIN SMALL LETTER EGYPTOLOGICAL AIN +A726 ; mapped ; A727 # 5.1 LATIN CAPITAL LETTER HENG +A727 ; valid # 5.1 LATIN SMALL LETTER HENG +A728 ; mapped ; A729 # 5.1 LATIN CAPITAL LETTER TZ +A729 ; valid # 5.1 LATIN SMALL LETTER TZ +A72A ; mapped ; A72B # 5.1 LATIN CAPITAL LETTER TRESILLO +A72B ; valid # 5.1 LATIN SMALL LETTER TRESILLO +A72C ; mapped ; A72D # 5.1 LATIN CAPITAL LETTER CUATRILLO +A72D ; valid # 5.1 LATIN SMALL LETTER CUATRILLO +A72E ; mapped ; A72F # 5.1 LATIN CAPITAL LETTER CUATRILLO WITH COMMA +A72F..A731 ; valid # 5.1 LATIN SMALL LETTER CUATRILLO WITH COMMA..LATIN LETTER SMALL CAPITAL S +A732 ; mapped ; A733 # 5.1 LATIN CAPITAL LETTER AA +A733 ; valid # 5.1 LATIN SMALL LETTER AA +A734 ; mapped ; A735 # 5.1 LATIN CAPITAL LETTER AO +A735 ; valid # 5.1 LATIN SMALL LETTER AO +A736 ; mapped ; A737 # 5.1 LATIN CAPITAL LETTER AU +A737 ; valid # 5.1 LATIN SMALL LETTER AU +A738 ; mapped ; A739 # 5.1 LATIN CAPITAL LETTER AV +A739 ; valid # 5.1 LATIN SMALL LETTER AV +A73A ; mapped ; A73B # 5.1 LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR +A73B ; valid # 5.1 LATIN SMALL LETTER AV WITH HORIZONTAL BAR +A73C ; mapped ; A73D # 5.1 LATIN CAPITAL LETTER AY +A73D ; valid # 5.1 LATIN SMALL LETTER AY +A73E ; mapped ; A73F # 5.1 LATIN CAPITAL LETTER REVERSED C WITH DOT +A73F ; valid # 5.1 LATIN SMALL LETTER REVERSED C WITH DOT +A740 ; mapped ; A741 # 5.1 LATIN CAPITAL LETTER K WITH STROKE +A741 ; valid # 5.1 LATIN SMALL LETTER K WITH STROKE +A742 ; mapped ; A743 # 5.1 LATIN CAPITAL LETTER K WITH DIAGONAL STROKE +A743 ; valid # 5.1 LATIN SMALL LETTER K WITH DIAGONAL STROKE +A744 ; mapped ; A745 # 5.1 LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE +A745 ; valid # 5.1 LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE +A746 ; mapped ; A747 # 5.1 LATIN CAPITAL LETTER BROKEN L +A747 ; valid # 5.1 LATIN SMALL LETTER BROKEN L +A748 ; mapped ; A749 # 5.1 LATIN CAPITAL LETTER L WITH HIGH STROKE +A749 ; valid # 5.1 LATIN SMALL LETTER L WITH HIGH STROKE +A74A ; mapped ; A74B # 5.1 LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY +A74B ; valid # 5.1 LATIN SMALL LETTER O WITH LONG STROKE OVERLAY +A74C ; mapped ; A74D # 5.1 LATIN CAPITAL LETTER O WITH LOOP +A74D ; valid # 5.1 LATIN SMALL LETTER O WITH LOOP +A74E ; mapped ; A74F # 5.1 LATIN CAPITAL LETTER OO +A74F ; valid # 5.1 LATIN SMALL LETTER OO +A750 ; mapped ; A751 # 5.1 LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER +A751 ; valid # 5.1 LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER +A752 ; mapped ; A753 # 5.1 LATIN CAPITAL LETTER P WITH FLOURISH +A753 ; valid # 5.1 LATIN SMALL LETTER P WITH FLOURISH +A754 ; mapped ; A755 # 5.1 LATIN CAPITAL LETTER P WITH SQUIRREL TAIL +A755 ; valid # 5.1 LATIN SMALL LETTER P WITH SQUIRREL TAIL +A756 ; mapped ; A757 # 5.1 LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER +A757 ; valid # 5.1 LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER +A758 ; mapped ; A759 # 5.1 LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE +A759 ; valid # 5.1 LATIN SMALL LETTER Q WITH DIAGONAL STROKE +A75A ; mapped ; A75B # 5.1 LATIN CAPITAL LETTER R ROTUNDA +A75B ; valid # 5.1 LATIN SMALL LETTER R ROTUNDA +A75C ; mapped ; A75D # 5.1 LATIN CAPITAL LETTER RUM ROTUNDA +A75D ; valid # 5.1 LATIN SMALL LETTER RUM ROTUNDA +A75E ; mapped ; A75F # 5.1 LATIN CAPITAL LETTER V WITH DIAGONAL STROKE +A75F ; valid # 5.1 LATIN SMALL LETTER V WITH DIAGONAL STROKE +A760 ; mapped ; A761 # 5.1 LATIN CAPITAL LETTER VY +A761 ; valid # 5.1 LATIN SMALL LETTER VY +A762 ; mapped ; A763 # 5.1 LATIN CAPITAL LETTER VISIGOTHIC Z +A763 ; valid # 5.1 LATIN SMALL LETTER VISIGOTHIC Z +A764 ; mapped ; A765 # 5.1 LATIN CAPITAL LETTER THORN WITH STROKE +A765 ; valid # 5.1 LATIN SMALL LETTER THORN WITH STROKE +A766 ; mapped ; A767 # 5.1 LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER +A767 ; valid # 5.1 LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER +A768 ; mapped ; A769 # 5.1 LATIN CAPITAL LETTER VEND +A769 ; valid # 5.1 LATIN SMALL LETTER VEND +A76A ; mapped ; A76B # 5.1 LATIN CAPITAL LETTER ET +A76B ; valid # 5.1 LATIN SMALL LETTER ET +A76C ; mapped ; A76D # 5.1 LATIN CAPITAL LETTER IS +A76D ; valid # 5.1 LATIN SMALL LETTER IS +A76E ; mapped ; A76F # 5.1 LATIN CAPITAL LETTER CON +A76F ; valid # 5.1 LATIN SMALL LETTER CON +A770 ; mapped ; A76F # 5.1 MODIFIER LETTER US +A771..A778 ; valid # 5.1 LATIN SMALL LETTER DUM..LATIN SMALL LETTER UM +A779 ; mapped ; A77A # 5.1 LATIN CAPITAL LETTER INSULAR D +A77A ; valid # 5.1 LATIN SMALL LETTER INSULAR D +A77B ; mapped ; A77C # 5.1 LATIN CAPITAL LETTER INSULAR F +A77C ; valid # 5.1 LATIN SMALL LETTER INSULAR F +A77D ; mapped ; 1D79 # 5.1 LATIN CAPITAL LETTER INSULAR G +A77E ; mapped ; A77F # 5.1 LATIN CAPITAL LETTER TURNED INSULAR G +A77F ; valid # 5.1 LATIN SMALL LETTER TURNED INSULAR G +A780 ; mapped ; A781 # 5.1 LATIN CAPITAL LETTER TURNED L +A781 ; valid # 5.1 LATIN SMALL LETTER TURNED L +A782 ; mapped ; A783 # 5.1 LATIN CAPITAL LETTER INSULAR R +A783 ; valid # 5.1 LATIN SMALL LETTER INSULAR R +A784 ; mapped ; A785 # 5.1 LATIN CAPITAL LETTER INSULAR S +A785 ; valid # 5.1 LATIN SMALL LETTER INSULAR S +A786 ; mapped ; A787 # 5.1 LATIN CAPITAL LETTER INSULAR T +A787..A788 ; valid # 5.1 LATIN SMALL LETTER INSULAR T..MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A ; valid ; ; NV8 # 5.1 MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN +A78B ; mapped ; A78C # 5.1 LATIN CAPITAL LETTER SALTILLO +A78C ; valid # 5.1 LATIN SMALL LETTER SALTILLO +A78D ; mapped ; 0265 # 6.0 LATIN CAPITAL LETTER TURNED H +A78E ; valid # 6.0 LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +A78F ; valid # 8.0 LATIN LETTER SINOLOGICAL DOT +A790 ; mapped ; A791 # 6.0 LATIN CAPITAL LETTER N WITH DESCENDER +A791 ; valid # 6.0 LATIN SMALL LETTER N WITH DESCENDER +A792 ; mapped ; A793 # 6.1 LATIN CAPITAL LETTER C WITH BAR +A793 ; valid # 6.1 LATIN SMALL LETTER C WITH BAR +A794..A795 ; valid # 7.0 LATIN SMALL LETTER C WITH PALATAL HOOK..LATIN SMALL LETTER H WITH PALATAL HOOK +A796 ; mapped ; A797 # 7.0 LATIN CAPITAL LETTER B WITH FLOURISH +A797 ; valid # 7.0 LATIN SMALL LETTER B WITH FLOURISH +A798 ; mapped ; A799 # 7.0 LATIN CAPITAL LETTER F WITH STROKE +A799 ; valid # 7.0 LATIN SMALL LETTER F WITH STROKE +A79A ; mapped ; A79B # 7.0 LATIN CAPITAL LETTER VOLAPUK AE +A79B ; valid # 7.0 LATIN SMALL LETTER VOLAPUK AE +A79C ; mapped ; A79D # 7.0 LATIN CAPITAL LETTER VOLAPUK OE +A79D ; valid # 7.0 LATIN SMALL LETTER VOLAPUK OE +A79E ; mapped ; A79F # 7.0 LATIN CAPITAL LETTER VOLAPUK UE +A79F ; valid # 7.0 LATIN SMALL LETTER VOLAPUK UE +A7A0 ; mapped ; A7A1 # 6.0 LATIN CAPITAL LETTER G WITH OBLIQUE STROKE +A7A1 ; valid # 6.0 LATIN SMALL LETTER G WITH OBLIQUE STROKE +A7A2 ; mapped ; A7A3 # 6.0 LATIN CAPITAL LETTER K WITH OBLIQUE STROKE +A7A3 ; valid # 6.0 LATIN SMALL LETTER K WITH OBLIQUE STROKE +A7A4 ; mapped ; A7A5 # 6.0 LATIN CAPITAL LETTER N WITH OBLIQUE STROKE +A7A5 ; valid # 6.0 LATIN SMALL LETTER N WITH OBLIQUE STROKE +A7A6 ; mapped ; A7A7 # 6.0 LATIN CAPITAL LETTER R WITH OBLIQUE STROKE +A7A7 ; valid # 6.0 LATIN SMALL LETTER R WITH OBLIQUE STROKE +A7A8 ; mapped ; A7A9 # 6.0 LATIN CAPITAL LETTER S WITH OBLIQUE STROKE +A7A9 ; valid # 6.0 LATIN SMALL LETTER S WITH OBLIQUE STROKE +A7AA ; mapped ; 0266 # 6.1 LATIN CAPITAL LETTER H WITH HOOK +A7AB ; mapped ; 025C # 7.0 LATIN CAPITAL LETTER REVERSED OPEN E +A7AC ; mapped ; 0261 # 7.0 LATIN CAPITAL LETTER SCRIPT G +A7AD ; mapped ; 026C # 7.0 LATIN CAPITAL LETTER L WITH BELT +A7AE ; mapped ; 026A # 9.0 LATIN CAPITAL LETTER SMALL CAPITAL I +A7AF ; disallowed # NA +A7B0 ; mapped ; 029E # 7.0 LATIN CAPITAL LETTER TURNED K +A7B1 ; mapped ; 0287 # 7.0 LATIN CAPITAL LETTER TURNED T +A7B2 ; mapped ; 029D # 8.0 LATIN CAPITAL LETTER J WITH CROSSED-TAIL +A7B3 ; mapped ; AB53 # 8.0 LATIN CAPITAL LETTER CHI +A7B4 ; mapped ; A7B5 # 8.0 LATIN CAPITAL LETTER BETA +A7B5 ; valid # 8.0 LATIN SMALL LETTER BETA +A7B6 ; mapped ; A7B7 # 8.0 LATIN CAPITAL LETTER OMEGA +A7B7 ; valid # 8.0 LATIN SMALL LETTER OMEGA +A7B8..A7F6 ; disallowed # NA .. +A7F7 ; valid # 7.0 LATIN EPIGRAPHIC LETTER SIDEWAYS I +A7F8 ; mapped ; 0127 # 6.1 MODIFIER LETTER CAPITAL H WITH STROKE +A7F9 ; mapped ; 0153 # 6.1 MODIFIER LETTER SMALL LIGATURE OE +A7FA ; valid # 6.0 LATIN LETTER SMALL CAPITAL TURNED M +A7FB..A7FF ; valid # 5.1 LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M +A800..A827 ; valid # 4.1 SYLOTI NAGRI LETTER A..SYLOTI NAGRI VOWEL SIGN OO +A828..A82B ; valid ; ; NV8 # 4.1 SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4 +A82C..A82F ; disallowed # NA .. +A830..A839 ; valid ; ; NV8 # 5.2 NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC QUANTITY MARK +A83A..A83F ; disallowed # NA .. +A840..A873 ; valid # 5.0 PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU +A874..A877 ; valid ; ; NV8 # 5.0 PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD +A878..A87F ; disallowed # NA .. +A880..A8C4 ; valid # 5.1 SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VIRAMA +A8C5 ; valid # 9.0 SAURASHTRA SIGN CANDRABINDU +A8C6..A8CD ; disallowed # NA .. +A8CE..A8CF ; valid ; ; NV8 # 5.1 SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A8D0..A8D9 ; valid # 5.1 SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE +A8DA..A8DF ; disallowed # NA .. +A8E0..A8F7 ; valid # 5.2 COMBINING DEVANAGARI DIGIT ZERO..DEVANAGARI SIGN CANDRABINDU AVAGRAHA +A8F8..A8FA ; valid ; ; NV8 # 5.2 DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET +A8FB ; valid # 5.2 DEVANAGARI HEADSTROKE +A8FC ; valid ; ; NV8 # 8.0 DEVANAGARI SIGN SIDDHAM +A8FD ; valid # 8.0 DEVANAGARI JAIN OM +A8FE..A8FF ; disallowed # NA .. +A900..A92D ; valid # 5.1 KAYAH LI DIGIT ZERO..KAYAH LI TONE CALYA PLOPHU +A92E..A92F ; valid ; ; NV8 # 5.1 KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA +A930..A953 ; valid # 5.1 REJANG LETTER KA..REJANG VIRAMA +A954..A95E ; disallowed # NA .. +A95F ; valid ; ; NV8 # 5.1 REJANG SECTION MARK +A960..A97C ; valid ; ; NV8 # 5.2 HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH +A97D..A97F ; disallowed # NA .. +A980..A9C0 ; valid # 5.2 JAVANESE SIGN PANYANGGA..JAVANESE PANGKON +A9C1..A9CD ; valid ; ; NV8 # 5.2 JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH +A9CE ; disallowed # NA +A9CF..A9D9 ; valid # 5.2 JAVANESE PANGRANGKEP..JAVANESE DIGIT NINE +A9DA..A9DD ; disallowed # NA .. +A9DE..A9DF ; valid ; ; NV8 # 5.2 JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN +A9E0..A9FE ; valid # 7.0 MYANMAR LETTER SHAN GHA..MYANMAR LETTER TAI LAING BHA +A9FF ; disallowed # NA +AA00..AA36 ; valid # 5.1 CHAM LETTER A..CHAM CONSONANT SIGN WA +AA37..AA3F ; disallowed # NA .. +AA40..AA4D ; valid # 5.1 CHAM LETTER FINAL K..CHAM CONSONANT SIGN FINAL H +AA4E..AA4F ; disallowed # NA .. +AA50..AA59 ; valid # 5.1 CHAM DIGIT ZERO..CHAM DIGIT NINE +AA5A..AA5B ; disallowed # NA .. +AA5C..AA5F ; valid ; ; NV8 # 5.1 CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA +AA60..AA76 ; valid # 5.2 MYANMAR LETTER KHAMTI GA..MYANMAR LOGOGRAM KHAMTI HM +AA77..AA79 ; valid ; ; NV8 # 5.2 MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO +AA7A..AA7B ; valid # 5.2 MYANMAR LETTER AITON RA..MYANMAR SIGN PAO KAREN TONE +AA7C..AA7F ; valid # 7.0 MYANMAR SIGN TAI LAING TONE-2..MYANMAR LETTER SHWE PALAUNG SHA +AA80..AAC2 ; valid # 5.2 TAI VIET LETTER LOW KO..TAI VIET TONE MAI SONG +AAC3..AADA ; disallowed # NA .. +AADB..AADD ; valid # 5.2 TAI VIET SYMBOL KON..TAI VIET SYMBOL SAM +AADE..AADF ; valid ; ; NV8 # 5.2 TAI VIET SYMBOL HO HOI..TAI VIET SYMBOL KOI KOI +AAE0..AAEF ; valid # 6.1 MEETEI MAYEK LETTER E..MEETEI MAYEK VOWEL SIGN AAU +AAF0..AAF1 ; valid ; ; NV8 # 6.1 MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +AAF2..AAF6 ; valid # 6.1 MEETEI MAYEK ANJI..MEETEI MAYEK VIRAMA +AAF7..AB00 ; disallowed # NA .. +AB01..AB06 ; valid # 6.0 ETHIOPIC SYLLABLE TTHU..ETHIOPIC SYLLABLE TTHO +AB07..AB08 ; disallowed # NA .. +AB09..AB0E ; valid # 6.0 ETHIOPIC SYLLABLE DDHU..ETHIOPIC SYLLABLE DDHO +AB0F..AB10 ; disallowed # NA .. +AB11..AB16 ; valid # 6.0 ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO +AB17..AB1F ; disallowed # NA .. +AB20..AB26 ; valid # 6.0 ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO +AB27 ; disallowed # NA +AB28..AB2E ; valid # 6.0 ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO +AB2F ; disallowed # NA +AB30..AB5A ; valid # 7.0 LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5B ; valid ; ; NV8 # 7.0 MODIFIER BREVE WITH INVERTED BREVE +AB5C ; mapped ; A727 # 7.0 MODIFIER LETTER SMALL HENG +AB5D ; mapped ; AB37 # 7.0 MODIFIER LETTER SMALL L WITH INVERTED LAZY S +AB5E ; mapped ; 026B # 7.0 MODIFIER LETTER SMALL L WITH MIDDLE TILDE +AB5F ; mapped ; AB52 # 7.0 MODIFIER LETTER SMALL U WITH LEFT HOOK +AB60..AB63 ; valid # 8.0 LATIN SMALL LETTER SAKHA YAT..LATIN SMALL LETTER UO +AB64..AB65 ; valid # 7.0 LATIN SMALL LETTER INVERTED ALPHA..GREEK LETTER SMALL CAPITAL OMEGA +AB66..AB6F ; disallowed # NA .. +AB70 ; mapped ; 13A0 # 8.0 CHEROKEE SMALL LETTER A +AB71 ; mapped ; 13A1 # 8.0 CHEROKEE SMALL LETTER E +AB72 ; mapped ; 13A2 # 8.0 CHEROKEE SMALL LETTER I +AB73 ; mapped ; 13A3 # 8.0 CHEROKEE SMALL LETTER O +AB74 ; mapped ; 13A4 # 8.0 CHEROKEE SMALL LETTER U +AB75 ; mapped ; 13A5 # 8.0 CHEROKEE SMALL LETTER V +AB76 ; mapped ; 13A6 # 8.0 CHEROKEE SMALL LETTER GA +AB77 ; mapped ; 13A7 # 8.0 CHEROKEE SMALL LETTER KA +AB78 ; mapped ; 13A8 # 8.0 CHEROKEE SMALL LETTER GE +AB79 ; mapped ; 13A9 # 8.0 CHEROKEE SMALL LETTER GI +AB7A ; mapped ; 13AA # 8.0 CHEROKEE SMALL LETTER GO +AB7B ; mapped ; 13AB # 8.0 CHEROKEE SMALL LETTER GU +AB7C ; mapped ; 13AC # 8.0 CHEROKEE SMALL LETTER GV +AB7D ; mapped ; 13AD # 8.0 CHEROKEE SMALL LETTER HA +AB7E ; mapped ; 13AE # 8.0 CHEROKEE SMALL LETTER HE +AB7F ; mapped ; 13AF # 8.0 CHEROKEE SMALL LETTER HI +AB80 ; mapped ; 13B0 # 8.0 CHEROKEE SMALL LETTER HO +AB81 ; mapped ; 13B1 # 8.0 CHEROKEE SMALL LETTER HU +AB82 ; mapped ; 13B2 # 8.0 CHEROKEE SMALL LETTER HV +AB83 ; mapped ; 13B3 # 8.0 CHEROKEE SMALL LETTER LA +AB84 ; mapped ; 13B4 # 8.0 CHEROKEE SMALL LETTER LE +AB85 ; mapped ; 13B5 # 8.0 CHEROKEE SMALL LETTER LI +AB86 ; mapped ; 13B6 # 8.0 CHEROKEE SMALL LETTER LO +AB87 ; mapped ; 13B7 # 8.0 CHEROKEE SMALL LETTER LU +AB88 ; mapped ; 13B8 # 8.0 CHEROKEE SMALL LETTER LV +AB89 ; mapped ; 13B9 # 8.0 CHEROKEE SMALL LETTER MA +AB8A ; mapped ; 13BA # 8.0 CHEROKEE SMALL LETTER ME +AB8B ; mapped ; 13BB # 8.0 CHEROKEE SMALL LETTER MI +AB8C ; mapped ; 13BC # 8.0 CHEROKEE SMALL LETTER MO +AB8D ; mapped ; 13BD # 8.0 CHEROKEE SMALL LETTER MU +AB8E ; mapped ; 13BE # 8.0 CHEROKEE SMALL LETTER NA +AB8F ; mapped ; 13BF # 8.0 CHEROKEE SMALL LETTER HNA +AB90 ; mapped ; 13C0 # 8.0 CHEROKEE SMALL LETTER NAH +AB91 ; mapped ; 13C1 # 8.0 CHEROKEE SMALL LETTER NE +AB92 ; mapped ; 13C2 # 8.0 CHEROKEE SMALL LETTER NI +AB93 ; mapped ; 13C3 # 8.0 CHEROKEE SMALL LETTER NO +AB94 ; mapped ; 13C4 # 8.0 CHEROKEE SMALL LETTER NU +AB95 ; mapped ; 13C5 # 8.0 CHEROKEE SMALL LETTER NV +AB96 ; mapped ; 13C6 # 8.0 CHEROKEE SMALL LETTER QUA +AB97 ; mapped ; 13C7 # 8.0 CHEROKEE SMALL LETTER QUE +AB98 ; mapped ; 13C8 # 8.0 CHEROKEE SMALL LETTER QUI +AB99 ; mapped ; 13C9 # 8.0 CHEROKEE SMALL LETTER QUO +AB9A ; mapped ; 13CA # 8.0 CHEROKEE SMALL LETTER QUU +AB9B ; mapped ; 13CB # 8.0 CHEROKEE SMALL LETTER QUV +AB9C ; mapped ; 13CC # 8.0 CHEROKEE SMALL LETTER SA +AB9D ; mapped ; 13CD # 8.0 CHEROKEE SMALL LETTER S +AB9E ; mapped ; 13CE # 8.0 CHEROKEE SMALL LETTER SE +AB9F ; mapped ; 13CF # 8.0 CHEROKEE SMALL LETTER SI +ABA0 ; mapped ; 13D0 # 8.0 CHEROKEE SMALL LETTER SO +ABA1 ; mapped ; 13D1 # 8.0 CHEROKEE SMALL LETTER SU +ABA2 ; mapped ; 13D2 # 8.0 CHEROKEE SMALL LETTER SV +ABA3 ; mapped ; 13D3 # 8.0 CHEROKEE SMALL LETTER DA +ABA4 ; mapped ; 13D4 # 8.0 CHEROKEE SMALL LETTER TA +ABA5 ; mapped ; 13D5 # 8.0 CHEROKEE SMALL LETTER DE +ABA6 ; mapped ; 13D6 # 8.0 CHEROKEE SMALL LETTER TE +ABA7 ; mapped ; 13D7 # 8.0 CHEROKEE SMALL LETTER DI +ABA8 ; mapped ; 13D8 # 8.0 CHEROKEE SMALL LETTER TI +ABA9 ; mapped ; 13D9 # 8.0 CHEROKEE SMALL LETTER DO +ABAA ; mapped ; 13DA # 8.0 CHEROKEE SMALL LETTER DU +ABAB ; mapped ; 13DB # 8.0 CHEROKEE SMALL LETTER DV +ABAC ; mapped ; 13DC # 8.0 CHEROKEE SMALL LETTER DLA +ABAD ; mapped ; 13DD # 8.0 CHEROKEE SMALL LETTER TLA +ABAE ; mapped ; 13DE # 8.0 CHEROKEE SMALL LETTER TLE +ABAF ; mapped ; 13DF # 8.0 CHEROKEE SMALL LETTER TLI +ABB0 ; mapped ; 13E0 # 8.0 CHEROKEE SMALL LETTER TLO +ABB1 ; mapped ; 13E1 # 8.0 CHEROKEE SMALL LETTER TLU +ABB2 ; mapped ; 13E2 # 8.0 CHEROKEE SMALL LETTER TLV +ABB3 ; mapped ; 13E3 # 8.0 CHEROKEE SMALL LETTER TSA +ABB4 ; mapped ; 13E4 # 8.0 CHEROKEE SMALL LETTER TSE +ABB5 ; mapped ; 13E5 # 8.0 CHEROKEE SMALL LETTER TSI +ABB6 ; mapped ; 13E6 # 8.0 CHEROKEE SMALL LETTER TSO +ABB7 ; mapped ; 13E7 # 8.0 CHEROKEE SMALL LETTER TSU +ABB8 ; mapped ; 13E8 # 8.0 CHEROKEE SMALL LETTER TSV +ABB9 ; mapped ; 13E9 # 8.0 CHEROKEE SMALL LETTER WA +ABBA ; mapped ; 13EA # 8.0 CHEROKEE SMALL LETTER WE +ABBB ; mapped ; 13EB # 8.0 CHEROKEE SMALL LETTER WI +ABBC ; mapped ; 13EC # 8.0 CHEROKEE SMALL LETTER WO +ABBD ; mapped ; 13ED # 8.0 CHEROKEE SMALL LETTER WU +ABBE ; mapped ; 13EE # 8.0 CHEROKEE SMALL LETTER WV +ABBF ; mapped ; 13EF # 8.0 CHEROKEE SMALL LETTER YA +ABC0..ABEA ; valid # 5.2 MEETEI MAYEK LETTER KOK..MEETEI MAYEK VOWEL SIGN NUNG +ABEB ; valid ; ; NV8 # 5.2 MEETEI MAYEK CHEIKHEI +ABEC..ABED ; valid # 5.2 MEETEI MAYEK LUM IYEK..MEETEI MAYEK APUN IYEK +ABEE..ABEF ; disallowed # NA .. +ABF0..ABF9 ; valid # 5.2 MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT NINE +ABFA..ABFF ; disallowed # NA .. +AC00..D7A3 ; valid # 2.0 HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH +D7A4..D7AF ; disallowed # NA .. +D7B0..D7C6 ; valid ; ; NV8 # 5.2 HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E +D7C7..D7CA ; disallowed # NA .. +D7CB..D7FB ; valid ; ; NV8 # 5.2 HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH +D7FC..D7FF ; disallowed # NA .. +D800..DFFF ; disallowed # 2.0 .. +E000..F8FF ; disallowed # 1.1 .. +F900 ; mapped ; 8C48 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F900 +F901 ; mapped ; 66F4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F901 +F902 ; mapped ; 8ECA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F902 +F903 ; mapped ; 8CC8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F903 +F904 ; mapped ; 6ED1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F904 +F905 ; mapped ; 4E32 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F905 +F906 ; mapped ; 53E5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F906 +F907..F908 ; mapped ; 9F9C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F907..CJK COMPATIBILITY IDEOGRAPH-F908 +F909 ; mapped ; 5951 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F909 +F90A ; mapped ; 91D1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90A +F90B ; mapped ; 5587 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90B +F90C ; mapped ; 5948 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90C +F90D ; mapped ; 61F6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90D +F90E ; mapped ; 7669 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90E +F90F ; mapped ; 7F85 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F90F +F910 ; mapped ; 863F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F910 +F911 ; mapped ; 87BA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F911 +F912 ; mapped ; 88F8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F912 +F913 ; mapped ; 908F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F913 +F914 ; mapped ; 6A02 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F914 +F915 ; mapped ; 6D1B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F915 +F916 ; mapped ; 70D9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F916 +F917 ; mapped ; 73DE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F917 +F918 ; mapped ; 843D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F918 +F919 ; mapped ; 916A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F919 +F91A ; mapped ; 99F1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91A +F91B ; mapped ; 4E82 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91B +F91C ; mapped ; 5375 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91C +F91D ; mapped ; 6B04 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91D +F91E ; mapped ; 721B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91E +F91F ; mapped ; 862D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F91F +F920 ; mapped ; 9E1E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F920 +F921 ; mapped ; 5D50 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F921 +F922 ; mapped ; 6FEB # 1.1 CJK COMPATIBILITY IDEOGRAPH-F922 +F923 ; mapped ; 85CD # 1.1 CJK COMPATIBILITY IDEOGRAPH-F923 +F924 ; mapped ; 8964 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F924 +F925 ; mapped ; 62C9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F925 +F926 ; mapped ; 81D8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F926 +F927 ; mapped ; 881F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F927 +F928 ; mapped ; 5ECA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F928 +F929 ; mapped ; 6717 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F929 +F92A ; mapped ; 6D6A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92A +F92B ; mapped ; 72FC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92B +F92C ; mapped ; 90CE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92C +F92D ; mapped ; 4F86 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92D +F92E ; mapped ; 51B7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92E +F92F ; mapped ; 52DE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F92F +F930 ; mapped ; 64C4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F930 +F931 ; mapped ; 6AD3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F931 +F932 ; mapped ; 7210 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F932 +F933 ; mapped ; 76E7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F933 +F934 ; mapped ; 8001 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F934 +F935 ; mapped ; 8606 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F935 +F936 ; mapped ; 865C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F936 +F937 ; mapped ; 8DEF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F937 +F938 ; mapped ; 9732 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F938 +F939 ; mapped ; 9B6F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F939 +F93A ; mapped ; 9DFA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93A +F93B ; mapped ; 788C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93B +F93C ; mapped ; 797F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93C +F93D ; mapped ; 7DA0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93D +F93E ; mapped ; 83C9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93E +F93F ; mapped ; 9304 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F93F +F940 ; mapped ; 9E7F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F940 +F941 ; mapped ; 8AD6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F941 +F942 ; mapped ; 58DF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F942 +F943 ; mapped ; 5F04 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F943 +F944 ; mapped ; 7C60 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F944 +F945 ; mapped ; 807E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F945 +F946 ; mapped ; 7262 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F946 +F947 ; mapped ; 78CA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F947 +F948 ; mapped ; 8CC2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F948 +F949 ; mapped ; 96F7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F949 +F94A ; mapped ; 58D8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94A +F94B ; mapped ; 5C62 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94B +F94C ; mapped ; 6A13 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94C +F94D ; mapped ; 6DDA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94D +F94E ; mapped ; 6F0F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94E +F94F ; mapped ; 7D2F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F94F +F950 ; mapped ; 7E37 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F950 +F951 ; mapped ; 964B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F951 +F952 ; mapped ; 52D2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F952 +F953 ; mapped ; 808B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F953 +F954 ; mapped ; 51DC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F954 +F955 ; mapped ; 51CC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F955 +F956 ; mapped ; 7A1C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F956 +F957 ; mapped ; 7DBE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F957 +F958 ; mapped ; 83F1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F958 +F959 ; mapped ; 9675 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F959 +F95A ; mapped ; 8B80 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95A +F95B ; mapped ; 62CF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95B +F95C ; mapped ; 6A02 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95C +F95D ; mapped ; 8AFE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95D +F95E ; mapped ; 4E39 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95E +F95F ; mapped ; 5BE7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F95F +F960 ; mapped ; 6012 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F960 +F961 ; mapped ; 7387 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F961 +F962 ; mapped ; 7570 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F962 +F963 ; mapped ; 5317 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F963 +F964 ; mapped ; 78FB # 1.1 CJK COMPATIBILITY IDEOGRAPH-F964 +F965 ; mapped ; 4FBF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F965 +F966 ; mapped ; 5FA9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F966 +F967 ; mapped ; 4E0D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F967 +F968 ; mapped ; 6CCC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F968 +F969 ; mapped ; 6578 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F969 +F96A ; mapped ; 7D22 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96A +F96B ; mapped ; 53C3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96B +F96C ; mapped ; 585E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96C +F96D ; mapped ; 7701 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96D +F96E ; mapped ; 8449 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96E +F96F ; mapped ; 8AAA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F96F +F970 ; mapped ; 6BBA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F970 +F971 ; mapped ; 8FB0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F971 +F972 ; mapped ; 6C88 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F972 +F973 ; mapped ; 62FE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F973 +F974 ; mapped ; 82E5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F974 +F975 ; mapped ; 63A0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F975 +F976 ; mapped ; 7565 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F976 +F977 ; mapped ; 4EAE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F977 +F978 ; mapped ; 5169 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F978 +F979 ; mapped ; 51C9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F979 +F97A ; mapped ; 6881 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97A +F97B ; mapped ; 7CE7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97B +F97C ; mapped ; 826F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97C +F97D ; mapped ; 8AD2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97D +F97E ; mapped ; 91CF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97E +F97F ; mapped ; 52F5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F97F +F980 ; mapped ; 5442 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F980 +F981 ; mapped ; 5973 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F981 +F982 ; mapped ; 5EEC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F982 +F983 ; mapped ; 65C5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F983 +F984 ; mapped ; 6FFE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F984 +F985 ; mapped ; 792A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F985 +F986 ; mapped ; 95AD # 1.1 CJK COMPATIBILITY IDEOGRAPH-F986 +F987 ; mapped ; 9A6A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F987 +F988 ; mapped ; 9E97 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F988 +F989 ; mapped ; 9ECE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F989 +F98A ; mapped ; 529B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98A +F98B ; mapped ; 66C6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98B +F98C ; mapped ; 6B77 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98C +F98D ; mapped ; 8F62 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98D +F98E ; mapped ; 5E74 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98E +F98F ; mapped ; 6190 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F98F +F990 ; mapped ; 6200 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F990 +F991 ; mapped ; 649A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F991 +F992 ; mapped ; 6F23 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F992 +F993 ; mapped ; 7149 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F993 +F994 ; mapped ; 7489 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F994 +F995 ; mapped ; 79CA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F995 +F996 ; mapped ; 7DF4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F996 +F997 ; mapped ; 806F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F997 +F998 ; mapped ; 8F26 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F998 +F999 ; mapped ; 84EE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F999 +F99A ; mapped ; 9023 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99A +F99B ; mapped ; 934A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99B +F99C ; mapped ; 5217 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99C +F99D ; mapped ; 52A3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99D +F99E ; mapped ; 54BD # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99E +F99F ; mapped ; 70C8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F99F +F9A0 ; mapped ; 88C2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A0 +F9A1 ; mapped ; 8AAA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A1 +F9A2 ; mapped ; 5EC9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A2 +F9A3 ; mapped ; 5FF5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A3 +F9A4 ; mapped ; 637B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A4 +F9A5 ; mapped ; 6BAE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A5 +F9A6 ; mapped ; 7C3E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A6 +F9A7 ; mapped ; 7375 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A7 +F9A8 ; mapped ; 4EE4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A8 +F9A9 ; mapped ; 56F9 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9A9 +F9AA ; mapped ; 5BE7 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AA +F9AB ; mapped ; 5DBA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AB +F9AC ; mapped ; 601C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AC +F9AD ; mapped ; 73B2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AD +F9AE ; mapped ; 7469 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AE +F9AF ; mapped ; 7F9A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9AF +F9B0 ; mapped ; 8046 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B0 +F9B1 ; mapped ; 9234 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B1 +F9B2 ; mapped ; 96F6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B2 +F9B3 ; mapped ; 9748 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B3 +F9B4 ; mapped ; 9818 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B4 +F9B5 ; mapped ; 4F8B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B5 +F9B6 ; mapped ; 79AE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B6 +F9B7 ; mapped ; 91B4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B7 +F9B8 ; mapped ; 96B8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B8 +F9B9 ; mapped ; 60E1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9B9 +F9BA ; mapped ; 4E86 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BA +F9BB ; mapped ; 50DA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BB +F9BC ; mapped ; 5BEE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BC +F9BD ; mapped ; 5C3F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BD +F9BE ; mapped ; 6599 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BE +F9BF ; mapped ; 6A02 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9BF +F9C0 ; mapped ; 71CE # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C0 +F9C1 ; mapped ; 7642 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C1 +F9C2 ; mapped ; 84FC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C2 +F9C3 ; mapped ; 907C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C3 +F9C4 ; mapped ; 9F8D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C4 +F9C5 ; mapped ; 6688 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C5 +F9C6 ; mapped ; 962E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C6 +F9C7 ; mapped ; 5289 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C7 +F9C8 ; mapped ; 677B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C8 +F9C9 ; mapped ; 67F3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9C9 +F9CA ; mapped ; 6D41 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CA +F9CB ; mapped ; 6E9C # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CB +F9CC ; mapped ; 7409 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CC +F9CD ; mapped ; 7559 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CD +F9CE ; mapped ; 786B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CE +F9CF ; mapped ; 7D10 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9CF +F9D0 ; mapped ; 985E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D0 +F9D1 ; mapped ; 516D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D1 +F9D2 ; mapped ; 622E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D2 +F9D3 ; mapped ; 9678 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D3 +F9D4 ; mapped ; 502B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D4 +F9D5 ; mapped ; 5D19 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D5 +F9D6 ; mapped ; 6DEA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D6 +F9D7 ; mapped ; 8F2A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D7 +F9D8 ; mapped ; 5F8B # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D8 +F9D9 ; mapped ; 6144 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9D9 +F9DA ; mapped ; 6817 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DA +F9DB ; mapped ; 7387 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DB +F9DC ; mapped ; 9686 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DC +F9DD ; mapped ; 5229 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DD +F9DE ; mapped ; 540F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DE +F9DF ; mapped ; 5C65 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9DF +F9E0 ; mapped ; 6613 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E0 +F9E1 ; mapped ; 674E # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E1 +F9E2 ; mapped ; 68A8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E2 +F9E3 ; mapped ; 6CE5 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E3 +F9E4 ; mapped ; 7406 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E4 +F9E5 ; mapped ; 75E2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E5 +F9E6 ; mapped ; 7F79 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E6 +F9E7 ; mapped ; 88CF # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E7 +F9E8 ; mapped ; 88E1 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E8 +F9E9 ; mapped ; 91CC # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9E9 +F9EA ; mapped ; 96E2 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9EA +F9EB ; mapped ; 533F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9EB +F9EC ; mapped ; 6EBA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9EC +F9ED ; mapped ; 541D # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9ED +F9EE ; mapped ; 71D0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9EE +F9EF ; mapped ; 7498 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9EF +F9F0 ; mapped ; 85FA # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F0 +F9F1 ; mapped ; 96A3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F1 +F9F2 ; mapped ; 9C57 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F2 +F9F3 ; mapped ; 9E9F # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F3 +F9F4 ; mapped ; 6797 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F4 +F9F5 ; mapped ; 6DCB # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F5 +F9F6 ; mapped ; 81E8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F6 +F9F7 ; mapped ; 7ACB # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F7 +F9F8 ; mapped ; 7B20 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F8 +F9F9 ; mapped ; 7C92 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9F9 +F9FA ; mapped ; 72C0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FA +F9FB ; mapped ; 7099 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FB +F9FC ; mapped ; 8B58 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FC +F9FD ; mapped ; 4EC0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FD +F9FE ; mapped ; 8336 # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FE +F9FF ; mapped ; 523A # 1.1 CJK COMPATIBILITY IDEOGRAPH-F9FF +FA00 ; mapped ; 5207 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA00 +FA01 ; mapped ; 5EA6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA01 +FA02 ; mapped ; 62D3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA02 +FA03 ; mapped ; 7CD6 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA03 +FA04 ; mapped ; 5B85 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA04 +FA05 ; mapped ; 6D1E # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA05 +FA06 ; mapped ; 66B4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA06 +FA07 ; mapped ; 8F3B # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA07 +FA08 ; mapped ; 884C # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA08 +FA09 ; mapped ; 964D # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA09 +FA0A ; mapped ; 898B # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA0A +FA0B ; mapped ; 5ED3 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA0B +FA0C ; mapped ; 5140 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA0C +FA0D ; mapped ; 55C0 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA0D +FA0E..FA0F ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F +FA10 ; mapped ; 585A # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA10 +FA11 ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA11 +FA12 ; mapped ; 6674 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA12 +FA13..FA14 ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 +FA15 ; mapped ; 51DE # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA15 +FA16 ; mapped ; 732A # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA16 +FA17 ; mapped ; 76CA # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA17 +FA18 ; mapped ; 793C # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA18 +FA19 ; mapped ; 795E # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA19 +FA1A ; mapped ; 7965 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1A +FA1B ; mapped ; 798F # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1B +FA1C ; mapped ; 9756 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1C +FA1D ; mapped ; 7CBE # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1D +FA1E ; mapped ; 7FBD # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1E +FA1F ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA1F +FA20 ; mapped ; 8612 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA20 +FA21 ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA21 +FA22 ; mapped ; 8AF8 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA22 +FA23..FA24 ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA23..CJK COMPATIBILITY IDEOGRAPH-FA24 +FA25 ; mapped ; 9038 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA25 +FA26 ; mapped ; 90FD # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA26 +FA27..FA29 ; valid # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA27..CJK COMPATIBILITY IDEOGRAPH-FA29 +FA2A ; mapped ; 98EF # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA2A +FA2B ; mapped ; 98FC # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA2B +FA2C ; mapped ; 9928 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA2C +FA2D ; mapped ; 9DB4 # 1.1 CJK COMPATIBILITY IDEOGRAPH-FA2D +FA2E ; mapped ; 90DE # 6.1 CJK COMPATIBILITY IDEOGRAPH-FA2E +FA2F ; mapped ; 96B7 # 6.1 CJK COMPATIBILITY IDEOGRAPH-FA2F +FA30 ; mapped ; 4FAE # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA30 +FA31 ; mapped ; 50E7 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA31 +FA32 ; mapped ; 514D # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA32 +FA33 ; mapped ; 52C9 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA33 +FA34 ; mapped ; 52E4 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA34 +FA35 ; mapped ; 5351 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA35 +FA36 ; mapped ; 559D # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA36 +FA37 ; mapped ; 5606 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA37 +FA38 ; mapped ; 5668 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA38 +FA39 ; mapped ; 5840 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA39 +FA3A ; mapped ; 58A8 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3A +FA3B ; mapped ; 5C64 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3B +FA3C ; mapped ; 5C6E # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3C +FA3D ; mapped ; 6094 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3D +FA3E ; mapped ; 6168 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3E +FA3F ; mapped ; 618E # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA3F +FA40 ; mapped ; 61F2 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA40 +FA41 ; mapped ; 654F # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA41 +FA42 ; mapped ; 65E2 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA42 +FA43 ; mapped ; 6691 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA43 +FA44 ; mapped ; 6885 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA44 +FA45 ; mapped ; 6D77 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA45 +FA46 ; mapped ; 6E1A # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA46 +FA47 ; mapped ; 6F22 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA47 +FA48 ; mapped ; 716E # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA48 +FA49 ; mapped ; 722B # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA49 +FA4A ; mapped ; 7422 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4A +FA4B ; mapped ; 7891 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4B +FA4C ; mapped ; 793E # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4C +FA4D ; mapped ; 7949 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4D +FA4E ; mapped ; 7948 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4E +FA4F ; mapped ; 7950 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA4F +FA50 ; mapped ; 7956 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA50 +FA51 ; mapped ; 795D # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA51 +FA52 ; mapped ; 798D # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA52 +FA53 ; mapped ; 798E # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA53 +FA54 ; mapped ; 7A40 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA54 +FA55 ; mapped ; 7A81 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA55 +FA56 ; mapped ; 7BC0 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA56 +FA57 ; mapped ; 7DF4 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA57 +FA58 ; mapped ; 7E09 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA58 +FA59 ; mapped ; 7E41 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA59 +FA5A ; mapped ; 7F72 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA5A +FA5B ; mapped ; 8005 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA5B +FA5C ; mapped ; 81ED # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA5C +FA5D..FA5E ; mapped ; 8279 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA5D..CJK COMPATIBILITY IDEOGRAPH-FA5E +FA5F ; mapped ; 8457 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA5F +FA60 ; mapped ; 8910 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA60 +FA61 ; mapped ; 8996 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA61 +FA62 ; mapped ; 8B01 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA62 +FA63 ; mapped ; 8B39 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA63 +FA64 ; mapped ; 8CD3 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA64 +FA65 ; mapped ; 8D08 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA65 +FA66 ; mapped ; 8FB6 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA66 +FA67 ; mapped ; 9038 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA67 +FA68 ; mapped ; 96E3 # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA68 +FA69 ; mapped ; 97FF # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA69 +FA6A ; mapped ; 983B # 3.2 CJK COMPATIBILITY IDEOGRAPH-FA6A +FA6B ; mapped ; 6075 # 5.2 CJK COMPATIBILITY IDEOGRAPH-FA6B +FA6C ; mapped ; 242EE # 5.2 CJK COMPATIBILITY IDEOGRAPH-FA6C +FA6D ; mapped ; 8218 # 5.2 CJK COMPATIBILITY IDEOGRAPH-FA6D +FA6E..FA6F ; disallowed # NA .. +FA70 ; mapped ; 4E26 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA70 +FA71 ; mapped ; 51B5 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA71 +FA72 ; mapped ; 5168 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA72 +FA73 ; mapped ; 4F80 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA73 +FA74 ; mapped ; 5145 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA74 +FA75 ; mapped ; 5180 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA75 +FA76 ; mapped ; 52C7 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA76 +FA77 ; mapped ; 52FA # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA77 +FA78 ; mapped ; 559D # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA78 +FA79 ; mapped ; 5555 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA79 +FA7A ; mapped ; 5599 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7A +FA7B ; mapped ; 55E2 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7B +FA7C ; mapped ; 585A # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7C +FA7D ; mapped ; 58B3 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7D +FA7E ; mapped ; 5944 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7E +FA7F ; mapped ; 5954 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA7F +FA80 ; mapped ; 5A62 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA80 +FA81 ; mapped ; 5B28 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA81 +FA82 ; mapped ; 5ED2 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA82 +FA83 ; mapped ; 5ED9 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA83 +FA84 ; mapped ; 5F69 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA84 +FA85 ; mapped ; 5FAD # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA85 +FA86 ; mapped ; 60D8 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA86 +FA87 ; mapped ; 614E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA87 +FA88 ; mapped ; 6108 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA88 +FA89 ; mapped ; 618E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA89 +FA8A ; mapped ; 6160 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8A +FA8B ; mapped ; 61F2 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8B +FA8C ; mapped ; 6234 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8C +FA8D ; mapped ; 63C4 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8D +FA8E ; mapped ; 641C # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8E +FA8F ; mapped ; 6452 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA8F +FA90 ; mapped ; 6556 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA90 +FA91 ; mapped ; 6674 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA91 +FA92 ; mapped ; 6717 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA92 +FA93 ; mapped ; 671B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA93 +FA94 ; mapped ; 6756 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA94 +FA95 ; mapped ; 6B79 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA95 +FA96 ; mapped ; 6BBA # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA96 +FA97 ; mapped ; 6D41 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA97 +FA98 ; mapped ; 6EDB # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA98 +FA99 ; mapped ; 6ECB # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA99 +FA9A ; mapped ; 6F22 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9A +FA9B ; mapped ; 701E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9B +FA9C ; mapped ; 716E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9C +FA9D ; mapped ; 77A7 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9D +FA9E ; mapped ; 7235 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9E +FA9F ; mapped ; 72AF # 4.1 CJK COMPATIBILITY IDEOGRAPH-FA9F +FAA0 ; mapped ; 732A # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA0 +FAA1 ; mapped ; 7471 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA1 +FAA2 ; mapped ; 7506 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA2 +FAA3 ; mapped ; 753B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA3 +FAA4 ; mapped ; 761D # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA4 +FAA5 ; mapped ; 761F # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA5 +FAA6 ; mapped ; 76CA # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA6 +FAA7 ; mapped ; 76DB # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA7 +FAA8 ; mapped ; 76F4 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA8 +FAA9 ; mapped ; 774A # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAA9 +FAAA ; mapped ; 7740 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAA +FAAB ; mapped ; 78CC # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAB +FAAC ; mapped ; 7AB1 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAC +FAAD ; mapped ; 7BC0 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAD +FAAE ; mapped ; 7C7B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAE +FAAF ; mapped ; 7D5B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAAF +FAB0 ; mapped ; 7DF4 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB0 +FAB1 ; mapped ; 7F3E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB1 +FAB2 ; mapped ; 8005 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB2 +FAB3 ; mapped ; 8352 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB3 +FAB4 ; mapped ; 83EF # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB4 +FAB5 ; mapped ; 8779 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB5 +FAB6 ; mapped ; 8941 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB6 +FAB7 ; mapped ; 8986 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB7 +FAB8 ; mapped ; 8996 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB8 +FAB9 ; mapped ; 8ABF # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAB9 +FABA ; mapped ; 8AF8 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABA +FABB ; mapped ; 8ACB # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABB +FABC ; mapped ; 8B01 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABC +FABD ; mapped ; 8AFE # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABD +FABE ; mapped ; 8AED # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABE +FABF ; mapped ; 8B39 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FABF +FAC0 ; mapped ; 8B8A # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC0 +FAC1 ; mapped ; 8D08 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC1 +FAC2 ; mapped ; 8F38 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC2 +FAC3 ; mapped ; 9072 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC3 +FAC4 ; mapped ; 9199 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC4 +FAC5 ; mapped ; 9276 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC5 +FAC6 ; mapped ; 967C # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC6 +FAC7 ; mapped ; 96E3 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC7 +FAC8 ; mapped ; 9756 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC8 +FAC9 ; mapped ; 97DB # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAC9 +FACA ; mapped ; 97FF # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACA +FACB ; mapped ; 980B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACB +FACC ; mapped ; 983B # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACC +FACD ; mapped ; 9B12 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACD +FACE ; mapped ; 9F9C # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACE +FACF ; mapped ; 2284A # 4.1 CJK COMPATIBILITY IDEOGRAPH-FACF +FAD0 ; mapped ; 22844 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD0 +FAD1 ; mapped ; 233D5 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD1 +FAD2 ; mapped ; 3B9D # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD2 +FAD3 ; mapped ; 4018 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD3 +FAD4 ; mapped ; 4039 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD4 +FAD5 ; mapped ; 25249 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD5 +FAD6 ; mapped ; 25CD0 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD6 +FAD7 ; mapped ; 27ED3 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD7 +FAD8 ; mapped ; 9F43 # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD8 +FAD9 ; mapped ; 9F8E # 4.1 CJK COMPATIBILITY IDEOGRAPH-FAD9 +FADA..FAFF ; disallowed # NA .. +FB00 ; mapped ; 0066 0066 # 1.1 LATIN SMALL LIGATURE FF +FB01 ; mapped ; 0066 0069 # 1.1 LATIN SMALL LIGATURE FI +FB02 ; mapped ; 0066 006C # 1.1 LATIN SMALL LIGATURE FL +FB03 ; mapped ; 0066 0066 0069 #1.1 LATIN SMALL LIGATURE FFI +FB04 ; mapped ; 0066 0066 006C #1.1 LATIN SMALL LIGATURE FFL +FB05..FB06 ; mapped ; 0073 0074 # 1.1 LATIN SMALL LIGATURE LONG S T..LATIN SMALL LIGATURE ST +FB07..FB12 ; disallowed # NA .. +FB13 ; mapped ; 0574 0576 # 1.1 ARMENIAN SMALL LIGATURE MEN NOW +FB14 ; mapped ; 0574 0565 # 1.1 ARMENIAN SMALL LIGATURE MEN ECH +FB15 ; mapped ; 0574 056B # 1.1 ARMENIAN SMALL LIGATURE MEN INI +FB16 ; mapped ; 057E 0576 # 1.1 ARMENIAN SMALL LIGATURE VEW NOW +FB17 ; mapped ; 0574 056D # 1.1 ARMENIAN SMALL LIGATURE MEN XEH +FB18..FB1C ; disallowed # NA .. +FB1D ; mapped ; 05D9 05B4 # 3.0 HEBREW LETTER YOD WITH HIRIQ +FB1E ; valid # 1.1 HEBREW POINT JUDEO-SPANISH VARIKA +FB1F ; mapped ; 05F2 05B7 # 1.1 HEBREW LIGATURE YIDDISH YOD YOD PATAH +FB20 ; mapped ; 05E2 # 1.1 HEBREW LETTER ALTERNATIVE AYIN +FB21 ; mapped ; 05D0 # 1.1 HEBREW LETTER WIDE ALEF +FB22 ; mapped ; 05D3 # 1.1 HEBREW LETTER WIDE DALET +FB23 ; mapped ; 05D4 # 1.1 HEBREW LETTER WIDE HE +FB24 ; mapped ; 05DB # 1.1 HEBREW LETTER WIDE KAF +FB25 ; mapped ; 05DC # 1.1 HEBREW LETTER WIDE LAMED +FB26 ; mapped ; 05DD # 1.1 HEBREW LETTER WIDE FINAL MEM +FB27 ; mapped ; 05E8 # 1.1 HEBREW LETTER WIDE RESH +FB28 ; mapped ; 05EA # 1.1 HEBREW LETTER WIDE TAV +FB29 ; disallowed_STD3_mapped ; 002B # 1.1 HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A ; mapped ; 05E9 05C1 # 1.1 HEBREW LETTER SHIN WITH SHIN DOT +FB2B ; mapped ; 05E9 05C2 # 1.1 HEBREW LETTER SHIN WITH SIN DOT +FB2C ; mapped ; 05E9 05BC 05C1 #1.1 HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT +FB2D ; mapped ; 05E9 05BC 05C2 #1.1 HEBREW LETTER SHIN WITH DAGESH AND SIN DOT +FB2E ; mapped ; 05D0 05B7 # 1.1 HEBREW LETTER ALEF WITH PATAH +FB2F ; mapped ; 05D0 05B8 # 1.1 HEBREW LETTER ALEF WITH QAMATS +FB30 ; mapped ; 05D0 05BC # 1.1 HEBREW LETTER ALEF WITH MAPIQ +FB31 ; mapped ; 05D1 05BC # 1.1 HEBREW LETTER BET WITH DAGESH +FB32 ; mapped ; 05D2 05BC # 1.1 HEBREW LETTER GIMEL WITH DAGESH +FB33 ; mapped ; 05D3 05BC # 1.1 HEBREW LETTER DALET WITH DAGESH +FB34 ; mapped ; 05D4 05BC # 1.1 HEBREW LETTER HE WITH MAPIQ +FB35 ; mapped ; 05D5 05BC # 1.1 HEBREW LETTER VAV WITH DAGESH +FB36 ; mapped ; 05D6 05BC # 1.1 HEBREW LETTER ZAYIN WITH DAGESH +FB37 ; disallowed # NA +FB38 ; mapped ; 05D8 05BC # 1.1 HEBREW LETTER TET WITH DAGESH +FB39 ; mapped ; 05D9 05BC # 1.1 HEBREW LETTER YOD WITH DAGESH +FB3A ; mapped ; 05DA 05BC # 1.1 HEBREW LETTER FINAL KAF WITH DAGESH +FB3B ; mapped ; 05DB 05BC # 1.1 HEBREW LETTER KAF WITH DAGESH +FB3C ; mapped ; 05DC 05BC # 1.1 HEBREW LETTER LAMED WITH DAGESH +FB3D ; disallowed # NA +FB3E ; mapped ; 05DE 05BC # 1.1 HEBREW LETTER MEM WITH DAGESH +FB3F ; disallowed # NA +FB40 ; mapped ; 05E0 05BC # 1.1 HEBREW LETTER NUN WITH DAGESH +FB41 ; mapped ; 05E1 05BC # 1.1 HEBREW LETTER SAMEKH WITH DAGESH +FB42 ; disallowed # NA +FB43 ; mapped ; 05E3 05BC # 1.1 HEBREW LETTER FINAL PE WITH DAGESH +FB44 ; mapped ; 05E4 05BC # 1.1 HEBREW LETTER PE WITH DAGESH +FB45 ; disallowed # NA +FB46 ; mapped ; 05E6 05BC # 1.1 HEBREW LETTER TSADI WITH DAGESH +FB47 ; mapped ; 05E7 05BC # 1.1 HEBREW LETTER QOF WITH DAGESH +FB48 ; mapped ; 05E8 05BC # 1.1 HEBREW LETTER RESH WITH DAGESH +FB49 ; mapped ; 05E9 05BC # 1.1 HEBREW LETTER SHIN WITH DAGESH +FB4A ; mapped ; 05EA 05BC # 1.1 HEBREW LETTER TAV WITH DAGESH +FB4B ; mapped ; 05D5 05B9 # 1.1 HEBREW LETTER VAV WITH HOLAM +FB4C ; mapped ; 05D1 05BF # 1.1 HEBREW LETTER BET WITH RAFE +FB4D ; mapped ; 05DB 05BF # 1.1 HEBREW LETTER KAF WITH RAFE +FB4E ; mapped ; 05E4 05BF # 1.1 HEBREW LETTER PE WITH RAFE +FB4F ; mapped ; 05D0 05DC # 1.1 HEBREW LIGATURE ALEF LAMED +FB50..FB51 ; mapped ; 0671 # 1.1 ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER ALEF WASLA FINAL FORM +FB52..FB55 ; mapped ; 067B # 1.1 ARABIC LETTER BEEH ISOLATED FORM..ARABIC LETTER BEEH MEDIAL FORM +FB56..FB59 ; mapped ; 067E # 1.1 ARABIC LETTER PEH ISOLATED FORM..ARABIC LETTER PEH MEDIAL FORM +FB5A..FB5D ; mapped ; 0680 # 1.1 ARABIC LETTER BEHEH ISOLATED FORM..ARABIC LETTER BEHEH MEDIAL FORM +FB5E..FB61 ; mapped ; 067A # 1.1 ARABIC LETTER TTEHEH ISOLATED FORM..ARABIC LETTER TTEHEH MEDIAL FORM +FB62..FB65 ; mapped ; 067F # 1.1 ARABIC LETTER TEHEH ISOLATED FORM..ARABIC LETTER TEHEH MEDIAL FORM +FB66..FB69 ; mapped ; 0679 # 1.1 ARABIC LETTER TTEH ISOLATED FORM..ARABIC LETTER TTEH MEDIAL FORM +FB6A..FB6D ; mapped ; 06A4 # 1.1 ARABIC LETTER VEH ISOLATED FORM..ARABIC LETTER VEH MEDIAL FORM +FB6E..FB71 ; mapped ; 06A6 # 1.1 ARABIC LETTER PEHEH ISOLATED FORM..ARABIC LETTER PEHEH MEDIAL FORM +FB72..FB75 ; mapped ; 0684 # 1.1 ARABIC LETTER DYEH ISOLATED FORM..ARABIC LETTER DYEH MEDIAL FORM +FB76..FB79 ; mapped ; 0683 # 1.1 ARABIC LETTER NYEH ISOLATED FORM..ARABIC LETTER NYEH MEDIAL FORM +FB7A..FB7D ; mapped ; 0686 # 1.1 ARABIC LETTER TCHEH ISOLATED FORM..ARABIC LETTER TCHEH MEDIAL FORM +FB7E..FB81 ; mapped ; 0687 # 1.1 ARABIC LETTER TCHEHEH ISOLATED FORM..ARABIC LETTER TCHEHEH MEDIAL FORM +FB82..FB83 ; mapped ; 068D # 1.1 ARABIC LETTER DDAHAL ISOLATED FORM..ARABIC LETTER DDAHAL FINAL FORM +FB84..FB85 ; mapped ; 068C # 1.1 ARABIC LETTER DAHAL ISOLATED FORM..ARABIC LETTER DAHAL FINAL FORM +FB86..FB87 ; mapped ; 068E # 1.1 ARABIC LETTER DUL ISOLATED FORM..ARABIC LETTER DUL FINAL FORM +FB88..FB89 ; mapped ; 0688 # 1.1 ARABIC LETTER DDAL ISOLATED FORM..ARABIC LETTER DDAL FINAL FORM +FB8A..FB8B ; mapped ; 0698 # 1.1 ARABIC LETTER JEH ISOLATED FORM..ARABIC LETTER JEH FINAL FORM +FB8C..FB8D ; mapped ; 0691 # 1.1 ARABIC LETTER RREH ISOLATED FORM..ARABIC LETTER RREH FINAL FORM +FB8E..FB91 ; mapped ; 06A9 # 1.1 ARABIC LETTER KEHEH ISOLATED FORM..ARABIC LETTER KEHEH MEDIAL FORM +FB92..FB95 ; mapped ; 06AF # 1.1 ARABIC LETTER GAF ISOLATED FORM..ARABIC LETTER GAF MEDIAL FORM +FB96..FB99 ; mapped ; 06B3 # 1.1 ARABIC LETTER GUEH ISOLATED FORM..ARABIC LETTER GUEH MEDIAL FORM +FB9A..FB9D ; mapped ; 06B1 # 1.1 ARABIC LETTER NGOEH ISOLATED FORM..ARABIC LETTER NGOEH MEDIAL FORM +FB9E..FB9F ; mapped ; 06BA # 1.1 ARABIC LETTER NOON GHUNNA ISOLATED FORM..ARABIC LETTER NOON GHUNNA FINAL FORM +FBA0..FBA3 ; mapped ; 06BB # 1.1 ARABIC LETTER RNOON ISOLATED FORM..ARABIC LETTER RNOON MEDIAL FORM +FBA4..FBA5 ; mapped ; 06C0 # 1.1 ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM..ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM +FBA6..FBA9 ; mapped ; 06C1 # 1.1 ARABIC LETTER HEH GOAL ISOLATED FORM..ARABIC LETTER HEH GOAL MEDIAL FORM +FBAA..FBAD ; mapped ; 06BE # 1.1 ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM..ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM +FBAE..FBAF ; mapped ; 06D2 # 1.1 ARABIC LETTER YEH BARREE ISOLATED FORM..ARABIC LETTER YEH BARREE FINAL FORM +FBB0..FBB1 ; mapped ; 06D3 # 1.1 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBB2..FBC1 ; valid ; ; NV8 # 6.0 ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW +FBC2..FBD2 ; disallowed # NA .. +FBD3..FBD6 ; mapped ; 06AD # 1.1 ARABIC LETTER NG ISOLATED FORM..ARABIC LETTER NG MEDIAL FORM +FBD7..FBD8 ; mapped ; 06C7 # 1.1 ARABIC LETTER U ISOLATED FORM..ARABIC LETTER U FINAL FORM +FBD9..FBDA ; mapped ; 06C6 # 1.1 ARABIC LETTER OE ISOLATED FORM..ARABIC LETTER OE FINAL FORM +FBDB..FBDC ; mapped ; 06C8 # 1.1 ARABIC LETTER YU ISOLATED FORM..ARABIC LETTER YU FINAL FORM +FBDD ; mapped ; 06C7 0674 # 1.1 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM +FBDE..FBDF ; mapped ; 06CB # 1.1 ARABIC LETTER VE ISOLATED FORM..ARABIC LETTER VE FINAL FORM +FBE0..FBE1 ; mapped ; 06C5 # 1.1 ARABIC LETTER KIRGHIZ OE ISOLATED FORM..ARABIC LETTER KIRGHIZ OE FINAL FORM +FBE2..FBE3 ; mapped ; 06C9 # 1.1 ARABIC LETTER KIRGHIZ YU ISOLATED FORM..ARABIC LETTER KIRGHIZ YU FINAL FORM +FBE4..FBE7 ; mapped ; 06D0 # 1.1 ARABIC LETTER E ISOLATED FORM..ARABIC LETTER E MEDIAL FORM +FBE8..FBE9 ; mapped ; 0649 # 1.1 ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM..ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM +FBEA..FBEB ; mapped ; 0626 0627 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM +FBEC..FBED ; mapped ; 0626 06D5 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM +FBEE..FBEF ; mapped ; 0626 0648 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM +FBF0..FBF1 ; mapped ; 0626 06C7 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM +FBF2..FBF3 ; mapped ; 0626 06C6 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM +FBF4..FBF5 ; mapped ; 0626 06C8 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM +FBF6..FBF8 ; mapped ; 0626 06D0 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM..ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM +FBF9..FBFB ; mapped ; 0626 0649 # 1.1 ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM..ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM +FBFC..FBFF ; mapped ; 06CC # 1.1 ARABIC LETTER FARSI YEH ISOLATED FORM..ARABIC LETTER FARSI YEH MEDIAL FORM +FC00 ; mapped ; 0626 062C # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM +FC01 ; mapped ; 0626 062D # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM +FC02 ; mapped ; 0626 0645 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM +FC03 ; mapped ; 0626 0649 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FC04 ; mapped ; 0626 064A # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM +FC05 ; mapped ; 0628 062C # 1.1 ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM +FC06 ; mapped ; 0628 062D # 1.1 ARABIC LIGATURE BEH WITH HAH ISOLATED FORM +FC07 ; mapped ; 0628 062E # 1.1 ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM +FC08 ; mapped ; 0628 0645 # 1.1 ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM +FC09 ; mapped ; 0628 0649 # 1.1 ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM +FC0A ; mapped ; 0628 064A # 1.1 ARABIC LIGATURE BEH WITH YEH ISOLATED FORM +FC0B ; mapped ; 062A 062C # 1.1 ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM +FC0C ; mapped ; 062A 062D # 1.1 ARABIC LIGATURE TEH WITH HAH ISOLATED FORM +FC0D ; mapped ; 062A 062E # 1.1 ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM +FC0E ; mapped ; 062A 0645 # 1.1 ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM +FC0F ; mapped ; 062A 0649 # 1.1 ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM +FC10 ; mapped ; 062A 064A # 1.1 ARABIC LIGATURE TEH WITH YEH ISOLATED FORM +FC11 ; mapped ; 062B 062C # 1.1 ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM +FC12 ; mapped ; 062B 0645 # 1.1 ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM +FC13 ; mapped ; 062B 0649 # 1.1 ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM +FC14 ; mapped ; 062B 064A # 1.1 ARABIC LIGATURE THEH WITH YEH ISOLATED FORM +FC15 ; mapped ; 062C 062D # 1.1 ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM +FC16 ; mapped ; 062C 0645 # 1.1 ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM +FC17 ; mapped ; 062D 062C # 1.1 ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM +FC18 ; mapped ; 062D 0645 # 1.1 ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM +FC19 ; mapped ; 062E 062C # 1.1 ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM +FC1A ; mapped ; 062E 062D # 1.1 ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM +FC1B ; mapped ; 062E 0645 # 1.1 ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM +FC1C ; mapped ; 0633 062C # 1.1 ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM +FC1D ; mapped ; 0633 062D # 1.1 ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM +FC1E ; mapped ; 0633 062E # 1.1 ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM +FC1F ; mapped ; 0633 0645 # 1.1 ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM +FC20 ; mapped ; 0635 062D # 1.1 ARABIC LIGATURE SAD WITH HAH ISOLATED FORM +FC21 ; mapped ; 0635 0645 # 1.1 ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM +FC22 ; mapped ; 0636 062C # 1.1 ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM +FC23 ; mapped ; 0636 062D # 1.1 ARABIC LIGATURE DAD WITH HAH ISOLATED FORM +FC24 ; mapped ; 0636 062E # 1.1 ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM +FC25 ; mapped ; 0636 0645 # 1.1 ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM +FC26 ; mapped ; 0637 062D # 1.1 ARABIC LIGATURE TAH WITH HAH ISOLATED FORM +FC27 ; mapped ; 0637 0645 # 1.1 ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM +FC28 ; mapped ; 0638 0645 # 1.1 ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM +FC29 ; mapped ; 0639 062C # 1.1 ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM +FC2A ; mapped ; 0639 0645 # 1.1 ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM +FC2B ; mapped ; 063A 062C # 1.1 ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM +FC2C ; mapped ; 063A 0645 # 1.1 ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM +FC2D ; mapped ; 0641 062C # 1.1 ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM +FC2E ; mapped ; 0641 062D # 1.1 ARABIC LIGATURE FEH WITH HAH ISOLATED FORM +FC2F ; mapped ; 0641 062E # 1.1 ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM +FC30 ; mapped ; 0641 0645 # 1.1 ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM +FC31 ; mapped ; 0641 0649 # 1.1 ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM +FC32 ; mapped ; 0641 064A # 1.1 ARABIC LIGATURE FEH WITH YEH ISOLATED FORM +FC33 ; mapped ; 0642 062D # 1.1 ARABIC LIGATURE QAF WITH HAH ISOLATED FORM +FC34 ; mapped ; 0642 0645 # 1.1 ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM +FC35 ; mapped ; 0642 0649 # 1.1 ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM +FC36 ; mapped ; 0642 064A # 1.1 ARABIC LIGATURE QAF WITH YEH ISOLATED FORM +FC37 ; mapped ; 0643 0627 # 1.1 ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM +FC38 ; mapped ; 0643 062C # 1.1 ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM +FC39 ; mapped ; 0643 062D # 1.1 ARABIC LIGATURE KAF WITH HAH ISOLATED FORM +FC3A ; mapped ; 0643 062E # 1.1 ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM +FC3B ; mapped ; 0643 0644 # 1.1 ARABIC LIGATURE KAF WITH LAM ISOLATED FORM +FC3C ; mapped ; 0643 0645 # 1.1 ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM +FC3D ; mapped ; 0643 0649 # 1.1 ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM +FC3E ; mapped ; 0643 064A # 1.1 ARABIC LIGATURE KAF WITH YEH ISOLATED FORM +FC3F ; mapped ; 0644 062C # 1.1 ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM +FC40 ; mapped ; 0644 062D # 1.1 ARABIC LIGATURE LAM WITH HAH ISOLATED FORM +FC41 ; mapped ; 0644 062E # 1.1 ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM +FC42 ; mapped ; 0644 0645 # 1.1 ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM +FC43 ; mapped ; 0644 0649 # 1.1 ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM +FC44 ; mapped ; 0644 064A # 1.1 ARABIC LIGATURE LAM WITH YEH ISOLATED FORM +FC45 ; mapped ; 0645 062C # 1.1 ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM +FC46 ; mapped ; 0645 062D # 1.1 ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM +FC47 ; mapped ; 0645 062E # 1.1 ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM +FC48 ; mapped ; 0645 0645 # 1.1 ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM +FC49 ; mapped ; 0645 0649 # 1.1 ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM +FC4A ; mapped ; 0645 064A # 1.1 ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM +FC4B ; mapped ; 0646 062C # 1.1 ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM +FC4C ; mapped ; 0646 062D # 1.1 ARABIC LIGATURE NOON WITH HAH ISOLATED FORM +FC4D ; mapped ; 0646 062E # 1.1 ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM +FC4E ; mapped ; 0646 0645 # 1.1 ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM +FC4F ; mapped ; 0646 0649 # 1.1 ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM +FC50 ; mapped ; 0646 064A # 1.1 ARABIC LIGATURE NOON WITH YEH ISOLATED FORM +FC51 ; mapped ; 0647 062C # 1.1 ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM +FC52 ; mapped ; 0647 0645 # 1.1 ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM +FC53 ; mapped ; 0647 0649 # 1.1 ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM +FC54 ; mapped ; 0647 064A # 1.1 ARABIC LIGATURE HEH WITH YEH ISOLATED FORM +FC55 ; mapped ; 064A 062C # 1.1 ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM +FC56 ; mapped ; 064A 062D # 1.1 ARABIC LIGATURE YEH WITH HAH ISOLATED FORM +FC57 ; mapped ; 064A 062E # 1.1 ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM +FC58 ; mapped ; 064A 0645 # 1.1 ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM +FC59 ; mapped ; 064A 0649 # 1.1 ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM +FC5A ; mapped ; 064A 064A # 1.1 ARABIC LIGATURE YEH WITH YEH ISOLATED FORM +FC5B ; mapped ; 0630 0670 # 1.1 ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5C ; mapped ; 0631 0670 # 1.1 ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5D ; mapped ; 0649 0670 # 1.1 ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC5E ; disallowed_STD3_mapped ; 0020 064C 0651 #1.1 ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM +FC5F ; disallowed_STD3_mapped ; 0020 064D 0651 #1.1 ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM +FC60 ; disallowed_STD3_mapped ; 0020 064E 0651 #1.1 ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM +FC61 ; disallowed_STD3_mapped ; 0020 064F 0651 #1.1 ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM +FC62 ; disallowed_STD3_mapped ; 0020 0650 0651 #1.1 ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM +FC63 ; disallowed_STD3_mapped ; 0020 0651 0670 #1.1 ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM +FC64 ; mapped ; 0626 0631 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM +FC65 ; mapped ; 0626 0632 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM +FC66 ; mapped ; 0626 0645 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM +FC67 ; mapped ; 0626 0646 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM +FC68 ; mapped ; 0626 0649 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FC69 ; mapped ; 0626 064A # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM +FC6A ; mapped ; 0628 0631 # 1.1 ARABIC LIGATURE BEH WITH REH FINAL FORM +FC6B ; mapped ; 0628 0632 # 1.1 ARABIC LIGATURE BEH WITH ZAIN FINAL FORM +FC6C ; mapped ; 0628 0645 # 1.1 ARABIC LIGATURE BEH WITH MEEM FINAL FORM +FC6D ; mapped ; 0628 0646 # 1.1 ARABIC LIGATURE BEH WITH NOON FINAL FORM +FC6E ; mapped ; 0628 0649 # 1.1 ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM +FC6F ; mapped ; 0628 064A # 1.1 ARABIC LIGATURE BEH WITH YEH FINAL FORM +FC70 ; mapped ; 062A 0631 # 1.1 ARABIC LIGATURE TEH WITH REH FINAL FORM +FC71 ; mapped ; 062A 0632 # 1.1 ARABIC LIGATURE TEH WITH ZAIN FINAL FORM +FC72 ; mapped ; 062A 0645 # 1.1 ARABIC LIGATURE TEH WITH MEEM FINAL FORM +FC73 ; mapped ; 062A 0646 # 1.1 ARABIC LIGATURE TEH WITH NOON FINAL FORM +FC74 ; mapped ; 062A 0649 # 1.1 ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM +FC75 ; mapped ; 062A 064A # 1.1 ARABIC LIGATURE TEH WITH YEH FINAL FORM +FC76 ; mapped ; 062B 0631 # 1.1 ARABIC LIGATURE THEH WITH REH FINAL FORM +FC77 ; mapped ; 062B 0632 # 1.1 ARABIC LIGATURE THEH WITH ZAIN FINAL FORM +FC78 ; mapped ; 062B 0645 # 1.1 ARABIC LIGATURE THEH WITH MEEM FINAL FORM +FC79 ; mapped ; 062B 0646 # 1.1 ARABIC LIGATURE THEH WITH NOON FINAL FORM +FC7A ; mapped ; 062B 0649 # 1.1 ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM +FC7B ; mapped ; 062B 064A # 1.1 ARABIC LIGATURE THEH WITH YEH FINAL FORM +FC7C ; mapped ; 0641 0649 # 1.1 ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM +FC7D ; mapped ; 0641 064A # 1.1 ARABIC LIGATURE FEH WITH YEH FINAL FORM +FC7E ; mapped ; 0642 0649 # 1.1 ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM +FC7F ; mapped ; 0642 064A # 1.1 ARABIC LIGATURE QAF WITH YEH FINAL FORM +FC80 ; mapped ; 0643 0627 # 1.1 ARABIC LIGATURE KAF WITH ALEF FINAL FORM +FC81 ; mapped ; 0643 0644 # 1.1 ARABIC LIGATURE KAF WITH LAM FINAL FORM +FC82 ; mapped ; 0643 0645 # 1.1 ARABIC LIGATURE KAF WITH MEEM FINAL FORM +FC83 ; mapped ; 0643 0649 # 1.1 ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM +FC84 ; mapped ; 0643 064A # 1.1 ARABIC LIGATURE KAF WITH YEH FINAL FORM +FC85 ; mapped ; 0644 0645 # 1.1 ARABIC LIGATURE LAM WITH MEEM FINAL FORM +FC86 ; mapped ; 0644 0649 # 1.1 ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM +FC87 ; mapped ; 0644 064A # 1.1 ARABIC LIGATURE LAM WITH YEH FINAL FORM +FC88 ; mapped ; 0645 0627 # 1.1 ARABIC LIGATURE MEEM WITH ALEF FINAL FORM +FC89 ; mapped ; 0645 0645 # 1.1 ARABIC LIGATURE MEEM WITH MEEM FINAL FORM +FC8A ; mapped ; 0646 0631 # 1.1 ARABIC LIGATURE NOON WITH REH FINAL FORM +FC8B ; mapped ; 0646 0632 # 1.1 ARABIC LIGATURE NOON WITH ZAIN FINAL FORM +FC8C ; mapped ; 0646 0645 # 1.1 ARABIC LIGATURE NOON WITH MEEM FINAL FORM +FC8D ; mapped ; 0646 0646 # 1.1 ARABIC LIGATURE NOON WITH NOON FINAL FORM +FC8E ; mapped ; 0646 0649 # 1.1 ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM +FC8F ; mapped ; 0646 064A # 1.1 ARABIC LIGATURE NOON WITH YEH FINAL FORM +FC90 ; mapped ; 0649 0670 # 1.1 ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM +FC91 ; mapped ; 064A 0631 # 1.1 ARABIC LIGATURE YEH WITH REH FINAL FORM +FC92 ; mapped ; 064A 0632 # 1.1 ARABIC LIGATURE YEH WITH ZAIN FINAL FORM +FC93 ; mapped ; 064A 0645 # 1.1 ARABIC LIGATURE YEH WITH MEEM FINAL FORM +FC94 ; mapped ; 064A 0646 # 1.1 ARABIC LIGATURE YEH WITH NOON FINAL FORM +FC95 ; mapped ; 064A 0649 # 1.1 ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM +FC96 ; mapped ; 064A 064A # 1.1 ARABIC LIGATURE YEH WITH YEH FINAL FORM +FC97 ; mapped ; 0626 062C # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM +FC98 ; mapped ; 0626 062D # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM +FC99 ; mapped ; 0626 062E # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM +FC9A ; mapped ; 0626 0645 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM +FC9B ; mapped ; 0626 0647 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM +FC9C ; mapped ; 0628 062C # 1.1 ARABIC LIGATURE BEH WITH JEEM INITIAL FORM +FC9D ; mapped ; 0628 062D # 1.1 ARABIC LIGATURE BEH WITH HAH INITIAL FORM +FC9E ; mapped ; 0628 062E # 1.1 ARABIC LIGATURE BEH WITH KHAH INITIAL FORM +FC9F ; mapped ; 0628 0645 # 1.1 ARABIC LIGATURE BEH WITH MEEM INITIAL FORM +FCA0 ; mapped ; 0628 0647 # 1.1 ARABIC LIGATURE BEH WITH HEH INITIAL FORM +FCA1 ; mapped ; 062A 062C # 1.1 ARABIC LIGATURE TEH WITH JEEM INITIAL FORM +FCA2 ; mapped ; 062A 062D # 1.1 ARABIC LIGATURE TEH WITH HAH INITIAL FORM +FCA3 ; mapped ; 062A 062E # 1.1 ARABIC LIGATURE TEH WITH KHAH INITIAL FORM +FCA4 ; mapped ; 062A 0645 # 1.1 ARABIC LIGATURE TEH WITH MEEM INITIAL FORM +FCA5 ; mapped ; 062A 0647 # 1.1 ARABIC LIGATURE TEH WITH HEH INITIAL FORM +FCA6 ; mapped ; 062B 0645 # 1.1 ARABIC LIGATURE THEH WITH MEEM INITIAL FORM +FCA7 ; mapped ; 062C 062D # 1.1 ARABIC LIGATURE JEEM WITH HAH INITIAL FORM +FCA8 ; mapped ; 062C 0645 # 1.1 ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM +FCA9 ; mapped ; 062D 062C # 1.1 ARABIC LIGATURE HAH WITH JEEM INITIAL FORM +FCAA ; mapped ; 062D 0645 # 1.1 ARABIC LIGATURE HAH WITH MEEM INITIAL FORM +FCAB ; mapped ; 062E 062C # 1.1 ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM +FCAC ; mapped ; 062E 0645 # 1.1 ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM +FCAD ; mapped ; 0633 062C # 1.1 ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM +FCAE ; mapped ; 0633 062D # 1.1 ARABIC LIGATURE SEEN WITH HAH INITIAL FORM +FCAF ; mapped ; 0633 062E # 1.1 ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM +FCB0 ; mapped ; 0633 0645 # 1.1 ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM +FCB1 ; mapped ; 0635 062D # 1.1 ARABIC LIGATURE SAD WITH HAH INITIAL FORM +FCB2 ; mapped ; 0635 062E # 1.1 ARABIC LIGATURE SAD WITH KHAH INITIAL FORM +FCB3 ; mapped ; 0635 0645 # 1.1 ARABIC LIGATURE SAD WITH MEEM INITIAL FORM +FCB4 ; mapped ; 0636 062C # 1.1 ARABIC LIGATURE DAD WITH JEEM INITIAL FORM +FCB5 ; mapped ; 0636 062D # 1.1 ARABIC LIGATURE DAD WITH HAH INITIAL FORM +FCB6 ; mapped ; 0636 062E # 1.1 ARABIC LIGATURE DAD WITH KHAH INITIAL FORM +FCB7 ; mapped ; 0636 0645 # 1.1 ARABIC LIGATURE DAD WITH MEEM INITIAL FORM +FCB8 ; mapped ; 0637 062D # 1.1 ARABIC LIGATURE TAH WITH HAH INITIAL FORM +FCB9 ; mapped ; 0638 0645 # 1.1 ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM +FCBA ; mapped ; 0639 062C # 1.1 ARABIC LIGATURE AIN WITH JEEM INITIAL FORM +FCBB ; mapped ; 0639 0645 # 1.1 ARABIC LIGATURE AIN WITH MEEM INITIAL FORM +FCBC ; mapped ; 063A 062C # 1.1 ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM +FCBD ; mapped ; 063A 0645 # 1.1 ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM +FCBE ; mapped ; 0641 062C # 1.1 ARABIC LIGATURE FEH WITH JEEM INITIAL FORM +FCBF ; mapped ; 0641 062D # 1.1 ARABIC LIGATURE FEH WITH HAH INITIAL FORM +FCC0 ; mapped ; 0641 062E # 1.1 ARABIC LIGATURE FEH WITH KHAH INITIAL FORM +FCC1 ; mapped ; 0641 0645 # 1.1 ARABIC LIGATURE FEH WITH MEEM INITIAL FORM +FCC2 ; mapped ; 0642 062D # 1.1 ARABIC LIGATURE QAF WITH HAH INITIAL FORM +FCC3 ; mapped ; 0642 0645 # 1.1 ARABIC LIGATURE QAF WITH MEEM INITIAL FORM +FCC4 ; mapped ; 0643 062C # 1.1 ARABIC LIGATURE KAF WITH JEEM INITIAL FORM +FCC5 ; mapped ; 0643 062D # 1.1 ARABIC LIGATURE KAF WITH HAH INITIAL FORM +FCC6 ; mapped ; 0643 062E # 1.1 ARABIC LIGATURE KAF WITH KHAH INITIAL FORM +FCC7 ; mapped ; 0643 0644 # 1.1 ARABIC LIGATURE KAF WITH LAM INITIAL FORM +FCC8 ; mapped ; 0643 0645 # 1.1 ARABIC LIGATURE KAF WITH MEEM INITIAL FORM +FCC9 ; mapped ; 0644 062C # 1.1 ARABIC LIGATURE LAM WITH JEEM INITIAL FORM +FCCA ; mapped ; 0644 062D # 1.1 ARABIC LIGATURE LAM WITH HAH INITIAL FORM +FCCB ; mapped ; 0644 062E # 1.1 ARABIC LIGATURE LAM WITH KHAH INITIAL FORM +FCCC ; mapped ; 0644 0645 # 1.1 ARABIC LIGATURE LAM WITH MEEM INITIAL FORM +FCCD ; mapped ; 0644 0647 # 1.1 ARABIC LIGATURE LAM WITH HEH INITIAL FORM +FCCE ; mapped ; 0645 062C # 1.1 ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM +FCCF ; mapped ; 0645 062D # 1.1 ARABIC LIGATURE MEEM WITH HAH INITIAL FORM +FCD0 ; mapped ; 0645 062E # 1.1 ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM +FCD1 ; mapped ; 0645 0645 # 1.1 ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM +FCD2 ; mapped ; 0646 062C # 1.1 ARABIC LIGATURE NOON WITH JEEM INITIAL FORM +FCD3 ; mapped ; 0646 062D # 1.1 ARABIC LIGATURE NOON WITH HAH INITIAL FORM +FCD4 ; mapped ; 0646 062E # 1.1 ARABIC LIGATURE NOON WITH KHAH INITIAL FORM +FCD5 ; mapped ; 0646 0645 # 1.1 ARABIC LIGATURE NOON WITH MEEM INITIAL FORM +FCD6 ; mapped ; 0646 0647 # 1.1 ARABIC LIGATURE NOON WITH HEH INITIAL FORM +FCD7 ; mapped ; 0647 062C # 1.1 ARABIC LIGATURE HEH WITH JEEM INITIAL FORM +FCD8 ; mapped ; 0647 0645 # 1.1 ARABIC LIGATURE HEH WITH MEEM INITIAL FORM +FCD9 ; mapped ; 0647 0670 # 1.1 ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM +FCDA ; mapped ; 064A 062C # 1.1 ARABIC LIGATURE YEH WITH JEEM INITIAL FORM +FCDB ; mapped ; 064A 062D # 1.1 ARABIC LIGATURE YEH WITH HAH INITIAL FORM +FCDC ; mapped ; 064A 062E # 1.1 ARABIC LIGATURE YEH WITH KHAH INITIAL FORM +FCDD ; mapped ; 064A 0645 # 1.1 ARABIC LIGATURE YEH WITH MEEM INITIAL FORM +FCDE ; mapped ; 064A 0647 # 1.1 ARABIC LIGATURE YEH WITH HEH INITIAL FORM +FCDF ; mapped ; 0626 0645 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM +FCE0 ; mapped ; 0626 0647 # 1.1 ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM +FCE1 ; mapped ; 0628 0645 # 1.1 ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM +FCE2 ; mapped ; 0628 0647 # 1.1 ARABIC LIGATURE BEH WITH HEH MEDIAL FORM +FCE3 ; mapped ; 062A 0645 # 1.1 ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM +FCE4 ; mapped ; 062A 0647 # 1.1 ARABIC LIGATURE TEH WITH HEH MEDIAL FORM +FCE5 ; mapped ; 062B 0645 # 1.1 ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM +FCE6 ; mapped ; 062B 0647 # 1.1 ARABIC LIGATURE THEH WITH HEH MEDIAL FORM +FCE7 ; mapped ; 0633 0645 # 1.1 ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM +FCE8 ; mapped ; 0633 0647 # 1.1 ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM +FCE9 ; mapped ; 0634 0645 # 1.1 ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM +FCEA ; mapped ; 0634 0647 # 1.1 ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM +FCEB ; mapped ; 0643 0644 # 1.1 ARABIC LIGATURE KAF WITH LAM MEDIAL FORM +FCEC ; mapped ; 0643 0645 # 1.1 ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM +FCED ; mapped ; 0644 0645 # 1.1 ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM +FCEE ; mapped ; 0646 0645 # 1.1 ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM +FCEF ; mapped ; 0646 0647 # 1.1 ARABIC LIGATURE NOON WITH HEH MEDIAL FORM +FCF0 ; mapped ; 064A 0645 # 1.1 ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM +FCF1 ; mapped ; 064A 0647 # 1.1 ARABIC LIGATURE YEH WITH HEH MEDIAL FORM +FCF2 ; mapped ; 0640 064E 0651 #1.1 ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM +FCF3 ; mapped ; 0640 064F 0651 #1.1 ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM +FCF4 ; mapped ; 0640 0650 0651 #1.1 ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM +FCF5 ; mapped ; 0637 0649 # 1.1 ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM +FCF6 ; mapped ; 0637 064A # 1.1 ARABIC LIGATURE TAH WITH YEH ISOLATED FORM +FCF7 ; mapped ; 0639 0649 # 1.1 ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM +FCF8 ; mapped ; 0639 064A # 1.1 ARABIC LIGATURE AIN WITH YEH ISOLATED FORM +FCF9 ; mapped ; 063A 0649 # 1.1 ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM +FCFA ; mapped ; 063A 064A # 1.1 ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM +FCFB ; mapped ; 0633 0649 # 1.1 ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM +FCFC ; mapped ; 0633 064A # 1.1 ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM +FCFD ; mapped ; 0634 0649 # 1.1 ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM +FCFE ; mapped ; 0634 064A # 1.1 ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM +FCFF ; mapped ; 062D 0649 # 1.1 ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM +FD00 ; mapped ; 062D 064A # 1.1 ARABIC LIGATURE HAH WITH YEH ISOLATED FORM +FD01 ; mapped ; 062C 0649 # 1.1 ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM +FD02 ; mapped ; 062C 064A # 1.1 ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM +FD03 ; mapped ; 062E 0649 # 1.1 ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM +FD04 ; mapped ; 062E 064A # 1.1 ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM +FD05 ; mapped ; 0635 0649 # 1.1 ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM +FD06 ; mapped ; 0635 064A # 1.1 ARABIC LIGATURE SAD WITH YEH ISOLATED FORM +FD07 ; mapped ; 0636 0649 # 1.1 ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM +FD08 ; mapped ; 0636 064A # 1.1 ARABIC LIGATURE DAD WITH YEH ISOLATED FORM +FD09 ; mapped ; 0634 062C # 1.1 ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM +FD0A ; mapped ; 0634 062D # 1.1 ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM +FD0B ; mapped ; 0634 062E # 1.1 ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM +FD0C ; mapped ; 0634 0645 # 1.1 ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM +FD0D ; mapped ; 0634 0631 # 1.1 ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM +FD0E ; mapped ; 0633 0631 # 1.1 ARABIC LIGATURE SEEN WITH REH ISOLATED FORM +FD0F ; mapped ; 0635 0631 # 1.1 ARABIC LIGATURE SAD WITH REH ISOLATED FORM +FD10 ; mapped ; 0636 0631 # 1.1 ARABIC LIGATURE DAD WITH REH ISOLATED FORM +FD11 ; mapped ; 0637 0649 # 1.1 ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM +FD12 ; mapped ; 0637 064A # 1.1 ARABIC LIGATURE TAH WITH YEH FINAL FORM +FD13 ; mapped ; 0639 0649 # 1.1 ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM +FD14 ; mapped ; 0639 064A # 1.1 ARABIC LIGATURE AIN WITH YEH FINAL FORM +FD15 ; mapped ; 063A 0649 # 1.1 ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM +FD16 ; mapped ; 063A 064A # 1.1 ARABIC LIGATURE GHAIN WITH YEH FINAL FORM +FD17 ; mapped ; 0633 0649 # 1.1 ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM +FD18 ; mapped ; 0633 064A # 1.1 ARABIC LIGATURE SEEN WITH YEH FINAL FORM +FD19 ; mapped ; 0634 0649 # 1.1 ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM +FD1A ; mapped ; 0634 064A # 1.1 ARABIC LIGATURE SHEEN WITH YEH FINAL FORM +FD1B ; mapped ; 062D 0649 # 1.1 ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM +FD1C ; mapped ; 062D 064A # 1.1 ARABIC LIGATURE HAH WITH YEH FINAL FORM +FD1D ; mapped ; 062C 0649 # 1.1 ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM +FD1E ; mapped ; 062C 064A # 1.1 ARABIC LIGATURE JEEM WITH YEH FINAL FORM +FD1F ; mapped ; 062E 0649 # 1.1 ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM +FD20 ; mapped ; 062E 064A # 1.1 ARABIC LIGATURE KHAH WITH YEH FINAL FORM +FD21 ; mapped ; 0635 0649 # 1.1 ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM +FD22 ; mapped ; 0635 064A # 1.1 ARABIC LIGATURE SAD WITH YEH FINAL FORM +FD23 ; mapped ; 0636 0649 # 1.1 ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM +FD24 ; mapped ; 0636 064A # 1.1 ARABIC LIGATURE DAD WITH YEH FINAL FORM +FD25 ; mapped ; 0634 062C # 1.1 ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM +FD26 ; mapped ; 0634 062D # 1.1 ARABIC LIGATURE SHEEN WITH HAH FINAL FORM +FD27 ; mapped ; 0634 062E # 1.1 ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM +FD28 ; mapped ; 0634 0645 # 1.1 ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM +FD29 ; mapped ; 0634 0631 # 1.1 ARABIC LIGATURE SHEEN WITH REH FINAL FORM +FD2A ; mapped ; 0633 0631 # 1.1 ARABIC LIGATURE SEEN WITH REH FINAL FORM +FD2B ; mapped ; 0635 0631 # 1.1 ARABIC LIGATURE SAD WITH REH FINAL FORM +FD2C ; mapped ; 0636 0631 # 1.1 ARABIC LIGATURE DAD WITH REH FINAL FORM +FD2D ; mapped ; 0634 062C # 1.1 ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM +FD2E ; mapped ; 0634 062D # 1.1 ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM +FD2F ; mapped ; 0634 062E # 1.1 ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM +FD30 ; mapped ; 0634 0645 # 1.1 ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM +FD31 ; mapped ; 0633 0647 # 1.1 ARABIC LIGATURE SEEN WITH HEH INITIAL FORM +FD32 ; mapped ; 0634 0647 # 1.1 ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM +FD33 ; mapped ; 0637 0645 # 1.1 ARABIC LIGATURE TAH WITH MEEM INITIAL FORM +FD34 ; mapped ; 0633 062C # 1.1 ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM +FD35 ; mapped ; 0633 062D # 1.1 ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM +FD36 ; mapped ; 0633 062E # 1.1 ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM +FD37 ; mapped ; 0634 062C # 1.1 ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM +FD38 ; mapped ; 0634 062D # 1.1 ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM +FD39 ; mapped ; 0634 062E # 1.1 ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM +FD3A ; mapped ; 0637 0645 # 1.1 ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM +FD3B ; mapped ; 0638 0645 # 1.1 ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM +FD3C..FD3D ; mapped ; 0627 064B # 1.1 ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD3E..FD3F ; valid ; ; NV8 # 1.1 ORNATE LEFT PARENTHESIS..ORNATE RIGHT PARENTHESIS +FD40..FD4F ; disallowed # NA .. +FD50 ; mapped ; 062A 062C 0645 #1.1 ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM +FD51..FD52 ; mapped ; 062A 062D 062C #1.1 ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM..ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM +FD53 ; mapped ; 062A 062D 0645 #1.1 ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM +FD54 ; mapped ; 062A 062E 0645 #1.1 ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM +FD55 ; mapped ; 062A 0645 062C #1.1 ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM +FD56 ; mapped ; 062A 0645 062D #1.1 ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM +FD57 ; mapped ; 062A 0645 062E #1.1 ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM +FD58..FD59 ; mapped ; 062C 0645 062D #1.1 ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM..ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM +FD5A ; mapped ; 062D 0645 064A #1.1 ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM +FD5B ; mapped ; 062D 0645 0649 #1.1 ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD5C ; mapped ; 0633 062D 062C #1.1 ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM +FD5D ; mapped ; 0633 062C 062D #1.1 ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM +FD5E ; mapped ; 0633 062C 0649 #1.1 ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD5F..FD60 ; mapped ; 0633 0645 062D #1.1 ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM..ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM +FD61 ; mapped ; 0633 0645 062C #1.1 ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM +FD62..FD63 ; mapped ; 0633 0645 0645 #1.1 ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM..ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM +FD64..FD65 ; mapped ; 0635 062D 062D #1.1 ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM..ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM +FD66 ; mapped ; 0635 0645 0645 #1.1 ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM +FD67..FD68 ; mapped ; 0634 062D 0645 #1.1 ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM..ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM +FD69 ; mapped ; 0634 062C 064A #1.1 ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM +FD6A..FD6B ; mapped ; 0634 0645 062E #1.1 ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM..ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM +FD6C..FD6D ; mapped ; 0634 0645 0645 #1.1 ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM..ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM +FD6E ; mapped ; 0636 062D 0649 #1.1 ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM +FD6F..FD70 ; mapped ; 0636 062E 0645 #1.1 ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM..ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM +FD71..FD72 ; mapped ; 0637 0645 062D #1.1 ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM..ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM +FD73 ; mapped ; 0637 0645 0645 #1.1 ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM +FD74 ; mapped ; 0637 0645 064A #1.1 ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM +FD75 ; mapped ; 0639 062C 0645 #1.1 ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM +FD76..FD77 ; mapped ; 0639 0645 0645 #1.1 ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM..ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM +FD78 ; mapped ; 0639 0645 0649 #1.1 ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD79 ; mapped ; 063A 0645 0645 #1.1 ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM +FD7A ; mapped ; 063A 0645 064A #1.1 ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM +FD7B ; mapped ; 063A 0645 0649 #1.1 ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD7C..FD7D ; mapped ; 0641 062E 0645 #1.1 ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM..ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM +FD7E ; mapped ; 0642 0645 062D #1.1 ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM +FD7F ; mapped ; 0642 0645 0645 #1.1 ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM +FD80 ; mapped ; 0644 062D 0645 #1.1 ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM +FD81 ; mapped ; 0644 062D 064A #1.1 ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM +FD82 ; mapped ; 0644 062D 0649 #1.1 ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM +FD83..FD84 ; mapped ; 0644 062C 062C #1.1 ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM..ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM +FD85..FD86 ; mapped ; 0644 062E 0645 #1.1 ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM..ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM +FD87..FD88 ; mapped ; 0644 0645 062D #1.1 ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM..ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM +FD89 ; mapped ; 0645 062D 062C #1.1 ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM +FD8A ; mapped ; 0645 062D 0645 #1.1 ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM +FD8B ; mapped ; 0645 062D 064A #1.1 ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM +FD8C ; mapped ; 0645 062C 062D #1.1 ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM +FD8D ; mapped ; 0645 062C 0645 #1.1 ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM +FD8E ; mapped ; 0645 062E 062C #1.1 ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM +FD8F ; mapped ; 0645 062E 0645 #1.1 ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD90..FD91 ; disallowed # NA .. +FD92 ; mapped ; 0645 062C 062E #1.1 ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM +FD93 ; mapped ; 0647 0645 062C #1.1 ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM +FD94 ; mapped ; 0647 0645 0645 #1.1 ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM +FD95 ; mapped ; 0646 062D 0645 #1.1 ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM +FD96 ; mapped ; 0646 062D 0649 #1.1 ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM +FD97..FD98 ; mapped ; 0646 062C 0645 #1.1 ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM +FD99 ; mapped ; 0646 062C 0649 #1.1 ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD9A ; mapped ; 0646 0645 064A #1.1 ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM +FD9B ; mapped ; 0646 0645 0649 #1.1 ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD9C..FD9D ; mapped ; 064A 0645 0645 #1.1 ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM..ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM +FD9E ; mapped ; 0628 062E 064A #1.1 ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM +FD9F ; mapped ; 062A 062C 064A #1.1 ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM +FDA0 ; mapped ; 062A 062C 0649 #1.1 ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM +FDA1 ; mapped ; 062A 062E 064A #1.1 ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM +FDA2 ; mapped ; 062A 062E 0649 #1.1 ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA3 ; mapped ; 062A 0645 064A #1.1 ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM +FDA4 ; mapped ; 062A 0645 0649 #1.1 ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA5 ; mapped ; 062C 0645 064A #1.1 ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM +FDA6 ; mapped ; 062C 062D 0649 #1.1 ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM +FDA7 ; mapped ; 062C 0645 0649 #1.1 ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA8 ; mapped ; 0633 062E 0649 #1.1 ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA9 ; mapped ; 0635 062D 064A #1.1 ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM +FDAA ; mapped ; 0634 062D 064A #1.1 ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM +FDAB ; mapped ; 0636 062D 064A #1.1 ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM +FDAC ; mapped ; 0644 062C 064A #1.1 ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM +FDAD ; mapped ; 0644 0645 064A #1.1 ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM +FDAE ; mapped ; 064A 062D 064A #1.1 ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM +FDAF ; mapped ; 064A 062C 064A #1.1 ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM +FDB0 ; mapped ; 064A 0645 064A #1.1 ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM +FDB1 ; mapped ; 0645 0645 064A #1.1 ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM +FDB2 ; mapped ; 0642 0645 064A #1.1 ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM +FDB3 ; mapped ; 0646 062D 064A #1.1 ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM +FDB4 ; mapped ; 0642 0645 062D #1.1 ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM +FDB5 ; mapped ; 0644 062D 0645 #1.1 ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM +FDB6 ; mapped ; 0639 0645 064A #1.1 ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM +FDB7 ; mapped ; 0643 0645 064A #1.1 ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM +FDB8 ; mapped ; 0646 062C 062D #1.1 ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM +FDB9 ; mapped ; 0645 062E 064A #1.1 ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM +FDBA ; mapped ; 0644 062C 0645 #1.1 ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM +FDBB ; mapped ; 0643 0645 0645 #1.1 ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM +FDBC ; mapped ; 0644 062C 0645 #1.1 ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM +FDBD ; mapped ; 0646 062C 062D #1.1 ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM +FDBE ; mapped ; 062C 062D 064A #1.1 ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM +FDBF ; mapped ; 062D 062C 064A #1.1 ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM +FDC0 ; mapped ; 0645 062C 064A #1.1 ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM +FDC1 ; mapped ; 0641 0645 064A #1.1 ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM +FDC2 ; mapped ; 0628 062D 064A #1.1 ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM +FDC3 ; mapped ; 0643 0645 0645 #1.1 ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM +FDC4 ; mapped ; 0639 062C 0645 #1.1 ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM +FDC5 ; mapped ; 0635 0645 0645 #1.1 ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM +FDC6 ; mapped ; 0633 062E 064A #1.1 ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM +FDC7 ; mapped ; 0646 062C 064A #1.1 ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDC8..FDCF ; disallowed # NA .. +FDD0..FDEF ; disallowed # 3.1 .. +FDF0 ; mapped ; 0635 0644 06D2 #1.1 ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF1 ; mapped ; 0642 0644 06D2 #1.1 ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM +FDF2 ; mapped ; 0627 0644 0644 0647 #1.1 ARABIC LIGATURE ALLAH ISOLATED FORM +FDF3 ; mapped ; 0627 0643 0628 0631 #1.1 ARABIC LIGATURE AKBAR ISOLATED FORM +FDF4 ; mapped ; 0645 062D 0645 062F #1.1 ARABIC LIGATURE MOHAMMAD ISOLATED FORM +FDF5 ; mapped ; 0635 0644 0639 0645 #1.1 ARABIC LIGATURE SALAM ISOLATED FORM +FDF6 ; mapped ; 0631 0633 0648 0644 #1.1 ARABIC LIGATURE RASOUL ISOLATED FORM +FDF7 ; mapped ; 0639 0644 064A 0647 #1.1 ARABIC LIGATURE ALAYHE ISOLATED FORM +FDF8 ; mapped ; 0648 0633 0644 0645 #1.1 ARABIC LIGATURE WASALLAM ISOLATED FORM +FDF9 ; mapped ; 0635 0644 0649 #1.1 ARABIC LIGATURE SALLA ISOLATED FORM +FDFA ; disallowed_STD3_mapped ; 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645 #1.1 ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM +FDFB ; disallowed_STD3_mapped ; 062C 0644 0020 062C 0644 0627 0644 0647 #1.1 ARABIC LIGATURE JALLAJALALOUHOU +FDFC ; mapped ; 0631 06CC 0627 0644 #3.2 RIAL SIGN +FDFD ; valid ; ; NV8 # 4.0 ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +FDFE..FDFF ; disallowed # NA .. +FE00..FE0F ; ignored # 3.2 VARIATION SELECTOR-1..VARIATION SELECTOR-16 +FE10 ; disallowed_STD3_mapped ; 002C # 4.1 PRESENTATION FORM FOR VERTICAL COMMA +FE11 ; mapped ; 3001 # 4.1 PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA +FE12 ; disallowed # 4.1 PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE13 ; disallowed_STD3_mapped ; 003A # 4.1 PRESENTATION FORM FOR VERTICAL COLON +FE14 ; disallowed_STD3_mapped ; 003B # 4.1 PRESENTATION FORM FOR VERTICAL SEMICOLON +FE15 ; disallowed_STD3_mapped ; 0021 # 4.1 PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK +FE16 ; disallowed_STD3_mapped ; 003F # 4.1 PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE17 ; mapped ; 3016 # 4.1 PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET +FE18 ; mapped ; 3017 # 4.1 PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET +FE19 ; disallowed # 4.1 PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS +FE1A..FE1F ; disallowed # NA .. +FE20..FE23 ; valid # 1.1 COMBINING LIGATURE LEFT HALF..COMBINING DOUBLE TILDE RIGHT HALF +FE24..FE26 ; valid # 5.1 COMBINING MACRON LEFT HALF..COMBINING CONJOINING MACRON +FE27..FE2D ; valid # 7.0 COMBINING LIGATURE LEFT HALF BELOW..COMBINING CONJOINING MACRON BELOW +FE2E..FE2F ; valid # 8.0 COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF +FE30 ; disallowed # 1.1 PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31 ; mapped ; 2014 # 1.1 PRESENTATION FORM FOR VERTICAL EM DASH +FE32 ; mapped ; 2013 # 1.1 PRESENTATION FORM FOR VERTICAL EN DASH +FE33..FE34 ; disallowed_STD3_mapped ; 005F # 1.1 PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35 ; disallowed_STD3_mapped ; 0028 # 1.1 PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36 ; disallowed_STD3_mapped ; 0029 # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37 ; disallowed_STD3_mapped ; 007B # 1.1 PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38 ; disallowed_STD3_mapped ; 007D # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39 ; mapped ; 3014 # 1.1 PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A ; mapped ; 3015 # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B ; mapped ; 3010 # 1.1 PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C ; mapped ; 3011 # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D ; mapped ; 300A # 1.1 PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E ; mapped ; 300B # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F ; mapped ; 3008 # 1.1 PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40 ; mapped ; 3009 # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41 ; mapped ; 300C # 1.1 PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42 ; mapped ; 300D # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43 ; mapped ; 300E # 1.1 PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44 ; mapped ; 300F # 1.1 PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE45..FE46 ; valid ; ; NV8 # 3.2 SESAME DOT..WHITE SESAME DOT +FE47 ; disallowed_STD3_mapped ; 005B # 4.0 PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET +FE48 ; disallowed_STD3_mapped ; 005D # 4.0 PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET +FE49..FE4C ; disallowed_STD3_mapped ; 0020 0305 # 1.1 DASHED OVERLINE..DOUBLE WAVY OVERLINE +FE4D..FE4F ; disallowed_STD3_mapped ; 005F # 1.1 DASHED LOW LINE..WAVY LOW LINE +FE50 ; disallowed_STD3_mapped ; 002C # 1.1 SMALL COMMA +FE51 ; mapped ; 3001 # 1.1 SMALL IDEOGRAPHIC COMMA +FE52 ; disallowed # 1.1 SMALL FULL STOP +FE53 ; disallowed # NA +FE54 ; disallowed_STD3_mapped ; 003B # 1.1 SMALL SEMICOLON +FE55 ; disallowed_STD3_mapped ; 003A # 1.1 SMALL COLON +FE56 ; disallowed_STD3_mapped ; 003F # 1.1 SMALL QUESTION MARK +FE57 ; disallowed_STD3_mapped ; 0021 # 1.1 SMALL EXCLAMATION MARK +FE58 ; mapped ; 2014 # 1.1 SMALL EM DASH +FE59 ; disallowed_STD3_mapped ; 0028 # 1.1 SMALL LEFT PARENTHESIS +FE5A ; disallowed_STD3_mapped ; 0029 # 1.1 SMALL RIGHT PARENTHESIS +FE5B ; disallowed_STD3_mapped ; 007B # 1.1 SMALL LEFT CURLY BRACKET +FE5C ; disallowed_STD3_mapped ; 007D # 1.1 SMALL RIGHT CURLY BRACKET +FE5D ; mapped ; 3014 # 1.1 SMALL LEFT TORTOISE SHELL BRACKET +FE5E ; mapped ; 3015 # 1.1 SMALL RIGHT TORTOISE SHELL BRACKET +FE5F ; disallowed_STD3_mapped ; 0023 # 1.1 SMALL NUMBER SIGN +FE60 ; disallowed_STD3_mapped ; 0026 # 1.1 SMALL AMPERSAND +FE61 ; disallowed_STD3_mapped ; 002A # 1.1 SMALL ASTERISK +FE62 ; disallowed_STD3_mapped ; 002B # 1.1 SMALL PLUS SIGN +FE63 ; mapped ; 002D # 1.1 SMALL HYPHEN-MINUS +FE64 ; disallowed_STD3_mapped ; 003C # 1.1 SMALL LESS-THAN SIGN +FE65 ; disallowed_STD3_mapped ; 003E # 1.1 SMALL GREATER-THAN SIGN +FE66 ; disallowed_STD3_mapped ; 003D # 1.1 SMALL EQUALS SIGN +FE67 ; disallowed # NA +FE68 ; disallowed_STD3_mapped ; 005C # 1.1 SMALL REVERSE SOLIDUS +FE69 ; disallowed_STD3_mapped ; 0024 # 1.1 SMALL DOLLAR SIGN +FE6A ; disallowed_STD3_mapped ; 0025 # 1.1 SMALL PERCENT SIGN +FE6B ; disallowed_STD3_mapped ; 0040 # 1.1 SMALL COMMERCIAL AT +FE6C..FE6F ; disallowed # NA .. +FE70 ; disallowed_STD3_mapped ; 0020 064B # 1.1 ARABIC FATHATAN ISOLATED FORM +FE71 ; mapped ; 0640 064B # 1.1 ARABIC TATWEEL WITH FATHATAN ABOVE +FE72 ; disallowed_STD3_mapped ; 0020 064C # 1.1 ARABIC DAMMATAN ISOLATED FORM +FE73 ; valid # 3.2 ARABIC TAIL FRAGMENT +FE74 ; disallowed_STD3_mapped ; 0020 064D # 1.1 ARABIC KASRATAN ISOLATED FORM +FE75 ; disallowed # NA +FE76 ; disallowed_STD3_mapped ; 0020 064E # 1.1 ARABIC FATHA ISOLATED FORM +FE77 ; mapped ; 0640 064E # 1.1 ARABIC FATHA MEDIAL FORM +FE78 ; disallowed_STD3_mapped ; 0020 064F # 1.1 ARABIC DAMMA ISOLATED FORM +FE79 ; mapped ; 0640 064F # 1.1 ARABIC DAMMA MEDIAL FORM +FE7A ; disallowed_STD3_mapped ; 0020 0650 # 1.1 ARABIC KASRA ISOLATED FORM +FE7B ; mapped ; 0640 0650 # 1.1 ARABIC KASRA MEDIAL FORM +FE7C ; disallowed_STD3_mapped ; 0020 0651 # 1.1 ARABIC SHADDA ISOLATED FORM +FE7D ; mapped ; 0640 0651 # 1.1 ARABIC SHADDA MEDIAL FORM +FE7E ; disallowed_STD3_mapped ; 0020 0652 # 1.1 ARABIC SUKUN ISOLATED FORM +FE7F ; mapped ; 0640 0652 # 1.1 ARABIC SUKUN MEDIAL FORM +FE80 ; mapped ; 0621 # 1.1 ARABIC LETTER HAMZA ISOLATED FORM +FE81..FE82 ; mapped ; 0622 # 1.1 ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM..ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +FE83..FE84 ; mapped ; 0623 # 1.1 ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM..ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +FE85..FE86 ; mapped ; 0624 # 1.1 ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM..ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +FE87..FE88 ; mapped ; 0625 # 1.1 ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM..ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +FE89..FE8C ; mapped ; 0626 # 1.1 ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM..ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +FE8D..FE8E ; mapped ; 0627 # 1.1 ARABIC LETTER ALEF ISOLATED FORM..ARABIC LETTER ALEF FINAL FORM +FE8F..FE92 ; mapped ; 0628 # 1.1 ARABIC LETTER BEH ISOLATED FORM..ARABIC LETTER BEH MEDIAL FORM +FE93..FE94 ; mapped ; 0629 # 1.1 ARABIC LETTER TEH MARBUTA ISOLATED FORM..ARABIC LETTER TEH MARBUTA FINAL FORM +FE95..FE98 ; mapped ; 062A # 1.1 ARABIC LETTER TEH ISOLATED FORM..ARABIC LETTER TEH MEDIAL FORM +FE99..FE9C ; mapped ; 062B # 1.1 ARABIC LETTER THEH ISOLATED FORM..ARABIC LETTER THEH MEDIAL FORM +FE9D..FEA0 ; mapped ; 062C # 1.1 ARABIC LETTER JEEM ISOLATED FORM..ARABIC LETTER JEEM MEDIAL FORM +FEA1..FEA4 ; mapped ; 062D # 1.1 ARABIC LETTER HAH ISOLATED FORM..ARABIC LETTER HAH MEDIAL FORM +FEA5..FEA8 ; mapped ; 062E # 1.1 ARABIC LETTER KHAH ISOLATED FORM..ARABIC LETTER KHAH MEDIAL FORM +FEA9..FEAA ; mapped ; 062F # 1.1 ARABIC LETTER DAL ISOLATED FORM..ARABIC LETTER DAL FINAL FORM +FEAB..FEAC ; mapped ; 0630 # 1.1 ARABIC LETTER THAL ISOLATED FORM..ARABIC LETTER THAL FINAL FORM +FEAD..FEAE ; mapped ; 0631 # 1.1 ARABIC LETTER REH ISOLATED FORM..ARABIC LETTER REH FINAL FORM +FEAF..FEB0 ; mapped ; 0632 # 1.1 ARABIC LETTER ZAIN ISOLATED FORM..ARABIC LETTER ZAIN FINAL FORM +FEB1..FEB4 ; mapped ; 0633 # 1.1 ARABIC LETTER SEEN ISOLATED FORM..ARABIC LETTER SEEN MEDIAL FORM +FEB5..FEB8 ; mapped ; 0634 # 1.1 ARABIC LETTER SHEEN ISOLATED FORM..ARABIC LETTER SHEEN MEDIAL FORM +FEB9..FEBC ; mapped ; 0635 # 1.1 ARABIC LETTER SAD ISOLATED FORM..ARABIC LETTER SAD MEDIAL FORM +FEBD..FEC0 ; mapped ; 0636 # 1.1 ARABIC LETTER DAD ISOLATED FORM..ARABIC LETTER DAD MEDIAL FORM +FEC1..FEC4 ; mapped ; 0637 # 1.1 ARABIC LETTER TAH ISOLATED FORM..ARABIC LETTER TAH MEDIAL FORM +FEC5..FEC8 ; mapped ; 0638 # 1.1 ARABIC LETTER ZAH ISOLATED FORM..ARABIC LETTER ZAH MEDIAL FORM +FEC9..FECC ; mapped ; 0639 # 1.1 ARABIC LETTER AIN ISOLATED FORM..ARABIC LETTER AIN MEDIAL FORM +FECD..FED0 ; mapped ; 063A # 1.1 ARABIC LETTER GHAIN ISOLATED FORM..ARABIC LETTER GHAIN MEDIAL FORM +FED1..FED4 ; mapped ; 0641 # 1.1 ARABIC LETTER FEH ISOLATED FORM..ARABIC LETTER FEH MEDIAL FORM +FED5..FED8 ; mapped ; 0642 # 1.1 ARABIC LETTER QAF ISOLATED FORM..ARABIC LETTER QAF MEDIAL FORM +FED9..FEDC ; mapped ; 0643 # 1.1 ARABIC LETTER KAF ISOLATED FORM..ARABIC LETTER KAF MEDIAL FORM +FEDD..FEE0 ; mapped ; 0644 # 1.1 ARABIC LETTER LAM ISOLATED FORM..ARABIC LETTER LAM MEDIAL FORM +FEE1..FEE4 ; mapped ; 0645 # 1.1 ARABIC LETTER MEEM ISOLATED FORM..ARABIC LETTER MEEM MEDIAL FORM +FEE5..FEE8 ; mapped ; 0646 # 1.1 ARABIC LETTER NOON ISOLATED FORM..ARABIC LETTER NOON MEDIAL FORM +FEE9..FEEC ; mapped ; 0647 # 1.1 ARABIC LETTER HEH ISOLATED FORM..ARABIC LETTER HEH MEDIAL FORM +FEED..FEEE ; mapped ; 0648 # 1.1 ARABIC LETTER WAW ISOLATED FORM..ARABIC LETTER WAW FINAL FORM +FEEF..FEF0 ; mapped ; 0649 # 1.1 ARABIC LETTER ALEF MAKSURA ISOLATED FORM..ARABIC LETTER ALEF MAKSURA FINAL FORM +FEF1..FEF4 ; mapped ; 064A # 1.1 ARABIC LETTER YEH ISOLATED FORM..ARABIC LETTER YEH MEDIAL FORM +FEF5..FEF6 ; mapped ; 0644 0622 # 1.1 ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +FEF7..FEF8 ; mapped ; 0644 0623 # 1.1 ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +FEF9..FEFA ; mapped ; 0644 0625 # 1.1 ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +FEFB..FEFC ; mapped ; 0644 0627 # 1.1 ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FEFD..FEFE ; disallowed # NA .. +FEFF ; ignored # 1.1 ZERO WIDTH NO-BREAK SPACE +FF00 ; disallowed # NA +FF01 ; disallowed_STD3_mapped ; 0021 # 1.1 FULLWIDTH EXCLAMATION MARK +FF02 ; disallowed_STD3_mapped ; 0022 # 1.1 FULLWIDTH QUOTATION MARK +FF03 ; disallowed_STD3_mapped ; 0023 # 1.1 FULLWIDTH NUMBER SIGN +FF04 ; disallowed_STD3_mapped ; 0024 # 1.1 FULLWIDTH DOLLAR SIGN +FF05 ; disallowed_STD3_mapped ; 0025 # 1.1 FULLWIDTH PERCENT SIGN +FF06 ; disallowed_STD3_mapped ; 0026 # 1.1 FULLWIDTH AMPERSAND +FF07 ; disallowed_STD3_mapped ; 0027 # 1.1 FULLWIDTH APOSTROPHE +FF08 ; disallowed_STD3_mapped ; 0028 # 1.1 FULLWIDTH LEFT PARENTHESIS +FF09 ; disallowed_STD3_mapped ; 0029 # 1.1 FULLWIDTH RIGHT PARENTHESIS +FF0A ; disallowed_STD3_mapped ; 002A # 1.1 FULLWIDTH ASTERISK +FF0B ; disallowed_STD3_mapped ; 002B # 1.1 FULLWIDTH PLUS SIGN +FF0C ; disallowed_STD3_mapped ; 002C # 1.1 FULLWIDTH COMMA +FF0D ; mapped ; 002D # 1.1 FULLWIDTH HYPHEN-MINUS +FF0E ; mapped ; 002E # 1.1 FULLWIDTH FULL STOP +FF0F ; disallowed_STD3_mapped ; 002F # 1.1 FULLWIDTH SOLIDUS +FF10 ; mapped ; 0030 # 1.1 FULLWIDTH DIGIT ZERO +FF11 ; mapped ; 0031 # 1.1 FULLWIDTH DIGIT ONE +FF12 ; mapped ; 0032 # 1.1 FULLWIDTH DIGIT TWO +FF13 ; mapped ; 0033 # 1.1 FULLWIDTH DIGIT THREE +FF14 ; mapped ; 0034 # 1.1 FULLWIDTH DIGIT FOUR +FF15 ; mapped ; 0035 # 1.1 FULLWIDTH DIGIT FIVE +FF16 ; mapped ; 0036 # 1.1 FULLWIDTH DIGIT SIX +FF17 ; mapped ; 0037 # 1.1 FULLWIDTH DIGIT SEVEN +FF18 ; mapped ; 0038 # 1.1 FULLWIDTH DIGIT EIGHT +FF19 ; mapped ; 0039 # 1.1 FULLWIDTH DIGIT NINE +FF1A ; disallowed_STD3_mapped ; 003A # 1.1 FULLWIDTH COLON +FF1B ; disallowed_STD3_mapped ; 003B # 1.1 FULLWIDTH SEMICOLON +FF1C ; disallowed_STD3_mapped ; 003C # 1.1 FULLWIDTH LESS-THAN SIGN +FF1D ; disallowed_STD3_mapped ; 003D # 1.1 FULLWIDTH EQUALS SIGN +FF1E ; disallowed_STD3_mapped ; 003E # 1.1 FULLWIDTH GREATER-THAN SIGN +FF1F ; disallowed_STD3_mapped ; 003F # 1.1 FULLWIDTH QUESTION MARK +FF20 ; disallowed_STD3_mapped ; 0040 # 1.1 FULLWIDTH COMMERCIAL AT +FF21 ; mapped ; 0061 # 1.1 FULLWIDTH LATIN CAPITAL LETTER A +FF22 ; mapped ; 0062 # 1.1 FULLWIDTH LATIN CAPITAL LETTER B +FF23 ; mapped ; 0063 # 1.1 FULLWIDTH LATIN CAPITAL LETTER C +FF24 ; mapped ; 0064 # 1.1 FULLWIDTH LATIN CAPITAL LETTER D +FF25 ; mapped ; 0065 # 1.1 FULLWIDTH LATIN CAPITAL LETTER E +FF26 ; mapped ; 0066 # 1.1 FULLWIDTH LATIN CAPITAL LETTER F +FF27 ; mapped ; 0067 # 1.1 FULLWIDTH LATIN CAPITAL LETTER G +FF28 ; mapped ; 0068 # 1.1 FULLWIDTH LATIN CAPITAL LETTER H +FF29 ; mapped ; 0069 # 1.1 FULLWIDTH LATIN CAPITAL LETTER I +FF2A ; mapped ; 006A # 1.1 FULLWIDTH LATIN CAPITAL LETTER J +FF2B ; mapped ; 006B # 1.1 FULLWIDTH LATIN CAPITAL LETTER K +FF2C ; mapped ; 006C # 1.1 FULLWIDTH LATIN CAPITAL LETTER L +FF2D ; mapped ; 006D # 1.1 FULLWIDTH LATIN CAPITAL LETTER M +FF2E ; mapped ; 006E # 1.1 FULLWIDTH LATIN CAPITAL LETTER N +FF2F ; mapped ; 006F # 1.1 FULLWIDTH LATIN CAPITAL LETTER O +FF30 ; mapped ; 0070 # 1.1 FULLWIDTH LATIN CAPITAL LETTER P +FF31 ; mapped ; 0071 # 1.1 FULLWIDTH LATIN CAPITAL LETTER Q +FF32 ; mapped ; 0072 # 1.1 FULLWIDTH LATIN CAPITAL LETTER R +FF33 ; mapped ; 0073 # 1.1 FULLWIDTH LATIN CAPITAL LETTER S +FF34 ; mapped ; 0074 # 1.1 FULLWIDTH LATIN CAPITAL LETTER T +FF35 ; mapped ; 0075 # 1.1 FULLWIDTH LATIN CAPITAL LETTER U +FF36 ; mapped ; 0076 # 1.1 FULLWIDTH LATIN CAPITAL LETTER V +FF37 ; mapped ; 0077 # 1.1 FULLWIDTH LATIN CAPITAL LETTER W +FF38 ; mapped ; 0078 # 1.1 FULLWIDTH LATIN CAPITAL LETTER X +FF39 ; mapped ; 0079 # 1.1 FULLWIDTH LATIN CAPITAL LETTER Y +FF3A ; mapped ; 007A # 1.1 FULLWIDTH LATIN CAPITAL LETTER Z +FF3B ; disallowed_STD3_mapped ; 005B # 1.1 FULLWIDTH LEFT SQUARE BRACKET +FF3C ; disallowed_STD3_mapped ; 005C # 1.1 FULLWIDTH REVERSE SOLIDUS +FF3D ; disallowed_STD3_mapped ; 005D # 1.1 FULLWIDTH RIGHT SQUARE BRACKET +FF3E ; disallowed_STD3_mapped ; 005E # 1.1 FULLWIDTH CIRCUMFLEX ACCENT +FF3F ; disallowed_STD3_mapped ; 005F # 1.1 FULLWIDTH LOW LINE +FF40 ; disallowed_STD3_mapped ; 0060 # 1.1 FULLWIDTH GRAVE ACCENT +FF41 ; mapped ; 0061 # 1.1 FULLWIDTH LATIN SMALL LETTER A +FF42 ; mapped ; 0062 # 1.1 FULLWIDTH LATIN SMALL LETTER B +FF43 ; mapped ; 0063 # 1.1 FULLWIDTH LATIN SMALL LETTER C +FF44 ; mapped ; 0064 # 1.1 FULLWIDTH LATIN SMALL LETTER D +FF45 ; mapped ; 0065 # 1.1 FULLWIDTH LATIN SMALL LETTER E +FF46 ; mapped ; 0066 # 1.1 FULLWIDTH LATIN SMALL LETTER F +FF47 ; mapped ; 0067 # 1.1 FULLWIDTH LATIN SMALL LETTER G +FF48 ; mapped ; 0068 # 1.1 FULLWIDTH LATIN SMALL LETTER H +FF49 ; mapped ; 0069 # 1.1 FULLWIDTH LATIN SMALL LETTER I +FF4A ; mapped ; 006A # 1.1 FULLWIDTH LATIN SMALL LETTER J +FF4B ; mapped ; 006B # 1.1 FULLWIDTH LATIN SMALL LETTER K +FF4C ; mapped ; 006C # 1.1 FULLWIDTH LATIN SMALL LETTER L +FF4D ; mapped ; 006D # 1.1 FULLWIDTH LATIN SMALL LETTER M +FF4E ; mapped ; 006E # 1.1 FULLWIDTH LATIN SMALL LETTER N +FF4F ; mapped ; 006F # 1.1 FULLWIDTH LATIN SMALL LETTER O +FF50 ; mapped ; 0070 # 1.1 FULLWIDTH LATIN SMALL LETTER P +FF51 ; mapped ; 0071 # 1.1 FULLWIDTH LATIN SMALL LETTER Q +FF52 ; mapped ; 0072 # 1.1 FULLWIDTH LATIN SMALL LETTER R +FF53 ; mapped ; 0073 # 1.1 FULLWIDTH LATIN SMALL LETTER S +FF54 ; mapped ; 0074 # 1.1 FULLWIDTH LATIN SMALL LETTER T +FF55 ; mapped ; 0075 # 1.1 FULLWIDTH LATIN SMALL LETTER U +FF56 ; mapped ; 0076 # 1.1 FULLWIDTH LATIN SMALL LETTER V +FF57 ; mapped ; 0077 # 1.1 FULLWIDTH LATIN SMALL LETTER W +FF58 ; mapped ; 0078 # 1.1 FULLWIDTH LATIN SMALL LETTER X +FF59 ; mapped ; 0079 # 1.1 FULLWIDTH LATIN SMALL LETTER Y +FF5A ; mapped ; 007A # 1.1 FULLWIDTH LATIN SMALL LETTER Z +FF5B ; disallowed_STD3_mapped ; 007B # 1.1 FULLWIDTH LEFT CURLY BRACKET +FF5C ; disallowed_STD3_mapped ; 007C # 1.1 FULLWIDTH VERTICAL LINE +FF5D ; disallowed_STD3_mapped ; 007D # 1.1 FULLWIDTH RIGHT CURLY BRACKET +FF5E ; disallowed_STD3_mapped ; 007E # 1.1 FULLWIDTH TILDE +FF5F ; mapped ; 2985 # 3.2 FULLWIDTH LEFT WHITE PARENTHESIS +FF60 ; mapped ; 2986 # 3.2 FULLWIDTH RIGHT WHITE PARENTHESIS +FF61 ; mapped ; 002E # 1.1 HALFWIDTH IDEOGRAPHIC FULL STOP +FF62 ; mapped ; 300C # 1.1 HALFWIDTH LEFT CORNER BRACKET +FF63 ; mapped ; 300D # 1.1 HALFWIDTH RIGHT CORNER BRACKET +FF64 ; mapped ; 3001 # 1.1 HALFWIDTH IDEOGRAPHIC COMMA +FF65 ; mapped ; 30FB # 1.1 HALFWIDTH KATAKANA MIDDLE DOT +FF66 ; mapped ; 30F2 # 1.1 HALFWIDTH KATAKANA LETTER WO +FF67 ; mapped ; 30A1 # 1.1 HALFWIDTH KATAKANA LETTER SMALL A +FF68 ; mapped ; 30A3 # 1.1 HALFWIDTH KATAKANA LETTER SMALL I +FF69 ; mapped ; 30A5 # 1.1 HALFWIDTH KATAKANA LETTER SMALL U +FF6A ; mapped ; 30A7 # 1.1 HALFWIDTH KATAKANA LETTER SMALL E +FF6B ; mapped ; 30A9 # 1.1 HALFWIDTH KATAKANA LETTER SMALL O +FF6C ; mapped ; 30E3 # 1.1 HALFWIDTH KATAKANA LETTER SMALL YA +FF6D ; mapped ; 30E5 # 1.1 HALFWIDTH KATAKANA LETTER SMALL YU +FF6E ; mapped ; 30E7 # 1.1 HALFWIDTH KATAKANA LETTER SMALL YO +FF6F ; mapped ; 30C3 # 1.1 HALFWIDTH KATAKANA LETTER SMALL TU +FF70 ; mapped ; 30FC # 1.1 HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF71 ; mapped ; 30A2 # 1.1 HALFWIDTH KATAKANA LETTER A +FF72 ; mapped ; 30A4 # 1.1 HALFWIDTH KATAKANA LETTER I +FF73 ; mapped ; 30A6 # 1.1 HALFWIDTH KATAKANA LETTER U +FF74 ; mapped ; 30A8 # 1.1 HALFWIDTH KATAKANA LETTER E +FF75 ; mapped ; 30AA # 1.1 HALFWIDTH KATAKANA LETTER O +FF76 ; mapped ; 30AB # 1.1 HALFWIDTH KATAKANA LETTER KA +FF77 ; mapped ; 30AD # 1.1 HALFWIDTH KATAKANA LETTER KI +FF78 ; mapped ; 30AF # 1.1 HALFWIDTH KATAKANA LETTER KU +FF79 ; mapped ; 30B1 # 1.1 HALFWIDTH KATAKANA LETTER KE +FF7A ; mapped ; 30B3 # 1.1 HALFWIDTH KATAKANA LETTER KO +FF7B ; mapped ; 30B5 # 1.1 HALFWIDTH KATAKANA LETTER SA +FF7C ; mapped ; 30B7 # 1.1 HALFWIDTH KATAKANA LETTER SI +FF7D ; mapped ; 30B9 # 1.1 HALFWIDTH KATAKANA LETTER SU +FF7E ; mapped ; 30BB # 1.1 HALFWIDTH KATAKANA LETTER SE +FF7F ; mapped ; 30BD # 1.1 HALFWIDTH KATAKANA LETTER SO +FF80 ; mapped ; 30BF # 1.1 HALFWIDTH KATAKANA LETTER TA +FF81 ; mapped ; 30C1 # 1.1 HALFWIDTH KATAKANA LETTER TI +FF82 ; mapped ; 30C4 # 1.1 HALFWIDTH KATAKANA LETTER TU +FF83 ; mapped ; 30C6 # 1.1 HALFWIDTH KATAKANA LETTER TE +FF84 ; mapped ; 30C8 # 1.1 HALFWIDTH KATAKANA LETTER TO +FF85 ; mapped ; 30CA # 1.1 HALFWIDTH KATAKANA LETTER NA +FF86 ; mapped ; 30CB # 1.1 HALFWIDTH KATAKANA LETTER NI +FF87 ; mapped ; 30CC # 1.1 HALFWIDTH KATAKANA LETTER NU +FF88 ; mapped ; 30CD # 1.1 HALFWIDTH KATAKANA LETTER NE +FF89 ; mapped ; 30CE # 1.1 HALFWIDTH KATAKANA LETTER NO +FF8A ; mapped ; 30CF # 1.1 HALFWIDTH KATAKANA LETTER HA +FF8B ; mapped ; 30D2 # 1.1 HALFWIDTH KATAKANA LETTER HI +FF8C ; mapped ; 30D5 # 1.1 HALFWIDTH KATAKANA LETTER HU +FF8D ; mapped ; 30D8 # 1.1 HALFWIDTH KATAKANA LETTER HE +FF8E ; mapped ; 30DB # 1.1 HALFWIDTH KATAKANA LETTER HO +FF8F ; mapped ; 30DE # 1.1 HALFWIDTH KATAKANA LETTER MA +FF90 ; mapped ; 30DF # 1.1 HALFWIDTH KATAKANA LETTER MI +FF91 ; mapped ; 30E0 # 1.1 HALFWIDTH KATAKANA LETTER MU +FF92 ; mapped ; 30E1 # 1.1 HALFWIDTH KATAKANA LETTER ME +FF93 ; mapped ; 30E2 # 1.1 HALFWIDTH KATAKANA LETTER MO +FF94 ; mapped ; 30E4 # 1.1 HALFWIDTH KATAKANA LETTER YA +FF95 ; mapped ; 30E6 # 1.1 HALFWIDTH KATAKANA LETTER YU +FF96 ; mapped ; 30E8 # 1.1 HALFWIDTH KATAKANA LETTER YO +FF97 ; mapped ; 30E9 # 1.1 HALFWIDTH KATAKANA LETTER RA +FF98 ; mapped ; 30EA # 1.1 HALFWIDTH KATAKANA LETTER RI +FF99 ; mapped ; 30EB # 1.1 HALFWIDTH KATAKANA LETTER RU +FF9A ; mapped ; 30EC # 1.1 HALFWIDTH KATAKANA LETTER RE +FF9B ; mapped ; 30ED # 1.1 HALFWIDTH KATAKANA LETTER RO +FF9C ; mapped ; 30EF # 1.1 HALFWIDTH KATAKANA LETTER WA +FF9D ; mapped ; 30F3 # 1.1 HALFWIDTH KATAKANA LETTER N +FF9E ; mapped ; 3099 # 1.1 HALFWIDTH KATAKANA VOICED SOUND MARK +FF9F ; mapped ; 309A # 1.1 HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +FFA0 ; disallowed # 1.1 HALFWIDTH HANGUL FILLER +FFA1 ; mapped ; 1100 # 1.1 HALFWIDTH HANGUL LETTER KIYEOK +FFA2 ; mapped ; 1101 # 1.1 HALFWIDTH HANGUL LETTER SSANGKIYEOK +FFA3 ; mapped ; 11AA # 1.1 HALFWIDTH HANGUL LETTER KIYEOK-SIOS +FFA4 ; mapped ; 1102 # 1.1 HALFWIDTH HANGUL LETTER NIEUN +FFA5 ; mapped ; 11AC # 1.1 HALFWIDTH HANGUL LETTER NIEUN-CIEUC +FFA6 ; mapped ; 11AD # 1.1 HALFWIDTH HANGUL LETTER NIEUN-HIEUH +FFA7 ; mapped ; 1103 # 1.1 HALFWIDTH HANGUL LETTER TIKEUT +FFA8 ; mapped ; 1104 # 1.1 HALFWIDTH HANGUL LETTER SSANGTIKEUT +FFA9 ; mapped ; 1105 # 1.1 HALFWIDTH HANGUL LETTER RIEUL +FFAA ; mapped ; 11B0 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-KIYEOK +FFAB ; mapped ; 11B1 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-MIEUM +FFAC ; mapped ; 11B2 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-PIEUP +FFAD ; mapped ; 11B3 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-SIOS +FFAE ; mapped ; 11B4 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-THIEUTH +FFAF ; mapped ; 11B5 # 1.1 HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH +FFB0 ; mapped ; 111A # 1.1 HALFWIDTH HANGUL LETTER RIEUL-HIEUH +FFB1 ; mapped ; 1106 # 1.1 HALFWIDTH HANGUL LETTER MIEUM +FFB2 ; mapped ; 1107 # 1.1 HALFWIDTH HANGUL LETTER PIEUP +FFB3 ; mapped ; 1108 # 1.1 HALFWIDTH HANGUL LETTER SSANGPIEUP +FFB4 ; mapped ; 1121 # 1.1 HALFWIDTH HANGUL LETTER PIEUP-SIOS +FFB5 ; mapped ; 1109 # 1.1 HALFWIDTH HANGUL LETTER SIOS +FFB6 ; mapped ; 110A # 1.1 HALFWIDTH HANGUL LETTER SSANGSIOS +FFB7 ; mapped ; 110B # 1.1 HALFWIDTH HANGUL LETTER IEUNG +FFB8 ; mapped ; 110C # 1.1 HALFWIDTH HANGUL LETTER CIEUC +FFB9 ; mapped ; 110D # 1.1 HALFWIDTH HANGUL LETTER SSANGCIEUC +FFBA ; mapped ; 110E # 1.1 HALFWIDTH HANGUL LETTER CHIEUCH +FFBB ; mapped ; 110F # 1.1 HALFWIDTH HANGUL LETTER KHIEUKH +FFBC ; mapped ; 1110 # 1.1 HALFWIDTH HANGUL LETTER THIEUTH +FFBD ; mapped ; 1111 # 1.1 HALFWIDTH HANGUL LETTER PHIEUPH +FFBE ; mapped ; 1112 # 1.1 HALFWIDTH HANGUL LETTER HIEUH +FFBF..FFC1 ; disallowed # NA .. +FFC2 ; mapped ; 1161 # 1.1 HALFWIDTH HANGUL LETTER A +FFC3 ; mapped ; 1162 # 1.1 HALFWIDTH HANGUL LETTER AE +FFC4 ; mapped ; 1163 # 1.1 HALFWIDTH HANGUL LETTER YA +FFC5 ; mapped ; 1164 # 1.1 HALFWIDTH HANGUL LETTER YAE +FFC6 ; mapped ; 1165 # 1.1 HALFWIDTH HANGUL LETTER EO +FFC7 ; mapped ; 1166 # 1.1 HALFWIDTH HANGUL LETTER E +FFC8..FFC9 ; disallowed # NA .. +FFCA ; mapped ; 1167 # 1.1 HALFWIDTH HANGUL LETTER YEO +FFCB ; mapped ; 1168 # 1.1 HALFWIDTH HANGUL LETTER YE +FFCC ; mapped ; 1169 # 1.1 HALFWIDTH HANGUL LETTER O +FFCD ; mapped ; 116A # 1.1 HALFWIDTH HANGUL LETTER WA +FFCE ; mapped ; 116B # 1.1 HALFWIDTH HANGUL LETTER WAE +FFCF ; mapped ; 116C # 1.1 HALFWIDTH HANGUL LETTER OE +FFD0..FFD1 ; disallowed # NA .. +FFD2 ; mapped ; 116D # 1.1 HALFWIDTH HANGUL LETTER YO +FFD3 ; mapped ; 116E # 1.1 HALFWIDTH HANGUL LETTER U +FFD4 ; mapped ; 116F # 1.1 HALFWIDTH HANGUL LETTER WEO +FFD5 ; mapped ; 1170 # 1.1 HALFWIDTH HANGUL LETTER WE +FFD6 ; mapped ; 1171 # 1.1 HALFWIDTH HANGUL LETTER WI +FFD7 ; mapped ; 1172 # 1.1 HALFWIDTH HANGUL LETTER YU +FFD8..FFD9 ; disallowed # NA .. +FFDA ; mapped ; 1173 # 1.1 HALFWIDTH HANGUL LETTER EU +FFDB ; mapped ; 1174 # 1.1 HALFWIDTH HANGUL LETTER YI +FFDC ; mapped ; 1175 # 1.1 HALFWIDTH HANGUL LETTER I +FFDD..FFDF ; disallowed # NA .. +FFE0 ; mapped ; 00A2 # 1.1 FULLWIDTH CENT SIGN +FFE1 ; mapped ; 00A3 # 1.1 FULLWIDTH POUND SIGN +FFE2 ; mapped ; 00AC # 1.1 FULLWIDTH NOT SIGN +FFE3 ; disallowed_STD3_mapped ; 0020 0304 # 1.1 FULLWIDTH MACRON +FFE4 ; mapped ; 00A6 # 1.1 FULLWIDTH BROKEN BAR +FFE5 ; mapped ; 00A5 # 1.1 FULLWIDTH YEN SIGN +FFE6 ; mapped ; 20A9 # 1.1 FULLWIDTH WON SIGN +FFE7 ; disallowed # NA +FFE8 ; mapped ; 2502 # 1.1 HALFWIDTH FORMS LIGHT VERTICAL +FFE9 ; mapped ; 2190 # 1.1 HALFWIDTH LEFTWARDS ARROW +FFEA ; mapped ; 2191 # 1.1 HALFWIDTH UPWARDS ARROW +FFEB ; mapped ; 2192 # 1.1 HALFWIDTH RIGHTWARDS ARROW +FFEC ; mapped ; 2193 # 1.1 HALFWIDTH DOWNWARDS ARROW +FFED ; mapped ; 25A0 # 1.1 HALFWIDTH BLACK SQUARE +FFEE ; mapped ; 25CB # 1.1 HALFWIDTH WHITE CIRCLE +FFEF..FFF8 ; disallowed # NA .. +FFF9..FFFB ; disallowed # 3.0 INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR +FFFC ; disallowed # 2.1 OBJECT REPLACEMENT CHARACTER +FFFD ; disallowed # 1.1 REPLACEMENT CHARACTER +FFFE..FFFF ; disallowed # 1.1 .. +10000..1000B ; valid # 4.0 LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE +1000C ; disallowed # NA +1000D..10026 ; valid # 4.0 LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO +10027 ; disallowed # NA +10028..1003A ; valid # 4.0 LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO +1003B ; disallowed # NA +1003C..1003D ; valid # 4.0 LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE +1003E ; disallowed # NA +1003F..1004D ; valid # 4.0 LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO +1004E..1004F ; disallowed # NA .. +10050..1005D ; valid # 4.0 LINEAR B SYMBOL B018..LINEAR B SYMBOL B089 +1005E..1007F ; disallowed # NA .. +10080..100FA ; valid # 4.0 LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305 +100FB..100FF ; disallowed # NA .. +10100..10102 ; valid ; ; NV8 # 4.0 AEGEAN WORD SEPARATOR LINE..AEGEAN CHECK MARK +10103..10106 ; disallowed # NA .. +10107..10133 ; valid ; ; NV8 # 4.0 AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND +10134..10136 ; disallowed # NA .. +10137..1013F ; valid ; ; NV8 # 4.0 AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT +10140..1018A ; valid ; ; NV8 # 4.1 GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ZERO SIGN +1018B..1018C ; valid ; ; NV8 # 7.0 GREEK ONE QUARTER SIGN..GREEK SINUSOID SIGN +1018D..1018E ; valid ; ; NV8 # 9.0 GREEK INDICTION SIGN..NOMISMA SIGN +1018F ; disallowed # NA +10190..1019B ; valid ; ; NV8 # 5.1 ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN +1019C..1019F ; disallowed # NA .. +101A0 ; valid ; ; NV8 # 7.0 GREEK SYMBOL TAU RHO +101A1..101CF ; disallowed # NA .. +101D0..101FC ; valid ; ; NV8 # 5.1 PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND +101FD ; valid # 5.1 PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +101FE..1027F ; disallowed # NA .. +10280..1029C ; valid # 5.1 LYCIAN LETTER A..LYCIAN LETTER X +1029D..1029F ; disallowed # NA .. +102A0..102D0 ; valid # 5.1 CARIAN LETTER A..CARIAN LETTER UUU3 +102D1..102DF ; disallowed # NA .. +102E0 ; valid # 7.0 COPTIC EPACT THOUSANDS MARK +102E1..102FB ; valid ; ; NV8 # 7.0 COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED +102FC..102FF ; disallowed # NA .. +10300..1031E ; valid # 3.1 OLD ITALIC LETTER A..OLD ITALIC LETTER UU +1031F ; valid # 7.0 OLD ITALIC LETTER ESS +10320..10323 ; valid ; ; NV8 # 3.1 OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +10324..1032C ; disallowed # NA .. +1032D..1032F ; valid # 10.0 OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE +10330..10340 ; valid # 3.1 GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +10341 ; valid ; ; NV8 # 3.1 GOTHIC LETTER NINETY +10342..10349 ; valid # 3.1 GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL +1034A ; valid ; ; NV8 # 3.1 GOTHIC LETTER NINE HUNDRED +1034B..1034F ; disallowed # NA .. +10350..1037A ; valid # 7.0 OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII +1037B..1037F ; disallowed # NA .. +10380..1039D ; valid # 4.0 UGARITIC LETTER ALPA..UGARITIC LETTER SSU +1039E ; disallowed # NA +1039F ; valid ; ; NV8 # 4.0 UGARITIC WORD DIVIDER +103A0..103C3 ; valid # 4.1 OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA +103C4..103C7 ; disallowed # NA .. +103C8..103CF ; valid # 4.1 OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH +103D0..103D5 ; valid ; ; NV8 # 4.1 OLD PERSIAN WORD DIVIDER..OLD PERSIAN NUMBER HUNDRED +103D6..103FF ; disallowed # NA .. +10400 ; mapped ; 10428 # 3.1 DESERET CAPITAL LETTER LONG I +10401 ; mapped ; 10429 # 3.1 DESERET CAPITAL LETTER LONG E +10402 ; mapped ; 1042A # 3.1 DESERET CAPITAL LETTER LONG A +10403 ; mapped ; 1042B # 3.1 DESERET CAPITAL LETTER LONG AH +10404 ; mapped ; 1042C # 3.1 DESERET CAPITAL LETTER LONG O +10405 ; mapped ; 1042D # 3.1 DESERET CAPITAL LETTER LONG OO +10406 ; mapped ; 1042E # 3.1 DESERET CAPITAL LETTER SHORT I +10407 ; mapped ; 1042F # 3.1 DESERET CAPITAL LETTER SHORT E +10408 ; mapped ; 10430 # 3.1 DESERET CAPITAL LETTER SHORT A +10409 ; mapped ; 10431 # 3.1 DESERET CAPITAL LETTER SHORT AH +1040A ; mapped ; 10432 # 3.1 DESERET CAPITAL LETTER SHORT O +1040B ; mapped ; 10433 # 3.1 DESERET CAPITAL LETTER SHORT OO +1040C ; mapped ; 10434 # 3.1 DESERET CAPITAL LETTER AY +1040D ; mapped ; 10435 # 3.1 DESERET CAPITAL LETTER OW +1040E ; mapped ; 10436 # 3.1 DESERET CAPITAL LETTER WU +1040F ; mapped ; 10437 # 3.1 DESERET CAPITAL LETTER YEE +10410 ; mapped ; 10438 # 3.1 DESERET CAPITAL LETTER H +10411 ; mapped ; 10439 # 3.1 DESERET CAPITAL LETTER PEE +10412 ; mapped ; 1043A # 3.1 DESERET CAPITAL LETTER BEE +10413 ; mapped ; 1043B # 3.1 DESERET CAPITAL LETTER TEE +10414 ; mapped ; 1043C # 3.1 DESERET CAPITAL LETTER DEE +10415 ; mapped ; 1043D # 3.1 DESERET CAPITAL LETTER CHEE +10416 ; mapped ; 1043E # 3.1 DESERET CAPITAL LETTER JEE +10417 ; mapped ; 1043F # 3.1 DESERET CAPITAL LETTER KAY +10418 ; mapped ; 10440 # 3.1 DESERET CAPITAL LETTER GAY +10419 ; mapped ; 10441 # 3.1 DESERET CAPITAL LETTER EF +1041A ; mapped ; 10442 # 3.1 DESERET CAPITAL LETTER VEE +1041B ; mapped ; 10443 # 3.1 DESERET CAPITAL LETTER ETH +1041C ; mapped ; 10444 # 3.1 DESERET CAPITAL LETTER THEE +1041D ; mapped ; 10445 # 3.1 DESERET CAPITAL LETTER ES +1041E ; mapped ; 10446 # 3.1 DESERET CAPITAL LETTER ZEE +1041F ; mapped ; 10447 # 3.1 DESERET CAPITAL LETTER ESH +10420 ; mapped ; 10448 # 3.1 DESERET CAPITAL LETTER ZHEE +10421 ; mapped ; 10449 # 3.1 DESERET CAPITAL LETTER ER +10422 ; mapped ; 1044A # 3.1 DESERET CAPITAL LETTER EL +10423 ; mapped ; 1044B # 3.1 DESERET CAPITAL LETTER EM +10424 ; mapped ; 1044C # 3.1 DESERET CAPITAL LETTER EN +10425 ; mapped ; 1044D # 3.1 DESERET CAPITAL LETTER ENG +10426 ; mapped ; 1044E # 4.0 DESERET CAPITAL LETTER OI +10427 ; mapped ; 1044F # 4.0 DESERET CAPITAL LETTER EW +10428..1044D ; valid # 3.1 DESERET SMALL LETTER LONG I..DESERET SMALL LETTER ENG +1044E..1049D ; valid # 4.0 DESERET SMALL LETTER OI..OSMANYA LETTER OO +1049E..1049F ; disallowed # NA .. +104A0..104A9 ; valid # 4.0 OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104AA..104AF ; disallowed # NA .. +104B0 ; mapped ; 104D8 # 9.0 OSAGE CAPITAL LETTER A +104B1 ; mapped ; 104D9 # 9.0 OSAGE CAPITAL LETTER AI +104B2 ; mapped ; 104DA # 9.0 OSAGE CAPITAL LETTER AIN +104B3 ; mapped ; 104DB # 9.0 OSAGE CAPITAL LETTER AH +104B4 ; mapped ; 104DC # 9.0 OSAGE CAPITAL LETTER BRA +104B5 ; mapped ; 104DD # 9.0 OSAGE CAPITAL LETTER CHA +104B6 ; mapped ; 104DE # 9.0 OSAGE CAPITAL LETTER EHCHA +104B7 ; mapped ; 104DF # 9.0 OSAGE CAPITAL LETTER E +104B8 ; mapped ; 104E0 # 9.0 OSAGE CAPITAL LETTER EIN +104B9 ; mapped ; 104E1 # 9.0 OSAGE CAPITAL LETTER HA +104BA ; mapped ; 104E2 # 9.0 OSAGE CAPITAL LETTER HYA +104BB ; mapped ; 104E3 # 9.0 OSAGE CAPITAL LETTER I +104BC ; mapped ; 104E4 # 9.0 OSAGE CAPITAL LETTER KA +104BD ; mapped ; 104E5 # 9.0 OSAGE CAPITAL LETTER EHKA +104BE ; mapped ; 104E6 # 9.0 OSAGE CAPITAL LETTER KYA +104BF ; mapped ; 104E7 # 9.0 OSAGE CAPITAL LETTER LA +104C0 ; mapped ; 104E8 # 9.0 OSAGE CAPITAL LETTER MA +104C1 ; mapped ; 104E9 # 9.0 OSAGE CAPITAL LETTER NA +104C2 ; mapped ; 104EA # 9.0 OSAGE CAPITAL LETTER O +104C3 ; mapped ; 104EB # 9.0 OSAGE CAPITAL LETTER OIN +104C4 ; mapped ; 104EC # 9.0 OSAGE CAPITAL LETTER PA +104C5 ; mapped ; 104ED # 9.0 OSAGE CAPITAL LETTER EHPA +104C6 ; mapped ; 104EE # 9.0 OSAGE CAPITAL LETTER SA +104C7 ; mapped ; 104EF # 9.0 OSAGE CAPITAL LETTER SHA +104C8 ; mapped ; 104F0 # 9.0 OSAGE CAPITAL LETTER TA +104C9 ; mapped ; 104F1 # 9.0 OSAGE CAPITAL LETTER EHTA +104CA ; mapped ; 104F2 # 9.0 OSAGE CAPITAL LETTER TSA +104CB ; mapped ; 104F3 # 9.0 OSAGE CAPITAL LETTER EHTSA +104CC ; mapped ; 104F4 # 9.0 OSAGE CAPITAL LETTER TSHA +104CD ; mapped ; 104F5 # 9.0 OSAGE CAPITAL LETTER DHA +104CE ; mapped ; 104F6 # 9.0 OSAGE CAPITAL LETTER U +104CF ; mapped ; 104F7 # 9.0 OSAGE CAPITAL LETTER WA +104D0 ; mapped ; 104F8 # 9.0 OSAGE CAPITAL LETTER KHA +104D1 ; mapped ; 104F9 # 9.0 OSAGE CAPITAL LETTER GHA +104D2 ; mapped ; 104FA # 9.0 OSAGE CAPITAL LETTER ZA +104D3 ; mapped ; 104FB # 9.0 OSAGE CAPITAL LETTER ZHA +104D4..104D7 ; disallowed # NA .. +104D8..104FB ; valid # 9.0 OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA +104FC..104FF ; disallowed # NA .. +10500..10527 ; valid # 7.0 ELBASAN LETTER A..ELBASAN LETTER KHE +10528..1052F ; disallowed # NA .. +10530..10563 ; valid # 7.0 CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW +10564..1056E ; disallowed # NA .. +1056F ; valid ; ; NV8 # 7.0 CAUCASIAN ALBANIAN CITATION MARK +10570..105FF ; disallowed # NA .. +10600..10736 ; valid # 7.0 LINEAR A SIGN AB001..LINEAR A SIGN A664 +10737..1073F ; disallowed # NA .. +10740..10755 ; valid # 7.0 LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE +10756..1075F ; disallowed # NA .. +10760..10767 ; valid # 7.0 LINEAR A SIGN A800..LINEAR A SIGN A807 +10768..107FF ; disallowed # NA .. +10800..10805 ; valid # 4.0 CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA +10806..10807 ; disallowed # NA .. +10808 ; valid # 4.0 CYPRIOT SYLLABLE JO +10809 ; disallowed # NA +1080A..10835 ; valid # 4.0 CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO +10836 ; disallowed # NA +10837..10838 ; valid # 4.0 CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE +10839..1083B ; disallowed # NA .. +1083C ; valid # 4.0 CYPRIOT SYLLABLE ZA +1083D..1083E ; disallowed # NA .. +1083F ; valid # 4.0 CYPRIOT SYLLABLE ZO +10840..10855 ; valid # 5.2 IMPERIAL ARAMAIC LETTER ALEPH..IMPERIAL ARAMAIC LETTER TAW +10856 ; disallowed # NA +10857..1085F ; valid ; ; NV8 # 5.2 IMPERIAL ARAMAIC SECTION SIGN..IMPERIAL ARAMAIC NUMBER TEN THOUSAND +10860..10876 ; valid # 7.0 PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW +10877..1087F ; valid ; ; NV8 # 7.0 PALMYRENE LEFT-POINTING FLEURON..PALMYRENE NUMBER TWENTY +10880..1089E ; valid # 7.0 NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW +1089F..108A6 ; disallowed # NA .. +108A7..108AF ; valid ; ; NV8 # 7.0 NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED +108B0..108DF ; disallowed # NA .. +108E0..108F2 ; valid # 8.0 HATRAN LETTER ALEPH..HATRAN LETTER QOPH +108F3 ; disallowed # NA +108F4..108F5 ; valid # 8.0 HATRAN LETTER SHIN..HATRAN LETTER TAW +108F6..108FA ; disallowed # NA .. +108FB..108FF ; valid ; ; NV8 # 8.0 HATRAN NUMBER ONE..HATRAN NUMBER ONE HUNDRED +10900..10915 ; valid # 5.0 PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU +10916..10919 ; valid ; ; NV8 # 5.0 PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER ONE HUNDRED +1091A..1091B ; valid ; ; NV8 # 5.2 PHOENICIAN NUMBER TWO..PHOENICIAN NUMBER THREE +1091C..1091E ; disallowed # NA .. +1091F ; valid ; ; NV8 # 5.0 PHOENICIAN WORD SEPARATOR +10920..10939 ; valid # 5.1 LYDIAN LETTER A..LYDIAN LETTER C +1093A..1093E ; disallowed # NA .. +1093F ; valid ; ; NV8 # 5.1 LYDIAN TRIANGULAR MARK +10940..1097F ; disallowed # NA .. +10980..109B7 ; valid # 6.1 MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA +109B8..109BB ; disallowed # NA .. +109BC..109BD ; valid ; ; NV8 # 8.0 MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS..MEROITIC CURSIVE FRACTION ONE HALF +109BE..109BF ; valid # 6.1 MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN +109C0..109CF ; valid ; ; NV8 # 8.0 MEROITIC CURSIVE NUMBER ONE..MEROITIC CURSIVE NUMBER SEVENTY +109D0..109D1 ; disallowed # NA .. +109D2..109FF ; valid ; ; NV8 # 8.0 MEROITIC CURSIVE NUMBER ONE HUNDRED..MEROITIC CURSIVE FRACTION TEN TWELFTHS +10A00..10A03 ; valid # 4.1 KHAROSHTHI LETTER A..KHAROSHTHI VOWEL SIGN VOCALIC R +10A04 ; disallowed # NA +10A05..10A06 ; valid # 4.1 KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O +10A07..10A0B ; disallowed # NA .. +10A0C..10A13 ; valid # 4.1 KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI LETTER GHA +10A14 ; disallowed # NA +10A15..10A17 ; valid # 4.1 KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA +10A18 ; disallowed # NA +10A19..10A33 ; valid # 4.1 KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA +10A34..10A37 ; disallowed # NA .. +10A38..10A3A ; valid # 4.1 KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW +10A3B..10A3E ; disallowed # NA .. +10A3F ; valid # 4.1 KHAROSHTHI VIRAMA +10A40..10A47 ; valid ; ; NV8 # 4.1 KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND +10A48..10A4F ; disallowed # NA .. +10A50..10A58 ; valid ; ; NV8 # 4.1 KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES +10A59..10A5F ; disallowed # NA .. +10A60..10A7C ; valid # 5.2 OLD SOUTH ARABIAN LETTER HE..OLD SOUTH ARABIAN LETTER THETH +10A7D..10A7F ; valid ; ; NV8 # 5.2 OLD SOUTH ARABIAN NUMBER ONE..OLD SOUTH ARABIAN NUMERIC INDICATOR +10A80..10A9C ; valid # 7.0 OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH +10A9D..10A9F ; valid ; ; NV8 # 7.0 OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY +10AA0..10ABF ; disallowed # NA .. +10AC0..10AC7 ; valid # 7.0 MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC8 ; valid ; ; NV8 # 7.0 MANICHAEAN SIGN UD +10AC9..10AE6 ; valid # 7.0 MANICHAEAN LETTER ZAYIN..MANICHAEAN ABBREVIATION MARK BELOW +10AE7..10AEA ; disallowed # NA .. +10AEB..10AF6 ; valid ; ; NV8 # 7.0 MANICHAEAN NUMBER ONE..MANICHAEAN PUNCTUATION LINE FILLER +10AF7..10AFF ; disallowed # NA .. +10B00..10B35 ; valid # 5.2 AVESTAN LETTER A..AVESTAN LETTER HE +10B36..10B38 ; disallowed # NA .. +10B39..10B3F ; valid ; ; NV8 # 5.2 AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B40..10B55 ; valid # 5.2 INSCRIPTIONAL PARTHIAN LETTER ALEPH..INSCRIPTIONAL PARTHIAN LETTER TAW +10B56..10B57 ; disallowed # NA .. +10B58..10B5F ; valid ; ; NV8 # 5.2 INSCRIPTIONAL PARTHIAN NUMBER ONE..INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND +10B60..10B72 ; valid # 5.2 INSCRIPTIONAL PAHLAVI LETTER ALEPH..INSCRIPTIONAL PAHLAVI LETTER TAW +10B73..10B77 ; disallowed # NA .. +10B78..10B7F ; valid ; ; NV8 # 5.2 INSCRIPTIONAL PAHLAVI NUMBER ONE..INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND +10B80..10B91 ; valid # 7.0 PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW +10B92..10B98 ; disallowed # NA .. +10B99..10B9C ; valid ; ; NV8 # 7.0 PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT +10B9D..10BA8 ; disallowed # NA .. +10BA9..10BAF ; valid ; ; NV8 # 7.0 PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED +10BB0..10BFF ; disallowed # NA .. +10C00..10C48 ; valid # 5.2 OLD TURKIC LETTER ORKHON A..OLD TURKIC LETTER ORKHON BASH +10C49..10C7F ; disallowed # NA .. +10C80 ; mapped ; 10CC0 # 8.0 OLD HUNGARIAN CAPITAL LETTER A +10C81 ; mapped ; 10CC1 # 8.0 OLD HUNGARIAN CAPITAL LETTER AA +10C82 ; mapped ; 10CC2 # 8.0 OLD HUNGARIAN CAPITAL LETTER EB +10C83 ; mapped ; 10CC3 # 8.0 OLD HUNGARIAN CAPITAL LETTER AMB +10C84 ; mapped ; 10CC4 # 8.0 OLD HUNGARIAN CAPITAL LETTER EC +10C85 ; mapped ; 10CC5 # 8.0 OLD HUNGARIAN CAPITAL LETTER ENC +10C86 ; mapped ; 10CC6 # 8.0 OLD HUNGARIAN CAPITAL LETTER ECS +10C87 ; mapped ; 10CC7 # 8.0 OLD HUNGARIAN CAPITAL LETTER ED +10C88 ; mapped ; 10CC8 # 8.0 OLD HUNGARIAN CAPITAL LETTER AND +10C89 ; mapped ; 10CC9 # 8.0 OLD HUNGARIAN CAPITAL LETTER E +10C8A ; mapped ; 10CCA # 8.0 OLD HUNGARIAN CAPITAL LETTER CLOSE E +10C8B ; mapped ; 10CCB # 8.0 OLD HUNGARIAN CAPITAL LETTER EE +10C8C ; mapped ; 10CCC # 8.0 OLD HUNGARIAN CAPITAL LETTER EF +10C8D ; mapped ; 10CCD # 8.0 OLD HUNGARIAN CAPITAL LETTER EG +10C8E ; mapped ; 10CCE # 8.0 OLD HUNGARIAN CAPITAL LETTER EGY +10C8F ; mapped ; 10CCF # 8.0 OLD HUNGARIAN CAPITAL LETTER EH +10C90 ; mapped ; 10CD0 # 8.0 OLD HUNGARIAN CAPITAL LETTER I +10C91 ; mapped ; 10CD1 # 8.0 OLD HUNGARIAN CAPITAL LETTER II +10C92 ; mapped ; 10CD2 # 8.0 OLD HUNGARIAN CAPITAL LETTER EJ +10C93 ; mapped ; 10CD3 # 8.0 OLD HUNGARIAN CAPITAL LETTER EK +10C94 ; mapped ; 10CD4 # 8.0 OLD HUNGARIAN CAPITAL LETTER AK +10C95 ; mapped ; 10CD5 # 8.0 OLD HUNGARIAN CAPITAL LETTER UNK +10C96 ; mapped ; 10CD6 # 8.0 OLD HUNGARIAN CAPITAL LETTER EL +10C97 ; mapped ; 10CD7 # 8.0 OLD HUNGARIAN CAPITAL LETTER ELY +10C98 ; mapped ; 10CD8 # 8.0 OLD HUNGARIAN CAPITAL LETTER EM +10C99 ; mapped ; 10CD9 # 8.0 OLD HUNGARIAN CAPITAL LETTER EN +10C9A ; mapped ; 10CDA # 8.0 OLD HUNGARIAN CAPITAL LETTER ENY +10C9B ; mapped ; 10CDB # 8.0 OLD HUNGARIAN CAPITAL LETTER O +10C9C ; mapped ; 10CDC # 8.0 OLD HUNGARIAN CAPITAL LETTER OO +10C9D ; mapped ; 10CDD # 8.0 OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE +10C9E ; mapped ; 10CDE # 8.0 OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE +10C9F ; mapped ; 10CDF # 8.0 OLD HUNGARIAN CAPITAL LETTER OEE +10CA0 ; mapped ; 10CE0 # 8.0 OLD HUNGARIAN CAPITAL LETTER EP +10CA1 ; mapped ; 10CE1 # 8.0 OLD HUNGARIAN CAPITAL LETTER EMP +10CA2 ; mapped ; 10CE2 # 8.0 OLD HUNGARIAN CAPITAL LETTER ER +10CA3 ; mapped ; 10CE3 # 8.0 OLD HUNGARIAN CAPITAL LETTER SHORT ER +10CA4 ; mapped ; 10CE4 # 8.0 OLD HUNGARIAN CAPITAL LETTER ES +10CA5 ; mapped ; 10CE5 # 8.0 OLD HUNGARIAN CAPITAL LETTER ESZ +10CA6 ; mapped ; 10CE6 # 8.0 OLD HUNGARIAN CAPITAL LETTER ET +10CA7 ; mapped ; 10CE7 # 8.0 OLD HUNGARIAN CAPITAL LETTER ENT +10CA8 ; mapped ; 10CE8 # 8.0 OLD HUNGARIAN CAPITAL LETTER ETY +10CA9 ; mapped ; 10CE9 # 8.0 OLD HUNGARIAN CAPITAL LETTER ECH +10CAA ; mapped ; 10CEA # 8.0 OLD HUNGARIAN CAPITAL LETTER U +10CAB ; mapped ; 10CEB # 8.0 OLD HUNGARIAN CAPITAL LETTER UU +10CAC ; mapped ; 10CEC # 8.0 OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE +10CAD ; mapped ; 10CED # 8.0 OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE +10CAE ; mapped ; 10CEE # 8.0 OLD HUNGARIAN CAPITAL LETTER EV +10CAF ; mapped ; 10CEF # 8.0 OLD HUNGARIAN CAPITAL LETTER EZ +10CB0 ; mapped ; 10CF0 # 8.0 OLD HUNGARIAN CAPITAL LETTER EZS +10CB1 ; mapped ; 10CF1 # 8.0 OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN +10CB2 ; mapped ; 10CF2 # 8.0 OLD HUNGARIAN CAPITAL LETTER US +10CB3..10CBF ; disallowed # NA .. +10CC0..10CF2 ; valid # 8.0 OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US +10CF3..10CF9 ; disallowed # NA .. +10CFA..10CFF ; valid ; ; NV8 # 8.0 OLD HUNGARIAN NUMBER ONE..OLD HUNGARIAN NUMBER ONE THOUSAND +10D00..10E5F ; disallowed # NA .. +10E60..10E7E ; valid ; ; NV8 # 5.2 RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS +10E7F..10FFF ; disallowed # NA .. +11000..11046 ; valid # 6.0 BRAHMI SIGN CANDRABINDU..BRAHMI VIRAMA +11047..1104D ; valid ; ; NV8 # 6.0 BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS +1104E..11051 ; disallowed # NA .. +11052..11065 ; valid ; ; NV8 # 6.0 BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND +11066..1106F ; valid # 6.0 BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE +11070..1107E ; disallowed # NA .. +1107F ; valid # 7.0 BRAHMI NUMBER JOINER +11080..110BA ; valid # 5.2 KAITHI SIGN CANDRABINDU..KAITHI SIGN NUKTA +110BB..110BC ; valid ; ; NV8 # 5.2 KAITHI ABBREVIATION SIGN..KAITHI ENUMERATION SIGN +110BD ; disallowed # 5.2 KAITHI NUMBER SIGN +110BE..110C1 ; valid ; ; NV8 # 5.2 KAITHI SECTION MARK..KAITHI DOUBLE DANDA +110C2..110CF ; disallowed # NA .. +110D0..110E8 ; valid # 6.1 SORA SOMPENG LETTER SAH..SORA SOMPENG LETTER MAE +110E9..110EF ; disallowed # NA .. +110F0..110F9 ; valid # 6.1 SORA SOMPENG DIGIT ZERO..SORA SOMPENG DIGIT NINE +110FA..110FF ; disallowed # NA .. +11100..11134 ; valid # 6.1 CHAKMA SIGN CANDRABINDU..CHAKMA MAAYYAA +11135 ; disallowed # NA +11136..1113F ; valid # 6.1 CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE +11140..11143 ; valid ; ; NV8 # 6.1 CHAKMA SECTION MARK..CHAKMA QUESTION MARK +11144..1114F ; disallowed # NA .. +11150..11173 ; valid # 7.0 MAHAJANI LETTER A..MAHAJANI SIGN NUKTA +11174..11175 ; valid ; ; NV8 # 7.0 MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK +11176 ; valid # 7.0 MAHAJANI LIGATURE SHRI +11177..1117F ; disallowed # NA .. +11180..111C4 ; valid # 6.1 SHARADA SIGN CANDRABINDU..SHARADA OM +111C5..111C8 ; valid ; ; NV8 # 6.1 SHARADA DANDA..SHARADA SEPARATOR +111C9 ; valid ; ; NV8 # 8.0 SHARADA SANDHI MARK +111CA..111CC ; valid # 8.0 SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK +111CD ; valid ; ; NV8 # 7.0 SHARADA SUTRA MARK +111CE..111CF ; disallowed # NA .. +111D0..111D9 ; valid # 6.1 SHARADA DIGIT ZERO..SHARADA DIGIT NINE +111DA ; valid # 7.0 SHARADA EKAM +111DB ; valid ; ; NV8 # 8.0 SHARADA SIGN SIDDHAM +111DC ; valid # 8.0 SHARADA HEADSTROKE +111DD..111DF ; valid ; ; NV8 # 8.0 SHARADA CONTINUATION SIGN..SHARADA SECTION MARK-2 +111E0 ; disallowed # NA +111E1..111F4 ; valid ; ; NV8 # 7.0 SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND +111F5..111FF ; disallowed # NA .. +11200..11211 ; valid # 7.0 KHOJKI LETTER A..KHOJKI LETTER JJA +11212 ; disallowed # NA +11213..11237 ; valid # 7.0 KHOJKI LETTER NYA..KHOJKI SIGN SHADDA +11238..1123D ; valid ; ; NV8 # 7.0 KHOJKI DANDA..KHOJKI ABBREVIATION SIGN +1123E ; valid # 9.0 KHOJKI SIGN SUKUN +1123F..1127F ; disallowed # NA .. +11280..11286 ; valid # 8.0 MULTANI LETTER A..MULTANI LETTER GA +11287 ; disallowed # NA +11288 ; valid # 8.0 MULTANI LETTER GHA +11289 ; disallowed # NA +1128A..1128D ; valid # 8.0 MULTANI LETTER CA..MULTANI LETTER JJA +1128E ; disallowed # NA +1128F..1129D ; valid # 8.0 MULTANI LETTER NYA..MULTANI LETTER BA +1129E ; disallowed # NA +1129F..112A8 ; valid # 8.0 MULTANI LETTER BHA..MULTANI LETTER RHA +112A9 ; valid ; ; NV8 # 8.0 MULTANI SECTION MARK +112AA..112AF ; disallowed # NA .. +112B0..112EA ; valid # 7.0 KHUDAWADI LETTER A..KHUDAWADI SIGN VIRAMA +112EB..112EF ; disallowed # NA .. +112F0..112F9 ; valid # 7.0 KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +112FA..112FF ; disallowed # NA .. +11300 ; valid # 8.0 GRANTHA SIGN COMBINING ANUSVARA ABOVE +11301..11303 ; valid # 7.0 GRANTHA SIGN CANDRABINDU..GRANTHA SIGN VISARGA +11304 ; disallowed # NA +11305..1130C ; valid # 7.0 GRANTHA LETTER A..GRANTHA LETTER VOCALIC L +1130D..1130E ; disallowed # NA .. +1130F..11310 ; valid # 7.0 GRANTHA LETTER EE..GRANTHA LETTER AI +11311..11312 ; disallowed # NA .. +11313..11328 ; valid # 7.0 GRANTHA LETTER OO..GRANTHA LETTER NA +11329 ; disallowed # NA +1132A..11330 ; valid # 7.0 GRANTHA LETTER PA..GRANTHA LETTER RA +11331 ; disallowed # NA +11332..11333 ; valid # 7.0 GRANTHA LETTER LA..GRANTHA LETTER LLA +11334 ; disallowed # NA +11335..11339 ; valid # 7.0 GRANTHA LETTER VA..GRANTHA LETTER HA +1133A..1133B ; disallowed # NA .. +1133C..11344 ; valid # 7.0 GRANTHA SIGN NUKTA..GRANTHA VOWEL SIGN VOCALIC RR +11345..11346 ; disallowed # NA .. +11347..11348 ; valid # 7.0 GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI +11349..1134A ; disallowed # NA .. +1134B..1134D ; valid # 7.0 GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA +1134E..1134F ; disallowed # NA .. +11350 ; valid # 8.0 GRANTHA OM +11351..11356 ; disallowed # NA .. +11357 ; valid # 7.0 GRANTHA AU LENGTH MARK +11358..1135C ; disallowed # NA .. +1135D..11363 ; valid # 7.0 GRANTHA SIGN PLUTA..GRANTHA VOWEL SIGN VOCALIC LL +11364..11365 ; disallowed # NA .. +11366..1136C ; valid # 7.0 COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX +1136D..1136F ; disallowed # NA .. +11370..11374 ; valid # 7.0 COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11375..113FF ; disallowed # NA .. +11400..1144A ; valid # 9.0 NEWA LETTER A..NEWA SIDDHI +1144B..1144F ; valid ; ; NV8 # 9.0 NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459 ; valid # 9.0 NEWA DIGIT ZERO..NEWA DIGIT NINE +1145A ; disallowed # NA +1145B ; valid ; ; NV8 # 9.0 NEWA PLACEHOLDER MARK +1145C ; disallowed # NA +1145D ; valid ; ; NV8 # 9.0 NEWA INSERTION SIGN +1145E..1147F ; disallowed # NA .. +11480..114C5 ; valid # 7.0 TIRHUTA ANJI..TIRHUTA GVANG +114C6 ; valid ; ; NV8 # 7.0 TIRHUTA ABBREVIATION SIGN +114C7 ; valid # 7.0 TIRHUTA OM +114C8..114CF ; disallowed # NA .. +114D0..114D9 ; valid # 7.0 TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE +114DA..1157F ; disallowed # NA .. +11580..115B5 ; valid # 7.0 SIDDHAM LETTER A..SIDDHAM VOWEL SIGN VOCALIC RR +115B6..115B7 ; disallowed # NA .. +115B8..115C0 ; valid # 7.0 SIDDHAM VOWEL SIGN E..SIDDHAM SIGN NUKTA +115C1..115C9 ; valid ; ; NV8 # 7.0 SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK +115CA..115D7 ; valid ; ; NV8 # 8.0 SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +115D8..115DD ; valid # 8.0 SIDDHAM LETTER THREE-CIRCLE ALTERNATE I..SIDDHAM VOWEL SIGN ALTERNATE UU +115DE..115FF ; disallowed # NA .. +11600..11640 ; valid # 7.0 MODI LETTER A..MODI SIGN ARDHACANDRA +11641..11643 ; valid ; ; NV8 # 7.0 MODI DANDA..MODI ABBREVIATION SIGN +11644 ; valid # 7.0 MODI SIGN HUVA +11645..1164F ; disallowed # NA .. +11650..11659 ; valid # 7.0 MODI DIGIT ZERO..MODI DIGIT NINE +1165A..1165F ; disallowed # NA .. +11660..1166C ; valid ; ; NV8 # 9.0 MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT +1166D..1167F ; disallowed # NA .. +11680..116B7 ; valid # 6.1 TAKRI LETTER A..TAKRI SIGN NUKTA +116B8..116BF ; disallowed # NA .. +116C0..116C9 ; valid # 6.1 TAKRI DIGIT ZERO..TAKRI DIGIT NINE +116CA..116FF ; disallowed # NA .. +11700..11719 ; valid # 8.0 AHOM LETTER KA..AHOM LETTER JHA +1171A..1171C ; disallowed # NA .. +1171D..1172B ; valid # 8.0 AHOM CONSONANT SIGN MEDIAL LA..AHOM SIGN KILLER +1172C..1172F ; disallowed # NA .. +11730..11739 ; valid # 8.0 AHOM DIGIT ZERO..AHOM DIGIT NINE +1173A..1173F ; valid ; ; NV8 # 8.0 AHOM NUMBER TEN..AHOM SYMBOL VI +11740..1189F ; disallowed # NA .. +118A0 ; mapped ; 118C0 # 7.0 WARANG CITI CAPITAL LETTER NGAA +118A1 ; mapped ; 118C1 # 7.0 WARANG CITI CAPITAL LETTER A +118A2 ; mapped ; 118C2 # 7.0 WARANG CITI CAPITAL LETTER WI +118A3 ; mapped ; 118C3 # 7.0 WARANG CITI CAPITAL LETTER YU +118A4 ; mapped ; 118C4 # 7.0 WARANG CITI CAPITAL LETTER YA +118A5 ; mapped ; 118C5 # 7.0 WARANG CITI CAPITAL LETTER YO +118A6 ; mapped ; 118C6 # 7.0 WARANG CITI CAPITAL LETTER II +118A7 ; mapped ; 118C7 # 7.0 WARANG CITI CAPITAL LETTER UU +118A8 ; mapped ; 118C8 # 7.0 WARANG CITI CAPITAL LETTER E +118A9 ; mapped ; 118C9 # 7.0 WARANG CITI CAPITAL LETTER O +118AA ; mapped ; 118CA # 7.0 WARANG CITI CAPITAL LETTER ANG +118AB ; mapped ; 118CB # 7.0 WARANG CITI CAPITAL LETTER GA +118AC ; mapped ; 118CC # 7.0 WARANG CITI CAPITAL LETTER KO +118AD ; mapped ; 118CD # 7.0 WARANG CITI CAPITAL LETTER ENY +118AE ; mapped ; 118CE # 7.0 WARANG CITI CAPITAL LETTER YUJ +118AF ; mapped ; 118CF # 7.0 WARANG CITI CAPITAL LETTER UC +118B0 ; mapped ; 118D0 # 7.0 WARANG CITI CAPITAL LETTER ENN +118B1 ; mapped ; 118D1 # 7.0 WARANG CITI CAPITAL LETTER ODD +118B2 ; mapped ; 118D2 # 7.0 WARANG CITI CAPITAL LETTER TTE +118B3 ; mapped ; 118D3 # 7.0 WARANG CITI CAPITAL LETTER NUNG +118B4 ; mapped ; 118D4 # 7.0 WARANG CITI CAPITAL LETTER DA +118B5 ; mapped ; 118D5 # 7.0 WARANG CITI CAPITAL LETTER AT +118B6 ; mapped ; 118D6 # 7.0 WARANG CITI CAPITAL LETTER AM +118B7 ; mapped ; 118D7 # 7.0 WARANG CITI CAPITAL LETTER BU +118B8 ; mapped ; 118D8 # 7.0 WARANG CITI CAPITAL LETTER PU +118B9 ; mapped ; 118D9 # 7.0 WARANG CITI CAPITAL LETTER HIYO +118BA ; mapped ; 118DA # 7.0 WARANG CITI CAPITAL LETTER HOLO +118BB ; mapped ; 118DB # 7.0 WARANG CITI CAPITAL LETTER HORR +118BC ; mapped ; 118DC # 7.0 WARANG CITI CAPITAL LETTER HAR +118BD ; mapped ; 118DD # 7.0 WARANG CITI CAPITAL LETTER SSUU +118BE ; mapped ; 118DE # 7.0 WARANG CITI CAPITAL LETTER SII +118BF ; mapped ; 118DF # 7.0 WARANG CITI CAPITAL LETTER VIYO +118C0..118E9 ; valid # 7.0 WARANG CITI SMALL LETTER NGAA..WARANG CITI DIGIT NINE +118EA..118F2 ; valid ; ; NV8 # 7.0 WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY +118F3..118FE ; disallowed # NA .. +118FF ; valid # 7.0 WARANG CITI OM +11900..119FF ; disallowed # NA .. +11A00..11A3E ; valid # 10.0 ZANABAZAR SQUARE LETTER A..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F..11A46 ; valid ; ; NV8 # 10.0 ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47 ; valid # 10.0 ZANABAZAR SQUARE SUBJOINER +11A48..11A4F ; disallowed # NA .. +11A50..11A83 ; valid # 10.0 SOYOMBO LETTER A..SOYOMBO LETTER KSSA +11A84..11A85 ; disallowed # NA .. +11A86..11A99 ; valid # 10.0 SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO SUBJOINER +11A9A..11A9C ; valid ; ; NV8 # 10.0 SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9D ; disallowed # NA +11A9E..11AA2 ; valid ; ; NV8 # 10.0 SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 +11AA3..11ABF ; disallowed # NA .. +11AC0..11AF8 ; valid # 7.0 PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11AF9..11BFF ; disallowed # NA .. +11C00..11C08 ; valid # 9.0 BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C09 ; disallowed # NA +11C0A..11C36 ; valid # 9.0 BHAIKSUKI LETTER E..BHAIKSUKI VOWEL SIGN VOCALIC L +11C37 ; disallowed # NA +11C38..11C40 ; valid # 9.0 BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN AVAGRAHA +11C41..11C45 ; valid ; ; NV8 # 9.0 BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C46..11C4F ; disallowed # NA .. +11C50..11C59 ; valid # 9.0 BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C ; valid ; ; NV8 # 9.0 BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C6D..11C6F ; disallowed # NA .. +11C70..11C71 ; valid ; ; NV8 # 9.0 MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F ; valid # 9.0 MARCHEN LETTER KA..MARCHEN LETTER A +11C90..11C91 ; disallowed # NA .. +11C92..11CA7 ; valid # 9.0 MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA8 ; disallowed # NA +11CA9..11CB6 ; valid # 9.0 MARCHEN SUBJOINED LETTER YA..MARCHEN SIGN CANDRABINDU +11CB7..11CFF ; disallowed # NA .. +11D00..11D06 ; valid # 10.0 MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D07 ; disallowed # NA +11D08..11D09 ; valid # 10.0 MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0A ; disallowed # NA +11D0B..11D36 ; valid # 10.0 MASARAM GONDI LETTER AU..MASARAM GONDI VOWEL SIGN VOCALIC R +11D37..11D39 ; disallowed # NA .. +11D3A ; valid # 10.0 MASARAM GONDI VOWEL SIGN E +11D3B ; disallowed # NA +11D3C..11D3D ; valid # 10.0 MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3E ; disallowed # NA +11D3F..11D47 ; valid # 10.0 MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI RA-KARA +11D48..11D4F ; disallowed # NA .. +11D50..11D59 ; valid # 10.0 MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE +11D5A..11FFF ; disallowed # NA .. +12000..1236E ; valid # 5.0 CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM +1236F..12398 ; valid # 7.0 CUNEIFORM SIGN KAP ELAMITE..CUNEIFORM SIGN UM TIMES ME +12399 ; valid # 8.0 CUNEIFORM SIGN U U +1239A..123FF ; disallowed # NA .. +12400..12462 ; valid ; ; NV8 # 5.0 CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER +12463..1246E ; valid ; ; NV8 # 7.0 CUNEIFORM NUMERIC SIGN ONE QUARTER GUR..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +1246F ; disallowed # NA +12470..12473 ; valid ; ; NV8 # 5.0 CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +12474 ; valid ; ; NV8 # 7.0 CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +12475..1247F ; disallowed # NA .. +12480..12543 ; valid # 8.0 CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU +12544..12FFF ; disallowed # NA .. +13000..1342E ; valid # 5.2 EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 +1342F..143FF ; disallowed # NA .. +14400..14646 ; valid # 8.0 ANATOLIAN HIEROGLYPH A001..ANATOLIAN HIEROGLYPH A530 +14647..167FF ; disallowed # NA .. +16800..16A38 ; valid # 6.0 BAMUM LETTER PHASE-A NGKUE MFON..BAMUM LETTER PHASE-F VUEQ +16A39..16A3F ; disallowed # NA .. +16A40..16A5E ; valid # 7.0 MRO LETTER TA..MRO LETTER TEK +16A5F ; disallowed # NA +16A60..16A69 ; valid # 7.0 MRO DIGIT ZERO..MRO DIGIT NINE +16A6A..16A6D ; disallowed # NA .. +16A6E..16A6F ; valid ; ; NV8 # 7.0 MRO DANDA..MRO DOUBLE DANDA +16A70..16ACF ; disallowed # NA .. +16AD0..16AED ; valid # 7.0 BASSA VAH LETTER ENNI..BASSA VAH LETTER I +16AEE..16AEF ; disallowed # NA .. +16AF0..16AF4 ; valid # 7.0 BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE +16AF5 ; valid ; ; NV8 # 7.0 BASSA VAH FULL STOP +16AF6..16AFF ; disallowed # NA .. +16B00..16B36 ; valid # 7.0 PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG MARK CIM TAUM +16B37..16B3F ; valid ; ; NV8 # 7.0 PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN XYEEM FAIB +16B40..16B43 ; valid # 7.0 PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM +16B44..16B45 ; valid ; ; NV8 # 7.0 PAHAWH HMONG SIGN XAUS..PAHAWH HMONG SIGN CIM TSOV ROG +16B46..16B4F ; disallowed # NA .. +16B50..16B59 ; valid # 7.0 PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE +16B5A ; disallowed # NA +16B5B..16B61 ; valid ; ; NV8 # 7.0 PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS +16B62 ; disallowed # NA +16B63..16B77 ; valid # 7.0 PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS +16B78..16B7C ; disallowed # NA .. +16B7D..16B8F ; valid # 7.0 PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ +16B90..16EFF ; disallowed # NA .. +16F00..16F44 ; valid # 6.1 MIAO LETTER PA..MIAO LETTER HHA +16F45..16F4F ; disallowed # NA .. +16F50..16F7E ; valid # 6.1 MIAO LETTER NASALIZATION..MIAO VOWEL SIGN NG +16F7F..16F8E ; disallowed # NA .. +16F8F..16F9F ; valid # 6.1 MIAO TONE RIGHT..MIAO LETTER REFORMED TONE-8 +16FA0..16FDF ; disallowed # NA .. +16FE0 ; valid # 9.0 TANGUT ITERATION MARK +16FE1 ; valid # 10.0 NUSHU ITERATION MARK +16FE2..16FFF ; disallowed # NA .. +17000..187EC ; valid # 9.0 TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +187ED..187FF ; disallowed # NA .. +18800..18AF2 ; valid # 9.0 TANGUT COMPONENT-001..TANGUT COMPONENT-755 +18AF3..1AFFF ; disallowed # NA .. +1B000..1B001 ; valid # 6.0 KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE +1B002..1B11E ; valid # 10.0 HENTAIGANA LETTER A-1..HENTAIGANA LETTER N-MU-MO-2 +1B11F..1B16F ; disallowed # NA .. +1B170..1B2FB ; valid # 10.0 NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB +1B2FC..1BBFF ; disallowed # NA .. +1BC00..1BC6A ; valid # 7.0 DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC6B..1BC6F ; disallowed # NA .. +1BC70..1BC7C ; valid # 7.0 DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC7D..1BC7F ; disallowed # NA .. +1BC80..1BC88 ; valid # 7.0 DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC89..1BC8F ; disallowed # NA .. +1BC90..1BC99 ; valid # 7.0 DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1BC9A..1BC9B ; disallowed # NA .. +1BC9C ; valid ; ; NV8 # 7.0 DUPLOYAN SIGN O WITH CROSS +1BC9D..1BC9E ; valid # 7.0 DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1BC9F ; valid ; ; NV8 # 7.0 DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1BCA0..1BCA3 ; ignored # 7.0 SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP +1BCA4..1CFFF ; disallowed # NA .. +1D000..1D0F5 ; valid ; ; NV8 # 3.1 BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D0F6..1D0FF ; disallowed # NA .. +1D100..1D126 ; valid ; ; NV8 # 3.1 MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 +1D127..1D128 ; disallowed # NA .. +1D129 ; valid ; ; NV8 # 5.1 MUSICAL SYMBOL MULTIPLE MEASURE REST +1D12A..1D15D ; valid ; ; NV8 # 3.1 MUSICAL SYMBOL DOUBLE SHARP..MUSICAL SYMBOL WHOLE NOTE +1D15E ; mapped ; 1D157 1D165 # 3.1 MUSICAL SYMBOL HALF NOTE +1D15F ; mapped ; 1D158 1D165 # 3.1 MUSICAL SYMBOL QUARTER NOTE +1D160 ; mapped ; 1D158 1D165 1D16E #3.1 MUSICAL SYMBOL EIGHTH NOTE +1D161 ; mapped ; 1D158 1D165 1D16F #3.1 MUSICAL SYMBOL SIXTEENTH NOTE +1D162 ; mapped ; 1D158 1D165 1D170 #3.1 MUSICAL SYMBOL THIRTY-SECOND NOTE +1D163 ; mapped ; 1D158 1D165 1D171 #3.1 MUSICAL SYMBOL SIXTY-FOURTH NOTE +1D164 ; mapped ; 1D158 1D165 1D172 #3.1 MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D165..1D172 ; valid ; ; NV8 # 3.1 MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING FLAG-5 +1D173..1D17A ; disallowed # 3.1 MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE +1D17B..1D1BA ; valid ; ; NV8 # 3.1 MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL SEMIBREVIS BLACK +1D1BB ; mapped ; 1D1B9 1D165 # 3.1 MUSICAL SYMBOL MINIMA +1D1BC ; mapped ; 1D1BA 1D165 # 3.1 MUSICAL SYMBOL MINIMA BLACK +1D1BD ; mapped ; 1D1B9 1D165 1D16E #3.1 MUSICAL SYMBOL SEMIMINIMA WHITE +1D1BE ; mapped ; 1D1BA 1D165 1D16E #3.1 MUSICAL SYMBOL SEMIMINIMA BLACK +1D1BF ; mapped ; 1D1B9 1D165 1D16F #3.1 MUSICAL SYMBOL FUSA WHITE +1D1C0 ; mapped ; 1D1BA 1D165 1D16F #3.1 MUSICAL SYMBOL FUSA BLACK +1D1C1..1D1DD ; valid ; ; NV8 # 3.1 MUSICAL SYMBOL LONGA PERFECTA REST..MUSICAL SYMBOL PES SUBPUNCTIS +1D1DE..1D1E8 ; valid ; ; NV8 # 8.0 MUSICAL SYMBOL KIEVAN C CLEF..MUSICAL SYMBOL KIEVAN FLAT SIGN +1D1E9..1D1FF ; disallowed # NA .. +1D200..1D245 ; valid ; ; NV8 # 4.1 GREEK VOCAL NOTATION SYMBOL-1..GREEK MUSICAL LEIMMA +1D246..1D2FF ; disallowed # NA .. +1D300..1D356 ; valid ; ; NV8 # 4.0 MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING +1D357..1D35F ; disallowed # NA .. +1D360..1D371 ; valid ; ; NV8 # 5.0 COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE +1D372..1D3FF ; disallowed # NA .. +1D400 ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD CAPITAL A +1D401 ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD CAPITAL B +1D402 ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD CAPITAL C +1D403 ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD CAPITAL D +1D404 ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD CAPITAL E +1D405 ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD CAPITAL F +1D406 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD CAPITAL G +1D407 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD CAPITAL H +1D408 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD CAPITAL I +1D409 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD CAPITAL J +1D40A ; mapped ; 006B # 3.1 MATHEMATICAL BOLD CAPITAL K +1D40B ; mapped ; 006C # 3.1 MATHEMATICAL BOLD CAPITAL L +1D40C ; mapped ; 006D # 3.1 MATHEMATICAL BOLD CAPITAL M +1D40D ; mapped ; 006E # 3.1 MATHEMATICAL BOLD CAPITAL N +1D40E ; mapped ; 006F # 3.1 MATHEMATICAL BOLD CAPITAL O +1D40F ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD CAPITAL P +1D410 ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD CAPITAL Q +1D411 ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD CAPITAL R +1D412 ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD CAPITAL S +1D413 ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD CAPITAL T +1D414 ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD CAPITAL U +1D415 ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD CAPITAL V +1D416 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD CAPITAL W +1D417 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD CAPITAL X +1D418 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD CAPITAL Y +1D419 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD CAPITAL Z +1D41A ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD SMALL A +1D41B ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD SMALL B +1D41C ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD SMALL C +1D41D ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD SMALL D +1D41E ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD SMALL E +1D41F ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD SMALL F +1D420 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD SMALL G +1D421 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD SMALL H +1D422 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD SMALL I +1D423 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD SMALL J +1D424 ; mapped ; 006B # 3.1 MATHEMATICAL BOLD SMALL K +1D425 ; mapped ; 006C # 3.1 MATHEMATICAL BOLD SMALL L +1D426 ; mapped ; 006D # 3.1 MATHEMATICAL BOLD SMALL M +1D427 ; mapped ; 006E # 3.1 MATHEMATICAL BOLD SMALL N +1D428 ; mapped ; 006F # 3.1 MATHEMATICAL BOLD SMALL O +1D429 ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD SMALL P +1D42A ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD SMALL Q +1D42B ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD SMALL R +1D42C ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD SMALL S +1D42D ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD SMALL T +1D42E ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD SMALL U +1D42F ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD SMALL V +1D430 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD SMALL W +1D431 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD SMALL X +1D432 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD SMALL Y +1D433 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD SMALL Z +1D434 ; mapped ; 0061 # 3.1 MATHEMATICAL ITALIC CAPITAL A +1D435 ; mapped ; 0062 # 3.1 MATHEMATICAL ITALIC CAPITAL B +1D436 ; mapped ; 0063 # 3.1 MATHEMATICAL ITALIC CAPITAL C +1D437 ; mapped ; 0064 # 3.1 MATHEMATICAL ITALIC CAPITAL D +1D438 ; mapped ; 0065 # 3.1 MATHEMATICAL ITALIC CAPITAL E +1D439 ; mapped ; 0066 # 3.1 MATHEMATICAL ITALIC CAPITAL F +1D43A ; mapped ; 0067 # 3.1 MATHEMATICAL ITALIC CAPITAL G +1D43B ; mapped ; 0068 # 3.1 MATHEMATICAL ITALIC CAPITAL H +1D43C ; mapped ; 0069 # 3.1 MATHEMATICAL ITALIC CAPITAL I +1D43D ; mapped ; 006A # 3.1 MATHEMATICAL ITALIC CAPITAL J +1D43E ; mapped ; 006B # 3.1 MATHEMATICAL ITALIC CAPITAL K +1D43F ; mapped ; 006C # 3.1 MATHEMATICAL ITALIC CAPITAL L +1D440 ; mapped ; 006D # 3.1 MATHEMATICAL ITALIC CAPITAL M +1D441 ; mapped ; 006E # 3.1 MATHEMATICAL ITALIC CAPITAL N +1D442 ; mapped ; 006F # 3.1 MATHEMATICAL ITALIC CAPITAL O +1D443 ; mapped ; 0070 # 3.1 MATHEMATICAL ITALIC CAPITAL P +1D444 ; mapped ; 0071 # 3.1 MATHEMATICAL ITALIC CAPITAL Q +1D445 ; mapped ; 0072 # 3.1 MATHEMATICAL ITALIC CAPITAL R +1D446 ; mapped ; 0073 # 3.1 MATHEMATICAL ITALIC CAPITAL S +1D447 ; mapped ; 0074 # 3.1 MATHEMATICAL ITALIC CAPITAL T +1D448 ; mapped ; 0075 # 3.1 MATHEMATICAL ITALIC CAPITAL U +1D449 ; mapped ; 0076 # 3.1 MATHEMATICAL ITALIC CAPITAL V +1D44A ; mapped ; 0077 # 3.1 MATHEMATICAL ITALIC CAPITAL W +1D44B ; mapped ; 0078 # 3.1 MATHEMATICAL ITALIC CAPITAL X +1D44C ; mapped ; 0079 # 3.1 MATHEMATICAL ITALIC CAPITAL Y +1D44D ; mapped ; 007A # 3.1 MATHEMATICAL ITALIC CAPITAL Z +1D44E ; mapped ; 0061 # 3.1 MATHEMATICAL ITALIC SMALL A +1D44F ; mapped ; 0062 # 3.1 MATHEMATICAL ITALIC SMALL B +1D450 ; mapped ; 0063 # 3.1 MATHEMATICAL ITALIC SMALL C +1D451 ; mapped ; 0064 # 3.1 MATHEMATICAL ITALIC SMALL D +1D452 ; mapped ; 0065 # 3.1 MATHEMATICAL ITALIC SMALL E +1D453 ; mapped ; 0066 # 3.1 MATHEMATICAL ITALIC SMALL F +1D454 ; mapped ; 0067 # 3.1 MATHEMATICAL ITALIC SMALL G +1D455 ; disallowed # NA +1D456 ; mapped ; 0069 # 3.1 MATHEMATICAL ITALIC SMALL I +1D457 ; mapped ; 006A # 3.1 MATHEMATICAL ITALIC SMALL J +1D458 ; mapped ; 006B # 3.1 MATHEMATICAL ITALIC SMALL K +1D459 ; mapped ; 006C # 3.1 MATHEMATICAL ITALIC SMALL L +1D45A ; mapped ; 006D # 3.1 MATHEMATICAL ITALIC SMALL M +1D45B ; mapped ; 006E # 3.1 MATHEMATICAL ITALIC SMALL N +1D45C ; mapped ; 006F # 3.1 MATHEMATICAL ITALIC SMALL O +1D45D ; mapped ; 0070 # 3.1 MATHEMATICAL ITALIC SMALL P +1D45E ; mapped ; 0071 # 3.1 MATHEMATICAL ITALIC SMALL Q +1D45F ; mapped ; 0072 # 3.1 MATHEMATICAL ITALIC SMALL R +1D460 ; mapped ; 0073 # 3.1 MATHEMATICAL ITALIC SMALL S +1D461 ; mapped ; 0074 # 3.1 MATHEMATICAL ITALIC SMALL T +1D462 ; mapped ; 0075 # 3.1 MATHEMATICAL ITALIC SMALL U +1D463 ; mapped ; 0076 # 3.1 MATHEMATICAL ITALIC SMALL V +1D464 ; mapped ; 0077 # 3.1 MATHEMATICAL ITALIC SMALL W +1D465 ; mapped ; 0078 # 3.1 MATHEMATICAL ITALIC SMALL X +1D466 ; mapped ; 0079 # 3.1 MATHEMATICAL ITALIC SMALL Y +1D467 ; mapped ; 007A # 3.1 MATHEMATICAL ITALIC SMALL Z +1D468 ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL A +1D469 ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL B +1D46A ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL C +1D46B ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL D +1D46C ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL E +1D46D ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL F +1D46E ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL G +1D46F ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL H +1D470 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL I +1D471 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL J +1D472 ; mapped ; 006B # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL K +1D473 ; mapped ; 006C # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL L +1D474 ; mapped ; 006D # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL M +1D475 ; mapped ; 006E # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL N +1D476 ; mapped ; 006F # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL O +1D477 ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL P +1D478 ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL Q +1D479 ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL R +1D47A ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL S +1D47B ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL T +1D47C ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL U +1D47D ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL V +1D47E ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL W +1D47F ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL X +1D480 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL Y +1D481 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL Z +1D482 ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD ITALIC SMALL A +1D483 ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD ITALIC SMALL B +1D484 ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD ITALIC SMALL C +1D485 ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD ITALIC SMALL D +1D486 ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD ITALIC SMALL E +1D487 ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD ITALIC SMALL F +1D488 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD ITALIC SMALL G +1D489 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD ITALIC SMALL H +1D48A ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD ITALIC SMALL I +1D48B ; mapped ; 006A # 3.1 MATHEMATICAL BOLD ITALIC SMALL J +1D48C ; mapped ; 006B # 3.1 MATHEMATICAL BOLD ITALIC SMALL K +1D48D ; mapped ; 006C # 3.1 MATHEMATICAL BOLD ITALIC SMALL L +1D48E ; mapped ; 006D # 3.1 MATHEMATICAL BOLD ITALIC SMALL M +1D48F ; mapped ; 006E # 3.1 MATHEMATICAL BOLD ITALIC SMALL N +1D490 ; mapped ; 006F # 3.1 MATHEMATICAL BOLD ITALIC SMALL O +1D491 ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD ITALIC SMALL P +1D492 ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD ITALIC SMALL Q +1D493 ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD ITALIC SMALL R +1D494 ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD ITALIC SMALL S +1D495 ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD ITALIC SMALL T +1D496 ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD ITALIC SMALL U +1D497 ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD ITALIC SMALL V +1D498 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD ITALIC SMALL W +1D499 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD ITALIC SMALL X +1D49A ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD ITALIC SMALL Y +1D49B ; mapped ; 007A # 3.1 MATHEMATICAL BOLD ITALIC SMALL Z +1D49C ; mapped ; 0061 # 3.1 MATHEMATICAL SCRIPT CAPITAL A +1D49D ; disallowed # NA +1D49E ; mapped ; 0063 # 3.1 MATHEMATICAL SCRIPT CAPITAL C +1D49F ; mapped ; 0064 # 3.1 MATHEMATICAL SCRIPT CAPITAL D +1D4A0..1D4A1 ; disallowed # NA .. +1D4A2 ; mapped ; 0067 # 3.1 MATHEMATICAL SCRIPT CAPITAL G +1D4A3..1D4A4 ; disallowed # NA .. +1D4A5 ; mapped ; 006A # 3.1 MATHEMATICAL SCRIPT CAPITAL J +1D4A6 ; mapped ; 006B # 3.1 MATHEMATICAL SCRIPT CAPITAL K +1D4A7..1D4A8 ; disallowed # NA .. +1D4A9 ; mapped ; 006E # 3.1 MATHEMATICAL SCRIPT CAPITAL N +1D4AA ; mapped ; 006F # 3.1 MATHEMATICAL SCRIPT CAPITAL O +1D4AB ; mapped ; 0070 # 3.1 MATHEMATICAL SCRIPT CAPITAL P +1D4AC ; mapped ; 0071 # 3.1 MATHEMATICAL SCRIPT CAPITAL Q +1D4AD ; disallowed # NA +1D4AE ; mapped ; 0073 # 3.1 MATHEMATICAL SCRIPT CAPITAL S +1D4AF ; mapped ; 0074 # 3.1 MATHEMATICAL SCRIPT CAPITAL T +1D4B0 ; mapped ; 0075 # 3.1 MATHEMATICAL SCRIPT CAPITAL U +1D4B1 ; mapped ; 0076 # 3.1 MATHEMATICAL SCRIPT CAPITAL V +1D4B2 ; mapped ; 0077 # 3.1 MATHEMATICAL SCRIPT CAPITAL W +1D4B3 ; mapped ; 0078 # 3.1 MATHEMATICAL SCRIPT CAPITAL X +1D4B4 ; mapped ; 0079 # 3.1 MATHEMATICAL SCRIPT CAPITAL Y +1D4B5 ; mapped ; 007A # 3.1 MATHEMATICAL SCRIPT CAPITAL Z +1D4B6 ; mapped ; 0061 # 3.1 MATHEMATICAL SCRIPT SMALL A +1D4B7 ; mapped ; 0062 # 3.1 MATHEMATICAL SCRIPT SMALL B +1D4B8 ; mapped ; 0063 # 3.1 MATHEMATICAL SCRIPT SMALL C +1D4B9 ; mapped ; 0064 # 3.1 MATHEMATICAL SCRIPT SMALL D +1D4BA ; disallowed # NA +1D4BB ; mapped ; 0066 # 3.1 MATHEMATICAL SCRIPT SMALL F +1D4BC ; disallowed # NA +1D4BD ; mapped ; 0068 # 3.1 MATHEMATICAL SCRIPT SMALL H +1D4BE ; mapped ; 0069 # 3.1 MATHEMATICAL SCRIPT SMALL I +1D4BF ; mapped ; 006A # 3.1 MATHEMATICAL SCRIPT SMALL J +1D4C0 ; mapped ; 006B # 3.1 MATHEMATICAL SCRIPT SMALL K +1D4C1 ; mapped ; 006C # 4.0 MATHEMATICAL SCRIPT SMALL L +1D4C2 ; mapped ; 006D # 3.1 MATHEMATICAL SCRIPT SMALL M +1D4C3 ; mapped ; 006E # 3.1 MATHEMATICAL SCRIPT SMALL N +1D4C4 ; disallowed # NA +1D4C5 ; mapped ; 0070 # 3.1 MATHEMATICAL SCRIPT SMALL P +1D4C6 ; mapped ; 0071 # 3.1 MATHEMATICAL SCRIPT SMALL Q +1D4C7 ; mapped ; 0072 # 3.1 MATHEMATICAL SCRIPT SMALL R +1D4C8 ; mapped ; 0073 # 3.1 MATHEMATICAL SCRIPT SMALL S +1D4C9 ; mapped ; 0074 # 3.1 MATHEMATICAL SCRIPT SMALL T +1D4CA ; mapped ; 0075 # 3.1 MATHEMATICAL SCRIPT SMALL U +1D4CB ; mapped ; 0076 # 3.1 MATHEMATICAL SCRIPT SMALL V +1D4CC ; mapped ; 0077 # 3.1 MATHEMATICAL SCRIPT SMALL W +1D4CD ; mapped ; 0078 # 3.1 MATHEMATICAL SCRIPT SMALL X +1D4CE ; mapped ; 0079 # 3.1 MATHEMATICAL SCRIPT SMALL Y +1D4CF ; mapped ; 007A # 3.1 MATHEMATICAL SCRIPT SMALL Z +1D4D0 ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL A +1D4D1 ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL B +1D4D2 ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL C +1D4D3 ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL D +1D4D4 ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL E +1D4D5 ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL F +1D4D6 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL G +1D4D7 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL H +1D4D8 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL I +1D4D9 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL J +1D4DA ; mapped ; 006B # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL K +1D4DB ; mapped ; 006C # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL L +1D4DC ; mapped ; 006D # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL M +1D4DD ; mapped ; 006E # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL N +1D4DE ; mapped ; 006F # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL O +1D4DF ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL P +1D4E0 ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL Q +1D4E1 ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL R +1D4E2 ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL S +1D4E3 ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL T +1D4E4 ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL U +1D4E5 ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL V +1D4E6 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL W +1D4E7 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL X +1D4E8 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL Y +1D4E9 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD SCRIPT CAPITAL Z +1D4EA ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL A +1D4EB ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL B +1D4EC ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL C +1D4ED ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL D +1D4EE ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL E +1D4EF ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL F +1D4F0 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL G +1D4F1 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL H +1D4F2 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL I +1D4F3 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD SCRIPT SMALL J +1D4F4 ; mapped ; 006B # 3.1 MATHEMATICAL BOLD SCRIPT SMALL K +1D4F5 ; mapped ; 006C # 3.1 MATHEMATICAL BOLD SCRIPT SMALL L +1D4F6 ; mapped ; 006D # 3.1 MATHEMATICAL BOLD SCRIPT SMALL M +1D4F7 ; mapped ; 006E # 3.1 MATHEMATICAL BOLD SCRIPT SMALL N +1D4F8 ; mapped ; 006F # 3.1 MATHEMATICAL BOLD SCRIPT SMALL O +1D4F9 ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL P +1D4FA ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL Q +1D4FB ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL R +1D4FC ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL S +1D4FD ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL T +1D4FE ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL U +1D4FF ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL V +1D500 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL W +1D501 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL X +1D502 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD SCRIPT SMALL Y +1D503 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD SCRIPT SMALL Z +1D504 ; mapped ; 0061 # 3.1 MATHEMATICAL FRAKTUR CAPITAL A +1D505 ; mapped ; 0062 # 3.1 MATHEMATICAL FRAKTUR CAPITAL B +1D506 ; disallowed # NA +1D507 ; mapped ; 0064 # 3.1 MATHEMATICAL FRAKTUR CAPITAL D +1D508 ; mapped ; 0065 # 3.1 MATHEMATICAL FRAKTUR CAPITAL E +1D509 ; mapped ; 0066 # 3.1 MATHEMATICAL FRAKTUR CAPITAL F +1D50A ; mapped ; 0067 # 3.1 MATHEMATICAL FRAKTUR CAPITAL G +1D50B..1D50C ; disallowed # NA .. +1D50D ; mapped ; 006A # 3.1 MATHEMATICAL FRAKTUR CAPITAL J +1D50E ; mapped ; 006B # 3.1 MATHEMATICAL FRAKTUR CAPITAL K +1D50F ; mapped ; 006C # 3.1 MATHEMATICAL FRAKTUR CAPITAL L +1D510 ; mapped ; 006D # 3.1 MATHEMATICAL FRAKTUR CAPITAL M +1D511 ; mapped ; 006E # 3.1 MATHEMATICAL FRAKTUR CAPITAL N +1D512 ; mapped ; 006F # 3.1 MATHEMATICAL FRAKTUR CAPITAL O +1D513 ; mapped ; 0070 # 3.1 MATHEMATICAL FRAKTUR CAPITAL P +1D514 ; mapped ; 0071 # 3.1 MATHEMATICAL FRAKTUR CAPITAL Q +1D515 ; disallowed # NA +1D516 ; mapped ; 0073 # 3.1 MATHEMATICAL FRAKTUR CAPITAL S +1D517 ; mapped ; 0074 # 3.1 MATHEMATICAL FRAKTUR CAPITAL T +1D518 ; mapped ; 0075 # 3.1 MATHEMATICAL FRAKTUR CAPITAL U +1D519 ; mapped ; 0076 # 3.1 MATHEMATICAL FRAKTUR CAPITAL V +1D51A ; mapped ; 0077 # 3.1 MATHEMATICAL FRAKTUR CAPITAL W +1D51B ; mapped ; 0078 # 3.1 MATHEMATICAL FRAKTUR CAPITAL X +1D51C ; mapped ; 0079 # 3.1 MATHEMATICAL FRAKTUR CAPITAL Y +1D51D ; disallowed # NA +1D51E ; mapped ; 0061 # 3.1 MATHEMATICAL FRAKTUR SMALL A +1D51F ; mapped ; 0062 # 3.1 MATHEMATICAL FRAKTUR SMALL B +1D520 ; mapped ; 0063 # 3.1 MATHEMATICAL FRAKTUR SMALL C +1D521 ; mapped ; 0064 # 3.1 MATHEMATICAL FRAKTUR SMALL D +1D522 ; mapped ; 0065 # 3.1 MATHEMATICAL FRAKTUR SMALL E +1D523 ; mapped ; 0066 # 3.1 MATHEMATICAL FRAKTUR SMALL F +1D524 ; mapped ; 0067 # 3.1 MATHEMATICAL FRAKTUR SMALL G +1D525 ; mapped ; 0068 # 3.1 MATHEMATICAL FRAKTUR SMALL H +1D526 ; mapped ; 0069 # 3.1 MATHEMATICAL FRAKTUR SMALL I +1D527 ; mapped ; 006A # 3.1 MATHEMATICAL FRAKTUR SMALL J +1D528 ; mapped ; 006B # 3.1 MATHEMATICAL FRAKTUR SMALL K +1D529 ; mapped ; 006C # 3.1 MATHEMATICAL FRAKTUR SMALL L +1D52A ; mapped ; 006D # 3.1 MATHEMATICAL FRAKTUR SMALL M +1D52B ; mapped ; 006E # 3.1 MATHEMATICAL FRAKTUR SMALL N +1D52C ; mapped ; 006F # 3.1 MATHEMATICAL FRAKTUR SMALL O +1D52D ; mapped ; 0070 # 3.1 MATHEMATICAL FRAKTUR SMALL P +1D52E ; mapped ; 0071 # 3.1 MATHEMATICAL FRAKTUR SMALL Q +1D52F ; mapped ; 0072 # 3.1 MATHEMATICAL FRAKTUR SMALL R +1D530 ; mapped ; 0073 # 3.1 MATHEMATICAL FRAKTUR SMALL S +1D531 ; mapped ; 0074 # 3.1 MATHEMATICAL FRAKTUR SMALL T +1D532 ; mapped ; 0075 # 3.1 MATHEMATICAL FRAKTUR SMALL U +1D533 ; mapped ; 0076 # 3.1 MATHEMATICAL FRAKTUR SMALL V +1D534 ; mapped ; 0077 # 3.1 MATHEMATICAL FRAKTUR SMALL W +1D535 ; mapped ; 0078 # 3.1 MATHEMATICAL FRAKTUR SMALL X +1D536 ; mapped ; 0079 # 3.1 MATHEMATICAL FRAKTUR SMALL Y +1D537 ; mapped ; 007A # 3.1 MATHEMATICAL FRAKTUR SMALL Z +1D538 ; mapped ; 0061 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL A +1D539 ; mapped ; 0062 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53A ; disallowed # NA +1D53B ; mapped ; 0064 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL D +1D53C ; mapped ; 0065 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL E +1D53D ; mapped ; 0066 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL F +1D53E ; mapped ; 0067 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D53F ; disallowed # NA +1D540 ; mapped ; 0069 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL I +1D541 ; mapped ; 006A # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL J +1D542 ; mapped ; 006B # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL K +1D543 ; mapped ; 006C # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL L +1D544 ; mapped ; 006D # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D545 ; disallowed # NA +1D546 ; mapped ; 006F # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D547..1D549 ; disallowed # NA .. +1D54A ; mapped ; 0073 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL S +1D54B ; mapped ; 0074 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL T +1D54C ; mapped ; 0075 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL U +1D54D ; mapped ; 0076 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL V +1D54E ; mapped ; 0077 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL W +1D54F ; mapped ; 0078 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL X +1D550 ; mapped ; 0079 # 3.1 MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D551 ; disallowed # NA +1D552 ; mapped ; 0061 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL A +1D553 ; mapped ; 0062 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL B +1D554 ; mapped ; 0063 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL C +1D555 ; mapped ; 0064 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL D +1D556 ; mapped ; 0065 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL E +1D557 ; mapped ; 0066 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL F +1D558 ; mapped ; 0067 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL G +1D559 ; mapped ; 0068 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL H +1D55A ; mapped ; 0069 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL I +1D55B ; mapped ; 006A # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL J +1D55C ; mapped ; 006B # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL K +1D55D ; mapped ; 006C # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL L +1D55E ; mapped ; 006D # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL M +1D55F ; mapped ; 006E # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL N +1D560 ; mapped ; 006F # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL O +1D561 ; mapped ; 0070 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL P +1D562 ; mapped ; 0071 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL Q +1D563 ; mapped ; 0072 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL R +1D564 ; mapped ; 0073 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL S +1D565 ; mapped ; 0074 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL T +1D566 ; mapped ; 0075 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL U +1D567 ; mapped ; 0076 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL V +1D568 ; mapped ; 0077 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL W +1D569 ; mapped ; 0078 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL X +1D56A ; mapped ; 0079 # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL Y +1D56B ; mapped ; 007A # 3.1 MATHEMATICAL DOUBLE-STRUCK SMALL Z +1D56C ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL A +1D56D ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL B +1D56E ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL C +1D56F ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL D +1D570 ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL E +1D571 ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL F +1D572 ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL G +1D573 ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL H +1D574 ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL I +1D575 ; mapped ; 006A # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL J +1D576 ; mapped ; 006B # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL K +1D577 ; mapped ; 006C # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL L +1D578 ; mapped ; 006D # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL M +1D579 ; mapped ; 006E # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL N +1D57A ; mapped ; 006F # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL O +1D57B ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL P +1D57C ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL Q +1D57D ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL R +1D57E ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL S +1D57F ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL T +1D580 ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL U +1D581 ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL V +1D582 ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL W +1D583 ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL X +1D584 ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL Y +1D585 ; mapped ; 007A # 3.1 MATHEMATICAL BOLD FRAKTUR CAPITAL Z +1D586 ; mapped ; 0061 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL A +1D587 ; mapped ; 0062 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL B +1D588 ; mapped ; 0063 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL C +1D589 ; mapped ; 0064 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL D +1D58A ; mapped ; 0065 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL E +1D58B ; mapped ; 0066 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL F +1D58C ; mapped ; 0067 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL G +1D58D ; mapped ; 0068 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL H +1D58E ; mapped ; 0069 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL I +1D58F ; mapped ; 006A # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL J +1D590 ; mapped ; 006B # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL K +1D591 ; mapped ; 006C # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL L +1D592 ; mapped ; 006D # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL M +1D593 ; mapped ; 006E # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL N +1D594 ; mapped ; 006F # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL O +1D595 ; mapped ; 0070 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL P +1D596 ; mapped ; 0071 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL Q +1D597 ; mapped ; 0072 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL R +1D598 ; mapped ; 0073 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL S +1D599 ; mapped ; 0074 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL T +1D59A ; mapped ; 0075 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL U +1D59B ; mapped ; 0076 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL V +1D59C ; mapped ; 0077 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL W +1D59D ; mapped ; 0078 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL X +1D59E ; mapped ; 0079 # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL Y +1D59F ; mapped ; 007A # 3.1 MATHEMATICAL BOLD FRAKTUR SMALL Z +1D5A0 ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL A +1D5A1 ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL B +1D5A2 ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL C +1D5A3 ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL D +1D5A4 ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL E +1D5A5 ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL F +1D5A6 ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL G +1D5A7 ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL H +1D5A8 ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL I +1D5A9 ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF CAPITAL J +1D5AA ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF CAPITAL K +1D5AB ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF CAPITAL L +1D5AC ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF CAPITAL M +1D5AD ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF CAPITAL N +1D5AE ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF CAPITAL O +1D5AF ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL P +1D5B0 ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL Q +1D5B1 ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL R +1D5B2 ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL S +1D5B3 ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL T +1D5B4 ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL U +1D5B5 ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL V +1D5B6 ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL W +1D5B7 ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL X +1D5B8 ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF CAPITAL Y +1D5B9 ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF CAPITAL Z +1D5BA ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF SMALL A +1D5BB ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF SMALL B +1D5BC ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF SMALL C +1D5BD ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF SMALL D +1D5BE ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF SMALL E +1D5BF ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF SMALL F +1D5C0 ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF SMALL G +1D5C1 ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF SMALL H +1D5C2 ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF SMALL I +1D5C3 ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF SMALL J +1D5C4 ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF SMALL K +1D5C5 ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF SMALL L +1D5C6 ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF SMALL M +1D5C7 ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF SMALL N +1D5C8 ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF SMALL O +1D5C9 ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF SMALL P +1D5CA ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF SMALL Q +1D5CB ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF SMALL R +1D5CC ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF SMALL S +1D5CD ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF SMALL T +1D5CE ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF SMALL U +1D5CF ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF SMALL V +1D5D0 ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF SMALL W +1D5D1 ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF SMALL X +1D5D2 ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF SMALL Y +1D5D3 ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF SMALL Z +1D5D4 ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL A +1D5D5 ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL B +1D5D6 ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL C +1D5D7 ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL D +1D5D8 ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL E +1D5D9 ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL F +1D5DA ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL G +1D5DB ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL H +1D5DC ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL I +1D5DD ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL J +1D5DE ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL K +1D5DF ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL L +1D5E0 ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL M +1D5E1 ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL N +1D5E2 ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL O +1D5E3 ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL P +1D5E4 ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL Q +1D5E5 ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL R +1D5E6 ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL S +1D5E7 ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL T +1D5E8 ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL U +1D5E9 ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL V +1D5EA ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL W +1D5EB ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL X +1D5EC ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL Y +1D5ED ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL Z +1D5EE ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL A +1D5EF ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL B +1D5F0 ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL C +1D5F1 ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL D +1D5F2 ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL E +1D5F3 ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL F +1D5F4 ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL G +1D5F5 ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL H +1D5F6 ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL I +1D5F7 ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL J +1D5F8 ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL K +1D5F9 ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL L +1D5FA ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL M +1D5FB ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL N +1D5FC ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL O +1D5FD ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL P +1D5FE ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL Q +1D5FF ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL R +1D600 ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL S +1D601 ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL T +1D602 ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL U +1D603 ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL V +1D604 ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL W +1D605 ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL X +1D606 ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL Y +1D607 ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL Z +1D608 ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL A +1D609 ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL B +1D60A ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL C +1D60B ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL D +1D60C ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL E +1D60D ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL F +1D60E ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL G +1D60F ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL H +1D610 ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL I +1D611 ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL J +1D612 ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL K +1D613 ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL L +1D614 ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL M +1D615 ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL N +1D616 ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL O +1D617 ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL P +1D618 ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q +1D619 ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL R +1D61A ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL S +1D61B ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL T +1D61C ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL U +1D61D ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL V +1D61E ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL W +1D61F ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL X +1D620 ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y +1D621 ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z +1D622 ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL A +1D623 ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL B +1D624 ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL C +1D625 ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL D +1D626 ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL E +1D627 ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL F +1D628 ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL G +1D629 ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL H +1D62A ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL I +1D62B ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL J +1D62C ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL K +1D62D ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL L +1D62E ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL M +1D62F ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL N +1D630 ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL O +1D631 ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL P +1D632 ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL Q +1D633 ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL R +1D634 ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL S +1D635 ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL T +1D636 ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL U +1D637 ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL V +1D638 ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL W +1D639 ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL X +1D63A ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL Y +1D63B ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF ITALIC SMALL Z +1D63C ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A +1D63D ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B +1D63E ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C +1D63F ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D +1D640 ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E +1D641 ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F +1D642 ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G +1D643 ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H +1D644 ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I +1D645 ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J +1D646 ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K +1D647 ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L +1D648 ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M +1D649 ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N +1D64A ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O +1D64B ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P +1D64C ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q +1D64D ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R +1D64E ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S +1D64F ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T +1D650 ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U +1D651 ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V +1D652 ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W +1D653 ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X +1D654 ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y +1D655 ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z +1D656 ; mapped ; 0061 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A +1D657 ; mapped ; 0062 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B +1D658 ; mapped ; 0063 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C +1D659 ; mapped ; 0064 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D +1D65A ; mapped ; 0065 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E +1D65B ; mapped ; 0066 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F +1D65C ; mapped ; 0067 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G +1D65D ; mapped ; 0068 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H +1D65E ; mapped ; 0069 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I +1D65F ; mapped ; 006A # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J +1D660 ; mapped ; 006B # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K +1D661 ; mapped ; 006C # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L +1D662 ; mapped ; 006D # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M +1D663 ; mapped ; 006E # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N +1D664 ; mapped ; 006F # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O +1D665 ; mapped ; 0070 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P +1D666 ; mapped ; 0071 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q +1D667 ; mapped ; 0072 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R +1D668 ; mapped ; 0073 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S +1D669 ; mapped ; 0074 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T +1D66A ; mapped ; 0075 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U +1D66B ; mapped ; 0076 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V +1D66C ; mapped ; 0077 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W +1D66D ; mapped ; 0078 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X +1D66E ; mapped ; 0079 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y +1D66F ; mapped ; 007A # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z +1D670 ; mapped ; 0061 # 3.1 MATHEMATICAL MONOSPACE CAPITAL A +1D671 ; mapped ; 0062 # 3.1 MATHEMATICAL MONOSPACE CAPITAL B +1D672 ; mapped ; 0063 # 3.1 MATHEMATICAL MONOSPACE CAPITAL C +1D673 ; mapped ; 0064 # 3.1 MATHEMATICAL MONOSPACE CAPITAL D +1D674 ; mapped ; 0065 # 3.1 MATHEMATICAL MONOSPACE CAPITAL E +1D675 ; mapped ; 0066 # 3.1 MATHEMATICAL MONOSPACE CAPITAL F +1D676 ; mapped ; 0067 # 3.1 MATHEMATICAL MONOSPACE CAPITAL G +1D677 ; mapped ; 0068 # 3.1 MATHEMATICAL MONOSPACE CAPITAL H +1D678 ; mapped ; 0069 # 3.1 MATHEMATICAL MONOSPACE CAPITAL I +1D679 ; mapped ; 006A # 3.1 MATHEMATICAL MONOSPACE CAPITAL J +1D67A ; mapped ; 006B # 3.1 MATHEMATICAL MONOSPACE CAPITAL K +1D67B ; mapped ; 006C # 3.1 MATHEMATICAL MONOSPACE CAPITAL L +1D67C ; mapped ; 006D # 3.1 MATHEMATICAL MONOSPACE CAPITAL M +1D67D ; mapped ; 006E # 3.1 MATHEMATICAL MONOSPACE CAPITAL N +1D67E ; mapped ; 006F # 3.1 MATHEMATICAL MONOSPACE CAPITAL O +1D67F ; mapped ; 0070 # 3.1 MATHEMATICAL MONOSPACE CAPITAL P +1D680 ; mapped ; 0071 # 3.1 MATHEMATICAL MONOSPACE CAPITAL Q +1D681 ; mapped ; 0072 # 3.1 MATHEMATICAL MONOSPACE CAPITAL R +1D682 ; mapped ; 0073 # 3.1 MATHEMATICAL MONOSPACE CAPITAL S +1D683 ; mapped ; 0074 # 3.1 MATHEMATICAL MONOSPACE CAPITAL T +1D684 ; mapped ; 0075 # 3.1 MATHEMATICAL MONOSPACE CAPITAL U +1D685 ; mapped ; 0076 # 3.1 MATHEMATICAL MONOSPACE CAPITAL V +1D686 ; mapped ; 0077 # 3.1 MATHEMATICAL MONOSPACE CAPITAL W +1D687 ; mapped ; 0078 # 3.1 MATHEMATICAL MONOSPACE CAPITAL X +1D688 ; mapped ; 0079 # 3.1 MATHEMATICAL MONOSPACE CAPITAL Y +1D689 ; mapped ; 007A # 3.1 MATHEMATICAL MONOSPACE CAPITAL Z +1D68A ; mapped ; 0061 # 3.1 MATHEMATICAL MONOSPACE SMALL A +1D68B ; mapped ; 0062 # 3.1 MATHEMATICAL MONOSPACE SMALL B +1D68C ; mapped ; 0063 # 3.1 MATHEMATICAL MONOSPACE SMALL C +1D68D ; mapped ; 0064 # 3.1 MATHEMATICAL MONOSPACE SMALL D +1D68E ; mapped ; 0065 # 3.1 MATHEMATICAL MONOSPACE SMALL E +1D68F ; mapped ; 0066 # 3.1 MATHEMATICAL MONOSPACE SMALL F +1D690 ; mapped ; 0067 # 3.1 MATHEMATICAL MONOSPACE SMALL G +1D691 ; mapped ; 0068 # 3.1 MATHEMATICAL MONOSPACE SMALL H +1D692 ; mapped ; 0069 # 3.1 MATHEMATICAL MONOSPACE SMALL I +1D693 ; mapped ; 006A # 3.1 MATHEMATICAL MONOSPACE SMALL J +1D694 ; mapped ; 006B # 3.1 MATHEMATICAL MONOSPACE SMALL K +1D695 ; mapped ; 006C # 3.1 MATHEMATICAL MONOSPACE SMALL L +1D696 ; mapped ; 006D # 3.1 MATHEMATICAL MONOSPACE SMALL M +1D697 ; mapped ; 006E # 3.1 MATHEMATICAL MONOSPACE SMALL N +1D698 ; mapped ; 006F # 3.1 MATHEMATICAL MONOSPACE SMALL O +1D699 ; mapped ; 0070 # 3.1 MATHEMATICAL MONOSPACE SMALL P +1D69A ; mapped ; 0071 # 3.1 MATHEMATICAL MONOSPACE SMALL Q +1D69B ; mapped ; 0072 # 3.1 MATHEMATICAL MONOSPACE SMALL R +1D69C ; mapped ; 0073 # 3.1 MATHEMATICAL MONOSPACE SMALL S +1D69D ; mapped ; 0074 # 3.1 MATHEMATICAL MONOSPACE SMALL T +1D69E ; mapped ; 0075 # 3.1 MATHEMATICAL MONOSPACE SMALL U +1D69F ; mapped ; 0076 # 3.1 MATHEMATICAL MONOSPACE SMALL V +1D6A0 ; mapped ; 0077 # 3.1 MATHEMATICAL MONOSPACE SMALL W +1D6A1 ; mapped ; 0078 # 3.1 MATHEMATICAL MONOSPACE SMALL X +1D6A2 ; mapped ; 0079 # 3.1 MATHEMATICAL MONOSPACE SMALL Y +1D6A3 ; mapped ; 007A # 3.1 MATHEMATICAL MONOSPACE SMALL Z +1D6A4 ; mapped ; 0131 # 4.1 MATHEMATICAL ITALIC SMALL DOTLESS I +1D6A5 ; mapped ; 0237 # 4.1 MATHEMATICAL ITALIC SMALL DOTLESS J +1D6A6..1D6A7 ; disallowed # NA .. +1D6A8 ; mapped ; 03B1 # 3.1 MATHEMATICAL BOLD CAPITAL ALPHA +1D6A9 ; mapped ; 03B2 # 3.1 MATHEMATICAL BOLD CAPITAL BETA +1D6AA ; mapped ; 03B3 # 3.1 MATHEMATICAL BOLD CAPITAL GAMMA +1D6AB ; mapped ; 03B4 # 3.1 MATHEMATICAL BOLD CAPITAL DELTA +1D6AC ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD CAPITAL EPSILON +1D6AD ; mapped ; 03B6 # 3.1 MATHEMATICAL BOLD CAPITAL ZETA +1D6AE ; mapped ; 03B7 # 3.1 MATHEMATICAL BOLD CAPITAL ETA +1D6AF ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD CAPITAL THETA +1D6B0 ; mapped ; 03B9 # 3.1 MATHEMATICAL BOLD CAPITAL IOTA +1D6B1 ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD CAPITAL KAPPA +1D6B2 ; mapped ; 03BB # 3.1 MATHEMATICAL BOLD CAPITAL LAMDA +1D6B3 ; mapped ; 03BC # 3.1 MATHEMATICAL BOLD CAPITAL MU +1D6B4 ; mapped ; 03BD # 3.1 MATHEMATICAL BOLD CAPITAL NU +1D6B5 ; mapped ; 03BE # 3.1 MATHEMATICAL BOLD CAPITAL XI +1D6B6 ; mapped ; 03BF # 3.1 MATHEMATICAL BOLD CAPITAL OMICRON +1D6B7 ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD CAPITAL PI +1D6B8 ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD CAPITAL RHO +1D6B9 ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD CAPITAL THETA SYMBOL +1D6BA ; mapped ; 03C3 # 3.1 MATHEMATICAL BOLD CAPITAL SIGMA +1D6BB ; mapped ; 03C4 # 3.1 MATHEMATICAL BOLD CAPITAL TAU +1D6BC ; mapped ; 03C5 # 3.1 MATHEMATICAL BOLD CAPITAL UPSILON +1D6BD ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD CAPITAL PHI +1D6BE ; mapped ; 03C7 # 3.1 MATHEMATICAL BOLD CAPITAL CHI +1D6BF ; mapped ; 03C8 # 3.1 MATHEMATICAL BOLD CAPITAL PSI +1D6C0 ; mapped ; 03C9 # 3.1 MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1 ; mapped ; 2207 # 3.1 MATHEMATICAL BOLD NABLA +1D6C2 ; mapped ; 03B1 # 3.1 MATHEMATICAL BOLD SMALL ALPHA +1D6C3 ; mapped ; 03B2 # 3.1 MATHEMATICAL BOLD SMALL BETA +1D6C4 ; mapped ; 03B3 # 3.1 MATHEMATICAL BOLD SMALL GAMMA +1D6C5 ; mapped ; 03B4 # 3.1 MATHEMATICAL BOLD SMALL DELTA +1D6C6 ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD SMALL EPSILON +1D6C7 ; mapped ; 03B6 # 3.1 MATHEMATICAL BOLD SMALL ZETA +1D6C8 ; mapped ; 03B7 # 3.1 MATHEMATICAL BOLD SMALL ETA +1D6C9 ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD SMALL THETA +1D6CA ; mapped ; 03B9 # 3.1 MATHEMATICAL BOLD SMALL IOTA +1D6CB ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD SMALL KAPPA +1D6CC ; mapped ; 03BB # 3.1 MATHEMATICAL BOLD SMALL LAMDA +1D6CD ; mapped ; 03BC # 3.1 MATHEMATICAL BOLD SMALL MU +1D6CE ; mapped ; 03BD # 3.1 MATHEMATICAL BOLD SMALL NU +1D6CF ; mapped ; 03BE # 3.1 MATHEMATICAL BOLD SMALL XI +1D6D0 ; mapped ; 03BF # 3.1 MATHEMATICAL BOLD SMALL OMICRON +1D6D1 ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD SMALL PI +1D6D2 ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD SMALL RHO +1D6D3..1D6D4 ; mapped ; 03C3 # 3.1 MATHEMATICAL BOLD SMALL FINAL SIGMA..MATHEMATICAL BOLD SMALL SIGMA +1D6D5 ; mapped ; 03C4 # 3.1 MATHEMATICAL BOLD SMALL TAU +1D6D6 ; mapped ; 03C5 # 3.1 MATHEMATICAL BOLD SMALL UPSILON +1D6D7 ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD SMALL PHI +1D6D8 ; mapped ; 03C7 # 3.1 MATHEMATICAL BOLD SMALL CHI +1D6D9 ; mapped ; 03C8 # 3.1 MATHEMATICAL BOLD SMALL PSI +1D6DA ; mapped ; 03C9 # 3.1 MATHEMATICAL BOLD SMALL OMEGA +1D6DB ; mapped ; 2202 # 3.1 MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD EPSILON SYMBOL +1D6DD ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD THETA SYMBOL +1D6DE ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD KAPPA SYMBOL +1D6DF ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD PHI SYMBOL +1D6E0 ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD RHO SYMBOL +1D6E1 ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD PI SYMBOL +1D6E2 ; mapped ; 03B1 # 3.1 MATHEMATICAL ITALIC CAPITAL ALPHA +1D6E3 ; mapped ; 03B2 # 3.1 MATHEMATICAL ITALIC CAPITAL BETA +1D6E4 ; mapped ; 03B3 # 3.1 MATHEMATICAL ITALIC CAPITAL GAMMA +1D6E5 ; mapped ; 03B4 # 3.1 MATHEMATICAL ITALIC CAPITAL DELTA +1D6E6 ; mapped ; 03B5 # 3.1 MATHEMATICAL ITALIC CAPITAL EPSILON +1D6E7 ; mapped ; 03B6 # 3.1 MATHEMATICAL ITALIC CAPITAL ZETA +1D6E8 ; mapped ; 03B7 # 3.1 MATHEMATICAL ITALIC CAPITAL ETA +1D6E9 ; mapped ; 03B8 # 3.1 MATHEMATICAL ITALIC CAPITAL THETA +1D6EA ; mapped ; 03B9 # 3.1 MATHEMATICAL ITALIC CAPITAL IOTA +1D6EB ; mapped ; 03BA # 3.1 MATHEMATICAL ITALIC CAPITAL KAPPA +1D6EC ; mapped ; 03BB # 3.1 MATHEMATICAL ITALIC CAPITAL LAMDA +1D6ED ; mapped ; 03BC # 3.1 MATHEMATICAL ITALIC CAPITAL MU +1D6EE ; mapped ; 03BD # 3.1 MATHEMATICAL ITALIC CAPITAL NU +1D6EF ; mapped ; 03BE # 3.1 MATHEMATICAL ITALIC CAPITAL XI +1D6F0 ; mapped ; 03BF # 3.1 MATHEMATICAL ITALIC CAPITAL OMICRON +1D6F1 ; mapped ; 03C0 # 3.1 MATHEMATICAL ITALIC CAPITAL PI +1D6F2 ; mapped ; 03C1 # 3.1 MATHEMATICAL ITALIC CAPITAL RHO +1D6F3 ; mapped ; 03B8 # 3.1 MATHEMATICAL ITALIC CAPITAL THETA SYMBOL +1D6F4 ; mapped ; 03C3 # 3.1 MATHEMATICAL ITALIC CAPITAL SIGMA +1D6F5 ; mapped ; 03C4 # 3.1 MATHEMATICAL ITALIC CAPITAL TAU +1D6F6 ; mapped ; 03C5 # 3.1 MATHEMATICAL ITALIC CAPITAL UPSILON +1D6F7 ; mapped ; 03C6 # 3.1 MATHEMATICAL ITALIC CAPITAL PHI +1D6F8 ; mapped ; 03C7 # 3.1 MATHEMATICAL ITALIC CAPITAL CHI +1D6F9 ; mapped ; 03C8 # 3.1 MATHEMATICAL ITALIC CAPITAL PSI +1D6FA ; mapped ; 03C9 # 3.1 MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB ; mapped ; 2207 # 3.1 MATHEMATICAL ITALIC NABLA +1D6FC ; mapped ; 03B1 # 3.1 MATHEMATICAL ITALIC SMALL ALPHA +1D6FD ; mapped ; 03B2 # 3.1 MATHEMATICAL ITALIC SMALL BETA +1D6FE ; mapped ; 03B3 # 3.1 MATHEMATICAL ITALIC SMALL GAMMA +1D6FF ; mapped ; 03B4 # 3.1 MATHEMATICAL ITALIC SMALL DELTA +1D700 ; mapped ; 03B5 # 3.1 MATHEMATICAL ITALIC SMALL EPSILON +1D701 ; mapped ; 03B6 # 3.1 MATHEMATICAL ITALIC SMALL ZETA +1D702 ; mapped ; 03B7 # 3.1 MATHEMATICAL ITALIC SMALL ETA +1D703 ; mapped ; 03B8 # 3.1 MATHEMATICAL ITALIC SMALL THETA +1D704 ; mapped ; 03B9 # 3.1 MATHEMATICAL ITALIC SMALL IOTA +1D705 ; mapped ; 03BA # 3.1 MATHEMATICAL ITALIC SMALL KAPPA +1D706 ; mapped ; 03BB # 3.1 MATHEMATICAL ITALIC SMALL LAMDA +1D707 ; mapped ; 03BC # 3.1 MATHEMATICAL ITALIC SMALL MU +1D708 ; mapped ; 03BD # 3.1 MATHEMATICAL ITALIC SMALL NU +1D709 ; mapped ; 03BE # 3.1 MATHEMATICAL ITALIC SMALL XI +1D70A ; mapped ; 03BF # 3.1 MATHEMATICAL ITALIC SMALL OMICRON +1D70B ; mapped ; 03C0 # 3.1 MATHEMATICAL ITALIC SMALL PI +1D70C ; mapped ; 03C1 # 3.1 MATHEMATICAL ITALIC SMALL RHO +1D70D..1D70E ; mapped ; 03C3 # 3.1 MATHEMATICAL ITALIC SMALL FINAL SIGMA..MATHEMATICAL ITALIC SMALL SIGMA +1D70F ; mapped ; 03C4 # 3.1 MATHEMATICAL ITALIC SMALL TAU +1D710 ; mapped ; 03C5 # 3.1 MATHEMATICAL ITALIC SMALL UPSILON +1D711 ; mapped ; 03C6 # 3.1 MATHEMATICAL ITALIC SMALL PHI +1D712 ; mapped ; 03C7 # 3.1 MATHEMATICAL ITALIC SMALL CHI +1D713 ; mapped ; 03C8 # 3.1 MATHEMATICAL ITALIC SMALL PSI +1D714 ; mapped ; 03C9 # 3.1 MATHEMATICAL ITALIC SMALL OMEGA +1D715 ; mapped ; 2202 # 3.1 MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716 ; mapped ; 03B5 # 3.1 MATHEMATICAL ITALIC EPSILON SYMBOL +1D717 ; mapped ; 03B8 # 3.1 MATHEMATICAL ITALIC THETA SYMBOL +1D718 ; mapped ; 03BA # 3.1 MATHEMATICAL ITALIC KAPPA SYMBOL +1D719 ; mapped ; 03C6 # 3.1 MATHEMATICAL ITALIC PHI SYMBOL +1D71A ; mapped ; 03C1 # 3.1 MATHEMATICAL ITALIC RHO SYMBOL +1D71B ; mapped ; 03C0 # 3.1 MATHEMATICAL ITALIC PI SYMBOL +1D71C ; mapped ; 03B1 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL ALPHA +1D71D ; mapped ; 03B2 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL BETA +1D71E ; mapped ; 03B3 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL GAMMA +1D71F ; mapped ; 03B4 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL DELTA +1D720 ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL EPSILON +1D721 ; mapped ; 03B6 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL ZETA +1D722 ; mapped ; 03B7 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL ETA +1D723 ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL THETA +1D724 ; mapped ; 03B9 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL IOTA +1D725 ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL KAPPA +1D726 ; mapped ; 03BB # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL LAMDA +1D727 ; mapped ; 03BC # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL MU +1D728 ; mapped ; 03BD # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL NU +1D729 ; mapped ; 03BE # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL XI +1D72A ; mapped ; 03BF # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL OMICRON +1D72B ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL PI +1D72C ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL RHO +1D72D ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL +1D72E ; mapped ; 03C3 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL SIGMA +1D72F ; mapped ; 03C4 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL TAU +1D730 ; mapped ; 03C5 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL UPSILON +1D731 ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL PHI +1D732 ; mapped ; 03C7 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL CHI +1D733 ; mapped ; 03C8 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL PSI +1D734 ; mapped ; 03C9 # 3.1 MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735 ; mapped ; 2207 # 3.1 MATHEMATICAL BOLD ITALIC NABLA +1D736 ; mapped ; 03B1 # 3.1 MATHEMATICAL BOLD ITALIC SMALL ALPHA +1D737 ; mapped ; 03B2 # 3.1 MATHEMATICAL BOLD ITALIC SMALL BETA +1D738 ; mapped ; 03B3 # 3.1 MATHEMATICAL BOLD ITALIC SMALL GAMMA +1D739 ; mapped ; 03B4 # 3.1 MATHEMATICAL BOLD ITALIC SMALL DELTA +1D73A ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD ITALIC SMALL EPSILON +1D73B ; mapped ; 03B6 # 3.1 MATHEMATICAL BOLD ITALIC SMALL ZETA +1D73C ; mapped ; 03B7 # 3.1 MATHEMATICAL BOLD ITALIC SMALL ETA +1D73D ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD ITALIC SMALL THETA +1D73E ; mapped ; 03B9 # 3.1 MATHEMATICAL BOLD ITALIC SMALL IOTA +1D73F ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD ITALIC SMALL KAPPA +1D740 ; mapped ; 03BB # 3.1 MATHEMATICAL BOLD ITALIC SMALL LAMDA +1D741 ; mapped ; 03BC # 3.1 MATHEMATICAL BOLD ITALIC SMALL MU +1D742 ; mapped ; 03BD # 3.1 MATHEMATICAL BOLD ITALIC SMALL NU +1D743 ; mapped ; 03BE # 3.1 MATHEMATICAL BOLD ITALIC SMALL XI +1D744 ; mapped ; 03BF # 3.1 MATHEMATICAL BOLD ITALIC SMALL OMICRON +1D745 ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD ITALIC SMALL PI +1D746 ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD ITALIC SMALL RHO +1D747..1D748 ; mapped ; 03C3 # 3.1 MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA..MATHEMATICAL BOLD ITALIC SMALL SIGMA +1D749 ; mapped ; 03C4 # 3.1 MATHEMATICAL BOLD ITALIC SMALL TAU +1D74A ; mapped ; 03C5 # 3.1 MATHEMATICAL BOLD ITALIC SMALL UPSILON +1D74B ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD ITALIC SMALL PHI +1D74C ; mapped ; 03C7 # 3.1 MATHEMATICAL BOLD ITALIC SMALL CHI +1D74D ; mapped ; 03C8 # 3.1 MATHEMATICAL BOLD ITALIC SMALL PSI +1D74E ; mapped ; 03C9 # 3.1 MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F ; mapped ; 2202 # 3.1 MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750 ; mapped ; 03B5 # 3.1 MATHEMATICAL BOLD ITALIC EPSILON SYMBOL +1D751 ; mapped ; 03B8 # 3.1 MATHEMATICAL BOLD ITALIC THETA SYMBOL +1D752 ; mapped ; 03BA # 3.1 MATHEMATICAL BOLD ITALIC KAPPA SYMBOL +1D753 ; mapped ; 03C6 # 3.1 MATHEMATICAL BOLD ITALIC PHI SYMBOL +1D754 ; mapped ; 03C1 # 3.1 MATHEMATICAL BOLD ITALIC RHO SYMBOL +1D755 ; mapped ; 03C0 # 3.1 MATHEMATICAL BOLD ITALIC PI SYMBOL +1D756 ; mapped ; 03B1 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA +1D757 ; mapped ; 03B2 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA +1D758 ; mapped ; 03B3 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA +1D759 ; mapped ; 03B4 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA +1D75A ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON +1D75B ; mapped ; 03B6 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA +1D75C ; mapped ; 03B7 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA +1D75D ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA +1D75E ; mapped ; 03B9 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA +1D75F ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA +1D760 ; mapped ; 03BB # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA +1D761 ; mapped ; 03BC # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL MU +1D762 ; mapped ; 03BD # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL NU +1D763 ; mapped ; 03BE # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL XI +1D764 ; mapped ; 03BF # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON +1D765 ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL PI +1D766 ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO +1D767 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL +1D768 ; mapped ; 03C3 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA +1D769 ; mapped ; 03C4 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU +1D76A ; mapped ; 03C5 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON +1D76B ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI +1D76C ; mapped ; 03C7 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI +1D76D ; mapped ; 03C8 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI +1D76E ; mapped ; 03C9 # 3.1 MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F ; mapped ; 2207 # 3.1 MATHEMATICAL SANS-SERIF BOLD NABLA +1D770 ; mapped ; 03B1 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA +1D771 ; mapped ; 03B2 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL BETA +1D772 ; mapped ; 03B3 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA +1D773 ; mapped ; 03B4 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL DELTA +1D774 ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON +1D775 ; mapped ; 03B6 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL ZETA +1D776 ; mapped ; 03B7 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL ETA +1D777 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL THETA +1D778 ; mapped ; 03B9 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL IOTA +1D779 ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA +1D77A ; mapped ; 03BB # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA +1D77B ; mapped ; 03BC # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL MU +1D77C ; mapped ; 03BD # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL NU +1D77D ; mapped ; 03BE # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL XI +1D77E ; mapped ; 03BF # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON +1D77F ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL PI +1D780 ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL RHO +1D781..1D782 ; mapped ; 03C3 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA..MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA +1D783 ; mapped ; 03C4 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL TAU +1D784 ; mapped ; 03C5 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON +1D785 ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL PHI +1D786 ; mapped ; 03C7 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL CHI +1D787 ; mapped ; 03C8 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL PSI +1D788 ; mapped ; 03C9 # 3.1 MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789 ; mapped ; 2202 # 3.1 MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL +1D78B ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL +1D78C ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL +1D78D ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL +1D78E ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL +1D78F ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD PI SYMBOL +1D790 ; mapped ; 03B1 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA +1D791 ; mapped ; 03B2 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA +1D792 ; mapped ; 03B3 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA +1D793 ; mapped ; 03B4 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA +1D794 ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON +1D795 ; mapped ; 03B6 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA +1D796 ; mapped ; 03B7 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA +1D797 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA +1D798 ; mapped ; 03B9 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA +1D799 ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA +1D79A ; mapped ; 03BB # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA +1D79B ; mapped ; 03BC # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU +1D79C ; mapped ; 03BD # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU +1D79D ; mapped ; 03BE # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI +1D79E ; mapped ; 03BF # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON +1D79F ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI +1D7A0 ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO +1D7A1 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL +1D7A2 ; mapped ; 03C3 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA +1D7A3 ; mapped ; 03C4 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU +1D7A4 ; mapped ; 03C5 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON +1D7A5 ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI +1D7A6 ; mapped ; 03C7 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI +1D7A7 ; mapped ; 03C8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI +1D7A8 ; mapped ; 03C9 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9 ; mapped ; 2207 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA ; mapped ; 03B1 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA +1D7AB ; mapped ; 03B2 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA +1D7AC ; mapped ; 03B3 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA +1D7AD ; mapped ; 03B4 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA +1D7AE ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON +1D7AF ; mapped ; 03B6 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA +1D7B0 ; mapped ; 03B7 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA +1D7B1 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA +1D7B2 ; mapped ; 03B9 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA +1D7B3 ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA +1D7B4 ; mapped ; 03BB # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA +1D7B5 ; mapped ; 03BC # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU +1D7B6 ; mapped ; 03BD # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU +1D7B7 ; mapped ; 03BE # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI +1D7B8 ; mapped ; 03BF # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON +1D7B9 ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI +1D7BA ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO +1D7BB..1D7BC ; mapped ; 03C3 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA +1D7BD ; mapped ; 03C4 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU +1D7BE ; mapped ; 03C5 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON +1D7BF ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI +1D7C0 ; mapped ; 03C7 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI +1D7C1 ; mapped ; 03C8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI +1D7C2 ; mapped ; 03C9 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3 ; mapped ; 2202 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4 ; mapped ; 03B5 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL +1D7C5 ; mapped ; 03B8 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL +1D7C6 ; mapped ; 03BA # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL +1D7C7 ; mapped ; 03C6 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL +1D7C8 ; mapped ; 03C1 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL +1D7C9 ; mapped ; 03C0 # 3.1 MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL +1D7CA..1D7CB ; mapped ; 03DD # 5.0 MATHEMATICAL BOLD CAPITAL DIGAMMA..MATHEMATICAL BOLD SMALL DIGAMMA +1D7CC..1D7CD ; disallowed # NA .. +1D7CE ; mapped ; 0030 # 3.1 MATHEMATICAL BOLD DIGIT ZERO +1D7CF ; mapped ; 0031 # 3.1 MATHEMATICAL BOLD DIGIT ONE +1D7D0 ; mapped ; 0032 # 3.1 MATHEMATICAL BOLD DIGIT TWO +1D7D1 ; mapped ; 0033 # 3.1 MATHEMATICAL BOLD DIGIT THREE +1D7D2 ; mapped ; 0034 # 3.1 MATHEMATICAL BOLD DIGIT FOUR +1D7D3 ; mapped ; 0035 # 3.1 MATHEMATICAL BOLD DIGIT FIVE +1D7D4 ; mapped ; 0036 # 3.1 MATHEMATICAL BOLD DIGIT SIX +1D7D5 ; mapped ; 0037 # 3.1 MATHEMATICAL BOLD DIGIT SEVEN +1D7D6 ; mapped ; 0038 # 3.1 MATHEMATICAL BOLD DIGIT EIGHT +1D7D7 ; mapped ; 0039 # 3.1 MATHEMATICAL BOLD DIGIT NINE +1D7D8 ; mapped ; 0030 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO +1D7D9 ; mapped ; 0031 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT ONE +1D7DA ; mapped ; 0032 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT TWO +1D7DB ; mapped ; 0033 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT THREE +1D7DC ; mapped ; 0034 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR +1D7DD ; mapped ; 0035 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE +1D7DE ; mapped ; 0036 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT SIX +1D7DF ; mapped ; 0037 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN +1D7E0 ; mapped ; 0038 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT +1D7E1 ; mapped ; 0039 # 3.1 MATHEMATICAL DOUBLE-STRUCK DIGIT NINE +1D7E2 ; mapped ; 0030 # 3.1 MATHEMATICAL SANS-SERIF DIGIT ZERO +1D7E3 ; mapped ; 0031 # 3.1 MATHEMATICAL SANS-SERIF DIGIT ONE +1D7E4 ; mapped ; 0032 # 3.1 MATHEMATICAL SANS-SERIF DIGIT TWO +1D7E5 ; mapped ; 0033 # 3.1 MATHEMATICAL SANS-SERIF DIGIT THREE +1D7E6 ; mapped ; 0034 # 3.1 MATHEMATICAL SANS-SERIF DIGIT FOUR +1D7E7 ; mapped ; 0035 # 3.1 MATHEMATICAL SANS-SERIF DIGIT FIVE +1D7E8 ; mapped ; 0036 # 3.1 MATHEMATICAL SANS-SERIF DIGIT SIX +1D7E9 ; mapped ; 0037 # 3.1 MATHEMATICAL SANS-SERIF DIGIT SEVEN +1D7EA ; mapped ; 0038 # 3.1 MATHEMATICAL SANS-SERIF DIGIT EIGHT +1D7EB ; mapped ; 0039 # 3.1 MATHEMATICAL SANS-SERIF DIGIT NINE +1D7EC ; mapped ; 0030 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO +1D7ED ; mapped ; 0031 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT ONE +1D7EE ; mapped ; 0032 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT TWO +1D7EF ; mapped ; 0033 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT THREE +1D7F0 ; mapped ; 0034 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR +1D7F1 ; mapped ; 0035 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE +1D7F2 ; mapped ; 0036 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT SIX +1D7F3 ; mapped ; 0037 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN +1D7F4 ; mapped ; 0038 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT +1D7F5 ; mapped ; 0039 # 3.1 MATHEMATICAL SANS-SERIF BOLD DIGIT NINE +1D7F6 ; mapped ; 0030 # 3.1 MATHEMATICAL MONOSPACE DIGIT ZERO +1D7F7 ; mapped ; 0031 # 3.1 MATHEMATICAL MONOSPACE DIGIT ONE +1D7F8 ; mapped ; 0032 # 3.1 MATHEMATICAL MONOSPACE DIGIT TWO +1D7F9 ; mapped ; 0033 # 3.1 MATHEMATICAL MONOSPACE DIGIT THREE +1D7FA ; mapped ; 0034 # 3.1 MATHEMATICAL MONOSPACE DIGIT FOUR +1D7FB ; mapped ; 0035 # 3.1 MATHEMATICAL MONOSPACE DIGIT FIVE +1D7FC ; mapped ; 0036 # 3.1 MATHEMATICAL MONOSPACE DIGIT SIX +1D7FD ; mapped ; 0037 # 3.1 MATHEMATICAL MONOSPACE DIGIT SEVEN +1D7FE ; mapped ; 0038 # 3.1 MATHEMATICAL MONOSPACE DIGIT EIGHT +1D7FF ; mapped ; 0039 # 3.1 MATHEMATICAL MONOSPACE DIGIT NINE +1D800..1D9FF ; valid ; ; NV8 # 8.0 SIGNWRITING HAND-FIST INDEX..SIGNWRITING HEAD +1DA00..1DA36 ; valid # 8.0 SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +1DA37..1DA3A ; valid ; ; NV8 # 8.0 SIGNWRITING AIR BLOW SMALL ROTATIONS..SIGNWRITING BREATH EXHALE +1DA3B..1DA6C ; valid # 8.0 SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT +1DA6D..1DA74 ; valid ; ; NV8 # 8.0 SIGNWRITING SHOULDER HIP SPINE..SIGNWRITING TORSO-FLOORPLANE TWISTING +1DA75 ; valid # 8.0 SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA76..1DA83 ; valid ; ; NV8 # 8.0 SIGNWRITING LIMB COMBINATION..SIGNWRITING LOCATION DEPTH +1DA84 ; valid # 8.0 SIGNWRITING LOCATION HEAD NECK +1DA85..1DA8B ; valid ; ; NV8 # 8.0 SIGNWRITING LOCATION TORSO..SIGNWRITING PARENTHESIS +1DA8C..1DA9A ; disallowed # NA .. +1DA9B..1DA9F ; valid # 8.0 SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 +1DAA0 ; disallowed # NA +1DAA1..1DAAF ; valid # 8.0 SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1DAB0..1DFFF ; disallowed # NA .. +1E000..1E006 ; valid # 9.0 COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E007 ; disallowed # NA +1E008..1E018 ; valid # 9.0 COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E019..1E01A ; disallowed # NA .. +1E01B..1E021 ; valid # 9.0 COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E022 ; disallowed # NA +1E023..1E024 ; valid # 9.0 COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E025 ; disallowed # NA +1E026..1E02A ; valid # 9.0 COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E02B..1E7FF ; disallowed # NA .. +1E800..1E8C4 ; valid # 7.0 MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E8C5..1E8C6 ; disallowed # NA .. +1E8C7..1E8CF ; valid ; ; NV8 # 7.0 MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE +1E8D0..1E8D6 ; valid # 7.0 MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E8D7..1E8FF ; disallowed # NA .. +1E900 ; mapped ; 1E922 # 9.0 ADLAM CAPITAL LETTER ALIF +1E901 ; mapped ; 1E923 # 9.0 ADLAM CAPITAL LETTER DAALI +1E902 ; mapped ; 1E924 # 9.0 ADLAM CAPITAL LETTER LAAM +1E903 ; mapped ; 1E925 # 9.0 ADLAM CAPITAL LETTER MIIM +1E904 ; mapped ; 1E926 # 9.0 ADLAM CAPITAL LETTER BA +1E905 ; mapped ; 1E927 # 9.0 ADLAM CAPITAL LETTER SINNYIIYHE +1E906 ; mapped ; 1E928 # 9.0 ADLAM CAPITAL LETTER PE +1E907 ; mapped ; 1E929 # 9.0 ADLAM CAPITAL LETTER BHE +1E908 ; mapped ; 1E92A # 9.0 ADLAM CAPITAL LETTER RA +1E909 ; mapped ; 1E92B # 9.0 ADLAM CAPITAL LETTER E +1E90A ; mapped ; 1E92C # 9.0 ADLAM CAPITAL LETTER FA +1E90B ; mapped ; 1E92D # 9.0 ADLAM CAPITAL LETTER I +1E90C ; mapped ; 1E92E # 9.0 ADLAM CAPITAL LETTER O +1E90D ; mapped ; 1E92F # 9.0 ADLAM CAPITAL LETTER DHA +1E90E ; mapped ; 1E930 # 9.0 ADLAM CAPITAL LETTER YHE +1E90F ; mapped ; 1E931 # 9.0 ADLAM CAPITAL LETTER WAW +1E910 ; mapped ; 1E932 # 9.0 ADLAM CAPITAL LETTER NUN +1E911 ; mapped ; 1E933 # 9.0 ADLAM CAPITAL LETTER KAF +1E912 ; mapped ; 1E934 # 9.0 ADLAM CAPITAL LETTER YA +1E913 ; mapped ; 1E935 # 9.0 ADLAM CAPITAL LETTER U +1E914 ; mapped ; 1E936 # 9.0 ADLAM CAPITAL LETTER JIIM +1E915 ; mapped ; 1E937 # 9.0 ADLAM CAPITAL LETTER CHI +1E916 ; mapped ; 1E938 # 9.0 ADLAM CAPITAL LETTER HA +1E917 ; mapped ; 1E939 # 9.0 ADLAM CAPITAL LETTER QAAF +1E918 ; mapped ; 1E93A # 9.0 ADLAM CAPITAL LETTER GA +1E919 ; mapped ; 1E93B # 9.0 ADLAM CAPITAL LETTER NYA +1E91A ; mapped ; 1E93C # 9.0 ADLAM CAPITAL LETTER TU +1E91B ; mapped ; 1E93D # 9.0 ADLAM CAPITAL LETTER NHA +1E91C ; mapped ; 1E93E # 9.0 ADLAM CAPITAL LETTER VA +1E91D ; mapped ; 1E93F # 9.0 ADLAM CAPITAL LETTER KHA +1E91E ; mapped ; 1E940 # 9.0 ADLAM CAPITAL LETTER GBE +1E91F ; mapped ; 1E941 # 9.0 ADLAM CAPITAL LETTER ZAL +1E920 ; mapped ; 1E942 # 9.0 ADLAM CAPITAL LETTER KPO +1E921 ; mapped ; 1E943 # 9.0 ADLAM CAPITAL LETTER SHA +1E922..1E94A ; valid # 9.0 ADLAM SMALL LETTER ALIF..ADLAM NUKTA +1E94B..1E94F ; disallowed # NA .. +1E950..1E959 ; valid # 9.0 ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95A..1E95D ; disallowed # NA .. +1E95E..1E95F ; valid ; ; NV8 # 9.0 ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK +1E960..1EDFF ; disallowed # NA .. +1EE00 ; mapped ; 0627 # 6.1 ARABIC MATHEMATICAL ALEF +1EE01 ; mapped ; 0628 # 6.1 ARABIC MATHEMATICAL BEH +1EE02 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL JEEM +1EE03 ; mapped ; 062F # 6.1 ARABIC MATHEMATICAL DAL +1EE04 ; disallowed # NA +1EE05 ; mapped ; 0648 # 6.1 ARABIC MATHEMATICAL WAW +1EE06 ; mapped ; 0632 # 6.1 ARABIC MATHEMATICAL ZAIN +1EE07 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL HAH +1EE08 ; mapped ; 0637 # 6.1 ARABIC MATHEMATICAL TAH +1EE09 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL YEH +1EE0A ; mapped ; 0643 # 6.1 ARABIC MATHEMATICAL KAF +1EE0B ; mapped ; 0644 # 6.1 ARABIC MATHEMATICAL LAM +1EE0C ; mapped ; 0645 # 6.1 ARABIC MATHEMATICAL MEEM +1EE0D ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL NOON +1EE0E ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL SEEN +1EE0F ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL AIN +1EE10 ; mapped ; 0641 # 6.1 ARABIC MATHEMATICAL FEH +1EE11 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL SAD +1EE12 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL QAF +1EE13 ; mapped ; 0631 # 6.1 ARABIC MATHEMATICAL REH +1EE14 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL SHEEN +1EE15 ; mapped ; 062A # 6.1 ARABIC MATHEMATICAL TEH +1EE16 ; mapped ; 062B # 6.1 ARABIC MATHEMATICAL THEH +1EE17 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL KHAH +1EE18 ; mapped ; 0630 # 6.1 ARABIC MATHEMATICAL THAL +1EE19 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL DAD +1EE1A ; mapped ; 0638 # 6.1 ARABIC MATHEMATICAL ZAH +1EE1B ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL GHAIN +1EE1C ; mapped ; 066E # 6.1 ARABIC MATHEMATICAL DOTLESS BEH +1EE1D ; mapped ; 06BA # 6.1 ARABIC MATHEMATICAL DOTLESS NOON +1EE1E ; mapped ; 06A1 # 6.1 ARABIC MATHEMATICAL DOTLESS FEH +1EE1F ; mapped ; 066F # 6.1 ARABIC MATHEMATICAL DOTLESS QAF +1EE20 ; disallowed # NA +1EE21 ; mapped ; 0628 # 6.1 ARABIC MATHEMATICAL INITIAL BEH +1EE22 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL INITIAL JEEM +1EE23 ; disallowed # NA +1EE24 ; mapped ; 0647 # 6.1 ARABIC MATHEMATICAL INITIAL HEH +1EE25..1EE26 ; disallowed # NA .. +1EE27 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL INITIAL HAH +1EE28 ; disallowed # NA +1EE29 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL INITIAL YEH +1EE2A ; mapped ; 0643 # 6.1 ARABIC MATHEMATICAL INITIAL KAF +1EE2B ; mapped ; 0644 # 6.1 ARABIC MATHEMATICAL INITIAL LAM +1EE2C ; mapped ; 0645 # 6.1 ARABIC MATHEMATICAL INITIAL MEEM +1EE2D ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL INITIAL NOON +1EE2E ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL INITIAL SEEN +1EE2F ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL INITIAL AIN +1EE30 ; mapped ; 0641 # 6.1 ARABIC MATHEMATICAL INITIAL FEH +1EE31 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL INITIAL SAD +1EE32 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL INITIAL QAF +1EE33 ; disallowed # NA +1EE34 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL INITIAL SHEEN +1EE35 ; mapped ; 062A # 6.1 ARABIC MATHEMATICAL INITIAL TEH +1EE36 ; mapped ; 062B # 6.1 ARABIC MATHEMATICAL INITIAL THEH +1EE37 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL INITIAL KHAH +1EE38 ; disallowed # NA +1EE39 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL INITIAL DAD +1EE3A ; disallowed # NA +1EE3B ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL INITIAL GHAIN +1EE3C..1EE41 ; disallowed # NA .. +1EE42 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL TAILED JEEM +1EE43..1EE46 ; disallowed # NA .. +1EE47 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL TAILED HAH +1EE48 ; disallowed # NA +1EE49 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL TAILED YEH +1EE4A ; disallowed # NA +1EE4B ; mapped ; 0644 # 6.1 ARABIC MATHEMATICAL TAILED LAM +1EE4C ; disallowed # NA +1EE4D ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL TAILED NOON +1EE4E ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL TAILED SEEN +1EE4F ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL TAILED AIN +1EE50 ; disallowed # NA +1EE51 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL TAILED SAD +1EE52 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL TAILED QAF +1EE53 ; disallowed # NA +1EE54 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL TAILED SHEEN +1EE55..1EE56 ; disallowed # NA .. +1EE57 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL TAILED KHAH +1EE58 ; disallowed # NA +1EE59 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL TAILED DAD +1EE5A ; disallowed # NA +1EE5B ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL TAILED GHAIN +1EE5C ; disallowed # NA +1EE5D ; mapped ; 06BA # 6.1 ARABIC MATHEMATICAL TAILED DOTLESS NOON +1EE5E ; disallowed # NA +1EE5F ; mapped ; 066F # 6.1 ARABIC MATHEMATICAL TAILED DOTLESS QAF +1EE60 ; disallowed # NA +1EE61 ; mapped ; 0628 # 6.1 ARABIC MATHEMATICAL STRETCHED BEH +1EE62 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL STRETCHED JEEM +1EE63 ; disallowed # NA +1EE64 ; mapped ; 0647 # 6.1 ARABIC MATHEMATICAL STRETCHED HEH +1EE65..1EE66 ; disallowed # NA .. +1EE67 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL STRETCHED HAH +1EE68 ; mapped ; 0637 # 6.1 ARABIC MATHEMATICAL STRETCHED TAH +1EE69 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL STRETCHED YEH +1EE6A ; mapped ; 0643 # 6.1 ARABIC MATHEMATICAL STRETCHED KAF +1EE6B ; disallowed # NA +1EE6C ; mapped ; 0645 # 6.1 ARABIC MATHEMATICAL STRETCHED MEEM +1EE6D ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL STRETCHED NOON +1EE6E ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL STRETCHED SEEN +1EE6F ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL STRETCHED AIN +1EE70 ; mapped ; 0641 # 6.1 ARABIC MATHEMATICAL STRETCHED FEH +1EE71 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL STRETCHED SAD +1EE72 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL STRETCHED QAF +1EE73 ; disallowed # NA +1EE74 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL STRETCHED SHEEN +1EE75 ; mapped ; 062A # 6.1 ARABIC MATHEMATICAL STRETCHED TEH +1EE76 ; mapped ; 062B # 6.1 ARABIC MATHEMATICAL STRETCHED THEH +1EE77 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL STRETCHED KHAH +1EE78 ; disallowed # NA +1EE79 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL STRETCHED DAD +1EE7A ; mapped ; 0638 # 6.1 ARABIC MATHEMATICAL STRETCHED ZAH +1EE7B ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL STRETCHED GHAIN +1EE7C ; mapped ; 066E # 6.1 ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +1EE7D ; disallowed # NA +1EE7E ; mapped ; 06A1 # 6.1 ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +1EE7F ; disallowed # NA +1EE80 ; mapped ; 0627 # 6.1 ARABIC MATHEMATICAL LOOPED ALEF +1EE81 ; mapped ; 0628 # 6.1 ARABIC MATHEMATICAL LOOPED BEH +1EE82 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL LOOPED JEEM +1EE83 ; mapped ; 062F # 6.1 ARABIC MATHEMATICAL LOOPED DAL +1EE84 ; mapped ; 0647 # 6.1 ARABIC MATHEMATICAL LOOPED HEH +1EE85 ; mapped ; 0648 # 6.1 ARABIC MATHEMATICAL LOOPED WAW +1EE86 ; mapped ; 0632 # 6.1 ARABIC MATHEMATICAL LOOPED ZAIN +1EE87 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL LOOPED HAH +1EE88 ; mapped ; 0637 # 6.1 ARABIC MATHEMATICAL LOOPED TAH +1EE89 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL LOOPED YEH +1EE8A ; disallowed # NA +1EE8B ; mapped ; 0644 # 6.1 ARABIC MATHEMATICAL LOOPED LAM +1EE8C ; mapped ; 0645 # 6.1 ARABIC MATHEMATICAL LOOPED MEEM +1EE8D ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL LOOPED NOON +1EE8E ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL LOOPED SEEN +1EE8F ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL LOOPED AIN +1EE90 ; mapped ; 0641 # 6.1 ARABIC MATHEMATICAL LOOPED FEH +1EE91 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL LOOPED SAD +1EE92 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL LOOPED QAF +1EE93 ; mapped ; 0631 # 6.1 ARABIC MATHEMATICAL LOOPED REH +1EE94 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL LOOPED SHEEN +1EE95 ; mapped ; 062A # 6.1 ARABIC MATHEMATICAL LOOPED TEH +1EE96 ; mapped ; 062B # 6.1 ARABIC MATHEMATICAL LOOPED THEH +1EE97 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL LOOPED KHAH +1EE98 ; mapped ; 0630 # 6.1 ARABIC MATHEMATICAL LOOPED THAL +1EE99 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL LOOPED DAD +1EE9A ; mapped ; 0638 # 6.1 ARABIC MATHEMATICAL LOOPED ZAH +1EE9B ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL LOOPED GHAIN +1EE9C..1EEA0 ; disallowed # NA .. +1EEA1 ; mapped ; 0628 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK BEH +1EEA2 ; mapped ; 062C # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM +1EEA3 ; mapped ; 062F # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +1EEA4 ; disallowed # NA +1EEA5 ; mapped ; 0648 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK WAW +1EEA6 ; mapped ; 0632 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN +1EEA7 ; mapped ; 062D # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK HAH +1EEA8 ; mapped ; 0637 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK TAH +1EEA9 ; mapped ; 064A # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +1EEAA ; disallowed # NA +1EEAB ; mapped ; 0644 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK LAM +1EEAC ; mapped ; 0645 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM +1EEAD ; mapped ; 0646 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK NOON +1EEAE ; mapped ; 0633 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN +1EEAF ; mapped ; 0639 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK AIN +1EEB0 ; mapped ; 0641 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK FEH +1EEB1 ; mapped ; 0635 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK SAD +1EEB2 ; mapped ; 0642 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK QAF +1EEB3 ; mapped ; 0631 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK REH +1EEB4 ; mapped ; 0634 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN +1EEB5 ; mapped ; 062A # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK TEH +1EEB6 ; mapped ; 062B # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK THEH +1EEB7 ; mapped ; 062E # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH +1EEB8 ; mapped ; 0630 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK THAL +1EEB9 ; mapped ; 0636 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK DAD +1EEBA ; mapped ; 0638 # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH +1EEBB ; mapped ; 063A # 6.1 ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +1EEBC..1EEEF ; disallowed # NA .. +1EEF0..1EEF1 ; valid ; ; NV8 # 6.1 ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL +1EEF2..1EFFF ; disallowed # NA .. +1F000..1F02B ; valid ; ; NV8 # 5.1 MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F02C..1F02F ; disallowed # NA .. +1F030..1F093 ; valid ; ; NV8 # 5.1 DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 +1F094..1F09F ; disallowed # NA .. +1F0A0..1F0AE ; valid ; ; NV8 # 6.0 PLAYING CARD BACK..PLAYING CARD KING OF SPADES +1F0AF..1F0B0 ; disallowed # NA .. +1F0B1..1F0BE ; valid ; ; NV8 # 6.0 PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS +1F0BF ; valid ; ; NV8 # 7.0 PLAYING CARD RED JOKER +1F0C0 ; disallowed # NA +1F0C1..1F0CF ; valid ; ; NV8 # 6.0 PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER +1F0D0 ; disallowed # NA +1F0D1..1F0DF ; valid ; ; NV8 # 6.0 PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER +1F0E0..1F0F5 ; valid ; ; NV8 # 7.0 PLAYING CARD FOOL..PLAYING CARD TRUMP-21 +1F0F6..1F0FF ; disallowed # NA .. +1F100 ; disallowed # 5.2 DIGIT ZERO FULL STOP +1F101 ; disallowed_STD3_mapped ; 0030 002C # 5.2 DIGIT ZERO COMMA +1F102 ; disallowed_STD3_mapped ; 0031 002C # 5.2 DIGIT ONE COMMA +1F103 ; disallowed_STD3_mapped ; 0032 002C # 5.2 DIGIT TWO COMMA +1F104 ; disallowed_STD3_mapped ; 0033 002C # 5.2 DIGIT THREE COMMA +1F105 ; disallowed_STD3_mapped ; 0034 002C # 5.2 DIGIT FOUR COMMA +1F106 ; disallowed_STD3_mapped ; 0035 002C # 5.2 DIGIT FIVE COMMA +1F107 ; disallowed_STD3_mapped ; 0036 002C # 5.2 DIGIT SIX COMMA +1F108 ; disallowed_STD3_mapped ; 0037 002C # 5.2 DIGIT SEVEN COMMA +1F109 ; disallowed_STD3_mapped ; 0038 002C # 5.2 DIGIT EIGHT COMMA +1F10A ; disallowed_STD3_mapped ; 0039 002C # 5.2 DIGIT NINE COMMA +1F10B..1F10C ; valid ; ; NV8 # 7.0 DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO +1F10D..1F10F ; disallowed # NA .. +1F110 ; disallowed_STD3_mapped ; 0028 0061 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER A +1F111 ; disallowed_STD3_mapped ; 0028 0062 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER B +1F112 ; disallowed_STD3_mapped ; 0028 0063 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER C +1F113 ; disallowed_STD3_mapped ; 0028 0064 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER D +1F114 ; disallowed_STD3_mapped ; 0028 0065 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER E +1F115 ; disallowed_STD3_mapped ; 0028 0066 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER F +1F116 ; disallowed_STD3_mapped ; 0028 0067 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER G +1F117 ; disallowed_STD3_mapped ; 0028 0068 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER H +1F118 ; disallowed_STD3_mapped ; 0028 0069 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER I +1F119 ; disallowed_STD3_mapped ; 0028 006A 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER J +1F11A ; disallowed_STD3_mapped ; 0028 006B 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER K +1F11B ; disallowed_STD3_mapped ; 0028 006C 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER L +1F11C ; disallowed_STD3_mapped ; 0028 006D 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER M +1F11D ; disallowed_STD3_mapped ; 0028 006E 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER N +1F11E ; disallowed_STD3_mapped ; 0028 006F 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER O +1F11F ; disallowed_STD3_mapped ; 0028 0070 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER P +1F120 ; disallowed_STD3_mapped ; 0028 0071 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER Q +1F121 ; disallowed_STD3_mapped ; 0028 0072 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER R +1F122 ; disallowed_STD3_mapped ; 0028 0073 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER S +1F123 ; disallowed_STD3_mapped ; 0028 0074 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER T +1F124 ; disallowed_STD3_mapped ; 0028 0075 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER U +1F125 ; disallowed_STD3_mapped ; 0028 0076 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER V +1F126 ; disallowed_STD3_mapped ; 0028 0077 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER W +1F127 ; disallowed_STD3_mapped ; 0028 0078 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER X +1F128 ; disallowed_STD3_mapped ; 0028 0079 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER Y +1F129 ; disallowed_STD3_mapped ; 0028 007A 0029 #5.2 PARENTHESIZED LATIN CAPITAL LETTER Z +1F12A ; mapped ; 3014 0073 3015 #5.2 TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S +1F12B ; mapped ; 0063 # 5.2 CIRCLED ITALIC LATIN CAPITAL LETTER C +1F12C ; mapped ; 0072 # 5.2 CIRCLED ITALIC LATIN CAPITAL LETTER R +1F12D ; mapped ; 0063 0064 # 5.2 CIRCLED CD +1F12E ; mapped ; 0077 007A # 5.2 CIRCLED WZ +1F12F ; disallowed # NA +1F130 ; mapped ; 0061 # 6.0 SQUARED LATIN CAPITAL LETTER A +1F131 ; mapped ; 0062 # 5.2 SQUARED LATIN CAPITAL LETTER B +1F132 ; mapped ; 0063 # 6.0 SQUARED LATIN CAPITAL LETTER C +1F133 ; mapped ; 0064 # 6.0 SQUARED LATIN CAPITAL LETTER D +1F134 ; mapped ; 0065 # 6.0 SQUARED LATIN CAPITAL LETTER E +1F135 ; mapped ; 0066 # 6.0 SQUARED LATIN CAPITAL LETTER F +1F136 ; mapped ; 0067 # 6.0 SQUARED LATIN CAPITAL LETTER G +1F137 ; mapped ; 0068 # 6.0 SQUARED LATIN CAPITAL LETTER H +1F138 ; mapped ; 0069 # 6.0 SQUARED LATIN CAPITAL LETTER I +1F139 ; mapped ; 006A # 6.0 SQUARED LATIN CAPITAL LETTER J +1F13A ; mapped ; 006B # 6.0 SQUARED LATIN CAPITAL LETTER K +1F13B ; mapped ; 006C # 6.0 SQUARED LATIN CAPITAL LETTER L +1F13C ; mapped ; 006D # 6.0 SQUARED LATIN CAPITAL LETTER M +1F13D ; mapped ; 006E # 5.2 SQUARED LATIN CAPITAL LETTER N +1F13E ; mapped ; 006F # 6.0 SQUARED LATIN CAPITAL LETTER O +1F13F ; mapped ; 0070 # 5.2 SQUARED LATIN CAPITAL LETTER P +1F140 ; mapped ; 0071 # 6.0 SQUARED LATIN CAPITAL LETTER Q +1F141 ; mapped ; 0072 # 6.0 SQUARED LATIN CAPITAL LETTER R +1F142 ; mapped ; 0073 # 5.2 SQUARED LATIN CAPITAL LETTER S +1F143 ; mapped ; 0074 # 6.0 SQUARED LATIN CAPITAL LETTER T +1F144 ; mapped ; 0075 # 6.0 SQUARED LATIN CAPITAL LETTER U +1F145 ; mapped ; 0076 # 6.0 SQUARED LATIN CAPITAL LETTER V +1F146 ; mapped ; 0077 # 5.2 SQUARED LATIN CAPITAL LETTER W +1F147 ; mapped ; 0078 # 6.0 SQUARED LATIN CAPITAL LETTER X +1F148 ; mapped ; 0079 # 6.0 SQUARED LATIN CAPITAL LETTER Y +1F149 ; mapped ; 007A # 6.0 SQUARED LATIN CAPITAL LETTER Z +1F14A ; mapped ; 0068 0076 # 5.2 SQUARED HV +1F14B ; mapped ; 006D 0076 # 5.2 SQUARED MV +1F14C ; mapped ; 0073 0064 # 5.2 SQUARED SD +1F14D ; mapped ; 0073 0073 # 5.2 SQUARED SS +1F14E ; mapped ; 0070 0070 0076 #5.2 SQUARED PPV +1F14F ; mapped ; 0077 0063 # 6.0 SQUARED WC +1F150..1F156 ; valid ; ; NV8 # 6.0 NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER G +1F157 ; valid ; ; NV8 # 5.2 NEGATIVE CIRCLED LATIN CAPITAL LETTER H +1F158..1F15E ; valid ; ; NV8 # 6.0 NEGATIVE CIRCLED LATIN CAPITAL LETTER I..NEGATIVE CIRCLED LATIN CAPITAL LETTER O +1F15F ; valid ; ; NV8 # 5.2 NEGATIVE CIRCLED LATIN CAPITAL LETTER P +1F160..1F169 ; valid ; ; NV8 # 6.0 NEGATIVE CIRCLED LATIN CAPITAL LETTER Q..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1F16A ; mapped ; 006D 0063 # 6.1 RAISED MC SIGN +1F16B ; mapped ; 006D 0064 # 6.1 RAISED MD SIGN +1F16C..1F16F ; disallowed # NA .. +1F170..1F178 ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER I +1F179 ; valid ; ; NV8 # 5.2 NEGATIVE SQUARED LATIN CAPITAL LETTER J +1F17A ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED LATIN CAPITAL LETTER K +1F17B..1F17C ; valid ; ; NV8 # 5.2 NEGATIVE SQUARED LATIN CAPITAL LETTER L..NEGATIVE SQUARED LATIN CAPITAL LETTER M +1F17D..1F17E ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED LATIN CAPITAL LETTER N..NEGATIVE SQUARED LATIN CAPITAL LETTER O +1F17F ; valid ; ; NV8 # 5.2 NEGATIVE SQUARED LATIN CAPITAL LETTER P +1F180..1F189 ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED LATIN CAPITAL LETTER Q..NEGATIVE SQUARED LATIN CAPITAL LETTER Z +1F18A..1F18D ; valid ; ; NV8 # 5.2 CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P..NEGATIVE SQUARED SA +1F18E..1F18F ; valid ; ; NV8 # 6.0 NEGATIVE SQUARED AB..NEGATIVE SQUARED WC +1F190 ; mapped ; 0064 006A # 5.2 SQUARE DJ +1F191..1F19A ; valid ; ; NV8 # 6.0 SQUARED CL..SQUARED VS +1F19B..1F1AC ; valid ; ; NV8 # 9.0 SQUARED THREE D..SQUARED VOD +1F1AD..1F1E5 ; disallowed # NA .. +1F1E6..1F1FF ; valid ; ; NV8 # 6.0 REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z +1F200 ; mapped ; 307B 304B # 5.2 SQUARE HIRAGANA HOKA +1F201 ; mapped ; 30B3 30B3 # 6.0 SQUARED KATAKANA KOKO +1F202 ; mapped ; 30B5 # 6.0 SQUARED KATAKANA SA +1F203..1F20F ; disallowed # NA .. +1F210 ; mapped ; 624B # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-624B +1F211 ; mapped ; 5B57 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-5B57 +1F212 ; mapped ; 53CC # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-53CC +1F213 ; mapped ; 30C7 # 5.2 SQUARED KATAKANA DE +1F214 ; mapped ; 4E8C # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-4E8C +1F215 ; mapped ; 591A # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-591A +1F216 ; mapped ; 89E3 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-89E3 +1F217 ; mapped ; 5929 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-5929 +1F218 ; mapped ; 4EA4 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-4EA4 +1F219 ; mapped ; 6620 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6620 +1F21A ; mapped ; 7121 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-7121 +1F21B ; mapped ; 6599 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6599 +1F21C ; mapped ; 524D # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-524D +1F21D ; mapped ; 5F8C # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-5F8C +1F21E ; mapped ; 518D # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-518D +1F21F ; mapped ; 65B0 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-65B0 +1F220 ; mapped ; 521D # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-521D +1F221 ; mapped ; 7D42 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-7D42 +1F222 ; mapped ; 751F # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-751F +1F223 ; mapped ; 8CA9 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-8CA9 +1F224 ; mapped ; 58F0 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-58F0 +1F225 ; mapped ; 5439 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-5439 +1F226 ; mapped ; 6F14 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6F14 +1F227 ; mapped ; 6295 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6295 +1F228 ; mapped ; 6355 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6355 +1F229 ; mapped ; 4E00 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-4E00 +1F22A ; mapped ; 4E09 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-4E09 +1F22B ; mapped ; 904A # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-904A +1F22C ; mapped ; 5DE6 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-5DE6 +1F22D ; mapped ; 4E2D # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-4E2D +1F22E ; mapped ; 53F3 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-53F3 +1F22F ; mapped ; 6307 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6307 +1F230 ; mapped ; 8D70 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-8D70 +1F231 ; mapped ; 6253 # 5.2 SQUARED CJK UNIFIED IDEOGRAPH-6253 +1F232 ; mapped ; 7981 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-7981 +1F233 ; mapped ; 7A7A # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-7A7A +1F234 ; mapped ; 5408 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-5408 +1F235 ; mapped ; 6E80 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-6E80 +1F236 ; mapped ; 6709 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-6709 +1F237 ; mapped ; 6708 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-6708 +1F238 ; mapped ; 7533 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-7533 +1F239 ; mapped ; 5272 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-5272 +1F23A ; mapped ; 55B6 # 6.0 SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F23B ; mapped ; 914D # 9.0 SQUARED CJK UNIFIED IDEOGRAPH-914D +1F23C..1F23F ; disallowed # NA .. +1F240 ; mapped ; 3014 672C 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C +1F241 ; mapped ; 3014 4E09 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 +1F242 ; mapped ; 3014 4E8C 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C +1F243 ; mapped ; 3014 5B89 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89 +1F244 ; mapped ; 3014 70B9 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9 +1F245 ; mapped ; 3014 6253 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253 +1F246 ; mapped ; 3014 76D7 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7 +1F247 ; mapped ; 3014 52DD 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD +1F248 ; mapped ; 3014 6557 3015 #5.2 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +1F249..1F24F ; disallowed # NA .. +1F250 ; mapped ; 5F97 # 6.0 CIRCLED IDEOGRAPH ADVANTAGE +1F251 ; mapped ; 53EF # 6.0 CIRCLED IDEOGRAPH ACCEPT +1F252..1F25F ; disallowed # NA .. +1F260..1F265 ; valid ; ; NV8 # 10.0 ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F266..1F2FF ; disallowed # NA .. +1F300..1F320 ; valid ; ; NV8 # 6.0 CYCLONE..SHOOTING STAR +1F321..1F32C ; valid ; ; NV8 # 7.0 THERMOMETER..WIND BLOWING FACE +1F32D..1F32F ; valid ; ; NV8 # 8.0 HOT DOG..BURRITO +1F330..1F335 ; valid ; ; NV8 # 6.0 CHESTNUT..CACTUS +1F336 ; valid ; ; NV8 # 7.0 HOT PEPPER +1F337..1F37C ; valid ; ; NV8 # 6.0 TULIP..BABY BOTTLE +1F37D ; valid ; ; NV8 # 7.0 FORK AND KNIFE WITH PLATE +1F37E..1F37F ; valid ; ; NV8 # 8.0 BOTTLE WITH POPPING CORK..POPCORN +1F380..1F393 ; valid ; ; NV8 # 6.0 RIBBON..GRADUATION CAP +1F394..1F39F ; valid ; ; NV8 # 7.0 HEART WITH TIP ON THE LEFT..ADMISSION TICKETS +1F3A0..1F3C4 ; valid ; ; NV8 # 6.0 CAROUSEL HORSE..SURFER +1F3C5 ; valid ; ; NV8 # 7.0 SPORTS MEDAL +1F3C6..1F3CA ; valid ; ; NV8 # 6.0 TROPHY..SWIMMER +1F3CB..1F3CE ; valid ; ; NV8 # 7.0 WEIGHT LIFTER..RACING CAR +1F3CF..1F3D3 ; valid ; ; NV8 # 8.0 CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL +1F3D4..1F3DF ; valid ; ; NV8 # 7.0 SNOW CAPPED MOUNTAIN..STADIUM +1F3E0..1F3F0 ; valid ; ; NV8 # 6.0 HOUSE BUILDING..EUROPEAN CASTLE +1F3F1..1F3F7 ; valid ; ; NV8 # 7.0 WHITE PENNANT..LABEL +1F3F8..1F3FF ; valid ; ; NV8 # 8.0 BADMINTON RACQUET AND SHUTTLECOCK..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F43E ; valid ; ; NV8 # 6.0 RAT..PAW PRINTS +1F43F ; valid ; ; NV8 # 7.0 CHIPMUNK +1F440 ; valid ; ; NV8 # 6.0 EYES +1F441 ; valid ; ; NV8 # 7.0 EYE +1F442..1F4F7 ; valid ; ; NV8 # 6.0 EAR..CAMERA +1F4F8 ; valid ; ; NV8 # 7.0 CAMERA WITH FLASH +1F4F9..1F4FC ; valid ; ; NV8 # 6.0 VIDEO CAMERA..VIDEOCASSETTE +1F4FD..1F4FE ; valid ; ; NV8 # 7.0 FILM PROJECTOR..PORTABLE STEREO +1F4FF ; valid ; ; NV8 # 8.0 PRAYER BEADS +1F500..1F53D ; valid ; ; NV8 # 6.0 TWISTED RIGHTWARDS ARROWS..DOWN-POINTING SMALL RED TRIANGLE +1F53E..1F53F ; valid ; ; NV8 # 7.0 LOWER RIGHT SHADOWED WHITE CIRCLE..UPPER RIGHT SHADOWED WHITE CIRCLE +1F540..1F543 ; valid ; ; NV8 # 6.1 CIRCLED CROSS POMMEE..NOTCHED LEFT SEMICIRCLE WITH THREE DOTS +1F544..1F54A ; valid ; ; NV8 # 7.0 NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS..DOVE OF PEACE +1F54B..1F54F ; valid ; ; NV8 # 8.0 KAABA..BOWL OF HYGIEIA +1F550..1F567 ; valid ; ; NV8 # 6.0 CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY +1F568..1F579 ; valid ; ; NV8 # 7.0 RIGHT SPEAKER..JOYSTICK +1F57A ; valid ; ; NV8 # 9.0 MAN DANCING +1F57B..1F5A3 ; valid ; ; NV8 # 7.0 LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX +1F5A4 ; valid ; ; NV8 # 9.0 BLACK HEART +1F5A5..1F5FA ; valid ; ; NV8 # 7.0 DESKTOP COMPUTER..WORLD MAP +1F5FB..1F5FF ; valid ; ; NV8 # 6.0 MOUNT FUJI..MOYAI +1F600 ; valid ; ; NV8 # 6.1 GRINNING FACE +1F601..1F610 ; valid ; ; NV8 # 6.0 GRINNING FACE WITH SMILING EYES..NEUTRAL FACE +1F611 ; valid ; ; NV8 # 6.1 EXPRESSIONLESS FACE +1F612..1F614 ; valid ; ; NV8 # 6.0 UNAMUSED FACE..PENSIVE FACE +1F615 ; valid ; ; NV8 # 6.1 CONFUSED FACE +1F616 ; valid ; ; NV8 # 6.0 CONFOUNDED FACE +1F617 ; valid ; ; NV8 # 6.1 KISSING FACE +1F618 ; valid ; ; NV8 # 6.0 FACE THROWING A KISS +1F619 ; valid ; ; NV8 # 6.1 KISSING FACE WITH SMILING EYES +1F61A ; valid ; ; NV8 # 6.0 KISSING FACE WITH CLOSED EYES +1F61B ; valid ; ; NV8 # 6.1 FACE WITH STUCK-OUT TONGUE +1F61C..1F61E ; valid ; ; NV8 # 6.0 FACE WITH STUCK-OUT TONGUE AND WINKING EYE..DISAPPOINTED FACE +1F61F ; valid ; ; NV8 # 6.1 WORRIED FACE +1F620..1F625 ; valid ; ; NV8 # 6.0 ANGRY FACE..DISAPPOINTED BUT RELIEVED FACE +1F626..1F627 ; valid ; ; NV8 # 6.1 FROWNING FACE WITH OPEN MOUTH..ANGUISHED FACE +1F628..1F62B ; valid ; ; NV8 # 6.0 FEARFUL FACE..TIRED FACE +1F62C ; valid ; ; NV8 # 6.1 GRIMACING FACE +1F62D ; valid ; ; NV8 # 6.0 LOUDLY CRYING FACE +1F62E..1F62F ; valid ; ; NV8 # 6.1 FACE WITH OPEN MOUTH..HUSHED FACE +1F630..1F633 ; valid ; ; NV8 # 6.0 FACE WITH OPEN MOUTH AND COLD SWEAT..FLUSHED FACE +1F634 ; valid ; ; NV8 # 6.1 SLEEPING FACE +1F635..1F640 ; valid ; ; NV8 # 6.0 DIZZY FACE..WEARY CAT FACE +1F641..1F642 ; valid ; ; NV8 # 7.0 SLIGHTLY FROWNING FACE..SLIGHTLY SMILING FACE +1F643..1F644 ; valid ; ; NV8 # 8.0 UPSIDE-DOWN FACE..FACE WITH ROLLING EYES +1F645..1F64F ; valid ; ; NV8 # 6.0 FACE WITH NO GOOD GESTURE..PERSON WITH FOLDED HANDS +1F650..1F67F ; valid ; ; NV8 # 7.0 NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD +1F680..1F6C5 ; valid ; ; NV8 # 6.0 ROCKET..LEFT LUGGAGE +1F6C6..1F6CF ; valid ; ; NV8 # 7.0 TRIANGLE WITH ROUNDED CORNERS..BED +1F6D0 ; valid ; ; NV8 # 8.0 PLACE OF WORSHIP +1F6D1..1F6D2 ; valid ; ; NV8 # 9.0 OCTAGONAL SIGN..SHOPPING TROLLEY +1F6D3..1F6D4 ; valid ; ; NV8 # 10.0 STUPA..PAGODA +1F6D5..1F6DF ; disallowed # NA .. +1F6E0..1F6EC ; valid ; ; NV8 # 7.0 HAMMER AND WRENCH..AIRPLANE ARRIVING +1F6ED..1F6EF ; disallowed # NA .. +1F6F0..1F6F3 ; valid ; ; NV8 # 7.0 SATELLITE..PASSENGER SHIP +1F6F4..1F6F6 ; valid ; ; NV8 # 9.0 SCOOTER..CANOE +1F6F7..1F6F8 ; valid ; ; NV8 # 10.0 SLED..FLYING SAUCER +1F6F9..1F6FF ; disallowed # NA .. +1F700..1F773 ; valid ; ; NV8 # 6.0 ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE +1F774..1F77F ; disallowed # NA .. +1F780..1F7D4 ; valid ; ; NV8 # 7.0 BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR +1F7D5..1F7FF ; disallowed # NA .. +1F800..1F80B ; valid ; ; NV8 # 7.0 LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F80C..1F80F ; disallowed # NA .. +1F810..1F847 ; valid ; ; NV8 # 7.0 LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F848..1F84F ; disallowed # NA .. +1F850..1F859 ; valid ; ; NV8 # 7.0 LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F85A..1F85F ; disallowed # NA .. +1F860..1F887 ; valid ; ; NV8 # 7.0 WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F888..1F88F ; disallowed # NA .. +1F890..1F8AD ; valid ; ; NV8 # 7.0 LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS +1F8AE..1F8FF ; disallowed # NA .. +1F900..1F90B ; valid ; ; NV8 # 10.0 CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F90C..1F90F ; disallowed # NA .. +1F910..1F918 ; valid ; ; NV8 # 8.0 ZIPPER-MOUTH FACE..SIGN OF THE HORNS +1F919..1F91E ; valid ; ; NV8 # 9.0 CALL ME HAND..HAND WITH INDEX AND MIDDLE FINGERS CROSSED +1F91F ; valid ; ; NV8 # 10.0 I LOVE YOU HAND SIGN +1F920..1F927 ; valid ; ; NV8 # 9.0 FACE WITH COWBOY HAT..SNEEZING FACE +1F928..1F92F ; valid ; ; NV8 # 10.0 FACE WITH ONE EYEBROW RAISED..SHOCKED FACE WITH EXPLODING HEAD +1F930 ; valid ; ; NV8 # 9.0 PREGNANT WOMAN +1F931..1F932 ; valid ; ; NV8 # 10.0 BREAST-FEEDING..PALMS UP TOGETHER +1F933..1F93E ; valid ; ; NV8 # 9.0 SELFIE..HANDBALL +1F93F ; disallowed # NA +1F940..1F94B ; valid ; ; NV8 # 9.0 WILTED FLOWER..MARTIAL ARTS UNIFORM +1F94C ; valid ; ; NV8 # 10.0 CURLING STONE +1F94D..1F94F ; disallowed # NA .. +1F950..1F95E ; valid ; ; NV8 # 9.0 CROISSANT..PANCAKES +1F95F..1F96B ; valid ; ; NV8 # 10.0 DUMPLING..CANNED FOOD +1F96C..1F97F ; disallowed # NA .. +1F980..1F984 ; valid ; ; NV8 # 8.0 CRAB..UNICORN FACE +1F985..1F991 ; valid ; ; NV8 # 9.0 EAGLE..SQUID +1F992..1F997 ; valid ; ; NV8 # 10.0 GIRAFFE FACE..CRICKET +1F998..1F9BF ; disallowed # NA .. +1F9C0 ; valid ; ; NV8 # 8.0 CHEESE WEDGE +1F9C1..1F9CF ; disallowed # NA .. +1F9D0..1F9E6 ; valid ; ; NV8 # 10.0 FACE WITH MONOCLE..SOCKS +1F9E7..1FFFD ; disallowed # NA .. +1FFFE..1FFFF ; disallowed # 2.0 .. +20000..2A6D6 ; valid # 3.1 CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 +2A6D7..2A6FF ; disallowed # NA .. +2A700..2B734 ; valid # 5.2 CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 +2B735..2B73F ; disallowed # NA .. +2B740..2B81D ; valid # 6.0 CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D +2B81E..2B81F ; disallowed # NA .. +2B820..2CEA1 ; valid # 8.0 CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEA2..2CEAF ; disallowed # NA .. +2CEB0..2EBE0 ; valid # 10.0 CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBE1..2F7FF ; disallowed # NA .. +2F800 ; mapped ; 4E3D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F800 +2F801 ; mapped ; 4E38 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F801 +2F802 ; mapped ; 4E41 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F802 +2F803 ; mapped ; 20122 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F803 +2F804 ; mapped ; 4F60 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F804 +2F805 ; mapped ; 4FAE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F805 +2F806 ; mapped ; 4FBB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F806 +2F807 ; mapped ; 5002 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F807 +2F808 ; mapped ; 507A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F808 +2F809 ; mapped ; 5099 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F809 +2F80A ; mapped ; 50E7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80A +2F80B ; mapped ; 50CF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80B +2F80C ; mapped ; 349E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80C +2F80D ; mapped ; 2063A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80D +2F80E ; mapped ; 514D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80E +2F80F ; mapped ; 5154 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F80F +2F810 ; mapped ; 5164 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F810 +2F811 ; mapped ; 5177 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F811 +2F812 ; mapped ; 2051C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F812 +2F813 ; mapped ; 34B9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F813 +2F814 ; mapped ; 5167 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F814 +2F815 ; mapped ; 518D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F815 +2F816 ; mapped ; 2054B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F816 +2F817 ; mapped ; 5197 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F817 +2F818 ; mapped ; 51A4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F818 +2F819 ; mapped ; 4ECC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F819 +2F81A ; mapped ; 51AC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81A +2F81B ; mapped ; 51B5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81B +2F81C ; mapped ; 291DF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81C +2F81D ; mapped ; 51F5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81D +2F81E ; mapped ; 5203 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81E +2F81F ; mapped ; 34DF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F81F +2F820 ; mapped ; 523B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F820 +2F821 ; mapped ; 5246 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F821 +2F822 ; mapped ; 5272 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F822 +2F823 ; mapped ; 5277 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F823 +2F824 ; mapped ; 3515 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F824 +2F825 ; mapped ; 52C7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F825 +2F826 ; mapped ; 52C9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F826 +2F827 ; mapped ; 52E4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F827 +2F828 ; mapped ; 52FA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F828 +2F829 ; mapped ; 5305 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F829 +2F82A ; mapped ; 5306 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82A +2F82B ; mapped ; 5317 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82B +2F82C ; mapped ; 5349 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82C +2F82D ; mapped ; 5351 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82D +2F82E ; mapped ; 535A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82E +2F82F ; mapped ; 5373 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F82F +2F830 ; mapped ; 537D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F830 +2F831..2F833 ; mapped ; 537F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F831..CJK COMPATIBILITY IDEOGRAPH-2F833 +2F834 ; mapped ; 20A2C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F834 +2F835 ; mapped ; 7070 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F835 +2F836 ; mapped ; 53CA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F836 +2F837 ; mapped ; 53DF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F837 +2F838 ; mapped ; 20B63 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F838 +2F839 ; mapped ; 53EB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F839 +2F83A ; mapped ; 53F1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83A +2F83B ; mapped ; 5406 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83B +2F83C ; mapped ; 549E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83C +2F83D ; mapped ; 5438 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83D +2F83E ; mapped ; 5448 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83E +2F83F ; mapped ; 5468 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F83F +2F840 ; mapped ; 54A2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F840 +2F841 ; mapped ; 54F6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F841 +2F842 ; mapped ; 5510 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F842 +2F843 ; mapped ; 5553 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F843 +2F844 ; mapped ; 5563 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F844 +2F845..2F846 ; mapped ; 5584 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F845..CJK COMPATIBILITY IDEOGRAPH-2F846 +2F847 ; mapped ; 5599 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F847 +2F848 ; mapped ; 55AB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F848 +2F849 ; mapped ; 55B3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F849 +2F84A ; mapped ; 55C2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84A +2F84B ; mapped ; 5716 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84B +2F84C ; mapped ; 5606 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84C +2F84D ; mapped ; 5717 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84D +2F84E ; mapped ; 5651 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84E +2F84F ; mapped ; 5674 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F84F +2F850 ; mapped ; 5207 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F850 +2F851 ; mapped ; 58EE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F851 +2F852 ; mapped ; 57CE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F852 +2F853 ; mapped ; 57F4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F853 +2F854 ; mapped ; 580D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F854 +2F855 ; mapped ; 578B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F855 +2F856 ; mapped ; 5832 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F856 +2F857 ; mapped ; 5831 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F857 +2F858 ; mapped ; 58AC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F858 +2F859 ; mapped ; 214E4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F859 +2F85A ; mapped ; 58F2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85A +2F85B ; mapped ; 58F7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85B +2F85C ; mapped ; 5906 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85C +2F85D ; mapped ; 591A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85D +2F85E ; mapped ; 5922 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85E +2F85F ; mapped ; 5962 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F85F +2F860 ; mapped ; 216A8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F860 +2F861 ; mapped ; 216EA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F861 +2F862 ; mapped ; 59EC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F862 +2F863 ; mapped ; 5A1B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F863 +2F864 ; mapped ; 5A27 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F864 +2F865 ; mapped ; 59D8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F865 +2F866 ; mapped ; 5A66 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F866 +2F867 ; mapped ; 36EE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F867 +2F868 ; disallowed # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F868 +2F869 ; mapped ; 5B08 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F869 +2F86A..2F86B ; mapped ; 5B3E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F86A..CJK COMPATIBILITY IDEOGRAPH-2F86B +2F86C ; mapped ; 219C8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F86C +2F86D ; mapped ; 5BC3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F86D +2F86E ; mapped ; 5BD8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F86E +2F86F ; mapped ; 5BE7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F86F +2F870 ; mapped ; 5BF3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F870 +2F871 ; mapped ; 21B18 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F871 +2F872 ; mapped ; 5BFF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F872 +2F873 ; mapped ; 5C06 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F873 +2F874 ; disallowed # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F874 +2F875 ; mapped ; 5C22 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F875 +2F876 ; mapped ; 3781 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F876 +2F877 ; mapped ; 5C60 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F877 +2F878 ; mapped ; 5C6E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F878 +2F879 ; mapped ; 5CC0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F879 +2F87A ; mapped ; 5C8D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87A +2F87B ; mapped ; 21DE4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87B +2F87C ; mapped ; 5D43 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87C +2F87D ; mapped ; 21DE6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87D +2F87E ; mapped ; 5D6E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87E +2F87F ; mapped ; 5D6B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F87F +2F880 ; mapped ; 5D7C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F880 +2F881 ; mapped ; 5DE1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F881 +2F882 ; mapped ; 5DE2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F882 +2F883 ; mapped ; 382F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F883 +2F884 ; mapped ; 5DFD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F884 +2F885 ; mapped ; 5E28 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F885 +2F886 ; mapped ; 5E3D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F886 +2F887 ; mapped ; 5E69 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F887 +2F888 ; mapped ; 3862 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F888 +2F889 ; mapped ; 22183 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F889 +2F88A ; mapped ; 387C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88A +2F88B ; mapped ; 5EB0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88B +2F88C ; mapped ; 5EB3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88C +2F88D ; mapped ; 5EB6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88D +2F88E ; mapped ; 5ECA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88E +2F88F ; mapped ; 2A392 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F88F +2F890 ; mapped ; 5EFE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F890 +2F891..2F892 ; mapped ; 22331 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F891..CJK COMPATIBILITY IDEOGRAPH-2F892 +2F893 ; mapped ; 8201 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F893 +2F894..2F895 ; mapped ; 5F22 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F894..CJK COMPATIBILITY IDEOGRAPH-2F895 +2F896 ; mapped ; 38C7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F896 +2F897 ; mapped ; 232B8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F897 +2F898 ; mapped ; 261DA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F898 +2F899 ; mapped ; 5F62 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F899 +2F89A ; mapped ; 5F6B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89A +2F89B ; mapped ; 38E3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89B +2F89C ; mapped ; 5F9A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89C +2F89D ; mapped ; 5FCD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89D +2F89E ; mapped ; 5FD7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89E +2F89F ; mapped ; 5FF9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F89F +2F8A0 ; mapped ; 6081 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A0 +2F8A1 ; mapped ; 393A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A1 +2F8A2 ; mapped ; 391C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A2 +2F8A3 ; mapped ; 6094 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A3 +2F8A4 ; mapped ; 226D4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A4 +2F8A5 ; mapped ; 60C7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A5 +2F8A6 ; mapped ; 6148 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A6 +2F8A7 ; mapped ; 614C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A7 +2F8A8 ; mapped ; 614E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A8 +2F8A9 ; mapped ; 614C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8A9 +2F8AA ; mapped ; 617A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AA +2F8AB ; mapped ; 618E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AB +2F8AC ; mapped ; 61B2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AC +2F8AD ; mapped ; 61A4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AD +2F8AE ; mapped ; 61AF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AE +2F8AF ; mapped ; 61DE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8AF +2F8B0 ; mapped ; 61F2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B0 +2F8B1 ; mapped ; 61F6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B1 +2F8B2 ; mapped ; 6210 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B2 +2F8B3 ; mapped ; 621B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B3 +2F8B4 ; mapped ; 625D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B4 +2F8B5 ; mapped ; 62B1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B5 +2F8B6 ; mapped ; 62D4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B6 +2F8B7 ; mapped ; 6350 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B7 +2F8B8 ; mapped ; 22B0C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B8 +2F8B9 ; mapped ; 633D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8B9 +2F8BA ; mapped ; 62FC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BA +2F8BB ; mapped ; 6368 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BB +2F8BC ; mapped ; 6383 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BC +2F8BD ; mapped ; 63E4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BD +2F8BE ; mapped ; 22BF1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BE +2F8BF ; mapped ; 6422 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8BF +2F8C0 ; mapped ; 63C5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C0 +2F8C1 ; mapped ; 63A9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C1 +2F8C2 ; mapped ; 3A2E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C2 +2F8C3 ; mapped ; 6469 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C3 +2F8C4 ; mapped ; 647E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C4 +2F8C5 ; mapped ; 649D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C5 +2F8C6 ; mapped ; 6477 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C6 +2F8C7 ; mapped ; 3A6C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C7 +2F8C8 ; mapped ; 654F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C8 +2F8C9 ; mapped ; 656C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8C9 +2F8CA ; mapped ; 2300A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CA +2F8CB ; mapped ; 65E3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CB +2F8CC ; mapped ; 66F8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CC +2F8CD ; mapped ; 6649 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CD +2F8CE ; mapped ; 3B19 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CE +2F8CF ; mapped ; 6691 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8CF +2F8D0 ; mapped ; 3B08 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D0 +2F8D1 ; mapped ; 3AE4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D1 +2F8D2 ; mapped ; 5192 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D2 +2F8D3 ; mapped ; 5195 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D3 +2F8D4 ; mapped ; 6700 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D4 +2F8D5 ; mapped ; 669C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D5 +2F8D6 ; mapped ; 80AD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D6 +2F8D7 ; mapped ; 43D9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D7 +2F8D8 ; mapped ; 6717 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D8 +2F8D9 ; mapped ; 671B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8D9 +2F8DA ; mapped ; 6721 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DA +2F8DB ; mapped ; 675E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DB +2F8DC ; mapped ; 6753 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DC +2F8DD ; mapped ; 233C3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DD +2F8DE ; mapped ; 3B49 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DE +2F8DF ; mapped ; 67FA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8DF +2F8E0 ; mapped ; 6785 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E0 +2F8E1 ; mapped ; 6852 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E1 +2F8E2 ; mapped ; 6885 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E2 +2F8E3 ; mapped ; 2346D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E3 +2F8E4 ; mapped ; 688E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E4 +2F8E5 ; mapped ; 681F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E5 +2F8E6 ; mapped ; 6914 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E6 +2F8E7 ; mapped ; 3B9D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E7 +2F8E8 ; mapped ; 6942 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E8 +2F8E9 ; mapped ; 69A3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8E9 +2F8EA ; mapped ; 69EA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8EA +2F8EB ; mapped ; 6AA8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8EB +2F8EC ; mapped ; 236A3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8EC +2F8ED ; mapped ; 6ADB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8ED +2F8EE ; mapped ; 3C18 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8EE +2F8EF ; mapped ; 6B21 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8EF +2F8F0 ; mapped ; 238A7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F0 +2F8F1 ; mapped ; 6B54 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F1 +2F8F2 ; mapped ; 3C4E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F2 +2F8F3 ; mapped ; 6B72 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F3 +2F8F4 ; mapped ; 6B9F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F4 +2F8F5 ; mapped ; 6BBA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F5 +2F8F6 ; mapped ; 6BBB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F6 +2F8F7 ; mapped ; 23A8D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F7 +2F8F8 ; mapped ; 21D0B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F8 +2F8F9 ; mapped ; 23AFA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8F9 +2F8FA ; mapped ; 6C4E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FA +2F8FB ; mapped ; 23CBC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FB +2F8FC ; mapped ; 6CBF # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FC +2F8FD ; mapped ; 6CCD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FD +2F8FE ; mapped ; 6C67 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FE +2F8FF ; mapped ; 6D16 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F8FF +2F900 ; mapped ; 6D3E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F900 +2F901 ; mapped ; 6D77 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F901 +2F902 ; mapped ; 6D41 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F902 +2F903 ; mapped ; 6D69 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F903 +2F904 ; mapped ; 6D78 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F904 +2F905 ; mapped ; 6D85 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F905 +2F906 ; mapped ; 23D1E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F906 +2F907 ; mapped ; 6D34 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F907 +2F908 ; mapped ; 6E2F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F908 +2F909 ; mapped ; 6E6E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F909 +2F90A ; mapped ; 3D33 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90A +2F90B ; mapped ; 6ECB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90B +2F90C ; mapped ; 6EC7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90C +2F90D ; mapped ; 23ED1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90D +2F90E ; mapped ; 6DF9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90E +2F90F ; mapped ; 6F6E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F90F +2F910 ; mapped ; 23F5E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F910 +2F911 ; mapped ; 23F8E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F911 +2F912 ; mapped ; 6FC6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F912 +2F913 ; mapped ; 7039 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F913 +2F914 ; mapped ; 701E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F914 +2F915 ; mapped ; 701B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F915 +2F916 ; mapped ; 3D96 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F916 +2F917 ; mapped ; 704A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F917 +2F918 ; mapped ; 707D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F918 +2F919 ; mapped ; 7077 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F919 +2F91A ; mapped ; 70AD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91A +2F91B ; mapped ; 20525 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91B +2F91C ; mapped ; 7145 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91C +2F91D ; mapped ; 24263 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91D +2F91E ; mapped ; 719C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91E +2F91F ; disallowed # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F91F +2F920 ; mapped ; 7228 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F920 +2F921 ; mapped ; 7235 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F921 +2F922 ; mapped ; 7250 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F922 +2F923 ; mapped ; 24608 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F923 +2F924 ; mapped ; 7280 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F924 +2F925 ; mapped ; 7295 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F925 +2F926 ; mapped ; 24735 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F926 +2F927 ; mapped ; 24814 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F927 +2F928 ; mapped ; 737A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F928 +2F929 ; mapped ; 738B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F929 +2F92A ; mapped ; 3EAC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F92A +2F92B ; mapped ; 73A5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F92B +2F92C..2F92D ; mapped ; 3EB8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F92C..CJK COMPATIBILITY IDEOGRAPH-2F92D +2F92E ; mapped ; 7447 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F92E +2F92F ; mapped ; 745C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F92F +2F930 ; mapped ; 7471 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F930 +2F931 ; mapped ; 7485 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F931 +2F932 ; mapped ; 74CA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F932 +2F933 ; mapped ; 3F1B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F933 +2F934 ; mapped ; 7524 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F934 +2F935 ; mapped ; 24C36 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F935 +2F936 ; mapped ; 753E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F936 +2F937 ; mapped ; 24C92 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F937 +2F938 ; mapped ; 7570 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F938 +2F939 ; mapped ; 2219F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F939 +2F93A ; mapped ; 7610 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93A +2F93B ; mapped ; 24FA1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93B +2F93C ; mapped ; 24FB8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93C +2F93D ; mapped ; 25044 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93D +2F93E ; mapped ; 3FFC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93E +2F93F ; mapped ; 4008 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F93F +2F940 ; mapped ; 76F4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F940 +2F941 ; mapped ; 250F3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F941 +2F942 ; mapped ; 250F2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F942 +2F943 ; mapped ; 25119 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F943 +2F944 ; mapped ; 25133 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F944 +2F945 ; mapped ; 771E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F945 +2F946..2F947 ; mapped ; 771F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F946..CJK COMPATIBILITY IDEOGRAPH-2F947 +2F948 ; mapped ; 774A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F948 +2F949 ; mapped ; 4039 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F949 +2F94A ; mapped ; 778B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94A +2F94B ; mapped ; 4046 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94B +2F94C ; mapped ; 4096 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94C +2F94D ; mapped ; 2541D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94D +2F94E ; mapped ; 784E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94E +2F94F ; mapped ; 788C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F94F +2F950 ; mapped ; 78CC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F950 +2F951 ; mapped ; 40E3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F951 +2F952 ; mapped ; 25626 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F952 +2F953 ; mapped ; 7956 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F953 +2F954 ; mapped ; 2569A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F954 +2F955 ; mapped ; 256C5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F955 +2F956 ; mapped ; 798F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F956 +2F957 ; mapped ; 79EB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F957 +2F958 ; mapped ; 412F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F958 +2F959 ; mapped ; 7A40 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F959 +2F95A ; mapped ; 7A4A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F95A +2F95B ; mapped ; 7A4F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F95B +2F95C ; mapped ; 2597C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F95C +2F95D..2F95E ; mapped ; 25AA7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F95D..CJK COMPATIBILITY IDEOGRAPH-2F95E +2F95F ; disallowed # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F95F +2F960 ; mapped ; 4202 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F960 +2F961 ; mapped ; 25BAB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F961 +2F962 ; mapped ; 7BC6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F962 +2F963 ; mapped ; 7BC9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F963 +2F964 ; mapped ; 4227 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F964 +2F965 ; mapped ; 25C80 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F965 +2F966 ; mapped ; 7CD2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F966 +2F967 ; mapped ; 42A0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F967 +2F968 ; mapped ; 7CE8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F968 +2F969 ; mapped ; 7CE3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F969 +2F96A ; mapped ; 7D00 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96A +2F96B ; mapped ; 25F86 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96B +2F96C ; mapped ; 7D63 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96C +2F96D ; mapped ; 4301 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96D +2F96E ; mapped ; 7DC7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96E +2F96F ; mapped ; 7E02 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F96F +2F970 ; mapped ; 7E45 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F970 +2F971 ; mapped ; 4334 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F971 +2F972 ; mapped ; 26228 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F972 +2F973 ; mapped ; 26247 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F973 +2F974 ; mapped ; 4359 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F974 +2F975 ; mapped ; 262D9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F975 +2F976 ; mapped ; 7F7A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F976 +2F977 ; mapped ; 2633E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F977 +2F978 ; mapped ; 7F95 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F978 +2F979 ; mapped ; 7FFA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F979 +2F97A ; mapped ; 8005 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97A +2F97B ; mapped ; 264DA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97B +2F97C ; mapped ; 26523 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97C +2F97D ; mapped ; 8060 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97D +2F97E ; mapped ; 265A8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97E +2F97F ; mapped ; 8070 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F97F +2F980 ; mapped ; 2335F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F980 +2F981 ; mapped ; 43D5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F981 +2F982 ; mapped ; 80B2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F982 +2F983 ; mapped ; 8103 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F983 +2F984 ; mapped ; 440B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F984 +2F985 ; mapped ; 813E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F985 +2F986 ; mapped ; 5AB5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F986 +2F987 ; mapped ; 267A7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F987 +2F988 ; mapped ; 267B5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F988 +2F989 ; mapped ; 23393 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F989 +2F98A ; mapped ; 2339C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98A +2F98B ; mapped ; 8201 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98B +2F98C ; mapped ; 8204 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98C +2F98D ; mapped ; 8F9E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98D +2F98E ; mapped ; 446B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98E +2F98F ; mapped ; 8291 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F98F +2F990 ; mapped ; 828B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F990 +2F991 ; mapped ; 829D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F991 +2F992 ; mapped ; 52B3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F992 +2F993 ; mapped ; 82B1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F993 +2F994 ; mapped ; 82B3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F994 +2F995 ; mapped ; 82BD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F995 +2F996 ; mapped ; 82E6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F996 +2F997 ; mapped ; 26B3C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F997 +2F998 ; mapped ; 82E5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F998 +2F999 ; mapped ; 831D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F999 +2F99A ; mapped ; 8363 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99A +2F99B ; mapped ; 83AD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99B +2F99C ; mapped ; 8323 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99C +2F99D ; mapped ; 83BD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99D +2F99E ; mapped ; 83E7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99E +2F99F ; mapped ; 8457 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F99F +2F9A0 ; mapped ; 8353 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A0 +2F9A1 ; mapped ; 83CA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A1 +2F9A2 ; mapped ; 83CC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A2 +2F9A3 ; mapped ; 83DC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A3 +2F9A4 ; mapped ; 26C36 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A4 +2F9A5 ; mapped ; 26D6B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A5 +2F9A6 ; mapped ; 26CD5 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A6 +2F9A7 ; mapped ; 452B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A7 +2F9A8 ; mapped ; 84F1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A8 +2F9A9 ; mapped ; 84F3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9A9 +2F9AA ; mapped ; 8516 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AA +2F9AB ; mapped ; 273CA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AB +2F9AC ; mapped ; 8564 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AC +2F9AD ; mapped ; 26F2C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AD +2F9AE ; mapped ; 455D # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AE +2F9AF ; mapped ; 4561 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9AF +2F9B0 ; mapped ; 26FB1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B0 +2F9B1 ; mapped ; 270D2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B1 +2F9B2 ; mapped ; 456B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B2 +2F9B3 ; mapped ; 8650 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B3 +2F9B4 ; mapped ; 865C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B4 +2F9B5 ; mapped ; 8667 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B5 +2F9B6 ; mapped ; 8669 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B6 +2F9B7 ; mapped ; 86A9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B7 +2F9B8 ; mapped ; 8688 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B8 +2F9B9 ; mapped ; 870E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9B9 +2F9BA ; mapped ; 86E2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BA +2F9BB ; mapped ; 8779 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BB +2F9BC ; mapped ; 8728 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BC +2F9BD ; mapped ; 876B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BD +2F9BE ; mapped ; 8786 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BE +2F9BF ; disallowed # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9BF +2F9C0 ; mapped ; 87E1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C0 +2F9C1 ; mapped ; 8801 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C1 +2F9C2 ; mapped ; 45F9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C2 +2F9C3 ; mapped ; 8860 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C3 +2F9C4 ; mapped ; 8863 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C4 +2F9C5 ; mapped ; 27667 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C5 +2F9C6 ; mapped ; 88D7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C6 +2F9C7 ; mapped ; 88DE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C7 +2F9C8 ; mapped ; 4635 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C8 +2F9C9 ; mapped ; 88FA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9C9 +2F9CA ; mapped ; 34BB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CA +2F9CB ; mapped ; 278AE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CB +2F9CC ; mapped ; 27966 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CC +2F9CD ; mapped ; 46BE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CD +2F9CE ; mapped ; 46C7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CE +2F9CF ; mapped ; 8AA0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9CF +2F9D0 ; mapped ; 8AED # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D0 +2F9D1 ; mapped ; 8B8A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D1 +2F9D2 ; mapped ; 8C55 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D2 +2F9D3 ; mapped ; 27CA8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D3 +2F9D4 ; mapped ; 8CAB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D4 +2F9D5 ; mapped ; 8CC1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D5 +2F9D6 ; mapped ; 8D1B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D6 +2F9D7 ; mapped ; 8D77 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D7 +2F9D8 ; mapped ; 27F2F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D8 +2F9D9 ; mapped ; 20804 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9D9 +2F9DA ; mapped ; 8DCB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DA +2F9DB ; mapped ; 8DBC # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DB +2F9DC ; mapped ; 8DF0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DC +2F9DD ; mapped ; 208DE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DD +2F9DE ; mapped ; 8ED4 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DE +2F9DF ; mapped ; 8F38 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9DF +2F9E0 ; mapped ; 285D2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E0 +2F9E1 ; mapped ; 285ED # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E1 +2F9E2 ; mapped ; 9094 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E2 +2F9E3 ; mapped ; 90F1 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E3 +2F9E4 ; mapped ; 9111 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E4 +2F9E5 ; mapped ; 2872E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E5 +2F9E6 ; mapped ; 911B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E6 +2F9E7 ; mapped ; 9238 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E7 +2F9E8 ; mapped ; 92D7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E8 +2F9E9 ; mapped ; 92D8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9E9 +2F9EA ; mapped ; 927C # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9EA +2F9EB ; mapped ; 93F9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9EB +2F9EC ; mapped ; 9415 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9EC +2F9ED ; mapped ; 28BFA # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9ED +2F9EE ; mapped ; 958B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9EE +2F9EF ; mapped ; 4995 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9EF +2F9F0 ; mapped ; 95B7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F0 +2F9F1 ; mapped ; 28D77 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F1 +2F9F2 ; mapped ; 49E6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F2 +2F9F3 ; mapped ; 96C3 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F3 +2F9F4 ; mapped ; 5DB2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F4 +2F9F5 ; mapped ; 9723 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F5 +2F9F6 ; mapped ; 29145 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F6 +2F9F7 ; mapped ; 2921A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F7 +2F9F8 ; mapped ; 4A6E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F8 +2F9F9 ; mapped ; 4A76 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9F9 +2F9FA ; mapped ; 97E0 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9FA +2F9FB ; mapped ; 2940A # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9FB +2F9FC ; mapped ; 4AB2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9FC +2F9FD ; mapped ; 29496 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9FD +2F9FE..2F9FF ; mapped ; 980B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2F9FE..CJK COMPATIBILITY IDEOGRAPH-2F9FF +2FA00 ; mapped ; 9829 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA00 +2FA01 ; mapped ; 295B6 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA01 +2FA02 ; mapped ; 98E2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA02 +2FA03 ; mapped ; 4B33 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA03 +2FA04 ; mapped ; 9929 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA04 +2FA05 ; mapped ; 99A7 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA05 +2FA06 ; mapped ; 99C2 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA06 +2FA07 ; mapped ; 99FE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA07 +2FA08 ; mapped ; 4BCE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA08 +2FA09 ; mapped ; 29B30 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA09 +2FA0A ; mapped ; 9B12 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0A +2FA0B ; mapped ; 9C40 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0B +2FA0C ; mapped ; 9CFD # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0C +2FA0D ; mapped ; 4CCE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0D +2FA0E ; mapped ; 4CED # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0E +2FA0F ; mapped ; 9D67 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA0F +2FA10 ; mapped ; 2A0CE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA10 +2FA11 ; mapped ; 4CF8 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA11 +2FA12 ; mapped ; 2A105 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA12 +2FA13 ; mapped ; 2A20E # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA13 +2FA14 ; mapped ; 2A291 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA14 +2FA15 ; mapped ; 9EBB # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA15 +2FA16 ; mapped ; 4D56 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA16 +2FA17 ; mapped ; 9EF9 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA17 +2FA18 ; mapped ; 9EFE # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA18 +2FA19 ; mapped ; 9F05 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA19 +2FA1A ; mapped ; 9F0F # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA1A +2FA1B ; mapped ; 9F16 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA1B +2FA1C ; mapped ; 9F3B # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA1C +2FA1D ; mapped ; 2A600 # 3.1 CJK COMPATIBILITY IDEOGRAPH-2FA1D +2FA1E..2FFFD ; disallowed # NA .. +2FFFE..2FFFF ; disallowed # 2.0 .. +30000..3FFFD ; disallowed # NA .. +3FFFE..3FFFF ; disallowed # 2.0 .. +40000..4FFFD ; disallowed # NA .. +4FFFE..4FFFF ; disallowed # 2.0 .. +50000..5FFFD ; disallowed # NA .. +5FFFE..5FFFF ; disallowed # 2.0 .. +60000..6FFFD ; disallowed # NA .. +6FFFE..6FFFF ; disallowed # 2.0 .. +70000..7FFFD ; disallowed # NA .. +7FFFE..7FFFF ; disallowed # 2.0 .. +80000..8FFFD ; disallowed # NA .. +8FFFE..8FFFF ; disallowed # 2.0 .. +90000..9FFFD ; disallowed # NA .. +9FFFE..9FFFF ; disallowed # 2.0 .. +A0000..AFFFD ; disallowed # NA .. +AFFFE..AFFFF ; disallowed # 2.0 .. +B0000..BFFFD ; disallowed # NA .. +BFFFE..BFFFF ; disallowed # 2.0 .. +C0000..CFFFD ; disallowed # NA .. +CFFFE..CFFFF ; disallowed # 2.0 .. +D0000..DFFFD ; disallowed # NA .. +DFFFE..DFFFF ; disallowed # 2.0 .. +E0000 ; disallowed # NA +E0001 ; disallowed # 3.1 LANGUAGE TAG +E0002..E001F ; disallowed # NA .. +E0020..E007F ; disallowed # 3.1 TAG SPACE..CANCEL TAG +E0080..E00FF ; disallowed # NA .. +E0100..E01EF ; ignored # 4.0 VARIATION SELECTOR-17..VARIATION SELECTOR-256 +E01F0..EFFFD ; disallowed # NA .. +EFFFE..EFFFF ; disallowed # 2.0 .. +F0000..FFFFD ; disallowed # 2.0 .. +FFFFE..FFFFF ; disallowed # 2.0 .. +100000..10FFFD; disallowed # 2.0 .. +10FFFE..10FFFF; disallowed # 2.0 .. + +# Total code points: 1114112 + diff --git a/idna/src/lib.rs b/idna/src/lib.rs new file mode 100644 index 000000000..92b5df230 --- /dev/null +++ b/idna/src/lib.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This Rust crate implements IDNA +//! [per the WHATWG URL Standard](https://url.spec.whatwg.org/#idna). +//! +//! It also exposes the underlying algorithms from [*Unicode IDNA Compatibility Processing* +//! (Unicode Technical Standard #46)](http://www.unicode.org/reports/tr46/) +//! and [Punycode (RFC 3492)](https://tools.ietf.org/html/rfc3492). +//! +//! Quoting from [UTS #46’s introduction](http://www.unicode.org/reports/tr46/#Introduction): +//! +//! > Initially, domain names were restricted to ASCII characters. +//! > A system was introduced in 2003 for internationalized domain names (IDN). +//! > This system is called Internationalizing Domain Names for Applications, +//! > or IDNA2003 for short. +//! > This mechanism supports IDNs by means of a client software transformation +//! > into a format known as Punycode. +//! > A revision of IDNA was approved in 2010 (IDNA2008). +//! > This revision has a number of incompatibilities with IDNA2003. +//! > +//! > The incompatibilities force implementers of client software, +//! > such as browsers and emailers, +//! > to face difficult choices during the transition period +//! > as registries shift from IDNA2003 to IDNA2008. +//! > This document specifies a mechanism +//! > that minimizes the impact of this transition for client software, +//! > allowing client software to access domains that are valid under either system. + +#[macro_use] extern crate matches; +extern crate unicode_bidi; +extern crate unicode_normalization; + +pub mod punycode; +pub mod uts46; + +/// The [domain to ASCII](https://url.spec.whatwg.org/#concept-domain-to-ascii) algorithm. +/// +/// Return the ASCII representation a domain name, +/// normalizing characters (upper-case to lower-case and other kinds of equivalence) +/// and using Punycode as necessary. +/// +/// This process may fail. +pub fn domain_to_ascii(domain: &str) -> Result { + uts46::to_ascii(domain, uts46::Flags { + use_std3_ascii_rules: false, + transitional_processing: false, + verify_dns_length: false, + }) +} + +/// The [domain to Unicode](https://url.spec.whatwg.org/#concept-domain-to-unicode) algorithm. +/// +/// Return the Unicode representation of a domain name, +/// normalizing characters (upper-case to lower-case and other kinds of equivalence) +/// and decoding Punycode as necessary. +/// +/// This may indicate [syntax violations](https://url.spec.whatwg.org/#syntax-violation) +/// but always returns a string for the mapped domain. +pub fn domain_to_unicode(domain: &str) -> (String, Result<(), uts46::Errors>) { + uts46::to_unicode(domain, uts46::Flags { + use_std3_ascii_rules: false, + + // Unused: + transitional_processing: false, + verify_dns_length: false, + }) +} diff --git a/idna/src/make_uts46_mapping_table.py b/idna/src/make_uts46_mapping_table.py new file mode 100644 index 000000000..16e4feb44 --- /dev/null +++ b/idna/src/make_uts46_mapping_table.py @@ -0,0 +1,192 @@ +# Copyright 2013-2014 The rust-url developers. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# Run as: python make_uts46_mapping_table.py IdnaMappingTable.txt > uts46_mapping_table.rs +# You can get the latest idna table from +# http://www.unicode.org/Public/idna/latest/IdnaMappingTable.txt + +from __future__ import print_function +import collections +import itertools + +print('''\ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Generated by make_idna_table.py +''') + +txt = open("IdnaMappingTable.txt") + +def escape_char(c): + return "\\u{%x}" % ord(c[0]) + +def char(s): + return unichr(int(s, 16)) + +strtab = collections.OrderedDict() +strtab_offset = 0 + +def strtab_slice(s): + global strtab, strtab_offset + + if s in strtab: + return strtab[s] + else: + utf8_len = len(s.encode('utf8')) + c = (strtab_offset, utf8_len) + strtab[s] = c + strtab_offset += utf8_len + return c + +def rust_slice(s): + start = s[0] + length = s[1] + start_lo = start & 0xff + start_hi = start >> 8 + assert length <= 255 + assert start_hi <= 255 + return "(StringTableSlice { byte_start_lo: %d, byte_start_hi: %d, byte_len: %d })" % (start_lo, start_hi, length) + +ranges = [] + +for line in txt: + # remove comments + line, _, _ = line.partition('#') + # skip empty lines + if len(line.strip()) == 0: + continue + fields = line.split(';') + if fields[0].strip() == 'D800..DFFF': + continue # Surrogates don't occur in Rust strings. + first, _, last = fields[0].strip().partition('..') + if not last: + last = first + mapping = fields[1].strip().replace('_', ' ').title().replace(' ', '') + unicode_str = None + if len(fields) > 2: + if fields[2].strip(): + unicode_str = u''.join(char(c) for c in fields[2].strip().split(' ')) + elif mapping == "Deviation": + unicode_str = u'' + ranges.append((first, last, mapping, unicode_str)) + +def mergeable_key(r): + mapping = r[2] + + # These types have associated data, so we should not merge them. + if mapping in ('Mapped', 'Deviation', 'DisallowedStd3Mapped'): + return r + assert mapping in ('Valid', 'Ignored', 'Disallowed', 'DisallowedStd3Valid') + return mapping + +grouped_ranges = itertools.groupby(ranges, key=mergeable_key) + +optimized_ranges = [] + +for (k, g) in grouped_ranges: + group = list(g) + if len(group) == 1: + optimized_ranges.append(group[0]) + continue + # Assert that nothing in the group has an associated unicode string. + for g in group: + if g[3] is not None and len(g[3]) > 2: + assert not g[3][2].strip() + # Assert that consecutive members of the group don't leave gaps in + # the codepoint space. + a, b = itertools.tee(group) + next(b, None) + for (g1, g2) in itertools.izip(a, b): + last_char = int(g1[1], 16) + next_char = int(g2[0], 16) + if last_char + 1 == next_char: + continue + # There's a gap where surrogates would appear, but we don't have to + # worry about that gap, as surrogates never appear in Rust strings. + # Assert we're seeing the surrogate case here. + assert last_char == 0xd7ff + assert next_char == 0xe000 + first = group[0][0] + last = group[-1][1] + mapping = group[0][2] + unicode_str = group[0][3] + optimized_ranges.append((first, last, mapping, unicode_str)) + +def is_single_char_range(r): + (first, last, _, _) = r + return first == last + +# We can reduce the size of the character range table and the index table to about 1/4 +# by merging runs of single character ranges and using character offsets from the start +# of that range to retrieve the correct `Mapping` value +def merge_single_char_ranges(ranges): + current = [] + for r in ranges: + if not current or is_single_char_range(current[-1]) and is_single_char_range(r): + current.append(r) + continue + if len(current) != 0: + ret = current + current = [r] + yield ret + continue + current.append(r) + ret = current + current = [] + yield ret + yield current + +optimized_ranges = list(merge_single_char_ranges(optimized_ranges)) + + +print("static TABLE: &'static [Range] = &[") + +for ranges in optimized_ranges: + first = ranges[0][0] + last = ranges[-1][1] + print(" Range { from: '%s', to: '%s', }," % (escape_char(char(first)), + escape_char(char(last)))) + +print("];\n") + +print("static INDEX_TABLE: &'static [u16] = &[") + +SINGLE_MARKER = 1 << 15 + +offset = 0 +for ranges in optimized_ranges: + assert offset < SINGLE_MARKER + + block_len = len(ranges) + single = SINGLE_MARKER if block_len == 1 else 0 + print(" %s," % (offset | single)) + offset += block_len + +print("];\n") + +print("static MAPPING_TABLE: &'static [Mapping] = &[") + +for ranges in optimized_ranges: + for (first, last, mapping, unicode_str) in ranges: + if unicode_str is not None: + mapping += rust_slice(strtab_slice(unicode_str)) + print(" %s," % mapping) + +print("];\n") + +def escape_str(s): + return [escape_char(c) for c in s] + +print("static STRING_TABLE: &'static str = \"%s\";" + % '\\\n '.join(itertools.chain(*[escape_str(s) for s in strtab.iterkeys()]))) diff --git a/idna/src/punycode.rs b/idna/src/punycode.rs new file mode 100644 index 000000000..acdde5897 --- /dev/null +++ b/idna/src/punycode.rs @@ -0,0 +1,213 @@ +// Copyright 2013 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Punycode ([RFC 3492](http://tools.ietf.org/html/rfc3492)) implementation. +//! +//! Since Punycode fundamentally works on unicode code points, +//! `encode` and `decode` take and return slices and vectors of `char`. +//! `encode_str` and `decode_to_string` provide convenience wrappers +//! that convert from and to Rust’s UTF-8 based `str` and `String` types. + +use std::u32; +use std::char; +#[allow(unused_imports, deprecated)] +use std::ascii::AsciiExt; + +// Bootstring parameters for Punycode +static BASE: u32 = 36; +static T_MIN: u32 = 1; +static T_MAX: u32 = 26; +static SKEW: u32 = 38; +static DAMP: u32 = 700; +static INITIAL_BIAS: u32 = 72; +static INITIAL_N: u32 = 0x80; +static DELIMITER: char = '-'; + + +#[inline] +fn adapt(mut delta: u32, num_points: u32, first_time: bool) -> u32 { + delta /= if first_time { DAMP } else { 2 }; + delta += delta / num_points; + let mut k = 0; + while delta > ((BASE - T_MIN) * T_MAX) / 2 { + delta /= BASE - T_MIN; + k += BASE; + } + k + (((BASE - T_MIN + 1) * delta) / (delta + SKEW)) +} + + +/// Convert Punycode to an Unicode `String`. +/// +/// This is a convenience wrapper around `decode`. +#[inline] +pub fn decode_to_string(input: &str) -> Option { + decode(input).map(|chars| chars.into_iter().collect()) +} + + +/// Convert Punycode to Unicode. +/// +/// Return None on malformed input or overflow. +/// Overflow can only happen on inputs that take more than +/// 63 encoded bytes, the DNS limit on domain name labels. +pub fn decode(input: &str) -> Option> { + // Handle "basic" (ASCII) code points. + // They are encoded as-is before the last delimiter, if any. + let (mut output, input) = match input.rfind(DELIMITER) { + None => (Vec::new(), input), + Some(position) => ( + input[..position].chars().collect(), + if position > 0 { &input[position + 1..] } else { input } + ) + }; + let mut code_point = INITIAL_N; + let mut bias = INITIAL_BIAS; + let mut i = 0; + let mut iter = input.bytes(); + loop { + let previous_i = i; + let mut weight = 1; + let mut k = BASE; + let mut byte = match iter.next() { + None => break, + Some(byte) => byte, + }; + // Decode a generalized variable-length integer into delta, + // which gets added to i. + loop { + let digit = match byte { + byte @ b'0' ... b'9' => byte - b'0' + 26, + byte @ b'A' ... b'Z' => byte - b'A', + byte @ b'a' ... b'z' => byte - b'a', + _ => return None + } as u32; + if digit > (u32::MAX - i) / weight { + return None // Overflow + } + i += digit * weight; + let t = if k <= bias { T_MIN } + else if k >= bias + T_MAX { T_MAX } + else { k - bias }; + if digit < t { + break + } + if weight > u32::MAX / (BASE - t) { + return None // Overflow + } + weight *= BASE - t; + k += BASE; + byte = match iter.next() { + None => return None, // End of input before the end of this delta + Some(byte) => byte, + }; + } + let length = output.len() as u32; + bias = adapt(i - previous_i, length + 1, previous_i == 0); + if i / (length + 1) > u32::MAX - code_point { + return None // Overflow + } + // i was supposed to wrap around from length+1 to 0, + // incrementing code_point each time. + code_point += i / (length + 1); + i %= length + 1; + let c = match char::from_u32(code_point) { + Some(c) => c, + None => return None + }; + output.insert(i as usize, c); + i += 1; + } + Some(output) +} + + +/// Convert an Unicode `str` to Punycode. +/// +/// This is a convenience wrapper around `encode`. +#[inline] +pub fn encode_str(input: &str) -> Option { + encode(&input.chars().collect::>()) +} + + +/// Convert Unicode to Punycode. +/// +/// Return None on overflow, which can only happen on inputs that would take more than +/// 63 encoded bytes, the DNS limit on domain name labels. +pub fn encode(input: &[char]) -> Option { + // Handle "basic" (ASCII) code points. They are encoded as-is. + let output_bytes = input.iter().filter_map(|&c| + if c.is_ascii() { Some(c as u8) } else { None } + ).collect(); + let mut output = unsafe { String::from_utf8_unchecked(output_bytes) }; + let basic_length = output.len() as u32; + if basic_length > 0 { + output.push_str("-") + } + let mut code_point = INITIAL_N; + let mut delta = 0; + let mut bias = INITIAL_BIAS; + let mut processed = basic_length; + let input_length = input.len() as u32; + while processed < input_length { + // All code points < code_point have been handled already. + // Find the next larger one. + let min_code_point = input.iter().map(|&c| c as u32) + .filter(|&c| c >= code_point).min().unwrap(); + if min_code_point - code_point > (u32::MAX - delta) / (processed + 1) { + return None // Overflow + } + // Increase delta to advance the decoder’s state to + delta += (min_code_point - code_point) * (processed + 1); + code_point = min_code_point; + for &c in input { + let c = c as u32; + if c < code_point { + delta += 1; + if delta == 0 { + return None // Overflow + } + } + if c == code_point { + // Represent delta as a generalized variable-length integer: + let mut q = delta; + let mut k = BASE; + loop { + let t = if k <= bias { T_MIN } + else if k >= bias + T_MAX { T_MAX } + else { k - bias }; + if q < t { + break + } + let value = t + ((q - t) % (BASE - t)); + output.push(value_to_digit(value)); + q = (q - t) / (BASE - t); + k += BASE; + } + output.push(value_to_digit(q)); + bias = adapt(delta, processed + 1, processed == basic_length); + delta = 0; + processed += 1; + } + } + delta += 1; + code_point += 1; + } + Some(output) +} + + +#[inline] +fn value_to_digit(value: u32) -> char { + match value { + 0 ... 25 => (value as u8 + 'a' as u8) as char, // a..z + 26 ... 35 => (value as u8 - 26 + '0' as u8) as char, // 0..9 + _ => panic!() + } +} diff --git a/idna/src/uts46.rs b/idna/src/uts46.rs new file mode 100644 index 000000000..ac348d1fa --- /dev/null +++ b/idna/src/uts46.rs @@ -0,0 +1,433 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! [*Unicode IDNA Compatibility Processing* +//! (Unicode Technical Standard #46)](http://www.unicode.org/reports/tr46/) + +use self::Mapping::*; +use punycode; +#[allow(unused_imports, deprecated)] +use std::ascii::AsciiExt; +use std::cmp::Ordering::{Equal, Less, Greater}; +use unicode_bidi::{BidiClass, bidi_class}; +use unicode_normalization::UnicodeNormalization; +use unicode_normalization::char::is_combining_mark; + +include!("uts46_mapping_table.rs"); + + +pub static PUNYCODE_PREFIX: &'static str = "xn--"; + + +#[derive(Debug)] +struct StringTableSlice { + // Store these as separate fields so the structure will have an + // alignment of 1 and thus pack better into the Mapping enum, below. + byte_start_lo: u8, + byte_start_hi: u8, + byte_len: u8, +} + +fn decode_slice(slice: &StringTableSlice) -> &'static str { + let lo = slice.byte_start_lo as usize; + let hi = slice.byte_start_hi as usize; + let start = (hi << 8) | lo; + let len = slice.byte_len as usize; + &STRING_TABLE[start..(start + len)] +} + +#[repr(u8)] +#[derive(Debug)] +enum Mapping { + Valid, + Ignored, + Mapped(StringTableSlice), + Deviation(StringTableSlice), + Disallowed, + DisallowedStd3Valid, + DisallowedStd3Mapped(StringTableSlice), +} + +struct Range { + from: char, + to: char, +} + +fn find_char(codepoint: char) -> &'static Mapping { + let r = TABLE.binary_search_by(|ref range| { + if codepoint > range.to { + Less + } else if codepoint < range.from { + Greater + } else { + Equal + } + }); + r.ok().map(|i| { + const SINGLE_MARKER: u16 = 1 << 15; + + let x = INDEX_TABLE[i]; + let single = (x & SINGLE_MARKER) != 0; + let offset = !SINGLE_MARKER & x; + + if single { + &MAPPING_TABLE[offset as usize] + } else { + &MAPPING_TABLE[(offset + (codepoint as u16 - TABLE[i].from as u16)) as usize] + } + }).unwrap() +} + +fn map_char(codepoint: char, flags: Flags, output: &mut String, errors: &mut Vec) { + match *find_char(codepoint) { + Mapping::Valid => output.push(codepoint), + Mapping::Ignored => {}, + Mapping::Mapped(ref slice) => output.push_str(decode_slice(slice)), + Mapping::Deviation(ref slice) => { + if flags.transitional_processing { + output.push_str(decode_slice(slice)) + } else { + output.push(codepoint) + } + } + Mapping::Disallowed => { + errors.push(Error::DissallowedCharacter); + output.push(codepoint); + } + Mapping::DisallowedStd3Valid => { + if flags.use_std3_ascii_rules { + errors.push(Error::DissallowedByStd3AsciiRules); + } + output.push(codepoint) + } + Mapping::DisallowedStd3Mapped(ref slice) => { + if flags.use_std3_ascii_rules { + errors.push(Error::DissallowedMappedInStd3); + } + output.push_str(decode_slice(slice)) + } + } +} + +// http://tools.ietf.org/html/rfc5893#section-2 +fn passes_bidi(label: &str, is_bidi_domain: bool) -> bool { + // Rule 0: Bidi Rules apply to Bidi Domain Names: a name with at least one RTL label. A label + // is RTL if it contains at least one character of bidi class R, AL or AN. + if !is_bidi_domain { + return true; + } + + let mut chars = label.chars(); + let first_char_class = match chars.next() { + Some(c) => bidi_class(c), + None => return true, // empty string + }; + + match first_char_class { + // LTR label + BidiClass::L => { + // Rule 5 + loop { + match chars.next() { + Some(c) => { + if !matches!(bidi_class(c), + BidiClass::L | BidiClass::EN | + BidiClass::ES | BidiClass::CS | + BidiClass::ET | BidiClass::ON | + BidiClass::BN | BidiClass::NSM + ) { + return false; + } + }, + None => { break; }, + } + } + + // Rule 6 + // must end in L or EN followed by 0 or more NSM + let mut rev_chars = label.chars().rev(); + let mut last_non_nsm = rev_chars.next(); + loop { + match last_non_nsm { + Some(c) if bidi_class(c) == BidiClass::NSM => { + last_non_nsm = rev_chars.next(); + continue; + } + _ => { break; }, + } + } + match last_non_nsm { + Some(c) if bidi_class(c) == BidiClass::L + || bidi_class(c) == BidiClass::EN => {}, + Some(_) => { return false; }, + _ => {} + } + + } + + // RTL label + BidiClass::R | BidiClass::AL => { + let mut found_en = false; + let mut found_an = false; + + // Rule 2 + loop { + match chars.next() { + Some(c) => { + let char_class = bidi_class(c); + + if char_class == BidiClass::EN { + found_en = true; + } + if char_class == BidiClass::AN { + found_an = true; + } + + if !matches!(char_class, BidiClass::R | BidiClass::AL | + BidiClass::AN | BidiClass::EN | + BidiClass::ES | BidiClass::CS | + BidiClass::ET | BidiClass::ON | + BidiClass::BN | BidiClass::NSM) { + return false; + } + }, + None => { break; }, + } + } + // Rule 3 + let mut rev_chars = label.chars().rev(); + let mut last = rev_chars.next(); + loop { // must end in L or EN followed by 0 or more NSM + match last { + Some(c) if bidi_class(c) == BidiClass::NSM => { + last = rev_chars.next(); + continue; + } + _ => { break; }, + } + } + match last { + Some(c) if matches!(bidi_class(c), BidiClass::R | BidiClass::AL | + BidiClass::EN | BidiClass::AN) => {}, + _ => { return false; } + } + + // Rule 4 + if found_an && found_en { + return false; + } + } + + // Rule 1: Should start with L or R/AL + _ => { + return false; + } + } + + return true; +} + +/// http://www.unicode.org/reports/tr46/#Validity_Criteria +fn validate_full(label: &str, is_bidi_domain: bool, flags: Flags, errors: &mut Vec) { + // V1: Must be in NFC form. + if label.nfc().ne(label.chars()) { + errors.push(Error::ValidityCriteria); + } else { + validate(label, is_bidi_domain, flags, errors); + } +} + +fn validate(label: &str, is_bidi_domain: bool, flags: Flags, errors: &mut Vec) { + let first_char = label.chars().next(); + if first_char == None { + // Empty string, pass + } + + // V2: No U+002D HYPHEN-MINUS in both third and fourth positions. + // + // NOTE: Spec says that the label must not contain a HYPHEN-MINUS character in both the + // third and fourth positions. But nobody follows this criteria. See the spec issue below: + // https://github.com/whatwg/url/issues/53 + // + // TODO: Add *CheckHyphens* flag. + + // V3: neither begin nor end with a U+002D HYPHEN-MINUS + else if label.starts_with("-") || label.ends_with("-") { + errors.push(Error::ValidityCriteria); + } + + // V4: not contain a U+002E FULL STOP + // + // Here, label can't contain '.' since the input is from .split('.') + + // V5: not begin with a GC=Mark + else if is_combining_mark(first_char.unwrap()) { + errors.push(Error::ValidityCriteria); + } + + // V6: Check against Mapping Table + else if label.chars().any(|c| match *find_char(c) { + Mapping::Valid => false, + Mapping::Deviation(_) => flags.transitional_processing, + Mapping::DisallowedStd3Valid => flags.use_std3_ascii_rules, + _ => true, + }) { + errors.push(Error::ValidityCriteria); + } + + // V7: ContextJ rules + // + // TODO: Implement rules and add *CheckJoiners* flag. + + // V8: Bidi rules + // + // TODO: Add *CheckBidi* flag + else if !passes_bidi(label, is_bidi_domain) + { + errors.push(Error::ValidityCriteria); + } +} + +/// http://www.unicode.org/reports/tr46/#Processing +fn processing(domain: &str, flags: Flags, errors: &mut Vec) -> String { + let mut mapped = String::with_capacity(domain.len()); + for c in domain.chars() { + map_char(c, flags, &mut mapped, errors) + } + let mut normalized = String::with_capacity(mapped.len()); + normalized.extend(mapped.nfc()); + + // Find out if it's a Bidi Domain Name + // + // First, check for literal bidi chars + let mut is_bidi_domain = domain.chars().any(|c| + matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN) + ); + if !is_bidi_domain { + // Then check for punycode-encoded bidi chars + for label in normalized.split('.') { + if label.starts_with(PUNYCODE_PREFIX) { + match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) { + Some(decoded_label) => { + if decoded_label.chars().any(|c| + matches!(bidi_class(c), BidiClass::R | BidiClass::AL | BidiClass::AN) + ) { + is_bidi_domain = true; + } + } + None => { + is_bidi_domain = true; + } + } + } + } + } + + let mut validated = String::new(); + let mut first = true; + for label in normalized.split('.') { + if !first { + validated.push('.'); + } + first = false; + if label.starts_with(PUNYCODE_PREFIX) { + match punycode::decode_to_string(&label[PUNYCODE_PREFIX.len()..]) { + Some(decoded_label) => { + let flags = Flags { transitional_processing: false, ..flags }; + validate_full(&decoded_label, is_bidi_domain, flags, errors); + validated.push_str(&decoded_label) + } + None => errors.push(Error::PunycodeError) + } + } else { + // `normalized` is already `NFC` so we can skip that check + validate(label, is_bidi_domain, flags, errors); + validated.push_str(label) + } + } + validated +} + +#[derive(Copy, Clone)] +pub struct Flags { + pub use_std3_ascii_rules: bool, + pub transitional_processing: bool, + pub verify_dns_length: bool, +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +enum Error { + PunycodeError, + ValidityCriteria, + DissallowedByStd3AsciiRules, + DissallowedMappedInStd3, + DissallowedCharacter, + TooLongForDns, + TooShortForDns, +} + +/// Errors recorded during UTS #46 processing. +/// +/// This is opaque for now, only indicating the presence of at least one error. +/// More details may be exposed in the future. +#[derive(Debug)] +pub struct Errors(Vec); + +/// http://www.unicode.org/reports/tr46/#ToASCII +pub fn to_ascii(domain: &str, flags: Flags) -> Result { + let mut errors = Vec::new(); + let mut result = String::new(); + let mut first = true; + for label in processing(domain, flags, &mut errors).split('.') { + if !first { + result.push('.'); + } + first = false; + if label.is_ascii() { + result.push_str(label); + } else { + match punycode::encode_str(label) { + Some(x) => { + result.push_str(PUNYCODE_PREFIX); + result.push_str(&x); + }, + None => errors.push(Error::PunycodeError) + } + } + } + + if flags.verify_dns_length { + let domain = if result.ends_with(".") { &result[..result.len()-1] } else { &*result }; + if domain.len() < 1 || domain.split('.').any(|label| label.len() < 1) { + errors.push(Error::TooShortForDns) + } + if domain.len() > 253 || domain.split('.').any(|label| label.len() > 63) { + errors.push(Error::TooLongForDns) + } + } + if errors.is_empty() { + Ok(result) + } else { + Err(Errors(errors)) + } +} + +/// http://www.unicode.org/reports/tr46/#ToUnicode +/// +/// Only `use_std3_ascii_rules` is used in `flags`. +pub fn to_unicode(domain: &str, mut flags: Flags) -> (String, Result<(), Errors>) { + flags.transitional_processing = false; + let mut errors = Vec::new(); + let domain = processing(domain, flags, &mut errors); + let errors = if errors.is_empty() { + Ok(()) + } else { + Err(Errors(errors)) + }; + (domain, errors) +} diff --git a/idna/src/uts46_mapping_table.rs b/idna/src/uts46_mapping_table.rs new file mode 100644 index 000000000..2733290d6 --- /dev/null +++ b/idna/src/uts46_mapping_table.rs @@ -0,0 +1,16005 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Generated by make_idna_table.py + +static TABLE: &'static [Range] = &[ + Range { from: '\u{0}', to: '\u{2c}', }, + Range { from: '\u{2d}', to: '\u{2e}', }, + Range { from: '\u{2f}', to: '\u{2f}', }, + Range { from: '\u{30}', to: '\u{39}', }, + Range { from: '\u{3a}', to: '\u{40}', }, + Range { from: '\u{41}', to: '\u{5a}', }, + Range { from: '\u{5b}', to: '\u{60}', }, + Range { from: '\u{61}', to: '\u{7a}', }, + Range { from: '\u{7b}', to: '\u{7f}', }, + Range { from: '\u{80}', to: '\u{9f}', }, + Range { from: '\u{a0}', to: '\u{a0}', }, + Range { from: '\u{a1}', to: '\u{a7}', }, + Range { from: '\u{a8}', to: '\u{aa}', }, + Range { from: '\u{ab}', to: '\u{ac}', }, + Range { from: '\u{ad}', to: '\u{af}', }, + Range { from: '\u{b0}', to: '\u{b1}', }, + Range { from: '\u{b2}', to: '\u{b5}', }, + Range { from: '\u{b6}', to: '\u{b7}', }, + Range { from: '\u{b8}', to: '\u{df}', }, + Range { from: '\u{e0}', to: '\u{ff}', }, + Range { from: '\u{100}', to: '\u{131}', }, + Range { from: '\u{132}', to: '\u{133}', }, + Range { from: '\u{134}', to: '\u{136}', }, + Range { from: '\u{137}', to: '\u{138}', }, + Range { from: '\u{139}', to: '\u{13e}', }, + Range { from: '\u{13f}', to: '\u{140}', }, + Range { from: '\u{141}', to: '\u{18b}', }, + Range { from: '\u{18c}', to: '\u{18d}', }, + Range { from: '\u{18e}', to: '\u{198}', }, + Range { from: '\u{199}', to: '\u{19b}', }, + Range { from: '\u{19c}', to: '\u{1a9}', }, + Range { from: '\u{1aa}', to: '\u{1ab}', }, + Range { from: '\u{1ac}', to: '\u{1b8}', }, + Range { from: '\u{1b9}', to: '\u{1bb}', }, + Range { from: '\u{1bc}', to: '\u{1bc}', }, + Range { from: '\u{1bd}', to: '\u{1c3}', }, + Range { from: '\u{1c4}', to: '\u{1c6}', }, + Range { from: '\u{1c7}', to: '\u{1c9}', }, + Range { from: '\u{1ca}', to: '\u{1cc}', }, + Range { from: '\u{1cd}', to: '\u{1db}', }, + Range { from: '\u{1dc}', to: '\u{1dd}', }, + Range { from: '\u{1de}', to: '\u{1ee}', }, + Range { from: '\u{1ef}', to: '\u{1f0}', }, + Range { from: '\u{1f1}', to: '\u{1f3}', }, + Range { from: '\u{1f4}', to: '\u{232}', }, + Range { from: '\u{233}', to: '\u{239}', }, + Range { from: '\u{23a}', to: '\u{23e}', }, + Range { from: '\u{23f}', to: '\u{240}', }, + Range { from: '\u{241}', to: '\u{24e}', }, + Range { from: '\u{24f}', to: '\u{2af}', }, + Range { from: '\u{2b0}', to: '\u{2b8}', }, + Range { from: '\u{2b9}', to: '\u{2d7}', }, + Range { from: '\u{2d8}', to: '\u{2dd}', }, + Range { from: '\u{2de}', to: '\u{2df}', }, + Range { from: '\u{2e0}', to: '\u{2e4}', }, + Range { from: '\u{2e5}', to: '\u{33f}', }, + Range { from: '\u{340}', to: '\u{345}', }, + Range { from: '\u{346}', to: '\u{34e}', }, + Range { from: '\u{34f}', to: '\u{34f}', }, + Range { from: '\u{350}', to: '\u{36f}', }, + Range { from: '\u{370}', to: '\u{377}', }, + Range { from: '\u{378}', to: '\u{379}', }, + Range { from: '\u{37a}', to: '\u{37a}', }, + Range { from: '\u{37b}', to: '\u{37d}', }, + Range { from: '\u{37e}', to: '\u{37f}', }, + Range { from: '\u{380}', to: '\u{383}', }, + Range { from: '\u{384}', to: '\u{3ab}', }, + Range { from: '\u{3ac}', to: '\u{3c1}', }, + Range { from: '\u{3c2}', to: '\u{3c2}', }, + Range { from: '\u{3c3}', to: '\u{3ce}', }, + Range { from: '\u{3cf}', to: '\u{3fa}', }, + Range { from: '\u{3fb}', to: '\u{3fc}', }, + Range { from: '\u{3fd}', to: '\u{42f}', }, + Range { from: '\u{430}', to: '\u{45f}', }, + Range { from: '\u{460}', to: '\u{480}', }, + Range { from: '\u{481}', to: '\u{489}', }, + Range { from: '\u{48a}', to: '\u{4cd}', }, + Range { from: '\u{4ce}', to: '\u{4cf}', }, + Range { from: '\u{4d0}', to: '\u{556}', }, + Range { from: '\u{557}', to: '\u{558}', }, + Range { from: '\u{559}', to: '\u{55f}', }, + Range { from: '\u{560}', to: '\u{560}', }, + Range { from: '\u{561}', to: '\u{586}', }, + Range { from: '\u{587}', to: '\u{588}', }, + Range { from: '\u{589}', to: '\u{58a}', }, + Range { from: '\u{58b}', to: '\u{58c}', }, + Range { from: '\u{58d}', to: '\u{58f}', }, + Range { from: '\u{590}', to: '\u{590}', }, + Range { from: '\u{591}', to: '\u{5c7}', }, + Range { from: '\u{5c8}', to: '\u{5cf}', }, + Range { from: '\u{5d0}', to: '\u{5ea}', }, + Range { from: '\u{5eb}', to: '\u{5ef}', }, + Range { from: '\u{5f0}', to: '\u{5f4}', }, + Range { from: '\u{5f5}', to: '\u{605}', }, + Range { from: '\u{606}', to: '\u{61b}', }, + Range { from: '\u{61c}', to: '\u{61d}', }, + Range { from: '\u{61e}', to: '\u{674}', }, + Range { from: '\u{675}', to: '\u{678}', }, + Range { from: '\u{679}', to: '\u{6dc}', }, + Range { from: '\u{6dd}', to: '\u{6dd}', }, + Range { from: '\u{6de}', to: '\u{70d}', }, + Range { from: '\u{70e}', to: '\u{70f}', }, + Range { from: '\u{710}', to: '\u{74a}', }, + Range { from: '\u{74b}', to: '\u{74c}', }, + Range { from: '\u{74d}', to: '\u{7b1}', }, + Range { from: '\u{7b2}', to: '\u{7bf}', }, + Range { from: '\u{7c0}', to: '\u{7fa}', }, + Range { from: '\u{7fb}', to: '\u{7ff}', }, + Range { from: '\u{800}', to: '\u{82d}', }, + Range { from: '\u{82e}', to: '\u{82f}', }, + Range { from: '\u{830}', to: '\u{83e}', }, + Range { from: '\u{83f}', to: '\u{83f}', }, + Range { from: '\u{840}', to: '\u{85b}', }, + Range { from: '\u{85c}', to: '\u{85d}', }, + Range { from: '\u{85e}', to: '\u{85f}', }, + Range { from: '\u{860}', to: '\u{86a}', }, + Range { from: '\u{86b}', to: '\u{89f}', }, + Range { from: '\u{8a0}', to: '\u{8b4}', }, + Range { from: '\u{8b5}', to: '\u{8b5}', }, + Range { from: '\u{8b6}', to: '\u{8bd}', }, + Range { from: '\u{8be}', to: '\u{8d3}', }, + Range { from: '\u{8d4}', to: '\u{8e1}', }, + Range { from: '\u{8e2}', to: '\u{8e2}', }, + Range { from: '\u{8e3}', to: '\u{957}', }, + Range { from: '\u{958}', to: '\u{95f}', }, + Range { from: '\u{960}', to: '\u{983}', }, + Range { from: '\u{984}', to: '\u{984}', }, + Range { from: '\u{985}', to: '\u{98c}', }, + Range { from: '\u{98d}', to: '\u{98e}', }, + Range { from: '\u{98f}', to: '\u{990}', }, + Range { from: '\u{991}', to: '\u{992}', }, + Range { from: '\u{993}', to: '\u{9a8}', }, + Range { from: '\u{9a9}', to: '\u{9a9}', }, + Range { from: '\u{9aa}', to: '\u{9b0}', }, + Range { from: '\u{9b1}', to: '\u{9b2}', }, + Range { from: '\u{9b3}', to: '\u{9b5}', }, + Range { from: '\u{9b6}', to: '\u{9b9}', }, + Range { from: '\u{9ba}', to: '\u{9bb}', }, + Range { from: '\u{9bc}', to: '\u{9c4}', }, + Range { from: '\u{9c5}', to: '\u{9c6}', }, + Range { from: '\u{9c7}', to: '\u{9c8}', }, + Range { from: '\u{9c9}', to: '\u{9ca}', }, + Range { from: '\u{9cb}', to: '\u{9ce}', }, + Range { from: '\u{9cf}', to: '\u{9d6}', }, + Range { from: '\u{9d7}', to: '\u{9d7}', }, + Range { from: '\u{9d8}', to: '\u{9db}', }, + Range { from: '\u{9dc}', to: '\u{9df}', }, + Range { from: '\u{9e0}', to: '\u{9e3}', }, + Range { from: '\u{9e4}', to: '\u{9e5}', }, + Range { from: '\u{9e6}', to: '\u{9fd}', }, + Range { from: '\u{9fe}', to: '\u{a00}', }, + Range { from: '\u{a01}', to: '\u{a03}', }, + Range { from: '\u{a04}', to: '\u{a04}', }, + Range { from: '\u{a05}', to: '\u{a0a}', }, + Range { from: '\u{a0b}', to: '\u{a0e}', }, + Range { from: '\u{a0f}', to: '\u{a10}', }, + Range { from: '\u{a11}', to: '\u{a12}', }, + Range { from: '\u{a13}', to: '\u{a28}', }, + Range { from: '\u{a29}', to: '\u{a29}', }, + Range { from: '\u{a2a}', to: '\u{a30}', }, + Range { from: '\u{a31}', to: '\u{a37}', }, + Range { from: '\u{a38}', to: '\u{a39}', }, + Range { from: '\u{a3a}', to: '\u{a3b}', }, + Range { from: '\u{a3c}', to: '\u{a3d}', }, + Range { from: '\u{a3e}', to: '\u{a42}', }, + Range { from: '\u{a43}', to: '\u{a46}', }, + Range { from: '\u{a47}', to: '\u{a48}', }, + Range { from: '\u{a49}', to: '\u{a4a}', }, + Range { from: '\u{a4b}', to: '\u{a4d}', }, + Range { from: '\u{a4e}', to: '\u{a50}', }, + Range { from: '\u{a51}', to: '\u{a51}', }, + Range { from: '\u{a52}', to: '\u{a58}', }, + Range { from: '\u{a59}', to: '\u{a5e}', }, + Range { from: '\u{a5f}', to: '\u{a65}', }, + Range { from: '\u{a66}', to: '\u{a75}', }, + Range { from: '\u{a76}', to: '\u{a80}', }, + Range { from: '\u{a81}', to: '\u{a83}', }, + Range { from: '\u{a84}', to: '\u{a84}', }, + Range { from: '\u{a85}', to: '\u{a8d}', }, + Range { from: '\u{a8e}', to: '\u{a8e}', }, + Range { from: '\u{a8f}', to: '\u{a91}', }, + Range { from: '\u{a92}', to: '\u{a92}', }, + Range { from: '\u{a93}', to: '\u{aa8}', }, + Range { from: '\u{aa9}', to: '\u{aa9}', }, + Range { from: '\u{aaa}', to: '\u{ab0}', }, + Range { from: '\u{ab1}', to: '\u{ab1}', }, + Range { from: '\u{ab2}', to: '\u{ab3}', }, + Range { from: '\u{ab4}', to: '\u{ab4}', }, + Range { from: '\u{ab5}', to: '\u{ab9}', }, + Range { from: '\u{aba}', to: '\u{abb}', }, + Range { from: '\u{abc}', to: '\u{ac5}', }, + Range { from: '\u{ac6}', to: '\u{ac6}', }, + Range { from: '\u{ac7}', to: '\u{ac9}', }, + Range { from: '\u{aca}', to: '\u{aca}', }, + Range { from: '\u{acb}', to: '\u{acd}', }, + Range { from: '\u{ace}', to: '\u{acf}', }, + Range { from: '\u{ad0}', to: '\u{ad0}', }, + Range { from: '\u{ad1}', to: '\u{adf}', }, + Range { from: '\u{ae0}', to: '\u{ae3}', }, + Range { from: '\u{ae4}', to: '\u{ae5}', }, + Range { from: '\u{ae6}', to: '\u{af1}', }, + Range { from: '\u{af2}', to: '\u{af8}', }, + Range { from: '\u{af9}', to: '\u{aff}', }, + Range { from: '\u{b00}', to: '\u{b00}', }, + Range { from: '\u{b01}', to: '\u{b03}', }, + Range { from: '\u{b04}', to: '\u{b04}', }, + Range { from: '\u{b05}', to: '\u{b0c}', }, + Range { from: '\u{b0d}', to: '\u{b0e}', }, + Range { from: '\u{b0f}', to: '\u{b10}', }, + Range { from: '\u{b11}', to: '\u{b12}', }, + Range { from: '\u{b13}', to: '\u{b28}', }, + Range { from: '\u{b29}', to: '\u{b29}', }, + Range { from: '\u{b2a}', to: '\u{b30}', }, + Range { from: '\u{b31}', to: '\u{b31}', }, + Range { from: '\u{b32}', to: '\u{b33}', }, + Range { from: '\u{b34}', to: '\u{b34}', }, + Range { from: '\u{b35}', to: '\u{b39}', }, + Range { from: '\u{b3a}', to: '\u{b3b}', }, + Range { from: '\u{b3c}', to: '\u{b44}', }, + Range { from: '\u{b45}', to: '\u{b46}', }, + Range { from: '\u{b47}', to: '\u{b48}', }, + Range { from: '\u{b49}', to: '\u{b4a}', }, + Range { from: '\u{b4b}', to: '\u{b4d}', }, + Range { from: '\u{b4e}', to: '\u{b55}', }, + Range { from: '\u{b56}', to: '\u{b57}', }, + Range { from: '\u{b58}', to: '\u{b5b}', }, + Range { from: '\u{b5c}', to: '\u{b5e}', }, + Range { from: '\u{b5f}', to: '\u{b63}', }, + Range { from: '\u{b64}', to: '\u{b65}', }, + Range { from: '\u{b66}', to: '\u{b77}', }, + Range { from: '\u{b78}', to: '\u{b81}', }, + Range { from: '\u{b82}', to: '\u{b83}', }, + Range { from: '\u{b84}', to: '\u{b84}', }, + Range { from: '\u{b85}', to: '\u{b8a}', }, + Range { from: '\u{b8b}', to: '\u{b8d}', }, + Range { from: '\u{b8e}', to: '\u{b90}', }, + Range { from: '\u{b91}', to: '\u{b91}', }, + Range { from: '\u{b92}', to: '\u{b95}', }, + Range { from: '\u{b96}', to: '\u{b98}', }, + Range { from: '\u{b99}', to: '\u{b9a}', }, + Range { from: '\u{b9b}', to: '\u{b9d}', }, + Range { from: '\u{b9e}', to: '\u{b9f}', }, + Range { from: '\u{ba0}', to: '\u{ba2}', }, + Range { from: '\u{ba3}', to: '\u{ba4}', }, + Range { from: '\u{ba5}', to: '\u{ba7}', }, + Range { from: '\u{ba8}', to: '\u{baa}', }, + Range { from: '\u{bab}', to: '\u{bad}', }, + Range { from: '\u{bae}', to: '\u{bb9}', }, + Range { from: '\u{bba}', to: '\u{bbd}', }, + Range { from: '\u{bbe}', to: '\u{bc2}', }, + Range { from: '\u{bc3}', to: '\u{bc5}', }, + Range { from: '\u{bc6}', to: '\u{bc8}', }, + Range { from: '\u{bc9}', to: '\u{bc9}', }, + Range { from: '\u{bca}', to: '\u{bcd}', }, + Range { from: '\u{bce}', to: '\u{bcf}', }, + Range { from: '\u{bd0}', to: '\u{bd0}', }, + Range { from: '\u{bd1}', to: '\u{bd6}', }, + Range { from: '\u{bd7}', to: '\u{bd7}', }, + Range { from: '\u{bd8}', to: '\u{be5}', }, + Range { from: '\u{be6}', to: '\u{bfa}', }, + Range { from: '\u{bfb}', to: '\u{bff}', }, + Range { from: '\u{c00}', to: '\u{c03}', }, + Range { from: '\u{c04}', to: '\u{c04}', }, + Range { from: '\u{c05}', to: '\u{c0c}', }, + Range { from: '\u{c0d}', to: '\u{c0d}', }, + Range { from: '\u{c0e}', to: '\u{c10}', }, + Range { from: '\u{c11}', to: '\u{c11}', }, + Range { from: '\u{c12}', to: '\u{c28}', }, + Range { from: '\u{c29}', to: '\u{c29}', }, + Range { from: '\u{c2a}', to: '\u{c39}', }, + Range { from: '\u{c3a}', to: '\u{c3c}', }, + Range { from: '\u{c3d}', to: '\u{c44}', }, + Range { from: '\u{c45}', to: '\u{c45}', }, + Range { from: '\u{c46}', to: '\u{c48}', }, + Range { from: '\u{c49}', to: '\u{c49}', }, + Range { from: '\u{c4a}', to: '\u{c4d}', }, + Range { from: '\u{c4e}', to: '\u{c54}', }, + Range { from: '\u{c55}', to: '\u{c56}', }, + Range { from: '\u{c57}', to: '\u{c57}', }, + Range { from: '\u{c58}', to: '\u{c5a}', }, + Range { from: '\u{c5b}', to: '\u{c5f}', }, + Range { from: '\u{c60}', to: '\u{c63}', }, + Range { from: '\u{c64}', to: '\u{c65}', }, + Range { from: '\u{c66}', to: '\u{c6f}', }, + Range { from: '\u{c70}', to: '\u{c77}', }, + Range { from: '\u{c78}', to: '\u{c83}', }, + Range { from: '\u{c84}', to: '\u{c84}', }, + Range { from: '\u{c85}', to: '\u{c8c}', }, + Range { from: '\u{c8d}', to: '\u{c8d}', }, + Range { from: '\u{c8e}', to: '\u{c90}', }, + Range { from: '\u{c91}', to: '\u{c91}', }, + Range { from: '\u{c92}', to: '\u{ca8}', }, + Range { from: '\u{ca9}', to: '\u{ca9}', }, + Range { from: '\u{caa}', to: '\u{cb3}', }, + Range { from: '\u{cb4}', to: '\u{cb4}', }, + Range { from: '\u{cb5}', to: '\u{cb9}', }, + Range { from: '\u{cba}', to: '\u{cbb}', }, + Range { from: '\u{cbc}', to: '\u{cc4}', }, + Range { from: '\u{cc5}', to: '\u{cc5}', }, + Range { from: '\u{cc6}', to: '\u{cc8}', }, + Range { from: '\u{cc9}', to: '\u{cc9}', }, + Range { from: '\u{cca}', to: '\u{ccd}', }, + Range { from: '\u{cce}', to: '\u{cd4}', }, + Range { from: '\u{cd5}', to: '\u{cd6}', }, + Range { from: '\u{cd7}', to: '\u{cdd}', }, + Range { from: '\u{cde}', to: '\u{cdf}', }, + Range { from: '\u{ce0}', to: '\u{ce3}', }, + Range { from: '\u{ce4}', to: '\u{ce5}', }, + Range { from: '\u{ce6}', to: '\u{cef}', }, + Range { from: '\u{cf0}', to: '\u{cf0}', }, + Range { from: '\u{cf1}', to: '\u{cf2}', }, + Range { from: '\u{cf3}', to: '\u{cff}', }, + Range { from: '\u{d00}', to: '\u{d03}', }, + Range { from: '\u{d04}', to: '\u{d04}', }, + Range { from: '\u{d05}', to: '\u{d0c}', }, + Range { from: '\u{d0d}', to: '\u{d0d}', }, + Range { from: '\u{d0e}', to: '\u{d10}', }, + Range { from: '\u{d11}', to: '\u{d11}', }, + Range { from: '\u{d12}', to: '\u{d44}', }, + Range { from: '\u{d45}', to: '\u{d45}', }, + Range { from: '\u{d46}', to: '\u{d48}', }, + Range { from: '\u{d49}', to: '\u{d49}', }, + Range { from: '\u{d4a}', to: '\u{d4f}', }, + Range { from: '\u{d50}', to: '\u{d53}', }, + Range { from: '\u{d54}', to: '\u{d63}', }, + Range { from: '\u{d64}', to: '\u{d65}', }, + Range { from: '\u{d66}', to: '\u{d7f}', }, + Range { from: '\u{d80}', to: '\u{d81}', }, + Range { from: '\u{d82}', to: '\u{d83}', }, + Range { from: '\u{d84}', to: '\u{d84}', }, + Range { from: '\u{d85}', to: '\u{d96}', }, + Range { from: '\u{d97}', to: '\u{d99}', }, + Range { from: '\u{d9a}', to: '\u{db1}', }, + Range { from: '\u{db2}', to: '\u{db2}', }, + Range { from: '\u{db3}', to: '\u{dbb}', }, + Range { from: '\u{dbc}', to: '\u{dbd}', }, + Range { from: '\u{dbe}', to: '\u{dbf}', }, + Range { from: '\u{dc0}', to: '\u{dc6}', }, + Range { from: '\u{dc7}', to: '\u{dc9}', }, + Range { from: '\u{dca}', to: '\u{dca}', }, + Range { from: '\u{dcb}', to: '\u{dce}', }, + Range { from: '\u{dcf}', to: '\u{dd4}', }, + Range { from: '\u{dd5}', to: '\u{dd7}', }, + Range { from: '\u{dd8}', to: '\u{ddf}', }, + Range { from: '\u{de0}', to: '\u{de5}', }, + Range { from: '\u{de6}', to: '\u{def}', }, + Range { from: '\u{df0}', to: '\u{df1}', }, + Range { from: '\u{df2}', to: '\u{df4}', }, + Range { from: '\u{df5}', to: '\u{e00}', }, + Range { from: '\u{e01}', to: '\u{e32}', }, + Range { from: '\u{e33}', to: '\u{e33}', }, + Range { from: '\u{e34}', to: '\u{e3a}', }, + Range { from: '\u{e3b}', to: '\u{e3e}', }, + Range { from: '\u{e3f}', to: '\u{e5b}', }, + Range { from: '\u{e5c}', to: '\u{e80}', }, + Range { from: '\u{e81}', to: '\u{e82}', }, + Range { from: '\u{e83}', to: '\u{e84}', }, + Range { from: '\u{e85}', to: '\u{e86}', }, + Range { from: '\u{e87}', to: '\u{e88}', }, + Range { from: '\u{e89}', to: '\u{e8a}', }, + Range { from: '\u{e8b}', to: '\u{e8c}', }, + Range { from: '\u{e8d}', to: '\u{e8d}', }, + Range { from: '\u{e8e}', to: '\u{e93}', }, + Range { from: '\u{e94}', to: '\u{e97}', }, + Range { from: '\u{e98}', to: '\u{e98}', }, + Range { from: '\u{e99}', to: '\u{e9f}', }, + Range { from: '\u{ea0}', to: '\u{ea0}', }, + Range { from: '\u{ea1}', to: '\u{ea3}', }, + Range { from: '\u{ea4}', to: '\u{ea7}', }, + Range { from: '\u{ea8}', to: '\u{ea9}', }, + Range { from: '\u{eaa}', to: '\u{eab}', }, + Range { from: '\u{eac}', to: '\u{eac}', }, + Range { from: '\u{ead}', to: '\u{eb2}', }, + Range { from: '\u{eb3}', to: '\u{eb3}', }, + Range { from: '\u{eb4}', to: '\u{eb9}', }, + Range { from: '\u{eba}', to: '\u{eba}', }, + Range { from: '\u{ebb}', to: '\u{ebd}', }, + Range { from: '\u{ebe}', to: '\u{ebf}', }, + Range { from: '\u{ec0}', to: '\u{ec4}', }, + Range { from: '\u{ec5}', to: '\u{ec7}', }, + Range { from: '\u{ec8}', to: '\u{ecd}', }, + Range { from: '\u{ece}', to: '\u{ecf}', }, + Range { from: '\u{ed0}', to: '\u{ed9}', }, + Range { from: '\u{eda}', to: '\u{edb}', }, + Range { from: '\u{edc}', to: '\u{edd}', }, + Range { from: '\u{ede}', to: '\u{edf}', }, + Range { from: '\u{ee0}', to: '\u{eff}', }, + Range { from: '\u{f00}', to: '\u{f0b}', }, + Range { from: '\u{f0c}', to: '\u{f0c}', }, + Range { from: '\u{f0d}', to: '\u{f42}', }, + Range { from: '\u{f43}', to: '\u{f43}', }, + Range { from: '\u{f44}', to: '\u{f47}', }, + Range { from: '\u{f48}', to: '\u{f48}', }, + Range { from: '\u{f49}', to: '\u{f4c}', }, + Range { from: '\u{f4d}', to: '\u{f4d}', }, + Range { from: '\u{f4e}', to: '\u{f51}', }, + Range { from: '\u{f52}', to: '\u{f52}', }, + Range { from: '\u{f53}', to: '\u{f56}', }, + Range { from: '\u{f57}', to: '\u{f57}', }, + Range { from: '\u{f58}', to: '\u{f5b}', }, + Range { from: '\u{f5c}', to: '\u{f5c}', }, + Range { from: '\u{f5d}', to: '\u{f68}', }, + Range { from: '\u{f69}', to: '\u{f69}', }, + Range { from: '\u{f6a}', to: '\u{f6c}', }, + Range { from: '\u{f6d}', to: '\u{f70}', }, + Range { from: '\u{f71}', to: '\u{f72}', }, + Range { from: '\u{f73}', to: '\u{f79}', }, + Range { from: '\u{f7a}', to: '\u{f80}', }, + Range { from: '\u{f81}', to: '\u{f81}', }, + Range { from: '\u{f82}', to: '\u{f92}', }, + Range { from: '\u{f93}', to: '\u{f93}', }, + Range { from: '\u{f94}', to: '\u{f97}', }, + Range { from: '\u{f98}', to: '\u{f98}', }, + Range { from: '\u{f99}', to: '\u{f9c}', }, + Range { from: '\u{f9d}', to: '\u{f9d}', }, + Range { from: '\u{f9e}', to: '\u{fa1}', }, + Range { from: '\u{fa2}', to: '\u{fa2}', }, + Range { from: '\u{fa3}', to: '\u{fa6}', }, + Range { from: '\u{fa7}', to: '\u{fa7}', }, + Range { from: '\u{fa8}', to: '\u{fab}', }, + Range { from: '\u{fac}', to: '\u{fac}', }, + Range { from: '\u{fad}', to: '\u{fb8}', }, + Range { from: '\u{fb9}', to: '\u{fb9}', }, + Range { from: '\u{fba}', to: '\u{fbc}', }, + Range { from: '\u{fbd}', to: '\u{fbd}', }, + Range { from: '\u{fbe}', to: '\u{fcc}', }, + Range { from: '\u{fcd}', to: '\u{fcd}', }, + Range { from: '\u{fce}', to: '\u{fda}', }, + Range { from: '\u{fdb}', to: '\u{fff}', }, + Range { from: '\u{1000}', to: '\u{109f}', }, + Range { from: '\u{10a0}', to: '\u{10c6}', }, + Range { from: '\u{10c7}', to: '\u{10c7}', }, + Range { from: '\u{10c8}', to: '\u{10cc}', }, + Range { from: '\u{10cd}', to: '\u{10cd}', }, + Range { from: '\u{10ce}', to: '\u{10cf}', }, + Range { from: '\u{10d0}', to: '\u{10fb}', }, + Range { from: '\u{10fc}', to: '\u{10fc}', }, + Range { from: '\u{10fd}', to: '\u{115e}', }, + Range { from: '\u{115f}', to: '\u{1160}', }, + Range { from: '\u{1161}', to: '\u{1248}', }, + Range { from: '\u{1249}', to: '\u{1249}', }, + Range { from: '\u{124a}', to: '\u{124d}', }, + Range { from: '\u{124e}', to: '\u{124f}', }, + Range { from: '\u{1250}', to: '\u{1256}', }, + Range { from: '\u{1257}', to: '\u{1259}', }, + Range { from: '\u{125a}', to: '\u{125d}', }, + Range { from: '\u{125e}', to: '\u{125f}', }, + Range { from: '\u{1260}', to: '\u{1288}', }, + Range { from: '\u{1289}', to: '\u{1289}', }, + Range { from: '\u{128a}', to: '\u{128d}', }, + Range { from: '\u{128e}', to: '\u{128f}', }, + Range { from: '\u{1290}', to: '\u{12b0}', }, + Range { from: '\u{12b1}', to: '\u{12b1}', }, + Range { from: '\u{12b2}', to: '\u{12b5}', }, + Range { from: '\u{12b6}', to: '\u{12b7}', }, + Range { from: '\u{12b8}', to: '\u{12be}', }, + Range { from: '\u{12bf}', to: '\u{12c1}', }, + Range { from: '\u{12c2}', to: '\u{12c5}', }, + Range { from: '\u{12c6}', to: '\u{12c7}', }, + Range { from: '\u{12c8}', to: '\u{12d6}', }, + Range { from: '\u{12d7}', to: '\u{12d7}', }, + Range { from: '\u{12d8}', to: '\u{1310}', }, + Range { from: '\u{1311}', to: '\u{1311}', }, + Range { from: '\u{1312}', to: '\u{1315}', }, + Range { from: '\u{1316}', to: '\u{1317}', }, + Range { from: '\u{1318}', to: '\u{135a}', }, + Range { from: '\u{135b}', to: '\u{135c}', }, + Range { from: '\u{135d}', to: '\u{137c}', }, + Range { from: '\u{137d}', to: '\u{137f}', }, + Range { from: '\u{1380}', to: '\u{1399}', }, + Range { from: '\u{139a}', to: '\u{139f}', }, + Range { from: '\u{13a0}', to: '\u{13f5}', }, + Range { from: '\u{13f6}', to: '\u{13f7}', }, + Range { from: '\u{13f8}', to: '\u{13fd}', }, + Range { from: '\u{13fe}', to: '\u{13ff}', }, + Range { from: '\u{1400}', to: '\u{167f}', }, + Range { from: '\u{1680}', to: '\u{1680}', }, + Range { from: '\u{1681}', to: '\u{169c}', }, + Range { from: '\u{169d}', to: '\u{169f}', }, + Range { from: '\u{16a0}', to: '\u{16f8}', }, + Range { from: '\u{16f9}', to: '\u{16ff}', }, + Range { from: '\u{1700}', to: '\u{170c}', }, + Range { from: '\u{170d}', to: '\u{170d}', }, + Range { from: '\u{170e}', to: '\u{1714}', }, + Range { from: '\u{1715}', to: '\u{171f}', }, + Range { from: '\u{1720}', to: '\u{1736}', }, + Range { from: '\u{1737}', to: '\u{173f}', }, + Range { from: '\u{1740}', to: '\u{1753}', }, + Range { from: '\u{1754}', to: '\u{175f}', }, + Range { from: '\u{1760}', to: '\u{176c}', }, + Range { from: '\u{176d}', to: '\u{176d}', }, + Range { from: '\u{176e}', to: '\u{1770}', }, + Range { from: '\u{1771}', to: '\u{1771}', }, + Range { from: '\u{1772}', to: '\u{1773}', }, + Range { from: '\u{1774}', to: '\u{177f}', }, + Range { from: '\u{1780}', to: '\u{17b3}', }, + Range { from: '\u{17b4}', to: '\u{17b5}', }, + Range { from: '\u{17b6}', to: '\u{17dd}', }, + Range { from: '\u{17de}', to: '\u{17df}', }, + Range { from: '\u{17e0}', to: '\u{17e9}', }, + Range { from: '\u{17ea}', to: '\u{17ef}', }, + Range { from: '\u{17f0}', to: '\u{17f9}', }, + Range { from: '\u{17fa}', to: '\u{17ff}', }, + Range { from: '\u{1800}', to: '\u{1805}', }, + Range { from: '\u{1806}', to: '\u{1806}', }, + Range { from: '\u{1807}', to: '\u{180a}', }, + Range { from: '\u{180b}', to: '\u{180d}', }, + Range { from: '\u{180e}', to: '\u{180f}', }, + Range { from: '\u{1810}', to: '\u{1819}', }, + Range { from: '\u{181a}', to: '\u{181f}', }, + Range { from: '\u{1820}', to: '\u{1877}', }, + Range { from: '\u{1878}', to: '\u{187f}', }, + Range { from: '\u{1880}', to: '\u{18aa}', }, + Range { from: '\u{18ab}', to: '\u{18af}', }, + Range { from: '\u{18b0}', to: '\u{18f5}', }, + Range { from: '\u{18f6}', to: '\u{18ff}', }, + Range { from: '\u{1900}', to: '\u{191e}', }, + Range { from: '\u{191f}', to: '\u{191f}', }, + Range { from: '\u{1920}', to: '\u{192b}', }, + Range { from: '\u{192c}', to: '\u{192f}', }, + Range { from: '\u{1930}', to: '\u{193b}', }, + Range { from: '\u{193c}', to: '\u{193f}', }, + Range { from: '\u{1940}', to: '\u{1940}', }, + Range { from: '\u{1941}', to: '\u{1943}', }, + Range { from: '\u{1944}', to: '\u{196d}', }, + Range { from: '\u{196e}', to: '\u{196f}', }, + Range { from: '\u{1970}', to: '\u{1974}', }, + Range { from: '\u{1975}', to: '\u{197f}', }, + Range { from: '\u{1980}', to: '\u{19ab}', }, + Range { from: '\u{19ac}', to: '\u{19af}', }, + Range { from: '\u{19b0}', to: '\u{19c9}', }, + Range { from: '\u{19ca}', to: '\u{19cf}', }, + Range { from: '\u{19d0}', to: '\u{19da}', }, + Range { from: '\u{19db}', to: '\u{19dd}', }, + Range { from: '\u{19de}', to: '\u{1a1b}', }, + Range { from: '\u{1a1c}', to: '\u{1a1d}', }, + Range { from: '\u{1a1e}', to: '\u{1a5e}', }, + Range { from: '\u{1a5f}', to: '\u{1a5f}', }, + Range { from: '\u{1a60}', to: '\u{1a7c}', }, + Range { from: '\u{1a7d}', to: '\u{1a7e}', }, + Range { from: '\u{1a7f}', to: '\u{1a89}', }, + Range { from: '\u{1a8a}', to: '\u{1a8f}', }, + Range { from: '\u{1a90}', to: '\u{1a99}', }, + Range { from: '\u{1a9a}', to: '\u{1a9f}', }, + Range { from: '\u{1aa0}', to: '\u{1aad}', }, + Range { from: '\u{1aae}', to: '\u{1aaf}', }, + Range { from: '\u{1ab0}', to: '\u{1abe}', }, + Range { from: '\u{1abf}', to: '\u{1aff}', }, + Range { from: '\u{1b00}', to: '\u{1b4b}', }, + Range { from: '\u{1b4c}', to: '\u{1b4f}', }, + Range { from: '\u{1b50}', to: '\u{1b7c}', }, + Range { from: '\u{1b7d}', to: '\u{1b7f}', }, + Range { from: '\u{1b80}', to: '\u{1bf3}', }, + Range { from: '\u{1bf4}', to: '\u{1bfb}', }, + Range { from: '\u{1bfc}', to: '\u{1c37}', }, + Range { from: '\u{1c38}', to: '\u{1c3a}', }, + Range { from: '\u{1c3b}', to: '\u{1c49}', }, + Range { from: '\u{1c4a}', to: '\u{1c4c}', }, + Range { from: '\u{1c4d}', to: '\u{1c7f}', }, + Range { from: '\u{1c80}', to: '\u{1c83}', }, + Range { from: '\u{1c84}', to: '\u{1c85}', }, + Range { from: '\u{1c86}', to: '\u{1c88}', }, + Range { from: '\u{1c89}', to: '\u{1cbf}', }, + Range { from: '\u{1cc0}', to: '\u{1cc7}', }, + Range { from: '\u{1cc8}', to: '\u{1ccf}', }, + Range { from: '\u{1cd0}', to: '\u{1cf9}', }, + Range { from: '\u{1cfa}', to: '\u{1cff}', }, + Range { from: '\u{1d00}', to: '\u{1d2b}', }, + Range { from: '\u{1d2c}', to: '\u{1d6a}', }, + Range { from: '\u{1d6b}', to: '\u{1d77}', }, + Range { from: '\u{1d78}', to: '\u{1d78}', }, + Range { from: '\u{1d79}', to: '\u{1d9a}', }, + Range { from: '\u{1d9b}', to: '\u{1dbf}', }, + Range { from: '\u{1dc0}', to: '\u{1df9}', }, + Range { from: '\u{1dfa}', to: '\u{1dfa}', }, + Range { from: '\u{1dfb}', to: '\u{1dff}', }, + Range { from: '\u{1e00}', to: '\u{1e94}', }, + Range { from: '\u{1e95}', to: '\u{1e99}', }, + Range { from: '\u{1e9a}', to: '\u{1e9b}', }, + Range { from: '\u{1e9c}', to: '\u{1e9d}', }, + Range { from: '\u{1e9e}', to: '\u{1efe}', }, + Range { from: '\u{1eff}', to: '\u{1f07}', }, + Range { from: '\u{1f08}', to: '\u{1f0f}', }, + Range { from: '\u{1f10}', to: '\u{1f15}', }, + Range { from: '\u{1f16}', to: '\u{1f17}', }, + Range { from: '\u{1f18}', to: '\u{1f1d}', }, + Range { from: '\u{1f1e}', to: '\u{1f1f}', }, + Range { from: '\u{1f20}', to: '\u{1f27}', }, + Range { from: '\u{1f28}', to: '\u{1f2f}', }, + Range { from: '\u{1f30}', to: '\u{1f37}', }, + Range { from: '\u{1f38}', to: '\u{1f3f}', }, + Range { from: '\u{1f40}', to: '\u{1f45}', }, + Range { from: '\u{1f46}', to: '\u{1f47}', }, + Range { from: '\u{1f48}', to: '\u{1f4d}', }, + Range { from: '\u{1f4e}', to: '\u{1f4f}', }, + Range { from: '\u{1f50}', to: '\u{1f57}', }, + Range { from: '\u{1f58}', to: '\u{1f5f}', }, + Range { from: '\u{1f60}', to: '\u{1f67}', }, + Range { from: '\u{1f68}', to: '\u{1f7d}', }, + Range { from: '\u{1f7e}', to: '\u{1f7f}', }, + Range { from: '\u{1f80}', to: '\u{1faf}', }, + Range { from: '\u{1fb0}', to: '\u{1fb1}', }, + Range { from: '\u{1fb2}', to: '\u{1fcf}', }, + Range { from: '\u{1fd0}', to: '\u{1fd2}', }, + Range { from: '\u{1fd3}', to: '\u{1fd3}', }, + Range { from: '\u{1fd4}', to: '\u{1fd5}', }, + Range { from: '\u{1fd6}', to: '\u{1fd7}', }, + Range { from: '\u{1fd8}', to: '\u{1fdf}', }, + Range { from: '\u{1fe0}', to: '\u{1fe2}', }, + Range { from: '\u{1fe3}', to: '\u{1fe3}', }, + Range { from: '\u{1fe4}', to: '\u{1fe7}', }, + Range { from: '\u{1fe8}', to: '\u{1fef}', }, + Range { from: '\u{1ff0}', to: '\u{1ff1}', }, + Range { from: '\u{1ff2}', to: '\u{1fff}', }, + Range { from: '\u{2000}', to: '\u{200a}', }, + Range { from: '\u{200b}', to: '\u{200b}', }, + Range { from: '\u{200c}', to: '\u{200d}', }, + Range { from: '\u{200e}', to: '\u{200f}', }, + Range { from: '\u{2010}', to: '\u{2011}', }, + Range { from: '\u{2012}', to: '\u{2016}', }, + Range { from: '\u{2017}', to: '\u{2017}', }, + Range { from: '\u{2018}', to: '\u{2023}', }, + Range { from: '\u{2024}', to: '\u{2026}', }, + Range { from: '\u{2027}', to: '\u{2027}', }, + Range { from: '\u{2028}', to: '\u{202e}', }, + Range { from: '\u{202f}', to: '\u{202f}', }, + Range { from: '\u{2030}', to: '\u{2032}', }, + Range { from: '\u{2033}', to: '\u{2037}', }, + Range { from: '\u{2038}', to: '\u{203b}', }, + Range { from: '\u{203c}', to: '\u{203e}', }, + Range { from: '\u{203f}', to: '\u{2046}', }, + Range { from: '\u{2047}', to: '\u{2049}', }, + Range { from: '\u{204a}', to: '\u{2056}', }, + Range { from: '\u{2057}', to: '\u{2057}', }, + Range { from: '\u{2058}', to: '\u{205e}', }, + Range { from: '\u{205f}', to: '\u{2060}', }, + Range { from: '\u{2061}', to: '\u{2063}', }, + Range { from: '\u{2064}', to: '\u{2064}', }, + Range { from: '\u{2065}', to: '\u{206f}', }, + Range { from: '\u{2070}', to: '\u{2071}', }, + Range { from: '\u{2072}', to: '\u{2073}', }, + Range { from: '\u{2074}', to: '\u{209c}', }, + Range { from: '\u{209d}', to: '\u{209f}', }, + Range { from: '\u{20a0}', to: '\u{20a7}', }, + Range { from: '\u{20a8}', to: '\u{20a8}', }, + Range { from: '\u{20a9}', to: '\u{20bf}', }, + Range { from: '\u{20c0}', to: '\u{20cf}', }, + Range { from: '\u{20d0}', to: '\u{20f0}', }, + Range { from: '\u{20f1}', to: '\u{20ff}', }, + Range { from: '\u{2100}', to: '\u{210a}', }, + Range { from: '\u{210b}', to: '\u{210e}', }, + Range { from: '\u{210f}', to: '\u{210f}', }, + Range { from: '\u{2110}', to: '\u{2111}', }, + Range { from: '\u{2112}', to: '\u{2113}', }, + Range { from: '\u{2114}', to: '\u{2116}', }, + Range { from: '\u{2117}', to: '\u{2118}', }, + Range { from: '\u{2119}', to: '\u{211a}', }, + Range { from: '\u{211b}', to: '\u{211d}', }, + Range { from: '\u{211e}', to: '\u{211f}', }, + Range { from: '\u{2120}', to: '\u{212e}', }, + Range { from: '\u{212f}', to: '\u{2130}', }, + Range { from: '\u{2131}', to: '\u{213c}', }, + Range { from: '\u{213d}', to: '\u{213e}', }, + Range { from: '\u{213f}', to: '\u{2140}', }, + Range { from: '\u{2141}', to: '\u{2144}', }, + Range { from: '\u{2145}', to: '\u{2146}', }, + Range { from: '\u{2147}', to: '\u{2149}', }, + Range { from: '\u{214a}', to: '\u{214f}', }, + Range { from: '\u{2150}', to: '\u{217f}', }, + Range { from: '\u{2180}', to: '\u{2182}', }, + Range { from: '\u{2183}', to: '\u{2183}', }, + Range { from: '\u{2184}', to: '\u{2188}', }, + Range { from: '\u{2189}', to: '\u{2189}', }, + Range { from: '\u{218a}', to: '\u{218b}', }, + Range { from: '\u{218c}', to: '\u{218f}', }, + Range { from: '\u{2190}', to: '\u{222b}', }, + Range { from: '\u{222c}', to: '\u{2230}', }, + Range { from: '\u{2231}', to: '\u{225f}', }, + Range { from: '\u{2260}', to: '\u{2260}', }, + Range { from: '\u{2261}', to: '\u{226d}', }, + Range { from: '\u{226e}', to: '\u{226f}', }, + Range { from: '\u{2270}', to: '\u{2328}', }, + Range { from: '\u{2329}', to: '\u{232a}', }, + Range { from: '\u{232b}', to: '\u{2426}', }, + Range { from: '\u{2427}', to: '\u{243f}', }, + Range { from: '\u{2440}', to: '\u{244a}', }, + Range { from: '\u{244b}', to: '\u{245f}', }, + Range { from: '\u{2460}', to: '\u{2487}', }, + Range { from: '\u{2488}', to: '\u{249b}', }, + Range { from: '\u{249c}', to: '\u{24ea}', }, + Range { from: '\u{24eb}', to: '\u{2a0b}', }, + Range { from: '\u{2a0c}', to: '\u{2a0c}', }, + Range { from: '\u{2a0d}', to: '\u{2a73}', }, + Range { from: '\u{2a74}', to: '\u{2a76}', }, + Range { from: '\u{2a77}', to: '\u{2adb}', }, + Range { from: '\u{2adc}', to: '\u{2adc}', }, + Range { from: '\u{2add}', to: '\u{2b73}', }, + Range { from: '\u{2b74}', to: '\u{2b75}', }, + Range { from: '\u{2b76}', to: '\u{2b95}', }, + Range { from: '\u{2b96}', to: '\u{2b97}', }, + Range { from: '\u{2b98}', to: '\u{2bb9}', }, + Range { from: '\u{2bba}', to: '\u{2bbc}', }, + Range { from: '\u{2bbd}', to: '\u{2bc8}', }, + Range { from: '\u{2bc9}', to: '\u{2bc9}', }, + Range { from: '\u{2bca}', to: '\u{2bd2}', }, + Range { from: '\u{2bd3}', to: '\u{2beb}', }, + Range { from: '\u{2bec}', to: '\u{2bef}', }, + Range { from: '\u{2bf0}', to: '\u{2bff}', }, + Range { from: '\u{2c00}', to: '\u{2c2f}', }, + Range { from: '\u{2c30}', to: '\u{2c5e}', }, + Range { from: '\u{2c5f}', to: '\u{2c64}', }, + Range { from: '\u{2c65}', to: '\u{2c66}', }, + Range { from: '\u{2c67}', to: '\u{2c72}', }, + Range { from: '\u{2c73}', to: '\u{2c74}', }, + Range { from: '\u{2c75}', to: '\u{2c75}', }, + Range { from: '\u{2c76}', to: '\u{2c7b}', }, + Range { from: '\u{2c7c}', to: '\u{2ce2}', }, + Range { from: '\u{2ce3}', to: '\u{2cea}', }, + Range { from: '\u{2ceb}', to: '\u{2ced}', }, + Range { from: '\u{2cee}', to: '\u{2cf1}', }, + Range { from: '\u{2cf2}', to: '\u{2cf3}', }, + Range { from: '\u{2cf4}', to: '\u{2cf8}', }, + Range { from: '\u{2cf9}', to: '\u{2d25}', }, + Range { from: '\u{2d26}', to: '\u{2d27}', }, + Range { from: '\u{2d28}', to: '\u{2d2c}', }, + Range { from: '\u{2d2d}', to: '\u{2d2d}', }, + Range { from: '\u{2d2e}', to: '\u{2d2f}', }, + Range { from: '\u{2d30}', to: '\u{2d67}', }, + Range { from: '\u{2d68}', to: '\u{2d6e}', }, + Range { from: '\u{2d6f}', to: '\u{2d70}', }, + Range { from: '\u{2d71}', to: '\u{2d7e}', }, + Range { from: '\u{2d7f}', to: '\u{2d96}', }, + Range { from: '\u{2d97}', to: '\u{2d9f}', }, + Range { from: '\u{2da0}', to: '\u{2da6}', }, + Range { from: '\u{2da7}', to: '\u{2da7}', }, + Range { from: '\u{2da8}', to: '\u{2dae}', }, + Range { from: '\u{2daf}', to: '\u{2daf}', }, + Range { from: '\u{2db0}', to: '\u{2db6}', }, + Range { from: '\u{2db7}', to: '\u{2db7}', }, + Range { from: '\u{2db8}', to: '\u{2dbe}', }, + Range { from: '\u{2dbf}', to: '\u{2dbf}', }, + Range { from: '\u{2dc0}', to: '\u{2dc6}', }, + Range { from: '\u{2dc7}', to: '\u{2dc7}', }, + Range { from: '\u{2dc8}', to: '\u{2dce}', }, + Range { from: '\u{2dcf}', to: '\u{2dcf}', }, + Range { from: '\u{2dd0}', to: '\u{2dd6}', }, + Range { from: '\u{2dd7}', to: '\u{2dd7}', }, + Range { from: '\u{2dd8}', to: '\u{2dde}', }, + Range { from: '\u{2ddf}', to: '\u{2ddf}', }, + Range { from: '\u{2de0}', to: '\u{2e49}', }, + Range { from: '\u{2e4a}', to: '\u{2e7f}', }, + Range { from: '\u{2e80}', to: '\u{2e99}', }, + Range { from: '\u{2e9a}', to: '\u{2e9a}', }, + Range { from: '\u{2e9b}', to: '\u{2e9e}', }, + Range { from: '\u{2e9f}', to: '\u{2e9f}', }, + Range { from: '\u{2ea0}', to: '\u{2ef2}', }, + Range { from: '\u{2ef3}', to: '\u{2ef3}', }, + Range { from: '\u{2ef4}', to: '\u{2eff}', }, + Range { from: '\u{2f00}', to: '\u{2fd5}', }, + Range { from: '\u{2fd6}', to: '\u{2fff}', }, + Range { from: '\u{3000}', to: '\u{3002}', }, + Range { from: '\u{3003}', to: '\u{3035}', }, + Range { from: '\u{3036}', to: '\u{303a}', }, + Range { from: '\u{303b}', to: '\u{303f}', }, + Range { from: '\u{3040}', to: '\u{3040}', }, + Range { from: '\u{3041}', to: '\u{3096}', }, + Range { from: '\u{3097}', to: '\u{3098}', }, + Range { from: '\u{3099}', to: '\u{309a}', }, + Range { from: '\u{309b}', to: '\u{309c}', }, + Range { from: '\u{309d}', to: '\u{309e}', }, + Range { from: '\u{309f}', to: '\u{309f}', }, + Range { from: '\u{30a0}', to: '\u{30fe}', }, + Range { from: '\u{30ff}', to: '\u{30ff}', }, + Range { from: '\u{3100}', to: '\u{3104}', }, + Range { from: '\u{3105}', to: '\u{312e}', }, + Range { from: '\u{312f}', to: '\u{3130}', }, + Range { from: '\u{3131}', to: '\u{318f}', }, + Range { from: '\u{3190}', to: '\u{3191}', }, + Range { from: '\u{3192}', to: '\u{319f}', }, + Range { from: '\u{31a0}', to: '\u{31ba}', }, + Range { from: '\u{31bb}', to: '\u{31bf}', }, + Range { from: '\u{31c0}', to: '\u{31e3}', }, + Range { from: '\u{31e4}', to: '\u{31ef}', }, + Range { from: '\u{31f0}', to: '\u{31ff}', }, + Range { from: '\u{3200}', to: '\u{3247}', }, + Range { from: '\u{3248}', to: '\u{324f}', }, + Range { from: '\u{3250}', to: '\u{33ff}', }, + Range { from: '\u{3400}', to: '\u{4db5}', }, + Range { from: '\u{4db6}', to: '\u{4dbf}', }, + Range { from: '\u{4dc0}', to: '\u{9fea}', }, + Range { from: '\u{9feb}', to: '\u{9fff}', }, + Range { from: '\u{a000}', to: '\u{a48c}', }, + Range { from: '\u{a48d}', to: '\u{a48f}', }, + Range { from: '\u{a490}', to: '\u{a4c6}', }, + Range { from: '\u{a4c7}', to: '\u{a4cf}', }, + Range { from: '\u{a4d0}', to: '\u{a62b}', }, + Range { from: '\u{a62c}', to: '\u{a63f}', }, + Range { from: '\u{a640}', to: '\u{a66c}', }, + Range { from: '\u{a66d}', to: '\u{a67f}', }, + Range { from: '\u{a680}', to: '\u{a69d}', }, + Range { from: '\u{a69e}', to: '\u{a6f7}', }, + Range { from: '\u{a6f8}', to: '\u{a6ff}', }, + Range { from: '\u{a700}', to: '\u{a721}', }, + Range { from: '\u{a722}', to: '\u{a72e}', }, + Range { from: '\u{a72f}', to: '\u{a731}', }, + Range { from: '\u{a732}', to: '\u{a770}', }, + Range { from: '\u{a771}', to: '\u{a778}', }, + Range { from: '\u{a779}', to: '\u{a786}', }, + Range { from: '\u{a787}', to: '\u{a78a}', }, + Range { from: '\u{a78b}', to: '\u{a78d}', }, + Range { from: '\u{a78e}', to: '\u{a78f}', }, + Range { from: '\u{a790}', to: '\u{a792}', }, + Range { from: '\u{a793}', to: '\u{a795}', }, + Range { from: '\u{a796}', to: '\u{a7b7}', }, + Range { from: '\u{a7b8}', to: '\u{a7f6}', }, + Range { from: '\u{a7f7}', to: '\u{a7f9}', }, + Range { from: '\u{a7fa}', to: '\u{a82b}', }, + Range { from: '\u{a82c}', to: '\u{a82f}', }, + Range { from: '\u{a830}', to: '\u{a839}', }, + Range { from: '\u{a83a}', to: '\u{a83f}', }, + Range { from: '\u{a840}', to: '\u{a877}', }, + Range { from: '\u{a878}', to: '\u{a87f}', }, + Range { from: '\u{a880}', to: '\u{a8c5}', }, + Range { from: '\u{a8c6}', to: '\u{a8cd}', }, + Range { from: '\u{a8ce}', to: '\u{a8d9}', }, + Range { from: '\u{a8da}', to: '\u{a8df}', }, + Range { from: '\u{a8e0}', to: '\u{a8fd}', }, + Range { from: '\u{a8fe}', to: '\u{a8ff}', }, + Range { from: '\u{a900}', to: '\u{a953}', }, + Range { from: '\u{a954}', to: '\u{a95e}', }, + Range { from: '\u{a95f}', to: '\u{a97c}', }, + Range { from: '\u{a97d}', to: '\u{a97f}', }, + Range { from: '\u{a980}', to: '\u{a9cd}', }, + Range { from: '\u{a9ce}', to: '\u{a9ce}', }, + Range { from: '\u{a9cf}', to: '\u{a9d9}', }, + Range { from: '\u{a9da}', to: '\u{a9dd}', }, + Range { from: '\u{a9de}', to: '\u{a9fe}', }, + Range { from: '\u{a9ff}', to: '\u{a9ff}', }, + Range { from: '\u{aa00}', to: '\u{aa36}', }, + Range { from: '\u{aa37}', to: '\u{aa3f}', }, + Range { from: '\u{aa40}', to: '\u{aa4d}', }, + Range { from: '\u{aa4e}', to: '\u{aa4f}', }, + Range { from: '\u{aa50}', to: '\u{aa59}', }, + Range { from: '\u{aa5a}', to: '\u{aa5b}', }, + Range { from: '\u{aa5c}', to: '\u{aac2}', }, + Range { from: '\u{aac3}', to: '\u{aada}', }, + Range { from: '\u{aadb}', to: '\u{aaf6}', }, + Range { from: '\u{aaf7}', to: '\u{ab00}', }, + Range { from: '\u{ab01}', to: '\u{ab06}', }, + Range { from: '\u{ab07}', to: '\u{ab08}', }, + Range { from: '\u{ab09}', to: '\u{ab0e}', }, + Range { from: '\u{ab0f}', to: '\u{ab10}', }, + Range { from: '\u{ab11}', to: '\u{ab16}', }, + Range { from: '\u{ab17}', to: '\u{ab1f}', }, + Range { from: '\u{ab20}', to: '\u{ab26}', }, + Range { from: '\u{ab27}', to: '\u{ab27}', }, + Range { from: '\u{ab28}', to: '\u{ab2e}', }, + Range { from: '\u{ab2f}', to: '\u{ab2f}', }, + Range { from: '\u{ab30}', to: '\u{ab5b}', }, + Range { from: '\u{ab5c}', to: '\u{ab5f}', }, + Range { from: '\u{ab60}', to: '\u{ab65}', }, + Range { from: '\u{ab66}', to: '\u{ab6f}', }, + Range { from: '\u{ab70}', to: '\u{abbf}', }, + Range { from: '\u{abc0}', to: '\u{abed}', }, + Range { from: '\u{abee}', to: '\u{abef}', }, + Range { from: '\u{abf0}', to: '\u{abf9}', }, + Range { from: '\u{abfa}', to: '\u{abff}', }, + Range { from: '\u{ac00}', to: '\u{d7a3}', }, + Range { from: '\u{d7a4}', to: '\u{d7af}', }, + Range { from: '\u{d7b0}', to: '\u{d7c6}', }, + Range { from: '\u{d7c7}', to: '\u{d7ca}', }, + Range { from: '\u{d7cb}', to: '\u{d7fb}', }, + Range { from: '\u{d7fc}', to: '\u{f8ff}', }, + Range { from: '\u{f900}', to: '\u{f906}', }, + Range { from: '\u{f907}', to: '\u{f908}', }, + Range { from: '\u{f909}', to: '\u{fa0d}', }, + Range { from: '\u{fa0e}', to: '\u{fa0f}', }, + Range { from: '\u{fa10}', to: '\u{fa12}', }, + Range { from: '\u{fa13}', to: '\u{fa14}', }, + Range { from: '\u{fa15}', to: '\u{fa22}', }, + Range { from: '\u{fa23}', to: '\u{fa24}', }, + Range { from: '\u{fa25}', to: '\u{fa26}', }, + Range { from: '\u{fa27}', to: '\u{fa29}', }, + Range { from: '\u{fa2a}', to: '\u{fa5c}', }, + Range { from: '\u{fa5d}', to: '\u{fa5e}', }, + Range { from: '\u{fa5f}', to: '\u{fa6d}', }, + Range { from: '\u{fa6e}', to: '\u{fa6f}', }, + Range { from: '\u{fa70}', to: '\u{fad9}', }, + Range { from: '\u{fada}', to: '\u{faff}', }, + Range { from: '\u{fb00}', to: '\u{fb04}', }, + Range { from: '\u{fb05}', to: '\u{fb06}', }, + Range { from: '\u{fb07}', to: '\u{fb12}', }, + Range { from: '\u{fb13}', to: '\u{fb17}', }, + Range { from: '\u{fb18}', to: '\u{fb1c}', }, + Range { from: '\u{fb1d}', to: '\u{fb4f}', }, + Range { from: '\u{fb50}', to: '\u{fb51}', }, + Range { from: '\u{fb52}', to: '\u{fb55}', }, + Range { from: '\u{fb56}', to: '\u{fb59}', }, + Range { from: '\u{fb5a}', to: '\u{fb5d}', }, + Range { from: '\u{fb5e}', to: '\u{fb61}', }, + Range { from: '\u{fb62}', to: '\u{fb65}', }, + Range { from: '\u{fb66}', to: '\u{fb69}', }, + Range { from: '\u{fb6a}', to: '\u{fb6d}', }, + Range { from: '\u{fb6e}', to: '\u{fb71}', }, + Range { from: '\u{fb72}', to: '\u{fb75}', }, + Range { from: '\u{fb76}', to: '\u{fb79}', }, + Range { from: '\u{fb7a}', to: '\u{fb7d}', }, + Range { from: '\u{fb7e}', to: '\u{fb81}', }, + Range { from: '\u{fb82}', to: '\u{fb83}', }, + Range { from: '\u{fb84}', to: '\u{fb85}', }, + Range { from: '\u{fb86}', to: '\u{fb87}', }, + Range { from: '\u{fb88}', to: '\u{fb89}', }, + Range { from: '\u{fb8a}', to: '\u{fb8b}', }, + Range { from: '\u{fb8c}', to: '\u{fb8d}', }, + Range { from: '\u{fb8e}', to: '\u{fb91}', }, + Range { from: '\u{fb92}', to: '\u{fb95}', }, + Range { from: '\u{fb96}', to: '\u{fb99}', }, + Range { from: '\u{fb9a}', to: '\u{fb9d}', }, + Range { from: '\u{fb9e}', to: '\u{fb9f}', }, + Range { from: '\u{fba0}', to: '\u{fba3}', }, + Range { from: '\u{fba4}', to: '\u{fba5}', }, + Range { from: '\u{fba6}', to: '\u{fba9}', }, + Range { from: '\u{fbaa}', to: '\u{fbad}', }, + Range { from: '\u{fbae}', to: '\u{fbaf}', }, + Range { from: '\u{fbb0}', to: '\u{fbb1}', }, + Range { from: '\u{fbb2}', to: '\u{fbc1}', }, + Range { from: '\u{fbc2}', to: '\u{fbd2}', }, + Range { from: '\u{fbd3}', to: '\u{fbd6}', }, + Range { from: '\u{fbd7}', to: '\u{fbd8}', }, + Range { from: '\u{fbd9}', to: '\u{fbda}', }, + Range { from: '\u{fbdb}', to: '\u{fbdc}', }, + Range { from: '\u{fbdd}', to: '\u{fbdd}', }, + Range { from: '\u{fbde}', to: '\u{fbdf}', }, + Range { from: '\u{fbe0}', to: '\u{fbe1}', }, + Range { from: '\u{fbe2}', to: '\u{fbe3}', }, + Range { from: '\u{fbe4}', to: '\u{fbe7}', }, + Range { from: '\u{fbe8}', to: '\u{fbe9}', }, + Range { from: '\u{fbea}', to: '\u{fbeb}', }, + Range { from: '\u{fbec}', to: '\u{fbed}', }, + Range { from: '\u{fbee}', to: '\u{fbef}', }, + Range { from: '\u{fbf0}', to: '\u{fbf1}', }, + Range { from: '\u{fbf2}', to: '\u{fbf3}', }, + Range { from: '\u{fbf4}', to: '\u{fbf5}', }, + Range { from: '\u{fbf6}', to: '\u{fbf8}', }, + Range { from: '\u{fbf9}', to: '\u{fbfb}', }, + Range { from: '\u{fbfc}', to: '\u{fbff}', }, + Range { from: '\u{fc00}', to: '\u{fd3b}', }, + Range { from: '\u{fd3c}', to: '\u{fd3d}', }, + Range { from: '\u{fd3e}', to: '\u{fd3f}', }, + Range { from: '\u{fd40}', to: '\u{fd4f}', }, + Range { from: '\u{fd50}', to: '\u{fd50}', }, + Range { from: '\u{fd51}', to: '\u{fd52}', }, + Range { from: '\u{fd53}', to: '\u{fd57}', }, + Range { from: '\u{fd58}', to: '\u{fd59}', }, + Range { from: '\u{fd5a}', to: '\u{fd5e}', }, + Range { from: '\u{fd5f}', to: '\u{fd60}', }, + Range { from: '\u{fd61}', to: '\u{fd61}', }, + Range { from: '\u{fd62}', to: '\u{fd63}', }, + Range { from: '\u{fd64}', to: '\u{fd65}', }, + Range { from: '\u{fd66}', to: '\u{fd66}', }, + Range { from: '\u{fd67}', to: '\u{fd68}', }, + Range { from: '\u{fd69}', to: '\u{fd69}', }, + Range { from: '\u{fd6a}', to: '\u{fd6b}', }, + Range { from: '\u{fd6c}', to: '\u{fd6d}', }, + Range { from: '\u{fd6e}', to: '\u{fd6e}', }, + Range { from: '\u{fd6f}', to: '\u{fd70}', }, + Range { from: '\u{fd71}', to: '\u{fd72}', }, + Range { from: '\u{fd73}', to: '\u{fd75}', }, + Range { from: '\u{fd76}', to: '\u{fd77}', }, + Range { from: '\u{fd78}', to: '\u{fd7b}', }, + Range { from: '\u{fd7c}', to: '\u{fd7d}', }, + Range { from: '\u{fd7e}', to: '\u{fd82}', }, + Range { from: '\u{fd83}', to: '\u{fd84}', }, + Range { from: '\u{fd85}', to: '\u{fd86}', }, + Range { from: '\u{fd87}', to: '\u{fd88}', }, + Range { from: '\u{fd89}', to: '\u{fd8f}', }, + Range { from: '\u{fd90}', to: '\u{fd91}', }, + Range { from: '\u{fd92}', to: '\u{fd96}', }, + Range { from: '\u{fd97}', to: '\u{fd98}', }, + Range { from: '\u{fd99}', to: '\u{fd9b}', }, + Range { from: '\u{fd9c}', to: '\u{fd9d}', }, + Range { from: '\u{fd9e}', to: '\u{fdc7}', }, + Range { from: '\u{fdc8}', to: '\u{fdef}', }, + Range { from: '\u{fdf0}', to: '\u{fdfd}', }, + Range { from: '\u{fdfe}', to: '\u{fdff}', }, + Range { from: '\u{fe00}', to: '\u{fe0f}', }, + Range { from: '\u{fe10}', to: '\u{fe18}', }, + Range { from: '\u{fe19}', to: '\u{fe1f}', }, + Range { from: '\u{fe20}', to: '\u{fe2f}', }, + Range { from: '\u{fe30}', to: '\u{fe32}', }, + Range { from: '\u{fe33}', to: '\u{fe34}', }, + Range { from: '\u{fe35}', to: '\u{fe44}', }, + Range { from: '\u{fe45}', to: '\u{fe46}', }, + Range { from: '\u{fe47}', to: '\u{fe48}', }, + Range { from: '\u{fe49}', to: '\u{fe4c}', }, + Range { from: '\u{fe4d}', to: '\u{fe4f}', }, + Range { from: '\u{fe50}', to: '\u{fe51}', }, + Range { from: '\u{fe52}', to: '\u{fe53}', }, + Range { from: '\u{fe54}', to: '\u{fe6b}', }, + Range { from: '\u{fe6c}', to: '\u{fe6f}', }, + Range { from: '\u{fe70}', to: '\u{fe80}', }, + Range { from: '\u{fe81}', to: '\u{fe82}', }, + Range { from: '\u{fe83}', to: '\u{fe84}', }, + Range { from: '\u{fe85}', to: '\u{fe86}', }, + Range { from: '\u{fe87}', to: '\u{fe88}', }, + Range { from: '\u{fe89}', to: '\u{fe8c}', }, + Range { from: '\u{fe8d}', to: '\u{fe8e}', }, + Range { from: '\u{fe8f}', to: '\u{fe92}', }, + Range { from: '\u{fe93}', to: '\u{fe94}', }, + Range { from: '\u{fe95}', to: '\u{fe98}', }, + Range { from: '\u{fe99}', to: '\u{fe9c}', }, + Range { from: '\u{fe9d}', to: '\u{fea0}', }, + Range { from: '\u{fea1}', to: '\u{fea4}', }, + Range { from: '\u{fea5}', to: '\u{fea8}', }, + Range { from: '\u{fea9}', to: '\u{feaa}', }, + Range { from: '\u{feab}', to: '\u{feac}', }, + Range { from: '\u{fead}', to: '\u{feae}', }, + Range { from: '\u{feaf}', to: '\u{feb0}', }, + Range { from: '\u{feb1}', to: '\u{feb4}', }, + Range { from: '\u{feb5}', to: '\u{feb8}', }, + Range { from: '\u{feb9}', to: '\u{febc}', }, + Range { from: '\u{febd}', to: '\u{fec0}', }, + Range { from: '\u{fec1}', to: '\u{fec4}', }, + Range { from: '\u{fec5}', to: '\u{fec8}', }, + Range { from: '\u{fec9}', to: '\u{fecc}', }, + Range { from: '\u{fecd}', to: '\u{fed0}', }, + Range { from: '\u{fed1}', to: '\u{fed4}', }, + Range { from: '\u{fed5}', to: '\u{fed8}', }, + Range { from: '\u{fed9}', to: '\u{fedc}', }, + Range { from: '\u{fedd}', to: '\u{fee0}', }, + Range { from: '\u{fee1}', to: '\u{fee4}', }, + Range { from: '\u{fee5}', to: '\u{fee8}', }, + Range { from: '\u{fee9}', to: '\u{feec}', }, + Range { from: '\u{feed}', to: '\u{feee}', }, + Range { from: '\u{feef}', to: '\u{fef0}', }, + Range { from: '\u{fef1}', to: '\u{fef4}', }, + Range { from: '\u{fef5}', to: '\u{fef6}', }, + Range { from: '\u{fef7}', to: '\u{fef8}', }, + Range { from: '\u{fef9}', to: '\u{fefa}', }, + Range { from: '\u{fefb}', to: '\u{fefc}', }, + Range { from: '\u{fefd}', to: '\u{fefe}', }, + Range { from: '\u{feff}', to: '\u{ffbe}', }, + Range { from: '\u{ffbf}', to: '\u{ffc1}', }, + Range { from: '\u{ffc2}', to: '\u{ffc7}', }, + Range { from: '\u{ffc8}', to: '\u{ffc9}', }, + Range { from: '\u{ffca}', to: '\u{ffcf}', }, + Range { from: '\u{ffd0}', to: '\u{ffd1}', }, + Range { from: '\u{ffd2}', to: '\u{ffd7}', }, + Range { from: '\u{ffd8}', to: '\u{ffd9}', }, + Range { from: '\u{ffda}', to: '\u{ffdc}', }, + Range { from: '\u{ffdd}', to: '\u{ffdf}', }, + Range { from: '\u{ffe0}', to: '\u{ffee}', }, + Range { from: '\u{ffef}', to: '\u{ffff}', }, + Range { from: '\u{10000}', to: '\u{1000b}', }, + Range { from: '\u{1000c}', to: '\u{1000c}', }, + Range { from: '\u{1000d}', to: '\u{10026}', }, + Range { from: '\u{10027}', to: '\u{10027}', }, + Range { from: '\u{10028}', to: '\u{1003a}', }, + Range { from: '\u{1003b}', to: '\u{1003b}', }, + Range { from: '\u{1003c}', to: '\u{1003d}', }, + Range { from: '\u{1003e}', to: '\u{1003e}', }, + Range { from: '\u{1003f}', to: '\u{1004d}', }, + Range { from: '\u{1004e}', to: '\u{1004f}', }, + Range { from: '\u{10050}', to: '\u{1005d}', }, + Range { from: '\u{1005e}', to: '\u{1007f}', }, + Range { from: '\u{10080}', to: '\u{100fa}', }, + Range { from: '\u{100fb}', to: '\u{100ff}', }, + Range { from: '\u{10100}', to: '\u{10102}', }, + Range { from: '\u{10103}', to: '\u{10106}', }, + Range { from: '\u{10107}', to: '\u{10133}', }, + Range { from: '\u{10134}', to: '\u{10136}', }, + Range { from: '\u{10137}', to: '\u{1018e}', }, + Range { from: '\u{1018f}', to: '\u{1018f}', }, + Range { from: '\u{10190}', to: '\u{1019b}', }, + Range { from: '\u{1019c}', to: '\u{1019f}', }, + Range { from: '\u{101a0}', to: '\u{101a0}', }, + Range { from: '\u{101a1}', to: '\u{101cf}', }, + Range { from: '\u{101d0}', to: '\u{101fd}', }, + Range { from: '\u{101fe}', to: '\u{1027f}', }, + Range { from: '\u{10280}', to: '\u{1029c}', }, + Range { from: '\u{1029d}', to: '\u{1029f}', }, + Range { from: '\u{102a0}', to: '\u{102d0}', }, + Range { from: '\u{102d1}', to: '\u{102df}', }, + Range { from: '\u{102e0}', to: '\u{102fb}', }, + Range { from: '\u{102fc}', to: '\u{102ff}', }, + Range { from: '\u{10300}', to: '\u{10323}', }, + Range { from: '\u{10324}', to: '\u{1032c}', }, + Range { from: '\u{1032d}', to: '\u{1034a}', }, + Range { from: '\u{1034b}', to: '\u{1034f}', }, + Range { from: '\u{10350}', to: '\u{1037a}', }, + Range { from: '\u{1037b}', to: '\u{1037f}', }, + Range { from: '\u{10380}', to: '\u{1039d}', }, + Range { from: '\u{1039e}', to: '\u{1039e}', }, + Range { from: '\u{1039f}', to: '\u{103c3}', }, + Range { from: '\u{103c4}', to: '\u{103c7}', }, + Range { from: '\u{103c8}', to: '\u{103d5}', }, + Range { from: '\u{103d6}', to: '\u{103ff}', }, + Range { from: '\u{10400}', to: '\u{10427}', }, + Range { from: '\u{10428}', to: '\u{1049d}', }, + Range { from: '\u{1049e}', to: '\u{1049f}', }, + Range { from: '\u{104a0}', to: '\u{104a9}', }, + Range { from: '\u{104aa}', to: '\u{104af}', }, + Range { from: '\u{104b0}', to: '\u{104d3}', }, + Range { from: '\u{104d4}', to: '\u{104d7}', }, + Range { from: '\u{104d8}', to: '\u{104fb}', }, + Range { from: '\u{104fc}', to: '\u{104ff}', }, + Range { from: '\u{10500}', to: '\u{10527}', }, + Range { from: '\u{10528}', to: '\u{1052f}', }, + Range { from: '\u{10530}', to: '\u{10563}', }, + Range { from: '\u{10564}', to: '\u{1056e}', }, + Range { from: '\u{1056f}', to: '\u{1056f}', }, + Range { from: '\u{10570}', to: '\u{105ff}', }, + Range { from: '\u{10600}', to: '\u{10736}', }, + Range { from: '\u{10737}', to: '\u{1073f}', }, + Range { from: '\u{10740}', to: '\u{10755}', }, + Range { from: '\u{10756}', to: '\u{1075f}', }, + Range { from: '\u{10760}', to: '\u{10767}', }, + Range { from: '\u{10768}', to: '\u{107ff}', }, + Range { from: '\u{10800}', to: '\u{10805}', }, + Range { from: '\u{10806}', to: '\u{10807}', }, + Range { from: '\u{10808}', to: '\u{10809}', }, + Range { from: '\u{1080a}', to: '\u{10835}', }, + Range { from: '\u{10836}', to: '\u{10836}', }, + Range { from: '\u{10837}', to: '\u{10838}', }, + Range { from: '\u{10839}', to: '\u{1083b}', }, + Range { from: '\u{1083c}', to: '\u{1083c}', }, + Range { from: '\u{1083d}', to: '\u{1083e}', }, + Range { from: '\u{1083f}', to: '\u{10855}', }, + Range { from: '\u{10856}', to: '\u{10856}', }, + Range { from: '\u{10857}', to: '\u{1089e}', }, + Range { from: '\u{1089f}', to: '\u{108a6}', }, + Range { from: '\u{108a7}', to: '\u{108af}', }, + Range { from: '\u{108b0}', to: '\u{108df}', }, + Range { from: '\u{108e0}', to: '\u{108f2}', }, + Range { from: '\u{108f3}', to: '\u{108f3}', }, + Range { from: '\u{108f4}', to: '\u{108f5}', }, + Range { from: '\u{108f6}', to: '\u{108fa}', }, + Range { from: '\u{108fb}', to: '\u{1091b}', }, + Range { from: '\u{1091c}', to: '\u{1091e}', }, + Range { from: '\u{1091f}', to: '\u{10939}', }, + Range { from: '\u{1093a}', to: '\u{1093e}', }, + Range { from: '\u{1093f}', to: '\u{1093f}', }, + Range { from: '\u{10940}', to: '\u{1097f}', }, + Range { from: '\u{10980}', to: '\u{109b7}', }, + Range { from: '\u{109b8}', to: '\u{109bb}', }, + Range { from: '\u{109bc}', to: '\u{109cf}', }, + Range { from: '\u{109d0}', to: '\u{109d1}', }, + Range { from: '\u{109d2}', to: '\u{10a03}', }, + Range { from: '\u{10a04}', to: '\u{10a04}', }, + Range { from: '\u{10a05}', to: '\u{10a06}', }, + Range { from: '\u{10a07}', to: '\u{10a0b}', }, + Range { from: '\u{10a0c}', to: '\u{10a13}', }, + Range { from: '\u{10a14}', to: '\u{10a14}', }, + Range { from: '\u{10a15}', to: '\u{10a17}', }, + Range { from: '\u{10a18}', to: '\u{10a18}', }, + Range { from: '\u{10a19}', to: '\u{10a33}', }, + Range { from: '\u{10a34}', to: '\u{10a37}', }, + Range { from: '\u{10a38}', to: '\u{10a3a}', }, + Range { from: '\u{10a3b}', to: '\u{10a3e}', }, + Range { from: '\u{10a3f}', to: '\u{10a47}', }, + Range { from: '\u{10a48}', to: '\u{10a4f}', }, + Range { from: '\u{10a50}', to: '\u{10a58}', }, + Range { from: '\u{10a59}', to: '\u{10a5f}', }, + Range { from: '\u{10a60}', to: '\u{10a9f}', }, + Range { from: '\u{10aa0}', to: '\u{10abf}', }, + Range { from: '\u{10ac0}', to: '\u{10ae6}', }, + Range { from: '\u{10ae7}', to: '\u{10aea}', }, + Range { from: '\u{10aeb}', to: '\u{10af6}', }, + Range { from: '\u{10af7}', to: '\u{10aff}', }, + Range { from: '\u{10b00}', to: '\u{10b35}', }, + Range { from: '\u{10b36}', to: '\u{10b38}', }, + Range { from: '\u{10b39}', to: '\u{10b55}', }, + Range { from: '\u{10b56}', to: '\u{10b57}', }, + Range { from: '\u{10b58}', to: '\u{10b72}', }, + Range { from: '\u{10b73}', to: '\u{10b77}', }, + Range { from: '\u{10b78}', to: '\u{10b91}', }, + Range { from: '\u{10b92}', to: '\u{10b98}', }, + Range { from: '\u{10b99}', to: '\u{10b9c}', }, + Range { from: '\u{10b9d}', to: '\u{10ba8}', }, + Range { from: '\u{10ba9}', to: '\u{10baf}', }, + Range { from: '\u{10bb0}', to: '\u{10bff}', }, + Range { from: '\u{10c00}', to: '\u{10c48}', }, + Range { from: '\u{10c49}', to: '\u{10c7f}', }, + Range { from: '\u{10c80}', to: '\u{10cb2}', }, + Range { from: '\u{10cb3}', to: '\u{10cbf}', }, + Range { from: '\u{10cc0}', to: '\u{10cf2}', }, + Range { from: '\u{10cf3}', to: '\u{10cf9}', }, + Range { from: '\u{10cfa}', to: '\u{10cff}', }, + Range { from: '\u{10d00}', to: '\u{10e5f}', }, + Range { from: '\u{10e60}', to: '\u{10e7e}', }, + Range { from: '\u{10e7f}', to: '\u{10fff}', }, + Range { from: '\u{11000}', to: '\u{1104d}', }, + Range { from: '\u{1104e}', to: '\u{11051}', }, + Range { from: '\u{11052}', to: '\u{1106f}', }, + Range { from: '\u{11070}', to: '\u{1107e}', }, + Range { from: '\u{1107f}', to: '\u{110bc}', }, + Range { from: '\u{110bd}', to: '\u{110bd}', }, + Range { from: '\u{110be}', to: '\u{110c1}', }, + Range { from: '\u{110c2}', to: '\u{110cf}', }, + Range { from: '\u{110d0}', to: '\u{110e8}', }, + Range { from: '\u{110e9}', to: '\u{110ef}', }, + Range { from: '\u{110f0}', to: '\u{110f9}', }, + Range { from: '\u{110fa}', to: '\u{110ff}', }, + Range { from: '\u{11100}', to: '\u{11134}', }, + Range { from: '\u{11135}', to: '\u{11135}', }, + Range { from: '\u{11136}', to: '\u{11143}', }, + Range { from: '\u{11144}', to: '\u{1114f}', }, + Range { from: '\u{11150}', to: '\u{11176}', }, + Range { from: '\u{11177}', to: '\u{1117f}', }, + Range { from: '\u{11180}', to: '\u{111cd}', }, + Range { from: '\u{111ce}', to: '\u{111cf}', }, + Range { from: '\u{111d0}', to: '\u{111df}', }, + Range { from: '\u{111e0}', to: '\u{111e0}', }, + Range { from: '\u{111e1}', to: '\u{111f4}', }, + Range { from: '\u{111f5}', to: '\u{111ff}', }, + Range { from: '\u{11200}', to: '\u{11211}', }, + Range { from: '\u{11212}', to: '\u{11212}', }, + Range { from: '\u{11213}', to: '\u{1123e}', }, + Range { from: '\u{1123f}', to: '\u{1127f}', }, + Range { from: '\u{11280}', to: '\u{11286}', }, + Range { from: '\u{11287}', to: '\u{11289}', }, + Range { from: '\u{1128a}', to: '\u{1128d}', }, + Range { from: '\u{1128e}', to: '\u{1128e}', }, + Range { from: '\u{1128f}', to: '\u{1129d}', }, + Range { from: '\u{1129e}', to: '\u{1129e}', }, + Range { from: '\u{1129f}', to: '\u{112a9}', }, + Range { from: '\u{112aa}', to: '\u{112af}', }, + Range { from: '\u{112b0}', to: '\u{112ea}', }, + Range { from: '\u{112eb}', to: '\u{112ef}', }, + Range { from: '\u{112f0}', to: '\u{112f9}', }, + Range { from: '\u{112fa}', to: '\u{112ff}', }, + Range { from: '\u{11300}', to: '\u{11303}', }, + Range { from: '\u{11304}', to: '\u{11304}', }, + Range { from: '\u{11305}', to: '\u{1130c}', }, + Range { from: '\u{1130d}', to: '\u{1130e}', }, + Range { from: '\u{1130f}', to: '\u{11310}', }, + Range { from: '\u{11311}', to: '\u{11312}', }, + Range { from: '\u{11313}', to: '\u{11328}', }, + Range { from: '\u{11329}', to: '\u{11329}', }, + Range { from: '\u{1132a}', to: '\u{11330}', }, + Range { from: '\u{11331}', to: '\u{11331}', }, + Range { from: '\u{11332}', to: '\u{11333}', }, + Range { from: '\u{11334}', to: '\u{11334}', }, + Range { from: '\u{11335}', to: '\u{11339}', }, + Range { from: '\u{1133a}', to: '\u{1133b}', }, + Range { from: '\u{1133c}', to: '\u{11344}', }, + Range { from: '\u{11345}', to: '\u{11346}', }, + Range { from: '\u{11347}', to: '\u{11348}', }, + Range { from: '\u{11349}', to: '\u{1134a}', }, + Range { from: '\u{1134b}', to: '\u{1134d}', }, + Range { from: '\u{1134e}', to: '\u{1134f}', }, + Range { from: '\u{11350}', to: '\u{11350}', }, + Range { from: '\u{11351}', to: '\u{11356}', }, + Range { from: '\u{11357}', to: '\u{11357}', }, + Range { from: '\u{11358}', to: '\u{1135c}', }, + Range { from: '\u{1135d}', to: '\u{11363}', }, + Range { from: '\u{11364}', to: '\u{11365}', }, + Range { from: '\u{11366}', to: '\u{1136c}', }, + Range { from: '\u{1136d}', to: '\u{1136f}', }, + Range { from: '\u{11370}', to: '\u{11374}', }, + Range { from: '\u{11375}', to: '\u{113ff}', }, + Range { from: '\u{11400}', to: '\u{11459}', }, + Range { from: '\u{1145a}', to: '\u{1145d}', }, + Range { from: '\u{1145e}', to: '\u{1147f}', }, + Range { from: '\u{11480}', to: '\u{114c7}', }, + Range { from: '\u{114c8}', to: '\u{114cf}', }, + Range { from: '\u{114d0}', to: '\u{114d9}', }, + Range { from: '\u{114da}', to: '\u{1157f}', }, + Range { from: '\u{11580}', to: '\u{115b5}', }, + Range { from: '\u{115b6}', to: '\u{115b7}', }, + Range { from: '\u{115b8}', to: '\u{115dd}', }, + Range { from: '\u{115de}', to: '\u{115ff}', }, + Range { from: '\u{11600}', to: '\u{11644}', }, + Range { from: '\u{11645}', to: '\u{1164f}', }, + Range { from: '\u{11650}', to: '\u{11659}', }, + Range { from: '\u{1165a}', to: '\u{1165f}', }, + Range { from: '\u{11660}', to: '\u{1166c}', }, + Range { from: '\u{1166d}', to: '\u{1167f}', }, + Range { from: '\u{11680}', to: '\u{116b7}', }, + Range { from: '\u{116b8}', to: '\u{116bf}', }, + Range { from: '\u{116c0}', to: '\u{116c9}', }, + Range { from: '\u{116ca}', to: '\u{116ff}', }, + Range { from: '\u{11700}', to: '\u{11719}', }, + Range { from: '\u{1171a}', to: '\u{1171c}', }, + Range { from: '\u{1171d}', to: '\u{1172b}', }, + Range { from: '\u{1172c}', to: '\u{1172f}', }, + Range { from: '\u{11730}', to: '\u{1173f}', }, + Range { from: '\u{11740}', to: '\u{1189f}', }, + Range { from: '\u{118a0}', to: '\u{118bf}', }, + Range { from: '\u{118c0}', to: '\u{118f2}', }, + Range { from: '\u{118f3}', to: '\u{118fe}', }, + Range { from: '\u{118ff}', to: '\u{118ff}', }, + Range { from: '\u{11900}', to: '\u{119ff}', }, + Range { from: '\u{11a00}', to: '\u{11a47}', }, + Range { from: '\u{11a48}', to: '\u{11a4f}', }, + Range { from: '\u{11a50}', to: '\u{11a83}', }, + Range { from: '\u{11a84}', to: '\u{11a85}', }, + Range { from: '\u{11a86}', to: '\u{11a9c}', }, + Range { from: '\u{11a9d}', to: '\u{11a9d}', }, + Range { from: '\u{11a9e}', to: '\u{11aa2}', }, + Range { from: '\u{11aa3}', to: '\u{11abf}', }, + Range { from: '\u{11ac0}', to: '\u{11af8}', }, + Range { from: '\u{11af9}', to: '\u{11bff}', }, + Range { from: '\u{11c00}', to: '\u{11c08}', }, + Range { from: '\u{11c09}', to: '\u{11c09}', }, + Range { from: '\u{11c0a}', to: '\u{11c36}', }, + Range { from: '\u{11c37}', to: '\u{11c37}', }, + Range { from: '\u{11c38}', to: '\u{11c45}', }, + Range { from: '\u{11c46}', to: '\u{11c4f}', }, + Range { from: '\u{11c50}', to: '\u{11c6c}', }, + Range { from: '\u{11c6d}', to: '\u{11c6f}', }, + Range { from: '\u{11c70}', to: '\u{11c8f}', }, + Range { from: '\u{11c90}', to: '\u{11c91}', }, + Range { from: '\u{11c92}', to: '\u{11ca7}', }, + Range { from: '\u{11ca8}', to: '\u{11ca8}', }, + Range { from: '\u{11ca9}', to: '\u{11cb6}', }, + Range { from: '\u{11cb7}', to: '\u{11cff}', }, + Range { from: '\u{11d00}', to: '\u{11d06}', }, + Range { from: '\u{11d07}', to: '\u{11d07}', }, + Range { from: '\u{11d08}', to: '\u{11d09}', }, + Range { from: '\u{11d0a}', to: '\u{11d0a}', }, + Range { from: '\u{11d0b}', to: '\u{11d36}', }, + Range { from: '\u{11d37}', to: '\u{11d39}', }, + Range { from: '\u{11d3a}', to: '\u{11d3b}', }, + Range { from: '\u{11d3c}', to: '\u{11d3d}', }, + Range { from: '\u{11d3e}', to: '\u{11d3e}', }, + Range { from: '\u{11d3f}', to: '\u{11d47}', }, + Range { from: '\u{11d48}', to: '\u{11d4f}', }, + Range { from: '\u{11d50}', to: '\u{11d59}', }, + Range { from: '\u{11d5a}', to: '\u{11fff}', }, + Range { from: '\u{12000}', to: '\u{12399}', }, + Range { from: '\u{1239a}', to: '\u{123ff}', }, + Range { from: '\u{12400}', to: '\u{1246e}', }, + Range { from: '\u{1246f}', to: '\u{1246f}', }, + Range { from: '\u{12470}', to: '\u{12474}', }, + Range { from: '\u{12475}', to: '\u{1247f}', }, + Range { from: '\u{12480}', to: '\u{12543}', }, + Range { from: '\u{12544}', to: '\u{12fff}', }, + Range { from: '\u{13000}', to: '\u{1342e}', }, + Range { from: '\u{1342f}', to: '\u{143ff}', }, + Range { from: '\u{14400}', to: '\u{14646}', }, + Range { from: '\u{14647}', to: '\u{167ff}', }, + Range { from: '\u{16800}', to: '\u{16a38}', }, + Range { from: '\u{16a39}', to: '\u{16a3f}', }, + Range { from: '\u{16a40}', to: '\u{16a5e}', }, + Range { from: '\u{16a5f}', to: '\u{16a5f}', }, + Range { from: '\u{16a60}', to: '\u{16a69}', }, + Range { from: '\u{16a6a}', to: '\u{16a6d}', }, + Range { from: '\u{16a6e}', to: '\u{16a6f}', }, + Range { from: '\u{16a70}', to: '\u{16acf}', }, + Range { from: '\u{16ad0}', to: '\u{16aed}', }, + Range { from: '\u{16aee}', to: '\u{16aef}', }, + Range { from: '\u{16af0}', to: '\u{16af5}', }, + Range { from: '\u{16af6}', to: '\u{16aff}', }, + Range { from: '\u{16b00}', to: '\u{16b45}', }, + Range { from: '\u{16b46}', to: '\u{16b4f}', }, + Range { from: '\u{16b50}', to: '\u{16b59}', }, + Range { from: '\u{16b5a}', to: '\u{16b5a}', }, + Range { from: '\u{16b5b}', to: '\u{16b61}', }, + Range { from: '\u{16b62}', to: '\u{16b62}', }, + Range { from: '\u{16b63}', to: '\u{16b77}', }, + Range { from: '\u{16b78}', to: '\u{16b7c}', }, + Range { from: '\u{16b7d}', to: '\u{16b8f}', }, + Range { from: '\u{16b90}', to: '\u{16eff}', }, + Range { from: '\u{16f00}', to: '\u{16f44}', }, + Range { from: '\u{16f45}', to: '\u{16f4f}', }, + Range { from: '\u{16f50}', to: '\u{16f7e}', }, + Range { from: '\u{16f7f}', to: '\u{16f8e}', }, + Range { from: '\u{16f8f}', to: '\u{16f9f}', }, + Range { from: '\u{16fa0}', to: '\u{16fdf}', }, + Range { from: '\u{16fe0}', to: '\u{16fe1}', }, + Range { from: '\u{16fe2}', to: '\u{16fff}', }, + Range { from: '\u{17000}', to: '\u{187ec}', }, + Range { from: '\u{187ed}', to: '\u{187ff}', }, + Range { from: '\u{18800}', to: '\u{18af2}', }, + Range { from: '\u{18af3}', to: '\u{1afff}', }, + Range { from: '\u{1b000}', to: '\u{1b11e}', }, + Range { from: '\u{1b11f}', to: '\u{1b16f}', }, + Range { from: '\u{1b170}', to: '\u{1b2fb}', }, + Range { from: '\u{1b2fc}', to: '\u{1bbff}', }, + Range { from: '\u{1bc00}', to: '\u{1bc6a}', }, + Range { from: '\u{1bc6b}', to: '\u{1bc6f}', }, + Range { from: '\u{1bc70}', to: '\u{1bc7c}', }, + Range { from: '\u{1bc7d}', to: '\u{1bc7f}', }, + Range { from: '\u{1bc80}', to: '\u{1bc88}', }, + Range { from: '\u{1bc89}', to: '\u{1bc8f}', }, + Range { from: '\u{1bc90}', to: '\u{1bc99}', }, + Range { from: '\u{1bc9a}', to: '\u{1bc9b}', }, + Range { from: '\u{1bc9c}', to: '\u{1bc9f}', }, + Range { from: '\u{1bca0}', to: '\u{1bca3}', }, + Range { from: '\u{1bca4}', to: '\u{1cfff}', }, + Range { from: '\u{1d000}', to: '\u{1d0f5}', }, + Range { from: '\u{1d0f6}', to: '\u{1d0ff}', }, + Range { from: '\u{1d100}', to: '\u{1d126}', }, + Range { from: '\u{1d127}', to: '\u{1d128}', }, + Range { from: '\u{1d129}', to: '\u{1d15d}', }, + Range { from: '\u{1d15e}', to: '\u{1d164}', }, + Range { from: '\u{1d165}', to: '\u{1d172}', }, + Range { from: '\u{1d173}', to: '\u{1d17a}', }, + Range { from: '\u{1d17b}', to: '\u{1d1ba}', }, + Range { from: '\u{1d1bb}', to: '\u{1d1c0}', }, + Range { from: '\u{1d1c1}', to: '\u{1d1e8}', }, + Range { from: '\u{1d1e9}', to: '\u{1d1ff}', }, + Range { from: '\u{1d200}', to: '\u{1d245}', }, + Range { from: '\u{1d246}', to: '\u{1d2ff}', }, + Range { from: '\u{1d300}', to: '\u{1d356}', }, + Range { from: '\u{1d357}', to: '\u{1d35f}', }, + Range { from: '\u{1d360}', to: '\u{1d371}', }, + Range { from: '\u{1d372}', to: '\u{1d3ff}', }, + Range { from: '\u{1d400}', to: '\u{1d49f}', }, + Range { from: '\u{1d4a0}', to: '\u{1d4a1}', }, + Range { from: '\u{1d4a2}', to: '\u{1d4a2}', }, + Range { from: '\u{1d4a3}', to: '\u{1d4a4}', }, + Range { from: '\u{1d4a5}', to: '\u{1d4a6}', }, + Range { from: '\u{1d4a7}', to: '\u{1d4a8}', }, + Range { from: '\u{1d4a9}', to: '\u{1d50a}', }, + Range { from: '\u{1d50b}', to: '\u{1d50c}', }, + Range { from: '\u{1d50d}', to: '\u{1d546}', }, + Range { from: '\u{1d547}', to: '\u{1d549}', }, + Range { from: '\u{1d54a}', to: '\u{1d6a5}', }, + Range { from: '\u{1d6a6}', to: '\u{1d6a7}', }, + Range { from: '\u{1d6a8}', to: '\u{1d6d2}', }, + Range { from: '\u{1d6d3}', to: '\u{1d6d4}', }, + Range { from: '\u{1d6d5}', to: '\u{1d70c}', }, + Range { from: '\u{1d70d}', to: '\u{1d70e}', }, + Range { from: '\u{1d70f}', to: '\u{1d746}', }, + Range { from: '\u{1d747}', to: '\u{1d748}', }, + Range { from: '\u{1d749}', to: '\u{1d780}', }, + Range { from: '\u{1d781}', to: '\u{1d782}', }, + Range { from: '\u{1d783}', to: '\u{1d7ba}', }, + Range { from: '\u{1d7bb}', to: '\u{1d7bc}', }, + Range { from: '\u{1d7bd}', to: '\u{1d7c9}', }, + Range { from: '\u{1d7ca}', to: '\u{1d7cb}', }, + Range { from: '\u{1d7cc}', to: '\u{1d7cd}', }, + Range { from: '\u{1d7ce}', to: '\u{1d7ff}', }, + Range { from: '\u{1d800}', to: '\u{1da8b}', }, + Range { from: '\u{1da8c}', to: '\u{1da9a}', }, + Range { from: '\u{1da9b}', to: '\u{1da9f}', }, + Range { from: '\u{1daa0}', to: '\u{1daa0}', }, + Range { from: '\u{1daa1}', to: '\u{1daaf}', }, + Range { from: '\u{1dab0}', to: '\u{1dfff}', }, + Range { from: '\u{1e000}', to: '\u{1e006}', }, + Range { from: '\u{1e007}', to: '\u{1e007}', }, + Range { from: '\u{1e008}', to: '\u{1e018}', }, + Range { from: '\u{1e019}', to: '\u{1e01a}', }, + Range { from: '\u{1e01b}', to: '\u{1e021}', }, + Range { from: '\u{1e022}', to: '\u{1e022}', }, + Range { from: '\u{1e023}', to: '\u{1e024}', }, + Range { from: '\u{1e025}', to: '\u{1e025}', }, + Range { from: '\u{1e026}', to: '\u{1e02a}', }, + Range { from: '\u{1e02b}', to: '\u{1e7ff}', }, + Range { from: '\u{1e800}', to: '\u{1e8c4}', }, + Range { from: '\u{1e8c5}', to: '\u{1e8c6}', }, + Range { from: '\u{1e8c7}', to: '\u{1e8d6}', }, + Range { from: '\u{1e8d7}', to: '\u{1e8ff}', }, + Range { from: '\u{1e900}', to: '\u{1e921}', }, + Range { from: '\u{1e922}', to: '\u{1e94a}', }, + Range { from: '\u{1e94b}', to: '\u{1e94f}', }, + Range { from: '\u{1e950}', to: '\u{1e959}', }, + Range { from: '\u{1e95a}', to: '\u{1e95d}', }, + Range { from: '\u{1e95e}', to: '\u{1e95f}', }, + Range { from: '\u{1e960}', to: '\u{1edff}', }, + Range { from: '\u{1ee00}', to: '\u{1ee24}', }, + Range { from: '\u{1ee25}', to: '\u{1ee26}', }, + Range { from: '\u{1ee27}', to: '\u{1ee3b}', }, + Range { from: '\u{1ee3c}', to: '\u{1ee41}', }, + Range { from: '\u{1ee42}', to: '\u{1ee42}', }, + Range { from: '\u{1ee43}', to: '\u{1ee46}', }, + Range { from: '\u{1ee47}', to: '\u{1ee54}', }, + Range { from: '\u{1ee55}', to: '\u{1ee56}', }, + Range { from: '\u{1ee57}', to: '\u{1ee64}', }, + Range { from: '\u{1ee65}', to: '\u{1ee66}', }, + Range { from: '\u{1ee67}', to: '\u{1ee9b}', }, + Range { from: '\u{1ee9c}', to: '\u{1eea0}', }, + Range { from: '\u{1eea1}', to: '\u{1eebb}', }, + Range { from: '\u{1eebc}', to: '\u{1eeef}', }, + Range { from: '\u{1eef0}', to: '\u{1eef1}', }, + Range { from: '\u{1eef2}', to: '\u{1efff}', }, + Range { from: '\u{1f000}', to: '\u{1f02b}', }, + Range { from: '\u{1f02c}', to: '\u{1f02f}', }, + Range { from: '\u{1f030}', to: '\u{1f093}', }, + Range { from: '\u{1f094}', to: '\u{1f09f}', }, + Range { from: '\u{1f0a0}', to: '\u{1f0ae}', }, + Range { from: '\u{1f0af}', to: '\u{1f0b0}', }, + Range { from: '\u{1f0b1}', to: '\u{1f0bf}', }, + Range { from: '\u{1f0c0}', to: '\u{1f0c0}', }, + Range { from: '\u{1f0c1}', to: '\u{1f0cf}', }, + Range { from: '\u{1f0d0}', to: '\u{1f0d0}', }, + Range { from: '\u{1f0d1}', to: '\u{1f0f5}', }, + Range { from: '\u{1f0f6}', to: '\u{1f100}', }, + Range { from: '\u{1f101}', to: '\u{1f10a}', }, + Range { from: '\u{1f10b}', to: '\u{1f10c}', }, + Range { from: '\u{1f10d}', to: '\u{1f10f}', }, + Range { from: '\u{1f110}', to: '\u{1f14f}', }, + Range { from: '\u{1f150}', to: '\u{1f169}', }, + Range { from: '\u{1f16a}', to: '\u{1f16b}', }, + Range { from: '\u{1f16c}', to: '\u{1f16f}', }, + Range { from: '\u{1f170}', to: '\u{1f18f}', }, + Range { from: '\u{1f190}', to: '\u{1f190}', }, + Range { from: '\u{1f191}', to: '\u{1f1ac}', }, + Range { from: '\u{1f1ad}', to: '\u{1f1e5}', }, + Range { from: '\u{1f1e6}', to: '\u{1f1ff}', }, + Range { from: '\u{1f200}', to: '\u{1f202}', }, + Range { from: '\u{1f203}', to: '\u{1f20f}', }, + Range { from: '\u{1f210}', to: '\u{1f23b}', }, + Range { from: '\u{1f23c}', to: '\u{1f23f}', }, + Range { from: '\u{1f240}', to: '\u{1f248}', }, + Range { from: '\u{1f249}', to: '\u{1f24f}', }, + Range { from: '\u{1f250}', to: '\u{1f251}', }, + Range { from: '\u{1f252}', to: '\u{1f25f}', }, + Range { from: '\u{1f260}', to: '\u{1f265}', }, + Range { from: '\u{1f266}', to: '\u{1f2ff}', }, + Range { from: '\u{1f300}', to: '\u{1f6d4}', }, + Range { from: '\u{1f6d5}', to: '\u{1f6df}', }, + Range { from: '\u{1f6e0}', to: '\u{1f6ec}', }, + Range { from: '\u{1f6ed}', to: '\u{1f6ef}', }, + Range { from: '\u{1f6f0}', to: '\u{1f6f8}', }, + Range { from: '\u{1f6f9}', to: '\u{1f6ff}', }, + Range { from: '\u{1f700}', to: '\u{1f773}', }, + Range { from: '\u{1f774}', to: '\u{1f77f}', }, + Range { from: '\u{1f780}', to: '\u{1f7d4}', }, + Range { from: '\u{1f7d5}', to: '\u{1f7ff}', }, + Range { from: '\u{1f800}', to: '\u{1f80b}', }, + Range { from: '\u{1f80c}', to: '\u{1f80f}', }, + Range { from: '\u{1f810}', to: '\u{1f847}', }, + Range { from: '\u{1f848}', to: '\u{1f84f}', }, + Range { from: '\u{1f850}', to: '\u{1f859}', }, + Range { from: '\u{1f85a}', to: '\u{1f85f}', }, + Range { from: '\u{1f860}', to: '\u{1f887}', }, + Range { from: '\u{1f888}', to: '\u{1f88f}', }, + Range { from: '\u{1f890}', to: '\u{1f8ad}', }, + Range { from: '\u{1f8ae}', to: '\u{1f8ff}', }, + Range { from: '\u{1f900}', to: '\u{1f90b}', }, + Range { from: '\u{1f90c}', to: '\u{1f90f}', }, + Range { from: '\u{1f910}', to: '\u{1f93e}', }, + Range { from: '\u{1f93f}', to: '\u{1f93f}', }, + Range { from: '\u{1f940}', to: '\u{1f94c}', }, + Range { from: '\u{1f94d}', to: '\u{1f94f}', }, + Range { from: '\u{1f950}', to: '\u{1f96b}', }, + Range { from: '\u{1f96c}', to: '\u{1f97f}', }, + Range { from: '\u{1f980}', to: '\u{1f997}', }, + Range { from: '\u{1f998}', to: '\u{1f9bf}', }, + Range { from: '\u{1f9c0}', to: '\u{1f9c0}', }, + Range { from: '\u{1f9c1}', to: '\u{1f9cf}', }, + Range { from: '\u{1f9d0}', to: '\u{1f9e6}', }, + Range { from: '\u{1f9e7}', to: '\u{1ffff}', }, + Range { from: '\u{20000}', to: '\u{2a6d6}', }, + Range { from: '\u{2a6d7}', to: '\u{2a6ff}', }, + Range { from: '\u{2a700}', to: '\u{2b734}', }, + Range { from: '\u{2b735}', to: '\u{2b73f}', }, + Range { from: '\u{2b740}', to: '\u{2b81d}', }, + Range { from: '\u{2b81e}', to: '\u{2b81f}', }, + Range { from: '\u{2b820}', to: '\u{2cea1}', }, + Range { from: '\u{2cea2}', to: '\u{2ceaf}', }, + Range { from: '\u{2ceb0}', to: '\u{2ebe0}', }, + Range { from: '\u{2ebe1}', to: '\u{2f7ff}', }, + Range { from: '\u{2f800}', to: '\u{2f830}', }, + Range { from: '\u{2f831}', to: '\u{2f833}', }, + Range { from: '\u{2f834}', to: '\u{2f844}', }, + Range { from: '\u{2f845}', to: '\u{2f846}', }, + Range { from: '\u{2f847}', to: '\u{2f869}', }, + Range { from: '\u{2f86a}', to: '\u{2f86b}', }, + Range { from: '\u{2f86c}', to: '\u{2f890}', }, + Range { from: '\u{2f891}', to: '\u{2f892}', }, + Range { from: '\u{2f893}', to: '\u{2f893}', }, + Range { from: '\u{2f894}', to: '\u{2f895}', }, + Range { from: '\u{2f896}', to: '\u{2f92b}', }, + Range { from: '\u{2f92c}', to: '\u{2f92d}', }, + Range { from: '\u{2f92e}', to: '\u{2f945}', }, + Range { from: '\u{2f946}', to: '\u{2f947}', }, + Range { from: '\u{2f948}', to: '\u{2f95c}', }, + Range { from: '\u{2f95d}', to: '\u{2f95e}', }, + Range { from: '\u{2f95f}', to: '\u{2f9fd}', }, + Range { from: '\u{2f9fe}', to: '\u{2f9ff}', }, + Range { from: '\u{2fa00}', to: '\u{2fa1d}', }, + Range { from: '\u{2fa1e}', to: '\u{e00ff}', }, + Range { from: '\u{e0100}', to: '\u{e01ef}', }, + Range { from: '\u{e01f0}', to: '\u{10ffff}', }, +]; + +static INDEX_TABLE: &'static [u16] = &[ + 32768, + 32769, + 32770, + 32771, + 32772, + 5, + 32799, + 32800, + 32801, + 32802, + 32803, + 32804, + 37, + 32808, + 41, + 32812, + 45, + 32817, + 50, + 32858, + 91, + 32909, + 142, + 32913, + 146, + 32920, + 153, + 32996, + 229, + 33008, + 241, + 33023, + 256, + 33037, + 33038, + 33039, + 33040, + 33041, + 33042, + 275, + 33058, + 291, + 33076, + 33077, + 310, + 33141, + 374, + 33147, + 380, + 33162, + 395, + 33172, + 405, + 33179, + 412, + 33185, + 418, + 33192, + 33193, + 33194, + 427, + 33203, + 33204, + 33205, + 438, + 33208, + 441, + 33249, + 33250, + 33251, + 484, + 33296, + 529, + 33348, + 581, + 33382, + 615, + 33451, + 684, + 33587, + 33588, + 33589, + 33590, + 823, + 33593, + 33594, + 33595, + 33596, + 33597, + 33598, + 33599, + 33600, + 33601, + 33602, + 33603, + 33604, + 33605, + 838, + 33610, + 33611, + 33612, + 33613, + 33614, + 33615, + 33616, + 33617, + 33618, + 33619, + 33620, + 33621, + 33622, + 33623, + 33624, + 33625, + 858, + 33628, + 33629, + 33630, + 33631, + 33632, + 33633, + 33634, + 33635, + 33636, + 869, + 33645, + 33646, + 33647, + 33648, + 33649, + 33650, + 33651, + 33652, + 33653, + 886, + 33656, + 33657, + 33658, + 33659, + 33660, + 33661, + 33662, + 33663, + 33664, + 33665, + 33666, + 899, + 33671, + 33672, + 33673, + 33674, + 33675, + 33676, + 33677, + 33678, + 33679, + 33680, + 33681, + 33682, + 33683, + 916, + 33691, + 33692, + 925, + 33695, + 33696, + 33697, + 33698, + 33699, + 33700, + 33701, + 33702, + 935, + 33709, + 33710, + 33711, + 33712, + 33713, + 33714, + 33715, + 33716, + 33717, + 33718, + 33719, + 33720, + 33721, + 33722, + 33723, + 33724, + 33725, + 33726, + 33727, + 33728, + 33729, + 33730, + 33731, + 33732, + 33733, + 33734, + 33735, + 33736, + 33737, + 33738, + 33739, + 33740, + 33741, + 33742, + 33743, + 33744, + 33745, + 33746, + 33747, + 33748, + 33749, + 33750, + 33751, + 33752, + 33753, + 33754, + 33755, + 33756, + 33757, + 33758, + 33759, + 33760, + 33761, + 994, + 33765, + 33766, + 33767, + 33768, + 33769, + 33770, + 33771, + 33772, + 33773, + 33774, + 33775, + 33776, + 33777, + 1010, + 33781, + 33782, + 33783, + 33784, + 33785, + 33786, + 33787, + 33788, + 33789, + 33790, + 33791, + 33792, + 33793, + 33794, + 33795, + 33796, + 33797, + 33798, + 33799, + 33800, + 33801, + 33802, + 33803, + 33804, + 33805, + 33806, + 33807, + 33808, + 33809, + 33810, + 33811, + 33812, + 33813, + 33814, + 33815, + 33816, + 33817, + 33818, + 33819, + 33820, + 33821, + 33822, + 33823, + 33824, + 33825, + 33826, + 33827, + 33828, + 33829, + 33830, + 33831, + 33832, + 33833, + 33834, + 33835, + 33836, + 33837, + 33838, + 33839, + 33840, + 33841, + 33842, + 33843, + 33844, + 1077, + 33847, + 33848, + 33849, + 33850, + 33851, + 33852, + 33853, + 33854, + 33855, + 33856, + 33857, + 33858, + 33859, + 33860, + 33861, + 33862, + 33863, + 33864, + 33865, + 33866, + 33867, + 33868, + 33869, + 33870, + 33871, + 33872, + 33873, + 33874, + 33875, + 1108, + 33878, + 33879, + 33880, + 33881, + 33882, + 33883, + 1116, + 33887, + 33888, + 33889, + 33890, + 33891, + 33892, + 33893, + 33894, + 33895, + 33896, + 33897, + 33898, + 33899, + 1132, + 33902, + 33903, + 1136, + 33906, + 33907, + 33908, + 33909, + 33910, + 33911, + 33912, + 33913, + 1146, + 33918, + 33919, + 33920, + 33921, + 33922, + 33923, + 33924, + 33925, + 33926, + 33927, + 1160, + 33931, + 33932, + 33933, + 33934, + 1167, + 33937, + 33938, + 33939, + 33940, + 33941, + 33942, + 33943, + 33944, + 33945, + 33946, + 33947, + 33948, + 33949, + 33950, + 33951, + 33952, + 33953, + 33954, + 33955, + 33956, + 33957, + 1190, + 33965, + 33966, + 33967, + 33968, + 33969, + 33970, + 33971, + 33972, + 33973, + 33974, + 33975, + 33976, + 33977, + 33978, + 33979, + 33980, + 33981, + 33982, + 33983, + 33984, + 33985, + 33986, + 33987, + 33988, + 33989, + 33990, + 33991, + 33992, + 33993, + 33994, + 33995, + 33996, + 33997, + 33998, + 33999, + 34000, + 34001, + 1234, + 34005, + 34006, + 34007, + 34008, + 34009, + 34010, + 34011, + 34012, + 34013, + 34014, + 34015, + 1248, + 34019, + 34020, + 34021, + 34022, + 34023, + 34024, + 34025, + 34026, + 34027, + 34028, + 34029, + 34030, + 34031, + 34032, + 34033, + 34034, + 1267, + 34041, + 34042, + 34043, + 34044, + 34045, + 34046, + 34047, + 34048, + 34049, + 34050, + 34051, + 34052, + 34053, + 34054, + 34055, + 34056, + 34057, + 34058, + 34059, + 34060, + 34061, + 34062, + 34063, + 34064, + 34065, + 34066, + 34067, + 34068, + 34069, + 34070, + 34071, + 34072, + 34073, + 34074, + 34075, + 34076, + 34077, + 34078, + 34079, + 34080, + 34081, + 34082, + 34083, + 34084, + 34085, + 34086, + 34087, + 34088, + 34089, + 34090, + 34091, + 34092, + 34093, + 34094, + 34095, + 34096, + 34097, + 34098, + 34099, + 34100, + 34101, + 34102, + 34103, + 34104, + 34105, + 34106, + 34107, + 34108, + 34109, + 34110, + 34111, + 34112, + 34113, + 34114, + 34115, + 34116, + 34117, + 34118, + 34119, + 34120, + 34121, + 34122, + 34123, + 34124, + 34125, + 1358, + 34130, + 1363, + 34134, + 34135, + 34136, + 34137, + 34138, + 34139, + 1372, + 34203, + 34204, + 34205, + 1438, + 34243, + 34244, + 34245, + 1478, + 34395, + 1628, + 34398, + 1631, + 34496, + 1729, + 34505, + 34506, + 1739, + 34513, + 34514, + 1747, + 34523, + 1756, + 34532, + 34533, + 1766, + 34540, + 34541, + 1774, + 34550, + 1783, + 34573, + 1806, + 34622, + 1855, + 34653, + 34654, + 34655, + 34656, + 1889, + 34665, + 34666, + 34667, + 1900, + 34676, + 1909, + 34691, + 34692, + 34693, + 34694, + 1927, + 34697, + 34698, + 34699, + 34700, + 34701, + 34702, + 34703, + 34704, + 1937, + 34710, + 1943, + 34714, + 1947, + 34718, + 34719, + 34720, + 1953, + 34723, + 34724, + 34725, + 1958, + 34728, + 1961, + 34770, + 34771, + 34772, + 34773, + 34774, + 34775, + 34776, + 2009, + 34788, + 34789, + 34790, + 34791, + 2024, + 34795, + 2028, + 34798, + 34799, + 2032, + 34815, + 2048, + 34828, + 2061, + 34831, + 34832, + 2065, + 34836, + 2069, + 34885, + 34886, + 34887, + 34888, + 34889, + 34890, + 34891, + 2124, + 34897, + 34898, + 34899, + 34900, + 34901, + 2134, + 34904, + 34905, + 34906, + 34907, + 2140, + 34948, + 2181, + 35028, + 35029, + 35030, + 2263, + 35034, + 35035, + 35036, + 35037, + 35038, + 35039, + 35040, + 35041, + 35042, + 35043, + 35044, + 35045, + 35046, + 35047, + 2280, + 35096, + 2329, + 35103, + 2336, + 35116, + 35117, + 35118, + 2351, + 35222, + 2455, + 35226, + 2459, + 35229, + 35230, + 2463, + 35233, + 35234, + 35235, + 35236, + 35237, + 2470, + 35240, + 35241, + 35242, + 35243, + 35244, + 35245, + 35246, + 35247, + 35248, + 35249, + 35250, + 35251, + 35252, + 35253, + 35254, + 35255, + 35256, + 35257, + 35258, + 35259, + 35260, + 35261, + 35262, + 35263, + 35264, + 35265, + 35266, + 35267, + 2500, + 35482, + 2715, + 35486, + 2719, + 35492, + 35493, + 35494, + 35495, + 35496, + 2729, + 35499, + 35500, + 35501, + 35502, + 35503, + 35504, + 35505, + 2738, + 35601, + 2834, + 35616, + 35617, + 35618, + 35619, + 35620, + 2853, + 35693, + 2926, + 36126, + 36127, + 36128, + 36129, + 36130, + 36131, + 36132, + 36133, + 36134, + 36135, + 3368, + 36181, + 3414, + 36212, + 36213, + 36214, + 3447, + 36228, + 3461, + 36292, + 3525, + 36307, + 3540, + 36311, + 3544, + 36315, + 3548, + 36350, + 3583, + 36354, + 36355, + 36356, + 36357, + 36358, + 36359, + 36360, + 36361, + 36362, + 36363, + 36364, + 36365, + 36366, + 36367, + 36368, + 36369, + 36370, + 36371, + 36372, + 36373, + 36374, + 36375, + 36376, + 36377, + 36378, + 36379, + 36380, + 36381, + 36382, + 36383, + 36384, + 36385, + 36386, + 36387, + 36388, + 36389, + 36390, + 36391, + 36392, + 36393, + 36394, + 36395, + 36396, + 3629, + 36401, + 36402, + 3635, + 36483, + 36484, + 36485, + 36486, + 36487, + 36488, + 36489, + 36490, + 36491, + 36492, + 3725, + 36500, + 3733, + 36762, + 3995, + 36766, + 3999, + 36781, + 4014, + 36784, + 4017, + 36836, + 4069, + 36852, + 4085, + 36959, + 4192, + 36965, + 36966, + 4199, + 36972, + 4205, + 37024, + 37025, + 37026, + 37027, + 37028, + 37029, + 37030, + 37031, + 37032, + 37033, + 37034, + 37035, + 37036, + 37037, + 37038, + 37039, + 37040, + 37041, + 37042, + 37043, + 37044, + 37045, + 37046, + 37047, + 37048, + 37049, + 37050, + 37051, + 37052, + 37053, + 37054, + 37055, + 37056, + 37057, + 37058, + 37059, + 37060, + 37061, + 37062, + 37063, + 37064, + 37065, + 37066, + 37067, + 37068, + 37069, + 37070, + 37071, + 37072, + 37073, + 37074, + 4307, + 37391, + 37392, + 37393, + 37394, + 37395, + 4628, + 37401, + 4634, + 37407, + 37408, + 37409, + 37410, + 37411, + 37412, + 37413, + 37414, + 37415, + 37416, + 37417, + 37418, + 4651, + 37422, + 4655, + 37427, + 4660, + 37433, + 37434, + 37435, + 4668, + 37443, + 4676, + 37449, + 4682, + 37453, + 4686, + 37496, + 4729, + 37511, + 37512, + 4745, + 37522, + 37523, + 4756, + 37527, + 4760, + 37544, + 4777, + 37547, + 37548, + 4781, + 37551, + 4784, + 37576, + 4809, + 37594, + 37595, + 37596, + 37597, + 37598, + 37599, + 37600, + 37601, + 37602, + 37603, + 37604, + 37605, + 37606, + 37607, + 37608, + 37609, + 37610, + 37611, + 37612, + 37613, + 37614, + 37615, + 37616, + 37617, + 37618, + 37619, + 37620, + 37621, + 37622, + 37623, + 37624, + 37625, + 37626, + 37627, + 37628, + 37629, + 37630, + 37631, + 37632, + 37633, + 4866, + 37826, + 5059, + 37833, + 5066, + 37840, + 5073, + 37847, + 5080, + 37851, + 5084, + 37867, + 37868, + 37869, + 37870, + 37871, + 37872, + 37873, + 37874, + 37875, + 37876, + 37877, + 37878, + 37879, + 37880, + 37881, + 37882, + 37883, + 37884, + 37885, + 37886, + 37887, + 37888, + 37889, + 37890, + 37891, + 37892, + 37893, + 37894, + 37895, + 37896, + 37897, + 37898, + 37899, + 37900, + 37901, + 37902, + 37903, + 37904, + 37905, + 37906, + 37907, + 37908, + 37909, + 37910, + 37911, + 5144, + 37952, + 37953, + 37954, + 37955, + 5188, + 37992, + 37993, + 37994, + 37995, + 37996, + 37997, + 37998, + 37999, + 38000, + 38001, + 38002, + 38003, + 38004, + 38005, + 38006, + 38007, + 38008, + 5241, + 38011, + 38012, + 38013, + 38014, + 38015, + 38016, + 38017, + 38018, + 38019, + 38020, + 38021, + 38022, + 38023, + 38024, + 38025, + 38026, + 38027, + 38028, + 38029, + 38030, + 38031, + 38032, + 38033, + 38034, + 38035, + 38036, + 38037, + 38038, + 38039, + 38040, + 38041, + 38042, + 38043, + 38044, + 38045, + 38046, + 38047, + 38048, + 38049, + 38050, + 38051, + 38052, + 38053, + 38054, + 38055, + 38056, + 38057, + 38058, + 38059, + 38060, + 38061, + 38062, + 38063, + 38064, + 38065, + 38066, + 38067, + 38068, + 38069, + 38070, + 38071, + 38072, + 5305, + 38124, + 38125, + 38126, + 38127, + 38128, + 38129, + 38130, + 38131, + 38132, + 38133, + 38134, + 38135, + 38136, + 38137, + 38138, + 38139, + 38140, + 38141, + 38142, + 38143, + 38144, + 38145, + 38146, + 38147, + 38148, + 38149, + 38150, + 38151, + 38152, + 38153, + 38154, + 38155, + 38156, + 38157, + 38158, + 38159, + 5392, + 38163, + 38164, + 38165, + 38166, + 38167, + 38168, + 38169, + 38170, + 38171, + 38172, + 38173, + 38174, + 38175, + 38176, + 38177, + 38178, + 38179, + 38180, + 38181, + 38182, + 38183, + 38184, + 38185, + 38186, + 38187, + 38188, + 38189, + 38190, + 38191, + 38192, + 38193, + 38194, + 38195, + 38196, + 38197, + 38198, + 38199, + 38200, + 38201, + 38202, + 38203, + 5436, + 38208, + 38209, + 38210, + 38211, + 38212, + 38213, + 38214, + 38215, + 38216, + 38217, + 38218, + 38219, + 38220, + 38221, + 38222, + 38223, + 38224, + 38225, + 38226, + 38227, + 38228, + 38229, + 38230, + 38231, + 38232, + 5465, + 38265, + 38266, + 38267, + 38268, + 38269, + 38270, + 38271, + 38272, + 38273, + 38274, + 38275, + 38276, + 38277, + 38278, + 38279, + 38280, + 38281, + 38282, + 38283, + 38284, + 38285, + 38286, + 38287, + 38288, + 38289, + 38290, + 38291, + 38292, + 38293, + 38294, + 38295, + 38296, + 38297, + 38298, + 5531, + 38301, + 38302, + 38303, + 38304, + 38305, + 38306, + 38307, + 38308, + 38309, + 38310, + 38311, + 38312, + 38313, + 38314, + 38315, + 38316, + 38317, + 38318, + 38319, + 38320, + 38321, + 38322, + 38323, + 38324, + 38325, + 38326, + 38327, + 38328, + 38329, + 38330, + 38331, + 38332, + 38333, + 38334, + 38335, + 38336, + 38337, + 38338, + 38339, + 38340, + 38341, + 38342, + 38343, + 38344, + 38345, + 38346, + 38347, + 38348, + 38349, + 38350, + 38351, + 38352, + 38353, + 38354, + 38355, + 38356, + 38357, + 38358, + 38359, + 38360, + 38361, + 38362, + 38363, + 38364, + 38365, + 38366, + 38367, + 38368, + 38369, + 38370, + 38371, + 38372, + 5605, + 38380, + 38381, + 38382, + 5615, + 38389, + 38390, + 38391, + 38392, + 38393, + 38394, + 38395, + 38396, + 5629, + 38557, + 38558, + 38559, + 5792, + 38562, + 5795, + 38661, + 5894, + 38720, + 5953, + 39069, + 6302, + 39113, + 6346, + 39170, + 6403, + 39227, + 6460, + 39284, + 6517, + 39341, + 6574, + 39355, + 39356, + 6589, + 39407, + 39408, + 39409, + 39410, + 39411, + 39412, + 39413, + 39414, + 39415, + 39416, + 39417, + 39418, + 39419, + 39420, + 39421, + 39422, + 39423, + 39424, + 39425, + 39426, + 6659, + 39461, + 39462, + 39463, + 39464, + 39465, + 39466, + 6699, + 39504, + 6737, + 39526, + 39527, + 39528, + 6761, + 39543, + 6776, + 39558, + 6791, + 39612, + 6845, + 39640, + 39641, + 39642, + 39643, + 39644, + 39645, + 39646, + 39647, + 39648, + 39649, + 39650, + 39651, + 39652, + 39653, + 39654, + 6887, + 39665, + 39666, + 6899, + 39731, + 6964, + 39734, + 39735, + 39736, + 39737, + 39738, + 39739, + 6972, + 39743, + 6976, + 39788, + 7021, + 39798, + 7031, + 39801, + 39802, + 39803, + 39804, + 39805, + 39806, + 39807, + 39808, + 39809, + 39810, + 39811, + 39812, + 39813, + 39814, + 39815, + 39816, + 39817, + 39818, + 39819, + 39820, + 39821, + 39822, + 39823, + 39824, + 39825, + 39826, + 39827, + 39828, + 39829, + 39830, + 39831, + 39832, + 39833, + 39834, + 39835, + 39836, + 39837, + 39838, + 39839, + 39840, + 39841, + 39842, + 39843, + 39844, + 39845, + 39846, + 39847, + 7080, + 39897, + 7130, + 39915, + 7148, + 39951, + 7184, + 39989, + 39990, + 39991, + 7224, + 40142, + 7375, + 40167, + 7400, + 40189, + 7422, + 40349, + 7582, + 40380, + 40381, + 40382, +]; + +static MAPPING_TABLE: &'static [Mapping] = &[ + DisallowedStd3Valid, + Valid, + DisallowedStd3Valid, + Valid, + DisallowedStd3Valid, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + DisallowedStd3Valid, + Valid, + DisallowedStd3Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 0, byte_len: 1 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 0, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Valid, + Ignored, + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 0, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 0, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 0, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 0, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 0, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 0, byte_len: 5 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 0, byte_len: 2 }), + Deviation(StringTableSlice { byte_start_lo: 119, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 0, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 0, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 0, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 1, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 1, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 1, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 1, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 1, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 1, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 1, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 1, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 1, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 1, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Valid, + Ignored, + Valid, + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 1, byte_len: 2 }), + Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 1, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 2, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 0, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 2, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 2, byte_len: 2 }), + Valid, + Deviation(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 3, byte_len: 2 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 3, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 3, byte_len: 2 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 3, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 3, byte_len: 2 }), + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 3, byte_len: 4 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 3, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 3, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 3, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 3, byte_len: 4 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 3, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 3, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 3, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 4, byte_len: 6 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 4, byte_len: 6 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 4, byte_len: 6 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 4, byte_len: 6 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 4, byte_len: 6 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 4, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 4, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 4, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 4, byte_len: 9 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 4, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 4, byte_len: 6 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 4, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 4, byte_len: 3 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 4, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 5, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Ignored, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 5, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 5, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 0, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 6, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 6, byte_len: 3 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 6, byte_len: 3 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 6, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 7, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 7, byte_len: 3 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 7, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 7, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 7, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 7, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 7, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 7, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 7, byte_len: 5 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 7, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 7, byte_len: 4 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 7, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 7, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 7, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 7, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 7, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 7, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 8, byte_len: 4 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 7, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 8, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 8, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 8, byte_len: 5 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 8, byte_len: 2 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 8, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 8, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 8, byte_len: 5 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 8, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 8, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 2, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 8, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 8, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 8, byte_len: 4 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 8, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 0, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 8, byte_len: 3 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 0, byte_len: 1 }), + Ignored, + Deviation(StringTableSlice { byte_start_lo: 105, byte_start_hi: 8, byte_len: 0 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 8, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 8, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 8, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 8, byte_len: 9 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 8, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 8, byte_len: 9 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 8, byte_len: 2 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 8, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 8, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 8, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 8, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 8, byte_len: 12 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 0, byte_len: 1 }), + Ignored, + Disallowed, + Ignored, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 8, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 8, byte_len: 2 }), + Valid, + Disallowed, + Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 8, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 1, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 8, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 8, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 8, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 8, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 8, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 8, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 9, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 9, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 9, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 9, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 9, byte_len: 5 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 9, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 9, byte_len: 9 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 9, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 9, byte_len: 9 }), + Valid, + DisallowedStd3Valid, + Valid, + DisallowedStd3Valid, + Valid, + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 9, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 9, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 9, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 9, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 9, byte_len: 4 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 10, byte_len: 12 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 10, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 10, byte_len: 5 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 10, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 10, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 10, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 5, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 10, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 10, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 10, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 11, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 11, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 11, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 11, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 0, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 14, byte_len: 1 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 14, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 14, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 14, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 14, byte_len: 4 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 14, byte_len: 6 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 14, byte_len: 6 }), + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 15, byte_len: 3 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 11, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 15, byte_len: 8 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 15, byte_len: 8 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 15, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 16, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 16, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 16, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 16, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 16, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 17, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 17, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 17, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 17, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 17, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 17, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 17, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 17, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 18, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 18, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 18, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 18, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 19, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 19, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 19, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 19, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 19, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 19, byte_len: 18 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 19, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 19, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 19, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 19, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 19, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 19, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 19, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 19, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 19, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 19, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 19, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 20, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 20, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 20, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 20, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 20, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 20, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 20, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 20, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 20, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 20, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 20, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 20, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 20, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 20, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 21, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 21, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 21, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 21, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 21, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 21, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 21, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 21, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 21, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 21, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 22, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 22, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 22, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 22, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 22, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 22, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 22, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 22, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 22, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 22, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 22, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 23, byte_len: 7 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 23, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 23, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 23, byte_len: 6 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 22, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 23, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 23, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 23, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 23, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 24, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 24, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 24, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 5, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 2, byte_len: 2 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 24, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 24, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 5, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 25, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 5, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 25, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 25, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 5, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 25, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 25, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 0, byte_len: 2 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 24, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 10, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 25, byte_len: 3 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 25, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 26, byte_len: 3 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 91, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 97, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 12, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 29, byte_len: 3 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 30, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 30, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 30, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 30, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 30, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 31, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 31, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 31, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 31, byte_len: 4 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 8, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 31, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 31, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 31, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 31, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 31, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 31, byte_len: 2 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 3, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 33, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 33, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 33, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 33, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 33, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 33, byte_len: 5 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 33, byte_len: 5 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 33, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 34, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 32, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 34, byte_len: 4 }), + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 34, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 35, byte_len: 6 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 35, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 36, byte_len: 6 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 36, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 37, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 37, byte_len: 6 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 37, byte_len: 33 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 37, byte_len: 15 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 37, byte_len: 8 }), + Valid, + Disallowed, + Ignored, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 37, byte_len: 3 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 2, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 37, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 37, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 9, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 37, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 8, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 37, byte_len: 3 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 2, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 37, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 37, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 8, byte_len: 1 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 37, byte_len: 1 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 37, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 37, byte_len: 3 }), + Valid, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 37, byte_len: 3 }), + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 37, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 37, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 37, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 37, byte_len: 4 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 37, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 32, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 38, byte_len: 4 }), + Disallowed, + Ignored, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 38, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 38, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 14, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 38, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 2, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 175, byte_start_hi: 8, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 37, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 38, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 38, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 37, byte_len: 1 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 38, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 14, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 37, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 49, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 55, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 18, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 38, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 98, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 101, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 107, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 113, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 125, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 146, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 14, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 14, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 38, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 0, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 38, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 38, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 38, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 38, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 39, byte_len: 4 }), + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 39, byte_len: 4 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 39, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 116, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 40, byte_len: 4 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 236, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 40, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 41, byte_len: 4 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Ignored, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 41, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 41, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 41, byte_len: 12 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 41, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 41, byte_len: 8 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 41, byte_len: 12 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 41, byte_len: 12 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 41, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 41, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 1, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 41, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 2, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 2, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 169, byte_start_hi: 8, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 8, byte_len: 1 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 166, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 41, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 42, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 42, byte_len: 4 }), + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 42, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 31, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 42, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 31, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 42, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 37, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 38, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 38, byte_len: 2 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 52, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 42, byte_len: 2 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 42, byte_len: 2 }), + Valid, + Disallowed, + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 205, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 208, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 211, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 217, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 220, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 223, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 9, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 10, byte_len: 3 }), + DisallowedStd3Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 10, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 42, byte_len: 7 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 2, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 5, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 15, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 0, byte_len: 1 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 42, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 39, byte_start_hi: 23, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 42, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 0, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 88, byte_start_hi: 42, byte_len: 2 }), + Valid, + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 42, byte_len: 2 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 42, byte_len: 2 }), + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 42, byte_len: 2 }), + Valid, + Disallowed, + Valid, + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 42, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 42, byte_len: 6 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 17, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 129, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 172, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 58, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 15, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 17, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 94, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 42, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 42, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 8, byte_start_hi: 43, byte_len: 9 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 43, byte_len: 9 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 43, byte_len: 3 }), + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Valid, + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 11, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 30, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 158, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 161, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 192, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 36, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 43, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 43, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 42, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 9, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 12, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 32, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 35, byte_start_hi: 44, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 44, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 73, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 76, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 79, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 117, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 123, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 12, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 164, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 182, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 185, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 201, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 204, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 234, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 44, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 247, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 250, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 253, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 19, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 22, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 25, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 28, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 59, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 62, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 65, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 71, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 106, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 131, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 134, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 137, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 140, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 144, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 150, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 153, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 110, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 178, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 181, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 156, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 103, byte_start_hi: 28, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 202, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 225, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 45, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 239, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 242, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 245, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 251, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 254, byte_start_hi: 45, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 1, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 11, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 14, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 18, byte_start_hi: 46, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 21, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 45, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 48, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 54, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 63, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 120, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 66, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 69, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 82, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 85, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 100, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 104, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 111, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 114, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 122, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 126, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 231, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 142, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 149, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 195, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 173, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 176, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 179, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 46, byte_len: 4 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 219, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 226, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 229, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 232, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 235, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 238, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 241, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 244, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 248, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 46, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 255, byte_start_hi: 46, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 3, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 6, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 213, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 16, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 24, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 27, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 31, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 34, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 38, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 41, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 44, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 47, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 56, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 60, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 68, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 44, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 75, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 78, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 81, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 84, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 87, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 90, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 93, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 96, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 119, byte_start_hi: 27, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 109, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 222, byte_start_hi: 29, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 127, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 130, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 133, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 136, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 139, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 143, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 147, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 151, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 154, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 157, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 160, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 163, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 167, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 170, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 188, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 191, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 198, byte_start_hi: 26, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 194, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 197, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 200, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 209, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 212, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 215, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 47, byte_len: 3 }), + Disallowed, + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 51, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 237, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 240, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 246, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 249, byte_start_hi: 47, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 252, byte_start_hi: 47, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 0, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 4, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 7, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 10, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 183, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 186, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 72, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 13, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 17, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 20, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 23, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 26, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 29, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 33, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 37, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 40, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 43, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 46, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 50, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 189, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 53, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 57, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 61, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 64, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 67, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 70, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 74, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 77, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 80, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 83, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 86, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 89, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 92, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 95, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 99, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 102, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 105, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 108, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 112, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 115, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 118, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 121, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 124, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 128, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 132, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 135, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 138, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 141, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 145, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 148, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 207, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 152, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 155, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 159, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 162, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 165, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 168, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 171, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 174, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 177, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 180, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 30, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 184, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 187, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 190, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 193, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 196, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 199, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 203, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 206, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 210, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 214, byte_start_hi: 48, byte_len: 4 }), + Mapped(StringTableSlice { byte_start_lo: 216, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 218, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 228, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 221, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 224, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 227, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 230, byte_start_hi: 48, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 243, byte_start_hi: 13, byte_len: 3 }), + Mapped(StringTableSlice { byte_start_lo: 233, byte_start_hi: 48, byte_len: 4 }), + Disallowed, + Ignored, + Disallowed, +]; + +static STRING_TABLE: &'static str = "\u{61}\ + \u{62}\ + \u{63}\ + \u{64}\ + \u{65}\ + \u{66}\ + \u{67}\ + \u{68}\ + \u{69}\ + \u{6a}\ + \u{6b}\ + \u{6c}\ + \u{6d}\ + \u{6e}\ + \u{6f}\ + \u{70}\ + \u{71}\ + \u{72}\ + \u{73}\ + \u{74}\ + \u{75}\ + \u{76}\ + \u{77}\ + \u{78}\ + \u{79}\ + \u{7a}\ + \u{20}\ + \u{20}\ + \u{308}\ + \u{20}\ + \u{304}\ + \u{32}\ + \u{33}\ + \u{20}\ + \u{301}\ + \u{3bc}\ + \u{20}\ + \u{327}\ + \u{31}\ + \u{31}\ + \u{2044}\ + \u{34}\ + \u{31}\ + \u{2044}\ + \u{32}\ + \u{33}\ + \u{2044}\ + \u{34}\ + \u{e0}\ + \u{e1}\ + \u{e2}\ + \u{e3}\ + \u{e4}\ + \u{e5}\ + \u{e6}\ + \u{e7}\ + \u{e8}\ + \u{e9}\ + \u{ea}\ + \u{eb}\ + \u{ec}\ + \u{ed}\ + \u{ee}\ + \u{ef}\ + \u{f0}\ + \u{f1}\ + \u{f2}\ + \u{f3}\ + \u{f4}\ + \u{f5}\ + \u{f6}\ + \u{f8}\ + \u{f9}\ + \u{fa}\ + \u{fb}\ + \u{fc}\ + \u{fd}\ + \u{fe}\ + \u{73}\ + \u{73}\ + \u{101}\ + \u{103}\ + \u{105}\ + \u{107}\ + \u{109}\ + \u{10b}\ + \u{10d}\ + \u{10f}\ + \u{111}\ + \u{113}\ + \u{115}\ + \u{117}\ + \u{119}\ + \u{11b}\ + \u{11d}\ + \u{11f}\ + \u{121}\ + \u{123}\ + \u{125}\ + \u{127}\ + \u{129}\ + \u{12b}\ + \u{12d}\ + \u{12f}\ + \u{69}\ + \u{307}\ + \u{69}\ + \u{6a}\ + \u{135}\ + \u{137}\ + \u{13a}\ + \u{13c}\ + \u{13e}\ + \u{6c}\ + \u{b7}\ + \u{142}\ + \u{144}\ + \u{146}\ + \u{148}\ + \u{2bc}\ + \u{6e}\ + \u{14b}\ + \u{14d}\ + \u{14f}\ + \u{151}\ + \u{153}\ + \u{155}\ + \u{157}\ + \u{159}\ + \u{15b}\ + \u{15d}\ + \u{15f}\ + \u{161}\ + \u{163}\ + \u{165}\ + \u{167}\ + \u{169}\ + \u{16b}\ + \u{16d}\ + \u{16f}\ + \u{171}\ + \u{173}\ + \u{175}\ + \u{177}\ + \u{ff}\ + \u{17a}\ + \u{17c}\ + \u{17e}\ + \u{253}\ + \u{183}\ + \u{185}\ + \u{254}\ + \u{188}\ + \u{256}\ + \u{257}\ + \u{18c}\ + \u{1dd}\ + \u{259}\ + \u{25b}\ + \u{192}\ + \u{260}\ + \u{263}\ + \u{269}\ + \u{268}\ + \u{199}\ + \u{26f}\ + \u{272}\ + \u{275}\ + \u{1a1}\ + \u{1a3}\ + \u{1a5}\ + \u{280}\ + \u{1a8}\ + \u{283}\ + \u{1ad}\ + \u{288}\ + \u{1b0}\ + \u{28a}\ + \u{28b}\ + \u{1b4}\ + \u{1b6}\ + \u{292}\ + \u{1b9}\ + \u{1bd}\ + \u{64}\ + \u{17e}\ + \u{6c}\ + \u{6a}\ + \u{6e}\ + \u{6a}\ + \u{1ce}\ + \u{1d0}\ + \u{1d2}\ + \u{1d4}\ + \u{1d6}\ + \u{1d8}\ + \u{1da}\ + \u{1dc}\ + \u{1df}\ + \u{1e1}\ + \u{1e3}\ + \u{1e5}\ + \u{1e7}\ + \u{1e9}\ + \u{1eb}\ + \u{1ed}\ + \u{1ef}\ + \u{64}\ + \u{7a}\ + \u{1f5}\ + \u{195}\ + \u{1bf}\ + \u{1f9}\ + \u{1fb}\ + \u{1fd}\ + \u{1ff}\ + \u{201}\ + \u{203}\ + \u{205}\ + \u{207}\ + \u{209}\ + \u{20b}\ + \u{20d}\ + \u{20f}\ + \u{211}\ + \u{213}\ + \u{215}\ + \u{217}\ + \u{219}\ + \u{21b}\ + \u{21d}\ + \u{21f}\ + \u{19e}\ + \u{223}\ + \u{225}\ + \u{227}\ + \u{229}\ + \u{22b}\ + \u{22d}\ + \u{22f}\ + \u{231}\ + \u{233}\ + \u{2c65}\ + \u{23c}\ + \u{19a}\ + \u{2c66}\ + \u{242}\ + \u{180}\ + \u{289}\ + \u{28c}\ + \u{247}\ + \u{249}\ + \u{24b}\ + \u{24d}\ + \u{24f}\ + \u{266}\ + \u{279}\ + \u{27b}\ + \u{281}\ + \u{20}\ + \u{306}\ + \u{20}\ + \u{307}\ + \u{20}\ + \u{30a}\ + \u{20}\ + \u{328}\ + \u{20}\ + \u{303}\ + \u{20}\ + \u{30b}\ + \u{295}\ + \u{300}\ + \u{301}\ + \u{313}\ + \u{308}\ + \u{301}\ + \u{3b9}\ + \u{371}\ + \u{373}\ + \u{2b9}\ + \u{377}\ + \u{20}\ + \u{3b9}\ + \u{3b}\ + \u{3f3}\ + \u{20}\ + \u{308}\ + \u{301}\ + \u{3ac}\ + \u{b7}\ + \u{3ad}\ + \u{3ae}\ + \u{3af}\ + \u{3cc}\ + \u{3cd}\ + \u{3ce}\ + \u{3b1}\ + \u{3b2}\ + \u{3b3}\ + \u{3b4}\ + \u{3b5}\ + \u{3b6}\ + \u{3b7}\ + \u{3b8}\ + \u{3ba}\ + \u{3bb}\ + \u{3bd}\ + \u{3be}\ + \u{3bf}\ + \u{3c0}\ + \u{3c1}\ + \u{3c3}\ + \u{3c4}\ + \u{3c5}\ + \u{3c6}\ + \u{3c7}\ + \u{3c8}\ + \u{3c9}\ + \u{3ca}\ + \u{3cb}\ + \u{3d7}\ + \u{3d9}\ + \u{3db}\ + \u{3dd}\ + \u{3df}\ + \u{3e1}\ + \u{3e3}\ + \u{3e5}\ + \u{3e7}\ + \u{3e9}\ + \u{3eb}\ + \u{3ed}\ + \u{3ef}\ + \u{3f8}\ + \u{3fb}\ + \u{37b}\ + \u{37c}\ + \u{37d}\ + \u{450}\ + \u{451}\ + \u{452}\ + \u{453}\ + \u{454}\ + \u{455}\ + \u{456}\ + \u{457}\ + \u{458}\ + \u{459}\ + \u{45a}\ + \u{45b}\ + \u{45c}\ + \u{45d}\ + \u{45e}\ + \u{45f}\ + \u{430}\ + \u{431}\ + \u{432}\ + \u{433}\ + \u{434}\ + \u{435}\ + \u{436}\ + \u{437}\ + \u{438}\ + \u{439}\ + \u{43a}\ + \u{43b}\ + \u{43c}\ + \u{43d}\ + \u{43e}\ + \u{43f}\ + \u{440}\ + \u{441}\ + \u{442}\ + \u{443}\ + \u{444}\ + \u{445}\ + \u{446}\ + \u{447}\ + \u{448}\ + \u{449}\ + \u{44a}\ + \u{44b}\ + \u{44c}\ + \u{44d}\ + \u{44e}\ + \u{44f}\ + \u{461}\ + \u{463}\ + \u{465}\ + \u{467}\ + \u{469}\ + \u{46b}\ + \u{46d}\ + \u{46f}\ + \u{471}\ + \u{473}\ + \u{475}\ + \u{477}\ + \u{479}\ + \u{47b}\ + \u{47d}\ + \u{47f}\ + \u{481}\ + \u{48b}\ + \u{48d}\ + \u{48f}\ + \u{491}\ + \u{493}\ + \u{495}\ + \u{497}\ + \u{499}\ + \u{49b}\ + \u{49d}\ + \u{49f}\ + \u{4a1}\ + \u{4a3}\ + \u{4a5}\ + \u{4a7}\ + \u{4a9}\ + \u{4ab}\ + \u{4ad}\ + \u{4af}\ + \u{4b1}\ + \u{4b3}\ + \u{4b5}\ + \u{4b7}\ + \u{4b9}\ + \u{4bb}\ + \u{4bd}\ + \u{4bf}\ + \u{4c2}\ + \u{4c4}\ + \u{4c6}\ + \u{4c8}\ + \u{4ca}\ + \u{4cc}\ + \u{4ce}\ + \u{4d1}\ + \u{4d3}\ + \u{4d5}\ + \u{4d7}\ + \u{4d9}\ + \u{4db}\ + \u{4dd}\ + \u{4df}\ + \u{4e1}\ + \u{4e3}\ + \u{4e5}\ + \u{4e7}\ + \u{4e9}\ + \u{4eb}\ + \u{4ed}\ + \u{4ef}\ + \u{4f1}\ + \u{4f3}\ + \u{4f5}\ + \u{4f7}\ + \u{4f9}\ + \u{4fb}\ + \u{4fd}\ + \u{4ff}\ + \u{501}\ + \u{503}\ + \u{505}\ + \u{507}\ + \u{509}\ + \u{50b}\ + \u{50d}\ + \u{50f}\ + \u{511}\ + \u{513}\ + \u{515}\ + \u{517}\ + \u{519}\ + \u{51b}\ + \u{51d}\ + \u{51f}\ + \u{521}\ + \u{523}\ + \u{525}\ + \u{527}\ + \u{529}\ + \u{52b}\ + \u{52d}\ + \u{52f}\ + \u{561}\ + \u{562}\ + \u{563}\ + \u{564}\ + \u{565}\ + \u{566}\ + \u{567}\ + \u{568}\ + \u{569}\ + \u{56a}\ + \u{56b}\ + \u{56c}\ + \u{56d}\ + \u{56e}\ + \u{56f}\ + \u{570}\ + \u{571}\ + \u{572}\ + \u{573}\ + \u{574}\ + \u{575}\ + \u{576}\ + \u{577}\ + \u{578}\ + \u{579}\ + \u{57a}\ + \u{57b}\ + \u{57c}\ + \u{57d}\ + \u{57e}\ + \u{57f}\ + \u{580}\ + \u{581}\ + \u{582}\ + \u{583}\ + \u{584}\ + \u{585}\ + \u{586}\ + \u{565}\ + \u{582}\ + \u{627}\ + \u{674}\ + \u{648}\ + \u{674}\ + \u{6c7}\ + \u{674}\ + \u{64a}\ + \u{674}\ + \u{915}\ + \u{93c}\ + \u{916}\ + \u{93c}\ + \u{917}\ + \u{93c}\ + \u{91c}\ + \u{93c}\ + \u{921}\ + \u{93c}\ + \u{922}\ + \u{93c}\ + \u{92b}\ + \u{93c}\ + \u{92f}\ + \u{93c}\ + \u{9a1}\ + \u{9bc}\ + \u{9a2}\ + \u{9bc}\ + \u{9af}\ + \u{9bc}\ + \u{a32}\ + \u{a3c}\ + \u{a38}\ + \u{a3c}\ + \u{a16}\ + \u{a3c}\ + \u{a17}\ + \u{a3c}\ + \u{a1c}\ + \u{a3c}\ + \u{a2b}\ + \u{a3c}\ + \u{b21}\ + \u{b3c}\ + \u{b22}\ + \u{b3c}\ + \u{e4d}\ + \u{e32}\ + \u{ecd}\ + \u{eb2}\ + \u{eab}\ + \u{e99}\ + \u{eab}\ + \u{ea1}\ + \u{f0b}\ + \u{f42}\ + \u{fb7}\ + \u{f4c}\ + \u{fb7}\ + \u{f51}\ + \u{fb7}\ + \u{f56}\ + \u{fb7}\ + \u{f5b}\ + \u{fb7}\ + \u{f40}\ + \u{fb5}\ + \u{f71}\ + \u{f72}\ + \u{f71}\ + \u{f74}\ + \u{fb2}\ + \u{f80}\ + \u{fb2}\ + \u{f71}\ + \u{f80}\ + \u{fb3}\ + \u{f80}\ + \u{fb3}\ + \u{f71}\ + \u{f80}\ + \u{f71}\ + \u{f80}\ + \u{f92}\ + \u{fb7}\ + \u{f9c}\ + \u{fb7}\ + \u{fa1}\ + \u{fb7}\ + \u{fa6}\ + \u{fb7}\ + \u{fab}\ + \u{fb7}\ + \u{f90}\ + \u{fb5}\ + \u{2d27}\ + \u{2d2d}\ + \u{10dc}\ + \u{13f0}\ + \u{13f1}\ + \u{13f2}\ + \u{13f3}\ + \u{13f4}\ + \u{13f5}\ + \u{a64b}\ + \u{250}\ + \u{251}\ + \u{1d02}\ + \u{25c}\ + \u{1d16}\ + \u{1d17}\ + \u{1d1d}\ + \u{1d25}\ + \u{252}\ + \u{255}\ + \u{25f}\ + \u{261}\ + \u{265}\ + \u{26a}\ + \u{1d7b}\ + \u{29d}\ + \u{26d}\ + \u{1d85}\ + \u{29f}\ + \u{271}\ + \u{270}\ + \u{273}\ + \u{274}\ + \u{278}\ + \u{282}\ + \u{1ab}\ + \u{1d1c}\ + \u{290}\ + \u{291}\ + \u{1e01}\ + \u{1e03}\ + \u{1e05}\ + \u{1e07}\ + \u{1e09}\ + \u{1e0b}\ + \u{1e0d}\ + \u{1e0f}\ + \u{1e11}\ + \u{1e13}\ + \u{1e15}\ + \u{1e17}\ + \u{1e19}\ + \u{1e1b}\ + \u{1e1d}\ + \u{1e1f}\ + \u{1e21}\ + \u{1e23}\ + \u{1e25}\ + \u{1e27}\ + \u{1e29}\ + \u{1e2b}\ + \u{1e2d}\ + \u{1e2f}\ + \u{1e31}\ + \u{1e33}\ + \u{1e35}\ + \u{1e37}\ + \u{1e39}\ + \u{1e3b}\ + \u{1e3d}\ + \u{1e3f}\ + \u{1e41}\ + \u{1e43}\ + \u{1e45}\ + \u{1e47}\ + \u{1e49}\ + \u{1e4b}\ + \u{1e4d}\ + \u{1e4f}\ + \u{1e51}\ + \u{1e53}\ + \u{1e55}\ + \u{1e57}\ + \u{1e59}\ + \u{1e5b}\ + \u{1e5d}\ + \u{1e5f}\ + \u{1e61}\ + \u{1e63}\ + \u{1e65}\ + \u{1e67}\ + \u{1e69}\ + \u{1e6b}\ + \u{1e6d}\ + \u{1e6f}\ + \u{1e71}\ + \u{1e73}\ + \u{1e75}\ + \u{1e77}\ + \u{1e79}\ + \u{1e7b}\ + \u{1e7d}\ + \u{1e7f}\ + \u{1e81}\ + \u{1e83}\ + \u{1e85}\ + \u{1e87}\ + \u{1e89}\ + \u{1e8b}\ + \u{1e8d}\ + \u{1e8f}\ + \u{1e91}\ + \u{1e93}\ + \u{1e95}\ + \u{61}\ + \u{2be}\ + \u{1ea1}\ + \u{1ea3}\ + \u{1ea5}\ + \u{1ea7}\ + \u{1ea9}\ + \u{1eab}\ + \u{1ead}\ + \u{1eaf}\ + \u{1eb1}\ + \u{1eb3}\ + \u{1eb5}\ + \u{1eb7}\ + \u{1eb9}\ + \u{1ebb}\ + \u{1ebd}\ + \u{1ebf}\ + \u{1ec1}\ + \u{1ec3}\ + \u{1ec5}\ + \u{1ec7}\ + \u{1ec9}\ + \u{1ecb}\ + \u{1ecd}\ + \u{1ecf}\ + \u{1ed1}\ + \u{1ed3}\ + \u{1ed5}\ + \u{1ed7}\ + \u{1ed9}\ + \u{1edb}\ + \u{1edd}\ + \u{1edf}\ + \u{1ee1}\ + \u{1ee3}\ + \u{1ee5}\ + \u{1ee7}\ + \u{1ee9}\ + \u{1eeb}\ + \u{1eed}\ + \u{1eef}\ + \u{1ef1}\ + \u{1ef3}\ + \u{1ef5}\ + \u{1ef7}\ + \u{1ef9}\ + \u{1efb}\ + \u{1efd}\ + \u{1eff}\ + \u{1f00}\ + \u{1f01}\ + \u{1f02}\ + \u{1f03}\ + \u{1f04}\ + \u{1f05}\ + \u{1f06}\ + \u{1f07}\ + \u{1f10}\ + \u{1f11}\ + \u{1f12}\ + \u{1f13}\ + \u{1f14}\ + \u{1f15}\ + \u{1f20}\ + \u{1f21}\ + \u{1f22}\ + \u{1f23}\ + \u{1f24}\ + \u{1f25}\ + \u{1f26}\ + \u{1f27}\ + \u{1f30}\ + \u{1f31}\ + \u{1f32}\ + \u{1f33}\ + \u{1f34}\ + \u{1f35}\ + \u{1f36}\ + \u{1f37}\ + \u{1f40}\ + \u{1f41}\ + \u{1f42}\ + \u{1f43}\ + \u{1f44}\ + \u{1f45}\ + \u{1f51}\ + \u{1f53}\ + \u{1f55}\ + \u{1f57}\ + \u{1f60}\ + \u{1f61}\ + \u{1f62}\ + \u{1f63}\ + \u{1f64}\ + \u{1f65}\ + \u{1f66}\ + \u{1f67}\ + \u{1f00}\ + \u{3b9}\ + \u{1f01}\ + \u{3b9}\ + \u{1f02}\ + \u{3b9}\ + \u{1f03}\ + \u{3b9}\ + \u{1f04}\ + \u{3b9}\ + \u{1f05}\ + \u{3b9}\ + \u{1f06}\ + \u{3b9}\ + \u{1f07}\ + \u{3b9}\ + \u{1f20}\ + \u{3b9}\ + \u{1f21}\ + \u{3b9}\ + \u{1f22}\ + \u{3b9}\ + \u{1f23}\ + \u{3b9}\ + \u{1f24}\ + \u{3b9}\ + \u{1f25}\ + \u{3b9}\ + \u{1f26}\ + \u{3b9}\ + \u{1f27}\ + \u{3b9}\ + \u{1f60}\ + \u{3b9}\ + \u{1f61}\ + \u{3b9}\ + \u{1f62}\ + \u{3b9}\ + \u{1f63}\ + \u{3b9}\ + \u{1f64}\ + \u{3b9}\ + \u{1f65}\ + \u{3b9}\ + \u{1f66}\ + \u{3b9}\ + \u{1f67}\ + \u{3b9}\ + \u{1f70}\ + \u{3b9}\ + \u{3b1}\ + \u{3b9}\ + \u{3ac}\ + \u{3b9}\ + \u{1fb6}\ + \u{3b9}\ + \u{1fb0}\ + \u{1fb1}\ + \u{1f70}\ + \u{20}\ + \u{313}\ + \u{20}\ + \u{342}\ + \u{20}\ + \u{308}\ + \u{342}\ + \u{1f74}\ + \u{3b9}\ + \u{3b7}\ + \u{3b9}\ + \u{3ae}\ + \u{3b9}\ + \u{1fc6}\ + \u{3b9}\ + \u{1f72}\ + \u{1f74}\ + \u{20}\ + \u{313}\ + \u{300}\ + \u{20}\ + \u{313}\ + \u{301}\ + \u{20}\ + \u{313}\ + \u{342}\ + \u{390}\ + \u{1fd0}\ + \u{1fd1}\ + \u{1f76}\ + \u{20}\ + \u{314}\ + \u{300}\ + \u{20}\ + \u{314}\ + \u{301}\ + \u{20}\ + \u{314}\ + \u{342}\ + \u{3b0}\ + \u{1fe0}\ + \u{1fe1}\ + \u{1f7a}\ + \u{1fe5}\ + \u{20}\ + \u{308}\ + \u{300}\ + \u{60}\ + \u{1f7c}\ + \u{3b9}\ + \u{3c9}\ + \u{3b9}\ + \u{3ce}\ + \u{3b9}\ + \u{1ff6}\ + \u{3b9}\ + \u{1f78}\ + \u{1f7c}\ + \u{20}\ + \u{314}\ + \u{2010}\ + \u{20}\ + \u{333}\ + \u{2032}\ + \u{2032}\ + \u{2032}\ + \u{2032}\ + \u{2032}\ + \u{2035}\ + \u{2035}\ + \u{2035}\ + \u{2035}\ + \u{2035}\ + \u{21}\ + \u{21}\ + \u{20}\ + \u{305}\ + \u{3f}\ + \u{3f}\ + \u{3f}\ + \u{21}\ + \u{21}\ + \u{3f}\ + \u{2032}\ + \u{2032}\ + \u{2032}\ + \u{2032}\ + \u{30}\ + \u{34}\ + \u{35}\ + \u{36}\ + \u{37}\ + \u{38}\ + \u{39}\ + \u{2b}\ + \u{2212}\ + \u{3d}\ + \u{28}\ + \u{29}\ + \u{72}\ + \u{73}\ + \u{61}\ + \u{2f}\ + \u{63}\ + \u{61}\ + \u{2f}\ + \u{73}\ + \u{b0}\ + \u{63}\ + \u{63}\ + \u{2f}\ + \u{6f}\ + \u{63}\ + \u{2f}\ + \u{75}\ + \u{b0}\ + \u{66}\ + \u{6e}\ + \u{6f}\ + \u{73}\ + \u{6d}\ + \u{74}\ + \u{65}\ + \u{6c}\ + \u{74}\ + \u{6d}\ + \u{5d0}\ + \u{5d1}\ + \u{5d2}\ + \u{5d3}\ + \u{66}\ + \u{61}\ + \u{78}\ + \u{2211}\ + \u{31}\ + \u{2044}\ + \u{37}\ + \u{31}\ + \u{2044}\ + \u{39}\ + \u{31}\ + \u{2044}\ + \u{31}\ + \u{30}\ + \u{31}\ + \u{2044}\ + \u{33}\ + \u{32}\ + \u{2044}\ + \u{33}\ + \u{31}\ + \u{2044}\ + \u{35}\ + \u{32}\ + \u{2044}\ + \u{35}\ + \u{33}\ + \u{2044}\ + \u{35}\ + \u{34}\ + \u{2044}\ + \u{35}\ + \u{31}\ + \u{2044}\ + \u{36}\ + \u{35}\ + \u{2044}\ + \u{36}\ + \u{31}\ + \u{2044}\ + \u{38}\ + \u{33}\ + \u{2044}\ + \u{38}\ + \u{35}\ + \u{2044}\ + \u{38}\ + \u{37}\ + \u{2044}\ + \u{38}\ + \u{31}\ + \u{2044}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{76}\ + \u{76}\ + \u{69}\ + \u{76}\ + \u{69}\ + \u{69}\ + \u{76}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{69}\ + \u{78}\ + \u{78}\ + \u{69}\ + \u{78}\ + \u{69}\ + \u{69}\ + \u{30}\ + \u{2044}\ + \u{33}\ + \u{222b}\ + \u{222b}\ + \u{222b}\ + \u{222b}\ + \u{222b}\ + \u{222e}\ + \u{222e}\ + \u{222e}\ + \u{222e}\ + \u{222e}\ + \u{3008}\ + \u{3009}\ + \u{31}\ + \u{30}\ + \u{31}\ + \u{31}\ + \u{31}\ + \u{32}\ + \u{31}\ + \u{33}\ + \u{31}\ + \u{34}\ + \u{31}\ + \u{35}\ + \u{31}\ + \u{36}\ + \u{31}\ + \u{37}\ + \u{31}\ + \u{38}\ + \u{31}\ + \u{39}\ + \u{32}\ + \u{30}\ + \u{28}\ + \u{31}\ + \u{29}\ + \u{28}\ + \u{32}\ + \u{29}\ + \u{28}\ + \u{33}\ + \u{29}\ + \u{28}\ + \u{34}\ + \u{29}\ + \u{28}\ + \u{35}\ + \u{29}\ + \u{28}\ + \u{36}\ + \u{29}\ + \u{28}\ + \u{37}\ + \u{29}\ + \u{28}\ + \u{38}\ + \u{29}\ + \u{28}\ + \u{39}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{30}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{31}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{32}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{33}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{34}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{35}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{36}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{37}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{38}\ + \u{29}\ + \u{28}\ + \u{31}\ + \u{39}\ + \u{29}\ + \u{28}\ + \u{32}\ + \u{30}\ + \u{29}\ + \u{28}\ + \u{61}\ + \u{29}\ + \u{28}\ + \u{62}\ + \u{29}\ + \u{28}\ + \u{63}\ + \u{29}\ + \u{28}\ + \u{64}\ + \u{29}\ + \u{28}\ + \u{65}\ + \u{29}\ + \u{28}\ + \u{66}\ + \u{29}\ + \u{28}\ + \u{67}\ + \u{29}\ + \u{28}\ + \u{68}\ + \u{29}\ + \u{28}\ + \u{69}\ + \u{29}\ + \u{28}\ + \u{6a}\ + \u{29}\ + \u{28}\ + \u{6b}\ + \u{29}\ + \u{28}\ + \u{6c}\ + \u{29}\ + \u{28}\ + \u{6d}\ + \u{29}\ + \u{28}\ + \u{6e}\ + \u{29}\ + \u{28}\ + \u{6f}\ + \u{29}\ + \u{28}\ + \u{70}\ + \u{29}\ + \u{28}\ + \u{71}\ + \u{29}\ + \u{28}\ + \u{72}\ + \u{29}\ + \u{28}\ + \u{73}\ + \u{29}\ + \u{28}\ + \u{74}\ + \u{29}\ + \u{28}\ + \u{75}\ + \u{29}\ + \u{28}\ + \u{76}\ + \u{29}\ + \u{28}\ + \u{77}\ + \u{29}\ + \u{28}\ + \u{78}\ + \u{29}\ + \u{28}\ + \u{79}\ + \u{29}\ + \u{28}\ + \u{7a}\ + \u{29}\ + \u{222b}\ + \u{222b}\ + \u{222b}\ + \u{222b}\ + \u{3a}\ + \u{3a}\ + \u{3d}\ + \u{3d}\ + \u{3d}\ + \u{3d}\ + \u{3d}\ + \u{3d}\ + \u{2add}\ + \u{338}\ + \u{2c30}\ + \u{2c31}\ + \u{2c32}\ + \u{2c33}\ + \u{2c34}\ + \u{2c35}\ + \u{2c36}\ + \u{2c37}\ + \u{2c38}\ + \u{2c39}\ + \u{2c3a}\ + \u{2c3b}\ + \u{2c3c}\ + \u{2c3d}\ + \u{2c3e}\ + \u{2c3f}\ + \u{2c40}\ + \u{2c41}\ + \u{2c42}\ + \u{2c43}\ + \u{2c44}\ + \u{2c45}\ + \u{2c46}\ + \u{2c47}\ + \u{2c48}\ + \u{2c49}\ + \u{2c4a}\ + \u{2c4b}\ + \u{2c4c}\ + \u{2c4d}\ + \u{2c4e}\ + \u{2c4f}\ + \u{2c50}\ + \u{2c51}\ + \u{2c52}\ + \u{2c53}\ + \u{2c54}\ + \u{2c55}\ + \u{2c56}\ + \u{2c57}\ + \u{2c58}\ + \u{2c59}\ + \u{2c5a}\ + \u{2c5b}\ + \u{2c5c}\ + \u{2c5d}\ + \u{2c5e}\ + \u{2c61}\ + \u{26b}\ + \u{1d7d}\ + \u{27d}\ + \u{2c68}\ + \u{2c6a}\ + \u{2c6c}\ + \u{2c73}\ + \u{2c76}\ + \u{23f}\ + \u{240}\ + \u{2c81}\ + \u{2c83}\ + \u{2c85}\ + \u{2c87}\ + \u{2c89}\ + \u{2c8b}\ + \u{2c8d}\ + \u{2c8f}\ + \u{2c91}\ + \u{2c93}\ + \u{2c95}\ + \u{2c97}\ + \u{2c99}\ + \u{2c9b}\ + \u{2c9d}\ + \u{2c9f}\ + \u{2ca1}\ + \u{2ca3}\ + \u{2ca5}\ + \u{2ca7}\ + \u{2ca9}\ + \u{2cab}\ + \u{2cad}\ + \u{2caf}\ + \u{2cb1}\ + \u{2cb3}\ + \u{2cb5}\ + \u{2cb7}\ + \u{2cb9}\ + \u{2cbb}\ + \u{2cbd}\ + \u{2cbf}\ + \u{2cc1}\ + \u{2cc3}\ + \u{2cc5}\ + \u{2cc7}\ + \u{2cc9}\ + \u{2ccb}\ + \u{2ccd}\ + \u{2ccf}\ + \u{2cd1}\ + \u{2cd3}\ + \u{2cd5}\ + \u{2cd7}\ + \u{2cd9}\ + \u{2cdb}\ + \u{2cdd}\ + \u{2cdf}\ + \u{2ce1}\ + \u{2ce3}\ + \u{2cec}\ + \u{2cee}\ + \u{2cf3}\ + \u{2d61}\ + \u{6bcd}\ + \u{9f9f}\ + \u{4e00}\ + \u{4e28}\ + \u{4e36}\ + \u{4e3f}\ + \u{4e59}\ + \u{4e85}\ + \u{4e8c}\ + \u{4ea0}\ + \u{4eba}\ + \u{513f}\ + \u{5165}\ + \u{516b}\ + \u{5182}\ + \u{5196}\ + \u{51ab}\ + \u{51e0}\ + \u{51f5}\ + \u{5200}\ + \u{529b}\ + \u{52f9}\ + \u{5315}\ + \u{531a}\ + \u{5338}\ + \u{5341}\ + \u{535c}\ + \u{5369}\ + \u{5382}\ + \u{53b6}\ + \u{53c8}\ + \u{53e3}\ + \u{56d7}\ + \u{571f}\ + \u{58eb}\ + \u{5902}\ + \u{590a}\ + \u{5915}\ + \u{5927}\ + \u{5973}\ + \u{5b50}\ + \u{5b80}\ + \u{5bf8}\ + \u{5c0f}\ + \u{5c22}\ + \u{5c38}\ + \u{5c6e}\ + \u{5c71}\ + \u{5ddb}\ + \u{5de5}\ + \u{5df1}\ + \u{5dfe}\ + \u{5e72}\ + \u{5e7a}\ + \u{5e7f}\ + \u{5ef4}\ + \u{5efe}\ + \u{5f0b}\ + \u{5f13}\ + \u{5f50}\ + \u{5f61}\ + \u{5f73}\ + \u{5fc3}\ + \u{6208}\ + \u{6236}\ + \u{624b}\ + \u{652f}\ + \u{6534}\ + \u{6587}\ + \u{6597}\ + \u{65a4}\ + \u{65b9}\ + \u{65e0}\ + \u{65e5}\ + \u{66f0}\ + \u{6708}\ + \u{6728}\ + \u{6b20}\ + \u{6b62}\ + \u{6b79}\ + \u{6bb3}\ + \u{6bcb}\ + \u{6bd4}\ + \u{6bdb}\ + \u{6c0f}\ + \u{6c14}\ + \u{6c34}\ + \u{706b}\ + \u{722a}\ + \u{7236}\ + \u{723b}\ + \u{723f}\ + \u{7247}\ + \u{7259}\ + \u{725b}\ + \u{72ac}\ + \u{7384}\ + \u{7389}\ + \u{74dc}\ + \u{74e6}\ + \u{7518}\ + \u{751f}\ + \u{7528}\ + \u{7530}\ + \u{758b}\ + \u{7592}\ + \u{7676}\ + \u{767d}\ + \u{76ae}\ + \u{76bf}\ + \u{76ee}\ + \u{77db}\ + \u{77e2}\ + \u{77f3}\ + \u{793a}\ + \u{79b8}\ + \u{79be}\ + \u{7a74}\ + \u{7acb}\ + \u{7af9}\ + \u{7c73}\ + \u{7cf8}\ + \u{7f36}\ + \u{7f51}\ + \u{7f8a}\ + \u{7fbd}\ + \u{8001}\ + \u{800c}\ + \u{8012}\ + \u{8033}\ + \u{807f}\ + \u{8089}\ + \u{81e3}\ + \u{81ea}\ + \u{81f3}\ + \u{81fc}\ + \u{820c}\ + \u{821b}\ + \u{821f}\ + \u{826e}\ + \u{8272}\ + \u{8278}\ + \u{864d}\ + \u{866b}\ + \u{8840}\ + \u{884c}\ + \u{8863}\ + \u{897e}\ + \u{898b}\ + \u{89d2}\ + \u{8a00}\ + \u{8c37}\ + \u{8c46}\ + \u{8c55}\ + \u{8c78}\ + \u{8c9d}\ + \u{8d64}\ + \u{8d70}\ + \u{8db3}\ + \u{8eab}\ + \u{8eca}\ + \u{8f9b}\ + \u{8fb0}\ + \u{8fb5}\ + \u{9091}\ + \u{9149}\ + \u{91c6}\ + \u{91cc}\ + \u{91d1}\ + \u{9577}\ + \u{9580}\ + \u{961c}\ + \u{96b6}\ + \u{96b9}\ + \u{96e8}\ + \u{9751}\ + \u{975e}\ + \u{9762}\ + \u{9769}\ + \u{97cb}\ + \u{97ed}\ + \u{97f3}\ + \u{9801}\ + \u{98a8}\ + \u{98db}\ + \u{98df}\ + \u{9996}\ + \u{9999}\ + \u{99ac}\ + \u{9aa8}\ + \u{9ad8}\ + \u{9adf}\ + \u{9b25}\ + \u{9b2f}\ + \u{9b32}\ + \u{9b3c}\ + \u{9b5a}\ + \u{9ce5}\ + \u{9e75}\ + \u{9e7f}\ + \u{9ea5}\ + \u{9ebb}\ + \u{9ec3}\ + \u{9ecd}\ + \u{9ed1}\ + \u{9ef9}\ + \u{9efd}\ + \u{9f0e}\ + \u{9f13}\ + \u{9f20}\ + \u{9f3b}\ + \u{9f4a}\ + \u{9f52}\ + \u{9f8d}\ + \u{9f9c}\ + \u{9fa0}\ + \u{2e}\ + \u{3012}\ + \u{5344}\ + \u{5345}\ + \u{20}\ + \u{3099}\ + \u{20}\ + \u{309a}\ + \u{3088}\ + \u{308a}\ + \u{30b3}\ + \u{30c8}\ + \u{1100}\ + \u{1101}\ + \u{11aa}\ + \u{1102}\ + \u{11ac}\ + \u{11ad}\ + \u{1103}\ + \u{1104}\ + \u{1105}\ + \u{11b0}\ + \u{11b1}\ + \u{11b2}\ + \u{11b3}\ + \u{11b4}\ + \u{11b5}\ + \u{111a}\ + \u{1106}\ + \u{1107}\ + \u{1108}\ + \u{1121}\ + \u{1109}\ + \u{110a}\ + \u{110b}\ + \u{110c}\ + \u{110d}\ + \u{110e}\ + \u{110f}\ + \u{1110}\ + \u{1111}\ + \u{1112}\ + \u{1161}\ + \u{1162}\ + \u{1163}\ + \u{1164}\ + \u{1165}\ + \u{1166}\ + \u{1167}\ + \u{1168}\ + \u{1169}\ + \u{116a}\ + \u{116b}\ + \u{116c}\ + \u{116d}\ + \u{116e}\ + \u{116f}\ + \u{1170}\ + \u{1171}\ + \u{1172}\ + \u{1173}\ + \u{1174}\ + \u{1175}\ + \u{1114}\ + \u{1115}\ + \u{11c7}\ + \u{11c8}\ + \u{11cc}\ + \u{11ce}\ + \u{11d3}\ + \u{11d7}\ + \u{11d9}\ + \u{111c}\ + \u{11dd}\ + \u{11df}\ + \u{111d}\ + \u{111e}\ + \u{1120}\ + \u{1122}\ + \u{1123}\ + \u{1127}\ + \u{1129}\ + \u{112b}\ + \u{112c}\ + \u{112d}\ + \u{112e}\ + \u{112f}\ + \u{1132}\ + \u{1136}\ + \u{1140}\ + \u{1147}\ + \u{114c}\ + \u{11f1}\ + \u{11f2}\ + \u{1157}\ + \u{1158}\ + \u{1159}\ + \u{1184}\ + \u{1185}\ + \u{1188}\ + \u{1191}\ + \u{1192}\ + \u{1194}\ + \u{119e}\ + \u{11a1}\ + \u{4e09}\ + \u{56db}\ + \u{4e0a}\ + \u{4e2d}\ + \u{4e0b}\ + \u{7532}\ + \u{4e19}\ + \u{4e01}\ + \u{5929}\ + \u{5730}\ + \u{28}\ + \u{1100}\ + \u{29}\ + \u{28}\ + \u{1102}\ + \u{29}\ + \u{28}\ + \u{1103}\ + \u{29}\ + \u{28}\ + \u{1105}\ + \u{29}\ + \u{28}\ + \u{1106}\ + \u{29}\ + \u{28}\ + \u{1107}\ + \u{29}\ + \u{28}\ + \u{1109}\ + \u{29}\ + \u{28}\ + \u{110b}\ + \u{29}\ + \u{28}\ + \u{110c}\ + \u{29}\ + \u{28}\ + \u{110e}\ + \u{29}\ + \u{28}\ + \u{110f}\ + \u{29}\ + \u{28}\ + \u{1110}\ + \u{29}\ + \u{28}\ + \u{1111}\ + \u{29}\ + \u{28}\ + \u{1112}\ + \u{29}\ + \u{28}\ + \u{ac00}\ + \u{29}\ + \u{28}\ + \u{b098}\ + \u{29}\ + \u{28}\ + \u{b2e4}\ + \u{29}\ + \u{28}\ + \u{b77c}\ + \u{29}\ + \u{28}\ + \u{b9c8}\ + \u{29}\ + \u{28}\ + \u{bc14}\ + \u{29}\ + \u{28}\ + \u{c0ac}\ + \u{29}\ + \u{28}\ + \u{c544}\ + \u{29}\ + \u{28}\ + \u{c790}\ + \u{29}\ + \u{28}\ + \u{cc28}\ + \u{29}\ + \u{28}\ + \u{ce74}\ + \u{29}\ + \u{28}\ + \u{d0c0}\ + \u{29}\ + \u{28}\ + \u{d30c}\ + \u{29}\ + \u{28}\ + \u{d558}\ + \u{29}\ + \u{28}\ + \u{c8fc}\ + \u{29}\ + \u{28}\ + \u{c624}\ + \u{c804}\ + \u{29}\ + \u{28}\ + \u{c624}\ + \u{d6c4}\ + \u{29}\ + \u{28}\ + \u{4e00}\ + \u{29}\ + \u{28}\ + \u{4e8c}\ + \u{29}\ + \u{28}\ + \u{4e09}\ + \u{29}\ + \u{28}\ + \u{56db}\ + \u{29}\ + \u{28}\ + \u{4e94}\ + \u{29}\ + \u{28}\ + \u{516d}\ + \u{29}\ + \u{28}\ + \u{4e03}\ + \u{29}\ + \u{28}\ + \u{516b}\ + \u{29}\ + \u{28}\ + \u{4e5d}\ + \u{29}\ + \u{28}\ + \u{5341}\ + \u{29}\ + \u{28}\ + \u{6708}\ + \u{29}\ + \u{28}\ + \u{706b}\ + \u{29}\ + \u{28}\ + \u{6c34}\ + \u{29}\ + \u{28}\ + \u{6728}\ + \u{29}\ + \u{28}\ + \u{91d1}\ + \u{29}\ + \u{28}\ + \u{571f}\ + \u{29}\ + \u{28}\ + \u{65e5}\ + \u{29}\ + \u{28}\ + \u{682a}\ + \u{29}\ + \u{28}\ + \u{6709}\ + \u{29}\ + \u{28}\ + \u{793e}\ + \u{29}\ + \u{28}\ + \u{540d}\ + \u{29}\ + \u{28}\ + \u{7279}\ + \u{29}\ + \u{28}\ + \u{8ca1}\ + \u{29}\ + \u{28}\ + \u{795d}\ + \u{29}\ + \u{28}\ + \u{52b4}\ + \u{29}\ + \u{28}\ + \u{4ee3}\ + \u{29}\ + \u{28}\ + \u{547c}\ + \u{29}\ + \u{28}\ + \u{5b66}\ + \u{29}\ + \u{28}\ + \u{76e3}\ + \u{29}\ + \u{28}\ + \u{4f01}\ + \u{29}\ + \u{28}\ + \u{8cc7}\ + \u{29}\ + \u{28}\ + \u{5354}\ + \u{29}\ + \u{28}\ + \u{796d}\ + \u{29}\ + \u{28}\ + \u{4f11}\ + \u{29}\ + \u{28}\ + \u{81ea}\ + \u{29}\ + \u{28}\ + \u{81f3}\ + \u{29}\ + \u{554f}\ + \u{5e7c}\ + \u{7b8f}\ + \u{70}\ + \u{74}\ + \u{65}\ + \u{32}\ + \u{31}\ + \u{32}\ + \u{32}\ + \u{32}\ + \u{33}\ + \u{32}\ + \u{34}\ + \u{32}\ + \u{35}\ + \u{32}\ + \u{36}\ + \u{32}\ + \u{37}\ + \u{32}\ + \u{38}\ + \u{32}\ + \u{39}\ + \u{33}\ + \u{30}\ + \u{33}\ + \u{31}\ + \u{33}\ + \u{32}\ + \u{33}\ + \u{33}\ + \u{33}\ + \u{34}\ + \u{33}\ + \u{35}\ + \u{ac00}\ + \u{b098}\ + \u{b2e4}\ + \u{b77c}\ + \u{b9c8}\ + \u{bc14}\ + \u{c0ac}\ + \u{c544}\ + \u{c790}\ + \u{cc28}\ + \u{ce74}\ + \u{d0c0}\ + \u{d30c}\ + \u{d558}\ + \u{cc38}\ + \u{ace0}\ + \u{c8fc}\ + \u{c758}\ + \u{c6b0}\ + \u{4e94}\ + \u{516d}\ + \u{4e03}\ + \u{4e5d}\ + \u{682a}\ + \u{6709}\ + \u{793e}\ + \u{540d}\ + \u{7279}\ + \u{8ca1}\ + \u{795d}\ + \u{52b4}\ + \u{79d8}\ + \u{7537}\ + \u{9069}\ + \u{512a}\ + \u{5370}\ + \u{6ce8}\ + \u{9805}\ + \u{4f11}\ + \u{5199}\ + \u{6b63}\ + \u{5de6}\ + \u{53f3}\ + \u{533b}\ + \u{5b97}\ + \u{5b66}\ + \u{76e3}\ + \u{4f01}\ + \u{8cc7}\ + \u{5354}\ + \u{591c}\ + \u{33}\ + \u{36}\ + \u{33}\ + \u{37}\ + \u{33}\ + \u{38}\ + \u{33}\ + \u{39}\ + \u{34}\ + \u{30}\ + \u{34}\ + \u{31}\ + \u{34}\ + \u{32}\ + \u{34}\ + \u{33}\ + \u{34}\ + \u{34}\ + \u{34}\ + \u{35}\ + \u{34}\ + \u{36}\ + \u{34}\ + \u{37}\ + \u{34}\ + \u{38}\ + \u{34}\ + \u{39}\ + \u{35}\ + \u{30}\ + \u{31}\ + \u{6708}\ + \u{32}\ + \u{6708}\ + \u{33}\ + \u{6708}\ + \u{34}\ + \u{6708}\ + \u{35}\ + \u{6708}\ + \u{36}\ + \u{6708}\ + \u{37}\ + \u{6708}\ + \u{38}\ + \u{6708}\ + \u{39}\ + \u{6708}\ + \u{31}\ + \u{30}\ + \u{6708}\ + \u{31}\ + \u{31}\ + \u{6708}\ + \u{31}\ + \u{32}\ + \u{6708}\ + \u{68}\ + \u{67}\ + \u{65}\ + \u{72}\ + \u{67}\ + \u{65}\ + \u{76}\ + \u{6c}\ + \u{74}\ + \u{64}\ + \u{30a2}\ + \u{30a4}\ + \u{30a6}\ + \u{30a8}\ + \u{30aa}\ + \u{30ab}\ + \u{30ad}\ + \u{30af}\ + \u{30b1}\ + \u{30b3}\ + \u{30b5}\ + \u{30b7}\ + \u{30b9}\ + \u{30bb}\ + \u{30bd}\ + \u{30bf}\ + \u{30c1}\ + \u{30c4}\ + \u{30c6}\ + \u{30c8}\ + \u{30ca}\ + \u{30cb}\ + \u{30cc}\ + \u{30cd}\ + \u{30ce}\ + \u{30cf}\ + \u{30d2}\ + \u{30d5}\ + \u{30d8}\ + \u{30db}\ + \u{30de}\ + \u{30df}\ + \u{30e0}\ + \u{30e1}\ + \u{30e2}\ + \u{30e4}\ + \u{30e6}\ + \u{30e8}\ + \u{30e9}\ + \u{30ea}\ + \u{30eb}\ + \u{30ec}\ + \u{30ed}\ + \u{30ef}\ + \u{30f0}\ + \u{30f1}\ + \u{30f2}\ + \u{30a2}\ + \u{30d1}\ + \u{30fc}\ + \u{30c8}\ + \u{30a2}\ + \u{30eb}\ + \u{30d5}\ + \u{30a1}\ + \u{30a2}\ + \u{30f3}\ + \u{30da}\ + \u{30a2}\ + \u{30a2}\ + \u{30fc}\ + \u{30eb}\ + \u{30a4}\ + \u{30cb}\ + \u{30f3}\ + \u{30b0}\ + \u{30a4}\ + \u{30f3}\ + \u{30c1}\ + \u{30a6}\ + \u{30a9}\ + \u{30f3}\ + \u{30a8}\ + \u{30b9}\ + \u{30af}\ + \u{30fc}\ + \u{30c9}\ + \u{30a8}\ + \u{30fc}\ + \u{30ab}\ + \u{30fc}\ + \u{30aa}\ + \u{30f3}\ + \u{30b9}\ + \u{30aa}\ + \u{30fc}\ + \u{30e0}\ + \u{30ab}\ + \u{30a4}\ + \u{30ea}\ + \u{30ab}\ + \u{30e9}\ + \u{30c3}\ + \u{30c8}\ + \u{30ab}\ + \u{30ed}\ + \u{30ea}\ + \u{30fc}\ + \u{30ac}\ + \u{30ed}\ + \u{30f3}\ + \u{30ac}\ + \u{30f3}\ + \u{30de}\ + \u{30ae}\ + \u{30ac}\ + \u{30ae}\ + \u{30cb}\ + \u{30fc}\ + \u{30ad}\ + \u{30e5}\ + \u{30ea}\ + \u{30fc}\ + \u{30ae}\ + \u{30eb}\ + \u{30c0}\ + \u{30fc}\ + \u{30ad}\ + \u{30ed}\ + \u{30ad}\ + \u{30ed}\ + \u{30b0}\ + \u{30e9}\ + \u{30e0}\ + \u{30ad}\ + \u{30ed}\ + \u{30e1}\ + \u{30fc}\ + \u{30c8}\ + \u{30eb}\ + \u{30ad}\ + \u{30ed}\ + \u{30ef}\ + \u{30c3}\ + \u{30c8}\ + \u{30b0}\ + \u{30e9}\ + \u{30e0}\ + \u{30b0}\ + \u{30e9}\ + \u{30e0}\ + \u{30c8}\ + \u{30f3}\ + \u{30af}\ + \u{30eb}\ + \u{30bc}\ + \u{30a4}\ + \u{30ed}\ + \u{30af}\ + \u{30ed}\ + \u{30fc}\ + \u{30cd}\ + \u{30b1}\ + \u{30fc}\ + \u{30b9}\ + \u{30b3}\ + \u{30eb}\ + \u{30ca}\ + \u{30b3}\ + \u{30fc}\ + \u{30dd}\ + \u{30b5}\ + \u{30a4}\ + \u{30af}\ + \u{30eb}\ + \u{30b5}\ + \u{30f3}\ + \u{30c1}\ + \u{30fc}\ + \u{30e0}\ + \u{30b7}\ + \u{30ea}\ + \u{30f3}\ + \u{30b0}\ + \u{30bb}\ + \u{30f3}\ + \u{30c1}\ + \u{30bb}\ + \u{30f3}\ + \u{30c8}\ + \u{30c0}\ + \u{30fc}\ + \u{30b9}\ + \u{30c7}\ + \u{30b7}\ + \u{30c9}\ + \u{30eb}\ + \u{30c8}\ + \u{30f3}\ + \u{30ca}\ + \u{30ce}\ + \u{30ce}\ + \u{30c3}\ + \u{30c8}\ + \u{30cf}\ + \u{30a4}\ + \u{30c4}\ + \u{30d1}\ + \u{30fc}\ + \u{30bb}\ + \u{30f3}\ + \u{30c8}\ + \u{30d1}\ + \u{30fc}\ + \u{30c4}\ + \u{30d0}\ + \u{30fc}\ + \u{30ec}\ + \u{30eb}\ + \u{30d4}\ + \u{30a2}\ + \u{30b9}\ + \u{30c8}\ + \u{30eb}\ + \u{30d4}\ + \u{30af}\ + \u{30eb}\ + \u{30d4}\ + \u{30b3}\ + \u{30d3}\ + \u{30eb}\ + \u{30d5}\ + \u{30a1}\ + \u{30e9}\ + \u{30c3}\ + \u{30c9}\ + \u{30d5}\ + \u{30a3}\ + \u{30fc}\ + \u{30c8}\ + \u{30d6}\ + \u{30c3}\ + \u{30b7}\ + \u{30a7}\ + \u{30eb}\ + \u{30d5}\ + \u{30e9}\ + \u{30f3}\ + \u{30d8}\ + \u{30af}\ + \u{30bf}\ + \u{30fc}\ + \u{30eb}\ + \u{30da}\ + \u{30bd}\ + \u{30da}\ + \u{30cb}\ + \u{30d2}\ + \u{30d8}\ + \u{30eb}\ + \u{30c4}\ + \u{30da}\ + \u{30f3}\ + \u{30b9}\ + \u{30da}\ + \u{30fc}\ + \u{30b8}\ + \u{30d9}\ + \u{30fc}\ + \u{30bf}\ + \u{30dd}\ + \u{30a4}\ + \u{30f3}\ + \u{30c8}\ + \u{30dc}\ + \u{30eb}\ + \u{30c8}\ + \u{30db}\ + \u{30f3}\ + \u{30dd}\ + \u{30f3}\ + \u{30c9}\ + \u{30db}\ + \u{30fc}\ + \u{30eb}\ + \u{30db}\ + \u{30fc}\ + \u{30f3}\ + \u{30de}\ + \u{30a4}\ + \u{30af}\ + \u{30ed}\ + \u{30de}\ + \u{30a4}\ + \u{30eb}\ + \u{30de}\ + \u{30c3}\ + \u{30cf}\ + \u{30de}\ + \u{30eb}\ + \u{30af}\ + \u{30de}\ + \u{30f3}\ + \u{30b7}\ + \u{30e7}\ + \u{30f3}\ + \u{30df}\ + \u{30af}\ + \u{30ed}\ + \u{30f3}\ + \u{30df}\ + \u{30ea}\ + \u{30df}\ + \u{30ea}\ + \u{30d0}\ + \u{30fc}\ + \u{30eb}\ + \u{30e1}\ + \u{30ac}\ + \u{30e1}\ + \u{30ac}\ + \u{30c8}\ + \u{30f3}\ + \u{30e1}\ + \u{30fc}\ + \u{30c8}\ + \u{30eb}\ + \u{30e4}\ + \u{30fc}\ + \u{30c9}\ + \u{30e4}\ + \u{30fc}\ + \u{30eb}\ + \u{30e6}\ + \u{30a2}\ + \u{30f3}\ + \u{30ea}\ + \u{30c3}\ + \u{30c8}\ + \u{30eb}\ + \u{30ea}\ + \u{30e9}\ + \u{30eb}\ + \u{30d4}\ + \u{30fc}\ + \u{30eb}\ + \u{30fc}\ + \u{30d6}\ + \u{30eb}\ + \u{30ec}\ + \u{30e0}\ + \u{30ec}\ + \u{30f3}\ + \u{30c8}\ + \u{30b2}\ + \u{30f3}\ + \u{30ef}\ + \u{30c3}\ + \u{30c8}\ + \u{30}\ + \u{70b9}\ + \u{31}\ + \u{70b9}\ + \u{32}\ + \u{70b9}\ + \u{33}\ + \u{70b9}\ + \u{34}\ + \u{70b9}\ + \u{35}\ + \u{70b9}\ + \u{36}\ + \u{70b9}\ + \u{37}\ + \u{70b9}\ + \u{38}\ + \u{70b9}\ + \u{39}\ + \u{70b9}\ + \u{31}\ + \u{30}\ + \u{70b9}\ + \u{31}\ + \u{31}\ + \u{70b9}\ + \u{31}\ + \u{32}\ + \u{70b9}\ + \u{31}\ + \u{33}\ + \u{70b9}\ + \u{31}\ + \u{34}\ + \u{70b9}\ + \u{31}\ + \u{35}\ + \u{70b9}\ + \u{31}\ + \u{36}\ + \u{70b9}\ + \u{31}\ + \u{37}\ + \u{70b9}\ + \u{31}\ + \u{38}\ + \u{70b9}\ + \u{31}\ + \u{39}\ + \u{70b9}\ + \u{32}\ + \u{30}\ + \u{70b9}\ + \u{32}\ + \u{31}\ + \u{70b9}\ + \u{32}\ + \u{32}\ + \u{70b9}\ + \u{32}\ + \u{33}\ + \u{70b9}\ + \u{32}\ + \u{34}\ + \u{70b9}\ + \u{68}\ + \u{70}\ + \u{61}\ + \u{64}\ + \u{61}\ + \u{61}\ + \u{75}\ + \u{62}\ + \u{61}\ + \u{72}\ + \u{6f}\ + \u{76}\ + \u{70}\ + \u{63}\ + \u{64}\ + \u{6d}\ + \u{64}\ + \u{6d}\ + \u{32}\ + \u{64}\ + \u{6d}\ + \u{33}\ + \u{69}\ + \u{75}\ + \u{5e73}\ + \u{6210}\ + \u{662d}\ + \u{548c}\ + \u{5927}\ + \u{6b63}\ + \u{660e}\ + \u{6cbb}\ + \u{682a}\ + \u{5f0f}\ + \u{4f1a}\ + \u{793e}\ + \u{70}\ + \u{61}\ + \u{6e}\ + \u{61}\ + \u{3bc}\ + \u{61}\ + \u{6d}\ + \u{61}\ + \u{6b}\ + \u{61}\ + \u{6b}\ + \u{62}\ + \u{6d}\ + \u{62}\ + \u{67}\ + \u{62}\ + \u{63}\ + \u{61}\ + \u{6c}\ + \u{6b}\ + \u{63}\ + \u{61}\ + \u{6c}\ + \u{70}\ + \u{66}\ + \u{6e}\ + \u{66}\ + \u{3bc}\ + \u{66}\ + \u{3bc}\ + \u{67}\ + \u{6d}\ + \u{67}\ + \u{6b}\ + \u{67}\ + \u{68}\ + \u{7a}\ + \u{6b}\ + \u{68}\ + \u{7a}\ + \u{6d}\ + \u{68}\ + \u{7a}\ + \u{67}\ + \u{68}\ + \u{7a}\ + \u{74}\ + \u{68}\ + \u{7a}\ + \u{3bc}\ + \u{6c}\ + \u{6d}\ + \u{6c}\ + \u{64}\ + \u{6c}\ + \u{6b}\ + \u{6c}\ + \u{66}\ + \u{6d}\ + \u{6e}\ + \u{6d}\ + \u{3bc}\ + \u{6d}\ + \u{6d}\ + \u{6d}\ + \u{63}\ + \u{6d}\ + \u{6b}\ + \u{6d}\ + \u{6d}\ + \u{6d}\ + \u{32}\ + \u{63}\ + \u{6d}\ + \u{32}\ + \u{6d}\ + \u{32}\ + \u{6b}\ + \u{6d}\ + \u{32}\ + \u{6d}\ + \u{6d}\ + \u{33}\ + \u{63}\ + \u{6d}\ + \u{33}\ + \u{6d}\ + \u{33}\ + \u{6b}\ + \u{6d}\ + \u{33}\ + \u{6d}\ + \u{2215}\ + \u{73}\ + \u{6d}\ + \u{2215}\ + \u{73}\ + \u{32}\ + \u{6b}\ + \u{70}\ + \u{61}\ + \u{6d}\ + \u{70}\ + \u{61}\ + \u{67}\ + \u{70}\ + \u{61}\ + \u{72}\ + \u{61}\ + \u{64}\ + \u{72}\ + \u{61}\ + \u{64}\ + \u{2215}\ + \u{73}\ + \u{72}\ + \u{61}\ + \u{64}\ + \u{2215}\ + \u{73}\ + \u{32}\ + \u{70}\ + \u{73}\ + \u{6e}\ + \u{73}\ + \u{3bc}\ + \u{73}\ + \u{6d}\ + \u{73}\ + \u{70}\ + \u{76}\ + \u{6e}\ + \u{76}\ + \u{3bc}\ + \u{76}\ + \u{6d}\ + \u{76}\ + \u{6b}\ + \u{76}\ + \u{70}\ + \u{77}\ + \u{6e}\ + \u{77}\ + \u{3bc}\ + \u{77}\ + \u{6d}\ + \u{77}\ + \u{6b}\ + \u{77}\ + \u{6b}\ + \u{3c9}\ + \u{6d}\ + \u{3c9}\ + \u{62}\ + \u{71}\ + \u{63}\ + \u{63}\ + \u{63}\ + \u{64}\ + \u{63}\ + \u{2215}\ + \u{6b}\ + \u{67}\ + \u{64}\ + \u{62}\ + \u{67}\ + \u{79}\ + \u{68}\ + \u{61}\ + \u{68}\ + \u{70}\ + \u{69}\ + \u{6e}\ + \u{6b}\ + \u{6b}\ + \u{6b}\ + \u{74}\ + \u{6c}\ + \u{6d}\ + \u{6c}\ + \u{6e}\ + \u{6c}\ + \u{6f}\ + \u{67}\ + \u{6c}\ + \u{78}\ + \u{6d}\ + \u{69}\ + \u{6c}\ + \u{6d}\ + \u{6f}\ + \u{6c}\ + \u{70}\ + \u{68}\ + \u{70}\ + \u{70}\ + \u{6d}\ + \u{70}\ + \u{72}\ + \u{73}\ + \u{72}\ + \u{73}\ + \u{76}\ + \u{77}\ + \u{62}\ + \u{76}\ + \u{2215}\ + \u{6d}\ + \u{61}\ + \u{2215}\ + \u{6d}\ + \u{31}\ + \u{65e5}\ + \u{32}\ + \u{65e5}\ + \u{33}\ + \u{65e5}\ + \u{34}\ + \u{65e5}\ + \u{35}\ + \u{65e5}\ + \u{36}\ + \u{65e5}\ + \u{37}\ + \u{65e5}\ + \u{38}\ + \u{65e5}\ + \u{39}\ + \u{65e5}\ + \u{31}\ + \u{30}\ + \u{65e5}\ + \u{31}\ + \u{31}\ + \u{65e5}\ + \u{31}\ + \u{32}\ + \u{65e5}\ + \u{31}\ + \u{33}\ + \u{65e5}\ + \u{31}\ + \u{34}\ + \u{65e5}\ + \u{31}\ + \u{35}\ + \u{65e5}\ + \u{31}\ + \u{36}\ + \u{65e5}\ + \u{31}\ + \u{37}\ + \u{65e5}\ + \u{31}\ + \u{38}\ + \u{65e5}\ + \u{31}\ + \u{39}\ + \u{65e5}\ + \u{32}\ + \u{30}\ + \u{65e5}\ + \u{32}\ + \u{31}\ + \u{65e5}\ + \u{32}\ + \u{32}\ + \u{65e5}\ + \u{32}\ + \u{33}\ + \u{65e5}\ + \u{32}\ + \u{34}\ + \u{65e5}\ + \u{32}\ + \u{35}\ + \u{65e5}\ + \u{32}\ + \u{36}\ + \u{65e5}\ + \u{32}\ + \u{37}\ + \u{65e5}\ + \u{32}\ + \u{38}\ + \u{65e5}\ + \u{32}\ + \u{39}\ + \u{65e5}\ + \u{33}\ + \u{30}\ + \u{65e5}\ + \u{33}\ + \u{31}\ + \u{65e5}\ + \u{67}\ + \u{61}\ + \u{6c}\ + \u{a641}\ + \u{a643}\ + \u{a645}\ + \u{a647}\ + \u{a649}\ + \u{a64d}\ + \u{a64f}\ + \u{a651}\ + \u{a653}\ + \u{a655}\ + \u{a657}\ + \u{a659}\ + \u{a65b}\ + \u{a65d}\ + \u{a65f}\ + \u{a661}\ + \u{a663}\ + \u{a665}\ + \u{a667}\ + \u{a669}\ + \u{a66b}\ + \u{a66d}\ + \u{a681}\ + \u{a683}\ + \u{a685}\ + \u{a687}\ + \u{a689}\ + \u{a68b}\ + \u{a68d}\ + \u{a68f}\ + \u{a691}\ + \u{a693}\ + \u{a695}\ + \u{a697}\ + \u{a699}\ + \u{a69b}\ + \u{a723}\ + \u{a725}\ + \u{a727}\ + \u{a729}\ + \u{a72b}\ + \u{a72d}\ + \u{a72f}\ + \u{a733}\ + \u{a735}\ + \u{a737}\ + \u{a739}\ + \u{a73b}\ + \u{a73d}\ + \u{a73f}\ + \u{a741}\ + \u{a743}\ + \u{a745}\ + \u{a747}\ + \u{a749}\ + \u{a74b}\ + \u{a74d}\ + \u{a74f}\ + \u{a751}\ + \u{a753}\ + \u{a755}\ + \u{a757}\ + \u{a759}\ + \u{a75b}\ + \u{a75d}\ + \u{a75f}\ + \u{a761}\ + \u{a763}\ + \u{a765}\ + \u{a767}\ + \u{a769}\ + \u{a76b}\ + \u{a76d}\ + \u{a76f}\ + \u{a77a}\ + \u{a77c}\ + \u{1d79}\ + \u{a77f}\ + \u{a781}\ + \u{a783}\ + \u{a785}\ + \u{a787}\ + \u{a78c}\ + \u{a791}\ + \u{a793}\ + \u{a797}\ + \u{a799}\ + \u{a79b}\ + \u{a79d}\ + \u{a79f}\ + \u{a7a1}\ + \u{a7a3}\ + \u{a7a5}\ + \u{a7a7}\ + \u{a7a9}\ + \u{26c}\ + \u{29e}\ + \u{287}\ + \u{ab53}\ + \u{a7b5}\ + \u{a7b7}\ + \u{ab37}\ + \u{ab52}\ + \u{13a0}\ + \u{13a1}\ + \u{13a2}\ + \u{13a3}\ + \u{13a4}\ + \u{13a5}\ + \u{13a6}\ + \u{13a7}\ + \u{13a8}\ + \u{13a9}\ + \u{13aa}\ + \u{13ab}\ + \u{13ac}\ + \u{13ad}\ + \u{13ae}\ + \u{13af}\ + \u{13b0}\ + \u{13b1}\ + \u{13b2}\ + \u{13b3}\ + \u{13b4}\ + \u{13b5}\ + \u{13b6}\ + \u{13b7}\ + \u{13b8}\ + \u{13b9}\ + \u{13ba}\ + \u{13bb}\ + \u{13bc}\ + \u{13bd}\ + \u{13be}\ + \u{13bf}\ + \u{13c0}\ + \u{13c1}\ + \u{13c2}\ + \u{13c3}\ + \u{13c4}\ + \u{13c5}\ + \u{13c6}\ + \u{13c7}\ + \u{13c8}\ + \u{13c9}\ + \u{13ca}\ + \u{13cb}\ + \u{13cc}\ + \u{13cd}\ + \u{13ce}\ + \u{13cf}\ + \u{13d0}\ + \u{13d1}\ + \u{13d2}\ + \u{13d3}\ + \u{13d4}\ + \u{13d5}\ + \u{13d6}\ + \u{13d7}\ + \u{13d8}\ + \u{13d9}\ + \u{13da}\ + \u{13db}\ + \u{13dc}\ + \u{13dd}\ + \u{13de}\ + \u{13df}\ + \u{13e0}\ + \u{13e1}\ + \u{13e2}\ + \u{13e3}\ + \u{13e4}\ + \u{13e5}\ + \u{13e6}\ + \u{13e7}\ + \u{13e8}\ + \u{13e9}\ + \u{13ea}\ + \u{13eb}\ + \u{13ec}\ + \u{13ed}\ + \u{13ee}\ + \u{13ef}\ + \u{8c48}\ + \u{66f4}\ + \u{8cc8}\ + \u{6ed1}\ + \u{4e32}\ + \u{53e5}\ + \u{5951}\ + \u{5587}\ + \u{5948}\ + \u{61f6}\ + \u{7669}\ + \u{7f85}\ + \u{863f}\ + \u{87ba}\ + \u{88f8}\ + \u{908f}\ + \u{6a02}\ + \u{6d1b}\ + \u{70d9}\ + \u{73de}\ + \u{843d}\ + \u{916a}\ + \u{99f1}\ + \u{4e82}\ + \u{5375}\ + \u{6b04}\ + \u{721b}\ + \u{862d}\ + \u{9e1e}\ + \u{5d50}\ + \u{6feb}\ + \u{85cd}\ + \u{8964}\ + \u{62c9}\ + \u{81d8}\ + \u{881f}\ + \u{5eca}\ + \u{6717}\ + \u{6d6a}\ + \u{72fc}\ + \u{90ce}\ + \u{4f86}\ + \u{51b7}\ + \u{52de}\ + \u{64c4}\ + \u{6ad3}\ + \u{7210}\ + \u{76e7}\ + \u{8606}\ + \u{865c}\ + \u{8def}\ + \u{9732}\ + \u{9b6f}\ + \u{9dfa}\ + \u{788c}\ + \u{797f}\ + \u{7da0}\ + \u{83c9}\ + \u{9304}\ + \u{8ad6}\ + \u{58df}\ + \u{5f04}\ + \u{7c60}\ + \u{807e}\ + \u{7262}\ + \u{78ca}\ + \u{8cc2}\ + \u{96f7}\ + \u{58d8}\ + \u{5c62}\ + \u{6a13}\ + \u{6dda}\ + \u{6f0f}\ + \u{7d2f}\ + \u{7e37}\ + \u{964b}\ + \u{52d2}\ + \u{808b}\ + \u{51dc}\ + \u{51cc}\ + \u{7a1c}\ + \u{7dbe}\ + \u{83f1}\ + \u{9675}\ + \u{8b80}\ + \u{62cf}\ + \u{8afe}\ + \u{4e39}\ + \u{5be7}\ + \u{6012}\ + \u{7387}\ + \u{7570}\ + \u{5317}\ + \u{78fb}\ + \u{4fbf}\ + \u{5fa9}\ + \u{4e0d}\ + \u{6ccc}\ + \u{6578}\ + \u{7d22}\ + \u{53c3}\ + \u{585e}\ + \u{7701}\ + \u{8449}\ + \u{8aaa}\ + \u{6bba}\ + \u{6c88}\ + \u{62fe}\ + \u{82e5}\ + \u{63a0}\ + \u{7565}\ + \u{4eae}\ + \u{5169}\ + \u{51c9}\ + \u{6881}\ + \u{7ce7}\ + \u{826f}\ + \u{8ad2}\ + \u{91cf}\ + \u{52f5}\ + \u{5442}\ + \u{5eec}\ + \u{65c5}\ + \u{6ffe}\ + \u{792a}\ + \u{95ad}\ + \u{9a6a}\ + \u{9e97}\ + \u{9ece}\ + \u{66c6}\ + \u{6b77}\ + \u{8f62}\ + \u{5e74}\ + \u{6190}\ + \u{6200}\ + \u{649a}\ + \u{6f23}\ + \u{7149}\ + \u{7489}\ + \u{79ca}\ + \u{7df4}\ + \u{806f}\ + \u{8f26}\ + \u{84ee}\ + \u{9023}\ + \u{934a}\ + \u{5217}\ + \u{52a3}\ + \u{54bd}\ + \u{70c8}\ + \u{88c2}\ + \u{5ec9}\ + \u{5ff5}\ + \u{637b}\ + \u{6bae}\ + \u{7c3e}\ + \u{7375}\ + \u{4ee4}\ + \u{56f9}\ + \u{5dba}\ + \u{601c}\ + \u{73b2}\ + \u{7469}\ + \u{7f9a}\ + \u{8046}\ + \u{9234}\ + \u{96f6}\ + \u{9748}\ + \u{9818}\ + \u{4f8b}\ + \u{79ae}\ + \u{91b4}\ + \u{96b8}\ + \u{60e1}\ + \u{4e86}\ + \u{50da}\ + \u{5bee}\ + \u{5c3f}\ + \u{6599}\ + \u{71ce}\ + \u{7642}\ + \u{84fc}\ + \u{907c}\ + \u{6688}\ + \u{962e}\ + \u{5289}\ + \u{677b}\ + \u{67f3}\ + \u{6d41}\ + \u{6e9c}\ + \u{7409}\ + \u{7559}\ + \u{786b}\ + \u{7d10}\ + \u{985e}\ + \u{622e}\ + \u{9678}\ + \u{502b}\ + \u{5d19}\ + \u{6dea}\ + \u{8f2a}\ + \u{5f8b}\ + \u{6144}\ + \u{6817}\ + \u{9686}\ + \u{5229}\ + \u{540f}\ + \u{5c65}\ + \u{6613}\ + \u{674e}\ + \u{68a8}\ + \u{6ce5}\ + \u{7406}\ + \u{75e2}\ + \u{7f79}\ + \u{88cf}\ + \u{88e1}\ + \u{96e2}\ + \u{533f}\ + \u{6eba}\ + \u{541d}\ + \u{71d0}\ + \u{7498}\ + \u{85fa}\ + \u{96a3}\ + \u{9c57}\ + \u{9e9f}\ + \u{6797}\ + \u{6dcb}\ + \u{81e8}\ + \u{7b20}\ + \u{7c92}\ + \u{72c0}\ + \u{7099}\ + \u{8b58}\ + \u{4ec0}\ + \u{8336}\ + \u{523a}\ + \u{5207}\ + \u{5ea6}\ + \u{62d3}\ + \u{7cd6}\ + \u{5b85}\ + \u{6d1e}\ + \u{66b4}\ + \u{8f3b}\ + \u{964d}\ + \u{5ed3}\ + \u{5140}\ + \u{55c0}\ + \u{585a}\ + \u{6674}\ + \u{51de}\ + \u{732a}\ + \u{76ca}\ + \u{793c}\ + \u{795e}\ + \u{7965}\ + \u{798f}\ + \u{9756}\ + \u{7cbe}\ + \u{8612}\ + \u{8af8}\ + \u{9038}\ + \u{90fd}\ + \u{98ef}\ + \u{98fc}\ + \u{9928}\ + \u{9db4}\ + \u{90de}\ + \u{96b7}\ + \u{4fae}\ + \u{50e7}\ + \u{514d}\ + \u{52c9}\ + \u{52e4}\ + \u{5351}\ + \u{559d}\ + \u{5606}\ + \u{5668}\ + \u{5840}\ + \u{58a8}\ + \u{5c64}\ + \u{6094}\ + \u{6168}\ + \u{618e}\ + \u{61f2}\ + \u{654f}\ + \u{65e2}\ + \u{6691}\ + \u{6885}\ + \u{6d77}\ + \u{6e1a}\ + \u{6f22}\ + \u{716e}\ + \u{722b}\ + \u{7422}\ + \u{7891}\ + \u{7949}\ + \u{7948}\ + \u{7950}\ + \u{7956}\ + \u{798d}\ + \u{798e}\ + \u{7a40}\ + \u{7a81}\ + \u{7bc0}\ + \u{7e09}\ + \u{7e41}\ + \u{7f72}\ + \u{8005}\ + \u{81ed}\ + \u{8279}\ + \u{8457}\ + \u{8910}\ + \u{8996}\ + \u{8b01}\ + \u{8b39}\ + \u{8cd3}\ + \u{8d08}\ + \u{8fb6}\ + \u{96e3}\ + \u{97ff}\ + \u{983b}\ + \u{6075}\ + \u{242ee}\ + \u{8218}\ + \u{4e26}\ + \u{51b5}\ + \u{5168}\ + \u{4f80}\ + \u{5145}\ + \u{5180}\ + \u{52c7}\ + \u{52fa}\ + \u{5555}\ + \u{5599}\ + \u{55e2}\ + \u{58b3}\ + \u{5944}\ + \u{5954}\ + \u{5a62}\ + \u{5b28}\ + \u{5ed2}\ + \u{5ed9}\ + \u{5f69}\ + \u{5fad}\ + \u{60d8}\ + \u{614e}\ + \u{6108}\ + \u{6160}\ + \u{6234}\ + \u{63c4}\ + \u{641c}\ + \u{6452}\ + \u{6556}\ + \u{671b}\ + \u{6756}\ + \u{6edb}\ + \u{6ecb}\ + \u{701e}\ + \u{77a7}\ + \u{7235}\ + \u{72af}\ + \u{7471}\ + \u{7506}\ + \u{753b}\ + \u{761d}\ + \u{761f}\ + \u{76db}\ + \u{76f4}\ + \u{774a}\ + \u{7740}\ + \u{78cc}\ + \u{7ab1}\ + \u{7c7b}\ + \u{7d5b}\ + \u{7f3e}\ + \u{8352}\ + \u{83ef}\ + \u{8779}\ + \u{8941}\ + \u{8986}\ + \u{8abf}\ + \u{8acb}\ + \u{8aed}\ + \u{8b8a}\ + \u{8f38}\ + \u{9072}\ + \u{9199}\ + \u{9276}\ + \u{967c}\ + \u{97db}\ + \u{980b}\ + \u{9b12}\ + \u{2284a}\ + \u{22844}\ + \u{233d5}\ + \u{3b9d}\ + \u{4018}\ + \u{4039}\ + \u{25249}\ + \u{25cd0}\ + \u{27ed3}\ + \u{9f43}\ + \u{9f8e}\ + \u{66}\ + \u{66}\ + \u{66}\ + \u{69}\ + \u{66}\ + \u{6c}\ + \u{66}\ + \u{66}\ + \u{69}\ + \u{66}\ + \u{66}\ + \u{6c}\ + \u{73}\ + \u{74}\ + \u{574}\ + \u{576}\ + \u{574}\ + \u{565}\ + \u{574}\ + \u{56b}\ + \u{57e}\ + \u{576}\ + \u{574}\ + \u{56d}\ + \u{5d9}\ + \u{5b4}\ + \u{5f2}\ + \u{5b7}\ + \u{5e2}\ + \u{5d4}\ + \u{5db}\ + \u{5dc}\ + \u{5dd}\ + \u{5e8}\ + \u{5ea}\ + \u{5e9}\ + \u{5c1}\ + \u{5e9}\ + \u{5c2}\ + \u{5e9}\ + \u{5bc}\ + \u{5c1}\ + \u{5e9}\ + \u{5bc}\ + \u{5c2}\ + \u{5d0}\ + \u{5b7}\ + \u{5d0}\ + \u{5b8}\ + \u{5d0}\ + \u{5bc}\ + \u{5d1}\ + \u{5bc}\ + \u{5d2}\ + \u{5bc}\ + \u{5d3}\ + \u{5bc}\ + \u{5d4}\ + \u{5bc}\ + \u{5d5}\ + \u{5bc}\ + \u{5d6}\ + \u{5bc}\ + \u{5d8}\ + \u{5bc}\ + \u{5d9}\ + \u{5bc}\ + \u{5da}\ + \u{5bc}\ + \u{5db}\ + \u{5bc}\ + \u{5dc}\ + \u{5bc}\ + \u{5de}\ + \u{5bc}\ + \u{5e0}\ + \u{5bc}\ + \u{5e1}\ + \u{5bc}\ + \u{5e3}\ + \u{5bc}\ + \u{5e4}\ + \u{5bc}\ + \u{5e6}\ + \u{5bc}\ + \u{5e7}\ + \u{5bc}\ + \u{5e8}\ + \u{5bc}\ + \u{5e9}\ + \u{5bc}\ + \u{5ea}\ + \u{5bc}\ + \u{5d5}\ + \u{5b9}\ + \u{5d1}\ + \u{5bf}\ + \u{5db}\ + \u{5bf}\ + \u{5e4}\ + \u{5bf}\ + \u{5d0}\ + \u{5dc}\ + \u{671}\ + \u{67b}\ + \u{67e}\ + \u{680}\ + \u{67a}\ + \u{67f}\ + \u{679}\ + \u{6a4}\ + \u{6a6}\ + \u{684}\ + \u{683}\ + \u{686}\ + \u{687}\ + \u{68d}\ + \u{68c}\ + \u{68e}\ + \u{688}\ + \u{698}\ + \u{691}\ + \u{6a9}\ + \u{6af}\ + \u{6b3}\ + \u{6b1}\ + \u{6ba}\ + \u{6bb}\ + \u{6c0}\ + \u{6c1}\ + \u{6be}\ + \u{6d2}\ + \u{6d3}\ + \u{6ad}\ + \u{6c7}\ + \u{6c6}\ + \u{6c8}\ + \u{6cb}\ + \u{6c5}\ + \u{6c9}\ + \u{6d0}\ + \u{649}\ + \u{626}\ + \u{627}\ + \u{626}\ + \u{6d5}\ + \u{626}\ + \u{648}\ + \u{626}\ + \u{6c7}\ + \u{626}\ + \u{6c6}\ + \u{626}\ + \u{6c8}\ + \u{626}\ + \u{6d0}\ + \u{626}\ + \u{649}\ + \u{6cc}\ + \u{626}\ + \u{62c}\ + \u{626}\ + \u{62d}\ + \u{626}\ + \u{645}\ + \u{626}\ + \u{64a}\ + \u{628}\ + \u{62c}\ + \u{628}\ + \u{62d}\ + \u{628}\ + \u{62e}\ + \u{628}\ + \u{645}\ + \u{628}\ + \u{649}\ + \u{628}\ + \u{64a}\ + \u{62a}\ + \u{62c}\ + \u{62a}\ + \u{62d}\ + \u{62a}\ + \u{62e}\ + \u{62a}\ + \u{645}\ + \u{62a}\ + \u{649}\ + \u{62a}\ + \u{64a}\ + \u{62b}\ + \u{62c}\ + \u{62b}\ + \u{645}\ + \u{62b}\ + \u{649}\ + \u{62b}\ + \u{64a}\ + \u{62c}\ + \u{62d}\ + \u{62c}\ + \u{645}\ + \u{62d}\ + \u{62c}\ + \u{62d}\ + \u{645}\ + \u{62e}\ + \u{62c}\ + \u{62e}\ + \u{62d}\ + \u{62e}\ + \u{645}\ + \u{633}\ + \u{62c}\ + \u{633}\ + \u{62d}\ + \u{633}\ + \u{62e}\ + \u{633}\ + \u{645}\ + \u{635}\ + \u{62d}\ + \u{635}\ + \u{645}\ + \u{636}\ + \u{62c}\ + \u{636}\ + \u{62d}\ + \u{636}\ + \u{62e}\ + \u{636}\ + \u{645}\ + \u{637}\ + \u{62d}\ + \u{637}\ + \u{645}\ + \u{638}\ + \u{645}\ + \u{639}\ + \u{62c}\ + \u{639}\ + \u{645}\ + \u{63a}\ + \u{62c}\ + \u{63a}\ + \u{645}\ + \u{641}\ + \u{62c}\ + \u{641}\ + \u{62d}\ + \u{641}\ + \u{62e}\ + \u{641}\ + \u{645}\ + \u{641}\ + \u{649}\ + \u{641}\ + \u{64a}\ + \u{642}\ + \u{62d}\ + \u{642}\ + \u{645}\ + \u{642}\ + \u{649}\ + \u{642}\ + \u{64a}\ + \u{643}\ + \u{627}\ + \u{643}\ + \u{62c}\ + \u{643}\ + \u{62d}\ + \u{643}\ + \u{62e}\ + \u{643}\ + \u{644}\ + \u{643}\ + \u{645}\ + \u{643}\ + \u{649}\ + \u{643}\ + \u{64a}\ + \u{644}\ + \u{62c}\ + \u{644}\ + \u{62d}\ + \u{644}\ + \u{62e}\ + \u{644}\ + \u{645}\ + \u{644}\ + \u{649}\ + \u{644}\ + \u{64a}\ + \u{645}\ + \u{62c}\ + \u{645}\ + \u{62d}\ + \u{645}\ + \u{62e}\ + \u{645}\ + \u{645}\ + \u{645}\ + \u{649}\ + \u{645}\ + \u{64a}\ + \u{646}\ + \u{62c}\ + \u{646}\ + \u{62d}\ + \u{646}\ + \u{62e}\ + \u{646}\ + \u{645}\ + \u{646}\ + \u{649}\ + \u{646}\ + \u{64a}\ + \u{647}\ + \u{62c}\ + \u{647}\ + \u{645}\ + \u{647}\ + \u{649}\ + \u{647}\ + \u{64a}\ + \u{64a}\ + \u{62c}\ + \u{64a}\ + \u{62d}\ + \u{64a}\ + \u{62e}\ + \u{64a}\ + \u{645}\ + \u{64a}\ + \u{649}\ + \u{64a}\ + \u{64a}\ + \u{630}\ + \u{670}\ + \u{631}\ + \u{670}\ + \u{649}\ + \u{670}\ + \u{20}\ + \u{64c}\ + \u{651}\ + \u{20}\ + \u{64d}\ + \u{651}\ + \u{20}\ + \u{64e}\ + \u{651}\ + \u{20}\ + \u{64f}\ + \u{651}\ + \u{20}\ + \u{650}\ + \u{651}\ + \u{20}\ + \u{651}\ + \u{670}\ + \u{626}\ + \u{631}\ + \u{626}\ + \u{632}\ + \u{626}\ + \u{646}\ + \u{628}\ + \u{631}\ + \u{628}\ + \u{632}\ + \u{628}\ + \u{646}\ + \u{62a}\ + \u{631}\ + \u{62a}\ + \u{632}\ + \u{62a}\ + \u{646}\ + \u{62b}\ + \u{631}\ + \u{62b}\ + \u{632}\ + \u{62b}\ + \u{646}\ + \u{645}\ + \u{627}\ + \u{646}\ + \u{631}\ + \u{646}\ + \u{632}\ + \u{646}\ + \u{646}\ + \u{64a}\ + \u{631}\ + \u{64a}\ + \u{632}\ + \u{64a}\ + \u{646}\ + \u{626}\ + \u{62e}\ + \u{626}\ + \u{647}\ + \u{628}\ + \u{647}\ + \u{62a}\ + \u{647}\ + \u{635}\ + \u{62e}\ + \u{644}\ + \u{647}\ + \u{646}\ + \u{647}\ + \u{647}\ + \u{670}\ + \u{64a}\ + \u{647}\ + \u{62b}\ + \u{647}\ + \u{633}\ + \u{647}\ + \u{634}\ + \u{645}\ + \u{634}\ + \u{647}\ + \u{640}\ + \u{64e}\ + \u{651}\ + \u{640}\ + \u{64f}\ + \u{651}\ + \u{640}\ + \u{650}\ + \u{651}\ + \u{637}\ + \u{649}\ + \u{637}\ + \u{64a}\ + \u{639}\ + \u{649}\ + \u{639}\ + \u{64a}\ + \u{63a}\ + \u{649}\ + \u{63a}\ + \u{64a}\ + \u{633}\ + \u{649}\ + \u{633}\ + \u{64a}\ + \u{634}\ + \u{649}\ + \u{634}\ + \u{64a}\ + \u{62d}\ + \u{649}\ + \u{62d}\ + \u{64a}\ + \u{62c}\ + \u{649}\ + \u{62c}\ + \u{64a}\ + \u{62e}\ + \u{649}\ + \u{62e}\ + \u{64a}\ + \u{635}\ + \u{649}\ + \u{635}\ + \u{64a}\ + \u{636}\ + \u{649}\ + \u{636}\ + \u{64a}\ + \u{634}\ + \u{62c}\ + \u{634}\ + \u{62d}\ + \u{634}\ + \u{62e}\ + \u{634}\ + \u{631}\ + \u{633}\ + \u{631}\ + \u{635}\ + \u{631}\ + \u{636}\ + \u{631}\ + \u{627}\ + \u{64b}\ + \u{62a}\ + \u{62c}\ + \u{645}\ + \u{62a}\ + \u{62d}\ + \u{62c}\ + \u{62a}\ + \u{62d}\ + \u{645}\ + \u{62a}\ + \u{62e}\ + \u{645}\ + \u{62a}\ + \u{645}\ + \u{62c}\ + \u{62a}\ + \u{645}\ + \u{62d}\ + \u{62a}\ + \u{645}\ + \u{62e}\ + \u{62c}\ + \u{645}\ + \u{62d}\ + \u{62d}\ + \u{645}\ + \u{64a}\ + \u{62d}\ + \u{645}\ + \u{649}\ + \u{633}\ + \u{62d}\ + \u{62c}\ + \u{633}\ + \u{62c}\ + \u{62d}\ + \u{633}\ + \u{62c}\ + \u{649}\ + \u{633}\ + \u{645}\ + \u{62d}\ + \u{633}\ + \u{645}\ + \u{62c}\ + \u{633}\ + \u{645}\ + \u{645}\ + \u{635}\ + \u{62d}\ + \u{62d}\ + \u{635}\ + \u{645}\ + \u{645}\ + \u{634}\ + \u{62d}\ + \u{645}\ + \u{634}\ + \u{62c}\ + \u{64a}\ + \u{634}\ + \u{645}\ + \u{62e}\ + \u{634}\ + \u{645}\ + \u{645}\ + \u{636}\ + \u{62d}\ + \u{649}\ + \u{636}\ + \u{62e}\ + \u{645}\ + \u{637}\ + \u{645}\ + \u{62d}\ + \u{637}\ + \u{645}\ + \u{645}\ + \u{637}\ + \u{645}\ + \u{64a}\ + \u{639}\ + \u{62c}\ + \u{645}\ + \u{639}\ + \u{645}\ + \u{645}\ + \u{639}\ + \u{645}\ + \u{649}\ + \u{63a}\ + \u{645}\ + \u{645}\ + \u{63a}\ + \u{645}\ + \u{64a}\ + \u{63a}\ + \u{645}\ + \u{649}\ + \u{641}\ + \u{62e}\ + \u{645}\ + \u{642}\ + \u{645}\ + \u{62d}\ + \u{642}\ + \u{645}\ + \u{645}\ + \u{644}\ + \u{62d}\ + \u{645}\ + \u{644}\ + \u{62d}\ + \u{64a}\ + \u{644}\ + \u{62d}\ + \u{649}\ + \u{644}\ + \u{62c}\ + \u{62c}\ + \u{644}\ + \u{62e}\ + \u{645}\ + \u{644}\ + \u{645}\ + \u{62d}\ + \u{645}\ + \u{62d}\ + \u{62c}\ + \u{645}\ + \u{62d}\ + \u{645}\ + \u{645}\ + \u{62d}\ + \u{64a}\ + \u{645}\ + \u{62c}\ + \u{62d}\ + \u{645}\ + \u{62c}\ + \u{645}\ + \u{645}\ + \u{62e}\ + \u{62c}\ + \u{645}\ + \u{62e}\ + \u{645}\ + \u{645}\ + \u{62c}\ + \u{62e}\ + \u{647}\ + \u{645}\ + \u{62c}\ + \u{647}\ + \u{645}\ + \u{645}\ + \u{646}\ + \u{62d}\ + \u{645}\ + \u{646}\ + \u{62d}\ + \u{649}\ + \u{646}\ + \u{62c}\ + \u{645}\ + \u{646}\ + \u{62c}\ + \u{649}\ + \u{646}\ + \u{645}\ + \u{64a}\ + \u{646}\ + \u{645}\ + \u{649}\ + \u{64a}\ + \u{645}\ + \u{645}\ + \u{628}\ + \u{62e}\ + \u{64a}\ + \u{62a}\ + \u{62c}\ + \u{64a}\ + \u{62a}\ + \u{62c}\ + \u{649}\ + \u{62a}\ + \u{62e}\ + \u{64a}\ + \u{62a}\ + \u{62e}\ + \u{649}\ + \u{62a}\ + \u{645}\ + \u{64a}\ + \u{62a}\ + \u{645}\ + \u{649}\ + \u{62c}\ + \u{645}\ + \u{64a}\ + \u{62c}\ + \u{62d}\ + \u{649}\ + \u{62c}\ + \u{645}\ + \u{649}\ + \u{633}\ + \u{62e}\ + \u{649}\ + \u{635}\ + \u{62d}\ + \u{64a}\ + \u{634}\ + \u{62d}\ + \u{64a}\ + \u{636}\ + \u{62d}\ + \u{64a}\ + \u{644}\ + \u{62c}\ + \u{64a}\ + \u{644}\ + \u{645}\ + \u{64a}\ + \u{64a}\ + \u{62d}\ + \u{64a}\ + \u{64a}\ + \u{62c}\ + \u{64a}\ + \u{64a}\ + \u{645}\ + \u{64a}\ + \u{645}\ + \u{645}\ + \u{64a}\ + \u{642}\ + \u{645}\ + \u{64a}\ + \u{646}\ + \u{62d}\ + \u{64a}\ + \u{639}\ + \u{645}\ + \u{64a}\ + \u{643}\ + \u{645}\ + \u{64a}\ + \u{646}\ + \u{62c}\ + \u{62d}\ + \u{645}\ + \u{62e}\ + \u{64a}\ + \u{644}\ + \u{62c}\ + \u{645}\ + \u{643}\ + \u{645}\ + \u{645}\ + \u{62c}\ + \u{62d}\ + \u{64a}\ + \u{62d}\ + \u{62c}\ + \u{64a}\ + \u{645}\ + \u{62c}\ + \u{64a}\ + \u{641}\ + \u{645}\ + \u{64a}\ + \u{628}\ + \u{62d}\ + \u{64a}\ + \u{633}\ + \u{62e}\ + \u{64a}\ + \u{646}\ + \u{62c}\ + \u{64a}\ + \u{635}\ + \u{644}\ + \u{6d2}\ + \u{642}\ + \u{644}\ + \u{6d2}\ + \u{627}\ + \u{644}\ + \u{644}\ + \u{647}\ + \u{627}\ + \u{643}\ + \u{628}\ + \u{631}\ + \u{645}\ + \u{62d}\ + \u{645}\ + \u{62f}\ + \u{635}\ + \u{644}\ + \u{639}\ + \u{645}\ + \u{631}\ + \u{633}\ + \u{648}\ + \u{644}\ + \u{639}\ + \u{644}\ + \u{64a}\ + \u{647}\ + \u{648}\ + \u{633}\ + \u{644}\ + \u{645}\ + \u{635}\ + \u{644}\ + \u{649}\ + \u{635}\ + \u{644}\ + \u{649}\ + \u{20}\ + \u{627}\ + \u{644}\ + \u{644}\ + \u{647}\ + \u{20}\ + \u{639}\ + \u{644}\ + \u{64a}\ + \u{647}\ + \u{20}\ + \u{648}\ + \u{633}\ + \u{644}\ + \u{645}\ + \u{62c}\ + \u{644}\ + \u{20}\ + \u{62c}\ + \u{644}\ + \u{627}\ + \u{644}\ + \u{647}\ + \u{631}\ + \u{6cc}\ + \u{627}\ + \u{644}\ + \u{2c}\ + \u{3001}\ + \u{3a}\ + \u{21}\ + \u{3f}\ + \u{3016}\ + \u{3017}\ + \u{2014}\ + \u{2013}\ + \u{5f}\ + \u{7b}\ + \u{7d}\ + \u{3014}\ + \u{3015}\ + \u{3010}\ + \u{3011}\ + \u{300a}\ + \u{300b}\ + \u{300c}\ + \u{300d}\ + \u{300e}\ + \u{300f}\ + \u{5b}\ + \u{5d}\ + \u{23}\ + \u{26}\ + \u{2a}\ + \u{2d}\ + \u{3c}\ + \u{3e}\ + \u{5c}\ + \u{24}\ + \u{25}\ + \u{40}\ + \u{20}\ + \u{64b}\ + \u{640}\ + \u{64b}\ + \u{20}\ + \u{64c}\ + \u{20}\ + \u{64d}\ + \u{20}\ + \u{64e}\ + \u{640}\ + \u{64e}\ + \u{20}\ + \u{64f}\ + \u{640}\ + \u{64f}\ + \u{20}\ + \u{650}\ + \u{640}\ + \u{650}\ + \u{20}\ + \u{651}\ + \u{640}\ + \u{651}\ + \u{20}\ + \u{652}\ + \u{640}\ + \u{652}\ + \u{621}\ + \u{622}\ + \u{623}\ + \u{624}\ + \u{625}\ + \u{626}\ + \u{627}\ + \u{628}\ + \u{629}\ + \u{62a}\ + \u{62b}\ + \u{62c}\ + \u{62d}\ + \u{62e}\ + \u{62f}\ + \u{630}\ + \u{631}\ + \u{632}\ + \u{633}\ + \u{634}\ + \u{635}\ + \u{636}\ + \u{637}\ + \u{638}\ + \u{639}\ + \u{63a}\ + \u{641}\ + \u{642}\ + \u{643}\ + \u{644}\ + \u{645}\ + \u{646}\ + \u{647}\ + \u{648}\ + \u{64a}\ + \u{644}\ + \u{622}\ + \u{644}\ + \u{623}\ + \u{644}\ + \u{625}\ + \u{644}\ + \u{627}\ + \u{22}\ + \u{27}\ + \u{2f}\ + \u{5e}\ + \u{7c}\ + \u{7e}\ + \u{2985}\ + \u{2986}\ + \u{30fb}\ + \u{30a1}\ + \u{30a3}\ + \u{30a5}\ + \u{30a7}\ + \u{30a9}\ + \u{30e3}\ + \u{30e5}\ + \u{30e7}\ + \u{30c3}\ + \u{30fc}\ + \u{30f3}\ + \u{3099}\ + \u{309a}\ + \u{a2}\ + \u{a3}\ + \u{ac}\ + \u{a6}\ + \u{a5}\ + \u{20a9}\ + \u{2502}\ + \u{2190}\ + \u{2191}\ + \u{2192}\ + \u{2193}\ + \u{25a0}\ + \u{25cb}\ + \u{10428}\ + \u{10429}\ + \u{1042a}\ + \u{1042b}\ + \u{1042c}\ + \u{1042d}\ + \u{1042e}\ + \u{1042f}\ + \u{10430}\ + \u{10431}\ + \u{10432}\ + \u{10433}\ + \u{10434}\ + \u{10435}\ + \u{10436}\ + \u{10437}\ + \u{10438}\ + \u{10439}\ + \u{1043a}\ + \u{1043b}\ + \u{1043c}\ + \u{1043d}\ + \u{1043e}\ + \u{1043f}\ + \u{10440}\ + \u{10441}\ + \u{10442}\ + \u{10443}\ + \u{10444}\ + \u{10445}\ + \u{10446}\ + \u{10447}\ + \u{10448}\ + \u{10449}\ + \u{1044a}\ + \u{1044b}\ + \u{1044c}\ + \u{1044d}\ + \u{1044e}\ + \u{1044f}\ + \u{104d8}\ + \u{104d9}\ + \u{104da}\ + \u{104db}\ + \u{104dc}\ + \u{104dd}\ + \u{104de}\ + \u{104df}\ + \u{104e0}\ + \u{104e1}\ + \u{104e2}\ + \u{104e3}\ + \u{104e4}\ + \u{104e5}\ + \u{104e6}\ + \u{104e7}\ + \u{104e8}\ + \u{104e9}\ + \u{104ea}\ + \u{104eb}\ + \u{104ec}\ + \u{104ed}\ + \u{104ee}\ + \u{104ef}\ + \u{104f0}\ + \u{104f1}\ + \u{104f2}\ + \u{104f3}\ + \u{104f4}\ + \u{104f5}\ + \u{104f6}\ + \u{104f7}\ + \u{104f8}\ + \u{104f9}\ + \u{104fa}\ + \u{104fb}\ + \u{10cc0}\ + \u{10cc1}\ + \u{10cc2}\ + \u{10cc3}\ + \u{10cc4}\ + \u{10cc5}\ + \u{10cc6}\ + \u{10cc7}\ + \u{10cc8}\ + \u{10cc9}\ + \u{10cca}\ + \u{10ccb}\ + \u{10ccc}\ + \u{10ccd}\ + \u{10cce}\ + \u{10ccf}\ + \u{10cd0}\ + \u{10cd1}\ + \u{10cd2}\ + \u{10cd3}\ + \u{10cd4}\ + \u{10cd5}\ + \u{10cd6}\ + \u{10cd7}\ + \u{10cd8}\ + \u{10cd9}\ + \u{10cda}\ + \u{10cdb}\ + \u{10cdc}\ + \u{10cdd}\ + \u{10cde}\ + \u{10cdf}\ + \u{10ce0}\ + \u{10ce1}\ + \u{10ce2}\ + \u{10ce3}\ + \u{10ce4}\ + \u{10ce5}\ + \u{10ce6}\ + \u{10ce7}\ + \u{10ce8}\ + \u{10ce9}\ + \u{10cea}\ + \u{10ceb}\ + \u{10cec}\ + \u{10ced}\ + \u{10cee}\ + \u{10cef}\ + \u{10cf0}\ + \u{10cf1}\ + \u{10cf2}\ + \u{118c0}\ + \u{118c1}\ + \u{118c2}\ + \u{118c3}\ + \u{118c4}\ + \u{118c5}\ + \u{118c6}\ + \u{118c7}\ + \u{118c8}\ + \u{118c9}\ + \u{118ca}\ + \u{118cb}\ + \u{118cc}\ + \u{118cd}\ + \u{118ce}\ + \u{118cf}\ + \u{118d0}\ + \u{118d1}\ + \u{118d2}\ + \u{118d3}\ + \u{118d4}\ + \u{118d5}\ + \u{118d6}\ + \u{118d7}\ + \u{118d8}\ + \u{118d9}\ + \u{118da}\ + \u{118db}\ + \u{118dc}\ + \u{118dd}\ + \u{118de}\ + \u{118df}\ + \u{1d157}\ + \u{1d165}\ + \u{1d158}\ + \u{1d165}\ + \u{1d158}\ + \u{1d165}\ + \u{1d16e}\ + \u{1d158}\ + \u{1d165}\ + \u{1d16f}\ + \u{1d158}\ + \u{1d165}\ + \u{1d170}\ + \u{1d158}\ + \u{1d165}\ + \u{1d171}\ + \u{1d158}\ + \u{1d165}\ + \u{1d172}\ + \u{1d1b9}\ + \u{1d165}\ + \u{1d1ba}\ + \u{1d165}\ + \u{1d1b9}\ + \u{1d165}\ + \u{1d16e}\ + \u{1d1ba}\ + \u{1d165}\ + \u{1d16e}\ + \u{1d1b9}\ + \u{1d165}\ + \u{1d16f}\ + \u{1d1ba}\ + \u{1d165}\ + \u{1d16f}\ + \u{131}\ + \u{237}\ + \u{2207}\ + \u{2202}\ + \u{1e922}\ + \u{1e923}\ + \u{1e924}\ + \u{1e925}\ + \u{1e926}\ + \u{1e927}\ + \u{1e928}\ + \u{1e929}\ + \u{1e92a}\ + \u{1e92b}\ + \u{1e92c}\ + \u{1e92d}\ + \u{1e92e}\ + \u{1e92f}\ + \u{1e930}\ + \u{1e931}\ + \u{1e932}\ + \u{1e933}\ + \u{1e934}\ + \u{1e935}\ + \u{1e936}\ + \u{1e937}\ + \u{1e938}\ + \u{1e939}\ + \u{1e93a}\ + \u{1e93b}\ + \u{1e93c}\ + \u{1e93d}\ + \u{1e93e}\ + \u{1e93f}\ + \u{1e940}\ + \u{1e941}\ + \u{1e942}\ + \u{1e943}\ + \u{66e}\ + \u{6a1}\ + \u{66f}\ + \u{30}\ + \u{2c}\ + \u{31}\ + \u{2c}\ + \u{32}\ + \u{2c}\ + \u{33}\ + \u{2c}\ + \u{34}\ + \u{2c}\ + \u{35}\ + \u{2c}\ + \u{36}\ + \u{2c}\ + \u{37}\ + \u{2c}\ + \u{38}\ + \u{2c}\ + \u{39}\ + \u{2c}\ + \u{3014}\ + \u{73}\ + \u{3015}\ + \u{77}\ + \u{7a}\ + \u{68}\ + \u{76}\ + \u{73}\ + \u{64}\ + \u{70}\ + \u{70}\ + \u{76}\ + \u{77}\ + \u{63}\ + \u{6d}\ + \u{63}\ + \u{6d}\ + \u{64}\ + \u{64}\ + \u{6a}\ + \u{307b}\ + \u{304b}\ + \u{30b3}\ + \u{30b3}\ + \u{5b57}\ + \u{53cc}\ + \u{30c7}\ + \u{591a}\ + \u{89e3}\ + \u{4ea4}\ + \u{6620}\ + \u{7121}\ + \u{524d}\ + \u{5f8c}\ + \u{518d}\ + \u{65b0}\ + \u{521d}\ + \u{7d42}\ + \u{8ca9}\ + \u{58f0}\ + \u{5439}\ + \u{6f14}\ + \u{6295}\ + \u{6355}\ + \u{904a}\ + \u{6307}\ + \u{6253}\ + \u{7981}\ + \u{7a7a}\ + \u{5408}\ + \u{6e80}\ + \u{7533}\ + \u{5272}\ + \u{55b6}\ + \u{914d}\ + \u{3014}\ + \u{672c}\ + \u{3015}\ + \u{3014}\ + \u{4e09}\ + \u{3015}\ + \u{3014}\ + \u{4e8c}\ + \u{3015}\ + \u{3014}\ + \u{5b89}\ + \u{3015}\ + \u{3014}\ + \u{70b9}\ + \u{3015}\ + \u{3014}\ + \u{6253}\ + \u{3015}\ + \u{3014}\ + \u{76d7}\ + \u{3015}\ + \u{3014}\ + \u{52dd}\ + \u{3015}\ + \u{3014}\ + \u{6557}\ + \u{3015}\ + \u{5f97}\ + \u{53ef}\ + \u{4e3d}\ + \u{4e38}\ + \u{4e41}\ + \u{20122}\ + \u{4f60}\ + \u{4fbb}\ + \u{5002}\ + \u{507a}\ + \u{5099}\ + \u{50cf}\ + \u{349e}\ + \u{2063a}\ + \u{5154}\ + \u{5164}\ + \u{5177}\ + \u{2051c}\ + \u{34b9}\ + \u{5167}\ + \u{2054b}\ + \u{5197}\ + \u{51a4}\ + \u{4ecc}\ + \u{51ac}\ + \u{291df}\ + \u{5203}\ + \u{34df}\ + \u{523b}\ + \u{5246}\ + \u{5277}\ + \u{3515}\ + \u{5305}\ + \u{5306}\ + \u{5349}\ + \u{535a}\ + \u{5373}\ + \u{537d}\ + \u{537f}\ + \u{20a2c}\ + \u{7070}\ + \u{53ca}\ + \u{53df}\ + \u{20b63}\ + \u{53eb}\ + \u{53f1}\ + \u{5406}\ + \u{549e}\ + \u{5438}\ + \u{5448}\ + \u{5468}\ + \u{54a2}\ + \u{54f6}\ + \u{5510}\ + \u{5553}\ + \u{5563}\ + \u{5584}\ + \u{55ab}\ + \u{55b3}\ + \u{55c2}\ + \u{5716}\ + \u{5717}\ + \u{5651}\ + \u{5674}\ + \u{58ee}\ + \u{57ce}\ + \u{57f4}\ + \u{580d}\ + \u{578b}\ + \u{5832}\ + \u{5831}\ + \u{58ac}\ + \u{214e4}\ + \u{58f2}\ + \u{58f7}\ + \u{5906}\ + \u{5922}\ + \u{5962}\ + \u{216a8}\ + \u{216ea}\ + \u{59ec}\ + \u{5a1b}\ + \u{5a27}\ + \u{59d8}\ + \u{5a66}\ + \u{36ee}\ + \u{5b08}\ + \u{5b3e}\ + \u{219c8}\ + \u{5bc3}\ + \u{5bd8}\ + \u{5bf3}\ + \u{21b18}\ + \u{5bff}\ + \u{5c06}\ + \u{3781}\ + \u{5c60}\ + \u{5cc0}\ + \u{5c8d}\ + \u{21de4}\ + \u{5d43}\ + \u{21de6}\ + \u{5d6e}\ + \u{5d6b}\ + \u{5d7c}\ + \u{5de1}\ + \u{5de2}\ + \u{382f}\ + \u{5dfd}\ + \u{5e28}\ + \u{5e3d}\ + \u{5e69}\ + \u{3862}\ + \u{22183}\ + \u{387c}\ + \u{5eb0}\ + \u{5eb3}\ + \u{5eb6}\ + \u{2a392}\ + \u{22331}\ + \u{8201}\ + \u{5f22}\ + \u{38c7}\ + \u{232b8}\ + \u{261da}\ + \u{5f62}\ + \u{5f6b}\ + \u{38e3}\ + \u{5f9a}\ + \u{5fcd}\ + \u{5fd7}\ + \u{5ff9}\ + \u{6081}\ + \u{393a}\ + \u{391c}\ + \u{226d4}\ + \u{60c7}\ + \u{6148}\ + \u{614c}\ + \u{617a}\ + \u{61b2}\ + \u{61a4}\ + \u{61af}\ + \u{61de}\ + \u{6210}\ + \u{621b}\ + \u{625d}\ + \u{62b1}\ + \u{62d4}\ + \u{6350}\ + \u{22b0c}\ + \u{633d}\ + \u{62fc}\ + \u{6368}\ + \u{6383}\ + \u{63e4}\ + \u{22bf1}\ + \u{6422}\ + \u{63c5}\ + \u{63a9}\ + \u{3a2e}\ + \u{6469}\ + \u{647e}\ + \u{649d}\ + \u{6477}\ + \u{3a6c}\ + \u{656c}\ + \u{2300a}\ + \u{65e3}\ + \u{66f8}\ + \u{6649}\ + \u{3b19}\ + \u{3b08}\ + \u{3ae4}\ + \u{5192}\ + \u{5195}\ + \u{6700}\ + \u{669c}\ + \u{80ad}\ + \u{43d9}\ + \u{6721}\ + \u{675e}\ + \u{6753}\ + \u{233c3}\ + \u{3b49}\ + \u{67fa}\ + \u{6785}\ + \u{6852}\ + \u{2346d}\ + \u{688e}\ + \u{681f}\ + \u{6914}\ + \u{6942}\ + \u{69a3}\ + \u{69ea}\ + \u{6aa8}\ + \u{236a3}\ + \u{6adb}\ + \u{3c18}\ + \u{6b21}\ + \u{238a7}\ + \u{6b54}\ + \u{3c4e}\ + \u{6b72}\ + \u{6b9f}\ + \u{6bbb}\ + \u{23a8d}\ + \u{21d0b}\ + \u{23afa}\ + \u{6c4e}\ + \u{23cbc}\ + \u{6cbf}\ + \u{6ccd}\ + \u{6c67}\ + \u{6d16}\ + \u{6d3e}\ + \u{6d69}\ + \u{6d78}\ + \u{6d85}\ + \u{23d1e}\ + \u{6d34}\ + \u{6e2f}\ + \u{6e6e}\ + \u{3d33}\ + \u{6ec7}\ + \u{23ed1}\ + \u{6df9}\ + \u{6f6e}\ + \u{23f5e}\ + \u{23f8e}\ + \u{6fc6}\ + \u{7039}\ + \u{701b}\ + \u{3d96}\ + \u{704a}\ + \u{707d}\ + \u{7077}\ + \u{70ad}\ + \u{20525}\ + \u{7145}\ + \u{24263}\ + \u{719c}\ + \u{7228}\ + \u{7250}\ + \u{24608}\ + \u{7280}\ + \u{7295}\ + \u{24735}\ + \u{24814}\ + \u{737a}\ + \u{738b}\ + \u{3eac}\ + \u{73a5}\ + \u{3eb8}\ + \u{7447}\ + \u{745c}\ + \u{7485}\ + \u{74ca}\ + \u{3f1b}\ + \u{7524}\ + \u{24c36}\ + \u{753e}\ + \u{24c92}\ + \u{2219f}\ + \u{7610}\ + \u{24fa1}\ + \u{24fb8}\ + \u{25044}\ + \u{3ffc}\ + \u{4008}\ + \u{250f3}\ + \u{250f2}\ + \u{25119}\ + \u{25133}\ + \u{771e}\ + \u{771f}\ + \u{778b}\ + \u{4046}\ + \u{4096}\ + \u{2541d}\ + \u{784e}\ + \u{40e3}\ + \u{25626}\ + \u{2569a}\ + \u{256c5}\ + \u{79eb}\ + \u{412f}\ + \u{7a4a}\ + \u{7a4f}\ + \u{2597c}\ + \u{25aa7}\ + \u{4202}\ + \u{25bab}\ + \u{7bc6}\ + \u{7bc9}\ + \u{4227}\ + \u{25c80}\ + \u{7cd2}\ + \u{42a0}\ + \u{7ce8}\ + \u{7ce3}\ + \u{7d00}\ + \u{25f86}\ + \u{7d63}\ + \u{4301}\ + \u{7dc7}\ + \u{7e02}\ + \u{7e45}\ + \u{4334}\ + \u{26228}\ + \u{26247}\ + \u{4359}\ + \u{262d9}\ + \u{7f7a}\ + \u{2633e}\ + \u{7f95}\ + \u{7ffa}\ + \u{264da}\ + \u{26523}\ + \u{8060}\ + \u{265a8}\ + \u{8070}\ + \u{2335f}\ + \u{43d5}\ + \u{80b2}\ + \u{8103}\ + \u{440b}\ + \u{813e}\ + \u{5ab5}\ + \u{267a7}\ + \u{267b5}\ + \u{23393}\ + \u{2339c}\ + \u{8204}\ + \u{8f9e}\ + \u{446b}\ + \u{8291}\ + \u{828b}\ + \u{829d}\ + \u{52b3}\ + \u{82b1}\ + \u{82b3}\ + \u{82bd}\ + \u{82e6}\ + \u{26b3c}\ + \u{831d}\ + \u{8363}\ + \u{83ad}\ + \u{8323}\ + \u{83bd}\ + \u{83e7}\ + \u{8353}\ + \u{83ca}\ + \u{83cc}\ + \u{83dc}\ + \u{26c36}\ + \u{26d6b}\ + \u{26cd5}\ + \u{452b}\ + \u{84f1}\ + \u{84f3}\ + \u{8516}\ + \u{273ca}\ + \u{8564}\ + \u{26f2c}\ + \u{455d}\ + \u{4561}\ + \u{26fb1}\ + \u{270d2}\ + \u{456b}\ + \u{8650}\ + \u{8667}\ + \u{8669}\ + \u{86a9}\ + \u{8688}\ + \u{870e}\ + \u{86e2}\ + \u{8728}\ + \u{876b}\ + \u{8786}\ + \u{87e1}\ + \u{8801}\ + \u{45f9}\ + \u{8860}\ + \u{27667}\ + \u{88d7}\ + \u{88de}\ + \u{4635}\ + \u{88fa}\ + \u{34bb}\ + \u{278ae}\ + \u{27966}\ + \u{46be}\ + \u{46c7}\ + \u{8aa0}\ + \u{27ca8}\ + \u{8cab}\ + \u{8cc1}\ + \u{8d1b}\ + \u{8d77}\ + \u{27f2f}\ + \u{20804}\ + \u{8dcb}\ + \u{8dbc}\ + \u{8df0}\ + \u{208de}\ + \u{8ed4}\ + \u{285d2}\ + \u{285ed}\ + \u{9094}\ + \u{90f1}\ + \u{9111}\ + \u{2872e}\ + \u{911b}\ + \u{9238}\ + \u{92d7}\ + \u{92d8}\ + \u{927c}\ + \u{93f9}\ + \u{9415}\ + \u{28bfa}\ + \u{958b}\ + \u{4995}\ + \u{95b7}\ + \u{28d77}\ + \u{49e6}\ + \u{96c3}\ + \u{5db2}\ + \u{9723}\ + \u{29145}\ + \u{2921a}\ + \u{4a6e}\ + \u{4a76}\ + \u{97e0}\ + \u{2940a}\ + \u{4ab2}\ + \u{29496}\ + \u{9829}\ + \u{295b6}\ + \u{98e2}\ + \u{4b33}\ + \u{9929}\ + \u{99a7}\ + \u{99c2}\ + \u{99fe}\ + \u{4bce}\ + \u{29b30}\ + \u{9c40}\ + \u{9cfd}\ + \u{4cce}\ + \u{4ced}\ + \u{9d67}\ + \u{2a0ce}\ + \u{4cf8}\ + \u{2a105}\ + \u{2a20e}\ + \u{2a291}\ + \u{4d56}\ + \u{9efe}\ + \u{9f05}\ + \u{9f0f}\ + \u{9f16}\ + \u{2a600}"; diff --git a/idna/tests/IdnaTest.txt b/idna/tests/IdnaTest.txt new file mode 100644 index 000000000..123a1f061 --- /dev/null +++ b/idna/tests/IdnaTest.txt @@ -0,0 +1,7848 @@ +# IdnaTest.txt +# Date: 2017-06-02, 14:19:52 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Contains test cases for verifying UTS46 conformance. For more information, +# see http://www.unicode.org/reports/tr46/ +# +# FORMAT: +# +# This file is in UTF8, with certain characters escaped using the \uXXXX or \x{XXXX} +# convention where they could otherwise have a confusing display. +# These characters include: +# +# - General Categories C, Z, and M +# - Default ignorable characters +# - Bidi categories R, AL, AN +# +# Columns (c1, c2,...) are separated by semicolons. +# Leading and trailing spaces and tabs in each column are ignored. +# Comments are indicated with hash marks. +# +# Column 1: type - T for transitional, N for nontransitional, B for both +# Column 2: source - The source string to be tested +# Column 3: toUnicode - The result of applying toUnicode to the source, using nontransitional. +# A blank value means the same as the source value; a value in [...] is a set of error codes. +# Column 4: toASCII - The result of applying toASCII to the source, using the specified type: T, N, or B. +# A blank value means the same as the toUnicode value; a value in [...] is a set of error codes. +# Column 5: idna2008 - NV8 is only present if the status is valid but the character is excluded by IDNA2008 +# from all domain names for all versions of Unicode. +# XV8 is present when the character is excluded by IDNA2008 for the current version of Unicode. +# These are informative values only. +# +# If the value of toUnicode is the same as source, the column will be blank. +# The line comments currently show visible characters that have been escaped +# (after removing default-ignorables and controls, except for whitespace) +# +# The test is performed with the following flag settings: +# +# VerifyDnsLength: true +# CheckHyphens: true +# CheckBidi: true +# CheckJoiners: true +# UseSTD3ASCIIRules: true +# +# An error in toUnicode or toASCII is indicated by a value in square brackets, such as "[B5 B6]". +# In such a case, the contents is a list of error codes based on the step numbers in UTS46 and IDNA2008, +# with the following formats: +# +# Pn for Section 4 Processing step n +# Vn for 4.1 Validity Criteria step n +# An for 4.2 ToASCII step n +# Bn for Bidi (in IDNA2008) +# Cn for ContextJ (in IDNA2008) +# +# However, these particular error codes are only informative; +# the important feature is whether or not there is an error. +# +# CONFORMANCE: +# +# To test for conformance to UTS46, an implementation must first perform the toUnicode operation +# on the source string, then the toASCII operation (with the indicated type) on the source string. +# Implementations may be more strict than UTS46; thus they may have errors where the file indicates results. +# In particular, an implementation conformant to IDNA2008 would disallow the input for lines marked with NV8. +# +# Moreover, the error codes in the file are informative; implementations need only record that there is an error: +# they need not reproduce those codes. Thus to then verify conformance for the toASCII and toUnicode columns: +# +# - If the file indicates an error, the implementation must also have an error. +# - If the file does not indicate an error, then the implementation must either have an error, +# or must have a matching result. +# +# ==================================================================================================== +B; fass.de; ; +T; faß.de; ; fass.de +N; faß.de; ; xn--fa-hia.de +T; Faß.de; faß.de; fass.de +N; Faß.de; faß.de; xn--fa-hia.de +B; xn--fa-hia.de; faß.de; xn--fa-hia.de + +# BIDI TESTS + +B; à\u05D0; [B5 B6]; [B5 B6] # àא +B; a\u0300\u05D0; [B5 B6]; [B5 B6] # àא +B; A\u0300\u05D0; [B5 B6]; [B5 B6] # àא +B; À\u05D0; [B5 B6]; [B5 B6] # àא +B; xn--0ca24w; [B5 B6]; [B5 B6] # àא +B; 0à.\u05D0; [B1]; [B1] # 0à.א +B; 0a\u0300.\u05D0; [B1]; [B1] # 0à.א +B; 0A\u0300.\u05D0; [B1]; [B1] # 0à.א +B; 0À.\u05D0; [B1]; [B1] # 0à.א +B; xn--0-sfa.xn--4db; [B1]; [B1] # 0à.א +B; à.\u05D0\u0308; ; xn--0ca.xn--ssa73l # à.א̈ +B; a\u0300.\u05D0\u0308; à.\u05D0\u0308; xn--0ca.xn--ssa73l # à.א̈ +B; A\u0300.\u05D0\u0308; à.\u05D0\u0308; xn--0ca.xn--ssa73l # à.א̈ +B; À.\u05D0\u0308; à.\u05D0\u0308; xn--0ca.xn--ssa73l # à.א̈ +B; xn--0ca.xn--ssa73l; à.\u05D0\u0308; xn--0ca.xn--ssa73l # à.א̈ +B; à.\u05D00\u0660\u05D0; [B4]; [B4] # à.א0٠א +B; a\u0300.\u05D00\u0660\u05D0; [B4]; [B4] # à.א0٠א +B; A\u0300.\u05D00\u0660\u05D0; [B4]; [B4] # à.א0٠א +B; À.\u05D00\u0660\u05D0; [B4]; [B4] # à.א0٠א +B; xn--0ca.xn--0-zhcb98c; [B4]; [B4] # à.א0٠א +B; \u0308.\u05D0; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ̈.א +B; xn--ssa.xn--4db; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ̈.א +B; à.\u05D00\u0660; [B4]; [B4] # à.א0٠ +B; a\u0300.\u05D00\u0660; [B4]; [B4] # à.א0٠ +B; A\u0300.\u05D00\u0660; [B4]; [B4] # à.א0٠ +B; À.\u05D00\u0660; [B4]; [B4] # à.א0٠ +B; xn--0ca.xn--0-zhc74b; [B4]; [B4] # à.א0٠ +B; àˇ.\u05D0; [B6]; [B6] # àˇ.א +B; a\u0300ˇ.\u05D0; [B6]; [B6] # àˇ.א +B; A\u0300ˇ.\u05D0; [B6]; [B6] # àˇ.א +B; Àˇ.\u05D0; [B6]; [B6] # àˇ.א +B; xn--0ca88g.xn--4db; [B6]; [B6] # àˇ.א +B; à\u0308.\u05D0; ; xn--0ca81i.xn--4db # à̈.א +B; a\u0300\u0308.\u05D0; à\u0308.\u05D0; xn--0ca81i.xn--4db # à̈.א +B; A\u0300\u0308.\u05D0; à\u0308.\u05D0; xn--0ca81i.xn--4db # à̈.א +B; À\u0308.\u05D0; à\u0308.\u05D0; xn--0ca81i.xn--4db # à̈.א +B; xn--0ca81i.xn--4db; à\u0308.\u05D0; xn--0ca81i.xn--4db # à̈.א + +# CONTEXT TESTS + +T; a\u200Cb; [C1]; ab # ab +N; a\u200Cb; [C1]; [C1] # ab +T; A\u200CB; [C1]; ab # ab +N; A\u200CB; [C1]; [C1] # ab +T; A\u200Cb; [C1]; ab # ab +N; A\u200Cb; [C1]; [C1] # ab +B; ab; ; +B; xn--ab-j1t; [C1]; [C1] # ab +T; a\u094D\u200Cb; ; xn--ab-fsf # a्b +N; a\u094D\u200Cb; ; xn--ab-fsf604u # a्b +T; A\u094D\u200CB; a\u094D\u200Cb; xn--ab-fsf # a्b +N; A\u094D\u200CB; a\u094D\u200Cb; xn--ab-fsf604u # a्b +T; A\u094D\u200Cb; a\u094D\u200Cb; xn--ab-fsf # a्b +N; A\u094D\u200Cb; a\u094D\u200Cb; xn--ab-fsf604u # a्b +B; xn--ab-fsf; a\u094Db; xn--ab-fsf # a्b +B; a\u094Db; ; xn--ab-fsf # a्b +B; A\u094DB; a\u094Db; xn--ab-fsf # a्b +B; A\u094Db; a\u094Db; xn--ab-fsf # a्b +B; xn--ab-fsf604u; a\u094D\u200Cb; xn--ab-fsf604u # a्b +T; \u0308\u200C\u0308\u0628b; [B1 C1 V5]; [B1 V5] # ̈̈بb +N; \u0308\u200C\u0308\u0628b; [B1 C1 V5]; [B1 C1 V5] # ̈̈بb +T; \u0308\u200C\u0308\u0628B; [B1 C1 V5]; [B1 V5] # ̈̈بb +N; \u0308\u200C\u0308\u0628B; [B1 C1 V5]; [B1 C1 V5] # ̈̈بb +B; xn--b-bcba413a; [B1 V5]; [B1 V5] # ̈̈بb +B; xn--b-bcba413a2w8b; [B1 C1 V5]; [B1 C1 V5] # ̈̈بb +T; a\u0628\u0308\u200C\u0308; [B5 B6 C1]; [B5 B6] # aب̈̈ +N; a\u0628\u0308\u200C\u0308; [B5 B6 C1]; [B5 B6 C1] # aب̈̈ +T; A\u0628\u0308\u200C\u0308; [B5 B6 C1]; [B5 B6] # aب̈̈ +N; A\u0628\u0308\u200C\u0308; [B5 B6 C1]; [B5 B6 C1] # aب̈̈ +B; xn--a-ccba213a; [B5 B6]; [B5 B6] # aب̈̈ +B; xn--a-ccba213a5w8b; [B5 B6 C1]; [B5 B6 C1] # aب̈̈ +T; a\u0628\u0308\u200C\u0308\u0628b; [B5]; [B5] # aب̈̈بb +N; a\u0628\u0308\u200C\u0308\u0628b; [B5]; [B5] # aب̈̈بb +T; A\u0628\u0308\u200C\u0308\u0628B; [B5]; [B5] # aب̈̈بb +N; A\u0628\u0308\u200C\u0308\u0628B; [B5]; [B5] # aب̈̈بb +T; A\u0628\u0308\u200C\u0308\u0628b; [B5]; [B5] # aب̈̈بb +N; A\u0628\u0308\u200C\u0308\u0628b; [B5]; [B5] # aب̈̈بb +B; xn--ab-uuba211bca; [B5]; [B5] # aب̈̈بb +B; xn--ab-uuba211bca8057b; [B5]; [B5] # aب̈̈بb +T; a\u200Db; [C2]; ab # ab +N; a\u200Db; [C2]; [C2] # ab +T; A\u200DB; [C2]; ab # ab +N; A\u200DB; [C2]; [C2] # ab +T; A\u200Db; [C2]; ab # ab +N; A\u200Db; [C2]; [C2] # ab +B; xn--ab-m1t; [C2]; [C2] # ab +T; a\u094D\u200Db; ; xn--ab-fsf # a्b +N; a\u094D\u200Db; ; xn--ab-fsf014u # a्b +T; A\u094D\u200DB; a\u094D\u200Db; xn--ab-fsf # a्b +N; A\u094D\u200DB; a\u094D\u200Db; xn--ab-fsf014u # a्b +T; A\u094D\u200Db; a\u094D\u200Db; xn--ab-fsf # a्b +N; A\u094D\u200Db; a\u094D\u200Db; xn--ab-fsf014u # a्b +B; xn--ab-fsf014u; a\u094D\u200Db; xn--ab-fsf014u # a्b +T; \u0308\u200D\u0308\u0628b; [B1 C2 V5]; [B1 V5] # ̈̈بb +N; \u0308\u200D\u0308\u0628b; [B1 C2 V5]; [B1 C2 V5] # ̈̈بb +T; \u0308\u200D\u0308\u0628B; [B1 C2 V5]; [B1 V5] # ̈̈بb +N; \u0308\u200D\u0308\u0628B; [B1 C2 V5]; [B1 C2 V5] # ̈̈بb +B; xn--b-bcba413a7w8b; [B1 C2 V5]; [B1 C2 V5] # ̈̈بb +T; a\u0628\u0308\u200D\u0308; [B5 B6 C2]; [B5 B6] # aب̈̈ +N; a\u0628\u0308\u200D\u0308; [B5 B6 C2]; [B5 B6 C2] # aب̈̈ +T; A\u0628\u0308\u200D\u0308; [B5 B6 C2]; [B5 B6] # aب̈̈ +N; A\u0628\u0308\u200D\u0308; [B5 B6 C2]; [B5 B6 C2] # aب̈̈ +B; xn--a-ccba213abx8b; [B5 B6 C2]; [B5 B6 C2] # aب̈̈ +T; a\u0628\u0308\u200D\u0308\u0628b; [B5 C2]; [B5] # aب̈̈بb +N; a\u0628\u0308\u200D\u0308\u0628b; [B5 C2]; [B5 C2] # aب̈̈بb +T; A\u0628\u0308\u200D\u0308\u0628B; [B5 C2]; [B5] # aب̈̈بb +N; A\u0628\u0308\u200D\u0308\u0628B; [B5 C2]; [B5 C2] # aب̈̈بb +T; A\u0628\u0308\u200D\u0308\u0628b; [B5 C2]; [B5] # aب̈̈بb +N; A\u0628\u0308\u200D\u0308\u0628b; [B5 C2]; [B5 C2] # aب̈̈بb +B; xn--ab-uuba211bca5157b; [B5 C2]; [B5 C2] # aب̈̈بb + +# SELECTED TESTS + +B; ¡; ; xn--7a; NV8 +B; xn--7a; ¡; xn--7a; NV8 +B; ᧚; ; xn--pkf; XV8 +B; xn--pkf; ᧚; xn--pkf; XV8 +B; 。; [A4_2]; [A4_2] +B; .; [A4_2]; [A4_2] +B; ꭠ; ; xn--3y9a +B; xn--3y9a; ꭠ; xn--3y9a +B; 1234567890ä1234567890123456789012345678901234567890123456; ; [A4_2] +B; 1234567890a\u03081234567890123456789012345678901234567890123456; 1234567890ä1234567890123456789012345678901234567890123456; [A4_2] +B; 1234567890A\u03081234567890123456789012345678901234567890123456; 1234567890ä1234567890123456789012345678901234567890123456; [A4_2] +B; 1234567890Ä1234567890123456789012345678901234567890123456; 1234567890ä1234567890123456789012345678901234567890123456; [A4_2] +B; xn--12345678901234567890123456789012345678901234567890123456-fxe; 1234567890ä1234567890123456789012345678901234567890123456; [A4_2] +B; www.eXample.cOm; www.example.com; +B; Bücher.de; bücher.de; xn--bcher-kva.de +B; Bu\u0308cher.de; bücher.de; xn--bcher-kva.de +B; bu\u0308cher.de; bücher.de; xn--bcher-kva.de +B; bücher.de; ; xn--bcher-kva.de +B; BÜCHER.DE; bücher.de; xn--bcher-kva.de +B; BU\u0308CHER.DE; bücher.de; xn--bcher-kva.de +B; xn--bcher-kva.de; bücher.de; xn--bcher-kva.de +B; ÖBB; öbb; xn--bb-eka +B; O\u0308BB; öbb; xn--bb-eka +B; o\u0308bb; öbb; xn--bb-eka +B; öbb; ; xn--bb-eka +B; Öbb; öbb; xn--bb-eka +B; O\u0308bb; öbb; xn--bb-eka +B; xn--bb-eka; öbb; xn--bb-eka +T; βόλος.com; ; xn--nxasmq6b.com +N; βόλος.com; ; xn--nxasmm1c.com +T; βο\u0301λος.com; βόλος.com; xn--nxasmq6b.com +N; βο\u0301λος.com; βόλος.com; xn--nxasmm1c.com +B; ΒΟ\u0301ΛΟΣ.COM; βόλοσ.com; xn--nxasmq6b.com +B; ΒΌΛΟΣ.COM; βόλοσ.com; xn--nxasmq6b.com +B; βόλοσ.com; ; xn--nxasmq6b.com +B; βο\u0301λοσ.com; βόλοσ.com; xn--nxasmq6b.com +B; Βο\u0301λοσ.com; βόλοσ.com; xn--nxasmq6b.com +B; Βόλοσ.com; βόλοσ.com; xn--nxasmq6b.com +B; xn--nxasmq6b.com; βόλοσ.com; xn--nxasmq6b.com +T; Βο\u0301λος.com; βόλος.com; xn--nxasmq6b.com +N; Βο\u0301λος.com; βόλος.com; xn--nxasmm1c.com +T; Βόλος.com; βόλος.com; xn--nxasmq6b.com +N; Βόλος.com; βόλος.com; xn--nxasmm1c.com +B; xn--nxasmm1c.com; βόλος.com; xn--nxasmm1c.com +B; xn--nxasmm1c; βόλος; xn--nxasmm1c +T; βόλος; ; xn--nxasmq6b +N; βόλος; ; xn--nxasmm1c +T; βο\u0301λος; βόλος; xn--nxasmq6b +N; βο\u0301λος; βόλος; xn--nxasmm1c +B; ΒΟ\u0301ΛΟΣ; βόλοσ; xn--nxasmq6b +B; ΒΌΛΟΣ; βόλοσ; xn--nxasmq6b +B; βόλοσ; ; xn--nxasmq6b +B; βο\u0301λοσ; βόλοσ; xn--nxasmq6b +B; Βο\u0301λοσ; βόλοσ; xn--nxasmq6b +B; Βόλοσ; βόλοσ; xn--nxasmq6b +B; xn--nxasmq6b; βόλοσ; xn--nxasmq6b +T; Βόλος; βόλος; xn--nxasmq6b +N; Βόλος; βόλος; xn--nxasmm1c +T; Βο\u0301λος; βόλος; xn--nxasmq6b +N; Βο\u0301λος; βόλος; xn--nxasmm1c +T; www.ශ\u0DCA\u200Dර\u0DD3.com; ; www.xn--10cl1a0b.com # www.ශ්රී.com +N; www.ශ\u0DCA\u200Dර\u0DD3.com; ; www.xn--10cl1a0b660p.com # www.ශ්රී.com +T; WWW.ශ\u0DCA\u200Dර\u0DD3.COM; www.ශ\u0DCA\u200Dර\u0DD3.com; www.xn--10cl1a0b.com # www.ශ්රී.com +N; WWW.ශ\u0DCA\u200Dර\u0DD3.COM; www.ශ\u0DCA\u200Dර\u0DD3.com; www.xn--10cl1a0b660p.com # www.ශ්රී.com +T; Www.ශ\u0DCA\u200Dර\u0DD3.com; www.ශ\u0DCA\u200Dර\u0DD3.com; www.xn--10cl1a0b.com # www.ශ්රී.com +N; Www.ශ\u0DCA\u200Dර\u0DD3.com; www.ශ\u0DCA\u200Dර\u0DD3.com; www.xn--10cl1a0b660p.com # www.ශ්රී.com +B; www.xn--10cl1a0b.com; www.ශ\u0DCAර\u0DD3.com; www.xn--10cl1a0b.com # www.ශ්රී.com +B; www.ශ\u0DCAර\u0DD3.com; ; www.xn--10cl1a0b.com # www.ශ්රී.com +B; WWW.ශ\u0DCAර\u0DD3.COM; www.ශ\u0DCAර\u0DD3.com; www.xn--10cl1a0b.com # www.ශ්රී.com +B; Www.ශ\u0DCAර\u0DD3.com; www.ශ\u0DCAර\u0DD3.com; www.xn--10cl1a0b.com # www.ශ්රී.com +B; www.xn--10cl1a0b660p.com; www.ශ\u0DCA\u200Dර\u0DD3.com; www.xn--10cl1a0b660p.com # www.ශ්රී.com +T; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC; ; xn--mgba3gch31f # نامهای +N; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC; ; xn--mgba3gch31f060k # نامهای +B; xn--mgba3gch31f; \u0646\u0627\u0645\u0647\u0627\u06CC; xn--mgba3gch31f # نامهای +B; \u0646\u0627\u0645\u0647\u0627\u06CC; ; xn--mgba3gch31f # نامهای +B; xn--mgba3gch31f060k; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC; xn--mgba3gch31f060k # نامهای +B; xn--mgba3gch31f060k.com; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; xn--mgba3gch31f060k.com # نامهای.com +T; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; ; xn--mgba3gch31f.com # نامهای.com +N; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; ; xn--mgba3gch31f060k.com # نامهای.com +T; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.COM; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; xn--mgba3gch31f.com # نامهای.com +N; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.COM; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; xn--mgba3gch31f060k.com # نامهای.com +T; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.Com; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; xn--mgba3gch31f.com # نامهای.com +N; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.Com; \u0646\u0627\u0645\u0647\u200C\u0627\u06CC.com; xn--mgba3gch31f060k.com # نامهای.com +B; xn--mgba3gch31f.com; \u0646\u0627\u0645\u0647\u0627\u06CC.com; xn--mgba3gch31f.com # نامهای.com +B; \u0646\u0627\u0645\u0647\u0627\u06CC.com; ; xn--mgba3gch31f.com # نامهای.com +B; \u0646\u0627\u0645\u0647\u0627\u06CC.COM; \u0646\u0627\u0645\u0647\u0627\u06CC.com; xn--mgba3gch31f.com # نامهای.com +B; \u0646\u0627\u0645\u0647\u0627\u06CC.Com; \u0646\u0627\u0645\u0647\u0627\u06CC.com; xn--mgba3gch31f.com # نامهای.com +B; a.b.c。d。; a.b.c.d.; +B; a.b.c。d。; a.b.c.d.; +B; A.B.C。D。; a.b.c.d.; +B; A.b.c。D。; a.b.c.d.; +B; a.b.c.d.; ; +B; A.B.C。D。; a.b.c.d.; +B; A.b.c。D。; a.b.c.d.; +B; U\u0308.xn--tda; ü.ü; xn--tda.xn--tda +B; Ü.xn--tda; ü.ü; xn--tda.xn--tda +B; ü.xn--tda; ü.ü; xn--tda.xn--tda +B; u\u0308.xn--tda; ü.ü; xn--tda.xn--tda +B; U\u0308.XN--TDA; ü.ü; xn--tda.xn--tda +B; Ü.XN--TDA; ü.ü; xn--tda.xn--tda +B; Ü.xn--Tda; ü.ü; xn--tda.xn--tda +B; U\u0308.xn--Tda; ü.ü; xn--tda.xn--tda +B; xn--tda.xn--tda; ü.ü; xn--tda.xn--tda +B; ü.ü; ; xn--tda.xn--tda +B; u\u0308.u\u0308; ü.ü; xn--tda.xn--tda +B; U\u0308.U\u0308; ü.ü; xn--tda.xn--tda +B; Ü.Ü; ü.ü; xn--tda.xn--tda +B; Ü.ü; ü.ü; xn--tda.xn--tda +B; U\u0308.u\u0308; ü.ü; xn--tda.xn--tda +B; xn--u-ccb; [V1]; [V1] # ü +B; a⒈com; [P1 V6]; [P1 V6] +B; a1.com; ; +B; A⒈COM; [P1 V6]; [P1 V6] +B; A⒈Com; [P1 V6]; [P1 V6] +B; xn--acom-0w1b; [V6]; [V6] +B; xn--a-ecp.ru; [V6]; [V6] +B; xn--0.pt; [A3]; [A3] +B; xn--a.pt; [V6]; [V6] # .pt +B; xn--a-Ä.pt; [A3]; [A3] +B; xn--a-A\u0308.pt; [A3]; [A3] +B; xn--a-a\u0308.pt; [A3]; [A3] +B; xn--a-ä.pt; [A3]; [A3] +B; XN--A-Ä.PT; [A3]; [A3] +B; XN--A-A\u0308.PT; [A3]; [A3] +B; Xn--A-A\u0308.pt; [A3]; [A3] +B; Xn--A-Ä.pt; [A3]; [A3] +B; xn--xn--a--gua.pt; [V2]; [V2] +B; 日本語。JP; 日本語.jp; xn--wgv71a119e.jp +B; 日本語。JP; 日本語.jp; xn--wgv71a119e.jp +B; 日本語。jp; 日本語.jp; xn--wgv71a119e.jp +B; 日本語。Jp; 日本語.jp; xn--wgv71a119e.jp +B; xn--wgv71a119e.jp; 日本語.jp; xn--wgv71a119e.jp +B; 日本語.jp; ; xn--wgv71a119e.jp +B; 日本語.JP; 日本語.jp; xn--wgv71a119e.jp +B; 日本語.Jp; 日本語.jp; xn--wgv71a119e.jp +B; 日本語。jp; 日本語.jp; xn--wgv71a119e.jp +B; 日本語。Jp; 日本語.jp; xn--wgv71a119e.jp +B; ☕; ; xn--53h; NV8 +B; xn--53h; ☕; xn--53h; NV8 +T; 1.aß\u200C\u200Db\u200C\u200Dcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß\u0302ßz; [C1 C2]; [A4_2] # 1.aßbcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß̂ßz +N; 1.aß\u200C\u200Db\u200C\u200Dcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß\u0302ßz; [C1 C2]; [C1 C2 A4_2] # 1.aßbcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß̂ßz +T; 1.ASS\u200C\u200DB\u200C\u200DCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSS\u0302SSZ; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.ASS\u200C\u200DB\u200C\u200DCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSS\u0302SSZ; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.ASS\u200C\u200DB\u200C\u200DCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSŜSSZ; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.ASS\u200C\u200DB\u200C\u200DCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSŜSSZ; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.Ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.Ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.Ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [C1 C2]; [A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +N; 1.Ass\u200C\u200Db\u200C\u200Dcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +B; 1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; ; [A4_2] +B; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.ASSBCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSS\u0302SSZ; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.ASSBCSSSSSSSSDΣΣSSSSSSSSSSSSSSSSESSSSSSSSSSSSSSSSSSSSXSSSSSSSSSSSSSSSSSSSSYSSSSSSSSSSSSSSSŜSSZ; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.Assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.Assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssyssssssssssssssss\u0302ssz; 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz; [A4_2] +B; 1.xn--assbcssssssssdssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssssz-pxq1419aa69989dba9gc; [C1 C2]; [C1 C2 A4_2] # 1.assbcssssssssdσσssssssssssssssssessssssssssssssssssssxssssssssssssssssssssysssssssssssssssŝssz +T; 1.Aß\u200C\u200Db\u200C\u200Dcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß\u0302ßz; [C1 C2]; [A4_2] # 1.aßbcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß̂ßz +N; 1.Aß\u200C\u200Db\u200C\u200Dcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß\u0302ßz; [C1 C2]; [C1 C2 A4_2] # 1.aßbcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß̂ßz +B; 1.xn--abcdexyz-qyacaaabaaaaaaabaaaaaaaaabaaaaaaaaabaaaaaaaa010ze2isb1140zba8cc; [C1 C2]; [C1 C2 A4_2] # 1.aßbcßßßßdςσßßßßßßßßeßßßßßßßßßßxßßßßßßßßßßyßßßßßßßß̂ßz +T; \u200Cx\u200Dn\u200C-\u200D-bß; [C1 C2]; xn--bss # xn--bß +N; \u200Cx\u200Dn\u200C-\u200D-bß; [C1 C2]; [C1 C2] # xn--bß +T; \u200CX\u200DN\u200C-\u200D-BSS; [C1 C2]; xn--bss # xn--bss +N; \u200CX\u200DN\u200C-\u200D-BSS; [C1 C2]; [C1 C2] # xn--bss +T; \u200Cx\u200Dn\u200C-\u200D-bss; [C1 C2]; xn--bss # xn--bss +N; \u200Cx\u200Dn\u200C-\u200D-bss; [C1 C2]; [C1 C2] # xn--bss +T; \u200CX\u200Dn\u200C-\u200D-Bss; [C1 C2]; xn--bss # xn--bss +N; \u200CX\u200Dn\u200C-\u200D-Bss; [C1 C2]; [C1 C2] # xn--bss +B; xn--bss; 夙; xn--bss +B; 夙; ; xn--bss +B; xn--xn--bss-7z6ccid; [C1 C2]; [C1 C2] # xn--bss +T; \u200CX\u200Dn\u200C-\u200D-Bß; [C1 C2]; xn--bss # xn--bß +N; \u200CX\u200Dn\u200C-\u200D-Bß; [C1 C2]; [C1 C2] # xn--bß +B; xn--xn--b-pqa5796ccahd; [C1 C2]; [C1 C2] # xn--bß +B; ˣ\u034Fℕ\u200B﹣\u00AD-\u180Cℬ\uFE00ſ\u2064𝔰󠇯ffl; 夡夞夜夙; xn--bssffl +B; x\u034FN\u200B-\u00AD-\u180CB\uFE00s\u2064s󠇯ffl; 夡夞夜夙; xn--bssffl +B; x\u034Fn\u200B-\u00AD-\u180Cb\uFE00s\u2064s󠇯ffl; 夡夞夜夙; xn--bssffl +B; X\u034FN\u200B-\u00AD-\u180CB\uFE00S\u2064S󠇯FFL; 夡夞夜夙; xn--bssffl +B; X\u034Fn\u200B-\u00AD-\u180CB\uFE00s\u2064s󠇯ffl; 夡夞夜夙; xn--bssffl +B; xn--bssffl; 夡夞夜夙; xn--bssffl +B; 夡夞夜夙; ; xn--bssffl +B; ˣ\u034Fℕ\u200B﹣\u00AD-\u180Cℬ\uFE00S\u2064𝔰󠇯FFL; 夡夞夜夙; xn--bssffl +B; x\u034FN\u200B-\u00AD-\u180CB\uFE00S\u2064s󠇯FFL; 夡夞夜夙; xn--bssffl +B; ˣ\u034Fℕ\u200B﹣\u00AD-\u180Cℬ\uFE00s\u2064𝔰󠇯ffl; 夡夞夜夙; xn--bssffl +B; 123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; ; +B; 123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; ; +B; 123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; ; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; ; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; ; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901234.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; ; [A4_1 A4_2] +B; ä1234567890123456789012345678901234567890123456789012345; ; xn--1234567890123456789012345678901234567890123456789012345-9te +B; a\u03081234567890123456789012345678901234567890123456789012345; ä1234567890123456789012345678901234567890123456789012345; xn--1234567890123456789012345678901234567890123456789012345-9te +B; A\u03081234567890123456789012345678901234567890123456789012345; ä1234567890123456789012345678901234567890123456789012345; xn--1234567890123456789012345678901234567890123456789012345-9te +B; Ä1234567890123456789012345678901234567890123456789012345; ä1234567890123456789012345678901234567890123456789012345; xn--1234567890123456789012345678901234567890123456789012345-9te +B; xn--1234567890123456789012345678901234567890123456789012345-9te; ä1234567890123456789012345678901234567890123456789012345; xn--1234567890123456789012345678901234567890123456789012345-9te +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; ; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901 +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901 +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901 +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901 +B; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901 +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; ; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901. +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901. +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901. +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901. +B; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901. +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; ; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u0308123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.xn--1234567890123456789012345678901234567890123456789012345-kue.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012; [A4_1] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; ; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; ; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890.; [A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; ; [A4_1 A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890a\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; [A4_1 A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890A\u03081234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; [A4_1 A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.1234567890Ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; [A4_1 A4_2] +B; 123456789012345678901234567890123456789012345678901234567890123.xn--12345678901234567890123456789012345678901234567890123456-fxe.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; 123456789012345678901234567890123456789012345678901234567890123.1234567890ä1234567890123456789012345678901234567890123456.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901; [A4_1 A4_2] +B; a.b..-q--a-.e; [V2 V3 A4_2]; [V2 V3 A4_2] +B; a.b..-q--ä-.e; [V2 V3 A4_2]; [V2 V3 A4_2] +B; a.b..-q--a\u0308-.e; [V2 V3 A4_2]; [V2 V3 A4_2] +B; A.B..-Q--A\u0308-.E; [V2 V3 A4_2]; [V2 V3 A4_2] +B; A.B..-Q--Ä-.E; [V2 V3 A4_2]; [V2 V3 A4_2] +B; A.b..-Q--Ä-.E; [V2 V3 A4_2]; [V2 V3 A4_2] +B; A.b..-Q--A\u0308-.E; [V2 V3 A4_2]; [V2 V3 A4_2] +B; a.b..xn---q----jra.e; [V2 V3 A4_2]; [V2 V3 A4_2] +B; a..c; [A4_2]; [A4_2] +B; a.-b.; [V3]; [V3] +B; a.b-.c; [V3]; [V3] +B; a.-.c; [V3]; [V3] +B; a.bc--de.f; [V2]; [V2] +B; ä.\u00AD.c; [A4_2]; [A4_2] +B; a\u0308.\u00AD.c; [A4_2]; [A4_2] +B; A\u0308.\u00AD.C; [A4_2]; [A4_2] +B; Ä.\u00AD.C; [A4_2]; [A4_2] +B; xn--4ca..c; [A4_2]; [A4_2] +B; ä.-b.; [V3]; [V3] +B; a\u0308.-b.; [V3]; [V3] +B; A\u0308.-B.; [V3]; [V3] +B; Ä.-B.; [V3]; [V3] +B; xn--4ca.-b.; [V3]; [V3] +B; ä.b-.c; [V3]; [V3] +B; a\u0308.b-.c; [V3]; [V3] +B; A\u0308.B-.C; [V3]; [V3] +B; Ä.B-.C; [V3]; [V3] +B; Ä.b-.C; [V3]; [V3] +B; A\u0308.b-.C; [V3]; [V3] +B; xn--4ca.b-.c; [V3]; [V3] +B; ä.-.c; [V3]; [V3] +B; a\u0308.-.c; [V3]; [V3] +B; A\u0308.-.C; [V3]; [V3] +B; Ä.-.C; [V3]; [V3] +B; xn--4ca.-.c; [V3]; [V3] +B; ä.bc--de.f; [V2]; [V2] +B; a\u0308.bc--de.f; [V2]; [V2] +B; A\u0308.BC--DE.F; [V2]; [V2] +B; Ä.BC--DE.F; [V2]; [V2] +B; Ä.bc--De.f; [V2]; [V2] +B; A\u0308.bc--De.f; [V2]; [V2] +B; xn--4ca.bc--de.f; [V2]; [V2] +B; a.b.\u0308c.d; [V5]; [V5] # a.b.̈c.d +B; A.B.\u0308C.D; [V5]; [V5] # a.b.̈c.d +B; A.b.\u0308c.d; [V5]; [V5] # a.b.̈c.d +B; a.b.xn--c-bcb.d; [V5]; [V5] # a.b.̈c.d +B; A0; a0; +B; 0A; 0a; +B; 0A.\u05D0; [B1]; [B1] # 0a.א +B; 0a.\u05D0; [B1]; [B1] # 0a.א +B; 0a.xn--4db; [B1]; [B1] # 0a.א +B; c.xn--0-eha.xn--4db; [B1]; [B1] # c.0ü.א +B; b-.\u05D0; [B6 V3]; [B6 V3] # b-.א +B; B-.\u05D0; [B6 V3]; [B6 V3] # b-.א +B; b-.xn--4db; [B6 V3]; [B6 V3] # b-.א +B; d.xn----dha.xn--4db; [B6 V3]; [B6 V3] # d.ü-.א +B; a\u05D0; [B5 B6]; [B5 B6] # aא +B; A\u05D0; [B5 B6]; [B5 B6] # aא +B; xn--a-0hc; [B5 B6]; [B5 B6] # aא +B; \u05D0\u05C7; ; xn--vdbr # אׇ +B; xn--vdbr; \u05D0\u05C7; xn--vdbr # אׇ +B; \u05D09\u05C7; ; xn--9-ihcz # א9ׇ +B; xn--9-ihcz; \u05D09\u05C7; xn--9-ihcz # א9ׇ +B; \u05D0a\u05C7; [B2 B3]; [B2 B3] # אaׇ +B; \u05D0A\u05C7; [B2 B3]; [B2 B3] # אaׇ +B; xn--a-ihcz; [B2 B3]; [B2 B3] # אaׇ +B; \u05D0\u05EA; ; xn--4db6c # את +B; xn--4db6c; \u05D0\u05EA; xn--4db6c # את +B; \u05D0\u05F3\u05EA; ; xn--4db6c0a # א׳ת +B; xn--4db6c0a; \u05D0\u05F3\u05EA; xn--4db6c0a # א׳ת +B; a\u05D0Tz; [B5]; [B5] # aאtz +B; a\u05D0tz; [B5]; [B5] # aאtz +B; A\u05D0TZ; [B5]; [B5] # aאtz +B; A\u05D0tz; [B5]; [B5] # aאtz +B; xn--atz-qpe; [B5]; [B5] # aאtz +B; \u05D0T\u05EA; [B2]; [B2] # אtת +B; \u05D0t\u05EA; [B2]; [B2] # אtת +B; xn--t-zhc3f; [B2]; [B2] # אtת +B; \u05D07\u05EA; ; xn--7-zhc3f # א7ת +B; xn--7-zhc3f; \u05D07\u05EA; xn--7-zhc3f # א7ת +B; \u05D0\u0667\u05EA; ; xn--4db6c6t # א٧ת +B; xn--4db6c6t; \u05D0\u0667\u05EA; xn--4db6c6t # א٧ת +B; a7\u0667z; [B5]; [B5] # a7٧z +B; A7\u0667Z; [B5]; [B5] # a7٧z +B; A7\u0667z; [B5]; [B5] # a7٧z +B; xn--a7z-06e; [B5]; [B5] # a7٧z +B; \u05D07\u0667\u05EA; [B4]; [B4] # א7٧ת +B; xn--7-zhc3fty; [B4]; [B4] # א7٧ת +T; ஹ\u0BCD\u200D; ; xn--dmc4b # ஹ் +N; ஹ\u0BCD\u200D; ; xn--dmc4b194h # ஹ் +B; xn--dmc4b; ஹ\u0BCD; xn--dmc4b # ஹ் +B; ஹ\u0BCD; ; xn--dmc4b # ஹ் +B; xn--dmc4b194h; ஹ\u0BCD\u200D; xn--dmc4b194h # ஹ் +T; ஹ\u200D; [C2]; xn--dmc # ஹ +N; ஹ\u200D; [C2]; [C2] # ஹ +B; xn--dmc; ஹ; xn--dmc +B; ஹ; ; xn--dmc +B; xn--dmc225h; [C2]; [C2] # ஹ +T; \u200D; [C2]; [A4_2] # +N; \u200D; [C2]; [C2] # +B; ; [A4_2]; [A4_2] +B; xn--1ug; [C2]; [C2] # +T; ஹ\u0BCD\u200C; ; xn--dmc4b # ஹ் +N; ஹ\u0BCD\u200C; ; xn--dmc4by94h # ஹ் +B; xn--dmc4by94h; ஹ\u0BCD\u200C; xn--dmc4by94h # ஹ் +T; ஹ\u200C; [C1]; xn--dmc # ஹ +N; ஹ\u200C; [C1]; [C1] # ஹ +B; xn--dmc025h; [C1]; [C1] # ஹ +T; \u200C; [C1]; [A4_2] # +N; \u200C; [C1]; [C1] # +B; xn--0ug; [C1]; [C1] # +T; \u0644\u0670\u200C\u06ED\u06EF; ; xn--ghb2gxqia # لٰۭۯ +N; \u0644\u0670\u200C\u06ED\u06EF; ; xn--ghb2gxqia7523a # لٰۭۯ +B; xn--ghb2gxqia; \u0644\u0670\u06ED\u06EF; xn--ghb2gxqia # لٰۭۯ +B; \u0644\u0670\u06ED\u06EF; ; xn--ghb2gxqia # لٰۭۯ +B; xn--ghb2gxqia7523a; \u0644\u0670\u200C\u06ED\u06EF; xn--ghb2gxqia7523a # لٰۭۯ +T; \u0644\u0670\u200C\u06EF; ; xn--ghb2g3q # لٰۯ +N; \u0644\u0670\u200C\u06EF; ; xn--ghb2g3qq34f # لٰۯ +B; xn--ghb2g3q; \u0644\u0670\u06EF; xn--ghb2g3q # لٰۯ +B; \u0644\u0670\u06EF; ; xn--ghb2g3q # لٰۯ +B; xn--ghb2g3qq34f; \u0644\u0670\u200C\u06EF; xn--ghb2g3qq34f # لٰۯ +T; \u0644\u200C\u06ED\u06EF; ; xn--ghb25aga # لۭۯ +N; \u0644\u200C\u06ED\u06EF; ; xn--ghb25aga828w # لۭۯ +B; xn--ghb25aga; \u0644\u06ED\u06EF; xn--ghb25aga # لۭۯ +B; \u0644\u06ED\u06EF; ; xn--ghb25aga # لۭۯ +B; xn--ghb25aga828w; \u0644\u200C\u06ED\u06EF; xn--ghb25aga828w # لۭۯ +T; \u0644\u200C\u06EF; ; xn--ghb65a # لۯ +N; \u0644\u200C\u06EF; ; xn--ghb65a953d # لۯ +B; xn--ghb65a; \u0644\u06EF; xn--ghb65a # لۯ +B; \u0644\u06EF; ; xn--ghb65a # لۯ +B; xn--ghb65a953d; \u0644\u200C\u06EF; xn--ghb65a953d # لۯ +T; \u0644\u0670\u200C\u06ED; [B3 C1]; xn--ghb2gxq # لٰۭ +N; \u0644\u0670\u200C\u06ED; [B3 C1]; [B3 C1] # لٰۭ +B; xn--ghb2gxq; \u0644\u0670\u06ED; xn--ghb2gxq # لٰۭ +B; \u0644\u0670\u06ED; ; xn--ghb2gxq # لٰۭ +B; xn--ghb2gxqy34f; [B3 C1]; [B3 C1] # لٰۭ +T; \u06EF\u200C\u06EF; [C1]; xn--cmba # ۯۯ +N; \u06EF\u200C\u06EF; [C1]; [C1] # ۯۯ +B; xn--cmba; \u06EF\u06EF; xn--cmba # ۯۯ +B; \u06EF\u06EF; ; xn--cmba # ۯۯ +B; xn--cmba004q; [C1]; [C1] # ۯۯ +T; \u0644\u200C; [B3 C1]; xn--ghb # ل +N; \u0644\u200C; [B3 C1]; [B3 C1] # ل +B; xn--ghb; \u0644; xn--ghb # ل +B; \u0644; ; xn--ghb # ل +B; xn--ghb413k; [B3 C1]; [B3 C1] # ل +B; a。。b; [A4_2]; [A4_2] +B; A。。B; [A4_2]; [A4_2] +B; a..b; [A4_2]; [A4_2] +T; \u200D。。\u06B9\u200C; [B1 B3 C1 C2 A4_2]; [A4_2] # ..ڹ +N; \u200D。。\u06B9\u200C; [B1 B3 C1 C2 A4_2]; [B1 B3 C1 C2 A4_2] # ..ڹ +B; ..xn--skb; [A4_2]; [A4_2] # ..ڹ +B; xn--1ug..xn--skb080k; [B1 B3 C1 C2 A4_2]; [B1 B3 C1 C2 A4_2] # ..ڹ +B; \u05D00\u0660; [B4]; [B4] # א0٠ +B; xn--0-zhc74b; [B4]; [B4] # א0٠ +B; $; [P1 V6]; [P1 V6] + +# RANDOMIZED TESTS + +B; c.0ü.\u05D0; [B1]; [B1] # c.0ü.א +B; c.0u\u0308.\u05D0; [B1]; [B1] # c.0ü.א +B; C.0U\u0308.\u05D0; [B1]; [B1] # c.0ü.א +B; C.0Ü.\u05D0; [B1]; [B1] # c.0ü.א +B; ⒕∝\u065F򓤦.-󠄯; [P1 V3 V6]; [P1 V3 V6] # ⒕∝ٟ.- +B; 14.∝\u065F򓤦.-󠄯; [P1 V3 V6]; [P1 V3 V6] # 14.∝ٟ.- +B; 14.xn--7hb713l3v90n.-; [V3 V6]; [V3 V6] # 14.∝ٟ.- +B; xn--7hb713lfwbi1311b.-; [V3 V6]; [V3 V6] # ⒕∝ٟ.- +B; ꡣ.\u07CF; ; xn--8c9a.xn--qsb # ꡣ.ߏ +B; xn--8c9a.xn--qsb; ꡣ.\u07CF; xn--8c9a.xn--qsb # ꡣ.ߏ +B; ≯\u0603。-; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≯.- +B; >\u0338\u0603。-; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≯.- +B; ≯\u0603。-; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≯.- +B; >\u0338\u0603。-; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≯.- +B; xn--lfb566l.-; [B1 V3 V6]; [B1 V3 V6] # ≯.- +T; ⾛𐹧⾕.\u115F󠗰ςႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςႭ +N; ⾛𐹧⾕.\u115F󠗰ςႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςႭ +T; 走𐹧谷.\u115F󠗰ςႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςႭ +N; 走𐹧谷.\u115F󠗰ςႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςႭ +T; 走𐹧谷.\u115F󠗰ςⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςⴍ +N; 走𐹧谷.\u115F󠗰ςⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςⴍ +B; 走𐹧谷.\u115F󠗰ΣႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σႭ +B; 走𐹧谷.\u115F󠗰σⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σⴍ +B; 走𐹧谷.\u115F󠗰Σⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σⴍ +B; xn--6g3a1x434z.xn--4xa180eotvh7453a; [B5 V6]; [B5 V6] # 走𐹧谷.σⴍ +B; xn--6g3a1x434z.xn--4xa627dhpae6345i; [B5 V6]; [B5 V6] # 走𐹧谷.σႭ +B; xn--6g3a1x434z.xn--3xa380eotvh7453a; [B5 V6]; [B5 V6] # 走𐹧谷.ςⴍ +B; xn--6g3a1x434z.xn--3xa827dhpae6345i; [B5 V6]; [B5 V6] # 走𐹧谷.ςႭ +T; ⾛𐹧⾕.\u115F󠗰ςⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςⴍ +N; ⾛𐹧⾕.\u115F󠗰ςⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.ςⴍ +B; ⾛𐹧⾕.\u115F󠗰ΣႭ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σႭ +B; ⾛𐹧⾕.\u115F󠗰σⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σⴍ +B; ⾛𐹧⾕.\u115F󠗰Σⴍ; [B5 P1 V6]; [B5 P1 V6] # 走𐹧谷.σⴍ +T; \u200D≠ᢙ≯.솣-ᡴႠ; [C2 P1 V6]; [P1 V6] # ≠ᢙ≯.솣-ᡴႠ +N; \u200D≠ᢙ≯.솣-ᡴႠ; [C2 P1 V6]; [C2 P1 V6] # ≠ᢙ≯.솣-ᡴႠ +T; \u200D=\u0338ᢙ>\u0338.솣-ᡴႠ; [C2 P1 V6]; [P1 V6] # ≠ᢙ≯.솣-ᡴႠ +N; \u200D=\u0338ᢙ>\u0338.솣-ᡴႠ; [C2 P1 V6]; [C2 P1 V6] # ≠ᢙ≯.솣-ᡴႠ +T; \u200D=\u0338ᢙ>\u0338.솣-ᡴⴀ; [C2 P1 V6]; [P1 V6] # ≠ᢙ≯.솣-ᡴⴀ +N; \u200D=\u0338ᢙ>\u0338.솣-ᡴⴀ; [C2 P1 V6]; [C2 P1 V6] # ≠ᢙ≯.솣-ᡴⴀ +T; \u200D≠ᢙ≯.솣-ᡴⴀ; [C2 P1 V6]; [P1 V6] # ≠ᢙ≯.솣-ᡴⴀ +N; \u200D≠ᢙ≯.솣-ᡴⴀ; [C2 P1 V6]; [C2 P1 V6] # ≠ᢙ≯.솣-ᡴⴀ +B; xn--jbf911clb.xn----p9j493ivi4l; [V6]; [V6] +B; xn--jbf929a90b0b.xn----p9j493ivi4l; [C2 V6]; [C2 V6] # ≠ᢙ≯.솣-ᡴⴀ +B; xn--jbf911clb.xn----6zg521d196p; [V6]; [V6] +B; xn--jbf929a90b0b.xn----6zg521d196p; [C2 V6]; [C2 V6] # ≠ᢙ≯.솣-ᡴႠ +B; 񯞜.𐿇\u0FA2\u077D\u0600; [P1 V6]; [P1 V6] # .ྡྷݽ +B; 񯞜.𐿇\u0FA1\u0FB7\u077D\u0600; [P1 V6]; [P1 V6] # .ྡྷݽ +B; 񯞜.𐿇\u0FA1\u0FB7\u077D\u0600; [P1 V6]; [P1 V6] # .ྡྷݽ +B; xn--gw68a.xn--ifb57ev2psc6027m; [V6]; [V6] # .ྡྷݽ +B; 𣳔\u0303.𑓂; [V5]; [V5] # 𣳔̃.𑓂 +B; xn--nsa95820a.xn--wz1d; [V5]; [V5] # 𣳔̃.𑓂 +B; 𞤀𞥅񘐱。󠄌Ⴣꡥ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 𞤢𞥅񘐱。󠄌ⴣꡥ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--9d6hgcy3556a.xn--rlju750b; [B2 B3 V6]; [B2 B3 V6] +B; xn--9d6hgcy3556a.xn--7nd0578e; [B2 B3 V6]; [B2 B3 V6] +B; 𞤀𞥅񘐱。󠄌ⴣꡥ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +T; \u08E2𑁿ς𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿ς𖬱.렧 +N; \u08E2𑁿ς𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿ς𖬱.렧 +T; \u08E2𑁿ς𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿ς𖬱.렧 +N; \u08E2𑁿ς𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿ς𖬱.렧 +B; \u08E2𑁿Σ𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿σ𖬱.렧 +B; \u08E2𑁿Σ𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿σ𖬱.렧 +B; \u08E2𑁿σ𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿σ𖬱.렧 +B; \u08E2𑁿σ𖬱。󠅡렧; [B1 P1 V6]; [B1 P1 V6] # 𑁿σ𖬱.렧 +B; xn--4xa53xp48ys2xc.xn--kn2b; [B1 V6]; [B1 V6] # 𑁿σ𖬱.렧 +B; xn--3xa73xp48ys2xc.xn--kn2b; [B1 V6]; [B1 V6] # 𑁿ς𖬱.렧 +T; -\u200D。𞤍\u200C\u200D⒈; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V6] # -.𞤯⒈ +N; -\u200D。𞤍\u200C\u200D⒈; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # -.𞤯⒈ +T; -\u200D。𞤍\u200C\u200D1.; [B1 C1 C2 V3]; [B1 V3] # -.𞤯1. +N; -\u200D。𞤍\u200C\u200D1.; [B1 C1 C2 V3]; [B1 C1 C2 V3] # -.𞤯1. +T; -\u200D。𞤯\u200C\u200D1.; [B1 C1 C2 V3]; [B1 V3] # -.𞤯1. +N; -\u200D。𞤯\u200C\u200D1.; [B1 C1 C2 V3]; [B1 C1 C2 V3] # -.𞤯1. +B; -.xn--1-0i8r.; [B1 V3]; [B1 V3] +B; xn----ugn.xn--1-rgnd61297b.; [B1 C1 C2 V3]; [B1 C1 C2 V3] # -.𞤯1. +T; -\u200D。𞤯\u200C\u200D⒈; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V6] # -.𞤯⒈ +N; -\u200D。𞤯\u200C\u200D⒈; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # -.𞤯⒈ +B; -.xn--tsh3666n; [B1 V3 V6]; [B1 V3 V6] +B; xn----ugn.xn--0ugc555aiv51d; [B1 C1 C2 V3 V6]; [B1 C1 C2 V3 V6] # -.𞤯⒈ +T; \u200C򅎭.Ⴒ𑇀; [C1 P1 V6]; [P1 V6] # .Ⴒ𑇀 +N; \u200C򅎭.Ⴒ𑇀; [C1 P1 V6]; [C1 P1 V6] # .Ⴒ𑇀 +T; \u200C򅎭.ⴒ𑇀; [C1 P1 V6]; [P1 V6] # .ⴒ𑇀 +N; \u200C򅎭.ⴒ𑇀; [C1 P1 V6]; [C1 P1 V6] # .ⴒ𑇀 +B; xn--bn95b.xn--9kj2034e; [V6]; [V6] +B; xn--0ug15083f.xn--9kj2034e; [C1 V6]; [C1 V6] # .ⴒ𑇀 +B; xn--bn95b.xn--qnd6272k; [V6]; [V6] +B; xn--0ug15083f.xn--qnd6272k; [C1 V6]; [C1 V6] # .Ⴒ𑇀 +T; 繱𑖿\u200D.8︒; [P1 V6]; [P1 V6] # 繱𑖿.8︒ +N; 繱𑖿\u200D.8︒; [P1 V6]; [P1 V6] # 繱𑖿.8︒ +T; 繱𑖿\u200D.8。; 繱𑖿\u200D.8.; xn--gl0as212a.8. # 繱𑖿.8. +N; 繱𑖿\u200D.8。; 繱𑖿\u200D.8.; xn--1ug6928ac48e.8. # 繱𑖿.8. +B; xn--gl0as212a.8.; 繱𑖿.8.; xn--gl0as212a.8. +B; 繱𑖿.8.; ; xn--gl0as212a.8. +B; xn--1ug6928ac48e.8.; 繱𑖿\u200D.8.; xn--1ug6928ac48e.8. # 繱𑖿.8. +T; 繱𑖿\u200D.8.; ; xn--gl0as212a.8. # 繱𑖿.8. +N; 繱𑖿\u200D.8.; ; xn--1ug6928ac48e.8. # 繱𑖿.8. +B; xn--gl0as212a.xn--8-o89h; [V6]; [V6] +B; xn--1ug6928ac48e.xn--8-o89h; [V6]; [V6] # 繱𑖿.8︒ +B; 󠆾.𞀈; [V5 A4_2]; [V5 A4_2] +B; 󠆾.𞀈; [V5 A4_2]; [V5 A4_2] +B; .xn--ph4h; [V5 A4_2]; [V5 A4_2] +T; ß\u06EB。\u200D; [C2]; xn--ss-59d. # ß۫. +N; ß\u06EB。\u200D; [C2]; [C2] # ß۫. +T; SS\u06EB。\u200D; [C2]; xn--ss-59d. # ss۫. +N; SS\u06EB。\u200D; [C2]; [C2] # ss۫. +T; ss\u06EB。\u200D; [C2]; xn--ss-59d. # ss۫. +N; ss\u06EB。\u200D; [C2]; [C2] # ss۫. +T; Ss\u06EB。\u200D; [C2]; xn--ss-59d. # ss۫. +N; Ss\u06EB。\u200D; [C2]; [C2] # ss۫. +B; xn--ss-59d.; ss\u06EB.; xn--ss-59d. # ss۫. +B; ss\u06EB.; ; xn--ss-59d. # ss۫. +B; SS\u06EB.; ss\u06EB.; xn--ss-59d. # ss۫. +B; Ss\u06EB.; ss\u06EB.; xn--ss-59d. # ss۫. +B; xn--ss-59d.xn--1ug; [C2]; [C2] # ss۫. +B; xn--zca012a.xn--1ug; [C2]; [C2] # ß۫. +T; 󠐵\u200C⒈.󠎇; [C1 P1 V6]; [P1 V6] # ⒈. +N; 󠐵\u200C⒈.󠎇; [C1 P1 V6]; [C1 P1 V6] # ⒈. +T; 󠐵\u200C1..󠎇; [C1 P1 V6 A4_2]; [P1 V6 A4_2] # 1.. +N; 󠐵\u200C1..󠎇; [C1 P1 V6 A4_2]; [C1 P1 V6 A4_2] # 1.. +B; xn--1-bs31m..xn--tv36e; [V6 A4_2]; [V6 A4_2] +B; xn--1-rgn37671n..xn--tv36e; [C1 V6 A4_2]; [C1 V6 A4_2] # 1.. +B; xn--tshz2001k.xn--tv36e; [V6]; [V6] +B; xn--0ug88o47900b.xn--tv36e; [C1 V6]; [C1 V6] # ⒈. +T; 󟈣\u065F\uAAB2ß。󌓧; [P1 V6]; [P1 V6] # ٟꪲß. +N; 󟈣\u065F\uAAB2ß。󌓧; [P1 V6]; [P1 V6] # ٟꪲß. +B; 󟈣\u065F\uAAB2SS。󌓧; [P1 V6]; [P1 V6] # ٟꪲss. +B; 󟈣\u065F\uAAB2ss。󌓧; [P1 V6]; [P1 V6] # ٟꪲss. +B; 󟈣\u065F\uAAB2Ss。󌓧; [P1 V6]; [P1 V6] # ٟꪲss. +B; xn--ss-3xd2839nncy1m.xn--bb79d; [V6]; [V6] # ٟꪲss. +B; xn--zca92z0t7n5w96j.xn--bb79d; [V6]; [V6] # ٟꪲß. +T; \u0774\u200C𞤿。𽘐䉜\u200D񿤼; [C1 C2 P1 V6]; [P1 V6] # ݴ𞤿.䉜 +N; \u0774\u200C𞤿。𽘐䉜\u200D񿤼; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ݴ𞤿.䉜 +T; \u0774\u200C𞤝。𽘐䉜\u200D񿤼; [C1 C2 P1 V6]; [P1 V6] # ݴ𞤿.䉜 +N; \u0774\u200C𞤝。𽘐䉜\u200D񿤼; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ݴ𞤿.䉜 +B; xn--4pb2977v.xn--z0nt555ukbnv; [V6]; [V6] # ݴ𞤿.䉜 +B; xn--4pb607jjt73a.xn--1ug236ke314donv1a; [C1 C2 V6]; [C1 C2 V6] # ݴ𞤿.䉜 +T; 򔭜ςᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # ςᡱ⒈.≮𑄳𐮍 +N; 򔭜ςᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # ςᡱ⒈.≮𑄳𐮍 +T; 򔭜ςᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # ςᡱ⒈.≮𑄳𐮍 +N; 򔭜ςᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # ςᡱ⒈.≮𑄳𐮍 +T; 򔭜ςᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ςᡱ1..≮𑄳𐮍 +N; 򔭜ςᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ςᡱ1..≮𑄳𐮍 +T; 򔭜ςᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ςᡱ1..≮𑄳𐮍 +N; 򔭜ςᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ςᡱ1..≮𑄳𐮍 +T; 򔭜Σᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +N; 򔭜Σᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +T; 򔭜Σᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +N; 򔭜Σᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +T; 򔭜σᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +N; 򔭜σᡱ1..≮𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +T; 򔭜σᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +N; 򔭜σᡱ1..<\u0338𑄳\u200D𐮍; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +B; xn--1-zmb699meq63t..xn--gdh5392g6sd; [B1 V6 A4_2]; [B1 V6 A4_2] +B; xn--1-zmb699meq63t..xn--1ug85gn777ahze; [B1 V6 A4_2]; [B1 V6 A4_2] # σᡱ1..≮𑄳𐮍 +B; xn--1-xmb999meq63t..xn--1ug85gn777ahze; [B1 V6 A4_2]; [B1 V6 A4_2] # ςᡱ1..≮𑄳𐮍 +T; 򔭜Σᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +N; 򔭜Σᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +T; 򔭜Σᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +N; 򔭜Σᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +T; 򔭜σᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +N; 򔭜σᡱ⒈.≮𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +T; 򔭜σᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +N; 򔭜σᡱ⒈.<\u0338𑄳\u200D𐮍; [B1 P1 V6]; [B1 P1 V6] # σᡱ⒈.≮𑄳𐮍 +B; xn--4xa207hkzinr77u.xn--gdh5392g6sd; [B1 V6]; [B1 V6] +B; xn--4xa207hkzinr77u.xn--1ug85gn777ahze; [B1 V6]; [B1 V6] # σᡱ⒈.≮𑄳𐮍 +B; xn--3xa407hkzinr77u.xn--1ug85gn777ahze; [B1 V6]; [B1 V6] # ςᡱ⒈.≮𑄳𐮍 +B; \u3164\u094DႠ\u17D0.\u180B; [P1 V6]; [P1 V6] # ्Ⴀ័. +B; \u1160\u094DႠ\u17D0.\u180B; [P1 V6]; [P1 V6] # ्Ⴀ័. +B; \u1160\u094Dⴀ\u17D0.\u180B; [P1 V6]; [P1 V6] # ्ⴀ័. +B; xn--n3b742bkqf4ty.; [V6]; [V6] # ्ⴀ័. +B; xn--n3b468aoqa89r.; [V6]; [V6] # ्Ⴀ័. +B; \u3164\u094Dⴀ\u17D0.\u180B; [P1 V6]; [P1 V6] # ्ⴀ័. +B; xn--n3b445e53po6d.; [V6]; [V6] # ्ⴀ័. +B; xn--n3b468azngju2a.; [V6]; [V6] # ्Ⴀ័. +T; ❣\u200D.\u09CD𑰽\u0612\uA929; [C2 V5]; [V5] # ❣.্𑰽ؒꤩ +N; ❣\u200D.\u09CD𑰽\u0612\uA929; [C2 V5]; [C2 V5] # ❣.্𑰽ؒꤩ +T; ❣\u200D.\u09CD𑰽\u0612\uA929; [C2 V5]; [V5] # ❣.্𑰽ؒꤩ +N; ❣\u200D.\u09CD𑰽\u0612\uA929; [C2 V5]; [C2 V5] # ❣.্𑰽ؒꤩ +B; xn--pei.xn--0fb32q3w7q2g4d; [V5]; [V5] # ❣.্𑰽ؒꤩ +B; xn--1ugy10a.xn--0fb32q3w7q2g4d; [C2 V5]; [C2 V5] # ❣.্𑰽ؒꤩ +B; ≮𐳺𐹄.≯񪮸ꡅ; [B1 P1 V6]; [B1 P1 V6] +B; <\u0338𐳺𐹄.>\u0338񪮸ꡅ; [B1 P1 V6]; [B1 P1 V6] +B; xn--gdh7943gk2a.xn--hdh1383c5e36c; [B1 V6]; [B1 V6] +B; \u0CCC𐧅𐳏󠲺。\u0CCDᠦ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ೌ𐧅𐳏.್ᠦ +B; \u0CCC𐧅𐳏󠲺。\u0CCDᠦ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ೌ𐧅𐳏.್ᠦ +B; \u0CCC𐧅𐲏󠲺。\u0CCDᠦ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ೌ𐧅𐳏.್ᠦ +B; xn--7tc6360ky5bn2732c.xn--8tc429c; [B1 V5 V6]; [B1 V5 V6] # ೌ𐧅𐳏.್ᠦ +B; \u0CCC𐧅𐲏󠲺。\u0CCDᠦ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ೌ𐧅𐳏.್ᠦ +B; \u0349。𧡫; [V5]; [V5] # ͉.𧡫 +B; xn--nua.xn--bc6k; [V5]; [V5] # ͉.𧡫 +B; 𑰿󠅦.\u1160; [P1 V5 V6]; [P1 V5 V6] # 𑰿. +B; 𑰿󠅦.\u1160; [P1 V5 V6]; [P1 V5 V6] # 𑰿. +B; xn--ok3d.xn--psd; [V5 V6]; [V5 V6] # 𑰿. +T; -𞤆\u200D。󸼄𞳒; [B1 B5 B6 C2 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # -𞤨. +N; -𞤆\u200D。󸼄𞳒; [B1 B5 B6 C2 P1 V3 V6]; [B1 B5 B6 C2 P1 V3 V6] # -𞤨. +T; -𞤨\u200D。󸼄𞳒; [B1 B5 B6 C2 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # -𞤨. +N; -𞤨\u200D。󸼄𞳒; [B1 B5 B6 C2 P1 V3 V6]; [B1 B5 B6 C2 P1 V3 V6] # -𞤨. +B; xn----ni8r.xn--846h96596c; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----ugnx367r.xn--846h96596c; [B1 B5 B6 C2 V3 V6]; [B1 B5 B6 C2 V3 V6] # -𞤨. +B; ꡏ󠇶≯𳾽。\u1DFD⾇滸𐹰; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꡏ≯.᷽舛滸𐹰 +B; ꡏ󠇶>\u0338𳾽。\u1DFD⾇滸𐹰; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꡏ≯.᷽舛滸𐹰 +B; ꡏ󠇶≯𳾽。\u1DFD舛滸𐹰; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꡏ≯.᷽舛滸𐹰 +B; ꡏ󠇶>\u0338𳾽。\u1DFD舛滸𐹰; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꡏ≯.᷽舛滸𐹰 +B; xn--hdh7483cu6twwki8e.xn--yfg0765a58l0n6k; [B1 V5 V6]; [B1 V5 V6] # ꡏ≯.᷽舛滸𐹰 +B; 蔏。𑰺; [V5]; [V5] +B; 蔏。𑰺; [V5]; [V5] +B; xn--uy1a.xn--jk3d; [V5]; [V5] +B; 𝟿𐮋。󠄊; [B1]; [B1] +B; 9𐮋。󠄊; [B1]; [B1] +B; xn--9-rv5i.; [B1]; [B1] +B; 󟇇-䟖F。\u07CB⒈\u0662; [B4 P1 V6]; [B4 P1 V6] # -䟖f.ߋ⒈٢ +B; 󟇇-䟖F。\u07CB1.\u0662; [B1 P1 V6]; [B1 P1 V6] # -䟖f.ߋ1.٢ +B; 󟇇-䟖f。\u07CB1.\u0662; [B1 P1 V6]; [B1 P1 V6] # -䟖f.ߋ1.٢ +B; xn---f-mz8b08788k.xn--1-ybd.xn--bib; [B1 V6]; [B1 V6] # -䟖f.ߋ1.٢ +B; 󟇇-䟖f。\u07CB⒈\u0662; [B4 P1 V6]; [B4 P1 V6] # -䟖f.ߋ⒈٢ +B; xn---f-mz8b08788k.xn--bib53ev44d; [B4 V6]; [B4 V6] # -䟖f.ߋ⒈٢ +T; \u200C。𐹺; [B1 C1]; [B1 A4_2] # .𐹺 +N; \u200C。𐹺; [B1 C1]; [B1 C1] # .𐹺 +T; \u200C。𐹺; [B1 C1]; [B1 A4_2] # .𐹺 +N; \u200C。𐹺; [B1 C1]; [B1 C1] # .𐹺 +B; .xn--yo0d; [B1 A4_2]; [B1 A4_2] +B; xn--0ug.xn--yo0d; [B1 C1]; [B1 C1] # .𐹺 +T; 𐡆.≯\u200C-𞥀; [B1 C1 P1 V6]; [B1 P1 V6] # 𐡆.≯-𞥀 +N; 𐡆.≯\u200C-𞥀; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐡆.≯-𞥀 +T; 𐡆.>\u0338\u200C-𞥀; [B1 C1 P1 V6]; [B1 P1 V6] # 𐡆.≯-𞥀 +N; 𐡆.>\u0338\u200C-𞥀; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐡆.≯-𞥀 +T; 𐡆.>\u0338\u200C-𞤞; [B1 C1 P1 V6]; [B1 P1 V6] # 𐡆.≯-𞥀 +N; 𐡆.>\u0338\u200C-𞤞; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐡆.≯-𞥀 +T; 𐡆.≯\u200C-𞤞; [B1 C1 P1 V6]; [B1 P1 V6] # 𐡆.≯-𞥀 +N; 𐡆.≯\u200C-𞤞; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐡆.≯-𞥀 +B; xn--le9c.xn----ogo9956r; [B1 V6]; [B1 V6] +B; xn--le9c.xn----rgn40iy359e; [B1 C1 V6]; [B1 C1 V6] # 𐡆.≯-𞥀 +B; 󠁀-。≠\uFCD7; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.≠هج +B; 󠁀-。=\u0338\uFCD7; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.≠هج +B; 󠁀-。≠\u0647\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.≠هج +B; 󠁀-。=\u0338\u0647\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.≠هج +B; xn----f411m.xn--rgb7c611j; [B1 V3 V6]; [B1 V3 V6] # -.≠هج +T; 񻬹𑈵。\u200D𞨶; [B1 C2 P1 V6]; [P1 V6] # 𑈵. +N; 񻬹𑈵。\u200D𞨶; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𑈵. +B; xn--8g1d12120a.xn--5l6h; [V6]; [V6] +B; xn--8g1d12120a.xn--1ug6651p; [B1 C2 V6]; [B1 C2 V6] # 𑈵. +B; 𑋧\uA9C02。㧉򒖄; [P1 V5 V6]; [P1 V5 V6] # 𑋧꧀2.㧉 +B; 𑋧\uA9C02。㧉򒖄; [P1 V5 V6]; [P1 V5 V6] # 𑋧꧀2.㧉 +B; xn--2-5z4eu89y.xn--97l02706d; [V5 V6]; [V5 V6] # 𑋧꧀2.㧉 +T; \u200C𽬄𐹴𞩥。≯6; [B1 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹴.≯6 +N; \u200C𽬄𐹴𞩥。≯6; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹴.≯6 +T; \u200C𽬄𐹴𞩥。>\u03386; [B1 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹴.≯6 +N; \u200C𽬄𐹴𞩥。>\u03386; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹴.≯6 +B; xn--so0du768aim9m.xn--6-ogo; [B1 B5 B6 V6]; [B1 B5 B6 V6] +B; xn--0ug7105gf5wfxepq.xn--6-ogo; [B1 C1 V6]; [B1 C1 V6] # 𐹴.≯6 +T; 𑁿.𐹦𻞵-\u200D; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 P1 V3 V5 V6] # 𑁿.𐹦- +N; 𑁿.𐹦𻞵-\u200D; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 C2 P1 V5 V6] # 𑁿.𐹦- +T; 𑁿.𐹦𻞵-\u200D; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 P1 V3 V5 V6] # 𑁿.𐹦- +N; 𑁿.𐹦𻞵-\u200D; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 C2 P1 V5 V6] # 𑁿.𐹦- +B; xn--q30d.xn----i26i1299n; [B1 B3 B6 V3 V5 V6]; [B1 B3 B6 V3 V5 V6] +B; xn--q30d.xn----ugn1088hfsxv; [B1 B3 B6 C2 V5 V6]; [B1 B3 B6 C2 V5 V6] # 𑁿.𐹦- +T; ⤸ς𺱀。\uFFA0; [P1 V6]; [P1 V6] # ⤸ς. +N; ⤸ς𺱀。\uFFA0; [P1 V6]; [P1 V6] # ⤸ς. +T; ⤸ς𺱀。\u1160; [P1 V6]; [P1 V6] # ⤸ς. +N; ⤸ς𺱀。\u1160; [P1 V6]; [P1 V6] # ⤸ς. +B; ⤸Σ𺱀。\u1160; [P1 V6]; [P1 V6] # ⤸σ. +B; ⤸σ𺱀。\u1160; [P1 V6]; [P1 V6] # ⤸σ. +B; xn--4xa192qmp03d.xn--psd; [V6]; [V6] # ⤸σ. +B; xn--3xa392qmp03d.xn--psd; [V6]; [V6] # ⤸ς. +B; ⤸Σ𺱀。\uFFA0; [P1 V6]; [P1 V6] # ⤸σ. +B; ⤸σ𺱀。\uFFA0; [P1 V6]; [P1 V6] # ⤸σ. +B; xn--4xa192qmp03d.xn--cl7c; [V6]; [V6] # ⤸σ. +B; xn--3xa392qmp03d.xn--cl7c; [V6]; [V6] # ⤸ς. +B; \u0765\u1035𐫔\u06D5.𐦬𑋪Ⴃ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ݥဵ𐫔ە.𐦬𑋪Ⴃ +B; \u0765\u1035𐫔\u06D5.𐦬𑋪ⴃ; [B2 B3]; [B2 B3] # ݥဵ𐫔ە.𐦬𑋪ⴃ +B; xn--llb10as9tqp5y.xn--ukj7371e21f; [B2 B3]; [B2 B3] # ݥဵ𐫔ە.𐦬𑋪ⴃ +B; xn--llb10as9tqp5y.xn--bnd9168j21f; [B2 B3 V6]; [B2 B3 V6] # ݥဵ𐫔ە.𐦬𑋪Ⴃ +B; \u0661\u1B44-킼.\u1BAA\u0616\u066C≯; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ١᭄-킼.᮪ؖ٬≯ +B; \u0661\u1B44-킼.\u1BAA\u0616\u066C>\u0338; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ١᭄-킼.᮪ؖ٬≯ +B; xn----9pc551nk39n.xn--4fb6o571degg; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ١᭄-킼.᮪ؖ٬≯ +B; -。\u06C2\u0604򅖡𑓂; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -.ۂ𑓂 +B; -。\u06C1\u0654\u0604򅖡𑓂; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -.ۂ𑓂 +B; -.xn--mfb39a7208dzgs3d; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # -.ۂ𑓂 +T; \u200D󯑖󠁐.\u05BD𙮰ꡝ𐋡; [C2 P1 V5 V6]; [P1 V5 V6] # .ֽꡝ𐋡 +N; \u200D󯑖󠁐.\u05BD𙮰ꡝ𐋡; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .ֽꡝ𐋡 +T; \u200D󯑖󠁐.\u05BD𙮰ꡝ𐋡; [C2 P1 V5 V6]; [P1 V5 V6] # .ֽꡝ𐋡 +N; \u200D󯑖󠁐.\u05BD𙮰ꡝ𐋡; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .ֽꡝ𐋡 +B; xn--b726ey18m.xn--ldb8734fg0qcyzzg; [V5 V6]; [V5 V6] # .ֽꡝ𐋡 +B; xn--1ug66101lt8me.xn--ldb8734fg0qcyzzg; [C2 V5 V6]; [C2 V5 V6] # .ֽꡝ𐋡 +T; ︒􃈵ς񀠇。𐮈; [B1 P1 V6]; [B1 P1 V6] +N; ︒􃈵ς񀠇。𐮈; [B1 P1 V6]; [B1 P1 V6] +T; 。􃈵ς񀠇。𐮈; [P1 V6 A4_2]; [P1 V6 A4_2] +N; 。􃈵ς񀠇。𐮈; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 。􃈵Σ񀠇。𐮈; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 。􃈵σ񀠇。𐮈; [P1 V6 A4_2]; [P1 V6 A4_2] +B; .xn--4xa68573c7n64d.xn--f29c; [V6 A4_2]; [V6 A4_2] +B; .xn--3xa88573c7n64d.xn--f29c; [V6 A4_2]; [V6 A4_2] +B; ︒􃈵Σ񀠇。𐮈; [B1 P1 V6]; [B1 P1 V6] +B; ︒􃈵σ񀠇。𐮈; [B1 P1 V6]; [B1 P1 V6] +B; xn--4xa1729jwz5t7gl5f.xn--f29c; [B1 V6]; [B1 V6] +B; xn--3xa3729jwz5t7gl5f.xn--f29c; [B1 V6]; [B1 V6] +B; \u07D9.\u06EE󆾃≯󠅲; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ߙ.ۮ≯ +B; \u07D9.\u06EE󆾃>\u0338󠅲; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ߙ.ۮ≯ +B; \u07D9.\u06EE󆾃≯󠅲; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ߙ.ۮ≯ +B; \u07D9.\u06EE󆾃>\u0338󠅲; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ߙ.ۮ≯ +B; xn--0sb.xn--bmb691l0524t; [B2 B3 V6]; [B2 B3 V6] # ߙ.ۮ≯ +B; \u1A73󚙸.𐭍; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᩳ.𐭍 +B; xn--2of22352n.xn--q09c; [B1 V5 V6]; [B1 V5 V6] # ᩳ.𐭍 +B; ⒉󠊓≠。Ⴟ⬣Ⴈ; [P1 V6]; [P1 V6] +B; ⒉󠊓=\u0338。Ⴟ⬣Ⴈ; [P1 V6]; [P1 V6] +B; 2.󠊓≠。Ⴟ⬣Ⴈ; [P1 V6]; [P1 V6] +B; 2.󠊓=\u0338。Ⴟ⬣Ⴈ; [P1 V6]; [P1 V6] +B; 2.󠊓=\u0338。ⴟ⬣ⴈ; [P1 V6]; [P1 V6] +B; 2.󠊓≠。ⴟ⬣ⴈ; [P1 V6]; [P1 V6] +B; 2.xn--1chz4101l.xn--45iz7d6b; [V6]; [V6] +B; 2.xn--1chz4101l.xn--gnd9b297j; [V6]; [V6] +B; ⒉󠊓=\u0338。ⴟ⬣ⴈ; [P1 V6]; [P1 V6] +B; ⒉󠊓≠。ⴟ⬣ⴈ; [P1 V6]; [P1 V6] +B; xn--1ch07f91401d.xn--45iz7d6b; [V6]; [V6] +B; xn--1ch07f91401d.xn--gnd9b297j; [V6]; [V6] +B; -󠉱\u0FB8Ⴥ。-𐹽\u0774𞣑; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ྸჅ.-𐹽ݴ𞣑 +B; -󠉱\u0FB8ⴥ。-𐹽\u0774𞣑; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ྸⴥ.-𐹽ݴ𞣑 +B; xn----xmg317tgv352a.xn----05c4213ryr0g; [B1 V3 V6]; [B1 V3 V6] # -ྸⴥ.-𐹽ݴ𞣑 +B; xn----xmg12fm2555h.xn----05c4213ryr0g; [B1 V3 V6]; [B1 V3 V6] # -ྸჅ.-𐹽ݴ𞣑 +B; \u0659。𑄴︒\u0627\u07DD; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ٙ.𑄴︒اߝ +B; \u0659。𑄴。\u0627\u07DD; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ٙ.𑄴.اߝ +B; xn--1hb.xn--w80d.xn--mgb09f; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ٙ.𑄴.اߝ +B; xn--1hb.xn--mgb09fp820c08pa; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # ٙ.𑄴︒اߝ +T; Ⴙ\u0638.󠆓\u200D; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # Ⴙظ. +N; Ⴙ\u0638.󠆓\u200D; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # Ⴙظ. +T; ⴙ\u0638.󠆓\u200D; [B1 B5 B6 C2]; [B5 B6] # ⴙظ. +N; ⴙ\u0638.󠆓\u200D; [B1 B5 B6 C2]; [B1 B5 B6 C2] # ⴙظ. +B; xn--3gb910r.; [B5 B6]; [B5 B6] # ⴙظ. +B; xn--3gb910r.xn--1ug; [B1 B5 B6 C2]; [B1 B5 B6 C2] # ⴙظ. +B; xn--3gb194c.; [B5 B6 V6]; [B5 B6 V6] # Ⴙظ. +B; xn--3gb194c.xn--1ug; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # Ⴙظ. +B; 󠆸。₆0𐺧\u0756; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # .60ݖ +B; 󠆸。60𐺧\u0756; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # .60ݖ +B; .xn--60-cke9470y; [B1 V6 A4_2]; [B1 V6 A4_2] # .60ݖ +B; 6\u084F。-𑈴; [B1 V3]; [B1 V3] # 6ࡏ.-𑈴 +B; 6\u084F。-𑈴; [B1 V3]; [B1 V3] # 6ࡏ.-𑈴 +B; xn--6-jjd.xn----6n8i; [B1 V3]; [B1 V3] # 6ࡏ.-𑈴 +T; \u200D񋌿𐹰。\u0ACDς𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્ςࣖ +N; \u200D񋌿𐹰。\u0ACDς𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્ςࣖ +T; \u200D񋌿𐹰。\u0ACDς𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્ςࣖ +N; \u200D񋌿𐹰。\u0ACDς𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્ςࣖ +T; \u200D񋌿𐹰。\u0ACDΣ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્σࣖ +N; \u200D񋌿𐹰。\u0ACDΣ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્σࣖ +T; \u200D񋌿𐹰。\u0ACDσ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્σࣖ +N; \u200D񋌿𐹰。\u0ACDσ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્σࣖ +B; xn--oo0d1330n.xn--4xa21xcwbfz15g; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # 𐹰.્σࣖ +B; xn--1ugx105gq26y.xn--4xa21xcwbfz15g; [B1 C2 V5 V6]; [B1 C2 V5 V6] # 𐹰.્σࣖ +B; xn--1ugx105gq26y.xn--3xa41xcwbfz15g; [B1 C2 V5 V6]; [B1 C2 V5 V6] # 𐹰.્ςࣖ +T; \u200D񋌿𐹰。\u0ACDΣ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્σࣖ +N; \u200D񋌿𐹰。\u0ACDΣ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્σࣖ +T; \u200D񋌿𐹰。\u0ACDσ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𐹰.્σࣖ +N; \u200D񋌿𐹰。\u0ACDσ𞰎\u08D6; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹰.્σࣖ +B; ⒈񟄜Ⴓ⒪.\u0DCA򘘶\u088B𐹢; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ⒈Ⴓ⒪.්𐹢 +B; 1.񟄜Ⴓ(o).\u0DCA򘘶\u088B𐹢; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # 1.Ⴓ(o).්𐹢 +B; 1.񟄜ⴓ(o).\u0DCA򘘶\u088B𐹢; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # 1.ⴓ(o).්𐹢 +B; 1.񟄜Ⴓ(O).\u0DCA򘘶\u088B𐹢; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # 1.Ⴓ(o).්𐹢 +B; 1.xn--(o)-7sn88849j.xn--3xb99xpx1yoes3e; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # 1.Ⴓ(o).්𐹢 +B; 1.xn--(o)-ej1bu5389e.xn--3xb99xpx1yoes3e; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # 1.ⴓ(o).්𐹢 +B; ⒈񟄜ⴓ⒪.\u0DCA򘘶\u088B𐹢; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ⒈ⴓ⒪.්𐹢 +B; xn--tsh0ds63atl31n.xn--3xb99xpx1yoes3e; [B1 V5 V6]; [B1 V5 V6] # ⒈ⴓ⒪.්𐹢 +B; xn--rnd762h7cx3027d.xn--3xb99xpx1yoes3e; [B1 V5 V6]; [B1 V5 V6] # ⒈Ⴓ⒪.්𐹢 +B; 𞤷.𐮐𞢁𐹠\u0624; ; xn--ve6h.xn--jgb1694kz0b2176a; NV8 # 𞤷.𐮐𞢁𐹠ؤ +B; 𞤷.𐮐𞢁𐹠\u0648\u0654; 𞤷.𐮐𞢁𐹠\u0624; xn--ve6h.xn--jgb1694kz0b2176a; NV8 # 𞤷.𐮐𞢁𐹠ؤ +B; 𞤕.𐮐𞢁𐹠\u0648\u0654; 𞤷.𐮐𞢁𐹠\u0624; xn--ve6h.xn--jgb1694kz0b2176a; NV8 # 𞤷.𐮐𞢁𐹠ؤ +B; 𞤕.𐮐𞢁𐹠\u0624; 𞤷.𐮐𞢁𐹠\u0624; xn--ve6h.xn--jgb1694kz0b2176a; NV8 # 𞤷.𐮐𞢁𐹠ؤ +B; xn--ve6h.xn--jgb1694kz0b2176a; 𞤷.𐮐𞢁𐹠\u0624; xn--ve6h.xn--jgb1694kz0b2176a; NV8 # 𞤷.𐮐𞢁𐹠ؤ +B; 𐲈-。𑄳񢌻; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] +B; 𐲈-。𑄳񢌻; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] +B; 𐳈-。𑄳񢌻; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] +B; xn----ue6i.xn--v80d6662t; [B1 B3 V3 V5 V6]; [B1 B3 V3 V5 V6] +B; 𐳈-。𑄳񢌻; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] +B; -󠉖ꡧ.󠊂񇆃🄉; [P1 V3 V6]; [P1 V3 V6] +B; -󠉖ꡧ.󠊂񇆃8,; [P1 V3 V6]; [P1 V3 V6] +B; xn----hg4ei0361g.xn--8,-k362evu488a; [P1 V3 V6]; [P1 V3 V6] +B; xn----hg4ei0361g.xn--207ht163h7m94c; [V3 V6]; [V3 V6] +B; 󠾛󠈴臯𧔤.\u0768𝟝; [B1 P1 V6]; [B1 P1 V6] # 臯𧔤.ݨ5 +B; 󠾛󠈴臯𧔤.\u07685; [B1 P1 V6]; [B1 P1 V6] # 臯𧔤.ݨ5 +B; xn--zb1at733hm579ddhla.xn--5-b5c; [B1 V6]; [B1 V6] # 臯𧔤.ݨ5 +B; ≮𐹣.𝨿; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] +B; <\u0338𐹣.𝨿; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] +B; ≮𐹣.𝨿; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] +B; <\u0338𐹣.𝨿; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] +B; xn--gdh1504g.xn--e92h; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] +B; 𐹯ᯛ\u0A4D。脥; [B1]; [B1] # 𐹯ᯛ੍.脥 +B; 𐹯ᯛ\u0A4D。脥; [B1]; [B1] # 𐹯ᯛ੍.脥 +B; xn--ybc101g3m1p.xn--740a; [B1]; [B1] # 𐹯ᯛ੍.脥 +B; \u1B44\u115F𞷿򃀍.-; [B1 B5 P1 V3 V5 V6]; [B1 B5 P1 V3 V5 V6] # ᭄.- +B; xn--osd971cpx70btgt8b.-; [B1 B5 V3 V5 V6]; [B1 B5 V3 V5 V6] # ᭄.- +T; \u200C。\u0354; [C1 V5]; [V5 A4_2] # .͔ +N; \u200C。\u0354; [C1 V5]; [C1 V5] # .͔ +T; \u200C。\u0354; [C1 V5]; [V5 A4_2] # .͔ +N; \u200C。\u0354; [C1 V5]; [C1 V5] # .͔ +B; .xn--yua; [V5 A4_2]; [V5 A4_2] # .͔ +B; xn--0ug.xn--yua; [C1 V5]; [C1 V5] # .͔ +B; 𞤥󠅮.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤥󠅮.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤥󠅮.ᡄⴎ; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; 𞤃󠅮.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤃󠅮.ᡄⴎ; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; xn--de6h.xn--37e857h; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; 𞤥.ᡄⴎ; ; xn--de6h.xn--37e857h +B; 𞤃.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤃.ᡄⴎ; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; xn--de6h.xn--mnd799a; [V6]; [V6] +B; 𞤥󠅮.ᡄⴎ; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; 𞤃󠅮.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤃󠅮.ᡄⴎ; 𞤥.ᡄⴎ; xn--de6h.xn--37e857h +B; 𞤥.ᡄႮ; [P1 V6]; [P1 V6] +B; 𞤧𝨨Ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤧𝨨Ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤧𝨨ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤅𝨨Ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤅𝨨ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; xn--zxa5691vboja.xn--bfi293ci119b; [B2 B3 B6]; [B2 B3 B6] +B; 𞤧𝨨ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤅𝨨Ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +B; 𞤅𝨨ξ.𪺏㛨❸; [B2 B3 B6]; [B2 B3 B6] +T; ᠆몆\u200C-。Ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.Ⴛ𐦅︒ +N; ᠆몆\u200C-。Ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.Ⴛ𐦅︒ +T; ᠆몆\u200C-。Ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.Ⴛ𐦅︒ +N; ᠆몆\u200C-。Ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.Ⴛ𐦅︒ +T; ᠆몆\u200C-。Ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.Ⴛ𐦅. +N; ᠆몆\u200C-。Ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.Ⴛ𐦅. +T; ᠆몆\u200C-。Ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.Ⴛ𐦅. +N; ᠆몆\u200C-。Ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.Ⴛ𐦅. +T; ᠆몆\u200C-。ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.ⴛ𐦅. +N; ᠆몆\u200C-。ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.ⴛ𐦅. +T; ᠆몆\u200C-。ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.ⴛ𐦅. +N; ᠆몆\u200C-。ⴛ𐦅。; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.ⴛ𐦅. +B; xn----e3j6620g.xn--jlju661e.; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----e3j425bsk1o.xn--jlju661e.; [B1 B5 B6 C1 V3 V6]; [B1 B5 B6 C1 V3 V6] # ᠆몆-.ⴛ𐦅. +B; xn----e3j6620g.xn--znd4948j.; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----e3j425bsk1o.xn--znd4948j.; [B1 B5 B6 C1 V3 V6]; [B1 B5 B6 C1 V3 V6] # ᠆몆-.Ⴛ𐦅. +T; ᠆몆\u200C-。ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.ⴛ𐦅︒ +N; ᠆몆\u200C-。ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.ⴛ𐦅︒ +T; ᠆몆\u200C-。ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᠆몆-.ⴛ𐦅︒ +N; ᠆몆\u200C-。ⴛ𐦅︒; [B1 B5 B6 C1 P1 V3 V6]; [B1 B5 B6 C1 P1 V3 V6] # ᠆몆-.ⴛ𐦅︒ +B; xn----e3j6620g.xn--jlj4997dhgh; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----e3j425bsk1o.xn--jlj4997dhgh; [B1 B5 B6 C1 V3 V6]; [B1 B5 B6 C1 V3 V6] # ᠆몆-.ⴛ𐦅︒ +B; xn----e3j6620g.xn--znd2362jhgh; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----e3j425bsk1o.xn--znd2362jhgh; [B1 B5 B6 C1 V3 V6]; [B1 B5 B6 C1 V3 V6] # ᠆몆-.Ⴛ𐦅︒ +T; 󠾳.︒⥱\u200C𐹬; [B1 C1 P1 V6]; [B1 P1 V6] # .︒⥱𐹬 +N; 󠾳.︒⥱\u200C𐹬; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .︒⥱𐹬 +T; 󠾳.。⥱\u200C𐹬; [B1 C1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ..⥱𐹬 +N; 󠾳.。⥱\u200C𐹬; [B1 C1 P1 V6 A4_2]; [B1 C1 P1 V6 A4_2] # ..⥱𐹬 +B; xn--uf66e..xn--qti2829e; [B1 V6 A4_2]; [B1 V6 A4_2] +B; xn--uf66e..xn--0ugz28as66q; [B1 C1 V6 A4_2]; [B1 C1 V6 A4_2] # ..⥱𐹬 +B; xn--uf66e.xn--qtiz073e3ik; [B1 V6]; [B1 V6] +B; xn--uf66e.xn--0ugz28axl3pqxna; [B1 C1 V6]; [B1 C1 V6] # .︒⥱𐹬 +B; 𐯖.𐹠Ⴑ񚇜𐫊; [B1 P1 V6]; [B1 P1 V6] +B; 𐯖.𐹠ⴑ񚇜𐫊; [B1 P1 V6]; [B1 P1 V6] +B; xn--n49c.xn--8kj8702ewicl862o; [B1 V6]; [B1 V6] +B; xn--n49c.xn--pnd4619jwicl862o; [B1 V6]; [B1 V6] +B; \u0FA4񱤯.𝟭Ⴛ; [P1 V5 V6]; [P1 V5 V6] # ྤ.1Ⴛ +B; \u0FA4񱤯.1Ⴛ; [P1 V5 V6]; [P1 V5 V6] # ྤ.1Ⴛ +B; \u0FA4񱤯.1ⴛ; [P1 V5 V6]; [P1 V5 V6] # ྤ.1ⴛ +B; xn--0fd40533g.xn--1-tws; [V5 V6]; [V5 V6] # ྤ.1ⴛ +B; xn--0fd40533g.xn--1-q1g; [V5 V6]; [V5 V6] # ྤ.1Ⴛ +B; \u0FA4񱤯.𝟭ⴛ; [P1 V5 V6]; [P1 V5 V6] # ྤ.1ⴛ +B; -\u0826齀。릿𐸋; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # -ࠦ齀.릿 +B; -\u0826齀。릿𐸋; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # -ࠦ齀.릿 +B; xn----6gd0617i.xn--7y2bm55m; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] # -ࠦ齀.릿 +T; 󠔊\u071C鹝꾗。񾵐\u200D\u200D⏃; [B1 B6 C2 P1 V6]; [B1 B6 P1 V6] # ܜ鹝꾗.⏃ +N; 󠔊\u071C鹝꾗。񾵐\u200D\u200D⏃; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ܜ鹝꾗.⏃ +T; 󠔊\u071C鹝꾗。񾵐\u200D\u200D⏃; [B1 B6 C2 P1 V6]; [B1 B6 P1 V6] # ܜ鹝꾗.⏃ +N; 󠔊\u071C鹝꾗。񾵐\u200D\u200D⏃; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ܜ鹝꾗.⏃ +B; xn--mnb6558e91kyq533a.xn--6mh27269e; [B1 B6 V6]; [B1 B6 V6] # ܜ鹝꾗.⏃ +B; xn--mnb6558e91kyq533a.xn--1uga46zs309y; [B1 B6 C2 V6]; [B1 B6 C2 V6] # ܜ鹝꾗.⏃ +B; ≮.-\u0708--; [B1 P1 V2 V3 V6]; [B1 P1 V2 V3 V6] # ≮.-܈-- +B; <\u0338.-\u0708--; [B1 P1 V2 V3 V6]; [B1 P1 V2 V3 V6] # ≮.-܈-- +B; ≮.-\u0708--; [B1 P1 V2 V3 V6]; [B1 P1 V2 V3 V6] # ≮.-܈-- +B; <\u0338.-\u0708--; [B1 P1 V2 V3 V6]; [B1 P1 V2 V3 V6] # ≮.-܈-- +B; xn--gdh.xn------eqf; [B1 V2 V3 V6]; [B1 V2 V3 V6] # ≮.-܈-- +T; 𐹸󠋳。\u200Dς𝟩; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.ς7 +N; 𐹸󠋳。\u200Dς𝟩; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.ς7 +T; 𐹸󠋳。\u200Dς7; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.ς7 +N; 𐹸󠋳。\u200Dς7; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.ς7 +T; 𐹸󠋳。\u200DΣ7; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.σ7 +N; 𐹸󠋳。\u200DΣ7; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.σ7 +T; 𐹸󠋳。\u200Dσ7; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.σ7 +N; 𐹸󠋳。\u200Dσ7; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.σ7 +B; xn--wo0di5177c.xn--7-zmb; [B1 V6]; [B1 V6] +B; xn--wo0di5177c.xn--7-zmb938s; [B1 C2 V6]; [B1 C2 V6] # 𐹸.σ7 +B; xn--wo0di5177c.xn--7-xmb248s; [B1 C2 V6]; [B1 C2 V6] # 𐹸.ς7 +T; 𐹸󠋳。\u200DΣ𝟩; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.σ7 +N; 𐹸󠋳。\u200DΣ𝟩; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.σ7 +T; 𐹸󠋳。\u200Dσ𝟩; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹸.σ7 +N; 𐹸󠋳。\u200Dσ𝟩; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹸.σ7 +T; ς򅜌8.𞭤; [P1 V6]; [P1 V6] +N; ς򅜌8.𞭤; [P1 V6]; [P1 V6] +T; ς򅜌8.𞭤; [P1 V6]; [P1 V6] +N; ς򅜌8.𞭤; [P1 V6]; [P1 V6] +B; Σ򅜌8.𞭤; [P1 V6]; [P1 V6] +B; σ򅜌8.𞭤; [P1 V6]; [P1 V6] +B; xn--8-zmb14974n.xn--su6h; [V6]; [V6] +B; xn--8-xmb44974n.xn--su6h; [V6]; [V6] +B; Σ򅜌8.𞭤; [P1 V6]; [P1 V6] +B; σ򅜌8.𞭤; [P1 V6]; [P1 V6] +T; \u200Cᡑ🄀\u0684.-𐫄𑲤; [B1 C1 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # ᡑ🄀ڄ.-𐫄𑲤 +N; \u200Cᡑ🄀\u0684.-𐫄𑲤; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # ᡑ🄀ڄ.-𐫄𑲤 +T; \u200Cᡑ0.\u0684.-𐫄𑲤; [B1 C1 V3]; [B1 V3] # ᡑ0.ڄ.-𐫄𑲤 +N; \u200Cᡑ0.\u0684.-𐫄𑲤; [B1 C1 V3]; [B1 C1 V3] # ᡑ0.ڄ.-𐫄𑲤 +B; xn--0-o7j.xn--9ib.xn----ek5i065b; [B1 V3]; [B1 V3] # ᡑ0.ڄ.-𐫄𑲤 +B; xn--0-o7j263b.xn--9ib.xn----ek5i065b; [B1 C1 V3]; [B1 C1 V3] # ᡑ0.ڄ.-𐫄𑲤 +B; xn--9ib722gbw95a.xn----ek5i065b; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] # ᡑ🄀ڄ.-𐫄𑲤 +B; xn--9ib722gvtfi563c.xn----ek5i065b; [B1 C1 V3 V6]; [B1 C1 V3 V6] # ᡑ🄀ڄ.-𐫄𑲤 +B; 𖠍。𐪿넯򞵲; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 𖠍。𐪿넯򞵲; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--4e9e.xn--l60bj21opd57g; [B2 B3 V6]; [B2 B3 V6] +B; ᠇Ⴘ。\u0603Ⴈ𝆊; [B1 P1 V6]; [B1 P1 V6] # ᠇Ⴘ.Ⴈ𝆊 +B; ᠇ⴘ。\u0603ⴈ𝆊; [B1 P1 V6]; [B1 P1 V6] # ᠇ⴘ.ⴈ𝆊 +B; xn--d6e009h.xn--lfb290rfu3z; [B1 V6]; [B1 V6] # ᠇ⴘ.ⴈ𝆊 +B; xn--wnd558a.xn--lfb465c1v87a; [B1 V6]; [B1 V6] # ᠇Ⴘ.Ⴈ𝆊 +B; ⒚󠋑𞤰。牣\u0667Ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # ⒚𞤰.牣٧Ⴜᣥ +B; 19.󠋑𞤰。牣\u0667Ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 19.𞤰.牣٧Ⴜᣥ +B; 19.󠋑𞤰。牣\u0667ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 19.𞤰.牣٧ⴜᣥ +B; 19.󠋑𞤎。牣\u0667Ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 19.𞤰.牣٧Ⴜᣥ +B; 19.xn--oe6h75760c.xn--gib404ccxgh00h; [B1 B5 V6]; [B1 B5 V6] # 19.𞤰.牣٧Ⴜᣥ +B; 19.xn--oe6h75760c.xn--gib285gtxo2l9d; [B1 B5 V6]; [B1 B5 V6] # 19.𞤰.牣٧ⴜᣥ +B; ⒚󠋑𞤰。牣\u0667ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # ⒚𞤰.牣٧ⴜᣥ +B; ⒚󠋑𞤎。牣\u0667Ⴜᣥ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # ⒚𞤰.牣٧Ⴜᣥ +B; xn--cthy466n29j3e.xn--gib404ccxgh00h; [B1 B5 V6]; [B1 B5 V6] # ⒚𞤰.牣٧Ⴜᣥ +B; xn--cthy466n29j3e.xn--gib285gtxo2l9d; [B1 B5 V6]; [B1 B5 V6] # ⒚𞤰.牣٧ⴜᣥ +B; -𐋱𐰽⒈.Ⴓ; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -𐋱𐰽1..Ⴓ; [B1 P1 V3 V6 A4_2]; [B1 P1 V3 V6 A4_2] +B; -𐋱𐰽1..ⴓ; [B1 V3 A4_2]; [B1 V3 A4_2] +B; xn---1-895nq11a..xn--blj; [B1 V3 A4_2]; [B1 V3 A4_2] +B; xn---1-895nq11a..xn--rnd; [B1 V3 V6 A4_2]; [B1 V3 V6 A4_2] +B; -𐋱𐰽⒈.ⴓ; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; xn----ecp0206g90h.xn--blj; [B1 V3 V6]; [B1 V3 V6] +B; xn----ecp0206g90h.xn--rnd; [B1 V3 V6]; [B1 V3 V6] +T; \u200C긃.榶-; [C1 V3]; [V3] # 긃.榶- +N; \u200C긃.榶-; [C1 V3]; [C1 V3] # 긃.榶- +T; \u200C긃.榶-; [C1 V3]; [V3] # 긃.榶- +N; \u200C긃.榶-; [C1 V3]; [C1 V3] # 긃.榶- +B; xn--ej0b.xn----d87b; [V3]; [V3] +B; xn--0ug3307c.xn----d87b; [C1 V3]; [C1 V3] # 긃.榶- +T; 뉓泓𜵽.\u09CD\u200D; [P1 V5 V6]; [P1 V5 V6] # 뉓泓.্ +N; 뉓泓𜵽.\u09CD\u200D; [P1 V5 V6]; [P1 V5 V6] # 뉓泓.্ +T; 뉓泓𜵽.\u09CD\u200D; [P1 V5 V6]; [P1 V5 V6] # 뉓泓.্ +N; 뉓泓𜵽.\u09CD\u200D; [P1 V5 V6]; [P1 V5 V6] # 뉓泓.্ +B; xn--lwwp69lqs7m.xn--b7b; [V5 V6]; [V5 V6] # 뉓泓.্ +B; xn--lwwp69lqs7m.xn--b7b605i; [V5 V6]; [V5 V6] # 뉓泓.্ +T; \u200D𐹴ß。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ß.ິ +N; \u200D𐹴ß。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ß.ິ +T; \u200D𐹴ß。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ß.ິ +N; \u200D𐹴ß。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ß.ິ +T; \u200D𐹴SS。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴SS。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +T; \u200D𐹴ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +T; \u200D𐹴Ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴Ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +B; xn--ss-ti3o.xn--57c638l8774i; [B1 V5 V6]; [B1 V5 V6] # 𐹴ss.ິ +B; xn--ss-l1t5169j.xn--57c638l8774i; [B1 C2 V5 V6]; [B1 C2 V5 V6] # 𐹴ss.ິ +B; xn--zca770nip7n.xn--57c638l8774i; [B1 C2 V5 V6]; [B1 C2 V5 V6] # 𐹴ß.ິ +T; \u200D𐹴SS。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴SS。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +T; \u200D𐹴ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +T; \u200D𐹴Ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𐹴ss.ິ +N; \u200D𐹴Ss。\u0EB4\u2B75񪅌; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𐹴ss.ິ +B; \u1B44.\u1BAA-≮≠; [P1 V5 V6]; [P1 V5 V6] # ᭄.᮪-≮≠ +B; \u1B44.\u1BAA-<\u0338=\u0338; [P1 V5 V6]; [P1 V5 V6] # ᭄.᮪-≮≠ +B; \u1B44.\u1BAA-≮≠; [P1 V5 V6]; [P1 V5 V6] # ᭄.᮪-≮≠ +B; \u1B44.\u1BAA-<\u0338=\u0338; [P1 V5 V6]; [P1 V5 V6] # ᭄.᮪-≮≠ +B; xn--1uf.xn----nmlz65aub; [V5 V6]; [V5 V6] # ᭄.᮪-≮≠ +B; \u1BF3Ⴑ\u115F.𑄴Ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳Ⴑ.𑄴Ⅎ +B; \u1BF3Ⴑ\u115F.𑄴Ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳Ⴑ.𑄴Ⅎ +B; \u1BF3ⴑ\u115F.𑄴ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳ⴑ.𑄴ⅎ +B; \u1BF3Ⴑ\u115F.𑄴ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳Ⴑ.𑄴ⅎ +B; xn--pnd26a55x.xn--73g3065g; [V5 V6]; [V5 V6] # ᯳Ⴑ.𑄴ⅎ +B; xn--osd925cvyn.xn--73g3065g; [V5 V6]; [V5 V6] # ᯳ⴑ.𑄴ⅎ +B; xn--pnd26a55x.xn--f3g7465g; [V5 V6]; [V5 V6] # ᯳Ⴑ.𑄴Ⅎ +B; \u1BF3ⴑ\u115F.𑄴ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳ⴑ.𑄴ⅎ +B; \u1BF3Ⴑ\u115F.𑄴ⅎ; [P1 V5 V6]; [P1 V5 V6] # ᯳Ⴑ.𑄴ⅎ +B; 𜉆。Ⴃ𐴣𐹹똯; [B5 P1 V6]; [B5 P1 V6] +B; 𜉆。Ⴃ𐴣𐹹똯; [B5 P1 V6]; [B5 P1 V6] +B; 𜉆。ⴃ𐴣𐹹똯; [B5 P1 V6]; [B5 P1 V6] +B; 𜉆。ⴃ𐴣𐹹똯; [B5 P1 V6]; [B5 P1 V6] +B; xn--187g.xn--ukjy205b8rscdeb; [B5 V6]; [B5 V6] +B; xn--187g.xn--bnd4785f8r8bdeb; [B5 V6]; [B5 V6] +B; 𐫀。⳻󠙾󠄷\u3164; [B1 P1 V6]; [B1 P1 V6] # 𐫀.⳻ +B; 𐫀。⳻󠙾󠄷\u1160; [B1 P1 V6]; [B1 P1 V6] # 𐫀.⳻ +B; xn--pw9c.xn--psd742lxt32w; [B1 V6]; [B1 V6] # 𐫀.⳻ +B; xn--pw9c.xn--mkj83l4v899a; [B1 V6]; [B1 V6] # 𐫀.⳻ +B; \u079A⾇.\u071E-𐋰; [B2 B3]; [B2 B3] # ޚ舛.ܞ-𐋰 +B; \u079A舛.\u071E-𐋰; [B2 B3]; [B2 B3] # ޚ舛.ܞ-𐋰 +B; xn--7qb6383d.xn----20c3154q; [B2 B3]; [B2 B3] # ޚ舛.ܞ-𐋰 +B; Ⴉ猕󹛫≮.︒; [P1 V6]; [P1 V6] +B; Ⴉ猕󹛫<\u0338.︒; [P1 V6]; [P1 V6] +B; Ⴉ猕󹛫≮.。; [P1 V6 A4_2]; [P1 V6 A4_2] +B; Ⴉ猕󹛫<\u0338.。; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ⴉ猕󹛫<\u0338.。; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ⴉ猕󹛫≮.。; [P1 V6 A4_2]; [P1 V6 A4_2] +B; xn--gdh892bbz0d5438s..; [V6 A4_2]; [V6 A4_2] +B; xn--hnd212gz32d54x5r..; [V6 A4_2]; [V6 A4_2] +B; ⴉ猕󹛫<\u0338.︒; [P1 V6]; [P1 V6] +B; ⴉ猕󹛫≮.︒; [P1 V6]; [P1 V6] +B; xn--gdh892bbz0d5438s.xn--y86c; [V6]; [V6] +B; xn--hnd212gz32d54x5r.xn--y86c; [V6]; [V6] +B; 🏮。\u062B鳳\u07E2󠅉; [B1 B2]; [B1 B2] # 🏮.ث鳳ߢ +B; 🏮。\u062B鳳\u07E2󠅉; [B1 B2]; [B1 B2] # 🏮.ث鳳ߢ +B; xn--8m8h.xn--qgb29f6z90a; [B1 B2]; [B1 B2] # 🏮.ث鳳ߢ +T; \u200D𐹶。ß; [B1 C2]; [B1] # 𐹶.ß +N; \u200D𐹶。ß; [B1 C2]; [B1 C2] # 𐹶.ß +T; \u200D𐹶。SS; [B1 C2]; [B1] # 𐹶.ss +N; \u200D𐹶。SS; [B1 C2]; [B1 C2] # 𐹶.ss +T; \u200D𐹶。ss; [B1 C2]; [B1] # 𐹶.ss +N; \u200D𐹶。ss; [B1 C2]; [B1 C2] # 𐹶.ss +T; \u200D𐹶。Ss; [B1 C2]; [B1] # 𐹶.ss +N; \u200D𐹶。Ss; [B1 C2]; [B1 C2] # 𐹶.ss +B; xn--uo0d.ss; [B1]; [B1] +B; xn--1ug9105g.ss; [B1 C2]; [B1 C2] # 𐹶.ss +B; xn--1ug9105g.xn--zca; [B1 C2]; [B1 C2] # 𐹶.ß +T; Å둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; Å둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; A\u030A둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; A\u030A둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; Å둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; Å둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; A\u030A둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; A\u030A둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; a\u030A둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; a\u030A둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; å둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; å둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +B; xn----1fa1788k.; [V3]; [V3] +B; xn----1fa1788k.xn--0ug; [C1 V3]; [C1 V3] # å둄-. +T; a\u030A둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; a\u030A둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +T; å둄-.\u200C; [C1 V3]; [V3] # å둄-. +N; å둄-.\u200C; [C1 V3]; [C1 V3] # å둄-. +B; \u3099򬎑\u1DD7𞤀.򱲢-\u0953; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # ゙ᷗ𞤢.-॓ +B; \u3099򬎑\u1DD7𞤢.򱲢-\u0953; [B1 B6 P1 V5 V6]; [B1 B6 P1 V5 V6] # ゙ᷗ𞤢.-॓ +B; xn--veg121fwg63altj9d.xn----eyd92688s; [B1 B6 V5 V6]; [B1 B6 V5 V6] # ゙ᷗ𞤢.-॓ +T; ς.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ς.ß⵿ +N; ς.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ς.ß⵿ +B; Σ.SS񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ss⵿ +B; σ.ss񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ss⵿ +B; Σ.ss񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ss⵿ +B; xn--4xa.xn--ss-y8d4760biv60n; [B5 B6 V6]; [B5 B6 V6] # σ.ss⵿ +T; Σ.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ß⵿ +N; Σ.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ß⵿ +T; σ.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ß⵿ +N; σ.ß񴱄\u06DD\u2D7F; [B5 B6 P1 V6]; [B5 B6 P1 V6] # σ.ß⵿ +B; xn--4xa.xn--zca281az71b8x73m; [B5 B6 V6]; [B5 B6 V6] # σ.ß⵿ +B; xn--3xa.xn--zca281az71b8x73m; [B5 B6 V6]; [B5 B6 V6] # ς.ß⵿ +B; ꡀ𞀟。\u066B\u0599; [B1]; [B1] # ꡀ𞀟.٫֙ +B; ꡀ𞀟。\u066B\u0599; [B1]; [B1] # ꡀ𞀟.٫֙ +B; xn--8b9a1720d.xn--kcb33b; [B1]; [B1] # ꡀ𞀟.٫֙ +T; 򈛉\u200C\u08A9。⧅񘘡-𐭡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # ࢩ.⧅-𐭡 +N; 򈛉\u200C\u08A9。⧅񘘡-𐭡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # ࢩ.⧅-𐭡 +T; 򈛉\u200C\u08A9。⧅񘘡-𐭡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # ࢩ.⧅-𐭡 +N; 򈛉\u200C\u08A9。⧅񘘡-𐭡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # ࢩ.⧅-𐭡 +B; xn--yyb56242i.xn----zir1232guu71b; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ࢩ.⧅-𐭡 +B; xn--yyb780jll63m.xn----zir1232guu71b; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # ࢩ.⧅-𐭡 +T; 룱\u200D𰍨\u200C。𝨖︒; [C1 C2 P1 V5 V6]; [P1 V5 V6] # 룱.𝨖︒ +N; 룱\u200D𰍨\u200C。𝨖︒; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # 룱.𝨖︒ +T; 룱\u200D𰍨\u200C。𝨖︒; [C1 C2 P1 V5 V6]; [P1 V5 V6] # 룱.𝨖︒ +N; 룱\u200D𰍨\u200C。𝨖︒; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # 룱.𝨖︒ +T; 룱\u200D𰍨\u200C。𝨖。; [C1 C2 P1 V5 V6]; [P1 V5 V6] # 룱.𝨖. +N; 룱\u200D𰍨\u200C。𝨖。; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # 룱.𝨖. +T; 룱\u200D𰍨\u200C。𝨖。; [C1 C2 P1 V5 V6]; [P1 V5 V6] # 룱.𝨖. +N; 룱\u200D𰍨\u200C。𝨖。; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # 룱.𝨖. +B; xn--ct2b0738h.xn--772h.; [V5 V6]; [V5 V6] +B; xn--0ugb3358ili2v.xn--772h.; [C1 C2 V5 V6]; [C1 C2 V5 V6] # 룱.𝨖. +B; xn--ct2b0738h.xn--y86cl899a; [V5 V6]; [V5 V6] +B; xn--0ugb3358ili2v.xn--y86cl899a; [C1 C2 V5 V6]; [C1 C2 V5 V6] # 룱.𝨖︒ +T; 🄄.\u1CDC⒈ß; [P1 V5 V6]; [P1 V5 V6] # 🄄.᳜⒈ß +N; 🄄.\u1CDC⒈ß; [P1 V5 V6]; [P1 V5 V6] # 🄄.᳜⒈ß +T; 3,.\u1CDC1.ß; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ß +N; 3,.\u1CDC1.ß; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ß +B; 3,.\u1CDC1.SS; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ss +B; 3,.\u1CDC1.ss; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ss +B; 3,.\u1CDC1.Ss; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ss +B; 3,.xn--1-43l.ss; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ss +B; 3,.xn--1-43l.xn--zca; [P1 V5 V6]; [P1 V5 V6] # 3,.᳜1.ß +B; 🄄.\u1CDC⒈SS; [P1 V5 V6]; [P1 V5 V6] # 🄄.᳜⒈ss +B; 🄄.\u1CDC⒈ss; [P1 V5 V6]; [P1 V5 V6] # 🄄.᳜⒈ss +B; 🄄.\u1CDC⒈Ss; [P1 V5 V6]; [P1 V5 V6] # 🄄.᳜⒈ss +B; xn--x07h.xn--ss-k1r094b; [V5 V6]; [V5 V6] # 🄄.᳜⒈ss +B; xn--x07h.xn--zca344lmif; [V5 V6]; [V5 V6] # 🄄.᳜⒈ß +B; 񇌍\u2D7F。𞼓򡄨𑐺; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ⵿.𑐺 +B; 񇌍\u2D7F。𞼓򡄨𑐺; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ⵿.𑐺 +B; xn--eoj16016a.xn--0v1d3848a3lr0d; [B2 B3 V6]; [B2 B3 V6] # ⵿.𑐺 +T; \u1DFD\u103A\u094D.≠\u200D㇛; [C2 P1 V5 V6]; [P1 V5 V6] # ်्᷽.≠㇛ +N; \u1DFD\u103A\u094D.≠\u200D㇛; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ်्᷽.≠㇛ +T; \u103A\u094D\u1DFD.≠\u200D㇛; [C2 P1 V5 V6]; [P1 V5 V6] # ်्᷽.≠㇛ +N; \u103A\u094D\u1DFD.≠\u200D㇛; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ်्᷽.≠㇛ +T; \u103A\u094D\u1DFD.=\u0338\u200D㇛; [C2 P1 V5 V6]; [P1 V5 V6] # ်्᷽.≠㇛ +N; \u103A\u094D\u1DFD.=\u0338\u200D㇛; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ်्᷽.≠㇛ +T; \u103A\u094D\u1DFD.≠\u200D㇛; [C2 P1 V5 V6]; [P1 V5 V6] # ်्᷽.≠㇛ +N; \u103A\u094D\u1DFD.≠\u200D㇛; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ်्᷽.≠㇛ +T; \u103A\u094D\u1DFD.=\u0338\u200D㇛; [C2 P1 V5 V6]; [P1 V5 V6] # ်्᷽.≠㇛ +N; \u103A\u094D\u1DFD.=\u0338\u200D㇛; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ်्᷽.≠㇛ +B; xn--n3b956a9zm.xn--1ch912d; [V5 V6]; [V5 V6] # ်्᷽.≠㇛ +B; xn--n3b956a9zm.xn--1ug63gz5w; [C2 V5 V6]; [C2 V5 V6] # ်्᷽.≠㇛ +T; Ⴁ𐋨娤.\u200D\u033C\u0662𑖿; [B1 C2 P1 V6]; [B1 P1 V5 V6] # Ⴁ𐋨娤.̼٢𑖿 +N; Ⴁ𐋨娤.\u200D\u033C\u0662𑖿; [B1 C2 P1 V6]; [B1 C2 P1 V6] # Ⴁ𐋨娤.̼٢𑖿 +T; ⴁ𐋨娤.\u200D\u033C\u0662𑖿; [B1 C2]; [B1 V5] # ⴁ𐋨娤.̼٢𑖿 +N; ⴁ𐋨娤.\u200D\u033C\u0662𑖿; [B1 C2]; [B1 C2] # ⴁ𐋨娤.̼٢𑖿 +B; xn--skjw75lg29h.xn--9ta62nrv36a; [B1 V5]; [B1 V5] # ⴁ𐋨娤.̼٢𑖿 +B; xn--skjw75lg29h.xn--9ta62ngt6aou8t; [B1 C2]; [B1 C2] # ⴁ𐋨娤.̼٢𑖿 +B; xn--8md2578ag21g.xn--9ta62nrv36a; [B1 V5 V6]; [B1 V5 V6] # Ⴁ𐋨娤.̼٢𑖿 +B; xn--8md2578ag21g.xn--9ta62ngt6aou8t; [B1 C2 V6]; [B1 C2 V6] # Ⴁ𐋨娤.̼٢𑖿 +T; 🄀Ⴄ\u0669\u0820。⒈\u0FB6ß; [B1 P1 V6]; [B1 P1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶß +N; 🄀Ⴄ\u0669\u0820。⒈\u0FB6ß; [B1 P1 V6]; [B1 P1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶß +T; 0.Ⴄ\u0669\u0820。1.\u0FB6ß; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶß +N; 0.Ⴄ\u0669\u0820。1.\u0FB6ß; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶß +T; 0.ⴄ\u0669\u0820。1.\u0FB6ß; [B1 B5 B6 V5]; [B1 B5 B6 V5] # 0.ⴄ٩ࠠ.1.ྶß +N; 0.ⴄ\u0669\u0820。1.\u0FB6ß; [B1 B5 B6 V5]; [B1 B5 B6 V5] # 0.ⴄ٩ࠠ.1.ྶß +B; 0.Ⴄ\u0669\u0820。1.\u0FB6SS; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶss +B; 0.ⴄ\u0669\u0820。1.\u0FB6ss; [B1 B5 B6 V5]; [B1 B5 B6 V5] # 0.ⴄ٩ࠠ.1.ྶss +B; 0.Ⴄ\u0669\u0820。1.\u0FB6Ss; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶss +B; 0.xn--iib29f26o.1.xn--ss-1sj; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶss +B; 0.xn--iib29fp25e.1.xn--ss-1sj; [B1 B5 B6 V5]; [B1 B5 B6 V5] # 0.ⴄ٩ࠠ.1.ྶss +B; 0.xn--iib29fp25e.1.xn--zca117e; [B1 B5 B6 V5]; [B1 B5 B6 V5] # 0.ⴄ٩ࠠ.1.ྶß +B; 0.xn--iib29f26o.1.xn--zca117e; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # 0.Ⴄ٩ࠠ.1.ྶß +T; 🄀ⴄ\u0669\u0820。⒈\u0FB6ß; [B1 P1 V6]; [B1 P1 V6] # 🄀ⴄ٩ࠠ.⒈ྶß +N; 🄀ⴄ\u0669\u0820。⒈\u0FB6ß; [B1 P1 V6]; [B1 P1 V6] # 🄀ⴄ٩ࠠ.⒈ྶß +B; 🄀Ⴄ\u0669\u0820。⒈\u0FB6SS; [B1 P1 V6]; [B1 P1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶss +B; 🄀ⴄ\u0669\u0820。⒈\u0FB6ss; [B1 P1 V6]; [B1 P1 V6] # 🄀ⴄ٩ࠠ.⒈ྶss +B; 🄀Ⴄ\u0669\u0820。⒈\u0FB6Ss; [B1 P1 V6]; [B1 P1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶss +B; xn--iib29f26o6n43c.xn--ss-1sj588o; [B1 V6]; [B1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶss +B; xn--iib29fp25e0219a.xn--ss-1sj588o; [B1 V6]; [B1 V6] # 🄀ⴄ٩ࠠ.⒈ྶss +B; xn--iib29fp25e0219a.xn--zca117e3vp; [B1 V6]; [B1 V6] # 🄀ⴄ٩ࠠ.⒈ྶß +B; xn--iib29f26o6n43c.xn--zca117e3vp; [B1 V6]; [B1 V6] # 🄀Ⴄ٩ࠠ.⒈ྶß +T; ≠.\u200C-\u066B; [B1 C1 P1 V6]; [B1 P1 V3 V6] # ≠.-٫ +N; ≠.\u200C-\u066B; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.-٫ +T; =\u0338.\u200C-\u066B; [B1 C1 P1 V6]; [B1 P1 V3 V6] # ≠.-٫ +N; =\u0338.\u200C-\u066B; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.-٫ +B; xn--1ch.xn----vqc; [B1 V3 V6]; [B1 V3 V6] # ≠.-٫ +B; xn--1ch.xn----vqc597q; [B1 C1 V6]; [B1 C1 V6] # ≠.-٫ +B; \u0660۱。󠳶𞠁\u0665; [B1 P1 V6]; [B1 P1 V6] # ٠۱.𞠁٥ +B; \u0660۱。󠳶𞠁\u0665; [B1 P1 V6]; [B1 P1 V6] # ٠۱.𞠁٥ +B; xn--8hb40a.xn--eib7967vner3e; [B1 V6]; [B1 V6] # ٠۱.𞠁٥ +T; \u200C\u0663⒖。󱅉𽷛\u1BF3; [B1 C1 P1 V6]; [B1 P1 V6] # ٣⒖.᯳ +N; \u200C\u0663⒖。󱅉𽷛\u1BF3; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ٣⒖.᯳ +T; \u200C\u066315.。󱅉𽷛\u1BF3; [B1 C1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ٣15..᯳ +N; \u200C\u066315.。󱅉𽷛\u1BF3; [B1 C1 P1 V6 A4_2]; [B1 C1 P1 V6 A4_2] # ٣15..᯳ +B; xn--15-gyd..xn--1zf13512buy41d; [B1 V6 A4_2]; [B1 V6 A4_2] # ٣15..᯳ +B; xn--15-gyd983x..xn--1zf13512buy41d; [B1 C1 V6 A4_2]; [B1 C1 V6 A4_2] # ٣15..᯳ +B; xn--cib675m.xn--1zf13512buy41d; [B1 V6]; [B1 V6] # ٣⒖.᯳ +B; xn--cib152kwgd.xn--1zf13512buy41d; [B1 C1 V6]; [B1 C1 V6] # ٣⒖.᯳ +B; \u1BF3.-逋񳦭󙙮; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ᯳.-逋 +B; xn--1zf.xn----483d46987byr50b; [V3 V5 V6]; [V3 V5 V6] # ᯳.-逋 +T; \u0756。\u3164\u200Dς; [C2 P1 V6]; [P1 V6] # ݖ.ς +N; \u0756。\u3164\u200Dς; [C2 P1 V6]; [C2 P1 V6] # ݖ.ς +T; \u0756。\u1160\u200Dς; [C2 P1 V6]; [P1 V6] # ݖ.ς +N; \u0756。\u1160\u200Dς; [C2 P1 V6]; [C2 P1 V6] # ݖ.ς +T; \u0756。\u1160\u200DΣ; [C2 P1 V6]; [P1 V6] # ݖ.σ +N; \u0756。\u1160\u200DΣ; [C2 P1 V6]; [C2 P1 V6] # ݖ.σ +T; \u0756。\u1160\u200Dσ; [C2 P1 V6]; [P1 V6] # ݖ.σ +N; \u0756。\u1160\u200Dσ; [C2 P1 V6]; [C2 P1 V6] # ݖ.σ +B; xn--9ob.xn--4xa380e; [V6]; [V6] # ݖ.σ +B; xn--9ob.xn--4xa380ebol; [C2 V6]; [C2 V6] # ݖ.σ +B; xn--9ob.xn--3xa580ebol; [C2 V6]; [C2 V6] # ݖ.ς +T; \u0756。\u3164\u200DΣ; [C2 P1 V6]; [P1 V6] # ݖ.σ +N; \u0756。\u3164\u200DΣ; [C2 P1 V6]; [C2 P1 V6] # ݖ.σ +T; \u0756。\u3164\u200Dσ; [C2 P1 V6]; [P1 V6] # ݖ.σ +N; \u0756。\u3164\u200Dσ; [C2 P1 V6]; [C2 P1 V6] # ݖ.σ +B; xn--9ob.xn--4xa574u; [V6]; [V6] # ݖ.σ +B; xn--9ob.xn--4xa795lq2l; [C2 V6]; [C2 V6] # ݖ.σ +B; xn--9ob.xn--3xa995lq2l; [C2 V6]; [C2 V6] # ݖ.ς +T; ᡆႣ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [P1 V6] # ᡆႣ.̕ +N; ᡆႣ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡆႣ.̕ +T; ᡆႣ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [P1 V6] # ᡆႣ.̕ +N; ᡆႣ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡆႣ.̕ +T; ᡆⴃ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [P1 V6] # ᡆⴃ.̕ +N; ᡆⴃ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡆⴃ.̕ +B; xn--57e237h.xn--5sa98523p; [V6]; [V6] # ᡆⴃ.̕ +B; xn--57e237h.xn--5sa649la993427a; [C2 V6]; [C2 V6] # ᡆⴃ.̕ +B; xn--bnd320b.xn--5sa98523p; [V6]; [V6] # ᡆႣ.̕ +B; xn--bnd320b.xn--5sa649la993427a; [C2 V6]; [C2 V6] # ᡆႣ.̕ +T; ᡆⴃ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [P1 V6] # ᡆⴃ.̕ +N; ᡆⴃ。󞢧\u0315\u200D\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡆⴃ.̕ +T; 㭄\u200D\u084F𑚵.ς𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.ς𐮮 +N; 㭄\u200D\u084F𑚵.ς𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.ς𐮮 +T; 㭄\u200D\u084F𑚵.ς𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.ς𐮮 +N; 㭄\u200D\u084F𑚵.ς𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.ς𐮮 +T; 㭄\u200D\u084F𑚵.Σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.σ𐮮 +N; 㭄\u200D\u084F𑚵.Σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.σ𐮮 +T; 㭄\u200D\u084F𑚵.σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.σ𐮮 +N; 㭄\u200D\u084F𑚵.σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.σ𐮮 +B; xn--ewb302xhu1l.xn--4xa0426k; [B5 B6]; [B5 B6] # 㭄ࡏ𑚵.σ𐮮 +B; xn--ewb962jfitku4r.xn--4xa695lda6932v; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.σ𐮮 +B; xn--ewb962jfitku4r.xn--3xa895lda6932v; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.ς𐮮 +T; 㭄\u200D\u084F𑚵.Σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.σ𐮮 +N; 㭄\u200D\u084F𑚵.Σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.σ𐮮 +T; 㭄\u200D\u084F𑚵.σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6] # 㭄ࡏ𑚵.σ𐮮 +N; 㭄\u200D\u084F𑚵.σ𐮮\u200C\u200D; [B5 B6 C1 C2]; [B5 B6 C1 C2] # 㭄ࡏ𑚵.σ𐮮 +B; \u17B5。𞯸ꡀ🄋; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # .ꡀ🄋 +B; xn--03e.xn--8b9ar252dngd; [B1 B2 B3 B6 V5 V6]; [B1 B2 B3 B6 V5 V6] # .ꡀ🄋 +B; 󐪺暑.⾑\u0668; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 暑.襾٨ +B; 󐪺暑.襾\u0668; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 暑.襾٨ +B; xn--tlvq3513e.xn--hib9228d; [B5 B6 V6]; [B5 B6 V6] # 暑.襾٨ +B; 󠄚≯ꡢ。\u0891\u1DFF; [B1 P1 V6]; [B1 P1 V6] # ≯ꡢ.᷿ +B; 󠄚>\u0338ꡢ。\u0891\u1DFF; [B1 P1 V6]; [B1 P1 V6] # ≯ꡢ.᷿ +B; xn--hdh7783c.xn--9xb680i; [B1 V6]; [B1 V6] # ≯ꡢ.᷿ +B; \uFDC3𮁱\u0B4D𐨿.󐧤Ⴗ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # كمم𮁱୍𐨿.Ⴗ +B; \u0643\u0645\u0645𮁱\u0B4D𐨿.󐧤Ⴗ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # كمم𮁱୍𐨿.Ⴗ +B; \u0643\u0645\u0645𮁱\u0B4D𐨿.󐧤ⴗ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # كمم𮁱୍𐨿.ⴗ +B; xn--fhbea662czx68a2tju.xn--fljz2846h; [B2 B3 V6]; [B2 B3 V6] # كمم𮁱୍𐨿.ⴗ +B; xn--fhbea662czx68a2tju.xn--vnd55511o; [B2 B3 V6]; [B2 B3 V6] # كمم𮁱୍𐨿.Ⴗ +B; \uFDC3𮁱\u0B4D𐨿.󐧤ⴗ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # كمم𮁱୍𐨿.ⴗ +B; 𞀨。\u1B44򡛨𞎇; [P1 V5 V6]; [P1 V5 V6] # 𞀨.᭄ +B; 𞀨。\u1B44򡛨𞎇; [P1 V5 V6]; [P1 V5 V6] # 𞀨.᭄ +B; xn--mi4h.xn--1uf6843smg20c; [V5 V6]; [V5 V6] # 𞀨.᭄ +T; 󠣼\u200C.𐺰\u200Cᡟ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # .ᡟ +N; 󠣼\u200C.𐺰\u200Cᡟ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .ᡟ +T; 󠣼\u200C.𐺰\u200Cᡟ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # .ᡟ +N; 󠣼\u200C.𐺰\u200Cᡟ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .ᡟ +B; xn--q046e.xn--v8e7227j; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; xn--0ug18531l.xn--v8e340bp21t; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # .ᡟ +T; ᢛ󨅟ß.ጧ; [P1 V6]; [P1 V6] +N; ᢛ󨅟ß.ጧ; [P1 V6]; [P1 V6] +B; ᢛ󨅟SS.ጧ; [P1 V6]; [P1 V6] +B; ᢛ󨅟ss.ጧ; [P1 V6]; [P1 V6] +B; ᢛ󨅟Ss.ጧ; [P1 V6]; [P1 V6] +B; xn--ss-7dp66033t.xn--p5d; [V6]; [V6] +B; xn--zca562jc642x.xn--p5d; [V6]; [V6] +T; ⮒\u200C.񒚗\u200C; [C1 P1 V6]; [P1 V6] # ⮒. +N; ⮒\u200C.񒚗\u200C; [C1 P1 V6]; [C1 P1 V6] # ⮒. +B; xn--b9i.xn--5p9y; [V6]; [V6] +B; xn--0ugx66b.xn--0ugz2871c; [C1 V6]; [C1 V6] # ⮒. +B; 𞤂񹞁𐹯。Ⴜ; [B2 P1 V6]; [B2 P1 V6] +B; 𞤤񹞁𐹯。ⴜ; [B2 P1 V6]; [B2 P1 V6] +B; xn--no0dr648a51o3b.xn--klj; [B2 V6]; [B2 V6] +B; xn--no0dr648a51o3b.xn--0nd; [B2 V6]; [B2 V6] +B; 𞤂񹞁𐹯。ⴜ; [B2 P1 V6]; [B2 P1 V6] +T; 𐹵⮣\u200C𑄰。񷴿\uFCB7; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹵⮣𑄰.ضم +N; 𐹵⮣\u200C𑄰。񷴿\uFCB7; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # 𐹵⮣𑄰.ضم +T; 𐹵⮣\u200C𑄰。񷴿\u0636\u0645; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹵⮣𑄰.ضم +N; 𐹵⮣\u200C𑄰。񷴿\u0636\u0645; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # 𐹵⮣𑄰.ضم +B; xn--s9i5458e7yb.xn--1gb4a66004i; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 𐹵⮣𑄰.ضم +B; xn--0ug586bcj8p7jc.xn--1gb4a66004i; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # 𐹵⮣𑄰.ضم +T; Ⴒ。デß𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デß𞤵్ +N; Ⴒ。デß𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デß𞤵్ +T; Ⴒ。テ\u3099ß𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デß𞤵్ +N; Ⴒ。テ\u3099ß𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デß𞤵్ +T; ⴒ。テ\u3099ß𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デß𞤵్ +N; ⴒ。テ\u3099ß𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デß𞤵్ +T; ⴒ。デß𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デß𞤵్ +N; ⴒ。デß𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デß𞤵్ +B; Ⴒ。デSS𞤓\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; Ⴒ。テ\u3099SS𞤓\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; ⴒ。テ\u3099ss𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デss𞤵్ +B; ⴒ。デss𞤵\u0C4D; [B5 B6]; [B5 B6] # ⴒ.デss𞤵్ +B; Ⴒ。デSs𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; Ⴒ。テ\u3099Ss𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; xn--qnd.xn--ss-9nh3648ahh20b; [B5 B6 V6]; [B5 B6 V6] # Ⴒ.デss𞤵్ +B; xn--9kj.xn--ss-9nh3648ahh20b; [B5 B6]; [B5 B6] # ⴒ.デss𞤵్ +B; xn--9kj.xn--zca669cmr3a0f28a; [B5 B6]; [B5 B6] # ⴒ.デß𞤵్ +B; xn--qnd.xn--zca669cmr3a0f28a; [B5 B6 V6]; [B5 B6 V6] # Ⴒ.デß𞤵్ +B; Ⴒ。デSS𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; Ⴒ。テ\u3099SS𞤵\u0C4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴒ.デss𞤵్ +B; 𑁿\u0D4D.7-\u07D2; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𑁿്.7-ߒ +B; 𑁿\u0D4D.7-\u07D2; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𑁿്.7-ߒ +B; xn--wxc1283k.xn--7--yue; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𑁿്.7-ߒ +B; ≯𑜫󠭇.\u1734񒞤𑍬ᢧ; [P1 V5 V6]; [P1 V5 V6] # ≯𑜫.᜴𑍬ᢧ +B; >\u0338𑜫󠭇.\u1734񒞤𑍬ᢧ; [P1 V5 V6]; [P1 V5 V6] # ≯𑜫.᜴𑍬ᢧ +B; xn--hdhx157g68o0g.xn--c0e65eu616c34o7a; [V5 V6]; [V5 V6] # ≯𑜫.᜴𑍬ᢧ +B; \u1DDB򎐙Ⴗ쏔。\u0781; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᷛႷ쏔.ށ +B; \u1DDB򎐙Ⴗ쏔。\u0781; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᷛႷ쏔.ށ +B; \u1DDB򎐙ⴗ쏔。\u0781; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᷛⴗ쏔.ށ +B; \u1DDB򎐙ⴗ쏔。\u0781; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᷛⴗ쏔.ށ +B; xn--zegy26dw47iy6w2f.xn--iqb; [B1 V5 V6]; [B1 V5 V6] # ᷛⴗ쏔.ށ +B; xn--vnd148d733ky6n9e.xn--iqb; [B1 V5 V6]; [B1 V5 V6] # ᷛႷ쏔.ށ +T; ß。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ß.𐋳Ⴌྸ +N; ß。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ß.𐋳Ⴌྸ +T; ß。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ß.𐋳Ⴌྸ +N; ß。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ß.𐋳Ⴌྸ +T; ß。𐋳ⴌ\u0FB8; ß.𐋳ⴌ\u0FB8; ss.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +N; ß。𐋳ⴌ\u0FB8; ß.𐋳ⴌ\u0FB8; xn--zca.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +B; SS。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +B; ss。𐋳ⴌ\u0FB8; ss.𐋳ⴌ\u0FB8; ss.xn--lgd921mvv0m; NV8 # ss.𐋳ⴌྸ +B; Ss。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +B; ss.xn--lgd10cu829c; [V6]; [V6] # ss.𐋳Ⴌྸ +B; ss.xn--lgd921mvv0m; ss.𐋳ⴌ\u0FB8; ss.xn--lgd921mvv0m; NV8 # ss.𐋳ⴌྸ +B; ss.𐋳ⴌ\u0FB8; ; ss.xn--lgd921mvv0m; NV8 # ss.𐋳ⴌྸ +B; SS.𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +B; Ss.𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +B; xn--zca.xn--lgd921mvv0m; ß.𐋳ⴌ\u0FB8; xn--zca.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +T; ß.𐋳ⴌ\u0FB8; ; ss.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +N; ß.𐋳ⴌ\u0FB8; ; xn--zca.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +B; xn--zca.xn--lgd10cu829c; [V6]; [V6] # ß.𐋳Ⴌྸ +T; ß。𐋳ⴌ\u0FB8; ß.𐋳ⴌ\u0FB8; ss.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +N; ß。𐋳ⴌ\u0FB8; ß.𐋳ⴌ\u0FB8; xn--zca.xn--lgd921mvv0m; NV8 # ß.𐋳ⴌྸ +B; SS。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +B; ss。𐋳ⴌ\u0FB8; ss.𐋳ⴌ\u0FB8; ss.xn--lgd921mvv0m; NV8 # ss.𐋳ⴌྸ +B; Ss。𐋳Ⴌ\u0FB8; [P1 V6]; [P1 V6] # ss.𐋳Ⴌྸ +T; -\u069E𐶡.\u200C⾝\u09CD; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ڞ.身্ +N; -\u069E𐶡.\u200C⾝\u09CD; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ڞ.身্ +T; -\u069E𐶡.\u200C身\u09CD; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ڞ.身্ +N; -\u069E𐶡.\u200C身\u09CD; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ڞ.身্ +B; xn----stc7013r.xn--b7b1419d; [B1 V3 V6]; [B1 V3 V6] # -ڞ.身্ +B; xn----stc7013r.xn--b7b305imj2f; [B1 C1 V3 V6]; [B1 C1 V3 V6] # -ڞ.身্ +T; 😮\u0764𑈵𞀖.💅\u200D; [B1 C2]; [B1] # 😮ݤ𑈵𞀖.💅 +N; 😮\u0764𑈵𞀖.💅\u200D; [B1 C2]; [B1 C2] # 😮ݤ𑈵𞀖.💅 +T; 😮\u0764𑈵𞀖.💅\u200D; [B1 C2]; [B1] # 😮ݤ𑈵𞀖.💅 +N; 😮\u0764𑈵𞀖.💅\u200D; [B1 C2]; [B1 C2] # 😮ݤ𑈵𞀖.💅 +B; xn--opb4277kuc7elqsa.xn--kr8h; [B1]; [B1] # 😮ݤ𑈵𞀖.💅 +B; xn--opb4277kuc7elqsa.xn--1ug5265p; [B1 C2]; [B1 C2] # 😮ݤ𑈵𞀖.💅 +T; \u08F2\u200D꙳\u0712.ᢏ\u200C󠍄; [B1 B6 C1 C2 P1 V5 V6]; [B1 B6 P1 V5 V6] # ࣲ꙳ܒ.ᢏ +N; \u08F2\u200D꙳\u0712.ᢏ\u200C󠍄; [B1 B6 C1 C2 P1 V5 V6]; [B1 B6 C1 C2 P1 V5 V6] # ࣲ꙳ܒ.ᢏ +B; xn--cnb37gdy00a.xn--89e02253p; [B1 B6 V5 V6]; [B1 B6 V5 V6] # ࣲ꙳ܒ.ᢏ +B; xn--cnb37g904be26j.xn--89e849ax9363a; [B1 B6 C1 C2 V5 V6]; [B1 B6 C1 C2 V5 V6] # ࣲ꙳ܒ.ᢏ +B; Ⴑ.\u06BF𞯓ᠲ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # Ⴑ.ڿᠲ +B; Ⴑ.\u06BF𞯓ᠲ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # Ⴑ.ڿᠲ +B; ⴑ.\u06BF𞯓ᠲ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ⴑ.ڿᠲ +B; xn--8kj.xn--ykb840gd555a; [B2 B3 V6]; [B2 B3 V6] # ⴑ.ڿᠲ +B; xn--pnd.xn--ykb840gd555a; [B2 B3 V6]; [B2 B3 V6] # Ⴑ.ڿᠲ +B; ⴑ.\u06BF𞯓ᠲ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ⴑ.ڿᠲ +B; \u1A5A𛦝\u0C4D。𚝬𝟵; [P1 V5 V6]; [P1 V5 V6] # ᩚ్.9 +B; \u1A5A𛦝\u0C4D。𚝬9; [P1 V5 V6]; [P1 V5 V6] # ᩚ్.9 +B; xn--lqc703ebm93a.xn--9-000p; [V5 V6]; [V5 V6] # ᩚ్.9 +T; \u200C\u06A0𿺆𝟗。Ⴣ꒘\uFCD0񐘖; [B1 B5 C1 P1 V6]; [B2 B5 P1 V6] # ڠ9.Ⴣ꒘مخ +N; \u200C\u06A0𿺆𝟗。Ⴣ꒘\uFCD0񐘖; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ڠ9.Ⴣ꒘مخ +T; \u200C\u06A0𿺆9。Ⴣ꒘\u0645\u062E񐘖; [B1 B5 C1 P1 V6]; [B2 B5 P1 V6] # ڠ9.Ⴣ꒘مخ +N; \u200C\u06A0𿺆9。Ⴣ꒘\u0645\u062E񐘖; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ڠ9.Ⴣ꒘مخ +T; \u200C\u06A0𿺆9。ⴣ꒘\u0645\u062E񐘖; [B1 B5 C1 P1 V6]; [B2 B5 P1 V6] # ڠ9.ⴣ꒘مخ +N; \u200C\u06A0𿺆9。ⴣ꒘\u0645\u062E񐘖; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ڠ9.ⴣ꒘مخ +B; xn--9-vtc42319e.xn--tgb9bz87p833hw316c; [B2 B5 V6]; [B2 B5 V6] # ڠ9.ⴣ꒘مخ +B; xn--9-vtc736qts91g.xn--tgb9bz87p833hw316c; [B1 B5 C1 V6]; [B1 B5 C1 V6] # ڠ9.ⴣ꒘مخ +B; xn--9-vtc42319e.xn--tgb9bz61cfn8mw3t2c; [B2 B5 V6]; [B2 B5 V6] # ڠ9.Ⴣ꒘مخ +B; xn--9-vtc736qts91g.xn--tgb9bz61cfn8mw3t2c; [B1 B5 C1 V6]; [B1 B5 C1 V6] # ڠ9.Ⴣ꒘مخ +T; \u200C\u06A0𿺆𝟗。ⴣ꒘\uFCD0񐘖; [B1 B5 C1 P1 V6]; [B2 B5 P1 V6] # ڠ9.ⴣ꒘مخ +N; \u200C\u06A0𿺆𝟗。ⴣ꒘\uFCD0񐘖; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ڠ9.ⴣ꒘مخ +B; ᡖ。\u031F񗛨\u0B82-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ᡖ.̟ஂ- +B; ᡖ。\u031F񗛨\u0B82-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ᡖ.̟ஂ- +B; xn--m8e.xn----mdb555dkk71m; [V3 V5 V6]; [V3 V5 V6] # ᡖ.̟ஂ- +B; 𞠠浘。絧𞀀; [B2 B3]; [B2 B3] +B; xn--e0wp491f.xn--ud0a3573e; [B2 B3]; [B2 B3] +B; \u0596Ⴋ.𝟳≯︒\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖Ⴋ.7≯︒ +B; \u0596Ⴋ.𝟳>\u0338︒\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖Ⴋ.7≯︒ +B; \u0596Ⴋ.7≯。\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖Ⴋ.7≯. +B; \u0596Ⴋ.7>\u0338。\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖Ⴋ.7≯. +B; \u0596ⴋ.7>\u0338。\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖ⴋ.7≯. +B; \u0596ⴋ.7≯。\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖ⴋ.7≯. +B; xn--hcb613r.xn--7-pgo.; [V5 V6]; [V5 V6] # ֖ⴋ.7≯. +B; xn--hcb887c.xn--7-pgo.; [V5 V6]; [V5 V6] # ֖Ⴋ.7≯. +B; \u0596ⴋ.𝟳>\u0338︒\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖ⴋ.7≯︒ +B; \u0596ⴋ.𝟳≯︒\uFE0A; [P1 V5 V6]; [P1 V5 V6] # ֖ⴋ.7≯︒ +B; xn--hcb613r.xn--7-pgoy530h; [V5 V6]; [V5 V6] # ֖ⴋ.7≯︒ +B; xn--hcb887c.xn--7-pgoy530h; [V5 V6]; [V5 V6] # ֖Ⴋ.7≯︒ +T; \u200DF𑓂。󠺨︒\u077E𐹢; [B1 C2 P1 V6]; [B1 P1 V6] # f𑓂.︒ݾ𐹢 +N; \u200DF𑓂。󠺨︒\u077E𐹢; [B1 C2 P1 V6]; [B1 C2 P1 V6] # f𑓂.︒ݾ𐹢 +T; \u200DF𑓂。󠺨。\u077E𐹢; [B1 C2 P1 V6]; [B1 P1 V6] # f𑓂..ݾ𐹢 +N; \u200DF𑓂。󠺨。\u077E𐹢; [B1 C2 P1 V6]; [B1 C2 P1 V6] # f𑓂..ݾ𐹢 +T; \u200Df𑓂。󠺨。\u077E𐹢; [B1 C2 P1 V6]; [B1 P1 V6] # f𑓂..ݾ𐹢 +N; \u200Df𑓂。󠺨。\u077E𐹢; [B1 C2 P1 V6]; [B1 C2 P1 V6] # f𑓂..ݾ𐹢 +B; xn--f-kq9i.xn--7656e.xn--fqb4175k; [B1 V6]; [B1 V6] # f𑓂..ݾ𐹢 +B; xn--f-tgn9761i.xn--7656e.xn--fqb4175k; [B1 C2 V6]; [B1 C2 V6] # f𑓂..ݾ𐹢 +T; \u200Df𑓂。󠺨︒\u077E𐹢; [B1 C2 P1 V6]; [B1 P1 V6] # f𑓂.︒ݾ𐹢 +N; \u200Df𑓂。󠺨︒\u077E𐹢; [B1 C2 P1 V6]; [B1 C2 P1 V6] # f𑓂.︒ݾ𐹢 +B; xn--f-kq9i.xn--fqb1637j8hky9452a; [B1 V6]; [B1 V6] # f𑓂.︒ݾ𐹢 +B; xn--f-tgn9761i.xn--fqb1637j8hky9452a; [B1 C2 V6]; [B1 C2 V6] # f𑓂.︒ݾ𐹢 +B; \u0845🄇𐼗︒。𐹻𑜫; [B1 B3 P1 V6]; [B1 B3 P1 V6] # ࡅ🄇︒.𐹻𑜫 +B; \u08456,𐼗。。𐹻𑜫; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ࡅ6,..𐹻𑜫 +B; xn--6,-r4e4420y..xn--zo0di2m; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ࡅ6,..𐹻𑜫 +B; xn--3vb4696jpxkjh7s.xn--zo0di2m; [B1 B3 V6]; [B1 B3 V6] # ࡅ🄇︒.𐹻𑜫 +B; 𐹈.\u1DC0𑈱𐦭; [B1 P1 V5 V6]; [B1 P1 V5 V6] # .᷀𑈱𐦭 +B; xn--jn0d.xn--7dg0871h3lf; [B1 V5 V6]; [B1 V5 V6] # .᷀𑈱𐦭 +B; Ⴂ䠺。𞤃񅏎󙮦\u0693; [B2 P1 V6]; [B2 P1 V6] # Ⴂ䠺.𞤥ړ +B; ⴂ䠺。𞤥񅏎󙮦\u0693; [B2 P1 V6]; [B2 P1 V6] # ⴂ䠺.𞤥ړ +B; xn--tkj638f.xn--pjb9818vg4xno967d; [B2 V6]; [B2 V6] # ⴂ䠺.𞤥ړ +B; xn--9md875z.xn--pjb9818vg4xno967d; [B2 V6]; [B2 V6] # Ⴂ䠺.𞤥ړ +B; ⴂ䠺。𞤃񅏎󙮦\u0693; [B2 P1 V6]; [B2 P1 V6] # ⴂ䠺.𞤥ړ +B; 🄇伐︒.𜙚\uA8C4; [P1 V6]; [P1 V6] # 🄇伐︒.꣄ +B; 6,伐。.𜙚\uA8C4; [P1 V6 A4_2]; [P1 V6 A4_2] # 6,伐..꣄ +B; xn--6,-7i3c..xn--0f9ao925c; [P1 V6 A4_2]; [P1 V6 A4_2] # 6,伐..꣄ +B; xn--woqs083bel0g.xn--0f9ao925c; [V6]; [V6] # 🄇伐︒.꣄ +T; \u200D𐹠\uABED\uFFFB。\u200D𐫓Ⴚ𑂹; [B1 C2 P1 V6]; [B1 B2 B3 P1 V6] # 𐹠꯭.𐫓Ⴚ𑂹 +N; \u200D𐹠\uABED\uFFFB。\u200D𐫓Ⴚ𑂹; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹠꯭.𐫓Ⴚ𑂹 +T; \u200D𐹠\uABED\uFFFB。\u200D𐫓ⴚ𑂹; [B1 C2 P1 V6]; [B1 B2 B3 P1 V6] # 𐹠꯭.𐫓ⴚ𑂹 +N; \u200D𐹠\uABED\uFFFB。\u200D𐫓ⴚ𑂹; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹠꯭.𐫓ⴚ𑂹 +B; xn--429az70n29i.xn--ilj7702eqyd; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 𐹠꯭.𐫓ⴚ𑂹 +B; xn--1ugz126coy7bdbm.xn--1ug062chv7ov6e; [B1 C2 V6]; [B1 C2 V6] # 𐹠꯭.𐫓ⴚ𑂹 +B; xn--429az70n29i.xn--ynd3619jqyd; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 𐹠꯭.𐫓Ⴚ𑂹 +B; xn--1ugz126coy7bdbm.xn--ynd959evs1pv6e; [B1 C2 V6]; [B1 C2 V6] # 𐹠꯭.𐫓Ⴚ𑂹 +B; 󠆠.񷐴󌟈; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 󠆠.񷐴󌟈; [P1 V6 A4_2]; [P1 V6 A4_2] +B; .xn--rx21bhv12i; [V6 A4_2]; [V6 A4_2] +T; 𐫃\u200CႦ.≠𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐫃Ⴆ.≠ +N; 𐫃\u200CႦ.≠𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 𐫃Ⴆ.≠ +T; 𐫃\u200CႦ.=\u0338𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐫃Ⴆ.≠ +N; 𐫃\u200CႦ.=\u0338𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 𐫃Ⴆ.≠ +T; 𐫃\u200Cⴆ.=\u0338𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐫃ⴆ.≠ +N; 𐫃\u200Cⴆ.=\u0338𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 𐫃ⴆ.≠ +T; 𐫃\u200Cⴆ.≠𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐫃ⴆ.≠ +N; 𐫃\u200Cⴆ.≠𞷙; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 𐫃ⴆ.≠ +B; xn--xkjz802e.xn--1ch2802p; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; xn--0ug132csv7o.xn--1ch2802p; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # 𐫃ⴆ.≠ +B; xn--end1719j.xn--1ch2802p; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; xn--end799ekr1p.xn--1ch2802p; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # 𐫃Ⴆ.≠ +B; 󠁲𙩢𝟥ꘌ.\u0841; [B1 P1 V6]; [B1 P1 V6] # 3ꘌ.ࡁ +B; 󠁲𙩢3ꘌ.\u0841; [B1 P1 V6]; [B1 P1 V6] # 3ꘌ.ࡁ +B; xn--3-0g3es485d8i15h.xn--zvb; [B1 V6]; [B1 V6] # 3ꘌ.ࡁ +B; -.\u1886󡲣-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -.ᢆ- +B; -.xn----pbkx6497q; [V3 V5 V6]; [V3 V5 V6] # -.ᢆ- +T; 󲚗\u200C。\u200C𞰆ς; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .ς +N; 󲚗\u200C。\u200C𞰆ς; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .ς +T; 󲚗\u200C。\u200C𞰆ς; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .ς +N; 󲚗\u200C。\u200C𞰆ς; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .ς +T; 󲚗\u200C。\u200C𞰆Σ; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .σ +N; 󲚗\u200C。\u200C𞰆Σ; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .σ +T; 󲚗\u200C。\u200C𞰆σ; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .σ +N; 󲚗\u200C。\u200C𞰆σ; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .σ +B; xn--qp42f.xn--4xa3011w; [B2 B3 V6]; [B2 B3 V6] +B; xn--0ug76062m.xn--4xa595lhn92a; [B1 B6 C1 V6]; [B1 B6 C1 V6] # .σ +B; xn--0ug76062m.xn--3xa795lhn92a; [B1 B6 C1 V6]; [B1 B6 C1 V6] # .ς +T; 󲚗\u200C。\u200C𞰆Σ; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .σ +N; 󲚗\u200C。\u200C𞰆Σ; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .σ +T; 󲚗\u200C。\u200C𞰆σ; [B1 B6 C1 P1 V6]; [B2 B3 P1 V6] # .σ +N; 󲚗\u200C。\u200C𞰆σ; [B1 B6 C1 P1 V6]; [B1 B6 C1 P1 V6] # .σ +T; 堕𑓂\u1B02。𐮇𞤽\u200C-; [B3 C1 V3]; [B3 V3] # 堕𑓂ᬂ.𐮇𞤽- +N; 堕𑓂\u1B02。𐮇𞤽\u200C-; [B3 C1 V3]; [B3 C1 V3] # 堕𑓂ᬂ.𐮇𞤽- +T; 堕𑓂\u1B02。𐮇𞤛\u200C-; [B3 C1 V3]; [B3 V3] # 堕𑓂ᬂ.𐮇𞤽- +N; 堕𑓂\u1B02。𐮇𞤛\u200C-; [B3 C1 V3]; [B3 C1 V3] # 堕𑓂ᬂ.𐮇𞤽- +B; xn--5sf345zdk8h.xn----iv5iw606c; [B3 V3]; [B3 V3] # 堕𑓂ᬂ.𐮇𞤽- +B; xn--5sf345zdk8h.xn----rgnt157hwl9g; [B3 C1 V3]; [B3 C1 V3] # 堕𑓂ᬂ.𐮇𞤽- +T; 𐹶𑁆ᡕ𞤢。ᡥς\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥςتς +N; 𐹶𑁆ᡕ𞤢。ᡥς\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥςتς +T; 𐹶𑁆ᡕ𞤢。ᡥς\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥςتς +N; 𐹶𑁆ᡕ𞤢。ᡥς\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥςتς +B; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062AΣ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; xn--l8e1317j1ebz456b.xn--4xaa85plx4a; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +T; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +T; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +B; xn--l8e1317j1ebz456b.xn--3xab95plx4a; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +B; xn--l8e1317j1ebz456b.xn--3xaa16plx4a; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥςتς +B; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062AΣ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +T; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤀。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +T; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤢。ᡥσ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +B; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062AΣ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +T; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +B; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062AΣ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +B; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aσ; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتσ +T; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +N; 𐹶𑁆ᡕ𞤢。ᡥΣ\u062Aς; [B1 B5]; [B1 B5] # 𐹶𑁆ᡕ𞤢.ᡥσتς +T; 󏒰.-𝟻ß; [P1 V3 V6]; [P1 V3 V6] +N; 󏒰.-𝟻ß; [P1 V3 V6]; [P1 V3 V6] +T; 󏒰.-5ß; [P1 V3 V6]; [P1 V3 V6] +N; 󏒰.-5ß; [P1 V3 V6]; [P1 V3 V6] +B; 󏒰.-5SS; [P1 V3 V6]; [P1 V3 V6] +B; 󏒰.-5ss; [P1 V3 V6]; [P1 V3 V6] +B; 󏒰.-5Ss; [P1 V3 V6]; [P1 V3 V6] +B; xn--t960e.-5ss; [V3 V6]; [V3 V6] +B; xn--t960e.xn---5-hia; [V3 V6]; [V3 V6] +B; 󏒰.-𝟻SS; [P1 V3 V6]; [P1 V3 V6] +B; 󏒰.-𝟻ss; [P1 V3 V6]; [P1 V3 V6] +B; 󏒰.-𝟻Ss; [P1 V3 V6]; [P1 V3 V6] +T; \u200D𐨿.🤒Ⴥ򑮶; [C2 P1 V6]; [P1 V5 V6] # 𐨿.🤒Ⴥ +N; \u200D𐨿.🤒Ⴥ򑮶; [C2 P1 V6]; [C2 P1 V6] # 𐨿.🤒Ⴥ +T; \u200D𐨿.🤒ⴥ򑮶; [C2 P1 V6]; [P1 V5 V6] # 𐨿.🤒ⴥ +N; \u200D𐨿.🤒ⴥ򑮶; [C2 P1 V6]; [C2 P1 V6] # 𐨿.🤒ⴥ +B; xn--0s9c.xn--tljz038l0gz4b; [V5 V6]; [V5 V6] +B; xn--1ug9533g.xn--tljz038l0gz4b; [C2 V6]; [C2 V6] # 𐨿.🤒ⴥ +B; xn--0s9c.xn--9nd3211w0gz4b; [V5 V6]; [V5 V6] +B; xn--1ug9533g.xn--9nd3211w0gz4b; [C2 V6]; [C2 V6] # 𐨿.🤒Ⴥ +T; 𵋅。ß𬵩\u200D; [C2 P1 V6]; [P1 V6] # .ß𬵩 +N; 𵋅。ß𬵩\u200D; [C2 P1 V6]; [C2 P1 V6] # .ß𬵩 +T; 𵋅。SS𬵩\u200D; [C2 P1 V6]; [P1 V6] # .ss𬵩 +N; 𵋅。SS𬵩\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss𬵩 +T; 𵋅。ss𬵩\u200D; [C2 P1 V6]; [P1 V6] # .ss𬵩 +N; 𵋅。ss𬵩\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss𬵩 +T; 𵋅。Ss𬵩\u200D; [C2 P1 V6]; [P1 V6] # .ss𬵩 +N; 𵋅。Ss𬵩\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss𬵩 +B; xn--ey1p.xn--ss-eq36b; [V6]; [V6] +B; xn--ey1p.xn--ss-n1tx0508a; [C2 V6]; [C2 V6] # .ss𬵩 +B; xn--ey1p.xn--zca870nz438b; [C2 V6]; [C2 V6] # .ß𬵩 +T; \u200C𭉝。\u07F1\u0301𞹻; [B1 C1 V5]; [B1 V5] # 𭉝.߱́غ +N; \u200C𭉝。\u07F1\u0301𞹻; [B1 C1 V5]; [B1 C1 V5] # 𭉝.߱́غ +T; \u200C𭉝。\u07F1\u0301\u063A; [B1 C1 V5]; [B1 V5] # 𭉝.߱́غ +N; \u200C𭉝。\u07F1\u0301\u063A; [B1 C1 V5]; [B1 C1 V5] # 𭉝.߱́غ +B; xn--634m.xn--lsa46nuub; [B1 V5]; [B1 V5] # 𭉝.߱́غ +B; xn--0ugy003y.xn--lsa46nuub; [B1 C1 V5]; [B1 C1 V5] # 𭉝.߱́غ +T; 𞼌\u200C𑈶。𐹡; [B1 B3 C1 P1 V6]; [B1 P1 V6] # 𑈶.𐹡 +N; 𞼌\u200C𑈶。𐹡; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # 𑈶.𐹡 +B; xn--9g1d1288a.xn--8n0d; [B1 V6]; [B1 V6] +B; xn--0ug7946gzpxf.xn--8n0d; [B1 B3 C1 V6]; [B1 B3 C1 V6] # 𑈶.𐹡 +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBς≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻ς≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBς≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻ς≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBς=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻ς≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBς=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻ς≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBς≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻ς≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBς≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻ς≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBς=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻ς≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBς=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻ς≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +B; xn--zb9h5968x.xn--4xa378i1mfjw7y; [V5 V6]; [V5 V6] # 🜭.𑖿᪻σ≠ +B; xn--0ug3766p5nm1b.xn--4xa378i1mfjw7y; [C1 V5 V6]; [C1 V5 V6] # 🜭.𑖿᪻σ≠ +B; xn--0ug3766p5nm1b.xn--3xa578i1mfjw7y; [C1 V5 V6]; [C1 V5 V6] # 🜭.𑖿᪻ς≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBΣ≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ≠; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ≠; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ=\u0338; [C1 P1 V5 V6]; [P1 V5 V6] # 🜭.𑖿᪻σ≠ +N; 󠅯򇽭\u200C🜭。𑖿\u1ABBσ=\u0338; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 🜭.𑖿᪻σ≠ +T; ⒋。⒈\u200D򳴢; [C2 P1 V6]; [P1 V6] # ⒋.⒈ +N; ⒋。⒈\u200D򳴢; [C2 P1 V6]; [C2 P1 V6] # ⒋.⒈ +T; 4.。1.\u200D򳴢; [C2 P1 V6 A4_2]; [P1 V6 A4_2] # 4..1. +N; 4.。1.\u200D򳴢; [C2 P1 V6 A4_2]; [C2 P1 V6 A4_2] # 4..1. +B; 4..1.xn--sf51d; [V6 A4_2]; [V6 A4_2] +B; 4..1.xn--1ug64613i; [C2 V6 A4_2]; [C2 V6 A4_2] # 4..1. +B; xn--wsh.xn--tsh07994h; [V6]; [V6] +B; xn--wsh.xn--1ug58o74922a; [C2 V6]; [C2 V6] # ⒋.⒈ +T; \u0644ß。𐇽\u1A60򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +N; \u0644ß。𐇽\u1A60򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +T; \u0644ß。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +N; \u0644ß。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +T; \u0644ß。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +N; \u0644ß。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لß.᩠𐇽𞤾 +B; \u0644SS。\u1A60𐇽򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644ss。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。\u1A60𐇽򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; xn--ss-svd.xn--jof2298hn83fln78f; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # لss.᩠𐇽𞤾 +B; xn--zca57y.xn--jof2298hn83fln78f; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # لß.᩠𐇽𞤾 +B; \u0644SS。\u1A60𐇽򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644ss。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。\u1A60𐇽򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644SS。𐇽\u1A60򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644ss。𐇽\u1A60򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。𐇽\u1A60򾅢𞤜; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644SS。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644SS。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。\u1A60𐇽򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644SS。𐇽\u1A60򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; \u0644Ss。𐇽\u1A60򾅢𞤾; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # لss.᩠𐇽𞤾 +B; 𐹽𑄳񼜲.\u1DDF\u17B8\uA806𑜫; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𐹽𑄳.ᷟី꠆𑜫 +B; xn--1o0di0c0652w.xn--33e362arr1l153d; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # 𐹽𑄳.ᷟី꠆𑜫 +T; Ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # Ⴓ𑜫.ڧ𑰶 +N; Ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # Ⴓ𑜫.ڧ𑰶 +T; Ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # Ⴓ𑜫.ڧ𑰶 +N; Ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # Ⴓ𑜫.ڧ𑰶 +T; ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # ⴓ𑜫.ڧ𑰶 +N; ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # ⴓ𑜫.ڧ𑰶 +B; xn--blj6306ey091d.xn--9jb4223l; [V6]; [V6] # ⴓ𑜫.ڧ𑰶 +B; xn--1ugy52cym7p7xu5e.xn--9jb4223l; [V6]; [V6] # ⴓ𑜫.ڧ𑰶 +B; xn--rnd8945ky009c.xn--9jb4223l; [V6]; [V6] # Ⴓ𑜫.ڧ𑰶 +B; xn--rnd479ep20q7x12e.xn--9jb4223l; [V6]; [V6] # Ⴓ𑜫.ڧ𑰶 +T; ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # ⴓ𑜫.ڧ𑰶 +N; ⴓ𑜫\u200D򗭓.\u06A7𑰶; [P1 V6]; [P1 V6] # ⴓ𑜫.ڧ𑰶 +B; 𐨿.🄆—; [P1 V5 V6]; [P1 V5 V6] +B; 𐨿.5,—; [P1 V5 V6]; [P1 V5 V6] +B; xn--0s9c.xn--5,-81t; [P1 V5 V6]; [P1 V5 V6] +B; xn--0s9c.xn--8ug8324p; [V5 V6]; [V5 V6] +B; 򔊱񁦮۸。󠾭-; [P1 V3 V6]; [P1 V3 V6] +B; xn--lmb18944c0g2z.xn----2k81m; [V3 V6]; [V3 V6] +B; 𼗸\u07CD𐹮。\u06DDᡎᠴ; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ߍ𐹮.ᡎᠴ +B; xn--osb0855kcc2r.xn--tlb299fhc; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ߍ𐹮.ᡎᠴ +T; \u200DᠮႾ🄂.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 P1 V6] # ᠮႾ🄂.🚗ࡁ +N; \u200DᠮႾ🄂.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮႾ🄂.🚗ࡁ +T; \u200DᠮႾ1,.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 B6 P1 V6] # ᠮႾ1,.🚗ࡁ +N; \u200DᠮႾ1,.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮႾ1,.🚗ࡁ +T; \u200Dᠮⴞ1,.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 B6 P1 V6] # ᠮⴞ1,.🚗ࡁ +N; \u200Dᠮⴞ1,.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮⴞ1,.🚗ࡁ +B; xn--1,-v3o625k.xn--zvb3124wpkpf; [B1 B6 P1 V6]; [B1 B6 P1 V6] # ᠮⴞ1,.🚗ࡁ +B; xn--1,-v3o161c53q.xn--zvb692j9664aic1g; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮⴞ1,.🚗ࡁ +B; xn--1,-ogkx89c.xn--zvb3124wpkpf; [B1 B6 P1 V6]; [B1 B6 P1 V6] # ᠮႾ1,.🚗ࡁ +B; xn--1,-ogkx89c39j.xn--zvb692j9664aic1g; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮႾ1,.🚗ࡁ +T; \u200Dᠮⴞ🄂.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 P1 V6] # ᠮⴞ🄂.🚗ࡁ +N; \u200Dᠮⴞ🄂.🚗\u0841𮹌\u200C; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ᠮⴞ🄂.🚗ࡁ +B; xn--h7e438h1p44a.xn--zvb3124wpkpf; [B1 V6]; [B1 V6] # ᠮⴞ🄂.🚗ࡁ +B; xn--h7e341b0wlbv45b.xn--zvb692j9664aic1g; [B1 C1 C2 V6]; [B1 C1 C2 V6] # ᠮⴞ🄂.🚗ࡁ +B; xn--2nd129ai554b.xn--zvb3124wpkpf; [B1 V6]; [B1 V6] # ᠮႾ🄂.🚗ࡁ +B; xn--2nd129ay2gnw71c.xn--zvb692j9664aic1g; [B1 C1 C2 V6]; [B1 C1 C2 V6] # ᠮႾ🄂.🚗ࡁ +B; \u0601\u0697.𑚶񼡷⾆; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ڗ.𑚶舌 +B; \u0601\u0697.𑚶񼡷舌; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ڗ.𑚶舌 +B; xn--jfb41a.xn--tc1ap851axo39c; [B1 V5 V6]; [B1 V5 V6] # ڗ.𑚶舌 +B; 🞅󠳡󜍙.񲖷; [P1 V6]; [P1 V6] +B; xn--ie9hi1349bqdlb.xn--oj69a; [V6]; [V6] +T; \u20E7񯡎-򫣝.4Ⴄ\u200C; [C1 P1 V5 V6]; [P1 V5 V6] # ⃧-.4Ⴄ +N; \u20E7񯡎-򫣝.4Ⴄ\u200C; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⃧-.4Ⴄ +T; \u20E7񯡎-򫣝.4ⴄ\u200C; [C1 P1 V5 V6]; [P1 V5 V6] # ⃧-.4ⴄ +N; \u20E7񯡎-򫣝.4ⴄ\u200C; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⃧-.4ⴄ +B; xn----9snu5320fi76w.xn--4-ivs; [V5 V6]; [V5 V6] # ⃧-.4ⴄ +B; xn----9snu5320fi76w.xn--4-sgn589c; [C1 V5 V6]; [C1 V5 V6] # ⃧-.4ⴄ +B; xn----9snu5320fi76w.xn--4-f0g; [V5 V6]; [V5 V6] # ⃧-.4Ⴄ +B; xn----9snu5320fi76w.xn--4-f0g649i; [C1 V5 V6]; [C1 V5 V6] # ⃧-.4Ⴄ +T; ᚭ。𝌠ß𖫱; ᚭ.𝌠ß𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +N; ᚭ。𝌠ß𖫱; ᚭ.𝌠ß𖫱; xn--hwe.xn--zca4946pblnc; NV8 +T; ᚭ。𝌠ß𖫱; ᚭ.𝌠ß𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +N; ᚭ。𝌠ß𖫱; ᚭ.𝌠ß𖫱; xn--hwe.xn--zca4946pblnc; NV8 +B; ᚭ。𝌠SS𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ。𝌠ss𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ。𝌠Ss𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; xn--hwe.xn--ss-ci1ub261a; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ.𝌠ss𖫱; ; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ.𝌠SS𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ.𝌠Ss𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; xn--hwe.xn--zca4946pblnc; ᚭ.𝌠ß𖫱; xn--hwe.xn--zca4946pblnc; NV8 +T; ᚭ.𝌠ß𖫱; ; xn--hwe.xn--ss-ci1ub261a; NV8 +N; ᚭ.𝌠ß𖫱; ; xn--hwe.xn--zca4946pblnc; NV8 +B; ᚭ。𝌠SS𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ。𝌠ss𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ᚭ。𝌠Ss𖫱; ᚭ.𝌠ss𖫱; xn--hwe.xn--ss-ci1ub261a; NV8 +B; ₁。𞤫ꡪ; [B1 B2 B3]; [B1 B2 B3] +B; 1。𞤫ꡪ; [B1 B2 B3]; [B1 B2 B3] +B; 1。𞤉ꡪ; [B1 B2 B3]; [B1 B2 B3] +B; 1.xn--gd9al691d; [B1 B2 B3]; [B1 B2 B3] +B; ₁。𞤉ꡪ; [B1 B2 B3]; [B1 B2 B3] +T; 𯻼\u200C.𞶞ò»™¤ñ¥˜‡; [B2 B3 B6 C1 P1 V6]; [B2 B3 P1 V6] # . +N; 𯻼\u200C.𞶞ò»™¤ñ¥˜‡; [B2 B3 B6 C1 P1 V6]; [B2 B3 B6 C1 P1 V6] # . +B; xn--kg4n.xn--2b7hs861pl540a; [B2 B3 V6]; [B2 B3 V6] +B; xn--0ug27500a.xn--2b7hs861pl540a; [B2 B3 B6 C1 V6]; [B2 B3 B6 C1 V6] # . +B; 𑑄≯。𑜤; [P1 V5 V6]; [P1 V5 V6] +B; 𑑄>\u0338。𑜤; [P1 V5 V6]; [P1 V5 V6] +B; 𑑄≯。𑜤; [P1 V5 V6]; [P1 V5 V6] +B; 𑑄>\u0338。𑜤; [P1 V5 V6]; [P1 V5 V6] +B; xn--hdh5636g.xn--ci2d; [V5 V6]; [V5 V6] +T; Ⴋ≮𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [P1 V5 V6] # Ⴋ≮.ާ𐋣 +N; Ⴋ≮𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [C2 P1 V6] # Ⴋ≮.ާ𐋣 +T; Ⴋ<\u0338𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [P1 V5 V6] # Ⴋ≮.ާ𐋣 +N; Ⴋ<\u0338𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [C2 P1 V6] # Ⴋ≮.ާ𐋣 +T; ⴋ<\u0338𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [P1 V5 V6] # ⴋ≮.ާ𐋣 +N; ⴋ<\u0338𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [C2 P1 V6] # ⴋ≮.ާ𐋣 +T; ⴋ≮𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [P1 V5 V6] # ⴋ≮.ާ𐋣 +N; ⴋ≮𱲆。\u200D\u07A7𐋣; [C2 P1 V6]; [C2 P1 V6] # ⴋ≮.ާ𐋣 +B; xn--gdhz03bxt42d.xn--lrb6479j; [V5 V6]; [V5 V6] # ⴋ≮.ާ𐋣 +B; xn--gdhz03bxt42d.xn--lrb506jqr4n; [C2 V6]; [C2 V6] # ⴋ≮.ާ𐋣 +B; xn--jnd802gsm17c.xn--lrb6479j; [V5 V6]; [V5 V6] # Ⴋ≮.ާ𐋣 +B; xn--jnd802gsm17c.xn--lrb506jqr4n; [C2 V6]; [C2 V6] # Ⴋ≮.ާ𐋣 +B; \u17D2.ò†½’≯; [P1 V5 V6]; [P1 V5 V6] # ្.≯ +B; \u17D2.ò†½’>\u0338; [P1 V5 V6]; [P1 V5 V6] # ្.≯ +B; xn--u4e.xn--hdhx0084f; [V5 V6]; [V5 V6] # ្.≯ +B; ñ‡\u1734.𐨺É⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺E\u0301⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺É⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺E\u0301⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺e\u0301⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺é⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; xn--c0e34564d.xn--9ca207st53lg3f; [V5 V6]; [V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺e\u0301⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +B; ñ‡\u1734.𐨺é⬓𑄴; [P1 V5 V6]; [P1 V5 V6] # ᜴.𐨺é⬓𑄴 +T; ᢇ\u200D\uA8C4。︒𞤺; [B1 B6 C2 P1 V6]; [B1 P1 V6] # ᢇ꣄.︒𞤺 +N; ᢇ\u200D\uA8C4。︒𞤺; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ᢇ꣄.︒𞤺 +T; ᢇ\u200D\uA8C4。。𞤺; [B6 C2 A4_2]; [A4_2] # ᢇ꣄..𞤺 +N; ᢇ\u200D\uA8C4。。𞤺; [B6 C2 A4_2]; [B6 C2 A4_2] # ᢇ꣄..𞤺 +T; ᢇ\u200D\uA8C4。。𞤘; [B6 C2 A4_2]; [A4_2] # ᢇ꣄..𞤺 +N; ᢇ\u200D\uA8C4。。𞤘; [B6 C2 A4_2]; [B6 C2 A4_2] # ᢇ꣄..𞤺 +B; xn--09e4694e..xn--ye6h; [A4_2]; [A4_2] # ᢇ꣄..𞤺 +B; xn--09e669a6x8j..xn--ye6h; [B6 C2 A4_2]; [B6 C2 A4_2] # ᢇ꣄..𞤺 +T; ᢇ\u200D\uA8C4。︒𞤘; [B1 B6 C2 P1 V6]; [B1 P1 V6] # ᢇ꣄.︒𞤺 +N; ᢇ\u200D\uA8C4。︒𞤘; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ᢇ꣄.︒𞤺 +B; xn--09e4694e.xn--y86cv562b; [B1 V6]; [B1 V6] # ᢇ꣄.︒𞤺 +B; xn--09e669a6x8j.xn--y86cv562b; [B1 B6 C2 V6]; [B1 B6 C2 V6] # ᢇ꣄.︒𞤺 +T; 𞩬ò–™±\u1714\u200C。\u0631\u07AA≮; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +N; 𞩬ò–™±\u1714\u200C。\u0631\u07AA≮; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +T; 𞩬ò–™±\u1714\u200C。\u0631\u07AA<\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +N; 𞩬ò–™±\u1714\u200C。\u0631\u07AA<\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +T; 𞩬ò–™±\u1714\u200C。\u0631\u07AA≮; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +N; 𞩬ò–™±\u1714\u200C。\u0631\u07AA≮; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +T; 𞩬ò–™±\u1714\u200C。\u0631\u07AA<\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +N; 𞩬ò–™±\u1714\u200C。\u0631\u07AA<\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ᜔.رު≮ +B; xn--fze3930v7hz6b.xn--wgb86el10d; [B2 B3 V6]; [B2 B3 V6] # ᜔.رު≮ +B; xn--fze607b9651bjwl7c.xn--wgb86el10d; [B2 B3 V6]; [B2 B3 V6] # ᜔.رު≮ +B; Ⴣ.\u0653ᢤ; [P1 V5 V6]; [P1 V5 V6] # Ⴣ.ٓᢤ +B; Ⴣ.\u0653ᢤ; [P1 V5 V6]; [P1 V5 V6] # Ⴣ.ٓᢤ +B; â´£.\u0653ᢤ; [V5]; [V5] # â´£.ٓᢤ +B; xn--rlj.xn--vhb294g; [V5]; [V5] # â´£.ٓᢤ +B; xn--7nd.xn--vhb294g; [V5 V6]; [V5 V6] # Ⴣ.ٓᢤ +B; ⴣ.\u0653ᢤ; [V5]; [V5] # â´£.ٓᢤ +B; 󠄈\u0813.싉ò„†»áƒ„ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉Ⴤ +B; 󠄈\u0813.싉ò„†»áƒ„ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉Ⴤ +B; 󠄈\u0813.싉ò„†»áƒ„ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉Ⴤ +B; 󠄈\u0813.싉ò„†»áƒ„ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉Ⴤ +B; 󠄈\u0813.싉ò„†»â´¤ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉ⴤ +B; 󠄈\u0813.싉ò„†»â´¤ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉ⴤ +B; xn--oub.xn--sljz109bpe25dviva; [V6]; [V6] # ࠓ.싉ⴤ +B; xn--oub.xn--8nd9522gpe69cviva; [V6]; [V6] # ࠓ.싉Ⴤ +B; 󠄈\u0813.싉ò„†»â´¤ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉ⴤ +B; 󠄈\u0813.싉ò„†»â´¤ò‚¡; [P1 V6]; [P1 V6] # ࠓ.싉ⴤ +B; \uAA2C𑲫≮.⤂; [P1 V5 V6]; [P1 V5 V6] # ꨬ𑲫≮.⤂ +B; \uAA2C𑲫<\u0338.⤂; [P1 V5 V6]; [P1 V5 V6] # ꨬ𑲫≮.⤂ +B; \uAA2C𑲫≮.⤂; [P1 V5 V6]; [P1 V5 V6] # ꨬ𑲫≮.⤂ +B; \uAA2C𑲫<\u0338.⤂; [P1 V5 V6]; [P1 V5 V6] # ꨬ𑲫≮.⤂ +B; xn--gdh1854cn19c.xn--kqi; [V5 V6]; [V5 V6] # ꨬ𑲫≮.⤂ +B; \u0604𐩔≮Ⴢ.Ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.Ⴃ +B; \u0604𐩔<\u0338Ⴢ.Ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.Ⴃ +B; \u0604𐩔≮Ⴢ.Ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.Ⴃ +B; \u0604𐩔<\u0338Ⴢ.Ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.Ⴃ +B; \u0604𐩔<\u0338â´¢.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮ⴢ.ⴃ +B; \u0604𐩔≮ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮ⴢ.ⴃ +B; \u0604𐩔≮Ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.ⴃ +B; \u0604𐩔<\u0338Ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.ⴃ +B; xn--mfb416c0jox02t.xn--ukj; [B1 V6]; [B1 V6] # 𐩔≮Ⴢ.ⴃ +B; xn--mfb266l4khr54u.xn--ukj; [B1 V6]; [B1 V6] # 𐩔≮ⴢ.ⴃ +B; xn--mfb416c0jox02t.xn--bnd; [B1 V6]; [B1 V6] # 𐩔≮Ⴢ.Ⴃ +B; \u0604𐩔<\u0338ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮ⴢ.ⴃ +B; \u0604𐩔≮ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮ⴢ.ⴃ +B; \u0604𐩔≮Ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.ⴃ +B; \u0604𐩔<\u0338Ⴢ.ⴃ; [B1 P1 V6]; [B1 P1 V6] # 𐩔≮Ⴢ.ⴃ +B; 𑁅。-; [V3 V5]; [V3 V5] +B; xn--210d.-; [V3 V5]; [V3 V5] +B; \u0DCAò•¸½ó §±ï½¡é¥ˆâ‰ \u0664; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ්.饈≠٤ +B; \u0DCAò•¸½ó §±ï½¡é¥ˆ=\u0338\u0664; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ්.饈≠٤ +B; \u0DCAò•¸½ó §±ã€‚饈≠\u0664; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ්.饈≠٤ +B; \u0DCAò•¸½ó §±ã€‚饈=\u0338\u0664; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ්.饈≠٤ +B; xn--h1c25913jfwov.xn--dib144ler5f; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ්.饈≠٤ +B; 𞥃ᠠ⁷。≯邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞥃ᠠ⁷。>\u0338邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞥃ᠠ7。≯邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞥃ᠠ7。>\u0338邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞤡ᠠ7。>\u0338邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞤡ᠠ7。≯邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; xn--7-v4j2826w.xn--4-ogoy01bou3i; [B1 B2 V6]; [B1 B2 V6] +B; 𞤡ᠠ⁷。>\u0338邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; 𞤡ᠠ⁷。≯邅⬻4; [B1 B2 P1 V6]; [B1 B2 P1 V6] +B; ò ¿¯á¡³-𑐻.𐹴𐋫\u0605󑎳; [B1 B6 P1 V6]; [B1 B6 P1 V6] # ᡳ-𑐻.𐹴𐋫 +B; xn----m9j3429kxmy7e.xn--nfb7950kdihrp812a; [B1 B6 V6]; [B1 B6 V6] # ᡳ-𑐻.𐹴𐋫 +B; ò ¶†\u0845\u0A51.넨-󶧈; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡅੑ.넨- +B; ò ¶†\u0845\u0A51.넨-󶧈; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡅੑ.넨- +B; xn--3vb26hb6834b.xn----i37ez0957g; [B5 B6 V6]; [B5 B6 V6] # ࡅੑ.넨- +T; ꡦᡑ\u200D⒈。𐋣-; [C2 P1 V3 V6]; [P1 V3 V6] # ꡦᡑ⒈.𐋣- +N; ꡦᡑ\u200D⒈。𐋣-; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ꡦᡑ⒈.𐋣- +T; ꡦᡑ\u200D1.。𐋣-; [C2 V3 A4_2]; [V3 A4_2] # ꡦᡑ1..𐋣- +N; ꡦᡑ\u200D1.。𐋣-; [C2 V3 A4_2]; [C2 V3 A4_2] # ꡦᡑ1..𐋣- +B; xn--1-o7j0610f..xn----381i; [V3 A4_2]; [V3 A4_2] +B; xn--1-o7j663bdl7m..xn----381i; [C2 V3 A4_2]; [C2 V3 A4_2] # ꡦᡑ1..𐋣- +B; xn--h8e863drj7h.xn----381i; [V3 V6]; [V3 V6] +B; xn--h8e470bl0d838o.xn----381i; [C2 V3 V6]; [C2 V3 V6] # ꡦᡑ⒈.𐋣- +B; Ⴌ。ô¼ \uFB69; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴌ.Ù¹ +B; Ⴌ。ô¼ \u0679; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴌ.Ù¹ +B; ⴌ。ô¼ \u0679; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴌ.Ù¹ +B; xn--3kj.xn--yib19191t; [B5 B6 V6]; [B5 B6 V6] # ⴌ.Ù¹ +B; xn--knd.xn--yib19191t; [B5 B6 V6]; [B5 B6 V6] # Ⴌ.Ù¹ +B; ⴌ。ô¼ \uFB69; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴌ.Ù¹ +B; 𐮁𐭱.\u0F84\u135E-\u1CFA; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𐮁𐭱.྄፞- +B; xn--r19c5a.xn----xjg270ag3m; [B1 V5 V6]; [B1 V5 V6] # 𐮁𐭱.྄፞- +T; ⒈䰹\u200D-。웈; [C2 P1 V3 V6]; [P1 V3 V6] # ⒈䰹-.웈 +N; ⒈䰹\u200D-。웈; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ⒈䰹-.웈 +T; ⒈䰹\u200D-。웈; [C2 P1 V3 V6]; [P1 V3 V6] # ⒈䰹-.웈 +N; ⒈䰹\u200D-。웈; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ⒈䰹-.웈 +T; 1.ä°¹\u200D-。웈; [C2 V3]; [V3] # 1.ä°¹-.웈 +N; 1.ä°¹\u200D-。웈; [C2 V3]; [C2 V3] # 1.ä°¹-.웈 +T; 1.ä°¹\u200D-。웈; [C2 V3]; [V3] # 1.ä°¹-.웈 +N; 1.ä°¹\u200D-。웈; [C2 V3]; [C2 V3] # 1.ä°¹-.웈 +B; 1.xn----zw5a.xn--kp5b; [V3]; [V3] +B; 1.xn----tgnz80r.xn--kp5b; [C2 V3]; [C2 V3] # 1.ä°¹-.웈 +B; xn----dcp160o.xn--kp5b; [V3 V6]; [V3 V6] +B; xn----tgnx5rjr6c.xn--kp5b; [C2 V3 V6]; [C2 V3 V6] # ⒈䰹-.웈 +T; て。\u200Có ³½\u07F3; [C1 P1 V6]; [P1 V6] # て.ß³ +N; て。\u200Có ³½\u07F3; [C1 P1 V6]; [C1 P1 V6] # て.ß³ +B; xn--m9j.xn--rtb10784p; [V6]; [V6] # て.ß³ +B; xn--m9j.xn--rtb154j9l73w; [C1 V6]; [C1 V6] # て.ß³ +T; ς。\uA9C0\u06E7; [V5]; [V5] # ς.꧀ۧ +N; ς。\uA9C0\u06E7; [V5]; [V5] # ς.꧀ۧ +T; ς。\uA9C0\u06E7; [V5]; [V5] # ς.꧀ۧ +N; ς。\uA9C0\u06E7; [V5]; [V5] # ς.꧀ۧ +B; Σ。\uA9C0\u06E7; [V5]; [V5] # σ.꧀ۧ +B; σ。\uA9C0\u06E7; [V5]; [V5] # σ.꧀ۧ +B; xn--4xa.xn--3lb1944f; [V5]; [V5] # σ.꧀ۧ +B; xn--3xa.xn--3lb1944f; [V5]; [V5] # ς.꧀ۧ +B; Σ。\uA9C0\u06E7; [V5]; [V5] # σ.꧀ۧ +B; σ。\uA9C0\u06E7; [V5]; [V5] # σ.꧀ۧ +B; \u0BCD󥫅òŒ‰‘.ႢႵ; [P1 V5 V6]; [P1 V5 V6] # ்.ႢႵ +B; \u0BCD󥫅òŒ‰‘.ⴂⴕ; [P1 V5 V6]; [P1 V5 V6] # ்.ⴂⴕ +B; \u0BCD󥫅òŒ‰‘.Ⴂⴕ; [P1 V5 V6]; [P1 V5 V6] # ்.Ⴂⴕ +B; xn--xmc83135idcxza.xn--9md086l; [V5 V6]; [V5 V6] # ்.Ⴂⴕ +B; xn--xmc83135idcxza.xn--tkjwb; [V5 V6]; [V5 V6] # ்.ⴂⴕ +B; xn--xmc83135idcxza.xn--9md2b; [V5 V6]; [V5 V6] # ்.ႢႵ +T; \u1C32🄈⾛\u05A6.\u200Dò¯¥¤\u07FD; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ᰲ🄈走֦. +N; \u1C32🄈⾛\u05A6.\u200Dò¯¥¤\u07FD; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ᰲ🄈走֦. +T; \u1C327,èµ°\u05A6.\u200Dò¯¥¤\u07FD; [B1 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # á°²7,èµ°Ö¦. +N; \u1C327,èµ°\u05A6.\u200Dò¯¥¤\u07FD; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # á°²7,èµ°Ö¦. +B; xn--7,-bid991urn3k.xn--1tb13454l; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # á°²7,èµ°Ö¦. +B; xn--7,-bid991urn3k.xn--1tb334j1197q; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # á°²7,èµ°Ö¦. +B; xn--xcb756i493fwi5o.xn--1tb13454l; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ᰲ🄈走֦. +B; xn--xcb756i493fwi5o.xn--1tb334j1197q; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ᰲ🄈走֦. +B; ᢗ。Ӏñ„»; [P1 V6]; [P1 V6] +B; ᢗ。Ӏñ„»; [P1 V6]; [P1 V6] +B; ᢗ。ӏñ„»; [P1 V6]; [P1 V6] +B; xn--hbf.xn--s5a83117e; [V6]; [V6] +B; xn--hbf.xn--d5a86117e; [V6]; [V6] +B; ᢗ。ӏñ„»; [P1 V6]; [P1 V6] +B; \u0668-。ñ ‡ðŸ†á„¾; [B1 P1 V3 V6]; [B1 P1 V3 V6] # Ù¨-.🝆ᄾ +B; xn----oqc.xn--qrd1699v327w; [B1 V3 V6]; [B1 V3 V6] # Ù¨-.🝆ᄾ +B; -𐋷𖾑。󠆬; [V3]; [V3] +B; xn----991iq40y.; [V3]; [V3] +T; \u200C𐹳🐴멈.\uABEDñ¡¼; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹳🐴멈.꯭ +N; \u200C𐹳🐴멈.\uABEDñ¡¼; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𐹳🐴멈.꯭ +T; \u200C𐹳🐴멈.\uABEDñ¡¼; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹳🐴멈.꯭ +N; \u200C𐹳🐴멈.\uABEDñ¡¼; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𐹳🐴멈.꯭ +B; xn--422b325mqb6i.xn--429a8682s; [B1 V5 V6]; [B1 V5 V6] # 𐹳🐴멈.꯭ +B; xn--0ug6681d406b7bwk.xn--429a8682s; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 𐹳🐴멈.꯭ +B; ≮.\u0769\u0603; [B1 P1 V6]; [B1 P1 V6] # ≮.Ý© +B; <\u0338.\u0769\u0603; [B1 P1 V6]; [B1 P1 V6] # ≮.Ý© +B; xn--gdh.xn--lfb92e; [B1 V6]; [B1 V6] # ≮.Ý© +T; 𐶭⾆。\u200C𑚶òŸ±ƒðž°˜; [B1 B2 B3 C1 P1 V6]; [B2 B3 B5 B6 P1 V5 V6] # 舌.𑚶 +N; 𐶭⾆。\u200C𑚶òŸ±ƒðž°˜; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 舌.𑚶 +T; 𐶭舌。\u200C𑚶òŸ±ƒðž°˜; [B1 B2 B3 C1 P1 V6]; [B2 B3 B5 B6 P1 V5 V6] # 舌.𑚶 +N; 𐶭舌。\u200C𑚶òŸ±ƒðž°˜; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 舌.𑚶 +B; xn--tc1ao37z.xn--6e2dw557azds2d; [B2 B3 B5 B6 V5 V6]; [B2 B3 B5 B6 V5 V6] +B; xn--tc1ao37z.xn--0ugx728gi1nfwqz2e; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # 舌.𑚶 +T; \u200CჀ-.𝟷ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # Ⴠ-.1ςς +N; \u200CჀ-.𝟷ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴠ-.1ςς +T; \u200CჀ-.1ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # Ⴠ-.1ςς +N; \u200CჀ-.1ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴠ-.1ςς +T; \u200Câ´ -.1ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # â´ -.1ςς +N; \u200Câ´ -.1ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # â´ -.1ςς +T; \u200CჀ-.1Σ𞴺Σ; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # Ⴠ-.1σσ +N; \u200CჀ-.1Σ𞴺Σ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴠ-.1σσ +T; \u200Câ´ -.1σ𞴺σ; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # â´ -.1σσ +N; \u200Câ´ -.1σ𞴺σ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # â´ -.1σσ +B; xn----2ws.xn--1-0mba52321c; [B1 B6 V3 V6]; [B1 B6 V3 V6] +B; xn----rgn530d.xn--1-0mba52321c; [B1 C1 V3 V6]; [B1 C1 V3 V6] # â´ -.1σσ +B; xn----z1g.xn--1-0mba52321c; [B1 B6 V3 V6]; [B1 B6 V3 V6] +B; xn----z1g168i.xn--1-0mba52321c; [B1 C1 V3 V6]; [B1 C1 V3 V6] # Ⴠ-.1σσ +B; xn----rgn530d.xn--1-ymba92321c; [B1 C1 V3 V6]; [B1 C1 V3 V6] # â´ -.1ςς +B; xn----z1g168i.xn--1-ymba92321c; [B1 C1 V3 V6]; [B1 C1 V3 V6] # Ⴠ-.1ςς +T; \u200Câ´ -.𝟷ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # â´ -.1ςς +N; \u200Câ´ -.𝟷ς𞴺ς; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # â´ -.1ςς +T; \u200CჀ-.𝟷Σ𞴺Σ; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # Ⴠ-.1σσ +N; \u200CჀ-.𝟷Σ𞴺Σ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴠ-.1σσ +T; \u200Câ´ -.𝟷σ𞴺σ; [B1 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # â´ -.1σσ +N; \u200Câ´ -.𝟷σ𞴺σ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # â´ -.1σσ +B; 𑲘󠄒𓑡。𝟪Ⴜ; [P1 V5 V6]; [P1 V5 V6] +B; 𑲘󠄒𓑡。8Ⴜ; [P1 V5 V6]; [P1 V5 V6] +B; 𑲘󠄒𓑡。8ⴜ; [P1 V5 V6]; [P1 V5 V6] +B; xn--7m3d291b.xn--8-vws; [V5 V6]; [V5 V6] +B; xn--7m3d291b.xn--8-s1g; [V5 V6]; [V5 V6] +B; 𑲘󠄒𓑡。𝟪ⴜ; [P1 V5 V6]; [P1 V5 V6] +B; 䪏\u06AB\u07E0\u0941。뭕ᢝ\u17B9; [B5 B6]; [B5 B6] # 䪏ګߠु.뭕ᢝឹ +B; 䪏\u06AB\u07E0\u0941。뭕ᢝ\u17B9; [B5 B6]; [B5 B6] # 䪏ګߠु.뭕ᢝឹ +B; 䪏\u06AB\u07E0\u0941。뭕ᢝ\u17B9; [B5 B6]; [B5 B6] # 䪏ګߠु.뭕ᢝឹ +B; 䪏\u06AB\u07E0\u0941。뭕ᢝ\u17B9; [B5 B6]; [B5 B6] # 䪏ګߠु.뭕ᢝឹ +B; xn--ekb23dj4at01n.xn--43e96bh910b; [B5 B6]; [B5 B6] # 䪏ګߠु.뭕ᢝឹ +B; \u1BAB。🂉󠁰; [P1 V5 V6]; [P1 V5 V6] # ᮫.🂉 +B; \u1BAB。🂉󠁰; [P1 V5 V6]; [P1 V5 V6] # ᮫.🂉 +B; xn--zxf.xn--fx7ho0250c; [V5 V6]; [V5 V6] # ᮫.🂉 +T; 󩎃\u0AC4。ς\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 P1 V6] # ૄ.ς𐹮𑈵 +N; 󩎃\u0AC4。ς\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 C2 P1 V6] # ૄ.ς𐹮𑈵 +T; 󩎃\u0AC4。Σ\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 P1 V6] # ૄ.σ𐹮𑈵 +N; 󩎃\u0AC4。Σ\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 C2 P1 V6] # ૄ.σ𐹮𑈵 +T; 󩎃\u0AC4。σ\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 P1 V6] # ૄ.σ𐹮𑈵 +N; 󩎃\u0AC4。σ\u200D𐹮𑈵; [B5 C2 P1 V6]; [B5 C2 P1 V6] # ૄ.σ𐹮𑈵 +B; xn--dfc53161q.xn--4xa8467k5mc; [B5 V6]; [B5 V6] # ૄ.σ𐹮𑈵 +B; xn--dfc53161q.xn--4xa895lzo7nsfd; [B5 C2 V6]; [B5 C2 V6] # ૄ.σ𐹮𑈵 +B; xn--dfc53161q.xn--3xa006lzo7nsfd; [B5 C2 V6]; [B5 C2 V6] # ૄ.ς𐹮𑈵 +B; 𐫀ᡂ𑜫.𑘿; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] +B; 𐫀ᡂ𑜫.𑘿; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] +B; xn--17e9625js1h.xn--sb2d; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] +T; 󬚶󸋖ò–©°-。\u200C; [C1 P1 V3 V6]; [P1 V3 V6] # -. +N; 󬚶󸋖ò–©°-。\u200C; [C1 P1 V3 V6]; [C1 P1 V3 V6] # -. +B; xn----7i12hu122k9ire.; [V3 V6]; [V3 V6] +B; xn----7i12hu122k9ire.xn--0ug; [C1 V3 V6]; [C1 V3 V6] # -. +B; 𐹣.\u07C2; [B1]; [B1] # 𐹣.߂ +B; 𐹣.\u07C2; [B1]; [B1] # 𐹣.߂ +B; xn--bo0d.xn--dsb; [B1]; [B1] # 𐹣.߂ +B; -\u07E1。Ↄ; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ß¡.Ↄ +B; -\u07E1。Ↄ; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ß¡.Ↄ +B; -\u07E1。ↄ; [B1 V3]; [B1 V3] # -ß¡.ↄ +B; xn----8cd.xn--r5g; [B1 V3]; [B1 V3] # -ß¡.ↄ +B; xn----8cd.xn--q5g; [B1 V3 V6]; [B1 V3 V6] # -ß¡.Ↄ +B; -\u07E1。ↄ; [B1 V3]; [B1 V3] # -ß¡.ↄ +T; \u200D-︒󠄄。ß哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 P1 V3 V6] # -︒.ß哑 +N; \u200D-︒󠄄。ß哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # -︒.ß哑 +T; \u200D-。󠄄。ß哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 P1 V3 V6 A4_2] # -..ß哑 +N; \u200D-。󠄄。ß哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2] # -..ß哑 +T; \u200D-。󠄄。SS哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 P1 V3 V6 A4_2] # -..ss哑 +N; \u200D-。󠄄。SS哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2] # -..ss哑 +T; \u200D-。󠄄。ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 P1 V3 V6 A4_2] # -..ss哑 +N; \u200D-。󠄄。ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2] # -..ss哑 +T; \u200D-。󠄄。Ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 P1 V3 V6 A4_2] # -..ss哑 +N; \u200D-。󠄄。Ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2]; [B1 B5 B6 C1 C2 P1 V3 V6 A4_2] # -..ss哑 +B; -..xn--ss-h46c5711e; [B1 B5 B6 V3 V6 A4_2]; [B1 B5 B6 V3 V6 A4_2] +B; xn----tgn..xn--ss-k1ts75zb8ym; [B1 B5 B6 C1 C2 V3 V6 A4_2]; [B1 B5 B6 C1 C2 V3 V6 A4_2] # -..ss哑 +B; xn----tgn..xn--zca670n5f0binyk; [B1 B5 B6 C1 C2 V3 V6 A4_2]; [B1 B5 B6 C1 C2 V3 V6 A4_2] # -..ß哑 +T; \u200D-︒󠄄。SS哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 P1 V3 V6] # -︒.ss哑 +N; \u200D-︒󠄄。SS哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # -︒.ss哑 +T; \u200D-︒󠄄。ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 P1 V3 V6] # -︒.ss哑 +N; \u200D-︒󠄄。ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # -︒.ss哑 +T; \u200D-︒󠄄。Ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 P1 V3 V6] # -︒.ss哑 +N; \u200D-︒󠄄。Ss哑\u200C𐵿; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # -︒.ss哑 +B; xn----o89h.xn--ss-h46c5711e; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +B; xn----tgnt341h.xn--ss-k1ts75zb8ym; [B1 B5 B6 C1 C2 V6]; [B1 B5 B6 C1 C2 V6] # -︒.ss哑 +B; xn----tgnt341h.xn--zca670n5f0binyk; [B1 B5 B6 C1 C2 V6]; [B1 B5 B6 C1 C2 V6] # -︒.ß哑 +B; ︒.\uFE2F𑑂; [P1 V5 V6]; [P1 V5 V6] # ︒.𑑂︯ +B; ︒.𑑂\uFE2F; [P1 V5 V6]; [P1 V5 V6] # ︒.𑑂︯ +B; 。.𑑂\uFE2F; [V5 A4_2]; [V5 A4_2] # ..𑑂︯ +B; ..xn--s96cu30b; [V5 A4_2]; [V5 A4_2] # ..𑑂︯ +B; xn--y86c.xn--s96cu30b; [V5 V6]; [V5 V6] # ︒.𑑂︯ +T; \uA92C。\u200D; [C2 V5]; [V5] # ꤬. +N; \uA92C。\u200D; [C2 V5]; [C2 V5] # ꤬. +B; xn--zi9a.; [V5]; [V5] # ꤬. +B; xn--zi9a.xn--1ug; [C2 V5]; [C2 V5] # ꤬. +T; \u200D󠸡。\uFCD7; [B1 C2 P1 V6]; [B1 P1 V6] # .هج +N; \u200D󠸡。\uFCD7; [B1 C2 P1 V6]; [B1 C2 P1 V6] # .هج +T; \u200D󠸡。\u0647\u062C; [B1 C2 P1 V6]; [B1 P1 V6] # .هج +N; \u200D󠸡。\u0647\u062C; [B1 C2 P1 V6]; [B1 C2 P1 V6] # .هج +B; xn--d356e.xn--rgb7c; [B1 V6]; [B1 V6] # .هج +B; xn--1ug80651l.xn--rgb7c; [B1 C2 V6]; [B1 C2 V6] # .هج +T; -Ⴄ𝟢\u0663.𑍴ς; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴ς +N; -Ⴄ𝟢\u0663.𑍴ς; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴ς +T; -Ⴄ0\u0663.𑍴ς; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴ς +N; -Ⴄ0\u0663.𑍴ς; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴ς +T; -ⴄ0\u0663.𑍴ς; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴ς +N; -ⴄ0\u0663.𑍴ς; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴ς +B; -Ⴄ0\u0663.𑍴Σ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴σ +B; -ⴄ0\u0663.𑍴σ; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴σ +B; xn---0-iyd8660b.xn--4xa9120l; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴σ +B; xn---0-iyd216h.xn--4xa9120l; [B1 V3 V5 V6]; [B1 V3 V5 V6] # -Ⴄ0Ù£.𑍴σ +B; xn---0-iyd8660b.xn--3xa1220l; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴ς +B; xn---0-iyd216h.xn--3xa1220l; [B1 V3 V5 V6]; [B1 V3 V5 V6] # -Ⴄ0Ù£.𑍴ς +T; -ⴄ𝟢\u0663.𑍴ς; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴ς +N; -ⴄ𝟢\u0663.𑍴ς; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴ς +B; -Ⴄ𝟢\u0663.𑍴Σ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -Ⴄ0Ù£.𑍴σ +B; -ⴄ𝟢\u0663.𑍴σ; [B1 V3 V5]; [B1 V3 V5] # -ⴄ0Ù£.𑍴σ +B; 󦈄。-; [P1 V3 V6]; [P1 V3 V6] +B; xn--xm38e.-; [V3 V6]; [V3 V6] +T; ⋠𐋮.ò¶ˆ®\u0F18ß≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +N; ⋠𐋮.ò¶ˆ®\u0F18ß≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +T; ≼\u0338𐋮.ò¶ˆ®\u0F18ß>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +N; ≼\u0338𐋮.ò¶ˆ®\u0F18ß>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +T; ⋠𐋮.ò¶ˆ®\u0F18ß≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +N; ⋠𐋮.ò¶ˆ®\u0F18ß≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +T; ≼\u0338𐋮.ò¶ˆ®\u0F18ß>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +N; ≼\u0338𐋮.ò¶ˆ®\u0F18ß>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ß≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18SS>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18SS≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18ss≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18ss>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18Ss>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18Ss≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; xn--pgh4639f.xn--ss-ifj426nle504a; [V6]; [V6] # ⋠𐋮.༘ss≯ +B; xn--pgh4639f.xn--zca593eo6oc013y; [V6]; [V6] # ⋠𐋮.༘ß≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18SS>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18SS≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18ss≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18ss>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ≼\u0338𐋮.ò¶ˆ®\u0F18Ss>\u0338; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; ⋠𐋮.ò¶ˆ®\u0F18Ss≯; [P1 V6]; [P1 V6] # ⋠𐋮.༘ss≯ +B; 1𐋸\u0664。󠢮\uFBA4ñ·Š; [B1 P1 V6]; [B1 P1 V6] # 1𐋸٤.ۀ +B; 1𐋸\u0664。󠢮\u06C0ñ·Š; [B1 P1 V6]; [B1 P1 V6] # 1𐋸٤.ۀ +B; 1𐋸\u0664。󠢮\u06D5\u0654ñ·Š; [B1 P1 V6]; [B1 P1 V6] # 1𐋸٤.ۀ +B; xn--1-hqc3905q.xn--zkb83268gqee4a; [B1 V6]; [B1 V6] # 1𐋸٤.ۀ +T; 儭-。𐹴Ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # 儭-.𐹴Ⴢ +N; 儭-。𐹴Ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # 儭-.𐹴Ⴢ +T; 儭-。𐹴Ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # 儭-.𐹴Ⴢ +N; 儭-。𐹴Ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # 儭-.𐹴Ⴢ +T; 儭-。𐹴ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # 儭-.𐹴ⴢ +N; 儭-。𐹴ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # 儭-.𐹴ⴢ +B; xn----gz7a.xn--qlj9223eywx0b; [B1 B6 V3 V6]; [B1 B6 V3 V6] +B; xn----gz7a.xn--0ug472cfq0pus98b; [B1 B6 C1 V3 V6]; [B1 B6 C1 V3 V6] # 儭-.𐹴ⴢ +B; xn----gz7a.xn--6nd5001kyw98a; [B1 B6 V3 V6]; [B1 B6 V3 V6] +B; xn----gz7a.xn--6nd249ejl4pusr7b; [B1 B6 C1 V3 V6]; [B1 B6 C1 V3 V6] # 儭-.𐹴Ⴢ +T; 儭-。𐹴ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 P1 V3 V6] # 儭-.𐹴ⴢ +N; 儭-。𐹴ⴢñ¥³ \u200C; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # 儭-.𐹴ⴢ +B; 𝟺𐋷\u06B9.𞤭ò¿¡; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 4𐋷ڹ.𞤭 +B; 4𐋷\u06B9.𞤭ò¿¡; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 4𐋷ڹ.𞤭 +B; 4𐋷\u06B9.𞤋ò¿¡; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 4𐋷ڹ.𞤭 +B; xn--4-cvc5384q.xn--le6hi7322b; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 4𐋷ڹ.𞤭 +B; 𝟺𐋷\u06B9.𞤋ò¿¡; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 4𐋷ڹ.𞤭 +B; ≯-ꡋ𑲣.⒈𐹭; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338-ꡋ𑲣.⒈𐹭; [B1 P1 V6]; [B1 P1 V6] +B; ≯-ꡋ𑲣.1.𐹭; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338-ꡋ𑲣.1.𐹭; [B1 P1 V6]; [B1 P1 V6] +B; xn----ogox061d5i8d.1.xn--lo0d; [B1 V6]; [B1 V6] +B; xn----ogox061d5i8d.xn--tsh0666f; [B1 V6]; [B1 V6] +B; \u0330.󰜱蚀; [P1 V5 V6]; [P1 V5 V6] # ̰.蚀 +B; \u0330.󰜱蚀; [P1 V5 V6]; [P1 V5 V6] # ̰.蚀 +B; xn--xta.xn--e91aw9417e; [V5 V6]; [V5 V6] # ̰.蚀 +T; \uFB39Ⴘ.𞡼𑇀ß\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ß⃗ +N; \uFB39Ⴘ.𞡼𑇀ß\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ß⃗ +T; \u05D9\u05BCႸ.𞡼𑇀ß\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ß⃗ +N; \u05D9\u05BCႸ.𞡼𑇀ß\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ß⃗ +T; \u05D9\u05BCⴘ.𞡼𑇀ß\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ß⃗ +N; \u05D9\u05BCⴘ.𞡼𑇀ß\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ß⃗ +B; \u05D9\u05BCႸ.𞡼𑇀SS\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ss⃗ +B; \u05D9\u05BCⴘ.𞡼𑇀ss\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ss⃗ +B; \u05D9\u05BCႸ.𞡼𑇀ss\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ss⃗ +B; xn--kdb1d867b.xn--ss-yju5690ken9h; [B2 B3 V6]; [B2 B3 V6] # יּႸ.𞡼𑇀ss⃗ +B; xn--kdb1d278n.xn--ss-yju5690ken9h; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ss⃗ +B; xn--kdb1d278n.xn--zca284nhg9nrrxg; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ß⃗ +B; xn--kdb1d867b.xn--zca284nhg9nrrxg; [B2 B3 V6]; [B2 B3 V6] # יּႸ.𞡼𑇀ß⃗ +T; \uFB39ⴘ.𞡼𑇀ß\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ß⃗ +N; \uFB39ⴘ.𞡼𑇀ß\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ß⃗ +B; \uFB39Ⴘ.𞡼𑇀SS\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ss⃗ +B; \uFB39ⴘ.𞡼𑇀ss\u20D7; [B2 B3]; [B2 B3] # יּⴘ.𞡼𑇀ss⃗ +B; \uFB39Ⴘ.𞡼𑇀ss\u20D7; [B2 B3 P1 V6]; [B2 B3 P1 V6] # יּႸ.𞡼𑇀ss⃗ +B; \u1BA3𐹰ò±“。凬; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᮣ𐹰.凬 +B; \u1BA3𐹰ò±“。凬; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᮣ𐹰.凬 +B; xn--rxfz314ilg20c.xn--t9q; [B1 V5 V6]; [B1 V5 V6] # ᮣ𐹰.凬 +T; 🢟🄈\u200Dꡎ。\u0F84; [C2 P1 V5 V6]; [P1 V5 V6] # 🢟🄈ꡎ.྄ +N; 🢟🄈\u200Dꡎ。\u0F84; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 🢟🄈ꡎ.྄ +T; 🢟7,\u200Dꡎ。\u0F84; [C2 P1 V5 V6]; [P1 V5 V6] # 🢟7,ꡎ.྄ +N; 🢟7,\u200Dꡎ。\u0F84; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 🢟7,ꡎ.྄ +B; xn--7,-gh9hg322i.xn--3ed; [P1 V5 V6]; [P1 V5 V6] # 🢟7,ꡎ.྄ +B; xn--7,-n1t0654eqo3o.xn--3ed; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 🢟7,ꡎ.྄ +B; xn--nc9aq743ds0e.xn--3ed; [V5 V6]; [V5 V6] # 🢟🄈ꡎ.྄ +B; xn--1ug4874cfd0kbmg.xn--3ed; [C2 V5 V6]; [C2 V5 V6] # 🢟🄈ꡎ.྄ +B; ꡔ。\u1039ᢇ; [V5]; [V5] # ꡔ.္ᢇ +B; xn--tc9a.xn--9jd663b; [V5]; [V5] # ꡔ.္ᢇ +B; \u20EB≮.𝨖; [P1 V5 V6]; [P1 V5 V6] # ⃫≮.𝨖 +B; \u20EB<\u0338.𝨖; [P1 V5 V6]; [P1 V5 V6] # ⃫≮.𝨖 +B; xn--e1g71d.xn--772h; [V5 V6]; [V5 V6] # ⃫≮.𝨖 +B; Ⴢ≯褦.ᠪ\u07EAႾ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴢ≯褦.ᠪߪႾݧ +B; Ⴢ>\u0338褦.ᠪ\u07EAႾ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴢ≯褦.ᠪߪႾݧ +B; Ⴢ≯褦.á ª\u07EAႾ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴢ≯褦.ᠪߪႾݧ +B; Ⴢ>\u0338褦.á ª\u07EAႾ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴢ≯褦.ᠪߪႾݧ +B; â´¢>\u0338褦.á ª\u07EAⴞ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴢ≯褦.ᠪߪⴞݧ +B; ⴢ≯褦.á ª\u07EAⴞ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴢ≯褦.ᠪߪⴞݧ +B; xn--hdh433bev8e.xn--rpb5x392bcyt; [B5 B6 V6]; [B5 B6 V6] # ⴢ≯褦.ᠪߪⴞݧ +B; xn--6nd461g478e.xn--rpb5x49td2h; [B5 B6 V6]; [B5 B6 V6] # Ⴢ≯褦.ᠪߪႾݧ +B; â´¢>\u0338褦.ᠪ\u07EAⴞ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴢ≯褦.ᠪߪⴞݧ +B; ⴢ≯褦.ᠪ\u07EAⴞ\u0767; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴢ≯褦.ᠪߪⴞݧ +T; òЉ†ó †’\u200C\uA953。𞤙\u067Bꡘ; [B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # ꥓.𞤻ٻꡘ +N; òЉ†ó †’\u200C\uA953。𞤙\u067Bꡘ; [B2 B3 C1 P1 V6]; [B2 B3 C1 P1 V6] # ꥓.𞤻ٻꡘ +T; òЉ†ó †’\u200C\uA953。𞤻\u067Bꡘ; [B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # ꥓.𞤻ٻꡘ +N; òЉ†ó †’\u200C\uA953。𞤻\u067Bꡘ; [B2 B3 C1 P1 V6]; [B2 B3 C1 P1 V6] # ꥓.𞤻ٻꡘ +B; xn--3j9al6189a.xn--0ib8893fegvj; [B2 B3 V6]; [B2 B3 V6] # ꥓.𞤻ٻꡘ +B; xn--0ug8815chtz0e.xn--0ib8893fegvj; [B2 B3 C1 V6]; [B2 B3 C1 V6] # ꥓.𞤻ٻꡘ +T; \u200C.≯; [C1 P1 V6]; [P1 V6 A4_2] # .≯ +N; \u200C.≯; [C1 P1 V6]; [C1 P1 V6] # .≯ +T; \u200C.>\u0338; [C1 P1 V6]; [P1 V6 A4_2] # .≯ +N; \u200C.>\u0338; [C1 P1 V6]; [C1 P1 V6] # .≯ +B; .xn--hdh; [V6 A4_2]; [V6 A4_2] +B; xn--0ug.xn--hdh; [C1 V6]; [C1 V6] # .≯ +B; 𰅧ñ£© -.\uABED-悜; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -.꯭-悜 +B; 𰅧ñ£© -.\uABED-悜; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -.꯭-悜 +B; xn----7m53aj640l.xn----8f4br83t; [V3 V5 V6]; [V3 V5 V6] # -.꯭-悜 +T; ᡉ𶓧⬞ᢜ.-\u200D𞣑\u202E; [C2 P1 V3 V6]; [P1 V3 V6] # ᡉ⬞ᢜ.-𞣑 +N; ᡉ𶓧⬞ᢜ.-\u200D𞣑\u202E; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ᡉ⬞ᢜ.-𞣑 +B; xn--87e0ol04cdl39e.xn----qinu247r; [V3 V6]; [V3 V6] # ᡉ⬞ᢜ.-𞣑 +B; xn--87e0ol04cdl39e.xn----ugn5e3763s; [C2 V3 V6]; [C2 V3 V6] # ᡉ⬞ᢜ.-𞣑 +T; ⒐\u200C衃Ⴝ.\u0682Ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # ⒐衃Ⴝ.ڂႴ +N; ⒐\u200C衃Ⴝ.\u0682Ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # ⒐衃Ⴝ.ڂႴ +T; 9.\u200C衃Ⴝ.\u0682Ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 9.衃Ⴝ.ڂႴ +N; 9.\u200C衃Ⴝ.\u0682Ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 9.衃Ⴝ.ڂႴ +T; 9.\u200C衃ⴝ.\u0682ⴔ; [B1 B2 B3 C1]; [B1 B2 B3] # 9.衃ⴝ.ڂⴔ +N; 9.\u200C衃ⴝ.\u0682ⴔ; [B1 B2 B3 C1]; [B1 B2 B3 C1] # 9.衃ⴝ.ڂⴔ +T; 9.\u200C衃Ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # 9.衃Ⴝ.ڂⴔ +N; 9.\u200C衃Ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # 9.衃Ⴝ.ڂⴔ +B; 9.xn--1nd9032d.xn--7ib268q; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 9.衃Ⴝ.ڂⴔ +B; 9.xn--1nd159e1y2f.xn--7ib268q; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # 9.衃Ⴝ.ڂⴔ +B; 9.xn--llj1920a.xn--7ib268q; [B1 B2 B3]; [B1 B2 B3] # 9.衃ⴝ.ڂⴔ +B; 9.xn--0ug862cbm5e.xn--7ib268q; [B1 B2 B3 C1]; [B1 B2 B3 C1] # 9.衃ⴝ.ڂⴔ +B; 9.xn--1nd9032d.xn--7ib433c; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 9.衃Ⴝ.ڂႴ +B; 9.xn--1nd159e1y2f.xn--7ib433c; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # 9.衃Ⴝ.ڂႴ +T; ⒐\u200C衃ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # ⒐衃ⴝ.ڂⴔ +N; ⒐\u200C衃ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # ⒐衃ⴝ.ڂⴔ +T; ⒐\u200C衃Ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 P1 V6] # ⒐衃Ⴝ.ڂⴔ +N; ⒐\u200C衃Ⴝ.\u0682ⴔ; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # ⒐衃Ⴝ.ڂⴔ +B; xn--1nd362hy16e.xn--7ib268q; [B1 B2 B3 V6]; [B1 B2 B3 V6] # ⒐衃Ⴝ.ڂⴔ +B; xn--1nd159ecmd785k.xn--7ib268q; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # ⒐衃Ⴝ.ڂⴔ +B; xn--1shy52abz3f.xn--7ib268q; [B1 B2 B3 V6]; [B1 B2 B3 V6] # ⒐衃ⴝ.ڂⴔ +B; xn--0ugx0px1izu2h.xn--7ib268q; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # ⒐衃ⴝ.ڂⴔ +B; xn--1nd362hy16e.xn--7ib433c; [B1 B2 B3 V6]; [B1 B2 B3 V6] # ⒐衃Ⴝ.ڂႴ +B; xn--1nd159ecmd785k.xn--7ib433c; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # ⒐衃Ⴝ.ڂႴ +T; \u07E1\u200C。--⸬; [B1 B3 C1 V3]; [B1 V3] # ß¡.--⸬ +N; \u07E1\u200C。--⸬; [B1 B3 C1 V3]; [B1 B3 C1 V3] # ß¡.--⸬ +B; xn--8sb.xn-----iw2a; [B1 V3]; [B1 V3] # ß¡.--⸬ +B; xn--8sb884j.xn-----iw2a; [B1 B3 C1 V3]; [B1 B3 C1 V3] # ß¡.--⸬ +B; 𞥓.\u0718; 𞥓.\u0718; xn--of6h.xn--inb # 𞥓.ܘ +B; 𞥓.\u0718; ; xn--of6h.xn--inb # 𞥓.ܘ +B; xn--of6h.xn--inb; 𞥓.\u0718; xn--of6h.xn--inb # 𞥓.ܘ +B; 󠄽-.-\u0DCA; [V3]; [V3] # -.-් +B; 󠄽-.-\u0DCA; [V3]; [V3] # -.-් +B; -.xn----ptf; [V3]; [V3] # -.-් +B; 󠇝\u075B-.\u1927; [B1 B3 B6 V3 V5]; [B1 B3 B6 V3 V5] # ݛ-.ᤧ +B; xn----k4c.xn--lff; [B1 B3 B6 V3 V5]; [B1 B3 B6 V3 V5] # ݛ-.ᤧ +B; 𞤴󠆹⦉𐹺.\uA806⒌󘤸; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴⦉𐹺.꠆⒌ +B; 𞤴󠆹⦉𐹺.\uA8065.󘤸; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴⦉𐹺.꠆5. +B; 𞤒󠆹⦉𐹺.\uA8065.󘤸; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴⦉𐹺.꠆5. +B; xn--fuix729epewf.xn--5-w93e.xn--7b83e; [B1 V5 V6]; [B1 V5 V6] # 𞤴⦉𐹺.꠆5. +B; 𞤒󠆹⦉𐹺.\uA806⒌󘤸; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴⦉𐹺.꠆⒌ +B; xn--fuix729epewf.xn--xsh5029b6e77i; [B1 V5 V6]; [B1 V5 V6] # 𞤴⦉𐹺.꠆⒌ +T; 󠄸₀。𑖿\u200C𐦂\u200D; [B1 C2 V5]; [B1 V5] # 0.𑖿𐦂 +N; 󠄸₀。𑖿\u200C𐦂\u200D; [B1 C2 V5]; [B1 C2 V5] # 0.𑖿𐦂 +T; 󠄸0。𑖿\u200C𐦂\u200D; [B1 C2 V5]; [B1 V5] # 0.𑖿𐦂 +N; 󠄸0。𑖿\u200C𐦂\u200D; [B1 C2 V5]; [B1 C2 V5] # 0.𑖿𐦂 +B; 0.xn--mn9cz2s; [B1 V5]; [B1 V5] +B; 0.xn--0ugc8040p9hk; [B1 C2 V5]; [B1 C2 V5] # 0.𑖿𐦂 +B; Ⴚ𐋸󠄄。𝟝ퟶ\u103A; [P1 V6]; [P1 V6] # Ⴚ𐋸.5ퟶ် +B; Ⴚ𐋸󠄄。5ퟶ\u103A; [P1 V6]; [P1 V6] # Ⴚ𐋸.5ퟶ် +B; ⴚ𐋸󠄄。5ퟶ\u103A; ⴚ𐋸.5ퟶ\u103A; xn--ilj2659d.xn--5-dug9054m; NV8 # ⴚ𐋸.5ퟶ် +B; xn--ilj2659d.xn--5-dug9054m; ⴚ𐋸.5ퟶ\u103A; xn--ilj2659d.xn--5-dug9054m; NV8 # ⴚ𐋸.5ퟶ် +B; ⴚ𐋸.5ퟶ\u103A; ; xn--ilj2659d.xn--5-dug9054m; NV8 # ⴚ𐋸.5ퟶ် +B; Ⴚ𐋸.5ퟶ\u103A; [P1 V6]; [P1 V6] # Ⴚ𐋸.5ퟶ် +B; xn--ynd2415j.xn--5-dug9054m; [V6]; [V6] # Ⴚ𐋸.5ퟶ် +B; ⴚ𐋸󠄄。𝟝ퟶ\u103A; ⴚ𐋸.5ퟶ\u103A; xn--ilj2659d.xn--5-dug9054m; NV8 # ⴚ𐋸.5ퟶ် +T; \u200D-ᠹ﹪.\u1DE1\u1922; [C2 P1 V5 V6]; [P1 V3 V5 V6] # -ᠹ﹪.ᷡᤢ +N; \u200D-ᠹ﹪.\u1DE1\u1922; [C2 P1 V5 V6]; [C2 P1 V5 V6] # -ᠹ﹪.ᷡᤢ +T; \u200D-á ¹%.\u1DE1\u1922; [C2 P1 V5 V6]; [P1 V3 V5 V6] # -á ¹%.ᷡᤢ +N; \u200D-á ¹%.\u1DE1\u1922; [C2 P1 V5 V6]; [C2 P1 V5 V6] # -á ¹%.ᷡᤢ +B; xn---%-u4o.xn--gff52t; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -á ¹%.ᷡᤢ +B; xn---%-u4oy48b.xn--gff52t; [C2 P1 V5 V6]; [C2 P1 V5 V6] # -á ¹%.ᷡᤢ +B; xn----c6jx047j.xn--gff52t; [V3 V5 V6]; [V3 V5 V6] # -ᠹ﹪.ᷡᤢ +B; xn----c6j614b1z4v.xn--gff52t; [C2 V5 V6]; [C2 V5 V6] # -ᠹ﹪.ᷡᤢ +B; ≠.á ¿; [P1 V6]; [P1 V6] +B; =\u0338.á ¿; [P1 V6]; [P1 V6] +B; xn--1ch.xn--y7e; [V6]; [V6] +B; \u0723\u05A3。㌪; \u0723\u05A3.ハイツ; xn--ucb18e.xn--eck4c5a # Ü£Ö£.ハイツ +B; \u0723\u05A3。ハイツ; \u0723\u05A3.ハイツ; xn--ucb18e.xn--eck4c5a # Ü£Ö£.ハイツ +B; xn--ucb18e.xn--eck4c5a; \u0723\u05A3.ハイツ; xn--ucb18e.xn--eck4c5a # Ü£Ö£.ハイツ +B; \u0723\u05A3.ハイツ; ; xn--ucb18e.xn--eck4c5a # Ü£Ö£.ハイツ +B; 𞷥󠆀≮.\u2D7F-; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] # ≮.⵿- +B; 𞷥󠆀<\u0338.\u2D7F-; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] # ≮.⵿- +B; xn--gdhx802p.xn----i2s; [B1 B3 V3 V5 V6]; [B1 B3 V3 V5 V6] # ≮.⵿- +B; ₆榎ò¦–Ž\u0D4D。𞤅\u06ED\uFC5A󠮨; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 6榎്.𞤧ۭيي +B; 6榎ò¦–Ž\u0D4D。𞤅\u06ED\u064A\u064A󠮨; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 6榎്.𞤧ۭيي +B; 6榎ò¦–Ž\u0D4D。𞤧\u06ED\u064A\u064A󠮨; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 6榎്.𞤧ۭيي +B; xn--6-kmf4691ejv41j.xn--mhba10ch545mn8v8h; [B1 B3 V6]; [B1 B3 V6] # 6榎്.𞤧ۭيي +B; ₆榎ò¦–Ž\u0D4D。𞤧\u06ED\uFC5A󠮨; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 6榎്.𞤧ۭيي +B; 𣩫.òŒ‘²; [P1 V6]; [P1 V6] +B; 𣩫.òŒ‘²; [P1 V6]; [P1 V6] +B; xn--td3j.xn--4628b; [V6]; [V6] +T; \u200D︒。\u06B9\u200C; [B1 B3 C1 C2 P1 V6]; [B1 P1 V6] # ︒.Ú¹ +N; \u200D︒。\u06B9\u200C; [B1 B3 C1 C2 P1 V6]; [B1 B3 C1 C2 P1 V6] # ︒.Ú¹ +B; xn--y86c.xn--skb; [B1 V6]; [B1 V6] # ︒.Ú¹ +B; xn--1ug2658f.xn--skb080k; [B1 B3 C1 C2 V6]; [B1 B3 C1 C2 V6] # ︒.Ú¹ +B; xn--skb; \u06B9; xn--skb # Ú¹ +B; \u06B9; ; xn--skb # Ú¹ +T; 𐹦\u200C𐹶。\u206D; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹦𐹶. +N; 𐹦\u200C𐹶。\u206D; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹦𐹶. +B; xn--eo0d6a.xn--sxg; [B1 V6]; [B1 V6] # 𐹦𐹶. +B; xn--0ug4994goba.xn--sxg; [B1 C1 V6]; [B1 C1 V6] # 𐹦𐹶. +B; \u0C4D𝨾\u05A9𝟭。-𑜨; [V3 V5]; [V3 V5] # ్𝨾֩1.-𑜨 +B; \u0C4D𝨾\u05A91。-𑜨; [V3 V5]; [V3 V5] # ్𝨾֩1.-𑜨 +B; xn--1-rfc312cdp45c.xn----nq0j; [V3 V5]; [V3 V5] # ్𝨾֩1.-𑜨 +B; ò£¿ˆã€‚뙏; [P1 V6]; [P1 V6] +B; ò£¿ˆã€‚뙏; [P1 V6]; [P1 V6] +B; xn--ph26c.xn--281b; [V6]; [V6] +B; ñ•¨šó „Œó‘½€á¡€.\u08B6; [P1 V6]; [P1 V6] # ᡀ.ࢶ +B; xn--z7e98100evc01b.xn--czb; [V6]; [V6] # ᡀ.ࢶ +T; \u200D。ñ…›; [C2 P1 V6]; [P1 V6 A4_2] # . +N; \u200D。ñ…›; [C2 P1 V6]; [C2 P1 V6] # . +T; \u200D。ñ…›; [C2 P1 V6]; [P1 V6 A4_2] # . +N; \u200D。ñ…›; [C2 P1 V6]; [C2 P1 V6] # . +B; .xn--6x4u; [V6 A4_2]; [V6 A4_2] +B; xn--1ug.xn--6x4u; [C2 V6]; [C2 V6] # . +B; \u084B皥.-; [B1 B2 B3 V3]; [B1 B2 B3 V3] # ࡋ皥.- +B; \u084B皥.-; [B1 B2 B3 V3]; [B1 B2 B3 V3] # ࡋ皥.- +B; xn--9vb4167c.-; [B1 B2 B3 V3]; [B1 B2 B3 V3] # ࡋ皥.- +B; 𐣸\u0315𐮇.⒈ꡦ; [B1 P1 V6]; [B1 P1 V6] # ̕𐮇.⒈ꡦ +B; 𐣸\u0315𐮇.1.ꡦ; [B1 P1 V6]; [B1 P1 V6] # ̕𐮇.1.ꡦ +B; xn--5sa9915kgvb.1.xn--cd9a; [B1 V6]; [B1 V6] # ̕𐮇.1.ꡦ +B; xn--5sa9915kgvb.xn--tshw539b; [B1 V6]; [B1 V6] # ̕𐮇.⒈ꡦ +T; Ⴛ\u200C\u05A2\u200D。\uFFA0ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\uFFA0ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\uFFA0a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\uFFA0a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\u1160ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\u1160ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\u1160a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\u1160a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; ⴛ\u200C\u05A2\u200D。\u1160a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ⴛ֢.ā𐹦 +N; ⴛ\u200C\u05A2\u200D。\u1160a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ⴛ֢.ā𐹦 +T; ⴛ\u200C\u05A2\u200D。\u1160ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ⴛ֢.ā𐹦 +N; ⴛ\u200C\u05A2\u200D。\u1160ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\u1160Ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\u1160Ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\u1160A\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\u1160A\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb597c.xn--yda594fdn5q; [B5 B6 V6]; [B5 B6 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb597cdmmfa.xn--yda594fdn5q; [B5 B6 C1 C2 V6]; [B5 B6 C1 C2 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb323r.xn--yda594fdn5q; [B5 B6 V6]; [B5 B6 V6] # ⴛ֢.ā𐹦 +B; xn--tcb736kea974k.xn--yda594fdn5q; [B5 B6 C1 C2 V6]; [B5 B6 C1 C2 V6] # ⴛ֢.ā𐹦 +T; ⴛ\u200C\u05A2\u200D。\uFFA0a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ⴛ֢.ā𐹦 +N; ⴛ\u200C\u05A2\u200D。\uFFA0a\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ⴛ֢.ā𐹦 +T; ⴛ\u200C\u05A2\u200D。\uFFA0ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ⴛ֢.ā𐹦 +N; ⴛ\u200C\u05A2\u200D。\uFFA0ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\uFFA0Ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\uFFA0Ā𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +T; Ⴛ\u200C\u05A2\u200D。\uFFA0A\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # Ⴛ֢.ā𐹦 +N; Ⴛ\u200C\u05A2\u200D。\uFFA0A\u0304𐹦; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb597c.xn--yda9741khjj; [B5 B6 V6]; [B5 B6 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb597cdmmfa.xn--yda9741khjj; [B5 B6 C1 C2 V6]; [B5 B6 C1 C2 V6] # Ⴛ֢.ā𐹦 +B; xn--tcb323r.xn--yda9741khjj; [B5 B6 V6]; [B5 B6 V6] # ⴛ֢.ā𐹦 +B; xn--tcb736kea974k.xn--yda9741khjj; [B5 B6 C1 C2 V6]; [B5 B6 C1 C2 V6] # ⴛ֢.ā𐹦 +T; \uFFF9\u200C。曳⾑𐋰≯; [C1 P1 V6]; [P1 V6] # .曳襾𐋰≯ +N; \uFFF9\u200C。曳⾑𐋰≯; [C1 P1 V6]; [C1 P1 V6] # .曳襾𐋰≯ +T; \uFFF9\u200C。曳⾑𐋰>\u0338; [C1 P1 V6]; [P1 V6] # .曳襾𐋰≯ +N; \uFFF9\u200C。曳⾑𐋰>\u0338; [C1 P1 V6]; [C1 P1 V6] # .曳襾𐋰≯ +T; \uFFF9\u200C。曳襾𐋰≯; [C1 P1 V6]; [P1 V6] # .曳襾𐋰≯ +N; \uFFF9\u200C。曳襾𐋰≯; [C1 P1 V6]; [C1 P1 V6] # .曳襾𐋰≯ +T; \uFFF9\u200C。曳襾𐋰>\u0338; [C1 P1 V6]; [P1 V6] # .曳襾𐋰≯ +N; \uFFF9\u200C。曳襾𐋰>\u0338; [C1 P1 V6]; [C1 P1 V6] # .曳襾𐋰≯ +B; xn--vn7c.xn--hdh501y8wvfs5h; [V6]; [V6] # .曳襾𐋰≯ +B; xn--0ug2139f.xn--hdh501y8wvfs5h; [C1 V6]; [C1 V6] # .曳襾𐋰≯ +T; ≯⒈。ß; [P1 V6]; [P1 V6] +N; ≯⒈。ß; [P1 V6]; [P1 V6] +T; >\u0338⒈。ß; [P1 V6]; [P1 V6] +N; >\u0338⒈。ß; [P1 V6]; [P1 V6] +T; ≯1.。ß; [P1 V6 A4_2]; [P1 V6 A4_2] +N; ≯1.。ß; [P1 V6 A4_2]; [P1 V6 A4_2] +T; >\u03381.。ß; [P1 V6 A4_2]; [P1 V6 A4_2] +N; >\u03381.。ß; [P1 V6 A4_2]; [P1 V6 A4_2] +B; >\u03381.。SS; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ≯1.。SS; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ≯1.。ss; [P1 V6 A4_2]; [P1 V6 A4_2] +B; >\u03381.。ss; [P1 V6 A4_2]; [P1 V6 A4_2] +B; >\u03381.。Ss; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ≯1.。Ss; [P1 V6 A4_2]; [P1 V6 A4_2] +B; xn--1-ogo..ss; [V6 A4_2]; [V6 A4_2] +B; xn--1-ogo..xn--zca; [V6 A4_2]; [V6 A4_2] +B; >\u0338⒈。SS; [P1 V6]; [P1 V6] +B; ≯⒈。SS; [P1 V6]; [P1 V6] +B; ≯⒈。ss; [P1 V6]; [P1 V6] +B; >\u0338⒈。ss; [P1 V6]; [P1 V6] +B; >\u0338⒈。Ss; [P1 V6]; [P1 V6] +B; ≯⒈。Ss; [P1 V6]; [P1 V6] +B; xn--hdh84f.ss; [V6]; [V6] +B; xn--hdh84f.xn--zca; [V6]; [V6] +T; \u0667\u200D\uFB96。\u07DA-₆Ⴙ; [B1 B2 B3 C2 P1 V6]; [B1 B2 B3 P1 V6] # Ù§Ú³.ߚ-6Ⴙ +N; \u0667\u200D\uFB96。\u07DA-₆Ⴙ; [B1 B2 B3 C2 P1 V6]; [B1 B2 B3 C2 P1 V6] # Ù§Ú³.ߚ-6Ⴙ +T; \u0667\u200D\u06B3。\u07DA-6Ⴙ; [B1 B2 B3 C2 P1 V6]; [B1 B2 B3 P1 V6] # Ù§Ú³.ߚ-6Ⴙ +N; \u0667\u200D\u06B3。\u07DA-6Ⴙ; [B1 B2 B3 C2 P1 V6]; [B1 B2 B3 C2 P1 V6] # Ù§Ú³.ߚ-6Ⴙ +T; \u0667\u200D\u06B3。\u07DA-6ⴙ; [B1 B2 B3 C2]; [B1 B2 B3] # Ù§Ú³.ߚ-6ⴙ +N; \u0667\u200D\u06B3。\u07DA-6ⴙ; [B1 B2 B3 C2]; [B1 B2 B3 C2] # Ù§Ú³.ߚ-6ⴙ +B; xn--gib6m.xn---6-lve6529a; [B1 B2 B3]; [B1 B2 B3] # Ù§Ú³.ߚ-6ⴙ +B; xn--gib6m343e.xn---6-lve6529a; [B1 B2 B3 C2]; [B1 B2 B3 C2] # Ù§Ú³.ߚ-6ⴙ +B; xn--gib6m.xn---6-lve002g; [B1 B2 B3 V6]; [B1 B2 B3 V6] # Ù§Ú³.ߚ-6Ⴙ +B; xn--gib6m343e.xn---6-lve002g; [B1 B2 B3 C2 V6]; [B1 B2 B3 C2 V6] # Ù§Ú³.ߚ-6Ⴙ +T; \u0667\u200D\uFB96。\u07DA-₆ⴙ; [B1 B2 B3 C2]; [B1 B2 B3] # Ù§Ú³.ߚ-6ⴙ +N; \u0667\u200D\uFB96。\u07DA-₆ⴙ; [B1 B2 B3 C2]; [B1 B2 B3 C2] # Ù§Ú³.ߚ-6ⴙ +T; \u200C。≠; [C1 P1 V6]; [P1 V6 A4_2] # .≠ +N; \u200C。≠; [C1 P1 V6]; [C1 P1 V6] # .≠ +T; \u200C。=\u0338; [C1 P1 V6]; [P1 V6 A4_2] # .≠ +N; \u200C。=\u0338; [C1 P1 V6]; [C1 P1 V6] # .≠ +T; \u200C。≠; [C1 P1 V6]; [P1 V6 A4_2] # .≠ +N; \u200C。≠; [C1 P1 V6]; [C1 P1 V6] # .≠ +T; \u200C。=\u0338; [C1 P1 V6]; [P1 V6 A4_2] # .≠ +N; \u200C。=\u0338; [C1 P1 V6]; [C1 P1 V6] # .≠ +B; .xn--1ch; [V6 A4_2]; [V6 A4_2] +B; xn--0ug.xn--1ch; [C1 V6]; [C1 V6] # .≠ +T; 𑖿𝨔.ᡟ𑖿\u1B42\u200C; [C1 V5]; [V5] # 𑖿𝨔.ᡟ𑖿ᭂ +N; 𑖿𝨔.ᡟ𑖿\u1B42\u200C; [C1 V5]; [C1 V5] # 𑖿𝨔.ᡟ𑖿ᭂ +B; xn--461dw464a.xn--v8e29loy65a; [V5]; [V5] # 𑖿𝨔.ᡟ𑖿ᭂ +B; xn--461dw464a.xn--v8e29ldzfo952a; [C1 V5]; [C1 V5] # 𑖿𝨔.ᡟ𑖿ᭂ +T; ò”£³\u200Dò‘±.𖬴Ↄ≠-; [C2 P1 V3 V5 V6]; [P1 V3 V5 V6] # .𖬴Ↄ≠- +N; ò”£³\u200Dò‘±.𖬴Ↄ≠-; [C2 P1 V3 V5 V6]; [C2 P1 V3 V5 V6] # .𖬴Ↄ≠- +T; ò”£³\u200Dò‘±.𖬴Ↄ=\u0338-; [C2 P1 V3 V5 V6]; [P1 V3 V5 V6] # .𖬴Ↄ≠- +N; ò”£³\u200Dò‘±.𖬴Ↄ=\u0338-; [C2 P1 V3 V5 V6]; [C2 P1 V3 V5 V6] # .𖬴Ↄ≠- +T; ò”£³\u200Dò‘±.𖬴ↄ=\u0338-; [C2 P1 V3 V5 V6]; [P1 V3 V5 V6] # .𖬴ↄ≠- +N; ò”£³\u200Dò‘±.𖬴ↄ=\u0338-; [C2 P1 V3 V5 V6]; [C2 P1 V3 V5 V6] # .𖬴ↄ≠- +T; ò”£³\u200Dò‘±.𖬴ↄ≠-; [C2 P1 V3 V5 V6]; [P1 V3 V5 V6] # .𖬴ↄ≠- +N; ò”£³\u200Dò‘±.𖬴ↄ≠-; [C2 P1 V3 V5 V6]; [C2 P1 V3 V5 V6] # .𖬴ↄ≠- +B; xn--6j00chy9a.xn----81n51bt713h; [V3 V5 V6]; [V3 V5 V6] +B; xn--1ug15151gkb5a.xn----81n51bt713h; [C2 V3 V5 V6]; [C2 V3 V5 V6] # .𖬴ↄ≠- +B; xn--6j00chy9a.xn----61n81bt713h; [V3 V5 V6]; [V3 V5 V6] +B; xn--1ug15151gkb5a.xn----61n81bt713h; [C2 V3 V5 V6]; [C2 V3 V5 V6] # .𖬴Ↄ≠- +T; \u07E2ς\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢς7.蔑 +N; \u07E2ς\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢς7.蔑 +T; \u07E2ς\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢς7.蔑 +N; \u07E2ς\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢς7.蔑 +T; \u07E2Σ\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢσ7.蔑 +N; \u07E2Σ\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢσ7.蔑 +T; \u07E2σ\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢσ7.蔑 +N; \u07E2σ\u200D7。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢσ7.蔑 +B; xn--7-zmb872a.xn--wy1ao4929b; [B2 V6]; [B2 V6] # ߢσ7.蔑 +B; xn--7-zmb872aez5a.xn--wy1ao4929b; [B2 C2 V6]; [B2 C2 V6] # ߢσ7.蔑 +B; xn--7-xmb182aez5a.xn--wy1ao4929b; [B2 C2 V6]; [B2 C2 V6] # ߢς7.蔑 +T; \u07E2Σ\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢσ7.蔑 +N; \u07E2Σ\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢσ7.蔑 +T; \u07E2σ\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 P1 V6] # ߢσ7.蔑 +N; \u07E2σ\u200D𝟳。蔑ò›–¢; [B2 C2 P1 V6]; [B2 C2 P1 V6] # ߢσ7.蔑 +B; 𐹰.\u0600; [B1 P1 V6]; [B1 P1 V6] # 𐹰. +B; xn--oo0d.xn--ifb; [B1 V6]; [B1 V6] # 𐹰. +B; -\u08A8.𱠖; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ࢨ. +B; xn----mod.xn--5o9n; [B1 V3 V6]; [B1 V3 V6] # -ࢨ. +B; ≯𞱸󠇀。誆⒈; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338𞱸󠇀。誆⒈; [B1 P1 V6]; [B1 P1 V6] +B; ≯𞱸󠇀。誆1.; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338𞱸󠇀。誆1.; [B1 P1 V6]; [B1 P1 V6] +B; xn--hdh7151p.xn--1-dy1d.; [B1 V6]; [B1 V6] +B; xn--hdh7151p.xn--tsh1248a; [B1 V6]; [B1 V6] +B; \u0616𞥙䐊\u0650.︒\u0645↺\u069C; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ؖ𞥙䐊ِ.︒م↺ڜ +B; \u0616𞥙䐊\u0650.。\u0645↺\u069C; [B1 V5 A4_2]; [B1 V5 A4_2] # ؖ𞥙䐊ِ..م↺ڜ +B; xn--4fb0j490qjg4x..xn--hhb8o948e; [B1 V5 A4_2]; [B1 V5 A4_2] # ؖ𞥙䐊ِ..م↺ڜ +B; xn--4fb0j490qjg4x.xn--hhb8o948euo5r; [B1 V5 V6]; [B1 V5 V6] # ؖ𞥙䐊ِ.︒م↺ڜ +T; 퀬-\uDF7Eñ¶³’.\u200C\u0AC5󩸤۴; [C1 P1 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +N; 퀬-\uDF7Eñ¶³’.\u200C\u0AC5󩸤۴; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +T; 퀬-\uDF7Eñ¶³’.\u200C\u0AC5󩸤۴; [C1 P1 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +N; 퀬-\uDF7Eñ¶³’.\u200C\u0AC5󩸤۴; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.xn--hmb76q74166b; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.xn--hmb76q74166b; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.XN--HMB76Q74166B; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.XN--HMB76Q74166B; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.Xn--Hmb76q74166b; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.Xn--Hmb76q74166b; [P1 V5 V6]; [P1 V5 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.xn--hmb76q48y18505a; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.xn--hmb76q48y18505a; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.XN--HMB76Q48Y18505A; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.XN--HMB76Q48Y18505A; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.Xn--Hmb76q48y18505a; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; 퀬-\uDF7Eñ¶³’.Xn--Hmb76q48y18505a; [C1 P1 V6]; [C1 P1 V6 A3] # 퀬-.ૅ۴ +B; Ⴌ.𐹾︒𑁿𞾄; [B1 P1 V6]; [B1 P1 V6] +B; Ⴌ.𐹾。𑁿𞾄; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; ⴌ.𐹾。𑁿𞾄; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; xn--3kj.xn--2o0d.xn--q30dg029a; [B1 V5 V6]; [B1 V5 V6] +B; xn--knd.xn--2o0d.xn--q30dg029a; [B1 V5 V6]; [B1 V5 V6] +B; ⴌ.𐹾︒𑁿𞾄; [B1 P1 V6]; [B1 P1 V6] +B; xn--3kj.xn--y86c030a9ob6374b; [B1 V6]; [B1 V6] +B; xn--knd.xn--y86c030a9ob6374b; [B1 V6]; [B1 V6] +B; ñ§ž¿â•ã€‚𞩕󠁾; [B3 B6 P1 V6]; [B3 B6 P1 V6] +B; xn--iyh90030d.xn--1m6hs0260c; [B3 B6 V6]; [B3 B6 V6] +T; \u200D┮󠇐.\u0C00\u0C4D\u1734\u200D; [C2 V5]; [V5] # ┮.ఀ్᜴ +N; \u200D┮󠇐.\u0C00\u0C4D\u1734\u200D; [C2 V5]; [C2 V5] # ┮.ఀ్᜴ +T; \u200D┮󠇐.\u0C00\u0C4D\u1734\u200D; [C2 V5]; [V5] # ┮.ఀ్᜴ +N; \u200D┮󠇐.\u0C00\u0C4D\u1734\u200D; [C2 V5]; [C2 V5] # ┮.ఀ్᜴ +B; xn--kxh.xn--eoc8m432a; [V5]; [V5] # ┮.ఀ్᜴ +B; xn--1ug04r.xn--eoc8m432a40i; [C2 V5]; [C2 V5] # ┮.ఀ్᜴ +B; ò¹šªï½¡ðŸ„‚; [P1 V6]; [P1 V6] +B; ò¹šªã€‚1,; [P1 V6]; [P1 V6] +B; xn--n433d.1,; [P1 V6]; [P1 V6] +B; xn--n433d.xn--v07h; [V6]; [V6] +B; 𑍨刍.🛦; [V5]; [V5] +B; xn--rbry728b.xn--y88h; [V5]; [V5] +B; 󠌏3。\u1BF1𝟒; [P1 V5 V6]; [P1 V5 V6] # 3.ᯱ4 +B; 󠌏3。\u1BF14; [P1 V5 V6]; [P1 V5 V6] # 3.ᯱ4 +B; xn--3-ib31m.xn--4-pql; [V5 V6]; [V5 V6] # 3.ᯱ4 +T; \u06876Ⴔ辘.\uFD22\u0687\u200C; [B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # ڇ6Ⴔ辘.صيڇ +N; \u06876Ⴔ辘.\uFD22\u0687\u200C; [B2 B3 C1 P1 V6]; [B2 B3 C1 P1 V6] # ڇ6Ⴔ辘.صيڇ +T; \u06876Ⴔ辘.\u0635\u064A\u0687\u200C; [B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # ڇ6Ⴔ辘.صيڇ +N; \u06876Ⴔ辘.\u0635\u064A\u0687\u200C; [B2 B3 C1 P1 V6]; [B2 B3 C1 P1 V6] # ڇ6Ⴔ辘.صيڇ +T; \u06876ⴔ辘.\u0635\u064A\u0687\u200C; [B2 B3 C1]; [B2 B3] # ڇ6ⴔ辘.صيڇ +N; \u06876ⴔ辘.\u0635\u064A\u0687\u200C; [B2 B3 C1]; [B2 B3 C1] # ڇ6ⴔ辘.صيڇ +B; xn--6-gsc2270akm6f.xn--0gb6bxk; [B2 B3]; [B2 B3] # ڇ6ⴔ辘.صيڇ +B; xn--6-gsc2270akm6f.xn--0gb6bxkx18g; [B2 B3 C1]; [B2 B3 C1] # ڇ6ⴔ辘.صيڇ +B; xn--6-gsc039eqq6k.xn--0gb6bxk; [B2 B3 V6]; [B2 B3 V6] # ڇ6Ⴔ辘.صيڇ +B; xn--6-gsc039eqq6k.xn--0gb6bxkx18g; [B2 B3 C1 V6]; [B2 B3 C1 V6] # ڇ6Ⴔ辘.صيڇ +T; \u06876ⴔ辘.\uFD22\u0687\u200C; [B2 B3 C1]; [B2 B3] # ڇ6ⴔ辘.صيڇ +N; \u06876ⴔ辘.\uFD22\u0687\u200C; [B2 B3 C1]; [B2 B3 C1] # ڇ6ⴔ辘.صيڇ +B; 󠄍.𐮭𞰬ò»«žÛ¹; [B2 P1 V6 A4_2]; [B2 P1 V6 A4_2] +B; .xn--mmb3954kd0uf1zx7f; [B2 V6 A4_2]; [B2 V6 A4_2] +B; \uA87D≯.ò»²€ò’³„; [P1 V6]; [P1 V6] # ≯. +B; \uA87D>\u0338.ò»²€ò’³„; [P1 V6]; [P1 V6] # ≯. +B; \uA87D≯.ò»²€ò’³„; [P1 V6]; [P1 V6] # ≯. +B; \uA87D>\u0338.ò»²€ò’³„; [P1 V6]; [P1 V6] # ≯. +B; xn--hdh8193c.xn--5z40cp629b; [V6]; [V6] # ≯. +T; ςო\u067B.ς\u0714; [B5 B6]; [B5 B6] # ςოٻ.ςܔ +N; ςო\u067B.ς\u0714; [B5 B6]; [B5 B6] # ςოٻ.ςܔ +B; Σო\u067B.Σ\u0714; [B5 B6]; [B5 B6] # σოٻ.σܔ +B; σო\u067B.σ\u0714; [B5 B6]; [B5 B6] # σოٻ.σܔ +B; Σო\u067B.σ\u0714; [B5 B6]; [B5 B6] # σოٻ.σܔ +B; xn--4xa60l26n.xn--4xa21o; [B5 B6]; [B5 B6] # σოٻ.σܔ +T; Σო\u067B.ς\u0714; [B5 B6]; [B5 B6] # σოٻ.ςܔ +N; Σო\u067B.ς\u0714; [B5 B6]; [B5 B6] # σოٻ.ςܔ +T; σო\u067B.ς\u0714; [B5 B6]; [B5 B6] # σოٻ.ςܔ +N; σო\u067B.ς\u0714; [B5 B6]; [B5 B6] # σოٻ.ςܔ +B; xn--4xa60l26n.xn--3xa41o; [B5 B6]; [B5 B6] # σოٻ.ςܔ +B; xn--3xa80l26n.xn--3xa41o; [B5 B6]; [B5 B6] # ςოٻ.ςܔ +B; ò„–š\u0748𠄯\u075F。󠛩; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ݈𠄯ݟ. +B; ò„–š\u0748𠄯\u075F。󠛩; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ݈𠄯ݟ. +B; xn--vob0c4369twfv8b.xn--kl46e; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ݈𠄯ݟ. +T; 󠳛.\u200D䤫≠Ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠Ⴞ +N; 󠳛.\u200D䤫≠Ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠Ⴞ +T; 󠳛.\u200D䤫=\u0338Ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠Ⴞ +N; 󠳛.\u200D䤫=\u0338Ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠Ⴞ +T; 󠳛.\u200D䤫≠Ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠Ⴞ +N; 󠳛.\u200D䤫≠Ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠Ⴞ +T; 󠳛.\u200D䤫=\u0338Ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠Ⴞ +N; 󠳛.\u200D䤫=\u0338Ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠Ⴞ +T; 󠳛.\u200D䤫=\u0338ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠ⴞ +N; 󠳛.\u200D䤫=\u0338ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠ⴞ +T; 󠳛.\u200D䤫≠ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠ⴞ +N; 󠳛.\u200D䤫≠ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠ⴞ +B; xn--1t56e.xn--1ch153bqvw; [V6]; [V6] +B; xn--1t56e.xn--1ug73gzzpwi3a; [C2 V6]; [C2 V6] # .䤫≠ⴞ +B; xn--1t56e.xn--2nd141ghl2a; [V6]; [V6] +B; xn--1t56e.xn--2nd159e9vb743e; [C2 V6]; [C2 V6] # .䤫≠Ⴞ +T; 󠳛.\u200D䤫=\u0338ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠ⴞ +N; 󠳛.\u200D䤫=\u0338ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠ⴞ +T; 󠳛.\u200D䤫≠ⴞ; [C2 P1 V6]; [P1 V6] # .䤫≠ⴞ +N; 󠳛.\u200D䤫≠ⴞ; [C2 P1 V6]; [C2 P1 V6] # .䤫≠ⴞ +B; 𐽘𑈵.𐹣🕥; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 𐽘𑈵.𐹣🕥; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; xn--bv0d02c.xn--bo0dq650b; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; ⒊⒈𑁄。9; [P1 V6]; [P1 V6] +B; 3.1.𑁄。9; [V5]; [V5] +B; 3.1.xn--110d.9; [V5]; [V5] +B; xn--tshd3512p.9; [V6]; [V6] +T; -\u200C\u2DF1≮.𐹱ò­´4₉; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ⷱ≮.𐹱49 +N; -\u200C\u2DF1≮.𐹱ò­´4₉; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ⷱ≮.𐹱49 +T; -\u200C\u2DF1<\u0338.𐹱ò­´4₉; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ⷱ≮.𐹱49 +N; -\u200C\u2DF1<\u0338.𐹱ò­´4₉; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ⷱ≮.𐹱49 +T; -\u200C\u2DF1≮.𐹱ò­´49; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ⷱ≮.𐹱49 +N; -\u200C\u2DF1≮.𐹱ò­´49; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ⷱ≮.𐹱49 +T; -\u200C\u2DF1<\u0338.𐹱ò­´49; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # -ⷱ≮.𐹱49 +N; -\u200C\u2DF1<\u0338.𐹱ò­´49; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # -ⷱ≮.𐹱49 +B; xn----ngo823c.xn--49-ki3om2611f; [B1 V3 V6]; [B1 V3 V6] # -ⷱ≮.𐹱49 +B; xn----sgn20i14s.xn--49-ki3om2611f; [B1 C1 V3 V6]; [B1 C1 V3 V6] # -ⷱ≮.𐹱49 +B; -≯딾。\u0847; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≯딾.ࡇ +B; ->\u0338딾。\u0847; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≯딾.ࡇ +B; -≯딾。\u0847; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≯딾.ࡇ +B; ->\u0338딾。\u0847; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≯딾.ࡇ +B; xn----pgow547d.xn--5vb; [B1 V3 V6]; [B1 V3 V6] # -≯딾.ࡇ +T; 𑙢⒈𐹠-。󠗐\u200C; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𑙢⒈𐹠-. +N; 𑙢⒈𐹠-。󠗐\u200C; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𑙢⒈𐹠-. +T; 𑙢1.𐹠-。󠗐\u200C; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𑙢1.𐹠-. +N; 𑙢1.𐹠-。󠗐\u200C; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𑙢1.𐹠-. +B; xn--1-bf0j.xn----516i.xn--jd46e; [B1 V3 V6]; [B1 V3 V6] +B; xn--1-bf0j.xn----516i.xn--0ug23321l; [B1 C1 V3 V6]; [B1 C1 V3 V6] # 𑙢1.𐹠-. +B; xn----dcpy090hiyg.xn--jd46e; [B1 V3 V6]; [B1 V3 V6] +B; xn----dcpy090hiyg.xn--0ug23321l; [B1 C1 V3 V6]; [B1 C1 V3 V6] # 𑙢⒈𐹠-. +B; \u034A.𐨎; [V5]; [V5] # ͊.𐨎 +B; \u034A.𐨎; [V5]; [V5] # ͊.𐨎 +B; xn--oua.xn--mr9c; [V5]; [V5] # ͊.𐨎 +B; 훉≮。\u0E34; [P1 V5 V6]; [P1 V5 V6] # 훉≮.ิ +B; 훉<\u0338。\u0E34; [P1 V5 V6]; [P1 V5 V6] # 훉≮.ิ +B; 훉≮。\u0E34; [P1 V5 V6]; [P1 V5 V6] # 훉≮.ิ +B; 훉<\u0338。\u0E34; [P1 V5 V6]; [P1 V5 V6] # 훉≮.ิ +B; xn--gdh2512e.xn--i4c; [V5 V6]; [V5 V6] # 훉≮.ิ +B; \u2DF7òž£‰ðŸƒ˜ï¼Žð´ˆ‡ðŸ¸\u0659𞤯; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ⷷ🃘.2ٙ𞤯 +B; \u2DF7òž£‰ðŸƒ˜.𴈇2\u0659𞤯; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ⷷ🃘.2ٙ𞤯 +B; \u2DF7òž£‰ðŸƒ˜.𴈇2\u0659𞤍; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ⷷ🃘.2ٙ𞤯 +B; xn--trj8045le6s9b.xn--2-upc23918acjsj; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ⷷ🃘.2ٙ𞤯 +B; \u2DF7òž£‰ðŸƒ˜ï¼Žð´ˆ‡ðŸ¸\u0659𞤍; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ⷷ🃘.2ٙ𞤯 +T; 󗇩ßᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ßᢞ.٠نخ- +N; 󗇩ßᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ßᢞ.٠نخ- +T; 󗇩ßᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ßᢞ.٠نخ- +N; 󗇩ßᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ßᢞ.٠نخ- +T; 󗇩SSᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩SSᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +T; 󗇩ssᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩ssᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +T; 󗇩Ssᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩Ssᢞ\u200C。\u0660𞷻\u0646\u062E-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +B; xn--ss-jepz4596r.xn----dnc5e1er384z; [B1 V3 V6]; [B1 V3 V6] # ssᢞ.٠نخ- +B; xn--ss-jep006bqt765b.xn----dnc5e1er384z; [B1 B6 C1 V3 V6]; [B1 B6 C1 V3 V6] # ssᢞ.٠نخ- +B; xn--zca272jbif10059a.xn----dnc5e1er384z; [B1 B6 C1 V3 V6]; [B1 B6 C1 V3 V6] # ßᢞ.٠نخ- +T; 󗇩SSᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩SSᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +T; 󗇩ssᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩ssᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +T; 󗇩Ssᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 P1 V3 V6] # ssᢞ.٠نخ- +N; 󗇩Ssᢞ\u200C。\u0660𞷻\uFCD4-; [B1 B6 C1 P1 V3 V6]; [B1 B6 C1 P1 V3 V6] # ssᢞ.٠نخ- +B; ꡆ。Ↄ\u0FB5놮-; [P1 V3 V6]; [P1 V3 V6] # ꡆ.Ↄྵ놮- +B; ꡆ。Ↄ\u0FB5놮-; [P1 V3 V6]; [P1 V3 V6] # ꡆ.Ↄྵ놮- +B; ꡆ。ↄ\u0FB5놮-; [V3]; [V3] # ꡆ.ↄྵ놮- +B; ꡆ。ↄ\u0FB5놮-; [V3]; [V3] # ꡆ.ↄྵ놮- +B; xn--fc9a.xn----qmg097k469k; [V3]; [V3] # ꡆ.ↄྵ놮- +B; xn--fc9a.xn----qmg787k869k; [V3 V6]; [V3 V6] # ꡆ.Ↄྵ놮- +T; \uFDAD\u200D.ñ¥°Œ\u06A9; [B3 B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # لمي.Ú© +N; \uFDAD\u200D.ñ¥°Œ\u06A9; [B3 B5 B6 C2 P1 V6]; [B3 B5 B6 C2 P1 V6] # لمي.Ú© +T; \u0644\u0645\u064A\u200D.ñ¥°Œ\u06A9; [B3 B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # لمي.Ú© +N; \u0644\u0645\u064A\u200D.ñ¥°Œ\u06A9; [B3 B5 B6 C2 P1 V6]; [B3 B5 B6 C2 P1 V6] # لمي.Ú© +B; xn--ghbcp.xn--ckb36214f; [B5 B6 V6]; [B5 B6 V6] # لمي.Ú© +B; xn--ghbcp494x.xn--ckb36214f; [B3 B5 B6 C2 V6]; [B3 B5 B6 C2 V6] # لمي.Ú© +B; Ⴜ\u1C2F𐳒≯。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # Ⴜᰯ𐳒≯.۠ᜲྺ +B; Ⴜ\u1C2F𐳒>\u0338。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # Ⴜᰯ𐳒≯.۠ᜲྺ +B; ⴜ\u1C2F𐳒>\u0338。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ⴜᰯ𐳒≯.۠ᜲྺ +B; ⴜ\u1C2F𐳒≯。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ⴜᰯ𐳒≯.۠ᜲྺ +B; Ⴜ\u1C2F𐲒≯。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # Ⴜᰯ𐳒≯.۠ᜲྺ +B; Ⴜ\u1C2F𐲒>\u0338。\u06E0\u1732\u0FBA; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # Ⴜᰯ𐳒≯.۠ᜲྺ +B; xn--0nd679cf3eq67y.xn--wlb646b4ng; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # Ⴜᰯ𐳒≯.۠ᜲྺ +B; xn--r1f68xh1jgv7u.xn--wlb646b4ng; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ⴜᰯ𐳒≯.۠ᜲྺ +B; 𐋵。\uFCEC; [B1]; [B1] # 𐋵.كم +B; 𐋵。\u0643\u0645; [B1]; [B1] # 𐋵.كم +B; xn--p97c.xn--fhbe; [B1]; [B1] # 𐋵.كم +B; 𐋵.\u0643\u0645; [B1]; [B1] # 𐋵.كم +B; ≮𝅶.ñ±²\uAAEC⹈󰥭; [P1 V6]; [P1 V6] # ≮.ꫬ⹈ +B; <\u0338𝅶.ñ±²\uAAEC⹈󰥭; [P1 V6]; [P1 V6] # ≮.ꫬ⹈ +B; ≮𝅶.ñ±²\uAAEC⹈󰥭; [P1 V6]; [P1 V6] # ≮.ꫬ⹈ +B; <\u0338𝅶.ñ±²\uAAEC⹈󰥭; [P1 V6]; [P1 V6] # ≮.ꫬ⹈ +B; xn--gdh0880o.xn--4tjx101bsg00ds9pyc; [V6]; [V6] # ≮.ꫬ⹈ +B; \u2DF0\u0358ᢕ.\u0361𐹷󠴍; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ⷰ͘ᢕ.͡𐹷 +B; \u2DF0\u0358ᢕ.\u0361𐹷󠴍; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ⷰ͘ᢕ.͡𐹷 +B; xn--2ua889htsp.xn--cva2687k2tv0g; [B1 V5 V6]; [B1 V5 V6] # ⷰ͘ᢕ.͡𐹷 +T; \uFD79ᡐ\u200C\u06AD.𑋪\u05C7; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +N; \uFD79ᡐ\u200C\u06AD.𑋪\u05C7; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +T; \u063A\u0645\u0645ᡐ\u200C\u06AD.𑋪\u05C7; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +N; \u063A\u0645\u0645ᡐ\u200C\u06AD.𑋪\u05C7; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +B; xn--5gbwa03bg24e.xn--vdb1198k; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +B; xn--5gbwa03bg24eptk.xn--vdb1198k; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] # غممᡐڭ.𑋪ׇ +T; 𑑂。\u200D󥞀🞕ò¥”; [C2 P1 V5 V6]; [P1 V5 V6] # 𑑂.🞕 +N; 𑑂。\u200D󥞀🞕ò¥”; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 𑑂.🞕 +T; 𑑂。\u200D󥞀🞕ò¥”; [C2 P1 V5 V6]; [P1 V5 V6] # 𑑂.🞕 +N; 𑑂。\u200D󥞀🞕ò¥”; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 𑑂.🞕 +B; xn--8v1d.xn--ye9h41035a2qqs; [V5 V6]; [V5 V6] +B; xn--8v1d.xn--1ug1386plvx1cd8vya; [C2 V5 V6]; [C2 V5 V6] # 𑑂.🞕 +B; -\u05E9。⒚; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ש.⒚ +B; -\u05E9。19.; [B1 V3]; [B1 V3] # -ש.19. +B; xn----gjc.19.; [B1 V3]; [B1 V3] # -ש.19. +B; xn----gjc.xn--cth; [B1 V3 V6]; [B1 V3 V6] # -ש.⒚ +T; ôо»\u0845\u200C。ᢎ\u200D; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ࡅ.ᢎ +N; ôо»\u0845\u200C。ᢎ\u200D; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ࡅ.ᢎ +T; ôо»\u0845\u200C。ᢎ\u200D; [B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # ࡅ.ᢎ +N; ôо»\u0845\u200C。ᢎ\u200D; [B5 B6 C1 C2 P1 V6]; [B5 B6 C1 C2 P1 V6] # ࡅ.ᢎ +B; xn--3vb50049s.xn--79e; [B5 B6 V6]; [B5 B6 V6] # ࡅ.ᢎ +B; xn--3vb882jz4411a.xn--79e259a; [B5 B6 C1 C2 V6]; [B5 B6 C1 C2 V6] # ࡅ.ᢎ +T; ß\u09C1\u1DED。\u06208₅; ß\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ßুᷭ.Ø 85 +N; ß\u09C1\u1DED。\u06208₅; ß\u09C1\u1DED.\u062085; xn--zca266bwrr.xn--85-psd # ßুᷭ.Ø 85 +T; ß\u09C1\u1DED。\u062085; ß\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ßুᷭ.Ø 85 +N; ß\u09C1\u1DED。\u062085; ß\u09C1\u1DED.\u062085; xn--zca266bwrr.xn--85-psd # ßুᷭ.Ø 85 +B; SS\u09C1\u1DED。\u062085; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; ss\u09C1\u1DED。\u062085; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; Ss\u09C1\u1DED。\u062085; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; xn--ss-e2f077r.xn--85-psd; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; ss\u09C1\u1DED.\u062085; ; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; SS\u09C1\u1DED.\u062085; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; Ss\u09C1\u1DED.\u062085; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; xn--zca266bwrr.xn--85-psd; ß\u09C1\u1DED.\u062085; xn--zca266bwrr.xn--85-psd # ßুᷭ.Ø 85 +T; ß\u09C1\u1DED.\u062085; ; xn--ss-e2f077r.xn--85-psd # ßুᷭ.Ø 85 +N; ß\u09C1\u1DED.\u062085; ; xn--zca266bwrr.xn--85-psd # ßুᷭ.Ø 85 +B; SS\u09C1\u1DED。\u06208₅; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; ss\u09C1\u1DED。\u06208₅; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +B; Ss\u09C1\u1DED。\u06208₅; ss\u09C1\u1DED.\u062085; xn--ss-e2f077r.xn--85-psd # ssুᷭ.Ø 85 +T; \u0ACD\u0484魅𝟣.₃𐹥ß; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ß +N; \u0ACD\u0484魅𝟣.₃𐹥ß; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ß +T; \u0ACD\u0484魅1.3𐹥ß; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ß +N; \u0ACD\u0484魅1.3𐹥ß; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ß +B; \u0ACD\u0484魅1.3𐹥SS; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; \u0ACD\u0484魅1.3𐹥ss; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; \u0ACD\u0484魅1.3𐹥Ss; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; xn--1-0xb049b102o.xn--3ss-nv9t; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; xn--1-0xb049b102o.xn--3-qfa7018r; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ß +B; \u0ACD\u0484魅𝟣.₃𐹥SS; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; \u0ACD\u0484魅𝟣.₃𐹥ss; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; \u0ACD\u0484魅𝟣.₃𐹥Ss; [B1 V5]; [B1 V5] # ્҄魅1.3𐹥ss +B; \u072B。𑓂⒈𑜫󠿻; [B1 P1 V5 V6]; [B1 P1 V5 V6] # Ü«.𑓂⒈𑜫 +B; \u072B。𑓂1.𑜫󠿻; [B1 P1 V5 V6]; [B1 P1 V5 V6] # Ü«.𑓂1.𑜫 +B; xn--1nb.xn--1-jq9i.xn--ji2dg9877c; [B1 V5 V6]; [B1 V5 V6] # Ü«.𑓂1.𑜫 +B; xn--1nb.xn--tsh7798f6rbrt828c; [B1 V5 V6]; [B1 V5 V6] # Ü«.𑓂⒈𑜫 +B; \uFE0Dછ。嵨; છ.嵨; xn--6dc.xn--tot +B; xn--6dc.xn--tot; છ.嵨; xn--6dc.xn--tot +B; છ.嵨; ; xn--6dc.xn--tot +B; Ⴔ≠Ⴀ.𐹥𐹰; [B1 P1 V6]; [B1 P1 V6] +B; Ⴔ=\u0338Ⴀ.𐹥𐹰; [B1 P1 V6]; [B1 P1 V6] +B; ⴔ=\u0338ⴀ.𐹥𐹰; [B1 P1 V6]; [B1 P1 V6] +B; ⴔ≠ⴀ.𐹥𐹰; [B1 P1 V6]; [B1 P1 V6] +B; xn--1ch603bxb.xn--do0dwa; [B1 V6]; [B1 V6] +B; xn--7md3b171g.xn--do0dwa; [B1 V6]; [B1 V6] +T; -\u200C⒙𐫥。𝨵; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # -⒙𐫥.𝨵 +N; -\u200C⒙𐫥。𝨵; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # -⒙𐫥.𝨵 +T; -\u200C18.𐫥。𝨵; [C1 V3 V5]; [V3 V5] # -18.𐫥.𝨵 +N; -\u200C18.𐫥。𝨵; [C1 V3 V5]; [C1 V3 V5] # -18.𐫥.𝨵 +B; -18.xn--rx9c.xn--382h; [V3 V5]; [V3 V5] +B; xn---18-9m0a.xn--rx9c.xn--382h; [C1 V3 V5]; [C1 V3 V5] # -18.𐫥.𝨵 +B; xn----ddps939g.xn--382h; [V3 V5 V6]; [V3 V5 V6] +B; xn----sgn18r3191a.xn--382h; [C1 V3 V5 V6]; [C1 V3 V5 V6] # -⒙𐫥.𝨵 +B; ︒.ʌᠣ-𐹽; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] +B; 。.ʌᠣ-𐹽; [B5 B6 A4_2]; [B5 B6 A4_2] +B; 。.Ʌᠣ-𐹽; [B5 B6 A4_2]; [B5 B6 A4_2] +B; ..xn----73a596nuh9t; [B5 B6 A4_2]; [B5 B6 A4_2] +B; ︒.Ʌᠣ-𐹽; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] +B; xn--y86c.xn----73a596nuh9t; [B1 B5 B6 V6]; [B1 B5 B6 V6] +B; \uFE05︒。𦀾\u1CE0; [P1 V6]; [P1 V6] # ︒.𦀾᳠ +B; \uFE05。。𦀾\u1CE0; [A4_2]; [A4_2] # ..𦀾᳠ +B; ..xn--t6f5138v; [A4_2]; [A4_2] # ..𦀾᳠ +B; xn--y86c.xn--t6f5138v; [V6]; [V6] # ︒.𦀾᳠ +B; xn--t6f5138v; 𦀾\u1CE0; xn--t6f5138v # 𦀾᳠ +B; 𦀾\u1CE0; ; xn--t6f5138v # 𦀾᳠ +T; 𞮑ßôžžã€‚ᡁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +N; 𞮑ßôžžã€‚ᡁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 𞮑SSôžžã€‚ᡁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 𞮑ssôžžã€‚ᡁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 𞮑Ssôžžã€‚ᡁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--ss-o412ac6305g.xn--07e; [B2 B3 V6]; [B2 B3 V6] +B; xn--zca9432wb989f.xn--07e; [B2 B3 V6]; [B2 B3 V6] +T; \uA953\u200D\u062C\u066C。𱆎󻡟\u200C󠅆; [B5 B6 C1 P1 V5 V6]; [B5 B6 P1 V5 V6] # ꥓ج٬. +N; \uA953\u200D\u062C\u066C。𱆎󻡟\u200C󠅆; [B5 B6 C1 P1 V5 V6]; [B5 B6 C1 P1 V5 V6] # ꥓ج٬. +B; xn--rgb2k6711c.xn--ec8nj3948b; [B5 B6 V5 V6]; [B5 B6 V5 V6] # ꥓ج٬. +B; xn--rgb2k500fhq9j.xn--0ug78870a5sp9d; [B5 B6 C1 V5 V6]; [B5 B6 C1 V5 V6] # ꥓ج٬. +T; 󠕏.-ß\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ß≠ +N; 󠕏.-ß\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ß≠ +T; 󠕏.-ß\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ß≠ +N; 󠕏.-ß\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ß≠ +T; 󠕏.-ß\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ß≠ +N; 󠕏.-ß\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ß≠ +T; 󠕏.-ß\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ß≠ +N; 󠕏.-ß\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ß≠ +T; 󠕏.-SS\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-SS\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-SS\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-SS\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-ss\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-ss\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-ss\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-ss\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-Ss\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-Ss\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-Ss\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-Ss\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +B; xn--u836e.xn---ss-gl2a; [V3 V6]; [V3 V6] +B; xn--u836e.xn---ss-cn0at5l; [C1 V3 V6]; [C1 V3 V6] # .-ss≠ +B; xn--u836e.xn----qfa750ve7b; [C1 V3 V6]; [C1 V3 V6] # .-ß≠ +T; 󠕏.-SS\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-SS\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-SS\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-SS\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-ss\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-ss\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-ss\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-ss\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-Ss\u200C=\u0338; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-Ss\u200C=\u0338; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; 󠕏.-Ss\u200C≠; [C1 P1 V3 V6]; [P1 V3 V6] # .-ss≠ +N; 󠕏.-Ss\u200C≠; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .-ss≠ +T; ᡙ\u200C。≯𐋲≠; [C1 P1 V6]; [P1 V6] # ᡙ.≯𐋲≠ +N; ᡙ\u200C。≯𐋲≠; [C1 P1 V6]; [C1 P1 V6] # ᡙ.≯𐋲≠ +T; ᡙ\u200C。>\u0338𐋲=\u0338; [C1 P1 V6]; [P1 V6] # ᡙ.≯𐋲≠ +N; ᡙ\u200C。>\u0338𐋲=\u0338; [C1 P1 V6]; [C1 P1 V6] # ᡙ.≯𐋲≠ +T; ᡙ\u200C。≯𐋲≠; [C1 P1 V6]; [P1 V6] # ᡙ.≯𐋲≠ +N; ᡙ\u200C。≯𐋲≠; [C1 P1 V6]; [C1 P1 V6] # ᡙ.≯𐋲≠ +T; ᡙ\u200C。>\u0338𐋲=\u0338; [C1 P1 V6]; [P1 V6] # ᡙ.≯𐋲≠ +N; ᡙ\u200C。>\u0338𐋲=\u0338; [C1 P1 V6]; [C1 P1 V6] # ᡙ.≯𐋲≠ +B; xn--p8e.xn--1ch3a7084l; [V6]; [V6] +B; xn--p8e650b.xn--1ch3a7084l; [C1 V6]; [C1 V6] # ᡙ.≯𐋲≠ +B; 𐹧𞲄󠁭ñ†¼©ã€‚\u034E🄀; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹧.͎🄀 +B; 𐹧𞲄󠁭ñ†¼©ã€‚\u034E0.; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹧.͎0. +B; xn--fo0dw409aq58qrn69d.xn--0-bgb.; [B1 V5 V6]; [B1 V5 V6] # 𐹧.͎0. +B; xn--fo0dw409aq58qrn69d.xn--sua6883w; [B1 V5 V6]; [B1 V5 V6] # 𐹧.͎🄀 +T; Ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B2 B3 P1 V6] # Ⴄ.ܡς +N; Ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B1 C2 P1 V6] # Ⴄ.ܡς +T; Ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B2 B3 P1 V6] # Ⴄ.ܡς +N; Ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B1 C2 P1 V6] # Ⴄ.ܡς +T; ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B2 B3 P1 V6] # ⴄ.ܡς +N; ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⴄ.ܡς +T; Ⴄ.\u200D\u0721󻣋Σ; [B1 C2 P1 V6]; [B2 B3 P1 V6] # Ⴄ.ܡσ +N; Ⴄ.\u200D\u0721󻣋Σ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # Ⴄ.ܡσ +T; ⴄ.\u200D\u0721󻣋σ; [B1 C2 P1 V6]; [B2 B3 P1 V6] # ⴄ.ܡσ +N; ⴄ.\u200D\u0721󻣋σ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⴄ.ܡσ +B; xn--vkj.xn--4xa73ob5892c; [B2 B3 V6]; [B2 B3 V6] # ⴄ.ܡσ +B; xn--vkj.xn--4xa73o3t5ajq467a; [B1 C2 V6]; [B1 C2 V6] # ⴄ.ܡσ +B; xn--cnd.xn--4xa73ob5892c; [B2 B3 V6]; [B2 B3 V6] # Ⴄ.ܡσ +B; xn--cnd.xn--4xa73o3t5ajq467a; [B1 C2 V6]; [B1 C2 V6] # Ⴄ.ܡσ +B; xn--vkj.xn--3xa93o3t5ajq467a; [B1 C2 V6]; [B1 C2 V6] # ⴄ.ܡς +B; xn--cnd.xn--3xa93o3t5ajq467a; [B1 C2 V6]; [B1 C2 V6] # Ⴄ.ܡς +T; ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B2 B3 P1 V6] # ⴄ.ܡς +N; ⴄ.\u200D\u0721󻣋ς; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⴄ.ܡς +T; Ⴄ.\u200D\u0721󻣋Σ; [B1 C2 P1 V6]; [B2 B3 P1 V6] # Ⴄ.ܡσ +N; Ⴄ.\u200D\u0721󻣋Σ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # Ⴄ.ܡσ +T; ⴄ.\u200D\u0721󻣋σ; [B1 C2 P1 V6]; [B2 B3 P1 V6] # ⴄ.ܡσ +N; ⴄ.\u200D\u0721󻣋σ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⴄ.ܡσ +B; ò®µ›\u0613.Ⴕ; [P1 V6]; [P1 V6] # ؓ.Ⴕ +B; ò®µ›\u0613.ⴕ; [P1 V6]; [P1 V6] # ؓ.ⴕ +B; xn--1fb94204l.xn--dlj; [V6]; [V6] # ؓ.ⴕ +B; xn--1fb94204l.xn--tnd; [V6]; [V6] # ؓ.Ⴕ +T; ≯\u1DF3𞤥。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 P1 V5 V6] # ≯ᷳ𞤥.꣄ +N; ≯\u1DF3𞤥。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ≯ᷳ𞤥.꣄ +T; >\u0338\u1DF3𞤥。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 P1 V5 V6] # ≯ᷳ𞤥.꣄ +N; >\u0338\u1DF3𞤥。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ≯ᷳ𞤥.꣄ +T; >\u0338\u1DF3𞤃。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 P1 V5 V6] # ≯ᷳ𞤥.꣄ +N; >\u0338\u1DF3𞤃。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ≯ᷳ𞤥.꣄ +T; ≯\u1DF3𞤃。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 P1 V5 V6] # ≯ᷳ𞤥.꣄ +N; ≯\u1DF3𞤃。\u200C\uA8C4󠪉\u200D; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # ≯ᷳ𞤥.꣄ +B; xn--ofg13qyr21c.xn--0f9au6706d; [B1 V5 V6]; [B1 V5 V6] # ≯ᷳ𞤥.꣄ +B; xn--ofg13qyr21c.xn--0ugc0116hix29k; [B1 C1 C2 V6]; [B1 C1 C2 V6] # ≯ᷳ𞤥.꣄ +T; \u200C󠄷。ò’‘; [C1 P1 V6]; [P1 V6 A4_2] # . +N; \u200C󠄷。ò’‘; [C1 P1 V6]; [C1 P1 V6] # . +T; \u200C󠄷。ò’‘; [C1 P1 V6]; [P1 V6 A4_2] # . +N; \u200C󠄷。ò’‘; [C1 P1 V6]; [C1 P1 V6] # . +B; .xn--w720c; [V6 A4_2]; [V6 A4_2] +B; xn--0ug.xn--w720c; [C1 V6]; [C1 V6] # . +T; ⒈\u0DD6焅.󗡙\u200Dꡟ; [C2 P1 V6]; [P1 V6] # ⒈ූ焅.ꡟ +N; ⒈\u0DD6焅.󗡙\u200Dꡟ; [C2 P1 V6]; [C2 P1 V6] # ⒈ූ焅.ꡟ +T; 1.\u0DD6焅.󗡙\u200Dꡟ; [C2 P1 V5 V6]; [P1 V5 V6] # 1.ූ焅.ꡟ +N; 1.\u0DD6焅.󗡙\u200Dꡟ; [C2 P1 V5 V6]; [C2 P1 V5 V6] # 1.ූ焅.ꡟ +B; 1.xn--t1c6981c.xn--4c9a21133d; [V5 V6]; [V5 V6] # 1.ූ焅.ꡟ +B; 1.xn--t1c6981c.xn--1ugz184c9lw7i; [C2 V5 V6]; [C2 V5 V6] # 1.ූ焅.ꡟ +B; xn--t1c337io97c.xn--4c9a21133d; [V6]; [V6] # ⒈ූ焅.ꡟ +B; xn--t1c337io97c.xn--1ugz184c9lw7i; [C2 V6]; [C2 V6] # ⒈ූ焅.ꡟ +T; \u1DCDς≮.ς𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +N; \u1DCDς≮.ς𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +T; \u1DCDς<\u0338.ς𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +N; \u1DCDς<\u0338.ς𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +T; \u1DCDς<\u0338.ς𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +N; \u1DCDς<\u0338.ς𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +T; \u1DCDς≮.ς𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +N; \u1DCDς≮.ς𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +B; \u1DCDΣ≮.Σ𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDΣ<\u0338.Σ𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDσ<\u0338.σ𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDσ≮.σ𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDΣ≮.Σ𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDΣ<\u0338.Σ𝪦𞤷0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; xn--4xa544kvid.xn--0-zmb55727aggma; [B1 B5 V5 V6]; [B1 B5 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; xn--3xa744kvid.xn--0-xmb85727aggma; [B1 B5 V5 V6]; [B1 B5 V5 V6] # ᷍ς≮.ς𝪦𞤷0 +B; \u1DCDσ≮.σ𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +B; \u1DCDσ<\u0338.σ𝪦𞤕0; [B1 B5 P1 V5 V6]; [B1 B5 P1 V5 V6] # ᷍σ≮.σ𝪦𞤷0 +T; ò¢¦¾ÃŸ\u05B9𐫙.\u05AD\u08A1; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ßֹ𐫙.֭ࢡ +N; ò¢¦¾ÃŸ\u05B9𐫙.\u05AD\u08A1; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ßֹ𐫙.֭ࢡ +B; ò¢¦¾SS\u05B9𐫙.\u05AD\u08A1; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ssֹ𐫙.֭ࢡ +B; ò¢¦¾ss\u05B9𐫙.\u05AD\u08A1; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ssֹ𐫙.֭ࢡ +B; ò¢¦¾Ss\u05B9𐫙.\u05AD\u08A1; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ssֹ𐫙.֭ࢡ +B; xn--ss-xjd6058xlz50g.xn--4cb62m; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ssֹ𐫙.֭ࢡ +B; xn--zca89v339zj118e.xn--4cb62m; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ßֹ𐫙.֭ࢡ +B; -𞣄。⒈; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -𞣄。1.; [B1 V3]; [B1 V3] +B; xn----xc8r.1.; [B1 V3]; [B1 V3] +B; xn----xc8r.xn--tsh; [B1 V3 V6]; [B1 V3 V6] +B; ñˆ ¢ð«–𝟡。\u063E𑘿; [B5 P1 V6]; [B5 P1 V6] # 𐫖9.ؾ𑘿 +B; ñˆ ¢ð«–9。\u063E𑘿; [B5 P1 V6]; [B5 P1 V6] # 𐫖9.ؾ𑘿 +B; xn--9-el5iv442t.xn--9gb0830l; [B5 V6]; [B5 V6] # 𐫖9.ؾ𑘿 +T; \u0668\uFC8C\u0668\u1A5D.\u200D; [B1 C2]; [B1] # ٨نم٨ᩝ. +N; \u0668\uFC8C\u0668\u1A5D.\u200D; [B1 C2]; [B1 C2] # ٨نم٨ᩝ. +T; \u0668\u0646\u0645\u0668\u1A5D.\u200D; [B1 C2]; [B1] # ٨نم٨ᩝ. +N; \u0668\u0646\u0645\u0668\u1A5D.\u200D; [B1 C2]; [B1 C2] # ٨نم٨ᩝ. +B; xn--hhbb5hc956w.; [B1]; [B1] # ٨نم٨ᩝ. +B; xn--hhbb5hc956w.xn--1ug; [B1 C2]; [B1 C2] # ٨نم٨ᩝ. +B; 𝟘.Ⴇ󀳑\uFD50ñ«ƒ±; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 0.Ⴇتجم +B; 0.Ⴇ󀳑\u062A\u062C\u0645ñ«ƒ±; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 0.Ⴇتجم +B; 0.ⴇ󀳑\u062A\u062C\u0645ñ«ƒ±; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 0.ⴇتجم +B; 0.xn--pgbe9ez79qd207lvff8b; [B1 B5 V6]; [B1 B5 V6] # 0.ⴇتجم +B; 0.xn--pgbe9e344c2725svff8b; [B1 B5 V6]; [B1 B5 V6] # 0.Ⴇتجم +B; 𝟘.ⴇ󀳑\uFD50ñ«ƒ±; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 0.ⴇتجم +B; 𑇀▍.⁞ᠰ; [V5]; [V5] +B; xn--9zh3057f.xn--j7e103b; [V5]; [V5] +T; \u200D-\u067A.ò¯©; [B1 C2 P1 V6]; [B1 P1 V3 V6] # -Ùº. +N; \u200D-\u067A.ò¯©; [B1 C2 P1 V6]; [B1 C2 P1 V6] # -Ùº. +B; xn----qrc.xn--ts49b; [B1 V3 V6]; [B1 V3 V6] # -Ùº. +B; xn----qrc357q.xn--ts49b; [B1 C2 V6]; [B1 C2 V6] # -Ùº. +T; ᠢ𐮂𐫘寐。\u200C≯✳; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +N; ᠢ𐮂𐫘寐。\u200C≯✳; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +T; ᠢ𐮂𐫘寐。\u200C>\u0338✳; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +N; ᠢ𐮂𐫘寐。\u200C>\u0338✳; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +T; ᠢ𐮂𐫘寐。\u200C≯✳; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +N; ᠢ𐮂𐫘寐。\u200C≯✳; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +T; ᠢ𐮂𐫘寐。\u200C>\u0338✳; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +N; ᠢ𐮂𐫘寐。\u200C>\u0338✳; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ᠢ𐮂𐫘寐.≯✳ +B; xn--46e6675axzzhota.xn--hdh99p; [B1 B5 V6]; [B1 B5 V6] +B; xn--46e6675axzzhota.xn--0ug06gu8f; [B1 B5 C1 V6]; [B1 B5 C1 V6] # ᠢ𐮂𐫘寐.≯✳ +T; \u200D。󸲜ႺႴ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .ႺႴ +N; \u200D。󸲜ႺႴ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .ႺႴ +T; \u200D。󸲜ႺႴ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .ႺႴ +N; \u200D。󸲜ႺႴ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .ႺႴ +T; \u200D。󸲜ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴚⴔ +N; \u200D。󸲜ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .ⴚⴔ +T; \u200D。󸲜Ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴚⴔ +N; \u200D。󸲜Ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .Ⴚⴔ +B; .xn--ynd036lq981an3r4h; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] +B; xn--1ug.xn--ynd036lq981an3r4h; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # .Ⴚⴔ +B; .xn--cljl81825an3r4h; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] +B; xn--1ug.xn--cljl81825an3r4h; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # .ⴚⴔ +B; .xn--sndl01647an3h1h; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] +B; xn--1ug.xn--sndl01647an3h1h; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # .ႺႴ +T; \u200D。󸲜ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴚⴔ +N; \u200D。󸲜ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .ⴚⴔ +T; \u200D。󸲜Ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴚⴔ +N; \u200D。󸲜Ⴚⴔ𞨇; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # .Ⴚⴔ +T; -3.\u200Dヌᢕ; [C2 V3]; [V3] # -3.ヌᢕ +N; -3.\u200Dヌᢕ; [C2 V3]; [C2 V3] # -3.ヌᢕ +B; -3.xn--fbf115j; [V3]; [V3] +B; -3.xn--fbf739aq5o; [C2 V3]; [C2 V3] # -3.ヌᢕ +T; 🂃\u0666ß\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 P1 V3 V6] # 🂃٦ß.- +N; 🂃\u0666ß\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # 🂃٦ß.- +T; 🂃\u0666SS\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 P1 V3 V6] # 🂃٦ss.- +N; 🂃\u0666SS\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # 🂃٦ss.- +T; 🂃\u0666ss\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 P1 V3 V6] # 🂃٦ss.- +N; 🂃\u0666ss\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # 🂃٦ss.- +T; 🂃\u0666Ss\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 P1 V3 V6] # 🂃٦ss.- +N; 🂃\u0666Ss\u200D。󠠂ò­°ðž©’-; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # 🂃٦ss.- +B; xn--ss-pyd98921c.xn----nz8rh7531csznt; [B1 V3 V6]; [B1 V3 V6] # 🂃٦ss.- +B; xn--ss-pyd483x5k99b.xn----nz8rh7531csznt; [B1 C2 V3 V6]; [B1 C2 V3 V6] # 🂃٦ss.- +B; xn--zca34z68yzu83b.xn----nz8rh7531csznt; [B1 C2 V3 V6]; [B1 C2 V3 V6] # 🂃٦ß.- +T; ꇟ-𐾺\u069F。ò°€º\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ꇟ-ڟ. +N; ꇟ-𐾺\u069F。ò°€º\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ꇟ-ڟ. +B; xn----utc4430jd3zd.xn--bp20d; [B5 B6 V6]; [B5 B6 V6] # ꇟ-ڟ. +B; xn----utc4430jd3zd.xn--0ugx6670i; [B5 B6 C1 V6]; [B5 B6 C1 V6] # ꇟ-ڟ. +B; \u0665.\u0484𐨗𝩋𴤃; [B1 P1 V5 V6]; [B1 P1 V5 V6] # Ù¥.҄𐨗𝩋 +B; xn--eib.xn--n3a0405kus8eft5l; [B1 V5 V6]; [B1 V5 V6] # Ù¥.҄𐨗𝩋 +B; -.ñ±¼“\u0649𐨿; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # -.ى𐨿 +B; -.xn--lhb4124khbq4b; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] # -.ى𐨿 +T; 󾬨ς.𞶙녫ß; [B2 B3 P1 V6]; [B2 B3 P1 V6] +N; 󾬨ς.𞶙녫ß; [B2 B3 P1 V6]; [B2 B3 P1 V6] +T; 󾬨ς.𞶙녫ß; [B2 B3 P1 V6]; [B2 B3 P1 V6] +N; 󾬨ς.𞶙녫ß; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨Σ.𞶙녫SS; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨Σ.𞶙녫SS; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨σ.𞶙녫ss; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨σ.𞶙녫ss; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨Σ.𞶙녫Ss; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; 󾬨Σ.𞶙녫Ss; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--4xa76659r.xn--ss-d64i8755h; [B2 B3 V6]; [B2 B3 V6] +B; xn--3xa96659r.xn--zca5051g4h4i; [B2 B3 V6]; [B2 B3 V6] +T; Ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # Ⅎ្.≠ +N; Ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⅎ្.≠ +T; Ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # Ⅎ្.≠ +N; Ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⅎ្.≠ +T; Ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # Ⅎ្.≠ +N; Ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⅎ្.≠ +T; Ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # Ⅎ្.≠ +N; Ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⅎ្.≠ +T; ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # ⅎ្.≠ +N; ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⅎ្.≠ +T; ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # ⅎ្.≠ +N; ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⅎ្.≠ +B; xn--u4e969b.xn--1ch; [V6]; [V6] # ⅎ្.≠ +B; xn--u4e823bq1a.xn--0ugb89o; [C1 C2 V6]; [C1 C2 V6] # ⅎ្.≠ +B; xn--u4e319b.xn--1ch; [V6]; [V6] # Ⅎ្.≠ +B; xn--u4e823bcza.xn--0ugb89o; [C1 C2 V6]; [C1 C2 V6] # Ⅎ្.≠ +T; ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # ⅎ្.≠ +N; ⅎ\u17D2\u200D。=\u0338\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⅎ្.≠ +T; ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [P1 V6] # ⅎ្.≠ +N; ⅎ\u17D2\u200D。≠\u200D\u200C; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⅎ្.≠ +T; 𐋺\uAAF6\uA953󧦉.\u200C\u1714\u068F; [B1 C1 P1 V6]; [B1 P1 V5 V6] # 𐋺꫶꥓.᜔ڏ +N; 𐋺\uAAF6\uA953󧦉.\u200C\u1714\u068F; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐋺꫶꥓.᜔ڏ +T; 𐋺\uAAF6\uA953󧦉.\u200C\u1714\u068F; [B1 C1 P1 V6]; [B1 P1 V5 V6] # 𐋺꫶꥓.᜔ڏ +N; 𐋺\uAAF6\uA953󧦉.\u200C\u1714\u068F; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐋺꫶꥓.᜔ڏ +B; xn--3j9a14ak27osbz2o.xn--ljb175f; [B1 V5 V6]; [B1 V5 V6] # 𐋺꫶꥓.᜔ڏ +B; xn--3j9a14ak27osbz2o.xn--ljb175f1wg; [B1 C1 V6]; [B1 C1 V6] # 𐋺꫶꥓.᜔ڏ +B; ñº”¯\u0FA8.≯; [P1 V6]; [P1 V6] # ྨ.≯ +B; ñº”¯\u0FA8.>\u0338; [P1 V6]; [P1 V6] # ྨ.≯ +B; ñº”¯\u0FA8.≯; [P1 V6]; [P1 V6] # ྨ.≯ +B; ñº”¯\u0FA8.>\u0338; [P1 V6]; [P1 V6] # ྨ.≯ +B; xn--4fd57150h.xn--hdh; [V6]; [V6] # ྨ.≯ +T; \u200D𞡄Ⴓ.𐇽; [B1 B3 B6 C2 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # 𞡄Ⴓ.𐇽 +N; \u200D𞡄Ⴓ.𐇽; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 C2 P1 V5 V6] # 𞡄Ⴓ.𐇽 +T; \u200D𞡄Ⴓ.𐇽; [B1 B3 B6 C2 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # 𞡄Ⴓ.𐇽 +N; \u200D𞡄Ⴓ.𐇽; [B1 B3 B6 C2 P1 V5 V6]; [B1 B3 B6 C2 P1 V5 V6] # 𞡄Ⴓ.𐇽 +T; \u200D𞡄ⴓ.𐇽; [B1 B3 B6 C2 V5]; [B1 B2 B3 B6 V5] # 𞡄ⴓ.𐇽 +N; \u200D𞡄ⴓ.𐇽; [B1 B3 B6 C2 V5]; [B1 B3 B6 C2 V5] # 𞡄ⴓ.𐇽 +B; xn--blj7492l.xn--m27c; [B1 B2 B3 B6 V5]; [B1 B2 B3 B6 V5] +B; xn--1ugz52c4i16a.xn--m27c; [B1 B3 B6 C2 V5]; [B1 B3 B6 C2 V5] # 𞡄ⴓ.𐇽 +B; xn--rnd5552v.xn--m27c; [B1 B2 B3 B6 V5 V6]; [B1 B2 B3 B6 V5 V6] +B; xn--rnd379ex885a.xn--m27c; [B1 B3 B6 C2 V5 V6]; [B1 B3 B6 C2 V5 V6] # 𞡄Ⴓ.𐇽 +T; \u200D𞡄ⴓ.𐇽; [B1 B3 B6 C2 V5]; [B1 B2 B3 B6 V5] # 𞡄ⴓ.𐇽 +N; \u200D𞡄ⴓ.𐇽; [B1 B3 B6 C2 V5]; [B1 B3 B6 C2 V5] # 𞡄ⴓ.𐇽 +T; 𐪒ß\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ß꣪.ᡤ +N; 𐪒ß\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ß꣪.ᡤ +T; 𐪒ß\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ß꣪.ᡤ +N; 𐪒ß\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ß꣪.ᡤ +B; 𐪒SS\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; 𐪒ss\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; 𐪒Ss\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; xn--ss-tu9hw933a.xn--08e; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; xn--zca2517f2hvc.xn--08e; [B2 B3]; [B2 B3] # 𐪒ß꣪.ᡤ +B; 𐪒SS\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; 𐪒ss\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +B; 𐪒Ss\uA8EA.ᡤ; [B2 B3]; [B2 B3] # 𐪒ss꣪.ᡤ +T; 𐨿󠆌鸮𑚶.ς; [V5]; [V5] +N; 𐨿󠆌鸮𑚶.ς; [V5]; [V5] +B; 𐨿󠆌鸮𑚶.Σ; [V5]; [V5] +B; 𐨿󠆌鸮𑚶.σ; [V5]; [V5] +B; xn--l76a726rt2h.xn--4xa; [V5]; [V5] +B; xn--l76a726rt2h.xn--3xa; [V5]; [V5] +B; ⒗𞤬。-𑚶; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; 16.𞤬。-𑚶; [B1 V3]; [B1 V3] +B; 16.𞤊。-𑚶; [B1 V3]; [B1 V3] +B; 16.xn--ke6h.xn----4j0j; [B1 V3]; [B1 V3] +B; ⒗𞤊。-𑚶; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; xn--8shw466n.xn----4j0j; [B1 V3 V6]; [B1 V3 V6] +B; \u08B3𞤿⾫。𐹣\u068F⒈; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # ࢳ𞤿隹.𐹣ڏ⒈ +B; \u08B3𞤿隹。𐹣\u068F1.; [B1 B2 B3]; [B1 B2 B3] # ࢳ𞤿隹.𐹣ڏ1. +B; \u08B3𞤝隹。𐹣\u068F1.; [B1 B2 B3]; [B1 B2 B3] # ࢳ𞤿隹.𐹣ڏ1. +B; xn--8yb0383efiwk.xn--1-wsc3373r.; [B1 B2 B3]; [B1 B2 B3] # ࢳ𞤿隹.𐹣ڏ1. +B; \u08B3𞤝⾫。𐹣\u068F⒈; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # ࢳ𞤿隹.𐹣ڏ⒈ +B; xn--8yb0383efiwk.xn--ljb064mol4n; [B1 B2 B3 V6]; [B1 B2 B3 V6] # ࢳ𞤿隹.𐹣ڏ⒈ +B; \u2433𚎛𝟧\u0661.á¡¢8\u0F72\u0600; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 5Ù¡.á¡¢8ི +B; \u2433𚎛5\u0661.á¡¢8\u0F72\u0600; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 5Ù¡.á¡¢8ི +B; xn--5-bqc410un435a.xn--8-rkc763epjj; [B5 B6 V6]; [B5 B6 V6] # 5Ù¡.á¡¢8ི +B; 𐹠.🄀⒒-󨰈; [B1 P1 V6]; [B1 P1 V6] +B; 𐹠.0.11.-󨰈; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; xn--7n0d.0.11.xn----8j07m; [B1 V3 V6]; [B1 V3 V6] +B; xn--7n0d.xn----xcp9757q1s13g; [B1 V6]; [B1 V6] +T; ς-。\u200C𝟭-; [C1 V3]; [V3] # ς-.1- +N; ς-。\u200C𝟭-; [C1 V3]; [C1 V3] # ς-.1- +T; ς-。\u200C1-; [C1 V3]; [V3] # ς-.1- +N; ς-。\u200C1-; [C1 V3]; [C1 V3] # ς-.1- +T; Σ-。\u200C1-; [C1 V3]; [V3] # σ-.1- +N; Σ-。\u200C1-; [C1 V3]; [C1 V3] # σ-.1- +T; σ-。\u200C1-; [C1 V3]; [V3] # σ-.1- +N; σ-。\u200C1-; [C1 V3]; [C1 V3] # σ-.1- +B; xn----zmb.1-; [V3]; [V3] +B; xn----zmb.xn--1--i1t; [C1 V3]; [C1 V3] # σ-.1- +B; xn----xmb.xn--1--i1t; [C1 V3]; [C1 V3] # ς-.1- +T; Σ-。\u200C𝟭-; [C1 V3]; [V3] # σ-.1- +N; Σ-。\u200C𝟭-; [C1 V3]; [C1 V3] # σ-.1- +T; σ-。\u200C𝟭-; [C1 V3]; [V3] # σ-.1- +N; σ-。\u200C𝟭-; [C1 V3]; [C1 V3] # σ-.1- +B; \u1734-\u0CE2.󠄩Ⴄ; [P1 V5 V6]; [P1 V5 V6] # ᜴-à³¢.Ⴄ +B; \u1734-\u0CE2.󠄩Ⴄ; [P1 V5 V6]; [P1 V5 V6] # ᜴-à³¢.Ⴄ +B; \u1734-\u0CE2.󠄩ⴄ; [V5]; [V5] # ᜴-à³¢.ⴄ +B; xn----ggf830f.xn--vkj; [V5]; [V5] # ᜴-à³¢.ⴄ +B; xn----ggf830f.xn--cnd; [V5 V6]; [V5 V6] # ᜴-à³¢.Ⴄ +B; \u1734-\u0CE2.󠄩ⴄ; [V5]; [V5] # ᜴-à³¢.ⴄ +B; ò­ˆ—♋\u06BB𐦥。\u0954⒈; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ♋ڻ𐦥.॔⒈ +B; ò­ˆ—♋\u06BB𐦥。\u09541.; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ♋ڻ𐦥.॔1. +B; xn--ukb372n129m3rs7f.xn--1-fyd.; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ♋ڻ𐦥.॔1. +B; xn--ukb372n129m3rs7f.xn--u3b240l; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ♋ڻ𐦥.॔⒈ +T; \u05A4.\u06C1\u1AB3\u200C; [B1 B3 B6 C1 V5]; [B1 B3 B6 V5] # Ö¤.ہ᪳ +N; \u05A4.\u06C1\u1AB3\u200C; [B1 B3 B6 C1 V5]; [B1 B3 B6 C1 V5] # Ö¤.ہ᪳ +T; \u05A4.\u06C1\u1AB3\u200C; [B1 B3 B6 C1 V5]; [B1 B3 B6 V5] # Ö¤.ہ᪳ +N; \u05A4.\u06C1\u1AB3\u200C; [B1 B3 B6 C1 V5]; [B1 B3 B6 C1 V5] # Ö¤.ہ᪳ +B; xn--vcb.xn--0kb623h; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ö¤.ہ᪳ +B; xn--vcb.xn--0kb623hm1d; [B1 B3 B6 C1 V5]; [B1 B3 B6 C1 V5] # Ö¤.ہ᪳ +B; ñ¢­\u0846≮\u0ACD.𞦊; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡆ≮્. +B; ñ¢­\u0846<\u0338\u0ACD.𞦊; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡆ≮્. +B; ñ¢­\u0846≮\u0ACD.𞦊; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡆ≮્. +B; ñ¢­\u0846<\u0338\u0ACD.𞦊; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡆ≮્. +B; xn--4vb80kq29ayo62l.xn--8g6h; [B5 B6 V6]; [B5 B6 V6] # ࡆ≮્. +T; \u200D。𞀘⒈ꡍ擉; [C2 P1 V5 V6]; [P1 V5 V6 A4_2] # .𞀘⒈ꡍ擉 +N; \u200D。𞀘⒈ꡍ擉; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .𞀘⒈ꡍ擉 +T; \u200D。𞀘1.ꡍ擉; [C2 V5]; [V5 A4_2] # .𞀘1.ꡍ擉 +N; \u200D。𞀘1.ꡍ擉; [C2 V5]; [C2 V5] # .𞀘1.ꡍ擉 +B; .xn--1-1p4r.xn--s7uv61m; [V5 A4_2]; [V5 A4_2] +B; xn--1ug.xn--1-1p4r.xn--s7uv61m; [C2 V5]; [C2 V5] # .𞀘1.ꡍ擉 +B; .xn--tsh026uql4bew9p; [V5 V6 A4_2]; [V5 V6 A4_2] +B; xn--1ug.xn--tsh026uql4bew9p; [C2 V5 V6]; [C2 V5 V6] # .𞀘⒈ꡍ擉 +B; ₈\u07CB.\uFB64≠; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 8ߋ.ٿ≠ +B; ₈\u07CB.\uFB64=\u0338; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 8ߋ.ٿ≠ +B; 8\u07CB.\u067F≠; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 8ߋ.ٿ≠ +B; 8\u07CB.\u067F=\u0338; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 8ߋ.ٿ≠ +B; xn--8-zbd.xn--4ib883l; [B1 B3 V6]; [B1 B3 V6] # 8ߋ.ٿ≠ +B; ᢡ\u07DEò¹£.⒒\u0642𑍦; [B1 B5 P1 V6]; [B1 B5 P1 V6] # ᢡߞ.⒒ق𑍦 +B; ᢡ\u07DEò¹£.11.\u0642𑍦; [B1 B5 P1 V6]; [B1 B5 P1 V6] # ᢡߞ.11.ق𑍦 +B; xn--5sb596fi873t.11.xn--ehb4198k; [B1 B5 V6]; [B1 B5 V6] # ᢡߞ.11.ق𑍦 +B; xn--5sb596fi873t.xn--ehb336mvy7n; [B1 B5 V6]; [B1 B5 V6] # ᢡߞ.⒒ق𑍦 +B; \u0E48-𐹺𝟜.\u0363\u06E1⒏; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ่-𐹺4.ͣۡ⒏ +B; \u0E48-𐹺4.\u0363\u06E18.; [B1 V5]; [B1 V5] # ่-𐹺4.Í£Û¡8. +B; xn---4-owiz479s.xn--8-ihb69x.; [B1 V5]; [B1 V5] # ่-𐹺4.Í£Û¡8. +B; xn---4-owiz479s.xn--eva20pjv9a; [B1 V5 V6]; [B1 V5 V6] # ่-𐹺4.ͣۡ⒏ +B; ⫐。Ⴠ-󃐢; [P1 V6]; [P1 V6] +B; ⫐。Ⴠ-󃐢; [P1 V6]; [P1 V6] +B; ⫐。ⴠ-󃐢; [P1 V6]; [P1 V6] +B; xn--r3i.xn----2wst7439i; [V6]; [V6] +B; xn--r3i.xn----z1g58579u; [V6]; [V6] +B; ⫐。ⴠ-󃐢; [P1 V6]; [P1 V6] +B; 𑑂◊.⦟∠; [V5]; [V5] +B; 𑑂◊.⦟∠; [V5]; [V5] +B; xn--01h3338f.xn--79g270a; [V5]; [V5] +B; 𿌰-\u0662。󋸛ꡂ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -Ù¢.ꡂ +B; xn----dqc20828e.xn--bc9an2879c; [B5 B6 V6]; [B5 B6 V6] # -Ù¢.ꡂ +B; \u0678。󠏬\u0741𞪭𐹪; [B1 P1 V6]; [B1 P1 V6] # يٴ.݁𐹪 +B; \u064A\u0674。󠏬\u0741𞪭𐹪; [B1 P1 V6]; [B1 P1 V6] # يٴ.݁𐹪 +B; xn--mhb8f.xn--oob2585kfdsfsbo7h; [B1 V6]; [B1 V6] # يٴ.݁𐹪 +T; 𐫆ꌄ。\u200Dᣬ; [B1 B2 B3 C2]; [B2 B3] # 𐫆ꌄ.ᣬ +N; 𐫆ꌄ。\u200Dᣬ; [B1 B2 B3 C2]; [B1 B2 B3 C2] # 𐫆ꌄ.ᣬ +T; 𐫆ꌄ。\u200Dᣬ; [B1 B2 B3 C2]; [B2 B3] # 𐫆ꌄ.ᣬ +N; 𐫆ꌄ。\u200Dᣬ; [B1 B2 B3 C2]; [B1 B2 B3 C2] # 𐫆ꌄ.ᣬ +B; xn--y77ao18q.xn--wdf; [B2 B3]; [B2 B3] +B; xn--y77ao18q.xn--wdf367a; [B1 B2 B3 C2]; [B1 B2 B3 C2] # 𐫆ꌄ.ᣬ +B; ₀\u0662。󅪞≯-; [B1 B6 P1 V3 V6]; [B1 B6 P1 V3 V6] # 0Ù¢.≯- +B; ₀\u0662。󅪞>\u0338-; [B1 B6 P1 V3 V6]; [B1 B6 P1 V3 V6] # 0Ù¢.≯- +B; 0\u0662。󅪞≯-; [B1 B6 P1 V3 V6]; [B1 B6 P1 V3 V6] # 0Ù¢.≯- +B; 0\u0662。󅪞>\u0338-; [B1 B6 P1 V3 V6]; [B1 B6 P1 V3 V6] # 0Ù¢.≯- +B; xn--0-dqc.xn----ogov3342l; [B1 B6 V3 V6]; [B1 B6 V3 V6] # 0Ù¢.≯- +B; \u031C𐹫-𞯃.𐋤\u0845; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ̜𐹫-.𐋤ࡅ +B; xn----gdb7046r692g.xn--3vb1349j; [B1 V5 V6]; [B1 V5 V6] # ̜𐹫-.𐋤ࡅ +B; ≠。𝩑𐹩Ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩Ⴡ֔ +B; =\u0338。𝩑𐹩Ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩Ⴡ֔ +B; ≠。𝩑𐹩Ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩Ⴡ֔ +B; =\u0338。𝩑𐹩Ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩Ⴡ֔ +B; =\u0338。𝩑𐹩ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩ⴡ֔ +B; ≠。𝩑𐹩ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩ⴡ֔ +B; xn--1ch.xn--fcb363rk03mypug; [B1 V5 V6]; [B1 V5 V6] # ≠.𝩑𐹩ⴡ֔ +B; xn--1ch.xn--fcb538c649rypog; [B1 V5 V6]; [B1 V5 V6] # ≠.𝩑𐹩Ⴡ֔ +B; =\u0338。𝩑𐹩ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩ⴡ֔ +B; ≠。𝩑𐹩ⴡ\u0594; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≠.𝩑𐹩ⴡ֔ +B; 𖫳≠.Ⴀ𐮀; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] +B; 𖫳=\u0338.Ⴀ𐮀; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] +B; 𖫳=\u0338.ⴀ𐮀; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] +B; 𖫳≠.ⴀ𐮀; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] +B; xn--1ch9250k.xn--rkj6232e; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--1ch9250k.xn--7md2659j; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; 󠅾\u0736\u0726.ᢚ閪\u08E2𝩟; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ܶܦ.ᢚ閪𝩟 +B; 󠅾\u0736\u0726.ᢚ閪\u08E2𝩟; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ܶܦ.ᢚ閪𝩟 +B; xn--wnb5a.xn--l0b161fis8gbp5m; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ܶܦ.ᢚ閪𝩟 +T; \u200D󠇜\u06CB\uA8E9。\u20DD\u0FB0-ᛟ; [B1 C2 V5]; [B1 V5] # ۋ꣩.⃝ྰ-ᛟ +N; \u200D󠇜\u06CB\uA8E9。\u20DD\u0FB0-ᛟ; [B1 C2 V5]; [B1 C2 V5] # ۋ꣩.⃝ྰ-ᛟ +T; \u200D󠇜\u06CB\uA8E9。\u20DD\u0FB0-ᛟ; [B1 C2 V5]; [B1 V5] # ۋ꣩.⃝ྰ-ᛟ +N; \u200D󠇜\u06CB\uA8E9。\u20DD\u0FB0-ᛟ; [B1 C2 V5]; [B1 C2 V5] # ۋ꣩.⃝ྰ-ᛟ +B; xn--blb8114f.xn----gmg236cj6k; [B1 V5]; [B1 V5] # ۋ꣩.⃝ྰ-ᛟ +B; xn--blb540ke10h.xn----gmg236cj6k; [B1 C2 V5]; [B1 C2 V5] # ۋ꣩.⃝ྰ-ᛟ +B; 헁󘖙\u0E3A󚍚。\u06BA𝟜; [P1 V6]; [P1 V6] # 헁ฺ.Úº4 +B; 헁󘖙\u0E3A󚍚。\u06BA𝟜; [P1 V6]; [P1 V6] # 헁ฺ.Úº4 +B; 헁󘖙\u0E3A󚍚。\u06BA4; [P1 V6]; [P1 V6] # 헁ฺ.Úº4 +B; 헁󘖙\u0E3A󚍚。\u06BA4; [P1 V6]; [P1 V6] # 헁ฺ.Úº4 +B; xn--o4c1723h8g85gt4ya.xn--4-dvc; [V6]; [V6] # 헁ฺ.Úº4 +T; 𐹭。󃱂\u200CႾ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹭.Ⴞ +N; 𐹭。󃱂\u200CႾ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹭.Ⴞ +T; 𐹭。󃱂\u200CႾ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹭.Ⴞ +N; 𐹭。󃱂\u200CႾ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹭.Ⴞ +T; 𐹭。󃱂\u200Cⴞ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹭.ⴞ +N; 𐹭。󃱂\u200Cⴞ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹭.ⴞ +B; xn--lo0d.xn--mljx1099g; [B1 V6]; [B1 V6] +B; xn--lo0d.xn--0ugx72cwi33v; [B1 C1 V6]; [B1 C1 V6] # 𐹭.ⴞ +B; xn--lo0d.xn--2nd75260n; [B1 V6]; [B1 V6] +B; xn--lo0d.xn--2nd949eqw95u; [B1 C1 V6]; [B1 C1 V6] # 𐹭.Ⴞ +T; 𐹭。󃱂\u200Cⴞ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹭.ⴞ +N; 𐹭。󃱂\u200Cⴞ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹭.ⴞ +B; \uA953.\u033D𑂽馋; [P1 V5 V6]; [P1 V5 V6] # ꥓.̽馋 +B; xn--3j9a.xn--bua0708eqzrd; [V5 V6]; [V5 V6] # ꥓.̽馋 +T; 󈫝òª›¸\u200D。䜖; [C2 P1 V6]; [P1 V6] # .䜖 +N; 󈫝òª›¸\u200D。䜖; [C2 P1 V6]; [C2 P1 V6] # .䜖 +T; 󈫝òª›¸\u200D。䜖; [C2 P1 V6]; [P1 V6] # .䜖 +N; 󈫝òª›¸\u200D。䜖; [C2 P1 V6]; [C2 P1 V6] # .䜖 +B; xn--g138cxw05a.xn--k0o; [V6]; [V6] +B; xn--1ug30527h9mxi.xn--k0o; [C2 V6]; [C2 V6] # .䜖 +T; ᡯ⚉姶🄉.۷\u200D🎪\u200D; [C2 P1 V6]; [P1 V6] # ᡯ⚉姶🄉.۷🎪 +N; ᡯ⚉姶🄉.۷\u200D🎪\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡯ⚉姶🄉.۷🎪 +T; ᡯ⚉姶8,.Û·\u200D🎪\u200D; [C2 P1 V6]; [P1 V6] # ᡯ⚉姶8,.۷🎪 +N; ᡯ⚉姶8,.Û·\u200D🎪\u200D; [C2 P1 V6]; [C2 P1 V6] # ᡯ⚉姶8,.۷🎪 +B; xn--8,-g9oy26fzu4d.xn--kmb6733w; [P1 V6]; [P1 V6] +B; xn--8,-g9oy26fzu4d.xn--kmb859ja94998b; [C2 P1 V6]; [C2 P1 V6] # ᡯ⚉姶8,.۷🎪 +B; xn--c9e433epi4b3j20a.xn--kmb6733w; [V6]; [V6] +B; xn--c9e433epi4b3j20a.xn--kmb859ja94998b; [C2 V6]; [C2 V6] # ᡯ⚉姶🄉.۷🎪 +B; 𞽀.𐹸🚖\u0E3A; [B1 P1 V6]; [B1 P1 V6] # .𐹸🚖ฺ +B; xn--0n7h.xn--o4c9032klszf; [B1 V6]; [B1 V6] # .𐹸🚖ฺ +B; Ⴔᠵ。𐹧\u0747Û¹; [B1 P1 V6]; [B1 P1 V6] # Ⴔᠵ.𐹧݇۹ +B; Ⴔᠵ。𐹧\u0747Û¹; [B1 P1 V6]; [B1 P1 V6] # Ⴔᠵ.𐹧݇۹ +B; ⴔᠵ。𐹧\u0747Û¹; [B1]; [B1] # ⴔᠵ.𐹧݇۹ +B; xn--o7e997h.xn--mmb9ml895e; [B1]; [B1] # ⴔᠵ.𐹧݇۹ +B; xn--snd659a.xn--mmb9ml895e; [B1 V6]; [B1 V6] # Ⴔᠵ.𐹧݇۹ +B; ⴔᠵ。𐹧\u0747Û¹; [B1]; [B1] # ⴔᠵ.𐹧݇۹ +T; \u135Fᡈ\u200C.︒-𖾐-; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # ፟ᡈ.︒-𖾐- +N; \u135Fᡈ\u200C.︒-𖾐-; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # ፟ᡈ.︒-𖾐- +T; \u135Fᡈ\u200C.。-𖾐-; [C1 V3 V5 A4_2]; [V3 V5 A4_2] # ፟ᡈ..-𖾐- +N; \u135Fᡈ\u200C.。-𖾐-; [C1 V3 V5 A4_2]; [C1 V3 V5 A4_2] # ፟ᡈ..-𖾐- +B; xn--b7d82w..xn-----pe4u; [V3 V5 A4_2]; [V3 V5 A4_2] # ፟ᡈ..-𖾐- +B; xn--b7d82wo4h..xn-----pe4u; [C1 V3 V5 A4_2]; [C1 V3 V5 A4_2] # ፟ᡈ..-𖾐- +B; xn--b7d82w.xn-----c82nz547a; [V3 V5 V6]; [V3 V5 V6] # ፟ᡈ.︒-𖾐- +B; xn--b7d82wo4h.xn-----c82nz547a; [C1 V3 V5 V6]; [C1 V3 V5 V6] # ፟ᡈ.︒-𖾐- +T; ⒈\u0601⒖\u200C.\u1DF0\u07DB; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # ⒈⒖.ᷰߛ +N; ⒈\u0601⒖\u200C.\u1DF0\u07DB; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # ⒈⒖.ᷰߛ +T; 1.\u060115.\u200C.\u1DF0\u07DB; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6 A4_2] # 1.15..ᷰߛ +N; 1.\u060115.\u200C.\u1DF0\u07DB; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 1.15..ᷰߛ +B; 1.xn--15-1pd..xn--2sb914i; [B1 V5 V6 A4_2]; [B1 V5 V6 A4_2] # 1.15..ᷰߛ +B; 1.xn--15-1pd.xn--0ug.xn--2sb914i; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 1.15..ᷰߛ +B; xn--jfb347mib.xn--2sb914i; [B1 V5 V6]; [B1 V5 V6] # ⒈⒖.ᷰߛ +B; xn--jfb844kmfdwb.xn--2sb914i; [B1 C1 V5 V6]; [B1 C1 V5 V6] # ⒈⒖.ᷰߛ +B; 𝩜。-\u0B4DႫ; [P1 V3 V5 V6]; [P1 V3 V5 V6] # 𝩜.-୍Ⴋ +B; 𝩜。-\u0B4Dⴋ; [V3 V5]; [V3 V5] # 𝩜.-୍ⴋ +B; xn--792h.xn----bse820x; [V3 V5]; [V3 V5] # 𝩜.-୍ⴋ +B; xn--792h.xn----bse632b; [V3 V5 V6]; [V3 V5 V6] # 𝩜.-୍Ⴋ +T; ßჀ.\u0620刯Ⴝ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ßჀ.ؠ刯Ⴝ +N; ßჀ.\u0620刯Ⴝ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ßჀ.ؠ刯Ⴝ +T; ßⴠ.\u0620刯ⴝ; [B2 B3]; [B2 B3] # ßⴠ.ؠ刯ⴝ +N; ßⴠ.\u0620刯ⴝ; [B2 B3]; [B2 B3] # ßⴠ.ؠ刯ⴝ +B; SSჀ.\u0620刯Ⴝ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ssჀ.ؠ刯Ⴝ +B; ssâ´ .\u0620刯ⴝ; [B2 B3]; [B2 B3] # ssâ´ .ؠ刯ⴝ +B; Ssâ´ .\u0620刯Ⴝ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ssâ´ .ؠ刯Ⴝ +B; xn--ss-j81a.xn--fgb845cb66c; [B2 B3 V6]; [B2 B3 V6] # ssâ´ .ؠ刯Ⴝ +B; xn--ss-j81a.xn--fgb670rovy; [B2 B3]; [B2 B3] # ssâ´ .ؠ刯ⴝ +B; xn--ss-wgk.xn--fgb845cb66c; [B2 B3 V6]; [B2 B3 V6] # ssჀ.ؠ刯Ⴝ +B; xn--zca277t.xn--fgb670rovy; [B2 B3]; [B2 B3] # ßⴠ.ؠ刯ⴝ +B; xn--zca442f.xn--fgb845cb66c; [B2 B3 V6]; [B2 B3 V6] # ßჀ.ؠ刯Ⴝ +B; \u1BAAႣℲ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪ႣℲ.ᠳ툻ٳ +B; \u1BAAႣℲ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪ႣℲ.ᠳ툻ٳ +B; \u1BAAႣℲ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪ႣℲ.ᠳ툻ٳ +B; \u1BAAႣℲ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪ႣℲ.ᠳ툻ٳ +B; \u1BAAⴃⅎ。ᠳ툻\u0673; [B5 B6 V5]; [B5 B6 V5] # ᮪ⴃⅎ.ᠳ툻ٳ +B; \u1BAAⴃⅎ。ᠳ툻\u0673; [B5 B6 V5]; [B5 B6 V5] # ᮪ⴃⅎ.ᠳ툻ٳ +B; \u1BAAႣⅎ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪Ⴃⅎ.ᠳ툻ٳ +B; \u1BAAႣⅎ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪Ⴃⅎ.ᠳ툻ٳ +B; xn--bnd957c2pe.xn--sib102gc69k; [B5 B6 V5 V6]; [B5 B6 V5 V6] # ᮪Ⴃⅎ.ᠳ툻ٳ +B; xn--yxf24x4ol.xn--sib102gc69k; [B5 B6 V5]; [B5 B6 V5] # ᮪ⴃⅎ.ᠳ툻ٳ +B; xn--bnd957cone.xn--sib102gc69k; [B5 B6 V5 V6]; [B5 B6 V5 V6] # ᮪ႣℲ.ᠳ툻ٳ +B; \u1BAAⴃⅎ。ᠳ툻\u0673; [B5 B6 V5]; [B5 B6 V5] # ᮪ⴃⅎ.ᠳ툻ٳ +B; \u1BAAⴃⅎ。ᠳ툻\u0673; [B5 B6 V5]; [B5 B6 V5] # ᮪ⴃⅎ.ᠳ툻ٳ +B; \u1BAAႣⅎ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪Ⴃⅎ.ᠳ툻ٳ +B; \u1BAAႣⅎ。ᠳ툻\u0673; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] # ᮪Ⴃⅎ.ᠳ툻ٳ +B; \u06EC.\u08A2𐹫\u067C; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Û¬.ࢢ𐹫ټ +B; xn--8lb.xn--1ib31ily45b; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Û¬.ࢢ𐹫ټ +B; \u06B6\u06DF。₇\uA806; [B1]; [B1] # ڶ۟.7꠆ +B; \u06B6\u06DF。7\uA806; [B1]; [B1] # ڶ۟.7꠆ +B; xn--pkb6f.xn--7-x93e; [B1]; [B1] # ڶ۟.7꠆ +B; \u06B6\u06DF.7\uA806; [B1]; [B1] # ڶ۟.7꠆ +T; Ⴣ𐹻.\u200C𝪣≮󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V5 V6] # Ⴣ𐹻.𝪣≮ +N; Ⴣ𐹻.\u200C𝪣≮󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # Ⴣ𐹻.𝪣≮ +T; Ⴣ𐹻.\u200C𝪣<\u0338󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V5 V6] # Ⴣ𐹻.𝪣≮ +N; Ⴣ𐹻.\u200C𝪣<\u0338󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # Ⴣ𐹻.𝪣≮ +T; ⴣ𐹻.\u200C𝪣<\u0338󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V5 V6] # ⴣ𐹻.𝪣≮ +N; ⴣ𐹻.\u200C𝪣<\u0338󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # ⴣ𐹻.𝪣≮ +T; ⴣ𐹻.\u200C𝪣≮󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V5 V6] # ⴣ𐹻.𝪣≮ +N; ⴣ𐹻.\u200C𝪣≮󠩉; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # ⴣ𐹻.𝪣≮ +B; xn--rlj6323e.xn--gdh4944ob3x3e; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--rlj6323e.xn--0ugy6gn120eb103g; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # ⴣ𐹻.𝪣≮ +B; xn--7nd8101k.xn--gdh4944ob3x3e; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--7nd8101k.xn--0ugy6gn120eb103g; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # Ⴣ𐹻.𝪣≮ +T; 𝟵隁⯮.\u180D\u200C; [C1]; xn--9-mfs8024b. # 9隁⯮. +N; 𝟵隁⯮.\u180D\u200C; [C1]; [C1] # 9隁⯮. +T; 9隁⯮.\u180D\u200C; [C1]; xn--9-mfs8024b. # 9隁⯮. +N; 9隁⯮.\u180D\u200C; [C1]; [C1] # 9隁⯮. +B; xn--9-mfs8024b.; 9隁⯮.; xn--9-mfs8024b.; NV8 +B; 9隁⯮.; ; xn--9-mfs8024b.; NV8 +B; xn--9-mfs8024b.xn--0ug; [C1]; [C1] # 9隁⯮. +B; ⒏𐹧。Ⴣ\u0F84彦; [B1 P1 V6]; [B1 P1 V6] # ⒏𐹧.Ⴣ྄彦 +B; 8.𐹧。Ⴣ\u0F84彦; [B1 P1 V6]; [B1 P1 V6] # 8.𐹧.Ⴣ྄彦 +B; 8.𐹧。ⴣ\u0F84彦; [B1]; [B1] # 8.𐹧.ⴣ྄彦 +B; 8.xn--fo0d.xn--3ed972m6o8a; [B1]; [B1] # 8.𐹧.ⴣ྄彦 +B; 8.xn--fo0d.xn--3ed15dt93o; [B1 V6]; [B1 V6] # 8.𐹧.Ⴣ྄彦 +B; ⒏𐹧。ⴣ\u0F84彦; [B1 P1 V6]; [B1 P1 V6] # ⒏𐹧.ⴣ྄彦 +B; xn--0sh2466f.xn--3ed972m6o8a; [B1 V6]; [B1 V6] # ⒏𐹧.ⴣ྄彦 +B; xn--0sh2466f.xn--3ed15dt93o; [B1 V6]; [B1 V6] # ⒏𐹧.Ⴣ྄彦 +B; -问ñ¬°”⒛。\u0604-ñœ—‰æ©¬; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -问⒛.-橬 +B; -问ñ¬°”20.。\u0604-ñœ—‰æ©¬; [B1 P1 V3 V6 A4_2]; [B1 P1 V3 V6 A4_2] # -问20..-橬 +B; xn---20-658jx1776d..xn----ykc7228efm46d; [B1 V3 V6 A4_2]; [B1 V3 V6 A4_2] # -问20..-橬 +B; xn----hdpu849bhis3e.xn----ykc7228efm46d; [B1 V3 V6]; [B1 V3 V6] # -问⒛.-橬 +T; \u1BACႬ\u200C\u0325。𝟸; [C1 P1 V5 V6]; [P1 V5 V6] # ᮬႬ̥.2 +N; \u1BACႬ\u200C\u0325。𝟸; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ᮬႬ̥.2 +T; \u1BACႬ\u200C\u0325。2; [C1 P1 V5 V6]; [P1 V5 V6] # ᮬႬ̥.2 +N; \u1BACႬ\u200C\u0325。2; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ᮬႬ̥.2 +T; \u1BACⴌ\u200C\u0325。2; [C1 V5]; [V5] # ᮬⴌ̥.2 +N; \u1BACⴌ\u200C\u0325。2; [C1 V5]; [C1 V5] # ᮬⴌ̥.2 +B; xn--mta176jjjm.2; [V5]; [V5] # ᮬⴌ̥.2 +B; xn--mta176j97cl2q.2; [C1 V5]; [C1 V5] # ᮬⴌ̥.2 +B; xn--mta930emri.2; [V5 V6]; [V5 V6] # ᮬႬ̥.2 +B; xn--mta930emribme.2; [C1 V5 V6]; [C1 V5 V6] # ᮬႬ̥.2 +T; \u1BACⴌ\u200C\u0325。𝟸; [C1 V5]; [V5] # ᮬⴌ̥.2 +N; \u1BACⴌ\u200C\u0325。𝟸; [C1 V5]; [C1 V5] # ᮬⴌ̥.2 +B; \uDC5F。\uA806\u0669󠒩; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # .꠆٩ +B; \uDC5F.xn--iib9583fusy0i; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # .꠆٩ +B; \uDC5F.XN--IIB9583FUSY0I; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # .꠆٩ +B; \uDC5F.Xn--Iib9583fusy0i; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # .꠆٩ +B; 󠄁\u035F⾶。₇︒눇≮; [P1 V5 V6]; [P1 V5 V6] # ͟飛.7︒눇≮ +B; 󠄁\u035F⾶。₇︒눇<\u0338; [P1 V5 V6]; [P1 V5 V6] # ͟飛.7︒눇≮ +B; 󠄁\u035F飛。7。눇≮; [P1 V5 V6]; [P1 V5 V6] # ͟飛.7.눇≮ +B; 󠄁\u035F飛。7。눇<\u0338; [P1 V5 V6]; [P1 V5 V6] # ͟飛.7.눇≮ +B; xn--9ua0567e.7.xn--gdh6767c; [V5 V6]; [V5 V6] # ͟飛.7.눇≮ +B; xn--9ua0567e.xn--7-ngou006d1ttc; [V5 V6]; [V5 V6] # ͟飛.7︒눇≮ +T; \u200C\uFE09𐹴\u200D.\u200C⿃; [B1 C1 C2]; [B1] # 𐹴.é³¥ +N; \u200C\uFE09𐹴\u200D.\u200C⿃; [B1 C1 C2]; [B1 C1 C2] # 𐹴.é³¥ +T; \u200C\uFE09𐹴\u200D.\u200Cé³¥; [B1 C1 C2]; [B1] # 𐹴.é³¥ +N; \u200C\uFE09𐹴\u200D.\u200Cé³¥; [B1 C1 C2]; [B1 C1 C2] # 𐹴.é³¥ +B; xn--so0d.xn--6x6a; [B1]; [B1] +B; xn--0ugc6024p.xn--0ug1920c; [B1 C1 C2]; [B1 C1 C2] # 𐹴.é³¥ +T; 🍮.\u200D󠗒𐦁𝨝; [B1 C2 P1 V6]; [B1 P1 V6] # 🍮.𐦁𝨝 +N; 🍮.\u200D󠗒𐦁𝨝; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 🍮.𐦁𝨝 +T; 🍮.\u200D󠗒𐦁𝨝; [B1 C2 P1 V6]; [B1 P1 V6] # 🍮.𐦁𝨝 +N; 🍮.\u200D󠗒𐦁𝨝; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 🍮.𐦁𝨝 +B; xn--lj8h.xn--ln9ci476aqmr2g; [B1 V6]; [B1 V6] +B; xn--lj8h.xn--1ug6603gr1pfwq37h; [B1 C2 V6]; [B1 C2 V6] # 🍮.𐦁𝨝 +T; \u067D\u0943.𞤓\u200D; [B3 C2]; xn--2ib43l.xn--te6h # ٽृ.𞤵 +N; \u067D\u0943.𞤓\u200D; [B3 C2]; [B3 C2] # ٽृ.𞤵 +T; \u067D\u0943.𞤵\u200D; [B3 C2]; xn--2ib43l.xn--te6h # ٽृ.𞤵 +N; \u067D\u0943.𞤵\u200D; [B3 C2]; [B3 C2] # ٽृ.𞤵 +B; xn--2ib43l.xn--te6h; \u067D\u0943.𞤵; xn--2ib43l.xn--te6h # ٽृ.𞤵 +B; \u067D\u0943.𞤵; ; xn--2ib43l.xn--te6h # ٽृ.𞤵 +B; \u067D\u0943.𞤓; \u067D\u0943.𞤵; xn--2ib43l.xn--te6h # ٽृ.𞤵 +B; xn--2ib43l.xn--1ugy711p; [B3 C2]; [B3 C2] # ٽृ.𞤵 +B; \u0664\u0A4D-.󥜽\u1039ñ¦¦; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ٤੍-.္ +B; \u0664\u0A4D-.󥜽\u1039ñ¦¦; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ٤੍-.္ +B; xn----gqc711a.xn--9jd88234f3qm0b; [B1 V3 V6]; [B1 V3 V6] # ٤੍-.္ +T; 4\u103A-𐹸。\uAA29\u200C𐹴≮; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +N; 4\u103A-𐹸。\uAA29\u200C𐹴≮; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +T; 4\u103A-𐹸。\uAA29\u200C𐹴<\u0338; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +N; 4\u103A-𐹸。\uAA29\u200C𐹴<\u0338; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +T; 4\u103A-𐹸。\uAA29\u200C𐹴≮; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +N; 4\u103A-𐹸。\uAA29\u200C𐹴≮; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +T; 4\u103A-𐹸。\uAA29\u200C𐹴<\u0338; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +N; 4\u103A-𐹸。\uAA29\u200C𐹴<\u0338; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +B; xn--4--e4j7831r.xn--gdh8754cz40c; [B1 V5 V6]; [B1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +B; xn--4--e4j7831r.xn--0ugy6gjy5sl3ud; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 4်-𐹸.ꨩ𐹴≮ +T; \u200C。\uFFA0\u0F84\u0F96; [C1 P1 V6]; [P1 V6 A4_2] # .྄ྖ +N; \u200C。\uFFA0\u0F84\u0F96; [C1 P1 V6]; [C1 P1 V6] # .྄ྖ +T; \u200C。\u1160\u0F84\u0F96; [C1 P1 V6]; [P1 V6 A4_2] # .྄ྖ +N; \u200C。\u1160\u0F84\u0F96; [C1 P1 V6]; [C1 P1 V6] # .྄ྖ +B; .xn--3ed0b20h; [V6 A4_2]; [V6 A4_2] # .྄ྖ +B; xn--0ug.xn--3ed0b20h; [C1 V6]; [C1 V6] # .྄ྖ +B; .xn--3ed0by082k; [V6 A4_2]; [V6 A4_2] # .྄ྖ +B; xn--0ug.xn--3ed0by082k; [C1 V6]; [C1 V6] # .྄ྖ +T; ≯ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [P1 V6] # ≯.𐅼 +N; ≯ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [C2 P1 V6] # ≯.𐅼 +T; >\u0338ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [P1 V6] # ≯.𐅼 +N; >\u0338ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [C2 P1 V6] # ≯.𐅼 +T; ≯ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [P1 V6] # ≯.𐅼 +N; ≯ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [C2 P1 V6] # ≯.𐅼 +T; >\u0338ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [P1 V6] # ≯.𐅼 +N; >\u0338ò˜….\u200D𐅼ò²‡›; [C2 P1 V6]; [C2 P1 V6] # ≯.𐅼 +B; xn--hdh84488f.xn--xy7cw2886b; [V6]; [V6] +B; xn--hdh84488f.xn--1ug8099fbjp4e; [C2 V6]; [C2 V6] # ≯.𐅼 +T; \u0641ß𐰯。𝟕𐫫; [B1 B2]; [B1 B2] # فß𐰯.7𐫫 +N; \u0641ß𐰯。𝟕𐫫; [B1 B2]; [B1 B2] # فß𐰯.7𐫫 +T; \u0641ß𐰯。7𐫫; [B1 B2]; [B1 B2] # فß𐰯.7𐫫 +N; \u0641ß𐰯。7𐫫; [B1 B2]; [B1 B2] # فß𐰯.7𐫫 +B; \u0641SS𐰯。7𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; \u0641ss𐰯。7𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; \u0641Ss𐰯。7𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; xn--ss-jvd2339x.xn--7-mm5i; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; xn--zca96ys96y.xn--7-mm5i; [B1 B2]; [B1 B2] # فß𐰯.7𐫫 +B; \u0641SS𐰯。𝟕𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; \u0641ss𐰯。𝟕𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +B; \u0641Ss𐰯。𝟕𐫫; [B1 B2]; [B1 B2] # فss𐰯.7𐫫 +T; ß\u07AC\u07A7\u08B1。𐭁ô…®™ð¹²; [B2 B5 B6 P1 V6]; [B2 B5 B6 P1 V6] # ßެާࢱ.𐭁𐹲 +N; ß\u07AC\u07A7\u08B1。𐭁ô…®™ð¹²; [B2 B5 B6 P1 V6]; [B2 B5 B6 P1 V6] # ßެާࢱ.𐭁𐹲 +B; SS\u07AC\u07A7\u08B1。𐭁ô…®™ð¹²; [B2 B5 B6 P1 V6]; [B2 B5 B6 P1 V6] # ssެާࢱ.𐭁𐹲 +B; ss\u07AC\u07A7\u08B1。𐭁ô…®™ð¹²; [B2 B5 B6 P1 V6]; [B2 B5 B6 P1 V6] # ssެާࢱ.𐭁𐹲 +B; Ss\u07AC\u07A7\u08B1。𐭁ô…®™ð¹²; [B2 B5 B6 P1 V6]; [B2 B5 B6 P1 V6] # ssެާࢱ.𐭁𐹲 +B; xn--ss-9qet02k.xn--e09co8cr9861c; [B2 B5 B6 V6]; [B2 B5 B6 V6] # ssެާࢱ.𐭁𐹲 +B; xn--zca685aoa95h.xn--e09co8cr9861c; [B2 B5 B6 V6]; [B2 B5 B6 V6] # ßެާࢱ.𐭁𐹲 +B; -。󠉗⒌𞯛; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -。󠉗5.𞯛; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -.xn--5-zz21m.xn--6x6h; [B1 V3 V6]; [B1 V3 V6] +B; -.xn--xsh6367n1bi3e; [B1 V3 V6]; [B1 V3 V6] +T; 𼎏ς.-≮\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +N; 𼎏ς.-≮\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +T; 𼎏ς.-<\u0338\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +N; 𼎏ς.-<\u0338\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +T; 𼎏ς.-≮\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +N; 𼎏ς.-≮\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +T; 𼎏ς.-<\u0338\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +N; 𼎏ς.-<\u0338\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ς.-≮خج +B; 𼎏Σ.-<\u0338\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏Σ.-≮\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏σ.-≮\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏σ.-<\u0338\u062E\u062C; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; xn--4xa92520c.xn----9mcf1400a; [B1 V3 V6]; [B1 V3 V6] # σ.-≮خج +B; xn--3xa13520c.xn----9mcf1400a; [B1 V3 V6]; [B1 V3 V6] # ς.-≮خج +B; 𼎏Σ.-<\u0338\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏Σ.-≮\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏σ.-≮\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; 𼎏σ.-<\u0338\uFCAB; [B1 P1 V3 V6]; [B1 P1 V3 V6] # σ.-≮خج +B; ꡗ\u08B8\u0719.ñ”¤”ó ›™\u0C4D\uFC3E; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ꡗࢸܙ.్كي +B; ꡗ\u08B8\u0719.ñ”¤”ó ›™\u0C4D\u0643\u064A; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ꡗࢸܙ.్كي +B; xn--jnb34fs003a.xn--fhbo927bk128mpi24d; [B5 B6 V6]; [B5 B6 V6] # ꡗࢸܙ.్كي +B; 𐠰\u08B7𞤌𐫭。𐋦\u17CD𝩃; [B1]; [B1] # 𐠰ࢷ𞤮𐫭.𐋦៍𝩃 +B; 𐠰\u08B7𞤮𐫭。𐋦\u17CD𝩃; [B1]; [B1] # 𐠰ࢷ𞤮𐫭.𐋦៍𝩃 +B; xn--dzb5191kezbrw47a.xn--p4e3841jz9tf; [B1]; [B1] # 𐠰ࢷ𞤮𐫭.𐋦៍𝩃 +B; 𐠰\u08B7𞤮𐫭.𐋦\u17CD𝩃; [B1]; [B1] # 𐠰ࢷ𞤮𐫭.𐋦៍𝩃 +B; 𐠰\u08B7𞤌𐫭.𐋦\u17CD𝩃; [B1]; [B1] # 𐠰ࢷ𞤮𐫭.𐋦៍𝩃 +T; ₂㘷--。\u06D3\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +N; ₂㘷--。\u06D3\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 C1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +T; ₂㘷--。\u06D2\u0654\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +N; ₂㘷--。\u06D2\u0654\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 C1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +T; 2㘷--。\u06D3\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +N; 2㘷--。\u06D3\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 C1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +T; 2㘷--。\u06D2\u0654\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +N; 2㘷--。\u06D2\u0654\u200C𐫆𑖿; [B1 C1 V2 V3]; [B1 C1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +B; xn--2---u58b.xn--jlb8024k14g; [B1 V2 V3]; [B1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +B; xn--2---u58b.xn--jlb820ku99nbgj; [B1 C1 V2 V3]; [B1 C1 V2 V3] # 2㘷--.ۓ𐫆𑖿 +B; -𘊻.ᡮ\u062D-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # -𘊻.ᡮح- +B; -𘊻.á¡®\u062D-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # -𘊻.ᡮح- +B; xn----bp5n.xn----bnc231l; [B1 B5 B6 V3]; [B1 B5 B6 V3] # -𘊻.ᡮح- +T; \u200C-ß。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ß.ᢣ𐹭ؿ +N; \u200C-ß。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ß.ᢣ𐹭ؿ +T; \u200C-ß。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ß.ᢣ𐹭ؿ +N; \u200C-ß。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ß.ᢣ𐹭ؿ +T; \u200C-SS。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-SS。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +T; \u200C-ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +T; \u200C-Ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-Ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +B; -ss.xn--bhb925glx3p; [B1 B5 B6 V3]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +B; xn---ss-8m0a.xn--bhb925glx3p; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +B; xn----qfa550v.xn--bhb925glx3p; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ß.ᢣ𐹭ؿ +T; \u200C-SS。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-SS。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +T; \u200C-ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +T; \u200C-Ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 V3] # -ss.ᢣ𐹭ؿ +N; \u200C-Ss。ᢣ𐹭\u063F; [B1 B5 B6 C1]; [B1 B5 B6 C1] # -ss.ᢣ𐹭ؿ +B; ꧐Ӏ\u1BAA\u08F6.눵; [P1 V6]; [P1 V6] # ꧐Ӏ᮪ࣶ.눵 +B; ꧐Ӏ\u1BAA\u08F6.눵; [P1 V6]; [P1 V6] # ꧐Ӏ᮪ࣶ.눵 +B; ꧐Ӏ\u1BAA\u08F6.눵; [P1 V6]; [P1 V6] # ꧐Ӏ᮪ࣶ.눵 +B; ꧐Ӏ\u1BAA\u08F6.눵; [P1 V6]; [P1 V6] # ꧐Ӏ᮪ࣶ.눵 +B; ꧐ӏ\u1BAA\u08F6.눵; ꧐ӏ\u1BAA\u08F6.눵; xn--s5a04sn4u297k.xn--2e1b # ꧐ӏ᮪ࣶ.눵 +B; ꧐ӏ\u1BAA\u08F6.눵; ; xn--s5a04sn4u297k.xn--2e1b # ꧐ӏ᮪ࣶ.눵 +B; xn--s5a04sn4u297k.xn--2e1b; ꧐ӏ\u1BAA\u08F6.눵; xn--s5a04sn4u297k.xn--2e1b # ꧐ӏ᮪ࣶ.눵 +B; xn--d5a07sn4u297k.xn--2e1b; [V6]; [V6] # ꧐Ӏ᮪ࣶ.눵 +B; ꧐ӏ\u1BAA\u08F6.눵; ꧐ӏ\u1BAA\u08F6.눵; xn--s5a04sn4u297k.xn--2e1b # ꧐ӏ᮪ࣶ.눵 +B; ꧐ӏ\u1BAA\u08F6.눵; ꧐ӏ\u1BAA\u08F6.눵; xn--s5a04sn4u297k.xn--2e1b # ꧐ӏ᮪ࣶ.눵 +B; \uA8EA。𖄿𑆾󠇗; [P1 V5 V6]; [P1 V5 V6] # ꣪.𑆾 +B; \uA8EA。𖄿𑆾󠇗; [P1 V5 V6]; [P1 V5 V6] # ꣪.𑆾 +B; xn--3g9a.xn--ud1dz07k; [V5 V6]; [V5 V6] # ꣪.𑆾 +B; 󇓓𑚳。ñ·¿â‰¯â¾‡; [P1 V6]; [P1 V6] +B; 󇓓𑚳。ñ·¿>\u0338⾇; [P1 V6]; [P1 V6] +B; 󇓓𑚳。ñ·¿â‰¯èˆ›; [P1 V6]; [P1 V6] +B; 󇓓𑚳。ñ·¿>\u0338舛; [P1 V6]; [P1 V6] +B; xn--3e2d79770c.xn--hdh0088abyy1c; [V6]; [V6] +T; 𐫇\u0661\u200C.\u200D\u200C; [B1 B3 C1 C2]; xn--9hb7344k. # 𐫇١. +N; 𐫇\u0661\u200C.\u200D\u200C; [B1 B3 C1 C2]; [B1 B3 C1 C2] # 𐫇١. +T; 𐫇\u0661\u200C.\u200D\u200C; [B1 B3 C1 C2]; xn--9hb7344k. # 𐫇١. +N; 𐫇\u0661\u200C.\u200D\u200C; [B1 B3 C1 C2]; [B1 B3 C1 C2] # 𐫇١. +B; xn--9hb7344k.; 𐫇\u0661.; xn--9hb7344k. # 𐫇١. +B; 𐫇\u0661.; ; xn--9hb7344k. # 𐫇١. +B; xn--9hb652kv99n.xn--0ugb; [B1 B3 C1 C2]; [B1 B3 C1 C2] # 𐫇١. +T; ñ¡…ˆç ªâ‰¯á¢‘。≯𝩚ò“´”\u200C; [C1 P1 V6]; [P1 V6] # 砪≯ᢑ.≯𝩚 +N; ñ¡…ˆç ªâ‰¯á¢‘。≯𝩚ò“´”\u200C; [C1 P1 V6]; [C1 P1 V6] # 砪≯ᢑ.≯𝩚 +T; ñ¡…ˆç ª>\u0338ᢑ。>\u0338𝩚ò“´”\u200C; [C1 P1 V6]; [P1 V6] # 砪≯ᢑ.≯𝩚 +N; ñ¡…ˆç ª>\u0338ᢑ。>\u0338𝩚ò“´”\u200C; [C1 P1 V6]; [C1 P1 V6] # 砪≯ᢑ.≯𝩚 +T; ñ¡…ˆç ªâ‰¯á¢‘。≯𝩚ò“´”\u200C; [C1 P1 V6]; [P1 V6] # 砪≯ᢑ.≯𝩚 +N; ñ¡…ˆç ªâ‰¯á¢‘。≯𝩚ò“´”\u200C; [C1 P1 V6]; [C1 P1 V6] # 砪≯ᢑ.≯𝩚 +T; ñ¡…ˆç ª>\u0338ᢑ。>\u0338𝩚ò“´”\u200C; [C1 P1 V6]; [P1 V6] # 砪≯ᢑ.≯𝩚 +N; ñ¡…ˆç ª>\u0338ᢑ。>\u0338𝩚ò“´”\u200C; [C1 P1 V6]; [C1 P1 V6] # 砪≯ᢑ.≯𝩚 +B; xn--bbf561cf95e57y3e.xn--hdh0834o7mj6b; [V6]; [V6] +B; xn--bbf561cf95e57y3e.xn--0ugz6gc910ejro8c; [C1 V6]; [C1 V6] # 砪≯ᢑ.≯𝩚 +B; Ⴥ.𑄳㊸; [P1 V5 V6]; [P1 V5 V6] +B; Ⴥ.𑄳43; [P1 V5 V6]; [P1 V5 V6] +B; â´¥.𑄳43; [V5]; [V5] +B; xn--tlj.xn--43-274o; [V5]; [V5] +B; xn--9nd.xn--43-274o; [V5 V6]; [V5 V6] +B; â´¥.𑄳㊸; [V5]; [V5] +B; 𝟎\u0663。Ⴒᡇ\u08F2𐹠; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 0Ù£.Ⴒᡇࣲ𐹠 +B; 0\u0663。Ⴒᡇ\u08F2𐹠; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 0Ù£.Ⴒᡇࣲ𐹠 +B; 0\u0663。ⴒᡇ\u08F2𐹠; [B1 B5 B6]; [B1 B5 B6] # 0Ù£.ⴒᡇࣲ𐹠 +B; xn--0-fqc.xn--10b369eivp359r; [B1 B5 B6]; [B1 B5 B6] # 0Ù£.ⴒᡇࣲ𐹠 +B; xn--0-fqc.xn--10b180bnwgfy0z; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 0Ù£.Ⴒᡇࣲ𐹠 +B; 𝟎\u0663。ⴒᡇ\u08F2𐹠; [B1 B5 B6]; [B1 B5 B6] # 0Ù£.ⴒᡇࣲ𐹠 +B; ñ—ª¨ó „‰\uFFA0\u0FB7.ñ¸ž°\uA953; [P1 V6]; [P1 V6] # ྷ.꥓ +B; ñ—ª¨ó „‰\u1160\u0FB7.ñ¸ž°\uA953; [P1 V6]; [P1 V6] # ྷ.꥓ +B; xn--kgd36f9z57y.xn--3j9au7544a; [V6]; [V6] # ྷ.꥓ +B; xn--kgd7493jee34a.xn--3j9au7544a; [V6]; [V6] # ྷ.꥓ +T; \u0618.Û³\u200C\uA953; [C1 V5]; [V5] # ؘ.۳꥓ +N; \u0618.Û³\u200C\uA953; [C1 V5]; [C1 V5] # ؘ.۳꥓ +B; xn--6fb.xn--gmb0524f; [V5]; [V5] # ؘ.۳꥓ +B; xn--6fb.xn--gmb469jjf1h; [C1 V5]; [C1 V5] # ؘ.۳꥓ +B; ᡌ.︒ᢑ; [P1 V6]; [P1 V6] +B; ᡌ.。ᢑ; [A4_2]; [A4_2] +B; xn--c8e..xn--bbf; [A4_2]; [A4_2] +B; xn--c8e.xn--bbf9168i; [V6]; [V6] +B; 𑋪\u1073。𞽧; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑋪ၳ. +B; 𑋪\u1073。𞽧; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑋪ၳ. +B; xn--xld7443k.xn--4o7h; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # 𑋪ၳ. +B; 𞷏。ᠢò“˜†; [P1 V6]; [P1 V6] +B; xn--hd7h.xn--46e66060j; [V6]; [V6] +T; 𑄳㴼.\u200C𐹡\u20EBñ«º¦; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𑄳㴼.𐹡⃫ +N; 𑄳㴼.\u200C𐹡\u20EBñ«º¦; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𑄳㴼.𐹡⃫ +T; 𑄳㴼.\u200C𐹡\u20EBñ«º¦; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𑄳㴼.𐹡⃫ +N; 𑄳㴼.\u200C𐹡\u20EBñ«º¦; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𑄳㴼.𐹡⃫ +B; xn--iym9428c.xn--e1g3464g08p3b; [B1 V5 V6]; [B1 V5 V6] # 𑄳㴼.𐹡⃫ +B; xn--iym9428c.xn--0ug46a7218cllv0c; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 𑄳㴼.𐹡⃫ +B; ñ »Ÿð¹³ð‘ˆ¯ï½¡\u031D; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # 𐹳𑈯.̝ +B; ñ »Ÿð¹³ð‘ˆ¯ã€‚\u031D; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # 𐹳𑈯.̝ +B; xn--ro0dw7dey96m.xn--eta; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # 𐹳𑈯.̝ +B; ᢊ뾜󠱴𑚶。\u089D𐹥; [P1 V6]; [P1 V6] # ᢊ뾜𑚶.𐹥 +B; ᢊ뾜󠱴𑚶。\u089D𐹥; [P1 V6]; [P1 V6] # ᢊ뾜𑚶.𐹥 +B; xn--39e4566fjv8bwmt6n.xn--myb6415k; [V6]; [V6] # ᢊ뾜𑚶.𐹥 +T; 𐹥≠。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹥≠.𐋲 +N; 𐹥≠。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹥≠.𐋲 +T; 𐹥=\u0338。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹥≠.𐋲 +N; 𐹥=\u0338。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹥≠.𐋲 +T; 𐹥≠。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹥≠.𐋲 +N; 𐹥≠。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹥≠.𐋲 +T; 𐹥=\u0338。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹥≠.𐋲 +N; 𐹥=\u0338。𐋲󠧠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹥≠.𐋲 +B; xn--1ch6704g.xn--m97cw2999c; [B1 V6]; [B1 V6] +B; xn--1ch6704g.xn--0ug3840g51u4g; [B1 C1 V6]; [B1 C1 V6] # 𐹥≠.𐋲 +T; \u115Fñ™¯ \u094D.\u200D\uA953𐪤; [B1 C2 P1 V6]; [B5 B6 P1 V5 V6] # ्.꥓ +N; \u115Fñ™¯ \u094D.\u200D\uA953𐪤; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ्.꥓ +T; \u115Fñ™¯ \u094D.\u200D\uA953𐪤; [B1 C2 P1 V6]; [B5 B6 P1 V5 V6] # ्.꥓ +N; \u115Fñ™¯ \u094D.\u200D\uA953𐪤; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ्.꥓ +B; xn--n3b542bb085j.xn--3j9al95p; [B5 B6 V5 V6]; [B5 B6 V5 V6] # ्.꥓ +B; xn--n3b542bb085j.xn--1ug6815co9wc; [B1 C2 V6]; [B1 C2 V6] # ्.꥓ +B; òŒ‹”󠆎󠆗𑲕。≮; [P1 V6]; [P1 V6] +B; òŒ‹”󠆎󠆗𑲕。<\u0338; [P1 V6]; [P1 V6] +B; xn--4m3dv4354a.xn--gdh; [V6]; [V6] +B; 󠆦.\u08E3暀≠; [P1 V5 V6 A4_2]; [P1 V5 V6 A4_2] # .ࣣ暀≠ +B; 󠆦.\u08E3暀=\u0338; [P1 V5 V6 A4_2]; [P1 V5 V6 A4_2] # .ࣣ暀≠ +B; .xn--m0b461k3g2c; [V5 V6 A4_2]; [V5 V6 A4_2] # .ࣣ暀≠ +B; 𐡤\uABED。\uFD30òœ–…\u1DF0; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐡤꯭.شمᷰ +B; 𐡤\uABED。\u0634\u0645òœ–…\u1DF0; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐡤꯭.شمᷰ +B; xn--429ak76o.xn--zgb8a701kox37t; [B2 B3 V6]; [B2 B3 V6] # 𐡤꯭.شمᷰ +T; 𝉃\u200D⒈。Ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝉃⒈.Ⴌ +N; 𝉃\u200D⒈。Ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # 𝉃⒈.Ⴌ +T; 𝉃\u200D1.。Ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6 A4_2]; [B1 B5 B6 P1 V5 V6 A4_2] # 𝉃1..Ⴌ +N; 𝉃\u200D1.。Ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6 A4_2]; [B1 B5 B6 C2 P1 V5 V6 A4_2] # 𝉃1..Ⴌ +T; 𝉃\u200D1.。ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6 A4_2]; [B1 B5 B6 P1 V5 V6 A4_2] # 𝉃1..ⴌ +N; 𝉃\u200D1.。ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6 A4_2]; [B1 B5 B6 C2 P1 V5 V6 A4_2] # 𝉃1..ⴌ +B; xn--1-px8q..xn--3kj4524l; [B1 B5 B6 V5 V6 A4_2]; [B1 B5 B6 V5 V6 A4_2] +B; xn--1-tgn9827q..xn--3kj4524l; [B1 B5 B6 C2 V5 V6 A4_2]; [B1 B5 B6 C2 V5 V6 A4_2] # 𝉃1..ⴌ +B; xn--1-px8q..xn--knd8464v; [B1 B5 B6 V5 V6 A4_2]; [B1 B5 B6 V5 V6 A4_2] +B; xn--1-tgn9827q..xn--knd8464v; [B1 B5 B6 C2 V5 V6 A4_2]; [B1 B5 B6 C2 V5 V6 A4_2] # 𝉃1..Ⴌ +T; 𝉃\u200D⒈。ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝉃⒈.ⴌ +N; 𝉃\u200D⒈。ⴌ𞱓; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # 𝉃⒈.ⴌ +B; xn--tshz828m.xn--3kj4524l; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--1ug68oq348b.xn--3kj4524l; [B1 B5 B6 C2 V5 V6]; [B1 B5 B6 C2 V5 V6] # 𝉃⒈.ⴌ +B; xn--tshz828m.xn--knd8464v; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--1ug68oq348b.xn--knd8464v; [B1 B5 B6 C2 V5 V6]; [B1 B5 B6 C2 V5 V6] # 𝉃⒈.Ⴌ +T; 󠣙\u0A4D𱫘𞤸.ςñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.ς +N; 󠣙\u0A4D𱫘𞤸.ςñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.ς +B; 󠣙\u0A4D𱫘𞤖.Σñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.σ +B; 󠣙\u0A4D𱫘𞤸.σñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.σ +B; 󠣙\u0A4D𱫘𞤖.σñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.σ +B; xn--ybc0236vjvxgt5q0g.xn--4xa82737giye6b; [B1 V6]; [B1 V6] # ੍𞤸.σ +T; 󠣙\u0A4D𱫘𞤖.ςñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.ς +N; 󠣙\u0A4D𱫘𞤖.ςñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.ς +B; xn--ybc0236vjvxgt5q0g.xn--3xa03737giye6b; [B1 V6]; [B1 V6] # ੍𞤸.ς +B; 󠣙\u0A4D𱫘𞤸.Σñµ¯žôˆ°”; [B1 P1 V6]; [B1 P1 V6] # ੍𞤸.σ +T; \u07D3。\u200C𐫀òž­±; [B1 C1 P1 V6]; [B2 B3 P1 V6] # ߓ.𐫀 +N; \u07D3。\u200C𐫀òž­±; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ߓ.𐫀 +B; xn--usb.xn--pw9ci1099a; [B2 B3 V6]; [B2 B3 V6] # ߓ.𐫀 +B; xn--usb.xn--0ug9553gm3v5d; [B1 C1 V6]; [B1 C1 V6] # ߓ.𐫀 +B; \u1C2E𞀝.\u05A6ꡟ𞤕󠆖; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ᰮ𞀝.֦ꡟ𞤷 +B; \u1C2E𞀝.\u05A6ꡟ𞤷󠆖; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ᰮ𞀝.֦ꡟ𞤷 +B; xn--q1f4493q.xn--xcb8244fifvj; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ᰮ𞀝.֦ꡟ𞤷 +T; 䂹󾖅𐋦.\u200D; [C2 P1 V6]; [P1 V6] # 䂹𐋦. +N; 䂹󾖅𐋦.\u200D; [C2 P1 V6]; [C2 P1 V6] # 䂹𐋦. +T; 䂹󾖅𐋦.\u200D; [C2 P1 V6]; [P1 V6] # 䂹𐋦. +N; 䂹󾖅𐋦.\u200D; [C2 P1 V6]; [C2 P1 V6] # 䂹𐋦. +B; xn--0on3543c5981i.; [V6]; [V6] +B; xn--0on3543c5981i.xn--1ug; [C2 V6]; [C2 V6] # 䂹𐋦. +T; \uA9C0\u200C𐹲\u200C。\u0767🄉; [B5 B6 C1 P1 V5 V6]; [B5 B6 P1 V5 V6] # ꧀𐹲.ݧ🄉 +N; \uA9C0\u200C𐹲\u200C。\u0767🄉; [B5 B6 C1 P1 V5 V6]; [B5 B6 C1 P1 V5 V6] # ꧀𐹲.ݧ🄉 +T; \uA9C0\u200C𐹲\u200C。\u07678,; [B3 B5 B6 C1 P1 V5 V6]; [B3 B5 B6 P1 V5 V6] # ꧀𐹲.ݧ8, +N; \uA9C0\u200C𐹲\u200C。\u07678,; [B3 B5 B6 C1 P1 V5 V6]; [B3 B5 B6 C1 P1 V5 V6] # ꧀𐹲.ݧ8, +B; xn--7m9an32q.xn--8,-qle; [B3 B5 B6 P1 V5 V6]; [B3 B5 B6 P1 V5 V6] # ꧀𐹲.ݧ8, +B; xn--0uga8686hdgvd.xn--8,-qle; [B3 B5 B6 C1 P1 V5 V6]; [B3 B5 B6 C1 P1 V5 V6] # ꧀𐹲.ݧ8, +B; xn--7m9an32q.xn--rpb6081w; [B5 B6 V5 V6]; [B5 B6 V5 V6] # ꧀𐹲.ݧ🄉 +B; xn--0uga8686hdgvd.xn--rpb6081w; [B5 B6 C1 V5 V6]; [B5 B6 C1 V5 V6] # ꧀𐹲.ݧ🄉 +B; ︒。Ⴃ≯; [P1 V6]; [P1 V6] +B; ︒。Ⴃ>\u0338; [P1 V6]; [P1 V6] +B; 。。Ⴃ≯; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 。。Ⴃ>\u0338; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 。。ⴃ>\u0338; [P1 V6 A4_2]; [P1 V6 A4_2] +B; 。。ⴃ≯; [P1 V6 A4_2]; [P1 V6 A4_2] +B; ..xn--hdh782b; [V6 A4_2]; [V6 A4_2] +B; ..xn--bnd622g; [V6 A4_2]; [V6 A4_2] +B; ︒。ⴃ>\u0338; [P1 V6]; [P1 V6] +B; ︒。ⴃ≯; [P1 V6]; [P1 V6] +B; xn--y86c.xn--hdh782b; [V6]; [V6] +B; xn--y86c.xn--bnd622g; [V6]; [V6] +T; 𐹮。󠢼\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹮. +N; 𐹮。󠢼\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹮. +T; 𐹮。󠢼\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹮. +N; 𐹮。󠢼\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹮. +B; xn--mo0d.xn--wy46e; [B1 V6]; [B1 V6] +B; xn--mo0d.xn--1ug18431l; [B1 C2 V6]; [B1 C2 V6] # 𐹮. +T; Ⴞ𐹨。︒\u077D\u200DႯ; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 P1 V6] # Ⴞ𐹨.︒ݽႯ +N; Ⴞ𐹨。︒\u077D\u200DႯ; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # Ⴞ𐹨.︒ݽႯ +T; Ⴞ𐹨。。\u077D\u200DႯ; [B2 B3 B5 B6 C2 P1 V6 A4_2]; [B2 B3 B5 B6 P1 V6 A4_2] # Ⴞ𐹨..ݽႯ +N; Ⴞ𐹨。。\u077D\u200DႯ; [B2 B3 B5 B6 C2 P1 V6 A4_2]; [B2 B3 B5 B6 C2 P1 V6 A4_2] # Ⴞ𐹨..ݽႯ +T; ⴞ𐹨。。\u077D\u200Dⴏ; [B2 B3 B5 B6 C2 A4_2]; [B2 B3 B5 B6 A4_2] # ⴞ𐹨..ݽⴏ +N; ⴞ𐹨。。\u077D\u200Dⴏ; [B2 B3 B5 B6 C2 A4_2]; [B2 B3 B5 B6 C2 A4_2] # ⴞ𐹨..ݽⴏ +B; xn--mlju223e..xn--eqb053q; [B2 B3 B5 B6 A4_2]; [B2 B3 B5 B6 A4_2] # ⴞ𐹨..ݽⴏ +B; xn--mlju223e..xn--eqb096jpgj; [B2 B3 B5 B6 C2 A4_2]; [B2 B3 B5 B6 C2 A4_2] # ⴞ𐹨..ݽⴏ +B; xn--2nd0990k..xn--eqb228b; [B2 B3 B5 B6 V6 A4_2]; [B2 B3 B5 B6 V6 A4_2] # Ⴞ𐹨..ݽႯ +B; xn--2nd0990k..xn--eqb228bgzm; [B2 B3 B5 B6 C2 V6 A4_2]; [B2 B3 B5 B6 C2 V6 A4_2] # Ⴞ𐹨..ݽႯ +T; ⴞ𐹨。︒\u077D\u200Dⴏ; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 P1 V6] # ⴞ𐹨.︒ݽⴏ +N; ⴞ𐹨。︒\u077D\u200Dⴏ; [B1 B5 B6 C2 P1 V6]; [B1 B5 B6 C2 P1 V6] # ⴞ𐹨.︒ݽⴏ +B; xn--mlju223e.xn--eqb053qjk7l; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ⴞ𐹨.︒ݽⴏ +B; xn--mlju223e.xn--eqb096jpgj9y7r; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # ⴞ𐹨.︒ݽⴏ +B; xn--2nd0990k.xn--eqb228b583r; [B1 B5 B6 V6]; [B1 B5 B6 V6] # Ⴞ𐹨.︒ݽႯ +B; xn--2nd0990k.xn--eqb228bgzmvp0t; [B1 B5 B6 C2 V6]; [B1 B5 B6 C2 V6] # Ⴞ𐹨.︒ݽႯ +T; \u200CႦ𝟹。-\u20D2-\u07D1; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # Ⴆ3.-⃒-ߑ +N; \u200CႦ𝟹。-\u20D2-\u07D1; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴆ3.-⃒-ߑ +T; \u200CႦ3。-\u20D2-\u07D1; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # Ⴆ3.-⃒-ߑ +N; \u200CႦ3。-\u20D2-\u07D1; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # Ⴆ3.-⃒-ߑ +T; \u200Cⴆ3。-\u20D2-\u07D1; [B1 C1 V3]; [B1 V3] # ⴆ3.-⃒-ߑ +N; \u200Cⴆ3。-\u20D2-\u07D1; [B1 C1 V3]; [B1 C1 V3] # ⴆ3.-⃒-ߑ +B; xn--3-lvs.xn-----vue617w; [B1 V3]; [B1 V3] # ⴆ3.-⃒-ߑ +B; xn--3-rgnv99c.xn-----vue617w; [B1 C1 V3]; [B1 C1 V3] # ⴆ3.-⃒-ߑ +B; xn--3-i0g.xn-----vue617w; [B1 V3 V6]; [B1 V3 V6] # Ⴆ3.-⃒-ߑ +B; xn--3-i0g939i.xn-----vue617w; [B1 C1 V3 V6]; [B1 C1 V3 V6] # Ⴆ3.-⃒-ߑ +T; \u200Cⴆ𝟹。-\u20D2-\u07D1; [B1 C1 V3]; [B1 V3] # ⴆ3.-⃒-ߑ +N; \u200Cⴆ𝟹。-\u20D2-\u07D1; [B1 C1 V3]; [B1 C1 V3] # ⴆ3.-⃒-ߑ +B; 箃Ⴡ-󠁝。≠-🤖; [P1 V6]; [P1 V6] +B; 箃Ⴡ-󠁝。=\u0338-🤖; [P1 V6]; [P1 V6] +B; 箃Ⴡ-󠁝。≠-🤖; [P1 V6]; [P1 V6] +B; 箃Ⴡ-󠁝。=\u0338-🤖; [P1 V6]; [P1 V6] +B; 箃ⴡ-󠁝。=\u0338-🤖; [P1 V6]; [P1 V6] +B; 箃ⴡ-󠁝。≠-🤖; [P1 V6]; [P1 V6] +B; xn----4wsr321ay823p.xn----tfot873s; [V6]; [V6] +B; xn----11g3013fy8x5m.xn----tfot873s; [V6]; [V6] +B; 箃ⴡ-󠁝。=\u0338-🤖; [P1 V6]; [P1 V6] +B; 箃ⴡ-󠁝。≠-🤖; [P1 V6]; [P1 V6] +B; \u07E5.\u06B5; ; xn--dtb.xn--okb # ߥ.Úµ +B; xn--dtb.xn--okb; \u07E5.\u06B5; xn--dtb.xn--okb # ߥ.Úµ +T; \u200C\u200D.𞤿; [B1 C1 C2]; [A4_2] # .𞤿 +N; \u200C\u200D.𞤿; [B1 C1 C2]; [B1 C1 C2] # .𞤿 +T; \u200C\u200D.𞤝; [B1 C1 C2]; [A4_2] # .𞤿 +N; \u200C\u200D.𞤝; [B1 C1 C2]; [B1 C1 C2] # .𞤿 +B; .xn--3e6h; [A4_2]; [A4_2] +B; xn--0ugc.xn--3e6h; [B1 C1 C2]; [B1 C1 C2] # .𞤿 +B; xn--3e6h; 𞤿; xn--3e6h +B; 𞤿; ; xn--3e6h +B; 𞤝; 𞤿; xn--3e6h +T; 🜑𐹧\u0639.ς𑍍蜹; [B1]; [B1] # 🜑𐹧ع.ς𑍍蜹 +N; 🜑𐹧\u0639.ς𑍍蜹; [B1]; [B1] # 🜑𐹧ع.ς𑍍蜹 +B; 🜑𐹧\u0639.Σ𑍍蜹; [B1]; [B1] # 🜑𐹧ع.σ𑍍蜹 +B; 🜑𐹧\u0639.σ𑍍蜹; [B1]; [B1] # 🜑𐹧ع.σ𑍍蜹 +B; xn--4gb3736kk4zf.xn--4xa2248dy27d; [B1]; [B1] # 🜑𐹧ع.σ𑍍蜹 +B; xn--4gb3736kk4zf.xn--3xa4248dy27d; [B1]; [B1] # 🜑𐹧ع.ς𑍍蜹 +B; ò« ã‚¹ô†Ÿ¤\u0669.󚃟; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ス٩. +B; ò« ã‚¹ô†Ÿ¤\u0669.󚃟; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ス٩. +B; xn--iib777sp230oo708a.xn--7824e; [B5 B6 V6]; [B5 B6 V6] # ス٩. +B; 𝪣ò•¡ï¼Ž\u059A\uD850\u06C2; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; 𝪣ò•¡ï¼Ž\u059A\uD850\u06C1\u0654; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; 𝪣ò•¡.\u059A\uD850\u06C2; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; 𝪣ò•¡.\u059A\uD850\u06C1\u0654; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; xn--8c3hu7971a.\u059A\uD850\u06C2; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; xn--8c3hu7971a.\u059A\uD850\u06C1\u0654; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; XN--8C3HU7971A.\u059A\uD850\u06C1\u0654; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; XN--8C3HU7971A.\u059A\uD850\u06C2; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; Xn--8C3hu7971a.\u059A\uD850\u06C2; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +B; Xn--8C3hu7971a.\u059A\uD850\u06C1\u0654; [B1 P1 V5 V6]; [B1 P1 V5 V6 A3] # 𝪣.֚ۂ +T; \u0660òª“µ\u200C。\u0757; [B1 C1 P1 V6]; [B1 P1 V6] # Ù .ݗ +N; \u0660òª“µ\u200C。\u0757; [B1 C1 P1 V6]; [B1 C1 P1 V6] # Ù .ݗ +B; xn--8hb82030l.xn--bpb; [B1 V6]; [B1 V6] # Ù .ݗ +B; xn--8hb852ke991q.xn--bpb; [B1 C1 V6]; [B1 C1 V6] # Ù .ݗ +T; \u103A\u200D\u200C。-\u200C; [C1 V3 V5]; [V3 V5] # ်.- +N; \u103A\u200D\u200C。-\u200C; [C1 V3 V5]; [C1 V3 V5] # ်.- +B; xn--bkd.-; [V3 V5]; [V3 V5] # ်.- +B; xn--bkd412fca.xn----sgn; [C1 V3 V5]; [C1 V3 V5] # ်.- +B; ︒。\u1B44ᡉ; [P1 V5 V6]; [P1 V5 V6] # ︒.᭄ᡉ +B; 。。\u1B44ᡉ; [V5 A4_2]; [V5 A4_2] # ..᭄ᡉ +B; ..xn--87e93m; [V5 A4_2]; [V5 A4_2] # ..᭄ᡉ +B; xn--y86c.xn--87e93m; [V5 V6]; [V5 V6] # ︒.᭄ᡉ +T; \u0758ß。ጫᢊ\u0768𝟐; [B2 B3 B5]; [B2 B3 B5] # ݘß.ጫᢊݨ2 +N; \u0758ß。ጫᢊ\u0768𝟐; [B2 B3 B5]; [B2 B3 B5] # ݘß.ጫᢊݨ2 +T; \u0758ß。ጫᢊ\u07682; [B2 B3 B5]; [B2 B3 B5] # ݘß.ጫᢊݨ2 +N; \u0758ß。ጫᢊ\u07682; [B2 B3 B5]; [B2 B3 B5] # ݘß.ጫᢊݨ2 +B; \u0758SS。ጫᢊ\u07682; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; \u0758ss。ጫᢊ\u07682; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; \u0758Ss。ጫᢊ\u07682; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; xn--ss-gke.xn--2-b5c641gfmf; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; xn--zca724a.xn--2-b5c641gfmf; [B2 B3 B5]; [B2 B3 B5] # ݘß.ጫᢊݨ2 +B; \u0758SS。ጫᢊ\u0768𝟐; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; \u0758ss。ጫᢊ\u0768𝟐; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; \u0758Ss。ጫᢊ\u0768𝟐; [B2 B3 B5]; [B2 B3 B5] # ݘss.ጫᢊݨ2 +B; \u07C3𞶇ᚲ.\u0902\u0353𝟚\u09CD; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ߃ᚲ.ं͓2্ +B; \u07C3𞶇ᚲ.\u0902\u03532\u09CD; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ߃ᚲ.ं͓2্ +B; xn--esb067enh07a.xn--2-lgb874bjxa; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # ߃ᚲ.ं͓2্ +T; -\u1BAB︒\u200D.ñ’¶ˆñ¥¹“; [C2 P1 V3 V6]; [P1 V3 V6] # -᮫︒. +N; -\u1BAB︒\u200D.ñ’¶ˆñ¥¹“; [C2 P1 V3 V6]; [C2 P1 V3 V6] # -᮫︒. +T; -\u1BAB。\u200D.ñ’¶ˆñ¥¹“; [C2 P1 V3 V6]; [P1 V3 V6 A4_2] # -᮫.. +N; -\u1BAB。\u200D.ñ’¶ˆñ¥¹“; [C2 P1 V3 V6]; [C2 P1 V3 V6] # -᮫.. +B; xn----qml..xn--x50zy803a; [V3 V6 A4_2]; [V3 V6 A4_2] # -᮫.. +B; xn----qml.xn--1ug.xn--x50zy803a; [C2 V3 V6]; [C2 V3 V6] # -᮫.. +B; xn----qml1407i.xn--x50zy803a; [V3 V6]; [V3 V6] # -᮫︒. +B; xn----qmlv7tw180a.xn--x50zy803a; [C2 V3 V6]; [C2 V3 V6] # -᮫︒. +B; 󠦮.≯𞀆; [P1 V6]; [P1 V6] +B; 󠦮.>\u0338𞀆; [P1 V6]; [P1 V6] +B; xn--t546e.xn--hdh5166o; [V6]; [V6] +B; -𑄳󠊗𐹩。𞮱; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; xn----p26i72em2894c.xn--zw6h; [B1 V3 V6]; [B1 V3 V6] +B; \u06B9.ᡳ\u115F; [P1 V6]; [P1 V6] # Ú¹.ᡳ +B; \u06B9.ᡳ\u115F; [P1 V6]; [P1 V6] # Ú¹.ᡳ +B; xn--skb.xn--osd737a; [V6]; [V6] # Ú¹.ᡳ +B; 㨛𘱎.︒𝟕\u0D01; [P1 V6]; [P1 V6] # 㨛.︒7ഁ +B; 㨛𘱎.。7\u0D01; [P1 V6 A4_2]; [P1 V6 A4_2] # 㨛..7ഁ +B; xn--mbm8237g..xn--7-7hf; [V6 A4_2]; [V6 A4_2] # 㨛..7ഁ +B; xn--mbm8237g.xn--7-7hf1526p; [V6]; [V6] # 㨛.︒7ഁ +B; \u06DDð»±§-。𞷁\u2064𞤣≮; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤣<\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤣≮; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤣<\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤁<\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤁≮; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; xn----dxc06304e.xn--gdh5020pk5c; [B1 B3 V3 V6]; [B1 B3 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤁<\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +B; \u06DDð»±§-。𞷁\u2064𞤁≮; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # -.𞤣≮ +T; ß\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [P1 V6] # ß꫶ᢥ.⊶ჁႶ +N; ß\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [C1 P1 V6] # ß꫶ᢥ.⊶ჁႶ +T; ß\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [P1 V6] # ß꫶ᢥ.⊶ჁႶ +N; ß\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [C1 P1 V6] # ß꫶ᢥ.⊶ჁႶ +T; ß\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; xn--ss-4epx629f.xn--ifh802b6a # ß꫶ᢥ.⊶ⴡⴖ +N; ß\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; [C1] # ß꫶ᢥ.⊶ⴡⴖ +T; SS\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [P1 V6] # ss꫶ᢥ.⊶ჁႶ +N; SS\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [C1 P1 V6] # ss꫶ᢥ.⊶ჁႶ +T; ss\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; xn--ss-4epx629f.xn--ifh802b6a # ss꫶ᢥ.⊶ⴡⴖ +N; ss\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; [C1] # ss꫶ᢥ.⊶ⴡⴖ +T; Ss\u200C\uAAF6ᢥ.⊶Ⴡⴖ; [C1 P1 V6]; [P1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +N; Ss\u200C\uAAF6ᢥ.⊶Ⴡⴖ; [C1 P1 V6]; [C1 P1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +B; xn--ss-4epx629f.xn--5nd703gyrh; [V6]; [V6] # ss꫶ᢥ.⊶Ⴡⴖ +B; xn--ss-4ep585bkm5p.xn--5nd703gyrh; [C1 V6]; [C1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +B; xn--ss-4epx629f.xn--ifh802b6a; ss\uAAF6ᢥ.⊶ⴡⴖ; xn--ss-4epx629f.xn--ifh802b6a; NV8 # ss꫶ᢥ.⊶ⴡⴖ +B; ss\uAAF6ᢥ.⊶ⴡⴖ; ; xn--ss-4epx629f.xn--ifh802b6a; NV8 # ss꫶ᢥ.⊶ⴡⴖ +B; SS\uAAF6ᢥ.⊶ჁႶ; [P1 V6]; [P1 V6] # ss꫶ᢥ.⊶ჁႶ +B; Ss\uAAF6ᢥ.⊶Ⴡⴖ; [P1 V6]; [P1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +B; xn--ss-4epx629f.xn--undv409k; [V6]; [V6] # ss꫶ᢥ.⊶ჁႶ +B; xn--ss-4ep585bkm5p.xn--ifh802b6a; [C1]; [C1] # ss꫶ᢥ.⊶ⴡⴖ +B; xn--ss-4ep585bkm5p.xn--undv409k; [C1 V6]; [C1 V6] # ss꫶ᢥ.⊶ჁႶ +B; xn--zca682johfi89m.xn--ifh802b6a; [C1]; [C1] # ß꫶ᢥ.⊶ⴡⴖ +B; xn--zca682johfi89m.xn--undv409k; [C1 V6]; [C1 V6] # ß꫶ᢥ.⊶ჁႶ +T; ß\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; xn--ss-4epx629f.xn--ifh802b6a # ß꫶ᢥ.⊶ⴡⴖ +N; ß\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; [C1] # ß꫶ᢥ.⊶ⴡⴖ +T; SS\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [P1 V6] # ss꫶ᢥ.⊶ჁႶ +N; SS\u200C\uAAF6ᢥ.⊶ჁႶ; [C1 P1 V6]; [C1 P1 V6] # ss꫶ᢥ.⊶ჁႶ +T; ss\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; xn--ss-4epx629f.xn--ifh802b6a # ss꫶ᢥ.⊶ⴡⴖ +N; ss\u200C\uAAF6ᢥ.⊶ⴡⴖ; [C1]; [C1] # ss꫶ᢥ.⊶ⴡⴖ +T; Ss\u200C\uAAF6ᢥ.⊶Ⴡⴖ; [C1 P1 V6]; [P1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +N; Ss\u200C\uAAF6ᢥ.⊶Ⴡⴖ; [C1 P1 V6]; [C1 P1 V6] # ss꫶ᢥ.⊶Ⴡⴖ +T; \u200D。ς󠁉; [C2 P1 V6]; [P1 V6 A4_2] # .ς +N; \u200D。ς󠁉; [C2 P1 V6]; [C2 P1 V6] # .ς +T; \u200D。Σ󠁉; [C2 P1 V6]; [P1 V6 A4_2] # .σ +N; \u200D。Σ󠁉; [C2 P1 V6]; [C2 P1 V6] # .σ +T; \u200D。σ󠁉; [C2 P1 V6]; [P1 V6 A4_2] # .σ +N; \u200D。σ󠁉; [C2 P1 V6]; [C2 P1 V6] # .σ +B; .xn--4xa24344p; [V6 A4_2]; [V6 A4_2] +B; xn--1ug.xn--4xa24344p; [C2 V6]; [C2 V6] # .σ +B; xn--1ug.xn--3xa44344p; [C2 V6]; [C2 V6] # .ς +T; 𞵑ß.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ß.ݑ𞤽- +N; 𞵑ß.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ß.ݑ𞤽- +T; 𞵑ß.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ß.ݑ𞤽- +N; 𞵑ß.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ß.ݑ𞤽- +T; 𞵑SS.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ss.ݑ𞤽- +N; 𞵑SS.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ss.ݑ𞤽- +T; 𞵑ss.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ss.ݑ𞤽- +N; 𞵑ss.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ss.ݑ𞤽- +T; 𞵑Ss.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ss.ݑ𞤽- +N; 𞵑Ss.\u0751\u200D𞤽-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ss.ݑ𞤽- +B; xn--ss-2722a.xn----z3c03218a; [B2 B3 V3 V6]; [B2 B3 V3 V6] # ss.ݑ𞤽- +B; xn--ss-2722a.xn----z3c011q9513b; [B2 B3 C2 V3 V6]; [B2 B3 C2 V3 V6] # ss.ݑ𞤽- +B; xn--zca5423w.xn----z3c011q9513b; [B2 B3 C2 V3 V6]; [B2 B3 C2 V3 V6] # ß.ݑ𞤽- +T; 𞵑ss.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ss.ݑ𞤽- +N; 𞵑ss.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ss.ݑ𞤽- +T; 𞵑Ss.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 P1 V3 V6] # ss.ݑ𞤽- +N; 𞵑Ss.\u0751\u200D𞤛-; [B2 B3 C2 P1 V3 V6]; [B2 B3 C2 P1 V3 V6] # ss.ݑ𞤽- +T; 𑘽\u200D𞤧.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +N; 𑘽\u200D𞤧.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +T; 𑘽\u200D𞤧.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +N; 𑘽\u200D𞤧.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +T; 𑘽\u200D𞤅.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +N; 𑘽\u200D𞤅.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +B; xn--qb2ds317a.xn----k26iq1483f; [B1 V3 V5 V6]; [B1 V3 V5 V6] +B; xn--1ugz808gdimf.xn----k26iq1483f; [B1 C2 V3 V5 V6]; [B1 C2 V3 V5 V6] # 𑘽𞤧.𐹧- +T; 𑘽\u200D𞤅.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +N; 𑘽\u200D𞤅.𐹧󡦪-; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # 𑘽𞤧.𐹧- +B; ⒒ò¨˜™ò³³ ð‘“€.-󞡊; [P1 V3 V6]; [P1 V3 V6] +B; 11.ò¨˜™ò³³ ð‘“€.-󞡊; [P1 V3 V6]; [P1 V3 V6] +B; 11.xn--uz1d59632bxujd.xn----x310m; [V3 V6]; [V3 V6] +B; xn--3shy698frsu9dt1me.xn----x310m; [V3 V6]; [V3 V6] +T; -。\u200D; [C2 V3]; [V3] # -. +N; -。\u200D; [C2 V3]; [C2 V3] # -. +T; -。\u200D; [C2 V3]; [V3] # -. +N; -。\u200D; [C2 V3]; [C2 V3] # -. +B; -.; [V3]; [V3] +B; -.xn--1ug; [C2 V3]; [C2 V3] # -. +T; ≮ᡬ.ς¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; ≮ᡬ.ς¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +T; <\u0338ᡬ.ς¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; <\u0338ᡬ.ς¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +T; ≮ᡬ.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; ≮ᡬ.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +T; <\u0338ᡬ.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; <\u0338ᡬ.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +B; <\u0338ᡬ.Σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; ≮ᡬ.Σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; ≮ᡬ.σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; <\u0338ᡬ.σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; xn--88e732c.σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; XN--88E732C.Σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +T; xn--88e732c.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; xn--88e732c.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +T; Xn--88E732c.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +N; Xn--88E732c.ς1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.ς1- +B; Xn--88E732c.σ1-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; <\u0338ᡬ.Σ¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; ≮ᡬ.Σ¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; ≮ᡬ.σ¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; <\u0338ᡬ.σ¹-\uDB09; [P1 V6]; [P1 V6 A3] # ≮ᡬ.σ1- +B; ቬò” ¼ñ—¶ï½¡ð¨¬ðŸ ; [P1 V6]; [P1 V6] +B; ቬò” ¼ñ—¶ã€‚𐨬8; [P1 V6]; [P1 V6] +B; xn--d0d41273c887z.xn--8-ob5i; [V6]; [V6] +B; 𐱲。蔫\u0766; [B5 B6 P1 V6]; [B5 B6 P1 V6] # .蔫ݦ +B; xn--389c.xn--qpb7055d; [B5 B6 V6]; [B5 B6 V6] # .蔫ݦ +B; ò’²§â‚ƒï½¡ê¡šð›‡‘ó „³\u0647; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 3.ꡚ𛇑ه +B; ò’²§3。ꡚ𛇑󠄳\u0647; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 3.ꡚ𛇑ه +B; xn--3-ep59g.xn--jhb5904fcp0h; [B5 B6 V6]; [B5 B6 V6] # 3.ꡚ𛇑ه +T; 蓸\u0642≠.ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ß +N; 蓸\u0642≠.ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ß +T; 蓸\u0642=\u0338.ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ß +N; 蓸\u0642=\u0338.ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ß +B; 蓸\u0642=\u0338.SS; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; 蓸\u0642≠.SS; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; 蓸\u0642≠.ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; 蓸\u0642=\u0338.ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; 蓸\u0642=\u0338.Ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; 蓸\u0642≠.Ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 蓸ق≠.ss +B; xn--ehb015lnt1e.ss; [B5 B6 V6]; [B5 B6 V6] # 蓸ق≠.ss +B; xn--ehb015lnt1e.xn--zca; [B5 B6 V6]; [B5 B6 V6] # 蓸ق≠.ß +T; \u084E\u067A\u0DD3⒊.𐹹𞱩󠃪\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # ࡎٺී⒊.𐹹 +N; \u084E\u067A\u0DD3⒊.𐹹𞱩󠃪\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ࡎٺී⒊.𐹹 +T; \u084E\u067A\u0DD33..𐹹𞱩󠃪\u200C; [B1 C1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ࡎٺී3..𐹹 +N; \u084E\u067A\u0DD33..𐹹𞱩󠃪\u200C; [B1 C1 P1 V6 A4_2]; [B1 C1 P1 V6 A4_2] # ࡎٺී3..𐹹 +B; xn--3-prc71ls9j..xn--xo0dw109an237f; [B1 V6 A4_2]; [B1 V6 A4_2] # ࡎٺී3..𐹹 +B; xn--3-prc71ls9j..xn--0ug3205g7eyf3c96h; [B1 C1 V6 A4_2]; [B1 C1 V6 A4_2] # ࡎٺී3..𐹹 +B; xn--zib94gfziuq1a.xn--xo0dw109an237f; [B1 V6]; [B1 V6] # ࡎٺී⒊.𐹹 +B; xn--zib94gfziuq1a.xn--0ug3205g7eyf3c96h; [B1 C1 V6]; [B1 C1 V6] # ࡎٺී⒊.𐹹 +T; ς\u200D-.Ⴣ𦟙; [C2 P1 V3 V6]; [P1 V3 V6] # ς-.Ⴣ𦟙 +N; ς\u200D-.Ⴣ𦟙; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ς-.Ⴣ𦟙 +T; ς\u200D-.ⴣ𦟙; [C2 V3]; [V3] # ς-.ⴣ𦟙 +N; ς\u200D-.ⴣ𦟙; [C2 V3]; [C2 V3] # ς-.ⴣ𦟙 +T; Σ\u200D-.Ⴣ𦟙; [C2 P1 V3 V6]; [P1 V3 V6] # σ-.Ⴣ𦟙 +N; Σ\u200D-.Ⴣ𦟙; [C2 P1 V3 V6]; [C2 P1 V3 V6] # σ-.Ⴣ𦟙 +T; σ\u200D-.ⴣ𦟙; [C2 V3]; [V3] # σ-.ⴣ𦟙 +N; σ\u200D-.ⴣ𦟙; [C2 V3]; [C2 V3] # σ-.ⴣ𦟙 +B; xn----zmb.xn--rlj2573p; [V3]; [V3] +B; xn----zmb048s.xn--rlj2573p; [C2 V3]; [C2 V3] # σ-.ⴣ𦟙 +B; xn----zmb.xn--7nd64871a; [V3 V6]; [V3 V6] +B; xn----zmb048s.xn--7nd64871a; [C2 V3 V6]; [C2 V3 V6] # σ-.Ⴣ𦟙 +B; xn----xmb348s.xn--rlj2573p; [C2 V3]; [C2 V3] # ς-.ⴣ𦟙 +B; xn----xmb348s.xn--7nd64871a; [C2 V3 V6]; [C2 V3 V6] # ς-.Ⴣ𦟙 +B; ≠。🞳𝟲; [P1 V6]; [P1 V6] +B; =\u0338。🞳𝟲; [P1 V6]; [P1 V6] +B; ≠。🞳6; [P1 V6]; [P1 V6] +B; =\u0338。🞳6; [P1 V6]; [P1 V6] +B; xn--1ch.xn--6-dl4s; [V6]; [V6] +B; 󅬽.蠔; [P1 V6]; [P1 V6] +B; xn--g747d.xn--xl2a; [V6]; [V6] +T; \u08E6\u200D.뼽; [C2 V5]; [V5] # ࣦ.ë¼½ +N; \u08E6\u200D.뼽; [C2 V5]; [C2 V5] # ࣦ.ë¼½ +T; \u08E6\u200D.뼽; [C2 V5]; [V5] # ࣦ.ë¼½ +N; \u08E6\u200D.뼽; [C2 V5]; [C2 V5] # ࣦ.ë¼½ +T; \u08E6\u200D.ë¼½; [C2 V5]; [V5] # ࣦ.ë¼½ +N; \u08E6\u200D.ë¼½; [C2 V5]; [C2 V5] # ࣦ.ë¼½ +T; \u08E6\u200D.뼽; [C2 V5]; [V5] # ࣦ.ë¼½ +N; \u08E6\u200D.뼽; [C2 V5]; [C2 V5] # ࣦ.ë¼½ +B; xn--p0b.xn--e43b; [V5]; [V5] # ࣦ.ë¼½ +B; xn--p0b869i.xn--e43b; [C2 V5]; [C2 V5] # ࣦ.ë¼½ +B; ₇\u0BCDôƒ‚·\u06D2。👖\u0675-𞪑; [B1 P1 V6]; [B1 P1 V6] # 7்ے.👖اٴ- +B; 7\u0BCDôƒ‚·\u06D2。👖\u0627\u0674-𞪑; [B1 P1 V6]; [B1 P1 V6] # 7்ے.👖اٴ- +B; xn--7-rwc839aj3073c.xn----ymc5uv818oghka; [B1 V6]; [B1 V6] # 7்ے.👖اٴ- +B; -。\u077B; [B1 V3]; [B1 V3] # -.Ý» +B; -。\u077B; [B1 V3]; [B1 V3] # -.Ý» +B; -.xn--cqb; [B1 V3]; [B1 V3] # -.Ý» +B; 𑇌𵛓。-⒈ꡏ\u072B; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 𑇌.-⒈ꡏܫ +B; 𑇌𵛓。-1.ꡏ\u072B; [B1 B5 B6 P1 V3 V5 V6]; [B1 B5 B6 P1 V3 V5 V6] # 𑇌.-1.ꡏܫ +B; xn--8d1dg030h.-1.xn--1nb7163f; [B1 B5 B6 V3 V5 V6]; [B1 B5 B6 V3 V5 V6] # 𑇌.-1.ꡏܫ +B; xn--8d1dg030h.xn----u1c466tp10j; [B1 V3 V5 V6]; [B1 V3 V5 V6] # 𑇌.-⒈ꡏܫ +B; 璛\u1734\u06AF.-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # 璛᜴گ.- +B; xn--ikb175frt4e.-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # 璛᜴گ.- +B; 󠆰\u08A1\u0A4D샕.𐹲휁; [B1 B2 B3]; [B1 B2 B3] # ࢡ੍샕.𐹲휁 +B; 󠆰\u08A1\u0A4D샕.𐹲휁; [B1 B2 B3]; [B1 B2 B3] # ࢡ੍샕.𐹲휁 +B; 󠆰\u08A1\u0A4D샕.𐹲휁; [B1 B2 B3]; [B1 B2 B3] # ࢡ੍샕.𐹲휁 +B; 󠆰\u08A1\u0A4D샕.𐹲휁; [B1 B2 B3]; [B1 B2 B3] # ࢡ੍샕.𐹲휁 +B; xn--qyb07fj857a.xn--728bv72h; [B1 B2 B3]; [B1 B2 B3] # ࢡ੍샕.𐹲휁 +B; ñ¨½ï¼Žñ‹¸•; [P1 V6]; [P1 V6] +B; ñ¨½.ñ‹¸•; [P1 V6]; [P1 V6] +B; xn--pr3x.xn--rv7w; [V6]; [V6] +B; \u067D𞥕。𑑂𞤶Ⴍ-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ٽ𞥕.𑑂𞤶Ⴍ- +B; \u067D𞥕。𑑂𞤶Ⴍ-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ٽ𞥕.𑑂𞤶Ⴍ- +B; \u067D𞥕。𑑂𞤶ⴍ-; [B1 V3 V5]; [B1 V3 V5] # ٽ𞥕.𑑂𞤶ⴍ- +B; \u067D𞥕。𑑂𞤔Ⴍ-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ٽ𞥕.𑑂𞤶Ⴍ- +B; \u067D𞥕。𑑂𞤔ⴍ-; [B1 V3 V5]; [B1 V3 V5] # ٽ𞥕.𑑂𞤶ⴍ- +B; xn--2ib0338v.xn----zvs0199fo91g; [B1 V3 V5]; [B1 V3 V5] # ٽ𞥕.𑑂𞤶ⴍ- +B; xn--2ib0338v.xn----w0g2740ro9vg; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ٽ𞥕.𑑂𞤶Ⴍ- +B; \u067D𞥕。𑑂𞤶ⴍ-; [B1 V3 V5]; [B1 V3 V5] # ٽ𞥕.𑑂𞤶ⴍ- +B; \u067D𞥕。𑑂𞤔Ⴍ-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ٽ𞥕.𑑂𞤶Ⴍ- +B; \u067D𞥕。𑑂𞤔ⴍ-; [B1 V3 V5]; [B1 V3 V5] # ٽ𞥕.𑑂𞤶ⴍ- +B; 𐯀𐸉𞧏。ñ¢š§â‚„á‚«ñ‚¹«; [P1 V6]; [P1 V6] +B; 𐯀𐸉𞧏。ñ¢š§4Ⴋñ‚¹«; [P1 V6]; [P1 V6] +B; 𐯀𐸉𞧏。ñ¢š§4ⴋñ‚¹«; [P1 V6]; [P1 V6] +B; xn--039c42bq865a.xn--4-wvs27840bnrzm; [V6]; [V6] +B; xn--039c42bq865a.xn--4-t0g49302fnrzm; [V6]; [V6] +B; 𐯀𐸉𞧏。ñ¢š§â‚„â´‹ñ‚¹«; [P1 V6]; [P1 V6] +B; 4\u06BD︒󠑥.≠; [B1 P1 V6]; [B1 P1 V6] # 4ڽ︒.≠ +B; 4\u06BD︒󠑥.=\u0338; [B1 P1 V6]; [B1 P1 V6] # 4ڽ︒.≠ +B; 4\u06BD。󠑥.≠; [B1 P1 V6]; [B1 P1 V6] # 4Ú½..≠ +B; 4\u06BD。󠑥.=\u0338; [B1 P1 V6]; [B1 P1 V6] # 4Ú½..≠ +B; xn--4-kvc.xn--5136e.xn--1ch; [B1 V6]; [B1 V6] # 4Ú½..≠ +B; xn--4-kvc5601q2h50i.xn--1ch; [B1 V6]; [B1 V6] # 4ڽ︒.≠ +B; 𝟓。\u06D7; [V5]; [V5] # 5.ۗ +B; 5。\u06D7; [V5]; [V5] # 5.ۗ +B; 5.xn--nlb; [V5]; [V5] # 5.ۗ +T; \u200Còº¸©.⾕; [C1 P1 V6]; [P1 V6] # .è°· +N; \u200Còº¸©.⾕; [C1 P1 V6]; [C1 P1 V6] # .è°· +T; \u200Còº¸©.è°·; [C1 P1 V6]; [P1 V6] # .è°· +N; \u200Còº¸©.è°·; [C1 P1 V6]; [C1 P1 V6] # .è°· +B; xn--i183d.xn--6g3a; [V6]; [V6] +B; xn--0ug26167i.xn--6g3a; [C1 V6]; [C1 V6] # .è°· +T; ︒󎰇\u200D.-\u073C\u200C; [C1 C2 P1 V3 V6]; [P1 V3 V6] # ︒.-ܼ +N; ︒󎰇\u200D.-\u073C\u200C; [C1 C2 P1 V3 V6]; [C1 C2 P1 V3 V6] # ︒.-ܼ +T; 。󎰇\u200D.-\u073C\u200C; [C1 C2 P1 V3 V6 A4_2]; [P1 V3 V6 A4_2] # ..-ܼ +N; 。󎰇\u200D.-\u073C\u200C; [C1 C2 P1 V3 V6 A4_2]; [C1 C2 P1 V3 V6 A4_2] # ..-ܼ +B; .xn--hh50e.xn----t2c; [V3 V6 A4_2]; [V3 V6 A4_2] # ..-ܼ +B; .xn--1ug05310k.xn----t2c071q; [C1 C2 V3 V6 A4_2]; [C1 C2 V3 V6 A4_2] # ..-ܼ +B; xn--y86c71305c.xn----t2c; [V3 V6]; [V3 V6] # ︒.-ܼ +B; xn--1ug1658ftw26f.xn----t2c071q; [C1 C2 V3 V6]; [C1 C2 V3 V6] # ︒.-ܼ +B; ≯𞤟。ᡨ; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338𞤟。ᡨ; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338𞥁。ᡨ; [B1 P1 V6]; [B1 P1 V6] +B; ≯𞥁。ᡨ; [B1 P1 V6]; [B1 P1 V6] +B; xn--hdhz520p.xn--48e; [B1 V6]; [B1 V6] +B; \u0F74𫫰𝨄。\u0713𐹦; [B1 V5]; [B1 V5] # ུ𫫰𝨄.ܓ𐹦 +B; xn--ned8985uo92e.xn--dnb6395k; [B1 V5]; [B1 V5] # ུ𫫰𝨄.ܓ𐹦 +B; \u033C\u07DB⁷𝟹。𝟬; [B1 V5]; [B1 V5] # ̼ߛ73.0 +B; \u033C\u07DB73。0; [B1 V5]; [B1 V5] # ̼ߛ73.0 +B; xn--73-9yb648b.0; [B1 V5]; [B1 V5] # ̼ߛ73.0 +T; \u200D.𝟗; [C2]; [A4_2] # .9 +N; \u200D.𝟗; [C2]; [C2] # .9 +T; \u200D.9; [C2]; [A4_2] # .9 +N; \u200D.9; [C2]; [C2] # .9 +B; .9; [A4_2]; [A4_2] +B; xn--1ug.9; [C2]; [C2] # .9 +B; 9; ; +B; \u0779ᡭ𪕈。\u06B6\u08D9; [B2 B3]; [B2 B3] # ݹᡭ𪕈.ڶࣙ +B; xn--9pb497fs270c.xn--pkb80i; [B2 B3]; [B2 B3] # ݹᡭ𪕈.ڶࣙ +B; \u07265\u07E2겙。\u1CF4𐷚; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ܦ5ߢ겙.á³´ +B; \u07265\u07E2겙。\u1CF4𐷚; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ܦ5ߢ겙.á³´ +B; \u07265\u07E2겙。\u1CF4𐷚; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ܦ5ߢ겙.á³´ +B; \u07265\u07E2겙。\u1CF4𐷚; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ܦ5ߢ겙.á³´ +B; xn--5-j1c97c2483c.xn--e7f2093h; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # ܦ5ߢ겙.á³´ +T; Ⴍ𿣍ꡨ\u05AE。Ⴞ\u200C\u200C; [C1 P1 V6]; [P1 V6] # Ⴍꡨ֮.Ⴞ +N; Ⴍ𿣍ꡨ\u05AE。Ⴞ\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # Ⴍꡨ֮.Ⴞ +T; ⴍ𿣍ꡨ\u05AE。ⴞ\u200C\u200C; [C1 P1 V6]; [P1 V6] # ⴍꡨ֮.ⴞ +N; ⴍ𿣍ꡨ\u05AE。ⴞ\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # ⴍꡨ֮.ⴞ +B; xn--5cb172r175fug38a.xn--mlj; [V6]; [V6] # ⴍꡨ֮.ⴞ +B; xn--5cb172r175fug38a.xn--0uga051h; [C1 V6]; [C1 V6] # ⴍꡨ֮.ⴞ +B; xn--5cb347co96jug15a.xn--2nd; [V6]; [V6] # Ⴍꡨ֮.Ⴞ +B; xn--5cb347co96jug15a.xn--2nd059ea; [C1 V6]; [C1 V6] # Ⴍꡨ֮.Ⴞ +B; 𐋰。󑓱; [P1 V6]; [P1 V6] +B; xn--k97c.xn--q031e; [V6]; [V6] +B; 󡎦\u17B4\u0B4D.𐹾; [B1 P1 V6]; [B1 P1 V6] # ୍.𐹾 +B; xn--9ic364dho91z.xn--2o0d; [B1 V6]; [B1 V6] # ୍.𐹾 +B; \u08DFႫ𶿸귤.ò …¼ðŸ¢íœª\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟႫ귤.0휪ૣ +B; \u08DFႫ𶿸귤.ò …¼ðŸ¢á„’ᅱᆹ\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟႫ귤.0휪ૣ +B; \u08DFႫ𶿸귤.ò …¼0휪\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟႫ귤.0휪ૣ +B; \u08DFႫ𶿸귤.ò …¼0휪\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟႫ귤.0휪ૣ +B; \u08DFⴋ𶿸귤.ò …¼0휪\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟⴋ귤.0휪ૣ +B; \u08DFⴋ𶿸귤.ò …¼0휪\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟⴋ귤.0휪ૣ +B; xn--i0b436pkl2g2h42a.xn--0-8le8997mulr5f; [V5 V6]; [V5 V6] # ࣟⴋ귤.0휪ૣ +B; xn--i0b601b6r7l2hs0a.xn--0-8le8997mulr5f; [V5 V6]; [V5 V6] # ࣟႫ귤.0휪ૣ +B; \u08DFⴋ𶿸귤.ò …¼ðŸ¢á„’ᅱᆹ\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟⴋ귤.0휪ૣ +B; \u08DFⴋ𶿸귤.ò …¼ðŸ¢íœª\u0AE3; [P1 V5 V6]; [P1 V5 V6] # ࣟⴋ귤.0휪ૣ +B; \u0784.𞡝\u0601; [P1 V6]; [P1 V6] # ބ.𞡝 +B; \u0784.𞡝\u0601; [P1 V6]; [P1 V6] # ބ.𞡝 +B; xn--lqb.xn--jfb1808v; [V6]; [V6] # ބ.𞡝 +T; \u0ACD₃.8\uA8C4\u200D🃤; [V5]; [V5] # ્3.8꣄🃤 +N; \u0ACD₃.8\uA8C4\u200D🃤; [V5]; [V5] # ્3.8꣄🃤 +T; \u0ACD3.8\uA8C4\u200D🃤; [V5]; [V5] # ્3.8꣄🃤 +N; \u0ACD3.8\uA8C4\u200D🃤; [V5]; [V5] # ્3.8꣄🃤 +B; xn--3-yke.xn--8-sl4et308f; [V5]; [V5] # ્3.8꣄🃤 +B; xn--3-yke.xn--8-ugnv982dbkwm; [V5]; [V5] # ્3.8꣄🃤 +B; ℻⩷𝆆。𞤠󠆁\u180C; [B6]; [B6] +B; FAX⩷𝆆。𞤠󠆁\u180C; [B6]; [B6] +B; fax⩷𝆆。𞥂󠆁\u180C; [B6]; [B6] +B; Fax⩷𝆆。𞤠󠆁\u180C; [B6]; [B6] +B; xn--fax-4c9a1676t.xn--6e6h; [B6]; [B6] +B; ℻⩷𝆆。𞥂󠆁\u180C; [B6]; [B6] +B; FAX⩷𝆆。𞥂󠆁\u180C; [B6]; [B6] +B; fax⩷𝆆。𞤠󠆁\u180C; [B6]; [B6] +B; fax⩷𝆆.𞥂; [B6]; [B6] +B; FAX⩷𝆆.𞤠; [B6]; [B6] +B; Fax⩷𝆆.𞤠; [B6]; [B6] +B; FAX⩷𝆆.𞥂; [B6]; [B6] +B; Fax⩷𝆆.𞥂; [B6]; [B6] +B; ꡕ≠\u105E󮿱。𐵧󠄫\uFFA0; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ꡕ≠ၞ. +B; ꡕ=\u0338\u105E󮿱。𐵧󠄫\uFFA0; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ꡕ≠ၞ. +B; ꡕ≠\u105E󮿱。𐵧󠄫\u1160; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ꡕ≠ၞ. +B; ꡕ=\u0338\u105E󮿱。𐵧󠄫\u1160; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ꡕ≠ၞ. +B; xn--cld333gn31h0158l.xn--psd1510k; [B2 B3 V6]; [B2 B3 V6] # ꡕ≠ၞ. +B; xn--cld333gn31h0158l.xn--cl7c96v; [B2 B3 V6]; [B2 B3 V6] # ꡕ≠ၞ. +T; 鱊。\u200C; [C1]; xn--rt6a. # 鱊. +N; 鱊。\u200C; [C1]; [C1] # 鱊. +B; xn--rt6a.; 鱊.; xn--rt6a. +B; 鱊.; ; xn--rt6a. +B; xn--rt6a.xn--0ug; [C1]; [C1] # 鱊. +B; 8𐹣.𑍨; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; 8𐹣.𑍨; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; xn--8-d26i.xn--0p1d; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; ⏹𐧀.𐫯; [B1]; [B1] +B; ⏹𐧀.𐫯; [B1]; [B1] +B; xn--qoh9161g.xn--1x9c; [B1]; [B1] +T; 𞤺\u07CC4.\u200D; [B1 C2]; xn--4-0bd15808a. # 𞤺ߌ4. +N; 𞤺\u07CC4.\u200D; [B1 C2]; [B1 C2] # 𞤺ߌ4. +T; 𞤺\u07CC4.\u200D; [B1 C2]; xn--4-0bd15808a. # 𞤺ߌ4. +N; 𞤺\u07CC4.\u200D; [B1 C2]; [B1 C2] # 𞤺ߌ4. +T; 𞤘\u07CC4.\u200D; [B1 C2]; xn--4-0bd15808a. # 𞤺ߌ4. +N; 𞤘\u07CC4.\u200D; [B1 C2]; [B1 C2] # 𞤺ߌ4. +B; xn--4-0bd15808a.; 𞤺\u07CC4.; xn--4-0bd15808a. # 𞤺ߌ4. +B; 𞤺\u07CC4.; ; xn--4-0bd15808a. # 𞤺ߌ4. +B; 𞤘\u07CC4.; 𞤺\u07CC4.; xn--4-0bd15808a. # 𞤺ߌ4. +B; xn--4-0bd15808a.xn--1ug; [B1 C2]; [B1 C2] # 𞤺ߌ4. +T; 𞤘\u07CC4.\u200D; [B1 C2]; xn--4-0bd15808a. # 𞤺ߌ4. +N; 𞤘\u07CC4.\u200D; [B1 C2]; [B1 C2] # 𞤺ߌ4. +B; ⒗\u0981\u20EF-.\u08E2•; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ⒗ঁ⃯-.• +B; 16.\u0981\u20EF-.\u08E2•; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # 16.ঁ⃯-.• +B; 16.xn----z0d801p.xn--l0b810j; [B1 V3 V5 V6]; [B1 V3 V5 V6] # 16.ঁ⃯-.• +B; xn----z0d801p6kd.xn--l0b810j; [B1 V3 V6]; [B1 V3 V6] # ⒗ঁ⃯-.• +B; -。䏛; [V3]; [V3] +B; -。䏛; [V3]; [V3] +B; -.xn--xco; [V3]; [V3] +T; \u200Cñ’ƒ ï¼Ž\u200D; [C1 C2 P1 V6]; [P1 V6] # . +N; \u200Cñ’ƒ ï¼Ž\u200D; [C1 C2 P1 V6]; [C1 C2 P1 V6] # . +T; \u200Cñ’ƒ .\u200D; [C1 C2 P1 V6]; [P1 V6] # . +N; \u200Cñ’ƒ .\u200D; [C1 C2 P1 V6]; [C1 C2 P1 V6] # . +B; xn--dj8y.; [V6]; [V6] +B; xn--0ugz7551c.xn--1ug; [C1 C2 V6]; [C1 C2 V6] # . +T; ⒈⓰󥣇。𐹠\u200Dò—·¦á‚µ; [B1 C2 P1 V6]; [B1 P1 V6] # ⒈⓰.𐹠Ⴕ +N; ⒈⓰󥣇。𐹠\u200Dò—·¦á‚µ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⒈⓰.𐹠Ⴕ +T; 1.⓰󥣇。𐹠\u200Dò—·¦á‚µ; [B1 C2 P1 V6]; [B1 P1 V6] # 1.⓰.𐹠Ⴕ +N; 1.⓰󥣇。𐹠\u200Dò—·¦á‚µ; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 1.⓰.𐹠Ⴕ +T; 1.⓰󥣇。𐹠\u200Dò—·¦â´•; [B1 C2 P1 V6]; [B1 P1 V6] # 1.⓰.𐹠ⴕ +N; 1.⓰󥣇。𐹠\u200Dò—·¦â´•; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 1.⓰.𐹠ⴕ +B; 1.xn--svh00804k.xn--dljv223ee5t2d; [B1 V6]; [B1 V6] +B; 1.xn--svh00804k.xn--1ug352csp0psg45e; [B1 C2 V6]; [B1 C2 V6] # 1.⓰.𐹠ⴕ +B; 1.xn--svh00804k.xn--tnd1990ke579c; [B1 V6]; [B1 V6] +B; 1.xn--svh00804k.xn--tnd969erj4psgl3e; [B1 C2 V6]; [B1 C2 V6] # 1.⓰.𐹠Ⴕ +T; ⒈⓰󥣇。𐹠\u200Dò—·¦â´•; [B1 C2 P1 V6]; [B1 P1 V6] # ⒈⓰.𐹠ⴕ +N; ⒈⓰󥣇。𐹠\u200Dò—·¦â´•; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ⒈⓰.𐹠ⴕ +B; xn--tsh0nz9380h.xn--dljv223ee5t2d; [B1 V6]; [B1 V6] +B; xn--tsh0nz9380h.xn--1ug352csp0psg45e; [B1 C2 V6]; [B1 C2 V6] # ⒈⓰.𐹠ⴕ +B; xn--tsh0nz9380h.xn--tnd1990ke579c; [B1 V6]; [B1 V6] +B; xn--tsh0nz9380h.xn--tnd969erj4psgl3e; [B1 C2 V6]; [B1 C2 V6] # ⒈⓰.𐹠Ⴕ +T; 𞠊ᠮ-ß。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ß.᳐効 +N; 𞠊ᠮ-ß。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ß.᳐効 +T; 𞠊ᠮ-ß。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ß.᳐効 +N; 𞠊ᠮ-ß。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ß.᳐効 +B; 𞠊ᠮ-SS。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; 𞠊ᠮ-ss。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; 𞠊ᠮ-Ss。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; xn---ss-21t18904a.xn--jfb197i791bi6x4c; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; xn----qfa310pg973b.xn--jfb197i791bi6x4c; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # 𞠊ᠮ-ß.᳐効 +B; 𞠊ᠮ-SS。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; 𞠊ᠮ-ss。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; 𞠊ᠮ-Ss。\u1CD0効\u0601ð·£­; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # 𞠊ᠮ-ss.᳐効 +B; 𑇀.󠨱; [P1 V5 V6]; [P1 V5 V6] +B; xn--wd1d.xn--k946e; [V5 V6]; [V5 V6] +B; ␒3\uFB88。𝟘𐨿𐹆; [B1 P1 V6]; [B1 P1 V6] # ␒3ڈ.0𐨿 +B; ␒3\u0688。0𐨿𐹆; [B1 P1 V6]; [B1 P1 V6] # ␒3ڈ.0𐨿 +B; xn--3-jsc897t.xn--0-sc5iy3h; [B1 V6]; [B1 V6] # ␒3ڈ.0𐨿 +B; \u076B6\u0A81\u08A6。\u1DE3; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ý«6ઁࢦ.á·£ +B; \u076B6\u0A81\u08A6。\u1DE3; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ý«6ઁࢦ.á·£ +B; xn--6-h5c06gj6c.xn--7eg; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ý«6ઁࢦ.á·£ +T; \u0605-𽤞Ⴂ。ò…¤¶\u200D; [B1 B6 C2 P1 V6]; [B1 P1 V6] # -Ⴂ. +N; \u0605-𽤞Ⴂ。ò…¤¶\u200D; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # -Ⴂ. +T; \u0605-𽤞ⴂ。ò…¤¶\u200D; [B1 B6 C2 P1 V6]; [B1 P1 V6] # -ⴂ. +N; \u0605-𽤞ⴂ。ò…¤¶\u200D; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # -ⴂ. +B; xn----0kc8501a5399e.xn--ss06b; [B1 V6]; [B1 V6] # -ⴂ. +B; xn----0kc8501a5399e.xn--1ugy3204f; [B1 B6 C2 V6]; [B1 B6 C2 V6] # -ⴂ. +B; xn----0kc662fc152h.xn--ss06b; [B1 V6]; [B1 V6] # -Ⴂ. +B; xn----0kc662fc152h.xn--1ugy3204f; [B1 B6 C2 V6]; [B1 B6 C2 V6] # -Ⴂ. +T; ⾆.ꡈ5≯ß; [P1 V6]; [P1 V6] +N; ⾆.ꡈ5≯ß; [P1 V6]; [P1 V6] +T; ⾆.ꡈ5>\u0338ß; [P1 V6]; [P1 V6] +N; ⾆.ꡈ5>\u0338ß; [P1 V6]; [P1 V6] +T; 舌.ꡈ5≯ß; [P1 V6]; [P1 V6] +N; 舌.ꡈ5≯ß; [P1 V6]; [P1 V6] +T; 舌.ꡈ5>\u0338ß; [P1 V6]; [P1 V6] +N; 舌.ꡈ5>\u0338ß; [P1 V6]; [P1 V6] +B; 舌.ꡈ5>\u0338SS; [P1 V6]; [P1 V6] +B; 舌.ꡈ5≯SS; [P1 V6]; [P1 V6] +B; 舌.ꡈ5≯ss; [P1 V6]; [P1 V6] +B; 舌.ꡈ5>\u0338ss; [P1 V6]; [P1 V6] +B; 舌.ꡈ5>\u0338Ss; [P1 V6]; [P1 V6] +B; 舌.ꡈ5≯Ss; [P1 V6]; [P1 V6] +B; xn--tc1a.xn--5ss-3m2a5009e; [V6]; [V6] +B; xn--tc1a.xn--5-qfa988w745i; [V6]; [V6] +B; ⾆.ꡈ5>\u0338SS; [P1 V6]; [P1 V6] +B; ⾆.ꡈ5≯SS; [P1 V6]; [P1 V6] +B; ⾆.ꡈ5≯ss; [P1 V6]; [P1 V6] +B; ⾆.ꡈ5>\u0338ss; [P1 V6]; [P1 V6] +B; ⾆.ꡈ5>\u0338Ss; [P1 V6]; [P1 V6] +B; ⾆.ꡈ5≯Ss; [P1 V6]; [P1 V6] +T; \u0ACD8\u200D.ò¾‚ˆ\u075C; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ્8.ݜ +N; \u0ACD8\u200D.ò¾‚ˆ\u075C; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # ્8.ݜ +T; \u0ACD8\u200D.ò¾‚ˆ\u075C; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ્8.ݜ +N; \u0ACD8\u200D.ò¾‚ˆ\u075C; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # ્8.ݜ +B; xn--8-yke.xn--gpb79046m; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ્8.ݜ +B; xn--8-yke534n.xn--gpb79046m; [B1 B5 B6 C2 V5 V6]; [B1 B5 B6 C2 V5 V6] # ્8.ݜ +B; ò¸·†\u0A70≮ò¹“™ï¼ŽñžŽ§â·ó ¯™\u06B6; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ੰ≮.7Ú¶ +B; ò¸·†\u0A70<\u0338ò¹“™ï¼ŽñžŽ§â·ó ¯™\u06B6; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ੰ≮.7Ú¶ +B; ò¸·†\u0A70≮ò¹“™.ñžŽ§7󠯙\u06B6; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ੰ≮.7Ú¶ +B; ò¸·†\u0A70<\u0338ò¹“™.ñžŽ§7󠯙\u06B6; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ੰ≮.7Ú¶ +B; xn--ycc893jqh38rb6fa.xn--7-5uc53836ixt41c; [B5 B6 V6]; [B5 B6 V6] # ੰ≮.7Ú¶ +T; 𞤪.ς; ; xn--ie6h.xn--4xa +N; 𞤪.ς; ; xn--ie6h.xn--3xa +B; 𞤈.Σ; 𞤪.σ; xn--ie6h.xn--4xa +B; 𞤪.σ; ; xn--ie6h.xn--4xa +B; 𞤈.σ; 𞤪.σ; xn--ie6h.xn--4xa +B; xn--ie6h.xn--4xa; 𞤪.σ; xn--ie6h.xn--4xa +T; 𞤈.ς; 𞤪.ς; xn--ie6h.xn--4xa +N; 𞤈.ς; 𞤪.ς; xn--ie6h.xn--3xa +B; xn--ie6h.xn--3xa; 𞤪.ς; xn--ie6h.xn--3xa +B; 𞤪.Σ; 𞤪.σ; xn--ie6h.xn--4xa +T; \u200CႺ。ς; [C1 P1 V6]; [P1 V6] # Ⴚ.ς +N; \u200CႺ。ς; [C1 P1 V6]; [C1 P1 V6] # Ⴚ.ς +T; \u200CႺ。ς; [C1 P1 V6]; [P1 V6] # Ⴚ.ς +N; \u200CႺ。ς; [C1 P1 V6]; [C1 P1 V6] # Ⴚ.ς +T; \u200Cⴚ。ς; [C1]; xn--ilj.xn--4xa # ⴚ.ς +N; \u200Cⴚ。ς; [C1]; [C1] # ⴚ.ς +T; \u200CႺ。Σ; [C1 P1 V6]; [P1 V6] # Ⴚ.σ +N; \u200CႺ。Σ; [C1 P1 V6]; [C1 P1 V6] # Ⴚ.σ +T; \u200Cⴚ。σ; [C1]; xn--ilj.xn--4xa # ⴚ.σ +N; \u200Cⴚ。σ; [C1]; [C1] # ⴚ.σ +B; xn--ilj.xn--4xa; ⴚ.σ; xn--ilj.xn--4xa +B; ⴚ.σ; ; xn--ilj.xn--4xa +B; Ⴚ.Σ; [P1 V6]; [P1 V6] +T; ⴚ.ς; ; xn--ilj.xn--4xa +N; ⴚ.ς; ; xn--ilj.xn--3xa +T; Ⴚ.ς; [P1 V6]; [P1 V6] +N; Ⴚ.ς; [P1 V6]; [P1 V6] +B; xn--ynd.xn--4xa; [V6]; [V6] +B; xn--ynd.xn--3xa; [V6]; [V6] +B; xn--ilj.xn--3xa; ⴚ.ς; xn--ilj.xn--3xa +B; Ⴚ.σ; [P1 V6]; [P1 V6] +B; xn--0ug262c.xn--4xa; [C1]; [C1] # ⴚ.σ +B; xn--ynd759e.xn--4xa; [C1 V6]; [C1 V6] # Ⴚ.σ +B; xn--0ug262c.xn--3xa; [C1]; [C1] # ⴚ.ς +B; xn--ynd759e.xn--3xa; [C1 V6]; [C1 V6] # Ⴚ.ς +T; \u200Cⴚ。ς; [C1]; xn--ilj.xn--4xa # ⴚ.ς +N; \u200Cⴚ。ς; [C1]; [C1] # ⴚ.ς +T; \u200CႺ。Σ; [C1 P1 V6]; [P1 V6] # Ⴚ.σ +N; \u200CႺ。Σ; [C1 P1 V6]; [C1 P1 V6] # Ⴚ.σ +T; \u200Cⴚ。σ; [C1]; xn--ilj.xn--4xa # ⴚ.σ +N; \u200Cⴚ。σ; [C1]; [C1] # ⴚ.σ +B; 𞤃.𐹦; [B1]; [B1] +B; 𞤃.𐹦; [B1]; [B1] +B; 𞤥.𐹦; [B1]; [B1] +B; xn--de6h.xn--eo0d; [B1]; [B1] +B; 𞤥.𐹦; [B1]; [B1] +T; \u200D⾕。\u200C\u0310\uA953ꡎ; [C1 C2]; [V5] # è°·.꥓̐ꡎ +N; \u200D⾕。\u200C\u0310\uA953ꡎ; [C1 C2]; [C1 C2] # è°·.꥓̐ꡎ +T; \u200D⾕。\u200C\uA953\u0310ꡎ; [C1 C2]; [V5] # è°·.꥓̐ꡎ +N; \u200D⾕。\u200C\uA953\u0310ꡎ; [C1 C2]; [C1 C2] # è°·.꥓̐ꡎ +T; \u200D谷。\u200C\uA953\u0310ꡎ; [C1 C2]; [V5] # è°·.꥓̐ꡎ +N; \u200D谷。\u200C\uA953\u0310ꡎ; [C1 C2]; [C1 C2] # è°·.꥓̐ꡎ +B; xn--6g3a.xn--0sa8175flwa; [V5]; [V5] # è°·.꥓̐ꡎ +B; xn--1ug0273b.xn--0sa359l6n7g13a; [C1 C2]; [C1 C2] # è°·.꥓̐ꡎ +T; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤐\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +B; xn----guc3592k.xn--qe6h; [B2 B3]; [B2 B3] # Úª-뉔.𞤲 +B; xn----guc3592k.xn--0ug7611p; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3] # Úª-뉔.𞤲 +N; \u06AA-뉔.𞤲\u200C; [B2 B3 C1]; [B2 B3 C1] # Úª-뉔.𞤲 +T; ñ”²µï¼•ᦛς.\uA8C4\u077B\u1CD2\u0738; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +N; ñ”²µï¼•ᦛς.\uA8C4\u077B\u1CD2\u0738; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +T; ñ”²µï¼•ᦛς.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +N; ñ”²µï¼•ᦛς.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +T; ñ”²µ5ᦛς.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +N; ñ”²µ5ᦛς.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +B; ñ”²µ5ᦛΣ.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; ñ”²µ5ᦛσ.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; xn--5-0mb988ng603j.xn--fob7kk44dl41k; [B1 V5 V6]; [B1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; xn--5-ymb298ng603j.xn--fob7kk44dl41k; [B1 V5 V6]; [B1 V5 V6] # 5ᦛς.꣄ݻܸ᳒ +B; ñ”²µï¼•ᦛΣ.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; ñ”²µï¼•ᦛσ.\uA8C4\u077B\u0738\u1CD2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; ñ”²µï¼•ᦛΣ.\uA8C4\u077B\u1CD2\u0738; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; ñ”²µï¼•ᦛσ.\uA8C4\u077B\u1CD2\u0738; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 5ᦛσ.꣄ݻܸ᳒ +B; 淽。ᠾ; æ·½.á ¾; xn--34w.xn--x7e +B; xn--34w.xn--x7e; æ·½.á ¾; xn--34w.xn--x7e +B; æ·½.á ¾; ; xn--34w.xn--x7e +B; 𐹴𑘷。-; [B1 V3]; [B1 V3] +B; xn--so0do6k.-; [B1 V3]; [B1 V3] +B; ò¬¨©á‚³â“。𑄨; [P1 V5 V6]; [P1 V5 V6] +B; ò¬¨©á‚³â“。𑄨; [P1 V5 V6]; [P1 V5 V6] +B; ò¬¨©â´“❓。𑄨; [P1 V5 V6]; [P1 V5 V6] +B; xn--8di78qvw32y.xn--k80d; [V5 V6]; [V5 V6] +B; xn--rnd896i0j14q.xn--k80d; [V5 V6]; [V5 V6] +B; ò¬¨©â´“❓。𑄨; [P1 V5 V6]; [P1 V5 V6] +T; \u200C𐹡𞤌Ⴇ。ßႣ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ßႣ +N; \u200C𐹡𞤌Ⴇ。ßႣ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ßႣ +T; \u200C𐹡𞤌Ⴇ。ßႣ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ßႣ +N; \u200C𐹡𞤌Ⴇ。ßႣ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ßႣ +T; \u200C𐹡𞤮ⴇ。ßⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ßⴃ +N; \u200C𐹡𞤮ⴇ。ßⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ßⴃ +T; \u200C𐹡𞤌Ⴇ。SSႣ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ssႣ +N; \u200C𐹡𞤌Ⴇ。SSႣ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ssႣ +T; \u200C𐹡𞤮ⴇ。ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤮ⴇ。ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +T; \u200C𐹡𞤌ⴇ。Ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤌ⴇ。Ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +B; xn--ykj9323eegwf.xn--ss-151a; [B1]; [B1] +B; xn--0ug332c3q0pr56g.xn--ss-151a; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +B; xn--fnd1201kegrf.xn--ss-fek; [B1 V6]; [B1 V6] +B; xn--fnd599eyj4pr50g.xn--ss-fek; [B1 C1 V6]; [B1 C1 V6] # 𐹡𞤮Ⴇ.ssႣ +B; xn--0ug332c3q0pr56g.xn--zca417t; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ßⴃ +B; xn--fnd599eyj4pr50g.xn--zca681f; [B1 C1 V6]; [B1 C1 V6] # 𐹡𞤮Ⴇ.ßႣ +T; \u200C𐹡𞤮ⴇ。ßⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ßⴃ +N; \u200C𐹡𞤮ⴇ。ßⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ßⴃ +T; \u200C𐹡𞤌Ⴇ。SSႣ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ssႣ +N; \u200C𐹡𞤌Ⴇ。SSႣ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ssႣ +T; \u200C𐹡𞤮ⴇ。ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤮ⴇ。ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +T; \u200C𐹡𞤌ⴇ。Ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤌ⴇ。Ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +T; \u200C𐹡𞤌ⴇ。ßⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ßⴃ +N; \u200C𐹡𞤌ⴇ。ßⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ßⴃ +T; \u200C𐹡𞤌ⴇ。ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤌ⴇ。ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +T; \u200C𐹡𞤌Ⴇ。Ssⴃ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ssⴃ +N; \u200C𐹡𞤌Ⴇ。Ssⴃ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ssⴃ +B; xn--fnd1201kegrf.xn--ss-151a; [B1 V6]; [B1 V6] +B; xn--fnd599eyj4pr50g.xn--ss-151a; [B1 C1 V6]; [B1 C1 V6] # 𐹡𞤮Ⴇ.ssⴃ +T; \u200C𐹡𞤌ⴇ。ßⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ßⴃ +N; \u200C𐹡𞤌ⴇ。ßⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ßⴃ +T; \u200C𐹡𞤌ⴇ。ssⴃ; [B1 C1]; [B1] # 𐹡𞤮ⴇ.ssⴃ +N; \u200C𐹡𞤌ⴇ。ssⴃ; [B1 C1]; [B1 C1] # 𐹡𞤮ⴇ.ssⴃ +T; \u200C𐹡𞤌Ⴇ。Ssⴃ; [B1 C1 P1 V6]; [B1 P1 V6] # 𐹡𞤮Ⴇ.ssⴃ +N; \u200C𐹡𞤌Ⴇ。Ssⴃ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹡𞤮Ⴇ.ssⴃ +B; \u17FF。𞬳; [P1 V6]; [P1 V6] # . +B; \u17FF。𞬳; [P1 V6]; [P1 V6] # . +B; xn--45e.xn--et6h; [V6]; [V6] # . +T; \u0652\u200D。\u0CCD𑚳; [C2 V5]; [V5] # ْ.್𑚳 +N; \u0652\u200D。\u0CCD𑚳; [C2 V5]; [C2 V5] # ْ.್𑚳 +T; \u0652\u200D。\u0CCD𑚳; [C2 V5]; [V5] # ْ.್𑚳 +N; \u0652\u200D。\u0CCD𑚳; [C2 V5]; [C2 V5] # ْ.್𑚳 +B; xn--uhb.xn--8tc4527k; [V5]; [V5] # ْ.್𑚳 +B; xn--uhb882k.xn--8tc4527k; [C2 V5]; [C2 V5] # ْ.್𑚳 +B; -≠ᠻ.\u076D𞥃≮󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -=\u0338ᠻ.\u076D𞥃<\u0338󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -≠ᠻ.\u076D𞥃≮󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -=\u0338á ».\u076D𞥃<\u0338󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -=\u0338á ».\u076D𞤡<\u0338󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -≠ᠻ.\u076D𞤡≮󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; xn----g6j886c.xn--xpb049kk353abj99f; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -=\u0338ᠻ.\u076D𞤡<\u0338󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; -≠ᠻ.\u076D𞤡≮󟷺; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # -≠ᠻ.ݭ𞥃≮ +B; 󠰆≯\u07B5𐻪.òŠ¥•≮𑁆\u084C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ≯.≮𑁆ࡌ +B; 󠰆>\u0338\u07B5𐻪.òŠ¥•<\u0338𑁆\u084C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ≯.≮𑁆ࡌ +B; 󠰆≯\u07B5𐻪.òŠ¥•≮𑁆\u084C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ≯.≮𑁆ࡌ +B; 󠰆>\u0338\u07B5𐻪.òŠ¥•<\u0338𑁆\u084C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ≯.≮𑁆ࡌ +B; xn--zrb797kdm1oes34i.xn--bwb394k8k2o25n6d; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ≯.≮𑁆ࡌ +B; ≠󦋂.\u0600\u0BCD-\u06B9; [B1 P1 V6]; [B1 P1 V6] # ≠.்-Ú¹ +B; =\u0338󦋂.\u0600\u0BCD-\u06B9; [B1 P1 V6]; [B1 P1 V6] # ≠.்-Ú¹ +B; xn--1ch22084l.xn----qkc07co6n; [B1 V6]; [B1 V6] # ≠.்-Ú¹ +B; \u17DD󠁣≠。𐹼𐋤; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ៝≠.𐹼𐋤 +B; \u17DD󠁣=\u0338。𐹼𐋤; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ៝≠.𐹼𐋤 +B; \u17DD󠁣≠。𐹼𐋤; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ៝≠.𐹼𐋤 +B; \u17DD󠁣=\u0338。𐹼𐋤; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ៝≠.𐹼𐋤 +B; xn--54e694cn389z.xn--787ct8r; [B1 V5 V6]; [B1 V5 V6] # ៝≠.𐹼𐋤 +T; ß𰀻ñ†¬—。𝩨🕮ß; [P1 V5 V6]; [P1 V5 V6] +N; ß𰀻ñ†¬—。𝩨🕮ß; [P1 V5 V6]; [P1 V5 V6] +T; ß𰀻ñ†¬—。𝩨🕮ß; [P1 V5 V6]; [P1 V5 V6] +N; ß𰀻ñ†¬—。𝩨🕮ß; [P1 V5 V6]; [P1 V5 V6] +B; SS𰀻ñ†¬—。𝩨🕮SS; [P1 V5 V6]; [P1 V5 V6] +B; ss𰀻ñ†¬—。𝩨🕮ss; [P1 V5 V6]; [P1 V5 V6] +B; Ss𰀻ñ†¬—。𝩨🕮Ss; [P1 V5 V6]; [P1 V5 V6] +B; xn--ss-jl59biy67d.xn--ss-4d11aw87d; [V5 V6]; [V5 V6] +B; xn--zca20040bgrkh.xn--zca3653v86qa; [V5 V6]; [V5 V6] +B; SS𰀻ñ†¬—。𝩨🕮SS; [P1 V5 V6]; [P1 V5 V6] +B; ss𰀻ñ†¬—。𝩨🕮ss; [P1 V5 V6]; [P1 V5 V6] +B; Ss𰀻ñ†¬—。𝩨🕮Ss; [P1 V5 V6]; [P1 V5 V6] +T; \u200D。\u200C; [C1 C2]; [A4_2] # . +N; \u200D。\u200C; [C1 C2]; [C1 C2] # . +B; xn--1ug.xn--0ug; [C1 C2]; [C1 C2] # . +T; \u0483𐭞\u200D.\u17B9𞯌òŸ©š; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ҃𐭞.ឹ +N; \u0483𐭞\u200D.\u17B9𞯌òŸ©š; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ҃𐭞.ឹ +B; xn--m3a6965k.xn--43e8670vmd79b; [B1 V5 V6]; [B1 V5 V6] # ҃𐭞.ឹ +B; xn--m3a412lrr0o.xn--43e8670vmd79b; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ҃𐭞.ឹ +T; \u200C𐠨\u200C临。ꡢò„·žâ¶ð¹£; [B1 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # 𐠨临.ꡢⶏ𐹣 +N; \u200C𐠨\u200C临。ꡢò„·žâ¶ð¹£; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # 𐠨临.ꡢⶏ𐹣 +B; xn--miq9646b.xn--uojv340bk71c99u9f; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] +B; xn--0uga2656aop9k.xn--uojv340bk71c99u9f; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # 𐠨临.ꡢⶏ𐹣 +B; 󠑘.󠄮; [P1 V6]; [P1 V6] +B; 󠑘.󠄮; [P1 V6]; [P1 V6] +B; xn--s136e.; [V6]; [V6] +B; 𐫄\u0D4D.\uAAF6; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐫄്.ê«¶ +B; 𐫄\u0D4D.\uAAF6; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐫄്.ê«¶ +B; xn--wxc7880k.xn--2v9a; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐫄്.ê«¶ +B; \uA9B7󝵙멹。⒛󠨇; [P1 V5 V6]; [P1 V5 V6] # ꦷ멹.⒛ +B; \uA9B7󝵙멹。⒛󠨇; [P1 V5 V6]; [P1 V5 V6] # ꦷ멹.⒛ +B; \uA9B7󝵙멹。20.󠨇; [P1 V5 V6]; [P1 V5 V6] # ꦷ멹.20. +B; \uA9B7󝵙멹。20.󠨇; [P1 V5 V6]; [P1 V5 V6] # ꦷ멹.20. +B; xn--ym9av13acp85w.20.xn--d846e; [V5 V6]; [V5 V6] # ꦷ멹.20. +B; xn--ym9av13acp85w.xn--dth22121k; [V5 V6]; [V5 V6] # ꦷ멹.⒛ +B; Ⴅ󲬹릖󠶚.\u0777𐹳⒊; [B4 B6 P1 V6]; [B4 B6 P1 V6] # Ⴅ릖.ݷ𐹳⒊ +B; Ⴅ󲬹릖󠶚.\u0777𐹳⒊; [B4 B6 P1 V6]; [B4 B6 P1 V6] # Ⴅ릖.ݷ𐹳⒊ +B; Ⴅ󲬹릖󠶚.\u0777𐹳3.; [B4 B6 P1 V6]; [B4 B6 P1 V6] # Ⴅ릖.ݷ𐹳3. +B; Ⴅ󲬹릖󠶚.\u0777𐹳3.; [B4 B6 P1 V6]; [B4 B6 P1 V6] # Ⴅ릖.ݷ𐹳3. +B; ⴅ󲬹릖󠶚.\u0777𐹳3.; [B4 B6 P1 V6]; [B4 B6 P1 V6] # ⴅ릖.ݷ𐹳3. +B; ⴅ󲬹릖󠶚.\u0777𐹳3.; [B4 B6 P1 V6]; [B4 B6 P1 V6] # ⴅ릖.ݷ𐹳3. +B; xn--wkj8016bne45io02g.xn--3-55c6803r.; [B4 B6 V6]; [B4 B6 V6] # ⴅ릖.ݷ𐹳3. +B; xn--dnd2167fnet0io02g.xn--3-55c6803r.; [B4 B6 V6]; [B4 B6 V6] # Ⴅ릖.ݷ𐹳3. +B; ⴅ󲬹릖󠶚.\u0777𐹳⒊; [B4 B6 P1 V6]; [B4 B6 P1 V6] # ⴅ릖.ݷ𐹳⒊ +B; ⴅ󲬹릖󠶚.\u0777𐹳⒊; [B4 B6 P1 V6]; [B4 B6 P1 V6] # ⴅ릖.ݷ𐹳⒊ +B; xn--wkj8016bne45io02g.xn--7pb000mwm4n; [B4 B6 V6]; [B4 B6 V6] # ⴅ릖.ݷ𐹳⒊ +B; xn--dnd2167fnet0io02g.xn--7pb000mwm4n; [B4 B6 V6]; [B4 B6 V6] # Ⴅ릖.ݷ𐹳⒊ +T; \u200C。︒; [C1 P1 V6]; [P1 V6 A4_2] # .︒ +N; \u200C。︒; [C1 P1 V6]; [C1 P1 V6] # .︒ +T; \u200C。。; [C1 A4_2]; [A4_2] # .. +N; \u200C。。; [C1 A4_2]; [C1 A4_2] # .. +B; ..; [A4_2]; [A4_2] +B; xn--0ug..; [C1 A4_2]; [C1 A4_2] # .. +B; .xn--y86c; [V6 A4_2]; [V6 A4_2] +B; xn--0ug.xn--y86c; [C1 V6]; [C1 V6] # .︒ +B; ≯\u076D.₄; [B1 P1 V6]; [B1 P1 V6] # ≯ݭ.4 +B; >\u0338\u076D.₄; [B1 P1 V6]; [B1 P1 V6] # ≯ݭ.4 +B; ≯\u076D.4; [B1 P1 V6]; [B1 P1 V6] # ≯ݭ.4 +B; >\u0338\u076D.4; [B1 P1 V6]; [B1 P1 V6] # ≯ݭ.4 +B; xn--xpb149k.4; [B1 V6]; [B1 V6] # ≯ݭ.4 +T; ᡲ-𝟹.ß-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ß-- +N; ᡲ-𝟹.ß-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ß-- +T; ᡲ-3.ß-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ß-- +N; ᡲ-3.ß-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ß-- +T; ᡲ-3.SS-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-3.SS-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +T; ᡲ-3.ss-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-3.ss-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +T; ᡲ-3.Ss-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-3.Ss-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +B; xn---3-p9o.ss--; [V2 V3]; [V2 V3] +B; xn---3-p9o.xn--ss---276a; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +B; xn---3-p9o.xn-----fia9303a; [C1 V3]; [C1 V3] # ᡲ-3.ß-- +T; ᡲ-𝟹.SS-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-𝟹.SS-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +T; ᡲ-𝟹.ss-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-𝟹.ss-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +T; ᡲ-𝟹.Ss-\u200C-; [C1 V3]; [V2 V3] # ᡲ-3.ss-- +N; ᡲ-𝟹.Ss-\u200C-; [C1 V3]; [C1 V3] # ᡲ-3.ss-- +B; \uFD08𝟦\u0647󎊯。Ӏ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ضي4ه.Ӏ +B; \u0636\u064A4\u0647󎊯。Ӏ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ضي4ه.Ӏ +B; \u0636\u064A4\u0647󎊯。ӏ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ضي4ه.ӏ +B; xn--4-tnc6ck183523b.xn--s5a; [B2 B3 V6]; [B2 B3 V6] # ضي4ه.ӏ +B; xn--4-tnc6ck183523b.xn--d5a; [B2 B3 V6]; [B2 B3 V6] # ضي4ه.Ӏ +B; \uFD08𝟦\u0647󎊯。ӏ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # ضي4ه.ӏ +B; -.\u0602\u0622𑆾🐹; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.آ𑆾🐹 +B; -.\u0602\u0627\u0653𑆾🐹; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.آ𑆾🐹 +B; -.xn--kfb8dy983hgl7g; [B1 V3 V6]; [B1 V3 V6] # -.آ𑆾🐹 +B; 󙶜ᢘ。\u1A7F⺢; [P1 V5 V6]; [P1 V5 V6] # ᢘ.᩿⺢ +B; xn--ibf35138o.xn--fpfz94g; [V5 V6]; [V5 V6] # ᢘ.᩿⺢ +B; ≠ႷᠤႫ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; =\u0338ႷᠤႫ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; ≠ႷᠤႫ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; =\u0338ႷᠤႫ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; =\u0338ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; ≠ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; ≠Ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; =\u0338Ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; xn--vnd619as6ig6k.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; XN--VND619AS6IG6K.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; Xn--Vnd619as6ig6k.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; xn--66e353ce0ilb.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; XN--66E353CE0ILB.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; Xn--66E353ce0ilb.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; xn--jndx718cnnl.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; XN--JNDX718CNNL.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; Xn--Jndx718cnnl.\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ႷᠤႫ.͌س觴 +B; =\u0338ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; ≠ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠ⴗᠤⴋ.͌س觴 +B; ≠Ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; =\u0338Ⴗᠤⴋ。\uD907\u034C\u0633è§´; [B1 B5 P1 V6]; [B1 B5 P1 V6 A3] # ≠Ⴗᠤⴋ.͌س觴 +B; \u0667.𐥨; [B1 P1 V6]; [B1 P1 V6] # Ù§. +B; xn--gib.xn--vm9c; [B1 V6]; [B1 V6] # Ù§. +T; \uA9C0𝟯。\u200Dñ¼‘¥ð¹ª\u1BF3; [B1 C2 P1 V5 V6]; [B5 P1 V5 V6] # ꧀3.𐹪᯳ +N; \uA9C0𝟯。\u200Dñ¼‘¥ð¹ª\u1BF3; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ꧀3.𐹪᯳ +T; \uA9C03。\u200Dñ¼‘¥ð¹ª\u1BF3; [B1 C2 P1 V5 V6]; [B5 P1 V5 V6] # ꧀3.𐹪᯳ +N; \uA9C03。\u200Dñ¼‘¥ð¹ª\u1BF3; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ꧀3.𐹪᯳ +B; xn--3-5z4e.xn--1zfz754hncv8b; [B5 V5 V6]; [B5 V5 V6] # ꧀3.𐹪᯳ +B; xn--3-5z4e.xn--1zf96ony8ygd68c; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ꧀3.𐹪᯳ +B; ò£•„4ñ –½.≯\u0664𑀾󠸌; [B1 P1 V6]; [B1 P1 V6] # 4.≯٤𑀾 +B; ò£•„4ñ –½.>\u0338\u0664𑀾󠸌; [B1 P1 V6]; [B1 P1 V6] # 4.≯٤𑀾 +B; xn--4-fg85dl688i.xn--dib174li86ntdy0i; [B1 V6]; [B1 V6] # 4.≯٤𑀾 +B; ò—†§ðŸ¯ã€‚â’ˆ\u1A76𝟚ò ˜Œ; [P1 V6]; [P1 V6] # 3.⒈᩶2 +B; ò—†§3。1.\u1A762ò ˜Œ; [P1 V5 V6]; [P1 V5 V6] # 3.1.á©¶2 +B; xn--3-rj42h.1.xn--2-13k96240l; [V5 V6]; [V5 V6] # 3.1.á©¶2 +B; xn--3-rj42h.xn--2-13k746cq465x; [V6]; [V6] # 3.⒈᩶2 +T; \u200D₅⒈。≯𝟴\u200D; [C2 P1 V6]; [P1 V6] # 5⒈.≯8 +N; \u200D₅⒈。≯𝟴\u200D; [C2 P1 V6]; [C2 P1 V6] # 5⒈.≯8 +T; \u200D₅⒈。>\u0338𝟴\u200D; [C2 P1 V6]; [P1 V6] # 5⒈.≯8 +N; \u200D₅⒈。>\u0338𝟴\u200D; [C2 P1 V6]; [C2 P1 V6] # 5⒈.≯8 +T; \u200D51.。≯8\u200D; [C2 P1 V6 A4_2]; [P1 V6 A4_2] # 51..≯8 +N; \u200D51.。≯8\u200D; [C2 P1 V6 A4_2]; [C2 P1 V6 A4_2] # 51..≯8 +T; \u200D51.。>\u03388\u200D; [C2 P1 V6 A4_2]; [P1 V6 A4_2] # 51..≯8 +N; \u200D51.。>\u03388\u200D; [C2 P1 V6 A4_2]; [C2 P1 V6 A4_2] # 51..≯8 +B; 51..xn--8-ogo; [V6 A4_2]; [V6 A4_2] +B; xn--51-l1t..xn--8-ugn00i; [C2 V6 A4_2]; [C2 V6 A4_2] # 51..≯8 +B; xn--5-ecp.xn--8-ogo; [V6]; [V6] +B; xn--5-tgnz5r.xn--8-ugn00i; [C2 V6]; [C2 V6] # 5⒈.≯8 +T; ê¡°\u0697\u1086.òª˜™\u072F≠\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ꡰڗႆ.ܯ≠ +N; ê¡°\u0697\u1086.òª˜™\u072F≠\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ꡰڗႆ.ܯ≠ +T; ê¡°\u0697\u1086.òª˜™\u072F=\u0338\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ꡰڗႆ.ܯ≠ +N; ê¡°\u0697\u1086.òª˜™\u072F=\u0338\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ꡰڗႆ.ܯ≠ +T; ê¡°\u0697\u1086.òª˜™\u072F≠\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ꡰڗႆ.ܯ≠ +N; ê¡°\u0697\u1086.òª˜™\u072F≠\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ꡰڗႆ.ܯ≠ +T; ê¡°\u0697\u1086.òª˜™\u072F=\u0338\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ꡰڗႆ.ܯ≠ +N; ê¡°\u0697\u1086.òª˜™\u072F=\u0338\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ꡰڗႆ.ܯ≠ +B; xn--tjb002cn51k.xn--5nb630lbj91q; [B5 B6 V6]; [B5 B6 V6] # ꡰڗႆ.ܯ≠ +B; xn--tjb002cn51k.xn--5nb448jcubcz547b; [B5 B6 C1 V6]; [B5 B6 C1 V6] # ꡰڗႆ.ܯ≠ +B; 𑄱。òªŒ¿ð¹µ; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] +B; 𑄱。òªŒ¿ð¹µ; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] +B; xn--t80d.xn--to0d14792b; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] +B; 𝟥\u0600。\u073D; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 3.ܽ +B; 3\u0600。\u073D; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 3.ܽ +B; xn--3-rkc.xn--kob; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # 3.ܽ +B; \u0637𐹣\u0666.\u076D긷; [B2 B3]; [B2 B3] # ط𐹣٦.ݭ긷 +B; \u0637𐹣\u0666.\u076D긷; [B2 B3]; [B2 B3] # ط𐹣٦.ݭ긷 +B; xn--2gb8gu829f.xn--xpb0156f; [B2 B3]; [B2 B3] # ط𐹣٦.ݭ긷 +B; ︒Ↄ\u2DE7ò¾€ƒï¼Žá‚·ð£ž; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ︒Ↄⷧ.Ⴗ +B; 。Ↄ\u2DE7ò¾€ƒ.Ⴗ𐣞; [B5 B6 P1 V6 A4_2]; [B5 B6 P1 V6 A4_2] # .Ↄⷧ.Ⴗ +B; 。ↄ\u2DE7ò¾€ƒ.ⴗ𐣞; [B5 B6 P1 V6 A4_2]; [B5 B6 P1 V6 A4_2] # .ↄⷧ.ⴗ +B; .xn--r5gy00cll06u.xn--flj4541e; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] # .ↄⷧ.ⴗ +B; .xn--q5g000cll06u.xn--vnd8618j; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] # .Ↄⷧ.Ⴗ +B; ︒ↄ\u2DE7ò¾€ƒï¼Žâ´—𐣞; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ︒ↄⷧ.ⴗ +B; xn--r5gy00c056n0226g.xn--flj4541e; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ︒ↄⷧ.ⴗ +B; xn--q5g000c056n0226g.xn--vnd8618j; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ︒Ↄⷧ.Ⴗ +B; \u0600.\u05B1; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # .Ö± +B; xn--ifb.xn--8cb; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # .Ö± +T; ς≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +N; ς≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +T; ς>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +N; ς>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +T; ς≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +N; ς≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +T; ς>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +N; ς>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; Σ>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; Σ≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; σ≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; σ>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; xn--4xa818m.xn--1o0d; [B1 B6 V6]; [B1 B6 V6] +B; xn--3xa028m.xn--1o0d; [B1 B6 V6]; [B1 B6 V6] +B; Σ>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; Σ≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; σ≯。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; σ>\u0338。𐹽; [B1 B6 P1 V6]; [B1 B6 P1 V6] +T; \u17D2\u200D\u075F。𐹶; [B1 V5]; [B1 V5] # ្ݟ.𐹶 +N; \u17D2\u200D\u075F。𐹶; [B1 V5]; [B1 V5] # ្ݟ.𐹶 +B; xn--jpb535f.xn--uo0d; [B1 V5]; [B1 V5] # ្ݟ.𐹶 +B; xn--jpb535fv9f.xn--uo0d; [B1 V5]; [B1 V5] # ្ݟ.𐹶 +B; 𾷂\u0A42Ⴊñ‚‚Ÿ.≮; [P1 V6]; [P1 V6] # ੂႪ.≮ +B; 𾷂\u0A42Ⴊñ‚‚Ÿ.<\u0338; [P1 V6]; [P1 V6] # ੂႪ.≮ +B; 𾷂\u0A42ⴊñ‚‚Ÿ.<\u0338; [P1 V6]; [P1 V6] # ੂⴊ.≮ +B; 𾷂\u0A42ⴊñ‚‚Ÿ.≮; [P1 V6]; [P1 V6] # ੂⴊ.≮ +B; xn--nbc229o4y27dgskb.xn--gdh; [V6]; [V6] # ੂⴊ.≮ +B; xn--nbc493aro75ggskb.xn--gdh; [V6]; [V6] # ੂႪ.≮ +B; ꡠ.۲; ê¡ .Û²; xn--5c9a.xn--fmb +B; ê¡ .Û²; ; xn--5c9a.xn--fmb +B; xn--5c9a.xn--fmb; ê¡ .Û²; xn--5c9a.xn--fmb +B; 𐹣ñ„·„。ꡬ🄄; [B1 P1 V6]; [B1 P1 V6] +B; 𐹣ñ„·„。ꡬ3,; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; xn--bo0d0203l.xn--3,-yj9h; [B1 B6 P1 V6]; [B1 B6 P1 V6] +B; xn--bo0d0203l.xn--id9a4443d; [B1 V6]; [B1 V6] +T; -\u0C4D𞾀𑲓。\u200D\u0D4D; [B1 C2 P1 V3 V6]; [B1 B3 B6 P1 V3 V5 V6] # -్𑲓.് +N; -\u0C4D𞾀𑲓。\u200D\u0D4D; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # -్𑲓.് +T; -\u0C4D𞾀𑲓。\u200D\u0D4D; [B1 C2 P1 V3 V6]; [B1 B3 B6 P1 V3 V5 V6] # -్𑲓.് +N; -\u0C4D𞾀𑲓。\u200D\u0D4D; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # -్𑲓.് +B; xn----x6e0220sclug.xn--wxc; [B1 B3 B6 V3 V5 V6]; [B1 B3 B6 V3 V5 V6] # -్𑲓.് +B; xn----x6e0220sclug.xn--wxc317g; [B1 C2 V3 V6]; [B1 C2 V3 V6] # -్𑲓.് +T; \uA67D\u200C霣🄆。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [P1 V5 V6] # ꙽霣🄆.𑁂ᬁ +N; \uA67D\u200C霣🄆。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ꙽霣🄆.𑁂ᬁ +T; \uA67D\u200C霣🄆。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [P1 V5 V6] # ꙽霣🄆.𑁂ᬁ +N; \uA67D\u200C霣🄆。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ꙽霣🄆.𑁂ᬁ +T; \uA67D\u200C霣5,。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [P1 V5 V6] # ꙽霣5,.𑁂ᬁ +N; \uA67D\u200C霣5,。\u200C𑁂\u1B01; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ꙽霣5,.𑁂ᬁ +B; xn--5,-op8g373c.xn--4sf0725i; [P1 V5 V6]; [P1 V5 V6] # ꙽霣5,.𑁂ᬁ +B; xn--5,-i1tz135dnbqa.xn--4sf36u6u4w; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ꙽霣5,.𑁂ᬁ +B; xn--2q5a751a653w.xn--4sf0725i; [V5 V6]; [V5 V6] # ꙽霣🄆.𑁂ᬁ +B; xn--0ug4208b2vjuk63a.xn--4sf36u6u4w; [C1 V5 V6]; [C1 V5 V6] # ꙽霣🄆.𑁂ᬁ +B; 兎。ᠼ󠴜𑚶𑰿; [P1 V6]; [P1 V6] +B; 兎。ᠼ󠴜𑚶𑰿; [P1 V6]; [P1 V6] +B; xn--b5q.xn--v7e6041kqqd4m251b; [V6]; [V6] +T; 𝟙。\u200D𝟸\u200D⁷; [C2]; 1.27 # 1.27 +N; 𝟙。\u200D𝟸\u200D⁷; [C2]; [C2] # 1.27 +T; 1。\u200D2\u200D7; [C2]; 1.27 # 1.27 +N; 1。\u200D2\u200D7; [C2]; [C2] # 1.27 +B; 1.27; ; +B; 1.xn--27-l1tb; [C2]; [C2] # 1.27 +B; ᡨ-。󠻋𝟷; [P1 V3 V6]; [P1 V3 V6] +B; ᡨ-。󠻋1; [P1 V3 V6]; [P1 V3 V6] +B; xn----z8j.xn--1-5671m; [V3 V6]; [V3 V6] +B; 𑰻ñµ€ð«šï¼Ž\u0668⁹; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𑰻𐫚.Ù¨9 +B; 𑰻ñµ€ð«š.\u06689; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𑰻𐫚.Ù¨9 +B; xn--gx9cr01aul57i.xn--9-oqc; [B1 V5 V6]; [B1 V5 V6] # 𑰻𐫚.Ù¨9 +T; Ⴜòˆ·­\u0F80⾇。Ⴏ♀\u200C\u200C; [C1 P1 V6]; [P1 V6] # Ⴜྀ舛.Ⴏ♀ +N; Ⴜòˆ·­\u0F80⾇。Ⴏ♀\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # Ⴜྀ舛.Ⴏ♀ +T; Ⴜòˆ·­\u0F80舛。Ⴏ♀\u200C\u200C; [C1 P1 V6]; [P1 V6] # Ⴜྀ舛.Ⴏ♀ +N; Ⴜòˆ·­\u0F80舛。Ⴏ♀\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # Ⴜྀ舛.Ⴏ♀ +T; ⴜòˆ·­\u0F80舛。ⴏ♀\u200C\u200C; [C1 P1 V6]; [P1 V6] # ⴜྀ舛.ⴏ♀ +N; ⴜòˆ·­\u0F80舛。ⴏ♀\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # ⴜྀ舛.ⴏ♀ +B; xn--zed372mdj2do3v4h.xn--e5h11w; [V6]; [V6] # ⴜྀ舛.ⴏ♀ +B; xn--zed372mdj2do3v4h.xn--0uga678bgyh; [C1 V6]; [C1 V6] # ⴜྀ舛.ⴏ♀ +B; xn--zed54dz10wo343g.xn--nnd651i; [V6]; [V6] # Ⴜྀ舛.Ⴏ♀ +B; xn--zed54dz10wo343g.xn--nnd089ea464d; [C1 V6]; [C1 V6] # Ⴜྀ舛.Ⴏ♀ +T; ⴜòˆ·­\u0F80⾇。ⴏ♀\u200C\u200C; [C1 P1 V6]; [P1 V6] # ⴜྀ舛.ⴏ♀ +N; ⴜòˆ·­\u0F80⾇。ⴏ♀\u200C\u200C; [C1 P1 V6]; [C1 P1 V6] # ⴜྀ舛.ⴏ♀ +T; 𑁆𝟰.\u200D; [C2 V5]; [V5] # 𑁆4. +N; 𑁆𝟰.\u200D; [C2 V5]; [C2 V5] # 𑁆4. +T; 𑁆4.\u200D; [C2 V5]; [V5] # 𑁆4. +N; 𑁆4.\u200D; [C2 V5]; [C2 V5] # 𑁆4. +B; xn--4-xu7i.; [V5]; [V5] +B; xn--4-xu7i.xn--1ug; [C2 V5]; [C2 V5] # 𑁆4. +T; ñ®´˜á‚¾ç™€ï½¡ð‘˜¿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [P1 V5 V6] # Ⴞ癀.𑘿붼 +N; ñ®´˜á‚¾ç™€ï½¡ð‘˜¿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # Ⴞ癀.𑘿붼 +T; ñ®´˜á‚¾ç™€ï½¡ð‘˜¿\u200D\u200C붼; [C1 P1 V5 V6]; [P1 V5 V6] # Ⴞ癀.𑘿붼 +N; ñ®´˜á‚¾ç™€ï½¡ð‘˜¿\u200D\u200C붼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # Ⴞ癀.𑘿붼 +T; ñ®´˜á‚¾ç™€ã€‚𑘿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [P1 V5 V6] # Ⴞ癀.𑘿붼 +N; ñ®´˜á‚¾ç™€ã€‚𑘿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # Ⴞ癀.𑘿붼 +T; ñ®´˜á‚¾ç™€ã€‚𑘿\u200D\u200C붼; [C1 P1 V5 V6]; [P1 V5 V6] # Ⴞ癀.𑘿붼 +N; ñ®´˜á‚¾ç™€ã€‚𑘿\u200D\u200C붼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # Ⴞ癀.𑘿붼 +T; ñ®´˜â´žç™€ã€‚𑘿\u200D\u200C붼; [C1 P1 V5 V6]; [P1 V5 V6] # ⴞ癀.𑘿붼 +N; ñ®´˜â´žç™€ã€‚𑘿\u200D\u200C붼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⴞ癀.𑘿붼 +T; ñ®´˜â´žç™€ã€‚𑘿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [P1 V5 V6] # ⴞ癀.𑘿붼 +N; ñ®´˜â´žç™€ã€‚𑘿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⴞ癀.𑘿붼 +B; xn--mlju35u7qx2f.xn--et3bn23n; [V5 V6]; [V5 V6] +B; xn--mlju35u7qx2f.xn--0ugb6122js83c; [C1 V5 V6]; [C1 V5 V6] # ⴞ癀.𑘿붼 +B; xn--2nd6803c7q37d.xn--et3bn23n; [V5 V6]; [V5 V6] +B; xn--2nd6803c7q37d.xn--0ugb6122js83c; [C1 V5 V6]; [C1 V5 V6] # Ⴞ癀.𑘿붼 +T; ñ®´˜â´žç™€ï½¡ð‘˜¿\u200D\u200C붼; [C1 P1 V5 V6]; [P1 V5 V6] # ⴞ癀.𑘿붼 +N; ñ®´˜â´žç™€ï½¡ð‘˜¿\u200D\u200C붼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⴞ癀.𑘿붼 +T; ñ®´˜â´žç™€ï½¡ð‘˜¿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [P1 V5 V6] # ⴞ癀.𑘿붼 +N; ñ®´˜â´žç™€ï½¡ð‘˜¿\u200D\u200Cë¶¼; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⴞ癀.𑘿붼 +B; 󚀅-\u0BCD。\u06B9; [B6 P1 V6]; [B6 P1 V6] # -்.Ú¹ +B; xn----mze84808x.xn--skb; [B6 V6]; [B6 V6] # -்.Ú¹ +B; ᡃ𝟧≯ᠣ.氁ñ¨±ê«; [P1 V6]; [P1 V6] +B; ᡃ𝟧>\u0338ᠣ.氁ñ¨±ê«; [P1 V6]; [P1 V6] +B; ᡃ5≯ᠣ.氁ñ¨±ê«; [P1 V6]; [P1 V6] +B; ᡃ5>\u0338á £.氁ñ¨±ê«; [P1 V6]; [P1 V6] +B; xn--5-24jyf768b.xn--lqw213ime95g; [V6]; [V6] +B; 𐹬𝩇.\u0F76; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐹬𝩇.ྲྀ +B; 𐹬𝩇.\u0FB2\u0F80; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐹬𝩇.ྲྀ +B; 𐹬𝩇.\u0FB2\u0F80; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐹬𝩇.ྲྀ +B; xn--ko0d8295a.xn--zed3h; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𐹬𝩇.ྲྀ +B; -𑈶⒏.⒎𰛢󠎭; [P1 V3 V6]; [P1 V3 V6] +B; -𑈶8..7.𰛢󠎭; [P1 V3 V6 A4_2]; [P1 V3 V6 A4_2] +B; xn---8-bv5o..7.xn--c35nf1622b; [V3 V6 A4_2]; [V3 V6 A4_2] +B; xn----scp6252h.xn--zshy411yzpx2d; [V3 V6]; [V3 V6] +T; \u200CႡ畝\u200D.≮; [C1 C2 P1 V6]; [P1 V6] # Ⴁ畝.≮ +N; \u200CႡ畝\u200D.≮; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⴁ畝.≮ +T; \u200CႡ畝\u200D.<\u0338; [C1 C2 P1 V6]; [P1 V6] # Ⴁ畝.≮ +N; \u200CႡ畝\u200D.<\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⴁ畝.≮ +T; \u200CႡ畝\u200D.≮; [C1 C2 P1 V6]; [P1 V6] # Ⴁ畝.≮ +N; \u200CႡ畝\u200D.≮; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⴁ畝.≮ +T; \u200CႡ畝\u200D.<\u0338; [C1 C2 P1 V6]; [P1 V6] # Ⴁ畝.≮ +N; \u200CႡ畝\u200D.<\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6] # Ⴁ畝.≮ +T; \u200Cⴁ畝\u200D.<\u0338; [C1 C2 P1 V6]; [P1 V6] # ⴁ畝.≮ +N; \u200Cⴁ畝\u200D.<\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⴁ畝.≮ +T; \u200Cⴁ畝\u200D.≮; [C1 C2 P1 V6]; [P1 V6] # ⴁ畝.≮ +N; \u200Cⴁ畝\u200D.≮; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⴁ畝.≮ +B; xn--skjy82u.xn--gdh; [V6]; [V6] +B; xn--0ugc160hb36e.xn--gdh; [C1 C2 V6]; [C1 C2 V6] # ⴁ畝.≮ +B; xn--8md0962c.xn--gdh; [V6]; [V6] +B; xn--8md700fea3748f.xn--gdh; [C1 C2 V6]; [C1 C2 V6] # Ⴁ畝.≮ +T; \u200Cⴁ畝\u200D.<\u0338; [C1 C2 P1 V6]; [P1 V6] # ⴁ畝.≮ +N; \u200Cⴁ畝\u200D.<\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⴁ畝.≮ +T; \u200Cⴁ畝\u200D.≮; [C1 C2 P1 V6]; [P1 V6] # ⴁ畝.≮ +N; \u200Cⴁ畝\u200D.≮; [C1 C2 P1 V6]; [C1 C2 P1 V6] # ⴁ畝.≮ +T; 歷。𐹻≯󳛽\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # æ­·.𐹻≯ +N; 歷。𐹻≯󳛽\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # æ­·.𐹻≯ +T; 歷。𐹻>\u0338󳛽\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # æ­·.𐹻≯ +N; 歷。𐹻>\u0338󳛽\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # æ­·.𐹻≯ +T; 歷。𐹻≯󳛽\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # æ­·.𐹻≯ +N; 歷。𐹻≯󳛽\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # æ­·.𐹻≯ +T; 歷。𐹻>\u0338󳛽\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # æ­·.𐹻≯ +N; 歷。𐹻>\u0338󳛽\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # æ­·.𐹻≯ +B; xn--nmw.xn--hdh7804gdms2h; [B1 V6]; [B1 V6] +B; xn--nmw.xn--1ugx6gs128a1134j; [B1 C2 V6]; [B1 C2 V6] # æ­·.𐹻≯ +T; \u0ECB\u200D.鎁󠰑; [C2 P1 V5 V6]; [P1 V5 V6] # ໋.鎁 +N; \u0ECB\u200D.鎁󠰑; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ໋.鎁 +T; \u0ECB\u200D.鎁󠰑; [C2 P1 V5 V6]; [P1 V5 V6] # ໋.鎁 +N; \u0ECB\u200D.鎁󠰑; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ໋.鎁 +B; xn--t8c.xn--iz4a43209d; [V5 V6]; [V5 V6] # ໋.鎁 +B; xn--t8c059f.xn--iz4a43209d; [C2 V5 V6]; [C2 V5 V6] # ໋.鎁 +T; \u200D\u200C𞤀。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # 𞤢. +N; \u200D\u200C𞤀。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # 𞤢. +T; \u200D\u200C𞤀。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # 𞤢. +N; \u200D\u200C𞤀。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # 𞤢. +T; \u200D\u200C𞤢。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # 𞤢. +N; \u200D\u200C𞤢。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # 𞤢. +B; xn--9d6h.xn--wh0dj799f; [B5 B6 V6]; [B5 B6 V6] +B; xn--0ugb45126a.xn--wh0dj799f; [B1 B5 B6 C1 C2 V6]; [B1 B5 B6 C1 C2 V6] # 𞤢. +T; \u200D\u200C𞤢。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B5 B6 P1 V6] # 𞤢. +N; \u200D\u200C𞤢。𱘅𐶃; [B1 B5 B6 C1 C2 P1 V6]; [B1 B5 B6 C1 C2 P1 V6] # 𞤢. +T; \u0628≠𝟫-.ς⒍𐹦≠; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.ς⒍𐹦≠ +N; \u0628≠𝟫-.ς⒍𐹦≠; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.ς⒍𐹦≠ +T; \u0628=\u0338𝟫-.ς⒍𐹦=\u0338; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.ς⒍𐹦≠ +N; \u0628=\u0338𝟫-.ς⒍𐹦=\u0338; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.ς⒍𐹦≠ +T; \u0628≠9-.ς6.𐹦≠; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.ς6.𐹦≠ +N; \u0628≠9-.ς6.𐹦≠; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.ς6.𐹦≠ +T; \u0628=\u03389-.ς6.𐹦=\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.ς6.𐹦≠ +N; \u0628=\u03389-.ς6.𐹦=\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.ς6.𐹦≠ +B; \u0628=\u03389-.Σ6.𐹦=\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.σ6.𐹦≠ +B; \u0628≠9-.Σ6.𐹦≠; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.σ6.𐹦≠ +B; \u0628≠9-.σ6.𐹦≠; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.σ6.𐹦≠ +B; \u0628=\u03389-.σ6.𐹦=\u0338; [B1 B3 P1 V3 V6]; [B1 B3 P1 V3 V6] # ب≠9-.σ6.𐹦≠ +B; xn--9--etd0100a.xn--6-zmb.xn--1ch8704g; [B1 B3 V3 V6]; [B1 B3 V3 V6] # ب≠9-.σ6.𐹦≠ +B; xn--9--etd0100a.xn--6-xmb.xn--1ch8704g; [B1 B3 V3 V6]; [B1 B3 V3 V6] # ب≠9-.ς6.𐹦≠ +B; \u0628=\u0338𝟫-.Σ⒍𐹦=\u0338; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.σ⒍𐹦≠ +B; \u0628≠𝟫-.Σ⒍𐹦≠; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.σ⒍𐹦≠ +B; \u0628≠𝟫-.σ⒍𐹦≠; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.σ⒍𐹦≠ +B; \u0628=\u0338𝟫-.σ⒍𐹦=\u0338; [B3 B5 B6 P1 V3 V6]; [B3 B5 B6 P1 V3 V6] # ب≠9-.σ⒍𐹦≠ +B; xn--9--etd0100a.xn--4xa887mzpbzz04b; [B3 B5 B6 V3 V6]; [B3 B5 B6 V3 V6] # ب≠9-.σ⒍𐹦≠ +B; xn--9--etd0100a.xn--3xa097mzpbzz04b; [B3 B5 B6 V3 V6]; [B3 B5 B6 V3 V6] # ب≠9-.ς⒍𐹦≠ +B; ò‰›´.-á¡¢\u0592𝨠; [P1 V3 V6]; [P1 V3 V6] # .-ᡢ֒𝨠 +B; xn--ep37b.xn----hec165lho83b; [V3 V6]; [V3 V6] # .-ᡢ֒𝨠 +T; \u06CB⒈ß󠄽。ñ·‹-; [B2 B3 B6 P1 V3 V6]; [B2 B3 B6 P1 V3 V6] # ۋ⒈ß.- +N; \u06CB⒈ß󠄽。ñ·‹-; [B2 B3 B6 P1 V3 V6]; [B2 B3 B6 P1 V3 V6] # ۋ⒈ß.- +T; \u06CB1.ß󠄽。ñ·‹-; [B6 P1 V3 V6]; [B6 P1 V3 V6] # ۋ1.ß.- +N; \u06CB1.ß󠄽。ñ·‹-; [B6 P1 V3 V6]; [B6 P1 V3 V6] # ۋ1.ß.- +B; \u06CB1.SS󠄽。ñ·‹-; [B6 P1 V3 V6]; [B6 P1 V3 V6] # ۋ1.ss.- +B; \u06CB1.ss󠄽。ñ·‹-; [B6 P1 V3 V6]; [B6 P1 V3 V6] # ۋ1.ss.- +B; \u06CB1.Ss󠄽。ñ·‹-; [B6 P1 V3 V6]; [B6 P1 V3 V6] # ۋ1.ss.- +B; xn--1-cwc.ss.xn----q001f; [B6 V3 V6]; [B6 V3 V6] # ۋ1.ss.- +B; xn--1-cwc.xn--zca.xn----q001f; [B6 V3 V6]; [B6 V3 V6] # ۋ1.ß.- +B; \u06CB⒈SS󠄽。ñ·‹-; [B2 B3 B6 P1 V3 V6]; [B2 B3 B6 P1 V3 V6] # ۋ⒈ss.- +B; \u06CB⒈ss󠄽。ñ·‹-; [B2 B3 B6 P1 V3 V6]; [B2 B3 B6 P1 V3 V6] # ۋ⒈ss.- +B; \u06CB⒈Ss󠄽。ñ·‹-; [B2 B3 B6 P1 V3 V6]; [B2 B3 B6 P1 V3 V6] # ۋ⒈ss.- +B; xn--ss-d7d6651a.xn----q001f; [B2 B3 B6 V3 V6]; [B2 B3 B6 V3 V6] # ۋ⒈ss.- +B; xn--zca541ato3a.xn----q001f; [B2 B3 B6 V3 V6]; [B2 B3 B6 V3 V6] # ۋ⒈ß.- +T; 𿀫.\u1BAAςႦ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪ςႦ +N; 𿀫.\u1BAAςႦ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪ςႦ +T; 𿀫.\u1BAAςႦ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪ςႦ +N; 𿀫.\u1BAAςႦ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪ςႦ +T; 𿀫.\u1BAAςⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪ςⴆ +N; 𿀫.\u1BAAςⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪ςⴆ +T; 𿀫.\u1BAAΣႦ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σႦ +N; 𿀫.\u1BAAΣႦ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σႦ +T; 𿀫.\u1BAAσⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σⴆ +N; 𿀫.\u1BAAσⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σⴆ +T; 𿀫.\u1BAAΣⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σⴆ +N; 𿀫.\u1BAAΣⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σⴆ +B; xn--nu4s.xn--4xa153j7im; [V5 V6]; [V5 V6] # .᮪σⴆ +B; xn--nu4s.xn--4xa153jk8cs1q; [C2 V5 V6]; [C2 V5 V6] # .᮪σⴆ +B; xn--nu4s.xn--4xa217dxri; [V5 V6]; [V5 V6] # .᮪σႦ +B; xn--nu4s.xn--4xa217dxriome; [C2 V5 V6]; [C2 V5 V6] # .᮪σႦ +B; xn--nu4s.xn--3xa353jk8cs1q; [C2 V5 V6]; [C2 V5 V6] # .᮪ςⴆ +B; xn--nu4s.xn--3xa417dxriome; [C2 V5 V6]; [C2 V5 V6] # .᮪ςႦ +T; 𿀫.\u1BAAςⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪ςⴆ +N; 𿀫.\u1BAAςⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪ςⴆ +T; 𿀫.\u1BAAΣႦ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σႦ +N; 𿀫.\u1BAAΣႦ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σႦ +T; 𿀫.\u1BAAσⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σⴆ +N; 𿀫.\u1BAAσⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σⴆ +T; 𿀫.\u1BAAΣⴆ\u200D; [C2 P1 V5 V6]; [P1 V5 V6] # .᮪σⴆ +N; 𿀫.\u1BAAΣⴆ\u200D; [C2 P1 V5 V6]; [C2 P1 V5 V6] # .᮪σⴆ +B; ⾆\u08E2.𝈴; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 舌.𝈴 +B; 舌\u08E2.𝈴; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 舌.𝈴 +B; xn--l0b9413d.xn--kl1h; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 舌.𝈴 +B; ⫞𐹶𖫴。⭠⒈; [B1 P1 V6]; [B1 P1 V6] +B; ⫞𐹶𖫴。⭠1.; [B1]; [B1] +B; xn--53ix188et88b.xn--1-h6r.; [B1]; [B1] +B; xn--53ix188et88b.xn--tsh52w; [B1 V6]; [B1 V6] +T; ⒈\u200C\uAAEC︒.\u0ACD; [C1 P1 V5 V6]; [P1 V5 V6] # ⒈ꫬ︒.્ +N; ⒈\u200C\uAAEC︒.\u0ACD; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⒈ꫬ︒.્ +T; 1.\u200C\uAAEC。.\u0ACD; [C1 V5 A4_2]; [V5 A4_2] # 1.ꫬ..્ +N; 1.\u200C\uAAEC。.\u0ACD; [C1 V5 A4_2]; [C1 V5 A4_2] # 1.ꫬ..્ +B; 1.xn--sv9a..xn--mfc; [V5 A4_2]; [V5 A4_2] # 1.ꫬ..્ +B; 1.xn--0ug7185c..xn--mfc; [C1 V5 A4_2]; [C1 V5 A4_2] # 1.ꫬ..્ +B; xn--tsh0720cse8b.xn--mfc; [V5 V6]; [V5 V6] # ⒈ꫬ︒.્ +B; xn--0ug78o720myr1c.xn--mfc; [C1 V5 V6]; [C1 V5 V6] # ⒈ꫬ︒.્ +B; \u0C46。䰀\u0668𞭅󠅼; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ె.䰀٨ +B; xn--eqc.xn--hib5476aim6t; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ె.䰀٨ +T; ß\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [P1 V5 V6] # ß.᯲ +N; ß\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ß.᯲ +T; SS\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [P1 V5 V6] # ss.᯲ +N; SS\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ss.᯲ +T; ss\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [P1 V5 V6] # ss.᯲ +N; ss\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ss.᯲ +T; Ss\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [P1 V5 V6] # ss.᯲ +N; Ss\u200D.\u1BF2ñ„¾¼; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ss.᯲ +B; ss.xn--0zf22107b; [V5 V6]; [V5 V6] # ss.᯲ +B; xn--ss-n1t.xn--0zf22107b; [C2 V5 V6]; [C2 V5 V6] # ss.᯲ +B; xn--zca870n.xn--0zf22107b; [C2 V5 V6]; [C2 V5 V6] # ß.᯲ +T; 𑓂\u200C≮.≮; [P1 V5 V6]; [P1 V5 V6] # 𑓂≮.≮ +N; 𑓂\u200C≮.≮; [P1 V5 V6]; [P1 V5 V6] # 𑓂≮.≮ +T; 𑓂\u200C<\u0338.<\u0338; [P1 V5 V6]; [P1 V5 V6] # 𑓂≮.≮ +N; 𑓂\u200C<\u0338.<\u0338; [P1 V5 V6]; [P1 V5 V6] # 𑓂≮.≮ +B; xn--gdhz656g.xn--gdh; [V5 V6]; [V5 V6] +B; xn--0ugy6glz29a.xn--gdh; [V5 V6]; [V5 V6] # 𑓂≮.≮ +B; 🕼.\uFFA0; [P1 V6]; [P1 V6] # 🕼. +B; 🕼.\u1160; [P1 V6]; [P1 V6] # 🕼. +B; xn--my8h.xn--psd; [V6]; [V6] # 🕼. +B; xn--my8h.xn--cl7c; [V6]; [V6] # 🕼. +B; ᡔ\uFD82。ñ·˜Ž; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ᡔلحى. +B; ᡔ\u0644\u062D\u0649。ñ·˜Ž; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ᡔلحى. +B; xn--sgb9bq785p.xn--bc31b; [B5 B6 V6]; [B5 B6 V6] # ᡔلحى. +B; 爕ò³™‘.𝟰気; [P1 V6]; [P1 V6] +B; 爕ò³™‘.4気; [P1 V6]; [P1 V6] +B; xn--1zxq3199c.xn--4-678b; [V6]; [V6] +B; ⒋𑍍Ⴝ-.𞬪\u0DCA\u05B5; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ⒋𑍍Ⴝ-.්ֵ +B; 4.𑍍Ⴝ-.𞬪\u0DCA\u05B5; [B1 B6 P1 V3 V5 V6]; [B1 B6 P1 V3 V5 V6] # 4.𑍍Ⴝ-.්ֵ +B; 4.𑍍ⴝ-.𞬪\u0DCA\u05B5; [B1 B6 P1 V3 V5 V6]; [B1 B6 P1 V3 V5 V6] # 4.𑍍ⴝ-.්ֵ +B; 4.xn----wwsx259f.xn--ddb152b7y23b; [B1 B6 V3 V5 V6]; [B1 B6 V3 V5 V6] # 4.𑍍ⴝ-.්ֵ +B; 4.xn----t1g9869q.xn--ddb152b7y23b; [B1 B6 V3 V5 V6]; [B1 B6 V3 V5 V6] # 4.𑍍Ⴝ-.්ֵ +B; ⒋𑍍ⴝ-.𞬪\u0DCA\u05B5; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ⒋𑍍ⴝ-.්ֵ +B; xn----jcp487avl3w.xn--ddb152b7y23b; [B1 V3 V6]; [B1 V3 V6] # ⒋𑍍ⴝ-.්ֵ +B; xn----t1g323mnk9t.xn--ddb152b7y23b; [B1 V3 V6]; [B1 V3 V6] # ⒋𑍍Ⴝ-.්ֵ +B; 󞝃。ò‘†ƒñ‰¢—--; [P1 V2 V3 V6]; [P1 V2 V3 V6] +B; xn--2y75e.xn-----1l15eer88n; [V2 V3 V6]; [V2 V3 V6] +T; \u200D\u07DF。\u200C\uABED; [B1 C1 C2]; [B1 B3 B6 V5] # ߟ.꯭ +N; \u200D\u07DF。\u200C\uABED; [B1 C1 C2]; [B1 C1 C2] # ߟ.꯭ +T; \u200D\u07DF。\u200C\uABED; [B1 C1 C2]; [B1 B3 B6 V5] # ߟ.꯭ +N; \u200D\u07DF。\u200C\uABED; [B1 C1 C2]; [B1 C1 C2] # ߟ.꯭ +B; xn--6sb.xn--429a; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ߟ.꯭ +B; xn--6sb394j.xn--0ug1126c; [B1 C1 C2]; [B1 C1 C2] # ߟ.꯭ +B; 𞮽\u07FF\u084E。ᢍò¹ð«˜; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡎ.ᢍ𐫘 +B; 𞮽\u07FF\u084E。ᢍò¹ð«˜; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ࡎ.ᢍ𐫘 +B; xn--3tb2nz468k.xn--69e8615j5rn5d; [B5 B6 V6]; [B5 B6 V6] # ࡎ.ᢍ𐫘 +B; \u06ED𞺌𑄚\u1714.ꡞ\u08B7; [B1 B5 B6 V5]; [B1 B5 B6 V5] # ۭم𑄚᜔.ꡞࢷ +B; \u06ED\u0645𑄚\u1714.ꡞ\u08B7; [B1 B5 B6 V5]; [B1 B5 B6 V5] # ۭم𑄚᜔.ꡞࢷ +B; xn--hhb94ag41b739u.xn--dzb5582f; [B1 B5 B6 V5]; [B1 B5 B6 V5] # ۭم𑄚᜔.ꡞࢷ +T; ñ»‚µí‚ƒð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +T; ñ»‚µí‚ƒð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。ς\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.ςؼς +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063CΣ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063CΣ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; xn--3sb7483hoyvbbe76g.xn--4xaa21q; [B5 B6 V6]; [B5 B6 V6] # 킃𑘶ߜ.σؼσ +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +B; xn--3sb7483hoyvbbe76g.xn--3xab31q; [B5 B6 V6]; [B5 B6 V6] # 킃𑘶ߜ.σؼς +B; xn--3sb7483hoyvbbe76g.xn--3xaa51q; [B5 B6 V6]; [B5 B6 V6] # 킃𑘶ߜ.ςؼς +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063CΣ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063CΣ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +B; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cσ; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼσ +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。Σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µí‚ƒð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +T; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +N; ñ»‚µá„á…³á†¾ð‘˜¶\u07DC。σ\u063Cς; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 킃𑘶ߜ.σؼς +B; 蔰。󠁹\u08DD-𑈵; [P1 V6]; [P1 V6] # 蔰.ࣝ-𑈵 +B; xn--sz1a.xn----mrd9984r3dl0i; [V6]; [V6] # 蔰.ࣝ-𑈵 +T; ςჅ。\u075A; [P1 V6]; [P1 V6] # ςჅ.ݚ +N; ςჅ。\u075A; [P1 V6]; [P1 V6] # ςჅ.ݚ +T; ςⴥ。\u075A; ςⴥ.\u075A; xn--4xa203s.xn--epb # ςⴥ.ݚ +N; ςⴥ。\u075A; ςⴥ.\u075A; xn--3xa403s.xn--epb # ςⴥ.ݚ +B; ΣჅ。\u075A; [P1 V6]; [P1 V6] # σჅ.ݚ +B; σⴥ。\u075A; σⴥ.\u075A; xn--4xa203s.xn--epb # σⴥ.ݚ +B; Σⴥ。\u075A; σⴥ.\u075A; xn--4xa203s.xn--epb # σⴥ.ݚ +B; xn--4xa203s.xn--epb; σⴥ.\u075A; xn--4xa203s.xn--epb # σⴥ.ݚ +B; σⴥ.\u075A; ; xn--4xa203s.xn--epb # σⴥ.ݚ +B; ΣჅ.\u075A; [P1 V6]; [P1 V6] # σჅ.ݚ +B; Σⴥ.\u075A; σⴥ.\u075A; xn--4xa203s.xn--epb # σⴥ.ݚ +B; xn--4xa477d.xn--epb; [V6]; [V6] # σჅ.ݚ +B; xn--3xa403s.xn--epb; ςⴥ.\u075A; xn--3xa403s.xn--epb # ςⴥ.ݚ +T; ςⴥ.\u075A; ; xn--4xa203s.xn--epb # ςⴥ.ݚ +N; ςⴥ.\u075A; ; xn--3xa403s.xn--epb # ςⴥ.ݚ +B; xn--3xa677d.xn--epb; [V6]; [V6] # ςჅ.ݚ +B; \u0C4DႩ𞰓.\u1B72; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ్Ⴉ.á­² +B; \u0C4DႩ𞰓.\u1B72; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ్Ⴉ.á­² +B; \u0C4Dⴉ𞰓.\u1B72; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ్ⴉ.á­² +B; xn--lqc478nlr02a.xn--dwf; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # ్ⴉ.á­² +B; xn--lqc64t7t26c.xn--dwf; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # ్Ⴉ.á­² +B; \u0C4Dⴉ𞰓.\u1B72; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ్ⴉ.á­² +B; ⮷≮ñŽˆ´ó „Ÿã€‚𐠄; [B1 P1 V6]; [B1 P1 V6] +B; â®·<\u0338ñŽˆ´ó „Ÿã€‚𐠄; [B1 P1 V6]; [B1 P1 V6] +B; xn--gdh877a3513h.xn--pc9c; [B1 V6]; [B1 V6] +T; \u06BC。\u200Dẏ\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200Dẏ\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200Dy\u0307\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200Dy\u0307\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200Dẏ\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200Dẏ\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200Dy\u0307\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200Dy\u0307\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200DY\u0307\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200DY\u0307\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200DẎ\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200DẎ\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +B; xn--vkb.xn--08e172a; \u06BC.ẏᡤ; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +B; \u06BC.ẏᡤ; ; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +B; \u06BC.y\u0307ᡤ; \u06BC.ẏᡤ; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +B; \u06BC.Y\u0307ᡤ; \u06BC.ẏᡤ; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +B; \u06BC.Ẏᡤ; \u06BC.ẏᡤ; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +B; xn--vkb.xn--08e172ax6aca; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200DY\u0307\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200DY\u0307\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +T; \u06BC。\u200DẎ\u200Cᡤ; [B1 C1 C2]; xn--vkb.xn--08e172a # Ú¼.ẏᡤ +N; \u06BC。\u200DẎ\u200Cᡤ; [B1 C1 C2]; [B1 C1 C2] # Ú¼.ẏᡤ +B; 𐹹𑲛。ñ‘‚\u0DCA; [B1 P1 V6]; [B1 P1 V6] # 𐹹𑲛.් +B; xn--xo0dg5v.xn--h1c39876d; [B1 V6]; [B1 V6] # 𐹹𑲛.් +B; -≠𑈵。嵕\uFEF1Û´\uA953; [B1 B5 P1 V3 V6]; [B1 B5 P1 V3 V6] # -≠𑈵.嵕ي۴꥓ +B; -=\u0338𑈵。嵕\uFEF1Û´\uA953; [B1 B5 P1 V3 V6]; [B1 B5 P1 V3 V6] # -≠𑈵.嵕ي۴꥓ +B; -≠𑈵。嵕\u064AÛ´\uA953; [B1 B5 P1 V3 V6]; [B1 B5 P1 V3 V6] # -≠𑈵.嵕ي۴꥓ +B; -=\u0338𑈵。嵕\u064AÛ´\uA953; [B1 B5 P1 V3 V6]; [B1 B5 P1 V3 V6] # -≠𑈵.嵕ي۴꥓ +B; xn----ufo4749h.xn--mhb45a235sns3c; [B1 B5 V3 V6]; [B1 B5 V3 V6] # -≠𑈵.嵕ي۴꥓ +T; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D≯\u200D; [B1 B3 C1 C2 P1 V6]; [B3 B5 B6 P1 V6] # 𐹶ݮ.ہ≯ +N; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D≯\u200D; [B1 B3 C1 C2 P1 V6]; [B1 B3 C1 C2 P1 V6] # 𐹶ݮ.ہ≯ +T; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D>\u0338\u200D; [B1 B3 C1 C2 P1 V6]; [B3 B5 B6 P1 V6] # 𐹶ݮ.ہ≯ +N; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D>\u0338\u200D; [B1 B3 C1 C2 P1 V6]; [B1 B3 C1 C2 P1 V6] # 𐹶ݮ.ہ≯ +T; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D≯\u200D; [B1 B3 C1 C2 P1 V6]; [B3 B5 B6 P1 V6] # 𐹶ݮ.ہ≯ +N; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D≯\u200D; [B1 B3 C1 C2 P1 V6]; [B1 B3 C1 C2 P1 V6] # 𐹶ݮ.ہ≯ +T; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D>\u0338\u200D; [B1 B3 C1 C2 P1 V6]; [B3 B5 B6 P1 V6] # 𐹶ݮ.ہ≯ +N; \u200Cñ¸°ð¹¶\u076E.\u06C1\u200D>\u0338\u200D; [B1 B3 C1 C2 P1 V6]; [B1 B3 C1 C2 P1 V6] # 𐹶ݮ.ہ≯ +B; xn--ypb5875khz9y.xn--0kb682l; [B3 B5 B6 V6]; [B3 B5 B6 V6] # 𐹶ݮ.ہ≯ +B; xn--ypb717jrx2o7v94a.xn--0kb660ka35v; [B1 B3 C1 C2 V6]; [B1 B3 C1 C2 V6] # 𐹶ݮ.ہ≯ +B; ≮.\u17B5\u0855𐫔; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮.ࡕ𐫔 +B; <\u0338.\u17B5\u0855𐫔; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮.ࡕ𐫔 +B; ≮.\u17B5\u0855𐫔; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮.ࡕ𐫔 +B; <\u0338.\u17B5\u0855𐫔; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮.ࡕ𐫔 +B; xn--gdh.xn--kwb589e217p; [B1 V5 V6]; [B1 V5 V6] # ≮.ࡕ𐫔 +T; 𐩗\u200D。ႩႵ; [B3 C2 P1 V6]; [P1 V6] # 𐩗.ႩႵ +N; 𐩗\u200D。ႩႵ; [B3 C2 P1 V6]; [B3 C2 P1 V6] # 𐩗.ႩႵ +T; 𐩗\u200D。ႩႵ; [B3 C2 P1 V6]; [P1 V6] # 𐩗.ႩႵ +N; 𐩗\u200D。ႩႵ; [B3 C2 P1 V6]; [B3 C2 P1 V6] # 𐩗.ႩႵ +T; 𐩗\u200D。ⴉⴕ; [B3 C2]; xn--pt9c.xn--0kjya # 𐩗.ⴉⴕ +N; 𐩗\u200D。ⴉⴕ; [B3 C2]; [B3 C2] # 𐩗.ⴉⴕ +T; 𐩗\u200D。Ⴉⴕ; [B3 C2 P1 V6]; [P1 V6] # 𐩗.Ⴉⴕ +N; 𐩗\u200D。Ⴉⴕ; [B3 C2 P1 V6]; [B3 C2 P1 V6] # 𐩗.Ⴉⴕ +B; xn--pt9c.xn--hnd666l; [V6]; [V6] +B; xn--1ug4933g.xn--hnd666l; [B3 C2 V6]; [B3 C2 V6] # 𐩗.Ⴉⴕ +B; xn--pt9c.xn--0kjya; 𐩗.ⴉⴕ; xn--pt9c.xn--0kjya; NV8 +B; 𐩗.ⴉⴕ; ; xn--pt9c.xn--0kjya; NV8 +B; 𐩗.ႩႵ; [P1 V6]; [P1 V6] +B; 𐩗.Ⴉⴕ; [P1 V6]; [P1 V6] +B; xn--pt9c.xn--hndy; [V6]; [V6] +B; xn--1ug4933g.xn--0kjya; [B3 C2]; [B3 C2] # 𐩗.ⴉⴕ +B; xn--1ug4933g.xn--hndy; [B3 C2 V6]; [B3 C2 V6] # 𐩗.ႩႵ +T; 𐩗\u200D。ⴉⴕ; [B3 C2]; xn--pt9c.xn--0kjya # 𐩗.ⴉⴕ +N; 𐩗\u200D。ⴉⴕ; [B3 C2]; [B3 C2] # 𐩗.ⴉⴕ +T; 𐩗\u200D。Ⴉⴕ; [B3 C2 P1 V6]; [P1 V6] # 𐩗.Ⴉⴕ +N; 𐩗\u200D。Ⴉⴕ; [B3 C2 P1 V6]; [B3 C2 P1 V6] # 𐩗.Ⴉⴕ +T; \u200C\u200Cㄤ.\u032E󕨑\u09C2; [C1 P1 V5 V6]; [P1 V5 V6] # ㄤ.̮ূ +N; \u200C\u200Cㄤ.\u032E󕨑\u09C2; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ㄤ.̮ূ +T; \u200C\u200Cㄤ.\u032E󕨑\u09C2; [C1 P1 V5 V6]; [P1 V5 V6] # ㄤ.̮ূ +N; \u200C\u200Cㄤ.\u032E󕨑\u09C2; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ㄤ.̮ূ +B; xn--1fk.xn--vta284a9o563a; [V5 V6]; [V5 V6] # ㄤ.̮ূ +B; xn--0uga242k.xn--vta284a9o563a; [C1 V5 V6]; [C1 V5 V6] # ㄤ.̮ূ +T; 𐋻。-\u200C𐫄Ⴗ; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𐋻.-𐫄Ⴗ +N; 𐋻。-\u200C𐫄Ⴗ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𐋻.-𐫄Ⴗ +T; 𐋻。-\u200C𐫄Ⴗ; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𐋻.-𐫄Ⴗ +N; 𐋻。-\u200C𐫄Ⴗ; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𐋻.-𐫄Ⴗ +T; 𐋻。-\u200C𐫄ⴗ; [B1 C1 V3]; [B1 V3] # 𐋻.-𐫄ⴗ +N; 𐋻。-\u200C𐫄ⴗ; [B1 C1 V3]; [B1 C1 V3] # 𐋻.-𐫄ⴗ +B; xn--v97c.xn----lws0526f; [B1 V3]; [B1 V3] +B; xn--v97c.xn----sgnv20du99s; [B1 C1 V3]; [B1 C1 V3] # 𐋻.-𐫄ⴗ +B; xn--v97c.xn----i1g2513q; [B1 V3 V6]; [B1 V3 V6] +B; xn--v97c.xn----i1g888ih12u; [B1 C1 V3 V6]; [B1 C1 V3 V6] # 𐋻.-𐫄Ⴗ +T; 𐋻。-\u200C𐫄ⴗ; [B1 C1 V3]; [B1 V3] # 𐋻.-𐫄ⴗ +N; 𐋻。-\u200C𐫄ⴗ; [B1 C1 V3]; [B1 C1 V3] # 𐋻.-𐫄ⴗ +T; 🙑𐷺.≠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 🙑.≠ +N; 🙑𐷺.≠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 🙑.≠ +T; 🙑𐷺.=\u0338\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 🙑.≠ +N; 🙑𐷺.=\u0338\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 🙑.≠ +T; 🙑𐷺.≠\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 🙑.≠ +N; 🙑𐷺.≠\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 🙑.≠ +T; 🙑𐷺.=\u0338\u200C; [B1 C1 P1 V6]; [B1 P1 V6] # 🙑.≠ +N; 🙑𐷺.=\u0338\u200C; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 🙑.≠ +B; xn--bl0dh970b.xn--1ch; [B1 V6]; [B1 V6] +B; xn--bl0dh970b.xn--0ug83g; [B1 C1 V6]; [B1 C1 V6] # 🙑.≠ +B; \u064C\u1CD2。𞮞\u2D7F⧎; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ٌ᳒.⵿⧎ +B; \u064C\u1CD2。𞮞\u2D7F⧎; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ٌ᳒.⵿⧎ +B; xn--ohb646i.xn--ewi38jf765c; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # ٌ᳒.⵿⧎ +B; Ⴔ𝨨₃󠁦.𝟳𑂹\u0B82; [P1 V6]; [P1 V6] # Ⴔ𝨨3.7𑂹ஂ +B; Ⴔ𝨨3󠁦.7𑂹\u0B82; [P1 V6]; [P1 V6] # Ⴔ𝨨3.7𑂹ஂ +B; ⴔ𝨨3󠁦.7𑂹\u0B82; [P1 V6]; [P1 V6] # ⴔ𝨨3.7𑂹ஂ +B; xn--3-ews6985n35s3g.xn--7-cve6271r; [V6]; [V6] # ⴔ𝨨3.7𑂹ஂ +B; xn--3-b1g83426a35t0g.xn--7-cve6271r; [V6]; [V6] # Ⴔ𝨨3.7𑂹ஂ +B; ⴔ𝨨₃󠁦.𝟳𑂹\u0B82; [P1 V6]; [P1 V6] # ⴔ𝨨3.7𑂹ஂ +T; 䏈\u200C。\u200C⒈ñ±¢•; [C1 P1 V6]; [P1 V6] # 䏈.⒈ +N; 䏈\u200C。\u200C⒈ñ±¢•; [C1 P1 V6]; [C1 P1 V6] # 䏈.⒈ +T; 䏈\u200C。\u200C1.ñ±¢•; [C1 P1 V6]; [P1 V6] # 䏈.1. +N; 䏈\u200C。\u200C1.ñ±¢•; [C1 P1 V6]; [C1 P1 V6] # 䏈.1. +B; xn--eco.1.xn--ms39a; [V6]; [V6] +B; xn--0ug491l.xn--1-rgn.xn--ms39a; [C1 V6]; [C1 V6] # 䏈.1. +B; xn--eco.xn--tsh21126d; [V6]; [V6] +B; xn--0ug491l.xn--0ug88oot66q; [C1 V6]; [C1 V6] # 䏈.⒈ +T; 1\uAAF6ß𑲥。\u1DD8; [V5]; [V5] # 1꫶ß𑲥.ᷘ +N; 1\uAAF6ß𑲥。\u1DD8; [V5]; [V5] # 1꫶ß𑲥.ᷘ +T; 1\uAAF6ß𑲥。\u1DD8; [V5]; [V5] # 1꫶ß𑲥.ᷘ +N; 1\uAAF6ß𑲥。\u1DD8; [V5]; [V5] # 1꫶ß𑲥.ᷘ +B; 1\uAAF6SS𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; 1\uAAF6ss𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; 1\uAAF6Ss𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; xn--1ss-ir6ln166b.xn--weg; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; xn--1-qfa2471kdb0d.xn--weg; [V5]; [V5] # 1꫶ß𑲥.ᷘ +B; 1\uAAF6SS𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; 1\uAAF6ss𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +B; 1\uAAF6Ss𑲥。\u1DD8; [V5]; [V5] # 1ê«¶ss𑲥.ᷘ +T; \u200Dñ«¶©ðžª¯\u0CCD。\u077C⒈; [B1 C2 P1 V6]; [B5 B6 P1 V6] # ್.ݼ⒈ +N; \u200Dñ«¶©ðžª¯\u0CCD。\u077C⒈; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ್.ݼ⒈ +T; \u200Dñ«¶©ðžª¯\u0CCD。\u077C1.; [B1 C2 P1 V6]; [B5 B6 P1 V6] # ್.ݼ1. +N; \u200Dñ«¶©ðžª¯\u0CCD。\u077C1.; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ್.ݼ1. +B; xn--8tc9875v5is1a.xn--1-g6c.; [B5 B6 V6]; [B5 B6 V6] # ್.ݼ1. +B; xn--8tc969gzn94a4lm8a.xn--1-g6c.; [B1 C2 V6]; [B1 C2 V6] # ್.ݼ1. +B; xn--8tc9875v5is1a.xn--dqb689l; [B5 B6 V6]; [B5 B6 V6] # ್.ݼ⒈ +B; xn--8tc969gzn94a4lm8a.xn--dqb689l; [B1 C2 V6]; [B1 C2 V6] # ್.ݼ⒈ +B; \u1AB6.𞤳ò“¢–ò»‰’\u07D7; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # ᪶.𞤳ߗ +B; \u1AB6.𞤳ò“¢–ò»‰’\u07D7; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # ᪶.𞤳ߗ +B; \u1AB6.𞤑ò“¢–ò»‰’\u07D7; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # ᪶.𞤳ߗ +B; xn--zqf.xn--ysb9657vuiz5bj0ep; [B1 B2 B3 B6 V5 V6]; [B1 B2 B3 B6 V5 V6] # ᪶.𞤳ߗ +B; \u1AB6.𞤑ò“¢–ò»‰’\u07D7; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # ᪶.𞤳ߗ +B; \u0842𞩚⒈.󠬌8ò³\u0770; [B1 P1 V6]; [B1 P1 V6] # ࡂ⒈.8ݰ +B; \u0842𞩚1..󠬌8ò³\u0770; [B1 P1 V6 A4_2]; [B1 P1 V6 A4_2] # ࡂ1..8ݰ +B; xn--1-rid26318a..xn--8-s5c22427ox454a; [B1 V6 A4_2]; [B1 V6 A4_2] # ࡂ1..8ݰ +B; xn--0vb095ldg52a.xn--8-s5c22427ox454a; [B1 V6]; [B1 V6] # ࡂ⒈.8ݰ +B; \u0361𐫫\u0369ᡷ。-󠰛鞰; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ͡𐫫ͩᡷ.-鞰 +B; xn--cvaq482npv5t.xn----yg7dt1332g; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ͡𐫫ͩᡷ.-鞰 +T; -.\u0ACD剘ß𐫃; [B1 V3 V5]; [B1 V3 V5] # -.્剘ß𐫃 +N; -.\u0ACD剘ß𐫃; [B1 V3 V5]; [B1 V3 V5] # -.્剘ß𐫃 +B; -.\u0ACD剘SS𐫃; [B1 V3 V5]; [B1 V3 V5] # -.્剘ss𐫃 +B; -.\u0ACD剘ss𐫃; [B1 V3 V5]; [B1 V3 V5] # -.્剘ss𐫃 +B; -.\u0ACD剘Ss𐫃; [B1 V3 V5]; [B1 V3 V5] # -.્剘ss𐫃 +B; -.xn--ss-bqg4734erywk; [B1 V3 V5]; [B1 V3 V5] # -.્剘ss𐫃 +B; -.xn--zca791c493duf8i; [B1 V3 V5]; [B1 V3 V5] # -.્剘ß𐫃 +B; \u08FB𞵸。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ࣻ.- +B; \u08FB𞵸。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ࣻ.- +B; xn--b1b2719v.-; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ࣻ.- +B; ⒈󠈻𐹲。≠\u0603𐹽; [B1 P1 V6]; [B1 P1 V6] # ⒈𐹲.≠𐹽 +B; ⒈󠈻𐹲。=\u0338\u0603𐹽; [B1 P1 V6]; [B1 P1 V6] # ⒈𐹲.≠𐹽 +B; 1.󠈻𐹲。≠\u0603𐹽; [B1 P1 V6]; [B1 P1 V6] # 1.𐹲.≠𐹽 +B; 1.󠈻𐹲。=\u0338\u0603𐹽; [B1 P1 V6]; [B1 P1 V6] # 1.𐹲.≠𐹽 +B; 1.xn--qo0dl3077c.xn--lfb536lb35n; [B1 V6]; [B1 V6] # 1.𐹲.≠𐹽 +B; xn--tshw766f1153g.xn--lfb536lb35n; [B1 V6]; [B1 V6] # ⒈𐹲.≠𐹽 +T; 𐹢󠈚Ⴎ\u200C.㖾𐹡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹢Ⴎ.㖾𐹡 +N; 𐹢󠈚Ⴎ\u200C.㖾𐹡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # 𐹢Ⴎ.㖾𐹡 +T; 𐹢󠈚ⴎ\u200C.㖾𐹡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # 𐹢ⴎ.㖾𐹡 +N; 𐹢󠈚ⴎ\u200C.㖾𐹡; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # 𐹢ⴎ.㖾𐹡 +B; xn--5kjx323em053g.xn--pelu572d; [B1 B5 B6 V6]; [B1 B5 B6 V6] +B; xn--0ug342clq0pqxv4i.xn--pelu572d; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # 𐹢ⴎ.㖾𐹡 +B; xn--mnd9001km0o0g.xn--pelu572d; [B1 B5 B6 V6]; [B1 B5 B6 V6] +B; xn--mnd289ezj4pqxp0i.xn--pelu572d; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # 𐹢Ⴎ.㖾𐹡 +B; ò©¼—.\u07C7ᡖႳႧ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖႳႧ +B; ò©¼—.\u07C7ᡖႳႧ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖႳႧ +B; ò©¼—.\u07C7ᡖⴓⴇ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖⴓⴇ +B; ò©¼—.\u07C7ᡖႳⴇ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖႳⴇ +B; xn--te28c.xn--isb286btrgo7w; [B2 B3 V6]; [B2 B3 V6] # .߇ᡖႳⴇ +B; xn--te28c.xn--isb295fbtpmb; [B2 B3 V6]; [B2 B3 V6] # .߇ᡖⴓⴇ +B; xn--te28c.xn--isb856b9a631d; [B2 B3 V6]; [B2 B3 V6] # .߇ᡖႳႧ +B; ò©¼—.\u07C7ᡖⴓⴇ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖⴓⴇ +B; ò©¼—.\u07C7ᡖႳⴇ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # .߇ᡖႳⴇ +T; \u200Dô…‰.\u06B3\u0775; [B1 C2 P1 V6]; [P1 V6] # .ڳݵ +N; \u200Dô…‰.\u06B3\u0775; [B1 C2 P1 V6]; [B1 C2 P1 V6] # .ڳݵ +B; xn--3j78f.xn--mkb20b; [V6]; [V6] # .ڳݵ +B; xn--1ug39444n.xn--mkb20b; [B1 C2 V6]; [B1 C2 V6] # .ڳݵ +B; 𲤱⒛⾳.ꡦ⒈; [P1 V6]; [P1 V6] +B; 𲤱20.音.ꡦ1.; [P1 V6]; [P1 V6] +B; xn--20-9802c.xn--0w5a.xn--1-eg4e.; [V6]; [V6] +B; xn--dth6033bzbvx.xn--tsh9439b; [V6]; [V6] +B; \u07DC8ñ³¦“-。òž²™ð‘¿ð©¥\u09CD; [B2 B3 B5 B6 P1 V3 V6]; [B2 B3 B5 B6 P1 V3 V6] # ߜ8-.𑁿𐩥্ +B; \u07DC8ñ³¦“-。òž²™ð‘¿ð©¥\u09CD; [B2 B3 B5 B6 P1 V3 V6]; [B2 B3 B5 B6 P1 V3 V6] # ߜ8-.𑁿𐩥্ +B; xn--8--rve13079p.xn--b7b9842k42df776x; [B2 B3 B5 B6 V3 V6]; [B2 B3 B5 B6 V3 V6] # ߜ8-.𑁿𐩥্ +T; Ⴕ。۰≮ß\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ß݅ +N; Ⴕ。۰≮ß\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ß݅ +T; Ⴕ。۰<\u0338ß\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ß݅ +N; Ⴕ。۰<\u0338ß\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ß݅ +T; ⴕ。۰<\u0338ß\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ß݅ +N; ⴕ。۰<\u0338ß\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ß݅ +T; ⴕ。۰≮ß\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ß݅ +N; ⴕ。۰≮ß\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ß݅ +B; Ⴕ。۰≮SS\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ss݅ +B; Ⴕ。۰<\u0338SS\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ss݅ +B; ⴕ。۰<\u0338ss\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ss݅ +B; ⴕ。۰≮ss\u0745; [P1 V6]; [P1 V6] # ⴕ.۰≮ss݅ +B; Ⴕ。۰≮Ss\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ss݅ +B; Ⴕ。۰<\u0338Ss\u0745; [P1 V6]; [P1 V6] # Ⴕ.۰≮ss݅ +B; xn--tnd.xn--ss-jbe65aw27i; [V6]; [V6] # Ⴕ.۰≮ss݅ +B; xn--dlj.xn--ss-jbe65aw27i; [V6]; [V6] # ⴕ.۰≮ss݅ +B; xn--dlj.xn--zca912alh227g; [V6]; [V6] # ⴕ.۰≮ß݅ +B; xn--tnd.xn--zca912alh227g; [V6]; [V6] # Ⴕ.۰≮ß݅ +B; \u07E9-.𝨗꒱\u1B72; [B1 B3 V3 V5]; [B1 B3 V3 V5] # ß©-.𝨗꒱᭲ +B; xn----odd.xn--dwf8994dc8wj; [B1 B3 V3 V5]; [B1 B3 V3 V5] # ß©-.𝨗꒱᭲ +T; 𞼸\u200C.≯䕵⫧; [B1 B3 C1 P1 V6]; [B1 P1 V6] # .≯䕵⫧ +N; 𞼸\u200C.≯䕵⫧; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # .≯䕵⫧ +T; 𞼸\u200C.>\u0338䕵⫧; [B1 B3 C1 P1 V6]; [B1 P1 V6] # .≯䕵⫧ +N; 𞼸\u200C.>\u0338䕵⫧; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # .≯䕵⫧ +B; xn--sn7h.xn--hdh754ax6w; [B1 V6]; [B1 V6] +B; xn--0ugx453p.xn--hdh754ax6w; [B1 B3 C1 V6]; [B1 B3 C1 V6] # .≯䕵⫧ +T; 𐨅ß\uFC57.\u06AC۳︒; [B1 B3 P1 V5 V6]; [B1 B3 P1 V5 V6] # 𐨅ßيخ.ڬ۳︒ +N; 𐨅ß\uFC57.\u06AC۳︒; [B1 B3 P1 V5 V6]; [B1 B3 P1 V5 V6] # 𐨅ßيخ.ڬ۳︒ +T; 𐨅ß\u064A\u062E.\u06AC۳。; [B1 V5]; [B1 V5] # 𐨅ßيخ.Ú¬Û³. +N; 𐨅ß\u064A\u062E.\u06AC۳。; [B1 V5]; [B1 V5] # 𐨅ßيخ.Ú¬Û³. +B; 𐨅SS\u064A\u062E.\u06AC۳。; [B1 V5]; [B1 V5] # 𐨅ssيخ.Ú¬Û³. +B; 𐨅ss\u064A\u062E.\u06AC۳。; [B1 V5]; [B1 V5] # 𐨅ssيخ.Ú¬Û³. +B; 𐨅Ss\u064A\u062E.\u06AC۳。; [B1 V5]; [B1 V5] # 𐨅ssيخ.Ú¬Û³. +B; xn--ss-ytd5i7765l.xn--fkb6l.; [B1 V5]; [B1 V5] # 𐨅ssيخ.Ú¬Û³. +B; xn--zca23yncs877j.xn--fkb6l.; [B1 V5]; [B1 V5] # 𐨅ßيخ.Ú¬Û³. +B; 𐨅SS\uFC57.\u06AC۳︒; [B1 B3 P1 V5 V6]; [B1 B3 P1 V5 V6] # 𐨅ssيخ.ڬ۳︒ +B; 𐨅ss\uFC57.\u06AC۳︒; [B1 B3 P1 V5 V6]; [B1 B3 P1 V5 V6] # 𐨅ssيخ.ڬ۳︒ +B; 𐨅Ss\uFC57.\u06AC۳︒; [B1 B3 P1 V5 V6]; [B1 B3 P1 V5 V6] # 𐨅ssيخ.ڬ۳︒ +B; xn--ss-ytd5i7765l.xn--fkb6lp314e; [B1 B3 V5 V6]; [B1 B3 V5 V6] # 𐨅ssيخ.ڬ۳︒ +B; xn--zca23yncs877j.xn--fkb6lp314e; [B1 B3 V5 V6]; [B1 B3 V5 V6] # 𐨅ßيخ.ڬ۳︒ +B; -≮🡒\u1CED.ñ¿¾á‚¡\u0714; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≮🡒᳭.Ⴁܔ +B; -<\u0338🡒\u1CED.ñ¿¾á‚¡\u0714; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≮🡒᳭.Ⴁܔ +B; -<\u0338🡒\u1CED.ñ¿¾â´\u0714; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≮🡒᳭.ⴁܔ +B; -≮🡒\u1CED.ñ¿¾â´\u0714; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -≮🡒᳭.ⴁܔ +B; xn----44l04zxt68c.xn--enb135qf106f; [B1 V3 V6]; [B1 V3 V6] # -≮🡒᳭.ⴁܔ +B; xn----44l04zxt68c.xn--enb300c1597h; [B1 V3 V6]; [B1 V3 V6] # -≮🡒᳭.Ⴁܔ +T; 𞤨。ꡏ\u200D\u200C; [B6 C1 C2]; xn--ge6h.xn--oc9a # 𞤨.ꡏ +N; 𞤨。ꡏ\u200D\u200C; [B6 C1 C2]; [B6 C1 C2] # 𞤨.ꡏ +T; 𞤨。ꡏ\u200D\u200C; [B6 C1 C2]; xn--ge6h.xn--oc9a # 𞤨.ꡏ +N; 𞤨。ꡏ\u200D\u200C; [B6 C1 C2]; [B6 C1 C2] # 𞤨.ꡏ +T; 𞤆。ꡏ\u200D\u200C; [B6 C1 C2]; xn--ge6h.xn--oc9a # 𞤨.ꡏ +N; 𞤆。ꡏ\u200D\u200C; [B6 C1 C2]; [B6 C1 C2] # 𞤨.ꡏ +B; xn--ge6h.xn--oc9a; 𞤨.ꡏ; xn--ge6h.xn--oc9a +B; 𞤨.ꡏ; ; xn--ge6h.xn--oc9a +B; 𞤆.ꡏ; 𞤨.ꡏ; xn--ge6h.xn--oc9a +B; xn--ge6h.xn--0ugb9575h; [B6 C1 C2]; [B6 C1 C2] # 𞤨.ꡏ +T; 𞤆。ꡏ\u200D\u200C; [B6 C1 C2]; xn--ge6h.xn--oc9a # 𞤨.ꡏ +N; 𞤆。ꡏ\u200D\u200C; [B6 C1 C2]; [B6 C1 C2] # 𞤨.ꡏ +B; 󠅹𑂶.ᢌ𑂹\u0669; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𑂶.ᢌ𑂹٩ +B; 󠅹𑂶.ᢌ𑂹\u0669; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𑂶.ᢌ𑂹٩ +B; xn--b50d.xn--iib993gyp5p; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𑂶.ᢌ𑂹٩ +B; Ⅎ󠅺ñµ’。≯⾑; [P1 V6]; [P1 V6] +B; Ⅎ󠅺ñµ’。>\u0338⾑; [P1 V6]; [P1 V6] +B; Ⅎ󠅺ñµ’。≯襾; [P1 V6]; [P1 V6] +B; Ⅎ󠅺ñµ’。>\u0338襾; [P1 V6]; [P1 V6] +B; ⅎ󠅺ñµ’。>\u0338襾; [P1 V6]; [P1 V6] +B; ⅎ󠅺ñµ’。≯襾; [P1 V6]; [P1 V6] +B; xn--73g39298c.xn--hdhz171b; [V6]; [V6] +B; xn--f3g73398c.xn--hdhz171b; [V6]; [V6] +B; ⅎ󠅺ñµ’。>\u0338⾑; [P1 V6]; [P1 V6] +B; ⅎ󠅺ñµ’。≯⾑; [P1 V6]; [P1 V6] +T; ς\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # ςු٠.- +N; ς\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # ςු٠.- +T; ς\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # ςු٠.- +N; ς\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # ςු٠.- +T; Σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # σු٠.- +N; Σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # σු٠.- +T; σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # σු٠.- +N; σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # σු٠.- +B; xn--4xa25ks2j.-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # σු٠.- +B; xn--4xa25ks2jenu.-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # σු٠.- +B; xn--3xa45ks2jenu.-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # ςු٠.- +T; Σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # σු٠.- +N; Σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # σු٠.- +T; σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 V3] # σු٠.- +N; σ\u200D\u0DD4\u0660。-; [B1 B5 B6 C2 V3]; [B1 B5 B6 C2 V3] # σු٠.- +T; \u200C.ßႩ-; [C1 P1 V3 V6]; [P1 V3 V6 A4_2] # .ßႩ- +N; \u200C.ßႩ-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .ßႩ- +T; \u200C.ßⴉ-; [C1 V3]; [V3 A4_2] # .ßⴉ- +N; \u200C.ßⴉ-; [C1 V3]; [C1 V3] # .ßⴉ- +T; \u200C.SSႩ-; [C1 P1 V3 V6]; [P1 V3 V6 A4_2] # .ssႩ- +N; \u200C.SSႩ-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # .ssႩ- +T; \u200C.ssⴉ-; [C1 V3]; [V3 A4_2] # .ssⴉ- +N; \u200C.ssⴉ-; [C1 V3]; [C1 V3] # .ssⴉ- +T; \u200C.Ssⴉ-; [C1 V3]; [V3 A4_2] # .ssⴉ- +N; \u200C.Ssⴉ-; [C1 V3]; [C1 V3] # .ssⴉ- +B; .xn--ss--bi1b; [V3 A4_2]; [V3 A4_2] +B; xn--0ug.xn--ss--bi1b; [C1 V3]; [C1 V3] # .ssⴉ- +B; .xn--ss--4rn; [V3 V6 A4_2]; [V3 V6 A4_2] +B; xn--0ug.xn--ss--4rn; [C1 V3 V6]; [C1 V3 V6] # .ssႩ- +B; xn--0ug.xn----pfa2305a; [C1 V3]; [C1 V3] # .ßⴉ- +B; xn--0ug.xn----pfa042j; [C1 V3 V6]; [C1 V3 V6] # .ßႩ- +B; 󍭲𐫍㓱。⾑; [B5 P1 V6]; [B5 P1 V6] +B; 󍭲𐫍㓱。襾; [B5 P1 V6]; [B5 P1 V6] +B; xn--u7kt691dlj09f.xn--9v2a; [B5 V6]; [B5 V6] +T; \u06A0𐮋𐹰≮。≯󠦗\u200D; [B1 B3 C2 P1 V6]; [B1 B3 P1 V6] # ڠ𐮋𐹰≮.≯ +N; \u06A0𐮋𐹰≮。≯󠦗\u200D; [B1 B3 C2 P1 V6]; [B1 B3 C2 P1 V6] # ڠ𐮋𐹰≮.≯ +T; \u06A0𐮋𐹰<\u0338。>\u0338󠦗\u200D; [B1 B3 C2 P1 V6]; [B1 B3 P1 V6] # ڠ𐮋𐹰≮.≯ +N; \u06A0𐮋𐹰<\u0338。>\u0338󠦗\u200D; [B1 B3 C2 P1 V6]; [B1 B3 C2 P1 V6] # ڠ𐮋𐹰≮.≯ +B; xn--2jb053lf13nyoc.xn--hdh08821l; [B1 B3 V6]; [B1 B3 V6] # ڠ𐮋𐹰≮.≯ +B; xn--2jb053lf13nyoc.xn--1ugx6gc8096c; [B1 B3 C2 V6]; [B1 B3 C2 V6] # ڠ𐮋𐹰≮.≯ +B; 𝟞。ñƒ°¶\u0777\u08B0⩋; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 6.ݷࢰ⩋ +B; 6。ñƒ°¶\u0777\u08B0⩋; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 6.ݷࢰ⩋ +B; 6.xn--7pb04do15eq748f; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 6.ݷࢰ⩋ +B; -\uFCFD。𑇀𑍴; [B1 V3 V5]; [B1 V3 V5] # -شى.𑇀𑍴 +B; -\uFCFD。𑇀𑍴; [B1 V3 V5]; [B1 V3 V5] # -شى.𑇀𑍴 +B; -\u0634\u0649。𑇀𑍴; [B1 V3 V5]; [B1 V3 V5] # -شى.𑇀𑍴 +B; xn----qnc7d.xn--wd1d62a; [B1 V3 V5]; [B1 V3 V5] # -شى.𑇀𑍴 +T; \u200C󠊶𝟏.\u0D43òª¥ð¹¬óŠ“¶; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 1.ൃ𐹬 +N; \u200C󠊶𝟏.\u0D43òª¥ð¹¬óŠ“¶; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 1.ൃ𐹬 +T; \u200C󠊶1.\u0D43òª¥ð¹¬óŠ“¶; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 1.ൃ𐹬 +N; \u200C󠊶1.\u0D43òª¥ð¹¬óŠ“¶; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 1.ൃ𐹬 +B; xn--1-f521m.xn--mxc0872kcu37dnmem; [B1 V5 V6]; [B1 V5 V6] # 1.ൃ𐹬 +B; xn--1-rgnu0071n.xn--mxc0872kcu37dnmem; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 1.ൃ𐹬 +T; 齙--𝟰.ß; 齙--4.ß; xn----4-p16k.ss +N; 齙--𝟰.ß; 齙--4.ß; xn----4-p16k.xn--zca +T; 齙--4.ß; ; xn----4-p16k.ss +N; 齙--4.ß; ; xn----4-p16k.xn--zca +B; 齙--4.SS; 齙--4.ss; xn----4-p16k.ss +B; 齙--4.ss; ; xn----4-p16k.ss +B; 齙--4.Ss; 齙--4.ss; xn----4-p16k.ss +B; xn----4-p16k.ss; 齙--4.ss; xn----4-p16k.ss +B; xn----4-p16k.xn--zca; 齙--4.ß; xn----4-p16k.xn--zca +B; 齙--𝟰.SS; 齙--4.ss; xn----4-p16k.ss +B; 齙--𝟰.ss; 齙--4.ss; xn----4-p16k.ss +B; 齙--𝟰.Ss; 齙--4.ss; xn----4-p16k.ss +T; \u1BF2.𐹢𞀖\u200C; [B1 C1 V5]; [B1 V5] # ᯲.𐹢𞀖 +N; \u1BF2.𐹢𞀖\u200C; [B1 C1 V5]; [B1 C1 V5] # ᯲.𐹢𞀖 +B; xn--0zf.xn--9n0d2296a; [B1 V5]; [B1 V5] # ᯲.𐹢𞀖 +B; xn--0zf.xn--0ug9894grqqf; [B1 C1 V5]; [B1 C1 V5] # ᯲.𐹢𞀖 +T; 󃲙󠋘。\uDEDE-\u200D; [C2 P1 V6]; [P1 V3 V6 A3] # .- +N; 󃲙󠋘。\uDEDE-\u200D; [C2 P1 V6]; [C2 P1 V6 A3] # .- +T; 󃲙󠋘。\uDEDE-\u200D; [C2 P1 V6]; [P1 V3 V6 A3] # .- +N; 󃲙󠋘。\uDEDE-\u200D; [C2 P1 V6]; [C2 P1 V6 A3] # .- +B; xn--ct86d8w51a.\uDEDE-; [P1 V3 V6]; [P1 V3 V6 A3] # .- +B; XN--CT86D8W51A.\uDEDE-; [P1 V3 V6]; [P1 V3 V6 A3] # .- +B; Xn--Ct86d8w51a.\uDEDE-; [P1 V3 V6]; [P1 V3 V6 A3] # .- +T; xn--ct86d8w51a.\uDEDE-\u200D; [C2 P1 V6]; [P1 V3 V6 A3] # .- +N; xn--ct86d8w51a.\uDEDE-\u200D; [C2 P1 V6]; [C2 P1 V6 A3] # .- +T; XN--CT86D8W51A.\uDEDE-\u200D; [C2 P1 V6]; [P1 V3 V6 A3] # .- +N; XN--CT86D8W51A.\uDEDE-\u200D; [C2 P1 V6]; [C2 P1 V6 A3] # .- +T; Xn--Ct86d8w51a.\uDEDE-\u200D; [C2 P1 V6]; [P1 V3 V6 A3] # .- +N; Xn--Ct86d8w51a.\uDEDE-\u200D; [C2 P1 V6]; [C2 P1 V6 A3] # .- +B; \u1A60.𞵷-𝪩悎; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # á© .-𝪩悎 +B; \u1A60.𞵷-𝪩悎; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # á© .-𝪩悎 +B; xn--jof.xn----gf4bq282iezpa; [B1 B2 B3 B6 V5 V6]; [B1 B2 B3 B6 V5 V6] # á© .-𝪩悎 +B; 𛜯󠊛.𞤳ñ¥¾; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] +B; 𛜯󠊛.𞤳ñ¥¾; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] +B; 𛜯󠊛.𞤑ñ¥¾; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] +B; xn--xx5gy2741c.xn--re6hw266j; [B2 B3 B6 V6]; [B2 B3 B6 V6] +B; 𛜯󠊛.𞤑ñ¥¾; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] +B; \u071C𐫒\u062E.𐋲; [B1]; [B1] # ܜ𐫒خ.𐋲 +B; xn--tgb98b8643d.xn--m97c; [B1]; [B1] # ܜ𐫒خ.𐋲 +B; 𐼑𞤓\u0637\u08E2.\uDF56; [P1 V6]; [P1 V6 A3] # 𞤵ط. +B; 𐼑𞤵\u0637\u08E2.\uDF56; [P1 V6]; [P1 V6 A3] # 𞤵ط. +B; xn--2gb08k9w69agm0g.\uDF56; [P1 V6]; [P1 V6 A3] # 𞤵ط. +B; XN--2GB08K9W69AGM0G.\uDF56; [P1 V6]; [P1 V6 A3] # 𞤵ط. +B; Xn--2Gb08k9w69agm0g.\uDF56; [P1 V6]; [P1 V6 A3] # 𞤵ط. +B; Ↄ。\u0A4D\u1CD4𞷣; [B1 P1 V5 V6]; [B1 P1 V5 V6] # Ↄ.᳔੍ +B; Ↄ。\u1CD4\u0A4D𞷣; [B1 P1 V5 V6]; [B1 P1 V5 V6] # Ↄ.᳔੍ +B; ↄ。\u1CD4\u0A4D𞷣; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ↄ.᳔੍ +B; xn--r5g.xn--ybc995g0835a; [B1 V5 V6]; [B1 V5 V6] # ↄ.᳔੍ +B; xn--q5g.xn--ybc995g0835a; [B1 V5 V6]; [B1 V5 V6] # Ↄ.᳔੍ +B; ↄ。\u0A4D\u1CD4𞷣; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ↄ.᳔੍ +B; 󠪢-。ò›‚â‰®ð‘œ«; [P1 V3 V6]; [P1 V3 V6] +B; 󠪢-。ò›‚<\u0338𑜫; [P1 V3 V6]; [P1 V3 V6] +B; xn----bh61m.xn--gdhz157g0em1d; [V3 V6]; [V3 V6] +T; \u200C󠉹\u200D。òŒ¿§â‰®á‚©; [C1 C2 P1 V6]; [P1 V6] # .≮Ⴉ +N; \u200C󠉹\u200D。òŒ¿§â‰®á‚©; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .≮Ⴉ +T; \u200C󠉹\u200D。òŒ¿§<\u0338Ⴉ; [C1 C2 P1 V6]; [P1 V6] # .≮Ⴉ +N; \u200C󠉹\u200D。òŒ¿§<\u0338Ⴉ; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .≮Ⴉ +T; \u200C󠉹\u200D。òŒ¿§<\u0338ⴉ; [C1 C2 P1 V6]; [P1 V6] # .≮ⴉ +N; \u200C󠉹\u200D。òŒ¿§<\u0338ⴉ; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .≮ⴉ +T; \u200C󠉹\u200D。òŒ¿§â‰®â´‰; [C1 C2 P1 V6]; [P1 V6] # .≮ⴉ +N; \u200C󠉹\u200D。òŒ¿§â‰®â´‰; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .≮ⴉ +B; xn--3n36e.xn--gdh992byu01p; [V6]; [V6] +B; xn--0ugc90904y.xn--gdh992byu01p; [C1 C2 V6]; [C1 C2 V6] # .≮ⴉ +B; xn--3n36e.xn--hnd112gpz83n; [V6]; [V6] +B; xn--0ugc90904y.xn--hnd112gpz83n; [C1 C2 V6]; [C1 C2 V6] # .≮Ⴉ +B; 𐹯-𑄴\u08BC。︒䖐⾆; [B1 P1 V6]; [B1 P1 V6] # 𐹯-𑄴ࢼ.︒䖐舌 +B; 𐹯-𑄴\u08BC。。䖐舌; [B1 A4_2]; [B1 A4_2] # 𐹯-𑄴ࢼ..䖐舌 +B; xn----rpd7902rclc..xn--fpo216m; [B1 A4_2]; [B1 A4_2] # 𐹯-𑄴ࢼ..䖐舌 +B; xn----rpd7902rclc.xn--fpo216mn07e; [B1 V6]; [B1 V6] # 𐹯-𑄴ࢼ.︒䖐舌 +B; 𝪞Ⴐ。쪡; [P1 V5 V6]; [P1 V5 V6] +B; 𝪞Ⴐ。쪡; [P1 V5 V6]; [P1 V5 V6] +B; 𝪞Ⴐ。쪡; [P1 V5 V6]; [P1 V5 V6] +B; 𝪞Ⴐ。쪡; [P1 V5 V6]; [P1 V5 V6] +B; 𝪞ⴐ。쪡; [V5]; [V5] +B; 𝪞ⴐ。쪡; [V5]; [V5] +B; xn--7kj1858k.xn--pi6b; [V5]; [V5] +B; xn--ond3755u.xn--pi6b; [V5 V6]; [V5 V6] +B; 𝪞ⴐ。쪡; [V5]; [V5] +B; 𝪞ⴐ。쪡; [V5]; [V5] +B; \u0E3A쩁𐹬.ô‹‰³; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ฺ쩁𐹬. +B; \u0E3A쩁𐹬.ô‹‰³; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ฺ쩁𐹬. +B; xn--o4c4837g2zvb.xn--5f70g; [B1 V5 V6]; [B1 V5 V6] # ฺ쩁𐹬. +T; ᡅ0\u200C。⎢󤨄; [C1 P1 V6]; [P1 V6] # ᡅ0.⎢ +N; ᡅ0\u200C。⎢󤨄; [C1 P1 V6]; [C1 P1 V6] # ᡅ0.⎢ +T; ᡅ0\u200C。⎢󤨄; [C1 P1 V6]; [P1 V6] # ᡅ0.⎢ +N; ᡅ0\u200C。⎢󤨄; [C1 P1 V6]; [C1 P1 V6] # ᡅ0.⎢ +B; xn--0-z6j.xn--8lh28773l; [V6]; [V6] +B; xn--0-z6jy93b.xn--8lh28773l; [C1 V6]; [C1 V6] # ᡅ0.⎢ +T; 𲮚9ꍩ\u17D3.\u200Dß; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ß +N; 𲮚9ꍩ\u17D3.\u200Dß; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ß +T; 𲮚9ꍩ\u17D3.\u200Dß; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ß +N; 𲮚9ꍩ\u17D3.\u200Dß; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ß +T; 𲮚9ꍩ\u17D3.\u200DSS; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200DSS; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +T; 𲮚9ꍩ\u17D3.\u200Dss; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200Dss; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +T; 𲮚9ꍩ\u17D3.\u200DSs; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200DSs; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +B; xn--9-i0j5967eg3qz.ss; [V6]; [V6] # 9ꍩ៓.ss +B; xn--9-i0j5967eg3qz.xn--ss-l1t; [C2 V6]; [C2 V6] # 9ꍩ៓.ss +B; xn--9-i0j5967eg3qz.xn--zca770n; [C2 V6]; [C2 V6] # 9ꍩ៓.ß +T; 𲮚9ꍩ\u17D3.\u200DSS; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200DSS; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +T; 𲮚9ꍩ\u17D3.\u200Dss; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200Dss; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +T; 𲮚9ꍩ\u17D3.\u200DSs; [C2 P1 V6]; [P1 V6] # 9ꍩ៓.ss +N; 𲮚9ꍩ\u17D3.\u200DSs; [C2 P1 V6]; [C2 P1 V6] # 9ꍩ៓.ss +B; ꗷ𑆀.\u075D𐩒; ; xn--ju8a625r.xn--hpb0073k; NV8 # ꗷ𑆀.ݝ𐩒 +B; xn--ju8a625r.xn--hpb0073k; ꗷ𑆀.\u075D𐩒; xn--ju8a625r.xn--hpb0073k; NV8 # ꗷ𑆀.ݝ𐩒 +B; ⒐≯-。︒ò©‘£-ñž› ; [P1 V3 V6]; [P1 V3 V6] +B; ⒐>\u0338-。︒ò©‘£-ñž› ; [P1 V3 V6]; [P1 V3 V6] +B; 9.≯-。。ò©‘£-ñž› ; [P1 V3 V6 A4_2]; [P1 V3 V6 A4_2] +B; 9.>\u0338-。。ò©‘£-ñž› ; [P1 V3 V6 A4_2]; [P1 V3 V6 A4_2] +B; 9.xn----ogo..xn----xj54d1s69k; [V3 V6 A4_2]; [V3 V6 A4_2] +B; xn----ogot9g.xn----n89hl0522az9u2a; [V3 V6]; [V3 V6] +B; òˆªš\u0CE3Ⴡ󠢏.\u061D; [B6 P1 V6]; [B6 P1 V6] # ೣჁ. +B; òˆªš\u0CE3Ⴡ󠢏.\u061D; [B6 P1 V6]; [B6 P1 V6] # ೣჁ. +B; òˆªš\u0CE3ⴡ󠢏.\u061D; [B6 P1 V6]; [B6 P1 V6] # ೣⴡ. +B; xn--vuc226n8n28lmju7a.xn--cgb; [B6 V6]; [B6 V6] # ೣⴡ. +B; xn--vuc49qvu85xmju7a.xn--cgb; [B6 V6]; [B6 V6] # ೣჁ. +B; òˆªš\u0CE3ⴡ󠢏.\u061D; [B6 P1 V6]; [B6 P1 V6] # ೣⴡ. +B; \u1DEB。𐋩\u0638-𐫮; [B1 B3 B6 V5]; [B1 B3 B6 V5] # á·«.𐋩ظ-𐫮 +B; xn--gfg.xn----xnc0815qyyg; [B1 B3 B6 V5]; [B1 B3 B6 V5] # á·«.𐋩ظ-𐫮 +B; 싇。⾇𐳋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。⾇𐳋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。舛𐳋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。舛𐳋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。舛𐳋ⴝ; [B5]; [B5] +B; 싇。舛𐳋ⴝ; [B5]; [B5] +B; 싇。舛𐲋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。舛𐲋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。舛𐲋ⴝ; [B5]; [B5] +B; 싇。舛𐲋ⴝ; [B5]; [B5] +B; xn--9u4b.xn--llj123yh74e; [B5]; [B5] +B; xn--9u4b.xn--1nd7519ch79d; [B5 V6]; [B5 V6] +B; 싇。⾇𐳋ⴝ; [B5]; [B5] +B; 싇。⾇𐳋ⴝ; [B5]; [B5] +B; 싇。⾇𐲋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。⾇𐲋Ⴝ; [B5 P1 V6]; [B5 P1 V6] +B; 싇。⾇𐲋ⴝ; [B5]; [B5] +B; 싇。⾇𐲋ⴝ; [B5]; [B5] +T; 𐹠ς。\u200C\u06BFჀ; [B1 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐹠ς.ڿჀ +N; 𐹠ς。\u200C\u06BFჀ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹠ς.ڿჀ +T; 𐹠ς。\u200C\u06BFâ´ ; [B1 C1]; [B1 B2 B3] # 𐹠ς.Ú¿â´  +N; 𐹠ς。\u200C\u06BFâ´ ; [B1 C1]; [B1 C1] # 𐹠ς.Ú¿â´  +T; 𐹠Σ。\u200C\u06BFჀ; [B1 C1 P1 V6]; [B1 B2 B3 P1 V6] # 𐹠σ.ڿჀ +N; 𐹠Σ。\u200C\u06BFჀ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 𐹠σ.ڿჀ +T; 𐹠σ。\u200C\u06BFâ´ ; [B1 C1]; [B1 B2 B3] # 𐹠σ.Ú¿â´  +N; 𐹠σ。\u200C\u06BFâ´ ; [B1 C1]; [B1 C1] # 𐹠σ.Ú¿â´  +B; xn--4xa9167k.xn--ykb467q; [B1 B2 B3]; [B1 B2 B3] # 𐹠σ.Ú¿â´  +B; xn--4xa9167k.xn--ykb760k9hj; [B1 C1]; [B1 C1] # 𐹠σ.Ú¿â´  +B; xn--4xa9167k.xn--ykb632c; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 𐹠σ.ڿჀ +B; xn--4xa9167k.xn--ykb632cvxm; [B1 C1 V6]; [B1 C1 V6] # 𐹠σ.ڿჀ +B; xn--3xa1267k.xn--ykb760k9hj; [B1 C1]; [B1 C1] # 𐹠ς.Ú¿â´  +B; xn--3xa1267k.xn--ykb632cvxm; [B1 C1 V6]; [B1 C1 V6] # 𐹠ς.ڿჀ +T; ò‡’\u200C\u0604.\u069A-ß; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # .ښ-ß +N; ò‡’\u200C\u0604.\u069A-ß; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # .ښ-ß +T; ò‡’\u200C\u0604.\u069A-SS; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # .ښ-ss +N; ò‡’\u200C\u0604.\u069A-SS; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # .ښ-ss +T; ò‡’\u200C\u0604.\u069A-ss; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # .ښ-ss +N; ò‡’\u200C\u0604.\u069A-ss; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # .ښ-ss +T; ò‡’\u200C\u0604.\u069A-Ss; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # .ښ-ss +N; ò‡’\u200C\u0604.\u069A-Ss; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # .ښ-ss +B; xn--mfb98261i.xn---ss-sdf; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # .ښ-ss +B; xn--mfb144kqo32m.xn---ss-sdf; [B2 B3 B5 B6 C1 V6]; [B2 B3 B5 B6 C1 V6] # .ښ-ss +B; xn--mfb144kqo32m.xn----qfa315b; [B2 B3 B5 B6 C1 V6]; [B2 B3 B5 B6 C1 V6] # .ښ-ß +T; \u200C\u200D\u17B5\u067A.-\uFBB0󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V5 V6] # Ùº.-ۓ +N; \u200C\u200D\u17B5\u067A.-\uFBB0󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # Ùº.-ۓ +T; \u200C\u200D\u17B5\u067A.-\u06D3󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V5 V6] # Ùº.-ۓ +N; \u200C\u200D\u17B5\u067A.-\u06D3󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # Ùº.-ۓ +T; \u200C\u200D\u17B5\u067A.-\u06D2\u0654󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V5 V6] # Ùº.-ۓ +N; \u200C\u200D\u17B5\u067A.-\u06D2\u0654󅄞𐸚; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # Ùº.-ۓ +B; xn--zib539f.xn----twc1133r17r6g; [B1 V3 V5 V6]; [B1 V3 V5 V6] # Ùº.-ۓ +B; xn--zib539f8igea.xn----twc1133r17r6g; [B1 C1 C2 V3 V6]; [B1 C1 C2 V3 V6] # Ùº.-ۓ +B; ò¡¶±ï½¡ð®¬â‰ ; [B3 P1 V6]; [B3 P1 V6] +B; ò¡¶±ï½¡ð®¬=\u0338; [B3 P1 V6]; [B3 P1 V6] +B; ò¡¶±ã€‚𐮬≠; [B3 P1 V6]; [B3 P1 V6] +B; ò¡¶±ã€‚𐮬=\u0338; [B3 P1 V6]; [B3 P1 V6] +B; xn--dd55c.xn--1ch3003g; [B3 V6]; [B3 V6] +B; \u0FB2𞶅。𐹮𐹷덝۵; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ྲ.𐹮𐹷덝۵ +B; \u0FB2𞶅。𐹮𐹷덝۵; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ྲ.𐹮𐹷덝۵ +B; \u0FB2𞶅。𐹮𐹷덝۵; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ྲ.𐹮𐹷덝۵ +B; \u0FB2𞶅。𐹮𐹷덝۵; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ྲ.𐹮𐹷덝۵ +B; xn--fgd0675v.xn--imb5839fidpcbba; [B1 V5 V6]; [B1 V5 V6] # ྲ.𐹮𐹷덝۵ +T; Ⴏ󠅋-.\u200DႩ; [C2 P1 V3 V6]; [P1 V3 V6] # Ⴏ-.Ⴉ +N; Ⴏ󠅋-.\u200DႩ; [C2 P1 V3 V6]; [C2 P1 V3 V6] # Ⴏ-.Ⴉ +T; Ⴏ󠅋-.\u200DႩ; [C2 P1 V3 V6]; [P1 V3 V6] # Ⴏ-.Ⴉ +N; Ⴏ󠅋-.\u200DႩ; [C2 P1 V3 V6]; [C2 P1 V3 V6] # Ⴏ-.Ⴉ +T; ⴏ󠅋-.\u200Dⴉ; [C2 V3]; [V3] # ⴏ-.ⴉ +N; ⴏ󠅋-.\u200Dⴉ; [C2 V3]; [C2 V3] # ⴏ-.ⴉ +B; xn----3vs.xn--0kj; [V3]; [V3] +B; xn----3vs.xn--1ug532c; [C2 V3]; [C2 V3] # ⴏ-.ⴉ +B; xn----00g.xn--hnd; [V3 V6]; [V3 V6] +B; xn----00g.xn--hnd399e; [C2 V3 V6]; [C2 V3 V6] # Ⴏ-.Ⴉ +T; ⴏ󠅋-.\u200Dⴉ; [C2 V3]; [V3] # ⴏ-.ⴉ +N; ⴏ󠅋-.\u200Dⴉ; [C2 V3]; [C2 V3] # ⴏ-.ⴉ +B; ⇧𐨏󠾈󯶅。\u0600󠈵󠆉; [B1 P1 V6]; [B1 P1 V6] # ⇧𐨏. +B; xn--l8g5552g64t4g46xf.xn--ifb08144p; [B1 V6]; [B1 V6] # ⇧𐨏. +B; ≠𐮂.↑🄇⒈; [B1 P1 V6]; [B1 P1 V6] +B; =\u0338𐮂.↑🄇⒈; [B1 P1 V6]; [B1 P1 V6] +B; ≠𐮂.↑6,1.; [B1 P1 V6]; [B1 P1 V6] +B; =\u0338𐮂.↑6,1.; [B1 P1 V6]; [B1 P1 V6] +B; xn--1chy492g.xn--6,1-pw1a.; [B1 P1 V6]; [B1 P1 V6] +B; xn--1chy492g.xn--45gx9iuy44d; [B1 V6]; [B1 V6] +T; 𝩏󠲉ß.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝩏ß.ᢤ𐹫 +N; 𝩏󠲉ß.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # 𝩏ß.ᢤ𐹫 +T; 𝩏󠲉SS.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +N; 𝩏󠲉SS.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +T; 𝩏󠲉ss.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +N; 𝩏󠲉ss.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +T; 𝩏󠲉Ss.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +N; 𝩏󠲉Ss.ᢤò„¦Œ\u200C𐹫; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # 𝩏ss.ᢤ𐹫 +B; xn--ss-zb11ap1427e.xn--ubf2596jbt61c; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] +B; xn--ss-zb11ap1427e.xn--ubf609atw1tynn3d; [B1 B5 B6 C1 V5 V6]; [B1 B5 B6 C1 V5 V6] # 𝩏ss.ᢤ𐹫 +B; xn--zca3153vupz3e.xn--ubf609atw1tynn3d; [B1 B5 B6 C1 V5 V6]; [B1 B5 B6 C1 V5 V6] # 𝩏ß.ᢤ𐹫 +T; ß𐵳ñ—˜á‚§ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßႧ.ꙺ +N; ß𐵳ñ—˜á‚§ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßႧ.ꙺ +T; ß𐵳ñ—˜á‚§ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßႧ.ꙺ +N; ß𐵳ñ—˜á‚§ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßႧ.ꙺ +T; ß𐵳ñ—˜â´‡ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßⴇ.ꙺ +N; ß𐵳ñ—˜â´‡ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßⴇ.ꙺ +B; SS𐵳ñ—˜á‚§ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssႧ.ꙺ +B; ss𐵳ñ—˜â´‡ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssⴇ.ꙺ +B; Ss𐵳ñ—˜á‚§ã€‚\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssႧ.ꙺ +B; xn--ss-rek7420r4hs7b.xn--9x8a; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ssႧ.ꙺ +B; xn--ss-e61ar955h4hs7b.xn--9x8a; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ssⴇ.ꙺ +B; xn--zca227tpy4lkns1b.xn--9x8a; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ßⴇ.ꙺ +B; xn--zca491fci5qkn79a.xn--9x8a; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # ßႧ.ꙺ +T; ß𐵳ñ—˜â´‡ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßⴇ.ꙺ +N; ß𐵳ñ—˜â´‡ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ßⴇ.ꙺ +B; SS𐵳ñ—˜á‚§ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssႧ.ꙺ +B; ss𐵳ñ—˜â´‡ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssⴇ.ꙺ +B; Ss𐵳ñ—˜á‚§ï½¡\uA67A; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # ssႧ.ꙺ +B; \u1714。󠆣-𑋪; [V3 V5]; [V3 V5] # ᜔.-𑋪 +B; xn--fze.xn----ly8i; [V3 V5]; [V3 V5] # ᜔.-𑋪 +T; \uABE8-.ò¨œ\u05BDß; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.ֽß +N; \uABE8-.ò¨œ\u05BDß; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.ֽß +T; \uABE8-.ò¨œ\u05BDß; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.ֽß +N; \uABE8-.ò¨œ\u05BDß; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.ֽß +B; \uABE8-.ò¨œ\u05BDSS; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; \uABE8-.ò¨œ\u05BDss; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; \uABE8-.ò¨œ\u05BDSs; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; xn----pw5e.xn--ss-7jd10716y; [V3 V5 V6]; [V3 V5 V6] # ꯨ-.Ö½ss +B; xn----pw5e.xn--zca50wfv060a; [V3 V5 V6]; [V3 V5 V6] # ꯨ-.ֽß +B; \uABE8-.ò¨œ\u05BDSS; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; \uABE8-.ò¨œ\u05BDss; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; \uABE8-.ò¨œ\u05BDSs; [P1 V3 V5 V6]; [P1 V3 V5 V6] # ꯨ-.Ö½ss +B; ᡓ-≮。\u066B󠅱ᡄ; [B1 B6 P1 V6]; [B1 B6 P1 V6] # ᡓ-≮.٫ᡄ +B; ᡓ-<\u0338。\u066B󠅱ᡄ; [B1 B6 P1 V6]; [B1 B6 P1 V6] # ᡓ-≮.٫ᡄ +B; xn----s7j866c.xn--kib252g; [B1 B6 V6]; [B1 B6 V6] # ᡓ-≮.٫ᡄ +B; 𝟥♮𑜫\u08ED.\u17D2𑜫8󠆏; [V5]; [V5] # 3♮𑜫࣭.្𑜫8 +B; 3♮𑜫\u08ED.\u17D2𑜫8󠆏; [V5]; [V5] # 3♮𑜫࣭.្𑜫8 +B; xn--3-ksd277tlo7s.xn--8-f0jx021l; [V5]; [V5] # 3♮𑜫࣭.្𑜫8 +T; -。ò•Œ€\u200D❡; [C2 P1 V3 V6]; [P1 V3 V6] # -.❡ +N; -。ò•Œ€\u200D❡; [C2 P1 V3 V6]; [C2 P1 V3 V6] # -.❡ +T; -。ò•Œ€\u200D❡; [C2 P1 V3 V6]; [P1 V3 V6] # -.❡ +N; -。ò•Œ€\u200D❡; [C2 P1 V3 V6]; [C2 P1 V3 V6] # -.❡ +B; -.xn--nei54421f; [V3 V6]; [V3 V6] +B; -.xn--1ug800aq795s; [C2 V3 V6]; [C2 V3 V6] # -.❡ +B; 𝟓☱𝟐ò¥°µï½¡ðª®ñ¡³; [P1 V5 V6]; [P1 V5 V6] +B; 5☱2ò¥°µã€‚𝪮ñ¡³; [P1 V5 V6]; [P1 V5 V6] +B; xn--52-dwx47758j.xn--kd3hk431k; [V5 V6]; [V5 V6] +B; -.-├ò–¦£; [P1 V3 V6]; [P1 V3 V6] +B; -.xn----ukp70432h; [V3 V6]; [V3 V6] +T; \u05A5\u076D。\u200D󠀘; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ֥ݭ. +N; \u05A5\u076D。\u200D󠀘; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ֥ݭ. +T; \u05A5\u076D。\u200D󠀘; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ֥ݭ. +N; \u05A5\u076D。\u200D󠀘; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ֥ݭ. +B; xn--wcb62g.xn--p526e; [B1 V5 V6]; [B1 V5 V6] # ֥ݭ. +B; xn--wcb62g.xn--1ugy8001l; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ֥ݭ. +T; 쥥󔏉Ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥Ⴎ.⒈⒈𐫒 +N; 쥥󔏉Ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥Ⴎ.⒈⒈𐫒 +T; 쥥󔏉Ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥Ⴎ.⒈⒈𐫒 +N; 쥥󔏉Ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥Ⴎ.⒈⒈𐫒 +T; 쥥󔏉Ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥Ⴎ.1.1.𐫒 +N; 쥥󔏉Ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥Ⴎ.1.1.𐫒 +T; 쥥󔏉Ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥Ⴎ.1.1.𐫒 +N; 쥥󔏉Ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥Ⴎ.1.1.𐫒 +T; 쥥󔏉ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥ⴎ.1.1.𐫒 +N; 쥥󔏉ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥ⴎ.1.1.𐫒 +T; 쥥󔏉ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥ⴎ.1.1.𐫒 +N; 쥥󔏉ⴎ.\u200C1.1.𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥ⴎ.1.1.𐫒 +B; xn--5kj3511ccyw3h.1.1.xn--7w9c; [B1 V6]; [B1 V6] +B; xn--5kj3511ccyw3h.xn--1-rgn.1.xn--7w9c; [B1 C1 V6]; [B1 C1 V6] # 쥥ⴎ.1.1.𐫒 +B; xn--mnd7865gcy28g.1.1.xn--7w9c; [B1 V6]; [B1 V6] +B; xn--mnd7865gcy28g.xn--1-rgn.1.xn--7w9c; [B1 C1 V6]; [B1 C1 V6] # 쥥Ⴎ.1.1.𐫒 +T; 쥥󔏉ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥ⴎ.⒈⒈𐫒 +N; 쥥󔏉ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥ⴎ.⒈⒈𐫒 +T; 쥥󔏉ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 P1 V6] # 쥥ⴎ.⒈⒈𐫒 +N; 쥥󔏉ⴎ.\u200C⒈⒈𐫒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # 쥥ⴎ.⒈⒈𐫒 +B; xn--5kj3511ccyw3h.xn--tsha6797o; [B1 V6]; [B1 V6] +B; xn--5kj3511ccyw3h.xn--0ug88oa0396u; [B1 C1 V6]; [B1 C1 V6] # 쥥ⴎ.⒈⒈𐫒 +B; xn--mnd7865gcy28g.xn--tsha6797o; [B1 V6]; [B1 V6] +B; xn--mnd7865gcy28g.xn--0ug88oa0396u; [B1 C1 V6]; [B1 C1 V6] # 쥥Ⴎ.⒈⒈𐫒 +B; \u0827𝟶\u06A0-。𑄳; [B1 B3 B6 V3 V5]; [B1 B3 B6 V3 V5] # à §0Ú -.𑄳 +B; \u08270\u06A0-。𑄳; [B1 B3 B6 V3 V5]; [B1 B3 B6 V3 V5] # à §0Ú -.𑄳 +B; xn--0--p3d67m.xn--v80d; [B1 B3 B6 V3 V5]; [B1 B3 B6 V3 V5] # à §0Ú -.𑄳 +T; ς.\uFDC1🞛⒈; [P1 V6]; [P1 V6] # ς.فمي🞛⒈ +N; ς.\uFDC1🞛⒈; [P1 V6]; [P1 V6] # ς.فمي🞛⒈ +T; ς.\u0641\u0645\u064A🞛1.; ; xn--4xa.xn--1-gocmu97674d.; NV8 # ς.فمي🞛1. +N; ς.\u0641\u0645\u064A🞛1.; ; xn--3xa.xn--1-gocmu97674d.; NV8 # ς.فمي🞛1. +B; Σ.\u0641\u0645\u064A🞛1.; σ.\u0641\u0645\u064A🞛1.; xn--4xa.xn--1-gocmu97674d.; NV8 # σ.فمي🞛1. +B; σ.\u0641\u0645\u064A🞛1.; ; xn--4xa.xn--1-gocmu97674d.; NV8 # σ.فمي🞛1. +B; xn--4xa.xn--1-gocmu97674d.; σ.\u0641\u0645\u064A🞛1.; xn--4xa.xn--1-gocmu97674d.; NV8 # σ.فمي🞛1. +B; xn--3xa.xn--1-gocmu97674d.; ς.\u0641\u0645\u064A🞛1.; xn--3xa.xn--1-gocmu97674d.; NV8 # ς.فمي🞛1. +B; Σ.\uFDC1🞛⒈; [P1 V6]; [P1 V6] # σ.فمي🞛⒈ +B; σ.\uFDC1🞛⒈; [P1 V6]; [P1 V6] # σ.فمي🞛⒈ +B; xn--4xa.xn--dhbip2802atb20c; [V6]; [V6] # σ.فمي🞛⒈ +B; xn--3xa.xn--dhbip2802atb20c; [V6]; [V6] # ς.فمي🞛⒈ +B; 🗩-。𐹻󐞆ñ¥‰®; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; 🗩-。𐹻󐞆ñ¥‰®; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; xn----6t3s.xn--zo0d4811u6ru6a; [B1 V3 V6]; [B1 V3 V6] +T; 𐡜-🔪。𝟻\u200C𐿀; [B1 B3 C1 P1 V6]; [B1 B3 P1 V6] # 𐡜-🔪.5 +N; 𐡜-🔪。𝟻\u200C𐿀; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # 𐡜-🔪.5 +T; 𐡜-🔪。5\u200C𐿀; [B1 B3 C1 P1 V6]; [B1 B3 P1 V6] # 𐡜-🔪.5 +N; 𐡜-🔪。5\u200C𐿀; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # 𐡜-🔪.5 +B; xn----5j4iv089c.xn--5-bn7i; [B1 B3 V6]; [B1 B3 V6] +B; xn----5j4iv089c.xn--5-sgn7149h; [B1 B3 C1 V6]; [B1 B3 C1 V6] # 𐡜-🔪.5 +T; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ß.ߏ0Ö¼ +N; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ß.ߏ0Ö¼ +T; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ß.ߏ0Ö¼ +N; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ß.ߏ0Ö¼ +T; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ß.ߏ0Ö¼ +N; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ß.ߏ0Ö¼ +T; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ß.ߏ0Ö¼ +N; 𐹣늿\u200Dß.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ß.ߏ0Ö¼ +T; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +B; xn--ss-i05i7041a.xn--0-vgc50n; [B1]; [B1] # 𐹣늿ss.ߏ0Ö¼ +B; xn--ss-l1tu910fo0xd.xn--0-vgc50n; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +B; xn--zca770n5s4hev6c.xn--0-vgc50n; [B1 C2]; [B1 C2] # 𐹣늿ß.ߏ0Ö¼ +T; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSS.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200Dss.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +T; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1] # 𐹣늿ss.ߏ0Ö¼ +N; 𐹣늿\u200DSs.\u07CF0\u05BC; [B1 C2]; [B1 C2] # 𐹣늿ss.ߏ0Ö¼ +B; 9󠇥.󪴴ᢓ; [P1 V6]; [P1 V6] +B; 9󠇥.󪴴ᢓ; [P1 V6]; [P1 V6] +B; 9.xn--dbf91222q; [V6]; [V6] +T; \u200C\uFFA0.𐫭🠗ß⽟; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ß玉 +N; \u200C\uFFA0.𐫭🠗ß⽟; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ß玉 +T; \u200C\u1160.𐫭🠗ß玉; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ß玉 +N; \u200C\u1160.𐫭🠗ß玉; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ß玉 +T; \u200C\u1160.𐫭🠗SS玉; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\u1160.𐫭🠗SS玉; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +T; \u200C\u1160.𐫭🠗ss玉; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\u1160.𐫭🠗ss玉; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +T; \u200C\u1160.𐫭🠗Ss玉; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\u1160.𐫭🠗Ss玉; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +B; xn--psd.xn--ss-je6eq954cp25j; [B2 B3 V6]; [B2 B3 V6] # .𐫭🠗ss玉 +B; xn--psd526e.xn--ss-je6eq954cp25j; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # .𐫭🠗ss玉 +B; xn--psd526e.xn--zca2289c550e0iwi; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # .𐫭🠗ß玉 +T; \u200C\uFFA0.𐫭🠗SS⽟; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\uFFA0.𐫭🠗SS⽟; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +T; \u200C\uFFA0.𐫭🠗ss⽟; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\uFFA0.𐫭🠗ss⽟; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +T; \u200C\uFFA0.𐫭🠗Ss⽟; [B1 B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # .𐫭🠗ss玉 +N; \u200C\uFFA0.𐫭🠗Ss⽟; [B1 B2 B3 C1 P1 V6]; [B1 B2 B3 C1 P1 V6] # .𐫭🠗ss玉 +B; xn--cl7c.xn--ss-je6eq954cp25j; [B2 B3 V6]; [B2 B3 V6] # .𐫭🠗ss玉 +B; xn--0ug7719f.xn--ss-je6eq954cp25j; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # .𐫭🠗ss玉 +B; xn--0ug7719f.xn--zca2289c550e0iwi; [B1 B2 B3 C1 V6]; [B1 B2 B3 C1 V6] # .𐫭🠗ß玉 +T; ︒Ⴖ\u0366.\u200C; [C1 P1 V6]; [P1 V6] # ︒Ⴖͦ. +N; ︒Ⴖ\u0366.\u200C; [C1 P1 V6]; [C1 P1 V6] # ︒Ⴖͦ. +T; 。Ⴖ\u0366.\u200C; [C1 P1 V6 A4_2]; [P1 V6 A4_2] # .Ⴖͦ. +N; 。Ⴖ\u0366.\u200C; [C1 P1 V6 A4_2]; [C1 P1 V6 A4_2] # .Ⴖͦ. +T; 。ⴖ\u0366.\u200C; [C1 A4_2]; [A4_2] # .ⴖͦ. +N; 。ⴖ\u0366.\u200C; [C1 A4_2]; [C1 A4_2] # .ⴖͦ. +B; .xn--hva754s.; [A4_2]; [A4_2] # .ⴖͦ. +B; .xn--hva754s.xn--0ug; [C1 A4_2]; [C1 A4_2] # .ⴖͦ. +B; .xn--hva929d.; [V6 A4_2]; [V6 A4_2] # .Ⴖͦ. +B; .xn--hva929d.xn--0ug; [C1 V6 A4_2]; [C1 V6 A4_2] # .Ⴖͦ. +T; ︒ⴖ\u0366.\u200C; [C1 P1 V6]; [P1 V6] # ︒ⴖͦ. +N; ︒ⴖ\u0366.\u200C; [C1 P1 V6]; [C1 P1 V6] # ︒ⴖͦ. +B; xn--hva754sy94k.; [V6]; [V6] # ︒ⴖͦ. +B; xn--hva754sy94k.xn--0ug; [C1 V6]; [C1 V6] # ︒ⴖͦ. +B; xn--hva929dl29p.; [V6]; [V6] # ︒Ⴖͦ. +B; xn--hva929dl29p.xn--0ug; [C1 V6]; [C1 V6] # ︒Ⴖͦ. +B; xn--hva754s.; ⴖ\u0366.; xn--hva754s. # ⴖͦ. +B; ⴖ\u0366.; ; xn--hva754s. # ⴖͦ. +B; Ⴖ\u0366.; [P1 V6]; [P1 V6] # Ⴖͦ. +B; xn--hva929d.; [V6]; [V6] # Ⴖͦ. +T; \u08BB.\u200CႣ𞀒; [B1 C1 P1 V6]; [P1 V6] # ࢻ.Ⴃ𞀒 +N; \u08BB.\u200CႣ𞀒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ࢻ.Ⴃ𞀒 +T; \u08BB.\u200CႣ𞀒; [B1 C1 P1 V6]; [P1 V6] # ࢻ.Ⴃ𞀒 +N; \u08BB.\u200CႣ𞀒; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ࢻ.Ⴃ𞀒 +T; \u08BB.\u200Cⴃ𞀒; [B1 C1]; xn--hzb.xn--ukj4430l # ࢻ.ⴃ𞀒 +N; \u08BB.\u200Cⴃ𞀒; [B1 C1]; [B1 C1] # ࢻ.ⴃ𞀒 +B; xn--hzb.xn--ukj4430l; \u08BB.ⴃ𞀒; xn--hzb.xn--ukj4430l # ࢻ.ⴃ𞀒 +B; \u08BB.ⴃ𞀒; ; xn--hzb.xn--ukj4430l # ࢻ.ⴃ𞀒 +B; \u08BB.Ⴃ𞀒; [P1 V6]; [P1 V6] # ࢻ.Ⴃ𞀒 +B; xn--hzb.xn--bnd2938u; [V6]; [V6] # ࢻ.Ⴃ𞀒 +B; xn--hzb.xn--0ug822cp045a; [B1 C1]; [B1 C1] # ࢻ.ⴃ𞀒 +B; xn--hzb.xn--bnd300f7225a; [B1 C1 V6]; [B1 C1 V6] # ࢻ.Ⴃ𞀒 +T; \u08BB.\u200Cⴃ𞀒; [B1 C1]; xn--hzb.xn--ukj4430l # ࢻ.ⴃ𞀒 +N; \u08BB.\u200Cⴃ𞀒; [B1 C1]; [B1 C1] # ࢻ.ⴃ𞀒 +T; \u200D\u200C。2䫷󠧷; [C1 C2 P1 V6]; [P1 V6 A4_2] # .2ä«· +N; \u200D\u200C。2䫷󠧷; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .2ä«· +T; \u200D\u200C。2ä«·ó §·; [C1 C2 P1 V6]; [P1 V6 A4_2] # .2ä«· +N; \u200D\u200C。2ä«·ó §·; [C1 C2 P1 V6]; [C1 C2 P1 V6] # .2ä«· +B; .xn--2-me5ay1273i; [V6 A4_2]; [V6 A4_2] +B; xn--0ugb.xn--2-me5ay1273i; [C1 C2 V6]; [C1 C2 V6] # .2ä«· +B; -𞀤󜠐。òˆ¬–; [P1 V3 V6]; [P1 V3 V6] +B; xn----rq4re4997d.xn--l707b; [V3 V6]; [V3 V6] +T; 󳛂︒\u200C㟀.\u0624⒈; [C1 P1 V6]; [P1 V6] # ︒㟀.ؤ⒈ +N; 󳛂︒\u200C㟀.\u0624⒈; [C1 P1 V6]; [C1 P1 V6] # ︒㟀.ؤ⒈ +T; 󳛂︒\u200C㟀.\u0648\u0654⒈; [C1 P1 V6]; [P1 V6] # ︒㟀.ؤ⒈ +N; 󳛂︒\u200C㟀.\u0648\u0654⒈; [C1 P1 V6]; [C1 P1 V6] # ︒㟀.ؤ⒈ +T; 󳛂。\u200C㟀.\u06241.; [B1 C1 P1 V6]; [P1 V6] # .㟀.ؤ1. +N; 󳛂。\u200C㟀.\u06241.; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .㟀.ؤ1. +T; 󳛂。\u200C㟀.\u0648\u06541.; [B1 C1 P1 V6]; [P1 V6] # .㟀.ؤ1. +N; 󳛂。\u200C㟀.\u0648\u06541.; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .㟀.ؤ1. +B; xn--z272f.xn--etl.xn--1-smc.; [V6]; [V6] # .㟀.ؤ1. +B; xn--z272f.xn--0ug754g.xn--1-smc.; [B1 C1 V6]; [B1 C1 V6] # .㟀.ؤ1. +B; xn--etlt457ccrq7h.xn--jgb476m; [V6]; [V6] # ︒㟀.ؤ⒈ +B; xn--0ug754gxl4ldlt0k.xn--jgb476m; [C1 V6]; [C1 V6] # ︒㟀.ؤ⒈ +T; 𑲜\u07CA𝅼。-\u200D; [B1 C2 V3 V5]; [B1 V3 V5] # 𑲜ߊ𝅼.- +N; 𑲜\u07CA𝅼。-\u200D; [B1 C2 V3 V5]; [B1 C2 V3 V5] # 𑲜ߊ𝅼.- +B; xn--lsb5482l7nre.-; [B1 V3 V5]; [B1 V3 V5] # 𑲜ߊ𝅼.- +B; xn--lsb5482l7nre.xn----ugn; [B1 C2 V3 V5]; [B1 C2 V3 V5] # 𑲜ߊ𝅼.- +T; \u200C.Ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴉ≠𐫶 +N; \u200C.Ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .Ⴉ≠𐫶 +T; \u200C.Ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴉ≠𐫶 +N; \u200C.Ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .Ⴉ≠𐫶 +T; \u200C.Ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴉ≠𐫶 +N; \u200C.Ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .Ⴉ≠𐫶 +T; \u200C.Ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .Ⴉ≠𐫶 +N; \u200C.Ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .Ⴉ≠𐫶 +T; \u200C.ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴉ≠𐫶 +N; \u200C.ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ⴉ≠𐫶 +T; \u200C.ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴉ≠𐫶 +N; \u200C.ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ⴉ≠𐫶 +B; .xn--1chx23bzj4p; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] +B; xn--0ug.xn--1chx23bzj4p; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # .ⴉ≠𐫶 +B; .xn--hnd481gv73o; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] +B; xn--0ug.xn--hnd481gv73o; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # .Ⴉ≠𐫶 +T; \u200C.ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴉ≠𐫶 +N; \u200C.ⴉ=\u0338𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ⴉ≠𐫶 +T; \u200C.ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ⴉ≠𐫶 +N; \u200C.ⴉ≠𐫶; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ⴉ≠𐫶 +T; \u0750。≯ς; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯ς +N; \u0750。≯ς; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯ς +T; \u0750。>\u0338ς; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯ς +N; \u0750。>\u0338ς; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯ς +B; \u0750。>\u0338Σ; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯σ +B; \u0750。≯Σ; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯σ +B; \u0750。≯σ; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯σ +B; \u0750。>\u0338σ; [B1 P1 V6]; [B1 P1 V6] # ݐ.≯σ +B; xn--3ob.xn--4xa718m; [B1 V6]; [B1 V6] # ݐ.≯σ +B; xn--3ob.xn--3xa918m; [B1 V6]; [B1 V6] # ݐ.≯ς +B; \u07FC𐸆.𓖏︒ñЍ©á‚°; [P1 V6]; [P1 V6] # .︒Ⴐ +B; \u07FC𐸆.𓖏。ñЍ©á‚°; [P1 V6]; [P1 V6] # ..Ⴐ +B; \u07FC𐸆.𓖏。ñЍ©â´; [P1 V6]; [P1 V6] # ..ⴐ +B; xn--0tb8725k.xn--tu8d.xn--7kj73887a; [V6]; [V6] # ..ⴐ +B; xn--0tb8725k.xn--tu8d.xn--ond97931d; [V6]; [V6] # ..Ⴐ +B; \u07FC𐸆.𓖏︒ñЍ©â´; [P1 V6]; [P1 V6] # .︒ⴐ +B; xn--0tb8725k.xn--7kj9008dt18a7py9c; [V6]; [V6] # .︒ⴐ +B; xn--0tb8725k.xn--ond3562jt18a7py9c; [V6]; [V6] # .︒Ⴐ +B; Ⴥ⚭󠖫⋃。𑌼; [P1 V5 V6]; [P1 V5 V6] +B; Ⴥ⚭󠖫⋃。𑌼; [P1 V5 V6]; [P1 V5 V6] +B; ⴥ⚭󠖫⋃。𑌼; [P1 V5 V6]; [P1 V5 V6] +B; xn--vfh16m67gx1162b.xn--ro1d; [V5 V6]; [V5 V6] +B; xn--9nd623g4zc5z060c.xn--ro1d; [V5 V6]; [V5 V6] +B; ⴥ⚭󠖫⋃。𑌼; [P1 V5 V6]; [P1 V5 V6] +B; 🄈。󠷳\u0844; [B1 P1 V6]; [B1 P1 V6] # 🄈.ࡄ +B; 7,。󠷳\u0844; [B1 P1 V6]; [B1 P1 V6] # 7,.ࡄ +B; 7,.xn--2vb13094p; [B1 P1 V6]; [B1 P1 V6] # 7,.ࡄ +B; xn--107h.xn--2vb13094p; [B1 V6]; [B1 V6] # 🄈.ࡄ +T; ≮\u0846。섖쮖ß; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ß +N; ≮\u0846。섖쮖ß; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ß +T; <\u0338\u0846。섖쮖ß; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ß +N; <\u0338\u0846。섖쮖ß; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ß +B; <\u0338\u0846。섖쮖SS; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; ≮\u0846。섖쮖SS; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; ≮\u0846。섖쮖ss; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; <\u0338\u0846。섖쮖ss; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; <\u0338\u0846。섖쮖Ss; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; ≮\u0846。섖쮖Ss; [B1 P1 V6]; [B1 P1 V6] # ≮ࡆ.섖쮖ss +B; xn--4vb505k.xn--ss-5z4j006a; [B1 V6]; [B1 V6] # ≮ࡆ.섖쮖ss +B; xn--4vb505k.xn--zca7259goug; [B1 V6]; [B1 V6] # ≮ࡆ.섖쮖ß +B; 󠆓⛏-。ꡒ; [V3]; [V3] +B; xn----o9p.xn--rc9a; [V3]; [V3] +T; \u07BB𐹳\u0626𑁆。\u08A7\u06B0\u200Cᢒ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐹳ئ𑁆.ࢧڰᢒ +N; \u07BB𐹳\u0626𑁆。\u08A7\u06B0\u200Cᢒ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐹳ئ𑁆.ࢧڰᢒ +T; \u07BB𐹳\u064A𑁆\u0654。\u08A7\u06B0\u200Cᢒ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐹳ئ𑁆.ࢧڰᢒ +N; \u07BB𐹳\u064A𑁆\u0654。\u08A7\u06B0\u200Cᢒ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐹳ئ𑁆.ࢧڰᢒ +B; xn--lgb32f2753cosb.xn--jkb91hlz1a; [B2 B3 V6]; [B2 B3 V6] # 𐹳ئ𑁆.ࢧڰᢒ +B; xn--lgb32f2753cosb.xn--jkb91hlz1azih; [B2 B3 V6]; [B2 B3 V6] # 𐹳ئ𑁆.ࢧڰᢒ +B; \u0816.𐨕𚚕; [B1 B2 B3 B6 P1 V5 V6]; [B1 B2 B3 B6 P1 V5 V6] # ࠖ.𐨕 +B; xn--rub.xn--tr9c248x; [B1 B2 B3 B6 V5 V6]; [B1 B2 B3 B6 V5 V6] # ࠖ.𐨕 +B; --。𽊆\u0767𐽋𞠬; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # --.ݧ𞠬 +B; --.xn--rpb6226k77pfh58p; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] # --.ݧ𞠬 +B; ò›­¦ð‹¥ð¹¸.≯\u08B0\u08A6󔛣; [B1 P1 V6]; [B1 P1 V6] # 𐋥.≯ࢰࢦ +B; ò›­¦ð‹¥ð¹¸.>\u0338\u08B0\u08A6󔛣; [B1 P1 V6]; [B1 P1 V6] # 𐋥.≯ࢰࢦ +B; xn--887c2298i5mv6a.xn--vybt688qm8981a; [B1 V6]; [B1 V6] # 𐋥.≯ࢰࢦ +B; 䔛󠇒ò¤¸žð¹§ï¼Ž-䤷; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] +B; 䔛󠇒ò¤¸žð¹§.-䤷; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] +B; xn--2loy662coo60e.xn----0n4a; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] +T; 𐹩.\u200D-; [B1 C2 V3]; [B1 V3] # 𐹩.- +N; 𐹩.\u200D-; [B1 C2 V3]; [B1 C2 V3] # 𐹩.- +T; 𐹩.\u200D-; [B1 C2 V3]; [B1 V3] # 𐹩.- +N; 𐹩.\u200D-; [B1 C2 V3]; [B1 C2 V3] # 𐹩.- +B; xn--ho0d.-; [B1 V3]; [B1 V3] +B; xn--ho0d.xn----tgn; [B1 C2 V3]; [B1 C2 V3] # 𐹩.- +B; ñ‚ˆ¦å¸·ï½¡â‰¯èº\u1DC8-; [P1 V3 V6]; [P1 V3 V6] # 帷.≯萺᷈- +B; ñ‚ˆ¦å¸·ï½¡>\u0338萺\u1DC8-; [P1 V3 V6]; [P1 V3 V6] # 帷.≯萺᷈- +B; ñ‚ˆ¦å¸·ã€‚≯萺\u1DC8-; [P1 V3 V6]; [P1 V3 V6] # 帷.≯萺᷈- +B; ñ‚ˆ¦å¸·ã€‚>\u0338萺\u1DC8-; [P1 V3 V6]; [P1 V3 V6] # 帷.≯萺᷈- +B; xn--qutw175s.xn----mimu6tf67j; [V3 V6]; [V3 V6] # 帷.≯萺᷈- +T; \u200D攌\uABED。ᢖ-Ⴘ; [C2 P1 V6]; [P1 V6] # 攌꯭.ᢖ-Ⴘ +N; \u200D攌\uABED。ᢖ-Ⴘ; [C2 P1 V6]; [C2 P1 V6] # 攌꯭.ᢖ-Ⴘ +T; \u200D攌\uABED。ᢖ-ⴘ; [C2]; xn--p9ut19m.xn----mck373i # 攌꯭.ᢖ-ⴘ +N; \u200D攌\uABED。ᢖ-ⴘ; [C2]; [C2] # 攌꯭.ᢖ-ⴘ +B; xn--p9ut19m.xn----mck373i; 攌\uABED.ᢖ-ⴘ; xn--p9ut19m.xn----mck373i # 攌꯭.ᢖ-ⴘ +B; 攌\uABED.ᢖ-ⴘ; ; xn--p9ut19m.xn----mck373i # 攌꯭.ᢖ-ⴘ +B; 攌\uABED.ᢖ-Ⴘ; [P1 V6]; [P1 V6] # 攌꯭.ᢖ-Ⴘ +B; xn--p9ut19m.xn----k1g451d; [V6]; [V6] # 攌꯭.ᢖ-Ⴘ +B; xn--1ug592ykp6b.xn----mck373i; [C2]; [C2] # 攌꯭.ᢖ-ⴘ +B; xn--1ug592ykp6b.xn----k1g451d; [C2 V6]; [C2 V6] # 攌꯭.ᢖ-Ⴘ +T; \u200Cꖨ.⒗3툒۳; [C1 P1 V6]; [P1 V6] # ꖨ.⒗3툒۳ +N; \u200Cꖨ.⒗3툒۳; [C1 P1 V6]; [C1 P1 V6] # ꖨ.⒗3툒۳ +T; \u200Cꖨ.⒗3툒۳; [C1 P1 V6]; [P1 V6] # ꖨ.⒗3툒۳ +N; \u200Cꖨ.⒗3툒۳; [C1 P1 V6]; [C1 P1 V6] # ꖨ.⒗3툒۳ +T; \u200Cꖨ.16.3툒۳; [C1]; xn--9r8a.16.xn--3-nyc0117m # ꖨ.16.3툒۳ +N; \u200Cꖨ.16.3툒۳; [C1]; [C1] # ꖨ.16.3툒۳ +T; \u200Cꖨ.16.3툒۳; [C1]; xn--9r8a.16.xn--3-nyc0117m # ꖨ.16.3툒۳ +N; \u200Cꖨ.16.3툒۳; [C1]; [C1] # ꖨ.16.3툒۳ +B; xn--9r8a.16.xn--3-nyc0117m; ꖨ.16.3툒۳; xn--9r8a.16.xn--3-nyc0117m +B; ꖨ.16.3툒۳; ; xn--9r8a.16.xn--3-nyc0117m +B; ꖨ.16.3툒۳; ꖨ.16.3툒۳; xn--9r8a.16.xn--3-nyc0117m +B; xn--0ug2473c.16.xn--3-nyc0117m; [C1]; [C1] # ꖨ.16.3툒۳ +B; xn--9r8a.xn--3-nyc678tu07m; [V6]; [V6] +B; xn--0ug2473c.xn--3-nyc678tu07m; [C1 V6]; [C1 V6] # ꖨ.⒗3툒۳ +B; ⒈걾6.𐱁\u06D0; [B1 P1 V6]; [B1 P1 V6] # ⒈걾6.𐱁ې +B; ⒈걾6.𐱁\u06D0; [B1 P1 V6]; [B1 P1 V6] # ⒈걾6.𐱁ې +B; 1.ê±¾6.𐱁\u06D0; [B1]; [B1] # 1.ê±¾6.𐱁ې +B; 1.걾6.𐱁\u06D0; [B1]; [B1] # 1.ê±¾6.𐱁ې +B; 1.xn--6-945e.xn--glb1794k; [B1]; [B1] # 1.ê±¾6.𐱁ې +B; xn--6-dcps419c.xn--glb1794k; [B1 V6]; [B1 V6] # ⒈걾6.𐱁ې +B; 𐲞𝟶≮≮.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐲞𝟶<\u0338<\u0338.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐲞0≮≮.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐲞0<\u0338<\u0338.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐳞0<\u0338<\u0338.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐳞0≮≮.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; xn--0-ngoa5711v.xn--4gb31034p; [B1 B3 V6]; [B1 B3 V6] # 𐳞0≮≮.ع +B; 𐳞𝟶<\u0338<\u0338.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; 𐳞𝟶≮≮.󠀧\u0639; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 𐳞0≮≮.ع +B; \u0AE3.𐹺\u115F; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # à«£.𐹺 +B; xn--8fc.xn--osd3070k; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # à«£.𐹺 +T; 𝟏𝨙⸖.\u200D; [C2]; xn--1-5bt6845n. # 1𝨙⸖. +N; 𝟏𝨙⸖.\u200D; [C2]; [C2] # 1𝨙⸖. +T; 1𝨙⸖.\u200D; [C2]; xn--1-5bt6845n. # 1𝨙⸖. +N; 1𝨙⸖.\u200D; [C2]; [C2] # 1𝨙⸖. +B; xn--1-5bt6845n.; 1𝨙⸖.; xn--1-5bt6845n.; NV8 +B; 1𝨙⸖.; ; xn--1-5bt6845n.; NV8 +B; xn--1-5bt6845n.xn--1ug; [C2]; [C2] # 1𝨙⸖. +T; 𞤐≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤐≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤐=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤐=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤐≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤐≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤐=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤐=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤲=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤲=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤲≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤲≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +B; xn--wnb859grzfzw60c.xn----kcd; [B1 V3 V6]; [B1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +B; xn--wnb859grzfzw60c.xn----kcd017p; [B1 C1 V3 V6]; [B1 C1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤲=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤲=\u0338\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +T; 𞤲≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +N; 𞤲≠\u0726\u1A60。-\u200C\u07D5; [B1 C1 P1 V3 V6]; [B1 C1 P1 V3 V6] # 𞤲≠ܦ᩠.-ߕ +B; 𐹰\u0368-ꡧ。\u0675; [B1]; [B1] # 𐹰ͨ-ê¡§.اٴ +B; 𐹰\u0368-ꡧ。\u0627\u0674; [B1]; [B1] # 𐹰ͨ-ê¡§.اٴ +B; xn----shb2387jgkqd.xn--mgb8m; [B1]; [B1] # 𐹰ͨ-ê¡§.اٴ +B; F󠅟。ò—…♚; [P1 V6]; [P1 V6] +B; F󠅟。ò—…♚; [P1 V6]; [P1 V6] +B; f󠅟。ò—…♚; [P1 V6]; [P1 V6] +B; f.xn--45hz6953f; [V6]; [V6] +B; f󠅟。ò—…♚; [P1 V6]; [P1 V6] +B; \u0B4D𑄴\u1DE9。𝟮Ⴘ𞀨ñƒ¥‡; [P1 V5 V6]; [P1 V5 V6] # ୍𑄴ᷩ.2Ⴘ𞀨 +B; \u0B4D𑄴\u1DE9。2Ⴘ𞀨ñƒ¥‡; [P1 V5 V6]; [P1 V5 V6] # ୍𑄴ᷩ.2Ⴘ𞀨 +B; \u0B4D𑄴\u1DE9。2ⴘ𞀨ñƒ¥‡; [P1 V5 V6]; [P1 V5 V6] # ୍𑄴ᷩ.2ⴘ𞀨 +B; xn--9ic246gs21p.xn--2-nws2918ndrjr; [V5 V6]; [V5 V6] # ୍𑄴ᷩ.2ⴘ𞀨 +B; xn--9ic246gs21p.xn--2-k1g43076adrwq; [V5 V6]; [V5 V6] # ୍𑄴ᷩ.2Ⴘ𞀨 +B; \u0B4D𑄴\u1DE9。𝟮ⴘ𞀨ñƒ¥‡; [P1 V5 V6]; [P1 V5 V6] # ୍𑄴ᷩ.2ⴘ𞀨 +T; ò“ ­\u200C\u200C⒈。勉𑁅; [C1 P1 V6]; [P1 V6] # ⒈.勉𑁅 +N; ò“ ­\u200C\u200C⒈。勉𑁅; [C1 P1 V6]; [C1 P1 V6] # ⒈.勉𑁅 +T; ò“ ­\u200C\u200C1.。勉𑁅; [C1 P1 V6 A4_2]; [P1 V6 A4_2] # 1..勉𑁅 +N; ò“ ­\u200C\u200C1.。勉𑁅; [C1 P1 V6 A4_2]; [C1 P1 V6 A4_2] # 1..勉𑁅 +B; xn--1-yi00h..xn--4grs325b; [V6 A4_2]; [V6 A4_2] +B; xn--1-rgna61159u..xn--4grs325b; [C1 V6 A4_2]; [C1 V6 A4_2] # 1..勉𑁅 +B; xn--tsh11906f.xn--4grs325b; [V6]; [V6] +B; xn--0uga855aez302a.xn--4grs325b; [C1 V6]; [C1 V6] # ⒈.勉𑁅 +B; ᡃ.玿ñ«ˆœó•ž; [P1 V6]; [P1 V6] +B; xn--27e.xn--7cy81125a0yq4a; [V6]; [V6] +T; \u200C\u200C。⒈≯𝟵; [C1 P1 V6]; [P1 V6 A4_2] # .⒈≯9 +N; \u200C\u200C。⒈≯𝟵; [C1 P1 V6]; [C1 P1 V6] # .⒈≯9 +T; \u200C\u200C。⒈>\u0338𝟵; [C1 P1 V6]; [P1 V6 A4_2] # .⒈≯9 +N; \u200C\u200C。⒈>\u0338𝟵; [C1 P1 V6]; [C1 P1 V6] # .⒈≯9 +T; \u200C\u200C。1.≯9; [C1 P1 V6]; [P1 V6 A4_2] # .1.≯9 +N; \u200C\u200C。1.≯9; [C1 P1 V6]; [C1 P1 V6] # .1.≯9 +T; \u200C\u200C。1.>\u03389; [C1 P1 V6]; [P1 V6 A4_2] # .1.≯9 +N; \u200C\u200C。1.>\u03389; [C1 P1 V6]; [C1 P1 V6] # .1.≯9 +B; .1.xn--9-ogo; [V6 A4_2]; [V6 A4_2] +B; xn--0uga.1.xn--9-ogo; [C1 V6]; [C1 V6] # .1.≯9 +B; .xn--9-ogo37g; [V6 A4_2]; [V6 A4_2] +B; xn--0uga.xn--9-ogo37g; [C1 V6]; [C1 V6] # .⒈≯9 +B; \u115F\u1DE0ò€.𺻆≯𐮁; [B5 B6 P1 V6]; [B5 B6 P1 V6] # á· .≯𐮁 +B; \u115F\u1DE0ò€.𺻆>\u0338𐮁; [B5 B6 P1 V6]; [B5 B6 P1 V6] # á· .≯𐮁 +B; xn--osd615d5659o.xn--hdh5192gkm6r; [B5 B6 V6]; [B5 B6 V6] # á· .≯𐮁 +T; 󠄫𝩤\u200D\u063E.𝩩-\u081E󑼩; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # 𝩤ؾ.𝩩-ࠞ +N; 󠄫𝩤\u200D\u063E.𝩩-\u081E󑼩; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # 𝩤ؾ.𝩩-ࠞ +B; xn--9gb5080v.xn----qgd52296avol4f; [B1 V5 V6]; [B1 V5 V6] # 𝩤ؾ.𝩩-ࠞ +B; xn--9gb723kg862a.xn----qgd52296avol4f; [B1 C2 V5 V6]; [B1 C2 V5 V6] # 𝩤ؾ.𝩩-ࠞ +B; \u20DA.𑘿-; [V3 V5]; [V3 V5] # ⃚.𑘿- +B; \u20DA.𑘿-; [V3 V5]; [V3 V5] # ⃚.𑘿- +B; xn--w0g.xn----bd0j; [V3 V5]; [V3 V5] # ⃚.𑘿- +T; 䮸ß.󠵟󠭎紙\u08A8; [B1 P1 V6]; [B1 P1 V6] # 䮸ß.紙ࢨ +N; 䮸ß.󠵟󠭎紙\u08A8; [B1 P1 V6]; [B1 P1 V6] # 䮸ß.紙ࢨ +B; 䮸SS.󠵟󠭎紙\u08A8; [B1 P1 V6]; [B1 P1 V6] # 䮸ss.紙ࢨ +B; 䮸ss.󠵟󠭎紙\u08A8; [B1 P1 V6]; [B1 P1 V6] # 䮸ss.紙ࢨ +B; 䮸Ss.󠵟󠭎紙\u08A8; [B1 P1 V6]; [B1 P1 V6] # 䮸ss.紙ࢨ +B; xn--ss-sf1c.xn--xyb1370div70kpzba; [B1 V6]; [B1 V6] # 䮸ss.紙ࢨ +B; xn--zca5349a.xn--xyb1370div70kpzba; [B1 V6]; [B1 V6] # 䮸ß.紙ࢨ +B; -Ⴞ.-𝩨⅔𐦕; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -Ⴞ.-𝩨2⁄3𐦕; [B1 P1 V3 V6]; [B1 P1 V3 V6] +B; -ⴞ.-𝩨2⁄3𐦕; [B1 V3]; [B1 V3] +B; xn----zws.xn---23-pt0a0433lk3jj; [B1 V3]; [B1 V3] +B; xn----w1g.xn---23-pt0a0433lk3jj; [B1 V3 V6]; [B1 V3 V6] +B; -ⴞ.-𝩨⅔𐦕; [B1 V3]; [B1 V3] +B; 󧈯𐹯\u0AC2。ò–¢¨ð®ñ‡¼–á¡‚; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 𐹯ૂ.𐮁ᡂ +B; 󧈯𐹯\u0AC2。ò–¢¨ð®ñ‡¼–á¡‚; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 𐹯ૂ.𐮁ᡂ +B; xn--bfc7604kv8m3g.xn--17e5565jl7zw4h16a; [B5 B6 V6]; [B5 B6 V6] # 𐹯ૂ.𐮁ᡂ +T; \u1082-\u200D\uA8EA.ꡊ\u200Dñ¼¸³; [C2 P1 V5 V6]; [P1 V5 V6] # ႂ-꣪.ꡊ +N; \u1082-\u200D\uA8EA.ꡊ\u200Dñ¼¸³; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ႂ-꣪.ꡊ +T; \u1082-\u200D\uA8EA.ꡊ\u200Dñ¼¸³; [C2 P1 V5 V6]; [P1 V5 V6] # ႂ-꣪.ꡊ +N; \u1082-\u200D\uA8EA.ꡊ\u200Dñ¼¸³; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ႂ-꣪.ꡊ +B; xn----gyg3618i.xn--jc9ao4185a; [V5 V6]; [V5 V6] # ႂ-꣪.ꡊ +B; xn----gyg250jio7k.xn--1ug8774cri56d; [C2 V5 V6]; [C2 V5 V6] # ႂ-꣪.ꡊ +B; ۱。≠\u0668; [B1 P1 V6]; [B1 P1 V6] # Û±.≠٨ +B; ۱。=\u0338\u0668; [B1 P1 V6]; [B1 P1 V6] # Û±.≠٨ +B; xn--emb.xn--hib334l; [B1 V6]; [B1 V6] # Û±.≠٨ +B; 𑈵廊.𐠍; [V5]; [V5] +B; xn--xytw701b.xn--yc9c; [V5]; [V5] +T; \u200D\u0356-.-Ⴐ\u0661; [B1 C2 P1 V3 V6]; [B1 P1 V3 V5 V6] # ͖-.-Ⴐ١ +N; \u200D\u0356-.-Ⴐ\u0661; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # ͖-.-Ⴐ١ +T; \u200D\u0356-.-Ⴐ\u0661; [B1 C2 P1 V3 V6]; [B1 P1 V3 V5 V6] # ͖-.-Ⴐ١ +N; \u200D\u0356-.-Ⴐ\u0661; [B1 C2 P1 V3 V6]; [B1 C2 P1 V3 V6] # ͖-.-Ⴐ١ +T; \u200D\u0356-.-ⴐ\u0661; [B1 C2 V3]; [B1 V3 V5] # ͖-.-ⴐ١ +N; \u200D\u0356-.-ⴐ\u0661; [B1 C2 V3]; [B1 C2 V3] # ͖-.-ⴐ١ +B; xn----rgb.xn----bqc2280a; [B1 V3 V5]; [B1 V3 V5] # ͖-.-ⴐ١ +B; xn----rgb661t.xn----bqc2280a; [B1 C2 V3]; [B1 C2 V3] # ͖-.-ⴐ١ +B; xn----rgb.xn----bqc030f; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ͖-.-Ⴐ١ +B; xn----rgb661t.xn----bqc030f; [B1 C2 V3 V6]; [B1 C2 V3 V6] # ͖-.-Ⴐ١ +T; \u200D\u0356-.-ⴐ\u0661; [B1 C2 V3]; [B1 V3 V5] # ͖-.-ⴐ١ +N; \u200D\u0356-.-ⴐ\u0661; [B1 C2 V3]; [B1 C2 V3] # ͖-.-ⴐ١ +B; \u063A\u0661挏󾯐.-; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # غ١挏.- +B; xn--5gb2f4205aqi47p.-; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # غ١挏.- +B; \u06EF。𐹧𞤽; [B1]; [B1] # Û¯.𐹧𞤽 +B; \u06EF。𐹧𞤽; [B1]; [B1] # Û¯.𐹧𞤽 +B; \u06EF。𐹧𞤛; [B1]; [B1] # Û¯.𐹧𞤽 +B; xn--cmb.xn--fo0dy848a; [B1]; [B1] # Û¯.𐹧𞤽 +B; \u06EF。𐹧𞤛; [B1]; [B1] # Û¯.𐹧𞤽 +B; Ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; Ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; Ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; Ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; xn--mlj0486jgl2j.xn--hbf6853f; [V6]; [V6] +B; xn--2nd8876sgl2j.xn--hbf6853f; [V6]; [V6] +B; ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +B; ⴞ𶛀𛗻.ᢗ릫; [P1 V6]; [P1 V6] +T; 󠎃󗭞\u06B7𐹷。≯\u200C\u1DFE; [B1 C1 P1 V6]; [B1 P1 V6] # ڷ𐹷.≯᷾ +N; 󠎃󗭞\u06B7𐹷。≯\u200C\u1DFE; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ڷ𐹷.≯᷾ +T; 󠎃󗭞\u06B7𐹷。>\u0338\u200C\u1DFE; [B1 C1 P1 V6]; [B1 P1 V6] # ڷ𐹷.≯᷾ +N; 󠎃󗭞\u06B7𐹷。>\u0338\u200C\u1DFE; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ڷ𐹷.≯᷾ +T; 󠎃󗭞\u06B7𐹷。≯\u200C\u1DFE; [B1 C1 P1 V6]; [B1 P1 V6] # ڷ𐹷.≯᷾ +N; 󠎃󗭞\u06B7𐹷。≯\u200C\u1DFE; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ڷ𐹷.≯᷾ +T; 󠎃󗭞\u06B7𐹷。>\u0338\u200C\u1DFE; [B1 C1 P1 V6]; [B1 P1 V6] # ڷ𐹷.≯᷾ +N; 󠎃󗭞\u06B7𐹷。>\u0338\u200C\u1DFE; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ڷ𐹷.≯᷾ +B; xn--qkb4516kbi06fg2id.xn--zfg31q; [B1 V6]; [B1 V6] # ڷ𐹷.≯᷾ +B; xn--qkb4516kbi06fg2id.xn--zfg59fm0c; [B1 C1 V6]; [B1 C1 V6] # ڷ𐹷.≯᷾ +T; ᛎ󠅍󠐕\u200D。𐹾𐹪𐻝-; [B1 B6 C2 P1 V3 V6]; [B1 B6 P1 V3 V6] # ᛎ.𐹾𐹪- +N; ᛎ󠅍󠐕\u200D。𐹾𐹪𐻝-; [B1 B6 C2 P1 V3 V6]; [B1 B6 C2 P1 V3 V6] # ᛎ.𐹾𐹪- +T; ᛎ󠅍󠐕\u200D。𐹾𐹪𐻝-; [B1 B6 C2 P1 V3 V6]; [B1 B6 P1 V3 V6] # ᛎ.𐹾𐹪- +N; ᛎ󠅍󠐕\u200D。𐹾𐹪𐻝-; [B1 B6 C2 P1 V3 V6]; [B1 B6 C2 P1 V3 V6] # ᛎ.𐹾𐹪- +B; xn--fxe63563p.xn----q26i2bvu; [B1 B6 V3 V6]; [B1 B6 V3 V6] +B; xn--fxe848bq3411a.xn----q26i2bvu; [B1 B6 C2 V3 V6]; [B1 B6 C2 V3 V6] # ᛎ.𐹾𐹪- +B; 𐹶.𐫂; [B1]; [B1] +B; xn--uo0d.xn--rw9c; [B1]; [B1] +T; ß\u200D\u103A。⒈; [C2 P1 V6]; [P1 V6] # ß်.⒈ +N; ß\u200D\u103A。⒈; [C2 P1 V6]; [C2 P1 V6] # ß်.⒈ +T; ß\u200D\u103A。1.; [C2]; xn--ss-f4j.1. # ß်.1. +N; ß\u200D\u103A。1.; [C2]; [C2] # ß်.1. +T; SS\u200D\u103A。1.; [C2]; xn--ss-f4j.1. # ss်.1. +N; SS\u200D\u103A。1.; [C2]; [C2] # ss်.1. +T; ss\u200D\u103A。1.; [C2]; xn--ss-f4j.1. # ss်.1. +N; ss\u200D\u103A。1.; [C2]; [C2] # ss်.1. +T; Ss\u200D\u103A。1.; [C2]; xn--ss-f4j.1. # ss်.1. +N; Ss\u200D\u103A。1.; [C2]; [C2] # ss်.1. +B; xn--ss-f4j.1.; ss\u103A.1.; xn--ss-f4j.1. # ss်.1. +B; ss\u103A.1.; ; xn--ss-f4j.1. # ss်.1. +B; SS\u103A.1.; ss\u103A.1.; xn--ss-f4j.1. # ss်.1. +B; Ss\u103A.1.; ss\u103A.1.; xn--ss-f4j.1. # ss်.1. +B; xn--ss-f4j585j.1.; [C2]; [C2] # ss်.1. +B; xn--zca679eh2l.1.; [C2]; [C2] # ß်.1. +T; SS\u200D\u103A。⒈; [C2 P1 V6]; [P1 V6] # ss်.⒈ +N; SS\u200D\u103A。⒈; [C2 P1 V6]; [C2 P1 V6] # ss်.⒈ +T; ss\u200D\u103A。⒈; [C2 P1 V6]; [P1 V6] # ss်.⒈ +N; ss\u200D\u103A。⒈; [C2 P1 V6]; [C2 P1 V6] # ss်.⒈ +T; Ss\u200D\u103A。⒈; [C2 P1 V6]; [P1 V6] # ss်.⒈ +N; Ss\u200D\u103A。⒈; [C2 P1 V6]; [C2 P1 V6] # ss်.⒈ +B; xn--ss-f4j.xn--tsh; [V6]; [V6] # ss်.⒈ +B; xn--ss-f4j585j.xn--tsh; [C2 V6]; [C2 V6] # ss်.⒈ +B; xn--zca679eh2l.xn--tsh; [C2 V6]; [C2 V6] # ß်.⒈ +T; \u0B4D\u200C𙶵𞻘。\u200D; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ୍. +N; \u0B4D\u200C𙶵𞻘。\u200D; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ୍. +B; xn--9ic6417rn4xb.; [B1 V5 V6]; [B1 V5 V6] # ୍. +B; xn--9ic637hz82z32jc.xn--1ug; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ୍. +B; 𐮅。\u06BC🁕; [B3]; [B3] # 𐮅.ڼ🁕 +B; 𐮅。\u06BC🁕; [B3]; [B3] # 𐮅.ڼ🁕 +B; xn--c29c.xn--vkb8871w; [B3]; [B3] # 𐮅.ڼ🁕 +T; \u0620\u17D2。𐫔󠀧\u200C𑈵; [B2 B3 C1 P1 V6]; [B2 B3 P1 V6] # ؠ្.𐫔𑈵 +N; \u0620\u17D2。𐫔󠀧\u200C𑈵; [B2 B3 C1 P1 V6]; [B2 B3 C1 P1 V6] # ؠ្.𐫔𑈵 +B; xn--fgb471g.xn--9w9c29jw3931a; [B2 B3 V6]; [B2 B3 V6] # ؠ្.𐫔𑈵 +B; xn--fgb471g.xn--0ug9853g7verp838a; [B2 B3 C1 V6]; [B2 B3 C1 V6] # ؠ្.𐫔𑈵 +B; ñ‹‰•.𞣕𞤊; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; ñ‹‰•.𞣕𞤬; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; xn--tf5w.xn--2b6hof; [B1 V5 V6]; [B1 V5 V6] +T; \u06CC𐨿.ß\u0F84𑍬; \u06CC𐨿.ß\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ß྄𑍬 +N; \u06CC𐨿.ß\u0F84𑍬; \u06CC𐨿.ß\u0F84𑍬; xn--clb2593k.xn--zca216edt0r # ی𐨿.ß྄𑍬 +T; \u06CC𐨿.ß\u0F84𑍬; ; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ß྄𑍬 +N; \u06CC𐨿.ß\u0F84𑍬; ; xn--clb2593k.xn--zca216edt0r # ی𐨿.ß྄𑍬 +B; \u06CC𐨿.SS\u0F84𑍬; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; \u06CC𐨿.ss\u0F84𑍬; ; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; \u06CC𐨿.Ss\u0F84𑍬; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; xn--clb2593k.xn--ss-toj6092t; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; xn--clb2593k.xn--zca216edt0r; \u06CC𐨿.ß\u0F84𑍬; xn--clb2593k.xn--zca216edt0r # ی𐨿.ß྄𑍬 +B; \u06CC𐨿.SS\u0F84𑍬; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; \u06CC𐨿.ss\u0F84𑍬; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +B; \u06CC𐨿.Ss\u0F84𑍬; \u06CC𐨿.ss\u0F84𑍬; xn--clb2593k.xn--ss-toj6092t # ی𐨿.ss྄𑍬 +T; 𝟠≮\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [P1 V5 V6] # 8≮. +N; 𝟠≮\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 8≮. +T; 𝟠<\u0338\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [P1 V5 V6] # 8≮. +N; 𝟠<\u0338\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 8≮. +T; 8≮\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [P1 V5 V6] # 8≮. +N; 8≮\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 8≮. +T; 8<\u0338\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [P1 V5 V6] # 8≮. +N; 8<\u0338\u200C。󠅱\u17B4; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 8≮. +B; xn--8-ngo.xn--z3e; [V5 V6]; [V5 V6] # 8≮. +B; xn--8-sgn10i.xn--z3e; [C1 V5 V6]; [C1 V5 V6] # 8≮. +B; ᢕ≯︒ñ„‚¯ï¼Žá‚ ; [P1 V6]; [P1 V6] +B; ᢕ>\u0338︒ñ„‚¯ï¼Žá‚ ; [P1 V6]; [P1 V6] +B; ᢕ≯。ñ„‚¯.Ⴀ; [P1 V6]; [P1 V6] +B; ᢕ>\u0338。ñ„‚¯.Ⴀ; [P1 V6]; [P1 V6] +B; ᢕ>\u0338。ñ„‚¯.ⴀ; [P1 V6]; [P1 V6] +B; ᢕ≯。ñ„‚¯.ⴀ; [P1 V6]; [P1 V6] +B; xn--fbf851c.xn--ko1u.xn--rkj; [V6]; [V6] +B; xn--fbf851c.xn--ko1u.xn--7md; [V6]; [V6] +B; ᢕ>\u0338︒ñ„‚¯ï¼Žâ´€; [P1 V6]; [P1 V6] +B; ᢕ≯︒ñ„‚¯ï¼Žâ´€; [P1 V6]; [P1 V6] +B; xn--fbf851cq98poxw1a.xn--rkj; [V6]; [V6] +B; xn--fbf851cq98poxw1a.xn--7md; [V6]; [V6] +B; \u0F9F.-\u082A; [V3 V5]; [V3 V5] # ྟ.-à ª +B; \u0F9F.-\u082A; [V3 V5]; [V3 V5] # ྟ.-à ª +B; xn--vfd.xn----fhd; [V3 V5]; [V3 V5] # ྟ.-à ª +B; ᵬ󠆠.핒⒒⒈ôˆ„¦; [P1 V6]; [P1 V6] +B; ᵬ󠆠.핒⒒⒈ôˆ„¦; [P1 V6]; [P1 V6] +B; ᵬ󠆠.핒11.1.ôˆ„¦; [P1 V6]; [P1 V6] +B; ᵬ󠆠.핒11.1.ôˆ„¦; [P1 V6]; [P1 V6] +B; xn--tbg.xn--11-5o7k.1.xn--k469f; [V6]; [V6] +B; xn--tbg.xn--tsht7586kyts9l; [V6]; [V6] +T; ς𑓂𐋢.\u0668; [B1]; [B1] # ς𑓂𐋢.Ù¨ +N; ς𑓂𐋢.\u0668; [B1]; [B1] # ς𑓂𐋢.Ù¨ +T; ς𑓂𐋢.\u0668; [B1]; [B1] # ς𑓂𐋢.Ù¨ +N; ς𑓂𐋢.\u0668; [B1]; [B1] # ς𑓂𐋢.Ù¨ +B; Σ𑓂𐋢.\u0668; [B1]; [B1] # σ𑓂𐋢.Ù¨ +B; σ𑓂𐋢.\u0668; [B1]; [B1] # σ𑓂𐋢.Ù¨ +B; xn--4xa6371khhl.xn--hib; [B1]; [B1] # σ𑓂𐋢.Ù¨ +B; xn--3xa8371khhl.xn--hib; [B1]; [B1] # ς𑓂𐋢.Ù¨ +B; Σ𑓂𐋢.\u0668; [B1]; [B1] # σ𑓂𐋢.Ù¨ +B; σ𑓂𐋢.\u0668; [B1]; [B1] # σ𑓂𐋢.Ù¨ +T; \uA953\u200C𐋻\u200D.\u2DF8𞿄𐹲; [B1 B6 C2 P1 V5 V6]; [B1 P1 V5 V6] # ꥓𐋻.ⷸ𐹲 +N; \uA953\u200C𐋻\u200D.\u2DF8𞿄𐹲; [B1 B6 C2 P1 V5 V6]; [B1 B6 C2 P1 V5 V6] # ꥓𐋻.ⷸ𐹲 +B; xn--3j9a531o.xn--urju692efj0f; [B1 V5 V6]; [B1 V5 V6] # ꥓𐋻.ⷸ𐹲 +B; xn--0ugc8356he76c.xn--urju692efj0f; [B1 B6 C2 V5 V6]; [B1 B6 C2 V5 V6] # ꥓𐋻.ⷸ𐹲 +B; ⊼。ñª§–\u0695; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ⊼.ڕ +B; xn--ofh.xn--rjb13118f; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ⊼.ڕ +B; 𐯬ñ–‹”。󜳥; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--949co370q.xn--7g25e; [B2 B3 V6]; [B2 B3 V6] +T; \u0601𑍧\u07DD。ςò¬˜ðŸ€ž\u17B5; [B1 B6 P1 V6]; [B1 B6 P1 V6] # 𑍧ߝ.ς🀞 +N; \u0601𑍧\u07DD。ςò¬˜ðŸ€ž\u17B5; [B1 B6 P1 V6]; [B1 B6 P1 V6] # 𑍧ߝ.ς🀞 +B; \u0601𑍧\u07DD。Σò¬˜ðŸ€ž\u17B5; [B1 B6 P1 V6]; [B1 B6 P1 V6] # 𑍧ߝ.σ🀞 +B; \u0601𑍧\u07DD。σò¬˜ðŸ€ž\u17B5; [B1 B6 P1 V6]; [B1 B6 P1 V6] # 𑍧ߝ.σ🀞 +B; xn--jfb66gt010c.xn--4xa623h9p95ars26d; [B1 B6 V6]; [B1 B6 V6] # 𑍧ߝ.σ🀞 +B; xn--jfb66gt010c.xn--3xa823h9p95ars26d; [B1 B6 V6]; [B1 B6 V6] # 𑍧ߝ.ς🀞 +B; -𐳲\u0646󠺐。\uABED𝟥; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -𐳲ن.꯭3 +B; -𐳲\u0646󠺐。\uABED3; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -𐳲ن.꯭3 +B; -𐲲\u0646󠺐。\uABED3; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -𐳲ن.꯭3 +B; xn----roc5482rek10i.xn--3-zw5e; [B1 V3 V5 V6]; [B1 V3 V5 V6] # -𐳲ن.꯭3 +B; -𐲲\u0646󠺐。\uABED𝟥; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # -𐳲ن.꯭3 +T; \u200C󠴦。ñ²¨•≮𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # .≮𐦜 +N; \u200C󠴦。ñ²¨•≮𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .≮𐦜 +T; \u200C󠴦。ñ²¨•<\u0338𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # .≮𐦜 +N; \u200C󠴦。ñ²¨•<\u0338𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .≮𐦜 +T; \u200C󠴦。ñ²¨•≮𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # .≮𐦜 +N; \u200C󠴦。ñ²¨•≮𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .≮𐦜 +T; \u200C󠴦。ñ²¨•<\u0338𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 P1 V6] # .≮𐦜 +N; \u200C󠴦。ñ²¨•<\u0338𐦜; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .≮𐦜 +B; xn--6v56e.xn--gdhz712gzlr6b; [B1 B5 B6 V6]; [B1 B5 B6 V6] +B; xn--0ug22251l.xn--gdhz712gzlr6b; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # .≮𐦜 +B; ⒈✌òŸ¬Ÿï¼ŽðŸ¡ñ ±£; [P1 V6]; [P1 V6] +B; 1.✌òŸ¬Ÿ.9ñ ±£; [P1 V6]; [P1 V6] +B; 1.xn--7bi44996f.xn--9-o706d; [V6]; [V6] +B; xn--tsh24g49550b.xn--9-o706d; [V6]; [V6] +B; 𑆾𞤬𐮆.\u0666\u1DD4; [B1 V5]; [B1 V5] # 𑆾𞤬𐮆.٦ᷔ +B; 𑆾𞤊𐮆.\u0666\u1DD4; [B1 V5]; [B1 V5] # 𑆾𞤬𐮆.٦ᷔ +B; xn--d29c79hf98r.xn--fib011j; [B1 V5]; [B1 V5] # 𑆾𞤬𐮆.٦ᷔ +T; ς.\uA9C0\uA8C4; [V5]; [V5] # ς.꧀꣄ +N; ς.\uA9C0\uA8C4; [V5]; [V5] # ς.꧀꣄ +T; ς.\uA9C0\uA8C4; [V5]; [V5] # ς.꧀꣄ +N; ς.\uA9C0\uA8C4; [V5]; [V5] # ς.꧀꣄ +B; Σ.\uA9C0\uA8C4; [V5]; [V5] # σ.꧀꣄ +B; σ.\uA9C0\uA8C4; [V5]; [V5] # σ.꧀꣄ +B; xn--4xa.xn--0f9ars; [V5]; [V5] # σ.꧀꣄ +B; xn--3xa.xn--0f9ars; [V5]; [V5] # ς.꧀꣄ +B; Σ.\uA9C0\uA8C4; [V5]; [V5] # σ.꧀꣄ +B; σ.\uA9C0\uA8C4; [V5]; [V5] # σ.꧀꣄ +T; 𑰶\u200C≯𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C≯𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C>\u0338𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C>\u0338𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C≯𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C≯𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C>\u0338𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C>\u0338𐳐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C>\u0338𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C>\u0338𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C≯𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C≯𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +B; xn--hdhz343g3wj.xn--qwb; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # 𑰶≯𐳐.࡛ +B; xn--0ug06g7697ap4ma.xn--qwb; [B1 B3 B6 C1 V5 V6]; [B1 B3 B6 C1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C>\u0338𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C>\u0338𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +T; 𑰶\u200C≯𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𑰶≯𐳐.࡛ +N; 𑰶\u200C≯𐲐.\u085B; [B1 B3 B6 C1 P1 V5 V6]; [B1 B3 B6 C1 P1 V5 V6] # 𑰶≯𐳐.࡛ +B; 羚。≯; [P1 V6]; [P1 V6] +B; 羚。>\u0338; [P1 V6]; [P1 V6] +B; 羚。≯; [P1 V6]; [P1 V6] +B; 羚。>\u0338; [P1 V6]; [P1 V6] +B; xn--xt0a.xn--hdh; [V6]; [V6] +B; 𑓂\u1759.\u08A8; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𑓂.ࢨ +B; 𑓂\u1759.\u08A8; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𑓂.ࢨ +B; xn--e1e9580k.xn--xyb; [B1 V5 V6]; [B1 V5 V6] # 𑓂.ࢨ +T; 󨣿󠇀\u200D。\u0663ҠჀ𝟑; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .٣ҡჀ3 +N; 󨣿󠇀\u200D。\u0663ҠჀ𝟑; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .٣ҡჀ3 +T; 󨣿󠇀\u200D。\u0663ҠჀ3; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .٣ҡჀ3 +N; 󨣿󠇀\u200D。\u0663ҠჀ3; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .٣ҡჀ3 +T; 󨣿󠇀\u200D。\u0663Ò¡â´ 3; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .Ù£Ò¡â´ 3 +N; 󨣿󠇀\u200D。\u0663Ò¡â´ 3; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .Ù£Ò¡â´ 3 +T; 󨣿󠇀\u200D。\u0663Ò â´ 3; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .Ù£Ò¡â´ 3 +N; 󨣿󠇀\u200D。\u0663Ò â´ 3; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .Ù£Ò¡â´ 3 +B; xn--1r19e.xn--3-ozb36ko13f; [B1 V6]; [B1 V6] # .Ù£Ò¡â´ 3 +B; xn--1ug89936l.xn--3-ozb36ko13f; [B1 B6 C2 V6]; [B1 B6 C2 V6] # .Ù£Ò¡â´ 3 +B; xn--1r19e.xn--3-ozb36kixu; [B1 V6]; [B1 V6] # .٣ҡჀ3 +B; xn--1ug89936l.xn--3-ozb36kixu; [B1 B6 C2 V6]; [B1 B6 C2 V6] # .٣ҡჀ3 +T; 󨣿󠇀\u200D。\u0663ҡⴠ𝟑; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .Ù£Ò¡â´ 3 +N; 󨣿󠇀\u200D。\u0663ҡⴠ𝟑; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .Ù£Ò¡â´ 3 +T; 󨣿󠇀\u200D。\u0663Ҡⴠ𝟑; [B1 B6 C2 P1 V6]; [B1 P1 V6] # .Ù£Ò¡â´ 3 +N; 󨣿󠇀\u200D。\u0663Ҡⴠ𝟑; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # .Ù£Ò¡â´ 3 +B; ᡷ。𐹢\u08E0; [B1]; [B1] # á¡·.𐹢࣠ +B; xn--k9e.xn--j0b5005k; [B1]; [B1] # á¡·.𐹢࣠ +T; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ß; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ß +N; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ß; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ß +T; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ß; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ß +N; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ß; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ß +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2SS; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ss; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2Ss; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; xn--1zf58212h.xn--ss-pyd459o3258m; [B1 V6]; [B1 V6] # ᯳.٦្ss +B; xn--1zf58212h.xn--zca34zk4qx711k; [B1 V6]; [B1 V6] # ᯳.٦្ß +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2SS; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2ss; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; ò•®‡\u1BF3。\u0666ñ—œ¼\u17D2Ss; [B1 P1 V6]; [B1 P1 V6] # ᯳.٦្ss +B; \u0664ò¤½Žð‘²›.󠔢︒≠; [B1 P1 V6]; [B1 P1 V6] # ٤𑲛.︒≠ +B; \u0664ò¤½Žð‘²›.󠔢︒=\u0338; [B1 P1 V6]; [B1 P1 V6] # ٤𑲛.︒≠ +B; \u0664ò¤½Žð‘²›.󠔢。≠; [B1 P1 V6]; [B1 P1 V6] # ٤𑲛..≠ +B; \u0664ò¤½Žð‘²›.󠔢。=\u0338; [B1 P1 V6]; [B1 P1 V6] # ٤𑲛..≠ +B; xn--dib0653l2i02d.xn--k736e.xn--1ch; [B1 V6]; [B1 V6] # ٤𑲛..≠ +B; xn--dib0653l2i02d.xn--1ch7467f14u4g; [B1 V6]; [B1 V6] # ٤𑲛.︒≠ +B; ➆ñ·§•ỗ⒈.ò‘¬’ñ¡˜®\u085B𝟫; [P1 V6]; [P1 V6] # ➆ỗ⒈.࡛9 +B; ➆ñ·§•o\u0302\u0303⒈.ò‘¬’ñ¡˜®\u085B𝟫; [P1 V6]; [P1 V6] # ➆ỗ⒈.࡛9 +B; ➆ñ·§•á»—1..ò‘¬’ñ¡˜®\u085B9; [P1 V6 A4_2]; [P1 V6 A4_2] # ➆ỗ1..࡛9 +B; ➆ñ·§•o\u0302\u03031..ò‘¬’ñ¡˜®\u085B9; [P1 V6 A4_2]; [P1 V6 A4_2] # ➆ỗ1..࡛9 +B; ➆ñ·§•O\u0302\u03031..ò‘¬’ñ¡˜®\u085B9; [P1 V6 A4_2]; [P1 V6 A4_2] # ➆ỗ1..࡛9 +B; ➆ñ·§•á»–1..ò‘¬’ñ¡˜®\u085B9; [P1 V6 A4_2]; [P1 V6 A4_2] # ➆ỗ1..࡛9 +B; xn--1-3xm292b6044r..xn--9-6jd87310jtcqs; [V6 A4_2]; [V6 A4_2] # ➆ỗ1..࡛9 +B; ➆ñ·§•O\u0302\u0303⒈.ò‘¬’ñ¡˜®\u085B𝟫; [P1 V6]; [P1 V6] # ➆ỗ⒈.࡛9 +B; ➆ñ·§•Ỗ⒈.ò‘¬’ñ¡˜®\u085B𝟫; [P1 V6]; [P1 V6] # ➆ỗ⒈.࡛9 +B; xn--6lg26tvvc6v99z.xn--9-6jd87310jtcqs; [V6]; [V6] # ➆ỗ⒈.࡛9 +T; \u200D。𞤘; [B1 C2]; [A4_2] # .𞤺 +N; \u200D。𞤘; [B1 C2]; [B1 C2] # .𞤺 +T; \u200D。𞤘; [B1 C2]; [A4_2] # .𞤺 +N; \u200D。𞤘; [B1 C2]; [B1 C2] # .𞤺 +T; \u200D。𞤺; [B1 C2]; [A4_2] # .𞤺 +N; \u200D。𞤺; [B1 C2]; [B1 C2] # .𞤺 +B; .xn--ye6h; [A4_2]; [A4_2] +B; xn--1ug.xn--ye6h; [B1 C2]; [B1 C2] # .𞤺 +T; \u200D。𞤺; [B1 C2]; [A4_2] # .𞤺 +N; \u200D。𞤺; [B1 C2]; [B1 C2] # .𞤺 +B; xn--ye6h; 𞤺; xn--ye6h +B; 𞤺; ; xn--ye6h +B; 𞤘; 𞤺; xn--ye6h +B; \u0829\u0724.ᢣ; [B1 V5]; [B1 V5] # ࠩܤ.ᢣ +B; xn--unb53c.xn--tbf; [B1 V5]; [B1 V5] # ࠩܤ.ᢣ +T; \u073C\u200C-。𓐾ß; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # ܼ-.ß +N; \u073C\u200C-。𓐾ß; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # ܼ-.ß +T; \u073C\u200C-。𓐾SS; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # ܼ-.ss +N; \u073C\u200C-。𓐾SS; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # ܼ-.ss +T; \u073C\u200C-。𓐾ss; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # ܼ-.ss +N; \u073C\u200C-。𓐾ss; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # ܼ-.ss +T; \u073C\u200C-。𓐾Ss; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # ܼ-.ss +N; \u073C\u200C-。𓐾Ss; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # ܼ-.ss +B; xn----s2c.xn--ss-066q; [V3 V5 V6]; [V3 V5 V6] # ܼ-.ss +B; xn----s2c071q.xn--ss-066q; [C1 V3 V5 V6]; [C1 V3 V5 V6] # ܼ-.ss +B; xn----s2c071q.xn--zca7848m; [C1 V3 V5 V6]; [C1 V3 V5 V6] # ܼ-.ß +T; \u200Cς🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B5 B6 P1 V5 V6] # ς🃡⒗.ೆ仧ݖ +N; \u200Cς🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # ς🃡⒗.ೆ仧ݖ +T; \u200Cς🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B5 B6 V5 A4_2] # ς🃡16..ೆ仧ݖ +N; \u200Cς🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B1 B5 B6 C1 V5 A4_2] # ς🃡16..ೆ仧ݖ +T; \u200CΣ🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B5 B6 V5 A4_2] # σ🃡16..ೆ仧ݖ +N; \u200CΣ🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B1 B5 B6 C1 V5 A4_2] # σ🃡16..ೆ仧ݖ +T; \u200Cσ🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B5 B6 V5 A4_2] # σ🃡16..ೆ仧ݖ +N; \u200Cσ🃡16..\u0CC6ä»§\u0756; [B1 B5 B6 C1 V5 A4_2]; [B1 B5 B6 C1 V5 A4_2] # σ🃡16..ೆ仧ݖ +B; xn--16-ubc66061c..xn--9ob79ycx2e; [B5 B6 V5 A4_2]; [B5 B6 V5 A4_2] # σ🃡16..ೆ仧ݖ +B; xn--16-ubc7700avy99b..xn--9ob79ycx2e; [B1 B5 B6 C1 V5 A4_2]; [B1 B5 B6 C1 V5 A4_2] # σ🃡16..ೆ仧ݖ +B; xn--16-rbc1800avy99b..xn--9ob79ycx2e; [B1 B5 B6 C1 V5 A4_2]; [B1 B5 B6 C1 V5 A4_2] # ς🃡16..ೆ仧ݖ +T; \u200CΣ🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B5 B6 P1 V5 V6] # σ🃡⒗.ೆ仧ݖ +N; \u200CΣ🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # σ🃡⒗.ೆ仧ݖ +T; \u200Cσ🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B5 B6 P1 V5 V6] # σ🃡⒗.ೆ仧ݖ +N; \u200Cσ🃡⒗.\u0CC6ä»§\u0756; [B1 B5 B6 C1 P1 V5 V6]; [B1 B5 B6 C1 P1 V5 V6] # σ🃡⒗.ೆ仧ݖ +B; xn--4xa229nbu92a.xn--9ob79ycx2e; [B5 B6 V5 V6]; [B5 B6 V5 V6] # σ🃡⒗.ೆ仧ݖ +B; xn--4xa595lz9czy52d.xn--9ob79ycx2e; [B1 B5 B6 C1 V5 V6]; [B1 B5 B6 C1 V5 V6] # σ🃡⒗.ೆ仧ݖ +B; xn--3xa795lz9czy52d.xn--9ob79ycx2e; [B1 B5 B6 C1 V5 V6]; [B1 B5 B6 C1 V5 V6] # ς🃡⒗.ೆ仧ݖ +B; -.𞸚; [B1 V3]; [B1 V3] # -.ظ +B; -.\u0638; [B1 V3]; [B1 V3] # -.ظ +B; -.xn--3gb; [B1 V3]; [B1 V3] # -.ظ +B; ò›“\u0683.\u0F7E\u0634; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ڃ.ཾش +B; xn--8ib92728i.xn--zgb968b; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ڃ.ཾش +B; \u0FE6\u0843ñ½¶¬.𐮏; [B5 P1 V6]; [B5 P1 V6] # ࡃ.𐮏 +B; xn--1vb320b5m04p.xn--m29c; [B5 V6]; [B5 V6] # ࡃ.𐮏 +T; 2ñލ \u07CBß。ᠽ; [B1 P1 V6]; [B1 P1 V6] # 2ߋß.á ½ +N; 2ñލ \u07CBß。ᠽ; [B1 P1 V6]; [B1 P1 V6] # 2ߋß.á ½ +B; 2ñލ \u07CBSS。ᠽ; [B1 P1 V6]; [B1 P1 V6] # 2ߋss.á ½ +B; 2ñލ \u07CBss。ᠽ; [B1 P1 V6]; [B1 P1 V6] # 2ߋss.á ½ +B; 2ñލ \u07CBSs。ᠽ; [B1 P1 V6]; [B1 P1 V6] # 2ߋss.á ½ +B; xn--2ss-odg83511n.xn--w7e; [B1 V6]; [B1 V6] # 2ߋss.á ½ +B; xn--2-qfa924cez02l.xn--w7e; [B1 V6]; [B1 V6] # 2ߋß.á ½ +T; 㸳\u07CA≮.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێß- +N; 㸳\u07CA≮.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێß- +T; 㸳\u07CA<\u0338.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێß- +N; 㸳\u07CA<\u0338.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێß- +T; 㸳\u07CA≮.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێß- +N; 㸳\u07CA≮.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێß- +T; 㸳\u07CA<\u0338.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێß- +N; 㸳\u07CA<\u0338.\u06CEß-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێß- +T; 㸳\u07CA<\u0338.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA<\u0338.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA<\u0338.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +B; xn--lsb457kkut.xn--ss--qjf; [B2 B3 B5 B6 V3 V6]; [B2 B3 B5 B6 V3 V6] # 㸳ߊ≮.ێss- +B; xn--lsb457kkut.xn--ss--qjf2343a; [B2 B3 B5 B6 C2 V6]; [B2 B3 B5 B6 C2 V6] # 㸳ߊ≮.ێss- +B; xn--lsb457kkut.xn----pfa076bys4a; [B2 B3 B5 B6 C2 V6]; [B2 B3 B5 B6 C2 V6] # 㸳ߊ≮.ێß- +T; 㸳\u07CA<\u0338.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CESS-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA<\u0338.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CEss-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA<\u0338.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA<\u0338.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +T; 㸳\u07CA≮.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V3 V6] # 㸳ߊ≮.ێss- +N; 㸳\u07CA≮.\u06CESs-\u200D; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # 㸳ߊ≮.ێss- +B; -ò·¬\u135E𑜧.\u1DEB-︒; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -፞𑜧.á·«-︒ +B; -ò·¬\u135E𑜧.\u1DEB-。; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -፞𑜧.á·«-. +B; xn----b5h1837n2ok9f.xn----mkm.; [V3 V5 V6]; [V3 V5 V6] # -፞𑜧.á·«-. +B; xn----b5h1837n2ok9f.xn----mkmw278h; [V3 V5 V6]; [V3 V5 V6] # -፞𑜧.á·«-︒ +B; ︒.òš ¡\u1A59; [P1 V6]; [P1 V6] # ︒.ᩙ +B; 。.òš ¡\u1A59; [P1 V6 A4_2]; [P1 V6 A4_2] # ..ᩙ +B; ..xn--cof61594i; [V6 A4_2]; [V6 A4_2] # ..ᩙ +B; xn--y86c.xn--cof61594i; [V6]; [V6] # ︒.ᩙ +T; \u0323\u2DE1。\u200C⓾\u200C\u06B9; [B1 B3 B6 C1 V5]; [B1 B3 B6 V5] # ̣ⷡ.⓾ڹ +N; \u0323\u2DE1。\u200C⓾\u200C\u06B9; [B1 B3 B6 C1 V5]; [B1 B3 B6 C1 V5] # ̣ⷡ.⓾ڹ +B; xn--kta899s.xn--skb116m; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ̣ⷡ.⓾ڹ +B; xn--kta899s.xn--skb970ka771c; [B1 B3 B6 C1 V5]; [B1 B3 B6 C1 V5] # ̣ⷡ.⓾ڹ +B; 𞠶ᠴ\u06DD。\u1074𞤵󠅦; [B1 B2 P1 V5 V6]; [B1 B2 P1 V5 V6] # 𞠶ᠴ.ၴ𞤵 +B; 𞠶ᠴ\u06DD。\u1074𞤵󠅦; [B1 B2 P1 V5 V6]; [B1 B2 P1 V5 V6] # 𞠶ᠴ.ၴ𞤵 +B; 𞠶ᠴ\u06DD。\u1074𞤓󠅦; [B1 B2 P1 V5 V6]; [B1 B2 P1 V5 V6] # 𞠶ᠴ.ၴ𞤵 +B; xn--tlb199fwl35a.xn--yld4613v; [B1 B2 V5 V6]; [B1 B2 V5 V6] # 𞠶ᠴ.ၴ𞤵 +B; 𞠶ᠴ\u06DD。\u1074𞤓󠅦; [B1 B2 P1 V5 V6]; [B1 B2 P1 V5 V6] # 𞠶ᠴ.ၴ𞤵 +B; 𑰺.-ò‘Ÿ; [P1 V3 V5 V6]; [P1 V3 V5 V6] +B; xn--jk3d.xn----iz68g; [V3 V5 V6]; [V3 V5 V6] +B; 󠻩.赏; [P1 V6]; [P1 V6] +B; ó »©.赏; [P1 V6]; [P1 V6] +B; xn--2856e.xn--6o3a; [V6]; [V6] +B; \u06B0ᠡ。Ⴁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # Ú°á ¡.Ⴁ +B; \u06B0ᠡ。Ⴁ; [B2 B3 P1 V6]; [B2 B3 P1 V6] # Ú°á ¡.Ⴁ +B; \u06B0ᠡ。ⴁ; [B2 B3]; [B2 B3] # Ú°á ¡.ⴁ +B; xn--jkb440g.xn--skj; [B2 B3]; [B2 B3] # Ú°á ¡.ⴁ +B; xn--jkb440g.xn--8md; [B2 B3 V6]; [B2 B3 V6] # Ú°á ¡.Ⴁ +B; \u06B0ᠡ。ⴁ; [B2 B3]; [B2 B3] # Ú°á ¡.ⴁ +T; \u20DEႪ\u06BBς。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻς.- +N; \u20DEႪ\u06BBς。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻς.- +T; \u20DEႪ\u06BBς。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻς.- +N; \u20DEႪ\u06BBς。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻς.- +T; \u20DEⴊ\u06BBς。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻς.- +N; \u20DEⴊ\u06BBς。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻς.- +B; \u20DEႪ\u06BBΣ。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻσ.- +B; \u20DEⴊ\u06BBσ。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻσ.- +B; \u20DEႪ\u06BBσ。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻσ.- +B; xn--4xa33m7zmb0q.-; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ⃞Ⴊڻσ.- +B; xn--4xa33mr38aeel.-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻσ.- +B; xn--3xa53mr38aeel.-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻς.- +B; xn--3xa53m7zmb0q.-; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ⃞Ⴊڻς.- +T; \u20DEⴊ\u06BBς。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻς.- +N; \u20DEⴊ\u06BBς。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻς.- +B; \u20DEႪ\u06BBΣ。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻσ.- +B; \u20DEⴊ\u06BBσ。-; [B1 V3 V5]; [B1 V3 V5] # ⃞ⴊڻσ.- +B; \u20DEႪ\u06BBσ。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ⃞Ⴊڻσ.- +T; Ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [P1 V6] # Ⴍ. +N; Ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [C1 P1 V6] # Ⴍ. +T; Ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [P1 V6] # Ⴍ. +N; Ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [C1 P1 V6] # Ⴍ. +T; ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [P1 V6] # ⴍ. +N; ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [C1 P1 V6] # ⴍ. +B; xn--4kj.xn--p01x; [V6]; [V6] +B; xn--4kj.xn--0ug56448b; [C1 V6]; [C1 V6] # ⴍ. +B; xn--lnd.xn--p01x; [V6]; [V6] +B; xn--lnd.xn--0ug56448b; [C1 V6]; [C1 V6] # Ⴍ. +T; ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [P1 V6] # ⴍ. +N; ⴍ.ñ‡¦\u200C; [C1 P1 V6]; [C1 P1 V6] # ⴍ. +B; ò‰Ÿ‚ó µ£.𐫫\u1A60󴺖\u1B44; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # .𐫫᩠᭄ +B; xn--9u37blu98h.xn--jof13bt568cork1j; [B2 B3 B6 V6]; [B2 B3 B6 V6] # .𐫫᩠᭄ +B; ≯❊ᠯ。𐹱⺨; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338❊ᠯ。𐹱⺨; [B1 P1 V6]; [B1 P1 V6] +B; ≯❊ᠯ。𐹱⺨; [B1 P1 V6]; [B1 P1 V6] +B; >\u0338❊ᠯ。𐹱⺨; [B1 P1 V6]; [B1 P1 V6] +B; xn--i7e163ct2d.xn--vwj7372e; [B1 V6]; [B1 V6] +B; ô•œð¹§ðž­ð¹©ã€‚Ⴈ𐫮Ⴏ; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; ô•œð¹§ðž­ð¹©ã€‚ⴈ𐫮ⴏ; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; xn--fo0de1270ope54j.xn--zkjo0151o; [B5 B6 V6]; [B5 B6 V6] +B; xn--fo0de1270ope54j.xn--gndo2033q; [B5 B6 V6]; [B5 B6 V6] +B; 𞠂。\uA926; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𞠂.ꤦ +B; xn--145h.xn--ti9a; [B1 B3 B6 V5]; [B1 B3 B6 V5] # 𞠂.ꤦ +B; 𝟔𐹫.\u0733\u10379ꡇ; [B1 V5]; [B1 V5] # 6𐹫.့ܳ9ꡇ +B; 𝟔𐹫.\u1037\u07339ꡇ; [B1 V5]; [B1 V5] # 6𐹫.့ܳ9ꡇ +B; 6𐹫.\u1037\u07339ꡇ; [B1 V5]; [B1 V5] # 6𐹫.့ܳ9ꡇ +B; xn--6-t26i.xn--9-91c730e8u8n; [B1 V5]; [B1 V5] # 6𐹫.့ܳ9ꡇ +B; \u0724\u0603𞲶.\u06D8; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ܤ.ۘ +B; \u0724\u0603𞲶.\u06D8; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # ܤ.ۘ +B; xn--lfb19ct414i.xn--olb; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # ܤ.ۘ +T; ✆ñ±”©ê¡‹ï¼Ž\u0632\u200D𞣴; [B1 C2 P1 V6]; [B1 P1 V6] # ✆ꡋ.ز +N; ✆ñ±”©ê¡‹ï¼Ž\u0632\u200D𞣴; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ✆ꡋ.ز +T; ✆ñ±”©ê¡‹.\u0632\u200D𞣴; [B1 C2 P1 V6]; [B1 P1 V6] # ✆ꡋ.ز +N; ✆ñ±”©ê¡‹.\u0632\u200D𞣴; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ✆ꡋ.ز +B; xn--1biv525bcix0d.xn--xgb6828v; [B1 V6]; [B1 V6] # ✆ꡋ.ز +B; xn--1biv525bcix0d.xn--xgb253k0m73a; [B1 C2 V6]; [B1 C2 V6] # ✆ꡋ.ز +B; \u0845ñƒ¾°ðž¸-.≠òƒŸð‘‹ª; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ࡅن-.≠𑋪 +B; \u0845ñƒ¾°ðž¸-.=\u0338òƒŸð‘‹ª; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ࡅن-.≠𑋪 +B; \u0845ñƒ¾°\u0646-.≠òƒŸð‘‹ª; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ࡅن-.≠𑋪 +B; \u0845ñƒ¾°\u0646-.=\u0338òƒŸð‘‹ª; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ࡅن-.≠𑋪 +B; xn----qoc64my971s.xn--1ch7585g76o3c; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # ࡅن-.≠𑋪 +B; 𝟛.笠; 3.笠; 3.xn--6vz +B; 𝟛.笠; 3.笠; 3.xn--6vz +B; 3.笠; ; 3.xn--6vz +B; 3.xn--6vz; 3.笠; 3.xn--6vz +T; -\u200D.Ⴞ𐋷; [C2 P1 V3 V6]; [P1 V3 V6] # -.Ⴞ𐋷 +N; -\u200D.Ⴞ𐋷; [C2 P1 V3 V6]; [C2 P1 V3 V6] # -.Ⴞ𐋷 +T; -\u200D.ⴞ𐋷; [C2 V3]; [V3] # -.ⴞ𐋷 +N; -\u200D.ⴞ𐋷; [C2 V3]; [C2 V3] # -.ⴞ𐋷 +B; -.xn--mlj8559d; [V3]; [V3] +B; xn----ugn.xn--mlj8559d; [C2 V3]; [C2 V3] # -.ⴞ𐋷 +B; -.xn--2nd2315j; [V3 V6]; [V3 V6] +B; xn----ugn.xn--2nd2315j; [C2 V3 V6]; [C2 V3 V6] # -.Ⴞ𐋷 +T; \u200Dςß\u0731.\u0BCD; [C2 V5]; [V5] # ςßܱ.் +N; \u200Dςß\u0731.\u0BCD; [C2 V5]; [C2 V5] # ςßܱ.் +T; \u200Dςß\u0731.\u0BCD; [C2 V5]; [V5] # ςßܱ.் +N; \u200Dςß\u0731.\u0BCD; [C2 V5]; [C2 V5] # ςßܱ.் +T; \u200DΣSS\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200DΣSS\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200Dσss\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200Dσss\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200DΣss\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200DΣss\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +B; xn--ss-ubc826a.xn--xmc; [V5]; [V5] # σssܱ.் +B; xn--ss-ubc826ab34b.xn--xmc; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200DΣß\u0731.\u0BCD; [C2 V5]; [V5] # σßܱ.் +N; \u200DΣß\u0731.\u0BCD; [C2 V5]; [C2 V5] # σßܱ.் +T; \u200Dσß\u0731.\u0BCD; [C2 V5]; [V5] # σßܱ.் +N; \u200Dσß\u0731.\u0BCD; [C2 V5]; [C2 V5] # σßܱ.் +B; xn--zca39lk1di19a.xn--xmc; [C2 V5]; [C2 V5] # σßܱ.் +B; xn--zca19ln1di19a.xn--xmc; [C2 V5]; [C2 V5] # ςßܱ.் +T; \u200DΣSS\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200DΣSS\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200Dσss\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200Dσss\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200DΣss\u0731.\u0BCD; [C2 V5]; [V5] # σssܱ.் +N; \u200DΣss\u0731.\u0BCD; [C2 V5]; [C2 V5] # σssܱ.் +T; \u200DΣß\u0731.\u0BCD; [C2 V5]; [V5] # σßܱ.் +N; \u200DΣß\u0731.\u0BCD; [C2 V5]; [C2 V5] # σßܱ.் +T; \u200Dσß\u0731.\u0BCD; [C2 V5]; [V5] # σßܱ.் +N; \u200Dσß\u0731.\u0BCD; [C2 V5]; [C2 V5] # σßܱ.் +T; ≠.\u200D; [C2 P1 V6]; [P1 V6] # ≠. +N; ≠.\u200D; [C2 P1 V6]; [C2 P1 V6] # ≠. +T; =\u0338.\u200D; [C2 P1 V6]; [P1 V6] # ≠. +N; =\u0338.\u200D; [C2 P1 V6]; [C2 P1 V6] # ≠. +T; ≠.\u200D; [C2 P1 V6]; [P1 V6] # ≠. +N; ≠.\u200D; [C2 P1 V6]; [C2 P1 V6] # ≠. +T; =\u0338.\u200D; [C2 P1 V6]; [P1 V6] # ≠. +N; =\u0338.\u200D; [C2 P1 V6]; [C2 P1 V6] # ≠. +B; xn--1ch.; [V6]; [V6] +B; xn--1ch.xn--1ug; [C2 V6]; [C2 V6] # ≠. +B; \uFC01。\u0C81ᠼ▗ò’‹; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ئح.ಁᠼ▗ +B; \u0626\u062D。\u0C81ᠼ▗ò’‹; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ئح.ಁᠼ▗ +B; \u064A\u0654\u062D。\u0C81ᠼ▗ò’‹; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ئح.ಁᠼ▗ +B; xn--lgbo.xn--2rc021dcxkrx55t; [B1 V5 V6]; [B1 V5 V6] # ئح.ಁᠼ▗ +T; 󧋵\u09CDς.ς𐨿; [P1 V6]; [P1 V6] # ্ς.ς𐨿 +N; 󧋵\u09CDς.ς𐨿; [P1 V6]; [P1 V6] # ্ς.ς𐨿 +T; 󧋵\u09CDς.ς𐨿; [P1 V6]; [P1 V6] # ্ς.ς𐨿 +N; 󧋵\u09CDς.ς𐨿; [P1 V6]; [P1 V6] # ্ς.ς𐨿 +B; 󧋵\u09CDΣ.Σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +T; 󧋵\u09CDσ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +N; 󧋵\u09CDσ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +B; 󧋵\u09CDσ.σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +B; 󧋵\u09CDΣ.σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +B; xn--4xa502av8297a.xn--4xa6055k; [V6]; [V6] # ্σ.σ𐨿 +T; 󧋵\u09CDΣ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +N; 󧋵\u09CDΣ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +B; xn--4xa502av8297a.xn--3xa8055k; [V6]; [V6] # ্σ.ς𐨿 +B; xn--3xa702av8297a.xn--3xa8055k; [V6]; [V6] # ্ς.ς𐨿 +B; 󧋵\u09CDΣ.Σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +T; 󧋵\u09CDσ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +N; 󧋵\u09CDσ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +B; 󧋵\u09CDσ.σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +B; 󧋵\u09CDΣ.σ𐨿; [P1 V6]; [P1 V6] # ্σ.σ𐨿 +T; 󧋵\u09CDΣ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +N; 󧋵\u09CDΣ.ς𐨿; [P1 V6]; [P1 V6] # ্σ.ς𐨿 +B; 𐫓\u07D8牅\u08F8。𞦤\u1A17ò±°á‚¹; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐫓ߘ牅ࣸ.ᨗႹ +B; 𐫓\u07D8牅\u08F8。𞦤\u1A17ò±°á‚¹; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐫓ߘ牅ࣸ.ᨗႹ +B; 𐫓\u07D8牅\u08F8。𞦤\u1A17ò±°â´™; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐫓ߘ牅ࣸ.ᨗⴙ +B; xn--zsb09cu46vjs6f.xn--gmf469fr883am5r1e; [B2 B3 V6]; [B2 B3 V6] # 𐫓ߘ牅ࣸ.ᨗⴙ +B; xn--zsb09cu46vjs6f.xn--xnd909bv540bm5k9d; [B2 B3 V6]; [B2 B3 V6] # 𐫓ߘ牅ࣸ.ᨗႹ +B; 𐫓\u07D8牅\u08F8。𞦤\u1A17ò±°â´™; [B2 B3 P1 V6]; [B2 B3 P1 V6] # 𐫓ߘ牅ࣸ.ᨗⴙ +B; ñ£¤’。륧; [P1 V6]; [P1 V6] +B; ñ£¤’。륧; [P1 V6]; [P1 V6] +B; ñ£¤’。륧; [P1 V6]; [P1 V6] +B; ñ£¤’。륧; [P1 V6]; [P1 V6] +B; xn--s264a.xn--pw2b; [V6]; [V6] +T; 𐹷\u200D。󉵢; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹷. +N; 𐹷\u200D。󉵢; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹷. +B; xn--vo0d.xn--8088d; [B1 V6]; [B1 V6] +B; xn--1ugx205g.xn--8088d; [B1 C2 V6]; [B1 C2 V6] # 𐹷. +B; Ⴘ\u06C2𑲭。-; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # Ⴘۂ𑲭.- +B; Ⴘ\u06C1\u0654𑲭。-; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # Ⴘۂ𑲭.- +B; Ⴘ\u06C2𑲭。-; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # Ⴘۂ𑲭.- +B; Ⴘ\u06C1\u0654𑲭。-; [B1 B5 B6 P1 V3 V6]; [B1 B5 B6 P1 V3 V6] # Ⴘۂ𑲭.- +B; ⴘ\u06C1\u0654𑲭。-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # ⴘۂ𑲭.- +B; ⴘ\u06C2𑲭。-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # ⴘۂ𑲭.- +B; xn--1kb147qfk3n.-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # ⴘۂ𑲭.- +B; xn--1kb312c139t.-; [B1 B5 B6 V3 V6]; [B1 B5 B6 V3 V6] # Ⴘۂ𑲭.- +B; ⴘ\u06C1\u0654𑲭。-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # ⴘۂ𑲭.- +B; ⴘ\u06C2𑲭。-; [B1 B5 B6 V3]; [B1 B5 B6 V3] # ⴘۂ𑲭.- +B; \uA806\u067B₆ᡐ。🛇\uFCDD; [B1 V5]; [B1 V5] # ꠆ٻ6ᡐ.🛇يم +B; \uA806\u067B6ᡐ。🛇\u064A\u0645; [B1 V5]; [B1 V5] # ꠆ٻ6ᡐ.🛇يم +B; xn--6-rrc018krt9k.xn--hhbj61429a; [B1 V5]; [B1 V5] # ꠆ٻ6ᡐ.🛇يم +B; ò¸‚.㇄ᡟ𐫂\u0622; [B1 P1 V6]; [B1 P1 V6] # .㇄ᡟ𐫂آ +B; ò¸‚.㇄ᡟ𐫂\u0627\u0653; [B1 P1 V6]; [B1 P1 V6] # .㇄ᡟ𐫂آ +B; xn--p292d.xn--hgb154ghrsvm2r; [B1 V6]; [B1 V6] # .㇄ᡟ𐫂آ +B; \u07DFòµšŒã€‚-\u07E9; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ߟ.-ß© +B; xn--6sb88139l.xn----pdd; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # ߟ.-ß© +T; ς\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B5 P1 V6] # ςك襾.ᢟ⒈ +N; ς\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # ςك襾.ᢟ⒈ +T; ς\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B5] # ςك襾.ᢟ1. +N; ς\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B1 B5 C1] # ςك襾.ᢟ1. +T; Σ\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B5] # σك襾.ᢟ1. +N; Σ\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B1 B5 C1] # σك襾.ᢟ1. +T; σ\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B5] # σك襾.ᢟ1. +N; σ\u0643襾.\u200Cᢟ\u200C1.; [B1 B5 C1]; [B1 B5 C1] # σك襾.ᢟ1. +B; xn--4xa49jux8r.xn--1-4ck.; [B5]; [B5] # σك襾.ᢟ1. +B; xn--4xa49jux8r.xn--1-4ck691bba.; [B1 B5 C1]; [B1 B5 C1] # σك襾.ᢟ1. +B; xn--3xa69jux8r.xn--1-4ck691bba.; [B1 B5 C1]; [B1 B5 C1] # ςك襾.ᢟ1. +T; Σ\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B5 P1 V6] # σك襾.ᢟ⒈ +N; Σ\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # σك襾.ᢟ⒈ +T; σ\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B5 P1 V6] # σك襾.ᢟ⒈ +N; σ\u0643⾑.\u200Cᢟ\u200C⒈; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # σك襾.ᢟ⒈ +B; xn--4xa49jux8r.xn--pbf212d; [B5 V6]; [B5 V6] # σك襾.ᢟ⒈ +B; xn--4xa49jux8r.xn--pbf519aba607b; [B1 B5 C1 V6]; [B1 B5 C1 V6] # σك襾.ᢟ⒈ +B; xn--3xa69jux8r.xn--pbf519aba607b; [B1 B5 C1 V6]; [B1 B5 C1 V6] # ςك襾.ᢟ⒈ +B; ᡆ𑓝.𞵆; [P1 V6]; [P1 V6] +B; ᡆ𑓝.𞵆; [P1 V6]; [P1 V6] +B; xn--57e0440k.xn--k86h; [V6]; [V6] +T; \u0A4D𦍓\u1DEE。\u200C\u08BDñ¹²; [B1 C1 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ੍𦍓ᷮ.ࢽ +N; \u0A4D𦍓\u1DEE。\u200C\u08BDñ¹²; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # ੍𦍓ᷮ.ࢽ +T; \u0A4D𦍓\u1DEE。\u200C\u08BDñ¹²; [B1 C1 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ੍𦍓ᷮ.ࢽ +N; \u0A4D𦍓\u1DEE。\u200C\u08BDñ¹²; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # ੍𦍓ᷮ.ࢽ +B; xn--ybc461hph93b.xn--jzb29857e; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # ੍𦍓ᷮ.ࢽ +B; xn--ybc461hph93b.xn--jzb740j1y45h; [B1 C1 V5 V6]; [B1 C1 V5 V6] # ੍𦍓ᷮ.ࢽ +T; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B2 B3 P1 V3 V6] # خ݈-.먿 +N; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B1 B2 B3 C1 P1 V3 V6] # خ݈-.먿 +T; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B2 B3 P1 V3 V6] # خ݈-.먿 +N; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B1 B2 B3 C1 P1 V3 V6] # خ݈-.먿 +T; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B2 B3 P1 V3 V6] # خ݈-.먿 +N; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B1 B2 B3 C1 P1 V3 V6] # خ݈-.먿 +T; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B2 B3 P1 V3 V6] # خ݈-.먿 +N; \u062E\u0748ñ…ªª-.\u200C먿; [B1 B2 B3 C1 P1 V3 V6]; [B1 B2 B3 C1 P1 V3 V6] # خ݈-.먿 +B; xn----dnc06f42153a.xn--v22b; [B2 B3 V3 V6]; [B2 B3 V3 V6] # خ݈-.먿 +B; xn----dnc06f42153a.xn--0ug1581d; [B1 B2 B3 C1 V3 V6]; [B1 B2 B3 C1 V3 V6] # خ݈-.먿 +B; ô‹¿¦ï½¡á ½; [P1 V6]; [P1 V6] +B; ô‹¿¦ã€‚á ½; [P1 V6]; [P1 V6] +B; xn--j890g.xn--w7e; [V6]; [V6] +T; 嬃𝍌.\u200D\u0B44; [C2]; [V5] # 嬃𝍌.ୄ +N; 嬃𝍌.\u200D\u0B44; [C2]; [C2] # 嬃𝍌.ୄ +T; 嬃𝍌.\u200D\u0B44; [C2]; [V5] # 嬃𝍌.ୄ +N; 嬃𝍌.\u200D\u0B44; [C2]; [C2] # 嬃𝍌.ୄ +B; xn--b6s0078f.xn--0ic; [V5]; [V5] # 嬃𝍌.ୄ +B; xn--b6s0078f.xn--0ic557h; [C2]; [C2] # 嬃𝍌.ୄ +B; \u0602𝌪≯.𚋲òµ¨; [B1 P1 V6]; [B1 P1 V6] # 𝌪≯. +B; \u0602𝌪>\u0338.𚋲òµ¨; [B1 P1 V6]; [B1 P1 V6] # 𝌪≯. +B; \u0602𝌪≯.𚋲òµ¨; [B1 P1 V6]; [B1 P1 V6] # 𝌪≯. +B; \u0602𝌪>\u0338.𚋲òµ¨; [B1 P1 V6]; [B1 P1 V6] # 𝌪≯. +B; xn--kfb866llx01a.xn--wp1gm3570b; [B1 V6]; [B1 V6] # 𝌪≯. +B; ò«¾¥\u08B7\u17CC\uA9C0.𞼠; [B5 P1 V6]; [B5 P1 V6] # ࢷ៌꧀. +B; xn--dzb638ewm4i1iy1h.xn--3m7h; [B5 V6]; [B5 V6] # ࢷ៌꧀. +T; \u200C.ñŸ›¤; [C1 P1 V6]; [P1 V6 A4_2] # . +N; \u200C.ñŸ›¤; [C1 P1 V6]; [C1 P1 V6] # . +B; .xn--q823a; [V6 A4_2]; [V6 A4_2] +B; xn--0ug.xn--q823a; [C1 V6]; [C1 V6] # . +B; òº›•Ⴃ䠅.𐸑; [P1 V6]; [P1 V6] +B; òº›•Ⴃ䠅.𐸑; [P1 V6]; [P1 V6] +B; òº›•ⴃ䠅.𐸑; [P1 V6]; [P1 V6] +B; xn--ukju77frl47r.xn--yl0d; [V6]; [V6] +B; xn--bnd074zr557n.xn--yl0d; [V6]; [V6] +B; òº›•ⴃ䠅.𐸑; [P1 V6]; [P1 V6] +B; \u1BF1𐹳𐹵𞤚。𝟨Ⴅ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᯱ𐹳𐹵𞤼.6Ⴅ +B; \u1BF1𐹳𐹵𞤚。6Ⴅ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ᯱ𐹳𐹵𞤼.6Ⴅ +B; \u1BF1𐹳𐹵𞤼。6ⴅ; [B1 V5]; [B1 V5] # ᯱ𐹳𐹵𞤼.6ⴅ +B; xn--zzfy954hga2415t.xn--6-kvs; [B1 V5]; [B1 V5] # ᯱ𐹳𐹵𞤼.6ⴅ +B; xn--zzfy954hga2415t.xn--6-h0g; [B1 V5 V6]; [B1 V5 V6] # ᯱ𐹳𐹵𞤼.6Ⴅ +B; \u1BF1𐹳𐹵𞤼。𝟨ⴅ; [B1 V5]; [B1 V5] # ᯱ𐹳𐹵𞤼.6ⴅ +B; \u1BF1𐹳𐹵𞤚。6ⴅ; [B1 V5]; [B1 V5] # ᯱ𐹳𐹵𞤼.6ⴅ +B; \u1BF1𐹳𐹵𞤚。𝟨ⴅ; [B1 V5]; [B1 V5] # ᯱ𐹳𐹵𞤼.6ⴅ +B; -。︒; [P1 V3 V6]; [P1 V3 V6] +B; -。。; [V3 A4_2]; [V3 A4_2] +B; -..; [V3 A4_2]; [V3 A4_2] +B; -.xn--y86c; [V3 V6]; [V3 V6] +B; \u07DBჀ。-⁵--; [B1 B2 B3 P1 V2 V3 V6]; [B1 B2 B3 P1 V2 V3 V6] # ߛჀ.-5-- +B; \u07DBჀ。-5--; [B1 B2 B3 P1 V2 V3 V6]; [B1 B2 B3 P1 V2 V3 V6] # ߛჀ.-5-- +B; \u07DBⴠ。-5--; [B1 B2 B3 V2 V3]; [B1 B2 B3 V2 V3] # ߛⴠ.-5-- +B; xn--2sb691q.-5--; [B1 B2 B3 V2 V3]; [B1 B2 B3 V2 V3] # ߛⴠ.-5-- +B; xn--2sb866b.-5--; [B1 B2 B3 V2 V3 V6]; [B1 B2 B3 V2 V3 V6] # ߛჀ.-5-- +B; \u07DBⴠ。-⁵--; [B1 B2 B3 V2 V3]; [B1 B2 B3 V2 V3] # ߛⴠ.-5-- +B; ≯\uD8DD󠑕。𐹷𐹻≯𐷒; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; >\u0338\uD8DD󠑕。𐹷𐹻>\u0338𐷒; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; ≯\uD8DD󠑕。𐹷𐹻≯𐷒; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; >\u0338\uD8DD󠑕。𐹷𐹻>\u0338𐷒; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; ≯\uD8DD󠑕.xn--hdh8283gdoaqa; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; >\u0338\uD8DD󠑕.xn--hdh8283gdoaqa; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; >\u0338\uD8DD󠑕.XN--HDH8283GDOAQA; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; ≯\uD8DD󠑕.XN--HDH8283GDOAQA; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; ≯\uD8DD󠑕.Xn--Hdh8283gdoaqa; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +B; >\u0338\uD8DD󠑕.Xn--Hdh8283gdoaqa; [B1 P1 V6]; [B1 P1 V6 A3] # ≯.𐹷𐹻≯ +T; ㍔\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ルーブルࣦݼ.͆ +N; ㍔\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # ルーブルࣦݼ.͆ +T; ルーブル\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ルーブルࣦݼ.͆ +N; ルーブル\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # ルーブルࣦݼ.͆ +T; ルーフ\u3099ル\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # ルーブルࣦݼ.͆ +N; ルーフ\u3099ル\u08E6\u077C\u200D。\u0346ò³Šð…¶\u0604; [B1 B5 B6 C2 P1 V5 V6]; [B1 B5 B6 C2 P1 V5 V6] # ルーブルࣦݼ.͆ +B; xn--dqb73el09fncab4h.xn--kua81ls548d3608b; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # ルーブルࣦݼ.͆ +B; xn--dqb73ec22c9kp8cb1j.xn--kua81ls548d3608b; [B1 B5 B6 C2 V5 V6]; [B1 B5 B6 C2 V5 V6] # ルーブルࣦݼ.͆ +T; \u200D.F; [C2]; [A4_2] # .f +N; \u200D.F; [C2]; [C2] # .f +T; \u200D.f; [C2]; [A4_2] # .f +N; \u200D.f; [C2]; [C2] # .f +B; .f; [A4_2]; [A4_2] +B; xn--1ug.f; [C2]; [C2] # .f +B; f; ; +T; \u200D㨲。ß; [C2]; xn--9bm.ss # 㨲.ß +N; \u200D㨲。ß; [C2]; [C2] # 㨲.ß +T; \u200D㨲。ß; [C2]; xn--9bm.ss # 㨲.ß +N; \u200D㨲。ß; [C2]; [C2] # 㨲.ß +T; \u200D㨲。SS; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。SS; [C2]; [C2] # 㨲.ss +T; \u200D㨲。ss; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。ss; [C2]; [C2] # 㨲.ss +T; \u200D㨲。Ss; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。Ss; [C2]; [C2] # 㨲.ss +B; xn--9bm.ss; 㨲.ss; xn--9bm.ss +B; 㨲.ss; ; xn--9bm.ss +B; 㨲.SS; 㨲.ss; xn--9bm.ss +B; 㨲.Ss; 㨲.ss; xn--9bm.ss +B; xn--1ug914h.ss; [C2]; [C2] # 㨲.ss +B; xn--1ug914h.xn--zca; [C2]; [C2] # 㨲.ß +T; \u200D㨲。SS; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。SS; [C2]; [C2] # 㨲.ss +T; \u200D㨲。ss; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。ss; [C2]; [C2] # 㨲.ss +T; \u200D㨲。Ss; [C2]; xn--9bm.ss # 㨲.ss +N; \u200D㨲。Ss; [C2]; [C2] # 㨲.ss +B; \u0605\u067E。\u08A8; [B1 P1 V6]; [B1 P1 V6] # Ù¾.ࢨ +B; \u0605\u067E。\u08A8; [B1 P1 V6]; [B1 P1 V6] # Ù¾.ࢨ +B; xn--nfb6v.xn--xyb; [B1 V6]; [B1 V6] # Ù¾.ࢨ +B; ⾑\u0753𞤁。𐹵\u0682; [B1 B5 B6]; [B1 B5 B6] # 襾ݓ𞤣.𐹵ڂ +B; 襾\u0753𞤁。𐹵\u0682; [B1 B5 B6]; [B1 B5 B6] # 襾ݓ𞤣.𐹵ڂ +B; 襾\u0753𞤣。𐹵\u0682; [B1 B5 B6]; [B1 B5 B6] # 襾ݓ𞤣.𐹵ڂ +B; xn--6ob9577deqwl.xn--7ib5526k; [B1 B5 B6]; [B1 B5 B6] # 襾ݓ𞤣.𐹵ڂ +B; ⾑\u0753𞤣。𐹵\u0682; [B1 B5 B6]; [B1 B5 B6] # 襾ݓ𞤣.𐹵ڂ +T; ñ¦´»Ï‚-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ς-⃫.ݔ-ꡛ +N; ñ¦´»Ï‚-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ς-⃫.ݔ-ꡛ +T; ñ¦´»Ï‚-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ς-⃫.ݔ-ꡛ +N; ñ¦´»Ï‚-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ς-⃫.ݔ-ꡛ +B; ñ¦´»Î£-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # σ-⃫.ݔ-ꡛ +B; ñ¦´»Ïƒ-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # σ-⃫.ݔ-ꡛ +B; xn----zmb705tuo34l.xn----53c4874j; [B2 B3 B6 V6]; [B2 B3 B6 V6] # σ-⃫.ݔ-ꡛ +B; xn----xmb015tuo34l.xn----53c4874j; [B2 B3 B6 V6]; [B2 B3 B6 V6] # ς-⃫.ݔ-ꡛ +B; ñ¦´»Î£-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # σ-⃫.ݔ-ꡛ +B; ñ¦´»Ïƒ-\u20EB。\u0754-ꡛ; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # σ-⃫.ݔ-ꡛ +T; \u200D.ô€¸¨; [C2 P1 V6]; [P1 V6 A4_2] # . +N; \u200D.ô€¸¨; [C2 P1 V6]; [C2 P1 V6] # . +T; \u200D.ô€¸¨; [C2 P1 V6]; [P1 V6 A4_2] # . +N; \u200D.ô€¸¨; [C2 P1 V6]; [C2 P1 V6] # . +B; .xn--h327f; [V6 A4_2]; [V6 A4_2] +B; xn--1ug.xn--h327f; [C2 V6]; [C2 V6] # . +B; ñ£­»ñŒ¥ï½¡â‰ ðŸ²; [P1 V6]; [P1 V6] +B; ñ£­»ñŒ¥ï½¡=\u0338𝟲; [P1 V6]; [P1 V6] +B; ñ£­»ñŒ¥ã€‚≠6; [P1 V6]; [P1 V6] +B; ñ£­»ñŒ¥ã€‚=\u03386; [P1 V6]; [P1 V6] +B; xn--h79w4z99a.xn--6-tfo; [V6]; [V6] +T; 󠅊ᡭ\u200D.𐥡; [B6 C2 P1 V6]; [P1 V6] # á¡­. +N; 󠅊ᡭ\u200D.𐥡; [B6 C2 P1 V6]; [B6 C2 P1 V6] # á¡­. +B; xn--98e.xn--om9c; [V6]; [V6] +B; xn--98e810b.xn--om9c; [B6 C2 V6]; [B6 C2 V6] # á¡­. +B; \u0C40\u0855𐥛𑄴.󭰵; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ీࡕ𑄴. +B; \u0C40\u0855𐥛𑄴.ó­°µ; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ీࡕ𑄴. +B; xn--kwb91r5112avtg.xn--o580f; [B1 V5 V6]; [B1 V5 V6] # ీࡕ𑄴. +T; 𞤮。𑇊\u200C≯\u1CE6; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤮.𑇊≯᳦ +N; 𞤮。𑇊\u200C≯\u1CE6; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𞤮.𑇊≯᳦ +T; 𞤮。𑇊\u200C>\u0338\u1CE6; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤮.𑇊≯᳦ +N; 𞤮。𑇊\u200C>\u0338\u1CE6; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𞤮.𑇊≯᳦ +T; 𞤌。𑇊\u200C>\u0338\u1CE6; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤮.𑇊≯᳦ +N; 𞤌。𑇊\u200C>\u0338\u1CE6; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𞤮.𑇊≯᳦ +T; 𞤌。𑇊\u200C≯\u1CE6; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤮.𑇊≯᳦ +N; 𞤌。𑇊\u200C≯\u1CE6; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𞤮.𑇊≯᳦ +B; xn--me6h.xn--z6fz8ueq2v; [B1 V5 V6]; [B1 V5 V6] # 𞤮.𑇊≯᳦ +B; xn--me6h.xn--z6f16kn9b2642b; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 𞤮.𑇊≯᳦ +B; 󠄀𝟕.𞤌ñ›—“á‚©; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 󠄀7.𞤌ñ›—“á‚©; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 󠄀7.𞤮ñ›—“â´‰; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 7.xn--0kjz523lv1vv; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; 7.xn--hnd3403vv1vv; [B1 B2 B3 V6]; [B1 B2 B3 V6] +B; 󠄀𝟕.𞤮ñ›—“â´‰; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 󠄀7.𞤌ñ›—“â´‰; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 󠄀𝟕.𞤌ñ›—“â´‰; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] +B; 閃9𝩍。Ↄ\u0669\u08B1\u0B4D; [B5 B6 P1 V6]; [B5 B6 P1 V6] # 閃9𝩍.Ↄ٩ࢱ୍ +B; 閃9𝩍。ↄ\u0669\u08B1\u0B4D; [B5 B6]; [B5 B6] # 閃9𝩍.ↄ٩ࢱ୍ +B; xn--9-3j6dk517f.xn--iib28ij3c4t9a; [B5 B6]; [B5 B6] # 閃9𝩍.ↄ٩ࢱ୍ +B; xn--9-3j6dk517f.xn--iib28ij3c0t9a; [B5 B6 V6]; [B5 B6 V6] # 閃9𝩍.Ↄ٩ࢱ୍ +B; \uAAF6ᢏ\u0E3A2.𐋢\u0745\u0F9F︒; [P1 V5 V6]; [P1 V5 V6] # ꫶ᢏฺ2.𐋢݅ྟ︒ +B; \uAAF6ᢏ\u0E3A2.𐋢\u0745\u0F9F。; [V5]; [V5] # ꫶ᢏฺ2.𐋢݅ྟ. +B; xn--2-2zf840fk16m.xn--sob093b2m7s.; [V5]; [V5] # ꫶ᢏฺ2.𐋢݅ྟ. +B; xn--2-2zf840fk16m.xn--sob093bj62sz9d; [V5 V6]; [V5 V6] # ꫶ᢏฺ2.𐋢݅ྟ︒ +B; 󅴧。≠-󠙄⾛; [P1 V6]; [P1 V6] +B; 󅴧。=\u0338-󠙄⾛; [P1 V6]; [P1 V6] +B; 󅴧。≠-󠙄走; [P1 V6]; [P1 V6] +B; 󅴧。=\u0338-󠙄走; [P1 V6]; [P1 V6] +B; xn--gm57d.xn----tfo4949b3664m; [V6]; [V6] +B; \u076E\u0604Ⴊ。-≠\u1160; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ݮႪ.-≠ +B; \u076E\u0604Ⴊ。-=\u0338\u1160; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ݮႪ.-≠ +B; \u076E\u0604ⴊ。-=\u0338\u1160; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ݮⴊ.-≠ +B; \u076E\u0604ⴊ。-≠\u1160; [B1 B2 B3 P1 V3 V6]; [B1 B2 B3 P1 V3 V6] # ݮⴊ.-≠ +B; xn--mfb73ek93f.xn----5bh589i; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # ݮⴊ.-≠ +B; xn--mfb73ex6r.xn----5bh589i; [B1 B2 B3 V3 V6]; [B1 B2 B3 V3 V6] # ݮႪ.-≠ +T; \uFB4F𐹧𝟒≯。\u200C; [B1 B3 B4 C1 P1 V6]; [B3 B4 P1 V6] # אל𐹧4≯. +N; \uFB4F𐹧𝟒≯。\u200C; [B1 B3 B4 C1 P1 V6]; [B1 B3 B4 C1 P1 V6] # אל𐹧4≯. +T; \uFB4F𐹧𝟒>\u0338。\u200C; [B1 B3 B4 C1 P1 V6]; [B3 B4 P1 V6] # אל𐹧4≯. +N; \uFB4F𐹧𝟒>\u0338。\u200C; [B1 B3 B4 C1 P1 V6]; [B1 B3 B4 C1 P1 V6] # אל𐹧4≯. +T; \u05D0\u05DC𐹧4≯。\u200C; [B1 B3 B4 C1 P1 V6]; [B3 B4 P1 V6] # אל𐹧4≯. +N; \u05D0\u05DC𐹧4≯。\u200C; [B1 B3 B4 C1 P1 V6]; [B1 B3 B4 C1 P1 V6] # אל𐹧4≯. +T; \u05D0\u05DC𐹧4>\u0338。\u200C; [B1 B3 B4 C1 P1 V6]; [B3 B4 P1 V6] # אל𐹧4≯. +N; \u05D0\u05DC𐹧4>\u0338。\u200C; [B1 B3 B4 C1 P1 V6]; [B1 B3 B4 C1 P1 V6] # אל𐹧4≯. +B; xn--4-zhc0by36txt0w.; [B3 B4 V6]; [B3 B4 V6] # אל𐹧4≯. +B; xn--4-zhc0by36txt0w.xn--0ug; [B1 B3 B4 C1 V6]; [B1 B3 B4 C1 V6] # אל𐹧4≯. +B; 𝟎。甯; 0.甯; 0.xn--qny +B; 0。甯; 0.甯; 0.xn--qny +B; 0.xn--qny; 0.甯; 0.xn--qny +B; 0.甯; ; 0.xn--qny +B; -⾆.\uAAF6; [V3 V5]; [V3 V5] # -舌.ê«¶ +B; -舌.\uAAF6; [V3 V5]; [V3 V5] # -舌.ê«¶ +B; xn----ef8c.xn--2v9a; [V3 V5]; [V3 V5] # -舌.ê«¶ +B; -。ᢘ; [V3]; [V3] +B; -。ᢘ; [V3]; [V3] +B; -.xn--ibf; [V3]; [V3] +B; 🂴Ⴋ.≮; [P1 V6]; [P1 V6] +B; 🂴Ⴋ.<\u0338; [P1 V6]; [P1 V6] +B; 🂴ⴋ.<\u0338; [P1 V6]; [P1 V6] +B; 🂴ⴋ.≮; [P1 V6]; [P1 V6] +B; xn--2kj7565l.xn--gdh; [V6]; [V6] +B; xn--jnd1986v.xn--gdh; [V6]; [V6] +T; 璼𝨭。\u200C󠇟; [C1]; xn--gky8837e. # 璼𝨭. +N; 璼𝨭。\u200C󠇟; [C1]; [C1] # 璼𝨭. +T; 璼𝨭。\u200C󠇟; [C1]; xn--gky8837e. # 璼𝨭. +N; 璼𝨭。\u200C󠇟; [C1]; [C1] # 璼𝨭. +B; xn--gky8837e.; 璼𝨭.; xn--gky8837e. +B; 璼𝨭.; ; xn--gky8837e. +B; xn--gky8837e.xn--0ug; [C1]; [C1] # 璼𝨭. +B; \u06698ñ‚½ï½¡-5🞥; [B1 P1 V3 V6]; [B1 P1 V3 V6] # Ù©8.-5🞥 +B; \u06698ñ‚½ã€‚-5🞥; [B1 P1 V3 V6]; [B1 P1 V3 V6] # Ù©8.-5🞥 +B; xn--8-qqc97891f.xn---5-rp92a; [B1 V3 V6]; [B1 V3 V6] # Ù©8.-5🞥 +T; \u200C.\u200C; [C1]; [A4_2] # . +N; \u200C.\u200C; [C1]; [C1] # . +B; xn--0ug.xn--0ug; [C1]; [C1] # . +T; \u200D튛.\u0716; [B1 C2]; xn--157b.xn--gnb # 튛.ܖ +N; \u200D튛.\u0716; [B1 C2]; [B1 C2] # 튛.ܖ +T; \u200D튛.\u0716; [B1 C2]; xn--157b.xn--gnb # 튛.ܖ +N; \u200D튛.\u0716; [B1 C2]; [B1 C2] # 튛.ܖ +B; xn--157b.xn--gnb; 튛.\u0716; xn--157b.xn--gnb # 튛.ܖ +B; 튛.\u0716; ; xn--157b.xn--gnb # 튛.ܖ +B; 튛.\u0716; 튛.\u0716; xn--157b.xn--gnb # 튛.ܖ +B; xn--1ug4441e.xn--gnb; [B1 C2]; [B1 C2] # 튛.ܖ +B; ᡋ𐹰𞽳.\u0779ⴞ; [B2 B3 B5 B6 P1 V6]; [B2 B3 B5 B6 P1 V6] # ᡋ𐹰.ݹⴞ +B; ᡋ𐹰𞽳.\u0779Ⴞ; [B2 B3 B5 B6 P1 V6]; [B2 B3 B5 B6 P1 V6] # ᡋ𐹰.ݹႾ +B; xn--b8e0417jocvf.xn--9pb068b; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # ᡋ𐹰.ݹႾ +B; xn--b8e0417jocvf.xn--9pb883q; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # ᡋ𐹰.ݹⴞ +B; 𐷃\u0662𝅻𝟧.𐹮𐹬Ⴇ; [B1 B4 P1 V6]; [B1 B4 P1 V6] # ٢𝅻5.𐹮𐹬Ⴇ +B; 𐷃\u0662𝅻5.𐹮𐹬Ⴇ; [B1 B4 P1 V6]; [B1 B4 P1 V6] # ٢𝅻5.𐹮𐹬Ⴇ +B; 𐷃\u0662𝅻5.𐹮𐹬ⴇ; [B1 B4 P1 V6]; [B1 B4 P1 V6] # ٢𝅻5.𐹮𐹬ⴇ +B; xn--5-cqc8833rhv7f.xn--ykjz523efa; [B1 B4 V6]; [B1 B4 V6] # ٢𝅻5.𐹮𐹬ⴇ +B; xn--5-cqc8833rhv7f.xn--fnd3401kfa; [B1 B4 V6]; [B1 B4 V6] # ٢𝅻5.𐹮𐹬Ⴇ +B; 𐷃\u0662𝅻𝟧.𐹮𐹬ⴇ; [B1 B4 P1 V6]; [B1 B4 P1 V6] # ٢𝅻5.𐹮𐹬ⴇ +B; Ⴗ.\u05C2𑄴\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # Ⴗ.𑄴ׂꦷ +B; Ⴗ.𑄴\u05C2\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # Ⴗ.𑄴ׂꦷ +B; Ⴗ.𑄴\u05C2\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # Ⴗ.𑄴ׂꦷ +B; ⴗ.𑄴\u05C2\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # ⴗ.𑄴ׂꦷ +B; xn--flj.xn--qdb0605f14ycrms3c; [V5 V6]; [V5 V6] # ⴗ.𑄴ׂꦷ +B; xn--vnd.xn--qdb0605f14ycrms3c; [V5 V6]; [V5 V6] # Ⴗ.𑄴ׂꦷ +B; ⴗ.𑄴\u05C2\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # ⴗ.𑄴ׂꦷ +B; ⴗ.\u05C2𑄴\uA9B7ñ˜ƒ¨; [P1 V5 V6]; [P1 V5 V6] # ⴗ.𑄴ׂꦷ +B; 𝟾𾤘.ò‡•›\u066C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 8.Ù¬ +B; 8𾤘.ò‡•›\u066C; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # 8.Ù¬ +B; xn--8-kh23b.xn--lib78461i; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 8.Ù¬ +B; ⒈酫︒。\u08D6; [P1 V5 V6]; [P1 V5 V6] # ⒈酫︒.ࣖ +B; 1.酫。。\u08D6; [V5 A4_2]; [V5 A4_2] # 1.酫..ࣖ +B; 1.xn--8j4a..xn--8zb; [V5 A4_2]; [V5 A4_2] # 1.酫..ࣖ +B; xn--tsh4490bfe8c.xn--8zb; [V5 V6]; [V5 V6] # ⒈酫︒.ࣖ +T; \u2DE3\u200C≮\u1A6B.\u200C\u0E3A; [C1 P1 V5 V6]; [P1 V5 V6] # ⷣ≮ᩫ.ฺ +N; \u2DE3\u200C≮\u1A6B.\u200C\u0E3A; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⷣ≮ᩫ.ฺ +T; \u2DE3\u200C<\u0338\u1A6B.\u200C\u0E3A; [C1 P1 V5 V6]; [P1 V5 V6] # ⷣ≮ᩫ.ฺ +N; \u2DE3\u200C<\u0338\u1A6B.\u200C\u0E3A; [C1 P1 V5 V6]; [C1 P1 V5 V6] # ⷣ≮ᩫ.ฺ +B; xn--uof548an0j.xn--o4c; [V5 V6]; [V5 V6] # ⷣ≮ᩫ.ฺ +B; xn--uof63xk4bf3s.xn--o4c732g; [C1 V5 V6]; [C1 V5 V6] # ⷣ≮ᩫ.ฺ +T; 𞪂。ႷႽ¹\u200D; [B6 C2 P1 V6]; [P1 V6] # .ႷႽ1 +N; 𞪂。ႷႽ¹\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .ႷႽ1 +T; 𞪂。ႷႽ1\u200D; [B6 C2 P1 V6]; [P1 V6] # .ႷႽ1 +N; 𞪂。ႷႽ1\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .ႷႽ1 +T; 𞪂。ⴗⴝ1\u200D; [B6 C2 P1 V6]; [P1 V6] # .ⴗⴝ1 +N; 𞪂。ⴗⴝ1\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .ⴗⴝ1 +T; 𞪂。Ⴗⴝ1\u200D; [B6 C2 P1 V6]; [P1 V6] # .Ⴗⴝ1 +N; 𞪂。Ⴗⴝ1\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .Ⴗⴝ1 +B; xn--co6h.xn--1-h1g429s; [V6]; [V6] +B; xn--co6h.xn--1-h1g398iewm; [B6 C2 V6]; [B6 C2 V6] # .Ⴗⴝ1 +B; xn--co6h.xn--1-kwssa; [V6]; [V6] +B; xn--co6h.xn--1-ugn710dya; [B6 C2 V6]; [B6 C2 V6] # .ⴗⴝ1 +B; xn--co6h.xn--1-h1gs; [V6]; [V6] +B; xn--co6h.xn--1-h1gs597m; [B6 C2 V6]; [B6 C2 V6] # .ႷႽ1 +T; 𞪂。ⴗⴝ¹\u200D; [B6 C2 P1 V6]; [P1 V6] # .ⴗⴝ1 +N; 𞪂。ⴗⴝ¹\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .ⴗⴝ1 +T; 𞪂。Ⴗⴝ¹\u200D; [B6 C2 P1 V6]; [P1 V6] # .Ⴗⴝ1 +N; 𞪂。Ⴗⴝ¹\u200D; [B6 C2 P1 V6]; [B6 C2 P1 V6] # .Ⴗⴝ1 +B; 𑄴𑄳2.𞳿󠀳-; [B1 B3 P1 V3 V5 V6]; [B1 B3 P1 V3 V5 V6] +B; xn--2-h87ic.xn----s39r33498d; [B1 B3 V3 V5 V6]; [B1 B3 V3 V5 V6] +B; 󠕲󟶶\u0665。ñ€ð‘„³ðž¤ƒ\u0710; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # Ù¥.𑄳𞤥ܐ +B; 󠕲󟶶\u0665。ñ€ð‘„³ðž¤ƒ\u0710; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # Ù¥.𑄳𞤥ܐ +B; 󠕲󟶶\u0665。ñ€ð‘„³ðž¤¥\u0710; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # Ù¥.𑄳𞤥ܐ +B; xn--eib57614py3ea.xn--9mb5737kqnpfzkwr; [B1 B5 B6 V6]; [B1 B5 B6 V6] # Ù¥.𑄳𞤥ܐ +B; 󠕲󟶶\u0665。ñ€ð‘„³ðž¤¥\u0710; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # Ù¥.𑄳𞤥ܐ +T; \u0720ò² ½ð¹¢\u17BB。ςᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.ςᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。ςᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.ςᢈ🝭 +T; \u0720ò² ½ð¹¢\u17BB。ςᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.ςᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。ςᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.ςᢈ🝭 +T; \u0720ò² ½ð¹¢\u17BB。Σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。Σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +T; \u0720ò² ½ð¹¢\u17BB。σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +B; xn--qnb616fis0qzt36f.xn--4xa847hli46a; [B2 B6 V6]; [B2 B6 V6] # ܠ𐹢ុ.σᢈ🝭 +B; xn--qnb616fis0qzt36f.xn--4xa847h6ofgl44c; [B2 B6 C1 V6]; [B2 B6 C1 V6] # ܠ𐹢ុ.σᢈ🝭 +B; xn--qnb616fis0qzt36f.xn--3xa057h6ofgl44c; [B2 B6 C1 V6]; [B2 B6 C1 V6] # ܠ𐹢ុ.ςᢈ🝭 +T; \u0720ò² ½ð¹¢\u17BB。Σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。Σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +T; \u0720ò² ½ð¹¢\u17BB。σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +N; \u0720ò² ½ð¹¢\u17BB。σᢈ🝭\u200C; [B2 B6 C1 P1 V6]; [B2 B6 C1 P1 V6] # ܠ𐹢ុ.σᢈ🝭 +T; \u200D--≮。𐹧; [B1 C2 P1 V6]; [B1 P1 V3 V6] # --≮.𐹧 +N; \u200D--≮。𐹧; [B1 C2 P1 V6]; [B1 C2 P1 V6] # --≮.𐹧 +T; \u200D--<\u0338。𐹧; [B1 C2 P1 V6]; [B1 P1 V3 V6] # --≮.𐹧 +N; \u200D--<\u0338。𐹧; [B1 C2 P1 V6]; [B1 C2 P1 V6] # --≮.𐹧 +B; xn-----ujv.xn--fo0d; [B1 V3 V6]; [B1 V3 V6] +B; xn-----l1tz1k.xn--fo0d; [B1 C2 V6]; [B1 C2 V6] # --≮.𐹧 +B; \uA806。𻚏\u0FB0⒕; [P1 V5 V6]; [P1 V5 V6] # ꠆.ྰ⒕ +B; \uA806。𻚏\u0FB014.; [P1 V5 V6]; [P1 V5 V6] # ꠆.ྰ14. +B; xn--l98a.xn--14-jsj57880f.; [V5 V6]; [V5 V6] # ꠆.ྰ14. +B; xn--l98a.xn--dgd218hhp28d; [V5 V6]; [V5 V6] # ꠆.ྰ⒕ +B; ò®‰‚\u06BC.𑆺\u0669; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # Ú¼.𑆺٩ +B; ò®‰‚\u06BC.𑆺\u0669; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # Ú¼.𑆺٩ +B; xn--vkb92243l.xn--iib9797k; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # Ú¼.𑆺٩ +B; 󠁎\u06D0-。𞤴; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ې-.𞤴 +B; 󠁎\u06D0-。𞤒; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ې-.𞤴 +B; xn----mwc72685y.xn--se6h; [B1 V3 V6]; [B1 V3 V6] # ې-.𞤴 +T; 𝟠4󠇗𝈻.\u200D𐋵⛧\u200D; [C2]; xn--84-s850a.xn--59h6326e # 84𝈻.𐋵⛧ +N; 𝟠4󠇗𝈻.\u200D𐋵⛧\u200D; [C2]; [C2] # 84𝈻.𐋵⛧ +T; 84󠇗𝈻.\u200D𐋵⛧\u200D; [C2]; xn--84-s850a.xn--59h6326e # 84𝈻.𐋵⛧ +N; 84󠇗𝈻.\u200D𐋵⛧\u200D; [C2]; [C2] # 84𝈻.𐋵⛧ +B; xn--84-s850a.xn--59h6326e; 84𝈻.𐋵⛧; xn--84-s850a.xn--59h6326e; NV8 +B; 84𝈻.𐋵⛧; ; xn--84-s850a.xn--59h6326e; NV8 +B; xn--84-s850a.xn--1uga573cfq1w; [C2]; [C2] # 84𝈻.𐋵⛧ +B; -\u0601。ᡪ; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.ᡪ +B; -\u0601。ᡪ; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.ᡪ +B; xn----tkc.xn--68e; [B1 V3 V6]; [B1 V3 V6] # -.ᡪ +T; ≮𝟕.謖ß≯; [P1 V6]; [P1 V6] +N; ≮𝟕.謖ß≯; [P1 V6]; [P1 V6] +T; <\u0338𝟕.謖ß>\u0338; [P1 V6]; [P1 V6] +N; <\u0338𝟕.謖ß>\u0338; [P1 V6]; [P1 V6] +T; ≮7.謖ß≯; [P1 V6]; [P1 V6] +N; ≮7.謖ß≯; [P1 V6]; [P1 V6] +T; <\u03387.謖ß>\u0338; [P1 V6]; [P1 V6] +N; <\u03387.謖ß>\u0338; [P1 V6]; [P1 V6] +B; <\u03387.謖SS>\u0338; [P1 V6]; [P1 V6] +B; ≮7.謖SS≯; [P1 V6]; [P1 V6] +B; ≮7.謖ss≯; [P1 V6]; [P1 V6] +B; <\u03387.謖ss>\u0338; [P1 V6]; [P1 V6] +B; <\u03387.謖Ss>\u0338; [P1 V6]; [P1 V6] +B; ≮7.謖Ss≯; [P1 V6]; [P1 V6] +B; xn--7-mgo.xn--ss-xjvv174c; [V6]; [V6] +B; xn--7-mgo.xn--zca892oly5e; [V6]; [V6] +B; <\u0338𝟕.謖SS>\u0338; [P1 V6]; [P1 V6] +B; ≮𝟕.謖SS≯; [P1 V6]; [P1 V6] +B; ≮𝟕.謖ss≯; [P1 V6]; [P1 V6] +B; <\u0338𝟕.謖ss>\u0338; [P1 V6]; [P1 V6] +B; <\u0338𝟕.謖Ss>\u0338; [P1 V6]; [P1 V6] +B; ≮𝟕.謖Ss≯; [P1 V6]; [P1 V6] +B; 朶Ⴉ𞪡.𝨽\u0825📻-; [B1 B5 B6 P1 V3 V5 V6]; [B1 B5 B6 P1 V3 V5 V6] # 朶Ⴉ.𝨽ࠥ📻- +B; 朶ⴉ𞪡.𝨽\u0825📻-; [B1 B5 B6 P1 V3 V5 V6]; [B1 B5 B6 P1 V3 V5 V6] # 朶ⴉ.𝨽ࠥ📻- +B; xn--0kjz47pd57t.xn----3gd37096apmwa; [B1 B5 B6 V3 V5 V6]; [B1 B5 B6 V3 V5 V6] # 朶ⴉ.𝨽ࠥ📻- +B; xn--hnd7245bd56p.xn----3gd37096apmwa; [B1 B5 B6 V3 V5 V6]; [B1 B5 B6 V3 V5 V6] # 朶Ⴉ.𝨽ࠥ📻- +T; 𐤎。󑿰\u200C≮\u200D; [B6 C1 C2 P1 V6]; [B6 P1 V6] # 𐤎.≮ +N; 𐤎。󑿰\u200C≮\u200D; [B6 C1 C2 P1 V6]; [B6 C1 C2 P1 V6] # 𐤎.≮ +T; 𐤎。󑿰\u200C<\u0338\u200D; [B6 C1 C2 P1 V6]; [B6 P1 V6] # 𐤎.≮ +N; 𐤎。󑿰\u200C<\u0338\u200D; [B6 C1 C2 P1 V6]; [B6 C1 C2 P1 V6] # 𐤎.≮ +B; xn--bk9c.xn--gdhx6802k; [B6 V6]; [B6 V6] +B; xn--bk9c.xn--0ugc04p2u638c; [B6 C1 C2 V6]; [B6 C1 C2 V6] # 𐤎.≮ +T; ñ­œŽâ’ˆï½¡\u200C𝟤; [C1 P1 V6]; [P1 V6] # ⒈.2 +N; ñ­œŽâ’ˆï½¡\u200C𝟤; [C1 P1 V6]; [C1 P1 V6] # ⒈.2 +T; ñ­œŽ1.。\u200C2; [C1 P1 V6 A4_2]; [P1 V6 A4_2] # 1..2 +N; ñ­œŽ1.。\u200C2; [C1 P1 V6 A4_2]; [C1 P1 V6 A4_2] # 1..2 +B; xn--1-ex54e..2; [V6 A4_2]; [V6 A4_2] +B; xn--1-ex54e..xn--2-rgn; [C1 V6 A4_2]; [C1 V6 A4_2] # 1..2 +B; xn--tsh94183d.2; [V6]; [V6] +B; xn--tsh94183d.xn--2-rgn; [C1 V6]; [C1 V6] # ⒈.2 +T; 󠟊𐹤\u200D.𐹳󙄵𐹶; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹤.𐹳𐹶 +N; 󠟊𐹤\u200D.𐹳󙄵𐹶; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹤.𐹳𐹶 +T; 󠟊𐹤\u200D.𐹳󙄵𐹶; [B1 C2 P1 V6]; [B1 P1 V6] # 𐹤.𐹳𐹶 +N; 󠟊𐹤\u200D.𐹳󙄵𐹶; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 𐹤.𐹳𐹶 +B; xn--co0d98977c.xn--ro0dga22807v; [B1 V6]; [B1 V6] +B; xn--1ugy994g7k93g.xn--ro0dga22807v; [B1 C2 V6]; [B1 C2 V6] # 𐹤.𐹳𐹶 +B; 𞤴𐹻𑓂𐭝.\u094D\uFE07ô‰›¯; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴𐹻𑓂𐭝.् +B; 𞤴𐹻𑓂𐭝.\u094D\uFE07ô‰›¯; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴𐹻𑓂𐭝.् +B; 𞤒𐹻𑓂𐭝.\u094D\uFE07ô‰›¯; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴𐹻𑓂𐭝.् +B; xn--609c96c09grp2w.xn--n3b28708s; [B1 V5 V6]; [B1 V5 V6] # 𞤴𐹻𑓂𐭝.् +B; 𞤒𐹻𑓂𐭝.\u094D\uFE07ô‰›¯; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𞤴𐹻𑓂𐭝.् +B; \u0668。𐹠𐹽ñ—®¶; [B1 P1 V6]; [B1 P1 V6] # Ù¨.𐹠𐹽 +B; \u0668。𐹠𐹽ñ—®¶; [B1 P1 V6]; [B1 P1 V6] # Ù¨.𐹠𐹽 +B; xn--hib.xn--7n0d2bu9196b; [B1 V6]; [B1 V6] # Ù¨.𐹠𐹽 +B; \u1160ñ€œ.8ò¶¾µ\u069C; [B1 P1 V6]; [B1 P1 V6] # .8ڜ +B; xn--psd85033d.xn--8-otc61545t; [B1 V6]; [B1 V6] # .8ڜ +T; \u200D\u200C󠆪。ß𑓃; [C1 C2]; [A4_2] # .ß𑓃 +N; \u200D\u200C󠆪。ß𑓃; [C1 C2]; [C1 C2] # .ß𑓃 +T; \u200D\u200C󠆪。ß𑓃; [C1 C2]; [A4_2] # .ß𑓃 +N; \u200D\u200C󠆪。ß𑓃; [C1 C2]; [C1 C2] # .ß𑓃 +T; \u200D\u200C󠆪。SS𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。SS𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +T; \u200D\u200C󠆪。ss𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。ss𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +T; \u200D\u200C󠆪。Ss𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。Ss𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +B; .xn--ss-bh7o; [A4_2]; [A4_2] +B; xn--0ugb.xn--ss-bh7o; [C1 C2]; [C1 C2] # .ss𑓃 +B; xn--0ugb.xn--zca0732l; [C1 C2]; [C1 C2] # .ß𑓃 +T; \u200D\u200C󠆪。SS𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。SS𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +T; \u200D\u200C󠆪。ss𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。ss𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +T; \u200D\u200C󠆪。Ss𑓃; [C1 C2]; [A4_2] # .ss𑓃 +N; \u200D\u200C󠆪。Ss𑓃; [C1 C2]; [C1 C2] # .ss𑓃 +B; xn--ss-bh7o; ss𑓃; xn--ss-bh7o +B; ss𑓃; ; xn--ss-bh7o +B; SS𑓃; ss𑓃; xn--ss-bh7o +B; Ss𑓃; ss𑓃; xn--ss-bh7o +T; ︒\u200Cヶ䒩.ꡪ; [C1 P1 V6]; [P1 V6] # ︒ヶ䒩.ꡪ +N; ︒\u200Cヶ䒩.ꡪ; [C1 P1 V6]; [C1 P1 V6] # ︒ヶ䒩.ꡪ +T; 。\u200Cヶ䒩.ꡪ; [C1 A4_2]; [A4_2] # .ヶ䒩.ꡪ +N; 。\u200Cヶ䒩.ꡪ; [C1 A4_2]; [C1 A4_2] # .ヶ䒩.ꡪ +B; .xn--qekw60d.xn--gd9a; [A4_2]; [A4_2] +B; .xn--0ug287dj0o.xn--gd9a; [C1 A4_2]; [C1 A4_2] # .ヶ䒩.ꡪ +B; xn--qekw60dns9k.xn--gd9a; [V6]; [V6] +B; xn--0ug287dj0or48o.xn--gd9a; [C1 V6]; [C1 V6] # ︒ヶ䒩.ꡪ +B; xn--qekw60d.xn--gd9a; ヶ䒩.ꡪ; xn--qekw60d.xn--gd9a +B; ヶ䒩.ꡪ; ; xn--qekw60d.xn--gd9a +T; \u200C⒈𤮍.󢓋\u1A60; [C1 P1 V6]; [P1 V6] # ⒈𤮍.á©  +N; \u200C⒈𤮍.󢓋\u1A60; [C1 P1 V6]; [C1 P1 V6] # ⒈𤮍.á©  +T; \u200C1.𤮍.󢓋\u1A60; [C1 P1 V6]; [P1 V6] # 1.𤮍.á©  +N; \u200C1.𤮍.󢓋\u1A60; [C1 P1 V6]; [C1 P1 V6] # 1.𤮍.á©  +B; 1.xn--4x6j.xn--jof45148n; [V6]; [V6] # 1.𤮍.á©  +B; xn--1-rgn.xn--4x6j.xn--jof45148n; [C1 V6]; [C1 V6] # 1.𤮍.á©  +B; xn--tshw462r.xn--jof45148n; [V6]; [V6] # ⒈𤮍.á©  +B; xn--0ug88o7471d.xn--jof45148n; [C1 V6]; [C1 V6] # ⒈𤮍.á©  +T; ⒈\u200C𐫓󠀺。\u1A60ñ¤°µ\u200D; [B1 C1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ⒈𐫓.á©  +N; ⒈\u200C𐫓󠀺。\u1A60ñ¤°µ\u200D; [B1 C1 C2 P1 V5 V6]; [B1 C1 C2 P1 V5 V6] # ⒈𐫓.á©  +T; 1.\u200C𐫓󠀺。\u1A60ñ¤°µ\u200D; [B1 C1 C2 P1 V5 V6]; [B1 B3 P1 V5 V6] # 1.𐫓.á©  +N; 1.\u200C𐫓󠀺。\u1A60ñ¤°µ\u200D; [B1 C1 C2 P1 V5 V6]; [B1 C1 C2 P1 V5 V6] # 1.𐫓.á©  +B; 1.xn--8w9c40377c.xn--jofz5294e; [B1 B3 V5 V6]; [B1 B3 V5 V6] # 1.𐫓.á©  +B; 1.xn--0ug8853gk263g.xn--jof95xex98m; [B1 C1 C2 V5 V6]; [B1 C1 C2 V5 V6] # 1.𐫓.á©  +B; xn--tsh4435fk263g.xn--jofz5294e; [B1 V5 V6]; [B1 V5 V6] # ⒈𐫓.á©  +B; xn--0ug78ol75wzcx4i.xn--jof95xex98m; [B1 C1 C2 V5 V6]; [B1 C1 C2 V5 V6] # ⒈𐫓.á©  +B; 𝅵。𝟫𞀈䬺⒈; [P1 V6]; [P1 V6] +B; 𝅵。9𞀈䬺1.; [P1 V6]; [P1 V6] +B; xn--3f1h.xn--91-030c1650n.; [V6]; [V6] +B; xn--3f1h.xn--9-ecp936non25a; [V6]; [V6] +B; ò¡¼ºâ‰¯ã€‚盚\u0635; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ≯.盚ص +B; ò¡¼º>\u0338。盚\u0635; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ≯.盚ص +B; xn--hdh30181h.xn--0gb7878c; [B5 B6 V6]; [B5 B6 V6] # ≯.盚ص +B; -ñ¿°­\u05B4。-󠁊𐢸≯; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -Ö´.-≯ +B; -ñ¿°­\u05B4。-󠁊𐢸>\u0338; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -Ö´.-≯ +B; xn----fgc06667m.xn----pgoy615he5y4i; [B1 V3 V6]; [B1 V3 V6] # -Ö´.-≯ +T; 󿭓\u1B44\u200C\u0A4D.𐭛ñ³‹”; [B2 B3 B6 P1 V6]; [B2 B3 P1 V6] # ᭄੍.𐭛 +N; 󿭓\u1B44\u200C\u0A4D.𐭛ñ³‹”; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ᭄੍.𐭛 +T; 󿭓\u1B44\u200C\u0A4D.𐭛ñ³‹”; [B2 B3 B6 P1 V6]; [B2 B3 P1 V6] # ᭄੍.𐭛 +N; 󿭓\u1B44\u200C\u0A4D.𐭛ñ³‹”; [B2 B3 B6 P1 V6]; [B2 B3 B6 P1 V6] # ᭄੍.𐭛 +B; xn--ybc997fb5881a.xn--409c6100y; [B2 B3 V6]; [B2 B3 V6] # ᭄੍.𐭛 +B; xn--ybc997f6rd2n772c.xn--409c6100y; [B2 B3 B6 V6]; [B2 B3 B6 V6] # ᭄੍.𐭛 +T; ⾇.\u067D𞤴\u06BB\u200D; [B3 C2]; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +N; ⾇.\u067D𞤴\u06BB\u200D; [B3 C2]; [B3 C2] # 舛.ٽ𞤴ڻ +T; 舛.\u067D𞤴\u06BB\u200D; [B3 C2]; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +N; 舛.\u067D𞤴\u06BB\u200D; [B3 C2]; [B3 C2] # 舛.ٽ𞤴ڻ +T; 舛.\u067D𞤒\u06BB\u200D; [B3 C2]; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +N; 舛.\u067D𞤒\u06BB\u200D; [B3 C2]; [B3 C2] # 舛.ٽ𞤴ڻ +B; xn--8c1a.xn--2ib8jn539l; 舛.\u067D𞤴\u06BB; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +B; 舛.\u067D𞤴\u06BB; ; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +B; 舛.\u067D𞤒\u06BB; 舛.\u067D𞤴\u06BB; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +B; xn--8c1a.xn--2ib8jv19e6413b; [B3 C2]; [B3 C2] # 舛.ٽ𞤴ڻ +T; ⾇.\u067D𞤒\u06BB\u200D; [B3 C2]; xn--8c1a.xn--2ib8jn539l # 舛.ٽ𞤴ڻ +N; ⾇.\u067D𞤒\u06BB\u200D; [B3 C2]; [B3 C2] # 舛.ٽ𞤴ڻ +B; 4ò­†¥ã€‚\u0767≯; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 4.ݧ≯ +B; 4ò­†¥ã€‚\u0767>\u0338; [B1 B3 P1 V6]; [B1 B3 P1 V6] # 4.ݧ≯ +B; xn--4-xn17i.xn--rpb459k; [B1 B3 V6]; [B1 B3 V6] # 4.ݧ≯ +B; 𲔏𞫨ñº¿‚硲.\u06AD; [B5 P1 V6]; [B5 P1 V6] # 硲.Ú­ +B; 𲔏𞫨ñº¿‚硲.\u06AD; [B5 P1 V6]; [B5 P1 V6] # 硲.Ú­ +B; xn--lcz1610fn78gk609a.xn--gkb; [B5 V6]; [B5 V6] # 硲.Ú­ +T; \u200C.\uFE08\u0666Ⴆ℮; [B1 C1 P1 V6]; [B1 P1 V6 A4_2] # .٦Ⴆ℮ +N; \u200C.\uFE08\u0666Ⴆ℮; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .٦Ⴆ℮ +T; \u200C.\uFE08\u0666ⴆ℮; [B1 C1]; [B1 A4_2] # .٦ⴆ℮ +N; \u200C.\uFE08\u0666ⴆ℮; [B1 C1]; [B1 C1] # .٦ⴆ℮ +B; .xn--fib628k4li; [B1 A4_2]; [B1 A4_2] # .٦ⴆ℮ +B; xn--0ug.xn--fib628k4li; [B1 C1]; [B1 C1] # .٦ⴆ℮ +B; .xn--fib263c0yn; [B1 V6 A4_2]; [B1 V6 A4_2] # .٦Ⴆ℮ +B; xn--0ug.xn--fib263c0yn; [B1 C1 V6]; [B1 C1 V6] # .٦Ⴆ℮ +T; \u06A3.\u0D4D\u200DϞ; [B1 V5]; [B1 V5] # Ú£.്ϟ +N; \u06A3.\u0D4D\u200DϞ; [B1 V5]; [B1 V5] # Ú£.്ϟ +T; \u06A3.\u0D4D\u200DϞ; [B1 V5]; [B1 V5] # Ú£.്ϟ +N; \u06A3.\u0D4D\u200DϞ; [B1 V5]; [B1 V5] # Ú£.്ϟ +T; \u06A3.\u0D4D\u200Dϟ; [B1 V5]; [B1 V5] # Ú£.്ϟ +N; \u06A3.\u0D4D\u200Dϟ; [B1 V5]; [B1 V5] # Ú£.്ϟ +B; xn--5jb.xn--xya149b; [B1 V5]; [B1 V5] # Ú£.്ϟ +B; xn--5jb.xn--xya149bpvp; [B1 V5]; [B1 V5] # Ú£.്ϟ +T; \u06A3.\u0D4D\u200Dϟ; [B1 V5]; [B1 V5] # Ú£.്ϟ +N; \u06A3.\u0D4D\u200Dϟ; [B1 V5]; [B1 V5] # Ú£.്ϟ +T; \u200C𞸇𑘿。\u0623𐮂-腍; [B1 B2 B3 C1]; [B2 B3] # ح𑘿.أ𐮂-腍 +N; \u200C𞸇𑘿。\u0623𐮂-腍; [B1 B2 B3 C1]; [B1 B2 B3 C1] # ح𑘿.أ𐮂-腍 +T; \u200C𞸇𑘿。\u0627\u0654𐮂-腍; [B1 B2 B3 C1]; [B2 B3] # ح𑘿.أ𐮂-腍 +N; \u200C𞸇𑘿。\u0627\u0654𐮂-腍; [B1 B2 B3 C1]; [B1 B2 B3 C1] # ح𑘿.أ𐮂-腍 +T; \u200C\u062D𑘿。\u0623𐮂-腍; [B1 B2 B3 C1]; [B2 B3] # ح𑘿.أ𐮂-腍 +N; \u200C\u062D𑘿。\u0623𐮂-腍; [B1 B2 B3 C1]; [B1 B2 B3 C1] # ح𑘿.أ𐮂-腍 +T; \u200C\u062D𑘿。\u0627\u0654𐮂-腍; [B1 B2 B3 C1]; [B2 B3] # ح𑘿.أ𐮂-腍 +N; \u200C\u062D𑘿。\u0627\u0654𐮂-腍; [B1 B2 B3 C1]; [B1 B2 B3 C1] # ح𑘿.أ𐮂-腍 +B; xn--sgb4140l.xn----qmc5075grs9e; [B2 B3]; [B2 B3] # ح𑘿.أ𐮂-腍 +B; xn--sgb953kmi8o.xn----qmc5075grs9e; [B1 B2 B3 C1]; [B1 B2 B3 C1] # ح𑘿.أ𐮂-腍 +B; -ò­·™\u066B纛。𝟛ñ­¤‡ðŸ„…; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -٫纛.3🄅 +B; -ò­·™\u066B纛。3ñ­¤‡4,; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -٫纛.34, +B; xn----vqc8143g0tt4i.xn--34,-8787l; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -٫纛.34, +B; xn----vqc8143g0tt4i.xn--3-os1sn476y; [B1 V3 V6]; [B1 V3 V6] # -٫纛.3🄅 +B; 🔔.Ⴂ\u07CC\u0BCD𐋮; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 🔔.Ⴂߌ்𐋮 +B; 🔔.Ⴂ\u07CC\u0BCD𐋮; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 🔔.Ⴂߌ்𐋮 +B; 🔔.ⴂ\u07CC\u0BCD𐋮; [B1 B5]; [B1 B5] # 🔔.ⴂߌ்𐋮 +B; xn--nv8h.xn--nsb46rvz1b222p; [B1 B5]; [B1 B5] # 🔔.ⴂߌ்𐋮 +B; xn--nv8h.xn--nsb46r83e8112a; [B1 B5 V6]; [B1 B5 V6] # 🔔.Ⴂߌ்𐋮 +B; 🔔.ⴂ\u07CC\u0BCD𐋮; [B1 B5]; [B1 B5] # 🔔.ⴂߌ்𐋮 +B; 軥\u06B3.-𖬵; [B1 B5 B6 V3]; [B1 B5 B6 V3] # 軥ڳ.-𖬵 +B; xn--mkb5480e.xn----6u5m; [B1 B5 B6 V3]; [B1 B5 B6 V3] # 軥ڳ.-𖬵 +B; 𐹤\u07CA\u06B6.𐨂-; [B1 V3 V5]; [B1 V3 V5] # 𐹤ߊڶ.𐨂- +B; xn--pkb56cn614d.xn----974i; [B1 V3 V5]; [B1 V3 V5] # 𐹤ߊڶ.𐨂- +B; -󠅱0。\u17CF\u1DFD톇십; [V3 V5]; [V3 V5] # -0.៏᷽톇십 +B; -󠅱0。\u17CF\u1DFD톇십; [V3 V5]; [V3 V5] # -0.៏᷽톇십 +B; -󠅱0。\u17CF\u1DFD톇십; [V3 V5]; [V3 V5] # -0.៏᷽톇십 +B; -󠅱0。\u17CF\u1DFD톇십; [V3 V5]; [V3 V5] # -0.៏᷽톇십 +B; -0.xn--r4e872ah77nghm; [V3 V5]; [V3 V5] # -0.៏᷽톇십 +B; ꡰ︒--。\u17CC靈𐹢ñ˜³®; [B1 B6 P1 V2 V3 V5 V6]; [B1 B6 P1 V2 V3 V5 V6] # ꡰ︒--.៌靈𐹢 +B; ꡰ。--。\u17CC靈𐹢ñ˜³®; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ê¡°.--.៌靈𐹢 +B; xn--md9a.--.xn--o4e6836dpxudz0v1c; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ê¡°.--.៌靈𐹢 +B; xn-----bk9hu24z.xn--o4e6836dpxudz0v1c; [B1 B6 V2 V3 V5 V6]; [B1 B6 V2 V3 V5 V6] # ꡰ︒--.៌靈𐹢 +B; \u115FႿႵრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # ႿႵრ.୍ +B; \u115FႿႵრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # ႿႵრ.୍ +B; \u115Fⴟⴕრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # ⴟⴕრ.୍ +B; \u115FႿⴕრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # Ⴟⴕრ.୍ +B; xn--3nd0etsm92g.xn--9ic; [V5 V6]; [V5 V6] # Ⴟⴕრ.୍ +B; xn--1od7wz74eeb.xn--9ic; [V5 V6]; [V5 V6] # ⴟⴕრ.୍ +B; xn--tndt4hvw.xn--9ic; [V5 V6]; [V5 V6] # ႿႵრ.୍ +B; \u115Fⴟⴕრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # ⴟⴕრ.୍ +B; \u115FႿⴕრ。\u0B4D; [P1 V5 V6]; [P1 V5 V6] # Ⴟⴕრ.୍ +B; 🄃𐹠.\u0664󠅇; [B1 P1 V6]; [B1 P1 V6] # 🄃𐹠.Ù¤ +B; 2,𐹠.\u0664󠅇; [B1 P1 V6]; [B1 P1 V6] # 2,𐹠.Ù¤ +B; xn--2,-5g3o.xn--dib; [B1 P1 V6]; [B1 P1 V6] # 2,𐹠.Ù¤ +B; xn--7n0d1189a.xn--dib; [B1 V6]; [B1 V6] # 🄃𐹠.Ù¤ +T; ò»²¼\u200C\uFC5B.\u07D2\u0848\u1BF3; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # ذٰ.ߒࡈ᯳ +N; ò»²¼\u200C\uFC5B.\u07D2\u0848\u1BF3; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # ذٰ.ߒࡈ᯳ +T; ò»²¼\u200C\u0630\u0670.\u07D2\u0848\u1BF3; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 P1 V6] # ذٰ.ߒࡈ᯳ +N; ò»²¼\u200C\u0630\u0670.\u07D2\u0848\u1BF3; [B2 B3 B5 B6 C1 P1 V6]; [B2 B3 B5 B6 C1 P1 V6] # ذٰ.ߒࡈ᯳ +B; xn--vgb2kp1223g.xn--tsb0vz43c; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # ذٰ.ߒࡈ᯳ +B; xn--vgb2kq00fl213y.xn--tsb0vz43c; [B2 B3 B5 B6 C1 V6]; [B2 B3 B5 B6 C1 V6] # ذٰ.ߒࡈ᯳ +T; \u200D\u200D𞵪\u200C。ᡘ𑲭\u17B5; [B1 C1 C2 P1 V6]; [P1 V6] # .ᡘ𑲭 +N; \u200D\u200D𞵪\u200C。ᡘ𑲭\u17B5; [B1 C1 C2 P1 V6]; [B1 C1 C2 P1 V6] # .ᡘ𑲭 +B; xn--l96h.xn--03e93aq365d; [V6]; [V6] # .ᡘ𑲭 +B; xn--0ugba05538b.xn--03e93aq365d; [B1 C1 C2 V6]; [B1 C1 C2 V6] # .ᡘ𑲭 +B; 𞷻。⚄ñ—‘‡ð‘¿; [B1 P1 V6]; [B1 P1 V6] +B; xn--qe7h.xn--c7h2966f7so4a; [B1 V6]; [B1 V6] +B; \uA8C4≠.𞠨\u0667; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꣄≠.𞠨٧ +B; \uA8C4=\u0338.𞠨\u0667; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꣄≠.𞠨٧ +B; \uA8C4≠.𞠨\u0667; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꣄≠.𞠨٧ +B; \uA8C4=\u0338.𞠨\u0667; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ꣄≠.𞠨٧ +B; xn--1chy504c.xn--gib1777v; [B1 V5 V6]; [B1 V5 V6] # ꣄≠.𞠨٧ +B; 𝟛𝆪\uA8C4。\uA8EA-; [V3 V5]; [V3 V5] # 3꣄𝆪.꣪- +B; 𝟛\uA8C4𝆪。\uA8EA-; [V3 V5]; [V3 V5] # 3꣄𝆪.꣪- +B; 3\uA8C4𝆪。\uA8EA-; [V3 V5]; [V3 V5] # 3꣄𝆪.꣪- +B; xn--3-sl4eu679e.xn----xn4e; [V3 V5]; [V3 V5] # 3꣄𝆪.꣪- +B; \u075F\u1BA2\u103AႧ.4; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # ݟᮢ်Ⴇ.4 +B; \u075F\u1BA2\u103Aⴇ.4; [B1 B2 B3]; [B1 B2 B3] # ݟᮢ်ⴇ.4 +B; xn--jpb846bjzj7pr.4; [B1 B2 B3]; [B1 B2 B3] # ݟᮢ်ⴇ.4 +B; xn--jpb846bmjw88a.4; [B1 B2 B3 V6]; [B1 B2 B3 V6] # ݟᮢ်Ⴇ.4 +B; ᄹ。\u0ECAò ¯¤ó „ž; [P1 V5 V6]; [P1 V5 V6] # ᄹ.໊ +B; ᄹ。\u0ECAò ¯¤ó „ž; [P1 V5 V6]; [P1 V5 V6] # ᄹ.໊ +B; xn--lrd.xn--s8c05302k; [V5 V6]; [V5 V6] # ᄹ.໊ +B; Ⴆò»¢©ï¼Žó †¡\uFE09𞤍; [P1 V6]; [P1 V6] +B; Ⴆò»¢©.󠆡\uFE09𞤍; [P1 V6]; [P1 V6] +B; ⴆò»¢©.󠆡\uFE09𞤯; [P1 V6]; [P1 V6] +B; xn--xkjw3965g.xn--ne6h; [V6]; [V6] +B; xn--end82983m.xn--ne6h; [V6]; [V6] +B; ⴆò»¢©ï¼Žó †¡\uFE09𞤯; [P1 V6]; [P1 V6] +B; ⴆò»¢©.󠆡\uFE09𞤍; [P1 V6]; [P1 V6] +B; ⴆò»¢©ï¼Žó †¡\uFE09𞤍; [P1 V6]; [P1 V6] +T; ß\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ßࠋ︒ٻ.帼f∫∫ +N; ß\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ßࠋ︒ٻ.帼f∫∫ +T; ß\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6] # ßࠋ.Ù».帼f∫∫ +N; ß\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6 C1] # ßࠋ.Ù».帼f∫∫ +T; ß\u080B。\u067B.帼f∫∫\u200C; [B5 B6 C1]; [B5 B6] # ßࠋ.Ù».帼f∫∫ +N; ß\u080B。\u067B.帼f∫∫\u200C; [B5 B6 C1]; [B5 B6 C1] # ßࠋ.Ù».帼f∫∫ +T; SS\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6] # ssࠋ.Ù».帼f∫∫ +N; SS\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6 C1] # ssࠋ.Ù».帼f∫∫ +T; ss\u080B。\u067B.帼f∫∫\u200C; [B5 B6 C1]; [B5 B6] # ssࠋ.Ù».帼f∫∫ +N; ss\u080B。\u067B.帼f∫∫\u200C; [B5 B6 C1]; [B5 B6 C1] # ssࠋ.Ù».帼f∫∫ +T; Ss\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6] # ssࠋ.Ù».帼f∫∫ +N; Ss\u080B。\u067B.帼F∫∫\u200C; [B5 B6 C1]; [B5 B6 C1] # ssࠋ.Ù».帼f∫∫ +B; xn--ss-uze.xn--0ib.xn--f-tcoa9162d; [B5 B6]; [B5 B6] # ssࠋ.Ù».帼f∫∫ +B; xn--ss-uze.xn--0ib.xn--f-sgn48ga6997e; [B5 B6 C1]; [B5 B6 C1] # ssࠋ.Ù».帼f∫∫ +B; xn--zca687a.xn--0ib.xn--f-sgn48ga6997e; [B5 B6 C1]; [B5 B6 C1] # ßࠋ.Ù».帼f∫∫ +T; ß\u080B︒\u067B.帼f∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ßࠋ︒ٻ.帼f∫∫ +N; ß\u080B︒\u067B.帼f∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ßࠋ︒ٻ.帼f∫∫ +T; SS\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +N; SS\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +T; ss\u080B︒\u067B.帼f∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +N; ss\u080B︒\u067B.帼f∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +T; Ss\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +N; Ss\u080B︒\u067B.帼F∬\u200C; [B5 B6 C1 P1 V6]; [B5 B6 C1 P1 V6] # ssࠋ︒ٻ.帼f∫∫ +B; xn--ss-k0d31nu121d.xn--f-tcoa9162d; [B5 B6 V6]; [B5 B6 V6] # ssࠋ︒ٻ.帼f∫∫ +B; xn--ss-k0d31nu121d.xn--f-sgn48ga6997e; [B5 B6 C1 V6]; [B5 B6 C1 V6] # ssࠋ︒ٻ.帼f∫∫ +B; xn--zca68zj8ac956c.xn--f-sgn48ga6997e; [B5 B6 C1 V6]; [B5 B6 C1 V6] # ßࠋ︒ٻ.帼f∫∫ +T; 󘪗。𐹴𞨌\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # .𐹴 +N; 󘪗。𐹴𞨌\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # .𐹴 +T; 󘪗。𐹴𞨌\u200D; [B1 C2 P1 V6]; [B1 P1 V6] # .𐹴 +N; 󘪗。𐹴𞨌\u200D; [B1 C2 P1 V6]; [B1 C2 P1 V6] # .𐹴 +B; xn--8l83e.xn--so0dw168a; [B1 V6]; [B1 V6] +B; xn--8l83e.xn--1ug4105gsxwf; [B1 C2 V6]; [B1 C2 V6] # .𐹴 +B; ñ—›¨.ò…Ÿ¢ðŸ¨\uA8C4; [P1 V6]; [P1 V6] # .6꣄ +B; ñ—›¨.ò…Ÿ¢6\uA8C4; [P1 V6]; [P1 V6] # .6꣄ +B; xn--mi60a.xn--6-sl4es8023c; [V6]; [V6] # .6꣄ +B; \u1AB2\uFD8E。-۹ႱႨ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᪲مخج.-۹ႱႨ +B; \u1AB2\u0645\u062E\u062C。-۹ႱႨ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᪲مخج.-۹ႱႨ +B; \u1AB2\u0645\u062E\u062C。-۹ⴑⴈ; [B1 V3 V5]; [B1 V3 V5] # ᪲مخج.-۹ⴑⴈ +B; \u1AB2\u0645\u062E\u062C。-۹Ⴑⴈ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᪲مخج.-۹Ⴑⴈ +B; xn--rgbd2e831i.xn----zyc875efr3a; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ᪲مخج.-۹Ⴑⴈ +B; xn--rgbd2e831i.xn----zyc3430a9a; [B1 V3 V5]; [B1 V3 V5] # ᪲مخج.-۹ⴑⴈ +B; xn--rgbd2e831i.xn----zyc155e9a; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ᪲مخج.-۹ႱႨ +B; \u1AB2\uFD8E。-۹ⴑⴈ; [B1 V3 V5]; [B1 V3 V5] # ᪲مخج.-۹ⴑⴈ +B; \u1AB2\uFD8E。-۹Ⴑⴈ; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᪲مخج.-۹Ⴑⴈ +B; 𞤤.-\u08A3︒; [B1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤤.-ࢣ︒ +B; 𞤤.-\u08A3。; [B1 V3]; [B1 V3] # 𞤤.-ࢣ. +B; 𞤂.-\u08A3。; [B1 V3]; [B1 V3] # 𞤤.-ࢣ. +B; xn--ce6h.xn----cod.; [B1 V3]; [B1 V3] # 𞤤.-ࢣ. +B; 𞤂.-\u08A3︒; [B1 P1 V3 V6]; [B1 P1 V3 V6] # 𞤤.-ࢣ︒ +B; xn--ce6h.xn----cod7069p; [B1 V3 V6]; [B1 V3 V6] # 𞤤.-ࢣ︒ +T; \u200C𐺨.\u0859--; [B1 C1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # .࡙-- +N; \u200C𐺨.\u0859--; [B1 C1 P1 V3 V5 V6]; [B1 C1 P1 V3 V5 V6] # .࡙-- +B; xn--9p0d.xn-----h6e; [B1 V3 V5 V6]; [B1 V3 V5 V6] # .࡙-- +B; xn--0ug7905g.xn-----h6e; [B1 C1 V3 V5 V6]; [B1 C1 V3 V5 V6] # .࡙-- +B; 𐋸󮘋Ⴢ.Ⴁ; [P1 V6]; [P1 V6] +B; 𐋸󮘋ⴢ.ⴁ; [P1 V6]; [P1 V6] +B; 𐋸󮘋Ⴢ.ⴁ; [P1 V6]; [P1 V6] +B; xn--6nd5215jr2u0h.xn--skj; [V6]; [V6] +B; xn--qlj1559dr224h.xn--skj; [V6]; [V6] +B; xn--6nd5215jr2u0h.xn--8md; [V6]; [V6] +T; ñ—‘¿\uA806₄ò©ž†ï½¡ð²©§ó ’¹Ï‚; [P1 V6]; [P1 V6] # ꠆4.ς +N; ñ—‘¿\uA806₄ò©ž†ï½¡ð²©§ó ’¹Ï‚; [P1 V6]; [P1 V6] # ꠆4.ς +T; ñ—‘¿\uA8064ò©ž†ã€‚𲩧󠒹ς; [P1 V6]; [P1 V6] # ꠆4.ς +N; ñ—‘¿\uA8064ò©ž†ã€‚𲩧󠒹ς; [P1 V6]; [P1 V6] # ꠆4.ς +B; ñ—‘¿\uA8064ò©ž†ã€‚𲩧󠒹Σ; [P1 V6]; [P1 V6] # ꠆4.σ +B; ñ—‘¿\uA8064ò©ž†ã€‚𲩧󠒹σ; [P1 V6]; [P1 V6] # ꠆4.σ +B; xn--4-w93ej7463a9io5a.xn--4xa31142bk3f0d; [V6]; [V6] # ꠆4.σ +B; xn--4-w93ej7463a9io5a.xn--3xa51142bk3f0d; [V6]; [V6] # ꠆4.ς +B; ñ—‘¿\uA806₄ò©ž†ï½¡ð²©§ó ’¹Î£; [P1 V6]; [P1 V6] # ꠆4.σ +B; ñ—‘¿\uA806₄ò©ž†ï½¡ð²©§ó ’¹Ïƒ; [P1 V6]; [P1 V6] # ꠆4.σ +B; 󠆀\u0723。\u1DF4\u0775; [B1 V5]; [B1 V5] # Ü£.ᷴݵ +B; xn--tnb.xn--5pb136i; [B1 V5]; [B1 V5] # Ü£.ᷴݵ +T; 𐹱\u0842𝪨。𬼖Ⴑ\u200D; [B1 B6 C2 P1 V6]; [B1 P1 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +N; 𐹱\u0842𝪨。𬼖Ⴑ\u200D; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +T; 𐹱\u0842𝪨。𬼖Ⴑ\u200D; [B1 B6 C2 P1 V6]; [B1 P1 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +N; 𐹱\u0842𝪨。𬼖Ⴑ\u200D; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +T; 𐹱\u0842𝪨。𬼖ⴑ\u200D; [B1 B6 C2]; [B1] # 𐹱ࡂ𝪨.𬼖ⴑ +N; 𐹱\u0842𝪨。𬼖ⴑ\u200D; [B1 B6 C2]; [B1 B6 C2] # 𐹱ࡂ𝪨.𬼖ⴑ +B; xn--0vb1535kdb6e.xn--8kjz186s; [B1]; [B1] # 𐹱ࡂ𝪨.𬼖ⴑ +B; xn--0vb1535kdb6e.xn--1ug742c5714c; [B1 B6 C2]; [B1 B6 C2] # 𐹱ࡂ𝪨.𬼖ⴑ +B; xn--0vb1535kdb6e.xn--pnd93707a; [B1 V6]; [B1 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +B; xn--0vb1535kdb6e.xn--pnd879eqy33c; [B1 B6 C2 V6]; [B1 B6 C2 V6] # 𐹱ࡂ𝪨.𬼖Ⴑ +T; 𐹱\u0842𝪨。𬼖ⴑ\u200D; [B1 B6 C2]; [B1] # 𐹱ࡂ𝪨.𬼖ⴑ +N; 𐹱\u0842𝪨。𬼖ⴑ\u200D; [B1 B6 C2]; [B1 B6 C2] # 𐹱ࡂ𝪨.𬼖ⴑ +T; \u1714𐭪󠙘\u200D。-𐹴; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᜔𐭪.-𐹴 +N; \u1714𐭪󠙘\u200D。-𐹴; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # ᜔𐭪.-𐹴 +T; \u1714𐭪󠙘\u200D。-𐹴; [B1 C2 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ᜔𐭪.-𐹴 +N; \u1714𐭪󠙘\u200D。-𐹴; [B1 C2 P1 V3 V5 V6]; [B1 C2 P1 V3 V5 V6] # ᜔𐭪.-𐹴 +B; xn--fze4126jujt0g.xn----c36i; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ᜔𐭪.-𐹴 +B; xn--fze807bso0spy14i.xn----c36i; [B1 C2 V3 V5 V6]; [B1 C2 V3 V5 V6] # ᜔𐭪.-𐹴 +B; 𾢬。\u0729︒쯙𝟧; [B2 P1 V6]; [B2 P1 V6] # .ܩ︒쯙5 +B; 𾢬。\u0729︒쯙𝟧; [B2 P1 V6]; [B2 P1 V6] # .ܩ︒쯙5 +B; 𾢬。\u0729。쯙5; [P1 V6]; [P1 V6] # .Ü©.쯙5 +B; 𾢬。\u0729。쯙5; [P1 V6]; [P1 V6] # .Ü©.쯙5 +B; xn--t92s.xn--znb.xn--5-y88f; [V6]; [V6] # .Ü©.쯙5 +B; xn--t92s.xn--5-p1c0712mm8rb; [B2 V6]; [B2 V6] # .ܩ︒쯙5 +B; 𞤟-。\u0762≮뻐; [B2 B3 P1 V3 V6]; [B2 B3 P1 V3 V6] # 𞥁-.ݢ≮뻐 +B; 𞤟-。\u0762<\u0338뻐; [B2 B3 P1 V3 V6]; [B2 B3 P1 V3 V6] # 𞥁-.ݢ≮뻐 +B; 𞥁-。\u0762<\u0338뻐; [B2 B3 P1 V3 V6]; [B2 B3 P1 V3 V6] # 𞥁-.ݢ≮뻐 +B; 𞥁-。\u0762≮뻐; [B2 B3 P1 V3 V6]; [B2 B3 P1 V3 V6] # 𞥁-.ݢ≮뻐 +B; xn----1j8r.xn--mpb269krv4i; [B2 B3 V3 V6]; [B2 B3 V3 V6] # 𞥁-.ݢ≮뻐 +B; 𞥩-òŠ« ï¼Ž\u08B4≠; [B2 B3 P1 V6]; [B2 B3 P1 V6] # -.ࢴ≠ +B; 𞥩-òŠ« ï¼Ž\u08B4=\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # -.ࢴ≠ +B; 𞥩-òŠ« .\u08B4≠; [B2 B3 P1 V6]; [B2 B3 P1 V6] # -.ࢴ≠ +B; 𞥩-òŠ« .\u08B4=\u0338; [B2 B3 P1 V6]; [B2 B3 P1 V6] # -.ࢴ≠ +B; xn----cm8rp3609a.xn--9yb852k; [B2 B3 V6]; [B2 B3 V6] # -.ࢴ≠ +T; -ñ…‚Ï‚Ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςႼ.Ù¡ +N; -ñ…‚Ï‚Ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςႼ.Ù¡ +T; -ñ…‚Ï‚Ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςႼ.Ù¡ +N; -ñ…‚Ï‚Ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςႼ.Ù¡ +T; -ñ…‚Ï‚â´œ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςⴜ.Ù¡ +N; -ñ…‚Ï‚â´œ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςⴜ.Ù¡ +B; -ñ…‚Î£á‚¼.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σႼ.Ù¡ +B; -ñ…‚Ïƒâ´œ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σⴜ.Ù¡ +B; -ñ…‚Î£â´œ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σⴜ.Ù¡ +B; xn----0mb9682aov12f.xn--9hb; [B1 V3 V6]; [B1 V3 V6] # -σⴜ.Ù¡ +B; xn----0mb770hun11i.xn--9hb; [B1 V3 V6]; [B1 V3 V6] # -σႼ.Ù¡ +B; xn----ymb2782aov12f.xn--9hb; [B1 V3 V6]; [B1 V3 V6] # -ςⴜ.Ù¡ +B; xn----ymb080hun11i.xn--9hb; [B1 V3 V6]; [B1 V3 V6] # -ςႼ.Ù¡ +T; -ñ…‚Ï‚ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςⴜ.Ù¡ +N; -ñ…‚Ï‚ⴜ.\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ςⴜ.Ù¡ +B; -ñ…‚Î£á‚¼ï¼Ž\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σႼ.Ù¡ +B; -ñ…‚Ïƒâ´œï¼Ž\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σⴜ.Ù¡ +B; -ñ…‚Î£â´œï¼Ž\u0661; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -σⴜ.Ù¡ +T; \u17CA.\u200D𝟮𑀿; [C2 V5]; [V5] # ៊.2𑀿 +N; \u17CA.\u200D𝟮𑀿; [C2 V5]; [C2 V5] # ៊.2𑀿 +T; \u17CA.\u200D2𑀿; [C2 V5]; [V5] # ៊.2𑀿 +N; \u17CA.\u200D2𑀿; [C2 V5]; [C2 V5] # ៊.2𑀿 +B; xn--m4e.xn--2-ku7i; [V5]; [V5] # ៊.2𑀿 +B; xn--m4e.xn--2-tgnv469h; [C2 V5]; [C2 V5] # ៊.2𑀿 +B; ≯𝟖。\u1A60𐫓òŸ‡‘; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≯8.᩠𐫓 +B; >\u0338𝟖。\u1A60𐫓òŸ‡‘; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≯8.᩠𐫓 +B; ≯8。\u1A60𐫓òŸ‡‘; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≯8.᩠𐫓 +B; >\u03388。\u1A60𐫓òŸ‡‘; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≯8.᩠𐫓 +B; xn--8-ogo.xn--jof5303iv1z5d; [B1 V5 V6]; [B1 V5 V6] # ≯8.᩠𐫓 +T; 𑲫Ↄ\u0664。\u200C; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𑲫Ↄ٤. +N; 𑲫Ↄ\u0664。\u200C; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𑲫Ↄ٤. +T; 𑲫Ↄ\u0664。\u200C; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # 𑲫Ↄ٤. +N; 𑲫Ↄ\u0664。\u200C; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # 𑲫Ↄ٤. +T; 𑲫ↄ\u0664。\u200C; [B1 C1 V5]; [B1 V5] # 𑲫ↄ٤. +N; 𑲫ↄ\u0664。\u200C; [B1 C1 V5]; [B1 C1 V5] # 𑲫ↄ٤. +B; xn--dib100l8x1p.; [B1 V5]; [B1 V5] # 𑲫ↄ٤. +B; xn--dib100l8x1p.xn--0ug; [B1 C1 V5]; [B1 C1 V5] # 𑲫ↄ٤. +B; xn--dib999kcy1p.; [B1 V5 V6]; [B1 V5 V6] # 𑲫Ↄ٤. +B; xn--dib999kcy1p.xn--0ug; [B1 C1 V5 V6]; [B1 C1 V5 V6] # 𑲫Ↄ٤. +T; 𑲫ↄ\u0664。\u200C; [B1 C1 V5]; [B1 V5] # 𑲫ↄ٤. +N; 𑲫ↄ\u0664。\u200C; [B1 C1 V5]; [B1 C1 V5] # 𑲫ↄ٤. +T; \u0C00𝟵\u200D\uFC9D.\u200D\u0750⒈; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ఀ9بح.ݐ⒈ +N; \u0C00𝟵\u200D\uFC9D.\u200D\u0750⒈; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ఀ9بح.ݐ⒈ +T; \u0C009\u200D\u0628\u062D.\u200D\u07501.; [B1 C2 V5]; [B1 V5] # ఀ9بح.ݐ1. +N; \u0C009\u200D\u0628\u062D.\u200D\u07501.; [B1 C2 V5]; [B1 C2 V5] # ఀ9بح.ݐ1. +B; xn--9-1mcp570d.xn--1-x3c.; [B1 V5]; [B1 V5] # ఀ9بح.ݐ1. +B; xn--9-1mcp570dl51a.xn--1-x3c211q.; [B1 C2 V5]; [B1 C2 V5] # ఀ9بح.ݐ1. +B; xn--9-1mcp570d.xn--3ob470m; [B1 V5 V6]; [B1 V5 V6] # ఀ9بح.ݐ⒈ +B; xn--9-1mcp570dl51a.xn--3ob977jmfd; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ఀ9بح.ݐ⒈ +T; \uAAF6。嬶ß葽; [V5]; [V5] # ê«¶.嬶ß葽 +N; \uAAF6。嬶ß葽; [V5]; [V5] # ê«¶.嬶ß葽 +B; \uAAF6。嬶SS葽; [V5]; [V5] # ê«¶.嬶ss葽 +B; \uAAF6。嬶ss葽; [V5]; [V5] # ê«¶.嬶ss葽 +B; \uAAF6。嬶Ss葽; [V5]; [V5] # ê«¶.嬶ss葽 +B; xn--2v9a.xn--ss-q40dp97m; [V5]; [V5] # ê«¶.嬶ss葽 +B; xn--2v9a.xn--zca7637b14za; [V5]; [V5] # ê«¶.嬶ß葽 +B; 𑚶⒈。ñž»¡ð¹º; [B5 B6 P1 V5 V6]; [B5 B6 P1 V5 V6] +B; 𑚶1.。ñž»¡ð¹º; [B5 B6 P1 V5 V6 A4_2]; [B5 B6 P1 V5 V6 A4_2] +B; xn--1-3j0j..xn--yo0d5914s; [B5 B6 V5 V6 A4_2]; [B5 B6 V5 V6 A4_2] +B; xn--tshz969f.xn--yo0d5914s; [B5 B6 V5 V6]; [B5 B6 V5 V6] +B; 𑜤︒≮.ñš•½\u05D8𞾩; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𑜤︒≮.ט +B; 𑜤︒<\u0338.ñš•½\u05D8𞾩; [B1 B5 B6 P1 V5 V6]; [B1 B5 B6 P1 V5 V6] # 𑜤︒≮.ט +B; 𑜤。≮.ñš•½\u05D8𞾩; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # 𑜤.≮.ט +B; 𑜤。<\u0338.ñš•½\u05D8𞾩; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # 𑜤.≮.ט +B; xn--ci2d.xn--gdh.xn--deb0091w5q9u; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # 𑜤.≮.ט +B; xn--gdh5267fdzpa.xn--deb0091w5q9u; [B1 B5 B6 V5 V6]; [B1 B5 B6 V5 V6] # 𑜤︒≮.ט +T; 󠆋\u0603ñ¦¤.⇁ςò‹ˆòº‡¥; [B1 P1 V6]; [B1 P1 V6] # .⇁ς +N; 󠆋\u0603ñ¦¤.⇁ςò‹ˆòº‡¥; [B1 P1 V6]; [B1 P1 V6] # .⇁ς +B; 󠆋\u0603ñ¦¤.⇁Σò‹ˆòº‡¥; [B1 P1 V6]; [B1 P1 V6] # .⇁σ +B; 󠆋\u0603ñ¦¤.⇁σò‹ˆòº‡¥; [B1 P1 V6]; [B1 P1 V6] # .⇁σ +B; xn--lfb04106d.xn--4xa964mxv16m8moq; [B1 V6]; [B1 V6] # .⇁σ +B; xn--lfb04106d.xn--3xa174mxv16m8moq; [B1 V6]; [B1 V6] # .⇁ς +T; ς𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # ς𑐽𑜫.𐫄 +N; ς𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # ς𑐽𑜫.𐫄 +T; ς𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # ς𑐽𑜫.𐫄 +N; ς𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # ς𑐽𑜫.𐫄 +T; Σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # σ𑐽𑜫.𐫄 +N; Σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # σ𑐽𑜫.𐫄 +T; σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # σ𑐽𑜫.𐫄 +N; σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # σ𑐽𑜫.𐫄 +B; xn--4xa2260lk3b8z15g.xn--tw9ct349a; [V6]; [V6] +B; xn--4xa2260lk3b8z15g.xn--0ug4653g2xzf; [C1 V6]; [C1 V6] # σ𑐽𑜫.𐫄 +B; xn--3xa4260lk3b8z15g.xn--0ug4653g2xzf; [C1 V6]; [C1 V6] # ς𑐽𑜫.𐫄 +T; Σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # σ𑐽𑜫.𐫄 +N; Σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # σ𑐽𑜫.𐫄 +T; σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [P1 V6] # σ𑐽𑜫.𐫄 +N; σ𑐽𵢈𑜫。𞬩\u200C𐫄; [C1 P1 V6]; [C1 P1 V6] # σ𑐽𑜫.𐫄 +B; -òµ½ï½¡-\uFC4C\u075B; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.-نحݛ +B; -òµ½ã€‚-\u0646\u062D\u075B; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -.-نحݛ +B; xn----o452j.xn----cnc8e38c; [B1 V3 V6]; [B1 V3 V6] # -.-نحݛ +T; ⺢ò‡º…𝟤。\u200D🚷; [C2 P1 V6]; [P1 V6] # ⺢2.🚷 +N; ⺢ò‡º…𝟤。\u200D🚷; [C2 P1 V6]; [C2 P1 V6] # ⺢2.🚷 +T; ⺢ò‡º…2。\u200D🚷; [C2 P1 V6]; [P1 V6] # ⺢2.🚷 +N; ⺢ò‡º…2。\u200D🚷; [C2 P1 V6]; [C2 P1 V6] # ⺢2.🚷 +B; xn--2-4jtr4282f.xn--m78h; [V6]; [V6] +B; xn--2-4jtr4282f.xn--1ugz946p; [C2 V6]; [C2 V6] # ⺢2.🚷 +T; \u0CF8\u200D\u2DFE𐹲。ò¤¶; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # ⷾ𐹲. +N; \u0CF8\u200D\u2DFE𐹲。ò¤¶; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # ⷾ𐹲. +T; \u0CF8\u200D\u2DFE𐹲。ò¤¶; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # ⷾ𐹲. +N; \u0CF8\u200D\u2DFE𐹲。ò¤¶; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # ⷾ𐹲. +B; xn--hvc220of37m.xn--3e36c; [B5 B6 V6]; [B5 B6 V6] # ⷾ𐹲. +B; xn--hvc488g69j402t.xn--3e36c; [B5 B6 C2 V6]; [B5 B6 C2 V6] # ⷾ𐹲. +B; 𐹢.Ⴍ₉⁸; [B1 P1 V6]; [B1 P1 V6] +B; 𐹢.Ⴍ98; [B1 P1 V6]; [B1 P1 V6] +B; 𐹢.ⴍ98; [B1]; [B1] +B; xn--9n0d.xn--98-u61a; [B1]; [B1] +B; xn--9n0d.xn--98-7ek; [B1 V6]; [B1 V6] +B; 𐹢.ⴍ₉⁸; [B1]; [B1] +T; \u200C\u034F。ß\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ß⒚≯ +N; \u200C\u034F。ß\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ß⒚≯ +T; \u200C\u034F。ß\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ß⒚≯ +N; \u200C\u034F。ß\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ß⒚≯ +T; \u200C\u034F。ß\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ß19.≯ +N; \u200C\u034F。ß\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ß19.≯ +T; \u200C\u034F。ß\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ß19.≯ +N; \u200C\u034F。ß\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ß19.≯ +T; \u200C\u034F。SS\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。SS\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +T; \u200C\u034F。SS\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。SS\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +T; \u200C\u034F。ss\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。ss\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +T; \u200C\u034F。ss\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。ss\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +T; \u200C\u034F。Ss\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。Ss\u08E219.>\u0338; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +T; \u200C\u034F。Ss\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 P1 V6 A4_2] # .ss19.≯ +N; \u200C\u034F。Ss\u08E219.≯; [B1 B5 C1 P1 V6]; [B1 B5 C1 P1 V6] # .ss19.≯ +B; .xn--ss19-w0i.xn--hdh; [B1 B5 V6 A4_2]; [B1 B5 V6 A4_2] # .ss19.≯ +B; xn--0ug.xn--ss19-w0i.xn--hdh; [B1 B5 C1 V6]; [B1 B5 C1 V6] # .ss19.≯ +B; xn--0ug.xn--19-fia813f.xn--hdh; [B1 B5 C1 V6]; [B1 B5 C1 V6] # .ß19.≯ +T; \u200C\u034F。SS\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。SS\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +T; \u200C\u034F。SS\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。SS\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +T; \u200C\u034F。ss\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。ss\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +T; \u200C\u034F。ss\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。ss\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +T; \u200C\u034F。Ss\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。Ss\u08E2⒚>\u0338; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +T; \u200C\u034F。Ss\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6 A4_2] # .ss⒚≯ +N; \u200C\u034F。Ss\u08E2⒚≯; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # .ss⒚≯ +B; .xn--ss-9if872xjjc; [B5 B6 V6 A4_2]; [B5 B6 V6 A4_2] # .ss⒚≯ +B; xn--0ug.xn--ss-9if872xjjc; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # .ss⒚≯ +B; xn--0ug.xn--zca612bx9vo5b; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # .ß⒚≯ +T; \u200C𞥍ᡌ.𣃔; [B1 C1 P1 V6]; [B2 B3 P1 V6] # ᡌ.𣃔 +N; \u200C𞥍ᡌ.𣃔; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ᡌ.𣃔 +T; \u200C𞥍ᡌ.𣃔; [B1 C1 P1 V6]; [B2 B3 P1 V6] # ᡌ.𣃔 +N; \u200C𞥍ᡌ.𣃔; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ᡌ.𣃔 +B; xn--c8e5919u.xn--od1j; [B2 B3 V6]; [B2 B3 V6] +B; xn--c8e180bqz13b.xn--od1j; [B1 C1 V6]; [B1 C1 V6] # ᡌ.𣃔 +B; \u07D0òœ¬-ñ¡¢¬ã€‚\u0FA0Ⴛ𞷏𝆬; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ߐ-.ྠႻ𝆬 +B; \u07D0òœ¬-ñ¡¢¬ã€‚\u0FA0ⴛ𞷏𝆬; [B1 B2 B3 P1 V5 V6]; [B1 B2 B3 P1 V5 V6] # ߐ-.ྠⴛ𝆬 +B; xn----8bd11730jefvw.xn--wfd802mpm20agsxa; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # ߐ-.ྠⴛ𝆬 +B; xn----8bd11730jefvw.xn--wfd08cd265hgsxa; [B1 B2 B3 V5 V6]; [B1 B2 B3 V5 V6] # ߐ-.ྠႻ𝆬 +B; 𝨥。⫟𑈾; [V5]; [V5] +B; xn--n82h.xn--63iw010f; [V5]; [V5] +T; ⾛\u0753.Ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 走ݓ.Ⴕ𞠬 +N; ⾛\u0753.Ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 走ݓ.Ⴕ𞠬 +T; èµ°\u0753.Ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 走ݓ.Ⴕ𞠬 +N; èµ°\u0753.Ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 走ݓ.Ⴕ𞠬 +T; èµ°\u0753.ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 走ݓ.ⴕ𞠬 +N; èµ°\u0753.ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 走ݓ.ⴕ𞠬 +B; xn--6ob9779d.xn--mfb511rxu80a; [B5 B6 V6]; [B5 B6 V6] # 走ݓ.ⴕ𞠬 +B; xn--6ob9779d.xn--mfb444k5gjt754b; [B5 B6 C2 V6]; [B5 B6 C2 V6] # 走ݓ.ⴕ𞠬 +B; xn--6ob9779d.xn--mfb785ck569a; [B5 B6 V6]; [B5 B6 V6] # 走ݓ.Ⴕ𞠬 +B; xn--6ob9779d.xn--mfb785czmm0y85b; [B5 B6 C2 V6]; [B5 B6 C2 V6] # 走ݓ.Ⴕ𞠬 +T; ⾛\u0753.ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 走ݓ.ⴕ𞠬 +N; ⾛\u0753.ⴕ𞠬\u0604\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 走ݓ.ⴕ𞠬 +T; -ᢗ\u200C🄄.𑜢; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # -ᢗ🄄.𑜢 +N; -ᢗ\u200C🄄.𑜢; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # -ᢗ🄄.𑜢 +T; -ᢗ\u200C3,.𑜢; [C1 P1 V3 V5 V6]; [P1 V3 V5 V6] # -ᢗ3,.𑜢 +N; -ᢗ\u200C3,.𑜢; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # -ᢗ3,.𑜢 +B; xn---3,-3eu.xn--9h2d; [P1 V3 V5 V6]; [P1 V3 V5 V6] +B; xn---3,-3eu051c.xn--9h2d; [C1 P1 V3 V5 V6]; [C1 P1 V3 V5 V6] # -ᢗ3,.𑜢 +B; xn----pck1820x.xn--9h2d; [V3 V5 V6]; [V3 V5 V6] +B; xn----pck312bx563c.xn--9h2d; [C1 V3 V5 V6]; [C1 V3 V5 V6] # -ᢗ🄄.𑜢 +T; ≠𐸁𹏁\u200C.Ⴚò³„ ; [B1 C1 P1 V6]; [B1 P1 V6] # ≠.Ⴚ +N; ≠𐸁𹏁\u200C.Ⴚò³„ ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.Ⴚ +T; =\u0338𐸁𹏁\u200C.Ⴚò³„ ; [B1 C1 P1 V6]; [B1 P1 V6] # ≠.Ⴚ +N; =\u0338𐸁𹏁\u200C.Ⴚò³„ ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.Ⴚ +T; =\u0338𐸁𹏁\u200C.ⴚò³„ ; [B1 C1 P1 V6]; [B1 P1 V6] # ≠.ⴚ +N; =\u0338𐸁𹏁\u200C.ⴚò³„ ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.ⴚ +T; ≠𐸁𹏁\u200C.ⴚò³„ ; [B1 C1 P1 V6]; [B1 P1 V6] # ≠.ⴚ +N; ≠𐸁𹏁\u200C.ⴚò³„ ; [B1 C1 P1 V6]; [B1 C1 P1 V6] # ≠.ⴚ +B; xn--1ch2293gv3nr.xn--ilj23531g; [B1 V6]; [B1 V6] +B; xn--0ug83gn618a21ov.xn--ilj23531g; [B1 C1 V6]; [B1 C1 V6] # ≠.ⴚ +B; xn--1ch2293gv3nr.xn--ynd49496l; [B1 V6]; [B1 V6] +B; xn--0ug83gn618a21ov.xn--ynd49496l; [B1 C1 V6]; [B1 C1 V6] # ≠.Ⴚ +B; \u0669。󠇀𑇊; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ù©.𑇊 +B; \u0669。󠇀𑇊; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ù©.𑇊 +B; xn--iib.xn--6d1d; [B1 B3 B6 V5]; [B1 B3 B6 V5] # Ù©.𑇊 +B; \u1086𞶀≯⒍。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ႆ≯⒍.- +B; \u1086𞶀>\u0338⒍。-; [B1 P1 V3 V5 V6]; [B1 P1 V3 V5 V6] # ႆ≯⒍.- +B; \u1086𞶀≯6.。-; [B1 P1 V3 V5 V6 A4_2]; [B1 P1 V3 V5 V6 A4_2] # ႆ≯6..- +B; \u1086𞶀>\u03386.。-; [B1 P1 V3 V5 V6 A4_2]; [B1 P1 V3 V5 V6 A4_2] # ႆ≯6..- +B; xn--6-oyg968k7h74b..-; [B1 V3 V5 V6 A4_2]; [B1 V3 V5 V6 A4_2] # ႆ≯6..- +B; xn--hmd482gqqb8730g.-; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ႆ≯⒍.- +B; \u17B4.쮇-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # .쮇- +B; \u17B4.쮇-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # .쮇- +B; xn--z3e.xn----938f; [V3 V5 V6]; [V3 V5 V6] # .쮇- +T; \u200C𑓂。⒈-ô€ª›; [C1 P1 V6]; [P1 V5 V6] # 𑓂.⒈- +N; \u200C𑓂。⒈-ô€ª›; [C1 P1 V6]; [C1 P1 V6] # 𑓂.⒈- +T; \u200C𑓂。1.-ô€ª›; [C1 P1 V3 V6]; [P1 V3 V5 V6] # 𑓂.1.- +N; \u200C𑓂。1.-ô€ª›; [C1 P1 V3 V6]; [C1 P1 V3 V6] # 𑓂.1.- +B; xn--wz1d.1.xn----rg03o; [V3 V5 V6]; [V3 V5 V6] +B; xn--0ugy057g.1.xn----rg03o; [C1 V3 V6]; [C1 V3 V6] # 𑓂.1.- +B; xn--wz1d.xn----dcp29674o; [V5 V6]; [V5 V6] +B; xn--0ugy057g.xn----dcp29674o; [C1 V6]; [C1 V6] # 𑓂.⒈- +T; ⒈\uFEAE\u200C。\u20E9🖞\u200C𖬴; [B1 C1 P1 V5 V6]; [B1 P1 V5 V6] # ⒈ر.⃩🖞𖬴 +N; ⒈\uFEAE\u200C。\u20E9🖞\u200C𖬴; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # ⒈ر.⃩🖞𖬴 +T; 1.\u0631\u200C。\u20E9🖞\u200C𖬴; [B1 B3 C1 V5]; [B1 V5] # 1.ر.⃩🖞𖬴 +N; 1.\u0631\u200C。\u20E9🖞\u200C𖬴; [B1 B3 C1 V5]; [B1 B3 C1 V5] # 1.ر.⃩🖞𖬴 +B; 1.xn--wgb.xn--c1g6021kg18c; [B1 V5]; [B1 V5] # 1.ر.⃩🖞𖬴 +B; 1.xn--wgb253k.xn--0ugz6a8040fty5d; [B1 B3 C1 V5]; [B1 B3 C1 V5] # 1.ر.⃩🖞𖬴 +B; xn--wgb746m.xn--c1g6021kg18c; [B1 V5 V6]; [B1 V5 V6] # ⒈ر.⃩🖞𖬴 +B; xn--wgb253kmfd.xn--0ugz6a8040fty5d; [B1 C1 V5 V6]; [B1 C1 V5 V6] # ⒈ر.⃩🖞𖬴 +B; 󌭇。𝟐\u1BA8\u07D4; [B1 P1 V6]; [B1 P1 V6] # .2ᮨߔ +B; 󌭇。2\u1BA8\u07D4; [B1 P1 V6]; [B1 P1 V6] # .2ᮨߔ +B; xn--xm89d.xn--2-icd143m; [B1 V6]; [B1 V6] # .2ᮨߔ +T; \uFD8Fò«³º.ς\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.ς𐹷 +N; \uFD8Fò«³º.ς\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.ς𐹷 +T; \u0645\u062E\u0645ò«³º.ς\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.ς𐹷 +N; \u0645\u062E\u0645ò«³º.ς\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.ς𐹷 +T; \u0645\u062E\u0645ò«³º.Σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.σ𐹷 +N; \u0645\u062E\u0645ò«³º.Σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.σ𐹷 +T; \u0645\u062E\u0645ò«³º.σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.σ𐹷 +N; \u0645\u062E\u0645ò«³º.σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.σ𐹷 +B; xn--tgb9bb64691z.xn--4xa6667k; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # مخم.σ𐹷 +B; xn--tgb9bb64691z.xn--4xa895lrp7n; [B2 B3 B5 B6 C2 V6]; [B2 B3 B5 B6 C2 V6] # مخم.σ𐹷 +B; xn--tgb9bb64691z.xn--3xa006lrp7n; [B2 B3 B5 B6 C2 V6]; [B2 B3 B5 B6 C2 V6] # مخم.ς𐹷 +T; \uFD8Fò«³º.Σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.σ𐹷 +N; \uFD8Fò«³º.Σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.σ𐹷 +T; \uFD8Fò«³º.σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # مخم.σ𐹷 +N; \uFD8Fò«³º.σ\u200D𐹷; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # مخم.σ𐹷 +B; ⒎\u06C1\u0605。\uAAF6۵𐇽; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ⒎ہ.꫶۵𐇽 +B; 7.\u06C1\u0605。\uAAF6۵𐇽; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 7.ہ.꫶۵𐇽 +B; 7.xn--nfb98a.xn--imb3805fxt8b; [B1 V5 V6]; [B1 V5 V6] # 7.ہ.꫶۵𐇽 +B; xn--nfb98ai25e.xn--imb3805fxt8b; [B1 V5 V6]; [B1 V5 V6] # ⒎ہ.꫶۵𐇽 +B; -ᡥ᠆󍲭。\u0605\u1A5D𐹡; [B1 P1 V3 V6]; [B1 P1 V3 V6] # -ᡥ᠆.ᩝ𐹡 +B; xn----f3j6s87156i.xn--nfb035hoo2p; [B1 V3 V6]; [B1 V3 V6] # -ᡥ᠆.ᩝ𐹡 +T; \u200D.\u06BD\u0663\u0596; [B1 C2]; [A4_2] # .ڽ٣֖ +N; \u200D.\u06BD\u0663\u0596; [B1 C2]; [B1 C2] # .ڽ٣֖ +B; .xn--hcb32bni; [A4_2]; [A4_2] # .ڽ٣֖ +B; xn--1ug.xn--hcb32bni; [B1 C2]; [B1 C2] # .ڽ٣֖ +B; xn--hcb32bni; \u06BD\u0663\u0596; xn--hcb32bni # ڽ٣֖ +B; \u06BD\u0663\u0596; ; xn--hcb32bni # ڽ٣֖ +T; 㒧۱.Ⴚ\u0678\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 㒧۱.Ⴚيٴ +N; 㒧۱.Ⴚ\u0678\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 㒧۱.Ⴚيٴ +T; 㒧۱.Ⴚ\u064A\u0674\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # 㒧۱.Ⴚيٴ +N; 㒧۱.Ⴚ\u064A\u0674\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # 㒧۱.Ⴚيٴ +T; 㒧۱.ⴚ\u064A\u0674\u200D; [B5 B6 C2]; [B5 B6] # 㒧۱.ⴚيٴ +N; 㒧۱.ⴚ\u064A\u0674\u200D; [B5 B6 C2]; [B5 B6 C2] # 㒧۱.ⴚيٴ +B; xn--emb715u.xn--mhb8fy26k; [B5 B6]; [B5 B6] # 㒧۱.ⴚيٴ +B; xn--emb715u.xn--mhb8f960g03l; [B5 B6 C2]; [B5 B6 C2] # 㒧۱.ⴚيٴ +B; xn--emb715u.xn--mhb8f817a; [B5 B6 V6]; [B5 B6 V6] # 㒧۱.Ⴚيٴ +B; xn--emb715u.xn--mhb8f817ao2p; [B5 B6 C2 V6]; [B5 B6 C2 V6] # 㒧۱.Ⴚيٴ +T; 㒧۱.ⴚ\u0678\u200D; [B5 B6 C2]; [B5 B6] # 㒧۱.ⴚيٴ +N; 㒧۱.ⴚ\u0678\u200D; [B5 B6 C2]; [B5 B6 C2] # 㒧۱.ⴚيٴ +B; \u0F94ꡋ-.-𖬴; [V3 V5]; [V3 V5] # ྔꡋ-.-𖬴 +B; \u0F94ꡋ-.-𖬴; [V3 V5]; [V3 V5] # ྔꡋ-.-𖬴 +B; xn----ukg9938i.xn----4u5m; [V3 V5]; [V3 V5] # ྔꡋ-.-𖬴 +T; ñ¿’³-⋢\u200C.标-; [C1 P1 V3 V6]; [P1 V3 V6] # -⋢.标- +N; ñ¿’³-⋢\u200C.标-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # -⋢.标- +T; ñ¿’³-⊑\u0338\u200C.标-; [C1 P1 V3 V6]; [P1 V3 V6] # -⋢.标- +N; ñ¿’³-⊑\u0338\u200C.标-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # -⋢.标- +T; ñ¿’³-⋢\u200C.标-; [C1 P1 V3 V6]; [P1 V3 V6] # -⋢.标- +N; ñ¿’³-⋢\u200C.标-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # -⋢.标- +T; ñ¿’³-⊑\u0338\u200C.标-; [C1 P1 V3 V6]; [P1 V3 V6] # -⋢.标- +N; ñ¿’³-⊑\u0338\u200C.标-; [C1 P1 V3 V6]; [C1 P1 V3 V6] # -⋢.标- +B; xn----9mo67451g.xn----qj7b; [V3 V6]; [V3 V6] +B; xn----sgn90kn5663a.xn----qj7b; [C1 V3 V6]; [C1 V3 V6] # -⋢.标- +T; \u0671.ς\u07DC; [B5 B6]; [B5 B6] # Ù±.ςߜ +N; \u0671.ς\u07DC; [B5 B6]; [B5 B6] # Ù±.ςߜ +T; \u0671.ς\u07DC; [B5 B6]; [B5 B6] # Ù±.ςߜ +N; \u0671.ς\u07DC; [B5 B6]; [B5 B6] # Ù±.ςߜ +B; \u0671.Σ\u07DC; [B5 B6]; [B5 B6] # Ù±.σߜ +B; \u0671.σ\u07DC; [B5 B6]; [B5 B6] # Ù±.σߜ +B; xn--qib.xn--4xa21s; [B5 B6]; [B5 B6] # Ù±.σߜ +B; xn--qib.xn--3xa41s; [B5 B6]; [B5 B6] # Ù±.ςߜ +B; \u0671.Σ\u07DC; [B5 B6]; [B5 B6] # Ù±.σߜ +B; \u0671.σ\u07DC; [B5 B6]; [B5 B6] # Ù±.σߜ +T; ñ¼ˆ¶\u0605.\u08C1\u200D𑑂𱼱; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # .𑑂 +N; ñ¼ˆ¶\u0605.\u08C1\u200D𑑂𱼱; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # .𑑂 +T; ñ¼ˆ¶\u0605.\u08C1\u200D𑑂𱼱; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 P1 V6] # .𑑂 +N; ñ¼ˆ¶\u0605.\u08C1\u200D𑑂𱼱; [B2 B3 B5 B6 C2 P1 V6]; [B2 B3 B5 B6 C2 P1 V6] # .𑑂 +B; xn--nfb17942h.xn--nzb6708kx3pn; [B2 B3 B5 B6 V6]; [B2 B3 B5 B6 V6] # .𑑂 +B; xn--nfb17942h.xn--nzb240jv06otevq; [B2 B3 B5 B6 C2 V6]; [B2 B3 B5 B6 C2 V6] # .𑑂 +B; 𐹾𐋩𞵜。\u1BF2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹾𐋩.᯲ +B; 𐹾𐋩𞵜。\u1BF2; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𐹾𐋩.᯲ +B; xn--d97cn8rn44p.xn--0zf; [B1 V5 V6]; [B1 V5 V6] # 𐹾𐋩.᯲ +T; 6\u1160\u1C33󠸧.òŸœŠé”°\u072Cς; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 6á°³.锰ܬς +N; 6\u1160\u1C33󠸧.òŸœŠé”°\u072Cς; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 6á°³.锰ܬς +B; 6\u1160\u1C33󠸧.òŸœŠé”°\u072CΣ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 6á°³.锰ܬσ +B; 6\u1160\u1C33󠸧.òŸœŠé”°\u072Cσ; [B1 B5 P1 V6]; [B1 B5 P1 V6] # 6á°³.锰ܬσ +B; xn--6-5bh476ewr517a.xn--4xa95ohw6pk078g; [B1 B5 V6]; [B1 B5 V6] # 6á°³.锰ܬσ +B; xn--6-5bh476ewr517a.xn--3xa16ohw6pk078g; [B1 B5 V6]; [B1 B5 V6] # 6á°³.锰ܬς +B; \u06B3\uFE04ñ…Ž¦ðŸ½ï½¡ð¹½; [B1 B2 P1 V6]; [B1 B2 P1 V6] # Ú³7.𐹽 +B; \u06B3\uFE04ñ…ަ7。𐹽; [B1 B2 P1 V6]; [B1 B2 P1 V6] # Ú³7.𐹽 +B; xn--7-yuc34665f.xn--1o0d; [B1 B2 V6]; [B1 B2 V6] # Ú³7.𐹽 +T; 𞮧.\u200C⫞; [B1 C1 P1 V6]; [B1 P1 V6] # .⫞ +N; 𞮧.\u200C⫞; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .⫞ +T; 𞮧.\u200C⫞; [B1 C1 P1 V6]; [B1 P1 V6] # .⫞ +N; 𞮧.\u200C⫞; [B1 C1 P1 V6]; [B1 C1 P1 V6] # .⫞ +B; xn--pw6h.xn--53i; [B1 V6]; [B1 V6] +B; xn--pw6h.xn--0ug283b; [B1 C1 V6]; [B1 C1 V6] # .⫞ +B; -ñ•‰´.\u06E0ᢚ-; [P1 V3 V5 V6]; [P1 V3 V5 V6] # -.۠ᢚ- +B; xn----qi38c.xn----jxc827k; [V3 V5 V6]; [V3 V5 V6] # -.۠ᢚ- +T; ⌁\u200D𑄴.\u200C𝟩\u066C; [B1 C1 C2]; [B1] # ⌁𑄴.7Ù¬ +N; ⌁\u200D𑄴.\u200C𝟩\u066C; [B1 C1 C2]; [B1 C1 C2] # ⌁𑄴.7Ù¬ +T; ⌁\u200D𑄴.\u200C7\u066C; [B1 C1 C2]; [B1] # ⌁𑄴.7Ù¬ +N; ⌁\u200D𑄴.\u200C7\u066C; [B1 C1 C2]; [B1 C1 C2] # ⌁𑄴.7Ù¬ +B; xn--nhh5394g.xn--7-xqc; [B1]; [B1] # ⌁𑄴.7Ù¬ +B; xn--1ug38i2093a.xn--7-xqc297q; [B1 C1 C2]; [B1 C1 C2] # ⌁𑄴.7Ù¬ +B; ︒\uFD05\u0E37\uFEFC。岓\u1BF2󠾃ᡂ; [B1 P1 V6]; [B1 P1 V6] # ︒صىืلا.岓᯲ᡂ +B; 。\u0635\u0649\u0E37\u0644\u0627。岓\u1BF2󠾃ᡂ; [P1 V6 A4_2]; [P1 V6 A4_2] # .صىืلا.岓᯲ᡂ +B; .xn--mgb1a7bt462h.xn--17e10qe61f9r71s; [V6 A4_2]; [V6 A4_2] # .صىืلا.岓᯲ᡂ +B; xn--mgb1a7bt462hf267a.xn--17e10qe61f9r71s; [B1 V6]; [B1 V6] # ︒صىืلا.岓᯲ᡂ +B; 𐹨。8𑁆; [B1]; [B1] +B; xn--go0d.xn--8-yu7i; [B1]; [B1] +B; 𞀕\u0D43.ꡚ\u08FA𐹰\u0D44; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𞀕ൃ.ꡚࣺ𐹰ൄ +B; 𞀕\u0D43.ꡚ\u08FA𐹰\u0D44; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𞀕ൃ.ꡚࣺ𐹰ൄ +B; xn--mxc5210v.xn--90b01t8u2p1ltd; [B1 B3 B5 B6 V5]; [B1 B3 B5 B6 V5] # 𞀕ൃ.ꡚࣺ𐹰ൄ +B; 󆩏𐦹\u0303。󠍅; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ̃. +B; 󆩏𐦹\u0303。󠍅; [B1 B5 B6 P1 V6]; [B1 B5 B6 P1 V6] # ̃. +B; xn--nsa1265kp9z9e.xn--xt36e; [B1 B5 B6 V6]; [B1 B5 B6 V6] # ̃. +B; ᢌ.-\u085A; [V3]; [V3] # ᢌ.-࡚ +B; ᢌ.-\u085A; [V3]; [V3] # ᢌ.-࡚ +B; xn--59e.xn----5jd; [V3]; [V3] # ᢌ.-࡚ +B; 𥛛𑘶。𐹬𐲸\u0BCD; [B1 P1 V6]; [B1 P1 V6] # 𥛛𑘶.𐹬் +B; 𥛛𑘶。𐹬𐲸\u0BCD; [B1 P1 V6]; [B1 P1 V6] # 𥛛𑘶.𐹬் +B; xn--jb2dj685c.xn--xmc5562kmcb; [B1 V6]; [B1 V6] # 𥛛𑘶.𐹬் +T; Ⴐ\u077F.\u200C; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # Ⴐݿ. +N; Ⴐ\u077F.\u200C; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # Ⴐݿ. +T; Ⴐ\u077F.\u200C; [B1 B5 B6 C1 P1 V6]; [B5 B6 P1 V6] # Ⴐݿ. +N; Ⴐ\u077F.\u200C; [B1 B5 B6 C1 P1 V6]; [B1 B5 B6 C1 P1 V6] # Ⴐݿ. +T; ⴐ\u077F.\u200C; [B1 B5 B6 C1]; [B5 B6] # ⴐݿ. +N; ⴐ\u077F.\u200C; [B1 B5 B6 C1]; [B1 B5 B6 C1] # ⴐݿ. +B; xn--gqb743q.; [B5 B6]; [B5 B6] # ⴐݿ. +B; xn--gqb743q.xn--0ug; [B1 B5 B6 C1]; [B1 B5 B6 C1] # ⴐݿ. +B; xn--gqb918b.; [B5 B6 V6]; [B5 B6 V6] # Ⴐݿ. +B; xn--gqb918b.xn--0ug; [B1 B5 B6 C1 V6]; [B1 B5 B6 C1 V6] # Ⴐݿ. +T; ⴐ\u077F.\u200C; [B1 B5 B6 C1]; [B5 B6] # ⴐݿ. +N; ⴐ\u077F.\u200C; [B1 B5 B6 C1]; [B1 B5 B6 C1] # ⴐݿ. +T; 🄅𑲞-⒈。\u200Dá ©\u06A5; [B1 C2 P1 V6]; [B1 B5 B6 P1 V6] # 🄅𑲞-⒈.á ©Ú¥ +N; 🄅𑲞-⒈。\u200Dá ©\u06A5; [B1 C2 P1 V6]; [B1 C2 P1 V6] # 🄅𑲞-⒈.á ©Ú¥ +T; 4,𑲞-1.。\u200Dá ©\u06A5; [B1 C2 P1 V6 A4_2]; [B1 B5 B6 P1 V6 A4_2] # 4,𑲞-1..á ©Ú¥ +N; 4,𑲞-1.。\u200Dá ©\u06A5; [B1 C2 P1 V6 A4_2]; [B1 C2 P1 V6 A4_2] # 4,𑲞-1..á ©Ú¥ +B; xn--4,-1-w401a..xn--7jb180g; [B1 B5 B6 P1 V6 A4_2]; [B1 B5 B6 P1 V6 A4_2] # 4,𑲞-1..á ©Ú¥ +B; xn--4,-1-w401a..xn--7jb180gexf; [B1 C2 P1 V6 A4_2]; [B1 C2 P1 V6 A4_2] # 4,𑲞-1..á ©Ú¥ +B; xn----ecp8796hjtvg.xn--7jb180g; [B1 B5 B6 V6]; [B1 B5 B6 V6] # 🄅𑲞-⒈.á ©Ú¥ +B; xn----ecp8796hjtvg.xn--7jb180gexf; [B1 C2 V6]; [B1 C2 V6] # 🄅𑲞-⒈.á ©Ú¥ +B; ñ—€¤ã€‚𞤪ò®¿‹; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; ñ—€¤ã€‚𞤈ò®¿‹; [B2 B3 P1 V6]; [B2 B3 P1 V6] +B; xn--4240a.xn--ie6h83808a; [B2 B3 V6]; [B2 B3 V6] +B; \u05C1۲。𐮊\u066C𝨊鄨; [B1 B2 B3 V5]; [B1 B2 B3 V5] # ׁ۲.𐮊٬𝨊鄨 +B; \u05C1۲。𐮊\u066C𝨊鄨; [B1 B2 B3 V5]; [B1 B2 B3 V5] # ׁ۲.𐮊٬𝨊鄨 +B; xn--pdb42d.xn--lib6412enztdwv6h; [B1 B2 B3 V5]; [B1 B2 B3 V5] # ׁ۲.𐮊٬𝨊鄨 +B; 𞭳-ꡁ。\u1A69\u0BCD-; [B1 B2 B3 P1 V3 V5 V6]; [B1 B2 B3 P1 V3 V5 V6] # -ꡁ.ᩩ்- +B; xn----be4e4276f.xn----lze333i; [B1 B2 B3 V3 V5 V6]; [B1 B2 B3 V3 V5 V6] # -ꡁ.ᩩ்- +T; \u1039-𚮭🞢.ß; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ß +N; \u1039-𚮭🞢.ß; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ß +T; \u1039-𚮭🞢.ß; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ß +N; \u1039-𚮭🞢.ß; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ß +B; \u1039-𚮭🞢.SS; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +B; \u1039-𚮭🞢.ss; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +B; \u1039-𚮭🞢.Ss; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +B; xn----9tg11172akr8b.ss; [V5 V6]; [V5 V6] # ္-🞢.ss +B; xn----9tg11172akr8b.xn--zca; [V5 V6]; [V5 V6] # ္-🞢.ß +B; \u1039-𚮭🞢.SS; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +B; \u1039-𚮭🞢.ss; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +B; \u1039-𚮭🞢.Ss; [P1 V5 V6]; [P1 V5 V6] # ္-🞢.ss +T; \uFCF2-\u200C。Ⴟ\u200C␣; [B3 B6 C1 P1 V6]; [B3 B6 P1 V3 V6] # ـَّ-.Ⴟ␣ +N; \uFCF2-\u200C。Ⴟ\u200C␣; [B3 B6 C1 P1 V6]; [B3 B6 C1 P1 V6] # ـَّ-.Ⴟ␣ +T; \u0640\u064E\u0651-\u200C。Ⴟ\u200C␣; [B3 B6 C1 P1 V6]; [B3 B6 P1 V3 V6] # ـَّ-.Ⴟ␣ +N; \u0640\u064E\u0651-\u200C。Ⴟ\u200C␣; [B3 B6 C1 P1 V6]; [B3 B6 C1 P1 V6] # ـَّ-.Ⴟ␣ +T; \u0640\u064E\u0651-\u200C。ⴟ\u200C␣; [B3 B6 C1]; [B3 B6 V3] # ـَّ-.ⴟ␣ +N; \u0640\u064E\u0651-\u200C。ⴟ\u200C␣; [B3 B6 C1]; [B3 B6 C1] # ـَّ-.ⴟ␣ +B; xn----eoc6bm.xn--xph904a; [B3 B6 V3]; [B3 B6 V3] # ـَّ-.ⴟ␣ +B; xn----eoc6bm0504a.xn--0ug13nd0j; [B3 B6 C1]; [B3 B6 C1] # ـَّ-.ⴟ␣ +B; xn----eoc6bm.xn--3nd240h; [B3 B6 V3 V6]; [B3 B6 V3 V6] # ـَّ-.Ⴟ␣ +B; xn----eoc6bm0504a.xn--3nd849e05c; [B3 B6 C1 V6]; [B3 B6 C1 V6] # ـَّ-.Ⴟ␣ +T; \uFCF2-\u200C。ⴟ\u200C␣; [B3 B6 C1]; [B3 B6 V3] # ـَّ-.ⴟ␣ +N; \uFCF2-\u200C。ⴟ\u200C␣; [B3 B6 C1]; [B3 B6 C1] # ـَّ-.ⴟ␣ +T; \u0D4D-\u200D\u200C。ñ¥ž§â‚…≠; [C1 C2 P1 V5 V6]; [P1 V3 V5 V6] # ്-.5≠ +N; \u0D4D-\u200D\u200C。ñ¥ž§â‚…≠; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # ്-.5≠ +T; \u0D4D-\u200D\u200C。ñ¥ž§â‚…=\u0338; [C1 C2 P1 V5 V6]; [P1 V3 V5 V6] # ്-.5≠ +N; \u0D4D-\u200D\u200C。ñ¥ž§â‚…=\u0338; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # ്-.5≠ +T; \u0D4D-\u200D\u200C。ñ¥ž§5≠; [C1 C2 P1 V5 V6]; [P1 V3 V5 V6] # ്-.5≠ +N; \u0D4D-\u200D\u200C。ñ¥ž§5≠; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # ്-.5≠ +T; \u0D4D-\u200D\u200C。ñ¥ž§5=\u0338; [C1 C2 P1 V5 V6]; [P1 V3 V5 V6] # ്-.5≠ +N; \u0D4D-\u200D\u200C。ñ¥ž§5=\u0338; [C1 C2 P1 V5 V6]; [C1 C2 P1 V5 V6] # ്-.5≠ +B; xn----jmf.xn--5-ufo50192e; [V3 V5 V6]; [V3 V5 V6] # ്-.5≠ +B; xn----jmf215lda.xn--5-ufo50192e; [C1 C2 V5 V6]; [C1 C2 V5 V6] # ്-.5≠ +B; 锣。\u0A4D󠘻󠚆; [P1 V5 V6]; [P1 V5 V6] # 锣.੍ +B; xn--gc5a.xn--ybc83044ppga; [V5 V6]; [V5 V6] # 锣.੍ +T; \u063D𑈾.\u0649\u200D\uA92B; [B3 C2]; xn--8gb2338k.xn--lhb0154f # ؽ𑈾.ى꤫ +N; \u063D𑈾.\u0649\u200D\uA92B; [B3 C2]; [B3 C2] # ؽ𑈾.ى꤫ +T; \u063D𑈾.\u0649\u200D\uA92B; [B3 C2]; xn--8gb2338k.xn--lhb0154f # ؽ𑈾.ى꤫ +N; \u063D𑈾.\u0649\u200D\uA92B; [B3 C2]; [B3 C2] # ؽ𑈾.ى꤫ +B; xn--8gb2338k.xn--lhb0154f; \u063D𑈾.\u0649\uA92B; xn--8gb2338k.xn--lhb0154f # ؽ𑈾.ى꤫ +B; \u063D𑈾.\u0649\uA92B; ; xn--8gb2338k.xn--lhb0154f # ؽ𑈾.ى꤫ +B; xn--8gb2338k.xn--lhb603k060h; [B3 C2]; [B3 C2] # ؽ𑈾.ى꤫ +T; \u0666⁴Ⴅ.\u08BD\u200C; [B1 B3 C1 P1 V6]; [B1 P1 V6] # Ù¦4Ⴅ.ࢽ +N; \u0666⁴Ⴅ.\u08BD\u200C; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # Ù¦4Ⴅ.ࢽ +T; \u06664Ⴅ.\u08BD\u200C; [B1 B3 C1 P1 V6]; [B1 P1 V6] # Ù¦4Ⴅ.ࢽ +N; \u06664Ⴅ.\u08BD\u200C; [B1 B3 C1 P1 V6]; [B1 B3 C1 P1 V6] # Ù¦4Ⴅ.ࢽ +T; \u06664ⴅ.\u08BD\u200C; [B1 B3 C1]; [B1] # Ù¦4ⴅ.ࢽ +N; \u06664ⴅ.\u08BD\u200C; [B1 B3 C1]; [B1 B3 C1] # Ù¦4ⴅ.ࢽ +B; xn--4-kqc6770a.xn--jzb; [B1]; [B1] # Ù¦4ⴅ.ࢽ +B; xn--4-kqc6770a.xn--jzb840j; [B1 B3 C1]; [B1 B3 C1] # Ù¦4ⴅ.ࢽ +B; xn--4-kqc489e.xn--jzb; [B1 V6]; [B1 V6] # Ù¦4Ⴅ.ࢽ +B; xn--4-kqc489e.xn--jzb840j; [B1 B3 C1 V6]; [B1 B3 C1 V6] # Ù¦4Ⴅ.ࢽ +T; \u0666⁴ⴅ.\u08BD\u200C; [B1 B3 C1]; [B1] # Ù¦4ⴅ.ࢽ +N; \u0666⁴ⴅ.\u08BD\u200C; [B1 B3 C1]; [B1 B3 C1] # Ù¦4ⴅ.ࢽ +T; ჁႱ6\u0318。ß\u1B03; [P1 V6]; [P1 V6] # ჁႱ6̘.ßᬃ +N; ჁႱ6\u0318。ß\u1B03; [P1 V6]; [P1 V6] # ჁႱ6̘.ßᬃ +T; ⴡⴑ6\u0318。ß\u1B03; ⴡⴑ6\u0318.ß\u1B03; xn--6-8cb7433a2ba.xn--ss-2vq # ⴡⴑ6̘.ßᬃ +N; ⴡⴑ6\u0318。ß\u1B03; ⴡⴑ6\u0318.ß\u1B03; xn--6-8cb7433a2ba.xn--zca894k # ⴡⴑ6̘.ßᬃ +B; ჁႱ6\u0318。SS\u1B03; [P1 V6]; [P1 V6] # ჁႱ6̘.ssᬃ +B; ⴡⴑ6\u0318。ss\u1B03; ⴡⴑ6\u0318.ss\u1B03; xn--6-8cb7433a2ba.xn--ss-2vq # ⴡⴑ6̘.ssᬃ +B; Ⴡⴑ6\u0318。Ss\u1B03; [P1 V6]; [P1 V6] # Ⴡⴑ6̘.ssᬃ +B; xn--6-8cb306hms1a.xn--ss-2vq; [V6]; [V6] # Ⴡⴑ6̘.ssᬃ +B; xn--6-8cb7433a2ba.xn--ss-2vq; ⴡⴑ6\u0318.ss\u1B03; xn--6-8cb7433a2ba.xn--ss-2vq # ⴡⴑ6̘.ssᬃ +B; ⴡⴑ6\u0318.ss\u1B03; ; xn--6-8cb7433a2ba.xn--ss-2vq # ⴡⴑ6̘.ssᬃ +B; ჁႱ6\u0318.SS\u1B03; [P1 V6]; [P1 V6] # ჁႱ6̘.ssᬃ +B; Ⴡⴑ6\u0318.Ss\u1B03; [P1 V6]; [P1 V6] # Ⴡⴑ6̘.ssᬃ +B; xn--6-8cb555h2b.xn--ss-2vq; [V6]; [V6] # ჁႱ6̘.ssᬃ +B; xn--6-8cb7433a2ba.xn--zca894k; ⴡⴑ6\u0318.ß\u1B03; xn--6-8cb7433a2ba.xn--zca894k # ⴡⴑ6̘.ßᬃ +T; ⴡⴑ6\u0318.ß\u1B03; ; xn--6-8cb7433a2ba.xn--ss-2vq # ⴡⴑ6̘.ßᬃ +N; ⴡⴑ6\u0318.ß\u1B03; ; xn--6-8cb7433a2ba.xn--zca894k # ⴡⴑ6̘.ßᬃ +B; xn--6-8cb555h2b.xn--zca894k; [V6]; [V6] # ჁႱ6̘.ßᬃ +B; ò‹¡ï½¡â‰¯ð‘‹ª; [P1 V6]; [P1 V6] +B; ò‹¡ï½¡>\u0338𑋪; [P1 V6]; [P1 V6] +B; ò‹¡ã€‚≯𑋪; [P1 V6]; [P1 V6] +B; ò‹¡ã€‚>\u0338𑋪; [P1 V6]; [P1 V6] +B; xn--eo08b.xn--hdh3385g; [V6]; [V6] +T; \u065A۲。\u200C-\u1BF3\u08E2; [B1 C1 P1 V5 V6]; [B1 P1 V3 V5 V6] # ٚ۲.-᯳ +N; \u065A۲。\u200C-\u1BF3\u08E2; [B1 C1 P1 V5 V6]; [B1 C1 P1 V5 V6] # ٚ۲.-᯳ +B; xn--2hb81a.xn----xrd657l; [B1 V3 V5 V6]; [B1 V3 V5 V6] # ٚ۲.-᯳ +B; xn--2hb81a.xn----xrd657l30d; [B1 C1 V5 V6]; [B1 C1 V5 V6] # ٚ۲.-᯳ +B; 󠄏𖬴󠲽。\uFFA0; [P1 V5 V6]; [P1 V5 V6] # 𖬴. +B; 󠄏𖬴󠲽。\u1160; [P1 V5 V6]; [P1 V5 V6] # 𖬴. +B; xn--619ep9154c.xn--psd; [V5 V6]; [V5 V6] # 𖬴. +B; xn--619ep9154c.xn--cl7c; [V5 V6]; [V5 V6] # 𖬴. +T; ß⒈\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B5 P1 V6]; [B5 P1 V6] # ß⒈ݠ. +N; ß⒈\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B5 P1 V6]; [B5 P1 V6] # ß⒈ݠ. +T; ß1.\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B2 B3 B5 P1 V6]; [B2 B3 B5 P1 V6] # ß1.Ý . +N; ß1.\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B2 B3 B5 P1 V6]; [B2 B3 B5 P1 V6] # ß1.Ý . +B; SS1.\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B2 B3 B5 P1 V6]; [B2 B3 B5 P1 V6] # ss1.Ý . +B; ss1.\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B2 B3 B5 P1 V6]; [B2 B3 B5 P1 V6] # ss1.Ý . +B; Ss1.\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B2 B3 B5 P1 V6]; [B2 B3 B5 P1 V6] # ss1.Ý . +B; ss1.xn--kpb6677h.xn--nfb09923ifkyyb; [B2 B3 B5 V6]; [B2 B3 B5 V6] # ss1.Ý . +B; xn--1-pfa.xn--kpb6677h.xn--nfb09923ifkyyb; [B2 B3 B5 V6]; [B2 B3 B5 V6] # ß1.Ý . +B; SS⒈\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B5 P1 V6]; [B5 P1 V6] # ss⒈ݠ. +B; ss⒈\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B5 P1 V6]; [B5 P1 V6] # ss⒈ݠ. +B; Ss⒈\u0760\uD7AE.ô‰–²ó …„\u0605ò‰”¯; [B5 P1 V6]; [B5 P1 V6] # ss⒈ݠ. +B; xn--ss-6ke9690a0g1q.xn--nfb09923ifkyyb; [B5 V6]; [B5 V6] # ss⒈ݠ. +B; xn--zca444a0s1ao12n.xn--nfb09923ifkyyb; [B5 V6]; [B5 V6] # ß⒈ݠ. +B; 󠭔.𐋱₂; [P1 V6]; [P1 V6] +B; 󠭔.𐋱2; [P1 V6]; [P1 V6] +B; xn--vi56e.xn--2-w91i; [V6]; [V6] +T; \u0716\u0947。-ß\u06A5\u200C; [B1 C1 V3]; [B1 V3] # ܖे.-ßڥ +N; \u0716\u0947。-ß\u06A5\u200C; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ßڥ +T; \u0716\u0947。-SS\u06A5\u200C; [B1 C1 V3]; [B1 V3] # ܖे.-ssÚ¥ +N; \u0716\u0947。-SS\u06A5\u200C; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ssÚ¥ +T; \u0716\u0947。-ss\u06A5\u200C; [B1 C1 V3]; [B1 V3] # ܖे.-ssÚ¥ +N; \u0716\u0947。-ss\u06A5\u200C; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ssÚ¥ +T; \u0716\u0947。-Ss\u06A5\u200C; [B1 C1 V3]; [B1 V3] # ܖे.-ssÚ¥ +N; \u0716\u0947。-Ss\u06A5\u200C; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ssÚ¥ +B; xn--gnb63i.xn---ss-4ef; [B1 V3]; [B1 V3] # ܖे.-ssÚ¥ +B; xn--gnb63i.xn---ss-4ef9263a; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ssÚ¥ +B; xn--gnb63i.xn----qfa845bhx4a; [B1 C1 V3]; [B1 C1 V3] # ܖे.-ßڥ +T; \u1BA9\u200D\u062Añ¡šˆï¼Ž\u1CD5䷉Ⴡ; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ᮩت.᳕䷉Ⴡ +N; \u1BA9\u200D\u062Añ¡šˆï¼Ž\u1CD5䷉Ⴡ; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ᮩت.᳕䷉Ⴡ +T; \u1BA9\u200D\u062Añ¡šˆ.\u1CD5䷉Ⴡ; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ᮩت.᳕䷉Ⴡ +N; \u1BA9\u200D\u062Añ¡šˆ.\u1CD5䷉Ⴡ; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ᮩت.᳕䷉Ⴡ +T; \u1BA9\u200D\u062Añ¡šˆ.\u1CD5䷉ⴡ; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ᮩت.᳕䷉ⴡ +N; \u1BA9\u200D\u062Añ¡šˆ.\u1CD5䷉ⴡ; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ᮩت.᳕䷉ⴡ +B; xn--pgb911izv33i.xn--i6f270etuy; [B1 V5 V6]; [B1 V5 V6] # ᮩت.᳕䷉ⴡ +B; xn--pgb911imgdrw34r.xn--i6f270etuy; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ᮩت.᳕䷉ⴡ +B; xn--pgb911izv33i.xn--5nd792dgv3b; [B1 V5 V6]; [B1 V5 V6] # ᮩت.᳕䷉Ⴡ +B; xn--pgb911imgdrw34r.xn--5nd792dgv3b; [B1 C2 V5 V6]; [B1 C2 V5 V6] # ᮩت.᳕䷉Ⴡ +T; \u1BA9\u200D\u062Añ¡šˆï¼Ž\u1CD5䷉ⴡ; [B1 C2 P1 V5 V6]; [B1 P1 V5 V6] # ᮩت.᳕䷉ⴡ +N; \u1BA9\u200D\u062Añ¡šˆï¼Ž\u1CD5䷉ⴡ; [B1 C2 P1 V5 V6]; [B1 C2 P1 V5 V6] # ᮩت.᳕䷉ⴡ +T; \u2DBF.ß\u200D; [C2 P1 V6]; [P1 V6] # .ß +N; \u2DBF.ß\u200D; [C2 P1 V6]; [C2 P1 V6] # .ß +T; \u2DBF.SS\u200D; [C2 P1 V6]; [P1 V6] # .ss +N; \u2DBF.SS\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss +T; \u2DBF.ss\u200D; [C2 P1 V6]; [P1 V6] # .ss +N; \u2DBF.ss\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss +T; \u2DBF.Ss\u200D; [C2 P1 V6]; [P1 V6] # .ss +N; \u2DBF.Ss\u200D; [C2 P1 V6]; [C2 P1 V6] # .ss +B; xn--7pj.ss; [V6]; [V6] # .ss +B; xn--7pj.xn--ss-n1t; [C2 V6]; [C2 V6] # .ss +B; xn--7pj.xn--zca870n; [C2 V6]; [C2 V6] # .ß +B; \u1BF3︒.\u062A≯ꡂ; [B2 B3 B6 P1 V5 V6]; [B2 B3 B6 P1 V5 V6] # ᯳︒.ت≯ꡂ +B; \u1BF3︒.\u062A>\u0338ꡂ; [B2 B3 B6 P1 V5 V6]; [B2 B3 B6 P1 V5 V6] # ᯳︒.ت≯ꡂ +B; \u1BF3。.\u062A≯ꡂ; [B2 B3 P1 V5 V6 A4_2]; [B2 B3 P1 V5 V6 A4_2] # ᯳..ت≯ꡂ +B; \u1BF3。.\u062A>\u0338ꡂ; [B2 B3 P1 V5 V6 A4_2]; [B2 B3 P1 V5 V6 A4_2] # ᯳..ت≯ꡂ +B; xn--1zf..xn--pgb885lry5g; [B2 B3 V5 V6 A4_2]; [B2 B3 V5 V6 A4_2] # ᯳..ت≯ꡂ +B; xn--1zf8957g.xn--pgb885lry5g; [B2 B3 B6 V5 V6]; [B2 B3 B6 V5 V6] # ᯳︒.ت≯ꡂ +B; ≮≠ñ»ƒï½¡-𫠆\u06B7𐹪; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≮≠.-𫠆ڷ𐹪 +B; <\u0338=\u0338ñ»ƒï½¡-𫠆\u06B7𐹪; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≮≠.-𫠆ڷ𐹪 +B; ≮≠ñ»ƒã€‚-𫠆\u06B7𐹪; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≮≠.-𫠆ڷ𐹪 +B; <\u0338=\u0338ñ»ƒã€‚-𫠆\u06B7𐹪; [B1 P1 V3 V6]; [B1 P1 V3 V6] # ≮≠.-𫠆ڷ𐹪 +B; xn--1ch1a29470f.xn----7uc5363rc1rn; [B1 V3 V6]; [B1 V3 V6] # ≮≠.-𫠆ڷ𐹪 +B; 𐹡\u0777。ꡂ; [B1]; [B1] # 𐹡ݷ.ꡂ +B; xn--7pb5275k.xn--bc9a; [B1]; [B1] # 𐹡ݷ.ꡂ +T; Ⴉ𝆅ñ”»…\u0619.ß𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴉؙ𝆅.ß𐧦𐹳ݵ +N; Ⴉ𝆅ñ”»…\u0619.ß𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴉؙ𝆅.ß𐧦𐹳ݵ +T; ⴉ𝆅ñ”»…\u0619.ß𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴉؙ𝆅.ß𐧦𐹳ݵ +N; ⴉ𝆅ñ”»…\u0619.ß𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴉؙ𝆅.ß𐧦𐹳ݵ +B; Ⴉ𝆅ñ”»…\u0619.SS𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴉؙ𝆅.ss𐧦𐹳ݵ +B; ⴉ𝆅ñ”»…\u0619.ss𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # ⴉؙ𝆅.ss𐧦𐹳ݵ +B; Ⴉ𝆅ñ”»…\u0619.Ss𐧦𐹳\u0775; [B5 B6 P1 V6]; [B5 B6 P1 V6] # Ⴉؙ𝆅.ss𐧦𐹳ݵ +B; xn--7fb125cjv87a7xvz.xn--ss-zme7575xp0e; [B5 B6 V6]; [B5 B6 V6] # Ⴉؙ𝆅.ss𐧦𐹳ݵ +B; xn--7fb940rwt3z7xvz.xn--ss-zme7575xp0e; [B5 B6 V6]; [B5 B6 V6] # ⴉؙ𝆅.ss𐧦𐹳ݵ +B; xn--7fb940rwt3z7xvz.xn--zca684a699vf2d; [B5 B6 V6]; [B5 B6 V6] # ⴉؙ𝆅.ß𐧦𐹳ݵ +B; xn--7fb125cjv87a7xvz.xn--zca684a699vf2d; [B5 B6 V6]; [B5 B6 V6] # Ⴉؙ𝆅.ß𐧦𐹳ݵ +T; \u200D\u0643𐧾↙.ñн¡; [B1 C2 P1 V6]; [B3 P1 V6] # ك𐧾↙. +N; \u200D\u0643𐧾↙.ñн¡; [B1 C2 P1 V6]; [B1 C2 P1 V6] # ك𐧾↙. +B; xn--fhb011lnp8n.xn--7s4w; [B3 V6]; [B3 V6] # ك𐧾↙. +B; xn--fhb713k87ag053c.xn--7s4w; [B1 C2 V6]; [B1 C2 V6] # ك𐧾↙. +T; 梉。\u200C; [C1]; xn--7zv. # 梉. +N; 梉。\u200C; [C1]; [C1] # 梉. +B; xn--7zv.; 梉.; xn--7zv. +B; 梉.; ; xn--7zv. +B; xn--7zv.xn--0ug; [C1]; [C1] # 梉. +T; ê¡£-≠.\u200D𞤗𐅢Ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢Ↄ +N; ê¡£-≠.\u200D𞤗𐅢Ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢Ↄ +T; ê¡£-=\u0338.\u200D𞤗𐅢Ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢Ↄ +N; ê¡£-=\u0338.\u200D𞤗𐅢Ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢Ↄ +T; ê¡£-=\u0338.\u200D𞤹𐅢ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +N; ê¡£-=\u0338.\u200D𞤹𐅢ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +T; ê¡£-≠.\u200D𞤹𐅢ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +N; ê¡£-≠.\u200D𞤹𐅢ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +T; ê¡£-≠.\u200D𞤗𐅢ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +N; ê¡£-≠.\u200D𞤗𐅢ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +T; ê¡£-=\u0338.\u200D𞤗𐅢ↄ; [B1 B6 C2 P1 V6]; [B2 B3 B6 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +N; ê¡£-=\u0338.\u200D𞤗𐅢ↄ; [B1 B6 C2 P1 V6]; [B1 B6 C2 P1 V6] # ê¡£-≠.𞤹𐅢ↄ +B; xn----ufo9661d.xn--r5gy929fhm4f; [B2 B3 B6 V6]; [B2 B3 B6 V6] +B; xn----ufo9661d.xn--1ug99cj620c71sh; [B1 B6 C2 V6]; [B1 B6 C2 V6] # ê¡£-≠.𞤹𐅢ↄ +B; xn----ufo9661d.xn--q5g0929fhm4f; [B2 B3 B6 V6]; [B2 B3 B6 V6] +B; xn----ufo9661d.xn--1ug79cm620c71sh; [B1 B6 C2 V6]; [B1 B6 C2 V6] # ê¡£-≠.𞤹𐅢Ↄ +T; ς⒐𝆫⸵。𐱢🄊𝟳; [B6 P1 V6]; [B6 P1 V6] +N; ς⒐𝆫⸵。𐱢🄊𝟳; [B6 P1 V6]; [B6 P1 V6] +T; ς9.𝆫⸵。𐱢9,7; [B1 P1 V5 V6]; [B1 P1 V5 V6] +N; ς9.𝆫⸵。𐱢9,7; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; Σ9.𝆫⸵。𐱢9,7; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; σ9.𝆫⸵。𐱢9,7; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; xn--9-zmb.xn--ltj1535k.xn--9,7-r67t; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; xn--9-xmb.xn--ltj1535k.xn--9,7-r67t; [B1 P1 V5 V6]; [B1 P1 V5 V6] +B; Σ⒐𝆫⸵。𐱢🄊𝟳; [B6 P1 V6]; [B6 P1 V6] +B; σ⒐𝆫⸵。𐱢🄊𝟳; [B6 P1 V6]; [B6 P1 V6] +B; xn--4xa809nwtghi25b.xn--7-075iy877c; [B6 V6]; [B6 V6] +B; xn--3xa019nwtghi25b.xn--7-075iy877c; [B6 V6]; [B6 V6] +T; \u0853.\u200Cß; [B1 C1]; xn--iwb.ss # ࡓ.ß +N; \u0853.\u200Cß; [B1 C1]; [B1 C1] # ࡓ.ß +T; \u0853.\u200Cß; [B1 C1]; xn--iwb.ss # ࡓ.ß +N; \u0853.\u200Cß; [B1 C1]; [B1 C1] # ࡓ.ß +T; \u0853.\u200CSS; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200CSS; [B1 C1]; [B1 C1] # ࡓ.ss +T; \u0853.\u200Css; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200Css; [B1 C1]; [B1 C1] # ࡓ.ss +T; \u0853.\u200CSs; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200CSs; [B1 C1]; [B1 C1] # ࡓ.ss +B; xn--iwb.ss; \u0853.ss; xn--iwb.ss # ࡓ.ss +B; \u0853.ss; ; xn--iwb.ss # ࡓ.ss +B; \u0853.SS; \u0853.ss; xn--iwb.ss # ࡓ.ss +B; \u0853.Ss; \u0853.ss; xn--iwb.ss # ࡓ.ss +B; xn--iwb.xn--ss-i1t; [B1 C1]; [B1 C1] # ࡓ.ss +B; xn--iwb.xn--zca570n; [B1 C1]; [B1 C1] # ࡓ.ß +T; \u0853.\u200CSS; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200CSS; [B1 C1]; [B1 C1] # ࡓ.ss +T; \u0853.\u200Css; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200Css; [B1 C1]; [B1 C1] # ࡓ.ss +T; \u0853.\u200CSs; [B1 C1]; xn--iwb.ss # ࡓ.ss +N; \u0853.\u200CSs; [B1 C1]; [B1 C1] # ࡓ.ss +T; ñ¯¶£-.\u200D\u074E\uA94D󠻨; [B1 B6 C2 P1 V3 V6]; [B3 B6 P1 V3 V6] # -.ݎꥍ +N; ñ¯¶£-.\u200D\u074E\uA94D󠻨; [B1 B6 C2 P1 V3 V6]; [B1 B6 C2 P1 V3 V6] # -.ݎꥍ +B; xn----s116e.xn--1ob6504fmf40i; [B3 B6 V3 V6]; [B3 B6 V3 V6] # -.ݎꥍ +B; xn----s116e.xn--1ob387jy90hq459k; [B1 B6 C2 V3 V6]; [B1 B6 C2 V3 V6] # -.ݎꥍ +B; 䃚蟥-。-ñ½’˜â’ˆ; [P1 V3 V6]; [P1 V3 V6] +B; 䃚蟥-。-ñ½’˜1.; [P1 V3 V6]; [P1 V3 V6] +B; xn----n50a258u.xn---1-up07j.; [V3 V6]; [V3 V6] +B; xn----n50a258u.xn----ecp33805f; [V3 V6]; [V3 V6] +B; 𐹸䚵-ꡡ。⺇; [B1]; [B1] +B; xn----bm3an932a1l5d.xn--xvj; [B1]; [B1] +B; 𑄳。\u1ADC𐹻; [B1 B3 B5 B6 P1 V5 V6]; [B1 B3 B5 B6 P1 V5 V6] # 𑄳.𐹻 +B; xn--v80d.xn--2rf1154i; [B1 B3 B5 B6 V5 V6]; [B1 B3 B5 B6 V5 V6] # 𑄳.𐹻 +B; ≮𐹻.⒎𑂵\u06BA\u0602; [B1 P1 V6]; [B1 P1 V6] # ≮𐹻.⒎𑂵ں +B; <\u0338𐹻.⒎𑂵\u06BA\u0602; [B1 P1 V6]; [B1 P1 V6] # ≮𐹻.⒎𑂵ں +B; ≮𐹻.7.𑂵\u06BA\u0602; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮𐹻.7.𑂵ں +B; <\u0338𐹻.7.𑂵\u06BA\u0602; [B1 P1 V5 V6]; [B1 P1 V5 V6] # ≮𐹻.7.𑂵ں +B; xn--gdhx904g.7.xn--kfb18an307d; [B1 V5 V6]; [B1 V5 V6] # ≮𐹻.7.𑂵ں +B; xn--gdhx904g.xn--kfb18a325efm3s; [B1 V6]; [B1 V6] # ≮𐹻.⒎𑂵ں +T; ᢔ≠ô‹‰‚.\u200D𐋢; [C2 P1 V6]; [P1 V6] # ᢔ≠.𐋢 +N; ᢔ≠ô‹‰‚.\u200D𐋢; [C2 P1 V6]; [C2 P1 V6] # ᢔ≠.𐋢 +T; ᢔ=\u0338ô‹‰‚.\u200D𐋢; [C2 P1 V6]; [P1 V6] # ᢔ≠.𐋢 +N; ᢔ=\u0338ô‹‰‚.\u200D𐋢; [C2 P1 V6]; [C2 P1 V6] # ᢔ≠.𐋢 +B; xn--ebf031cf7196a.xn--587c; [V6]; [V6] +B; xn--ebf031cf7196a.xn--1ug9540g; [C2 V6]; [C2 V6] # ᢔ≠.𐋢 +B; 𐩁≮ñ£Š›â‰¯ï¼Ž\u066C𞵕⳿; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 𐩁≮≯.٬⳿ +B; 𐩁<\u0338ñ£Š›>\u0338.\u066C𞵕⳿; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 𐩁≮≯.٬⳿ +B; 𐩁≮ñ£Š›â‰¯.\u066C𞵕⳿; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 𐩁≮≯.٬⳿ +B; 𐩁<\u0338ñ£Š›>\u0338.\u066C𞵕⳿; [B1 B2 B3 P1 V6]; [B1 B2 B3 P1 V6] # 𐩁≮≯.٬⳿ +B; xn--gdhc0519o0y27b.xn--lib468q0d21a; [B1 B2 B3 V6]; [B1 B2 B3 V6] # 𐩁≮≯.٬⳿ +B; -。⺐; [V3]; [V3] +B; -。⺐; [V3]; [V3] +B; -.xn--6vj; [V3]; [V3] +B; 󠰩𑲬.\u065C; [P1 V5 V6]; [P1 V5 V6] # 𑲬.ٜ +B; 󠰩𑲬.\u065C; [P1 V5 V6]; [P1 V5 V6] # 𑲬.ٜ +B; xn--sn3d59267c.xn--4hb; [V5 V6]; [V5 V6] # 𑲬.ٜ +T; 𐍺.ñš‡ƒ\u200C; [C1 P1 V5 V6]; [P1 V5 V6] # 𐍺. +N; 𐍺.ñš‡ƒ\u200C; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 𐍺. +B; xn--ie8c.xn--2g51a; [V5 V6]; [V5 V6] +B; xn--ie8c.xn--0ug03366c; [C1 V5 V6]; [C1 V5 V6] # 𐍺. +B; \u063D\u06E3.𐨎; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ؽۣ.𐨎 +B; xn--8gb64a.xn--mr9c; [B1 B3 B6 V5]; [B1 B3 B6 V5] # ؽۣ.𐨎 +T; 漦Ⴙς.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +N; 漦Ⴙς.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +T; 漦ⴙς.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +N; 漦ⴙς.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; 漦ႹΣ.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; 漦ⴙσ.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; 漦Ⴙσ.ñ¡»€ð´„; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; xn--4xa947d717e.xn--9d0d3162t; [B5 B6 V6]; [B5 B6 V6] +B; xn--4xa772sl47b.xn--9d0d3162t; [B5 B6 V6]; [B5 B6 V6] +B; xn--3xa972sl47b.xn--9d0d3162t; [B5 B6 V6]; [B5 B6 V6] +B; xn--3xa157d717e.xn--9d0d3162t; [B5 B6 V6]; [B5 B6 V6] +B; 𐹫踧\u0CCDò«š‡.󜀃⒈𝨤; [B1 P1 V6]; [B1 P1 V6] # 𐹫踧್.⒈𝨤 +B; 𐹫踧\u0CCDò«š‡.󜀃1.𝨤; [B1 B3 B6 P1 V5 V6]; [B1 B3 B6 P1 V5 V6] # 𐹫踧್.1.𝨤 +B; xn--8tc1437dro0d6q06h.xn--1-p948l.xn--m82h; [B1 B3 B6 V5 V6]; [B1 B3 B6 V5 V6] # 𐹫踧್.1.𝨤 +B; xn--8tc1437dro0d6q06h.xn--tsh2611ncu71e; [B1 V6]; [B1 V6] # 𐹫踧್.⒈𝨤 +T; \u200D≮.󠟪𹫏-; [C2 P1 V3 V6]; [P1 V3 V6] # ≮.- +N; \u200D≮.󠟪𹫏-; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ≮.- +T; \u200D<\u0338.󠟪𹫏-; [C2 P1 V3 V6]; [P1 V3 V6] # ≮.- +N; \u200D<\u0338.󠟪𹫏-; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ≮.- +T; \u200D≮.󠟪𹫏-; [C2 P1 V3 V6]; [P1 V3 V6] # ≮.- +N; \u200D≮.󠟪𹫏-; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ≮.- +T; \u200D<\u0338.󠟪𹫏-; [C2 P1 V3 V6]; [P1 V3 V6] # ≮.- +N; \u200D<\u0338.󠟪𹫏-; [C2 P1 V3 V6]; [C2 P1 V3 V6] # ≮.- +B; xn--gdh.xn----cr99a1w710b; [V3 V6]; [V3 V6] +B; xn--1ug95g.xn----cr99a1w710b; [C2 V3 V6]; [C2 V3 V6] # ≮.- +T; \u200D\u200D襔。Ⴜ5ê¡®ñµ; [C2 P1 V6]; [P1 V6] # 襔.Ⴜ5ê¡® +N; \u200D\u200D襔。Ⴜ5ê¡®ñµ; [C2 P1 V6]; [C2 P1 V6] # 襔.Ⴜ5ê¡® +T; \u200D\u200D襔。ⴜ5ê¡®ñµ; [C2 P1 V6]; [P1 V6] # 襔.ⴜ5ê¡® +N; \u200D\u200D襔。ⴜ5ê¡®ñµ; [C2 P1 V6]; [C2 P1 V6] # 襔.ⴜ5ê¡® +B; xn--2u2a.xn--5-uws5848bpf44e; [V6]; [V6] +B; xn--1uga7691f.xn--5-uws5848bpf44e; [C2 V6]; [C2 V6] # 襔.ⴜ5ê¡® +B; xn--2u2a.xn--5-r1g7167ipfw8d; [V6]; [V6] +B; xn--1uga7691f.xn--5-r1g7167ipfw8d; [C2 V6]; [C2 V6] # 襔.Ⴜ5ê¡® +T; 𐫜𑌼\u200D.婀; [B3 C2]; xn--ix9c26l.xn--q0s # 𐫜𑌼.婀 +N; 𐫜𑌼\u200D.婀; [B3 C2]; [B3 C2] # 𐫜𑌼.婀 +T; 𐫜𑌼\u200D.婀; [B3 C2]; xn--ix9c26l.xn--q0s # 𐫜𑌼.婀 +N; 𐫜𑌼\u200D.婀; [B3 C2]; [B3 C2] # 𐫜𑌼.婀 +B; xn--ix9c26l.xn--q0s; 𐫜𑌼.婀; xn--ix9c26l.xn--q0s +B; 𐫜𑌼.婀; ; xn--ix9c26l.xn--q0s +B; xn--1ugx063g1if.xn--q0s; [B3 C2]; [B3 C2] # 𐫜𑌼.婀 +B; 󠅽︒︒𐹯。⬳\u1A78; [B1 P1 V6]; [B1 P1 V6] # ︒︒𐹯.⬳᩸ +B; 󠅽。。𐹯。⬳\u1A78; [B1 A4_2]; [B1 A4_2] # ..𐹯.⬳᩸ +B; ..xn--no0d.xn--7of309e; [B1 A4_2]; [B1 A4_2] # ..𐹯.⬳᩸ +B; xn--y86ca186j.xn--7of309e; [B1 V6]; [B1 V6] # ︒︒𐹯.⬳᩸ +T; 𝟖ß.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +N; 𝟖ß.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +T; 8ß.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +N; 8ß.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +T; 8ß.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-ⴏ +N; 8ß.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-ⴏ +B; 8SS.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; 8ss.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-ⴏ +B; 8Ss.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; 8ss.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; 8ss.-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-ⴏ +B; 8SS.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; 8Ss.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; xn--8-qfa.-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-ⴏ +B; XN--8-QFA.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +B; Xn--8-Qfa.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +B; xn--8-qfa.-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-Ⴏ +T; 𝟖ß.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-ⴏ +N; 𝟖ß.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ß.-ⴏ +B; 𝟖SS.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +B; 𝟖ss.󠄐-\uDBDAⴏ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-ⴏ +B; 𝟖Ss.󠄐-\uDBDAႯ; [P1 V3 V6]; [P1 V3 V6 A3] # 8ss.-Ⴏ +T; -\u200D󠋟.\u200C𐹣Ⴅ; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V6] # -.𐹣Ⴅ +N; -\u200D󠋟.\u200C𐹣Ⴅ; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # -.𐹣Ⴅ +T; -\u200D󠋟.\u200C𐹣ⴅ; [B1 C1 C2 P1 V3 V6]; [B1 P1 V3 V6] # -.𐹣ⴅ +N; -\u200D󠋟.\u200C𐹣ⴅ; [B1 C1 C2 P1 V3 V6]; [B1 C1 C2 P1 V3 V6] # -.𐹣ⴅ +B; xn----s721m.xn--wkj1423e; [B1 V3 V6]; [B1 V3 V6] +B; xn----ugnv7071n.xn--0ugz32cgr0p; [B1 C1 C2 V3 V6]; [B1 C1 C2 V3 V6] # -.𐹣ⴅ +B; xn----s721m.xn--dnd9201k; [B1 V3 V6]; [B1 V3 V6] +B; xn----ugnv7071n.xn--dnd999e4j4p; [B1 C1 C2 V3 V6]; [B1 C1 C2 V3 V6] # -.𐹣Ⴅ +T; \uA9B9\u200D큷𻶡。₂; [C2 P1 V5 V6]; [P1 V5 V6] # ꦹ큷.2 +N; \uA9B9\u200D큷𻶡。₂; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ꦹ큷.2 +T; \uA9B9\u200D큷𻶡。₂; [C2 P1 V5 V6]; [P1 V5 V6] # ꦹ큷.2 +N; \uA9B9\u200D큷𻶡。₂; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ꦹ큷.2 +T; \uA9B9\u200D큷𻶡。2; [C2 P1 V5 V6]; [P1 V5 V6] # ꦹ큷.2 +N; \uA9B9\u200D큷𻶡。2; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ꦹ큷.2 +T; \uA9B9\u200D큷𻶡。2; [C2 P1 V5 V6]; [P1 V5 V6] # ꦹ큷.2 +N; \uA9B9\u200D큷𻶡。2; [C2 P1 V5 V6]; [C2 P1 V5 V6] # ꦹ큷.2 +B; xn--0m9as84e2e21c.2; [V5 V6]; [V5 V6] # ꦹ큷.2 +B; xn--1ug1435cfkyaoi04d.2; [C2 V5 V6]; [C2 V5 V6] # ꦹ큷.2 +B; \uDF4D.🄄𞯘; [B1 P1 V6]; [B1 P1 V6 A3] # .🄄 +B; \uDF4D.3,𞯘; [B1 P1 V6]; [B1 P1 V6 A3] # .3, +B; \uDF4D.xn--3,-tb22a; [B1 P1 V6]; [B1 P1 V6 A3] # .3, +B; \uDF4D.XN--3,-TB22A; [B1 P1 V6]; [B1 P1 V6 A3] # .3, +B; \uDF4D.Xn--3,-Tb22a; [B1 P1 V6]; [B1 P1 V6 A3] # .3, +B; \uDF4D.xn--3x6hx6f; [B1 P1 V6]; [B1 P1 V6 A3] # .🄄 +B; \uDF4D.XN--3X6HX6F; [B1 P1 V6]; [B1 P1 V6 A3] # .🄄 +B; \uDF4D.Xn--3X6hx6f; [B1 P1 V6]; [B1 P1 V6 A3] # .🄄 +B; 𝨖𐩙。\u06DD󀡶\uA8C5⒈; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𝨖.ꣅ⒈ +B; 𝨖𐩙。\u06DD󀡶\uA8C51.; [B1 P1 V5 V6]; [B1 P1 V5 V6] # 𝨖.ꣅ1. +B; xn--rt9cl956a.xn--1-dxc8545j0693i.; [B1 V5 V6]; [B1 V5 V6] # 𝨖.ꣅ1. +B; xn--rt9cl956a.xn--tlb403mxv4g06s9i; [B1 V5 V6]; [B1 V5 V6] # 𝨖.ꣅ⒈ +T; ò’ˆ£\u05E1\u06B8。Ⴈ\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # סڸ.Ⴈ +N; ò’ˆ£\u05E1\u06B8。Ⴈ\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # סڸ.Ⴈ +T; ò’ˆ£\u05E1\u06B8。ⴈ\u200D; [B5 B6 C2 P1 V6]; [B5 B6 P1 V6] # סڸ.ⴈ +N; ò’ˆ£\u05E1\u06B8。ⴈ\u200D; [B5 B6 C2 P1 V6]; [B5 B6 C2 P1 V6] # סڸ.ⴈ +B; xn--meb44b57607c.xn--zkj; [B5 B6 V6]; [B5 B6 V6] # סڸ.ⴈ +B; xn--meb44b57607c.xn--1ug232c; [B5 B6 C2 V6]; [B5 B6 C2 V6] # סڸ.ⴈ +B; xn--meb44b57607c.xn--gnd; [B5 B6 V6]; [B5 B6 V6] # סڸ.Ⴈ +B; xn--meb44b57607c.xn--gnd699e; [B5 B6 C2 V6]; [B5 B6 C2 V6] # סڸ.Ⴈ +T; 󀚶𝨱\u07E6⒈.𑗝髯\u200C; [B1 B5 C1 P1 V5 V6]; [B1 B5 P1 V5 V6] # 𝨱ߦ⒈.𑗝髯 +N; 󀚶𝨱\u07E6⒈.𑗝髯\u200C; [B1 B5 C1 P1 V5 V6]; [B1 B5 C1 P1 V5 V6] # 𝨱ߦ⒈.𑗝髯 +T; 󀚶𝨱\u07E61..𑗝髯\u200C; [B1 B5 C1 P1 V5 V6 A4_2]; [B1 B5 P1 V5 V6 A4_2] # 𝨱ߦ1..𑗝髯 +N; 󀚶𝨱\u07E61..𑗝髯\u200C; [B1 B5 C1 P1 V5 V6 A4_2]; [B1 B5 C1 P1 V5 V6 A4_2] # 𝨱ߦ1..𑗝髯 +B; xn--1-idd62296a1fr6e..xn--uj6at43v; [B1 B5 V5 V6 A4_2]; [B1 B5 V5 V6 A4_2] # 𝨱ߦ1..𑗝髯 +B; xn--1-idd62296a1fr6e..xn--0ugx259bocxd; [B1 B5 C1 V5 V6 A4_2]; [B1 B5 C1 V5 V6 A4_2] # 𝨱ߦ1..𑗝髯 +B; xn--etb477lq931a1f58e.xn--uj6at43v; [B1 B5 V5 V6]; [B1 B5 V5 V6] # 𝨱ߦ⒈.𑗝髯 +B; xn--etb477lq931a1f58e.xn--0ugx259bocxd; [B1 B5 C1 V5 V6]; [B1 B5 C1 V5 V6] # 𝨱ߦ⒈.𑗝髯 +B; 𐫀.\u0689𑌀; 𐫀.\u0689𑌀; xn--pw9c.xn--fjb8658k # 𐫀.ډ𑌀 +B; 𐫀.\u0689𑌀; ; xn--pw9c.xn--fjb8658k # 𐫀.ډ𑌀 +B; xn--pw9c.xn--fjb8658k; 𐫀.\u0689𑌀; xn--pw9c.xn--fjb8658k # 𐫀.ډ𑌀 +B; 𑋪.𐳝; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; 𑋪.𐳝; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; 𑋪.𐲝; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; xn--fm1d.xn--5c0d; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; 𑋪.𐲝; [B1 B3 B6 V5]; [B1 B3 B6 V5] +B; ≠膣。\u0F83; [P1 V5 V6]; [P1 V5 V6] # ≠膣.ྃ +B; =\u0338膣。\u0F83; [P1 V5 V6]; [P1 V5 V6] # ≠膣.ྃ +B; xn--1chy468a.xn--2ed; [V5 V6]; [V5 V6] # ≠膣.ྃ +T; ñ°€Ž-\u077D。ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ß +N; ñ°€Ž-\u077D。ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ß +T; ñ°€Ž-\u077D。ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ß +N; ñ°€Ž-\u077D。ß; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ß +B; ñ°€Ž-\u077D。SS; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +B; ñ°€Ž-\u077D。ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +B; ñ°€Ž-\u077D。Ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +B; xn----j6c95618k.ss; [B5 B6 V6]; [B5 B6 V6] # -ݽ.ss +B; xn----j6c95618k.xn--zca; [B5 B6 V6]; [B5 B6 V6] # -ݽ.ß +B; ñ°€Ž-\u077D。SS; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +B; ñ°€Ž-\u077D。ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +B; ñ°€Ž-\u077D。Ss; [B5 B6 P1 V6]; [B5 B6 P1 V6] # -ݽ.ss +T; ς𐹠ᡚ𑄳.⾭𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +N; ς𐹠ᡚ𑄳.⾭𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +T; ς𐹠ᡚ𑄳.靑𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +N; ς𐹠ᡚ𑄳.靑𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; Σ𐹠ᡚ𑄳.靑𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; σ𐹠ᡚ𑄳.靑𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; xn--4xa656hp23pxmc.xn--es5a888tvjc2u15h; [B5 B6 V6]; [B5 B6 V6] +B; xn--3xa856hp23pxmc.xn--es5a888tvjc2u15h; [B5 B6 V6]; [B5 B6 V6] +B; Σ𐹠ᡚ𑄳.⾭𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +B; σ𐹠ᡚ𑄳.⾭𐹽𽐖𐫜; [B5 B6 P1 V6]; [B5 B6 P1 V6] +T; 𐋷。\u200D; [C2]; xn--r97c. # 𐋷. +N; 𐋷。\u200D; [C2]; [C2] # 𐋷. +B; xn--r97c.; 𐋷.; xn--r97c.; NV8 +B; 𐋷.; ; xn--r97c.; NV8 +B; xn--r97c.xn--1ug; [C2]; [C2] # 𐋷. +B; 𑰳𑈯。⥪; [V5]; [V5] +B; xn--2g1d14o.xn--jti; [V5]; [V5] +T; 𑆀䁴ñ¤§£ï¼Žá‚µðŸœ\u200C\u0348; [C1 P1 V5 V6]; [P1 V5 V6] # 𑆀䁴.Ⴕ4͈ +N; 𑆀䁴ñ¤§£ï¼Žá‚µðŸœ\u200C\u0348; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 𑆀䁴.Ⴕ4͈ +T; 𑆀䁴ñ¤§£.Ⴕ4\u200C\u0348; [C1 P1 V5 V6]; [P1 V5 V6] # 𑆀䁴.Ⴕ4͈ +N; 𑆀䁴ñ¤§£.Ⴕ4\u200C\u0348; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 𑆀䁴.Ⴕ4͈ +T; 𑆀䁴ñ¤§£.ⴕ4\u200C\u0348; [C1 P1 V5 V6]; [P1 V5 V6] # 𑆀䁴.ⴕ4͈ +N; 𑆀䁴ñ¤§£.ⴕ4\u200C\u0348; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 𑆀䁴.ⴕ4͈ +B; xn--1mnx647cg3x1b.xn--4-zfb5123a; [V5 V6]; [V5 V6] # 𑆀䁴.ⴕ4͈ +B; xn--1mnx647cg3x1b.xn--4-zfb502tlsl; [C1 V5 V6]; [C1 V5 V6] # 𑆀䁴.ⴕ4͈ +B; xn--1mnx647cg3x1b.xn--4-zfb324h; [V5 V6]; [V5 V6] # 𑆀䁴.Ⴕ4͈ +B; xn--1mnx647cg3x1b.xn--4-zfb324h32o; [C1 V5 V6]; [C1 V5 V6] # 𑆀䁴.Ⴕ4͈ +T; 𑆀䁴ñ¤§£ï¼Žâ´•𝟜\u200C\u0348; [C1 P1 V5 V6]; [P1 V5 V6] # 𑆀䁴.ⴕ4͈ +N; 𑆀䁴ñ¤§£ï¼Žâ´•𝟜\u200C\u0348; [C1 P1 V5 V6]; [C1 P1 V5 V6] # 𑆀䁴.ⴕ4͈ +T; 憡\uDF1F\u200CႴ.𐋮\u200D≠; [C1 C2 P1 V6]; [P1 V6 A3] # 憡Ⴔ.𐋮≠ +N; 憡\uDF1F\u200CႴ.𐋮\u200D≠; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +T; 憡\uDF1F\u200CႴ.𐋮\u200D=\u0338; [C1 C2 P1 V6]; [P1 V6 A3] # 憡Ⴔ.𐋮≠ +N; 憡\uDF1F\u200CႴ.𐋮\u200D=\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +T; 憡\uDF1F\u200Cⴔ.𐋮\u200D=\u0338; [C1 C2 P1 V6]; [P1 V6 A3] # 憡ⴔ.𐋮≠ +N; 憡\uDF1F\u200Cⴔ.𐋮\u200D=\u0338; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡ⴔ.𐋮≠ +T; 憡\uDF1F\u200Cⴔ.𐋮\u200D≠; [C1 C2 P1 V6]; [P1 V6 A3] # 憡ⴔ.𐋮≠ +N; 憡\uDF1F\u200Cⴔ.𐋮\u200D≠; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡ⴔ.𐋮≠ +B; 憡\uDF1Fⴔ.xn--1chz659f; [P1 V6]; [P1 V6 A3] # 憡ⴔ.𐋮≠ +B; 憡\uDF1FႴ.XN--1CHZ659F; [P1 V6]; [P1 V6 A3] # 憡Ⴔ.𐋮≠ +B; 憡\uDF1FႴ.xn--1Chz659f; [P1 V6]; [P1 V6 A3] # 憡Ⴔ.𐋮≠ +B; 憡\uDF1FႴ.xn--1chz659f; [P1 V6]; [P1 V6 A3] # 憡Ⴔ.𐋮≠ +T; 憡\uDF1F\u200Cⴔ.xn--1ug73gl146a; [C1 C2 P1 V6]; [C2 P1 V6 A3] # 憡ⴔ.𐋮≠ +N; 憡\uDF1F\u200Cⴔ.xn--1ug73gl146a; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡ⴔ.𐋮≠ +T; 憡\uDF1F\u200CႴ.XN--1UG73GL146A; [C1 C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +N; 憡\uDF1F\u200CႴ.XN--1UG73GL146A; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +T; 憡\uDF1F\u200CႴ.xn--1Ug73gl146a; [C1 C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +N; 憡\uDF1F\u200CႴ.xn--1Ug73gl146a; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +B; 憡\uDF1FႴ.xn--1ug73gl146a; [C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +B; 憡\uDF1Fⴔ.xn--1ug73gl146a; [C2 P1 V6]; [C2 P1 V6 A3] # 憡ⴔ.𐋮≠ +B; 憡\uDF1FႴ.XN--1UG73GL146A; [C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +B; 憡\uDF1FႴ.xn--1Ug73gl146a; [C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +T; 憡\uDF1F\u200CႴ.xn--1ug73gl146a; [C1 C2 P1 V6]; [C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ +N; 憡\uDF1F\u200CႴ.xn--1ug73gl146a; [C1 C2 P1 V6]; [C1 C2 P1 V6 A3] # 憡Ⴔ.𐋮≠ diff --git a/idna/tests/punycode.rs b/idna/tests/punycode.rs new file mode 100644 index 000000000..67988e80c --- /dev/null +++ b/idna/tests/punycode.rs @@ -0,0 +1,65 @@ +// Copyright 2013 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use idna::punycode::{decode, encode_str}; +use rustc_serialize::json::{Json, Object}; +use test::TestFn; + +fn one_test(decoded: &str, encoded: &str) { + match decode(encoded) { + None => panic!("Decoding {} failed.", encoded), + Some(result) => { + let result = result.into_iter().collect::(); + assert!(result == decoded, + format!("Incorrect decoding of \"{}\":\n \"{}\"\n!= \"{}\"\n", + encoded, result, decoded)) + } + } + + match encode_str(decoded) { + None => panic!("Encoding {} failed.", decoded), + Some(result) => { + assert!(result == encoded, + format!("Incorrect encoding of \"{}\":\n \"{}\"\n!= \"{}\"\n", + decoded, result, encoded)) + } + } +} + +fn get_string<'a>(map: &'a Object, key: &str) -> &'a str { + match map.get(&key.to_string()) { + Some(&Json::String(ref s)) => s, + None => "", + _ => panic!(), + } +} + +pub fn collect_tests(add_test: &mut F) { + match Json::from_str(include_str!("punycode_tests.json")) { + Ok(Json::Array(tests)) => for (i, test) in tests.into_iter().enumerate() { + match test { + Json::Object(o) => { + let test_name = { + let desc = get_string(&o, "description"); + if desc.is_empty() { + format!("Punycode {}", i + 1) + } else { + format!("Punycode {}: {}", i + 1, desc) + } + }; + add_test(test_name, TestFn::dyn_test_fn(move || one_test( + get_string(&o, "decoded"), + get_string(&o, "encoded"), + ))) + } + _ => panic!(), + } + }, + other => panic!("{:?}", other) + } +} diff --git a/idna/tests/punycode_tests.json b/idna/tests/punycode_tests.json new file mode 100644 index 000000000..86785b124 --- /dev/null +++ b/idna/tests/punycode_tests.json @@ -0,0 +1,120 @@ +[ +{ + "description": "These tests are copied from https://github.com/bestiejs/punycode.js/blob/master/tests/tests.js , used under the MIT license.", + "decoded": "", + "encoded": "" +}, +{ + "description": "a single basic code point", + "decoded": "Bach", + "encoded": "Bach-" +}, +{ + "description": "a single non-ASCII character", + "decoded": "\u00FC", + "encoded": "tda" +}, +{ + "description": "multiple non-ASCII characters", + "decoded": "\u00FC\u00EB\u00E4\u00F6\u2665", + "encoded": "4can8av2009b" +}, +{ + "description": "mix of ASCII and non-ASCII characters", + "decoded": "b\u00FCcher", + "encoded": "bcher-kva" +}, +{ + "description": "long string with both ASCII and non-ASCII characters", + "decoded": "Willst du die Bl\u00FCthe des fr\u00FChen, die Fr\u00FCchte des sp\u00E4teren Jahres", + "encoded": "Willst du die Blthe des frhen, die Frchte des spteren Jahres-x9e96lkal" +}, +{ + "description": "Arabic (Egyptian)", + "decoded": "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F", + "encoded": "egbpdaj6bu4bxfgehfvwxn" +}, +{ + "description": "Chinese (simplified)", + "decoded": "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2d\u6587", + "encoded": "ihqwcrb4cv8a8dqg056pqjye" +}, +{ + "description": "Chinese (traditional)", + "decoded": "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587", + "encoded": "ihqwctvzc91f659drss3x8bo0yb" +}, +{ + "description": "Czech", + "decoded": "Pro\u010Dprost\u011Bnemluv\u00ED\u010Desky", + "encoded": "Proprostnemluvesky-uyb24dma41a" +}, +{ + "description": "Hebrew", + "decoded": "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2\u05D1\u05E8\u05D9\u05EA", + "encoded": "4dbcagdahymbxekheh6e0a7fei0b" +}, +{ + "description": "Hindi (Devanagari)", + "decoded": "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947\u0939\u0948\u0902", + "encoded": "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd" +}, +{ + "description": "Japanese (kanji and hiragana)", + "decoded": "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B", + "encoded": "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa" +}, +{ + "description": "Korean (Hangul syllables)", + "decoded": "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C", + "encoded": "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c" +}, +{ + "description": "Russian (Cyrillic)", + "decoded": "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A\u0438", + "encoded": "b1abfaaepdrnnbgefbadotcwatmq2g4l" +}, +{ + "description": "Spanish", + "decoded": "Porqu\u00E9nopuedensimplementehablarenEspa\u00F1ol", + "encoded": "PorqunopuedensimplementehablarenEspaol-fmd56a" +}, +{ + "description": "Vietnamese", + "decoded": "T\u1EA1isaoh\u1ECDkh\u00F4ngth\u1EC3ch\u1EC9n\u00F3iti\u1EBFngVi\u1EC7t", + "encoded": "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g" +}, +{ + "decoded": "3\u5E74B\u7D44\u91D1\u516B\u5148\u751F", + "encoded": "3B-ww4c5e180e575a65lsy2b" +}, +{ + "decoded": "\u5B89\u5BA4\u5948\u7F8E\u6075-with-SUPER-MONKEYS", + "encoded": "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n" +}, +{ + "decoded": "Hello-Another-Way-\u305D\u308C\u305E\u308C\u306E\u5834\u6240", + "encoded": "Hello-Another-Way--fc4qua05auwb3674vfr0b" +}, +{ + "decoded": "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B2", + "encoded": "2-u9tlzr9756bt3uc0v" +}, +{ + "decoded": "Maji\u3067Koi\u3059\u308B5\u79D2\u524D", + "encoded": "MajiKoi5-783gue6qz075azm5e" +}, +{ + "decoded": "\u30D1\u30D5\u30A3\u30FCde\u30EB\u30F3\u30D0", + "encoded": "de-jg4avhby1noc0d" +}, +{ + "decoded": "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067", + "encoded": "d9juau41awczczp" +}, +{ + "description": "ASCII string that breaks the existing rules for host-name labels (It's not a realistic example for IDNA, because IDNA never encodes pure ASCII labels.)", + "decoded": "-> $1.00 <-", + "encoded": "-> $1.00 <--" +} +] diff --git a/idna/tests/tests.rs b/idna/tests/tests.rs new file mode 100644 index 000000000..808ad6ba8 --- /dev/null +++ b/idna/tests/tests.rs @@ -0,0 +1,21 @@ +extern crate idna; +extern crate rustc_serialize; +extern crate rustc_test as test; + +mod punycode; +mod uts46; + +fn main() { + let mut tests = Vec::new(); + { + let mut add_test = |name, run| { + tests.push(test::TestDescAndFn { + desc: test::TestDesc::new(test::DynTestName(name)), + testfn: run, + }) + }; + punycode::collect_tests(&mut add_test); + uts46::collect_tests(&mut add_test); + } + test::test_main(&std::env::args().collect::>(), tests) +} diff --git a/idna/tests/unit.rs b/idna/tests/unit.rs new file mode 100644 index 000000000..a7d158d5c --- /dev/null +++ b/idna/tests/unit.rs @@ -0,0 +1,40 @@ +extern crate idna; +extern crate unicode_normalization; + +use idna::uts46; +use unicode_normalization::char::is_combining_mark; + + +fn _to_ascii(domain: &str) -> Result { + uts46::to_ascii(domain, uts46::Flags { + transitional_processing: false, + use_std3_ascii_rules: true, + verify_dns_length: true, + }) +} + +#[test] +fn test_v5() { + // IdnaTest:784 蔏。𑰺 + assert!(is_combining_mark('\u{11C3A}')); + assert!(_to_ascii("\u{11C3A}").is_err()); + assert!(_to_ascii("\u{850f}.\u{11C3A}").is_err()); + assert!(_to_ascii("\u{850f}\u{ff61}\u{11C3A}").is_err()); +} + +#[test] +fn test_v8_bidi_rules() { + assert_eq!(_to_ascii("abc").unwrap(), "abc"); + assert_eq!(_to_ascii("123").unwrap(), "123"); + assert_eq!(_to_ascii("אבּג").unwrap(), "xn--kdb3bdf"); + assert_eq!(_to_ascii("ابج").unwrap(), "xn--mgbcm"); + assert_eq!(_to_ascii("abc.ابج").unwrap(), "abc.xn--mgbcm"); + assert_eq!(_to_ascii("אבּג.ابج").unwrap(), "xn--kdb3bdf.xn--mgbcm"); + + // Bidi domain names cannot start with digits + assert!(_to_ascii("0a.\u{05D0}").is_err()); + assert!(_to_ascii("0à.\u{05D0}").is_err()); + + // Bidi chars may be punycode-encoded + assert!(_to_ascii("xn--0ca24w").is_err()); +} diff --git a/idna/tests/uts46.rs b/idna/tests/uts46.rs new file mode 100644 index 000000000..59ec1cd76 --- /dev/null +++ b/idna/tests/uts46.rs @@ -0,0 +1,124 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::char; +use idna::uts46; +use test::TestFn; + +pub fn collect_tests(add_test: &mut F) { + // http://www.unicode.org/Public/idna/latest/IdnaTest.txt + for (i, line) in include_str!("IdnaTest.txt").lines().enumerate() { + if line == "" || line.starts_with("#") { + continue + } + // Remove comments + let mut line = match line.find("#") { + Some(index) => &line[0..index], + None => line + }; + + let mut expected_failure = false; + if line.starts_with("XFAIL") { + expected_failure = true; + line = &line[5..line.len()]; + }; + + let mut pieces = line.split(';').map(|x| x.trim()).collect::>(); + + let test_type = pieces.remove(0); + let original = pieces.remove(0); + let source = unescape(original); + let to_unicode = pieces.remove(0); + let to_ascii = pieces.remove(0); + let nv8 = if pieces.len() > 0 { pieces.remove(0) } else { "" }; + + if expected_failure { + continue; + } + + let test_name = format!("UTS #46 line {}", i + 1); + add_test(test_name, TestFn::dyn_test_fn(move || { + let result = uts46::to_ascii(&source, uts46::Flags { + use_std3_ascii_rules: true, + transitional_processing: test_type == "T", + verify_dns_length: true, + }); + + if to_ascii.starts_with("[") { + if to_ascii.starts_with("[C") { + // http://unicode.org/reports/tr46/#Deviations + // applications that perform IDNA2008 lookup are not required to check + // for these contexts + return; + } + if to_ascii == "[V2]" { + // Everybody ignores V2 + // https://github.com/servo/rust-url/pull/240 + // https://github.com/whatwg/url/issues/53#issuecomment-181528158 + // http://www.unicode.org/review/pri317/ + return; + } + let res = result.ok(); + assert!(res == None, "Expected error. result: {} | original: {} | source: {}", + res.unwrap(), original, source); + return; + } + + let to_ascii = if to_ascii.len() > 0 { + to_ascii.to_string() + } else { + if to_unicode.len() > 0 { + to_unicode.to_string() + } else { + source.clone() + } + }; + + if nv8 == "NV8" { + // This result isn't valid under IDNA2008. Skip it + return; + } + + assert!(result.is_ok(), "Couldn't parse {} | original: {} | error: {:?}", + source, original, result.err()); + let output = result.ok().unwrap(); + assert!(output == to_ascii, "result: {} | expected: {} | original: {} | source: {}", + output, to_ascii, original, source); + })) + } +} + +fn unescape(input: &str) -> String { + let mut output = String::new(); + let mut chars = input.chars(); + loop { + match chars.next() { + None => return output, + Some(c) => + if c == '\\' { + match chars.next().unwrap() { + '\\' => output.push('\\'), + 'u' => { + let c1 = chars.next().unwrap().to_digit(16).unwrap(); + let c2 = chars.next().unwrap().to_digit(16).unwrap(); + let c3 = chars.next().unwrap().to_digit(16).unwrap(); + let c4 = chars.next().unwrap().to_digit(16).unwrap(); + match char::from_u32(((c1 * 16 + c2) * 16 + c3) * 16 + c4) + { + Some(c) => output.push(c), + None => { output.push_str(&format!("\\u{:X}{:X}{:X}{:X}",c1,c2,c3,c4)); } + }; + } + _ => panic!("Invalid test data input"), + } + } else { + output.push(c); + } + } + } +} diff --git a/ignore/.cargo-checksum.json b/ignore/.cargo-checksum.json new file mode 100644 index 000000000..b064f7270 --- /dev/null +++ b/ignore/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002"} \ No newline at end of file diff --git a/ignore/COPYING b/ignore/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/ignore/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/ignore/Cargo.toml b/ignore/Cargo.toml new file mode 100644 index 000000000..30c863e29 --- /dev/null +++ b/ignore/Cargo.toml @@ -0,0 +1,60 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "ignore" +version = "0.4.7" +authors = ["Andrew Gallant "] +description = "A fast library for efficiently matching ignore files such as `.gitignore`\nagainst file paths.\n" +homepage = "https://github.com/BurntSushi/ripgrep/tree/master/ignore" +documentation = "https://docs.rs/ignore" +readme = "README.md" +keywords = ["glob", "ignore", "gitignore", "pattern", "file"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/ripgrep/tree/master/ignore" + +[lib] +name = "ignore" +bench = false +[dependencies.crossbeam-channel] +version = "0.3.6" + +[dependencies.globset] +version = "0.4.3" + +[dependencies.lazy_static] +version = "1.1" + +[dependencies.log] +version = "0.4.5" + +[dependencies.memchr] +version = "2.1" + +[dependencies.regex] +version = "1.1" + +[dependencies.same-file] +version = "1.0.4" + +[dependencies.thread_local] +version = "0.3.6" + +[dependencies.walkdir] +version = "2.2.7" +[dev-dependencies.tempfile] +version = "3.0.5" + +[features] +simd-accel = ["globset/simd-accel"] +[target."cfg(windows)".dependencies.winapi-util] +version = "0.1.2" diff --git a/ignore/LICENSE-MIT b/ignore/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/ignore/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ignore/README.md b/ignore/README.md new file mode 100644 index 000000000..b0e659a9c --- /dev/null +++ b/ignore/README.md @@ -0,0 +1,66 @@ +ignore +====== +The ignore crate provides a fast recursive directory iterator that respects +various filters such as globs, file types and `.gitignore` files. This crate +also provides lower level direct access to gitignore and file type matchers. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.svg)](https://travis-ci.org/BurntSushi/ripgrep) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) +[![](https://img.shields.io/crates/v/ignore.svg)](https://crates.io/crates/ignore) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +[https://docs.rs/ignore](https://docs.rs/ignore) + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +ignore = "0.4" +``` + +and this to your crate root: + +```rust +extern crate ignore; +``` + +### Example + +This example shows the most basic usage of this crate. This code will +recursively traverse the current directory while automatically filtering out +files and directories according to ignore globs found in files like +`.ignore` and `.gitignore`: + + +```rust,no_run +use ignore::Walk; + +for result in Walk::new("./") { + // Each item yielded by the iterator is either a directory entry or an + // error, so either print the path or the error. + match result { + Ok(entry) => println!("{}", entry.path().display()), + Err(err) => println!("ERROR: {}", err), + } +} +``` + +### Example: advanced + +By default, the recursive directory iterator will ignore hidden files and +directories. This can be disabled by building the iterator with `WalkBuilder`: + +```rust,no_run +use ignore::WalkBuilder; + +for result in WalkBuilder::new("./").hidden(false).build() { + println!("{:?}", result); +} +``` + +See the documentation for `WalkBuilder` for many other options. diff --git a/ignore/UNLICENSE b/ignore/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/ignore/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/ignore/examples/walk.rs b/ignore/examples/walk.rs new file mode 100644 index 000000000..1f2a3cea9 --- /dev/null +++ b/ignore/examples/walk.rs @@ -0,0 +1,84 @@ +extern crate crossbeam_channel as channel; +extern crate ignore; +extern crate walkdir; + +use std::env; +use std::io::{self, Write}; +use std::path::Path; +use std::thread; + +use ignore::WalkBuilder; +use walkdir::WalkDir; + +fn main() { + let mut path = env::args().nth(1).unwrap(); + let mut parallel = false; + let mut simple = false; + let (tx, rx) = channel::bounded::(100); + if path == "parallel" { + path = env::args().nth(2).unwrap(); + parallel = true; + } else if path == "walkdir" { + path = env::args().nth(2).unwrap(); + simple = true; + } + + let stdout_thread = thread::spawn(move || { + let mut stdout = io::BufWriter::new(io::stdout()); + for dent in rx { + write_path(&mut stdout, dent.path()); + } + }); + + if parallel { + let walker = WalkBuilder::new(path).threads(6).build_parallel(); + walker.run(|| { + let tx = tx.clone(); + Box::new(move |result| { + use ignore::WalkState::*; + + tx.send(DirEntry::Y(result.unwrap())).unwrap(); + Continue + }) + }); + } else if simple { + let walker = WalkDir::new(path); + for result in walker { + tx.send(DirEntry::X(result.unwrap())).unwrap(); + } + } else { + let walker = WalkBuilder::new(path).build(); + for result in walker { + tx.send(DirEntry::Y(result.unwrap())).unwrap(); + } + } + drop(tx); + stdout_thread.join().unwrap(); +} + +enum DirEntry { + X(walkdir::DirEntry), + Y(ignore::DirEntry), +} + +impl DirEntry { + fn path(&self) -> &Path { + match *self { + DirEntry::X(ref x) => x.path(), + DirEntry::Y(ref y) => y.path(), + } + } +} + +#[cfg(unix)] +fn write_path(mut wtr: W, path: &Path) { + use std::os::unix::ffi::OsStrExt; + wtr.write(path.as_os_str().as_bytes()).unwrap(); + wtr.write(b"\n").unwrap(); +} + +#[cfg(not(unix))] +fn write_path(mut wtr: W, path: &Path) { + wtr.write(path.to_string_lossy().as_bytes()).unwrap(); + wtr.write(b"\n").unwrap(); +} diff --git a/ignore/src/dir.rs b/ignore/src/dir.rs new file mode 100644 index 000000000..be2b8351c --- /dev/null +++ b/ignore/src/dir.rs @@ -0,0 +1,993 @@ +// This module provides a data structure, `Ignore`, that connects "directory +// traversal" with "ignore matchers." Specifically, it knows about gitignore +// semantics and precedence, and is organized based on directory hierarchy. +// Namely, every matcher logically corresponds to ignore rules from a single +// directory, and points to the matcher for its corresponding parent directory. +// In this sense, `Ignore` is a *persistent* data structure. +// +// This design was specifically chosen to make it possible to use this data +// structure in a parallel directory iterator. +// +// My initial intention was to expose this module as part of this crate's +// public API, but I think the data structure's public API is too complicated +// with non-obvious failure modes. Alas, such things haven't been documented +// well. + +use std::collections::HashMap; +use std::ffi::{OsString, OsStr}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, RwLock}; + +use gitignore::{self, Gitignore, GitignoreBuilder}; +use pathutil::{is_hidden, strip_prefix}; +use overrides::{self, Override}; +use types::{self, Types}; +use walk::DirEntry; +use {Error, Match, PartialErrorBuilder}; + +/// IgnoreMatch represents information about where a match came from when using +/// the `Ignore` matcher. +#[derive(Clone, Debug)] +pub struct IgnoreMatch<'a>(IgnoreMatchInner<'a>); + +/// IgnoreMatchInner describes precisely where the match information came from. +/// This is private to allow expansion to more matchers in the future. +#[derive(Clone, Debug)] +enum IgnoreMatchInner<'a> { + Override(overrides::Glob<'a>), + Gitignore(&'a gitignore::Glob), + Types(types::Glob<'a>), + Hidden, +} + +impl<'a> IgnoreMatch<'a> { + fn overrides(x: overrides::Glob<'a>) -> IgnoreMatch<'a> { + IgnoreMatch(IgnoreMatchInner::Override(x)) + } + + fn gitignore(x: &'a gitignore::Glob) -> IgnoreMatch<'a> { + IgnoreMatch(IgnoreMatchInner::Gitignore(x)) + } + + fn types(x: types::Glob<'a>) -> IgnoreMatch<'a> { + IgnoreMatch(IgnoreMatchInner::Types(x)) + } + + fn hidden() -> IgnoreMatch<'static> { + IgnoreMatch(IgnoreMatchInner::Hidden) + } +} + +/// Options for the ignore matcher, shared between the matcher itself and the +/// builder. +#[derive(Clone, Copy, Debug)] +struct IgnoreOptions { + /// Whether to ignore hidden file paths or not. + hidden: bool, + /// Whether to read .ignore files. + ignore: bool, + /// Whether to respect any ignore files in parent directories. + parents: bool, + /// Whether to read git's global gitignore file. + git_global: bool, + /// Whether to read .gitignore files. + git_ignore: bool, + /// Whether to read .git/info/exclude files. + git_exclude: bool, + /// Whether to ignore files case insensitively + ignore_case_insensitive: bool, +} + +/// Ignore is a matcher useful for recursively walking one or more directories. +#[derive(Clone, Debug)] +pub struct Ignore(Arc); + +#[derive(Clone, Debug)] +struct IgnoreInner { + /// A map of all existing directories that have already been + /// compiled into matchers. + /// + /// Note that this is never used during matching, only when adding new + /// parent directory matchers. This avoids needing to rebuild glob sets for + /// parent directories if many paths are being searched. + compiled: Arc>>, + /// The path to the directory that this matcher was built from. + dir: PathBuf, + /// An override matcher (default is empty). + overrides: Arc, + /// A file type matcher. + types: Arc, + /// The parent directory to match next. + /// + /// If this is the root directory or there are otherwise no more + /// directories to match, then `parent` is `None`. + parent: Option, + /// Whether this is an absolute parent matcher, as added by add_parent. + is_absolute_parent: bool, + /// The absolute base path of this matcher. Populated only if parent + /// directories are added. + absolute_base: Option>, + /// Explicit global ignore matchers specified by the caller. + explicit_ignores: Arc>, + /// Ignore files used in addition to `.ignore` + custom_ignore_filenames: Arc>, + /// The matcher for custom ignore files + custom_ignore_matcher: Gitignore, + /// The matcher for .ignore files. + ignore_matcher: Gitignore, + /// A global gitignore matcher, usually from $XDG_CONFIG_HOME/git/ignore. + git_global_matcher: Arc, + /// The matcher for .gitignore files. + git_ignore_matcher: Gitignore, + /// Special matcher for `.git/info/exclude` files. + git_exclude_matcher: Gitignore, + /// Whether this directory contains a .git sub-directory. + has_git: bool, + /// Ignore config. + opts: IgnoreOptions, +} + +impl Ignore { + /// Return the directory path of this matcher. + pub fn path(&self) -> &Path { + &self.0.dir + } + + /// Return true if this matcher has no parent. + pub fn is_root(&self) -> bool { + self.0.parent.is_none() + } + + /// Returns true if this matcher was added via the `add_parents` method. + pub fn is_absolute_parent(&self) -> bool { + self.0.is_absolute_parent + } + + /// Return this matcher's parent, if one exists. + pub fn parent(&self) -> Option { + self.0.parent.clone() + } + + /// Create a new `Ignore` matcher with the parent directories of `dir`. + /// + /// Note that this can only be called on an `Ignore` matcher with no + /// parents (i.e., `is_root` returns `true`). This will panic otherwise. + pub fn add_parents>( + &self, + path: P, + ) -> (Ignore, Option) { + if !self.0.opts.parents + && !self.0.opts.git_ignore + && !self.0.opts.git_exclude + && !self.0.opts.git_global + { + // If we never need info from parent directories, then don't do + // anything. + return (self.clone(), None); + } + if !self.is_root() { + panic!("Ignore::add_parents called on non-root matcher"); + } + let absolute_base = match path.as_ref().canonicalize() { + Ok(path) => Arc::new(path), + Err(_) => { + // There's not much we can do here, so just return our + // existing matcher. We drop the error to be consistent + // with our general pattern of ignoring I/O errors when + // processing ignore files. + return (self.clone(), None); + } + }; + // List of parents, from child to root. + let mut parents = vec![]; + let mut path = &**absolute_base; + while let Some(parent) = path.parent() { + parents.push(parent); + path = parent; + } + let mut errs = PartialErrorBuilder::default(); + let mut ig = self.clone(); + for parent in parents.into_iter().rev() { + let mut compiled = self.0.compiled.write().unwrap(); + if let Some(prebuilt) = compiled.get(parent.as_os_str()) { + ig = prebuilt.clone(); + continue; + } + let (mut igtmp, err) = ig.add_child_path(parent); + errs.maybe_push(err); + igtmp.is_absolute_parent = true; + igtmp.absolute_base = Some(absolute_base.clone()); + igtmp.has_git = parent.join(".git").exists(); + ig = Ignore(Arc::new(igtmp)); + compiled.insert(parent.as_os_str().to_os_string(), ig.clone()); + } + (ig, errs.into_error_option()) + } + + /// Create a new `Ignore` matcher for the given child directory. + /// + /// Since building the matcher may require reading from multiple + /// files, it's possible that this method partially succeeds. Therefore, + /// a matcher is always returned (which may match nothing) and an error is + /// returned if it exists. + /// + /// Note that all I/O errors are completely ignored. + pub fn add_child>( + &self, + dir: P, + ) -> (Ignore, Option) { + let (ig, err) = self.add_child_path(dir.as_ref()); + (Ignore(Arc::new(ig)), err) + } + + /// Like add_child, but takes a full path and returns an IgnoreInner. + fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option) { + let mut errs = PartialErrorBuilder::default(); + let custom_ig_matcher = + if self.0.custom_ignore_filenames.is_empty() { + Gitignore::empty() + } else { + let (m, err) = + create_gitignore( + &dir, + &self.0.custom_ignore_filenames, + self.0.opts.ignore_case_insensitive, + ); + errs.maybe_push(err); + m + }; + let ig_matcher = + if !self.0.opts.ignore { + Gitignore::empty() + } else { + let (m, err) = + create_gitignore( + &dir, + &[".ignore"], + self.0.opts.ignore_case_insensitive, + ); + errs.maybe_push(err); + m + }; + let gi_matcher = + if !self.0.opts.git_ignore { + Gitignore::empty() + } else { + let (m, err) = + create_gitignore( + &dir, + &[".gitignore"], + self.0.opts.ignore_case_insensitive, + ); + errs.maybe_push(err); + m + }; + let gi_exclude_matcher = + if !self.0.opts.git_exclude { + Gitignore::empty() + } else { + let (m, err) = + create_gitignore( + &dir, + &[".git/info/exclude"], + self.0.opts.ignore_case_insensitive, + ); + errs.maybe_push(err); + m + }; + let ig = IgnoreInner { + compiled: self.0.compiled.clone(), + dir: dir.to_path_buf(), + overrides: self.0.overrides.clone(), + types: self.0.types.clone(), + parent: Some(self.clone()), + is_absolute_parent: false, + absolute_base: self.0.absolute_base.clone(), + explicit_ignores: self.0.explicit_ignores.clone(), + custom_ignore_filenames: self.0.custom_ignore_filenames.clone(), + custom_ignore_matcher: custom_ig_matcher, + ignore_matcher: ig_matcher, + git_global_matcher: self.0.git_global_matcher.clone(), + git_ignore_matcher: gi_matcher, + git_exclude_matcher: gi_exclude_matcher, + has_git: dir.join(".git").exists(), + opts: self.0.opts, + }; + (ig, errs.into_error_option()) + } + + /// Returns true if at least one type of ignore rule should be matched. + fn has_any_ignore_rules(&self) -> bool { + let opts = self.0.opts; + let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty(); + let has_explicit_ignores = !self.0.explicit_ignores.is_empty(); + + opts.ignore || opts.git_global || opts.git_ignore + || opts.git_exclude || has_custom_ignore_files + || has_explicit_ignores + } + + /// Like `matched`, but works with a directory entry instead. + pub fn matched_dir_entry<'a>( + &'a self, + dent: &DirEntry, + ) -> Match> { + let m = self.matched(dent.path(), dent.is_dir()); + if m.is_none() && self.0.opts.hidden && is_hidden(dent) { + return Match::Ignore(IgnoreMatch::hidden()); + } + m + } + + /// Returns a match indicating whether the given file path should be + /// ignored or not. + /// + /// The match contains information about its origin. + fn matched<'a, P: AsRef>( + &'a self, + path: P, + is_dir: bool, + ) -> Match> { + // We need to be careful with our path. If it has a leading ./, then + // strip it because it causes nothing but trouble. + let mut path = path.as_ref(); + if let Some(p) = strip_prefix("./", path) { + path = p; + } + // Match against the override patterns. If an override matches + // regardless of whether it's whitelist/ignore, then we quit and + // return that result immediately. Overrides have the highest + // precedence. + if !self.0.overrides.is_empty() { + let mat = + self.0.overrides.matched(path, is_dir) + .map(IgnoreMatch::overrides); + if !mat.is_none() { + return mat; + } + } + let mut whitelisted = Match::None; + if self.has_any_ignore_rules() { + let mat = self.matched_ignore(path, is_dir); + if mat.is_ignore() { + return mat; + } else if mat.is_whitelist() { + whitelisted = mat; + } + } + if !self.0.types.is_empty() { + let mat = + self.0.types.matched(path, is_dir).map(IgnoreMatch::types); + if mat.is_ignore() { + return mat; + } else if mat.is_whitelist() { + whitelisted = mat; + } + } + whitelisted + } + + /// Performs matching only on the ignore files for this directory and + /// all parent directories. + fn matched_ignore<'a>( + &'a self, + path: &Path, + is_dir: bool, + ) -> Match> { + let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = + (Match::None, Match::None, Match::None, Match::None, Match::None); + let any_git = self.parents().any(|ig| ig.0.has_git); + let mut saw_git = false; + for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) { + if m_custom_ignore.is_none() { + m_custom_ignore = + ig.0.custom_ignore_matcher.matched(path, is_dir) + .map(IgnoreMatch::gitignore); + } + if m_ignore.is_none() { + m_ignore = + ig.0.ignore_matcher.matched(path, is_dir) + .map(IgnoreMatch::gitignore); + } + if any_git && !saw_git && m_gi.is_none() { + m_gi = + ig.0.git_ignore_matcher.matched(path, is_dir) + .map(IgnoreMatch::gitignore); + } + if any_git && !saw_git && m_gi_exclude.is_none() { + m_gi_exclude = + ig.0.git_exclude_matcher.matched(path, is_dir) + .map(IgnoreMatch::gitignore); + } + saw_git = saw_git || ig.0.has_git; + } + if self.0.opts.parents { + if let Some(abs_parent_path) = self.absolute_base() { + let path = abs_parent_path.join(path); + for ig in self.parents().skip_while(|ig|!ig.0.is_absolute_parent) { + if m_custom_ignore.is_none() { + m_custom_ignore = + ig.0.custom_ignore_matcher.matched(&path, is_dir) + .map(IgnoreMatch::gitignore); + } + if m_ignore.is_none() { + m_ignore = + ig.0.ignore_matcher.matched(&path, is_dir) + .map(IgnoreMatch::gitignore); + } + if any_git && !saw_git && m_gi.is_none() { + m_gi = + ig.0.git_ignore_matcher.matched(&path, is_dir) + .map(IgnoreMatch::gitignore); + } + if any_git && !saw_git && m_gi_exclude.is_none() { + m_gi_exclude = + ig.0.git_exclude_matcher.matched(&path, is_dir) + .map(IgnoreMatch::gitignore); + } + saw_git = saw_git || ig.0.has_git; + } + } + } + for gi in self.0.explicit_ignores.iter().rev() { + if !m_explicit.is_none() { + break; + } + m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore); + } + let m_global = + if any_git { + self.0.git_global_matcher + .matched(&path, is_dir) + .map(IgnoreMatch::gitignore) + } else { + Match::None + }; + + m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit) + } + + /// Returns an iterator over parent ignore matchers, including this one. + pub fn parents(&self) -> Parents { + Parents(Some(self)) + } + + /// Returns the first absolute path of the first absolute parent, if + /// one exists. + fn absolute_base(&self) -> Option<&Path> { + self.0.absolute_base.as_ref().map(|p| &***p) + } +} + +/// An iterator over all parents of an ignore matcher, including itself. +/// +/// The lifetime `'a` refers to the lifetime of the initial `Ignore` matcher. +pub struct Parents<'a>(Option<&'a Ignore>); + +impl<'a> Iterator for Parents<'a> { + type Item = &'a Ignore; + + fn next(&mut self) -> Option<&'a Ignore> { + match self.0.take() { + None => None, + Some(ig) => { + self.0 = ig.0.parent.as_ref(); + Some(ig) + } + } + } +} + +/// A builder for creating an Ignore matcher. +#[derive(Clone, Debug)] +pub struct IgnoreBuilder { + /// The root directory path for this ignore matcher. + dir: PathBuf, + /// An override matcher (default is empty). + overrides: Arc, + /// A type matcher (default is empty). + types: Arc, + /// Explicit global ignore matchers. + explicit_ignores: Vec, + /// Ignore files in addition to .ignore. + custom_ignore_filenames: Vec, + /// Ignore config. + opts: IgnoreOptions, +} + +impl IgnoreBuilder { + /// Create a new builder for an `Ignore` matcher. + /// + /// All relative file paths are resolved with respect to the current + /// working directory. + pub fn new() -> IgnoreBuilder { + IgnoreBuilder { + dir: Path::new("").to_path_buf(), + overrides: Arc::new(Override::empty()), + types: Arc::new(Types::empty()), + explicit_ignores: vec![], + custom_ignore_filenames: vec![], + opts: IgnoreOptions { + hidden: true, + ignore: true, + parents: true, + git_global: true, + git_ignore: true, + git_exclude: true, + ignore_case_insensitive: false, + }, + } + } + + /// Builds a new `Ignore` matcher. + /// + /// The matcher returned won't match anything until ignore rules from + /// directories are added to it. + pub fn build(&self) -> Ignore { + let git_global_matcher = + if !self.opts.git_global { + Gitignore::empty() + } else { + let mut builder = GitignoreBuilder::new(""); + builder + .case_insensitive(self.opts.ignore_case_insensitive) + .unwrap(); + let (gi, err) = builder.build_global(); + if let Some(err) = err { + debug!("{}", err); + } + gi + }; + + Ignore(Arc::new(IgnoreInner { + compiled: Arc::new(RwLock::new(HashMap::new())), + dir: self.dir.clone(), + overrides: self.overrides.clone(), + types: self.types.clone(), + parent: None, + is_absolute_parent: true, + absolute_base: None, + explicit_ignores: Arc::new(self.explicit_ignores.clone()), + custom_ignore_filenames: Arc::new(self.custom_ignore_filenames.clone()), + custom_ignore_matcher: Gitignore::empty(), + ignore_matcher: Gitignore::empty(), + git_global_matcher: Arc::new(git_global_matcher), + git_ignore_matcher: Gitignore::empty(), + git_exclude_matcher: Gitignore::empty(), + has_git: false, + opts: self.opts, + })) + } + + /// Add an override matcher. + /// + /// By default, no override matcher is used. + /// + /// This overrides any previous setting. + pub fn overrides(&mut self, overrides: Override) -> &mut IgnoreBuilder { + self.overrides = Arc::new(overrides); + self + } + + /// Add a file type matcher. + /// + /// By default, no file type matcher is used. + /// + /// This overrides any previous setting. + pub fn types(&mut self, types: Types) -> &mut IgnoreBuilder { + self.types = Arc::new(types); + self + } + + /// Adds a new global ignore matcher from the ignore file path given. + pub fn add_ignore(&mut self, ig: Gitignore) -> &mut IgnoreBuilder { + self.explicit_ignores.push(ig); + self + } + + /// Add a custom ignore file name + /// + /// These ignore files have higher precedence than all other ignore files. + /// + /// When specifying multiple names, earlier names have lower precedence than + /// later names. + pub fn add_custom_ignore_filename>( + &mut self, + file_name: S + ) -> &mut IgnoreBuilder { + self.custom_ignore_filenames.push(file_name.as_ref().to_os_string()); + self + } + + /// Enables ignoring hidden files. + /// + /// This is enabled by default. + pub fn hidden(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.hidden = yes; + self + } + + /// Enables reading `.ignore` files. + /// + /// `.ignore` files have the same semantics as `gitignore` files and are + /// supported by search tools such as ripgrep and The Silver Searcher. + /// + /// This is enabled by default. + pub fn ignore(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.ignore = yes; + self + } + + /// Enables reading ignore files from parent directories. + /// + /// If this is enabled, then .gitignore files in parent directories of each + /// file path given are respected. Otherwise, they are ignored. + /// + /// This is enabled by default. + pub fn parents(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.parents = yes; + self + } + + /// Add a global gitignore matcher. + /// + /// Its precedence is lower than both normal `.gitignore` files and + /// `.git/info/exclude` files. + /// + /// This overwrites any previous global gitignore setting. + /// + /// This is enabled by default. + pub fn git_global(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.git_global = yes; + self + } + + /// Enables reading `.gitignore` files. + /// + /// `.gitignore` files have match semantics as described in the `gitignore` + /// man page. + /// + /// This is enabled by default. + pub fn git_ignore(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.git_ignore = yes; + self + } + + /// Enables reading `.git/info/exclude` files. + /// + /// `.git/info/exclude` files have match semantics as described in the + /// `gitignore` man page. + /// + /// This is enabled by default. + pub fn git_exclude(&mut self, yes: bool) -> &mut IgnoreBuilder { + self.opts.git_exclude = yes; + self + } + + /// Process ignore files case insensitively + /// + /// This is disabled by default. + pub fn ignore_case_insensitive( + &mut self, + yes: bool, + ) -> &mut IgnoreBuilder { + self.opts.ignore_case_insensitive = yes; + self + } +} + +/// Creates a new gitignore matcher for the directory given. +/// +/// Ignore globs are extracted from each of the file names in `dir` in the +/// order given (earlier names have lower precedence than later names). +/// +/// I/O errors are ignored. +pub fn create_gitignore>( + dir: &Path, + names: &[T], + case_insensitive: bool, +) -> (Gitignore, Option) { + let mut builder = GitignoreBuilder::new(dir); + let mut errs = PartialErrorBuilder::default(); + builder.case_insensitive(case_insensitive).unwrap(); + for name in names { + let gipath = dir.join(name.as_ref()); + errs.maybe_push_ignore_io(builder.add(gipath)); + } + let gi = match builder.build() { + Ok(gi) => gi, + Err(err) => { + errs.push(err); + GitignoreBuilder::new(dir).build().unwrap() + } + }; + (gi, errs.into_error_option()) +} + +#[cfg(test)] +mod tests { + use std::fs::{self, File}; + use std::io::Write; + use std::path::Path; + + use tempfile::{self, TempDir}; + + use dir::IgnoreBuilder; + use gitignore::Gitignore; + use Error; + + fn wfile>(path: P, contents: &str) { + let mut file = File::create(path).unwrap(); + file.write_all(contents.as_bytes()).unwrap(); + } + + fn mkdirp>(path: P) { + fs::create_dir_all(path).unwrap(); + } + + fn partial(err: Error) -> Vec { + match err { + Error::Partial(errs) => errs, + _ => panic!("expected partial error but got {:?}", err), + } + } + + fn tmpdir(prefix: &str) -> TempDir { + tempfile::Builder::new().prefix(prefix).tempdir().unwrap() + } + + #[test] + fn explicit_ignore() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join("not-an-ignore"), "foo\n!bar"); + + let (gi, err) = Gitignore::new(td.path().join("not-an-ignore")); + assert!(err.is_none()); + let (ig, err) = IgnoreBuilder::new() + .add_ignore(gi).build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_ignore()); + assert!(ig.matched("bar", false).is_whitelist()); + assert!(ig.matched("baz", false).is_none()); + } + + #[test] + fn git_exclude() { + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git/info")); + wfile(td.path().join(".git/info/exclude"), "foo\n!bar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_ignore()); + assert!(ig.matched("bar", false).is_whitelist()); + assert!(ig.matched("baz", false).is_none()); + } + + #[test] + fn gitignore() { + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git")); + wfile(td.path().join(".gitignore"), "foo\n!bar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_ignore()); + assert!(ig.matched("bar", false).is_whitelist()); + assert!(ig.matched("baz", false).is_none()); + } + + #[test] + fn gitignore_no_git() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "foo\n!bar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_none()); + assert!(ig.matched("bar", false).is_none()); + assert!(ig.matched("baz", false).is_none()); + } + + #[test] + fn ignore() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".ignore"), "foo\n!bar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_ignore()); + assert!(ig.matched("bar", false).is_whitelist()); + assert!(ig.matched("baz", false).is_none()); + } + + #[test] + fn custom_ignore() { + let td = tmpdir("ignore-test-"); + let custom_ignore = ".customignore"; + wfile(td.path().join(custom_ignore), "foo\n!bar"); + + let (ig, err) = IgnoreBuilder::new() + .add_custom_ignore_filename(custom_ignore) + .build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_ignore()); + assert!(ig.matched("bar", false).is_whitelist()); + assert!(ig.matched("baz", false).is_none()); + } + + // Tests that a custom ignore file will override an .ignore. + #[test] + fn custom_ignore_over_ignore() { + let td = tmpdir("ignore-test-"); + let custom_ignore = ".customignore"; + wfile(td.path().join(".ignore"), "foo"); + wfile(td.path().join(custom_ignore), "!foo"); + + let (ig, err) = IgnoreBuilder::new() + .add_custom_ignore_filename(custom_ignore) + .build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_whitelist()); + } + + // Tests that earlier custom ignore files have lower precedence than later. + #[test] + fn custom_ignore_precedence() { + let td = tmpdir("ignore-test-"); + let custom_ignore1 = ".customignore1"; + let custom_ignore2 = ".customignore2"; + wfile(td.path().join(custom_ignore1), "foo"); + wfile(td.path().join(custom_ignore2), "!foo"); + + let (ig, err) = IgnoreBuilder::new() + .add_custom_ignore_filename(custom_ignore1) + .add_custom_ignore_filename(custom_ignore2) + .build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_whitelist()); + } + + // Tests that an .ignore will override a .gitignore. + #[test] + fn ignore_over_gitignore() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "foo"); + wfile(td.path().join(".ignore"), "!foo"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("foo", false).is_whitelist()); + } + + // Tests that exclude has lower precedent than both .ignore and .gitignore. + #[test] + fn exclude_lowest() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "!foo"); + wfile(td.path().join(".ignore"), "!bar"); + mkdirp(td.path().join(".git/info")); + wfile(td.path().join(".git/info/exclude"), "foo\nbar\nbaz"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + assert!(ig.matched("baz", false).is_ignore()); + assert!(ig.matched("foo", false).is_whitelist()); + assert!(ig.matched("bar", false).is_whitelist()); + } + + #[test] + fn errored() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "{foo"); + + let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_some()); + } + + #[test] + fn errored_both() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "{foo"); + wfile(td.path().join(".ignore"), "{bar"); + + let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert_eq!(2, partial(err.expect("an error")).len()); + } + + #[test] + fn errored_partial() { + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git")); + wfile(td.path().join(".gitignore"), "{foo\nbar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_some()); + assert!(ig.matched("bar", false).is_ignore()); + } + + #[test] + fn errored_partial_and_ignore() { + let td = tmpdir("ignore-test-"); + wfile(td.path().join(".gitignore"), "{foo\nbar"); + wfile(td.path().join(".ignore"), "!bar"); + + let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_some()); + assert!(ig.matched("bar", false).is_whitelist()); + } + + #[test] + fn not_present_empty() { + let td = tmpdir("ignore-test-"); + + let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); + assert!(err.is_none()); + } + + #[test] + fn stops_at_git_dir() { + // This tests that .gitignore files beyond a .git barrier aren't + // matched, but .ignore files are. + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git")); + mkdirp(td.path().join("foo/.git")); + wfile(td.path().join(".gitignore"), "foo"); + wfile(td.path().join(".ignore"), "bar"); + + let ig0 = IgnoreBuilder::new().build(); + let (ig1, err) = ig0.add_child(td.path()); + assert!(err.is_none()); + let (ig2, err) = ig1.add_child(ig1.path().join("foo")); + assert!(err.is_none()); + + assert!(ig1.matched("foo", false).is_ignore()); + assert!(ig2.matched("foo", false).is_none()); + + assert!(ig1.matched("bar", false).is_ignore()); + assert!(ig2.matched("bar", false).is_ignore()); + } + + #[test] + fn absolute_parent() { + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git")); + mkdirp(td.path().join("foo")); + wfile(td.path().join(".gitignore"), "bar"); + + // First, check that the parent gitignore file isn't detected if the + // parent isn't added. This establishes a baseline. + let ig0 = IgnoreBuilder::new().build(); + let (ig1, err) = ig0.add_child(td.path().join("foo")); + assert!(err.is_none()); + assert!(ig1.matched("bar", false).is_none()); + + // Second, check that adding a parent directory actually works. + let ig0 = IgnoreBuilder::new().build(); + let (ig1, err) = ig0.add_parents(td.path().join("foo")); + assert!(err.is_none()); + let (ig2, err) = ig1.add_child(td.path().join("foo")); + assert!(err.is_none()); + assert!(ig2.matched("bar", false).is_ignore()); + } + + #[test] + fn absolute_parent_anchored() { + let td = tmpdir("ignore-test-"); + mkdirp(td.path().join(".git")); + mkdirp(td.path().join("src/llvm")); + wfile(td.path().join(".gitignore"), "/llvm/\nfoo"); + + let ig0 = IgnoreBuilder::new().build(); + let (ig1, err) = ig0.add_parents(td.path().join("src")); + assert!(err.is_none()); + let (ig2, err) = ig1.add_child("src"); + assert!(err.is_none()); + + assert!(ig1.matched("llvm", true).is_none()); + assert!(ig2.matched("llvm", true).is_none()); + assert!(ig2.matched("src/llvm", true).is_none()); + assert!(ig2.matched("foo", false).is_ignore()); + assert!(ig2.matched("src/foo", false).is_ignore()); + } +} diff --git a/ignore/src/gitignore.rs b/ignore/src/gitignore.rs new file mode 100644 index 000000000..b8db42ba2 --- /dev/null +++ b/ignore/src/gitignore.rs @@ -0,0 +1,787 @@ +/*! +The gitignore module provides a way to match globs from a gitignore file +against file paths. + +Note that this module implements the specification as described in the +`gitignore` man page from scratch. That is, this module does *not* shell out to +the `git` command line tool. +*/ + +use std::cell::RefCell; +use std::env; +use std::fs::File; +use std::io::{self, BufRead, Read}; +use std::path::{Path, PathBuf}; +use std::str; +use std::sync::Arc; + +use globset::{Candidate, GlobBuilder, GlobSet, GlobSetBuilder}; +use regex::bytes::Regex; +use thread_local::ThreadLocal; + +use pathutil::{is_file_name, strip_prefix}; +use {Error, Match, PartialErrorBuilder}; + +/// Glob represents a single glob in a gitignore file. +/// +/// This is used to report information about the highest precedent glob that +/// matched in one or more gitignore files. +#[derive(Clone, Debug)] +pub struct Glob { + /// The file path that this glob was extracted from. + from: Option, + /// The original glob string. + original: String, + /// The actual glob string used to convert to a regex. + actual: String, + /// Whether this is a whitelisted glob or not. + is_whitelist: bool, + /// Whether this glob should only match directories or not. + is_only_dir: bool, +} + +impl Glob { + /// Returns the file path that defined this glob. + pub fn from(&self) -> Option<&Path> { + self.from.as_ref().map(|p| &**p) + } + + /// The original glob as it was defined in a gitignore file. + pub fn original(&self) -> &str { + &self.original + } + + /// The actual glob that was compiled to respect gitignore + /// semantics. + pub fn actual(&self) -> &str { + &self.actual + } + + /// Whether this was a whitelisted glob or not. + pub fn is_whitelist(&self) -> bool { + self.is_whitelist + } + + /// Whether this glob must match a directory or not. + pub fn is_only_dir(&self) -> bool { + self.is_only_dir + } + + /// Returns true if and only if this glob has a `**/` prefix. + fn has_doublestar_prefix(&self) -> bool { + self.actual.starts_with("**/") || self.actual == "**" + } +} + +/// Gitignore is a matcher for the globs in one or more gitignore files +/// in the same directory. +#[derive(Clone, Debug)] +pub struct Gitignore { + set: GlobSet, + root: PathBuf, + globs: Vec, + num_ignores: u64, + num_whitelists: u64, + matches: Option>>>>, +} + +impl Gitignore { + /// Creates a new gitignore matcher from the gitignore file path given. + /// + /// If it's desirable to include multiple gitignore files in a single + /// matcher, or read gitignore globs from a different source, then + /// use `GitignoreBuilder`. + /// + /// This always returns a valid matcher, even if it's empty. In particular, + /// a Gitignore file can be partially valid, e.g., when one glob is invalid + /// but the rest aren't. + /// + /// Note that I/O errors are ignored. For more granular control over + /// errors, use `GitignoreBuilder`. + pub fn new>( + gitignore_path: P, + ) -> (Gitignore, Option) { + let path = gitignore_path.as_ref(); + let parent = path.parent().unwrap_or(Path::new("/")); + let mut builder = GitignoreBuilder::new(parent); + let mut errs = PartialErrorBuilder::default(); + errs.maybe_push_ignore_io(builder.add(path)); + match builder.build() { + Ok(gi) => (gi, errs.into_error_option()), + Err(err) => { + errs.push(err); + (Gitignore::empty(), errs.into_error_option()) + } + } + } + + /// Creates a new gitignore matcher from the global ignore file, if one + /// exists. + /// + /// The global config file path is specified by git's `core.excludesFile` + /// config option. + /// + /// Git's config file location is `$HOME/.gitconfig`. If `$HOME/.gitconfig` + /// does not exist or does not specify `core.excludesFile`, then + /// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not + /// set or is empty, then `$HOME/.config/git/ignore` is used instead. + pub fn global() -> (Gitignore, Option) { + GitignoreBuilder::new("").build_global() + } + + /// Creates a new empty gitignore matcher that never matches anything. + /// + /// Its path is empty. + pub fn empty() -> Gitignore { + Gitignore { + set: GlobSet::empty(), + root: PathBuf::from(""), + globs: vec![], + num_ignores: 0, + num_whitelists: 0, + matches: None, + } + } + + /// Returns the directory containing this gitignore matcher. + /// + /// All matches are done relative to this path. + pub fn path(&self) -> &Path { + &*self.root + } + + /// Returns true if and only if this gitignore has zero globs, and + /// therefore never matches any file path. + pub fn is_empty(&self) -> bool { + self.set.is_empty() + } + + /// Returns the total number of globs, which should be equivalent to + /// `num_ignores + num_whitelists`. + pub fn len(&self) -> usize { + self.set.len() + } + + /// Returns the total number of ignore globs. + pub fn num_ignores(&self) -> u64 { + self.num_ignores + } + + /// Returns the total number of whitelisted globs. + pub fn num_whitelists(&self) -> u64 { + self.num_whitelists + } + + /// Returns whether the given path (file or directory) matched a pattern in + /// this gitignore matcher. + /// + /// `is_dir` should be true if the path refers to a directory and false + /// otherwise. + /// + /// The given path is matched relative to the path given when building + /// the matcher. Specifically, before matching `path`, its prefix (as + /// determined by a common suffix of the directory containing this + /// gitignore) is stripped. If there is no common suffix/prefix overlap, + /// then `path` is assumed to be relative to this matcher. + pub fn matched>( + &self, + path: P, + is_dir: bool, + ) -> Match<&Glob> { + if self.is_empty() { + return Match::None; + } + self.matched_stripped(self.strip(path.as_ref()), is_dir) + } + + /// Returns whether the given path (file or directory, and expected to be + /// under the root) or any of its parent directories (up to the root) + /// matched a pattern in this gitignore matcher. + /// + /// NOTE: This method is more expensive than walking the directory hierarchy + /// top-to-bottom and matching the entries. But, is easier to use in cases + /// when a list of paths are available without a hierarchy. + /// + /// `is_dir` should be true if the path refers to a directory and false + /// otherwise. + /// + /// The given path is matched relative to the path given when building + /// the matcher. Specifically, before matching `path`, its prefix (as + /// determined by a common suffix of the directory containing this + /// gitignore) is stripped. If there is no common suffix/prefix overlap, + /// then `path` is assumed to be relative to this matcher. + /// + /// # Panics + /// + /// This method panics if the given file path is not under the root path + /// of this matcher. + pub fn matched_path_or_any_parents>( + &self, + path: P, + is_dir: bool, + ) -> Match<&Glob> { + if self.is_empty() { + return Match::None; + } + let mut path = self.strip(path.as_ref()); + assert!(!path.has_root(), "path is expected to be under the root"); + + match self.matched_stripped(path, is_dir) { + Match::None => (), // walk up + a_match => return a_match, + } + while let Some(parent) = path.parent() { + match self.matched_stripped(parent, /* is_dir */ true) { + Match::None => path = parent, // walk up + a_match => return a_match, + } + } + Match::None + } + + /// Like matched, but takes a path that has already been stripped. + fn matched_stripped>( + &self, + path: P, + is_dir: bool, + ) -> Match<&Glob> { + if self.is_empty() { + return Match::None; + } + let path = path.as_ref(); + let _matches = self.matches.as_ref().unwrap().get_default(); + let mut matches = _matches.borrow_mut(); + let candidate = Candidate::new(path); + self.set.matches_candidate_into(&candidate, &mut *matches); + for &i in matches.iter().rev() { + let glob = &self.globs[i]; + if !glob.is_only_dir() || is_dir { + return if glob.is_whitelist() { + Match::Whitelist(glob) + } else { + Match::Ignore(glob) + }; + } + } + Match::None + } + + /// Strips the given path such that it's suitable for matching with this + /// gitignore matcher. + fn strip<'a, P: 'a + AsRef + ?Sized>( + &'a self, + path: &'a P, + ) -> &'a Path { + let mut path = path.as_ref(); + // A leading ./ is completely superfluous. We also strip it from + // our gitignore root path, so we need to strip it from our candidate + // path too. + if let Some(p) = strip_prefix("./", path) { + path = p; + } + // Strip any common prefix between the candidate path and the root + // of the gitignore, to make sure we get relative matching right. + // BUT, a file name might not have any directory components to it, + // in which case, we don't want to accidentally strip any part of the + // file name. + // + // As an additional special case, if the root is just `.`, then we + // shouldn't try to strip anything, e.g., when path begins with a `.`. + if self.root != Path::new(".") && !is_file_name(path) { + if let Some(p) = strip_prefix(&self.root, path) { + path = p; + // If we're left with a leading slash, get rid of it. + if let Some(p) = strip_prefix("/", path) { + path = p; + } + } + } + path + } +} + +/// Builds a matcher for a single set of globs from a .gitignore file. +#[derive(Clone, Debug)] +pub struct GitignoreBuilder { + builder: GlobSetBuilder, + root: PathBuf, + globs: Vec, + case_insensitive: bool, +} + +impl GitignoreBuilder { + /// Create a new builder for a gitignore file. + /// + /// The path given should be the path at which the globs for this gitignore + /// file should be matched. Note that paths are always matched relative + /// to the root path given here. Generally, the root path should correspond + /// to the *directory* containing a `.gitignore` file. + pub fn new>(root: P) -> GitignoreBuilder { + let root = root.as_ref(); + GitignoreBuilder { + builder: GlobSetBuilder::new(), + root: strip_prefix("./", root).unwrap_or(root).to_path_buf(), + globs: vec![], + case_insensitive: false, + } + } + + /// Builds a new matcher from the globs added so far. + /// + /// Once a matcher is built, no new globs can be added to it. + pub fn build(&self) -> Result { + let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count(); + let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count(); + let set = + self.builder.build().map_err(|err| { + Error::Glob { + glob: None, + err: err.to_string(), + } + })?; + Ok(Gitignore { + set: set, + root: self.root.clone(), + globs: self.globs.clone(), + num_ignores: nignore as u64, + num_whitelists: nwhite as u64, + matches: Some(Arc::new(ThreadLocal::default())), + }) + } + + /// Build a global gitignore matcher using the configuration in this + /// builder. + /// + /// This consumes ownership of the builder unlike `build` because it + /// must mutate the builder to add the global gitignore globs. + /// + /// Note that this ignores the path given to this builder's constructor + /// and instead derives the path automatically from git's global + /// configuration. + pub fn build_global(mut self) -> (Gitignore, Option) { + match gitconfig_excludes_path() { + None => (Gitignore::empty(), None), + Some(path) => { + if !path.is_file() { + (Gitignore::empty(), None) + } else { + let mut errs = PartialErrorBuilder::default(); + errs.maybe_push_ignore_io(self.add(path)); + match self.build() { + Ok(gi) => (gi, errs.into_error_option()), + Err(err) => { + errs.push(err); + (Gitignore::empty(), errs.into_error_option()) + } + } + } + } + } + } + + /// Add each glob from the file path given. + /// + /// The file given should be formatted as a `gitignore` file. + /// + /// Note that partial errors can be returned. For example, if there was + /// a problem adding one glob, an error for that will be returned, but + /// all other valid globs will still be added. + pub fn add>(&mut self, path: P) -> Option { + let path = path.as_ref(); + let file = match File::open(path) { + Err(err) => return Some(Error::Io(err).with_path(path)), + Ok(file) => file, + }; + let rdr = io::BufReader::new(file); + let mut errs = PartialErrorBuilder::default(); + for (i, line) in rdr.lines().enumerate() { + let lineno = (i + 1) as u64; + let line = match line { + Ok(line) => line, + Err(err) => { + errs.push(Error::Io(err).tagged(path, lineno)); + break; + } + }; + if let Err(err) = self.add_line(Some(path.to_path_buf()), &line) { + errs.push(err.tagged(path, lineno)); + } + } + errs.into_error_option() + } + + /// Add each glob line from the string given. + /// + /// If this string came from a particular `gitignore` file, then its path + /// should be provided here. + /// + /// The string given should be formatted as a `gitignore` file. + #[cfg(test)] + fn add_str( + &mut self, + from: Option, + gitignore: &str, + ) -> Result<&mut GitignoreBuilder, Error> { + for line in gitignore.lines() { + self.add_line(from.clone(), line)?; + } + Ok(self) + } + + /// Add a line from a gitignore file to this builder. + /// + /// If this line came from a particular `gitignore` file, then its path + /// should be provided here. + /// + /// If the line could not be parsed as a glob, then an error is returned. + pub fn add_line( + &mut self, + from: Option, + mut line: &str, + ) -> Result<&mut GitignoreBuilder, Error> { + #![allow(deprecated)] + + if line.starts_with("#") { + return Ok(self); + } + if !line.ends_with("\\ ") { + line = line.trim_right(); + } + if line.is_empty() { + return Ok(self); + } + let mut glob = Glob { + from: from, + original: line.to_string(), + actual: String::new(), + is_whitelist: false, + is_only_dir: false, + }; + let mut is_absolute = false; + if line.starts_with("\\!") || line.starts_with("\\#") { + line = &line[1..]; + is_absolute = line.chars().nth(0) == Some('/'); + } else { + if line.starts_with("!") { + glob.is_whitelist = true; + line = &line[1..]; + } + if line.starts_with("/") { + // `man gitignore` says that if a glob starts with a slash, + // then the glob can only match the beginning of a path + // (relative to the location of gitignore). We achieve this by + // simply banning wildcards from matching /. + line = &line[1..]; + is_absolute = true; + } + } + // If it ends with a slash, then this should only match directories, + // but the slash should otherwise not be used while globbing. + if let Some((i, c)) = line.char_indices().rev().nth(0) { + if c == '/' { + glob.is_only_dir = true; + line = &line[..i]; + } + } + glob.actual = line.to_string(); + // If there is a literal slash, then this is a glob that must match the + // entire path name. Otherwise, we should let it match anywhere, so use + // a **/ prefix. + if !is_absolute && !line.chars().any(|c| c == '/') { + // ... but only if we don't already have a **/ prefix. + if !glob.has_doublestar_prefix() { + glob.actual = format!("**/{}", glob.actual); + } + } + // If the glob ends with `/**`, then we should only match everything + // inside a directory, but not the directory itself. Standard globs + // will match the directory. So we add `/*` to force the issue. + if glob.actual.ends_with("/**") { + glob.actual = format!("{}/*", glob.actual); + } + let parsed = + GlobBuilder::new(&glob.actual) + .literal_separator(true) + .case_insensitive(self.case_insensitive) + .backslash_escape(true) + .build() + .map_err(|err| { + Error::Glob { + glob: Some(glob.original.clone()), + err: err.kind().to_string(), + } + })?; + self.builder.add(parsed); + self.globs.push(glob); + Ok(self) + } + + /// Toggle whether the globs should be matched case insensitively or not. + /// + /// When this option is changed, only globs added after the change will be + /// affected. + /// + /// This is disabled by default. + pub fn case_insensitive( + &mut self, + yes: bool, + ) -> Result<&mut GitignoreBuilder, Error> { + // TODO: This should not return a `Result`. Fix this in the next semver + // release. + self.case_insensitive = yes; + Ok(self) + } +} + +/// Return the file path of the current environment's global gitignore file. +/// +/// Note that the file path returned may not exist. +fn gitconfig_excludes_path() -> Option { + // git supports $HOME/.gitconfig and $XDG_CONFIG_DIR/git/config. Notably, + // both can be active at the same time, where $HOME/.gitconfig takes + // precedent. So if $HOME/.gitconfig defines a `core.excludesFile`, then + // we're done. + match gitconfig_home_contents().and_then(|x| parse_excludes_file(&x)) { + Some(path) => return Some(path), + None => {} + } + match gitconfig_xdg_contents().and_then(|x| parse_excludes_file(&x)) { + Some(path) => return Some(path), + None => {} + } + excludes_file_default() +} + +/// Returns the file contents of git's global config file, if one exists, in +/// the user's home directory. +fn gitconfig_home_contents() -> Option> { + let home = match home_dir() { + None => return None, + Some(home) => home, + }; + let mut file = match File::open(home.join(".gitconfig")) { + Err(_) => return None, + Ok(file) => io::BufReader::new(file), + }; + let mut contents = vec![]; + file.read_to_end(&mut contents).ok().map(|_| contents) +} + +/// Returns the file contents of git's global config file, if one exists, in +/// the user's XDG_CONFIG_DIR directory. +fn gitconfig_xdg_contents() -> Option> { + let path = env::var_os("XDG_CONFIG_HOME") + .and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) }) + .or_else(|| home_dir().map(|p| p.join(".config"))) + .map(|x| x.join("git/config")); + let mut file = match path.and_then(|p| File::open(p).ok()) { + None => return None, + Some(file) => io::BufReader::new(file), + }; + let mut contents = vec![]; + file.read_to_end(&mut contents).ok().map(|_| contents) +} + +/// Returns the default file path for a global .gitignore file. +/// +/// Specifically, this respects XDG_CONFIG_HOME. +fn excludes_file_default() -> Option { + env::var_os("XDG_CONFIG_HOME") + .and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) }) + .or_else(|| home_dir().map(|p| p.join(".config"))) + .map(|x| x.join("git/ignore")) +} + +/// Extract git's `core.excludesfile` config setting from the raw file contents +/// given. +fn parse_excludes_file(data: &[u8]) -> Option { + // N.B. This is the lazy approach, and isn't technically correct, but + // probably works in more circumstances. I guess we would ideally have + // a full INI parser. Yuck. + lazy_static! { + static ref RE: Regex = Regex::new( + r"(?im)^\s*excludesfile\s*=\s*(.+)\s*$" + ).unwrap(); + }; + let caps = match RE.captures(data) { + None => return None, + Some(caps) => caps, + }; + str::from_utf8(&caps[1]).ok().map(|s| PathBuf::from(expand_tilde(s))) +} + +/// Expands ~ in file paths to the value of $HOME. +fn expand_tilde(path: &str) -> String { + let home = match home_dir() { + None => return path.to_string(), + Some(home) => home.to_string_lossy().into_owned(), + }; + path.replace("~", &home) +} + +/// Returns the location of the user's home directory. +fn home_dir() -> Option { + // We're fine with using env::home_dir for now. Its bugs are, IMO, pretty + // minor corner cases. We should still probably eventually migrate to + // the `dirs` crate to get a proper implementation. + #![allow(deprecated)] + env::home_dir() +} + +#[cfg(test)] +mod tests { + use std::path::Path; + use super::{Gitignore, GitignoreBuilder}; + + fn gi_from_str>(root: P, s: &str) -> Gitignore { + let mut builder = GitignoreBuilder::new(root); + builder.add_str(None, s).unwrap(); + builder.build().unwrap() + } + + macro_rules! ignored { + ($name:ident, $root:expr, $gi:expr, $path:expr) => { + ignored!($name, $root, $gi, $path, false); + }; + ($name:ident, $root:expr, $gi:expr, $path:expr, $is_dir:expr) => { + #[test] + fn $name() { + let gi = gi_from_str($root, $gi); + assert!(gi.matched($path, $is_dir).is_ignore()); + } + }; + } + + macro_rules! not_ignored { + ($name:ident, $root:expr, $gi:expr, $path:expr) => { + not_ignored!($name, $root, $gi, $path, false); + }; + ($name:ident, $root:expr, $gi:expr, $path:expr, $is_dir:expr) => { + #[test] + fn $name() { + let gi = gi_from_str($root, $gi); + assert!(!gi.matched($path, $is_dir).is_ignore()); + } + }; + } + + const ROOT: &'static str = "/home/foobar/rust/rg"; + + ignored!(ig1, ROOT, "months", "months"); + ignored!(ig2, ROOT, "*.lock", "Cargo.lock"); + ignored!(ig3, ROOT, "*.rs", "src/main.rs"); + ignored!(ig4, ROOT, "src/*.rs", "src/main.rs"); + ignored!(ig5, ROOT, "/*.c", "cat-file.c"); + ignored!(ig6, ROOT, "/src/*.rs", "src/main.rs"); + ignored!(ig7, ROOT, "!src/main.rs\n*.rs", "src/main.rs"); + ignored!(ig8, ROOT, "foo/", "foo", true); + ignored!(ig9, ROOT, "**/foo", "foo"); + ignored!(ig10, ROOT, "**/foo", "src/foo"); + ignored!(ig11, ROOT, "**/foo/**", "src/foo/bar"); + ignored!(ig12, ROOT, "**/foo/**", "wat/src/foo/bar/baz"); + ignored!(ig13, ROOT, "**/foo/bar", "foo/bar"); + ignored!(ig14, ROOT, "**/foo/bar", "src/foo/bar"); + ignored!(ig15, ROOT, "abc/**", "abc/x"); + ignored!(ig16, ROOT, "abc/**", "abc/x/y"); + ignored!(ig17, ROOT, "abc/**", "abc/x/y/z"); + ignored!(ig18, ROOT, "a/**/b", "a/b"); + ignored!(ig19, ROOT, "a/**/b", "a/x/b"); + ignored!(ig20, ROOT, "a/**/b", "a/x/y/b"); + ignored!(ig21, ROOT, r"\!xy", "!xy"); + ignored!(ig22, ROOT, r"\#foo", "#foo"); + ignored!(ig23, ROOT, "foo", "./foo"); + ignored!(ig24, ROOT, "target", "grep/target"); + ignored!(ig25, ROOT, "Cargo.lock", "./tabwriter-bin/Cargo.lock"); + ignored!(ig26, ROOT, "/foo/bar/baz", "./foo/bar/baz"); + ignored!(ig27, ROOT, "foo/", "xyz/foo", true); + ignored!(ig28, "./src", "/llvm/", "./src/llvm", true); + ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true); + ignored!(ig30, ROOT, "**/", "foo/bar", true); + ignored!(ig31, ROOT, "path1/*", "path1/foo"); + ignored!(ig32, ROOT, ".a/b", ".a/b"); + ignored!(ig33, "./", ".a/b", ".a/b"); + ignored!(ig34, ".", ".a/b", ".a/b"); + ignored!(ig35, "./.", ".a/b", ".a/b"); + ignored!(ig36, "././", ".a/b", ".a/b"); + ignored!(ig37, "././.", ".a/b", ".a/b"); + ignored!(ig38, ROOT, "\\[", "["); + ignored!(ig39, ROOT, "\\?", "?"); + ignored!(ig40, ROOT, "\\*", "*"); + ignored!(ig41, ROOT, "\\a", "a"); + ignored!(ig42, ROOT, "s*.rs", "sfoo.rs"); + ignored!(ig43, ROOT, "**", "foo.rs"); + ignored!(ig44, ROOT, "**/**/*", "a/foo.rs"); + + not_ignored!(ignot1, ROOT, "amonths", "months"); + not_ignored!(ignot2, ROOT, "monthsa", "months"); + not_ignored!(ignot3, ROOT, "/src/*.rs", "src/grep/src/main.rs"); + not_ignored!(ignot4, ROOT, "/*.c", "mozilla-sha1/sha1.c"); + not_ignored!(ignot5, ROOT, "/src/*.rs", "src/grep/src/main.rs"); + not_ignored!(ignot6, ROOT, "*.rs\n!src/main.rs", "src/main.rs"); + not_ignored!(ignot7, ROOT, "foo/", "foo", false); + not_ignored!(ignot8, ROOT, "**/foo/**", "wat/src/afoo/bar/baz"); + not_ignored!(ignot9, ROOT, "**/foo/**", "wat/src/fooa/bar/baz"); + not_ignored!(ignot10, ROOT, "**/foo/bar", "foo/src/bar"); + not_ignored!(ignot11, ROOT, "#foo", "#foo"); + not_ignored!(ignot12, ROOT, "\n\n\n", "foo"); + not_ignored!(ignot13, ROOT, "foo/**", "foo", true); + not_ignored!( + ignot14, "./third_party/protobuf", "m4/ltoptions.m4", + "./third_party/protobuf/csharp/src/packages/repositories.config"); + not_ignored!(ignot15, ROOT, "!/bar", "foo/bar"); + not_ignored!(ignot16, ROOT, "*\n!**/", "foo", true); + not_ignored!(ignot17, ROOT, "src/*.rs", "src/grep/src/main.rs"); + not_ignored!(ignot18, ROOT, "path1/*", "path2/path1/foo"); + not_ignored!(ignot19, ROOT, "s*.rs", "src/foo.rs"); + + fn bytes(s: &str) -> Vec { + s.to_string().into_bytes() + } + + fn path_string>(path: P) -> String { + path.as_ref().to_str().unwrap().to_string() + } + + #[test] + fn parse_excludes_file1() { + let data = bytes("[core]\nexcludesFile = /foo/bar"); + let got = super::parse_excludes_file(&data).unwrap(); + assert_eq!(path_string(got), "/foo/bar"); + } + + #[test] + fn parse_excludes_file2() { + let data = bytes("[core]\nexcludesFile = ~/foo/bar"); + let got = super::parse_excludes_file(&data).unwrap(); + assert_eq!(path_string(got), super::expand_tilde("~/foo/bar")); + } + + #[test] + fn parse_excludes_file3() { + let data = bytes("[core]\nexcludeFile = /foo/bar"); + assert!(super::parse_excludes_file(&data).is_none()); + } + + // See: https://github.com/BurntSushi/ripgrep/issues/106 + #[test] + fn regression_106() { + gi_from_str("/", " "); + } + + #[test] + fn case_insensitive() { + let gi = GitignoreBuilder::new(ROOT) + .case_insensitive(true).unwrap() + .add_str(None, "*.html").unwrap() + .build().unwrap(); + assert!(gi.matched("foo.html", false).is_ignore()); + assert!(gi.matched("foo.HTML", false).is_ignore()); + assert!(!gi.matched("foo.htm", false).is_ignore()); + assert!(!gi.matched("foo.HTM", false).is_ignore()); + } + + ignored!(cs1, ROOT, "*.html", "foo.html"); + not_ignored!(cs2, ROOT, "*.html", "foo.HTML"); + not_ignored!(cs3, ROOT, "*.html", "foo.htm"); + not_ignored!(cs4, ROOT, "*.html", "foo.HTM"); +} diff --git a/ignore/src/lib.rs b/ignore/src/lib.rs new file mode 100644 index 000000000..d0c8d2fc8 --- /dev/null +++ b/ignore/src/lib.rs @@ -0,0 +1,444 @@ +/*! +The ignore crate provides a fast recursive directory iterator that respects +various filters such as globs, file types and `.gitignore` files. The precise +matching rules and precedence is explained in the documentation for +`WalkBuilder`. + +Secondarily, this crate exposes gitignore and file type matchers for use cases +that demand more fine-grained control. + +# Example + +This example shows the most basic usage of this crate. This code will +recursively traverse the current directory while automatically filtering out +files and directories according to ignore globs found in files like +`.ignore` and `.gitignore`: + + +```rust,no_run +use ignore::Walk; + +for result in Walk::new("./") { + // Each item yielded by the iterator is either a directory entry or an + // error, so either print the path or the error. + match result { + Ok(entry) => println!("{}", entry.path().display()), + Err(err) => println!("ERROR: {}", err), + } +} +``` + +# Example: advanced + +By default, the recursive directory iterator will ignore hidden files and +directories. This can be disabled by building the iterator with `WalkBuilder`: + +```rust,no_run +use ignore::WalkBuilder; + +for result in WalkBuilder::new("./").hidden(false).build() { + println!("{:?}", result); +} +``` + +See the documentation for `WalkBuilder` for many other options. +*/ + +#![deny(missing_docs)] + +extern crate crossbeam_channel as channel; +extern crate globset; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate memchr; +extern crate regex; +extern crate same_file; +#[cfg(test)] +extern crate tempfile; +extern crate thread_local; +extern crate walkdir; +#[cfg(windows)] +extern crate winapi_util; + +use std::error; +use std::fmt; +use std::io; +use std::path::{Path, PathBuf}; + +pub use walk::{DirEntry, Walk, WalkBuilder, WalkParallel, WalkState}; + +mod dir; +pub mod gitignore; +mod pathutil; +pub mod overrides; +pub mod types; +mod walk; + +/// Represents an error that can occur when parsing a gitignore file. +#[derive(Debug)] +pub enum Error { + /// A collection of "soft" errors. These occur when adding an ignore + /// file partially succeeded. + Partial(Vec), + /// An error associated with a specific line number. + WithLineNumber { + /// The line number. + line: u64, + /// The underlying error. + err: Box, + }, + /// An error associated with a particular file path. + WithPath { + /// The file path. + path: PathBuf, + /// The underlying error. + err: Box, + }, + /// An error associated with a particular directory depth when recursively + /// walking a directory. + WithDepth { + /// The directory depth. + depth: usize, + /// The underlying error. + err: Box, + }, + /// An error that occurs when a file loop is detected when traversing + /// symbolic links. + Loop { + /// The ancestor file path in the loop. + ancestor: PathBuf, + /// The child file path in the loop. + child: PathBuf, + }, + /// An error that occurs when doing I/O, such as reading an ignore file. + Io(io::Error), + /// An error that occurs when trying to parse a glob. + Glob { + /// The original glob that caused this error. This glob, when + /// available, always corresponds to the glob provided by an end user. + /// e.g., It is the glob as written in a `.gitignore` file. + /// + /// (This glob may be distinct from the glob that is actually + /// compiled, after accounting for `gitignore` semantics.) + glob: Option, + /// The underlying glob error as a string. + err: String, + }, + /// A type selection for a file type that is not defined. + UnrecognizedFileType(String), + /// A user specified file type definition could not be parsed. + InvalidDefinition, +} + +impl Clone for Error { + fn clone(&self) -> Error { + match *self { + Error::Partial(ref errs) => Error::Partial(errs.clone()), + Error::WithLineNumber { line, ref err } => { + Error::WithLineNumber { line: line, err: err.clone() } + } + Error::WithPath { ref path, ref err } => { + Error::WithPath { path: path.clone(), err: err.clone() } + } + Error::WithDepth { depth, ref err } => { + Error::WithDepth { depth: depth, err: err.clone() } + } + Error::Loop { ref ancestor, ref child } => { + Error::Loop { + ancestor: ancestor.clone(), + child: child.clone() + } + } + Error::Io(ref err) => { + match err.raw_os_error() { + Some(e) => Error::Io(io::Error::from_raw_os_error(e)), + None => { + Error::Io(io::Error::new(err.kind(), err.to_string())) + } + } + } + Error::Glob { ref glob, ref err } => { + Error::Glob { glob: glob.clone(), err: err.clone() } + } + Error::UnrecognizedFileType(ref err) => { + Error::UnrecognizedFileType(err.clone()) + } + Error::InvalidDefinition => Error::InvalidDefinition, + } + } +} + +impl Error { + /// Returns true if this is a partial error. + /// + /// A partial error occurs when only some operations failed while others + /// may have succeeded. For example, an ignore file may contain an invalid + /// glob among otherwise valid globs. + pub fn is_partial(&self) -> bool { + match *self { + Error::Partial(_) => true, + Error::WithLineNumber { ref err, .. } => err.is_partial(), + Error::WithPath { ref err, .. } => err.is_partial(), + Error::WithDepth { ref err, .. } => err.is_partial(), + _ => false, + } + } + + /// Returns true if this error is exclusively an I/O error. + pub fn is_io(&self) -> bool { + match *self { + Error::Partial(ref errs) => errs.len() == 1 && errs[0].is_io(), + Error::WithLineNumber { ref err, .. } => err.is_io(), + Error::WithPath { ref err, .. } => err.is_io(), + Error::WithDepth { ref err, .. } => err.is_io(), + Error::Loop { .. } => false, + Error::Io(_) => true, + Error::Glob { .. } => false, + Error::UnrecognizedFileType(_) => false, + Error::InvalidDefinition => false, + } + } + + /// Returns a depth associated with recursively walking a directory (if + /// this error was generated from a recursive directory iterator). + pub fn depth(&self) -> Option { + match *self { + Error::WithPath { ref err, .. } => err.depth(), + Error::WithDepth { depth, .. } => Some(depth), + _ => None, + } + } + + /// Turn an error into a tagged error with the given file path. + fn with_path>(self, path: P) -> Error { + Error::WithPath { + path: path.as_ref().to_path_buf(), + err: Box::new(self), + } + } + + /// Turn an error into a tagged error with the given depth. + fn with_depth(self, depth: usize) -> Error { + Error::WithDepth { + depth: depth, + err: Box::new(self), + } + } + + /// Turn an error into a tagged error with the given file path and line + /// number. If path is empty, then it is omitted from the error. + fn tagged>(self, path: P, lineno: u64) -> Error { + let errline = Error::WithLineNumber { + line: lineno, + err: Box::new(self), + }; + if path.as_ref().as_os_str().is_empty() { + return errline; + } + errline.with_path(path) + } + + /// Build an error from a walkdir error. + fn from_walkdir(err: walkdir::Error) -> Error { + let depth = err.depth(); + if let (Some(anc), Some(child)) = (err.loop_ancestor(), err.path()) { + return Error::WithDepth { + depth: depth, + err: Box::new(Error::Loop { + ancestor: anc.to_path_buf(), + child: child.to_path_buf(), + }), + }; + } + let path = err.path().map(|p| p.to_path_buf()); + let mut ig_err = Error::Io(io::Error::from(err)); + if let Some(path) = path { + ig_err = Error::WithPath { + path: path, + err: Box::new(ig_err), + }; + } + ig_err + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Partial(_) => "partial error", + Error::WithLineNumber { ref err, .. } => err.description(), + Error::WithPath { ref err, .. } => err.description(), + Error::WithDepth { ref err, .. } => err.description(), + Error::Loop { .. } => "file system loop found", + Error::Io(ref err) => err.description(), + Error::Glob { ref err, .. } => err, + Error::UnrecognizedFileType(_) => "unrecognized file type", + Error::InvalidDefinition => "invalid definition", + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Partial(ref errs) => { + let msgs: Vec = + errs.iter().map(|err| err.to_string()).collect(); + write!(f, "{}", msgs.join("\n")) + } + Error::WithLineNumber { line, ref err } => { + write!(f, "line {}: {}", line, err) + } + Error::WithPath { ref path, ref err } => { + write!(f, "{}: {}", path.display(), err) + } + Error::WithDepth { ref err, .. } => err.fmt(f), + Error::Loop { ref ancestor, ref child } => { + write!(f, "File system loop found: \ + {} points to an ancestor {}", + child.display(), ancestor.display()) + } + Error::Io(ref err) => err.fmt(f), + Error::Glob { glob: None, ref err } => write!(f, "{}", err), + Error::Glob { glob: Some(ref glob), ref err } => { + write!(f, "error parsing glob '{}': {}", glob, err) + } + Error::UnrecognizedFileType(ref ty) => { + write!(f, "unrecognized file type: {}", ty) + } + Error::InvalidDefinition => { + write!(f, "invalid definition (format is type:glob, e.g., \ + html:*.html)") + } + } + } +} + +impl From for Error { + fn from(err: io::Error) -> Error { + Error::Io(err) + } +} + +#[derive(Debug, Default)] +struct PartialErrorBuilder(Vec); + +impl PartialErrorBuilder { + fn push(&mut self, err: Error) { + self.0.push(err); + } + + fn push_ignore_io(&mut self, err: Error) { + if !err.is_io() { + self.push(err); + } + } + + fn maybe_push(&mut self, err: Option) { + if let Some(err) = err { + self.push(err); + } + } + + fn maybe_push_ignore_io(&mut self, err: Option) { + if let Some(err) = err { + self.push_ignore_io(err); + } + } + + fn into_error_option(mut self) -> Option { + if self.0.is_empty() { + None + } else if self.0.len() == 1 { + Some(self.0.pop().unwrap()) + } else { + Some(Error::Partial(self.0)) + } + } +} + +/// The result of a glob match. +/// +/// The type parameter `T` typically refers to a type that provides more +/// information about a particular match. For example, it might identify +/// the specific gitignore file and the specific glob pattern that caused +/// the match. +#[derive(Clone, Debug)] +pub enum Match { + /// The path didn't match any glob. + None, + /// The highest precedent glob matched indicates the path should be + /// ignored. + Ignore(T), + /// The highest precedent glob matched indicates the path should be + /// whitelisted. + Whitelist(T), +} + +impl Match { + /// Returns true if the match result didn't match any globs. + pub fn is_none(&self) -> bool { + match *self { + Match::None => true, + Match::Ignore(_) | Match::Whitelist(_) => false, + } + } + + /// Returns true if the match result implies the path should be ignored. + pub fn is_ignore(&self) -> bool { + match *self { + Match::Ignore(_) => true, + Match::None | Match::Whitelist(_) => false, + } + } + + /// Returns true if the match result implies the path should be + /// whitelisted. + pub fn is_whitelist(&self) -> bool { + match *self { + Match::Whitelist(_) => true, + Match::None | Match::Ignore(_) => false, + } + } + + /// Inverts the match so that `Ignore` becomes `Whitelist` and + /// `Whitelist` becomes `Ignore`. A non-match remains the same. + pub fn invert(self) -> Match { + match self { + Match::None => Match::None, + Match::Ignore(t) => Match::Whitelist(t), + Match::Whitelist(t) => Match::Ignore(t), + } + } + + /// Return the value inside this match if it exists. + pub fn inner(&self) -> Option<&T> { + match *self { + Match::None => None, + Match::Ignore(ref t) => Some(t), + Match::Whitelist(ref t) => Some(t), + } + } + + /// Apply the given function to the value inside this match. + /// + /// If the match has no value, then return the match unchanged. + pub fn map U>(self, f: F) -> Match { + match self { + Match::None => Match::None, + Match::Ignore(t) => Match::Ignore(f(t)), + Match::Whitelist(t) => Match::Whitelist(f(t)), + } + } + + /// Return the match if it is not none. Otherwise, return other. + pub fn or(self, other: Self) -> Self { + if self.is_none() { + other + } else { + self + } + } +} diff --git a/ignore/src/overrides.rs b/ignore/src/overrides.rs new file mode 100644 index 000000000..08dbdac24 --- /dev/null +++ b/ignore/src/overrides.rs @@ -0,0 +1,262 @@ +/*! +The overrides module provides a way to specify a set of override globs. +This provides functionality similar to `--include` or `--exclude` in command +line tools. +*/ + +use std::path::Path; + +use gitignore::{self, Gitignore, GitignoreBuilder}; +use {Error, Match}; + +/// Glob represents a single glob in an override matcher. +/// +/// This is used to report information about the highest precedent glob +/// that matched. +/// +/// Note that not all matches necessarily correspond to a specific glob. For +/// example, if there are one or more whitelist globs and a file path doesn't +/// match any glob in the set, then the file path is considered to be ignored. +/// +/// The lifetime `'a` refers to the lifetime of the matcher that produced +/// this glob. +#[derive(Clone, Debug)] +pub struct Glob<'a>(GlobInner<'a>); + +#[derive(Clone, Debug)] +enum GlobInner<'a> { + /// No glob matched, but the file path should still be ignored. + UnmatchedIgnore, + /// A glob matched. + Matched(&'a gitignore::Glob), +} + +impl<'a> Glob<'a> { + fn unmatched() -> Glob<'a> { + Glob(GlobInner::UnmatchedIgnore) + } +} + +/// Manages a set of overrides provided explicitly by the end user. +#[derive(Clone, Debug)] +pub struct Override(Gitignore); + +impl Override { + /// Returns an empty matcher that never matches any file path. + pub fn empty() -> Override { + Override(Gitignore::empty()) + } + + /// Returns the directory of this override set. + /// + /// All matches are done relative to this path. + pub fn path(&self) -> &Path { + self.0.path() + } + + /// Returns true if and only if this matcher is empty. + /// + /// When a matcher is empty, it will never match any file path. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns the total number of ignore globs. + pub fn num_ignores(&self) -> u64 { + self.0.num_whitelists() + } + + /// Returns the total number of whitelisted globs. + pub fn num_whitelists(&self) -> u64 { + self.0.num_ignores() + } + + /// Returns whether the given file path matched a pattern in this override + /// matcher. + /// + /// `is_dir` should be true if the path refers to a directory and false + /// otherwise. + /// + /// If there are no overrides, then this always returns `Match::None`. + /// + /// If there is at least one whitelist override and `is_dir` is false, then + /// this never returns `Match::None`, since non-matches are interpreted as + /// ignored. + /// + /// The given path is matched to the globs relative to the path given + /// when building the override matcher. Specifically, before matching + /// `path`, its prefix (as determined by a common suffix of the directory + /// given) is stripped. If there is no common suffix/prefix overlap, then + /// `path` is assumed to reside in the same directory as the root path for + /// this set of overrides. + pub fn matched<'a, P: AsRef>( + &'a self, + path: P, + is_dir: bool, + ) -> Match> { + if self.is_empty() { + return Match::None; + } + let mat = self.0.matched(path, is_dir).invert(); + if mat.is_none() && self.num_whitelists() > 0 && !is_dir { + return Match::Ignore(Glob::unmatched()); + } + mat.map(move |giglob| Glob(GlobInner::Matched(giglob))) + } +} + +/// Builds a matcher for a set of glob overrides. +pub struct OverrideBuilder { + builder: GitignoreBuilder, +} + +impl OverrideBuilder { + /// Create a new override builder. + /// + /// Matching is done relative to the directory path provided. + pub fn new>(path: P) -> OverrideBuilder { + OverrideBuilder { + builder: GitignoreBuilder::new(path), + } + } + + /// Builds a new override matcher from the globs added so far. + /// + /// Once a matcher is built, no new globs can be added to it. + pub fn build(&self) -> Result { + Ok(Override(self.builder.build()?)) + } + + /// Add a glob to the set of overrides. + /// + /// Globs provided here have precisely the same semantics as a single + /// line in a `gitignore` file, where the meaning of `!` is inverted: + /// namely, `!` at the beginning of a glob will ignore a file. Without `!`, + /// all matches of the glob provided are treated as whitelist matches. + pub fn add(&mut self, glob: &str) -> Result<&mut OverrideBuilder, Error> { + self.builder.add_line(None, glob)?; + Ok(self) + } + + /// Toggle whether the globs should be matched case insensitively or not. + /// + /// When this option is changed, only globs added after the change will be affected. + /// + /// This is disabled by default. + pub fn case_insensitive( + &mut self, + yes: bool, + ) -> Result<&mut OverrideBuilder, Error> { + // TODO: This should not return a `Result`. Fix this in the next semver + // release. + self.builder.case_insensitive(yes)?; + Ok(self) + } +} + +#[cfg(test)] +mod tests { + use super::{Override, OverrideBuilder}; + + const ROOT: &'static str = "/home/andrew/foo"; + + fn ov(globs: &[&str]) -> Override { + let mut builder = OverrideBuilder::new(ROOT); + for glob in globs { + builder.add(glob).unwrap(); + } + builder.build().unwrap() + } + + #[test] + fn empty() { + let ov = ov(&[]); + assert!(ov.matched("a.foo", false).is_none()); + assert!(ov.matched("a", false).is_none()); + assert!(ov.matched("", false).is_none()); + } + + #[test] + fn simple() { + let ov = ov(&["*.foo", "!*.bar"]); + assert!(ov.matched("a.foo", false).is_whitelist()); + assert!(ov.matched("a.foo", true).is_whitelist()); + assert!(ov.matched("a.rs", false).is_ignore()); + assert!(ov.matched("a.rs", true).is_none()); + assert!(ov.matched("a.bar", false).is_ignore()); + assert!(ov.matched("a.bar", true).is_ignore()); + } + + #[test] + fn only_ignores() { + let ov = ov(&["!*.bar"]); + assert!(ov.matched("a.rs", false).is_none()); + assert!(ov.matched("a.rs", true).is_none()); + assert!(ov.matched("a.bar", false).is_ignore()); + assert!(ov.matched("a.bar", true).is_ignore()); + } + + #[test] + fn precedence() { + let ov = ov(&["*.foo", "!*.bar.foo"]); + assert!(ov.matched("a.foo", false).is_whitelist()); + assert!(ov.matched("a.baz", false).is_ignore()); + assert!(ov.matched("a.bar.foo", false).is_ignore()); + } + + #[test] + fn gitignore() { + let ov = ov(&["/foo", "bar/*.rs", "baz/**"]); + assert!(ov.matched("bar/lib.rs", false).is_whitelist()); + assert!(ov.matched("bar/wat/lib.rs", false).is_ignore()); + assert!(ov.matched("wat/bar/lib.rs", false).is_ignore()); + assert!(ov.matched("foo", false).is_whitelist()); + assert!(ov.matched("wat/foo", false).is_ignore()); + assert!(ov.matched("baz", false).is_ignore()); + assert!(ov.matched("baz/a", false).is_whitelist()); + assert!(ov.matched("baz/a/b", false).is_whitelist()); + } + + #[test] + fn allow_directories() { + // This tests that directories are NOT ignored when they are unmatched. + let ov = ov(&["*.rs"]); + assert!(ov.matched("foo.rs", false).is_whitelist()); + assert!(ov.matched("foo.c", false).is_ignore()); + assert!(ov.matched("foo", false).is_ignore()); + assert!(ov.matched("foo", true).is_none()); + assert!(ov.matched("src/foo.rs", false).is_whitelist()); + assert!(ov.matched("src/foo.c", false).is_ignore()); + assert!(ov.matched("src/foo", false).is_ignore()); + assert!(ov.matched("src/foo", true).is_none()); + } + + #[test] + fn absolute_path() { + let ov = ov(&["!/bar"]); + assert!(ov.matched("./foo/bar", false).is_none()); + } + + #[test] + fn case_insensitive() { + let ov = OverrideBuilder::new(ROOT) + .case_insensitive(true).unwrap() + .add("*.html").unwrap() + .build().unwrap(); + assert!(ov.matched("foo.html", false).is_whitelist()); + assert!(ov.matched("foo.HTML", false).is_whitelist()); + assert!(ov.matched("foo.htm", false).is_ignore()); + assert!(ov.matched("foo.HTM", false).is_ignore()); + } + + #[test] + fn default_case_sensitive() { + let ov = OverrideBuilder::new(ROOT) + .add("*.html").unwrap() + .build().unwrap(); + assert!(ov.matched("foo.html", false).is_whitelist()); + assert!(ov.matched("foo.HTML", false).is_ignore()); + assert!(ov.matched("foo.htm", false).is_ignore()); + assert!(ov.matched("foo.HTM", false).is_ignore()); + } +} diff --git a/ignore/src/pathutil.rs b/ignore/src/pathutil.rs new file mode 100644 index 000000000..fbbc0f89b --- /dev/null +++ b/ignore/src/pathutil.rs @@ -0,0 +1,142 @@ +use std::ffi::OsStr; +use std::path::Path; + +use walk::DirEntry; + +/// Returns true if and only if this entry is considered to be hidden. +/// +/// This only returns true if the base name of the path starts with a `.`. +/// +/// On Unix, this implements a more optimized check. +#[cfg(unix)] +pub fn is_hidden(dent: &DirEntry) -> bool { + use std::os::unix::ffi::OsStrExt; + + if let Some(name) = file_name(dent.path()) { + name.as_bytes().get(0) == Some(&b'.') + } else { + false + } +} + +/// Returns true if and only if this entry is considered to be hidden. +/// +/// On Windows, this returns true if one of the following is true: +/// +/// * The base name of the path starts with a `.`. +/// * The file attributes have the `HIDDEN` property set. +#[cfg(windows)] +pub fn is_hidden(dent: &DirEntry) -> bool { + use std::os::windows::fs::MetadataExt; + use winapi_util::file; + + // This looks like we're doing an extra stat call, but on Windows, the + // directory traverser reuses the metadata retrieved from each directory + // entry and stores it on the DirEntry itself. So this is "free." + if let Ok(md) = dent.metadata() { + if file::is_hidden(md.file_attributes() as u64) { + return true; + } + } + if let Some(name) = file_name(dent.path()) { + name.to_str().map(|s| s.starts_with(".")).unwrap_or(false) + } else { + false + } +} + +/// Returns true if and only if this entry is considered to be hidden. +/// +/// This only returns true if the base name of the path starts with a `.`. +#[cfg(not(any(unix, windows)))] +pub fn is_hidden(dent: &DirEntry) -> bool { + if let Some(name) = file_name(dent.path()) { + name.to_str().map(|s| s.starts_with(".")).unwrap_or(false) + } else { + false + } +} + +/// Strip `prefix` from the `path` and return the remainder. +/// +/// If `path` doesn't have a prefix `prefix`, then return `None`. +#[cfg(unix)] +pub fn strip_prefix<'a, P: AsRef + ?Sized>( + prefix: &'a P, + path: &'a Path, +) -> Option<&'a Path> { + use std::os::unix::ffi::OsStrExt; + + let prefix = prefix.as_ref().as_os_str().as_bytes(); + let path = path.as_os_str().as_bytes(); + if prefix.len() > path.len() || prefix != &path[0..prefix.len()] { + None + } else { + Some(&Path::new(OsStr::from_bytes(&path[prefix.len()..]))) + } +} + +/// Strip `prefix` from the `path` and return the remainder. +/// +/// If `path` doesn't have a prefix `prefix`, then return `None`. +#[cfg(not(unix))] +pub fn strip_prefix<'a, P: AsRef + ?Sized>( + prefix: &'a P, + path: &'a Path, +) -> Option<&'a Path> { + path.strip_prefix(prefix).ok() +} + +/// Returns true if this file path is just a file name. i.e., Its parent is +/// the empty string. +#[cfg(unix)] +pub fn is_file_name>(path: P) -> bool { + use std::os::unix::ffi::OsStrExt; + use memchr::memchr; + + let path = path.as_ref().as_os_str().as_bytes(); + memchr(b'/', path).is_none() +} + +/// Returns true if this file path is just a file name. i.e., Its parent is +/// the empty string. +#[cfg(not(unix))] +pub fn is_file_name>(path: P) -> bool { + path.as_ref().parent().map(|p| p.as_os_str().is_empty()).unwrap_or(false) +} + +/// The final component of the path, if it is a normal file. +/// +/// If the path terminates in ., .., or consists solely of a root of prefix, +/// file_name will return None. +#[cfg(unix)] +pub fn file_name<'a, P: AsRef + ?Sized>( + path: &'a P, +) -> Option<&'a OsStr> { + use std::os::unix::ffi::OsStrExt; + use memchr::memrchr; + + let path = path.as_ref().as_os_str().as_bytes(); + if path.is_empty() { + return None; + } else if path.len() == 1 && path[0] == b'.' { + return None; + } else if path.last() == Some(&b'.') { + return None; + } else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] { + return None; + } + let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0); + Some(OsStr::from_bytes(&path[last_slash..])) +} + +/// The final component of the path, if it is a normal file. +/// +/// If the path terminates in ., .., or consists solely of a root of prefix, +/// file_name will return None. +#[cfg(not(unix))] +pub fn file_name<'a, P: AsRef + ?Sized>( + path: &'a P, +) -> Option<&'a OsStr> { + path.as_ref().file_name() +} diff --git a/ignore/src/types.rs b/ignore/src/types.rs new file mode 100644 index 000000000..6ebdeb0e1 --- /dev/null +++ b/ignore/src/types.rs @@ -0,0 +1,811 @@ +/*! +The types module provides a way of associating globs on file names to file +types. + +This can be used to match specific types of files. For example, among +the default file types provided, the Rust file type is defined to be `*.rs` +with name `rust`. Similarly, the C file type is defined to be `*.{c,h}` with +name `c`. + +Note that the set of default types may change over time. + +# Example + +This shows how to create and use a simple file type matcher using the default +file types defined in this crate. + +``` +use ignore::types::TypesBuilder; + +let mut builder = TypesBuilder::new(); +builder.add_defaults(); +builder.select("rust"); +let matcher = builder.build().unwrap(); + +assert!(matcher.matched("foo.rs", false).is_whitelist()); +assert!(matcher.matched("foo.c", false).is_ignore()); +``` + +# Example: negation + +This is like the previous example, but shows how negating a file type works. +That is, this will let us match file paths that *don't* correspond to a +particular file type. + +``` +use ignore::types::TypesBuilder; + +let mut builder = TypesBuilder::new(); +builder.add_defaults(); +builder.negate("c"); +let matcher = builder.build().unwrap(); + +assert!(matcher.matched("foo.rs", false).is_none()); +assert!(matcher.matched("foo.c", false).is_ignore()); +``` + +# Example: custom file type definitions + +This shows how to extend this library default file type definitions with +your own. + +``` +use ignore::types::TypesBuilder; + +let mut builder = TypesBuilder::new(); +builder.add_defaults(); +builder.add("foo", "*.foo"); +// Another way of adding a file type definition. +// This is useful when accepting input from an end user. +builder.add_def("bar:*.bar"); +// Note: we only select `foo`, not `bar`. +builder.select("foo"); +let matcher = builder.build().unwrap(); + +assert!(matcher.matched("x.foo", false).is_whitelist()); +// This is ignored because we only selected the `foo` file type. +assert!(matcher.matched("x.bar", false).is_ignore()); +``` + +We can also add file type definitions based on other definitions. + +``` +use ignore::types::TypesBuilder; + +let mut builder = TypesBuilder::new(); +builder.add_defaults(); +builder.add("foo", "*.foo"); +builder.add_def("bar:include:foo,cpp"); +builder.select("bar"); +let matcher = builder.build().unwrap(); + +assert!(matcher.matched("x.foo", false).is_whitelist()); +assert!(matcher.matched("y.cpp", false).is_whitelist()); +``` +*/ + +use std::cell::RefCell; +use std::collections::HashMap; +use std::path::Path; +use std::sync::Arc; + +use globset::{GlobBuilder, GlobSet, GlobSetBuilder}; +use regex::Regex; +use thread_local::ThreadLocal; + +use pathutil::file_name; +use {Error, Match}; + +const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[ + ("agda", &["*.agda", "*.lagda"]), + ("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]), + ("aidl", &["*.aidl"]), + ("amake", &["*.mk", "*.bp"]), + ("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]), + ("asm", &["*.asm", "*.s", "*.S"]), + ("asp", &["*.aspx", "*.aspx.cs", "*.aspx.cs", "*.ascx", "*.ascx.cs", "*.ascx.vb"]), + ("avro", &["*.avdl", "*.avpr", "*.avsc"]), + ("awk", &["*.awk"]), + ("bazel", &["*.bzl", "WORKSPACE", "BUILD", "BUILD.bazel"]), + ("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]), + ("brotli", &["*.br"]), + ("buildstream", &["*.bst"]), + ("bzip2", &["*.bz2", "*.tbz2"]), + ("c", &["*.[chH]", "*.[chH].in", "*.cats"]), + ("cabal", &["*.cabal"]), + ("cbor", &["*.cbor"]), + ("ceylon", &["*.ceylon"]), + ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]), + ("cmake", &["*.cmake", "CMakeLists.txt"]), + ("coffeescript", &["*.coffee"]), + ("creole", &["*.creole"]), + ("config", &["*.cfg", "*.conf", "*.config", "*.ini"]), + ("cpp", &[ + "*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh", "*.inl", + "*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in", + ]), + ("crystal", &["Projectfile", "*.cr"]), + ("cs", &["*.cs"]), + ("csharp", &["*.cs"]), + ("cshtml", &["*.cshtml"]), + ("css", &["*.css", "*.scss"]), + ("csv", &["*.csv"]), + ("cython", &["*.pyx", "*.pxi", "*.pxd"]), + ("dart", &["*.dart"]), + ("d", &["*.d"]), + ("dhall", &["*.dhall"]), + ("docker", &["*Dockerfile*"]), + ("elisp", &["*.el"]), + ("elixir", &["*.ex", "*.eex", "*.exs"]), + ("elm", &["*.elm"]), + ("erlang", &["*.erl", "*.hrl"]), + ("fidl", &["*.fidl"]), + ("fish", &["*.fish"]), + ("fortran", &[ + "*.f", "*.F", "*.f77", "*.F77", "*.pfo", + "*.f90", "*.F90", "*.f95", "*.F95", + ]), + ("fsharp", &["*.fs", "*.fsx", "*.fsi"]), + ("gn", &["*.gn", "*.gni"]), + ("go", &["*.go"]), + ("gzip", &["*.gz", "*.tgz"]), + ("groovy", &["*.groovy", "*.gradle"]), + ("h", &["*.h", "*.hpp"]), + ("hbs", &["*.hbs"]), + ("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]), + ("hs", &["*.hs", "*.lhs"]), + ("html", &["*.htm", "*.html", "*.ejs"]), + ("idris", &["*.idr", "*.lidr"]), + ("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]), + ("jinja", &["*.j2", "*.jinja", "*.jinja2"]), + ("js", &[ + "*.js", "*.jsx", "*.vue", + ]), + ("json", &["*.json", "composer.lock"]), + ("jsonl", &["*.jsonl"]), + ("julia", &["*.jl"]), + ("jupyter", &["*.ipynb", "*.jpynb"]), + ("jl", &["*.jl"]), + ("kotlin", &["*.kt", "*.kts"]), + ("less", &["*.less"]), + ("license", &[ + // General + "COPYING", "COPYING[.-]*", + "COPYRIGHT", "COPYRIGHT[.-]*", + "EULA", "EULA[.-]*", + "licen[cs]e", "licen[cs]e.*", + "LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*", + "NOTICE", "NOTICE[.-]*", + "PATENTS", "PATENTS[.-]*", + "UNLICEN[CS]E", "UNLICEN[CS]E[.-]*", + // GPL (gpl.txt, etc.) + "agpl[.-]*", + "gpl[.-]*", + "lgpl[.-]*", + // Other license-specific (APACHE-2.0.txt, etc.) + "AGPL-*[0-9]*", + "APACHE-*[0-9]*", + "BSD-*[0-9]*", + "CC-BY-*", + "GFDL-*[0-9]*", + "GNU-*[0-9]*", + "GPL-*[0-9]*", + "LGPL-*[0-9]*", + "MIT-*[0-9]*", + "MPL-*[0-9]*", + "OFL-*[0-9]*", + ]), + ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]), + ("lock", &["*.lock", "package-lock.json"]), + ("log", &["*.log"]), + ("lua", &["*.lua"]), + ("lzma", &["*.lzma"]), + ("lz4", &["*.lz4"]), + ("m4", &["*.ac", "*.m4"]), + ("make", &[ + "[Gg][Nn][Uu]makefile", "[Mm]akefile", + "[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am", + "[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in", + "*.mk", "*.mak" + ]), + ("mako", &["*.mako", "*.mao"]), + ("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]), + ("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]), + ("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]), + ("matlab", &["*.m"]), + ("mk", &["mkfile"]), + ("ml", &["*.ml"]), + ("msbuild", &[ + "*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets" + ]), + ("nim", &["*.nim"]), + ("nix", &["*.nix"]), + ("objc", &["*.h", "*.m"]), + ("objcpp", &["*.h", "*.mm"]), + ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]), + ("org", &["*.org"]), + ("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]), + ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]), + ("pdf", &["*.pdf"]), + ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]), + ("pod", &["*.pod"]), + ("postscript", &[".eps", ".ps"]), + ("protobuf", &["*.proto"]), + ("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]), + ("puppet", &["*.erb", "*.pp", "*.rb"]), + ("purs", &["*.purs"]), + ("py", &["*.py"]), + ("qmake", &["*.pro", "*.pri", "*.prf"]), + ("qml", &["*.qml"]), + ("readme", &["README*", "*README"]), + ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]), + ("rdoc", &["*.rdoc"]), + ("rst", &["*.rst"]), + ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]), + ("rust", &["*.rs"]), + ("sass", &["*.sass", "*.scss"]), + ("scala", &["*.scala", "*.sbt"]), + ("sh", &[ + // Portable/misc. init files + ".login", ".logout", ".profile", "profile", + // bash-specific init files + ".bash_login", "bash_login", + ".bash_logout", "bash_logout", + ".bash_profile", "bash_profile", + ".bashrc", "bashrc", "*.bashrc", + // csh-specific init files + ".cshrc", "*.cshrc", + // ksh-specific init files + ".kshrc", "*.kshrc", + // tcsh-specific init files + ".tcshrc", + // zsh-specific init files + ".zshenv", "zshenv", + ".zlogin", "zlogin", + ".zlogout", "zlogout", + ".zprofile", "zprofile", + ".zshrc", "zshrc", + // Extensions + "*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh", + ]), + ("smarty", &["*.tpl"]), + ("sml", &["*.sml", "*.sig"]), + ("soy", &["*.soy"]), + ("spark", &["*.spark"]), + ("sql", &["*.sql", "*.psql"]), + ("stylus", &["*.styl"]), + ("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]), + ("svg", &["*.svg"]), + ("swift", &["*.swift"]), + ("swig", &["*.def", "*.i"]), + ("systemd", &[ + "*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path", + "*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target", + "*.timer", + ]), + ("taskpaper", &["*.taskpaper"]), + ("tcl", &["*.tcl"]), + ("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]), + ("textile", &["*.textile"]), + ("thrift", &["*.thrift"]), + ("tf", &["*.tf"]), + ("ts", &["*.ts", "*.tsx"]), + ("txt", &["*.txt"]), + ("toml", &["*.toml", "Cargo.lock"]), + ("twig", &["*.twig"]), + ("vala", &["*.vala"]), + ("vb", &["*.vb"]), + ("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]), + ("vhdl", &["*.vhd", "*.vhdl"]), + ("vim", &["*.vim"]), + ("vimscript", &["*.vim"]), + ("wiki", &["*.mediawiki", "*.wiki"]), + ("webidl", &["*.idl", "*.webidl", "*.widl"]), + ("xml", &[ + "*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb", + "*.rng", "*.sch", + ]), + ("xz", &["*.xz", "*.txz"]), + ("yacc", &["*.y"]), + ("yaml", &["*.yaml", "*.yml"]), + ("zig", &["*.zig"]), + ("zsh", &[ + ".zshenv", "zshenv", + ".zlogin", "zlogin", + ".zlogout", "zlogout", + ".zprofile", "zprofile", + ".zshrc", "zshrc", + "*.zsh", + ]), + ("zstd", &["*.zst", "*.zstd"]), +]; + +/// Glob represents a single glob in a set of file type definitions. +/// +/// There may be more than one glob for a particular file type. +/// +/// This is used to report information about the highest precedent glob +/// that matched. +/// +/// Note that not all matches necessarily correspond to a specific glob. +/// For example, if there are one or more selections and a file path doesn't +/// match any of those selections, then the file path is considered to be +/// ignored. +/// +/// The lifetime `'a` refers to the lifetime of the underlying file type +/// definition, which corresponds to the lifetime of the file type matcher. +#[derive(Clone, Debug)] +pub struct Glob<'a>(GlobInner<'a>); + +#[derive(Clone, Debug)] +enum GlobInner<'a> { + /// No glob matched, but the file path should still be ignored. + UnmatchedIgnore, + /// A glob matched. + Matched { + /// The file type definition which provided the glob. + def: &'a FileTypeDef, + /// The index of the glob that matched inside the file type definition. + which: usize, + /// Whether the selection was negated or not. + negated: bool, + } +} + +impl<'a> Glob<'a> { + fn unmatched() -> Glob<'a> { + Glob(GlobInner::UnmatchedIgnore) + } + + /// Return the file type defintion that matched, if one exists. A file type + /// definition always exists when a specific definition matches a file + /// path. + pub fn file_type_def(&self) -> Option<&FileTypeDef> { + match self { + Glob(GlobInner::UnmatchedIgnore) => None, + Glob(GlobInner::Matched { def, .. }) => { + Some(def) + }, + } + } +} + +/// A single file type definition. +/// +/// File type definitions can be retrieved in aggregate from a file type +/// matcher. File type definitions are also reported when its responsible +/// for a match. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FileTypeDef { + name: String, + globs: Vec, +} + +impl FileTypeDef { + /// Return the name of this file type. + pub fn name(&self) -> &str { + &self.name + } + + /// Return the globs used to recognize this file type. + pub fn globs(&self) -> &[String] { + &self.globs + } +} + +/// Types is a file type matcher. +#[derive(Clone, Debug)] +pub struct Types { + /// All of the file type definitions, sorted lexicographically by name. + defs: Vec, + /// All of the selections made by the user. + selections: Vec>, + /// Whether there is at least one Selection::Select in our selections. + /// When this is true, a Match::None is converted to Match::Ignore. + has_selected: bool, + /// A mapping from glob index in the set to two indices. The first is an + /// index into `selections` and the second is an index into the + /// corresponding file type definition's list of globs. + glob_to_selection: Vec<(usize, usize)>, + /// The set of all glob selections, used for actual matching. + set: GlobSet, + /// Temporary storage for globs that match. + matches: Arc>>>, +} + +/// Indicates the type of a selection for a particular file type. +#[derive(Clone, Debug)] +enum Selection { + Select(String, T), + Negate(String, T), +} + +impl Selection { + fn is_negated(&self) -> bool { + match *self { + Selection::Select(..) => false, + Selection::Negate(..) => true, + } + } + + fn name(&self) -> &str { + match *self { + Selection::Select(ref name, _) => name, + Selection::Negate(ref name, _) => name, + } + } + + fn map U>(self, f: F) -> Selection { + match self { + Selection::Select(name, inner) => { + Selection::Select(name, f(inner)) + } + Selection::Negate(name, inner) => { + Selection::Negate(name, f(inner)) + } + } + } + + fn inner(&self) -> &T { + match *self { + Selection::Select(_, ref inner) => inner, + Selection::Negate(_, ref inner) => inner, + } + } +} + +impl Types { + /// Creates a new file type matcher that never matches any path and + /// contains no file type definitions. + pub fn empty() -> Types { + Types { + defs: vec![], + selections: vec![], + has_selected: false, + glob_to_selection: vec![], + set: GlobSetBuilder::new().build().unwrap(), + matches: Arc::new(ThreadLocal::default()), + } + } + + /// Returns true if and only if this matcher has zero selections. + pub fn is_empty(&self) -> bool { + self.selections.is_empty() + } + + /// Returns the number of selections used in this matcher. + pub fn len(&self) -> usize { + self.selections.len() + } + + /// Return the set of current file type definitions. + /// + /// Definitions and globs are sorted. + pub fn definitions(&self) -> &[FileTypeDef] { + &self.defs + } + + /// Returns a match for the given path against this file type matcher. + /// + /// The path is considered whitelisted if it matches a selected file type. + /// The path is considered ignored if it matches a negated file type. + /// If at least one file type is selected and `path` doesn't match, then + /// the path is also considered ignored. + pub fn matched<'a, P: AsRef>( + &'a self, + path: P, + is_dir: bool, + ) -> Match> { + // File types don't apply to directories, and we can't do anything + // if our glob set is empty. + if is_dir || self.set.is_empty() { + return Match::None; + } + // We only want to match against the file name, so extract it. + // If one doesn't exist, then we can't match it. + let name = match file_name(path.as_ref()) { + Some(name) => name, + None if self.has_selected => { + return Match::Ignore(Glob::unmatched()); + } + None => { + return Match::None; + } + }; + let mut matches = self.matches.get_default().borrow_mut(); + self.set.matches_into(name, &mut *matches); + // The highest precedent match is the last one. + if let Some(&i) = matches.last() { + let (isel, iglob) = self.glob_to_selection[i]; + let sel = &self.selections[isel]; + let glob = Glob(GlobInner::Matched { + def: sel.inner(), + which: iglob, + negated: sel.is_negated(), + }); + return if sel.is_negated() { + Match::Ignore(glob) + } else { + Match::Whitelist(glob) + }; + } + if self.has_selected { + Match::Ignore(Glob::unmatched()) + } else { + Match::None + } + } +} + +/// TypesBuilder builds a type matcher from a set of file type definitions and +/// a set of file type selections. +pub struct TypesBuilder { + types: HashMap, + selections: Vec>, +} + +impl TypesBuilder { + /// Create a new builder for a file type matcher. + /// + /// The builder contains *no* type definitions to start with. A set + /// of default type definitions can be added with `add_defaults`, and + /// additional type definitions can be added with `select` and `negate`. + pub fn new() -> TypesBuilder { + TypesBuilder { + types: HashMap::new(), + selections: vec![], + } + } + + /// Build the current set of file type definitions *and* selections into + /// a file type matcher. + pub fn build(&self) -> Result { + let defs = self.definitions(); + let has_selected = self.selections.iter().any(|s| !s.is_negated()); + + let mut selections = vec![]; + let mut glob_to_selection = vec![]; + let mut build_set = GlobSetBuilder::new(); + for (isel, selection) in self.selections.iter().enumerate() { + let def = match self.types.get(selection.name()) { + Some(def) => def.clone(), + None => { + let name = selection.name().to_string(); + return Err(Error::UnrecognizedFileType(name)); + } + }; + for (iglob, glob) in def.globs.iter().enumerate() { + build_set.add( + GlobBuilder::new(glob) + .literal_separator(true) + .build() + .map_err(|err| { + Error::Glob { + glob: Some(glob.to_string()), + err: err.kind().to_string(), + } + })?); + glob_to_selection.push((isel, iglob)); + } + selections.push(selection.clone().map(move |_| def)); + } + let set = build_set.build().map_err(|err| { + Error::Glob { glob: None, err: err.to_string() } + })?; + Ok(Types { + defs: defs, + selections: selections, + has_selected: has_selected, + glob_to_selection: glob_to_selection, + set: set, + matches: Arc::new(ThreadLocal::default()), + }) + } + + /// Return the set of current file type definitions. + /// + /// Definitions and globs are sorted. + pub fn definitions(&self) -> Vec { + let mut defs = vec![]; + for def in self.types.values() { + let mut def = def.clone(); + def.globs.sort(); + defs.push(def); + } + defs.sort_by(|def1, def2| def1.name().cmp(def2.name())); + defs + } + + /// Select the file type given by `name`. + /// + /// If `name` is `all`, then all file types currently defined are selected. + pub fn select(&mut self, name: &str) -> &mut TypesBuilder { + if name == "all" { + for name in self.types.keys() { + self.selections.push(Selection::Select(name.to_string(), ())); + } + } else { + self.selections.push(Selection::Select(name.to_string(), ())); + } + self + } + + /// Ignore the file type given by `name`. + /// + /// If `name` is `all`, then all file types currently defined are negated. + pub fn negate(&mut self, name: &str) -> &mut TypesBuilder { + if name == "all" { + for name in self.types.keys() { + self.selections.push(Selection::Negate(name.to_string(), ())); + } + } else { + self.selections.push(Selection::Negate(name.to_string(), ())); + } + self + } + + /// Clear any file type definitions for the type name given. + pub fn clear(&mut self, name: &str) -> &mut TypesBuilder { + self.types.remove(name); + self + } + + /// Add a new file type definition. `name` can be arbitrary and `pat` + /// should be a glob recognizing file paths belonging to the `name` type. + /// + /// If `name` is `all` or otherwise contains any character that is not a + /// Unicode letter or number, then an error is returned. + pub fn add(&mut self, name: &str, glob: &str) -> Result<(), Error> { + lazy_static! { + static ref RE: Regex = Regex::new(r"^[\pL\pN]+$").unwrap(); + }; + if name == "all" || !RE.is_match(name) { + return Err(Error::InvalidDefinition); + } + let (key, glob) = (name.to_string(), glob.to_string()); + self.types.entry(key).or_insert_with(|| { + FileTypeDef { name: name.to_string(), globs: vec![] } + }).globs.push(glob); + Ok(()) + } + + /// Add a new file type definition specified in string form. There are two + /// valid formats: + /// 1. `{name}:{glob}`. This defines a 'root' definition that associates the + /// given name with the given glob. + /// 2. `{name}:include:{comma-separated list of already defined names}. + /// This defines an 'include' definition that associates the given name + /// with the definitions of the given existing types. + /// Names may not include any characters that are not + /// Unicode letters or numbers. + pub fn add_def(&mut self, def: &str) -> Result<(), Error> { + let parts: Vec<&str> = def.split(':').collect(); + match parts.len() { + 2 => { + let name = parts[0]; + let glob = parts[1]; + if name.is_empty() || glob.is_empty() { + return Err(Error::InvalidDefinition); + } + self.add(name, glob) + } + 3 => { + let name = parts[0]; + let types_string = parts[2]; + if name.is_empty() || parts[1] != "include" || types_string.is_empty() { + return Err(Error::InvalidDefinition); + } + let types = types_string.split(','); + // Check ahead of time to ensure that all types specified are + // present and fail fast if not. + if types.clone().any(|t| !self.types.contains_key(t)) { + return Err(Error::InvalidDefinition); + } + for type_name in types { + let globs = self.types.get(type_name).unwrap().globs.clone(); + for glob in globs { + self.add(name, &glob)?; + } + } + Ok(()) + } + _ => Err(Error::InvalidDefinition) + } + } + + /// Add a set of default file type definitions. + pub fn add_defaults(&mut self) -> &mut TypesBuilder { + static MSG: &'static str = "adding a default type should never fail"; + for &(name, exts) in DEFAULT_TYPES { + for ext in exts { + self.add(name, ext).expect(MSG); + } + } + self + } +} + +#[cfg(test)] +mod tests { + use super::TypesBuilder; + + macro_rules! matched { + ($name:ident, $types:expr, $sel:expr, $selnot:expr, + $path:expr) => { + matched!($name, $types, $sel, $selnot, $path, true); + }; + (not, $name:ident, $types:expr, $sel:expr, $selnot:expr, + $path:expr) => { + matched!($name, $types, $sel, $selnot, $path, false); + }; + ($name:ident, $types:expr, $sel:expr, $selnot:expr, + $path:expr, $matched:expr) => { + #[test] + fn $name() { + let mut btypes = TypesBuilder::new(); + for tydef in $types { + btypes.add_def(tydef).unwrap(); + } + for sel in $sel { + btypes.select(sel); + } + for selnot in $selnot { + btypes.negate(selnot); + } + let types = btypes.build().unwrap(); + let mat = types.matched($path, false); + assert_eq!($matched, !mat.is_ignore()); + } + }; + } + + fn types() -> Vec<&'static str> { + vec![ + "html:*.html", + "html:*.htm", + "rust:*.rs", + "js:*.js", + "foo:*.{rs,foo}", + "combo:include:html,rust" + ] + } + + matched!(match1, types(), vec!["rust"], vec![], "lib.rs"); + matched!(match2, types(), vec!["html"], vec![], "index.html"); + matched!(match3, types(), vec!["html"], vec![], "index.htm"); + matched!(match4, types(), vec!["html", "rust"], vec![], "main.rs"); + matched!(match5, types(), vec![], vec![], "index.html"); + matched!(match6, types(), vec![], vec!["rust"], "index.html"); + matched!(match7, types(), vec!["foo"], vec!["rust"], "main.foo"); + matched!(match8, types(), vec!["combo"], vec![], "index.html"); + matched!(match9, types(), vec!["combo"], vec![], "lib.rs"); + + matched!(not, matchnot1, types(), vec!["rust"], vec![], "index.html"); + matched!(not, matchnot2, types(), vec![], vec!["rust"], "main.rs"); + matched!(not, matchnot3, types(), vec!["foo"], vec!["rust"], "main.rs"); + matched!(not, matchnot4, types(), vec!["rust"], vec!["foo"], "main.rs"); + matched!(not, matchnot5, types(), vec!["rust"], vec!["foo"], "main.foo"); + matched!(not, matchnot6, types(), vec!["combo"], vec![], "leftpad.js"); + + #[test] + fn test_invalid_defs() { + let mut btypes = TypesBuilder::new(); + for tydef in types() { + btypes.add_def(tydef).unwrap(); + } + // Preserve the original definitions for later comparison. + let original_defs = btypes.definitions(); + let bad_defs = vec![ + // Reference to type that does not exist + "combo:include:html,python", + // Bad format + "combo:foobar:html,rust", + "" + ]; + for def in bad_defs { + assert!(btypes.add_def(def).is_err()); + // Ensure that nothing changed, even if some of the includes were valid. + assert_eq!(btypes.definitions(), original_defs); + } + } +} diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs new file mode 100644 index 000000000..724592204 --- /dev/null +++ b/ignore/src/walk.rs @@ -0,0 +1,2060 @@ +use std::cmp; +use std::ffi::OsStr; +use std::fmt; +use std::fs::{self, FileType, Metadata}; +use std::io; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::thread; +use std::time::Duration; +use std::vec; + +use channel; +use same_file::Handle; +use walkdir::{self, WalkDir}; + +use dir::{Ignore, IgnoreBuilder}; +use gitignore::GitignoreBuilder; +use overrides::Override; +use types::Types; +use {Error, PartialErrorBuilder}; + +/// A directory entry with a possible error attached. +/// +/// The error typically refers to a problem parsing ignore files in a +/// particular directory. +#[derive(Clone, Debug)] +pub struct DirEntry { + dent: DirEntryInner, + err: Option, +} + +impl DirEntry { + /// The full path that this entry represents. + pub fn path(&self) -> &Path { + self.dent.path() + } + + /// The full path that this entry represents. + /// Analogous to [`path`], but moves ownership of the path. + /// + /// [`path`]: struct.DirEntry.html#method.path + pub fn into_path(self) -> PathBuf { + self.dent.into_path() + } + + /// Whether this entry corresponds to a symbolic link or not. + pub fn path_is_symlink(&self) -> bool { + self.dent.path_is_symlink() + } + + /// Returns true if and only if this entry corresponds to stdin. + /// + /// i.e., The entry has depth 0 and its file name is `-`. + pub fn is_stdin(&self) -> bool { + self.dent.is_stdin() + } + + /// Return the metadata for the file that this entry points to. + pub fn metadata(&self) -> Result { + self.dent.metadata() + } + + /// Return the file type for the file that this entry points to. + /// + /// This entry doesn't have a file type if it corresponds to stdin. + pub fn file_type(&self) -> Option { + self.dent.file_type() + } + + /// Return the file name of this entry. + /// + /// If this entry has no file name (e.g., `/`), then the full path is + /// returned. + pub fn file_name(&self) -> &OsStr { + self.dent.file_name() + } + + /// Returns the depth at which this entry was created relative to the root. + pub fn depth(&self) -> usize { + self.dent.depth() + } + + /// Returns the underlying inode number if one exists. + /// + /// If this entry doesn't have an inode number, then `None` is returned. + #[cfg(unix)] + pub fn ino(&self) -> Option { + self.dent.ino() + } + + /// Returns an error, if one exists, associated with processing this entry. + /// + /// An example of an error is one that occurred while parsing an ignore + /// file. Errors related to traversing a directory tree itself are reported + /// as part of yielding the directory entry, and not with this method. + pub fn error(&self) -> Option<&Error> { + self.err.as_ref() + } + + /// Returns true if and only if this entry points to a directory. + pub(crate) fn is_dir(&self) -> bool { + self.dent.is_dir() + } + + fn new_stdin() -> DirEntry { + DirEntry { + dent: DirEntryInner::Stdin, + err: None, + } + } + + fn new_walkdir(dent: walkdir::DirEntry, err: Option) -> DirEntry { + DirEntry { + dent: DirEntryInner::Walkdir(dent), + err: err, + } + } + + fn new_raw(dent: DirEntryRaw, err: Option) -> DirEntry { + DirEntry { + dent: DirEntryInner::Raw(dent), + err: err, + } + } +} + +/// DirEntryInner is the implementation of DirEntry. +/// +/// It specifically represents three distinct sources of directory entries: +/// +/// 1. From the walkdir crate. +/// 2. Special entries that represent things like stdin. +/// 3. From a path. +/// +/// Specifically, (3) has to essentially re-create the DirEntry implementation +/// from WalkDir. +#[derive(Clone, Debug)] +enum DirEntryInner { + Stdin, + Walkdir(walkdir::DirEntry), + Raw(DirEntryRaw), +} + +impl DirEntryInner { + fn path(&self) -> &Path { + use self::DirEntryInner::*; + match *self { + Stdin => Path::new(""), + Walkdir(ref x) => x.path(), + Raw(ref x) => x.path(), + } + } + + fn into_path(self) -> PathBuf { + use self::DirEntryInner::*; + match self { + Stdin => PathBuf::from(""), + Walkdir(x) => x.into_path(), + Raw(x) => x.into_path(), + } + } + + fn path_is_symlink(&self) -> bool { + use self::DirEntryInner::*; + match *self { + Stdin => false, + Walkdir(ref x) => x.path_is_symlink(), + Raw(ref x) => x.path_is_symlink(), + } + } + + fn is_stdin(&self) -> bool { + match *self { + DirEntryInner::Stdin => true, + _ => false, + } + } + + fn metadata(&self) -> Result { + use self::DirEntryInner::*; + match *self { + Stdin => { + let err = Error::Io(io::Error::new( + io::ErrorKind::Other, " has no metadata")); + Err(err.with_path("")) + } + Walkdir(ref x) => { + x.metadata().map_err(|err| { + Error::Io(io::Error::from(err)).with_path(x.path()) + }) + } + Raw(ref x) => x.metadata(), + } + } + + fn file_type(&self) -> Option { + use self::DirEntryInner::*; + match *self { + Stdin => None, + Walkdir(ref x) => Some(x.file_type()), + Raw(ref x) => Some(x.file_type()), + } + } + + fn file_name(&self) -> &OsStr { + use self::DirEntryInner::*; + match *self { + Stdin => OsStr::new(""), + Walkdir(ref x) => x.file_name(), + Raw(ref x) => x.file_name(), + } + } + + fn depth(&self) -> usize { + use self::DirEntryInner::*; + match *self { + Stdin => 0, + Walkdir(ref x) => x.depth(), + Raw(ref x) => x.depth(), + } + } + + #[cfg(unix)] + fn ino(&self) -> Option { + use walkdir::DirEntryExt; + use self::DirEntryInner::*; + match *self { + Stdin => None, + Walkdir(ref x) => Some(x.ino()), + Raw(ref x) => Some(x.ino()), + } + } + + /// Returns true if and only if this entry points to a directory. + fn is_dir(&self) -> bool { + self.file_type().map(|ft| ft.is_dir()).unwrap_or(false) + } +} + +/// DirEntryRaw is essentially copied from the walkdir crate so that we can +/// build `DirEntry`s from whole cloth in the parallel iterator. +#[derive(Clone)] +struct DirEntryRaw { + /// The path as reported by the `fs::ReadDir` iterator (even if it's a + /// symbolic link). + path: PathBuf, + /// The file type. Necessary for recursive iteration, so store it. + ty: FileType, + /// Is set when this entry was created from a symbolic link and the user + /// expects the iterator to follow symbolic links. + follow_link: bool, + /// The depth at which this entry was generated relative to the root. + depth: usize, + /// The underlying inode number (Unix only). + #[cfg(unix)] + ino: u64, + /// The underlying metadata (Windows only). We store this on Windows + /// because this comes for free while reading a directory. + #[cfg(windows)] + metadata: fs::Metadata, +} + +impl fmt::Debug for DirEntryRaw { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Leaving out FileType because it doesn't have a debug impl + // in Rust 1.9. We could add it if we really wanted to by manually + // querying each possibly file type. Meh. ---AG + f.debug_struct("DirEntryRaw") + .field("path", &self.path) + .field("follow_link", &self.follow_link) + .field("depth", &self.depth) + .finish() + } +} + +impl DirEntryRaw { + fn path(&self) -> &Path { + &self.path + } + + fn into_path(self) -> PathBuf { + self.path + } + + fn path_is_symlink(&self) -> bool { + self.ty.is_symlink() || self.follow_link + } + + fn metadata(&self) -> Result { + self.metadata_internal() + } + + #[cfg(windows)] + fn metadata_internal(&self) -> Result { + if self.follow_link { + fs::metadata(&self.path) + } else { + Ok(self.metadata.clone()) + }.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) + } + + #[cfg(not(windows))] + fn metadata_internal(&self) -> Result { + if self.follow_link { + fs::metadata(&self.path) + } else { + fs::symlink_metadata(&self.path) + }.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) + } + + fn file_type(&self) -> FileType { + self.ty + } + + fn file_name(&self) -> &OsStr { + self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) + } + + fn depth(&self) -> usize { + self.depth + } + + #[cfg(unix)] + fn ino(&self) -> u64 { + self.ino + } + + fn from_entry( + depth: usize, + ent: &fs::DirEntry, + ) -> Result { + let ty = ent.file_type().map_err(|err| { + let err = Error::Io(io::Error::from(err)).with_path(ent.path()); + Error::WithDepth { + depth: depth, + err: Box::new(err), + } + })?; + DirEntryRaw::from_entry_os(depth, ent, ty) + } + + #[cfg(windows)] + fn from_entry_os( + depth: usize, + ent: &fs::DirEntry, + ty: fs::FileType, + ) -> Result { + let md = ent.metadata().map_err(|err| { + let err = Error::Io(io::Error::from(err)).with_path(ent.path()); + Error::WithDepth { + depth: depth, + err: Box::new(err), + } + })?; + Ok(DirEntryRaw { + path: ent.path(), + ty: ty, + follow_link: false, + depth: depth, + metadata: md, + }) + } + + #[cfg(unix)] + fn from_entry_os( + depth: usize, + ent: &fs::DirEntry, + ty: fs::FileType, + ) -> Result { + use std::os::unix::fs::DirEntryExt; + + Ok(DirEntryRaw { + path: ent.path(), + ty: ty, + follow_link: false, + depth: depth, + ino: ent.ino(), + }) + } + + #[cfg(not(unix))] + fn from_path( + depth: usize, + pb: PathBuf, + link: bool, + ) -> Result { + let md = fs::metadata(&pb).map_err(|err| { + Error::Io(err).with_path(&pb) + })?; + Ok(DirEntryRaw { + path: pb, + ty: md.file_type(), + follow_link: link, + depth: depth, + metadata: md, + }) + } + + #[cfg(unix)] + fn from_path( + depth: usize, + pb: PathBuf, + link: bool, + ) -> Result { + use std::os::unix::fs::MetadataExt; + + let md = fs::metadata(&pb).map_err(|err| { + Error::Io(err).with_path(&pb) + })?; + Ok(DirEntryRaw { + path: pb, + ty: md.file_type(), + follow_link: link, + depth: depth, + ino: md.ino(), + }) + } +} + +/// WalkBuilder builds a recursive directory iterator. +/// +/// The builder supports a large number of configurable options. This includes +/// specific glob overrides, file type matching, toggling whether hidden +/// files are ignored or not, and of course, support for respecting gitignore +/// files. +/// +/// By default, all ignore files found are respected. This includes `.ignore`, +/// `.gitignore`, `.git/info/exclude` and even your global gitignore +/// globs, usually found in `$XDG_CONFIG_HOME/git/ignore`. +/// +/// Some standard recursive directory options are also supported, such as +/// limiting the recursive depth or whether to follow symbolic links (disabled +/// by default). +/// +/// # Ignore rules +/// +/// There are many rules that influence whether a particular file or directory +/// is skipped by this iterator. Those rules are documented here. Note that +/// the rules assume a default configuration. +/// +/// * First, glob overrides are checked. If a path matches a glob override, +/// then matching stops. The path is then only skipped if the glob that matched +/// the path is an ignore glob. (An override glob is a whitelist glob unless it +/// starts with a `!`, in which case it is an ignore glob.) +/// * Second, ignore files are checked. Ignore files currently only come from +/// git ignore files (`.gitignore`, `.git/info/exclude` and the configured +/// global gitignore file), plain `.ignore` files, which have the same format +/// as gitignore files, or explicitly added ignore files. The precedence order +/// is: `.ignore`, `.gitignore`, `.git/info/exclude`, global gitignore and +/// finally explicitly added ignore files. Note that precedence between +/// different types of ignore files is not impacted by the directory hierarchy; +/// any `.ignore` file overrides all `.gitignore` files. Within each precedence +/// level, more nested ignore files have a higher precedence than less nested +/// ignore files. +/// * Third, if the previous step yields an ignore match, then all matching +/// is stopped and the path is skipped. If it yields a whitelist match, then +/// matching continues. A whitelist match can be overridden by a later matcher. +/// * Fourth, unless the path is a directory, the file type matcher is run on +/// the path. As above, if it yields an ignore match, then all matching is +/// stopped and the path is skipped. If it yields a whitelist match, then +/// matching continues. +/// * Fifth, if the path hasn't been whitelisted and it is hidden, then the +/// path is skipped. +/// * Sixth, unless the path is a directory, the size of the file is compared +/// against the max filesize limit. If it exceeds the limit, it is skipped. +/// * Seventh, if the path has made it this far then it is yielded in the +/// iterator. +#[derive(Clone)] +pub struct WalkBuilder { + paths: Vec, + ig_builder: IgnoreBuilder, + max_depth: Option, + max_filesize: Option, + follow_links: bool, + same_file_system: bool, + sorter: Option, + threads: usize, + skip: Option>, +} + +#[derive(Clone)] +enum Sorter { + ByName(Arc cmp::Ordering + Send + Sync + 'static>), + ByPath(Arc cmp::Ordering + Send + Sync + 'static>), +} + +impl fmt::Debug for WalkBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("WalkBuilder") + .field("paths", &self.paths) + .field("ig_builder", &self.ig_builder) + .field("max_depth", &self.max_depth) + .field("max_filesize", &self.max_filesize) + .field("follow_links", &self.follow_links) + .field("threads", &self.threads) + .field("skip", &self.skip) + .finish() + } +} + +impl WalkBuilder { + /// Create a new builder for a recursive directory iterator for the + /// directory given. + /// + /// Note that if you want to traverse multiple different directories, it + /// is better to call `add` on this builder than to create multiple + /// `Walk` values. + pub fn new>(path: P) -> WalkBuilder { + WalkBuilder { + paths: vec![path.as_ref().to_path_buf()], + ig_builder: IgnoreBuilder::new(), + max_depth: None, + max_filesize: None, + follow_links: false, + same_file_system: false, + sorter: None, + threads: 0, + skip: None, + } + } + + /// Build a new `Walk` iterator. + pub fn build(&self) -> Walk { + let follow_links = self.follow_links; + let max_depth = self.max_depth; + let sorter = self.sorter.clone(); + let its = self.paths.iter().map(move |p| { + if p == Path::new("-") { + (p.to_path_buf(), None) + } else { + let mut wd = WalkDir::new(p); + wd = wd.follow_links(follow_links || p.is_file()); + wd = wd.same_file_system(self.same_file_system); + if let Some(max_depth) = max_depth { + wd = wd.max_depth(max_depth); + } + if let Some(ref sorter) = sorter { + match sorter.clone() { + Sorter::ByName(cmp) => { + wd = wd.sort_by(move |a, b| { + cmp(a.file_name(), b.file_name()) + }); + } + Sorter::ByPath(cmp) => { + wd = wd.sort_by(move |a, b| { + cmp(a.path(), b.path()) + }); + } + } + } + (p.to_path_buf(), Some(WalkEventIter::from(wd))) + } + }).collect::>().into_iter(); + let ig_root = self.ig_builder.build(); + Walk { + its: its, + it: None, + ig_root: ig_root.clone(), + ig: ig_root.clone(), + max_filesize: self.max_filesize, + skip: self.skip.clone(), + } + } + + /// Build a new `WalkParallel` iterator. + /// + /// Note that this *doesn't* return something that implements `Iterator`. + /// Instead, the returned value must be run with a closure. e.g., + /// `builder.build_parallel().run(|| |path| println!("{:?}", path))`. + pub fn build_parallel(&self) -> WalkParallel { + WalkParallel { + paths: self.paths.clone().into_iter(), + ig_root: self.ig_builder.build(), + max_depth: self.max_depth, + max_filesize: self.max_filesize, + follow_links: self.follow_links, + same_file_system: self.same_file_system, + threads: self.threads, + skip: self.skip.clone(), + } + } + + /// Add a file path to the iterator. + /// + /// Each additional file path added is traversed recursively. This should + /// be preferred over building multiple `Walk` iterators since this + /// enables reusing resources across iteration. + pub fn add>(&mut self, path: P) -> &mut WalkBuilder { + self.paths.push(path.as_ref().to_path_buf()); + self + } + + /// The maximum depth to recurse. + /// + /// The default, `None`, imposes no depth restriction. + pub fn max_depth(&mut self, depth: Option) -> &mut WalkBuilder { + self.max_depth = depth; + self + } + + /// Whether to follow symbolic links or not. + pub fn follow_links(&mut self, yes: bool) -> &mut WalkBuilder { + self.follow_links = yes; + self + } + + /// Whether to ignore files above the specified limit. + pub fn max_filesize(&mut self, filesize: Option) -> &mut WalkBuilder { + self.max_filesize = filesize; + self + } + + /// The number of threads to use for traversal. + /// + /// Note that this only has an effect when using `build_parallel`. + /// + /// The default setting is `0`, which chooses the number of threads + /// automatically using heuristics. + pub fn threads(&mut self, n: usize) -> &mut WalkBuilder { + self.threads = n; + self + } + + /// Add a global ignore file to the matcher. + /// + /// This has lower precedence than all other sources of ignore rules. + /// + /// If there was a problem adding the ignore file, then an error is + /// returned. Note that the error may indicate *partial* failure. For + /// example, if an ignore file contains an invalid glob, all other globs + /// are still applied. + pub fn add_ignore>(&mut self, path: P) -> Option { + let mut builder = GitignoreBuilder::new(""); + let mut errs = PartialErrorBuilder::default(); + errs.maybe_push(builder.add(path)); + match builder.build() { + Ok(gi) => { self.ig_builder.add_ignore(gi); } + Err(err) => { errs.push(err); } + } + errs.into_error_option() + } + + /// Add a custom ignore file name + /// + /// These ignore files have higher precedence than all other ignore files. + /// + /// When specifying multiple names, earlier names have lower precedence than + /// later names. + pub fn add_custom_ignore_filename>( + &mut self, + file_name: S + ) -> &mut WalkBuilder { + self.ig_builder.add_custom_ignore_filename(file_name); + self + } + + /// Add an override matcher. + /// + /// By default, no override matcher is used. + /// + /// This overrides any previous setting. + pub fn overrides(&mut self, overrides: Override) -> &mut WalkBuilder { + self.ig_builder.overrides(overrides); + self + } + + /// Add a file type matcher. + /// + /// By default, no file type matcher is used. + /// + /// This overrides any previous setting. + pub fn types(&mut self, types: Types) -> &mut WalkBuilder { + self.ig_builder.types(types); + self + } + + /// Enables all the standard ignore filters. + /// + /// This toggles, as a group, all the filters that are enabled by default: + /// + /// - [hidden()](#method.hidden) + /// - [parents()](#method.parents) + /// - [ignore()](#method.ignore) + /// - [git_ignore()](#method.git_ignore) + /// - [git_global()](#method.git_global) + /// - [git_exclude()](#method.git_exclude) + /// + /// They may still be toggled individually after calling this function. + /// + /// This is (by definition) enabled by default. + pub fn standard_filters(&mut self, yes: bool) -> &mut WalkBuilder { + self.hidden(yes) + .parents(yes) + .ignore(yes) + .git_ignore(yes) + .git_global(yes) + .git_exclude(yes) + } + + /// Enables ignoring hidden files. + /// + /// This is enabled by default. + pub fn hidden(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.hidden(yes); + self + } + + /// Enables reading ignore files from parent directories. + /// + /// If this is enabled, then .gitignore files in parent directories of each + /// file path given are respected. Otherwise, they are ignored. + /// + /// This is enabled by default. + pub fn parents(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.parents(yes); + self + } + + /// Enables reading `.ignore` files. + /// + /// `.ignore` files have the same semantics as `gitignore` files and are + /// supported by search tools such as ripgrep and The Silver Searcher. + /// + /// This is enabled by default. + pub fn ignore(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.ignore(yes); + self + } + + /// Enables reading a global gitignore file, whose path is specified in + /// git's `core.excludesFile` config option. + /// + /// Git's config file location is `$HOME/.gitconfig`. If `$HOME/.gitconfig` + /// does not exist or does not specify `core.excludesFile`, then + /// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not + /// set or is empty, then `$HOME/.config/git/ignore` is used instead. + /// + /// This is enabled by default. + pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.git_global(yes); + self + } + + /// Enables reading `.gitignore` files. + /// + /// `.gitignore` files have match semantics as described in the `gitignore` + /// man page. + /// + /// This is enabled by default. + pub fn git_ignore(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.git_ignore(yes); + self + } + + /// Enables reading `.git/info/exclude` files. + /// + /// `.git/info/exclude` files have match semantics as described in the + /// `gitignore` man page. + /// + /// This is enabled by default. + pub fn git_exclude(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.git_exclude(yes); + self + } + + /// Process ignore files case insensitively + /// + /// This is disabled by default. + pub fn ignore_case_insensitive(&mut self, yes: bool) -> &mut WalkBuilder { + self.ig_builder.ignore_case_insensitive(yes); + self + } + + /// Set a function for sorting directory entries by their path. + /// + /// If a compare function is set, the resulting iterator will return all + /// paths in sorted order. The compare function will be called to compare + /// entries from the same directory. + /// + /// This is like `sort_by_file_name`, except the comparator accepts + /// a `&Path` instead of the base file name, which permits it to sort by + /// more criteria. + /// + /// This method will override any previous sorter set by this method or + /// by `sort_by_file_name`. + /// + /// Note that this is not used in the parallel iterator. + pub fn sort_by_file_path( + &mut self, + cmp: F, + ) -> &mut WalkBuilder + where F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static + { + self.sorter = Some(Sorter::ByPath(Arc::new(cmp))); + self + } + + /// Set a function for sorting directory entries by file name. + /// + /// If a compare function is set, the resulting iterator will return all + /// paths in sorted order. The compare function will be called to compare + /// names from entries from the same directory using only the name of the + /// entry. + /// + /// This method will override any previous sorter set by this method or + /// by `sort_by_file_path`. + /// + /// Note that this is not used in the parallel iterator. + pub fn sort_by_file_name(&mut self, cmp: F) -> &mut WalkBuilder + where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static + { + self.sorter = Some(Sorter::ByName(Arc::new(cmp))); + self + } + + /// Do not cross file system boundaries. + /// + /// When this option is enabled, directory traversal will not descend into + /// directories that are on a different file system from the root path. + /// + /// Currently, this option is only supported on Unix and Windows. If this + /// option is used on an unsupported platform, then directory traversal + /// will immediately return an error and will not yield any entries. + pub fn same_file_system(&mut self, yes: bool) -> &mut WalkBuilder { + self.same_file_system = yes; + self + } + + /// Do not yield directory entries that are believed to correspond to + /// stdout. + /// + /// This is useful when a command is invoked via shell redirection to a + /// file that is also being read. For example, `grep -r foo ./ > results` + /// might end up trying to search `results` even though it is also writing + /// to it, which could cause an unbounded feedback loop. Setting this + /// option prevents this from happening by skipping over the `results` + /// file. + /// + /// This is disabled by default. + pub fn skip_stdout(&mut self, yes: bool) -> &mut WalkBuilder { + if yes { + self.skip = stdout_handle().map(Arc::new); + } else { + self.skip = None; + } + self + } +} + +/// Walk is a recursive directory iterator over file paths in one or more +/// directories. +/// +/// Only file and directory paths matching the rules are returned. By default, +/// ignore files like `.gitignore` are respected. The precise matching rules +/// and precedence is explained in the documentation for `WalkBuilder`. +pub struct Walk { + its: vec::IntoIter<(PathBuf, Option)>, + it: Option, + ig_root: Ignore, + ig: Ignore, + max_filesize: Option, + skip: Option>, +} + +impl Walk { + /// Creates a new recursive directory iterator for the file path given. + /// + /// Note that this uses default settings, which include respecting + /// `.gitignore` files. To configure the iterator, use `WalkBuilder` + /// instead. + pub fn new>(path: P) -> Walk { + WalkBuilder::new(path).build() + } + + fn skip_entry(&self, ent: &DirEntry) -> Result { + if ent.depth() == 0 { + return Ok(false); + } + + if let Some(ref stdout) = self.skip { + if path_equals(ent, stdout)? { + return Ok(true); + } + } + if should_skip_entry(&self.ig, ent) { + return Ok(true); + } + if self.max_filesize.is_some() && !ent.is_dir() { + return Ok(skip_filesize( + self.max_filesize.unwrap(), + ent.path(), + &ent.metadata().ok(), + )); + } + Ok(false) + } +} + +impl Iterator for Walk { + type Item = Result; + + #[inline(always)] + fn next(&mut self) -> Option> { + loop { + let ev = match self.it.as_mut().and_then(|it| it.next()) { + Some(ev) => ev, + None => { + match self.its.next() { + None => return None, + Some((_, None)) => { + return Some(Ok(DirEntry::new_stdin())); + } + Some((path, Some(it))) => { + self.it = Some(it); + if path.is_dir() { + let (ig, err) = self.ig_root.add_parents(path); + self.ig = ig; + if let Some(err) = err { + return Some(Err(err)); + } + } else { + self.ig = self.ig_root.clone(); + } + } + } + continue; + } + }; + match ev { + Err(err) => { + return Some(Err(Error::from_walkdir(err))); + } + Ok(WalkEvent::Exit) => { + self.ig = self.ig.parent().unwrap(); + } + Ok(WalkEvent::Dir(ent)) => { + let mut ent = DirEntry::new_walkdir(ent, None); + let should_skip = match self.skip_entry(&ent) { + Err(err) => return Some(Err(err)), + Ok(should_skip) => should_skip, + }; + if should_skip { + self.it.as_mut().unwrap().it.skip_current_dir(); + // Still need to push this on the stack because + // we'll get a WalkEvent::Exit event for this dir. + // We don't care if it errors though. + let (igtmp, _) = self.ig.add_child(ent.path()); + self.ig = igtmp; + continue; + } + let (igtmp, err) = self.ig.add_child(ent.path()); + self.ig = igtmp; + ent.err = err; + return Some(Ok(ent)); + } + Ok(WalkEvent::File(ent)) => { + let ent = DirEntry::new_walkdir(ent, None); + let should_skip = match self.skip_entry(&ent) { + Err(err) => return Some(Err(err)), + Ok(should_skip) => should_skip, + }; + if should_skip { + continue; + } + return Some(Ok(ent)); + } + } + } + } +} + +/// WalkEventIter transforms a WalkDir iterator into an iterator that more +/// accurately describes the directory tree. Namely, it emits events that are +/// one of three types: directory, file or "exit." An "exit" event means that +/// the entire contents of a directory have been enumerated. +struct WalkEventIter { + depth: usize, + it: walkdir::IntoIter, + next: Option>, +} + +#[derive(Debug)] +enum WalkEvent { + Dir(walkdir::DirEntry), + File(walkdir::DirEntry), + Exit, +} + +impl From for WalkEventIter { + fn from(it: WalkDir) -> WalkEventIter { + WalkEventIter { depth: 0, it: it.into_iter(), next: None } + } +} + +impl Iterator for WalkEventIter { + type Item = walkdir::Result; + + #[inline(always)] + fn next(&mut self) -> Option> { + let dent = self.next.take().or_else(|| self.it.next()); + let depth = match dent { + None => 0, + Some(Ok(ref dent)) => dent.depth(), + Some(Err(ref err)) => err.depth(), + }; + if depth < self.depth { + self.depth -= 1; + self.next = dent; + return Some(Ok(WalkEvent::Exit)); + } + self.depth = depth; + match dent { + None => None, + Some(Err(err)) => Some(Err(err)), + Some(Ok(dent)) => { + if dent.file_type().is_dir() { + self.depth += 1; + Some(Ok(WalkEvent::Dir(dent))) + } else { + Some(Ok(WalkEvent::File(dent))) + } + } + } + } +} + +/// WalkState is used in the parallel recursive directory iterator to indicate +/// whether walking should continue as normal, skip descending into a +/// particular directory or quit the walk entirely. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum WalkState { + /// Continue walking as normal. + Continue, + /// If the directory entry given is a directory, don't descend into it. + /// In all other cases, this has no effect. + Skip, + /// Quit the entire iterator as soon as possible. + /// + /// Note that this is an inherently asynchronous action. It is possible + /// for more entries to be yielded even after instructing the iterator + /// to quit. + Quit, +} + +impl WalkState { + fn is_quit(&self) -> bool { + *self == WalkState::Quit + } +} + +/// WalkParallel is a parallel recursive directory iterator over files paths +/// in one or more directories. +/// +/// Only file and directory paths matching the rules are returned. By default, +/// ignore files like `.gitignore` are respected. The precise matching rules +/// and precedence is explained in the documentation for `WalkBuilder`. +/// +/// Unlike `Walk`, this uses multiple threads for traversing a directory. +pub struct WalkParallel { + paths: vec::IntoIter, + ig_root: Ignore, + max_filesize: Option, + max_depth: Option, + follow_links: bool, + same_file_system: bool, + threads: usize, + skip: Option>, +} + +impl WalkParallel { + /// Execute the parallel recursive directory iterator. `mkf` is called + /// for each thread used for iteration. The function produced by `mkf` + /// is then in turn called for each visited file path. + pub fn run( + self, + mut mkf: F, + ) where F: FnMut() -> Box) -> WalkState + Send + 'static> { + let mut f = mkf(); + let threads = self.threads(); + // TODO: Figure out how to use a bounded channel here. With an + // unbounded channel, the workers can run away and fill up memory + // with all of the file paths. But a bounded channel doesn't work since + // our producers are also are consumers, so they end up getting stuck. + // + // We probably need to rethink parallel traversal completely to fix + // this. The best case scenario would be finding a way to use rayon + // to do this. + let (tx, rx) = channel::unbounded(); + let mut any_work = false; + // Send the initial set of root paths to the pool of workers. + // Note that we only send directories. For files, we send to them the + // callback directly. + for path in self.paths { + let (dent, root_device) = + if path == Path::new("-") { + (DirEntry::new_stdin(), None) + } else { + let root_device = + if !self.same_file_system { + None + } else { + match device_num(&path) { + Ok(root_device) => Some(root_device), + Err(err) => { + let err = Error::Io(err).with_path(path); + if f(Err(err)).is_quit() { + return; + } + continue; + } + } + }; + match DirEntryRaw::from_path(0, path, false) { + Ok(dent) => { + (DirEntry::new_raw(dent, None), root_device) + } + Err(err) => { + if f(Err(err)).is_quit() { + return; + } + continue; + } + } + }; + tx.send(Message::Work(Work { + dent: dent, + ignore: self.ig_root.clone(), + root_device: root_device, + })).unwrap(); + any_work = true; + } + // ... but there's no need to start workers if we don't need them. + if !any_work { + return; + } + // Create the workers and then wait for them to finish. + let num_waiting = Arc::new(AtomicUsize::new(0)); + let num_quitting = Arc::new(AtomicUsize::new(0)); + let quit_now = Arc::new(AtomicBool::new(false)); + let mut handles = vec![]; + for _ in 0..threads { + let worker = Worker { + f: mkf(), + tx: tx.clone(), + rx: rx.clone(), + quit_now: quit_now.clone(), + is_waiting: false, + is_quitting: false, + num_waiting: num_waiting.clone(), + num_quitting: num_quitting.clone(), + threads: threads, + max_depth: self.max_depth, + max_filesize: self.max_filesize, + follow_links: self.follow_links, + skip: self.skip.clone(), + }; + handles.push(thread::spawn(|| worker.run())); + } + drop(tx); + drop(rx); + for handle in handles { + handle.join().unwrap(); + } + } + + fn threads(&self) -> usize { + if self.threads == 0 { + 2 + } else { + self.threads + } + } +} + +/// Message is the set of instructions that a worker knows how to process. +enum Message { + /// A work item corresponds to a directory that should be descended into. + /// Work items for entries that should be skipped or ignored should not + /// be produced. + Work(Work), + /// This instruction indicates that the worker should start quitting. + Quit, +} + +/// A unit of work for each worker to process. +/// +/// Each unit of work corresponds to a directory that should be descended +/// into. +struct Work { + /// The directory entry. + dent: DirEntry, + /// Any ignore matchers that have been built for this directory's parents. + ignore: Ignore, + /// The root device number. When present, only files with the same device + /// number should be considered. + root_device: Option, +} + +impl Work { + /// Returns true if and only if this work item is a directory. + fn is_dir(&self) -> bool { + self.dent.is_dir() + } + + /// Returns true if and only if this work item is a symlink. + fn is_symlink(&self) -> bool { + self.dent.file_type().map_or(false, |ft| ft.is_symlink()) + } + + /// Adds ignore rules for parent directories. + /// + /// Note that this only applies to entries at depth 0. On all other + /// entries, this is a no-op. + fn add_parents(&mut self) -> Option { + if self.dent.depth() > 0 { + return None; + } + // At depth 0, the path of this entry is a root path, so we can + // use it directly to add parent ignore rules. + let (ig, err) = self.ignore.add_parents(self.dent.path()); + self.ignore = ig; + err + } + + /// Reads the directory contents of this work item and adds ignore + /// rules for this directory. + /// + /// If there was a problem with reading the directory contents, then + /// an error is returned. If there was a problem reading the ignore + /// rules for this directory, then the error is attached to this + /// work item's directory entry. + fn read_dir(&mut self) -> Result { + let readdir = match fs::read_dir(self.dent.path()) { + Ok(readdir) => readdir, + Err(err) => { + let err = Error::from(err) + .with_path(self.dent.path()) + .with_depth(self.dent.depth()); + return Err(err); + } + }; + let (ig, err) = self.ignore.add_child(self.dent.path()); + self.ignore = ig; + self.dent.err = err; + Ok(readdir) + } +} + +/// A worker is responsible for descending into directories, updating the +/// ignore matchers, producing new work and invoking the caller's callback. +/// +/// Note that a worker is *both* a producer and a consumer. +struct Worker { + /// The caller's callback. + f: Box) -> WalkState + Send + 'static>, + /// The push side of our mpmc queue. + tx: channel::Sender, + /// The receive side of our mpmc queue. + rx: channel::Receiver, + /// Whether all workers should quit at the next opportunity. Note that + /// this is distinct from quitting because of exhausting the contents of + /// a directory. Instead, this is used when the caller's callback indicates + /// that the iterator should quit immediately. + quit_now: Arc, + /// Whether this worker is waiting for more work. + is_waiting: bool, + /// Whether this worker has started to quit. + is_quitting: bool, + /// The number of workers waiting for more work. + num_waiting: Arc, + /// The number of workers waiting to quit. + num_quitting: Arc, + /// The total number of workers. + threads: usize, + /// The maximum depth of directories to descend. A value of `0` means no + /// descension at all. + max_depth: Option, + /// The maximum size a searched file can be (in bytes). If a file exceeds + /// this size it will be skipped. + max_filesize: Option, + /// Whether to follow symbolic links or not. When this is enabled, loop + /// detection is performed. + follow_links: bool, + /// A file handle to skip, currently is either `None` or stdout, if it's + /// a file and it has been requested to skip files identical to stdout. + skip: Option>, +} + +impl Worker { + /// Runs this worker until there is no more work left to do. + /// + /// The worker will call the caller's callback for all entries that aren't + /// skipped by the ignore matcher. + fn run(mut self) { + while let Some(mut work) = self.get_work() { + // If the work is not a directory, then we can just execute the + // caller's callback immediately and move on. + if work.is_symlink() || !work.is_dir() { + if (self.f)(Ok(work.dent)).is_quit() { + self.quit_now(); + return; + } + continue; + } + if let Some(err) = work.add_parents() { + if (self.f)(Err(err)).is_quit() { + self.quit_now(); + return; + } + } + let readdir = match work.read_dir() { + Ok(readdir) => readdir, + Err(err) => { + if (self.f)(Err(err)).is_quit() { + self.quit_now(); + return; + } + continue; + } + }; + let descend = + if let Some(root_device) = work.root_device { + match is_same_file_system(root_device, work.dent.path()) { + Ok(true) => true, + Ok(false) => false, + Err(err) => { + if (self.f)(Err(err)).is_quit() { + self.quit_now(); + return; + } + false + } + } + } else { + true + }; + + let depth = work.dent.depth(); + match (self.f)(Ok(work.dent)) { + WalkState::Continue => {} + WalkState::Skip => continue, + WalkState::Quit => { + self.quit_now(); + return; + } + } + if !descend { + continue; + } + if self.max_depth.map_or(false, |max| depth >= max) { + continue; + } + for result in readdir { + let state = self.run_one( + &work.ignore, + depth + 1, + work.root_device, + result, + ); + if state.is_quit() { + self.quit_now(); + return; + } + } + } + } + + /// Runs the worker on a single entry from a directory iterator. + /// + /// If the entry is a path that should be ignored, then this is a no-op. + /// Otherwise, the entry is pushed on to the queue. (The actual execution + /// of the callback happens in `run`.) + /// + /// If an error occurs while reading the entry, then it is sent to the + /// caller's callback. + /// + /// `ig` is the `Ignore` matcher for the parent directory. `depth` should + /// be the depth of this entry. `result` should be the item yielded by + /// a directory iterator. + fn run_one( + &mut self, + ig: &Ignore, + depth: usize, + root_device: Option, + result: Result, + ) -> WalkState { + let fs_dent = match result { + Ok(fs_dent) => fs_dent, + Err(err) => { + return (self.f)(Err(Error::from(err).with_depth(depth))); + } + }; + let mut dent = match DirEntryRaw::from_entry(depth, &fs_dent) { + Ok(dent) => DirEntry::new_raw(dent, None), + Err(err) => { + return (self.f)(Err(err)); + } + }; + let is_symlink = dent.file_type().map_or(false, |ft| ft.is_symlink()); + if self.follow_links && is_symlink { + let path = dent.path().to_path_buf(); + dent = match DirEntryRaw::from_path(depth, path, true) { + Ok(dent) => DirEntry::new_raw(dent, None), + Err(err) => { + return (self.f)(Err(err)); + } + }; + if dent.is_dir() { + if let Err(err) = check_symlink_loop(ig, dent.path(), depth) { + return (self.f)(Err(err)); + } + } + } + if let Some(ref stdout) = self.skip { + let is_stdout = match path_equals(&dent, stdout) { + Ok(is_stdout) => is_stdout, + Err(err) => return (self.f)(Err(err)), + }; + if is_stdout { + return WalkState::Continue; + } + } + let should_skip_path = should_skip_entry(ig, &dent); + let should_skip_filesize = + if self.max_filesize.is_some() && !dent.is_dir() { + skip_filesize( + self.max_filesize.unwrap(), + dent.path(), + &dent.metadata().ok(), + ) + } else { + false + }; + + if !should_skip_path && !should_skip_filesize { + self.tx.send(Message::Work(Work { + dent: dent, + ignore: ig.clone(), + root_device: root_device, + })).unwrap(); + } + WalkState::Continue + } + + /// Returns the next directory to descend into. + /// + /// If all work has been exhausted, then this returns None. The worker + /// should then subsequently quit. + fn get_work(&mut self) -> Option { + loop { + if self.is_quit_now() { + return None; + } + match self.rx.try_recv() { + Ok(Message::Work(work)) => { + self.waiting(false); + self.quitting(false); + return Some(work); + } + Ok(Message::Quit) => { + // We can't just quit because a Message::Quit could be + // spurious. For example, it's possible to observe that + // all workers are waiting even if there's more work to + // be done. + // + // Therefore, we do a bit of a dance to wait until all + // workers have signaled that they're ready to quit before + // actually quitting. + // + // If the Quit message turns out to be spurious, then the + // loop below will break and we'll go back to looking for + // more work. + self.waiting(true); + self.quitting(true); + while !self.is_quit_now() { + let nwait = self.num_waiting(); + let nquit = self.num_quitting(); + // If the number of waiting workers dropped, then + // abort our attempt to quit. + if nwait < self.threads { + break; + } + // If all workers are in this quit loop, then we + // can stop. + if nquit == self.threads { + return None; + } + // Otherwise, spin. + } + } + Err(_) => { + self.waiting(true); + self.quitting(false); + if self.num_waiting() == self.threads { + for _ in 0..self.threads { + self.tx.send(Message::Quit).unwrap(); + } + } else { + // You're right to consider this suspicious, but it's + // a useful heuristic to permit producers to catch up + // to consumers without burning the CPU. It is also + // useful as a means to prevent burning the CPU if only + // one worker is left doing actual work. It's not + // perfect and it doesn't leave the CPU completely + // idle, but it's not clear what else we can do. :-/ + thread::sleep(Duration::from_millis(1)); + } + } + } + } + } + + /// Indicates that all workers should quit immediately. + fn quit_now(&self) { + self.quit_now.store(true, Ordering::SeqCst); + } + + /// Returns true if this worker should quit immediately. + fn is_quit_now(&self) -> bool { + self.quit_now.load(Ordering::SeqCst) + } + + /// Returns the total number of workers waiting for work. + fn num_waiting(&self) -> usize { + self.num_waiting.load(Ordering::SeqCst) + } + + /// Returns the total number of workers ready to quit. + fn num_quitting(&self) -> usize { + self.num_quitting.load(Ordering::SeqCst) + } + + /// Sets this worker's "quitting" state to the value of `yes`. + fn quitting(&mut self, yes: bool) { + if yes { + if !self.is_quitting { + self.is_quitting = true; + self.num_quitting.fetch_add(1, Ordering::SeqCst); + } + } else { + if self.is_quitting { + self.is_quitting = false; + self.num_quitting.fetch_sub(1, Ordering::SeqCst); + } + } + } + + /// Sets this worker's "waiting" state to the value of `yes`. + fn waiting(&mut self, yes: bool) { + if yes { + if !self.is_waiting { + self.is_waiting = true; + self.num_waiting.fetch_add(1, Ordering::SeqCst); + } + } else { + if self.is_waiting { + self.is_waiting = false; + self.num_waiting.fetch_sub(1, Ordering::SeqCst); + } + } + } +} + +fn check_symlink_loop( + ig_parent: &Ignore, + child_path: &Path, + child_depth: usize, +) -> Result<(), Error> { + let hchild = Handle::from_path(child_path).map_err(|err| { + Error::from(err).with_path(child_path).with_depth(child_depth) + })?; + for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_parent()) { + let h = Handle::from_path(ig.path()).map_err(|err| { + Error::from(err).with_path(child_path).with_depth(child_depth) + })?; + if hchild == h { + return Err(Error::Loop { + ancestor: ig.path().to_path_buf(), + child: child_path.to_path_buf(), + }.with_depth(child_depth)); + } + } + Ok(()) +} + +// Before calling this function, make sure that you ensure that is really +// necessary as the arguments imply a file stat. +fn skip_filesize( + max_filesize: u64, + path: &Path, + ent: &Option +) -> bool { + let filesize = match *ent { + Some(ref md) => Some(md.len()), + None => None + }; + + if let Some(fs) = filesize { + if fs > max_filesize { + debug!("ignoring {}: {} bytes", path.display(), fs); + true + } else { + false + } + } else { + false + } +} + +fn should_skip_entry( + ig: &Ignore, + dent: &DirEntry, +) -> bool { + let m = ig.matched_dir_entry(dent); + if m.is_ignore() { + debug!("ignoring {}: {:?}", dent.path().display(), m); + true + } else if m.is_whitelist() { + debug!("whitelisting {}: {:?}", dent.path().display(), m); + false + } else { + false + } +} + +/// Returns a handle to stdout for filtering search. +/// +/// A handle is returned if and only if stdout is being redirected to a file. +/// The handle returned corresponds to that file. +/// +/// This can be used to ensure that we do not attempt to search a file that we +/// may also be writing to. +fn stdout_handle() -> Option { + let h = match Handle::stdout() { + Err(_) => return None, + Ok(h) => h, + }; + let md = match h.as_file().metadata() { + Err(_) => return None, + Ok(md) => md, + }; + if !md.is_file() { + return None; + } + Some(h) +} + +/// Returns true if and only if the given directory entry is believed to be +/// equivalent to the given handle. If there was a problem querying the path +/// for information to determine equality, then that error is returned. +fn path_equals(dent: &DirEntry, handle: &Handle) -> Result { + #[cfg(unix)] + fn never_equal(dent: &DirEntry, handle: &Handle) -> bool { + dent.ino() != Some(handle.ino()) + } + + #[cfg(not(unix))] + fn never_equal(_: &DirEntry, _: &Handle) -> bool { + false + } + + // If we know for sure that these two things aren't equal, then avoid + // the costly extra stat call to determine equality. + if dent.is_stdin() || never_equal(dent, handle) { + return Ok(false); + } + Handle::from_path(dent.path()) + .map(|h| &h == handle) + .map_err(|err| Error::Io(err).with_path(dent.path())) +} + +/// Returns true if and only if the given path is on the same device as the +/// given root device. +fn is_same_file_system(root_device: u64, path: &Path) -> Result { + let dent_device = device_num(path) + .map_err(|err| Error::Io(err).with_path(path))?; + Ok(root_device == dent_device) +} + +#[cfg(unix)] +fn device_num>(path: P)-> io::Result { + use std::os::unix::fs::MetadataExt; + + path.as_ref().metadata().map(|md| md.dev()) +} + + #[cfg(windows)] +fn device_num>(path: P) -> io::Result { + use winapi_util::{Handle, file}; + + let h = Handle::from_path_any(path)?; + file::information(h).map(|info| info.volume_serial_number()) +} + +#[cfg(not(any(unix, windows)))] +fn device_num>(_: P)-> io::Result { + Err(io::Error::new( + io::ErrorKind::Other, + "walkdir: same_file_system option not supported on this platform", + )) +} + +#[cfg(test)] +mod tests { + use std::fs::{self, File}; + use std::io::Write; + use std::path::Path; + use std::sync::{Arc, Mutex}; + + use tempfile::{self, TempDir}; + + use super::{DirEntry, WalkBuilder, WalkState}; + + fn wfile>(path: P, contents: &str) { + let mut file = File::create(path).unwrap(); + file.write_all(contents.as_bytes()).unwrap(); + } + + fn wfile_size>(path: P, size: u64) { + let file = File::create(path).unwrap(); + file.set_len(size).unwrap(); + } + + #[cfg(unix)] + fn symlink, Q: AsRef>(src: P, dst: Q) { + use std::os::unix::fs::symlink; + symlink(src, dst).unwrap(); + } + + fn mkdirp>(path: P) { + fs::create_dir_all(path).unwrap(); + } + + fn normal_path(unix: &str) -> String { + if cfg!(windows) { + unix.replace("\\", "/") + } else { + unix.to_string() + } + } + + fn walk_collect(prefix: &Path, builder: &WalkBuilder) -> Vec { + let mut paths = vec![]; + for result in builder.build() { + let dent = match result { + Err(_) => continue, + Ok(dent) => dent, + }; + let path = dent.path().strip_prefix(prefix).unwrap(); + if path.as_os_str().is_empty() { + continue; + } + paths.push(normal_path(path.to_str().unwrap())); + } + paths.sort(); + paths + } + + fn walk_collect_parallel( + prefix: &Path, + builder: &WalkBuilder, + ) -> Vec { + let mut paths = vec![]; + for dent in walk_collect_entries_parallel(builder) { + let path = dent.path().strip_prefix(prefix).unwrap(); + if path.as_os_str().is_empty() { + continue; + } + paths.push(normal_path(path.to_str().unwrap())); + } + paths.sort(); + paths + } + + fn walk_collect_entries_parallel(builder: &WalkBuilder) -> Vec { + let dents = Arc::new(Mutex::new(vec![])); + builder.build_parallel().run(|| { + let dents = dents.clone(); + Box::new(move |result| { + if let Ok(dent) = result { + dents.lock().unwrap().push(dent); + } + WalkState::Continue + }) + }); + + let dents = dents.lock().unwrap(); + dents.to_vec() + } + + fn mkpaths(paths: &[&str]) -> Vec { + let mut paths: Vec<_> = paths.iter().map(|s| s.to_string()).collect(); + paths.sort(); + paths + } + + fn tmpdir(prefix: &str) -> TempDir { + tempfile::Builder::new().prefix(prefix).tempdir().unwrap() + } + + fn assert_paths( + prefix: &Path, + builder: &WalkBuilder, + expected: &[&str], + ) { + let got = walk_collect(prefix, builder); + assert_eq!(got, mkpaths(expected), "single threaded"); + let got = walk_collect_parallel(prefix, builder); + assert_eq!(got, mkpaths(expected), "parallel"); + } + + #[test] + fn no_ignores() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("a/b/c")); + mkdirp(td.path().join("x/y")); + wfile(td.path().join("a/b/foo"), ""); + wfile(td.path().join("x/y/foo"), ""); + + assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ + "x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c", + ]); + } + + #[test] + fn custom_ignore() { + let td = tmpdir("walk-test-"); + let custom_ignore = ".customignore"; + mkdirp(td.path().join("a")); + wfile(td.path().join(custom_ignore), "foo"); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("bar"), ""); + wfile(td.path().join("a/bar"), ""); + + let mut builder = WalkBuilder::new(td.path()); + builder.add_custom_ignore_filename(&custom_ignore); + assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); + } + + #[test] + fn custom_ignore_exclusive_use() { + let td = tmpdir("walk-test-"); + let custom_ignore = ".customignore"; + mkdirp(td.path().join("a")); + wfile(td.path().join(custom_ignore), "foo"); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("bar"), ""); + wfile(td.path().join("a/bar"), ""); + + let mut builder = WalkBuilder::new(td.path()); + builder.ignore(false); + builder.git_ignore(false); + builder.git_global(false); + builder.git_exclude(false); + builder.add_custom_ignore_filename(&custom_ignore); + assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); + } + + #[test] + fn gitignore() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join(".git")); + mkdirp(td.path().join("a")); + wfile(td.path().join(".gitignore"), "foo"); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("bar"), ""); + wfile(td.path().join("a/bar"), ""); + + assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ + "bar", "a", "a/bar", + ]); + } + + #[test] + fn explicit_ignore() { + let td = tmpdir("walk-test-"); + let igpath = td.path().join(".not-an-ignore"); + mkdirp(td.path().join("a")); + wfile(&igpath, "foo"); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("bar"), ""); + wfile(td.path().join("a/bar"), ""); + + let mut builder = WalkBuilder::new(td.path()); + assert!(builder.add_ignore(&igpath).is_none()); + assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); + } + + #[test] + fn explicit_ignore_exclusive_use() { + let td = tmpdir("walk-test-"); + let igpath = td.path().join(".not-an-ignore"); + mkdirp(td.path().join("a")); + wfile(&igpath, "foo"); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("bar"), ""); + wfile(td.path().join("a/bar"), ""); + + let mut builder = WalkBuilder::new(td.path()); + builder.standard_filters(false); + assert!(builder.add_ignore(&igpath).is_none()); + assert_paths(td.path(), &builder, + &[".not-an-ignore", "bar", "a", "a/bar"]); + } + + #[test] + fn gitignore_parent() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join(".git")); + mkdirp(td.path().join("a")); + wfile(td.path().join(".gitignore"), "foo"); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("a/bar"), ""); + + let root = td.path().join("a"); + assert_paths(&root, &WalkBuilder::new(&root), &["bar"]); + } + + #[test] + fn max_depth() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("a/b/c")); + wfile(td.path().join("foo"), ""); + wfile(td.path().join("a/foo"), ""); + wfile(td.path().join("a/b/foo"), ""); + wfile(td.path().join("a/b/c/foo"), ""); + + let mut builder = WalkBuilder::new(td.path()); + assert_paths(td.path(), &builder, &[ + "a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo", + ]); + assert_paths(td.path(), builder.max_depth(Some(0)), &[]); + assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]); + assert_paths(td.path(), builder.max_depth(Some(2)), &[ + "a", "a/b", "foo", "a/foo", + ]); + } + + #[test] + fn max_filesize() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("a/b")); + wfile_size(td.path().join("foo"), 0); + wfile_size(td.path().join("bar"), 400); + wfile_size(td.path().join("baz"), 600); + wfile_size(td.path().join("a/foo"), 600); + wfile_size(td.path().join("a/bar"), 500); + wfile_size(td.path().join("a/baz"), 200); + + let mut builder = WalkBuilder::new(td.path()); + assert_paths(td.path(), &builder, &[ + "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", + ]); + assert_paths(td.path(), builder.max_filesize(Some(0)), &[ + "a", "a/b", "foo" + ]); + assert_paths(td.path(), builder.max_filesize(Some(500)), &[ + "a", "a/b", "foo", "bar", "a/bar", "a/baz" + ]); + assert_paths(td.path(), builder.max_filesize(Some(50000)), &[ + "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", + ]); + } + + #[cfg(unix)] // because symlinks on windows are weird + #[test] + fn symlinks() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("a/b")); + symlink(td.path().join("a/b"), td.path().join("z")); + wfile(td.path().join("a/b/foo"), ""); + + let mut builder = WalkBuilder::new(td.path()); + assert_paths(td.path(), &builder, &[ + "a", "a/b", "a/b/foo", "z", + ]); + assert_paths(td.path(), &builder.follow_links(true), &[ + "a", "a/b", "a/b/foo", "z", "z/foo", + ]); + } + + #[cfg(unix)] // because symlinks on windows are weird + #[test] + fn first_path_not_symlink() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("foo")); + + let dents = WalkBuilder::new(td.path().join("foo")) + .build() + .into_iter() + .collect::, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); + + let dents = walk_collect_entries_parallel( + &WalkBuilder::new(td.path().join("foo")), + ); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); + } + + #[cfg(unix)] // because symlinks on windows are weird + #[test] + fn symlink_loop() { + let td = tmpdir("walk-test-"); + mkdirp(td.path().join("a/b")); + symlink(td.path().join("a"), td.path().join("a/b/c")); + + let mut builder = WalkBuilder::new(td.path()); + assert_paths(td.path(), &builder, &[ + "a", "a/b", "a/b/c", + ]); + assert_paths(td.path(), &builder.follow_links(true), &[ + "a", "a/b", + ]); + } + + // It's a little tricky to test the 'same_file_system' option since + // we need an environment with more than one file system. We adopt a + // heuristic where /sys is typically a distinct volume on Linux and roll + // with that. + #[test] + #[cfg(target_os = "linux")] + fn same_file_system() { + use super::device_num; + + // If for some reason /sys doesn't exist or isn't a directory, just + // skip this test. + if !Path::new("/sys").is_dir() { + return; + } + + // If our test directory actually isn't a different volume from /sys, + // then this test is meaningless and we shouldn't run it. + let td = tmpdir("walk-test-"); + if device_num(td.path()).unwrap() == device_num("/sys").unwrap() { + return; + } + + mkdirp(td.path().join("same_file")); + symlink("/sys", td.path().join("same_file").join("alink")); + + // Create a symlink to sys and enable following symlinks. If the + // same_file_system option doesn't work, then this probably will hit a + // permission error. Otherwise, it should just skip over the symlink + // completely. + let mut builder = WalkBuilder::new(td.path()); + builder.follow_links(true).same_file_system(true); + assert_paths(td.path(), &builder, &[ + "same_file", "same_file/alink", + ]); + } +} diff --git a/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore b/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore new file mode 100644 index 000000000..ac09e12f7 --- /dev/null +++ b/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore @@ -0,0 +1,216 @@ +# Based on https://github.com/behnam/gitignore-test/blob/master/.gitignore + +### file in root + +# MATCH /file_root_1 +file_root_00 + +# NO_MATCH +file_root_01/ + +# NO_MATCH +file_root_02/* + +# NO_MATCH +file_root_03/** + + +# MATCH /file_root_10 +/file_root_10 + +# NO_MATCH +/file_root_11/ + +# NO_MATCH +/file_root_12/* + +# NO_MATCH +/file_root_13/** + + +# NO_MATCH +*/file_root_20 + +# NO_MATCH +*/file_root_21/ + +# NO_MATCH +*/file_root_22/* + +# NO_MATCH +*/file_root_23/** + + +# MATCH /file_root_30 +**/file_root_30 + +# NO_MATCH +**/file_root_31/ + +# NO_MATCH +**/file_root_32/* + +# NO_MATCH +**/file_root_33/** + + +### file in sub-dir + +# MATCH /parent_dir/file_deep_1 +file_deep_00 + +# NO_MATCH +file_deep_01/ + +# NO_MATCH +file_deep_02/* + +# NO_MATCH +file_deep_03/** + + +# NO_MATCH +/file_deep_10 + +# NO_MATCH +/file_deep_11/ + +# NO_MATCH +/file_deep_12/* + +# NO_MATCH +/file_deep_13/** + + +# MATCH /parent_dir/file_deep_20 +*/file_deep_20 + +# NO_MATCH +*/file_deep_21/ + +# NO_MATCH +*/file_deep_22/* + +# NO_MATCH +*/file_deep_23/** + + +# MATCH /parent_dir/file_deep_30 +**/file_deep_30 + +# NO_MATCH +**/file_deep_31/ + +# NO_MATCH +**/file_deep_32/* + +# NO_MATCH +**/file_deep_33/** + + +### dir in root + +# MATCH /dir_root_00 +dir_root_00 + +# MATCH /dir_root_01 +dir_root_01/ + +# MATCH /dir_root_02 +dir_root_02/* + +# MATCH /dir_root_03 +dir_root_03/** + + +# MATCH /dir_root_10 +/dir_root_10 + +# MATCH /dir_root_11 +/dir_root_11/ + +# MATCH /dir_root_12 +/dir_root_12/* + +# MATCH /dir_root_13 +/dir_root_13/** + + +# NO_MATCH +*/dir_root_20 + +# NO_MATCH +*/dir_root_21/ + +# NO_MATCH +*/dir_root_22/* + +# NO_MATCH +*/dir_root_23/** + + +# MATCH /dir_root_30 +**/dir_root_30 + +# MATCH /dir_root_31 +**/dir_root_31/ + +# MATCH /dir_root_32 +**/dir_root_32/* + +# MATCH /dir_root_33 +**/dir_root_33/** + + +### dir in sub-dir + +# MATCH /parent_dir/dir_deep_00 +dir_deep_00 + +# MATCH /parent_dir/dir_deep_01 +dir_deep_01/ + +# NO_MATCH +dir_deep_02/* + +# NO_MATCH +dir_deep_03/** + + +# NO_MATCH +/dir_deep_10 + +# NO_MATCH +/dir_deep_11/ + +# NO_MATCH +/dir_deep_12/* + +# NO_MATCH +/dir_deep_13/** + + +# MATCH /parent_dir/dir_deep_20 +*/dir_deep_20 + +# MATCH /parent_dir/dir_deep_21 +*/dir_deep_21/ + +# MATCH /parent_dir/dir_deep_22 +*/dir_deep_22/* + +# MATCH /parent_dir/dir_deep_23 +*/dir_deep_23/** + + +# MATCH /parent_dir/dir_deep_30 +**/dir_deep_30 + +# MATCH /parent_dir/dir_deep_31 +**/dir_deep_31/ + +# MATCH /parent_dir/dir_deep_32 +**/dir_deep_32/* + +# MATCH /parent_dir/dir_deep_33 +**/dir_deep_33/** diff --git a/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs b/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs new file mode 100644 index 000000000..28d8e2f84 --- /dev/null +++ b/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs @@ -0,0 +1,323 @@ +extern crate ignore; + +use std::path::Path; + +use ignore::gitignore::{Gitignore, GitignoreBuilder}; + +const IGNORE_FILE: &'static str = + "tests/gitignore_matched_path_or_any_parents_tests.gitignore"; + +fn get_gitignore() -> Gitignore { + let mut builder = GitignoreBuilder::new("ROOT"); + let error = builder.add(IGNORE_FILE); + assert!(error.is_none(), "failed to open gitignore file"); + builder.build().unwrap() +} + +#[test] +#[should_panic(expected = "path is expected to be under the root")] +fn test_path_should_be_under_root() { + let gitignore = get_gitignore(); + let path = "/tmp/some_file"; + gitignore.matched_path_or_any_parents(Path::new(path), false); + assert!(false); +} + +#[test] +fn test_files_in_root() { + let gitignore = get_gitignore(); + let m = |path: &str| { + gitignore.matched_path_or_any_parents(Path::new(path), false) + }; + + // 0x + assert!(m("ROOT/file_root_00").is_ignore()); + assert!(m("ROOT/file_root_01").is_none()); + assert!(m("ROOT/file_root_02").is_none()); + assert!(m("ROOT/file_root_03").is_none()); + + // 1x + assert!(m("ROOT/file_root_10").is_ignore()); + assert!(m("ROOT/file_root_11").is_none()); + assert!(m("ROOT/file_root_12").is_none()); + assert!(m("ROOT/file_root_13").is_none()); + + // 2x + assert!(m("ROOT/file_root_20").is_none()); + assert!(m("ROOT/file_root_21").is_none()); + assert!(m("ROOT/file_root_22").is_none()); + assert!(m("ROOT/file_root_23").is_none()); + + // 3x + assert!(m("ROOT/file_root_30").is_ignore()); + assert!(m("ROOT/file_root_31").is_none()); + assert!(m("ROOT/file_root_32").is_none()); + assert!(m("ROOT/file_root_33").is_none()); +} + + +#[test] +fn test_files_in_deep() { + let gitignore = get_gitignore(); + let m = |path: &str| { + gitignore.matched_path_or_any_parents(Path::new(path), false) + }; + + // 0x + assert!(m("ROOT/parent_dir/file_deep_00").is_ignore()); + assert!(m("ROOT/parent_dir/file_deep_01").is_none()); + assert!(m("ROOT/parent_dir/file_deep_02").is_none()); + assert!(m("ROOT/parent_dir/file_deep_03").is_none()); + + // 1x + assert!(m("ROOT/parent_dir/file_deep_10").is_none()); + assert!(m("ROOT/parent_dir/file_deep_11").is_none()); + assert!(m("ROOT/parent_dir/file_deep_12").is_none()); + assert!(m("ROOT/parent_dir/file_deep_13").is_none()); + + // 2x + assert!(m("ROOT/parent_dir/file_deep_20").is_ignore()); + assert!(m("ROOT/parent_dir/file_deep_21").is_none()); + assert!(m("ROOT/parent_dir/file_deep_22").is_none()); + assert!(m("ROOT/parent_dir/file_deep_23").is_none()); + + // 3x + assert!(m("ROOT/parent_dir/file_deep_30").is_ignore()); + assert!(m("ROOT/parent_dir/file_deep_31").is_none()); + assert!(m("ROOT/parent_dir/file_deep_32").is_none()); + assert!(m("ROOT/parent_dir/file_deep_33").is_none()); +} + + +#[test] +fn test_dirs_in_root() { + let gitignore = get_gitignore(); + let m = |path: &str, is_dir: bool| { + gitignore.matched_path_or_any_parents(Path::new(path), is_dir) + }; + + // 00 + assert!(m("ROOT/dir_root_00", true).is_ignore()); + assert!(m("ROOT/dir_root_00/file", false).is_ignore()); + assert!(m("ROOT/dir_root_00/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_00/child_dir/file", false).is_ignore()); + + // 01 + assert!(m("ROOT/dir_root_01", true).is_ignore()); + assert!(m("ROOT/dir_root_01/file", false).is_ignore()); + assert!(m("ROOT/dir_root_01/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_01/child_dir/file", false).is_ignore()); + + // 02 + assert!(m("ROOT/dir_root_02", true).is_none()); // dir itself doesn't match + assert!(m("ROOT/dir_root_02/file", false).is_ignore()); + assert!(m("ROOT/dir_root_02/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_02/child_dir/file", false).is_ignore()); + + // 03 + assert!(m("ROOT/dir_root_03", true).is_none()); // dir itself doesn't match + assert!(m("ROOT/dir_root_03/file", false).is_ignore()); + assert!(m("ROOT/dir_root_03/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_03/child_dir/file", false).is_ignore()); + + // 10 + assert!(m("ROOT/dir_root_10", true).is_ignore()); + assert!(m("ROOT/dir_root_10/file", false).is_ignore()); + assert!(m("ROOT/dir_root_10/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_10/child_dir/file", false).is_ignore()); + + // 11 + assert!(m("ROOT/dir_root_11", true).is_ignore()); + assert!(m("ROOT/dir_root_11/file", false).is_ignore()); + assert!(m("ROOT/dir_root_11/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_11/child_dir/file", false).is_ignore()); + + // 12 + assert!(m("ROOT/dir_root_12", true).is_none()); // dir itself doesn't match + assert!(m("ROOT/dir_root_12/file", false).is_ignore()); + assert!(m("ROOT/dir_root_12/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_12/child_dir/file", false).is_ignore()); + + // 13 + assert!(m("ROOT/dir_root_13", true).is_none()); + assert!(m("ROOT/dir_root_13/file", false).is_ignore()); + assert!(m("ROOT/dir_root_13/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_13/child_dir/file", false).is_ignore()); + + // 20 + assert!(m("ROOT/dir_root_20", true).is_none()); + assert!(m("ROOT/dir_root_20/file", false).is_none()); + assert!(m("ROOT/dir_root_20/child_dir", true).is_none()); + assert!(m("ROOT/dir_root_20/child_dir/file", false).is_none()); + + // 21 + assert!(m("ROOT/dir_root_21", true).is_none()); + assert!(m("ROOT/dir_root_21/file", false).is_none()); + assert!(m("ROOT/dir_root_21/child_dir", true).is_none()); + assert!(m("ROOT/dir_root_21/child_dir/file", false).is_none()); + + // 22 + assert!(m("ROOT/dir_root_22", true).is_none()); + assert!(m("ROOT/dir_root_22/file", false).is_none()); + assert!(m("ROOT/dir_root_22/child_dir", true).is_none()); + assert!(m("ROOT/dir_root_22/child_dir/file", false).is_none()); + + // 23 + assert!(m("ROOT/dir_root_23", true).is_none()); + assert!(m("ROOT/dir_root_23/file", false).is_none()); + assert!(m("ROOT/dir_root_23/child_dir", true).is_none()); + assert!(m("ROOT/dir_root_23/child_dir/file", false).is_none()); + + // 30 + assert!(m("ROOT/dir_root_30", true).is_ignore()); + assert!(m("ROOT/dir_root_30/file", false).is_ignore()); + assert!(m("ROOT/dir_root_30/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_30/child_dir/file", false).is_ignore()); + + // 31 + assert!(m("ROOT/dir_root_31", true).is_ignore()); + assert!(m("ROOT/dir_root_31/file", false).is_ignore()); + assert!(m("ROOT/dir_root_31/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_31/child_dir/file", false).is_ignore()); + + // 32 + assert!(m("ROOT/dir_root_32", true).is_none()); // dir itself doesn't match + assert!(m("ROOT/dir_root_32/file", false).is_ignore()); + assert!(m("ROOT/dir_root_32/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_32/child_dir/file", false).is_ignore()); + + // 33 + assert!(m("ROOT/dir_root_33", true).is_none()); // dir itself doesn't match + assert!(m("ROOT/dir_root_33/file", false).is_ignore()); + assert!(m("ROOT/dir_root_33/child_dir", true).is_ignore()); + assert!(m("ROOT/dir_root_33/child_dir/file", false).is_ignore()); +} + + +#[test] +fn test_dirs_in_deep() { + let gitignore = get_gitignore(); + let m = |path: &str, is_dir: bool| { + gitignore.matched_path_or_any_parents(Path::new(path), is_dir) + }; + + // 00 + assert!(m("ROOT/parent_dir/dir_deep_00", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_00/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_00/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_00/child_dir/file", false).is_ignore() + ); + + // 01 + assert!(m("ROOT/parent_dir/dir_deep_01", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_01/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_01/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_01/child_dir/file", false).is_ignore() + ); + + // 02 + assert!(m("ROOT/parent_dir/dir_deep_02", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_02/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_02/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_02/child_dir/file", false).is_none()); + + // 03 + assert!(m("ROOT/parent_dir/dir_deep_03", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_03/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_03/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_03/child_dir/file", false).is_none()); + + // 10 + assert!(m("ROOT/parent_dir/dir_deep_10", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_10/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_10/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_10/child_dir/file", false).is_none()); + + // 11 + assert!(m("ROOT/parent_dir/dir_deep_11", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_11/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_11/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_11/child_dir/file", false).is_none()); + + // 12 + assert!(m("ROOT/parent_dir/dir_deep_12", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_12/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_12/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_12/child_dir/file", false).is_none()); + + // 13 + assert!(m("ROOT/parent_dir/dir_deep_13", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_13/file", false).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_13/child_dir", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_13/child_dir/file", false).is_none()); + + // 20 + assert!(m("ROOT/parent_dir/dir_deep_20", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_20/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_20/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_20/child_dir/file", false).is_ignore() + ); + + // 21 + assert!(m("ROOT/parent_dir/dir_deep_21", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_21/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_21/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_21/child_dir/file", false).is_ignore() + ); + + // 22 + // dir itself doesn't match + assert!(m("ROOT/parent_dir/dir_deep_22", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_22/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_22/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_22/child_dir/file", false).is_ignore() + ); + + // 23 + // dir itself doesn't match + assert!(m("ROOT/parent_dir/dir_deep_23", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_23/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_23/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_23/child_dir/file", false).is_ignore() + ); + + // 30 + assert!(m("ROOT/parent_dir/dir_deep_30", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_30/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_30/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_30/child_dir/file", false).is_ignore() + ); + + // 31 + assert!(m("ROOT/parent_dir/dir_deep_31", true).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_31/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_31/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_31/child_dir/file", false).is_ignore() + ); + + // 32 + // dir itself doesn't match + assert!(m("ROOT/parent_dir/dir_deep_32", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_32/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_32/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_32/child_dir/file", false).is_ignore() + ); + + // 33 + // dir itself doesn't match + assert!(m("ROOT/parent_dir/dir_deep_33", true).is_none()); + assert!(m("ROOT/parent_dir/dir_deep_33/file", false).is_ignore()); + assert!(m("ROOT/parent_dir/dir_deep_33/child_dir", true).is_ignore()); + assert!( + m("ROOT/parent_dir/dir_deep_33/child_dir/file", false).is_ignore() + ); +} diff --git a/im-rc/.cargo-checksum.json b/im-rc/.cargo-checksum.json new file mode 100644 index 000000000..3c65c2a99 --- /dev/null +++ b/im-rc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e882e6e7cd335baacae574b56aa3ce74844ec82fc6777def7c0ac368837dc3d5"} \ No newline at end of file diff --git a/im-rc/CHANGELOG.md b/im-rc/CHANGELOG.md new file mode 100644 index 000000000..f79c01f38 --- /dev/null +++ b/im-rc/CHANGELOG.md @@ -0,0 +1,308 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic +Versioning](http://semver.org/spec/v2.0.0.html). + +## [12.3.4] - 2019-04-08 + +### Changed + +- `Clone` constraints have been further relaxed on maps and sets, so that you + can now lookup and iterate over them without requiring a `Clone` constraint + (though you do still need `Clone` to actually insert data into them to lookup + or iterate over). (#81) + +### Fixed + +- Enforces the latest bugfix release of sized-chunks. (#78) +- Another edge case bugfix to `Vector`'s size table handling. (#79) + +## [12.3.3] - 2019-03-11 + +### Fixed + +- A number of issues were fixed where `Vector`'s size table would get out of + sync with the node structure if exercised too much and cause erroneous + behaviour. (#72, #74) +- Comprehensive generative tests were added to test all data structures through + more unexpected code paths. + +## [12.3.2] - 2019-03-05 + +### Changed + +- `Clone` constraints on all data structures, as well as relevant constraints on + maps and sets, have been relaxed where possible, so that you can now construct + empty instances and call most query methods without requiring values implement + `Clone` etc. (#63) + +### Fixed + +- Constructing an empty `Vector` will not allocate any heap memory, instead + deferring allocation until you perform an operation that would increase its + length. (#65) +- Some bugs arising when using `Vector::append` repeatedly were fixed. (#67, + #70) + +## [12.3.1] - 2019-02-19 + +### Changed + +- Unsafe chunks have been separated out into the `sized-chunks` crate, which is + now a dependency of `im`. + +## [12.3.0] - 2019-01-15 + +### Added + +- `singleton` methods have been deprecated and renamed to `unit`. +- `Vector::chunks` and `Vector::chunks_mut` have been deprecated and renamed to + `leaves` and `leaves_mut` to avoid confusion with `Vec::chunks`. (#50) + +### Fixed + +- Fixed an issue where the `HashMap` draining iterator might access uninitialised memory leading to + undefined behaviour. (#60) +- Fixed multiple issues in `Vector::split_off` and `Vector::append` that would cause lookup errors + and unexpectedly unbalanced trees. (#55). + +## [12.2.0] - 2018-10-12 + +### Added +- `OrdMap` and `OrdSet` now have a `range()` method which makes an iterator over + a bounded subset of the values. The improved iterator implementation is also + considerably more efficient than the previous (about an order of magnitude + faster for nontrivial data sets). `iter()` has been updated to take advantage + of this, and is now just an alias for `range(..)`. (#27) +- `FocusMut` now has an `unmut` method to turn it into an immutable `Focus`, + releasing its exclusive hold on the underlying `Vector`. +- `Focus` now implements `Clone`. + +## [12.1.0] - 2018-09-25 + +### Added +- Maps and sets now have the `clear` method just like `Vector`. (#46) + +### Changed +- Single chunk `Vector`s are no longer allocated directly on the stack, meaning + that they're now comparable in performance to `std::vec::Vec` rather than + slightly faster, but they also won't eat up your stack space quite as quickly, + and they'll clone without copying and share structure with clones as you'd + expect. + +## [12.0.0] - 2018-08-30 + +Starting with this release, the `arc` flag is gone, in favour of publishing `im` +as two separate crates: `im` (using `Arc`) and `im-rc` (using `Rc`). They're +identical (and built from the same code), except that `im` is thread safe and +`im-rc` is a little bit more performant. + +This is a major release as a consequence, but there should be no breaking code +changes other than the new default choice of reference counter. + +### Added +- The `Chunk` datatype that's used to build `Vector` and `OrdMap` has been + exposed and made generally usable. It's somewhere between a + [`GenericArray`](https://crates.io/crates/generic-array) and a ring buffer, + offers O(1)* push in either direction, and is generally hyperoptimised for its + purpose of serving as nodes for Bagwell tries, but it's also a powered up + version of [`GenericArray`](https://crates.io/crates/generic-array) that might + be useful to others, hence the public API. +- `Vector` now has `Focus` and `FocusMut` APIs for caching index lookups, + yielding huge performance gains when performing multiple adjacent index + lookups. `Vector::iter` has been reimplemented using this API, and is now + much simpler and about twice as fast as a result, and `Vector::iter_mut` now + runs nearly an order of magnitude faster. Likewise, `Vector::sort` and + `Vector::retain` are now using `FocusMut` and run considerably faster as a + result. +- `Focus` and `FocusMut` can also be used as stand ins for subslices through the + `narrow` and `split_at` methods. You can also iterate over foci, making this + the most efficient way to iterate over a subset of a `Vector`. +- `Vector` now implements [Rayon](https://crates.io/crates/rayon)'s parallel + iterators behind the `rayon` feature flag. + +### Changed +- As `std::ops::RangeBounds` is now stabilised in Rust 1.28, the `Vector::slice` + method is now unconditionally available on the stable channel. +- Union/difference/intersection/is_submap methods on `HashMap` and `OrdMap` that + take functions now take `FnMut` instead of `Fn`. This should not affect any + existing code. (#34) +- `Vector::split_off` can now take an index equal to the length of the vector, + yielding an empty vector as the split result. (#33) +- `Vector::set` now returns the replaced value. + +### Fixed +- `Vector` is now represented as a single inline chunk until it grows larger + than the chunk size, making it even faster than `Vec` at small sizes, though + `clone` could now be slower if the clone is expensive (it's still absurdly + fast for `A: Copy`). + +## [11.0.1] - 2018-07-23 + +### Fixed +- Various performance improvements, amounting to a 5-10% speedup for both kinds + of map/set. +- Fixed an edge case bug in `sort::quicksort`. + +## [11.0.0] - 2018-07-10 + +### Changed + +This is a major release with many breaking changes, and is intended to stabilise +the API more than to denote that the rewrite is now production ready. You should +expect future releases with significant performance improvements as well as +additional APIs, but there should be no further major release with breaking +changes in the immediate future, barring very serious unforeseen issues. + +Specifically, you should expect imminent minor releases with performance +improvements for `Vector` and `OrdMap`, for which I have a number of known +optimisations that remain unimplemented. + +#### No More `Arc` + +All data structures have been reworked to take values of `A: Clone` instead of +`Arc`, meaning that there's less performance overhead (as well as mental +overhead) when using values that clone cheaply. The performance gain when values +are `A: Copy` is a factor of two or more. It's expected that users should wrap +values in `Arc` themselves when using values which are expensive to clone. + +Data structures still use reference counters internally to reference nodes, but +values are stored directly in the nodes with no further indirection. This is +also good for cache locality. + +Data structures now use `Rc` instead of `Arc` by default to do reference +counting. If you need a thread safe version that implements `Send` and `Sync`, +you can enable the `arc` feature on the package to compile with `Arc` instead. + +#### `std::collections` Compatible API + +The API has been reworked to align more closely with `std::collections`, +favouring mutable operations by default, so that operations that were previously +suffixed with `_mut` are now the standard operations, and immutable operations +which return a modified copy have been given different names altogether. In +short, all your code using previous versions of this library will no longer +work, and if it was relying heavily on immutable operations, it's recommended +that you rewrite it to be mutable by preference, but you should generally be +able to make it work again by using the new method names for the immutable +operations. + +Here is a list of the most notable changed method names for maps and sets: + +| Previous immutable | Current immutable | Previous mutable | Current mutable | +| ------------------ | ----------------- | ---------------- | --------------- | +| `insert` | `update` | `insert_mut` | `insert` | +| `remove` | `without` | `remove_mut` | `remove` | +| `pop` | `extract` | `pop_mut` | `remove` | + +You should expect to be able to rewrite code using `std::collections::HashMap` +and `std::collections::BTreeMap` with minimal or no changes using `im::HashMap` +and `im::OrdMap` respectively. + +`Vector` has been completely rewritten and has an API that aligns closely with +`std::collections::VecDeque`, with very few immutable equivalents. It's expected +that you should use `Vector::clone()` to take a snapshot when you need it rather +than cause an implicit clone for each operation. (It's still O(1) and +practically instant.) + +I'm considering adding back some of the immutable operations if I can come up +with good names for them, but for now, just `clone` it if you need it. + +#### RRB Vector + +`Vector` is now implemented as an [RRB +tree](https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf) with [smart +head/tail chunking](http://gallium.inria.fr/~rainey/chunked_seq.pdf), obsoleting +the previous [Hickey +trie](https://hypirion.com/musings/understanding-persistent-vector-pt-1) +implementation. + +RRB trees have generally similar performance characteristics to the Hickey trie, +with the added benefit of having O(log n) splitting and concatenation. + +| Operation | RRB tree | Hickey trie | Vec | VecDeque | +| --------------- | -------- | ----------- | ------ | -------- | +| Push front | O(1)\* | O(log n) | O(n) | O(1)\* | +| Push back | O(1)\* | O(log n) | O(1)\* | O(1)\* | +| Pop front | O(1)\* | O(log n) | O(n) | O(1)\* | +| Pop back | O(1)\* | O(log n) | O(1) | O(1)\* | +| Lookup by index | O(log n) | O(log n) | O(1) | O(1) | +| Split | O(log n) | O(log n) | O(n) | O(n) | +| Join | O(log n) | O(n) | O(n) | O(n) | + +(Please note that the timings above are for the `im` version of the Hickey trie, +based on the [Immutable.js](https://facebook.github.io/immutable-js/) +implementation, which performs better than the original Clojure version on +splits and push/pop front, but worse on push/pop back). + +The RRB tree is the most generally efficient list like data structure currently +known, to my knowledge, but obviously it does not and cannot perform as well as +a simple `Vec` on certain operations. It makes up for that by having no +operations you need to worry about the performance complexity of: nothing you +can do to an RRB tree is going to be more expensive than just iterating over it. +For larger data sets, being able to concatenate (and, by extension, insert and +remove at arbitrary locations) several orders of magnitude faster than `Vec` +could also be considered a selling point. + +#### No More `CatList` And `ConsList` + +`CatList` has been superseded by `Vector`, and `ConsList` was generally not very +useful except in the more peculiar edge cases where memory consumption matters +more than performance, and keeping it in line with current API changes wasn't +practical. + +#### No More Funny Words + +Though it breaks my heart, words like `cons`, `snoc`, `car`, `cdr` and `uncons` +are no longer used in the `im` API, to facilitiate closer alignment with +`std::collections`. Even the `head`/`tail` pair is gone, though `head` and +`last` remain as aliases for `front` and `back`. + +## [10.2.0] - 2018-04-15 + +### Added + +- Map/set methods which accept references to keys will now also take any value + that's borrowable to the key's type, ie. it will take a reference to a type + `Borrowable` where the key implements `Borrow`. This is + particularly handy for types such as `String` because you can now pass `&str` + to key lookups instead of `&String`. So, instead of the incredibly cumbersome + `map.get(&"foo".to_string())` you can just do `map.get("foo")` when looking up + a mapping for a string literal. + +## [10.1.0] - 2018-04-12 + +### Added + +- `Vector`, `OrdMap` and `HashMap` now implement `Index` and `IndexMut`, + allowing for syntax like `map[key] = value`. +- Added `cons`, `snoc`, `uncons` and `unsnoc` aliases where they were missing. +- Everything now implements `Sum` and `Extend` where possible. + +### Changed + +- Generalised `OrdMap`/`OrdSet`'s internal nodes so `OrdSet` now only needs to + store pointers to its values, not pairs of pointers to value and `Unit`. This + has caused `OrdMap/Set`'s type constraints to tighten somewhat - in + particular, iteration over maps/sets whose keys don't implement `Ord` is no + longer possible, but as you would only have been able to create empty + instances of these, no sensible code should break because of this. +- `HashMap`/`HashSet` now also cannot be iterated over unless they implement + `Hash + Eq`, with the same note as above. +- Constraints on single operations that take closures on `HashMap` and `OrdMap` + have been relaxed from `Fn` to `FnOnce`. (Fixes #7.) + +### Fixed + +- Hashes are now stored in `HashMap`s along with their associated values, + removing the need to recompute the hash when a value is reordered inside the + tree. + +## [10.0.0] - 2018-03-25 + +### Added + +This is the first release to be considered reasonably stable. No changelog has +been kept until now. diff --git a/im-rc/CODE_OF_CONDUCT.md b/im-rc/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..02a086970 --- /dev/null +++ b/im-rc/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at admin@immutable.rs. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/im-rc/Cargo.toml b/im-rc/Cargo.toml new file mode 100644 index 000000000..7e8c1f3a4 --- /dev/null +++ b/im-rc/Cargo.toml @@ -0,0 +1,80 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "im-rc" +version = "12.3.4" +authors = ["Bodil Stokke "] +build = "./build.rs" +description = "Immutable collection datatypes (the fast but not thread safe version)" +homepage = "http://immutable.rs/" +documentation = "http://immutable.rs/" +readme = "../../README.md" +keywords = ["immutable", "persistent", "hamt", "b-tree", "rrb-tree"] +categories = ["data-structures"] +license = "MPL-2.0+" +repository = "https://github.com/bodil/im-rs" + +[lib] +path = "./src/lib.rs" +[dependencies.proptest] +version = "0.9" +optional = true + +[dependencies.quickcheck] +version = "0.8" +optional = true + +[dependencies.rayon] +version = "1.0" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true + +[dependencies.sized-chunks] +version = "0.1.2" + +[dependencies.typenum] +version = "1.10" +[dev-dependencies.metrohash] +version = "1.0.6" + +[dev-dependencies.pretty_assertions] +version = "0.6" + +[dev-dependencies.proptest] +version = "0.9" + +[dev-dependencies.proptest-derive] +version = "0.1.0" + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.serde] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.syntect] +version = "3.1.0" +[build-dependencies.rustc_version] +version = "0.2" +[badges.travis-ci] +repository = "bodil/im-rs" diff --git a/im-rc/LICENCE.md b/im-rc/LICENCE.md new file mode 100644 index 000000000..cd44203cd --- /dev/null +++ b/im-rc/LICENCE.md @@ -0,0 +1,355 @@ +Mozilla Public License Version 2.0 +================================== + +### 1. Definitions + +**1.1. “Contributor”** + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +**1.2. “Contributor Version”** + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +**1.3. “Contribution”** + means Covered Software of a particular Contributor. + +**1.4. “Covered Software”** + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +**1.5. “Incompatible With Secondary Licenses”** + means + +* **(a)** that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or +* **(b)** that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +**1.6. “Executable Form”** + means any form of the work other than Source Code Form. + +**1.7. “Larger Work”** + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +**1.8. “License”** + means this document. + +**1.9. “Licensable”** + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +**1.10. “Modifications”** + means any of the following: + +* **(a)** any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or +* **(b)** any new file in Source Code Form that contains any Covered + Software. + +**1.11. “Patent Claims” of a Contributor** + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +**1.12. “Secondary License”** + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +**1.13. “Source Code Form”** + means the form of the work preferred for making modifications. + +**1.14. “You” (or “Your”)** + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, “control” means **(a)** the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or **(b)** ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + + +### 2. License Grants and Conditions + +#### 2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +* **(a)** under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and +* **(b)** under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +#### 2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +#### 2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +* **(a)** for any code that a Contributor has removed from Covered Software; + or +* **(b)** for infringements caused by: **(i)** Your and any other third party's + modifications of Covered Software, or **(ii)** the combination of its + Contributions with other software (except as part of its Contributor + Version); or +* **(c)** under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +#### 2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +#### 2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +#### 2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +#### 2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + + +### 3. Responsibilities + +#### 3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +#### 3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +* **(a)** such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +* **(b)** You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +#### 3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +#### 3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +#### 3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + + +### 4. Inability to Comply Due to Statute or Regulation + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: **(a)** comply with +the terms of this License to the maximum extent possible; and **(b)** +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + + +### 5. Termination + +**5.1.** The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated **(a)** provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and **(b)** on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +**5.2.** If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + + +### 6. Disclaimer of Warranty + +> Covered Software is provided under this License on an “as is” +> basis, without warranty of any kind, either expressed, implied, or +> statutory, including, without limitation, warranties that the +> Covered Software is free of defects, merchantable, fit for a +> particular purpose or non-infringing. The entire risk as to the +> quality and performance of the Covered Software is with You. +> Should any Covered Software prove defective in any respect, You +> (not any Contributor) assume the cost of any necessary servicing, +> repair, or correction. This disclaimer of warranty constitutes an +> essential part of this License. No use of any Covered Software is +> authorized under this License except under this disclaimer. + +### 7. Limitation of Liability + +> Under no circumstances and under no legal theory, whether tort +> (including negligence), contract, or otherwise, shall any +> Contributor, or anyone who distributes Covered Software as +> permitted above, be liable to You for any direct, indirect, +> special, incidental, or consequential damages of any character +> including, without limitation, damages for lost profits, loss of +> goodwill, work stoppage, computer failure or malfunction, or any +> and all other commercial damages or losses, even if such party +> shall have been informed of the possibility of such damages. This +> limitation of liability shall not apply to liability for death or +> personal injury resulting from such party's negligence to the +> extent applicable law prohibits such limitation. Some +> jurisdictions do not allow the exclusion or limitation of +> incidental or consequential damages, so this exclusion and +> limitation may not apply to You. + + +### 8. Litigation + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + + +### 9. Miscellaneous + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + + +### 10. Versions of the License + +#### 10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +#### 10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +#### 10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +## Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +## Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/im-rc/README.md b/im-rc/README.md new file mode 100644 index 000000000..1d315fc8c --- /dev/null +++ b/im-rc/README.md @@ -0,0 +1,26 @@ +# im-rs + +Blazing fast immutable collection datatypes for Rust. + +Comes in two versions: [`im`](https://crates.io/crates/im) (thread safe) and +[`im-rc`](https://crates.io/crates/im-rc) (fast but not thread safe). + +## Documentation + +* [API docs](https://docs.rs/im/) + +## Licence + +Copyright 2017 Bodil Stokke + +This software is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +## Code of Conduct + +Please note that this project is released with a [Contributor Code of +Conduct][coc]. By participating in this project you agree to abide by its +terms. + +[coc]: https://github.com/bodil/im-rs/blob/master/CODE_OF_CONDUCT.md diff --git a/im-rc/build.rs b/im-rc/build.rs new file mode 100644 index 000000000..1935d3e8c --- /dev/null +++ b/im-rc/build.rs @@ -0,0 +1,27 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +extern crate rustc_version; + +use rustc_version::{version_meta, Channel}; +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + match version_meta().unwrap().channel { + Channel::Nightly => { + println!("cargo:rustc-cfg=has_specialisation"); + } + _ => (), + } + let pkgname = env::var("CARGO_PKG_NAME").expect("Cargo didn't set the CARGO_PKG_NAME env var!"); + let test_rc = env::var("IM_TEST_RC").is_ok(); + match pkgname.as_str() { + "im" => if !test_rc { + println!("cargo:rustc-cfg=threadsafe") + }, + "im-rc" => {} + _ => panic!("unexpected package name!"), + } +} diff --git a/im-rc/proptest-regressions/hash/map.txt b/im-rc/proptest-regressions/hash/map.txt new file mode 100644 index 000000000..698800a72 --- /dev/null +++ b/im-rc/proptest-regressions/hash/map.txt @@ -0,0 +1,16 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 3591451162 2655640551 804983804 3307909230 # shrinks to ref m = {-13697: 30985, 1338: 29274, -14139: -4092, 673: -19662, -19198: 333, 9155: -4794, -24816: -12851, 14658: -17795, 23662: -25253, -4783: -12972, -31711: -1639, -26495: 16710, -7087: -26434, 18175: -4121, 5045: 8040, -23549: 17012, 6304: -7492, -23305: -28186, 606: 8452, -15872: 2415, 17913: 2306, -20500: 28581} +xs 1457767450 3825624317 1539332905 3279740856 # shrinks to ref m = {7136: -9742, -7547: 13954, -15860: 17017, -31620: -15850, 25480: -13526, 9943: -13939, 1142: 22444, 20378: -26706, -10165: -14641} +xs 2468731224 2159341902 336190467 4018852179 # shrinks to ref m = {22114: -20101, -30886: -4356, 29938: 40, 6256: -29990, 8450: -21821, 30253: 901, -10781: -24620, 22431: 593} +xs 1344206258 166909451 3875523340 3155104601 # shrinks to ref m = {25488: 22186, -4852: 28282, -5097: 4497, 29501: 8087, -29096: -18313, 22286: -17383, 30624: 25063, -2270: -1319, 31014: -28777, 23935: 1507} +xs 2403854785 21349881 2962261870 427550728 # shrinks to ref pairs = [(-17914, 0), (16838, 0)] +xs 1508395022 1122347352 4113209817 3965614759 # shrinks to ref m = {0: 0, 1: 0} +xs 1627474128 2843908894 3937915137 1370561421 # shrinks to ref input = {0: 0}, index_rand = 0 +xs 1863744963 3828268266 3976454353 1279901501 # shrinks to ref m = {1033: ",¦⾘f\u{b}C\u{bae94}}$n\"\u{fc28d}\u{feff}\u{b}-", 2568: "\u{8db77}ꖽ\r\u{7af7f}�7\u{a7bf3}\u{393b9}\u{0}G\u{8}\'%5E\u{cd0dc}?\u{ba311}%\u{ee814}Ѩ\\\u{80aa1}", 3527: "\u{41005}\u{41ff0}$`,L&%\u{1b}~\u{36ada}", 3577: "\u{feff}5\u{109dd9}:\u{8}\u{3}𬃹\u{3c2b6}\\\"5𡂏\'\u{feff}%\u{b8c12}?", 4544: "0*8🕴�\u{33669}\r\"\u{92011}𮡱<\u{0}<\u{1}$\u{1},\u{f1234}{G\u{1b}J\u{ceaa4}\\", 4560: "🕴\r\tѨ@\u{edbda}\u{1b}t�\u{b}\u{2}�ò\u{80090}.\'\u{34690}g%Ѩ\u{0}=\u{1}", 7113: "*", 7944: "¨\u{b6d08}$🕴&{H\rUi\u{feff}\u{0}.¥ô{_*\u{d73fc}:Ѩf`2.*\u{c9c6c}", 8738: "%𬊢*:Ä\u{90}\u{b}\u{48d7b}\"\u{4}"} +xs 1567907912 1646837549 2298759549 1787615177 # shrinks to ref pairs = [(-28601, 0), (2569, 0), (-3384, 0), (5639, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (-30583, 0), (0, 0), (-154, 0), (-27, 0), (105, 0), (-29, 0), (9, 0), (9, 0), (-508, 0), (-478, 0), (-4095, 0), (-2017, 0), (-130, 0), (27145, 0), (2345, 0), (3241, 0), (458, 0), (-6211, 0), (361, 0), (-4772, 0), (-7717, 0), (4265, 0), (-1144, 0)] +xs 2574157460 1821361166 2171243272 102290569 # shrinks to ref pairs = [(0, 0), (7, 0), (7, 0), (2055, 0), (0, 0), (-9530, 0), (0, 0), (6, 0), (6, 0), (0, 0), (6, 0), (0, 0), (0, 0), (0, 0), (0, 0), (-11133, 0), (-161, 0), (-2, 0), (-2051, 0), (-3111, 0), (-2092, 0), (0, 0), (24131, 0), (-5278, 0), (6, 0), (70, 0), (0, 0), (6, 0), (6, 0), (-31, 0), (-3492, 0), (-2373, 0), (8902, 0), (-2438, 0), (3014, 0), (7206, 0), (6854, 0), (15161, 0), (-699, 0)] diff --git a/im-rc/proptest-regressions/hash/set.txt b/im-rc/proptest-regressions/hash/set.txt new file mode 100644 index 000000000..a1071568c --- /dev/null +++ b/im-rc/proptest-regressions/hash/set.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 4213962225 2884706512 1606470227 2259275645 # shrinks to ref s = {"\\\u{4}\u{b}\u{c7afb}Q$x/\u{1a4f0}\u{1}\u{399ac}$.\u{0}=J>\"\u{2}=\t\t*qä¹£\'?6\u{ca350}\u{a20b5}", "\u{b50f2}$", "\u{de54f}/Â¥\u{1b}{*\"Â¥*:\\\u{e77d2}*s`?\u{3}/\u{9daa7}\t\u{1b}\":\'\u{7cf05}G🕴j", "\u{a2848}\u{bf244}.$=d\u{51d0f}Â¥\u{98d35}\u{3457c}<`𖡒{\"k�\t.$u\u{0}.", "!`", "\u{4}\u{9c2d9}r\u{d33a9}¥쇛\u{cd875}\u{7f}\\\u{37b37}`\u{b}\ruR\r\t\u{8aaa0}\\&`\u{b}\u{feff}\u{b868c}\u{a976e}\u{0}\\X\u{514dd}&k", "\u{feff}🕴M", "\u{b162a}S\u{6}\"\r\u{4b435}🕴 \\\u{b16df}\'\u{3468e}\\", "÷/\\\u{4dfaf}\u{7f}*\u{47f16}\"�aZ\r(Tj\u{1b}è®°\t;Â¥*<\u{1b}E\u{8d037}"} diff --git a/im-rc/proptest-regressions/ord/map b/im-rc/proptest-regressions/ord/map new file mode 100644 index 000000000..ce47e6b91 --- /dev/null +++ b/im-rc/proptest-regressions/ord/map @@ -0,0 +1,20 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 1087347487 1450735596 3800950698 1648897824 # shrinks to ref m = {29894: -24214, -22768: -29852, -25204: 19090, -22710: 4694, -27608: 14656, -27740: 29393, 7285: -78, -3041: 77, 20980: 467, 13472: 3518, 2845: -9597, 6987: -29072, -30486: 827, -1022: 15821, 22068: -24552, 6293: -21073, -7161: 10155, 3791: -27929, 6361: 15318, 3190: 30164, 31756: 4331, 11824: 30151, -14319: -451, -17781: -5693, -5991: 372, -27192: -2983, 23456: 21711, -19546: 28578, -9753: 30988, 21193: 22302, 432: 24303, -15110: 26679, -11612: -6722, 12373: -31848, -20837: -16031, 25861: -12660, -23775: 32410, -6760: 25269, 21702: -26852, -17649: 27279, -12789: -28758, -26032: 6316, -16837: -16182, 31817: -24478, -3564: -20084, -5315: 23517, 11955: -29343, 9175: -4003, 20615: -19515, -3453: 24768, -28231: 3065, 10336: -24811, -8978: 17861, 23428: 19571, -450: 14904, -5293: -12205, -15735: -13395, 12747: -25893, 29368: 14652, 16863: -31998, 29612: 2394, 3212: 4512, -2804: 16628, -9070: 2599, -8946: -6150, 22872: -15322, -12672: 22236, 8415: -22569, 18541: -20698, 12395: -11080, -3888: -6244, -4893: 21952, -3595: 16707, 11722: -9301, 23547: 8317, -10052: -5551, -8428: -1168, -6805: 1438, 6185: 27026, 9265: 14429, -7016: -19640, 4739: 28713, 27505: -9101, -21379: 11843, 10141: 26568, -27662: -7672, -5384: -15814, -31927: 23347, 28068: -13380, -3075: 11627, -28778: 26949, 821: 22814, 11572: 16591, -10426: 5726, -14986: 6492, -4472: -12187, -22049: -18715, 3822: -26724, -13821: 24964, 14780: 23541, -26068: -17472, 6419: -16387, -21443: -32036, -27285: -11138, -12544: -22185, -25942: -22158, 8799: 22607, 22203: 23175, -29997: 9170, 18341: -19711, -25162: -29851, 29377: -4845, -4337: -3624, -30764: 13318, 2000: 6862, 13510: 4642, 25068: -1590, 16270: -1390, -23439: 16616, -13611: 30094, 10084: -30492, -6677: 12289, 28032: -21767, 10105: 8774, 627: 24722, 27190: 3954, -26665: -7354, 27566: -8037, 15625: -9453, -30151: -25954, -28349: 30379, -6142: 691, -9262: 24633, 27808: -5306, 11490: -10950, 22022: -705, 7283: -7208, 29941: 6208, -4204: -2121, -9279: 17669, -4498: -4582, -4833: 29055, -22069: 27589, 32004: -31982, 4036: 11622, -5971: 6511, 7362: -31402, 2132: 16965, -17605: 3529, 16899: -16958, 20305: -26766, 18755: 21882, 13064: -29474, 1391: -25296, 9071: -8029, -20305: 30895, 167: 21243, 23450: -32278, -22095: 13405, 12963: 18120, 24666: 28046, 14320: 8050, 30437: -12581, 17277: 15852, -19808: -27963, -23409: 24638, 29401: 15328, -21257: -3018, 28299: 29000, 18823: -8987, 15409: 9114, -2476: -12749, 5807: -25088, -17559: 19530, -3994: 32042, -23994: 11576, 17613: -11312, 24203: 30135, 14421: 29461, -8181: 17641, 6171: -20014, 31027: 1105, 20177: 11742, 28023: 10685, -5413: 22256, -29512: -27827, 26068: -31380, 10750: 9166, -19988: 26137, 6165: -12868, -9662: 15887, 12809: -12054, 25972: 23426, -3522: 11010, -13516: 10518, -20198: 8172, -20051: -21390, 17149: 27954, -25908: -3999, 22600: -21800, -15240: -21275, -12894: -31550, 11168: 6165, 1471: -30312, 25562: 31867, -3575: -5407, 16896: -21901, -31594: -2825, 24966: -2987, 31931: 19139, -671: 16835, -13289: 32113, -7420: -21883, -26225: -29508, 14029: -23627, 13600: 7738, 19823: 22879, -7278: -31931, -18518: -15028, -24285: 15271, 30158: -6041, -7778: -10728, 18967: -9084, 12216: 15282, 7667: -29473, -29079: 5065, 28475: 262, 9873: 455, 14700: 2632, -6257: 15024, 2641: -23165, 25766: -21115, 30853: -8411, 24163: -4764, -30666: 17364, -14056: 31344, -16470: -21166, 7863: -28957, 28281: -15377, 4107: -8950, -9388: -32765, 24227: -9133, -10558: 13655, 23295: 9762, -3019: -27437, 11095: 29763, 10609: 12051, -19079: 16494, -638: -5842, 4362: 27932, 2639: -25626, -3030: -14761, 21408: -18773, -21262: -4491, -5008: 1094, -11589: -2784, 15655: 29651, -19013: -9552, 7540: -28066, 18000: 17054, 29752: 18144, 28226: 27155, -12924: 7241, 22083: 13808, -18448: -3080, 29456: 16400, 53: -12710, -1221: 30244, -16504: 24240, 5545: -27714, -20630: -18870, -21090: 28104, 4959: 12418, -15608: 1794, -23432: -22218} +xs 2470012874 1108569466 2705233914 2105395150 # shrinks to ref m = {-26536: -10140, -31941: 2328, -23547: -9253, -28157: -17639, -2098: -25615, 9417: -4376, 5027: 16722, 17121: -24663, 8128: -25969, 25933: 18490, -25489: 10837, -13402: 29678, 31055: 14092, -3811: 19345, 3565: -15536, 8160: 25591, 21133: -5677, 31382: -12602, -4552: -6140, 23595: 6118, -5496: 2443, 25445: -32364, 1737: -5168, -9077: -15214, 7942: -27346, 503: 29459, 30229: 31798, -21623: -984, -20767: 1391, -20732: -5138, 179: -2480, -30700: 32256, 23991: -29242, 5811: -2677, 8242: -19246, 14001: 121, 23994: 15968, 16850: 22675, 27403: 20078, 28998: 29713, -18285: -28709, 15265: -345, -2024: -7961, -26394: -16075, -15563: -14632, 3611: -4743, -16600: 8421, 9494: 30533, -26355: -7995, -31604: 15030, -28372: -30678, -1460: 4493, 12812: 6867, 3327: 5994, -27683: -25261, -6712: 14346, 20460: 1089, 10960: 1352, 24869: -29446, -8174: 30195, 24471: -27707, 26252: 15759, -17935: 12699, -19327: 31902, 10672: -17255, -3178: -31772, 14367: 13488, 9093: 13209, -20473: -9178, -31120: 3147, -5795: -3982, -24184: 19687, -8033: 16211, -12944: 8417, -9993: 4190, 2100: 30585, -1397: -27306, 68: -17544, 12442: -4284, 7519: -12190, 22795: -29312, -21157: -16782, -32441: -15527, 3210: -4247, 32108: 9123, 24488: 25516, 11162: -10170, -19251: -2295, -28559: -4773, 31985: 172, -227: 30045, -2104: 26418, -3076: 15669, 14672: 12100, 7576: -13667, -5021: -32276, 21621: 29212, 13537: -19166, -2389: 8930, -4556: -31064, -10630: 3433, 29934: 12298, 6640: -32416, 29552: -6676, 2449: 9495, -20587: -24712, -12359: 29691, -26177: -31729, 4421: -9542, -9965: 7463, 28677: 26334, -27845: -6260, 13285: 11380, 32752: -20965, 15706: -17233, 29886: 13339, 17438: -28315, 26609: 30547, 15151: -15429, -2919: -19952, 16934: -32480, 26615: 24385, 233: -32369, -10268: -10139, 29343: -30102, -15885: 30182, 15822: 25778, -26549: -2360, 2001: -4014, -12019: -1196, 731: 29634, -29995: -22547, -15831: -27743, 1976: -14216, 24671: 21678, -10275: -5156, 28289: 17246, 12893: -32150, -16308: 7767, 5729: 11546, 18882: -31578, -4231: 18279, -25379: -31185, -1139: -16861, -18054: -8385, -31606: -23236, 21235: 7426, -6400: -7360, -8606: -2630, -22484: -11090, 15370: -5085, 5679: -17878, -28308: -24539, 9009: -24480, -16109: -19862, -20544: -20765, -6411: -28066, 11890: 21190, 4579: -7721, -22198: -22517, 338: -4143, 12184: -11969, -15946: -24141, -23654: 2485, 9886: -26974, 11733: 28587, -8243: -20115, 13309: 31556, -14397: -19926, 29872: 19550, -4716: -14669, 16769: 14751, 8353: 18931, -22070: -5371, 24224: -26199, 24823: -30739, 9421: -13020, 19874: -2767, -10193: 2881, 6660: 1643, -31321: -16602, -12356: -8592, 7484: 15900, 4220: 7816, 2781: -7331, 17673: 7955, 21734: -2072, -4406: -26944, -2747: 17863, 4584: -2492, 31654: 15772, -10883: 4363, -3737: 3686, -18179: 30440, 18460: 23217, -3702: 15120, 14407: -18596, 7749: -11497, -27197: 12065, 15409: 18406, 1457: 4533, 24941: 24486, 12520: -29147, 9179: 31948, -14078: -21063, -22741: -21277, 29691: 24484, 13093: 30490, 11422: -28999, 19850: 28538, 58: -1946, 26401: -32289, 16997: -26844, -23467: -28453, 24138: -6868, -14289: 2223, -3164: -12604, -24071: -11711, 6645: -19591, 17685: 9616, -29576: 31095, 15812: -19219, -30119: 20657, -9465: -20600, 5077: 19208, -10326: 3699, 27078: -4075, -7152: 28943, 14558: -22676, -10615: 31120, 29487: 29114, -6096: -1001, 5941: -21634, -30352: 30888, 582: -23140, 16391: 7248, 25557: -14944, 21501: 18193, 11316: 11352, 18183: 17500, -18516: 2584, -2107: -32422, -8402: 12344, -17372: 11869, -15723: 2627, -1765: 19581, 2975: 1, -5867: 23341, 25489: -2444, 9809: 21415, 29497: -18101, -25328: 28247, 9621: -3108, 28275: 8915, 6846: 3451, 28008: 18058, 6195: 10677, 12779: 1341, 13248: 30900, -18786: 27113, -26425: 9293, 16195: 8935, -2461: -16811, -31431: 4635, -9480: 779, -22487: 19715, -15600: -8938, 29782: -1315, 8079: -27635, 3322: 10561, -23910: -4240, -10716: 3872, 12155: -11450, -23322: -27745, 3206: 9309, -23080: 1961, 6761: -31058, 28940: -20745, -29586: -5915, -9310: -8874, 23578: -31849, -24336: 2811, -31640: 13432, 17145: 4078, -10857: 25423, -28879: 7602, 8971: -12084, -19239: 2917, -32289: 12788, 10482: -26779, 7196: 18090, 17174: -28319, -16874: -29949, -10772: 15992, -1774: 239, 5296: -15898, -8433: 14050, -12827: 28010, 29685: -21923, -4742: 18358, -9399: 13522, -3136: 23448, 9803: -30280, 4633: 9138, 22129: -3054, -24759: -3027, 13549: -10895, 770: 13115, -22180: -30951, 26425: 26303, 15351: -14655, -2361: 9031, 21063: -15719, 26334: -23261, 1253: 4242, 21284: -31915, -16220: 4816, 957: -25495, -454: 18872, 8183: 8829, -21137: -20303, -6282: 12896, -23187: 23, -32053: 21416, -924: -16666, -30888: 11634, 31358: 22911, -6028: -984, -28864: 9371, 28554: 18962, 13368: -9926, 25395: 11310, -22859: -15920, 24079: 24924, -20238: -29669, -2746: -24651, -21422: 21027, 30773: 9672, -8756: -14597, -11425: 30250, -8475: 3559, 14902: 23939, 32064: 4283, 15572: 18467, -8531: -31074, 26651: -5381, 27619: -17005, -29712: 2868, 16457: 20436, -11057: -2269, 3024: -15357, 15023: -26768, 14212: -26881, -19185: -18690, -4924: 7128, 23174: -20610, -9472: -16907, 17569: -23072, 20118: -14428, 9805: 26597, 6994: -8522, 2040: -32366, 25162: -31175, -1386: 16672, -22403: 26995, 7584: 27458, -17532: -141, 18644: 3005, 24808: 28562, 9341: -5445, -25768: 32689, 16892: 17059, -30689: -12568, 28747: -19363, -2091: 1259, -11643: -20020} +xs 1943497849 4012822781 687301666 4052323690 # shrinks to ref input = {-14552: -9546, -24687: 4553, -5948: -11033, -30216: 31225, -1329: 18654, 25756: 28243, 26320: 32308, 14380: 20303, 30195: -29219, 12769: -13515, 4261: -10098, -15032: 27827, 22373: -30648, -18543: -27064, 20765: -17004, -7193: 29946, 17191: -11212, -9550: 6145, 30413: -3896, 25650: 15492, 6991: -3005, -27117: -18341, -31108: -14720, 2037: -9230, 21209: -17697, -17478: -15083, -7092: -21790, -18620: -19170, 7611: -13546, -10267: -19624, -32677: 26187, 23727: 29533, -3698: -10243, 5300: -3822, 346: -5404, -22233: 16053, 18668: 22996, 2804: 14570, -7140: -914, 29328: 531, 22194: 580, -29271: 32284, -30855: -25589, -24039: 22663, -17584: -7090, 30655: -22419, 6962: 3019, -11388: -29702, 7470: 10191, 12733: -8953, 31781: 29536, -4713: 28624, 29225: 2850, 10639: -17353, 28644: -28651, 27509: 26751, -21653: -3068, -23302: 16505, 23875: -4223, -12294: 8408, 22871: -26300, -11807: -10674, 11617: -20802, -12917: -3942, 12525: 8275, -28360: 25924, -11694: -17660, -8376: -23674, 28022: -11052, 1701: 16466, -10152: 27738, 25396: 3306, 27309: -15176, -24958: 25332, 13257: -9440, 28652: -31476, 28824: -25210, 19544: -26806, -16312: -554, -29314: -25624, -6344: -27482, 12638: 11012, 29993: -5753, -7052: -5445, 6885: -32534, -2710: 15172, 25838: -29888, -4162: 25600, 8274: 3660, 14914: -11250, 18077: 21149, 30865: 29780, 7652: -29810, -27575: -22324, 27190: 13088, -28712: -24931, 32575: 14212, 16100: 2414, 22459: -12558, 12914: 12488, -5756: 26535, -11609: 21588, -23178: 22887, -6623: 10056, 11425: 5119, -24807: 1930, 20747: -2695, 22174: 28280, 26661: -7627, -22429: 26131, 30256: -13483, -23654: -6600, 23857: 20134, -6396: 26307, 27673: -19775, 21325: -20165, 18149: -5624, -16291: 20822, 30797: -19910, -16498: -12698, -28455: -13778, -19937: 16733, 22899: 23440, 20491: -29335, 6724: -14015, 20327: 29236, -13404: 17062, 21857: 21139, -11068: -11817, -24465: -19689, 13258: -20349, -8846: 24655, -14100: -5192, 18797: -4050, 15238: -20885, 21853: -14590, -21265: -5581, 7767: 16287, -29108: -18338, 15365: -10543, -28008: 20715, -27679: 9383, 28946: -32523, -6815: -11660, 25311: -30043, -24259: -32354, -26480: -29813, -4922: -31962, -23235: -14838, -28240: -16289, -20429: -10753, -31466: 4099, 17742: 9919, 22328: -29633, 11484: 5947, -30743: -3454, 27329: -28404, -1440: 16220, -21058: -15381, -7339: 775, 23003: 3428, -29181: -11177, -7918: 18487, 26135: -17235, 31493: -32374, 8674: -29831, 23135: 3319, 22008: 26647, 14087: 926, 9495: 32645, -28424: 4358, -28839: -25000, 12270: 1203, -3843: 24513, 28974: 3537, -11154: 20241, -308: 15509, -1063: 1938, 22352: 16339, 22065: -4794, 25625: 30704, -29994: 25473, -32588: 8066, -19799: -28784, -16369: -7522, 12819: -26116, -10: -12210, 23530: -8239, -8702: 15218, -29559: -6059, 17386: 8272, 9791: 11158, 31268: -23502, 839: -12740, -20953: 30929, -6498: -6179, 18058: 26452, 17715: 21182, -444: 26708, -12166: -10624, -17286: -11707, -5285: 28283, 26686: 28422, -27560: 24488, -9092: -21679, -341: 5249, -1777: -19160, -8798: -18074, 5664: -26770, 8831: 21172, -15630: 10171, 10815: -23739, 10322: -14746, 3683: -28968, -968: -11470, 4300: -21106, 17329: -3943, 919: 15039, 11736: 24420, 18566: 8425, -6499: 17007, 1038: -20933, -1760: 2435, 32364: 17255, -23412: -10508, -20606: -2288, -12261: -24932, 23266: -16759, 29366: -24835, -4536: -26835, 11130: 15321, 9689: -25898, 10497: -8, 8379: -17866, 32503: 1391, -7464: -7476, -10905: 21006, 28934: 27973, -2489: 22253, 18422: -3749, -16897: -26476, 26037: 24177, 25372: -5235, -17793: 5394, -31916: 8290, 2514: 17926, -12681: 10612, -31402: 4216, -21993: 5489, -333: -29732, -7208: 12324, -2259: 7182, -14269: 19700, 7113: -6447, 312: 21681, 16777: -5191, 19799: -22785, -16984: 20498, 13781: -19721, -15005: -27421, -5197: 16418, -26014: 14386, -21116: -29472, 22218: -3249, -12769: 13282, -962: 27871, 323: -26453, -9145: 28365, 20899: 5521, 2983: -28582, 27272: 17304, 14965: 6793, 1119: -8804, 11980: 24389, -27467: 31369, -6059: 22193, 11148: -13064, 28685: 13279, 9266: 23559, 491: 31840, -24358: 20417, -1039: 32656, -8354: 27428, -6823: 13026, 7306: -28986, -29124: -12391, 11358: 19868, 21852: 31747, -354: 17738, -6380: -31076, 6993: -3593, 7749: -26991, -5736: 26845, -23757: -25868, -23018: 21291, -29482: -13037, -28028: -17152, -11500: -2400, 14240: 27368, 8517: -7890, 3318: 26016, 8702: -21694, -15698: -18674, -29992: -16745, 17497: 3921, 17256: 23908, 12994: 16354, -12133: -5976, -9636: -19253, 13662: 26694, -5291: -27961, -19711: -2634, 24676: 200, -21683: -20419, -10755: -20201, 5389: -24265, -18644: 25881, 24013: 26905, -15710: -40, -1078: 24024, 29202: 25073, 7358: 5121, -23181: -31628, 10282: -26184, -20910: -2762, 31789: -11576, -15966: 18578, -14285: 3170, 1448: -13499, -10080: 23097, 9012: -30126, -15463: -12150, 20289: 31453, -23544: -15457, 14694: -5005, 25006: -25213, 20402: -18375, 29679: 20672, -4570: -7111, 22495: -6454, 28869: 31665, 14191: 13852, 16134: 32353, 4529: 8494, 19093: 6864, -794: 18776, 17957: -11241, 25597: -20134, 18037: -1679, 27835: 3288, 22315: -10272, 13032: 9697, -20215: 3797, -12773: -983, 25848: -4873, 19596: 9706, 8030: -28925, 30246: 12946, 7467: -25254, -10731: 6363, 18631: 8976, 1414: -13096, 1779: 15953, -3595: 21321, 339: -8066, -7639: 14039, 20195: 12164, 7156: -11669, 16411: -8927, 13534: -14503, 13577: 17546, -27772: -32545, -6421: -3173, -12316: 16200, -31884: 603, 12395: 3034, 22659: 25898, 30481: -23170, -16623: 20360, -20279: 30762, 3968: -13181, -2313: -4445, -13314: 13183, 17186: -472, -25465: -11926, -12985: 12936, -17260: 21153, 14971: 366, 5035: 29873, 29: 19702, -29547: -10586, -10368: 11518, -13759: -4543, -29208: -4931, 1605: -15282, 22500: 24270, -25324: -150, -24578: -5930, -25949: 21945, -10053: 2314, 19195: 24191, -6760: 32697, -8885: 28695, 12676: -18931, -24963: 5956, -11667: -32632, 3496: -7015, -3422: 24361, 17031: -19643, -21362: 28410, 11868: -24693, 26928: -25916, -8771: -10298, -19434: 29046, 16057: -21815, -28508: -1488, 17240: -23998, 3146: 4003, -8669: 1658, -2885: 3442, 19212: -25066, 8584: -30453, -19749: 25649, 12925: 1864, -7982: -17592, -18312: -6020, 26066: -12698, 10168: 2258, 23411: -27324, 20913: 2058, -17161: -2704, -28674: -8941, 19334: -154, 29314: -18570, -4291: 13987, 27890: -10595, -6139: -19690, -2185: 29099, -19246: -21481, 18345: -7746, 8792: 32374, -12093: -11963, 27898: 28419, -2679: 31973, -6053: -9814, 28750: -1279, 5512: -22468, 24559: 13801, 29152: 10421, -8834: 21875, -11673: 15773, 28602: -9755, -5742: 6786, 13086: 15119, -10716: 23940, -31277: 6551, -12006: 16878, 31399: 15139, -3499: -14162, -7428: -10133, 31533: -4236, -20111: 23374, -13506: -28699, 31291: 27230, -32598: -7092, -5972: 31899, 15397: -8419, 15791: -2952, 24123: 9853, -32197: -7823, 12564: -18593, 16139: 21230, -23524: -28360, 6509: 20623, -8275: 31514, -6607: -5333, 5101: 31408, 23166: 21657, -12672: 8924, 1406: -11027, -24417: -3430, 27934: -17823, -7960: -29901, -20662: 24784, 9478: -22265, -3096: -26803, -5897: 23795, 29566: 26527, -19057: -10328, -22202: 18967, 11290: 32741, 14225: 4804, -31177: 15798, -23514: -7563, 21445: 15844, 14156: 8570, -23968: -24474, 12089: 5498, -14198: -26135, 12664: -23411, 11111: 27354, 15998: 11423, 2891: 21555, -3889: 17061, 32491: -4625, 110: -9137, -20559: -6986, -28721: 3288, 6697: -23898, 8774: -6890, -24838: 20366, 31820: 27280, 14127: 10447, 605: -23336, -28271: -9387, -1486: -28143, 1623: 19882, 30022: -7494, 16398: 31225, -20320: -23582, -23295: -17336, -14291: -775, 3270: 20106, 11662: 16973, 29041: 3377, 7387: -16397, 18767: 32565, 5022: 19191, 16397: -31024, -16106: 13405, -31898: -23690, -25746: 17046, -8847: -29236, 28656: 21644, -11311: -25314, 4515: -19390, -15847: -1245, -5025: 24474, 24302: 28820, -31534: 24028, -14548: -21272, 20722: -27070, -24083: 29927, -27812: 19042, -18194: 5028, -29732: -8181, 20316: 16946, 3176: -32144, -30223: -25654, 202: 22052, -20234: 6669, 18732: 15730, 7127: -27128, -2948: -22493, -21733: 27859, 25166: -31535, -27174: 28732, -14476: 5256, 20346: -27358, 6308: 18033, -10411: 12780, -5469: -28028, 4884: -15738, -12442: -3065, 24311: -21682, 18679: -10632, -13091: 25595, -18882: 31353, 23626: 20687, -17201: 13186, 4270: 16793, -22089: 5358, 4374: -23552, -13011: 5661, -14593: 1052, -10586: -18438, 9093: -3136, -19492: -30355, -5066: 24396, -9852: 13836, 8770: 30757, -18672: -13421, 16224: -10802, 21800: 12639, -213: 28223, 22311: -6756, 7182: 31529, 19224: 16315, 20067: -19940, 10720: -12330, 8384: 14353, 27730: -24075, -18309: 4570, 5808: -32765, 14330: -24746, -19632: -3605, 4228: 25887, 28783: -30008, 16483: -20439, 16655: 26861, -10047: -14259, 30091: 29732, 29182: -13397, -26897: 14659, -17202: 16830, -15265: -16433, 18554: 18464, 3269: -15505, -11054: -20924, -5253: 3749, 14888: -553, 15310: 29010, 3194: 31220, -13770: 21130, 4236: -15365, 13546: -11695, 32688: -16898, 24524: -8344, -2968: 25207, 1449: 26456, 29046: -5209, 12133: -27981, -27130: -21148, -3586: -24606}, index_rand = 6181253659715007859 +xs 3094145122 1848048556 41621330 1587738279 # shrinks to ref input = {25109: 17547, 13167: -24835, 32450: -27886, 28704: 27530, -29237: -31051, 17202: -31179, -22358: 15751, -17715: -2518, 82: -27363, -26280: -12489, -10711: 1113, 28197: -29265, -12233: 15499, 1578: 18570, -10956: 7886, 957: -15131, -26652: -19109, -1698: 7038, -3697: -2352, -18762: 4688, 2143: -17488, -30936: -28216, 26547: 20891, 20001: -10566, 20162: 12139, -15042: 4332, 23226: 835, -1720: 26602, -9048: -19721, -29320: -13680, 30000: -7286, -3693: -16312, -30022: -21864, 29541: 16785, 4006: -20908, -29599: 14040, -17690: 24907, -3766: 16608, 22217: -29766, -29552: -3913, -4046: -20703, -26412: 21205, -15898: 17844, -4553: 32030, 30908: 18124, -1065: 27619, 1642: -19186, 31516: 28398, -22847: 5892, -31043: 21198, -20284: 25965, -27740: 4090, -750: 29603, 29546: -7601, 19831: 16923, -27337: 27061, -5052: -22512, 19028: 22656, -6128: -20716, -5324: -2624, 7273: 5987, 26259: 28589, -5682: 24455, 19425: -13458, -8687: 1837, -29081: -5536, -5126: 19859, -23172: -26061, -17454: -9093, -14495: -19415, 124: 27981, -214: -15589, 17580: 24995, -22303: 227, -2043: -17283, 13309: -29027, -22094: -31943, -1826: 12330, -26959: 19945, 22155: 4915, 16: 1005, -6802: -8951, -29879: 4766, 21350: 7196, -4292: -29428, -17591: 7350, -23475: 20767, 23372: 13739, -16316: -30392, 17391: 5141, -10827: 27764, -11304: 7731, -4247: -21446, 8251: -19738, -568: 8414, 14787: 5321, 2403: -17445, -19412: -16874, 16247: -30651, 11946: -29414, -7725: -10389, -2002: -20578, -12689: -21992, 15800: -451, 32435: 1683, 16805: 11493, -8068: 32206, 27386: 26184, -14311: 21859, 7208: 19308, -13115: 24029, 32222: 19098, -3951: 20703, 10184: 5095, -3235: 29199, 7358: 3163, -9539: 23015, 17802: -31374, -12478: 18169, 21253: 2717, -4126: 30376, 31545: 13768, 14466: 10983, 26903: -7058, -8377: 21868, -15947: 21121, 31358: -30749, -22714: 23423, 17855: 9349, 7118: -3573, 20807: 30872, -19809: 19037, 3084: 622, -13442: -19023, -9314: 14811, 19551: 9175, 13945: -24551, -9482: 14832, 4058: -11363, -29175: 3097, 26866: -6501, -19528: 16419, 13884: -10693, -30894: 18387, 2434: -11471, -29588: 8302, 9537: 26353, 11223: -4669, 32503: -8454, -17566: -12769, 2898: 31182, -19042: 2208, 18941: -22060, -22700: -31888, -11067: -21667, -23130: -13776, 29835: 5369, -15197: -21652, -31889: 23653, 19121: -20925, -4888: 11878, -23301: -32625, -12188: 18858, 7983: -19066, 30772: 18792, 18565: -29423, -30448: -28531, -29781: -27670, -23123: 24404, -8686: -5154, 1956: 28781, -7050: -19514, -21874: -15534, 27434: 2933, 11568: 8591, 8645: -32175, -24288: -32065, 23708: -16804, -102: -20155, -21298: -10486, -5606: 25010, -6095: -10305, -19200: -11318, -2702: -31591, 10484: -30488, 12966: 18734, 19351: -29225, -10379: 28706, -13211: 13219, -30684: -30410, 12809: 3245, -9528: -14612, -13917: 30016, 15751: 14348, -16078: -20918, 21568: 22488, 18004: 30534, -19602: 18121, 13959: 22532, -9411: 17916, -13153: -12283, -16441: 24688, -31877: -25633, -10943: 21681, -12241: 25973, 18048: -16131, -32576: 16074, -23799: 30191, -27572: -4842, -9917: 17632, 28907: 26864, 1029: -8790, -15458: 5122, 617: 31966, 5083: 20195, 26118: -27966, -31719: 261, -30897: 26416, -28104: 25353, -25183: 10371, -25051: -9876, -8676: -2203, -25965: -25244, 14552: -27117, -6195: -9440, 6733: -15895, -16548: 22340, 7795: -7156, -5548: -8170, 1975: 11313, 26002: 13579, -1090: 16028, 3119: -22116, -26790: 3213, -12524: -21450, 19788: -30362, -11778: 7254, -24041: 18664, 10038: 10500, 12731: 10291, 19886: 8630, -13579: 4280, -10199: 16578, -10637: 18165, -3835: 6271, 14929: 24076, 27938: -31473, -14770: 5512, 15441: -3706, -17185: 2295, 15932: 20222, 13258: -18255, 24353: -11049, 24897: -6737, 365: -23551, 23329: 30521, -31648: -13380, -1552: -25692, -5206: -1325, -27419: 31094, -51: -28413, 12361: -29699, 5402: 26930, -27529: 7188, -12050: -7233, -7996: 20657, -18903: -31229, 2184: -27864, -22198: 8189, -14333: -3151, -8819: 32208, -25427: -1465, -13361: 23768, 25140: -13818, -18482: 5019, -9847: -31791, -17654: -16678, -18171: -25938, 24839: -22327, -10299: 17415, -517: -9938, 11604: 19413, -20522: 25880, -16853: 12843, -19711: 6243, -2217: 17848, 31544: -23358, 32481: -20104, 916: -13297, 21632: 27432, -20301: -905, -28748: -18375, -18946: -26872, -27139: 23619, -28341: -2690, -14751: 3261, -31340: -5866, 14129: -1873, -17466: -19221, -27794: -25683, -16132: -26856, -6446: 21798, -26329: -20765, -19511: 31669, -25708: -5275, 10217: 797, -9016: -17110, 7696: 13723, 6083: -19072, 31100: 8435, 8017: 10175, -23973: -199, 25418: 21954, -5106: 15703, -29119: -14678, -23448: -14905, -1334: 27615, -25389: 21402, 5764: -14910, -25059: -20274, 32586: -21603, 27022: 24446, 30370: -23901, -31423: 31764, -21135: -21011, -6284: 14914, -20672: -4657, 3691: 9397, 1305: -26046, -29806: 1663, 11409: -9037, -25440: 12737, -16350: -30111, -15664: 4544, 29290: -19087, -10773: -15820, -1299: 31105, -9945: -24879, 25445: -1393, 17568: -11207, 2868: 11240, -14478: -5443, -29749: 22046, 30402: 18906, -14676: 28148, -12434: 19407, -8904: -31377, 32723: 19548, 26961: -12468, -20695: 24529, -11186: -16253, 17983: -16005, -22681: 29406, -32124: -28864, 4551: -32279, 16423: 21410, -29467: 30297, -32316: -11084, 19168: 13447, 31777: -17253, -20788: 30789, 10397: 26717, -16290: 10403, 3436: -20939, 24973: 21047, -23977: 19143, -21115: 16465, -32140: -27035, 29494: 19758, -31925: 16559, 25544: 14705, 16117: 2902, 16076: 1994, 1259: -4130, 11871: -31322, 31923: -12428, 6485: 16367, -15055: 17454, -32536: -23142, 19287: -30036, 19046: -6360, 30467: -20193, -1352: 19442, -24389: -32203, -25508: 28905, 13432: -28476, 15794: -2020, 7907: 12590, 19319: -31856, -10096: -8759, 9365: 24849, -11559: 25438, 23762: 21598, -7248: 22542, -16926: 12934, -24708: 4222, 2179: 3309, 1855: -8693, 10786: 29825, 18783: 25809, -5169: 5570, -8235: -4664, -20234: 26252, 18273: -26922, -4496: 19147, 4458: -20329, -18952: -31435, 22439: -27690, -3304: -7512, -17425: 6385, 2885: -18520, 2478: -17666, -16036: 22920, -8658: -18048, -7204: -25509, 28983: 4786, -9146: 16439, -26893: -27056, -31037: 17541, 643: 17042, 27085: 11808, 26037: 20956, 4234: 1346, -14815: -6582, 25700: -8577, -10298: -23247, 5728: 10020, -25496: 10378, -27275: 28186, 24689: -21421, 32092: -15135, 17254: -370, 13808: 18349, 19084: -163, 16447: -25693, -22306: 26140, -1695: 3490, 32119: -6821, 25084: 21803, 10922: -26376, 27134: 21743, 30570: 8146, -12987: 6435, -20456: -22516, -31704: 12485, -23916: 4096, -26088: 20130, -19159: -28657, -3808: -29934, 21346: 18600, -17642: 22758, -9589: 9627, -12541: -16450, 3120: -31143, -5758: -4025, -14764: 22952, 26792: -16315, 12268: -8062, -31344: 20767, -10729: 652, 32354: 30556, 10533: 27076, 18563: 31611, -15395: -16343, -7271: 28710, 28693: -28840, 19304: -31194, 4838: -28332, -15421: 18530, 24139: -28363, -31872: 15347, 17464: -17470, 30063: -21708, -6516: -17705, 14553: 20142, 29460: -4329, -9381: -14281, 3286: 26530, -25478: 18858, 8614: 12250, 3087: 21051, -32628: 24370, -15651: -18351, 8024: 4382, 15805: -11203, -1077: 8609, 32285: -11583, -27614: 7211, -10535: 22639, -20099: 16870, 21230: 28095, 612: -23352, -5544: -26504, -25887: 2679, 14181: -26845, -31967: -7583, 26010: -15169, -6467: 12825, 24107: 4381, 3800: -2605, 2010: -21114, -1414: 6971, -12659: -21065, 20831: 9711, 20073: -8964, -24951: -3223, -6740: -32200, -8304: -23492, 27109: -8227, -17744: -25257, -28537: 18637, -18411: -15041, -25173: 928, -25903: -13895, -21831: -3009, -25678: 1895, 30480: 17166, -25850: 16586, 12531: -10102, 19095: -6338, -26672: -9944, 11671: 1505, -13311: 12087, 8454: 19381, -12936: -31002, -17139: 19189, 11596: 20259, -25535: 3542, 20951: -18777, -6500: -18332, 30742: -277, 31676: -30490, -27517: -19880, -25374: 32088, 21483: -10823, -16979: -18696, 14561: 13047, -13368: -16548, 4720: -14672, -29316: -19115, 1395: 9605, -10992: -10275, -21747: 8507, -4734: -6057, -30595: 16035, -24700: 22816, -2210: 19173, 7671: 24589, 27460: 5788, -10899: -21848, -26840: -3095, -28802: -2572, -3431: -5783, -21943: -31626, -22611: 26127, 3213: 396, -15957: 17787, -11959: 17422, 1613: 22455, 32292: -9957, -23718: -32341, 2795: 4614, -15162: 2211, 26391: 18246, 885: -15549, -29735: 26493, -17763: -9509, 832: 15026, -23215: 22609, 28230: 20969, -32629: 28951, 10402: -11520, 26729: 11732, 14065: -4855, -12988: 5456, -24309: -15464, -20942: -11584, -18355: 1571, 16650: -13337, -7873: -13362, 11313: -19130, 20194: -6007, -9755: -26600, -25013: 21165, -14900: 26513, 17728: 17821, -28277: -25003, -14757: 5100, 13577: -9806, -22115: 27298, 14668: -23429, -25174: -28161, 2367: 4067, -23795: 27843, -3780: 5571, 30910: -13600, 11355: -21254, -7086: 2278, -13419: 3221, 22732: 21622, 24582: 15497, -4771: -18262, -705: -24363, -6490: 13550, -3098: -31941, -20378: -12040, 25336: -18191, 21299: 822, -30797: -23895, -17162: 18699, 228: -17254, -12250: -21242, 4730: -2067, 8150: -16241, 15707: -29248, 6042: 32137, -26556: 15175, 14154: -28226, 9935: -23158, -29846: -22516, 9461: -29500, 11475: -19325, 31974: 2561, 1330: 8660, -1271: -17382, 3482: -8519, -25956: 15786, 25713: 3023, -394: -27817, 19478: 32434, -12289: 12678, -2608: 9330, -26485: -7465, -27840: 12092, -31666: 3630, 15748: -11979, 30892: 30006, -21505: -30879, 10340: 14885, 11619: 5575, -7216: -30397, -15140: -11637, 16761: -16433, -21925: 12562, 28429: 18057, -12739: -25584, 13377: -24419, -3752: 22641, 21444: -30136, -27669: 23044, 521: 28473, 9286: 5030, 29721: -14329, 10899: 8578, 9145: 15065, -30537: -15209, -21221: -5525, -16581: -17871, 27355: 23268, 56: 17851, -2659: 22647, -1630: 31617, -30759: -18270, -28584: -4801, 1875: 10171, -8604: -27218, -16634: -19036, -17802: -16413, 13379: -6140, 23704: 6880, 8765: -1719, -21255: -6806, -19546: 23388, -22379: -4391, -17126: -18724, -21340: -9110, 18182: -10221, -2471: 2014, 13850: 25597, 18153: -5252, 13325: -21738, -27130: 19737, 8324: -57, 16162: 17766, 30735: -1934, -13008: 18027, -14177: -26344, -3410: -15352, -22373: 13456, 23820: 30037, -16682: -8556, 2771: 32686, 7700: 2288, -15586: 23950, -23520: -30119, 24085: -27227, 28343: -27847, 11661: 11000, -2690: 6058, -30191: 21458, -10655: -20377, -18377: 8672, 15970: 29352, 13854: -28243, -12566: 12732, -11424: -5467, -13021: 19087, 4285: -20833, 4850: 15552, -28485: -26386, 8290: 259, -11749: 19444, 26075: -905, 30605: -1488, 6438: 27983, 9535: 25448, 10668: -26317, 9228: 2787, -9342: 6996, 3077: 2077, 14575: -17406, -13263: -28914, -16497: -8505, 17807: 29989, 17642: 27683, -7320: 22167, -28413: 23955, -29262: 1610, -7611: 20341, 13742: -22167, 1948: -3978, -26335: -18254, 7765: 4432, 22110: -27003, -3021: -16057, 15606: -23087, 8263: -28114, -28389: 28514, -24292: -3802, 593: -22012, -11632: 18700, -8493: -17690, -24000: 29402, -30405: 18870, 2054: -12353, 6302: 13902, 14627: 20456, -20713: -6796, 59: -27945, 15401: 3763, -31282: 2136, -30080: -21448, 596: 31173, -3777: 10969, -27062: -12955, 10983: -10220, 23508: 7525, 18741: -17043, -2752: -3564, 1045: 29156, -23741: -18438, -20412: -20083, 31569: 5108, -19554: 24719, -31716: -26184, 3254: 30063, -23755: -474, -10974: 24808, 32587: 24856, 13274: -13294, -23140: -5331, -1612: -8780, -12950: 16875, -7602: -1367, -8407: 24480, -18043: -18814, 5557: -14426, 23239: -32629, 12839: 10100, -23881: -9397, 9000: 1367, -16739: 24959, 27731: -23120, 1404: 16785, 26722: 2067, 13575: 21126, -4894: 14658, 13344: -7459, -3522: 8125, 10021: -14961, -10653: -5225, -23802: 25545, -6938: -12602, 3949: -14698, 29660: 11675, -2952: -7008, -30398: 12733, 24591: -27470, -8108: -1693, 8378: 6293, 19409: 107, -24293: 13979, -26643: 24382, -8928: 14933, -15145: -3845, -22551: 10211, 425: -15224, 16478: 7707, 2338: 16763, -23791: 31613, -8916: 7382, -5384: -31297, 10300: -1373, -27891: 1916, 2999: -30008, 1165: 24301, -397: -18055, -4201: -8619, -23959: -1718, 16219: -26007, -15100: -24529, -32527: -12160, 19770: -292, -10008: 22619, -26772: 3604, 236: 105, -7879: 31666, 19242: 10567, -6348: 14664, 5832: 13312, 1492: 10163, 8927: 21565, -26318: -18183, -10174: -25158, 9807: -26056, 26076: 17814, -15366: -19761, 2621: 12814, 30193: -31344, 4206: -18921, 7126: 22715, 16128: -10023, 25936: -31820}, index_rand = 5224467844040644997 +xs 361304641 2604218693 3136857884 1914902562 # shrinks to ref input = {-19354: 24819, -16292: -12090, -14434: -17000, 7065: 3299, -18458: 22292, 19194: 12574, 1: 18507, 32098: 548, 3309: 3711, 30631: 31499, -9540: -31601, 29472: 15053, 28278: 16574, 10805: -6409, 1937: -29445, -27617: -19598, 14618: -13991, -31216: -14546, -8002: -19976, 24690: -11392, 19023: 6532, -4475: -15383, -3276: 3043, -22021: -831, 7566: 28669, 7414: 7538, 3289: 1498, 32294: 11245, 27957: -24717, 394: -5551, -25550: 7578, -10781: 17801, -15265: 22301, -22600: -27228, 18049: 28811, -5680: -4765, 6393: -26312, -3763: 19239, 12387: -7834, -17270: 15102, -849: -18294, -11185: -8909, 5848: 28816, 4822: -1284, 9283: 17434, 5749: 13204, 11282: 18054, -30054: -1590, -5733: -8222, 27256: -17099, 25828: 27982, -26680: -20087, -31170: -3715, -27215: 20014, -3297: -27491, -4237: -9165, -3803: 6289, -13220: -7922, -31962: 28987, 15542: 18604, -17133: -25302, 13426: -25405, 2685: 15869, 5642: -8384, -8618: -21494, 696: -6333, 30169: 22735, -31498: -2698, -16350: -30346, 23455: -30868, 24880: 8411, 12752: -26951, 807: 5479, -31915: -6948, -6797: 32084, -27450: -5011, 12562: -16186, 16308: 9586, 8802: -8309, 22958: 1367, 5967: -7809, 7342: 9794, -21809: -30257, 22051: -8714, 11489: 27098, 9636: -24412, -22926: 4643, 16522: 3404, -13679: 20161, -20645: -4604, -27194: 2276, -1203: -23043, 15177: -16488, 17368: 19938, 18129: 13518, 29506: 13683, 30487: 29314, 22806: 20773, -1727: -29216, 8206: -19496, 7127: -23074, -2964: 1656, -8043: -15180, 31783: -24797, -14997: -8251, -9625: -985, -3485: -1572, 3259: 1018, 4124: 31363, -6871: 11567, -15128: -13650, -30770: 9112, -2638: 21963, -19057: 16043, 20685: 214, 17778: 6821, 27947: 8329, -13235: -3670, -15954: -21158, 12517: 13054, 23898: 16751, 16216: -18722, 15237: -7624, -31732: 21365, 30822: -28157, -17438: -30023, -26596: 3301, -13414: 5061, 17372: -8376, 30362: 28469, -20309: 143, 24393: 10508, -6411: 32337, -18972: 19110, 30365: 10104, -5140: 19909, 11898: 18406, -14442: -15467, -32552: 22492, -11355: 5350, -8307: -18294, 17475: 7093, 22597: 1992, 20469: 30777, -32614: -6165, 32573: 8339, 1514: 25969, 10701: -20617, -3021: -12256, 6587: 18950, -25402: 12031, -9936: 16285, -29946: 22912, -14064: -10944, 671: 13716, 5073: 7865, 5197: -26128, 19416: 9507, -30681: 8287, -21677: 28198, 3770: -21258, 14103: -8796, 21840: 6932, -14302: -3120, 18835: -21353, -19863: -30682, 30904: -24579, 23767: -2876, 14140: -7923, 23444: -8002, 20015: 24236, -8959: -10261, 19803: 10542, 13739: 29511, -28569: -14754, -3714: -30519, -14450: 8383, -11394: -30165, -32079: -13880, 13248: -30479, 11781: 9474, -10436: -2853, 6759: 27954, 25845: 29391, -31738: -26454, 30132: -23278, -18345: -23422, -25979: 16664, 9607: 29137, 8336: 22464, 20324: -23583, 15078: 31805, -28529: -17128, -12412: 9041, 5972: -27525, 10224: -32042, -6332: 7448, 26995: 20876, -12473: -28199, -23999: -23159, -18299: 21242, -14408: -31328, -29246: -10044, -10164: -28095, -27052: -5400, 10173: -25267, 23822: -17900, -23953: -13219, 28791: -8090, -21909: 21407, 17530: 26269, 29655: 29973, -16374: -16957, 13982: -24366, 11639: -20136, -18021: -4470, -28776: -14271, -19637: 20591, 17096: -6224, 19899: -7035, 10911: -124, 5706: -16549, 2364: -24950, -10944: 31678, 31723: 11433, 6413: 4440, 32675: 19466, 27096: -13819, -10806: 6633, -4937: 28751, -27140: -13550, -12557: 13547, 8629: 3152, 3413: 2565, -25866: 10729, -15566: -15218, -3621: -23194, 7527: -27521, -24127: -29997, 12909: -25868, 31772: 4680, 31014: 29821, 18678: -16508, 30298: 9039, 14505: -3668, 22669: -10595, 26152: -16178, 24944: -8114, 16694: -19338, -14047: 24498, -30270: 26317, -16665: -26461, -30656: 20249, 25517: -20809, -23571: 1882, 23007: 17866, -25659: 8076, -23717: -5810, 6904: 2115, 11784: -31335, 30197: 18033, 12572: -30508, 17268: -18072, 10674: -22655, 29365: 24132, -17185: 10599, 8749: -31736, -3334: 32668, 21915: -2453, 17556: -26978, -9373: 26250, 22616: 30289, 2165: 15435, 10766: 1818, 13715: -20952, 2935: -9271, 25227: 15051, 13045: 23934, 13260: 30812, 10690: -10114, 824: 8266, -14298: -13127, 11000: -14100, -18008: 21650, -8299: 6540, 3128: -12265, -7224: -8911, 19209: 14023, -8038: 24840, -26622: -26079, 14895: 22828, 31625: 20961, -2636: 19675, -17021: -28086, -5946: 15939, -32313: -153, -14012: 30196, 31144: 31395, 7996: 24091, 28923: -29327, -9247: 15709, -26391: -9285, -14883: 27089, -15544: -12422, 1374: 28261, -22870: -12032, 26286: -20763, 4080: 2040, -14599: 9484, 32660: -3226, -22977: 5487, 18067: 3363, -6489: -21852, -10804: -13137, 27933: 20036, 15275: -12004, -13892: -676, 16130: 22039, -24538: 21841, 24641: -3642, 21784: -26054, -20651: -27826, 5295: 32093, -24305: -3414, -18446: 10556, 4517: 526, 24294: 10881, 24194: 26364, -13901: 18395, -12783: -27360, -713: -29957, 8644: 14950, -6324: 9260, 9506: -30362, -29129: 6181, -3784: 18178, -28466: -21361, -18659: 3987, -10595: -19837, 7499: 30194, -12558: 7406, 28463: 12837, 27107: -2298, -6932: 4389, -32374: 25500, 23110: -23112, 8747: -22926, 4097: -2613, 3462: 30698, 3398: 31612, 30467: 23139, -1641: -3740, 3293: -19082, -20228: 31473, 20793: -17194, 17724: -25522, 8074: 32013, 23712: 19733, 31907: 8354, 12744: 28197, -24606: -11268, 23637: 3704, -3436: -24423, -2739: 10852, -4260: 18850, 12969: 6263, -26425: -6431, -28020: 25049, 31644: -1993, -20327: -6272, 22470: 17788, -28205: 31716, -21534: 32498, -4889: 19628, -825: 16644, -30248: -31584, -26932: -3743, -28597: 27796, 10641: 29403, 18736: 11379, 17445: 4741, 15954: -22253, 28955: 3994, -18758: -20179, -16666: -22951, -23409: 7546, 28441: 28286, -6600: 29204, 245: 5060, 21723: -31646, 13693: -28832, 17526: 19157, -3421: -30798, -12920: 25702, -13396: 4699, 25125: -17956, -378: 30900, -29352: 13943, 21551: -27295, -31207: 316, -5104: -20171, 10981: -14599, 13127: 7748, 12536: 20062, 15315: -493, 10111: 24216, 3207: -31216, 18499: -20515, 4815: 26753, 24865: -18658, 28562: -27549, -14256: -3818, 22292: 9007, 9550: -22562, -18174: -5902, 18354: -4282, -14416: 6361, -20722: -24289, 31715: 29227, 29704: 15935, -5533: -8673, 10845: -30941, 14160: 12144, 1992: 1318, -11404: 28138, -5428: 18711, -1624: 3223, -20437: 19171, -13983: -15469, 29721: -11600, -32689: 14340, -12675: 7713, -21501: 21229, -3729: 27686, 13580: -5131, -17708: 16700, 20809: 25221, -28564: -3272, 29509: 26850, -9889: -9564, 938: 25880, -17223: 18566, -20452: -799, -4292: -17811, -19061: -11617, 25764: -11388, -3347: -14170, 29220: -7185, -21149: -4187, -8341: -13996, -9012: -22916, 5303: -18306, 14513: 21706, -4815: 9868, 4316: 3968, 28688: -1524, -19338: 14733, -13386: -14098, 18253: 3130, -1221: -5690, 5093: 24217, -12424: -8733, 25791: 31206, 6697: 29204, 31192: 12158, 31407: 749, 17618: -3504, -3199: -3206, -11293: -20357, -16165: -3563, -27497: -25700, -27297: -3825, -23521: -23715, 4652: -29245, -17313: 10246, 22202: 28783, 12621: 7793, -25616: -9539, -8209: 11244, 2018: -23988, -29161: 7278, -17743: 748, 6678: -15931, -31969: -10178, 11253: -18267, 9135: -23204, -31002: 27729, 22133: 28453, -31372: 16243, 29200: -18504, 27344: -7996}, index_rand = 12865908526723545602 +xs 2514330554 4021224636 4249159765 809946243 # shrinks to ref input = {22983: 25567, -21524: 12652, -31419: -14369, 24781: -3215, -6098: -3626, -4344: 6615, 11513: -5995, -32129: -25765, 19648: -32475, 5272: 26666, 6416: 22836, 27222: -3403, -4042: 3636, 13253: -27848, 27331: -4442, 666: -14459, 13044: -27108, 2407: -18269, -11769: -23455, 6186: 23587, 3702: 7914, 29676: -21600, 12424: 12219, 27941: -5207, 15122: -12497, -11158: -27362, -8282: 26473, 3415: 26408, 12831: 17512, 5795: 28896, 21721: -11462, 20429: 9497, -12438: 9683, -3959: -13001, -25293: -23380, 5700: 24227, -21071: 9692, -18808: -24549, -27808: -4112, 14687: -13091, -14445: 10864, 8680: 29230, 28793: 2289, 572: 22804, -12907: -22882, 19549: 29926, -24247: -3077, -96: 16251, 8929: 32524, 18444: -31578, 24622: 19896, -20594: 13891, -22943: 19132, 31425: -2940, -12580: 30389, -526: 2891, -10880: -20465, -20861: -9108, -1990: -1706, -14673: -3333, -12415: 12446, 1711: -3619, 2889: 26166, 5135: -9934, 9761: 7314, -13727: -30121, 23167: -14068, 7972: -16912, 792: -2110, -23816: -11162, -14613: -11944, 2276: 16327, -1710: -513, 14501: 12803, -14424: 12359, 8166: 23242, 7132: -5033, 2661: 18395, -29564: -10169, -24378: -28753, -6535: -12561, 8864: 16922, 5509: 24075, 6948: -31451, 9166: -16562, -15552: -22739, -23577: -11089, -23262: 15724, 7935: -226, -15831: 22789, 19431: 12267, -32692: 13439, 8190: -27259, 5177: 21511, -25935: -29614, -23804: -9779, -5144: -13329, 13090: -1785, -24277: 11514, 23943: -7920, -5978: -7247, -10397: -26707, 25026: -2168, 16104: 8686, 1807: -29851, -24649: -22813, -19629: 11095, 22893: -20902, -23916: 17574, 1476: -25217, -24340: -19076, 28100: 15570, -22175: 22320, -6586: 6492, -18649: 11816, 16251: -21463, 17368: 3798, -20189: 3235, 16961: -6580, -8404: 20372, 16047: -15304, 29490: -3055, -24776: 15119, 27563: 16145, -22311: -2158, -15739: -32392, 2484: 14964, 21250: 7246, -9967: -28930, 31387: 5103, 14859: -2042, 16259: 31622, 29267: 26762, 6688: -2894, -25600: -27724, -22795: -11228, 2779: -25135, 3592: -29746, 2684: 25084, -14032: -6792, 16004: -29800, 10914: 6250, -15582: -26248, 21285: 13207, 22458: 2337, -13517: 14340, -29653: -16328, -9174: 8207, 6822: -22380, -13230: -5805, -24662: -20758, 23527: 6218, 21957: -1144, -29983: -14789, -25776: -10625, 29489: -29112, -634: -1687, 16362: -5095, 24103: 17173, -28568: 4122, -27366: -2615, -3220: 25064, 990: -31755, -14609: 23575, 31478: -24182, -15842: 9193, 7823: -20861, 32558: 23623, 28629: 20621, -27884: 26432, -14903: -17295, -20813: -25646, -14902: -25559, -13309: -1218, -12300: -17285, 31853: -3859, 1399: -7893, -26296: -29878, 19179: 13265, 15479: 17728, -25448: -8456, 13588: 27559, -24783: -7128, -32103: 29322, -1758: -3572, 13728: 31962, -17236: 5243, -21230: 27588, 20742: -27977, -20661: 4578, 9198: -15494, 5045: 25517, 29565: 31629, 20558: -6873, 24626: -30679, -7805: -9759, -3591: -19001, 28566: 18547, -13063: -28236, -19655: -4068, -9420: -16081, 25403: 23876, -17448: 2581, -26642: 1171, -24759: -17468, 20219: 24202, -30341: 13934, 27839: -18353, -545: -28904, 381: 6631, -14539: 19857, -2539: 19520, 31691: -3655, 1385: -507, 30959: -12761, -16041: 8706, 21997: -15520, -11702: 28136, -19969: -15001, -575: -19615, 15183: 2436, 5198: -26540, -18493: 24520, -17505: -5183, -2493: -30253, -25067: -4479, -1283: -3796, 31471: 3428, 25734: 30828, -12627: -6061, 11155: -26067, -26923: 20405, -24052: 21789, -435: -23207, 30135: -13145, -15985: 11367, 16307: 15640, 28752: -18459, 22594: 7750, 22206: -269, 12789: 803, 5691: -26452, 31114: 1532, -15192: -30273, 23101: 3141, 6407: 15910, -1158: -18687, -25606: 29881, 17713: 19127, -1122: -12940, -6489: -9054, 15743: 3691, 21427: -22498, 10898: 19136, -15369: 8230, 30219: 3776, 1353: 27070, 31264: 29339, 31831: -20760, -9233: -18316, 24841: -26176, -12699: 3016, -22370: -9549, -6545: -22728, -8574: -14535, -31864: -12833, 768: 15313, -19955: -22453, -30880: 9396, 29543: 755, -9778: -32702, -22077: -25372, -2605: 16746, -30839: 29080, 32699: 16318, 2417: -12052, -31380: 12651, 24376: -19710, -32686: 761, 5677: 30160, 12035: 12228, 32125: -20315, -20314: 5439, 11493: -17794, -26680: 11610, -28132: -20467, 16900: -25287, 25461: -31865, 24573: -32602, 9200: -1505, 27518: -25693, 12990: -27271, -9397: -803, 14105: 1387, 2651: 8640, 17112: 30678, -969: 19205, 19710: 31993, 1893: 5361, -17816: 24812, 2765: 16979, 1966: -21769, -26954: -1952, 29816: -1928, 26782: -29372, 18567: -22726, -10111: 5989, 14917: 22916, -14570: -2257, 1263: -4715, 18190: 30641, 11528: 12151, 4035: 20675, 20933: 20327, 20055: -30733, -14881: 6272, -26276: -44, 10879: -30096, -9294: -16413, 2817: 13299, 643: 15982, -7677: 4313, -20647: 31903, 3668: 29744, -895: 14661, -17897: -17401, -11844: -19818, -10186: 29763, -32372: 29925, -28816: 10622, 31355: 10910, -17637: -27328, 9535: -27794, 12855: 2934, -3109: 3109, -6427: -16454, -15442: 8398, -23169: 31026, 12834: -25030, 10930: -16079, -12447: 9572, 398: -5332, -11374: 27256, -12183: 32336, -14535: 14519, 12753: -3875, 8795: -11151, -3712: -16993, -26508: 14252, 20375: -14368, -13681: -745, -30307: -5112, 13277: 25773, -7944: -31433, -28425: -12788, 20210: 15294, 17797: -5799, -19999: -7498, 31427: -21005, 11063: 16683, -12187: -11576, 25180: 1372, 12244: -7444, 27900: 20262, 28587: 7083, 18724: 8161, -20180: 25818, 15692: -31648, -28303: 17209, -720: 21874, -16321: 31013, -454: 5366, 31803: 29349, 13754: 24292, 21162: -20849, -23732: -27863, 25477: -6654, -26061: -12152, 20032: -20593, -12006: 28036, 6291: -26468, 14737: 5272, 32728: 5626, -1731: -29345, 24503: 19404, -24868: -21379, -6468: -22831, 22287: 10296, 2631: -26020, 14590: 19330, -9565: 26433, -15283: 5147, 6630: 31769, -17396: -21499, -25553: -10823, 13619: -10207, 23182: -25363, -23069: -32662, 19477: 15524, -1868: 5359, 7929: 27049, -12723: 9380, -16172: -20285, -10286: -10075, -9506: 31490, -25795: 13824, -17148: -32529, -21164: -9272, 20979: 9504, -18600: -2080, 27700: -20006, 9823: 31533, -6997: -19415, 28861: 17091, 26758: -15191, 24983: -24729, -28254: -1130, 25914: -26157, -24819: 405, 20339: 9923, 30368: 1691, -21613: -748, 1453: -19462, 3731: 13394, -32452: 3223, 24913: -6930, -21912: 19356, -24594: 21413, -4422: -29373, -15940: -23075, 27267: 7024, 2732: -24160, -28400: 18241, -24538: 1422, -426: 12283, -10915: -11143, -22114: 31517, 28357: 14424, 19009: 15527, -11167: -4468, 22854: -18910, -23106: 19639, 10382: 23860, 6220: -23926, -26385: -10089, -7503: -5631, 22781: -1889, 16878: -26298, 18982: 21243, 31681: 22201, -7993: 27285, -7299: 25550, 610: 16890, 8167: 21304, -16920: -617, -22339: 30620, 11333: -26987, -26992: -20496, -7985: -22986, 10141: -7469, 372: -21212, 17081: -17544, -11618: -922, 27971: 8305, -28364: -29445, 15932: 3403, 20712: -21072, 14139: 24028, -1589: -1905, 32372: -17183, -21555: 12537, 31409: 17560, 3035: -19927, -5300: 22560, -4845: 21856, 15699: -25855, 7642: 27579, 30284: -15949, -30974: -30226, 15786: 8546, -5179: 30950, 5765: 5052, 1410: -23757, -2705: -31393, 4012: 30468, -1359: -31879, -24808: 31414, 7542: 20843, -26533: -25712, 16975: 8303, -3145: -28727, 30626: -4547, 7331: -22347, -229: -15652, 26743: 8164, -28242: -12747, -13570: 28103, -31635: -32305, 25882: -22303, 392: -21213, -3910: -419, -24637: -4685, 15423: -4564, 16842: -5323, 2530: -6191, -28954: -20857, 12709: -1223, -29605: -31941, -15037: 9147, -2441: -9869, -30549: -24089, -2045: -24975, -6257: 5642, 19458: -26673, -11026: -32379, 11073: -2714, -16340: 29939, 22558: -389, -282: -29137, -8915: 10668, 13276: -26492, -6567: 15209, 18167: 6255, 18833: 9305, 23382: 9685, 22344: -6270, -5200: -17657, -27124: -17742, -19079: -568, 31073: -16882, 28075: 23525, -27683: -6870, -4980: 20988, 15716: -12047, -17167: -27903, 14047: 1751, 18332: 17369, -4584: -13960, -19312: -7004, 24390: -26226, -31358: -20950, 2846: 8574, 23256: -28403, -12965: -970, -10968: 6290, 31485: 3696, -14595: -24510, 8331: -24508, 16660: -6434, -21947: -11573, -13276: 18857, -11196: 13858, 20146: 29787, 26780: 16229, 22109: -21982, 3218: 12243, 20958: -15577, -25637: -8935, -29695: -30458, -27502: -9512, 6608: -10482, 260: -12910, 7060: 3640, 20729: -5920, 9177: 17672, 23669: 9673, -4719: -23531, 12804: -12848, -29031: -3714, 17216: -27527, -23101: 8400, -6250: 26869, -26842: -26986, -21952: 31092, 14811: 3573, -6081: 2717, -10912: -16202, -24595: 20431, -11358: -22184, 21588: -21605, -6061: 3518, 18275: -24618, 24224: 28119, -32273: 6717, -25485: -19967, -21076: -16695, -16947: -17173, 6350: -31349, 21046: 2696, 16207: -13750, -6710: 6770, 24774: -11316, -26121: -7976, 24586: -1831, -28350: -32385, -28591: 6607, 19897: 5582, 10787: -15060, 10497: -6872, -10294: 17802, -8472: 16304, -25702: 1771, 24559: 25237, -22562: 12409, 5848: 32381, 6698: 29851, -29088: -2362, -25758: -7282, 13364: 9287, 9286: -21108, -5875: 7021, 10384: -19100, -14947: -31087, 9224: -30160, 10825: 11627, 15906: 24744, -2491: 14682, 25078: -8675, -1487: 9277, 20301: -16262, -16721: 3749, 12876: 2719, -17183: 4920, -7383: -20989, 587: -29137, 1359: -18302, -31714: 5165, -10671: 13375, -1014: 25286, -5237: 14127, -20162: -15366, -17597: -27172, -16427: 24301, 21080: 29359, -16296: 21156, -27123: 17636, -14475: -17380, 3677: 3071, -13795: -14542, 25583: 2939, -18388: 26695, -30563: -10031, -19535: 16570, 22004: 14784, 4240: 16012, -26396: -7757, 1009: -24215, 10291: 31948, 31730: 31672, -27181: 4692, -7558: 15578, 8628: 18466, 15093: -25146, 15115: -23111, -25498: 19694, -29510: -6893, 10810: -20013, -7953: 24646, 17484: -6921, -22020: 317, 6794: 31084, 3107: 30850, 31725: 21696, -27069: -15468, 20231: -10374, 13074: -27686, -5761: 4056, 6032: 974, -515: -19247, -21834: -21830, 12853: -24945, -12244: 15573, 22762: -30055, 21333: 27246, 17857: -18844, 7569: -30916, 2863: 30220, 24301: -32097, -26608: -8747, -32337: -4850, 27215: 16975, -28845: 5184, 29948: 16776, -8096: -19809, 28922: 1579, -22399: -10320, 23633: 9402, 25594: -10014, -19789: 21539, 7783: -5857, 6413: 28988, 18148: 24286, 16425: -21685, -2117: 24914, 22809: -2465, -4052: 29220, -17437: -20536, 1701: -13236, 3559: -26792, 13260: 28650, 24280: 28935, -31390: 4155, -27444: 448, -15557: -22317, -26261: 14775, 8621: -19065, 854: -24623, -13346: -13154, 28008: 7670, 8308: -26926, -15207: -30554, -4728: -30539, 19116: -14938, -31105: 13428, -17085: 28001, 640: 29984, -30694: -21836, 31336: 29388, -23090: 26134, -22064: -8217, 23023: 25281, 28377: 3055, -826: 32149, -10250: 30089, -21073: -18570, -18476: -26801, -26910: -26764, -23220: -30649, 11262: 14325, 3587: 12688, -20447: -11553, -14604: -1133, 3267: 12700, -30988: -604, 31066: -5487, 4192: 1516, -9863: 26649, -12142: 839, -5180: -23733, 4771: 18192, -30173: 21726, 5816: -6256, -332: -23918, 9971: 21833, 368: 10035, 7709: 315, 18131: 27655, -12214: -2422, 8036: -21700, -12127: 30496, -17331: 23521, -5948: -28752, 9996: -22175, -12256: -9599, 12127: -14043, 8773: 23434, -24251: 31338, -30890: 4170, 796: 22060, -9480: -23318, 30137: -12439, -11200: -14846, -20960: -6630, -11449: -12059, 1710: -25246, 27339: -29509, 23266: -11878, 11424: 13957, -31513: -6604, 29223: 6248, 18427: 26701, -12933: -29661, -22958: 17397, -20885: -7075, -12532: 11832, -11207: -31040, -25413: -32634, -24423: 1136, 27748: -23097, 6865: -20862, 18880: -20717, -10317: -13842, -13186: -15707, 26939: -25776, 28970: 10404, -5636: 14068, -20214: 17872, 24853: 30283, 9956: 8484, 9398: -6284, -16839: 21664, 22800: -14869, 6033: 9989, -4795: -32223, 7279: -20473, 1275: -11857, 22338: 29810, 27015: -1704, -19258: 30646, 29954: 8034, -25853: 14141, 3311: -18597, -23320: -20940, -29480: 24564, 10547: 5534, -242: -13465, 24209: -1327, 10490: -5572, 7640: -20006, -8432: 5032, -11149: -24754, -4663: -23686, -10592: -7167, -25371: 22450, 4522: 7837, 6151: 19181, -18379: -20567, -31877: -18894, 17881: 7374, 24203: -4232, -15566: 16796, 5510: -31735, 15169: -20736, -29601: -27463, 7747: -430, 25280: -6754, -15509: 2251, -3086: -2933, 5884: 27703, -11157: -24312, 14484: -912, -3230: -9668, 16082: -25169, -137: 14744, -2665: -8726, 32412: 31615, -7276: -27566, 6279: 1989, -25300: -15901, 2440: 7619, 31956: 264, -5369: 16171, 14418: 1610, 18599: 4848, 20977: -22077, -6321: -4946, -8343: -22193, 1775: -19058, 26761: -28761, -12920: 27027, 4448: -11253, 25002: 4314, -22369: 23526, -12022: -7474, 32105: -12895, 1455: -4159, 15674: -28876, 11387: 18072, -27516: -8671, -10452: 32061, -29518: 28392, 29722: -20187, 15094: -22775, -31173: 17747, 28936: -12104, -19139: -6836, 10489: -818, -19250: 2431, -24391: 29686, 5886: 4259, 11123: 7634, 14067: 14441}, index_rand = 8788646705830835008 +xs 1144700111 3351133221 1701312047 4140849688 # shrinks to ref input = {-995: -18367, -30184: -27030, 4338: -17464, -26495: 18470, -23875: 6714, 11043: 22383, -7998: 11935, 16847: 5368, -9936: 1676, 469: -14105, -25789: -439, 2949: -19822, -13219: -11532, -13024: 24096, 7755: -32141, 5267: 20461, 13213: 5297, -7746: 31930, -24638: 20376, 11502: 161, 28692: -9359, -5352: 788, 17858: 16574, -4832: 26375, 3089: 1666, -27646: -21448, -29415: 27692, 5699: -11459, 9914: -14535, 10779: 11740, -29883: 790, 1921: -17804, -2606: 26661, 355: 10341, -9220: -21783, 10130: 2847, -28778: -8331, -26138: 21104, 19481: -11787, 23407: -22704, -13780: 6006, 7248: 6188, 9583: -27582, -19931: 21871, 7757: 32217, 7030: 24321, 13903: -28335, -6040: -8746, -16956: 3084, -27320: 10074, -11931: 23573, -14684: -2347, 25890: 13771, 770: -22088, 3703: -21750, -20005: -1416, -7260: -3308, -13212: 5663, 11568: -1211, -31546: -12571, 1625: -28634, 29510: -27517, -14067: -32392, -6952: -15279, 32194: -28535, 22530: -9153, 23590: -10792, -24830: 4545, -1413: 4698, 13676: -29216, -22119: 20809, 11493: -23219, 30324: -19957, -19740: 9364, -28332: 23760, 7598: -15700, 5250: 5262, 8892: -11149, 512: 21208, -26713: -22645, 15901: -16244, -11774: 25184, -27782: 31736, 1932: 28625, -19899: -15534, -14500: 28168, -31943: -10376, 5096: -6393, -12529: -28083, 15871: -31782, 24491: 9705, -13197: -2280, 20267: 26985, -2805: -7895, -12439: -25986, -1013: 18461, 1975: 32395, 22412: 8807, 18620: -21921, 18836: -11655, 20099: 15576, -15176: -556, -16690: 10393, -20701: -25137, 16023: 6541, 6323: 30693, 22672: 4962, 6262: -6543, 16070: 8710, 16145: 28518, -1209: -18693, -28389: -24853, 17412: -24261, 3497: 10996, 9187: -19998, -32168: 10884, 3560: 7346, 22807: 23444, -23068: 18732, -26136: -17299, 4558: -4291, 16805: 25070, 23084: 30635, -25411: 22895, -2902: 31559, -7150: -27951, -20232: 1338, 6838: 27765, -31069: -28409, 11606: -29065, -13760: 30312, -2036: -14916, 25218: 18519, -10854: -7745, 27820: 15149, 102: 7496, 804: 9488, 30201: -8547, 32678: 20708, -25202: 31329, -5584: -22884, -5108: 30003, 25093: -865, 27335: 6724, -10328: 15249, 5215: -12859, 25426: -6436, 4131: 8277, -19570: 7708, 20395: 7626, 3155: 12890, 19644: 581, -19031: -9366, -7803: 24805, 6673: -15061, -10892: -20442, -28410: 17433, -18136: 18606, 16432: 31698, -9848: 7414, 10831: 4060, -19606: -19806, -26041: -14198, 7826: 18579, -12900: -19535, -21442: 30662, -9253: -13676, 4185: -25497, -32472: -11113, -20772: -21936, 30731: 247, -17401: -28973, -11698: -26755, -17077: -5017, 22536: -3777, 13939: 16609, -8959: -24782, 29183: 15322, 28738: -31932, 12914: -31447, 27024: 19561, -6230: -2767, -18069: 12291, -3808: -532, 8699: -30308, -13072: 26305, -24174: -1772, 5083: -26578, 32374: -29090, -32055: 12554, 8496: -6213, 3295: 7339, 13897: 31817, -32448: -28910, 16533: 26195, 16795: -8295, 23292: -32385, 15102: 2439, 9462: 19663, 24237: 21643, 5357: 20413, 2361: 5794, 25247: -17229, -4187: 5207, -21262: 19783, -24684: -4240, -24679: -18791, 2368: -8363, 12208: -20319, 23264: 16664, -13617: 1275, -19198: -25513, 5092: 16212, 15124: 28714, 21439: -1196, -4432: 30044, 9557: -4855, -22916: 1046, -26280: 25826, -27674: -20014, -13633: 27408, -10975: -4991, 26520: -9235, -6589: 27583, -31631: -21487, 31832: 8595, -18451: -12811, -10412: -24981, 17602: -10428, -25014: 15888, 21325: 14946, 7746: 2626, -29626: -22668, 29538: -5978, 21901: 5842, 13851: 31830, -11034: 29385, -3586: 7536, -6063: 32614, -11727: 16659, 29320: -1367, -21326: 9220, 3205: -1974, -4787: 12852, 30793: 2568, 25796: 9433, 19016: -13799, -9621: -14129, 20136: 20434, -18060: -13251, -634: 18285, 15435: 22675, 29971: 5174, 31997: -29557, 18450: 7875, 22519: -12860, -10973: -20277, -26809: 31348, 6220: 11504, -178: 22232, 9592: -1419, -13548: 27708, 6172: 20899, 27648: 15593, -12157: 24765, -3131: 27366, -1827: -2958, 18365: 18538, -17861: -8596, -25217: -20668, -4257: -9796, -27958: -17570, -11603: -23589, -17591: -21385, 23905: 22546, -6098: 13776, -26132: 18512, 8204: 14798, 29533: 4545, 62: 22711, -9020: -8280, 11140: -8181, 1781: 10516, -1334: 15284, -7224: 7160, -28987: 22020, -4891: 8434, -4403: 19578, -20394: 14965, 29827: -30255, -560: 29091, -23917: -11862, -13868: -21175, -10219: 16295, 2577: 3128, 9484: -11742, 8668: 21789, -25813: -8178, -21404: 29342, -21751: 13687, 18052: 7524, -19144: -30345, 24903: -25167, 30700: 1834, -28266: 27752, -30375: 954, -11219: -5836, 28011: 8806, 20451: -23577, 10616: -15512, 6848: 4786, -5701: -16618, 10552: -612, 14323: -30855, 25785: -3039, -423: -22087, 20028: 21248, -31919: 15338, -19884: 15952, -22678: -176}, index_rand = 4536586039788573449 +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 888006417 2608449019 3789353629 478040202 # shrinks to ref m = {0: 0} diff --git a/im-rc/proptest-regressions/ord/map.txt b/im-rc/proptest-regressions/ord/map.txt new file mode 100644 index 000000000..fc1e1def3 --- /dev/null +++ b/im-rc/proptest-regressions/ord/map.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 888006417 2608449019 3789353629 478040202 # shrinks to ref m = {0: 0} diff --git a/im-rc/proptest-regressions/ser.txt b/im-rc/proptest-regressions/ser.txt new file mode 100644 index 000000000..d5c25a33f --- /dev/null +++ b/im-rc/proptest-regressions/ser.txt @@ -0,0 +1,10 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 3983395997 40281418 114824171 2339847213 # shrinks to ref v = {1285771567, -841112960, -2090277076, 1080385872, 900828884, 615148720, -333870035, -1551786909, -1167746969, -1453736382, -1747821313, 367596715, 1982056530, -1495713558} +xs 2832291072 3367532499 2480853836 1445020057 # shrinks to ref v = {-1006265241: 1190299023, -874470135: -656918271, -747552887: -119701798, -446035143: 289470610, -38617499: -70412299, -28555422: 742423513, 549345238: -1218765301, 1006459863: 373426025, 1730586809: 1217890615, 1741069766: 1330906833} +xs 497222929 1550339526 1868828736 2852494662 # shrinks to ref v = {-33, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, 0} +xs 3367619631 4093181880 814513877 3641392342 # shrinks to ref v = {-33: 0, -32: 0, -31: 0, -30: 0, -29: 0, -28: 0, -27: 0, -26: 0, -25: 0, -24: 0, -23: 0, -22: 0, -21: 0, -20: 0, -19: 0, -18: 0, -17: 0, -16: 0, -15: 0, -14: 0, -13: 0, -12: 0, -11: 0, -10: 0, -9: 0, -8: 0, -7: 0, -6: 0, -5: 0, -4: 0, -3: 0, -2: 0, 0: 0} diff --git a/im-rc/proptest-regressions/sort.txt b/im-rc/proptest-regressions/sort.txt new file mode 100644 index 000000000..a6b62f5d4 --- /dev/null +++ b/im-rc/proptest-regressions/sort.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 1397459766 1987461941 1386942626 306293423 # shrinks to ref input = [0, 777418683, 1143505337, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1422499358, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1143505337, 0, -275943289, -1, 0, 0, 0, 777418684, 0, 777418684] diff --git a/im-rc/proptest-regressions/tests/vector.txt b/im-rc/proptest-regressions/tests/vector.txt new file mode 100644 index 000000000..3dcf8b199 --- /dev/null +++ b/im-rc/proptest-regressions/tests/vector.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc a81c870198d194d869b85a541fca54b5a3f3ea4e84705bfdede6212ad7451789 # shrinks to actions = [PushFront(0), PushFront(0), PushFront(0), PushFront(0), PushFront(0), PushFront(0), SplitLeft(0), PushFront(0), PushFront(0), PushFront(0), Remove(0), PopFront, PushFront(0), PushFront(0), PushFront(0), PushFront(0), PushFront(0), PushFront(0), SplitLeft(1026178654884686841), PushFront(0), PushFront(0), SplitLeft(2673257349917114567), PushFront(0), PushFront(0), PushFront(0), PushFront(0), JoinLeft([0, 0, 0, 0, 0, 0, 0]), PushFront(0), PushFront(0), SplitRight(6380212717721778205), JoinLeft([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), PopFront, Insert(0, 0), PushFront(0), PushFront(0), SplitRight(12236220624414400388), Insert(0, 0), PushFront(0), JoinLeft([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), SplitLeft(13848748256934322935), JoinLeft([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), JoinLeft([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), JoinLeft([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), SplitLeft(13115524110820767241), Insert(0, 0), JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), PushFront(0), PopFront, PopFront, Remove(0), Insert(0, 0), PopFront, JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), PopFront, PushFront(0), PopFront, PushFront(0), PushFront(0), Remove(0), SplitLeft(9383655485369749481), JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), PopBack, PushFront(0), Insert(455053961473158936, 0), SplitRight(676041696221001931), PushBack(0), PopFront, JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), JoinRight([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), PushFront(0), PushFront(0), PushFront(0), JoinLeft([0])] +cc bae4a6aa243531a345cb36883fda4aebc84848fffe12d051df4e24ff22af3689 # shrinks to actions = let mut vec = Vector::new(); let mut vec_new = Vector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); vec_new.append(vec); vec = vec_new; vec = vec.split_off(6); vec.pop_front(); vec.pop_front(); vec.push_front(0); vec.pop_front(); vec.push_front(0); vec.append(Vector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); vec.split_off(141); let mut vec_new = Vector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); vec_new.append(vec); vec = vec_new; vec.insert(41, 0); vec.pop_front(); vec.pop_front(); vec = vec.split_off(5); vec.pop_front(); vec.append(Vector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])); vec.append(Vector::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])); vec.push_front(0); vec.push_front(0); let mut vec_new = Vector::from([0]); vec_new.append(vec); vec = vec_new; diff --git a/im-rc/proptest-regressions/vector/mod.txt b/im-rc/proptest-regressions/vector/mod.txt new file mode 100644 index 000000000..375392de6 --- /dev/null +++ b/im-rc/proptest-regressions/vector/mod.txt @@ -0,0 +1,11 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 781088174 2402437932 46071810 3445483747 # shrinks to ref vec = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +xs 1236163365 497060525 1875560600 3785939576 +xs 2440477773 3871129562 3025797391 1057174199 # shrinks to ref vec1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ref vec2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +xs 3956050500 706730731 3245945489 2502775722 # shrinks to ref vec1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ref vec2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +cc cf2875f6f7c5648d87ffcab4ccac7f8a8f720c93ee377e89f8c86e542cc643bc diff --git a/im-rc/src/config.rs b/im-rc/src/config.rs new file mode 100644 index 000000000..84f1a21f5 --- /dev/null +++ b/im-rc/src/config.rs @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use typenum::*; + +/// The branching factor of RRB-trees +pub type VectorChunkSize = U64; + +/// The branching factor of B-trees +pub type OrdChunkSize = U64; // Must be an even number! + +/// The level size of HAMTs, in bits +/// Branching factor is 2 ^ HashLevelSize. +pub type HashLevelSize = U5; diff --git a/im-rc/src/hash/map.rs b/im-rc/src/hash/map.rs new file mode 100644 index 000000000..07ce723b5 --- /dev/null +++ b/im-rc/src/hash/map.rs @@ -0,0 +1,2214 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! An unordered map. +//! +//! An immutable hash map using [hash array mapped tries] [1]. +//! +//! Most operations on this map are O(logx n) for a +//! suitably high *x* that it should be nearly O(1) for most maps. +//! Because of this, it's a great choice for a generic map as long as +//! you don't mind that keys will need to implement +//! [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +//! +//! Map entries will have a predictable order based on the hasher +//! being used. Unless otherwise specified, this will be the standard +//! [`RandomState`][std::collections::hash_map::RandomState] hasher. +//! +//! [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie +//! [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +//! [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html +//! [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::collections; +use std::collections::hash_map::RandomState; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{BuildHasher, Hash, Hasher}; +use std::iter::{FromIterator, FusedIterator, Sum}; +use std::mem; +use std::ops::{Add, Index, IndexMut}; + +use crate::nodes::hamt::{ + hash_key, Drain as NodeDrain, HashBits, HashValue, Iter as NodeIter, IterMut as NodeIterMut, + Node, +}; +use crate::util::Ref; + +/// Construct a hash map from a sequence of key/value pairs. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::hashmap::HashMap; +/// # fn main() { +/// assert_eq!( +/// hashmap!{ +/// 1 => 11, +/// 2 => 22, +/// 3 => 33 +/// }, +/// HashMap::from(vec![(1, 11), (2, 22), (3, 33)]) +/// ); +/// # } +/// ``` +#[macro_export] +macro_rules! hashmap { + () => { $crate::hashmap::HashMap::new() }; + + ( $( $key:expr => $value:expr ),* ) => {{ + let mut map = $crate::hashmap::HashMap::new(); + $({ + map.insert($key, $value); + })*; + map + }}; + + ( $( $key:expr => $value:expr ,)* ) => {{ + let mut map = $crate::hashmap::HashMap::new(); + $({ + map.insert($key, $value); + })*; + map + }}; +} + +/// An unordered map. +/// +/// An immutable hash map using [hash array mapped tries] [1]. +/// +/// Most operations on this map are O(logx n) for a +/// suitably high *x* that it should be nearly O(1) for most maps. +/// Because of this, it's a great choice for a generic map as long as +/// you don't mind that keys will need to implement +/// [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +/// +/// Map entries will have a predictable order based on the hasher +/// being used. Unless otherwise specified, this will be the standard +/// [`RandomState`][std::collections::hash_map::RandomState] hasher. +/// +/// [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie +/// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + +pub struct HashMap { + size: usize, + root: Ref>, + hasher: Ref, +} + +impl HashValue for (K, V) +where + K: Eq, +{ + type Key = K; + + fn extract_key(&self) -> &Self::Key { + &self.0 + } + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } +} + +impl HashMap { + /// Construct an empty hash map. + #[inline] + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +impl HashMap +where + K: Hash + Eq + Clone, + V: Clone, +{ + /// Construct a hash map with a single mapping. + /// + /// This method has been deprecated; use [`unit`][unit] instead. + /// + /// [unit]: #method.unit + #[inline] + #[must_use] + #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")] + pub fn singleton(k: K, v: V) -> HashMap { + Self::unit(k, v) + } + + /// Construct a hash map with a single mapping. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map = HashMap::unit(123, "onetwothree"); + /// assert_eq!( + /// map.get(&123), + /// Some(&"onetwothree") + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn unit(k: K, v: V) -> HashMap { + HashMap::new().update(k, v) + } +} + +impl HashMap { + /// Test whether a hash map is empty. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// assert!( + /// !hashmap!{1 => 2}.is_empty() + /// ); + /// assert!( + /// HashMap::::new().is_empty() + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the size of a hash map. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// assert_eq!(3, hashmap!{ + /// 1 => 11, + /// 2 => 22, + /// 3 => 33 + /// }.len()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.size + } + + /// Construct an empty hash map using the provided hasher. + #[inline] + #[must_use] + pub fn with_hasher(hasher: RS) -> Self + where + Ref: From, + { + HashMap { + size: 0, + root: Ref::new(Node::new()), + hasher: From::from(hasher), + } + } + + /// Get a reference to the map's [`BuildHasher`][BuildHasher]. + /// + /// [BuildHasher]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + #[must_use] + pub fn hasher(&self) -> &Ref { + &self.hasher + } + + /// Construct an empty hash map using the same hasher as the + /// current hash map. + #[inline] + #[must_use] + pub fn new_from(&self) -> HashMap + where + K1: Hash + Eq + Clone, + V1: Clone, + { + HashMap { + size: 0, + root: Ref::new(Node::new()), + hasher: self.hasher.clone(), + } + } + + /// Get an iterator over the key/value pairs of a hash map. + /// + /// Please note that the order is consistent between maps using + /// the same hasher, but no other ordering guarantee is offered. + /// Items will not come out in insertion order or sort order. + /// They will, however, come out in the same order every time for + /// the same map. + #[inline] + #[must_use] + pub fn iter(&self) -> Iter<'_, K, V> { + Iter { + it: NodeIter::new(&self.root, self.size), + } + } + + /// Get an iterator over a hash map's keys. + /// + /// Please note that the order is consistent between maps using + /// the same hasher, but no other ordering guarantee is offered. + /// Items will not come out in insertion order or sort order. + /// They will, however, come out in the same order every time for + /// the same map. + #[inline] + #[must_use] + pub fn keys(&self) -> Keys { + Keys { + it: NodeIter::new(&self.root, self.size), + } + } + + /// Get an iterator over a hash map's values. + /// + /// Please note that the order is consistent between maps using + /// the same hasher, but no other ordering guarantee is offered. + /// Items will not come out in insertion order or sort order. + /// They will, however, come out in the same order every time for + /// the same map. + #[inline] + #[must_use] + pub fn values(&self) -> Values { + Values { + it: NodeIter::new(&self.root, self.size), + } + } + + /// Discard all elements from the map. + /// + /// This leaves you with an empty map, and all elements that + /// were previously inside it are dropped. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::HashMap; + /// # fn main() { + /// let mut map = hashmap![1=>1, 2=>2, 3=>3]; + /// map.clear(); + /// assert!(map.is_empty()); + /// # } + /// ``` + pub fn clear(&mut self) { + if !self.is_empty() { + self.root = Default::default(); + self.size = 0; + } + } +} + +impl HashMap +where + K: Hash + Eq, + S: BuildHasher, +{ + fn test_eq(&self, other: &Self) -> bool + where + K: Hash + Eq, + V: PartialEq, + { + if self.len() != other.len() { + return false; + } + let mut seen = collections::HashSet::new(); + for (key, value) in self.iter() { + if Some(value) != other.get(&key) { + return false; + } + seen.insert(key); + } + for key in other.keys() { + if !seen.contains(&key) { + return false; + } + } + true + } + + /// Get the value for a key from a hash map. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map = hashmap!{123 => "lol"}; + /// assert_eq!( + /// map.get(&123), + /// Some(&"lol") + /// ); + /// # } + /// ``` + #[must_use] + pub fn get(&self, key: &BK) -> Option<&V> + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + self.root + .get(hash_key(&*self.hasher, key), 0, key) + .map(|&(_, ref v)| v) + } + + /// Test for the presence of a key in a hash map. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map = hashmap!{123 => "lol"}; + /// assert!( + /// map.contains_key(&123) + /// ); + /// assert!( + /// !map.contains_key(&321) + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn contains_key(&self, k: &BK) -> bool + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + self.get(k).is_some() + } + + /// Test whether a map is a submap of another map, meaning that + /// all keys in our map must also be in the other map, with the + /// same values. + /// + /// Use the provided function to decide whether values are equal. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_submap_by(&self, other: RM, mut cmp: F) -> bool + where + F: FnMut(&V, &B) -> bool, + RM: Borrow>, + { + self.iter() + .all(|(k, v)| other.borrow().get(k).map(|ov| cmp(v, ov)).unwrap_or(false)) + } + + /// Test whether a map is a proper submap of another map, meaning + /// that all keys in our map must also be in the other map, with + /// the same values. To be a proper submap, ours must also contain + /// fewer keys than the other map. + /// + /// Use the provided function to decide whether values are equal. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_proper_submap_by(&self, other: RM, cmp: F) -> bool + where + F: FnMut(&V, &B) -> bool, + RM: Borrow>, + { + self.len() != other.borrow().len() && self.is_submap_by(other, cmp) + } + + /// Test whether a map is a submap of another map, meaning that + /// all keys in our map must also be in the other map, with the + /// same values. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 2 => 2}; + /// let map2 = hashmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert!(map1.is_submap(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_submap(&self, other: RM) -> bool + where + V: PartialEq, + RM: Borrow, + { + self.is_submap_by(other.borrow(), PartialEq::eq) + } + + /// Test whether a map is a proper submap of another map, meaning + /// that all keys in our map must also be in the other map, with + /// the same values. To be a proper submap, ours must also contain + /// fewer keys than the other map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 2 => 2}; + /// let map2 = hashmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert!(map1.is_proper_submap(map2)); + /// + /// let map3 = hashmap!{1 => 1, 2 => 2}; + /// let map4 = hashmap!{1 => 1, 2 => 2}; + /// assert!(!map3.is_proper_submap(map4)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_proper_submap(&self, other: RM) -> bool + where + V: PartialEq, + RM: Borrow, + { + self.is_proper_submap_by(other.borrow(), PartialEq::eq) + } +} + +impl HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + /// Get a mutable iterator over the values of a hash map. + /// + /// Please note that the order is consistent between maps using + /// the same hasher, but no other ordering guarantee is offered. + /// Items will not come out in insertion order or sort order. + /// They will, however, come out in the same order every time for + /// the same map. + #[inline] + #[must_use] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + let root = Ref::make_mut(&mut self.root); + IterMut { + it: NodeIterMut::new(root, self.size), + } + } + + /// Get a mutable reference to the value for a key from a hash + /// map. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map = hashmap!{123 => "lol"}; + /// assert_eq!( + /// map.get(&123), + /// Some(&"lol") + /// ); + /// # } + /// ``` + #[must_use] + pub fn get_mut(&mut self, key: &BK) -> Option<&mut V> + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + let root = Ref::make_mut(&mut self.root); + match root.get_mut(hash_key(&*self.hasher, key), 0, key) { + None => None, + Some(&mut (_, ref mut value)) => Some(value), + } + } + + /// Insert a key/value mapping into a map. + /// + /// If the map already has a mapping for the given key, the + /// previous value is overwritten. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let mut map = hashmap!{}; + /// map.insert(123, "123"); + /// map.insert(456, "456"); + /// assert_eq!( + /// map, + /// hashmap!{123 => "123", 456 => "456"} + /// ); + /// # } + /// ``` + #[inline] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = hash_key(&*self.hasher, &k); + let root = Ref::make_mut(&mut self.root); + let result = root.insert(hash, 0, (k, v)); + if result.is_none() { + self.size += 1; + } + result.map(|(_, v)| v) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed value. + /// + /// This is a copy-on-write operation, so that the parts of the + /// set's structure which are shared with other sets will be + /// safely copied before mutating. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let mut map = hashmap!{123 => "123", 456 => "456"}; + /// assert_eq!(Some("123"), map.remove(&123)); + /// assert_eq!(Some("456"), map.remove(&456)); + /// assert_eq!(None, map.remove(&789)); + /// assert!(map.is_empty()); + /// # } + /// ``` + pub fn remove(&mut self, k: &BK) -> Option + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + self.remove_with_key(k).map(|(_, v)| v) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed key and value. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let mut map = hashmap!{123 => "123", 456 => "456"}; + /// assert_eq!(Some((123, "123")), map.remove_with_key(&123)); + /// assert_eq!(Some((456, "456")), map.remove_with_key(&456)); + /// assert_eq!(None, map.remove_with_key(&789)); + /// assert!(map.is_empty()); + /// # } + /// ``` + pub fn remove_with_key(&mut self, k: &BK) -> Option<(K, V)> + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + let root = Ref::make_mut(&mut self.root); + let result = root.remove(hash_key(&*self.hasher, k), 0, k); + if result.is_some() { + self.size -= 1; + } + result + } + + /// Get the [`Entry`][Entry] for a key in the map for in-place manipulation. + /// + /// Time: O(log n) + /// + /// [Entry]: enum.Entry.html + #[must_use] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> { + let hash = hash_key(&*self.hasher, &key); + if self.root.get(hash, 0, &key).is_some() { + Entry::Occupied(OccupiedEntry { + map: self, + hash, + key, + }) + } else { + Entry::Vacant(VacantEntry { + map: self, + hash, + key, + }) + } + } + + /// Construct a new hash map by inserting a key/value mapping into a map. + /// + /// If the map already has a mapping for the given key, the previous value + /// is overwritten. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map = hashmap!{}; + /// assert_eq!( + /// map.update(123, "123"), + /// hashmap!{123 => "123"} + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn update(&self, k: K, v: V) -> Self { + let mut out = self.clone(); + out.insert(k, v); + out + } + + /// Construct a new hash map by inserting a key/value mapping into + /// a map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the old value and the new value, + /// and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_with(&self, k: K, v: V, f: F) -> Self + where + F: FnOnce(V, V) -> V, + { + match self.extract_with_key(&k) { + None => self.update(k, v), + Some((_, v2, m)) => m.update(k, f(v2, v)), + } + } + + /// Construct a new map by inserting a key/value mapping into a + /// map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the key, the old value and the new + /// value, and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_with_key(&self, k: K, v: V, f: F) -> Self + where + F: FnOnce(&K, V, V) -> V, + { + match self.extract_with_key(&k) { + None => self.update(k, v), + Some((_, v2, m)) => { + let out_v = f(&k, v2, v); + m.update(k, out_v) + } + } + } + + /// Construct a new map by inserting a key/value mapping into a + /// map, returning the old value for the key as well as the new + /// map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the key, the old value and the new + /// value, and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_lookup_with_key(&self, k: K, v: V, f: F) -> (Option, Self) + where + F: FnOnce(&K, &V, V) -> V, + { + match self.extract_with_key(&k) { + None => (None, self.update(k, v)), + Some((_, v2, m)) => { + let out_v = f(&k, &v2, v); + (Some(v2), m.update(k, out_v)) + } + } + } + + /// Update the value for a given key by calling a function with + /// the current value and overwriting it with the function's + /// return value. + /// + /// The function gets an [`Option`][std::option::Option] and + /// returns the same, so that it can decide to delete a mapping + /// instead of updating the value, and decide what to do if the + /// key isn't in the map. + /// + /// Time: O(log n) + /// + /// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html + #[must_use] + pub fn alter(&self, f: F, k: K) -> Self + where + F: FnOnce(Option) -> Option, + { + let pop = self.extract_with_key(&k); + match (f(pop.as_ref().map(|&(_, ref v, _)| v.clone())), pop) { + (None, None) => self.clone(), + (Some(v), None) => self.update(k, v), + (None, Some((_, _, m))) => m, + (Some(v), Some((_, _, m))) => m.update(k, v), + } + } + + /// Construct a new map without the given key. + /// + /// Construct a map that's a copy of the current map, absent the + /// mapping for `key` if it's present. + /// + /// Time: O(log n) + #[must_use] + pub fn without(&self, k: &BK) -> Self + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + match self.extract_with_key(k) { + None => self.clone(), + Some((_, _, map)) => map, + } + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed value as well as the updated map. + /// + /// Time: O(log n) + #[must_use] + pub fn extract(&self, k: &BK) -> Option<(V, Self)> + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + self.extract_with_key(k).map(|(_, v, m)| (v, m)) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed key and value as well as the updated list. + /// + /// Time: O(log n) + #[must_use] + pub fn extract_with_key(&self, k: &BK) -> Option<(K, V, Self)> + where + BK: Hash + Eq + ?Sized, + K: Borrow, + { + let mut out = self.clone(); + out.remove_with_key(k).map(|(k, v)| (k, v, out)) + } + + /// Construct the union of two maps, keeping the values in the + /// current map when keys exist in both maps. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 3 => 3}; + /// let map2 = hashmap!{2 => 2, 3 => 4}; + /// let expected = hashmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert_eq!(expected, map1.union(map2)); + /// # } + /// ``` + #[must_use] + pub fn union(mut self, other: Self) -> Self { + for (k, v) in other { + self.entry(k).or_insert(v); + } + self + } + + /// Construct the union of two maps, using a function to decide + /// what to do with the value when a key is in both maps. + /// + /// The function is called when a value exists in both maps, and + /// receives the value from the current map as its first argument, + /// and the value from the other map as the second. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn union_with(self, other: Self, mut f: F) -> Self + where + F: FnMut(V, V) -> V, + { + self.union_with_key(other, |_, v1, v2| f(v1, v2)) + } + + /// Construct the union of two maps, using a function to decide + /// what to do with the value when a key is in both maps. + /// + /// The function is called when a value exists in both maps, and + /// receives a reference to the key as its first argument, the + /// value from the current map as the second argument, and the + /// value from the other map as the third argument. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 3 => 4}; + /// let map2 = hashmap!{2 => 2, 3 => 5}; + /// let expected = hashmap!{1 => 1, 2 => 2, 3 => 9}; + /// assert_eq!(expected, map1.union_with_key( + /// map2, + /// |key, left, right| left + right + /// )); + /// # } + /// ``` + #[must_use] + pub fn union_with_key(mut self, other: Self, mut f: F) -> Self + where + F: FnMut(&K, V, V) -> V, + { + for (key, right_value) in other { + match self.remove(&key) { + None => { + self.insert(key, right_value); + } + Some(left_value) => { + let final_value = f(&key, left_value, right_value); + self.insert(key, final_value); + } + } + } + self + } + + /// Construct the union of a sequence of maps, selecting the value + /// of the leftmost when a key appears in more than one map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 3 => 3}; + /// let map2 = hashmap!{2 => 2}; + /// let expected = hashmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert_eq!(expected, HashMap::unions(vec![map1, map2])); + /// # } + /// ``` + #[must_use] + pub fn unions(i: I) -> Self + where + S: Default, + I: IntoIterator, + { + i.into_iter().fold(Self::default(), Self::union) + } + + /// Construct the union of a sequence of maps, using a function to + /// decide what to do with the value when a key is in more than + /// one map. + /// + /// The function is called when a value exists in multiple maps, + /// and receives the value from the current map as its first + /// argument, and the value from the next map as the second. It + /// should return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions_with(i: I, f: F) -> Self + where + S: Default, + I: IntoIterator, + F: Fn(V, V) -> V, + { + i.into_iter() + .fold(Self::default(), |a, b| a.union_with(b, &f)) + } + + /// Construct the union of a sequence of maps, using a function to + /// decide what to do with the value when a key is in more than + /// one map. + /// + /// The function is called when a value exists in multiple maps, + /// and receives a reference to the key as its first argument, the + /// value from the current map as the second argument, and the + /// value from the next map as the third argument. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions_with_key(i: I, f: F) -> Self + where + S: Default, + I: IntoIterator, + F: Fn(&K, V, V) -> V, + { + i.into_iter() + .fold(Self::default(), |a, b| a.union_with_key(b, &f)) + } + + /// Construct the difference between two maps by discarding keys + /// which occur in both maps. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 3 => 4}; + /// let map2 = hashmap!{2 => 2, 3 => 5}; + /// let expected = hashmap!{1 => 1, 2 => 2}; + /// assert_eq!(expected, map1.difference(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn difference(self, other: Self) -> Self { + self.difference_with_key(other, |_, _, _| None) + } + + /// Construct the difference between two maps by using a function + /// to decide what to do if a key occurs in both. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn difference_with(self, other: Self, mut f: F) -> Self + where + F: FnMut(V, V) -> Option, + { + self.difference_with_key(other, |_, a, b| f(a, b)) + } + + /// Construct the difference between two maps by using a function + /// to decide what to do if a key occurs in both. The function + /// receives the key as well as both values. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 3 => 4}; + /// let map2 = hashmap!{2 => 2, 3 => 5}; + /// let expected = hashmap!{1 => 1, 2 => 2, 3 => 9}; + /// assert_eq!(expected, map1.difference_with_key( + /// map2, + /// |key, left, right| Some(left + right) + /// )); + /// # } + /// ``` + #[must_use] + pub fn difference_with_key(mut self, other: Self, mut f: F) -> Self + where + F: FnMut(&K, V, V) -> Option, + { + let mut out = self.new_from(); + for (key, right_value) in other { + match self.remove(&key) { + None => { + out.insert(key, right_value); + } + Some(left_value) => { + if let Some(final_value) = f(&key, left_value, right_value) { + out.insert(key, final_value); + } + } + } + } + out.union(self) + } + + /// Construct the intersection of two maps, keeping the values + /// from the current map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 2 => 2}; + /// let map2 = hashmap!{2 => 3, 3 => 4}; + /// let expected = hashmap!{2 => 2}; + /// assert_eq!(expected, map1.intersection(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn intersection(self, other: Self) -> Self { + self.intersection_with_key(other, |_, v, _| v) + } + + /// Construct the intersection of two maps, calling a function + /// with both values for each key and using the result as the + /// value for the key. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn intersection_with(self, other: HashMap, mut f: F) -> HashMap + where + B: Clone, + C: Clone, + F: FnMut(V, B) -> C, + { + self.intersection_with_key(other, |_, v1, v2| f(v1, v2)) + } + + /// Construct the intersection of two maps, calling a function + /// with the key and both values for each key and using the result + /// as the value for the key. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashmap::HashMap; + /// # fn main() { + /// let map1 = hashmap!{1 => 1, 2 => 2}; + /// let map2 = hashmap!{2 => 3, 3 => 4}; + /// let expected = hashmap!{2 => 5}; + /// assert_eq!(expected, map1.intersection_with_key( + /// map2, + /// |key, left, right| left + right + /// )); + /// # } + /// ``` + #[must_use] + pub fn intersection_with_key( + mut self, + other: HashMap, + mut f: F, + ) -> HashMap + where + B: Clone, + C: Clone, + F: FnMut(&K, V, B) -> C, + { + let mut out = self.new_from(); + for (key, right_value) in other { + match self.remove(&key) { + None => (), + Some(left_value) => { + let result = f(&key, left_value, right_value); + out.insert(key, result); + } + } + } + out + } +} + +// Entries + +/// A handle for a key and its associated value. +/// +/// ## Performance Note +/// +/// When using an `Entry`, the key is only ever hashed once, when you +/// create the `Entry`. Operations on an `Entry` will never trigger a +/// rehash, where eg. a `contains_key(key)` followed by an +/// `insert(key, default_value)` (the equivalent of +/// `Entry::or_insert()`) would need to hash the key once for the +/// `contains_key` and again for the `insert`. The operations +/// generally perform similarly otherwise. +pub enum Entry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + Occupied(OccupiedEntry<'a, K, V, S>), + Vacant(VacantEntry<'a, K, V, S>), +} + +impl<'a, K, V, S> Entry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + /// Insert the default value provided if there was no value + /// already, and return a mutable reference to the value. + pub fn or_insert(self, default: V) -> &'a mut V { + self.or_insert_with(|| default) + } + + /// Insert the default value from the provided function if there + /// was no value already, and return a mutable reference to the + /// value. + pub fn or_insert_with(self, default: F) -> &'a mut V + where + F: FnOnce() -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Insert a default value if there was no value already, and + /// return a mutable reference to the value. + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + self.or_insert_with(Default::default) + } + + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + match self { + Entry::Occupied(entry) => entry.key(), + Entry::Vacant(entry) => entry.key(), + } + } + + /// Call the provided function to modify the value if the value + /// exists. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match &mut self { + Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Vacant(_) => (), + } + self + } +} + +/// An entry for a mapping that already exists in the map. +pub struct OccupiedEntry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + map: &'a mut HashMap, + hash: HashBits, + key: K, +} + +impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + &self.key + } + + /// Remove this entry from the map and return the removed mapping. + pub fn remove_entry(self) -> (K, V) { + let root = Ref::make_mut(&mut self.map.root); + let result = root.remove(self.hash, 0, &self.key); + self.map.size -= 1; + result.unwrap() + } + + /// Get the current value. + #[must_use] + pub fn get(&self) -> &V { + &self.map.root.get(self.hash, 0, &self.key).unwrap().1 + } + + /// Get a mutable reference to the current value. + #[must_use] + pub fn get_mut(&mut self) -> &mut V { + let root = Ref::make_mut(&mut self.map.root); + &mut root.get_mut(self.hash, 0, &self.key).unwrap().1 + } + + /// Convert this entry into a mutable reference. + #[must_use] + pub fn into_mut(self) -> &'a mut V { + let root = Ref::make_mut(&mut self.map.root); + &mut root.get_mut(self.hash, 0, &self.key).unwrap().1 + } + + /// Overwrite the current value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Remove this entry from the map and return the removed value. + pub fn remove(self) -> V { + self.remove_entry().1 + } +} + +/// An entry for a mapping that does not already exist in the map. +pub struct VacantEntry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + map: &'a mut HashMap, + hash: HashBits, + key: K, +} + +impl<'a, K, V, S> VacantEntry<'a, K, V, S> +where + K: 'a + Hash + Eq + Clone, + V: 'a + Clone, + S: 'a + BuildHasher, +{ + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + &self.key + } + + /// Convert this entry into its key. + #[must_use] + pub fn into_key(self) -> K { + self.key + } + + /// Insert a value into this entry. + pub fn insert(self, value: V) -> &'a mut V { + let root = Ref::make_mut(&mut self.map.root); + if root + .insert(self.hash, 0, (self.key.clone(), value)) + .is_none() + { + self.map.size += 1; + } + // TODO it's unfortunate that we need to look up the key again + // here to get the mut ref. + &mut root.get_mut(self.hash, 0, &self.key).unwrap().1 + } +} + +// Core traits + +impl Clone for HashMap +where + K: Clone, + V: Clone, +{ + #[inline] + fn clone(&self) -> Self { + HashMap { + root: self.root.clone(), + size: self.size, + hasher: self.hasher.clone(), + } + } +} + +#[cfg(not(has_specialisation))] +impl PartialEq for HashMap +where + K: Hash + Eq, + V: PartialEq, + S: BuildHasher, +{ + fn eq(&self, other: &Self) -> bool { + self.test_eq(other) + } +} + +#[cfg(has_specialisation)] +impl PartialEq for HashMap +where + K: Hash + Eq, + V: PartialEq, + S: BuildHasher, +{ + default fn eq(&self, other: &Self) -> bool { + self.test_eq(other) + } +} + +#[cfg(has_specialisation)] +impl PartialEq for HashMap +where + K: Hash + Eq, + V: Eq, + S: BuildHasher, +{ + fn eq(&self, other: &Self) -> bool { + if Ref::ptr_eq(&self.root, &other.root) { + return true; + } + self.test_eq(other) + } +} + +impl Eq for HashMap +where + K: Hash + Eq, + V: Eq, + S: BuildHasher, +{ +} + +impl PartialOrd for HashMap +where + K: Hash + Eq + Clone + PartialOrd, + V: PartialOrd + Clone, + S: BuildHasher, +{ + fn partial_cmp(&self, other: &Self) -> Option { + if Ref::ptr_eq(&self.hasher, &other.hasher) { + return self.iter().partial_cmp(other.iter()); + } + let m1: ::std::collections::HashMap = self.iter().cloned().collect(); + let m2: ::std::collections::HashMap = other.iter().cloned().collect(); + m1.iter().partial_cmp(m2.iter()) + } +} + +impl Ord for HashMap +where + K: Hash + Eq + Ord + Clone, + V: Ord + Clone, + S: BuildHasher, +{ + fn cmp(&self, other: &Self) -> Ordering { + if Ref::ptr_eq(&self.hasher, &other.hasher) { + return self.iter().cmp(other.iter()); + } + let m1: ::std::collections::HashMap = self.iter().cloned().collect(); + let m2: ::std::collections::HashMap = other.iter().cloned().collect(); + m1.iter().cmp(m2.iter()) + } +} + +impl Hash for HashMap +where + K: Hash + Eq, + V: Hash, + S: BuildHasher, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + for i in self.iter() { + i.hash(state); + } + } +} + +impl Default for HashMap +where + S: BuildHasher + Default, +{ + #[inline] + fn default() -> Self { + HashMap { + size: 0, + root: Ref::new(Node::new()), + hasher: Ref::::default(), + } + } +} + +impl Add for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + type Output = HashMap; + + fn add(self, other: Self) -> Self::Output { + self.union(other) + } +} + +impl<'a, K, V, S> Add for &'a HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + type Output = HashMap; + + fn add(self, other: Self) -> Self::Output { + self.clone().union(other.clone()) + } +} + +impl Sum for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn sum(it: I) -> Self + where + I: Iterator, + { + it.fold(Self::default(), |a, b| a + b) + } +} + +impl Extend<(RK, RV)> for HashMap +where + K: Hash + Eq + Clone + From, + V: Clone + From, + S: BuildHasher, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for (key, value) in iter { + self.insert(From::from(key), From::from(value)); + } + } +} + +impl<'a, BK, K, V, S> Index<&'a BK> for HashMap +where + BK: Hash + Eq + ?Sized, + K: Hash + Eq + Borrow, + S: BuildHasher, +{ + type Output = V; + + fn index(&self, key: &BK) -> &Self::Output { + match self.root.get(hash_key(&*self.hasher, key), 0, key) { + None => panic!("HashMap::index: invalid key"), + Some(&(_, ref value)) => value, + } + } +} + +impl<'a, BK, K, V, S> IndexMut<&'a BK> for HashMap +where + BK: Hash + Eq + ?Sized, + K: Hash + Eq + Clone + Borrow, + V: Clone, + S: BuildHasher, +{ + fn index_mut(&mut self, key: &BK) -> &mut Self::Output { + let root = Ref::make_mut(&mut self.root); + match root.get_mut(hash_key(&*self.hasher, key), 0, key) { + None => panic!("HashMap::index_mut: invalid key"), + Some(&mut (_, ref mut value)) => value, + } + } +} + +#[cfg(not(has_specialisation))] +impl Debug for HashMap +where + K: Hash + Eq + Debug, + V: Debug, + S: BuildHasher, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut d = f.debug_map(); + for (k, v) in self { + d.entry(k, v); + } + d.finish() + } +} + +#[cfg(has_specialisation)] +impl Debug for HashMap +where + K: Hash + Eq + Debug, + V: Debug, + S: BuildHasher, +{ + default fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut d = f.debug_map(); + for (k, v) in self { + d.entry(k, v); + } + d.finish() + } +} + +#[cfg(has_specialisation)] +impl Debug for HashMap +where + K: Hash + Eq + Ord + Debug, + V: Debug, + S: BuildHasher, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut keys = collections::BTreeSet::new(); + keys.extend(self.keys()); + let mut d = f.debug_map(); + for key in keys { + d.entry(key, &self[key]); + } + d.finish() + } +} + +// // Iterators + +// An iterator over the elements of a map. +pub struct Iter<'a, K: 'a, V: 'a> { + it: NodeIter<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = &'a (K, V); + + fn next(&mut self) -> Option { + self.it.next().map(|(p, _)| p) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {} + +impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} + +// A mutable iterator over the values of a map. +pub struct IterMut<'a, K: 'a, V: 'a> +where + K: Clone, + V: Clone, +{ + it: NodeIterMut<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> +where + K: Clone, + V: Clone, +{ + type Item = &'a mut V; + + fn next(&mut self) -> Option { + self.it.next().map(|(entry, _)| &mut entry.1) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> +where + K: Clone, + V: Clone, +{ +} + +impl<'a, K, V> FusedIterator for IterMut<'a, K, V> +where + K: Clone, + V: Clone, +{ +} + +// A consuming iterator over the elements of a map. +pub struct ConsumingIter { + it: NodeDrain, +} + +impl Iterator for ConsumingIter +where + A: HashValue + Clone, +{ + type Item = A; + + fn next(&mut self) -> Option { + self.it.next().map(|(p, _)| p) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl ExactSizeIterator for ConsumingIter where A: HashValue + Clone {} + +impl FusedIterator for ConsumingIter where A: HashValue + Clone {} + +// An iterator over the keys of a map. +pub struct Keys<'a, K: 'a, V: 'a> { + it: NodeIter<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + fn next(&mut self) -> Option { + self.it.next().map(|((k, _), _)| k) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {} + +impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} + +// An iterator over the values of a map. +pub struct Values<'a, K: 'a, V: 'a> { + it: NodeIter<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + fn next(&mut self) -> Option { + self.it.next().map(|((_, v), _)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {} + +impl<'a, K, V> FusedIterator for Values<'a, K, V> {} + +impl<'a, K, V, S> IntoIterator for &'a HashMap +where + K: Hash + Eq, + S: BuildHasher, +{ + type Item = &'a (K, V); + type IntoIter = Iter<'a, K, V>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher, +{ + type Item = (K, V); + type IntoIter = ConsumingIter<(K, V)>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + ConsumingIter { + it: NodeDrain::new(self.root, self.size), + } + } +} + +// Conversions + +impl FromIterator<(K, V)> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from_iter(i: T) -> Self + where + T: IntoIterator, + { + let mut map = Self::default(); + for (k, v) in i { + map.insert(k, v); + } + map + } +} + +impl AsRef> for HashMap { + #[inline] + fn as_ref(&self) -> &Self { + self + } +} + +impl<'m, 'k, 'v, K, V, OK, OV, SA, SB> From<&'m HashMap<&'k K, &'v V, SA>> for HashMap +where + K: Hash + Eq + ToOwned + ?Sized, + V: ToOwned + ?Sized, + OK: Hash + Eq + Clone + Borrow, + OV: Borrow + Clone, + SA: BuildHasher, + SB: BuildHasher + Default, +{ + fn from(m: &HashMap<&K, &V, SA>) -> Self { + m.iter() + .map(|(k, v)| ((*k).to_owned(), (*v).to_owned())) + .collect() + } +} + +impl<'a, K, V, S> From<&'a [(K, V)]> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: &'a [(K, V)]) -> Self { + m.iter().cloned().collect() + } +} + +impl From> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: Vec<(K, V)>) -> Self { + m.into_iter().collect() + } +} + +impl<'a, K, V, S> From<&'a Vec<(K, V)>> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: &'a Vec<(K, V)>) -> Self { + m.iter().cloned().collect() + } +} + +impl From> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: collections::HashMap) -> Self { + m.into_iter().collect() + } +} + +impl<'a, K, V, S> From<&'a collections::HashMap> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: &'a collections::HashMap) -> Self { + m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + } +} + +impl From> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: collections::BTreeMap) -> Self { + m.into_iter().collect() + } +} + +impl<'a, K, V, S> From<&'a collections::BTreeMap> for HashMap +where + K: Hash + Eq + Clone, + V: Clone, + S: BuildHasher + Default, +{ + fn from(m: &'a collections::BTreeMap) -> Self { + m.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + } +} + +// impl From> for HashMap +// where +// S: BuildHasher + Default, +// { +// fn from(m: OrdMap) -> Self { +// m.into_iter().collect() +// } +// } + +// impl<'a, K: Ord + Hash + Eq, V, S> From<&'a OrdMap> for HashMap +// where +// S: BuildHasher + Default, +// { +// fn from(m: &'a OrdMap) -> Self { +// m.into_iter().collect() +// } +// } + +// QuickCheck + +#[cfg(all(feature = "arc", any(test, feature = "quickcheck")))] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(all(feature = "arc", any(test, feature = "quickcheck")))] +impl Arbitrary for HashMap { + fn arbitrary(g: &mut G) -> Self { + HashMap::from(Vec::<(K, V)>::arbitrary(g)) + } +} + +// Proptest + +#[cfg(any(test, feature = "proptest"))] +pub mod proptest { + use super::*; + use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; + use std::ops::Range; + + /// A strategy for a hash map of a given size. + /// + /// # Examples + /// + /// ```rust,ignore + /// proptest! { + /// #[test] + /// fn proptest_works(ref m in hash_map(0..9999, ".*", 10..100)) { + /// assert!(m.len() < 100); + /// assert!(m.len() >= 10); + /// } + /// } + /// ``` + pub fn hash_map( + key: K, + value: V, + size: Range, + ) -> BoxedStrategy::Value, ::Value>> + where + ::Value: Hash + Eq + Clone, + ::Value: Clone, + { + ::proptest::collection::vec((key, value), size.clone()) + .prop_map(HashMap::from) + .prop_filter("Map minimum size".to_owned(), move |m| { + m.len() >= size.start + }) + .boxed() + } +} + +// Tests + +#[cfg(test)] +mod test { + use super::*; + use crate::test::LolHasher; + use ::proptest::num::{i16, usize}; + use ::proptest::{collection, proptest}; + use std::hash::BuildHasherDefault; + + #[test] + fn safe_mutation() { + let v1: HashMap = HashMap::from_iter((0..131_072).map(|i| (i, i))); + let mut v2 = v1.clone(); + v2.insert(131_000, 23); + assert_eq!(Some(&23), v2.get(&131_000)); + assert_eq!(Some(&131_000), v1.get(&131_000)); + } + + #[test] + fn index_operator() { + let mut map = hashmap![1 => 2, 3 => 4, 5 => 6]; + assert_eq!(4, map[&3]); + map[&3] = 8; + assert_eq!(hashmap![1 => 2, 3 => 8, 5 => 6], map); + } + + #[test] + fn proper_formatting() { + let map = hashmap![1 => 2]; + assert_eq!("{1: 2}", format!("{:?}", map)); + + assert_eq!("{}", format!("{:?}", HashMap::<(), ()>::new())); + } + + #[test] + fn remove_failing() { + let pairs = [(1469, 0), (-67, 0)]; + let hasher: BuildHasherDefault = Default::default(); + let mut m: collections::HashMap = + collections::HashMap::with_hasher(hasher.clone()); + for &(ref k, ref v) in &pairs { + m.insert(*k, *v); + } + let mut map: HashMap = HashMap::with_hasher(hasher); + for (k, v) in &m { + map = map.update(*k, *v); + } + for k in m.keys() { + let l = map.len(); + assert_eq!(m.get(k).cloned(), map.get(k).cloned()); + map = map.without(k); + assert_eq!(None, map.get(k)); + assert_eq!(l - 1, map.len()); + } + } + + #[test] + fn match_string_keys_with_string_slices() { + let mut map: HashMap = + From::from(&hashmap! { "foo" => &1, "bar" => &2, "baz" => &3 }); + assert_eq!(Some(&1), map.get("foo")); + map = map.without("foo"); + assert_eq!(Some(3), map.remove("baz")); + map["bar"] = 8; + assert_eq!(8, map["bar"]); + } + + #[test] + fn macro_allows_trailing_comma() { + let map1 = hashmap! {"x" => 1, "y" => 2}; + let map2 = hashmap! { + "x" => 1, + "y" => 2, + }; + assert_eq!(map1, map2); + } + + #[test] + fn remove_top_level_collisions() { + let pairs = vec![9, 2569, 27145]; + let mut map: HashMap> = Default::default(); + for k in pairs.clone() { + map.insert(k, k); + } + assert_eq!(pairs.len(), map.len()); + let keys: Vec<_> = map.keys().cloned().collect(); + for k in keys { + let l = map.len(); + assert_eq!(Some(&k), map.get(&k)); + map.remove(&k); + assert_eq!(None, map.get(&k)); + assert_eq!(l - 1, map.len()); + } + } + + #[test] + fn entry_api() { + let mut map = hashmap! {"bar" => 5}; + map.entry(&"foo").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(1, map[&"foo"]); + map.entry(&"foo").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(6, map[&"foo"]); + map.entry(&"bar").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(10, map[&"bar"]); + assert_eq!( + 10, + match map.entry(&"bar") { + Entry::Occupied(entry) => entry.remove(), + _ => panic!(), + } + ); + assert!(!map.contains_key(&"bar")); + } + + #[test] + fn large_map() { + let mut map = HashMap::new(); + let size = 32769; + for i in 0..size { + map.insert(i, i); + } + assert_eq!(size, map.len()); + for i in 0..size { + assert_eq!(Some(&i), map.get(&i)); + } + } + + proptest! { + #[test] + fn update_and_length(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let mut map: HashMap> = Default::default(); + for (index, (k, v)) in m.iter().enumerate() { + map = map.update(*k, *v); + assert_eq!(Some(v), map.get(k)); + assert_eq!(index + 1, map.len()); + } + } + + #[test] + fn from_iterator(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let map: HashMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(m.len(), map.len()); + } + + #[test] + fn iterate_over(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let map: HashMap = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(m.len(), map.iter().count()); + } + + #[test] + fn equality(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let map1: HashMap = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + let map2: HashMap = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(map1, map2); + } + + #[test] + fn lookup(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let map: HashMap = FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + for (k, v) in m { + assert_eq!(Some(*v), map.get(k).cloned()); + } + } + + #[test] + fn without(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) { + let hasher: BuildHasherDefault = Default::default(); + let mut m: collections::HashMap = + collections::HashMap::with_hasher(hasher.clone()); + for &(ref k, ref v) in pairs { + m.insert(*k, *v); + } + let mut map: HashMap = HashMap::with_hasher(hasher); + for (k, v) in &m { + map = map.update(*k, *v); + } + for k in m.keys() { + let l = map.len(); + assert_eq!(m.get(k).cloned(), map.get(k).cloned()); + map = map.without(k); + assert_eq!(None, map.get(k)); + assert_eq!(l - 1, map.len()); + } + } + + #[test] + fn insert(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..100)) { + let mut mut_map: HashMap> = Default::default(); + let mut map: HashMap> = Default::default(); + for (count, (k, v)) in m.iter().enumerate() { + map = map.update(*k, *v); + mut_map.insert(*k, *v); + assert_eq!(count + 1, map.len()); + assert_eq!(count + 1, mut_map.len()); + } + assert_eq!(map, mut_map); + } + + #[test] + fn remove(ref pairs in collection::vec((i16::ANY, i16::ANY), 0..100)) { + let hasher: BuildHasherDefault = Default::default(); + let mut m: collections::HashMap = + collections::HashMap::with_hasher(hasher.clone()); + for &(ref k, ref v) in pairs { + m.insert(*k, *v); + } + let mut map: HashMap = HashMap::with_hasher(hasher); + for (k, v) in &m { + map.insert(*k, *v); + } + for k in m.keys() { + let l = map.len(); + assert_eq!(m.get(k).cloned(), map.get(k).cloned()); + map.remove(k); + assert_eq!(None, map.get(k)); + assert_eq!(l - 1, map.len()); + } + } + + #[test] + fn delete_and_reinsert( + ref input in collection::hash_map(i16::ANY, i16::ANY, 1..100), + index_rand in usize::ANY + ) { + let index = *input.keys().nth(index_rand % input.len()).unwrap(); + let map1: HashMap<_, _> = HashMap::from_iter(input.clone()); + let (val, map2) = map1.extract(&index).unwrap(); + let map3 = map2.update(index, val); + for key in map2.keys() { + assert!(*key != index); + } + assert_eq!(map1.len(), map2.len() + 1); + assert_eq!(map1, map3); + } + + #[test] + fn proptest_works(ref m in proptest::hash_map(0..9999, ".*", 10..100)) { + assert!(m.len() < 100); + assert!(m.len() >= 10); + } + + #[test] + fn exact_size_iterator(ref m in proptest::hash_map(i16::ANY, i16::ANY, 0..100)) { + let mut should_be = m.len(); + let mut it = m.iter(); + loop { + assert_eq!(should_be, it.len()); + match it.next() { + None => break, + Some(_) => should_be -= 1, + } + } + assert_eq!(0, it.len()); + } + } +} diff --git a/im-rc/src/hash/mod.rs b/im-rc/src/hash/mod.rs new file mode 100644 index 000000000..27a56a5e2 --- /dev/null +++ b/im-rc/src/hash/mod.rs @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#[macro_use] +pub mod map; +#[macro_use] +pub mod set; diff --git a/im-rc/src/hash/set.rs b/im-rc/src/hash/set.rs new file mode 100644 index 000000000..781ca517b --- /dev/null +++ b/im-rc/src/hash/set.rs @@ -0,0 +1,1102 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! An unordered set. +//! +//! An immutable hash set using [hash array mapped tries] [1]. +//! +//! Most operations on this set are O(logx n) for a +//! suitably high *x* that it should be nearly O(1) for most sets. +//! Because of this, it's a great choice for a generic set as long as +//! you don't mind that values will need to implement +//! [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +//! +//! Values will have a predictable order based on the hasher +//! being used. Unless otherwise specified, this will be the standard +//! [`RandomState`][std::collections::hash_map::RandomState] hasher. +//! +//! [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie +//! [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +//! [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html +//! [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.h + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::collections::hash_map::RandomState; +use std::collections::{self, BTreeSet}; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{BuildHasher, Hash, Hasher}; +use std::iter::FusedIterator; +use std::iter::{FromIterator, IntoIterator, Sum}; +use std::ops::{Add, Deref, Mul}; + +use crate::nodes::hamt::{ + hash_key, Drain as NodeDrain, HashValue, Iter as NodeIter, IterMut as NodeIterMut, Node, +}; +use crate::ordset::OrdSet; +use crate::util::Ref; + +/// Construct a set from a sequence of values. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::hashset::HashSet; +/// # fn main() { +/// assert_eq!( +/// hashset![1, 2, 3], +/// HashSet::from(vec![1, 2, 3]) +/// ); +/// # } +/// ``` +#[macro_export] +macro_rules! hashset { + () => { $crate::hashset::HashSet::new() }; + + ( $($x:expr),* ) => {{ + let mut l = $crate::hashset::HashSet::new(); + $( + l.insert($x); + )* + l + }}; + + ( $($x:expr ,)* ) => {{ + let mut l = $crate::hashset::HashSet::new(); + $( + l.insert($x); + )* + l + }}; +} + +/// An unordered set. +/// +/// An immutable hash set using [hash array mapped tries] [1]. +/// +/// Most operations on this set are O(logx n) for a +/// suitably high *x* that it should be nearly O(1) for most sets. +/// Because of this, it's a great choice for a generic set as long as +/// you don't mind that values will need to implement +/// [`Hash`][std::hash::Hash] and [`Eq`][std::cmp::Eq]. +/// +/// Values will have a predictable order based on the hasher +/// being used. Unless otherwise specified, this will be the standard +/// [`RandomState`][std::collections::hash_map::RandomState] hasher. +/// +/// [1]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie +/// [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [std::collections::hash_map::RandomState]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.h +pub struct HashSet { + hasher: Ref, + root: Ref>>, + size: usize, +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct Value(A); + +impl Deref for Value { + type Target = A; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// FIXME lacking specialisation, we can't simply implement `HashValue` +// for `A`, we have to use the `Value` indirection. +impl HashValue for Value +where + A: Hash + Eq, +{ + type Key = A; + + fn extract_key(&self) -> &Self::Key { + &self.0 + } + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } +} + +impl HashSet { + /// Construct an empty set. + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +impl HashSet +where + A: Hash + Eq + Clone, +{ + /// Construct a set with a single value. + /// + /// This method has been deprecated; use [`unit`][unit] instead. + /// + /// [unit]: #method.unit + #[inline] + #[must_use] + #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")] + pub fn singleton(a: A) -> Self { + Self::unit(a) + } + + /// Construct a set with a single value. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # use std::sync::Arc; + /// # fn main() { + /// let set = HashSet::unit(123); + /// assert!(set.contains(&123)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn unit(a: A) -> Self { + HashSet::new().update(a) + } +} + +impl HashSet { + /// Test whether a set is empty. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # fn main() { + /// assert!( + /// !hashset![1, 2, 3].is_empty() + /// ); + /// assert!( + /// HashSet::::new().is_empty() + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the size of a set. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # fn main() { + /// assert_eq!(3, hashset![1, 2, 3].len()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.size + } + + /// Construct an empty hash set using the provided hasher. + #[inline] + #[must_use] + pub fn with_hasher(hasher: RS) -> Self + where + Ref: From, + { + HashSet { + size: 0, + root: Ref::new(Node::new()), + hasher: From::from(hasher), + } + } + + /// Get a reference to the set's [`BuildHasher`][BuildHasher]. + /// + /// [BuildHasher]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + #[must_use] + pub fn hasher(&self) -> &Ref { + &self.hasher + } + + /// Construct an empty hash set using the same hasher as the current hash set. + #[inline] + #[must_use] + pub fn new_from(&self) -> HashSet + where + A1: Hash + Eq + Clone, + { + HashSet { + size: 0, + root: Ref::new(Node::new()), + hasher: self.hasher.clone(), + } + } + + /// Discard all elements from the set. + /// + /// This leaves you with an empty set, and all elements that + /// were previously inside it are dropped. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::HashSet; + /// # fn main() { + /// let mut set = hashset![1, 2, 3]; + /// set.clear(); + /// assert!(set.is_empty()); + /// # } + /// ``` + pub fn clear(&mut self) { + if !self.is_empty() { + self.root = Default::default(); + self.size = 0; + } + } + + /// Get an iterator over the values in a hash set. + /// + /// Please note that the order is consistent between sets using + /// the same hasher, but no other ordering guarantee is offered. + /// Items will not come out in insertion order or sort order. + /// They will, however, come out in the same order every time for + /// the same set. + #[must_use] + pub fn iter(&self) -> Iter<'_, A> { + Iter { + it: NodeIter::new(&self.root, self.size), + } + } +} + +impl HashSet +where + A: Hash + Eq, + S: BuildHasher, +{ + fn test_eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + let mut seen = collections::HashSet::new(); + for value in self.iter() { + if !other.contains(&value) { + return false; + } + seen.insert(value); + } + for value in other.iter() { + if !seen.contains(&value) { + return false; + } + } + true + } + + /// Test if a value is part of a set. + /// + /// Time: O(log n) + #[must_use] + pub fn contains(&self, a: &BA) -> bool + where + BA: Hash + Eq + ?Sized, + A: Borrow, + { + self.root.get(hash_key(&*self.hasher, a), 0, a).is_some() + } + + /// Test whether a set is a subset of another set, meaning that + /// all values in our set must also be in the other set. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_subset(&self, other: RS) -> bool + where + RS: Borrow, + { + let o = other.borrow(); + self.iter().all(|a| o.contains(&a)) + } + + /// Test whether a set is a proper subset of another set, meaning + /// that all values in our set must also be in the other set. A + /// proper subset must also be smaller than the other set. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_proper_subset(&self, other: RS) -> bool + where + RS: Borrow, + { + self.len() != other.borrow().len() && self.is_subset(other) + } +} + +impl HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + /// Get a mutable iterator over the values in a hash set. + /// + /// Please note that the order is consistent between sets using the same + /// hasher, but no other ordering guarantee is offered. Items will not come + /// out in insertion order or sort order. They will, however, come out in + /// the same order every time for the same set. + #[must_use] + pub fn iter_mut(&mut self) -> IterMut<'_, A> { + let root = Ref::make_mut(&mut self.root); + IterMut { + it: NodeIterMut::new(root, self.size), + } + } + + /// Insert a value into a set. + /// + /// Time: O(log n) + #[inline] + pub fn insert(&mut self, a: A) -> Option { + let hash = hash_key(&*self.hasher, &a); + let root = Ref::make_mut(&mut self.root); + match root.insert(hash, 0, Value(a)) { + None => { + self.size += 1; + None + } + Some(Value(old_value)) => Some(old_value), + } + } + + /// Remove a value from a set if it exists. + /// + /// Time: O(log n) + pub fn remove(&mut self, a: &BA) -> Option + where + BA: Hash + Eq + ?Sized, + A: Borrow, + { + let root = Ref::make_mut(&mut self.root); + let result = root.remove(hash_key(&*self.hasher, a), 0, a); + if result.is_some() { + self.size -= 1; + } + result.map(|v| v.0) + } + + /// Construct a new set from the current set with the given value + /// added. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # use std::sync::Arc; + /// # fn main() { + /// let set = hashset![123]; + /// assert_eq!( + /// set.update(456), + /// hashset![123, 456] + /// ); + /// # } + /// ``` + #[must_use] + pub fn update(&self, a: A) -> Self { + let mut out = self.clone(); + out.insert(a); + out + } + + /// Construct a new set with the given value removed if it's in + /// the set. + /// + /// Time: O(log n) + #[must_use] + pub fn without(&self, a: &BA) -> Self + where + BA: Hash + Eq + ?Sized, + A: Borrow, + { + let mut out = self.clone(); + out.remove(a); + out + } + + /// Filter out values from a set which don't satisfy a predicate. + /// + /// This is slightly more efficient than filtering using an + /// iterator, in that it doesn't need to rehash the retained + /// values, but it still needs to reconstruct the entire tree + /// structure of the set. + /// + /// Time: O(n log n) + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&A) -> bool, + { + let old_root = self.root.clone(); + let root = Ref::make_mut(&mut self.root); + for (value, hash) in NodeIter::new(&old_root, self.size) { + if !f(value) && root.remove(hash, 0, value).is_some() { + self.size -= 1; + } + } + } + + /// Construct the union of two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # fn main() { + /// let set1 = hashset!{1, 2}; + /// let set2 = hashset!{2, 3}; + /// let expected = hashset!{1, 2, 3}; + /// assert_eq!(expected, set1.union(set2)); + /// # } + /// ``` + #[must_use] + pub fn union(mut self, other: Self) -> Self { + for value in other { + self.insert(value); + } + self + } + + /// Construct the union of multiple sets. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions(i: I) -> Self + where + I: IntoIterator, + S: Default, + { + i.into_iter().fold(Self::default(), Self::union) + } + + /// Construct the difference between two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # fn main() { + /// let set1 = hashset!{1, 2}; + /// let set2 = hashset!{2, 3}; + /// let expected = hashset!{1, 3}; + /// assert_eq!(expected, set1.difference(set2)); + /// # } + /// ``` + #[must_use] + pub fn difference(mut self, other: Self) -> Self { + for value in other { + if self.remove(&value).is_none() { + self.insert(value); + } + } + self + } + + /// Construct the intersection of two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::hashset::HashSet; + /// # fn main() { + /// let set1 = hashset!{1, 2}; + /// let set2 = hashset!{2, 3}; + /// let expected = hashset!{2}; + /// assert_eq!(expected, set1.intersection(set2)); + /// # } + /// ``` + #[must_use] + pub fn intersection(self, other: Self) -> Self { + let mut out = self.new_from(); + for value in other { + if self.contains(&value) { + out.insert(value); + } + } + out + } +} + +// Core traits + +impl Clone for HashSet +where + A: Clone, +{ + fn clone(&self) -> Self { + HashSet { + hasher: self.hasher.clone(), + root: self.root.clone(), + size: self.size, + } + } +} + +impl PartialEq for HashSet +where + A: Hash + Eq, + S: BuildHasher + Default, +{ + fn eq(&self, other: &Self) -> bool { + self.test_eq(other) + } +} + +impl Eq for HashSet +where + A: Hash + Eq, + S: BuildHasher + Default, +{ +} + +impl PartialOrd for HashSet +where + A: Hash + Eq + Clone + PartialOrd, + S: BuildHasher + Default, +{ + fn partial_cmp(&self, other: &Self) -> Option { + if Ref::ptr_eq(&self.hasher, &other.hasher) { + return self.iter().partial_cmp(other.iter()); + } + let m1: ::std::collections::HashSet = self.iter().cloned().collect(); + let m2: ::std::collections::HashSet = other.iter().cloned().collect(); + m1.iter().partial_cmp(m2.iter()) + } +} + +impl Ord for HashSet +where + A: Hash + Eq + Clone + Ord, + S: BuildHasher + Default, +{ + fn cmp(&self, other: &Self) -> Ordering { + if Ref::ptr_eq(&self.hasher, &other.hasher) { + return self.iter().cmp(other.iter()); + } + let m1: ::std::collections::HashSet = self.iter().cloned().collect(); + let m2: ::std::collections::HashSet = other.iter().cloned().collect(); + m1.iter().cmp(m2.iter()) + } +} + +impl Hash for HashSet +where + A: Hash + Eq, + S: BuildHasher + Default, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + for i in self.iter() { + i.hash(state); + } + } +} + +impl Default for HashSet +where + S: BuildHasher + Default, +{ + fn default() -> Self { + HashSet { + hasher: Ref::::default(), + root: Ref::new(Node::new()), + size: 0, + } + } +} + +impl Add for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + type Output = HashSet; + + fn add(self, other: Self) -> Self::Output { + self.union(other) + } +} + +impl Mul for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + type Output = HashSet; + + fn mul(self, other: Self) -> Self::Output { + self.intersection(other) + } +} + +impl<'a, A, S> Add for &'a HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + type Output = HashSet; + + fn add(self, other: Self) -> Self::Output { + self.clone().union(other.clone()) + } +} + +impl<'a, A, S> Mul for &'a HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + type Output = HashSet; + + fn mul(self, other: Self) -> Self::Output { + self.clone().intersection(other.clone()) + } +} + +impl Sum for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn sum(it: I) -> Self + where + I: Iterator, + { + it.fold(Self::default(), |a, b| a + b) + } +} + +impl Extend for HashSet +where + A: Hash + Eq + Clone + From, + S: BuildHasher, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for value in iter { + self.insert(From::from(value)); + } + } +} + +#[cfg(not(has_specialisation))] +impl Debug for HashSet +where + A: Hash + Eq + Debug, + S: BuildHasher, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_set().entries(self.iter()).finish() + } +} + +#[cfg(has_specialisation)] +impl Debug for HashSet +where + A: Hash + Eq + Debug, + S: BuildHasher, +{ + default fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_set().entries(self.iter()).finish() + } +} + +#[cfg(has_specialisation)] +impl Debug for HashSet +where + A: Hash + Eq + Debug + Ord, + S: BuildHasher, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_set().entries(self.iter()).finish() + } +} + +// Iterators + +// An iterator over the elements of a set. +pub struct Iter<'a, A> +where + A: 'a, +{ + it: NodeIter<'a, Value>, +} + +impl<'a, A> Iterator for Iter<'a, A> +where + A: 'a, +{ + type Item = &'a A; + + fn next(&mut self) -> Option { + self.it.next().map(|(v, _)| &v.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, A> ExactSizeIterator for Iter<'a, A> {} + +impl<'a, A> FusedIterator for Iter<'a, A> {} + +// A mutable iterator over the elements of a set. +pub struct IterMut<'a, A> +where + A: 'a, +{ + it: NodeIterMut<'a, Value>, +} + +impl<'a, A> Iterator for IterMut<'a, A> +where + A: 'a + Clone, +{ + type Item = &'a mut A; + + fn next(&mut self) -> Option { + self.it.next().map(|(v, _)| &mut v.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, A> ExactSizeIterator for IterMut<'a, A> where A: Clone {} + +impl<'a, A> FusedIterator for IterMut<'a, A> where A: Clone {} + +// A consuming iterator over the elements of a set. +pub struct ConsumingIter +where + A: Hash + Eq + Clone, +{ + it: NodeDrain>, +} + +impl Iterator for ConsumingIter +where + A: Hash + Eq + Clone, +{ + type Item = A; + + fn next(&mut self) -> Option { + self.it.next().map(|(v, _)| v.0) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl ExactSizeIterator for ConsumingIter where A: Hash + Eq + Clone {} + +impl FusedIterator for ConsumingIter where A: Hash + Eq + Clone {} + +// Iterator conversions + +impl FromIterator for HashSet +where + A: Hash + Eq + Clone + From, + S: BuildHasher + Default, +{ + fn from_iter(i: T) -> Self + where + T: IntoIterator, + { + let mut set = Self::default(); + for value in i { + set.insert(From::from(value)); + } + set + } +} + +impl<'a, A, S> IntoIterator for &'a HashSet +where + A: Hash + Eq, + S: BuildHasher, +{ + type Item = &'a A; + type IntoIter = Iter<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher, +{ + type Item = A; + type IntoIter = ConsumingIter; + + fn into_iter(self) -> Self::IntoIter { + ConsumingIter { + it: NodeDrain::new(self.root, self.size), + } + } +} + +// Conversions + +impl<'s, 'a, A, OA, SA, SB> From<&'s HashSet<&'a A, SA>> for HashSet +where + A: ToOwned + Hash + Eq + ?Sized, + OA: Borrow + Hash + Eq + Clone, + SA: BuildHasher, + SB: BuildHasher + Default, +{ + fn from(set: &HashSet<&A, SA>) -> Self { + set.iter().map(|a| (*a).to_owned()).collect() + } +} + +impl<'a, A, S> From<&'a [A]> for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(slice: &'a [A]) -> Self { + slice.iter().cloned().collect() + } +} + +impl From> for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(vec: Vec) -> Self { + vec.into_iter().collect() + } +} + +impl<'a, A, S> From<&'a Vec> for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(vec: &Vec) -> Self { + vec.iter().cloned().collect() + } +} + +impl From> for HashSet +where + A: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + fn from(hash_set: collections::HashSet) -> Self { + hash_set.into_iter().collect() + } +} + +impl<'a, A, S> From<&'a collections::HashSet> for HashSet +where + A: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + fn from(hash_set: &collections::HashSet) -> Self { + hash_set.iter().cloned().collect() + } +} + +impl<'a, A, S> From<&'a BTreeSet> for HashSet +where + A: Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(btree_set: &BTreeSet) -> Self { + btree_set.iter().cloned().collect() + } +} + +impl From> for HashSet +where + A: Ord + Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(ordset: OrdSet) -> Self { + ordset.into_iter().collect() + } +} + +impl<'a, A, S> From<&'a OrdSet> for HashSet +where + A: Ord + Hash + Eq + Clone, + S: BuildHasher + Default, +{ + fn from(ordset: &OrdSet) -> Self { + ordset.into_iter().cloned().collect() + } +} + +// QuickCheck + +#[cfg(all(threadsafe, feature = "quickcheck"))] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(all(threadsafe, feature = "quickcheck"))] +impl Arbitrary for HashSet +where + A: Hash + Eq + Arbitrary + Sync, + S: BuildHasher + Default + Send + Sync + 'static, +{ + fn arbitrary(g: &mut G) -> Self { + HashSet::from_iter(Vec::::arbitrary(g)) + } +} + +// Proptest + +#[cfg(any(test, feature = "proptest"))] +pub mod proptest { + use super::*; + use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; + use std::ops::Range; + + /// A strategy for a hash set of a given size. + /// + /// # Examples + /// + /// ```rust,ignore + /// proptest! { + /// #[test] + /// fn proptest_a_set(ref s in hashset(".*", 10..100)) { + /// assert!(s.len() < 100); + /// assert!(s.len() >= 10); + /// } + /// } + /// ``` + pub fn hash_set( + element: A, + size: Range, + ) -> BoxedStrategy::Value>> + where + ::Value: Hash + Eq + Clone, + { + ::proptest::collection::vec(element, size.clone()) + .prop_map(HashSet::from) + .prop_filter("HashSet minimum size".to_owned(), move |s| { + s.len() >= size.start + }) + .boxed() + } +} + +#[cfg(test)] +mod test { + use super::proptest::*; + use super::*; + use crate::test::LolHasher; + use ::proptest::num::i16; + use ::proptest::proptest; + use std::hash::BuildHasherDefault; + + #[test] + fn insert_failing() { + let mut set: HashSet> = Default::default(); + set.insert(14658); + assert_eq!(1, set.len()); + set.insert(-19198); + assert_eq!(2, set.len()); + } + + #[test] + fn match_strings_with_string_slices() { + let mut set: HashSet = From::from(&hashset!["foo", "bar"]); + set = set.without("bar"); + assert!(!set.contains("bar")); + set.remove("foo"); + assert!(!set.contains("foo")); + } + + #[test] + fn macro_allows_trailing_comma() { + let set1 = hashset! {"foo", "bar"}; + let set2 = hashset! { + "foo", + "bar", + }; + assert_eq!(set1, set2); + } + + #[test] + fn issue_60_drain_iterator_memory_corruption() { + use crate::test::MetroHashBuilder; + for i in 0..1000 { + let mut lhs = vec![0, 1, 2]; + lhs.sort(); + + let hasher = Ref::from(MetroHashBuilder::new(i)); + let mut iset: HashSet<_, MetroHashBuilder> = HashSet::with_hasher(hasher.clone()); + for &i in &lhs { + iset.insert(i); + } + + let mut rhs: Vec<_> = iset.clone().into_iter().collect(); + rhs.sort(); + + if lhs != rhs { + println!("iteration: {}", i); + println!("seed: {}", hasher.seed()); + println!("lhs: {}: {:?}", lhs.len(), &lhs); + println!("rhs: {}: {:?}", rhs.len(), &rhs); + panic!(); + } + } + } + + proptest! { + #[test] + fn proptest_a_set(ref s in hash_set(".*", 10..100)) { + assert!(s.len() < 100); + assert!(s.len() >= 10); + } + } +} diff --git a/im-rc/src/iter.rs b/im-rc/src/iter.rs new file mode 100644 index 000000000..e9cec06b2 --- /dev/null +++ b/im-rc/src/iter.rs @@ -0,0 +1,122 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! Iterators over immutable data. + +pub struct Unfold { + f: F, + value: S, +} + +impl Iterator for Unfold +where + F: Fn(&S) -> Option<(A, S)>, +{ + type Item = A; + + fn next(&mut self) -> Option { + match (self.f)(&self.value) { + None => None, + Some((next, value)) => { + self.value = value; + Some(next) + } + } + } +} + +pub struct UnfoldMut { + f: F, + value: S, +} + +impl Iterator for UnfoldMut +where + F: Fn(&mut S) -> Option, +{ + type Item = A; + + fn next(&mut self) -> Option { + (self.f)(&mut self.value) + } +} + +/// Create an iterator of values using a function to update a state +/// value. +/// +/// The function is called with the current state as its argument, and +/// should return an [`Option`][std::option::Option] of a tuple of the +/// next value to yield from the iterator and the updated state. If +/// the function returns [`None`][std::option::Option::None], the +/// iterator ends. +/// +/// # Examples +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::iter::unfold; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// // Create an infinite stream of numbers, starting at 0. +/// let mut it = unfold(0, |i| Some((*i, *i + 1))); +/// +/// // Make a list out of its first five elements. +/// let numbers = Vector::from_iter(it.take(5)); +/// assert_eq!(numbers, vector![0, 1, 2, 3, 4]); +/// # } +/// ``` +/// +/// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html +/// [std::option::Option::None]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +#[must_use] +pub fn unfold(value: S, f: F) -> Unfold +where + F: Fn(&S) -> Option<(A, S)>, +{ + Unfold { f, value } +} + +/// Create an iterator of values using a function to mutate a state +/// value. +/// +/// The function is called with a mutable reference to the current +/// state as its argument, and should return an +/// [`Option`][std::option::Option] of the next value to yield from +/// the iterator, updating the state as necessary. If the function +/// returns [`None`][std::option::Option::None], the iterator ends. +/// +/// This differs from [`unfold`][unfold] in that your update functions +/// will probably be less elegant, but it's easier to deal with state +/// that isn't efficiently cloneable. +/// +/// # Examples +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::iter::unfold_mut; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// // Create an infinite stream of numbers, starting at 0. +/// let mut it = unfold_mut(0, |i| { +/// let next = *i; +/// *i += 1; +/// Some(next) +/// }); +/// +/// // Make a list out of its first five elements. +/// let numbers = Vector::from_iter(it.take(5)); +/// assert_eq!(numbers, vector![0, 1, 2, 3, 4]); +/// # } +/// ``` +/// +/// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html +/// [std::option::Option::None]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// [unfold]: ./fn.unfold.html +#[must_use] +pub fn unfold_mut(value: S, f: F) -> UnfoldMut +where + F: Fn(&mut S) -> Option, +{ + UnfoldMut { f, value } +} diff --git a/im-rc/src/lib.rs b/im-rc/src/lib.rs new file mode 100644 index 000000000..9e866787f --- /dev/null +++ b/im-rc/src/lib.rs @@ -0,0 +1,484 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! # Immutable Data Structures for Rust +//! +//! This library implements several of the more commonly useful immutable data +//! structures for Rust. +//! +//! ## What are immutable data structures? +//! +//! Immutable data structures are data structures which can be copied and +//! modified efficiently without altering the original. The most uncomplicated +//! example of this is the venerable [cons list][cons-list]. This crate offers a +//! selection of more modern and flexible data structures with similar +//! properties, tuned for the needs of Rust developers. +//! +//! Briefly, the following data structures are provided: +//! +//! * [Vectors][vector::Vector] based on [RRB trees][rrb-tree] +//! * [Hash maps][hashmap::HashMap]/[sets][hashset::HashSet] based on [hash +//! array mapped tries][hamt] +//! * [Ordered maps][ordmap::OrdMap]/[sets][ordset::OrdSet] based on +//! [B-trees][b-tree] +//! +//! ## Why Would I Want This? +//! +//! While immutable data structures can be a game changer for other +//! programming languages, the most obvious benefit - avoiding the +//! accidental mutation of data - is already handled so well by Rust's +//! type system that it's just not something a Rust programmer needs +//! to worry about even when using data structures that would send a +//! conscientious Clojure programmer into a panic. +//! +//! Immutable data structures offer other benefits, though, some of +//! which are useful even in a language like Rust. The most prominent +//! is *structural sharing*, which means that if two data structures +//! are mostly copies of each other, most of the memory they take up +//! will be shared between them. This implies that making copies of an +//! immutable data structure is cheap: it's really only a matter of +//! copying a pointer and increasing a reference counter, where in the +//! case of [`Vec`][std::vec::Vec] you have to allocate the same +//! amount of memory all over again and make a copy of every element +//! it contains. For immutable data structures, extra memory isn't +//! allocated until you modify either the copy or the original, and +//! then only the memory needed to record the difference. +//! +//! Another goal of this library has been the idea that you shouldn't +//! even have to think about what data structure to use in any given +//! situation, until the point where you need to start worring about +//! optimisation - which, in practice, often never comes. Beyond the +//! shape of your data (ie. whether to use a list or a map), it should +//! be fine not to think too carefully about data structures - you can +//! just pick the one that has the right shape and it should have +//! acceptable performance characteristics for every operation you +//! might need. Specialised data structures will always be faster at +//! what they've been specialised for, but `im` aims to provide the +//! data structures which deliver the least chance of accidentally +//! using them for the wrong thing. +//! +//! For instance, [`Vec`][std::vec::Vec] beats everything at memory +//! usage, indexing and operations that happen at the back of the +//! list, but is terrible at insertion and removal, and gets worse the +//! closer to the front of the list you get. +//! [`VecDeque`][std::collections::VecDeque] adds a little bit of +//! complexity in order to make operations at the front as efficient +//! as operations at the back, but is still bad at insertion and +//! especially concatenation. [`Vector`][vector::Vector] adds another +//! bit of complexity, and could never match [`Vec`][std::vec::Vec] at +//! what it's best at, but in return every operation you can throw at +//! it can be completed in a reasonable amount of time - even normally +//! expensive operations like copying and especially concatenation are +//! reasonably cheap when using a [`Vector`][vector::Vector]. +//! +//! It should be noted, however, that because of its simplicity, +//! [`Vec`][std::vec::Vec] actually beats [`Vector`][vector::Vector] even at its +//! strongest operations at small sizes, just because modern CPUs are +//! hyperoptimised for things like copying small chunks of contiguous memory - +//! you actually need to go past a certain size (usually in the vicinity of +//! several hundred elements) before you get to the point where +//! [`Vec`][std::vec::Vec] isn't always going to be the fastest choice. +//! [`Vector`][vector::Vector] attempts to overcome this by actually just being +//! an array at very small sizes, and being able to switch efficiently to the +//! full data structure when it grows large enough. Thus, +//! [`Vector`][vector::Vector] will actually be equivalent to +//! [Vec][std::vec::Vec] until it grows past the size of a single chunk. +//! +//! The maps - [`HashMap`][hashmap::HashMap] and +//! [`OrdMap`][ordmap::OrdMap] - generally perform similarly to their +//! equivalents in the standard library, but tend to run a bit slower +//! on the basic operations ([`HashMap`][hashmap::HashMap] is almost +//! neck and neck with its counterpart, while +//! [`OrdMap`][ordmap::OrdMap] currently tends to run 2-3x slower). On +//! the other hand, they offer the cheap copy and structural sharing +//! between copies that you'd expect from immutable data structures. +//! +//! In conclusion, the aim of this library is to provide a safe +//! default choice for the most common kinds of data structures, +//! allowing you to defer careful thinking about the right data +//! structure for the job until you need to start looking for +//! optimisations - and you may find, especially for larger data sets, +//! that immutable data structures are still the right choice. +//! +//! ## Values +//! +//! Because we need to make copies of shared nodes in these data structures +//! before updating them, the values you store in them must implement +//! [`Clone`][std::clone::Clone]. For primitive values that implement +//! [`Copy`][std::marker::Copy], such as numbers, everything is fine: this is +//! the case for which the data structures are optimised, and performance is +//! going to be great. +//! +//! On the other hand, if you want to store values for which cloning is +//! expensive, or values that don't implement [`Clone`][std::clone::Clone], you +//! need to wrap them in [`Rc`][std::rc::Rc] or [`Arc`][std::sync::Arc]. Thus, +//! if you have a complex structure `BigBlobOfData` and you want to store a list +//! of them as a `Vector`, you should instead use a +//! `Vector>`, which is going to save you not only the time +//! spent cloning the big blobs of data, but also the memory spent keeping +//! multiple copies of it around, as [`Rc`][std::rc::Rc] keeps a single +//! reference counted copy around instead. +//! +//! If you're storing smaller values that aren't +//! [`Copy`][std::marker::Copy]able, you'll need to exercise judgement: if your +//! values are going to be very cheap to clone, as would be the case for short +//! [`String`][std::string::String]s or small [`Vec`][std::vec::Vec]s, you're +//! probably better off storing them directly without wrapping them in an +//! [`Rc`][std::rc::Rc], because, like the [`Rc`][std::rc::Rc], they're just +//! pointers to some data on the heap, and that data isn't expensive to clone - +//! you might actually lose more performance from the extra redirection of +//! wrapping them in an [`Rc`][std::rc::Rc] than you would from occasionally +//! cloning them. +//! +//! ### When does cloning happen? +//! +//! So when will your values actually be cloned? The easy answer is only if you +//! [`clone`][std::clone::Clone::clone] the data structure itself, and then only +//! lazily as you change it. Values are stored in tree nodes inside the data +//! structure, each node of which contains up to 64 values. When you +//! [`clone`][std::clone::Clone::clone] a data structure, nothing is actually +//! copied - it's just the reference count on the root node that's incremented, +//! to indicate that it's shared between two data structures. It's only when you +//! actually modify one of the shared data structures that nodes are cloned: +//! when you make a change somewhere in the tree, the node containing the change +//! needs to be cloned, and then its parent nodes need to be updated to contain +//! the new child node instead of the old version, and so they're cloned as +//! well. +//! +//! We can call this "lazy" cloning - if you make two copies of a data structure +//! and you never change either of them, there's never any need to clone the +//! data they contain. It's only when you start making changes that cloning +//! starts to happen, and then only on the specific tree nodes that are part of +//! the change. Note that the implications of lazily cloning the data structure +//! extend to memory usage as well as the CPU workload of copying the data +//! around - cloning an immutable data structure means both copies share the +//! same allocated memory, until you start making changes. +//! +//! Most crucially, if you never clone the data structure, the data inside it is +//! also never cloned, and in this case it acts just like a mutable data +//! structure, with minimal performance differences (but still non-zero, as we +//! still have to check for shared nodes). +//! +//! ## Data Structures +//! +//! We'll attempt to provide a comprehensive guide to the available +//! data structures below. +//! +//! ### Performance Notes +//! +//! "Big O notation" is the standard way of talking about the time +//! complexity of data structure operations. If you're not familiar +//! with big O notation, here's a quick cheat sheet: +//! +//! *O(1)* means an operation runs in constant time: it will take the +//! same time to complete regardless of the size of the data +//! structure. +//! +//! *O(n)* means an operation runs in linear time: if you double the +//! size of your data structure, the operation will take twice as long +//! to complete; if you quadruple the size, it will take four times as +//! long, etc. +//! +//! *O(log n)* means an operation runs in logarithmic time: for +//! *log2*, if you double the size of your data structure, +//! the operation will take one step longer to complete; if you +//! quadruple the size, it will need two steps more; and so on. +//! However, the data structures in this library generally run in +//! *log64* time, meaning you have to make your data +//! structure 64 times bigger to need one extra step, and 4096 times +//! bigger to need two steps. This means that, while they still count +//! as O(log n), operations on all but really large data sets will run +//! at near enough to O(1) that you won't usually notice. +//! +//! *O(n log n)* is the most expensive operation you'll see in this +//! library: it means that for every one of the *n* elements in your +//! data structure, you have to perform *log n* operations. In our +//! case, as noted above, this is often close enough to O(n) that it's +//! not usually as bad as it sounds, but even O(n) isn't cheap and the +//! cost still increases logarithmically, if slowly, as the size of +//! your data increases. O(n log n) basically means "are you sure you +//! need to do this?" +//! +//! *O(1)** means 'amortised O(1),' which means that an operation +//! usually runs in constant time but will occasionally be more +//! expensive: for instance, +//! [`Vector::push_back`][vector::Vector::push_back], if called in +//! sequence, will be O(1) most of the time but every 64th time it +//! will be O(log n), as it fills up its tail chunk and needs to +//! insert it into the tree. Please note that the O(1) with the +//! asterisk attached is not a common notation; it's just a convention +//! I've used in these docs to save myself from having to type +//! 'amortised' everywhere. +//! +//! ### Lists +//! +//! Lists are sequences of single elements which maintain the order in +//! which you inserted them. The only list in this library is +//! [`Vector`][vector::Vector], which offers the best all round +//! performance characteristics: it's pretty good at everything, even +//! if there's always another kind of list that's better at something. +//! +//! | Type | Algorithm | Constraints | Order | Push | Pop | Split | Append | Lookup | +//! | --- | --- | --- | --- | --- | --- | --- | +//! | [`Vector`][vector::Vector] | [RRB tree][rrb-tree] | [`Clone`][std::clone::Clone] | insertion | O(1)* | O(1)* | O(log n) | O(log n) | O(log n) | +//! +//! ### Maps +//! +//! Maps are mappings of keys to values, where the most common read +//! operation is to find the value associated with a given key. Maps +//! may or may not have a defined order. Any given key can only occur +//! once inside a map, and setting a key to a different value will +//! overwrite the previous value. +//! +//! | Type | Algorithm | Key Constraints | Order | Insert | Remove | Lookup | +//! | --- | --- | --- | --- | --- | --- | +//! | [`HashMap`][hashmap::HashMap] | [HAMT][hamt] | [`Clone`][std::clone::Clone] + [`Hash`][std::hash::Hash] + [`Eq`][std::cmp::Eq] | undefined | O(log n) | O(log n) | O(log n) | +//! | [`OrdMap`][ordmap::OrdMap] | [B-tree][b-tree] | [`Clone`][std::clone::Clone] + [`Ord`][std::cmp::Ord] | sorted | O(log n) | O(log n) | O(log n) | +//! +//! ### Sets +//! +//! Sets are collections of unique values, and may or may not have a +//! defined order. Their crucial property is that any given value can +//! only exist once in a given set. +//! +//! | Type | Algorithm | Constraints | Order | Insert | Remove | Lookup | +//! | --- | --- | --- | --- | --- | --- | +//! | [`HashSet`][hashset::HashSet] | [HAMT][hamt] | [`Clone`][std::clone::Clone] + [`Hash`][std::hash::Hash] + [`Eq`][std::cmp::Eq] | undefined | O(log n) | O(log n) | O(log n) | +//! | [`OrdSet`][ordset::OrdSet] | [B-tree][b-tree] | [`Clone`][std::clone::Clone] + [`Ord`][std::cmp::Ord] | sorted | O(log n) | O(log n) | O(log n) | +//! +//! ## In-place Mutation +//! +//! All of these data structures support in-place copy-on-write +//! mutation, which means that if you're the sole user of a data +//! structure, you can update it in place without taking the +//! performance hit of making a copy of the data structure before +//! modifying it (this is about an order of magnitude faster than +//! immutable operations, almost as fast as +//! [`std::collections`][std::collections]'s mutable data structures). +//! +//! Thanks to [`Rc`][std::rc::Rc]'s reference counting, we are able to +//! determine whether a node in a data structure is being shared with +//! other data structures, or whether it's safe to mutate it in place. +//! When it's shared, we'll automatically make a copy of the node +//! before modifying it. The consequence of this is that cloning a +//! data structure becomes a lazy operation: the initial clone is +//! instant, and as you modify the cloned data structure it will clone +//! chunks only where you change them, so that if you change the +//! entire thing you will eventually have performed a full clone. +//! +//! This also gives us a couple of other optimisations for free: +//! implementations of immutable data structures in other languages +//! often have the idea of local mutation, like Clojure's transients +//! or Haskell's `ST` monad - a managed scope where you can treat an +//! immutable data structure like a mutable one, gaining a +//! considerable amount of performance because you no longer need to +//! copy your changed nodes for every operation, just the first time +//! you hit a node that's sharing structure. In Rust, we don't need to +//! think about this kind of managed scope, it's all taken care of +//! behind the scenes because of our low level access to the garbage +//! collector (which, in our case, is just a simple +//! [`Rc`][std::rc::Rc]). +//! +//! ## Thread Safety +//! +//! The data structures in the `im` crate are thread safe, through +//! [`Arc`][std::sync::Arc]. This comes with a slight performance impact, so +//! that if you prioritise speed over thread safety, you may want to use the +//! `im-rc` crate instead, which is identical to `im` except that it uses +//! [`Rc`][std::rc::Rc] instead of [`Arc`][std::sync::Arc], implying that the +//! data structures in `im-rc` do not implement [`Send`][std::marker::Send] and +//! [`Sync`][std::marker::Sync]. This yields approximately a 20-25% increase in +//! general performance. +//! +//! ## Feature Flags +//! +//! `im` comes with optional support for the following crates through Cargo +//! feature flags. You can enable them in your `Cargo.toml` file like this: +//! +//! ```no_compile +//! [dependencies] +//! im = { version = "*", features = ["proptest", "serde"] } +//! ``` +//! +//! | Feature | Description | +//! | ------- | ----------- | +//! | [`proptest`](https://crates.io/crates/proptest) | Strategies for all `im` datatypes under a `proptest` namespace, eg. `im::vector::proptest::vector()` | +//! | [`quickcheck`](https://crates.io/crates/quickcheck) | `Arbitrary` implementations for all `im` datatypes (not available in `im-rc`) | +//! | [`rayon`](https://crates.io/crates/rayon) | parallel iterator implementations for `Vector` (not available in `im-rc`) | +//! | [`serde`](https://crates.io/crates/serde) | `Serialize` and `Deserialize` implementations for all `im` datatypes | +//! +//! [std::collections]: https://doc.rust-lang.org/std/collections/index.html +//! [std::collections::VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html +//! [std::vec::Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html +//! [std::string::String]: https://doc.rust-lang.org/std/string/struct.String.html +//! [std::rc::Rc]: https://doc.rust-lang.org/std/rc/struct.Rc.html +//! [std::sync::Arc]: https://doc.rust-lang.org/std/sync/struct.Arc.html +//! [std::cmp::Eq]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +//! [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html +//! [std::clone::Clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html +//! [std::clone::Clone::clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html#tymethod.clone +//! [std::marker::Copy]: https://doc.rust-lang.org/std/marker/trait.Copy.html +//! [std::hash::Hash]: https://doc.rust-lang.org/std/hash/trait.Hash.html +//! [std::marker::Send]: https://doc.rust-lang.org/std/marker/trait.Send.html +//! [std::marker::Sync]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! [hashmap::HashMap]: ./hashmap/struct.HashMap.html +//! [hashset::HashSet]: ./hashset/struct.HashSet.html +//! [ordmap::OrdMap]: ./ordmap/struct.OrdMap.html +//! [ordset::OrdSet]: ./ordset/struct.OrdSet.html +//! [vector::Vector]: ./vector/enum.Vector.html +//! [vector::Vector::push_back]: ./vector/enum.Vector.html#method.push_back +//! [rrb-tree]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf +//! [hamt]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie +//! [b-tree]: https://en.wikipedia.org/wiki/B-tree +//! [cons-list]: https://en.wikipedia.org/wiki/Cons#Lists + +#![deny(unsafe_code)] +#![cfg_attr(has_specialisation, feature(specialization))] + +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; + +mod config; +mod nodes; +mod sort; +mod sync; +mod util; + +#[macro_use] +mod ord; +pub use crate::ord::map as ordmap; +pub use crate::ord::set as ordset; + +#[macro_use] +mod hash; +pub use crate::hash::map as hashmap; +pub use crate::hash::set as hashset; + +#[macro_use] +pub mod vector; + +pub mod iter; + +#[cfg(any(test, feature = "serde"))] +pub mod ser; + +#[deprecated(since = "12.3.1", note = "please use the `sized_chunks` crate instead")] +pub use sized_chunks::sized_chunk as chunk; + +pub use crate::hashmap::HashMap; +pub use crate::hashset::HashSet; +pub use crate::ordmap::OrdMap; +pub use crate::ordset::OrdSet; +#[doc(inline)] +pub use crate::vector::Vector; + +#[cfg(test)] +mod test; + +#[cfg(test)] +mod tests; + +/// Update a value inside multiple levels of data structures. +/// +/// This macro takes a [`Vector`][Vector], [`OrdMap`][OrdMap] or [`HashMap`][HashMap], +/// a key or a series of keys, and a value, and returns the data structure with the +/// new value at the location described by the keys. +/// +/// If one of the keys in the path doesn't exist, the macro will panic. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use std::sync::Arc; +/// # fn main() { +/// let vec_inside_vec = vector![vector![1, 2, 3], vector![4, 5, 6]]; +/// +/// let expected = vector![vector![1, 2, 3], vector![4, 5, 1337]]; +/// +/// assert_eq!(expected, update_in![vec_inside_vec, 1 => 2, 1337]); +/// # } +/// ``` +/// +/// [Vector]: ../vector/enum.Vector.html +/// [HashMap]: ../hashmap/struct.HashMap.html +/// [OrdMap]: ../ordmap/struct.OrdMap.html +#[macro_export] +macro_rules! update_in { + ($target:expr, $path:expr => $($tail:tt) => *, $value:expr ) => {{ + let inner = $target.get($path).expect("update_in! macro: key not found in target"); + $target.update($path, update_in!(inner, $($tail) => *, $value)) + }}; + + ($target:expr, $path:expr, $value:expr) => { + $target.update($path, $value) + }; +} + +/// Get a value inside multiple levels of data structures. +/// +/// This macro takes a [`Vector`][Vector], [`OrdMap`][OrdMap] or [`HashMap`][HashMap], +/// along with a key or a series of keys, and returns the value at the location inside +/// the data structure described by the key sequence, or `None` if any of the keys didn't +/// exist. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use std::sync::Arc; +/// # fn main() { +/// let vec_inside_vec = vector![vector![1, 2, 3], vector![4, 5, 6]]; +/// +/// assert_eq!(Some(&6), get_in![vec_inside_vec, 1 => 2]); +/// # } +/// ``` +/// +/// [Vector]: ../vector/enum.Vector.html +/// [HashMap]: ../hashmap/struct.HashMap.html +/// [OrdMap]: ../ordmap/struct.OrdMap.html +#[macro_export] +macro_rules! get_in { + ($target:expr, $path:expr => $($tail:tt) => * ) => {{ + $target.get($path).and_then(|v| get_in!(v, $($tail) => *)) + }}; + + ($target:expr, $path:expr) => { + $target.get($path) + }; +} + +#[cfg(test)] +mod lib_test { + #[test] + fn update_in() { + let vector = vector![1, 2, 3, 4, 5]; + assert_eq!(vector![1, 2, 23, 4, 5], update_in!(vector, 2, 23)); + let hashmap = hashmap![1 => 1, 2 => 2, 3 => 3]; + assert_eq!( + hashmap![1 => 1, 2 => 23, 3 => 3], + update_in!(hashmap, 2, 23) + ); + let ordmap = ordmap![1 => 1, 2 => 2, 3 => 3]; + assert_eq!(ordmap![1 => 1, 2 => 23, 3 => 3], update_in!(ordmap, 2, 23)); + + let vecs = vector![vector![1, 2, 3], vector![4, 5, 6], vector![7, 8, 9]]; + let vecs_target = vector![vector![1, 2, 3], vector![4, 5, 23], vector![7, 8, 9]]; + assert_eq!(vecs_target, update_in!(vecs, 1 => 2, 23)); + } + + #[test] + fn get_in() { + let vector = vector![1, 2, 3, 4, 5]; + assert_eq!(Some(&3), get_in!(vector, 2)); + let hashmap = hashmap![1 => 1, 2 => 2, 3 => 3]; + assert_eq!(Some(&2), get_in!(hashmap, &2)); + let ordmap = ordmap![1 => 1, 2 => 2, 3 => 3]; + assert_eq!(Some(&2), get_in!(ordmap, &2)); + + let vecs = vector![vector![1, 2, 3], vector![4, 5, 6], vector![7, 8, 9]]; + assert_eq!(Some(&6), get_in!(vecs, 1 => 2)); + } +} diff --git a/im-rc/src/nodes/btree.rs b/im-rc/src/nodes/btree.rs new file mode 100644 index 000000000..c3850b0d6 --- /dev/null +++ b/im-rc/src/nodes/btree.rs @@ -0,0 +1,1189 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::mem; +use std::ops::{Bound, RangeBounds}; + +use typenum::{Add1, Unsigned}; + +use crate::config::OrdChunkSize as NodeSize; +use crate::nodes::sized_chunk::Chunk; +use crate::util::{clone_ref, Ref}; + +use self::Insert::*; +use self::InsertAction::*; + +const NODE_SIZE: usize = NodeSize::USIZE; +const MEDIAN: usize = (NODE_SIZE + 1) >> 1; + +pub trait BTreeValue { + type Key; + fn ptr_eq(&self, other: &Self) -> bool; + fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self: Sized, + Self::Key: Borrow; + fn search_value(slice: &[Self], value: &Self) -> Result + where + Self: Sized; + fn cmp_keys(&self, other: &BK) -> Ordering + where + BK: Ord + ?Sized, + Self::Key: Borrow; + fn cmp_values(&self, other: &Self) -> Ordering; +} + +pub struct Node { + keys: Chunk, + children: Chunk>>, Add1>, +} + +pub enum Insert { + Added, + Replaced(A), + Update(Node), + Split(Node, A, Node), +} + +enum InsertAction { + AddedAction, + ReplacedAction(A), + InsertAt, + InsertSplit(Node, A, Node), +} + +pub enum Remove { + NoChange, + Removed(A), + Update(A, Node), +} + +enum RemoveAction { + DeleteAt(usize), + PullUp(usize, usize, usize), + Merge(usize), + StealFromLeft(usize), + StealFromRight(usize), + MergeFirst(usize), + ContinueDown(usize), +} + +impl Clone for Node +where + A: Clone, +{ + fn clone(&self) -> Self { + Node { + keys: self.keys.clone(), + children: self.children.clone(), + } + } +} + +impl Default for Node { + fn default() -> Self { + Node { + keys: Chunk::new(), + children: Chunk::unit(None), + } + } +} + +impl Node { + #[inline] + fn has_room(&self) -> bool { + self.keys.len() < NODE_SIZE + } + + #[inline] + fn too_small(&self) -> bool { + self.keys.len() < MEDIAN + } + + #[inline] + fn is_leaf(&self) -> bool { + self.children[0].is_none() + } + + #[inline] + pub fn new() -> Self { + Self::default() + } + + #[inline] + pub fn unit(value: A) -> Self { + Node { + keys: Chunk::unit(value), + children: Chunk::pair(None, None), + } + } + + #[inline] + pub fn from_split(left: Node, median: A, right: Node) -> Self { + Node { + keys: Chunk::unit(median), + children: Chunk::pair(Some(Ref::from(left)), Some(Ref::from(right))), + } + } + + pub fn min(&self) -> Option<&A> { + match self.children.first().unwrap() { + None => self.keys.first(), + Some(ref child) => child.min(), + } + } + + pub fn max(&self) -> Option<&A> { + match self.children.last().unwrap() { + None => self.keys.last(), + Some(ref child) => child.max(), + } + } +} + +impl Node { + fn child_contains(&self, index: usize, key: &BK) -> bool + where + BK: Ord + ?Sized, + A::Key: Borrow, + { + if let Some(Some(ref child)) = self.children.get(index) { + child.lookup(key).is_some() + } else { + false + } + } + + pub fn lookup(&self, key: &BK) -> Option<&A> + where + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return None; + } + // Perform a binary search, resulting in either a match or + // the index of the first higher key, meaning we search the + // child to the left of it. + match A::search_key(&self.keys, key) { + Ok(index) => Some(&self.keys[index]), + Err(index) => match self.children[index] { + None => None, + Some(ref node) => node.lookup(key), + }, + } + } + + pub fn lookup_mut(&mut self, key: &BK) -> Option<&mut A> + where + A: Clone, + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return None; + } + // Perform a binary search, resulting in either a match or + // the index of the first higher key, meaning we search the + // child to the left of it. + match A::search_key(&self.keys, key) { + Ok(index) => Some(&mut self.keys[index]), + Err(index) => match self.children[index] { + None => None, + Some(ref mut child_ref) => { + let child = Ref::make_mut(child_ref); + child.lookup_mut(key) + } + }, + } + } + + pub fn path_first<'a, BK>( + &'a self, + mut path: Vec<(&'a Node, usize)>, + ) -> Vec<(&'a Node, usize)> + where + A: 'a, + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return Vec::new(); + } + match self.children[0] { + None => { + path.push((self, 0)); + path + } + Some(ref node) => { + path.push((self, 0)); + node.path_first(path) + } + } + } + + pub fn path_last<'a, BK>( + &'a self, + mut path: Vec<(&'a Node, usize)>, + ) -> Vec<(&'a Node, usize)> + where + A: 'a, + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return Vec::new(); + } + let end = self.children.len() - 1; + match self.children[end] { + None => { + path.push((self, end - 1)); + path + } + Some(ref node) => { + path.push((self, end)); + node.path_last(path) + } + } + } + + pub fn path_next<'a, BK>( + &'a self, + key: &BK, + mut path: Vec<(&'a Node, usize)>, + ) -> Vec<(&'a Node, usize)> + where + A: 'a, + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return Vec::new(); + } + match A::search_key(&self.keys, key) { + Ok(index) => { + path.push((self, index)); + path + } + Err(index) => match self.children[index] { + None => match self.keys.get(index) { + Some(_) => { + path.push((self, index)); + path + } + None => Vec::new(), + }, + Some(ref node) => { + path.push((self, index)); + node.path_next(key, path) + } + }, + } + } + + pub fn path_prev<'a, BK>( + &'a self, + key: &BK, + mut path: Vec<(&'a Node, usize)>, + ) -> Vec<(&'a Node, usize)> + where + A: 'a, + BK: Ord + ?Sized, + A::Key: Borrow, + { + if self.keys.is_empty() { + return Vec::new(); + } + match A::search_key(&self.keys, key) { + Ok(index) => { + path.push((self, index)); + path + } + Err(index) => match self.children[index] { + None if index == 0 => Vec::new(), + None => match self.keys.get(index - 1) { + Some(_) => { + path.push((self, index)); + path + } + None => Vec::new(), + }, + Some(ref node) => { + path.push((self, index)); + node.path_prev(key, path) + } + }, + } + } + + fn split( + &mut self, + value: A, + ins_left: Option>, + ins_right: Option>, + ) -> Insert { + let left_child = ins_left.map(Ref::from); + let right_child = ins_right.map(Ref::from); + let index = A::search_value(&self.keys, &value).unwrap_err(); + let mut left_keys; + let mut left_children; + let mut right_keys; + let mut right_children; + let median; + if index < MEDIAN { + self.children[index] = left_child; + + left_keys = Chunk::from_front(&mut self.keys, index); + left_keys.push_back(value); + left_keys.drain_from_front(&mut self.keys, MEDIAN - index - 1); + + left_children = Chunk::from_front(&mut self.children, index + 1); + left_children.push_back(right_child); + left_children.drain_from_front(&mut self.children, MEDIAN - index - 1); + + median = self.keys.pop_front(); + + right_keys = Chunk::drain_from(&mut self.keys); + right_children = Chunk::drain_from(&mut self.children); + } else if index > MEDIAN { + self.children[index] = left_child; + + left_keys = Chunk::from_front(&mut self.keys, MEDIAN); + left_children = Chunk::from_front(&mut self.children, MEDIAN + 1); + + median = self.keys.pop_front(); + + right_keys = Chunk::from_front(&mut self.keys, index - MEDIAN - 1); + right_keys.push_back(value); + right_keys.append(&mut self.keys); + + right_children = Chunk::from_front(&mut self.children, index - MEDIAN); + right_children.push_back(right_child); + right_children.append(&mut self.children); + } else { + left_keys = Chunk::from_front(&mut self.keys, MEDIAN); + left_children = Chunk::from_front(&mut self.children, MEDIAN); + left_children.push_back(left_child); + + median = value; + + right_keys = Chunk::drain_from(&mut self.keys); + right_children = Chunk::drain_from(&mut self.children); + right_children[0] = right_child; + } + + debug_assert!(left_keys.len() == MEDIAN); + debug_assert!(left_children.len() == MEDIAN + 1); + debug_assert!(right_keys.len() == MEDIAN); + debug_assert!(right_children.len() == MEDIAN + 1); + + Split( + Node { + keys: left_keys, + children: left_children, + }, + median, + Node { + keys: right_keys, + children: right_children, + }, + ) + } + + fn merge(middle: A, left: Node, mut right: Node) -> Node { + let mut keys = left.keys; + keys.push_back(middle); + keys.append(&mut right.keys); + let mut children = left.children; + children.append(&mut right.children); + Node { keys, children } + } + + fn pop_min(&mut self) -> (A, Option>>) { + let value = self.keys.pop_front(); + let child = self.children.pop_front(); + (value, child) + } + + fn pop_max(&mut self) -> (A, Option>>) { + let value = self.keys.pop_back(); + let child = self.children.pop_back(); + (value, child) + } + + fn push_min(&mut self, child: Option>>, value: A) { + self.keys.push_front(value); + self.children.push_front(child); + } + + fn push_max(&mut self, child: Option>>, value: A) { + self.keys.push_back(value); + self.children.push_back(child); + } + + pub fn insert(&mut self, value: A) -> Insert + where + A: Clone, + { + if self.keys.is_empty() { + self.keys.push_back(value); + self.children.push_back(None); + return Insert::Added; + } + let (median, left, right) = match A::search_value(&self.keys, &value) { + // Key exists in node + Ok(index) => { + return Insert::Replaced(mem::replace(&mut self.keys[index], value)); + } + // Key is adjacent to some key in node + Err(index) => { + let has_room = self.has_room(); + let action = match self.children[index] { + // No child at location, this is the target node. + None => InsertAt, + // Child at location, pass it on. + Some(ref mut child_ref) => { + let child = Ref::make_mut(child_ref); + match child.insert(value.clone()) { + Insert::Added => AddedAction, + Insert::Replaced(value) => ReplacedAction(value), + Insert::Update(_) => unreachable!(), + Insert::Split(left, median, right) => InsertSplit(left, median, right), + } + } + }; + match action { + ReplacedAction(value) => return Insert::Replaced(value), + AddedAction => { + return Insert::Added; + } + InsertAt => { + if has_room { + self.keys.insert(index, value); + self.children.insert(index + 1, None); + return Insert::Added; + } else { + (value, None, None) + } + } + InsertSplit(left, median, right) => { + if has_room { + self.children[index] = Some(Ref::from(left)); + self.keys.insert(index, median); + self.children.insert(index + 1, Some(Ref::from(right))); + return Insert::Added; + } else { + (median, Some(left), Some(right)) + } + } + } + } + }; + self.split(median, left, right) + } + + pub fn remove(&mut self, key: &BK) -> Remove + where + A: Clone, + BK: Ord + ?Sized, + A::Key: Borrow, + { + let index = A::search_key(&self.keys, key); + self.remove_index(index, key) + } + + fn remove_index(&mut self, index: Result, key: &BK) -> Remove + where + A: Clone, + BK: Ord + ?Sized, + A::Key: Borrow, + { + let action = match index { + // Key exists in node, remove it. + Ok(index) => { + match (&self.children[index], &self.children[index + 1]) { + // If we're a leaf, just delete the entry. + (&None, &None) => RemoveAction::DeleteAt(index), + // If the left hand child has capacity, pull the predecessor up. + (&Some(ref left), _) if !left.too_small() => { + if left.is_leaf() { + RemoveAction::PullUp(left.keys.len() - 1, index, index) + } else { + RemoveAction::StealFromLeft(index + 1) + } + } + // If the right hand child has capacity, pull the successor up. + (_, &Some(ref right)) if !right.too_small() => { + if right.is_leaf() { + RemoveAction::PullUp(0, index, index + 1) + } else { + RemoveAction::StealFromRight(index) + } + } + // If neither child has capacity, we'll have to merge them. + (&Some(_), &Some(_)) => RemoveAction::Merge(index), + // If one child exists and the other doesn't, we're in a bad state. + _ => unreachable!(), + } + } + // Key is adjacent to some key in node + Err(index) => match self.children[index] { + // No child at location means key isn't in map. + None => return Remove::NoChange, + // Child at location, but it's at minimum capacity. + Some(ref child) if child.too_small() => { + let left = if index > 0 { + self.children.get(index - 1) + } else { + None + }; // index is usize and can't be negative, best make sure it never is. + match (left, self.children.get(index + 1)) { + // If it has a left sibling with capacity, steal a key from it. + (Some(&Some(ref old_left)), _) if !old_left.too_small() => { + RemoveAction::StealFromLeft(index) + } + // If it has a right sibling with capacity, same as above. + (_, Some(&Some(ref old_right))) if !old_right.too_small() => { + RemoveAction::StealFromRight(index) + } + // If it has neither, we'll have to merge it with a sibling. + // If we have a right sibling, we'll merge with that. + (_, Some(&Some(_))) => RemoveAction::MergeFirst(index), + // If we have a left sibling, we'll merge with that. + (Some(&Some(_)), _) => RemoveAction::MergeFirst(index - 1), + // If none of the above, we're in a bad state. + _ => unreachable!(), + } + } + // Child at location, and it's big enough, we can recurse down. + Some(_) => RemoveAction::ContinueDown(index), + }, + }; + match action { + RemoveAction::DeleteAt(index) => { + let pair = self.keys.remove(index); + self.children.remove(index); + Remove::Removed(pair) + } + RemoveAction::PullUp(target_index, pull_to, child_index) => { + let children = &mut self.children; + let mut update = None; + let mut value; + if let Some(&mut Some(ref mut child_ref)) = children.get_mut(child_index) { + let child = Ref::make_mut(child_ref); + match child.remove_index(Ok(target_index), key) { + Remove::NoChange => unreachable!(), + Remove::Removed(pulled_value) => { + value = self.keys.set(pull_to, pulled_value); + } + Remove::Update(pulled_value, new_child) => { + value = self.keys.set(pull_to, pulled_value); + update = Some(new_child); + } + } + } else { + unreachable!() + } + if let Some(new_child) = update { + children[child_index] = Some(Ref::from(new_child)); + } + Remove::Removed(value) + } + RemoveAction::Merge(index) => { + let left = self.children.remove(index).unwrap(); + let right = mem::replace(&mut self.children[index], None).unwrap(); + let value = self.keys.remove(index); + let mut merged_child = Node::merge(value, clone_ref(left), clone_ref(right)); + let (removed, new_child) = match merged_child.remove(key) { + Remove::NoChange => unreachable!(), + Remove::Removed(removed) => (removed, merged_child), + Remove::Update(removed, updated_child) => (removed, updated_child), + }; + if self.keys.is_empty() { + // If we've depleted the root node, the merged child becomes the root. + Remove::Update(removed, new_child) + } else { + self.children[index] = Some(Ref::from(new_child)); + Remove::Removed(removed) + } + } + RemoveAction::StealFromLeft(index) => { + let mut update = None; + let mut out_value; + { + let mut children = self.children.as_mut_slice()[index - 1..=index] + .iter_mut() + .map(|n| { + if let Some(ref mut o) = *n { + o + } else { + unreachable!() + } + }); + let left = Ref::make_mut(children.next().unwrap()); + let child = Ref::make_mut(children.next().unwrap()); + // Prepare the rebalanced node. + child.push_min( + left.children.last().unwrap().clone(), + self.keys[index - 1].clone(), + ); + match child.remove(key) { + Remove::NoChange => { + // Key wasn't there, we need to revert the steal. + child.pop_min(); + return Remove::NoChange; + } + Remove::Removed(value) => { + // If we did remove something, we complete the rebalancing. + let (left_value, _) = left.pop_max(); + self.keys[index - 1] = left_value; + out_value = value; + } + Remove::Update(value, new_child) => { + // If we did remove something, we complete the rebalancing. + let (left_value, _) = left.pop_max(); + self.keys[index - 1] = left_value; + update = Some(new_child); + out_value = value; + } + } + } + if let Some(new_child) = update { + self.children[index] = Some(Ref::from(new_child)); + } + Remove::Removed(out_value) + } + RemoveAction::StealFromRight(index) => { + let mut update = None; + let mut out_value; + { + let mut children = self.children.as_mut_slice()[index..index + 2] + .iter_mut() + .map(|n| { + if let Some(ref mut o) = *n { + o + } else { + unreachable!() + } + }); + let child = Ref::make_mut(children.next().unwrap()); + let right = Ref::make_mut(children.next().unwrap()); + // Prepare the rebalanced node. + child.push_max(right.children[0].clone(), self.keys[index].clone()); + match child.remove(key) { + Remove::NoChange => { + // Key wasn't there, we need to revert the steal. + child.pop_max(); + return Remove::NoChange; + } + Remove::Removed(value) => { + // If we did remove something, we complete the rebalancing. + let (right_value, _) = right.pop_min(); + self.keys[index] = right_value; + out_value = value; + } + Remove::Update(value, new_child) => { + // If we did remove something, we complete the rebalancing. + let (right_value, _) = right.pop_min(); + self.keys[index] = right_value; + update = Some(new_child); + out_value = value; + } + } + } + if let Some(new_child) = update { + self.children[index] = Some(Ref::from(new_child)); + } + Remove::Removed(out_value) + } + RemoveAction::MergeFirst(index) => { + if self.keys[index].cmp_keys(key) != Ordering::Equal + && !self.child_contains(index, key) + && !self.child_contains(index + 1, key) + { + return Remove::NoChange; + } + let left = self.children.remove(index).unwrap(); + let right = mem::replace(&mut self.children[index], None).unwrap(); + let middle = self.keys.remove(index); + let mut merged = Node::merge(middle, clone_ref(left), clone_ref(right)); + let mut update; + let mut out_value; + match merged.remove(key) { + Remove::NoChange => { + panic!("nodes::btree::Node::remove: caught an absent key too late while merging"); + } + Remove::Removed(value) => { + if self.keys.is_empty() { + return Remove::Update(value, merged); + } + update = merged; + out_value = value; + } + Remove::Update(value, new_child) => { + if self.keys.is_empty() { + return Remove::Update(value, new_child); + } + update = new_child; + out_value = value; + } + } + self.children[index] = Some(Ref::from(update)); + Remove::Removed(out_value) + } + RemoveAction::ContinueDown(index) => { + let mut update = None; + let mut out_value; + if let Some(&mut Some(ref mut child_ref)) = self.children.get_mut(index) { + let child = Ref::make_mut(child_ref); + match child.remove(key) { + Remove::NoChange => return Remove::NoChange, + Remove::Removed(value) => { + out_value = value; + } + Remove::Update(value, new_child) => { + update = Some(new_child); + out_value = value; + } + } + } else { + unreachable!() + } + if let Some(new_child) = update { + self.children[index] = Some(Ref::from(new_child)); + } + Remove::Removed(out_value) + } + } + } +} + +// Iterator + +pub struct Iter<'a, A: 'a> { + fwd_path: Vec<(&'a Node, usize)>, + back_path: Vec<(&'a Node, usize)>, + pub(crate) remaining: usize, +} + +impl<'a, A: 'a + BTreeValue> Iter<'a, A> { + pub fn new(root: &'a Node, size: usize, range: R) -> Self + where + R: RangeBounds, + A::Key: Borrow, + BK: Ord + ?Sized, + { + let fwd_path = match range.start_bound() { + Bound::Included(key) => root.path_next(key, Vec::new()), + Bound::Excluded(key) => { + let mut path = root.path_next(key, Vec::new()); + if let Some(value) = Self::get(&path) { + if value.cmp_keys(key) == Ordering::Equal { + Self::step_forward(&mut path); + } + } + path + } + Bound::Unbounded => root.path_first(Vec::new()), + }; + let back_path = match range.end_bound() { + Bound::Included(key) => root.path_prev(key, Vec::new()), + Bound::Excluded(key) => { + let mut path = root.path_prev(key, Vec::new()); + if let Some(value) = Self::get(&path) { + if value.cmp_keys(key) == Ordering::Equal { + Self::step_back(&mut path); + } + } + path + } + Bound::Unbounded => root.path_last(Vec::new()), + }; + Iter { + fwd_path, + back_path, + remaining: size, + } + } + + fn get(path: &[(&'a Node, usize)]) -> Option<&'a A> { + match path.last() { + Some((node, index)) => Some(&node.keys[*index]), + None => None, + } + } + + fn step_forward(path: &mut Vec<(&'a Node, usize)>) -> Option<&'a A> { + match path.pop() { + Some((node, index)) => { + let index = index + 1; + match node.children[index] { + // Child between current and next key -> step down + Some(ref child) => { + path.push((node, index)); + path.push((child, 0)); + let mut node = child; + while let Some(ref left_child) = node.children[0] { + path.push((left_child, 0)); + node = left_child; + } + Some(&node.keys[0]) + } + None => match node.keys.get(index) { + // Yield next key + value @ Some(_) => { + path.push((node, index)); + value + } + // No more keys -> exhausted level, step up and yield + None => loop { + match path.pop() { + None => { + return None; + } + Some((node, index)) => { + if let value @ Some(_) = node.keys.get(index) { + path.push((node, index)); + return value; + } + } + } + }, + }, + } + } + None => None, + } + } + + fn step_back(path: &mut Vec<(&'a Node, usize)>) -> Option<&'a A> { + match path.pop() { + Some((node, index)) => match node.children[index] { + Some(ref child) => { + path.push((node, index)); + let mut end = child.keys.len() - 1; + path.push((child, end)); + let mut node = child; + while let Some(ref right_child) = node.children[end + 1] { + end = right_child.keys.len() - 1; + path.push((right_child, end)); + node = right_child; + } + Some(&node.keys[end]) + } + None => { + if index == 0 { + loop { + match path.pop() { + None => { + return None; + } + Some((node, index)) => { + if index > 0 { + let index = index - 1; + path.push((node, index)); + return Some(&node.keys[index]); + } + } + } + } + } else { + let index = index - 1; + path.push((node, index)); + Some(&node.keys[index]) + } + } + }, + None => None, + } + } +} + +impl<'a, A: 'a + BTreeValue> Iterator for Iter<'a, A> { + type Item = &'a A; + + fn next(&mut self) -> Option { + match Iter::get(&self.fwd_path) { + None => None, + Some(value) => match Iter::get(&self.back_path) { + Some(last_value) if value.cmp_values(last_value) == Ordering::Greater => None, + None => None, + Some(_) => { + Iter::step_forward(&mut self.fwd_path); + self.remaining -= 1; + Some(value) + } + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + // (0, Some(self.remaining)) + (0, None) + } +} + +impl<'a, A: 'a + BTreeValue> DoubleEndedIterator for Iter<'a, A> { + fn next_back(&mut self) -> Option { + match Iter::get(&self.back_path) { + None => None, + Some(value) => match Iter::get(&self.fwd_path) { + Some(last_value) if value.cmp_values(last_value) == Ordering::Less => None, + None => None, + Some(_) => { + Iter::step_back(&mut self.back_path); + self.remaining -= 1; + Some(value) + } + }, + } + } +} + +// Consuming iterator + +enum ConsumingIterItem { + Consider(Node), + Yield(A), +} + +pub struct ConsumingIter { + fwd_last: Option, + fwd_stack: Vec>, + back_last: Option, + back_stack: Vec>, + remaining: usize, +} + +impl ConsumingIter { + pub fn new(root: &Node, total: usize) -> Self { + ConsumingIter { + fwd_last: None, + fwd_stack: vec![ConsumingIterItem::Consider(root.clone())], + back_last: None, + back_stack: vec![ConsumingIterItem::Consider(root.clone())], + remaining: total, + } + } + + fn push_node(stack: &mut Vec>, maybe_node: Option>>) { + if let Some(node) = maybe_node { + stack.push(ConsumingIterItem::Consider(clone_ref(node))) + } + } + + fn push(stack: &mut Vec>, mut node: Node) { + for _n in 0..node.keys.len() { + ConsumingIter::push_node(stack, node.children.pop_back()); + stack.push(ConsumingIterItem::Yield(node.keys.pop_back())); + } + ConsumingIter::push_node(stack, node.children.pop_back()); + } + + fn push_fwd(&mut self, node: Node) { + ConsumingIter::push(&mut self.fwd_stack, node) + } + + fn push_node_back(&mut self, maybe_node: Option>>) { + if let Some(node) = maybe_node { + self.back_stack + .push(ConsumingIterItem::Consider(clone_ref(node))) + } + } + + fn push_back(&mut self, mut node: Node) { + for _i in 0..node.keys.len() { + self.push_node_back(node.children.pop_front()); + self.back_stack + .push(ConsumingIterItem::Yield(node.keys.pop_front())); + } + self.push_node_back(node.children.pop_back()); + } +} + +impl Iterator for ConsumingIter +where + A: BTreeValue + Clone, +{ + type Item = A; + + fn next(&mut self) -> Option { + loop { + match self.fwd_stack.pop() { + None => { + self.remaining = 0; + return None; + } + Some(ConsumingIterItem::Consider(node)) => self.push_fwd(node), + Some(ConsumingIterItem::Yield(value)) => { + if let Some(ref last) = self.back_last { + if value.cmp_values(last) != Ordering::Less { + self.fwd_stack.clear(); + self.back_stack.clear(); + self.remaining = 0; + return None; + } + } + self.remaining -= 1; + self.fwd_last = Some(value.clone()); + return Some(value); + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.remaining, Some(self.remaining)) + } +} + +impl DoubleEndedIterator for ConsumingIter +where + A: BTreeValue + Clone, +{ + fn next_back(&mut self) -> Option { + loop { + match self.back_stack.pop() { + None => { + self.remaining = 0; + return None; + } + Some(ConsumingIterItem::Consider(node)) => self.push_back(node), + Some(ConsumingIterItem::Yield(value)) => { + if let Some(ref last) = self.fwd_last { + if value.cmp_values(last) != Ordering::Greater { + self.fwd_stack.clear(); + self.back_stack.clear(); + self.remaining = 0; + return None; + } + } + self.remaining -= 1; + self.back_last = Some(value.clone()); + return Some(value); + } + } + } + } +} + +impl ExactSizeIterator for ConsumingIter {} + +// DiffIter + +pub struct DiffIter<'a, A: 'a> { + old_stack: Vec>, + new_stack: Vec>, +} + +#[derive(PartialEq, Eq)] +pub enum DiffItem<'a, A: 'a> { + Add(&'a A), + Update { old: &'a A, new: &'a A }, + Remove(&'a A), +} + +enum IterItem<'a, A: 'a> { + Consider(&'a Node), + Yield(&'a A), +} + +impl<'a, A: 'a> DiffIter<'a, A> { + pub fn new(old: &'a Node, new: &'a Node) -> Self { + DiffIter { + old_stack: if old.keys.is_empty() { + Vec::new() + } else { + vec![IterItem::Consider(old)] + }, + new_stack: if new.keys.is_empty() { + Vec::new() + } else { + vec![IterItem::Consider(new)] + }, + } + } + + fn push_node(stack: &mut Vec>, maybe_node: &'a Option>>) { + if let Some(ref node) = *maybe_node { + stack.push(IterItem::Consider(&node)) + } + } + + fn push(stack: &mut Vec>, node: &'a Node) { + for n in 0..node.keys.len() { + let i = node.keys.len() - n; + Self::push_node(stack, &node.children[i]); + stack.push(IterItem::Yield(&node.keys[i - 1])); + } + Self::push_node(stack, &node.children[0]); + } +} + +impl<'a, A> Iterator for DiffIter<'a, A> +where + A: 'a + BTreeValue + PartialEq, +{ + type Item = DiffItem<'a, A>; + + fn next(&mut self) -> Option { + loop { + match (self.old_stack.pop(), self.new_stack.pop()) { + (None, None) => return None, + (None, Some(new)) => match new { + IterItem::Consider(new) => Self::push(&mut self.new_stack, &new), + IterItem::Yield(new) => return Some(DiffItem::Add(new)), + }, + (Some(old), None) => match old { + IterItem::Consider(old) => Self::push(&mut self.old_stack, &old), + IterItem::Yield(old) => return Some(DiffItem::Remove(old)), + }, + (Some(old), Some(new)) => match (old, new) { + (IterItem::Consider(old), IterItem::Consider(new)) => { + match old.keys[0].cmp_values(&new.keys[0]) { + Ordering::Less => { + Self::push(&mut self.old_stack, &old); + self.new_stack.push(IterItem::Consider(new)); + } + Ordering::Greater => { + self.old_stack.push(IterItem::Consider(old)); + Self::push(&mut self.new_stack, &new); + } + Ordering::Equal => { + Self::push(&mut self.old_stack, &old); + Self::push(&mut self.new_stack, &new); + } + } + } + (IterItem::Consider(old), IterItem::Yield(new)) => { + Self::push(&mut self.old_stack, &old); + self.new_stack.push(IterItem::Yield(new)); + } + (IterItem::Yield(old), IterItem::Consider(new)) => { + self.old_stack.push(IterItem::Yield(old)); + Self::push(&mut self.new_stack, &new); + } + (IterItem::Yield(old), IterItem::Yield(new)) => match old.cmp_values(&new) { + Ordering::Less => { + self.new_stack.push(IterItem::Yield(new)); + return Some(DiffItem::Remove(old)); + } + Ordering::Equal => { + if old != new { + return Some(DiffItem::Update { old, new }); + } + } + Ordering::Greater => { + self.old_stack.push(IterItem::Yield(old)); + return Some(DiffItem::Add(new)); + } + }, + }, + } + } + } +} diff --git a/im-rc/src/nodes/hamt.rs b/im-rc/src/nodes/hamt.rs new file mode 100644 index 000000000..17ffc95e0 --- /dev/null +++ b/im-rc/src/nodes/hamt.rs @@ -0,0 +1,671 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::borrow::Borrow; +use std::fmt; +use std::hash::{BuildHasher, Hash, Hasher}; +use std::iter::FusedIterator; +use std::slice::{Iter as SliceIter, IterMut as SliceIterMut}; +use std::{mem, ptr}; + +use typenum::{Pow, Unsigned, U2}; + +use crate::config::HashLevelSize; +use crate::nodes::sparse_chunk::{Iter as ChunkIter, IterMut as ChunkIterMut, SparseChunk}; +use crate::nodes::types::Bits; +use crate::util::{clone_ref, Ref}; + +pub type HashWidth = >::Output; +pub type HashBits = ::Store; // a uint of HASH_SIZE bits +pub const HASH_SHIFT: usize = HashLevelSize::USIZE; +pub const HASH_WIDTH: usize = HashWidth::USIZE; +pub const HASH_MASK: HashBits = (HASH_WIDTH - 1) as HashBits; + +pub fn hash_key(bh: &S, key: &K) -> HashBits { + let mut hasher = bh.build_hasher(); + key.hash(&mut hasher); + hasher.finish() as HashBits +} + +#[inline] +fn mask(hash: HashBits, shift: usize) -> HashBits { + hash >> shift & HASH_MASK +} + +pub trait HashValue { + type Key: Eq; + + fn extract_key(&self) -> &Self::Key; + fn ptr_eq(&self, other: &Self) -> bool; +} + +#[derive(Clone)] +pub struct Node { + data: SparseChunk, HashWidth>, +} + +#[derive(Clone)] +pub struct CollisionNode { + hash: HashBits, + data: Vec, +} + +pub enum Entry { + Value(A, HashBits), + Collision(Ref>), + Node(Ref>), +} + +impl Clone for Entry { + fn clone(&self) -> Self { + match self { + Entry::Value(value, hash) => Entry::Value(value.clone(), *hash), + Entry::Collision(coll) => Entry::Collision(coll.clone()), + Entry::Node(node) => Entry::Node(node.clone()), + } + } +} + +impl Entry { + fn is_value(&self) -> bool { + match self { + Entry::Value(_, _) => true, + _ => false, + } + } + + fn unwrap_value(self) -> A { + match self { + Entry::Value(a, _) => a, + _ => panic!("nodes::hamt::Entry::unwrap_value: unwrapped a non-value"), + } + } +} + +impl From> for Entry { + fn from(node: Node) -> Self { + Entry::Node(Ref::new(node)) + } +} + +impl From> for Entry { + fn from(node: CollisionNode) -> Self { + Entry::Collision(Ref::new(node)) + } +} + +impl Default for Node { + fn default() -> Self { + Self::new() + } +} + +impl Node { + #[inline] + pub fn new() -> Self { + Node { + data: SparseChunk::new(), + } + } + + #[inline] + fn len(&self) -> usize { + self.data.len() + } + + #[inline] + pub fn unit(index: usize, value: Entry) -> Self { + Node { + data: SparseChunk::unit(index, value), + } + } + + #[inline] + pub fn pair(index1: usize, value1: Entry, index2: usize, value2: Entry) -> Self { + Node { + data: SparseChunk::pair(index1, value1, index2, value2), + } + } + + #[inline] + pub fn single_child(index: usize, node: Self) -> Self { + Node { + data: SparseChunk::unit(index, Entry::from(node)), + } + } + + fn pop(&mut self) -> Entry { + self.data.pop().unwrap() + } +} + +impl Node { + fn merge_values(value1: A, hash1: HashBits, value2: A, hash2: HashBits, shift: usize) -> Self { + let index1 = mask(hash1, shift) as usize; + let index2 = mask(hash2, shift) as usize; + if index1 != index2 { + // Both values fit on the same level. + Node::pair( + index1, + Entry::Value(value1, hash1), + index2, + Entry::Value(value2, hash2), + ) + } else if shift + HASH_SHIFT >= HASH_WIDTH { + // If we're at the bottom, we've got a collision. + Node::unit( + index1, + Entry::from(CollisionNode::new(hash1, value1, value2)), + ) + } else { + // Pass the values down a level. + let node = Node::merge_values(value1, hash1, value2, hash2, shift + HASH_SHIFT); + Node::single_child(index1, node) + } + } + + pub fn get(&self, hash: HashBits, shift: usize, key: &BK) -> Option<&A> + where + BK: Eq + ?Sized, + A::Key: Borrow, + { + let index = mask(hash, shift) as usize; + if let Some(entry) = self.data.get(index) { + match entry { + Entry::Value(ref value, _) => { + if key == value.extract_key().borrow() { + Some(value) + } else { + None + } + } + Entry::Collision(ref coll) => coll.get(key), + Entry::Node(ref child) => child.get(hash, shift + HASH_SHIFT, key), + } + } else { + None + } + } + + pub fn get_mut(&mut self, hash: HashBits, shift: usize, key: &BK) -> Option<&mut A> + where + A: Clone, + BK: Eq + ?Sized, + A::Key: Borrow, + { + let index = mask(hash, shift) as usize; + if let Some(entry) = self.data.get_mut(index) { + match entry { + Entry::Value(ref mut value, _) => { + if key == value.extract_key().borrow() { + Some(value) + } else { + None + } + } + Entry::Collision(ref mut coll_ref) => { + let coll = Ref::make_mut(coll_ref); + coll.get_mut(key) + } + Entry::Node(ref mut child_ref) => { + let child = Ref::make_mut(child_ref); + child.get_mut(hash, shift + HASH_SHIFT, key) + } + } + } else { + None + } + } + + pub fn insert(&mut self, hash: HashBits, shift: usize, value: A) -> Option + where + A: Clone, + { + let index = mask(hash, shift) as usize; + if let Some(entry) = self.data.get_mut(index) { + let mut fallthrough = false; + // Value is here + match entry { + // Update value or create a subtree + Entry::Value(ref current, _) => { + if current.extract_key() == value.extract_key() { + // If we have a key match, fall through to the outer + // level where we replace the current value. If we + // don't, fall through to the inner level where we merge + // some nodes. + fallthrough = true; + } + } + // There's already a collision here. + Entry::Collision(ref mut collision) => { + let coll = Ref::make_mut(collision); + return coll.insert(value); + } + Entry::Node(ref mut child_ref) => { + // Child node + let child = Ref::make_mut(child_ref); + return child.insert(hash, shift + HASH_SHIFT, value); + } + } + if !fallthrough { + // If we get here, we're looking at a value entry that needs a merge. + // We're going to be unsafe and pry it out of the reference, trusting + // that we overwrite it with the merged node. + #[allow(unsafe_code)] + let old_entry = unsafe { ptr::read(entry) }; + if shift + HASH_SHIFT >= HASH_WIDTH { + // We're at the lowest level, need to set up a collision node. + let coll = CollisionNode::new(hash, old_entry.unwrap_value(), value); + #[allow(unsafe_code)] + unsafe { + ptr::write(entry, Entry::from(coll)) + }; + } else if let Entry::Value(old_value, old_hash) = old_entry { + let node = + Node::merge_values(old_value, old_hash, value, hash, shift + HASH_SHIFT); + #[allow(unsafe_code)] + unsafe { + ptr::write(entry, Entry::from(node)) + }; + } else { + unreachable!() + } + return None; + } + } + // If we get here, either we found nothing at this index, in which case + // we insert a new entry, or we hit a value entry with the same key, in + // which case we replace it. + self.data + .insert(index, Entry::Value(value, hash)) + .map(Entry::unwrap_value) + } + + pub fn remove(&mut self, hash: HashBits, shift: usize, key: &BK) -> Option + where + A: Clone, + BK: Eq + ?Sized, + A::Key: Borrow, + { + let index = mask(hash, shift) as usize; + let mut new_node = None; + let mut removed = None; + if let Some(entry) = self.data.get_mut(index) { + match entry { + Entry::Value(ref value, _) => { + if key != value.extract_key().borrow() { + // Key wasn't in the map. + return None; + } // Otherwise, fall through to the removal. + } + Entry::Collision(ref mut coll_ref) => { + let coll = Ref::make_mut(coll_ref); + removed = coll.remove(key); + if coll.len() == 1 { + new_node = Some(coll.pop()); + } else { + return removed; + } + } + Entry::Node(ref mut child_ref) => { + let child = Ref::make_mut(child_ref); + match child.remove(hash, shift + HASH_SHIFT, key) { + None => { + return None; + } + Some(value) => { + if child.len() == 1 + && child.data[child.data.first_index().unwrap()].is_value() + { + // If the child now contains only a single value node, + // pull it up one level and discard the child. + removed = Some(value); + new_node = Some(child.pop()); + } else { + return Some(value); + } + } + } + } + } + } + if let Some(node) = new_node { + self.data.insert(index, node); + return removed; + } + self.data.remove(index).map(Entry::unwrap_value) + } +} + +impl CollisionNode { + fn new(hash: HashBits, value1: A, value2: A) -> Self { + CollisionNode { + hash, + data: vec![value1, value2], + } + } + + #[inline] + fn len(&self) -> usize { + self.data.len() + } + + fn get(&self, key: &BK) -> Option<&A> + where + BK: Eq + ?Sized, + A::Key: Borrow, + { + for entry in &self.data { + if key == entry.extract_key().borrow() { + return Some(entry); + } + } + None + } + + fn get_mut(&mut self, key: &BK) -> Option<&mut A> + where + BK: Eq + ?Sized, + A::Key: Borrow, + { + for entry in &mut self.data { + if key == entry.extract_key().borrow() { + return Some(entry); + } + } + None + } + + fn insert(&mut self, value: A) -> Option { + for item in &mut self.data { + if value.extract_key() == item.extract_key() { + return Some(mem::replace(item, value)); + } + } + self.data.push(value); + None + } + + fn remove(&mut self, key: &BK) -> Option + where + BK: Eq + ?Sized, + A::Key: Borrow, + { + let mut loc = None; + for (index, item) in self.data.iter().enumerate() { + if key == item.extract_key().borrow() { + loc = Some(index); + } + } + if let Some(index) = loc { + Some(self.data.remove(index)) + } else { + None + } + } + + fn pop(&mut self) -> Entry { + Entry::Value(self.data.pop().unwrap(), self.hash) + } +} + +// Ref iterator + +pub struct Iter<'a, A> +where + A: 'a, +{ + count: usize, + stack: Vec, HashWidth>>, + current: ChunkIter<'a, Entry, HashWidth>, + collision: Option<(HashBits, SliceIter<'a, A>)>, +} + +impl<'a, A> Iter<'a, A> +where + A: 'a, +{ + pub fn new(root: &'a Node, size: usize) -> Self { + Iter { + count: size, + stack: Vec::with_capacity((HASH_WIDTH / HASH_SHIFT) + 1), + current: root.data.iter(), + collision: None, + } + } +} + +impl<'a, A> Iterator for Iter<'a, A> +where + A: 'a, +{ + type Item = (&'a A, HashBits); + + fn next(&mut self) -> Option { + if self.count == 0 { + return None; + } + if self.collision.is_some() { + if let Some((hash, ref mut coll)) = self.collision { + match coll.next() { + None => {} + Some(value) => { + self.count -= 1; + return Some((value, hash)); + } + } + } + self.collision = None; + return self.next(); + } + match self.current.next() { + Some(Entry::Value(value, hash)) => { + self.count -= 1; + Some((value, *hash)) + } + Some(Entry::Node(child)) => { + let current = mem::replace(&mut self.current, child.data.iter()); + self.stack.push(current); + self.next() + } + Some(Entry::Collision(coll)) => { + self.collision = Some((coll.hash, coll.data.iter())); + self.next() + } + None => match self.stack.pop() { + None => None, + Some(iter) => { + self.current = iter; + self.next() + } + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) + } +} + +impl<'a, A> ExactSizeIterator for Iter<'a, A> where A: 'a {} + +impl<'a, A> FusedIterator for Iter<'a, A> where A: 'a {} + +// Mut ref iterator + +pub struct IterMut<'a, A> +where + A: 'a, +{ + count: usize, + stack: Vec, HashWidth>>, + current: ChunkIterMut<'a, Entry, HashWidth>, + collision: Option<(HashBits, SliceIterMut<'a, A>)>, +} + +impl<'a, A> IterMut<'a, A> +where + A: 'a, +{ + pub fn new(root: &'a mut Node, size: usize) -> Self { + IterMut { + count: size, + stack: Vec::with_capacity((HASH_WIDTH / HASH_SHIFT) + 1), + current: root.data.iter_mut(), + collision: None, + } + } +} + +impl<'a, A> Iterator for IterMut<'a, A> +where + A: Clone + 'a, +{ + type Item = (&'a mut A, HashBits); + + fn next(&mut self) -> Option { + if self.count == 0 { + return None; + } + if self.collision.is_some() { + if let Some((hash, ref mut coll)) = self.collision { + match coll.next() { + None => {} + Some(value) => { + self.count -= 1; + return Some((value, hash)); + } + } + } + self.collision = None; + return self.next(); + } + match self.current.next() { + Some(Entry::Value(value, hash)) => { + self.count -= 1; + Some((value, *hash)) + } + Some(Entry::Node(child_ref)) => { + let child = Ref::make_mut(child_ref); + let current = mem::replace(&mut self.current, child.data.iter_mut()); + self.stack.push(current); + self.next() + } + Some(Entry::Collision(coll_ref)) => { + let coll = Ref::make_mut(coll_ref); + self.collision = Some((coll.hash, coll.data.iter_mut())); + self.next() + } + None => match self.stack.pop() { + None => None, + Some(iter) => { + self.current = iter; + self.next() + } + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) + } +} + +impl<'a, A> ExactSizeIterator for IterMut<'a, A> where A: Clone + 'a {} + +impl<'a, A> FusedIterator for IterMut<'a, A> where A: Clone + 'a {} + +// Consuming iterator + +pub struct Drain +where + A: HashValue, +{ + count: usize, + stack: Vec>>, + current: Ref>, + collision: Option>, +} + +impl Drain +where + A: HashValue, +{ + pub fn new(root: Ref>, size: usize) -> Self { + Drain { + count: size, + stack: vec![], + current: root, + collision: None, + } + } +} + +impl Iterator for Drain +where + A: HashValue + Clone, +{ + type Item = (A, HashBits); + + fn next(&mut self) -> Option { + if self.count == 0 { + return None; + } + if self.collision.is_some() { + if let Some(ref mut coll) = self.collision { + if let Some(value) = coll.data.pop() { + self.count -= 1; + return Some((value, coll.hash)); + } + } + self.collision = None; + return self.next(); + } + match Ref::make_mut(&mut self.current).data.pop() { + Some(Entry::Value(value, hash)) => { + self.count -= 1; + Some((value, hash)) + } + Some(Entry::Collision(coll_ref)) => { + self.collision = Some(clone_ref(coll_ref)); + self.next() + } + Some(Entry::Node(child)) => { + let parent = mem::replace(&mut self.current, child); + self.stack.push(parent); + self.next() + } + None => match self.stack.pop() { + None => None, + Some(parent) => { + self.current = parent; + self.next() + } + }, + } + } + + fn size_hint(&self) -> (usize, Option) { + (self.count, Some(self.count)) + } +} + +impl ExactSizeIterator for Drain where A: Clone {} + +impl FusedIterator for Drain where A: Clone {} + +impl fmt::Debug for Node { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "Node[ ")?; + for i in self.data.indices() { + write!(f, "{}: ", i)?; + match &self.data[i] { + Entry::Value(v, h) => write!(f, "{:?} :: {}, ", v, h)?, + Entry::Collision(c) => write!(f, "Coll{:?} :: {}", c.data, c.hash)?, + Entry::Node(n) => write!(f, "{:?}, ", n)?, + } + } + write!(f, " ]") + } +} diff --git a/im-rc/src/nodes/mod.rs b/im-rc/src/nodes/mod.rs new file mode 100644 index 000000000..03651c8cf --- /dev/null +++ b/im-rc/src/nodes/mod.rs @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +pub mod btree; +pub mod hamt; +pub mod rrb; + +pub use sized_chunks::*; + +pub mod chunk { + use crate::config::VectorChunkSize; + use sized_chunks as sc; + use typenum::Unsigned; + + pub type Chunk = sc::sized_chunk::Chunk; + pub type Iter = sc::sized_chunk::Iter; + pub const CHUNK_SIZE: usize = VectorChunkSize::USIZE; +} diff --git a/im-rc/src/nodes/rrb.rs b/im-rc/src/nodes/rrb.rs new file mode 100644 index 000000000..0e15d4f11 --- /dev/null +++ b/im-rc/src/nodes/rrb.rs @@ -0,0 +1,1120 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::iter::FusedIterator; +use std::mem::replace; +use std::ops::Range; + +use crate::nodes::chunk::{Chunk, CHUNK_SIZE}; +use crate::util::{ + clone_ref, Ref, + Side::{self, Left, Right}, +}; + +use self::Entry::*; + +pub const NODE_SIZE: usize = CHUNK_SIZE; + +#[derive(Debug)] +enum Size { + Size(usize), + Table(Ref>), +} + +impl Clone for Size { + fn clone(&self) -> Self { + match *self { + Size::Size(size) => Size::Size(size), + Size::Table(ref table) => Size::Table(table.clone()), + } + } +} + +impl Size { + fn size(&self) -> usize { + match self { + Size::Size(s) => *s, + Size::Table(sizes) => sizes.iter().sum(), + } + } + + fn is_size(&self) -> bool { + match self { + Size::Size(_) => true, + Size::Table(_) => false, + } + } + + fn table_from_size(level: usize, size: usize) -> Self { + let mut chunk = Chunk::new(); + let mut remaining = size; + let child_size = NODE_SIZE.pow(level as u32); + while remaining > child_size { + let next_value = chunk.last().unwrap_or(&0) + child_size; + chunk.push_back(next_value); + remaining -= child_size; + } + if remaining > 0 { + let next_value = chunk.last().unwrap_or(&0) + remaining; + chunk.push_back(next_value); + } + Size::Table(Ref::new(chunk)) + } + + fn push(&mut self, side: Side, value: usize) { + match self { + Size::Size(ref mut size) => *size += value, + Size::Table(ref mut size_ref) => { + let size_table = Ref::make_mut(size_ref); + debug_assert!(size_table.len() < NODE_SIZE); + match side { + Left => { + for entry in size_table.iter_mut() { + *entry += value; + } + size_table.push_front(value); + } + Right => { + let prev = *(size_table.last().unwrap_or(&0)); + size_table.push_back(value + prev); + } + } + } + } + } + + fn pop(&mut self, side: Side, value: usize) { + match self { + Size::Size(ref mut size) => *size -= value, + Size::Table(ref mut size_ref) => { + let size_table = Ref::make_mut(size_ref); + match side { + Left => { + let first = size_table.pop_front(); + debug_assert_eq!(value, first); + for entry in size_table.iter_mut() { + *entry -= value; + } + } + Right => { + let pop = size_table.pop_back(); + let last = size_table.last().unwrap_or(&0); + debug_assert_eq!(value, pop - last); + } + } + } + } + } + + fn update(&mut self, index: usize, value: isize) { + match self { + Size::Size(ref mut size) => *size = (*size as isize + value) as usize, + Size::Table(ref mut size_ref) => { + let size_table = Ref::make_mut(size_ref); + for entry in size_table.iter_mut().skip(index) { + *entry = (*entry as isize + value) as usize; + } + } + } + } +} + +pub enum PushResult { + Full(A, usize), + Done, +} + +pub enum PopResult { + Done(A), + Drained(A), + Empty, +} + +pub enum SplitResult { + Dropped(usize), + OutOfBounds, +} + +// Invariants: Nodes only at level > 0, Values/Empty only at level = 0 +enum Entry { + Nodes(Size, Ref>>>), + Values(Ref>), + Empty, +} + +impl Clone for Entry { + fn clone(&self) -> Self { + match *self { + Nodes(ref size, ref nodes) => Nodes(size.clone(), nodes.clone()), + Values(ref values) => Values(values.clone()), + Empty => Empty, + } + } +} + +impl Entry { + fn len(&self) -> usize { + match self { + Nodes(_, ref nodes) => nodes.len(), + Values(ref values) => values.len(), + Empty => 0, + } + } + + fn is_empty(&self) -> bool { + match self { + Nodes(_, ref nodes) => nodes.is_empty(), + Values(ref values) => values.is_empty(), + Empty => true, + } + } + + fn is_full(&self) -> bool { + match self { + Nodes(_, ref nodes) => nodes.is_full(), + Values(ref values) => values.is_full(), + Empty => false, + } + } + + fn unwrap_values(&self) -> &Chunk { + match self { + Values(ref values) => values, + _ => panic!("rrb::Entry::unwrap_values: expected values, found nodes"), + } + } + + fn unwrap_nodes(&self) -> &Chunk>> { + match self { + Nodes(_, ref nodes) => nodes, + _ => panic!("rrb::Entry::unwrap_nodes: expected nodes, found values"), + } + } + + fn unwrap_values_mut(&mut self) -> &mut Chunk { + match self { + Values(ref mut values) => Ref::make_mut(values), + _ => panic!("rrb::Entry::unwrap_values_mut: expected values, found nodes"), + } + } + + fn unwrap_nodes_mut(&mut self) -> &mut Chunk>> { + match self { + Nodes(_, ref mut nodes) => Ref::make_mut(nodes), + _ => panic!("rrb::Entry::unwrap_nodes_mut: expected nodes, found values"), + } + } + + fn values(self) -> Chunk { + match self { + Values(values) => clone_ref(values), + _ => panic!("rrb::Entry::values: expected values, found nodes"), + } + } + + fn nodes(self) -> Chunk>> { + match self { + Nodes(_, nodes) => clone_ref(nodes), + _ => panic!("rrb::Entry::nodes: expected nodes, found values"), + } + } + + fn is_empty_node(&self) -> bool { + match self { + Empty => true, + _ => false, + } + } +} + +// Node + +pub struct Node { + children: Entry, +} + +impl Clone for Node { + fn clone(&self) -> Self { + Node { + children: self.children.clone(), + } + } +} + +impl Default for Node { + fn default() -> Self { + Self::new() + } +} + +impl Node { + pub fn new() -> Self { + Node { children: Empty } + } + + pub fn parent(level: usize, children: Chunk>) -> Self { + let size = { + let mut size = Size::Size(0); + let mut it = children.iter().peekable(); + loop { + match it.next() { + None => break, + Some(child) => { + if size.is_size() + && !child.is_completely_dense(level - 1) + && it.peek().is_some() + { + size = Size::table_from_size(level, size.size()); + } + size.push(Right, child.len()) + } + } + } + size + }; + Node { + children: Nodes(size, Ref::from(children)), + } + } + + pub fn clear_node(&mut self) { + self.children = Empty; + } + + pub fn from_chunk(level: usize, chunk: Ref>) -> Self { + let node = Node { + children: Values(chunk), + }; + node.elevate(level) + } + + pub fn single_parent(node: Ref) -> Self { + let size = if node.is_dense() { + Size::Size(node.len()) + } else { + let size_table = Chunk::unit(node.len()); + Size::Table(Ref::from(size_table)) + }; + let children = Chunk::unit(node); + Node { + children: Nodes(size, Ref::from(children)), + } + } + + pub fn join_dense(left: Ref, right: Ref) -> Self { + let left_len = left.len(); + let right_len = right.len(); + Node { + children: { + let children = Chunk::pair(left, right); + Nodes(Size::Size(left_len + right_len), Ref::from(children)) + }, + } + } + + pub fn elevate(self, level_increment: usize) -> Self { + if level_increment > 0 { + Self::single_parent(Ref::from(self.elevate(level_increment - 1))) + } else { + self + } + } + + pub fn join_branches(self, right: Self, level: usize) -> Self { + let left_len = self.len(); + let right_len = right.len(); + let size = if self.is_completely_dense(level) && right.is_dense() { + Size::Size(left_len + right_len) + } else { + let size_table = Chunk::pair(left_len, left_len + right_len); + Size::Table(Ref::from(size_table)) + }; + Node { + children: { + let children = Chunk::pair(Ref::from(self), Ref::from(right)); + Nodes(size, Ref::from(children)) + }, + } + } + + pub fn len(&self) -> usize { + match self.children { + Entry::Nodes(Size::Size(size), _) => size, + Entry::Nodes(Size::Table(ref size_table), _) => *(size_table.last().unwrap_or(&0)), + Entry::Values(ref values) => values.len(), + Entry::Empty => 0, + } + } + + pub fn is_empty(&self) -> bool { + self.children.is_empty() + } + + pub fn is_single(&self) -> bool { + self.children.len() == 1 + } + + pub fn is_full(&self) -> bool { + self.children.is_full() + } + + pub fn number_of_children(&self) -> usize { + self.children.len() + } + + pub fn first_child(&self) -> &Ref { + self.children.unwrap_nodes().first().unwrap() + } + + /// True if the node is dense and so doesn't have a size table + fn is_dense(&self) -> bool { + match self.children { + Entry::Nodes(Size::Table(_), _) => false, + _ => true, + } + } + + /// True if the node and its children are dense and at capacity + // TODO can use this technique to quickly test if a Size::Table + // should be converted back to a Size::Size + fn is_completely_dense(&self, level: usize) -> bool { + // Size of a full node is NODE_SIZE at level 0, NODE_SIZE² at + // level 1, etc. + self.size() == NODE_SIZE.pow(level as u32 + 1) + } + + #[inline] + fn size(&self) -> usize { + match self.children { + Entry::Nodes(ref size, _) => size.size(), + Entry::Values(ref values) => values.len(), + Entry::Empty => 0, + } + } + + #[inline] + fn push_size(&mut self, side: Side, value: usize) { + if let Entry::Nodes(ref mut size, _) = self.children { + size.push(side, value) + } + } + + #[inline] + fn pop_size(&mut self, side: Side, value: usize) { + if let Entry::Nodes(ref mut size, _) = self.children { + size.pop(side, value) + } + } + + #[inline] + fn update_size(&mut self, index: usize, value: isize) { + if let Entry::Nodes(ref mut size, _) = self.children { + size.update(index, value) + } + } + + fn size_up_to(&self, level: usize, index: usize) -> usize { + if let Entry::Nodes(ref size, _) = self.children { + if index == 0 { + 0 + } else { + match size { + Size::Table(ref size_table) => size_table[index - 1], + Size::Size(_) => index * NODE_SIZE.pow(level as u32), + } + } + } else { + index + } + } + + fn index_in(&self, level: usize, index: usize) -> Option { + let mut target_idx = index / NODE_SIZE.pow(level as u32); + if target_idx >= self.children.len() { + return None; + } + if let Entry::Nodes(Size::Table(ref size_table), _) = self.children { + while size_table[target_idx] <= index { + target_idx += 1; + if target_idx >= size_table.len() { + return None; + } + } + } + Some(target_idx) + } + + pub fn index(&self, level: usize, index: usize) -> &A { + if level == 0 { + &self.children.unwrap_values()[index] + } else { + let target_idx = self.index_in(level, index).unwrap(); + self.children.unwrap_nodes()[target_idx] + .index(level - 1, index - self.size_up_to(level, target_idx)) + } + } + + pub fn index_mut(&mut self, level: usize, index: usize) -> &mut A { + if level == 0 { + &mut self.children.unwrap_values_mut()[index] + } else { + let target_idx = self.index_in(level, index).unwrap(); + let offset = index - self.size_up_to(level, target_idx); + let child = Ref::make_mut(&mut self.children.unwrap_nodes_mut()[target_idx]); + child.index_mut(level - 1, offset) + } + } + + pub fn lookup_chunk( + &self, + level: usize, + base: usize, + index: usize, + ) -> (Range, *const Chunk) { + if level == 0 { + ( + base..(base + self.children.len()), + self.children.unwrap_values() as *const Chunk, + ) + } else { + let target_idx = self.index_in(level, index).unwrap(); + let offset = self.size_up_to(level, target_idx); + let child_base = base + offset; + let children = self.children.unwrap_nodes(); + let child = &*children[target_idx]; + child.lookup_chunk(level - 1, child_base, index - offset) + } + } + + pub fn lookup_chunk_mut( + &mut self, + level: usize, + base: usize, + index: usize, + ) -> (Range, *mut Chunk) { + if level == 0 { + ( + base..(base + self.children.len()), + self.children.unwrap_values_mut() as *mut Chunk, + ) + } else { + let target_idx = self.index_in(level, index).unwrap(); + let offset = self.size_up_to(level, target_idx); + let child_base = base + offset; + let children = self.children.unwrap_nodes_mut(); + let child = Ref::make_mut(&mut children[target_idx]); + child.lookup_chunk_mut(level - 1, child_base, index - offset) + } + } + + fn push_child_node(&mut self, side: Side, child: Ref>) { + let children = self.children.unwrap_nodes_mut(); + match side { + Left => children.push_front(child), + Right => children.push_back(child), + } + } + + fn pop_child_node(&mut self, side: Side) -> Ref> { + let children = self.children.unwrap_nodes_mut(); + match side { + Left => children.pop_front(), + Right => children.pop_back(), + } + } + + pub fn push_chunk( + &mut self, + level: usize, + side: Side, + mut chunk: Ref>, + ) -> PushResult>> { + if chunk.is_empty() { + return PushResult::Done; + } + let is_full = self.is_full(); + if level == 0 { + if self.children.is_empty_node() { + self.push_size(side, chunk.len()); + self.children = Values(chunk); + PushResult::Done + } else { + let values = self.children.unwrap_values_mut(); + if values.len() + chunk.len() <= NODE_SIZE { + let chunk = Ref::make_mut(&mut chunk); + match side { + Side::Left => { + chunk.append(values); + values.append(chunk); + } + Side::Right => values.append(chunk), + } + PushResult::Done + } else { + PushResult::Full(chunk, 0) + } + } + } else if level == 1 { + // If rightmost existing node has any room, merge as much as + // possible over from the new node. + let num_drained = match side { + Side::Right => { + if let Entry::Nodes(ref mut size, ref mut children) = self.children { + let rightmost = Ref::make_mut(Ref::make_mut(children).last_mut().unwrap()); + let old_size = rightmost.len(); + let chunk = Ref::make_mut(&mut chunk); + let values = rightmost.children.unwrap_values_mut(); + let to_drain = chunk.len().min(NODE_SIZE - values.len()); + values.drain_from_front(chunk, to_drain); + size.pop(Side::Right, old_size); + size.push(Side::Right, values.len()); + to_drain + } else { + 0 + } + } + Side::Left => { + if let Entry::Nodes(ref mut size, ref mut children) = self.children { + let leftmost = Ref::make_mut(Ref::make_mut(children).first_mut().unwrap()); + let old_size = leftmost.len(); + let chunk = Ref::make_mut(&mut chunk); + let values = leftmost.children.unwrap_values_mut(); + let to_drain = chunk.len().min(NODE_SIZE - values.len()); + values.drain_from_back(chunk, to_drain); + size.pop(Side::Left, old_size); + size.push(Side::Left, values.len()); + to_drain + } else { + 0 + } + } + }; + if is_full { + PushResult::Full(chunk, num_drained) + } else { + // If the chunk is empty after being drained, there might be + // more space in existing chunks. To keep the middle dense, we + // do not add it here. + if !chunk.is_empty() { + if side == Left && chunk.len() < NODE_SIZE { + if let Entry::Nodes(ref mut size, _) = self.children { + if let Size::Size(value) = *size { + *size = Size::table_from_size(level, value); + } + } + } + self.push_size(side, chunk.len()); + self.push_child_node(side, Ref::new(Node::from_chunk(0, chunk))); + } + PushResult::Done + } + } else { + let chunk_size = chunk.len(); + let index = match side { + Right => self.children.len() - 1, + Left => 0, + }; + let new_child = { + let children = self.children.unwrap_nodes_mut(); + let child = Ref::make_mut(&mut children[index]); + match child.push_chunk(level - 1, side, chunk) { + PushResult::Done => None, + PushResult::Full(chunk, num_drained) => { + // Our chunk was too large for `child`, so it could not + // be pushed there. However, exactly `num_drained` + // elements were added to the child. We need to reflect + // that change in the size field of the node. + match side { + Right => match self.children { + Entry::Nodes(Size::Table(ref mut sizes), _) => { + let sizes = Ref::make_mut(sizes); + sizes[index] += num_drained; + } + Entry::Nodes(Size::Size(ref mut size), _) => { + *size += num_drained; + } + Entry::Values(_) | Entry::Empty => (), + }, + Left => { + self.update_size(0, num_drained as isize); + } + } + if is_full { + return PushResult::Full(chunk, 0); + } else { + Some(Node::from_chunk(level - 1, chunk)) + } + } + } + }; + match new_child { + None => { + self.update_size(index, chunk_size as isize); + PushResult::Done + } + Some(child) => { + if side == Left && chunk_size < NODE_SIZE { + if let Entry::Nodes(ref mut size, _) = self.children { + if let Size::Size(value) = *size { + *size = Size::table_from_size(level, value); + } + } + } + self.push_size(side, child.len()); + self.push_child_node(side, Ref::from(child)); + PushResult::Done + } + } + } + } + + pub fn pop_chunk(&mut self, level: usize, side: Side) -> PopResult>> { + if self.is_empty() { + return PopResult::Empty; + } + if level == 0 { + // should only get here if the tree is just one leaf node + match replace(&mut self.children, Empty) { + Values(chunk) => PopResult::Drained(chunk), + Empty => panic!("rrb::Node::pop_chunk: non-empty tree with Empty leaf"), + Nodes(_, _) => panic!("rrb::Node::pop_chunk: branch node at leaf"), + } + } else if level == 1 { + let child_node = self.pop_child_node(side); + self.pop_size(side, child_node.len()); + let chunk = match child_node.children { + Values(ref chunk) => chunk.clone(), + Empty => panic!("rrb::Node::pop_chunk: non-empty tree with Empty leaf"), + Nodes(_, _) => panic!("rrb::Node::pop_chunk: branch node at leaf"), + }; + if self.is_empty() { + PopResult::Drained(chunk) + } else { + PopResult::Done(chunk) + } + } else { + let index = match side { + Right => self.children.len() - 1, + Left => 0, + }; + let mut drained = false; + let chunk = { + let children = self.children.unwrap_nodes_mut(); + let child = Ref::make_mut(&mut children[index]); + match child.pop_chunk(level - 1, side) { + PopResult::Empty => return PopResult::Empty, + PopResult::Done(chunk) => chunk, + PopResult::Drained(chunk) => { + drained = true; + chunk + } + } + }; + if drained { + self.pop_size(side, chunk.len()); + self.pop_child_node(side); + if self.is_empty() { + PopResult::Drained(chunk) + } else { + PopResult::Done(chunk) + } + } else { + self.update_size(index, -(chunk.len() as isize)); + PopResult::Done(chunk) + } + } + } + + pub fn split(&mut self, level: usize, drop_side: Side, index: usize) -> SplitResult { + if index == 0 && drop_side == Side::Left { + return SplitResult::Dropped(0); + } + let mut dropped; + if level == 0 { + let len = self.children.len(); + if index >= len { + return SplitResult::OutOfBounds; + } + let children = self.children.unwrap_values_mut(); + match drop_side { + Side::Left => children.drop_left(index), + Side::Right => children.drop_right(index), + } + SplitResult::Dropped(match drop_side { + Left => index, + Right => len - index, + }) + } else if let Some(target_idx) = self.index_in(level, index) { + let size_up_to = self.size_up_to(level, target_idx); + let (size, children) = + if let Entry::Nodes(ref mut size, ref mut children) = self.children { + (size, Ref::make_mut(children)) + } else { + unreachable!() + }; + let child_gone = 0 == { + let child_node = Ref::make_mut(&mut children[target_idx]); + match child_node.split(level - 1, drop_side, index - size_up_to) { + SplitResult::OutOfBounds => return SplitResult::OutOfBounds, + SplitResult::Dropped(amount) => dropped = amount, + } + child_node.len() + }; + match drop_side { + Left => { + let mut drop_from = target_idx; + if child_gone { + drop_from += 1; + } + children.drop_left(drop_from); + if let Size::Size(value) = *size { + *size = Size::table_from_size(level, value); + } + let size_table = if let Size::Table(ref mut size_ref) = size { + Ref::make_mut(size_ref) + } else { + unreachable!() + }; + let dropped_size = if target_idx > 0 { + size_table[target_idx - 1] + } else { + 0 + }; + dropped += dropped_size; + size_table.drop_left(drop_from); + for i in size_table.iter_mut() { + *i -= dropped; + } + } + Right => { + let at_last = target_idx == children.len() - 1; + let mut drop_from = target_idx + 1; + if child_gone { + drop_from -= 1; + } + if drop_from < children.len() { + children.drop_right(drop_from); + } + match size { + Size::Size(ref mut size) if at_last => { + *size -= dropped; + } + Size::Size(ref mut size) => { + let size_per_child = NODE_SIZE.pow(level as u32); + let remainder = (target_idx + 1) * size_per_child; + let new_size = remainder - dropped; + dropped = *size - new_size; + *size = new_size; + } + Size::Table(ref mut size_ref) => { + let size_table = Ref::make_mut(size_ref); + let dropped_size = + size_table[size_table.len() - 1] - size_table[target_idx]; + if drop_from < size_table.len() { + size_table.drop_right(drop_from); + } + if !child_gone { + size_table[target_idx] -= dropped; + } + dropped += dropped_size; + } + } + } + } + SplitResult::Dropped(dropped) + } else { + SplitResult::OutOfBounds + } + } + + fn merge_leaves(mut left: Ref, mut right: Ref) -> Self { + if left.children.is_empty_node() { + // Left is empty, just use right + Self::single_parent(right) + } else if right.children.is_empty_node() { + // Right is empty, just use left + Self::single_parent(left) + } else { + { + let left_node = Ref::make_mut(&mut left); + let right_node = Ref::make_mut(&mut right); + let left_vals = left_node.children.unwrap_values_mut(); + let left_len = left_vals.len(); + let right_vals = right_node.children.unwrap_values_mut(); + let right_len = right_vals.len(); + if left_len + right_len <= NODE_SIZE { + left_vals.append(right_vals); + } else { + let count = right_len.min(NODE_SIZE - left_len); + left_vals.drain_from_front(right_vals, count); + } + } + if right.is_empty() { + Self::single_parent(left) + } else { + Self::join_dense(left, right) + } + } + } + + fn merge_rebalance(level: usize, left: Ref, middle: Self, right: Ref) -> Self { + let left_nodes = clone_ref(left).children.nodes().into_iter(); + let middle_nodes = middle.children.nodes().into_iter(); + let right_nodes = clone_ref(right).children.nodes().into_iter(); + let mut subtree_still_balanced = true; + let mut next_leaf = Chunk::new(); + let mut next_node = Chunk::new(); + let mut next_subtree = Chunk::new(); + let mut root = Chunk::new(); + + for subtree in left_nodes.chain(middle_nodes).chain(right_nodes) { + if subtree.is_empty() { + continue; + } + if subtree.is_completely_dense(level) && subtree_still_balanced { + root.push_back(subtree); + continue; + } + subtree_still_balanced = false; + + let child = clone_ref(subtree); + if level == 1 { + for value in child.children.values() { + next_leaf.push_back(value); + if next_leaf.is_full() { + let new_node = Node::from_chunk(0, Ref::from(next_leaf)); + next_subtree.push_back(Ref::from(new_node)); + next_leaf = Chunk::new(); + if next_subtree.is_full() { + let new_subtree = Node::parent(level, next_subtree); + root.push_back(Ref::from(new_subtree)); + next_subtree = Chunk::new(); + } + } + } + } else { + for node in child.children.nodes() { + next_node.push_back(node); + if next_node.is_full() { + let new_node = Node::parent(level - 1, next_node); + next_subtree.push_back(Ref::from(new_node)); + next_node = Chunk::new(); + if next_subtree.is_full() { + let new_subtree = Node::parent(level, next_subtree); + root.push_back(Ref::from(new_subtree)); + next_subtree = Chunk::new(); + } + } + } + } + } + if !next_leaf.is_empty() { + let new_node = Node::from_chunk(0, Ref::from(next_leaf)); + next_subtree.push_back(Ref::from(new_node)); + } + if !next_node.is_empty() { + let new_node = Node::parent(level - 1, next_node); + next_subtree.push_back(Ref::from(new_node)); + } + if !next_subtree.is_empty() { + let new_subtree = Node::parent(level, next_subtree); + root.push_back(Ref::from(new_subtree)); + } + Node::parent(level + 1, root) + } + + pub fn merge(mut left: Ref, mut right: Ref, level: usize) -> Self { + if level == 0 { + Self::merge_leaves(left, right) + } else { + let merged = { + if level == 1 { + // We're going to rebalance all the leaves anyway, there's + // no need for a middle at level 1 + Node::parent(0, Chunk::new()) + } else { + let left_node = Ref::make_mut(&mut left); + let right_node = Ref::make_mut(&mut right); + let left_last = + if let Entry::Nodes(ref mut size, ref mut children) = left_node.children { + let node = Ref::make_mut(children).pop_back(); + size.pop(Side::Right, node.len()); + node + } else { + panic!("expected nodes, found entries or empty"); + }; + let right_first = + if let Entry::Nodes(ref mut size, ref mut children) = right_node.children { + let node = Ref::make_mut(children).pop_front(); + size.pop(Side::Left, node.len()); + node + } else { + panic!("expected nodes, found entries or empty"); + }; + Self::merge(left_last, right_first, level - 1) + } + }; + Self::merge_rebalance(level, left, merged, right) + } + } + + pub fn assert_invariants(&self) -> usize { + // Verifies that the size table matches reality. + match self.children { + Entry::Empty => 0, + Entry::Values(ref values) => { + // An empty value node is pointless and should never occur. + assert_ne!(0, values.len()); + values.len() + } + Entry::Nodes(ref size, ref children) => { + // A parent node with no children should never occur. + assert_ne!(0, children.len()); + let mut lengths = Vec::new(); + for child in &**children { + lengths.push(child.assert_invariants()); + } + match size { + Size::Size(size) => { + let total: usize = lengths.iter().sum(); + assert_eq!(*size, total); + } + Size::Table(ref table) => { + for (index, current) in table.iter().enumerate() { + let expected: usize = lengths.iter().take(index + 1).sum(); + assert_eq!(expected, *current); + } + } + } + lengths.iter().sum() + } + } + } + + // pub fn print(&self, f: &mut W, indent: usize, level: usize) -> Result<(), fmt::Error> + // where + // W: fmt::Write, + // A: fmt::Debug, + // { + // print_indent(f, indent)?; + // if level == 0 { + // if self.children.is_empty_node() { + // writeln!(f, "Leaf: EMPTY") + // } else { + // writeln!(f, "Leaf: {:?}", self.children.unwrap_values()) + // } + // } else { + // match &self.children { + // Entry::Nodes(size, children) => { + // writeln!(f, "Node level {} size_table {:?}", level, size)?; + // for child in children.iter() { + // child.print(f, indent + 4, level - 1)?; + // } + // Ok(()) + // } + // _ => unreachable!(), + // } + // } + // } +} + +// fn print_indent(f: &mut W, indent: usize) -> Result<(), fmt::Error> +// where +// W: fmt::Write, +// { +// for _i in 0..indent { +// write!(f, " ")?; +// } +// Ok(()) +// } + +// Consuming iterator + +pub struct ConsumingIter { + root: Node, + level: usize, + front_chunk: Option>, + back_chunk: Option>, + remaining: usize, +} + +impl ConsumingIter { + pub fn new(root: Node, level: usize) -> Self { + ConsumingIter { + remaining: root.len(), + root, + level, + front_chunk: None, + back_chunk: None, + } + } +} + +impl Iterator for ConsumingIter { + type Item = A; + + fn next(&mut self) -> Option { + if self.remaining == 0 { + return None; + } + if let Some(ref mut chunk) = self.front_chunk { + if !chunk.is_empty() { + self.remaining -= 1; + return Some(chunk.pop_front()); + } + } + match self.root.pop_chunk(self.level, Side::Left) { + PopResult::Done(chunk) => self.front_chunk = Some(clone_ref(chunk)), + PopResult::Drained(chunk) => self.front_chunk = Some(clone_ref(chunk)), + PopResult::Empty => { + if let Some(ref mut chunk) = self.back_chunk { + if !chunk.is_empty() { + self.remaining -= 1; + return Some(chunk.pop_front()); + } else { + return None; + } + } + } + } + self.next() + } + + fn size_hint(&self) -> (usize, Option) { + (self.remaining, Some(self.remaining)) + } +} + +impl DoubleEndedIterator for ConsumingIter { + fn next_back(&mut self) -> Option { + if self.remaining == 0 { + return None; + } + if let Some(ref mut chunk) = self.back_chunk { + if !chunk.is_empty() { + self.remaining -= 1; + return Some(chunk.pop_back()); + } + } + match self.root.pop_chunk(self.level, Side::Left) { + PopResult::Done(chunk) => self.front_chunk = Some(clone_ref(chunk)), + PopResult::Drained(chunk) => self.front_chunk = Some(clone_ref(chunk)), + PopResult::Empty => { + if let Some(ref mut chunk) = self.front_chunk { + if !chunk.is_empty() { + self.remaining -= 1; + return Some(chunk.pop_back()); + } else { + return None; + } + } + } + } + self.next() + } +} + +impl ExactSizeIterator for ConsumingIter {} + +impl FusedIterator for ConsumingIter {} diff --git a/im-rc/src/ord/map.rs b/im-rc/src/ord/map.rs new file mode 100644 index 000000000..6609a31a5 --- /dev/null +++ b/im-rc/src/ord/map.rs @@ -0,0 +1,2353 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! An ordered map. +//! +//! An immutable ordered map implemented as a [B-tree] [1]. +//! +//! Most operations on this type of map are O(log n). A +//! [`HashMap`][hashmap::HashMap] is usually a better choice for +//! performance, but the `OrdMap` has the advantage of only requiring +//! an [`Ord`][std::cmp::Ord] constraint on the key, and of being +//! ordered, so that keys always come out from lowest to highest, +//! where a [`HashMap`][hashmap::HashMap] has no guaranteed ordering. +//! +//! [1]: https://en.wikipedia.org/wiki/B-tree +//! [hashmap::HashMap]: ../hashmap/struct.HashMap.html +//! [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::collections; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{BuildHasher, Hash, Hasher}; +use std::iter::{FromIterator, Iterator, Sum}; +use std::mem; +use std::ops::{Add, Index, IndexMut, RangeBounds}; + +use crate::hashmap::HashMap; +use crate::nodes::btree::{BTreeValue, Insert, Node, Remove}; +#[cfg(has_specialisation)] +use crate::util::linear_search_by; +use crate::util::Ref; + +pub use crate::nodes::btree::{ConsumingIter, DiffItem, DiffIter, Iter as RangedIter}; + +/// Construct a map from a sequence of key/value pairs. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::ordmap::OrdMap; +/// # fn main() { +/// assert_eq!( +/// ordmap!{ +/// 1 => 11, +/// 2 => 22, +/// 3 => 33 +/// }, +/// OrdMap::from(vec![(1, 11), (2, 22), (3, 33)]) +/// ); +/// # } +/// ``` +#[macro_export] +macro_rules! ordmap { + () => { $crate::ordmap::OrdMap::new() }; + + ( $( $key:expr => $value:expr ),* ) => {{ + let mut map = $crate::ordmap::OrdMap::new(); + $({ + map.insert($key, $value); + })*; + map + }}; +} + +#[cfg(not(has_specialisation))] +impl BTreeValue for (K, V) { + type Key = K; + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } + + fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + slice.binary_search_by(|value| Self::Key::borrow(&value.0).cmp(key)) + } + + fn search_value(slice: &[Self], key: &Self) -> Result { + slice.binary_search_by(|value| value.0.cmp(&key.0)) + } + + fn cmp_keys(&self, other: &BK) -> Ordering + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + Self::Key::borrow(&self.0).cmp(other) + } + + fn cmp_values(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} + +#[cfg(has_specialisation)] +impl BTreeValue for (K, V) { + type Key = K; + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } + + default fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + slice.binary_search_by(|value| Self::Key::borrow(&value.0).cmp(key)) + } + + default fn search_value(slice: &[Self], key: &Self) -> Result { + slice.binary_search_by(|value| value.0.cmp(&key.0)) + } + + fn cmp_keys(&self, other: &BK) -> Ordering + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + Self::Key::borrow(&self.0).cmp(other) + } + + fn cmp_values(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} + +#[cfg(has_specialisation)] +impl BTreeValue for (K, V) { + fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + linear_search_by(slice, |value| Self::Key::borrow(&value.0).cmp(key)) + } + + fn search_value(slice: &[Self], key: &Self) -> Result { + linear_search_by(slice, |value| value.0.cmp(&key.0)) + } +} + +/// An ordered map. +/// +/// An immutable ordered map implemented as a B-tree. +/// +/// Most operations on this type of map are O(log n). A +/// [`HashMap`][hashmap::HashMap] is usually a better choice for +/// performance, but the `OrdMap` has the advantage of only requiring +/// an [`Ord`][std::cmp::Ord] constraint on the key, and of being +/// ordered, so that keys always come out from lowest to highest, +/// where a [`HashMap`][hashmap::HashMap] has no guaranteed ordering. +/// +/// [hashmap::HashMap]: ../hashmap/struct.HashMap.html +/// [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html +pub struct OrdMap { + size: usize, + root: Ref>, +} + +impl OrdMap { + /// Construct an empty map. + #[must_use] + pub fn new() -> Self { + OrdMap { + size: 0, + root: Ref::from(Node::new()), + } + } + + /// Construct a map with a single mapping. + /// + /// This method has been deprecated; use [`unit`][unit] instead. + /// + /// [unit]: #method.unit + #[inline] + #[must_use] + #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")] + pub fn singleton(key: K, value: V) -> Self { + Self::unit(key, value) + } + + /// Construct a map with a single mapping. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map = OrdMap::unit(123, "onetwothree"); + /// assert_eq!( + /// map.get(&123), + /// Some(&"onetwothree") + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn unit(key: K, value: V) -> Self { + OrdMap { + size: 1, + root: Ref::from(Node::unit((key, value))), + } + } + + /// Test whether a map is empty. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// assert!( + /// !ordmap!{1 => 2}.is_empty() + /// ); + /// assert!( + /// OrdMap::::new().is_empty() + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the size of a map. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// assert_eq!(3, ordmap!{ + /// 1 => 11, + /// 2 => 22, + /// 3 => 33 + /// }.len()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.size + } + + /// Discard all elements from the map. + /// + /// This leaves you with an empty map, and all elements that + /// were previously inside it are dropped. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::OrdMap; + /// # fn main() { + /// let mut map = ordmap![1=>1, 2=>2, 3=>3]; + /// map.clear(); + /// assert!(map.is_empty()); + /// # } + /// ``` + pub fn clear(&mut self) { + if !self.is_empty() { + self.root = Default::default(); + self.size = 0; + } + } +} + +impl OrdMap +where + K: Ord, +{ + /// Get the largest key in a map, along with its value. If the map + /// is empty, return `None`. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// assert_eq!(Some(&(3, 33)), ordmap!{ + /// 1 => 11, + /// 2 => 22, + /// 3 => 33 + /// }.get_max()); + /// # } + /// ``` + #[must_use] + pub fn get_max(&self) -> Option<&(K, V)> { + self.root.max() + } + + /// Get the smallest key in a map, along with its value. If the + /// map is empty, return `None`. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// assert_eq!(Some(&(1, 11)), ordmap!{ + /// 1 => 11, + /// 2 => 22, + /// 3 => 33 + /// }.get_min()); + /// # } + /// ``` + #[must_use] + pub fn get_min(&self) -> Option<&(K, V)> { + self.root.min() + } + + /// Get an iterator over the key/value pairs of a map. + #[must_use] + pub fn iter(&self) -> Iter<(K, V)> { + Iter { + it: RangedIter::new(&self.root, self.size, ..), + } + } + + // Create an iterator over a range of key/value pairs. + #[must_use] + pub fn range(&self, range: R) -> RangedIter<(K, V)> + where + R: RangeBounds, + K: Borrow, + BK: Ord + ?Sized, + { + RangedIter::new(&self.root, self.size, range) + } + + /// Get an iterator over a map's keys. + #[must_use] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { it: self.iter() } + } + + /// Get an iterator over a map's values. + #[must_use] + pub fn values(&self) -> Values<'_, K, V> { + Values { it: self.iter() } + } + + /// Get an iterator over the differences between this map and + /// another, i.e. the set of entries to add, update, or remove to + /// this map in order to make it equal to the other map. + /// + /// This function will avoid visiting nodes which are shared + /// between the two maps, meaning that even very large maps can be + /// compared quickly if most of their structure is shared. + /// + /// Time: O(n) (where n is the number of unique elements across + /// the two maps, minus the number of elements belonging to nodes + /// shared between them) + #[must_use] + pub fn diff<'a>(&'a self, other: &'a Self) -> DiffIter<'a, (K, V)> { + DiffIter::new(&self.root, &other.root) + } + + /// Get the value for a key from a map. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map = ordmap!{123 => "lol"}; + /// assert_eq!( + /// map.get(&123), + /// Some(&"lol") + /// ); + /// # } + /// ``` + #[must_use] + pub fn get(&self, key: &BK) -> Option<&V> + where + BK: Ord + ?Sized, + K: Borrow, + { + self.root.lookup(key).map(|(_, v)| v) + } + + /// Test for the presence of a key in a map. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map = ordmap!{123 => "lol"}; + /// assert!( + /// map.contains_key(&123) + /// ); + /// assert!( + /// !map.contains_key(&321) + /// ); + /// # } + /// ``` + #[must_use] + pub fn contains_key(&self, k: &BK) -> bool + where + BK: Ord + ?Sized, + K: Borrow, + { + self.get(k).is_some() + } + + /// Test whether a map is a submap of another map, meaning that + /// all keys in our map must also be in the other map, with the + /// same values. + /// + /// Use the provided function to decide whether values are equal. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_submap_by(&self, other: RM, mut cmp: F) -> bool + where + F: FnMut(&V, &B) -> bool, + RM: Borrow>, + { + self.iter() + .all(|(k, v)| other.borrow().get(k).map(|ov| cmp(v, ov)).unwrap_or(false)) + } + + /// Test whether a map is a proper submap of another map, meaning + /// that all keys in our map must also be in the other map, with + /// the same values. To be a proper submap, ours must also contain + /// fewer keys than the other map. + /// + /// Use the provided function to decide whether values are equal. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_proper_submap_by(&self, other: RM, cmp: F) -> bool + where + F: FnMut(&V, &B) -> bool, + RM: Borrow>, + { + self.len() != other.borrow().len() && self.is_submap_by(other, cmp) + } + + /// Test whether a map is a submap of another map, meaning that + /// all keys in our map must also be in the other map, with the + /// same values. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 2 => 2}; + /// let map2 = ordmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert!(map1.is_submap(map2)); + /// # } + /// ``` + #[must_use] + pub fn is_submap(&self, other: RM) -> bool + where + V: PartialEq, + RM: Borrow, + { + self.is_submap_by(other.borrow(), PartialEq::eq) + } + + /// Test whether a map is a proper submap of another map, meaning + /// that all keys in our map must also be in the other map, with + /// the same values. To be a proper submap, ours must also contain + /// fewer keys than the other map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 2 => 2}; + /// let map2 = ordmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert!(map1.is_proper_submap(map2)); + /// + /// let map3 = ordmap!{1 => 1, 2 => 2}; + /// let map4 = ordmap!{1 => 1, 2 => 2}; + /// assert!(!map3.is_proper_submap(map4)); + /// # } + /// ``` + #[must_use] + pub fn is_proper_submap(&self, other: RM) -> bool + where + V: PartialEq, + RM: Borrow, + { + self.is_proper_submap_by(other.borrow(), PartialEq::eq) + } +} + +impl OrdMap +where + K: Ord + Clone, + V: Clone, +{ + #[must_use] + fn get_mut(&mut self, key: &BK) -> Option<&mut V> + where + BK: Ord + ?Sized, + K: Borrow, + { + let root = Ref::make_mut(&mut self.root); + root.lookup_mut(key).map(|(_, v)| v) + } + + /// Insert a key/value mapping into a map. + /// + /// This is a copy-on-write operation, so that the parts of the + /// map's structure which are shared with other maps will be + /// safely copied before mutating. + /// + /// If the map already has a mapping for the given key, the + /// previous value is overwritten. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let mut map = ordmap!{}; + /// map.insert(123, "123"); + /// map.insert(456, "456"); + /// assert_eq!( + /// map, + /// ordmap!{123 => "123", 456 => "456"} + /// ); + /// # } + /// ``` + /// + /// [insert]: #method.insert + #[inline] + pub fn insert(&mut self, key: K, value: V) -> Option { + let new_root = { + let root = Ref::make_mut(&mut self.root); + match root.insert((key, value)) { + Insert::Replaced((_, old_value)) => return Some(old_value), + Insert::Added => { + self.size += 1; + return None; + } + Insert::Update(root) => Ref::from(root), + Insert::Split(left, median, right) => { + Ref::from(Node::from_split(left, median, right)) + } + } + }; + self.size += 1; + self.root = new_root; + None + } + + /// Remove a key/value mapping from a map if it exists. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let mut map = ordmap!{123 => "123", 456 => "456"}; + /// map.remove(&123); + /// map.remove(&456); + /// assert!(map.is_empty()); + /// # } + /// ``` + /// + /// [remove]: #method.remove + #[inline] + pub fn remove(&mut self, k: &BK) -> Option + where + BK: Ord + ?Sized, + K: Borrow, + { + self.remove_with_key(k).map(|(_, v)| v) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed key and value. + /// + /// Time: O(log n) + pub fn remove_with_key(&mut self, k: &BK) -> Option<(K, V)> + where + BK: Ord + ?Sized, + K: Borrow, + { + let (new_root, removed_value) = { + let root = Ref::make_mut(&mut self.root); + match root.remove(k) { + Remove::NoChange => return None, + Remove::Removed(pair) => { + self.size -= 1; + return Some(pair); + } + Remove::Update(pair, root) => (Ref::from(root), Some(pair)), + } + }; + self.size -= 1; + self.root = new_root; + removed_value + } + + /// Construct a new map by inserting a key/value mapping into a + /// map. + /// + /// If the map already has a mapping for the given key, the + /// previous value is overwritten. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map = ordmap!{}; + /// assert_eq!( + /// map.update(123, "123"), + /// ordmap!{123 => "123"} + /// ); + /// # } + /// ``` + #[must_use] + pub fn update(&self, key: K, value: V) -> Self { + let mut out = self.clone(); + out.insert(key, value); + out + } + + /// Construct a new map by inserting a key/value mapping into a + /// map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the old value and the new value, + /// and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_with(self, k: K, v: V, f: F) -> Self + where + F: FnOnce(V, V) -> V, + { + self.update_with_key(k, v, |_, v1, v2| f(v1, v2)) + } + + /// Construct a new map by inserting a key/value mapping into a + /// map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the key, the old value and the new + /// value, and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_with_key(self, k: K, v: V, f: F) -> Self + where + F: FnOnce(&K, V, V) -> V, + { + match self.extract_with_key(&k) { + None => self.update(k, v), + Some((_, v2, m)) => { + let out_v = f(&k, v2, v); + m.update(k, out_v) + } + } + } + + /// Construct a new map by inserting a key/value mapping into a + /// map, returning the old value for the key as well as the new + /// map. + /// + /// If the map already has a mapping for the given key, we call + /// the provided function with the key, the old value and the new + /// value, and insert the result as the new value. + /// + /// Time: O(log n) + #[must_use] + pub fn update_lookup_with_key(self, k: K, v: V, f: F) -> (Option, Self) + where + F: FnOnce(&K, &V, V) -> V, + { + match self.extract_with_key(&k) { + None => (None, self.update(k, v)), + Some((_, v2, m)) => { + let out_v = f(&k, &v2, v); + (Some(v2), m.update(k, out_v)) + } + } + } + + /// Update the value for a given key by calling a function with + /// the current value and overwriting it with the function's + /// return value. + /// + /// The function gets an [`Option`][std::option::Option] and + /// returns the same, so that it can decide to delete a mapping + /// instead of updating the value, and decide what to do if the + /// key isn't in the map. + /// + /// Time: O(log n) + /// + /// [std::option::Option]: https://doc.rust-lang.org/std/option/enum.Option.html + #[must_use] + pub fn alter(&self, f: F, k: K) -> Self + where + F: FnOnce(Option) -> Option, + { + let pop = self.extract_with_key(&k); + match (f(pop.as_ref().map(|&(_, ref v, _)| v.clone())), pop) { + (None, None) => self.clone(), + (Some(v), None) => self.update(k, v), + (None, Some((_, _, m))) => m, + (Some(v), Some((_, _, m))) => m.update(k, v), + } + } + + /// Remove a key/value pair from a map, if it exists. + /// + /// Time: O(log n) + #[must_use] + pub fn without(&self, k: &BK) -> Self + where + BK: Ord + ?Sized, + K: Borrow, + { + self.extract(k) + .map(|(_, m)| m) + .unwrap_or_else(|| self.clone()) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed value as well as the updated list. + /// + /// Time: O(log n) + #[must_use] + pub fn extract(&self, k: &BK) -> Option<(V, Self)> + where + BK: Ord + ?Sized, + K: Borrow, + { + self.extract_with_key(k).map(|(_, v, m)| (v, m)) + } + + /// Remove a key/value pair from a map, if it exists, and return + /// the removed key and value as well as the updated list. + /// + /// Time: O(log n) + #[must_use] + pub fn extract_with_key(&self, k: &BK) -> Option<(K, V, Self)> + where + BK: Ord + ?Sized, + K: Borrow, + { + let mut out = self.clone(); + let result = out.remove_with_key(k); + result.map(|(k, v)| (k, v, out)) + } + + /// Construct the union of two maps, keeping the values in the + /// current map when keys exist in both maps. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 3 => 3}; + /// let map2 = ordmap!{2 => 2, 3 => 4}; + /// let expected = ordmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert_eq!(expected, map1.union(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn union(mut self, other: Self) -> Self { + for (k, v) in other { + self.entry(k).or_insert(v); + } + self + } + + /// Construct the union of two maps, using a function to decide + /// what to do with the value when a key is in both maps. + /// + /// The function is called when a value exists in both maps, and + /// receives the value from the current map as its first argument, + /// and the value from the other map as the second. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn union_with(self, other: Self, mut f: F) -> Self + where + F: FnMut(V, V) -> V, + { + self.union_with_key(other, |_, v1, v2| f(v1, v2)) + } + + /// Construct the union of two maps, using a function to decide + /// what to do with the value when a key is in both maps. + /// + /// The function is called when a value exists in both maps, and + /// receives a reference to the key as its first argument, the + /// value from the current map as the second argument, and the + /// value from the other map as the third argument. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 3 => 4}; + /// let map2 = ordmap!{2 => 2, 3 => 5}; + /// let expected = ordmap!{1 => 1, 2 => 2, 3 => 9}; + /// assert_eq!(expected, map1.union_with_key( + /// map2, + /// |key, left, right| left + right + /// )); + /// # } + /// ``` + #[must_use] + pub fn union_with_key(mut self, other: Self, mut f: F) -> Self + where + F: FnMut(&K, V, V) -> V, + { + for (key, right_value) in other { + match self.remove(&key) { + None => { + self.insert(key, right_value); + } + Some(left_value) => { + let final_value = f(&key, left_value, right_value); + self.insert(key, final_value); + } + } + } + self + } + + /// Construct the union of a sequence of maps, selecting the value + /// of the leftmost when a key appears in more than one map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 3 => 3}; + /// let map2 = ordmap!{2 => 2}; + /// let expected = ordmap!{1 => 1, 2 => 2, 3 => 3}; + /// assert_eq!(expected, OrdMap::unions(vec![map1, map2])); + /// # } + /// ``` + #[must_use] + pub fn unions(i: I) -> Self + where + I: IntoIterator, + { + i.into_iter().fold(Self::default(), Self::union) + } + + /// Construct the union of a sequence of maps, using a function to + /// decide what to do with the value when a key is in more than + /// one map. + /// + /// The function is called when a value exists in multiple maps, + /// and receives the value from the current map as its first + /// argument, and the value from the next map as the second. It + /// should return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions_with(i: I, f: F) -> Self + where + I: IntoIterator, + F: Fn(V, V) -> V, + { + i.into_iter() + .fold(Self::default(), |a, b| a.union_with(b, &f)) + } + + /// Construct the union of a sequence of maps, using a function to + /// decide what to do with the value when a key is in more than + /// one map. + /// + /// The function is called when a value exists in multiple maps, + /// and receives a reference to the key as its first argument, the + /// value from the current map as the second argument, and the + /// value from the next map as the third argument. It should + /// return the value to be inserted in the resulting map. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions_with_key(i: I, f: F) -> Self + where + I: IntoIterator, + F: Fn(&K, V, V) -> V, + { + i.into_iter() + .fold(Self::default(), |a, b| a.union_with_key(b, &f)) + } + + /// Construct the difference between two maps by discarding keys + /// which occur in both maps. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 3 => 4}; + /// let map2 = ordmap!{2 => 2, 3 => 5}; + /// let expected = ordmap!{1 => 1, 2 => 2}; + /// assert_eq!(expected, map1.difference(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn difference(self, other: Self) -> Self { + self.difference_with_key(other, |_, _, _| None) + } + + /// Construct the difference between two maps by using a function + /// to decide what to do if a key occurs in both. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn difference_with(self, other: Self, mut f: F) -> Self + where + F: FnMut(V, V) -> Option, + { + self.difference_with_key(other, |_, a, b| f(a, b)) + } + + /// Construct the difference between two maps by using a function + /// to decide what to do if a key occurs in both. The function + /// receives the key as well as both values. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 3 => 4}; + /// let map2 = ordmap!{2 => 2, 3 => 5}; + /// let expected = ordmap!{1 => 1, 2 => 2, 3 => 9}; + /// assert_eq!(expected, map1.difference_with_key( + /// map2, + /// |key, left, right| Some(left + right) + /// )); + /// # } + /// ``` + #[must_use] + pub fn difference_with_key(mut self, other: Self, mut f: F) -> Self + where + F: FnMut(&K, V, V) -> Option, + { + let mut out = Self::default(); + for (key, right_value) in other { + match self.remove(&key) { + None => { + out.insert(key, right_value); + } + Some(left_value) => { + if let Some(final_value) = f(&key, left_value, right_value) { + out.insert(key, final_value); + } + } + } + } + out.union(self) + } + + /// Construct the intersection of two maps, keeping the values + /// from the current map. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 2 => 2}; + /// let map2 = ordmap!{2 => 3, 3 => 4}; + /// let expected = ordmap!{2 => 2}; + /// assert_eq!(expected, map1.intersection(map2)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn intersection(self, other: Self) -> Self { + self.intersection_with_key(other, |_, v, _| v) + } + + /// Construct the intersection of two maps, calling a function + /// with both values for each key and using the result as the + /// value for the key. + /// + /// Time: O(n log n) + #[inline] + #[must_use] + pub fn intersection_with(self, other: OrdMap, mut f: F) -> OrdMap + where + B: Clone, + C: Clone, + F: FnMut(V, B) -> C, + { + self.intersection_with_key(other, |_, v1, v2| f(v1, v2)) + } + + /// Construct the intersection of two maps, calling a function + /// with the key and both values for each key and using the result + /// as the value for the key. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordmap::OrdMap; + /// # fn main() { + /// let map1 = ordmap!{1 => 1, 2 => 2}; + /// let map2 = ordmap!{2 => 3, 3 => 4}; + /// let expected = ordmap!{2 => 5}; + /// assert_eq!(expected, map1.intersection_with_key( + /// map2, + /// |key, left, right| left + right + /// )); + /// # } + /// ``` + #[must_use] + pub fn intersection_with_key(mut self, other: OrdMap, mut f: F) -> OrdMap + where + B: Clone, + C: Clone, + F: FnMut(&K, V, B) -> C, + { + let mut out = OrdMap::::default(); + for (key, right_value) in other { + match self.remove(&key) { + None => (), + Some(left_value) => { + let result = f(&key, left_value, right_value); + out.insert(key, result); + } + } + } + out + } + + /// Split a map into two, with the left hand map containing keys + /// which are smaller than `split`, and the right hand map + /// containing keys which are larger than `split`. + /// + /// The `split` mapping is discarded. + #[must_use] + pub fn split(&self, split: &BK) -> (Self, Self) + where + BK: Ord + ?Sized, + K: Borrow, + { + let (l, _, r) = self.split_lookup(split); + (l, r) + } + + /// Split a map into two, with the left hand map containing keys + /// which are smaller than `split`, and the right hand map + /// containing keys which are larger than `split`. + /// + /// Returns both the two maps and the value of `split`. + #[must_use] + pub fn split_lookup(&self, split: &BK) -> (Self, Option, Self) + where + BK: Ord + ?Sized, + K: Borrow, + { + // TODO this is atrociously slow, got to be a better way + self.iter() + .fold((ordmap![], None, ordmap![]), |(l, m, r), (k, v)| { + match k.borrow().cmp(split) { + Ordering::Less => (l.update(k.clone(), v.clone()), m, r), + Ordering::Equal => (l, Some(v.clone()), r), + Ordering::Greater => (l, m, r.update(k.clone(), v.clone())), + } + }) + } + + /// Construct a map with only the `n` smallest keys from a given + /// map. + #[must_use] + pub fn take(&self, n: usize) -> Self { + self.iter().take(n).cloned().collect() + } + + /// Construct a map with the `n` smallest keys removed from a + /// given map. + #[must_use] + pub fn skip(&self, n: usize) -> Self { + self.iter().skip(n).cloned().collect() + } + + /// Remove the smallest key from a map, and return its value as + /// well as the updated map. + #[must_use] + pub fn without_min(&self) -> (Option, Self) { + let (pop, next) = self.without_min_with_key(); + (pop.map(|(_, v)| v), next) + } + + /// Remove the smallest key from a map, and return that key, its + /// value as well as the updated map. + #[must_use] + pub fn without_min_with_key(&self) -> (Option<(K, V)>, Self) { + match self.get_min() { + None => (None, self.clone()), + Some((k, _)) => { + let (key, value, next) = self.extract_with_key(k).unwrap(); + (Some((key, value)), next) + } + } + } + + /// Remove the largest key from a map, and return its value as + /// well as the updated map. + #[must_use] + pub fn without_max(&self) -> (Option, Self) { + let (pop, next) = self.without_max_with_key(); + (pop.map(|(_, v)| v), next) + } + + /// Remove the largest key from a map, and return that key, its + /// value as well as the updated map. + #[must_use] + pub fn without_max_with_key(&self) -> (Option<(K, V)>, Self) { + match self.get_max() { + None => (None, self.clone()), + Some((k, _)) => { + let (key, value, next) = self.extract_with_key(k).unwrap(); + (Some((key, value)), next) + } + } + } + + /// Get the [`Entry`][Entry] for a key in the map for in-place manipulation. + /// + /// Time: O(log n) + /// + /// [Entry]: enum.Entry.html + #[must_use] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { + if self.contains_key(&key) { + Entry::Occupied(OccupiedEntry { map: self, key }) + } else { + Entry::Vacant(VacantEntry { map: self, key }) + } + } +} + +// Entries + +/// A handle for a key and its associated value. +pub enum Entry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + Occupied(OccupiedEntry<'a, K, V>), + Vacant(VacantEntry<'a, K, V>), +} + +impl<'a, K, V> Entry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + /// Insert the default value provided if there was no value + /// already, and return a mutable reference to the value. + pub fn or_insert(self, default: V) -> &'a mut V { + self.or_insert_with(|| default) + } + + /// Insert the default value from the provided function if there + /// was no value already, and return a mutable reference to the + /// value. + pub fn or_insert_with(self, default: F) -> &'a mut V + where + F: FnOnce() -> V, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Insert a default value if there was no value already, and + /// return a mutable reference to the value. + pub fn or_default(self) -> &'a mut V + where + V: Default, + { + self.or_insert_with(Default::default) + } + + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + match self { + Entry::Occupied(entry) => entry.key(), + Entry::Vacant(entry) => entry.key(), + } + } + + /// Call the provided function to modify the value if the value + /// exists. + pub fn and_modify(mut self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match &mut self { + Entry::Occupied(ref mut entry) => f(entry.get_mut()), + Entry::Vacant(_) => (), + } + self + } +} + +/// An entry for a mapping that already exists in the map. +pub struct OccupiedEntry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + map: &'a mut OrdMap, + key: K, +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + &self.key + } + + /// Remove this entry from the map and return the removed mapping. + pub fn remove_entry(self) -> (K, V) { + self.map + .remove_with_key(&self.key) + .expect("ordmap::OccupiedEntry::remove_entry: key has vanished!") + } + + /// Get the current value. + #[must_use] + pub fn get(&self) -> &V { + self.map.get(&self.key).unwrap() + } + + /// Get a mutable reference to the current value. + #[must_use] + pub fn get_mut(&mut self) -> &mut V { + self.map.get_mut(&self.key).unwrap() + } + + /// Convert this entry into a mutable reference. + #[must_use] + pub fn into_mut(self) -> &'a mut V { + self.map.get_mut(&self.key).unwrap() + } + + /// Overwrite the current value. + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Remove this entry from the map and return the removed value. + pub fn remove(self) -> V { + self.remove_entry().1 + } +} + +/// An entry for a mapping that does not already exist in the map. +pub struct VacantEntry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + map: &'a mut OrdMap, + key: K, +} + +impl<'a, K, V> VacantEntry<'a, K, V> +where + K: 'a + Ord + Clone, + V: 'a + Clone, +{ + /// Get the key for this entry. + #[must_use] + pub fn key(&self) -> &K { + &self.key + } + + /// Convert this entry into its key. + #[must_use] + pub fn into_key(self) -> K { + self.key + } + + /// Insert a value into this entry. + pub fn insert(self, value: V) -> &'a mut V { + self.map.insert(self.key.clone(), value); + // TODO insert_mut ought to return this reference + self.map.get_mut(&self.key).unwrap() + } +} + +// Core traits + +impl Clone for OrdMap { + fn clone(&self) -> Self { + OrdMap { + size: self.size, + root: self.root.clone(), + } + } +} + +#[cfg(not(has_specialisation))] +impl PartialEq for OrdMap +where + K: Ord + PartialEq, + V: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.diff(other).next().is_none() + } +} + +#[cfg(has_specialisation)] +impl PartialEq for OrdMap +where + K: Ord + PartialEq, + V: PartialEq, +{ + default fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.diff(other).next().is_none() + } +} + +#[cfg(has_specialisation)] +impl PartialEq for OrdMap +where + K: Ord + Eq, + V: Eq, +{ + fn eq(&self, other: &Self) -> bool { + Ref::ptr_eq(&self.root, &other.root) + || (self.len() == other.len() && self.diff(other).next().is_none()) + } +} + +impl Eq for OrdMap {} + +impl PartialOrd for OrdMap +where + K: Ord, + V: PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +impl Ord for OrdMap +where + K: Ord, + V: Ord, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl Hash for OrdMap +where + K: Ord + Hash, + V: Hash, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + for i in self.iter() { + i.hash(state); + } + } +} + +impl Default for OrdMap { + fn default() -> Self { + Self::new() + } +} + +impl<'a, K, V> Add for &'a OrdMap +where + K: Ord + Clone, + V: Clone, +{ + type Output = OrdMap; + + fn add(self, other: Self) -> Self::Output { + self.clone().union(other.clone()) + } +} + +impl Add for OrdMap +where + K: Ord + Clone, + V: Clone, +{ + type Output = OrdMap; + + fn add(self, other: Self) -> Self::Output { + self.union(other) + } +} + +impl Sum for OrdMap +where + K: Ord + Clone, + V: Clone, +{ + fn sum(it: I) -> Self + where + I: Iterator, + { + it.fold(Self::default(), |a, b| a + b) + } +} + +impl Extend<(RK, RV)> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for (key, value) in iter { + self.insert(From::from(key), From::from(value)); + } + } +} + +impl<'a, BK, K, V> Index<&'a BK> for OrdMap +where + BK: Ord + ?Sized, + K: Ord + Borrow, +{ + type Output = V; + + fn index(&self, key: &BK) -> &Self::Output { + match self.root.lookup(key) { + None => panic!("OrdMap::index: invalid key"), + Some(&(_, ref value)) => value, + } + } +} + +impl<'a, BK, K, V> IndexMut<&'a BK> for OrdMap +where + BK: Ord + ?Sized, + K: Ord + Clone + Borrow, + V: Clone, +{ + fn index_mut(&mut self, key: &BK) -> &mut Self::Output { + let root = Ref::make_mut(&mut self.root); + match root.lookup_mut(key) { + None => panic!("OrdMap::index: invalid key"), + Some(&mut (_, ref mut value)) => value, + } + } +} + +impl Debug for OrdMap +where + K: Ord + Debug, + V: Debug, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut d = f.debug_map(); + for (k, v) in self { + d.entry(k, v); + } + d.finish() + } +} + +// Iterators + +pub struct Iter<'a, A: 'a> { + it: RangedIter<'a, A>, +} + +impl<'a, A> Iterator for Iter<'a, A> +where + A: 'a + BTreeValue, +{ + type Item = &'a A; + + fn next(&mut self) -> Option { + self.it.next() + } + + fn size_hint(&self) -> (usize, Option) { + (self.it.remaining, Some(self.it.remaining)) + } +} + +impl<'a, A> DoubleEndedIterator for Iter<'a, A> +where + A: 'a + BTreeValue, +{ + fn next_back(&mut self) -> Option { + self.it.next_back() + } +} + +impl<'a, A> ExactSizeIterator for Iter<'a, A> where A: 'a + BTreeValue {} + +pub struct Keys<'a, K: 'a, V: 'a> { + it: Iter<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ + type Item = &'a K; + + fn next(&mut self) -> Option { + match self.it.next() { + None => None, + Some((k, _)) => Some(k), + } + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ + fn next_back(&mut self) -> Option { + match self.it.next_back() { + None => None, + Some((k, _)) => Some(k), + } + } +} + +impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ +} + +pub struct Values<'a, K: 'a, V: 'a> { + it: Iter<'a, (K, V)>, +} + +impl<'a, K, V> Iterator for Values<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ + type Item = &'a V; + + fn next(&mut self) -> Option { + match self.it.next() { + None => None, + Some((_, v)) => Some(v), + } + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ + fn next_back(&mut self) -> Option { + match self.it.next_back() { + None => None, + Some((_, v)) => Some(v), + } + } +} + +impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> +where + K: 'a + Ord, + V: 'a, +{ +} + +impl FromIterator<(RK, RV)> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, +{ + fn from_iter(i: T) -> Self + where + T: IntoIterator, + { + let mut m = OrdMap::default(); + for (k, v) in i { + m.insert(From::from(k), From::from(v)); + } + m + } +} + +impl<'a, K, V> IntoIterator for &'a OrdMap +where + K: Ord, +{ + type Item = &'a (K, V); + type IntoIter = Iter<'a, (K, V)>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for OrdMap +where + K: Ord + Clone, + V: Clone, +{ + type Item = (K, V); + type IntoIter = ConsumingIter<(K, V)>; + + fn into_iter(self) -> Self::IntoIter { + ConsumingIter::new(&self.root, self.size) + } +} + +// Conversions + +impl AsRef> for OrdMap { + fn as_ref(&self) -> &Self { + self + } +} + +impl<'m, 'k, 'v, K, V, OK, OV> From<&'m OrdMap<&'k K, &'v V>> for OrdMap +where + K: Ord + ToOwned + ?Sized, + V: ToOwned + ?Sized, + OK: Ord + Clone + Borrow, + OV: Clone + Borrow, +{ + fn from(m: &OrdMap<&K, &V>) -> Self { + m.iter() + .map(|(k, v)| ((*k).to_owned(), (*v).to_owned())) + .collect() + } +} + +impl<'a, K, V, RK, RV, OK, OV> From<&'a [(RK, RV)]> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, + OK: Borrow, + OV: Borrow, + RK: ToOwned, + RV: ToOwned, +{ + fn from(m: &'a [(RK, RV)]) -> OrdMap { + m.iter() + .map(|&(ref k, ref v)| (k.to_owned(), v.to_owned())) + .collect() + } +} + +impl From> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, +{ + fn from(m: Vec<(RK, RV)>) -> OrdMap { + m.into_iter().collect() + } +} + +impl<'a, K: Ord, V, RK, RV, OK, OV> From<&'a Vec<(RK, RV)>> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, + OK: Borrow, + OV: Borrow, + RK: ToOwned, + RV: ToOwned, +{ + fn from(m: &'a Vec<(RK, RV)>) -> OrdMap { + m.iter() + .map(|&(ref k, ref v)| (k.to_owned(), v.to_owned())) + .collect() + } +} + +impl From> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, +{ + fn from(m: collections::HashMap) -> OrdMap { + m.into_iter().collect() + } +} + +impl<'a, K, V, OK, OV, RK, RV> From<&'a collections::HashMap> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, + OK: Borrow, + OV: Borrow, + RK: Hash + Eq + ToOwned, + RV: ToOwned, +{ + fn from(m: &'a collections::HashMap) -> OrdMap { + m.iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect() + } +} + +impl From> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, +{ + fn from(m: collections::BTreeMap) -> OrdMap { + m.into_iter().collect() + } +} + +impl<'a, K: Ord, V, RK, RV, OK, OV> From<&'a collections::BTreeMap> for OrdMap +where + K: Ord + Clone + From, + V: Clone + From, + OK: Borrow, + OV: Borrow, + RK: Ord + ToOwned, + RV: ToOwned, +{ + fn from(m: &'a collections::BTreeMap) -> OrdMap { + m.iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect() + } +} + +impl From> for OrdMap { + fn from(m: HashMap) -> Self { + m.into_iter().collect() + } +} + +impl<'a, K: Ord + Hash + Eq + Clone, V: Clone, S: BuildHasher> From<&'a HashMap> + for OrdMap +{ + fn from(m: &'a HashMap) -> Self { + m.iter().cloned().collect() + } +} + +// QuickCheck + +#[cfg(all(threadsafe, feature = "quickcheck"))] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(all(threadsafe, feature = "quickcheck"))] +impl Arbitrary for OrdMap { + fn arbitrary(g: &mut G) -> Self { + OrdMap::from_iter(Vec::<(K, V)>::arbitrary(g)) + } +} + +// Proptest + +#[cfg(any(test, feature = "proptest"))] +pub mod proptest { + use super::*; + use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; + use std::ops::Range; + + /// A strategy for a map of a given size. + /// + /// # Examples + /// + /// ```rust,ignore + /// proptest! { + /// #[test] + /// fn proptest_works(ref m in map(0..9999, ".*", 10..100)) { + /// assert!(m.len() < 100); + /// assert!(m.len() >= 10); + /// } + /// } + /// ``` + pub fn ord_map( + key: K, + value: V, + size: Range, + ) -> BoxedStrategy::Value, ::Value>> + where + ::Value: Ord + Clone, + ::Value: Clone, + { + ::proptest::collection::vec((key, value), size.clone()) + .prop_map(OrdMap::from) + .prop_filter("OrdMap minimum size".to_owned(), move |m| { + m.len() >= size.start + }) + .boxed() + } +} + +// Tests + +#[cfg(test)] +mod test { + use super::proptest::*; + use super::*; + use crate::nodes::btree::DiffItem; + use crate::test::is_sorted; + use ::proptest::num::{i16, usize}; + use ::proptest::{bool, collection, proptest}; + + #[test] + fn iterates_in_order() { + let map = ordmap! { + 2 => 22, + 1 => 11, + 3 => 33, + 8 => 88, + 9 => 99, + 4 => 44, + 5 => 55, + 7 => 77, + 6 => 66 + }; + let mut it = map.iter(); + assert_eq!(it.next(), Some(&(1, 11))); + assert_eq!(it.next(), Some(&(2, 22))); + assert_eq!(it.next(), Some(&(3, 33))); + assert_eq!(it.next(), Some(&(4, 44))); + assert_eq!(it.next(), Some(&(5, 55))); + assert_eq!(it.next(), Some(&(6, 66))); + assert_eq!(it.next(), Some(&(7, 77))); + assert_eq!(it.next(), Some(&(8, 88))); + assert_eq!(it.next(), Some(&(9, 99))); + assert_eq!(it.next(), None); + } + + #[test] + fn into_iter() { + let map = ordmap! { + 2 => 22, + 1 => 11, + 3 => 33, + 8 => 88, + 9 => 99, + 4 => 44, + 5 => 55, + 7 => 77, + 6 => 66 + }; + let mut vec = vec![]; + for (k, v) in map { + assert_eq!(k * 11, v); + vec.push(k) + } + assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]); + } + + #[test] + fn deletes_correctly() { + let map = ordmap! { + 2 => 22, + 1 => 11, + 3 => 33, + 8 => 88, + 9 => 99, + 4 => 44, + 5 => 55, + 7 => 77, + 6 => 66 + }; + assert_eq!(map.extract(&11), None); + let (popped, less) = map.extract(&5).unwrap(); + assert_eq!(popped, 55); + let mut it = less.iter(); + assert_eq!(it.next(), Some(&(1, 11))); + assert_eq!(it.next(), Some(&(2, 22))); + assert_eq!(it.next(), Some(&(3, 33))); + assert_eq!(it.next(), Some(&(4, 44))); + assert_eq!(it.next(), Some(&(6, 66))); + assert_eq!(it.next(), Some(&(7, 77))); + assert_eq!(it.next(), Some(&(8, 88))); + assert_eq!(it.next(), Some(&(9, 99))); + assert_eq!(it.next(), None); + } + + #[test] + fn debug_output() { + assert_eq!( + format!("{:?}", ordmap! { 3 => 4, 5 => 6, 1 => 2 }), + "{1: 2, 3: 4, 5: 6}" + ); + } + + #[test] + fn equality2() { + let v1 = "1".to_string(); + let v2 = "1".to_string(); + assert_eq!(v1, v2); + let p1 = Vec::::new(); + let p2 = Vec::::new(); + assert_eq!(p1, p2); + let c1 = OrdMap::unit(v1, p1); + let c2 = OrdMap::unit(v2, p2); + assert_eq!(c1, c2); + } + + #[test] + fn insert_remove_single_mut() { + let mut m = OrdMap::new(); + m.insert(0, 0); + assert_eq!(OrdMap::unit(0, 0), m); + m.remove(&0); + assert_eq!(OrdMap::new(), m); + } + + #[test] + fn double_ended_iterator_1() { + let m = ordmap! {1 => 1, 2 => 2, 3 => 3, 4 => 4}; + let mut it = m.iter(); + assert_eq!(Some(&(1, 1)), it.next()); + assert_eq!(Some(&(4, 4)), it.next_back()); + assert_eq!(Some(&(2, 2)), it.next()); + assert_eq!(Some(&(3, 3)), it.next_back()); + assert_eq!(None, it.next()); + } + + #[test] + fn double_ended_iterator_2() { + let m = ordmap! {1 => 1, 2 => 2, 3 => 3, 4 => 4}; + let mut it = m.iter(); + assert_eq!(Some(&(1, 1)), it.next()); + assert_eq!(Some(&(4, 4)), it.next_back()); + assert_eq!(Some(&(2, 2)), it.next()); + assert_eq!(Some(&(3, 3)), it.next_back()); + assert_eq!(None, it.next_back()); + } + + #[test] + fn safe_mutation() { + let v1 = OrdMap::from_iter((0..131_072).map(|i| (i, i))); + let mut v2 = v1.clone(); + v2.insert(131_000, 23); + assert_eq!(Some(&23), v2.get(&131_000)); + assert_eq!(Some(&131_000), v1.get(&131_000)); + } + + #[test] + fn index_operator() { + let mut map = ordmap! {1 => 2, 3 => 4, 5 => 6}; + assert_eq!(4, map[&3]); + map[&3] = 8; + assert_eq!(ordmap! {1 => 2, 3 => 8, 5 => 6}, map); + } + + #[test] + fn entry_api() { + let mut map = ordmap! {"bar" => 5}; + map.entry(&"foo").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(1, map[&"foo"]); + map.entry(&"foo").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(6, map[&"foo"]); + map.entry(&"bar").and_modify(|v| *v += 5).or_insert(1); + assert_eq!(10, map[&"bar"]); + assert_eq!( + 10, + match map.entry(&"bar") { + Entry::Occupied(entry) => entry.remove(), + _ => panic!(), + } + ); + assert!(!map.contains_key(&"bar")); + } + + #[test] + fn match_string_keys_with_string_slices() { + let mut map: OrdMap = + From::from(ºap! { "foo" => &1, "bar" => &2, "baz" => &3 }); + assert_eq!(Some(&1), map.get("foo")); + map = map.without("foo"); + assert_eq!(Some(3), map.remove("baz")); + map["bar"] = 8; + assert_eq!(8, map["bar"]); + } + + #[test] + fn ranged_iter() { + let map: OrdMap = ordmap![1=>2, 2=>3, 3=>4, 4=>5, 5=>6]; + let range: Vec<(i32, i32)> = map.range(..).cloned().collect(); + assert_eq!(vec![(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], range); + let range: Vec<(i32, i32)> = map.range(..).rev().cloned().collect(); + assert_eq!(vec![(5, 6), (4, 5), (3, 4), (2, 3), (1, 2)], range); + let range: Vec<(i32, i32)> = map.range(2..5).cloned().collect(); + assert_eq!(vec![(2, 3), (3, 4), (4, 5)], range); + let range: Vec<(i32, i32)> = map.range(2..5).rev().cloned().collect(); + assert_eq!(vec![(4, 5), (3, 4), (2, 3)], range); + let range: Vec<(i32, i32)> = map.range(3..).cloned().collect(); + assert_eq!(vec![(3, 4), (4, 5), (5, 6)], range); + let range: Vec<(i32, i32)> = map.range(3..).rev().cloned().collect(); + assert_eq!(vec![(5, 6), (4, 5), (3, 4)], range); + let range: Vec<(i32, i32)> = map.range(..4).cloned().collect(); + assert_eq!(vec![(1, 2), (2, 3), (3, 4)], range); + let range: Vec<(i32, i32)> = map.range(..4).rev().cloned().collect(); + assert_eq!(vec![(3, 4), (2, 3), (1, 2)], range); + let range: Vec<(i32, i32)> = map.range(..=3).cloned().collect(); + assert_eq!(vec![(1, 2), (2, 3), (3, 4)], range); + let range: Vec<(i32, i32)> = map.range(..=3).rev().cloned().collect(); + assert_eq!(vec![(3, 4), (2, 3), (1, 2)], range); + } + + proptest! { + #[test] + fn length(ref input in collection::btree_map(i16::ANY, i16::ANY, 0..1000)) { + let map: OrdMap = OrdMap::from(input.clone()); + input.len() == map.len() + } + + #[test] + fn order(ref input in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let map: OrdMap = OrdMap::from(input.clone()); + is_sorted(map.keys()) + } + + #[test] + fn overwrite_values(ref vec in collection::vec((i16::ANY, i16::ANY), 1..1000), index_rand in usize::ANY, new_val in i16::ANY) { + let index = vec[index_rand % vec.len()].0; + let map1 = OrdMap::from_iter(vec.clone()); + let map2 = map1.update(index, new_val); + for (k, v) in map2 { + if k == index { + assert_eq!(v, new_val); + } else { + match map1.get(&k) { + None => panic!("map1 didn't have key {:?}", k), + Some(other_v) => { + assert_eq!(v, *other_v); + } + } + } + } + } + + #[test] + fn delete_values(ref vec in collection::vec((usize::ANY, usize::ANY), 1..1000), index_rand in usize::ANY) { + let index = vec[index_rand % vec.len()].0; + let map1: OrdMap = OrdMap::from_iter(vec.clone()); + let map2 = map1.without(&index); + assert_eq!(map1.len(), map2.len() + 1); + for k in map2.keys() { + assert_ne!(*k, index); + } + } + + #[test] + fn insert_and_delete_values( + ref input in ord_map(0usize..64, 0usize..64, 1..1000), + ref ops in collection::vec((bool::ANY, usize::ANY, usize::ANY), 1..1000) + ) { + let mut map = input.clone(); + let mut tree: collections::BTreeMap = input.iter().cloned().collect(); + for (ins, key, val) in ops { + if *ins { + tree.insert(*key, *val); + map = map.update(*key, *val) + } else { + tree.remove(key); + map = map.without(key) + } + } + assert!(map.iter().map(|(k, v)| (*k, *v)).eq(tree.iter().map(|(k, v)| (*k, *v)))); + } + + #[test] + fn proptest_works(ref m in ord_map(0..9999, ".*", 10..100)) { + assert!(m.len() < 100); + assert!(m.len() >= 10); + } + + #[test] + fn insert_and_length(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let mut map: OrdMap = OrdMap::new(); + for (k, v) in m.iter() { + map = map.update(*k, *v) + } + assert_eq!(m.len(), map.len()); + } + + #[test] + fn from_iterator(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let map: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(m.len(), map.len()); + } + + #[test] + fn iterate_over(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let map: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(m.len(), map.iter().count()); + } + + #[test] + fn equality(ref m in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let map1: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + let map2: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + assert_eq!(map1, map2); + } + + #[test] + fn lookup(ref m in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let map: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + for (k, v) in m { + assert_eq!(Some(*v), map.get(k).cloned()); + } + } + + #[test] + fn remove(ref m in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let mut map: OrdMap = + FromIterator::from_iter(m.iter().map(|(k, v)| (*k, *v))); + for k in m.keys() { + let l = map.len(); + assert_eq!(m.get(k).cloned(), map.get(k).cloned()); + map = map.without(k); + assert_eq!(None, map.get(k)); + assert_eq!(l - 1, map.len()); + } + } + + #[test] + fn insert_mut(ref m in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let mut mut_map = OrdMap::new(); + let mut map = OrdMap::new(); + for (k, v) in m.iter() { + map = map.update(*k, *v); + mut_map.insert(*k, *v); + } + assert_eq!(map, mut_map); + } + + #[test] + fn remove_mut(ref orig in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let mut map = orig.clone(); + for key in orig.keys() { + let len = map.len(); + assert_eq!(orig.get(key), map.get(key)); + assert_eq!(orig.get(key).cloned(), map.remove(key)); + assert_eq!(None, map.get(key)); + assert_eq!(len - 1, map.len()); + } + } + + #[test] + fn remove_alien(ref orig in collection::hash_map(i16::ANY, i16::ANY, 0..1000)) { + let mut map = OrdMap::::from(orig.clone()); + for key in orig.keys() { + let len = map.len(); + assert_eq!(orig.get(key), map.get(key)); + assert_eq!(orig.get(key).cloned(), map.remove(key)); + assert_eq!(None, map.get(key)); + assert_eq!(len - 1, map.len()); + } + } + + #[test] + fn delete_and_reinsert( + ref input in collection::hash_map(i16::ANY, i16::ANY, 1..1000), + index_rand in usize::ANY + ) { + let index = *input.keys().nth(index_rand % input.len()).unwrap(); + let map1 = OrdMap::from_iter(input.clone()); + let (val, map2): (i16, _) = map1.extract(&index).unwrap(); + let map3 = map2.update(index, val); + for key in map2.keys() { + assert!(*key != index); + } + assert_eq!(map1.len(), map2.len() + 1); + assert_eq!(map1, map3); + } + + #[test] + fn exact_size_iterator(ref m in ord_map(i16::ANY, i16::ANY, 1..1000)) { + let mut should_be = m.len(); + let mut it = m.iter(); + loop { + assert_eq!(should_be, it.len()); + match it.next() { + None => break, + Some(_) => should_be -= 1, + } + } + assert_eq!(0, it.len()); + } + + #[test] + fn diff_added_values(a in ord_map(i16::ANY, i16::ANY, 0..1000), b in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let ab = a.clone().union(b.clone()); + assert!(a.diff(&ab).eq(b.iter().filter(|&(ref k, _)| !a.contains_key(k)).map(DiffItem::Add))); + } + + // fn diff_updated_values(a: Vec<(usize, usize)>, b: Vec<(usize, usize)>) -> bool { + // let a: OrdMap = OrdMap::from(a); + // let b: OrdMap = OrdMap::from(b); + // let ab: OrdMap = a.union(&b); + // let ba: OrdMap = ab.union_with(&b, |_, b| *b); + // ab.diff(&ba).eq(b.iter().filter(|&(ref k, ref v)| ab.get(k) != Some(&v)) + // .map(|(k, v)| DiffItem::Update { + // old: &(*k, *(ab.get(&k).unwrap())), + // new: &(*k, *v) + // })) + // } + + #[test] + fn diff_removed_values(a in ord_map(i16::ANY, i16::ANY, 0..1000), b in ord_map(i16::ANY, i16::ANY, 0..1000)) { + let ab = a.clone().union(b.clone()); + assert!(ab.diff(&a).eq(b.iter().filter(|&(ref k, _)| !a.contains_key(k)).map(DiffItem::Remove))); + } + + // fn diff_all_values(a: Vec<(usize, usize)>, b: Vec<(usize, usize)>) -> bool { + // let a: OrdMap = OrdMap::from(a); + // let b: OrdMap = OrdMap::from(b); + // a.diff(&b).eq(b.union(&a).iter().filter_map(|(k, v)| { + // if a.contains_key(&k) { + // if b.contains_key(&k) { + // let old = a.get(&k).unwrap(); + // if old != v { + // Some(DiffItem::Update { + // old: &(*k, *old), + // new: &(*k, *v), + // }) + // } else { + // None + // } + // } else { + // Some(DiffItem::Remove(&(*k, *v))) + // } + // } else { + // Some(DiffItem::Add(&(*k, *v))) + // } + // })) + // } + } +} diff --git a/im-rc/src/ord/mod.rs b/im-rc/src/ord/mod.rs new file mode 100644 index 000000000..27a56a5e2 --- /dev/null +++ b/im-rc/src/ord/mod.rs @@ -0,0 +1,8 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#[macro_use] +pub mod map; +#[macro_use] +pub mod set; diff --git a/im-rc/src/ord/set.rs b/im-rc/src/ord/set.rs new file mode 100644 index 000000000..0084dba23 --- /dev/null +++ b/im-rc/src/ord/set.rs @@ -0,0 +1,1160 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! An ordered set. +//! +//! An immutable ordered set implemented as a [B-tree] [1]. +//! +//! Most operations on this type of set are O(log n). A +//! [`HashSet`][hashset::HashSet] is usually a better choice for +//! performance, but the `OrdSet` has the advantage of only requiring +//! an [`Ord`][std::cmp::Ord] constraint on its values, and of being +//! ordered, so values always come out from lowest to highest, where a +//! [`HashSet`][hashset::HashSet] has no guaranteed ordering. +//! +//! [1]: https://en.wikipedia.org/wiki/B-tree +//! [hashset::HashSet]: ../hashset/struct.HashSet.html +//! [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::collections; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{BuildHasher, Hash, Hasher}; +use std::iter::{FromIterator, IntoIterator, Sum}; +use std::ops::{Add, Deref, Mul, RangeBounds}; + +use crate::hashset::HashSet; +use crate::nodes::btree::{ + BTreeValue, ConsumingIter as ConsumingNodeIter, DiffIter as NodeDiffIter, Insert, + Iter as NodeIter, Node, Remove, +}; +#[cfg(has_specialisation)] +use crate::util::linear_search_by; +use crate::util::Ref; + +pub use crate::nodes::btree::DiffItem; + +/// Construct a set from a sequence of values. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::ordset::OrdSet; +/// # fn main() { +/// assert_eq!( +/// ordset![1, 2, 3], +/// OrdSet::from(vec![1, 2, 3]) +/// ); +/// # } +/// ``` +#[macro_export] +macro_rules! ordset { + () => { $crate::ordset::OrdSet::new() }; + + ( $($x:expr),* ) => {{ + let mut l = $crate::ordset::OrdSet::new(); + $( + l.insert($x); + )* + l + }}; +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct Value(A); + +impl Deref for Value { + type Target = A; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// FIXME lacking specialisation, we can't simply implement `BTreeValue` +// for `A`, we have to use the `Value` indirection. +#[cfg(not(has_specialisation))] +impl BTreeValue for Value { + type Key = A; + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } + + fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + slice.binary_search_by(|value| Self::Key::borrow(value).cmp(key)) + } + + fn search_value(slice: &[Self], key: &Self) -> Result { + slice.binary_search_by(|value| value.cmp(key)) + } + + fn cmp_keys(&self, other: &BK) -> Ordering + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + Self::Key::borrow(self).cmp(other) + } + + fn cmp_values(&self, other: &Self) -> Ordering { + self.cmp(other) + } +} + +#[cfg(has_specialisation)] +impl BTreeValue for Value { + type Key = A; + + fn ptr_eq(&self, _other: &Self) -> bool { + false + } + + default fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + slice.binary_search_by(|value| Self::Key::borrow(value).cmp(key)) + } + + default fn search_value(slice: &[Self], key: &Self) -> Result { + slice.binary_search_by(|value| value.cmp(key)) + } + + fn cmp_keys(&self, other: &BK) -> Ordering + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + Self::Key::borrow(self).cmp(other) + } + + fn cmp_values(&self, other: &Self) -> Ordering { + self.cmp(other) + } +} + +#[cfg(has_specialisation)] +impl BTreeValue for Value { + fn search_key(slice: &[Self], key: &BK) -> Result + where + BK: Ord + ?Sized, + Self::Key: Borrow, + { + linear_search_by(slice, |value| Self::Key::borrow(value).cmp(key)) + } + + fn search_value(slice: &[Self], key: &Self) -> Result { + linear_search_by(slice, |value| value.cmp(key)) + } +} + +/// An ordered set. +/// +/// An immutable ordered set implemented as a [B-tree] [1]. +/// +/// Most operations on this type of set are O(log n). A +/// [`HashSet`][hashset::HashSet] is usually a better choice for +/// performance, but the `OrdSet` has the advantage of only requiring +/// an [`Ord`][std::cmp::Ord] constraint on its values, and of being +/// ordered, so values always come out from lowest to highest, where a +/// [`HashSet`][hashset::HashSet] has no guaranteed ordering. +/// +/// [1]: https://en.wikipedia.org/wiki/B-tree +/// [hashset::HashSet]: ../hashset/struct.HashSet.html +/// [std::cmp::Ord]: https://doc.rust-lang.org/std/cmp/trait.Ord.html +pub struct OrdSet { + size: usize, + root: Ref>>, +} + +impl OrdSet { + /// Construct an empty set. + #[must_use] + pub fn new() -> Self { + OrdSet { + size: 0, + root: Ref::from(Node::new()), + } + } + + /// Construct a set with a single value. + /// + /// This method has been deprecated; use [`unit`][unit] instead. + /// + /// [unit]: #method.unit + #[inline] + #[must_use] + #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")] + pub fn singleton(a: A) -> Self { + Self::unit(a) + } + + /// Construct a set with a single value. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let set = OrdSet::unit(123); + /// assert!(set.contains(&123)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn unit(a: A) -> Self { + OrdSet { + size: 1, + root: Ref::from(Node::unit(Value(a))), + } + } + + /// Test whether a set is empty. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// assert!( + /// !ordset![1, 2, 3].is_empty() + /// ); + /// assert!( + /// OrdSet::::new().is_empty() + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get the size of a set. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// assert_eq!(3, ordset![1, 2, 3].len()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.size + } + + /// Discard all elements from the set. + /// + /// This leaves you with an empty set, and all elements that + /// were previously inside it are dropped. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::OrdSet; + /// # fn main() { + /// let mut set = ordset![1, 2, 3]; + /// set.clear(); + /// assert!(set.is_empty()); + /// # } + /// ``` + pub fn clear(&mut self) { + if !self.is_empty() { + self.root = Default::default(); + self.size = 0; + } + } +} + +impl OrdSet +where + A: Ord, +{ + /// Get the smallest value in a set. + /// + /// If the set is empty, returns `None`. + #[must_use] + pub fn get_min(&self) -> Option<&A> { + self.root.min().map(Deref::deref) + } + + /// Get the largest value in a set. + /// + /// If the set is empty, returns `None`. + #[must_use] + pub fn get_max(&self) -> Option<&A> { + self.root.max().map(Deref::deref) + } + + // Create an iterator over the contents of the set. + #[must_use] + pub fn iter(&self) -> Iter { + Iter { + it: NodeIter::new(&self.root, self.size, ..), + } + } + + // Create an iterator over a range inside the set. + #[must_use] + pub fn range(&self, range: R) -> RangedIter + where + R: RangeBounds, + A: Borrow, + BA: Ord + ?Sized, + { + RangedIter { + it: NodeIter::new(&self.root, self.size, range), + } + } + + /// Get an iterator over the differences between this set and + /// another, i.e. the set of entries to add or remove to this set + /// in order to make it equal to the other set. + /// + /// This function will avoid visiting nodes which are shared + /// between the two sets, meaning that even very large sets can be + /// compared quickly if most of their structure is shared. + /// + /// Time: O(n) (where n is the number of unique elements across + /// the two sets, minus the number of elements belonging to nodes + /// shared between them) + #[must_use] + pub fn diff<'a>(&'a self, other: &'a Self) -> DiffIter { + DiffIter { + it: NodeDiffIter::new(&self.root, &other.root), + } + } + + /// Test if a value is part of a set. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let mut set = ordset!{1, 2, 3}; + /// assert!(set.contains(&1)); + /// assert!(!set.contains(&4)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn contains(&self, a: &BA) -> bool + where + BA: Ord + ?Sized, + A: Borrow, + { + self.root.lookup(a).is_some() + } + + /// Test whether a set is a subset of another set, meaning that + /// all values in our set must also be in the other set. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_subset(&self, other: RS) -> bool + where + RS: Borrow, + { + let o = other.borrow(); + self.iter().all(|a| o.contains(&a)) + } + + /// Test whether a set is a proper subset of another set, meaning + /// that all values in our set must also be in the other set. A + /// proper subset must also be smaller than the other set. + /// + /// Time: O(n log n) + #[must_use] + pub fn is_proper_subset(&self, other: RS) -> bool + where + RS: Borrow, + { + self.len() != other.borrow().len() && self.is_subset(other) + } +} + +impl OrdSet +where + A: Ord + Clone, +{ + /// Insert a value into a set. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let mut set = ordset!{}; + /// set.insert(123); + /// set.insert(456); + /// assert_eq!( + /// set, + /// ordset![123, 456] + /// ); + /// # } + /// ``` + #[inline] + pub fn insert(&mut self, a: A) -> Option { + let new_root = { + let root = Ref::make_mut(&mut self.root); + match root.insert(Value(a)) { + Insert::Replaced(Value(old_value)) => return Some(old_value), + Insert::Added => { + self.size += 1; + return None; + } + Insert::Update(root) => Ref::from(root), + Insert::Split(left, median, right) => { + Ref::from(Node::from_split(left, median, right)) + } + } + }; + self.size += 1; + self.root = new_root; + None + } + + /// Remove a value from a set. + /// + /// Time: O(log n) + #[inline] + pub fn remove(&mut self, a: &BA) -> Option + where + BA: Ord + ?Sized, + A: Borrow, + { + let (new_root, removed_value) = { + let root = Ref::make_mut(&mut self.root); + match root.remove(a) { + Remove::Update(value, root) => (Ref::from(root), Some(value.0)), + Remove::Removed(value) => { + self.size -= 1; + return Some(value.0); + } + Remove::NoChange => return None, + } + }; + self.size -= 1; + self.root = new_root; + removed_value + } + + /// Remove the smallest value from a set. + /// + /// Time: O(log n) + pub fn remove_min(&mut self) -> Option { + // FIXME implement this at the node level for better efficiency + let key = match self.get_min() { + None => return None, + Some(v) => v, + } + .clone(); + self.remove(&key) + } + + /// Remove the largest value from a set. + /// + /// Time: O(log n) + pub fn remove_max(&mut self) -> Option { + // FIXME implement this at the node level for better efficiency + let key = match self.get_max() { + None => return None, + Some(v) => v, + } + .clone(); + self.remove(&key) + } + + /// Construct a new set from the current set with the given value + /// added. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let set = ordset![456]; + /// assert_eq!( + /// set.update(123), + /// ordset![123, 456] + /// ); + /// # } + /// ``` + #[must_use] + pub fn update(&self, a: A) -> Self { + let mut out = self.clone(); + out.insert(a); + out + } + + /// Construct a new set with the given value removed if it's in + /// the set. + /// + /// Time: O(log n) + #[must_use] + pub fn without(&self, a: &BA) -> Self + where + BA: Ord + ?Sized, + A: Borrow, + { + let mut out = self.clone(); + out.remove(a); + out + } + + /// Remove the smallest value from a set, and return that value as + /// well as the updated set. + /// + /// Time: O(log n) + #[must_use] + pub fn without_min(&self) -> (Option, Self) { + match self.get_min() { + Some(v) => (Some(v.clone()), self.without(&v)), + None => (None, self.clone()), + } + } + + /// Remove the largest value from a set, and return that value as + /// well as the updated set. + /// + /// Time: O(log n) + #[must_use] + pub fn without_max(&self) -> (Option, Self) { + match self.get_max() { + Some(v) => (Some(v.clone()), self.without(&v)), + None => (None, self.clone()), + } + } + + /// Construct the union of two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let set1 = ordset!{1, 2}; + /// let set2 = ordset!{2, 3}; + /// let expected = ordset!{1, 2, 3}; + /// assert_eq!(expected, set1.union(set2)); + /// # } + /// ``` + #[must_use] + pub fn union(mut self, other: Self) -> Self { + for value in other { + self.insert(value); + } + self + } + + /// Construct the union of multiple sets. + /// + /// Time: O(n log n) + #[must_use] + pub fn unions(i: I) -> Self + where + I: IntoIterator, + { + i.into_iter().fold(Self::default(), Self::union) + } + + /// Construct the difference between two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let set1 = ordset!{1, 2}; + /// let set2 = ordset!{2, 3}; + /// let expected = ordset!{1, 3}; + /// assert_eq!(expected, set1.difference(set2)); + /// # } + /// ``` + #[must_use] + pub fn difference(mut self, other: Self) -> Self { + for value in other { + if self.remove(&value).is_none() { + self.insert(value); + } + } + self + } + + /// Construct the intersection of two sets. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::ordset::OrdSet; + /// # fn main() { + /// let set1 = ordset!{1, 2}; + /// let set2 = ordset!{2, 3}; + /// let expected = ordset!{2}; + /// assert_eq!(expected, set1.intersection(set2)); + /// # } + /// ``` + #[must_use] + pub fn intersection(self, other: Self) -> Self { + let mut out = Self::default(); + for value in other { + if self.contains(&value) { + out.insert(value); + } + } + out + } + + /// Split a set into two, with the left hand set containing values + /// which are smaller than `split`, and the right hand set + /// containing values which are larger than `split`. + /// + /// The `split` value itself is discarded. + /// + /// Time: O(n) + #[must_use] + pub fn split(self, split: &BA) -> (Self, Self) + where + BA: Ord + ?Sized, + A: Borrow, + { + let (left, _, right) = self.split_member(split); + (left, right) + } + + /// Split a set into two, with the left hand set containing values + /// which are smaller than `split`, and the right hand set + /// containing values which are larger than `split`. + /// + /// Returns a tuple of the two sets and a boolean which is true if + /// the `split` value existed in the original set, and false + /// otherwise. + /// + /// Time: O(n) + #[must_use] + pub fn split_member(self, split: &BA) -> (Self, bool, Self) + where + BA: Ord + ?Sized, + A: Borrow, + { + let mut left = Self::default(); + let mut right = Self::default(); + let mut present = false; + for value in self { + match value.borrow().cmp(split) { + Ordering::Less => { + left.insert(value); + } + Ordering::Equal => { + present = true; + } + Ordering::Greater => { + right.insert(value); + } + } + } + (left, present, right) + } + + /// Construct a set with only the `n` smallest values from a given + /// set. + /// + /// Time: O(n) + #[must_use] + pub fn take(&self, n: usize) -> Self { + self.iter().take(n).cloned().collect() + } + + /// Construct a set with the `n` smallest values removed from a + /// given set. + /// + /// Time: O(n) + #[must_use] + pub fn skip(&self, n: usize) -> Self { + self.iter().skip(n).cloned().collect() + } +} + +// Core traits + +impl Clone for OrdSet { + fn clone(&self) -> Self { + OrdSet { + size: self.size, + root: self.root.clone(), + } + } +} + +impl PartialEq for OrdSet { + fn eq(&self, other: &Self) -> bool { + Ref::ptr_eq(&self.root, &other.root) + || (self.len() == other.len() && self.diff(other).next().is_none()) + } +} + +impl Eq for OrdSet {} + +impl PartialOrd for OrdSet { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +impl Ord for OrdSet { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl Hash for OrdSet { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + for i in self.iter() { + i.hash(state); + } + } +} + +impl Default for OrdSet { + fn default() -> Self { + OrdSet::new() + } +} + +impl Add for OrdSet { + type Output = OrdSet; + + fn add(self, other: Self) -> Self::Output { + self.union(other) + } +} + +impl<'a, A: Ord + Clone> Add for &'a OrdSet { + type Output = OrdSet; + + fn add(self, other: Self) -> Self::Output { + self.clone().union(other.clone()) + } +} + +impl Mul for OrdSet { + type Output = OrdSet; + + fn mul(self, other: Self) -> Self::Output { + self.intersection(other) + } +} + +impl<'a, A: Ord + Clone> Mul for &'a OrdSet { + type Output = OrdSet; + + fn mul(self, other: Self) -> Self::Output { + self.clone().intersection(other.clone()) + } +} + +impl Sum for OrdSet { + fn sum(it: I) -> Self + where + I: Iterator, + { + it.fold(Self::new(), |a, b| a + b) + } +} + +impl Extend for OrdSet +where + A: Ord + Clone + From, +{ + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for value in iter { + self.insert(From::from(value)); + } + } +} + +impl Debug for OrdSet { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_set().entries(self.iter()).finish() + } +} + +// Iterators + +// An iterator over the elements of a set. +pub struct Iter<'a, A> +where + A: 'a, +{ + it: NodeIter<'a, Value>, +} + +impl<'a, A> Iterator for Iter<'a, A> +where + A: 'a + Ord, +{ + type Item = &'a A; + + fn next(&mut self) -> Option { + self.it.next().map(Deref::deref) + } + + fn size_hint(&self) -> (usize, Option) { + (self.it.remaining, Some(self.it.remaining)) + } +} + +impl<'a, A> DoubleEndedIterator for Iter<'a, A> +where + A: 'a + Ord, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().map(Deref::deref) + } +} + +impl<'a, A> ExactSizeIterator for Iter<'a, A> where A: 'a + Ord {} + +// A ranged iterator over the elements of a set. +// +// The only difference from `Iter` is that this one doesn't implement +// `ExactSizeIterator` because we can't know the size of the range without first +// iterating over it to count. +pub struct RangedIter<'a, A> +where + A: 'a, +{ + it: NodeIter<'a, Value>, +} + +impl<'a, A> Iterator for RangedIter<'a, A> +where + A: 'a + Ord, +{ + type Item = &'a A; + + fn next(&mut self) -> Option { + self.it.next().map(Deref::deref) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} + +impl<'a, A> DoubleEndedIterator for RangedIter<'a, A> +where + A: 'a + Ord, +{ + fn next_back(&mut self) -> Option { + self.it.next_back().map(Deref::deref) + } +} + +// A consuming iterator over the elements of a set. +pub struct ConsumingIter { + it: ConsumingNodeIter>, +} + +impl Iterator for ConsumingIter +where + A: Ord + Clone, +{ + type Item = A; + + fn next(&mut self) -> Option { + self.it.next().map(|v| v.0) + } +} + +// An iterator over the difference between two sets. +pub struct DiffIter<'a, A: 'a> { + it: NodeDiffIter<'a, Value>, +} + +impl<'a, A> Iterator for DiffIter<'a, A> +where + A: 'a + Ord + PartialEq, +{ + type Item = DiffItem<'a, A>; + + fn next(&mut self) -> Option { + self.it.next().map(|item| match item { + DiffItem::Add(v) => DiffItem::Add(v.deref()), + DiffItem::Update { old, new } => DiffItem::Update { + old: old.deref(), + new: new.deref(), + }, + DiffItem::Remove(v) => DiffItem::Remove(v.deref()), + }) + } +} + +impl FromIterator for OrdSet +where + A: Ord + Clone + From, +{ + fn from_iter(i: T) -> Self + where + T: IntoIterator, + { + let mut out = Self::new(); + for item in i { + out.insert(From::from(item)); + } + out + } +} + +impl<'a, A> IntoIterator for &'a OrdSet +where + A: 'a + Ord, +{ + type Item = &'a A; + type IntoIter = Iter<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for OrdSet +where + A: Ord + Clone, +{ + type Item = A; + type IntoIter = ConsumingIter; + + fn into_iter(self) -> Self::IntoIter { + ConsumingIter { + it: ConsumingNodeIter::new(&self.root, self.size), + } + } +} + +// Conversions + +impl<'s, 'a, A, OA> From<&'s OrdSet<&'a A>> for OrdSet +where + A: ToOwned + Ord + ?Sized, + OA: Borrow + Ord + Clone, +{ + fn from(set: &OrdSet<&A>) -> Self { + set.iter().map(|a| (*a).to_owned()).collect() + } +} + +impl<'a, A> From<&'a [A]> for OrdSet +where + A: Ord + Clone, +{ + fn from(slice: &'a [A]) -> Self { + slice.iter().cloned().collect() + } +} + +impl From> for OrdSet { + fn from(vec: Vec) -> Self { + vec.into_iter().collect() + } +} + +impl<'a, A: Ord + Clone> From<&'a Vec> for OrdSet { + fn from(vec: &Vec) -> Self { + vec.iter().cloned().collect() + } +} + +impl From> for OrdSet { + fn from(hash_set: collections::HashSet) -> Self { + hash_set.into_iter().collect() + } +} + +impl<'a, A: Eq + Hash + Ord + Clone> From<&'a collections::HashSet> for OrdSet { + fn from(hash_set: &collections::HashSet) -> Self { + hash_set.iter().cloned().collect() + } +} + +impl From> for OrdSet { + fn from(btree_set: collections::BTreeSet) -> Self { + btree_set.into_iter().collect() + } +} + +impl<'a, A: Ord + Clone> From<&'a collections::BTreeSet> for OrdSet { + fn from(btree_set: &collections::BTreeSet) -> Self { + btree_set.iter().cloned().collect() + } +} + +impl From> for OrdSet { + fn from(hashset: HashSet) -> Self { + hashset.into_iter().collect() + } +} + +impl<'a, A: Hash + Eq + Ord + Clone, S: BuildHasher> From<&'a HashSet> for OrdSet { + fn from(hashset: &HashSet) -> Self { + hashset.into_iter().cloned().collect() + } +} + +// QuickCheck + +#[cfg(all(threadsafe, feature = "quickcheck"))] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(all(threadsafe, feature = "quickcheck"))] +impl Arbitrary for OrdSet { + fn arbitrary(g: &mut G) -> Self { + OrdSet::from_iter(Vec::::arbitrary(g)) + } +} + +// Proptest + +#[cfg(any(test, feature = "proptest"))] +pub mod proptest { + use super::*; + use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; + use std::ops::Range; + + /// A strategy for a set of a given size. + /// + /// # Examples + /// + /// ```rust,ignore + /// proptest! { + /// #[test] + /// fn proptest_a_set(ref s in set(".*", 10..100)) { + /// assert!(s.len() < 100); + /// assert!(s.len() >= 10); + /// } + /// } + /// ``` + pub fn ord_set( + element: A, + size: Range, + ) -> BoxedStrategy::Value>> + where + ::Value: Ord + Clone, + { + ::proptest::collection::vec(element, size.clone()) + .prop_map(OrdSet::from) + .prop_filter("OrdSet minimum size".to_owned(), move |s| { + s.len() >= size.start + }) + .boxed() + } +} + +#[cfg(test)] +mod test { + use super::proptest::*; + use super::*; + use ::proptest::proptest; + + #[test] + fn match_strings_with_string_slices() { + let mut set: OrdSet = From::from(&ordset!["foo", "bar"]); + set = set.without("bar"); + assert!(!set.contains("bar")); + set.remove("foo"); + assert!(!set.contains("foo")); + } + + #[test] + fn ranged_iter() { + let set: OrdSet = ordset![1, 2, 3, 4, 5]; + let range: Vec = set.range(..).cloned().collect(); + assert_eq!(vec![1, 2, 3, 4, 5], range); + let range: Vec = set.range(..).rev().cloned().collect(); + assert_eq!(vec![5, 4, 3, 2, 1], range); + let range: Vec = set.range(2..5).cloned().collect(); + assert_eq!(vec![2, 3, 4], range); + let range: Vec = set.range(2..5).rev().cloned().collect(); + assert_eq!(vec![4, 3, 2], range); + let range: Vec = set.range(3..).cloned().collect(); + assert_eq!(vec![3, 4, 5], range); + let range: Vec = set.range(3..).rev().cloned().collect(); + assert_eq!(vec![5, 4, 3], range); + let range: Vec = set.range(..4).cloned().collect(); + assert_eq!(vec![1, 2, 3], range); + let range: Vec = set.range(..4).rev().cloned().collect(); + assert_eq!(vec![3, 2, 1], range); + let range: Vec = set.range(..=3).cloned().collect(); + assert_eq!(vec![1, 2, 3], range); + let range: Vec = set.range(..=3).rev().cloned().collect(); + assert_eq!(vec![3, 2, 1], range); + } + + proptest! { + #[test] + fn proptest_a_set(ref s in ord_set(".*", 10..100)) { + assert!(s.len() < 100); + assert!(s.len() >= 10); + } + + #[test] + fn long_ranged_iter(max in 1..1000) { + let range = 0..max; + let expected: Vec = range.clone().collect(); + let set: OrdSet = OrdSet::from_iter(range.clone()); + let result: Vec = set.range(..).cloned().collect(); + assert_eq!(expected, result); + + let expected: Vec = range.clone().rev().collect(); + let set: OrdSet = OrdSet::from_iter(range); + let result: Vec = set.range(..).rev().cloned().collect(); + assert_eq!(expected, result); + } + } +} diff --git a/im-rc/src/ser.rs b/im-rc/src/ser.rs new file mode 100644 index 000000000..9f635dd52 --- /dev/null +++ b/im-rc/src/ser.rs @@ -0,0 +1,297 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use serde::de::{Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; +use std::fmt; +use std::hash::{BuildHasher, Hash}; +use std::marker::PhantomData; +use std::ops::Deref; + +use crate::hashmap::HashMap; +use crate::hashset::HashSet; +use crate::ordmap::OrdMap; +use crate::ordset::OrdSet; +use crate::vector::Vector; + +struct SeqVisitor<'de, S, A> +where + S: From>, + A: Deserialize<'de>, +{ + phantom_s: PhantomData, + phantom_a: PhantomData, + phantom_lifetime: PhantomData<&'de ()>, +} + +impl<'de, S, A> SeqVisitor<'de, S, A> +where + S: From>, + A: Deserialize<'de>, +{ + pub fn new() -> SeqVisitor<'de, S, A> { + SeqVisitor { + phantom_s: PhantomData, + phantom_a: PhantomData, + phantom_lifetime: PhantomData, + } + } +} + +impl<'de, S, A> Visitor<'de> for SeqVisitor<'de, S, A> +where + S: From>, + A: Deserialize<'de>, +{ + type Value = S; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut access: Access) -> Result + where + Access: SeqAccess<'de>, + { + let mut v: Vec = match access.size_hint() { + None => Vec::new(), + Some(l) => Vec::with_capacity(l), + }; + while let Some(i) = access.next_element()? { + v.push(i) + } + Ok(From::from(v)) + } +} + +struct MapVisitor<'de, S, K, V> +where + S: From>, + K: Deserialize<'de>, + V: Deserialize<'de>, +{ + phantom_s: PhantomData, + phantom_k: PhantomData, + phantom_v: PhantomData, + phantom_lifetime: PhantomData<&'de ()>, +} + +impl<'de, S, K, V> MapVisitor<'de, S, K, V> +where + S: From>, + K: Deserialize<'de>, + V: Deserialize<'de>, +{ + pub fn new() -> MapVisitor<'de, S, K, V> { + MapVisitor { + phantom_s: PhantomData, + phantom_k: PhantomData, + phantom_v: PhantomData, + phantom_lifetime: PhantomData, + } + } +} + +impl<'de, S, K, V> Visitor<'de> for MapVisitor<'de, S, K, V> +where + S: From>, + K: Deserialize<'de>, + V: Deserialize<'de>, +{ + type Value = S; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_map(self, mut access: Access) -> Result + where + Access: MapAccess<'de>, + { + let mut v: Vec<(K, V)> = match access.size_hint() { + None => Vec::new(), + Some(l) => Vec::with_capacity(l), + }; + while let Some(i) = access.next_entry()? { + v.push(i) + } + Ok(From::from(v)) + } +} + +// Set + +impl<'de, A: Deserialize<'de> + Ord + Clone> Deserialize<'de> for OrdSet { + fn deserialize(des: D) -> Result + where + D: Deserializer<'de>, + { + des.deserialize_seq(SeqVisitor::new()) + } +} + +impl Serialize for OrdSet { + fn serialize(&self, ser: S) -> Result + where + S: Serializer, + { + let mut s = ser.serialize_seq(Some(self.len()))?; + for i in self.iter() { + s.serialize_element(i.deref())?; + } + s.end() + } +} + +// Map + +impl<'de, K: Deserialize<'de> + Ord + Clone, V: Deserialize<'de> + Clone> Deserialize<'de> + for OrdMap +{ + fn deserialize(des: D) -> Result + where + D: Deserializer<'de>, + { + des.deserialize_map(MapVisitor::<'de, OrdMap, K, V>::new()) + } +} + +impl Serialize for OrdMap { + fn serialize(&self, ser: S) -> Result + where + S: Serializer, + { + let mut s = ser.serialize_map(Some(self.len()))?; + for (k, v) in self.iter() { + s.serialize_entry(k.deref(), v.deref())?; + } + s.end() + } +} + +// HashMap + +impl<'de, K, V, S> Deserialize<'de> for HashMap +where + K: Deserialize<'de> + Hash + Eq + Clone, + V: Deserialize<'de> + Clone, + S: BuildHasher + Default, +{ + fn deserialize(des: D) -> Result + where + D: Deserializer<'de>, + { + des.deserialize_map(MapVisitor::<'de, HashMap, K, V>::new()) + } +} + +impl Serialize for HashMap +where + K: Serialize + Hash + Eq + Clone, + V: Serialize + Clone, + S: BuildHasher + Default, +{ + fn serialize(&self, ser: Ser) -> Result + where + Ser: Serializer, + { + let mut s = ser.serialize_map(Some(self.len()))?; + for (k, v) in self.iter() { + s.serialize_entry(k.deref(), v.deref())?; + } + s.end() + } +} + +// HashSet + +impl<'de, A: Deserialize<'de> + Hash + Eq + Clone, S: BuildHasher + Default> Deserialize<'de> + for HashSet +{ + fn deserialize(des: D) -> Result + where + D: Deserializer<'de>, + { + des.deserialize_seq(SeqVisitor::new()) + } +} + +impl Serialize for HashSet { + fn serialize(&self, ser: Ser) -> Result + where + Ser: Serializer, + { + let mut s = ser.serialize_seq(Some(self.len()))?; + for i in self.iter() { + s.serialize_element(i.deref())?; + } + s.end() + } +} + +// Vector + +impl<'de, A: Clone + Deserialize<'de>> Deserialize<'de> for Vector { + fn deserialize(des: D) -> Result + where + D: Deserializer<'de>, + { + des.deserialize_seq(SeqVisitor::<'de, Vector, A>::new()) + } +} + +impl Serialize for Vector { + fn serialize(&self, ser: S) -> Result + where + S: Serializer, + { + let mut s = ser.serialize_seq(Some(self.len()))?; + for i in self.iter() { + s.serialize_element(i.deref())?; + } + s.end() + } +} + +// Tests + +#[cfg(test)] +mod test { + use super::*; + use crate::hashmap::proptest::hash_map; + use crate::hashset::proptest::hash_set; + use crate::ordmap::proptest::ord_map; + use crate::ordset::proptest::ord_set; + use crate::vector::proptest::vector; + use ::proptest::num::i32; + use ::proptest::proptest; + use serde_json::{from_str, to_string}; + + proptest! { + #[test] + fn ser_ordset(ref v in ord_set(i32::ANY, 0..100)) { + assert_eq!(v, &from_str::>(&to_string(&v).unwrap()).unwrap()); + } + + #[test] + fn ser_ordmap(ref v in ord_map(i32::ANY, i32::ANY, 0..100)) { + assert_eq!(v, &from_str::>(&to_string(&v).unwrap()).unwrap()); + } + + #[test] + fn ser_hashmap(ref v in hash_map(i32::ANY, i32::ANY, 0..100)) { + assert_eq!(v, &from_str::>(&to_string(&v).unwrap()).unwrap()); + } + + #[test] + fn ser_hashset(ref v in hash_set(i32::ANY, 0..100)) { + assert_eq!(v, &from_str::>(&to_string(&v).unwrap()).unwrap()); + } + + #[test] + fn ser_vector(ref v in vector(i32::ANY, 0..100)) { + assert_eq!(v, &from_str::>(&to_string(&v).unwrap()).unwrap()); + } + } +} diff --git a/im-rc/src/sort.rs b/im-rc/src/sort.rs new file mode 100644 index 000000000..1bb7d4cf5 --- /dev/null +++ b/im-rc/src/sort.rs @@ -0,0 +1,92 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use crate::vector::FocusMut; +use std::cmp::Ordering; + +// Ported from the Java version at: +// http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf +// Should be O(n) to O(n log n) +pub fn quicksort(vector: &mut FocusMut, left: usize, right: usize, cmp: &F) +where + A: Clone, + F: Fn(&A, &A) -> Ordering, +{ + if right <= left { + return; + } + + let l = left as isize; + let r = right as isize; + let mut l1 = l; + let mut r1 = r; + let mut l2 = l - 1; + let mut r2 = r; + loop { + while l1 != r && vector.pair(l1 as usize, r as usize, |a, b| cmp(a, b)) == Ordering::Less { + l1 += 1; + } + r1 -= 1; + while r1 != r && vector.pair(r as usize, r1 as usize, |a, b| cmp(a, b)) == Ordering::Less { + if r1 == l { + break; + } + r1 -= 1; + } + if l1 >= r1 { + break; + } + vector.swap(l1 as usize, r1 as usize); + if l1 != r && vector.pair(l1 as usize, r as usize, |a, b| cmp(a, b)) == Ordering::Equal { + l2 += 1; + vector.swap(l2 as usize, l1 as usize); + } + if r1 != r && vector.pair(r as usize, r1 as usize, |a, b| cmp(a, b)) == Ordering::Equal { + r2 -= 1; + vector.swap(r1 as usize, r2 as usize); + } + } + vector.swap(l1 as usize, r as usize); + + r1 = l1 - 1; + l1 += 1; + let mut k = l; + while k < l2 { + vector.swap(k as usize, r1 as usize); + r1 -= 1; + k += 1; + } + k = r - 1; + while k > r2 { + vector.swap(l1 as usize, k as usize); + k -= 1; + l1 += 1; + } + + if r1 >= 0 { + quicksort(vector, left, r1 as usize, cmp); + } + quicksort(vector, l1 as usize, right, cmp); +} + +#[cfg(test)] +mod test { + use super::*; + use crate::test::is_sorted; + use crate::vector::proptest::vector; + use ::proptest::num::i32; + use ::proptest::proptest; + + proptest! { + #[test] + fn test_quicksort(ref input in vector(i32::ANY, 0..1000)) { + let mut vec = input.clone(); + let len = vec.len(); + if len > 1 { + quicksort(&mut vec.focus_mut(), 0, len - 1, &Ord::cmp); + } + assert!(is_sorted(vec)); + } + } +} diff --git a/im-rc/src/sync.rs b/im-rc/src/sync.rs new file mode 100644 index 000000000..bbffe7f16 --- /dev/null +++ b/im-rc/src/sync.rs @@ -0,0 +1,69 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +pub use self::lock::Lock; + +#[cfg(threadsafe)] +mod lock { + use std::sync::{Arc, Mutex, MutexGuard}; + + /// Thread safe lock: just wraps a `Mutex`. + pub struct Lock { + lock: Arc>, + } + + impl Lock { + pub fn new(value: A) -> Self { + Lock { + lock: Arc::new(Mutex::new(value)), + } + } + + #[inline] + pub fn lock(&mut self) -> Option> { + self.lock.lock().ok() + } + } + + impl Clone for Lock { + fn clone(&self) -> Self { + Lock { + lock: self.lock.clone(), + } + } + } +} + +#[cfg(not(threadsafe))] +mod lock { + use std::cell::{RefCell, RefMut}; + use std::rc::Rc; + + /// Single threaded lock: a `RefCell` so we should safely panic if somehow + /// trying to access the stored data twice from the same thread. + pub struct Lock { + lock: Rc>, + } + + impl Lock { + pub fn new(value: A) -> Self { + Lock { + lock: Rc::new(RefCell::new(value)), + } + } + + #[inline] + pub fn lock(&mut self) -> Option> { + self.lock.try_borrow_mut().ok() + } + } + + impl Clone for Lock { + fn clone(&self) -> Self { + Lock { + lock: self.lock.clone(), + } + } + } +} diff --git a/im-rc/src/test.rs b/im-rc/src/test.rs new file mode 100644 index 000000000..16cf93965 --- /dev/null +++ b/im-rc/src/test.rs @@ -0,0 +1,86 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use metrohash::MetroHash64; +use std::hash::{BuildHasher, Hasher}; +use std::marker::PhantomData; +use typenum::{Unsigned, U64}; + +pub fn is_sorted(l: I) -> bool +where + I: IntoIterator, + A: Ord, +{ + let mut it = l.into_iter().peekable(); + loop { + match (it.next(), it.peek()) { + (_, None) => return true, + (Some(ref a), Some(b)) if a > b => return false, + _ => (), + } + } +} + +pub struct LolHasher { + state: u64, + shift: usize, + size: PhantomData, +} + +impl LolHasher { + fn feed_me(&mut self, byte: u8) { + self.state ^= u64::from(byte) << self.shift; + self.shift += 8; + if self.shift >= 64 { + self.shift = 0; + } + } +} + +impl Hasher for LolHasher { + fn write(&mut self, bytes: &[u8]) { + for byte in bytes { + self.feed_me(*byte) + } + } + + fn finish(&self) -> u64 { + if N::USIZE == 64 { + self.state + } else { + self.state & ((1 << N::USIZE) - 1) + } + } +} + +impl Default for LolHasher { + fn default() -> Self { + LolHasher { + state: 0, + shift: 0, + size: PhantomData, + } + } +} + +pub struct MetroHashBuilder { + seed: u64, +} + +impl MetroHashBuilder { + pub fn new(seed: u64) -> Self { + MetroHashBuilder { seed } + } + + pub fn seed(&self) -> u64 { + self.seed + } +} + +impl BuildHasher for MetroHashBuilder { + type Hasher = MetroHash64; + fn build_hasher(&self) -> Self::Hasher { + MetroHash64::with_seed(self.seed) + } +} diff --git a/im-rc/src/tests/hashset.rs b/im-rc/src/tests/hashset.rs new file mode 100644 index 000000000..70945222d --- /dev/null +++ b/im-rc/src/tests/hashset.rs @@ -0,0 +1,85 @@ +#![allow(clippy::unit_arg)] + +use std::collections::HashSet as NatSet; +use std::fmt::{Debug, Error, Formatter, Write}; +use std::hash::Hash; + +use crate::HashSet; + +use proptest::proptest; +use proptest_derive::Arbitrary; + +#[derive(Arbitrary, Debug)] +enum Action { + Insert(A), + Remove(A), +} + +#[derive(Arbitrary)] +struct Actions(Vec>) +where + A: Hash + Eq + Clone; + +impl Debug for Actions +where + A: Hash + Eq + Debug + Clone, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut out = String::new(); + let mut expected = NatSet::new(); + writeln!(out, "let mut set = HashSet::new();")?; + for action in &self.0 { + match action { + Action::Insert(ref value) => { + expected.insert(value.clone()); + writeln!(out, "set.insert({:?});", value)?; + } + Action::Remove(ref value) => { + expected.remove(value); + writeln!(out, "set.remove({:?});", value)?; + } + } + } + writeln!( + out, + "let expected = vec!{:?};", + expected.into_iter().collect::>() + )?; + writeln!(out, "assert_eq!(HashSet::from(expected), set);")?; + write!(f, "{}", super::code_fmt(&out)) + } +} + +proptest! { + #[test] + fn comprehensive(actions: Actions) { + let mut set = HashSet::new(); + let mut nat = NatSet::new(); + for action in actions.0 { + match action { + Action::Insert(value) => { + let len = nat.len() + if nat.contains(&value) { + 0 + } else { + 1 + }; + nat.insert(value); + set.insert(value); + assert_eq!(len, set.len()); + } + Action::Remove(value) => { + let len = nat.len() - if nat.contains(&value) { + 1 + } else { + 0 + }; + nat.remove(&value); + set.remove(&value); + assert_eq!(len, set.len()); + } + } + assert_eq!(nat.len(), set.len()); + assert_eq!(HashSet::from(nat.clone()), set); + } + } +} diff --git a/im-rc/src/tests/mod.rs b/im-rc/src/tests/mod.rs new file mode 100644 index 000000000..72669bf69 --- /dev/null +++ b/im-rc/src/tests/mod.rs @@ -0,0 +1,23 @@ +mod hashset; +mod ordset; +mod vector; + +fn code_fmt(code: &str) -> String { + use syntect::easy::HighlightLines; + use syntect::highlighting::{Style, ThemeSet}; + use syntect::parsing::SyntaxSet; + use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings}; + + let ps = SyntaxSet::load_defaults_newlines(); + let ts = ThemeSet::load_defaults(); + let syntax = ps.find_syntax_by_extension("rs").unwrap(); + let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]); + let mut out = String::from("\n\n"); + for line in LinesWithEndings::from(&code) { + let ranges: Vec<(Style, &str)> = h.highlight(line, &ps); + let escaped = as_24_bit_terminal_escaped(&ranges[..], false); + out += &escaped; + } + out += "\n\x1b[0m"; + out +} diff --git a/im-rc/src/tests/ordset.rs b/im-rc/src/tests/ordset.rs new file mode 100644 index 000000000..628dfeb96 --- /dev/null +++ b/im-rc/src/tests/ordset.rs @@ -0,0 +1,85 @@ +#![allow(clippy::unit_arg)] + +use std::collections::BTreeSet; +use std::fmt::{Debug, Error, Formatter, Write}; + +use crate::OrdSet; + +use proptest::proptest; +use proptest_derive::Arbitrary; + +#[derive(Arbitrary, Debug)] +enum Action { + Insert(A), + Remove(A), +} + +#[derive(Arbitrary)] +struct Actions(Vec>) +where + A: Ord + Clone; + +impl Debug for Actions +where + A: Ord + Debug + Clone, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut out = String::new(); + let mut expected = BTreeSet::new(); + writeln!(out, "let mut set = OrdSet::new();")?; + for action in &self.0 { + match action { + Action::Insert(ref value) => { + expected.insert(value.clone()); + writeln!(out, "set.insert({:?});", value)?; + } + Action::Remove(ref value) => { + expected.remove(value); + writeln!(out, "set.remove({:?});", value)?; + } + } + } + writeln!( + out, + "let expected = vec!{:?};", + expected.into_iter().collect::>() + )?; + writeln!(out, "assert_eq!(OrdSet::from(expected), set);")?; + write!(f, "{}", super::code_fmt(&out)) + } +} + +proptest! { + #[test] + fn comprehensive(actions: Actions) { + let mut set = OrdSet::new(); + let mut nat = BTreeSet::new(); + for action in actions.0 { + match action { + Action::Insert(value) => { + let len = nat.len() + if nat.contains(&value) { + 0 + } else { + 1 + }; + nat.insert(value); + set.insert(value); + assert_eq!(len, set.len()); + } + Action::Remove(value) => { + let len = nat.len() - if nat.contains(&value) { + 1 + } else { + 0 + }; + nat.remove(&value); + set.remove(&value); + assert_eq!(len, set.len()); + } + } + assert_eq!(nat.len(), set.len()); + assert_eq!(OrdSet::from(nat.clone()), set); + assert!(nat.iter().eq(set.iter())); + } + } +} diff --git a/im-rc/src/tests/vector.rs b/im-rc/src/tests/vector.rs new file mode 100644 index 000000000..405985ef0 --- /dev/null +++ b/im-rc/src/tests/vector.rs @@ -0,0 +1,219 @@ +#![allow(clippy::unit_arg)] + +use std::fmt::{Debug, Error, Formatter, Write}; +use std::iter::FromIterator; + +use crate::Vector; + +use proptest::proptest; +use proptest_derive::Arbitrary; + +#[derive(Arbitrary, Debug)] +enum Action { + PushFront(A), + PushBack(A), + PopFront, + PopBack, + Insert(usize, A), + Remove(usize), + JoinLeft(Vec), + JoinRight(Vec), + SplitLeft(usize), + SplitRight(usize), +} + +#[derive(Arbitrary)] +struct Actions(Vec>) +where + A: Clone; + +impl Debug for Actions +where + A: Debug + Clone, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let mut out = String::new(); + let mut expected = vec![]; + writeln!(out, "let mut vec = Vector::new();")?; + for action in &self.0 { + match action { + Action::PushFront(ref value) => { + expected.insert(0, value.clone()); + writeln!(out, "vec.push_front({:?});", value)? + } + Action::PushBack(ref value) => { + expected.push(value.clone()); + writeln!(out, "vec.push_back({:?});", value)? + } + Action::PopFront => { + if !expected.is_empty() { + expected.remove(0); + } + writeln!(out, "vec.pop_front();")? + } + Action::PopBack => { + expected.pop(); + writeln!(out, "vec.pop_back();")? + } + Action::Insert(ref index, ref value) => { + let index = cap_index(expected.len(), *index); + expected.insert(index, value.clone()); + writeln!(out, "vec.insert({:?}, {:?});", index, value)? + } + Action::Remove(ref index) => { + if !expected.is_empty() { + let index = cap_index(expected.len(), *index); + expected.remove(index); + writeln!(out, "vec.remove({:?})", index)? + } else { + continue; + } + } + Action::JoinLeft(ref vec) => { + let mut vec_new = vec.clone(); + vec_new.append(&mut expected); + expected = vec_new; + writeln!( + out, + "let mut vec_new = Vector::from(vec!{:?}); // size {:?}", + vec, + vec.len() + )?; + writeln!(out, "vec_new.append(vec);")?; + writeln!(out, "vec = vec_new;")? + } + Action::JoinRight(ref vec) => { + expected.append(&mut vec.clone()); + writeln!( + out, + "vec.append(Vector::from(vec!{:?})); // size {:?}", + vec, + vec.len() + )? + } + Action::SplitLeft(ref index) => { + let index = cap_index(expected.len(), *index); + expected.split_off(index); + writeln!(out, "vec.split_off({:?});", index)? + } + Action::SplitRight(ref index) => { + let index = cap_index(expected.len(), *index); + expected = expected.split_off(index); + writeln!(out, "vec = vec.split_off({:?});", index)? + } + } + writeln!(out, "// len = {:?}", expected.len())?; + } + writeln!(out, "let expected = vec!{:?};", expected)?; + writeln!(out, "assert_eq!(Vector::from(expected), vec);")?; + write!(f, "{}", super::code_fmt(&out)) + } +} + +fn cap_index(len: usize, index: usize) -> usize { + if len == 0 { + 0 + } else { + index % len + } +} + +proptest! { + #[test] + fn comprehensive(actions: Actions) { + let mut vec = Vector::new(); + let mut nat = Vec::new(); + vec.assert_invariants(); + for action in actions.0 { + match action { + Action::PushFront(value) => { + let len = vec.len(); + nat.insert(0, value); + vec.push_front(value); + assert_eq!(len + 1, vec.len()); + } + Action::PushBack(value) => { + let len = vec.len(); + nat.push(value); + vec.push_back(value); + assert_eq!(len + 1, vec.len()); + } + Action::PopFront => { + if vec.is_empty() { + assert_eq!(None, vec.pop_front()); + } else { + let len = vec.len(); + assert_eq!(nat.remove(0), vec.pop_front().unwrap()); + assert_eq!(len - 1, vec.len()); + } + } + Action::PopBack => { + if vec.is_empty() { + assert_eq!(None, vec.pop_back()); + } else { + let len = vec.len(); + assert_eq!(nat.pop(), vec.pop_back()); + assert_eq!(len - 1, vec.len()); + } + } + Action::Insert(index, value) => { + let index = cap_index(vec.len(), index); + let len = vec.len(); + nat.insert(index, value); + vec.insert(index, value); + assert_eq!(len + 1, vec.len()); + } + Action::Remove(index) => { + if vec.is_empty() { + continue; + } + let index = cap_index(vec.len(), index); + let len = vec.len(); + assert_eq!(nat.remove(index), vec.remove(index)); + assert_eq!(len - 1, vec.len()); + } + Action::JoinLeft(mut new_nat) => { + let mut new_vec = Vector::from_iter(new_nat.iter().cloned()); + let add_len = new_nat.len(); + let len = vec.len(); + new_vec.append(vec); + vec = new_vec; + new_nat.append(&mut nat); + nat = new_nat; + assert_eq!(len + add_len, vec.len()); + } + Action::JoinRight(mut new_nat) => { + let new_vec = Vector::from_iter(new_nat.iter().cloned()); + let add_len = new_nat.len(); + let len = vec.len(); + vec.append(new_vec); + nat.append(&mut new_nat); + assert_eq!(len + add_len, vec.len()); + } + Action::SplitLeft(index) => { + let index = cap_index(vec.len(), index); + let len = vec.len(); + let vec_right = vec.split_off(index); + let nat_right = nat.split_off(index); + assert_eq!(index, vec.len()); + assert_eq!(len - index, vec_right.len()); + assert_eq!(Vector::from_iter(nat_right.iter().cloned()), vec_right); + } + Action::SplitRight(index) => { + let index = cap_index(vec.len(), index); + let len = vec.len(); + let vec_right = vec.split_off(index); + let nat_right = nat.split_off(index); + assert_eq!(index, vec.len()); + assert_eq!(len - index, vec_right.len()); + assert_eq!(Vector::from_iter(nat.iter().cloned()), vec); + vec = vec_right; + nat = nat_right; + } + } + vec.assert_invariants(); + assert_eq!(nat.len(),vec.len()); + assert_eq!(Vector::from_iter(nat.iter().cloned()), vec); + } + } +} diff --git a/im-rc/src/util.rs b/im-rc/src/util.rs new file mode 100644 index 000000000..a35f9ecf1 --- /dev/null +++ b/im-rc/src/util.rs @@ -0,0 +1,89 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Every codebase needs a `util` module. + +use std::cmp::Ordering; +use std::ops::{Bound, IndexMut, Range, RangeBounds}; +use std::ptr; + +// The `Ref` type is an alias for either `Rc` or `Arc`, user's choice. +#[cfg(threadsafe)] +use std::sync::Arc; +#[cfg(threadsafe)] +pub type Ref = Arc; +#[cfg(not(threadsafe))] +use std::rc::Rc; +#[cfg(not(threadsafe))] +pub type Ref = Rc; + +pub fn clone_ref(r: Ref) -> A +where + A: Clone, +{ + Ref::try_unwrap(r).unwrap_or_else(|r| (*r).clone()) +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Side { + Left, + Right, +} + +/// Swap two values of anything implementing `IndexMut`. +/// +/// Like `slice::swap`, but more generic. +#[allow(unsafe_code)] +pub fn swap_indices(vector: &mut V, a: usize, b: usize) +where + V: IndexMut, + V::Output: Sized, +{ + if a == b { + return; + } + // so sorry, but there's no implementation for this in std that's + // sufficiently generic + let pa: *mut V::Output = &mut vector[a]; + let pb: *mut V::Output = &mut vector[b]; + unsafe { + ptr::swap(pa, pb); + } +} + +#[allow(dead_code)] +pub fn linear_search_by<'a, A, I, F>(iterable: I, mut cmp: F) -> Result +where + A: 'a, + I: IntoIterator, + F: FnMut(&A) -> Ordering, +{ + let mut pos = 0; + for value in iterable { + match cmp(value) { + Ordering::Equal => return Ok(pos), + Ordering::Greater => return Err(pos), + Ordering::Less => {} + } + pos += 1; + } + Err(pos) +} + +pub fn to_range(range: &R, right_unbounded: usize) -> Range +where + R: RangeBounds, +{ + let start_index = match range.start_bound() { + Bound::Included(i) => *i, + Bound::Excluded(i) => *i + 1, + Bound::Unbounded => 0, + }; + let end_index = match range.end_bound() { + Bound::Included(i) => *i + 1, + Bound::Excluded(i) => *i, + Bound::Unbounded => right_unbounded, + }; + start_index..end_index +} diff --git a/im-rc/src/vector/focus.rs b/im-rc/src/vector/focus.rs new file mode 100644 index 000000000..883d8245a --- /dev/null +++ b/im-rc/src/vector/focus.rs @@ -0,0 +1,936 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::mem::{replace, swap}; +use std::ops::{Range, RangeBounds}; +use std::ptr::null; +use std::sync::atomic::{AtomicPtr, Ordering}; + +use crate::nodes::chunk::Chunk; +use crate::sync::Lock; +use crate::util::{to_range, Ref}; +use crate::vector::{Iter, IterMut, Vector, RRB}; + +/// Focused indexing over a [`Vector`][Vector]. +/// +/// By remembering the last tree node accessed through an index lookup and the +/// path we took to get there, we can speed up lookups for adjacent indices +/// tremendously. Lookups on indices in the same node are instantaneous, and +/// lookups on sibling nodes are also very fast. +/// +/// A `Focus` can also be used as a restricted view into a vector, using the +/// [`narrow`][narrow] and [`split_at`][split_at] methods. +/// +/// # When should I use a `Focus` for better performance? +/// +/// `Focus` is useful when you need to perform a large number of index lookups +/// that are more likely than not to be close to each other. It's usually worth +/// using a `Focus` in any situation where you're batching a lot of index +/// lookups together, even if they're not obviously adjacent - there's likely +/// to be some performance gain for even completely random access. +/// +/// If you're just iterating forwards or backwards over the [`Vector`][Vector] +/// in order, you're better off with a regular iterator, which, in fact, is +/// implemented using a `Focus`, but provides a simpler interface. +/// +/// If you're just doing a very small number of index lookups, the setup cost +/// for the `Focus` is probably not worth it. +/// +/// A `Focus` is never faster than an index lookup on a small [`Vector`][Vector] +/// with a length below the internal RRB tree's branching factor of 64. +/// +/// # Examples +/// +/// This example is contrived, as the better way to iterate forwards or +/// backwards over a vector is with an actual iterator. Even so, the version +/// using a `Focus` should run nearly an order of magnitude faster than the +/// version using index lookups at a length of 1000. It should also be noted +/// that [`vector::Iter`][Iter] is actually implemented using a `Focus` behind +/// the scenes, so the performance of the two should be identical. +/// +/// ```rust +/// # #[macro_use] extern crate im_rc as im; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// let mut vec: Vector = Vector::from_iter(0..1000); +/// +/// // Summing a vector, the slow way: +/// let mut sum = 0; +/// for i in 0..1000 { +/// sum += *vec.get(i).unwrap(); +/// } +/// assert_eq!(499500, sum); +/// +/// // Summing a vector faster using a Focus: +/// let mut sum = 0; +/// let mut focus = vec.focus(); +/// for i in 0..1000 { +/// sum += *focus.get(i).unwrap(); +/// } +/// assert_eq!(499500, sum); +/// +/// // And the easy way, for completeness: +/// let sum: i64 = vec.iter().sum(); +/// assert_eq!(499500, sum); +/// # } +/// ``` +/// +/// [Vector]: enum.Vector.html +/// [Iter]: struct.Iter.html +/// [narrow]: #method.narrow +/// [split_at]: #method.split_at +pub enum Focus<'a, A> +where + A: 'a, +{ + #[doc(hidden)] + Empty, + #[doc(hidden)] + Single(&'a [A]), + #[doc(hidden)] + Full(TreeFocus), +} + +impl<'a, A> Focus<'a, A> +where + A: Clone + 'a, +{ + /// Construct a `Focus` for a [`Vector`][Vector]. + /// + /// [Vector]: enum.Vector.html + pub fn new(vector: &'a Vector) -> Self { + match vector { + Vector::Empty => Focus::Empty, + Vector::Single(chunk) => Focus::Single(chunk), + Vector::Full(tree) => Focus::Full(TreeFocus::new(tree)), + } + } + + /// Get the length of the focused [`Vector`][Vector]. + /// + /// [Vector]: enum.Vector.html + pub fn len(&self) -> usize { + match self { + Focus::Empty => 0, + Focus::Single(chunk) => chunk.len(), + Focus::Full(tree) => tree.len(), + } + } + + /// Test if the focused [`Vector`][Vector] is empty. + /// + /// [Vector]: enum.Vector.html + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get a reference to the value at a given index. + pub fn get(&mut self, index: usize) -> Option<&A> { + match self { + Focus::Empty => None, + Focus::Single(chunk) => chunk.get(index), + Focus::Full(tree) => tree.get(index), + } + } + + /// Get a reference to the value at a given index. + /// + /// Panics if the index is out of bounds. + pub fn index(&mut self, index: usize) -> &A { + self.get(index).expect("index out of bounds") + } + + /// Get the chunk for the given index. + /// + /// This gives you a reference to the leaf node that contains the index, + /// along with its start and end indices. + pub fn chunk_at(&mut self, index: usize) -> (Range, &[A]) { + let len = self.len(); + if index >= len { + panic!("vector::Focus::chunk_at: index out of bounds"); + } + match self { + Focus::Empty => (0..0, &[]), + Focus::Single(chunk) => (0..len, chunk), + Focus::Full(tree) => tree.get_chunk(index), + } + } + + /// Narrow the focus onto a subslice of the vector. + /// + /// `Focus::narrow(range)` has the same effect as `&slice[range]`, without + /// actually modifying the underlying vector. + /// + /// Panics if the range isn't fully inside the current focus. + /// + /// ## Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let vec = Vector::from_iter(0..1000); + /// let narrowed = vec.focus().narrow(100..200); + /// let narrowed_vec = narrowed.into_iter().cloned().collect(); + /// assert_eq!(Vector::from_iter(100..200), narrowed_vec); + /// # } + /// ``` + /// + /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [Vector::split_at]: enum.Vector.html#method.split_at + pub fn narrow(self, range: R) -> Self + where + R: RangeBounds, + { + let r = to_range(&range, self.len()); + if r.start >= r.end || r.start >= self.len() { + panic!("vector::Focus::narrow: range out of bounds"); + } + match self { + Focus::Empty => Focus::Empty, + Focus::Single(chunk) => Focus::Single(&chunk[r]), + Focus::Full(tree) => Focus::Full(tree.narrow(r)), + } + } + + /// Split the focus into two. + /// + /// Given an index `index`, consume the focus and produce two new foci, the + /// left onto indices `0..index`, and the right onto indices `index..N` + /// where `N` is the length of the current focus. + /// + /// Panics if the index is out of bounds. + /// + /// This is the moral equivalent of [`slice::split_at`][slice::split_at], in + /// that it leaves the underlying data structure unchanged, unlike + /// [`Vector::split_at`][Vector::split_at]. + /// + /// ## Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let vec = Vector::from_iter(0..1000); + /// let (left, right) = vec.focus().split_at(500); + /// let left_vec = left.into_iter().cloned().collect(); + /// let right_vec = right.into_iter().cloned().collect(); + /// assert_eq!(Vector::from_iter(0..500), left_vec); + /// assert_eq!(Vector::from_iter(500..1000), right_vec); + /// # } + /// ``` + /// + /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [Vector::split_at]: enum.Vector.html#method.split_at + pub fn split_at(self, index: usize) -> (Self, Self) { + if index >= self.len() { + panic!("vector::Focus::split_at: index out of bounds"); + } + match self { + Focus::Empty => (Focus::Empty, Focus::Empty), + Focus::Single(chunk) => { + let (left, right) = chunk.split_at(index); + (Focus::Single(left), Focus::Single(right)) + } + Focus::Full(tree) => { + let (left, right) = tree.split_at(index); + (Focus::Full(left), Focus::Full(right)) + } + } + } +} + +impl<'a, A> IntoIterator for Focus<'a, A> +where + A: Clone + 'a, +{ + type Item = &'a A; + type IntoIter = Iter<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + Iter::from_focus(self) + } +} + +impl<'a, A> Clone for Focus<'a, A> +where + A: Clone + 'a, +{ + fn clone(&self) -> Self { + match self { + Focus::Empty => Focus::Empty, + Focus::Single(chunk) => Focus::Single(chunk), + Focus::Full(tree) => Focus::Full(tree.clone()), + } + } +} + +pub struct TreeFocus { + tree: RRB, + view: Range, + middle_range: Range, + target_range: Range, + target_ptr: *const Chunk, +} + +impl Clone for TreeFocus { + fn clone(&self) -> Self { + let tree = self.tree.clone(); + TreeFocus { + view: self.view.clone(), + middle_range: self.middle_range.clone(), + target_range: 0..0, + target_ptr: null(), + tree, + } + } +} + +#[allow(unsafe_code)] +#[cfg(threadsafe)] +unsafe impl Send for TreeFocus {} +#[allow(unsafe_code)] +#[cfg(threadsafe)] +unsafe impl Sync for TreeFocus {} + +#[inline] +fn contains(range: &Range, index: &A) -> bool { + *index >= range.start && *index < range.end +} + +impl TreeFocus +where + A: Clone, +{ + fn new(tree: &RRB) -> Self { + let middle_start = tree.outer_f.len() + tree.inner_f.len(); + let middle_end = middle_start + tree.middle.len(); + TreeFocus { + tree: tree.clone(), + view: 0..tree.length, + middle_range: middle_start..middle_end, + target_range: 0..0, + target_ptr: null(), + } + } + + fn len(&self) -> usize { + self.view.end - self.view.start + } + + fn narrow(self, mut view: Range) -> Self { + view.start += self.view.start; + view.end += self.view.start; + TreeFocus { + view, + middle_range: self.middle_range.clone(), + target_range: 0..0, + target_ptr: null(), + tree: self.tree, + } + } + + fn split_at(self, index: usize) -> (Self, Self) { + let len = self.len(); + let left = self.clone().narrow(0..index); + let right = self.narrow(index..len); + (left, right) + } + + fn physical_index(&self, index: usize) -> usize { + debug_assert!(index < self.view.end); + self.view.start + index + } + + fn logical_range(&self, range: &Range) -> Range { + (range.start - self.view.start)..(range.end - self.view.start) + } + + fn set_focus(&mut self, index: usize) { + if index < self.middle_range.start { + let outer_len = self.tree.outer_f.len(); + if index < outer_len { + self.target_range = 0..outer_len; + self.target_ptr = &*self.tree.outer_f; + } else { + self.target_range = outer_len..self.middle_range.start; + self.target_ptr = &*self.tree.inner_f; + } + } else if index >= self.middle_range.end { + let outer_start = self.middle_range.end + self.tree.inner_b.len(); + if index < outer_start { + self.target_range = self.middle_range.end..outer_start; + self.target_ptr = &*self.tree.inner_b; + } else { + self.target_range = outer_start..self.tree.length; + self.target_ptr = &*self.tree.outer_b; + } + } else { + let tree_index = index - self.middle_range.start; + let (range, ptr) = self + .tree + .middle + .lookup_chunk(self.tree.middle_level, 0, tree_index); + self.target_range = + (range.start + self.middle_range.start)..(range.end + self.middle_range.start); + self.target_ptr = ptr; + } + } + + #[allow(unsafe_code)] + fn get_focus(&self) -> &Chunk { + unsafe { &*self.target_ptr } + } + + pub fn get(&mut self, index: usize) -> Option<&A> { + if index >= self.len() { + return None; + } + let phys_index = self.physical_index(index); + if !contains(&self.target_range, &phys_index) { + self.set_focus(phys_index); + } + let target_phys_index = phys_index - self.target_range.start; + Some(&self.get_focus()[target_phys_index]) + } + + pub fn get_chunk(&mut self, index: usize) -> (Range, &[A]) { + let phys_index = self.physical_index(index); + if !contains(&self.target_range, &phys_index) { + self.set_focus(phys_index); + } + let mut slice: &[A] = self.get_focus(); + let mut left = 0; + let mut right = 0; + if self.target_range.start < self.view.start { + left = self.view.start - self.target_range.start; + } + if self.target_range.end > self.view.end { + right = self.target_range.end - self.view.end; + } + slice = &slice[left..(slice.len() - right)]; + let phys_range = (self.target_range.start + left)..(self.target_range.end - right); + (self.logical_range(&phys_range), slice) + } +} + +/// A mutable version of [`Focus`][Focus]. +/// +/// See [`Focus`][Focus] for more details. +/// +/// You can only build one `FocusMut` at a time for a vector, effectively +/// keeping a lock on the vector until you're done with the focus, which relies +/// on the structure of the vector not changing while it exists. +/// +/// ```rust,compile_fail +/// # #[macro_use] extern crate im_rc as im; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// let mut vec = Vector::from_iter(0..1000); +/// let focus1 = vec.focus_mut(); +/// // Fails here in 2015 edition because you're creating +/// // two mutable references to the same thing. +/// let focus2 = vec.focus_mut(); +/// // Fails here in 2018 edition because creating focus2 +/// // made focus1's lifetime go out of scope. +/// assert_eq!(Some(&0), focus1.get(0)); +/// # } +/// ``` +/// +/// On the other hand, you can split that one focus into multiple sub-focuses, +/// which is safe because they can't overlap: +/// +/// ```rust +/// # #[macro_use] extern crate im_rc as im; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// let mut vec = Vector::from_iter(0..1000); +/// let focus = vec.focus_mut(); +/// let (mut left, mut right) = focus.split_at(500); +/// assert_eq!(Some(&0), left.get(0)); +/// assert_eq!(Some(&500), right.get(0)); +/// # } +/// ``` +/// +/// These sub-foci also work as a lock on the vector, even if the focus they +/// were created from goes out of scope. +/// +/// ```rust,compile_fail +/// # #[macro_use] extern crate im_rc as im; +/// # use im::vector::Vector; +/// # use std::iter::FromIterator; +/// # fn main() { +/// let mut vec = Vector::from_iter(0..1000); +/// let (left, right) = { +/// let focus = vec.focus_mut(); +/// focus.split_at(500) +/// }; +/// // `left` and `right` are still in scope even if `focus` isn't, so we can't +/// // create another focus: +/// let focus2 = vec.focus_mut(); +/// assert_eq!(Some(&0), left.get(0)); +/// # } +/// ``` +/// +/// [Focus]: enum.Focus.html +pub enum FocusMut<'a, A> +where + A: 'a, +{ + #[doc(hidden)] + Empty, + #[doc(hidden)] + Single(&'a mut [A]), + #[doc(hidden)] + Full(TreeFocusMut<'a, A>), +} + +impl<'a, A> FocusMut<'a, A> +where + A: Clone + 'a, +{ + /// Construct a `FocusMut` for a `Vector`. + pub fn new(vector: &'a mut Vector) -> Self { + match vector { + Vector::Empty => FocusMut::Empty, + Vector::Single(chunk) => FocusMut::Single(Ref::make_mut(chunk).as_mut_slice()), + Vector::Full(tree) => FocusMut::Full(TreeFocusMut::new(tree)), + } + } + + /// Get the length of the focused `Vector`. + pub fn len(&self) -> usize { + match self { + FocusMut::Empty => 0, + FocusMut::Single(chunk) => chunk.len(), + FocusMut::Full(tree) => tree.len(), + } + } + + /// Test if the focused `Vector` is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get a reference to the value at a given index. + pub fn get(&mut self, index: usize) -> Option<&A> { + self.get_mut(index).map(|r| &*r) + } + + /// Get a mutable reference to the value at a given index. + pub fn get_mut(&mut self, index: usize) -> Option<&mut A> { + match self { + FocusMut::Empty => None, + FocusMut::Single(chunk) => chunk.get_mut(index), + FocusMut::Full(tree) => tree.get(index), + } + } + + /// Get a reference to the value at a given index. + /// + /// Panics if the index is out of bounds. + pub fn index(&mut self, index: usize) -> &A { + &*self.index_mut(index) + } + + /// Get a mutable reference to the value at a given index. + /// + /// Panics if the index is out of bounds. + #[allow(clippy::should_implement_trait)] // would if I could + pub fn index_mut(&mut self, index: usize) -> &mut A { + self.get_mut(index).expect("index out of bounds") + } + + /// Update the value at a given index. + /// + /// Returns `None` if the index is out of bounds, or the replaced value + /// otherwise. + pub fn set(&mut self, index: usize, value: A) -> Option { + match self.get_mut(index) { + Some(ref mut pos) => Some(replace(pos, value)), + None => None, + } + } + + /// Swap the values at two given indices. + /// + /// Panics if either index is out of bounds. + /// + /// If the indices are equal, this function returns without doing anything. + pub fn swap(&mut self, a: usize, b: usize) { + if a == b { + return; + } + self.pair(a, b, |left, right| swap(left, right)); + } + + /// Lookup two indices simultaneously and run a function over them. + /// + /// Useful because the borrow checker won't let you have more than one + /// mutable reference into the same data structure at any given time. + /// + /// Panics if either index is out of bounds, or if they are the same index. + /// + /// # Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 4, 5]; + /// vec.focus_mut().pair(1, 3, |a, b| *a += *b); + /// assert_eq!(vector![1, 6, 3, 4, 5], vec); + /// # } + /// ``` + #[allow(unsafe_code)] + pub fn pair(&mut self, a: usize, b: usize, mut f: F) -> B + where + F: FnMut(&mut A, &mut A) -> B, + { + if a == b { + panic!("vector::FocusMut::pair: indices cannot be equal!"); + } + let pa: *mut A = self.index_mut(a); + let pb: *mut A = self.index_mut(b); + unsafe { f(&mut *pa, &mut *pb) } + } + + /// Lookup three indices simultaneously and run a function over them. + /// + /// Useful because the borrow checker won't let you have more than one + /// mutable reference into the same data structure at any given time. + /// + /// Panics if any index is out of bounds, or if any indices are equal. + /// + /// # Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 4, 5]; + /// vec.focus_mut().triplet(0, 2, 4, |a, b, c| *a += *b + *c); + /// assert_eq!(vector![9, 2, 3, 4, 5], vec); + /// # } + /// ``` + #[allow(unsafe_code)] + pub fn triplet(&mut self, a: usize, b: usize, c: usize, mut f: F) -> B + where + F: FnMut(&mut A, &mut A, &mut A) -> B, + { + if a == b || b == c || a == c { + panic!("vector::FocusMut::triplet: indices cannot be equal!"); + } + let pa: *mut A = self.index_mut(a); + let pb: *mut A = self.index_mut(b); + let pc: *mut A = self.index_mut(c); + unsafe { f(&mut *pa, &mut *pb, &mut *pc) } + } + + /// Get the chunk for the given index. + /// + /// This gives you a reference to the leaf node that contains the index, + /// along with its start and end indices. + pub fn chunk_at(&mut self, index: usize) -> (Range, &mut [A]) { + let len = self.len(); + if index >= len { + panic!("vector::FocusMut::chunk_at: index out of bounds"); + } + match self { + FocusMut::Empty => (0..0, &mut []), + FocusMut::Single(chunk) => (0..len, chunk), + FocusMut::Full(tree) => { + let (range, chunk) = tree.get_chunk(index); + (range, chunk) + } + } + } + + /// Narrow the focus onto a subslice of the vector. + /// + /// `FocusMut::narrow(range)` has the same effect as `&slice[range]`, without + /// actually modifying the underlying vector. + /// + /// Panics if the range isn't fully inside the current focus. + /// + /// ## Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let mut vec = Vector::from_iter(0..1000); + /// let narrowed = vec.focus_mut().narrow(100..200); + /// let narrowed_vec = narrowed.unmut().into_iter().cloned().collect(); + /// assert_eq!(Vector::from_iter(100..200), narrowed_vec); + /// # } + /// ``` + /// + /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [Vector::split_at]: enum.Vector.html#method.split_at + pub fn narrow(self, range: R) -> Self + where + R: RangeBounds, + { + let r = to_range(&range, self.len()); + if r.start > r.end || r.start > self.len() { + panic!("vector::FocusMut::narrow: range out of bounds"); + } + match self { + FocusMut::Empty => FocusMut::Empty, + FocusMut::Single(chunk) => FocusMut::Single(&mut chunk[r]), + FocusMut::Full(tree) => FocusMut::Full(tree.narrow(r)), + } + } + + /// Split the focus into two. + /// + /// Given an index `index`, consume the focus and produce two new foci, the + /// left onto indices `0..index`, and the right onto indices `index..N` + /// where `N` is the length of the current focus. + /// + /// Panics if the index is out of bounds. + /// + /// This is the moral equivalent of [`slice::split_at`][slice::split_at], in + /// that it leaves the underlying data structure unchanged, unlike + /// [`Vector::split_at`][Vector::split_at]. + /// + /// ## Examples + /// + /// ```rust + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # use std::iter::FromIterator; + /// # fn main() { + /// let mut vec = Vector::from_iter(0..1000); + /// { + /// let (left, right) = vec.focus_mut().split_at(500); + /// for ptr in left { + /// *ptr += 100; + /// } + /// for ptr in right { + /// *ptr -= 100; + /// } + /// } + /// let expected = Vector::from_iter(100..600) + /// + Vector::from_iter(400..900); + /// assert_eq!(expected, vec); + /// # } + /// ``` + /// + /// [slice::split_at]: https://doc.rust-lang.org/std/primitive.slice.html#method.split_at + /// [Vector::split_at]: enum.Vector.html#method.split_at + pub fn split_at(self, index: usize) -> (Self, Self) { + if index > self.len() { + panic!("vector::FocusMut::split_at: index out of bounds"); + } + match self { + FocusMut::Empty => (FocusMut::Empty, FocusMut::Empty), + FocusMut::Single(chunk) => { + let (left, right) = chunk.split_at_mut(index); + (FocusMut::Single(left), FocusMut::Single(right)) + } + FocusMut::Full(tree) => { + let (left, right) = tree.split_at(index); + (FocusMut::Full(left), FocusMut::Full(right)) + } + } + } + + /// Convert a `FocusMut` into a `Focus`. + pub fn unmut(self) -> Focus<'a, A> { + match self { + FocusMut::Empty => Focus::Empty, + FocusMut::Single(chunk) => Focus::Single(chunk), + FocusMut::Full(mut tree) => Focus::Full(TreeFocus { + tree: { + let t = tree.tree.lock().unwrap(); + (*t).clone() + }, + view: tree.view.clone(), + middle_range: tree.middle_range.clone(), + target_range: 0..0, + target_ptr: null(), + }), + } + } +} + +impl<'a, A> IntoIterator for FocusMut<'a, A> +where + A: Clone + 'a, +{ + type Item = &'a mut A; + type IntoIter = IterMut<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + IterMut::from_focus(self) + } +} + +impl<'a, A> Into> for FocusMut<'a, A> +where + A: Clone + 'a, +{ + fn into(self) -> Focus<'a, A> { + self.unmut() + } +} + +pub struct TreeFocusMut<'a, A> +where + A: 'a, +{ + tree: Lock<&'a mut RRB>, + view: Range, + middle_range: Range, + target_range: Range, + target_ptr: AtomicPtr>, +} + +impl<'a, A> TreeFocusMut<'a, A> +where + A: Clone + 'a, +{ + fn new(tree: &'a mut RRB) -> Self { + let middle_start = tree.outer_f.len() + tree.inner_f.len(); + let middle_end = middle_start + tree.middle.len(); + TreeFocusMut { + view: 0..tree.length, + tree: Lock::new(tree), + middle_range: middle_start..middle_end, + target_range: 0..0, + target_ptr: AtomicPtr::default(), + } + } + + fn len(&self) -> usize { + self.view.end - self.view.start + } + + fn narrow(self, mut view: Range) -> Self { + view.start += self.view.start; + view.end += self.view.start; + TreeFocusMut { + view, + middle_range: self.middle_range.clone(), + target_range: 0..0, + target_ptr: AtomicPtr::default(), + tree: self.tree, + } + } + + fn split_at(self, index: usize) -> (Self, Self) { + let len = self.len(); + debug_assert!(index <= len); + #[allow(unsafe_code)] + let left = TreeFocusMut { + view: self.view.start..(self.view.start + index), + middle_range: self.middle_range.clone(), + target_range: 0..0, + target_ptr: AtomicPtr::default(), + tree: self.tree.clone(), + }; + let right = TreeFocusMut { + view: (self.view.start + index)..(self.view.start + len), + middle_range: self.middle_range.clone(), + target_range: 0..0, + target_ptr: AtomicPtr::default(), + tree: self.tree, + }; + (left, right) + } + + fn physical_index(&self, index: usize) -> usize { + debug_assert!(index < self.view.end); + self.view.start + index + } + + fn logical_range(&self, range: &Range) -> Range { + (range.start - self.view.start)..(range.end - self.view.start) + } + + fn set_focus(&mut self, index: usize) { + let mut tree = self + .tree + .lock() + .expect("im::vector::Focus::set_focus: unable to acquire exclusive lock on Vector"); + if index < self.middle_range.start { + let outer_len = tree.outer_f.len(); + if index < outer_len { + self.target_range = 0..outer_len; + self.target_ptr + .store(Ref::make_mut(&mut tree.outer_f), Ordering::Relaxed); + } else { + self.target_range = outer_len..self.middle_range.start; + self.target_ptr + .store(Ref::make_mut(&mut tree.inner_f), Ordering::Relaxed); + } + } else if index >= self.middle_range.end { + let outer_start = self.middle_range.end + tree.inner_b.len(); + if index < outer_start { + self.target_range = self.middle_range.end..outer_start; + self.target_ptr + .store(Ref::make_mut(&mut tree.inner_b), Ordering::Relaxed); + } else { + self.target_range = outer_start..tree.length; + self.target_ptr + .store(Ref::make_mut(&mut tree.outer_b), Ordering::Relaxed); + } + } else { + let tree_index = index - self.middle_range.start; + let level = tree.middle_level; + let middle = Ref::make_mut(&mut tree.middle); + let (range, ptr) = middle.lookup_chunk_mut(level, 0, tree_index); + self.target_range = + (range.start + self.middle_range.start)..(range.end + self.middle_range.start); + self.target_ptr.store(ptr, Ordering::Relaxed); + } + } + + #[allow(unsafe_code)] + fn get_focus(&mut self) -> &mut Chunk { + unsafe { &mut *self.target_ptr.load(Ordering::Relaxed) } + } + + pub fn get(&mut self, index: usize) -> Option<&mut A> { + if index >= self.len() { + return None; + } + let phys_index = self.physical_index(index); + if !contains(&self.target_range, &phys_index) { + self.set_focus(phys_index); + } + let target_phys_index = phys_index - self.target_range.start; + Some(&mut self.get_focus()[target_phys_index]) + } + + pub fn get_chunk(&mut self, index: usize) -> (Range, &mut [A]) { + let phys_index = self.physical_index(index); + if !contains(&self.target_range, &phys_index) { + self.set_focus(phys_index); + } + let mut left = 0; + let mut right = 0; + if self.target_range.start < self.view.start { + left = self.view.start - self.target_range.start; + } + if self.target_range.end > self.view.end { + right = self.target_range.end - self.view.end; + } + let phys_range = (self.target_range.start + left)..(self.target_range.end - right); + let log_range = self.logical_range(&phys_range); + let slice_len = self.get_focus().len(); + let slice = &mut (self.get_focus().as_mut_slice())[left..(slice_len - right)]; + (log_range, slice) + } +} diff --git a/im-rc/src/vector/mod.rs b/im-rc/src/vector/mod.rs new file mode 100644 index 000000000..378d7bd8d --- /dev/null +++ b/im-rc/src/vector/mod.rs @@ -0,0 +1,2846 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! A persistent vector. +//! +//! This is a sequence of elements in insertion order - if you need a +//! list of things, any kind of list of things, this is what you're +//! looking for. +//! +//! It's implemented as an [RRB vector][rrbpaper] with [smart +//! head/tail chunking][chunkedseq]. In performance terms, this means +//! that practically every operation is O(log n), except push/pop on +//! both sides, which will be O(1) amortised, and O(log n) in the +//! worst case. In practice, the push/pop operations will be +//! blindingly fast, nearly on par with the native +//! [`VecDeque`][VecDeque], and other operations will have decent, if +//! not high, performance, but they all have more or less the same +//! O(log n) complexity, so you don't need to keep their performance +//! characteristics in mind - everything, even splitting and merging, +//! is safe to use and never too slow. +//! +//! ## Performance Notes +//! +//! Because of the head/tail chunking technique, until you push a +//! number of items above double the tree's branching factor (that's +//! `self.len()` = 2 × *k* (where *k* = 64) = 128) on either side, the +//! data structure is still just a handful of arrays, not yet an RRB +//! tree, so you'll see performance and memory characteristics fairly +//! close to [`Vec`][Vec] or [`VecDeque`][VecDeque]. +//! +//! This means that the structure always preallocates four chunks of +//! size *k* (*k* being the tree's branching factor), equivalent to a +//! [`Vec`][Vec] with an initial capacity of 256. Beyond that, it will +//! allocate tree nodes of capacity *k* as needed. +//! +//! In addition, vectors start out as single chunks, and only expand into the +//! full data structure once you go past the chunk size. This makes them +//! perform identically to [`Vec`][Vec] at small sizes. +//! +//! [rrbpaper]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf +//! [chunkedseq]: http://deepsea.inria.fr/pasl/chunkedseq.pdf +//! [Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html +//! [VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{Hash, Hasher}; +use std::iter::Sum; +use std::iter::{Chain, FromIterator, FusedIterator}; +use std::mem::{replace, swap}; +use std::ops::{Add, Index, IndexMut, RangeBounds}; + +use crate::nodes::chunk::{Chunk, Iter as ChunkIter, CHUNK_SIZE}; +use crate::nodes::rrb::{ + ConsumingIter as ConsumingNodeIter, Node, PopResult, PushResult, SplitResult, +}; +use crate::sort; +use crate::util::{clone_ref, swap_indices, to_range, Ref, Side}; + +use self::Vector::{Empty, Full, Single}; + +mod focus; + +pub use self::focus::{Focus, FocusMut}; + +/// Construct a vector from a sequence of elements. +/// +/// # Examples +/// +/// ``` +/// # #[macro_use] extern crate im_rc as im; +/// # use im::vector::Vector; +/// # fn main() { +/// assert_eq!( +/// vector![1, 2, 3], +/// Vector::from(vec![1, 2, 3]) +/// ); +/// # } +/// ``` +#[macro_export] +macro_rules! vector { + () => { $crate::vector::Vector::new() }; + + ( $($x:expr),* ) => {{ + let mut l = $crate::vector::Vector::new(); + $( + l.push_back($x); + )* + l + }}; + + ( $($x:expr ,)* ) => {{ + let mut l = $crate::vector::Vector::new(); + $( + l.push_back($x); + )* + l + }}; +} + +/// A persistent vector. +/// +/// This is a sequence of elements in insertion order - if you need a list of +/// things, any kind of list of things, this is what you're looking for. +/// +/// It's implemented as an [RRB vector][rrbpaper] with [smart head/tail +/// chunking][chunkedseq]. In performance terms, this means that practically +/// every operation is O(log n), except push/pop on both sides, which will be +/// O(1) amortised, and O(log n) in the worst case. In practice, the push/pop +/// operations will be blindingly fast, nearly on par with the native +/// [`VecDeque`][VecDeque], and other operations will have decent, if not high, +/// performance, but they all have more or less the same O(log n) complexity, so +/// you don't need to keep their performance characteristics in mind - +/// everything, even splitting and merging, is safe to use and never too slow. +/// +/// ## Performance Notes +/// +/// Because of the head/tail chunking technique, until you push a number of +/// items above double the tree's branching factor (that's `self.len()` = 2 × +/// *k* (where *k* = 64) = 128) on either side, the data structure is still just +/// a handful of arrays, not yet an RRB tree, so you'll see performance and +/// memory characteristics similar to [`Vec`][Vec] or [`VecDeque`][VecDeque]. +/// +/// This means that the structure always preallocates four chunks of size *k* +/// (*k* being the tree's branching factor), equivalent to a [`Vec`][Vec] with +/// an initial capacity of 256. Beyond that, it will allocate tree nodes of +/// capacity *k* as needed. +/// +/// In addition, vectors start out as single chunks, and only expand into the +/// full data structure once you go past the chunk size. This makes them +/// perform identically to [`Vec`][Vec] at small sizes. +/// +/// [rrbpaper]: https://infoscience.epfl.ch/record/213452/files/rrbvector.pdf +/// [chunkedseq]: http://deepsea.inria.fr/pasl/chunkedseq.pdf +/// [Vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html +/// [VecDeque]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html +pub enum Vector { + #[doc(hidden)] + Empty, + #[doc(hidden)] + Single(Ref>), + #[doc(hidden)] + Full(RRB), +} + +#[doc(hidden)] +pub struct RRB { + length: usize, + middle_level: usize, + outer_f: Ref>, + inner_f: Ref>, + middle: Ref>, + inner_b: Ref>, + outer_b: Ref>, +} + +impl Clone for RRB { + fn clone(&self) -> Self { + RRB { + length: self.length, + middle_level: self.middle_level, + outer_f: self.outer_f.clone(), + inner_f: self.inner_f.clone(), + middle: self.middle.clone(), + inner_b: self.inner_b.clone(), + outer_b: self.outer_b.clone(), + } + } +} + +impl Vector { + /// True if a vector is empty or a full single chunk, ie. must be promoted + /// to grow further. + fn needs_promotion(&self) -> bool { + match self { + Empty => true, + Single(chunk) if chunk.is_full() => true, + _ => false, + } + } + + /// Promote an empty to a single. + fn promote_empty(&mut self) { + if let Empty = self { + *self = Single(Ref::new(Chunk::new())) + } + } + + /// Promote a single to a full, with the single chunk becomming inner_f, or + /// promote an empty to a single. + fn promote_front(&mut self) { + let chunk = match self { + Empty => return self.promote_empty(), + Single(chunk) => chunk.clone(), + _ => return, + }; + *self = Full(RRB { + length: chunk.len(), + middle_level: 0, + outer_f: Ref::new(Chunk::new()), + inner_f: chunk, + middle: Ref::new(Node::new()), + inner_b: Ref::new(Chunk::new()), + outer_b: Ref::new(Chunk::new()), + }) + } + + /// Promote a single to a full, with the single chunk becomming inner_b, or + /// promote an empty to a single. + fn promote_back(&mut self) { + let chunk = match self { + Empty => return self.promote_empty(), + Single(chunk) => chunk.clone(), + _ => return, + }; + *self = Full(RRB { + length: chunk.len(), + middle_level: 0, + outer_f: Ref::new(Chunk::new()), + inner_f: Ref::new(Chunk::new()), + middle: Ref::new(Node::new()), + inner_b: chunk, + outer_b: Ref::new(Chunk::new()), + }) + } + + /// Construct an empty vector. + #[must_use] + pub fn new() -> Self { + Empty + } + + /// Get the length of a vector. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # fn main() { + /// assert_eq!(5, vector![1, 2, 3, 4, 5].len()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + match self { + Empty => 0, + Single(chunk) => chunk.len(), + Full(tree) => tree.length, + } + } + + /// Test whether a vector is empty. + /// + /// Time: O(1) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let vec = vector!["Joe", "Mike", "Robert"]; + /// assert_eq!(false, vec.is_empty()); + /// assert_eq!(true, Vector::::new().is_empty()); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Get an iterator over a vector. + /// + /// Time: O(1) + #[inline] + #[must_use] + pub fn iter(&self) -> Iter { + Iter::new(self) + } + + /// Get a mutable iterator over a vector. + /// + /// Time: O(1) + #[inline] + #[must_use] + pub fn iter_mut(&mut self) -> IterMut { + IterMut::new(self) + } + + /// Get an iterator over the leaf nodes of a vector. + /// + /// This method has been deprecated; use [`leaves`][leaves] instead. + /// + /// Time: O(1) + /// + /// [leaves]: #method.leaves + #[inline] + #[must_use] + #[deprecated( + since = "12.3.0", + note = "renamed to `leaves` to avoid confusion with Vec::chunks" + )] + pub fn chunks(&self) -> Chunks<'_, A> { + Chunks::new(self) + } + + /// Get a mutable iterator over the leaf nodes of a vector. + /// + /// This method has been deprecated; use [`leaves_mut`][leaves_mut] instead. + /// + /// Time: O(1) + /// + /// [leaves_mut]: #method.leaves_mut + #[inline] + #[must_use] + #[deprecated( + since = "12.3.0", + note = "renamed to `leaves_mut` to avoid confusion with Vec::chunks" + )] + pub fn chunks_mut(&mut self) -> ChunksMut<'_, A> { + ChunksMut::new(self) + } + + /// Get an iterator over the leaf nodes of a vector. + /// + /// This returns an iterator over the [`Chunk`s][Chunk] at the leaves of the + /// RRB tree. These are useful for efficient parallelisation of work on + /// the vector, but should not be used for basic iteration. + /// + /// Time: O(1) + /// + /// [Chunk]: ../chunk/struct.Chunk.html + #[inline] + #[must_use] + pub fn leaves(&self) -> Chunks<'_, A> { + Chunks::new(self) + } + + /// Get a mutable iterator over the leaf nodes of a vector. + // + /// This returns an iterator over the [`Chunk`s][Chunk] at the leaves of the + /// RRB tree. These are useful for efficient parallelisation of work on + /// the vector, but should not be used for basic iteration. + /// + /// Time: O(1) + /// + /// [Chunk]: ../chunk/struct.Chunk.html + #[inline] + #[must_use] + pub fn leaves_mut(&mut self) -> ChunksMut<'_, A> { + ChunksMut::new(self) + } + + /// Construct a [`Focus`][Focus] for a vector. + /// + /// Time: O(1) + /// + /// [Focus]: enum.Focus.html + #[inline] + #[must_use] + pub fn focus(&self) -> Focus<'_, A> { + Focus::new(self) + } + + /// Construct a [`FocusMut`][FocusMut] for a vector. + /// + /// Time: O(1) + /// + /// [FocusMut]: enum.FocusMut.html + #[inline] + #[must_use] + pub fn focus_mut(&mut self) -> FocusMut<'_, A> { + FocusMut::new(self) + } + + /// Get a reference to the value at index `index` in a vector. + /// + /// Returns `None` if the index is out of bounds. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let vec = vector!["Joe", "Mike", "Robert"]; + /// assert_eq!(Some(&"Robert"), vec.get(2)); + /// assert_eq!(None, vec.get(5)); + /// # } + /// ``` + #[must_use] + pub fn get(&self, index: usize) -> Option<&A> { + if index >= self.len() { + return None; + } + + match self { + Empty => None, + Single(chunk) => chunk.get(index), + Full(tree) => { + let mut local_index = index; + + if local_index < tree.outer_f.len() { + return Some(&tree.outer_f[local_index]); + } + local_index -= tree.outer_f.len(); + + if local_index < tree.inner_f.len() { + return Some(&tree.inner_f[local_index]); + } + local_index -= tree.inner_f.len(); + + if local_index < tree.middle.len() { + return Some(tree.middle.index(tree.middle_level, local_index)); + } + local_index -= tree.middle.len(); + + if local_index < tree.inner_b.len() { + return Some(&tree.inner_b[local_index]); + } + local_index -= tree.inner_b.len(); + + Some(&tree.outer_b[local_index]) + } + } + } + + /// Get a mutable reference to the value at index `index` in a + /// vector. + /// + /// Returns `None` if the index is out of bounds. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector!["Joe", "Mike", "Robert"]; + /// { + /// let robert = vec.get_mut(2).unwrap(); + /// assert_eq!(&mut "Robert", robert); + /// *robert = "Bjarne"; + /// } + /// assert_eq!(vector!["Joe", "Mike", "Bjarne"], vec); + /// # } + /// ``` + #[must_use] + pub fn get_mut(&mut self, index: usize) -> Option<&mut A> { + if index >= self.len() { + return None; + } + + match self { + Empty => None, + Single(chunk) => Ref::make_mut(chunk).get_mut(index), + Full(tree) => { + let mut local_index = index; + + if local_index < tree.outer_f.len() { + let outer_f = Ref::make_mut(&mut tree.outer_f); + return Some(&mut outer_f[local_index]); + } + local_index -= tree.outer_f.len(); + + if local_index < tree.inner_f.len() { + let inner_f = Ref::make_mut(&mut tree.inner_f); + return Some(&mut inner_f[local_index]); + } + local_index -= tree.inner_f.len(); + + if local_index < tree.middle.len() { + let middle = Ref::make_mut(&mut tree.middle); + return Some(middle.index_mut(tree.middle_level, local_index)); + } + local_index -= tree.middle.len(); + + if local_index < tree.inner_b.len() { + let inner_b = Ref::make_mut(&mut tree.inner_b); + return Some(&mut inner_b[local_index]); + } + local_index -= tree.inner_b.len(); + + let outer_b = Ref::make_mut(&mut tree.outer_b); + Some(&mut outer_b[local_index]) + } + } + } + + /// Get the first element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// Time: O(log n) + #[inline] + #[must_use] + pub fn front(&self) -> Option<&A> { + self.get(0) + } + + /// Get a mutable reference to the first element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// Time: O(log n) + #[inline] + #[must_use] + pub fn front_mut(&mut self) -> Option<&mut A> { + self.get_mut(0) + } + + /// Get the first element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// This is an alias for the [`front`][front] method. + /// + /// Time: O(log n) + /// + /// [front]: #method.front + #[inline] + #[must_use] + pub fn head(&self) -> Option<&A> { + self.get(0) + } + + /// Get the last element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// Time: O(log n) + #[must_use] + pub fn back(&self) -> Option<&A> { + if self.is_empty() { + None + } else { + self.get(self.len() - 1) + } + } + + /// Get a mutable reference to the last element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// Time: O(log n) + #[must_use] + pub fn back_mut(&mut self) -> Option<&mut A> { + if self.is_empty() { + None + } else { + let len = self.len(); + self.get_mut(len - 1) + } + } + + /// Get the last element of a vector. + /// + /// If the vector is empty, `None` is returned. + /// + /// This is an alias for the [`back`][back] method. + /// + /// Time: O(log n) + /// + /// [back]: #method.back + #[inline] + #[must_use] + pub fn last(&self) -> Option<&A> { + self.back() + } + + /// Get the index of a given element in the vector. + /// + /// Searches the vector for the first occurrence of a given value, + /// and returns the index of the value if it's there. Otherwise, + /// it returns `None`. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 4, 5]; + /// assert_eq!(Some(2), vec.index_of(&3)); + /// assert_eq!(None, vec.index_of(&31337)); + /// # } + /// ``` + #[must_use] + pub fn index_of(&self, value: &A) -> Option + where + A: PartialEq, + { + for (index, item) in self.iter().enumerate() { + if value == item { + return Some(index); + } + } + None + } + + /// Test if a given element is in the vector. + /// + /// Searches the vector for the first occurrence of a given value, + /// and returns `true if it's there. If it's nowhere to be found + /// in the vector, it returns `false`. + /// + /// Time: O(n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 4, 5]; + /// assert_eq!(true, vec.contains(&3)); + /// assert_eq!(false, vec.contains(&31337)); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn contains(&self, value: &A) -> bool + where + A: PartialEq, + { + self.index_of(value).is_some() + } + + /// Discard all elements from the vector. + /// + /// This leaves you with an empty vector, and all elements that + /// were previously inside it are dropped. + /// + /// Time: O(n) + pub fn clear(&mut self) { + if !self.is_empty() { + *self = Single(Ref::new(Chunk::new())); + } + } + + /// Binary search a sorted vector for a given element using a comparator + /// function. + /// + /// Assumes the vector has already been sorted using the same comparator + /// function, eg. by using [`sort_by`][sort_by]. + /// + /// If the value is found, it returns `Ok(index)` where `index` is the index + /// of the element. If the value isn't found, it returns `Err(index)` where + /// `index` is the index at which the element would need to be inserted to + /// maintain sorted order. + /// + /// Time: O(log n) + /// + /// [sort_by]: #method.sort_by + #[must_use] + pub fn binary_search_by(&self, mut f: F) -> Result + where + F: FnMut(&A) -> Ordering, + { + let mut size = self.len(); + if size == 0 { + return Err(0); + } + let mut base = 0; + while size > 1 { + let half = size / 2; + let mid = base + half; + base = match f(&self[mid]) { + Ordering::Greater => base, + _ => mid, + }; + size -= half; + } + match f(&self[base]) { + Ordering::Equal => Ok(base), + Ordering::Greater => Err(base), + Ordering::Less => Err(base + 1), + } + } + + /// Binary search a sorted vector for a given element. + /// + /// If the value is found, it returns `Ok(index)` where `index` is the index + /// of the element. If the value isn't found, it returns `Err(index)` where + /// `index` is the index at which the element would need to be inserted to + /// maintain sorted order. + /// + /// Time: O(log n) + #[must_use] + pub fn binary_search(&self, value: &A) -> Result + where + A: Ord, + { + self.binary_search_by(|e| e.cmp(value)) + } + + /// Binary search a sorted vector for a given element with a key extract + /// function. + /// + /// Assumes the vector has already been sorted using the same key extract + /// function, eg. by using [`sort_by_key`][sort_by_key]. + /// + /// If the value is found, it returns `Ok(index)` where `index` is the index + /// of the element. If the value isn't found, it returns `Err(index)` where + /// `index` is the index at which the element would need to be inserted to + /// maintain sorted order. + /// + /// Time: O(log n) + /// + /// [sort_by_key]: #method.sort_by_key + #[must_use] + pub fn binary_search_by_key(&self, b: &B, mut f: F) -> Result + where + F: FnMut(&A) -> B, + B: Ord, + { + self.binary_search_by(|k| f(k).cmp(b)) + } +} + +impl Vector { + /// Construct a vector with a single value. + /// + /// This method has been deprecated; use [`unit`][unit] instead. + /// + /// [unit]: #method.unit + #[inline] + #[must_use] + #[deprecated(since = "12.3.0", note = "renamed to `unit` for consistency")] + pub fn singleton(a: A) -> Self { + Self::unit(a) + } + + /// Construct a vector with a single value. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let vec = Vector::unit(1337); + /// assert_eq!(1, vec.len()); + /// assert_eq!( + /// vec.get(0), + /// Some(&1337) + /// ); + /// # } + /// ``` + #[inline] + #[must_use] + pub fn unit(a: A) -> Self { + Single(Ref::new(Chunk::unit(a))) + } + + /// Create a new vector with the value at index `index` updated. + /// + /// Panics if the index is out of bounds. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3]; + /// assert_eq!(vector![1, 5, 3], vec.update(1, 5)); + /// # } + /// ``` + #[must_use] + pub fn update(&self, index: usize, value: A) -> Self { + let mut out = self.clone(); + out[index] = value; + out + } + + /// Update the value at index `index` in a vector. + /// + /// Returns the previous value at the index. + /// + /// Panics if the index is out of bounds. + /// + /// Time: O(log n) + #[inline] + pub fn set(&mut self, index: usize, value: A) -> A { + replace(&mut self[index], value) + } + + /// Swap the elements at indices `i` and `j`. + /// + /// Time: O(log n) + pub fn swap(&mut self, i: usize, j: usize) { + swap_indices(self, i, j) + } + + /// Push a value to the front of a vector. + /// + /// Time: O(1)* + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![5, 6, 7]; + /// vec.push_front(4); + /// assert_eq!(vector![4, 5, 6, 7], vec); + /// # } + /// ``` + pub fn push_front(&mut self, value: A) { + if self.needs_promotion() { + self.promote_back(); + } + match self { + Empty => unreachable!("promote should have promoted the Empty"), + Single(chunk) => Ref::make_mut(chunk).push_front(value), + Full(tree) => tree.push_front(value), + } + } + + /// Push a value to the back of a vector. + /// + /// Time: O(1)* + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3]; + /// vec.push_back(4); + /// assert_eq!(vector![1, 2, 3, 4], vec); + /// # } + /// ``` + pub fn push_back(&mut self, value: A) { + if self.needs_promotion() { + self.promote_front(); + } + match self { + Empty => unreachable!("promote should have promoted the Empty"), + Single(chunk) => Ref::make_mut(chunk).push_back(value), + Full(tree) => tree.push_back(value), + } + } + + /// Remove the first element from a vector and return it. + /// + /// Time: O(1)* + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3]; + /// assert_eq!(Some(1), vec.pop_front()); + /// assert_eq!(vector![2, 3], vec); + /// # } + /// ``` + pub fn pop_front(&mut self) -> Option { + if self.is_empty() { + None + } else { + match self { + Empty => None, + Single(chunk) => Some(Ref::make_mut(chunk).pop_front()), + Full(tree) => tree.pop_front(), + } + } + } + + /// Remove the last element from a vector and return it. + /// + /// Time: O(1)* + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3]; + /// assert_eq!(Some(3), vec.pop_back()); + /// assert_eq!(vector![1, 2], vec); + /// # } + /// ``` + pub fn pop_back(&mut self) -> Option { + if self.is_empty() { + None + } else { + match self { + Empty => None, + Single(chunk) => Some(Ref::make_mut(chunk).pop_back()), + Full(tree) => tree.pop_back(), + } + } + } + + /// Append the vector `other` to the end of the current vector. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3]; + /// vec.append(vector![7, 8, 9]); + /// assert_eq!(vector![1, 2, 3, 7, 8, 9], vec); + /// # } + /// ``` + pub fn append(&mut self, mut other: Self) { + if other.is_empty() { + return; + } + + if self.is_empty() { + replace(self, other); + return; + } + + let total_length = self + .len() + .checked_add(other.len()) + .expect("Vector length overflow"); + + match self { + Empty => unreachable!("empty vecs are handled before this"), + Single(left) => { + match other { + // If both are single chunks and left has room for right: directly + // memcpy right into left + Single(ref mut right) if total_length <= CHUNK_SIZE => { + Ref::make_mut(left).append(Ref::make_mut(right)); + return; + } + // If only left is a single chunk and has room for right: push + // right's elements into left + ref mut right if total_length <= CHUNK_SIZE => { + while let Some(value) = right.pop_front() { + Ref::make_mut(left).push_back(value); + } + return; + } + _ => {} + } + } + Full(left) => { + if let Full(mut right) = other { + // If left and right are trees with empty middles, left has no back + // buffers, and right has no front buffers: copy right's back + // buffers over to left + if left.middle.is_empty() + && right.middle.is_empty() + && left.outer_b.is_empty() + && left.inner_b.is_empty() + && right.outer_f.is_empty() + && right.inner_f.is_empty() + { + left.inner_b = right.inner_b; + left.outer_b = right.outer_b; + left.length = total_length; + return; + } + // If left and right are trees with empty middles and left's buffers + // can fit right's buffers: push right's elements onto left + if left.middle.is_empty() + && right.middle.is_empty() + && total_length <= CHUNK_SIZE * 4 + { + while let Some(value) = right.pop_front() { + left.push_back(value); + } + return; + } + // Both are full and big: do the full RRB join + let inner_b1 = left.inner_b.clone(); + left.push_middle(Side::Right, inner_b1); + let outer_b1 = left.outer_b.clone(); + left.push_middle(Side::Right, outer_b1); + let inner_f2 = right.inner_f.clone(); + right.push_middle(Side::Left, inner_f2); + let outer_f2 = right.outer_f.clone(); + right.push_middle(Side::Left, outer_f2); + + let mut middle1 = clone_ref(replace(&mut left.middle, Ref::from(Node::new()))); + let mut middle2 = clone_ref(right.middle); + let normalised_middle = if left.middle_level > right.middle_level { + middle2 = middle2.elevate(left.middle_level - right.middle_level); + left.middle_level + } else if left.middle_level < right.middle_level { + middle1 = middle1.elevate(right.middle_level - left.middle_level); + right.middle_level + } else { + left.middle_level + }; + left.middle = Ref::new(Node::merge( + Ref::from(middle1), + Ref::from(middle2), + normalised_middle, + )); + left.middle_level = normalised_middle + 1; + + left.inner_b = right.inner_b; + left.outer_b = right.outer_b; + left.length = total_length; + left.prune(); + return; + } + } + } + // No optimisations available, and either left, right or both are + // single: promote both to full and retry + self.promote_front(); + other.promote_back(); + self.append(other) + } + + /// Retain only the elements specified by the predicate. + /// + /// Remove all elements for which the provided function `f` + /// returns false from the vector. + /// + /// Time: O(n) + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&A) -> bool, + { + let len = self.len(); + let mut del = 0; + { + let mut focus = self.focus_mut(); + for i in 0..len { + if !f(focus.index(i)) { + del += 1; + } else if del > 0 { + focus.swap(i - del, i); + } + } + } + if del > 0 { + self.split_off(len - del); + } + } + + /// Split a vector at a given index. + /// + /// Split a vector at a given index, consuming the vector and + /// returning a pair of the left hand side and the right hand side + /// of the split. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 7, 8, 9]; + /// let (left, right) = vec.split_at(3); + /// assert_eq!(vector![1, 2, 3], left); + /// assert_eq!(vector![7, 8, 9], right); + /// # } + /// ``` + pub fn split_at(mut self, index: usize) -> (Self, Self) { + let right = self.split_off(index); + (self, right) + } + + /// Split a vector at a given index. + /// + /// Split a vector at a given index, leaving the left hand side in + /// the current vector and returning a new vector containing the + /// right hand side. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut left = vector![1, 2, 3, 7, 8, 9]; + /// let right = left.split_off(3); + /// assert_eq!(vector![1, 2, 3], left); + /// assert_eq!(vector![7, 8, 9], right); + /// # } + /// ``` + pub fn split_off(&mut self, index: usize) -> Self { + assert!(index <= self.len()); + + match self { + Empty => Empty, + Single(chunk) => Single(Ref::new(Ref::make_mut(chunk).split_off(index))), + Full(tree) => { + let mut local_index = index; + + if local_index < tree.outer_f.len() { + let of2 = Ref::make_mut(&mut tree.outer_f).split_off(local_index); + let right = RRB { + length: tree.length - index, + middle_level: tree.middle_level, + outer_f: Ref::new(of2), + inner_f: replace_def(&mut tree.inner_f), + middle: replace_def(&mut tree.middle), + inner_b: replace_def(&mut tree.inner_b), + outer_b: replace_def(&mut tree.outer_b), + }; + tree.length = index; + tree.middle_level = 0; + return Full(right); + } + + local_index -= tree.outer_f.len(); + + if local_index < tree.inner_f.len() { + let if2 = Ref::make_mut(&mut tree.inner_f).split_off(local_index); + let right = RRB { + length: tree.length - index, + middle_level: tree.middle_level, + outer_f: Ref::new(if2), + inner_f: Ref::>::default(), + middle: replace_def(&mut tree.middle), + inner_b: replace_def(&mut tree.inner_b), + outer_b: replace_def(&mut tree.outer_b), + }; + tree.length = index; + tree.middle_level = 0; + swap(&mut tree.outer_b, &mut tree.inner_f); + return Full(right); + } + + local_index -= tree.inner_f.len(); + + if local_index < tree.middle.len() { + let mut right_middle = tree.middle.clone(); + let (c1, c2) = { + let m1 = Ref::make_mut(&mut tree.middle); + let m2 = Ref::make_mut(&mut right_middle); + match m1.split(tree.middle_level, Side::Right, local_index) { + SplitResult::Dropped(_) => (), + SplitResult::OutOfBounds => unreachable!(), + }; + match m2.split(tree.middle_level, Side::Left, local_index) { + SplitResult::Dropped(_) => (), + SplitResult::OutOfBounds => unreachable!(), + }; + let c1 = match m1.pop_chunk(tree.middle_level, Side::Right) { + PopResult::Empty => Ref::>::default(), + PopResult::Done(chunk) => chunk, + PopResult::Drained(chunk) => { + m1.clear_node(); + chunk + } + }; + let c2 = match m2.pop_chunk(tree.middle_level, Side::Left) { + PopResult::Empty => Ref::>::default(), + PopResult::Done(chunk) => chunk, + PopResult::Drained(chunk) => { + m2.clear_node(); + chunk + } + }; + (c1, c2) + }; + let mut right = RRB { + length: tree.length - index, + middle_level: tree.middle_level, + outer_f: c2, + inner_f: Ref::>::default(), + middle: right_middle, + inner_b: replace_def(&mut tree.inner_b), + outer_b: replace(&mut tree.outer_b, c1), + }; + tree.length = index; + tree.prune(); + right.prune(); + return Full(right); + } + + local_index -= tree.middle.len(); + + if local_index < tree.inner_b.len() { + let ib2 = Ref::make_mut(&mut tree.inner_b).split_off(local_index); + let right = RRB { + length: tree.length - index, + outer_b: replace_def(&mut tree.outer_b), + outer_f: Ref::new(ib2), + ..RRB::new() + }; + tree.length = index; + swap(&mut tree.outer_b, &mut tree.inner_b); + return Full(right); + } + + local_index -= tree.inner_b.len(); + + let ob2 = Ref::make_mut(&mut tree.outer_b).split_off(local_index); + tree.length = index; + Single(Ref::new(ob2)) + } + } + } + + /// Construct a vector with `count` elements removed from the + /// start of the current vector. + /// + /// Time: O(log n) + #[must_use] + pub fn skip(&self, count: usize) -> Self { + // FIXME can be made more efficient by dropping the unwanted side without constructing it + self.clone().split_off(count) + } + + /// Construct a vector of the first `count` elements from the + /// current vector. + /// + /// Time: O(log n) + #[must_use] + pub fn take(&self, count: usize) -> Self { + // FIXME can be made more efficient by dropping the unwanted side without constructing it + let mut left = self.clone(); + left.split_off(count); + left + } + + /// Truncate a vector to the given size. + /// + /// Discards all elements in the vector beyond the given length. + /// + /// Panics if the new length is greater than the current length. + /// + /// Time: O(log n) + pub fn truncate(&mut self, len: usize) { + // FIXME can be made more efficient by dropping the unwanted side without constructing it + self.split_off(len); + } + + /// Extract a slice from a vector. + /// + /// Remove the elements from `start_index` until `end_index` in + /// the current vector and return the removed slice as a new + /// vector. + /// + /// Time: O(log n) + pub fn slice(&mut self, range: R) -> Self + where + R: RangeBounds, + { + let r = to_range(&range, self.len()); + if r.start >= r.end || r.start >= self.len() { + return Vector::new(); + } + let mut middle = self.split_off(r.start); + let right = middle.split_off(r.end - r.start); + self.append(right); + middle + } + + /// Insert an element into a vector. + /// + /// Insert an element at position `index`, shifting all elements + /// after it to the right. + /// + /// ## Performance Note + /// + /// While `push_front` and `push_back` are heavily optimised + /// operations, `insert` in the middle of a vector requires a + /// split, a push, and an append. Thus, if you want to insert + /// many elements at the same location, instead of `insert`ing + /// them one by one, you should rather create a new vector + /// containing the elements to insert, split the vector at the + /// insertion point, and append the left hand, the new vector and + /// the right hand in order. + /// + /// Time: O(log n) + pub fn insert(&mut self, index: usize, value: A) { + if index == 0 { + return self.push_front(value); + } + if index == self.len() { + return self.push_back(value); + } + assert!(index < self.len()); + match self { + Single(chunk) if chunk.len() < CHUNK_SIZE => Ref::make_mut(chunk).insert(index, value), + // TODO a lot of optimisations still possible here + _ => { + let right = self.split_off(index); + self.push_back(value); + self.append(right); + } + } + } + + /// Remove an element from a vector. + /// + /// Remove the element from position 'index', shifting all + /// elements after it to the left, and return the removec element. + /// + /// ## Performance Note + /// + /// While `pop_front` and `pop_back` are heavily optimised + /// operations, `remove` in the middle of a vector requires a + /// split, a pop, and an append. Thus, if you want to remove many + /// elements from the same location, instead of `remove`ing them + /// one by one, it is much better to use [`slice`][slice]. + /// + /// Time: O(log n) + /// + /// [slice]: #method.slice + pub fn remove(&mut self, index: usize) -> A { + assert!(index < self.len()); + match self { + Single(chunk) => Ref::make_mut(chunk).remove(index), + _ => { + if index == 0 { + return self.pop_front().unwrap(); + } + if index == self.len() - 1 { + return self.pop_back().unwrap(); + } + // TODO a lot of optimisations still possible here + let mut right = self.split_off(index); + let value = right.pop_front().unwrap(); + self.append(right); + value + } + } + } + + /// Insert an element into a sorted vector. + /// + /// Insert an element into a vector in sorted order, assuming the vector is + /// already in sorted order. + /// + /// Time: O(log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut vec = vector![1, 2, 3, 7, 8, 9]; + /// vec.insert_ord(5); + /// assert_eq!(vector![1, 2, 3, 5, 7, 8, 9], vec); + /// # } + /// ``` + pub fn insert_ord(&mut self, item: A) + where + A: Ord, + { + match self.binary_search(&item) { + Ok(index) => self.insert(index, item), + Err(index) => self.insert(index, item), + } + } + + /// Sort a vector. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut vec = vector![3, 2, 5, 4, 1]; + /// vec.sort(); + /// assert_eq!(vector![1, 2, 3, 4, 5], vec); + /// # } + /// ``` + pub fn sort(&mut self) + where + A: Ord, + { + self.sort_by(Ord::cmp) + } + + /// Sort a vector using a comparator function. + /// + /// Time: O(n log n) + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate im_rc as im; + /// # use im::vector::Vector; + /// # fn main() { + /// let mut vec = vector![3, 2, 5, 4, 1]; + /// vec.sort_by(|left, right| left.cmp(right)); + /// assert_eq!(vector![1, 2, 3, 4, 5], vec); + /// # } + /// ``` + pub fn sort_by(&mut self, cmp: F) + where + F: Fn(&A, &A) -> Ordering, + { + let len = self.len(); + if len > 1 { + sort::quicksort(&mut self.focus_mut(), 0, len - 1, &cmp); + } + } + + #[allow(dead_code)] + pub(crate) fn assert_invariants(&self) { + if let Vector::Full(ref tree) = self { + tree.middle.assert_invariants(); + } + } +} + +// Implementation details + +impl RRB { + fn into_iter( + self, + ) -> Chain< + Chain, ChunkIter>, ConsumingNodeIter>, ChunkIter>, + ChunkIter, + > { + let outer_f = clone_ref(self.outer_f).into_iter(); + let inner_f = clone_ref(self.inner_f).into_iter(); + let middle = ConsumingNodeIter::new(clone_ref(self.middle), self.middle_level); + let inner_b = clone_ref(self.inner_b).into_iter(); + let outer_b = clone_ref(self.outer_b).into_iter(); + outer_f + .chain(inner_f) + .chain(middle) + .chain(inner_b) + .chain(outer_b) + } + + fn new() -> Self { + RRB { + length: 0, + middle_level: 0, + outer_f: Ref::new(Chunk::new()), + inner_f: Ref::new(Chunk::new()), + middle: Ref::new(Node::new()), + inner_b: Ref::new(Chunk::new()), + outer_b: Ref::new(Chunk::new()), + } + } + + fn prune(&mut self) { + if self.middle.is_empty() { + self.middle = Ref::new(Node::new()); + self.middle_level = 0; + } else { + while self.middle_level > 0 && self.middle.is_single() { + self.middle = self.middle.first_child().clone(); + self.middle_level -= 1; + } + } + } + + fn pop_front(&mut self) -> Option { + if self.length == 0 { + return None; + } + if self.outer_f.is_empty() { + if self.inner_f.is_empty() { + if self.middle.is_empty() { + if self.inner_b.is_empty() { + swap(&mut self.outer_f, &mut self.outer_b); + } else { + swap(&mut self.outer_f, &mut self.inner_b); + } + } else { + self.outer_f = self.pop_middle(Side::Left).unwrap(); + } + } else { + swap(&mut self.outer_f, &mut self.inner_f); + } + } + self.length -= 1; + let outer_f = Ref::make_mut(&mut self.outer_f); + Some(outer_f.pop_front()) + } + + fn pop_back(&mut self) -> Option { + if self.length == 0 { + return None; + } + if self.outer_b.is_empty() { + if self.inner_b.is_empty() { + if self.middle.is_empty() { + if self.inner_f.is_empty() { + swap(&mut self.outer_b, &mut self.outer_f); + } else { + swap(&mut self.outer_b, &mut self.inner_f); + } + } else { + self.outer_b = self.pop_middle(Side::Right).unwrap(); + } + } else { + swap(&mut self.outer_b, &mut self.inner_b); + } + } + self.length -= 1; + let outer_b = Ref::make_mut(&mut self.outer_b); + Some(outer_b.pop_back()) + } + + fn push_front(&mut self, value: A) { + if self.outer_f.is_full() { + swap(&mut self.outer_f, &mut self.inner_f); + if !self.outer_f.is_empty() { + let mut chunk = Ref::new(Chunk::new()); + swap(&mut chunk, &mut self.outer_f); + self.push_middle(Side::Left, chunk); + } + } + self.length = self.length.checked_add(1).expect("Vector length overflow"); + let outer_f = Ref::make_mut(&mut self.outer_f); + outer_f.push_front(value) + } + + fn push_back(&mut self, value: A) { + if self.outer_b.is_full() { + swap(&mut self.outer_b, &mut self.inner_b); + if !self.outer_b.is_empty() { + let mut chunk = Ref::new(Chunk::new()); + swap(&mut chunk, &mut self.outer_b); + self.push_middle(Side::Right, chunk); + } + } + self.length = self.length.checked_add(1).expect("Vector length overflow"); + let outer_b = Ref::make_mut(&mut self.outer_b); + outer_b.push_back(value) + } + + fn push_middle(&mut self, side: Side, chunk: Ref>) { + if chunk.is_empty() { + return; + } + let new_middle = { + let middle = Ref::make_mut(&mut self.middle); + match middle.push_chunk(self.middle_level, side, chunk) { + PushResult::Done => return, + PushResult::Full(chunk, _num_drained) => Ref::from({ + match side { + Side::Left => Node::from_chunk(self.middle_level, chunk) + .join_branches(middle.clone(), self.middle_level), + Side::Right => middle.clone().join_branches( + Node::from_chunk(self.middle_level, chunk), + self.middle_level, + ), + } + }), + } + }; + self.middle_level += 1; + self.middle = new_middle; + } + + fn pop_middle(&mut self, side: Side) -> Option>> { + let chunk = { + let middle = Ref::make_mut(&mut self.middle); + match middle.pop_chunk(self.middle_level, side) { + PopResult::Empty => return None, + PopResult::Done(chunk) => chunk, + PopResult::Drained(chunk) => { + middle.clear_node(); + self.middle_level = 0; + chunk + } + } + }; + Some(chunk) + } +} + +#[inline] +fn replace_def(dest: &mut A) -> A { + replace(dest, Default::default()) +} + +// Core traits + +impl Default for Vector { + fn default() -> Self { + Self::new() + } +} + +impl Clone for Vector { + fn clone(&self) -> Self { + match self { + Empty => Empty, + Single(chunk) => Single(chunk.clone()), + Full(tree) => Full(tree.clone()), + } + } +} + +impl Debug for Vector { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.debug_list().entries(self.iter()).finish() + // match self { + // Full(rrb) => { + // writeln!(f, "Head: {:?} {:?}", rrb.outer_f, rrb.inner_f)?; + // rrb.middle.print(f, 0, rrb.middle_level)?; + // writeln!(f, "Tail: {:?} {:?}", rrb.inner_b, rrb.outer_b) + // } + // Single(_) => write!(f, "nowt"), + // } + } +} + +#[cfg(not(has_specialisation))] +impl PartialEq for Vector { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other.iter()) + } +} + +#[cfg(has_specialisation)] +impl PartialEq for Vector { + default fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other.iter()) + } +} + +#[cfg(has_specialisation)] +impl PartialEq for Vector { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Full(left), Full(right)) => { + if left.length != right.length { + return false; + } + + fn cmp_chunk(left: &Ref>, right: &Ref>) -> bool { + (left.is_empty() && right.is_empty()) || Ref::ptr_eq(left, right) + } + + if cmp_chunk(&left.outer_f, &right.outer_f) + && cmp_chunk(&left.inner_f, &right.inner_f) + && cmp_chunk(&left.inner_b, &right.inner_b) + && cmp_chunk(&left.outer_b, &right.outer_b) + && (left.middle.is_empty() && right.middle.is_empty()) + || Ref::ptr_eq(&left.middle, &right.middle) + { + return true; + } + self.iter().eq(other.iter()) + } + (left, right) => left.len() == right.len() && left.iter().eq(right.iter()), + } + } +} + +impl Eq for Vector {} + +impl PartialOrd for Vector { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other.iter()) + } +} + +impl Ord for Vector { + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl Hash for Vector { + fn hash(&self, state: &mut H) { + for i in self { + i.hash(state) + } + } +} + +impl Sum for Vector { + fn sum(it: I) -> Self + where + I: Iterator, + { + it.fold(Self::new(), |a, b| a + b) + } +} + +impl Add for Vector { + type Output = Vector; + + /// Concatenate two vectors. + /// + /// Time: O(log n) + fn add(mut self, other: Self) -> Self::Output { + self.append(other); + self + } +} + +impl<'a, A: Clone> Add for &'a Vector { + type Output = Vector; + + /// Concatenate two vectors. + /// + /// Time: O(log n) + fn add(self, other: Self) -> Self::Output { + let mut out = self.clone(); + out.append(other.clone()); + out + } +} + +impl Extend for Vector { + /// Add values to the end of a vector by consuming an iterator. + /// + /// Time: O(n) + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + for item in iter { + self.push_back(item) + } + } +} + +impl Index for Vector { + type Output = A; + /// Get a reference to the value at index `index` in the vector. + /// + /// Time: O(log n) + fn index(&self, index: usize) -> &Self::Output { + match self.get(index) { + Some(value) => value, + None => panic!( + "Vector::index: index out of bounds: {} < {}", + index, + self.len() + ), + } + } +} + +impl IndexMut for Vector { + /// Get a mutable reference to the value at index `index` in the + /// vector. + /// + /// Time: O(log n) + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + match self.get_mut(index) { + Some(value) => value, + None => panic!("Vector::index_mut: index out of bounds"), + } + } +} + +// Conversions + +impl<'a, A: Clone> IntoIterator for &'a Vector { + type Item = &'a A; + type IntoIter = Iter<'a, A>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Vector { + type Item = A; + type IntoIter = ConsumingIter; + fn into_iter(self) -> Self::IntoIter { + ConsumingIter::new(self) + } +} + +impl FromIterator for Vector { + /// Create a vector from an iterator. + /// + /// Time: O(n) + fn from_iter(iter: I) -> Self + where + I: IntoIterator, + { + let mut seq = Self::new(); + for item in iter { + seq.push_back(item) + } + seq + } +} + +impl<'s, 'a, A, OA> From<&'s Vector<&'a A>> for Vector +where + A: ToOwned, + OA: Borrow + Clone, +{ + fn from(vec: &Vector<&A>) -> Self { + vec.iter().map(|a| (*a).to_owned()).collect() + } +} + +impl<'a, A: Clone> From<&'a [A]> for Vector { + fn from(slice: &[A]) -> Self { + slice.iter().cloned().collect() + } +} + +impl From> for Vector { + /// Create a vector from a [`std::vec::Vec`][vec]. + /// + /// Time: O(n) + /// + /// [vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html + fn from(vec: Vec) -> Self { + vec.into_iter().collect() + } +} + +impl<'a, A: Clone> From<&'a Vec> for Vector { + /// Create a vector from a [`std::vec::Vec`][vec]. + /// + /// Time: O(n) + /// + /// [vec]: https://doc.rust-lang.org/std/vec/struct.Vec.html + fn from(vec: &Vec) -> Self { + vec.iter().cloned().collect() + } +} + +// Iterators + +/// An iterator over vectors with values of type `A`. +/// +/// To obtain one, use [`Vector::iter()`][iter]. +/// +/// [iter]: enum.Vector.html#method.iter +pub struct Iter<'a, A: 'a> { + focus: Focus<'a, A>, + front_index: usize, + back_index: usize, +} + +impl<'a, A: Clone> Iter<'a, A> { + fn new(seq: &'a Vector) -> Self { + Iter { + focus: seq.focus(), + front_index: 0, + back_index: seq.len(), + } + } + + fn from_focus(focus: Focus<'a, A>) -> Self { + Iter { + front_index: 0, + back_index: focus.len(), + focus, + } + } +} + +impl<'a, A: Clone> Iterator for Iter<'a, A> { + type Item = &'a A; + + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + #[allow(unsafe_code)] + let focus: &'a mut Focus<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let value = focus.get(self.front_index); + self.front_index += 1; + value + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = self.back_index - self.front_index; + (remaining, Some(remaining)) + } +} + +impl<'a, A: Clone> DoubleEndedIterator for Iter<'a, A> { + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next_back(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + self.back_index -= 1; + #[allow(unsafe_code)] + let focus: &'a mut Focus<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + focus.get(self.back_index) + } +} + +impl<'a, A: Clone> ExactSizeIterator for Iter<'a, A> {} + +impl<'a, A: Clone> FusedIterator for Iter<'a, A> {} + +/// A mutable iterator over vectors with values of type `A`. +/// +/// To obtain one, use [`Vector::iter_mut()`][iter_mut]. +/// +/// [iter_mut]: enum.Vector.html#method.iter_mut +pub struct IterMut<'a, A> +where + A: 'a, +{ + focus: FocusMut<'a, A>, + front_index: usize, + back_index: usize, +} + +impl<'a, A> IterMut<'a, A> +where + A: 'a + Clone, +{ + fn new(seq: &'a mut Vector) -> Self { + let focus = seq.focus_mut(); + let len = focus.len(); + IterMut { + focus, + front_index: 0, + back_index: len, + } + } + + fn from_focus(focus: FocusMut<'a, A>) -> Self { + IterMut { + front_index: 0, + back_index: focus.len(), + focus, + } + } +} + +impl<'a, A> Iterator for IterMut<'a, A> +where + A: 'a + Clone, +{ + type Item = &'a mut A; + + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + #[allow(unsafe_code)] + let focus: &'a mut FocusMut<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let value = focus.get_mut(self.front_index); + self.front_index += 1; + value + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = self.back_index - self.front_index; + (remaining, Some(remaining)) + } +} + +impl<'a, A> DoubleEndedIterator for IterMut<'a, A> +where + A: 'a + Clone, +{ + /// Remove and return an element from the back of the iterator. + /// + /// Time: O(1)* + fn next_back(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + self.back_index -= 1; + #[allow(unsafe_code)] + let focus: &'a mut FocusMut<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + focus.get_mut(self.back_index) + } +} + +impl<'a, A: Clone> ExactSizeIterator for IterMut<'a, A> {} + +impl<'a, A: Clone> FusedIterator for IterMut<'a, A> {} + +/// A consuming iterator over vectors with values of type `A`. +pub enum ConsumingIter { + Empty, + Single(ChunkIter), + Full( + Chain< + Chain, ChunkIter>, ConsumingNodeIter>, ChunkIter>, + ChunkIter, + >, + ), +} + +impl ConsumingIter { + fn new(seq: Vector) -> Self { + match seq { + Empty => ConsumingIter::Empty, + Single(chunk) => ConsumingIter::Single(clone_ref(chunk).into_iter()), + Full(tree) => ConsumingIter::Full(tree.into_iter()), + } + } +} + +impl Iterator for ConsumingIter { + type Item = A; + + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next(&mut self) -> Option { + match self { + ConsumingIter::Empty => None, + ConsumingIter::Single(iter) => iter.next(), + ConsumingIter::Full(iter) => iter.next(), + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + ConsumingIter::Empty => (0, Some(0)), + ConsumingIter::Single(iter) => iter.size_hint(), + ConsumingIter::Full(iter) => iter.size_hint(), + } + } +} + +impl DoubleEndedIterator for ConsumingIter { + /// Remove and return an element from the back of the iterator. + /// + /// Time: O(1)* + fn next_back(&mut self) -> Option { + match self { + ConsumingIter::Empty => None, + ConsumingIter::Single(iter) => iter.next_back(), + ConsumingIter::Full(iter) => iter.next_back(), + } + } +} + +impl ExactSizeIterator for ConsumingIter {} + +impl FusedIterator for ConsumingIter {} + +/// An iterator over the leaf nodes of a vector. +/// +/// To obtain one, use [`Vector::chunks()`][chunks]. +/// +/// [chunks]: enum.Vector.html#method.chunks +pub struct Chunks<'a, A: 'a> { + focus: Focus<'a, A>, + front_index: usize, + back_index: usize, +} + +impl<'a, A: Clone> Chunks<'a, A> { + fn new(seq: &'a Vector) -> Self { + Chunks { + focus: seq.focus(), + front_index: 0, + back_index: seq.len(), + } + } +} + +impl<'a, A: Clone> Iterator for Chunks<'a, A> { + type Item = &'a [A]; + + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + #[allow(unsafe_code)] + let focus: &'a mut Focus<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let (range, value) = focus.chunk_at(self.front_index); + self.front_index = range.end; + Some(value) + } +} + +impl<'a, A: Clone> DoubleEndedIterator for Chunks<'a, A> { + /// Remove and return an element from the back of the iterator. + /// + /// Time: O(1)* + fn next_back(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + self.back_index -= 1; + #[allow(unsafe_code)] + let focus: &'a mut Focus<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let (range, value) = focus.chunk_at(self.back_index); + self.back_index = range.start; + Some(value) + } +} + +impl<'a, A: Clone> FusedIterator for Chunks<'a, A> {} + +/// A mutable iterator over the leaf nodes of a vector. +/// +/// To obtain one, use [`Vector::chunks_mut()`][chunks_mut]. +/// +/// [chunks_mut]: enum.Vector.html#method.chunks_mut +pub struct ChunksMut<'a, A: 'a> { + focus: FocusMut<'a, A>, + front_index: usize, + back_index: usize, +} + +impl<'a, A: Clone> ChunksMut<'a, A> { + fn new(seq: &'a mut Vector) -> Self { + let len = seq.len(); + ChunksMut { + focus: seq.focus_mut(), + front_index: 0, + back_index: len, + } + } +} + +impl<'a, A: Clone> Iterator for ChunksMut<'a, A> { + type Item = &'a mut [A]; + + /// Advance the iterator and return the next value. + /// + /// Time: O(1)* + fn next(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + #[allow(unsafe_code)] + let focus: &'a mut FocusMut<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let (range, value) = focus.chunk_at(self.front_index); + self.front_index = range.end; + Some(value) + } +} + +impl<'a, A: Clone> DoubleEndedIterator for ChunksMut<'a, A> { + /// Remove and return an element from the back of the iterator. + /// + /// Time: O(1)* + fn next_back(&mut self) -> Option { + if self.front_index >= self.back_index { + return None; + } + self.back_index -= 1; + #[allow(unsafe_code)] + let focus: &'a mut FocusMut<'a, A> = unsafe { &mut *(&mut self.focus as *mut _) }; + let (range, value) = focus.chunk_at(self.back_index); + self.back_index = range.start; + Some(value) + } +} + +impl<'a, A: Clone> FusedIterator for ChunksMut<'a, A> {} + +// Rayon + +#[cfg(all(threadsafe, any(test, feature = "rayon")))] +pub mod rayon { + use super::*; + + use ::rayon::iter::plumbing::{ + bridge, Consumer, Producer, ProducerCallback, UnindexedConsumer, + }; + use ::rayon::iter::{ + IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, + ParallelIterator, + }; + + impl<'a, A> IntoParallelRefIterator<'a> for Vector + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a A; + type Iter = ParIter<'a, A>; + + fn par_iter(&'a self) -> Self::Iter { + ParIter { + focus: self.focus(), + } + } + } + + impl<'a, A> IntoParallelRefMutIterator<'a> for Vector + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a mut A; + type Iter = ParIterMut<'a, A>; + + fn par_iter_mut(&'a mut self) -> Self::Iter { + ParIterMut { + focus: self.focus_mut(), + } + } + } + + pub struct ParIter<'a, A> + where + A: Clone + Send + Sync + 'a, + { + focus: Focus<'a, A>, + } + + impl<'a, A> ParallelIterator for ParIter<'a, A> + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a A; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + bridge(self, consumer) + } + } + + impl<'a, A> IndexedParallelIterator for ParIter<'a, A> + where + A: Clone + Send + Sync + 'a, + { + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + bridge(self, consumer) + } + + fn len(&self) -> usize { + self.focus.len() + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + callback.callback(VectorProducer { focus: self.focus }) + } + } + + pub struct ParIterMut<'a, A> + where + A: Clone + Send + Sync + 'a, + { + focus: FocusMut<'a, A>, + } + + impl<'a, A> ParallelIterator for ParIterMut<'a, A> + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a mut A; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + bridge(self, consumer) + } + } + + impl<'a, A> IndexedParallelIterator for ParIterMut<'a, A> + where + A: Clone + Send + Sync + 'a, + { + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + bridge(self, consumer) + } + + fn len(&self) -> usize { + self.focus.len() + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + callback.callback(VectorMutProducer { focus: self.focus }) + } + } + + struct VectorProducer<'a, A> + where + A: Clone + Send + Sync + 'a, + { + focus: Focus<'a, A>, + } + + impl<'a, A> Producer for VectorProducer<'a, A> + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a A; + type IntoIter = Iter<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + self.focus.into_iter() + } + + fn split_at(self, index: usize) -> (Self, Self) { + let (left, right) = self.focus.split_at(index); + ( + VectorProducer { focus: left }, + VectorProducer { focus: right }, + ) + } + } + + struct VectorMutProducer<'a, A> + where + A: Clone + Send + Sync + 'a, + { + focus: FocusMut<'a, A>, + } + + impl<'a, A> Producer for VectorMutProducer<'a, A> + where + A: Clone + Send + Sync + 'a, + { + type Item = &'a mut A; + type IntoIter = IterMut<'a, A>; + + fn into_iter(self) -> Self::IntoIter { + self.focus.into_iter() + } + + fn split_at(self, index: usize) -> (Self, Self) { + let (left, right) = self.focus.split_at(index); + ( + VectorMutProducer { focus: left }, + VectorMutProducer { focus: right }, + ) + } + } + + #[cfg(test)] + mod test { + use super::super::*; + use super::proptest::vector; + use ::proptest::num::i32; + use ::proptest::proptest; + use ::rayon::iter::{ + IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, + }; + + proptest! { + #[test] + fn par_iter(ref mut input in vector(i32::ANY, 0..10000)) { + assert_eq!(input.iter().max(), input.par_iter().max()) + } + + #[test] + fn par_mut_iter(ref mut input in vector(i32::ANY, 0..10000)) { + let mut vec = input.clone(); + vec.par_iter_mut().for_each(|i| *i = i.overflowing_add(1).0); + let expected: Vector = input.clone().into_iter().map(|i| i.overflowing_add(1).0).collect(); + assert_eq!(expected, vec); + } + } + } +} + +// QuickCheck +#[cfg(all(threadsafe, feature = "quickcheck"))] +use quickcheck::{Arbitrary, Gen}; + +#[cfg(all(threadsafe, feature = "quickcheck"))] +impl Arbitrary for Vector { + fn arbitrary(g: &mut G) -> Self { + Vector::from_iter(Vec::::arbitrary(g)) + } +} + +// Proptest + +#[cfg(any(test, feature = "proptest"))] +pub mod proptest { + use super::*; + use ::proptest::collection::vec; + use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree}; + use std::ops::Range; + + /// A strategy for generating a vector of a certain size. + /// + /// # Examples + /// + /// ```rust,ignore + /// proptest! { + /// #[test] + /// fn proptest_a_vector(ref l in vector(".*", 10..100)) { + /// assert!(l.len() < 100); + /// assert!(l.len() >= 10); + /// } + /// } + /// ``` + pub fn vector( + element: A, + size: Range, + ) -> BoxedStrategy::Value>> + where + ::Value: Clone, + { + vec(element, size).prop_map(Vector::from_iter).boxed() + } +} + +// Tests + +#[cfg(test)] +mod test { + use super::proptest::vector; + use super::*; + use ::proptest::collection::vec; + use ::proptest::num::{i32, usize}; + use ::proptest::proptest; + + #[test] + fn macro_allows_trailing_comma() { + let vec1 = vector![1, 2, 3]; + let vec2 = vector![1, 2, 3,]; + assert_eq!(vec1, vec2); + } + + #[test] + fn indexing() { + let vec1 = vector![0, 1, 2, 3, 4, 5]; + let mut vec2 = vec1.clone(); + vec2.push_front(0); + assert_eq!(0, *vec2.get(0).unwrap()); + assert_eq!(0, vec2[0]); + } + + #[test] + fn large_vector_focus() { + let input = Vector::from_iter(0..100_000); + let vec = input.clone(); + let mut sum: i64 = 0; + let mut focus = vec.focus(); + for i in 0..input.len() { + sum += *focus.index(i); + } + let expected: i64 = (0..100_000).sum(); + assert_eq!(expected, sum); + } + + #[test] + fn large_vector_focus_mut() { + let input = Vector::from_iter(0..100_000); + let mut vec = input.clone(); + { + let mut focus = vec.focus_mut(); + for i in 0..input.len() { + let p = focus.index_mut(i); + *p += 1; + } + } + let expected: Vector = input.clone().into_iter().map(|i| i + 1).collect(); + assert_eq!(expected, vec); + } + + #[test] + fn issue_55_fwd() { + let mut l = Vector::new(); + for i in 0..4098 { + l.append(Vector::unit(i)); + } + l.append(Vector::unit(4098)); + assert_eq!(Some(&4097), l.get(4097)); + assert_eq!(Some(&4096), l.get(4096)); + } + + #[test] + fn issue_55_back() { + let mut l = Vector::unit(0); + for i in 0..4099 { + let mut tmp = Vector::unit(i + 1); + tmp.append(l); + l = tmp; + } + assert_eq!(Some(&4098), l.get(1)); + assert_eq!(Some(&4097), l.get(2)); + let len = l.len(); + l.slice(2..len); + } + + #[test] + fn issue_55_append() { + let mut vec1 = Vector::from_iter(0..92); + let vec2 = Vector::from_iter(0..165); + vec1.append(vec2); + } + + #[test] + fn issue_70() { + let mut x = Vector::new(); + for _ in 0..262 { + x.push_back(0); + } + for _ in 0..97 { + x.pop_front(); + } + for &offset in &[160, 163, 160] { + x.remove(offset); + } + for _ in 0..64 { + x.push_back(0); + } + // At this point middle contains three chunks of size 64, 64 and 1 + // respectively. Previously the next `push_back()` would append another + // zero-sized chunk to middle even though there is enough space left. + match x { + Vector::Full(ref tree) => { + assert_eq!(129, tree.middle.len()); + assert_eq!(3, tree.middle.number_of_children()); + } + _ => unreachable!(), + } + x.push_back(0); + match x { + Vector::Full(ref tree) => { + assert_eq!(131, tree.middle.len()); + assert_eq!(3, tree.middle.number_of_children()) + } + _ => unreachable!(), + } + for _ in 0..64 { + x.push_back(0); + } + for _ in x.iter() {} + } + + #[test] + fn issue_67() { + let mut l = Vector::unit(4100); + for i in (0..4099).rev() { + let mut tmp = Vector::unit(i); + tmp.append(l); + l = tmp; + } + assert_eq!(4100, l.len()); + let len = l.len(); + let tail = l.slice(1..len); + assert_eq!(1, l.len()); + assert_eq!(4099, tail.len()); + assert_eq!(Some(&0), l.get(0)); + assert_eq!(Some(&1), tail.get(0)); + } + + #[test] + fn issue_74_simple_size() { + use crate::nodes::rrb::NODE_SIZE; + let mut x = Vector::new(); + for _ in 0..(CHUNK_SIZE + * ( + 1 // inner_f + + (2 * NODE_SIZE) // middle: two full Entry::Nodes (4096 elements each) + + 1 // inner_b + + 1 + // outer_b + )) + { + x.push_back(0u32); + } + let middle_first_node_start = CHUNK_SIZE; + let middle_second_node_start = middle_first_node_start + NODE_SIZE * CHUNK_SIZE; + // This reduces the size of the second node to 4095. + x.remove(middle_second_node_start); + // As outer_b is full, this will cause inner_b (length 64) to be pushed + // to middle. The first element will be merged into the second node, the + // remaining 63 elements will end up in a new node. + x.push_back(0u32); + match x { + Vector::Full(tree) => { + assert_eq!(3, tree.middle.number_of_children()); + assert_eq!( + 2 * NODE_SIZE * CHUNK_SIZE + CHUNK_SIZE - 1, + tree.middle.len() + ); + } + _ => unreachable!(), + } + } + + #[test] + fn issue_77() { + let mut x = Vector::new(); + for _ in 0..44 { x.push_back(0); } + for _ in 0..20 { x.insert(0, 0); } + x.insert(1, 0); + for _ in 0..441 { x.push_back(0); } + for _ in 0..58 { x.insert(0, 0); } + x.insert(514, 0); + for _ in 0..73 { x.push_back(0); } + for _ in 0..10 { x.insert(0, 0); } + x.insert(514, 0); + } + + proptest! { + #[test] + fn iter(ref vec in vec(i32::ANY, 0..1000)) { + let seq: Vector = Vector::from_iter(vec.iter().cloned()); + for (index, item) in seq.iter().enumerate() { + assert_eq!(&vec[index], item); + } + assert_eq!(vec.len(), seq.len()); + } + + #[test] + fn push_front_mut(ref input in vec(i32::ANY, 0..1000)) { + let mut vector = Vector::new(); + for (count, value) in input.iter().cloned().enumerate() { + assert_eq!(count, vector.len()); + vector.push_front(value); + assert_eq!(count + 1, vector.len()); + } + let input2 = Vec::from_iter(input.iter().rev().cloned()); + assert_eq!(input2, Vec::from_iter(vector.iter().cloned())); + } + + #[test] + fn push_back_mut(ref input in vec(i32::ANY, 0..1000)) { + let mut vector = Vector::new(); + for (count, value) in input.iter().cloned().enumerate() { + assert_eq!(count, vector.len()); + vector.push_back(value); + assert_eq!(count + 1, vector.len()); + } + assert_eq!(input, &Vec::from_iter(vector.iter().cloned())); + } + + #[test] + fn pop_back_mut(ref input in vec(i32::ANY, 0..1000)) { + let mut vector = Vector::from_iter(input.iter().cloned()); + assert_eq!(input.len(), vector.len()); + for (index, value) in input.iter().cloned().enumerate().rev() { + match vector.pop_back() { + None => panic!("vector emptied unexpectedly"), + Some(item) => { + assert_eq!(index, vector.len()); + assert_eq!(value, item); + } + } + } + assert_eq!(0, vector.len()); + } + + #[test] + fn pop_front_mut(ref input in vec(i32::ANY, 0..1000)) { + let mut vector = Vector::from_iter(input.iter().cloned()); + assert_eq!(input.len(), vector.len()); + for (index, value) in input.iter().cloned().rev().enumerate().rev() { + match vector.pop_front() { + None => panic!("vector emptied unexpectedly"), + Some(item) => { + assert_eq!(index, vector.len()); + assert_eq!(value, item); + } + } + } + assert_eq!(0, vector.len()); + } + + // #[test] + // fn push_and_pop(ref input in vec(i32::ANY, 0..1000)) { + // let mut vector = Vector::new(); + // for (count, value) in input.iter().cloned().enumerate() { + // assert_eq!(count, vector.len()); + // vector.push_back(value); + // assert_eq!(count + 1, vector.len()); + // } + // for (index, value) in input.iter().cloned().rev().enumerate().rev() { + // match vector.pop_front() { + // None => panic!("vector emptied unexpectedly"), + // Some(item) => { + // assert_eq!(index, vector.len()); + // assert_eq!(value, item); + // } + // } + // } + // assert_eq!(true, vector.is_empty()); + // } + + #[test] + fn split(ref vec in vec(i32::ANY, 1..2000), split_pos in usize::ANY) { + let split_index = split_pos % (vec.len() + 1); + let mut left = Vector::from_iter(vec.iter().cloned()); + let right = left.split_off(split_index); + assert_eq!(left.len(), split_index); + assert_eq!(right.len(), vec.len() - split_index); + for (index, item) in left.iter().enumerate() { + assert_eq!(& vec[index], item); + } + for (index, item) in right.iter().enumerate() { + assert_eq!(&vec[split_index + index], item); + } + } + + #[test] + fn append(ref vec1 in vec(i32::ANY, 0..1000), ref vec2 in vec(i32::ANY, 0..1000)) { + let mut seq1 = Vector::from_iter(vec1.iter().cloned()); + let seq2 = Vector::from_iter(vec2.iter().cloned()); + assert_eq!(seq1.len(), vec1.len()); + assert_eq!(seq2.len(), vec2.len()); + seq1.append(seq2); + let mut vec = vec1.clone(); + vec.extend(vec2); + assert_eq!(seq1.len(), vec.len()); + for (index, item) in seq1.into_iter().enumerate() { + assert_eq!(vec[index], item); + } + } + + #[test] + fn iter_mut(ref input in vector(i32::ANY, 0..10000)) { + let mut vec = input.clone(); + { + for p in vec.iter_mut() { + *p = p.overflowing_add(1).0; + } + } + let expected: Vector = input.clone().into_iter().map(|i| i.overflowing_add(1).0).collect(); + assert_eq!(expected, vec); + } + + #[test] + fn focus(ref input in vector(i32::ANY, 0..10000)) { + let mut vec = input.clone(); + { + let mut focus = vec.focus_mut(); + for i in 0..input.len() { + let p = focus.index_mut(i); + *p = p.overflowing_add(1).0; + } + } + let expected: Vector = input.clone().into_iter().map(|i| i.overflowing_add(1).0).collect(); + assert_eq!(expected, vec); + } + + #[test] + fn focus_mut_split(ref input in vector(i32::ANY, 0..10000)) { + let mut vec = input.clone(); + + fn split_down(focus: FocusMut<'_, i32>) { + let len = focus.len(); + if len < 8 { + for p in focus { + *p = p.overflowing_add(1).0; + } + } else { + let (left, right) = focus.split_at(len / 2); + split_down(left); + split_down(right); + } + } + + split_down(vec.focus_mut()); + + let expected: Vector = input.clone().into_iter().map(|i| i.overflowing_add(1).0).collect(); + assert_eq!(expected, vec); + } + + #[test] + fn chunks(ref input in vector(i32::ANY, 0..10000)) { + let output: Vector<_> = input.leaves().flat_map(|a|a).cloned().collect(); + assert_eq!(input, &output); + let rev_in: Vector<_> = input.iter().rev().cloned().collect(); + let rev_out: Vector<_> = input.leaves().rev().map(|c| c.iter().rev()).flat_map(|a|a).cloned().collect(); + assert_eq!(rev_in, rev_out); + } + + #[test] + fn chunks_mut(ref mut input_src in vector(i32::ANY, 0..10000)) { + let mut input = input_src.clone(); + #[allow(clippy::map_clone)] + let output: Vector<_> = input.leaves_mut().flat_map(|a| a).map(|v| *v).collect(); + assert_eq!(input, output); + let rev_in: Vector<_> = input.iter().rev().cloned().collect(); + let rev_out: Vector<_> = input.leaves_mut().rev().map(|c| c.iter().rev()).flat_map(|a|a).cloned().collect(); + assert_eq!(rev_in, rev_out); + } + + // The following two tests are very slow and there are unit tests above + // which test for regression of issue #55. It would still be good to + // run them occasionally. + + // #[test] + // fn issue55_back(count in 0..10000, slice_at in usize::ANY) { + // let count = count as usize; + // let slice_at = slice_at % count; + // let mut l = Vector::unit(0); + // for _ in 0..count { + // let mut tmp = Vector::unit(0); + // tmp.append(l); + // l = tmp; + // } + // let len = l.len(); + // l.slice(slice_at..len); + // } + + // #[test] + // fn issue55_fwd(count in 0..10000, slice_at in usize::ANY) { + // let count = count as usize; + // let slice_at = slice_at % count; + // let mut l = Vector::new(); + // for i in 0..count { + // l.append(Vector::unit(i)); + // } + // assert_eq!(Some(&slice_at), l.get(slice_at)); + // } + } +} diff --git a/iovec/.cargo-checksum.json b/iovec/.cargo-checksum.json new file mode 100644 index 000000000..c4406413a --- /dev/null +++ b/iovec/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"} \ No newline at end of file diff --git a/iovec/.pc/.quilt_patches b/iovec/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/iovec/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/iovec/.pc/.quilt_series b/iovec/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/iovec/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/iovec/.pc/.version b/iovec/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/iovec/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/iovec/.pc/applied-patches b/iovec/.pc/applied-patches new file mode 100644 index 000000000..69afcd7f1 --- /dev/null +++ b/iovec/.pc/applied-patches @@ -0,0 +1 @@ +b90b433-backport.patch diff --git a/iovec/.pc/b90b433-backport.patch/.timestamp b/iovec/.pc/b90b433-backport.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/iovec/.pc/b90b433-backport.patch/Cargo.toml b/iovec/.pc/b90b433-backport.patch/Cargo.toml new file mode 100644 index 000000000..19fb6aac7 --- /dev/null +++ b/iovec/.pc/b90b433-backport.patch/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "iovec" +version = "0.1.2" +authors = ["Carl Lerche "] +description = "Portable buffer type for scatter/gather I/O operations\n" +homepage = "https://github.com/carllerche/iovec" +documentation = "https://docs.rs/iovec" +readme = "README.md" +keywords = ["scatter", "gather", "vectored", "io", "networking"] +categories = ["network-programming", "api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/carllerche/iovec" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.2" diff --git a/iovec/.pc/b90b433-backport.patch/src/sys/windows.rs b/iovec/.pc/b90b433-backport.patch/src/sys/windows.rs new file mode 100644 index 000000000..ccc5f35d9 --- /dev/null +++ b/iovec/.pc/b90b433-backport.patch/src/sys/windows.rs @@ -0,0 +1,56 @@ +use winapi::{WSABUF, DWORD}; +use std::{mem, slice, u32}; + +pub struct IoVec { + inner: [u8], +} + +pub const MAX_LENGTH: usize = u32::MAX as usize; + +impl IoVec { + pub fn as_ref(&self) -> &[u8] { + unsafe { + let vec = self.wsabuf(); + slice::from_raw_parts(vec.buf as *const u8, vec.len as usize) + } + } + + pub fn as_mut(&mut self) -> &mut [u8] { + unsafe { + let vec = self.wsabuf(); + slice::from_raw_parts_mut(vec.buf as *mut u8, vec.len as usize) + } + } + + unsafe fn wsabuf(&self) -> WSABUF { + mem::transmute(&self.inner) + } +} + +impl<'a> From<&'a [u8]> for &'a IoVec { + fn from(src: &'a [u8]) -> Self { + assert!(src.len() > 0); + assert!(src.len() <= MAX_LENGTH); + + unsafe { + mem::transmute(WSABUF { + buf: src.as_ptr() as *mut _, + len: src.len() as DWORD, + }) + } + } +} + +impl<'a> From<&'a mut [u8]> for &'a mut IoVec { + fn from(src: &'a mut [u8]) -> Self { + assert!(src.len() > 0); + assert!(src.len() <= MAX_LENGTH); + + unsafe { + mem::transmute(WSABUF { + buf: src.as_ptr() as *mut _, + len: src.len() as DWORD, + }) + } + } +} diff --git a/iovec/CHANGELOG.md b/iovec/CHANGELOG.md new file mode 100644 index 000000000..0e2dfa3d1 --- /dev/null +++ b/iovec/CHANGELOG.md @@ -0,0 +1,11 @@ +# 0.1.2 (January 26th, 2018) + +* Add support for non-windows/unix targets (#10) + +# 0.1.1 (October 5th, 2017) + +* Fix soundness bug: Assert slice lengths are always > 0 (#5) + +# 0.1.0 (March 14th, 2017) + +* Initial release diff --git a/iovec/Cargo.toml b/iovec/Cargo.toml new file mode 100644 index 000000000..7e79d6cc5 --- /dev/null +++ b/iovec/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "iovec" +version = "0.1.2" +authors = ["Carl Lerche "] +description = "Portable buffer type for scatter/gather I/O operations\n" +homepage = "https://github.com/carllerche/iovec" +documentation = "https://docs.rs/iovec" +readme = "README.md" +keywords = ["scatter", "gather", "vectored", "io", "networking"] +categories = ["network-programming", "api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/carllerche/iovec" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies] +winapi = { version = "0.3", features = ["minwindef", "ws2def"] } diff --git a/iovec/LICENSE-APACHE b/iovec/LICENSE-APACHE new file mode 100644 index 000000000..87d73e7f9 --- /dev/null +++ b/iovec/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 Carl Lerche + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/iovec/LICENSE-MIT b/iovec/LICENSE-MIT new file mode 100644 index 000000000..6c296bec8 --- /dev/null +++ b/iovec/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/iovec/README.md b/iovec/README.md new file mode 100644 index 000000000..6d2ea7bd7 --- /dev/null +++ b/iovec/README.md @@ -0,0 +1,35 @@ +# IoVec + +A specialized byte slice type for performing vectored I/O operations. + +[![Crates.io](https://img.shields.io/crates/v/iovec.svg?maxAge=2592000)](https://crates.io/crates/iovec) +[![Build Status](https://travis-ci.org/carllerche/iovec.svg?branch=master)](https://travis-ci.org/carllerche/iovec) + +[Documentation](https://docs.rs/iovec) + +## Usage + +To use `iovec`, first add this to your `Cargo.toml`: + +```toml +[dependencies] +iovec = "0.1" +``` + +Next, add this to your crate: + +```rust +extern crate iovec; + +use iovec::IoVec; +``` + +For more detail, see [documentation](https://docs.rs/iovec). + +# License + +`iovec` is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/iovec/appveyor.yml b/iovec/appveyor.yml new file mode 100644 index 000000000..4428146b9 --- /dev/null +++ b/iovec/appveyor.yml @@ -0,0 +1,16 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + +install: + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo build + - cargo test diff --git a/iovec/debian/patches/b90b433-backport.patch b/iovec/debian/patches/b90b433-backport.patch new file mode 100644 index 000000000..64a10b52c --- /dev/null +++ b/iovec/debian/patches/b90b433-backport.patch @@ -0,0 +1,30 @@ +From b90b433f58fb8d64ad6c67d8080cf3da1fce3543 Mon Sep 17 00:00:00 2001 +From: Steffen Butzer +Date: Thu, 21 Dec 2017 15:51:01 +0100 +Subject: [PATCH] migrate to winapi 0.3 + +--- + Cargo.toml | 2 +- + src/sys/windows.rs | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 25ff582..ee1c0d3 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -17,3 +17,3 @@ categories = ["network-programming", "api-bindings"] + version = "0.2" +-[target."cfg(windows)".dependencies.winapi] +-version = "0.2" ++[target."cfg(windows)".dependencies] ++winapi = { version = "0.3", features = ["minwindef", "ws2def"] } +diff --git a/src/sys/windows.rs b/src/sys/windows.rs +index 18681a4..8cc6351 100644 +--- a/src/sys/windows.rs ++++ b/src/sys/windows.rs +@@ -1,3 +1,4 @@ +-use winapi::{WSABUF, DWORD}; ++use winapi::shared::minwindef::DWORD; ++use winapi::shared::ws2def::WSABUF; + use std::{mem, slice, u32}; + diff --git a/iovec/debian/patches/series b/iovec/debian/patches/series new file mode 100644 index 000000000..69afcd7f1 --- /dev/null +++ b/iovec/debian/patches/series @@ -0,0 +1 @@ +b90b433-backport.patch diff --git a/iovec/src/lib.rs b/iovec/src/lib.rs new file mode 100644 index 000000000..af36e72cf --- /dev/null +++ b/iovec/src/lib.rs @@ -0,0 +1,164 @@ +//! A specialized byte slice type for performing vectored I/O operations. +//! +//! For more detail, see [`IoVec`] documentation. +//! +//! [`IoVec`]: struct.IoVec.html + +#[cfg(unix)] +extern crate libc; + +#[cfg(windows)] +extern crate winapi; + +mod sys; + +use std::{ops, mem}; + +#[cfg(unix)] +pub mod unix; + +/// Max length of an `IoVec` slice. +/// +/// Attempts to convert slices longer than this value will result in a panic. +pub const MAX_LENGTH: usize = sys::MAX_LENGTH; + +/// A specialized byte slice type for performing vectored I/O operations. +/// +/// On all systems, the types needed to perform vectored I/O systems have the +/// same size as Rust's [`slice`]. However, the layout is not necessarily the +/// same. `IoVec` provides a portable compatibility layer. +/// +/// The `IoVec` behaves like a Rust [`slice`], providing the same functions. +/// It also provides conversion functions to and from the OS specific vectored +/// types. +/// +/// [`slice`]: https://doc.rust-lang.org/std/primitive.slice.html +/// +/// # Examples +/// +/// ``` +/// use iovec::IoVec; +/// +/// let mut data = vec![]; +/// data.extend_from_slice(b"hello"); +/// +/// let iovec: &IoVec = data.as_slice().into(); +/// +/// assert_eq!(&iovec[..], &b"hello"[..]); +/// ``` +/// +/// # Panics +/// +/// Attempting to convert a zero-length slice or a slice longer than +/// [`MAX_LENGTH`] to an `IoVec` will result in a panic. +/// +/// [`MAX_LENGTH`]: constant.MAX_LENGTH.html +pub struct IoVec { + sys: sys::IoVec, +} + +impl IoVec { + pub fn from_bytes(slice: &[u8]) -> Option<&IoVec> { + if slice.len() == 0 { + return None + } + unsafe { + let iovec: &sys::IoVec = slice.into(); + Some(mem::transmute(iovec)) + } + } + + pub fn from_bytes_mut(slice: &mut [u8]) -> Option<&mut IoVec> { + if slice.len() == 0 { + return None + } + unsafe { + let iovec: &mut sys::IoVec = slice.into(); + Some(mem::transmute(iovec)) + } + } + + #[deprecated(since = "0.1.0", note = "deref instead")] + #[doc(hidden)] + pub fn as_bytes(&self) -> &[u8] { + &**self + } + + #[deprecated(since = "0.1.0", note = "deref instead")] + #[doc(hidden)] + pub fn as_mut_bytes(&mut self) -> &mut [u8] { + &mut **self + } +} + +impl ops::Deref for IoVec { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.sys.as_ref() + } +} + +impl ops::DerefMut for IoVec { + fn deref_mut(&mut self) -> &mut [u8] { + self.sys.as_mut() + } +} + +#[doc(hidden)] +impl<'a> From<&'a [u8]> for &'a IoVec { + fn from(bytes: &'a [u8]) -> &'a IoVec { + IoVec::from_bytes(bytes) + .expect("this crate accidentally accepted 0-sized slices \ + originally but this was since discovered as a soundness \ + hole, it's recommended to use the `from_bytes` \ + function instead") + } +} + +#[doc(hidden)] +impl<'a> From<&'a mut [u8]> for &'a mut IoVec { + fn from(bytes: &'a mut [u8]) -> &'a mut IoVec { + IoVec::from_bytes_mut(bytes) + .expect("this crate accidentally accepted 0-sized slices \ + originally but this was since discovered as a soundness \ + hole, it's recommended to use the `from_bytes_mut` \ + function instead") + } +} + +#[doc(hidden)] +impl<'a> Default for &'a IoVec { + fn default() -> Self { + panic!("this implementation was accidentally provided but is \ + unfortunately unsound, it's recommended to stop using \ + `IoVec::default` or construct a vector with a nonzero length"); + } +} + +#[doc(hidden)] +impl<'a> Default for &'a mut IoVec { + fn default() -> Self { + panic!("this implementation was accidentally provided but is \ + unfortunately unsound, it's recommended to stop using \ + `IoVec::default` or construct a vector with a nonzero length"); + } +} + +#[cfg(test)] +mod test { + use super::IoVec; + + #[test] + fn convert_ref() { + let buf: &IoVec = (&b"hello world"[..]).into(); + assert_eq!(buf[..], b"hello world"[..]); + } + + #[test] + fn convert_mut() { + let mut buf: Vec = b"hello world".to_vec(); + let buf: &mut IoVec = (&mut buf[..]).into(); + assert_eq!(buf[..], b"hello world"[..]); + } +} diff --git a/iovec/src/sys/mod.rs b/iovec/src/sys/mod.rs new file mode 100644 index 000000000..3e0efc99e --- /dev/null +++ b/iovec/src/sys/mod.rs @@ -0,0 +1,26 @@ +#[cfg(unix)] +mod unix; + +#[cfg(unix)] +pub use self::unix::{ + IoVec, + MAX_LENGTH, +}; + +#[cfg(windows)] +mod windows; + +#[cfg(windows)] +pub use self::windows::{ + IoVec, + MAX_LENGTH, +}; + +#[cfg(not(any(windows, unix)))] +mod unknown; + +#[cfg(not(any(windows, unix)))] +pub use self::unknown::{ + IoVec, + MAX_LENGTH, +}; diff --git a/iovec/src/sys/unix.rs b/iovec/src/sys/unix.rs new file mode 100644 index 000000000..4dbc0674f --- /dev/null +++ b/iovec/src/sys/unix.rs @@ -0,0 +1,52 @@ +use libc; +use std::{mem, slice, usize}; + +pub struct IoVec { + inner: [u8], +} + +pub const MAX_LENGTH: usize = usize::MAX; + +impl IoVec { + pub fn as_ref(&self) -> &[u8] { + unsafe { + let vec = self.iovec(); + slice::from_raw_parts(vec.iov_base as *const u8, vec.iov_len) + } + } + + pub fn as_mut(&mut self) -> &mut [u8] { + unsafe { + let vec = self.iovec(); + slice::from_raw_parts_mut(vec.iov_base as *mut u8, vec.iov_len) + } + } + + unsafe fn iovec(&self) -> libc::iovec { + mem::transmute(&self.inner) + } +} + +impl<'a> From<&'a [u8]> for &'a IoVec { + fn from(src: &'a [u8]) -> Self { + assert!(src.len() > 0); + unsafe { + mem::transmute(libc::iovec { + iov_base: src.as_ptr() as *mut _, + iov_len: src.len(), + }) + } + } +} + +impl<'a> From<&'a mut [u8]> for &'a mut IoVec { + fn from(src: &'a mut [u8]) -> Self { + assert!(src.len() > 0); + unsafe { + mem::transmute(libc::iovec { + iov_base: src.as_ptr() as *mut _, + iov_len: src.len(), + }) + } + } +} diff --git a/iovec/src/sys/unknown.rs b/iovec/src/sys/unknown.rs new file mode 100644 index 000000000..37acedd78 --- /dev/null +++ b/iovec/src/sys/unknown.rs @@ -0,0 +1,57 @@ +use std::{mem, slice, usize}; + +#[derive(Clone)] +pub struct WasmIoVec { + ptr: *const u8, + len: usize, +} + +pub struct IoVec { + inner: [u8], +} + +pub const MAX_LENGTH: usize = usize::MAX; + +impl IoVec { + pub fn as_ref(&self) -> &[u8] { + unsafe { + let vec = self.iovec(); + slice::from_raw_parts(vec.ptr as *const u8, vec.len) + } + } + + pub fn as_mut(&mut self) -> &mut [u8] { + unsafe { + let vec = self.iovec(); + slice::from_raw_parts_mut(vec.ptr as *mut u8, vec.len) + } + } + + unsafe fn iovec(&self) -> WasmIoVec { + mem::transmute(&self.inner) + } +} + +impl<'a> From<&'a [u8]> for &'a IoVec { + fn from(src: &'a [u8]) -> Self { + assert!(src.len() > 0); + unsafe { + mem::transmute(WasmIoVec { + ptr: src.as_ptr() as *mut _, + len: src.len(), + }) + } + } +} + +impl<'a> From<&'a mut [u8]> for &'a mut IoVec { + fn from(src: &'a mut [u8]) -> Self { + assert!(src.len() > 0); + unsafe { + mem::transmute(WasmIoVec { + ptr: src.as_ptr() as *mut _, + len: src.len(), + }) + } + } +} diff --git a/iovec/src/sys/windows.rs b/iovec/src/sys/windows.rs new file mode 100644 index 000000000..3ab649934 --- /dev/null +++ b/iovec/src/sys/windows.rs @@ -0,0 +1,57 @@ +use winapi::shared::minwindef::DWORD; +use winapi::shared::ws2def::WSABUF; +use std::{mem, slice, u32}; + +pub struct IoVec { + inner: [u8], +} + +pub const MAX_LENGTH: usize = u32::MAX as usize; + +impl IoVec { + pub fn as_ref(&self) -> &[u8] { + unsafe { + let vec = self.wsabuf(); + slice::from_raw_parts(vec.buf as *const u8, vec.len as usize) + } + } + + pub fn as_mut(&mut self) -> &mut [u8] { + unsafe { + let vec = self.wsabuf(); + slice::from_raw_parts_mut(vec.buf as *mut u8, vec.len as usize) + } + } + + unsafe fn wsabuf(&self) -> WSABUF { + mem::transmute(&self.inner) + } +} + +impl<'a> From<&'a [u8]> for &'a IoVec { + fn from(src: &'a [u8]) -> Self { + assert!(src.len() > 0); + assert!(src.len() <= MAX_LENGTH); + + unsafe { + mem::transmute(WSABUF { + buf: src.as_ptr() as *mut _, + len: src.len() as DWORD, + }) + } + } +} + +impl<'a> From<&'a mut [u8]> for &'a mut IoVec { + fn from(src: &'a mut [u8]) -> Self { + assert!(src.len() > 0); + assert!(src.len() <= MAX_LENGTH); + + unsafe { + mem::transmute(WSABUF { + buf: src.as_ptr() as *mut _, + len: src.len() as DWORD, + }) + } + } +} diff --git a/iovec/src/unix.rs b/iovec/src/unix.rs new file mode 100644 index 000000000..3ef3728bb --- /dev/null +++ b/iovec/src/unix.rs @@ -0,0 +1,68 @@ +//! IoVec extensions for Unix platforms. +//! +//! These functions provide conversions to unix specific representations of the +//! vectored data. +//! +//! # Examples +//! +//! ``` +//! use iovec::IoVec; +//! use iovec::unix; +//! +//! let a = b"hello".to_vec(); +//! let b = b"world".to_vec(); +//! +//! let bufs: &[&IoVec] = &[(&a[..]).into(), (&b[..]).into()]; +//! let os_bufs = unix::as_os_slice(&bufs[..]); +//! +//! // Use the `os_bufs` slice with `writev`. +//! ``` + +use IoVec; +use libc; + +use std::mem; + +/// Convert a slice of `IoVec` refs to a slice of `libc::iovec`. +/// +/// The return value can be passed to `writev` bindings. +/// +/// # Examples +/// +/// ``` +/// use iovec::IoVec; +/// use iovec::unix; +/// +/// let a = b"hello".to_vec(); +/// let b = b"world".to_vec(); +/// +/// let bufs: &[&IoVec] = &[a[..].into(), b[..].into()]; +/// let os_bufs = unix::as_os_slice(bufs); +/// +/// // Use the `os_bufs` slice with `writev`. +/// ``` +pub fn as_os_slice<'a>(iov: &'a [&IoVec]) -> &'a [libc::iovec] { + unsafe { mem::transmute(iov) } +} + +/// Convert a mutable slice of `IoVec` refs to a mutable slice of `libc::iovec`. +/// +/// The return value can be passed to `readv` bindings. +/// +/// # Examples +/// +/// ``` +/// use iovec::IoVec; +/// use iovec::unix; +/// +/// let mut a = [0; 10]; +/// let mut b = [0; 10]; +/// +/// let bufs: &mut [&mut IoVec] = &mut [(&mut a[..]).into(), (&mut b[..]).into()]; +/// let os_bufs = unix::as_os_slice_mut(bufs); +/// +/// // Use the `os_bufs` slice with `readv`. +/// ``` +pub fn as_os_slice_mut<'a>(iov: &'a mut [&mut IoVec]) -> &'a mut [libc::iovec] { + unsafe { mem::transmute(iov) } +} diff --git a/iovec/src/windows.rs b/iovec/src/windows.rs new file mode 100644 index 000000000..e69de29bb diff --git a/itoa/.cargo-checksum.json b/itoa/.cargo-checksum.json new file mode 100644 index 000000000..27213980a --- /dev/null +++ b/itoa/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"} \ No newline at end of file diff --git a/itoa/Cargo.toml b/itoa/Cargo.toml new file mode 100644 index 000000000..0563bc1af --- /dev/null +++ b/itoa/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "itoa" +version = "0.4.4" +authors = ["David Tolnay "] +exclude = ["performance.png"] +description = "Fast functions for printing integer primitives to an io::Write" +documentation = "https://github.com/dtolnay/itoa" +readme = "README.md" +categories = ["value-formatting"] +license = "MIT/Apache-2.0" +repository = "https://github.com/dtolnay/itoa" + +[features] +default = ["std"] +i128 = [] +std = [] +[badges.travis-ci] +repository = "dtolnay/itoa" diff --git a/itoa/LICENSE-APACHE b/itoa/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/itoa/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/itoa/LICENSE-MIT b/itoa/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/itoa/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/itoa/README.md b/itoa/README.md new file mode 100644 index 000000000..d36f4fd51 --- /dev/null +++ b/itoa/README.md @@ -0,0 +1,95 @@ +itoa +==== + +[![Build Status](https://api.travis-ci.org/dtolnay/itoa.svg?branch=master)](https://travis-ci.org/dtolnay/itoa) +[![Latest Version](https://img.shields.io/crates/v/itoa.svg)](https://crates.io/crates/itoa) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/itoa) + +This crate provides fast functions for printing integer primitives to an +[`io::Write`] or a [`fmt::Write`]. The implementation comes straight from +[libcore] but avoids the performance penalty of going through +[`fmt::Formatter`]. + +See also [`dtoa`] for printing floating point primitives. + +*Version requirement: rustc 1.0+* + +[`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +[`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html +[libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 +[`fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html +[`dtoa`]: https://github.com/dtolnay/dtoa + +```toml +[dependencies] +itoa = "0.4" +``` + +
+ +## Performance (lower is better) + +![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) + +
+ +## Examples + +```rust +use std::{fmt, io}; + +fn demo_itoa_write() -> io::Result<()> { + // Write to a vector or other io::Write. + let mut buf = Vec::new(); + itoa::write(&mut buf, 128u64)?; + println!("{:?}", buf); + + // Write to a stack buffer. + let mut bytes = [0u8; 20]; + let n = itoa::write(&mut bytes[..], 128u64)?; + println!("{:?}", &bytes[..n]); + + Ok(()) +} + +fn demo_itoa_fmt() -> fmt::Result { + // Write to a string. + let mut s = String::new(); + itoa::fmt(&mut s, 128u64)?; + println!("{}", s); + + Ok(()) +} +``` + +The function signatures are: + +```rust +fn write(writer: W, value: V) -> io::Result; + +fn fmt(writer: W, value: V) -> fmt::Result; +``` + +where `itoa::Integer` is implemented for i8, u8, i16, u16, i32, u32, i64, u64, +i128, u128, isize and usize. 128-bit integer support requires rustc 1.26+ and +the `i128` feature of this crate enabled. + +The `write` function is only available when the `std` feature is enabled +(default is enabled). The return value gives the number of bytes written. + +
+ +#### License + + +Licensed under either of
Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + diff --git a/itoa/benches/bench.rs b/itoa/benches/bench.rs new file mode 100644 index 000000000..c3b55000b --- /dev/null +++ b/itoa/benches/bench.rs @@ -0,0 +1,83 @@ +#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] +#![feature(test)] +#![allow(non_snake_case)] + +extern crate itoa; +extern crate test; + +macro_rules! benches { + ( + $( + $(#[$attr:meta])* + $name:ident($value:expr) + ),* + ) => { + mod bench_itoa_write { + use test::{Bencher, black_box}; + $( + $(#[$attr])* + #[bench] + fn $name(b: &mut Bencher) { + use itoa; + + let mut buf = Vec::with_capacity(40); + + b.iter(|| { + buf.clear(); + itoa::write(&mut buf, black_box($value)).unwrap() + }); + } + )* + } + + mod bench_itoa_fmt { + use test::{Bencher, black_box}; + $( + $(#[$attr])* + #[bench] + fn $name(b: &mut Bencher) { + use itoa; + + let mut buf = String::with_capacity(40); + + b.iter(|| { + buf.clear(); + itoa::fmt(&mut buf, black_box($value)).unwrap() + }); + } + )* + } + + mod bench_std_fmt { + use test::{Bencher, black_box}; + $( + $(#[$attr])* + #[bench] + fn $name(b: &mut Bencher) { + use std::io::Write; + + let mut buf = Vec::with_capacity(40); + + b.iter(|| { + buf.clear(); + write!(&mut buf, "{}", black_box($value)).unwrap() + }); + } + )* + } + } +} + +benches!{ + bench_u64_0(0u64), + bench_u64_half(::max_value() as u64), + bench_u64_max(::max_value()), + + bench_i16_0(0i16), + bench_i16_min(::min_value()), + + #[cfg(feature = "i128")] + bench_u128_0(0u128), + #[cfg(feature = "i128")] + bench_u128_max(::max_value()) +} diff --git a/itoa/src/lib.rs b/itoa/src/lib.rs new file mode 100644 index 000000000..323bb6e2f --- /dev/null +++ b/itoa/src/lib.rs @@ -0,0 +1,342 @@ +//! This crate provides fast functions for printing integer primitives to an +//! [`io::Write`] or a [`fmt::Write`]. The implementation comes straight from +//! [libcore] but avoids the performance penalty of going through +//! [`fmt::Formatter`]. +//! +//! See also [`dtoa`] for printing floating point primitives. +//! +//! [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! [`fmt::Write`]: https://doc.rust-lang.org/core/fmt/trait.Write.html +//! [libcore]: https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L201-L254 +//! [`fmt::Formatter`]: https://doc.rust-lang.org/std/fmt/struct.Formatter.html +//! [`dtoa`]: https://github.com/dtolnay/dtoa +//! +//!
+//! +//! # Performance (lower is better) +//! +//! ![performance](https://raw.githubusercontent.com/dtolnay/itoa/master/performance.png) +//! +//!
+//! +//! # Examples +//! +//! ```edition2018 +//! use std::{fmt, io}; +//! +//! fn demo_itoa_write() -> io::Result<()> { +//! // Write to a vector or other io::Write. +//! let mut buf = Vec::new(); +//! itoa::write(&mut buf, 128u64)?; +//! println!("{:?}", buf); +//! +//! // Write to a stack buffer. +//! let mut bytes = [0u8; 20]; +//! let n = itoa::write(&mut bytes[..], 128u64)?; +//! println!("{:?}", &bytes[..n]); +//! +//! Ok(()) +//! } +//! +//! fn demo_itoa_fmt() -> fmt::Result { +//! // Write to a string. +//! let mut s = String::new(); +//! itoa::fmt(&mut s, 128u64)?; +//! println!("{}", s); +//! +//! Ok(()) +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/itoa/0.4.4")] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr( + feature = "cargo-clippy", + allow(const_static_lifetime, transmute_ptr_to_ptr), +)] + +#[cfg(feature = "i128")] +mod udiv128; + +#[cfg(feature = "std")] +use std::{fmt, io, mem, ptr, slice, str}; + +#[cfg(not(feature = "std"))] +use core::{fmt, mem, ptr, slice, str}; + +/// Write integer to an `io::Write`. +#[cfg(feature = "std")] +#[inline] +pub fn write(mut wr: W, value: V) -> io::Result { + let mut buf = Buffer::new(); + let s = buf.format(value); + try!(wr.write_all(s.as_bytes())); + Ok(s.len()) +} + +/// Write integer to an `fmt::Write`. +#[inline] +pub fn fmt(mut wr: W, value: V) -> fmt::Result { + let mut buf = Buffer::new(); + wr.write_str(buf.format(value)) +} + +/// A safe API for formatting integers to text. +/// +/// # Example +/// +/// ``` +/// let mut buffer = itoa::Buffer::new(); +/// let printed = buffer.format(1234); +/// assert_eq!(printed, "1234"); +/// ``` +#[derive(Copy)] +pub struct Buffer { + bytes: [u8; I128_MAX_LEN], +} + +impl Default for Buffer { + #[inline] + fn default() -> Buffer { + Buffer::new() + } +} + +impl Clone for Buffer { + #[inline] + fn clone(&self) -> Self { + Buffer::new() + } +} + +impl Buffer { + /// This is a cheap operation; you don't need to worry about reusing buffers + /// for efficiency. + #[inline] + pub fn new() -> Buffer { + Buffer { + bytes: unsafe { mem::uninitialized() }, + } + } + + /// Print an integer into this buffer and return a reference to its string representation + /// within the buffer. + pub fn format(&mut self, i: I) -> &str { + i.write(self) + } +} + +// Seal to prevent downstream implementations of the Integer trait. +mod private { + pub trait Sealed {} +} + +/// An integer that can be formatted by `itoa::write` and `itoa::fmt`. +/// +/// This trait is sealed and cannot be implemented for types outside of itoa. +pub trait Integer: private::Sealed { + // Not public API. + #[doc(hidden)] + fn write(self, buf: &mut Buffer) -> &str; +} + +trait IntegerPrivate { + fn write_to(self, buf: &mut B) -> &[u8]; +} + +const DEC_DIGITS_LUT: &'static [u8] = b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +// Adaptation of the original implementation at +// https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266 +macro_rules! impl_IntegerCommon { + ($max_len:expr, $t:ident) => { + impl Integer for $t { + #[inline] + fn write(self, buf: &mut Buffer) -> &str { + unsafe { + debug_assert!($max_len <= I128_MAX_LEN); + let buf = mem::transmute::<&mut [u8; I128_MAX_LEN], &mut [u8; $max_len]>( + &mut buf.bytes, + ); + let bytes = self.write_to(buf); + str::from_utf8_unchecked(bytes) + } + } + } + + impl private::Sealed for $t {} + }; +} + +macro_rules! impl_Integer { + ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$( + impl_IntegerCommon!($max_len, $t); + + impl IntegerPrivate<[u8; $max_len]> for $t { + #[allow(unused_comparisons)] + #[inline] + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { + let is_nonnegative = self >= 0; + let mut n = if is_nonnegative { + self as $conv_fn + } else { + // convert the negative num to positive by summing 1 to it's 2 complement + (!(self as $conv_fn)).wrapping_add(1) + }; + let mut curr = buf.len() as isize; + let buf_ptr = buf.as_mut_ptr(); + let lut_ptr = DEC_DIGITS_LUT.as_ptr(); + + unsafe { + // need at least 16 bits for the 4-characters-at-a-time to work. + if mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time + while n >= 10000 { + let rem = (n % 10000) as isize; + n /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + } + } + + // if we reach here numbers are <= 9999, so at most 4 chars long + let mut n = n as isize; // possibly reduce 64bit math + + // decode 2 more chars, if > 2 chars + if n >= 100 { + let d1 = (n % 100) << 1; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + // decode last 1 or 2 chars + if n < 10 { + curr -= 1; + *buf_ptr.offset(curr) = (n as u8) + b'0'; + } else { + let d1 = n << 1; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + if !is_nonnegative { + curr -= 1; + *buf_ptr.offset(curr) = b'-'; + } + } + + let len = buf.len() - curr as usize; + unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) } + } + } + )*}; +} + +const I8_MAX_LEN: usize = 4; +const U8_MAX_LEN: usize = 3; +const I16_MAX_LEN: usize = 6; +const U16_MAX_LEN: usize = 5; +const I32_MAX_LEN: usize = 11; +const U32_MAX_LEN: usize = 10; +const I64_MAX_LEN: usize = 20; +const U64_MAX_LEN: usize = 20; + +impl_Integer!( + I8_MAX_LEN => i8, + U8_MAX_LEN => u8, + I16_MAX_LEN => i16, + U16_MAX_LEN => u16, + I32_MAX_LEN => i32, + U32_MAX_LEN => u32 + as u32); + +impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64); + +#[cfg(target_pointer_width = "16")] +impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16); + +#[cfg(target_pointer_width = "32")] +impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32); + +#[cfg(target_pointer_width = "64")] +impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64); + +#[cfg(all(feature = "i128"))] +macro_rules! impl_Integer128 { + ($($max_len:expr => $t:ident),*) => {$( + impl_IntegerCommon!($max_len, $t); + + impl IntegerPrivate<[u8; $max_len]> for $t { + #[allow(unused_comparisons)] + #[inline] + fn write_to(self, buf: &mut [u8; $max_len]) -> &[u8] { + let is_nonnegative = self >= 0; + let n = if is_nonnegative { + self as u128 + } else { + // convert the negative num to positive by summing 1 to it's 2 complement + (!(self as u128)).wrapping_add(1) + }; + let mut curr = buf.len() as isize; + let buf_ptr = buf.as_mut_ptr(); + + unsafe { + // Divide by 10^19 which is the highest power less than 2^64. + let (n, rem) = udiv128::udivmod_1e19(n); + let buf1 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; + curr -= rem.write_to(&mut *buf1).len() as isize; + + if n != 0 { + // Memset the base10 leading zeros of rem. + let target = buf.len() as isize - 19; + ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize); + curr = target; + + // Divide by 10^19 again. + let (n, rem) = udiv128::udivmod_1e19(n); + let buf2 = buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [u8; U64_MAX_LEN]; + curr -= rem.write_to(&mut *buf2).len() as isize; + + if n != 0 { + // Memset the leading zeros. + let target = buf.len() as isize - 38; + ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize); + curr = target; + + // There is at most one digit left + // because u128::max / 10^19 / 10^19 is 3. + curr -= 1; + *buf_ptr.offset(curr) = (n as u8) + b'0'; + } + } + + if !is_nonnegative { + curr -= 1; + *buf_ptr.offset(curr) = b'-'; + } + + let len = buf.len() - curr as usize; + slice::from_raw_parts(buf_ptr.offset(curr), len) + } + } + } + )*}; +} + +#[cfg(all(feature = "i128"))] +const U128_MAX_LEN: usize = 39; +const I128_MAX_LEN: usize = 40; + +#[cfg(all(feature = "i128"))] +impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128); diff --git a/itoa/src/udiv128.rs b/itoa/src/udiv128.rs new file mode 100644 index 000000000..adbdce227 --- /dev/null +++ b/itoa/src/udiv128.rs @@ -0,0 +1,61 @@ +// The code in this file is based on Rust's compiler-builtins crate. The Rust +// compiler automatically links programs against this crate for target-specific +// runtime support. We have copied the implementation of `__udivmodti4()` which +// is an intrinsic implementing division with remainder for architectures +// without 128-bit integers. This implementation works around some poor codegen +// by LLVM (https://github.com/rust-lang/rust/issues/44545) and allows for +// inlining which does not happen with the intrinsic. +// +// The compiler-builtins crate carries the following license, which is available +// in full at: +// https://github.com/rust-lang-nursery/compiler-builtins/blob/master/LICENSE.TXT +// +// --- +// +// Copyright 2009-2016 compiler-builtins Developers +// +// The compiler-builtins crate is dual licensed under both the University of +// Illinois "BSD-Like" license and the MIT license. As a user of this code you +// may choose to use it under either license. As a contributor, you agree to +// allow your code to be used under both. + +#[inline] +pub fn udivmod_1e19(n: u128) -> (u128, u64) { + let d = 10_000_000_000_000_000_000_u64; // 10^19 + + let high = (n >> 64) as u64; + if high == 0 { + let low = n as u64; + return ((low / d) as u128, low % d); + } + + let sr = 65 - high.leading_zeros(); + + // 2 <= sr <= 65 + let mut q: u128 = n << (128 - sr); + let mut r: u128 = n >> sr; + let mut carry: u64 = 0; + + // Don't use a range because they may generate references to memcpy in unoptimized code + // + // Loop invariants: r < d; carry is 0 or 1 + let mut i = 0; + while i < sr { + i += 1; + + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> 127); + q = (q << 1) | carry as u128; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d as u128).wrapping_sub(r).wrapping_sub(1) as i128 >> 127; + carry = (s & 1) as u64; + r -= (d as u128) & s as u128; + } + + ((q << 1) | carry as u128, r as u64) +} diff --git a/itoa/tests/test.rs b/itoa/tests/test.rs new file mode 100644 index 000000000..dd8d4948a --- /dev/null +++ b/itoa/tests/test.rs @@ -0,0 +1,50 @@ +#![cfg_attr( + feature = "cargo-clippy", + allow(cast_lossless, string_lit_as_bytes) +)] +#![allow(non_snake_case)] + +extern crate itoa; + +macro_rules! test { + ( + $( + $(#[$attr:meta])* + $name:ident($value:expr, $expected:expr) + ),* + ) => { + $( + $(#[$attr])* + #[test] + fn $name() { + #[cfg(feature = "std")] + { + let mut buf = [b'\0'; 40]; + let len = itoa::write(&mut buf[..], $value).unwrap(); + assert_eq!(&buf[0..len], $expected.as_bytes()); + } + + let mut s = String::new(); + itoa::fmt(&mut s, $value).unwrap(); + assert_eq!(s, $expected); + } + )* + } +} + +test!{ + test_u64_0(0u64, "0"), + test_u64_half(::max_value() as u64, "4294967295"), + test_u64_max(::max_value(), "18446744073709551615"), + test_i64_min(::min_value(), "-9223372036854775808"), + + test_i16_0(0i16, "0"), + test_i16_min(::min_value(), "-32768"), + + #[cfg(feature = "i128")] + test_u128_0(0u128, "0"), + #[cfg(feature = "i128")] + test_u128_max(::max_value(), "340282366920938463463374607431768211455"), + #[cfg(feature = "i128")] + test_i128_min(::min_value(), "-170141183460469231731687303715884105728") +} diff --git a/jobserver/.cargo-checksum.json b/jobserver/.cargo-checksum.json new file mode 100644 index 000000000..67223b5dd --- /dev/null +++ b/jobserver/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b3d51e24009d966c8285d524dbaf6d60926636b2a89caee9ce0bd612494ddc16"} \ No newline at end of file diff --git a/jobserver/.pc/.quilt_patches b/jobserver/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/jobserver/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/jobserver/.pc/.quilt_series b/jobserver/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/jobserver/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/jobserver/.pc/.version b/jobserver/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/jobserver/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/jobserver/.pc/applied-patches b/jobserver/.pc/applied-patches new file mode 100644 index 000000000..90590f229 --- /dev/null +++ b/jobserver/.pc/applied-patches @@ -0,0 +1 @@ +relax-dep-version.patch diff --git a/jobserver/.pc/relax-dep-version.patch/.timestamp b/jobserver/.pc/relax-dep-version.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/jobserver/.pc/relax-dep-version.patch/Cargo.toml b/jobserver/.pc/relax-dep-version.patch/Cargo.toml new file mode 100644 index 000000000..87805fde3 --- /dev/null +++ b/jobserver/.pc/relax-dep-version.patch/Cargo.toml @@ -0,0 +1,64 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "jobserver" +version = "0.1.13" +authors = ["Alex Crichton "] +description = "An implementation of the GNU make jobserver for Rust\n" +homepage = "https://github.com/alexcrichton/jobserver-rs" +documentation = "https://docs.rs/jobserver" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/jobserver-rs" + +[[test]] +name = "client" +path = "tests/client.rs" +harness = false + +[[test]] +name = "server" +path = "tests/server.rs" + +[[test]] +name = "client-of-myself" +path = "tests/client-of-myself.rs" +harness = false + +[[test]] +name = "make-as-a-client" +path = "tests/make-as-a-client.rs" +harness = false + +[[test]] +name = "helper" +path = "tests/helper.rs" +[dependencies.log] +version = "0.4" +[dev-dependencies.futures] +version = "0.1" + +[dev-dependencies.num_cpus] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3" + +[dev-dependencies.tokio-core] +version = "0.1" + +[dev-dependencies.tokio-process] +version = "0.2" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.rand] +version = "0.6" diff --git a/jobserver/Cargo.toml b/jobserver/Cargo.toml new file mode 100644 index 000000000..1389712e6 --- /dev/null +++ b/jobserver/Cargo.toml @@ -0,0 +1,64 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "jobserver" +version = "0.1.13" +authors = ["Alex Crichton "] +description = "An implementation of the GNU make jobserver for Rust\n" +homepage = "https://github.com/alexcrichton/jobserver-rs" +documentation = "https://docs.rs/jobserver" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/jobserver-rs" + +[[test]] +name = "client" +path = "tests/client.rs" +harness = false + +[[test]] +name = "server" +path = "tests/server.rs" + +[[test]] +name = "client-of-myself" +path = "tests/client-of-myself.rs" +harness = false + +[[test]] +name = "make-as-a-client" +path = "tests/make-as-a-client.rs" +harness = false + +[[test]] +name = "helper" +path = "tests/helper.rs" +[dependencies.log] +version = "0.4" +[dev-dependencies.futures] +version = "0.1" + +[dev-dependencies.num_cpus] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3" + +[dev-dependencies.tokio-core] +version = "0.1" + +[dev-dependencies.tokio-process] +version = "0.2" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.rand] +version = "< 0.7, >= 0.4" diff --git a/jobserver/LICENSE-APACHE b/jobserver/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/jobserver/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/jobserver/LICENSE-MIT b/jobserver/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/jobserver/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/jobserver/README.md b/jobserver/README.md new file mode 100644 index 000000000..91b5a3ade --- /dev/null +++ b/jobserver/README.md @@ -0,0 +1,41 @@ +# jobserver-rs + +An implementation of the GNU make jobserver for Rust + +[![Build Status](https://travis-ci.com/alexcrichton/jobserver-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/jobserver-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/h5jc30hohp7ejd9c/branch/master?svg=true)](https://ci.appveyor.com/project/alexcrichton/jobserver-rs/branch/master) +[![Crates.io](https://img.shields.io/crates/v/jobserver.svg?maxAge=2592000)](https://crates.io/crates/jobserver) + +[Documentation](https://docs.rs/jobserver) + +## Usage + +First, add this to your `Cargo.toml`: + +```toml +[dependencies] +jobserver = "0.1" +``` + +Next, add this to your crate: + +```rust +extern crate jobserver; +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/jobserver/debian/patches/relax-dep-version.patch b/jobserver/debian/patches/relax-dep-version.patch new file mode 100644 index 000000000..a58b35b17 --- /dev/null +++ b/jobserver/debian/patches/relax-dep-version.patch @@ -0,0 +1,8 @@ +--- a/Cargo.toml 2018-08-03 01:58:48.002962262 -0700 ++++ b/Cargo.toml 2018-08-03 01:58:54.275006248 -0700 +@@ -61,4 +61,4 @@ + [target."cfg(unix)".dependencies.libc] + version = "0.2" + [target."cfg(windows)".dependencies.rand] +-version = "0.6" ++version = "< 0.7, >= 0.4" diff --git a/jobserver/debian/patches/series b/jobserver/debian/patches/series new file mode 100644 index 000000000..90590f229 --- /dev/null +++ b/jobserver/debian/patches/series @@ -0,0 +1 @@ +relax-dep-version.patch diff --git a/jobserver/src/lib.rs b/jobserver/src/lib.rs new file mode 100644 index 000000000..9fa224742 --- /dev/null +++ b/jobserver/src/lib.rs @@ -0,0 +1,963 @@ +//! An implementation of the GNU make jobserver. +//! +//! This crate is an implementation, in Rust, of the GNU `make` jobserver for +//! CLI tools that are interoperating with make or otherwise require some form +//! of parallelism limiting across process boundaries. This was originally +//! written for usage in Cargo to both (a) work when `cargo` is invoked from +//! `make` (using `make`'s jobserver) and (b) work when `cargo` invokes build +//! scripts, exporting a jobserver implementation for `make` processes to +//! transitively use. +//! +//! The jobserver implementation can be found in [detail online][docs] but +//! basically boils down to a cross-process semaphore. On Unix this is +//! implemented with the `pipe` syscall and read/write ends of a pipe and on +//! Windows this is implemented literally with IPC semaphores. +//! +//! The jobserver protocol in `make` also dictates when tokens are acquire to +//! run child work, and clients using this crate should take care to implement +//! such details to ensure correct interoperation with `make` itself. +//! +//! ## Examples +//! +//! Connect to a jobserver that was set up by `make` or a different process: +//! +//! ```no_run +//! use jobserver::Client; +//! +//! // See API documentation for why this is `unsafe` +//! let client = match unsafe { Client::from_env() } { +//! Some(client) => client, +//! None => panic!("client not configured"), +//! }; +//! ``` +//! +//! Acquire and release token from a jobserver: +//! +//! ```no_run +//! use jobserver::Client; +//! +//! let client = unsafe { Client::from_env().unwrap() }; +//! let token = client.acquire().unwrap(); // blocks until it is available +//! drop(token); // releases the token when the work is done +//! ``` +//! +//! Create a new jobserver and configure a child process to have access: +//! +//! ``` +//! use std::process::Command; +//! use jobserver::Client; +//! +//! let client = Client::new(4).expect("failed to create jobserver"); +//! let mut cmd = Command::new("make"); +//! client.configure(&mut cmd); +//! ``` +//! +//! ## Caveats +//! +//! This crate makes no attempt to release tokens back to a jobserver on +//! abnormal exit of a process. If a process which acquires a token is killed +//! with ctrl-c or some similar signal then tokens will not be released and the +//! jobserver may be in a corrupt state. +//! +//! Note that this is typically ok as ctrl-c means that an entire build process +//! is being torn down, but it's worth being aware of at least! +//! +//! ## Windows caveats +//! +//! There appear to be two implementations of `make` on Windows. On MSYS2 one +//! typically comes as `mingw32-make` and the other as `make` itself. I'm not +//! personally too familiar with what's going on here, but for jobserver-related +//! information the `mingw32-make` implementation uses Windows semaphores +//! whereas the `make` program does not. The `make` program appears to use file +//! descriptors and I'm not really sure how it works, so this crate is not +//! compatible with `make` on Windows. It is, however, compatible with +//! `mingw32-make`. +//! +//! [docs]: http://make.mad-scientist.net/papers/jobserver-implementation/ + +#![deny(missing_docs, missing_debug_implementations)] +#![doc(html_root_url = "https://docs.rs/jobserver/0.1")] + +#[macro_use] +extern crate log; + +use std::env; +use std::io; +use std::process::Command; +use std::sync::Arc; +use std::sync::mpsc::{self, Sender}; + +/// A client of a jobserver +/// +/// This structure is the main type exposed by this library, and is where +/// interaction to a jobserver is configured through. Clients are either created +/// from scratch in which case the internal semphore is initialied on the spot, +/// or a client is created from the environment to connect to a jobserver +/// already created. +/// +/// Some usage examples can be found in the crate documentation for using a +/// client. +/// +/// Note that a `Client` implements the `Clone` trait, and all instances of a +/// `Client` refer to the same jobserver instance. +#[derive(Clone, Debug)] +pub struct Client { + inner: Arc, +} + +/// An acquired token from a jobserver. +/// +/// This token will be released back to the jobserver when it is dropped and +/// otherwise represents the ability to spawn off another thread of work. +#[derive(Debug)] +pub struct Acquired { + client: Arc, + data: imp::Acquired, +} + +impl Client { + /// Creates a new jobserver initialized with the given parallelism limit. + /// + /// A client to the jobserver created will be returned. This client will + /// allow at most `limit` tokens to be acquired from it in parallel. More + /// calls to `acquire` will cause the calling thread to block. + /// + /// Note that the created `Client` is not automatically inherited into + /// spawned child processes from this program. Manual usage of the + /// `configure` function is required for a child process to have access to a + /// job server. + /// + /// # Examples + /// + /// ``` + /// use jobserver::Client; + /// + /// let client = Client::new(4).expect("failed to create jobserver"); + /// ``` + /// + /// # Errors + /// + /// Returns an error if any I/O error happens when attempting to create the + /// jobserver client. + pub fn new(limit: usize) -> io::Result { + Ok(Client { + inner: Arc::new(imp::Client::new(limit)?), + }) + } + + /// Attempts to connect to the jobserver specified in this process's + /// environment. + /// + /// When the a `make` executable calls a child process it will configure the + /// environment of the child to ensure that it has handles to the jobserver + /// it's passing down. This function will attempt to look for these details + /// and connect to the jobserver. + /// + /// Note that the created `Client` is not automatically inherited into + /// spawned child processes from this program. Manual usage of the + /// `configure` function is required for a child process to have access to a + /// job server. + /// + /// # Return value + /// + /// If a jobserver was found in the environment and it looks correct then + /// `Some` of the connected client will be returned. If no jobserver was + /// found then `None` will be returned. + /// + /// Note that on Unix the `Client` returned **takes ownership of the file + /// descriptors specified in the environment**. Jobservers on Unix are + /// implemented with `pipe` file descriptors, and they're inherited from + /// parent processes. This `Client` returned takes ownership of the file + /// descriptors for this process and will close the file descriptors after + /// this value is dropped. + /// + /// Additionally on Unix this function will configure the file descriptors + /// with `CLOEXEC` so they're not automatically inherited by spawned + /// children. + /// + /// # Unsafety + /// + /// This function is `unsafe` to call on Unix specifically as it + /// transitively requires usage of the `from_raw_fd` function, which is + /// itself unsafe in some circumstances. + /// + /// It's recommended to call this function very early in the lifetime of a + /// program before any other file descriptors are opened. That way you can + /// make sure to take ownership properly of the file descriptors passed + /// down, if any. + /// + /// It's generally unsafe to call this function twice in a program if the + /// previous invocation returned `Some`. + /// + /// Note, though, that on Windows it should be safe to call this function + /// any number of times. + pub unsafe fn from_env() -> Option { + let var = match env::var("CARGO_MAKEFLAGS") + .or(env::var("MAKEFLAGS")) + .or(env::var("MFLAGS")) { + Ok(s) => s, + Err(_) => return None, + }; + let mut arg = "--jobserver-fds="; + let pos = match var.find(arg) { + Some(i) => i, + None => { + arg = "--jobserver-auth="; + match var.find(arg) { + Some(i) => i, + None => return None, + } + } + }; + + let s = var[pos + arg.len()..].split(' ').next().unwrap(); + imp::Client::open(s).map(|c| { + Client { inner: Arc::new(c) } + }) + } + + /// Acquires a token from this jobserver client. + /// + /// This function will block the calling thread until a new token can be + /// acquired from the jobserver. + /// + /// # Return value + /// + /// On successful acquisition of a token an instance of `Acquired` is + /// returned. This structure, when dropped, will release the token back to + /// the jobserver. It's recommended to avoid leaking this value. + /// + /// # Errors + /// + /// If an I/O error happens while acquiring a token then this function will + /// return immediately with the error. If an error is returned then a token + /// was not acquired. + pub fn acquire(&self) -> io::Result { + let data = try!(self.inner.acquire()); + Ok(Acquired { + client: self.inner.clone(), + data: data, + }) + } + + /// Configures a child process to have access to this client's jobserver as + /// well. + /// + /// This function is required to be called to ensure that a jobserver is + /// properly inherited to a child process. If this function is *not* called + /// then this `Client` will not be accessible in the child process. In other + /// words, if not called, then `Client::from_env` will return `None` in the + /// child process (or the equivalent of `Child::from_env` that `make` uses). + /// + /// ## Platform-specific behavior + /// + /// On Unix and Windows this will clobber the `CARGO_MAKEFLAGS` environment + /// variables for the child process, and on Unix this will also allow the + /// two file descriptors for this client to be inherited to the child. + pub fn configure(&self, cmd: &mut Command) { + let arg = self.inner.string_arg(); + // Older implementations of make use `--jobserver-fds` and newer + // implementations use `--jobserver-auth`, pass both to try to catch + // both implementations. + let value = format!("--jobserver-fds={0} --jobserver-auth={0}", arg); + cmd.env("CARGO_MAKEFLAGS", &value); + self.inner.configure(cmd); + } + + /// Converts this `Client` into a helper thread to deal with a blocking + /// `acquire` function a little more easily. + /// + /// The fact that the `acquire` function on `Client` blocks isn't always + /// the easiest to work with. Typically you're using a jobserver to + /// manage running other events in parallel! This means that you need to + /// either (a) wait for an existing job to finish or (b) wait for a + /// new token to become available. + /// + /// Unfortunately the blocking in `acquire` happens at the implementation + /// layer of jobservers. On Unix this requires a blocking call to `read` + /// and on Windows this requires one of the `WaitFor*` functions. Both + /// of these situations aren't the easiest to deal with: + /// + /// * On Unix there's basically only one way to wake up a `read` early, and + /// that's through a signal. This is what the `make` implementation + /// itself uses, relying on `SIGCHLD` to wake up a blocking acquisition + /// of a new job token. Unfortunately nonblocking I/O is not an option + /// here, so it means that "waiting for one of two events" means that + /// the latter event must generate a signal! This is not always the case + /// on unix for all jobservers. + /// + /// * On Windows you'd have to basically use the `WaitForMultipleObjects` + /// which means that you've got to canonicalize all your event sources + /// into a `HANDLE` which also isn't the easiest thing to do + /// unfortunately. + /// + /// This function essentially attempts to ease these limitations by + /// converting this `Client` into a helper thread spawned into this + /// process. The application can then request that the helper thread + /// acquires tokens and the provided closure will be invoked for each token + /// acquired. + /// + /// The intention is that this function can be used to translate the event + /// of a token acquisition into an arbitrary user-defined event. + /// + /// # Arguments + /// + /// This function will consume the `Client` provided to be transferred to + /// the helper thread that is spawned. Additionally a closure `f` is + /// provided to be invoked whenever a token is acquired. + /// + /// This closure is only invoked after calls to + /// `HelperThread::request_token` have been made and a token itself has + /// been acquired. If an error happens while acquiring the token then + /// an error will be yielded to the closure as well. + /// + /// # Return Value + /// + /// This function will return an instance of the `HelperThread` structure + /// which is used to manage the helper thread associated with this client. + /// Through the `HelperThread` you'll request that tokens are acquired. + /// When acquired, the closure provided here is invoked. + /// + /// When the `HelperThread` structure is returned it will be gracefully + /// torn down, and the calling thread will be blocked until the thread is + /// torn down (which should be prompt). + /// + /// # Errors + /// + /// This function may fail due to creation of the helper thread or + /// auxiliary I/O objects to manage the helper thread. In any of these + /// situations the error is propagated upwards. + /// + /// # Platform-specific behavior + /// + /// On Windows this function behaves pretty normally as expected, but on + /// Unix the implementation is... a little heinous. As mentioned above + /// we're forced into blocking I/O for token acquisition, namely a blocking + /// call to `read`. We must be able to unblock this, however, to tear down + /// the helper thread gracefully! + /// + /// Essentially what happens is that we'll send a signal to the helper + /// thread spawned and rely on `EINTR` being returned to wake up the helper + /// thread. This involves installing a global `SIGUSR1` handler that does + /// nothing along with sending signals to that thread. This may cause + /// odd behavior in some applications, so it's recommended to review and + /// test thoroughly before using this. + pub fn into_helper_thread(self, f: F) -> io::Result + where F: FnMut(io::Result) + Send + 'static, + { + let (tx, rx) = mpsc::channel(); + Ok(HelperThread { + inner: Some(imp::spawn_helper(self, rx, Box::new(f))?), + tx: Some(tx), + }) + } + + /// Blocks the current thread until a token is acquired. + /// + /// This is the same as `acquire`, except that it doesn't return an RAII + /// helper. If successful the process will need to guarantee that + /// `release_raw` is called in the future. + pub fn acquire_raw(&self) -> io::Result<()> { + self.inner.acquire()?; + Ok(()) + } + + /// Releases a jobserver token back to the original jobserver. + /// + /// This is intended to be paired with `acquire_raw` if it was called, but + /// in some situations it could also be called to relinquish a process's + /// implicit token temporarily which is then re-acquired later. + pub fn release_raw(&self) -> io::Result<()> { + self.inner.release(None)?; + Ok(()) + } +} + +impl Drop for Acquired { + fn drop(&mut self) { + drop(self.client.release(Some(&self.data))); + } +} + +/// Structure returned from `Client::into_helper_thread` to manage the lifetime +/// of the helper thread returned, see those associated docs for more info. +#[derive(Debug)] +pub struct HelperThread { + inner: Option, + tx: Option>, +} + +impl HelperThread { + /// Request that the helper thread acquires a token, eventually calling the + /// original closure with a token when it's available. + /// + /// For more information, see the docs on that function. + pub fn request_token(&self) { + self.tx.as_ref().unwrap().send(()).unwrap(); + } +} + +impl Drop for HelperThread { + fn drop(&mut self) { + drop(self.tx.take()); + self.inner.take().unwrap().join(); + } +} + +#[cfg(unix)] +mod imp { + extern crate libc; + + use std::fs::File; + use std::io::{self, Read, Write}; + use std::mem; + use std::os::unix::prelude::*; + use std::process::Command; + use std::ptr; + use std::sync::atomic::{AtomicBool, AtomicUsize, + ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT, + Ordering}; + use std::sync::mpsc::{self, Receiver, RecvTimeoutError}; + use std::sync::{Arc, Once, ONCE_INIT}; + use std::thread::{self, JoinHandle, Builder}; + use std::time::Duration; + + use self::libc::c_int; + + #[derive(Debug)] + pub struct Client { + read: File, + write: File, + } + + #[derive(Debug)] + pub struct Acquired { + byte: u8, + } + + impl Client { + pub fn new(limit: usize) -> io::Result { + let client = unsafe { Client::mk()? }; + // I don't think the character written here matters, but I could be + // wrong! + for _ in 0..limit { + (&client.write).write(&[b'|'])?; + } + info!("created a jobserver: {:?}", client); + Ok(client) + } + + unsafe fn mk() -> io::Result { + static INVALID: AtomicBool = ATOMIC_BOOL_INIT; + let mut pipes = [0; 2]; + + // Attempt atomically-create-with-cloexec if we can. Note that even + // when libc has the symbol, `pipe2` might still not be supported on + // the running kernel -> `ENOSYS`, then we need to use the fallback. + if cfg!(target_os = "linux") && !INVALID.load(Ordering::SeqCst) { + if let Some(pipe2) = pipe2() { + match cvt(pipe2(pipes.as_mut_ptr(), libc::O_CLOEXEC)) { + Ok(_) => return Ok(Client::from_fds(pipes[0], pipes[1])), + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { + INVALID.store(true, Ordering::SeqCst); + } + Err(e) => return Err(e), + } + } + } + + cvt(libc::pipe(pipes.as_mut_ptr()))?; + drop(set_cloexec(pipes[0], true)); + drop(set_cloexec(pipes[1], true)); + Ok(Client::from_fds(pipes[0], pipes[1])) + } + + pub unsafe fn open(s: &str) -> Option { + let mut parts = s.splitn(2, ','); + let read = parts.next().unwrap(); + let write = match parts.next() { + Some(s) => s, + None => return None, + }; + + let read = match read.parse() { + Ok(n) => n, + Err(_) => return None, + }; + let write = match write.parse() { + Ok(n) => n, + Err(_) => return None, + }; + + // Ok so we've got two integers that look like file descriptors, but + // for extra sanity checking let's see if they actually look like + // instances of a pipe before we return the client. + // + // If we're called from `make` *without* the leading + on our rule + // then we'll have `MAKEFLAGS` env vars but won't actually have + // access to the file descriptors. + if is_valid_fd(read) && is_valid_fd(write) { + info!("using env fds {} and {}", read, write); + drop(set_cloexec(read, true)); + drop(set_cloexec(write, true)); + Some(Client::from_fds(read, write)) + } else { + info!("one of {} or {} isn't a pipe", read, write); + None + } + } + + unsafe fn from_fds(read: c_int, write: c_int) -> Client { + Client { + read: File::from_raw_fd(read), + write: File::from_raw_fd(write), + } + } + + pub fn acquire(&self) -> io::Result { + // We don't actually know if the file descriptor here is set in + // blocking or nonblocking mode. AFAIK all released versions of + // `make` use blocking fds for the jobserver, but the unreleased + // version of `make` doesn't. In the unreleased version jobserver + // fds are set to nonblocking and combined with `pselect` + // internally. + // + // Here we try to be compatible with both strategies. We + // unconditionally expect the file descriptor to be in nonblocking + // mode and if it happens to be in blocking mode then most of this + // won't end up actually being necessary! + // + // We use `poll` here to block this thread waiting for read + // readiness, and then afterwards we perform the `read` itself. If + // the `read` returns that it would block then we start over and try + // again. + // + // Also note that we explicitly don't handle EINTR here. That's used + // to shut us down, so we otherwise punt all errors upwards. + unsafe { + let mut fd: libc::pollfd = mem::zeroed(); + fd.fd = self.read.as_raw_fd(); + fd.events = libc::POLLIN; + loop { + fd.revents = 0; + if libc::poll(&mut fd, 1, -1) == -1 { + return Err(io::Error::last_os_error()) + } + if fd.revents == 0 { + continue + } + let mut buf = [0]; + match (&self.read).read(&mut buf) { + Ok(1) => return Ok(Acquired { byte: buf[0] }), + Ok(_) => { + return Err(io::Error::new(io::ErrorKind::Other, + "early EOF on jobserver pipe")) + } + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} + Err(e) => return Err(e), + } + } + } + } + + pub fn release(&self, data: Option<&Acquired>) -> io::Result<()> { + // Note that the fd may be nonblocking but we're going to go ahead + // and assume that the writes here are always nonblocking (we can + // always quickly release a token). If that turns out to not be the + // case we'll get an error anyway! + let byte = data.map(|d| d.byte).unwrap_or(b'+'); + match (&self.write).write(&[byte])? { + 1 => Ok(()), + _ => Err(io::Error::new(io::ErrorKind::Other, + "failed to write token back to jobserver")), + } + } + + pub fn string_arg(&self) -> String { + format!("{},{} -j", self.read.as_raw_fd(), self.write.as_raw_fd()) + } + + pub fn configure(&self, cmd: &mut Command) { + // Here we basically just want to say that in the child process + // we'll configure the read/write file descriptors to *not* be + // cloexec, so they're inherited across the exec and specified as + // integers through `string_arg` above. + let read = self.read.as_raw_fd(); + let write = self.write.as_raw_fd(); + cmd.before_exec(move || { + set_cloexec(read, false)?; + set_cloexec(write, false)?; + Ok(()) + }); + } + } + + #[derive(Debug)] + pub struct Helper { + thread: JoinHandle<()>, + quitting: Arc, + rx_done: Receiver<()>, + } + + pub fn spawn_helper(client: ::Client, + rx: Receiver<()>, + mut f: Box) + Send>) + -> io::Result + { + static USR1_INIT: Once = ONCE_INIT; + let mut err = None; + USR1_INIT.call_once(|| unsafe { + let mut new: libc::sigaction = mem::zeroed(); + new.sa_sigaction = sigusr1_handler as usize; + new.sa_flags = libc::SA_SIGINFO as _; + if libc::sigaction(libc::SIGUSR1, &new, ptr::null_mut()) != 0 { + err = Some(io::Error::last_os_error()); + } + }); + + if let Some(e) = err.take() { + return Err(e) + } + + let quitting = Arc::new(AtomicBool::new(false)); + let quitting2 = quitting.clone(); + let (tx_done, rx_done) = mpsc::channel(); + let thread = Builder::new().spawn(move || { + 'outer: + for () in rx { + loop { + let res = client.acquire(); + if let Err(ref e) = res { + if e.kind() == io::ErrorKind::Interrupted { + if quitting2.load(Ordering::SeqCst) { + break 'outer + } else { + continue + } + } + } + f(res); + break + } + } + tx_done.send(()).unwrap(); + })?; + + Ok(Helper { + thread: thread, + quitting: quitting, + rx_done: rx_done, + }) + } + + impl Helper { + pub fn join(self) { + self.quitting.store(true, Ordering::SeqCst); + let dur = Duration::from_millis(10); + let mut done = false; + for _ in 0..100 { + unsafe { + // Ignore the return value here of `pthread_kill`, + // apparently on OSX if you kill a dead thread it will + // return an error, but on other platforms it may not. In + // that sense we don't actually know if this will succeed or + // not! + libc::pthread_kill(self.thread.as_pthread_t(), libc::SIGUSR1); + match self.rx_done.recv_timeout(dur) { + Ok(()) | + Err(RecvTimeoutError::Disconnected) => { + done = true; + break + } + Err(RecvTimeoutError::Timeout) => {} + } + } + thread::yield_now(); + } + if done { + drop(self.thread.join()); + } + } + } + + fn is_valid_fd(fd: c_int) -> bool { + unsafe { + return libc::fcntl(fd, libc::F_GETFD) != -1; + } + } + + fn set_cloexec(fd: c_int, set: bool) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; + let new = if set { + previous | libc::FD_CLOEXEC + } else { + previous & !libc::FD_CLOEXEC + }; + if new != previous { + cvt(libc::fcntl(fd, libc::F_SETFD, new))?; + } + Ok(()) + } + } + + fn cvt(t: c_int) -> io::Result { + if t == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } + } + + unsafe fn pipe2() -> Option<&'static fn(*mut c_int, c_int) -> c_int> { + static PIPE2: AtomicUsize = ATOMIC_USIZE_INIT; + + if PIPE2.load(Ordering::SeqCst) == 0 { + let name = "pipe2\0"; + let n = match libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize { + 0 => 1, + n => n, + }; + PIPE2.store(n, Ordering::SeqCst); + } + if PIPE2.load(Ordering::SeqCst) == 1 { + None + } else { + mem::transmute(&PIPE2) + } + } + + extern fn sigusr1_handler(_signum: c_int, + _info: *mut libc::siginfo_t, + _ptr: *mut libc::c_void) { + // nothing to do + } +} + +#[cfg(windows)] +mod imp { + extern crate rand; + + use std::ffi::CString; + use std::io; + use std::process::Command; + use std::ptr; + use std::sync::Arc; + use std::sync::mpsc::Receiver; + use std::thread::{Builder, JoinHandle}; + + #[derive(Debug)] + pub struct Client { + sem: Handle, + name: String, + } + + #[derive(Debug)] + pub struct Acquired; + + type BOOL = i32; + type DWORD = u32; + type HANDLE = *mut u8; + type LONG = i32; + + const ERROR_ALREADY_EXISTS: DWORD = 183; + const FALSE: BOOL = 0; + const INFINITE: DWORD = 0xffffffff; + const SEMAPHORE_MODIFY_STATE: DWORD = 0x2; + const SYNCHRONIZE: DWORD = 0x00100000; + const TRUE: BOOL = 1; + const WAIT_OBJECT_0: DWORD = 0; + + extern "system" { + fn CloseHandle(handle: HANDLE) -> BOOL; + fn SetEvent(hEvent: HANDLE) -> BOOL; + fn WaitForMultipleObjects(ncount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD) -> DWORD; + fn CreateEventA(lpEventAttributes: *mut u8, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: *const i8) -> HANDLE; + fn ReleaseSemaphore(hSemaphore: HANDLE, + lReleaseCount: LONG, + lpPreviousCount: *mut LONG) -> BOOL; + fn CreateSemaphoreA(lpEventAttributes: *mut u8, + lInitialCount: LONG, + lMaximumCount: LONG, + lpName: *const i8) -> HANDLE; + fn OpenSemaphoreA(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: *const i8) -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, + dwMilliseconds: DWORD) -> DWORD; + } + + impl Client { + pub fn new(limit: usize) -> io::Result { + // Try a bunch of random semaphore names until we get a unique one, + // but don't try for too long. + // + // Note that `limit == 0` is a valid argument above but Windows + // won't let us create a semaphore with 0 slots available to it. Get + // `limit == 0` working by creating a semaphore instead with one + // slot and then immediately acquire it (without ever releaseing it + // back). + for _ in 0..100 { + let mut name = format!("__rust_jobserver_semaphore_{}\0", + rand::random::()); + unsafe { + let create_limit = if limit == 0 {1} else {limit}; + let r = CreateSemaphoreA(ptr::null_mut(), + create_limit as LONG, + create_limit as LONG, + name.as_ptr() as *const _); + if r.is_null() { + return Err(io::Error::last_os_error()) + } + let handle = Handle(r); + + let err = io::Error::last_os_error(); + if err.raw_os_error() == Some(ERROR_ALREADY_EXISTS as i32) { + continue + } + name.pop(); // chop off the trailing nul + let client = Client { + sem: handle, + name: name, + }; + if create_limit != limit { + client.acquire()?; + } + info!("created jobserver {:?}", client); + return Ok(client) + } + } + + Err(io::Error::new(io::ErrorKind::Other, + "failed to find a unique name for a semaphore")) + } + + pub unsafe fn open(s: &str) -> Option { + let name = match CString::new(s) { + Ok(s) => s, + Err(_) => return None, + }; + + let sem = OpenSemaphoreA(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, + FALSE, + name.as_ptr()); + if sem.is_null() { + info!("failed to open environment semaphore {}", s); + None + } else { + info!("opened environment semaphore {}", s); + Some(Client { + sem: Handle(sem), + name: s.to_string(), + }) + } + } + + pub fn acquire(&self) -> io::Result { + unsafe { + let r = WaitForSingleObject(self.sem.0, INFINITE); + if r == WAIT_OBJECT_0 { + Ok(Acquired) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn release(&self, _data: Option<&Acquired>) -> io::Result<()> { + unsafe { + let r = ReleaseSemaphore(self.sem.0, 1, ptr::null_mut()); + if r != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn string_arg(&self) -> String { + self.name.clone() + } + + pub fn configure(&self, _cmd: &mut Command) { + // nothing to do here, we gave the name of our semaphore to the + // child above + } + } + + #[derive(Debug)] + struct Handle(HANDLE); + // HANDLE is a raw ptr, but we're send/sync + unsafe impl Sync for Handle {} + unsafe impl Send for Handle {} + + impl Drop for Handle { + fn drop(&mut self) { + unsafe { + CloseHandle(self.0); + } + } + } + + #[derive(Debug)] + pub struct Helper { + event: Arc, + thread: JoinHandle<()>, + } + + pub fn spawn_helper(client: ::Client, + rx: Receiver<()>, + mut f: Box) + Send>) + -> io::Result + { + let event = unsafe { + let r = CreateEventA(ptr::null_mut(), TRUE, FALSE, ptr::null()); + if r.is_null() { + return Err(io::Error::last_os_error()) + } else { + Handle(r) + } + }; + let event = Arc::new(event); + let event2 = event.clone(); + let thread = Builder::new().spawn(move || { + let objects = [event2.0, client.inner.sem.0]; + for () in rx { + let r = unsafe { + WaitForMultipleObjects(2, objects.as_ptr(), FALSE, INFINITE) + }; + if r == WAIT_OBJECT_0 { + break + } + if r == WAIT_OBJECT_0 + 1 { + f(Ok(::Acquired { + client: client.inner.clone(), + data: Acquired, + })) + } else { + f(Err(io::Error::last_os_error())) + } + } + })?; + Ok(Helper { + thread: thread, + event: event, + }) + } + + impl Helper { + pub fn join(self) { + let r = unsafe { SetEvent(self.event.0) }; + if r == 0 { + panic!("failed to set event: {}", io::Error::last_os_error()); + } + drop(self.thread.join()); + } + } +} diff --git a/jobserver/tests/client-of-myself.rs b/jobserver/tests/client-of-myself.rs new file mode 100644 index 000000000..106368949 --- /dev/null +++ b/jobserver/tests/client-of-myself.rs @@ -0,0 +1,60 @@ +extern crate jobserver; + +use std::env; +use std::io::BufReader; +use std::io::prelude::*; +use std::process::{Command, Stdio}; +use std::sync::mpsc; +use std::thread; + +use jobserver::Client; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn main() { + if env::var("I_AM_THE_CLIENT").is_ok() { + client(); + } else { + server(); + } +} + +fn server() { + let me = t!(env::current_exe()); + let client = t!(Client::new(1)); + let mut cmd = Command::new(me); + cmd.env("I_AM_THE_CLIENT", "1") + .stdout(Stdio::piped()); + client.configure(&mut cmd); + let acq = client.acquire().unwrap(); + let mut child = t!(cmd.spawn()); + let stdout = child.stdout.take().unwrap(); + let (tx, rx) = mpsc::channel(); + let t = thread::spawn(move || { + for line in BufReader::new(stdout).lines() { + tx.send(t!(line)).unwrap(); + } + }); + + for _ in 0..100 { + assert!(rx.try_recv().is_err()); + } + + drop(acq); + assert_eq!(rx.recv().unwrap(), "hello!"); + t.join().unwrap(); + assert!(rx.recv().is_err()); + client.acquire().unwrap(); +} + +fn client() { + let client = unsafe { Client::from_env().unwrap() }; + let acq = client.acquire().unwrap(); + println!("hello!"); + drop(acq); +} diff --git a/jobserver/tests/client.rs b/jobserver/tests/client.rs new file mode 100644 index 000000000..4bf608c03 --- /dev/null +++ b/jobserver/tests/client.rs @@ -0,0 +1,200 @@ +extern crate futures; +extern crate jobserver; +extern crate num_cpus; +extern crate tempdir; +extern crate tokio_core; +extern crate tokio_process; + +use std::env; +use std::fs::File; +use std::io::Write; +use std::process::Command; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc; +use std::thread; + +use futures::future::{self, Future}; +use futures::stream::{self, Stream}; +use jobserver::Client; +use tempdir::TempDir; +use tokio_core::reactor::Core; +use tokio_process::CommandExt; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +struct Test { + name: &'static str, + f: &'static Fn(), + make_args: &'static [&'static str], + rule: &'static Fn(&str) -> String, +} + +const TESTS: &[Test] = &[ + Test { + name: "no j args", + make_args: &[], + rule: &|me| format!("{}", me), + f: &|| { + assert!(unsafe { Client::from_env().is_none() }); + }, + }, + Test { + name: "no j args with plus", + make_args: &[], + rule: &|me| format!("+{}", me), + f: &|| { + assert!(unsafe { Client::from_env().is_none() }); + }, + }, + Test { + name: "j args with plus", + make_args: &["-j2"], + rule: &|me| format!("+{}", me), + f: &|| { + assert!(unsafe { Client::from_env().is_some() }); + }, + }, + Test { + name: "acquire", + make_args: &["-j2"], + rule: &|me| format!("+{}", me), + f: &|| { + let c = unsafe { Client::from_env().unwrap() }; + drop(c.acquire().unwrap()); + drop(c.acquire().unwrap()); + }, + }, + Test { + name: "acquire3", + make_args: &["-j3"], + rule: &|me| format!("+{}", me), + f: &|| { + let c = unsafe { Client::from_env().unwrap() }; + let a = c.acquire().unwrap(); + let b = c.acquire().unwrap(); + drop((a, b)); + }, + }, + Test { + name: "acquire blocks", + make_args: &["-j2"], + rule: &|me| format!("+{}", me), + f: &|| { + let c = unsafe { Client::from_env().unwrap() }; + let a = c.acquire().unwrap(); + let hit = Arc::new(AtomicBool::new(false)); + let hit2 = hit.clone(); + let (tx, rx) = mpsc::channel(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + let _b = c.acquire().unwrap(); + hit2.store(true, Ordering::SeqCst); + }); + rx.recv().unwrap(); + assert!(!hit.load(Ordering::SeqCst)); + drop(a); + t.join().unwrap(); + assert!(hit.load(Ordering::SeqCst)); + }, + }, + Test { + name: "acquire_raw", + make_args: &["-j2"], + rule: &|me| format!("+{}", me), + f: &|| { + let c = unsafe { Client::from_env().unwrap() }; + c.acquire_raw().unwrap(); + c.release_raw().unwrap(); + }, + }, +]; + +fn main() { + if let Ok(test) = env::var("TEST_TO_RUN") { + return (TESTS.iter().find(|t| t.name == test).unwrap().f)() + } + + let me = t!(env::current_exe()); + let me = me.to_str().unwrap(); + let filter = env::args().skip(1).next(); + + let mut core = t!(Core::new()); + + let futures = TESTS.iter().filter(|test| { + match filter { + Some(ref s) => test.name.contains(s), + None => true, + } + }).map(|test| { + let td = t!(TempDir::new("foo")); + let makefile = format!("\ +all: export TEST_TO_RUN={} +all: +\t{} +", test.name, (test.rule)(me)); + t!(t!(File::create(td.path().join("Makefile"))) + .write_all(makefile.as_bytes())); + let prog = env::var("MAKE").unwrap_or("make".to_string()); + let mut cmd = Command::new(prog); + cmd.args(test.make_args); + cmd.current_dir(td.path()); + future::lazy(move || { + cmd.output_async().map(move |e| { + drop(td); + (test, e) + }) + }) + }).collect::>(); + + println!("\nrunning {} tests\n", futures.len()); + + let stream = stream::iter(futures.into_iter().map(Ok)) + .buffer_unordered(num_cpus::get()); + + let mut failures = Vec::new(); + t!(core.run(stream.for_each(|(test, output)| { + if output.status.success() { + println!("test {} ... ok", test.name); + } else { + println!("test {} ... FAIL", test.name); + failures.push((test, output)); + } + Ok(()) + }))); + + if failures.len() == 0 { + println!("\ntest result: ok\n"); + return + } + + println!("\n----------- failures"); + + for (test, output) in failures { + println!("test {}", test.name); + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + println!("\texit status: {}", output.status); + if !stdout.is_empty() { + println!("\tstdout ==="); + for line in stdout.lines() { + println!("\t\t{}", line); + } + } + + if !stderr.is_empty() { + println!("\tstderr ==="); + for line in stderr.lines() { + println!("\t\t{}", line); + } + } + } + + std::process::exit(4); +} diff --git a/jobserver/tests/helper.rs b/jobserver/tests/helper.rs new file mode 100644 index 000000000..ed046ae59 --- /dev/null +++ b/jobserver/tests/helper.rs @@ -0,0 +1,44 @@ +extern crate jobserver; + +use std::sync::mpsc; + +use jobserver::Client; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +#[test] +fn helper_smoke() { + let client = t!(Client::new(1)); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); + drop(client.clone().into_helper_thread(|_| ()).unwrap()); +} + +#[test] +fn acquire() { + let (tx, rx) = mpsc::channel(); + let client = t!(Client::new(1)); + let helper = client.into_helper_thread(move |a| drop(tx.send(a))).unwrap(); + assert!(rx.try_recv().is_err()); + helper.request_token(); + rx.recv().unwrap().unwrap(); + helper.request_token(); + rx.recv().unwrap().unwrap(); + + helper.request_token(); + helper.request_token(); + rx.recv().unwrap().unwrap(); + rx.recv().unwrap().unwrap(); + + helper.request_token(); + helper.request_token(); + drop(helper); +} diff --git a/jobserver/tests/make-as-a-client.rs b/jobserver/tests/make-as-a-client.rs new file mode 100644 index 000000000..1f029555f --- /dev/null +++ b/jobserver/tests/make-as-a-client.rs @@ -0,0 +1,77 @@ +extern crate jobserver; +extern crate tempdir; + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::net::{TcpStream, TcpListener}; +use std::process::Command; + +use jobserver::Client; +use tempdir::TempDir; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn main() { + if env::var("_DO_THE_TEST").is_ok() { + std::process::exit( + Command::new(env::var_os("MAKE").unwrap()) + .env("MAKEFLAGS", env::var_os("CARGO_MAKEFLAGS").unwrap()) + .env_remove("_DO_THE_TEST") + .args(&env::args_os().skip(1).collect::>()) + .status() + .unwrap() + .code() + .unwrap_or(1) + ); + } + + if let Ok(s) = env::var("TEST_ADDR") { + let mut contents = Vec::new(); + t!(t!(TcpStream::connect(&s)).read_to_end(&mut contents)); + return + } + + let c = t!(Client::new(1)); + let td = TempDir::new("foo").unwrap(); + + let prog = env::var("MAKE").unwrap_or("make".to_string()); + + let me = t!(env::current_exe()); + let me = me.to_str().unwrap(); + + let mut cmd = Command::new(&me); + cmd.current_dir(td.path()); + cmd.env("MAKE", prog); + cmd.env("_DO_THE_TEST", "1"); + + t!(t!(File::create(td.path().join("Makefile"))).write_all(format!("\ +all: foo bar +foo: +\t{0} +bar: +\t{0} +", me).as_bytes())); + + // We're leaking one extra token to `make` sort of violating the makefile + // jobserver protocol. It has the desired effect though. + c.configure(&mut cmd); + + let listener = t!(TcpListener::bind("127.0.0.1:0")); + let addr = t!(listener.local_addr()); + cmd.env("TEST_ADDR", addr.to_string()); + let mut child = t!(cmd.spawn()); + + // We should get both connections as the two programs should be run + // concurrently. + let a = t!(listener.accept()); + let b = t!(listener.accept()); + drop((a, b)); + + assert!(t!(child.wait()).success()); +} diff --git a/jobserver/tests/server.rs b/jobserver/tests/server.rs new file mode 100644 index 000000000..94cd71c9c --- /dev/null +++ b/jobserver/tests/server.rs @@ -0,0 +1,145 @@ +extern crate jobserver; +extern crate tempdir; + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::process::Command; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc; +use std::thread; + +use jobserver::Client; +use tempdir::TempDir; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +#[test] +fn server_smoke() { + let c = t!(Client::new(1)); + drop(c.acquire().unwrap()); + drop(c.acquire().unwrap()); +} + +#[test] +fn server_multiple() { + let c = t!(Client::new(2)); + let a = c.acquire().unwrap(); + let b = c.acquire().unwrap(); + drop((a, b)); +} + +#[test] +fn server_blocks() { + let c = t!(Client::new(1)); + let a = c.acquire().unwrap(); + let hit = Arc::new(AtomicBool::new(false)); + let hit2 = hit.clone(); + let (tx, rx) = mpsc::channel(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + let _b = c.acquire().unwrap(); + hit2.store(true, Ordering::SeqCst); + }); + rx.recv().unwrap(); + assert!(!hit.load(Ordering::SeqCst)); + drop(a); + t.join().unwrap(); + assert!(hit.load(Ordering::SeqCst)); +} + +#[test] +fn make_as_a_single_thread_client() { + let c = t!(Client::new(1)); + let td = TempDir::new("foo").unwrap(); + + let prog = env::var("MAKE").unwrap_or("make".to_string()); + let mut cmd = Command::new(prog); + cmd.current_dir(td.path()); + + t!(t!(File::create(td.path().join("Makefile"))).write_all(b" +all: foo bar +foo: +\techo foo +bar: +\techo bar +")); + + // The jobserver protocol means that the `make` process itself "runs with a + // token", so we acquire our one token to drain the jobserver, and this + // should mean that `make` itself never has a second token available to it. + let _a = c.acquire(); + c.configure(&mut cmd); + let output = t!(cmd.output()); + println!("\n\t=== stderr\n\t\t{}", + String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")); + println!("\t=== stdout\n\t\t{}", + String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")); + + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + + let stdout = String::from_utf8_lossy(&output.stdout).replace("\r\n", "\n"); + let a = "\ +echo foo +foo +echo bar +bar +"; + let b = "\ +echo bar +bar +echo foo +foo +"; + + assert!(stdout == a || stdout == b); +} + +#[test] +fn make_as_a_multi_thread_client() { + let c = t!(Client::new(1)); + let td = TempDir::new("foo").unwrap(); + + let prog = env::var("MAKE").unwrap_or("make".to_string()); + let mut cmd = Command::new(prog); + cmd.current_dir(td.path()); + + t!(t!(File::create(td.path().join("Makefile"))).write_all(b" +all: foo bar +foo: +\techo foo +bar: +\techo bar +")); + + // We're leaking one extra token to `make` sort of violating the makefile + // jobserver protocol. It has the desired effect though. + c.configure(&mut cmd); + let output = t!(cmd.output()); + println!("\n\t=== stderr\n\t\t{}", + String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")); + println!("\t=== stdout\n\t\t{}", + String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")); + + assert!(output.status.success()); +} + +#[test] +fn zero_client() { + let client = t!(Client::new(0)); + let (tx, rx) = mpsc::channel(); + let helper = client.into_helper_thread(move |a| drop(tx.send(a))).unwrap(); + helper.request_token(); + helper.request_token(); + + for _ in 0..1000 { + assert!(rx.try_recv().is_err()); + } +} diff --git a/lazy_static/.cargo-checksum.json b/lazy_static/.cargo-checksum.json new file mode 100644 index 000000000..81605cc5b --- /dev/null +++ b/lazy_static/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"} \ No newline at end of file diff --git a/lazy_static/Cargo.toml b/lazy_static/Cargo.toml new file mode 100644 index 000000000..c6779f943 --- /dev/null +++ b/lazy_static/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "lazy_static" +version = "1.3.0" +authors = ["Marvin Löbel "] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A macro for declaring lazily evaluated statics in Rust." +documentation = "https://docs.rs/lazy_static" +readme = "README.md" +keywords = ["macro", "lazy", "static"] +categories = ["no-std", "rust-patterns", "memory-management"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/lazy-static.rs" +[dependencies.spin] +version = "0.5.0" +optional = true + +[features] +spin_no_std = ["spin"] +[badges.appveyor] +repository = "rust-lang-nursery/lazy-static.rs" + +[badges.is-it-maintained-issue-resolution] +repository = "rust-lang-nursery/lazy-static.rs" + +[badges.is-it-maintained-open-issues] +repository = "rust-lang-nursery/lazy-static.rs" + +[badges.maintenance] +status = "passively-maintained" + +[badges.travis-ci] +repository = "rust-lang-nursery/lazy-static.rs" diff --git a/lazy_static/LICENSE-APACHE b/lazy_static/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/lazy_static/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lazy_static/LICENSE-MIT b/lazy_static/LICENSE-MIT new file mode 100644 index 000000000..25597d583 --- /dev/null +++ b/lazy_static/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2010 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/lazy_static/README.md b/lazy_static/README.md new file mode 100644 index 000000000..c91337566 --- /dev/null +++ b/lazy_static/README.md @@ -0,0 +1,79 @@ +lazy-static.rs +============== + +A macro for declaring lazily evaluated statics in Rust. + +Using this macro, it is possible to have `static`s that require code to be +executed at runtime in order to be initialized. +This includes anything requiring heap allocations, like vectors or hash maps, +as well as anything that requires non-const function calls to be computed. + +[![Travis-CI Status](https://travis-ci.com/rust-lang-nursery/lazy-static.rs.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/lazy-static.rs) +[![Latest version](https://img.shields.io/crates/v/lazy_static.svg)](https://crates.io/crates/lazy_static) +[![Documentation](https://docs.rs/lazy_static/badge.svg)](https://docs.rs/lazy_static) +[![License](https://img.shields.io/crates/l/lazy_static.svg)](https://github.com/rust-lang-nursery/lazy-static.rs#license) + +## Minimum supported `rustc` + +`1.24.1+` + +This version is explicitly tested in CI and may only be bumped in new minor versions. Any changes to the supported minimum version will be called out in the release notes. + + +# Getting Started + +[lazy-static.rs is available on crates.io](https://crates.io/crates/lazy_static). +It is recommended to look there for the newest released version, as well as links to the newest builds of the docs. + +At the point of the last update of this README, the latest published version could be used like this: + +Add the following dependency to your Cargo manifest... + +```toml +[dependencies] +lazy_static = "1.3.0" +``` + +...and see the [docs](https://docs.rs/lazy_static) for how to use it. + +# Example + +```rust +#[macro_use] +extern crate lazy_static; + +use std::collections::HashMap; + +lazy_static! { + static ref HASHMAP: HashMap = { + let mut m = HashMap::new(); + m.insert(0, "foo"); + m.insert(1, "bar"); + m.insert(2, "baz"); + m + }; +} + +fn main() { + // First access to `HASHMAP` initializes it + println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); + + // Any further access to `HASHMAP` just returns the computed value + println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap()); +} +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/lazy_static/src/core_lazy.rs b/lazy_static/src/core_lazy.rs new file mode 100644 index 000000000..b66c3e0d0 --- /dev/null +++ b/lazy_static/src/core_lazy.rs @@ -0,0 +1,31 @@ +// Copyright 2016 lazy-static.rs Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +extern crate spin; + +use self::spin::Once; + +pub struct Lazy(Once); + +impl Lazy { + pub const INIT: Self = Lazy(Once::INIT); + + #[inline(always)] + pub fn get(&'static self, builder: F) -> &T + where F: FnOnce() -> T + { + self.0.call_once(builder) + } +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __lazy_static_create { + ($NAME:ident, $T:ty) => { + static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT; + } +} diff --git a/lazy_static/src/inline_lazy.rs b/lazy_static/src/inline_lazy.rs new file mode 100644 index 000000000..268dd45fd --- /dev/null +++ b/lazy_static/src/inline_lazy.rs @@ -0,0 +1,65 @@ +// Copyright 2016 lazy-static.rs Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +extern crate core; +extern crate std; + +use self::std::prelude::v1::*; +use self::std::cell::Cell; +use self::std::sync::Once; +pub use self::std::sync::ONCE_INIT; + +// FIXME: Replace Option with MaybeInitialized +pub struct Lazy(Cell>, Once); + +impl Lazy { + pub const INIT: Self = Lazy(Cell::new(None), ONCE_INIT); + + #[inline(always)] + pub fn get(&'static self, f: F) -> &T + where + F: FnOnce() -> T, + { + self.1.call_once(|| { + self.0.set(Some(f())); + }); + + // `self.0` is guaranteed to be `Some` by this point + // The `Once` will catch and propegate panics + unsafe { + match *self.0.as_ptr() { + Some(ref x) => x, + None => { + debug_assert!(false, "attempted to derefence an uninitialized lazy static. This is a bug"); + + unreachable_unchecked() + }, + } + } + } +} + +unsafe impl Sync for Lazy {} + +#[macro_export] +#[doc(hidden)] +macro_rules! __lazy_static_create { + ($NAME:ident, $T:ty) => { + static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT; + }; +} + +/// Polyfill for std::hint::unreachable_unchecked. There currently exists a +/// [crate](https://docs.rs/unreachable) for an equivalent to std::hint::unreachable_unchecked, but +/// lazy_static currently doesn't include any runtime dependencies and we've chosen to include this +/// short polyfill rather than include a new crate in every consumer's build. +/// +/// This should be replaced by std's version when lazy_static starts to require at least Rust 1.27. +unsafe fn unreachable_unchecked() -> ! { + enum Void {} + match std::mem::uninitialized::() {} +} diff --git a/lazy_static/src/lib.rs b/lazy_static/src/lib.rs new file mode 100644 index 000000000..ac0cf8a36 --- /dev/null +++ b/lazy_static/src/lib.rs @@ -0,0 +1,211 @@ +// Copyright 2016 lazy-static.rs Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +/*! +A macro for declaring lazily evaluated statics. + +Using this macro, it is possible to have `static`s that require code to be +executed at runtime in order to be initialized. +This includes anything requiring heap allocations, like vectors or hash maps, +as well as anything that requires function calls to be computed. + +# Syntax + +```ignore +lazy_static! { + [pub] static ref NAME_1: TYPE_1 = EXPR_1; + [pub] static ref NAME_2: TYPE_2 = EXPR_2; + ... + [pub] static ref NAME_N: TYPE_N = EXPR_N; +} +``` + +Attributes (including doc comments) are supported as well: + +```rust +# #[macro_use] +# extern crate lazy_static; +# fn main() { +lazy_static! { + /// This is an example for using doc comment attributes + static ref EXAMPLE: u8 = 42; +} +# } +``` + +# Semantics + +For a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that +implements `Deref` and stores it in a static with name `NAME`. (Attributes end up +attaching to this type.) + +On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs +can return a reference to the same object. Note that this can lead to deadlocks +if you have multiple lazy statics that depend on each other in their initialization. + +Apart from the lazy initialization, the resulting "static ref" variables +have generally the same properties as regular "static" variables: + +- Any type in them needs to fulfill the `Sync` trait. +- If the type has a destructor, then it will not run when the process exits. + +# Example + +Using the macro: + +```rust +#[macro_use] +extern crate lazy_static; + +use std::collections::HashMap; + +lazy_static! { + static ref HASHMAP: HashMap = { + let mut m = HashMap::new(); + m.insert(0, "foo"); + m.insert(1, "bar"); + m.insert(2, "baz"); + m + }; + static ref COUNT: usize = HASHMAP.len(); + static ref NUMBER: u32 = times_two(21); +} + +fn times_two(n: u32) -> u32 { n * 2 } + +fn main() { + println!("The map has {} entries.", *COUNT); + println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); + println!("A expensive calculation on a static results in: {}.", *NUMBER); +} +``` + +# Implementation details + +The `Deref` implementation uses a hidden static variable that is guarded by an atomic check on each access. + +# Cargo features + +This crate provides two cargo features: + +- `spin_no_std`: This allows using this crate in a no-std environment, by depending on the standalone `spin` crate. + +Both features depend on unstable language features, which means +no guarantees can be made about them in regard to SemVer stability. + +*/ + +#![doc(html_root_url = "https://docs.rs/lazy_static/1.3.0")] +#![no_std] + +#[cfg(not(feature = "spin_no_std"))] +#[path="inline_lazy.rs"] +#[doc(hidden)] +pub mod lazy; + +#[cfg(feature = "spin_no_std")] +#[path="core_lazy.rs"] +#[doc(hidden)] +pub mod lazy; + +#[doc(hidden)] +pub use core::ops::Deref as __Deref; + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __lazy_static_internal { + // optional visibility restrictions are wrapped in `()` to allow for + // explicitly passing otherwise implicit information about private items + ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { + __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N); + __lazy_static_internal!(@TAIL, $N : $T = $e); + lazy_static!($($t)*); + }; + (@TAIL, $N:ident : $T:ty = $e:expr) => { + impl $crate::__Deref for $N { + type Target = $T; + fn deref(&self) -> &$T { + #[inline(always)] + fn __static_ref_initialize() -> $T { $e } + + #[inline(always)] + fn __stability() -> &'static $T { + __lazy_static_create!(LAZY, $T); + LAZY.get(__static_ref_initialize) + } + __stability() + } + } + impl $crate::LazyStatic for $N { + fn initialize(lazy: &Self) { + let _ = &**lazy; + } + } + }; + // `vis` is wrapped in `()` to prevent parsing ambiguity + (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => { + #[allow(missing_copy_implementations)] + #[allow(non_camel_case_types)] + #[allow(dead_code)] + $(#[$attr])* + $($vis)* struct $N {__private_field: ()} + #[doc(hidden)] + $($vis)* static $N: $N = $N {__private_field: ()}; + }; + () => () +} + +#[macro_export(local_inner_macros)] +macro_rules! lazy_static { + ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { + // use `()` to explicitly forward the information about private items + __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*); + }; + ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { + __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*); + }; + ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { + __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*); + }; + () => () +} + +/// Support trait for enabling a few common operation on lazy static values. +/// +/// This is implemented by each defined lazy static, and +/// used by the free functions in this crate. +pub trait LazyStatic { + #[doc(hidden)] + fn initialize(lazy: &Self); +} + +/// Takes a shared reference to a lazy static and initializes +/// it if it has not been already. +/// +/// This can be used to control the initialization point of a lazy static. +/// +/// Example: +/// +/// ```rust +/// #[macro_use] +/// extern crate lazy_static; +/// +/// lazy_static! { +/// static ref BUFFER: Vec = (0..255).collect(); +/// } +/// +/// fn main() { +/// lazy_static::initialize(&BUFFER); +/// +/// // ... +/// work_with_initialized_data(&BUFFER); +/// } +/// # fn work_with_initialized_data(_: &[u8]) {} +/// ``` +pub fn initialize(lazy: &T) { + LazyStatic::initialize(lazy); +} diff --git a/lazy_static/tests/no_std.rs b/lazy_static/tests/no_std.rs new file mode 100644 index 000000000..f94a1aaa6 --- /dev/null +++ b/lazy_static/tests/no_std.rs @@ -0,0 +1,20 @@ +#![cfg(feature="spin_no_std")] + +#![no_std] + +#[macro_use] +extern crate lazy_static; + +lazy_static! { + /// Documentation! + pub static ref NUMBER: u32 = times_two(3); +} + +fn times_two(n: u32) -> u32 { + n * 2 +} + +#[test] +fn test_basic() { + assert_eq!(*NUMBER, 6); +} diff --git a/lazy_static/tests/test.rs b/lazy_static/tests/test.rs new file mode 100644 index 000000000..654abc541 --- /dev/null +++ b/lazy_static/tests/test.rs @@ -0,0 +1,162 @@ +#[macro_use] +extern crate lazy_static; +use std::collections::HashMap; + +lazy_static! { + /// Documentation! + pub static ref NUMBER: u32 = times_two(3); + + static ref ARRAY_BOXES: [Box; 3] = [Box::new(1), Box::new(2), Box::new(3)]; + + /// More documentation! + #[allow(unused_variables)] + #[derive(Copy, Clone, Debug)] + pub static ref STRING: String = "hello".to_string(); + + static ref HASHMAP: HashMap = { + let mut m = HashMap::new(); + m.insert(0, "abc"); + m.insert(1, "def"); + m.insert(2, "ghi"); + m + }; + + // This should not compile if the unsafe is removed. + static ref UNSAFE: u32 = unsafe { + std::mem::transmute::(-1) + }; +} + +lazy_static! { + static ref S1: &'static str = "a"; + static ref S2: &'static str = "b"; +} +lazy_static! { + static ref S3: String = [*S1, *S2].join(""); +} + +#[test] +fn s3() { + assert_eq!(&*S3, "ab"); +} + +fn times_two(n: u32) -> u32 { + n * 2 +} + +#[test] +fn test_basic() { + assert_eq!(&**STRING, "hello"); + assert_eq!(*NUMBER, 6); + assert!(HASHMAP.get(&1).is_some()); + assert!(HASHMAP.get(&3).is_none()); + assert_eq!(&*ARRAY_BOXES, &[Box::new(1), Box::new(2), Box::new(3)]); + assert_eq!(*UNSAFE, std::u32::MAX); +} + +#[test] +fn test_repeat() { + assert_eq!(*NUMBER, 6); + assert_eq!(*NUMBER, 6); + assert_eq!(*NUMBER, 6); +} + +#[test] +fn test_meta() { + // this would not compile if STRING were not marked #[derive(Copy, Clone)] + let copy_of_string = STRING; + // just to make sure it was copied + assert!(&STRING as *const _ != ©_of_string as *const _); + + // this would not compile if STRING were not marked #[derive(Debug)] + assert_eq!(format!("{:?}", STRING), "STRING { __private_field: () }".to_string()); +} + +mod visibility { + lazy_static! { + pub static ref FOO: Box = Box::new(0); + static ref BAR: Box = Box::new(98); + } + + pub mod inner { + lazy_static! { + pub(in visibility) static ref BAZ: Box = Box::new(42); + pub(crate) static ref BAG: Box = Box::new(37); + } + } + + #[test] + fn sub_test() { + assert_eq!(**FOO, 0); + assert_eq!(**BAR, 98); + assert_eq!(**inner::BAZ, 42); + assert_eq!(**inner::BAG, 37); + } +} + +#[test] +fn test_visibility() { + assert_eq!(*visibility::FOO, Box::new(0)); + assert_eq!(*visibility::inner::BAG, Box::new(37)); +} + +// This should not cause a warning about a missing Copy implementation +lazy_static! { + pub static ref VAR: i32 = { 0 }; +} + +#[derive(Copy, Clone, Debug, PartialEq)] +struct X; +struct Once(X); +const ONCE_INIT: Once = Once(X); +static DATA: X = X; +static ONCE: X = X; +fn require_sync() -> X { X } +fn transmute() -> X { X } +fn __static_ref_initialize() -> X { X } +fn test(_: Vec) -> X { X } + +// All these names should not be shadowed +lazy_static! { + static ref ITEM_NAME_TEST: X = { + test(vec![X, Once(X).0, ONCE_INIT.0, DATA, ONCE, + require_sync(), transmute(), + // Except this, which will sadly be shadowed by internals: + // __static_ref_initialize() + ]) + }; +} + +#[test] +fn item_name_shadowing() { + assert_eq!(*ITEM_NAME_TEST, X); +} + +use std::sync::atomic::AtomicBool; +use std::sync::atomic::ATOMIC_BOOL_INIT; +use std::sync::atomic::Ordering::SeqCst; + +static PRE_INIT_FLAG: AtomicBool = ATOMIC_BOOL_INIT; + +lazy_static! { + static ref PRE_INIT: () = { + PRE_INIT_FLAG.store(true, SeqCst); + () + }; +} + +#[test] +fn pre_init() { + assert_eq!(PRE_INIT_FLAG.load(SeqCst), false); + lazy_static::initialize(&PRE_INIT); + assert_eq!(PRE_INIT_FLAG.load(SeqCst), true); +} + +lazy_static! { + static ref LIFETIME_NAME: for<'a> fn(&'a u8) = { fn f(_: &u8) {} f }; +} + +#[test] +fn lifetime_name() { + let _ = LIFETIME_NAME; +} diff --git a/lazycell/.cargo-checksum.json b/lazycell/.cargo-checksum.json new file mode 100644 index 000000000..8ed184061 --- /dev/null +++ b/lazycell/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"} \ No newline at end of file diff --git a/lazycell/.pc/.quilt_patches b/lazycell/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/lazycell/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/lazycell/.pc/.quilt_series b/lazycell/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/lazycell/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/lazycell/.pc/.version b/lazycell/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/lazycell/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/lazycell/.pc/applied-patches b/lazycell/.pc/applied-patches new file mode 100644 index 000000000..bce906376 --- /dev/null +++ b/lazycell/.pc/applied-patches @@ -0,0 +1 @@ +no-clippy.patch diff --git a/lazycell/.pc/no-clippy.patch/.timestamp b/lazycell/.pc/no-clippy.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/lazycell/.pc/no-clippy.patch/Cargo.toml b/lazycell/.pc/no-clippy.patch/Cargo.toml new file mode 100644 index 000000000..faecd458d --- /dev/null +++ b/lazycell/.pc/no-clippy.patch/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "lazycell" +version = "1.2.1" +authors = ["Alex Crichton ", "Nikita Pekin "] +include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"] +description = "A library providing a lazily filled Cell struct" +documentation = "http://indiv0.github.io/lazycell/lazycell/" +readme = "README.md" +keywords = ["lazycell", "lazy", "cell", "library"] +license = "MIT/Apache-2.0" +repository = "https://github.com/indiv0/lazycell" +[dependencies.clippy] +version = "0.0" +optional = true + +[features] +nightly = [] +nightly-testing = ["clippy", "nightly"] diff --git a/lazycell/CHANGELOG.md b/lazycell/CHANGELOG.md new file mode 100644 index 000000000..33f1a7d1b --- /dev/null +++ b/lazycell/CHANGELOG.md @@ -0,0 +1,178 @@ + +## v1.2.1 (2018-12-03) + + +#### Features + +* Implement Clone for LazyCell and AtomicLazyCell ([30fe4a8f](https://github.com/indiv0/lazycell/commit/30fe4a8f568059b3c78ed149a810962a676cb2b2)) + + + + +## v1.2.0 (2018-09-19) + + +#### Features + +* add `LazyCell::replace` for infallible access ([a63ffb90](https://github.com/indiv0/lazycell/commit/a63ffb9040a5e0683a9bbf9d3d5ef589f2ca8b7c)) + + + + +## v1.1.0 (2018-09-10) + + +#### Documentation + +* add note regarding LazyCell::borrow_mut ([9d634d1f](https://github.com/indiv0/lazycell/commit/9d634d1fd9a21b7aa075d407bedf9fe77ba8b79f)) +* describe mutability more consistently ([b8078029](https://github.com/indiv0/lazycell/commit/b80780294611e92efddcdd33a701b3049ab5c5eb), closes [#78](https://github.com/indiv0/lazycell/issues/78)) + +#### Improvements + +* add NONE constant for an empty AtomicLazyCell ([31aff0da](https://github.com/indiv0/lazycell/commit/31aff0dacf824841c5f38ef4acf0aa71ec4c36eb), closes [#87](https://github.com/indiv0/lazycell/issues/87)) +* add `LazyCell::borrow_mut_with` and `LazyCell::try_borrow_mut_with` ([fdc6d268](https://github.com/indiv0/lazycell/commit/fdc6d268f0e9a6668768302f45fe2bb4aa9a7c34), closes [#79](https://github.com/indiv0/lazycell/issues/79), [#80](https://github.com/indiv0/lazycell/issues/80)) + + + + +## v1.0.0 (2018-06-06) + + +#### Features + +* Add #![no_std] ([e59f6b55](https://github.com/indiv0/lazycell/commit/e59f6b5531e310d3df26b0eb40b1431937f38096)) + + + + +## 0.6.0 (2017-11-25) + + +#### Bug Fixes + +* fix soundness hole in borrow_with ([d1f46bef](https://github.com/indiv0/lazycell/commit/d1f46bef9d1397570aa9c3e87e18e0d16e6d1585)) + +#### Features + +* add Default derives ([71bc5088](https://github.com/indiv0/lazycell/commit/71bc50880cd8e20002038197c9b890f5b76ad096)) +* add LazyCell::try_borrow_with ([bffa4028](https://github.com/indiv0/lazycell/commit/bffa402896670b5c78a9ec050d82a58ee98de6fb)) +* add LazyCell::borrow_mut method ([fd419dea](https://github.com/indiv0/lazycell/commit/fd419dea965ff1ad3853f26f37e8d107c6ca096c)) + +#### Breaking Changes + +* add `T: Send` for `AtomicLazyCell` `Sync` impl ([668bb2fa](https://github.com/indiv0/lazycell/commit/668bb2fa974fd6707c4c7edad292c76a9017d74d), closes [#67](https://github.com/indiv0/lazycell/issues/67)) + +#### Improvements + +* add `T: Send` for `AtomicLazyCell` `Sync` impl ([668bb2fa](https://github.com/indiv0/lazycell/commit/668bb2fa974fd6707c4c7edad292c76a9017d74d), closes [#67](https://github.com/indiv0/lazycell/issues/67)) + + + + +## v0.5.1 (2017-03-24) + + +#### Documentation + +* fix missing backticks ([44bafaaf](https://github.com/indiv0/lazycell/commit/44bafaaf93a91641261f58ee38adadcd4af6458e)) + +#### Improvements + +* derive `Debug` impls ([9da0a5a2](https://github.com/indiv0/lazycell/commit/9da0a5a2ffac1fef03ef02851c2c89d26d67d225)) + +#### Features + +* Add get method for Copy types ([dc8f8209](https://github.com/indiv0/lazycell/commit/dc8f8209888b6eba6d18717eba6a22614629b997)) + + + + +## v0.5.0 (2016-12-08) + + +#### Features + +* add borrow_with to LazyCell ([a15efa35](https://github.com/indiv0/lazycell/commit/a15efa359ea5a31a66ba57fc5b25f90c87b4b0dd)) + + + + +## (2016-08-17) + + +#### Breaking Changes + +* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/)) + +#### Improvements + +* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/)) + + + + +## (2016-08-16) + + +#### Features + +* add AtomicLazyCell which is thread-safe ([85afbd36](https://github.com/indiv0/lazycell/commit/85afbd36d8a148e14cc53654b39ddb523980124d)) + +#### Improvements + +* Use UnsafeCell instead of RefCell ([3347a8e9](https://github.com/indiv0/lazycell/commit/3347a8e97d2215a47e25c1e2fc953e8052ad8eb6)) + + + + +## (2016-04-18) + + +#### Documentation + +* put types in between backticks ([607cf939](https://github.com/indiv0/lazycell/commit/607cf939b05e35001ba3070ec7a0b17b064e7be1)) + + + + +## v0.2.0 (2016-03-28) + + +#### Features + +* **lazycell:** + * add tests for `LazyCell` struct ([38f1313d](https://github.com/indiv0/lazycell/commit/38f1313d98542ca8c98b424edfa9ba9c3975f99e), closes [#30](https://github.com/indiv0/lazycell/issues/30)) + * remove unnecessary `Default` impl ([68c16d2d](https://github.com/indiv0/lazycell/commit/68c16d2df4e9d13d5298162c06edf918246fd758)) + +#### Documentation + +* **CHANGELOG:** removed unnecessary sections ([1cc0555d](https://github.com/indiv0/lazycell/commit/1cc0555d875898a01b0832ff967aed6b40e720eb)) +* **README:** add link to documentation ([c8dc33f0](https://github.com/indiv0/lazycell/commit/c8dc33f01f2c0dc187f59ee53a2b73081053012b), closes [#13](https://github.com/indiv0/lazycell/issues/13)) + + + + +## v0.1.0 (2016-03-16) + + +#### Features + +* **lib.rs:** implement Default trait for LazyCell ([150a6304](https://github.com/indiv0/LazyCell/commit/150a6304a230ee1de8424e49c447ec1b2d6578ce)) + + + + +## v0.0.1 (2016-03-16) + + +#### Bug Fixes + +* **Cargo.toml:** loosen restrictions on Clippy version ([84dd8f96](https://github.com/indiv0/LazyCell/commit/84dd8f960000294f9dad47d776a41b98ed812981)) + +#### Features + +* add initial implementation ([4b39764a](https://github.com/indiv0/LazyCell/commit/4b39764a575bcb701dbd8047b966f72720fd18a4)) +* add initial commit ([a80407a9](https://github.com/indiv0/LazyCell/commit/a80407a907ef7c9401f120104663172f6965521a)) + + + diff --git a/lazycell/Cargo.toml b/lazycell/Cargo.toml new file mode 100644 index 000000000..dbb0d43df --- /dev/null +++ b/lazycell/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "lazycell" +version = "1.2.1" +authors = ["Alex Crichton ", "Nikita Pekin "] +include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"] +description = "A library providing a lazily filled Cell struct" +documentation = "http://indiv0.github.io/lazycell/lazycell/" +readme = "README.md" +keywords = ["lazycell", "lazy", "cell", "library"] +license = "MIT/Apache-2.0" +repository = "https://github.com/indiv0/lazycell" diff --git a/lazycell/LICENSE-APACHE b/lazycell/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/lazycell/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lazycell/LICENSE-MIT b/lazycell/LICENSE-MIT new file mode 100644 index 000000000..b4cbb4b7e --- /dev/null +++ b/lazycell/LICENSE-MIT @@ -0,0 +1,26 @@ +Original work Copyright (c) 2014 The Rust Project Developers +Modified work Copyright (c) 2016-2018 Nikita Pekin and lazycell contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/lazycell/README.md b/lazycell/README.md new file mode 100644 index 000000000..4e1dd993f --- /dev/null +++ b/lazycell/README.md @@ -0,0 +1,72 @@ +# lazycell + + + + + + + + + +
Linuxtravis-badge
+ api-docs-badge + crates-io + license-badge + coveralls-badge +
+ +Rust library providing a lazily filled Cell. + +# Table of Contents + +* [Usage](#usage) +* [Contributing](#contributing) +* [Credits](#credits) +* [License](#license) + +## Usage + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +lazycell = "1.2" +``` + +And in your `lib.rs` or `main.rs`: + +```rust +extern crate lazycell; +``` + +See the [API docs][api-docs] for information on using the crate in your library. + +## Contributing + +Contributions are always welcome! +If you have an idea for something to add (code, documentation, tests, examples, +etc.) feel free to give it a shot. + +Please read [CONTRIBUTING.md][contributing] before you start contributing. + +## Credits + +The LazyCell library is based originally on work by The Rust Project Developers +for the project [crates.io][crates-io-repo]. + +The list of contributors to this project can be found at +[CONTRIBUTORS.md][contributors]. + +## License + +LazyCell is distributed under the terms of both the MIT license and the Apache +License (Version 2.0). + +See [LICENSE-APACHE][license-apache], and [LICENSE-MIT][license-mit] for details. + +[api-docs]: https://indiv0.github.io/lazycell/lazycell +[contributing]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTING.md "Contribution Guide" +[contributors]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTORS.md "List of Contributors" +[crates-io-repo]: https://github.com/rust-lang/crates.io "rust-lang/crates.io: Source code for crates.io" +[license-apache]: https://github.com/indiv0/lazycell/blob/master/LICENSE-APACHE "Apache-2.0 License" +[license-mit]: https://github.com/indiv0/lazycell/blob/master/LICENSE-MIT "MIT License" diff --git a/lazycell/debian/patches/no-clippy.patch b/lazycell/debian/patches/no-clippy.patch new file mode 100644 index 000000000..5881ed6da --- /dev/null +++ b/lazycell/debian/patches/no-clippy.patch @@ -0,0 +1,11 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -23,8 +23 @@ license = "MIT/Apache-2.0" + repository = "https://github.com/indiv0/lazycell" +-[dependencies.clippy] +-version = "0.0" +-optional = true +- +-[features] +-nightly = [] +-nightly-testing = ["clippy", "nightly"] diff --git a/lazycell/debian/patches/series b/lazycell/debian/patches/series new file mode 100644 index 000000000..bce906376 --- /dev/null +++ b/lazycell/debian/patches/series @@ -0,0 +1 @@ +no-clippy.patch diff --git a/lazycell/src/lib.rs b/lazycell/src/lib.rs new file mode 100644 index 000000000..f7f8488a5 --- /dev/null +++ b/lazycell/src/lib.rs @@ -0,0 +1,649 @@ +// Original work Copyright (c) 2014 The Rust Project Developers +// Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors +// See the README.md file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(test), no_std)] + +#![deny(missing_docs)] +#![cfg_attr(feature = "nightly", feature(plugin))] +#![cfg_attr(feature = "clippy", plugin(clippy))] + +//! This crate provides a `LazyCell` struct which acts as a lazily filled +//! `Cell`. +//! +//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of +//! the entire object, but only of the borrows returned. A `LazyCell` is a +//! variation on `RefCell` which allows borrows to be tied to the lifetime of +//! the outer object. +//! +//! # Example +//! +//! The following example shows a quick example of the basic functionality of +//! `LazyCell`. +//! +//! ``` +//! use lazycell::LazyCell; +//! +//! let lazycell = LazyCell::new(); +//! +//! assert_eq!(lazycell.borrow(), None); +//! assert!(!lazycell.filled()); +//! lazycell.fill(1).ok(); +//! assert!(lazycell.filled()); +//! assert_eq!(lazycell.borrow(), Some(&1)); +//! assert_eq!(lazycell.into_inner(), Some(1)); +//! ``` +//! +//! `AtomicLazyCell` is a variant that uses an atomic variable to manage +//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell` +//! is that after it is initialized, it can't be modified. + + +#[cfg(not(test))] +#[macro_use] +extern crate core as std; + +use std::cell::UnsafeCell; +use std::mem; +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// A lazily filled `Cell`, with mutable contents. +/// +/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut` +/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the +/// contents. +#[derive(Debug, Default)] +pub struct LazyCell { + inner: UnsafeCell>, +} + +impl LazyCell { + /// Creates a new, empty, `LazyCell`. + pub fn new() -> LazyCell { + LazyCell { inner: UnsafeCell::new(None) } + } + + /// Put a value into this cell. + /// + /// This function will return `Err(value)` is the cell is already full. + pub fn fill(&self, value: T) -> Result<(), T> { + let slot = unsafe { &mut *self.inner.get() }; + if slot.is_some() { + return Err(value); + } + *slot = Some(value); + + Ok(()) + } + + /// Put a value into this cell. + /// + /// Note that this function is infallible but requires `&mut self`. By + /// requiring `&mut self` we're guaranteed that no active borrows to this + /// cell can exist so we can always fill in the value. This may not always + /// be usable, however, as `&mut self` may not be possible to borrow. + /// + /// # Return value + /// + /// This function returns the previous value, if any. + pub fn replace(&mut self, value: T) -> Option { + mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) + } + + /// Test whether this cell has been previously filled. + pub fn filled(&self) -> bool { + self.borrow().is_some() + } + + /// Borrows the contents of this lazy cell for the duration of the cell + /// itself. + /// + /// This function will return `Some` if the cell has been previously + /// initialized, and `None` if it has not yet been initialized. + pub fn borrow(&self) -> Option<&T> { + unsafe { &*self.inner.get() }.as_ref() + } + + /// Borrows the contents of this lazy cell mutably for the duration of the cell + /// itself. + /// + /// This function will return `Some` if the cell has been previously + /// initialized, and `None` if it has not yet been initialized. + pub fn borrow_mut(&mut self) -> Option<&mut T> { + unsafe { &mut *self.inner.get() }.as_mut() + } + + /// Borrows the contents of this lazy cell for the duration of the cell + /// itself. + /// + /// If the cell has not yet been filled, the cell is first filled using the + /// function provided. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn borrow_with T>(&self, f: F) -> &T { + if let Some(value) = self.borrow() { + return value; + } + let value = f(); + if self.fill(value).is_err() { + panic!("borrow_with: cell was filled by closure") + } + self.borrow().unwrap() + } + + /// Borrows the contents of this `LazyCell` mutably for the duration of the + /// cell itself. + /// + /// If the cell has not yet been filled, the cell is first filled using the + /// function provided. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn borrow_mut_with T>(&mut self, f: F) -> &mut T { + if !self.filled() { + let value = f(); + if self.fill(value).is_err() { + panic!("borrow_mut_with: cell was filled by closure") + } + } + + self.borrow_mut().unwrap() + } + + /// Same as `borrow_with`, but allows the initializing function to fail. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn try_borrow_with(&self, f: F) -> Result<&T, E> + where F: FnOnce() -> Result + { + if let Some(value) = self.borrow() { + return Ok(value); + } + let value = f()?; + if self.fill(value).is_err() { + panic!("try_borrow_with: cell was filled by closure") + } + Ok(self.borrow().unwrap()) + } + + /// Same as `borrow_mut_with`, but allows the initializing function to fail. + /// + /// # Panics + /// + /// Panics if the cell becomes filled as a side effect of `f`. + pub fn try_borrow_mut_with(&mut self, f: F) -> Result<&mut T, E> + where F: FnOnce() -> Result + { + if self.filled() { + return Ok(self.borrow_mut().unwrap()); + } + let value = f()?; + if self.fill(value).is_err() { + panic!("try_borrow_mut_with: cell was filled by closure") + } + Ok(self.borrow_mut().unwrap()) + } + + /// Consumes this `LazyCell`, returning the underlying value. + pub fn into_inner(self) -> Option { + // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe + // function. This unsafe can be removed when supporting Rust older than + // 1.25 is not needed. + #[allow(unused_unsafe)] + unsafe { self.inner.into_inner() } + } +} + +impl LazyCell { + /// Returns a copy of the contents of the lazy cell. + /// + /// This function will return `Some` if the cell has been previously initialized, + /// and `None` if it has not yet been initialized. + pub fn get(&self) -> Option { + unsafe { *self.inner.get() } + } +} + +impl Clone for LazyCell { + /// Create a clone of this `LazyCell` + /// + /// If self has not been initialized, returns an uninitialized `LazyCell` + /// otherwise returns a `LazyCell` already initialized with a clone of the + /// contents of self. + fn clone(&self) -> LazyCell { + LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) } + } +} + +// Tracks the AtomicLazyCell inner state +const NONE: usize = 0; +const LOCK: usize = 1; +const SOME: usize = 2; + +/// A lazily filled and thread-safe `Cell`, with frozen contents. +#[derive(Debug, Default)] +pub struct AtomicLazyCell { + inner: UnsafeCell>, + state: AtomicUsize, +} + +impl AtomicLazyCell { + /// An empty `AtomicLazyCell`. + pub const NONE: Self = Self { + inner: UnsafeCell::new(None), + state: AtomicUsize::new(NONE), + }; + + /// Creates a new, empty, `AtomicLazyCell`. + pub fn new() -> AtomicLazyCell { + Self::NONE + } + + /// Put a value into this cell. + /// + /// This function will return `Err(value)` is the cell is already full. + pub fn fill(&self, t: T) -> Result<(), T> { + if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) { + return Err(t); + } + + unsafe { *self.inner.get() = Some(t) }; + + if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) { + panic!("unable to release lock"); + } + + Ok(()) + } + + /// Put a value into this cell. + /// + /// Note that this function is infallible but requires `&mut self`. By + /// requiring `&mut self` we're guaranteed that no active borrows to this + /// cell can exist so we can always fill in the value. This may not always + /// be usable, however, as `&mut self` may not be possible to borrow. + /// + /// # Return value + /// + /// This function returns the previous value, if any. + pub fn replace(&mut self, value: T) -> Option { + match mem::replace(self.state.get_mut(), SOME) { + NONE | SOME => {} + _ => panic!("cell in inconsistent state"), + } + mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) + } + + /// Test whether this cell has been previously filled. + pub fn filled(&self) -> bool { + self.state.load(Ordering::Acquire) == SOME + } + + /// Borrows the contents of this lazy cell for the duration of the cell + /// itself. + /// + /// This function will return `Some` if the cell has been previously + /// initialized, and `None` if it has not yet been initialized. + pub fn borrow(&self) -> Option<&T> { + match self.state.load(Ordering::Acquire) { + SOME => unsafe { &*self.inner.get() }.as_ref(), + _ => None, + } + } + + /// Consumes this `LazyCell`, returning the underlying value. + pub fn into_inner(self) -> Option { + // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe + // function. This unsafe can be removed when supporting Rust older than + // 1.25 is not needed. + #[allow(unused_unsafe)] + unsafe { self.inner.into_inner() } + } +} + +impl AtomicLazyCell { + /// Returns a copy of the contents of the lazy cell. + /// + /// This function will return `Some` if the cell has been previously initialized, + /// and `None` if it has not yet been initialized. + pub fn get(&self) -> Option { + match self.state.load(Ordering::Acquire) { + SOME => unsafe { *self.inner.get() }, + _ => None, + } + } +} + +impl Clone for AtomicLazyCell { + /// Create a clone of this `AtomicLazyCell` + /// + /// If self has not been initialized, returns an uninitialized `AtomicLazyCell` + /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the + /// contents of self. + fn clone(&self) -> AtomicLazyCell { + self.borrow().map_or( + Self::NONE, + |v| AtomicLazyCell { + inner: UnsafeCell::new(Some(v.clone())), + state: AtomicUsize::new(SOME), + } + ) + } +} + +unsafe impl Sync for AtomicLazyCell {} + +unsafe impl Send for AtomicLazyCell {} + +#[cfg(test)] +mod tests { + use super::{AtomicLazyCell, LazyCell}; + + #[test] + fn test_borrow_from_empty() { + let lazycell: LazyCell = LazyCell::new(); + + let value = lazycell.borrow(); + assert_eq!(value, None); + + let value = lazycell.get(); + assert_eq!(value, None); + } + + #[test] + fn test_fill_and_borrow() { + let lazycell = LazyCell::new(); + + assert!(!lazycell.filled()); + lazycell.fill(1).unwrap(); + assert!(lazycell.filled()); + + let value = lazycell.borrow(); + assert_eq!(value, Some(&1)); + + let value = lazycell.get(); + assert_eq!(value, Some(1)); + } + + #[test] + fn test_borrow_mut() { + let mut lazycell = LazyCell::new(); + assert!(lazycell.borrow_mut().is_none()); + + lazycell.fill(1).unwrap(); + assert_eq!(lazycell.borrow_mut(), Some(&mut 1)); + + *lazycell.borrow_mut().unwrap() = 2; + assert_eq!(lazycell.borrow_mut(), Some(&mut 2)); + + // official way to reset the cell + lazycell = LazyCell::new(); + assert!(lazycell.borrow_mut().is_none()); + } + + #[test] + fn test_already_filled_error() { + let lazycell = LazyCell::new(); + + lazycell.fill(1).unwrap(); + assert_eq!(lazycell.fill(1), Err(1)); + } + + #[test] + fn test_borrow_with() { + let lazycell = LazyCell::new(); + + let value = lazycell.borrow_with(|| 1); + assert_eq!(&1, value); + } + + #[test] + fn test_borrow_with_already_filled() { + let lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_with(|| 1); + assert_eq!(&1, value); + } + + #[test] + fn test_borrow_with_not_called_when_filled() { + let lazycell = LazyCell::new(); + + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_with(|| 2); + assert_eq!(&1, value); + } + + #[test] + #[should_panic] + fn test_borrow_with_sound_with_reentrancy() { + // Kudos to dbaupp for discovering this issue + // https://www.reddit.com/r/rust/comments/5vs9rt/lazycell_a_rust_library_providing_a_lazilyfilled/de527xm/ + let lazycell: LazyCell> = LazyCell::new(); + + let mut reference: Option<&i32> = None; + + lazycell.borrow_with(|| { + let _ = lazycell.fill(Box::new(1)); + reference = lazycell.borrow().map(|r| &**r); + Box::new(2) + }); + } + + #[test] + fn test_borrow_mut_with() { + let mut lazycell = LazyCell::new(); + + { + let value = lazycell.borrow_mut_with(|| 1); + assert_eq!(&mut 1, value); + *value = 2; + } + assert_eq!(&2, lazycell.borrow().unwrap()); + } + + #[test] + fn test_borrow_mut_with_already_filled() { + let mut lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_mut_with(|| 1); + assert_eq!(&1, value); + } + + #[test] + fn test_borrow_mut_with_not_called_when_filled() { + let mut lazycell = LazyCell::new(); + + lazycell.fill(1).unwrap(); + + let value = lazycell.borrow_mut_with(|| 2); + assert_eq!(&1, value); + } + + #[test] + fn test_try_borrow_with_ok() { + let lazycell = LazyCell::new(); + let result = lazycell.try_borrow_with::<(), _>(|| Ok(1)); + assert_eq!(result, Ok(&1)); + } + + #[test] + fn test_try_borrow_with_err() { + let lazycell = LazyCell::<()>::new(); + let result = lazycell.try_borrow_with(|| Err(1)); + assert_eq!(result, Err(1)); + } + + #[test] + fn test_try_borrow_with_already_filled() { + let lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + let result = lazycell.try_borrow_with::<(), _>(|| unreachable!()); + assert_eq!(result, Ok(&1)); + } + + #[test] + #[should_panic] + fn test_try_borrow_with_sound_with_reentrancy() { + let lazycell: LazyCell> = LazyCell::new(); + + let mut reference: Option<&i32> = None; + + let _ = lazycell.try_borrow_with::<(), _>(|| { + let _ = lazycell.fill(Box::new(1)); + reference = lazycell.borrow().map(|r| &**r); + Ok(Box::new(2)) + }); + } + + #[test] + fn test_try_borrow_mut_with_ok() { + let mut lazycell = LazyCell::new(); + { + let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1)); + assert_eq!(result, Ok(&mut 1)); + *result.unwrap() = 2; + } + assert_eq!(&mut 2, lazycell.borrow().unwrap()); + } + + #[test] + fn test_try_borrow_mut_with_err() { + let mut lazycell = LazyCell::<()>::new(); + let result = lazycell.try_borrow_mut_with(|| Err(1)); + assert_eq!(result, Err(1)); + } + + #[test] + fn test_try_borrow_mut_with_already_filled() { + let mut lazycell = LazyCell::new(); + lazycell.fill(1).unwrap(); + let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!()); + assert_eq!(result, Ok(&mut 1)); + } + + #[test] + fn test_into_inner() { + let lazycell = LazyCell::new(); + + lazycell.fill(1).unwrap(); + let value = lazycell.into_inner(); + assert_eq!(value, Some(1)); + } + + #[test] + fn test_atomic_borrow_from_empty() { + let lazycell: AtomicLazyCell = AtomicLazyCell::new(); + + let value = lazycell.borrow(); + assert_eq!(value, None); + + let value = lazycell.get(); + assert_eq!(value, None); + } + + #[test] + fn test_atomic_fill_and_borrow() { + let lazycell = AtomicLazyCell::new(); + + assert!(!lazycell.filled()); + lazycell.fill(1).unwrap(); + assert!(lazycell.filled()); + + let value = lazycell.borrow(); + assert_eq!(value, Some(&1)); + + let value = lazycell.get(); + assert_eq!(value, Some(1)); + } + + #[test] + fn test_atomic_already_filled_panic() { + let lazycell = AtomicLazyCell::new(); + + lazycell.fill(1).unwrap(); + assert_eq!(1, lazycell.fill(1).unwrap_err()); + } + + #[test] + fn test_atomic_into_inner() { + let lazycell = AtomicLazyCell::new(); + + lazycell.fill(1).unwrap(); + let value = lazycell.into_inner(); + assert_eq!(value, Some(1)); + } + + #[test] + fn normal_replace() { + let mut cell = LazyCell::new(); + assert_eq!(cell.fill(1), Ok(())); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(cell.replace(3), Some(2)); + assert_eq!(cell.borrow(), Some(&3)); + + let mut cell = LazyCell::new(); + assert_eq!(cell.replace(2), None); + } + + #[test] + fn atomic_replace() { + let mut cell = AtomicLazyCell::new(); + assert_eq!(cell.fill(1), Ok(())); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(cell.replace(3), Some(2)); + assert_eq!(cell.borrow(), Some(&3)); + } + + #[test] + fn clone() { + let mut cell = LazyCell::new(); + let clone1 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(cell.fill(1), Ok(())); + let mut clone2 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(clone1.fill(3), Ok(())); + assert_eq!(clone2.replace(4), Some(1)); + assert_eq!(clone1.borrow(), Some(&3)); + assert_eq!(clone2.borrow(), Some(&4)); + assert_eq!(cell.borrow(), Some(&2)); + } + + #[test] + fn clone_atomic() { + let mut cell = AtomicLazyCell::new(); + let clone1 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(cell.fill(1), Ok(())); + let mut clone2 = cell.clone(); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(cell.replace(2), Some(1)); + assert_eq!(clone1.borrow(), None); + assert_eq!(clone2.borrow(), Some(&1)); + assert_eq!(clone1.fill(3), Ok(())); + assert_eq!(clone2.replace(4), Some(1)); + assert_eq!(clone1.borrow(), Some(&3)); + assert_eq!(clone2.borrow(), Some(&4)); + assert_eq!(cell.borrow(), Some(&2)); + } +} diff --git a/libc/.cargo-checksum.json b/libc/.cargo-checksum.json new file mode 100644 index 000000000..883ec0cc4 --- /dev/null +++ b/libc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880"} \ No newline at end of file diff --git a/libc/CONTRIBUTING.md b/libc/CONTRIBUTING.md new file mode 100644 index 000000000..0e5d0c68b --- /dev/null +++ b/libc/CONTRIBUTING.md @@ -0,0 +1,66 @@ +# Contributing to `libc` + +Welcome! If you are reading this document, it means you are interested in contributing +to the `libc` crate. + +## Adding an API + +Want to use an API which currently isn't bound in `libc`? It's quite easy to add +one! + +The internal structure of this crate is designed to minimize the number of +`#[cfg]` attributes in order to easily be able to add new items which apply +to all platforms in the future. As a result, the crate is organized +hierarchically based on platform. Each module has a number of `#[cfg]`'d +children, but only one is ever actually compiled. Each module then reexports all +the contents of its children. + +This means that for each platform that libc supports, the path from a +leaf module to the root will contain all bindings for the platform in question. +Consequently, this indicates where an API should be added! Adding an API at a +particular level in the hierarchy means that it is supported on all the child +platforms of that level. For example, when adding a Unix API it should be added +to `src/unix/mod.rs`, but when adding a Linux-only API it should be added to +`src/unix/notbsd/linux/mod.rs`. + +If you're not 100% sure at what level of the hierarchy an API should be added +at, fear not! This crate has CI support which tests any binding against all +platforms supported, so you'll see failures if an API is added at the wrong +level or has different signatures across platforms. + +With that in mind, the steps for adding a new API are: + +1. Determine where in the module hierarchy your API should be added. +2. Add the API. +3. Send a PR to this repo. +4. Wait for CI to pass, fixing errors. +5. Wait for a merge! + +### Test before you commit + +We have two automated tests running on [Travis](https://travis-ci.org/rust-lang/libc): + +1. [`libc-test`](https://github.com/alexcrichton/ctest) + - `cd libc-test && cargo test` + - Use the `skip_*()` functions in `build.rs` if you really need a workaround. +2. Style checker + - `rustc ci/style.rs && ./style src` + +### Releasing your change to crates.io + +Now that you've done the amazing job of landing your new API or your new +platform in this crate, the next step is to get that sweet, sweet usage from +crates.io! The only next step is to bump the version of libc and then publish +it. If you'd like to get a release out ASAP you can follow these steps: + +1. Update the version number in `Cargo.toml`, you'll just be bumping the patch + version number. +2. Run `cargo update` to regenerate the lockfile to encode your version bump in + the lock file. You may pull in some other updated dependencies, that's ok. +3. Send a PR to this repository. It should [look like this][example], but it'd + also be nice to fill out the description with a small rationale for the + release (any rationale is ok though!) +4. Once merged the release will be tagged and published by one of the libc crate + maintainers. + +[example]: https://github.com/rust-lang/libc/pull/583 diff --git a/libc/Cargo.toml b/libc/Cargo.toml new file mode 100644 index 000000000..86a488df3 --- /dev/null +++ b/libc/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libc" +version = "0.2.55" +authors = ["The Rust Project Developers"] +build = "build.rs" +exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"] +description = "Raw FFI bindings to platform libraries like libc.\n" +homepage = "https://github.com/rust-lang/libc" +documentation = "http://doc.rust-lang.org/libc" +readme = "README.md" +keywords = ["libc", "ffi", "bindings", "operating", "system"] +categories = ["external-ffi-bindings", "no-std", "os"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/libc" +[dependencies.rustc-std-workspace-core] +version = "1.0.0" +optional = true + +[features] +align = [] +default = ["use_std"] +extra_traits = [] +rustc-dep-of-std = ["align", "rustc-std-workspace-core"] +use_std = [] +[badges.appveyor] +project_name = "rust-lang-libs/libc" +repository = "rust-lang/libc" + +[badges.travis-ci] +repository = "rust-lang/libc" diff --git a/libc/LICENSE-APACHE b/libc/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/libc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libc/LICENSE-MIT b/libc/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/libc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libc/README.md b/libc/README.md new file mode 100644 index 000000000..a974ccd41 --- /dev/null +++ b/libc/README.md @@ -0,0 +1,103 @@ +[![Travis-CI Status]][Travis-CI] [![Appveyor Status]][Appveyor] [![Cirrus-CI Status]][Cirrus-CI] [![Latest Version]][crates.io] [![Documentation]][docs.rs] ![License] + +libc - Raw FFI bindings to platforms' system libraries +==== + +`libc` provides all of the definitions necessary to easily interoperate with C +code (or "C-like" code) on each of the platforms that Rust supports. This +includes type definitions (e.g. `c_int`), constants (e.g. `EINVAL`) as well as +function headers (e.g. `malloc`). + +This crate exports all underlying platform types, functions, and constants under +the crate root, so all items are accessible as `libc::foo`. The types and values +of all the exported APIs match the platform that libc is compiled for. + +More detailed information about the design of this library can be found in its +[associated RFC][rfc]. + +[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1291-promote-libc.md + +## Usage + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +libc = "0.2" +``` + +## Features + +* `use_std`: by default `libc` links to the standard library. Disable this + feature remove this dependency and be able to use `libc` in `#![no_std]` + crates. + +* `extra_traits`: all `struct`s implemented in `libc` are `Copy` and `Clone`. + This feature derives `Debug`, `Eq`, `Hash`, and `PartialEq`. + +## Rust version support + +The minimum supported Rust toolchain version is **Rust 1.13.0** . APIs requiring +newer Rust features are only available on newer Rust toolchains: + +| Feature | Version | +|----------------------|---------| +| `union` | 1.19.0 | +| `const mem::size_of` | 1.24.0 | +| `repr(align)` | 1.25.0 | +| `extra_traits` | 1.25.0 | +| `core::ffi::c_void` | 1.30.0 | +| `repr(packed(N))` | 1.33.0 | + +## Platform support + +[Platform-specific documentation (master branch)][docs.master]. + +See +[`ci/build.sh`](https://github.com/rust-lang/libc/blob/master/libc-test/build.rs) +for the platforms on which `libc` is guaranteed to build for each Rust +toolchain. The test-matrix at [Travis-CI], [Appveyor], and [Cirrus-CI] show the +platforms in which `libc` tests are run. + +

+ +## License + +This project is licensed under either of + +* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + ([LICENSE-APACHE](LICENSE-APACHE)) + +* [MIT License](http://opensource.org/licenses/MIT) + ([LICENSE-MIT](LICENSE-MIT)) + +at your option. + +## Contributing + +We welcome all people who want to contribute. Please see the [contributing +instructions] for more information. + +[contributing instructions]: CONTRIBUTING.md + +Contributions in any form (issues, pull requests, etc.) to this project +must adhere to Rust's [Code of Conduct]. + +[Code of Conduct]: https://www.rust-lang.org/en-US/conduct.html + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `libc` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[Travis-CI]: https://travis-ci.com/rust-lang/libc +[Travis-CI Status]: https://travis-ci.com/rust-lang/libc.svg?branch=master +[Appveyor]: https://ci.appveyor.com/project/rust-lang-libs/libc +[Appveyor Status]: https://ci.appveyor.com/api/projects/status/github/rust-lang/libc?svg=true +[Cirrus-CI]: https://cirrus-ci.com/github/rust-lang/libc +[Cirrus-CI Status]: https://api.cirrus-ci.com/github/rust-lang/libc.svg +[crates.io]: https://crates.io/crates/libc +[Latest Version]: https://img.shields.io/crates/v/libc.svg +[Documentation]: https://docs.rs/libc/badge.svg +[docs.rs]: https://docs.rs/libc +[License]: https://img.shields.io/crates/l/libc.svg +[docs.master]: https://rust-lang.github.io/libc/#platform-specific-documentation diff --git a/libc/build.rs b/libc/build.rs new file mode 100644 index 000000000..9b1337677 --- /dev/null +++ b/libc/build.rs @@ -0,0 +1,65 @@ +use std::env; +use std::process::Command; +use std::str; + +fn main() { + let rustc_minor_ver = + rustc_minor_version().expect("Failed to get rustc version"); + let rustc_dep_of_std = + std::env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok(); + let align_cargo_feature = std::env::var("CARGO_FEATURE_ALIGN").is_ok(); + + // Rust >= 1.15 supports private module use: + if rustc_minor_ver >= 15 || rustc_dep_of_std { + println!("cargo:rustc-cfg=libc_priv_mod_use"); + } + + // Rust >= 1.19 supports unions: + if rustc_minor_ver >= 19 || rustc_dep_of_std { + println!("cargo:rustc-cfg=libc_union"); + } + + // Rust >= 1.24 supports const mem::size_of: + if rustc_minor_ver >= 24 || rustc_dep_of_std { + println!("cargo:rustc-cfg=libc_const_size_of"); + } + + // Rust >= 1.25 supports repr(align): + if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature { + println!("cargo:rustc-cfg=libc_align"); + } + + // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it. + // Otherwise, it defines an incompatible type to retaining + // backwards-compatibility. + if rustc_minor_ver >= 30 || rustc_dep_of_std { + println!("cargo:rustc-cfg=libc_core_cvoid"); + } + + // Rust >= 1.33 supports repr(packed(N)) + if rustc_minor_ver >= 33 || rustc_dep_of_std { + println!("cargo:rustc-cfg=libc_packedN"); + } +} + +fn rustc_minor_version() -> Option { + macro_rules! otry { + ($e:expr) => { + match $e { + Some(e) => e, + None => return None, + } + }; + } + + let rustc = otry!(env::var_os("RUSTC")); + let output = otry!(Command::new(rustc).arg("--version").output().ok()); + let version = otry!(str::from_utf8(&output.stdout).ok()); + let mut pieces = version.split('.'); + + if pieces.next() != Some("rustc 1") { + return None; + } + + otry!(pieces.next()).parse().ok() +} diff --git a/libc/rustfmt.toml b/libc/rustfmt.toml new file mode 100644 index 000000000..7ecc610f3 --- /dev/null +++ b/libc/rustfmt.toml @@ -0,0 +1,3 @@ +max_width = 79 +comment_width = 79 +error_on_line_overflow = true \ No newline at end of file diff --git a/libc/src/cloudabi/aarch64.rs b/libc/src/cloudabi/aarch64.rs new file mode 100644 index 000000000..4caa6d7bb --- /dev/null +++ b/libc/src/cloudabi/aarch64.rs @@ -0,0 +1,4 @@ +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type wchar_t = u32; diff --git a/libc/src/cloudabi/arm.rs b/libc/src/cloudabi/arm.rs new file mode 100644 index 000000000..eca536074 --- /dev/null +++ b/libc/src/cloudabi/arm.rs @@ -0,0 +1,4 @@ +pub type c_char = u8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type wchar_t = u32; diff --git a/libc/src/cloudabi/mod.rs b/libc/src/cloudabi/mod.rs new file mode 100644 index 000000000..819196755 --- /dev/null +++ b/libc/src/cloudabi/mod.rs @@ -0,0 +1,334 @@ +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type pthread_key_t = usize; +pub type pthread_t = usize; +pub type sa_family_t = u8; +pub type socklen_t = usize; +pub type time_t = i64; + +s! { + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_addr: *mut ::sockaddr, + pub ai_canonname: *mut ::c_char, + pub ai_next: *mut addrinfo, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + pub struct pthread_attr_t { + __detachstate: ::c_int, + __stacksize: usize, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 0], + } + + pub struct sockaddr_in { + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_storage { + pub ss_family: ::sa_family_t, + __ss_data: [u8; 32], + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const _SC_NPROCESSORS_ONLN: ::c_int = 52; +pub const _SC_PAGESIZE: ::c_int = 54; + +pub const AF_INET: ::c_int = 1; +pub const AF_INET6: ::c_int = 2; + +pub const EACCES: ::c_int = 2; +pub const EADDRINUSE: ::c_int = 3; +pub const EADDRNOTAVAIL: ::c_int = 4; +pub const EAGAIN: ::c_int = 6; +pub const ECONNABORTED: ::c_int = 13; +pub const ECONNREFUSED: ::c_int = 14; +pub const ECONNRESET: ::c_int = 15; +pub const EEXIST: ::c_int = 20; +pub const EINTR: ::c_int = 27; +pub const EINVAL: ::c_int = 28; +pub const ENOENT: ::c_int = 44; +pub const ENOTCONN: ::c_int = 53; +pub const EPERM: ::c_int = 63; +pub const EPIPE: ::c_int = 64; +pub const ETIMEDOUT: ::c_int = 73; +pub const EWOULDBLOCK: ::c_int = EAGAIN; + +pub const EAI_SYSTEM: ::c_int = 9; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; + +pub const PTHREAD_STACK_MIN: ::size_t = 1024; + +pub const SOCK_DGRAM: ::c_int = 128; +pub const SOCK_STREAM: ::c_int = 130; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum FILE {} +impl ::Copy for FILE {} +impl ::Clone for FILE { + fn clone(&self) -> FILE { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos_t {} // TODO: fill this out with a struct +impl ::Copy for fpos_t {} +impl ::Clone for fpos_t { + fn clone(&self) -> fpos_t { *self } +} + +extern { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, + file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, + size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atoi(s: *const c_char) -> c_int; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_long; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_ulong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + pub fn getline (lineptr: *mut *mut c_char, n: *mut size_t, + stream: *mut FILE) -> ssize_t; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, + n: size_t) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, + n: size_t) -> ::size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn abs(i: c_int) -> c_int; + pub fn atof(s: *const c_char) -> c_double; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn arc4random_buf(buf: *const ::c_void, len: ::size_t); + pub fn freeaddrinfo(res: *mut addrinfo); + pub fn gai_strerror(errcode: ::c_int) -> *const ::c_char; + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> ::c_int; + pub fn getsockopt( + sockfd: ::c_int, + level: ::c_int, + optname: ::c_int, + optval: *mut ::c_void, + optlen: *mut ::socklen_t, + ) -> ::c_int; + pub fn posix_memalign( + memptr: *mut *mut ::c_void, + align: ::size_t, + size: ::size_t, + ) -> ::c_int; + pub fn pthread_attr_destroy(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_init(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_setstacksize( + attr: *mut ::pthread_attr_t, + stack_size: ::size_t, + ) -> ::c_int; + pub fn pthread_create( + native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void, + ) -> ::c_int; + pub fn pthread_detach(thread: ::pthread_t) -> ::c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ::c_void; + pub fn pthread_join( + native: ::pthread_t, + value: *mut *mut ::c_void, + ) -> ::c_int; + pub fn pthread_key_create( + key: *mut pthread_key_t, + dtor: ::Option, + ) -> ::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ::c_int; + pub fn pthread_setspecific( + key: pthread_key_t, + value: *const ::c_void, + ) -> ::c_int; + pub fn send( + socket: ::c_int, + buf: *const ::c_void, + len: ::size_t, + flags: ::c_int, + ) -> ::ssize_t; + pub fn sysconf(name: ::c_int) -> ::c_long; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "arm"))] { + mod arm; + pub use self::arm::*; + } else if #[cfg(any(target_arch = "x86"))] { + mod x86; + pub use self::x86::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} diff --git a/libc/src/cloudabi/x86.rs b/libc/src/cloudabi/x86.rs new file mode 100644 index 000000000..2f9f39c9b --- /dev/null +++ b/libc/src/cloudabi/x86.rs @@ -0,0 +1,4 @@ +pub type c_char = i8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type wchar_t = i32; diff --git a/libc/src/cloudabi/x86_64.rs b/libc/src/cloudabi/x86_64.rs new file mode 100644 index 000000000..bb17624b1 --- /dev/null +++ b/libc/src/cloudabi/x86_64.rs @@ -0,0 +1,4 @@ +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type wchar_t = i32; diff --git a/libc/src/fuchsia/aarch64.rs b/libc/src/fuchsia/aarch64.rs new file mode 100644 index 000000000..572f8c1ce --- /dev/null +++ b/libc/src/fuchsia/aarch64.rs @@ -0,0 +1,336 @@ +pub type c_char = u8; +pub type __u64 = ::c_ulonglong; +pub type wchar_t = u32; +pub type nlink_t = ::c_ulong; +pub type blksize_t = ::c_long; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad0: ::c_ulong, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + __pad1: ::c_int, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_uint; 2], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad0: ::c_ulong, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + __pad1: ::c_int, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_uint; 2], + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong, + } +} + +pub const MINSIGSTKSZ: ::size_t = 6144; +pub const SIGSTKSZ: ::size_t = 12288; + +#[doc(hidden)] +pub const PF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const AF_MAX: ::c_int = PF_MAX; + +pub const SYS_io_setup: ::c_long = 0; +pub const SYS_io_destroy: ::c_long = 1; +pub const SYS_io_submit: ::c_long = 2; +pub const SYS_io_cancel: ::c_long = 3; +pub const SYS_io_getevents: ::c_long = 4; +pub const SYS_setxattr: ::c_long = 5; +pub const SYS_lsetxattr: ::c_long = 6; +pub const SYS_fsetxattr: ::c_long = 7; +pub const SYS_getxattr: ::c_long = 8; +pub const SYS_lgetxattr: ::c_long = 9; +pub const SYS_fgetxattr: ::c_long = 10; +pub const SYS_listxattr: ::c_long = 11; +pub const SYS_llistxattr: ::c_long = 12; +pub const SYS_flistxattr: ::c_long = 13; +pub const SYS_removexattr: ::c_long = 14; +pub const SYS_lremovexattr: ::c_long = 15; +pub const SYS_fremovexattr: ::c_long = 16; +pub const SYS_getcwd: ::c_long = 17; +pub const SYS_lookup_dcookie: ::c_long = 18; +pub const SYS_eventfd2: ::c_long = 19; +pub const SYS_epoll_create1: ::c_long = 20; +pub const SYS_epoll_ctl: ::c_long = 21; +pub const SYS_epoll_pwait: ::c_long = 22; +pub const SYS_dup: ::c_long = 23; +pub const SYS_dup3: ::c_long = 24; +pub const SYS_inotify_init1: ::c_long = 26; +pub const SYS_inotify_add_watch: ::c_long = 27; +pub const SYS_inotify_rm_watch: ::c_long = 28; +pub const SYS_ioctl: ::c_long = 29; +pub const SYS_ioprio_set: ::c_long = 30; +pub const SYS_ioprio_get: ::c_long = 31; +pub const SYS_flock: ::c_long = 32; +pub const SYS_mknodat: ::c_long = 33; +pub const SYS_mkdirat: ::c_long = 34; +pub const SYS_unlinkat: ::c_long = 35; +pub const SYS_symlinkat: ::c_long = 36; +pub const SYS_linkat: ::c_long = 37; +pub const SYS_renameat: ::c_long = 38; +pub const SYS_umount2: ::c_long = 39; +pub const SYS_mount: ::c_long = 40; +pub const SYS_pivot_root: ::c_long = 41; +pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_fallocate: ::c_long = 47; +pub const SYS_faccessat: ::c_long = 48; +pub const SYS_chdir: ::c_long = 49; +pub const SYS_fchdir: ::c_long = 50; +pub const SYS_chroot: ::c_long = 51; +pub const SYS_fchmod: ::c_long = 52; +pub const SYS_fchmodat: ::c_long = 53; +pub const SYS_fchownat: ::c_long = 54; +pub const SYS_fchown: ::c_long = 55; +pub const SYS_openat: ::c_long = 56; +pub const SYS_close: ::c_long = 57; +pub const SYS_vhangup: ::c_long = 58; +pub const SYS_pipe2: ::c_long = 59; +pub const SYS_quotactl: ::c_long = 60; +pub const SYS_getdents64: ::c_long = 61; +pub const SYS_read: ::c_long = 63; +pub const SYS_write: ::c_long = 64; +pub const SYS_readv: ::c_long = 65; +pub const SYS_writev: ::c_long = 66; +pub const SYS_pread64: ::c_long = 67; +pub const SYS_pwrite64: ::c_long = 68; +pub const SYS_preadv: ::c_long = 69; +pub const SYS_pwritev: ::c_long = 70; +pub const SYS_pselect6: ::c_long = 72; +pub const SYS_ppoll: ::c_long = 73; +pub const SYS_signalfd4: ::c_long = 74; +pub const SYS_vmsplice: ::c_long = 75; +pub const SYS_splice: ::c_long = 76; +pub const SYS_tee: ::c_long = 77; +pub const SYS_readlinkat: ::c_long = 78; +pub const SYS_sync: ::c_long = 81; +pub const SYS_fsync: ::c_long = 82; +pub const SYS_fdatasync: ::c_long = 83; +pub const SYS_sync_file_range: ::c_long = 84; +pub const SYS_timerfd_create: ::c_long = 85; +pub const SYS_timerfd_settime: ::c_long = 86; +pub const SYS_timerfd_gettime: ::c_long = 87; +pub const SYS_utimensat: ::c_long = 88; +pub const SYS_acct: ::c_long = 89; +pub const SYS_capget: ::c_long = 90; +pub const SYS_capset: ::c_long = 91; +pub const SYS_personality: ::c_long = 92; +pub const SYS_exit: ::c_long = 93; +pub const SYS_exit_group: ::c_long = 94; +pub const SYS_waitid: ::c_long = 95; +pub const SYS_set_tid_address: ::c_long = 96; +pub const SYS_unshare: ::c_long = 97; +pub const SYS_futex: ::c_long = 98; +pub const SYS_set_robust_list: ::c_long = 99; +pub const SYS_get_robust_list: ::c_long = 100; +pub const SYS_nanosleep: ::c_long = 101; +pub const SYS_getitimer: ::c_long = 102; +pub const SYS_setitimer: ::c_long = 103; +pub const SYS_kexec_load: ::c_long = 104; +pub const SYS_init_module: ::c_long = 105; +pub const SYS_delete_module: ::c_long = 106; +pub const SYS_timer_create: ::c_long = 107; +pub const SYS_timer_gettime: ::c_long = 108; +pub const SYS_timer_getoverrun: ::c_long = 109; +pub const SYS_timer_settime: ::c_long = 110; +pub const SYS_timer_delete: ::c_long = 111; +pub const SYS_clock_settime: ::c_long = 112; +pub const SYS_clock_gettime: ::c_long = 113; +pub const SYS_clock_getres: ::c_long = 114; +pub const SYS_clock_nanosleep: ::c_long = 115; +pub const SYS_syslog: ::c_long = 116; +pub const SYS_ptrace: ::c_long = 117; +pub const SYS_sched_setparam: ::c_long = 118; +pub const SYS_sched_setscheduler: ::c_long = 119; +pub const SYS_sched_getscheduler: ::c_long = 120; +pub const SYS_sched_getparam: ::c_long = 121; +pub const SYS_sched_setaffinity: ::c_long = 122; +pub const SYS_sched_getaffinity: ::c_long = 123; +pub const SYS_sched_yield: ::c_long = 124; +pub const SYS_sched_get_priority_max: ::c_long = 125; +pub const SYS_sched_get_priority_min: ::c_long = 126; +pub const SYS_sched_rr_get_interval: ::c_long = 127; +pub const SYS_restart_syscall: ::c_long = 128; +pub const SYS_kill: ::c_long = 129; +pub const SYS_tkill: ::c_long = 130; +pub const SYS_tgkill: ::c_long = 131; +pub const SYS_sigaltstack: ::c_long = 132; +pub const SYS_rt_sigsuspend: ::c_long = 133; +pub const SYS_rt_sigaction: ::c_long = 134; +pub const SYS_rt_sigprocmask: ::c_long = 135; +pub const SYS_rt_sigpending: ::c_long = 136; +pub const SYS_rt_sigtimedwait: ::c_long = 137; +pub const SYS_rt_sigqueueinfo: ::c_long = 138; +pub const SYS_rt_sigreturn: ::c_long = 139; +pub const SYS_setpriority: ::c_long = 140; +pub const SYS_getpriority: ::c_long = 141; +pub const SYS_reboot: ::c_long = 142; +pub const SYS_setregid: ::c_long = 143; +pub const SYS_setgid: ::c_long = 144; +pub const SYS_setreuid: ::c_long = 145; +pub const SYS_setuid: ::c_long = 146; +pub const SYS_setresuid: ::c_long = 147; +pub const SYS_getresuid: ::c_long = 148; +pub const SYS_setresgid: ::c_long = 149; +pub const SYS_getresgid: ::c_long = 150; +pub const SYS_setfsuid: ::c_long = 151; +pub const SYS_setfsgid: ::c_long = 152; +pub const SYS_times: ::c_long = 153; +pub const SYS_setpgid: ::c_long = 154; +pub const SYS_getpgid: ::c_long = 155; +pub const SYS_getsid: ::c_long = 156; +pub const SYS_setsid: ::c_long = 157; +pub const SYS_getgroups: ::c_long = 158; +pub const SYS_setgroups: ::c_long = 159; +pub const SYS_uname: ::c_long = 160; +pub const SYS_sethostname: ::c_long = 161; +pub const SYS_setdomainname: ::c_long = 162; +pub const SYS_getrlimit: ::c_long = 163; +pub const SYS_setrlimit: ::c_long = 164; +pub const SYS_getrusage: ::c_long = 165; +pub const SYS_umask: ::c_long = 166; +pub const SYS_prctl: ::c_long = 167; +pub const SYS_getcpu: ::c_long = 168; +pub const SYS_gettimeofday: ::c_long = 169; +pub const SYS_settimeofday: ::c_long = 170; +pub const SYS_adjtimex: ::c_long = 171; +pub const SYS_getpid: ::c_long = 172; +pub const SYS_getppid: ::c_long = 173; +pub const SYS_getuid: ::c_long = 174; +pub const SYS_geteuid: ::c_long = 175; +pub const SYS_getgid: ::c_long = 176; +pub const SYS_getegid: ::c_long = 177; +pub const SYS_gettid: ::c_long = 178; +pub const SYS_sysinfo: ::c_long = 179; +pub const SYS_mq_open: ::c_long = 180; +pub const SYS_mq_unlink: ::c_long = 181; +pub const SYS_mq_timedsend: ::c_long = 182; +pub const SYS_mq_timedreceive: ::c_long = 183; +pub const SYS_mq_notify: ::c_long = 184; +pub const SYS_mq_getsetattr: ::c_long = 185; +pub const SYS_msgget: ::c_long = 186; +pub const SYS_msgctl: ::c_long = 187; +pub const SYS_msgrcv: ::c_long = 188; +pub const SYS_msgsnd: ::c_long = 189; +pub const SYS_semget: ::c_long = 190; +pub const SYS_semctl: ::c_long = 191; +pub const SYS_semtimedop: ::c_long = 192; +pub const SYS_semop: ::c_long = 193; +pub const SYS_shmget: ::c_long = 194; +pub const SYS_shmctl: ::c_long = 195; +pub const SYS_shmat: ::c_long = 196; +pub const SYS_shmdt: ::c_long = 197; +pub const SYS_socket: ::c_long = 198; +pub const SYS_socketpair: ::c_long = 199; +pub const SYS_bind: ::c_long = 200; +pub const SYS_listen: ::c_long = 201; +pub const SYS_accept: ::c_long = 202; +pub const SYS_connect: ::c_long = 203; +pub const SYS_getsockname: ::c_long = 204; +pub const SYS_getpeername: ::c_long = 205; +pub const SYS_sendto: ::c_long = 206; +pub const SYS_recvfrom: ::c_long = 207; +pub const SYS_setsockopt: ::c_long = 208; +pub const SYS_getsockopt: ::c_long = 209; +pub const SYS_shutdown: ::c_long = 210; +pub const SYS_sendmsg: ::c_long = 211; +pub const SYS_recvmsg: ::c_long = 212; +pub const SYS_readahead: ::c_long = 213; +pub const SYS_brk: ::c_long = 214; +pub const SYS_munmap: ::c_long = 215; +pub const SYS_mremap: ::c_long = 216; +pub const SYS_add_key: ::c_long = 217; +pub const SYS_request_key: ::c_long = 218; +pub const SYS_keyctl: ::c_long = 219; +pub const SYS_clone: ::c_long = 220; +pub const SYS_execve: ::c_long = 221; +pub const SYS_swapon: ::c_long = 224; +pub const SYS_swapoff: ::c_long = 225; +pub const SYS_mprotect: ::c_long = 226; +pub const SYS_msync: ::c_long = 227; +pub const SYS_mlock: ::c_long = 228; +pub const SYS_munlock: ::c_long = 229; +pub const SYS_mlockall: ::c_long = 230; +pub const SYS_munlockall: ::c_long = 231; +pub const SYS_mincore: ::c_long = 232; +pub const SYS_madvise: ::c_long = 233; +pub const SYS_remap_file_pages: ::c_long = 234; +pub const SYS_mbind: ::c_long = 235; +pub const SYS_get_mempolicy: ::c_long = 236; +pub const SYS_set_mempolicy: ::c_long = 237; +pub const SYS_migrate_pages: ::c_long = 238; +pub const SYS_move_pages: ::c_long = 239; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 240; +pub const SYS_perf_event_open: ::c_long = 241; +pub const SYS_accept4: ::c_long = 242; +pub const SYS_recvmmsg: ::c_long = 243; +pub const SYS_wait4: ::c_long = 260; +pub const SYS_prlimit64: ::c_long = 261; +pub const SYS_fanotify_init: ::c_long = 262; +pub const SYS_fanotify_mark: ::c_long = 263; +pub const SYS_name_to_handle_at: ::c_long = 264; +pub const SYS_open_by_handle_at: ::c_long = 265; +pub const SYS_clock_adjtime: ::c_long = 266; +pub const SYS_syncfs: ::c_long = 267; +pub const SYS_setns: ::c_long = 268; +pub const SYS_sendmmsg: ::c_long = 269; +pub const SYS_process_vm_readv: ::c_long = 270; +pub const SYS_process_vm_writev: ::c_long = 271; +pub const SYS_kcmp: ::c_long = 272; +pub const SYS_finit_module: ::c_long = 273; +pub const SYS_sched_setattr: ::c_long = 274; +pub const SYS_sched_getattr: ::c_long = 275; +pub const SYS_renameat2: ::c_long = 276; +pub const SYS_seccomp: ::c_long = 277; +pub const SYS_getrandom: ::c_long = 278; +pub const SYS_memfd_create: ::c_long = 279; +pub const SYS_bpf: ::c_long = 280; +pub const SYS_execveat: ::c_long = 281; +pub const SYS_userfaultfd: ::c_long = 282; +pub const SYS_membarrier: ::c_long = 283; +pub const SYS_mlock2: ::c_long = 284; +pub const SYS_copy_file_range: ::c_long = 285; +pub const SYS_preadv2: ::c_long = 286; +pub const SYS_pwritev2: ::c_long = 287; +pub const SYS_pkey_mprotect: ::c_long = 288; +pub const SYS_pkey_alloc: ::c_long = 289; +pub const SYS_pkey_free: ::c_long = 290; diff --git a/libc/src/fuchsia/align.rs b/libc/src/fuchsia/align.rs new file mode 100644 index 000000000..bc9727519 --- /dev/null +++ b/libc/src/fuchsia/align.rs @@ -0,0 +1,142 @@ +macro_rules! expand_align { + () => { + s! { + #[cfg_attr( + any( + target_pointer_width = "32", + target_arch = "x86_64" + ), + repr(align(4)))] + #[cfg_attr( + not(any( + target_pointer_width = "32", + target_arch = "x86_64" + )), + repr(align(8)))] + pub struct pthread_mutexattr_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct pthread_rwlockattr_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "arm", + target_arch = "x86_64")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "arm", + target_arch = "x86_64"))), + repr(align(8)))] + pub struct pthread_mutex_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "arm", + target_arch = "x86_64")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "arm", + target_arch = "x86_64"))), + repr(align(8)))] + pub struct pthread_rwlock_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + #[cfg_attr(target_arch = "x86", + repr(align(4)))] + #[cfg_attr(not(target_arch = "x86"), + repr(align(8)))] + pub struct pthread_cond_t { + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_cond_t {} + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + + impl PartialEq for pthread_mutex_t { + fn eq(&self, other: &pthread_mutex_t) -> bool { + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_mutex_t {} + impl ::fmt::Debug for pthread_mutex_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_mutex_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_mutex_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + + impl PartialEq for pthread_rwlock_t { + fn eq(&self, other: &pthread_rwlock_t) -> bool { + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_rwlock_t {} + impl ::fmt::Debug for pthread_rwlock_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_rwlock_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_rwlock_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + } + } + } +} diff --git a/libc/src/fuchsia/mod.rs b/libc/src/fuchsia/mod.rs new file mode 100644 index 000000000..cef48e522 --- /dev/null +++ b/libc/src/fuchsia/mod.rs @@ -0,0 +1,4275 @@ +//! Definitions found commonly among almost all Unix derivatives +//! +//! More functions and definitions can be found in the more specific modules +//! according to the platform in question. + +// PUB_TYPE + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type pid_t = i32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type sighandler_t = ::size_t; +pub type cc_t = ::c_uchar; +pub type sa_family_t = u16; +pub type pthread_key_t = ::c_uint; +pub type speed_t = ::c_uint; +pub type tcflag_t = ::c_uint; +pub type clockid_t = ::c_int; +pub type key_t = ::c_int; +pub type id_t = ::c_uint; +pub type useconds_t = u32; +pub type dev_t = u64; +pub type socklen_t = u32; +pub type pthread_t = c_ulong; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type mqd_t = ::c_int; +pub type nfds_t = ::c_ulong; +pub type nl_item = ::c_int; +pub type idtype_t = ::c_uint; +pub type loff_t = ::c_longlong; + +pub type __u8 = ::c_uchar; +pub type __u16 = ::c_ushort; +pub type __s16 = ::c_short; +pub type __u32 = ::c_uint; +pub type __s32 = ::c_int; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; + +pub type clock_t = c_long; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; + +pub type shmatt_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type fsblkcnt_t = ::c_ulonglong; +pub type fsfilcnt_t = ::c_ulonglong; +pub type rlim_t = ::c_ulonglong; + +pub type c_long = i64; +pub type c_ulong = u64; + +// FIXME: why are these uninhabited types? that seems... wrong? +// Presumably these should be `()` or an `extern type` (when that stabilizes). +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum DIR {} +impl ::Copy for DIR {} +impl ::Clone for DIR { + fn clone(&self) -> DIR { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum locale_t {} +impl ::Copy for locale_t {} +impl ::Clone for locale_t { + fn clone(&self) -> locale_t { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos64_t {} // TODO: fill this out with a struct +impl ::Copy for fpos64_t {} +impl ::Clone for fpos64_t { + fn clone(&self) -> fpos64_t { *self } +} + +// PUB_STRUCT + +s! { + pub struct group { + pub gr_name: *mut ::c_char, + pub gr_passwd: *mut ::c_char, + pub gr_gid: ::gid_t, + pub gr_mem: *mut *mut ::c_char, + } + + pub struct utimbuf { + pub actime: time_t, + pub modtime: time_t, + } + + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: ::c_long, + } + + // FIXME: the rlimit and rusage related functions and types don't exist + // within zircon. Are there reasons for keeping them around? + pub struct rlimit { + pub rlim_cur: rlim_t, + pub rlim_max: rlim_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad1: u32, + pub ru_ixrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad2: u32, + pub ru_idrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad3: u32, + pub ru_isrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad4: u32, + pub ru_minflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad5: u32, + pub ru_majflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad6: u32, + pub ru_nswap: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad7: u32, + pub ru_inblock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad8: u32, + pub ru_oublock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad9: u32, + pub ru_msgsnd: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad10: u32, + pub ru_msgrcv: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad11: u32, + pub ru_nsignals: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad12: u32, + pub ru_nvcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad13: u32, + pub ru_nivcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad14: u32, + } + + pub struct in_addr { + pub s_addr: in_addr_t, + } + + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: ::c_uint, + } + + pub struct hostent { + pub h_name: *mut ::c_char, + pub h_aliases: *mut *mut ::c_char, + pub h_addrtype: ::c_int, + pub h_length: ::c_int, + pub h_addr_list: *mut *mut ::c_char, + } + + pub struct iovec { + pub iov_base: *mut ::c_void, + pub iov_len: ::size_t, + } + + pub struct pollfd { + pub fd: ::c_int, + pub events: ::c_short, + pub revents: ::c_short, + } + + pub struct winsize { + pub ws_row: ::c_ushort, + pub ws_col: ::c_ushort, + pub ws_xpixel: ::c_ushort, + pub ws_ypixel: ::c_ushort, + } + + pub struct linger { + pub l_onoff: ::c_int, + pub l_linger: ::c_int, + } + + pub struct sigval { + // Actually a union of an int and a void* + pub sival_ptr: *mut ::c_void + } + + // + pub struct itimerval { + pub it_interval: ::timeval, + pub it_value: ::timeval, + } + + // + pub struct tms { + pub tms_utime: ::clock_t, + pub tms_stime: ::clock_t, + pub tms_cutime: ::clock_t, + pub tms_cstime: ::clock_t, + } + + pub struct servent { + pub s_name: *mut ::c_char, + pub s_aliases: *mut *mut ::c_char, + pub s_port: ::c_int, + pub s_proto: *mut ::c_char, + } + + pub struct protoent { + pub p_name: *mut ::c_char, + pub p_aliases: *mut *mut ::c_char, + pub p_proto: ::c_int, + } + + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __td: *mut ::c_void, + __lock: [::c_int; 2], + __err: ::c_int, + __ret: ::ssize_t, + pub aio_offset: off_t, + __next: *mut ::c_void, + __prev: *mut ::c_void, + #[cfg(target_pointer_width = "32")] + __dummy4: [::c_char; 24], + #[cfg(target_pointer_width = "64")] + __dummy4: [::c_char; 16], + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_int, + pub sa_restorer: ::Option, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub __c_ispeed: ::speed_t, + pub __c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct ucred { + pub pid: ::pid_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + + pub ai_addr: *mut ::sockaddr, + + pub ai_canonname: *mut c_char, + + pub ai_next: *mut addrinfo, + } + + pub struct sockaddr_nl { + pub nl_family: ::sa_family_t, + nl_pad: ::c_ushort, + pub nl_pid: u32, + pub nl_groups: u32 + } + + pub struct sockaddr_ll { + pub sll_family: ::c_ushort, + pub sll_protocol: ::c_ushort, + pub sll_ifindex: ::c_int, + pub sll_hatype: ::c_ushort, + pub sll_pkttype: ::c_uchar, + pub sll_halen: ::c_uchar, + pub sll_addr: [::c_uchar; 8] + } + + pub struct fd_set { + fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *const ::c_char, + } + + pub struct sched_param { + pub sched_priority: ::c_int, + pub sched_ss_low_priority: ::c_int, + pub sched_ss_repl_period: ::timespec, + pub sched_ss_init_budget: ::timespec, + pub sched_ss_max_repl: ::c_int, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct epoll_event { + pub events: ::uint32_t, + pub u64: ::uint64_t, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct sigevent { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + pub sigev_notify_function: fn(::sigval), + pub sigev_notify_attributes: *mut pthread_attr_t, + pub __pad: [::c_char; 56 - 3 * 8 /* 8 == sizeof(long) */], + } + + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: ::c_uint, + pub ifa_addr: *mut ::sockaddr, + pub ifa_netmask: *mut ::sockaddr, + pub ifa_ifu: *mut ::sockaddr, // FIXME This should be a union + pub ifa_data: *mut ::c_void + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct spwd { + pub sp_namp: *mut ::c_char, + pub sp_pwdp: *mut ::c_char, + pub sp_lstchg: ::c_long, + pub sp_min: ::c_long, + pub sp_max: ::c_long, + pub sp_warn: ::c_long, + pub sp_inact: ::c_long, + pub sp_expire: ::c_long, + pub sp_flag: ::c_ulong, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: ::c_ulong, + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86_64")))] + __f_unused: ::c_int, + #[cfg(target_endian = "big")] + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint64_t, + pub dqb_bsoftlimit: ::uint64_t, + pub dqb_curspace: ::uint64_t, + pub dqb_ihardlimit: ::uint64_t, + pub dqb_isoftlimit: ::uint64_t, + pub dqb_curinodes: ::uint64_t, + pub dqb_btime: ::uint64_t, + pub dqb_itime: ::uint64_t, + pub dqb_valid: ::uint32_t, + } + + pub struct signalfd_siginfo { + pub ssi_signo: ::uint32_t, + pub ssi_errno: ::int32_t, + pub ssi_code: ::int32_t, + pub ssi_pid: ::uint32_t, + pub ssi_uid: ::uint32_t, + pub ssi_fd: ::int32_t, + pub ssi_tid: ::uint32_t, + pub ssi_band: ::uint32_t, + pub ssi_overrun: ::uint32_t, + pub ssi_trapno: ::uint32_t, + pub ssi_status: ::int32_t, + pub ssi_int: ::int32_t, + pub ssi_ptr: ::uint64_t, + pub ssi_utime: ::uint64_t, + pub ssi_stime: ::uint64_t, + pub ssi_addr: ::uint64_t, + pub ssi_addr_lsb: ::uint16_t, + _pad2: ::uint16_t, + pub ssi_syscall: ::int32_t, + pub ssi_call_addr: ::uint64_t, + pub ssi_arch: ::uint32_t, + _pad: [::uint8_t; 28], + } + + pub struct itimerspec { + pub it_interval: ::timespec, + pub it_value: ::timespec, + } + + pub struct fsid_t { + __val: [::c_int; 2], + } + + // x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 + pub struct mq_attr { + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_flags: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_maxmsg: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_msgsize: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_curmsgs: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pad: [i64; 4], + + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_flags: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_maxmsg: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_msgsize: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_curmsgs: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pad: [::c_long; 4], + } + + pub struct cpu_set_t { + #[cfg(all(target_pointer_width = "32", + not(target_arch = "x86_64")))] + bits: [u32; 32], + #[cfg(not(all(target_pointer_width = "32", + not(target_arch = "x86_64"))))] + bits: [u64; 16], + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: ::c_int, + pub msgmap: ::c_int, + pub msgmax: ::c_int, + pub msgmnb: ::c_int, + pub msgmni: ::c_int, + pub msgssz: ::c_int, + pub msgtql: ::c_int, + pub msgseg: ::c_ushort, + } + + pub struct mmsghdr { + pub msg_hdr: ::msghdr, + pub msg_len: ::c_uint, + } + + pub struct sembuf { + pub sem_num: ::c_ushort, + pub sem_op: ::c_short, + pub sem_flg: ::c_short, + } + + pub struct input_event { + pub time: ::timeval, + pub type_: ::__u16, + pub code: ::__u16, + pub value: ::__s32, + } + + pub struct input_id { + pub bustype: ::__u16, + pub vendor: ::__u16, + pub product: ::__u16, + pub version: ::__u16, + } + + pub struct input_absinfo { + pub value: ::__s32, + pub minimum: ::__s32, + pub maximum: ::__s32, + pub fuzz: ::__s32, + pub flat: ::__s32, + pub resolution: ::__s32, + } + + pub struct input_keymap_entry { + pub flags: ::__u8, + pub len: ::__u8, + pub index: ::__u16, + pub keycode: ::__u32, + pub scancode: [::__u8; 32], + } + + pub struct input_mask { + pub type_: ::__u32, + pub codes_size: ::__u32, + pub codes_ptr: ::__u64, + } + + pub struct ff_replay { + pub length: ::__u16, + pub delay: ::__u16, + } + + pub struct ff_trigger { + pub button: ::__u16, + pub interval: ::__u16, + } + + pub struct ff_envelope { + pub attack_length: ::__u16, + pub attack_level: ::__u16, + pub fade_length: ::__u16, + pub fade_level: ::__u16, + } + + pub struct ff_constant_effect { + pub level: ::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_ramp_effect { + pub start_level: ::__s16, + pub end_level: ::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_condition_effect { + pub right_saturation: ::__u16, + pub left_saturation: ::__u16, + + pub right_coeff: ::__s16, + pub left_coeff: ::__s16, + + pub deadband: ::__u16, + pub center: ::__s16, + } + + pub struct ff_periodic_effect { + pub waveform: ::__u16, + pub period: ::__u16, + pub magnitude: ::__s16, + pub offset: ::__s16, + pub phase: ::__u16, + + pub envelope: ff_envelope, + + pub custom_len: ::__u32, + pub custom_data: *mut ::__s16, + } + + pub struct ff_rumble_effect { + pub strong_magnitude: ::__u16, + pub weak_magnitude: ::__u16, + } + + pub struct ff_effect { + pub type_: ::__u16, + pub id: ::__s16, + pub direction: ::__u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + // FIXME this is actually a union + #[cfg(target_pointer_width = "64")] + pub u: [u64; 4], + #[cfg(target_pointer_width = "32")] + pub u: [u32; 7], + } + + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const ::c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + pub dlpi_adds: ::c_ulonglong, + pub dlpi_subs: ::c_ulonglong, + pub dlpi_tls_modid: ::size_t, + pub dlpi_tls_data: *mut ::c_void, + } + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct pthread_attr_t { + __size: [u64; 7] + } + + pub struct sigset_t { + __val: [::c_ulong; 16], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + __pad1: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + __pad2: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::socklen_t, + pub __pad1: ::c_int, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct sem_t { + __val: [::c_int; 8], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +s_no_extra_traits! { + pub struct sysinfo { + pub uptime: ::c_ulong, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub __reserved: [::c_char; 256], + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [::c_char; 108] + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_align: ::size_t, + __ss_pad2: [u8; 128 - 2 * 8], + } + + pub struct utsname { + pub sysname: [::c_char; 65], + pub nodename: [::c_char; 65], + pub release: [::c_char; 65], + pub version: [::c_char; 65], + pub machine: [::c_char; 65], + pub domainname: [::c_char; 65] + } + + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct dirent64 { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sysinfo { + fn eq(&self, other: &sysinfo) -> bool { + self.uptime == other.uptime + && self.loads == other.loads + && self.totalram == other.totalram + && self.freeram == other.freeram + && self.sharedram == other.sharedram + && self.bufferram == other.bufferram + && self.totalswap == other.totalswap + && self.freeswap == other.freeswap + && self.procs == other.procs + && self.pad == other.pad + && self.totalhigh == other.totalhigh + && self.freehigh == other.freehigh + && self.mem_unit == other.mem_unit + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sysinfo {} + impl ::fmt::Debug for sysinfo { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sysinfo") + .field("uptime", &self.uptime) + .field("loads", &self.loads) + .field("totalram", &self.totalram) + .field("freeram", &self.freeram) + .field("sharedram", &self.sharedram) + .field("bufferram", &self.bufferram) + .field("totalswap", &self.totalswap) + .field("freeswap", &self.freeswap) + .field("procs", &self.procs) + .field("pad", &self.pad) + .field("totalhigh", &self.totalhigh) + .field("freehigh", &self.freehigh) + .field("mem_unit", &self.mem_unit) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + impl ::hash::Hash for sysinfo { + fn hash(&self, state: &mut H) { + self.uptime.hash(state); + self.loads.hash(state); + self.totalram.hash(state); + self.freeram.hash(state); + self.sharedram.hash(state); + self.bufferram.hash(state); + self.totalswap.hash(state); + self.freeswap.hash(state); + self.procs.hash(state); + self.pad.hash(state); + self.totalhigh.hash(state); + self.freehigh.hash(state); + self.mem_unit.hash(state); + self.__reserved.hash(state); + } + } + + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_un {} + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_family == other.ss_family + && self.__ss_align == other.__ss_align + && self + .__ss_pad2 + .iter() + .zip(other.__ss_pad2.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_family", &self.ss_family) + .field("__ss_align", &self.__ss_align) + // FIXME: .field("__ss_pad2", &self.__ss_pad2) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_family.hash(state); + self.__ss_align.hash(state); + self.__ss_pad2.hash(state); + } + } + + impl PartialEq for utsname { + fn eq(&self, other: &utsname) -> bool { + self.sysname + .iter() + .zip(other.sysname.iter()) + .all(|(a,b)| a == b) + && self + .nodename + .iter() + .zip(other.nodename.iter()) + .all(|(a,b)| a == b) + && self + .release + .iter() + .zip(other.release.iter()) + .all(|(a,b)| a == b) + && self + .version + .iter() + .zip(other.version.iter()) + .all(|(a,b)| a == b) + && self + .machine + .iter() + .zip(other.machine.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for utsname {} + impl ::fmt::Debug for utsname { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utsname") + // FIXME: .field("sysname", &self.sysname) + // FIXME: .field("nodename", &self.nodename) + // FIXME: .field("release", &self.release) + // FIXME: .field("version", &self.version) + // FIXME: .field("machine", &self.machine) + .finish() + } + } + impl ::hash::Hash for utsname { + fn hash(&self, state: &mut H) { + self.sysname.hash(state); + self.nodename.hash(state); + self.release.hash(state); + self.version.hash(state); + self.machine.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for dirent64 { + fn eq(&self, other: &dirent64) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent64 {} + impl ::fmt::Debug for dirent64 { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent64") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent64 { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + } +} + +// PUB_CONST + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = !0 as sighandler_t; + +pub const DT_FIFO: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_REG: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; + +pub const FD_CLOEXEC: ::c_int = 0x1; + +pub const USRQUOTA: ::c_int = 0; +pub const GRPQUOTA: ::c_int = 1; + +pub const SIGIOT: ::c_int = 6; + +pub const S_ISUID: ::c_int = 0x800; +pub const S_ISGID: ::c_int = 0x400; +pub const S_ISVTX: ::c_int = 0x200; + +pub const IF_NAMESIZE: ::size_t = 16; + +pub const LOG_EMERG: ::c_int = 0; +pub const LOG_ALERT: ::c_int = 1; +pub const LOG_CRIT: ::c_int = 2; +pub const LOG_ERR: ::c_int = 3; +pub const LOG_WARNING: ::c_int = 4; +pub const LOG_NOTICE: ::c_int = 5; +pub const LOG_INFO: ::c_int = 6; +pub const LOG_DEBUG: ::c_int = 7; + +pub const LOG_KERN: ::c_int = 0; +pub const LOG_USER: ::c_int = 1 << 3; +pub const LOG_MAIL: ::c_int = 2 << 3; +pub const LOG_DAEMON: ::c_int = 3 << 3; +pub const LOG_AUTH: ::c_int = 4 << 3; +pub const LOG_SYSLOG: ::c_int = 5 << 3; +pub const LOG_LPR: ::c_int = 6 << 3; +pub const LOG_NEWS: ::c_int = 7 << 3; +pub const LOG_UUCP: ::c_int = 8 << 3; +pub const LOG_LOCAL0: ::c_int = 16 << 3; +pub const LOG_LOCAL1: ::c_int = 17 << 3; +pub const LOG_LOCAL2: ::c_int = 18 << 3; +pub const LOG_LOCAL3: ::c_int = 19 << 3; +pub const LOG_LOCAL4: ::c_int = 20 << 3; +pub const LOG_LOCAL5: ::c_int = 21 << 3; +pub const LOG_LOCAL6: ::c_int = 22 << 3; +pub const LOG_LOCAL7: ::c_int = 23 << 3; + +pub const LOG_PID: ::c_int = 0x01; +pub const LOG_CONS: ::c_int = 0x02; +pub const LOG_ODELAY: ::c_int = 0x04; +pub const LOG_NDELAY: ::c_int = 0x08; +pub const LOG_NOWAIT: ::c_int = 0x10; + +pub const LOG_PRIMASK: ::c_int = 7; +pub const LOG_FACMASK: ::c_int = 0x3f8; + +pub const PRIO_PROCESS: ::c_int = 0; +pub const PRIO_PGRP: ::c_int = 1; +pub const PRIO_USER: ::c_int = 2; + +pub const PRIO_MIN: ::c_int = -20; +pub const PRIO_MAX: ::c_int = 20; + +pub const IPPROTO_ICMP: ::c_int = 1; +pub const IPPROTO_ICMPV6: ::c_int = 58; +pub const IPPROTO_TCP: ::c_int = 6; +pub const IPPROTO_UDP: ::c_int = 17; +pub const IPPROTO_IP: ::c_int = 0; +pub const IPPROTO_IPV6: ::c_int = 41; + +pub const INADDR_LOOPBACK: in_addr_t = 2130706433; +pub const INADDR_ANY: in_addr_t = 0; +pub const INADDR_BROADCAST: in_addr_t = 4294967295; +pub const INADDR_NONE: in_addr_t = 4294967295; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 2147483647; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; + +// Linux-specific fcntls +pub const F_SETLEASE: ::c_int = 1024; +pub const F_GETLEASE: ::c_int = 1025; +pub const F_NOTIFY: ::c_int = 1026; +pub const F_CANCELLK: ::c_int = 1029; +pub const F_DUPFD_CLOEXEC: ::c_int = 1030; +pub const F_SETPIPE_SZ: ::c_int = 1031; +pub const F_GETPIPE_SZ: ::c_int = 1032; +pub const F_ADD_SEALS: ::c_int = 1033; +pub const F_GET_SEALS: ::c_int = 1034; + +pub const F_SEAL_SEAL: ::c_int = 0x0001; +pub const F_SEAL_SHRINK: ::c_int = 0x0002; +pub const F_SEAL_GROW: ::c_int = 0x0004; +pub const F_SEAL_WRITE: ::c_int = 0x0008; + +// TODO(#235): Include file sealing fcntls once we have a way to verify them. + +pub const SIGTRAP: ::c_int = 5; + +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 1; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_MONOTONIC: ::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 3; +pub const CLOCK_MONOTONIC_RAW: ::clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: ::clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: ::clockid_t = 6; +pub const CLOCK_BOOTTIME: ::clockid_t = 7; +pub const CLOCK_REALTIME_ALARM: ::clockid_t = 8; +pub const CLOCK_BOOTTIME_ALARM: ::clockid_t = 9; +// TODO(#247) Someday our Travis shall have glibc 2.21 (released in Sep +// 2014.) See also musl/mod.rs +// pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +// pub const CLOCK_TAI: ::clockid_t = 11; +pub const TIMER_ABSTIME: ::c_int = 1; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_LOCKS: ::c_int = 10; +pub const RLIMIT_SIGPENDING: ::c_int = 11; +pub const RLIMIT_MSGQUEUE: ::c_int = 12; +pub const RLIMIT_NICE: ::c_int = 13; +pub const RLIMIT_RTPRIO: ::c_int = 14; + +pub const RUSAGE_SELF: ::c_int = 0; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; + +pub const SOCK_CLOEXEC: ::c_int = O_CLOEXEC; + +pub const S_IFIFO: ::mode_t = 4096; +pub const S_IFCHR: ::mode_t = 8192; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IRWXU: ::mode_t = 448; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IRWXG: ::mode_t = 56; +pub const S_IXGRP: ::mode_t = 8; +pub const S_IWGRP: ::mode_t = 16; +pub const S_IRGRP: ::mode_t = 32; +pub const S_IRWXO: ::mode_t = 7; +pub const S_IXOTH: ::mode_t = 1; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IROTH: ::mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const LC_CTYPE: ::c_int = 0; +pub const LC_NUMERIC: ::c_int = 1; +pub const LC_TIME: ::c_int = 2; +pub const LC_COLLATE: ::c_int = 3; +pub const LC_MONETARY: ::c_int = 4; +pub const LC_MESSAGES: ::c_int = 5; +pub const LC_ALL: ::c_int = 6; +pub const LC_CTYPE_MASK: ::c_int = (1 << LC_CTYPE); +pub const LC_NUMERIC_MASK: ::c_int = (1 << LC_NUMERIC); +pub const LC_TIME_MASK: ::c_int = (1 << LC_TIME); +pub const LC_COLLATE_MASK: ::c_int = (1 << LC_COLLATE); +pub const LC_MONETARY_MASK: ::c_int = (1 << LC_MONETARY); +pub const LC_MESSAGES_MASK: ::c_int = (1 << LC_MESSAGES); +// LC_ALL_MASK defined per platform + +pub const MAP_FILE: ::c_int = 0x0000; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +// MS_ flags for msync(2) +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; +pub const MS_SYNC: ::c_int = 0x0004; + +// MS_ flags for mount(2) +pub const MS_RDONLY: ::c_ulong = 0x01; +pub const MS_NOSUID: ::c_ulong = 0x02; +pub const MS_NODEV: ::c_ulong = 0x04; +pub const MS_NOEXEC: ::c_ulong = 0x08; +pub const MS_SYNCHRONOUS: ::c_ulong = 0x10; +pub const MS_REMOUNT: ::c_ulong = 0x20; +pub const MS_MANDLOCK: ::c_ulong = 0x40; +pub const MS_DIRSYNC: ::c_ulong = 0x80; +pub const MS_NOATIME: ::c_ulong = 0x0400; +pub const MS_NODIRATIME: ::c_ulong = 0x0800; +pub const MS_BIND: ::c_ulong = 0x1000; +pub const MS_MOVE: ::c_ulong = 0x2000; +pub const MS_REC: ::c_ulong = 0x4000; +pub const MS_SILENT: ::c_ulong = 0x8000; +pub const MS_POSIXACL: ::c_ulong = 0x010000; +pub const MS_UNBINDABLE: ::c_ulong = 0x020000; +pub const MS_PRIVATE: ::c_ulong = 0x040000; +pub const MS_SLAVE: ::c_ulong = 0x080000; +pub const MS_SHARED: ::c_ulong = 0x100000; +pub const MS_RELATIME: ::c_ulong = 0x200000; +pub const MS_KERNMOUNT: ::c_ulong = 0x400000; +pub const MS_I_VERSION: ::c_ulong = 0x800000; +pub const MS_STRICTATIME: ::c_ulong = 0x1000000; +pub const MS_ACTIVE: ::c_ulong = 0x40000000; +pub const MS_NOUSER: ::c_ulong = 0x80000000; +pub const MS_MGC_VAL: ::c_ulong = 0xc0ed0000; +pub const MS_MGC_MSK: ::c_ulong = 0xffff0000; +pub const MS_RMT_MASK: ::c_ulong = 0x800051; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EWOULDBLOCK: ::c_int = EAGAIN; + +pub const SCM_RIGHTS: ::c_int = 0x01; +pub const SCM_CREDENTIALS: ::c_int = 0x02; + +pub const PROT_GROWSDOWN: ::c_int = 0x1000000; +pub const PROT_GROWSUP: ::c_int = 0x2000000; + +pub const MAP_TYPE: ::c_int = 0x000f; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_FREE: ::c_int = 8; +pub const MADV_REMOVE: ::c_int = 9; +pub const MADV_DONTFORK: ::c_int = 10; +pub const MADV_DOFORK: ::c_int = 11; +pub const MADV_MERGEABLE: ::c_int = 12; +pub const MADV_UNMERGEABLE: ::c_int = 13; +pub const MADV_HUGEPAGE: ::c_int = 14; +pub const MADV_NOHUGEPAGE: ::c_int = 15; +pub const MADV_DONTDUMP: ::c_int = 16; +pub const MADV_DODUMP: ::c_int = 17; +pub const MADV_HWPOISON: ::c_int = 100; +pub const MADV_SOFT_OFFLINE: ::c_int = 101; + +pub const IFF_UP: ::c_int = 0x1; +pub const IFF_BROADCAST: ::c_int = 0x2; +pub const IFF_DEBUG: ::c_int = 0x4; +pub const IFF_LOOPBACK: ::c_int = 0x8; +pub const IFF_POINTOPOINT: ::c_int = 0x10; +pub const IFF_NOTRAILERS: ::c_int = 0x20; +pub const IFF_RUNNING: ::c_int = 0x40; +pub const IFF_NOARP: ::c_int = 0x80; +pub const IFF_PROMISC: ::c_int = 0x100; +pub const IFF_ALLMULTI: ::c_int = 0x200; +pub const IFF_MASTER: ::c_int = 0x400; +pub const IFF_SLAVE: ::c_int = 0x800; +pub const IFF_MULTICAST: ::c_int = 0x1000; +pub const IFF_PORTSEL: ::c_int = 0x2000; +pub const IFF_AUTOMEDIA: ::c_int = 0x4000; +pub const IFF_DYNAMIC: ::c_int = 0x8000; +pub const IFF_TUN: ::c_int = 0x0001; +pub const IFF_TAP: ::c_int = 0x0002; +pub const IFF_NO_PI: ::c_int = 0x1000; + +pub const SOL_IP: ::c_int = 0; +pub const SOL_TCP: ::c_int = 6; +pub const SOL_UDP: ::c_int = 17; +pub const SOL_IPV6: ::c_int = 41; +pub const SOL_ICMPV6: ::c_int = 58; +pub const SOL_RAW: ::c_int = 255; +pub const SOL_DECNET: ::c_int = 261; +pub const SOL_X25: ::c_int = 262; +pub const SOL_PACKET: ::c_int = 263; +pub const SOL_ATM: ::c_int = 264; +pub const SOL_AAL: ::c_int = 265; +pub const SOL_IRDA: ::c_int = 266; +pub const SOL_NETBEUI: ::c_int = 267; +pub const SOL_LLC: ::c_int = 268; +pub const SOL_DCCP: ::c_int = 269; +pub const SOL_NETLINK: ::c_int = 270; +pub const SOL_TIPC: ::c_int = 271; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_UNIX: ::c_int = 1; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_INET: ::c_int = 2; +pub const AF_AX25: ::c_int = 3; +pub const AF_IPX: ::c_int = 4; +pub const AF_APPLETALK: ::c_int = 5; +pub const AF_NETROM: ::c_int = 6; +pub const AF_BRIDGE: ::c_int = 7; +pub const AF_ATMPVC: ::c_int = 8; +pub const AF_X25: ::c_int = 9; +pub const AF_INET6: ::c_int = 10; +pub const AF_ROSE: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_NETBEUI: ::c_int = 13; +pub const AF_SECURITY: ::c_int = 14; +pub const AF_KEY: ::c_int = 15; +pub const AF_NETLINK: ::c_int = 16; +pub const AF_ROUTE: ::c_int = AF_NETLINK; +pub const AF_PACKET: ::c_int = 17; +pub const AF_ASH: ::c_int = 18; +pub const AF_ECONET: ::c_int = 19; +pub const AF_ATMSVC: ::c_int = 20; +pub const AF_RDS: ::c_int = 21; +pub const AF_SNA: ::c_int = 22; +pub const AF_IRDA: ::c_int = 23; +pub const AF_PPPOX: ::c_int = 24; +pub const AF_WANPIPE: ::c_int = 25; +pub const AF_LLC: ::c_int = 26; +pub const AF_CAN: ::c_int = 29; +pub const AF_TIPC: ::c_int = 30; +pub const AF_BLUETOOTH: ::c_int = 31; +pub const AF_IUCV: ::c_int = 32; +pub const AF_RXRPC: ::c_int = 33; +pub const AF_ISDN: ::c_int = 34; +pub const AF_PHONET: ::c_int = 35; +pub const AF_IEEE802154: ::c_int = 36; +pub const AF_CAIF: ::c_int = 37; +pub const AF_ALG: ::c_int = 38; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_UNIX: ::c_int = AF_UNIX; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_AX25: ::c_int = AF_AX25; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_NETROM: ::c_int = AF_NETROM; +pub const PF_BRIDGE: ::c_int = AF_BRIDGE; +pub const PF_ATMPVC: ::c_int = AF_ATMPVC; +pub const PF_X25: ::c_int = AF_X25; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_ROSE: ::c_int = AF_ROSE; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_NETBEUI: ::c_int = AF_NETBEUI; +pub const PF_SECURITY: ::c_int = AF_SECURITY; +pub const PF_KEY: ::c_int = AF_KEY; +pub const PF_NETLINK: ::c_int = AF_NETLINK; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_PACKET: ::c_int = AF_PACKET; +pub const PF_ASH: ::c_int = AF_ASH; +pub const PF_ECONET: ::c_int = AF_ECONET; +pub const PF_ATMSVC: ::c_int = AF_ATMSVC; +pub const PF_RDS: ::c_int = AF_RDS; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_IRDA: ::c_int = AF_IRDA; +pub const PF_PPPOX: ::c_int = AF_PPPOX; +pub const PF_WANPIPE: ::c_int = AF_WANPIPE; +pub const PF_LLC: ::c_int = AF_LLC; +pub const PF_CAN: ::c_int = AF_CAN; +pub const PF_TIPC: ::c_int = AF_TIPC; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_IUCV: ::c_int = AF_IUCV; +pub const PF_RXRPC: ::c_int = AF_RXRPC; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_PHONET: ::c_int = AF_PHONET; +pub const PF_IEEE802154: ::c_int = AF_IEEE802154; +pub const PF_CAIF: ::c_int = AF_CAIF; +pub const PF_ALG: ::c_int = AF_ALG; + +pub const SOMAXCONN: ::c_int = 128; + +pub const MSG_OOB: ::c_int = 1; +pub const MSG_PEEK: ::c_int = 2; +pub const MSG_DONTROUTE: ::c_int = 4; +pub const MSG_CTRUNC: ::c_int = 8; +pub const MSG_TRUNC: ::c_int = 0x20; +pub const MSG_DONTWAIT: ::c_int = 0x40; +pub const MSG_EOR: ::c_int = 0x80; +pub const MSG_WAITALL: ::c_int = 0x100; +pub const MSG_FIN: ::c_int = 0x200; +pub const MSG_SYN: ::c_int = 0x400; +pub const MSG_CONFIRM: ::c_int = 0x800; +pub const MSG_RST: ::c_int = 0x1000; +pub const MSG_ERRQUEUE: ::c_int = 0x2000; +pub const MSG_NOSIGNAL: ::c_int = 0x4000; +pub const MSG_MORE: ::c_int = 0x8000; +pub const MSG_WAITFORONE: ::c_int = 0x10000; +pub const MSG_FASTOPEN: ::c_int = 0x20000000; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x40000000; + +pub const SCM_TIMESTAMP: ::c_int = SO_TIMESTAMP; + +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_RDM: ::c_int = 4; +pub const IP_MULTICAST_IF: ::c_int = 32; +pub const IP_MULTICAST_TTL: ::c_int = 33; +pub const IP_MULTICAST_LOOP: ::c_int = 34; +pub const IP_TTL: ::c_int = 2; +pub const IP_HDRINCL: ::c_int = 3; +pub const IP_ADD_MEMBERSHIP: ::c_int = 35; +pub const IP_DROP_MEMBERSHIP: ::c_int = 36; +pub const IP_TRANSPARENT: ::c_int = 19; +pub const IPV6_UNICAST_HOPS: ::c_int = 16; +pub const IPV6_MULTICAST_IF: ::c_int = 17; +pub const IPV6_MULTICAST_HOPS: ::c_int = 18; +pub const IPV6_MULTICAST_LOOP: ::c_int = 19; +pub const IPV6_ADD_MEMBERSHIP: ::c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: ::c_int = 21; +pub const IPV6_V6ONLY: ::c_int = 26; + +pub const TCP_NODELAY: ::c_int = 1; +pub const TCP_MAXSEG: ::c_int = 2; +pub const TCP_CORK: ::c_int = 3; +pub const TCP_KEEPIDLE: ::c_int = 4; +pub const TCP_KEEPINTVL: ::c_int = 5; +pub const TCP_KEEPCNT: ::c_int = 6; +pub const TCP_SYNCNT: ::c_int = 7; +pub const TCP_LINGER2: ::c_int = 8; +pub const TCP_DEFER_ACCEPT: ::c_int = 9; +pub const TCP_WINDOW_CLAMP: ::c_int = 10; +pub const TCP_INFO: ::c_int = 11; +pub const TCP_QUICKACK: ::c_int = 12; +pub const TCP_CONGESTION: ::c_int = 13; + +pub const SO_DEBUG: ::c_int = 1; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const SS_ONSTACK: ::c_int = 1; +pub const SS_DISABLE: ::c_int = 2; + +pub const PATH_MAX: ::c_int = 4096; + +pub const FD_SETSIZE: usize = 1024; + +pub const EPOLLIN: ::c_int = 0x1; +pub const EPOLLPRI: ::c_int = 0x2; +pub const EPOLLOUT: ::c_int = 0x4; +pub const EPOLLRDNORM: ::c_int = 0x40; +pub const EPOLLRDBAND: ::c_int = 0x80; +pub const EPOLLWRNORM: ::c_int = 0x100; +pub const EPOLLWRBAND: ::c_int = 0x200; +pub const EPOLLMSG: ::c_int = 0x400; +pub const EPOLLERR: ::c_int = 0x8; +pub const EPOLLHUP: ::c_int = 0x10; +pub const EPOLLET: ::c_int = 0x80000000; + +pub const EPOLL_CTL_ADD: ::c_int = 1; +pub const EPOLL_CTL_MOD: ::c_int = 3; +pub const EPOLL_CTL_DEL: ::c_int = 2; + +pub const MNT_DETACH: ::c_int = 0x2; +pub const MNT_EXPIRE: ::c_int = 0x4; + +pub const Q_GETFMT: ::c_int = 0x800004; +pub const Q_GETINFO: ::c_int = 0x800005; +pub const Q_SETINFO: ::c_int = 0x800006; +pub const QIF_BLIMITS: ::uint32_t = 1; +pub const QIF_SPACE: ::uint32_t = 2; +pub const QIF_ILIMITS: ::uint32_t = 4; +pub const QIF_INODES: ::uint32_t = 8; +pub const QIF_BTIME: ::uint32_t = 16; +pub const QIF_ITIME: ::uint32_t = 32; +pub const QIF_LIMITS: ::uint32_t = 5; +pub const QIF_USAGE: ::uint32_t = 10; +pub const QIF_TIMES: ::uint32_t = 48; +pub const QIF_ALL: ::uint32_t = 63; + +pub const MNT_FORCE: ::c_int = 0x1; + +pub const Q_SYNC: ::c_int = 0x800001; +pub const Q_QUOTAON: ::c_int = 0x800002; +pub const Q_QUOTAOFF: ::c_int = 0x800003; +pub const Q_GETQUOTA: ::c_int = 0x800007; +pub const Q_SETQUOTA: ::c_int = 0x800008; + +pub const TCIOFF: ::c_int = 2; +pub const TCION: ::c_int = 3; +pub const TCOOFF: ::c_int = 0; +pub const TCOON: ::c_int = 1; +pub const TCIFLUSH: ::c_int = 0; +pub const TCOFLUSH: ::c_int = 1; +pub const TCIOFLUSH: ::c_int = 2; +pub const NL0: ::c_int = 0x00000000; +pub const NL1: ::c_int = 0x00000100; +pub const TAB0: ::c_int = 0x00000000; +pub const CR0: ::c_int = 0x00000000; +pub const FF0: ::c_int = 0x00000000; +pub const BS0: ::c_int = 0x00000000; +pub const VT0: ::c_int = 0x00000000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: ::tcflag_t = 0x00000001; +pub const BRKINT: ::tcflag_t = 0x00000002; +pub const IGNPAR: ::tcflag_t = 0x00000004; +pub const PARMRK: ::tcflag_t = 0x00000008; +pub const INPCK: ::tcflag_t = 0x00000010; +pub const ISTRIP: ::tcflag_t = 0x00000020; +pub const INLCR: ::tcflag_t = 0x00000040; +pub const IGNCR: ::tcflag_t = 0x00000080; +pub const ICRNL: ::tcflag_t = 0x00000100; +pub const IXANY: ::tcflag_t = 0x00000800; +pub const IMAXBEL: ::tcflag_t = 0x00002000; +pub const OPOST: ::tcflag_t = 0x1; +pub const CS5: ::tcflag_t = 0x00000000; +pub const CRTSCTS: ::tcflag_t = 0x80000000; +pub const ECHO: ::tcflag_t = 0x00000008; +pub const OCRNL: ::tcflag_t = 0o000010; +pub const ONOCR: ::tcflag_t = 0o000020; +pub const ONLRET: ::tcflag_t = 0o000040; +pub const OFILL: ::tcflag_t = 0o000100; +pub const OFDEL: ::tcflag_t = 0o000200; + +pub const CLONE_VM: ::c_int = 0x100; +pub const CLONE_FS: ::c_int = 0x200; +pub const CLONE_FILES: ::c_int = 0x400; +pub const CLONE_SIGHAND: ::c_int = 0x800; +pub const CLONE_PTRACE: ::c_int = 0x2000; +pub const CLONE_VFORK: ::c_int = 0x4000; +pub const CLONE_PARENT: ::c_int = 0x8000; +pub const CLONE_THREAD: ::c_int = 0x10000; +pub const CLONE_NEWNS: ::c_int = 0x20000; +pub const CLONE_SYSVSEM: ::c_int = 0x40000; +pub const CLONE_SETTLS: ::c_int = 0x80000; +pub const CLONE_PARENT_SETTID: ::c_int = 0x100000; +pub const CLONE_CHILD_CLEARTID: ::c_int = 0x200000; +pub const CLONE_DETACHED: ::c_int = 0x400000; +pub const CLONE_UNTRACED: ::c_int = 0x800000; +pub const CLONE_CHILD_SETTID: ::c_int = 0x01000000; +pub const CLONE_NEWUTS: ::c_int = 0x04000000; +pub const CLONE_NEWIPC: ::c_int = 0x08000000; +pub const CLONE_NEWUSER: ::c_int = 0x10000000; +pub const CLONE_NEWPID: ::c_int = 0x20000000; +pub const CLONE_NEWNET: ::c_int = 0x40000000; +pub const CLONE_IO: ::c_int = 0x80000000; +pub const CLONE_NEWCGROUP: ::c_int = 0x02000000; + +pub const WNOHANG: ::c_int = 0x00000001; +pub const WUNTRACED: ::c_int = 0x00000002; +pub const WSTOPPED: ::c_int = WUNTRACED; +pub const WEXITED: ::c_int = 0x00000004; +pub const WCONTINUED: ::c_int = 0x00000008; +pub const WNOWAIT: ::c_int = 0x01000000; + +// ::Options set using PTRACE_SETOPTIONS. +pub const PTRACE_O_TRACESYSGOOD: ::c_int = 0x00000001; +pub const PTRACE_O_TRACEFORK: ::c_int = 0x00000002; +pub const PTRACE_O_TRACEVFORK: ::c_int = 0x00000004; +pub const PTRACE_O_TRACECLONE: ::c_int = 0x00000008; +pub const PTRACE_O_TRACEEXEC: ::c_int = 0x00000010; +pub const PTRACE_O_TRACEVFORKDONE: ::c_int = 0x00000020; +pub const PTRACE_O_TRACEEXIT: ::c_int = 0x00000040; +pub const PTRACE_O_TRACESECCOMP: ::c_int = 0x00000080; +pub const PTRACE_O_EXITKILL: ::c_int = 0x00100000; +pub const PTRACE_O_SUSPEND_SECCOMP: ::c_int = 0x00200000; +pub const PTRACE_O_MASK: ::c_int = 0x003000ff; + +// Wait extended result codes for the above trace options. +pub const PTRACE_EVENT_FORK: ::c_int = 1; +pub const PTRACE_EVENT_VFORK: ::c_int = 2; +pub const PTRACE_EVENT_CLONE: ::c_int = 3; +pub const PTRACE_EVENT_EXEC: ::c_int = 4; +pub const PTRACE_EVENT_VFORK_DONE: ::c_int = 5; +pub const PTRACE_EVENT_EXIT: ::c_int = 6; +pub const PTRACE_EVENT_SECCOMP: ::c_int = 7; +// PTRACE_EVENT_STOP was added to glibc in 2.26 +// pub const PTRACE_EVENT_STOP: ::c_int = 128; + +pub const __WNOTHREAD: ::c_int = 0x20000000; +pub const __WALL: ::c_int = 0x40000000; +pub const __WCLONE: ::c_int = 0x80000000; + +pub const SPLICE_F_MOVE: ::c_uint = 0x01; +pub const SPLICE_F_NONBLOCK: ::c_uint = 0x02; +pub const SPLICE_F_MORE: ::c_uint = 0x04; +pub const SPLICE_F_GIFT: ::c_uint = 0x08; + +pub const RTLD_LOCAL: ::c_int = 0; +pub const RTLD_LAZY: ::c_int = 1; + +pub const POSIX_FADV_NORMAL: ::c_int = 0; +pub const POSIX_FADV_RANDOM: ::c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_FADV_WILLNEED: ::c_int = 3; + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x100; +pub const AT_REMOVEDIR: ::c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x400; +pub const AT_NO_AUTOMOUNT: ::c_int = 0x800; +pub const AT_EMPTY_PATH: ::c_int = 0x1000; + +pub const LOG_CRON: ::c_int = 9 << 3; +pub const LOG_AUTHPRIV: ::c_int = 10 << 3; +pub const LOG_FTP: ::c_int = 11 << 3; +pub const LOG_PERROR: ::c_int = 0x20; + +pub const PIPE_BUF: usize = 4096; + +pub const SI_LOAD_SHIFT: ::c_uint = 16; + +pub const SIGEV_SIGNAL: ::c_int = 0; +pub const SIGEV_NONE: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; +pub const POLLRDNORM: ::c_short = 0x040; +pub const POLLRDBAND: ::c_short = 0x080; + +pub const ABDAY_1: ::nl_item = 0x20000; +pub const ABDAY_2: ::nl_item = 0x20001; +pub const ABDAY_3: ::nl_item = 0x20002; +pub const ABDAY_4: ::nl_item = 0x20003; +pub const ABDAY_5: ::nl_item = 0x20004; +pub const ABDAY_6: ::nl_item = 0x20005; +pub const ABDAY_7: ::nl_item = 0x20006; + +pub const DAY_1: ::nl_item = 0x20007; +pub const DAY_2: ::nl_item = 0x20008; +pub const DAY_3: ::nl_item = 0x20009; +pub const DAY_4: ::nl_item = 0x2000A; +pub const DAY_5: ::nl_item = 0x2000B; +pub const DAY_6: ::nl_item = 0x2000C; +pub const DAY_7: ::nl_item = 0x2000D; + +pub const ABMON_1: ::nl_item = 0x2000E; +pub const ABMON_2: ::nl_item = 0x2000F; +pub const ABMON_3: ::nl_item = 0x20010; +pub const ABMON_4: ::nl_item = 0x20011; +pub const ABMON_5: ::nl_item = 0x20012; +pub const ABMON_6: ::nl_item = 0x20013; +pub const ABMON_7: ::nl_item = 0x20014; +pub const ABMON_8: ::nl_item = 0x20015; +pub const ABMON_9: ::nl_item = 0x20016; +pub const ABMON_10: ::nl_item = 0x20017; +pub const ABMON_11: ::nl_item = 0x20018; +pub const ABMON_12: ::nl_item = 0x20019; + +pub const MON_1: ::nl_item = 0x2001A; +pub const MON_2: ::nl_item = 0x2001B; +pub const MON_3: ::nl_item = 0x2001C; +pub const MON_4: ::nl_item = 0x2001D; +pub const MON_5: ::nl_item = 0x2001E; +pub const MON_6: ::nl_item = 0x2001F; +pub const MON_7: ::nl_item = 0x20020; +pub const MON_8: ::nl_item = 0x20021; +pub const MON_9: ::nl_item = 0x20022; +pub const MON_10: ::nl_item = 0x20023; +pub const MON_11: ::nl_item = 0x20024; +pub const MON_12: ::nl_item = 0x20025; + +pub const AM_STR: ::nl_item = 0x20026; +pub const PM_STR: ::nl_item = 0x20027; + +pub const D_T_FMT: ::nl_item = 0x20028; +pub const D_FMT: ::nl_item = 0x20029; +pub const T_FMT: ::nl_item = 0x2002A; +pub const T_FMT_AMPM: ::nl_item = 0x2002B; + +pub const ERA: ::nl_item = 0x2002C; +pub const ERA_D_FMT: ::nl_item = 0x2002E; +pub const ALT_DIGITS: ::nl_item = 0x2002F; +pub const ERA_D_T_FMT: ::nl_item = 0x20030; +pub const ERA_T_FMT: ::nl_item = 0x20031; + +pub const CODESET: ::nl_item = 14; + +pub const CRNCYSTR: ::nl_item = 0x4000F; + +pub const RUSAGE_THREAD: ::c_int = 1; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const RADIXCHAR: ::nl_item = 0x10000; +pub const THOUSEP: ::nl_item = 0x10001; + +pub const YESEXPR: ::nl_item = 0x50000; +pub const NOEXPR: ::nl_item = 0x50001; +pub const YESSTR: ::nl_item = 0x50002; +pub const NOSTR: ::nl_item = 0x50003; + +pub const FILENAME_MAX: ::c_uint = 4096; +pub const L_tmpnam: ::c_uint = 20; +pub const _PC_LINK_MAX: ::c_int = 0; +pub const _PC_MAX_CANON: ::c_int = 1; +pub const _PC_MAX_INPUT: ::c_int = 2; +pub const _PC_NAME_MAX: ::c_int = 3; +pub const _PC_PATH_MAX: ::c_int = 4; +pub const _PC_PIPE_BUF: ::c_int = 5; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 6; +pub const _PC_NO_TRUNC: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; +pub const _PC_SYNC_IO: ::c_int = 9; +pub const _PC_ASYNC_IO: ::c_int = 10; +pub const _PC_PRIO_IO: ::c_int = 11; +pub const _PC_SOCK_MAXBUF: ::c_int = 12; +pub const _PC_FILESIZEBITS: ::c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 16; +pub const _PC_REC_XFER_ALIGN: ::c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 18; +pub const _PC_SYMLINK_MAX: ::c_int = 19; +pub const _PC_2_SYMLINKS: ::c_int = 20; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_CHILD_MAX: ::c_int = 1; +pub const _SC_CLK_TCK: ::c_int = 2; +pub const _SC_NGROUPS_MAX: ::c_int = 3; +pub const _SC_OPEN_MAX: ::c_int = 4; +pub const _SC_STREAM_MAX: ::c_int = 5; +pub const _SC_TZNAME_MAX: ::c_int = 6; +pub const _SC_JOB_CONTROL: ::c_int = 7; +pub const _SC_SAVED_IDS: ::c_int = 8; +pub const _SC_REALTIME_SIGNALS: ::c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10; +pub const _SC_TIMERS: ::c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12; +pub const _SC_PRIORITIZED_IO: ::c_int = 13; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 14; +pub const _SC_FSYNC: ::c_int = 15; +pub const _SC_MAPPED_FILES: ::c_int = 16; +pub const _SC_MEMLOCK: ::c_int = 17; +pub const _SC_MEMLOCK_RANGE: ::c_int = 18; +pub const _SC_MEMORY_PROTECTION: ::c_int = 19; +pub const _SC_MESSAGE_PASSING: ::c_int = 20; +pub const _SC_SEMAPHORES: ::c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 23; +pub const _SC_AIO_MAX: ::c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25; +pub const _SC_DELAYTIMER_MAX: ::c_int = 26; +pub const _SC_MQ_OPEN_MAX: ::c_int = 27; +pub const _SC_MQ_PRIO_MAX: ::c_int = 28; +pub const _SC_VERSION: ::c_int = 29; +pub const _SC_PAGESIZE: ::c_int = 30; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: ::c_int = 31; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 32; +pub const _SC_SEM_VALUE_MAX: ::c_int = 33; +pub const _SC_SIGQUEUE_MAX: ::c_int = 34; +pub const _SC_TIMER_MAX: ::c_int = 35; +pub const _SC_BC_BASE_MAX: ::c_int = 36; +pub const _SC_BC_DIM_MAX: ::c_int = 37; +pub const _SC_BC_SCALE_MAX: ::c_int = 38; +pub const _SC_BC_STRING_MAX: ::c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40; +pub const _SC_EXPR_NEST_MAX: ::c_int = 42; +pub const _SC_LINE_MAX: ::c_int = 43; +pub const _SC_RE_DUP_MAX: ::c_int = 44; +pub const _SC_2_VERSION: ::c_int = 46; +pub const _SC_2_C_BIND: ::c_int = 47; +pub const _SC_2_C_DEV: ::c_int = 48; +pub const _SC_2_FORT_DEV: ::c_int = 49; +pub const _SC_2_FORT_RUN: ::c_int = 50; +pub const _SC_2_SW_DEV: ::c_int = 51; +pub const _SC_2_LOCALEDEF: ::c_int = 52; +pub const _SC_UIO_MAXIOV: ::c_int = 60; +pub const _SC_IOV_MAX: ::c_int = 60; +pub const _SC_THREADS: ::c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 71; +pub const _SC_TTY_NAME_MAX: ::c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 74; +pub const _SC_THREAD_STACK_MIN: ::c_int = 75; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 82; +pub const _SC_NPROCESSORS_CONF: ::c_int = 83; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 84; +pub const _SC_PHYS_PAGES: ::c_int = 85; +pub const _SC_AVPHYS_PAGES: ::c_int = 86; +pub const _SC_ATEXIT_MAX: ::c_int = 87; +pub const _SC_PASS_MAX: ::c_int = 88; +pub const _SC_XOPEN_VERSION: ::c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90; +pub const _SC_XOPEN_UNIX: ::c_int = 91; +pub const _SC_XOPEN_CRYPT: ::c_int = 92; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 93; +pub const _SC_XOPEN_SHM: ::c_int = 94; +pub const _SC_2_CHAR_TERM: ::c_int = 95; +pub const _SC_2_UPE: ::c_int = 97; +pub const _SC_XOPEN_XPG2: ::c_int = 98; +pub const _SC_XOPEN_XPG3: ::c_int = 99; +pub const _SC_XOPEN_XPG4: ::c_int = 100; +pub const _SC_NZERO: ::c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128; +pub const _SC_XOPEN_LEGACY: ::c_int = 129; +pub const _SC_XOPEN_REALTIME: ::c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131; +pub const _SC_ADVISORY_INFO: ::c_int = 132; +pub const _SC_BARRIERS: ::c_int = 133; +pub const _SC_CLOCK_SELECTION: ::c_int = 137; +pub const _SC_CPUTIME: ::c_int = 138; +pub const _SC_THREAD_CPUTIME: ::c_int = 139; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 149; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 153; +pub const _SC_SPIN_LOCKS: ::c_int = 154; +pub const _SC_REGEXP: ::c_int = 155; +pub const _SC_SHELL: ::c_int = 157; +pub const _SC_SPAWN: ::c_int = 159; +pub const _SC_SPORADIC_SERVER: ::c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 161; +pub const _SC_TIMEOUTS: ::c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 165; +pub const _SC_2_PBS: ::c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 169; +pub const _SC_2_PBS_LOCATE: ::c_int = 170; +pub const _SC_2_PBS_MESSAGE: ::c_int = 171; +pub const _SC_2_PBS_TRACK: ::c_int = 172; +pub const _SC_SYMLOOP_MAX: ::c_int = 173; +pub const _SC_STREAMS: ::c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 175; +pub const _SC_V6_ILP32_OFF32: ::c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 177; +pub const _SC_V6_LP64_OFF64: ::c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 179; +pub const _SC_HOST_NAME_MAX: ::c_int = 180; +pub const _SC_TRACE: ::c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 182; +pub const _SC_TRACE_INHERIT: ::c_int = 183; +pub const _SC_TRACE_LOG: ::c_int = 184; +pub const _SC_IPV6: ::c_int = 235; +pub const _SC_RAW_SOCKETS: ::c_int = 236; +pub const _SC_V7_ILP32_OFF32: ::c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 238; +pub const _SC_V7_LP64_OFF64: ::c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 240; +pub const _SC_SS_REPL_MAX: ::c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 242; +pub const _SC_TRACE_NAME_MAX: ::c_int = 243; +pub const _SC_TRACE_SYS_MAX: ::c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 245; +pub const _SC_XOPEN_STREAMS: ::c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 248; + +pub const RLIM_SAVED_MAX: ::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: ::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: ::c_int = 1 << 0; +pub const GLOB_MARK: ::c_int = 1 << 1; +pub const GLOB_NOSORT: ::c_int = 1 << 2; +pub const GLOB_DOOFFS: ::c_int = 1 << 3; +pub const GLOB_NOCHECK: ::c_int = 1 << 4; +pub const GLOB_APPEND: ::c_int = 1 << 5; +pub const GLOB_NOESCAPE: ::c_int = 1 << 6; + +pub const GLOB_NOSPACE: ::c_int = 1; +pub const GLOB_ABORTED: ::c_int = 2; +pub const GLOB_NOMATCH: ::c_int = 3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; + +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; + +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; + +pub const IFF_LOWER_UP: ::c_int = 0x10000; +pub const IFF_DORMANT: ::c_int = 0x20000; +pub const IFF_ECHO: ::c_int = 0x40000; + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; +pub const ST_NODEV: ::c_ulong = 4; +pub const ST_NOEXEC: ::c_ulong = 8; +pub const ST_SYNCHRONOUS: ::c_ulong = 16; +pub const ST_MANDLOCK: ::c_ulong = 64; +pub const ST_WRITE: ::c_ulong = 128; +pub const ST_APPEND: ::c_ulong = 256; +pub const ST_IMMUTABLE: ::c_ulong = 512; +pub const ST_NOATIME: ::c_ulong = 1024; +pub const ST_NODIRATIME: ::c_ulong = 2048; + +pub const RTLD_NEXT: *mut ::c_void = -1i64 as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_NOW: ::c_int = 0x2; + +pub const TCP_MD5SIG: ::c_int = 14; + +align_const! { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], + }; +} +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_PROCESS_PRIVATE: ::c_int = 0; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const RENAME_NOREPLACE: ::c_int = 1; +pub const RENAME_EXCHANGE: ::c_int = 2; +pub const RENAME_WHITEOUT: ::c_int = 4; + +pub const SCHED_OTHER: ::c_int = 0; +pub const SCHED_FIFO: ::c_int = 1; +pub const SCHED_RR: ::c_int = 2; +pub const SCHED_BATCH: ::c_int = 3; +pub const SCHED_IDLE: ::c_int = 5; + +// netinet/in.h +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: ::c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +pub const IPPROTO_MTP: ::c_int = 92; +pub const IPPROTO_BEETPH: ::c_int = 94; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: ::c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_COMP: ::c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; +pub const IPPROTO_MH: ::c_int = 135; +pub const IPPROTO_UDPLITE: ::c_int = 136; +pub const IPPROTO_MPLS: ::c_int = 137; +/// raw IP packet +pub const IPPROTO_RAW: ::c_int = 255; +pub const IPPROTO_MAX: ::c_int = 256; + +pub const AF_IB: ::c_int = 27; +pub const AF_MPLS: ::c_int = 28; +pub const AF_NFC: ::c_int = 39; +pub const AF_VSOCK: ::c_int = 40; +pub const PF_IB: ::c_int = AF_IB; +pub const PF_MPLS: ::c_int = AF_MPLS; +pub const PF_NFC: ::c_int = AF_NFC; +pub const PF_VSOCK: ::c_int = AF_VSOCK; + +// System V IPC +pub const IPC_PRIVATE: ::key_t = 0; + +pub const IPC_CREAT: ::c_int = 0o1000; +pub const IPC_EXCL: ::c_int = 0o2000; +pub const IPC_NOWAIT: ::c_int = 0o4000; + +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; +pub const IPC_INFO: ::c_int = 3; +pub const MSG_STAT: ::c_int = 11; +pub const MSG_INFO: ::c_int = 12; + +pub const MSG_NOERROR: ::c_int = 0o10000; +pub const MSG_EXCEPT: ::c_int = 0o20000; +pub const MSG_COPY: ::c_int = 0o40000; + +pub const SHM_R: ::c_int = 0o400; +pub const SHM_W: ::c_int = 0o200; + +pub const SHM_RDONLY: ::c_int = 0o10000; +pub const SHM_RND: ::c_int = 0o20000; +pub const SHM_REMAP: ::c_int = 0o40000; +pub const SHM_EXEC: ::c_int = 0o100000; + +pub const SHM_LOCK: ::c_int = 11; +pub const SHM_UNLOCK: ::c_int = 12; + +pub const SHM_HUGETLB: ::c_int = 0o4000; +pub const SHM_NORESERVE: ::c_int = 0o10000; + +pub const EPOLLRDHUP: ::c_int = 0x2000; +pub const EPOLLEXCLUSIVE: ::c_int = 0x10000000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; + +pub const QFMT_VFS_OLD: ::c_int = 1; +pub const QFMT_VFS_V0: ::c_int = 2; +pub const QFMT_VFS_V1: ::c_int = 4; + +pub const EFD_SEMAPHORE: ::c_int = 0x1; + +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const SEM_FAILED: *mut ::sem_t = 0 as *mut sem_t; + +pub const RB_AUTOBOOT: ::c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: ::c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: ::c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: ::c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: ::c_int = 0x4321fedcu32 as i32; +pub const RB_SW_SUSPEND: ::c_int = 0xd000fce2u32 as i32; +pub const RB_KEXEC: ::c_int = 0x45584543u32 as i32; + +pub const AI_PASSIVE: ::c_int = 0x0001; +pub const AI_CANONNAME: ::c_int = 0x0002; +pub const AI_NUMERICHOST: ::c_int = 0x0004; +pub const AI_V4MAPPED: ::c_int = 0x0008; +pub const AI_ALL: ::c_int = 0x0010; +pub const AI_ADDRCONFIG: ::c_int = 0x0020; + +pub const AI_NUMERICSERV: ::c_int = 0x0400; + +pub const EAI_BADFLAGS: ::c_int = -1; +pub const EAI_NONAME: ::c_int = -2; +pub const EAI_AGAIN: ::c_int = -3; +pub const EAI_FAIL: ::c_int = -4; +pub const EAI_FAMILY: ::c_int = -6; +pub const EAI_SOCKTYPE: ::c_int = -7; +pub const EAI_SERVICE: ::c_int = -8; +pub const EAI_MEMORY: ::c_int = -10; +pub const EAI_OVERFLOW: ::c_int = -12; + +pub const NI_NUMERICHOST: ::c_int = 1; +pub const NI_NUMERICSERV: ::c_int = 2; +pub const NI_NOFQDN: ::c_int = 4; +pub const NI_NAMEREQD: ::c_int = 8; +pub const NI_DGRAM: ::c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: ::c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: ::c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: ::c_uint = 4; + +pub const EAI_SYSTEM: ::c_int = -11; + +pub const AIO_CANCELED: ::c_int = 0; +pub const AIO_NOTCANCELED: ::c_int = 1; +pub const AIO_ALLDONE: ::c_int = 2; +pub const LIO_READ: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 1; +pub const LIO_NOP: ::c_int = 2; +pub const LIO_WAIT: ::c_int = 0; +pub const LIO_NOWAIT: ::c_int = 1; + +pub const MREMAP_MAYMOVE: ::c_int = 1; +pub const MREMAP_FIXED: ::c_int = 2; + +pub const PR_SET_PDEATHSIG: ::c_int = 1; +pub const PR_GET_PDEATHSIG: ::c_int = 2; + +pub const PR_GET_DUMPABLE: ::c_int = 3; +pub const PR_SET_DUMPABLE: ::c_int = 4; + +pub const PR_GET_UNALIGN: ::c_int = 5; +pub const PR_SET_UNALIGN: ::c_int = 6; +pub const PR_UNALIGN_NOPRINT: ::c_int = 1; +pub const PR_UNALIGN_SIGBUS: ::c_int = 2; + +pub const PR_GET_KEEPCAPS: ::c_int = 7; +pub const PR_SET_KEEPCAPS: ::c_int = 8; + +pub const PR_GET_FPEMU: ::c_int = 9; +pub const PR_SET_FPEMU: ::c_int = 10; +pub const PR_FPEMU_NOPRINT: ::c_int = 1; +pub const PR_FPEMU_SIGFPE: ::c_int = 2; + +pub const PR_GET_FPEXC: ::c_int = 11; +pub const PR_SET_FPEXC: ::c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: ::c_int = 0x80; +pub const PR_FP_EXC_DIV: ::c_int = 0x010000; +pub const PR_FP_EXC_OVF: ::c_int = 0x020000; +pub const PR_FP_EXC_UND: ::c_int = 0x040000; +pub const PR_FP_EXC_RES: ::c_int = 0x080000; +pub const PR_FP_EXC_INV: ::c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: ::c_int = 0; +pub const PR_FP_EXC_NONRECOV: ::c_int = 1; +pub const PR_FP_EXC_ASYNC: ::c_int = 2; +pub const PR_FP_EXC_PRECISE: ::c_int = 3; + +pub const PR_GET_TIMING: ::c_int = 13; +pub const PR_SET_TIMING: ::c_int = 14; +pub const PR_TIMING_STATISTICAL: ::c_int = 0; +pub const PR_TIMING_TIMESTAMP: ::c_int = 1; + +pub const PR_SET_NAME: ::c_int = 15; +pub const PR_GET_NAME: ::c_int = 16; + +pub const PR_GET_ENDIAN: ::c_int = 19; +pub const PR_SET_ENDIAN: ::c_int = 20; +pub const PR_ENDIAN_BIG: ::c_int = 0; +pub const PR_ENDIAN_LITTLE: ::c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: ::c_int = 2; + +pub const PR_GET_SECCOMP: ::c_int = 21; +pub const PR_SET_SECCOMP: ::c_int = 22; + +pub const PR_CAPBSET_READ: ::c_int = 23; +pub const PR_CAPBSET_DROP: ::c_int = 24; + +pub const PR_GET_TSC: ::c_int = 25; +pub const PR_SET_TSC: ::c_int = 26; +pub const PR_TSC_ENABLE: ::c_int = 1; +pub const PR_TSC_SIGSEGV: ::c_int = 2; + +pub const PR_GET_SECUREBITS: ::c_int = 27; +pub const PR_SET_SECUREBITS: ::c_int = 28; + +pub const PR_SET_TIMERSLACK: ::c_int = 29; +pub const PR_GET_TIMERSLACK: ::c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: ::c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: ::c_int = 32; + +pub const PR_MCE_KILL: ::c_int = 33; +pub const PR_MCE_KILL_CLEAR: ::c_int = 0; +pub const PR_MCE_KILL_SET: ::c_int = 1; + +pub const PR_MCE_KILL_LATE: ::c_int = 0; +pub const PR_MCE_KILL_EARLY: ::c_int = 1; +pub const PR_MCE_KILL_DEFAULT: ::c_int = 2; + +pub const PR_MCE_KILL_GET: ::c_int = 34; + +pub const PR_SET_MM: ::c_int = 35; +pub const PR_SET_MM_START_CODE: ::c_int = 1; +pub const PR_SET_MM_END_CODE: ::c_int = 2; +pub const PR_SET_MM_START_DATA: ::c_int = 3; +pub const PR_SET_MM_END_DATA: ::c_int = 4; +pub const PR_SET_MM_START_STACK: ::c_int = 5; +pub const PR_SET_MM_START_BRK: ::c_int = 6; +pub const PR_SET_MM_BRK: ::c_int = 7; +pub const PR_SET_MM_ARG_START: ::c_int = 8; +pub const PR_SET_MM_ARG_END: ::c_int = 9; +pub const PR_SET_MM_ENV_START: ::c_int = 10; +pub const PR_SET_MM_ENV_END: ::c_int = 11; +pub const PR_SET_MM_AUXV: ::c_int = 12; +pub const PR_SET_MM_EXE_FILE: ::c_int = 13; +pub const PR_SET_MM_MAP: ::c_int = 14; +pub const PR_SET_MM_MAP_SIZE: ::c_int = 15; + +pub const PR_SET_PTRACER: ::c_int = 0x59616d61; + +pub const PR_SET_CHILD_SUBREAPER: ::c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: ::c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: ::c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: ::c_int = 39; + +pub const PR_GET_TID_ADDRESS: ::c_int = 40; + +pub const PR_SET_THP_DISABLE: ::c_int = 41; +pub const PR_GET_THP_DISABLE: ::c_int = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT: ::c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: ::c_int = 44; + +pub const PR_SET_FP_MODE: ::c_int = 45; +pub const PR_GET_FP_MODE: ::c_int = 46; +pub const PR_FP_MODE_FR: ::c_int = 1 << 0; +pub const PR_FP_MODE_FRE: ::c_int = 1 << 1; + +pub const PR_CAP_AMBIENT: ::c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: ::c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: ::c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: ::c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: ::c_int = 4; + +pub const GRND_NONBLOCK: ::c_uint = 0x0001; +pub const GRND_RANDOM: ::c_uint = 0x0002; + +pub const ITIMER_REAL: ::c_int = 0; +pub const ITIMER_VIRTUAL: ::c_int = 1; +pub const ITIMER_PROF: ::c_int = 2; + +pub const TFD_CLOEXEC: ::c_int = O_CLOEXEC; +pub const TFD_NONBLOCK: ::c_int = O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: ::c_int = 1; + +pub const XATTR_CREATE: ::c_int = 0x1; +pub const XATTR_REPLACE: ::c_int = 0x2; + +pub const _POSIX_VDISABLE: ::cc_t = 0; + +pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02; +pub const FALLOC_FL_COLLAPSE_RANGE: ::c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: ::c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: ::c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: ::c_int = 0x40; + +// On Linux, libc doesn't define this constant, libattr does instead. +// We still define it for Linux as it's defined by libc on other platforms, +// and it's mentioned in the man pages for getxattr and setxattr. +pub const ENOATTR: ::c_int = ::ENODATA; + +pub const SO_ORIGINAL_DST: ::c_int = 80; +pub const IUTF8: ::tcflag_t = 0x00004000; +pub const CMSPAR: ::tcflag_t = 0o10000000000; + +pub const MFD_CLOEXEC: ::c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002; + +// these are used in the p_type field of Elf32_Phdr and Elf64_Phdr, which has +// the type Elf32Word and Elf64Word respectively. Luckily, both of those are u32 +// so we can use that type here to avoid having to cast. +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_NUM: u32 = 8; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_STACK: u32 = 0x6474e551; +pub const PT_GNU_RELRO: u32 = 0x6474e552; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 0x00040000; +pub const O_NOATIME: ::c_int = 0x00002000; +pub const O_CLOEXEC: ::c_int = 0x00000100; +pub const O_TMPFILE: ::c_int = 0x00004000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const BUFSIZ: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 10000; +pub const FOPEN_MAX: ::c_uint = 1000; +pub const O_PATH: ::c_int = 0x00400000; +pub const O_EXEC: ::c_int = O_PATH; +pub const O_SEARCH: ::c_int = O_PATH; +pub const O_ACCMODE: ::c_int = (03 | O_SEARCH); +pub const O_NDELAY: ::c_int = O_NONBLOCK; +pub const NI_MAXHOST: ::socklen_t = 255; +pub const PTHREAD_STACK_MIN: ::size_t = 2048; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; + +pub const POSIX_MADV_DONTNEED: ::c_int = 4; + +pub const RLIM_INFINITY: ::rlim_t = !0; +pub const RLIMIT_RTTIME: ::c_int = 15; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const MAP_ANONYMOUS: ::c_int = MAP_ANON; + +pub const SOCK_DCCP: ::c_int = 6; +pub const SOCK_PACKET: ::c_int = 10; + +pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16; +pub const TCP_THIN_DUPACK: ::c_int = 17; +pub const TCP_USER_TIMEOUT: ::c_int = 18; +pub const TCP_REPAIR: ::c_int = 19; +pub const TCP_REPAIR_QUEUE: ::c_int = 20; +pub const TCP_QUEUE_SEQ: ::c_int = 21; +pub const TCP_REPAIR_OPTIONS: ::c_int = 22; +pub const TCP_FASTOPEN: ::c_int = 23; +pub const TCP_TIMESTAMP: ::c_int = 24; + +pub const SIGUNUSED: ::c_int = ::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const CPU_SETSIZE: ::c_int = 128; + +pub const PTRACE_TRACEME: ::c_int = 0; +pub const PTRACE_PEEKTEXT: ::c_int = 1; +pub const PTRACE_PEEKDATA: ::c_int = 2; +pub const PTRACE_PEEKUSER: ::c_int = 3; +pub const PTRACE_POKETEXT: ::c_int = 4; +pub const PTRACE_POKEDATA: ::c_int = 5; +pub const PTRACE_POKEUSER: ::c_int = 6; +pub const PTRACE_CONT: ::c_int = 7; +pub const PTRACE_KILL: ::c_int = 8; +pub const PTRACE_SINGLESTEP: ::c_int = 9; +pub const PTRACE_GETREGS: ::c_int = 12; +pub const PTRACE_SETREGS: ::c_int = 13; +pub const PTRACE_GETFPREGS: ::c_int = 14; +pub const PTRACE_SETFPREGS: ::c_int = 15; +pub const PTRACE_ATTACH: ::c_int = 16; +pub const PTRACE_DETACH: ::c_int = 17; +pub const PTRACE_GETFPXREGS: ::c_int = 18; +pub const PTRACE_SETFPXREGS: ::c_int = 19; +pub const PTRACE_SYSCALL: ::c_int = 24; +pub const PTRACE_SETOPTIONS: ::c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_int = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_int = 0x4203; +pub const PTRACE_GETREGSET: ::c_int = 0x4204; +pub const PTRACE_SETREGSET: ::c_int = 0x4205; +pub const PTRACE_SEIZE: ::c_int = 0x4206; +pub const PTRACE_INTERRUPT: ::c_int = 0x4207; +pub const PTRACE_LISTEN: ::c_int = 0x4208; +pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209; + +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const EFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const SFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; + +pub const TIOCINQ: ::c_int = ::FIONREAD; + +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_NOLOAD: ::c_int = 0x4; + +// TODO(#247) Temporarily musl-specific (available since musl 0.9.12 / Linux +// kernel 3.10). See also notbsd/mod.rs +pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +pub const CLOCK_TAI: ::clockid_t = 11; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_MARK: ::c_int = 36; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; + +pub const O_ASYNC: ::c_int = 0x00000400; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; + +pub const O_APPEND: ::c_int = 0x00100000; +pub const O_CREAT: ::c_int = 0x00010000; +pub const O_EXCL: ::c_int = 0x00020000; +pub const O_NOCTTY: ::c_int = 0x00000200; +pub const O_NONBLOCK: ::c_int = 0x00000010; +pub const O_SYNC: ::c_int = (0x00000040 | O_DSYNC); +pub const O_RSYNC: ::c_int = O_SYNC; +pub const O_DSYNC: ::c_int = 0x00000020; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const EXTPROC: ::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; + +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +pub const O_DIRECTORY: ::c_int = 0x00080000; +pub const O_DIRECT: ::c_int = 0x00000800; +pub const O_LARGEFILE: ::c_int = 0x00001000; +pub const O_NOFOLLOW: ::c_int = 0x00000080; + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +// END_PUB_CONST + +f! { + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0xffff + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7f + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0x7f) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x80) != 0 + } + + pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + (cmd << 8) | (type_ & 0x00ff) + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * ::mem::size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn major(dev: ::dev_t) -> ::c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as ::c_uint + } + + pub fn minor(dev: ::dev_t) -> ::c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as ::c_uint + } + + pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } +} + +// EXTERN_FN + +#[link(name = "c")] +#[link(name = "fdio")] +extern {} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum FILE {} +impl ::Copy for FILE {} +impl ::Clone for FILE { + fn clone(&self) -> FILE { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos_t {} // TODO: fill this out with a struct +impl ::Copy for fpos_t {} +impl ::Clone for fpos_t { + fn clone(&self) -> fpos_t { *self } +} + +extern { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, + file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, + size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atoi(s: *const c_char) -> c_int; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_long; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_ulong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, + n: size_t) -> ::size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn abs(i: c_int) -> c_int; + pub fn atof(s: *const c_char) -> c_double; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn getpwnam(name: *const ::c_char) -> *mut passwd; + pub fn getpwuid(uid: ::uid_t) -> *mut passwd; + + pub fn fprintf(stream: *mut ::FILE, + format: *const ::c_char, ...) -> ::c_int; + pub fn printf(format: *const ::c_char, ...) -> ::c_int; + pub fn snprintf(s: *mut ::c_char, n: ::size_t, + format: *const ::c_char, ...) -> ::c_int; + pub fn sprintf(s: *mut ::c_char, format: *const ::c_char, ...) -> ::c_int; + pub fn fscanf(stream: *mut ::FILE, format: *const ::c_char, ...) -> ::c_int; + pub fn scanf(format: *const ::c_char, ...) -> ::c_int; + pub fn sscanf(s: *const ::c_char, format: *const ::c_char, ...) -> ::c_int; + pub fn getchar_unlocked() -> ::c_int; + pub fn putchar_unlocked(c: ::c_int) -> ::c_int; + + pub fn socket(domain: ::c_int, ty: ::c_int, protocol: ::c_int) -> ::c_int; + pub fn connect(socket: ::c_int, address: *const sockaddr, + len: socklen_t) -> ::c_int; + pub fn listen(socket: ::c_int, backlog: ::c_int) -> ::c_int; + pub fn accept(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + pub fn getpeername(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + pub fn getsockname(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + pub fn setsockopt(socket: ::c_int, level: ::c_int, name: ::c_int, + value: *const ::c_void, + option_len: socklen_t) -> ::c_int; + pub fn socketpair(domain: ::c_int, type_: ::c_int, protocol: ::c_int, + socket_vector: *mut ::c_int) -> ::c_int; + pub fn sendto(socket: ::c_int, buf: *const ::c_void, len: ::size_t, + flags: ::c_int, addr: *const sockaddr, + addrlen: socklen_t) -> ::ssize_t; + pub fn shutdown(socket: ::c_int, how: ::c_int) -> ::c_int; + + pub fn chmod(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fchmod(fd: ::c_int, mode: mode_t) -> ::c_int; + + pub fn fstat(fildes: ::c_int, buf: *mut stat) -> ::c_int; + + pub fn mkdir(path: *const c_char, mode: mode_t) -> ::c_int; + + pub fn stat(path: *const c_char, buf: *mut stat) -> ::c_int; + + pub fn pclose(stream: *mut ::FILE) -> ::c_int; + pub fn fdopen(fd: ::c_int, mode: *const c_char) -> *mut ::FILE; + pub fn fileno(stream: *mut ::FILE) -> ::c_int; + + pub fn open(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn creat(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int; + + pub fn opendir(dirname: *const c_char) -> *mut ::DIR; + pub fn readdir(dirp: *mut ::DIR) -> *mut ::dirent; + pub fn readdir_r(dirp: *mut ::DIR, entry: *mut ::dirent, + result: *mut *mut ::dirent) -> ::c_int; + pub fn closedir(dirp: *mut ::DIR) -> ::c_int; + pub fn rewinddir(dirp: *mut ::DIR); + + pub fn openat(dirfd: ::c_int, pathname: *const ::c_char, + flags: ::c_int, ...) -> ::c_int; + pub fn fchmodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, flags: ::c_int) -> ::c_int; + pub fn fchown(fd: ::c_int, + owner: ::uid_t, + group: ::gid_t) -> ::c_int; + pub fn fchownat(dirfd: ::c_int, pathname: *const ::c_char, + owner: ::uid_t, group: ::gid_t, + flags: ::c_int) -> ::c_int; + pub fn fstatat(dirfd: ::c_int, pathname: *const ::c_char, + buf: *mut stat, flags: ::c_int) -> ::c_int; + pub fn linkat(olddirfd: ::c_int, oldpath: *const ::c_char, + newdirfd: ::c_int, newpath: *const ::c_char, + flags: ::c_int) -> ::c_int; + pub fn mkdirat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn readlinkat(dirfd: ::c_int, pathname: *const ::c_char, + buf: *mut ::c_char, bufsiz: ::size_t) -> ::ssize_t; + pub fn renameat(olddirfd: ::c_int, oldpath: *const ::c_char, + newdirfd: ::c_int, newpath: *const ::c_char) + -> ::c_int; + pub fn symlinkat(target: *const ::c_char, newdirfd: ::c_int, + linkpath: *const ::c_char) -> ::c_int; + pub fn unlinkat(dirfd: ::c_int, pathname: *const ::c_char, + flags: ::c_int) -> ::c_int; + + pub fn access(path: *const c_char, amode: ::c_int) -> ::c_int; + pub fn alarm(seconds: ::c_uint) -> ::c_uint; + pub fn chdir(dir: *const c_char) -> ::c_int; + pub fn fchdir(dirfd: ::c_int) -> ::c_int; + pub fn chown(path: *const c_char, uid: uid_t, + gid: gid_t) -> ::c_int; + pub fn lchown(path: *const c_char, uid: uid_t, + gid: gid_t) -> ::c_int; + pub fn close(fd: ::c_int) -> ::c_int; + pub fn dup(fd: ::c_int) -> ::c_int; + pub fn dup2(src: ::c_int, dst: ::c_int) -> ::c_int; + pub fn execl(path: *const c_char, + arg0: *const c_char, ...) -> ::c_int; + pub fn execle(path: *const ::c_char, + arg0: *const ::c_char, ...) -> ::c_int; + pub fn execlp(file: *const ::c_char, + arg0: *const ::c_char, ...) -> ::c_int; + pub fn execv(prog: *const c_char, + argv: *const *const c_char) -> ::c_int; + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) + -> ::c_int; + pub fn execvp(c: *const c_char, + argv: *const *const c_char) -> ::c_int; + pub fn fork() -> pid_t; + pub fn fpathconf(filedes: ::c_int, name: ::c_int) -> c_long; + pub fn getcwd(buf: *mut c_char, size: ::size_t) -> *mut c_char; + pub fn getegid() -> gid_t; + pub fn geteuid() -> uid_t; + pub fn getgid() -> gid_t; + pub fn getgroups(ngroups_max: ::c_int, groups: *mut gid_t) + -> ::c_int; + pub fn getlogin() -> *mut c_char; + pub fn getopt(argc: ::c_int, argv: *const *mut c_char, + optstr: *const c_char) -> ::c_int; + pub fn getpgid(pid: pid_t) -> pid_t; + pub fn getpgrp() -> pid_t; + pub fn getpid() -> pid_t; + pub fn getppid() -> pid_t; + pub fn getuid() -> uid_t; + pub fn isatty(fd: ::c_int) -> ::c_int; + pub fn link(src: *const c_char, dst: *const c_char) -> ::c_int; + pub fn lseek(fd: ::c_int, offset: off_t, whence: ::c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: ::c_int) -> c_long; + pub fn pause() -> ::c_int; + pub fn pipe(fds: *mut ::c_int) -> ::c_int; + pub fn posix_memalign(memptr: *mut *mut ::c_void, + align: ::size_t, + size: ::size_t) -> ::c_int; + pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t) + -> ::ssize_t; + pub fn rmdir(path: *const c_char) -> ::c_int; + pub fn seteuid(uid: uid_t) -> ::c_int; + pub fn setegid(gid: gid_t) -> ::c_int; + pub fn setgid(gid: gid_t) -> ::c_int; + pub fn setpgid(pid: pid_t, pgid: pid_t) -> ::c_int; + pub fn setsid() -> pid_t; + pub fn setuid(uid: uid_t) -> ::c_int; + pub fn sleep(secs: ::c_uint) -> ::c_uint; + pub fn nanosleep(rqtp: *const timespec, + rmtp: *mut timespec) -> ::c_int; + pub fn tcgetpgrp(fd: ::c_int) -> pid_t; + pub fn tcsetpgrp(fd: ::c_int, pgrp: ::pid_t) -> ::c_int; + pub fn ttyname(fd: ::c_int) -> *mut c_char; + pub fn unlink(c: *const c_char) -> ::c_int; + pub fn wait(status: *mut ::c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *mut ::c_int, options: ::c_int) + -> pid_t; + pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) + -> ::ssize_t; + pub fn pread(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, + offset: off_t) -> ::ssize_t; + pub fn pwrite(fd: ::c_int, buf: *const ::c_void, count: ::size_t, + offset: off_t) -> ::ssize_t; + pub fn umask(mask: mode_t) -> mode_t; + + pub fn utime(file: *const c_char, buf: *const utimbuf) -> ::c_int; + + pub fn kill(pid: pid_t, sig: ::c_int) -> ::c_int; + + pub fn mlock(addr: *const ::c_void, len: ::size_t) -> ::c_int; + pub fn munlock(addr: *const ::c_void, len: ::size_t) -> ::c_int; + pub fn mlockall(flags: ::c_int) -> ::c_int; + pub fn munlockall() -> ::c_int; + + pub fn mmap(addr: *mut ::c_void, + len: ::size_t, + prot: ::c_int, + flags: ::c_int, + fd: ::c_int, + offset: off_t) + -> *mut ::c_void; + pub fn munmap(addr: *mut ::c_void, len: ::size_t) -> ::c_int; + + pub fn if_nametoindex(ifname: *const c_char) -> ::c_uint; + pub fn if_indextoname(ifindex: ::c_uint, + ifname: *mut ::c_char) -> *mut ::c_char; + + pub fn lstat(path: *const c_char, buf: *mut stat) -> ::c_int; + + pub fn fsync(fd: ::c_int) -> ::c_int; + + pub fn setenv(name: *const c_char, val: *const c_char, + overwrite: ::c_int) -> ::c_int; + pub fn unsetenv(name: *const c_char) -> ::c_int; + + pub fn symlink(path1: *const c_char, + path2: *const c_char) -> ::c_int; + + pub fn ftruncate(fd: ::c_int, length: off_t) -> ::c_int; + + pub fn signal(signum: ::c_int, handler: sighandler_t) -> sighandler_t; + + pub fn getrlimit(resource: ::c_int, rlim: *mut rlimit) -> ::c_int; + pub fn setrlimit(resource: ::c_int, rlim: *const rlimit) -> ::c_int; + pub fn getrusage(resource: ::c_int, usage: *mut rusage) -> ::c_int; + + pub fn realpath(pathname: *const ::c_char, resolved: *mut ::c_char) + -> *mut ::c_char; + + pub fn flock(fd: ::c_int, operation: ::c_int) -> ::c_int; + + pub fn gettimeofday(tp: *mut ::timeval, + tz: *mut ::c_void) -> ::c_int; + pub fn times(buf: *mut ::tms) -> ::clock_t; + + pub fn pthread_self() -> ::pthread_t; + pub fn pthread_join(native: ::pthread_t, + value: *mut *mut ::c_void) -> ::c_int; + pub fn pthread_exit(value: *mut ::c_void); + pub fn pthread_attr_init(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_destroy(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_setstacksize(attr: *mut ::pthread_attr_t, + stack_size: ::size_t) -> ::c_int; + pub fn pthread_attr_setdetachstate(attr: *mut ::pthread_attr_t, + state: ::c_int) -> ::c_int; + pub fn pthread_detach(thread: ::pthread_t) -> ::c_int; + pub fn sched_yield() -> ::c_int; + pub fn pthread_key_create(key: *mut pthread_key_t, + dtor: ::Option) + -> ::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ::c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ::c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const ::c_void) + -> ::c_int; + pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t) -> ::c_int; + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> ::c_int; + + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> ::c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> ::c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, + _type: ::c_int) -> ::c_int; + + pub fn pthread_cond_init(cond: *mut pthread_cond_t, + attr: *const pthread_condattr_t) -> ::c_int; + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> ::c_int; + pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> ::c_int; + pub fn pthread_rwlock_init(lock: *mut pthread_rwlock_t, + attr: *const pthread_rwlockattr_t) -> ::c_int; + pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> ::c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) + -> ::c_int; + pub fn strerror_r(errnum: ::c_int, buf: *mut c_char, + buflen: ::size_t) -> ::c_int; + + pub fn getsockopt(sockfd: ::c_int, + level: ::c_int, + optname: ::c_int, + optval: *mut ::c_void, + optlen: *mut ::socklen_t) -> ::c_int; + pub fn raise(signum: ::c_int) -> ::c_int; + pub fn sigaction(signum: ::c_int, + act: *const sigaction, + oldact: *mut sigaction) -> ::c_int; + + pub fn utimes(filename: *const ::c_char, + times: *const ::timeval) -> ::c_int; + pub fn dlopen(filename: *const ::c_char, + flag: ::c_int) -> *mut ::c_void; + pub fn dlerror() -> *mut ::c_char; + pub fn dlsym(handle: *mut ::c_void, + symbol: *const ::c_char) -> *mut ::c_void; + pub fn dlclose(handle: *mut ::c_void) -> ::c_int; + pub fn dladdr(addr: *const ::c_void, info: *mut Dl_info) -> ::c_int; + + pub fn getaddrinfo(node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo) -> ::c_int; + pub fn freeaddrinfo(res: *mut addrinfo); + pub fn gai_strerror(errcode: ::c_int) -> *const ::c_char; + pub fn res_init() -> ::c_int; + + pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + pub fn mktime(tm: *mut tm) -> time_t; + pub fn time(time: *mut time_t) -> time_t; + pub fn gmtime(time_p: *const time_t) -> *mut tm; + pub fn localtime(time_p: *const time_t) -> *mut tm; + + pub fn mknod(pathname: *const ::c_char, mode: ::mode_t, + dev: ::dev_t) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; + pub fn gethostname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn getservbyname(name: *const ::c_char, + proto: *const ::c_char) -> *mut servent; + pub fn getprotobyname(name: *const ::c_char) -> *mut protoent; + pub fn getprotobynumber(proto: ::c_int) -> *mut protoent; + pub fn chroot(name: *const ::c_char) -> ::c_int; + pub fn usleep(secs: ::c_uint) -> ::c_int; + pub fn send(socket: ::c_int, buf: *const ::c_void, len: ::size_t, + flags: ::c_int) -> ::ssize_t; + pub fn recv(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int) -> ::ssize_t; + pub fn putenv(string: *mut c_char) -> ::c_int; + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: ::c_int) -> ::c_int; + pub fn select(nfds: ::c_int, + readfs: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval) -> ::c_int; + pub fn setlocale(category: ::c_int, + locale: *const ::c_char) -> *mut ::c_char; + pub fn localeconv() -> *mut lconv; + + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_wait(sem: *mut sem_t) -> ::c_int; + pub fn sem_trywait(sem: *mut sem_t) -> ::c_int; + pub fn sem_post(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + pub fn statvfs(path: *const c_char, buf: *mut statvfs) -> ::c_int; + pub fn fstatvfs(fd: ::c_int, buf: *mut statvfs) -> ::c_int; + + pub fn readlink(path: *const c_char, + buf: *mut c_char, + bufsz: ::size_t) + -> ::ssize_t; + + pub fn sigemptyset(set: *mut sigset_t) -> ::c_int; + pub fn sigaddset(set: *mut sigset_t, signum: ::c_int) -> ::c_int; + pub fn sigfillset(set: *mut sigset_t) -> ::c_int; + pub fn sigdelset(set: *mut sigset_t, signum: ::c_int) -> ::c_int; + pub fn sigismember(set: *const sigset_t, signum: ::c_int) -> ::c_int; + + pub fn sigprocmask(how: ::c_int, + set: *const sigset_t, + oldset: *mut sigset_t) + -> ::c_int; + pub fn sigpending(set: *mut sigset_t) -> ::c_int; + + pub fn timegm(tm: *mut ::tm) -> time_t; + + pub fn getsid(pid: pid_t) -> pid_t; + + pub fn sysconf(name: ::c_int) -> ::c_long; + + pub fn mkfifo(path: *const c_char, mode: mode_t) -> ::c_int; + + pub fn pselect(nfds: ::c_int, + readfs: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn fseeko(stream: *mut ::FILE, + offset: ::off_t, + whence: ::c_int) -> ::c_int; + pub fn ftello(stream: *mut ::FILE) -> ::off_t; + pub fn tcdrain(fd: ::c_int) -> ::c_int; + pub fn cfgetispeed(termios: *const ::termios) -> ::speed_t; + pub fn cfgetospeed(termios: *const ::termios) -> ::speed_t; + pub fn cfmakeraw(termios: *mut ::termios); + pub fn cfsetispeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int; + pub fn cfsetospeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int; + pub fn cfsetspeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int; + pub fn tcgetattr(fd: ::c_int, termios: *mut ::termios) -> ::c_int; + pub fn tcsetattr(fd: ::c_int, + optional_actions: ::c_int, + termios: *const ::termios) -> ::c_int; + pub fn tcflow(fd: ::c_int, action: ::c_int) -> ::c_int; + pub fn tcflush(fd: ::c_int, action: ::c_int) -> ::c_int; + pub fn tcgetsid(fd: ::c_int) -> ::pid_t; + pub fn tcsendbreak(fd: ::c_int, duration: ::c_int) -> ::c_int; + pub fn mkstemp(template: *mut ::c_char) -> ::c_int; + pub fn mkdtemp(template: *mut ::c_char) -> *mut ::c_char; + + pub fn tmpnam(ptr: *mut ::c_char) -> *mut ::c_char; + + pub fn openlog(ident: *const ::c_char, logopt: ::c_int, facility: ::c_int); + pub fn closelog(); + pub fn setlogmask(maskpri: ::c_int) -> ::c_int; + pub fn syslog(priority: ::c_int, message: *const ::c_char, ...); + pub fn nice(incr: ::c_int) -> ::c_int; + + pub fn grantpt(fd: ::c_int) -> ::c_int; + pub fn posix_openpt(flags: ::c_int) -> ::c_int; + pub fn ptsname(fd: ::c_int) -> *mut ::c_char; + pub fn unlockpt(fd: ::c_int) -> ::c_int; + + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn mincore(addr: *mut ::c_void, len: ::size_t, + vec: *mut ::c_uchar) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + + pub fn pthread_getattr_np(native: ::pthread_t, + attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + pub fn setgroups(ngroups: ::size_t, + ptr: *const ::gid_t) -> ::c_int; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn statfs64(path: *const ::c_char, buf: *mut statfs64) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + pub fn fstatfs64(fd: ::c_int, buf: *mut statfs64) -> ::c_int; + pub fn statvfs64(path: *const ::c_char, buf: *mut statvfs64) -> ::c_int; + pub fn fstatvfs64(fd: ::c_int, buf: *mut statvfs64) -> ::c_int; + pub fn memrchr(cx: *const ::c_void, + c: ::c_int, + n: ::size_t) -> *mut ::c_void; + + pub fn posix_fadvise(fd: ::c_int, offset: ::off_t, len: ::off_t, + advise: ::c_int) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn creat64(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fstat64(fildes: ::c_int, buf: *mut stat64) -> ::c_int; + pub fn fstatat64(dirfd: ::c_int, pathname: *const c_char, + buf: *mut stat64, flags: ::c_int) -> ::c_int; + pub fn ftruncate64(fd: ::c_int, length: off64_t) -> ::c_int; + pub fn getrlimit64(resource: ::c_int, rlim: *mut rlimit64) -> ::c_int; + pub fn lseek64(fd: ::c_int, offset: off64_t, whence: ::c_int) -> off64_t; + pub fn lstat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn mmap64(addr: *mut ::c_void, + len: ::size_t, + prot: ::c_int, + flags: ::c_int, + fd: ::c_int, + offset: off64_t) + -> *mut ::c_void; + pub fn open64(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn openat64(fd: ::c_int, + path: *const c_char, + oflag: ::c_int, ...) -> ::c_int; + pub fn pread64(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn preadv64(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off64_t) -> ::ssize_t; + pub fn pwrite64(fd: ::c_int, buf: *const ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn pwritev64(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off64_t) -> ::ssize_t; + pub fn readdir64(dirp: *mut ::DIR) -> *mut ::dirent64; + pub fn readdir64_r(dirp: *mut ::DIR, entry: *mut ::dirent64, + result: *mut *mut ::dirent64) -> ::c_int; + pub fn setrlimit64(resource: ::c_int, rlim: *const rlimit64) -> ::c_int; + pub fn stat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn truncate64(path: *const c_char, length: off64_t) -> ::c_int; + + pub fn fdopendir(fd: ::c_int) -> *mut ::DIR; + + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, + pshared: ::c_int) -> ::c_int; + pub fn accept4(fd: ::c_int, addr: *mut ::sockaddr, len: *mut ::socklen_t, + flg: ::c_int) -> ::c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn ptsname_r(fd: ::c_int, + buf: *mut ::c_char, + buflen: ::size_t) -> ::c_int; + pub fn clearenv() -> ::c_int; + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + pub fn setreuid(ruid: ::uid_t, euid: ::uid_t) -> ::c_int; + pub fn setregid(rgid: ::gid_t, egid: ::gid_t) -> ::c_int; + pub fn getresuid(ruid: *mut ::uid_t, euid: *mut ::uid_t, + suid: *mut ::uid_t) -> ::c_int; + pub fn getresgid(rgid: *mut ::gid_t, egid: *mut ::gid_t, + sgid: *mut ::gid_t) -> ::c_int; + pub fn acct(filename: *const ::c_char) -> ::c_int; + pub fn brk(addr: *mut ::c_void) -> ::c_int; + pub fn sbrk(increment: ::intptr_t) -> *mut ::c_void; + pub fn vfork() -> ::pid_t; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; + pub fn wait4(pid: ::pid_t, status: *mut ::c_int, options: ::c_int, + rusage: *mut ::rusage) -> ::pid_t; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *const termios, + winp: *const ::winsize) -> ::c_int; + pub fn execvpe(file: *const ::c_char, argv: *const *const ::c_char, + envp: *const *const ::c_char) -> ::c_int; + pub fn fexecve(fd: ::c_int, argv: *const *const ::c_char, + envp: *const *const ::c_char) + -> ::c_int; + + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; + pub fn ptrace(request: ::c_int, ...) -> ::c_long; + pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; + + pub fn aio_read(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_fsync(op: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_error(aiocbp: *const aiocb) -> ::c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ::ssize_t; + pub fn aio_suspend(aiocb_list: *const *const aiocb, nitems: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn aio_cancel(fd: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn lio_listio(mode: ::c_int, aiocb_list: *const *mut aiocb, + nitems: ::c_int, sevp: *mut ::sigevent) -> ::c_int; + + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setspent(); + pub fn endspent(); + pub fn getspent() -> *mut spwd; + pub fn getspnam(__name: *const ::c_char) -> *mut spwd; + + pub fn shm_open(name: *const c_char, oflag: ::c_int, + mode: mode_t) -> ::c_int; + + // System V IPC + pub fn shmget(key: ::key_t, size: ::size_t, shmflg: ::c_int) -> ::c_int; + pub fn shmat(shmid: ::c_int, + shmaddr: *const ::c_void, + shmflg: ::c_int) -> *mut ::c_void; + pub fn shmdt(shmaddr: *const ::c_void) -> ::c_int; + pub fn shmctl(shmid: ::c_int, + cmd: ::c_int, + buf: *mut ::shmid_ds) -> ::c_int; + pub fn ftok(pathname: *const ::c_char, proj_id: ::c_int) -> ::key_t; + pub fn semget(key: ::key_t, nsems: ::c_int, semflag: ::c_int) -> ::c_int; + pub fn semop(semid: ::c_int, + sops: *mut ::sembuf, nsops: ::size_t) -> ::c_int; + pub fn semctl(semid: ::c_int, + semnum: ::c_int, cmd: ::c_int, ...) -> ::c_int; + pub fn msgctl(msqid: ::c_int, cmd: ::c_int, buf: *mut msqid_ds) -> ::c_int; + pub fn msgget(key: ::key_t, msgflg: ::c_int) -> ::c_int; + pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t, + msgtyp: ::c_long, msgflg: ::c_int) -> ::ssize_t; + pub fn msgsnd(msqid: ::c_int, msgp: *const ::c_void, msgsz: ::size_t, + msgflg: ::c_int) -> ::c_int; + + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn __errno_location() -> *mut ::c_int; + + pub fn fopen64(filename: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn freopen64(filename: *const c_char, mode: *const c_char, + file: *mut ::FILE) -> *mut ::FILE; + pub fn tmpfile64() -> *mut ::FILE; + pub fn fgetpos64(stream: *mut ::FILE, ptr: *mut fpos64_t) -> ::c_int; + pub fn fsetpos64(stream: *mut ::FILE, ptr: *const fpos64_t) -> ::c_int; + pub fn fseeko64(stream: *mut ::FILE, + offset: ::off64_t, + whence: ::c_int) -> ::c_int; + pub fn ftello64(stream: *mut ::FILE) -> ::off64_t; + pub fn fallocate(fd: ::c_int, mode: ::c_int, + offset: ::off_t, len: ::off_t) -> ::c_int; + pub fn posix_fallocate(fd: ::c_int, offset: ::off_t, + len: ::off_t) -> ::c_int; + pub fn readahead(fd: ::c_int, offset: ::off64_t, + count: ::size_t) -> ::ssize_t; + pub fn getxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn lgetxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn fgetxattr(filedes: ::c_int, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn setxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn lsetxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn fsetxattr(filedes: ::c_int, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn flistxattr(filedes: ::c_int, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn fremovexattr(filedes: ::c_int, name: *const c_char) -> ::c_int; + pub fn signalfd(fd: ::c_int, + mask: *const ::sigset_t, + flags: ::c_int) -> ::c_int; + pub fn timerfd_create(clockid: ::c_int, flags: ::c_int) -> ::c_int; + pub fn timerfd_gettime(fd: ::c_int, + curr_value: *mut itimerspec) -> ::c_int; + pub fn timerfd_settime(fd: ::c_int, + flags: ::c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec) -> ::c_int; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn quotactl(cmd: ::c_int, + special: *const ::c_char, + id: ::c_int, + data: *mut ::c_char) -> ::c_int; + pub fn mq_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::mqd_t; + pub fn mq_close(mqd: ::mqd_t) -> ::c_int; + pub fn mq_unlink(name: *const ::c_char) -> ::c_int; + pub fn mq_receive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint) -> ::ssize_t; + pub fn mq_send(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint) -> ::c_int; + pub fn mq_getattr(mqd: ::mqd_t, attr: *mut ::mq_attr) -> ::c_int; + pub fn mq_setattr(mqd: ::mqd_t, + newattr: *const ::mq_attr, + oldattr: *mut ::mq_attr) -> ::c_int; + pub fn epoll_pwait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int, + sigmask: *const ::sigset_t) -> ::c_int; + pub fn dup3(oldfd: ::c_int, newfd: ::c_int, flags: ::c_int) -> ::c_int; + pub fn mkostemp(template: *mut ::c_char, flags: ::c_int) -> ::c_int; + pub fn mkostemps(template: *mut ::c_char, + suffixlen: ::c_int, + flags: ::c_int) -> ::c_int; + pub fn sigtimedwait(set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const ::timespec) -> ::c_int; + pub fn sigwaitinfo(set: *const sigset_t, + info: *mut siginfo_t) -> ::c_int; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn pthread_setschedprio(native: ::pthread_t, + priority: ::c_int) -> ::c_int; + pub fn prlimit(pid: ::pid_t, resource: ::c_int, new_limit: *const ::rlimit, + old_limit: *mut ::rlimit) -> ::c_int; + pub fn prlimit64(pid: ::pid_t, + resource: ::c_int, + new_limit: *const ::rlimit64, + old_limit: *mut ::rlimit64) -> ::c_int; + pub fn getloadavg(loadavg: *mut ::c_double, nelem: ::c_int) -> ::c_int; + pub fn process_vm_readv(pid: ::pid_t, + local_iov: *const ::iovec, + liovcnt: ::c_ulong, + remote_iov: *const ::iovec, + riovcnt: ::c_ulong, + flags: ::c_ulong) -> isize; + pub fn process_vm_writev(pid: ::pid_t, + local_iov: *const ::iovec, + liovcnt: ::c_ulong, + remote_iov: *const ::iovec, + riovcnt: ::c_ulong, + flags: ::c_ulong) -> isize; + pub fn reboot(how_to: ::c_int) -> ::c_int; + pub fn setfsgid(gid: ::gid_t) -> ::c_int; + pub fn setfsuid(uid: ::uid_t) -> ::c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn sync_file_range(fd: ::c_int, offset: ::off64_t, + nbytes: ::off64_t, flags: ::c_uint) -> ::c_int; + pub fn getifaddrs(ifap: *mut *mut ::ifaddrs) -> ::c_int; + pub fn freeifaddrs(ifa: *mut ::ifaddrs); + + pub fn mremap(addr: *mut ::c_void, + len: ::size_t, + new_len: ::size_t, + flags: ::c_int, + ...) -> *mut ::c_void; + + pub fn glob(pattern: *const c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + pub fn futimes(fd: ::c_int, times: *const ::timeval) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + pub fn getdomainname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn vhangup() -> ::c_int; + pub fn sendmmsg(sockfd: ::c_int, msgvec: *mut mmsghdr, vlen: ::c_uint, + flags: ::c_int) -> ::c_int; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut mmsghdr, vlen: ::c_uint, + flags: ::c_int, timeout: *mut ::timespec) -> ::c_int; + pub fn sync(); + pub fn syscall(num: ::c_long, ...) -> ::c_long; + pub fn sched_getaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *mut cpu_set_t) -> ::c_int; + pub fn sched_setaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *const cpu_set_t) -> ::c_int; + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + pub fn pthread_getschedparam(native: ::pthread_t, + policy: *mut ::c_int, + param: *mut ::sched_param) -> ::c_int; + pub fn unshare(flags: ::c_int) -> ::c_int; + pub fn umount(target: *const ::c_char) -> ::c_int; + pub fn sched_get_priority_max(policy: ::c_int) -> ::c_int; + pub fn tee(fd_in: ::c_int, + fd_out: ::c_int, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn settimeofday(tv: *const ::timeval, tz: *const ::timezone) -> ::c_int; + pub fn splice(fd_in: ::c_int, + off_in: *mut ::loff_t, + fd_out: ::c_int, + off_out: *mut ::loff_t, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int; + pub fn sched_rr_get_interval(pid: ::pid_t, tp: *mut ::timespec) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn sched_setparam(pid: ::pid_t, param: *const ::sched_param) -> ::c_int; + pub fn setns(fd: ::c_int, nstype: ::c_int) -> ::c_int; + pub fn swapoff(puath: *const ::c_char) -> ::c_int; + pub fn vmsplice(fd: ::c_int, + iov: *const ::iovec, + nr_segs: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + fstype: *const ::c_char, + flags: ::c_ulong, + data: *const ::c_void) -> ::c_int; + pub fn personality(persona: ::c_ulong) -> ::c_int; + pub fn prctl(option: ::c_int, ...) -> ::c_int; + pub fn sched_getparam(pid: ::pid_t, param: *mut ::sched_param) -> ::c_int; + pub fn ppoll(fds: *mut ::pollfd, + nfds: nfds_t, + timeout: *const ::timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn clone(cb: extern fn(*mut ::c_void) -> ::c_int, + child_stack: *mut ::c_void, + flags: ::c_int, + arg: *mut ::c_void, ...) -> ::c_int; + pub fn sched_getscheduler(pid: ::pid_t) -> ::c_int; + pub fn clock_nanosleep(clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn sched_get_priority_min(policy: ::c_int) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn sysinfo(info: *mut ::sysinfo) -> ::c_int; + pub fn umount2(target: *const ::c_char, flags: ::c_int) -> ::c_int; + pub fn pthread_setschedparam(native: ::pthread_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn swapon(path: *const ::c_char, swapflags: ::c_int) -> ::c_int; + pub fn sched_setscheduler(pid: ::pid_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn sendfile(out_fd: ::c_int, + in_fd: ::c_int, + offset: *mut off_t, + count: ::size_t) -> ::ssize_t; + pub fn sigsuspend(mask: *const ::sigset_t) -> ::c_int; + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + pub fn initgroups(user: *const ::c_char, group: ::gid_t) -> ::c_int; + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_cancel(thread: ::pthread_t) -> ::c_int; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + pub fn getgrouplist(user: *const ::c_char, + group: ::gid_t, + groups: *mut ::gid_t, + ngroups: *mut ::c_int) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn faccessat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::c_int, flags: ::c_int) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn dl_iterate_phdr( + callback: ::Option ::c_int>, + data: *mut ::c_void + ) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} +expand_align!(); + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} diff --git a/libc/src/fuchsia/no_align.rs b/libc/src/fuchsia/no_align.rs new file mode 100644 index 000000000..437da97ee --- /dev/null +++ b/libc/src/fuchsia/no_align.rs @@ -0,0 +1,129 @@ +macro_rules! expand_align { + () => { + s! { + pub struct pthread_mutexattr_t { + #[cfg(target_arch = "x86_64")] + __align: [::c_int; 0], + #[cfg(not(target_arch = "x86_64"))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_rwlockattr_t { + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + pub struct pthread_condattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + pub struct pthread_mutex_t { + #[cfg(any(target_arch = "arm", + all(target_arch = "x86_64", + target_pointer_width = "32")))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "arm", + all(target_arch = "x86_64", + target_pointer_width = "32"))))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_rwlock_t { + __align: [::c_long; 0], + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + pub struct pthread_cond_t { + __align: [*const ::c_void; 0], + #[cfg(not(target_env = "musl"))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + // Ignore __align field + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_cond_t {} + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + // Ignore __align field + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + // Ignore __align field + self.size.hash(state); + } + } + + impl PartialEq for pthread_mutex_t { + fn eq(&self, other: &pthread_mutex_t) -> bool { + // Ignore __align field + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_mutex_t {} + impl ::fmt::Debug for pthread_mutex_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_mutex_t") + // Ignore __align field + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_mutex_t { + fn hash(&self, state: &mut H) { + // Ignore __align field + self.size.hash(state); + } + } + + impl PartialEq for pthread_rwlock_t { + fn eq(&self, other: &pthread_rwlock_t) -> bool { + // Ignore __align field + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_rwlock_t {} + impl ::fmt::Debug for pthread_rwlock_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_rwlock_t") + // Ignore __align field + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_rwlock_t { + fn hash(&self, state: &mut H) { + // Ignore __align field + self.size.hash(state); + } + } + } + } + } +} diff --git a/libc/src/fuchsia/x86_64.rs b/libc/src/fuchsia/x86_64.rs new file mode 100644 index 000000000..eb220998e --- /dev/null +++ b/libc/src/fuchsia/x86_64.rs @@ -0,0 +1,491 @@ +pub type c_char = i8; +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = ::c_long; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __reserved: [::c_long; 3], + } + + pub struct mcontext_t { + __private: [u64; 32], + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } +} + +s_no_extra_traits! { + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + __private: [u8; 512], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for ucontext_t { + fn eq(&self, other: &ucontext_t) -> bool { + self.uc_flags == other.uc_flags + && self.uc_link == other.uc_link + && self.uc_stack == other.uc_stack + && self.uc_mcontext == other.uc_mcontext + && self.uc_sigmask == other.uc_sigmask + && self + .__private + .iter() + .zip(other.__private.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for ucontext_t {} + impl ::fmt::Debug for ucontext_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ucontext_t") + .field("uc_flags", &self.uc_flags) + .field("uc_link", &self.uc_link) + .field("uc_stack", &self.uc_stack) + .field("uc_mcontext", &self.uc_mcontext) + .field("uc_sigmask", &self.uc_sigmask) + // FIXME: .field("__private", &self.__private) + .finish() + } + } + impl ::hash::Hash for ucontext_t { + fn hash(&self, state: &mut H) { + self.uc_flags.hash(state); + self.uc_link.hash(state); + self.uc_stack.hash(state); + self.uc_mcontext.hash(state); + self.uc_sigmask.hash(state); + self.__private.hash(state); + } + } + } +} + +// Syscall table + +pub const SYS_read: ::c_long = 0; +pub const SYS_write: ::c_long = 1; +pub const SYS_open: ::c_long = 2; +pub const SYS_close: ::c_long = 3; +pub const SYS_stat: ::c_long = 4; +pub const SYS_fstat: ::c_long = 5; +pub const SYS_lstat: ::c_long = 6; +pub const SYS_poll: ::c_long = 7; +pub const SYS_lseek: ::c_long = 8; +pub const SYS_mmap: ::c_long = 9; +pub const SYS_mprotect: ::c_long = 10; +pub const SYS_munmap: ::c_long = 11; +pub const SYS_brk: ::c_long = 12; +pub const SYS_rt_sigaction: ::c_long = 13; +pub const SYS_rt_sigprocmask: ::c_long = 14; +pub const SYS_rt_sigreturn: ::c_long = 15; +pub const SYS_ioctl: ::c_long = 16; +pub const SYS_pread64: ::c_long = 17; +pub const SYS_pwrite64: ::c_long = 18; +pub const SYS_readv: ::c_long = 19; +pub const SYS_writev: ::c_long = 20; +pub const SYS_access: ::c_long = 21; +pub const SYS_pipe: ::c_long = 22; +pub const SYS_select: ::c_long = 23; +pub const SYS_sched_yield: ::c_long = 24; +pub const SYS_mremap: ::c_long = 25; +pub const SYS_msync: ::c_long = 26; +pub const SYS_mincore: ::c_long = 27; +pub const SYS_madvise: ::c_long = 28; +pub const SYS_shmget: ::c_long = 29; +pub const SYS_shmat: ::c_long = 30; +pub const SYS_shmctl: ::c_long = 31; +pub const SYS_dup: ::c_long = 32; +pub const SYS_dup2: ::c_long = 33; +pub const SYS_pause: ::c_long = 34; +pub const SYS_nanosleep: ::c_long = 35; +pub const SYS_getitimer: ::c_long = 36; +pub const SYS_alarm: ::c_long = 37; +pub const SYS_setitimer: ::c_long = 38; +pub const SYS_getpid: ::c_long = 39; +pub const SYS_sendfile: ::c_long = 40; +pub const SYS_socket: ::c_long = 41; +pub const SYS_connect: ::c_long = 42; +pub const SYS_accept: ::c_long = 43; +pub const SYS_sendto: ::c_long = 44; +pub const SYS_recvfrom: ::c_long = 45; +pub const SYS_sendmsg: ::c_long = 46; +pub const SYS_recvmsg: ::c_long = 47; +pub const SYS_shutdown: ::c_long = 48; +pub const SYS_bind: ::c_long = 49; +pub const SYS_listen: ::c_long = 50; +pub const SYS_getsockname: ::c_long = 51; +pub const SYS_getpeername: ::c_long = 52; +pub const SYS_socketpair: ::c_long = 53; +pub const SYS_setsockopt: ::c_long = 54; +pub const SYS_getsockopt: ::c_long = 55; +pub const SYS_clone: ::c_long = 56; +pub const SYS_fork: ::c_long = 57; +pub const SYS_vfork: ::c_long = 58; +pub const SYS_execve: ::c_long = 59; +pub const SYS_exit: ::c_long = 60; +pub const SYS_wait4: ::c_long = 61; +pub const SYS_kill: ::c_long = 62; +pub const SYS_uname: ::c_long = 63; +pub const SYS_semget: ::c_long = 64; +pub const SYS_semop: ::c_long = 65; +pub const SYS_semctl: ::c_long = 66; +pub const SYS_shmdt: ::c_long = 67; +pub const SYS_msgget: ::c_long = 68; +pub const SYS_msgsnd: ::c_long = 69; +pub const SYS_msgrcv: ::c_long = 70; +pub const SYS_msgctl: ::c_long = 71; +pub const SYS_fcntl: ::c_long = 72; +pub const SYS_flock: ::c_long = 73; +pub const SYS_fsync: ::c_long = 74; +pub const SYS_fdatasync: ::c_long = 75; +pub const SYS_truncate: ::c_long = 76; +pub const SYS_ftruncate: ::c_long = 77; +pub const SYS_getdents: ::c_long = 78; +pub const SYS_getcwd: ::c_long = 79; +pub const SYS_chdir: ::c_long = 80; +pub const SYS_fchdir: ::c_long = 81; +pub const SYS_rename: ::c_long = 82; +pub const SYS_mkdir: ::c_long = 83; +pub const SYS_rmdir: ::c_long = 84; +pub const SYS_creat: ::c_long = 85; +pub const SYS_link: ::c_long = 86; +pub const SYS_unlink: ::c_long = 87; +pub const SYS_symlink: ::c_long = 88; +pub const SYS_readlink: ::c_long = 89; +pub const SYS_chmod: ::c_long = 90; +pub const SYS_fchmod: ::c_long = 91; +pub const SYS_chown: ::c_long = 92; +pub const SYS_fchown: ::c_long = 93; +pub const SYS_lchown: ::c_long = 94; +pub const SYS_umask: ::c_long = 95; +pub const SYS_gettimeofday: ::c_long = 96; +pub const SYS_getrlimit: ::c_long = 97; +pub const SYS_getrusage: ::c_long = 98; +pub const SYS_sysinfo: ::c_long = 99; +pub const SYS_times: ::c_long = 100; +pub const SYS_ptrace: ::c_long = 101; +pub const SYS_getuid: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_getgid: ::c_long = 104; +pub const SYS_setuid: ::c_long = 105; +pub const SYS_setgid: ::c_long = 106; +pub const SYS_geteuid: ::c_long = 107; +pub const SYS_getegid: ::c_long = 108; +pub const SYS_setpgid: ::c_long = 109; +pub const SYS_getppid: ::c_long = 110; +pub const SYS_getpgrp: ::c_long = 111; +pub const SYS_setsid: ::c_long = 112; +pub const SYS_setreuid: ::c_long = 113; +pub const SYS_setregid: ::c_long = 114; +pub const SYS_getgroups: ::c_long = 115; +pub const SYS_setgroups: ::c_long = 116; +pub const SYS_setresuid: ::c_long = 117; +pub const SYS_getresuid: ::c_long = 118; +pub const SYS_setresgid: ::c_long = 119; +pub const SYS_getresgid: ::c_long = 120; +pub const SYS_getpgid: ::c_long = 121; +pub const SYS_setfsuid: ::c_long = 122; +pub const SYS_setfsgid: ::c_long = 123; +pub const SYS_getsid: ::c_long = 124; +pub const SYS_capget: ::c_long = 125; +pub const SYS_capset: ::c_long = 126; +pub const SYS_rt_sigpending: ::c_long = 127; +pub const SYS_rt_sigtimedwait: ::c_long = 128; +pub const SYS_rt_sigqueueinfo: ::c_long = 129; +pub const SYS_rt_sigsuspend: ::c_long = 130; +pub const SYS_sigaltstack: ::c_long = 131; +pub const SYS_utime: ::c_long = 132; +pub const SYS_mknod: ::c_long = 133; +pub const SYS_uselib: ::c_long = 134; +pub const SYS_personality: ::c_long = 135; +pub const SYS_ustat: ::c_long = 136; +pub const SYS_statfs: ::c_long = 137; +pub const SYS_fstatfs: ::c_long = 138; +pub const SYS_sysfs: ::c_long = 139; +pub const SYS_getpriority: ::c_long = 140; +pub const SYS_setpriority: ::c_long = 141; +pub const SYS_sched_setparam: ::c_long = 142; +pub const SYS_sched_getparam: ::c_long = 143; +pub const SYS_sched_setscheduler: ::c_long = 144; +pub const SYS_sched_getscheduler: ::c_long = 145; +pub const SYS_sched_get_priority_max: ::c_long = 146; +pub const SYS_sched_get_priority_min: ::c_long = 147; +pub const SYS_sched_rr_get_interval: ::c_long = 148; +pub const SYS_mlock: ::c_long = 149; +pub const SYS_munlock: ::c_long = 150; +pub const SYS_mlockall: ::c_long = 151; +pub const SYS_munlockall: ::c_long = 152; +pub const SYS_vhangup: ::c_long = 153; +pub const SYS_modify_ldt: ::c_long = 154; +pub const SYS_pivot_root: ::c_long = 155; +pub const SYS__sysctl: ::c_long = 156; +pub const SYS_prctl: ::c_long = 157; +pub const SYS_arch_prctl: ::c_long = 158; +pub const SYS_adjtimex: ::c_long = 159; +pub const SYS_setrlimit: ::c_long = 160; +pub const SYS_chroot: ::c_long = 161; +pub const SYS_sync: ::c_long = 162; +pub const SYS_acct: ::c_long = 163; +pub const SYS_settimeofday: ::c_long = 164; +pub const SYS_mount: ::c_long = 165; +pub const SYS_umount2: ::c_long = 166; +pub const SYS_swapon: ::c_long = 167; +pub const SYS_swapoff: ::c_long = 168; +pub const SYS_reboot: ::c_long = 169; +pub const SYS_sethostname: ::c_long = 170; +pub const SYS_setdomainname: ::c_long = 171; +pub const SYS_iopl: ::c_long = 172; +pub const SYS_ioperm: ::c_long = 173; +pub const SYS_create_module: ::c_long = 174; +pub const SYS_init_module: ::c_long = 175; +pub const SYS_delete_module: ::c_long = 176; +pub const SYS_get_kernel_syms: ::c_long = 177; +pub const SYS_query_module: ::c_long = 178; +pub const SYS_quotactl: ::c_long = 179; +pub const SYS_nfsservctl: ::c_long = 180; +pub const SYS_getpmsg: ::c_long = 181; +pub const SYS_putpmsg: ::c_long = 182; +pub const SYS_afs_syscall: ::c_long = 183; +pub const SYS_tuxcall: ::c_long = 184; +pub const SYS_security: ::c_long = 185; +pub const SYS_gettid: ::c_long = 186; +pub const SYS_readahead: ::c_long = 187; +pub const SYS_setxattr: ::c_long = 188; +pub const SYS_lsetxattr: ::c_long = 189; +pub const SYS_fsetxattr: ::c_long = 190; +pub const SYS_getxattr: ::c_long = 191; +pub const SYS_lgetxattr: ::c_long = 192; +pub const SYS_fgetxattr: ::c_long = 193; +pub const SYS_listxattr: ::c_long = 194; +pub const SYS_llistxattr: ::c_long = 195; +pub const SYS_flistxattr: ::c_long = 196; +pub const SYS_removexattr: ::c_long = 197; +pub const SYS_lremovexattr: ::c_long = 198; +pub const SYS_fremovexattr: ::c_long = 199; +pub const SYS_tkill: ::c_long = 200; +pub const SYS_time: ::c_long = 201; +pub const SYS_futex: ::c_long = 202; +pub const SYS_sched_setaffinity: ::c_long = 203; +pub const SYS_sched_getaffinity: ::c_long = 204; +pub const SYS_set_thread_area: ::c_long = 205; +pub const SYS_io_setup: ::c_long = 206; +pub const SYS_io_destroy: ::c_long = 207; +pub const SYS_io_getevents: ::c_long = 208; +pub const SYS_io_submit: ::c_long = 209; +pub const SYS_io_cancel: ::c_long = 210; +pub const SYS_get_thread_area: ::c_long = 211; +pub const SYS_lookup_dcookie: ::c_long = 212; +pub const SYS_epoll_create: ::c_long = 213; +pub const SYS_epoll_ctl_old: ::c_long = 214; +pub const SYS_epoll_wait_old: ::c_long = 215; +pub const SYS_remap_file_pages: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_set_tid_address: ::c_long = 218; +pub const SYS_restart_syscall: ::c_long = 219; +pub const SYS_semtimedop: ::c_long = 220; +pub const SYS_fadvise64: ::c_long = 221; +pub const SYS_timer_create: ::c_long = 222; +pub const SYS_timer_settime: ::c_long = 223; +pub const SYS_timer_gettime: ::c_long = 224; +pub const SYS_timer_getoverrun: ::c_long = 225; +pub const SYS_timer_delete: ::c_long = 226; +pub const SYS_clock_settime: ::c_long = 227; +pub const SYS_clock_gettime: ::c_long = 228; +pub const SYS_clock_getres: ::c_long = 229; +pub const SYS_clock_nanosleep: ::c_long = 230; +pub const SYS_exit_group: ::c_long = 231; +pub const SYS_epoll_wait: ::c_long = 232; +pub const SYS_epoll_ctl: ::c_long = 233; +pub const SYS_tgkill: ::c_long = 234; +pub const SYS_utimes: ::c_long = 235; +pub const SYS_vserver: ::c_long = 236; +pub const SYS_mbind: ::c_long = 237; +pub const SYS_set_mempolicy: ::c_long = 238; +pub const SYS_get_mempolicy: ::c_long = 239; +pub const SYS_mq_open: ::c_long = 240; +pub const SYS_mq_unlink: ::c_long = 241; +pub const SYS_mq_timedsend: ::c_long = 242; +pub const SYS_mq_timedreceive: ::c_long = 243; +pub const SYS_mq_notify: ::c_long = 244; +pub const SYS_mq_getsetattr: ::c_long = 245; +pub const SYS_kexec_load: ::c_long = 246; +pub const SYS_waitid: ::c_long = 247; +pub const SYS_add_key: ::c_long = 248; +pub const SYS_request_key: ::c_long = 249; +pub const SYS_keyctl: ::c_long = 250; +pub const SYS_ioprio_set: ::c_long = 251; +pub const SYS_ioprio_get: ::c_long = 252; +pub const SYS_inotify_init: ::c_long = 253; +pub const SYS_inotify_add_watch: ::c_long = 254; +pub const SYS_inotify_rm_watch: ::c_long = 255; +pub const SYS_migrate_pages: ::c_long = 256; +pub const SYS_openat: ::c_long = 257; +pub const SYS_mkdirat: ::c_long = 258; +pub const SYS_mknodat: ::c_long = 259; +pub const SYS_fchownat: ::c_long = 260; +pub const SYS_futimesat: ::c_long = 261; +pub const SYS_newfstatat: ::c_long = 262; +pub const SYS_unlinkat: ::c_long = 263; +pub const SYS_renameat: ::c_long = 264; +pub const SYS_linkat: ::c_long = 265; +pub const SYS_symlinkat: ::c_long = 266; +pub const SYS_readlinkat: ::c_long = 267; +pub const SYS_fchmodat: ::c_long = 268; +pub const SYS_faccessat: ::c_long = 269; +pub const SYS_pselect6: ::c_long = 270; +pub const SYS_ppoll: ::c_long = 271; +pub const SYS_unshare: ::c_long = 272; +pub const SYS_set_robust_list: ::c_long = 273; +pub const SYS_get_robust_list: ::c_long = 274; +pub const SYS_splice: ::c_long = 275; +pub const SYS_tee: ::c_long = 276; +pub const SYS_sync_file_range: ::c_long = 277; +pub const SYS_vmsplice: ::c_long = 278; +pub const SYS_move_pages: ::c_long = 279; +pub const SYS_utimensat: ::c_long = 280; +pub const SYS_epoll_pwait: ::c_long = 281; +pub const SYS_signalfd: ::c_long = 282; +pub const SYS_timerfd_create: ::c_long = 283; +pub const SYS_eventfd: ::c_long = 284; +pub const SYS_fallocate: ::c_long = 285; +pub const SYS_timerfd_settime: ::c_long = 286; +pub const SYS_timerfd_gettime: ::c_long = 287; +pub const SYS_accept4: ::c_long = 288; +pub const SYS_signalfd4: ::c_long = 289; +pub const SYS_eventfd2: ::c_long = 290; +pub const SYS_epoll_create1: ::c_long = 291; +pub const SYS_dup3: ::c_long = 292; +pub const SYS_pipe2: ::c_long = 293; +pub const SYS_inotify_init1: ::c_long = 294; +pub const SYS_preadv: ::c_long = 295; +pub const SYS_pwritev: ::c_long = 296; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 297; +pub const SYS_perf_event_open: ::c_long = 298; +pub const SYS_recvmmsg: ::c_long = 299; +pub const SYS_fanotify_init: ::c_long = 300; +pub const SYS_fanotify_mark: ::c_long = 301; +pub const SYS_prlimit64: ::c_long = 302; +pub const SYS_name_to_handle_at: ::c_long = 303; +pub const SYS_open_by_handle_at: ::c_long = 304; +pub const SYS_clock_adjtime: ::c_long = 305; +pub const SYS_syncfs: ::c_long = 306; +pub const SYS_sendmmsg: ::c_long = 307; +pub const SYS_setns: ::c_long = 308; +pub const SYS_getcpu: ::c_long = 309; +pub const SYS_process_vm_readv: ::c_long = 310; +pub const SYS_process_vm_writev: ::c_long = 311; +pub const SYS_kcmp: ::c_long = 312; +pub const SYS_finit_module: ::c_long = 313; +pub const SYS_sched_setattr: ::c_long = 314; +pub const SYS_sched_getattr: ::c_long = 315; +pub const SYS_renameat2: ::c_long = 316; +pub const SYS_seccomp: ::c_long = 317; +pub const SYS_getrandom: ::c_long = 318; +pub const SYS_memfd_create: ::c_long = 319; +pub const SYS_kexec_file_load: ::c_long = 320; +pub const SYS_bpf: ::c_long = 321; +pub const SYS_execveat: ::c_long = 322; +pub const SYS_userfaultfd: ::c_long = 323; +pub const SYS_membarrier: ::c_long = 324; +pub const SYS_mlock2: ::c_long = 325; +pub const SYS_copy_file_range: ::c_long = 326; +pub const SYS_preadv2: ::c_long = 327; +pub const SYS_pwritev2: ::c_long = 328; +// FIXME syscalls 329-331 have been added in musl 1.16 +// See discussion https://github.com/rust-lang/libc/pull/699 + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: ::c_int = 0; +pub const R14: ::c_int = 1; +pub const R13: ::c_int = 2; +pub const R12: ::c_int = 3; +pub const RBP: ::c_int = 4; +pub const RBX: ::c_int = 5; +pub const R11: ::c_int = 6; +pub const R10: ::c_int = 7; +pub const R9: ::c_int = 8; +pub const R8: ::c_int = 9; +pub const RAX: ::c_int = 10; +pub const RCX: ::c_int = 11; +pub const RDX: ::c_int = 12; +pub const RSI: ::c_int = 13; +pub const RDI: ::c_int = 14; +pub const ORIG_RAX: ::c_int = 15; +pub const RIP: ::c_int = 16; +pub const CS: ::c_int = 17; +pub const EFLAGS: ::c_int = 18; +pub const RSP: ::c_int = 19; +pub const SS: ::c_int = 20; +pub const FS_BASE: ::c_int = 21; +pub const GS_BASE: ::c_int = 22; +pub const DS: ::c_int = 23; +pub const ES: ::c_int = 24; +pub const FS: ::c_int = 25; +pub const GS: ::c_int = 26; + +pub const MAP_32BIT: ::c_int = 0x0040; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; diff --git a/libc/src/hermit/aarch64.rs b/libc/src/hermit/aarch64.rs new file mode 100644 index 000000000..1a92e3b4f --- /dev/null +++ b/libc/src/hermit/aarch64.rs @@ -0,0 +1,2 @@ +pub type c_char = u8; +pub type wchar_t = u32; diff --git a/libc/src/hermit/mod.rs b/libc/src/hermit/mod.rs new file mode 100644 index 000000000..3e15175a5 --- /dev/null +++ b/libc/src/hermit/mod.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// libc port for HermitCore (https://hermitcore.org) +// +// Ported by Colin Fink +// and Stefan Lankes + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type c_long = i64; +pub type c_ulong = u64; + +pub type wint_t = u32; +pub type wctype_t = i64; + +pub type regoff_t = size_t; +pub type off_t = c_long; + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} diff --git a/libc/src/hermit/x86_64.rs b/libc/src/hermit/x86_64.rs new file mode 100644 index 000000000..76ec3ce82 --- /dev/null +++ b/libc/src/hermit/x86_64.rs @@ -0,0 +1,2 @@ +pub type c_char = i8; +pub type wchar_t = i32; diff --git a/libc/src/lib.rs b/libc/src/lib.rs new file mode 100644 index 000000000..baf632434 --- /dev/null +++ b/libc/src/lib.rs @@ -0,0 +1,119 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! libc - Raw FFI bindings to platforms' system libraries +//! +//! [Documentation for other platforms][pd]. +//! +//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation +#![crate_name = "libc"] +#![crate_type = "rlib"] +#![cfg_attr(not(feature = "rustc-dep-of-std"), deny(warnings))] +#![allow(bad_style, overflowing_literals, improper_ctypes, unknown_lints)] +// Attributes needed when building as part of the standard library +#![cfg_attr( + feature = "rustc-dep-of-std", + feature(cfg_target_vendor, link_cfg, no_core) +)] +// Enable extra lints: +#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))] +#![deny(missing_copy_implementations, safe_packed_borrows)] +#![no_std] +#![cfg_attr(feature = "rustc-dep-of-std", no_core)] +#![cfg_attr(target_os = "redox", feature(static_nobundle))] + +#[macro_use] +mod macros; + +cfg_if! { + if #[cfg(feature = "rustc-dep-of-std")] { + extern crate rustc_std_workspace_core as core; + #[allow(unused_imports)] + use core::iter; + #[allow(unused_imports)] + use core::option; + } +} + +cfg_if! { + if #[cfg(libc_priv_mod_use)] { + #[cfg(libc_core_cvoid)] + #[allow(unused_imports)] + use core::ffi; + #[allow(unused_imports)] + use core::fmt; + #[allow(unused_imports)] + use core::hash; + #[allow(unused_imports)] + use core::num; + #[allow(unused_imports)] + use core::mem; + #[doc(hidden)] + #[allow(unused_imports)] + use core::clone::Clone; + #[doc(hidden)] + #[allow(unused_imports)] + use core::marker::Copy; + #[doc(hidden)] + #[allow(unused_imports)] + use core::option::Option; + } else { + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::fmt; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::hash; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::num; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::mem; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::clone::Clone; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::marker::Copy; + #[doc(hidden)] + #[allow(unused_imports)] + pub use core::option::Option; + } +} + +cfg_if! { + if #[cfg(windows)] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "cloudabi")] { + mod cloudabi; + pub use cloudabi::*; + } else if #[cfg(target_os = "fuchsia")] { + mod fuchsia; + pub use fuchsia::*; + } else if #[cfg(target_os = "switch")] { + mod switch; + pub use switch::*; + } else if #[cfg(unix)] { + mod unix; + pub use unix::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] { + mod wasi; + pub use wasi::*; + } else { + // non-supported targets: empty... + } +} diff --git a/libc/src/macros.rs b/libc/src/macros.rs new file mode 100644 index 000000000..c48ae8bc4 --- /dev/null +++ b/libc/src/macros.rs @@ -0,0 +1,157 @@ +/// A macro for defining #[cfg] if-else statements. +/// +/// This is similar to the `if/elif` C preprocessor macro by allowing definition +/// of a cascade of `#[cfg]` cases, emitting the implementation which matches +/// first. +/// +/// This allows you to conveniently provide a long list #[cfg]'d blocks of code +/// without having to rewrite each clause multiple times. +#[allow(unused_macros)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), + $($rest:tt)*) => { + // Emit all items within one block, applying an approprate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +#[allow(unused_macros)] +macro_rules! s { + ($($(#[$attr:meta])* pub $t:ident $i:ident { $($field:tt)* })*) => ($( + s!(it: $(#[$attr])* pub $t $i { $($field)* }); + )*); + (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( + compile_error!("unions cannot derive extra traits, use s_no_extra_traits instead"); + ); + (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( + __item! { + #[repr(C)] + #[cfg_attr(feature = "extra_traits", derive(Debug, Eq, Hash, PartialEq))] + $(#[$attr])* + pub struct $i { $($field)* } + } + impl ::Copy for $i {} + impl ::Clone for $i { + fn clone(&self) -> $i { *self } + } + ); +} + +#[allow(unused_macros)] +macro_rules! s_no_extra_traits { + ($($(#[$attr:meta])* pub $t:ident $i:ident { $($field:tt)* })*) => ($( + s_no_extra_traits!(it: $(#[$attr])* pub $t $i { $($field)* }); + )*); + (it: $(#[$attr:meta])* pub union $i:ident { $($field:tt)* }) => ( + cfg_if! { + if #[cfg(libc_union)] { + __item! { + #[repr(C)] + $(#[$attr])* + pub union $i { $($field)* } + } + + impl ::Copy for $i {} + impl ::Clone for $i { + fn clone(&self) -> $i { *self } + } + } + } + ); + (it: $(#[$attr:meta])* pub struct $i:ident { $($field:tt)* }) => ( + __item! { + #[repr(C)] + $(#[$attr])* + pub struct $i { $($field)* } + } + impl ::Copy for $i {} + impl ::Clone for $i { + fn clone(&self) -> $i { *self } + } + ); +} + +#[allow(unused_macros)] +macro_rules! f { + ($(pub fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty { + $($body:stmt);* + })*) => ($( + #[inline] + pub unsafe extern fn $i($($arg: $argty),*) -> $ret { + $($body);* + } + )*) +} + +#[allow(unused_macros)] +macro_rules! __item { + ($i:item) => { + $i + }; +} + +#[allow(unused_macros)] +macro_rules! align_const { + ($($(#[$attr:meta])* + pub const $name:ident : $t1:ty + = $t2:ident { $($field:tt)* };)*) => ($( + #[cfg(libc_align)] + $(#[$attr])* + pub const $name : $t1 = $t2 { + $($field)* + }; + #[cfg(not(libc_align))] + $(#[$attr])* + pub const $name : $t1 = $t2 { + $($field)* + __align: [], + }; + )*) +} diff --git a/libc/src/sgx.rs b/libc/src/sgx.rs new file mode 100644 index 000000000..8a69ad36e --- /dev/null +++ b/libc/src/sgx.rs @@ -0,0 +1,56 @@ +//! SGX C types definition + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} diff --git a/libc/src/switch.rs b/libc/src/switch.rs new file mode 100644 index 000000000..06fa2030c --- /dev/null +++ b/libc/src/switch.rs @@ -0,0 +1,59 @@ +//! Switch C type definitions + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type off_t = i64; +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type wchar_t = u32; + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} + diff --git a/libc/src/unix/align.rs b/libc/src/unix/align.rs new file mode 100644 index 000000000..4fdba9a6a --- /dev/null +++ b/libc/src/unix/align.rs @@ -0,0 +1,6 @@ +s! { + #[repr(align(4))] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } +} diff --git a/libc/src/unix/bsd/apple/b32.rs b/libc/src/unix/bsd/apple/b32.rs new file mode 100644 index 000000000..13b1a0b7c --- /dev/null +++ b/libc/src/unix/bsd/apple/b32.rs @@ -0,0 +1,97 @@ +//! 32-bit specific Apple (ios/darwin) definitions + +pub type c_long = i32; +pub type c_ulong = u32; +pub type boolean_t = ::c_int; + +s! { + pub struct if_data { + pub ifi_type: ::c_uchar, + pub ifi_typelen: ::c_uchar, + pub ifi_physical: ::c_uchar, + pub ifi_addrlen: ::c_uchar, + pub ifi_hdrlen: ::c_uchar, + pub ifi_recvquota: ::c_uchar, + pub ifi_xmitquota: ::c_uchar, + pub ifi_unused1: ::c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_baudrate: u32, + pub ifi_ipackets: u32, + pub ifi_ierrors: u32, + pub ifi_opackets: u32, + pub ifi_oerrors: u32, + pub ifi_collisions: u32, + pub ifi_ibytes: u32, + pub ifi_obytes: u32, + pub ifi_imcasts: u32, + pub ifi_omcasts: u32, + pub ifi_iqdrops: u32, + pub ifi_noproto: u32, + pub ifi_recvtiming: u32, + pub ifi_xmittiming: u32, + pub ifi_lastchange: ::timeval, + pub ifi_unused2: u32, + pub ifi_hwassist: u32, + pub ifi_reserved1: u32, + pub ifi_reserved2: u32, + } + + pub struct bpf_hdr { + pub bh_tstamp: ::timeval, + pub bh_caplen: ::uint32_t, + pub bh_datalen: ::uint32_t, + pub bh_hdrlen: ::c_ushort, + } +} + +s_no_extra_traits!{ + pub struct pthread_attr_t { + __sig: c_long, + __opaque: [::c_char; 36] + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_attr_t { + fn eq(&self, other: &pthread_attr_t) -> bool { + self.__sig == other.__sig + && self.__opaque + .iter() + .zip(other.__opaque.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_attr_t {} + impl ::fmt::Debug for pthread_attr_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_attr_t") + .field("__sig", &self.__sig) + // FIXME: .field("__opaque", &self.__opaque) + .finish() + } + } + impl ::hash::Hash for pthread_attr_t { + fn hash(&self, state: &mut H) { + self.__sig.hash(state); + self.__opaque.hash(state); + } + } + } +} + +pub const __PTHREAD_MUTEX_SIZE__: usize = 40; +pub const __PTHREAD_COND_SIZE__: usize = 24; +pub const __PTHREAD_CONDATTR_SIZE__: usize = 4; +pub const __PTHREAD_RWLOCK_SIZE__: usize = 124; +pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 12; + +pub const TIOCTIMESTAMP: ::c_ulong = 0x40087459; +pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40087458; + +extern { + pub fn exchangedata(path1: *const ::c_char, + path2: *const ::c_char, + options: ::c_ulong) -> ::c_int; +} diff --git a/libc/src/unix/bsd/apple/b64.rs b/libc/src/unix/bsd/apple/b64.rs new file mode 100644 index 000000000..50b48fa5e --- /dev/null +++ b/libc/src/unix/bsd/apple/b64.rs @@ -0,0 +1,102 @@ +//! 64-bit specific Apple (ios/darwin) definitions + +pub type c_long = i64; +pub type c_ulong = u64; +pub type boolean_t = ::c_uint; + +s! { + pub struct timeval32 { + pub tv_sec: i32, + pub tv_usec: i32, + } + + pub struct if_data { + pub ifi_type: ::c_uchar, + pub ifi_typelen: ::c_uchar, + pub ifi_physical: ::c_uchar, + pub ifi_addrlen: ::c_uchar, + pub ifi_hdrlen: ::c_uchar, + pub ifi_recvquota: ::c_uchar, + pub ifi_xmitquota: ::c_uchar, + pub ifi_unused1: ::c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_baudrate: u32, + pub ifi_ipackets: u32, + pub ifi_ierrors: u32, + pub ifi_opackets: u32, + pub ifi_oerrors: u32, + pub ifi_collisions: u32, + pub ifi_ibytes: u32, + pub ifi_obytes: u32, + pub ifi_imcasts: u32, + pub ifi_omcasts: u32, + pub ifi_iqdrops: u32, + pub ifi_noproto: u32, + pub ifi_recvtiming: u32, + pub ifi_xmittiming: u32, + pub ifi_lastchange: timeval32, + pub ifi_unused2: u32, + pub ifi_hwassist: u32, + pub ifi_reserved1: u32, + pub ifi_reserved2: u32, + } + + pub struct bpf_hdr { + pub bh_tstamp: ::timeval32, + pub bh_caplen: ::uint32_t, + pub bh_datalen: ::uint32_t, + pub bh_hdrlen: ::c_ushort, + } +} + +s_no_extra_traits!{ + pub struct pthread_attr_t { + __sig: c_long, + __opaque: [::c_char; 56] + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_attr_t { + fn eq(&self, other: &pthread_attr_t) -> bool { + self.__sig == other.__sig + && self.__opaque + .iter() + .zip(other.__opaque.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_attr_t {} + impl ::fmt::Debug for pthread_attr_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_attr_t") + .field("__sig", &self.__sig) + // FIXME: .field("__opaque", &self.__opaque) + .finish() + } + } + impl ::hash::Hash for pthread_attr_t { + fn hash(&self, state: &mut H) { + self.__sig.hash(state); + self.__opaque.hash(state); + } + } + } +} + +pub const __PTHREAD_MUTEX_SIZE__: usize = 56; +pub const __PTHREAD_COND_SIZE__: usize = 40; +pub const __PTHREAD_CONDATTR_SIZE__: usize = 8; +pub const __PTHREAD_RWLOCK_SIZE__: usize = 192; +pub const __PTHREAD_RWLOCKATTR_SIZE__: usize = 16; + +pub const TIOCTIMESTAMP: ::c_ulong = 0x40107459; +pub const TIOCDCDTIMESTAMP: ::c_ulong = 0x40107458; + +extern { + pub fn exchangedata(path1: *const ::c_char, + path2: *const ::c_char, + options: ::c_uint) -> ::c_int; +} diff --git a/libc/src/unix/bsd/apple/mod.rs b/libc/src/unix/bsd/apple/mod.rs new file mode 100644 index 000000000..9483e90b6 --- /dev/null +++ b/libc/src/unix/bsd/apple/mod.rs @@ -0,0 +1,3294 @@ +//! Apple (ios/darwin)-specific definitions +//! +//! This covers *-apple-* triples currently +pub type c_char = i8; +pub type clock_t = c_ulong; +pub type time_t = c_long; +pub type suseconds_t = i32; +pub type dev_t = i32; +pub type ino_t = u64; +pub type mode_t = u16; +pub type nlink_t = u16; +pub type blksize_t = i32; +pub type rlim_t = u64; +pub type mach_timebase_info_data_t = mach_timebase_info; +pub type pthread_key_t = c_ulong; +pub type sigset_t = u32; +pub type clockid_t = ::c_uint; +pub type fsblkcnt_t = ::c_uint; +pub type fsfilcnt_t = ::c_uint; +pub type speed_t = ::c_ulong; +pub type tcflag_t = ::c_ulong; +pub type nl_item = ::c_int; +pub type id_t = ::c_uint; +pub type sem_t = ::c_int; +pub type idtype_t = ::c_uint; +pub type integer_t = ::c_int; +pub type cpu_type_t = integer_t; +pub type cpu_subtype_t = integer_t; +pub type vm_prot_t = ::c_int; +pub type posix_spawnattr_t = *mut ::c_void; +pub type posix_spawn_file_actions_t = *mut ::c_void; +pub type key_t = ::c_int; +pub type shmatt_t = ::c_ushort; +pub type vm_size_t = ::uintptr_t; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_offset: ::off_t, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_reqprio: ::c_int, + pub aio_sigevent: sigevent, + pub aio_lio_opcode: ::c_int + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + __unused1: ::c_int, + pub gl_offs: ::size_t, + __unused2: ::c_int, + pub gl_pathv: *mut *mut ::c_char, + + __unused3: *mut ::c_void, + + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + __unused8: *mut ::c_void, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct mach_timebase_info { + pub numer: u32, + pub denom: u32, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: ino_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: dev_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_birthtime: time_t, + pub st_birthtime_nsec: c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: ::uint32_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_qspare: [::int64_t; 2], + } + + pub struct pthread_mutexattr_t { + __sig: ::c_long, + __opaque: [u8; 8], + } + + pub struct pthread_condattr_t { + __sig: ::c_long, + __opaque: [u8; __PTHREAD_CONDATTR_SIZE__], + } + + pub struct pthread_rwlockattr_t { + __sig: ::c_long, + __opaque: [u8; __PTHREAD_RWLOCKATTR_SIZE__], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub si_pid: ::pid_t, + pub si_uid: ::uid_t, + pub si_status: ::c_int, + pub si_addr: *mut ::c_void, + _pad: [usize; 9], + } + + pub struct sigaction { + // FIXME: this field is actually a union + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + pub sa_flags: ::c_int, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct fstore_t { + pub fst_flags: ::c_uint, + pub fst_posmode: ::c_int, + pub fst_offset: ::off_t, + pub fst_length: ::off_t, + pub fst_bytesalloc: ::off_t, + } + + pub struct radvisory { + pub ra_offset: ::off_t, + pub ra_count: ::c_int, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::c_char; 8], + } + + pub struct kevent64_s { + pub ident: ::uint64_t, + pub filter: ::int16_t, + pub flags: ::uint16_t, + pub fflags: ::uint32_t, + pub data: ::int64_t, + pub udata: ::uint64_t, + pub ext: [::uint64_t; 2], + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint64_t, + pub dqb_bsoftlimit: ::uint64_t, + pub dqb_curbytes: ::uint64_t, + pub dqb_ihardlimit: ::uint32_t, + pub dqb_isoftlimit: ::uint32_t, + pub dqb_curinodes: ::uint32_t, + pub dqb_btime: ::uint32_t, + pub dqb_itime: ::uint32_t, + pub dqb_id: ::uint32_t, + pub dqb_spare: [::uint32_t; 4], + } + + pub struct if_msghdr { + pub ifm_msglen: ::c_ushort, + pub ifm_version: ::c_uchar, + pub ifm_type: ::c_uchar, + pub ifm_addrs: ::c_int, + pub ifm_flags: ::c_int, + pub ifm_index: ::c_ushort, + pub ifm_data: if_data, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + pub l_type: ::c_short, + pub l_whence: ::c_short, + } + + pub struct sf_hdtr { + pub headers: *mut ::iovec, + pub hdr_cnt: ::c_int, + pub trailers: *mut ::iovec, + pub trl_cnt: ::c_int, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + __unused1: *mut ::c_void, //actually a function pointer + pub sigev_notify_attributes: *mut ::pthread_attr_t + } + + pub struct proc_taskinfo { + pub pti_virtual_size: u64, + pub pti_resident_size: u64, + pub pti_total_user: u64, + pub pti_total_system: u64, + pub pti_threads_user: u64, + pub pti_threads_system: u64, + pub pti_policy: i32, + pub pti_faults: i32, + pub pti_pageins: i32, + pub pti_cow_faults: i32, + pub pti_messages_sent: i32, + pub pti_messages_received: i32, + pub pti_syscalls_mach: i32, + pub pti_syscalls_unix: i32, + pub pti_csw: i32, + pub pti_threadnum: i32, + pub pti_numrunning: i32, + pub pti_priority: i32, + } + + pub struct proc_bsdinfo { + pub pbi_flags: u32, + pub pbi_status: u32, + pub pbi_xstatus: u32, + pub pbi_pid: u32, + pub pbi_ppid: u32, + pub pbi_uid: ::uid_t, + pub pbi_gid: ::gid_t, + pub pbi_ruid: ::uid_t, + pub pbi_rgid: ::gid_t, + pub pbi_svuid: ::uid_t, + pub pbi_svgid: ::gid_t, + pub rfu_1: u32, + pub pbi_comm: [::c_char; MAXCOMLEN], + pub pbi_name: [::c_char; 32], // MAXCOMLEN * 2, but macro isn't happy... + pub pbi_nfiles: u32, + pub pbi_pgid: u32, + pub pbi_pjobc: u32, + pub e_tdev: u32, + pub e_tpgid: u32, + pub pbi_nice: i32, + pub pbi_start_tvsec: u64, + pub pbi_start_tvusec: u64, + } + + pub struct proc_taskallinfo { + pub pbsd: proc_bsdinfo, + pub ptinfo: proc_taskinfo, + } + + pub struct xsw_usage { + pub xsu_total: u64, + pub xsu_avail: u64, + pub xsu_used: u64, + pub xsu_pagesize: u32, + pub xsu_encrypted: ::boolean_t, + } + + pub struct xucred { + pub cr_version: ::c_uint, + pub cr_uid: ::uid_t, + pub cr_ngroups: ::c_short, + pub cr_groups: [::gid_t;16] + } + + pub struct mach_header { + pub magic: u32, + pub cputype: cpu_type_t, + pub cpusubtype: cpu_subtype_t, + pub filetype: u32, + pub ncmds: u32, + pub sizeofcmds: u32, + pub flags: u32, + } + + pub struct mach_header_64 { + pub magic: u32, + pub cputype: cpu_type_t, + pub cpusubtype: cpu_subtype_t, + pub filetype: u32, + pub ncmds: u32, + pub sizeofcmds: u32, + pub flags: u32, + pub reserved: u32, + } + + pub struct segment_command { + pub cmd: u32, + pub cmdsize: u32, + pub segname: [::c_char; 16], + pub vmaddr: u32, + pub vmsize: u32, + pub fileoff: u32, + pub filesize: u32, + pub maxprot: vm_prot_t, + pub initprot: vm_prot_t, + pub nsects: u32, + pub flags: u32, + } + + pub struct segment_command_64 { + pub cmd: u32, + pub cmdsize: u32, + pub segname: [::c_char; 16], + pub vmaddr: u64, + pub vmsize: u64, + pub fileoff: u64, + pub filesize: u64, + pub maxprot: vm_prot_t, + pub initprot: vm_prot_t, + pub nsects: u32, + pub flags: u32, + } + + pub struct load_command { + pub cmd: u32, + pub cmdsize: u32, + } + + pub struct sockaddr_dl { + pub sdl_len: ::c_uchar, + pub sdl_family: ::c_uchar, + pub sdl_index: ::c_ushort, + pub sdl_type: ::c_uchar, + pub sdl_nlen: ::c_uchar, + pub sdl_alen: ::c_uchar, + pub sdl_slen: ::c_uchar, + pub sdl_data: [::c_char; 12], + } + + pub struct sockaddr_inarp { + pub sin_len: ::c_uchar, + pub sin_family: ::c_uchar, + pub sin_port: ::c_ushort, + pub sin_addr: ::in_addr, + pub sin_srcaddr: ::in_addr, + pub sin_tos: ::c_ushort, + pub sin_other: ::c_ushort, + } + + pub struct sockaddr_ctl { + pub sc_len: ::c_uchar, + pub sc_family: ::c_uchar, + pub ss_sysaddr: ::uint16_t, + pub sc_id: ::uint32_t, + pub sc_unit: ::uint32_t, + pub sc_reserved: [::uint32_t; 5], + } + + pub struct in_pktinfo { + pub ipi_ifindex: ::c_uint, + pub ipi_spec_dst: ::in_addr, + pub ipi_addr: ::in_addr, + } + + pub struct in6_pktinfo { + pub ipi6_addr: ::in6_addr, + pub ipi6_ifindex: ::c_uint, + } + + // sys/ipc.h: + + pub struct ipc_perm { + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub _seq: ::c_ushort, + pub _key: ::key_t, + } + + // sys/sem.h + + pub struct sembuf { + pub sem_num: ::c_ushort, + pub sem_op: ::c_short, + pub sem_flg: ::c_short, + } + + // sys/shm.h + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct in_addr { + pub s_addr: ::in_addr_t, + } +} + +s_no_extra_traits!{ + #[cfg_attr(libc_packedN, repr(packed(4)))] + pub struct kevent { + pub ident: ::uintptr_t, + pub filter: ::int16_t, + pub flags: ::uint16_t, + pub fflags: ::uint32_t, + pub data: ::intptr_t, + pub udata: *mut ::c_void, + } + + #[cfg_attr(libc_packedN, repr(packed(4)))] + pub struct semid_ds { + // Note the manpage shows different types than the system header. + pub sem_perm: ipc_perm, + pub sem_base: ::int32_t, + pub sem_nsems: ::c_ushort, + pub sem_otime: ::time_t, + pub sem_pad1: ::int32_t, + pub sem_ctime: ::time_t, + pub sem_pad2: ::int32_t, + pub sem_pad3: [::int32_t; 4], + } + + #[cfg_attr(libc_packedN, repr(packed(4)))] + pub struct shmid_ds { + pub shm_perm: ipc_perm, + pub shm_segsz: ::size_t, + pub shm_lpid: ::pid_t, + pub shm_cpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + pub shm_atime: ::time_t, // FIXME: 64-bit wrong align => wrong offset + pub shm_dtime: ::time_t, // FIXME: 64-bit wrong align => wrong offset + pub shm_ctime: ::time_t, // FIXME: 64-bit wrong align => wrong offset + // FIXME: 64-bit wrong align => wrong offset: + pub shm_internal: *mut ::c_void, + } + + pub struct proc_threadinfo { + pub pth_user_time: u64, + pub pth_system_time: u64, + pub pth_cpu_usage: i32, + pub pth_policy: i32, + pub pth_run_state: i32, + pub pth_flags: i32, + pub pth_sleep_time: i32, + pub pth_curpri: i32, + pub pth_priority: i32, + pub pth_maxpriority: i32, + pub pth_name: [::c_char; MAXTHREADNAMESIZE], + } + + pub struct statfs { + pub f_bsize: ::uint32_t, + pub f_iosize: ::int32_t, + pub f_blocks: ::uint64_t, + pub f_bfree: ::uint64_t, + pub f_bavail: ::uint64_t, + pub f_files: ::uint64_t, + pub f_ffree: ::uint64_t, + pub f_fsid: ::fsid_t, + pub f_owner: ::uid_t, + pub f_type: ::uint32_t, + pub f_flags: ::uint32_t, + pub f_fssubtype: ::uint32_t, + pub f_fstypename: [::c_char; 16], + pub f_mntonname: [::c_char; 1024], + pub f_mntfromname: [::c_char; 1024], + pub f_reserved: [::uint32_t; 8], + } + + pub struct dirent { + pub d_ino: u64, + pub d_seekoff: u64, + pub d_reclen: u16, + pub d_namlen: u16, + pub d_type: u8, + pub d_name: [::c_char; 1024], + } + + pub struct pthread_rwlock_t { + __sig: ::c_long, + __opaque: [u8; __PTHREAD_RWLOCK_SIZE__], + } + + pub struct pthread_mutex_t { + __sig: ::c_long, + __opaque: [u8; __PTHREAD_MUTEX_SIZE__], + } + + pub struct pthread_cond_t { + __sig: ::c_long, + __opaque: [u8; __PTHREAD_COND_SIZE__], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: ::sa_family_t, + __ss_pad1: [u8; 6], + __ss_align: i64, + __ss_pad2: [u8; 112], + } + + pub struct utmpx { + pub ut_user: [::c_char; _UTX_USERSIZE], + pub ut_id: [::c_char; _UTX_IDSIZE], + pub ut_line: [::c_char; _UTX_LINESIZE], + pub ut_pid: ::pid_t, + pub ut_type: ::c_short, + pub ut_tv: ::timeval, + pub ut_host: [::c_char; _UTX_HOSTSIZE], + ut_pad: [::uint32_t; 16], + } +} + +cfg_if! { + if #[cfg(libc_union)] { + s_no_extra_traits! { + pub union semun { + pub val: ::c_int, + pub buf: *mut semid_ds, + pub array: *mut ::c_ushort, + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for semun { + fn eq(&self, other: &semun) -> bool { + unsafe { self.val == other.val } + } + } + impl Eq for semun {} + impl ::fmt::Debug for semun { + fn fmt(&self, f: &mut ::fmt::Formatter) + -> ::fmt::Result { + f.debug_struct("semun") + .field("val", unsafe { &self.val }) + .finish() + } + } + impl ::hash::Hash for semun { + fn hash(&self, state: &mut H) { + unsafe { self.val.hash(state) }; + } + } + } + } + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for kevent { + fn eq(&self, other: &kevent) -> bool { + self.ident == other.ident + && self.filter == other.filter + && self.flags == other.flags + && self.fflags == other.fflags + && self.data == other.data + && self.udata == other.udata + } + } + impl Eq for kevent {} + impl ::fmt::Debug for kevent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let ident = self.ident; + let filter = self.filter; + let flags = self.flags; + let fflags = self.fflags; + let data = self.data; + let udata = self.udata; + f.debug_struct("kevent") + .field("ident", &ident) + .field("filter", &filter) + .field("flags", &flags) + .field("fflags", &fflags) + .field("data", &data) + .field("udata", &udata) + .finish() + } + } + impl ::hash::Hash for kevent { + fn hash(&self, state: &mut H) { + let ident = self.ident; + let filter = self.filter; + let flags = self.flags; + let fflags = self.fflags; + let data = self.data; + let udata = self.udata; + ident.hash(state); + filter.hash(state); + flags.hash(state); + fflags.hash(state); + data.hash(state); + udata.hash(state); + } + } + + impl PartialEq for semid_ds { + fn eq(&self, other: &semid_ds) -> bool { + let sem_perm = self.sem_perm; + let sem_pad3 = self.sem_pad3; + let other_sem_perm = other.sem_perm; + let other_sem_pad3 = other.sem_pad3; + sem_perm == other_sem_perm + && self.sem_base == other.sem_base + && self.sem_nsems == other.sem_nsems + && self.sem_otime == other.sem_otime + && self.sem_pad1 == other.sem_pad1 + && self.sem_ctime == other.sem_ctime + && self.sem_pad2 == other.sem_pad2 + && sem_pad3 == other_sem_pad3 + } + } + impl Eq for semid_ds {} + impl ::fmt::Debug for semid_ds { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let sem_perm = self.sem_perm; + let sem_base = self.sem_base; + let sem_nsems = self.sem_nsems; + let sem_otime = self.sem_otime; + let sem_pad1 = self.sem_pad1; + let sem_ctime = self.sem_ctime; + let sem_pad2 = self.sem_pad2; + let sem_pad3 = self.sem_pad3; + f.debug_struct("semid_ds") + .field("sem_perm", &sem_perm) + .field("sem_base", &sem_base) + .field("sem_nsems", &sem_nsems) + .field("sem_otime", &sem_otime) + .field("sem_pad1", &sem_pad1) + .field("sem_ctime", &sem_ctime) + .field("sem_pad2", &sem_pad2) + .field("sem_pad3", &sem_pad3) + .finish() + } + } + impl ::hash::Hash for semid_ds { + fn hash(&self, state: &mut H) { + let sem_perm = self.sem_perm; + let sem_base = self.sem_base; + let sem_nsems = self.sem_nsems; + let sem_otime = self.sem_otime; + let sem_pad1 = self.sem_pad1; + let sem_ctime = self.sem_ctime; + let sem_pad2 = self.sem_pad2; + let sem_pad3 = self.sem_pad3; + sem_perm.hash(state); + sem_base.hash(state); + sem_nsems.hash(state); + sem_otime.hash(state); + sem_pad1.hash(state); + sem_ctime.hash(state); + sem_pad2.hash(state); + sem_pad3.hash(state); + } + } + + impl PartialEq for shmid_ds { + fn eq(&self, other: &shmid_ds) -> bool { + let shm_perm = self.shm_perm; + let other_shm_perm = other.shm_perm; + shm_perm == other_shm_perm + && self.shm_segsz == other.shm_segsz + && self.shm_lpid == other.shm_lpid + && self.shm_cpid == other.shm_cpid + && self.shm_nattch == other.shm_nattch + && self.shm_atime == other.shm_atime + && self.shm_dtime == other.shm_dtime + && self.shm_ctime == other.shm_ctime + && self.shm_internal == other.shm_internal + } + } + impl Eq for shmid_ds {} + impl ::fmt::Debug for shmid_ds { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let shm_perm = self.shm_perm; + let shm_segsz = self.shm_segsz; + let shm_lpid = self.shm_lpid; + let shm_cpid = self.shm_cpid; + let shm_nattch = self.shm_nattch; + let shm_atime = self.shm_atime; + let shm_dtime = self.shm_dtime; + let shm_ctime = self.shm_ctime; + let shm_internal = self.shm_internal; + f.debug_struct("shmid_ds") + .field("shm_perm", &shm_perm) + .field("shm_segsz", &shm_segsz) + .field("shm_lpid", &shm_lpid) + .field("shm_cpid", &shm_cpid) + .field("shm_nattch", &shm_nattch) + .field("shm_atime", &shm_atime) + .field("shm_dtime", &shm_dtime) + .field("shm_ctime", &shm_ctime) + .field("shm_internal", &shm_internal) + .finish() + } + } + impl ::hash::Hash for shmid_ds { + fn hash(&self, state: &mut H) { + let shm_perm = self.shm_perm; + let shm_segsz = self.shm_segsz; + let shm_lpid = self.shm_lpid; + let shm_cpid = self.shm_cpid; + let shm_nattch = self.shm_nattch; + let shm_atime = self.shm_atime; + let shm_dtime = self.shm_dtime; + let shm_ctime = self.shm_ctime; + let shm_internal = self.shm_internal; + shm_perm.hash(state); + shm_segsz.hash(state); + shm_lpid.hash(state); + shm_cpid.hash(state); + shm_nattch.hash(state); + shm_atime.hash(state); + shm_dtime.hash(state); + shm_ctime.hash(state); + shm_internal.hash(state); + } + } + + impl PartialEq for proc_threadinfo { + fn eq(&self, other: &proc_threadinfo) -> bool { + self.pth_user_time == other.pth_user_time + && self.pth_system_time == other.pth_system_time + && self.pth_cpu_usage == other.pth_cpu_usage + && self.pth_policy == other.pth_policy + && self.pth_run_state == other.pth_run_state + && self.pth_flags == other.pth_flags + && self.pth_sleep_time == other.pth_sleep_time + && self.pth_curpri == other.pth_curpri + && self.pth_priority == other.pth_priority + && self.pth_maxpriority == other.pth_maxpriority + && self.pth_name + .iter() + .zip(other.pth_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for proc_threadinfo {} + impl ::fmt::Debug for proc_threadinfo { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("proc_threadinfo") + .field("pth_user_time", &self.pth_user_time) + .field("pth_system_time", &self.pth_system_time) + .field("pth_cpu_usage", &self.pth_cpu_usage) + .field("pth_policy", &self.pth_policy) + .field("pth_run_state", &self.pth_run_state) + .field("pth_flags", &self.pth_flags) + .field("pth_sleep_time", &self.pth_sleep_time) + .field("pth_curpri", &self.pth_curpri) + .field("pth_priority", &self.pth_priority) + .field("pth_maxpriority", &self.pth_maxpriority) + // FIXME: .field("pth_name", &self.pth_name) + .finish() + } + } + impl ::hash::Hash for proc_threadinfo { + fn hash(&self, state: &mut H) { + self.pth_user_time.hash(state); + self.pth_system_time.hash(state); + self.pth_cpu_usage.hash(state); + self.pth_policy.hash(state); + self.pth_run_state.hash(state); + self.pth_flags.hash(state); + self.pth_sleep_time.hash(state); + self.pth_curpri.hash(state); + self.pth_priority.hash(state); + self.pth_maxpriority.hash(state); + self.pth_name.hash(state); + } + } + + impl PartialEq for statfs { + fn eq(&self, other: &statfs) -> bool { + self.f_bsize == other.f_bsize + && self.f_iosize == other.f_iosize + && self.f_blocks == other.f_blocks + && self.f_bfree == other.f_bfree + && self.f_bavail == other.f_bavail + && self.f_files == other.f_files + && self.f_ffree == other.f_ffree + && self.f_fsid == other.f_fsid + && self.f_owner == other.f_owner + && self.f_flags == other.f_flags + && self.f_fssubtype == other.f_fssubtype + && self.f_fstypename == other.f_fstypename + && self.f_type == other.f_type + && self + .f_mntonname + .iter() + .zip(other.f_mntonname.iter()) + .all(|(a,b)| a == b) + && self + .f_mntfromname + .iter() + .zip(other.f_mntfromname.iter()) + .all(|(a,b)| a == b) + && self.f_reserved == other.f_reserved + } + } + + impl Eq for statfs {} + impl ::fmt::Debug for statfs { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("statfs") + .field("f_bsize", &self.f_bsize) + .field("f_iosize", &self.f_iosize) + .field("f_blocks", &self.f_blocks) + .field("f_bfree", &self.f_bfree) + .field("f_bavail", &self.f_bavail) + .field("f_files", &self.f_files) + .field("f_ffree", &self.f_ffree) + .field("f_fsid", &self.f_fsid) + .field("f_owner", &self.f_owner) + .field("f_flags", &self.f_flags) + .field("f_fssubtype", &self.f_fssubtype) + .field("f_fstypename", &self.f_fstypename) + .field("f_type", &self.f_type) + // FIXME: .field("f_mntonname", &self.f_mntonname) + // FIXME: .field("f_mntfromname", &self.f_mntfromname) + .field("f_reserved", &self.f_reserved) + .finish() + } + } + + impl ::hash::Hash for statfs { + fn hash(&self, state: &mut H) { + self.f_bsize.hash(state); + self.f_iosize.hash(state); + self.f_blocks.hash(state); + self.f_bfree.hash(state); + self.f_bavail.hash(state); + self.f_files.hash(state); + self.f_ffree.hash(state); + self.f_fsid.hash(state); + self.f_owner.hash(state); + self.f_flags.hash(state); + self.f_fssubtype.hash(state); + self.f_fstypename.hash(state); + self.f_type.hash(state); + self.f_mntonname.hash(state); + self.f_mntfromname.hash(state); + self.f_reserved.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_seekoff == other.d_seekoff + && self.d_reclen == other.d_reclen + && self.d_namlen == other.d_namlen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_seekoff", &self.d_seekoff) + .field("d_reclen", &self.d_reclen) + .field("d_namlen", &self.d_namlen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_seekoff.hash(state); + self.d_reclen.hash(state); + self.d_namlen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + impl PartialEq for pthread_rwlock_t { + fn eq(&self, other: &pthread_rwlock_t) -> bool { + self.__sig == other.__sig + && self. + __opaque + .iter() + .zip(other.__opaque.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_rwlock_t {} + impl ::fmt::Debug for pthread_rwlock_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_rwlock_t") + .field("__sig", &self.__sig) + // FIXME: .field("__opaque", &self.__opaque) + .finish() + } + } + impl ::hash::Hash for pthread_rwlock_t { + fn hash(&self, state: &mut H) { + self.__sig.hash(state); + self.__opaque.hash(state); + } + } + + impl PartialEq for pthread_mutex_t { + fn eq(&self, other: &pthread_mutex_t) -> bool { + self.__sig == other.__sig + && self. + __opaque + .iter() + .zip(other.__opaque.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for pthread_mutex_t {} + + impl ::fmt::Debug for pthread_mutex_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_mutex_t") + .field("__sig", &self.__sig) + // FIXME: .field("__opaque", &self.__opaque) + .finish() + } + } + + impl ::hash::Hash for pthread_mutex_t { + fn hash(&self, state: &mut H) { + self.__sig.hash(state); + self.__opaque.hash(state); + } + } + + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.__sig == other.__sig + && self. + __opaque + .iter() + .zip(other.__opaque.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for pthread_cond_t {} + + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + .field("__sig", &self.__sig) + // FIXME: .field("__opaque", &self.__opaque) + .finish() + } + } + + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.__sig.hash(state); + self.__opaque.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_len == other.ss_len + && self.ss_family == other.ss_family + && self + .__ss_pad1 + .iter() + .zip(other.__ss_pad1.iter()) + .all(|(a, b)| a == b) + && self.__ss_align == other.__ss_align + && self + .__ss_pad2 + .iter() + .zip(other.__ss_pad2.iter()) + .all(|(a, b)| a == b) + } + } + + impl Eq for sockaddr_storage {} + + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_len", &self.ss_len) + .field("ss_family", &self.ss_family) + .field("__ss_pad1", &self.__ss_pad1) + .field("__ss_align", &self.__ss_align) + // FIXME: .field("__ss_pad2", &self.__ss_pad2) + .finish() + } + } + + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_len.hash(state); + self.ss_family.hash(state); + self.__ss_pad1.hash(state); + self.__ss_align.hash(state); + self.__ss_pad2.hash(state); + } + } + + impl PartialEq for utmpx { + fn eq(&self, other: &utmpx) -> bool { + self.ut_user + .iter() + .zip(other.ut_user.iter()) + .all(|(a,b)| a == b) + && self.ut_id == other.ut_id + && self.ut_line == other.ut_line + && self.ut_pid == other.ut_pid + && self.ut_type == other.ut_type + && self.ut_tv == other.ut_tv + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + && self.ut_pad == other.ut_pad + } + } + + impl Eq for utmpx {} + + impl ::fmt::Debug for utmpx { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmpx") + // FIXME: .field("ut_user", &self.ut_user) + .field("ut_id", &self.ut_id) + .field("ut_line", &self.ut_line) + .field("ut_pid", &self.ut_pid) + .field("ut_type", &self.ut_type) + .field("ut_tv", &self.ut_tv) + // FIXME: .field("ut_host", &self.ut_host) + .field("ut_pad", &self.ut_pad) + .finish() + } + } + + impl ::hash::Hash for utmpx { + fn hash(&self, state: &mut H) { + self.ut_user.hash(state); + self.ut_id.hash(state); + self.ut_line.hash(state); + self.ut_pid.hash(state); + self.ut_type.hash(state); + self.ut_tv.hash(state); + self.ut_host.hash(state); + self.ut_pad.hash(state); + } + } + } +} + +pub const _UTX_USERSIZE: usize = 256; +pub const _UTX_LINESIZE: usize = 32; +pub const _UTX_IDSIZE: usize = 4; +pub const _UTX_HOSTSIZE: usize = 256; + +pub const EMPTY: ::c_short = 0; +pub const RUN_LVL: ::c_short = 1; +pub const BOOT_TIME: ::c_short = 2; +pub const OLD_TIME: ::c_short = 3; +pub const NEW_TIME: ::c_short = 4; +pub const INIT_PROCESS: ::c_short = 5; +pub const LOGIN_PROCESS: ::c_short = 6; +pub const USER_PROCESS: ::c_short = 7; +pub const DEAD_PROCESS: ::c_short = 8; +pub const ACCOUNTING: ::c_short = 9; +pub const SIGNATURE: ::c_short = 10; +pub const SHUTDOWN_TIME: ::c_short = 11; + +pub const LC_COLLATE_MASK: ::c_int = (1 << 0); +pub const LC_CTYPE_MASK: ::c_int = (1 << 1); +pub const LC_MESSAGES_MASK: ::c_int = (1 << 2); +pub const LC_MONETARY_MASK: ::c_int = (1 << 3); +pub const LC_NUMERIC_MASK: ::c_int = (1 << 4); +pub const LC_TIME_MASK: ::c_int = (1 << 5); +pub const LC_ALL_MASK: ::c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const CODESET: ::nl_item = 0; +pub const D_T_FMT: ::nl_item = 1; +pub const D_FMT: ::nl_item = 2; +pub const T_FMT: ::nl_item = 3; +pub const T_FMT_AMPM: ::nl_item = 4; +pub const AM_STR: ::nl_item = 5; +pub const PM_STR: ::nl_item = 6; + +pub const DAY_1: ::nl_item = 7; +pub const DAY_2: ::nl_item = 8; +pub const DAY_3: ::nl_item = 9; +pub const DAY_4: ::nl_item = 10; +pub const DAY_5: ::nl_item = 11; +pub const DAY_6: ::nl_item = 12; +pub const DAY_7: ::nl_item = 13; + +pub const ABDAY_1: ::nl_item = 14; +pub const ABDAY_2: ::nl_item = 15; +pub const ABDAY_3: ::nl_item = 16; +pub const ABDAY_4: ::nl_item = 17; +pub const ABDAY_5: ::nl_item = 18; +pub const ABDAY_6: ::nl_item = 19; +pub const ABDAY_7: ::nl_item = 20; + +pub const MON_1: ::nl_item = 21; +pub const MON_2: ::nl_item = 22; +pub const MON_3: ::nl_item = 23; +pub const MON_4: ::nl_item = 24; +pub const MON_5: ::nl_item = 25; +pub const MON_6: ::nl_item = 26; +pub const MON_7: ::nl_item = 27; +pub const MON_8: ::nl_item = 28; +pub const MON_9: ::nl_item = 29; +pub const MON_10: ::nl_item = 30; +pub const MON_11: ::nl_item = 31; +pub const MON_12: ::nl_item = 32; + +pub const ABMON_1: ::nl_item = 33; +pub const ABMON_2: ::nl_item = 34; +pub const ABMON_3: ::nl_item = 35; +pub const ABMON_4: ::nl_item = 36; +pub const ABMON_5: ::nl_item = 37; +pub const ABMON_6: ::nl_item = 38; +pub const ABMON_7: ::nl_item = 39; +pub const ABMON_8: ::nl_item = 40; +pub const ABMON_9: ::nl_item = 41; +pub const ABMON_10: ::nl_item = 42; +pub const ABMON_11: ::nl_item = 43; +pub const ABMON_12: ::nl_item = 44; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_MONOTONIC: ::clockid_t = 6; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 12; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 16; + +pub const ERA: ::nl_item = 45; +pub const ERA_D_FMT: ::nl_item = 46; +pub const ERA_D_T_FMT: ::nl_item = 47; +pub const ERA_T_FMT: ::nl_item = 48; +pub const ALT_DIGITS: ::nl_item = 49; + +pub const RADIXCHAR: ::nl_item = 50; +pub const THOUSEP: ::nl_item = 51; + +pub const YESEXPR: ::nl_item = 52; +pub const NOEXPR: ::nl_item = 53; + +pub const YESSTR: ::nl_item = 54; +pub const NOSTR: ::nl_item = 55; + +pub const CRNCYSTR: ::nl_item = 56; + +pub const D_MD_ORDER: ::nl_item = 57; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 2147483647; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; +pub const BUFSIZ: ::c_uint = 1024; +pub const FOPEN_MAX: ::c_uint = 20; +pub const FILENAME_MAX: ::c_uint = 1024; +pub const L_tmpnam: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 308915776; +pub const _PC_LINK_MAX: ::c_int = 1; +pub const _PC_MAX_CANON: ::c_int = 2; +pub const _PC_MAX_INPUT: ::c_int = 3; +pub const _PC_NAME_MAX: ::c_int = 4; +pub const _PC_PATH_MAX: ::c_int = 5; +pub const _PC_PIPE_BUF: ::c_int = 6; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 7; +pub const _PC_NO_TRUNC: ::c_int = 8; +pub const _PC_VDISABLE: ::c_int = 9; +pub const O_DSYNC: ::c_int = 0x400000; +pub const O_NOCTTY: ::c_int = 0x20000; +pub const O_CLOEXEC: ::c_int = 0x1000000; +pub const O_DIRECTORY: ::c_int = 0x100000; +pub const S_IFIFO: mode_t = 4096; +pub const S_IFCHR: mode_t = 8192; +pub const S_IFBLK: mode_t = 24576; +pub const S_IFDIR: mode_t = 16384; +pub const S_IFREG: mode_t = 32768; +pub const S_IFLNK: mode_t = 40960; +pub const S_IFSOCK: mode_t = 49152; +pub const S_IFMT: mode_t = 61440; +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; +pub const S_IRWXU: mode_t = 448; +pub const S_IXUSR: mode_t = 64; +pub const S_IWUSR: mode_t = 128; +pub const S_IRUSR: mode_t = 256; +pub const S_IRWXG: mode_t = 56; +pub const S_IXGRP: mode_t = 8; +pub const S_IWGRP: mode_t = 16; +pub const S_IRGRP: mode_t = 32; +pub const S_IRWXO: mode_t = 7; +pub const S_IXOTH: mode_t = 1; +pub const S_IWOTH: mode_t = 2; +pub const S_IROTH: mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; +pub const F_GETLK: ::c_int = 7; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGEMT: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const PT_TRACE_ME: ::c_int = 0; +pub const PT_READ_I: ::c_int = 1; +pub const PT_READ_D: ::c_int = 2; +pub const PT_READ_U: ::c_int = 3; +pub const PT_WRITE_I: ::c_int = 4; +pub const PT_WRITE_D: ::c_int = 5; +pub const PT_WRITE_U: ::c_int = 6; +pub const PT_CONTINUE: ::c_int = 7; +pub const PT_KILL: ::c_int = 8; +pub const PT_STEP: ::c_int = 9; +pub const PT_ATTACH: ::c_int = 10; +pub const PT_DETACH: ::c_int = 11; +pub const PT_SIGEXC: ::c_int = 12; +pub const PT_THUPDATE: ::c_int = 13; +pub const PT_ATTACHEXC: ::c_int = 14; + +pub const PT_FORCEQUOTA: ::c_int = 30; +pub const PT_DENY_ATTACH: ::c_int = 31; +pub const PT_FIRSTMACH: ::c_int = 32; + +pub const MAP_FILE: ::c_int = 0x0000; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; +pub const MAP_ANON: ::c_int = 0x1000; +pub const MAP_ANONYMOUS: ::c_int = MAP_ANON; + +pub const VM_FLAGS_FIXED: ::c_int = 0x0000; +pub const VM_FLAGS_ANYWHERE: ::c_int = 0x0001; +pub const VM_FLAGS_PURGABLE: ::c_int = 0x0002; +pub const VM_FLAGS_RANDOM_ADDR: ::c_int = 0x0008; +pub const VM_FLAGS_NO_CACHE: ::c_int = 0x0010; +pub const VM_FLAGS_RESILIENT_CODESIGN: ::c_int = 0x0020; +pub const VM_FLAGS_RESILIENT_MEDIA: ::c_int = 0x0040; +pub const VM_FLAGS_OVERWRITE: ::c_int = 0x4000; +pub const VM_FLAGS_SUPERPAGE_MASK: ::c_int = 0x70000; +pub const VM_FLAGS_RETURN_DATA_ADDR: ::c_int = 0x100000; +pub const VM_FLAGS_RETURN_4K_DATA_ADDR: ::c_int = 0x800000; +pub const VM_FLAGS_ALIAS_MASK: ::c_int = 0xFF000000; +pub const VM_FLAGS_USER_ALLOCATE: ::c_int = 0xff07401f; +pub const VM_FLAGS_USER_MAP: ::c_int = 0xff97401f; +pub const VM_FLAGS_USER_REMAP: ::c_int = VM_FLAGS_FIXED | VM_FLAGS_ANYWHERE | + VM_FLAGS_RANDOM_ADDR | + VM_FLAGS_OVERWRITE | + VM_FLAGS_RETURN_DATA_ADDR | + VM_FLAGS_RESILIENT_CODESIGN; + +pub const VM_FLAGS_SUPERPAGE_SHIFT: ::c_int = 16; +pub const SUPERPAGE_NONE: ::c_int = 0; +pub const SUPERPAGE_SIZE_ANY: ::c_int = 1; +pub const VM_FLAGS_SUPERPAGE_NONE: ::c_int = SUPERPAGE_NONE << + VM_FLAGS_SUPERPAGE_SHIFT; +pub const VM_FLAGS_SUPERPAGE_SIZE_ANY: ::c_int = SUPERPAGE_SIZE_ANY << + VM_FLAGS_SUPERPAGE_SHIFT; +pub const SUPERPAGE_SIZE_2MB: ::c_int = 2; +pub const VM_FLAGS_SUPERPAGE_SIZE_2MB: ::c_int = SUPERPAGE_SIZE_2MB << + VM_FLAGS_SUPERPAGE_SHIFT; + +pub const VM_MEMORY_MALLOC: ::c_int = 1; +pub const VM_MEMORY_MALLOC_SMALL: ::c_int = 2; +pub const VM_MEMORY_MALLOC_LARGE: ::c_int = 3; +pub const VM_MEMORY_MALLOC_HUGE: ::c_int = 4; +pub const VM_MEMORY_SBRK: ::c_int = 5; +pub const VM_MEMORY_REALLOC: ::c_int = 6; +pub const VM_MEMORY_MALLOC_TINY: ::c_int = 7; +pub const VM_MEMORY_MALLOC_LARGE_REUSABLE: ::c_int = 8; +pub const VM_MEMORY_MALLOC_LARGE_REUSED: ::c_int = 9; +pub const VM_MEMORY_ANALYSIS_TOOL: ::c_int = 10; +pub const VM_MEMORY_MALLOC_NANO: ::c_int = 11; +pub const VM_MEMORY_MACH_MSG: ::c_int = 20; +pub const VM_MEMORY_IOKIT: ::c_int = 21; +pub const VM_MEMORY_STACK: ::c_int = 30; +pub const VM_MEMORY_GUARD: ::c_int = 31; +pub const VM_MEMORY_SHARED_PMAP: ::c_int = 32; +pub const VM_MEMORY_DYLIB: ::c_int = 33; +pub const VM_MEMORY_OBJC_DISPATCHERS: ::c_int = 34; +pub const VM_MEMORY_UNSHARED_PMAP: ::c_int = 35; +pub const VM_MEMORY_APPKIT: ::c_int = 40; +pub const VM_MEMORY_FOUNDATION: ::c_int = 41; +pub const VM_MEMORY_COREGRAPHICS: ::c_int = 42; +pub const VM_MEMORY_CORESERVICES: ::c_int = 43; +pub const VM_MEMORY_CARBON: ::c_int = VM_MEMORY_CORESERVICES; +pub const VM_MEMORY_JAVA: ::c_int = 44; +pub const VM_MEMORY_COREDATA: ::c_int = 45; +pub const VM_MEMORY_COREDATA_OBJECTIDS: ::c_int = 46; +pub const VM_MEMORY_ATS: ::c_int = 50; +pub const VM_MEMORY_LAYERKIT: ::c_int = 51; +pub const VM_MEMORY_CGIMAGE: ::c_int = 52; +pub const VM_MEMORY_TCMALLOC: ::c_int = 53; +pub const VM_MEMORY_COREGRAPHICS_DATA: ::c_int = 54; +pub const VM_MEMORY_COREGRAPHICS_SHARED: ::c_int = 55; +pub const VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS: ::c_int = 56; +pub const VM_MEMORY_COREGRAPHICS_BACKINGSTORES: ::c_int = 57; +pub const VM_MEMORY_COREGRAPHICS_XALLOC: ::c_int = 58; +pub const VM_MEMORY_COREGRAPHICS_MISC: ::c_int = VM_MEMORY_COREGRAPHICS; +pub const VM_MEMORY_DYLD: ::c_int = 60; +pub const VM_MEMORY_DYLD_MALLOC: ::c_int = 61; +pub const VM_MEMORY_SQLITE: ::c_int = 62; +pub const VM_MEMORY_JAVASCRIPT_CORE: ::c_int = 63; +pub const VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR: ::c_int = 64; +pub const VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE: ::c_int = 65; +pub const VM_MEMORY_GLSL: ::c_int = 66; +pub const VM_MEMORY_OPENCL: ::c_int = 67; +pub const VM_MEMORY_COREIMAGE: ::c_int = 68; +pub const VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS: ::c_int = 69; +pub const VM_MEMORY_IMAGEIO: ::c_int = 70; +pub const VM_MEMORY_COREPROFILE: ::c_int = 71; +pub const VM_MEMORY_ASSETSD: ::c_int = 72; +pub const VM_MEMORY_OS_ALLOC_ONCE: ::c_int = 73; +pub const VM_MEMORY_LIBDISPATCH: ::c_int = 74; +pub const VM_MEMORY_ACCELERATE: ::c_int = 75; +pub const VM_MEMORY_COREUI: ::c_int = 76; +pub const VM_MEMORY_COREUIFILE: ::c_int = 77; +pub const VM_MEMORY_GENEALOGY: ::c_int = 78; +pub const VM_MEMORY_RAWCAMERA: ::c_int = 79; +pub const VM_MEMORY_CORPSEINFO: ::c_int = 80; +pub const VM_MEMORY_ASL: ::c_int = 81; +pub const VM_MEMORY_SWIFT_RUNTIME: ::c_int = 82; +pub const VM_MEMORY_SWIFT_METADATA: ::c_int = 83; +pub const VM_MEMORY_DHMM: ::c_int = 84; +pub const VM_MEMORY_SCENEKIT: ::c_int = 86; +pub const VM_MEMORY_SKYWALK: ::c_int = 87; +pub const VM_MEMORY_APPLICATION_SPECIFIC_1: ::c_int = 240; +pub const VM_MEMORY_APPLICATION_SPECIFIC_16: ::c_int = 255; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; +pub const MS_SYNC: ::c_int = 0x0010; + +pub const MS_KILLPAGES: ::c_int = 0x0004; +pub const MS_DEACTIVATE: ::c_int = 0x0008; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EDEADLK: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EAGAIN: ::c_int = 35; +pub const EWOULDBLOCK: ::c_int = EAGAIN; +pub const EINPROGRESS: ::c_int = 36; +pub const EALREADY: ::c_int = 37; +pub const ENOTSOCK: ::c_int = 38; +pub const EDESTADDRREQ: ::c_int = 39; +pub const EMSGSIZE: ::c_int = 40; +pub const EPROTOTYPE: ::c_int = 41; +pub const ENOPROTOOPT: ::c_int = 42; +pub const EPROTONOSUPPORT: ::c_int = 43; +pub const ESOCKTNOSUPPORT: ::c_int = 44; +pub const ENOTSUP: ::c_int = 45; +pub const EPFNOSUPPORT: ::c_int = 46; +pub const EAFNOSUPPORT: ::c_int = 47; +pub const EADDRINUSE: ::c_int = 48; +pub const EADDRNOTAVAIL: ::c_int = 49; +pub const ENETDOWN: ::c_int = 50; +pub const ENETUNREACH: ::c_int = 51; +pub const ENETRESET: ::c_int = 52; +pub const ECONNABORTED: ::c_int = 53; +pub const ECONNRESET: ::c_int = 54; +pub const ENOBUFS: ::c_int = 55; +pub const EISCONN: ::c_int = 56; +pub const ENOTCONN: ::c_int = 57; +pub const ESHUTDOWN: ::c_int = 58; +pub const ETOOMANYREFS: ::c_int = 59; +pub const ETIMEDOUT: ::c_int = 60; +pub const ECONNREFUSED: ::c_int = 61; +pub const ELOOP: ::c_int = 62; +pub const ENAMETOOLONG: ::c_int = 63; +pub const EHOSTDOWN: ::c_int = 64; +pub const EHOSTUNREACH: ::c_int = 65; +pub const ENOTEMPTY: ::c_int = 66; +pub const EPROCLIM: ::c_int = 67; +pub const EUSERS: ::c_int = 68; +pub const EDQUOT: ::c_int = 69; +pub const ESTALE: ::c_int = 70; +pub const EREMOTE: ::c_int = 71; +pub const EBADRPC: ::c_int = 72; +pub const ERPCMISMATCH: ::c_int = 73; +pub const EPROGUNAVAIL: ::c_int = 74; +pub const EPROGMISMATCH: ::c_int = 75; +pub const EPROCUNAVAIL: ::c_int = 76; +pub const ENOLCK: ::c_int = 77; +pub const ENOSYS: ::c_int = 78; +pub const EFTYPE: ::c_int = 79; +pub const EAUTH: ::c_int = 80; +pub const ENEEDAUTH: ::c_int = 81; +pub const EPWROFF: ::c_int = 82; +pub const EDEVERR: ::c_int = 83; +pub const EOVERFLOW: ::c_int = 84; +pub const EBADEXEC: ::c_int = 85; +pub const EBADARCH: ::c_int = 86; +pub const ESHLIBVERS: ::c_int = 87; +pub const EBADMACHO: ::c_int = 88; +pub const ECANCELED: ::c_int = 89; +pub const EIDRM: ::c_int = 90; +pub const ENOMSG: ::c_int = 91; +pub const EILSEQ: ::c_int = 92; +pub const ENOATTR: ::c_int = 93; +pub const EBADMSG: ::c_int = 94; +pub const EMULTIHOP: ::c_int = 95; +pub const ENODATA: ::c_int = 96; +pub const ENOLINK: ::c_int = 97; +pub const ENOSR: ::c_int = 98; +pub const ENOSTR: ::c_int = 99; +pub const EPROTO: ::c_int = 100; +pub const ETIME: ::c_int = 101; +pub const EOPNOTSUPP: ::c_int = 102; +pub const ENOPOLICY: ::c_int = 103; +pub const ENOTRECOVERABLE: ::c_int = 104; +pub const EOWNERDEAD: ::c_int = 105; +pub const EQFULL: ::c_int = 106; +pub const ELAST: ::c_int = 106; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NODATA: ::c_int = 7; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 14; + +pub const F_DUPFD: ::c_int = 0; +pub const F_DUPFD_CLOEXEC: ::c_int = 67; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; +pub const F_PREALLOCATE: ::c_int = 42; +pub const F_RDADVISE: ::c_int = 44; +pub const F_RDAHEAD: ::c_int = 45; +pub const F_NOCACHE: ::c_int = 48; +pub const F_GETPATH: ::c_int = 50; +pub const F_FULLFSYNC: ::c_int = 51; +pub const F_FREEZE_FS: ::c_int = 53; +pub const F_THAW_FS: ::c_int = 54; +pub const F_GLOBAL_NOCACHE: ::c_int = 55; +pub const F_NODIRECT: ::c_int = 62; + +pub const F_ALLOCATECONTIG: ::c_uint = 0x02; +pub const F_ALLOCATEALL: ::c_uint = 0x04; + +pub const F_PEOFPOSMODE: ::c_int = 3; +pub const F_VOLPOSMODE: ::c_int = 4; + +pub const AT_FDCWD: ::c_int = -2; +pub const AT_EACCESS: ::c_int = 0x0010; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x0020; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x0040; +pub const AT_REMOVEDIR: ::c_int = 0x0080; + +pub const TIOCMODG: ::c_ulong = 0x40047403; +pub const TIOCMODS: ::c_ulong = 0x80047404; +pub const TIOCM_LE: ::c_int = 0x1; +pub const TIOCM_DTR: ::c_int = 0x2; +pub const TIOCM_RTS: ::c_int = 0x4; +pub const TIOCM_ST: ::c_int = 0x8; +pub const TIOCM_SR: ::c_int = 0x10; +pub const TIOCM_CTS: ::c_int = 0x20; +pub const TIOCM_CAR: ::c_int = 0x40; +pub const TIOCM_CD: ::c_int = 0x40; +pub const TIOCM_RNG: ::c_int = 0x80; +pub const TIOCM_RI: ::c_int = 0x80; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCEXCL: ::c_int = 0x2000740d; +pub const TIOCNXCL: ::c_int = 0x2000740e; +pub const TIOCFLUSH: ::c_ulong = 0x80047410; +pub const TIOCGETD: ::c_ulong = 0x4004741a; +pub const TIOCSETD: ::c_ulong = 0x8004741b; +pub const TIOCIXON: ::c_uint = 0x20007481; +pub const TIOCIXOFF: ::c_uint = 0x20007480; +pub const TIOCSBRK: ::c_uint = 0x2000747b; +pub const TIOCCBRK: ::c_uint = 0x2000747a; +pub const TIOCSDTR: ::c_uint = 0x20007479; +pub const TIOCCDTR: ::c_uint = 0x20007478; +pub const TIOCGPGRP: ::c_ulong = 0x40047477; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCOUTQ: ::c_ulong = 0x40047473; +pub const TIOCSTI: ::c_ulong = 0x80017472; +pub const TIOCNOTTY: ::c_uint = 0x20007471; +pub const TIOCPKT: ::c_ulong = 0x80047470; +pub const TIOCPKT_DATA: ::c_int = 0x0; +pub const TIOCPKT_FLUSHREAD: ::c_int = 0x1; +pub const TIOCPKT_FLUSHWRITE: ::c_int = 0x2; +pub const TIOCPKT_STOP: ::c_int = 0x4; +pub const TIOCPKT_START: ::c_int = 0x8; +pub const TIOCPKT_NOSTOP: ::c_int = 0x10; +pub const TIOCPKT_DOSTOP: ::c_int = 0x20; +pub const TIOCPKT_IOCTL: ::c_int = 0x40; +pub const TIOCSTOP: ::c_uint = 0x2000746f; +pub const TIOCSTART: ::c_uint = 0x2000746e; +pub const TIOCMSET: ::c_ulong = 0x8004746d; +pub const TIOCMBIS: ::c_ulong = 0x8004746c; +pub const TIOCMBIC: ::c_ulong = 0x8004746b; +pub const TIOCMGET: ::c_ulong = 0x4004746a; +pub const TIOCREMOTE: ::c_ulong = 0x80047469; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const TIOCUCNTL: ::c_ulong = 0x80047466; +pub const TIOCSTAT: ::c_uint = 0x20007465; +pub const TIOCSCONS: ::c_uint = 0x20007463; +pub const TIOCCONS: ::c_ulong = 0x80047462; +pub const TIOCSCTTY: ::c_uint = 0x20007461; +pub const TIOCEXT: ::c_ulong = 0x80047460; +pub const TIOCSIG: ::c_uint = 0x2000745f; +pub const TIOCDRAIN: ::c_uint = 0x2000745e; +pub const TIOCMSDTRWAIT: ::c_ulong = 0x8004745b; +pub const TIOCMGDTRWAIT: ::c_ulong = 0x4004745a; +pub const TIOCSDRAINWAIT: ::c_ulong = 0x80047457; +pub const TIOCGDRAINWAIT: ::c_ulong = 0x40047456; +pub const TIOCDSIMICROCODE: ::c_uint = 0x20007455; +pub const TIOCPTYGRANT: ::c_uint = 0x20007454; +pub const TIOCPTYGNAME: ::c_uint = 0x40807453; +pub const TIOCPTYUNLK: ::c_uint = 0x20007452; + +pub const FIONCLEX: ::c_uint = 0x20006602; +pub const FIONREAD: ::c_ulong = 0x4004667f; +pub const FIOASYNC: ::c_ulong = 0x8004667d; +pub const FIOSETOWN: ::c_ulong = 0x8004667c; +pub const FIOGETOWN: ::c_ulong = 0x4004667b; +pub const FIODTYPE: ::c_ulong = 0x4004667a; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SIGTRAP: ::c_int = 5; + +pub const GLOB_APPEND : ::c_int = 0x0001; +pub const GLOB_DOOFFS : ::c_int = 0x0002; +pub const GLOB_ERR : ::c_int = 0x0004; +pub const GLOB_MARK : ::c_int = 0x0008; +pub const GLOB_NOCHECK : ::c_int = 0x0010; +pub const GLOB_NOSORT : ::c_int = 0x0020; +pub const GLOB_NOESCAPE: ::c_int = 0x2000; + +pub const GLOB_NOSPACE : ::c_int = -1; +pub const GLOB_ABORTED : ::c_int = -2; +pub const GLOB_NOMATCH : ::c_int = -3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; + +pub const _SC_IOV_MAX: ::c_int = 56; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 70; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 71; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 73; +pub const _SC_MQ_PRIO_MAX: ::c_int = 75; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 82; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 83; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 85; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 86; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 87; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 88; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 89; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 90; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 91; +pub const _SC_THREAD_STACK_MIN: ::c_int = 93; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 94; +pub const _SC_THREADS: ::c_int = 96; +pub const _SC_TTY_NAME_MAX: ::c_int = 101; +pub const _SC_ATEXIT_MAX: ::c_int = 107; +pub const _SC_XOPEN_CRYPT: ::c_int = 108; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 109; +pub const _SC_XOPEN_LEGACY: ::c_int = 110; +pub const _SC_XOPEN_REALTIME: ::c_int = 111; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 112; +pub const _SC_XOPEN_SHM: ::c_int = 113; +pub const _SC_XOPEN_UNIX: ::c_int = 115; +pub const _SC_XOPEN_VERSION: ::c_int = 116; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 121; +pub const _SC_PHYS_PAGES: ::c_int = 200; + +pub const PTHREAD_PROCESS_PRIVATE: ::c_int = 2; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 1; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 2; +pub const PTHREAD_STACK_MIN: ::size_t = 8192; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_AS: ::c_int = 5; +pub const RLIMIT_RSS: ::c_int = RLIMIT_AS; +pub const RLIMIT_MEMLOCK: ::c_int = 6; +pub const RLIMIT_NPROC: ::c_int = 7; +pub const RLIMIT_NOFILE: ::c_int = 8; +pub const RLIM_NLIMITS: ::c_int = 9; +pub const _RLIMIT_POSIX_FLAG: ::c_int = 0x1000; + +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; + +pub const RUSAGE_SELF: ::c_int = 0; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_FREE: ::c_int = 5; +pub const MADV_ZERO_WIRED_PAGES: ::c_int = 6; +pub const MADV_FREE_REUSABLE: ::c_int = 7; +pub const MADV_FREE_REUSE: ::c_int = 8; +pub const MADV_CAN_REUSE: ::c_int = 9; + +pub const MINCORE_INCORE: ::c_int = 0x1; +pub const MINCORE_REFERENCED: ::c_int = 0x2; +pub const MINCORE_MODIFIED: ::c_int = 0x4; +pub const MINCORE_REFERENCED_OTHER: ::c_int = 0x8; +pub const MINCORE_MODIFIED_OTHER: ::c_int = 0x10; + +// +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// gateway2 (deprecated) +pub const IPPROTO_GGP: ::c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: ::c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: ::c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: ::c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: ::c_int = 11; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: ::c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: ::c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: ::c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: ::c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: ::c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: ::c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: ::c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: ::c_int = 21; +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: ::c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: ::c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: ::c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: ::c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: ::c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: ::c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: ::c_int = 30; +/// Network Services +pub const IPPROTO_NSP: ::c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: ::c_int = 32; +/// Sequential Exchange +pub const IPPROTO_SEP: ::c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: ::c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: ::c_int = 35; +/// XTP +pub const IPPROTO_XTP: ::c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: ::c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: ::c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: ::c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: ::c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: ::c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: ::c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: ::c_int = 48; +/// BHA +pub const IPPROTO_BHA: ::c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: ::c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: ::c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: ::c_int = 54; +/* 55-57: Unassigned */ +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: ::c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: ::c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: ::c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: ::c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: ::c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: ::c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: ::c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: ::c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: ::c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: ::c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: ::c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: ::c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: ::c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: ::c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: ::c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: ::c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: ::c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: ::c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: ::c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: ::c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: ::c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: ::c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: ::c_int = 83; +/// TTP +pub const IPPROTO_TTP: ::c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: ::c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: ::c_int = 86; +/// TCF +pub const IPPROTO_TCF: ::c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: ::c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: ::c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: ::c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: ::c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: ::c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: ::c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: ::c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: ::c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: ::c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: ::c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: ::c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: ::c_int = 100; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: ::c_int = 103; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: ::c_int = 108; +/// PGM +pub const IPPROTO_PGM: ::c_int = 113; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: ::c_int = 254; +/// raw IP packet +pub const IPPROTO_RAW: ::c_int = 255; +pub const IPPROTO_MAX: ::c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: ::c_int = 257; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_UNIX: ::c_int = AF_LOCAL; +pub const AF_INET: ::c_int = 2; +pub const AF_IMPLINK: ::c_int = 3; +pub const AF_PUP: ::c_int = 4; +pub const AF_CHAOS: ::c_int = 5; +pub const AF_NS: ::c_int = 6; +pub const AF_ISO: ::c_int = 7; +pub const AF_OSI: ::c_int = AF_ISO; +pub const AF_ECMA: ::c_int = 8; +pub const AF_DATAKIT: ::c_int = 9; +pub const AF_CCITT: ::c_int = 10; +pub const AF_SNA: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_DLI: ::c_int = 13; +pub const AF_LAT: ::c_int = 14; +pub const AF_HYLINK: ::c_int = 15; +pub const AF_APPLETALK: ::c_int = 16; +pub const AF_ROUTE: ::c_int = 17; +pub const AF_LINK: ::c_int = 18; +pub const pseudo_AF_XTP: ::c_int = 19; +pub const AF_COIP: ::c_int = 20; +pub const AF_CNT: ::c_int = 21; +pub const pseudo_AF_RTIP: ::c_int = 22; +pub const AF_IPX: ::c_int = 23; +pub const AF_SIP: ::c_int = 24; +pub const pseudo_AF_PIP: ::c_int = 25; +pub const AF_ISDN: ::c_int = 28; +pub const AF_E164: ::c_int = AF_ISDN; +pub const pseudo_AF_KEY: ::c_int = 29; +pub const AF_INET6: ::c_int = 30; +pub const AF_NATM: ::c_int = 31; +pub const AF_SYSTEM: ::c_int = 32; +pub const AF_NETBIOS: ::c_int = 33; +pub const AF_PPP: ::c_int = 34; +pub const pseudo_AF_HDRCMPLT: ::c_int = 35; +#[doc(hidden)] +pub const AF_MAX: ::c_int = 40; +pub const AF_SYS_CONTROL: ::c_int = 2; + +pub const SYSPROTO_EVENT: ::c_int = 1; +pub const SYSPROTO_CONTROL: ::c_int = 2; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_UNIX: ::c_int = PF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_IMPLINK: ::c_int = AF_IMPLINK; +pub const PF_PUP: ::c_int = AF_PUP; +pub const PF_CHAOS: ::c_int = AF_CHAOS; +pub const PF_NS: ::c_int = AF_NS; +pub const PF_ISO: ::c_int = AF_ISO; +pub const PF_OSI: ::c_int = AF_ISO; +pub const PF_ECMA: ::c_int = AF_ECMA; +pub const PF_DATAKIT: ::c_int = AF_DATAKIT; +pub const PF_CCITT: ::c_int = AF_CCITT; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_DLI: ::c_int = AF_DLI; +pub const PF_LAT: ::c_int = AF_LAT; +pub const PF_HYLINK: ::c_int = AF_HYLINK; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_LINK: ::c_int = AF_LINK; +pub const PF_XTP: ::c_int = pseudo_AF_XTP; +pub const PF_COIP: ::c_int = AF_COIP; +pub const PF_CNT: ::c_int = AF_CNT; +pub const PF_SIP: ::c_int = AF_SIP; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_RTIP: ::c_int = pseudo_AF_RTIP; +pub const PF_PIP: ::c_int = pseudo_AF_PIP; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_KEY: ::c_int = pseudo_AF_KEY; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_NATM: ::c_int = AF_NATM; +pub const PF_SYSTEM: ::c_int = AF_SYSTEM; +pub const PF_NETBIOS: ::c_int = AF_NETBIOS; +pub const PF_PPP: ::c_int = AF_PPP; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +#[doc(hidden)] +pub const NET_MAXID: ::c_int = AF_MAX; + +pub const NET_RT_DUMP: ::c_int = 1; +pub const NET_RT_FLAGS: ::c_int = 2; +pub const NET_RT_IFLIST: ::c_int = 3; +#[doc(hidden)] +pub const NET_RT_MAXID: ::c_int = 10; + +pub const SOMAXCONN: ::c_int = 128; + +pub const SOCK_MAXADDRLEN: ::c_int = 255; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_RDM: ::c_int = 4; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const IP_TTL: ::c_int = 4; +pub const IP_HDRINCL: ::c_int = 2; +pub const IP_RECVDSTADDR: ::c_int = 7; +pub const IP_ADD_MEMBERSHIP: ::c_int = 12; +pub const IP_DROP_MEMBERSHIP: ::c_int = 13; +pub const IP_RECVIF: ::c_int = 20; +pub const IP_PKTINFO: ::c_int = 26; +pub const IP_RECVTOS: ::c_int = 27; +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; +pub const IPV6_RECVTCLASS: ::c_int = 35; +pub const IPV6_TCLASS: ::c_int = 36; +pub const IPV6_PKTINFO: ::c_int = 46; +pub const IPV6_RECVPKTINFO: ::c_int = 61; + +pub const TCP_NOPUSH: ::c_int = 4; +pub const TCP_NOOPT: ::c_int = 8; +pub const TCP_KEEPALIVE: ::c_int = 0x10; + +pub const SOL_LOCAL: ::c_int = 0; + +pub const LOCAL_PEERCRED: ::c_int = 0x001; +pub const LOCAL_PEERPID: ::c_int = 0x002; +pub const LOCAL_PEEREPID: ::c_int = 0x003; +pub const LOCAL_PEERUUID: ::c_int = 0x004; +pub const LOCAL_PEEREUUID: ::c_int = 0x005; + +pub const SOL_SOCKET: ::c_int = 0xffff; + +pub const SO_DEBUG: ::c_int = 0x01; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_TIMESTAMP: ::c_int = 0x0400; +pub const SO_TIMESTAMP_MONOTONIC: ::c_int = 0x0800; +pub const SO_DONTTRUNC: ::c_int = 0x2000; +pub const SO_WANTMORE: ::c_int = 0x4000; +pub const SO_WANTOOBFLAG: ::c_int = 0x8000; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_LABEL: ::c_int = 0x1010; +pub const SO_PEERLABEL: ::c_int = 0x1011; +pub const SO_NREAD: ::c_int = 0x1020; +pub const SO_NKE: ::c_int = 0x1021; +pub const SO_NOSIGPIPE: ::c_int = 0x1022; +pub const SO_NOADDRERR: ::c_int = 0x1023; +pub const SO_NWRITE: ::c_int = 0x1024; +pub const SO_REUSESHAREUID: ::c_int = 0x1025; +pub const SO_NOTIFYCONFLICT: ::c_int = 0x1026; +pub const SO_RANDOMPORT: ::c_int = 0x1082; +pub const SO_NP_EXTENSIONS: ::c_int = 0x1083; + +pub const MSG_OOB: ::c_int = 0x1; +pub const MSG_PEEK: ::c_int = 0x2; +pub const MSG_DONTROUTE: ::c_int = 0x4; +pub const MSG_EOR: ::c_int = 0x8; +pub const MSG_TRUNC: ::c_int = 0x10; +pub const MSG_CTRUNC: ::c_int = 0x20; +pub const MSG_WAITALL: ::c_int = 0x40; +pub const MSG_DONTWAIT: ::c_int = 0x80; +pub const MSG_EOF: ::c_int = 0x100; +pub const MSG_FLUSH: ::c_int = 0x400; +pub const MSG_HOLD: ::c_int = 0x800; +pub const MSG_SEND: ::c_int = 0x1000; +pub const MSG_HAVEMORE: ::c_int = 0x2000; +pub const MSG_RCVMORE: ::c_int = 0x4000; +// pub const MSG_COMPAT: ::c_int = 0x8000; + +pub const SCM_TIMESTAMP: ::c_int = 0x02; +pub const SCM_CREDS: ::c_int = 0x03; + +// https://github.com/aosm/xnu/blob/master/bsd/net/if.h#L140-L156 +pub const IFF_UP: ::c_int = 0x1; // interface is up +pub const IFF_BROADCAST: ::c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x10; // interface is point-to-point link +pub const IFF_NOTRAILERS: ::c_int = 0x20; // obsolete: avoid use of trailers +pub const IFF_RUNNING: ::c_int = 0x40; // resources allocated +pub const IFF_NOARP: ::c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x100;// receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x200;// receive all multicast packets +pub const IFF_OACTIVE: ::c_int = 0x400;// transmission in progress +pub const IFF_SIMPLEX: ::c_int = 0x800;// can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000;// per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000;// per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000;// per link layer defined bit +pub const IFF_ALTPHYS: ::c_int = IFF_LINK2;// use alternate physical connection +pub const IFF_MULTICAST: ::c_int = 0x8000;// supports multicast + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const MAP_COPY: ::c_int = 0x0002; +pub const MAP_RENAME: ::c_int = 0x0020; +pub const MAP_NORESERVE: ::c_int = 0x0040; +pub const MAP_NOEXTEND: ::c_int = 0x0100; +pub const MAP_HASSEMAPHORE: ::c_int = 0x0200; +pub const MAP_NOCACHE: ::c_int = 0x0400; +pub const MAP_JIT: ::c_int = 0x0800; + +pub const _SC_ARG_MAX: ::c_int = 1; +pub const _SC_CHILD_MAX: ::c_int = 2; +pub const _SC_CLK_TCK: ::c_int = 3; +pub const _SC_NGROUPS_MAX: ::c_int = 4; +pub const _SC_OPEN_MAX: ::c_int = 5; +pub const _SC_JOB_CONTROL: ::c_int = 6; +pub const _SC_SAVED_IDS: ::c_int = 7; +pub const _SC_VERSION: ::c_int = 8; +pub const _SC_BC_BASE_MAX: ::c_int = 9; +pub const _SC_BC_DIM_MAX: ::c_int = 10; +pub const _SC_BC_SCALE_MAX: ::c_int = 11; +pub const _SC_BC_STRING_MAX: ::c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 13; +pub const _SC_EXPR_NEST_MAX: ::c_int = 14; +pub const _SC_LINE_MAX: ::c_int = 15; +pub const _SC_RE_DUP_MAX: ::c_int = 16; +pub const _SC_2_VERSION: ::c_int = 17; +pub const _SC_2_C_BIND: ::c_int = 18; +pub const _SC_2_C_DEV: ::c_int = 19; +pub const _SC_2_CHAR_TERM: ::c_int = 20; +pub const _SC_2_FORT_DEV: ::c_int = 21; +pub const _SC_2_FORT_RUN: ::c_int = 22; +pub const _SC_2_LOCALEDEF: ::c_int = 23; +pub const _SC_2_SW_DEV: ::c_int = 24; +pub const _SC_2_UPE: ::c_int = 25; +pub const _SC_STREAM_MAX: ::c_int = 26; +pub const _SC_TZNAME_MAX: ::c_int = 27; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 28; +pub const _SC_PAGESIZE: ::c_int = 29; +pub const _SC_MEMLOCK: ::c_int = 30; +pub const _SC_MEMLOCK_RANGE: ::c_int = 31; +pub const _SC_MEMORY_PROTECTION: ::c_int = 32; +pub const _SC_MESSAGE_PASSING: ::c_int = 33; +pub const _SC_PRIORITIZED_IO: ::c_int = 34; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 35; +pub const _SC_REALTIME_SIGNALS: ::c_int = 36; +pub const _SC_SEMAPHORES: ::c_int = 37; +pub const _SC_FSYNC: ::c_int = 38; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 39; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 40; +pub const _SC_TIMERS: ::c_int = 41; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 42; +pub const _SC_AIO_MAX: ::c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 44; +pub const _SC_DELAYTIMER_MAX: ::c_int = 45; +pub const _SC_MQ_OPEN_MAX: ::c_int = 46; +pub const _SC_MAPPED_FILES: ::c_int = 47; +pub const _SC_RTSIG_MAX: ::c_int = 48; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 49; +pub const _SC_SEM_VALUE_MAX: ::c_int = 50; +pub const _SC_SIGQUEUE_MAX: ::c_int = 51; +pub const _SC_TIMER_MAX: ::c_int = 52; +pub const _SC_NPROCESSORS_CONF: ::c_int = 57; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 58; +pub const _SC_2_PBS: ::c_int = 59; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 60; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 61; +pub const _SC_2_PBS_LOCATE: ::c_int = 62; +pub const _SC_2_PBS_MESSAGE: ::c_int = 63; +pub const _SC_2_PBS_TRACK: ::c_int = 64; +pub const _SC_ADVISORY_INFO: ::c_int = 65; +pub const _SC_BARRIERS: ::c_int = 66; +pub const _SC_CLOCK_SELECTION: ::c_int = 67; +pub const _SC_CPUTIME: ::c_int = 68; +pub const _SC_FILE_LOCKING: ::c_int = 69; +pub const _SC_HOST_NAME_MAX: ::c_int = 72; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 74; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 76; +pub const _SC_REGEXP: ::c_int = 77; +pub const _SC_SHELL: ::c_int = 78; +pub const _SC_SPAWN: ::c_int = 79; +pub const _SC_SPIN_LOCKS: ::c_int = 80; +pub const _SC_SPORADIC_SERVER: ::c_int = 81; +pub const _SC_THREAD_CPUTIME: ::c_int = 84; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 92; +pub const _SC_TIMEOUTS: ::c_int = 95; +pub const _SC_TRACE: ::c_int = 97; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 98; +pub const _SC_TRACE_INHERIT: ::c_int = 99; +pub const _SC_TRACE_LOG: ::c_int = 100; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 102; +pub const _SC_V6_ILP32_OFF32: ::c_int = 103; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 104; +pub const _SC_V6_LP64_OFF64: ::c_int = 105; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 106; +pub const _SC_IPV6: ::c_int = 118; +pub const _SC_RAW_SOCKETS: ::c_int = 119; +pub const _SC_SYMLOOP_MAX: ::c_int = 120; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_XOPEN_STREAMS: ::c_int = 114; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 122; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 123; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 124; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 125; +pub const _SC_SS_REPL_MAX: ::c_int = 126; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 127; +pub const _SC_TRACE_NAME_MAX: ::c_int = 128; +pub const _SC_TRACE_SYS_MAX: ::c_int = 129; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 130; +pub const _SC_PASS_MAX: ::c_int = 131; + +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; +pub const _PTHREAD_MUTEX_SIG_init: ::c_long = 0x32AAABA7; +pub const _PTHREAD_COND_SIG_init: ::c_long = 0x3CB0B1BB; +pub const _PTHREAD_RWLOCK_SIG_init: ::c_long = 0x2DA8B3B4; +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __sig: _PTHREAD_MUTEX_SIG_init, + __opaque: [0; __PTHREAD_MUTEX_SIZE__], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __sig: _PTHREAD_COND_SIG_init, + __opaque: [0; __PTHREAD_COND_SIZE__], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __sig: _PTHREAD_RWLOCK_SIG_init, + __opaque: [0; __PTHREAD_RWLOCK_SIZE__], +}; + +pub const SIGSTKSZ: ::size_t = 131072; + +pub const FD_SETSIZE: usize = 1024; + +pub const ST_NOSUID: ::c_ulong = 2; + +pub const EVFILT_READ: ::int16_t = -1; +pub const EVFILT_WRITE: ::int16_t = -2; +pub const EVFILT_AIO: ::int16_t = -3; +pub const EVFILT_VNODE: ::int16_t = -4; +pub const EVFILT_PROC: ::int16_t = -5; +pub const EVFILT_SIGNAL: ::int16_t = -6; +pub const EVFILT_TIMER: ::int16_t = -7; +pub const EVFILT_MACHPORT: ::int16_t = -8; +pub const EVFILT_FS: ::int16_t = -9; +pub const EVFILT_USER: ::int16_t = -10; +pub const EVFILT_VM: ::int16_t = -12; + +pub const EV_ADD: ::uint16_t = 0x1; +pub const EV_DELETE: ::uint16_t = 0x2; +pub const EV_ENABLE: ::uint16_t = 0x4; +pub const EV_DISABLE: ::uint16_t = 0x8; +pub const EV_ONESHOT: ::uint16_t = 0x10; +pub const EV_CLEAR: ::uint16_t = 0x20; +pub const EV_RECEIPT: ::uint16_t = 0x40; +pub const EV_DISPATCH: ::uint16_t = 0x80; +pub const EV_FLAG0: ::uint16_t = 0x1000; +pub const EV_POLL: ::uint16_t = 0x1000; +pub const EV_FLAG1: ::uint16_t = 0x2000; +pub const EV_OOBAND: ::uint16_t = 0x2000; +pub const EV_ERROR: ::uint16_t = 0x4000; +pub const EV_EOF: ::uint16_t = 0x8000; +pub const EV_SYSFLAGS: ::uint16_t = 0xf000; + +pub const NOTE_TRIGGER: ::uint32_t = 0x01000000; +pub const NOTE_FFNOP: ::uint32_t = 0x00000000; +pub const NOTE_FFAND: ::uint32_t = 0x40000000; +pub const NOTE_FFOR: ::uint32_t = 0x80000000; +pub const NOTE_FFCOPY: ::uint32_t = 0xc0000000; +pub const NOTE_FFCTRLMASK: ::uint32_t = 0xc0000000; +pub const NOTE_FFLAGSMASK: ::uint32_t = 0x00ffffff; +pub const NOTE_LOWAT: ::uint32_t = 0x00000001; +pub const NOTE_DELETE: ::uint32_t = 0x00000001; +pub const NOTE_WRITE: ::uint32_t = 0x00000002; +pub const NOTE_EXTEND: ::uint32_t = 0x00000004; +pub const NOTE_ATTRIB: ::uint32_t = 0x00000008; +pub const NOTE_LINK: ::uint32_t = 0x00000010; +pub const NOTE_RENAME: ::uint32_t = 0x00000020; +pub const NOTE_REVOKE: ::uint32_t = 0x00000040; +pub const NOTE_NONE: ::uint32_t = 0x00000080; +pub const NOTE_EXIT: ::uint32_t = 0x80000000; +pub const NOTE_FORK: ::uint32_t = 0x40000000; +pub const NOTE_EXEC: ::uint32_t = 0x20000000; +#[deprecated(since="0.2.49", note="Deprecated since MacOSX 10.9")] +pub const NOTE_REAP: ::uint32_t = 0x10000000; +pub const NOTE_SIGNAL: ::uint32_t = 0x08000000; +pub const NOTE_EXITSTATUS: ::uint32_t = 0x04000000; +pub const NOTE_EXIT_DETAIL: ::uint32_t = 0x02000000; +pub const NOTE_PDATAMASK: ::uint32_t = 0x000fffff; +pub const NOTE_PCTRLMASK: ::uint32_t = 0xfff00000; +#[deprecated(since="0.2.49", note="Deprecated since MacOSX 10.9")] +pub const NOTE_EXIT_REPARENTED: ::uint32_t = 0x00080000; +pub const NOTE_EXIT_DETAIL_MASK: ::uint32_t = 0x00070000; +pub const NOTE_EXIT_DECRYPTFAIL: ::uint32_t = 0x00010000; +pub const NOTE_EXIT_MEMORY: ::uint32_t = 0x00020000; +pub const NOTE_EXIT_CSERROR: ::uint32_t = 0x00040000; +pub const NOTE_VM_PRESSURE: ::uint32_t = 0x80000000; +pub const NOTE_VM_PRESSURE_TERMINATE: ::uint32_t = 0x40000000; +pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE: ::uint32_t = 0x20000000; +pub const NOTE_VM_ERROR: ::uint32_t = 0x10000000; +pub const NOTE_SECONDS: ::uint32_t = 0x00000001; +pub const NOTE_USECONDS: ::uint32_t = 0x00000002; +pub const NOTE_NSECONDS: ::uint32_t = 0x00000004; +pub const NOTE_ABSOLUTE: ::uint32_t = 0x00000008; +pub const NOTE_LEEWAY: ::uint32_t = 0x00000010; +pub const NOTE_CRITICAL: ::uint32_t = 0x00000020; +pub const NOTE_BACKGROUND: ::uint32_t = 0x00000040; +pub const NOTE_TRACK: ::uint32_t = 0x00000001; +pub const NOTE_TRACKERR: ::uint32_t = 0x00000002; +pub const NOTE_CHILD: ::uint32_t = 0x00000004; + +pub const OCRNL: ::c_int = 0x00000010; +pub const ONOCR: ::c_int = 0x00000020; +pub const ONLRET: ::c_int = 0x00000040; +pub const OFILL: ::c_int = 0x00000080; +pub const NLDLY: ::c_int = 0x00000300; +pub const TABDLY: ::c_int = 0x00000c04; +pub const CRDLY: ::c_int = 0x00003000; +pub const FFDLY: ::c_int = 0x00004000; +pub const BSDLY: ::c_int = 0x00008000; +pub const VTDLY: ::c_int = 0x00010000; +pub const OFDEL: ::c_int = 0x00020000; + +pub const NL0: ::c_int = 0x00000000; +pub const NL1: ::c_int = 0x00000100; +pub const TAB0: ::c_int = 0x00000000; +pub const TAB1: ::c_int = 0x00000400; +pub const TAB2: ::c_int = 0x00000800; +pub const CR0: ::c_int = 0x00000000; +pub const CR1: ::c_int = 0x00001000; +pub const CR2: ::c_int = 0x00002000; +pub const CR3: ::c_int = 0x00003000; +pub const FF0: ::c_int = 0x00000000; +pub const FF1: ::c_int = 0x00004000; +pub const BS0: ::c_int = 0x00000000; +pub const BS1: ::c_int = 0x00008000; +pub const TAB3: ::c_int = 0x00000004; +pub const VT0: ::c_int = 0x00000000; +pub const VT1: ::c_int = 0x00010000; +pub const IUTF8: ::tcflag_t = 0x00004000; +pub const CRTSCTS: ::tcflag_t = 0x00030000; + +pub const NI_MAXHOST: ::socklen_t = 1025; +pub const NI_MAXSERV: ::socklen_t = 32; +pub const NI_NOFQDN: ::c_int = 0x00000001; +pub const NI_NUMERICHOST: ::c_int = 0x00000002; +pub const NI_NAMEREQD: ::c_int = 0x00000004; +pub const NI_NUMERICSERV: ::c_int = 0x00000008; +pub const NI_NUMERICSCOPE: ::c_int = 0x00000100; +pub const NI_DGRAM: ::c_int = 0x00000010; + +pub const Q_GETQUOTA: ::c_int = 0x300; +pub const Q_SETQUOTA: ::c_int = 0x400; + +pub const RENAME_SWAP: ::c_uint = 0x00000002; +pub const RENAME_EXCL: ::c_uint = 0x00000004; + +pub const RTLD_LOCAL: ::c_int = 0x4; +pub const RTLD_FIRST: ::c_int = 0x100; +pub const RTLD_NODELETE: ::c_int = 0x80; +pub const RTLD_NOLOAD: ::c_int = 0x10; +pub const RTLD_GLOBAL: ::c_int = 0x8; + +pub const _WSTOPPED: ::c_int = 0o177; + +pub const LOG_NETINFO: ::c_int = 12 << 3; +pub const LOG_REMOTEAUTH: ::c_int = 13 << 3; +pub const LOG_INSTALL: ::c_int = 14 << 3; +pub const LOG_RAS: ::c_int = 15 << 3; +pub const LOG_LAUNCHD: ::c_int = 24 << 3; +pub const LOG_NFACILITIES: ::c_int = 25; + +pub const CTLTYPE: ::c_int = 0xf; +pub const CTLTYPE_NODE: ::c_int = 1; +pub const CTLTYPE_INT: ::c_int = 2; +pub const CTLTYPE_STRING: ::c_int = 3; +pub const CTLTYPE_QUAD: ::c_int = 4; +pub const CTLTYPE_OPAQUE: ::c_int = 5; +pub const CTLTYPE_STRUCT: ::c_int = CTLTYPE_OPAQUE; +pub const CTLFLAG_RD: ::c_int = 0x80000000; +pub const CTLFLAG_WR: ::c_int = 0x40000000; +pub const CTLFLAG_RW: ::c_int = CTLFLAG_RD | CTLFLAG_WR; +pub const CTLFLAG_NOLOCK: ::c_int = 0x20000000; +pub const CTLFLAG_ANYBODY: ::c_int = 0x10000000; +pub const CTLFLAG_SECURE: ::c_int = 0x08000000; +pub const CTLFLAG_MASKED: ::c_int = 0x04000000; +pub const CTLFLAG_NOAUTO: ::c_int = 0x02000000; +pub const CTLFLAG_KERN: ::c_int = 0x01000000; +pub const CTLFLAG_LOCKED: ::c_int = 0x00800000; +pub const CTLFLAG_OID2: ::c_int = 0x00400000; +pub const CTL_UNSPEC: ::c_int = 0; +pub const CTL_KERN: ::c_int = 1; +pub const CTL_VM: ::c_int = 2; +pub const CTL_VFS: ::c_int = 3; +pub const CTL_NET: ::c_int = 4; +pub const CTL_DEBUG: ::c_int = 5; +pub const CTL_HW: ::c_int = 6; +pub const CTL_MACHDEP: ::c_int = 7; +pub const CTL_USER: ::c_int = 8; +pub const CTL_MAXID: ::c_int = 9; +pub const KERN_OSTYPE: ::c_int = 1; +pub const KERN_OSRELEASE: ::c_int = 2; +pub const KERN_OSREV: ::c_int = 3; +pub const KERN_VERSION: ::c_int = 4; +pub const KERN_MAXVNODES: ::c_int = 5; +pub const KERN_MAXPROC: ::c_int = 6; +pub const KERN_MAXFILES: ::c_int = 7; +pub const KERN_ARGMAX: ::c_int = 8; +pub const KERN_SECURELVL: ::c_int = 9; +pub const KERN_HOSTNAME: ::c_int = 10; +pub const KERN_HOSTID: ::c_int = 11; +pub const KERN_CLOCKRATE: ::c_int = 12; +pub const KERN_VNODE: ::c_int = 13; +pub const KERN_PROC: ::c_int = 14; +pub const KERN_FILE: ::c_int = 15; +pub const KERN_PROF: ::c_int = 16; +pub const KERN_POSIX1: ::c_int = 17; +pub const KERN_NGROUPS: ::c_int = 18; +pub const KERN_JOB_CONTROL: ::c_int = 19; +pub const KERN_SAVED_IDS: ::c_int = 20; +pub const KERN_BOOTTIME: ::c_int = 21; +pub const KERN_NISDOMAINNAME: ::c_int = 22; +pub const KERN_DOMAINNAME: ::c_int = KERN_NISDOMAINNAME; +pub const KERN_MAXPARTITIONS: ::c_int = 23; +pub const KERN_KDEBUG: ::c_int = 24; +pub const KERN_UPDATEINTERVAL: ::c_int = 25; +pub const KERN_OSRELDATE: ::c_int = 26; +pub const KERN_NTP_PLL: ::c_int = 27; +pub const KERN_BOOTFILE: ::c_int = 28; +pub const KERN_MAXFILESPERPROC: ::c_int = 29; +pub const KERN_MAXPROCPERUID: ::c_int = 30; +pub const KERN_DUMPDEV: ::c_int = 31; +pub const KERN_IPC: ::c_int = 32; +pub const KERN_DUMMY: ::c_int = 33; +pub const KERN_PS_STRINGS: ::c_int = 34; +pub const KERN_USRSTACK32: ::c_int = 35; +pub const KERN_LOGSIGEXIT: ::c_int = 36; +pub const KERN_SYMFILE: ::c_int = 37; +pub const KERN_PROCARGS: ::c_int = 38; +pub const KERN_NETBOOT: ::c_int = 40; +pub const KERN_SYSV: ::c_int = 42; +pub const KERN_AFFINITY: ::c_int = 43; +pub const KERN_TRANSLATE: ::c_int = 44; +pub const KERN_CLASSIC: ::c_int = KERN_TRANSLATE; +pub const KERN_EXEC: ::c_int = 45; +pub const KERN_CLASSICHANDLER: ::c_int = KERN_EXEC; +pub const KERN_AIOMAX: ::c_int = 46; +pub const KERN_AIOPROCMAX: ::c_int = 47; +pub const KERN_AIOTHREADS: ::c_int = 48; +pub const KERN_COREFILE: ::c_int = 50; +pub const KERN_COREDUMP: ::c_int = 51; +pub const KERN_SUGID_COREDUMP: ::c_int = 52; +pub const KERN_PROCDELAYTERM: ::c_int = 53; +pub const KERN_SHREG_PRIVATIZABLE: ::c_int = 54; +pub const KERN_LOW_PRI_WINDOW: ::c_int = 56; +pub const KERN_LOW_PRI_DELAY: ::c_int = 57; +pub const KERN_POSIX: ::c_int = 58; +pub const KERN_USRSTACK64: ::c_int = 59; +pub const KERN_NX_PROTECTION: ::c_int = 60; +pub const KERN_TFP: ::c_int = 61; +pub const KERN_PROCNAME: ::c_int = 62; +pub const KERN_THALTSTACK: ::c_int = 63; +pub const KERN_SPECULATIVE_READS: ::c_int = 64; +pub const KERN_OSVERSION: ::c_int = 65; +pub const KERN_SAFEBOOT: ::c_int = 66; +pub const KERN_RAGEVNODE: ::c_int = 68; +pub const KERN_TTY: ::c_int = 69; +pub const KERN_CHECKOPENEVT: ::c_int = 70; +pub const KERN_THREADNAME: ::c_int = 71; +pub const KERN_MAXID: ::c_int = 72; +pub const KERN_RAGE_PROC: ::c_int = 1; +pub const KERN_RAGE_THREAD: ::c_int = 2; +pub const KERN_UNRAGE_PROC: ::c_int = 3; +pub const KERN_UNRAGE_THREAD: ::c_int = 4; +pub const KERN_OPENEVT_PROC: ::c_int = 1; +pub const KERN_UNOPENEVT_PROC: ::c_int = 2; +pub const KERN_TFP_POLICY: ::c_int = 1; +pub const KERN_TFP_POLICY_DENY: ::c_int = 0; +pub const KERN_TFP_POLICY_DEFAULT: ::c_int = 2; +pub const KERN_KDEFLAGS: ::c_int = 1; +pub const KERN_KDDFLAGS: ::c_int = 2; +pub const KERN_KDENABLE: ::c_int = 3; +pub const KERN_KDSETBUF: ::c_int = 4; +pub const KERN_KDGETBUF: ::c_int = 5; +pub const KERN_KDSETUP: ::c_int = 6; +pub const KERN_KDREMOVE: ::c_int = 7; +pub const KERN_KDSETREG: ::c_int = 8; +pub const KERN_KDGETREG: ::c_int = 9; +pub const KERN_KDREADTR: ::c_int = 10; +pub const KERN_KDPIDTR: ::c_int = 11; +pub const KERN_KDTHRMAP: ::c_int = 12; +pub const KERN_KDPIDEX: ::c_int = 14; +pub const KERN_KDSETRTCDEC: ::c_int = 15; +pub const KERN_KDGETENTROPY: ::c_int = 16; +pub const KERN_KDWRITETR: ::c_int = 17; +pub const KERN_KDWRITEMAP: ::c_int = 18; +#[deprecated(since = "0.2.49", note ="Removed in MacOSX 10.12")] +pub const KERN_KDENABLE_BG_TRACE: ::c_int = 19; +#[deprecated(since = "0.2.49", note ="Removed in MacOSX 10.12")] +pub const KERN_KDDISABLE_BG_TRACE: ::c_int = 20; +pub const KERN_KDREADCURTHRMAP: ::c_int = 21; +pub const KERN_KDSET_TYPEFILTER: ::c_int = 22; +pub const KERN_KDBUFWAIT: ::c_int = 23; +pub const KERN_KDCPUMAP: ::c_int = 24; +pub const KERN_PROC_ALL: ::c_int = 0; +pub const KERN_PROC_PID: ::c_int = 1; +pub const KERN_PROC_PGRP: ::c_int = 2; +pub const KERN_PROC_SESSION: ::c_int = 3; +pub const KERN_PROC_TTY: ::c_int = 4; +pub const KERN_PROC_UID: ::c_int = 5; +pub const KERN_PROC_RUID: ::c_int = 6; +pub const KERN_PROC_LCID: ::c_int = 7; +pub const KIPC_MAXSOCKBUF: ::c_int = 1; +pub const KIPC_SOCKBUF_WASTE: ::c_int = 2; +pub const KIPC_SOMAXCONN: ::c_int = 3; +pub const KIPC_MAX_LINKHDR: ::c_int = 4; +pub const KIPC_MAX_PROTOHDR: ::c_int = 5; +pub const KIPC_MAX_HDR: ::c_int = 6; +pub const KIPC_MAX_DATALEN: ::c_int = 7; +pub const KIPC_MBSTAT: ::c_int = 8; +pub const KIPC_NMBCLUSTERS: ::c_int = 9; +pub const KIPC_SOQLIMITCOMPAT: ::c_int = 10; +pub const VM_METER: ::c_int = 1; +pub const VM_LOADAVG: ::c_int = 2; +pub const VM_MACHFACTOR: ::c_int = 4; +pub const VM_SWAPUSAGE: ::c_int = 5; +pub const VM_MAXID: ::c_int = 6; +pub const HW_MACHINE: ::c_int = 1; +pub const HW_MODEL: ::c_int = 2; +pub const HW_NCPU: ::c_int = 3; +pub const HW_BYTEORDER: ::c_int = 4; +pub const HW_PHYSMEM: ::c_int = 5; +pub const HW_USERMEM: ::c_int = 6; +pub const HW_PAGESIZE: ::c_int = 7; +pub const HW_DISKNAMES: ::c_int = 8; +pub const HW_DISKSTATS: ::c_int = 9; +pub const HW_EPOCH: ::c_int = 10; +pub const HW_FLOATINGPT: ::c_int = 11; +pub const HW_MACHINE_ARCH: ::c_int = 12; +pub const HW_VECTORUNIT: ::c_int = 13; +pub const HW_BUS_FREQ: ::c_int = 14; +pub const HW_CPU_FREQ: ::c_int = 15; +pub const HW_CACHELINE: ::c_int = 16; +pub const HW_L1ICACHESIZE: ::c_int = 17; +pub const HW_L1DCACHESIZE: ::c_int = 18; +pub const HW_L2SETTINGS: ::c_int = 19; +pub const HW_L2CACHESIZE: ::c_int = 20; +pub const HW_L3SETTINGS: ::c_int = 21; +pub const HW_L3CACHESIZE: ::c_int = 22; +pub const HW_TB_FREQ: ::c_int = 23; +pub const HW_MEMSIZE: ::c_int = 24; +pub const HW_AVAILCPU: ::c_int = 25; +pub const HW_MAXID: ::c_int = 26; +pub const USER_CS_PATH: ::c_int = 1; +pub const USER_BC_BASE_MAX: ::c_int = 2; +pub const USER_BC_DIM_MAX: ::c_int = 3; +pub const USER_BC_SCALE_MAX: ::c_int = 4; +pub const USER_BC_STRING_MAX: ::c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: ::c_int = 6; +pub const USER_EXPR_NEST_MAX: ::c_int = 7; +pub const USER_LINE_MAX: ::c_int = 8; +pub const USER_RE_DUP_MAX: ::c_int = 9; +pub const USER_POSIX2_VERSION: ::c_int = 10; +pub const USER_POSIX2_C_BIND: ::c_int = 11; +pub const USER_POSIX2_C_DEV: ::c_int = 12; +pub const USER_POSIX2_CHAR_TERM: ::c_int = 13; +pub const USER_POSIX2_FORT_DEV: ::c_int = 14; +pub const USER_POSIX2_FORT_RUN: ::c_int = 15; +pub const USER_POSIX2_LOCALEDEF: ::c_int = 16; +pub const USER_POSIX2_SW_DEV: ::c_int = 17; +pub const USER_POSIX2_UPE: ::c_int = 18; +pub const USER_STREAM_MAX: ::c_int = 19; +pub const USER_TZNAME_MAX: ::c_int = 20; +pub const USER_MAXID: ::c_int = 21; +pub const CTL_DEBUG_NAME: ::c_int = 0; +pub const CTL_DEBUG_VALUE: ::c_int = 1; +pub const CTL_DEBUG_MAXID: ::c_int = 20; + +pub const PRIO_DARWIN_THREAD: ::c_int = 3; +pub const PRIO_DARWIN_PROCESS: ::c_int = 4; +pub const PRIO_DARWIN_BG: ::c_int = 0x1000; +pub const PRIO_DARWIN_NONUI: ::c_int = 0x1001; + +pub const SEM_FAILED: *mut sem_t = -1isize as *mut ::sem_t; + +pub const AI_PASSIVE: ::c_int = 0x00000001; +pub const AI_CANONNAME: ::c_int = 0x00000002; +pub const AI_NUMERICHOST: ::c_int = 0x00000004; +pub const AI_NUMERICSERV: ::c_int = 0x00001000; +pub const AI_MASK: ::c_int = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | + AI_NUMERICSERV | AI_ADDRCONFIG; +pub const AI_ALL: ::c_int = 0x00000100; +pub const AI_V4MAPPED_CFG: ::c_int = 0x00000200; +pub const AI_ADDRCONFIG: ::c_int = 0x00000400; +pub const AI_V4MAPPED: ::c_int = 0x00000800; +pub const AI_DEFAULT: ::c_int = AI_V4MAPPED_CFG | AI_ADDRCONFIG; +pub const AI_UNUSABLE: ::c_int = 0x10000000; + +pub const SIGEV_NONE: ::c_int = 0; +pub const SIGEV_SIGNAL: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 3; + +pub const AIO_CANCELED: ::c_int = 2; +pub const AIO_NOTCANCELED: ::c_int = 4; +pub const AIO_ALLDONE: ::c_int = 1; +pub const AIO_LISTIO_MAX: ::c_int = 16; +pub const LIO_NOP: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 2; +pub const LIO_READ: ::c_int = 1; +pub const LIO_WAIT: ::c_int = 2; +pub const LIO_NOWAIT: ::c_int = 1; + +pub const WEXITED: ::c_int = 0x00000004; +pub const WSTOPPED: ::c_int = 0x00000008; +pub const WCONTINUED: ::c_int = 0x00000010; +pub const WNOWAIT: ::c_int = 0x00000020; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const XATTR_NOFOLLOW: ::c_int = 0x0001; +pub const XATTR_CREATE: ::c_int = 0x0002; +pub const XATTR_REPLACE: ::c_int = 0x0004; +pub const XATTR_NOSECURITY: ::c_int = 0x0008; +pub const XATTR_NODEFAULT: ::c_int = 0x0010; +pub const XATTR_SHOWCOMPRESSION: ::c_int = 0x0020; + +pub const NET_RT_IFLIST2: ::c_int = 0x0006; + +// net/route.h +pub const RTF_UP: ::c_int = 0x1; +pub const RTF_GATEWAY: ::c_int = 0x2; +pub const RTF_HOST: ::c_int = 0x4; +pub const RTF_REJECT: ::c_int = 0x8; +pub const RTF_DYNAMIC: ::c_int = 0x10; +pub const RTF_MODIFIED: ::c_int = 0x20; +pub const RTF_DONE: ::c_int = 0x40; +pub const RTF_DELCLONE: ::c_int = 0x80; +pub const RTF_CLONING: ::c_int = 0x100; +pub const RTF_XRESOLVE: ::c_int = 0x200; +pub const RTF_LLINFO: ::c_int = 0x400; +pub const RTF_STATIC: ::c_int = 0x800; +pub const RTF_BLACKHOLE: ::c_int = 0x1000; +pub const RTF_NOIFREF: ::c_int = 0x2000; +pub const RTF_PROTO2: ::c_int = 0x4000; +pub const RTF_PROTO1: ::c_int = 0x8000; +pub const RTF_PRCLONING: ::c_int = 0x10000; +pub const RTF_WASCLONED: ::c_int = 0x20000; +pub const RTF_PROTO3: ::c_int = 0x40000; +pub const RTF_PINNED: ::c_int = 0x100000; +pub const RTF_LOCAL: ::c_int = 0x200000; +pub const RTF_BROADCAST: ::c_int = 0x400000; +pub const RTF_MULTICAST: ::c_int = 0x800000; +pub const RTF_IFSCOPE: ::c_int = 0x1000000; +pub const RTF_CONDEMNED: ::c_int = 0x2000000; +pub const RTF_IFREF: ::c_int = 0x4000000; +pub const RTF_PROXY: ::c_int = 0x8000000; +pub const RTF_ROUTER: ::c_int = 0x10000000; + +pub const RTM_VERSION: ::c_int = 5; + +// Message types +pub const RTM_ADD: ::c_int = 0x1; +pub const RTM_DELETE: ::c_int = 0x2; +pub const RTM_CHANGE: ::c_int = 0x3; +pub const RTM_GET: ::c_int = 0x4; +pub const RTM_LOSING: ::c_int = 0x5; +pub const RTM_REDIRECT: ::c_int = 0x6; +pub const RTM_MISS: ::c_int = 0x7; +pub const RTM_LOCK: ::c_int = 0x8; +pub const RTM_OLDADD: ::c_int = 0x9; +pub const RTM_OLDDEL: ::c_int = 0xa; +pub const RTM_RESOLVE: ::c_int = 0xb; +pub const RTM_NEWADDR: ::c_int = 0xc; +pub const RTM_DELADDR: ::c_int = 0xd; +pub const RTM_IFINFO: ::c_int = 0xe; +pub const RTM_NEWMADDR: ::c_int = 0xf; +pub const RTM_DELMADDR: ::c_int = 0x10; +pub const RTM_IFINFO2: ::c_int = 0x12; +pub const RTM_NEWMADDR2: ::c_int = 0x13; +pub const RTM_GET2: ::c_int = 0x14; + +// Bitmask values for rtm_inits and rmx_locks. +pub const RTV_MTU: ::c_int = 0x1; +pub const RTV_HOPCOUNT: ::c_int = 0x2; +pub const RTV_EXPIRE: ::c_int = 0x4; +pub const RTV_RPIPE: ::c_int = 0x8; +pub const RTV_SPIPE: ::c_int = 0x10; +pub const RTV_SSTHRESH: ::c_int = 0x20; +pub const RTV_RTT: ::c_int = 0x40; +pub const RTV_RTTVAR: ::c_int = 0x80; + +// Bitmask values for rtm_addrs. +pub const RTA_DST: ::c_int = 0x1; +pub const RTA_GATEWAY: ::c_int = 0x2; +pub const RTA_NETMASK: ::c_int = 0x4; +pub const RTA_GENMASK: ::c_int = 0x8; +pub const RTA_IFP: ::c_int = 0x10; +pub const RTA_IFA: ::c_int = 0x20; +pub const RTA_AUTHOR: ::c_int = 0x40; +pub const RTA_BRD: ::c_int = 0x80; + +// Index offsets for sockaddr array for alternate internal encoding. +pub const RTAX_DST: ::c_int = 0; +pub const RTAX_GATEWAY: ::c_int = 1; +pub const RTAX_NETMASK: ::c_int = 2; +pub const RTAX_GENMASK: ::c_int = 3; +pub const RTAX_IFP: ::c_int = 4; +pub const RTAX_IFA: ::c_int = 5; +pub const RTAX_AUTHOR: ::c_int = 6; +pub const RTAX_BRD: ::c_int = 7; +pub const RTAX_MAX: ::c_int = 8; + +pub const KERN_PROCARGS2: ::c_int = 49; + +pub const PROC_PIDTASKALLINFO: ::c_int = 2; +pub const PROC_PIDTASKINFO: ::c_int = 4; +pub const PROC_PIDTHREADINFO: ::c_int = 5; +pub const MAXCOMLEN: usize = 16; +pub const MAXTHREADNAMESIZE: usize = 64; + +pub const XUCRED_VERSION: ::c_uint = 0; + +pub const LC_SEGMENT: u32 = 0x1; +pub const LC_SEGMENT_64: u32 = 0x19; + +pub const MH_MAGIC: u32 = 0xfeedface; +pub const MH_MAGIC_64: u32 = 0xfeedfacf; + +// net/if_utun.h +pub const UTUN_OPT_FLAGS: ::c_int = 1; +pub const UTUN_OPT_IFNAME: ::c_int = 2; + +// net/bpf.h +pub const DLT_NULL: ::c_uint = 0; // no link-layer encapsulation +pub const DLT_EN10MB: ::c_uint = 1; // Ethernet (10Mb) +pub const DLT_EN3MB: ::c_uint = 2; // Experimental Ethernet (3Mb) +pub const DLT_AX25: ::c_uint = 3; // Amateur Radio AX.25 +pub const DLT_PRONET: ::c_uint = 4; // Proteon ProNET Token Ring +pub const DLT_CHAOS: ::c_uint = 5; // Chaos +pub const DLT_IEEE802: ::c_uint = 6; // IEEE 802 Networks +pub const DLT_ARCNET: ::c_uint = 7; // ARCNET +pub const DLT_SLIP: ::c_uint = 8; // Serial Line IP +pub const DLT_PPP: ::c_uint = 9; // Point-to-point Protocol +pub const DLT_FDDI: ::c_uint = 10; // FDDI +pub const DLT_ATM_RFC1483: ::c_uint = 11; // LLC/SNAP encapsulated atm +pub const DLT_RAW: ::c_uint = 12; // raw IP +pub const DLT_LOOP: ::c_uint = 108; + +// https://github.com/apple/darwin-xnu/blob/master/bsd/net/bpf.h#L100 +// sizeof(int32_t) +pub const BPF_ALIGNMENT: ::c_int = 4; + +// sys/spawn.h: +pub const POSIX_SPAWN_RESETIDS: ::c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: ::c_int = 0x02; +pub const POSIX_SPAWN_SETSIGDEF: ::c_int = 0x04; +pub const POSIX_SPAWN_SETSIGMASK: ::c_int = 0x08; +pub const POSIX_SPAWN_SETEXEC: ::c_int = 0x40; +pub const POSIX_SPAWN_START_SUSPENDED: ::c_int = 0x80; +pub const POSIX_SPAWN_CLOEXEC_DEFAULT: ::c_int = 0x4000; + +// sys/ipc.h: +pub const IPC_CREAT: ::c_int = 0x200; +pub const IPC_EXCL: ::c_int = 0x400; +pub const IPC_NOWAIT: ::c_int = 0x800; +pub const IPC_PRIVATE: key_t = 0; + +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; + +pub const IPC_R: ::c_int = 0x100; +pub const IPC_W: ::c_int = 0x80; +pub const IPC_M: ::c_int = 0x1000; + +// sys/sem.h +pub const SEM_UNDO: ::c_int = 0o10000; + +pub const GETNCNT: ::c_int = 3; +pub const GETPID: ::c_int = 4; +pub const GETVAL: ::c_int = 5; +pub const GETALL: ::c_int = 6; +pub const GETZCNT: ::c_int = 7; +pub const SETVAL: ::c_int = 8; +pub const SETALL: ::c_int = 9; + +// sys/shm.h +pub const SHM_RDONLY: ::c_int = 0x1000; +pub const SHM_RND: ::c_int = 0x2000; +pub const SHMLBA: ::c_int = 4096; +pub const SHM_R: ::c_int = IPC_R; +pub const SHM_W: ::c_int = IPC_W; + +// Flags for chflags(2) +pub const UF_SETTABLE: ::c_uint = 0x0000ffff; +pub const UF_NODUMP: ::c_uint = 0x00000001; +pub const UF_IMMUTABLE: ::c_uint = 0x00000002; +pub const UF_APPEND: ::c_uint = 0x00000004; +pub const UF_OPAQUE: ::c_uint = 0x00000008; +pub const UF_COMPRESSED: ::c_uint = 0x00000020; +pub const UF_TRACKED: ::c_uint = 0x00000040; +pub const SF_SETTABLE: ::c_uint = 0xffff0000; +pub const SF_ARCHIVED: ::c_uint = 0x00010000; +pub const SF_IMMUTABLE: ::c_uint = 0x00020000; +pub const SF_APPEND: ::c_uint = 0x00040000; +pub const UF_HIDDEN: ::c_uint = 0x00008000; + +cfg_if! { + if #[cfg(libc_const_size_of)] { + fn __DARWIN_ALIGN32(p: usize) -> usize { + const __DARWIN_ALIGNBYTES32: usize = ::mem::size_of::() - 1; + p + __DARWIN_ALIGNBYTES32 & !__DARWIN_ALIGNBYTES32 + } + } else { + fn __DARWIN_ALIGN32(p: usize) -> usize { + let __DARWIN_ALIGNBYTES32: usize = ::mem::size_of::() - 1; + p + __DARWIN_ALIGNBYTES32 & !__DARWIN_ALIGNBYTES32 + } + } +} + +f! { + pub fn CMSG_NXTHDR(mhdr: *const ::msghdr, + cmsg: *const ::cmsghdr) -> *mut ::cmsghdr { + if cmsg.is_null() { + return ::CMSG_FIRSTHDR(mhdr); + }; + let cmsg_len = (*cmsg).cmsg_len as usize; + let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len as usize); + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if next + __DARWIN_ALIGN32(::mem::size_of::<::cmsghdr>()) > max { + 0 as *mut ::cmsghdr + } else { + next as *mut ::cmsghdr + } + } + + pub fn CMSG_DATA(cmsg: *const ::cmsghdr) -> *mut ::c_uchar { + (cmsg as *mut ::c_uchar) + .offset(__DARWIN_ALIGN32(::mem::size_of::<::cmsghdr>()) as isize) + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (__DARWIN_ALIGN32(::mem::size_of::<::cmsghdr>()) + + __DARWIN_ALIGN32(length as usize)) + as ::c_uint + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + (__DARWIN_ALIGN32(::mem::size_of::<::cmsghdr>()) + length as usize) + as ::c_uint + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + status >> 8 + } + + pub fn _WSTATUS(status: ::c_int) -> ::c_int { + status & 0x7f + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + _WSTATUS(status) == _WSTOPPED && WSTOPSIG(status) == 0x13 + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + _WSTATUS(status) != _WSTOPPED && _WSTATUS(status) != 0 + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + _WSTATUS(status) == _WSTOPPED && WSTOPSIG(status) != 0x13 + } +} + +extern { + #[deprecated(since="0.2.49", note="Deprecated in MacOSX 10.5")] + #[link_name = "daemon$1050"] + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[deprecated(since="0.2.49", note="Deprecated in MacOSX 10.10")] + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + #[deprecated(since="0.2.49", note="Deprecated in MacOSX 10.10")] + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_fsync(op: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_error(aiocbp: *const aiocb) -> ::c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "aio_suspend$UNIX2003")] + pub fn aio_suspend(aiocb_list: *const *const aiocb, nitems: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn aio_cancel(fd: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn chflags(path: *const ::c_char, flags: ::c_uint) -> ::c_int; + pub fn fchflags(fd: ::c_int, flags: ::c_uint) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn lio_listio(mode: ::c_int, aiocb_list: *const *mut aiocb, + nitems: ::c_int, sevp: *mut sigevent) -> ::c_int; + + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + pub fn utmpxname(file: *const ::c_char) -> ::c_int; + + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn mincore(addr: *const ::c_void, len: ::size_t, + vec: *mut ::c_char) -> ::c_int; + pub fn sysctlnametomib(name: *const ::c_char, + mibp: *mut ::c_int, + sizep: *mut ::size_t) + -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "mprotect$UNIX2003")] + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn semget(key: key_t, nsems: ::c_int, semflg: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "semctl$UNIX2003")] + pub fn semctl(semid: ::c_int, + semnum: ::c_int, + cmd: ::c_int, ...) -> ::c_int; + pub fn semop(semid: ::c_int, sops: *mut sembuf, nsops: ::size_t) -> ::c_int; + pub fn shm_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn ftok(pathname : *const c_char, proj_id : ::c_int) -> key_t; + pub fn shmat(shmid: ::c_int, shmaddr: *const ::c_void, + shmflg: ::c_int) -> *mut ::c_void; + pub fn shmdt(shmaddr: *const ::c_void) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "shmctl$UNIX2003")] + pub fn shmctl(shmid: ::c_int, cmd: ::c_int, + buf: *mut ::shmid_ds) -> ::c_int; + pub fn shmget(key: key_t, size: ::size_t, shmflg: ::c_int) -> ::c_int; + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_uint, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn sysctlbyname(name: *const ::c_char, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn mach_absolute_time() -> u64; + pub fn mach_timebase_info(info: *mut ::mach_timebase_info) -> ::c_int; + pub fn pthread_setname_np(name: *const ::c_char) -> ::c_int; + pub fn pthread_get_stackaddr_np(thread: ::pthread_t) -> *mut ::c_void; + pub fn pthread_get_stacksize_np(thread: ::pthread_t) -> ::size_t; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn __error() -> *mut ::c_int; + pub fn backtrace(buf: *mut *mut ::c_void, + sz: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "macos", link_name = "statfs$INODE64")] + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + #[cfg_attr(target_os = "macos", link_name = "fstatfs$INODE64")] + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + pub fn kevent(kq: ::c_int, + changelist: *const ::kevent, + nchanges: ::c_int, + eventlist: *mut ::kevent, + nevents: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn kevent64(kq: ::c_int, + changelist: *const ::kevent64_s, + nchanges: ::c_int, + eventlist: *mut ::kevent64_s, + nevents: ::c_int, + flags: ::c_uint, + timeout: *const ::timespec) -> ::c_int; + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + flags: ::c_int, + data: *mut ::c_void) -> ::c_int; + pub fn ptrace(request: ::c_int, + pid: ::pid_t, + addr: *mut ::c_char, + data: ::c_int) -> ::c_int; + pub fn quotactl(special: *const ::c_char, + cmd: ::c_int, + id: ::c_int, + data: *mut ::c_char) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::c_int) -> ::c_int; + pub fn sendfile(fd: ::c_int, + s: ::c_int, + offset: ::off_t, + len: *mut ::off_t, + hdtr: *mut ::sf_hdtr, + flags: ::c_int) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::c_int; + pub fn forkpty(amaster: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::pid_t; + pub fn login_tty(fd: ::c_int) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t) -> ::c_int; + pub fn localeconv_l(loc: ::locale_t) -> *mut lconv; + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn querylocale(mask: ::c_int, loc: ::locale_t) -> *const ::c_char; + pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; + pub fn getdomainname(name: *mut ::c_char, len: ::c_int) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::c_int) -> ::c_int; + pub fn getxattr(path: *const ::c_char, name: *const ::c_char, + value: *mut ::c_void, size: ::size_t, position: u32, + flags: ::c_int) -> ::ssize_t; + pub fn fgetxattr(filedes: ::c_int, name: *const ::c_char, + value: *mut ::c_void, size: ::size_t, position: u32, + flags: ::c_int) -> ::ssize_t; + pub fn setxattr(path: *const ::c_char, name: *const ::c_char, + value: *const ::c_void, size: ::size_t, position: u32, + flags: ::c_int) -> ::c_int; + pub fn fsetxattr(filedes: ::c_int, name: *const ::c_char, + value: *const ::c_void, size: ::size_t, position: u32, + flags: ::c_int) -> ::c_int; + pub fn listxattr(path: *const ::c_char, list: *mut ::c_char, + size: ::size_t, flags: ::c_int) -> ::ssize_t; + pub fn flistxattr(filedes: ::c_int, list: *mut ::c_char, + size: ::size_t, flags: ::c_int) -> ::ssize_t; + pub fn removexattr(path: *const ::c_char, name: *const ::c_char, + flags: ::c_int) -> ::c_int; + pub fn renamex_np(from: *const ::c_char, to: *const ::c_char, + flags: ::c_uint) -> ::c_int; + pub fn renameatx_np(fromfd: ::c_int, from: *const ::c_char, + tofd: ::c_int, to: *const ::c_char, + flags: ::c_uint) -> ::c_int; + pub fn fremovexattr(filedes: ::c_int, name: *const ::c_char, + flags: ::c_int) -> ::c_int; + + pub fn getgrouplist(name: *const ::c_char, + basegid: ::c_int, + groups: *mut ::c_int, + ngroups: *mut ::c_int) -> ::c_int; + pub fn initgroups(user: *const ::c_char, basegroup: ::c_int) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "waitid$UNIX2003")] + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + pub fn brk(addr: *const ::c_void) -> *mut ::c_void; + pub fn sbrk(increment: ::c_int) -> *mut ::c_void; + pub fn settimeofday(tv: *const ::timeval, tz: *const ::timezone) -> ::c_int; + pub fn _dyld_image_count() -> u32; + pub fn _dyld_get_image_header(image_index: u32) -> *const mach_header; + pub fn _dyld_get_image_vmaddr_slide(image_index: u32) -> ::intptr_t; + pub fn _dyld_get_image_name(image_index: u32) -> *const ::c_char; + + pub fn posix_spawn(pid: *mut ::pid_t, + path: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnp(pid: *mut ::pid_t, + file: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_getsigdefault(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigdefault(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getsigmask(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigmask(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, + flags: *mut ::c_short) -> ::c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, + flags: ::c_short) -> ::c_int; + pub fn posix_spawnattr_getpgroup(attr: *const posix_spawnattr_t, + flags: *mut ::pid_t) -> ::c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, + flags: ::pid_t) -> ::c_int; + + pub fn posix_spawn_file_actions_init( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_destroy( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + path: *const ::c_char, + oflag: ::c_int, + mode: ::mode_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + ) -> ::c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + newfd: ::c_int, + ) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "arm", target_arch = "x86"))] { + mod b32; + pub use self::b32::*; + } else if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs new file mode 100644 index 000000000..e91b351cc --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs @@ -0,0 +1,1030 @@ +pub type c_char = i8; +pub type clock_t = u64; +pub type ino_t = u64; +pub type lwpid_t = i32; +pub type nlink_t = u32; +pub type blksize_t = i64; +pub type clockid_t = ::c_ulong; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type time_t = i64; +pub type suseconds_t = i64; + +pub type uuid_t = ::uuid; + +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; + +pub type mqd_t = ::c_int; +pub type sem_t = *mut sem; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum sem {} +impl ::Copy for sem {} +impl ::Clone for sem { + fn clone(&self) -> sem { *self } +} + +s! { + pub struct exit_status { + pub e_termination: u16, + pub e_exit: u16 + } + + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_offset: ::off_t, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: sigevent, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + _aio_val: ::c_int, + _aio_err: ::c_int + } + + pub struct uuid { + pub time_low: u32, + pub time_mid: u16, + pub time_hi_and_version: u16, + pub clock_seq_hi_and_reserved: u8, + pub clock_seq_low: u8, + pub node: [u8; 6], + } + + pub struct mq_attr { + pub mq_flags: ::c_long, + pub mq_maxmsg: ::c_long, + pub mq_msgsize: ::c_long, + pub mq_curmsgs: ::c_long, + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + // The union is 8-byte in size, so it is aligned at a 8-byte offset. + #[cfg(target_pointer_width = "64")] + __unused1: ::c_int, + pub sigev_signo: ::c_int, //actually a union + // pad the union + #[cfg(target_pointer_width = "64")] + __unused2: ::c_int, + pub sigev_value: ::sigval, + __unused3: *mut ::c_void //actually a function pointer + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + pub f_owner: ::uid_t, + pub f_type: ::c_uint, + pub f_syncreads: u64, + pub f_syncwrites: u64, + pub f_asyncreads: u64, + pub f_asyncwrites: u64, + pub f_fsid_uuid: ::uuid_t, + pub f_uid_uuid: ::uuid_t, + } + + pub struct stat { + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_dev: ::dev_t, + pub st_mode: ::mode_t, + pub st_padding1: ::uint16_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::int64_t, + pub st_blksize: ::uint32_t, + pub st_flags: ::uint32_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_qspare1: ::int64_t, + pub st_qspare2: ::int64_t, + } + + pub struct if_data { + pub ifi_type: ::c_uchar, + pub ifi_physical: ::c_uchar, + pub ifi_addrlen: ::c_uchar, + pub ifi_hdrlen: ::c_uchar, + pub ifi_recvquota: ::c_uchar, + pub ifi_xmitquota: ::c_uchar, + pub ifi_mtu: ::c_ulong, + pub ifi_metric: ::c_ulong, + pub ifi_link_state: ::c_ulong, + pub ifi_baudrate: u64, + pub ifi_ipackets: ::c_ulong, + pub ifi_ierrors: ::c_ulong, + pub ifi_opackets: ::c_ulong, + pub ifi_oerrors: ::c_ulong, + pub ifi_collisions: ::c_ulong, + pub ifi_ibytes: ::c_ulong, + pub ifi_obytes: ::c_ulong, + pub ifi_imcasts: ::c_ulong, + pub ifi_omcasts: ::c_ulong, + pub ifi_iqdrops: ::c_ulong, + pub ifi_noproto: ::c_ulong, + pub ifi_hwassist: ::c_ulong, + pub ifi_oqdrops: ::c_ulong, + pub ifi_lastchange: ::timeval, + } + + pub struct if_msghdr { + pub ifm_msglen: ::c_ushort, + pub ifm_version: ::c_uchar, + pub ifm_type: ::c_uchar, + pub ifm_addrs: ::c_int, + pub ifm_flags: ::c_int, + pub ifm_index: ::c_ushort, + pub ifm_data: if_data, + } + + pub struct sockaddr_dl { + pub sdl_len: ::c_uchar, + pub sdl_family: ::c_uchar, + pub sdl_index: ::c_ushort, + pub sdl_type: ::c_uchar, + pub sdl_nlen: ::c_uchar, + pub sdl_alen: ::c_uchar, + pub sdl_slen: ::c_uchar, + pub sdl_data: [::c_char; 12], + pub sdl_rcf: ::c_ushort, + pub sdl_route: [::c_ushort; 16], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_char, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } +} + +s_no_extra_traits! { + pub struct utmpx { + pub ut_name: [::c_char; 32], + pub ut_id: [::c_char; 4], + + pub ut_line: [::c_char; 32], + pub ut_host: [::c_char; 256], + + pub ut_unused: [u8; 16], + pub ut_session: u16, + pub ut_type: u16, + pub ut_pid: ::pid_t, + ut_exit: exit_status, + ut_ss: ::sockaddr_storage, + pub ut_tv: ::timeval, + pub ut_unused2: [u8; 16], + } + + pub struct dirent { + pub d_fileno: ::ino_t, + pub d_namlen: u16, + pub d_type: u8, + __unused1: u8, + __unused2: u32, + pub d_name: [::c_char; 256], + } + + pub struct statfs { + pub f_bsize: ::c_long, + pub f_iosize: ::c_long, + pub f_blocks: ::c_long, + pub f_bfree: ::c_long, + pub f_bavail: ::c_long, + pub f_files: ::c_long, + pub f_ffree: ::c_long, + pub f_fsid: ::fsid_t, + pub f_owner: ::uid_t, + pub f_type: ::int32_t, + pub f_flags: ::int32_t, + pub f_syncwrites: ::c_long, + pub f_asyncwrites: ::c_long, + pub f_fstypename: [::c_char; 16], + pub f_mntonname: [::c_char; 90], + pub f_syncreads: ::c_long, + pub f_asyncreads: ::c_long, + pub f_mntfromname: [::c_char; 90], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for utmpx { + fn eq(&self, other: &utmpx) -> bool { + self.ut_name == other.ut_name + && self.ut_id == other.ut_id + && self.ut_line == other.ut_line + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + && self.ut_unused == other.ut_unused + && self.ut_session == other.ut_session + && self.ut_type == other.ut_type + && self.ut_pid == other.ut_pid + && self.ut_exit == other.ut_exit + && self.ut_ss == other.ut_ss + && self.ut_tv == other.ut_tv + && self.ut_unused2 == other.ut_unused2 + } + } + impl Eq for utmpx {} + impl ::fmt::Debug for utmpx { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmpx") + .field("ut_name", &self.ut_name) + .field("ut_id", &self.ut_id) + .field("ut_line", &self.ut_line) + // FIXME: .field("ut_host", &self.ut_host) + .field("ut_unused", &self.ut_unused) + .field("ut_session", &self.ut_session) + .field("ut_type", &self.ut_type) + .field("ut_pid", &self.ut_pid) + .field("ut_exit", &self.ut_exit) + .field("ut_ss", &self.ut_ss) + .field("ut_tv", &self.ut_tv) + .field("ut_unused2", &self.ut_unused2) + .finish() + } + } + impl ::hash::Hash for utmpx { + fn hash(&self, state: &mut H) { + self.ut_name.hash(state); + self.ut_id.hash(state); + self.ut_line.hash(state); + self.ut_host.hash(state); + self.ut_unused.hash(state); + self.ut_session.hash(state); + self.ut_type.hash(state); + self.ut_pid.hash(state); + self.ut_exit.hash(state); + self.ut_ss.hash(state); + self.ut_tv.hash(state); + self.ut_unused2.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_fileno == other.d_fileno + && self.d_namlen == other.d_namlen + && self.d_type == other.d_type + // Ignore __unused1 + // Ignore __unused2 + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_fileno", &self.d_fileno) + .field("d_namlen", &self.d_namlen) + .field("d_type", &self.d_type) + // Ignore __unused1 + // Ignore __unused2 + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_fileno.hash(state); + self.d_namlen.hash(state); + self.d_type.hash(state); + // Ignore __unused1 + // Ignore __unused2 + self.d_name.hash(state); + } + } + + impl PartialEq for statfs { + fn eq(&self, other: &statfs) -> bool { + self.f_bsize == other.f_bsize + && self.f_iosize == other.f_iosize + && self.f_blocks == other.f_blocks + && self.f_bfree == other.f_bfree + && self.f_bavail == other.f_bavail + && self.f_files == other.f_files + && self.f_ffree == other.f_ffree + && self.f_fsid == other.f_fsid + && self.f_owner == other.f_owner + && self.f_type == other.f_type + && self.f_flags == other.f_flags + && self.f_syncwrites == other.f_syncwrites + && self.f_asyncwrites == other.f_asyncwrites + && self.f_fstypename == other.f_fstypename + && self + .f_mntonname + .iter() + .zip(other.f_mntonname.iter()) + .all(|(a,b)| a == b) + && self.f_syncreads == other.f_syncreads + && self.f_asyncreads == other.f_asyncreads + && self + .f_mntfromname + .iter() + .zip(other.f_mntfromname.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for statfs {} + impl ::fmt::Debug for statfs { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("statfs") + .field("f_bsize", &self.f_bsize) + .field("f_iosize", &self.f_iosize) + .field("f_blocks", &self.f_blocks) + .field("f_bfree", &self.f_bfree) + .field("f_bavail", &self.f_bavail) + .field("f_files", &self.f_files) + .field("f_ffree", &self.f_ffree) + .field("f_fsid", &self.f_fsid) + .field("f_owner", &self.f_owner) + .field("f_type", &self.f_type) + .field("f_flags", &self.f_flags) + .field("f_syncwrites", &self.f_syncwrites) + .field("f_asyncwrites", &self.f_asyncwrites) + // FIXME: .field("f_mntonname", &self.f_mntonname) + .field("f_syncreads", &self.f_syncreads) + .field("f_asyncreads", &self.f_asyncreads) + // FIXME: .field("f_mntfromname", &self.f_mntfromname) + .finish() + } + } + impl ::hash::Hash for statfs { + fn hash(&self, state: &mut H) { + self.f_bsize.hash(state); + self.f_iosize.hash(state); + self.f_blocks.hash(state); + self.f_bfree.hash(state); + self.f_bavail.hash(state); + self.f_files.hash(state); + self.f_ffree.hash(state); + self.f_fsid.hash(state); + self.f_owner.hash(state); + self.f_type.hash(state); + self.f_flags.hash(state); + self.f_syncwrites.hash(state); + self.f_asyncwrites.hash(state); + self.f_fstypename.hash(state); + self.f_mntonname.hash(state); + self.f_syncreads.hash(state); + self.f_asyncreads.hash(state); + self.f_mntfromname.hash(state); + } + } + } +} + +pub const RAND_MAX: ::c_int = 0x7fff_ffff; +pub const PTHREAD_STACK_MIN: ::size_t = 16384; +pub const SIGSTKSZ: ::size_t = 40960; +pub const MADV_INVAL: ::c_int = 10; +pub const MADV_SETMAP: ::c_int = 11; +pub const O_CLOEXEC: ::c_int = 0x00020000; +pub const O_DIRECTORY: ::c_int = 0x08000000; +pub const F_GETLK: ::c_int = 7; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; +pub const ENOMEDIUM: ::c_int = 93; +pub const EASYNC: ::c_int = 99; +pub const ELAST: ::c_int = 99; +pub const RLIMIT_POSIXLOCKS: ::c_int = 11; +pub const RLIM_NLIMITS: ::rlim_t = 12; + +pub const Q_GETQUOTA: ::c_int = 0x300; +pub const Q_SETQUOTA: ::c_int = 0x400; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_VIRTUAL: ::clockid_t = 1; +pub const CLOCK_PROF: ::clockid_t = 2; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; +pub const CLOCK_UPTIME: ::clockid_t = 5; +pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; +pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; +pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; +pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; +pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; +pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; +pub const CLOCK_SECOND: ::clockid_t = 13; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; + +pub const CTL_UNSPEC: ::c_int = 0; +pub const CTL_KERN: ::c_int = 1; +pub const CTL_VM: ::c_int = 2; +pub const CTL_VFS: ::c_int = 3; +pub const CTL_NET: ::c_int = 4; +pub const CTL_DEBUG: ::c_int = 5; +pub const CTL_HW: ::c_int = 6; +pub const CTL_MACHDEP: ::c_int = 7; +pub const CTL_USER: ::c_int = 8; +pub const CTL_P1003_1B: ::c_int = 9; +pub const CTL_LWKT: ::c_int = 10; +pub const CTL_MAXID: ::c_int = 11; +pub const KERN_OSTYPE: ::c_int = 1; +pub const KERN_OSRELEASE: ::c_int = 2; +pub const KERN_OSREV: ::c_int = 3; +pub const KERN_VERSION: ::c_int = 4; +pub const KERN_MAXVNODES: ::c_int = 5; +pub const KERN_MAXPROC: ::c_int = 6; +pub const KERN_MAXFILES: ::c_int = 7; +pub const KERN_ARGMAX: ::c_int = 8; +pub const KERN_SECURELVL: ::c_int = 9; +pub const KERN_HOSTNAME: ::c_int = 10; +pub const KERN_HOSTID: ::c_int = 11; +pub const KERN_CLOCKRATE: ::c_int = 12; +pub const KERN_VNODE: ::c_int = 13; +pub const KERN_PROC: ::c_int = 14; +pub const KERN_FILE: ::c_int = 15; +pub const KERN_PROF: ::c_int = 16; +pub const KERN_POSIX1: ::c_int = 17; +pub const KERN_NGROUPS: ::c_int = 18; +pub const KERN_JOB_CONTROL: ::c_int = 19; +pub const KERN_SAVED_IDS: ::c_int = 20; +pub const KERN_BOOTTIME: ::c_int = 21; +pub const KERN_NISDOMAINNAME: ::c_int = 22; +pub const KERN_UPDATEINTERVAL: ::c_int = 23; +pub const KERN_OSRELDATE: ::c_int = 24; +pub const KERN_NTP_PLL: ::c_int = 25; +pub const KERN_BOOTFILE: ::c_int = 26; +pub const KERN_MAXFILESPERPROC: ::c_int = 27; +pub const KERN_MAXPROCPERUID: ::c_int = 28; +pub const KERN_DUMPDEV: ::c_int = 29; +pub const KERN_IPC: ::c_int = 30; +pub const KERN_DUMMY: ::c_int = 31; +pub const KERN_PS_STRINGS: ::c_int = 32; +pub const KERN_USRSTACK: ::c_int = 33; +pub const KERN_LOGSIGEXIT: ::c_int = 34; +pub const KERN_IOV_MAX: ::c_int = 35; +pub const KERN_MAXPOSIXLOCKSPERUID: ::c_int = 36; +pub const KERN_MAXID: ::c_int = 37; +pub const KERN_PROC_ALL: ::c_int = 0; +pub const KERN_PROC_PID: ::c_int = 1; +pub const KERN_PROC_PGRP: ::c_int = 2; +pub const KERN_PROC_SESSION: ::c_int = 3; +pub const KERN_PROC_TTY: ::c_int = 4; +pub const KERN_PROC_UID: ::c_int = 5; +pub const KERN_PROC_RUID: ::c_int = 6; +pub const KERN_PROC_ARGS: ::c_int = 7; +pub const KERN_PROC_CWD: ::c_int = 8; +pub const KERN_PROC_PATHNAME: ::c_int = 9; +pub const KERN_PROC_FLAGMASK: ::c_int = 0x10; +pub const KERN_PROC_FLAG_LWP: ::c_int = 0x10; +pub const KIPC_MAXSOCKBUF: ::c_int = 1; +pub const KIPC_SOCKBUF_WASTE: ::c_int = 2; +pub const KIPC_SOMAXCONN: ::c_int = 3; +pub const KIPC_MAX_LINKHDR: ::c_int = 4; +pub const KIPC_MAX_PROTOHDR: ::c_int = 5; +pub const KIPC_MAX_HDR: ::c_int = 6; +pub const KIPC_MAX_DATALEN: ::c_int = 7; +pub const KIPC_MBSTAT: ::c_int = 8; +pub const KIPC_NMBCLUSTERS: ::c_int = 9; +pub const HW_MACHINE: ::c_int = 1; +pub const HW_MODEL: ::c_int = 2; +pub const HW_NCPU: ::c_int = 3; +pub const HW_BYTEORDER: ::c_int = 4; +pub const HW_PHYSMEM: ::c_int = 5; +pub const HW_USERMEM: ::c_int = 6; +pub const HW_PAGESIZE: ::c_int = 7; +pub const HW_DISKNAMES: ::c_int = 8; +pub const HW_DISKSTATS: ::c_int = 9; +pub const HW_FLOATINGPT: ::c_int = 10; +pub const HW_MACHINE_ARCH: ::c_int = 11; +pub const HW_MACHINE_PLATFORM: ::c_int = 12; +pub const HW_SENSORS: ::c_int = 13; +pub const HW_MAXID: ::c_int = 14; +pub const USER_CS_PATH: ::c_int = 1; +pub const USER_BC_BASE_MAX: ::c_int = 2; +pub const USER_BC_DIM_MAX: ::c_int = 3; +pub const USER_BC_SCALE_MAX: ::c_int = 4; +pub const USER_BC_STRING_MAX: ::c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: ::c_int = 6; +pub const USER_EXPR_NEST_MAX: ::c_int = 7; +pub const USER_LINE_MAX: ::c_int = 8; +pub const USER_RE_DUP_MAX: ::c_int = 9; +pub const USER_POSIX2_VERSION: ::c_int = 10; +pub const USER_POSIX2_C_BIND: ::c_int = 11; +pub const USER_POSIX2_C_DEV: ::c_int = 12; +pub const USER_POSIX2_CHAR_TERM: ::c_int = 13; +pub const USER_POSIX2_FORT_DEV: ::c_int = 14; +pub const USER_POSIX2_FORT_RUN: ::c_int = 15; +pub const USER_POSIX2_LOCALEDEF: ::c_int = 16; +pub const USER_POSIX2_SW_DEV: ::c_int = 17; +pub const USER_POSIX2_UPE: ::c_int = 18; +pub const USER_STREAM_MAX: ::c_int = 19; +pub const USER_TZNAME_MAX: ::c_int = 20; +pub const USER_MAXID: ::c_int = 21; +pub const CTL_P1003_1B_ASYNCHRONOUS_IO: ::c_int = 1; +pub const CTL_P1003_1B_MAPPED_FILES: ::c_int = 2; +pub const CTL_P1003_1B_MEMLOCK: ::c_int = 3; +pub const CTL_P1003_1B_MEMLOCK_RANGE: ::c_int = 4; +pub const CTL_P1003_1B_MEMORY_PROTECTION: ::c_int = 5; +pub const CTL_P1003_1B_MESSAGE_PASSING: ::c_int = 6; +pub const CTL_P1003_1B_PRIORITIZED_IO: ::c_int = 7; +pub const CTL_P1003_1B_PRIORITY_SCHEDULING: ::c_int = 8; +pub const CTL_P1003_1B_REALTIME_SIGNALS: ::c_int = 9; +pub const CTL_P1003_1B_SEMAPHORES: ::c_int = 10; +pub const CTL_P1003_1B_FSYNC: ::c_int = 11; +pub const CTL_P1003_1B_SHARED_MEMORY_OBJECTS: ::c_int = 12; +pub const CTL_P1003_1B_SYNCHRONIZED_IO: ::c_int = 13; +pub const CTL_P1003_1B_TIMERS: ::c_int = 14; +pub const CTL_P1003_1B_AIO_LISTIO_MAX: ::c_int = 15; +pub const CTL_P1003_1B_AIO_MAX: ::c_int = 16; +pub const CTL_P1003_1B_AIO_PRIO_DELTA_MAX: ::c_int = 17; +pub const CTL_P1003_1B_DELAYTIMER_MAX: ::c_int = 18; +pub const CTL_P1003_1B_UNUSED1: ::c_int = 19; +pub const CTL_P1003_1B_PAGESIZE: ::c_int = 20; +pub const CTL_P1003_1B_RTSIG_MAX: ::c_int = 21; +pub const CTL_P1003_1B_SEM_NSEMS_MAX: ::c_int = 22; +pub const CTL_P1003_1B_SEM_VALUE_MAX: ::c_int = 23; +pub const CTL_P1003_1B_SIGQUEUE_MAX: ::c_int = 24; +pub const CTL_P1003_1B_TIMER_MAX: ::c_int = 25; +pub const CTL_P1003_1B_MAXID: ::c_int = 26; + +pub const EVFILT_READ: ::int16_t = -1; +pub const EVFILT_WRITE: ::int16_t = -2; +pub const EVFILT_AIO: ::int16_t = -3; +pub const EVFILT_VNODE: ::int16_t = -4; +pub const EVFILT_PROC: ::int16_t = -5; +pub const EVFILT_SIGNAL: ::int16_t = -6; +pub const EVFILT_TIMER: ::int16_t = -7; +pub const EVFILT_EXCEPT: ::int16_t = -8; +pub const EVFILT_USER: ::int16_t = -9; +pub const EVFILT_FS: ::int16_t = -10; + +pub const EV_ADD: ::uint16_t = 0x1; +pub const EV_DELETE: ::uint16_t = 0x2; +pub const EV_ENABLE: ::uint16_t = 0x4; +pub const EV_DISABLE: ::uint16_t = 0x8; +pub const EV_ONESHOT: ::uint16_t = 0x10; +pub const EV_CLEAR: ::uint16_t = 0x20; +pub const EV_RECEIPT: ::uint16_t = 0x40; +pub const EV_DISPATCH: ::uint16_t = 0x80; +pub const EV_NODATA: ::uint16_t = 0x1000; +pub const EV_FLAG1: ::uint16_t = 0x2000; +pub const EV_ERROR: ::uint16_t = 0x4000; +pub const EV_EOF: ::uint16_t = 0x8000; +pub const EV_SYSFLAGS: ::uint16_t = 0xf000; + +pub const NOTE_TRIGGER: ::uint32_t = 0x01000000; +pub const NOTE_FFNOP: ::uint32_t = 0x00000000; +pub const NOTE_FFAND: ::uint32_t = 0x40000000; +pub const NOTE_FFOR: ::uint32_t = 0x80000000; +pub const NOTE_FFCOPY: ::uint32_t = 0xc0000000; +pub const NOTE_FFCTRLMASK: ::uint32_t = 0xc0000000; +pub const NOTE_FFLAGSMASK: ::uint32_t = 0x00ffffff; +pub const NOTE_LOWAT: ::uint32_t = 0x00000001; +pub const NOTE_OOB: ::uint32_t = 0x00000002; +pub const NOTE_DELETE: ::uint32_t = 0x00000001; +pub const NOTE_WRITE: ::uint32_t = 0x00000002; +pub const NOTE_EXTEND: ::uint32_t = 0x00000004; +pub const NOTE_ATTRIB: ::uint32_t = 0x00000008; +pub const NOTE_LINK: ::uint32_t = 0x00000010; +pub const NOTE_RENAME: ::uint32_t = 0x00000020; +pub const NOTE_REVOKE: ::uint32_t = 0x00000040; +pub const NOTE_EXIT: ::uint32_t = 0x80000000; +pub const NOTE_FORK: ::uint32_t = 0x40000000; +pub const NOTE_EXEC: ::uint32_t = 0x20000000; +pub const NOTE_PDATAMASK: ::uint32_t = 0x000fffff; +pub const NOTE_PCTRLMASK: ::uint32_t = 0xf0000000; +pub const NOTE_TRACK: ::uint32_t = 0x00000001; +pub const NOTE_TRACKERR: ::uint32_t = 0x00000002; +pub const NOTE_CHILD: ::uint32_t = 0x00000004; + +pub const SO_SNDSPACE: ::c_int = 0x100a; +pub const SO_CPUHINT: ::c_int = 0x1030; + +pub const PT_FIRSTMACH: ::c_int = 32; + +// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/net/if.h#L101 +pub const IFF_UP: ::c_int = 0x1; // interface is up +pub const IFF_BROADCAST: ::c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x10; // interface is point-to-point link +pub const IFF_SMART: ::c_int = 0x20; // interface manages own routes +pub const IFF_RUNNING: ::c_int = 0x40; // resources allocated +pub const IFF_NOARP: ::c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE_COMPAT: ::c_int = 0x400; // was transmission in progress +pub const IFF_SIMPLEX: ::c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: ::c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: ::c_int = 0x8000; // supports multicast +// was interface is in polling mode +pub const IFF_POLLING_COMPAT: ::c_int = 0x10000; +pub const IFF_PPROMISC: ::c_int = 0x20000; // user-requested promisc mode +pub const IFF_MONITOR: ::c_int = 0x40000; // user-requested monitor mode +pub const IFF_STATICARP: ::c_int = 0x80000; // static ARP +pub const IFF_NPOLLING: ::c_int = 0x100000; // interface is in polling mode +pub const IFF_IDIRECT: ::c_int = 0x200000; // direct input + +// +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: ::c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: ::c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: ::c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: ::c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: ::c_int = 11; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: ::c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: ::c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: ::c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: ::c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: ::c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: ::c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: ::c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: ::c_int = 21; +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: ::c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: ::c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: ::c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: ::c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: ::c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: ::c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: ::c_int = 30; +/// Network Services +pub const IPPROTO_NSP: ::c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: ::c_int = 32; +/// Sequential Exchange +pub const IPPROTO_SEP: ::c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: ::c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: ::c_int = 35; +/// XTP +pub const IPPROTO_XTP: ::c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: ::c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: ::c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: ::c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: ::c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: ::c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: ::c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: ::c_int = 48; +/// BHA +pub const IPPROTO_BHA: ::c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: ::c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: ::c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: ::c_int = 54; +/// IP Mobility +pub const IPPROTO_MOBILE: ::c_int = 55; +/// Transport Layer Security +pub const IPPROTO_TLSP: ::c_int = 56; +/// SKIP +pub const IPPROTO_SKIP: ::c_int = 57; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: ::c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: ::c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: ::c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: ::c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: ::c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: ::c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: ::c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: ::c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: ::c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: ::c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: ::c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: ::c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: ::c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: ::c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: ::c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: ::c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: ::c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: ::c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: ::c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: ::c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: ::c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: ::c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: ::c_int = 83; +/// TTP +pub const IPPROTO_TTP: ::c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: ::c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: ::c_int = 86; +/// TCF +pub const IPPROTO_TCF: ::c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: ::c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: ::c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: ::c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: ::c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: ::c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: ::c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: ::c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: ::c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: ::c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: ::c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: ::c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: ::c_int = 100; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: ::c_int = 108; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: ::c_int = 103; +/// CARP +pub const IPPROTO_CARP: ::c_int = 112; +/// PGM +pub const IPPROTO_PGM: ::c_int = 113; +/// PFSYNC +pub const IPPROTO_PFSYNC: ::c_int = 240; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion, no longer used */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: ::c_int = 254; +pub const IPPROTO_MAX: ::c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: ::c_int = 257; + +/// Used by RSS: the layer3 protocol is unknown +pub const IPPROTO_UNKNOWN: ::c_int = 258; + +// sys/netinet/tcp.h +pub const TCP_SIGNATURE_ENABLE: ::c_int = 16; +pub const TCP_KEEPINIT: ::c_int = 32; +pub const TCP_FASTKEEP: ::c_int = 128; + +pub const AF_BLUETOOTH: ::c_int = 33; +pub const AF_MPLS: ::c_int = 34; +pub const AF_IEEE80211: ::c_int = 35; +pub const AF_MAX: ::c_int = 36; + +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_MAX: ::c_int = AF_MAX; + +pub const NET_RT_DUMP: ::c_int = 1; +pub const NET_RT_FLAGS: ::c_int = 2; +pub const NET_RT_IFLIST: ::c_int = 3; +pub const NET_RT_MAXID: ::c_int = 4; + +pub const SOMAXOPT_SIZE: ::c_int = 65536; + +#[doc(hidden)] +pub const NET_MAXID: ::c_int = AF_MAX; + +pub const MSG_UNUSED09: ::c_int = 0x00000200; +pub const MSG_NOSIGNAL: ::c_int = 0x00000400; +pub const MSG_SYNC: ::c_int = 0x00000800; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x00001000; +pub const MSG_FBLOCKING: ::c_int = 0x00010000; +pub const MSG_FNONBLOCKING: ::c_int = 0x00020000; +pub const MSG_FMASK: ::c_int = 0xFFFF0000; + +pub const EMPTY: ::c_short = 0; +pub const RUN_LVL: ::c_short = 1; +pub const BOOT_TIME: ::c_short = 2; +pub const OLD_TIME: ::c_short = 3; +pub const NEW_TIME: ::c_short = 4; +pub const INIT_PROCESS: ::c_short = 5; +pub const LOGIN_PROCESS: ::c_short = 6; +pub const USER_PROCESS: ::c_short = 7; +pub const DEAD_PROCESS: ::c_short = 8; + +pub const LC_COLLATE_MASK: ::c_int = (1 << 0); +pub const LC_CTYPE_MASK: ::c_int = (1 << 1); +pub const LC_MONETARY_MASK: ::c_int = (1 << 2); +pub const LC_NUMERIC_MASK: ::c_int = (1 << 3); +pub const LC_TIME_MASK: ::c_int = (1 << 4); +pub const LC_MESSAGES_MASK: ::c_int = (1 << 5); +pub const LC_ALL_MASK: ::c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const TIOCSIG: ::c_uint = 0x2000745f; +pub const BTUARTDISC: ::c_int = 0x7; +pub const TIOCDCDTIMESTAMP: ::c_uint = 0x40107458; +pub const TIOCISPTMASTER: ::c_uint = 0x20007455; +pub const TIOCMODG: ::c_uint = 0x40047403; +pub const TIOCMODS: ::c_ulong = 0x80047404; +pub const TIOCREMOTE: ::c_ulong = 0x80047469; + +// Constants used by "at" family of system calls. +pub const AT_FDCWD: ::c_int = 0xFFFAFDCD; // invalid file descriptor +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 1; +pub const AT_REMOVEDIR: ::c_int = 2; +pub const AT_EACCESS: ::c_int = 4; +pub const AT_SYMLINK_FOLLOW: ::c_int = 8; + +pub const VCHECKPT: usize = 19; + +pub const _PC_2_SYMLINKS: ::c_int = 22; +pub const _PC_TIMESTAMP_RESOLUTION: ::c_int = 23; + +pub const _SC_V7_ILP32_OFF32: ::c_int = 122; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 123; +pub const _SC_V7_LP64_OFF64: ::c_int = 124; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 125; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 126; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 127; + +pub const WCONTINUED: ::c_int = 4; +pub const WSTOPPED: ::c_int = 0o177; + +// Values for struct rtprio (type_ field) +pub const RTP_PRIO_REALTIME: ::c_ushort = 0; +pub const RTP_PRIO_NORMAL: ::c_ushort = 1; +pub const RTP_PRIO_IDLE: ::c_ushort = 2; +pub const RTP_PRIO_THREAD: ::c_ushort = 3; + +// Flags for chflags(2) +pub const UF_NOHISTORY: ::c_ulong = 0x00000040; +pub const UF_CACHE: ::c_ulong = 0x00000080; +pub const UF_XLINK: ::c_ulong = 0x00000100; +pub const SF_NOHISTORY: ::c_ulong = 0x00400000; +pub const SF_CACHE: ::c_ulong = 0x00800000; +pub const SF_XLINK: ::c_ulong = 0x01000000; + +fn _CMSG_ALIGN(n: usize) -> usize { + (n + 3) & !3 +} + +f! { + pub fn CMSG_DATA(cmsg: *const ::cmsghdr) -> *mut ::c_uchar { + (cmsg as *mut ::c_uchar) + .offset(_CMSG_ALIGN(::mem::size_of::<::cmsghdr>()) as isize) + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + (_CMSG_ALIGN(::mem::size_of::<::cmsghdr>()) + length as usize) + as ::c_uint + } + + pub fn CMSG_NXTHDR(mhdr: *const ::msghdr, cmsg: *const ::cmsghdr) + -> *mut ::cmsghdr + { + let next = cmsg as usize + _CMSG_ALIGN((*cmsg).cmsg_len as usize) + + _CMSG_ALIGN(::mem::size_of::<::cmsghdr>()); + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if next <= max { + (cmsg as usize + _CMSG_ALIGN((*cmsg).cmsg_len as usize)) + as *mut ::cmsghdr + } else { + 0 as *mut ::cmsghdr + } + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (_CMSG_ALIGN(::mem::size_of::<::cmsghdr>()) + + _CMSG_ALIGN(length as usize)) as ::c_uint + } +} + +extern { + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + + pub fn setutxdb(_type: ::c_uint, file: *mut ::c_char) -> ::c_int; + + pub fn aio_waitcomplete(iocbp: *mut *mut aiocb, + timeout: *mut ::timespec) -> ::c_int; + + pub fn freelocale(loc: ::locale_t); + + pub fn lwp_rtprio(function: ::c_int, pid: ::pid_t, lwpid: lwpid_t, + rtp: *mut super::rtprio) -> ::c_int; + + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs b/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs new file mode 100644 index 000000000..996abc5e3 --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/aarch64.rs @@ -0,0 +1,44 @@ +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type time_t = i64; +pub type suseconds_t = i64; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::fflags_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + } +} + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const MAP_32BIT: ::c_int = 0x00080000; diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs b/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs new file mode 100644 index 000000000..945aca98c --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/arm.rs @@ -0,0 +1,47 @@ +pub type c_char = u8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type time_t = i64; +pub type suseconds_t = i32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_atime_pad: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_mtime_pad: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ctime_pad: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::fflags_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + pub st_birthtime_pad: ::c_long, + } +} + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_int>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 4 - 1; + } +} +pub const MAP_32BIT: ::c_int = 0x00080000; diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs b/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs new file mode 100644 index 000000000..3ce96e896 --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -0,0 +1,1473 @@ +pub type fflags_t = u32; +pub type clock_t = i32; +pub type ino_t = u32; +pub type lwpid_t = i32; +pub type nlink_t = u16; +pub type blksize_t = i32; +pub type clockid_t = ::c_int; +pub type sem_t = _sem; + +pub type fsblkcnt_t = ::uint64_t; +pub type fsfilcnt_t = ::uint64_t; +pub type idtype_t = ::c_uint; + +pub type key_t = ::c_long; +pub type msglen_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; + +pub type mqd_t = *mut ::c_void; +pub type posix_spawnattr_t = *mut ::c_void; +pub type posix_spawn_file_actions_t = *mut ::c_void; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_offset: ::off_t, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + __unused1: [::c_int; 2], + __unused2: *mut ::c_void, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + // unused 3 through 5 are the __aiocb_private structure + __unused3: ::c_long, + __unused4: ::c_long, + __unused5: *mut ::c_void, + pub aio_sigevent: sigevent + } + + pub struct jail { + pub version: u32, + pub path: *mut ::c_char, + pub hostname: *mut ::c_char, + pub jailname: *mut ::c_char, + pub ip4s: ::c_uint, + pub ip6s: ::c_uint, + pub ip4: *mut ::in_addr, + pub ip6: *mut ::in6_addr, + } + + pub struct mq_attr { + pub mq_flags: ::c_long, + pub mq_maxmsg: ::c_long, + pub mq_msgsize: ::c_long, + pub mq_curmsgs: ::c_long, + __reserved: [::c_long; 4] + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + //The rest of the structure is actually a union. We expose only + //sigev_notify_thread_id because it's the most useful union member. + pub sigev_notify_thread_id: ::lwpid_t, + #[cfg(target_pointer_width = "64")] + __unused1: ::c_int, + __unused2: [::c_long; 7] + } + + pub struct statvfs { + pub f_bavail: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_blocks: ::fsblkcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_bsize: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_fsid: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + // internal structure has changed over time + pub struct _sem { + data: [u32; 4], + } + + pub struct ipc_perm { + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub mode: ::mode_t, + pub seq: ::c_ushort, + pub key: ::key_t, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + pub msg_cbytes: ::msglen_t, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_lpid: ::pid_t, + pub shm_cpid: ::pid_t, + pub shm_nattch: ::c_int, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + } + + pub struct xucred { + pub cr_version: ::c_uint, + pub cr_uid: ::uid_t, + pub cr_ngroups: ::c_short, + pub cr_groups: [::gid_t;16], + __cr_unused1: *mut ::c_void, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct mmsghdr { + pub msg_hdr: ::msghdr, + pub msg_len: ::ssize_t, + } +} + +s_no_extra_traits! { + pub struct utmpx { + pub ut_type: ::c_short, + pub ut_tv: ::timeval, + pub ut_id: [::c_char; 8], + pub ut_pid: ::pid_t, + pub ut_user: [::c_char; 32], + pub ut_line: [::c_char; 16], + pub ut_host: [::c_char; 128], + pub __ut_spare: [::c_char; 64], + } + + pub struct dirent { + pub d_fileno: u32, + pub d_reclen: u16, + pub d_type: u8, + pub d_namlen: u8, + pub d_name: [::c_char; 256], + } + + pub struct statfs { + pub f_version: ::uint32_t, + pub f_type: ::uint32_t, + pub f_flags: ::uint64_t, + pub f_bsize: ::uint64_t, + pub f_iosize: ::uint64_t, + pub f_blocks: ::uint64_t, + pub f_bfree: ::uint64_t, + pub f_bavail: ::int64_t, + pub f_files: ::uint64_t, + pub f_ffree: ::int64_t, + pub f_syncwrites: ::uint64_t, + pub f_asyncwrites: ::uint64_t, + pub f_syncreads: ::uint64_t, + pub f_asyncreads: ::uint64_t, + f_spare: [::uint64_t; 10], + pub f_namemax: ::uint32_t, + pub f_owner: ::uid_t, + pub f_fsid: ::fsid_t, + f_charspare: [::c_char; 80], + pub f_fstypename: [::c_char; 16], + pub f_mntfromname: [::c_char; 88], + pub f_mntonname: [::c_char; 88], + } + + pub struct sockaddr_dl { + pub sdl_len: ::c_uchar, + pub sdl_family: ::c_uchar, + pub sdl_index: ::c_ushort, + pub sdl_type: ::c_uchar, + pub sdl_nlen: ::c_uchar, + pub sdl_alen: ::c_uchar, + pub sdl_slen: ::c_uchar, + pub sdl_data: [::c_char; 46], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for utmpx { + fn eq(&self, other: &utmpx) -> bool { + self.ut_type == other.ut_type + && self.ut_tv == other.ut_tv + && self.ut_id == other.ut_id + && self.ut_pid == other.ut_pid + && self.ut_user == other.ut_user + && self.ut_line == other.ut_line + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + && self + .__ut_spare + .iter() + .zip(other.__ut_spare.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for utmpx {} + impl ::fmt::Debug for utmpx { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmpx") + .field("ut_type", &self.ut_type) + .field("ut_tv", &self.ut_tv) + .field("ut_id", &self.ut_id) + .field("ut_pid", &self.ut_pid) + .field("ut_user", &self.ut_user) + .field("ut_line", &self.ut_line) + // FIXME: .field("ut_host", &self.ut_host) + // FIXME: .field("__ut_spare", &self.__ut_spare) + .finish() + } + } + impl ::hash::Hash for utmpx { + fn hash(&self, state: &mut H) { + self.ut_type.hash(state); + self.ut_tv.hash(state); + self.ut_id.hash(state); + self.ut_pid.hash(state); + self.ut_user.hash(state); + self.ut_line.hash(state); + self.ut_host.hash(state); + self.__ut_spare.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_fileno == other.d_fileno + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self.d_namlen == other.d_namlen + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_fileno", &self.d_fileno) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + .field("d_namlen", &self.d_namlen) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_fileno.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_namlen.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for statfs { + fn eq(&self, other: &statfs) -> bool { + self.f_version == other.f_version + && self.f_type == other.f_type + && self.f_flags == other.f_flags + && self.f_bsize == other.f_bsize + && self.f_iosize == other.f_iosize + && self.f_blocks == other.f_blocks + && self.f_bfree == other.f_bfree + && self.f_bavail == other.f_bavail + && self.f_files == other.f_files + && self.f_ffree == other.f_ffree + && self.f_syncwrites == other.f_syncwrites + && self.f_asyncwrites == other.f_asyncwrites + && self.f_syncreads == other.f_syncreads + && self.f_asyncreads == other.f_asyncreads + && self.f_spare == other.f_spare + && self.f_namemax == other.f_namemax + && self.f_owner == other.f_owner + && self.f_fsid == other.f_fsid + && self + .f_charspare + .iter() + .zip(other.f_charspare.iter()) + .all(|(a,b)| a == b) + && self.f_fstypename == other.f_fstypename + && self + .f_mntfromname + .iter() + .zip(other.f_mntfromname.iter()) + .all(|(a,b)| a == b) + && self + .f_mntonname + .iter() + .zip(other.f_mntonname.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for statfs {} + impl ::fmt::Debug for statfs { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("statfs") + .field("f_bsize", &self.f_bsize) + .field("f_iosize", &self.f_iosize) + .field("f_blocks", &self.f_blocks) + .field("f_bfree", &self.f_bfree) + .field("f_bavail", &self.f_bavail) + .field("f_files", &self.f_files) + .field("f_ffree", &self.f_ffree) + .field("f_syncwrites", &self.f_syncwrites) + .field("f_asyncwrites", &self.f_asyncwrites) + .field("f_syncreads", &self.f_syncreads) + .field("f_asyncreads", &self.f_asyncreads) + .field("f_spare", &self.f_spare) + .field("f_namemax", &self.f_namemax) + .field("f_owner", &self.f_owner) + .field("f_fsid", &self.f_fsid) + // FIXME: .field("f_charspare", &self.f_charspare) + .field("f_fstypename", &self.f_fstypename) + // FIXME: .field("f_mntfromname", &self.f_mntfromname) + // FIXME: .field("f_mntonname", &self.f_mntonname) + .finish() + } + } + impl ::hash::Hash for statfs { + fn hash(&self, state: &mut H) { + self.f_version.hash(state); + self.f_type.hash(state); + self.f_flags.hash(state); + self.f_bsize.hash(state); + self.f_iosize.hash(state); + self.f_blocks.hash(state); + self.f_bfree.hash(state); + self.f_bavail.hash(state); + self.f_files.hash(state); + self.f_ffree.hash(state); + self.f_syncwrites.hash(state); + self.f_asyncwrites.hash(state); + self.f_syncreads.hash(state); + self.f_asyncreads.hash(state); + self.f_spare.hash(state); + self.f_namemax.hash(state); + self.f_owner.hash(state); + self.f_fsid.hash(state); + self.f_charspare.hash(state); + self.f_fstypename.hash(state); + self.f_mntfromname.hash(state); + self.f_mntonname.hash(state); + } + } + + impl PartialEq for sockaddr_dl { + fn eq(&self, other: &sockaddr_dl) -> bool { + self.sdl_len == other.sdl_len + && self.sdl_family == other.sdl_family + && self.sdl_index == other.sdl_index + && self.sdl_type == other.sdl_type + && self.sdl_nlen == other.sdl_nlen + && self.sdl_alen == other.sdl_alen + && self.sdl_slen == other.sdl_slen + && self + .sdl_data + .iter() + .zip(other.sdl_data.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_dl {} + impl ::fmt::Debug for sockaddr_dl { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_dl") + .field("sdl_len", &self.sdl_len) + .field("sdl_family", &self.sdl_family) + .field("sdl_index", &self.sdl_index) + .field("sdl_type", &self.sdl_type) + .field("sdl_nlen", &self.sdl_nlen) + .field("sdl_alen", &self.sdl_alen) + .field("sdl_slen", &self.sdl_slen) + // FIXME: .field("sdl_data", &self.sdl_data) + .finish() + } + } + impl ::hash::Hash for sockaddr_dl { + fn hash(&self, state: &mut H) { + self.sdl_len.hash(state); + self.sdl_family.hash(state); + self.sdl_index.hash(state); + self.sdl_type.hash(state); + self.sdl_nlen.hash(state); + self.sdl_alen.hash(state); + self.sdl_slen.hash(state); + self.sdl_data.hash(state); + } + } + } +} + +pub const SIGEV_THREAD_ID: ::c_int = 4; + +pub const EXTATTR_NAMESPACE_EMPTY: ::c_int = 0; +pub const EXTATTR_NAMESPACE_USER: ::c_int = 1; +pub const EXTATTR_NAMESPACE_SYSTEM: ::c_int = 2; + +pub const RAND_MAX: ::c_int = 0x7fff_fffd; +pub const PTHREAD_STACK_MIN: ::size_t = 2048; +pub const PTHREAD_MUTEX_ADAPTIVE_NP: ::c_int = 4; +pub const SIGSTKSZ: ::size_t = 34816; +pub const SF_NODISKIO: ::c_int = 0x00000001; +pub const SF_MNOWAIT: ::c_int = 0x00000002; +pub const SF_SYNC: ::c_int = 0x00000004; +pub const SF_USER_READAHEAD: ::c_int = 0x00000008; +pub const SF_NOCACHE: ::c_int = 0x00000010; +pub const O_CLOEXEC: ::c_int = 0x00100000; +pub const O_DIRECTORY: ::c_int = 0x00020000; +pub const O_EXEC: ::c_int = 0x00040000; +pub const O_TTY_INIT: ::c_int = 0x00080000; +pub const F_GETLK: ::c_int = 11; +pub const F_SETLK: ::c_int = 12; +pub const F_SETLKW: ::c_int = 13; +pub const ENOTCAPABLE: ::c_int = 93; +pub const ECAPMODE: ::c_int = 94; +pub const ENOTRECOVERABLE: ::c_int = 95; +pub const EOWNERDEAD: ::c_int = 96; +pub const ELAST: ::c_int = 96; +pub const RLIMIT_NPTS: ::c_int = 11; +pub const RLIMIT_SWAP: ::c_int = 12; +pub const RLIMIT_KQUEUES: ::c_int = 13; +pub const RLIMIT_UMTXP: ::c_int = 14; +pub const RLIM_NLIMITS: ::rlim_t = 15; + +pub const Q_GETQUOTA: ::c_int = 0x700; +pub const Q_SETQUOTA: ::c_int = 0x800; + +pub const POSIX_FADV_NORMAL: ::c_int = 0; +pub const POSIX_FADV_RANDOM: ::c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_FADV_WILLNEED: ::c_int = 3; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; + +pub const POLLINIGNEOF: ::c_short = 0x2000; + +pub const EVFILT_READ: ::int16_t = -1; +pub const EVFILT_WRITE: ::int16_t = -2; +pub const EVFILT_AIO: ::int16_t = -3; +pub const EVFILT_VNODE: ::int16_t = -4; +pub const EVFILT_PROC: ::int16_t = -5; +pub const EVFILT_SIGNAL: ::int16_t = -6; +pub const EVFILT_TIMER: ::int16_t = -7; +pub const EVFILT_PROCDESC: ::int16_t = -8; +pub const EVFILT_FS: ::int16_t = -9; +pub const EVFILT_LIO: ::int16_t = -10; +pub const EVFILT_USER: ::int16_t = -11; +pub const EVFILT_SENDFILE: ::int16_t = -12; +pub const EVFILT_EMPTY: ::int16_t = -13; + +pub const EV_ADD: ::uint16_t = 0x1; +pub const EV_DELETE: ::uint16_t = 0x2; +pub const EV_ENABLE: ::uint16_t = 0x4; +pub const EV_DISABLE: ::uint16_t = 0x8; +pub const EV_ONESHOT: ::uint16_t = 0x10; +pub const EV_CLEAR: ::uint16_t = 0x20; +pub const EV_RECEIPT: ::uint16_t = 0x40; +pub const EV_DISPATCH: ::uint16_t = 0x80; +pub const EV_DROP: ::uint16_t = 0x1000; +pub const EV_FLAG1: ::uint16_t = 0x2000; +pub const EV_ERROR: ::uint16_t = 0x4000; +pub const EV_EOF: ::uint16_t = 0x8000; +pub const EV_SYSFLAGS: ::uint16_t = 0xf000; + +pub const NOTE_TRIGGER: ::uint32_t = 0x01000000; +pub const NOTE_FFNOP: ::uint32_t = 0x00000000; +pub const NOTE_FFAND: ::uint32_t = 0x40000000; +pub const NOTE_FFOR: ::uint32_t = 0x80000000; +pub const NOTE_FFCOPY: ::uint32_t = 0xc0000000; +pub const NOTE_FFCTRLMASK: ::uint32_t = 0xc0000000; +pub const NOTE_FFLAGSMASK: ::uint32_t = 0x00ffffff; +pub const NOTE_LOWAT: ::uint32_t = 0x00000001; +pub const NOTE_DELETE: ::uint32_t = 0x00000001; +pub const NOTE_WRITE: ::uint32_t = 0x00000002; +pub const NOTE_EXTEND: ::uint32_t = 0x00000004; +pub const NOTE_ATTRIB: ::uint32_t = 0x00000008; +pub const NOTE_LINK: ::uint32_t = 0x00000010; +pub const NOTE_RENAME: ::uint32_t = 0x00000020; +pub const NOTE_REVOKE: ::uint32_t = 0x00000040; +pub const NOTE_EXIT: ::uint32_t = 0x80000000; +pub const NOTE_FORK: ::uint32_t = 0x40000000; +pub const NOTE_EXEC: ::uint32_t = 0x20000000; +pub const NOTE_PDATAMASK: ::uint32_t = 0x000fffff; +pub const NOTE_PCTRLMASK: ::uint32_t = 0xf0000000; +pub const NOTE_TRACK: ::uint32_t = 0x00000001; +pub const NOTE_TRACKERR: ::uint32_t = 0x00000002; +pub const NOTE_CHILD: ::uint32_t = 0x00000004; +pub const NOTE_SECONDS: ::uint32_t = 0x00000001; +pub const NOTE_MSECONDS: ::uint32_t = 0x00000002; +pub const NOTE_USECONDS: ::uint32_t = 0x00000004; +pub const NOTE_NSECONDS: ::uint32_t = 0x00000008; + +pub const MADV_PROTECT: ::c_int = 10; +pub const RUSAGE_THREAD: ::c_int = 1; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_VIRTUAL: ::clockid_t = 1; +pub const CLOCK_PROF: ::clockid_t = 2; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; +pub const CLOCK_UPTIME: ::clockid_t = 5; +pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; +pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; +pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; +pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; +pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; +pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; +pub const CLOCK_SECOND: ::clockid_t = 13; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; + +pub const CTL_UNSPEC: ::c_int = 0; +pub const CTL_KERN: ::c_int = 1; +pub const CTL_VM: ::c_int = 2; +pub const CTL_VFS: ::c_int = 3; +pub const CTL_NET: ::c_int = 4; +pub const CTL_DEBUG: ::c_int = 5; +pub const CTL_HW: ::c_int = 6; +pub const CTL_MACHDEP: ::c_int = 7; +pub const CTL_USER: ::c_int = 8; +pub const CTL_P1003_1B: ::c_int = 9; +pub const KERN_OSTYPE: ::c_int = 1; +pub const KERN_OSRELEASE: ::c_int = 2; +pub const KERN_OSREV: ::c_int = 3; +pub const KERN_VERSION: ::c_int = 4; +pub const KERN_MAXVNODES: ::c_int = 5; +pub const KERN_MAXPROC: ::c_int = 6; +pub const KERN_MAXFILES: ::c_int = 7; +pub const KERN_ARGMAX: ::c_int = 8; +pub const KERN_SECURELVL: ::c_int = 9; +pub const KERN_HOSTNAME: ::c_int = 10; +pub const KERN_HOSTID: ::c_int = 11; +pub const KERN_CLOCKRATE: ::c_int = 12; +pub const KERN_VNODE: ::c_int = 13; +pub const KERN_PROC: ::c_int = 14; +pub const KERN_FILE: ::c_int = 15; +pub const KERN_PROF: ::c_int = 16; +pub const KERN_POSIX1: ::c_int = 17; +pub const KERN_NGROUPS: ::c_int = 18; +pub const KERN_JOB_CONTROL: ::c_int = 19; +pub const KERN_SAVED_IDS: ::c_int = 20; +pub const KERN_BOOTTIME: ::c_int = 21; +pub const KERN_NISDOMAINNAME: ::c_int = 22; +pub const KERN_UPDATEINTERVAL: ::c_int = 23; +pub const KERN_OSRELDATE: ::c_int = 24; +pub const KERN_NTP_PLL: ::c_int = 25; +pub const KERN_BOOTFILE: ::c_int = 26; +pub const KERN_MAXFILESPERPROC: ::c_int = 27; +pub const KERN_MAXPROCPERUID: ::c_int = 28; +pub const KERN_DUMPDEV: ::c_int = 29; +pub const KERN_IPC: ::c_int = 30; +pub const KERN_DUMMY: ::c_int = 31; +pub const KERN_PS_STRINGS: ::c_int = 32; +pub const KERN_USRSTACK: ::c_int = 33; +pub const KERN_LOGSIGEXIT: ::c_int = 34; +pub const KERN_IOV_MAX: ::c_int = 35; +pub const KERN_HOSTUUID: ::c_int = 36; +pub const KERN_ARND: ::c_int = 37; +pub const KERN_PROC_ALL: ::c_int = 0; +pub const KERN_PROC_PID: ::c_int = 1; +pub const KERN_PROC_PGRP: ::c_int = 2; +pub const KERN_PROC_SESSION: ::c_int = 3; +pub const KERN_PROC_TTY: ::c_int = 4; +pub const KERN_PROC_UID: ::c_int = 5; +pub const KERN_PROC_RUID: ::c_int = 6; +pub const KERN_PROC_ARGS: ::c_int = 7; +pub const KERN_PROC_PROC: ::c_int = 8; +pub const KERN_PROC_SV_NAME: ::c_int = 9; +pub const KERN_PROC_RGID: ::c_int = 10; +pub const KERN_PROC_GID: ::c_int = 11; +pub const KERN_PROC_PATHNAME: ::c_int = 12; +pub const KERN_PROC_OVMMAP: ::c_int = 13; +pub const KERN_PROC_OFILEDESC: ::c_int = 14; +pub const KERN_PROC_KSTACK: ::c_int = 15; +pub const KERN_PROC_INC_THREAD: ::c_int = 0x10; +pub const KERN_PROC_VMMAP: ::c_int = 32; +pub const KERN_PROC_FILEDESC: ::c_int = 33; +pub const KERN_PROC_GROUPS: ::c_int = 34; +pub const KERN_PROC_ENV: ::c_int = 35; +pub const KERN_PROC_AUXV: ::c_int = 36; +pub const KERN_PROC_RLIMIT: ::c_int = 37; +pub const KERN_PROC_PS_STRINGS: ::c_int = 38; +pub const KERN_PROC_UMASK: ::c_int = 39; +pub const KERN_PROC_OSREL: ::c_int = 40; +pub const KERN_PROC_SIGTRAMP: ::c_int = 41; +pub const KIPC_MAXSOCKBUF: ::c_int = 1; +pub const KIPC_SOCKBUF_WASTE: ::c_int = 2; +pub const KIPC_SOMAXCONN: ::c_int = 3; +pub const KIPC_MAX_LINKHDR: ::c_int = 4; +pub const KIPC_MAX_PROTOHDR: ::c_int = 5; +pub const KIPC_MAX_HDR: ::c_int = 6; +pub const KIPC_MAX_DATALEN: ::c_int = 7; +pub const HW_MACHINE: ::c_int = 1; +pub const HW_MODEL: ::c_int = 2; +pub const HW_NCPU: ::c_int = 3; +pub const HW_BYTEORDER: ::c_int = 4; +pub const HW_PHYSMEM: ::c_int = 5; +pub const HW_USERMEM: ::c_int = 6; +pub const HW_PAGESIZE: ::c_int = 7; +pub const HW_DISKNAMES: ::c_int = 8; +pub const HW_DISKSTATS: ::c_int = 9; +pub const HW_FLOATINGPT: ::c_int = 10; +pub const HW_MACHINE_ARCH: ::c_int = 11; +pub const HW_REALMEM: ::c_int = 12; +pub const USER_CS_PATH: ::c_int = 1; +pub const USER_BC_BASE_MAX: ::c_int = 2; +pub const USER_BC_DIM_MAX: ::c_int = 3; +pub const USER_BC_SCALE_MAX: ::c_int = 4; +pub const USER_BC_STRING_MAX: ::c_int = 5; +pub const USER_COLL_WEIGHTS_MAX: ::c_int = 6; +pub const USER_EXPR_NEST_MAX: ::c_int = 7; +pub const USER_LINE_MAX: ::c_int = 8; +pub const USER_RE_DUP_MAX: ::c_int = 9; +pub const USER_POSIX2_VERSION: ::c_int = 10; +pub const USER_POSIX2_C_BIND: ::c_int = 11; +pub const USER_POSIX2_C_DEV: ::c_int = 12; +pub const USER_POSIX2_CHAR_TERM: ::c_int = 13; +pub const USER_POSIX2_FORT_DEV: ::c_int = 14; +pub const USER_POSIX2_FORT_RUN: ::c_int = 15; +pub const USER_POSIX2_LOCALEDEF: ::c_int = 16; +pub const USER_POSIX2_SW_DEV: ::c_int = 17; +pub const USER_POSIX2_UPE: ::c_int = 18; +pub const USER_STREAM_MAX: ::c_int = 19; +pub const USER_TZNAME_MAX: ::c_int = 20; +pub const CTL_P1003_1B_ASYNCHRONOUS_IO: ::c_int = 1; +pub const CTL_P1003_1B_MAPPED_FILES: ::c_int = 2; +pub const CTL_P1003_1B_MEMLOCK: ::c_int = 3; +pub const CTL_P1003_1B_MEMLOCK_RANGE: ::c_int = 4; +pub const CTL_P1003_1B_MEMORY_PROTECTION: ::c_int = 5; +pub const CTL_P1003_1B_MESSAGE_PASSING: ::c_int = 6; +pub const CTL_P1003_1B_PRIORITIZED_IO: ::c_int = 7; +pub const CTL_P1003_1B_PRIORITY_SCHEDULING: ::c_int = 8; +pub const CTL_P1003_1B_REALTIME_SIGNALS: ::c_int = 9; +pub const CTL_P1003_1B_SEMAPHORES: ::c_int = 10; +pub const CTL_P1003_1B_FSYNC: ::c_int = 11; +pub const CTL_P1003_1B_SHARED_MEMORY_OBJECTS: ::c_int = 12; +pub const CTL_P1003_1B_SYNCHRONIZED_IO: ::c_int = 13; +pub const CTL_P1003_1B_TIMERS: ::c_int = 14; +pub const CTL_P1003_1B_AIO_LISTIO_MAX: ::c_int = 15; +pub const CTL_P1003_1B_AIO_MAX: ::c_int = 16; +pub const CTL_P1003_1B_AIO_PRIO_DELTA_MAX: ::c_int = 17; +pub const CTL_P1003_1B_DELAYTIMER_MAX: ::c_int = 18; +pub const CTL_P1003_1B_MQ_OPEN_MAX: ::c_int = 19; +pub const CTL_P1003_1B_PAGESIZE: ::c_int = 20; +pub const CTL_P1003_1B_RTSIG_MAX: ::c_int = 21; +pub const CTL_P1003_1B_SEM_NSEMS_MAX: ::c_int = 22; +pub const CTL_P1003_1B_SEM_VALUE_MAX: ::c_int = 23; +pub const CTL_P1003_1B_SIGQUEUE_MAX: ::c_int = 24; +pub const CTL_P1003_1B_TIMER_MAX: ::c_int = 25; +pub const TIOCGPTN: ::c_uint = 0x4004740f; +pub const TIOCPTMASTER: ::c_uint = 0x2000741c; +pub const TIOCSIG: ::c_uint = 0x2004745f; +pub const TIOCM_DCD: ::c_int = 0x40; +pub const H4DISC: ::c_int = 0x7; + +pub const FIONCLEX: ::c_ulong = 0x20006602; +pub const FIONREAD: ::c_ulong = 0x4004667f; +pub const FIOASYNC: ::c_ulong = 0x8004667d; +pub const FIOSETOWN: ::c_ulong = 0x8004667c; +pub const FIOGETOWN: ::c_ulong = 0x4004667b; +pub const FIODTYPE: ::c_ulong = 0x4004667a; +pub const FIOGETLBA: ::c_ulong = 0x40046679; +pub const FIODGNAME: ::c_ulong = 0x80106678; +pub const FIONWRITE: ::c_ulong = 0x40046677; +pub const FIONSPACE: ::c_ulong = 0x40046676; +pub const FIOSEEKDATA: ::c_ulong = 0xc0086661; +pub const FIOSEEKHOLE: ::c_ulong = 0xc0086662; + +pub const JAIL_API_VERSION: u32 = 2; +pub const JAIL_CREATE: ::c_int = 0x01; +pub const JAIL_UPDATE: ::c_int = 0x02; +pub const JAIL_ATTACH: ::c_int = 0x04; +pub const JAIL_DYING: ::c_int = 0x08; +pub const JAIL_SET_MASK: ::c_int = 0x0f; +pub const JAIL_GET_MASK: ::c_int = 0x08; +pub const JAIL_SYS_DISABLE: ::c_int = 0; +pub const JAIL_SYS_NEW: ::c_int = 1; +pub const JAIL_SYS_INHERIT: ::c_int = 2; + +pub const SO_BINTIME: ::c_int = 0x2000; +pub const SO_NO_OFFLOAD: ::c_int = 0x4000; +pub const SO_NO_DDP: ::c_int = 0x8000; +pub const SO_REUSEPORT_LB: ::c_int = 0x10000; +pub const SO_LABEL: ::c_int = 0x1009; +pub const SO_PEERLABEL: ::c_int = 0x1010; +pub const SO_LISTENQLIMIT: ::c_int = 0x1011; +pub const SO_LISTENQLEN: ::c_int = 0x1012; +pub const SO_LISTENINCQLEN: ::c_int = 0x1013; +pub const SO_SETFIB: ::c_int = 0x1014; +pub const SO_USER_COOKIE: ::c_int = 0x1015; +pub const SO_PROTOCOL: ::c_int = 0x1016; +pub const SO_PROTOTYPE: ::c_int = SO_PROTOCOL; +pub const SO_VENDOR: ::c_int = 0x80000000; + +pub const LOCAL_PEERCRED: ::c_int = 1; +pub const LOCAL_CREDS: ::c_int = 2; +pub const LOCAL_CONNWAIT: ::c_int = 4; +pub const LOCAL_VENDOR: ::c_int = SO_VENDOR; + +pub const PT_LWPINFO: ::c_int = 13; +pub const PT_GETNUMLWPS: ::c_int = 14; +pub const PT_GETLWPLIST: ::c_int = 15; +pub const PT_CLEARSTEP: ::c_int = 16; +pub const PT_SETSTEP: ::c_int = 17; +pub const PT_SUSPEND: ::c_int = 18; +pub const PT_RESUME: ::c_int = 19; +pub const PT_TO_SCE: ::c_int = 20; +pub const PT_TO_SCX: ::c_int = 21; +pub const PT_SYSCALL: ::c_int = 22; +pub const PT_FOLLOW_FORK: ::c_int = 23; +pub const PT_LWP_EVENTS: ::c_int = 24; +pub const PT_GET_EVENT_MASK: ::c_int = 25; +pub const PT_SET_EVENT_MASK: ::c_int = 26; +pub const PT_GETREGS: ::c_int = 33; +pub const PT_SETREGS: ::c_int = 34; +pub const PT_GETFPREGS: ::c_int = 35; +pub const PT_SETFPREGS: ::c_int = 36; +pub const PT_GETDBREGS: ::c_int = 37; +pub const PT_SETDBREGS: ::c_int = 38; +pub const PT_VM_TIMESTAMP: ::c_int = 40; +pub const PT_VM_ENTRY: ::c_int = 41; +pub const PT_FIRSTMACH: ::c_int = 64; + +pub const PTRACE_EXEC: ::c_int = 0x0001; +pub const PTRACE_SCE: ::c_int = 0x0002; +pub const PTRACE_SCX: ::c_int = 0x0004; +pub const PTRACE_SYSCALL: ::c_int = PTRACE_SCE | PTRACE_SCX; +pub const PTRACE_FORK: ::c_int = 0x0008; +pub const PTRACE_LWP: ::c_int = 0x0010; +pub const PTRACE_VFORK: ::c_int = 0x0020; +pub const PTRACE_DEFAULT: ::c_int = PTRACE_EXEC; + +pub const AF_SLOW: ::c_int = 33; +pub const AF_SCLUSTER: ::c_int = 34; +pub const AF_ARP: ::c_int = 35; +pub const AF_BLUETOOTH: ::c_int = 36; +pub const AF_IEEE80211: ::c_int = 37; +pub const AF_INET_SDP: ::c_int = 40; +pub const AF_INET6_SDP: ::c_int = 42; +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; + +// https://github.com/freebsd/freebsd/blob/master/sys/net/if.h#L140 +pub const IFF_UP: ::c_int = 0x1; // (n) interface is up +pub const IFF_BROADCAST: ::c_int = 0x2; // (i) broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x4; // (n) turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x8; // (i) is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x10; // (i) is a point-to-point link +// 0x20 was IFF_SMART +pub const IFF_RUNNING: ::c_int = 0x40; // (d) resources allocated +#[doc(hidden)] +// IFF_DRV_RUNNING is deprecated. Use the portable `IFF_RUNNING` instead +pub const IFF_DRV_RUNNING: ::c_int = 0x40; +pub const IFF_NOARP: ::c_int = 0x80; // (n) no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x100; // (n) receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x200; // (n) receive all multicast packets +pub const IFF_OACTIVE: ::c_int = 0x400; // (d) tx hardware queue is full +#[doc(hidden)] +// IFF_DRV_OACTIVE is deprecated. Use the portable `IFF_OACTIVE` instead +pub const IFF_DRV_OACTIVE: ::c_int = 0x400; +pub const IFF_SIMPLEX: ::c_int = 0x800; // (i) can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: ::c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: ::c_int = 0x8000; // (i) supports multicast +// (i) unconfigurable using ioctl(2) +pub const IFF_CANTCONFIG: ::c_int = 0x10000; +pub const IFF_PPROMISC: ::c_int = 0x20000; // (n) user-requested promisc mode +pub const IFF_MONITOR: ::c_int = 0x40000; // (n) user-requested monitor mode +pub const IFF_STATICARP: ::c_int = 0x80000; // (n) static ARP +pub const IFF_DYING: ::c_int = 0x200000; // (n) interface is winding down +pub const IFF_RENAMING: ::c_int = 0x400000; // (n) interface is being renamed + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: ::c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// Stream protocol II. +pub const IPPROTO_ST: ::c_int = 7; +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// private interior gateway +pub const IPPROTO_PIGP: ::c_int = 9; +/// BBN RCC Monitoring +pub const IPPROTO_RCCMON: ::c_int = 10; +/// network voice protocol +pub const IPPROTO_NVPII: ::c_int = 11; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +/// Argus +pub const IPPROTO_ARGUS: ::c_int = 13; +/// EMCON +pub const IPPROTO_EMCON: ::c_int = 14; +/// Cross Net Debugger +pub const IPPROTO_XNET: ::c_int = 15; +/// Chaos +pub const IPPROTO_CHAOS: ::c_int = 16; +// IPPROTO_UDP defined in src/unix/mod.rs +/// Multiplexing +pub const IPPROTO_MUX: ::c_int = 18; +/// DCN Measurement Subsystems +pub const IPPROTO_MEAS: ::c_int = 19; +/// Host Monitoring +pub const IPPROTO_HMP: ::c_int = 20; +/// Packet Radio Measurement +pub const IPPROTO_PRM: ::c_int = 21; +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// Trunk-1 +pub const IPPROTO_TRUNK1: ::c_int = 23; +/// Trunk-2 +pub const IPPROTO_TRUNK2: ::c_int = 24; +/// Leaf-1 +pub const IPPROTO_LEAF1: ::c_int = 25; +/// Leaf-2 +pub const IPPROTO_LEAF2: ::c_int = 26; +/// Reliable Data +pub const IPPROTO_RDP: ::c_int = 27; +/// Reliable Transaction +pub const IPPROTO_IRTP: ::c_int = 28; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// Bulk Data Transfer +pub const IPPROTO_BLT: ::c_int = 30; +/// Network Services +pub const IPPROTO_NSP: ::c_int = 31; +/// Merit Internodal +pub const IPPROTO_INP: ::c_int = 32; +/// Sequential Exchange +pub const IPPROTO_SEP: ::c_int = 33; +/// Third Party Connect +pub const IPPROTO_3PC: ::c_int = 34; +/// InterDomain Policy Routing +pub const IPPROTO_IDPR: ::c_int = 35; +/// XTP +pub const IPPROTO_XTP: ::c_int = 36; +/// Datagram Delivery +pub const IPPROTO_DDP: ::c_int = 37; +/// Control Message Transport +pub const IPPROTO_CMTP: ::c_int = 38; +/// TP++ Transport +pub const IPPROTO_TPXX: ::c_int = 39; +/// IL transport protocol +pub const IPPROTO_IL: ::c_int = 40; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// Source Demand Routing +pub const IPPROTO_SDRP: ::c_int = 42; +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// InterDomain Routing +pub const IPPROTO_IDRP: ::c_int = 45; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// Mobile Host Routing +pub const IPPROTO_MHRP: ::c_int = 48; +/// BHA +pub const IPPROTO_BHA: ::c_int = 49; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +/// Integ. Net Layer Security +pub const IPPROTO_INLSP: ::c_int = 52; +/// IP with encryption +pub const IPPROTO_SWIPE: ::c_int = 53; +/// Next Hop Resolution +pub const IPPROTO_NHRP: ::c_int = 54; +/// IP Mobility +pub const IPPROTO_MOBILE: ::c_int = 55; +/// Transport Layer Security +pub const IPPROTO_TLSP: ::c_int = 56; +/// SKIP +pub const IPPROTO_SKIP: ::c_int = 57; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +/// any host internal protocol +pub const IPPROTO_AHIP: ::c_int = 61; +/// CFTP +pub const IPPROTO_CFTP: ::c_int = 62; +/// "hello" routing protocol +pub const IPPROTO_HELLO: ::c_int = 63; +/// SATNET/Backroom EXPAK +pub const IPPROTO_SATEXPAK: ::c_int = 64; +/// Kryptolan +pub const IPPROTO_KRYPTOLAN: ::c_int = 65; +/// Remote Virtual Disk +pub const IPPROTO_RVD: ::c_int = 66; +/// Pluribus Packet Core +pub const IPPROTO_IPPC: ::c_int = 67; +/// Any distributed FS +pub const IPPROTO_ADFS: ::c_int = 68; +/// Satnet Monitoring +pub const IPPROTO_SATMON: ::c_int = 69; +/// VISA Protocol +pub const IPPROTO_VISA: ::c_int = 70; +/// Packet Core Utility +pub const IPPROTO_IPCV: ::c_int = 71; +/// Comp. Prot. Net. Executive +pub const IPPROTO_CPNX: ::c_int = 72; +/// Comp. Prot. HeartBeat +pub const IPPROTO_CPHB: ::c_int = 73; +/// Wang Span Network +pub const IPPROTO_WSN: ::c_int = 74; +/// Packet Video Protocol +pub const IPPROTO_PVP: ::c_int = 75; +/// BackRoom SATNET Monitoring +pub const IPPROTO_BRSATMON: ::c_int = 76; +/// Sun net disk proto (temp.) +pub const IPPROTO_ND: ::c_int = 77; +/// WIDEBAND Monitoring +pub const IPPROTO_WBMON: ::c_int = 78; +/// WIDEBAND EXPAK +pub const IPPROTO_WBEXPAK: ::c_int = 79; +/// ISO cnlp +pub const IPPROTO_EON: ::c_int = 80; +/// VMTP +pub const IPPROTO_VMTP: ::c_int = 81; +/// Secure VMTP +pub const IPPROTO_SVMTP: ::c_int = 82; +/// Banyon VINES +pub const IPPROTO_VINES: ::c_int = 83; +/// TTP +pub const IPPROTO_TTP: ::c_int = 84; +/// NSFNET-IGP +pub const IPPROTO_IGP: ::c_int = 85; +/// dissimilar gateway prot. +pub const IPPROTO_DGP: ::c_int = 86; +/// TCF +pub const IPPROTO_TCF: ::c_int = 87; +/// Cisco/GXS IGRP +pub const IPPROTO_IGRP: ::c_int = 88; +/// OSPFIGP +pub const IPPROTO_OSPFIGP: ::c_int = 89; +/// Strite RPC protocol +pub const IPPROTO_SRPC: ::c_int = 90; +/// Locus Address Resoloution +pub const IPPROTO_LARP: ::c_int = 91; +/// Multicast Transport +pub const IPPROTO_MTP: ::c_int = 92; +/// AX.25 Frames +pub const IPPROTO_AX25: ::c_int = 93; +/// IP encapsulated in IP +pub const IPPROTO_IPEIP: ::c_int = 94; +/// Mobile Int.ing control +pub const IPPROTO_MICP: ::c_int = 95; +/// Semaphore Comm. security +pub const IPPROTO_SCCSP: ::c_int = 96; +/// Ethernet IP encapsulation +pub const IPPROTO_ETHERIP: ::c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// any private encr. scheme +pub const IPPROTO_APES: ::c_int = 99; +/// GMTP +pub const IPPROTO_GMTP: ::c_int = 100; +/// payload compression (IPComp) +pub const IPPROTO_IPCOMP: ::c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; +/// IPv6 Mobility Header +pub const IPPROTO_MH: ::c_int = 135; +/// UDP-Lite +pub const IPPROTO_UDPLITE: ::c_int = 136; +/// IP6 Host Identity Protocol +pub const IPPROTO_HIP: ::c_int = 139; +/// IP6 Shim6 Protocol +pub const IPPROTO_SHIM6: ::c_int = 140; + +/* 101-254: Partly Unassigned */ +/// Protocol Independent Mcast +pub const IPPROTO_PIM: ::c_int = 103; +/// CARP +pub const IPPROTO_CARP: ::c_int = 112; +/// PGM +pub const IPPROTO_PGM: ::c_int = 113; +/// MPLS-in-IP +pub const IPPROTO_MPLS: ::c_int = 137; +/// PFSYNC +pub const IPPROTO_PFSYNC: ::c_int = 240; + +/* 255: Reserved */ +/* BSD Private, local use, namespace incursion, no longer used */ +/// OLD divert pseudo-proto +pub const IPPROTO_OLD_DIVERT: ::c_int = 254; +pub const IPPROTO_MAX: ::c_int = 256; +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: ::c_int = 257; + +/* Only used internally, so can be outside the range of valid IP protocols. */ +/// divert pseudo-protocol +pub const IPPROTO_DIVERT: ::c_int = 258; +/// SeND pseudo-protocol +pub const IPPROTO_SEND: ::c_int = 259; + +// sys/netinet/TCP.h +pub const TCP_MD5SIG: ::c_int = 16; +pub const TCP_INFO: ::c_int = 32; +pub const TCP_CONGESTION: ::c_int = 64; +pub const TCP_CCALGOOPT: ::c_int = 65; +pub const TCP_KEEPINIT: ::c_int = 128; +pub const TCP_FASTOPEN: ::c_int = 1025; +pub const TCP_PCAP_OUT: ::c_int = 2048; +pub const TCP_PCAP_IN: ::c_int = 4096; + +pub const IP_BINDANY: ::c_int = 24; +pub const IP_BINDMULTI: ::c_int = 25; +pub const IP_RSS_LISTEN_BUCKET: ::c_int = 26; +pub const IP_ORIGDSTADDR : ::c_int = 27; +pub const IP_RECVORIGDSTADDR : ::c_int = IP_ORIGDSTADDR; + +pub const IP_RECVTOS: ::c_int = 68; + +pub const IPV6_ORIGDSTADDR: ::c_int = 72; +pub const IPV6_RECVORIGDSTADDR: ::c_int = IPV6_ORIGDSTADDR; + +pub const PF_SLOW: ::c_int = AF_SLOW; +pub const PF_SCLUSTER: ::c_int = AF_SCLUSTER; +pub const PF_ARP: ::c_int = AF_ARP; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_IEEE80211: ::c_int = AF_IEEE80211; +pub const PF_INET_SDP: ::c_int = AF_INET_SDP; +pub const PF_INET6_SDP: ::c_int = AF_INET6_SDP; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +pub const NET_RT_DUMP: ::c_int = 1; +pub const NET_RT_FLAGS: ::c_int = 2; +pub const NET_RT_IFLIST: ::c_int = 3; +pub const NET_RT_IFMALIST: ::c_int = 4; +pub const NET_RT_IFLISTL: ::c_int = 5; + +// System V IPC +pub const IPC_PRIVATE: ::key_t = 0; +pub const IPC_CREAT: ::c_int = 0o1000; +pub const IPC_EXCL: ::c_int = 0o2000; +pub const IPC_NOWAIT: ::c_int = 0o4000; +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; +pub const IPC_INFO: ::c_int = 3; +pub const IPC_R : ::c_int = 0o400; +pub const IPC_W : ::c_int = 0o200; +pub const IPC_M : ::c_int = 0o10000; +pub const MSG_NOERROR: ::c_int = 0o10000; +pub const SHM_RDONLY: ::c_int = 0o10000; +pub const SHM_RND: ::c_int = 0o20000; +pub const SHM_R: ::c_int = 0o400; +pub const SHM_W: ::c_int = 0o200; +pub const SHM_LOCK: ::c_int = 11; +pub const SHM_UNLOCK: ::c_int = 12; +pub const SHM_STAT: ::c_int = 13; +pub const SHM_INFO: ::c_int = 14; +pub const SHM_ANON: *mut ::c_char = 1 as *mut ::c_char; + +// The *_MAXID constants never should've been used outside of the +// FreeBSD base system. And with the exception of CTL_P1003_1B_MAXID, +// they were all removed in svn r262489. They remain here for backwards +// compatibility only, and are scheduled to be removed in libc 1.0.0. +#[doc(hidden)] +pub const NET_MAXID: ::c_int = AF_MAX; +#[doc(hidden)] +pub const CTL_MAXID: ::c_int = 10; +#[doc(hidden)] +pub const KERN_MAXID: ::c_int = 38; +#[doc(hidden)] +pub const HW_MAXID: ::c_int = 13; +#[doc(hidden)] +pub const USER_MAXID: ::c_int = 21; +#[doc(hidden)] +pub const CTL_P1003_1B_MAXID: ::c_int = 26; + +pub const MSG_NOTIFICATION: ::c_int = 0x00002000; +pub const MSG_NBIO: ::c_int = 0x00004000; +pub const MSG_COMPAT: ::c_int = 0x00008000; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x00040000; +pub const MSG_NOSIGNAL: ::c_int = 0x20000; + +pub const EMPTY: ::c_short = 0; +pub const BOOT_TIME: ::c_short = 1; +pub const OLD_TIME: ::c_short = 2; +pub const NEW_TIME: ::c_short = 3; +pub const USER_PROCESS: ::c_short = 4; +pub const INIT_PROCESS: ::c_short = 5; +pub const LOGIN_PROCESS: ::c_short = 6; +pub const DEAD_PROCESS: ::c_short = 7; +pub const SHUTDOWN_TIME: ::c_short = 8; + +pub const LC_COLLATE_MASK: ::c_int = (1 << 0); +pub const LC_CTYPE_MASK: ::c_int = (1 << 1); +pub const LC_MONETARY_MASK: ::c_int =(1 << 2); +pub const LC_NUMERIC_MASK: ::c_int = (1 << 3); +pub const LC_TIME_MASK: ::c_int = (1 << 4); +pub const LC_MESSAGES_MASK: ::c_int = (1 << 5); +pub const LC_ALL_MASK: ::c_int = LC_COLLATE_MASK + | LC_CTYPE_MASK + | LC_MESSAGES_MASK + | LC_MONETARY_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK; + +pub const WSTOPPED: ::c_int = 2; // same as WUNTRACED +pub const WCONTINUED: ::c_int = 4; +pub const WNOWAIT: ::c_int = 8; +pub const WEXITED: ::c_int = 16; +pub const WTRAPPED: ::c_int = 32; + +// FreeBSD defines a great many more of these, we only expose the +// standardized ones. +pub const P_PID: idtype_t = 0; +pub const P_PGID: idtype_t = 2; +pub const P_ALL: idtype_t = 7; + +pub const B460800: ::speed_t = 460800; +pub const B921600: ::speed_t = 921600; + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_EACCESS: ::c_int = 0x100; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x400; +pub const AT_REMOVEDIR: ::c_int = 0x800; + +pub const TABDLY: ::tcflag_t = 0x00000004; +pub const TAB0: ::tcflag_t = 0x00000000; +pub const TAB3: ::tcflag_t = 0x00000004; + +pub const _PC_ACL_NFS4: ::c_int = 64; + +pub const _SC_CPUSET_SIZE: ::c_int = 122; + +pub const XU_NGROUPS: ::c_int = 16; +pub const XUCRED_VERSION: ::c_uint = 0; + +// Flags which can be passed to pdfork(2) +pub const PD_DAEMON: ::c_int = 0x00000001; +pub const PD_CLOEXEC: ::c_int = 0x00000002; +pub const PD_ALLOWED_AT_FORK: ::c_int = PD_DAEMON | PD_CLOEXEC; + +// Values for struct rtprio (type_ field) +pub const RTP_PRIO_REALTIME: ::c_ushort = 2; +pub const RTP_PRIO_NORMAL: ::c_ushort = 3; +pub const RTP_PRIO_IDLE: ::c_ushort = 4; + +pub const POSIX_SPAWN_RESETIDS: ::c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: ::c_int = 0x02; +pub const POSIX_SPAWN_SETSCHEDPARAM: ::c_int = 0x04; +pub const POSIX_SPAWN_SETSCHEDULER: ::c_int = 0x08; +pub const POSIX_SPAWN_SETSIGDEF: ::c_int = 0x10; +pub const POSIX_SPAWN_SETSIGMASK: ::c_int = 0x20; + +// Flags for chflags(2) +pub const UF_SYSTEM: ::c_ulong = 0x00000080; +pub const UF_SPARSE: ::c_ulong = 0x00000100; +pub const UF_OFFLINE: ::c_ulong = 0x00000200; +pub const UF_REPARSE: ::c_ulong = 0x00000400; +pub const UF_ARCHIVE: ::c_ulong = 0x00000800; +pub const UF_READONLY: ::c_ulong = 0x00001000; +pub const UF_HIDDEN: ::c_ulong = 0x00008000; +pub const SF_SNAPSHOT: ::c_ulong = 0x00200000; + +fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const ::cmsghdr) -> *mut ::c_uchar { + (cmsg as *mut ::c_uchar) + .offset(_ALIGN(::mem::size_of::<::cmsghdr>()) as isize) + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + _ALIGN(::mem::size_of::<::cmsghdr>()) as ::c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const ::msghdr, cmsg: *const ::cmsghdr) + -> *mut ::cmsghdr + { + if cmsg.is_null() { + return ::CMSG_FIRSTHDR(mhdr); + }; + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + + _ALIGN(::mem::size_of::<::cmsghdr>()); + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if next > max { + 0 as *mut ::cmsghdr + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) + as *mut ::cmsghdr + } + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (_ALIGN(::mem::size_of::<::cmsghdr>()) + _ALIGN(length as usize)) + as ::c_uint + } + + pub fn uname(buf: *mut ::utsname) -> ::c_int { + __xuname(256, buf as *mut ::c_void) + } +} + +extern { + pub fn __error() -> *mut ::c_int; + + pub fn mprotect(addr: *const ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + + pub fn extattr_delete_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_delete_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_delete_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_get_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_get_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_get_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_list_fd(fd: ::c_int, + attrnamespace: ::c_int, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_list_file(path: *const ::c_char, + attrnamespace: ::c_int, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_list_link(path: *const ::c_char, + attrnamespace: ::c_int, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_set_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_set_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_set_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::ssize_t; + + pub fn jail(jail: *mut ::jail) -> ::c_int; + pub fn jail_attach(jid: ::c_int) -> ::c_int; + pub fn jail_remove(jid: ::c_int) -> ::c_int; + pub fn jail_get(iov: *mut ::iovec, niov: ::c_uint, flags: ::c_int) + -> ::c_int; + pub fn jail_set(iov: *mut ::iovec, niov: ::c_uint, flags: ::c_int) + -> ::c_int; + + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn posix_fallocate(fd: ::c_int, offset: ::off_t, + len: ::off_t) -> ::c_int; + pub fn posix_fadvise(fd: ::c_int, offset: ::off_t, len: ::off_t, + advise: ::c_int) -> ::c_int; + pub fn mkostemp(template: *mut ::c_char, flags: ::c_int) -> ::c_int; + pub fn mkostemps(template: *mut ::c_char, + suffixlen: ::c_int, + flags: ::c_int) -> ::c_int; + + pub fn getutxuser(user: *const ::c_char) -> *mut utmpx; + pub fn setutxdb(_type: ::c_int, file: *const ::c_char) -> ::c_int; + + pub fn aio_waitcomplete(iocbp: *mut *mut aiocb, + timeout: *mut ::timespec) -> ::ssize_t; + pub fn mq_getfd_np(mqd: ::mqd_t) -> ::c_int; + + pub fn freelocale(loc: ::locale_t) -> ::c_int; + pub fn waitid(idtype: idtype_t, id: ::id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + + pub fn ftok(pathname: *const ::c_char, proj_id: ::c_int) -> ::key_t; + pub fn shmget(key: ::key_t, size: ::size_t, shmflg: ::c_int) -> ::c_int; + pub fn shmat(shmid: ::c_int, shmaddr: *const ::c_void, + shmflg: ::c_int) -> *mut ::c_void; + pub fn shmdt(shmaddr: *const ::c_void) -> ::c_int; + pub fn shmctl(shmid: ::c_int, cmd: ::c_int, + buf: *mut ::shmid_ds) -> ::c_int; + pub fn msgctl(msqid: ::c_int, cmd: ::c_int, + buf: *mut ::msqid_ds) -> ::c_int; + pub fn msgget(key: ::key_t, msgflg: ::c_int) -> ::c_int; + pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t, + msgtyp: ::c_long, msgflg: ::c_int) -> ::c_int; + pub fn msgsnd(msqid: ::c_int, msgp: *const ::c_void, msgsz: ::size_t, + msgflg: ::c_int) -> ::c_int; + pub fn cfmakesane(termios: *mut ::termios); + pub fn fexecve(fd: ::c_int, argv: *const *const ::c_char, + envp: *const *const ::c_char) + -> ::c_int; + + pub fn pdfork(fdp: *mut ::c_int, flags: ::c_int) -> ::pid_t; + pub fn pdgetpid(fd: ::c_int, pidp: *mut ::pid_t) -> ::c_int; + pub fn pdkill(fd: ::c_int, signum: ::c_int) -> ::c_int; + + pub fn rtprio_thread(function: ::c_int, lwpid: ::lwpid_t, + rtp: *mut super::rtprio) -> ::c_int; + + pub fn posix_spawn(pid: *mut ::pid_t, + path: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnp(pid: *mut ::pid_t, + file: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_getsigdefault(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigdefault(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getsigmask(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigmask(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, + flags: *mut ::c_short) -> ::c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, + flags: ::c_short) -> ::c_int; + pub fn posix_spawnattr_getpgroup(attr: *const posix_spawnattr_t, + flags: *mut ::pid_t) -> ::c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, + flags: ::pid_t) -> ::c_int; + pub fn posix_spawnattr_getschedpolicy(attr: *const posix_spawnattr_t, + flags: *mut ::c_int) -> ::c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, + flags: ::c_int) -> ::c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut ::sched_param, + ) -> ::c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const ::sched_param, + ) -> ::c_int; + + pub fn posix_spawn_file_actions_init( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_destroy( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + path: *const ::c_char, + oflag: ::c_int, + mode: ::mode_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + ) -> ::c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + newfd: ::c_int, + ) -> ::c_int; + + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + + pub fn dup3(src: ::c_int, dst: ::c_int, flags: ::c_int) -> ::c_int; + pub fn __xuname(nmln: ::c_int, buf: *mut ::c_void) -> ::c_int; + + pub fn sendmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::size_t, + flags: ::c_int) -> ::ssize_t; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::size_t, + flags: ::c_int, timeout: *const ::timespec) -> ::ssize_t; +} + +#[link(name = "util")] +extern { + pub fn extattr_namespace_to_string(attrnamespace: ::c_int, + string: *mut *mut ::c_char) -> ::c_int; + pub fn extattr_string_to_namespace(string: *const ::c_char, + attrnamespace: *mut ::c_int) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "powerpc64")] { + mod powerpc64; + pub use self::powerpc64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs b/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs new file mode 100644 index 000000000..9d893b69a --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/powerpc64.rs @@ -0,0 +1,44 @@ +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type time_t = i64; +pub type suseconds_t = i64; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::fflags_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + } +} + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const MAP_32BIT: ::c_int = 0x00080000; diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs b/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs new file mode 100644 index 000000000..845124d04 --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/x86.rs @@ -0,0 +1,43 @@ +pub type c_char = i8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type time_t = i32; +pub type suseconds_t = i32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::fflags_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + __unused: [u8; 8], + } +} + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} diff --git a/libc/src/unix/bsd/freebsdlike/freebsd/x86_64.rs b/libc/src/unix/bsd/freebsdlike/freebsd/x86_64.rs new file mode 100644 index 000000000..323d1ab7b --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/freebsd/x86_64.rs @@ -0,0 +1,43 @@ +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type time_t = i64; +pub type suseconds_t = i64; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::fflags_t, + pub st_gen: ::uint32_t, + pub st_lspare: ::int32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + } +} + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} +pub const MAP_32BIT: ::c_int = 0x00080000; diff --git a/libc/src/unix/bsd/freebsdlike/mod.rs b/libc/src/unix/bsd/freebsdlike/mod.rs new file mode 100644 index 000000000..7a82a45e1 --- /dev/null +++ b/libc/src/unix/bsd/freebsdlike/mod.rs @@ -0,0 +1,1315 @@ +pub type dev_t = u32; +pub type mode_t = u16; +pub type pthread_attr_t = *mut ::c_void; +pub type rlim_t = i64; +pub type pthread_mutex_t = *mut ::c_void; +pub type pthread_mutexattr_t = *mut ::c_void; +pub type pthread_cond_t = *mut ::c_void; +pub type pthread_condattr_t = *mut ::c_void; +pub type pthread_rwlock_t = *mut ::c_void; +pub type pthread_rwlockattr_t = *mut ::c_void; +pub type pthread_key_t = ::c_int; +pub type tcflag_t = ::c_uint; +pub type speed_t = ::c_uint; +pub type nl_item = ::c_int; +pub type id_t = i64; +pub type vm_size_t = ::uintptr_t; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_matchc: ::size_t, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + pub gl_pathv: *mut *mut ::c_char, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + __unused8: *mut ::c_void, + } + + pub struct kevent { + pub ident: ::uintptr_t, + pub filter: ::c_short, + pub flags: ::c_ushort, + pub fflags: ::c_uint, + pub data: ::intptr_t, + pub udata: *mut ::c_void, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct sigset_t { + bits: [u32; 4], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub si_pid: ::pid_t, + pub si_uid: ::uid_t, + pub si_status: ::c_int, + pub si_addr: *mut ::c_void, + _pad: [::c_int; 12], + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_flags: ::c_int, + pub sa_mask: sigset_t, + } + + pub struct sched_param { + pub sched_priority: ::c_int, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::c_char; 8], + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + pub l_type: ::c_short, + pub l_whence: ::c_short, + #[cfg(not(target_os = "dragonfly"))] + pub l_sysid: ::c_int, + } + + pub struct sf_hdtr { + pub headers: *mut ::iovec, + pub hdr_cnt: ::c_int, + pub trailers: *mut ::iovec, + pub trl_cnt: ::c_int, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct cmsgcred { + pub cmcred_pid: ::pid_t, + pub cmcred_uid: ::uid_t, + pub cmcred_euid: ::uid_t, + pub cmcred_gid: ::gid_t, + pub cmcred_ngroups: ::c_short, + pub cmcred_groups: [::gid_t; CMGROUP_MAX], + } + + pub struct rtprio { + pub type_: ::c_ushort, + pub prio: ::c_ushort, + } + + pub struct in6_pktinfo { + pub ipi6_addr: ::in6_addr, + pub ipi6_ifindex: ::c_uint, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } +} + +s_no_extra_traits! { + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: ::sa_family_t, + __ss_pad1: [u8; 6], + __ss_align: i64, + __ss_pad2: [u8; 112], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_len == other.ss_len + && self.ss_family == other.ss_family + && self.__ss_pad1 == other.__ss_pad1 + && self.__ss_align == other.__ss_align + && self + .__ss_pad2 + .iter() + .zip(other.__ss_pad2.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_len", &self.ss_len) + .field("ss_family", &self.ss_family) + .field("__ss_pad1", &self.__ss_pad1) + .field("__ss_align", &self.__ss_align) + // FIXME: .field("__ss_pad2", &self.__ss_pad2) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_len.hash(state); + self.ss_family.hash(state); + self.__ss_pad1.hash(state); + self.__ss_align.hash(state); + self.__ss_pad2.hash(state); + } + } + } +} + +pub const AIO_LISTIO_MAX: ::c_int = 16; +pub const AIO_CANCELED: ::c_int = 1; +pub const AIO_NOTCANCELED: ::c_int = 2; +pub const AIO_ALLDONE: ::c_int = 3; +pub const LIO_NOP: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 1; +pub const LIO_READ: ::c_int = 2; +pub const LIO_WAIT: ::c_int = 1; +pub const LIO_NOWAIT: ::c_int = 0; + +pub const SIGEV_NONE: ::c_int = 0; +pub const SIGEV_SIGNAL: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; +pub const SIGEV_KEVENT: ::c_int = 3; + +pub const CODESET: ::nl_item = 0; +pub const D_T_FMT: ::nl_item = 1; +pub const D_FMT: ::nl_item = 2; +pub const T_FMT: ::nl_item = 3; +pub const T_FMT_AMPM: ::nl_item = 4; +pub const AM_STR: ::nl_item = 5; +pub const PM_STR: ::nl_item = 6; + +pub const DAY_1: ::nl_item = 7; +pub const DAY_2: ::nl_item = 8; +pub const DAY_3: ::nl_item = 9; +pub const DAY_4: ::nl_item = 10; +pub const DAY_5: ::nl_item = 11; +pub const DAY_6: ::nl_item = 12; +pub const DAY_7: ::nl_item = 13; + +pub const ABDAY_1: ::nl_item = 14; +pub const ABDAY_2: ::nl_item = 15; +pub const ABDAY_3: ::nl_item = 16; +pub const ABDAY_4: ::nl_item = 17; +pub const ABDAY_5: ::nl_item = 18; +pub const ABDAY_6: ::nl_item = 19; +pub const ABDAY_7: ::nl_item = 20; + +pub const MON_1: ::nl_item = 21; +pub const MON_2: ::nl_item = 22; +pub const MON_3: ::nl_item = 23; +pub const MON_4: ::nl_item = 24; +pub const MON_5: ::nl_item = 25; +pub const MON_6: ::nl_item = 26; +pub const MON_7: ::nl_item = 27; +pub const MON_8: ::nl_item = 28; +pub const MON_9: ::nl_item = 29; +pub const MON_10: ::nl_item = 30; +pub const MON_11: ::nl_item = 31; +pub const MON_12: ::nl_item = 32; + +pub const ABMON_1: ::nl_item = 33; +pub const ABMON_2: ::nl_item = 34; +pub const ABMON_3: ::nl_item = 35; +pub const ABMON_4: ::nl_item = 36; +pub const ABMON_5: ::nl_item = 37; +pub const ABMON_6: ::nl_item = 38; +pub const ABMON_7: ::nl_item = 39; +pub const ABMON_8: ::nl_item = 40; +pub const ABMON_9: ::nl_item = 41; +pub const ABMON_10: ::nl_item = 42; +pub const ABMON_11: ::nl_item = 43; +pub const ABMON_12: ::nl_item = 44; + +pub const ERA: ::nl_item = 45; +pub const ERA_D_FMT: ::nl_item = 46; +pub const ERA_D_T_FMT: ::nl_item = 47; +pub const ERA_T_FMT: ::nl_item = 48; +pub const ALT_DIGITS: ::nl_item = 49; + +pub const RADIXCHAR: ::nl_item = 50; +pub const THOUSEP: ::nl_item = 51; + +pub const YESEXPR: ::nl_item = 52; +pub const NOEXPR: ::nl_item = 53; + +pub const YESSTR: ::nl_item = 54; +pub const NOSTR: ::nl_item = 55; + +pub const CRNCYSTR: ::nl_item = 56; + +pub const D_MD_ORDER: ::nl_item = 57; + +pub const ALTMON_1: ::nl_item = 58; +pub const ALTMON_2: ::nl_item = 59; +pub const ALTMON_3: ::nl_item = 60; +pub const ALTMON_4: ::nl_item = 61; +pub const ALTMON_5: ::nl_item = 62; +pub const ALTMON_6: ::nl_item = 63; +pub const ALTMON_7: ::nl_item = 64; +pub const ALTMON_8: ::nl_item = 65; +pub const ALTMON_9: ::nl_item = 66; +pub const ALTMON_10: ::nl_item = 67; +pub const ALTMON_11: ::nl_item = 68; +pub const ALTMON_12: ::nl_item = 69; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const SEEK_DATA: ::c_int = 3; +pub const SEEK_HOLE: ::c_int = 4; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; +pub const BUFSIZ: ::c_uint = 1024; +pub const FOPEN_MAX: ::c_uint = 20; +pub const FILENAME_MAX: ::c_uint = 1024; +pub const L_tmpnam: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 308915776; + +pub const O_NOCTTY: ::c_int = 32768; +pub const O_DIRECT: ::c_int = 0x00010000; + +pub const S_IFIFO: mode_t = 4096; +pub const S_IFCHR: mode_t = 8192; +pub const S_IFBLK: mode_t = 24576; +pub const S_IFDIR: mode_t = 16384; +pub const S_IFREG: mode_t = 32768; +pub const S_IFLNK: mode_t = 40960; +pub const S_IFSOCK: mode_t = 49152; +pub const S_IFMT: mode_t = 61440; +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; +pub const S_IRWXU: mode_t = 448; +pub const S_IXUSR: mode_t = 64; +pub const S_IWUSR: mode_t = 128; +pub const S_IRUSR: mode_t = 256; +pub const S_IRWXG: mode_t = 56; +pub const S_IXGRP: mode_t = 8; +pub const S_IWGRP: mode_t = 16; +pub const S_IRGRP: mode_t = 32; +pub const S_IRWXO: mode_t = 7; +pub const S_IXOTH: mode_t = 1; +pub const S_IWOTH: mode_t = 2; +pub const S_IROTH: mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; +pub const F_DUPFD_CLOEXEC: ::c_int = 17; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGEMT: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const MAP_FILE: ::c_int = 0x0000; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; +pub const MAP_ANON: ::c_int = 0x1000; +pub const MAP_ANONYMOUS: ::c_int = MAP_ANON; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const MS_SYNC: ::c_int = 0x0000; +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EDEADLK: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EAGAIN: ::c_int = 35; +pub const EWOULDBLOCK: ::c_int = 35; +pub const EINPROGRESS: ::c_int = 36; +pub const EALREADY: ::c_int = 37; +pub const ENOTSOCK: ::c_int = 38; +pub const EDESTADDRREQ: ::c_int = 39; +pub const EMSGSIZE: ::c_int = 40; +pub const EPROTOTYPE: ::c_int = 41; +pub const ENOPROTOOPT: ::c_int = 42; +pub const EPROTONOSUPPORT: ::c_int = 43; +pub const ESOCKTNOSUPPORT: ::c_int = 44; +pub const EOPNOTSUPP: ::c_int = 45; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 46; +pub const EAFNOSUPPORT: ::c_int = 47; +pub const EADDRINUSE: ::c_int = 48; +pub const EADDRNOTAVAIL: ::c_int = 49; +pub const ENETDOWN: ::c_int = 50; +pub const ENETUNREACH: ::c_int = 51; +pub const ENETRESET: ::c_int = 52; +pub const ECONNABORTED: ::c_int = 53; +pub const ECONNRESET: ::c_int = 54; +pub const ENOBUFS: ::c_int = 55; +pub const EISCONN: ::c_int = 56; +pub const ENOTCONN: ::c_int = 57; +pub const ESHUTDOWN: ::c_int = 58; +pub const ETOOMANYREFS: ::c_int = 59; +pub const ETIMEDOUT: ::c_int = 60; +pub const ECONNREFUSED: ::c_int = 61; +pub const ELOOP: ::c_int = 62; +pub const ENAMETOOLONG: ::c_int = 63; +pub const EHOSTDOWN: ::c_int = 64; +pub const EHOSTUNREACH: ::c_int = 65; +pub const ENOTEMPTY: ::c_int = 66; +pub const EPROCLIM: ::c_int = 67; +pub const EUSERS: ::c_int = 68; +pub const EDQUOT: ::c_int = 69; +pub const ESTALE: ::c_int = 70; +pub const EREMOTE: ::c_int = 71; +pub const EBADRPC: ::c_int = 72; +pub const ERPCMISMATCH: ::c_int = 73; +pub const EPROGUNAVAIL: ::c_int = 74; +pub const EPROGMISMATCH: ::c_int = 75; +pub const EPROCUNAVAIL: ::c_int = 76; +pub const ENOLCK: ::c_int = 77; +pub const ENOSYS: ::c_int = 78; +pub const EFTYPE: ::c_int = 79; +pub const EAUTH: ::c_int = 80; +pub const ENEEDAUTH: ::c_int = 81; +pub const EIDRM: ::c_int = 82; +pub const ENOMSG: ::c_int = 83; +pub const EOVERFLOW: ::c_int = 84; +pub const ECANCELED: ::c_int = 85; +pub const EILSEQ: ::c_int = 86; +pub const ENOATTR: ::c_int = 87; +pub const EDOOFUS: ::c_int = 88; +pub const EBADMSG: ::c_int = 89; +pub const EMULTIHOP: ::c_int = 90; +pub const ENOLINK: ::c_int = 91; +pub const EPROTO: ::c_int = 92; + +pub const POLLSTANDARD: ::c_short = ::POLLIN | ::POLLPRI | ::POLLOUT | + ::POLLRDNORM | ::POLLRDBAND | ::POLLWRBAND | ::POLLERR | + ::POLLHUP | ::POLLNVAL; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 14; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; + +pub const SIGTRAP: ::c_int = 5; + +pub const GLOB_APPEND : ::c_int = 0x0001; +pub const GLOB_DOOFFS : ::c_int = 0x0002; +pub const GLOB_ERR : ::c_int = 0x0004; +pub const GLOB_MARK : ::c_int = 0x0008; +pub const GLOB_NOCHECK : ::c_int = 0x0010; +pub const GLOB_NOSORT : ::c_int = 0x0020; +pub const GLOB_NOESCAPE: ::c_int = 0x2000; + +pub const GLOB_NOSPACE : ::c_int = -1; +pub const GLOB_ABORTED : ::c_int = -2; +pub const GLOB_NOMATCH : ::c_int = -3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; + +pub const PTHREAD_PROCESS_PRIVATE: ::c_int = 0; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 1; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_MEMLOCK: ::c_int = 6; +pub const RLIMIT_NPROC: ::c_int = 7; +pub const RLIMIT_NOFILE: ::c_int = 8; +pub const RLIMIT_SBSIZE: ::c_int = 9; +pub const RLIMIT_VMEM: ::c_int = 10; +pub const RLIMIT_AS: ::c_int = RLIMIT_VMEM; +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; + +pub const RUSAGE_SELF: ::c_int = 0; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_FREE: ::c_int = 5; +pub const MADV_NOSYNC: ::c_int = 6; +pub const MADV_AUTOSYNC: ::c_int = 7; +pub const MADV_NOCORE: ::c_int = 8; +pub const MADV_CORE: ::c_int = 9; + +pub const MINCORE_INCORE: ::c_int = 0x1; +pub const MINCORE_REFERENCED: ::c_int = 0x2; +pub const MINCORE_MODIFIED: ::c_int = 0x4; +pub const MINCORE_REFERENCED_OTHER: ::c_int = 0x8; +pub const MINCORE_MODIFIED_OTHER: ::c_int = 0x10; +pub const MINCORE_SUPER: ::c_int = 0x20; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_UNIX: ::c_int = AF_LOCAL; +pub const AF_INET: ::c_int = 2; +pub const AF_IMPLINK: ::c_int = 3; +pub const AF_PUP: ::c_int = 4; +pub const AF_CHAOS: ::c_int = 5; +pub const AF_NETBIOS: ::c_int = 6; +pub const AF_ISO: ::c_int = 7; +pub const AF_OSI: ::c_int = AF_ISO; +pub const AF_ECMA: ::c_int = 8; +pub const AF_DATAKIT: ::c_int = 9; +pub const AF_CCITT: ::c_int = 10; +pub const AF_SNA: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_DLI: ::c_int = 13; +pub const AF_LAT: ::c_int = 14; +pub const AF_HYLINK: ::c_int = 15; +pub const AF_APPLETALK: ::c_int = 16; +pub const AF_ROUTE: ::c_int = 17; +pub const AF_LINK: ::c_int = 18; +pub const pseudo_AF_XTP: ::c_int = 19; +pub const AF_COIP: ::c_int = 20; +pub const AF_CNT: ::c_int = 21; +pub const pseudo_AF_RTIP: ::c_int = 22; +pub const AF_IPX: ::c_int = 23; +pub const AF_SIP: ::c_int = 24; +pub const pseudo_AF_PIP: ::c_int = 25; +pub const AF_ISDN: ::c_int = 26; +pub const AF_E164: ::c_int = AF_ISDN; +pub const pseudo_AF_KEY: ::c_int = 27; +pub const AF_INET6: ::c_int = 28; +pub const AF_NATM: ::c_int = 29; +pub const AF_ATM: ::c_int = 30; +pub const pseudo_AF_HDRCMPLT: ::c_int = 31; +pub const AF_NETGRAPH: ::c_int = 32; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_UNIX: ::c_int = PF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_IMPLINK: ::c_int = AF_IMPLINK; +pub const PF_PUP: ::c_int = AF_PUP; +pub const PF_CHAOS: ::c_int = AF_CHAOS; +pub const PF_NETBIOS: ::c_int = AF_NETBIOS; +pub const PF_ISO: ::c_int = AF_ISO; +pub const PF_OSI: ::c_int = AF_ISO; +pub const PF_ECMA: ::c_int = AF_ECMA; +pub const PF_DATAKIT: ::c_int = AF_DATAKIT; +pub const PF_CCITT: ::c_int = AF_CCITT; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_DLI: ::c_int = AF_DLI; +pub const PF_LAT: ::c_int = AF_LAT; +pub const PF_HYLINK: ::c_int = AF_HYLINK; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_LINK: ::c_int = AF_LINK; +pub const PF_XTP: ::c_int = pseudo_AF_XTP; +pub const PF_COIP: ::c_int = AF_COIP; +pub const PF_CNT: ::c_int = AF_CNT; +pub const PF_SIP: ::c_int = AF_SIP; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_RTIP: ::c_int = pseudo_AF_RTIP; +pub const PF_PIP: ::c_int = pseudo_AF_PIP; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_KEY: ::c_int = pseudo_AF_KEY; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_NATM: ::c_int = AF_NATM; +pub const PF_ATM: ::c_int = AF_ATM; +pub const PF_NETGRAPH: ::c_int = AF_NETGRAPH; + +pub const PT_TRACE_ME: ::c_int = 0; +pub const PT_READ_I: ::c_int = 1; +pub const PT_READ_D: ::c_int = 2; +pub const PT_WRITE_I: ::c_int = 4; +pub const PT_WRITE_D: ::c_int = 5; +pub const PT_CONTINUE: ::c_int = 7; +pub const PT_KILL: ::c_int = 8; +pub const PT_STEP: ::c_int = 9; +pub const PT_ATTACH: ::c_int = 10; +pub const PT_DETACH: ::c_int = 11; +pub const PT_IO: ::c_int = 12; + +pub const SOMAXCONN: ::c_int = 128; + +pub const MSG_OOB: ::c_int = 0x00000001; +pub const MSG_PEEK: ::c_int = 0x00000002; +pub const MSG_DONTROUTE: ::c_int = 0x00000004; +pub const MSG_EOR: ::c_int = 0x00000008; +pub const MSG_TRUNC: ::c_int = 0x00000010; +pub const MSG_CTRUNC: ::c_int = 0x00000020; +pub const MSG_WAITALL: ::c_int = 0x00000040; +pub const MSG_DONTWAIT: ::c_int = 0x00000080; +pub const MSG_EOF: ::c_int = 0x00000100; + +pub const SCM_TIMESTAMP: ::c_int = 0x02; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_RDM: ::c_int = 4; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const SOCK_CLOEXEC: ::c_int = 0x10000000; +pub const SOCK_NONBLOCK: ::c_int = 0x20000000; +pub const SOCK_MAXADDRLEN: ::c_int = 255; +pub const IP_TTL: ::c_int = 4; +pub const IP_HDRINCL: ::c_int = 2; +pub const IP_RECVDSTADDR: ::c_int = 7; +pub const IP_SENDSRCADDR: ::c_int = IP_RECVDSTADDR; +pub const IP_ADD_MEMBERSHIP: ::c_int = 12; +pub const IP_DROP_MEMBERSHIP: ::c_int = 13; +pub const IP_RECVIF: ::c_int = 20; +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; +pub const IPV6_RECVPKTINFO: ::c_int = 36; +pub const IPV6_PKTINFO: ::c_int = 46; +pub const IPV6_RECVTCLASS: ::c_int = 57; +pub const IPV6_TCLASS: ::c_int = 61; + +pub const TCP_NOPUSH: ::c_int = 4; +pub const TCP_NOOPT: ::c_int = 8; +pub const TCP_KEEPIDLE: ::c_int = 256; +pub const TCP_KEEPINTVL: ::c_int = 512; +pub const TCP_KEEPCNT: ::c_int = 1024; + +pub const SOL_SOCKET: ::c_int = 0xffff; +pub const SO_DEBUG: ::c_int = 0x01; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_TIMESTAMP: ::c_int = 0x0400; +pub const SO_NOSIGPIPE: ::c_int = 0x0800; +pub const SO_ACCEPTFILTER: ::c_int = 0x1000; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const MAP_COPY: ::c_int = 0x0002; +pub const MAP_RENAME: ::c_int = 0x0020; +pub const MAP_NORESERVE: ::c_int = 0x0040; +pub const MAP_HASSEMAPHORE: ::c_int = 0x0200; +pub const MAP_STACK: ::c_int = 0x0400; +pub const MAP_NOSYNC: ::c_int = 0x0800; +pub const MAP_NOCORE: ::c_int = 0x020000; + +pub const IPPROTO_RAW: ::c_int = 255; + +pub const _PC_LINK_MAX: ::c_int = 1; +pub const _PC_MAX_CANON: ::c_int = 2; +pub const _PC_MAX_INPUT: ::c_int = 3; +pub const _PC_NAME_MAX: ::c_int = 4; +pub const _PC_PATH_MAX: ::c_int = 5; +pub const _PC_PIPE_BUF: ::c_int = 6; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 7; +pub const _PC_NO_TRUNC: ::c_int = 8; +pub const _PC_VDISABLE: ::c_int = 9; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 10; +pub const _PC_FILESIZEBITS: ::c_int = 12; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 16; +pub const _PC_REC_XFER_ALIGN: ::c_int = 17; +pub const _PC_SYMLINK_MAX: ::c_int = 18; +pub const _PC_MIN_HOLE_SIZE: ::c_int = 21; +pub const _PC_ASYNC_IO: ::c_int = 53; +pub const _PC_PRIO_IO: ::c_int = 54; +pub const _PC_SYNC_IO: ::c_int = 55; +pub const _PC_ACL_EXTENDED: ::c_int = 59; +pub const _PC_ACL_PATH_MAX: ::c_int = 60; +pub const _PC_CAP_PRESENT: ::c_int = 61; +pub const _PC_INF_PRESENT: ::c_int = 62; +pub const _PC_MAC_PRESENT: ::c_int = 63; + +pub const _SC_ARG_MAX: ::c_int = 1; +pub const _SC_CHILD_MAX: ::c_int = 2; +pub const _SC_CLK_TCK: ::c_int = 3; +pub const _SC_NGROUPS_MAX: ::c_int = 4; +pub const _SC_OPEN_MAX: ::c_int = 5; +pub const _SC_JOB_CONTROL: ::c_int = 6; +pub const _SC_SAVED_IDS: ::c_int = 7; +pub const _SC_VERSION: ::c_int = 8; +pub const _SC_BC_BASE_MAX: ::c_int = 9; +pub const _SC_BC_DIM_MAX: ::c_int = 10; +pub const _SC_BC_SCALE_MAX: ::c_int = 11; +pub const _SC_BC_STRING_MAX: ::c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 13; +pub const _SC_EXPR_NEST_MAX: ::c_int = 14; +pub const _SC_LINE_MAX: ::c_int = 15; +pub const _SC_RE_DUP_MAX: ::c_int = 16; +pub const _SC_2_VERSION: ::c_int = 17; +pub const _SC_2_C_BIND: ::c_int = 18; +pub const _SC_2_C_DEV: ::c_int = 19; +pub const _SC_2_CHAR_TERM: ::c_int = 20; +pub const _SC_2_FORT_DEV: ::c_int = 21; +pub const _SC_2_FORT_RUN: ::c_int = 22; +pub const _SC_2_LOCALEDEF: ::c_int = 23; +pub const _SC_2_SW_DEV: ::c_int = 24; +pub const _SC_2_UPE: ::c_int = 25; +pub const _SC_STREAM_MAX: ::c_int = 26; +pub const _SC_TZNAME_MAX: ::c_int = 27; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 28; +pub const _SC_MAPPED_FILES: ::c_int = 29; +pub const _SC_MEMLOCK: ::c_int = 30; +pub const _SC_MEMLOCK_RANGE: ::c_int = 31; +pub const _SC_MEMORY_PROTECTION: ::c_int = 32; +pub const _SC_MESSAGE_PASSING: ::c_int = 33; +pub const _SC_PRIORITIZED_IO: ::c_int = 34; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 35; +pub const _SC_REALTIME_SIGNALS: ::c_int = 36; +pub const _SC_SEMAPHORES: ::c_int = 37; +pub const _SC_FSYNC: ::c_int = 38; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 39; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 40; +pub const _SC_TIMERS: ::c_int = 41; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 42; +pub const _SC_AIO_MAX: ::c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 44; +pub const _SC_DELAYTIMER_MAX: ::c_int = 45; +pub const _SC_MQ_OPEN_MAX: ::c_int = 46; +pub const _SC_PAGESIZE: ::c_int = 47; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: ::c_int = 48; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 49; +pub const _SC_SEM_VALUE_MAX: ::c_int = 50; +pub const _SC_SIGQUEUE_MAX: ::c_int = 51; +pub const _SC_TIMER_MAX: ::c_int = 52; +pub const _SC_IOV_MAX: ::c_int = 56; +pub const _SC_NPROCESSORS_CONF: ::c_int = 57; +pub const _SC_2_PBS: ::c_int = 59; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 60; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 61; +pub const _SC_2_PBS_LOCATE: ::c_int = 62; +pub const _SC_2_PBS_MESSAGE: ::c_int = 63; +pub const _SC_2_PBS_TRACK: ::c_int = 64; +pub const _SC_ADVISORY_INFO: ::c_int = 65; +pub const _SC_BARRIERS: ::c_int = 66; +pub const _SC_CLOCK_SELECTION: ::c_int = 67; +pub const _SC_CPUTIME: ::c_int = 68; +pub const _SC_FILE_LOCKING: ::c_int = 69; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 58; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 70; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 71; +pub const _SC_HOST_NAME_MAX: ::c_int = 72; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 73; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 74; +pub const _SC_MQ_PRIO_MAX: ::c_int = 75; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 76; +pub const _SC_REGEXP: ::c_int = 77; +pub const _SC_SHELL: ::c_int = 78; +pub const _SC_SPAWN: ::c_int = 79; +pub const _SC_SPIN_LOCKS: ::c_int = 80; +pub const _SC_SPORADIC_SERVER: ::c_int = 81; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 82; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 83; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 85; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 86; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 87; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 88; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 89; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 90; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 91; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 92; +pub const _SC_THREAD_STACK_MIN: ::c_int = 93; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 94; +pub const _SC_TIMEOUTS: ::c_int = 95; +pub const _SC_THREADS: ::c_int = 96; +pub const _SC_TRACE: ::c_int = 97; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 98; +pub const _SC_TRACE_INHERIT: ::c_int = 99; +pub const _SC_TRACE_LOG: ::c_int = 100; +pub const _SC_TTY_NAME_MAX: ::c_int = 101; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 102; +pub const _SC_V6_ILP32_OFF32: ::c_int = 103; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 104; +pub const _SC_V6_LP64_OFF64: ::c_int = 105; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 106; +pub const _SC_ATEXIT_MAX: ::c_int = 107; +pub const _SC_XOPEN_CRYPT: ::c_int = 108; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 109; +pub const _SC_XOPEN_LEGACY: ::c_int = 110; +pub const _SC_XOPEN_REALTIME: ::c_int = 111; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 112; +pub const _SC_XOPEN_SHM: ::c_int = 113; +pub const _SC_XOPEN_STREAMS: ::c_int = 114; +pub const _SC_XOPEN_UNIX: ::c_int = 115; +pub const _SC_XOPEN_VERSION: ::c_int = 116; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 117; +pub const _SC_IPV6: ::c_int = 118; +pub const _SC_RAW_SOCKETS: ::c_int = 119; +pub const _SC_SYMLOOP_MAX: ::c_int = 120; +pub const _SC_PHYS_PAGES: ::c_int = 121; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 3; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_ERRORCHECK; + +pub const SCHED_FIFO: ::c_int = 1; +pub const SCHED_OTHER: ::c_int = 2; +pub const SCHED_RR: ::c_int = 3; + +pub const FD_SETSIZE: usize = 1024; + +pub const ST_NOSUID: ::c_ulong = 2; + +pub const NI_MAXHOST: ::size_t = 1025; + +pub const RTLD_LOCAL: ::c_int = 0; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_NOLOAD: ::c_int = 0x2000; +pub const RTLD_GLOBAL: ::c_int = 0x100; + +pub const LOG_NTP: ::c_int = 12 << 3; +pub const LOG_SECURITY: ::c_int = 13 << 3; +pub const LOG_CONSOLE: ::c_int = 14 << 3; +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const TIOCEXCL: ::c_uint = 0x2000740d; +pub const TIOCNXCL: ::c_uint = 0x2000740e; +pub const TIOCFLUSH: ::c_ulong = 0x80047410; +pub const TIOCGETA: ::c_uint = 0x402c7413; +pub const TIOCSETA: ::c_ulong = 0x802c7414; +pub const TIOCSETAW: ::c_ulong = 0x802c7415; +pub const TIOCSETAF: ::c_ulong = 0x802c7416; +pub const TIOCGETD: ::c_uint = 0x4004741a; +pub const TIOCSETD: ::c_ulong = 0x8004741b; +pub const TIOCGDRAINWAIT: ::c_uint = 0x40047456; +pub const TIOCSDRAINWAIT: ::c_ulong = 0x80047457; +pub const TIOCTIMESTAMP: ::c_uint = 0x40107459; +pub const TIOCMGDTRWAIT: ::c_uint = 0x4004745a; +pub const TIOCMSDTRWAIT: ::c_ulong = 0x8004745b; +pub const TIOCDRAIN: ::c_uint = 0x2000745e; +pub const TIOCEXT: ::c_ulong = 0x80047460; +pub const TIOCSCTTY: ::c_uint = 0x20007461; +pub const TIOCCONS: ::c_ulong = 0x80047462; +pub const TIOCGSID: ::c_uint = 0x40047463; +pub const TIOCSTAT: ::c_uint = 0x20007465; +pub const TIOCUCNTL: ::c_ulong = 0x80047466; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const TIOCGWINSZ: ::c_uint = 0x40087468; +pub const TIOCMGET: ::c_uint = 0x4004746a; +pub const TIOCM_LE: ::c_int = 0x1; +pub const TIOCM_DTR: ::c_int = 0x2; +pub const TIOCM_RTS: ::c_int = 0x4; +pub const TIOCM_ST: ::c_int = 0x8; +pub const TIOCM_SR: ::c_int = 0x10; +pub const TIOCM_CTS: ::c_int = 0x20; +pub const TIOCM_RI: ::c_int = 0x80; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = 0x40; +pub const TIOCM_CAR: ::c_int = 0x40; +pub const TIOCM_RNG: ::c_int = 0x80; +pub const TIOCMBIC: ::c_ulong = 0x8004746b; +pub const TIOCMBIS: ::c_ulong = 0x8004746c; +pub const TIOCMSET: ::c_ulong = 0x8004746d; +pub const TIOCSTART: ::c_uint = 0x2000746e; +pub const TIOCSTOP: ::c_uint = 0x2000746f; +pub const TIOCPKT: ::c_ulong = 0x80047470; +pub const TIOCPKT_DATA: ::c_int = 0x0; +pub const TIOCPKT_FLUSHREAD: ::c_int = 0x1; +pub const TIOCPKT_FLUSHWRITE: ::c_int = 0x2; +pub const TIOCPKT_STOP: ::c_int = 0x4; +pub const TIOCPKT_START: ::c_int = 0x8; +pub const TIOCPKT_NOSTOP: ::c_int = 0x10; +pub const TIOCPKT_DOSTOP: ::c_int = 0x20; +pub const TIOCPKT_IOCTL: ::c_int = 0x40; +pub const TIOCNOTTY: ::c_uint = 0x20007471; +pub const TIOCSTI: ::c_ulong = 0x80017472; +pub const TIOCOUTQ: ::c_uint = 0x40047473; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCGPGRP: ::c_uint = 0x40047477; +pub const TIOCCDTR: ::c_uint = 0x20007478; +pub const TIOCSDTR: ::c_uint = 0x20007479; +pub const TIOCCBRK: ::c_uint = 0x2000747a; +pub const TIOCSBRK: ::c_uint = 0x2000747b; +pub const TTYDISC: ::c_int = 0x0; +pub const SLIPDISC: ::c_int = 0x4; +pub const PPPDISC: ::c_int = 0x5; +pub const NETGRAPHDISC: ::c_int = 0x6; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SEM_FAILED: *mut sem_t = 0 as *mut sem_t; + +pub const CRTSCTS: ::tcflag_t = 0x00030000; +pub const CCTS_OFLOW: ::tcflag_t = 0x00010000; +pub const CRTS_IFLOW: ::tcflag_t = 0x00020000; +pub const CDTR_IFLOW: ::tcflag_t = 0x00040000; +pub const CDSR_OFLOW: ::tcflag_t = 0x00080000; +pub const CCAR_OFLOW: ::tcflag_t = 0x00100000; +pub const VERASE2: usize = 7; +pub const OCRNL: ::tcflag_t = 0x10; +pub const ONOCR: ::tcflag_t = 0x20; +pub const ONLRET: ::tcflag_t = 0x40; + +pub const CMGROUP_MAX: usize = 16; + +// https://github.com/freebsd/freebsd/blob/master/sys/net/bpf.h +// sizeof(long) +pub const BPF_ALIGNMENT: ::c_int = 8; + +// Values for rtprio struct (prio field) and syscall (function argument) +pub const RTP_PRIO_MIN: ::c_ushort = 0; +pub const RTP_PRIO_MAX: ::c_ushort = 31; +pub const RTP_LOOKUP: ::c_int = 0; +pub const RTP_SET: ::c_int = 1; + +// Flags for chflags(2) +pub const UF_SETTABLE: ::c_ulong = 0x0000ffff; +pub const UF_NODUMP: ::c_ulong = 0x00000001; +pub const UF_IMMUTABLE: ::c_ulong = 0x00000002; +pub const UF_APPEND: ::c_ulong = 0x00000004; +pub const UF_OPAQUE: ::c_ulong = 0x00000008; +pub const UF_NOUNLINK: ::c_ulong = 0x00000010; +pub const SF_SETTABLE: ::c_ulong = 0xffff0000; +pub const SF_ARCHIVED: ::c_ulong = 0x00010000; +pub const SF_IMMUTABLE: ::c_ulong = 0x00020000; +pub const SF_APPEND: ::c_ulong = 0x00040000; +pub const SF_NOUNLINK: ::c_ulong = 0x00100000; + +pub const TIMER_ABSTIME: ::c_int = 1; + +f! { + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0x13 + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + status >> 8 + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0o177) == 0o177 + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + + pub fn accept4(s: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t, flags: ::c_int) -> ::c_int; + pub fn aio_read(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_fsync(op: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_error(aiocbp: *const aiocb) -> ::c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ::ssize_t; + pub fn aio_suspend(aiocb_list: *const *const aiocb, nitems: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn aio_cancel(fd: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn chflags(path: *const ::c_char, flags: ::c_ulong) -> ::c_int; + pub fn chflagsat(fd: ::c_int, path: *const ::c_char, flags: ::c_ulong, + atflag: ::c_int) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn endutxent(); + pub fn fchflags(fd: ::c_int, flags: ::c_ulong) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn getdomainname(name: *mut ::c_char, len: ::c_int) -> ::c_int; + pub fn getgrent_r(grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwent_r50")] + pub fn getpwent_r(pwd: *mut ::passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::passwd) -> ::c_int; + pub fn getgrouplist(name: *const ::c_char, + basegid: ::gid_t, + groups: *mut ::gid_t, + ngroups: *mut ::c_int) -> ::c_int; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::size_t, + serv: *mut ::c_char, + servlen: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn getpriority(which: ::c_int, who: ::c_int) -> ::c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn initgroups(name: *const ::c_char, basegid: ::gid_t) -> ::c_int; + #[cfg_attr(target_os = "freebsd", link_name = "kevent@FBSD_1.0")] + pub fn kevent(kq: ::c_int, + changelist: *const ::kevent, + nchanges: ::c_int, + eventlist: *mut ::kevent, + nevents: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn lchflags(path: *const ::c_char, flags: ::c_ulong) -> ::c_int; + pub fn lio_listio(mode: ::c_int, aiocb_list: *const *mut aiocb, + nitems: ::c_int, sevp: *mut sigevent) -> ::c_int; + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + pub fn memrchr(cx: *const ::c_void, + c: ::c_int, + n: ::size_t) -> *mut ::c_void; + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + #[cfg_attr(target_os = "freebsd", link_name = "mknodat@FBSD_1.1")] + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn mq_close(mqd: ::mqd_t) -> ::c_int; + pub fn mq_getattr(mqd: ::mqd_t, attr: *mut ::mq_attr) -> ::c_int; + pub fn mq_notify(mqd: ::mqd_t, notification: *const ::sigevent) -> ::c_int; + pub fn mq_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::mqd_t; + pub fn mq_receive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint) -> ::ssize_t; + pub fn mq_send(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint) -> ::c_int; + pub fn mq_setattr(mqd: ::mqd_t, + newattr: *const ::mq_attr, + oldattr: *mut ::mq_attr) -> ::c_int; + pub fn mq_timedreceive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint, + abs_timeout: *const ::timespec) -> ::ssize_t; + pub fn mq_timedsend(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint, + abs_timeout: *const ::timespec) -> ::c_int; + pub fn mq_unlink(name: *const ::c_char) -> ::c_int; + pub fn mincore(addr: *const ::c_void, len: ::size_t, + vec: *mut ::c_char) -> ::c_int; + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; + pub fn ppoll(fds: *mut ::pollfd, + nfds: ::nfds_t, + timeout: *const ::timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn pthread_attr_get_np(tid: ::pthread_t, + attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn pthread_set_name_np(tid: ::pthread_t, name: *const ::c_char); + pub fn ptrace(request: ::c_int, + pid: ::pid_t, + addr: *mut ::c_char, + data: ::c_int) -> ::c_int; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn querylocale(mask: ::c_int, loc: ::locale_t) -> *const ::c_char; + pub fn rtprio(function: ::c_int, pid: ::pid_t, rtp: *mut rtprio) -> ::c_int; + pub fn sched_getscheduler(pid: ::pid_t) -> ::c_int; + pub fn sched_setscheduler(pid: ::pid_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sendfile(fd: ::c_int, + s: ::c_int, + offset: ::off_t, + nbytes: ::size_t, + hdtr: *mut ::sf_hdtr, + sbytes: *mut ::off_t, + flags: ::c_int) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::c_int) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::c_int) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::c_int, prio: ::c_int) -> ::c_int; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; + pub fn settimeofday(tv: *const ::timeval, tz: *const ::timezone) -> ::c_int; + pub fn setutxent(); + pub fn shm_open(name: *const ::c_char, oflag: ::c_int, mode: ::mode_t) + -> ::c_int; + pub fn sigtimedwait(set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const ::timespec) -> ::c_int; + pub fn sigwaitinfo(set: *const sigset_t, + info: *mut siginfo_t) -> ::c_int; + pub fn sysctl(name: *const ::c_int, + namelen: ::c_uint, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *const ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn sysctlbyname(name: *const ::c_char, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *const ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn sysctlnametomib(name: *const ::c_char, + mibp: *mut ::c_int, + sizep: *mut ::size_t) + -> ::c_int; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; +} + +#[link(name = "util")] +extern { + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::c_int; + pub fn forkpty(amaster: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::pid_t; + pub fn login_tty(fd: ::c_int) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_os = "freebsd")] { + mod freebsd; + pub use self::freebsd::*; + } else if #[cfg(target_os = "dragonfly")] { + mod dragonfly; + pub use self::dragonfly::*; + } else { + // ... + } +} diff --git a/libc/src/unix/bsd/mod.rs b/libc/src/unix/bsd/mod.rs new file mode 100644 index 000000000..03c987dd3 --- /dev/null +++ b/libc/src/unix/bsd/mod.rs @@ -0,0 +1,675 @@ +pub type wchar_t = i32; +pub type off_t = i64; +pub type useconds_t = u32; +pub type blkcnt_t = i64; +pub type socklen_t = u32; +pub type sa_family_t = u8; +pub type pthread_t = ::uintptr_t; +pub type nfds_t = ::c_uint; + +s! { + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_change: ::time_t, + pub pw_class: *mut ::c_char, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + pub pw_expire: ::time_t, + + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "netbsd", + target_os = "openbsd")))] + pub pw_fields: ::c_int, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut ::c_char, + pub ifa_flags: ::c_uint, + pub ifa_addr: *mut ::sockaddr, + pub ifa_netmask: *mut ::sockaddr, + pub ifa_dstaddr: *mut ::sockaddr, + pub ifa_data: *mut ::c_void, + #[cfg(target_os = "netbsd")] + pub ifa_addrflags: ::c_uint + } + + pub struct fd_set { + #[cfg(all(target_pointer_width = "64", + any(target_os = "freebsd", target_os = "dragonfly")))] + fds_bits: [i64; FD_SETSIZE / 64], + #[cfg(not(all(target_pointer_width = "64", + any(target_os = "freebsd", target_os = "dragonfly"))))] + fds_bits: [i32; FD_SETSIZE / 32], + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *mut ::c_char, + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::socklen_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct fsid_t { + __fsid_val: [::int32_t; 2], + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } +} + +s_no_extra_traits!{ + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [c_char; 104] + } + + pub struct utsname { + #[cfg(not(target_os = "dragonfly"))] + pub sysname: [::c_char; 256], + #[cfg(target_os = "dragonfly")] + pub sysname: [::c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub nodename: [::c_char; 256], + #[cfg(target_os = "dragonfly")] + pub nodename: [::c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub release: [::c_char; 256], + #[cfg(target_os = "dragonfly")] + pub release: [::c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub version: [::c_char; 256], + #[cfg(target_os = "dragonfly")] + pub version: [::c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + pub machine: [::c_char; 256], + #[cfg(target_os = "dragonfly")] + pub machine: [::c_char; 32], + } + +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_len == other.sun_len + && self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for sockaddr_un {} + + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_len", &self.sun_len) + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_len.hash(state); + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for utsname { + fn eq(&self, other: &utsname) -> bool { + self.sysname + .iter() + .zip(other.sysname.iter()) + .all(|(a,b)| a == b) + && self + .nodename + .iter() + .zip(other.nodename.iter()) + .all(|(a,b)| a == b) + && self + .release + .iter() + .zip(other.release.iter()) + .all(|(a,b)| a == b) + && self + .version + .iter() + .zip(other.version.iter()) + .all(|(a,b)| a == b) + && self + .machine + .iter() + .zip(other.machine.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for utsname {} + + impl ::fmt::Debug for utsname { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utsname") + // FIXME: .field("sysname", &self.sysname) + // FIXME: .field("nodename", &self.nodename) + // FIXME: .field("release", &self.release) + // FIXME: .field("version", &self.version) + // FIXME: .field("machine", &self.machine) + .finish() + } + } + + impl ::hash::Hash for utsname { + fn hash(&self, state: &mut H) { + self.sysname.hash(state); + self.nodename.hash(state); + self.release.hash(state); + self.version.hash(state); + self.machine.hash(state); + } + } + } +} + +pub const LC_ALL: ::c_int = 0; +pub const LC_COLLATE: ::c_int = 1; +pub const LC_CTYPE: ::c_int = 2; +pub const LC_MONETARY: ::c_int = 3; +pub const LC_NUMERIC: ::c_int = 4; +pub const LC_TIME: ::c_int = 5; +pub const LC_MESSAGES: ::c_int = 6; + +pub const FIOCLEX: ::c_ulong = 0x20006601; +pub const FIONBIO: ::c_ulong = 0x8004667e; + +pub const PATH_MAX: ::c_int = 1024; + +pub const SA_ONSTACK: ::c_int = 0x0001; +pub const SA_SIGINFO: ::c_int = 0x0040; +pub const SA_RESTART: ::c_int = 0x0002; +pub const SA_RESETHAND: ::c_int = 0x0004; +pub const SA_NOCLDSTOP: ::c_int = 0x0008; +pub const SA_NODEFER: ::c_int = 0x0010; +pub const SA_NOCLDWAIT: ::c_int = 0x0020; + +pub const SS_ONSTACK: ::c_int = 1; +pub const SS_DISABLE: ::c_int = 4; + +pub const SIGCHLD: ::c_int = 20; +pub const SIGBUS: ::c_int = 10; +pub const SIGUSR1: ::c_int = 30; +pub const SIGUSR2: ::c_int = 31; +pub const SIGCONT: ::c_int = 19; +pub const SIGSTOP: ::c_int = 17; +pub const SIGTSTP: ::c_int = 18; +pub const SIGURG: ::c_int = 16; +pub const SIGIO: ::c_int = 23; +pub const SIGSYS: ::c_int = 12; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGINFO: ::c_int = 29; + +pub const SIG_SETMASK: ::c_int = 3; +pub const SIG_BLOCK: ::c_int = 0x1; +pub const SIG_UNBLOCK: ::c_int = 0x2; + +pub const IP_TOS: ::c_int = 3; +pub const IP_MULTICAST_IF: ::c_int = 9; +pub const IP_MULTICAST_TTL: ::c_int = 10; +pub const IP_MULTICAST_LOOP: ::c_int = 11; + +pub const IPV6_UNICAST_HOPS: ::c_int = 4; +pub const IPV6_MULTICAST_IF: ::c_int = 9; +pub const IPV6_MULTICAST_HOPS: ::c_int = 10; +pub const IPV6_MULTICAST_LOOP: ::c_int = 11; +pub const IPV6_V6ONLY: ::c_int = 27; + +pub const IPTOS_ECN_NOTECT: u8 = 0x00; +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const ST_RDONLY: ::c_ulong = 1; + +pub const SCM_RIGHTS: ::c_int = 0x01; + +pub const NCCS: usize = 20; + +pub const O_ACCMODE: ::c_int = 0x3; +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 512; +pub const O_TRUNC: ::c_int = 1024; +pub const O_EXCL: ::c_int = 2048; +pub const O_ASYNC: ::c_int = 0x40; +pub const O_SYNC: ::c_int = 0x80; +pub const O_NONBLOCK: ::c_int = 0x4; +pub const O_NOFOLLOW: ::c_int = 0x100; +pub const O_SHLOCK: ::c_int = 0x10; +pub const O_EXLOCK: ::c_int = 0x20; +pub const O_FSYNC: ::c_int = O_SYNC; +pub const O_NDELAY: ::c_int = O_NONBLOCK; + +pub const F_GETOWN: ::c_int = 5; +pub const F_SETOWN: ::c_int = 6; + +pub const F_RDLCK: ::c_short = 1; +pub const F_UNLCK: ::c_short = 2; +pub const F_WRLCK: ::c_short = 3; + +pub const MNT_FORCE: ::c_int = 0x80000; + +pub const Q_SYNC: ::c_int = 0x600; +pub const Q_QUOTAON: ::c_int = 0x100; +pub const Q_QUOTAOFF: ::c_int = 0x200; + +pub const TCIOFF: ::c_int = 3; +pub const TCION: ::c_int = 4; +pub const TCOOFF: ::c_int = 1; +pub const TCOON: ::c_int = 2; +pub const TCIFLUSH: ::c_int = 1; +pub const TCOFLUSH: ::c_int = 2; +pub const TCIOFLUSH: ::c_int = 3; +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; +pub const VEOF: usize = 0; +pub const VEOL: usize = 1; +pub const VEOL2: usize = 2; +pub const VERASE: usize = 3; +pub const VWERASE: usize = 4; +pub const VKILL: usize = 5; +pub const VREPRINT: usize = 6; +pub const VINTR: usize = 8; +pub const VQUIT: usize = 9; +pub const VSUSP: usize = 10; +pub const VDSUSP: usize = 11; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VLNEXT: usize = 14; +pub const VDISCARD: usize = 15; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; +pub const VSTATUS: usize = 18; +pub const _POSIX_VDISABLE: ::cc_t = 0xff; +pub const IGNBRK: ::tcflag_t = 0x00000001; +pub const BRKINT: ::tcflag_t = 0x00000002; +pub const IGNPAR: ::tcflag_t = 0x00000004; +pub const PARMRK: ::tcflag_t = 0x00000008; +pub const INPCK: ::tcflag_t = 0x00000010; +pub const ISTRIP: ::tcflag_t = 0x00000020; +pub const INLCR: ::tcflag_t = 0x00000040; +pub const IGNCR: ::tcflag_t = 0x00000080; +pub const ICRNL: ::tcflag_t = 0x00000100; +pub const IXON: ::tcflag_t = 0x00000200; +pub const IXOFF: ::tcflag_t = 0x00000400; +pub const IXANY: ::tcflag_t = 0x00000800; +pub const IMAXBEL: ::tcflag_t = 0x00002000; +pub const OPOST: ::tcflag_t = 0x1; +pub const ONLCR: ::tcflag_t = 0x2; +pub const OXTABS: ::tcflag_t = 0x4; +pub const ONOEOT: ::tcflag_t = 0x8; +pub const CIGNORE: ::tcflag_t = 0x00000001; +pub const CSIZE: ::tcflag_t = 0x00000300; +pub const CS5: ::tcflag_t = 0x00000000; +pub const CS6: ::tcflag_t = 0x00000100; +pub const CS7: ::tcflag_t = 0x00000200; +pub const CS8: ::tcflag_t = 0x00000300; +pub const CSTOPB: ::tcflag_t = 0x00000400; +pub const CREAD: ::tcflag_t = 0x00000800; +pub const PARENB: ::tcflag_t = 0x00001000; +pub const PARODD: ::tcflag_t = 0x00002000; +pub const HUPCL: ::tcflag_t = 0x00004000; +pub const CLOCAL: ::tcflag_t = 0x00008000; +pub const ECHOKE: ::tcflag_t = 0x00000001; +pub const ECHOE: ::tcflag_t = 0x00000002; +pub const ECHOK: ::tcflag_t = 0x00000004; +pub const ECHO: ::tcflag_t = 0x00000008; +pub const ECHONL: ::tcflag_t = 0x00000010; +pub const ECHOPRT: ::tcflag_t = 0x00000020; +pub const ECHOCTL: ::tcflag_t = 0x00000040; +pub const ISIG: ::tcflag_t = 0x00000080; +pub const ICANON: ::tcflag_t = 0x00000100; +pub const ALTWERASE: ::tcflag_t = 0x00000200; +pub const IEXTEN: ::tcflag_t = 0x00000400; +pub const EXTPROC: ::tcflag_t = 0x00000800; +pub const TOSTOP: ::tcflag_t = 0x00400000; +pub const FLUSHO: ::tcflag_t = 0x00800000; +pub const NOKERNINFO: ::tcflag_t = 0x02000000; +pub const PENDIN: ::tcflag_t = 0x20000000; +pub const NOFLSH: ::tcflag_t = 0x80000000; +pub const MDMBUF: ::tcflag_t = 0x00100000; + +pub const WNOHANG: ::c_int = 0x00000001; +pub const WUNTRACED: ::c_int = 0x00000002; + +pub const RTLD_LAZY: ::c_int = 0x1; +pub const RTLD_NOW: ::c_int = 0x2; +pub const RTLD_NEXT: *mut ::c_void = -1isize as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = -2isize as *mut ::c_void; +pub const RTLD_SELF: *mut ::c_void = -3isize as *mut ::c_void; + +pub const LOG_CRON: ::c_int = 9 << 3; +pub const LOG_AUTHPRIV: ::c_int = 10 << 3; +pub const LOG_FTP: ::c_int = 11 << 3; +pub const LOG_PERROR: ::c_int = 0x20; + +pub const TCP_NODELAY: ::c_int = 1; +pub const TCP_MAXSEG: ::c_int = 2; + +pub const PIPE_BUF: usize = 512; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; +pub const POLLRDNORM: ::c_short = 0x040; +pub const POLLWRNORM: ::c_short = 0x004; +pub const POLLRDBAND: ::c_short = 0x080; +pub const POLLWRBAND: ::c_short = 0x100; + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const ::msghdr) -> *mut ::cmsghdr { + if (*mhdr).msg_controllen as usize >= ::mem::size_of::<::cmsghdr>() { + (*mhdr).msg_control as *mut ::cmsghdr + } else { + 0 as *mut ::cmsghdr + } + } + + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0o177 + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0o177) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + status >> 8 + } + + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0o200) != 0 + } + + pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + (cmd << 8) | (type_ & 0x00ff) + } +} + +extern { + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn getifaddrs(ifap: *mut *mut ::ifaddrs) -> ::c_int; + pub fn freeifaddrs(ifa: *mut ::ifaddrs); + pub fn setgroups(ngroups: ::c_int, + ptr: *const ::gid_t) -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn kqueue() -> ::c_int; + pub fn unmount(target: *const ::c_char, arg: ::c_int) -> ::c_int; + pub fn syscall(num: ::c_int, ...) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwent50")] + pub fn getpwent() -> *mut passwd; + pub fn setpwent(); + pub fn endpwent(); + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut ::group; + + pub fn getprogname() -> *const ::c_char; + pub fn setprogname(name: *const ::c_char); + pub fn getloadavg(loadavg: *mut ::c_double, nelem: ::c_int) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn getpeereid(socket: ::c_int, + euid: *mut ::uid_t, + egid: *mut ::gid_t) -> ::c_int; + + #[cfg_attr(target_os = "macos", link_name = "glob$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__glob30")] + #[cfg_attr(target_os = "freebsd", link_name = "glob@FBSD_1.0")] + pub fn glob(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__globfree30")] + #[cfg_attr(target_os = "freebsd", link_name = "globfree@FBSD_1.0")] + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "seekdir$INODE64")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "seekdir$INODE64$UNIX2003")] + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "telldir$INODE64")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "telldir$INODE64$UNIX2003")] + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "msync$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__msync13")] + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "recvfrom$UNIX2003")] + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__futimes50")] + pub fn futimes(fd: ::c_int, times: *const ::timeval) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "bind$UNIX2003")] + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "writev$UNIX2003")] + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "readv$UNIX2003")] + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sendmsg$UNIX2003")] + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "recvmsg$UNIX2003")] + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + + pub fn sync(); + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cancel$UNIX2003")] + pub fn pthread_cancel(thread: ::pthread_t) -> ::c_int; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn faccessat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::c_int, flags: ::c_int) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn acct(filename: *const ::c_char) -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + mod apple; + pub use self::apple::*; + } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd"))] { + mod netbsdlike; + pub use self::netbsdlike::*; + } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { + mod freebsdlike; + pub use self::freebsdlike::*; + } else { + // Unknown target_os + } +} diff --git a/libc/src/unix/bsd/netbsdlike/mod.rs b/libc/src/unix/bsd/netbsdlike/mod.rs new file mode 100644 index 000000000..29b4dd764 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/mod.rs @@ -0,0 +1,685 @@ +pub type time_t = i64; +pub type mode_t = u32; +pub type nlink_t = ::uint32_t; +pub type ino_t = ::uint64_t; +pub type pthread_key_t = ::c_int; +pub type rlim_t = u64; +pub type speed_t = ::c_uint; +pub type tcflag_t = ::c_uint; +pub type nl_item = c_long; +pub type clockid_t = ::c_int; +pub type id_t = ::uint32_t; +pub type sem_t = *mut sem; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum sem {} +impl ::Copy for sem {} +impl ::Clone for sem { + fn clone(&self) -> sem { *self } +} + +s! { + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_int, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct in6_pktinfo { + pub ipi6_addr: ::in6_addr, + pub ipi6_ifindex: ::c_uint, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::c_int, + pub c_ospeed: ::c_int, + } + + pub struct flock { + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + pub l_type: ::c_short, + pub l_whence: ::c_short, + } +} + +pub const D_T_FMT: ::nl_item = 0; +pub const D_FMT: ::nl_item = 1; +pub const T_FMT: ::nl_item = 2; +pub const T_FMT_AMPM: ::nl_item = 3; +pub const AM_STR: ::nl_item = 4; +pub const PM_STR: ::nl_item = 5; + +pub const DAY_1: ::nl_item = 6; +pub const DAY_2: ::nl_item = 7; +pub const DAY_3: ::nl_item = 8; +pub const DAY_4: ::nl_item = 9; +pub const DAY_5: ::nl_item = 10; +pub const DAY_6: ::nl_item = 11; +pub const DAY_7: ::nl_item = 12; + +pub const ABDAY_1: ::nl_item = 13; +pub const ABDAY_2: ::nl_item = 14; +pub const ABDAY_3: ::nl_item = 15; +pub const ABDAY_4: ::nl_item = 16; +pub const ABDAY_5: ::nl_item = 17; +pub const ABDAY_6: ::nl_item = 18; +pub const ABDAY_7: ::nl_item = 19; + +pub const MON_1: ::nl_item = 20; +pub const MON_2: ::nl_item = 21; +pub const MON_3: ::nl_item = 22; +pub const MON_4: ::nl_item = 23; +pub const MON_5: ::nl_item = 24; +pub const MON_6: ::nl_item = 25; +pub const MON_7: ::nl_item = 26; +pub const MON_8: ::nl_item = 27; +pub const MON_9: ::nl_item = 28; +pub const MON_10: ::nl_item = 29; +pub const MON_11: ::nl_item = 30; +pub const MON_12: ::nl_item = 31; + +pub const ABMON_1: ::nl_item = 32; +pub const ABMON_2: ::nl_item = 33; +pub const ABMON_3: ::nl_item = 34; +pub const ABMON_4: ::nl_item = 35; +pub const ABMON_5: ::nl_item = 36; +pub const ABMON_6: ::nl_item = 37; +pub const ABMON_7: ::nl_item = 38; +pub const ABMON_8: ::nl_item = 39; +pub const ABMON_9: ::nl_item = 40; +pub const ABMON_10: ::nl_item = 41; +pub const ABMON_11: ::nl_item = 42; +pub const ABMON_12: ::nl_item = 43; + +pub const RADIXCHAR: ::nl_item = 44; +pub const THOUSEP: ::nl_item = 45; +pub const YESSTR: ::nl_item = 46; +pub const YESEXPR: ::nl_item = 47; +pub const NOSTR: ::nl_item = 48; +pub const NOEXPR: ::nl_item = 49; +pub const CRNCYSTR: ::nl_item = 50; + +pub const CODESET: ::nl_item = 51; + +pub const EXIT_FAILURE : ::c_int = 1; +pub const EXIT_SUCCESS : ::c_int = 0; +pub const RAND_MAX : ::c_int = 2147483647; +pub const EOF : ::c_int = -1; +pub const SEEK_SET : ::c_int = 0; +pub const SEEK_CUR : ::c_int = 1; +pub const SEEK_END : ::c_int = 2; +pub const _IOFBF : ::c_int = 0; +pub const _IONBF : ::c_int = 2; +pub const _IOLBF : ::c_int = 1; +pub const BUFSIZ : ::c_uint = 1024; +pub const FOPEN_MAX : ::c_uint = 20; +pub const FILENAME_MAX : ::c_uint = 1024; +pub const L_tmpnam : ::c_uint = 1024; +pub const O_NOCTTY : ::c_int = 32768; +pub const S_IFIFO : mode_t = 4096; +pub const S_IFCHR : mode_t = 8192; +pub const S_IFBLK : mode_t = 24576; +pub const S_IFDIR : mode_t = 16384; +pub const S_IFREG : mode_t = 32768; +pub const S_IFLNK : mode_t = 40960; +pub const S_IFSOCK : mode_t = 49152; +pub const S_IFMT : mode_t = 61440; +pub const S_IEXEC : mode_t = 64; +pub const S_IWRITE : mode_t = 128; +pub const S_IREAD : mode_t = 256; +pub const S_IRWXU : mode_t = 448; +pub const S_IXUSR : mode_t = 64; +pub const S_IWUSR : mode_t = 128; +pub const S_IRUSR : mode_t = 256; +pub const S_IRWXG : mode_t = 56; +pub const S_IXGRP : mode_t = 8; +pub const S_IWGRP : mode_t = 16; +pub const S_IRGRP : mode_t = 32; +pub const S_IRWXO : mode_t = 7; +pub const S_IXOTH : mode_t = 1; +pub const S_IWOTH : mode_t = 2; +pub const S_IROTH : mode_t = 4; +pub const F_OK : ::c_int = 0; +pub const R_OK : ::c_int = 4; +pub const W_OK : ::c_int = 2; +pub const X_OK : ::c_int = 1; +pub const STDIN_FILENO : ::c_int = 0; +pub const STDOUT_FILENO : ::c_int = 1; +pub const STDERR_FILENO : ::c_int = 2; +pub const F_LOCK : ::c_int = 1; +pub const F_TEST : ::c_int = 3; +pub const F_TLOCK : ::c_int = 2; +pub const F_ULOCK : ::c_int = 0; +pub const F_GETLK: ::c_int = 7; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; +pub const SIGHUP : ::c_int = 1; +pub const SIGINT : ::c_int = 2; +pub const SIGQUIT : ::c_int = 3; +pub const SIGILL : ::c_int = 4; +pub const SIGABRT : ::c_int = 6; +pub const SIGEMT: ::c_int = 7; +pub const SIGFPE : ::c_int = 8; +pub const SIGKILL : ::c_int = 9; +pub const SIGSEGV : ::c_int = 11; +pub const SIGPIPE : ::c_int = 13; +pub const SIGALRM : ::c_int = 14; +pub const SIGTERM : ::c_int = 15; + +pub const PROT_NONE : ::c_int = 0; +pub const PROT_READ : ::c_int = 1; +pub const PROT_WRITE : ::c_int = 2; +pub const PROT_EXEC : ::c_int = 4; + +pub const MAP_FILE : ::c_int = 0x0000; +pub const MAP_SHARED : ::c_int = 0x0001; +pub const MAP_PRIVATE : ::c_int = 0x0002; +pub const MAP_FIXED : ::c_int = 0x0010; +pub const MAP_ANON : ::c_int = 0x1000; + +pub const MAP_FAILED : *mut ::c_void = !0 as *mut ::c_void; + +pub const MCL_CURRENT : ::c_int = 0x0001; +pub const MCL_FUTURE : ::c_int = 0x0002; + +pub const MS_ASYNC : ::c_int = 0x0001; + +pub const EPERM : ::c_int = 1; +pub const ENOENT : ::c_int = 2; +pub const ESRCH : ::c_int = 3; +pub const EINTR : ::c_int = 4; +pub const EIO : ::c_int = 5; +pub const ENXIO : ::c_int = 6; +pub const E2BIG : ::c_int = 7; +pub const ENOEXEC : ::c_int = 8; +pub const EBADF : ::c_int = 9; +pub const ECHILD : ::c_int = 10; +pub const EDEADLK : ::c_int = 11; +pub const ENOMEM : ::c_int = 12; +pub const EACCES : ::c_int = 13; +pub const EFAULT : ::c_int = 14; +pub const ENOTBLK : ::c_int = 15; +pub const EBUSY : ::c_int = 16; +pub const EEXIST : ::c_int = 17; +pub const EXDEV : ::c_int = 18; +pub const ENODEV : ::c_int = 19; +pub const ENOTDIR : ::c_int = 20; +pub const EISDIR : ::c_int = 21; +pub const EINVAL : ::c_int = 22; +pub const ENFILE : ::c_int = 23; +pub const EMFILE : ::c_int = 24; +pub const ENOTTY : ::c_int = 25; +pub const ETXTBSY : ::c_int = 26; +pub const EFBIG : ::c_int = 27; +pub const ENOSPC : ::c_int = 28; +pub const ESPIPE : ::c_int = 29; +pub const EROFS : ::c_int = 30; +pub const EMLINK : ::c_int = 31; +pub const EPIPE : ::c_int = 32; +pub const EDOM : ::c_int = 33; +pub const ERANGE : ::c_int = 34; +pub const EAGAIN : ::c_int = 35; +pub const EWOULDBLOCK : ::c_int = 35; +pub const EINPROGRESS : ::c_int = 36; +pub const EALREADY : ::c_int = 37; +pub const ENOTSOCK : ::c_int = 38; +pub const EDESTADDRREQ : ::c_int = 39; +pub const EMSGSIZE : ::c_int = 40; +pub const EPROTOTYPE : ::c_int = 41; +pub const ENOPROTOOPT : ::c_int = 42; +pub const EPROTONOSUPPORT : ::c_int = 43; +pub const ESOCKTNOSUPPORT : ::c_int = 44; +pub const EOPNOTSUPP : ::c_int = 45; +pub const EPFNOSUPPORT : ::c_int = 46; +pub const EAFNOSUPPORT : ::c_int = 47; +pub const EADDRINUSE : ::c_int = 48; +pub const EADDRNOTAVAIL : ::c_int = 49; +pub const ENETDOWN : ::c_int = 50; +pub const ENETUNREACH : ::c_int = 51; +pub const ENETRESET : ::c_int = 52; +pub const ECONNABORTED : ::c_int = 53; +pub const ECONNRESET : ::c_int = 54; +pub const ENOBUFS : ::c_int = 55; +pub const EISCONN : ::c_int = 56; +pub const ENOTCONN : ::c_int = 57; +pub const ESHUTDOWN : ::c_int = 58; +pub const ETOOMANYREFS : ::c_int = 59; +pub const ETIMEDOUT : ::c_int = 60; +pub const ECONNREFUSED : ::c_int = 61; +pub const ELOOP : ::c_int = 62; +pub const ENAMETOOLONG : ::c_int = 63; +pub const EHOSTDOWN : ::c_int = 64; +pub const EHOSTUNREACH : ::c_int = 65; +pub const ENOTEMPTY : ::c_int = 66; +pub const EPROCLIM : ::c_int = 67; +pub const EUSERS : ::c_int = 68; +pub const EDQUOT : ::c_int = 69; +pub const ESTALE : ::c_int = 70; +pub const EREMOTE : ::c_int = 71; +pub const EBADRPC : ::c_int = 72; +pub const ERPCMISMATCH : ::c_int = 73; +pub const EPROGUNAVAIL : ::c_int = 74; +pub const EPROGMISMATCH : ::c_int = 75; +pub const EPROCUNAVAIL : ::c_int = 76; +pub const ENOLCK : ::c_int = 77; +pub const ENOSYS : ::c_int = 78; +pub const EFTYPE : ::c_int = 79; +pub const EAUTH : ::c_int = 80; +pub const ENEEDAUTH : ::c_int = 81; + +pub const F_DUPFD : ::c_int = 0; +pub const F_GETFD : ::c_int = 1; +pub const F_SETFD : ::c_int = 2; +pub const F_GETFL : ::c_int = 3; +pub const F_SETFL : ::c_int = 4; + +pub const SIGTRAP : ::c_int = 5; + +pub const GLOB_APPEND : ::c_int = 0x0001; +pub const GLOB_DOOFFS : ::c_int = 0x0002; +pub const GLOB_ERR : ::c_int = 0x0004; +pub const GLOB_MARK : ::c_int = 0x0008; +pub const GLOB_NOCHECK : ::c_int = 0x0010; +pub const GLOB_NOSORT : ::c_int = 0x0020; +pub const GLOB_NOESCAPE : ::c_int = 0x1000; + +pub const GLOB_NOSPACE : ::c_int = -1; +pub const GLOB_ABORTED : ::c_int = -2; +pub const GLOB_NOMATCH : ::c_int = -3; +pub const GLOB_NOSYS : ::c_int = -4; + +pub const POSIX_MADV_NORMAL : ::c_int = 0; +pub const POSIX_MADV_RANDOM : ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL : ::c_int = 2; +pub const POSIX_MADV_WILLNEED : ::c_int = 3; +pub const POSIX_MADV_DONTNEED : ::c_int = 4; + +pub const PTHREAD_CREATE_JOINABLE : ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED : ::c_int = 1; + +pub const PT_TRACE_ME: ::c_int = 0; +pub const PT_READ_I: ::c_int = 1; +pub const PT_READ_D: ::c_int = 2; +pub const PT_WRITE_I: ::c_int = 4; +pub const PT_WRITE_D: ::c_int = 5; +pub const PT_CONTINUE: ::c_int = 7; +pub const PT_KILL: ::c_int = 8; +pub const PT_ATTACH: ::c_int = 9; +pub const PT_DETACH: ::c_int = 10; +pub const PT_IO: ::c_int = 11; + +// http://man.openbsd.org/OpenBSD-current/man2/clock_getres.2 +// The man page says clock_gettime(3) can accept various values as clockid_t but +// http://fxr.watson.org/fxr/source/kern/kern_time.c?v=OPENBSD;im=excerpts#L161 +// the implementation rejects anything other than the below two +// +// http://netbsd.gw.com/cgi-bin/man-cgi?clock_gettime +// https://github.com/jsonn/src/blob/HEAD/sys/kern/subr_time.c#L222 +// Basically the same goes for NetBSD +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_MONOTONIC: ::clockid_t = 3; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_MEMLOCK: ::c_int = 6; +pub const RLIMIT_NPROC: ::c_int = 7; +pub const RLIMIT_NOFILE: ::c_int = 8; + +pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; +pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY; + +pub const RUSAGE_SELF: ::c_int = 0; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const MADV_NORMAL : ::c_int = 0; +pub const MADV_RANDOM : ::c_int = 1; +pub const MADV_SEQUENTIAL : ::c_int = 2; +pub const MADV_WILLNEED : ::c_int = 3; +pub const MADV_DONTNEED : ::c_int = 4; +pub const MADV_FREE : ::c_int = 6; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_UNIX: ::c_int = AF_LOCAL; +pub const AF_INET: ::c_int = 2; +pub const AF_IMPLINK: ::c_int = 3; +pub const AF_PUP: ::c_int = 4; +pub const AF_CHAOS: ::c_int = 5; +pub const AF_NS: ::c_int = 6; +pub const AF_ISO: ::c_int = 7; +pub const AF_OSI: ::c_int = AF_ISO; +pub const AF_DATAKIT: ::c_int = 9; +pub const AF_CCITT: ::c_int = 10; +pub const AF_SNA: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_DLI: ::c_int = 13; +pub const AF_LAT: ::c_int = 14; +pub const AF_HYLINK: ::c_int = 15; +pub const AF_APPLETALK: ::c_int = 16; +pub const AF_LINK: ::c_int = 18; +pub const pseudo_AF_XTP: ::c_int = 19; +pub const AF_COIP: ::c_int = 20; +pub const AF_CNT: ::c_int = 21; +pub const pseudo_AF_RTIP: ::c_int = 22; +pub const AF_IPX: ::c_int = 23; +pub const AF_INET6: ::c_int = 24; +pub const pseudo_AF_PIP: ::c_int = 25; +pub const AF_ISDN: ::c_int = 26; +pub const AF_E164: ::c_int = AF_ISDN; +pub const AF_NATM: ::c_int = 27; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_UNIX: ::c_int = PF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_IMPLINK: ::c_int = AF_IMPLINK; +pub const PF_PUP: ::c_int = AF_PUP; +pub const PF_CHAOS: ::c_int = AF_CHAOS; +pub const PF_NS: ::c_int = AF_NS; +pub const PF_ISO: ::c_int = AF_ISO; +pub const PF_OSI: ::c_int = AF_ISO; +pub const PF_DATAKIT: ::c_int = AF_DATAKIT; +pub const PF_CCITT: ::c_int = AF_CCITT; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_DLI: ::c_int = AF_DLI; +pub const PF_LAT: ::c_int = AF_LAT; +pub const PF_HYLINK: ::c_int = AF_HYLINK; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_LINK: ::c_int = AF_LINK; +pub const PF_XTP: ::c_int = pseudo_AF_XTP; +pub const PF_COIP: ::c_int = AF_COIP; +pub const PF_CNT: ::c_int = AF_CNT; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_RTIP: ::c_int = pseudo_AF_RTIP; +pub const PF_PIP: ::c_int = pseudo_AF_PIP; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_NATM: ::c_int = AF_NATM; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_RDM: ::c_int = 4; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const IP_TTL: ::c_int = 4; +pub const IP_HDRINCL: ::c_int = 2; +pub const IP_ADD_MEMBERSHIP: ::c_int = 12; +pub const IP_DROP_MEMBERSHIP: ::c_int = 13; +pub const IPV6_RECVPKTINFO: ::c_int = 36; +pub const IPV6_PKTINFO: ::c_int = 46; +pub const IPV6_RECVTCLASS: ::c_int = 57; +pub const IPV6_TCLASS: ::c_int = 61; + +pub const SOL_SOCKET: ::c_int = 0xffff; +pub const SO_DEBUG: ::c_int = 0x01; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; + +pub const SOMAXCONN: ::c_int = 128; + +pub const MSG_OOB: ::c_int = 0x1; +pub const MSG_PEEK: ::c_int = 0x2; +pub const MSG_DONTROUTE: ::c_int = 0x4; +pub const MSG_EOR: ::c_int = 0x8; +pub const MSG_TRUNC: ::c_int = 0x10; +pub const MSG_CTRUNC: ::c_int = 0x20; +pub const MSG_WAITALL: ::c_int = 0x40; +pub const MSG_DONTWAIT: ::c_int = 0x80; +pub const MSG_BCAST: ::c_int = 0x100; +pub const MSG_MCAST: ::c_int = 0x200; +pub const MSG_NOSIGNAL: ::c_int = 0x400; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x800; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const IPPROTO_RAW : ::c_int = 255; + +pub const _SC_ARG_MAX : ::c_int = 1; +pub const _SC_CHILD_MAX : ::c_int = 2; +pub const _SC_NGROUPS_MAX : ::c_int = 4; +pub const _SC_OPEN_MAX : ::c_int = 5; +pub const _SC_JOB_CONTROL : ::c_int = 6; +pub const _SC_SAVED_IDS : ::c_int = 7; +pub const _SC_VERSION : ::c_int = 8; +pub const _SC_BC_BASE_MAX : ::c_int = 9; +pub const _SC_BC_DIM_MAX : ::c_int = 10; +pub const _SC_BC_SCALE_MAX : ::c_int = 11; +pub const _SC_BC_STRING_MAX : ::c_int = 12; +pub const _SC_COLL_WEIGHTS_MAX : ::c_int = 13; +pub const _SC_EXPR_NEST_MAX : ::c_int = 14; +pub const _SC_LINE_MAX : ::c_int = 15; +pub const _SC_RE_DUP_MAX : ::c_int = 16; +pub const _SC_2_VERSION : ::c_int = 17; +pub const _SC_2_C_BIND : ::c_int = 18; +pub const _SC_2_C_DEV : ::c_int = 19; +pub const _SC_2_CHAR_TERM : ::c_int = 20; +pub const _SC_2_FORT_DEV : ::c_int = 21; +pub const _SC_2_FORT_RUN : ::c_int = 22; +pub const _SC_2_LOCALEDEF : ::c_int = 23; +pub const _SC_2_SW_DEV : ::c_int = 24; +pub const _SC_2_UPE : ::c_int = 25; +pub const _SC_STREAM_MAX : ::c_int = 26; +pub const _SC_TZNAME_MAX : ::c_int = 27; +pub const _SC_PAGESIZE : ::c_int = 28; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_FSYNC : ::c_int = 29; +pub const _SC_XOPEN_SHM : ::c_int = 30; + +pub const Q_GETQUOTA: ::c_int = 0x300; +pub const Q_SETQUOTA: ::c_int = 0x400; + +pub const RTLD_GLOBAL: ::c_int = 0x100; + +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const HW_NCPU: ::c_int = 3; + +pub const B0: speed_t = 0; +pub const B50: speed_t = 50; +pub const B75: speed_t = 75; +pub const B110: speed_t = 110; +pub const B134: speed_t = 134; +pub const B150: speed_t = 150; +pub const B200: speed_t = 200; +pub const B300: speed_t = 300; +pub const B600: speed_t = 600; +pub const B1200: speed_t = 1200; +pub const B1800: speed_t = 1800; +pub const B2400: speed_t = 2400; +pub const B4800: speed_t = 4800; +pub const B9600: speed_t = 9600; +pub const B19200: speed_t = 19200; +pub const B38400: speed_t = 38400; +pub const B7200: speed_t = 7200; +pub const B14400: speed_t = 14400; +pub const B28800: speed_t = 28800; +pub const B57600: speed_t = 57600; +pub const B76800: speed_t = 76800; +pub const B115200: speed_t = 115200; +pub const B230400: speed_t = 230400; +pub const EXTA: speed_t = 19200; +pub const EXTB: speed_t = 38400; + +pub const SEM_FAILED: *mut sem_t = 0 as *mut sem_t; + +pub const CRTSCTS: ::tcflag_t = 0x00010000; +pub const CRTS_IFLOW: ::tcflag_t = CRTSCTS; +pub const CCTS_OFLOW: ::tcflag_t = CRTSCTS; +pub const OCRNL: ::tcflag_t = 0x10; + +pub const TIOCEXCL: ::c_ulong = 0x2000740d; +pub const TIOCNXCL: ::c_ulong = 0x2000740e; +pub const TIOCFLUSH: ::c_ulong = 0x80047410; +pub const TIOCGETA: ::c_ulong = 0x402c7413; +pub const TIOCSETA: ::c_ulong = 0x802c7414; +pub const TIOCSETAW: ::c_ulong = 0x802c7415; +pub const TIOCSETAF: ::c_ulong = 0x802c7416; +pub const TIOCGETD: ::c_ulong = 0x4004741a; +pub const TIOCSETD: ::c_ulong = 0x8004741b; +pub const TIOCMGET: ::c_ulong = 0x4004746a; +pub const TIOCMBIC: ::c_ulong = 0x8004746b; +pub const TIOCMBIS: ::c_ulong = 0x8004746c; +pub const TIOCMSET: ::c_ulong = 0x8004746d; +pub const TIOCSTART: ::c_ulong = 0x2000746e; +pub const TIOCSTOP: ::c_ulong = 0x2000746f; +pub const TIOCSCTTY: ::c_ulong = 0x20007461; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const TIOCM_LE: ::c_int = 0o0001; +pub const TIOCM_DTR: ::c_int = 0o0002; +pub const TIOCM_RTS: ::c_int = 0o0004; +pub const TIOCM_ST: ::c_int = 0o0010; +pub const TIOCM_SR: ::c_int = 0o0020; +pub const TIOCM_CTS: ::c_int = 0o0040; +pub const TIOCM_CAR: ::c_int = 0o0100; +pub const TIOCM_RNG: ::c_int = 0o0200; +pub const TIOCM_DSR: ::c_int = 0o0400; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +// Flags for chflags(2) +pub const UF_SETTABLE: ::c_ulong = 0x0000ffff; +pub const UF_NODUMP: ::c_ulong = 0x00000001; +pub const UF_IMMUTABLE: ::c_ulong = 0x00000002; +pub const UF_APPEND: ::c_ulong = 0x00000004; +pub const UF_OPAQUE: ::c_ulong = 0x00000008; +pub const SF_SETTABLE: ::c_ulong = 0xffff0000; +pub const SF_ARCHIVED: ::c_ulong = 0x00010000; +pub const SF_IMMUTABLE: ::c_ulong = 0x00020000; +pub const SF_APPEND: ::c_ulong = 0x00040000; + +pub const TIMER_ABSTIME: ::c_int = 1; + +#[link(name = "util")] +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + pub fn mincore(addr: *mut ::c_void, len: ::size_t, + vec: *mut ::c_char) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_getres50")] + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_gettime50")] + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__clock_settime50")] + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + pub fn __errno() -> *mut ::c_int; + pub fn shm_open(name: *const ::c_char, oflag: ::c_int, mode: ::mode_t) + -> ::c_int; + pub fn memrchr(cx: *const ::c_void, + c: ::c_int, + n: ::size_t) -> *mut ::c_void; + pub fn mkostemp(template: *mut ::c_char, flags: ::c_int) -> ::c_int; + pub fn mkostemps(template: *mut ::c_char, + suffixlen: ::c_int, + flags: ::c_int) -> ::c_int; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::c_int; + pub fn forkpty(amaster: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::pid_t; + pub fn login_tty(fd: ::c_int) -> ::c_int; + pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; + + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; + + pub fn getgrouplist(name: *const ::c_char, + basegid: ::gid_t, + groups: *mut ::gid_t, + ngroups: *mut ::c_int) -> ::c_int; + pub fn initgroups(name: *const ::c_char, basegid: ::gid_t) -> ::c_int; + pub fn getdomainname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_os = "netbsd")] { + mod netbsd; + pub use self::netbsd::*; + } else if #[cfg(target_os = "openbsd")] { + mod openbsdlike; + pub use self::openbsdlike::*; + } else { + // Unknown target_os + } +} diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs b/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs new file mode 100644 index 000000000..58c4cf7c4 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/aarch64.rs @@ -0,0 +1,22 @@ +use PT_FIRSTMACH; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = u8; +pub type __cpu_simple_lock_nv_t = ::c_uchar; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_int>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 4 - 1; + } +} + +pub const PT_GETREGS: ::c_int = PT_FIRSTMACH + 0; +pub const PT_SETREGS: ::c_int = PT_FIRSTMACH + 1; +pub const PT_GETFPREGS: ::c_int = PT_FIRSTMACH + 2; +pub const PT_SETFPREGS: ::c_int = PT_FIRSTMACH + 3; diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs b/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs new file mode 100644 index 000000000..4bf3ccd02 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/arm.rs @@ -0,0 +1,22 @@ +use PT_FIRSTMACH; + +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_char = u8; +pub type __cpu_simple_lock_nv_t = ::c_int; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_longlong>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const PT_GETREGS: ::c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: ::c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: ::c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: ::c_int = PT_FIRSTMACH + 4; diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs b/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs new file mode 100644 index 000000000..ad53c19b3 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/mod.rs @@ -0,0 +1,1630 @@ +pub type clock_t = ::c_uint; +pub type suseconds_t = ::c_int; +pub type dev_t = u64; +pub type blksize_t = ::int32_t; +pub type fsblkcnt_t = ::uint64_t; +pub type fsfilcnt_t = ::uint64_t; +pub type idtype_t = ::c_int; +pub type mqd_t = ::c_int; +type __pthread_spin_t = __cpu_simple_lock_nv_t; +pub type vm_size_t = ::uintptr_t; + +s! { + pub struct aiocb { + pub aio_offset: ::off_t, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_sigevent: ::sigevent, + _state: ::c_int, + _errno: ::c_int, + _retval: ::ssize_t + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_matchc: ::size_t, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + pub gl_pathv: *mut *mut ::c_char, + + __unused3: *mut ::c_void, + + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + __unused8: *mut ::c_void, + } + + pub struct mq_attr { + pub mq_flags: ::c_long, + pub mq_maxmsg: ::c_long, + pub mq_msgsize: ::c_long, + pub mq_curmsgs: ::c_long, + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + __unused1: *mut ::c_void, //actually a function pointer + pub sigev_notify_attributes: *mut ::c_void + } + + pub struct sigset_t { + __bits: [u32; 4], + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_mode: ::mode_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atimensec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtimensec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctimensec: ::c_long, + pub st_birthtime: ::time_t, + pub st_birthtimensec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::uint32_t, + pub st_gen: ::uint32_t, + pub st_spare: [::uint32_t; 2], + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut ::addrinfo, + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + __pad1: ::c_int, + pub si_addr: *mut ::c_void, + __pad2: [u64; 13], + } + + pub struct pthread_attr_t { + pta_magic: ::c_uint, + pta_flags: ::c_int, + pta_private: *mut ::c_void, + } + + pub struct pthread_mutex_t { + ptm_magic: ::c_uint, + ptm_errorcheck: __pthread_spin_t, + #[cfg(any(target_arch = "sparc", target_arch = "sparc64", + target_arch = "x86", target_arch = "x86_64"))] + ptm_pad1: [u8; 3], + // actually a union with a non-unused, 0-initialized field + ptm_unused: __pthread_spin_t, + #[cfg(any(target_arch = "sparc", target_arch = "sparc64", + target_arch = "x86", target_arch = "x86_64"))] + ptm_pad2: [u8; 3], + ptm_owner: ::pthread_t, + ptm_waiters: *mut u8, + ptm_recursed: ::c_uint, + ptm_spare2: *mut ::c_void, + } + + pub struct pthread_mutexattr_t { + ptma_magic: ::c_uint, + ptma_private: *mut ::c_void, + } + + pub struct pthread_rwlockattr_t { + ptra_magic: ::c_uint, + ptra_private: *mut ::c_void, + } + + pub struct pthread_cond_t { + ptc_magic: ::c_uint, + ptc_lock: __pthread_spin_t, + ptc_waiters_first: *mut u8, + ptc_waiters_last: *mut u8, + ptc_mutex: *mut ::pthread_mutex_t, + ptc_private: *mut ::c_void, + } + + pub struct pthread_condattr_t { + ptca_magic: ::c_uint, + ptca_private: *mut ::c_void, + } + + pub struct pthread_rwlock_t { + ptr_magic: ::c_uint, + ptr_interlock: __pthread_spin_t, + ptr_rblocked_first: *mut u8, + ptr_rblocked_last: *mut u8, + ptr_wblocked_first: *mut u8, + ptr_wblocked_last: *mut u8, + ptr_nreaders: ::c_uint, + ptr_owner: ::pthread_t, + ptr_private: *mut ::c_void, + } + + pub struct kevent { + pub ident: ::uintptr_t, + pub filter: ::uint32_t, + pub flags: ::uint32_t, + pub fflags: ::uint32_t, + pub data: ::int64_t, + pub udata: ::intptr_t, + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint32_t, + pub dqb_bsoftlimit: ::uint32_t, + pub dqb_curblocks: ::uint32_t, + pub dqb_ihardlimit: ::uint32_t, + pub dqb_isoftlimit: ::uint32_t, + pub dqb_curinodes: ::uint32_t, + pub dqb_btime: ::int32_t, + pub dqb_itime: ::int32_t, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *const ::c_void, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct if_data { + pub ifi_type: ::c_uchar, + pub ifi_addrlen: ::c_uchar, + pub ifi_hdrlen: ::c_uchar, + pub ifi_link_state: ::c_int, + pub ifi_mtu: u64, + pub ifi_metric: u64, + pub ifi_baudrate: u64, + pub ifi_ipackets: u64, + pub ifi_ierrors: u64, + pub ifi_opackets: u64, + pub ifi_oerrors: u64, + pub ifi_collisions: u64, + pub ifi_ibytes: u64, + pub ifi_obytes: u64, + pub ifi_imcasts: u64, + pub ifi_omcasts: u64, + pub ifi_iqdrops: u64, + pub ifi_noproto: u64, + pub ifi_lastchange: ::timespec, + } + + pub struct if_msghdr { + pub ifm_msglen: ::c_ushort, + pub ifm_version: ::c_uchar, + pub ifm_type: ::c_uchar, + pub ifm_addrs: ::c_int, + pub ifm_flags: ::c_int, + pub ifm_index: ::c_ushort, + pub ifm_data: if_data, + } + + pub struct sockcred { + pub sc_pid: ::pid_t, + pub sc_uid: ::uid_t, + pub sc_euid: ::uid_t, + pub sc_gid: ::gid_t, + pub sc_egid: ::gid_t, + pub sc_ngroups: ::c_int, + pub sc_groups: [::gid_t; 1], + } + + pub struct sockaddr_dl { + pub sdl_len: ::c_uchar, + pub sdl_family: ::c_uchar, + pub sdl_index: ::c_ushort, + pub sdl_type: ::uint8_t, + pub sdl_nlen: ::uint8_t, + pub sdl_alen: ::uint8_t, + pub sdl_slen: ::uint8_t, + pub sdl_data: [::c_char; 12], + } + + pub struct mmsghdr { + pub msg_hdr: ::msghdr, + pub msg_len: ::c_uint, + } +} + +s_no_extra_traits! { + pub struct in_pktinfo { + pub ipi_addr: ::in_addr, + pub ipi_ifindex: ::c_uint, + } + + #[repr(packed)] + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + #[repr(packed)] + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::int8_t; 8], + } + + pub struct dirent { + pub d_fileno: ::ino_t, + pub d_reclen: u16, + pub d_namlen: u16, + pub d_type: u8, + pub d_name: [::c_char; 512], + } + + pub struct statvfs { + pub f_flag: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_iosize: ::c_ulong, + + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_bresvd: ::fsblkcnt_t, + + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fresvd: ::fsfilcnt_t, + + pub f_syncreads: ::uint64_t, + pub f_syncwrites: ::uint64_t, + + pub f_asyncreads: ::uint64_t, + pub f_asyncwrites: ::uint64_t, + + pub f_fsidx: ::fsid_t, + pub f_fsid: ::c_ulong, + pub f_namemax: ::c_ulong, + pub f_owner: ::uid_t, + + pub f_spare: [::uint32_t; 4], + + pub f_fstypename: [::c_char; 32], + pub f_mntonname: [::c_char; 1024], + pub f_mntfromname: [::c_char; 1024], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: ::sa_family_t, + __ss_pad1: [u8; 6], + __ss_pad2: i64, + __ss_pad3: [u8; 112], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for in_pktinfo { + fn eq(&self, other: &in_pktinfo) -> bool { + self.ipi_addr == other.ipi_addr + && self.ipi_ifindex == other.ipi_ifindex + } + } + impl Eq for in_pktinfo {} + impl ::fmt::Debug for in_pktinfo { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("in_pktinfo") + .field("ipi_addr", &self.ipi_addr) + .field("ipi_ifindex", &self.ipi_ifindex) + .finish() + } + } + impl ::hash::Hash for in_pktinfo { + fn hash(&self, state: &mut H) { + self.ipi_addr.hash(state); + self.ipi_ifindex.hash(state); + } + } + + impl PartialEq for arphdr { + fn eq(&self, other: &arphdr) -> bool { + self.ar_hrd == other.ar_hrd + && self.ar_pro == other.ar_pro + && self.ar_hln == other.ar_hln + && self.ar_pln == other.ar_pln + && self.ar_op == other.ar_op + } + } + impl Eq for arphdr {} + impl ::fmt::Debug for arphdr { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let ar_hrd = self.ar_hrd; + let ar_pro = self.ar_pro; + let ar_op = self.ar_op; + f.debug_struct("arphdr") + .field("ar_hrd", &ar_hrd) + .field("ar_pro", &ar_pro) + .field("ar_hln", &self.ar_hln) + .field("ar_pln", &self.ar_pln) + .field("ar_op", &ar_op) + .finish() + } + } + impl ::hash::Hash for arphdr { + fn hash(&self, state: &mut H) { + let ar_hrd = self.ar_hrd; + let ar_pro = self.ar_pro; + let ar_op = self.ar_op; + ar_hrd.hash(state); + ar_pro.hash(state); + self.ar_hln.hash(state); + self.ar_pln.hash(state); + ar_op.hash(state); + } + } + + impl PartialEq for in_addr { + fn eq(&self, other: &in_addr) -> bool { + self.s_addr == other.s_addr + } + } + impl Eq for in_addr {} + impl ::fmt::Debug for in_addr { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let s_addr = self.s_addr; + f.debug_struct("in_addr") + .field("s_addr", &s_addr) + .finish() + } + } + impl ::hash::Hash for in_addr { + fn hash(&self, state: &mut H) { + let s_addr = self.s_addr; + s_addr.hash(state); + } + } + + impl PartialEq for ip_mreq { + fn eq(&self, other: &ip_mreq) -> bool { + self.imr_multiaddr == other.imr_multiaddr + && self.imr_interface == other.imr_interface + } + } + impl Eq for ip_mreq {} + impl ::fmt::Debug for ip_mreq { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ip_mreq") + .field("imr_multiaddr", &self.imr_multiaddr) + .field("imr_interface", &self.imr_interface) + .finish() + } + } + impl ::hash::Hash for ip_mreq { + fn hash(&self, state: &mut H) { + self.imr_multiaddr.hash(state); + self.imr_interface.hash(state); + } + } + + impl PartialEq for sockaddr_in { + fn eq(&self, other: &sockaddr_in) -> bool { + self.sin_len == other.sin_len + && self.sin_family == other.sin_family + && self.sin_port == other.sin_port + && self.sin_addr == other.sin_addr + && self.sin_zero == other.sin_zero + } + } + impl Eq for sockaddr_in {} + impl ::fmt::Debug for sockaddr_in { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_in") + .field("sin_len", &self.sin_len) + .field("sin_family", &self.sin_family) + .field("sin_port", &self.sin_port) + .field("sin_addr", &self.sin_addr) + .field("sin_zero", &self.sin_zero) + .finish() + } + } + impl ::hash::Hash for sockaddr_in { + fn hash(&self, state: &mut H) { + self.sin_len.hash(state); + self.sin_family.hash(state); + self.sin_port.hash(state); + self.sin_addr.hash(state); + self.sin_zero.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_fileno == other.d_fileno + && self.d_reclen == other.d_reclen + && self.d_namlen == other.d_namlen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_fileno", &self.d_fileno) + .field("d_reclen", &self.d_reclen) + .field("d_namlen", &self.d_namlen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_fileno.hash(state); + self.d_reclen.hash(state); + self.d_namlen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for statvfs { + fn eq(&self, other: &statvfs) -> bool { + self.f_flag == other.f_flag + && self.f_bsize == other.f_bsize + && self.f_frsize == other.f_frsize + && self.f_iosize == other.f_iosize + && self.f_blocks == other.f_blocks + && self.f_bfree == other.f_bfree + && self.f_bavail == other.f_bavail + && self.f_bresvd == other.f_bresvd + && self.f_files == other.f_files + && self.f_ffree == other.f_ffree + && self.f_favail == other.f_favail + && self.f_fresvd == other.f_fresvd + && self.f_syncreads == other.f_syncreads + && self.f_syncwrites == other.f_syncwrites + && self.f_asyncreads == other.f_asyncreads + && self.f_asyncwrites == other.f_asyncwrites + && self.f_fsidx == other.f_fsidx + && self.f_fsid == other.f_fsid + && self.f_namemax == other.f_namemax + && self.f_owner == other.f_owner + && self.f_spare == other.f_spare + && self.f_fstypename == other.f_fstypename + && self + .f_mntonname + .iter() + .zip(other.f_mntonname.iter()) + .all(|(a,b)| a == b) + && self + .f_mntfromname + .iter() + .zip(other.f_mntfromname.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for statvfs {} + impl ::fmt::Debug for statvfs { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("statvfs") + .field("f_flag", &self.f_flag) + .field("f_bsize", &self.f_bsize) + .field("f_frsize", &self.f_frsize) + .field("f_iosize", &self.f_iosize) + .field("f_blocks", &self.f_blocks) + .field("f_bfree", &self.f_bfree) + .field("f_bavail", &self.f_bavail) + .field("f_bresvd", &self.f_bresvd) + .field("f_files", &self.f_files) + .field("f_ffree", &self.f_ffree) + .field("f_favail", &self.f_favail) + .field("f_fresvd", &self.f_fresvd) + .field("f_syncreads", &self.f_syncreads) + .field("f_syncwrites", &self.f_syncwrites) + .field("f_asyncreads", &self.f_asyncreads) + .field("f_asyncwrites", &self.f_asyncwrites) + .field("f_fsidx", &self.f_fsidx) + .field("f_fsid", &self.f_fsid) + .field("f_namemax", &self.f_namemax) + .field("f_owner", &self.f_owner) + .field("f_spare", &self.f_spare) + .field("f_fstypename", &self.f_fstypename) + // FIXME: .field("f_mntonname", &self.f_mntonname) + // FIXME: .field("f_mntfromname", &self.f_mntfromname) + .finish() + } + } + impl ::hash::Hash for statvfs { + fn hash(&self, state: &mut H) { + self.f_flag.hash(state); + self.f_bsize.hash(state); + self.f_frsize.hash(state); + self.f_iosize.hash(state); + self.f_blocks.hash(state); + self.f_bfree.hash(state); + self.f_bavail.hash(state); + self.f_bresvd.hash(state); + self.f_files.hash(state); + self.f_ffree.hash(state); + self.f_favail.hash(state); + self.f_fresvd.hash(state); + self.f_syncreads.hash(state); + self.f_syncwrites.hash(state); + self.f_asyncreads.hash(state); + self.f_asyncwrites.hash(state); + self.f_fsidx.hash(state); + self.f_fsid.hash(state); + self.f_namemax.hash(state); + self.f_owner.hash(state); + self.f_spare.hash(state); + self.f_fstypename.hash(state); + self.f_mntonname.hash(state); + self.f_mntfromname.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_len == other.ss_len + && self.ss_family == other.ss_family + && self.__ss_pad1 == other.__ss_pad1 + && self.__ss_pad2 == other.__ss_pad2 + && self + .__ss_pad3 + .iter() + .zip(other.__ss_pad3.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_len", &self.ss_len) + .field("ss_family", &self.ss_family) + .field("__ss_pad1", &self.__ss_pad1) + .field("__ss_pad2", &self.__ss_pad2) + // FIXME: .field("__ss_pad3", &self.__ss_pad3) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_len.hash(state); + self.ss_family.hash(state); + self.__ss_pad1.hash(state); + self.__ss_pad2.hash(state); + self.__ss_pad3.hash(state); + } + } + } +} + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_EACCESS: ::c_int = 0x100; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x400; +pub const AT_REMOVEDIR: ::c_int = 0x800; + +pub const EXTATTR_NAMESPACE_USER: ::c_int = 1; +pub const EXTATTR_NAMESPACE_SYSTEM: ::c_int = 2; + +pub const LC_COLLATE_MASK: ::c_int = (1 << ::LC_COLLATE); +pub const LC_CTYPE_MASK: ::c_int = (1 << ::LC_CTYPE); +pub const LC_MONETARY_MASK: ::c_int = (1 << ::LC_MONETARY); +pub const LC_NUMERIC_MASK: ::c_int = (1 << ::LC_NUMERIC); +pub const LC_TIME_MASK: ::c_int = (1 << ::LC_TIME); +pub const LC_MESSAGES_MASK: ::c_int = (1 << ::LC_MESSAGES); +pub const LC_ALL_MASK: ::c_int = !0; + +pub const ERA: ::nl_item = 52; +pub const ERA_D_FMT: ::nl_item = 53; +pub const ERA_D_T_FMT: ::nl_item = 54; +pub const ERA_T_FMT: ::nl_item = 55; +pub const ALT_DIGITS: ::nl_item = 56; + +pub const O_CLOEXEC: ::c_int = 0x400000; +pub const O_ALT_IO: ::c_int = 0x40000; +pub const O_NOSIGPIPE: ::c_int = 0x1000000; +pub const O_SEARCH: ::c_int = 0x800000; +pub const O_DIRECTORY: ::c_int = 0x200000; +pub const O_DIRECT : ::c_int = 0x00080000; +pub const O_RSYNC : ::c_int = 0x00020000; + +pub const MS_SYNC : ::c_int = 0x4; +pub const MS_INVALIDATE : ::c_int = 0x2; + +pub const RLIM_NLIMITS: ::c_int = 12; + +pub const EIDRM: ::c_int = 82; +pub const ENOMSG: ::c_int = 83; +pub const EOVERFLOW: ::c_int = 84; +pub const EILSEQ: ::c_int = 85; +pub const ENOTSUP: ::c_int = 86; +pub const ECANCELED: ::c_int = 87; +pub const EBADMSG: ::c_int = 88; +pub const ENODATA: ::c_int = 89; +pub const ENOSR: ::c_int = 90; +pub const ENOSTR: ::c_int = 91; +pub const ETIME: ::c_int = 92; +pub const ENOATTR: ::c_int = 93; +pub const EMULTIHOP: ::c_int = 94; +pub const ENOLINK: ::c_int = 95; +pub const EPROTO: ::c_int = 96; +pub const ELAST: ::c_int = 96; + +pub const F_DUPFD_CLOEXEC : ::c_int = 12; +pub const F_CLOSEM: ::c_int = 10; +pub const F_GETNOSIGPIPE: ::c_int = 13; +pub const F_SETNOSIGPIPE: ::c_int = 14; +pub const F_MAXFD: ::c_int = 11; + +pub const IP_RECVDSTADDR: ::c_int = 7; +pub const IP_SENDSRCADDR: ::c_int = IP_RECVDSTADDR; +pub const IP_RECVIF: ::c_int = 20; +pub const IP_PKTINFO: ::c_int = 25; +pub const IP_RECVPKTINFO: ::c_int = 26; +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; + +pub const TCP_KEEPIDLE: ::c_int = 3; +pub const TCP_KEEPINTVL: ::c_int = 5; +pub const TCP_KEEPCNT: ::c_int = 6; +pub const TCP_KEEPINIT: ::c_int = 7; +pub const TCP_INFO: ::c_int = 9; +pub const TCP_MD5SIG: ::c_int = 0x10; +pub const TCP_CONGCTL: ::c_int = 0x20; + +pub const SOCK_CONN_DGRAM: ::c_int = 6; +pub const SOCK_DCCP: ::c_int = SOCK_CONN_DGRAM; +pub const SOCK_NOSIGPIPE: ::c_int = 0x40000000; +pub const SOCK_FLAGS_MASK: ::c_int = 0xf0000000; + +pub const SO_SNDTIMEO: ::c_int = 0x100b; +pub const SO_RCVTIMEO: ::c_int = 0x100c; +pub const SO_ACCEPTFILTER: ::c_int = 0x1000; +pub const SO_TIMESTAMP: ::c_int = 0x2000; +pub const SO_OVERFLOWED: ::c_int = 0x1009; +pub const SO_NOHEADER: ::c_int = 0x100a; + +// https://github.com/NetBSD/src/blob/trunk/sys/net/if.h#L373 +pub const IFF_UP: ::c_int = 0x0001; // interface is up +pub const IFF_BROADCAST: ::c_int = 0x0002; // broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x0004; // turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x0008; // is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x0010; // interface is point-to-point link +pub const IFF_NOTRAILERS: ::c_int = 0x0020; // avoid use of trailers +pub const IFF_RUNNING: ::c_int = 0x0040; // resources allocated +pub const IFF_NOARP: ::c_int = 0x0080; // no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x0100; // receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x0200; // receive all multicast packets +pub const IFF_OACTIVE: ::c_int = 0x0400; // transmission in progress +pub const IFF_SIMPLEX: ::c_int = 0x0800; // can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000; // per link layer defined bit +pub const IFF_MULTICAST: ::c_int = 0x8000; // supports multicast + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: ::c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: ::c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +/// IP Mobility RFC 2004 +pub const IPPROTO_MOBILE: ::c_int = 55; +/// IPv6 ICMP +pub const IPPROTO_IPV6_ICMP: ::c_int = 58; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +/// ISO cnlp +pub const IPPROTO_EON: ::c_int = 80; +/// Ethernet-in-IP +pub const IPPROTO_ETHERIP: ::c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: ::c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_IPCOMP: ::c_int = 108; +/// VRRP RFC 2338 +pub const IPPROTO_VRRP: ::c_int = 112; +/// Common Address Resolution Protocol +pub const IPPROTO_CARP: ::c_int = 112; +/// L2TPv3 +// TEMP: Disabled for now; this constant was added to NetBSD on 2017-02-16, +// but isn't yet supported by the NetBSD rumprun kernel image used for +// libc testing. +//pub const IPPROTO_L2TP: ::c_int = 115; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; +/// PFSYNC +pub const IPPROTO_PFSYNC: ::c_int = 240; +pub const IPPROTO_MAX: ::c_int = 256; + +/// last return value of *_input(), meaning "all job for this pkt is done". +pub const IPPROTO_DONE: ::c_int = 257; + +/// sysctl placeholder for (FAST_)IPSEC +pub const CTL_IPPROTO_IPSEC: ::c_int = 258; + +pub const AF_OROUTE: ::c_int = 17; +pub const AF_ARP: ::c_int = 28; +pub const pseudo_AF_KEY: ::c_int = 29; +pub const pseudo_AF_HDRCMPLT: ::c_int = 30; +pub const AF_BLUETOOTH: ::c_int = 31; +pub const AF_IEEE80211: ::c_int = 32; +pub const AF_MPLS: ::c_int = 33; +pub const AF_ROUTE: ::c_int = 34; +pub const AF_MAX: ::c_int = 36; + +pub const NET_MAXID: ::c_int = AF_MAX; +pub const NET_RT_DUMP: ::c_int = 1; +pub const NET_RT_FLAGS: ::c_int = 2; +pub const NET_RT_OOOIFLIST: ::c_int = 3; +pub const NET_RT_OOIFLIST: ::c_int = 4; +pub const NET_RT_OIFLIST: ::c_int = 5; +pub const NET_RT_IFLIST: ::c_int = 6; +pub const NET_RT_MAXID: ::c_int = 7; + +pub const PF_OROUTE: ::c_int = AF_OROUTE; +pub const PF_ARP: ::c_int = AF_ARP; +pub const PF_KEY: ::c_int = pseudo_AF_KEY; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_MPLS: ::c_int = AF_MPLS; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_MAX: ::c_int = AF_MAX; + +pub const MSG_NBIO: ::c_int = 0x1000; +pub const MSG_WAITFORONE: ::c_int = 0x2000; +pub const MSG_NOTIFICATION: ::c_int = 0x4000; + +pub const SCM_TIMESTAMP: ::c_int = 0x08; +pub const SCM_CREDS: ::c_int = 0x10; + +pub const O_DSYNC : ::c_int = 0x10000; + +pub const MAP_RENAME : ::c_int = 0x20; +pub const MAP_NORESERVE : ::c_int = 0x40; +pub const MAP_HASSEMAPHORE : ::c_int = 0x200; +pub const MAP_WIRED: ::c_int = 0x800; + +pub const DCCP_TYPE_REQUEST: ::c_int = 0; +pub const DCCP_TYPE_RESPONSE: ::c_int = 1; +pub const DCCP_TYPE_DATA: ::c_int = 2; +pub const DCCP_TYPE_ACK: ::c_int = 3; +pub const DCCP_TYPE_DATAACK: ::c_int = 4; +pub const DCCP_TYPE_CLOSEREQ: ::c_int = 5; +pub const DCCP_TYPE_CLOSE: ::c_int = 6; +pub const DCCP_TYPE_RESET: ::c_int = 7; +pub const DCCP_TYPE_MOVE: ::c_int = 8; + +pub const DCCP_FEATURE_CC: ::c_int = 1; +pub const DCCP_FEATURE_ECN: ::c_int = 2; +pub const DCCP_FEATURE_ACKRATIO: ::c_int = 3; +pub const DCCP_FEATURE_ACKVECTOR: ::c_int = 4; +pub const DCCP_FEATURE_MOBILITY: ::c_int = 5; +pub const DCCP_FEATURE_LOSSWINDOW: ::c_int = 6; +pub const DCCP_FEATURE_CONN_NONCE: ::c_int = 8; +pub const DCCP_FEATURE_IDENTREG: ::c_int = 7; + +pub const DCCP_OPT_PADDING: ::c_int = 0; +pub const DCCP_OPT_DATA_DISCARD: ::c_int = 1; +pub const DCCP_OPT_SLOW_RECV: ::c_int = 2; +pub const DCCP_OPT_BUF_CLOSED: ::c_int = 3; +pub const DCCP_OPT_CHANGE_L: ::c_int = 32; +pub const DCCP_OPT_CONFIRM_L: ::c_int = 33; +pub const DCCP_OPT_CHANGE_R: ::c_int = 34; +pub const DCCP_OPT_CONFIRM_R: ::c_int = 35; +pub const DCCP_OPT_INIT_COOKIE: ::c_int = 36; +pub const DCCP_OPT_NDP_COUNT: ::c_int = 37; +pub const DCCP_OPT_ACK_VECTOR0: ::c_int = 38; +pub const DCCP_OPT_ACK_VECTOR1: ::c_int = 39; +pub const DCCP_OPT_RECV_BUF_DROPS: ::c_int = 40; +pub const DCCP_OPT_TIMESTAMP: ::c_int = 41; +pub const DCCP_OPT_TIMESTAMP_ECHO: ::c_int = 42; +pub const DCCP_OPT_ELAPSEDTIME: ::c_int = 43; +pub const DCCP_OPT_DATACHECKSUM: ::c_int = 44; + +pub const DCCP_REASON_UNSPEC: ::c_int = 0; +pub const DCCP_REASON_CLOSED: ::c_int = 1; +pub const DCCP_REASON_INVALID: ::c_int = 2; +pub const DCCP_REASON_OPTION_ERR: ::c_int = 3; +pub const DCCP_REASON_FEA_ERR: ::c_int = 4; +pub const DCCP_REASON_CONN_REF: ::c_int = 5; +pub const DCCP_REASON_BAD_SNAME: ::c_int = 6; +pub const DCCP_REASON_BAD_COOKIE: ::c_int = 7; +pub const DCCP_REASON_INV_MOVE: ::c_int = 8; +pub const DCCP_REASON_UNANSW_CH: ::c_int = 10; +pub const DCCP_REASON_FRUITLESS_NEG: ::c_int = 11; + +pub const DCCP_CCID: ::c_int = 1; +pub const DCCP_CSLEN: ::c_int = 2; +pub const DCCP_MAXSEG: ::c_int = 4; +pub const DCCP_SERVICE: ::c_int = 8; + +pub const DCCP_NDP_LIMIT: ::c_int = 16; +pub const DCCP_SEQ_NUM_LIMIT: ::c_int = 16777216; +pub const DCCP_MAX_OPTIONS: ::c_int = 32; +pub const DCCP_MAX_PKTS: ::c_int = 100; + +pub const _PC_LINK_MAX : ::c_int = 1; +pub const _PC_MAX_CANON : ::c_int = 2; +pub const _PC_MAX_INPUT : ::c_int = 3; +pub const _PC_NAME_MAX : ::c_int = 4; +pub const _PC_PATH_MAX : ::c_int = 5; +pub const _PC_PIPE_BUF : ::c_int = 6; +pub const _PC_CHOWN_RESTRICTED : ::c_int = 7; +pub const _PC_NO_TRUNC : ::c_int = 8; +pub const _PC_VDISABLE : ::c_int = 9; +pub const _PC_SYNC_IO : ::c_int = 10; +pub const _PC_FILESIZEBITS : ::c_int = 11; +pub const _PC_SYMLINK_MAX : ::c_int = 12; +pub const _PC_2_SYMLINKS : ::c_int = 13; +pub const _PC_ACL_EXTENDED : ::c_int = 14; +pub const _PC_MIN_HOLE_SIZE : ::c_int = 15; + +pub const _SC_SYNCHRONIZED_IO : ::c_int = 31; +pub const _SC_IOV_MAX : ::c_int = 32; +pub const _SC_MAPPED_FILES : ::c_int = 33; +pub const _SC_MEMLOCK : ::c_int = 34; +pub const _SC_MEMLOCK_RANGE : ::c_int = 35; +pub const _SC_MEMORY_PROTECTION : ::c_int = 36; +pub const _SC_LOGIN_NAME_MAX : ::c_int = 37; +pub const _SC_MONOTONIC_CLOCK : ::c_int = 38; +pub const _SC_CLK_TCK : ::c_int = 39; +pub const _SC_ATEXIT_MAX : ::c_int = 40; +pub const _SC_THREADS : ::c_int = 41; +pub const _SC_SEMAPHORES : ::c_int = 42; +pub const _SC_BARRIERS : ::c_int = 43; +pub const _SC_TIMERS : ::c_int = 44; +pub const _SC_SPIN_LOCKS : ::c_int = 45; +pub const _SC_READER_WRITER_LOCKS : ::c_int = 46; +pub const _SC_GETGR_R_SIZE_MAX : ::c_int = 47; +pub const _SC_GETPW_R_SIZE_MAX : ::c_int = 48; +pub const _SC_CLOCK_SELECTION : ::c_int = 49; +pub const _SC_ASYNCHRONOUS_IO : ::c_int = 50; +pub const _SC_AIO_LISTIO_MAX : ::c_int = 51; +pub const _SC_AIO_MAX : ::c_int = 52; +pub const _SC_MESSAGE_PASSING : ::c_int = 53; +pub const _SC_MQ_OPEN_MAX : ::c_int = 54; +pub const _SC_MQ_PRIO_MAX : ::c_int = 55; +pub const _SC_PRIORITY_SCHEDULING : ::c_int = 56; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : ::c_int = 57; +pub const _SC_THREAD_KEYS_MAX : ::c_int = 58; +pub const _SC_THREAD_STACK_MIN : ::c_int = 59; +pub const _SC_THREAD_THREADS_MAX : ::c_int = 60; +pub const _SC_THREAD_ATTR_STACKADDR : ::c_int = 61; +pub const _SC_THREAD_ATTR_STACKSIZE : ::c_int = 62; +pub const _SC_THREAD_PRIORITY_SCHEDULING : ::c_int = 63; +pub const _SC_THREAD_PRIO_INHERIT : ::c_int = 64; +pub const _SC_THREAD_PRIO_PROTECT : ::c_int = 65; +pub const _SC_THREAD_PROCESS_SHARED : ::c_int = 66; +pub const _SC_THREAD_SAFE_FUNCTIONS : ::c_int = 67; +pub const _SC_TTY_NAME_MAX : ::c_int = 68; +pub const _SC_HOST_NAME_MAX : ::c_int = 69; +pub const _SC_PASS_MAX : ::c_int = 70; +pub const _SC_REGEXP : ::c_int = 71; +pub const _SC_SHELL : ::c_int = 72; +pub const _SC_SYMLOOP_MAX : ::c_int = 73; +pub const _SC_V6_ILP32_OFF32 : ::c_int = 74; +pub const _SC_V6_ILP32_OFFBIG : ::c_int = 75; +pub const _SC_V6_LP64_OFF64 : ::c_int = 76; +pub const _SC_V6_LPBIG_OFFBIG : ::c_int = 77; +pub const _SC_2_PBS : ::c_int = 80; +pub const _SC_2_PBS_ACCOUNTING : ::c_int = 81; +pub const _SC_2_PBS_CHECKPOINT : ::c_int = 82; +pub const _SC_2_PBS_LOCATE : ::c_int = 83; +pub const _SC_2_PBS_MESSAGE : ::c_int = 84; +pub const _SC_2_PBS_TRACK : ::c_int = 85; +pub const _SC_SPAWN : ::c_int = 86; +pub const _SC_SHARED_MEMORY_OBJECTS : ::c_int = 87; +pub const _SC_TIMER_MAX : ::c_int = 88; +pub const _SC_SEM_NSEMS_MAX : ::c_int = 89; +pub const _SC_CPUTIME : ::c_int = 90; +pub const _SC_THREAD_CPUTIME : ::c_int = 91; +pub const _SC_DELAYTIMER_MAX : ::c_int = 92; +// These two variables will be supported in NetBSD 8.0 +// pub const _SC_SIGQUEUE_MAX : ::c_int = 93; +// pub const _SC_REALTIME_SIGNALS : ::c_int = 94; +pub const _SC_PHYS_PAGES : ::c_int = 121; +pub const _SC_NPROCESSORS_CONF : ::c_int = 1001; +pub const _SC_NPROCESSORS_ONLN : ::c_int = 1002; +pub const _SC_SCHED_RT_TS : ::c_int = 2001; +pub const _SC_SCHED_PRI_MIN : ::c_int = 2002; +pub const _SC_SCHED_PRI_MAX : ::c_int = 2003; + +pub const FD_SETSIZE: usize = 0x100; + +pub const ST_NOSUID: ::c_ulong = 8; + +cfg_if! { + if #[cfg(any(target_arch = "sparc", target_arch = "sparc64", + target_arch = "x86", target_arch = "x86_64"))] { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + ptm_magic: 0x33330003, + ptm_errorcheck: 0, + ptm_pad1: [0; 3], + ptm_unused: 0, + ptm_pad2: [0; 3], + ptm_waiters: 0 as *mut _, + ptm_owner: 0, + ptm_recursed: 0, + ptm_spare2: 0 as *mut _, + }; + } else { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + ptm_magic: 0x33330003, + ptm_errorcheck: 0, + ptm_unused: 0, + ptm_waiters: 0 as *mut _, + ptm_owner: 0, + ptm_recursed: 0, + ptm_spare2: 0 as *mut _, + }; + } +} + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + ptc_magic: 0x55550005, + ptc_lock: 0, + ptc_waiters_first: 0 as *mut _, + ptc_waiters_last: 0 as *mut _, + ptc_mutex: 0 as *mut _, + ptc_private: 0 as *mut _, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + ptr_magic: 0x99990009, + ptr_interlock: 0, + ptr_rblocked_first: 0 as *mut _, + ptr_rblocked_last: 0 as *mut _, + ptr_wblocked_first: 0 as *mut _, + ptr_wblocked_last: 0 as *mut _, + ptr_nreaders: 0, + ptr_owner: 0, + ptr_private: 0 as *mut _, +}; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; + +pub const EVFILT_AIO: ::uint32_t = 2; +pub const EVFILT_PROC: ::uint32_t = 4; +pub const EVFILT_READ: ::uint32_t = 0; +pub const EVFILT_SIGNAL: ::uint32_t = 5; +pub const EVFILT_TIMER: ::uint32_t = 6; +pub const EVFILT_VNODE: ::uint32_t = 3; +pub const EVFILT_WRITE: ::uint32_t = 1; + +pub const EV_ADD: ::uint32_t = 0x1; +pub const EV_DELETE: ::uint32_t = 0x2; +pub const EV_ENABLE: ::uint32_t = 0x4; +pub const EV_DISABLE: ::uint32_t = 0x8; +pub const EV_ONESHOT: ::uint32_t = 0x10; +pub const EV_CLEAR: ::uint32_t = 0x20; +pub const EV_RECEIPT: ::uint32_t = 0x40; +pub const EV_DISPATCH: ::uint32_t = 0x80; +pub const EV_FLAG1: ::uint32_t = 0x2000; +pub const EV_ERROR: ::uint32_t = 0x4000; +pub const EV_EOF: ::uint32_t = 0x8000; +pub const EV_SYSFLAGS: ::uint32_t = 0xf000; + +pub const NOTE_LOWAT: ::uint32_t = 0x00000001; +pub const NOTE_DELETE: ::uint32_t = 0x00000001; +pub const NOTE_WRITE: ::uint32_t = 0x00000002; +pub const NOTE_EXTEND: ::uint32_t = 0x00000004; +pub const NOTE_ATTRIB: ::uint32_t = 0x00000008; +pub const NOTE_LINK: ::uint32_t = 0x00000010; +pub const NOTE_RENAME: ::uint32_t = 0x00000020; +pub const NOTE_REVOKE: ::uint32_t = 0x00000040; +pub const NOTE_EXIT: ::uint32_t = 0x80000000; +pub const NOTE_FORK: ::uint32_t = 0x40000000; +pub const NOTE_EXEC: ::uint32_t = 0x20000000; +pub const NOTE_PDATAMASK: ::uint32_t = 0x000fffff; +pub const NOTE_PCTRLMASK: ::uint32_t = 0xf0000000; +pub const NOTE_TRACK: ::uint32_t = 0x00000001; +pub const NOTE_TRACKERR: ::uint32_t = 0x00000002; +pub const NOTE_CHILD: ::uint32_t = 0x00000004; + +pub const TMP_MAX : ::c_uint = 308915776; + +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const RTLD_NOLOAD: ::c_int = 0x2000; +pub const RTLD_LOCAL: ::c_int = 0x200; + +pub const CTL_MAXNAME: ::c_int = 12; +pub const SYSCTL_NAMELEN: ::c_int = 32; +pub const SYSCTL_DEFSIZE: ::c_int = 8; +pub const CTLTYPE_NODE: ::c_int = 1; +pub const CTLTYPE_INT: ::c_int = 2; +pub const CTLTYPE_STRING: ::c_int = 3; +pub const CTLTYPE_QUAD: ::c_int = 4; +pub const CTLTYPE_STRUCT: ::c_int = 5; +pub const CTLTYPE_BOOL: ::c_int = 6; +pub const CTLFLAG_READONLY: ::c_int = 0x00000000; +pub const CTLFLAG_READWRITE: ::c_int = 0x00000070; +pub const CTLFLAG_ANYWRITE: ::c_int = 0x00000080; +pub const CTLFLAG_PRIVATE: ::c_int = 0x00000100; +pub const CTLFLAG_PERMANENT: ::c_int = 0x00000200; +pub const CTLFLAG_OWNDATA: ::c_int = 0x00000400; +pub const CTLFLAG_IMMEDIATE: ::c_int = 0x00000800; +pub const CTLFLAG_HEX: ::c_int = 0x00001000; +pub const CTLFLAG_ROOT: ::c_int = 0x00002000; +pub const CTLFLAG_ANYNUMBER: ::c_int = 0x00004000; +pub const CTLFLAG_HIDDEN: ::c_int = 0x00008000; +pub const CTLFLAG_ALIAS: ::c_int = 0x00010000; +pub const CTLFLAG_MMAP: ::c_int = 0x00020000; +pub const CTLFLAG_OWNDESC: ::c_int = 0x00040000; +pub const CTLFLAG_UNSIGNED: ::c_int = 0x00080000; +pub const SYSCTL_VERS_MASK: ::c_int = 0xff000000; +pub const SYSCTL_VERS_0: ::c_int = 0x00000000; +pub const SYSCTL_VERS_1: ::c_int = 0x01000000; +pub const SYSCTL_VERSION: ::c_int = SYSCTL_VERS_1; +pub const CTL_EOL: ::c_int = -1; +pub const CTL_QUERY: ::c_int = -2; +pub const CTL_CREATE: ::c_int = -3; +pub const CTL_CREATESYM: ::c_int = -4; +pub const CTL_DESTROY: ::c_int = -5; +pub const CTL_MMAP: ::c_int = -6; +pub const CTL_DESCRIBE: ::c_int = -7; +pub const CTL_UNSPEC: ::c_int = 0; +pub const CTL_KERN: ::c_int = 1; +pub const CTL_VM: ::c_int = 2; +pub const CTL_VFS: ::c_int = 3; +pub const CTL_NET: ::c_int = 4; +pub const CTL_DEBUG: ::c_int = 5; +pub const CTL_HW: ::c_int = 6; +pub const CTL_MACHDEP: ::c_int = 7; +pub const CTL_USER: ::c_int = 8; +pub const CTL_DDB: ::c_int = 9; +pub const CTL_PROC: ::c_int = 10; +pub const CTL_VENDOR: ::c_int = 11; +pub const CTL_EMUL: ::c_int = 12; +pub const CTL_SECURITY: ::c_int = 13; +pub const CTL_MAXID: ::c_int = 14; +pub const KERN_OSTYPE: ::c_int = 1; +pub const KERN_OSRELEASE: ::c_int = 2; +pub const KERN_OSREV: ::c_int = 3; +pub const KERN_VERSION: ::c_int = 4; +pub const KERN_MAXVNODES: ::c_int = 5; +pub const KERN_MAXPROC: ::c_int = 6; +pub const KERN_MAXFILES: ::c_int = 7; +pub const KERN_ARGMAX: ::c_int = 8; +pub const KERN_SECURELVL: ::c_int = 9; +pub const KERN_HOSTNAME: ::c_int = 10; +pub const KERN_HOSTID: ::c_int = 11; +pub const KERN_CLOCKRATE: ::c_int = 12; +pub const KERN_VNODE: ::c_int = 13; +pub const KERN_PROC: ::c_int = 14; +pub const KERN_FILE: ::c_int = 15; +pub const KERN_PROF: ::c_int = 16; +pub const KERN_POSIX1: ::c_int = 17; +pub const KERN_NGROUPS: ::c_int = 18; +pub const KERN_JOB_CONTROL: ::c_int = 19; +pub const KERN_SAVED_IDS: ::c_int = 20; +pub const KERN_OBOOTTIME: ::c_int = 21; +pub const KERN_DOMAINNAME: ::c_int = 22; +pub const KERN_MAXPARTITIONS: ::c_int = 23; +pub const KERN_RAWPARTITION: ::c_int = 24; +pub const KERN_NTPTIME: ::c_int = 25; +pub const KERN_TIMEX: ::c_int = 26; +pub const KERN_AUTONICETIME: ::c_int = 27; +pub const KERN_AUTONICEVAL: ::c_int = 28; +pub const KERN_RTC_OFFSET: ::c_int = 29; +pub const KERN_ROOT_DEVICE: ::c_int = 30; +pub const KERN_MSGBUFSIZE: ::c_int = 31; +pub const KERN_FSYNC: ::c_int = 32; +pub const KERN_OLDSYSVMSG: ::c_int = 33; +pub const KERN_OLDSYSVSEM: ::c_int = 34; +pub const KERN_OLDSYSVSHM: ::c_int = 35; +pub const KERN_OLDSHORTCORENAME: ::c_int = 36; +pub const KERN_SYNCHRONIZED_IO: ::c_int = 37; +pub const KERN_IOV_MAX: ::c_int = 38; +pub const KERN_MBUF: ::c_int = 39; +pub const KERN_MAPPED_FILES: ::c_int = 40; +pub const KERN_MEMLOCK: ::c_int = 41; +pub const KERN_MEMLOCK_RANGE: ::c_int = 42; +pub const KERN_MEMORY_PROTECTION: ::c_int = 43; +pub const KERN_LOGIN_NAME_MAX: ::c_int = 44; +pub const KERN_DEFCORENAME: ::c_int = 45; +pub const KERN_LOGSIGEXIT: ::c_int = 46; +pub const KERN_PROC2: ::c_int = 47; +pub const KERN_PROC_ARGS: ::c_int = 48; +pub const KERN_FSCALE: ::c_int = 49; +pub const KERN_CCPU: ::c_int = 50; +pub const KERN_CP_TIME: ::c_int = 51; +pub const KERN_OLDSYSVIPC_INFO: ::c_int = 52; +pub const KERN_MSGBUF: ::c_int = 53; +pub const KERN_CONSDEV: ::c_int = 54; +pub const KERN_MAXPTYS: ::c_int = 55; +pub const KERN_PIPE: ::c_int = 56; +pub const KERN_MAXPHYS: ::c_int = 57; +pub const KERN_SBMAX: ::c_int = 58; +pub const KERN_TKSTAT: ::c_int = 59; +pub const KERN_MONOTONIC_CLOCK: ::c_int = 60; +pub const KERN_URND: ::c_int = 61; +pub const KERN_LABELSECTOR: ::c_int = 62; +pub const KERN_LABELOFFSET: ::c_int = 63; +pub const KERN_LWP: ::c_int = 64; +pub const KERN_FORKFSLEEP: ::c_int = 65; +pub const KERN_POSIX_THREADS: ::c_int = 66; +pub const KERN_POSIX_SEMAPHORES: ::c_int = 67; +pub const KERN_POSIX_BARRIERS: ::c_int = 68; +pub const KERN_POSIX_TIMERS: ::c_int = 69; +pub const KERN_POSIX_SPIN_LOCKS: ::c_int = 70; +pub const KERN_POSIX_READER_WRITER_LOCKS: ::c_int = 71; +pub const KERN_DUMP_ON_PANIC: ::c_int = 72; +pub const KERN_SOMAXKVA: ::c_int = 73; +pub const KERN_ROOT_PARTITION: ::c_int = 74; +pub const KERN_DRIVERS: ::c_int = 75; +pub const KERN_BUF: ::c_int = 76; +pub const KERN_FILE2: ::c_int = 77; +pub const KERN_VERIEXEC: ::c_int = 78; +pub const KERN_CP_ID: ::c_int = 79; +pub const KERN_HARDCLOCK_TICKS: ::c_int = 80; +pub const KERN_ARND: ::c_int = 81; +pub const KERN_SYSVIPC: ::c_int = 82; +pub const KERN_BOOTTIME: ::c_int = 83; +pub const KERN_EVCNT: ::c_int = 84; +pub const KERN_MAXID: ::c_int = 85; +pub const KERN_PROC_ALL: ::c_int = 0; +pub const KERN_PROC_PID: ::c_int = 1; +pub const KERN_PROC_PGRP: ::c_int = 2; +pub const KERN_PROC_SESSION: ::c_int = 3; +pub const KERN_PROC_TTY: ::c_int = 4; +pub const KERN_PROC_UID: ::c_int = 5; +pub const KERN_PROC_RUID: ::c_int = 6; +pub const KERN_PROC_GID: ::c_int = 7; +pub const KERN_PROC_RGID: ::c_int = 8; +pub const KERN_PROC_ARGV: ::c_int = 1; +pub const KERN_PROC_NARGV: ::c_int = 2; +pub const KERN_PROC_ENV: ::c_int = 3; +pub const KERN_PROC_NENV: ::c_int = 4; +pub const KERN_PROC_PATHNAME: ::c_int = 5; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NODATA: ::c_int = 7; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 14; + +pub const AIO_CANCELED: ::c_int = 1; +pub const AIO_NOTCANCELED: ::c_int = 2; +pub const AIO_ALLDONE: ::c_int = 3; +pub const LIO_NOP: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 1; +pub const LIO_READ: ::c_int = 2; +pub const LIO_WAIT: ::c_int = 1; +pub const LIO_NOWAIT: ::c_int = 0; + +pub const SIGEV_NONE: ::c_int = 0; +pub const SIGEV_SIGNAL: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; + +pub const WSTOPPED: ::c_int = 0x00000002; // same as WUNTRACED +pub const WCONTINUED: ::c_int = 0x00000010; +pub const WEXITED: ::c_int = 0x000000020; +pub const WNOWAIT: ::c_int = 0x00010000; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 4; + +pub const B460800: ::speed_t = 460800; +pub const B921600: ::speed_t = 921600; + +pub const ONOCR: ::tcflag_t = 0x20; +pub const ONLRET: ::tcflag_t = 0x40; +pub const CDTRCTS: ::tcflag_t = 0x00020000; +pub const CHWFLOW: ::tcflag_t = ::MDMBUF | ::CRTSCTS | ::CDTRCTS; + +pub const SOCK_CLOEXEC: ::c_int = 0x10000000; +pub const SOCK_NONBLOCK: ::c_int = 0x20000000; + +pub const FIONCLEX: ::c_ulong = 0x20006602; +// Uncomment on next NetBSD release +// pub const FIOSEEKDATA: ::c_ulong = 0xc0086661; +// pub const FIOSEEKHOLE: ::c_ulong = 0xc0086662; +pub const FIONREAD: ::c_ulong = 0x4004667f; +pub const FIOASYNC: ::c_ulong = 0x8004667d; +pub const FIOSETOWN: ::c_ulong = 0x8004667c; +pub const FIOGETOWN: ::c_ulong = 0x4004667b; +pub const OFIOGETBMAP: ::c_ulong = 0xc004667a; +pub const FIOGETBMAP: ::c_ulong = 0xc008667a; +pub const FIONWRITE: ::c_ulong = 0x40046679; +pub const FIONSPACE: ::c_ulong = 0x40046678; +pub const FIBMAP: ::c_ulong = 0xc008667a; + +pub const SIGSTKSZ : ::size_t = 40960; + +pub const PT_DUMPCORE: ::c_int = 12; +pub const PT_LWPINFO: ::c_int = 13; +pub const PT_SYSCALL: ::c_int = 14; +pub const PT_SYSCALLEMU: ::c_int = 15; +pub const PT_SET_EVENT_MASK: ::c_int = 16; +pub const PT_GET_EVENT_MASK: ::c_int = 17; +pub const PT_GET_PROCESS_STATE: ::c_int = 18; +pub const PT_FIRSTMACH: ::c_int = 32; + +// Flags for chflags(2) +pub const SF_SNAPSHOT: ::c_ulong = 0x00200000; +pub const SF_LOG: ::c_ulong = 0x00400000; +pub const SF_SNAPINVAL: ::c_ulong = 0x00800000; + +fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const ::cmsghdr) -> *mut ::c_uchar { + (cmsg as *mut ::c_uchar) + .offset(_ALIGN(::mem::size_of::<::cmsghdr>()) as isize) + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + _ALIGN(::mem::size_of::<::cmsghdr>()) as ::c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const ::msghdr, cmsg: *const ::cmsghdr) + -> *mut ::cmsghdr + { + if cmsg.is_null() { + return ::CMSG_FIRSTHDR(mhdr); + }; + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + + _ALIGN(::mem::size_of::<::cmsghdr>()); + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if next > max { + 0 as *mut ::cmsghdr + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) + as *mut ::cmsghdr + } + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (_ALIGN(::mem::size_of::<::cmsghdr>()) + _ALIGN(length as usize)) + as ::c_uint + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + status >> 8 + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0o177) == 0o177 + } + + // dirfd() is a macro on netbsd to access + // the first field of the struct where dirp points to: + // http://cvsweb.netbsd.org/bsdweb.cgi/src/include/dirent.h?rev=1.36 + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int { + *(dirp as *const ::c_int) + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0xffff + } + + pub fn SOCKCREDSIZE(ngrps: usize) -> usize { + let ngrps = if ngrps > 0 { + ngrps - 1 + } else { + 0 + }; + ::mem::size_of::() + ::mem::size_of::<::gid_t>() * ngrps + } +} + +#[link(name = "rt")] +extern { + pub fn aio_read(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_fsync(op: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_error(aiocbp: *const aiocb) -> ::c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ::ssize_t; + #[link_name = "__aio_suspend50"] + pub fn aio_suspend(aiocb_list: *const *const aiocb, nitems: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn aio_cancel(fd: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn lio_listio(mode: ::c_int, aiocb_list: *const *mut aiocb, + nitems: ::c_int, sevp: *mut sigevent) -> ::c_int; +} + +extern { + pub fn chflags(path: *const ::c_char, flags: ::c_ulong) -> ::c_int; + pub fn fchflags(fd: ::c_int, flags: ::c_ulong) -> ::c_int; + pub fn lchflags(path: *const ::c_char, flags: ::c_ulong) -> ::c_int; + + pub fn extattr_delete_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_delete_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_delete_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char) -> ::c_int; + pub fn extattr_get_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_get_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_get_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *mut ::c_void, + nbytes: ::size_t) -> ::ssize_t; + pub fn extattr_namespace_to_string(attrnamespace: ::c_int, + string: *mut *mut ::c_char) -> ::c_int; + pub fn extattr_set_fd(fd: ::c_int, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::c_int; + pub fn extattr_set_file(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::c_int; + pub fn extattr_set_link(path: *const ::c_char, + attrnamespace: ::c_int, + attrname: *const ::c_char, + data: *const ::c_void, + nbytes: ::size_t) -> ::c_int; + pub fn extattr_string_to_namespace(string: *const ::c_char, + attrnamespace: *mut ::c_int) -> ::c_int; + + #[link_name = "__lutimes50"] + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn sysctl(name: *const ::c_int, + namelen: ::c_uint, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *const ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn sysctlbyname(name: *const ::c_char, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *const ::c_void, + newlen: ::size_t) + -> ::c_int; + #[link_name = "__kevent50"] + pub fn kevent(kq: ::c_int, + changelist: *const ::kevent, + nchanges: ::size_t, + eventlist: *mut ::kevent, + nevents: ::size_t, + timeout: *const ::timespec) -> ::c_int; + #[link_name = "__mount50"] + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + flags: ::c_int, + data: *mut ::c_void, + size: ::size_t) -> ::c_int; + pub fn mq_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::mqd_t; + pub fn mq_close(mqd: ::mqd_t) -> ::c_int; + pub fn mq_getattr(mqd: ::mqd_t, attr: *mut ::mq_attr) -> ::c_int; + pub fn mq_notify(mqd: ::mqd_t, notification: *const ::sigevent) -> ::c_int; + pub fn mq_receive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint) -> ::ssize_t; + pub fn mq_send(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint) -> ::c_int; + pub fn mq_setattr(mqd: ::mqd_t, + newattr: *const ::mq_attr, + oldattr: *mut ::mq_attr) -> ::c_int; + #[link_name = "__mq_timedreceive50"] + pub fn mq_timedreceive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint, + abs_timeout: *const ::timespec) -> ::ssize_t; + #[link_name = "__mq_timedsend50"] + pub fn mq_timedsend(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint, + abs_timeout: *const ::timespec) -> ::c_int; + pub fn mq_unlink(name: *const ::c_char) -> ::c_int; + pub fn ptrace(request: ::c_int, + pid: ::pid_t, + addr: *mut ::c_void, + data: ::c_int) -> ::c_int; + pub fn pthread_setname_np(t: ::pthread_t, + name: *const ::c_char, + arg: *mut ::c_void) -> ::c_int; + pub fn pthread_getattr_np(native: ::pthread_t, + attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + #[link_name = "__sigtimedwait50"] + pub fn sigtimedwait(set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const ::timespec) -> ::c_int; + pub fn sigwaitinfo(set: *const sigset_t, + info: *mut siginfo_t) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn localeconv_l(loc: ::locale_t) -> *mut lconv; + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + #[link_name = "__settimeofday50"] + pub fn settimeofday(tv: *const ::timeval, tz: *const ::c_void) -> ::c_int; + + pub fn dup3(src: ::c_int, dst: ::c_int, flags: ::c_int) -> ::c_int; + + pub fn sendmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int) -> ::c_int; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int, timeout: *mut ::timespec) -> ::c_int; +} + +#[link(name = "util")] +extern { + #[cfg_attr(target_os = "netbsd", link_name = "__getpwent_r50")] + pub fn getpwent_r(pwd: *mut ::passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::passwd) -> ::c_int; + pub fn getgrent_r(grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else if #[cfg(target_arch = "sparc64")] { + mod sparc64; + pub use self::sparc64::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs b/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs new file mode 100644 index 000000000..e12fd5e11 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/powerpc.rs @@ -0,0 +1,21 @@ +use PT_FIRSTMACH; + +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_char = u8; +pub type __cpu_simple_lock_nv_t = ::c_int; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_double>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const PT_STEP: ::c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: ::c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: ::c_int = PT_FIRSTMACH + 2; diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs b/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs new file mode 100644 index 000000000..6a86759e0 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/sparc64.rs @@ -0,0 +1,8 @@ +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = i8; +pub type __cpu_simple_lock_nv_t = ::c_uchar; + +// should be pub(crate), but that requires Rust 1.18.0 +#[doc(hidden)] +pub const _ALIGNBYTES: usize = 0xf; diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs b/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs new file mode 100644 index 000000000..daa89a11a --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/x86.rs @@ -0,0 +1,15 @@ +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_char = i8; +pub type __cpu_simple_lock_nv_t = ::c_uchar; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_int>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 4 - 1; + } +} diff --git a/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs b/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs new file mode 100644 index 000000000..0860d4f6c --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/netbsd/x86_64.rs @@ -0,0 +1,23 @@ +use PT_FIRSTMACH; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = i8; +pub type __cpu_simple_lock_nv_t = ::c_uchar; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const PT_STEP: ::c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: ::c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: ::c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: ::c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: ::c_int = PT_FIRSTMACH + 4; diff --git a/libc/src/unix/bsd/netbsdlike/openbsdlike/mod.rs b/libc/src/unix/bsd/netbsdlike/openbsdlike/mod.rs new file mode 100644 index 000000000..223064b76 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/openbsdlike/mod.rs @@ -0,0 +1,945 @@ +use unix::bsd::O_SYNC; + +pub type clock_t = i64; +pub type suseconds_t = ::c_long; +pub type dev_t = i32; +pub type sigset_t = ::c_uint; +pub type blksize_t = ::int32_t; +pub type fsblkcnt_t = ::uint64_t; +pub type fsfilcnt_t = ::uint64_t; +pub type pthread_attr_t = *mut ::c_void; +pub type pthread_mutex_t = *mut ::c_void; +pub type pthread_mutexattr_t = *mut ::c_void; +pub type pthread_cond_t = *mut ::c_void; +pub type pthread_condattr_t = *mut ::c_void; +pub type pthread_rwlock_t = *mut ::c_void; +pub type pthread_rwlockattr_t = *mut ::c_void; +pub type caddr_t = *mut ::c_char; + +s! { + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::int8_t; 8], + } + + pub struct kevent { + pub ident: ::uintptr_t, + pub filter: ::c_short, + pub flags: ::c_ushort, + pub fflags: ::c_uint, + pub data: ::int64_t, + pub udata: *mut ::c_void, + } + + pub struct stat { + pub st_mode: ::mode_t, + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_size: ::off_t, + pub st_blocks: ::blkcnt_t, + pub st_blksize: ::blksize_t, + pub st_flags: ::uint32_t, + pub st_gen: ::uint32_t, + pub st_birthtime: ::time_t, + pub st_birthtime_nsec: ::c_long, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_addr: *mut ::sockaddr, + pub ai_canonname: *mut ::c_char, + pub ai_next: *mut ::addrinfo, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct if_data { + pub ifi_type: ::c_uchar, + pub ifi_addrlen: ::c_uchar, + pub ifi_hdrlen: ::c_uchar, + pub ifi_link_state: ::c_uchar, + pub ifi_mtu: u32, + pub ifi_metric: u32, + pub ifi_rdomain: u32, + pub ifi_baudrate: u64, + pub ifi_ipackets: u64, + pub ifi_ierrors: u64, + pub ifi_opackets: u64, + pub ifi_oerrors: u64, + pub ifi_collisions: u64, + pub ifi_ibytes: u64, + pub ifi_obytes: u64, + pub ifi_imcasts: u64, + pub ifi_omcasts: u64, + pub ifi_iqdrops: u64, + pub ifi_oqdrops: u64, + pub ifi_noproto: u64, + pub ifi_capabilities: u32, + pub ifi_lastchange: ::timeval, + } + + pub struct if_msghdr { + pub ifm_msglen: ::c_ushort, + pub ifm_version: ::c_uchar, + pub ifm_type: ::c_uchar, + pub ifm_hdrlen: ::c_ushort, + pub ifm_index: ::c_ushort, + pub ifm_tableid: ::c_ushort, + pub ifm_pad1: ::c_uchar, + pub ifm_pad2: ::c_uchar, + pub ifm_addrs: ::c_int, + pub ifm_flags: ::c_int, + pub ifm_xflags: ::c_int, + pub ifm_data: if_data, + } + + pub struct sockaddr_dl { + pub sdl_len: ::c_uchar, + pub sdl_family: ::c_uchar, + pub sdl_index: ::c_ushort, + pub sdl_type: ::c_uchar, + pub sdl_nlen: ::c_uchar, + pub sdl_alen: ::c_uchar, + pub sdl_slen: ::c_uchar, + pub sdl_data: [::c_char; 24], + } + + pub struct sockpeercred { + pub uid: ::uid_t, + pub gid: ::gid_t, + pub pid: ::pid_t, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } +} + +s_no_extra_traits! { + pub struct dirent { + pub d_fileno: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: u16, + pub d_type: u8, + pub d_namlen: u8, + __d_padding: [u8; 4], + pub d_name: [::c_char; 256], + } + + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: ::sa_family_t, + __ss_pad1: [u8; 6], + __ss_pad2: i64, + __ss_pad3: [u8; 240], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub si_addr: *mut ::c_char, + #[cfg(target_pointer_width = "32")] + __pad: [u8; 112], + #[cfg(target_pointer_width = "64")] + __pad: [u8; 108], + } + + pub struct lastlog { + ll_time: ::time_t, + ll_line: [::c_char; UT_LINESIZE], + ll_host: [::c_char; UT_HOSTSIZE], + } + + pub struct utmp { + pub ut_line: [::c_char; UT_LINESIZE], + pub ut_name: [::c_char; UT_NAMESIZE], + pub ut_host: [::c_char; UT_HOSTSIZE], + pub ut_time: ::time_t, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_fileno == other.d_fileno + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self.d_namlen == other.d_namlen + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for dirent {} + + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_fileno", &self.d_fileno) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + .field("d_namlen", &self.d_namlen) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_fileno.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_namlen.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_len == other.ss_len + && self.ss_family == other.ss_family + } + } + + impl Eq for sockaddr_storage {} + + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_len", &self.ss_len) + .field("ss_family", &self.ss_family) + .finish() + } + } + + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_len.hash(state); + self.ss_family.hash(state); + } + } + + impl PartialEq for siginfo_t { + fn eq(&self, other: &siginfo_t) -> bool { + self.si_signo == other.si_signo + && self.si_code == other.si_code + && self.si_errno == other.si_errno + && self.si_addr == other.si_addr + } + } + + impl Eq for siginfo_t {} + + impl ::fmt::Debug for siginfo_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("siginfo_t") + .field("si_signo", &self.si_signo) + .field("si_code", &self.si_code) + .field("si_errno", &self.si_errno) + .field("si_addr", &self.si_addr) + .finish() + } + } + + impl ::hash::Hash for siginfo_t { + fn hash(&self, state: &mut H) { + self.si_signo.hash(state); + self.si_code.hash(state); + self.si_errno.hash(state); + self.si_addr.hash(state); + } + } + + impl PartialEq for lastlog { + fn eq(&self, other: &lastlog) -> bool { + self.ll_time == other.ll_time + && self + .ll_line + .iter() + .zip(other.ll_line.iter()) + .all(|(a,b)| a == b) + && self + .ll_host + .iter() + .zip(other.ll_host.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for lastlog {} + + impl ::fmt::Debug for lastlog { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("lastlog") + .field("ll_time", &self.ll_time) + // FIXME: .field("ll_line", &self.ll_line) + // FIXME: .field("ll_host", &self.ll_host) + .finish() + } + } + + impl ::hash::Hash for lastlog { + fn hash(&self, state: &mut H) { + self.ll_time.hash(state); + self.ll_line.hash(state); + self.ll_host.hash(state); + } + } + + impl PartialEq for utmp { + fn eq(&self, other: &utmp) -> bool { + self.ut_time == other.ut_time + && self + .ut_line + .iter() + .zip(other.ut_line.iter()) + .all(|(a,b)| a == b) + && self + .ut_name + .iter() + .zip(other.ut_name.iter()) + .all(|(a,b)| a == b) + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for utmp {} + + impl ::fmt::Debug for utmp { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmp") + // FIXME: .field("ut_line", &self.ut_line) + // FIXME: .field("ut_name", &self.ut_name) + // FIXME: .field("ut_host", &self.ut_host) + .field("ut_time", &self.ut_time) + .finish() + } + } + + impl ::hash::Hash for utmp { + fn hash(&self, state: &mut H) { + self.ut_line.hash(state); + self.ut_name.hash(state); + self.ut_host.hash(state); + self.ut_time.hash(state); + } + } + } +} + +pub const UT_NAMESIZE: usize = 32; +pub const UT_LINESIZE: usize = 8; +pub const UT_HOSTSIZE: usize = 256; + +pub const O_CLOEXEC: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x20000; +pub const O_RSYNC: ::c_int = O_SYNC; + +pub const MS_SYNC : ::c_int = 0x0002; +pub const MS_INVALIDATE : ::c_int = 0x0004; + +pub const POLLNORM: ::c_short = ::POLLRDNORM; + +pub const ENOATTR : ::c_int = 83; +pub const EILSEQ : ::c_int = 84; +pub const EOVERFLOW : ::c_int = 87; +pub const ECANCELED : ::c_int = 88; +pub const EIDRM : ::c_int = 89; +pub const ENOMSG : ::c_int = 90; +pub const ENOTSUP : ::c_int = 91; +pub const EBADMSG : ::c_int = 92; +pub const ENOTRECOVERABLE : ::c_int = 93; +pub const EOWNERDEAD : ::c_int = 94; +pub const EPROTO : ::c_int = 95; +pub const ELAST : ::c_int = 95; + +pub const F_DUPFD_CLOEXEC : ::c_int = 10; + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_EACCESS: ::c_int = 0x01; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x02; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x04; +pub const AT_REMOVEDIR: ::c_int = 0x08; + +pub const RLIM_NLIMITS: ::c_int = 9; + +pub const SO_TIMESTAMP: ::c_int = 0x0800; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_BINDANY: ::c_int = 0x1000; +pub const SO_NETPROC: ::c_int = 0x1020; +pub const SO_RTABLE: ::c_int = 0x1021; +pub const SO_PEERCRED: ::c_int = 0x1022; +pub const SO_SPLICE: ::c_int = 0x1023; + +// sys/netinet/in.h +// Protocols (RFC 1700) +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// gateway^2 (deprecated) +pub const IPPROTO_GGP: ::c_int = 3; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +/// IP Mobility RFC 2004 +pub const IPPROTO_MOBILE: ::c_int = 55; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +/// ISO cnlp +pub const IPPROTO_EON: ::c_int = 80; +/// Ethernet-in-IP +pub const IPPROTO_ETHERIP: ::c_int = 97; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: ::c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_IPCOMP: ::c_int = 108; +/// CARP +pub const IPPROTO_CARP: ::c_int = 112; +/// unicast MPLS packet +pub const IPPROTO_MPLS: ::c_int = 137; +/// PFSYNC +pub const IPPROTO_PFSYNC: ::c_int = 240; +pub const IPPROTO_MAX: ::c_int = 256; + +/* Only used internally, so it can be outside the range of valid IP protocols */ +/// Divert sockets +pub const IPPROTO_DIVERT: ::c_int = 258; + +pub const IP_RECVDSTADDR: ::c_int = 7; +pub const IP_SENDSRCADDR: ::c_int = IP_RECVDSTADDR; +pub const IP_RECVIF: ::c_int = 30; + +// sys/netinet/in.h +pub const TCP_MD5SIG: ::c_int = 0x04; +pub const TCP_NOPUSH: ::c_int = 0x10; + +pub const AF_ECMA: ::c_int = 8; +pub const AF_ROUTE: ::c_int = 17; +pub const AF_ENCAP: ::c_int = 28; +pub const AF_SIP: ::c_int = 29; +pub const AF_KEY: ::c_int = 30; +pub const pseudo_AF_HDRCMPLT: ::c_int = 31; +pub const AF_BLUETOOTH: ::c_int = 32; +pub const AF_MPLS: ::c_int = 33; +pub const pseudo_AF_PFLOW: ::c_int = 34; +pub const pseudo_AF_PIPEX: ::c_int = 35; +#[doc(hidden)] +pub const AF_MAX: ::c_int = 36; + +#[doc(hidden)] +pub const NET_MAXID: ::c_int = AF_MAX; +pub const NET_RT_DUMP: ::c_int = 1; +pub const NET_RT_FLAGS: ::c_int = 2; +pub const NET_RT_IFLIST: ::c_int = 3; +pub const NET_RT_STATS: ::c_int = 4; +pub const NET_RT_TABLE: ::c_int = 5; +pub const NET_RT_IFNAMES: ::c_int = 6; +#[doc(hidden)] +pub const NET_RT_MAXID: ::c_int = 7; + +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; + +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_ECMA: ::c_int = AF_ECMA; +pub const PF_ENCAP: ::c_int = AF_ENCAP; +pub const PF_SIP: ::c_int = AF_SIP; +pub const PF_KEY: ::c_int = AF_KEY; +pub const PF_BPF: ::c_int = pseudo_AF_HDRCMPLT; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_MPLS: ::c_int = AF_MPLS; +pub const PF_PFLOW: ::c_int = pseudo_AF_PFLOW; +pub const PF_PIPEX: ::c_int = pseudo_AF_PIPEX; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +pub const SCM_TIMESTAMP: ::c_int = 0x04; + +pub const O_DSYNC : ::c_int = 128; + +pub const MAP_RENAME : ::c_int = 0x0000; +pub const MAP_NORESERVE : ::c_int = 0x0000; +pub const MAP_HASSEMAPHORE : ::c_int = 0x0000; + +pub const EIPSEC : ::c_int = 82; +pub const ENOMEDIUM : ::c_int = 85; +pub const EMEDIUMTYPE : ::c_int = 86; + +pub const EAI_BADFLAGS: ::c_int = -1; +pub const EAI_NONAME: ::c_int = -2; +pub const EAI_AGAIN: ::c_int = -3; +pub const EAI_FAIL: ::c_int = -4; +pub const EAI_NODATA: ::c_int = -5; +pub const EAI_FAMILY: ::c_int = -6; +pub const EAI_SOCKTYPE: ::c_int = -7; +pub const EAI_SERVICE: ::c_int = -8; +pub const EAI_MEMORY: ::c_int = -10; +pub const EAI_SYSTEM: ::c_int = -11; +pub const EAI_OVERFLOW: ::c_int = -14; + +pub const RUSAGE_THREAD: ::c_int = 1; + +pub const MAP_COPY : ::c_int = 0x0002; +pub const MAP_NOEXTEND : ::c_int = 0x0000; + +pub const _PC_LINK_MAX : ::c_int = 1; +pub const _PC_MAX_CANON : ::c_int = 2; +pub const _PC_MAX_INPUT : ::c_int = 3; +pub const _PC_NAME_MAX : ::c_int = 4; +pub const _PC_PATH_MAX : ::c_int = 5; +pub const _PC_PIPE_BUF : ::c_int = 6; +pub const _PC_CHOWN_RESTRICTED : ::c_int = 7; +pub const _PC_NO_TRUNC : ::c_int = 8; +pub const _PC_VDISABLE : ::c_int = 9; +pub const _PC_2_SYMLINKS : ::c_int = 10; +pub const _PC_ALLOC_SIZE_MIN : ::c_int = 11; +pub const _PC_ASYNC_IO : ::c_int = 12; +pub const _PC_FILESIZEBITS : ::c_int = 13; +pub const _PC_PRIO_IO : ::c_int = 14; +pub const _PC_REC_INCR_XFER_SIZE : ::c_int = 15; +pub const _PC_REC_MAX_XFER_SIZE : ::c_int = 16; +pub const _PC_REC_MIN_XFER_SIZE : ::c_int = 17; +pub const _PC_REC_XFER_ALIGN : ::c_int = 18; +pub const _PC_SYMLINK_MAX : ::c_int = 19; +pub const _PC_SYNC_IO : ::c_int = 20; +pub const _PC_TIMESTAMP_RESOLUTION : ::c_int = 21; + +pub const _SC_CLK_TCK : ::c_int = 3; +pub const _SC_SEM_NSEMS_MAX : ::c_int = 31; +pub const _SC_SEM_VALUE_MAX : ::c_int = 32; +pub const _SC_HOST_NAME_MAX : ::c_int = 33; +pub const _SC_MONOTONIC_CLOCK : ::c_int = 34; +pub const _SC_2_PBS : ::c_int = 35; +pub const _SC_2_PBS_ACCOUNTING : ::c_int = 36; +pub const _SC_2_PBS_CHECKPOINT : ::c_int = 37; +pub const _SC_2_PBS_LOCATE : ::c_int = 38; +pub const _SC_2_PBS_MESSAGE : ::c_int = 39; +pub const _SC_2_PBS_TRACK : ::c_int = 40; +pub const _SC_ADVISORY_INFO : ::c_int = 41; +pub const _SC_AIO_LISTIO_MAX : ::c_int = 42; +pub const _SC_AIO_MAX : ::c_int = 43; +pub const _SC_AIO_PRIO_DELTA_MAX : ::c_int = 44; +pub const _SC_ASYNCHRONOUS_IO : ::c_int = 45; +pub const _SC_ATEXIT_MAX : ::c_int = 46; +pub const _SC_BARRIERS : ::c_int = 47; +pub const _SC_CLOCK_SELECTION : ::c_int = 48; +pub const _SC_CPUTIME : ::c_int = 49; +pub const _SC_DELAYTIMER_MAX : ::c_int = 50; +pub const _SC_IOV_MAX : ::c_int = 51; +pub const _SC_IPV6 : ::c_int = 52; +pub const _SC_MAPPED_FILES : ::c_int = 53; +pub const _SC_MEMLOCK : ::c_int = 54; +pub const _SC_MEMLOCK_RANGE : ::c_int = 55; +pub const _SC_MEMORY_PROTECTION : ::c_int = 56; +pub const _SC_MESSAGE_PASSING : ::c_int = 57; +pub const _SC_MQ_OPEN_MAX : ::c_int = 58; +pub const _SC_MQ_PRIO_MAX : ::c_int = 59; +pub const _SC_PRIORITIZED_IO : ::c_int = 60; +pub const _SC_PRIORITY_SCHEDULING : ::c_int = 61; +pub const _SC_RAW_SOCKETS : ::c_int = 62; +pub const _SC_READER_WRITER_LOCKS : ::c_int = 63; +pub const _SC_REALTIME_SIGNALS : ::c_int = 64; +pub const _SC_REGEXP : ::c_int = 65; +pub const _SC_RTSIG_MAX : ::c_int = 66; +pub const _SC_SEMAPHORES : ::c_int = 67; +pub const _SC_SHARED_MEMORY_OBJECTS : ::c_int = 68; +pub const _SC_SHELL : ::c_int = 69; +pub const _SC_SIGQUEUE_MAX : ::c_int = 70; +pub const _SC_SPAWN : ::c_int = 71; +pub const _SC_SPIN_LOCKS : ::c_int = 72; +pub const _SC_SPORADIC_SERVER : ::c_int = 73; +pub const _SC_SS_REPL_MAX : ::c_int = 74; +pub const _SC_SYNCHRONIZED_IO : ::c_int = 75; +pub const _SC_SYMLOOP_MAX : ::c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR : ::c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE : ::c_int = 78; +pub const _SC_THREAD_CPUTIME : ::c_int = 79; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : ::c_int = 80; +pub const _SC_THREAD_KEYS_MAX : ::c_int = 81; +pub const _SC_THREAD_PRIO_INHERIT : ::c_int = 82; +pub const _SC_THREAD_PRIO_PROTECT : ::c_int = 83; +pub const _SC_THREAD_PRIORITY_SCHEDULING : ::c_int = 84; +pub const _SC_THREAD_PROCESS_SHARED : ::c_int = 85; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT : ::c_int = 86; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT : ::c_int = 87; +pub const _SC_THREAD_SPORADIC_SERVER : ::c_int = 88; +pub const _SC_THREAD_STACK_MIN : ::c_int = 89; +pub const _SC_THREAD_THREADS_MAX : ::c_int = 90; +pub const _SC_THREADS : ::c_int = 91; +pub const _SC_TIMEOUTS : ::c_int = 92; +pub const _SC_TIMER_MAX : ::c_int = 93; +pub const _SC_TIMERS : ::c_int = 94; +pub const _SC_TRACE : ::c_int = 95; +pub const _SC_TRACE_EVENT_FILTER : ::c_int = 96; +pub const _SC_TRACE_EVENT_NAME_MAX : ::c_int = 97; +pub const _SC_TRACE_INHERIT : ::c_int = 98; +pub const _SC_TRACE_LOG : ::c_int = 99; +pub const _SC_GETGR_R_SIZE_MAX : ::c_int = 100; +pub const _SC_GETPW_R_SIZE_MAX : ::c_int = 101; +pub const _SC_LOGIN_NAME_MAX : ::c_int = 102; +pub const _SC_THREAD_SAFE_FUNCTIONS : ::c_int = 103; +pub const _SC_TRACE_NAME_MAX : ::c_int = 104; +pub const _SC_TRACE_SYS_MAX : ::c_int = 105; +pub const _SC_TRACE_USER_EVENT_MAX : ::c_int = 106; +pub const _SC_TTY_NAME_MAX : ::c_int = 107; +pub const _SC_TYPED_MEMORY_OBJECTS : ::c_int = 108; +pub const _SC_V6_ILP32_OFF32 : ::c_int = 109; +pub const _SC_V6_ILP32_OFFBIG : ::c_int = 110; +pub const _SC_V6_LP64_OFF64 : ::c_int = 111; +pub const _SC_V6_LPBIG_OFFBIG : ::c_int = 112; +pub const _SC_V7_ILP32_OFF32 : ::c_int = 113; +pub const _SC_V7_ILP32_OFFBIG : ::c_int = 114; +pub const _SC_V7_LP64_OFF64 : ::c_int = 115; +pub const _SC_V7_LPBIG_OFFBIG : ::c_int = 116; +pub const _SC_XOPEN_CRYPT : ::c_int = 117; +pub const _SC_XOPEN_ENH_I18N : ::c_int = 118; +pub const _SC_XOPEN_LEGACY : ::c_int = 119; +pub const _SC_XOPEN_REALTIME : ::c_int = 120; +pub const _SC_XOPEN_REALTIME_THREADS : ::c_int = 121; +pub const _SC_XOPEN_STREAMS : ::c_int = 122; +pub const _SC_XOPEN_UNIX : ::c_int = 123; +pub const _SC_XOPEN_UUCP : ::c_int = 124; +pub const _SC_XOPEN_VERSION : ::c_int = 125; +pub const _SC_PHYS_PAGES : ::c_int = 500; +pub const _SC_AVPHYS_PAGES : ::c_int = 501; +pub const _SC_NPROCESSORS_CONF : ::c_int = 502; +pub const _SC_NPROCESSORS_ONLN : ::c_int = 503; + +pub const FD_SETSIZE: usize = 1024; + +pub const ST_NOSUID: ::c_ulong = 2; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _; + +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 1; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 2; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 3; +pub const PTHREAD_MUTEX_STRICT_NP: ::c_int = 4; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_STRICT_NP; + +pub const EVFILT_AIO: ::int16_t = -3; +pub const EVFILT_PROC: ::int16_t = -5; +pub const EVFILT_READ: ::int16_t = -1; +pub const EVFILT_SIGNAL: ::int16_t = -6; +pub const EVFILT_TIMER: ::int16_t = -7; +pub const EVFILT_VNODE: ::int16_t = -4; +pub const EVFILT_WRITE: ::int16_t = -2; + +pub const EV_ADD: ::uint16_t = 0x1; +pub const EV_DELETE: ::uint16_t = 0x2; +pub const EV_ENABLE: ::uint16_t = 0x4; +pub const EV_DISABLE: ::uint16_t = 0x8; +pub const EV_ONESHOT: ::uint16_t = 0x10; +pub const EV_CLEAR: ::uint16_t = 0x20; +pub const EV_RECEIPT: ::uint16_t = 0x40; +pub const EV_DISPATCH: ::uint16_t = 0x80; +pub const EV_FLAG1: ::uint16_t = 0x2000; +pub const EV_ERROR: ::uint16_t = 0x4000; +pub const EV_EOF: ::uint16_t = 0x8000; +pub const EV_SYSFLAGS: ::uint16_t = 0xf000; + +pub const NOTE_LOWAT: ::uint32_t = 0x00000001; +pub const NOTE_EOF: ::uint32_t = 0x00000002; +pub const NOTE_DELETE: ::uint32_t = 0x00000001; +pub const NOTE_WRITE: ::uint32_t = 0x00000002; +pub const NOTE_EXTEND: ::uint32_t = 0x00000004; +pub const NOTE_ATTRIB: ::uint32_t = 0x00000008; +pub const NOTE_LINK: ::uint32_t = 0x00000010; +pub const NOTE_RENAME: ::uint32_t = 0x00000020; +pub const NOTE_REVOKE: ::uint32_t = 0x00000040; +pub const NOTE_TRUNCATE: ::uint32_t = 0x00000080; +pub const NOTE_EXIT: ::uint32_t = 0x80000000; +pub const NOTE_FORK: ::uint32_t = 0x40000000; +pub const NOTE_EXEC: ::uint32_t = 0x20000000; +pub const NOTE_PDATAMASK: ::uint32_t = 0x000fffff; +pub const NOTE_PCTRLMASK: ::uint32_t = 0xf0000000; +pub const NOTE_TRACK: ::uint32_t = 0x00000001; +pub const NOTE_TRACKERR: ::uint32_t = 0x00000002; +pub const NOTE_CHILD: ::uint32_t = 0x00000004; + +pub const TMP_MAX : ::c_uint = 0x7fffffff; + +pub const NI_MAXHOST: ::size_t = 256; + +pub const RTLD_LOCAL: ::c_int = 0; +pub const CTL_MAXNAME: ::c_int = 12; +pub const CTLTYPE_NODE: ::c_int = 1; +pub const CTLTYPE_INT: ::c_int = 2; +pub const CTLTYPE_STRING: ::c_int = 3; +pub const CTLTYPE_QUAD: ::c_int = 4; +pub const CTLTYPE_STRUCT: ::c_int = 5; +pub const CTL_UNSPEC: ::c_int = 0; +pub const CTL_KERN: ::c_int = 1; +pub const CTL_VM: ::c_int = 2; +pub const CTL_FS: ::c_int = 3; +pub const CTL_NET: ::c_int = 4; +pub const CTL_DEBUG: ::c_int = 5; +pub const CTL_HW: ::c_int = 6; +pub const CTL_MACHDEP: ::c_int = 7; +pub const CTL_DDB: ::c_int = 9; +pub const CTL_VFS: ::c_int = 10; +pub const CTL_MAXID: ::c_int = 11; +pub const HW_NCPUONLINE: ::c_int = 25; +pub const KERN_OSTYPE: ::c_int = 1; +pub const KERN_OSRELEASE: ::c_int = 2; +pub const KERN_OSREV: ::c_int = 3; +pub const KERN_VERSION: ::c_int = 4; +pub const KERN_MAXVNODES: ::c_int = 5; +pub const KERN_MAXPROC: ::c_int = 6; +pub const KERN_MAXFILES: ::c_int = 7; +pub const KERN_ARGMAX: ::c_int = 8; +pub const KERN_SECURELVL: ::c_int = 9; +pub const KERN_HOSTNAME: ::c_int = 10; +pub const KERN_HOSTID: ::c_int = 11; +pub const KERN_CLOCKRATE: ::c_int = 12; +pub const KERN_PROF: ::c_int = 16; +pub const KERN_POSIX1: ::c_int = 17; +pub const KERN_NGROUPS: ::c_int = 18; +pub const KERN_JOB_CONTROL: ::c_int = 19; +pub const KERN_SAVED_IDS: ::c_int = 20; +pub const KERN_BOOTTIME: ::c_int = 21; +pub const KERN_DOMAINNAME: ::c_int = 22; +pub const KERN_MAXPARTITIONS: ::c_int = 23; +pub const KERN_RAWPARTITION: ::c_int = 24; +pub const KERN_MAXTHREAD: ::c_int = 25; +pub const KERN_NTHREADS: ::c_int = 26; +pub const KERN_OSVERSION: ::c_int = 27; +pub const KERN_SOMAXCONN: ::c_int = 28; +pub const KERN_SOMINCONN: ::c_int = 29; +pub const KERN_USERMOUNT: ::c_int = 30; +pub const KERN_NOSUIDCOREDUMP: ::c_int = 32; +pub const KERN_FSYNC: ::c_int = 33; +pub const KERN_SYSVMSG: ::c_int = 34; +pub const KERN_SYSVSEM: ::c_int = 35; +pub const KERN_SYSVSHM: ::c_int = 36; +pub const KERN_ARND: ::c_int = 37; +pub const KERN_MSGBUFSIZE: ::c_int = 38; +pub const KERN_MALLOCSTATS: ::c_int = 39; +pub const KERN_CPTIME: ::c_int = 40; +pub const KERN_NCHSTATS: ::c_int = 41; +pub const KERN_FORKSTAT: ::c_int = 42; +pub const KERN_NSELCOLL: ::c_int = 43; +pub const KERN_TTY: ::c_int = 44; +pub const KERN_CCPU: ::c_int = 45; +pub const KERN_FSCALE: ::c_int = 46; +pub const KERN_NPROCS: ::c_int = 47; +pub const KERN_MSGBUF: ::c_int = 48; +pub const KERN_POOL: ::c_int = 49; +pub const KERN_STACKGAPRANDOM: ::c_int = 50; +pub const KERN_SYSVIPC_INFO: ::c_int = 51; +pub const KERN_SPLASSERT: ::c_int = 54; +pub const KERN_PROC_ARGS: ::c_int = 55; +pub const KERN_NFILES: ::c_int = 56; +pub const KERN_TTYCOUNT: ::c_int = 57; +pub const KERN_NUMVNODES: ::c_int = 58; +pub const KERN_MBSTAT: ::c_int = 59; +pub const KERN_SEMINFO: ::c_int = 61; +pub const KERN_SHMINFO: ::c_int = 62; +pub const KERN_INTRCNT: ::c_int = 63; +pub const KERN_WATCHDOG: ::c_int = 64; +pub const KERN_PROC: ::c_int = 66; +pub const KERN_MAXCLUSTERS: ::c_int = 67; +pub const KERN_EVCOUNT: ::c_int = 68; +pub const KERN_TIMECOUNTER: ::c_int = 69; +pub const KERN_MAXLOCKSPERUID: ::c_int = 70; +pub const KERN_CPTIME2: ::c_int = 71; +pub const KERN_CACHEPCT: ::c_int = 72; +pub const KERN_FILE: ::c_int = 73; +pub const KERN_CONSDEV: ::c_int = 75; +pub const KERN_NETLIVELOCKS: ::c_int = 76; +pub const KERN_POOL_DEBUG: ::c_int = 77; +pub const KERN_PROC_CWD: ::c_int = 78; +pub const KERN_PROC_NOBROADCASTKILL: ::c_int = 79; +pub const KERN_PROC_VMMAP: ::c_int = 80; +pub const KERN_GLOBAL_PTRACE: ::c_int = 81; +pub const KERN_CONSBUFSIZE: ::c_int = 82; +pub const KERN_CONSBUF: ::c_int = 83; +pub const KERN_AUDIO: ::c_int = 84; +pub const KERN_CPUSTATS: ::c_int = 85; +pub const KERN_MAXID: ::c_int = 86; +pub const KERN_PROC_ALL: ::c_int = 0; +pub const KERN_PROC_PID: ::c_int = 1; +pub const KERN_PROC_PGRP: ::c_int = 2; +pub const KERN_PROC_SESSION: ::c_int = 3; +pub const KERN_PROC_TTY: ::c_int = 4; +pub const KERN_PROC_UID: ::c_int = 5; +pub const KERN_PROC_RUID: ::c_int = 6; +pub const KERN_PROC_KTHREAD: ::c_int = 7; +pub const KERN_PROC_SHOW_THREADS: ::c_int = 0x40000000; +pub const KERN_SYSVIPC_MSG_INFO: ::c_int = 1; +pub const KERN_SYSVIPC_SEM_INFO: ::c_int = 2; +pub const KERN_SYSVIPC_SHM_INFO: ::c_int = 3; +pub const KERN_PROC_ARGV: ::c_int = 1; +pub const KERN_PROC_NARGV: ::c_int = 2; +pub const KERN_PROC_ENV: ::c_int = 3; +pub const KERN_PROC_NENV: ::c_int = 4; +pub const KI_NGROUPS: ::c_int = 16; +pub const KI_MAXCOMLEN: ::c_int = 24; +pub const KI_WMESGLEN: ::c_int = 8; +pub const KI_MAXLOGNAME: ::c_int = 32; +pub const KI_EMULNAMELEN: ::c_int = 8; + +pub const CHWFLOW: ::tcflag_t = ::MDMBUF | ::CRTSCTS; +pub const OLCUC: ::tcflag_t = 0x20; +pub const ONOCR: ::tcflag_t = 0x40; +pub const ONLRET: ::tcflag_t = 0x80; + +pub const SOCK_CLOEXEC: ::c_int = 0x8000; +pub const SOCK_NONBLOCK: ::c_int = 0x4000; +pub const SOCK_DNS: ::c_int = 0x1000; + +pub const PTRACE_FORK: ::c_int = 0x0002; + +pub const WCONTINUED: ::c_int = 8; + +f! { + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status & 0o177777 == 0o177777 + } +} + +extern { + pub fn chflags(path: *const ::c_char, flags: ::c_uint) -> ::c_int; + pub fn fchflags(fd: ::c_int, flags: ::c_uint) -> ::c_int; + pub fn chflagsat(fd: ::c_int, path: *const ::c_char, flags: ::c_uint, + atflag: ::c_int) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::size_t, + serv: *mut ::c_char, + servlen: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn kevent(kq: ::c_int, + changelist: *const ::kevent, + nchanges: ::c_int, + eventlist: *mut ::kevent, + nevents: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn pthread_main_np() -> ::c_int; + pub fn pthread_set_name_np(tid: ::pthread_t, name: *const ::c_char); + pub fn pthread_stackseg_np(thread: ::pthread_t, + sinfo: *mut ::stack_t) -> ::c_int; + pub fn sysctl(name: *const ::c_int, + namelen: ::c_uint, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; + pub fn ptrace(request: ::c_int, + pid: ::pid_t, + addr: caddr_t, + data: ::c_int) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_os = "openbsd")] { + mod openbsd; + pub use self::openbsd::*; + } else { + // Unknown target_os + } +} diff --git a/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/aarch64.rs b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/aarch64.rs new file mode 100644 index 000000000..6a8cbb5c4 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/aarch64.rs @@ -0,0 +1,14 @@ +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = u8; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} diff --git a/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/mod.rs b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/mod.rs new file mode 100644 index 000000000..c1687111b --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/mod.rs @@ -0,0 +1,497 @@ +s! { + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_matchc: ::size_t, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + pub gl_pathv: *mut *mut ::c_char, + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct ufs_args { + pub fspec: *mut ::c_char, + pub export_info: export_args, + } + + pub struct mfs_args { + pub fspec: *mut ::c_char, + pub export_info: export_args, + // https://github.com/openbsd/src/blob/master/sys/sys/types.h#L134 + pub base: *mut ::c_char, + pub size: ::c_ulong, + } + + pub struct iso_args { + pub fspec: *mut ::c_char, + pub export_info: export_args, + pub flags: ::c_int, + pub sess: ::c_int, + } + + pub struct nfs_args { + pub version: ::c_int, + pub addr: *mut ::sockaddr, + pub addrlen: ::c_int, + pub sotype: ::c_int, + pub proto: ::c_int, + pub fh: *mut ::c_uchar, + pub fhsize: ::c_int, + pub flags: ::c_int, + pub wsize: ::c_int, + pub rsize: ::c_int, + pub readdirsize: ::c_int, + pub timeo: ::c_int, + pub retrans: ::c_int, + pub maxgrouplist: ::c_int, + pub readahead: ::c_int, + pub leaseterm: ::c_int, + pub deadthresh: ::c_int, + pub hostname: *mut ::c_char, + pub acregmin: ::c_int, + pub acregmax: ::c_int, + pub acdirmin: ::c_int, + pub acdirmax: ::c_int, + } + + pub struct msdosfs_args { + pub fspec: *mut ::c_char, + pub export_info: export_args, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub mask: ::mode_t, + pub flags: ::c_int, + } + + pub struct ntfs_args { + pub fspec: *mut ::c_char, + pub export_info: export_args, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub mode: ::mode_t, + pub flag: ::c_ulong, + } + + pub struct udf_args { + pub fspec: *mut ::c_char, + pub lastblock: ::uint32_t, + } + + pub struct tmpfs_args { + pub ta_version: ::c_int, + pub ta_nodes_max: ::ino_t, + pub ta_size_max: ::off_t, + pub ta_root_uid: ::uid_t, + pub ta_root_gid: ::gid_t, + pub ta_root_mode: ::mode_t, + } + + pub struct fusefs_args { + pub name: *mut ::c_char, + pub fd: ::c_int, + pub max_read: ::c_int, + pub allow_other: ::c_int, + } + + pub struct xucred { + pub cr_uid: ::uid_t, + pub cr_gid: ::gid_t, + pub cr_ngroups: ::c_short, + //https://github.com/openbsd/src/blob/master/sys/sys/syslimits.h#L44 + pub cr_groups: [::gid_t; 16], + } + + pub struct export_args { + pub ex_flags: ::c_int, + pub ex_root: ::uid_t, + pub ex_anon: xucred, + pub ex_addr: *mut ::sockaddr, + pub ex_addrlen: ::c_int, + pub ex_mask: *mut ::sockaddr, + pub ex_masklen: ::c_int, + } +} + +s_no_extra_traits! { + pub union mount_info { + pub ufs_args: ufs_args, + pub mfs_args: mfs_args, + pub nfs_args: nfs_args, + pub iso_args: iso_args, + pub msdosfs_args: msdosfs_args, + pub ntfs_args: ntfs_args, + pub tmpfs_args: tmpfs_args, + align: [::c_char; 160], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for mount_info { + fn eq(&self, other: &mount_info) -> bool { + unsafe { + self.align + .iter() + .zip(other.align.iter()) + .all(|(a,b)| a == b) + } + } + } + + impl Eq for mount_info { } + + impl ::fmt::Debug for mount_info { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("mount_info") + // FIXME: .field("align", &self.align) + .finish() + } + } + + impl ::hash::Hash for mount_info { + fn hash(&self, state: &mut H) { + unsafe { self.align.hash(state) }; + } + } + } +} + +cfg_if! { + if #[cfg(libc_union)] { + s_no_extra_traits! { + // This type uses the union mount_info: + pub struct statfs { + pub f_flags: ::uint32_t, + pub f_bsize: ::uint32_t, + pub f_iosize: ::uint32_t, + pub f_blocks: ::uint64_t, + pub f_bfree: ::uint64_t, + pub f_bavail: ::int64_t, + pub f_files: ::uint64_t, + pub f_ffree: ::uint64_t, + pub f_favail: ::int64_t, + pub f_syncwrites: ::uint64_t, + pub f_syncreads: ::uint64_t, + pub f_asyncwrites: ::uint64_t, + pub f_asyncreads: ::uint64_t, + pub f_fsid: ::fsid_t, + pub f_namemax: ::uint32_t, + pub f_owner: ::uid_t, + pub f_ctime: ::uint64_t, + pub f_fstypename: [::c_char; 16], + pub f_mntonname: [::c_char; 90], + pub f_mntfromname: [::c_char; 90], + pub f_mntfromspec: [::c_char; 90], + pub mount_info: mount_info, + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for statfs { + fn eq(&self, other: &statfs) -> bool { + self.f_flags == other.f_flags + && self.f_bsize == other.f_bsize + && self.f_iosize == other.f_iosize + && self.f_blocks == other.f_blocks + && self.f_bfree == other.f_bfree + && self.f_bavail == other.f_bavail + && self.f_files == other.f_files + && self.f_ffree == other.f_ffree + && self.f_favail == other.f_favail + && self.f_syncwrites == other.f_syncwrites + && self.f_syncreads == other.f_syncreads + && self.f_asyncwrites == other.f_asyncwrites + && self.f_asyncreads == other.f_asyncreads + && self.f_fsid == other.f_fsid + && self.f_namemax == other.f_namemax + && self.f_owner == other.f_owner + && self.f_ctime == other.f_ctime + && self.f_fstypename + .iter() + .zip(other.f_fstypename.iter()) + .all(|(a,b)| a == b) + && self.f_mntonname + .iter() + .zip(other.f_mntonname.iter()) + .all(|(a,b)| a == b) + && self.f_mntfromname + .iter() + .zip(other.f_mntfromname.iter()) + .all(|(a,b)| a == b) + && self.f_mntfromspec + .iter() + .zip(other.f_mntfromspec.iter()) + .all(|(a,b)| a == b) + && self.mount_info == other.mount_info + } + } + + impl Eq for statfs { } + + impl ::fmt::Debug for statfs { + fn fmt(&self, f: &mut ::fmt::Formatter) + -> ::fmt::Result { + f.debug_struct("statfs") + .field("f_flags", &self.f_flags) + .field("f_bsize", &self.f_bsize) + .field("f_iosize", &self.f_iosize) + .field("f_blocks", &self.f_blocks) + .field("f_bfree", &self.f_bfree) + .field("f_bavail", &self.f_bavail) + .field("f_files", &self.f_files) + .field("f_ffree", &self.f_ffree) + .field("f_favail", &self.f_favail) + .field("f_syncwrites", &self.f_syncwrites) + .field("f_syncreads", &self.f_syncreads) + .field("f_asyncwrites", &self.f_asyncwrites) + .field("f_asyncreads", &self.f_asyncreads) + .field("f_fsid", &self.f_fsid) + .field("f_namemax", &self.f_namemax) + .field("f_owner", &self.f_owner) + .field("f_ctime", &self.f_ctime) + // FIXME: .field("f_fstypename", &self.f_fstypename) + // FIXME: .field("f_mntonname", &self.f_mntonname) + // FIXME: .field("f_mntfromname", &self.f_mntfromname) + // FIXME: .field("f_mntfromspec", &self.f_mntfromspec) + .field("mount_info", &self.mount_info) + .finish() + } + } + + impl ::hash::Hash for statfs { + fn hash(&self, state: &mut H) { + self.f_flags.hash(state); + self.f_bsize.hash(state); + self.f_iosize.hash(state); + self.f_blocks.hash(state); + self.f_bfree.hash(state); + self.f_bavail.hash(state); + self.f_files.hash(state); + self.f_ffree.hash(state); + self.f_favail.hash(state); + self.f_syncwrites.hash(state); + self.f_syncreads.hash(state); + self.f_asyncwrites.hash(state); + self.f_asyncreads.hash(state); + self.f_fsid.hash(state); + self.f_namemax.hash(state); + self.f_owner.hash(state); + self.f_ctime.hash(state); + self.f_fstypename.hash(state); + self.f_mntonname.hash(state); + self.f_mntfromname.hash(state); + self.f_mntfromspec.hash(state); + self.mount_info.hash(state); + } + } + } + } + } +} + +//https://github.com/openbsd/src/blob/master/sys/sys/mount.h +pub const ISOFSMNT_NORRIP: ::c_int = 0x1; // disable Rock Ridge Ext +pub const ISOFSMNT_GENS: ::c_int = 0x2; // enable generation numbers +pub const ISOFSMNT_EXTATT: ::c_int = 0x4; // enable extended attr +pub const ISOFSMNT_NOJOLIET: ::c_int = 0x8; // disable Joliet Ext +pub const ISOFSMNT_SESS: ::c_int = 0x10; // use iso_args.sess + +pub const NFS_ARGSVERSION: ::c_int = 4; // change when nfs_args changes + +pub const NFSMNT_RESVPORT: ::c_int = 0; // always use reserved ports +pub const NFSMNT_SOFT: ::c_int = 0x1; // soft mount (hard is default) +pub const NFSMNT_WSIZE: ::c_int = 0x2; // set write size +pub const NFSMNT_RSIZE: ::c_int = 0x4; // set read size +pub const NFSMNT_TIMEO: ::c_int = 0x8; // set initial timeout +pub const NFSMNT_RETRANS: ::c_int = 0x10; // set number of request retries +pub const NFSMNT_MAXGRPS: ::c_int = 0x20; // set maximum grouplist size +pub const NFSMNT_INT: ::c_int = 0x40; // allow interrupts on hard mount +pub const NFSMNT_NOCONN: ::c_int = 0x80; // Don't Connect the socket +pub const NFSMNT_NQNFS: ::c_int = 0x100; // Use Nqnfs protocol +pub const NFSMNT_NFSV3: ::c_int = 0x200; // Use NFS Version 3 protocol +pub const NFSMNT_KERB: ::c_int = 0x400; // Use Kerberos authentication +pub const NFSMNT_DUMBTIMR: ::c_int = 0x800; // Don't estimate rtt dynamically +pub const NFSMNT_LEASETERM: ::c_int = 0x1000; // set lease term (nqnfs) +pub const NFSMNT_READAHEAD: ::c_int = 0x2000; // set read ahead +pub const NFSMNT_DEADTHRESH: ::c_int = 0x4000; // set dead server retry thresh +pub const NFSMNT_NOAC: ::c_int = 0x8000; // disable attribute cache +pub const NFSMNT_RDIRPLUS: ::c_int = 0x10000; // Use Readdirplus for V3 +pub const NFSMNT_READDIRSIZE: ::c_int = 0x20000; // Set readdir size + +/* Flags valid only in mount syscall arguments */ +pub const NFSMNT_ACREGMIN: ::c_int = 0x40000; // acregmin field valid +pub const NFSMNT_ACREGMAX: ::c_int = 0x80000; // acregmax field valid +pub const NFSMNT_ACDIRMIN: ::c_int = 0x100000; // acdirmin field valid +pub const NFSMNT_ACDIRMAX: ::c_int = 0x200000; // acdirmax field valid + +/* Flags valid only in kernel */ +pub const NFSMNT_INTERNAL: ::c_int = 0xfffc0000; // Bits set internally +pub const NFSMNT_HASWRITEVERF: ::c_int = 0x40000; // Has write verifier for V3 +pub const NFSMNT_GOTPATHCONF: ::c_int = 0x80000; // Got the V3 pathconf info +pub const NFSMNT_GOTFSINFO: ::c_int = 0x100000; // Got the V3 fsinfo +pub const NFSMNT_MNTD: ::c_int = 0x200000; // Mnt server for mnt point +pub const NFSMNT_DISMINPROG: ::c_int = 0x400000; // Dismount in progress +pub const NFSMNT_DISMNT: ::c_int = 0x800000; // Dismounted +pub const NFSMNT_SNDLOCK: ::c_int = 0x1000000; // Send socket lock +pub const NFSMNT_WANTSND: ::c_int = 0x2000000; // Want above +pub const NFSMNT_RCVLOCK: ::c_int = 0x4000000; // Rcv socket lock +pub const NFSMNT_WANTRCV: ::c_int = 0x8000000; // Want above +pub const NFSMNT_WAITAUTH: ::c_int = 0x10000000; // Wait for authentication +pub const NFSMNT_HASAUTH: ::c_int = 0x20000000; // Has authenticator +pub const NFSMNT_WANTAUTH: ::c_int = 0x40000000; // Wants an authenticator +pub const NFSMNT_AUTHERR: ::c_int = 0x80000000; // Authentication error + +pub const MSDOSFSMNT_SHORTNAME: ::c_int = 0x1; // Force old DOS short names only +pub const MSDOSFSMNT_LONGNAME: ::c_int = 0x2; // Force Win'95 long names +pub const MSDOSFSMNT_NOWIN95: ::c_int = 0x4; // Completely ignore Win95 entries + +pub const NTFS_MFLAG_CASEINS: ::c_int = 0x1; +pub const NTFS_MFLAG_ALLNAMES: ::c_int = 0x2; + +pub const TMPFS_ARGS_VERSION: ::c_int = 1; + +pub const MAP_STACK : ::c_int = 0x4000; + +// https://github.com/openbsd/src/blob/master/sys/net/if.h#L187 +pub const IFF_UP: ::c_int = 0x1; // interface is up +pub const IFF_BROADCAST: ::c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x10; // interface is point-to-point link +pub const IFF_STATICARP: ::c_int = 0x20; // only static ARP +pub const IFF_RUNNING: ::c_int = 0x40; // resources allocated +pub const IFF_NOARP: ::c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE: ::c_int = 0x400; // transmission in progress +pub const IFF_SIMPLEX: ::c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000; // per link layer defined bit +pub const IFF_MULTICAST: ::c_int = 0x8000; // supports multicast + +pub const PTHREAD_STACK_MIN : ::size_t = 4096; +pub const SIGSTKSZ : ::size_t = 28672; + +pub const PT_FIRSTMACH: ::c_int = 32; + +fn _ALIGN(p: usize) -> usize { + (p + _ALIGNBYTES) & !_ALIGNBYTES +} + +f! { + pub fn CMSG_DATA(cmsg: *const ::cmsghdr) -> *mut ::c_uchar { + (cmsg as *mut ::c_uchar) + .offset(_ALIGN(::mem::size_of::<::cmsghdr>()) as isize) + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + _ALIGN(::mem::size_of::<::cmsghdr>()) as ::c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const ::msghdr, cmsg: *const ::cmsghdr) + -> *mut ::cmsghdr + { + if cmsg.is_null() { + return ::CMSG_FIRSTHDR(mhdr); + }; + let next = cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize) + + _ALIGN(::mem::size_of::<::cmsghdr>()); + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if next > max { + 0 as *mut ::cmsghdr + } else { + (cmsg as usize + _ALIGN((*cmsg).cmsg_len as usize)) + as *mut ::cmsghdr + } + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (_ALIGN(::mem::size_of::<::cmsghdr>()) + _ALIGN(length as usize)) + as ::c_uint + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + status >> 8 + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + (status & 0o177) != 0o177 && (status & 0o177) != 0 + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0o177) == 0o177 + } +} + +extern { + pub fn accept4(s: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t, flags: ::c_int) -> ::c_int; + pub fn execvpe(file: *const ::c_char, argv: *const *const ::c_char, + envp: *const *const ::c_char) -> ::c_int; + pub fn pledge(promises: *const ::c_char, + execpromises: *const ::c_char) -> ::c_int; + pub fn strtonum(nptr: *const ::c_char, minval: ::c_longlong, + maxval: ::c_longlong, + errstr: *mut *const ::c_char) -> ::c_longlong; + pub fn dup3(src: ::c_int, dst: ::c_int, flags: ::c_int) -> ::c_int; +} + +cfg_if! { + if #[cfg(libc_union)] { + extern { + // these functions use statfs which uses the union mount_info: + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + } + } +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86.rs b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86.rs new file mode 100644 index 000000000..05538cd0a --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86.rs @@ -0,0 +1,14 @@ +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_char = i8; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_int>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 4 - 1; + } +} diff --git a/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86_64.rs b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86_64.rs new file mode 100644 index 000000000..7daa9d836 --- /dev/null +++ b/libc/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86_64.rs @@ -0,0 +1,22 @@ +use PT_FIRSTMACH; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = i8; + +// should be pub(crate), but that requires Rust 1.18.0 +cfg_if! { + if #[cfg(libc_const_size_of)] { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = ::mem::size_of::<::c_long>() - 1; + } else { + #[doc(hidden)] + pub const _ALIGNBYTES: usize = 8 - 1; + } +} + +pub const PT_STEP: ::c_int = PT_FIRSTMACH + 0; +pub const PT_GETREGS: ::c_int = PT_FIRSTMACH + 1; +pub const PT_SETREGS: ::c_int = PT_FIRSTMACH + 2; +pub const PT_GETFPREGS: ::c_int = PT_FIRSTMACH + 3; +pub const PT_SETFPREGS: ::c_int = PT_FIRSTMACH + 4; diff --git a/libc/src/unix/haiku/b32.rs b/libc/src/unix/haiku/b32.rs new file mode 100644 index 000000000..cce886488 --- /dev/null +++ b/libc/src/unix/haiku/b32.rs @@ -0,0 +1,3 @@ +pub type c_long = i32; +pub type c_ulong = u32; +pub type time_t = i32; diff --git a/libc/src/unix/haiku/b64.rs b/libc/src/unix/haiku/b64.rs new file mode 100644 index 000000000..3e66f14c9 --- /dev/null +++ b/libc/src/unix/haiku/b64.rs @@ -0,0 +1,3 @@ +pub type c_ulong = u64; +pub type c_long = i64; +pub type time_t = i64; diff --git a/libc/src/unix/haiku/mod.rs b/libc/src/unix/haiku/mod.rs new file mode 100644 index 000000000..26519a477 --- /dev/null +++ b/libc/src/unix/haiku/mod.rs @@ -0,0 +1,1384 @@ +pub type rlim_t = ::uintptr_t; +pub type sa_family_t = u8; +pub type pthread_key_t = ::c_int; +pub type nfds_t = ::c_long; +pub type tcflag_t = ::c_uint; +pub type speed_t = ::c_uint; +pub type c_char = i8; +pub type clock_t = i32; +pub type clockid_t = i32; +pub type suseconds_t = i32; +pub type wchar_t = i32; +pub type off_t = i64; +pub type ino_t = i64; +pub type blkcnt_t = i64; +pub type blksize_t = i32; +pub type dev_t = i32; +pub type mode_t = u32; +pub type nlink_t = i32; +pub type useconds_t = u32; +pub type socklen_t = u32; +pub type pthread_t = ::uintptr_t; +pub type pthread_mutexattr_t = ::uintptr_t; +pub type pthread_rwlockattr_t = ::uintptr_t; +pub type sigset_t = u64; +pub type fsblkcnt_t = i64; +pub type fsfilcnt_t = i64; +pub type pthread_attr_t = *mut ::c_void; +pub type nl_item = ::c_int; +pub type id_t = i32; +pub type idtype_t = ::c_uint; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 30], + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 24], + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct fd_set { + fds_bits: [c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *const ::c_char, + } + + pub struct utsname { + pub sysname: [::c_char; 32], + pub nodename: [::c_char; 32], + pub release: [::c_char; 32], + pub version: [::c_char; 32], + pub machine: [::c_char; 32], + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::c_char, + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_size: off_t, + pub st_rdev: dev_t, + pub st_blksize: blksize_t, + pub st_atime: time_t, + pub st_atime_nsec: c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: c_long, + pub st_crtime: time_t, + pub st_crtime_nsec: c_long, + pub st_type: u32, + pub st_blocks: blkcnt_t, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + __unused1: ::size_t, + pub gl_offs: ::size_t, + __unused2: ::size_t, + pub gl_pathv: *mut *mut c_char, + + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + __unused8: *mut ::c_void, + } + + pub struct pthread_mutex_t { + flags: u32, + lock: i32, + unused: i32, + owner: i32, + owner_count: i32, + } + + pub struct pthread_cond_t { + flags: u32, + unused: i32, + mutex: *mut ::c_void, + waiter_count: i32, + lock: i32, + } + + pub struct pthread_rwlock_t { + flags: u32, + owner: i32, + lock_sem: i32, // this is actually a union + lock_count: i32, + reader_count: i32, + writer_count: i32, + waiters: [*mut ::c_void; 2], + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + pub pw_gecos: *mut ::c_char, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub si_pid: ::pid_t, + pub si_uid: ::uid_t, + pub si_addr: *mut ::c_void, + pub si_status: ::c_int, + pub si_band: c_long, + pub sigval: *mut ::c_void, + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_int, + sa_userdata: *mut ::c_void, + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + __unused1: *mut ::c_void, // actually a function pointer + pub sigev_notify_attributes: *mut ::pthread_attr_t, + } + + pub struct sem_t { + pub se_type: i32, + pub se_named_id: i32, // this is actually a union + pub se_unnamed: i32, + pub se_padding: [i32; 4], + } + + pub struct pthread_condattr_t { + pub process_shared: bool, + pub clock_id: i32, + } +} + +s_no_extra_traits! { + pub struct sockaddr_un { + pub sun_len: u8, + pub sun_family: sa_family_t, + pub sun_path: [::c_char; 126] + } + pub struct sockaddr_storage { + pub ss_len: u8, + pub ss_family: sa_family_t, + __ss_pad1: [u8; 6], + __ss_pad2: u64, + __ss_pad3: [u8; 112], + } + pub struct dirent { + pub d_dev: dev_t, + pub d_pdev: dev_t, + pub d_ino: ino_t, + pub d_pino: i64, + pub d_reclen: ::c_ushort, + pub d_name: [::c_char; 1024], // Max length is _POSIX_PATH_MAX + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_len == other.sun_len + && self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_un {} + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_len", &self.sun_len) + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_len.hash(state); + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_len == other.ss_len + && self.ss_family == other.ss_family + && self + .__ss_pad1 + .iter() + .zip(other.__ss_pad1.iter()) + .all(|(a, b)| a == b) + && self.__ss_pad2 == other.__ss_pad2 + && self + .__ss_pad3 + .iter() + .zip(other.__ss_pad3.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_len", &self.ss_len) + .field("ss_family", &self.ss_family) + .field("__ss_pad1", &self.__ss_pad1) + .field("__ss_pad2", &self.__ss_pad2) + // FIXME: .field("__ss_pad3", &self.__ss_pad3) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_len.hash(state); + self.ss_family.hash(state); + self.__ss_pad1.hash(state); + self.__ss_pad2.hash(state); + self.__ss_pad3.hash(state); + } + } + + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_dev == other.d_dev + && self.d_pdev == other.d_pdev + && self.d_ino == other.d_ino + && self.d_pino == other.d_pino + && self.d_reclen == other.d_reclen + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_dev", &self.d_dev) + .field("d_pdev", &self.d_pdev) + .field("d_ino", &self.d_ino) + .field("d_pino", &self.d_pino) + .field("d_reclen", &self.d_reclen) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_dev.hash(state); + self.d_pdev.hash(state); + self.d_ino.hash(state); + self.d_pino.hash(state); + self.d_reclen.hash(state); + self.d_name.hash(state); + } + } + } +} + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 2147483647; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; + +pub const F_DUPFD: ::c_int = 0x0001; +pub const F_GETFD: ::c_int = 0x0002; +pub const F_SETFD: ::c_int = 0x0004; +pub const F_GETFL: ::c_int = 0x0008; +pub const F_SETFL: ::c_int = 0x0010; +pub const F_GETLK: ::c_int = 0x0020; +pub const F_SETLK: ::c_int = 0x0080; +pub const F_SETLKW: ::c_int = 0x0100; +pub const F_DUPFD_CLOEXEC: ::c_int = 0x0200; + +pub const F_RDLCK: ::c_int = 0x0040; +pub const F_UNLCK: ::c_int = 0x0200; +pub const F_WRLCK: ::c_int = 0x0400; + +pub const AT_FDCWD: ::c_int = -1; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x01; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x02; +pub const AT_REMOVEDIR: ::c_int = 0x04; +pub const AT_EACCESS: ::c_int = 0x08; + +pub const POLLIN: ::c_short = 0x0001; +pub const POLLOUT: ::c_short = 0x0002; +pub const POLLRDNORM: ::c_short = POLLIN; +pub const POLLWRNORM: ::c_short = POLLOUT; +pub const POLLRDBAND: ::c_short = 0x0008; +pub const POLLWRBAND: ::c_short = 0x0010; +pub const POLLPRI: ::c_short = 0x0020; +pub const POLLERR: ::c_short = 0x0004; +pub const POLLHUP: ::c_short = 0x0080; +pub const POLLNVAL: ::c_short = 0x1000; + +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 1; + +pub const CLOCK_REALTIME: ::c_int = -1; +pub const CLOCK_MONOTONIC: ::c_int = 0; + +pub const RLIMIT_CORE: ::c_int = 0; +pub const RLIMIT_CPU: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_FSIZE: ::c_int = 3; +pub const RLIMIT_NOFILE: ::c_int = 4; +pub const RLIMIT_STACK: ::c_int = 5; +pub const RLIMIT_AS: ::c_int = 6; +// Haiku specific +pub const RLIMIT_NOVMON: ::c_int = 7; +pub const RLIMIT_NLIMITS: ::c_int = 8; + +pub const RUSAGE_SELF: ::c_int = 0; + +pub const RTLD_LAZY: ::c_int = 0; + +pub const NCCS: usize = 11; + +pub const O_RDONLY: ::c_int = 0x0000; +pub const O_WRONLY: ::c_int = 0x0001; +pub const O_RDWR: ::c_int = 0x0002; +pub const O_ACCMODE: ::c_int = 0x0003; + +pub const O_EXCL: ::c_int = 0x0100; +pub const O_CREAT: ::c_int = 0x0200; +pub const O_TRUNC: ::c_int = 0x0400; +pub const O_NOCTTY: ::c_int = 0x1000; +pub const O_NOTRAVERSE: ::c_int = 0x2000; + +pub const O_CLOEXEC: ::c_int = 0x00000040; +pub const O_NONBLOCK: ::c_int = 0x00000080; +pub const O_APPEND: ::c_int = 0x00000800; +pub const O_SYNC: ::c_int = 0x00010000; +pub const O_RSYNC: ::c_int = 0x00020000; +pub const O_DSYNC: ::c_int = 0x00040000; +pub const O_NOFOLLOW: ::c_int = 0x00080000; +pub const O_NOCACHE: ::c_int = 0x00100000; +pub const O_DIRECTORY: ::c_int = 0x00200000; + +pub const S_IFIFO: ::mode_t = 61440; +pub const S_IFCHR: ::mode_t = 49152; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IRWXU: ::mode_t = 448; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IRWXG: ::mode_t = 70; +pub const S_IXGRP: ::mode_t = 10; +pub const S_IWGRP: ::mode_t = 20; +pub const S_IRGRP: ::mode_t = 40; +pub const S_IRWXO: ::mode_t = 7; +pub const S_IXOTH: ::mode_t = 1; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IROTH: ::mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGCHLD: ::c_int = 5; +pub const SIGABRT: ::c_int = 6; +pub const SIGPIPE: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSTOP: ::c_int = 10; +pub const SIGSEGV: ::c_int = 11; +pub const SIGCONT: ::c_int = 12; +pub const SIGTSTP: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; +pub const SIGTTIN: ::c_int = 16; +pub const SIGTTOU: ::c_int = 17; +pub const SIGUSR1: ::c_int = 18; +pub const SIGUSR2: ::c_int = 19; +pub const SIGWINCH: ::c_int = 20; +pub const SIGKILLTHR: ::c_int = 21; +pub const SIGTRAP: ::c_int = 22; +pub const SIGPOLL: ::c_int = 23; +pub const SIGPROF: ::c_int = 24; +pub const SIGSYS: ::c_int = 25; +pub const SIGURG: ::c_int = 26; +pub const SIGVTALRM: ::c_int = 27; +pub const SIGXCPU: ::c_int = 28; +pub const SIGXFSZ: ::c_int = 29; +pub const SIGBUS: ::c_int = 30; + +pub const SIG_BLOCK: ::c_int = 1; +pub const SIG_UNBLOCK: ::c_int = 2; +pub const SIG_SETMASK: ::c_int = 3; + +pub const SIGEV_NONE: ::c_int = 0; +pub const SIGEV_SIGNAL: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NODATA: ::c_int = 7; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 14; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const LC_ALL: ::c_int = 0; +pub const LC_COLLATE: ::c_int = 1; +pub const LC_CTYPE: ::c_int = 2; +pub const LC_MONETARY: ::c_int = 3; +pub const LC_NUMERIC: ::c_int = 4; +pub const LC_TIME: ::c_int = 5; +pub const LC_MESSAGES: ::c_int = 6; + +// TODO: Haiku does not have MAP_FILE, but libstd/os.rs requires it +pub const MAP_FILE: ::c_int = 0x00; +pub const MAP_SHARED: ::c_int = 0x01; +pub const MAP_PRIVATE: ::c_int = 0x02; +pub const MAP_FIXED: ::c_int = 0x04; +pub const MAP_ANONYMOUS: ::c_int = 0x08; +pub const MAP_ANON: ::c_int = MAP_ANONYMOUS; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +pub const MS_ASYNC: ::c_int = 0x01; +pub const MS_INVALIDATE: ::c_int = 0x04; +pub const MS_SYNC: ::c_int = 0x02; + +pub const E2BIG : ::c_int = -2147454975; +pub const ECHILD : ::c_int = -2147454974; +pub const EDEADLK : ::c_int = -2147454973; +pub const EFBIG : ::c_int = -2147454972; +pub const EMLINK : ::c_int = -2147454971; +pub const ENFILE : ::c_int = -2147454970; +pub const ENODEV : ::c_int = -2147454969; +pub const ENOLCK : ::c_int = -2147454968; +pub const ENOSYS : ::c_int = -2147454967; +pub const ENOTTY : ::c_int = -2147454966; +pub const ENXIO : ::c_int = -2147454965; +pub const ESPIPE : ::c_int = -2147454964; +pub const ESRCH : ::c_int = -2147454963; +pub const EFPOS : ::c_int = -2147457962; +pub const ESIGPARM : ::c_int = -2147457961; +pub const EDOM : ::c_int = -2147454960; +pub const ERANGE : ::c_int = -2147454959; +pub const EPROTOTYPE : ::c_int = -2147454958; +pub const EPROTONOSUPPORT : ::c_int = -2147454957; +pub const EPFNOSUPPORT : ::c_int = -2147454956; +pub const EAFNOSUPPORT : ::c_int = -2147454955; +pub const EADDRINUSE : ::c_int = -2147454954; +pub const EADDRNOTAVAIL : ::c_int = -2147454953; +pub const ENETDOWN : ::c_int = -2147454952; +pub const ENETUNREACH : ::c_int = -2147454951; +pub const ENETRESET : ::c_int = -2147454950; +pub const ECONNABORTED : ::c_int = -2147454949; +pub const ECONNRESET : ::c_int = -2147454948; +pub const EISCONN : ::c_int = -2147454947; +pub const ENOTCONN : ::c_int = -2147454946; +pub const ESHUTDOWN : ::c_int = -2147454945; +pub const ECONNREFUSED : ::c_int = -2147454944; +pub const EHOSTUNREACH : ::c_int = -2147454943; +pub const ENOPROTOOPT : ::c_int = -2147454942; +pub const ENOBUFS : ::c_int = -2147454941; +pub const EINPROGRESS : ::c_int = -2147454940; +pub const EALREADY : ::c_int = -2147454939; +pub const EILSEQ : ::c_int = -2147454938; +pub const ENOMSG : ::c_int = -2147454937; +pub const ESTALE : ::c_int = -2147454936; +pub const EOVERFLOW : ::c_int = -2147454935; +pub const EMSGSIZE : ::c_int = -2147454934; +pub const EOPNOTSUPP : ::c_int = -2147454933; +pub const ENOTSOCK : ::c_int = -2147454932; +pub const EHOSTDOWN : ::c_int = -2147454931; +pub const EBADMSG : ::c_int = -2147454930; +pub const ECANCELED : ::c_int = -2147454929; +pub const EDESTADDRREQ : ::c_int = -2147454928; +pub const EDQUOT : ::c_int = -2147454927; +pub const EIDRM : ::c_int = -2147454926; +pub const EMULTIHOP : ::c_int = -2147454925; +pub const ENODATA : ::c_int = -2147454924; +pub const ENOLINK : ::c_int = -2147454923; +pub const ENOSR : ::c_int = -2147454922; +pub const ENOSTR : ::c_int = -2147454921; +pub const ENOTSUP : ::c_int = -2147454920; +pub const EPROTO : ::c_int = -2147454919; +pub const ETIME : ::c_int = -2147454918; +pub const ETXTBSY : ::c_int = -2147454917; +pub const ENOATTR : ::c_int = -2147454916; + +// INT_MIN +pub const ENOMEM : ::c_int = -2147454976; + +// POSIX errors that can be mapped to BeOS error codes +pub const EACCES : ::c_int = -2147483646; +pub const EINTR : ::c_int = -2147483638; +pub const EIO : ::c_int = -2147483647; +pub const EBUSY : ::c_int = -2147483634; +pub const EFAULT : ::c_int = -2147478783; +pub const ETIMEDOUT : ::c_int = -2147483639; +pub const EAGAIN : ::c_int = -2147483637; +pub const EWOULDBLOCK : ::c_int = -2147483637; +pub const EBADF : ::c_int = -2147459072; +pub const EEXIST : ::c_int = -2147459070; +pub const EINVAL : ::c_int = -2147483643; +pub const ENAMETOOLONG : ::c_int = -2147459068; +pub const ENOENT : ::c_int = -2147459069; +pub const EPERM : ::c_int = -2147483633; +pub const ENOTDIR : ::c_int = -2147459067; +pub const EISDIR : ::c_int = -2147459063; +pub const ENOTEMPTY : ::c_int = -2147459066; +pub const ENOSPC : ::c_int = -2147459065; +pub const EROFS : ::c_int = -2147459064; +pub const EMFILE : ::c_int = -2147459062; +pub const EXDEV : ::c_int = -2147459061; +pub const ELOOP : ::c_int = -2147459060; +pub const ENOEXEC : ::c_int = -2147478782; +pub const EPIPE : ::c_int = -2147459059; + +pub const IPPROTO_RAW: ::c_int = 255; + +// These are prefixed with POSIX_ on Haiku +pub const MADV_NORMAL: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_RANDOM: ::c_int = 3; +pub const MADV_WILLNEED: ::c_int = 4; +pub const MADV_DONTNEED: ::c_int = 5; + +// https://github.com/haiku/haiku/blob/master/headers/posix/net/if.h#L80 +pub const IFF_UP: ::c_int = 0x0001; +pub const IFF_BROADCAST: ::c_int = 0x0002; // valid broadcast address +pub const IFF_LOOPBACK: ::c_int = 0x0008; +pub const IFF_POINTOPOINT: ::c_int = 0x0010; // point-to-point link +pub const IFF_NOARP: ::c_int = 0x0040; // no address resolution +pub const IFF_AUTOUP: ::c_int = 0x0080; // auto dial +pub const IFF_PROMISC: ::c_int = 0x0100; // receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x0200; // receive all multicast packets +pub const IFF_SIMPLEX: ::c_int = 0x0800; // doesn't receive own transmissions +pub const IFF_LINK: ::c_int = 0x1000; // has link +pub const IFF_AUTO_CONFIGURED: ::c_int = 0x2000; +pub const IFF_CONFIGURING: ::c_int = 0x4000; +pub const IFF_MULTICAST: ::c_int = 0x8000; // supports multicast + +pub const AF_UNSEC: ::c_int = 0; +pub const AF_INET: ::c_int = 1; +pub const AF_APPLETALK: ::c_int = 2; +pub const AF_ROUTE: ::c_int = 3; +pub const AF_LINK: ::c_int = 4; +pub const AF_INET6: ::c_int = 5; +pub const AF_DLI: ::c_int = 6; +pub const AF_IPX: ::c_int = 7; +pub const AF_NOTIFY: ::c_int = 8; +pub const AF_LOCAL: ::c_int = 9; +pub const AF_UNIX: ::c_int = AF_LOCAL; +pub const AF_BLUETOOTH: ::c_int = 10; +pub const AF_MAX: ::c_int = 11; + +pub const IP_OPTIONS: ::c_int = 1; +pub const IP_HDRINCL: ::c_int = 2; +pub const IP_TOS: ::c_int = 3; +pub const IP_TTL: ::c_int = 4; +pub const IP_RECVOPTS: ::c_int = 5; +pub const IP_RECVRETOPTS: ::c_int = 6; +pub const IP_RECVDSTADDR: ::c_int = 7; +pub const IP_RETOPTS: ::c_int = 8; +pub const IP_MULTICAST_IF: ::c_int = 9; +pub const IP_MULTICAST_TTL: ::c_int = 10; +pub const IP_MULTICAST_LOOP: ::c_int = 11; +pub const IP_ADD_MEMBERSHIP: ::c_int = 12; +pub const IP_DROP_MEMBERSHIP: ::c_int = 13; +pub const IP_BLOCK_SOURCE: ::c_int = 14; +pub const IP_UNBLOCK_SOURCE: ::c_int = 15; +pub const IP_ADD_SOURCE_MEMBERSHIP: ::c_int = 16; +pub const IP_DROP_SOURCE_MEMBERSHIP: ::c_int = 17; + +pub const TCP_NODELAY: ::c_int = 0x01; +pub const TCP_MAXSEG: ::c_int = 0x02; +pub const TCP_NOPUSH: ::c_int = 0x04; +pub const TCP_NOOPT: ::c_int = 0x08; + +pub const IPV6_MULTICAST_IF: ::c_int = 24; +pub const IPV6_MULTICAST_HOPS: ::c_int = 25; +pub const IPV6_MULTICAST_LOOP: ::c_int = 26; +pub const IPV6_UNICAST_HOPS: ::c_int = 27; +pub const IPV6_JOIN_GROUP: ::c_int = 28; +pub const IPV6_LEAVE_GROUP: ::c_int = 29; +pub const IPV6_V6ONLY: ::c_int = 30; +pub const IPV6_PKTINFO: ::c_int = 31; +pub const IPV6_RECVPKTINFO: ::c_int = 32; +pub const IPV6_HOPLIMIT: ::c_int = 33; +pub const IPV6_REVCHOPLIMIT: ::c_int = 34; +pub const IPV6_HOPOPTS: ::c_int = 35; +pub const IPV6_DSTOPTS: ::c_int = 36; +pub const IPV6_RTHDR: ::c_int = 37; + +pub const MSG_OOB: ::c_int = 0x0001; +pub const MSG_PEEK: ::c_int = 0x0002; +pub const MSG_DONTROUTE: ::c_int = 0x0004; +pub const MSG_EOR: ::c_int = 0x0008; +pub const MSG_TRUNC: ::c_int = 0x0010; +pub const MSG_CTRUNC: ::c_int = 0x0020; +pub const MSG_WAITALL: ::c_int = 0x0040; +pub const MSG_DONTWAIT: ::c_int = 0x0080; +pub const MSG_BCAST: ::c_int = 0x0100; +pub const MSG_MCAST: ::c_int = 0x0200; +pub const MSG_EOF: ::c_int = 0x0400; +pub const MSG_NOSIGNAL: ::c_int = 0x0800; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 0x01; +pub const LOCK_EX: ::c_int = 0x02; +pub const LOCK_NB: ::c_int = 0x04; +pub const LOCK_UN: ::c_int = 0x08; + +pub const SIGSTKSZ: ::size_t = 16384; + +pub const PATH_MAX: ::c_int = 1024; + +pub const SA_NOCLDSTOP: ::c_int = 0x01; +pub const SA_NOCLDWAIT: ::c_int = 0x02; +pub const SA_RESETHAND: ::c_int = 0x04; +pub const SA_NODEFER: ::c_int = 0x08; +pub const SA_RESTART: ::c_int = 0x10; +pub const SA_ONSTACK: ::c_int = 0x20; +pub const SA_SIGINFO: ::c_int = 0x40; +pub const SA_NOMASK: ::c_int = SA_NODEFER; +pub const SA_STACK: ::c_int = SA_ONSTACK; +pub const SA_ONESHOT: ::c_int = SA_RESETHAND; + +pub const FD_SETSIZE: usize = 1024; + +pub const RTLD_LOCAL: ::c_int = 0x0; +pub const RTLD_NOW: ::c_int = 0x1; +pub const RTLD_GLOBAL: ::c_int = 0x2; +pub const RTLD_DEFAULT: *mut ::c_void = 0isize as *mut ::c_void; + +pub const BUFSIZ: ::c_uint = 8192; +pub const FILENAME_MAX: ::c_uint = 256; +pub const FOPEN_MAX: ::c_uint = 128; +pub const L_tmpnam: ::c_uint = 512; +pub const TMP_MAX: ::c_uint = 32768; + +pub const _PC_CHOWN_RESTRICTED: ::c_int = 1; +pub const _PC_MAX_CANON: ::c_int = 2; +pub const _PC_MAX_INPUT: ::c_int = 3; +pub const _PC_NAME_MAX: ::c_int = 4; +pub const _PC_NO_TRUNC: ::c_int = 5; +pub const _PC_PATH_MAX: ::c_int = 6; +pub const _PC_PIPE_BUF: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; +pub const _PC_LINK_MAX: ::c_int = 25; +pub const _PC_SYNC_IO: ::c_int = 26; +pub const _PC_ASYNC_IO: ::c_int = 27; +pub const _PC_PRIO_IO: ::c_int = 28; +pub const _PC_SOCK_MAXBUF: ::c_int = 29; +pub const _PC_FILESIZEBITS: ::c_int = 30; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 31; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 32; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 33; +pub const _PC_REC_XFER_ALIGN: ::c_int = 34; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 35; +pub const _PC_SYMLINK_MAX: ::c_int = 36; +pub const _PC_2_SYMLINKS: ::c_int = 37; +pub const _PC_XATTR_EXISTS: ::c_int = 38; +pub const _PC_XATTR_ENABLED: ::c_int = 39; + +pub const FIONBIO: ::c_int = 0xbe000000; + +pub const _SC_ARG_MAX : ::c_int = 15; +pub const _SC_CHILD_MAX : ::c_int = 16; +pub const _SC_CLK_TCK : ::c_int = 17; +pub const _SC_JOB_CONTROL : ::c_int = 18; +pub const _SC_NGROUPS_MAX : ::c_int = 19; +pub const _SC_OPEN_MAX : ::c_int = 20; +pub const _SC_SAVED_IDS : ::c_int = 21; +pub const _SC_STREAM_MAX : ::c_int = 22; +pub const _SC_TZNAME_MAX : ::c_int = 23; +pub const _SC_VERSION : ::c_int = 24; +pub const _SC_GETGR_R_SIZE_MAX : ::c_int = 25; +pub const _SC_GETPW_R_SIZE_MAX : ::c_int = 26; +pub const _SC_PAGESIZE : ::c_int = 27; +pub const _SC_PAGE_SIZE : ::c_int = 27; +pub const _SC_SEM_NSEMS_MAX : ::c_int = 28; +pub const _SC_SEM_VALUE_MAX : ::c_int = 29; +pub const _SC_SEMAPHORES : ::c_int = 30; +pub const _SC_THREADS : ::c_int = 31; +pub const _SC_IOV_MAX : ::c_int = 32; +pub const _SC_UIO_MAXIOV : ::c_int = 32; +pub const _SC_NPROCESSORS_CONF : ::c_int = 34; +pub const _SC_NPROCESSORS_ONLN : ::c_int = 35; +pub const _SC_ATEXIT_MAX : ::c_int = 37; +pub const _SC_PASS_MAX : ::c_int = 39; +pub const _SC_PHYS_PAGES : ::c_int = 40; +pub const _SC_AVPHYS_PAGES : ::c_int = 41; +pub const _SC_PIPE : ::c_int = 42; +pub const _SC_SELECT : ::c_int = 43; +pub const _SC_POLL : ::c_int = 44; +pub const _SC_MAPPED_FILES : ::c_int = 45; +pub const _SC_THREAD_PROCESS_SHARED : ::c_int = 46; +pub const _SC_THREAD_STACK_MIN : ::c_int = 47; +pub const _SC_THREAD_ATTR_STACKADDR : ::c_int = 48; +pub const _SC_THREAD_ATTR_STACKSIZE : ::c_int = 49; +pub const _SC_THREAD_PRIORITY_SCHEDULING : ::c_int = 50; +pub const _SC_REALTIME_SIGNALS : ::c_int = 51; +pub const _SC_MEMORY_PROTECTION : ::c_int = 52; +pub const _SC_SIGQUEUE_MAX : ::c_int = 53; +pub const _SC_RTSIG_MAX : ::c_int = 54; +pub const _SC_MONOTONIC_CLOCK : ::c_int = 55; +pub const _SC_DELAYTIMER_MAX : ::c_int = 56; +pub const _SC_TIMER_MAX : ::c_int = 57; +pub const _SC_TIMERS : ::c_int = 58; +pub const _SC_CPUTIME : ::c_int = 59; +pub const _SC_THREAD_CPUTIME : ::c_int = 60; + +pub const PTHREAD_STACK_MIN: ::size_t = 8192; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + flags: 0, + lock: 0, + unused: -42, + owner: -1, + owner_count: 0, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + flags: 0, + unused: -42, + mutex: 0 as *mut _, + waiter_count: 0, + lock: 0, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + flags: 0, + owner: -1, + lock_sem: 0, + lock_count: 0, + reader_count: 0, + writer_count: 0, + waiters: [0 as *mut _; 2], +}; + +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = 0; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 3; + +pub const FIOCLEX: c_ulong = 0; // TODO: does not exist on Haiku! + +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = -1; +pub const SO_ACCEPTCONN: ::c_int = 0x00000001; +pub const SO_BROADCAST: ::c_int = 0x00000002; +pub const SO_DEBUG: ::c_int = 0x00000004; +pub const SO_DONTROUTE: ::c_int = 0x00000008; +pub const SO_KEEPALIVE: ::c_int = 0x00000010; +pub const SO_OOBINLINE: ::c_int = 0x00000020; +pub const SO_REUSEADDR: ::c_int = 0x00000040; +pub const SO_REUSEPORT: ::c_int = 0x00000080; +pub const SO_USELOOPBACK: ::c_int = 0x00000100; +pub const SO_LINGER: ::c_int = 0x00000200; +pub const SO_SNDBUF: ::c_int = 0x40000001; +pub const SO_SNDLOWAT: ::c_int = 0x40000002; +pub const SO_SNDTIMEO: ::c_int = 0x40000003; +pub const SO_RCVBUF: ::c_int = 0x40000004; +pub const SO_RCVLOWAT: ::c_int = 0x40000005; +pub const SO_RCVTIMEO: ::c_int = 0x40000006; +pub const SO_ERROR: ::c_int = 0x40000007; +pub const SO_TYPE: ::c_int = 0x40000008; +pub const SO_NONBLOCK: ::c_int = 0x40000009; +pub const SO_BINDTODEVICE: ::c_int = 0x4000000a; +pub const SO_PEERCRED: ::c_int = 0x4000000b; + +pub const SCM_RIGHTS: ::c_int = 0x01; + +pub const NI_MAXHOST: ::size_t = 1025; + +pub const WNOHANG: ::c_int = 0x01; +pub const WUNTRACED: ::c_int = 0x02; +pub const WCONTINUED: ::c_int = 0x04; +pub const WEXITED: ::c_int = 0x08; +pub const WSTOPPED: ::c_int = 0x10; +pub const WNOWAIT: ::c_int = 0x20; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VEOL: usize = 5; +pub const VMIN: usize = 4; +pub const VTIME: usize = 5; +pub const VEOL2: usize = 6; +pub const VSWTCH: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; + +pub const IGNBRK: ::tcflag_t = 0x01; +pub const BRKINT: ::tcflag_t = 0x02; +pub const IGNPAR: ::tcflag_t = 0x04; +pub const PARMRK: ::tcflag_t = 0x08; +pub const INPCK: ::tcflag_t = 0x10; +pub const ISTRIP: ::tcflag_t = 0x20; +pub const INLCR: ::tcflag_t = 0x40; +pub const IGNCR: ::tcflag_t = 0x80; +pub const ICRNL: ::tcflag_t = 0x100; +pub const IUCLC: ::tcflag_t = 0x200; +pub const IXON: ::tcflag_t = 0x400; +pub const IXANY: ::tcflag_t = 0x800; +pub const IXOFF: ::tcflag_t = 0x1000; + +pub const OPOST: ::tcflag_t = 0x00000001; +pub const OLCUC: ::tcflag_t = 0x00000002; +pub const ONLCR: ::tcflag_t = 0x00000004; +pub const OCRNL: ::tcflag_t = 0x00000008; +pub const ONOCR: ::tcflag_t = 0x00000010; +pub const ONLRET: ::tcflag_t = 0x00000020; +pub const OFILL: ::tcflag_t = 0x00000040; +pub const OFDEL: ::tcflag_t = 0x00000080; +pub const NLDLY: ::tcflag_t = 0x00000100; +pub const NL0: ::tcflag_t = 0x00000000; +pub const NL1: ::tcflag_t = 0x00000100; +pub const CRDLY: ::tcflag_t = 0x00000600; +pub const CR0: ::tcflag_t = 0x00000000; +pub const CR1: ::tcflag_t = 0x00000200; +pub const CR2: ::tcflag_t = 0x00000400; +pub const CR3: ::tcflag_t = 0x00000600; +pub const TABDLY: ::tcflag_t = 0x00001800; +pub const TAB0: ::tcflag_t = 0x00000000; +pub const TAB1: ::tcflag_t = 0x00000800; +pub const TAB2: ::tcflag_t = 0x00001000; +pub const TAB3: ::tcflag_t = 0x00001800; +pub const BSDLY: ::tcflag_t = 0x00002000; +pub const BS0: ::tcflag_t = 0x00000000; +pub const BS1: ::tcflag_t = 0x00002000; +pub const VTDLY: ::tcflag_t = 0x00004000; +pub const VT0: ::tcflag_t = 0x00000000; +pub const VT1: ::tcflag_t = 0x00004000; +pub const FFDLY: ::tcflag_t = 0x00008000; +pub const FF0: ::tcflag_t = 0x00000000; +pub const FF1: ::tcflag_t = 0x00008000; + +pub const CSIZE: ::tcflag_t = 0x00000020; +pub const CS5: ::tcflag_t = 0x00000000; +pub const CS6: ::tcflag_t = 0x00000000; +pub const CS7: ::tcflag_t = 0x00000000; +pub const CS8: ::tcflag_t = 0x00000020; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const XLOBLK: ::tcflag_t = 0x00001000; +pub const CTSFLOW: ::tcflag_t = 0x00002000; +pub const RTSFLOW: ::tcflag_t = 0x00004000; +pub const CRTSCTS: ::tcflag_t = RTSFLOW | CTSFLOW; + +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const XCASE: ::tcflag_t = 0x00000004; +pub const ECHO: ::tcflag_t = 0x00000008; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const IEXTEN: ::tcflag_t = 0x00000200; +pub const ECHOCTL: ::tcflag_t = 0x00000400; +pub const ECHOPRT: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00001000; +pub const FLUSHO: ::tcflag_t = 0x00002000; +pub const PENDIN: ::tcflag_t = 0x00004000; + +pub const TCGB_CTS: ::c_int = 0x01; +pub const TCGB_DSR: ::c_int = 0x02; +pub const TCGB_RI: ::c_int = 0x04; +pub const TCGB_DCD: ::c_int = 0x08; +pub const TIOCM_CTS: ::c_int = TCGB_CTS; +pub const TIOCM_CD: ::c_int = TCGB_DCD; +pub const TIOCM_CAR: ::c_int = TIOCM_CD; +pub const TIOCM_RI: ::c_int = TCGB_RI; +pub const TIOCM_DSR: ::c_int = TCGB_DSR; +pub const TIOCM_DTR: ::c_int = 0x10; +pub const TIOCM_RTS: ::c_int = 0x20; + +pub const B0: speed_t = 0x00; +pub const B50: speed_t = 0x01; +pub const B75: speed_t = 0x02; +pub const B110: speed_t = 0x03; +pub const B134: speed_t = 0x04; +pub const B150: speed_t = 0x05; +pub const B200: speed_t = 0x06; +pub const B300: speed_t = 0x07; +pub const B600: speed_t = 0x08; +pub const B1200: speed_t = 0x09; +pub const B1800: speed_t = 0x0A; +pub const B2400: speed_t = 0x0B; +pub const B4800: speed_t = 0x0C; +pub const B9600: speed_t = 0x0D; +pub const B19200: speed_t = 0x0E; +pub const B38400: speed_t = 0x0F; +pub const B57600: speed_t = 0x10; +pub const B115200: speed_t = 0x11; +pub const B230400: speed_t = 0x12; +pub const B31250: speed_t = 0x13; + +pub const TCSANOW: ::c_int = 0x01; +pub const TCSADRAIN: ::c_int = 0x02; +pub const TCSAFLUSH: ::c_int = 0x04; + +pub const TCOOFF: ::c_int = 0x01; +pub const TCOON: ::c_int = 0x02; +pub const TCIOFF: ::c_int = 0x04; +pub const TCION: ::c_int = 0x08; + +pub const TCIFLUSH: ::c_int = 0x01; +pub const TCOFLUSH: ::c_int = 0x02; +pub const TCIOFLUSH: ::c_int = 0x03; + +f! { + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & !0xff) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status & 0xff) + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status >> 8) & 0xff) != 0 + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + ((status >> 16) & 0xff) != 0 + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status >> 16) & 0xff + } + + // actually WIFCORED, but this is used everywhere else + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x10000) != 0 + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + (status & 0x20000) != 0 + } +} + +extern { + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); +} + +#[link(name = "bsd")] +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn clock_gettime(clk_id: ::c_int, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::c_int, tp: *const ::timespec) -> ::c_int; + pub fn pthread_create(thread: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + pub fn setgroups(ngroups: ::size_t, + ptr: *const ::gid_t) -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; + pub fn mprotect(addr: *const ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::size_t, + serv: *mut ::c_char, + sevlen: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + + pub fn glob(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_open(name: *const ::c_char, oflag: ::c_int, mode: ::mode_t) + -> ::c_int; + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + pub fn futimes(fd: ::c_int, times: *const ::timeval) -> ::c_int; + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + pub fn execvpe(file: *const ::c_char, argv: *const *const ::c_char, + environment: *const *const ::c_char) -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::c_int; + pub fn forkpty(amaster: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::pid_t; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + mod b32; + pub use self::b32::*; + } +} diff --git a/libc/src/unix/hermit/aarch64.rs b/libc/src/unix/hermit/aarch64.rs new file mode 100644 index 000000000..1a92e3b4f --- /dev/null +++ b/libc/src/unix/hermit/aarch64.rs @@ -0,0 +1,2 @@ +pub type c_char = u8; +pub type wchar_t = u32; diff --git a/libc/src/unix/hermit/mod.rs b/libc/src/unix/hermit/mod.rs new file mode 100644 index 000000000..288cc46a5 --- /dev/null +++ b/libc/src/unix/hermit/mod.rs @@ -0,0 +1,1017 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// liblibc port for HermitCore (https://hermitcore.org) +// HermitCore is a unikernel based on lwIP, newlib, and +// pthread-embedded. +// Consider these definitions when porting liblibc to another +// lwIP/newlib/pte-based target. +// +// Ported by Colin Finck + +pub type c_long = i64; +pub type c_ulong = u64; + +pub type speed_t = ::c_uint; +pub type mode_t = u32; +pub type dev_t = i16; +pub type nfds_t = ::c_ulong; +pub type socklen_t = u32; +pub type sa_family_t = u8; +pub type clock_t = c_ulong; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type off_t = i64; +pub type rlim_t = ::c_ulonglong; +pub type sigset_t = ::c_ulong; +pub type ino_t = u16; +pub type nlink_t = u16; +pub type blksize_t = c_long; +pub type blkcnt_t = c_long; +pub type stat64 = stat; +pub type clockid_t = c_ulong; +pub type pthread_t = pte_handle_t; +pub type pthread_attr_t = usize; +pub type pthread_cond_t = usize; +pub type pthread_condattr_t = usize; +pub type pthread_key_t = usize; +pub type pthread_mutex_t = usize; +pub type pthread_mutexattr_t = usize; +pub type pthread_rwlock_t = usize; +pub type pthread_rwlockattr_t = usize; + +s_no_extra_traits! { + pub struct dirent { + pub d_ino: ::c_long, + pub d_off: off_t, + pub d_reclen: u16, + pub d_name: [::c_char; 256], + } + + // Dummy + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [::c_char; 108], + } + + pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::c_char; 8], + } + + pub struct fd_set { + fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct sockaddr_storage { + pub s2_len: u8, + pub ss_family: sa_family_t, + pub s2_data1: [::c_char; 2], + pub s2_data2: [u32; 3], + pub s2_data3: [u32; 3], + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_spare4: [::c_long; 2], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_un {} + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for sockaddr { + fn eq(&self, other: &sockaddr) -> bool { + self.sa_len == other.sa_len + && self.sa_family == other.sa_family + && self + .sa_data + .iter() + .zip(other.sa_data.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr {} + impl ::fmt::Debug for sockaddr { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr") + .field("sa_len", &self.sa_len) + .field("sa_family", &self.sa_family) + // FIXME: .field("sa_data", &self.sa_data) + .finish() + } + } + impl ::hash::Hash for sockaddr { + fn hash(&self, state: &mut H) { + self.sa_len.hash(state); + self.sa_family.hash(state); + self.sa_data.hash(state); + } + } + + impl PartialEq for sockaddr_in { + fn eq(&self, other: &sockaddr_in) -> bool { + self.sin_len == other.sin_len + && self.sin_family == other.sin_family + && self.sin_port == other.sin_port + && self.sin_addr == other.sin_addr + && self + .sin_zero + .iter() + .zip(other.sin_zero.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_in {} + impl ::fmt::Debug for sockaddr_in { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_in") + .field("sin_len", &self.sin_len) + .field("sin_family", &self.sin_family) + .field("sin_port", &self.sin_port) + .field("sin_addr", &self.sin_addr) + // FIXME: .field("sin_zero", &self.sin_zero) + .finish() + } + } + impl ::hash::Hash for sockaddr_in { + fn hash(&self, state: &mut H) { + self.sin_len.hash(state); + self.sin_family.hash(state); + self.sin_port.hash(state); + self.sin_addr.hash(state); + self.sin_zero.hash(state); + } + } + + impl PartialEq for fd_set { + fn eq(&self, other: &fd_set) -> bool { + self.fds_bits + .iter() + .zip(other.fds_bits.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for fd_set {} + impl ::fmt::Debug for fd_set { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("fd_set") + // FIXME: .field("fds_bits", &self.fds_bits) + .finish() + } + } + impl ::hash::Hash for fd_set { + fn hash(&self, state: &mut H) { + self.fds_bits.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.s2_len == other.s2_len + && self.ss_family == other.ss_family + && self.s2_data1 + .iter() + .zip(other.s2_data1.iter()) + .all(|(a,b)| a == b) + && self.s2_data2 + .iter() + .zip(other.s2_data2.iter()) + .all(|(a,b)| a == b) + && self.s2_data3 + .iter() + .zip(other.s2_data3.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("s2_len", &self.s2_len) + .field("ss_family", &self.ss_family) + // FIXME: .field("s2_data1", &self.s2_data1) + // FIXME: .field("s2_data2", &self.s2_data2) + // FIXME: .field("s2_data3", &self.s2_data3) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.s2_len.hash(state); + self.ss_family.hash(state); + self.s2_data1.hash(state); + self.s2_data2.hash(state); + self.s2_data3.hash(state); + } + } + + impl PartialEq for stat { + fn eq(&self, other: &stat) -> bool { + self.st_dev == other.st_dev + && self.st_ino == other.st_ino + && self.st_mode == other.st_mode + && self.st_nlink == other.st_nlink + && self.st_uid == other.st_uid + && self.st_gid == other.st_gid + && self.st_rdev == other.st_rdev + && self.st_size == other.st_size + && self.st_atime == other.st_atime + && self.st_atime_nsec == other.st_atime_nsec + && self.st_mtime == other.st_mtime + && self.st_mtime_nsec == other.st_mtime_nsec + && self.st_ctime == other.st_ctime + && self.st_ctime_nsec == other.st_ctime_nsec + && self.st_blksize == other.st_blksize + && self.st_blocks == other.st_blocks + && self + .st_spare4 + .iter() + .zip(other.st_spare4.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for stat {} + impl ::fmt::Debug for stat { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("stat") + .field("st_dev", &self.st_dev) + .field("st_ino", &self.st_ino) + .field("st_mode", &self.st_mode) + .field("st_nlink", &self.st_nlink) + .field("st_uid", &self.st_uid) + .field("st_gid", &self.st_gid) + .field("st_rdev", &self.st_rdev) + .field("st_size", &self.st_size) + .field("st_atime", &self.st_atime) + .field("st_atime_nsec", &self.st_atime_nsec) + .field("st_mtime", &self.st_mtime) + .field("st_mtime_nsec", &self.st_mtime_nsec) + .field("st_ctime", &self.st_ctime) + .field("st_ctime_nsec", &self.st_ctime_nsec) + .field("st_blksize", &self.st_blksize) + .field("st_blocks", &self.st_blocks) + // FIXME: .field("st_spare4", &self.st_spare4) + .finish() + } + } + impl ::hash::Hash for stat { + fn hash(&self, state: &mut H) { + self.st_dev.hash(state); + self.st_ino.hash(state); + self.st_mode.hash(state); + self.st_nlink.hash(state); + self.st_uid.hash(state); + self.st_gid.hash(state); + self.st_rdev.hash(state); + self.st_size.hash(state); + self.st_atime.hash(state); + self.st_atime_nsec.hash(state); + self.st_mtime.hash(state); + self.st_mtime_nsec.hash(state); + self.st_ctime.hash(state); + self.st_ctime_nsec.hash(state); + self.st_blksize.hash(state); + self.st_blocks.hash(state); + self.st_spare4.hash(state); + } + } + } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut ::sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, + } + + pub struct Dl_info {} + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct passwd { // Unverified + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct pte_handle_t { + pub p: usize, + pub x: ::c_uint, + } + + pub struct sched_param { + pub sched_priority: ::c_int, + } + + pub struct sem_t { + pub value: i32, + pub lock: usize, + pub sem: usize, + } + + pub struct sigaction { + pub sa_flags: ::c_int, + pub sa_mask: sigset_t, + pub sa_handler: usize, + } + + pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct statvfs {} + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + } + + pub struct tms { + pub tms_utime: ::clock_t, + pub tms_stime: ::clock_t, + pub tms_cutime: ::clock_t, + pub tms_cstime: ::clock_t, + } + + pub struct termios {} + + pub struct utsname {} +} + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_INET: ::c_int = 2; +pub const AF_INET6: ::c_int = 10; + +// Dummy +pub const AF_UNIX: ::c_int = 1; + +pub const CLOCK_REALTIME: ::clockid_t = 1; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; + +// Dummy +pub const EAI_SYSTEM: ::c_int = -11; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const EWOULDBLOCK: ::c_int = EAGAIN; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EMULTIHOP: ::c_int = 72; +pub const EDOTDOT: ::c_int = 73; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; +pub const F_GETOWN: ::c_int = 5; +pub const F_SETOWN: ::c_int = 6; +pub const F_GETLK: ::c_int = 7; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; +pub const F_RGETLK: ::c_int = 10; +pub const F_RSETLK: ::c_int = 11; +pub const F_CNVT: ::c_int = 12; +pub const F_RSETLKW: ::c_int = 13; +pub const F_DUPFD_CLOEXEC: ::c_int = 14; + +pub const FD_SETSIZE: usize = 1024; + +// Dummy +pub const FIOCLEX: ::c_int = 0x5451; + +pub const FIONBIO: ::c_int = 0x8004667e; +pub const FIONREAD: ::c_int = 0x4004667f; + +pub const IP_ADD_MEMBERSHIP: ::c_int = 3; +pub const IP_DROP_MEMBERSHIP: ::c_int = 4; + +pub const IP_TOS: ::c_int = 1; +pub const IP_TTL: ::c_int = 2; + +pub const IP_MULTICAST_TTL: ::c_int = 5; +pub const IP_MULTICAST_IF: ::c_int = 6; +pub const IP_MULTICAST_LOOP: ::c_int = 7; + +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_ADD_MEMBERSHIP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; +pub const IPV6_DROP_MEMBERSHIP: ::c_int = 13; +pub const IPV6_V6ONLY: ::c_int = 27; + +// Dummy +pub const IPV6_MULTICAST_LOOP: ::c_int = 7; + +pub const MSG_PEEK: ::c_int = 0x01; +pub const MSG_WAITALL: ::c_int = 0x02; +pub const MSG_OOB: ::c_int = 0x04; +pub const MSG_DONTWAIT: ::c_int = 0x08; +pub const MSG_MORE: ::c_int = 0x10; + +pub const O_ACCMODE: ::c_int = 3; +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_TRUNC: ::c_int = 512; +pub const O_CLOEXEC: ::c_int = 524288; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; + +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = usize::max_value(); +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = usize::max_value(); +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = usize::max_value(); + +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_STACK_MIN: ::size_t = 0; + +// Dummy +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_CHILD_MAX: ::c_int = 1; +pub const _SC_CLK_TCK: ::c_int = 2; +pub const _SC_NGROUPS_MAX: ::c_int = 3; +pub const _SC_OPEN_MAX: ::c_int = 4; +pub const _SC_JOB_CONTROL: ::c_int = 5; +pub const _SC_SAVED_IDS: ::c_int = 6; +pub const _SC_VERSION: ::c_int = 7; +pub const _SC_PAGESIZE: ::c_int = 8; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_NPROCESSORS_CONF: ::c_int = 9; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 10; +pub const _SC_PHYS_PAGES: ::c_int = 11; +pub const _SC_AVPHYS_PAGES: ::c_int = 12; +pub const _SC_MQ_OPEN_MAX: ::c_int = 13; +pub const _SC_MQ_PRIO_MAX: ::c_int = 14; +pub const _SC_RTSIG_MAX: ::c_int = 15; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 16; +pub const _SC_SEM_VALUE_MAX: ::c_int = 17; +pub const _SC_SIGQUEUE_MAX: ::c_int = 18; +pub const _SC_TIMER_MAX: ::c_int = 19; +pub const _SC_TZNAME_MAX: ::c_int = 20; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 21; +pub const _SC_FSYNC: ::c_int = 22; +pub const _SC_MAPPED_FILES: ::c_int = 23; +pub const _SC_MEMLOCK: ::c_int = 24; +pub const _SC_MEMLOCK_RANGE: ::c_int = 25; +pub const _SC_MEMORY_PROTECTION: ::c_int = 26; +pub const _SC_MESSAGE_PASSING: ::c_int = 27; +pub const _SC_PRIORITIZED_IO: ::c_int = 28; +pub const _SC_REALTIME_SIGNALS: ::c_int = 29; +pub const _SC_SEMAPHORES: ::c_int = 30; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 31; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 32; +pub const _SC_TIMERS: ::c_int = 33; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 34; +pub const _SC_AIO_MAX: ::c_int = 35; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 36; +pub const _SC_DELAYTIMER_MAX: ::c_int = 37; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 38; +pub const _SC_THREAD_STACK_MIN: ::c_int = 39; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 40; +pub const _SC_TTY_NAME_MAX: ::c_int = 41; +pub const _SC_THREADS: ::c_int = 42; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 43; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 44; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 45; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 46; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 47; +pub const _SC_THREAD_PRIO_CEILING: ::c_int = _SC_THREAD_PRIO_PROTECT; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 48; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 49; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 50; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 51; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 52; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 53; +pub const _SC_ADVISORY_INFO: ::c_int = 54; +pub const _SC_ATEXIT_MAX: ::c_int = 55; +pub const _SC_BARRIERS: ::c_int = 56; +pub const _SC_BC_BASE_MAX: ::c_int = 57; +pub const _SC_BC_DIM_MAX: ::c_int = 58; +pub const _SC_BC_SCALE_MAX: ::c_int = 59; +pub const _SC_BC_STRING_MAX: ::c_int = 60; +pub const _SC_CLOCK_SELECTION: ::c_int = 61; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 62; +pub const _SC_CPUTIME: ::c_int = 63; +pub const _SC_EXPR_NEST_MAX: ::c_int = 64; +pub const _SC_HOST_NAME_MAX: ::c_int = 65; +pub const _SC_IOV_MAX: ::c_int = 66; +pub const _SC_IPV6: ::c_int = 67; +pub const _SC_LINE_MAX: ::c_int = 68; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 69; +pub const _SC_RAW_SOCKETS: ::c_int = 70; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 71; +pub const _SC_REGEXP: ::c_int = 72; +pub const _SC_RE_DUP_MAX: ::c_int = 73; +pub const _SC_SHELL: ::c_int = 74; +pub const _SC_SPAWN: ::c_int = 75; +pub const _SC_SPIN_LOCKS: ::c_int = 76; +pub const _SC_SPORADIC_SERVER: ::c_int = 77; +pub const _SC_SS_REPL_MAX: ::c_int = 78; +pub const _SC_SYMLOOP_MAX: ::c_int = 79; +pub const _SC_THREAD_CPUTIME: ::c_int = 80; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 81; +pub const _SC_TIMEOUTS: ::c_int = 82; +pub const _SC_TRACE: ::c_int = 83; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 84; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 85; +pub const _SC_TRACE_INHERIT: ::c_int = 86; +pub const _SC_TRACE_LOG: ::c_int = 87; +pub const _SC_TRACE_NAME_MAX: ::c_int = 88; +pub const _SC_TRACE_SYS_MAX: ::c_int = 89; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 90; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 91; +pub const _SC_V7_ILP32_OFF32: ::c_int = 92; +pub const _SC_V6_ILP32_OFF32: ::c_int =_SC_V7_ILP32_OFF32; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = _SC_V7_ILP32_OFF32; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 93; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = _SC_V7_ILP32_OFFBIG; +pub const _SC_V7_LP64_OFF64: ::c_int = 94; +pub const _SC_V6_LP64_OFF64: ::c_int = _SC_V7_LP64_OFF64; +pub const _SC_XBS5_LP64_OFF64: ::c_int = _SC_V7_LP64_OFF64; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 95; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = _SC_V7_LPBIG_OFFBIG; +pub const _SC_XOPEN_CRYPT: ::c_int = 96; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 97; +pub const _SC_XOPEN_LEGACY: ::c_int = 98; +pub const _SC_XOPEN_REALTIME: ::c_int = 99; +pub const _SC_STREAM_MAX: ::c_int = 100; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 101; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 102; +pub const _SC_XOPEN_SHM: ::c_int = 103; +pub const _SC_XOPEN_STREAMS: ::c_int = 104; +pub const _SC_XOPEN_UNIX: ::c_int = 105; +pub const _SC_XOPEN_VERSION: ::c_int = 106; +pub const _SC_2_CHAR_TERM: ::c_int = 107; +pub const _SC_2_C_BIND: ::c_int = 108; +pub const _SC_2_C_DEV: ::c_int = 109; +pub const _SC_2_FORT_DEV: ::c_int = 110; +pub const _SC_2_FORT_RUN: ::c_int = 111; +pub const _SC_2_LOCALEDEF: ::c_int = 112; +pub const _SC_2_PBS: ::c_int = 113; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 114; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 115; +pub const _SC_2_PBS_LOCATE: ::c_int = 116; +pub const _SC_2_PBS_MESSAGE: ::c_int = 117; +pub const _SC_2_PBS_TRACK: ::c_int = 118; +pub const _SC_2_SW_DEV: ::c_int = 119; +pub const _SC_2_UPE: ::c_int = 120; +pub const _SC_2_VERSION: ::c_int = 121; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 122; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 123; +pub const _SC_XOPEN_UUCP: ::c_int = 124; +pub const _SC_LEVEL1_ICACHE_SIZE: ::c_int = 125; +pub const _SC_LEVEL1_ICACHE_ASSOC: ::c_int = 126; +pub const _SC_LEVEL1_ICACHE_LINESIZE: ::c_int = 127; +pub const _SC_LEVEL1_DCACHE_SIZE: ::c_int = 128; +pub const _SC_LEVEL1_DCACHE_ASSOC: ::c_int = 129; +pub const _SC_LEVEL1_DCACHE_LINESIZE: ::c_int = 130; +pub const _SC_LEVEL2_CACHE_SIZE: ::c_int = 131; +pub const _SC_LEVEL2_CACHE_ASSOC: ::c_int = 132; +pub const _SC_LEVEL2_CACHE_LINESIZE: ::c_int = 133; +pub const _SC_LEVEL3_CACHE_SIZE: ::c_int = 134; +pub const _SC_LEVEL3_CACHE_ASSOC: ::c_int = 135; +pub const _SC_LEVEL3_CACHE_LINESIZE: ::c_int = 136; +pub const _SC_LEVEL4_CACHE_SIZE: ::c_int = 137; +pub const _SC_LEVEL4_CACHE_ASSOC: ::c_int = 138; +pub const _SC_LEVEL4_CACHE_LINESIZE: ::c_int = 139; + +pub const S_BLKSIZE: ::mode_t = 1024; +pub const S_IREAD: ::mode_t = 256; +pub const S_IWRITE: ::mode_t = 128; +pub const S_IEXEC: ::mode_t = 64; +pub const S_ENFMT: ::mode_t = 1024; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFCHR: ::mode_t = 8192; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFIFO: ::mode_t = 4096; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IRGRP: ::mode_t = 32; +pub const S_IWGRP: ::mode_t = 16; +pub const S_IXGRP: ::mode_t = 8; +pub const S_IROTH: ::mode_t = 4; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IXOTH: ::mode_t = 1; + +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const SIG_SETMASK: ::c_int = 0; + +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGEMT: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const SO_DEBUG: ::c_int = 0x0001; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_CONTIMEO: ::c_int = 0x1009; +pub const SO_NO_CHECK: ::c_int = 0x100a; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 3; + +pub const SOL_SOCKET: ::c_int = 0xfff; + +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +pub const TCP_NODELAY: ::c_int = 0x01; +pub const TCP_KEEPALIVE: ::c_int = 0x02; +pub const TCP_KEEPIDLE: ::c_int = 0x03; +pub const TCP_KEEPINTVL: ::c_int = 0x04; +pub const TCP_KEEPCNT: ::c_int = 0x05; + +const ULONG_SIZE: usize = 64; + +pub const WNOHANG: ::c_int = 0x00000001; + +f! { + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0xff) == 0 + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7f + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn bind(s: ::c_int, name: *const ::sockaddr, namelen: ::socklen_t) + -> ::c_int; + + pub fn clock_gettime(clock_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + + pub fn getpwuid_r(uid: ::uid_t, pwd: *mut passwd, buf: *mut ::c_char, + buflen: ::size_t, result: *mut *mut passwd) -> ::c_int; + + // Dummy + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; + + pub fn memalign(align: ::size_t, nbytes: ::size_t) -> *mut ::c_void; + + pub fn pthread_create(tid: *mut ::pthread_t, attr: *const ::pthread_attr_t, + start: extern fn(*mut ::c_void) -> *mut ::c_void, arg: *mut ::c_void) + -> ::c_int; + + pub fn pthread_sigmask(how: ::c_int, set: *const ::sigset_t, + oset: *mut ::sigset_t) -> ::c_int; + + pub fn recvfrom(s: ::c_int, mem: *mut ::c_void, len: ::size_t, + flags: ::c_int, from: *mut ::sockaddr, fromlen: *mut ::socklen_t) + -> ::c_int; + + pub fn setgroups(ngroups: ::c_int, grouplist: *const ::gid_t) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/hermit/x86_64.rs b/libc/src/unix/hermit/x86_64.rs new file mode 100644 index 000000000..76ec3ce82 --- /dev/null +++ b/libc/src/unix/hermit/x86_64.rs @@ -0,0 +1,2 @@ +pub type c_char = i8; +pub type wchar_t = i32; diff --git a/libc/src/unix/mod.rs b/libc/src/unix/mod.rs new file mode 100644 index 000000000..1565b6338 --- /dev/null +++ b/libc/src/unix/mod.rs @@ -0,0 +1,1220 @@ +//! Definitions found commonly among almost all Unix derivatives +//! +//! More functions and definitions can be found in the more specific modules +//! according to the platform in question. + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; + +pub type pid_t = i32; +pub type uid_t = u32; +pub type gid_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; +pub type sighandler_t = ::size_t; +pub type cc_t = ::c_uchar; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum DIR {} +impl ::Copy for DIR {} +impl ::Clone for DIR { + fn clone(&self) -> DIR { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum locale_t {} +impl ::Copy for locale_t {} +impl ::Clone for locale_t { + fn clone(&self) -> locale_t { *self } +} + +s! { + pub struct group { + pub gr_name: *mut ::c_char, + pub gr_passwd: *mut ::c_char, + pub gr_gid: ::gid_t, + pub gr_mem: *mut *mut ::c_char, + } + + pub struct utimbuf { + pub actime: time_t, + pub modtime: time_t, + } + + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + // linux x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 + pub struct timespec { + pub tv_sec: time_t, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub tv_nsec: i64, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub tv_nsec: ::c_long, + } + + pub struct rlimit { + pub rlim_cur: rlim_t, + pub rlim_max: rlim_t, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + pub ru_maxrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad1: u32, + pub ru_ixrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad2: u32, + pub ru_idrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad3: u32, + pub ru_isrss: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad4: u32, + pub ru_minflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad5: u32, + pub ru_majflt: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad6: u32, + pub ru_nswap: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad7: u32, + pub ru_inblock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad8: u32, + pub ru_oublock: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad9: u32, + pub ru_msgsnd: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad10: u32, + pub ru_msgrcv: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad11: u32, + pub ru_nsignals: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad12: u32, + pub ru_nvcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad13: u32, + pub ru_nivcsw: c_long, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + __pad14: u32, + + #[cfg(any(target_env = "musl", target_os = "emscripten"))] + __reserved: [c_long; 16], + } + + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + #[cfg(target_os = "android")] + pub ipv6mr_interface: ::c_int, + #[cfg(not(target_os = "android"))] + pub ipv6mr_interface: ::c_uint, + } + + pub struct hostent { + pub h_name: *mut ::c_char, + pub h_aliases: *mut *mut ::c_char, + pub h_addrtype: ::c_int, + pub h_length: ::c_int, + pub h_addr_list: *mut *mut ::c_char, + } + + pub struct iovec { + pub iov_base: *mut ::c_void, + pub iov_len: ::size_t, + } + + pub struct pollfd { + pub fd: ::c_int, + pub events: ::c_short, + pub revents: ::c_short, + } + + pub struct winsize { + pub ws_row: ::c_ushort, + pub ws_col: ::c_ushort, + pub ws_xpixel: ::c_ushort, + pub ws_ypixel: ::c_ushort, + } + + pub struct linger { + pub l_onoff: ::c_int, + pub l_linger: ::c_int, + } + + pub struct sigval { + // Actually a union of an int and a void* + pub sival_ptr: *mut ::c_void + } + + // + pub struct itimerval { + pub it_interval: ::timeval, + pub it_value: ::timeval, + } + + // + pub struct tms { + pub tms_utime: ::clock_t, + pub tms_stime: ::clock_t, + pub tms_cutime: ::clock_t, + pub tms_cstime: ::clock_t, + } + + pub struct servent { + pub s_name: *mut ::c_char, + pub s_aliases: *mut *mut ::c_char, + pub s_port: ::c_int, + pub s_proto: *mut ::c_char, + } + + pub struct protoent { + pub p_name: *mut ::c_char, + pub p_aliases: *mut *mut ::c_char, + pub p_proto: ::c_int, + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const SIG_DFL: sighandler_t = 0 as sighandler_t; +pub const SIG_IGN: sighandler_t = 1 as sighandler_t; +pub const SIG_ERR: sighandler_t = !0 as sighandler_t; + +pub const DT_UNKNOWN: u8 = 0; +pub const DT_FIFO: u8 = 1; +pub const DT_CHR: u8 = 2; +pub const DT_DIR: u8 = 4; +pub const DT_BLK: u8 = 6; +pub const DT_REG: u8 = 8; +pub const DT_LNK: u8 = 10; +pub const DT_SOCK: u8 = 12; + +cfg_if! { + if #[cfg(not(target_os = "redox"))] { + pub const FD_CLOEXEC: ::c_int = 0x1; + } +} + +pub const USRQUOTA: ::c_int = 0; +pub const GRPQUOTA: ::c_int = 1; + +pub const SIGIOT: ::c_int = 6; + +pub const S_ISUID: ::c_int = 0x800; +pub const S_ISGID: ::c_int = 0x400; +pub const S_ISVTX: ::c_int = 0x200; + +pub const IF_NAMESIZE: ::size_t = 16; +pub const IFNAMSIZ: ::size_t = IF_NAMESIZE; + +pub const LOG_EMERG: ::c_int = 0; +pub const LOG_ALERT: ::c_int = 1; +pub const LOG_CRIT: ::c_int = 2; +pub const LOG_ERR: ::c_int = 3; +pub const LOG_WARNING: ::c_int = 4; +pub const LOG_NOTICE: ::c_int = 5; +pub const LOG_INFO: ::c_int = 6; +pub const LOG_DEBUG: ::c_int = 7; + +pub const LOG_KERN: ::c_int = 0; +pub const LOG_USER: ::c_int = 1 << 3; +pub const LOG_MAIL: ::c_int = 2 << 3; +pub const LOG_DAEMON: ::c_int = 3 << 3; +pub const LOG_AUTH: ::c_int = 4 << 3; +pub const LOG_SYSLOG: ::c_int = 5 << 3; +pub const LOG_LPR: ::c_int = 6 << 3; +pub const LOG_NEWS: ::c_int = 7 << 3; +pub const LOG_UUCP: ::c_int = 8 << 3; +pub const LOG_LOCAL0: ::c_int = 16 << 3; +pub const LOG_LOCAL1: ::c_int = 17 << 3; +pub const LOG_LOCAL2: ::c_int = 18 << 3; +pub const LOG_LOCAL3: ::c_int = 19 << 3; +pub const LOG_LOCAL4: ::c_int = 20 << 3; +pub const LOG_LOCAL5: ::c_int = 21 << 3; +pub const LOG_LOCAL6: ::c_int = 22 << 3; +pub const LOG_LOCAL7: ::c_int = 23 << 3; + +pub const LOG_PID: ::c_int = 0x01; +pub const LOG_CONS: ::c_int = 0x02; +pub const LOG_ODELAY: ::c_int = 0x04; +pub const LOG_NDELAY: ::c_int = 0x08; +pub const LOG_NOWAIT: ::c_int = 0x10; + +pub const LOG_PRIMASK: ::c_int = 7; +pub const LOG_FACMASK: ::c_int = 0x3f8; + +pub const PRIO_PROCESS: ::c_int = 0; +pub const PRIO_PGRP: ::c_int = 1; +pub const PRIO_USER: ::c_int = 2; + +pub const PRIO_MIN: ::c_int = -20; +pub const PRIO_MAX: ::c_int = 20; + +pub const IPPROTO_ICMP: ::c_int = 1; +pub const IPPROTO_ICMPV6: ::c_int = 58; +pub const IPPROTO_TCP: ::c_int = 6; +pub const IPPROTO_UDP: ::c_int = 17; +pub const IPPROTO_IP: ::c_int = 0; +pub const IPPROTO_IPV6: ::c_int = 41; + +pub const INADDR_LOOPBACK: in_addr_t = 2130706433; +pub const INADDR_ANY: in_addr_t = 0; +pub const INADDR_BROADCAST: in_addr_t = 4294967295; +pub const INADDR_NONE: in_addr_t = 4294967295; + +pub const ARPOP_REQUEST: u16 = 1; +pub const ARPOP_REPLY: u16 = 2; + +pub const ATF_COM: ::c_int = 0x02; +pub const ATF_PERM: ::c_int = 0x04; +pub const ATF_PUBL: ::c_int = 0x08; +pub const ATF_USETRAILERS: ::c_int = 0x10; + +cfg_if! { + if #[cfg(target_os = "l4re")] { + // required libraries for L4Re are linked externally, ATM + } else if #[cfg(feature = "use_std")] { + // cargo build, don't pull in anything extra as the libstd dep + // already pulls in all libs. + } else if #[cfg(target_env = "musl")] { + #[cfg_attr(feature = "rustc-dep-of-std", + link(name = "c", kind = "static", + cfg(target_feature = "crt-static")))] + #[cfg_attr(feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))))] + extern {} + } else if #[cfg(target_os = "emscripten")] { + #[link(name = "c")] + extern {} + } else if #[cfg(all(target_os = "netbsd", + feature = "rustc-dep-of-std", + target_vendor = "rumprun"))] { + // Since we don't use -nodefaultlibs on Rumprun, libc is always pulled + // in automatically by the linker. We avoid passing it explicitly, as it + // causes some versions of binutils to crash with an assertion failure. + #[link(name = "m")] + extern {} + } else if #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "openbsd"))] { + #[link(name = "c")] + #[link(name = "m")] + extern {} + } else if #[cfg(target_os = "haiku")] { + #[link(name = "root")] + #[link(name = "network")] + extern {} + } else if #[cfg(target_env = "newlib")] { + #[link(name = "c")] + #[link(name = "m")] + extern {} + } else if #[cfg(target_os = "hermit")] { + // no_default_libraries is set to false for HermitCore, so only a link + // to "pthread" needs to be added. + #[link(name = "pthread")] + extern {} + } else if #[cfg(target_env = "illumos")] { + #[link(name = "c")] + #[link(name = "m")] + extern {} + } else if #[cfg(target_os = "redox")] { + #[cfg_attr(feature = "rustc-dep-of-std", + link(name = "c", kind = "static-nobundle", + cfg(target_feature = "crt-static")))] + #[cfg_attr(feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))))] + extern {} + } else { + #[link(name = "c")] + #[link(name = "m")] + #[link(name = "rt")] + #[link(name = "pthread")] + extern {} + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum FILE {} +impl ::Copy for FILE {} +impl ::Clone for FILE { + fn clone(&self) -> FILE { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos_t {} // TODO: fill this out with a struct +impl ::Copy for fpos_t {} +impl ::Clone for fpos_t { + fn clone(&self) -> fpos_t { *self } +} + +extern { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fopen$UNIX2003" + )] + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "freopen$UNIX2003" + )] + pub fn freopen(filename: *const c_char, mode: *const c_char, + file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, + size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fputs$UNIX2003" + )] + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "fwrite$UNIX2003" + )] + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + #[cfg_attr(target_os = "netbsd", link_name = "__fgetpos50")] + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__fsetpos50")] + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atoi(s: *const c_char) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "strtod$UNIX2003" + )] + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_long; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_ulong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern fn()) -> c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "system$UNIX2003" + )] + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp(s1: *const c_char, s2: *const c_char, + n: size_t) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "strerror$UNIX2003" + )] + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, + n: size_t) -> ::size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; +} + +extern { + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam50")] + pub fn getpwnam(name: *const ::c_char) -> *mut passwd; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid50")] + pub fn getpwuid(uid: ::uid_t) -> *mut passwd; + + pub fn fprintf(stream: *mut ::FILE, + format: *const ::c_char, ...) -> ::c_int; + pub fn printf(format: *const ::c_char, ...) -> ::c_int; + pub fn snprintf(s: *mut ::c_char, n: ::size_t, + format: *const ::c_char, ...) -> ::c_int; + pub fn sprintf(s: *mut ::c_char, format: *const ::c_char, ...) -> ::c_int; + #[cfg_attr(target_os = "linux", link_name = "__isoc99_fscanf")] + pub fn fscanf(stream: *mut ::FILE, format: *const ::c_char, ...) -> ::c_int; + #[cfg_attr(target_os = "linux", link_name = "__isoc99_scanf")] + pub fn scanf(format: *const ::c_char, ...) -> ::c_int; + #[cfg_attr(target_os = "linux", link_name = "__isoc99_sscanf")] + pub fn sscanf(s: *const ::c_char, format: *const ::c_char, ...) -> ::c_int; + pub fn getchar_unlocked() -> ::c_int; + pub fn putchar_unlocked(c: ::c_int) -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__socket30")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_socket")] + pub fn socket(domain: ::c_int, ty: ::c_int, protocol: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "connect$UNIX2003")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_connect")] + pub fn connect(socket: ::c_int, address: *const sockaddr, + len: socklen_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "listen$UNIX2003")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_listen")] + pub fn listen(socket: ::c_int, backlog: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "accept$UNIX2003")] + pub fn accept(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "getpeername$UNIX2003")] + pub fn getpeername(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "getsockname$UNIX2003")] + pub fn getsockname(socket: ::c_int, address: *mut sockaddr, + address_len: *mut socklen_t) -> ::c_int; + pub fn setsockopt(socket: ::c_int, level: ::c_int, name: ::c_int, + value: *const ::c_void, + option_len: socklen_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "socketpair$UNIX2003")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_socketpair")] + pub fn socketpair(domain: ::c_int, type_: ::c_int, protocol: ::c_int, + socket_vector: *mut ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sendto$UNIX2003")] + #[cfg_attr(target_os = "illumos", link_name = "__xnet_sendto")] + pub fn sendto(socket: ::c_int, buf: *const ::c_void, len: ::size_t, + flags: ::c_int, addr: *const sockaddr, + addrlen: socklen_t) -> ::ssize_t; + pub fn shutdown(socket: ::c_int, how: ::c_int) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "chmod$UNIX2003")] + pub fn chmod(path: *const c_char, mode: mode_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "fchmod$UNIX2003")] + pub fn fchmod(fd: ::c_int, mode: mode_t) -> ::c_int; + + #[cfg_attr(target_os = "macos", link_name = "fstat$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__fstat50")] + #[cfg_attr(target_os = "freebsd", link_name = "fstat@FBSD_1.0")] + pub fn fstat(fildes: ::c_int, buf: *mut stat) -> ::c_int; + + pub fn mkdir(path: *const c_char, mode: mode_t) -> ::c_int; + + #[cfg_attr(target_os = "macos", link_name = "stat$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__stat50")] + #[cfg_attr(target_os = "freebsd", link_name = "stat@FBSD_1.0")] + pub fn stat(path: *const c_char, buf: *mut stat) -> ::c_int; + + pub fn pclose(stream: *mut ::FILE) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "fdopen$UNIX2003")] + pub fn fdopen(fd: ::c_int, mode: *const c_char) -> *mut ::FILE; + pub fn fileno(stream: *mut ::FILE) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "open$UNIX2003")] + pub fn open(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "creat$UNIX2003")] + pub fn creat(path: *const c_char, mode: mode_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "fcntl$UNIX2003")] + pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "opendir$INODE64")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "opendir$INODE64$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__opendir30")] + pub fn opendir(dirname: *const c_char) -> *mut ::DIR; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "fdopendir$INODE64")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "fdopendir$INODE64$UNIX2003")] + pub fn fdopendir(fd: ::c_int) -> *mut ::DIR; + + #[cfg_attr(target_os = "macos", link_name = "readdir$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__readdir30")] + #[cfg_attr(target_os = "freebsd", link_name = "readdir@FBSD_1.0")] + pub fn readdir(dirp: *mut ::DIR) -> *mut ::dirent; + #[cfg_attr(target_os = "macos", link_name = "readdir_r$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__readdir_r30")] + #[cfg_attr(target_os = "freebsd", link_name = "readdir_r@FBSD_1.0")] + /// The 64-bit libc on Solaris and illumos only has readdir_r. If a + /// 32-bit Solaris or illumos target is ever created, it should use + /// __posix_readdir_r. See libc(3LIB) on Solaris or illumos: + /// https://illumos.org/man/3lib/libc + /// https://docs.oracle.com/cd/E36784_01/html/E36873/libc-3lib.html + /// https://www.unix.com/man-page/opensolaris/3LIB/libc/ + pub fn readdir_r(dirp: *mut ::DIR, entry: *mut ::dirent, + result: *mut *mut ::dirent) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "closedir$UNIX2003")] + pub fn closedir(dirp: *mut ::DIR) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "rewinddir$INODE64")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "rewinddir$INODE64$UNIX2003")] + pub fn rewinddir(dirp: *mut ::DIR); + + pub fn openat(dirfd: ::c_int, pathname: *const ::c_char, + flags: ::c_int, ...) -> ::c_int; + pub fn fchmodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, flags: ::c_int) -> ::c_int; + pub fn fchown(fd: ::c_int, + owner: ::uid_t, + group: ::gid_t) -> ::c_int; + pub fn fchownat(dirfd: ::c_int, pathname: *const ::c_char, + owner: ::uid_t, group: ::gid_t, + flags: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "macos", link_name = "fstatat$INODE64")] + #[cfg_attr(target_os = "freebsd", link_name = "fstatat@FBSD_1.1")] + pub fn fstatat(dirfd: ::c_int, pathname: *const ::c_char, + buf: *mut stat, flags: ::c_int) -> ::c_int; + pub fn linkat(olddirfd: ::c_int, oldpath: *const ::c_char, + newdirfd: ::c_int, newpath: *const ::c_char, + flags: ::c_int) -> ::c_int; + pub fn mkdirat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn readlinkat(dirfd: ::c_int, pathname: *const ::c_char, + buf: *mut ::c_char, bufsiz: ::size_t) -> ::ssize_t; + pub fn renameat(olddirfd: ::c_int, oldpath: *const ::c_char, + newdirfd: ::c_int, newpath: *const ::c_char) + -> ::c_int; + pub fn symlinkat(target: *const ::c_char, newdirfd: ::c_int, + linkpath: *const ::c_char) -> ::c_int; + pub fn unlinkat(dirfd: ::c_int, pathname: *const ::c_char, + flags: ::c_int) -> ::c_int; + + pub fn access(path: *const c_char, amode: ::c_int) -> ::c_int; + pub fn alarm(seconds: ::c_uint) -> ::c_uint; + pub fn chdir(dir: *const c_char) -> ::c_int; + pub fn fchdir(dirfd: ::c_int) -> ::c_int; + pub fn chown(path: *const c_char, uid: uid_t, + gid: gid_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "lchown$UNIX2003")] + pub fn lchown(path: *const c_char, uid: uid_t, + gid: gid_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "close$NOCANCEL$UNIX2003")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "close$NOCANCEL")] + pub fn close(fd: ::c_int) -> ::c_int; + pub fn dup(fd: ::c_int) -> ::c_int; + pub fn dup2(src: ::c_int, dst: ::c_int) -> ::c_int; + pub fn execl(path: *const c_char, + arg0: *const c_char, ...) -> ::c_int; + pub fn execle(path: *const ::c_char, + arg0: *const ::c_char, ...) -> ::c_int; + pub fn execlp(file: *const ::c_char, + arg0: *const ::c_char, ...) -> ::c_int; + pub fn execv(prog: *const c_char, + argv: *const *const c_char) -> ::c_int; + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) + -> ::c_int; + pub fn execvp(c: *const c_char, + argv: *const *const c_char) -> ::c_int; + pub fn fork() -> pid_t; + pub fn fpathconf(filedes: ::c_int, name: ::c_int) -> c_long; + pub fn getcwd(buf: *mut c_char, size: ::size_t) -> *mut c_char; + pub fn getegid() -> gid_t; + pub fn geteuid() -> uid_t; + pub fn getgid() -> gid_t; + pub fn getgroups(ngroups_max: ::c_int, groups: *mut gid_t) + -> ::c_int; + pub fn getlogin() -> *mut c_char; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "getopt$UNIX2003")] + pub fn getopt(argc: ::c_int, argv: *const *mut c_char, + optstr: *const c_char) -> ::c_int; + pub fn getpgid(pid: pid_t) -> pid_t; + pub fn getpgrp() -> pid_t; + pub fn getpid() -> pid_t; + pub fn getppid() -> pid_t; + pub fn getuid() -> uid_t; + pub fn isatty(fd: ::c_int) -> ::c_int; + pub fn link(src: *const c_char, dst: *const c_char) -> ::c_int; + pub fn lseek(fd: ::c_int, offset: off_t, whence: ::c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: ::c_int) -> c_long; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pause$UNIX2003")] + pub fn pause() -> ::c_int; + pub fn pipe(fds: *mut ::c_int) -> ::c_int; + pub fn posix_memalign(memptr: *mut *mut ::c_void, + align: ::size_t, + size: ::size_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "read$UNIX2003")] + pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t) + -> ::ssize_t; + pub fn rmdir(path: *const c_char) -> ::c_int; + pub fn seteuid(uid: uid_t) -> ::c_int; + pub fn setegid(gid: gid_t) -> ::c_int; + pub fn setgid(gid: gid_t) -> ::c_int; + pub fn setpgid(pid: pid_t, pgid: pid_t) -> ::c_int; + pub fn setsid() -> pid_t; + pub fn setuid(uid: uid_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sleep$UNIX2003")] + pub fn sleep(secs: ::c_uint) -> ::c_uint; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "nanosleep$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__nanosleep50")] + pub fn nanosleep(rqtp: *const timespec, + rmtp: *mut timespec) -> ::c_int; + pub fn tcgetpgrp(fd: ::c_int) -> pid_t; + pub fn tcsetpgrp(fd: ::c_int, pgrp: ::pid_t) -> ::c_int; + pub fn ttyname(fd: ::c_int) -> *mut c_char; + pub fn unlink(c: *const c_char) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "wait$UNIX2003")] + pub fn wait(status: *mut ::c_int) -> pid_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "waitpid$UNIX2003")] + pub fn waitpid(pid: pid_t, status: *mut ::c_int, options: ::c_int) + -> pid_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "write$UNIX2003")] + pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) + -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pread$UNIX2003")] + pub fn pread(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, + offset: off_t) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pwrite$UNIX2003")] + pub fn pwrite(fd: ::c_int, buf: *const ::c_void, count: ::size_t, + offset: off_t) -> ::ssize_t; + pub fn umask(mask: mode_t) -> mode_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__utime50")] + pub fn utime(file: *const c_char, buf: *const utimbuf) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "kill$UNIX2003")] + pub fn kill(pid: pid_t, sig: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "killpg$UNIX2003")] + pub fn killpg(pgrp: pid_t, sig: ::c_int) -> ::c_int; + + pub fn mlock(addr: *const ::c_void, len: ::size_t) -> ::c_int; + pub fn munlock(addr: *const ::c_void, len: ::size_t) -> ::c_int; + pub fn mlockall(flags: ::c_int) -> ::c_int; + pub fn munlockall() -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "mmap$UNIX2003")] + pub fn mmap(addr: *mut ::c_void, + len: ::size_t, + prot: ::c_int, + flags: ::c_int, + fd: ::c_int, + offset: off_t) + -> *mut ::c_void; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "munmap$UNIX2003")] + pub fn munmap(addr: *mut ::c_void, len: ::size_t) -> ::c_int; + + pub fn if_nametoindex(ifname: *const c_char) -> ::c_uint; + pub fn if_indextoname(ifindex: ::c_uint, + ifname: *mut ::c_char) -> *mut ::c_char; + + #[cfg_attr(target_os = "macos", link_name = "lstat$INODE64")] + #[cfg_attr(target_os = "netbsd", link_name = "__lstat50")] + #[cfg_attr(target_os = "freebsd", link_name = "lstat@FBSD_1.0")] + pub fn lstat(path: *const c_char, buf: *mut stat) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "fsync$UNIX2003")] + pub fn fsync(fd: ::c_int) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "setenv$UNIX2003")] + pub fn setenv(name: *const c_char, val: *const c_char, + overwrite: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "unsetenv$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__unsetenv13")] + pub fn unsetenv(name: *const c_char) -> ::c_int; + + pub fn symlink(path1: *const c_char, + path2: *const c_char) -> ::c_int; + + pub fn truncate(path: *const c_char, length: off_t) -> ::c_int; + pub fn ftruncate(fd: ::c_int, length: off_t) -> ::c_int; + + pub fn signal(signum: ::c_int, handler: sighandler_t) -> sighandler_t; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "getrlimit$UNIX2003")] + pub fn getrlimit(resource: ::c_int, rlim: *mut rlimit) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "setrlimit$UNIX2003")] + pub fn setrlimit(resource: ::c_int, rlim: *const rlimit) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getrusage50")] + pub fn getrusage(resource: ::c_int, usage: *mut rusage) -> ::c_int; + + #[cfg_attr(any(target_os = "macos", target_os = "ios"), + link_name = "realpath$DARWIN_EXTSN")] + pub fn realpath(pathname: *const ::c_char, resolved: *mut ::c_char) + -> *mut ::c_char; + + pub fn flock(fd: ::c_int, operation: ::c_int) -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__gettimeofday50")] + #[deprecated( + since="0.2.54", + note= + "The signature of this function is incorrect. \ + If you are using it, please report that in the following issue \ + so that we can evaluate the impact of fixing it: \ + https://github.com/rust-lang/libc/issues/1338" + )] + pub fn gettimeofday(tp: *mut ::timeval, + tz: *mut ::c_void) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__times13")] + pub fn times(buf: *mut ::tms) -> ::clock_t; + + pub fn pthread_self() -> ::pthread_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_join$UNIX2003")] + pub fn pthread_join(native: ::pthread_t, + value: *mut *mut ::c_void) -> ::c_int; + pub fn pthread_exit(value: *mut ::c_void); + pub fn pthread_attr_init(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_destroy(attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_setstacksize(attr: *mut ::pthread_attr_t, + stack_size: ::size_t) -> ::c_int; + pub fn pthread_attr_setdetachstate(attr: *mut ::pthread_attr_t, + state: ::c_int) -> ::c_int; + pub fn pthread_detach(thread: ::pthread_t) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__libc_thr_yield")] + pub fn sched_yield() -> ::c_int; + pub fn pthread_key_create(key: *mut pthread_key_t, + dtor: ::Option) + -> ::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ::c_int; + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ::c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const ::c_void) + -> ::c_int; + pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, + attr: *const pthread_mutexattr_t) -> ::c_int; + pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> ::c_int; + pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> ::c_int; + + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_mutexattr_destroy$UNIX2003")] + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> ::c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, + _type: ::c_int) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_init$UNIX2003")] + pub fn pthread_cond_init(cond: *mut pthread_cond_t, + attr: *const pthread_condattr_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_wait$UNIX2003")] + pub fn pthread_cond_wait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_cond_timedwait$UNIX2003")] + pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t, + lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> ::c_int; + pub fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> ::c_int; + pub fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_init$UNIX2003")] + pub fn pthread_rwlock_init(lock: *mut pthread_rwlock_t, + attr: *const pthread_rwlockattr_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_destroy$UNIX2003")] + pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_rdlock$UNIX2003")] + pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_tryrdlock$UNIX2003")] + pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_wrlock$UNIX2003")] + pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_trywrlock$UNIX2003")] + pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_rwlock_unlock$UNIX2003")] + pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> ::c_int; + pub fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> ::c_int; + pub fn pthread_rwlockattr_destroy(attr: *mut pthread_rwlockattr_t) + -> ::c_int; + #[cfg_attr(all(target_os = "linux", not(target_env = "musl")), + link_name = "__xpg_strerror_r")] + pub fn strerror_r(errnum: ::c_int, buf: *mut c_char, + buflen: ::size_t) -> ::c_int; + + #[cfg_attr(target_os = "illumos", link_name = "__xnet_getsockopt")] + pub fn getsockopt(sockfd: ::c_int, + level: ::c_int, + optname: ::c_int, + optval: *mut ::c_void, + optlen: *mut ::socklen_t) -> ::c_int; + pub fn raise(signum: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaction14")] + pub fn sigaction(signum: ::c_int, + act: *const sigaction, + oldact: *mut sigaction) -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__utimes50")] + pub fn utimes(filename: *const ::c_char, + times: *const ::timeval) -> ::c_int; + pub fn dlopen(filename: *const ::c_char, + flag: ::c_int) -> *mut ::c_void; + pub fn dlerror() -> *mut ::c_char; + pub fn dlsym(handle: *mut ::c_void, + symbol: *const ::c_char) -> *mut ::c_void; + pub fn dlclose(handle: *mut ::c_void) -> ::c_int; + pub fn dladdr(addr: *const ::c_void, info: *mut Dl_info) -> ::c_int; + + pub fn getaddrinfo(node: *const c_char, + service: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo) -> ::c_int; + pub fn freeaddrinfo(res: *mut addrinfo); + pub fn gai_strerror(errcode: ::c_int) -> *const ::c_char; + #[cfg_attr(any( + all(target_os = "linux", not(target_env = "musl")), + target_os = "freebsd", + target_os = "dragonfly", + target_os = "haiku"), + link_name = "__res_init")] + #[cfg_attr(any(target_os = "macos", target_os = "ios"), + link_name = "res_9_init")] + pub fn res_init() -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__gmtime_r50")] + pub fn gmtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__localtime_r50")] + pub fn localtime_r(time_p: *const time_t, result: *mut tm) -> *mut tm; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "mktime$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__mktime50")] + pub fn mktime(tm: *mut tm) -> time_t; + #[cfg_attr(target_os = "netbsd", link_name = "__time50")] + pub fn time(time: *mut time_t) -> time_t; + #[cfg_attr(target_os = "netbsd", link_name = "__gmtime50")] + pub fn gmtime(time_p: *const time_t) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__locatime50")] + pub fn localtime(time_p: *const time_t) -> *mut tm; + #[cfg_attr(target_os = "netbsd", link_name = "__difftime50")] + pub fn difftime(time1: time_t, time0: time_t) -> ::c_double; + + #[cfg_attr(target_os = "netbsd", link_name = "__mknod50")] + #[cfg_attr(target_os = "freebsd", link_name = "mknod@FBSD_1.0")] + pub fn mknod(pathname: *const ::c_char, mode: ::mode_t, + dev: ::dev_t) -> ::c_int; + pub fn gethostname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn getservbyname(name: *const ::c_char, + proto: *const ::c_char) -> *mut servent; + pub fn getprotobyname(name: *const ::c_char) -> *mut protoent; + pub fn getprotobynumber(proto: ::c_int) -> *mut protoent; + pub fn chroot(name: *const ::c_char) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "usleep$UNIX2003")] + pub fn usleep(secs: ::c_uint) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "send$UNIX2003")] + pub fn send(socket: ::c_int, buf: *const ::c_void, len: ::size_t, + flags: ::c_int) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "recv$UNIX2003")] + pub fn recv(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int) -> ::ssize_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "putenv$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__putenv50")] + pub fn putenv(string: *mut c_char) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "poll$UNIX2003")] + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "select$1050")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "select$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__select50")] + pub fn select(nfds: ::c_int, + readfs: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut timeval) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__setlocale50")] + pub fn setlocale(category: ::c_int, + locale: *const ::c_char) -> *mut ::c_char; + pub fn localeconv() -> *mut lconv; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sem_wait$UNIX2003")] + pub fn sem_wait(sem: *mut sem_t) -> ::c_int; + pub fn sem_trywait(sem: *mut sem_t) -> ::c_int; + pub fn sem_post(sem: *mut sem_t) -> ::c_int; + pub fn statvfs(path: *const c_char, buf: *mut statvfs) -> ::c_int; + pub fn fstatvfs(fd: ::c_int, buf: *mut statvfs) -> ::c_int; + + pub fn readlink(path: *const c_char, + buf: *mut c_char, + bufsz: ::size_t) + -> ::ssize_t; + + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + pub fn sigemptyset(set: *mut sigset_t) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] + pub fn sigaddset(set: *mut sigset_t, signum: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigfillset14")] + pub fn sigfillset(set: *mut sigset_t) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigdelset14")] + pub fn sigdelset(set: *mut sigset_t, signum: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigismember14")] + pub fn sigismember(set: *const sigset_t, signum: ::c_int) -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__sigprocmask14")] + pub fn sigprocmask(how: ::c_int, + set: *const sigset_t, + oldset: *mut sigset_t) + -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigpending14")] + pub fn sigpending(set: *mut sigset_t) -> ::c_int; + + #[cfg_attr(target_os = "netbsd", link_name = "__timegm50")] + pub fn timegm(tm: *mut ::tm) -> time_t; + + pub fn getsid(pid: pid_t) -> pid_t; + + pub fn sysconf(name: ::c_int) -> ::c_long; + + pub fn mkfifo(path: *const c_char, mode: mode_t) -> ::c_int; + + #[cfg_attr(all(target_os = "macos", target_arch = "x86_64"), + link_name = "pselect$1050")] + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pselect$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__pselect50")] + pub fn pselect(nfds: ::c_int, + readfs: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *const timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn fseeko(stream: *mut ::FILE, + offset: ::off_t, + whence: ::c_int) -> ::c_int; + pub fn ftello(stream: *mut ::FILE) -> ::off_t; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "tcdrain$UNIX2003")] + pub fn tcdrain(fd: ::c_int) -> ::c_int; + pub fn cfgetispeed(termios: *const ::termios) -> ::speed_t; + pub fn cfgetospeed(termios: *const ::termios) -> ::speed_t; + pub fn cfsetispeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int; + pub fn cfsetospeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int; + pub fn tcgetattr(fd: ::c_int, termios: *mut ::termios) -> ::c_int; + pub fn tcsetattr(fd: ::c_int, + optional_actions: ::c_int, + termios: *const ::termios) -> ::c_int; + pub fn tcflow(fd: ::c_int, action: ::c_int) -> ::c_int; + pub fn tcflush(fd: ::c_int, action: ::c_int) -> ::c_int; + pub fn tcgetsid(fd: ::c_int) -> ::pid_t; + pub fn tcsendbreak(fd: ::c_int, duration: ::c_int) -> ::c_int; + pub fn mkstemp(template: *mut ::c_char) -> ::c_int; + pub fn mkdtemp(template: *mut ::c_char) -> *mut ::c_char; + + pub fn tmpnam(ptr: *mut ::c_char) -> *mut ::c_char; + + pub fn openlog(ident: *const ::c_char, logopt: ::c_int, facility: ::c_int); + pub fn closelog(); + pub fn setlogmask(maskpri: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "macos", link_name = "syslog$DARWIN_EXTSN")] + pub fn syslog(priority: ::c_int, message: *const ::c_char, ...); + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "nice$UNIX2003")] + pub fn nice(incr: ::c_int) -> ::c_int; + + pub fn grantpt(fd: ::c_int) -> ::c_int; + pub fn posix_openpt(flags: ::c_int) -> ::c_int; + pub fn ptsname(fd: ::c_int) -> *mut ::c_char; + pub fn unlockpt(fd: ::c_int) -> ::c_int; + + pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn getline (lineptr: *mut *mut c_char, n: *mut size_t, + stream: *mut FILE) -> ssize_t; +} + +cfg_if! { + if #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] { + extern { + pub fn cfmakeraw(termios: *mut ::termios); + pub fn cfsetspeed(termios: *mut ::termios, + speed: ::speed_t) -> ::c_int; + } + } +} + +cfg_if! { + if #[cfg(target_env = "uclibc")] { + mod uclibc; + pub use self::uclibc::*; + } else if #[cfg(target_env = "newlib")] { + mod newlib; + pub use self::newlib::*; + } else if #[cfg(any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))] { + mod notbsd; + pub use self::notbsd::*; + } else if #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd"))] { + mod bsd; + pub use self::bsd::*; + } else if #[cfg(any(target_os = "solaris", + target_os = "illumos"))] { + mod solarish; + pub use self::solarish::*; + } else if #[cfg(target_os = "haiku")] { + mod haiku; + pub use self::haiku::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use self::hermit::*; + } else if #[cfg(target_os = "redox")] { + mod redox; + pub use self::redox::*; + } else { + // Unknown target_os + } +} + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/newlib/aarch64/mod.rs b/libc/src/unix/newlib/aarch64/mod.rs new file mode 100644 index 000000000..96f381a39 --- /dev/null +++ b/libc/src/unix/newlib/aarch64/mod.rs @@ -0,0 +1,5 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +pub type c_long = i64; +pub type c_ulong = u64; diff --git a/libc/src/unix/newlib/align.rs b/libc/src/unix/newlib/align.rs new file mode 100644 index 000000000..c018fbcbb --- /dev/null +++ b/libc/src/unix/newlib/align.rs @@ -0,0 +1,61 @@ +macro_rules! expand_align { + () => { + s! { + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))), + repr(align(8)))] + pub struct pthread_mutex_t { // Unverified + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))), + repr(align(8)))] + pub struct pthread_rwlock_t { // Unverified + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[cfg_attr(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64"), + repr(align(4)))] + #[cfg_attr(not(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64")), + repr(align(8)))] + pub struct pthread_mutexattr_t { // Unverified + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(8))] + pub struct pthread_cond_t { // Unverified + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { // Unverified + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + } +} diff --git a/libc/src/unix/newlib/arm/mod.rs b/libc/src/unix/newlib/arm/mod.rs new file mode 100644 index 000000000..372a48c4b --- /dev/null +++ b/libc/src/unix/newlib/arm/mod.rs @@ -0,0 +1,5 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +pub type c_long = i32; +pub type c_ulong = u32; diff --git a/libc/src/unix/newlib/mod.rs b/libc/src/unix/newlib/mod.rs new file mode 100644 index 000000000..c9a25a35d --- /dev/null +++ b/libc/src/unix/newlib/mod.rs @@ -0,0 +1,707 @@ +pub type blkcnt_t = i32; +pub type blksize_t = i32; +pub type clock_t = i32; +pub type clockid_t = ::c_ulong; +pub type dev_t = u32; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u32; +pub type id_t = u32; +pub type ino_t = u32; +pub type key_t = ::c_int; +pub type loff_t = ::c_longlong; +pub type mode_t = ::c_uint; +pub type nfds_t = u32; +pub type nlink_t = ::c_ushort; +pub type off_t = i64; +pub type pthread_t = ::c_ulong; +pub type pthread_key_t = ::c_uint; +pub type rlim_t = u32; +pub type sa_family_t = u8; +pub type socklen_t = u32; +pub type speed_t = u32; +pub type suseconds_t = i32; +pub type tcflag_t = ::c_uint; +pub type time_t = i32; +pub type useconds_t = u32; + +s! { + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { // Unverified + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + pub __ss_padding: [u8; 26], + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct linger { + pub l_onoff: ::c_int, + pub l_linger: ::c_int, + } + + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct hostent { + pub h_name: *mut ::c_char, + pub h_aliases: *mut *mut ::c_char, + pub h_addrtype: ::c_int, + pub h_length: ::c_int, + pub h_addr_list: *mut *mut ::c_char, + pub h_addr: *mut ::c_char, + } + + pub struct pollfd { + pub fd: ::c_int, + pub events: ::c_int, + pub revents: ::c_int, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_atime: time_t, + pub st_spare1: ::c_long, + pub st_mtime: time_t, + pub st_spare2: ::c_long, + pub st_ctime: time_t, + pub st_spare3: ::c_long, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_spare4: [::c_long; 2usize], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: fsblkcnt_t, + pub f_bfree: fsblkcnt_t, + pub f_bavail: fsblkcnt_t, + pub f_files: fsfilcnt_t, + pub f_ffree: fsfilcnt_t, + pub f_favail: fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct sigset_t { + __val: [::c_ulong; 16], + } + + pub struct sigaction { + pub sa_handler: extern fn(arg1: ::c_int), + pub sa_mask: sigset_t, + pub sa_flags: ::c_int, + } + + pub struct dirent { + pub d_ino: ino_t, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256usize], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: usize, + } + + pub struct fd_set { // Unverified + fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct passwd { // Unverified + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct termios { // Unverified + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct sem_t { // Unverified + __size: [::c_char; 16], + } + + pub struct Dl_info { // Unverified + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct utsname { // Unverified + pub sysname: [::c_char; 65], + pub nodename: [::c_char; 65], + pub release: [::c_char; 65], + pub version: [::c_char; 65], + pub machine: [::c_char; 65], + pub domainname: [::c_char; 65] + } + + pub struct cpu_set_t { // Unverified + bits: [u32; 32], + } + + pub struct pthread_attr_t { // Unverified + __size: [u64; 7] + } + + pub struct pthread_rwlockattr_t { // Unverified + __lockkind: ::c_int, + __pshared: ::c_int, + } +} + +// unverified constants +align_const! { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], + }; +} +pub const NCCS: usize = 32; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 56; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 32; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const __PTHREAD_MUTEX_HAVE_PREV: usize = 1; +pub const __PTHREAD_RWLOCK_INT_FLAGS_SHARED: usize = 1; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const FD_SETSIZE: usize = 1024; +// intentionally not public, only used for fd_set +const ULONG_SIZE: usize = 32; + +// Other constants +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const EDEADLK: ::c_int = 45; +pub const ENOLCK: ::c_int = 46; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENOLINK: ::c_int = 67; +pub const EPROTO: ::c_int = 71; +pub const EMULTIHOP: ::c_int = 74; +pub const EBADMSG: ::c_int = 77; +pub const EFTYPE: ::c_int = 79; +pub const ENOSYS: ::c_int = 88; +pub const ENOTEMPTY: ::c_int = 90; +pub const ENAMETOOLONG: ::c_int = 91; +pub const ELOOP: ::c_int = 92; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EAFNOSUPPORT: ::c_int = 106; +pub const EPROTOTYPE: ::c_int = 107; +pub const ENOTSOCK: ::c_int = 108; +pub const ENOPROTOOPT: ::c_int = 109; +pub const ECONNREFUSED: ::c_int = 111; +pub const EADDRINUSE: ::c_int = 112; +pub const ECONNABORTED: ::c_int = 113; +pub const ENETUNREACH: ::c_int = 114; +pub const ENETDOWN: ::c_int = 115; +pub const ETIMEDOUT: ::c_int = 116; +pub const EHOSTDOWN: ::c_int = 117; +pub const EHOSTUNREACH: ::c_int = 118; +pub const EINPROGRESS: ::c_int = 119; +pub const EALREADY: ::c_int = 120; +pub const EDESTADDRREQ: ::c_int = 121; +pub const EMSGSIZE: ::c_int = 122; +pub const EPROTONOSUPPORT: ::c_int = 123; +pub const EADDRNOTAVAIL: ::c_int = 125; +pub const ENETRESET: ::c_int = 126; +pub const EISCONN: ::c_int = 127; +pub const ENOTCONN: ::c_int = 128; +pub const ETOOMANYREFS: ::c_int = 129; +pub const EDQUOT: ::c_int = 132; +pub const ESTALE: ::c_int = 133; +pub const ENOTSUP: ::c_int = 134; +pub const EILSEQ: ::c_int = 138; +pub const EOVERFLOW: ::c_int = 139; +pub const ECANCELED: ::c_int = 140; +pub const ENOTRECOVERABLE: ::c_int = 141; +pub const EOWNERDEAD: ::c_int = 142; +pub const EWOULDBLOCK: ::c_int = 11; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; +pub const F_GETOWN: ::c_int = 5; +pub const F_SETOWN: ::c_int = 6; +pub const F_GETLK: ::c_int = 7; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; +pub const F_RGETLK: ::c_int = 10; +pub const F_RSETLK: ::c_int = 11; +pub const F_CNVT: ::c_int = 12; +pub const F_RSETLKW: ::c_int = 13; +pub const F_DUPFD_CLOEXEC: ::c_int = 14; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 512; +pub const O_TRUNC: ::c_int = 1024; +pub const O_EXCL: ::c_int = 2048; +pub const O_SYNC: ::c_int = 8192; +pub const O_NONBLOCK: ::c_int = 16384; + +pub const O_ACCMODE: ::c_int = 3; +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; + +pub const RTLD_LAZY: ::c_int = 0x1; + +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; + +pub const FIONBIO: ::c_ulong = 1; +pub const FIOCLEX: ::c_ulong = 0x20006601; + +pub const S_BLKSIZE: ::mode_t = 1024; +pub const S_IREAD: ::mode_t = 256; +pub const S_IWRITE: ::mode_t = 128; +pub const S_IEXEC: ::mode_t = 64; +pub const S_ENFMT: ::mode_t = 1024; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFCHR: ::mode_t = 8192; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFIFO: ::mode_t = 4096; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IRGRP: ::mode_t = 32; +pub const S_IWGRP: ::mode_t = 16; +pub const S_IXGRP: ::mode_t = 8; +pub const S_IROTH: ::mode_t = 4; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IXOTH: ::mode_t = 1; + +pub const SOL_SOCKET: ::c_int = 65535; +pub const SOL_TCP: ::c_int = 6; + +pub const PF_UNSPEC: ::c_int = 0; +pub const PF_INET: ::c_int = 2; +pub const PF_INET6: ::c_int = 23; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_INET: ::c_int = 2; +pub const AF_INET6: ::c_int = 23; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; + +pub const MSG_OOB: ::c_int = 1; +pub const MSG_PEEK: ::c_int = 2; +pub const MSG_DONTWAIT: ::c_int = 4; +pub const MSG_DONTROUTE: ::c_int = 0; +pub const MSG_WAITALL: ::c_int = 0; +pub const MSG_MORE: ::c_int = 0; +pub const MSG_NOSIGNAL: ::c_int = 0; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const SO_BINTIME: ::c_int = 0x2000; +pub const SO_NO_OFFLOAD: ::c_int = 0x4000; +pub const SO_NO_DDP: ::c_int = 0x8000; +pub const SO_REUSEPORT_LB: ::c_int = 0x10000; +pub const SO_LABEL: ::c_int = 0x1009; +pub const SO_PEERLABEL: ::c_int = 0x1010; +pub const SO_LISTENQLIMIT: ::c_int = 0x1011; +pub const SO_LISTENQLEN: ::c_int = 0x1012; +pub const SO_LISTENINCQLEN: ::c_int = 0x1013; +pub const SO_SETFIB: ::c_int = 0x1014; +pub const SO_USER_COOKIE: ::c_int = 0x1015; +pub const SO_PROTOCOL: ::c_int = 0x1016; +pub const SO_PROTOTYPE: ::c_int = SO_PROTOCOL; +pub const SO_VENDOR: ::c_int = 0x80000000; +pub const SO_DEBUG: ::c_int = 0x01; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_TIMESTAMP: ::c_int = 0x0400; +pub const SO_NOSIGPIPE: ::c_int = 0x0800; +pub const SO_ACCEPTFILTER: ::c_int = 0x1000; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; + +pub const SOCK_CLOEXEC: ::c_int = O_CLOEXEC; + +pub const INET_ADDRSTRLEN: ::c_int = 16; + +// https://github. +// com/bminor/newlib/blob/master/newlib/libc/sys/linux/include/net/if.h#L121 +pub const IFF_UP: ::c_int = 0x1; // interface is up +pub const IFF_BROADCAST: ::c_int = 0x2; // broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x4; // turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x8; // is a loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x10; // interface is point-to-point link +pub const IFF_NOTRAILERS: ::c_int = 0x20; // avoid use of trailers +pub const IFF_RUNNING: ::c_int = 0x40; // resources allocated +pub const IFF_NOARP: ::c_int = 0x80; // no address resolution protocol +pub const IFF_PROMISC: ::c_int = 0x100; // receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x200; // receive all multicast packets +pub const IFF_OACTIVE: ::c_int = 0x400; // transmission in progress +pub const IFF_SIMPLEX: ::c_int = 0x800; // can't hear own transmissions +pub const IFF_LINK0: ::c_int = 0x1000; // per link layer defined bit +pub const IFF_LINK1: ::c_int = 0x2000; // per link layer defined bit +pub const IFF_LINK2: ::c_int = 0x4000; // per link layer defined bit +pub const IFF_ALTPHYS: ::c_int = IFF_LINK2; // use alternate physical connection +pub const IFF_MULTICAST: ::c_int = 0x8000; // supports multicast + +pub const TCP_NODELAY: ::c_int = 8193; +pub const TCP_MAXSEG: ::c_int = 8194; +pub const TCP_NOPUSH: ::c_int = 4; +pub const TCP_NOOPT: ::c_int = 8; +pub const TCP_KEEPIDLE: ::c_int = 256; +pub const TCP_KEEPINTVL: ::c_int = 512; +pub const TCP_KEEPCNT: ::c_int = 1024; + +pub const IP_TOS: ::c_int = 3; +pub const IP_TTL: ::c_int = 8; +pub const IP_MULTICAST_IF: ::c_int = 9; +pub const IP_MULTICAST_TTL: ::c_int = 10; +pub const IP_MULTICAST_LOOP: ::c_int = 11; +pub const IP_ADD_MEMBERSHIP: ::c_int = 11; +pub const IP_DROP_MEMBERSHIP: ::c_int = 12; + +pub const IPV6_UNICAST_HOPS: ::c_int = 4; +pub const IPV6_MULTICAST_IF: ::c_int = 9; +pub const IPV6_MULTICAST_HOPS: ::c_int = 10; +pub const IPV6_MULTICAST_LOOP: ::c_int = 11; +pub const IPV6_V6ONLY: ::c_int = 27; +pub const IPV6_JOIN_GROUP: ::c_int = 12; +pub const IPV6_LEAVE_GROUP: ::c_int = 13; +pub const IPV6_ADD_MEMBERSHIP: ::c_int = 12; +pub const IPV6_DROP_MEMBERSHIP: ::c_int = 13; + +pub const HOST_NOT_FOUND: ::c_int = 1; +pub const NO_DATA: ::c_int = 2; +pub const NO_ADDRESS: ::c_int = 2; +pub const NO_RECOVERY: ::c_int = 3; +pub const TRY_AGAIN: ::c_int = 4; + +pub const AI_PASSIVE: ::c_int = 1; +pub const AI_CANONNAME: ::c_int = 2; +pub const AI_NUMERICHOST: ::c_int = 4; +pub const AI_NUMERICSERV: ::c_int = 0; +pub const AI_ADDRCONFIG: ::c_int = 0; + +pub const NI_MAXHOST: ::c_int = 1025; +pub const NI_MAXSERV: ::c_int = 32; +pub const NI_NOFQDN: ::c_int = 1; +pub const NI_NUMERICHOST: ::c_int = 2; +pub const NI_NAMEREQD: ::c_int = 4; +pub const NI_NUMERICSERV: ::c_int = 0; +pub const NI_DGRAM: ::c_int = 0; + +pub const EAI_FAMILY: ::c_int = -303; +pub const EAI_MEMORY: ::c_int = -304; +pub const EAI_NONAME: ::c_int = -305; +pub const EAI_SOCKTYPE: ::c_int = -307; + +f! { + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn bind(fd: ::c_int, addr: *const sockaddr, len: socklen_t) -> ::c_int; + pub fn closesocket(sockfd: ::c_int) -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn recvfrom(fd: ::c_int, buf: *mut ::c_void, n: usize, flags: ::c_int, + addr: *mut sockaddr, addr_len: *mut socklen_t) -> isize; + pub fn getnameinfo(sa: *const sockaddr, salen: socklen_t, + host: *mut ::c_char, hostlen: socklen_t, + serv: *mut ::c_char, servlen: socklen_t, + flags: ::c_int) -> ::c_int; + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + pub fn fexecve(fd: ::c_int, argv: *const *const ::c_char, + envp: *const *const ::c_char) + -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + // Only tested on ARM so far. Other platforms might have different + // definitions for types and constants. + pub use target_arch_not_implemented; + } +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} +expand_align!(); diff --git a/libc/src/unix/newlib/no_align.rs b/libc/src/unix/newlib/no_align.rs new file mode 100644 index 000000000..316c464ed --- /dev/null +++ b/libc/src/unix/newlib/no_align.rs @@ -0,0 +1,51 @@ +macro_rules! expand_align { + () => { + s! { + pub struct pthread_mutex_t { // Unverified + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_rwlock_t { // Unverified + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + pub struct pthread_mutexattr_t { // Unverified + #[cfg(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64"))] + __align: [::c_int; 0], + #[cfg(not(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64")))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_cond_t { // Unverified + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + pub struct pthread_condattr_t { // Unverified + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + } +} diff --git a/libc/src/unix/no_align.rs b/libc/src/unix/no_align.rs new file mode 100644 index 000000000..f6b9f4c12 --- /dev/null +++ b/libc/src/unix/no_align.rs @@ -0,0 +1,6 @@ +s! { + pub struct in6_addr { + pub s6_addr: [u8; 16], + __align: [u32; 0], + } +} diff --git a/libc/src/unix/notbsd/android/b32/arm.rs b/libc/src/unix/notbsd/android/b32/arm.rs new file mode 100644 index 000000000..1320b16ab --- /dev/null +++ b/libc/src/unix/notbsd/android/b32/arm.rs @@ -0,0 +1,357 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_LARGEFILE: ::c_int = 0o400000; + +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_pause: ::c_long = 29; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS_getdents: ::c_long = 141; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_pivot_root: ::c_long = 218; +pub const SYS_mincore: ::c_long = 219; +pub const SYS_madvise: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_io_setup: ::c_long = 243; +pub const SYS_io_destroy: ::c_long = 244; +pub const SYS_io_getevents: ::c_long = 245; +pub const SYS_io_submit: ::c_long = 246; +pub const SYS_io_cancel: ::c_long = 247; +pub const SYS_exit_group: ::c_long = 248; +pub const SYS_lookup_dcookie: ::c_long = 249; +pub const SYS_epoll_create: ::c_long = 250; +pub const SYS_epoll_ctl: ::c_long = 251; +pub const SYS_epoll_wait: ::c_long = 252; +pub const SYS_remap_file_pages: ::c_long = 253; +pub const SYS_set_tid_address: ::c_long = 256; +pub const SYS_timer_create: ::c_long = 257; +pub const SYS_timer_settime: ::c_long = 258; +pub const SYS_timer_gettime: ::c_long = 259; +pub const SYS_timer_getoverrun: ::c_long = 260; +pub const SYS_timer_delete: ::c_long = 261; +pub const SYS_clock_settime: ::c_long = 262; +pub const SYS_clock_gettime: ::c_long = 263; +pub const SYS_clock_getres: ::c_long = 264; +pub const SYS_clock_nanosleep: ::c_long = 265; +pub const SYS_statfs64: ::c_long = 266; +pub const SYS_fstatfs64: ::c_long = 267; +pub const SYS_tgkill: ::c_long = 268; +pub const SYS_utimes: ::c_long = 269; +pub const SYS_arm_fadvise64_64: ::c_long = 270; +pub const SYS_pciconfig_iobase: ::c_long = 271; +pub const SYS_pciconfig_read: ::c_long = 272; +pub const SYS_pciconfig_write: ::c_long = 273; +pub const SYS_mq_open: ::c_long = 274; +pub const SYS_mq_unlink: ::c_long = 275; +pub const SYS_mq_timedsend: ::c_long = 276; +pub const SYS_mq_timedreceive: ::c_long = 277; +pub const SYS_mq_notify: ::c_long = 278; +pub const SYS_mq_getsetattr: ::c_long = 279; +pub const SYS_waitid: ::c_long = 280; +pub const SYS_socket: ::c_long = 281; +pub const SYS_bind: ::c_long = 282; +pub const SYS_connect: ::c_long = 283; +pub const SYS_listen: ::c_long = 284; +pub const SYS_accept: ::c_long = 285; +pub const SYS_getsockname: ::c_long = 286; +pub const SYS_getpeername: ::c_long = 287; +pub const SYS_socketpair: ::c_long = 288; +pub const SYS_send: ::c_long = 289; +pub const SYS_sendto: ::c_long = 290; +pub const SYS_recv: ::c_long = 291; +pub const SYS_recvfrom: ::c_long = 292; +pub const SYS_shutdown: ::c_long = 293; +pub const SYS_setsockopt: ::c_long = 294; +pub const SYS_getsockopt: ::c_long = 295; +pub const SYS_sendmsg: ::c_long = 296; +pub const SYS_recvmsg: ::c_long = 297; +pub const SYS_semop: ::c_long = 298; +pub const SYS_semget: ::c_long = 299; +pub const SYS_semctl: ::c_long = 300; +pub const SYS_msgsnd: ::c_long = 301; +pub const SYS_msgrcv: ::c_long = 302; +pub const SYS_msgget: ::c_long = 303; +pub const SYS_msgctl: ::c_long = 304; +pub const SYS_shmat: ::c_long = 305; +pub const SYS_shmdt: ::c_long = 306; +pub const SYS_shmget: ::c_long = 307; +pub const SYS_shmctl: ::c_long = 308; +pub const SYS_add_key: ::c_long = 309; +pub const SYS_request_key: ::c_long = 310; +pub const SYS_keyctl: ::c_long = 311; +pub const SYS_semtimedop: ::c_long = 312; +pub const SYS_vserver: ::c_long = 313; +pub const SYS_ioprio_set: ::c_long = 314; +pub const SYS_ioprio_get: ::c_long = 315; +pub const SYS_inotify_init: ::c_long = 316; +pub const SYS_inotify_add_watch: ::c_long = 317; +pub const SYS_inotify_rm_watch: ::c_long = 318; +pub const SYS_mbind: ::c_long = 319; +pub const SYS_get_mempolicy: ::c_long = 320; +pub const SYS_set_mempolicy: ::c_long = 321; +pub const SYS_openat: ::c_long = 322; +pub const SYS_mkdirat: ::c_long = 323; +pub const SYS_mknodat: ::c_long = 324; +pub const SYS_fchownat: ::c_long = 325; +pub const SYS_futimesat: ::c_long = 326; +pub const SYS_fstatat64: ::c_long = 327; +pub const SYS_unlinkat: ::c_long = 328; +pub const SYS_renameat: ::c_long = 329; +pub const SYS_linkat: ::c_long = 330; +pub const SYS_symlinkat: ::c_long = 331; +pub const SYS_readlinkat: ::c_long = 332; +pub const SYS_fchmodat: ::c_long = 333; +pub const SYS_faccessat: ::c_long = 334; +pub const SYS_pselect6: ::c_long = 335; +pub const SYS_ppoll: ::c_long = 336; +pub const SYS_unshare: ::c_long = 337; +pub const SYS_set_robust_list: ::c_long = 338; +pub const SYS_get_robust_list: ::c_long = 339; +pub const SYS_splice: ::c_long = 340; +pub const SYS_arm_sync_file_range: ::c_long = 341; +pub const SYS_tee: ::c_long = 342; +pub const SYS_vmsplice: ::c_long = 343; +pub const SYS_move_pages: ::c_long = 344; +pub const SYS_getcpu: ::c_long = 345; +pub const SYS_epoll_pwait: ::c_long = 346; +pub const SYS_kexec_load: ::c_long = 347; +pub const SYS_utimensat: ::c_long = 348; +pub const SYS_signalfd: ::c_long = 349; +pub const SYS_timerfd_create: ::c_long = 350; +pub const SYS_eventfd: ::c_long = 351; +pub const SYS_fallocate: ::c_long = 352; +pub const SYS_timerfd_settime: ::c_long = 353; +pub const SYS_timerfd_gettime: ::c_long = 354; +pub const SYS_signalfd4: ::c_long = 355; +pub const SYS_eventfd2: ::c_long = 356; +pub const SYS_epoll_create1: ::c_long = 357; +pub const SYS_dup3: ::c_long = 358; +pub const SYS_pipe2: ::c_long = 359; +pub const SYS_inotify_init1: ::c_long = 360; +pub const SYS_preadv: ::c_long = 361; +pub const SYS_pwritev: ::c_long = 362; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 363; +pub const SYS_perf_event_open: ::c_long = 364; +pub const SYS_recvmmsg: ::c_long = 365; +pub const SYS_accept4: ::c_long = 366; +pub const SYS_fanotify_init: ::c_long = 367; +pub const SYS_fanotify_mark: ::c_long = 368; +pub const SYS_prlimit64: ::c_long = 369; +pub const SYS_name_to_handle_at: ::c_long = 370; +pub const SYS_open_by_handle_at: ::c_long = 371; +pub const SYS_clock_adjtime: ::c_long = 372; +pub const SYS_syncfs: ::c_long = 373; +pub const SYS_sendmmsg: ::c_long = 374; +pub const SYS_setns: ::c_long = 375; +pub const SYS_process_vm_readv: ::c_long = 376; +pub const SYS_process_vm_writev: ::c_long = 377; +pub const SYS_kcmp: ::c_long = 378; +pub const SYS_finit_module: ::c_long = 379; +pub const SYS_sched_setattr: ::c_long = 380; +pub const SYS_sched_getattr: ::c_long = 381; +pub const SYS_renameat2: ::c_long = 382; +pub const SYS_seccomp: ::c_long = 383; +pub const SYS_getrandom: ::c_long = 384; +pub const SYS_memfd_create: ::c_long = 385; +pub const SYS_bpf: ::c_long = 386; +pub const SYS_execveat: ::c_long = 387; +pub const SYS_userfaultfd: ::c_long = 388; +pub const SYS_membarrier: ::c_long = 389; +pub const SYS_mlock2: ::c_long = 390; +pub const SYS_copy_file_range: ::c_long = 391; +pub const SYS_preadv2: ::c_long = 392; +pub const SYS_pwritev2: ::c_long = 393; +pub const SYS_pkey_mprotect: ::c_long = 394; +pub const SYS_pkey_alloc: ::c_long = 395; +pub const SYS_pkey_free: ::c_long = 396; diff --git a/libc/src/unix/notbsd/android/b32/mod.rs b/libc/src/unix/notbsd/android/b32/mod.rs new file mode 100644 index 000000000..a8cc51b22 --- /dev/null +++ b/libc/src/unix/notbsd/android/b32/mod.rs @@ -0,0 +1,214 @@ +// The following definitions are correct for arm and i686, +// but may be wrong for mips + +pub type c_long = i32; +pub type c_ulong = u32; +pub type mode_t = u16; +pub type off64_t = ::c_longlong; +pub type sigset_t = ::c_ulong; +pub type socklen_t = i32; +pub type time64_t = i64; + +s! { + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_ulong, + pub sa_restorer: ::Option, + } + + pub struct rlimit64 { + pub rlim_cur: u64, + pub rlim_max: u64, + } + + pub struct stat { + pub st_dev: ::c_ulonglong, + __pad0: [::c_uchar; 4], + __st_ino: ::ino_t, + pub st_mode: ::c_uint, + pub st_nlink: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulonglong, + __pad3: [::c_uchar; 4], + pub st_size: ::c_longlong, + pub st_blksize: ::blksize_t, + pub st_blocks: ::c_ulonglong, + pub st_atime: ::c_ulong, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::c_ulong, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::c_ulong, + pub st_ctime_nsec: ::c_ulong, + pub st_ino: ::c_ulonglong, + } + + pub struct stat64 { + pub st_dev: ::c_ulonglong, + __pad0: [::c_uchar; 4], + __st_ino: ::ino_t, + pub st_mode: ::c_uint, + pub st_nlink: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulonglong, + __pad3: [::c_uchar; 4], + pub st_size: ::c_longlong, + pub st_blksize: ::blksize_t, + pub st_blocks: ::c_ulonglong, + pub st_atime: ::c_ulong, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::c_ulong, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::c_ulong, + pub st_ctime_nsec: ::c_ulong, + pub st_ino: ::c_ulonglong, + } + + pub struct statfs64 { + pub f_type: u32, + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + f_fsid: [u32; 2], + pub f_namelen: u32, + pub f_frsize: u32, + pub f_flags: u32, + pub f_spare: [u32; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::c_ulong, + pub f_bfree: ::c_ulong, + pub f_bavail: ::c_ulong, + pub f_files: ::c_ulong, + pub f_ffree: ::c_ulong, + pub f_favail: ::c_ulong, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct pthread_attr_t { + pub flags: ::uint32_t, + pub stack_base: *mut ::c_void, + pub stack_size: ::size_t, + pub guard_size: ::size_t, + pub sched_policy: ::int32_t, + pub sched_priority: ::int32_t, + } + + pub struct pthread_mutex_t { value: ::c_int } + + pub struct pthread_cond_t { value: ::c_int } + + pub struct pthread_rwlock_t { + lock: pthread_mutex_t, + cond: pthread_cond_t, + numLocks: ::c_int, + writerThreadId: ::c_int, + pendingReaders: ::c_int, + pendingWriters: ::c_int, + attr: i32, + __reserved: [::c_char; 12], + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct statfs { + pub f_type: ::uint32_t, + pub f_bsize: ::uint32_t, + pub f_blocks: ::uint64_t, + pub f_bfree: ::uint64_t, + pub f_bavail: ::uint64_t, + pub f_files: ::uint64_t, + pub f_ffree: ::uint64_t, + pub f_fsid: ::__fsid_t, + pub f_namelen: ::uint32_t, + pub f_frsize: ::uint32_t, + pub f_flags: ::uint32_t, + pub f_spare: [::uint32_t; 4], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 8], + } +} + +pub const RTLD_GLOBAL: ::c_int = 2; +pub const RTLD_NOW: ::c_int = 0; +pub const RTLD_DEFAULT: *mut ::c_void = -1isize as *mut ::c_void; + +pub const PTRACE_GETFPREGS: ::c_int = 14; +pub const PTRACE_SETFPREGS: ::c_int = 15; +pub const PTRACE_GETREGS: ::c_int = 12; +pub const PTRACE_SETREGS: ::c_int = 13; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + value: 0, +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + value: 0, +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + lock: PTHREAD_MUTEX_INITIALIZER, + cond: PTHREAD_COND_INITIALIZER, + numLocks: 0, + writerThreadId: 0, + pendingReaders: 0, + pendingWriters: 0, + attr: 0, + __reserved: [0; 12], +}; +pub const PTHREAD_STACK_MIN: ::size_t = 4096 * 2; +pub const CPU_SETSIZE: ::size_t = 32; +pub const __CPU_BITS: ::size_t = 32; + +pub const UT_LINESIZE: usize = 8; +pub const UT_NAMESIZE: usize = 8; +pub const UT_HOSTSIZE: usize = 16; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +extern { + pub fn timegm64(tm: *const ::tm) -> ::time64_t; +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/android/b32/x86.rs b/libc/src/unix/notbsd/android/b32/x86.rs new file mode 100644 index 000000000..a56fa0045 --- /dev/null +++ b/libc/src/unix/notbsd/android/b32/x86.rs @@ -0,0 +1,415 @@ +pub type c_char = i8; +pub type wchar_t = i32; + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const O_LARGEFILE: ::c_int = 0o0100000; + +pub const MAP_32BIT: ::c_int = 0x40; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86old: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +// FIXME: SYS__llseek is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +// FIXME: SYS__newselect is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +// FIXME: SYS__llseek is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_vm86: ::c_long = 166; +pub const SYS_query_module: ::c_long = 167; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_getpmsg: ::c_long = 188; +pub const SYS_putpmsg: ::c_long = 189; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_pivot_root: ::c_long = 217; +pub const SYS_mincore: ::c_long = 218; +pub const SYS_madvise: ::c_long = 219; +pub const SYS_getdents64: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_set_thread_area: ::c_long = 243; +pub const SYS_get_thread_area: ::c_long = 244; +pub const SYS_io_setup: ::c_long = 245; +pub const SYS_io_destroy: ::c_long = 246; +pub const SYS_io_getevents: ::c_long = 247; +pub const SYS_io_submit: ::c_long = 248; +pub const SYS_io_cancel: ::c_long = 249; +pub const SYS_fadvise64: ::c_long = 250; +pub const SYS_exit_group: ::c_long = 252; +pub const SYS_lookup_dcookie: ::c_long = 253; +pub const SYS_epoll_create: ::c_long = 254; +pub const SYS_epoll_ctl: ::c_long = 255; +pub const SYS_epoll_wait: ::c_long = 256; +pub const SYS_remap_file_pages: ::c_long = 257; +pub const SYS_set_tid_address: ::c_long = 258; +pub const SYS_timer_create: ::c_long = 259; +pub const SYS_timer_settime: ::c_long = 260; +pub const SYS_timer_gettime: ::c_long = 261; +pub const SYS_timer_getoverrun: ::c_long = 262; +pub const SYS_timer_delete: ::c_long = 263; +pub const SYS_clock_settime: ::c_long = 264; +pub const SYS_clock_gettime: ::c_long = 265; +pub const SYS_clock_getres: ::c_long = 266; +pub const SYS_clock_nanosleep: ::c_long = 267; +pub const SYS_statfs64: ::c_long = 268; +pub const SYS_fstatfs64: ::c_long = 269; +pub const SYS_tgkill: ::c_long = 270; +pub const SYS_utimes: ::c_long = 271; +pub const SYS_fadvise64_64: ::c_long = 272; +pub const SYS_vserver: ::c_long = 273; +pub const SYS_mbind: ::c_long = 274; +pub const SYS_get_mempolicy: ::c_long = 275; +pub const SYS_set_mempolicy: ::c_long = 276; +pub const SYS_mq_open: ::c_long = 277; +pub const SYS_mq_unlink: ::c_long = 278; +pub const SYS_mq_timedsend: ::c_long = 279; +pub const SYS_mq_timedreceive: ::c_long = 280; +pub const SYS_mq_notify: ::c_long = 281; +pub const SYS_mq_getsetattr: ::c_long = 282; +pub const SYS_kexec_load: ::c_long = 283; +pub const SYS_waitid: ::c_long = 284; +pub const SYS_add_key: ::c_long = 286; +pub const SYS_request_key: ::c_long = 287; +pub const SYS_keyctl: ::c_long = 288; +pub const SYS_ioprio_set: ::c_long = 289; +pub const SYS_ioprio_get: ::c_long = 290; +pub const SYS_inotify_init: ::c_long = 291; +pub const SYS_inotify_add_watch: ::c_long = 292; +pub const SYS_inotify_rm_watch: ::c_long = 293; +pub const SYS_migrate_pages: ::c_long = 294; +pub const SYS_openat: ::c_long = 295; +pub const SYS_mkdirat: ::c_long = 296; +pub const SYS_mknodat: ::c_long = 297; +pub const SYS_fchownat: ::c_long = 298; +pub const SYS_futimesat: ::c_long = 299; +pub const SYS_fstatat64: ::c_long = 300; +pub const SYS_unlinkat: ::c_long = 301; +pub const SYS_renameat: ::c_long = 302; +pub const SYS_linkat: ::c_long = 303; +pub const SYS_symlinkat: ::c_long = 304; +pub const SYS_readlinkat: ::c_long = 305; +pub const SYS_fchmodat: ::c_long = 306; +pub const SYS_faccessat: ::c_long = 307; +pub const SYS_pselect6: ::c_long = 308; +pub const SYS_ppoll: ::c_long = 309; +pub const SYS_unshare: ::c_long = 310; +pub const SYS_set_robust_list: ::c_long = 311; +pub const SYS_get_robust_list: ::c_long = 312; +pub const SYS_splice: ::c_long = 313; +pub const SYS_sync_file_range: ::c_long = 314; +pub const SYS_tee: ::c_long = 315; +pub const SYS_vmsplice: ::c_long = 316; +pub const SYS_move_pages: ::c_long = 317; +pub const SYS_getcpu: ::c_long = 318; +pub const SYS_epoll_pwait: ::c_long = 319; +pub const SYS_utimensat: ::c_long = 320; +pub const SYS_signalfd: ::c_long = 321; +pub const SYS_timerfd_create: ::c_long = 322; +pub const SYS_eventfd: ::c_long = 323; +pub const SYS_fallocate: ::c_long = 324; +pub const SYS_timerfd_settime: ::c_long = 325; +pub const SYS_timerfd_gettime: ::c_long = 326; +pub const SYS_signalfd4: ::c_long = 327; +pub const SYS_eventfd2: ::c_long = 328; +pub const SYS_epoll_create1: ::c_long = 329; +pub const SYS_dup3: ::c_long = 330; +pub const SYS_pipe2: ::c_long = 331; +pub const SYS_inotify_init1: ::c_long = 332; +pub const SYS_preadv: ::c_long = 333; +pub const SYS_pwritev: ::c_long = 334; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 335; +pub const SYS_perf_event_open: ::c_long = 336; +pub const SYS_recvmmsg: ::c_long = 337; +pub const SYS_fanotify_init: ::c_long = 338; +pub const SYS_fanotify_mark: ::c_long = 339; +pub const SYS_prlimit64: ::c_long = 340; +pub const SYS_name_to_handle_at: ::c_long = 341; +pub const SYS_open_by_handle_at: ::c_long = 342; +pub const SYS_clock_adjtime: ::c_long = 343; +pub const SYS_syncfs: ::c_long = 344; +pub const SYS_sendmmsg: ::c_long = 345; +pub const SYS_setns: ::c_long = 346; +pub const SYS_process_vm_readv: ::c_long = 347; +pub const SYS_process_vm_writev: ::c_long = 348; +pub const SYS_kcmp: ::c_long = 349; +pub const SYS_finit_module: ::c_long = 350; +pub const SYS_sched_setattr: ::c_long = 351; +pub const SYS_sched_getattr: ::c_long = 352; +pub const SYS_renameat2: ::c_long = 353; +pub const SYS_seccomp: ::c_long = 354; +pub const SYS_getrandom: ::c_long = 355; +pub const SYS_memfd_create: ::c_long = 356; +pub const SYS_bpf: ::c_long = 357; +pub const SYS_execveat: ::c_long = 358; +pub const SYS_socket: ::c_long = 359; +pub const SYS_socketpair: ::c_long = 360; +pub const SYS_bind: ::c_long = 361; +pub const SYS_connect: ::c_long = 362; +pub const SYS_listen: ::c_long = 363; +pub const SYS_accept4: ::c_long = 364; +pub const SYS_getsockopt: ::c_long = 365; +pub const SYS_setsockopt: ::c_long = 366; +pub const SYS_getsockname: ::c_long = 367; +pub const SYS_getpeername: ::c_long = 368; +pub const SYS_sendto: ::c_long = 369; +pub const SYS_sendmsg: ::c_long = 370; +pub const SYS_recvfrom: ::c_long = 371; +pub const SYS_recvmsg: ::c_long = 372; +pub const SYS_shutdown: ::c_long = 373; +pub const SYS_userfaultfd: ::c_long = 374; +pub const SYS_membarrier: ::c_long = 375; +pub const SYS_mlock2: ::c_long = 376; +pub const SYS_copy_file_range: ::c_long = 377; +pub const SYS_preadv2: ::c_long = 378; +pub const SYS_pwritev2: ::c_long = 379; +pub const SYS_pkey_mprotect: ::c_long = 380; +pub const SYS_pkey_alloc: ::c_long = 381; +pub const SYS_pkey_free: ::c_long = 382; + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: ::c_int = 0; +pub const ECX: ::c_int = 1; +pub const EDX: ::c_int = 2; +pub const ESI: ::c_int = 3; +pub const EDI: ::c_int = 4; +pub const EBP: ::c_int = 5; +pub const EAX: ::c_int = 6; +pub const DS: ::c_int = 7; +pub const ES: ::c_int = 8; +pub const FS: ::c_int = 9; +pub const GS: ::c_int = 10; +pub const ORIG_EAX: ::c_int = 11; +pub const EIP: ::c_int = 12; +pub const CS: ::c_int = 13; +pub const EFL: ::c_int = 14; +pub const UESP: ::c_int = 15; +pub const SS: ::c_int = 16; diff --git a/libc/src/unix/notbsd/android/b64/aarch64.rs b/libc/src/unix/notbsd/android/b64/aarch64.rs new file mode 100644 index 000000000..44dfee640 --- /dev/null +++ b/libc/src/unix/notbsd/android/b64/aarch64.rs @@ -0,0 +1,325 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::c_uint, + pub st_nlink: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad1: ::c_ulong, + pub st_size: ::off64_t, + pub st_blksize: ::c_int, + __pad2: ::c_int, + pub st_blocks: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_ulong, + __unused4: ::c_uint, + __unused5: ::c_uint, + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::c_uint, + pub st_nlink: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad1: ::c_ulong, + pub st_size: ::off64_t, + pub st_blksize: ::c_int, + __pad2: ::c_int, + pub st_blocks: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_ulong, + __unused4: ::c_uint, + __unused5: ::c_uint, + } +} + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_LARGEFILE: ::c_int = 0o400000; + +pub const SIGSTKSZ: ::size_t = 16384; +pub const MINSIGSTKSZ: ::size_t = 5120; + +pub const SYS_io_setup: ::c_long = 0; +pub const SYS_io_destroy: ::c_long = 1; +pub const SYS_io_submit: ::c_long = 2; +pub const SYS_io_cancel: ::c_long = 3; +pub const SYS_io_getevents: ::c_long = 4; +pub const SYS_setxattr: ::c_long = 5; +pub const SYS_lsetxattr: ::c_long = 6; +pub const SYS_fsetxattr: ::c_long = 7; +pub const SYS_getxattr: ::c_long = 8; +pub const SYS_lgetxattr: ::c_long = 9; +pub const SYS_fgetxattr: ::c_long = 10; +pub const SYS_listxattr: ::c_long = 11; +pub const SYS_llistxattr: ::c_long = 12; +pub const SYS_flistxattr: ::c_long = 13; +pub const SYS_removexattr: ::c_long = 14; +pub const SYS_lremovexattr: ::c_long = 15; +pub const SYS_fremovexattr: ::c_long = 16; +pub const SYS_getcwd: ::c_long = 17; +pub const SYS_lookup_dcookie: ::c_long = 18; +pub const SYS_eventfd2: ::c_long = 19; +pub const SYS_epoll_create1: ::c_long = 20; +pub const SYS_epoll_ctl: ::c_long = 21; +pub const SYS_epoll_pwait: ::c_long = 22; +pub const SYS_dup: ::c_long = 23; +pub const SYS_dup3: ::c_long = 24; +pub const SYS_inotify_init1: ::c_long = 26; +pub const SYS_inotify_add_watch: ::c_long = 27; +pub const SYS_inotify_rm_watch: ::c_long = 28; +pub const SYS_ioctl: ::c_long = 29; +pub const SYS_ioprio_set: ::c_long = 30; +pub const SYS_ioprio_get: ::c_long = 31; +pub const SYS_flock: ::c_long = 32; +pub const SYS_mknodat: ::c_long = 33; +pub const SYS_mkdirat: ::c_long = 34; +pub const SYS_unlinkat: ::c_long = 35; +pub const SYS_symlinkat: ::c_long = 36; +pub const SYS_linkat: ::c_long = 37; +pub const SYS_renameat: ::c_long = 38; +pub const SYS_umount2: ::c_long = 39; +pub const SYS_mount: ::c_long = 40; +pub const SYS_pivot_root: ::c_long = 41; +pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_fallocate: ::c_long = 47; +pub const SYS_faccessat: ::c_long = 48; +pub const SYS_chdir: ::c_long = 49; +pub const SYS_fchdir: ::c_long = 50; +pub const SYS_chroot: ::c_long = 51; +pub const SYS_fchmod: ::c_long = 52; +pub const SYS_fchmodat: ::c_long = 53; +pub const SYS_fchownat: ::c_long = 54; +pub const SYS_fchown: ::c_long = 55; +pub const SYS_openat: ::c_long = 56; +pub const SYS_close: ::c_long = 57; +pub const SYS_vhangup: ::c_long = 58; +pub const SYS_pipe2: ::c_long = 59; +pub const SYS_quotactl: ::c_long = 60; +pub const SYS_getdents64: ::c_long = 61; +pub const SYS_read: ::c_long = 63; +pub const SYS_write: ::c_long = 64; +pub const SYS_readv: ::c_long = 65; +pub const SYS_writev: ::c_long = 66; +pub const SYS_pread64: ::c_long = 67; +pub const SYS_pwrite64: ::c_long = 68; +pub const SYS_preadv: ::c_long = 69; +pub const SYS_pwritev: ::c_long = 70; +pub const SYS_pselect6: ::c_long = 72; +pub const SYS_ppoll: ::c_long = 73; +pub const SYS_signalfd4: ::c_long = 74; +pub const SYS_vmsplice: ::c_long = 75; +pub const SYS_splice: ::c_long = 76; +pub const SYS_tee: ::c_long = 77; +pub const SYS_readlinkat: ::c_long = 78; +pub const SYS_sync: ::c_long = 81; +pub const SYS_fsync: ::c_long = 82; +pub const SYS_fdatasync: ::c_long = 83; +pub const SYS_sync_file_range: ::c_long = 84; +pub const SYS_timerfd_create: ::c_long = 85; +pub const SYS_timerfd_settime: ::c_long = 86; +pub const SYS_timerfd_gettime: ::c_long = 87; +pub const SYS_utimensat: ::c_long = 88; +pub const SYS_acct: ::c_long = 89; +pub const SYS_capget: ::c_long = 90; +pub const SYS_capset: ::c_long = 91; +pub const SYS_personality: ::c_long = 92; +pub const SYS_exit: ::c_long = 93; +pub const SYS_exit_group: ::c_long = 94; +pub const SYS_waitid: ::c_long = 95; +pub const SYS_set_tid_address: ::c_long = 96; +pub const SYS_unshare: ::c_long = 97; +pub const SYS_futex: ::c_long = 98; +pub const SYS_set_robust_list: ::c_long = 99; +pub const SYS_get_robust_list: ::c_long = 100; +pub const SYS_nanosleep: ::c_long = 101; +pub const SYS_getitimer: ::c_long = 102; +pub const SYS_setitimer: ::c_long = 103; +pub const SYS_kexec_load: ::c_long = 104; +pub const SYS_init_module: ::c_long = 105; +pub const SYS_delete_module: ::c_long = 106; +pub const SYS_timer_create: ::c_long = 107; +pub const SYS_timer_gettime: ::c_long = 108; +pub const SYS_timer_getoverrun: ::c_long = 109; +pub const SYS_timer_settime: ::c_long = 110; +pub const SYS_timer_delete: ::c_long = 111; +pub const SYS_clock_settime: ::c_long = 112; +pub const SYS_clock_gettime: ::c_long = 113; +pub const SYS_clock_getres: ::c_long = 114; +pub const SYS_clock_nanosleep: ::c_long = 115; +pub const SYS_syslog: ::c_long = 116; +pub const SYS_ptrace: ::c_long = 117; +pub const SYS_sched_setparam: ::c_long = 118; +pub const SYS_sched_setscheduler: ::c_long = 119; +pub const SYS_sched_getscheduler: ::c_long = 120; +pub const SYS_sched_getparam: ::c_long = 121; +pub const SYS_sched_setaffinity: ::c_long = 122; +pub const SYS_sched_getaffinity: ::c_long = 123; +pub const SYS_sched_yield: ::c_long = 124; +pub const SYS_sched_get_priority_max: ::c_long = 125; +pub const SYS_sched_get_priority_min: ::c_long = 126; +pub const SYS_sched_rr_get_interval: ::c_long = 127; +pub const SYS_restart_syscall: ::c_long = 128; +pub const SYS_kill: ::c_long = 129; +pub const SYS_tkill: ::c_long = 130; +pub const SYS_tgkill: ::c_long = 131; +pub const SYS_sigaltstack: ::c_long = 132; +pub const SYS_rt_sigsuspend: ::c_long = 133; +pub const SYS_rt_sigaction: ::c_long = 134; +pub const SYS_rt_sigprocmask: ::c_long = 135; +pub const SYS_rt_sigpending: ::c_long = 136; +pub const SYS_rt_sigtimedwait: ::c_long = 137; +pub const SYS_rt_sigqueueinfo: ::c_long = 138; +pub const SYS_rt_sigreturn: ::c_long = 139; +pub const SYS_setpriority: ::c_long = 140; +pub const SYS_getpriority: ::c_long = 141; +pub const SYS_reboot: ::c_long = 142; +pub const SYS_setregid: ::c_long = 143; +pub const SYS_setgid: ::c_long = 144; +pub const SYS_setreuid: ::c_long = 145; +pub const SYS_setuid: ::c_long = 146; +pub const SYS_setresuid: ::c_long = 147; +pub const SYS_getresuid: ::c_long = 148; +pub const SYS_setresgid: ::c_long = 149; +pub const SYS_getresgid: ::c_long = 150; +pub const SYS_setfsuid: ::c_long = 151; +pub const SYS_setfsgid: ::c_long = 152; +pub const SYS_times: ::c_long = 153; +pub const SYS_setpgid: ::c_long = 154; +pub const SYS_getpgid: ::c_long = 155; +pub const SYS_getsid: ::c_long = 156; +pub const SYS_setsid: ::c_long = 157; +pub const SYS_getgroups: ::c_long = 158; +pub const SYS_setgroups: ::c_long = 159; +pub const SYS_uname: ::c_long = 160; +pub const SYS_sethostname: ::c_long = 161; +pub const SYS_setdomainname: ::c_long = 162; +pub const SYS_getrlimit: ::c_long = 163; +pub const SYS_setrlimit: ::c_long = 164; +pub const SYS_getrusage: ::c_long = 165; +pub const SYS_umask: ::c_long = 166; +pub const SYS_prctl: ::c_long = 167; +pub const SYS_getcpu: ::c_long = 168; +pub const SYS_gettimeofday: ::c_long = 169; +pub const SYS_settimeofday: ::c_long = 170; +pub const SYS_adjtimex: ::c_long = 171; +pub const SYS_getpid: ::c_long = 172; +pub const SYS_getppid: ::c_long = 173; +pub const SYS_getuid: ::c_long = 174; +pub const SYS_geteuid: ::c_long = 175; +pub const SYS_getgid: ::c_long = 176; +pub const SYS_getegid: ::c_long = 177; +pub const SYS_gettid: ::c_long = 178; +pub const SYS_sysinfo: ::c_long = 179; +pub const SYS_mq_open: ::c_long = 180; +pub const SYS_mq_unlink: ::c_long = 181; +pub const SYS_mq_timedsend: ::c_long = 182; +pub const SYS_mq_timedreceive: ::c_long = 183; +pub const SYS_mq_notify: ::c_long = 184; +pub const SYS_mq_getsetattr: ::c_long = 185; +pub const SYS_msgget: ::c_long = 186; +pub const SYS_msgctl: ::c_long = 187; +pub const SYS_msgrcv: ::c_long = 188; +pub const SYS_msgsnd: ::c_long = 189; +pub const SYS_semget: ::c_long = 190; +pub const SYS_semctl: ::c_long = 191; +pub const SYS_semtimedop: ::c_long = 192; +pub const SYS_semop: ::c_long = 193; +pub const SYS_shmget: ::c_long = 194; +pub const SYS_shmctl: ::c_long = 195; +pub const SYS_shmat: ::c_long = 196; +pub const SYS_shmdt: ::c_long = 197; +pub const SYS_socket: ::c_long = 198; +pub const SYS_socketpair: ::c_long = 199; +pub const SYS_bind: ::c_long = 200; +pub const SYS_listen: ::c_long = 201; +pub const SYS_accept: ::c_long = 202; +pub const SYS_connect: ::c_long = 203; +pub const SYS_getsockname: ::c_long = 204; +pub const SYS_getpeername: ::c_long = 205; +pub const SYS_sendto: ::c_long = 206; +pub const SYS_recvfrom: ::c_long = 207; +pub const SYS_setsockopt: ::c_long = 208; +pub const SYS_getsockopt: ::c_long = 209; +pub const SYS_shutdown: ::c_long = 210; +pub const SYS_sendmsg: ::c_long = 211; +pub const SYS_recvmsg: ::c_long = 212; +pub const SYS_readahead: ::c_long = 213; +pub const SYS_brk: ::c_long = 214; +pub const SYS_munmap: ::c_long = 215; +pub const SYS_mremap: ::c_long = 216; +pub const SYS_add_key: ::c_long = 217; +pub const SYS_request_key: ::c_long = 218; +pub const SYS_keyctl: ::c_long = 219; +pub const SYS_clone: ::c_long = 220; +pub const SYS_execve: ::c_long = 221; +pub const SYS_swapon: ::c_long = 224; +pub const SYS_swapoff: ::c_long = 225; +pub const SYS_mprotect: ::c_long = 226; +pub const SYS_msync: ::c_long = 227; +pub const SYS_mlock: ::c_long = 228; +pub const SYS_munlock: ::c_long = 229; +pub const SYS_mlockall: ::c_long = 230; +pub const SYS_munlockall: ::c_long = 231; +pub const SYS_mincore: ::c_long = 232; +pub const SYS_madvise: ::c_long = 233; +pub const SYS_remap_file_pages: ::c_long = 234; +pub const SYS_mbind: ::c_long = 235; +pub const SYS_get_mempolicy: ::c_long = 236; +pub const SYS_set_mempolicy: ::c_long = 237; +pub const SYS_migrate_pages: ::c_long = 238; +pub const SYS_move_pages: ::c_long = 239; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 240; +pub const SYS_perf_event_open: ::c_long = 241; +pub const SYS_accept4: ::c_long = 242; +pub const SYS_recvmmsg: ::c_long = 243; +pub const SYS_arch_specific_syscall: ::c_long = 244; +pub const SYS_wait4: ::c_long = 260; +pub const SYS_prlimit64: ::c_long = 261; +pub const SYS_fanotify_init: ::c_long = 262; +pub const SYS_fanotify_mark: ::c_long = 263; +pub const SYS_name_to_handle_at: ::c_long = 264; +pub const SYS_open_by_handle_at: ::c_long = 265; +pub const SYS_clock_adjtime: ::c_long = 266; +pub const SYS_syncfs: ::c_long = 267; +pub const SYS_setns: ::c_long = 268; +pub const SYS_sendmmsg: ::c_long = 269; +pub const SYS_process_vm_readv: ::c_long = 270; +pub const SYS_process_vm_writev: ::c_long = 271; +pub const SYS_kcmp: ::c_long = 272; +pub const SYS_finit_module: ::c_long = 273; +pub const SYS_sched_setattr: ::c_long = 274; +pub const SYS_sched_getattr: ::c_long = 275; +pub const SYS_renameat2: ::c_long = 276; +pub const SYS_seccomp: ::c_long = 277; +pub const SYS_getrandom: ::c_long = 278; +pub const SYS_memfd_create: ::c_long = 279; +pub const SYS_bpf: ::c_long = 280; +pub const SYS_execveat: ::c_long = 281; +pub const SYS_userfaultfd: ::c_long = 282; +pub const SYS_membarrier: ::c_long = 283; +pub const SYS_mlock2: ::c_long = 284; +pub const SYS_copy_file_range: ::c_long = 285; +pub const SYS_preadv2: ::c_long = 286; +pub const SYS_pwritev2: ::c_long = 287; +pub const SYS_pkey_mprotect: ::c_long = 288; +pub const SYS_pkey_alloc: ::c_long = 289; +pub const SYS_pkey_free: ::c_long = 290; +pub const SYS_syscalls: ::c_long = 291; diff --git a/libc/src/unix/notbsd/android/b64/mod.rs b/libc/src/unix/notbsd/android/b64/mod.rs new file mode 100644 index 000000000..46becc53d --- /dev/null +++ b/libc/src/unix/notbsd/android/b64/mod.rs @@ -0,0 +1,272 @@ +// The following definitions are correct for aarch64 and x86_64, +// but may be wrong for mips64 + +pub type c_long = i64; +pub type c_ulong = u64; +pub type mode_t = u32; +pub type off64_t = i64; +pub type socklen_t = u32; + +s! { + pub struct sigset_t { + __val: [::c_ulong; 1], + } + + pub struct sigaction { + pub sa_flags: ::c_uint, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_restorer: ::Option, + } + + pub struct rlimit64 { + pub rlim_cur: ::c_ulonglong, + pub rlim_max: ::c_ulonglong, + } + + pub struct pthread_attr_t { + pub flags: ::uint32_t, + pub stack_base: *mut ::c_void, + pub stack_size: ::size_t, + pub guard_size: ::size_t, + pub sched_policy: ::int32_t, + pub sched_priority: ::int32_t, + __reserved: [::c_char; 16], + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct statfs { + pub f_type: ::uint64_t, + pub f_bsize: ::uint64_t, + pub f_blocks: ::uint64_t, + pub f_bfree: ::uint64_t, + pub f_bavail: ::uint64_t, + pub f_files: ::uint64_t, + pub f_ffree: ::uint64_t, + pub f_fsid: ::__fsid_t, + pub f_namelen: ::uint64_t, + pub f_frsize: ::uint64_t, + pub f_flags: ::uint64_t, + pub f_spare: [::uint64_t; 4], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } + + pub struct statfs64 { + pub f_type: u64, + pub f_bsize: u64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + f_fsid: [u32; 2], + pub f_namelen: u64, + pub f_frsize: u64, + pub f_flags: u64, + pub f_spare: [u64; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } +} + +s_no_extra_traits!{ + pub struct pthread_mutex_t { + value: ::c_int, + __reserved: [::c_char; 36], + } + + pub struct pthread_cond_t { + value: ::c_int, + __reserved: [::c_char; 44], + } + + pub struct pthread_rwlock_t { + numLocks: ::c_int, + writerThreadId: ::c_int, + pendingReaders: ::c_int, + pendingWriters: ::c_int, + attr: i32, + __reserved: [::c_char; 36], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_mutex_t { + fn eq(&self, other: &pthread_mutex_t) -> bool { + self.value == other.value + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for pthread_mutex_t {} + + impl ::fmt::Debug for pthread_mutex_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_mutex_t") + .field("value", &self.value) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + + impl ::hash::Hash for pthread_mutex_t { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.__reserved.hash(state); + } + } + + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.value == other.value + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for pthread_cond_t {} + + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + .field("value", &self.value) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.__reserved.hash(state); + } + } + + impl PartialEq for pthread_rwlock_t { + fn eq(&self, other: &pthread_rwlock_t) -> bool { + self.numLocks == other.numLocks + && self.writerThreadId == other.writerThreadId + && self.pendingReaders == other.pendingReaders + && self.pendingWriters == other.pendingWriters + && self.attr == other.attr + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for pthread_rwlock_t {} + + impl ::fmt::Debug for pthread_rwlock_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_rwlock_t") + .field("numLocks", &self.numLocks) + .field("writerThreadId", &self.writerThreadId) + .field("pendingReaders", &self.pendingReaders) + .field("pendingWriters", &self.pendingWriters) + .field("attr", &self.attr) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + + impl ::hash::Hash for pthread_rwlock_t { + fn hash(&self, state: &mut H) { + self.numLocks.hash(state); + self.writerThreadId.hash(state); + self.pendingReaders.hash(state); + self.pendingWriters.hash(state); + self.attr.hash(state); + self.__reserved.hash(state); + } + } + } +} + +pub const RTLD_GLOBAL: ::c_int = 0x00100; +pub const RTLD_NOW: ::c_int = 2; +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + value: 0, + __reserved: [0; 36], +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + value: 0, + __reserved: [0; 44], +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + numLocks: 0, + writerThreadId: 0, + pendingReaders: 0, + pendingWriters: 0, + attr: 0, + __reserved: [0; 36], +}; +pub const PTHREAD_STACK_MIN: ::size_t = 4096 * 4; +pub const CPU_SETSIZE: ::size_t = 1024; +pub const __CPU_BITS: ::size_t = 64; + +pub const UT_LINESIZE: usize = 32; +pub const UT_NAMESIZE: usize = 32; +pub const UT_HOSTSIZE: usize = 256; + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/android/b64/x86_64.rs b/libc/src/unix/notbsd/android/b64/x86_64.rs new file mode 100644 index 000000000..c813e7da3 --- /dev/null +++ b/libc/src/unix/notbsd/android/b64/x86_64.rs @@ -0,0 +1,420 @@ +pub type c_char = i8; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::c_ulong, + pub st_mode: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_size: ::off64_t, + pub st_blksize: ::c_long, + pub st_blocks: ::c_long, + pub st_atime: ::c_ulong, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::c_ulong, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::c_ulong, + pub st_ctime_nsec: ::c_ulong, + __unused: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::c_ulong, + pub st_mode: ::c_uint, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_size: ::off64_t, + pub st_blksize: ::c_long, + pub st_blocks: ::c_long, + pub st_atime: ::c_ulong, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::c_ulong, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::c_ulong, + pub st_ctime_nsec: ::c_ulong, + __unused: [::c_long; 3], + } +} + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const O_LARGEFILE: ::c_int = 0o0100000; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +pub const MAP_32BIT: ::c_int = 0x40; + +// Syscall table + +pub const SYS_read: ::c_long = 0; +pub const SYS_write: ::c_long = 1; +pub const SYS_open: ::c_long = 2; +pub const SYS_close: ::c_long = 3; +pub const SYS_stat: ::c_long = 4; +pub const SYS_fstat: ::c_long = 5; +pub const SYS_lstat: ::c_long = 6; +pub const SYS_poll: ::c_long = 7; +pub const SYS_lseek: ::c_long = 8; +pub const SYS_mmap: ::c_long = 9; +pub const SYS_mprotect: ::c_long = 10; +pub const SYS_munmap: ::c_long = 11; +pub const SYS_brk: ::c_long = 12; +pub const SYS_rt_sigaction: ::c_long = 13; +pub const SYS_rt_sigprocmask: ::c_long = 14; +pub const SYS_rt_sigreturn: ::c_long = 15; +pub const SYS_ioctl: ::c_long = 16; +pub const SYS_pread64: ::c_long = 17; +pub const SYS_pwrite64: ::c_long = 18; +pub const SYS_readv: ::c_long = 19; +pub const SYS_writev: ::c_long = 20; +pub const SYS_access: ::c_long = 21; +pub const SYS_pipe: ::c_long = 22; +pub const SYS_select: ::c_long = 23; +pub const SYS_sched_yield: ::c_long = 24; +pub const SYS_mremap: ::c_long = 25; +pub const SYS_msync: ::c_long = 26; +pub const SYS_mincore: ::c_long = 27; +pub const SYS_madvise: ::c_long = 28; +pub const SYS_shmget: ::c_long = 29; +pub const SYS_shmat: ::c_long = 30; +pub const SYS_shmctl: ::c_long = 31; +pub const SYS_dup: ::c_long = 32; +pub const SYS_dup2: ::c_long = 33; +pub const SYS_pause: ::c_long = 34; +pub const SYS_nanosleep: ::c_long = 35; +pub const SYS_getitimer: ::c_long = 36; +pub const SYS_alarm: ::c_long = 37; +pub const SYS_setitimer: ::c_long = 38; +pub const SYS_getpid: ::c_long = 39; +pub const SYS_sendfile: ::c_long = 40; +pub const SYS_socket: ::c_long = 41; +pub const SYS_connect: ::c_long = 42; +pub const SYS_accept: ::c_long = 43; +pub const SYS_sendto: ::c_long = 44; +pub const SYS_recvfrom: ::c_long = 45; +pub const SYS_sendmsg: ::c_long = 46; +pub const SYS_recvmsg: ::c_long = 47; +pub const SYS_shutdown: ::c_long = 48; +pub const SYS_bind: ::c_long = 49; +pub const SYS_listen: ::c_long = 50; +pub const SYS_getsockname: ::c_long = 51; +pub const SYS_getpeername: ::c_long = 52; +pub const SYS_socketpair: ::c_long = 53; +pub const SYS_setsockopt: ::c_long = 54; +pub const SYS_getsockopt: ::c_long = 55; +pub const SYS_clone: ::c_long = 56; +pub const SYS_fork: ::c_long = 57; +pub const SYS_vfork: ::c_long = 58; +pub const SYS_execve: ::c_long = 59; +pub const SYS_exit: ::c_long = 60; +pub const SYS_wait4: ::c_long = 61; +pub const SYS_kill: ::c_long = 62; +pub const SYS_uname: ::c_long = 63; +pub const SYS_semget: ::c_long = 64; +pub const SYS_semop: ::c_long = 65; +pub const SYS_semctl: ::c_long = 66; +pub const SYS_shmdt: ::c_long = 67; +pub const SYS_msgget: ::c_long = 68; +pub const SYS_msgsnd: ::c_long = 69; +pub const SYS_msgrcv: ::c_long = 70; +pub const SYS_msgctl: ::c_long = 71; +pub const SYS_fcntl: ::c_long = 72; +pub const SYS_flock: ::c_long = 73; +pub const SYS_fsync: ::c_long = 74; +pub const SYS_fdatasync: ::c_long = 75; +pub const SYS_truncate: ::c_long = 76; +pub const SYS_ftruncate: ::c_long = 77; +pub const SYS_getdents: ::c_long = 78; +pub const SYS_getcwd: ::c_long = 79; +pub const SYS_chdir: ::c_long = 80; +pub const SYS_fchdir: ::c_long = 81; +pub const SYS_rename: ::c_long = 82; +pub const SYS_mkdir: ::c_long = 83; +pub const SYS_rmdir: ::c_long = 84; +pub const SYS_creat: ::c_long = 85; +pub const SYS_link: ::c_long = 86; +pub const SYS_unlink: ::c_long = 87; +pub const SYS_symlink: ::c_long = 88; +pub const SYS_readlink: ::c_long = 89; +pub const SYS_chmod: ::c_long = 90; +pub const SYS_fchmod: ::c_long = 91; +pub const SYS_chown: ::c_long = 92; +pub const SYS_fchown: ::c_long = 93; +pub const SYS_lchown: ::c_long = 94; +pub const SYS_umask: ::c_long = 95; +pub const SYS_gettimeofday: ::c_long = 96; +pub const SYS_getrlimit: ::c_long = 97; +pub const SYS_getrusage: ::c_long = 98; +pub const SYS_sysinfo: ::c_long = 99; +pub const SYS_times: ::c_long = 100; +pub const SYS_ptrace: ::c_long = 101; +pub const SYS_getuid: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_getgid: ::c_long = 104; +pub const SYS_setuid: ::c_long = 105; +pub const SYS_setgid: ::c_long = 106; +pub const SYS_geteuid: ::c_long = 107; +pub const SYS_getegid: ::c_long = 108; +pub const SYS_setpgid: ::c_long = 109; +pub const SYS_getppid: ::c_long = 110; +pub const SYS_getpgrp: ::c_long = 111; +pub const SYS_setsid: ::c_long = 112; +pub const SYS_setreuid: ::c_long = 113; +pub const SYS_setregid: ::c_long = 114; +pub const SYS_getgroups: ::c_long = 115; +pub const SYS_setgroups: ::c_long = 116; +pub const SYS_setresuid: ::c_long = 117; +pub const SYS_getresuid: ::c_long = 118; +pub const SYS_setresgid: ::c_long = 119; +pub const SYS_getresgid: ::c_long = 120; +pub const SYS_getpgid: ::c_long = 121; +pub const SYS_setfsuid: ::c_long = 122; +pub const SYS_setfsgid: ::c_long = 123; +pub const SYS_getsid: ::c_long = 124; +pub const SYS_capget: ::c_long = 125; +pub const SYS_capset: ::c_long = 126; +pub const SYS_rt_sigpending: ::c_long = 127; +pub const SYS_rt_sigtimedwait: ::c_long = 128; +pub const SYS_rt_sigqueueinfo: ::c_long = 129; +pub const SYS_rt_sigsuspend: ::c_long = 130; +pub const SYS_sigaltstack: ::c_long = 131; +pub const SYS_utime: ::c_long = 132; +pub const SYS_mknod: ::c_long = 133; +pub const SYS_uselib: ::c_long = 134; +pub const SYS_personality: ::c_long = 135; +pub const SYS_ustat: ::c_long = 136; +pub const SYS_statfs: ::c_long = 137; +pub const SYS_fstatfs: ::c_long = 138; +pub const SYS_sysfs: ::c_long = 139; +pub const SYS_getpriority: ::c_long = 140; +pub const SYS_setpriority: ::c_long = 141; +pub const SYS_sched_setparam: ::c_long = 142; +pub const SYS_sched_getparam: ::c_long = 143; +pub const SYS_sched_setscheduler: ::c_long = 144; +pub const SYS_sched_getscheduler: ::c_long = 145; +pub const SYS_sched_get_priority_max: ::c_long = 146; +pub const SYS_sched_get_priority_min: ::c_long = 147; +pub const SYS_sched_rr_get_interval: ::c_long = 148; +pub const SYS_mlock: ::c_long = 149; +pub const SYS_munlock: ::c_long = 150; +pub const SYS_mlockall: ::c_long = 151; +pub const SYS_munlockall: ::c_long = 152; +pub const SYS_vhangup: ::c_long = 153; +pub const SYS_modify_ldt: ::c_long = 154; +pub const SYS_pivot_root: ::c_long = 155; +// FIXME: SYS__sysctl is in the NDK sources but for some reason is +// not available in the tests +// pub const SYS__sysctl: ::c_long = 156; +pub const SYS_prctl: ::c_long = 157; +pub const SYS_arch_prctl: ::c_long = 158; +pub const SYS_adjtimex: ::c_long = 159; +pub const SYS_setrlimit: ::c_long = 160; +pub const SYS_chroot: ::c_long = 161; +pub const SYS_sync: ::c_long = 162; +pub const SYS_acct: ::c_long = 163; +pub const SYS_settimeofday: ::c_long = 164; +pub const SYS_mount: ::c_long = 165; +pub const SYS_umount2: ::c_long = 166; +pub const SYS_swapon: ::c_long = 167; +pub const SYS_swapoff: ::c_long = 168; +pub const SYS_reboot: ::c_long = 169; +pub const SYS_sethostname: ::c_long = 170; +pub const SYS_setdomainname: ::c_long = 171; +pub const SYS_iopl: ::c_long = 172; +pub const SYS_ioperm: ::c_long = 173; +pub const SYS_create_module: ::c_long = 174; +pub const SYS_init_module: ::c_long = 175; +pub const SYS_delete_module: ::c_long = 176; +pub const SYS_get_kernel_syms: ::c_long = 177; +pub const SYS_query_module: ::c_long = 178; +pub const SYS_quotactl: ::c_long = 179; +pub const SYS_nfsservctl: ::c_long = 180; +pub const SYS_getpmsg: ::c_long = 181; +pub const SYS_putpmsg: ::c_long = 182; +pub const SYS_afs_syscall: ::c_long = 183; +pub const SYS_tuxcall: ::c_long = 184; +pub const SYS_security: ::c_long = 185; +pub const SYS_gettid: ::c_long = 186; +pub const SYS_readahead: ::c_long = 187; +pub const SYS_setxattr: ::c_long = 188; +pub const SYS_lsetxattr: ::c_long = 189; +pub const SYS_fsetxattr: ::c_long = 190; +pub const SYS_getxattr: ::c_long = 191; +pub const SYS_lgetxattr: ::c_long = 192; +pub const SYS_fgetxattr: ::c_long = 193; +pub const SYS_listxattr: ::c_long = 194; +pub const SYS_llistxattr: ::c_long = 195; +pub const SYS_flistxattr: ::c_long = 196; +pub const SYS_removexattr: ::c_long = 197; +pub const SYS_lremovexattr: ::c_long = 198; +pub const SYS_fremovexattr: ::c_long = 199; +pub const SYS_tkill: ::c_long = 200; +pub const SYS_time: ::c_long = 201; +pub const SYS_futex: ::c_long = 202; +pub const SYS_sched_setaffinity: ::c_long = 203; +pub const SYS_sched_getaffinity: ::c_long = 204; +pub const SYS_set_thread_area: ::c_long = 205; +pub const SYS_io_setup: ::c_long = 206; +pub const SYS_io_destroy: ::c_long = 207; +pub const SYS_io_getevents: ::c_long = 208; +pub const SYS_io_submit: ::c_long = 209; +pub const SYS_io_cancel: ::c_long = 210; +pub const SYS_get_thread_area: ::c_long = 211; +pub const SYS_lookup_dcookie: ::c_long = 212; +pub const SYS_epoll_create: ::c_long = 213; +pub const SYS_epoll_ctl_old: ::c_long = 214; +pub const SYS_epoll_wait_old: ::c_long = 215; +pub const SYS_remap_file_pages: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_set_tid_address: ::c_long = 218; +pub const SYS_restart_syscall: ::c_long = 219; +pub const SYS_semtimedop: ::c_long = 220; +pub const SYS_fadvise64: ::c_long = 221; +pub const SYS_timer_create: ::c_long = 222; +pub const SYS_timer_settime: ::c_long = 223; +pub const SYS_timer_gettime: ::c_long = 224; +pub const SYS_timer_getoverrun: ::c_long = 225; +pub const SYS_timer_delete: ::c_long = 226; +pub const SYS_clock_settime: ::c_long = 227; +pub const SYS_clock_gettime: ::c_long = 228; +pub const SYS_clock_getres: ::c_long = 229; +pub const SYS_clock_nanosleep: ::c_long = 230; +pub const SYS_exit_group: ::c_long = 231; +pub const SYS_epoll_wait: ::c_long = 232; +pub const SYS_epoll_ctl: ::c_long = 233; +pub const SYS_tgkill: ::c_long = 234; +pub const SYS_utimes: ::c_long = 235; +pub const SYS_vserver: ::c_long = 236; +pub const SYS_mbind: ::c_long = 237; +pub const SYS_set_mempolicy: ::c_long = 238; +pub const SYS_get_mempolicy: ::c_long = 239; +pub const SYS_mq_open: ::c_long = 240; +pub const SYS_mq_unlink: ::c_long = 241; +pub const SYS_mq_timedsend: ::c_long = 242; +pub const SYS_mq_timedreceive: ::c_long = 243; +pub const SYS_mq_notify: ::c_long = 244; +pub const SYS_mq_getsetattr: ::c_long = 245; +pub const SYS_kexec_load: ::c_long = 246; +pub const SYS_waitid: ::c_long = 247; +pub const SYS_add_key: ::c_long = 248; +pub const SYS_request_key: ::c_long = 249; +pub const SYS_keyctl: ::c_long = 250; +pub const SYS_ioprio_set: ::c_long = 251; +pub const SYS_ioprio_get: ::c_long = 252; +pub const SYS_inotify_init: ::c_long = 253; +pub const SYS_inotify_add_watch: ::c_long = 254; +pub const SYS_inotify_rm_watch: ::c_long = 255; +pub const SYS_migrate_pages: ::c_long = 256; +pub const SYS_openat: ::c_long = 257; +pub const SYS_mkdirat: ::c_long = 258; +pub const SYS_mknodat: ::c_long = 259; +pub const SYS_fchownat: ::c_long = 260; +pub const SYS_futimesat: ::c_long = 261; +pub const SYS_newfstatat: ::c_long = 262; +pub const SYS_unlinkat: ::c_long = 263; +pub const SYS_renameat: ::c_long = 264; +pub const SYS_linkat: ::c_long = 265; +pub const SYS_symlinkat: ::c_long = 266; +pub const SYS_readlinkat: ::c_long = 267; +pub const SYS_fchmodat: ::c_long = 268; +pub const SYS_faccessat: ::c_long = 269; +pub const SYS_pselect6: ::c_long = 270; +pub const SYS_ppoll: ::c_long = 271; +pub const SYS_unshare: ::c_long = 272; +pub const SYS_set_robust_list: ::c_long = 273; +pub const SYS_get_robust_list: ::c_long = 274; +pub const SYS_splice: ::c_long = 275; +pub const SYS_tee: ::c_long = 276; +pub const SYS_sync_file_range: ::c_long = 277; +pub const SYS_vmsplice: ::c_long = 278; +pub const SYS_move_pages: ::c_long = 279; +pub const SYS_utimensat: ::c_long = 280; +pub const SYS_epoll_pwait: ::c_long = 281; +pub const SYS_signalfd: ::c_long = 282; +pub const SYS_timerfd_create: ::c_long = 283; +pub const SYS_eventfd: ::c_long = 284; +pub const SYS_fallocate: ::c_long = 285; +pub const SYS_timerfd_settime: ::c_long = 286; +pub const SYS_timerfd_gettime: ::c_long = 287; +pub const SYS_accept4: ::c_long = 288; +pub const SYS_signalfd4: ::c_long = 289; +pub const SYS_eventfd2: ::c_long = 290; +pub const SYS_epoll_create1: ::c_long = 291; +pub const SYS_dup3: ::c_long = 292; +pub const SYS_pipe2: ::c_long = 293; +pub const SYS_inotify_init1: ::c_long = 294; +pub const SYS_preadv: ::c_long = 295; +pub const SYS_pwritev: ::c_long = 296; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 297; +pub const SYS_perf_event_open: ::c_long = 298; +pub const SYS_recvmmsg: ::c_long = 299; +pub const SYS_fanotify_init: ::c_long = 300; +pub const SYS_fanotify_mark: ::c_long = 301; +pub const SYS_prlimit64: ::c_long = 302; +pub const SYS_name_to_handle_at: ::c_long = 303; +pub const SYS_open_by_handle_at: ::c_long = 304; +pub const SYS_clock_adjtime: ::c_long = 305; +pub const SYS_syncfs: ::c_long = 306; +pub const SYS_sendmmsg: ::c_long = 307; +pub const SYS_setns: ::c_long = 308; +pub const SYS_getcpu: ::c_long = 309; +pub const SYS_process_vm_readv: ::c_long = 310; +pub const SYS_process_vm_writev: ::c_long = 311; +pub const SYS_kcmp: ::c_long = 312; +pub const SYS_finit_module: ::c_long = 313; +pub const SYS_sched_setattr: ::c_long = 314; +pub const SYS_sched_getattr: ::c_long = 315; +pub const SYS_renameat2: ::c_long = 316; +pub const SYS_seccomp: ::c_long = 317; +pub const SYS_getrandom: ::c_long = 318; +pub const SYS_memfd_create: ::c_long = 319; +pub const SYS_kexec_file_load: ::c_long = 320; +pub const SYS_bpf: ::c_long = 321; +pub const SYS_execveat: ::c_long = 322; +pub const SYS_userfaultfd: ::c_long = 323; +pub const SYS_membarrier: ::c_long = 324; +pub const SYS_mlock2: ::c_long = 325; +pub const SYS_copy_file_range: ::c_long = 326; +pub const SYS_preadv2: ::c_long = 327; +pub const SYS_pwritev2: ::c_long = 328; +pub const SYS_pkey_mprotect: ::c_long = 329; +pub const SYS_pkey_alloc: ::c_long = 330; +pub const SYS_pkey_free: ::c_long = 331; + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: ::c_int = 0; +pub const R14: ::c_int = 1; +pub const R13: ::c_int = 2; +pub const R12: ::c_int = 3; +pub const RBP: ::c_int = 4; +pub const RBX: ::c_int = 5; +pub const R11: ::c_int = 6; +pub const R10: ::c_int = 7; +pub const R9: ::c_int = 8; +pub const R8: ::c_int = 9; +pub const RAX: ::c_int = 10; +pub const RCX: ::c_int = 11; +pub const RDX: ::c_int = 12; +pub const RSI: ::c_int = 13; +pub const RDI: ::c_int = 14; +pub const ORIG_RAX: ::c_int = 15; +pub const RIP: ::c_int = 16; +pub const CS: ::c_int = 17; +pub const EFLAGS: ::c_int = 18; +pub const RSP: ::c_int = 19; +pub const SS: ::c_int = 20; +pub const FS_BASE: ::c_int = 21; +pub const GS_BASE: ::c_int = 22; +pub const DS: ::c_int = 23; +pub const ES: ::c_int = 24; +pub const FS: ::c_int = 25; +pub const GS: ::c_int = 26; diff --git a/libc/src/unix/notbsd/android/mod.rs b/libc/src/unix/notbsd/android/mod.rs new file mode 100644 index 000000000..a430b1a00 --- /dev/null +++ b/libc/src/unix/notbsd/android/mod.rs @@ -0,0 +1,2143 @@ +//! Android-specific definitions for linux-like values + +pub type clock_t = ::c_long; +pub type time_t = ::c_long; +pub type suseconds_t = ::c_long; +pub type off_t = ::c_long; +pub type blkcnt_t = ::c_ulong; +pub type blksize_t = ::c_ulong; +pub type nlink_t = u32; +pub type useconds_t = u32; +pub type pthread_t = ::c_long; +pub type pthread_mutexattr_t = ::c_long; +pub type pthread_rwlockattr_t = ::c_long; +pub type pthread_condattr_t = ::c_long; +pub type fsfilcnt_t = ::c_ulong; +pub type fsblkcnt_t = ::c_ulong; +pub type nfds_t = ::c_uint; +pub type rlim_t = ::c_ulong; +pub type dev_t = ::c_ulong; +pub type ino_t = ::c_ulong; +pub type __CPU_BITTYPE = ::c_ulong; +pub type idtype_t = ::c_int; +pub type loff_t = ::c_longlong; + +s! { + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct __fsid_t { + __val: [::c_int; 2], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct cpu_set_t { + #[cfg(target_pointer_width = "64")] + __bits: [__CPU_BITTYPE; 16], + #[cfg(target_pointer_width = "32")] + __bits: [__CPU_BITTYPE; 1], + } + + pub struct sem_t { + count: ::c_uint, + #[cfg(target_pointer_width = "64")] + __reserved: [::c_int; 3], + } + + pub struct exit_status { + pub e_termination: ::c_short, + pub e_exit: ::c_short, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + #[cfg(target_pointer_width = "64")] + __f_reserved: [u32; 6], + } + + pub struct signalfd_siginfo { + pub ssi_signo: ::uint32_t, + pub ssi_errno: ::int32_t, + pub ssi_code: ::int32_t, + pub ssi_pid: ::uint32_t, + pub ssi_uid: ::uint32_t, + pub ssi_fd: ::int32_t, + pub ssi_tid: ::uint32_t, + pub ssi_band: ::uint32_t, + pub ssi_overrun: ::uint32_t, + pub ssi_trapno: ::uint32_t, + pub ssi_status: ::int32_t, + pub ssi_int: ::int32_t, + pub ssi_ptr: ::c_ulonglong, + pub ssi_utime: ::c_ulonglong, + pub ssi_stime: ::c_ulonglong, + pub ssi_addr: ::c_ulonglong, + pub ssi_addr_lsb: ::uint16_t, + _pad2: ::uint16_t, + pub ssi_syscall: ::int32_t, + pub ssi_call_addr: ::uint64_t, + pub ssi_arch: ::uint32_t, + _pad: [::uint8_t; 28], + } + + pub struct ucred { + pub pid: ::pid_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + } + + pub struct genlmsghdr { + pub cmd: u8, + pub version: u8, + pub reserved: u16, + } + + pub struct nlmsghdr { + pub nlmsg_len: u32, + pub nlmsg_type: u16, + pub nlmsg_flags: u16, + pub nlmsg_seq: u32, + pub nlmsg_pid: u32, + } + + pub struct nlmsgerr { + pub error: ::c_int, + pub msg: nlmsghdr, + } + + pub struct nl_pktinfo { + pub group: u32, + } + + pub struct nl_mmap_req { + pub nm_block_size: ::c_uint, + pub nm_block_nr: ::c_uint, + pub nm_frame_size: ::c_uint, + pub nm_frame_nr: ::c_uint, + } + + pub struct nl_mmap_hdr { + pub nm_status: ::c_uint, + pub nm_len: ::c_uint, + pub nm_group: u32, + pub nm_pid: u32, + pub nm_uid: u32, + pub nm_gid: u32, + } + + pub struct nlattr { + pub nla_len: u16, + pub nla_type: u16, + } + + pub struct in6_pktinfo { + pub ipi6_addr: ::in6_addr, + pub ipi6_ifindex: ::c_int, + } + + pub struct inotify_event { + pub wd: ::c_int, + pub mask: ::uint32_t, + pub cookie: ::uint32_t, + pub len: ::uint32_t + } +} + +s_no_extra_traits!{ + pub struct dirent { + pub d_ino: u64, + pub d_off: i64, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct dirent64 { + pub d_ino: u64, + pub d_off: i64, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct lastlog { + ll_time: ::time_t, + ll_line: [::c_char; UT_LINESIZE], + ll_host: [::c_char; UT_HOSTSIZE], + } + + pub struct utmp { + pub ut_type: ::c_short, + pub ut_pid: ::pid_t, + pub ut_line: [::c_char; UT_LINESIZE], + pub ut_id: [::c_char; 4], + pub ut_user: [::c_char; UT_NAMESIZE], + pub ut_host: [::c_char; UT_HOSTSIZE], + pub ut_exit: exit_status, + pub ut_session: ::c_long, + pub ut_tv: ::timeval, + pub ut_addr_v6: [::int32_t; 4], + unused: [::c_char; 20], + } + + pub struct sockaddr_alg { + pub salg_family: ::sa_family_t, + pub salg_type: [::c_uchar; 14], + pub salg_feat: u32, + pub salg_mask: u32, + pub salg_name: [::c_uchar; 64], + } + + pub struct af_alg_iv { + pub ivlen: u32, + pub iv: [::c_uchar; 0], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for dirent {} + + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for dirent64 { + fn eq(&self, other: &dirent64) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for dirent64 {} + + impl ::fmt::Debug for dirent64 { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent64") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + + impl ::hash::Hash for dirent64 { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for siginfo_t { + fn eq(&self, other: &siginfo_t) -> bool { + self.si_signo == other.si_signo + && self.si_errno == other.si_errno + && self.si_code == other.si_code + // Ignore _pad + // Ignore _align + } + } + + impl Eq for siginfo_t {} + + impl ::fmt::Debug for siginfo_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("siginfo_t") + .field("si_signo", &self.si_signo) + .field("si_errno", &self.si_errno) + .field("si_code", &self.si_code) + // Ignore _pad + // Ignore _align + .finish() + } + } + + impl ::hash::Hash for siginfo_t { + fn hash(&self, state: &mut H) { + self.si_signo.hash(state); + self.si_errno.hash(state); + self.si_code.hash(state); + // Ignore _pad + // Ignore _align + } + } + + impl PartialEq for lastlog { + fn eq(&self, other: &lastlog) -> bool { + self.ll_time == other.ll_time + && self + .ll_line + .iter() + .zip(other.ll_line.iter()) + .all(|(a,b)| a == b) + && self + .ll_host + .iter() + .zip(other.ll_host.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for lastlog {} + + impl ::fmt::Debug for lastlog { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("lastlog") + .field("ll_time", &self.ll_time) + .field("ll_line", &self.ll_line) + // FIXME: .field("ll_host", &self.ll_host) + .finish() + } + } + + impl ::hash::Hash for lastlog { + fn hash(&self, state: &mut H) { + self.ll_time.hash(state); + self.ll_line.hash(state); + self.ll_host.hash(state); + } + } + + impl PartialEq for utmp { + fn eq(&self, other: &utmp) -> bool { + self.ut_type == other.ut_type + && self.ut_pid == other.ut_pid + && self + .ut_line + .iter() + .zip(other.ut_line.iter()) + .all(|(a,b)| a == b) + && self.ut_id == other.ut_id + && self + .ut_user + .iter() + .zip(other.ut_user.iter()) + .all(|(a,b)| a == b) + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + && self.ut_exit == other.ut_exit + && self.ut_session == other.ut_session + && self.ut_tv == other.ut_tv + && self.ut_addr_v6 == other.ut_addr_v6 + && self.unused == other.unused + } + } + + impl Eq for utmp {} + + impl ::fmt::Debug for utmp { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmp") + .field("ut_type", &self.ut_type) + .field("ut_pid", &self.ut_pid) + .field("ut_line", &self.ut_line) + .field("ut_id", &self.ut_id) + .field("ut_user", &self.ut_user) + // FIXME: .field("ut_host", &self.ut_host) + .field("ut_exit", &self.ut_exit) + .field("ut_session", &self.ut_session) + .field("ut_tv", &self.ut_tv) + .field("ut_addr_v6", &self.ut_addr_v6) + .field("unused", &self.unused) + .finish() + } + } + + impl ::hash::Hash for utmp { + fn hash(&self, state: &mut H) { + self.ut_type.hash(state); + self.ut_pid.hash(state); + self.ut_line.hash(state); + self.ut_id.hash(state); + self.ut_user.hash(state); + self.ut_host.hash(state); + self.ut_exit.hash(state); + self.ut_session.hash(state); + self.ut_tv.hash(state); + self.ut_addr_v6.hash(state); + self.unused.hash(state); + } + } + + impl PartialEq for sockaddr_alg { + fn eq(&self, other: &sockaddr_alg) -> bool { + self.salg_family == other.salg_family + && self + .salg_type + .iter() + .zip(other.salg_type.iter()) + .all(|(a, b)| a == b) + && self.salg_feat == other.salg_feat + && self.salg_mask == other.salg_mask + && self + .salg_name + .iter() + .zip(other.salg_name.iter()) + .all(|(a, b)| a == b) + } + } + + impl Eq for sockaddr_alg {} + + impl ::fmt::Debug for sockaddr_alg { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_alg") + .field("salg_family", &self.salg_family) + .field("salg_type", &self.salg_type) + .field("salg_feat", &self.salg_feat) + .field("salg_mask", &self.salg_mask) + .field("salg_name", &&self.salg_name[..]) + .finish() + } + } + + impl ::hash::Hash for sockaddr_alg { + fn hash(&self, state: &mut H) { + self.salg_family.hash(state); + self.salg_type.hash(state); + self.salg_feat.hash(state); + self.salg_mask.hash(state); + self.salg_name.hash(state); + } + } + + impl af_alg_iv { + fn as_slice(&self) -> &[u8] { + unsafe { + ::core::slice::from_raw_parts( + self.iv.as_ptr(), + self.ivlen as usize + ) + } + } + } + + impl PartialEq for af_alg_iv { + fn eq(&self, other: &af_alg_iv) -> bool { + *self.as_slice() == *other.as_slice() + } + } + + impl Eq for af_alg_iv {} + + impl ::fmt::Debug for af_alg_iv { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("af_alg_iv") + .field("iv", &self.as_slice()) + .finish() + } + } + + impl ::hash::Hash for af_alg_iv { + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } + } + } +} + +pub const O_TRUNC: ::c_int = 512; +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_NOATIME: ::c_int = 0o1000000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; +pub const EPOLLRDHUP: ::c_int = 0x00002000; +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const USER_PROCESS: ::c_short = 7; + +pub const BUFSIZ: ::c_uint = 1024; +pub const FILENAME_MAX: ::c_uint = 1024; +pub const FOPEN_MAX: ::c_uint = 20; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; +pub const L_tmpnam: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 308915776; +pub const _PC_LINK_MAX: ::c_int = 1; +pub const _PC_MAX_CANON: ::c_int = 2; +pub const _PC_MAX_INPUT: ::c_int = 3; +pub const _PC_NAME_MAX: ::c_int = 4; +pub const _PC_PATH_MAX: ::c_int = 5; +pub const _PC_PIPE_BUF: ::c_int = 6; +pub const _PC_2_SYMLINKS: ::c_int = 7; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 8; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 9; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 10; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 11; +pub const _PC_REC_XFER_ALIGN: ::c_int = 12; +pub const _PC_SYMLINK_MAX: ::c_int = 13; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 14; +pub const _PC_NO_TRUNC: ::c_int = 15; +pub const _PC_VDISABLE: ::c_int = 16; +pub const _PC_ASYNC_IO: ::c_int = 17; +pub const _PC_PRIO_IO: ::c_int = 18; +pub const _PC_SYNC_IO: ::c_int = 19; + +pub const FIONBIO: ::c_int = 0x5421; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_BC_BASE_MAX: ::c_int = 1; +pub const _SC_BC_DIM_MAX: ::c_int = 2; +pub const _SC_BC_SCALE_MAX: ::c_int = 3; +pub const _SC_BC_STRING_MAX: ::c_int = 4; +pub const _SC_CHILD_MAX: ::c_int = 5; +pub const _SC_CLK_TCK: ::c_int = 6; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 7; +pub const _SC_EXPR_NEST_MAX: ::c_int = 8; +pub const _SC_LINE_MAX: ::c_int = 9; +pub const _SC_NGROUPS_MAX: ::c_int = 10; +pub const _SC_OPEN_MAX: ::c_int = 11; +pub const _SC_PASS_MAX: ::c_int = 12; +pub const _SC_2_C_BIND: ::c_int = 13; +pub const _SC_2_C_DEV: ::c_int = 14; +pub const _SC_2_C_VERSION: ::c_int = 15; +pub const _SC_2_CHAR_TERM: ::c_int = 16; +pub const _SC_2_FORT_DEV: ::c_int = 17; +pub const _SC_2_FORT_RUN: ::c_int = 18; +pub const _SC_2_LOCALEDEF: ::c_int = 19; +pub const _SC_2_SW_DEV: ::c_int = 20; +pub const _SC_2_UPE: ::c_int = 21; +pub const _SC_2_VERSION: ::c_int = 22; +pub const _SC_JOB_CONTROL: ::c_int = 23; +pub const _SC_SAVED_IDS: ::c_int = 24; +pub const _SC_VERSION: ::c_int = 25; +pub const _SC_RE_DUP_MAX: ::c_int = 26; +pub const _SC_STREAM_MAX: ::c_int = 27; +pub const _SC_TZNAME_MAX: ::c_int = 28; +pub const _SC_XOPEN_CRYPT: ::c_int = 29; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 30; +pub const _SC_XOPEN_SHM: ::c_int = 31; +pub const _SC_XOPEN_VERSION: ::c_int = 32; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 33; +pub const _SC_XOPEN_REALTIME: ::c_int = 34; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 35; +pub const _SC_XOPEN_LEGACY: ::c_int = 36; +pub const _SC_ATEXIT_MAX: ::c_int = 37; +pub const _SC_IOV_MAX: ::c_int = 38; +pub const _SC_PAGESIZE: ::c_int = 39; +pub const _SC_PAGE_SIZE: ::c_int = 40; +pub const _SC_XOPEN_UNIX: ::c_int = 41; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 42; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 43; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 44; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 45; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 46; +pub const _SC_AIO_MAX: ::c_int = 47; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 48; +pub const _SC_DELAYTIMER_MAX: ::c_int = 49; +pub const _SC_MQ_OPEN_MAX: ::c_int = 50; +pub const _SC_MQ_PRIO_MAX: ::c_int = 51; +pub const _SC_RTSIG_MAX: ::c_int = 52; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 53; +pub const _SC_SEM_VALUE_MAX: ::c_int = 54; +pub const _SC_SIGQUEUE_MAX: ::c_int = 55; +pub const _SC_TIMER_MAX: ::c_int = 56; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 57; +pub const _SC_FSYNC: ::c_int = 58; +pub const _SC_MAPPED_FILES: ::c_int = 59; +pub const _SC_MEMLOCK: ::c_int = 60; +pub const _SC_MEMLOCK_RANGE: ::c_int = 61; +pub const _SC_MEMORY_PROTECTION: ::c_int = 62; +pub const _SC_MESSAGE_PASSING: ::c_int = 63; +pub const _SC_PRIORITIZED_IO: ::c_int = 64; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 65; +pub const _SC_REALTIME_SIGNALS: ::c_int = 66; +pub const _SC_SEMAPHORES: ::c_int = 67; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 68; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 69; +pub const _SC_TIMERS: ::c_int = 70; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 71; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 72; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 73; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 74; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 75; +pub const _SC_THREAD_STACK_MIN: ::c_int = 76; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 77; +pub const _SC_TTY_NAME_MAX: ::c_int = 78; +pub const _SC_THREADS: ::c_int = 79; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 80; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 81; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 82; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 83; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 84; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 85; +pub const _SC_NPROCESSORS_CONF: ::c_int = 96; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 97; +pub const _SC_PHYS_PAGES: ::c_int = 98; +pub const _SC_AVPHYS_PAGES: ::c_int = 99; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 100; + +pub const _SC_2_PBS: ::c_int = 101; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 102; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 103; +pub const _SC_2_PBS_LOCATE: ::c_int = 104; +pub const _SC_2_PBS_MESSAGE: ::c_int = 105; +pub const _SC_2_PBS_TRACK: ::c_int = 106; +pub const _SC_ADVISORY_INFO: ::c_int = 107; +pub const _SC_BARRIERS: ::c_int = 108; +pub const _SC_CLOCK_SELECTION: ::c_int = 109; +pub const _SC_CPUTIME: ::c_int = 110; +pub const _SC_HOST_NAME_MAX: ::c_int = 111; +pub const _SC_IPV6: ::c_int = 112; +pub const _SC_RAW_SOCKETS: ::c_int = 113; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 114; +pub const _SC_REGEXP: ::c_int = 115; +pub const _SC_SHELL: ::c_int = 116; +pub const _SC_SPAWN: ::c_int = 117; +pub const _SC_SPIN_LOCKS: ::c_int = 118; +pub const _SC_SPORADIC_SERVER: ::c_int = 119; +pub const _SC_SS_REPL_MAX: ::c_int = 120; +pub const _SC_SYMLOOP_MAX: ::c_int = 121; +pub const _SC_THREAD_CPUTIME: ::c_int = 122; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 123; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 124; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 125; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 126; +pub const _SC_TIMEOUTS: ::c_int = 127; +pub const _SC_TRACE: ::c_int = 128; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 129; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 130; +pub const _SC_TRACE_INHERIT: ::c_int = 131; +pub const _SC_TRACE_LOG: ::c_int = 132; +pub const _SC_TRACE_NAME_MAX: ::c_int = 133; +pub const _SC_TRACE_SYS_MAX: ::c_int = 134; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 135; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 136; +pub const _SC_V7_ILP32_OFF32: ::c_int = 137; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 138; +pub const _SC_V7_LP64_OFF64: ::c_int = 139; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 140; +pub const _SC_XOPEN_STREAMS: ::c_int = 141; +pub const _SC_XOPEN_UUCP: ::c_int = 142; + +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; + +pub const FIOCLEX: ::c_int = 0x5451; + +pub const SA_ONSTACK: ::c_ulong = 0x08000000; +pub const SA_SIGINFO: ::c_ulong = 0x00000004; +pub const SA_NOCLDWAIT: ::c_ulong = 0x00000002; +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const LC_PAPER: ::c_int = 7; +pub const LC_NAME: ::c_int = 8; +pub const LC_ADDRESS: ::c_int = 9; +pub const LC_TELEPHONE: ::c_int = 10; +pub const LC_MEASUREMENT: ::c_int = 11; +pub const LC_IDENTIFICATION: ::c_int = 12; +pub const LC_PAPER_MASK: ::c_int = (1 << LC_PAPER); +pub const LC_NAME_MASK: ::c_int = (1 << LC_NAME); +pub const LC_ADDRESS_MASK: ::c_int = (1 << LC_ADDRESS); +pub const LC_TELEPHONE_MASK: ::c_int = (1 << LC_TELEPHONE); +pub const LC_MEASUREMENT_MASK: ::c_int = (1 << LC_MEASUREMENT); +pub const LC_IDENTIFICATION_MASK: ::c_int = (1 << LC_IDENTIFICATION); +pub const LC_ALL_MASK: ::c_int = ::LC_CTYPE_MASK + | ::LC_NUMERIC_MASK + | ::LC_TIME_MASK + | ::LC_COLLATE_MASK + | ::LC_MONETARY_MASK + | ::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_ANONYMOUS: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; + +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const SOCK_DCCP: ::c_int = 6; +pub const SOCK_PACKET: ::c_int = 10; + +pub const SOL_SOCKET: ::c_int = 1; +pub const SOL_SCTP: ::c_int = 132; +pub const SOL_IPX: ::c_int = 256; +pub const SOL_AX25: ::c_int = 257; +pub const SOL_ATALK: ::c_int = 258; +pub const SOL_NETROM: ::c_int = 259; +pub const SOL_ROSE: ::c_int = 260; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +/* DCCP socket options */ +pub const DCCP_SOCKOPT_PACKET_SIZE: ::c_int = 1; +pub const DCCP_SOCKOPT_SERVICE: ::c_int = 2; +pub const DCCP_SOCKOPT_CHANGE_L: ::c_int = 3; +pub const DCCP_SOCKOPT_CHANGE_R: ::c_int = 4; +pub const DCCP_SOCKOPT_GET_CUR_MPS: ::c_int = 5; +pub const DCCP_SOCKOPT_SERVER_TIMEWAIT: ::c_int = 6; +pub const DCCP_SOCKOPT_SEND_CSCOV: ::c_int = 10; +pub const DCCP_SOCKOPT_RECV_CSCOV: ::c_int = 11; +pub const DCCP_SOCKOPT_AVAILABLE_CCIDS: ::c_int = 12; +pub const DCCP_SOCKOPT_CCID: ::c_int = 13; +pub const DCCP_SOCKOPT_TX_CCID: ::c_int = 14; +pub const DCCP_SOCKOPT_RX_CCID: ::c_int = 15; +pub const DCCP_SOCKOPT_QPOLICY_ID: ::c_int = 16; +pub const DCCP_SOCKOPT_QPOLICY_TXQLEN: ::c_int = 17; +pub const DCCP_SOCKOPT_CCID_RX_INFO: ::c_int = 128; +pub const DCCP_SOCKOPT_CCID_TX_INFO: ::c_int = 192; + +/// maximum number of services provided on the same listening port +pub const DCCP_SERVICE_LIST_MAX_LEN: ::c_int = 32; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +pub const IPTOS_ECN_NOTECT: u8 = 0x00; + +pub const O_ACCMODE: ::c_int = 3; +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 0x101000; +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; +pub const O_DSYNC: ::c_int = 4096; + +pub const NI_MAXHOST: ::size_t = 1025; + +pub const NCCS: usize = 19; +pub const TCSBRKP: ::c_int = 0x5425; +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 0x1; +pub const TCSAFLUSH: ::c_int = 0x2; +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const EXTPROC: ::tcflag_t = 0o200000; + +pub const ADFS_SUPER_MAGIC: ::c_long = 0x0000adf5; +pub const AFFS_SUPER_MAGIC: ::c_long = 0x0000adff; +pub const CODA_SUPER_MAGIC: ::c_long = 0x73757245; +pub const CRAMFS_MAGIC: ::c_long = 0x28cd3d45; +pub const EFS_SUPER_MAGIC: ::c_long = 0x00414a53; +pub const EXT2_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT3_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT4_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const HPFS_SUPER_MAGIC: ::c_long = 0xf995e849; +pub const HUGETLBFS_MAGIC: ::c_long = 0x958458f6; +pub const ISOFS_SUPER_MAGIC: ::c_long = 0x00009660; +pub const JFFS2_SUPER_MAGIC: ::c_long = 0x000072b6; +pub const MINIX_SUPER_MAGIC: ::c_long = 0x0000137f; +pub const MINIX_SUPER_MAGIC2: ::c_long = 0x0000138f; +pub const MINIX2_SUPER_MAGIC: ::c_long = 0x00002468; +pub const MINIX2_SUPER_MAGIC2: ::c_long = 0x00002478; +pub const MSDOS_SUPER_MAGIC: ::c_long = 0x00004d44; +pub const NCP_SUPER_MAGIC: ::c_long = 0x0000564c; +pub const NFS_SUPER_MAGIC: ::c_long = 0x00006969; +pub const OPENPROM_SUPER_MAGIC: ::c_long = 0x00009fa1; +pub const PROC_SUPER_MAGIC: ::c_long = 0x00009fa0; +pub const QNX4_SUPER_MAGIC: ::c_long = 0x0000002f; +pub const REISERFS_SUPER_MAGIC: ::c_long = 0x52654973; +pub const SMB_SUPER_MAGIC: ::c_long = 0x0000517b; +pub const TMPFS_MAGIC: ::c_long = 0x01021994; +pub const USBDEVICE_SUPER_MAGIC: ::c_long = 0x00009fa2; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const PTRACE_TRACEME: ::c_int = 0; +pub const PTRACE_PEEKTEXT: ::c_int = 1; +pub const PTRACE_PEEKDATA: ::c_int = 2; +pub const PTRACE_PEEKUSER: ::c_int = 3; +pub const PTRACE_POKETEXT: ::c_int = 4; +pub const PTRACE_POKEDATA: ::c_int = 5; +pub const PTRACE_POKEUSER: ::c_int = 6; +pub const PTRACE_CONT: ::c_int = 7; +pub const PTRACE_KILL: ::c_int = 8; +pub const PTRACE_SINGLESTEP: ::c_int = 9; +pub const PTRACE_ATTACH: ::c_int = 16; +pub const PTRACE_DETACH: ::c_int = 17; +pub const PTRACE_SYSCALL: ::c_int = 24; +pub const PTRACE_SETOPTIONS: ::c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_int = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_int = 0x4203; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCINQ: ::c_int = 0x541B; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; +pub const ST_NODEV: ::c_ulong = 4; +pub const ST_NOEXEC: ::c_ulong = 8; +pub const ST_SYNCHRONOUS: ::c_ulong = 16; +pub const ST_MANDLOCK: ::c_ulong = 64; +pub const ST_NOATIME: ::c_ulong = 1024; +pub const ST_NODIRATIME: ::c_ulong = 2048; +pub const ST_RELATIME: ::c_ulong = 4096; + +pub const RTLD_NOLOAD: ::c_int = 0x4; + +pub const SEM_FAILED: *mut sem_t = 0 as *mut sem_t; + +pub const LINUX_REBOOT_MAGIC1: ::c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: ::c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: ::c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: ::c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: ::c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: ::c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: ::c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: ::c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: ::c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: ::c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NODATA: ::c_int = 7; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 14; + +pub const NETLINK_ROUTE: ::c_int = 0; +pub const NETLINK_UNUSED: ::c_int = 1; +pub const NETLINK_USERSOCK: ::c_int = 2; +pub const NETLINK_FIREWALL: ::c_int = 3; +pub const NETLINK_SOCK_DIAG: ::c_int = 4; +pub const NETLINK_NFLOG: ::c_int = 5; +pub const NETLINK_XFRM: ::c_int = 6; +pub const NETLINK_SELINUX: ::c_int = 7; +pub const NETLINK_ISCSI: ::c_int = 8; +pub const NETLINK_AUDIT: ::c_int = 9; +pub const NETLINK_FIB_LOOKUP: ::c_int = 10; +pub const NETLINK_CONNECTOR: ::c_int = 11; +pub const NETLINK_NETFILTER: ::c_int = 12; +pub const NETLINK_IP6_FW: ::c_int = 13; +pub const NETLINK_DNRTMSG: ::c_int = 14; +pub const NETLINK_KOBJECT_UEVENT: ::c_int = 15; +pub const NETLINK_GENERIC: ::c_int = 16; +pub const NETLINK_SCSITRANSPORT: ::c_int = 18; +pub const NETLINK_ECRYPTFS: ::c_int = 19; +pub const NETLINK_RDMA: ::c_int = 20; +pub const NETLINK_CRYPTO: ::c_int = 21; +pub const NETLINK_INET_DIAG: ::c_int = NETLINK_SOCK_DIAG; + +pub const MAX_LINKS: ::c_int = 32; + +pub const NLM_F_REQUEST: ::c_int = 1; +pub const NLM_F_MULTI: ::c_int = 2; +pub const NLM_F_ACK: ::c_int = 4; +pub const NLM_F_ECHO: ::c_int = 8; +pub const NLM_F_DUMP_INTR: ::c_int = 16; + +pub const NLM_F_ROOT: ::c_int = 0x100; +pub const NLM_F_MATCH: ::c_int = 0x200; +pub const NLM_F_ATOMIC: ::c_int = 0x400; +pub const NLM_F_DUMP: ::c_int = NLM_F_ROOT | NLM_F_MATCH; + +pub const NLM_F_REPLACE: ::c_int = 0x100; +pub const NLM_F_EXCL: ::c_int = 0x200; +pub const NLM_F_CREATE: ::c_int = 0x400; +pub const NLM_F_APPEND: ::c_int = 0x800; + +pub const NLMSG_NOOP: ::c_int = 0x1; +pub const NLMSG_ERROR: ::c_int = 0x2; +pub const NLMSG_DONE: ::c_int = 0x3; +pub const NLMSG_OVERRUN: ::c_int = 0x4; +pub const NLMSG_MIN_TYPE: ::c_int = 0x10; + +pub const GENL_NAMSIZ: ::c_int = 16; + +pub const GENL_MIN_ID: ::c_int = NLMSG_MIN_TYPE; +pub const GENL_MAX_ID: ::c_int = 1023; + +pub const GENL_ADMIN_PERM: ::c_int = 0x01; +pub const GENL_CMD_CAP_DO: ::c_int = 0x02; +pub const GENL_CMD_CAP_DUMP: ::c_int = 0x04; +pub const GENL_CMD_CAP_HASPOL: ::c_int = 0x08; +pub const GENL_UNS_ADMIN_PERM: ::c_int = 0x10; + +pub const GENL_ID_CTRL: ::c_int = NLMSG_MIN_TYPE; +pub const GENL_ID_VFS_DQUOT: ::c_int = NLMSG_MIN_TYPE + 1; +pub const GENL_ID_PMCRAID: ::c_int = NLMSG_MIN_TYPE + 2; + +pub const CTRL_CMD_UNSPEC: ::c_int = 0; +pub const CTRL_CMD_NEWFAMILY: ::c_int = 1; +pub const CTRL_CMD_DELFAMILY: ::c_int = 2; +pub const CTRL_CMD_GETFAMILY: ::c_int = 3; +pub const CTRL_CMD_NEWOPS: ::c_int = 4; +pub const CTRL_CMD_DELOPS: ::c_int = 5; +pub const CTRL_CMD_GETOPS: ::c_int = 6; +pub const CTRL_CMD_NEWMCAST_GRP: ::c_int = 7; +pub const CTRL_CMD_DELMCAST_GRP: ::c_int = 8; +pub const CTRL_CMD_GETMCAST_GRP: ::c_int = 9; + +pub const CTRL_ATTR_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_FAMILY_ID: ::c_int = 1; +pub const CTRL_ATTR_FAMILY_NAME: ::c_int = 2; +pub const CTRL_ATTR_VERSION: ::c_int = 3; +pub const CTRL_ATTR_HDRSIZE: ::c_int = 4; +pub const CTRL_ATTR_MAXATTR: ::c_int = 5; +pub const CTRL_ATTR_OPS: ::c_int = 6; +pub const CTRL_ATTR_MCAST_GROUPS: ::c_int = 7; + +pub const CTRL_ATTR_OP_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_OP_ID: ::c_int = 1; +pub const CTRL_ATTR_OP_FLAGS: ::c_int = 2; + +pub const CTRL_ATTR_MCAST_GRP_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_MCAST_GRP_NAME: ::c_int = 1; +pub const CTRL_ATTR_MCAST_GRP_ID: ::c_int = 2; + +pub const NETLINK_ADD_MEMBERSHIP: ::c_int = 1; +pub const NETLINK_DROP_MEMBERSHIP: ::c_int = 2; +pub const NETLINK_PKTINFO: ::c_int = 3; +pub const NETLINK_BROADCAST_ERROR: ::c_int = 4; +pub const NETLINK_NO_ENOBUFS: ::c_int = 5; +pub const NETLINK_RX_RING: ::c_int = 6; +pub const NETLINK_TX_RING: ::c_int = 7; + +pub const GRND_NONBLOCK: ::c_uint = 0x0001; +pub const GRND_RANDOM: ::c_uint = 0x0002; + +pub const SECCOMP_MODE_DISABLED: ::c_uint = 0; +pub const SECCOMP_MODE_STRICT: ::c_uint = 1; +pub const SECCOMP_MODE_FILTER: ::c_uint = 2; + +pub const NLA_F_NESTED: ::c_int = 1 << 15; +pub const NLA_F_NET_BYTEORDER: ::c_int = 1 << 14; +pub const NLA_TYPE_MASK: ::c_int = !(NLA_F_NESTED | NLA_F_NET_BYTEORDER); + +pub const NLA_ALIGNTO: ::c_int = 4; + +pub const SIGEV_THREAD_ID: ::c_int = 4; + +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const SFD_CLOEXEC: ::c_int = O_CLOEXEC; +pub const SFD_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const SOCK_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const SO_ORIGINAL_DST: ::c_int = 80; +pub const IP_ORIGDSTADDR : ::c_int = 20; +pub const IP_RECVORIGDSTADDR : ::c_int = IP_ORIGDSTADDR; +pub const IPV6_ORIGDSTADDR : ::c_int = 74; +pub const IPV6_RECVORIGDSTADDR : ::c_int = IPV6_ORIGDSTADDR; +pub const IPV6_FLOWINFO: ::c_int = 11; +pub const IPV6_FLOWLABEL_MGR: ::c_int = 32; +pub const IPV6_FLOWINFO_SEND: ::c_int = 33; +pub const IPV6_FLOWINFO_FLOWLABEL: ::c_int = 0x000fffff; +pub const IPV6_FLOWINFO_PRIORITY: ::c_int = 0x0ff00000; +pub const IUTF8: ::tcflag_t = 0x00004000; +pub const CMSPAR: ::tcflag_t = 0o10000000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const MFD_CLOEXEC: ::c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002; +pub const MFD_HUGETLB: ::c_uint = 0x0004; + +// linux/netfilter.h +pub const NF_DROP: ::c_int = 0; +pub const NF_ACCEPT: ::c_int = 1; +pub const NF_STOLEN: ::c_int = 2; +pub const NF_QUEUE: ::c_int = 3; +pub const NF_REPEAT: ::c_int = 4; +pub const NF_STOP: ::c_int = 5; +pub const NF_MAX_VERDICT: ::c_int = NF_STOP; + +pub const NF_VERDICT_MASK: ::c_int = 0x000000ff; +pub const NF_VERDICT_FLAG_QUEUE_BYPASS: ::c_int = 0x00008000; + +pub const NF_VERDICT_QMASK: ::c_int = 0xffff0000; +pub const NF_VERDICT_QBITS: ::c_int = 16; + +pub const NF_VERDICT_BITS: ::c_int = 16; + +pub const NF_INET_PRE_ROUTING: ::c_int = 0; +pub const NF_INET_LOCAL_IN: ::c_int = 1; +pub const NF_INET_FORWARD: ::c_int = 2; +pub const NF_INET_LOCAL_OUT: ::c_int = 3; +pub const NF_INET_POST_ROUTING: ::c_int = 4; +pub const NF_INET_NUMHOOKS: ::c_int = 5; + +pub const NF_NETDEV_INGRESS: ::c_int = 0; +pub const NF_NETDEV_NUMHOOKS: ::c_int = 1; + +pub const NFPROTO_UNSPEC: ::c_int = 0; +pub const NFPROTO_INET: ::c_int = 1; +pub const NFPROTO_IPV4: ::c_int = 2; +pub const NFPROTO_ARP: ::c_int = 3; +pub const NFPROTO_NETDEV: ::c_int = 5; +pub const NFPROTO_BRIDGE: ::c_int = 7; +pub const NFPROTO_IPV6: ::c_int = 10; +pub const NFPROTO_DECNET: ::c_int = 12; +pub const NFPROTO_NUMPROTO: ::c_int = 13; + +// linux/netfilter_ipv4.h +pub const NF_IP_PRE_ROUTING: ::c_int = 0; +pub const NF_IP_LOCAL_IN: ::c_int = 1; +pub const NF_IP_FORWARD: ::c_int = 2; +pub const NF_IP_LOCAL_OUT: ::c_int = 3; +pub const NF_IP_POST_ROUTING: ::c_int = 4; +pub const NF_IP_NUMHOOKS: ::c_int = 5; + +pub const NF_IP_PRI_FIRST: ::c_int = ::INT_MIN; +pub const NF_IP_PRI_CONNTRACK_DEFRAG: ::c_int = -400; +pub const NF_IP_PRI_RAW: ::c_int = -300; +pub const NF_IP_PRI_SELINUX_FIRST: ::c_int = -225; +pub const NF_IP_PRI_CONNTRACK: ::c_int = -200; +pub const NF_IP_PRI_MANGLE: ::c_int = -150; +pub const NF_IP_PRI_NAT_DST: ::c_int = -100; +pub const NF_IP_PRI_FILTER: ::c_int = 0; +pub const NF_IP_PRI_SECURITY: ::c_int = 50; +pub const NF_IP_PRI_NAT_SRC: ::c_int = 100; +pub const NF_IP_PRI_SELINUX_LAST: ::c_int = 225; +pub const NF_IP_PRI_CONNTRACK_HELPER: ::c_int = 300; +pub const NF_IP_PRI_CONNTRACK_CONFIRM: ::c_int = ::INT_MAX; +pub const NF_IP_PRI_LAST: ::c_int = ::INT_MAX; + +// linux/netfilter_ipv6.h +pub const NF_IP6_PRE_ROUTING: ::c_int = 0; +pub const NF_IP6_LOCAL_IN: ::c_int = 1; +pub const NF_IP6_FORWARD: ::c_int = 2; +pub const NF_IP6_LOCAL_OUT: ::c_int = 3; +pub const NF_IP6_POST_ROUTING: ::c_int = 4; +pub const NF_IP6_NUMHOOKS: ::c_int = 5; + +pub const NF_IP6_PRI_FIRST: ::c_int = ::INT_MIN; +pub const NF_IP6_PRI_CONNTRACK_DEFRAG: ::c_int = -400; +pub const NF_IP6_PRI_RAW: ::c_int = -300; +pub const NF_IP6_PRI_SELINUX_FIRST: ::c_int = -225; +pub const NF_IP6_PRI_CONNTRACK: ::c_int = -200; +pub const NF_IP6_PRI_MANGLE: ::c_int = -150; +pub const NF_IP6_PRI_NAT_DST: ::c_int = -100; +pub const NF_IP6_PRI_FILTER: ::c_int = 0; +pub const NF_IP6_PRI_SECURITY: ::c_int = 50; +pub const NF_IP6_PRI_NAT_SRC: ::c_int = 100; +pub const NF_IP6_PRI_SELINUX_LAST: ::c_int = 225; +pub const NF_IP6_PRI_CONNTRACK_HELPER: ::c_int = 300; +pub const NF_IP6_PRI_LAST: ::c_int = ::INT_MAX; + +// linux/netfilter/nf_tables.h +pub const NFT_TABLE_MAXNAMELEN: ::c_int = 32; +pub const NFT_CHAIN_MAXNAMELEN: ::c_int = 32; +pub const NFT_SET_MAXNAMELEN: ::c_int = 32; +pub const NFT_OBJ_MAXNAMELEN: ::c_int = 32; +pub const NFT_USERDATA_MAXLEN: ::c_int = 256; + +pub const NFT_REG_VERDICT: ::c_int = 0; +pub const NFT_REG_1: ::c_int = 1; +pub const NFT_REG_2: ::c_int = 2; +pub const NFT_REG_3: ::c_int = 3; +pub const NFT_REG_4: ::c_int = 4; +pub const __NFT_REG_MAX: ::c_int = 5; +pub const NFT_REG32_00: ::c_int = 8; +pub const NFT_REG32_01: ::c_int = 9; +pub const NFT_REG32_02: ::c_int = 10; +pub const NFT_REG32_03: ::c_int = 11; +pub const NFT_REG32_04: ::c_int = 12; +pub const NFT_REG32_05: ::c_int = 13; +pub const NFT_REG32_06: ::c_int = 14; +pub const NFT_REG32_07: ::c_int = 15; +pub const NFT_REG32_08: ::c_int = 16; +pub const NFT_REG32_09: ::c_int = 17; +pub const NFT_REG32_10: ::c_int = 18; +pub const NFT_REG32_11: ::c_int = 19; +pub const NFT_REG32_12: ::c_int = 20; +pub const NFT_REG32_13: ::c_int = 21; +pub const NFT_REG32_14: ::c_int = 22; +pub const NFT_REG32_15: ::c_int = 23; + +pub const NFT_REG_SIZE: ::c_int = 16; +pub const NFT_REG32_SIZE: ::c_int = 4; + +pub const NFT_CONTINUE: ::c_int = -1; +pub const NFT_BREAK: ::c_int = -2; +pub const NFT_JUMP: ::c_int = -3; +pub const NFT_GOTO: ::c_int = -4; +pub const NFT_RETURN: ::c_int = -5; + +pub const NFT_MSG_NEWTABLE: ::c_int = 0; +pub const NFT_MSG_GETTABLE: ::c_int = 1; +pub const NFT_MSG_DELTABLE: ::c_int = 2; +pub const NFT_MSG_NEWCHAIN: ::c_int = 3; +pub const NFT_MSG_GETCHAIN: ::c_int = 4; +pub const NFT_MSG_DELCHAIN: ::c_int = 5; +pub const NFT_MSG_NEWRULE: ::c_int = 6; +pub const NFT_MSG_GETRULE: ::c_int = 7; +pub const NFT_MSG_DELRULE: ::c_int = 8; +pub const NFT_MSG_NEWSET: ::c_int = 9; +pub const NFT_MSG_GETSET: ::c_int = 10; +pub const NFT_MSG_DELSET: ::c_int = 11; +pub const NFT_MSG_NEWSETELEM: ::c_int = 12; +pub const NFT_MSG_GETSETELEM: ::c_int = 13; +pub const NFT_MSG_DELSETELEM: ::c_int = 14; +pub const NFT_MSG_NEWGEN: ::c_int = 15; +pub const NFT_MSG_GETGEN: ::c_int = 16; +pub const NFT_MSG_TRACE: ::c_int = 17; +pub const NFT_MSG_NEWOBJ: ::c_int = 18; +pub const NFT_MSG_GETOBJ: ::c_int = 19; +pub const NFT_MSG_DELOBJ: ::c_int = 20; +pub const NFT_MSG_GETOBJ_RESET: ::c_int = 21; +pub const NFT_MSG_MAX: ::c_int = 22; + +pub const NFT_SET_ANONYMOUS: ::c_int = 0x1; +pub const NFT_SET_CONSTANT: ::c_int = 0x2; +pub const NFT_SET_INTERVAL: ::c_int = 0x4; +pub const NFT_SET_MAP: ::c_int = 0x8; +pub const NFT_SET_TIMEOUT: ::c_int = 0x10; +pub const NFT_SET_EVAL: ::c_int = 0x20; + +pub const NFT_SET_POL_PERFORMANCE: ::c_int = 0; +pub const NFT_SET_POL_MEMORY: ::c_int = 1; + +pub const NFT_SET_ELEM_INTERVAL_END: ::c_int = 0x1; + +pub const NFT_DATA_VALUE: ::c_uint = 0; +pub const NFT_DATA_VERDICT: ::c_uint = 0xffffff00; + +pub const NFT_DATA_RESERVED_MASK: ::c_uint = 0xffffff00; + +pub const NFT_DATA_VALUE_MAXLEN: ::c_int = 64; + +pub const NFT_BYTEORDER_NTOH: ::c_int = 0; +pub const NFT_BYTEORDER_HTON: ::c_int = 1; + +pub const NFT_CMP_EQ: ::c_int = 0; +pub const NFT_CMP_NEQ: ::c_int = 1; +pub const NFT_CMP_LT: ::c_int = 2; +pub const NFT_CMP_LTE: ::c_int = 3; +pub const NFT_CMP_GT: ::c_int = 4; +pub const NFT_CMP_GTE: ::c_int = 5; + +pub const NFT_RANGE_EQ: ::c_int = 0; +pub const NFT_RANGE_NEQ: ::c_int = 1; + +pub const NFT_LOOKUP_F_INV: ::c_int = (1 << 0); + +pub const NFT_DYNSET_OP_ADD: ::c_int = 0; +pub const NFT_DYNSET_OP_UPDATE: ::c_int = 1; + +pub const NFT_DYNSET_F_INV: ::c_int = (1 << 0); + +pub const NFT_PAYLOAD_LL_HEADER: ::c_int = 0; +pub const NFT_PAYLOAD_NETWORK_HEADER: ::c_int = 1; +pub const NFT_PAYLOAD_TRANSPORT_HEADER: ::c_int = 2; + +pub const NFT_PAYLOAD_CSUM_NONE: ::c_int = 0; +pub const NFT_PAYLOAD_CSUM_INET: ::c_int = 1; + +pub const NFT_META_LEN: ::c_int = 0; +pub const NFT_META_PROTOCOL: ::c_int = 1; +pub const NFT_META_PRIORITY: ::c_int = 2; +pub const NFT_META_MARK: ::c_int = 3; +pub const NFT_META_IIF: ::c_int = 4; +pub const NFT_META_OIF: ::c_int = 5; +pub const NFT_META_IIFNAME: ::c_int = 6; +pub const NFT_META_OIFNAME: ::c_int = 7; +pub const NFT_META_IIFTYPE: ::c_int = 8; +pub const NFT_META_OIFTYPE: ::c_int = 9; +pub const NFT_META_SKUID: ::c_int = 10; +pub const NFT_META_SKGID: ::c_int = 11; +pub const NFT_META_NFTRACE: ::c_int = 12; +pub const NFT_META_RTCLASSID: ::c_int = 13; +pub const NFT_META_SECMARK: ::c_int = 14; +pub const NFT_META_NFPROTO: ::c_int = 15; +pub const NFT_META_L4PROTO: ::c_int = 16; +pub const NFT_META_BRI_IIFNAME: ::c_int = 17; +pub const NFT_META_BRI_OIFNAME: ::c_int = 18; +pub const NFT_META_PKTTYPE: ::c_int = 19; +pub const NFT_META_CPU: ::c_int = 20; +pub const NFT_META_IIFGROUP: ::c_int = 21; +pub const NFT_META_OIFGROUP: ::c_int = 22; +pub const NFT_META_CGROUP: ::c_int = 23; +pub const NFT_META_PRANDOM: ::c_int = 24; + +pub const NFT_CT_STATE: ::c_int = 0; +pub const NFT_CT_DIRECTION: ::c_int = 1; +pub const NFT_CT_STATUS: ::c_int = 2; +pub const NFT_CT_MARK: ::c_int = 3; +pub const NFT_CT_SECMARK: ::c_int = 4; +pub const NFT_CT_EXPIRATION: ::c_int = 5; +pub const NFT_CT_HELPER: ::c_int = 6; +pub const NFT_CT_L3PROTOCOL: ::c_int = 7; +pub const NFT_CT_SRC: ::c_int = 8; +pub const NFT_CT_DST: ::c_int = 9; +pub const NFT_CT_PROTOCOL: ::c_int = 10; +pub const NFT_CT_PROTO_SRC: ::c_int = 11; +pub const NFT_CT_PROTO_DST: ::c_int = 12; +pub const NFT_CT_LABELS: ::c_int = 13; +pub const NFT_CT_PKTS: ::c_int = 14; +pub const NFT_CT_BYTES: ::c_int = 15; + +pub const NFT_LIMIT_PKTS: ::c_int = 0; +pub const NFT_LIMIT_PKT_BYTES: ::c_int = 1; + +pub const NFT_LIMIT_F_INV: ::c_int = (1 << 0); + +pub const NFT_QUEUE_FLAG_BYPASS: ::c_int = 0x01; +pub const NFT_QUEUE_FLAG_CPU_FANOUT: ::c_int = 0x02; +pub const NFT_QUEUE_FLAG_MASK: ::c_int = 0x03; + +pub const NFT_QUOTA_F_INV: ::c_int = (1 << 0); + +pub const NFT_REJECT_ICMP_UNREACH: ::c_int = 0; +pub const NFT_REJECT_TCP_RST: ::c_int = 1; +pub const NFT_REJECT_ICMPX_UNREACH: ::c_int = 2; + +pub const NFT_REJECT_ICMPX_NO_ROUTE: ::c_int = 0; +pub const NFT_REJECT_ICMPX_PORT_UNREACH: ::c_int = 1; +pub const NFT_REJECT_ICMPX_HOST_UNREACH: ::c_int = 2; +pub const NFT_REJECT_ICMPX_ADMIN_PROHIBITED: ::c_int = 3; + +pub const NFT_NAT_SNAT: ::c_int = 0; +pub const NFT_NAT_DNAT: ::c_int = 1; + +pub const NFT_TRACETYPE_UNSPEC: ::c_int = 0; +pub const NFT_TRACETYPE_POLICY: ::c_int = 1; +pub const NFT_TRACETYPE_RETURN: ::c_int = 2; +pub const NFT_TRACETYPE_RULE: ::c_int = 3; + +pub const NFT_NG_INCREMENTAL: ::c_int = 0; +pub const NFT_NG_RANDOM: ::c_int = 1; + +pub const IFF_TUN: ::c_int = 0x0001; +pub const IFF_TAP: ::c_int = 0x0002; +pub const IFF_NO_PI: ::c_int = 0x1000; + +// start android/platform/bionic/libc/kernel/uapi/linux/if_ether.h +// from https://android.googlesource.com/ +// platform/bionic/+/master/libc/kernel/uapi/linux/if_ether.h +pub const ETH_ALEN: ::c_int = 6; +pub const ETH_HLEN: ::c_int = 14; +pub const ETH_ZLEN: ::c_int = 60; +pub const ETH_DATA_LEN: ::c_int = 1500; +pub const ETH_FRAME_LEN: ::c_int = 1514; +pub const ETH_FCS_LEN: ::c_int = 4; +pub const ETH_MIN_MTU: ::c_int = 68; +pub const ETH_MAX_MTU: ::c_int = 0xFFFF; +pub const ETH_P_LOOP: ::c_int = 0x0060; +pub const ETH_P_PUP: ::c_int = 0x0200; +pub const ETH_P_PUPAT: ::c_int = 0x0201; +pub const ETH_P_TSN: ::c_int = 0x22F0; +pub const ETH_P_IP: ::c_int = 0x0800; +pub const ETH_P_X25: ::c_int = 0x0805; +pub const ETH_P_ARP: ::c_int = 0x0806; +pub const ETH_P_BPQ: ::c_int = 0x08FF; +pub const ETH_P_IEEEPUP: ::c_int = 0x0a00; +pub const ETH_P_IEEEPUPAT: ::c_int = 0x0a01; +pub const ETH_P_BATMAN: ::c_int = 0x4305; +pub const ETH_P_DEC: ::c_int = 0x6000; +pub const ETH_P_DNA_DL: ::c_int = 0x6001; +pub const ETH_P_DNA_RC: ::c_int = 0x6002; +pub const ETH_P_DNA_RT: ::c_int = 0x6003; +pub const ETH_P_LAT: ::c_int = 0x6004; +pub const ETH_P_DIAG: ::c_int = 0x6005; +pub const ETH_P_CUST: ::c_int = 0x6006; +pub const ETH_P_SCA: ::c_int = 0x6007; +pub const ETH_P_TEB: ::c_int = 0x6558; +pub const ETH_P_RARP: ::c_int = 0x8035; +pub const ETH_P_ATALK: ::c_int = 0x809B; +pub const ETH_P_AARP: ::c_int = 0x80F3; +pub const ETH_P_8021Q: ::c_int = 0x8100; +/* see rust-lang/libc#924 pub const ETH_P_ERSPAN: ::c_int = 0x88BE;*/ +pub const ETH_P_IPX: ::c_int = 0x8137; +pub const ETH_P_IPV6: ::c_int = 0x86DD; +pub const ETH_P_PAUSE: ::c_int = 0x8808; +pub const ETH_P_SLOW: ::c_int = 0x8809; +pub const ETH_P_WCCP: ::c_int = 0x883E; +pub const ETH_P_MPLS_UC: ::c_int = 0x8847; +pub const ETH_P_MPLS_MC: ::c_int = 0x8848; +pub const ETH_P_ATMMPOA: ::c_int = 0x884c; +pub const ETH_P_PPP_DISC: ::c_int = 0x8863; +pub const ETH_P_PPP_SES: ::c_int = 0x8864; +pub const ETH_P_LINK_CTL: ::c_int = 0x886c; +pub const ETH_P_ATMFATE: ::c_int = 0x8884; +pub const ETH_P_PAE: ::c_int = 0x888E; +pub const ETH_P_AOE: ::c_int = 0x88A2; +pub const ETH_P_8021AD: ::c_int = 0x88A8; +pub const ETH_P_802_EX1: ::c_int = 0x88B5; +pub const ETH_P_TIPC: ::c_int = 0x88CA; +pub const ETH_P_MACSEC: ::c_int = 0x88E5; +pub const ETH_P_8021AH: ::c_int = 0x88E7; +pub const ETH_P_MVRP: ::c_int = 0x88F5; +pub const ETH_P_1588: ::c_int = 0x88F7; +pub const ETH_P_NCSI: ::c_int = 0x88F8; +pub const ETH_P_PRP: ::c_int = 0x88FB; +pub const ETH_P_FCOE: ::c_int = 0x8906; +/* see rust-lang/libc#924 pub const ETH_P_IBOE: ::c_int = 0x8915;*/ +pub const ETH_P_TDLS: ::c_int = 0x890D; +pub const ETH_P_FIP: ::c_int = 0x8914; +pub const ETH_P_80221: ::c_int = 0x8917; +pub const ETH_P_HSR: ::c_int = 0x892F; +/* see rust-lang/libc#924 pub const ETH_P_NSH: ::c_int = 0x894F;*/ +pub const ETH_P_LOOPBACK: ::c_int = 0x9000; +pub const ETH_P_QINQ1: ::c_int = 0x9100; +pub const ETH_P_QINQ2: ::c_int = 0x9200; +pub const ETH_P_QINQ3: ::c_int = 0x9300; +pub const ETH_P_EDSA: ::c_int = 0xDADA; +/* see rust-lang/libc#924 pub const ETH_P_IFE: ::c_int = 0xED3E;*/ +pub const ETH_P_AF_IUCV: ::c_int = 0xFBFB; +pub const ETH_P_802_3_MIN: ::c_int = 0x0600; +pub const ETH_P_802_3: ::c_int = 0x0001; +pub const ETH_P_AX25: ::c_int = 0x0002; +pub const ETH_P_ALL: ::c_int = 0x0003; +pub const ETH_P_802_2: ::c_int = 0x0004; +pub const ETH_P_SNAP: ::c_int = 0x0005; +pub const ETH_P_DDCMP: ::c_int = 0x0006; +pub const ETH_P_WAN_PPP: ::c_int = 0x0007; +pub const ETH_P_PPP_MP: ::c_int = 0x0008; +pub const ETH_P_LOCALTALK: ::c_int = 0x0009; +pub const ETH_P_CAN: ::c_int = 0x000C; +pub const ETH_P_CANFD: ::c_int = 0x000D; +pub const ETH_P_PPPTALK: ::c_int = 0x0010; +pub const ETH_P_TR_802_2: ::c_int = 0x0011; +pub const ETH_P_MOBITEX: ::c_int = 0x0015; +pub const ETH_P_CONTROL: ::c_int = 0x0016; +pub const ETH_P_IRDA: ::c_int = 0x0017; +pub const ETH_P_ECONET: ::c_int = 0x0018; +pub const ETH_P_HDLC: ::c_int = 0x0019; +pub const ETH_P_ARCNET: ::c_int = 0x001A; +pub const ETH_P_DSA: ::c_int = 0x001B; +pub const ETH_P_TRAILER: ::c_int = 0x001C; +pub const ETH_P_PHONET: ::c_int = 0x00F5; +pub const ETH_P_IEEE802154: ::c_int = 0x00F6; +pub const ETH_P_CAIF: ::c_int = 0x00F7; +pub const ETH_P_XDSA: ::c_int = 0x00F8; +/* see rust-lang/libc#924 pub const ETH_P_MAP: ::c_int = 0x00F9;*/ +// end android/platform/bionic/libc/kernel/uapi/linux/if_ether.h + +pub const SIOCADDRT: ::c_ulong = 0x0000890B; +pub const SIOCDELRT: ::c_ulong = 0x0000890C; +pub const SIOCGIFNAME: ::c_ulong = 0x00008910; +pub const SIOCSIFLINK: ::c_ulong = 0x00008911; +pub const SIOCGIFCONF: ::c_ulong = 0x00008912; +pub const SIOCGIFFLAGS: ::c_ulong = 0x00008913; +pub const SIOCSIFFLAGS: ::c_ulong = 0x00008914; +pub const SIOCGIFADDR: ::c_ulong = 0x00008915; +pub const SIOCSIFADDR: ::c_ulong = 0x00008916; +pub const SIOCGIFDSTADDR: ::c_ulong = 0x00008917; +pub const SIOCSIFDSTADDR: ::c_ulong = 0x00008918; +pub const SIOCGIFBRDADDR: ::c_ulong = 0x00008919; +pub const SIOCSIFBRDADDR: ::c_ulong = 0x0000891A; +pub const SIOCGIFNETMASK: ::c_ulong = 0x0000891B; +pub const SIOCSIFNETMASK: ::c_ulong = 0x0000891C; +pub const SIOCGIFMETRIC: ::c_ulong = 0x0000891D; +pub const SIOCSIFMETRIC: ::c_ulong = 0x0000891E; +pub const SIOCGIFMEM: ::c_ulong = 0x0000891F; +pub const SIOCSIFMEM: ::c_ulong = 0x00008920; +pub const SIOCGIFMTU: ::c_ulong = 0x00008921; +pub const SIOCSIFMTU: ::c_ulong = 0x00008922; +pub const SIOCSIFHWADDR: ::c_ulong = 0x00008924; +pub const SIOCGIFENCAP: ::c_ulong = 0x00008925; +pub const SIOCSIFENCAP: ::c_ulong = 0x00008926; +pub const SIOCGIFHWADDR: ::c_ulong = 0x00008927; +pub const SIOCGIFSLAVE: ::c_ulong = 0x00008929; +pub const SIOCSIFSLAVE: ::c_ulong = 0x00008930; +pub const SIOCADDMULTI: ::c_ulong = 0x00008931; +pub const SIOCDELMULTI: ::c_ulong = 0x00008932; +pub const SIOCDARP: ::c_ulong = 0x00008953; +pub const SIOCGARP: ::c_ulong = 0x00008954; +pub const SIOCSARP: ::c_ulong = 0x00008955; +pub const SIOCDRARP: ::c_ulong = 0x00008960; +pub const SIOCGRARP: ::c_ulong = 0x00008961; +pub const SIOCSRARP: ::c_ulong = 0x00008962; +pub const SIOCGIFMAP: ::c_ulong = 0x00008970; +pub const SIOCSIFMAP: ::c_ulong = 0x00008971; + +// linux/module.h +pub const MODULE_INIT_IGNORE_MODVERSIONS: ::c_uint = 0x0001; +pub const MODULE_INIT_IGNORE_VERMAGIC: ::c_uint = 0x0002; + +// Similarity to Linux it's not used but defined for compatibility. +pub const ENOATTR: ::c_int = ::ENODATA; + +// linux/if_alg.h +pub const ALG_SET_KEY: ::c_int = 1; +pub const ALG_SET_IV: ::c_int = 2; +pub const ALG_SET_OP: ::c_int = 3; +pub const ALG_SET_AEAD_ASSOCLEN: ::c_int = 4; +pub const ALG_SET_AEAD_AUTHSIZE: ::c_int = 5; + +pub const ALG_OP_DECRYPT: ::c_int = 0; +pub const ALG_OP_ENCRYPT: ::c_int = 1; + +// uapi/linux/inotify.h +pub const IN_ACCESS: ::uint32_t = 0x0000_0001; +pub const IN_MODIFY: ::uint32_t = 0x0000_0002; +pub const IN_ATTRIB: ::uint32_t = 0x0000_0004; +pub const IN_CLOSE_WRITE: ::uint32_t = 0x0000_0008; +pub const IN_CLOSE_NOWRITE: ::uint32_t = 0x0000_0010; +pub const IN_CLOSE: ::uint32_t = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE); +pub const IN_OPEN: ::uint32_t = 0x0000_0020; +pub const IN_MOVED_FROM: ::uint32_t = 0x0000_0040; +pub const IN_MOVED_TO: ::uint32_t = 0x0000_0080; +pub const IN_MOVE: ::uint32_t = (IN_MOVED_FROM | IN_MOVED_TO); +pub const IN_CREATE: ::uint32_t = 0x0000_0100; +pub const IN_DELETE: ::uint32_t = 0x0000_0200; +pub const IN_DELETE_SELF: ::uint32_t = 0x0000_0400; +pub const IN_MOVE_SELF: ::uint32_t = 0x0000_0800; +pub const IN_UNMOUNT: ::uint32_t = 0x0000_2000; +pub const IN_Q_OVERFLOW: ::uint32_t = 0x0000_4000; +pub const IN_IGNORED: ::uint32_t = 0x0000_8000; +pub const IN_ONLYDIR: ::uint32_t = 0x0100_0000; +pub const IN_DONT_FOLLOW: ::uint32_t = 0x0200_0000; +// pub const IN_EXCL_UNLINK: ::uint32_t = 0x0400_0000; + +// pub const IN_MASK_CREATE: ::uint32_t = 0x1000_0000; +// pub const IN_MASK_ADD: ::uint32_t = 0x2000_0000; +pub const IN_ISDIR: ::uint32_t = 0x4000_0000; +pub const IN_ONESHOT: ::uint32_t = 0x8000_0000; + +pub const IN_ALL_EVENTS: ::uint32_t = ( + IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | + IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | + IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | + IN_MOVE_SELF +); + +pub const IN_CLOEXEC: ::c_int = O_CLOEXEC; +pub const IN_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const FUTEX_WAIT: ::c_int = 0; +pub const FUTEX_WAKE: ::c_int = 1; +pub const FUTEX_FD: ::c_int = 2; +pub const FUTEX_REQUEUE: ::c_int = 3; +pub const FUTEX_CMP_REQUEUE: ::c_int = 4; +pub const FUTEX_WAKE_OP: ::c_int = 5; +pub const FUTEX_LOCK_PI: ::c_int = 6; +pub const FUTEX_UNLOCK_PI: ::c_int = 7; +pub const FUTEX_TRYLOCK_PI: ::c_int = 8; +pub const FUTEX_WAIT_BITSET: ::c_int = 9; +pub const FUTEX_WAKE_BITSET: ::c_int = 10; +pub const FUTEX_WAIT_REQUEUE_PI: ::c_int = 11; +pub const FUTEX_CMP_REQUEUE_PI: ::c_int = 12; + +pub const FUTEX_PRIVATE_FLAG: ::c_int = 128; +pub const FUTEX_CLOCK_REALTIME: ::c_int = 256; +pub const FUTEX_CMD_MASK: ::c_int = + !(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, + cmsg: *const cmsghdr) -> *mut cmsghdr { + let next = (cmsg as usize + + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) + as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max { + 0 as *mut cmsghdr + } else { + next as *mut cmsghdr + } + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.__bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in___bits = 8 * ::mem::size_of_val(&cpuset.__bits[0]); + let (idx, offset) = (cpu / size_in___bits, cpu % size_in___bits); + cpuset.__bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in___bits = 8 * ::mem::size_of_val(&cpuset.__bits[0]); + let (idx, offset) = (cpu / size_in___bits, cpu % size_in___bits); + cpuset.__bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in___bits = 8 * ::mem::size_of_val(&cpuset.__bits[0]); + let (idx, offset) = (cpu / size_in___bits, cpu % size_in___bits); + 0 != (cpuset.__bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.__bits == set2.__bits + } + pub fn major(dev: ::dev_t) -> ::c_int { + ((dev >> 8) & 0xfff) as ::c_int + } + pub fn minor(dev: ::dev_t) -> ::c_int { + ((dev & 0xff) | ((dev >> 12) & 0xfff00)) as ::c_int + } + pub fn makedev(ma: ::c_int, mi: ::c_int) -> ::dev_t { + let ma = ma as ::dev_t; + let mi = mi as ::dev_t; + ((ma & 0xfff) << 8) | (mi & 0xff) | ((mi & 0xfff00) << 12) + } + + pub fn NLA_ALIGN(len: ::c_int) -> ::c_int { + return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) + } +} + +extern { + static mut __progname: *mut ::c_char; +} + +extern { + pub fn madvise(addr: *const ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; + pub fn msync(addr: *const ::c_void, len: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn mprotect(addr: *const ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *const ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::size_t, + serv: *mut ::c_char, + sevlen: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn ptrace(request: ::c_int, ...) -> ::c_long; + pub fn getpriority(which: ::c_int, who: ::c_int) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::c_int, prio: ::c_int) -> ::c_int; + pub fn __sched_cpualloc(count: ::size_t) -> *mut ::cpu_set_t; + pub fn __sched_cpufree(set: *mut ::cpu_set_t); + pub fn __sched_cpucount(setsize: ::size_t, set: *mut cpu_set_t) -> ::c_int; + pub fn sched_getcpu() -> ::c_int; + + pub fn utmpname(name: *const ::c_char) -> ::c_int; + pub fn setutent(); + pub fn getutent() -> *mut utmp; + + pub fn posix_fallocate(fd: ::c_int, offset: ::off_t, + len: ::off_t) -> ::c_int; + pub fn signalfd(fd: ::c_int, mask: *const ::sigset_t, flags: ::c_int) + -> ::c_int; + pub fn syscall(num: ::c_long, ...) -> ::c_long; + pub fn sched_getaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *mut cpu_set_t) -> ::c_int; + pub fn sched_setaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *const cpu_set_t) -> ::c_int; + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + pub fn pthread_getschedparam(native: ::pthread_t, + policy: *mut ::c_int, + param: *mut ::sched_param) -> ::c_int; + pub fn unshare(flags: ::c_int) -> ::c_int; + pub fn umount(target: *const ::c_char) -> ::c_int; + pub fn sched_get_priority_max(policy: ::c_int) -> ::c_int; + pub fn tee(fd_in: ::c_int, + fd_out: ::c_int, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn settimeofday(tv: *const ::timeval, tz: *const ::timezone) -> ::c_int; + pub fn splice(fd_in: ::c_int, + off_in: *mut ::loff_t, + fd_out: ::c_int, + off_out: *mut ::loff_t, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int; + pub fn sched_rr_get_interval(pid: ::pid_t, tp: *mut ::timespec) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn sched_setparam(pid: ::pid_t, param: *const ::sched_param) -> ::c_int; + pub fn setns(fd: ::c_int, nstype: ::c_int) -> ::c_int; + pub fn swapoff(puath: *const ::c_char) -> ::c_int; + pub fn vmsplice(fd: ::c_int, + iov: *const ::iovec, + nr_segs: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + fstype: *const ::c_char, + flags: ::c_ulong, + data: *const ::c_void) -> ::c_int; + pub fn personality(persona: ::c_ulong) -> ::c_int; + pub fn prctl(option: ::c_int, ...) -> ::c_int; + pub fn sched_getparam(pid: ::pid_t, param: *mut ::sched_param) -> ::c_int; + pub fn ppoll(fds: *mut ::pollfd, + nfds: nfds_t, + timeout: *const ::timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn clone(cb: extern fn(*mut ::c_void) -> ::c_int, + child_stack: *mut ::c_void, + flags: ::c_int, + arg: *mut ::c_void, ...) -> ::c_int; + pub fn sched_getscheduler(pid: ::pid_t) -> ::c_int; + pub fn clock_nanosleep(clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn sched_get_priority_min(policy: ::c_int) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn sysinfo(info: *mut ::sysinfo) -> ::c_int; + pub fn umount2(target: *const ::c_char, flags: ::c_int) -> ::c_int; + pub fn pthread_setschedparam(native: ::pthread_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn swapon(path: *const ::c_char, swapflags: ::c_int) -> ::c_int; + pub fn sched_setscheduler(pid: ::pid_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn sendfile(out_fd: ::c_int, + in_fd: ::c_int, + offset: *mut off_t, + count: ::size_t) -> ::ssize_t; + pub fn setfsgid(gid: ::gid_t) -> ::c_int; + pub fn setfsuid(uid: ::uid_t) -> ::c_int; + pub fn sigsuspend(mask: *const ::sigset_t) -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + pub fn getgrouplist(user: *const ::c_char, + group: ::gid_t, + groups: *mut ::gid_t, + ngroups: *mut ::c_int) -> ::c_int; + pub fn initgroups(user: *const ::c_char, group: ::gid_t) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn faccessat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::c_int, flags: ::c_int) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn __errno() -> *mut ::c_int; + pub fn inotify_rm_watch(fd: ::c_int, wd: ::uint32_t) -> ::c_int; + pub fn sendmmsg(sockfd: ::c_int, msgvec: *const ::mmsghdr, vlen: ::c_uint, + flags: ::c_int) -> ::c_int; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int, timeout: *const ::timespec) -> ::c_int; + pub fn inotify_init() -> ::c_int; + pub fn inotify_init1(flags: ::c_int) -> ::c_int; + pub fn inotify_add_watch(fd: ::c_int, + path: *const ::c_char, + mask: ::uint32_t) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod b32; + pub use self::b32::*; + } else if #[cfg(target_pointer_width = "64")] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_pointer_width + } +} diff --git a/libc/src/unix/notbsd/emscripten/align.rs b/libc/src/unix/notbsd/emscripten/align.rs new file mode 100644 index 000000000..26a49b234 --- /dev/null +++ b/libc/src/unix/notbsd/emscripten/align.rs @@ -0,0 +1,66 @@ +macro_rules! expand_align { + () => { + s! { + #[repr(align(4))] + pub struct pthread_mutex_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[repr(align(4))] + pub struct pthread_rwlock_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + #[repr(align(4))] + pub struct pthread_mutexattr_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_rwlockattr_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct pthread_cond_t { + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_cond_t {} + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + } + } + } +} diff --git a/libc/src/unix/notbsd/emscripten/mod.rs b/libc/src/unix/notbsd/emscripten/mod.rs new file mode 100644 index 000000000..0f8c76e3a --- /dev/null +++ b/libc/src/unix/notbsd/emscripten/mod.rs @@ -0,0 +1,1802 @@ +pub type c_char = i8; +pub type wchar_t = i32; +pub type useconds_t = u32; +pub type dev_t = u32; +pub type socklen_t = u32; +pub type pthread_t = c_ulong; +pub type mode_t = u32; +pub type ino64_t = u32; +pub type off64_t = i32; +pub type blkcnt64_t = i32; +pub type rlim64_t = u64; +pub type shmatt_t = ::c_ulong; +pub type mqd_t = ::c_int; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type nfds_t = ::c_ulong; +pub type nl_item = ::c_int; +pub type idtype_t = ::c_uint; +pub type loff_t = i32; + +pub type clock_t = c_long; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type ino_t = u32; +pub type off_t = i32; +pub type blkcnt_t = i32; + +pub type blksize_t = c_long; +pub type fsblkcnt_t = u32; +pub type fsfilcnt_t = u32; +pub type rlim_t = ::c_ulonglong; +pub type c_long = i32; +pub type c_ulong = u32; +pub type nlink_t = u32; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos64_t {} // TODO: fill this out with a struct +impl ::Copy for fpos64_t {} +impl ::Clone for fpos64_t { + fn clone(&self) -> fpos64_t { *self } +} + +s! { + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct spwd { + pub sp_namp: *mut ::c_char, + pub sp_pwdp: *mut ::c_char, + pub sp_lstchg: ::c_long, + pub sp_min: ::c_long, + pub sp_max: ::c_long, + pub sp_warn: ::c_long, + pub sp_inact: ::c_long, + pub sp_expire: ::c_long, + pub sp_flag: ::c_ulong, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint64_t, + pub dqb_bsoftlimit: ::uint64_t, + pub dqb_curspace: ::uint64_t, + pub dqb_ihardlimit: ::uint64_t, + pub dqb_isoftlimit: ::uint64_t, + pub dqb_curinodes: ::uint64_t, + pub dqb_btime: ::uint64_t, + pub dqb_itime: ::uint64_t, + pub dqb_valid: ::uint32_t, + } + + pub struct signalfd_siginfo { + pub ssi_signo: ::uint32_t, + pub ssi_errno: ::int32_t, + pub ssi_code: ::int32_t, + pub ssi_pid: ::uint32_t, + pub ssi_uid: ::uint32_t, + pub ssi_fd: ::int32_t, + pub ssi_tid: ::uint32_t, + pub ssi_band: ::uint32_t, + pub ssi_overrun: ::uint32_t, + pub ssi_trapno: ::uint32_t, + pub ssi_status: ::int32_t, + pub ssi_int: ::int32_t, + pub ssi_ptr: ::uint64_t, + pub ssi_utime: ::uint64_t, + pub ssi_stime: ::uint64_t, + pub ssi_addr: ::uint64_t, + pub ssi_addr_lsb: ::uint16_t, + _pad2: ::uint16_t, + pub ssi_syscall: ::int32_t, + pub ssi_call_addr: ::uint64_t, + pub ssi_arch: ::uint32_t, + _pad: [::uint8_t; 28], + } + + pub struct fsid_t { + __val: [::c_int; 2], + } + + pub struct mq_attr { + pub mq_flags: ::c_long, + pub mq_maxmsg: ::c_long, + pub mq_msgsize: ::c_long, + pub mq_curmsgs: ::c_long, + pad: [::c_long; 4] + } + + pub struct cpu_set_t { + bits: [u32; 32], + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: ::c_int, + pub msgmap: ::c_int, + pub msgmax: ::c_int, + pub msgmnb: ::c_int, + pub msgmni: ::c_int, + pub msgssz: ::c_int, + pub msgtql: ::c_int, + pub msgseg: ::c_ushort, + } + + pub struct sembuf { + pub sem_num: ::c_ushort, + pub sem_op: ::c_short, + pub sem_flg: ::c_short, + } + + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __td: *mut ::c_void, + __lock: [::c_int; 2], + __err: ::c_int, + __ret: ::ssize_t, + pub aio_offset: off_t, + __next: *mut ::c_void, + __prev: *mut ::c_void, + __dummy4: [::c_char; 24], + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_int, + pub sa_restorer: ::Option, + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub __c_ispeed: ::speed_t, + pub __c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct pthread_attr_t { + __size: [u32; 11] + } + + pub struct sigset_t { + __val: [::c_ulong; 32], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::socklen_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct sem_t { + __val: [::c_int; 4], + } + pub struct stat { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + __unused1: ::c_int, + pub shm_dtime: ::time_t, + __unused2: ::c_int, + pub shm_ctime: ::time_t, + __unused3: ::c_int, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + __unused1: ::c_int, + pub msg_rtime: ::time_t, + __unused2: ::c_int, + pub msg_ctime: ::time_t, + __unused3: ::c_int, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u32, + pub f_bfree: u32, + pub f_bavail: u32, + pub f_files: u32, + pub f_ffree: u32, + pub f_favail: u32, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct arpd_request { + pub req: ::c_ushort, + pub ip: u32, + pub dev: ::c_ulong, + pub stamp: ::c_ulong, + pub updated: ::c_ulong, + pub ha: [::c_uchar; ::MAX_ADDR_LEN], + } +} + +s_no_extra_traits! { + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct dirent64 { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct sysinfo { + pub uptime: ::c_ulong, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub __reserved: [::c_char; 256], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent {} + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for dirent64 { + fn eq(&self, other: &dirent64) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for dirent64 {} + impl ::fmt::Debug for dirent64 { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent64") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + impl ::hash::Hash for dirent64 { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for sysinfo { + fn eq(&self, other: &sysinfo) -> bool { + self.uptime == other.uptime + && self.loads == other.loads + && self.totalram == other.totalram + && self.freeram == other.freeram + && self.sharedram == other.sharedram + && self.bufferram == other.bufferram + && self.totalswap == other.totalswap + && self.freeswap == other.freeswap + && self.procs == other.procs + && self.pad == other.pad + && self.totalhigh == other.totalhigh + && self.freehigh == other.freehigh + && self.mem_unit == other.mem_unit + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sysinfo {} + impl ::fmt::Debug for sysinfo { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sysinfo") + .field("uptime", &self.uptime) + .field("loads", &self.loads) + .field("totalram", &self.totalram) + .field("freeram", &self.freeram) + .field("sharedram", &self.sharedram) + .field("bufferram", &self.bufferram) + .field("totalswap", &self.totalswap) + .field("freeswap", &self.freeswap) + .field("procs", &self.procs) + .field("pad", &self.pad) + .field("totalhigh", &self.totalhigh) + .field("freehigh", &self.freehigh) + .field("mem_unit", &self.mem_unit) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + impl ::hash::Hash for sysinfo { + fn hash(&self, state: &mut H) { + self.uptime.hash(state); + self.loads.hash(state); + self.totalram.hash(state); + self.freeram.hash(state); + self.sharedram.hash(state); + self.bufferram.hash(state); + self.totalswap.hash(state); + self.freeswap.hash(state); + self.procs.hash(state); + self.pad.hash(state); + self.totalhigh.hash(state); + self.freehigh.hash(state); + self.mem_unit.hash(state); + self.__reserved.hash(state); + } + } + } +} + +pub const ABDAY_1: ::nl_item = 0x20000; +pub const ABDAY_2: ::nl_item = 0x20001; +pub const ABDAY_3: ::nl_item = 0x20002; +pub const ABDAY_4: ::nl_item = 0x20003; +pub const ABDAY_5: ::nl_item = 0x20004; +pub const ABDAY_6: ::nl_item = 0x20005; +pub const ABDAY_7: ::nl_item = 0x20006; + +pub const DAY_1: ::nl_item = 0x20007; +pub const DAY_2: ::nl_item = 0x20008; +pub const DAY_3: ::nl_item = 0x20009; +pub const DAY_4: ::nl_item = 0x2000A; +pub const DAY_5: ::nl_item = 0x2000B; +pub const DAY_6: ::nl_item = 0x2000C; +pub const DAY_7: ::nl_item = 0x2000D; + +pub const ABMON_1: ::nl_item = 0x2000E; +pub const ABMON_2: ::nl_item = 0x2000F; +pub const ABMON_3: ::nl_item = 0x20010; +pub const ABMON_4: ::nl_item = 0x20011; +pub const ABMON_5: ::nl_item = 0x20012; +pub const ABMON_6: ::nl_item = 0x20013; +pub const ABMON_7: ::nl_item = 0x20014; +pub const ABMON_8: ::nl_item = 0x20015; +pub const ABMON_9: ::nl_item = 0x20016; +pub const ABMON_10: ::nl_item = 0x20017; +pub const ABMON_11: ::nl_item = 0x20018; +pub const ABMON_12: ::nl_item = 0x20019; + +pub const MON_1: ::nl_item = 0x2001A; +pub const MON_2: ::nl_item = 0x2001B; +pub const MON_3: ::nl_item = 0x2001C; +pub const MON_4: ::nl_item = 0x2001D; +pub const MON_5: ::nl_item = 0x2001E; +pub const MON_6: ::nl_item = 0x2001F; +pub const MON_7: ::nl_item = 0x20020; +pub const MON_8: ::nl_item = 0x20021; +pub const MON_9: ::nl_item = 0x20022; +pub const MON_10: ::nl_item = 0x20023; +pub const MON_11: ::nl_item = 0x20024; +pub const MON_12: ::nl_item = 0x20025; + +pub const AM_STR: ::nl_item = 0x20026; +pub const PM_STR: ::nl_item = 0x20027; + +pub const D_T_FMT: ::nl_item = 0x20028; +pub const D_FMT: ::nl_item = 0x20029; +pub const T_FMT: ::nl_item = 0x2002A; +pub const T_FMT_AMPM: ::nl_item = 0x2002B; + +pub const ERA: ::nl_item = 0x2002C; +pub const ERA_D_FMT: ::nl_item = 0x2002E; +pub const ALT_DIGITS: ::nl_item = 0x2002F; +pub const ERA_D_T_FMT: ::nl_item = 0x20030; +pub const ERA_T_FMT: ::nl_item = 0x20031; + +pub const CODESET: ::nl_item = 14; + +pub const CRNCYSTR: ::nl_item = 0x4000F; + +pub const RUSAGE_THREAD: ::c_int = 1; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const RADIXCHAR: ::nl_item = 0x10000; +pub const THOUSEP: ::nl_item = 0x10001; + +pub const YESEXPR: ::nl_item = 0x50000; +pub const NOEXPR: ::nl_item = 0x50001; +pub const YESSTR: ::nl_item = 0x50002; +pub const NOSTR: ::nl_item = 0x50003; + +pub const FILENAME_MAX: ::c_uint = 4096; +pub const L_tmpnam: ::c_uint = 20; +pub const _PC_LINK_MAX: ::c_int = 0; +pub const _PC_MAX_CANON: ::c_int = 1; +pub const _PC_MAX_INPUT: ::c_int = 2; +pub const _PC_NAME_MAX: ::c_int = 3; +pub const _PC_PATH_MAX: ::c_int = 4; +pub const _PC_PIPE_BUF: ::c_int = 5; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 6; +pub const _PC_NO_TRUNC: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; +pub const _PC_SYNC_IO: ::c_int = 9; +pub const _PC_ASYNC_IO: ::c_int = 10; +pub const _PC_PRIO_IO: ::c_int = 11; +pub const _PC_SOCK_MAXBUF: ::c_int = 12; +pub const _PC_FILESIZEBITS: ::c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 16; +pub const _PC_REC_XFER_ALIGN: ::c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 18; +pub const _PC_SYMLINK_MAX: ::c_int = 19; +pub const _PC_2_SYMLINKS: ::c_int = 20; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_CHILD_MAX: ::c_int = 1; +pub const _SC_CLK_TCK: ::c_int = 2; +pub const _SC_NGROUPS_MAX: ::c_int = 3; +pub const _SC_OPEN_MAX: ::c_int = 4; +pub const _SC_STREAM_MAX: ::c_int = 5; +pub const _SC_TZNAME_MAX: ::c_int = 6; +pub const _SC_JOB_CONTROL: ::c_int = 7; +pub const _SC_SAVED_IDS: ::c_int = 8; +pub const _SC_REALTIME_SIGNALS: ::c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10; +pub const _SC_TIMERS: ::c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12; +pub const _SC_PRIORITIZED_IO: ::c_int = 13; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 14; +pub const _SC_FSYNC: ::c_int = 15; +pub const _SC_MAPPED_FILES: ::c_int = 16; +pub const _SC_MEMLOCK: ::c_int = 17; +pub const _SC_MEMLOCK_RANGE: ::c_int = 18; +pub const _SC_MEMORY_PROTECTION: ::c_int = 19; +pub const _SC_MESSAGE_PASSING: ::c_int = 20; +pub const _SC_SEMAPHORES: ::c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 23; +pub const _SC_AIO_MAX: ::c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25; +pub const _SC_DELAYTIMER_MAX: ::c_int = 26; +pub const _SC_MQ_OPEN_MAX: ::c_int = 27; +pub const _SC_MQ_PRIO_MAX: ::c_int = 28; +pub const _SC_VERSION: ::c_int = 29; +pub const _SC_PAGESIZE: ::c_int = 30; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: ::c_int = 31; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 32; +pub const _SC_SEM_VALUE_MAX: ::c_int = 33; +pub const _SC_SIGQUEUE_MAX: ::c_int = 34; +pub const _SC_TIMER_MAX: ::c_int = 35; +pub const _SC_BC_BASE_MAX: ::c_int = 36; +pub const _SC_BC_DIM_MAX: ::c_int = 37; +pub const _SC_BC_SCALE_MAX: ::c_int = 38; +pub const _SC_BC_STRING_MAX: ::c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40; +pub const _SC_EXPR_NEST_MAX: ::c_int = 42; +pub const _SC_LINE_MAX: ::c_int = 43; +pub const _SC_RE_DUP_MAX: ::c_int = 44; +pub const _SC_2_VERSION: ::c_int = 46; +pub const _SC_2_C_BIND: ::c_int = 47; +pub const _SC_2_C_DEV: ::c_int = 48; +pub const _SC_2_FORT_DEV: ::c_int = 49; +pub const _SC_2_FORT_RUN: ::c_int = 50; +pub const _SC_2_SW_DEV: ::c_int = 51; +pub const _SC_2_LOCALEDEF: ::c_int = 52; +pub const _SC_UIO_MAXIOV: ::c_int = 60; +pub const _SC_IOV_MAX: ::c_int = 60; +pub const _SC_THREADS: ::c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 71; +pub const _SC_TTY_NAME_MAX: ::c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 74; +pub const _SC_THREAD_STACK_MIN: ::c_int = 75; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 82; +pub const _SC_NPROCESSORS_CONF: ::c_int = 83; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 84; +pub const _SC_PHYS_PAGES: ::c_int = 85; +pub const _SC_AVPHYS_PAGES: ::c_int = 86; +pub const _SC_ATEXIT_MAX: ::c_int = 87; +pub const _SC_PASS_MAX: ::c_int = 88; +pub const _SC_XOPEN_VERSION: ::c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90; +pub const _SC_XOPEN_UNIX: ::c_int = 91; +pub const _SC_XOPEN_CRYPT: ::c_int = 92; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 93; +pub const _SC_XOPEN_SHM: ::c_int = 94; +pub const _SC_2_CHAR_TERM: ::c_int = 95; +pub const _SC_2_UPE: ::c_int = 97; +pub const _SC_XOPEN_XPG2: ::c_int = 98; +pub const _SC_XOPEN_XPG3: ::c_int = 99; +pub const _SC_XOPEN_XPG4: ::c_int = 100; +pub const _SC_NZERO: ::c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128; +pub const _SC_XOPEN_LEGACY: ::c_int = 129; +pub const _SC_XOPEN_REALTIME: ::c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131; +pub const _SC_ADVISORY_INFO: ::c_int = 132; +pub const _SC_BARRIERS: ::c_int = 133; +pub const _SC_CLOCK_SELECTION: ::c_int = 137; +pub const _SC_CPUTIME: ::c_int = 138; +pub const _SC_THREAD_CPUTIME: ::c_int = 139; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 149; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 153; +pub const _SC_SPIN_LOCKS: ::c_int = 154; +pub const _SC_REGEXP: ::c_int = 155; +pub const _SC_SHELL: ::c_int = 157; +pub const _SC_SPAWN: ::c_int = 159; +pub const _SC_SPORADIC_SERVER: ::c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 161; +pub const _SC_TIMEOUTS: ::c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 165; +pub const _SC_2_PBS: ::c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 169; +pub const _SC_2_PBS_LOCATE: ::c_int = 170; +pub const _SC_2_PBS_MESSAGE: ::c_int = 171; +pub const _SC_2_PBS_TRACK: ::c_int = 172; +pub const _SC_SYMLOOP_MAX: ::c_int = 173; +pub const _SC_STREAMS: ::c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 175; +pub const _SC_V6_ILP32_OFF32: ::c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 177; +pub const _SC_V6_LP64_OFF64: ::c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 179; +pub const _SC_HOST_NAME_MAX: ::c_int = 180; +pub const _SC_TRACE: ::c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 182; +pub const _SC_TRACE_INHERIT: ::c_int = 183; +pub const _SC_TRACE_LOG: ::c_int = 184; +pub const _SC_IPV6: ::c_int = 235; +pub const _SC_RAW_SOCKETS: ::c_int = 236; +pub const _SC_V7_ILP32_OFF32: ::c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 238; +pub const _SC_V7_LP64_OFF64: ::c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 240; +pub const _SC_SS_REPL_MAX: ::c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 242; +pub const _SC_TRACE_NAME_MAX: ::c_int = 243; +pub const _SC_TRACE_SYS_MAX: ::c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 245; +pub const _SC_XOPEN_STREAMS: ::c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 248; + +pub const RLIM_SAVED_MAX: ::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: ::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: ::c_int = 1 << 0; +pub const GLOB_MARK: ::c_int = 1 << 1; +pub const GLOB_NOSORT: ::c_int = 1 << 2; +pub const GLOB_DOOFFS: ::c_int = 1 << 3; +pub const GLOB_NOCHECK: ::c_int = 1 << 4; +pub const GLOB_APPEND: ::c_int = 1 << 5; +pub const GLOB_NOESCAPE: ::c_int = 1 << 6; + +pub const GLOB_NOSPACE: ::c_int = 1; +pub const GLOB_ABORTED: ::c_int = 2; +pub const GLOB_NOMATCH: ::c_int = 3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; + +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; + +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; +pub const ST_NODEV: ::c_ulong = 4; +pub const ST_NOEXEC: ::c_ulong = 8; +pub const ST_SYNCHRONOUS: ::c_ulong = 16; +pub const ST_MANDLOCK: ::c_ulong = 64; +pub const ST_WRITE: ::c_ulong = 128; +pub const ST_APPEND: ::c_ulong = 256; +pub const ST_IMMUTABLE: ::c_ulong = 512; +pub const ST_NOATIME: ::c_ulong = 1024; +pub const ST_NODIRATIME: ::c_ulong = 2048; + +pub const RTLD_NEXT: *mut ::c_void = -1i64 as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_NOW: ::c_int = 0x2; + +pub const TCP_MD5SIG: ::c_int = 14; + +align_const! { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], + }; +} + +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_PROCESS_PRIVATE: ::c_int = 0; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const SCHED_OTHER: ::c_int = 0; +pub const SCHED_FIFO: ::c_int = 1; +pub const SCHED_RR: ::c_int = 2; +pub const SCHED_BATCH: ::c_int = 3; +pub const SCHED_IDLE: ::c_int = 5; + +pub const AF_IB: ::c_int = 27; +pub const AF_MPLS: ::c_int = 28; +pub const AF_NFC: ::c_int = 39; +pub const AF_VSOCK: ::c_int = 40; +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +pub const PF_IB: ::c_int = AF_IB; +pub const PF_MPLS: ::c_int = AF_MPLS; +pub const PF_NFC: ::c_int = AF_NFC; +pub const PF_VSOCK: ::c_int = AF_VSOCK; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +// System V IPC +pub const IPC_PRIVATE: ::key_t = 0; + +pub const IPC_CREAT: ::c_int = 0o1000; +pub const IPC_EXCL: ::c_int = 0o2000; +pub const IPC_NOWAIT: ::c_int = 0o4000; + +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; +pub const IPC_INFO: ::c_int = 3; +pub const MSG_STAT: ::c_int = 11; +pub const MSG_INFO: ::c_int = 12; + +pub const MSG_NOERROR: ::c_int = 0o10000; +pub const MSG_EXCEPT: ::c_int = 0o20000; +pub const MSG_COPY: ::c_int = 0o40000; + +pub const SHM_R: ::c_int = 0o400; +pub const SHM_W: ::c_int = 0o200; + +pub const SHM_RDONLY: ::c_int = 0o10000; +pub const SHM_RND: ::c_int = 0o20000; +pub const SHM_REMAP: ::c_int = 0o40000; +pub const SHM_EXEC: ::c_int = 0o100000; + +pub const SHM_LOCK: ::c_int = 11; +pub const SHM_UNLOCK: ::c_int = 12; + +pub const SHM_HUGETLB: ::c_int = 0o4000; +pub const SHM_NORESERVE: ::c_int = 0o10000; + +pub const EPOLLRDHUP: ::c_int = 0x2000; +pub const EPOLLEXCLUSIVE: ::c_int = 0x10000000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; + +pub const QFMT_VFS_OLD: ::c_int = 1; +pub const QFMT_VFS_V0: ::c_int = 2; + +pub const EFD_SEMAPHORE: ::c_int = 0x1; + +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const SEM_FAILED: *mut ::sem_t = 0 as *mut sem_t; + +pub const RB_AUTOBOOT: ::c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: ::c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: ::c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: ::c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: ::c_int = 0x4321fedcu32 as i32; +pub const RB_SW_SUSPEND: ::c_int = 0xd000fce2u32 as i32; +pub const RB_KEXEC: ::c_int = 0x45584543u32 as i32; + +pub const AI_PASSIVE: ::c_int = 0x0001; +pub const AI_CANONNAME: ::c_int = 0x0002; +pub const AI_NUMERICHOST: ::c_int = 0x0004; +pub const AI_V4MAPPED: ::c_int = 0x0008; +pub const AI_ALL: ::c_int = 0x0010; +pub const AI_ADDRCONFIG: ::c_int = 0x0020; + +pub const AI_NUMERICSERV: ::c_int = 0x0400; + +pub const EAI_BADFLAGS: ::c_int = -1; +pub const EAI_NONAME: ::c_int = -2; +pub const EAI_AGAIN: ::c_int = -3; +pub const EAI_FAIL: ::c_int = -4; +pub const EAI_FAMILY: ::c_int = -6; +pub const EAI_SOCKTYPE: ::c_int = -7; +pub const EAI_SERVICE: ::c_int = -8; +pub const EAI_MEMORY: ::c_int = -10; +pub const EAI_OVERFLOW: ::c_int = -12; + +pub const NI_NUMERICHOST: ::c_int = 1; +pub const NI_NUMERICSERV: ::c_int = 2; +pub const NI_NOFQDN: ::c_int = 4; +pub const NI_NAMEREQD: ::c_int = 8; +pub const NI_DGRAM: ::c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: ::c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: ::c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: ::c_uint = 4; + +pub const EAI_SYSTEM: ::c_int = -11; + +pub const AIO_CANCELED: ::c_int = 0; +pub const AIO_NOTCANCELED: ::c_int = 1; +pub const AIO_ALLDONE: ::c_int = 2; +pub const LIO_READ: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 1; +pub const LIO_NOP: ::c_int = 2; +pub const LIO_WAIT: ::c_int = 0; +pub const LIO_NOWAIT: ::c_int = 1; + +pub const MREMAP_MAYMOVE: ::c_int = 1; +pub const MREMAP_FIXED: ::c_int = 2; + +pub const PR_SET_PDEATHSIG: ::c_int = 1; +pub const PR_GET_PDEATHSIG: ::c_int = 2; + +pub const PR_GET_DUMPABLE: ::c_int = 3; +pub const PR_SET_DUMPABLE: ::c_int = 4; + +pub const PR_GET_UNALIGN: ::c_int = 5; +pub const PR_SET_UNALIGN: ::c_int = 6; +pub const PR_UNALIGN_NOPRINT: ::c_int = 1; +pub const PR_UNALIGN_SIGBUS: ::c_int = 2; + +pub const PR_GET_KEEPCAPS: ::c_int = 7; +pub const PR_SET_KEEPCAPS: ::c_int = 8; + +pub const PR_GET_FPEMU: ::c_int = 9; +pub const PR_SET_FPEMU: ::c_int = 10; +pub const PR_FPEMU_NOPRINT: ::c_int = 1; +pub const PR_FPEMU_SIGFPE: ::c_int = 2; + +pub const PR_GET_FPEXC: ::c_int = 11; +pub const PR_SET_FPEXC: ::c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: ::c_int = 0x80; +pub const PR_FP_EXC_DIV: ::c_int = 0x010000; +pub const PR_FP_EXC_OVF: ::c_int = 0x020000; +pub const PR_FP_EXC_UND: ::c_int = 0x040000; +pub const PR_FP_EXC_RES: ::c_int = 0x080000; +pub const PR_FP_EXC_INV: ::c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: ::c_int = 0; +pub const PR_FP_EXC_NONRECOV: ::c_int = 1; +pub const PR_FP_EXC_ASYNC: ::c_int = 2; +pub const PR_FP_EXC_PRECISE: ::c_int = 3; + +pub const PR_GET_TIMING: ::c_int = 13; +pub const PR_SET_TIMING: ::c_int = 14; +pub const PR_TIMING_STATISTICAL: ::c_int = 0; +pub const PR_TIMING_TIMESTAMP: ::c_int = 1; + +pub const PR_SET_NAME: ::c_int = 15; +pub const PR_GET_NAME: ::c_int = 16; + +pub const PR_GET_ENDIAN: ::c_int = 19; +pub const PR_SET_ENDIAN: ::c_int = 20; +pub const PR_ENDIAN_BIG: ::c_int = 0; +pub const PR_ENDIAN_LITTLE: ::c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: ::c_int = 2; + +pub const PR_GET_SECCOMP: ::c_int = 21; +pub const PR_SET_SECCOMP: ::c_int = 22; + +pub const PR_CAPBSET_READ: ::c_int = 23; +pub const PR_CAPBSET_DROP: ::c_int = 24; + +pub const PR_GET_TSC: ::c_int = 25; +pub const PR_SET_TSC: ::c_int = 26; +pub const PR_TSC_ENABLE: ::c_int = 1; +pub const PR_TSC_SIGSEGV: ::c_int = 2; + +pub const PR_GET_SECUREBITS: ::c_int = 27; +pub const PR_SET_SECUREBITS: ::c_int = 28; + +pub const PR_SET_TIMERSLACK: ::c_int = 29; +pub const PR_GET_TIMERSLACK: ::c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: ::c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: ::c_int = 32; + +pub const PR_MCE_KILL: ::c_int = 33; +pub const PR_MCE_KILL_CLEAR: ::c_int = 0; +pub const PR_MCE_KILL_SET: ::c_int = 1; + +pub const PR_MCE_KILL_LATE: ::c_int = 0; +pub const PR_MCE_KILL_EARLY: ::c_int = 1; +pub const PR_MCE_KILL_DEFAULT: ::c_int = 2; + +pub const PR_MCE_KILL_GET: ::c_int = 34; + +pub const PR_SET_MM: ::c_int = 35; +pub const PR_SET_MM_START_CODE: ::c_int = 1; +pub const PR_SET_MM_END_CODE: ::c_int = 2; +pub const PR_SET_MM_START_DATA: ::c_int = 3; +pub const PR_SET_MM_END_DATA: ::c_int = 4; +pub const PR_SET_MM_START_STACK: ::c_int = 5; +pub const PR_SET_MM_START_BRK: ::c_int = 6; +pub const PR_SET_MM_BRK: ::c_int = 7; +pub const PR_SET_MM_ARG_START: ::c_int = 8; +pub const PR_SET_MM_ARG_END: ::c_int = 9; +pub const PR_SET_MM_ENV_START: ::c_int = 10; +pub const PR_SET_MM_ENV_END: ::c_int = 11; +pub const PR_SET_MM_AUXV: ::c_int = 12; +pub const PR_SET_MM_EXE_FILE: ::c_int = 13; +pub const PR_SET_MM_MAP: ::c_int = 14; +pub const PR_SET_MM_MAP_SIZE: ::c_int = 15; + +pub const PR_SET_PTRACER: ::c_int = 0x59616d61; + +pub const PR_SET_CHILD_SUBREAPER: ::c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: ::c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: ::c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: ::c_int = 39; + +pub const PR_GET_TID_ADDRESS: ::c_int = 40; + +pub const PR_SET_THP_DISABLE: ::c_int = 41; +pub const PR_GET_THP_DISABLE: ::c_int = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT: ::c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: ::c_int = 44; + +pub const PR_SET_FP_MODE: ::c_int = 45; +pub const PR_GET_FP_MODE: ::c_int = 46; +pub const PR_FP_MODE_FR: ::c_int = 1 << 0; +pub const PR_FP_MODE_FRE: ::c_int = 1 << 1; + +pub const PR_CAP_AMBIENT: ::c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: ::c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: ::c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: ::c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: ::c_int = 4; + +pub const ITIMER_REAL: ::c_int = 0; +pub const ITIMER_VIRTUAL: ::c_int = 1; +pub const ITIMER_PROF: ::c_int = 2; + +pub const XATTR_CREATE: ::c_int = 0x1; +pub const XATTR_REPLACE: ::c_int = 0x2; + +pub const _POSIX_VDISABLE: ::cc_t = 0; + +pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02; +pub const FALLOC_FL_COLLAPSE_RANGE: ::c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: ::c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: ::c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: ::c_int = 0x40; + +// On Linux, libc doesn't define this constant, libattr does instead. +// We still define it for Linux as it's defined by libc on other platforms, +// and it's mentioned in the man pages for getxattr and setxattr. +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const BUFSIZ: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 10000; +pub const FOPEN_MAX: ::c_uint = 1000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_EXEC: ::c_int = 0o10000000; +pub const O_SEARCH: ::c_int = 0o10000000; +pub const O_ACCMODE: ::c_int = 0o10000003; +pub const O_NDELAY: ::c_int = O_NONBLOCK; +pub const NI_MAXHOST: ::socklen_t = 255; +pub const PTHREAD_STACK_MIN: ::size_t = 2048; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; + +pub const POSIX_MADV_DONTNEED: ::c_int = 0; + +pub const RLIM_INFINITY: ::rlim_t = !0; +pub const RLIMIT_RTTIME: ::c_int = 15; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const MAP_ANONYMOUS: ::c_int = MAP_ANON; + +pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16; +pub const TCP_THIN_DUPACK: ::c_int = 17; +pub const TCP_USER_TIMEOUT: ::c_int = 18; +pub const TCP_REPAIR: ::c_int = 19; +pub const TCP_REPAIR_QUEUE: ::c_int = 20; +pub const TCP_QUEUE_SEQ: ::c_int = 21; +pub const TCP_REPAIR_OPTIONS: ::c_int = 22; +pub const TCP_FASTOPEN: ::c_int = 23; +pub const TCP_TIMESTAMP: ::c_int = 24; + +pub const SIGUNUSED: ::c_int = ::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const CPU_SETSIZE: ::c_int = 128; + +pub const QFMT_VFS_V1: ::c_int = 4; + +pub const PTRACE_TRACEME: ::c_int = 0; +pub const PTRACE_PEEKTEXT: ::c_int = 1; +pub const PTRACE_PEEKDATA: ::c_int = 2; +pub const PTRACE_PEEKUSER: ::c_int = 3; +pub const PTRACE_POKETEXT: ::c_int = 4; +pub const PTRACE_POKEDATA: ::c_int = 5; +pub const PTRACE_POKEUSER: ::c_int = 6; +pub const PTRACE_CONT: ::c_int = 7; +pub const PTRACE_KILL: ::c_int = 8; +pub const PTRACE_SINGLESTEP: ::c_int = 9; +pub const PTRACE_ATTACH: ::c_int = 16; +pub const PTRACE_DETACH: ::c_int = 17; +pub const PTRACE_SYSCALL: ::c_int = 24; +pub const PTRACE_SETOPTIONS: ::c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_int = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_int = 0x4203; +pub const PTRACE_GETREGSET: ::c_int = 0x4204; +pub const PTRACE_SETREGSET: ::c_int = 0x4205; +pub const PTRACE_SEIZE: ::c_int = 0x4206; +pub const PTRACE_INTERRUPT: ::c_int = 0x4207; +pub const PTRACE_LISTEN: ::c_int = 0x4208; +pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209; + +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const PTRACE_GETFPREGS: ::c_uint = 14; +pub const PTRACE_SETFPREGS: ::c_uint = 15; +pub const PTRACE_GETFPXREGS: ::c_uint = 18; +pub const PTRACE_SETFPXREGS: ::c_uint = 19; +pub const PTRACE_GETREGS: ::c_uint = 12; +pub const PTRACE_SETREGS: ::c_uint = 13; + +pub const EFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const SFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; + +pub const TIOCINQ: ::c_int = ::FIONREAD; + +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_NOLOAD: ::c_int = 0x4; + +// TODO(#247) Temporarily musl-specific (available since musl 0.9.12 / Linux +// kernel 3.10). See also notbsd/mod.rs +pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +pub const CLOCK_TAI: ::clockid_t = 11; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_MARK: ::c_int = 36; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 28; + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const O_ASYNC: ::c_int = 0x2000; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_LINGER: ::c_int = 13; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_ACCEPTCONN: ::c_int = 30; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const EXTPROC: ::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const F_GETLK: ::c_int = 12; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 13; +pub const F_SETLKW: ::c_int = 14; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; + +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const SYS_gettid: ::c_long = 224; // Valid for arm (32-bit) and x86 (32-bit) + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; +pub const O_TMPFILE: ::c_int = 0x400000; + +pub const MAX_ADDR_LEN: usize = 7; +pub const ARPD_UPDATE: ::c_ushort = 0x01; +pub const ARPD_LOOKUP: ::c_ushort = 0x02; +pub const ARPD_FLUSH: ::c_ushort = 0x03; +pub const ATF_MAGIC: ::c_int = 0x80; + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, + cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < ::mem::size_of::() { + return 0 as *mut cmsghdr; + }; + let next = (cmsg as usize + + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) + as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max { + 0 as *mut cmsghdr + } else { + next as *mut cmsghdr + } + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * ::mem::size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn major(dev: ::dev_t) -> ::c_uint { + // see + // https://github.com/kripken/emscripten/blob/ + // master/system/include/libc/sys/sysmacros.h + let mut major = 0; + major |= (dev & 0x00000fff) >> 8; + major |= (dev & 0xfffff000) >> 31 >> 1; + major as ::c_uint + } + + pub fn minor(dev: ::dev_t) -> ::c_uint { + // see + // https://github.com/kripken/emscripten/blob/ + // master/system/include/libc/sys/sysmacros.h + let mut minor = 0; + minor |= (dev & 0x000000ff) >> 0; + minor |= (dev & 0xffffff00) >> 12; + minor as ::c_uint + } + + pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 31 << 1; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } +} + +extern { + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + + pub fn shm_open(name: *const c_char, oflag: ::c_int, + mode: mode_t) -> ::c_int; + + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn __errno_location() -> *mut ::c_int; + + pub fn fopen64(filename: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn freopen64(filename: *const c_char, mode: *const c_char, + file: *mut ::FILE) -> *mut ::FILE; + pub fn tmpfile64() -> *mut ::FILE; + pub fn fgetpos64(stream: *mut ::FILE, ptr: *mut fpos64_t) -> ::c_int; + pub fn fsetpos64(stream: *mut ::FILE, ptr: *const fpos64_t) -> ::c_int; + pub fn fseeko64(stream: *mut ::FILE, + offset: ::off64_t, + whence: ::c_int) -> ::c_int; + pub fn ftello64(stream: *mut ::FILE) -> ::off64_t; + pub fn posix_fallocate(fd: ::c_int, offset: ::off_t, + len: ::off_t) -> ::c_int; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn dup3(oldfd: ::c_int, newfd: ::c_int, flags: ::c_int) -> ::c_int; + pub fn mkostemp(template: *mut ::c_char, flags: ::c_int) -> ::c_int; + pub fn mkostemps(template: *mut ::c_char, + suffixlen: ::c_int, + flags: ::c_int) -> ::c_int; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn getloadavg(loadavg: *mut ::c_double, nelem: ::c_int) -> ::c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + + pub fn mremap(addr: *mut ::c_void, + len: ::size_t, + new_len: ::size_t, + flags: ::c_int, + ...) -> *mut ::c_void; + + pub fn glob(pattern: *const c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + pub fn getdomainname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn sendmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int) -> ::c_int; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int, timeout: *mut ::timespec) -> ::c_int; + pub fn sync(); + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; + pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} +expand_align!(); diff --git a/libc/src/unix/notbsd/emscripten/no_align.rs b/libc/src/unix/notbsd/emscripten/no_align.rs new file mode 100644 index 000000000..ece4dff17 --- /dev/null +++ b/libc/src/unix/notbsd/emscripten/no_align.rs @@ -0,0 +1,63 @@ +macro_rules! expand_align { + () => { + s! { + pub struct pthread_mutex_t { + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_rwlock_t { + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + pub struct pthread_mutexattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_rwlockattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + pub struct pthread_condattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + pub struct pthread_cond_t { + __align: [*const ::c_void; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + } + + cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.size + .iter() + .zip(other.size.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for pthread_cond_t {} + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + } + } + } +} diff --git a/libc/src/unix/notbsd/linux/align.rs b/libc/src/unix/notbsd/linux/align.rs new file mode 100644 index 000000000..0ff4649b8 --- /dev/null +++ b/libc/src/unix/notbsd/linux/align.rs @@ -0,0 +1,98 @@ +macro_rules! expand_align { + () => { + s! { + #[cfg_attr(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "aarch64"), + repr(align(4)))] + #[cfg_attr(not(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "aarch64")), + repr(align(8)))] + pub struct pthread_mutexattr_t { + #[doc(hidden)] + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[cfg_attr(any(target_env = "musl", target_pointer_width = "32"), + repr(align(4)))] + #[cfg_attr(all(not(target_env = "musl"), + target_pointer_width = "64"), + repr(align(8)))] + pub struct pthread_rwlockattr_t { + #[doc(hidden)] + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + #[doc(hidden)] + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + #[cfg_attr(all(target_env = "musl", + target_pointer_width = "32"), + repr(align(4)))] + #[cfg_attr(all(target_env = "musl", + target_pointer_width = "64"), + repr(align(8)))] + #[cfg_attr(all(not(target_env = "musl"), + target_arch = "x86"), + repr(align(4)))] + #[cfg_attr(all(not(target_env = "musl"), + not(target_arch = "x86")), + repr(align(8)))] + pub struct pthread_cond_t { + #[doc(hidden)] + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "x86_64", + target_arch = "x86")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "x86_64", + target_arch = "x86"))), + repr(align(8)))] + pub struct pthread_mutex_t { + #[doc(hidden)] + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "x86_64", + target_arch = "x86")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "x86_64", + target_arch = "x86"))), + repr(align(8)))] + pub struct pthread_rwlock_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + } + } +} diff --git a/libc/src/unix/notbsd/linux/mips/align.rs b/libc/src/unix/notbsd/linux/mips/align.rs new file mode 100644 index 000000000..4a0e07460 --- /dev/null +++ b/libc/src/unix/notbsd/linux/mips/align.rs @@ -0,0 +1,13 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/notbsd/linux/mips/mips32.rs b/libc/src/unix/notbsd/linux/mips/mips32.rs new file mode 100644 index 000000000..d9d558913 --- /dev/null +++ b/libc/src/unix/notbsd/linux/mips/mips32.rs @@ -0,0 +1,695 @@ +use pthread_mutex_t; + +pub type c_char = i8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type clock_t = i32; +pub type time_t = i32; +pub type suseconds_t = i32; +pub type wchar_t = i32; +pub type off_t = i32; +pub type ino_t = u32; +pub type blkcnt_t = i32; +pub type blksize_t = i32; +pub type nlink_t = u32; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __next_prio: *mut aiocb, + __abs_prio: ::c_int, + __policy: ::c_int, + __error_code: ::c_int, + __return_value: ::ssize_t, + pub aio_offset: off_t, + __unused1: [::c_char; 4], + __glibc_reserved: [::c_char; 32] + } + + pub struct stat { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 3], + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + pub st_pad2: [::c_long; 2], + pub st_size: ::off_t, + st_pad3: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + st_pad5: [::c_long; 14], + } + + pub struct stat64 { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 3], + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + st_pad2: [::c_long; 2], + pub st_size: ::off64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad3: ::c_long, + pub st_blocks: ::blkcnt64_t, + st_pad5: [::c_long; 14], + } + + pub struct statfs64 { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_bavail: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_long, + pub f_flags: ::c_long, + pub f_spare: [::c_long; 5], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u32; 9] + } + + pub struct sigaction { + pub sa_flags: ::c_int, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + pub sa_restorer: ::Option, + _resv: [::c_int; 1], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct sigset_t { + __val: [::c_ulong; 32], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub _pad: [::c_int; 29], + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_uint, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + #[cfg(target_endian = "big")] + __glibc_reserved1: ::c_ulong, + pub msg_stime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved1: ::c_ulong, + #[cfg(target_endian = "big")] + __glibc_reserved2: ::c_ulong, + pub msg_rtime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved2: ::c_ulong, + #[cfg(target_endian = "big")] + __glibc_reserved3: ::c_ulong, + pub msg_ctime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved3: ::c_ulong, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsblkcnt_t, + pub f_ffree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + + pub f_namelen: ::c_long, + f_spare: [::c_long; 6], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_sysid: ::c_long, + pub l_pid: ::pid_t, + pad: [::c_long; 4], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 8], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +align_const! { + #[cfg(target_endian = "little")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; +} + +pub const O_LARGEFILE: ::c_int = 0x2000; + +pub const RLIM_INFINITY: ::rlim_t = 0x7fffffff; + +pub const SYS_syscall: ::c_long = 4000 + 0; +pub const SYS_exit: ::c_long = 4000 + 1; +pub const SYS_fork: ::c_long = 4000 + 2; +pub const SYS_read: ::c_long = 4000 + 3; +pub const SYS_write: ::c_long = 4000 + 4; +pub const SYS_open: ::c_long = 4000 + 5; +pub const SYS_close: ::c_long = 4000 + 6; +pub const SYS_waitpid: ::c_long = 4000 + 7; +pub const SYS_creat: ::c_long = 4000 + 8; +pub const SYS_link: ::c_long = 4000 + 9; +pub const SYS_unlink: ::c_long = 4000 + 10; +pub const SYS_execve: ::c_long = 4000 + 11; +pub const SYS_chdir: ::c_long = 4000 + 12; +pub const SYS_time: ::c_long = 4000 + 13; +pub const SYS_mknod: ::c_long = 4000 + 14; +pub const SYS_chmod: ::c_long = 4000 + 15; +pub const SYS_lchown: ::c_long = 4000 + 16; +pub const SYS_break: ::c_long = 4000 + 17; +pub const SYS_lseek: ::c_long = 4000 + 19; +pub const SYS_getpid: ::c_long = 4000 + 20; +pub const SYS_mount: ::c_long = 4000 + 21; +pub const SYS_umount: ::c_long = 4000 + 22; +pub const SYS_setuid: ::c_long = 4000 + 23; +pub const SYS_getuid: ::c_long = 4000 + 24; +pub const SYS_stime: ::c_long = 4000 + 25; +pub const SYS_ptrace: ::c_long = 4000 + 26; +pub const SYS_alarm: ::c_long = 4000 + 27; +pub const SYS_pause: ::c_long = 4000 + 29; +pub const SYS_utime: ::c_long = 4000 + 30; +pub const SYS_stty: ::c_long = 4000 + 31; +pub const SYS_gtty: ::c_long = 4000 + 32; +pub const SYS_access: ::c_long = 4000 + 33; +pub const SYS_nice: ::c_long = 4000 + 34; +pub const SYS_ftime: ::c_long = 4000 + 35; +pub const SYS_sync: ::c_long = 4000 + 36; +pub const SYS_kill: ::c_long = 4000 + 37; +pub const SYS_rename: ::c_long = 4000 + 38; +pub const SYS_mkdir: ::c_long = 4000 + 39; +pub const SYS_rmdir: ::c_long = 4000 + 40; +pub const SYS_dup: ::c_long = 4000 + 41; +pub const SYS_pipe: ::c_long = 4000 + 42; +pub const SYS_times: ::c_long = 4000 + 43; +pub const SYS_prof: ::c_long = 4000 + 44; +pub const SYS_brk: ::c_long = 4000 + 45; +pub const SYS_setgid: ::c_long = 4000 + 46; +pub const SYS_getgid: ::c_long = 4000 + 47; +pub const SYS_signal: ::c_long = 4000 + 48; +pub const SYS_geteuid: ::c_long = 4000 + 49; +pub const SYS_getegid: ::c_long = 4000 + 50; +pub const SYS_acct: ::c_long = 4000 + 51; +pub const SYS_umount2: ::c_long = 4000 + 52; +pub const SYS_lock: ::c_long = 4000 + 53; +pub const SYS_ioctl: ::c_long = 4000 + 54; +pub const SYS_fcntl: ::c_long = 4000 + 55; +pub const SYS_mpx: ::c_long = 4000 + 56; +pub const SYS_setpgid: ::c_long = 4000 + 57; +pub const SYS_ulimit: ::c_long = 4000 + 58; +pub const SYS_umask: ::c_long = 4000 + 60; +pub const SYS_chroot: ::c_long = 4000 + 61; +pub const SYS_ustat: ::c_long = 4000 + 62; +pub const SYS_dup2: ::c_long = 4000 + 63; +pub const SYS_getppid: ::c_long = 4000 + 64; +pub const SYS_getpgrp: ::c_long = 4000 + 65; +pub const SYS_setsid: ::c_long = 4000 + 66; +pub const SYS_sigaction: ::c_long = 4000 + 67; +pub const SYS_sgetmask: ::c_long = 4000 + 68; +pub const SYS_ssetmask: ::c_long = 4000 + 69; +pub const SYS_setreuid: ::c_long = 4000 + 70; +pub const SYS_setregid: ::c_long = 4000 + 71; +pub const SYS_sigsuspend: ::c_long = 4000 + 72; +pub const SYS_sigpending: ::c_long = 4000 + 73; +pub const SYS_sethostname: ::c_long = 4000 + 74; +pub const SYS_setrlimit: ::c_long = 4000 + 75; +pub const SYS_getrlimit: ::c_long = 4000 + 76; +pub const SYS_getrusage: ::c_long = 4000 + 77; +pub const SYS_gettimeofday: ::c_long = 4000 + 78; +pub const SYS_settimeofday: ::c_long = 4000 + 79; +pub const SYS_getgroups: ::c_long = 4000 + 80; +pub const SYS_setgroups: ::c_long = 4000 + 81; +pub const SYS_symlink: ::c_long = 4000 + 83; +pub const SYS_readlink: ::c_long = 4000 + 85; +pub const SYS_uselib: ::c_long = 4000 + 86; +pub const SYS_swapon: ::c_long = 4000 + 87; +pub const SYS_reboot: ::c_long = 4000 + 88; +pub const SYS_readdir: ::c_long = 4000 + 89; +pub const SYS_mmap: ::c_long = 4000 + 90; +pub const SYS_munmap: ::c_long = 4000 + 91; +pub const SYS_truncate: ::c_long = 4000 + 92; +pub const SYS_ftruncate: ::c_long = 4000 + 93; +pub const SYS_fchmod: ::c_long = 4000 + 94; +pub const SYS_fchown: ::c_long = 4000 + 95; +pub const SYS_getpriority: ::c_long = 4000 + 96; +pub const SYS_setpriority: ::c_long = 4000 + 97; +pub const SYS_profil: ::c_long = 4000 + 98; +pub const SYS_statfs: ::c_long = 4000 + 99; +pub const SYS_fstatfs: ::c_long = 4000 + 100; +pub const SYS_ioperm: ::c_long = 4000 + 101; +pub const SYS_socketcall: ::c_long = 4000 + 102; +pub const SYS_syslog: ::c_long = 4000 + 103; +pub const SYS_setitimer: ::c_long = 4000 + 104; +pub const SYS_getitimer: ::c_long = 4000 + 105; +pub const SYS_stat: ::c_long = 4000 + 106; +pub const SYS_lstat: ::c_long = 4000 + 107; +pub const SYS_fstat: ::c_long = 4000 + 108; +pub const SYS_iopl: ::c_long = 4000 + 110; +pub const SYS_vhangup: ::c_long = 4000 + 111; +pub const SYS_idle: ::c_long = 4000 + 112; +pub const SYS_vm86: ::c_long = 4000 + 113; +pub const SYS_wait4: ::c_long = 4000 + 114; +pub const SYS_swapoff: ::c_long = 4000 + 115; +pub const SYS_sysinfo: ::c_long = 4000 + 116; +pub const SYS_ipc: ::c_long = 4000 + 117; +pub const SYS_fsync: ::c_long = 4000 + 118; +pub const SYS_sigreturn: ::c_long = 4000 + 119; +pub const SYS_clone: ::c_long = 4000 + 120; +pub const SYS_setdomainname: ::c_long = 4000 + 121; +pub const SYS_uname: ::c_long = 4000 + 122; +pub const SYS_modify_ldt: ::c_long = 4000 + 123; +pub const SYS_adjtimex: ::c_long = 4000 + 124; +pub const SYS_mprotect: ::c_long = 4000 + 125; +pub const SYS_sigprocmask: ::c_long = 4000 + 126; +pub const SYS_create_module: ::c_long = 4000 + 127; +pub const SYS_init_module: ::c_long = 4000 + 128; +pub const SYS_delete_module: ::c_long = 4000 + 129; +pub const SYS_get_kernel_syms: ::c_long = 4000 + 130; +pub const SYS_quotactl: ::c_long = 4000 + 131; +pub const SYS_getpgid: ::c_long = 4000 + 132; +pub const SYS_fchdir: ::c_long = 4000 + 133; +pub const SYS_bdflush: ::c_long = 4000 + 134; +pub const SYS_sysfs: ::c_long = 4000 + 135; +pub const SYS_personality: ::c_long = 4000 + 136; +pub const SYS_afs_syscall: ::c_long = 4000 + 137; +pub const SYS_setfsuid: ::c_long = 4000 + 138; +pub const SYS_setfsgid: ::c_long = 4000 + 139; +pub const SYS__llseek: ::c_long = 4000 + 140; +pub const SYS_getdents: ::c_long = 4000 + 141; +pub const SYS__newselect: ::c_long = 4000 + 142; +pub const SYS_flock: ::c_long = 4000 + 143; +pub const SYS_msync: ::c_long = 4000 + 144; +pub const SYS_readv: ::c_long = 4000 + 145; +pub const SYS_writev: ::c_long = 4000 + 146; +pub const SYS_cacheflush: ::c_long = 4000 + 147; +pub const SYS_cachectl: ::c_long = 4000 + 148; +pub const SYS_sysmips: ::c_long = 4000 + 149; +pub const SYS_getsid: ::c_long = 4000 + 151; +pub const SYS_fdatasync: ::c_long = 4000 + 152; +pub const SYS__sysctl: ::c_long = 4000 + 153; +pub const SYS_mlock: ::c_long = 4000 + 154; +pub const SYS_munlock: ::c_long = 4000 + 155; +pub const SYS_mlockall: ::c_long = 4000 + 156; +pub const SYS_munlockall: ::c_long = 4000 + 157; +pub const SYS_sched_setparam: ::c_long = 4000 + 158; +pub const SYS_sched_getparam: ::c_long = 4000 + 159; +pub const SYS_sched_setscheduler: ::c_long = 4000 + 160; +pub const SYS_sched_getscheduler: ::c_long = 4000 + 161; +pub const SYS_sched_yield: ::c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: ::c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: ::c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: ::c_long = 4000 + 165; +pub const SYS_nanosleep: ::c_long = 4000 + 166; +pub const SYS_mremap: ::c_long = 4000 + 167; +pub const SYS_accept: ::c_long = 4000 + 168; +pub const SYS_bind: ::c_long = 4000 + 169; +pub const SYS_connect: ::c_long = 4000 + 170; +pub const SYS_getpeername: ::c_long = 4000 + 171; +pub const SYS_getsockname: ::c_long = 4000 + 172; +pub const SYS_getsockopt: ::c_long = 4000 + 173; +pub const SYS_listen: ::c_long = 4000 + 174; +pub const SYS_recv: ::c_long = 4000 + 175; +pub const SYS_recvfrom: ::c_long = 4000 + 176; +pub const SYS_recvmsg: ::c_long = 4000 + 177; +pub const SYS_send: ::c_long = 4000 + 178; +pub const SYS_sendmsg: ::c_long = 4000 + 179; +pub const SYS_sendto: ::c_long = 4000 + 180; +pub const SYS_setsockopt: ::c_long = 4000 + 181; +pub const SYS_shutdown: ::c_long = 4000 + 182; +pub const SYS_socket: ::c_long = 4000 + 183; +pub const SYS_socketpair: ::c_long = 4000 + 184; +pub const SYS_setresuid: ::c_long = 4000 + 185; +pub const SYS_getresuid: ::c_long = 4000 + 186; +pub const SYS_query_module: ::c_long = 4000 + 187; +pub const SYS_poll: ::c_long = 4000 + 188; +pub const SYS_nfsservctl: ::c_long = 4000 + 189; +pub const SYS_setresgid: ::c_long = 4000 + 190; +pub const SYS_getresgid: ::c_long = 4000 + 191; +pub const SYS_prctl: ::c_long = 4000 + 192; +pub const SYS_rt_sigreturn: ::c_long = 4000 + 193; +pub const SYS_rt_sigaction: ::c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: ::c_long = 4000 + 195; +pub const SYS_rt_sigpending: ::c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: ::c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: ::c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: ::c_long = 4000 + 199; +pub const SYS_pread64: ::c_long = 4000 + 200; +pub const SYS_pwrite64: ::c_long = 4000 + 201; +pub const SYS_chown: ::c_long = 4000 + 202; +pub const SYS_getcwd: ::c_long = 4000 + 203; +pub const SYS_capget: ::c_long = 4000 + 204; +pub const SYS_capset: ::c_long = 4000 + 205; +pub const SYS_sigaltstack: ::c_long = 4000 + 206; +pub const SYS_sendfile: ::c_long = 4000 + 207; +pub const SYS_getpmsg: ::c_long = 4000 + 208; +pub const SYS_putpmsg: ::c_long = 4000 + 209; +pub const SYS_mmap2: ::c_long = 4000 + 210; +pub const SYS_truncate64: ::c_long = 4000 + 211; +pub const SYS_ftruncate64: ::c_long = 4000 + 212; +pub const SYS_stat64: ::c_long = 4000 + 213; +pub const SYS_lstat64: ::c_long = 4000 + 214; +pub const SYS_fstat64: ::c_long = 4000 + 215; +pub const SYS_pivot_root: ::c_long = 4000 + 216; +pub const SYS_mincore: ::c_long = 4000 + 217; +pub const SYS_madvise: ::c_long = 4000 + 218; +pub const SYS_getdents64: ::c_long = 4000 + 219; +pub const SYS_fcntl64: ::c_long = 4000 + 220; +pub const SYS_gettid: ::c_long = 4000 + 222; +pub const SYS_readahead: ::c_long = 4000 + 223; +pub const SYS_setxattr: ::c_long = 4000 + 224; +pub const SYS_lsetxattr: ::c_long = 4000 + 225; +pub const SYS_fsetxattr: ::c_long = 4000 + 226; +pub const SYS_getxattr: ::c_long = 4000 + 227; +pub const SYS_lgetxattr: ::c_long = 4000 + 228; +pub const SYS_fgetxattr: ::c_long = 4000 + 229; +pub const SYS_listxattr: ::c_long = 4000 + 230; +pub const SYS_llistxattr: ::c_long = 4000 + 231; +pub const SYS_flistxattr: ::c_long = 4000 + 232; +pub const SYS_removexattr: ::c_long = 4000 + 233; +pub const SYS_lremovexattr: ::c_long = 4000 + 234; +pub const SYS_fremovexattr: ::c_long = 4000 + 235; +pub const SYS_tkill: ::c_long = 4000 + 236; +pub const SYS_sendfile64: ::c_long = 4000 + 237; +pub const SYS_futex: ::c_long = 4000 + 238; +pub const SYS_sched_setaffinity: ::c_long = 4000 + 239; +pub const SYS_sched_getaffinity: ::c_long = 4000 + 240; +pub const SYS_io_setup: ::c_long = 4000 + 241; +pub const SYS_io_destroy: ::c_long = 4000 + 242; +pub const SYS_io_getevents: ::c_long = 4000 + 243; +pub const SYS_io_submit: ::c_long = 4000 + 244; +pub const SYS_io_cancel: ::c_long = 4000 + 245; +pub const SYS_exit_group: ::c_long = 4000 + 246; +pub const SYS_lookup_dcookie: ::c_long = 4000 + 247; +pub const SYS_epoll_create: ::c_long = 4000 + 248; +pub const SYS_epoll_ctl: ::c_long = 4000 + 249; +pub const SYS_epoll_wait: ::c_long = 4000 + 250; +pub const SYS_remap_file_pages: ::c_long = 4000 + 251; +pub const SYS_set_tid_address: ::c_long = 4000 + 252; +pub const SYS_restart_syscall: ::c_long = 4000 + 253; +pub const SYS_fadvise64: ::c_long = 4000 + 254; +pub const SYS_statfs64: ::c_long = 4000 + 255; +pub const SYS_fstatfs64: ::c_long = 4000 + 256; +pub const SYS_timer_create: ::c_long = 4000 + 257; +pub const SYS_timer_settime: ::c_long = 4000 + 258; +pub const SYS_timer_gettime: ::c_long = 4000 + 259; +pub const SYS_timer_getoverrun: ::c_long = 4000 + 260; +pub const SYS_timer_delete: ::c_long = 4000 + 261; +pub const SYS_clock_settime: ::c_long = 4000 + 262; +pub const SYS_clock_gettime: ::c_long = 4000 + 263; +pub const SYS_clock_getres: ::c_long = 4000 + 264; +pub const SYS_clock_nanosleep: ::c_long = 4000 + 265; +pub const SYS_tgkill: ::c_long = 4000 + 266; +pub const SYS_utimes: ::c_long = 4000 + 267; +pub const SYS_mbind: ::c_long = 4000 + 268; +pub const SYS_get_mempolicy: ::c_long = 4000 + 269; +pub const SYS_set_mempolicy: ::c_long = 4000 + 270; +pub const SYS_mq_open: ::c_long = 4000 + 271; +pub const SYS_mq_unlink: ::c_long = 4000 + 272; +pub const SYS_mq_timedsend: ::c_long = 4000 + 273; +pub const SYS_mq_timedreceive: ::c_long = 4000 + 274; +pub const SYS_mq_notify: ::c_long = 4000 + 275; +pub const SYS_mq_getsetattr: ::c_long = 4000 + 276; +pub const SYS_vserver: ::c_long = 4000 + 277; +pub const SYS_waitid: ::c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: ::c_long = 4000 + 279; */ +pub const SYS_add_key: ::c_long = 4000 + 280; +pub const SYS_request_key: ::c_long = 4000 + 281; +pub const SYS_keyctl: ::c_long = 4000 + 282; +pub const SYS_set_thread_area: ::c_long = 4000 + 283; +pub const SYS_inotify_init: ::c_long = 4000 + 284; +pub const SYS_inotify_add_watch: ::c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: ::c_long = 4000 + 286; +pub const SYS_migrate_pages: ::c_long = 4000 + 287; +pub const SYS_openat: ::c_long = 4000 + 288; +pub const SYS_mkdirat: ::c_long = 4000 + 289; +pub const SYS_mknodat: ::c_long = 4000 + 290; +pub const SYS_fchownat: ::c_long = 4000 + 291; +pub const SYS_futimesat: ::c_long = 4000 + 292; +pub const SYS_fstatat64: ::c_long = 4000 + 293; +pub const SYS_unlinkat: ::c_long = 4000 + 294; +pub const SYS_renameat: ::c_long = 4000 + 295; +pub const SYS_linkat: ::c_long = 4000 + 296; +pub const SYS_symlinkat: ::c_long = 4000 + 297; +pub const SYS_readlinkat: ::c_long = 4000 + 298; +pub const SYS_fchmodat: ::c_long = 4000 + 299; +pub const SYS_faccessat: ::c_long = 4000 + 300; +pub const SYS_pselect6: ::c_long = 4000 + 301; +pub const SYS_ppoll: ::c_long = 4000 + 302; +pub const SYS_unshare: ::c_long = 4000 + 303; +pub const SYS_splice: ::c_long = 4000 + 304; +pub const SYS_sync_file_range: ::c_long = 4000 + 305; +pub const SYS_tee: ::c_long = 4000 + 306; +pub const SYS_vmsplice: ::c_long = 4000 + 307; +pub const SYS_move_pages: ::c_long = 4000 + 308; +pub const SYS_set_robust_list: ::c_long = 4000 + 309; +pub const SYS_get_robust_list: ::c_long = 4000 + 310; +pub const SYS_kexec_load: ::c_long = 4000 + 311; +pub const SYS_getcpu: ::c_long = 4000 + 312; +pub const SYS_epoll_pwait: ::c_long = 4000 + 313; +pub const SYS_ioprio_set: ::c_long = 4000 + 314; +pub const SYS_ioprio_get: ::c_long = 4000 + 315; +pub const SYS_utimensat: ::c_long = 4000 + 316; +pub const SYS_signalfd: ::c_long = 4000 + 317; +pub const SYS_timerfd: ::c_long = 4000 + 318; +pub const SYS_eventfd: ::c_long = 4000 + 319; +pub const SYS_fallocate: ::c_long = 4000 + 320; +pub const SYS_timerfd_create: ::c_long = 4000 + 321; +pub const SYS_timerfd_gettime: ::c_long = 4000 + 322; +pub const SYS_timerfd_settime: ::c_long = 4000 + 323; +pub const SYS_signalfd4: ::c_long = 4000 + 324; +pub const SYS_eventfd2: ::c_long = 4000 + 325; +pub const SYS_epoll_create1: ::c_long = 4000 + 326; +pub const SYS_dup3: ::c_long = 4000 + 327; +pub const SYS_pipe2: ::c_long = 4000 + 328; +pub const SYS_inotify_init1: ::c_long = 4000 + 329; +pub const SYS_preadv: ::c_long = 4000 + 330; +pub const SYS_pwritev: ::c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 4000 + 332; +pub const SYS_perf_event_open: ::c_long = 4000 + 333; +pub const SYS_accept4: ::c_long = 4000 + 334; +pub const SYS_recvmmsg: ::c_long = 4000 + 335; +pub const SYS_fanotify_init: ::c_long = 4000 + 336; +pub const SYS_fanotify_mark: ::c_long = 4000 + 337; +pub const SYS_prlimit64: ::c_long = 4000 + 338; +pub const SYS_name_to_handle_at: ::c_long = 4000 + 339; +pub const SYS_open_by_handle_at: ::c_long = 4000 + 340; +pub const SYS_clock_adjtime: ::c_long = 4000 + 341; +pub const SYS_syncfs: ::c_long = 4000 + 342; +pub const SYS_sendmmsg: ::c_long = 4000 + 343; +pub const SYS_setns: ::c_long = 4000 + 344; +pub const SYS_process_vm_readv: ::c_long = 4000 + 345; +pub const SYS_process_vm_writev: ::c_long = 4000 + 346; +pub const SYS_kcmp: ::c_long = 4000 + 347; +pub const SYS_finit_module: ::c_long = 4000 + 348; +pub const SYS_sched_setattr: ::c_long = 4000 + 349; +pub const SYS_sched_getattr: ::c_long = 4000 + 350; +pub const SYS_renameat2: ::c_long = 4000 + 351; +pub const SYS_seccomp: ::c_long = 4000 + 352; +pub const SYS_getrandom: ::c_long = 4000 + 353; +pub const SYS_memfd_create: ::c_long = 4000 + 354; +pub const SYS_bpf: ::c_long = 4000 + 355; +pub const SYS_execveat: ::c_long = 4000 + 356; +pub const SYS_userfaultfd: ::c_long = 4000 + 357; +pub const SYS_membarrier: ::c_long = 4000 + 358; +pub const SYS_mlock2: ::c_long = 4000 + 359; +pub const SYS_copy_file_range: ::c_long = 4000 + 360; +pub const SYS_preadv2: ::c_long = 4000 + 361; +pub const SYS_pwritev2: ::c_long = 4000 + 362; +pub const SYS_pkey_mprotect: ::c_long = 4000 + 363; +pub const SYS_pkey_alloc: ::c_long = 4000 + 364; +pub const SYS_pkey_free: ::c_long = 4000 + 365; diff --git a/libc/src/unix/notbsd/linux/mips/mips64.rs b/libc/src/unix/notbsd/linux/mips/mips64.rs new file mode 100644 index 000000000..f480e50a8 --- /dev/null +++ b/libc/src/unix/notbsd/linux/mips/mips64.rs @@ -0,0 +1,645 @@ +use pthread_mutex_t; + +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type ino_t = u64; +pub type nlink_t = u64; +pub type off_t = i64; +pub type suseconds_t = i64; +pub type time_t = i64; +pub type wchar_t = i32; +pub type clock_t = i64; +pub type __u64 = ::c_ulong; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __next_prio: *mut aiocb, + __abs_prio: ::c_int, + __policy: ::c_int, + __error_code: ::c_int, + __return_value: ::ssize_t, + pub aio_offset: off_t, + __glibc_reserved: [::c_char; 32] + } + + pub struct stat { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 2], + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + st_pad2: [::c_ulong; 1], + pub st_size: ::off_t, + st_pad3: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad4: ::c_long, + pub st_blocks: ::blkcnt_t, + st_pad5: [::c_long; 7], + } + + pub struct stat64 { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 2], + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + st_pad2: [::c_long; 2], + pub st_size: ::off64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad3: ::c_long, + pub st_blocks: ::blkcnt64_t, + st_pad5: [::c_long; 7], + } + + pub struct statfs64 { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_bavail: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_long, + pub f_flags: ::c_long, + pub f_spare: [::c_long; 5], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [::c_ulong; 7] + } + + pub struct sigaction { + pub sa_flags: ::c_int, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + pub sa_restorer: ::Option, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct sigset_t { + __size: [::c_ulong; 16], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + _pad: ::c_int, + _pad2: [::c_long; 14], + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_uint, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsblkcnt_t, + pub f_ffree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + + pub f_namelen: ::c_long, + f_spare: [::c_long; 6], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +align_const! { + #[cfg(target_endian = "little")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +pub const O_LARGEFILE: ::c_int = 0; + +pub const RLIM_INFINITY: ::rlim_t = 0xffff_ffff_ffff_ffff; + +pub const SYS_read: ::c_long = 5000 + 0; +pub const SYS_write: ::c_long = 5000 + 1; +pub const SYS_open: ::c_long = 5000 + 2; +pub const SYS_close: ::c_long = 5000 + 3; +pub const SYS_stat: ::c_long = 5000 + 4; +pub const SYS_fstat: ::c_long = 5000 + 5; +pub const SYS_lstat: ::c_long = 5000 + 6; +pub const SYS_poll: ::c_long = 5000 + 7; +pub const SYS_lseek: ::c_long = 5000 + 8; +pub const SYS_mmap: ::c_long = 5000 + 9; +pub const SYS_mprotect: ::c_long = 5000 + 10; +pub const SYS_munmap: ::c_long = 5000 + 11; +pub const SYS_brk: ::c_long = 5000 + 12; +pub const SYS_rt_sigaction: ::c_long = 5000 + 13; +pub const SYS_rt_sigprocmask: ::c_long = 5000 + 14; +pub const SYS_ioctl: ::c_long = 5000 + 15; +pub const SYS_pread64: ::c_long = 5000 + 16; +pub const SYS_pwrite64: ::c_long = 5000 + 17; +pub const SYS_readv: ::c_long = 5000 + 18; +pub const SYS_writev: ::c_long = 5000 + 19; +pub const SYS_access: ::c_long = 5000 + 20; +pub const SYS_pipe: ::c_long = 5000 + 21; +pub const SYS__newselect: ::c_long = 5000 + 22; +pub const SYS_sched_yield: ::c_long = 5000 + 23; +pub const SYS_mremap: ::c_long = 5000 + 24; +pub const SYS_msync: ::c_long = 5000 + 25; +pub const SYS_mincore: ::c_long = 5000 + 26; +pub const SYS_madvise: ::c_long = 5000 + 27; +pub const SYS_shmget: ::c_long = 5000 + 28; +pub const SYS_shmat: ::c_long = 5000 + 29; +pub const SYS_shmctl: ::c_long = 5000 + 30; +pub const SYS_dup: ::c_long = 5000 + 31; +pub const SYS_dup2: ::c_long = 5000 + 32; +pub const SYS_pause: ::c_long = 5000 + 33; +pub const SYS_nanosleep: ::c_long = 5000 + 34; +pub const SYS_getitimer: ::c_long = 5000 + 35; +pub const SYS_setitimer: ::c_long = 5000 + 36; +pub const SYS_alarm: ::c_long = 5000 + 37; +pub const SYS_getpid: ::c_long = 5000 + 38; +pub const SYS_sendfile: ::c_long = 5000 + 39; +pub const SYS_socket: ::c_long = 5000 + 40; +pub const SYS_connect: ::c_long = 5000 + 41; +pub const SYS_accept: ::c_long = 5000 + 42; +pub const SYS_sendto: ::c_long = 5000 + 43; +pub const SYS_recvfrom: ::c_long = 5000 + 44; +pub const SYS_sendmsg: ::c_long = 5000 + 45; +pub const SYS_recvmsg: ::c_long = 5000 + 46; +pub const SYS_shutdown: ::c_long = 5000 + 47; +pub const SYS_bind: ::c_long = 5000 + 48; +pub const SYS_listen: ::c_long = 5000 + 49; +pub const SYS_getsockname: ::c_long = 5000 + 50; +pub const SYS_getpeername: ::c_long = 5000 + 51; +pub const SYS_socketpair: ::c_long = 5000 + 52; +pub const SYS_setsockopt: ::c_long = 5000 + 53; +pub const SYS_getsockopt: ::c_long = 5000 + 54; +pub const SYS_clone: ::c_long = 5000 + 55; +pub const SYS_fork: ::c_long = 5000 + 56; +pub const SYS_execve: ::c_long = 5000 + 57; +pub const SYS_exit: ::c_long = 5000 + 58; +pub const SYS_wait4: ::c_long = 5000 + 59; +pub const SYS_kill: ::c_long = 5000 + 60; +pub const SYS_uname: ::c_long = 5000 + 61; +pub const SYS_semget: ::c_long = 5000 + 62; +pub const SYS_semop: ::c_long = 5000 + 63; +pub const SYS_semctl: ::c_long = 5000 + 64; +pub const SYS_shmdt: ::c_long = 5000 + 65; +pub const SYS_msgget: ::c_long = 5000 + 66; +pub const SYS_msgsnd: ::c_long = 5000 + 67; +pub const SYS_msgrcv: ::c_long = 5000 + 68; +pub const SYS_msgctl: ::c_long = 5000 + 69; +pub const SYS_fcntl: ::c_long = 5000 + 70; +pub const SYS_flock: ::c_long = 5000 + 71; +pub const SYS_fsync: ::c_long = 5000 + 72; +pub const SYS_fdatasync: ::c_long = 5000 + 73; +pub const SYS_truncate: ::c_long = 5000 + 74; +pub const SYS_ftruncate: ::c_long = 5000 + 75; +pub const SYS_getdents: ::c_long = 5000 + 76; +pub const SYS_getcwd: ::c_long = 5000 + 77; +pub const SYS_chdir: ::c_long = 5000 + 78; +pub const SYS_fchdir: ::c_long = 5000 + 79; +pub const SYS_rename: ::c_long = 5000 + 80; +pub const SYS_mkdir: ::c_long = 5000 + 81; +pub const SYS_rmdir: ::c_long = 5000 + 82; +pub const SYS_creat: ::c_long = 5000 + 83; +pub const SYS_link: ::c_long = 5000 + 84; +pub const SYS_unlink: ::c_long = 5000 + 85; +pub const SYS_symlink: ::c_long = 5000 + 86; +pub const SYS_readlink: ::c_long = 5000 + 87; +pub const SYS_chmod: ::c_long = 5000 + 88; +pub const SYS_fchmod: ::c_long = 5000 + 89; +pub const SYS_chown: ::c_long = 5000 + 90; +pub const SYS_fchown: ::c_long = 5000 + 91; +pub const SYS_lchown: ::c_long = 5000 + 92; +pub const SYS_umask: ::c_long = 5000 + 93; +pub const SYS_gettimeofday: ::c_long = 5000 + 94; +pub const SYS_getrlimit: ::c_long = 5000 + 95; +pub const SYS_getrusage: ::c_long = 5000 + 96; +pub const SYS_sysinfo: ::c_long = 5000 + 97; +pub const SYS_times: ::c_long = 5000 + 98; +pub const SYS_ptrace: ::c_long = 5000 + 99; +pub const SYS_getuid: ::c_long = 5000 + 100; +pub const SYS_syslog: ::c_long = 5000 + 101; +pub const SYS_getgid: ::c_long = 5000 + 102; +pub const SYS_setuid: ::c_long = 5000 + 103; +pub const SYS_setgid: ::c_long = 5000 + 104; +pub const SYS_geteuid: ::c_long = 5000 + 105; +pub const SYS_getegid: ::c_long = 5000 + 106; +pub const SYS_setpgid: ::c_long = 5000 + 107; +pub const SYS_getppid: ::c_long = 5000 + 108; +pub const SYS_getpgrp: ::c_long = 5000 + 109; +pub const SYS_setsid: ::c_long = 5000 + 110; +pub const SYS_setreuid: ::c_long = 5000 + 111; +pub const SYS_setregid: ::c_long = 5000 + 112; +pub const SYS_getgroups: ::c_long = 5000 + 113; +pub const SYS_setgroups: ::c_long = 5000 + 114; +pub const SYS_setresuid: ::c_long = 5000 + 115; +pub const SYS_getresuid: ::c_long = 5000 + 116; +pub const SYS_setresgid: ::c_long = 5000 + 117; +pub const SYS_getresgid: ::c_long = 5000 + 118; +pub const SYS_getpgid: ::c_long = 5000 + 119; +pub const SYS_setfsuid: ::c_long = 5000 + 120; +pub const SYS_setfsgid: ::c_long = 5000 + 121; +pub const SYS_getsid: ::c_long = 5000 + 122; +pub const SYS_capget: ::c_long = 5000 + 123; +pub const SYS_capset: ::c_long = 5000 + 124; +pub const SYS_rt_sigpending: ::c_long = 5000 + 125; +pub const SYS_rt_sigtimedwait: ::c_long = 5000 + 126; +pub const SYS_rt_sigqueueinfo: ::c_long = 5000 + 127; +pub const SYS_rt_sigsuspend: ::c_long = 5000 + 128; +pub const SYS_sigaltstack: ::c_long = 5000 + 129; +pub const SYS_utime: ::c_long = 5000 + 130; +pub const SYS_mknod: ::c_long = 5000 + 131; +pub const SYS_personality: ::c_long = 5000 + 132; +pub const SYS_ustat: ::c_long = 5000 + 133; +pub const SYS_statfs: ::c_long = 5000 + 134; +pub const SYS_fstatfs: ::c_long = 5000 + 135; +pub const SYS_sysfs: ::c_long = 5000 + 136; +pub const SYS_getpriority: ::c_long = 5000 + 137; +pub const SYS_setpriority: ::c_long = 5000 + 138; +pub const SYS_sched_setparam: ::c_long = 5000 + 139; +pub const SYS_sched_getparam: ::c_long = 5000 + 140; +pub const SYS_sched_setscheduler: ::c_long = 5000 + 141; +pub const SYS_sched_getscheduler: ::c_long = 5000 + 142; +pub const SYS_sched_get_priority_max: ::c_long = 5000 + 143; +pub const SYS_sched_get_priority_min: ::c_long = 5000 + 144; +pub const SYS_sched_rr_get_interval: ::c_long = 5000 + 145; +pub const SYS_mlock: ::c_long = 5000 + 146; +pub const SYS_munlock: ::c_long = 5000 + 147; +pub const SYS_mlockall: ::c_long = 5000 + 148; +pub const SYS_munlockall: ::c_long = 5000 + 149; +pub const SYS_vhangup: ::c_long = 5000 + 150; +pub const SYS_pivot_root: ::c_long = 5000 + 151; +pub const SYS__sysctl: ::c_long = 5000 + 152; +pub const SYS_prctl: ::c_long = 5000 + 153; +pub const SYS_adjtimex: ::c_long = 5000 + 154; +pub const SYS_setrlimit: ::c_long = 5000 + 155; +pub const SYS_chroot: ::c_long = 5000 + 156; +pub const SYS_sync: ::c_long = 5000 + 157; +pub const SYS_acct: ::c_long = 5000 + 158; +pub const SYS_settimeofday: ::c_long = 5000 + 159; +pub const SYS_mount: ::c_long = 5000 + 160; +pub const SYS_umount2: ::c_long = 5000 + 161; +pub const SYS_swapon: ::c_long = 5000 + 162; +pub const SYS_swapoff: ::c_long = 5000 + 163; +pub const SYS_reboot: ::c_long = 5000 + 164; +pub const SYS_sethostname: ::c_long = 5000 + 165; +pub const SYS_setdomainname: ::c_long = 5000 + 166; +pub const SYS_create_module: ::c_long = 5000 + 167; +pub const SYS_init_module: ::c_long = 5000 + 168; +pub const SYS_delete_module: ::c_long = 5000 + 169; +pub const SYS_get_kernel_syms: ::c_long = 5000 + 170; +pub const SYS_query_module: ::c_long = 5000 + 171; +pub const SYS_quotactl: ::c_long = 5000 + 172; +pub const SYS_nfsservctl: ::c_long = 5000 + 173; +pub const SYS_getpmsg: ::c_long = 5000 + 174; +pub const SYS_putpmsg: ::c_long = 5000 + 175; +pub const SYS_afs_syscall: ::c_long = 5000 + 176; +pub const SYS_gettid: ::c_long = 5000 + 178; +pub const SYS_readahead: ::c_long = 5000 + 179; +pub const SYS_setxattr: ::c_long = 5000 + 180; +pub const SYS_lsetxattr: ::c_long = 5000 + 181; +pub const SYS_fsetxattr: ::c_long = 5000 + 182; +pub const SYS_getxattr: ::c_long = 5000 + 183; +pub const SYS_lgetxattr: ::c_long = 5000 + 184; +pub const SYS_fgetxattr: ::c_long = 5000 + 185; +pub const SYS_listxattr: ::c_long = 5000 + 186; +pub const SYS_llistxattr: ::c_long = 5000 + 187; +pub const SYS_flistxattr: ::c_long = 5000 + 188; +pub const SYS_removexattr: ::c_long = 5000 + 189; +pub const SYS_lremovexattr: ::c_long = 5000 + 190; +pub const SYS_fremovexattr: ::c_long = 5000 + 191; +pub const SYS_tkill: ::c_long = 5000 + 192; +pub const SYS_futex: ::c_long = 5000 + 194; +pub const SYS_sched_setaffinity: ::c_long = 5000 + 195; +pub const SYS_sched_getaffinity: ::c_long = 5000 + 196; +pub const SYS_cacheflush: ::c_long = 5000 + 197; +pub const SYS_cachectl: ::c_long = 5000 + 198; +pub const SYS_sysmips: ::c_long = 5000 + 199; +pub const SYS_io_setup: ::c_long = 5000 + 200; +pub const SYS_io_destroy: ::c_long = 5000 + 201; +pub const SYS_io_getevents: ::c_long = 5000 + 202; +pub const SYS_io_submit: ::c_long = 5000 + 203; +pub const SYS_io_cancel: ::c_long = 5000 + 204; +pub const SYS_exit_group: ::c_long = 5000 + 205; +pub const SYS_lookup_dcookie: ::c_long = 5000 + 206; +pub const SYS_epoll_create: ::c_long = 5000 + 207; +pub const SYS_epoll_ctl: ::c_long = 5000 + 208; +pub const SYS_epoll_wait: ::c_long = 5000 + 209; +pub const SYS_remap_file_pages: ::c_long = 5000 + 210; +pub const SYS_rt_sigreturn: ::c_long = 5000 + 211; +pub const SYS_set_tid_address: ::c_long = 5000 + 212; +pub const SYS_restart_syscall: ::c_long = 5000 + 213; +pub const SYS_semtimedop: ::c_long = 5000 + 214; +pub const SYS_fadvise64: ::c_long = 5000 + 215; +pub const SYS_timer_create: ::c_long = 5000 + 216; +pub const SYS_timer_settime: ::c_long = 5000 + 217; +pub const SYS_timer_gettime: ::c_long = 5000 + 218; +pub const SYS_timer_getoverrun: ::c_long = 5000 + 219; +pub const SYS_timer_delete: ::c_long = 5000 + 220; +pub const SYS_clock_settime: ::c_long = 5000 + 221; +pub const SYS_clock_gettime: ::c_long = 5000 + 222; +pub const SYS_clock_getres: ::c_long = 5000 + 223; +pub const SYS_clock_nanosleep: ::c_long = 5000 + 224; +pub const SYS_tgkill: ::c_long = 5000 + 225; +pub const SYS_utimes: ::c_long = 5000 + 226; +pub const SYS_mbind: ::c_long = 5000 + 227; +pub const SYS_get_mempolicy: ::c_long = 5000 + 228; +pub const SYS_set_mempolicy: ::c_long = 5000 + 229; +pub const SYS_mq_open: ::c_long = 5000 + 230; +pub const SYS_mq_unlink: ::c_long = 5000 + 231; +pub const SYS_mq_timedsend: ::c_long = 5000 + 232; +pub const SYS_mq_timedreceive: ::c_long = 5000 + 233; +pub const SYS_mq_notify: ::c_long = 5000 + 234; +pub const SYS_mq_getsetattr: ::c_long = 5000 + 235; +pub const SYS_vserver: ::c_long = 5000 + 236; +pub const SYS_waitid: ::c_long = 5000 + 237; +/* pub const SYS_sys_setaltroot: ::c_long = 5000 + 238; */ +pub const SYS_add_key: ::c_long = 5000 + 239; +pub const SYS_request_key: ::c_long = 5000 + 240; +pub const SYS_keyctl: ::c_long = 5000 + 241; +pub const SYS_set_thread_area: ::c_long = 5000 + 242; +pub const SYS_inotify_init: ::c_long = 5000 + 243; +pub const SYS_inotify_add_watch: ::c_long = 5000 + 244; +pub const SYS_inotify_rm_watch: ::c_long = 5000 + 245; +pub const SYS_migrate_pages: ::c_long = 5000 + 246; +pub const SYS_openat: ::c_long = 5000 + 247; +pub const SYS_mkdirat: ::c_long = 5000 + 248; +pub const SYS_mknodat: ::c_long = 5000 + 249; +pub const SYS_fchownat: ::c_long = 5000 + 250; +pub const SYS_futimesat: ::c_long = 5000 + 251; +pub const SYS_newfstatat: ::c_long = 5000 + 252; +pub const SYS_unlinkat: ::c_long = 5000 + 253; +pub const SYS_renameat: ::c_long = 5000 + 254; +pub const SYS_linkat: ::c_long = 5000 + 255; +pub const SYS_symlinkat: ::c_long = 5000 + 256; +pub const SYS_readlinkat: ::c_long = 5000 + 257; +pub const SYS_fchmodat: ::c_long = 5000 + 258; +pub const SYS_faccessat: ::c_long = 5000 + 259; +pub const SYS_pselect6: ::c_long = 5000 + 260; +pub const SYS_ppoll: ::c_long = 5000 + 261; +pub const SYS_unshare: ::c_long = 5000 + 262; +pub const SYS_splice: ::c_long = 5000 + 263; +pub const SYS_sync_file_range: ::c_long = 5000 + 264; +pub const SYS_tee: ::c_long = 5000 + 265; +pub const SYS_vmsplice: ::c_long = 5000 + 266; +pub const SYS_move_pages: ::c_long = 5000 + 267; +pub const SYS_set_robust_list: ::c_long = 5000 + 268; +pub const SYS_get_robust_list: ::c_long = 5000 + 269; +pub const SYS_kexec_load: ::c_long = 5000 + 270; +pub const SYS_getcpu: ::c_long = 5000 + 271; +pub const SYS_epoll_pwait: ::c_long = 5000 + 272; +pub const SYS_ioprio_set: ::c_long = 5000 + 273; +pub const SYS_ioprio_get: ::c_long = 5000 + 274; +pub const SYS_utimensat: ::c_long = 5000 + 275; +pub const SYS_signalfd: ::c_long = 5000 + 276; +pub const SYS_timerfd: ::c_long = 5000 + 277; +pub const SYS_eventfd: ::c_long = 5000 + 278; +pub const SYS_fallocate: ::c_long = 5000 + 279; +pub const SYS_timerfd_create: ::c_long = 5000 + 280; +pub const SYS_timerfd_gettime: ::c_long = 5000 + 281; +pub const SYS_timerfd_settime: ::c_long = 5000 + 282; +pub const SYS_signalfd4: ::c_long = 5000 + 283; +pub const SYS_eventfd2: ::c_long = 5000 + 284; +pub const SYS_epoll_create1: ::c_long = 5000 + 285; +pub const SYS_dup3: ::c_long = 5000 + 286; +pub const SYS_pipe2: ::c_long = 5000 + 287; +pub const SYS_inotify_init1: ::c_long = 5000 + 288; +pub const SYS_preadv: ::c_long = 5000 + 289; +pub const SYS_pwritev: ::c_long = 5000 + 290; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 5000 + 291; +pub const SYS_perf_event_open: ::c_long = 5000 + 292; +pub const SYS_accept4: ::c_long = 5000 + 293; +pub const SYS_recvmmsg: ::c_long = 5000 + 294; +pub const SYS_fanotify_init: ::c_long = 5000 + 295; +pub const SYS_fanotify_mark: ::c_long = 5000 + 296; +pub const SYS_prlimit64: ::c_long = 5000 + 297; +pub const SYS_name_to_handle_at: ::c_long = 5000 + 298; +pub const SYS_open_by_handle_at: ::c_long = 5000 + 299; +pub const SYS_clock_adjtime: ::c_long = 5000 + 300; +pub const SYS_syncfs: ::c_long = 5000 + 301; +pub const SYS_sendmmsg: ::c_long = 5000 + 302; +pub const SYS_setns: ::c_long = 5000 + 303; +pub const SYS_process_vm_readv: ::c_long = 5000 + 304; +pub const SYS_process_vm_writev: ::c_long = 5000 + 305; +pub const SYS_kcmp: ::c_long = 5000 + 306; +pub const SYS_finit_module: ::c_long = 5000 + 307; +pub const SYS_getdents64: ::c_long = 5000 + 308; +pub const SYS_sched_setattr: ::c_long = 5000 + 309; +pub const SYS_sched_getattr: ::c_long = 5000 + 310; +pub const SYS_renameat2: ::c_long = 5000 + 311; +pub const SYS_seccomp: ::c_long = 5000 + 312; +pub const SYS_getrandom: ::c_long = 5000 + 313; +pub const SYS_memfd_create: ::c_long = 5000 + 314; +pub const SYS_bpf: ::c_long = 5000 + 315; +pub const SYS_execveat: ::c_long = 5000 + 316; +pub const SYS_userfaultfd: ::c_long = 5000 + 317; +pub const SYS_membarrier: ::c_long = 5000 + 318; +pub const SYS_mlock2: ::c_long = 5000 + 319; +pub const SYS_copy_file_range: ::c_long = 5000 + 320; +pub const SYS_preadv2: ::c_long = 5000 + 321; +pub const SYS_pwritev2: ::c_long = 5000 + 322; +pub const SYS_pkey_mprotect: ::c_long = 5000 + 323; +pub const SYS_pkey_alloc: ::c_long = 5000 + 324; +pub const SYS_pkey_free: ::c_long = 5000 + 325; diff --git a/libc/src/unix/notbsd/linux/mips/mod.rs b/libc/src/unix/notbsd/linux/mips/mod.rs new file mode 100644 index 000000000..35534b44d --- /dev/null +++ b/libc/src/unix/notbsd/linux/mips/mod.rs @@ -0,0 +1,960 @@ +pub type shmatt_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type rlim_t = c_ulong; +pub type __priority_which_t = ::c_uint; + +s! { + pub struct glob64_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut ::c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 23], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct nlmsghdr { + pub nlmsg_len: u32, + pub nlmsg_type: u16, + pub nlmsg_flags: u16, + pub nlmsg_seq: u32, + pub nlmsg_pid: u32, + } + + pub struct nlmsgerr { + pub error: ::c_int, + pub msg: nlmsghdr, + } + + pub struct nl_pktinfo { + pub group: u32, + } + + pub struct nl_mmap_req { + pub nm_block_size: ::c_uint, + pub nm_block_nr: ::c_uint, + pub nm_frame_size: ::c_uint, + pub nm_frame_nr: ::c_uint, + } + + pub struct nl_mmap_hdr { + pub nm_status: ::c_uint, + pub nm_len: ::c_uint, + pub nm_group: u32, + pub nm_pid: u32, + pub nm_uid: u32, + pub nm_gid: u32, + } + + pub struct nlattr { + pub nla_len: u16, + pub nla_type: u16, + } +} + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const BUFSIZ: ::c_uint = 8192; +pub const TMP_MAX: ::c_uint = 238328; +pub const FOPEN_MAX: ::c_uint = 16; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; +pub const _SC_EQUIV_CLASS_MAX: ::c_int = 41; +pub const _SC_CHARCLASS_NAME_MAX: ::c_int = 45; +pub const _SC_PII: ::c_int = 53; +pub const _SC_PII_XTI: ::c_int = 54; +pub const _SC_PII_SOCKET: ::c_int = 55; +pub const _SC_PII_INTERNET: ::c_int = 56; +pub const _SC_PII_OSI: ::c_int = 57; +pub const _SC_POLL: ::c_int = 58; +pub const _SC_SELECT: ::c_int = 59; +pub const _SC_PII_INTERNET_STREAM: ::c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: ::c_int = 62; +pub const _SC_PII_OSI_COTS: ::c_int = 63; +pub const _SC_PII_OSI_CLTS: ::c_int = 64; +pub const _SC_PII_OSI_M: ::c_int = 65; +pub const _SC_T_IOV_MAX: ::c_int = 66; +pub const _SC_2_C_VERSION: ::c_int = 96; +pub const _SC_CHAR_BIT: ::c_int = 101; +pub const _SC_CHAR_MAX: ::c_int = 102; +pub const _SC_CHAR_MIN: ::c_int = 103; +pub const _SC_INT_MAX: ::c_int = 104; +pub const _SC_INT_MIN: ::c_int = 105; +pub const _SC_LONG_BIT: ::c_int = 106; +pub const _SC_WORD_BIT: ::c_int = 107; +pub const _SC_MB_LEN_MAX: ::c_int = 108; +pub const _SC_SSIZE_MAX: ::c_int = 110; +pub const _SC_SCHAR_MAX: ::c_int = 111; +pub const _SC_SCHAR_MIN: ::c_int = 112; +pub const _SC_SHRT_MAX: ::c_int = 113; +pub const _SC_SHRT_MIN: ::c_int = 114; +pub const _SC_UCHAR_MAX: ::c_int = 115; +pub const _SC_UINT_MAX: ::c_int = 116; +pub const _SC_ULONG_MAX: ::c_int = 117; +pub const _SC_USHRT_MAX: ::c_int = 118; +pub const _SC_NL_ARGMAX: ::c_int = 119; +pub const _SC_NL_LANGMAX: ::c_int = 120; +pub const _SC_NL_MSGMAX: ::c_int = 121; +pub const _SC_NL_NMAX: ::c_int = 122; +pub const _SC_NL_SETMAX: ::c_int = 123; +pub const _SC_NL_TEXTMAX: ::c_int = 124; +pub const _SC_BASE: ::c_int = 134; +pub const _SC_C_LANG_SUPPORT: ::c_int = 135; +pub const _SC_C_LANG_SUPPORT_R: ::c_int = 136; +pub const _SC_DEVICE_IO: ::c_int = 140; +pub const _SC_DEVICE_SPECIFIC: ::c_int = 141; +pub const _SC_DEVICE_SPECIFIC_R: ::c_int = 142; +pub const _SC_FD_MGMT: ::c_int = 143; +pub const _SC_FIFO: ::c_int = 144; +pub const _SC_PIPE: ::c_int = 145; +pub const _SC_FILE_ATTRIBUTES: ::c_int = 146; +pub const _SC_FILE_LOCKING: ::c_int = 147; +pub const _SC_FILE_SYSTEM: ::c_int = 148; +pub const _SC_MULTI_PROCESS: ::c_int = 150; +pub const _SC_SINGLE_PROCESS: ::c_int = 151; +pub const _SC_NETWORKING: ::c_int = 152; +pub const _SC_REGEX_VERSION: ::c_int = 156; +pub const _SC_SIGNALS: ::c_int = 158; +pub const _SC_SYSTEM_DATABASE: ::c_int = 162; +pub const _SC_SYSTEM_DATABASE_R: ::c_int = 163; +pub const _SC_USER_GROUPS: ::c_int = 166; +pub const _SC_USER_GROUPS_R: ::c_int = 167; +pub const _SC_LEVEL1_ICACHE_SIZE: ::c_int = 185; +pub const _SC_LEVEL1_ICACHE_ASSOC: ::c_int = 186; +pub const _SC_LEVEL1_ICACHE_LINESIZE: ::c_int = 187; +pub const _SC_LEVEL1_DCACHE_SIZE: ::c_int = 188; +pub const _SC_LEVEL1_DCACHE_ASSOC: ::c_int = 189; +pub const _SC_LEVEL1_DCACHE_LINESIZE: ::c_int = 190; +pub const _SC_LEVEL2_CACHE_SIZE: ::c_int = 191; +pub const _SC_LEVEL2_CACHE_ASSOC: ::c_int = 192; +pub const _SC_LEVEL2_CACHE_LINESIZE: ::c_int = 193; +pub const _SC_LEVEL3_CACHE_SIZE: ::c_int = 194; +pub const _SC_LEVEL3_CACHE_ASSOC: ::c_int = 195; +pub const _SC_LEVEL3_CACHE_LINESIZE: ::c_int = 196; +pub const _SC_LEVEL4_CACHE_SIZE: ::c_int = 197; +pub const _SC_LEVEL4_CACHE_ASSOC: ::c_int = 198; +pub const _SC_LEVEL4_CACHE_LINESIZE: ::c_int = 199; +pub const O_ACCMODE: ::c_int = 3; +pub const O_DIRECT: ::c_int = 0x8000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const ST_RELATIME: ::c_ulong = 4096; +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const RLIMIT_NOFILE: ::c_int = 5; +pub const RLIMIT_AS: ::c_int = 6; +pub const RLIMIT_RSS: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 8; +pub const RLIMIT_MEMLOCK: ::c_int = 9; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 256; +pub const O_EXCL: ::c_int = 1024; +pub const O_NOCTTY: ::c_int = 2048; +pub const O_NONBLOCK: ::c_int = 128; +pub const O_SYNC: ::c_int = 0x4010; +pub const O_RSYNC: ::c_int = 0x4010; +pub const O_DSYNC: ::c_int = 0x10; +pub const O_FSYNC: ::c_int = 0x4010; +pub const O_ASYNC: ::c_int = 0x1000; +pub const O_NDELAY: ::c_int = 0x80; + +pub const SOCK_NONBLOCK: ::c_int = 128; + +pub const EDEADLK: ::c_int = 45; +pub const ENAMETOOLONG: ::c_int = 78; +pub const ENOLCK: ::c_int = 46; +pub const ENOSYS: ::c_int = 89; +pub const ENOTEMPTY: ::c_int = 93; +pub const ELOOP: ::c_int = 90; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const ECHRNG: ::c_int = 37; +pub const EL2NSYNC: ::c_int = 38; +pub const EL3HLT: ::c_int = 39; +pub const EL3RST: ::c_int = 40; +pub const ELNRNG: ::c_int = 41; +pub const EUNATCH: ::c_int = 42; +pub const ENOCSI: ::c_int = 43; +pub const EL2HLT: ::c_int = 44; +pub const EBADE: ::c_int = 50; +pub const EBADR: ::c_int = 51; +pub const EXFULL: ::c_int = 52; +pub const ENOANO: ::c_int = 53; +pub const EBADRQC: ::c_int = 54; +pub const EBADSLT: ::c_int = 55; +pub const EDEADLOCK: ::c_int = 56; +pub const EMULTIHOP: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 79; +pub const ENOTUNIQ: ::c_int = 80; +pub const EBADFD: ::c_int = 81; +pub const EBADMSG: ::c_int = 77; +pub const EREMCHG: ::c_int = 82; +pub const ELIBACC: ::c_int = 83; +pub const ELIBBAD: ::c_int = 84; +pub const ELIBSCN: ::c_int = 85; +pub const ELIBMAX: ::c_int = 86; +pub const ELIBEXEC: ::c_int = 87; +pub const EILSEQ: ::c_int = 88; +pub const ERESTART: ::c_int = 91; +pub const ESTRPIPE: ::c_int = 92; +pub const EUSERS: ::c_int = 94; +pub const ENOTSOCK: ::c_int = 95; +pub const EDESTADDRREQ: ::c_int = 96; +pub const EMSGSIZE: ::c_int = 97; +pub const EPROTOTYPE: ::c_int = 98; +pub const ENOPROTOOPT: ::c_int = 99; +pub const EPROTONOSUPPORT: ::c_int = 120; +pub const ESOCKTNOSUPPORT: ::c_int = 121; +pub const EOPNOTSUPP: ::c_int = 122; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 123; +pub const EAFNOSUPPORT: ::c_int = 124; +pub const EADDRINUSE: ::c_int = 125; +pub const EADDRNOTAVAIL: ::c_int = 126; +pub const ENETDOWN: ::c_int = 127; +pub const ENETUNREACH: ::c_int = 128; +pub const ENETRESET: ::c_int = 129; +pub const ECONNABORTED: ::c_int = 130; +pub const ECONNRESET: ::c_int = 131; +pub const ENOBUFS: ::c_int = 132; +pub const EISCONN: ::c_int = 133; +pub const ENOTCONN: ::c_int = 134; +pub const ESHUTDOWN: ::c_int = 143; +pub const ETOOMANYREFS: ::c_int = 144; +pub const ETIMEDOUT: ::c_int = 145; +pub const ECONNREFUSED: ::c_int = 146; +pub const EHOSTDOWN: ::c_int = 147; +pub const EHOSTUNREACH: ::c_int = 148; +pub const EALREADY: ::c_int = 149; +pub const EINPROGRESS: ::c_int = 150; +pub const ESTALE: ::c_int = 151; +pub const EUCLEAN: ::c_int = 135; +pub const ENOTNAM: ::c_int = 137; +pub const ENAVAIL: ::c_int = 138; +pub const EISNAM: ::c_int = 139; +pub const EREMOTEIO: ::c_int = 140; +pub const EDQUOT: ::c_int = 1133; +pub const ENOMEDIUM: ::c_int = 159; +pub const EMEDIUMTYPE: ::c_int = 160; +pub const ECANCELED: ::c_int = 158; +pub const ENOKEY: ::c_int = 161; +pub const EKEYEXPIRED: ::c_int = 162; +pub const EKEYREVOKED: ::c_int = 163; +pub const EKEYREJECTED: ::c_int = 164; +pub const EOWNERDEAD: ::c_int = 165; +pub const ENOTRECOVERABLE: ::c_int = 166; +pub const ERFKILL: ::c_int = 167; + +pub const LC_PAPER: ::c_int = 7; +pub const LC_NAME: ::c_int = 8; +pub const LC_ADDRESS: ::c_int = 9; +pub const LC_TELEPHONE: ::c_int = 10; +pub const LC_MEASUREMENT: ::c_int = 11; +pub const LC_IDENTIFICATION: ::c_int = 12; +pub const LC_PAPER_MASK: ::c_int = (1 << LC_PAPER); +pub const LC_NAME_MASK: ::c_int = (1 << LC_NAME); +pub const LC_ADDRESS_MASK: ::c_int = (1 << LC_ADDRESS); +pub const LC_TELEPHONE_MASK: ::c_int = (1 << LC_TELEPHONE); +pub const LC_MEASUREMENT_MASK: ::c_int = (1 << LC_MEASUREMENT); +pub const LC_IDENTIFICATION_MASK: ::c_int = (1 << LC_IDENTIFICATION); +pub const LC_ALL_MASK: ::c_int = ::LC_CTYPE_MASK + | ::LC_NUMERIC_MASK + | ::LC_TIME_MASK + | ::LC_COLLATE_MASK + | ::LC_MONETARY_MASK + | ::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const MAP_NORESERVE: ::c_int = 0x400; +pub const MAP_ANON: ::c_int = 0x800; +pub const MAP_ANONYMOUS: ::c_int = 0x800; +pub const MAP_GROWSDOWN: ::c_int = 0x1000; +pub const MAP_DENYWRITE: ::c_int = 0x2000; +pub const MAP_EXECUTABLE: ::c_int = 0x4000; +pub const MAP_LOCKED: ::c_int = 0x8000; +pub const MAP_POPULATE: ::c_int = 0x10000; +pub const MAP_NONBLOCK: ::c_int = 0x20000; +pub const MAP_STACK: ::c_int = 0x40000; + +pub const SOCK_STREAM: ::c_int = 2; +pub const SOCK_DGRAM: ::c_int = 1; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const SOCK_DCCP: ::c_int = 6; +pub const SOCK_PACKET: ::c_int = 10; + +pub const SOL_SOCKET: ::c_int = 0xffff; + +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_STYLE: ::c_int = SO_TYPE; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ACCEPTCONN: ::c_int = 0x1009; +pub const SO_PROTOCOL: ::c_int = 0x1028; +pub const SO_DOMAIN: ::c_int = 0x1029; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_PASSCRED: ::c_int = 17; +pub const SO_PEERCRED: ::c_int = 18; +pub const SO_SECURITY_AUTHENTICATION: ::c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: ::c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: ::c_int = 24; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_ATTACH_FILTER: ::c_int = 26; +pub const SO_DETACH_FILTER: ::c_int = 27; +pub const SO_GET_FILTER: ::c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: ::c_int = 28; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_PEERSEC: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 31; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PASSSEC: ::c_int = 34; +pub const SO_TIMESTAMPNS: ::c_int = 35; +pub const SCM_TIMESTAMPNS: ::c_int = SO_TIMESTAMPNS; +pub const SO_MARK: ::c_int = 36; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_WIFI_STATUS: ::c_int = 41; +pub const SCM_WIFI_STATUS: ::c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_NOFCS: ::c_int = 43; +pub const SO_LOCK_FILTER: ::c_int = 44; +pub const SO_SELECT_ERR_QUEUE: ::c_int = 45; +pub const SO_BUSY_POLL: ::c_int = 46; +pub const SO_MAX_PACING_RATE: ::c_int = 47; +pub const SO_BPF_EXTENSIONS: ::c_int = 48; +pub const SO_INCOMING_CPU: ::c_int = 49; +pub const SO_ATTACH_BPF: ::c_int = 50; +pub const SO_DETACH_BPF: ::c_int = SO_DETACH_FILTER; + +/* DCCP socket options */ +pub const DCCP_SOCKOPT_PACKET_SIZE: ::c_int = 1; +pub const DCCP_SOCKOPT_SERVICE: ::c_int = 2; +pub const DCCP_SOCKOPT_CHANGE_L: ::c_int = 3; +pub const DCCP_SOCKOPT_CHANGE_R: ::c_int = 4; +pub const DCCP_SOCKOPT_GET_CUR_MPS: ::c_int = 5; +pub const DCCP_SOCKOPT_SERVER_TIMEWAIT: ::c_int = 6; +pub const DCCP_SOCKOPT_SEND_CSCOV: ::c_int = 10; +pub const DCCP_SOCKOPT_RECV_CSCOV: ::c_int = 11; +pub const DCCP_SOCKOPT_AVAILABLE_CCIDS: ::c_int = 12; +pub const DCCP_SOCKOPT_CCID: ::c_int = 13; +pub const DCCP_SOCKOPT_TX_CCID: ::c_int = 14; +pub const DCCP_SOCKOPT_RX_CCID: ::c_int = 15; +pub const DCCP_SOCKOPT_QPOLICY_ID: ::c_int = 16; +pub const DCCP_SOCKOPT_QPOLICY_TXQLEN: ::c_int = 17; +pub const DCCP_SOCKOPT_CCID_RX_INFO: ::c_int = 128; +pub const DCCP_SOCKOPT_CCID_TX_INFO: ::c_int = 192; + +/// maximum number of services provided on the same listening port +pub const DCCP_SERVICE_LIST_MAX_LEN: ::c_int = 32; + +pub const FIOCLEX: ::c_ulong = 0x6601; +pub const FIONBIO: ::c_ulong = 0x667e; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000008; +pub const SA_NOCLDWAIT: ::c_int = 0x00010000; + +pub const SIGCHLD: ::c_int = 18; +pub const SIGBUS: ::c_int = 10; +pub const SIGTTIN: ::c_int = 26; +pub const SIGTTOU: ::c_int = 27; +pub const SIGXCPU: ::c_int = 30; +pub const SIGXFSZ: ::c_int = 31; +pub const SIGVTALRM: ::c_int = 28; +pub const SIGPROF: ::c_int = 29; +pub const SIGWINCH: ::c_int = 20; +pub const SIGUSR1: ::c_int = 16; +pub const SIGUSR2: ::c_int = 17; +pub const SIGCONT: ::c_int = 25; +pub const SIGSTOP: ::c_int = 23; +pub const SIGTSTP: ::c_int = 24; +pub const SIGURG: ::c_int = 21; +pub const SIGIO: ::c_int = 22; +pub const SIGSYS: ::c_int = 12; +pub const SIGPOLL: ::c_int = 22; +pub const SIGPWR: ::c_int = 19; +pub const SIG_SETMASK: ::c_int = 3; +pub const SIG_BLOCK: ::c_int = 0x1; +pub const SIG_UNBLOCK: ::c_int = 0x2; + +pub const POLLWRNORM: ::c_short = 0x004; +pub const POLLWRBAND: ::c_short = 0x100; + +pub const PTHREAD_STACK_MIN: ::size_t = 131072; +pub const PTHREAD_MUTEX_ADAPTIVE_NP: ::c_int = 3; + +pub const ADFS_SUPER_MAGIC: ::c_long = 0x0000adf5; +pub const AFFS_SUPER_MAGIC: ::c_long = 0x0000adff; +pub const CODA_SUPER_MAGIC: ::c_long = 0x73757245; +pub const CRAMFS_MAGIC: ::c_long = 0x28cd3d45; +pub const EFS_SUPER_MAGIC: ::c_long = 0x00414a53; +pub const EXT2_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT3_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT4_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const HPFS_SUPER_MAGIC: ::c_long = 0xf995e849; +pub const HUGETLBFS_MAGIC: ::c_long = 0x958458f6; +pub const ISOFS_SUPER_MAGIC: ::c_long = 0x00009660; +pub const JFFS2_SUPER_MAGIC: ::c_long = 0x000072b6; +pub const MINIX_SUPER_MAGIC: ::c_long = 0x0000137f; +pub const MINIX_SUPER_MAGIC2: ::c_long = 0x0000138f; +pub const MINIX2_SUPER_MAGIC: ::c_long = 0x00002468; +pub const MINIX2_SUPER_MAGIC2: ::c_long = 0x00002478; +pub const MSDOS_SUPER_MAGIC: ::c_long = 0x00004d44; +pub const NCP_SUPER_MAGIC: ::c_long = 0x0000564c; +pub const NFS_SUPER_MAGIC: ::c_long = 0x00006969; +pub const OPENPROM_SUPER_MAGIC: ::c_long = 0x00009fa1; +pub const PROC_SUPER_MAGIC: ::c_long = 0x00009fa0; +pub const QNX4_SUPER_MAGIC: ::c_long = 0x0000002f; +pub const REISERFS_SUPER_MAGIC: ::c_long = 0x52654973; +pub const SMB_SUPER_MAGIC: ::c_long = 0x0000517b; +pub const TMPFS_MAGIC: ::c_long = 0x01021994; +pub const USBDEVICE_SUPER_MAGIC: ::c_long = 0x00009fa2; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: ::tcflag_t = 0x00000100; +pub const TOSTOP: ::tcflag_t = 0x00008000; +pub const FLUSHO: ::tcflag_t = 0x00002000; +pub const EXTPROC: ::tcflag_t = 0o200000; +pub const TCSANOW: ::c_int = 0x540e; +pub const TCSADRAIN: ::c_int = 0x540f; +pub const TCSAFLUSH: ::c_int = 0x5410; + +pub const CPU_SETSIZE: ::c_int = 0x400; + +pub const PTRACE_TRACEME: ::c_uint = 0; +pub const PTRACE_PEEKTEXT: ::c_uint = 1; +pub const PTRACE_PEEKDATA: ::c_uint = 2; +pub const PTRACE_PEEKUSER: ::c_uint = 3; +pub const PTRACE_POKETEXT: ::c_uint = 4; +pub const PTRACE_POKEDATA: ::c_uint = 5; +pub const PTRACE_POKEUSER: ::c_uint = 6; +pub const PTRACE_CONT: ::c_uint = 7; +pub const PTRACE_KILL: ::c_uint = 8; +pub const PTRACE_SINGLESTEP: ::c_uint = 9; +pub const PTRACE_ATTACH: ::c_uint = 16; +pub const PTRACE_DETACH: ::c_uint = 17; +pub const PTRACE_SYSCALL: ::c_uint = 24; +pub const PTRACE_SETOPTIONS: ::c_uint = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_uint = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_uint = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_uint = 0x4203; +pub const PTRACE_GETFPREGS: ::c_uint = 14; +pub const PTRACE_SETFPREGS: ::c_uint = 15; +pub const PTRACE_GETFPXREGS: ::c_uint = 18; +pub const PTRACE_SETFPXREGS: ::c_uint = 19; +pub const PTRACE_GETREGS: ::c_uint = 12; +pub const PTRACE_SETREGS: ::c_uint = 13; + +pub const MAP_HUGETLB: ::c_int = 0x080000; + +pub const EFD_NONBLOCK: ::c_int = 0x80; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; +pub const F_GETLK: ::c_int = 14; +pub const F_GETOWN: ::c_int = 23; +pub const F_SETOWN: ::c_int = 24; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const SFD_NONBLOCK: ::c_int = 0x80; + +pub const TCGETS: ::c_ulong = 0x540d; +pub const TCSETS: ::c_ulong = 0x540e; +pub const TCSETSW: ::c_ulong = 0x540f; +pub const TCSETSF: ::c_ulong = 0x5410; +pub const TCGETA: ::c_ulong = 0x5401; +pub const TCSETA: ::c_ulong = 0x5402; +pub const TCSETAW: ::c_ulong = 0x5403; +pub const TCSETAF: ::c_ulong = 0x5404; +pub const TCSBRK: ::c_ulong = 0x5405; +pub const TCXONC: ::c_ulong = 0x5406; +pub const TCFLSH: ::c_ulong = 0x5407; +pub const TIOCGSOFTCAR: ::c_ulong = 0x5481; +pub const TIOCSSOFTCAR: ::c_ulong = 0x5482; +pub const TIOCINQ: ::c_ulong = 0x467f; +pub const TIOCLINUX: ::c_ulong = 0x5483; +pub const TIOCGSERIAL: ::c_ulong = 0x5484; +pub const TIOCEXCL: ::c_ulong = 0x740d; +pub const TIOCNXCL: ::c_ulong = 0x740e; +pub const TIOCSCTTY: ::c_ulong = 0x5480; +pub const TIOCGPGRP: ::c_ulong = 0x40047477; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCOUTQ: ::c_ulong = 0x7472; +pub const TIOCSTI: ::c_ulong = 0x5472; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const TIOCMGET: ::c_ulong = 0x741d; +pub const TIOCMBIS: ::c_ulong = 0x741b; +pub const TIOCMBIC: ::c_ulong = 0x741c; +pub const TIOCMSET: ::c_ulong = 0x741a; +pub const FIONREAD: ::c_ulong = 0x467f; +pub const TIOCCONS: ::c_ulong = 0x80047478; + +pub const RTLD_DEEPBIND: ::c_int = 0x10; +pub const RTLD_GLOBAL: ::c_int = 0x4; +pub const RTLD_NOLOAD: ::c_int = 0x8; + +pub const LINUX_REBOOT_MAGIC1: ::c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: ::c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: ::c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: ::c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: ::c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: ::c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: ::c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: ::c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: ::c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: ::c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x010; +pub const TIOCM_SR: ::c_int = 0x020; +pub const TIOCM_CTS: ::c_int = 0x040; +pub const TIOCM_CAR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RNG: ::c_int = 0x200; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; +pub const TIOCM_DSR: ::c_int = 0x400; + +pub const EHWPOISON: ::c_int = 168; +pub const SIGEV_THREAD_ID: ::c_int = 4; +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const NF_NETDEV_INGRESS: ::c_int = 0; +pub const NF_NETDEV_NUMHOOKS: ::c_int = 1; + +pub const NFPROTO_INET: ::c_int = 1; +pub const NFPROTO_NETDEV: ::c_int = 5; + +pub const NLA_ALIGNTO: ::c_int = 4; + +pub const GENL_UNS_ADMIN_PERM: ::c_int = 0x10; + +pub const GENL_ID_VFS_DQUOT: ::c_int = ::NLMSG_MIN_TYPE + 1; +pub const GENL_ID_PMCRAID: ::c_int = ::NLMSG_MIN_TYPE + 2; + +pub const NFT_TABLE_MAXNAMELEN: ::c_int = 256; +pub const NFT_CHAIN_MAXNAMELEN: ::c_int = 256; +pub const NFT_SET_MAXNAMELEN: ::c_int = 256; +pub const NFT_OBJ_MAXNAMELEN: ::c_int = 256; +pub const NFT_USERDATA_MAXLEN: ::c_int = 256; + +pub const NFT_REG_VERDICT: ::c_int = 0; +pub const NFT_REG_1: ::c_int = 1; +pub const NFT_REG_2: ::c_int = 2; +pub const NFT_REG_3: ::c_int = 3; +pub const NFT_REG_4: ::c_int = 4; +pub const __NFT_REG_MAX: ::c_int = 5; +pub const NFT_REG32_00: ::c_int = 8; +pub const NFT_REG32_01: ::c_int = 9; +pub const NFT_REG32_02: ::c_int = 10; +pub const NFT_REG32_03: ::c_int = 11; +pub const NFT_REG32_04: ::c_int = 12; +pub const NFT_REG32_05: ::c_int = 13; +pub const NFT_REG32_06: ::c_int = 14; +pub const NFT_REG32_07: ::c_int = 15; +pub const NFT_REG32_08: ::c_int = 16; +pub const NFT_REG32_09: ::c_int = 17; +pub const NFT_REG32_10: ::c_int = 18; +pub const NFT_REG32_11: ::c_int = 19; +pub const NFT_REG32_12: ::c_int = 20; +pub const NFT_REG32_13: ::c_int = 21; +pub const NFT_REG32_14: ::c_int = 22; +pub const NFT_REG32_15: ::c_int = 23; + +pub const NFT_REG_SIZE: ::c_int = 16; +pub const NFT_REG32_SIZE: ::c_int = 4; + +pub const NFT_CONTINUE: ::c_int = -1; +pub const NFT_BREAK: ::c_int = -2; +pub const NFT_JUMP: ::c_int = -3; +pub const NFT_GOTO: ::c_int = -4; +pub const NFT_RETURN: ::c_int = -5; + +pub const NFT_MSG_NEWTABLE: ::c_int = 0; +pub const NFT_MSG_GETTABLE: ::c_int = 1; +pub const NFT_MSG_DELTABLE: ::c_int = 2; +pub const NFT_MSG_NEWCHAIN: ::c_int = 3; +pub const NFT_MSG_GETCHAIN: ::c_int = 4; +pub const NFT_MSG_DELCHAIN: ::c_int = 5; +pub const NFT_MSG_NEWRULE: ::c_int = 6; +pub const NFT_MSG_GETRULE: ::c_int = 7; +pub const NFT_MSG_DELRULE: ::c_int = 8; +pub const NFT_MSG_NEWSET: ::c_int = 9; +pub const NFT_MSG_GETSET: ::c_int = 10; +pub const NFT_MSG_DELSET: ::c_int = 11; +pub const NFT_MSG_NEWSETELEM: ::c_int = 12; +pub const NFT_MSG_GETSETELEM: ::c_int = 13; +pub const NFT_MSG_DELSETELEM: ::c_int = 14; +pub const NFT_MSG_NEWGEN: ::c_int = 15; +pub const NFT_MSG_GETGEN: ::c_int = 16; +pub const NFT_MSG_TRACE: ::c_int = 17; +pub const NFT_MSG_NEWOBJ: ::c_int = 18; +pub const NFT_MSG_GETOBJ: ::c_int = 19; +pub const NFT_MSG_DELOBJ: ::c_int = 20; +pub const NFT_MSG_GETOBJ_RESET: ::c_int = 21; +pub const NFT_MSG_MAX: ::c_int = 25; + +pub const NFT_SET_ANONYMOUS: ::c_int = 0x1; +pub const NFT_SET_CONSTANT: ::c_int = 0x2; +pub const NFT_SET_INTERVAL: ::c_int = 0x4; +pub const NFT_SET_MAP: ::c_int = 0x8; +pub const NFT_SET_TIMEOUT: ::c_int = 0x10; +pub const NFT_SET_EVAL: ::c_int = 0x20; + +pub const NFT_SET_POL_PERFORMANCE: ::c_int = 0; +pub const NFT_SET_POL_MEMORY: ::c_int = 1; + +pub const NFT_SET_ELEM_INTERVAL_END: ::c_int = 0x1; + +pub const NFT_DATA_VALUE: ::c_uint = 0; +pub const NFT_DATA_VERDICT: ::c_uint = 0xffffff00; + +pub const NFT_DATA_RESERVED_MASK: ::c_uint = 0xffffff00; + +pub const NFT_DATA_VALUE_MAXLEN: ::c_int = 64; + +pub const NFT_BYTEORDER_NTOH: ::c_int = 0; +pub const NFT_BYTEORDER_HTON: ::c_int = 1; + +pub const NFT_CMP_EQ: ::c_int = 0; +pub const NFT_CMP_NEQ: ::c_int = 1; +pub const NFT_CMP_LT: ::c_int = 2; +pub const NFT_CMP_LTE: ::c_int = 3; +pub const NFT_CMP_GT: ::c_int = 4; +pub const NFT_CMP_GTE: ::c_int = 5; + +pub const NFT_RANGE_EQ: ::c_int = 0; +pub const NFT_RANGE_NEQ: ::c_int = 1; + +pub const NFT_LOOKUP_F_INV: ::c_int = (1 << 0); + +pub const NFT_DYNSET_OP_ADD: ::c_int = 0; +pub const NFT_DYNSET_OP_UPDATE: ::c_int = 1; + +pub const NFT_DYNSET_F_INV: ::c_int = (1 << 0); + +pub const NFT_PAYLOAD_LL_HEADER: ::c_int = 0; +pub const NFT_PAYLOAD_NETWORK_HEADER: ::c_int = 1; +pub const NFT_PAYLOAD_TRANSPORT_HEADER: ::c_int = 2; + +pub const NFT_PAYLOAD_CSUM_NONE: ::c_int = 0; +pub const NFT_PAYLOAD_CSUM_INET: ::c_int = 1; + +pub const NFT_META_LEN: ::c_int = 0; +pub const NFT_META_PROTOCOL: ::c_int = 1; +pub const NFT_META_PRIORITY: ::c_int = 2; +pub const NFT_META_MARK: ::c_int = 3; +pub const NFT_META_IIF: ::c_int = 4; +pub const NFT_META_OIF: ::c_int = 5; +pub const NFT_META_IIFNAME: ::c_int = 6; +pub const NFT_META_OIFNAME: ::c_int = 7; +pub const NFT_META_IIFTYPE: ::c_int = 8; +pub const NFT_META_OIFTYPE: ::c_int = 9; +pub const NFT_META_SKUID: ::c_int = 10; +pub const NFT_META_SKGID: ::c_int = 11; +pub const NFT_META_NFTRACE: ::c_int = 12; +pub const NFT_META_RTCLASSID: ::c_int = 13; +pub const NFT_META_SECMARK: ::c_int = 14; +pub const NFT_META_NFPROTO: ::c_int = 15; +pub const NFT_META_L4PROTO: ::c_int = 16; +pub const NFT_META_BRI_IIFNAME: ::c_int = 17; +pub const NFT_META_BRI_OIFNAME: ::c_int = 18; +pub const NFT_META_PKTTYPE: ::c_int = 19; +pub const NFT_META_CPU: ::c_int = 20; +pub const NFT_META_IIFGROUP: ::c_int = 21; +pub const NFT_META_OIFGROUP: ::c_int = 22; +pub const NFT_META_CGROUP: ::c_int = 23; +pub const NFT_META_PRANDOM: ::c_int = 24; + +pub const NFT_CT_STATE: ::c_int = 0; +pub const NFT_CT_DIRECTION: ::c_int = 1; +pub const NFT_CT_STATUS: ::c_int = 2; +pub const NFT_CT_MARK: ::c_int = 3; +pub const NFT_CT_SECMARK: ::c_int = 4; +pub const NFT_CT_EXPIRATION: ::c_int = 5; +pub const NFT_CT_HELPER: ::c_int = 6; +pub const NFT_CT_L3PROTOCOL: ::c_int = 7; +pub const NFT_CT_SRC: ::c_int = 8; +pub const NFT_CT_DST: ::c_int = 9; +pub const NFT_CT_PROTOCOL: ::c_int = 10; +pub const NFT_CT_PROTO_SRC: ::c_int = 11; +pub const NFT_CT_PROTO_DST: ::c_int = 12; +pub const NFT_CT_LABELS: ::c_int = 13; +pub const NFT_CT_PKTS: ::c_int = 14; +pub const NFT_CT_BYTES: ::c_int = 15; + +pub const NFT_LIMIT_PKTS: ::c_int = 0; +pub const NFT_LIMIT_PKT_BYTES: ::c_int = 1; + +pub const NFT_LIMIT_F_INV: ::c_int = (1 << 0); + +pub const NFT_QUEUE_FLAG_BYPASS: ::c_int = 0x01; +pub const NFT_QUEUE_FLAG_CPU_FANOUT: ::c_int = 0x02; +pub const NFT_QUEUE_FLAG_MASK: ::c_int = 0x03; + +pub const NFT_QUOTA_F_INV: ::c_int = (1 << 0); + +pub const NFT_REJECT_ICMP_UNREACH: ::c_int = 0; +pub const NFT_REJECT_TCP_RST: ::c_int = 1; +pub const NFT_REJECT_ICMPX_UNREACH: ::c_int = 2; + +pub const NFT_REJECT_ICMPX_NO_ROUTE: ::c_int = 0; +pub const NFT_REJECT_ICMPX_PORT_UNREACH: ::c_int = 1; +pub const NFT_REJECT_ICMPX_HOST_UNREACH: ::c_int = 2; +pub const NFT_REJECT_ICMPX_ADMIN_PROHIBITED: ::c_int = 3; + +pub const NFT_NAT_SNAT: ::c_int = 0; +pub const NFT_NAT_DNAT: ::c_int = 1; + +pub const NFT_TRACETYPE_UNSPEC: ::c_int = 0; +pub const NFT_TRACETYPE_POLICY: ::c_int = 1; +pub const NFT_TRACETYPE_RETURN: ::c_int = 2; +pub const NFT_TRACETYPE_RULE: ::c_int = 3; + +pub const NFT_NG_INCREMENTAL: ::c_int = 0; +pub const NFT_NG_RANDOM: ::c_int = 1; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +f! { + pub fn NLA_ALIGN(len: ::c_int) -> ::c_int { + return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) + } +} + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn backtrace(buf: *mut *mut ::c_void, + sz: ::c_int) -> ::c_int; + pub fn glob64(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut glob64_t) -> ::c_int; + pub fn globfree64(pglob: *mut glob64_t); + pub fn ptrace(request: ::c_uint, ...) -> ::c_long; + pub fn pthread_attr_getaffinity_np(attr: *const ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_attr_setaffinity_np(attr: *mut ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn getpriority(which: ::__priority_which_t, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::__priority_which_t, who: ::id_t, + prio: ::c_int) -> ::c_int; + pub fn pthread_getaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_setaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn sched_getcpu() -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "mips")] { + mod mips32; + pub use self::mips32::*; + } else if #[cfg(target_arch = "mips64")] { + mod mips64; + pub use self::mips64::*; + } else { + // Unknown target_arch + } +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/notbsd/linux/mips/no_align.rs b/libc/src/unix/notbsd/linux/mips/no_align.rs new file mode 100644 index 000000000..e32bf673d --- /dev/null +++ b/libc/src/unix/notbsd/linux/mips/no_align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} diff --git a/libc/src/unix/notbsd/linux/mod.rs b/libc/src/unix/notbsd/linux/mod.rs new file mode 100644 index 000000000..2419a41d4 --- /dev/null +++ b/libc/src/unix/notbsd/linux/mod.rs @@ -0,0 +1,2489 @@ +//! Linux-specific definitions for linux-like values + +pub type useconds_t = u32; +pub type dev_t = u64; +pub type socklen_t = u32; +pub type pthread_t = c_ulong; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type mqd_t = ::c_int; +pub type nfds_t = ::c_ulong; +pub type nl_item = ::c_int; +pub type idtype_t = ::c_uint; +pub type loff_t = ::c_longlong; + +pub type __u8 = ::c_uchar; +pub type __u16 = ::c_ushort; +pub type __s16 = ::c_short; +pub type __u32 = ::c_uint; +pub type __s32 = ::c_int; + +pub type Elf32_Half = u16; +pub type Elf32_Word = u32; +pub type Elf32_Off = u32; +pub type Elf32_Addr = u32; + +pub type Elf64_Half = u16; +pub type Elf64_Word = u32; +pub type Elf64_Off = u64; +pub type Elf64_Addr = u64; +pub type Elf64_Xword = u64; +pub type Elf64_Sxword = i64; + +pub type Elf32_Section = u16; +pub type Elf64_Section = u16; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos64_t {} // TODO: fill this out with a struct +impl ::Copy for fpos64_t {} +impl ::Clone for fpos64_t { + fn clone(&self) -> fpos64_t { *self } +} + +s! { + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct spwd { + pub sp_namp: *mut ::c_char, + pub sp_pwdp: *mut ::c_char, + pub sp_lstchg: ::c_long, + pub sp_min: ::c_long, + pub sp_max: ::c_long, + pub sp_warn: ::c_long, + pub sp_inact: ::c_long, + pub sp_expire: ::c_long, + pub sp_flag: ::c_ulong, + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint64_t, + pub dqb_bsoftlimit: ::uint64_t, + pub dqb_curspace: ::uint64_t, + pub dqb_ihardlimit: ::uint64_t, + pub dqb_isoftlimit: ::uint64_t, + pub dqb_curinodes: ::uint64_t, + pub dqb_btime: ::uint64_t, + pub dqb_itime: ::uint64_t, + pub dqb_valid: ::uint32_t, + } + + pub struct signalfd_siginfo { + pub ssi_signo: ::uint32_t, + pub ssi_errno: ::int32_t, + pub ssi_code: ::int32_t, + pub ssi_pid: ::uint32_t, + pub ssi_uid: ::uint32_t, + pub ssi_fd: ::int32_t, + pub ssi_tid: ::uint32_t, + pub ssi_band: ::uint32_t, + pub ssi_overrun: ::uint32_t, + pub ssi_trapno: ::uint32_t, + pub ssi_status: ::int32_t, + pub ssi_int: ::int32_t, + pub ssi_ptr: ::uint64_t, + pub ssi_utime: ::uint64_t, + pub ssi_stime: ::uint64_t, + pub ssi_addr: ::uint64_t, + pub ssi_addr_lsb: ::uint16_t, + _pad2: ::uint16_t, + pub ssi_syscall: ::int32_t, + pub ssi_call_addr: ::uint64_t, + pub ssi_arch: ::uint32_t, + _pad: [::uint8_t; 28], + } + + pub struct itimerspec { + pub it_interval: ::timespec, + pub it_value: ::timespec, + } + + pub struct fsid_t { + __val: [::c_int; 2], + } + + // x32 compatibility + // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279 + pub struct mq_attr { + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_flags: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_maxmsg: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_msgsize: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pub mq_curmsgs: i64, + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + pad: [i64; 4], + + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_flags: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_maxmsg: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_msgsize: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pub mq_curmsgs: ::c_long, + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + pad: [::c_long; 4], + } + + pub struct packet_mreq { + pub mr_ifindex: ::c_int, + pub mr_type: ::c_ushort, + pub mr_alen: ::c_ushort, + pub mr_address: [::c_uchar; 8], + } + + pub struct cpu_set_t { + #[cfg(all(target_pointer_width = "32", + not(target_arch = "x86_64")))] + bits: [u32; 32], + #[cfg(not(all(target_pointer_width = "32", + not(target_arch = "x86_64"))))] + bits: [u64; 16], + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: ::c_int, + pub msgmap: ::c_int, + pub msgmax: ::c_int, + pub msgmnb: ::c_int, + pub msgmni: ::c_int, + pub msgssz: ::c_int, + pub msgtql: ::c_int, + pub msgseg: ::c_ushort, + } + + pub struct sembuf { + pub sem_num: ::c_ushort, + pub sem_op: ::c_short, + pub sem_flg: ::c_short, + } + + pub struct input_event { + pub time: ::timeval, + pub type_: ::__u16, + pub code: ::__u16, + pub value: ::__s32, + } + + pub struct input_id { + pub bustype: ::__u16, + pub vendor: ::__u16, + pub product: ::__u16, + pub version: ::__u16, + } + + pub struct input_absinfo { + pub value: ::__s32, + pub minimum: ::__s32, + pub maximum: ::__s32, + pub fuzz: ::__s32, + pub flat: ::__s32, + pub resolution: ::__s32, + } + + pub struct input_keymap_entry { + pub flags: ::__u8, + pub len: ::__u8, + pub index: ::__u16, + pub keycode: ::__u32, + pub scancode: [::__u8; 32], + } + + pub struct input_mask { + pub type_: ::__u32, + pub codes_size: ::__u32, + pub codes_ptr: ::__u64, + } + + pub struct ff_replay { + pub length: ::__u16, + pub delay: ::__u16, + } + + pub struct ff_trigger { + pub button: ::__u16, + pub interval: ::__u16, + } + + pub struct ff_envelope { + pub attack_length: ::__u16, + pub attack_level: ::__u16, + pub fade_length: ::__u16, + pub fade_level: ::__u16, + } + + pub struct ff_constant_effect { + pub level: ::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_ramp_effect { + pub start_level: ::__s16, + pub end_level: ::__s16, + pub envelope: ff_envelope, + } + + pub struct ff_condition_effect { + pub right_saturation: ::__u16, + pub left_saturation: ::__u16, + + pub right_coeff: ::__s16, + pub left_coeff: ::__s16, + + pub deadband: ::__u16, + pub center: ::__s16, + } + + pub struct ff_periodic_effect { + pub waveform: ::__u16, + pub period: ::__u16, + pub magnitude: ::__s16, + pub offset: ::__s16, + pub phase: ::__u16, + + pub envelope: ff_envelope, + + pub custom_len: ::__u32, + pub custom_data: *mut ::__s16, + } + + pub struct ff_rumble_effect { + pub strong_magnitude: ::__u16, + pub weak_magnitude: ::__u16, + } + + pub struct ff_effect { + pub type_: ::__u16, + pub id: ::__s16, + pub direction: ::__u16, + pub trigger: ff_trigger, + pub replay: ff_replay, + // FIXME this is actually a union + #[cfg(target_pointer_width = "64")] + pub u: [u64; 4], + #[cfg(target_pointer_width = "32")] + pub u: [u32; 7], + } + + pub struct dl_phdr_info { + #[cfg(target_pointer_width = "64")] + pub dlpi_addr: Elf64_Addr, + #[cfg(target_pointer_width = "32")] + pub dlpi_addr: Elf32_Addr, + + pub dlpi_name: *const ::c_char, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phdr: *const Elf64_Phdr, + #[cfg(target_pointer_width = "32")] + pub dlpi_phdr: *const Elf32_Phdr, + + #[cfg(target_pointer_width = "64")] + pub dlpi_phnum: Elf64_Half, + #[cfg(target_pointer_width = "32")] + pub dlpi_phnum: Elf32_Half, + + pub dlpi_adds: ::c_ulonglong, + pub dlpi_subs: ::c_ulonglong, + pub dlpi_tls_modid: ::size_t, + pub dlpi_tls_data: *mut ::c_void, + } + + pub struct Elf32_Ehdr { + pub e_ident: [::c_uchar; 16], + pub e_type: Elf32_Half, + pub e_machine: Elf32_Half, + pub e_version: Elf32_Word, + pub e_entry: Elf32_Addr, + pub e_phoff: Elf32_Off, + pub e_shoff: Elf32_Off, + pub e_flags: Elf32_Word, + pub e_ehsize: Elf32_Half, + pub e_phentsize: Elf32_Half, + pub e_phnum: Elf32_Half, + pub e_shentsize: Elf32_Half, + pub e_shnum: Elf32_Half, + pub e_shstrndx: Elf32_Half, + } + + pub struct Elf64_Ehdr { + pub e_ident: [::c_uchar; 16], + pub e_type: Elf64_Half, + pub e_machine: Elf64_Half, + pub e_version: Elf64_Word, + pub e_entry: Elf64_Addr, + pub e_phoff: Elf64_Off, + pub e_shoff: Elf64_Off, + pub e_flags: Elf64_Word, + pub e_ehsize: Elf64_Half, + pub e_phentsize: Elf64_Half, + pub e_phnum: Elf64_Half, + pub e_shentsize: Elf64_Half, + pub e_shnum: Elf64_Half, + pub e_shstrndx: Elf64_Half, + } + + pub struct Elf32_Sym { + pub st_name: Elf32_Word, + pub st_value: Elf32_Addr, + pub st_size: Elf32_Word, + pub st_info: ::c_uchar, + pub st_other: ::c_uchar, + pub st_shndx: Elf32_Section, + } + + pub struct Elf64_Sym { + pub st_name: Elf64_Word, + pub st_info: ::c_uchar, + pub st_other: ::c_uchar, + pub st_shndx: Elf64_Section, + pub st_value: Elf64_Addr, + pub st_size: Elf64_Xword, + } + + pub struct Elf32_Phdr { + pub p_type: Elf32_Word, + pub p_offset: Elf32_Off, + pub p_vaddr: Elf32_Addr, + pub p_paddr: Elf32_Addr, + pub p_filesz: Elf32_Word, + pub p_memsz: Elf32_Word, + pub p_flags: Elf32_Word, + pub p_align: Elf32_Word, + } + + pub struct Elf64_Phdr { + pub p_type: Elf64_Word, + pub p_flags: Elf64_Word, + pub p_offset: Elf64_Off, + pub p_vaddr: Elf64_Addr, + pub p_paddr: Elf64_Addr, + pub p_filesz: Elf64_Xword, + pub p_memsz: Elf64_Xword, + pub p_align: Elf64_Xword, + } + + pub struct Elf32_Shdr { + pub sh_name: Elf32_Word, + pub sh_type: Elf32_Word, + pub sh_flags: Elf32_Word, + pub sh_addr: Elf32_Addr, + pub sh_offset: Elf32_Off, + pub sh_size: Elf32_Word, + pub sh_link: Elf32_Word, + pub sh_info: Elf32_Word, + pub sh_addralign: Elf32_Word, + pub sh_entsize: Elf32_Word, + } + + pub struct Elf64_Shdr { + pub sh_name: Elf64_Word, + pub sh_type: Elf64_Word, + pub sh_flags: Elf64_Xword, + pub sh_addr: Elf64_Addr, + pub sh_offset: Elf64_Off, + pub sh_size: Elf64_Xword, + pub sh_link: Elf64_Word, + pub sh_info: Elf64_Word, + pub sh_addralign: Elf64_Xword, + pub sh_entsize: Elf64_Xword, + } + + pub struct Elf32_Chdr { + pub ch_type: Elf32_Word, + pub ch_size: Elf32_Word, + pub ch_addralign: Elf32_Word, + } + + pub struct Elf64_Chdr { + pub ch_type: Elf64_Word, + pub ch_reserved: Elf64_Word, + pub ch_size: Elf64_Xword, + pub ch_addralign: Elf64_Xword, + } + + pub struct ucred { + pub pid: ::pid_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + } + + pub struct mntent { + pub mnt_fsname: *mut ::c_char, + pub mnt_dir: *mut ::c_char, + pub mnt_type: *mut ::c_char, + pub mnt_opts: *mut ::c_char, + pub mnt_freq: ::c_int, + pub mnt_passno: ::c_int, + } + + pub struct posix_spawn_file_actions_t { + __allocated: ::c_int, + __used: ::c_int, + __actions: *mut ::c_int, + __pad: [::c_int; 16], + } + + pub struct posix_spawnattr_t { + __flags: ::c_short, + __pgrp: ::pid_t, + __sd: ::sigset_t, + __ss: ::sigset_t, + #[cfg(target_env = "musl")] + __prio: ::c_int, + #[cfg(not(target_env = "musl"))] + __sp: ::sched_param, + __policy: ::c_int, + __pad: [::c_int; 16], + } + + pub struct genlmsghdr { + pub cmd: u8, + pub version: u8, + pub reserved: u16, + } + + pub struct in6_pktinfo { + pub ipi6_addr: ::in6_addr, + pub ipi6_ifindex: ::c_uint, + } + + pub struct arpd_request { + pub req: ::c_ushort, + pub ip: u32, + pub dev: ::c_ulong, + pub stamp: ::c_ulong, + pub updated: ::c_ulong, + pub ha: [::c_uchar; ::MAX_ADDR_LEN], + } + + pub struct inotify_event { + pub wd: ::c_int, + pub mask: ::uint32_t, + pub cookie: ::uint32_t, + pub len: ::uint32_t + } +} + +s_no_extra_traits!{ + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct dirent64 { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct sockaddr_alg { + pub salg_family: ::sa_family_t, + pub salg_type: [::c_uchar; 14], + pub salg_feat: u32, + pub salg_mask: u32, + pub salg_name: [::c_uchar; 64], + } + + pub struct af_alg_iv { + pub ivlen: u32, + pub iv: [::c_uchar; 0], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for dirent { + fn eq(&self, other: &dirent) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for dirent {} + + impl ::fmt::Debug for dirent { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + + impl ::hash::Hash for dirent { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for dirent64 { + fn eq(&self, other: &dirent64) -> bool { + self.d_ino == other.d_ino + && self.d_off == other.d_off + && self.d_reclen == other.d_reclen + && self.d_type == other.d_type + && self + .d_name + .iter() + .zip(other.d_name.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for dirent64 {} + + impl ::fmt::Debug for dirent64 { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("dirent64") + .field("d_ino", &self.d_ino) + .field("d_off", &self.d_off) + .field("d_reclen", &self.d_reclen) + .field("d_type", &self.d_type) + // FIXME: .field("d_name", &self.d_name) + .finish() + } + } + + impl ::hash::Hash for dirent64 { + fn hash(&self, state: &mut H) { + self.d_ino.hash(state); + self.d_off.hash(state); + self.d_reclen.hash(state); + self.d_type.hash(state); + self.d_name.hash(state); + } + } + + impl PartialEq for pthread_cond_t { + fn eq(&self, other: &pthread_cond_t) -> bool { + self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b) + } + } + + impl Eq for pthread_cond_t {} + + impl ::fmt::Debug for pthread_cond_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_cond_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + + impl ::hash::Hash for pthread_cond_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + + impl PartialEq for pthread_mutex_t { + fn eq(&self, other: &pthread_mutex_t) -> bool { + self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b) + } + } + + impl Eq for pthread_mutex_t {} + + impl ::fmt::Debug for pthread_mutex_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_mutex_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + + impl ::hash::Hash for pthread_mutex_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + + impl PartialEq for pthread_rwlock_t { + fn eq(&self, other: &pthread_rwlock_t) -> bool { + self.size.iter().zip(other.size.iter()).all(|(a,b)| a == b) + } + } + + impl Eq for pthread_rwlock_t {} + + impl ::fmt::Debug for pthread_rwlock_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("pthread_rwlock_t") + // FIXME: .field("size", &self.size) + .finish() + } + } + + impl ::hash::Hash for pthread_rwlock_t { + fn hash(&self, state: &mut H) { + self.size.hash(state); + } + } + + impl PartialEq for sockaddr_alg { + fn eq(&self, other: &sockaddr_alg) -> bool { + self.salg_family == other.salg_family + && self + .salg_type + .iter() + .zip(other.salg_type.iter()) + .all(|(a, b)| a == b) + && self.salg_feat == other.salg_feat + && self.salg_mask == other.salg_mask + && self + .salg_name + .iter() + .zip(other.salg_name.iter()) + .all(|(a, b)| a == b) + } + } + + impl Eq for sockaddr_alg {} + + impl ::fmt::Debug for sockaddr_alg { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_alg") + .field("salg_family", &self.salg_family) + .field("salg_type", &self.salg_type) + .field("salg_feat", &self.salg_feat) + .field("salg_mask", &self.salg_mask) + .field("salg_name", &&self.salg_name[..]) + .finish() + } + } + + impl ::hash::Hash for sockaddr_alg { + fn hash(&self, state: &mut H) { + self.salg_family.hash(state); + self.salg_type.hash(state); + self.salg_feat.hash(state); + self.salg_mask.hash(state); + self.salg_name.hash(state); + } + } + + impl af_alg_iv { + fn as_slice(&self) -> &[u8] { + unsafe { + ::core::slice::from_raw_parts( + self.iv.as_ptr(), + self.ivlen as usize + ) + } + } + } + + impl PartialEq for af_alg_iv { + fn eq(&self, other: &af_alg_iv) -> bool { + *self.as_slice() == *other.as_slice() + } + } + + impl Eq for af_alg_iv {} + + impl ::fmt::Debug for af_alg_iv { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("af_alg_iv") + .field("iv", &self.as_slice()) + .finish() + } + } + + impl ::hash::Hash for af_alg_iv { + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } + } + } +} + +pub const ABDAY_1: ::nl_item = 0x20000; +pub const ABDAY_2: ::nl_item = 0x20001; +pub const ABDAY_3: ::nl_item = 0x20002; +pub const ABDAY_4: ::nl_item = 0x20003; +pub const ABDAY_5: ::nl_item = 0x20004; +pub const ABDAY_6: ::nl_item = 0x20005; +pub const ABDAY_7: ::nl_item = 0x20006; + +pub const DAY_1: ::nl_item = 0x20007; +pub const DAY_2: ::nl_item = 0x20008; +pub const DAY_3: ::nl_item = 0x20009; +pub const DAY_4: ::nl_item = 0x2000A; +pub const DAY_5: ::nl_item = 0x2000B; +pub const DAY_6: ::nl_item = 0x2000C; +pub const DAY_7: ::nl_item = 0x2000D; + +pub const ABMON_1: ::nl_item = 0x2000E; +pub const ABMON_2: ::nl_item = 0x2000F; +pub const ABMON_3: ::nl_item = 0x20010; +pub const ABMON_4: ::nl_item = 0x20011; +pub const ABMON_5: ::nl_item = 0x20012; +pub const ABMON_6: ::nl_item = 0x20013; +pub const ABMON_7: ::nl_item = 0x20014; +pub const ABMON_8: ::nl_item = 0x20015; +pub const ABMON_9: ::nl_item = 0x20016; +pub const ABMON_10: ::nl_item = 0x20017; +pub const ABMON_11: ::nl_item = 0x20018; +pub const ABMON_12: ::nl_item = 0x20019; + +pub const MON_1: ::nl_item = 0x2001A; +pub const MON_2: ::nl_item = 0x2001B; +pub const MON_3: ::nl_item = 0x2001C; +pub const MON_4: ::nl_item = 0x2001D; +pub const MON_5: ::nl_item = 0x2001E; +pub const MON_6: ::nl_item = 0x2001F; +pub const MON_7: ::nl_item = 0x20020; +pub const MON_8: ::nl_item = 0x20021; +pub const MON_9: ::nl_item = 0x20022; +pub const MON_10: ::nl_item = 0x20023; +pub const MON_11: ::nl_item = 0x20024; +pub const MON_12: ::nl_item = 0x20025; + +pub const AM_STR: ::nl_item = 0x20026; +pub const PM_STR: ::nl_item = 0x20027; + +pub const D_T_FMT: ::nl_item = 0x20028; +pub const D_FMT: ::nl_item = 0x20029; +pub const T_FMT: ::nl_item = 0x2002A; +pub const T_FMT_AMPM: ::nl_item = 0x2002B; + +pub const ERA: ::nl_item = 0x2002C; +pub const ERA_D_FMT: ::nl_item = 0x2002E; +pub const ALT_DIGITS: ::nl_item = 0x2002F; +pub const ERA_D_T_FMT: ::nl_item = 0x20030; +pub const ERA_T_FMT: ::nl_item = 0x20031; + +pub const CODESET: ::nl_item = 14; + +pub const CRNCYSTR: ::nl_item = 0x4000F; + +pub const RUSAGE_THREAD: ::c_int = 1; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const RADIXCHAR: ::nl_item = 0x10000; +pub const THOUSEP: ::nl_item = 0x10001; + +pub const YESEXPR: ::nl_item = 0x50000; +pub const NOEXPR: ::nl_item = 0x50001; +pub const YESSTR: ::nl_item = 0x50002; +pub const NOSTR: ::nl_item = 0x50003; + +pub const FILENAME_MAX: ::c_uint = 4096; +pub const L_tmpnam: ::c_uint = 20; +pub const _PC_LINK_MAX: ::c_int = 0; +pub const _PC_MAX_CANON: ::c_int = 1; +pub const _PC_MAX_INPUT: ::c_int = 2; +pub const _PC_NAME_MAX: ::c_int = 3; +pub const _PC_PATH_MAX: ::c_int = 4; +pub const _PC_PIPE_BUF: ::c_int = 5; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 6; +pub const _PC_NO_TRUNC: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; +pub const _PC_SYNC_IO: ::c_int = 9; +pub const _PC_ASYNC_IO: ::c_int = 10; +pub const _PC_PRIO_IO: ::c_int = 11; +pub const _PC_SOCK_MAXBUF: ::c_int = 12; +pub const _PC_FILESIZEBITS: ::c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 16; +pub const _PC_REC_XFER_ALIGN: ::c_int = 17; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 18; +pub const _PC_SYMLINK_MAX: ::c_int = 19; +pub const _PC_2_SYMLINKS: ::c_int = 20; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_CHILD_MAX: ::c_int = 1; +pub const _SC_CLK_TCK: ::c_int = 2; +pub const _SC_NGROUPS_MAX: ::c_int = 3; +pub const _SC_OPEN_MAX: ::c_int = 4; +pub const _SC_STREAM_MAX: ::c_int = 5; +pub const _SC_TZNAME_MAX: ::c_int = 6; +pub const _SC_JOB_CONTROL: ::c_int = 7; +pub const _SC_SAVED_IDS: ::c_int = 8; +pub const _SC_REALTIME_SIGNALS: ::c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10; +pub const _SC_TIMERS: ::c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12; +pub const _SC_PRIORITIZED_IO: ::c_int = 13; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 14; +pub const _SC_FSYNC: ::c_int = 15; +pub const _SC_MAPPED_FILES: ::c_int = 16; +pub const _SC_MEMLOCK: ::c_int = 17; +pub const _SC_MEMLOCK_RANGE: ::c_int = 18; +pub const _SC_MEMORY_PROTECTION: ::c_int = 19; +pub const _SC_MESSAGE_PASSING: ::c_int = 20; +pub const _SC_SEMAPHORES: ::c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 23; +pub const _SC_AIO_MAX: ::c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25; +pub const _SC_DELAYTIMER_MAX: ::c_int = 26; +pub const _SC_MQ_OPEN_MAX: ::c_int = 27; +pub const _SC_MQ_PRIO_MAX: ::c_int = 28; +pub const _SC_VERSION: ::c_int = 29; +pub const _SC_PAGESIZE: ::c_int = 30; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: ::c_int = 31; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 32; +pub const _SC_SEM_VALUE_MAX: ::c_int = 33; +pub const _SC_SIGQUEUE_MAX: ::c_int = 34; +pub const _SC_TIMER_MAX: ::c_int = 35; +pub const _SC_BC_BASE_MAX: ::c_int = 36; +pub const _SC_BC_DIM_MAX: ::c_int = 37; +pub const _SC_BC_SCALE_MAX: ::c_int = 38; +pub const _SC_BC_STRING_MAX: ::c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40; +pub const _SC_EXPR_NEST_MAX: ::c_int = 42; +pub const _SC_LINE_MAX: ::c_int = 43; +pub const _SC_RE_DUP_MAX: ::c_int = 44; +pub const _SC_2_VERSION: ::c_int = 46; +pub const _SC_2_C_BIND: ::c_int = 47; +pub const _SC_2_C_DEV: ::c_int = 48; +pub const _SC_2_FORT_DEV: ::c_int = 49; +pub const _SC_2_FORT_RUN: ::c_int = 50; +pub const _SC_2_SW_DEV: ::c_int = 51; +pub const _SC_2_LOCALEDEF: ::c_int = 52; +pub const _SC_UIO_MAXIOV: ::c_int = 60; +pub const _SC_IOV_MAX: ::c_int = 60; +pub const _SC_THREADS: ::c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 71; +pub const _SC_TTY_NAME_MAX: ::c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 74; +pub const _SC_THREAD_STACK_MIN: ::c_int = 75; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 82; +pub const _SC_NPROCESSORS_CONF: ::c_int = 83; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 84; +pub const _SC_PHYS_PAGES: ::c_int = 85; +pub const _SC_AVPHYS_PAGES: ::c_int = 86; +pub const _SC_ATEXIT_MAX: ::c_int = 87; +pub const _SC_PASS_MAX: ::c_int = 88; +pub const _SC_XOPEN_VERSION: ::c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90; +pub const _SC_XOPEN_UNIX: ::c_int = 91; +pub const _SC_XOPEN_CRYPT: ::c_int = 92; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 93; +pub const _SC_XOPEN_SHM: ::c_int = 94; +pub const _SC_2_CHAR_TERM: ::c_int = 95; +pub const _SC_2_UPE: ::c_int = 97; +pub const _SC_XOPEN_XPG2: ::c_int = 98; +pub const _SC_XOPEN_XPG3: ::c_int = 99; +pub const _SC_XOPEN_XPG4: ::c_int = 100; +pub const _SC_NZERO: ::c_int = 109; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 127; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128; +pub const _SC_XOPEN_LEGACY: ::c_int = 129; +pub const _SC_XOPEN_REALTIME: ::c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131; +pub const _SC_ADVISORY_INFO: ::c_int = 132; +pub const _SC_BARRIERS: ::c_int = 133; +pub const _SC_CLOCK_SELECTION: ::c_int = 137; +pub const _SC_CPUTIME: ::c_int = 138; +pub const _SC_THREAD_CPUTIME: ::c_int = 139; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 149; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 153; +pub const _SC_SPIN_LOCKS: ::c_int = 154; +pub const _SC_REGEXP: ::c_int = 155; +pub const _SC_SHELL: ::c_int = 157; +pub const _SC_SPAWN: ::c_int = 159; +pub const _SC_SPORADIC_SERVER: ::c_int = 160; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 161; +pub const _SC_TIMEOUTS: ::c_int = 164; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 165; +pub const _SC_2_PBS: ::c_int = 168; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 169; +pub const _SC_2_PBS_LOCATE: ::c_int = 170; +pub const _SC_2_PBS_MESSAGE: ::c_int = 171; +pub const _SC_2_PBS_TRACK: ::c_int = 172; +pub const _SC_SYMLOOP_MAX: ::c_int = 173; +pub const _SC_STREAMS: ::c_int = 174; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 175; +pub const _SC_V6_ILP32_OFF32: ::c_int = 176; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 177; +pub const _SC_V6_LP64_OFF64: ::c_int = 178; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 179; +pub const _SC_HOST_NAME_MAX: ::c_int = 180; +pub const _SC_TRACE: ::c_int = 181; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 182; +pub const _SC_TRACE_INHERIT: ::c_int = 183; +pub const _SC_TRACE_LOG: ::c_int = 184; +pub const _SC_IPV6: ::c_int = 235; +pub const _SC_RAW_SOCKETS: ::c_int = 236; +pub const _SC_V7_ILP32_OFF32: ::c_int = 237; +pub const _SC_V7_ILP32_OFFBIG: ::c_int = 238; +pub const _SC_V7_LP64_OFF64: ::c_int = 239; +pub const _SC_V7_LPBIG_OFFBIG: ::c_int = 240; +pub const _SC_SS_REPL_MAX: ::c_int = 241; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 242; +pub const _SC_TRACE_NAME_MAX: ::c_int = 243; +pub const _SC_TRACE_SYS_MAX: ::c_int = 244; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 245; +pub const _SC_XOPEN_STREAMS: ::c_int = 246; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 247; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 248; + +pub const RLIM_SAVED_MAX: ::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: ::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: ::c_int = 1 << 0; +pub const GLOB_MARK: ::c_int = 1 << 1; +pub const GLOB_NOSORT: ::c_int = 1 << 2; +pub const GLOB_DOOFFS: ::c_int = 1 << 3; +pub const GLOB_NOCHECK: ::c_int = 1 << 4; +pub const GLOB_APPEND: ::c_int = 1 << 5; +pub const GLOB_NOESCAPE: ::c_int = 1 << 6; + +pub const GLOB_NOSPACE: ::c_int = 1; +pub const GLOB_ABORTED: ::c_int = 2; +pub const GLOB_NOMATCH: ::c_int = 3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; + +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; + +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; + +pub const IFF_LOWER_UP: ::c_int = 0x10000; +pub const IFF_DORMANT: ::c_int = 0x20000; +pub const IFF_ECHO: ::c_int = 0x40000; + +// linux/if_tun.h +pub const IFF_TUN: ::c_short = 0x0001; +pub const IFF_TAP: ::c_short = 0x0002; +pub const IFF_NO_PI: ::c_short = 0x1000; +// Read queue size +pub const TUN_READQ_SIZE: ::c_short = 500; +// TUN device type flags: deprecated. Use IFF_TUN/IFF_TAP instead. +pub const TUN_TUN_DEV: ::c_short = ::IFF_TUN; +pub const TUN_TAP_DEV: ::c_short = ::IFF_TAP; +pub const TUN_TYPE_MASK: ::c_short = 0x000f; +// This flag has no real effect +pub const IFF_ONE_QUEUE: ::c_short = 0x2000; +pub const IFF_VNET_HDR: ::c_short = 0x4000; +pub const IFF_TUN_EXCL: ::c_short = 0x8000; +pub const IFF_MULTI_QUEUE: ::c_short = 0x0100; +pub const IFF_ATTACH_QUEUE: ::c_short = 0x0200; +pub const IFF_DETACH_QUEUE: ::c_short = 0x0400; +// read-only flag +pub const IFF_PERSIST: ::c_short = 0x0800; +pub const IFF_NOFILTER: ::c_short = 0x1000; + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; +pub const ST_NODEV: ::c_ulong = 4; +pub const ST_NOEXEC: ::c_ulong = 8; +pub const ST_SYNCHRONOUS: ::c_ulong = 16; +pub const ST_MANDLOCK: ::c_ulong = 64; +pub const ST_WRITE: ::c_ulong = 128; +pub const ST_APPEND: ::c_ulong = 256; +pub const ST_IMMUTABLE: ::c_ulong = 512; +pub const ST_NOATIME: ::c_ulong = 1024; +pub const ST_NODIRATIME: ::c_ulong = 2048; + +pub const RTLD_NEXT: *mut ::c_void = -1i64 as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_NOW: ::c_int = 0x2; + +pub const TCP_MD5SIG: ::c_int = 14; + +align_const! { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], + }; +} +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; +pub const PTHREAD_PROCESS_PRIVATE: ::c_int = 0; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const RENAME_NOREPLACE: ::c_int = 1; +pub const RENAME_EXCHANGE: ::c_int = 2; +pub const RENAME_WHITEOUT: ::c_int = 4; + +pub const SCHED_OTHER: ::c_int = 0; +pub const SCHED_FIFO: ::c_int = 1; +pub const SCHED_RR: ::c_int = 2; +pub const SCHED_BATCH: ::c_int = 3; +pub const SCHED_IDLE: ::c_int = 5; + +// netinet/in.h +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: ::c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +pub const IPPROTO_MTP: ::c_int = 92; +pub const IPPROTO_BEETPH: ::c_int = 94; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: ::c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_COMP: ::c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; +pub const IPPROTO_MH: ::c_int = 135; +pub const IPPROTO_UDPLITE: ::c_int = 136; +pub const IPPROTO_MPLS: ::c_int = 137; +/// raw IP packet +pub const IPPROTO_RAW: ::c_int = 255; +pub const IPPROTO_MAX: ::c_int = 256; + +pub const AF_IB: ::c_int = 27; +pub const AF_MPLS: ::c_int = 28; +pub const AF_NFC: ::c_int = 39; +pub const AF_VSOCK: ::c_int = 40; +pub const AF_XDP: ::c_int = 44; +pub const PF_IB: ::c_int = AF_IB; +pub const PF_MPLS: ::c_int = AF_MPLS; +pub const PF_NFC: ::c_int = AF_NFC; +pub const PF_VSOCK: ::c_int = AF_VSOCK; +pub const PF_XDP: ::c_int = AF_XDP; + +// System V IPC +pub const IPC_PRIVATE: ::key_t = 0; + +pub const IPC_CREAT: ::c_int = 0o1000; +pub const IPC_EXCL: ::c_int = 0o2000; +pub const IPC_NOWAIT: ::c_int = 0o4000; + +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; +pub const IPC_INFO: ::c_int = 3; +pub const MSG_STAT: ::c_int = 11; +pub const MSG_INFO: ::c_int = 12; + +pub const MSG_NOERROR: ::c_int = 0o10000; +pub const MSG_EXCEPT: ::c_int = 0o20000; +pub const MSG_COPY: ::c_int = 0o40000; + +pub const SHM_R: ::c_int = 0o400; +pub const SHM_W: ::c_int = 0o200; + +pub const SHM_RDONLY: ::c_int = 0o10000; +pub const SHM_RND: ::c_int = 0o20000; +pub const SHM_REMAP: ::c_int = 0o40000; +pub const SHM_EXEC: ::c_int = 0o100000; + +pub const SHM_LOCK: ::c_int = 11; +pub const SHM_UNLOCK: ::c_int = 12; + +pub const SHM_HUGETLB: ::c_int = 0o4000; +pub const SHM_NORESERVE: ::c_int = 0o10000; + +pub const EPOLLRDHUP: ::c_int = 0x2000; +pub const EPOLLEXCLUSIVE: ::c_int = 0x10000000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; + +pub const QFMT_VFS_OLD: ::c_int = 1; +pub const QFMT_VFS_V0: ::c_int = 2; +pub const QFMT_VFS_V1: ::c_int = 4; + +pub const EFD_SEMAPHORE: ::c_int = 0x1; + +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const SEM_FAILED: *mut ::sem_t = 0 as *mut sem_t; + +pub const RB_AUTOBOOT: ::c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: ::c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: ::c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: ::c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: ::c_int = 0x4321fedcu32 as i32; +pub const RB_SW_SUSPEND: ::c_int = 0xd000fce2u32 as i32; +pub const RB_KEXEC: ::c_int = 0x45584543u32 as i32; + +pub const AI_PASSIVE: ::c_int = 0x0001; +pub const AI_CANONNAME: ::c_int = 0x0002; +pub const AI_NUMERICHOST: ::c_int = 0x0004; +pub const AI_V4MAPPED: ::c_int = 0x0008; +pub const AI_ALL: ::c_int = 0x0010; +pub const AI_ADDRCONFIG: ::c_int = 0x0020; + +pub const AI_NUMERICSERV: ::c_int = 0x0400; + +pub const EAI_BADFLAGS: ::c_int = -1; +pub const EAI_NONAME: ::c_int = -2; +pub const EAI_AGAIN: ::c_int = -3; +pub const EAI_FAIL: ::c_int = -4; +pub const EAI_NODATA: ::c_int = -5; +pub const EAI_FAMILY: ::c_int = -6; +pub const EAI_SOCKTYPE: ::c_int = -7; +pub const EAI_SERVICE: ::c_int = -8; +pub const EAI_MEMORY: ::c_int = -10; +pub const EAI_SYSTEM: ::c_int = -11; +pub const EAI_OVERFLOW: ::c_int = -12; + +pub const NI_NUMERICHOST: ::c_int = 1; +pub const NI_NUMERICSERV: ::c_int = 2; +pub const NI_NOFQDN: ::c_int = 4; +pub const NI_NAMEREQD: ::c_int = 8; +pub const NI_DGRAM: ::c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: ::c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: ::c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: ::c_uint = 4; + +pub const AIO_CANCELED: ::c_int = 0; +pub const AIO_NOTCANCELED: ::c_int = 1; +pub const AIO_ALLDONE: ::c_int = 2; +pub const LIO_READ: ::c_int = 0; +pub const LIO_WRITE: ::c_int = 1; +pub const LIO_NOP: ::c_int = 2; +pub const LIO_WAIT: ::c_int = 0; +pub const LIO_NOWAIT: ::c_int = 1; + +pub const MREMAP_MAYMOVE: ::c_int = 1; +pub const MREMAP_FIXED: ::c_int = 2; + +pub const PR_SET_PDEATHSIG: ::c_int = 1; +pub const PR_GET_PDEATHSIG: ::c_int = 2; + +pub const PR_GET_DUMPABLE: ::c_int = 3; +pub const PR_SET_DUMPABLE: ::c_int = 4; + +pub const PR_GET_UNALIGN: ::c_int = 5; +pub const PR_SET_UNALIGN: ::c_int = 6; +pub const PR_UNALIGN_NOPRINT: ::c_int = 1; +pub const PR_UNALIGN_SIGBUS: ::c_int = 2; + +pub const PR_GET_KEEPCAPS: ::c_int = 7; +pub const PR_SET_KEEPCAPS: ::c_int = 8; + +pub const PR_GET_FPEMU: ::c_int = 9; +pub const PR_SET_FPEMU: ::c_int = 10; +pub const PR_FPEMU_NOPRINT: ::c_int = 1; +pub const PR_FPEMU_SIGFPE: ::c_int = 2; + +pub const PR_GET_FPEXC: ::c_int = 11; +pub const PR_SET_FPEXC: ::c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: ::c_int = 0x80; +pub const PR_FP_EXC_DIV: ::c_int = 0x010000; +pub const PR_FP_EXC_OVF: ::c_int = 0x020000; +pub const PR_FP_EXC_UND: ::c_int = 0x040000; +pub const PR_FP_EXC_RES: ::c_int = 0x080000; +pub const PR_FP_EXC_INV: ::c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: ::c_int = 0; +pub const PR_FP_EXC_NONRECOV: ::c_int = 1; +pub const PR_FP_EXC_ASYNC: ::c_int = 2; +pub const PR_FP_EXC_PRECISE: ::c_int = 3; + +pub const PR_GET_TIMING: ::c_int = 13; +pub const PR_SET_TIMING: ::c_int = 14; +pub const PR_TIMING_STATISTICAL: ::c_int = 0; +pub const PR_TIMING_TIMESTAMP: ::c_int = 1; + +pub const PR_SET_NAME: ::c_int = 15; +pub const PR_GET_NAME: ::c_int = 16; + +pub const PR_GET_ENDIAN: ::c_int = 19; +pub const PR_SET_ENDIAN: ::c_int = 20; +pub const PR_ENDIAN_BIG: ::c_int = 0; +pub const PR_ENDIAN_LITTLE: ::c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: ::c_int = 2; + +pub const PR_GET_SECCOMP: ::c_int = 21; +pub const PR_SET_SECCOMP: ::c_int = 22; + +pub const PR_CAPBSET_READ: ::c_int = 23; +pub const PR_CAPBSET_DROP: ::c_int = 24; + +pub const PR_GET_TSC: ::c_int = 25; +pub const PR_SET_TSC: ::c_int = 26; +pub const PR_TSC_ENABLE: ::c_int = 1; +pub const PR_TSC_SIGSEGV: ::c_int = 2; + +pub const PR_GET_SECUREBITS: ::c_int = 27; +pub const PR_SET_SECUREBITS: ::c_int = 28; + +pub const PR_SET_TIMERSLACK: ::c_int = 29; +pub const PR_GET_TIMERSLACK: ::c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: ::c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: ::c_int = 32; + +pub const PR_MCE_KILL: ::c_int = 33; +pub const PR_MCE_KILL_CLEAR: ::c_int = 0; +pub const PR_MCE_KILL_SET: ::c_int = 1; + +pub const PR_MCE_KILL_LATE: ::c_int = 0; +pub const PR_MCE_KILL_EARLY: ::c_int = 1; +pub const PR_MCE_KILL_DEFAULT: ::c_int = 2; + +pub const PR_MCE_KILL_GET: ::c_int = 34; + +pub const PR_SET_MM: ::c_int = 35; +pub const PR_SET_MM_START_CODE: ::c_int = 1; +pub const PR_SET_MM_END_CODE: ::c_int = 2; +pub const PR_SET_MM_START_DATA: ::c_int = 3; +pub const PR_SET_MM_END_DATA: ::c_int = 4; +pub const PR_SET_MM_START_STACK: ::c_int = 5; +pub const PR_SET_MM_START_BRK: ::c_int = 6; +pub const PR_SET_MM_BRK: ::c_int = 7; +pub const PR_SET_MM_ARG_START: ::c_int = 8; +pub const PR_SET_MM_ARG_END: ::c_int = 9; +pub const PR_SET_MM_ENV_START: ::c_int = 10; +pub const PR_SET_MM_ENV_END: ::c_int = 11; +pub const PR_SET_MM_AUXV: ::c_int = 12; +pub const PR_SET_MM_EXE_FILE: ::c_int = 13; +pub const PR_SET_MM_MAP: ::c_int = 14; +pub const PR_SET_MM_MAP_SIZE: ::c_int = 15; + +pub const PR_SET_PTRACER: ::c_int = 0x59616d61; + +pub const PR_SET_CHILD_SUBREAPER: ::c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: ::c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: ::c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: ::c_int = 39; + +pub const PR_GET_TID_ADDRESS: ::c_int = 40; + +pub const PR_SET_THP_DISABLE: ::c_int = 41; +pub const PR_GET_THP_DISABLE: ::c_int = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT: ::c_int = 43; +pub const PR_MPX_DISABLE_MANAGEMENT: ::c_int = 44; + +pub const PR_SET_FP_MODE: ::c_int = 45; +pub const PR_GET_FP_MODE: ::c_int = 46; +pub const PR_FP_MODE_FR: ::c_int = 1 << 0; +pub const PR_FP_MODE_FRE: ::c_int = 1 << 1; + +pub const PR_CAP_AMBIENT: ::c_int = 47; +pub const PR_CAP_AMBIENT_IS_SET: ::c_int = 1; +pub const PR_CAP_AMBIENT_RAISE: ::c_int = 2; +pub const PR_CAP_AMBIENT_LOWER: ::c_int = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL: ::c_int = 4; + +pub const GRND_NONBLOCK: ::c_uint = 0x0001; +pub const GRND_RANDOM: ::c_uint = 0x0002; + +pub const SECCOMP_MODE_DISABLED: ::c_uint = 0; +pub const SECCOMP_MODE_STRICT: ::c_uint = 1; +pub const SECCOMP_MODE_FILTER: ::c_uint = 2; + +pub const ITIMER_REAL: ::c_int = 0; +pub const ITIMER_VIRTUAL: ::c_int = 1; +pub const ITIMER_PROF: ::c_int = 2; + +pub const TFD_CLOEXEC: ::c_int = O_CLOEXEC; +pub const TFD_NONBLOCK: ::c_int = O_NONBLOCK; +pub const TFD_TIMER_ABSTIME: ::c_int = 1; + +pub const XATTR_CREATE: ::c_int = 0x1; +pub const XATTR_REPLACE: ::c_int = 0x2; + +pub const _POSIX_VDISABLE: ::cc_t = 0; + +pub const FALLOC_FL_KEEP_SIZE: ::c_int = 0x01; +pub const FALLOC_FL_PUNCH_HOLE: ::c_int = 0x02; +pub const FALLOC_FL_COLLAPSE_RANGE: ::c_int = 0x08; +pub const FALLOC_FL_ZERO_RANGE: ::c_int = 0x10; +pub const FALLOC_FL_INSERT_RANGE: ::c_int = 0x20; +pub const FALLOC_FL_UNSHARE_RANGE: ::c_int = 0x40; + +// On Linux, libc doesn't define this constant, libattr does instead. +// We still define it for Linux as it's defined by libc on other platforms, +// and it's mentioned in the man pages for getxattr and setxattr. +pub const ENOATTR: ::c_int = ::ENODATA; + +pub const SO_ORIGINAL_DST: ::c_int = 80; +pub const IP_ORIGDSTADDR : ::c_int = 20; +pub const IP_RECVORIGDSTADDR : ::c_int = IP_ORIGDSTADDR; +pub const IPV6_ORIGDSTADDR : ::c_int = 74; +pub const IPV6_RECVORIGDSTADDR : ::c_int = IPV6_ORIGDSTADDR; +pub const IPV6_FLOWINFO: ::c_int = 11; +pub const IPV6_FLOWLABEL_MGR: ::c_int = 32; +pub const IPV6_FLOWINFO_SEND: ::c_int = 33; +pub const IPV6_FLOWINFO_FLOWLABEL: ::c_int = 0x000fffff; +pub const IPV6_FLOWINFO_PRIORITY: ::c_int = 0x0ff00000; +pub const IUTF8: ::tcflag_t = 0x00004000; +pub const CMSPAR: ::tcflag_t = 0o10000000000; + +pub const MFD_CLOEXEC: ::c_uint = 0x0001; +pub const MFD_ALLOW_SEALING: ::c_uint = 0x0002; +pub const MFD_HUGETLB: ::c_uint = 0x0004; + +// these are used in the p_type field of Elf32_Phdr and Elf64_Phdr, which has +// the type Elf32Word and Elf64Word respectively. Luckily, both of those are u32 +// so we can use that type here to avoid having to cast. +pub const PT_NULL: u32 = 0; +pub const PT_LOAD: u32 = 1; +pub const PT_DYNAMIC: u32 = 2; +pub const PT_INTERP: u32 = 3; +pub const PT_NOTE: u32 = 4; +pub const PT_SHLIB: u32 = 5; +pub const PT_PHDR: u32 = 6; +pub const PT_TLS: u32 = 7; +pub const PT_NUM: u32 = 8; +pub const PT_LOOS: u32 = 0x60000000; +pub const PT_GNU_EH_FRAME: u32 = 0x6474e550; +pub const PT_GNU_STACK: u32 = 0x6474e551; +pub const PT_GNU_RELRO: u32 = 0x6474e552; + +// linux/if_ether.h +pub const ETH_ALEN: ::c_int = 6; +pub const ETH_HLEN: ::c_int = 14; +pub const ETH_ZLEN: ::c_int = 60; +pub const ETH_DATA_LEN: ::c_int = 1500; +pub const ETH_FRAME_LEN: ::c_int = 1514; +pub const ETH_FCS_LEN: ::c_int = 4; + +// These are the defined Ethernet Protocol ID's. +pub const ETH_P_LOOP: ::c_int = 0x0060; +pub const ETH_P_PUP: ::c_int = 0x0200; +pub const ETH_P_PUPAT: ::c_int = 0x0201; +pub const ETH_P_IP: ::c_int = 0x0800; +pub const ETH_P_X25: ::c_int = 0x0805; +pub const ETH_P_ARP: ::c_int = 0x0806; +pub const ETH_P_BPQ: ::c_int = 0x08FF; +pub const ETH_P_IEEEPUP: ::c_int = 0x0a00; +pub const ETH_P_IEEEPUPAT: ::c_int = 0x0a01; +pub const ETH_P_BATMAN: ::c_int = 0x4305; +pub const ETH_P_DEC: ::c_int = 0x6000; +pub const ETH_P_DNA_DL: ::c_int = 0x6001; +pub const ETH_P_DNA_RC: ::c_int = 0x6002; +pub const ETH_P_DNA_RT: ::c_int = 0x6003; +pub const ETH_P_LAT: ::c_int = 0x6004; +pub const ETH_P_DIAG: ::c_int = 0x6005; +pub const ETH_P_CUST: ::c_int = 0x6006; +pub const ETH_P_SCA: ::c_int = 0x6007; +pub const ETH_P_TEB: ::c_int = 0x6558; +pub const ETH_P_RARP: ::c_int = 0x8035; +pub const ETH_P_ATALK: ::c_int = 0x809B; +pub const ETH_P_AARP: ::c_int = 0x80F3; +pub const ETH_P_8021Q: ::c_int = 0x8100; +pub const ETH_P_IPX: ::c_int = 0x8137; +pub const ETH_P_IPV6: ::c_int = 0x86DD; +pub const ETH_P_PAUSE: ::c_int = 0x8808; +pub const ETH_P_SLOW: ::c_int = 0x8809; +pub const ETH_P_WCCP: ::c_int = 0x883E; +pub const ETH_P_MPLS_UC: ::c_int = 0x8847; +pub const ETH_P_MPLS_MC: ::c_int = 0x8848; +pub const ETH_P_ATMMPOA: ::c_int = 0x884c; +pub const ETH_P_PPP_DISC: ::c_int = 0x8863; +pub const ETH_P_PPP_SES: ::c_int = 0x8864; +pub const ETH_P_LINK_CTL: ::c_int = 0x886c; +pub const ETH_P_ATMFATE: ::c_int = 0x8884; +pub const ETH_P_PAE: ::c_int = 0x888E; +pub const ETH_P_AOE: ::c_int = 0x88A2; +pub const ETH_P_8021AD: ::c_int = 0x88A8; +pub const ETH_P_802_EX1: ::c_int = 0x88B5; +pub const ETH_P_TIPC: ::c_int = 0x88CA; +pub const ETH_P_MACSEC: ::c_int = 0x88E5; +pub const ETH_P_8021AH: ::c_int = 0x88E7; +pub const ETH_P_MVRP: ::c_int = 0x88F5; +pub const ETH_P_1588: ::c_int = 0x88F7; +pub const ETH_P_PRP: ::c_int = 0x88FB; +pub const ETH_P_FCOE: ::c_int = 0x8906; +pub const ETH_P_TDLS: ::c_int = 0x890D; +pub const ETH_P_FIP: ::c_int = 0x8914; +pub const ETH_P_80221: ::c_int = 0x8917; +pub const ETH_P_LOOPBACK: ::c_int = 0x9000; +pub const ETH_P_QINQ1: ::c_int = 0x9100; +pub const ETH_P_QINQ2: ::c_int = 0x9200; +pub const ETH_P_QINQ3: ::c_int = 0x9300; +pub const ETH_P_EDSA: ::c_int = 0xDADA; +pub const ETH_P_AF_IUCV: ::c_int = 0xFBFB; + +pub const ETH_P_802_3_MIN: ::c_int = 0x0600; + +// Non DIX types. Won't clash for 1500 types. +pub const ETH_P_802_3: ::c_int = 0x0001; +pub const ETH_P_AX25: ::c_int = 0x0002; +pub const ETH_P_ALL: ::c_int = 0x0003; +pub const ETH_P_802_2: ::c_int = 0x0004; +pub const ETH_P_SNAP: ::c_int = 0x0005; +pub const ETH_P_DDCMP: ::c_int = 0x0006; +pub const ETH_P_WAN_PPP: ::c_int = 0x0007; +pub const ETH_P_PPP_MP: ::c_int = 0x0008; +pub const ETH_P_LOCALTALK: ::c_int = 0x0009; +pub const ETH_P_CANFD: ::c_int = 0x000D; +pub const ETH_P_PPPTALK: ::c_int = 0x0010; +pub const ETH_P_TR_802_2: ::c_int = 0x0011; +pub const ETH_P_MOBITEX: ::c_int = 0x0015; +pub const ETH_P_CONTROL: ::c_int = 0x0016; +pub const ETH_P_IRDA: ::c_int = 0x0017; +pub const ETH_P_ECONET: ::c_int = 0x0018; +pub const ETH_P_HDLC: ::c_int = 0x0019; +pub const ETH_P_ARCNET: ::c_int = 0x001A; +pub const ETH_P_DSA: ::c_int = 0x001B; +pub const ETH_P_TRAILER: ::c_int = 0x001C; +pub const ETH_P_PHONET: ::c_int = 0x00F5; +pub const ETH_P_IEEE802154: ::c_int = 0x00F6; +pub const ETH_P_CAIF: ::c_int = 0x00F7; + +pub const POSIX_SPAWN_RESETIDS: ::c_int = 0x01; +pub const POSIX_SPAWN_SETPGROUP: ::c_int = 0x02; +pub const POSIX_SPAWN_SETSIGDEF: ::c_int = 0x04; +pub const POSIX_SPAWN_SETSIGMASK: ::c_int = 0x08; +pub const POSIX_SPAWN_SETSCHEDPARAM: ::c_int = 0x10; +pub const POSIX_SPAWN_SETSCHEDULER: ::c_int = 0x20; + +pub const NLMSG_NOOP: ::c_int = 0x1; +pub const NLMSG_ERROR: ::c_int = 0x2; +pub const NLMSG_DONE: ::c_int = 0x3; +pub const NLMSG_OVERRUN: ::c_int = 0x4; +pub const NLMSG_MIN_TYPE: ::c_int = 0x10; + +pub const GENL_NAMSIZ: ::c_int = 16; + +pub const GENL_MIN_ID: ::c_int = NLMSG_MIN_TYPE; +pub const GENL_MAX_ID: ::c_int = 1023; + +pub const GENL_ADMIN_PERM: ::c_int = 0x01; +pub const GENL_CMD_CAP_DO: ::c_int = 0x02; +pub const GENL_CMD_CAP_DUMP: ::c_int = 0x04; +pub const GENL_CMD_CAP_HASPOL: ::c_int = 0x08; + +pub const GENL_ID_CTRL: ::c_int = NLMSG_MIN_TYPE; + +pub const CTRL_CMD_UNSPEC: ::c_int = 0; +pub const CTRL_CMD_NEWFAMILY: ::c_int = 1; +pub const CTRL_CMD_DELFAMILY: ::c_int = 2; +pub const CTRL_CMD_GETFAMILY: ::c_int = 3; +pub const CTRL_CMD_NEWOPS: ::c_int = 4; +pub const CTRL_CMD_DELOPS: ::c_int = 5; +pub const CTRL_CMD_GETOPS: ::c_int = 6; +pub const CTRL_CMD_NEWMCAST_GRP: ::c_int = 7; +pub const CTRL_CMD_DELMCAST_GRP: ::c_int = 8; +pub const CTRL_CMD_GETMCAST_GRP: ::c_int = 9; + +pub const CTRL_ATTR_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_FAMILY_ID: ::c_int = 1; +pub const CTRL_ATTR_FAMILY_NAME: ::c_int = 2; +pub const CTRL_ATTR_VERSION: ::c_int = 3; +pub const CTRL_ATTR_HDRSIZE: ::c_int = 4; +pub const CTRL_ATTR_MAXATTR: ::c_int = 5; +pub const CTRL_ATTR_OPS: ::c_int = 6; +pub const CTRL_ATTR_MCAST_GROUPS: ::c_int = 7; + +pub const CTRL_ATTR_OP_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_OP_ID: ::c_int = 1; +pub const CTRL_ATTR_OP_FLAGS: ::c_int = 2; + +pub const CTRL_ATTR_MCAST_GRP_UNSPEC: ::c_int = 0; +pub const CTRL_ATTR_MCAST_GRP_NAME: ::c_int = 1; +pub const CTRL_ATTR_MCAST_GRP_ID: ::c_int = 2; + +// linux/if_packet.h +pub const PACKET_ADD_MEMBERSHIP: ::c_int = 1; +pub const PACKET_DROP_MEMBERSHIP: ::c_int = 2; + +pub const PACKET_MR_MULTICAST: ::c_int = 0; +pub const PACKET_MR_PROMISC: ::c_int = 1; +pub const PACKET_MR_ALLMULTI: ::c_int = 2; +pub const PACKET_MR_UNICAST: ::c_int = 3; + +// linux/netfilter.h +pub const NF_DROP: ::c_int = 0; +pub const NF_ACCEPT: ::c_int = 1; +pub const NF_STOLEN: ::c_int = 2; +pub const NF_QUEUE: ::c_int = 3; +pub const NF_REPEAT: ::c_int = 4; +pub const NF_STOP: ::c_int = 5; +pub const NF_MAX_VERDICT: ::c_int = NF_STOP; + +pub const NF_VERDICT_MASK: ::c_int = 0x000000ff; +pub const NF_VERDICT_FLAG_QUEUE_BYPASS: ::c_int = 0x00008000; + +pub const NF_VERDICT_QMASK: ::c_int = 0xffff0000; +pub const NF_VERDICT_QBITS: ::c_int = 16; + +pub const NF_VERDICT_BITS: ::c_int = 16; + +pub const NF_INET_PRE_ROUTING: ::c_int = 0; +pub const NF_INET_LOCAL_IN: ::c_int = 1; +pub const NF_INET_FORWARD: ::c_int = 2; +pub const NF_INET_LOCAL_OUT: ::c_int = 3; +pub const NF_INET_POST_ROUTING: ::c_int = 4; +pub const NF_INET_NUMHOOKS: ::c_int = 5; + +// Some NFPROTO are not compatible with musl and are defined in submodules. +pub const NFPROTO_UNSPEC: ::c_int = 0; +pub const NFPROTO_IPV4: ::c_int = 2; +pub const NFPROTO_ARP: ::c_int = 3; +pub const NFPROTO_BRIDGE: ::c_int = 7; +pub const NFPROTO_IPV6: ::c_int = 10; +pub const NFPROTO_DECNET: ::c_int = 12; +pub const NFPROTO_NUMPROTO: ::c_int = 13; + +// linux/netfilter_ipv4.h +pub const NF_IP_PRE_ROUTING: ::c_int = 0; +pub const NF_IP_LOCAL_IN: ::c_int = 1; +pub const NF_IP_FORWARD: ::c_int = 2; +pub const NF_IP_LOCAL_OUT: ::c_int = 3; +pub const NF_IP_POST_ROUTING: ::c_int = 4; +pub const NF_IP_NUMHOOKS: ::c_int = 5; + +pub const NF_IP_PRI_FIRST: ::c_int = ::INT_MIN; +pub const NF_IP_PRI_CONNTRACK_DEFRAG: ::c_int = -400; +pub const NF_IP_PRI_RAW: ::c_int = -300; +pub const NF_IP_PRI_SELINUX_FIRST: ::c_int = -225; +pub const NF_IP_PRI_CONNTRACK: ::c_int = -200; +pub const NF_IP_PRI_MANGLE: ::c_int = -150; +pub const NF_IP_PRI_NAT_DST: ::c_int = -100; +pub const NF_IP_PRI_FILTER: ::c_int = 0; +pub const NF_IP_PRI_SECURITY: ::c_int = 50; +pub const NF_IP_PRI_NAT_SRC: ::c_int = 100; +pub const NF_IP_PRI_SELINUX_LAST: ::c_int = 225; +pub const NF_IP_PRI_CONNTRACK_HELPER: ::c_int = 300; +pub const NF_IP_PRI_CONNTRACK_CONFIRM: ::c_int = ::INT_MAX; +pub const NF_IP_PRI_LAST: ::c_int = ::INT_MAX; + +// linux/netfilter_ipv6.h +pub const NF_IP6_PRE_ROUTING: ::c_int = 0; +pub const NF_IP6_LOCAL_IN: ::c_int = 1; +pub const NF_IP6_FORWARD: ::c_int = 2; +pub const NF_IP6_LOCAL_OUT: ::c_int = 3; +pub const NF_IP6_POST_ROUTING: ::c_int = 4; +pub const NF_IP6_NUMHOOKS: ::c_int = 5; + +pub const NF_IP6_PRI_FIRST: ::c_int = ::INT_MIN; +pub const NF_IP6_PRI_CONNTRACK_DEFRAG: ::c_int = -400; +pub const NF_IP6_PRI_RAW: ::c_int = -300; +pub const NF_IP6_PRI_SELINUX_FIRST: ::c_int = -225; +pub const NF_IP6_PRI_CONNTRACK: ::c_int = -200; +pub const NF_IP6_PRI_MANGLE: ::c_int = -150; +pub const NF_IP6_PRI_NAT_DST: ::c_int = -100; +pub const NF_IP6_PRI_FILTER: ::c_int = 0; +pub const NF_IP6_PRI_SECURITY: ::c_int = 50; +pub const NF_IP6_PRI_NAT_SRC: ::c_int = 100; +pub const NF_IP6_PRI_SELINUX_LAST: ::c_int = 225; +pub const NF_IP6_PRI_CONNTRACK_HELPER: ::c_int = 300; +pub const NF_IP6_PRI_LAST: ::c_int = ::INT_MAX; + +pub const SIOCADDRT: ::c_ulong = 0x0000890B; +pub const SIOCDELRT: ::c_ulong = 0x0000890C; +pub const SIOCGIFNAME: ::c_ulong = 0x00008910; +pub const SIOCSIFLINK: ::c_ulong = 0x00008911; +pub const SIOCGIFCONF: ::c_ulong = 0x00008912; +pub const SIOCGIFFLAGS: ::c_ulong = 0x00008913; +pub const SIOCSIFFLAGS: ::c_ulong = 0x00008914; +pub const SIOCGIFADDR: ::c_ulong = 0x00008915; +pub const SIOCSIFADDR: ::c_ulong = 0x00008916; +pub const SIOCGIFDSTADDR: ::c_ulong = 0x00008917; +pub const SIOCSIFDSTADDR: ::c_ulong = 0x00008918; +pub const SIOCGIFBRDADDR: ::c_ulong = 0x00008919; +pub const SIOCSIFBRDADDR: ::c_ulong = 0x0000891A; +pub const SIOCGIFNETMASK: ::c_ulong = 0x0000891B; +pub const SIOCSIFNETMASK: ::c_ulong = 0x0000891C; +pub const SIOCGIFMETRIC: ::c_ulong = 0x0000891D; +pub const SIOCSIFMETRIC: ::c_ulong = 0x0000891E; +pub const SIOCGIFMEM: ::c_ulong = 0x0000891F; +pub const SIOCSIFMEM: ::c_ulong = 0x00008920; +pub const SIOCGIFMTU: ::c_ulong = 0x00008921; +pub const SIOCSIFMTU: ::c_ulong = 0x00008922; +pub const SIOCSIFHWADDR: ::c_ulong = 0x00008924; +pub const SIOCGIFENCAP: ::c_ulong = 0x00008925; +pub const SIOCSIFENCAP: ::c_ulong = 0x00008926; +pub const SIOCGIFHWADDR: ::c_ulong = 0x00008927; +pub const SIOCGIFSLAVE: ::c_ulong = 0x00008929; +pub const SIOCSIFSLAVE: ::c_ulong = 0x00008930; +pub const SIOCADDMULTI: ::c_ulong = 0x00008931; +pub const SIOCDELMULTI: ::c_ulong = 0x00008932; +pub const SIOCDARP: ::c_ulong = 0x00008953; +pub const SIOCGARP: ::c_ulong = 0x00008954; +pub const SIOCSARP: ::c_ulong = 0x00008955; +pub const SIOCDRARP: ::c_ulong = 0x00008960; +pub const SIOCGRARP: ::c_ulong = 0x00008961; +pub const SIOCSRARP: ::c_ulong = 0x00008962; +pub const SIOCGIFMAP: ::c_ulong = 0x00008970; +pub const SIOCSIFMAP: ::c_ulong = 0x00008971; + +pub const IPTOS_TOS_MASK: u8 = 0x1E; +pub const IPTOS_PREC_MASK: u8 = 0xE0; + +pub const IPTOS_ECN_NOT_ECT: u8 = 0x00; + +pub const RTF_UP: ::c_ushort = 0x0001; +pub const RTF_GATEWAY: ::c_ushort = 0x0002; + +pub const RTF_HOST: ::c_ushort = 0x0004; +pub const RTF_REINSTATE: ::c_ushort = 0x0008; +pub const RTF_DYNAMIC: ::c_ushort = 0x0010; +pub const RTF_MODIFIED: ::c_ushort = 0x0020; +pub const RTF_MTU: ::c_ushort = 0x0040; +pub const RTF_MSS: ::c_ushort = RTF_MTU; +pub const RTF_WINDOW: ::c_ushort = 0x0080; +pub const RTF_IRTT: ::c_ushort = 0x0100; +pub const RTF_REJECT: ::c_ushort = 0x0200; +pub const RTF_STATIC: ::c_ushort = 0x0400; +pub const RTF_XRESOLVE: ::c_ushort = 0x0800; +pub const RTF_NOFORWARD: ::c_ushort = 0x1000; +pub const RTF_THROW: ::c_ushort = 0x2000; +pub const RTF_NOPMTUDISC: ::c_ushort = 0x4000; + +pub const RTF_DEFAULT: u32 = 0x00010000; +pub const RTF_ALLONLINK: u32 = 0x00020000; +pub const RTF_ADDRCONF: u32 = 0x00040000; +pub const RTF_LINKRT: u32 = 0x00100000; +pub const RTF_NONEXTHOP: u32 = 0x00200000; +pub const RTF_CACHE: u32 = 0x01000000; +pub const RTF_FLOW: u32 = 0x02000000; +pub const RTF_POLICY: u32 = 0x04000000; + +pub const RTCF_VALVE: u32 = 0x00200000; +pub const RTCF_MASQ: u32 = 0x00400000; +pub const RTCF_NAT: u32 = 0x00800000; +pub const RTCF_DOREDIRECT: u32 = 0x01000000; +pub const RTCF_LOG: u32 = 0x02000000; +pub const RTCF_DIRECTSRC: u32 = 0x04000000; + +pub const RTF_LOCAL: u32 = 0x80000000; +pub const RTF_INTERFACE: u32 = 0x40000000; +pub const RTF_MULTICAST: u32 = 0x20000000; +pub const RTF_BROADCAST: u32 = 0x10000000; +pub const RTF_NAT: u32 = 0x08000000; +pub const RTF_ADDRCLASSMASK: u32 = 0xF8000000; + +pub const RT_CLASS_UNSPEC: u8 = 0; +pub const RT_CLASS_DEFAULT: u8 = 253; +pub const RT_CLASS_MAIN: u8 = 254; +pub const RT_CLASS_LOCAL: u8 = 255; +pub const RT_CLASS_MAX: u8 = 255; + +pub const RTMSG_OVERRUN: u32 = ::NLMSG_OVERRUN as u32; +pub const RTMSG_NEWDEVICE: u32 = 0x11; +pub const RTMSG_DELDEVICE: u32 = 0x12; +pub const RTMSG_NEWROUTE: u32 = 0x21; +pub const RTMSG_DELROUTE: u32 = 0x22; +pub const RTMSG_NEWRULE: u32 = 0x31; +pub const RTMSG_DELRULE: u32 = 0x32; +pub const RTMSG_CONTROL: u32 = 0x40; +pub const RTMSG_AR_FAILED: u32 = 0x51; + +pub const MAX_ADDR_LEN: usize = 7; +pub const ARPD_UPDATE: ::c_ushort = 0x01; +pub const ARPD_LOOKUP: ::c_ushort = 0x02; +pub const ARPD_FLUSH: ::c_ushort = 0x03; +pub const ATF_MAGIC: ::c_int = 0x80; + +#[cfg(not(target_arch = "sparc64"))] +pub const SO_TIMESTAMPING: ::c_int = 37; +#[cfg(target_arch = "sparc64")] +pub const SO_TIMESTAMPING: ::c_int = 35; +pub const SCM_TIMESTAMPING: ::c_int = SO_TIMESTAMPING; + +// linux/module.h +pub const MODULE_INIT_IGNORE_MODVERSIONS: ::c_uint = 0x0001; +pub const MODULE_INIT_IGNORE_VERMAGIC: ::c_uint = 0x0002; + +// linux/net_tstamp.h +pub const SOF_TIMESTAMPING_TX_HARDWARE: ::c_uint = 1 << 0; +pub const SOF_TIMESTAMPING_TX_SOFTWARE: ::c_uint = 1 << 1; +pub const SOF_TIMESTAMPING_RX_HARDWARE: ::c_uint = 1 << 2; +pub const SOF_TIMESTAMPING_RX_SOFTWARE: ::c_uint = 1 << 3; +pub const SOF_TIMESTAMPING_SOFTWARE: ::c_uint = 1 << 4; +pub const SOF_TIMESTAMPING_SYS_HARDWARE: ::c_uint = 1 << 5; +pub const SOF_TIMESTAMPING_RAW_HARDWARE: ::c_uint = 1 << 6; + +// linux/if_alg.h +pub const ALG_SET_KEY: ::c_int = 1; +pub const ALG_SET_IV: ::c_int = 2; +pub const ALG_SET_OP: ::c_int = 3; +pub const ALG_SET_AEAD_ASSOCLEN: ::c_int = 4; +pub const ALG_SET_AEAD_AUTHSIZE: ::c_int = 5; + +pub const ALG_OP_DECRYPT: ::c_int = 0; +pub const ALG_OP_ENCRYPT: ::c_int = 1; + +// uapi/linux/inotify.h +pub const IN_ACCESS: ::uint32_t = 0x0000_0001; +pub const IN_MODIFY: ::uint32_t = 0x0000_0002; +pub const IN_ATTRIB: ::uint32_t = 0x0000_0004; +pub const IN_CLOSE_WRITE: ::uint32_t = 0x0000_0008; +pub const IN_CLOSE_NOWRITE: ::uint32_t = 0x0000_0010; +pub const IN_CLOSE: ::uint32_t = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE); +pub const IN_OPEN: ::uint32_t = 0x0000_0020; +pub const IN_MOVED_FROM: ::uint32_t = 0x0000_0040; +pub const IN_MOVED_TO: ::uint32_t = 0x0000_0080; +pub const IN_MOVE: ::uint32_t = (IN_MOVED_FROM | IN_MOVED_TO); +pub const IN_CREATE: ::uint32_t = 0x0000_0100; +pub const IN_DELETE: ::uint32_t = 0x0000_0200; +pub const IN_DELETE_SELF: ::uint32_t = 0x0000_0400; +pub const IN_MOVE_SELF: ::uint32_t = 0x0000_0800; +pub const IN_UNMOUNT: ::uint32_t = 0x0000_2000; +pub const IN_Q_OVERFLOW: ::uint32_t = 0x0000_4000; +pub const IN_IGNORED: ::uint32_t = 0x0000_8000; +pub const IN_ONLYDIR: ::uint32_t = 0x0100_0000; +pub const IN_DONT_FOLLOW: ::uint32_t = 0x0200_0000; +// pub const IN_EXCL_UNLINK: ::uint32_t = 0x0400_0000; + +// pub const IN_MASK_CREATE: ::uint32_t = 0x1000_0000; +// pub const IN_MASK_ADD: ::uint32_t = 0x2000_0000; +pub const IN_ISDIR: ::uint32_t = 0x4000_0000; +pub const IN_ONESHOT: ::uint32_t = 0x8000_0000; + +pub const IN_ALL_EVENTS: ::uint32_t = ( + IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | + IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | + IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | + IN_MOVE_SELF +); + +pub const IN_CLOEXEC: ::c_int = O_CLOEXEC; +pub const IN_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const FUTEX_WAIT: ::c_int = 0; +pub const FUTEX_WAKE: ::c_int = 1; +pub const FUTEX_FD: ::c_int = 2; +pub const FUTEX_REQUEUE: ::c_int = 3; +pub const FUTEX_CMP_REQUEUE: ::c_int = 4; +pub const FUTEX_WAKE_OP: ::c_int = 5; +pub const FUTEX_LOCK_PI: ::c_int = 6; +pub const FUTEX_UNLOCK_PI: ::c_int = 7; +pub const FUTEX_TRYLOCK_PI: ::c_int = 8; +pub const FUTEX_WAIT_BITSET: ::c_int = 9; +pub const FUTEX_WAKE_BITSET: ::c_int = 10; +pub const FUTEX_WAIT_REQUEUE_PI: ::c_int = 11; +pub const FUTEX_CMP_REQUEUE_PI: ::c_int = 12; + +pub const FUTEX_PRIVATE_FLAG: ::c_int = 128; +pub const FUTEX_CLOCK_REALTIME: ::c_int = 256; +pub const FUTEX_CMD_MASK: ::c_int = + !(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME); + +f! { + pub fn CMSG_NXTHDR(mhdr: *const msghdr, + cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < ::mem::size_of::() { + return 0 as *mut cmsghdr; + }; + let next = (cmsg as usize + + super::CMSG_ALIGN((*cmsg).cmsg_len as usize)) + as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max || + next as usize + super::CMSG_ALIGN((*next).cmsg_len as usize) > max + { + 0 as *mut cmsghdr + } else { + next as *mut cmsghdr + } + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * ::mem::size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn major(dev: ::dev_t) -> ::c_uint { + let mut major = 0; + major |= (dev & 0x00000000000fff00) >> 8; + major |= (dev & 0xfffff00000000000) >> 32; + major as ::c_uint + } + + pub fn minor(dev: ::dev_t) -> ::c_uint { + let mut minor = 0; + minor |= (dev & 0x00000000000000ff) >> 0; + minor |= (dev & 0x00000ffffff00000) >> 12; + minor as ::c_uint + } + + pub fn makedev(major: ::c_uint, minor: ::c_uint) -> ::dev_t { + let major = major as ::dev_t; + let minor = minor as ::dev_t; + let mut dev = 0; + dev |= (major & 0x00000fff) << 8; + dev |= (major & 0xfffff000) << 32; + dev |= (minor & 0x000000ff) << 0; + dev |= (minor & 0xffffff00) << 12; + dev + } + + pub fn IPTOS_TOS(tos: u8) -> u8 { + tos & IPTOS_TOS_MASK + } + + pub fn IPTOS_PREC(tos: u8) -> u8 { + tos & IPTOS_PREC_MASK + } + + pub fn RT_TOS(tos: u8) -> u8 { + tos & ::IPTOS_TOS_MASK + } + + pub fn RT_ADDRCLASS(flags: u32) -> u32 { + flags >> 23 + } + + pub fn RT_LOCALADDR(flags: u32) -> bool { + (flags & RTF_ADDRCLASSMASK) == (RTF_LOCAL | RTF_INTERFACE) + } +} + +extern { + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn aio_read(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_write(aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_fsync(op: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn aio_error(aiocbp: *const aiocb) -> ::c_int; + pub fn aio_return(aiocbp: *mut aiocb) -> ::ssize_t; + pub fn aio_suspend(aiocb_list: *const *const aiocb, nitems: ::c_int, + timeout: *const ::timespec) -> ::c_int; + pub fn aio_cancel(fd: ::c_int, aiocbp: *mut aiocb) -> ::c_int; + pub fn lio_listio(mode: ::c_int, aiocb_list: *const *mut aiocb, + nitems: ::c_int, sevp: *mut ::sigevent) -> ::c_int; + + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut ::group; + pub fn setspent(); + pub fn endspent(); + pub fn getspent() -> *mut spwd; + + pub fn getspnam(__name: *const ::c_char) -> *mut spwd; + + pub fn shm_open(name: *const c_char, oflag: ::c_int, + mode: mode_t) -> ::c_int; + + // System V IPC + pub fn shmget(key: ::key_t, size: ::size_t, shmflg: ::c_int) -> ::c_int; + pub fn shmat(shmid: ::c_int, + shmaddr: *const ::c_void, + shmflg: ::c_int) -> *mut ::c_void; + pub fn shmdt(shmaddr: *const ::c_void) -> ::c_int; + pub fn shmctl(shmid: ::c_int, + cmd: ::c_int, + buf: *mut ::shmid_ds) -> ::c_int; + pub fn ftok(pathname: *const ::c_char, proj_id: ::c_int) -> ::key_t; + pub fn semget(key: ::key_t, nsems: ::c_int, semflag: ::c_int) -> ::c_int; + pub fn semop(semid: ::c_int, + sops: *mut ::sembuf, nsops: ::size_t) -> ::c_int; + pub fn semctl(semid: ::c_int, + semnum: ::c_int, cmd: ::c_int, ...) -> ::c_int; + pub fn msgctl(msqid: ::c_int, cmd: ::c_int, buf: *mut msqid_ds) -> ::c_int; + pub fn msgget(key: ::key_t, msgflg: ::c_int) -> ::c_int; + pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t, + msgtyp: ::c_long, msgflg: ::c_int) -> ::ssize_t; + pub fn msgsnd(msqid: ::c_int, msgp: *const ::c_void, msgsz: ::size_t, + msgflg: ::c_int) -> ::c_int; + + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn __errno_location() -> *mut ::c_int; + + pub fn fopen64(filename: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn freopen64(filename: *const c_char, mode: *const c_char, + file: *mut ::FILE) -> *mut ::FILE; + pub fn tmpfile64() -> *mut ::FILE; + pub fn fgetpos64(stream: *mut ::FILE, ptr: *mut fpos64_t) -> ::c_int; + pub fn fsetpos64(stream: *mut ::FILE, ptr: *const fpos64_t) -> ::c_int; + pub fn fseeko64(stream: *mut ::FILE, + offset: ::off64_t, + whence: ::c_int) -> ::c_int; + pub fn ftello64(stream: *mut ::FILE) -> ::off64_t; + pub fn fallocate(fd: ::c_int, mode: ::c_int, + offset: ::off_t, len: ::off_t) -> ::c_int; + pub fn fallocate64(fd: ::c_int, mode: ::c_int, + offset: ::off64_t, len: ::off64_t) -> ::c_int; + pub fn posix_fallocate(fd: ::c_int, offset: ::off_t, + len: ::off_t) -> ::c_int; + pub fn posix_fallocate64(fd: ::c_int, offset: ::off64_t, + len: ::off64_t) -> ::c_int; + pub fn readahead(fd: ::c_int, offset: ::off64_t, + count: ::size_t) -> ::ssize_t; + pub fn getxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn lgetxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn fgetxattr(filedes: ::c_int, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn setxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn lsetxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn fsetxattr(filedes: ::c_int, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn flistxattr(filedes: ::c_int, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn fremovexattr(filedes: ::c_int, name: *const c_char) -> ::c_int; + pub fn signalfd(fd: ::c_int, + mask: *const ::sigset_t, + flags: ::c_int) -> ::c_int; + pub fn timerfd_create(clockid: ::c_int, flags: ::c_int) -> ::c_int; + pub fn timerfd_gettime(fd: ::c_int, + curr_value: *mut itimerspec) -> ::c_int; + pub fn timerfd_settime(fd: ::c_int, + flags: ::c_int, + new_value: *const itimerspec, + old_value: *mut itimerspec) -> ::c_int; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn quotactl(cmd: ::c_int, + special: *const ::c_char, + id: ::c_int, + data: *mut ::c_char) -> ::c_int; + pub fn mq_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::mqd_t; + pub fn mq_close(mqd: ::mqd_t) -> ::c_int; + pub fn mq_unlink(name: *const ::c_char) -> ::c_int; + pub fn mq_receive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint) -> ::ssize_t; + pub fn mq_send(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint) -> ::c_int; + pub fn mq_getattr(mqd: ::mqd_t, attr: *mut ::mq_attr) -> ::c_int; + pub fn mq_setattr(mqd: ::mqd_t, + newattr: *const ::mq_attr, + oldattr: *mut ::mq_attr) -> ::c_int; + pub fn epoll_pwait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int, + sigmask: *const ::sigset_t) -> ::c_int; + pub fn dup3(oldfd: ::c_int, newfd: ::c_int, flags: ::c_int) -> ::c_int; + pub fn mkostemp(template: *mut ::c_char, flags: ::c_int) -> ::c_int; + pub fn mkostemps(template: *mut ::c_char, + suffixlen: ::c_int, + flags: ::c_int) -> ::c_int; + pub fn sigtimedwait(set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const ::timespec) -> ::c_int; + pub fn sigwaitinfo(set: *const sigset_t, + info: *mut siginfo_t) -> ::c_int; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn pthread_setschedprio(native: ::pthread_t, + priority: ::c_int) -> ::c_int; + pub fn prlimit(pid: ::pid_t, resource: ::c_int, new_limit: *const ::rlimit, + old_limit: *mut ::rlimit) -> ::c_int; + pub fn prlimit64(pid: ::pid_t, + resource: ::c_int, + new_limit: *const ::rlimit64, + old_limit: *mut ::rlimit64) -> ::c_int; + pub fn getloadavg(loadavg: *mut ::c_double, nelem: ::c_int) -> ::c_int; + pub fn process_vm_readv(pid: ::pid_t, + local_iov: *const ::iovec, + liovcnt: ::c_ulong, + remote_iov: *const ::iovec, + riovcnt: ::c_ulong, + flags: ::c_ulong) -> isize; + pub fn process_vm_writev(pid: ::pid_t, + local_iov: *const ::iovec, + liovcnt: ::c_ulong, + remote_iov: *const ::iovec, + riovcnt: ::c_ulong, + flags: ::c_ulong) -> isize; + pub fn reboot(how_to: ::c_int) -> ::c_int; + pub fn setfsgid(gid: ::gid_t) -> ::c_int; + pub fn setfsuid(uid: ::uid_t) -> ::c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn sync_file_range(fd: ::c_int, offset: ::off64_t, + nbytes: ::off64_t, flags: ::c_uint) -> ::c_int; + pub fn mremap(addr: *mut ::c_void, + len: ::size_t, + new_len: ::size_t, + flags: ::c_int, + ...) -> *mut ::c_void; + + pub fn glob(pattern: *const c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + pub fn remap_file_pages(addr: *mut ::c_void, size: ::size_t, prot: ::c_int, + pgoff: ::size_t, flags: ::c_int) -> ::c_int; + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + pub fn futimes(fd: ::c_int, times: *const ::timeval) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + pub fn getdomainname(name: *mut ::c_char, len: ::size_t) -> ::c_int; + pub fn setdomainname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn vhangup() -> ::c_int; + pub fn sendmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int) -> ::c_int; + pub fn recvmmsg(sockfd: ::c_int, msgvec: *mut ::mmsghdr, vlen: ::c_uint, + flags: ::c_int, timeout: *mut ::timespec) -> ::c_int; + pub fn sync(); + pub fn syscall(num: ::c_long, ...) -> ::c_long; + pub fn sched_getaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *mut cpu_set_t) -> ::c_int; + pub fn sched_setaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *const cpu_set_t) -> ::c_int; + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + pub fn pthread_getschedparam(native: ::pthread_t, + policy: *mut ::c_int, + param: *mut ::sched_param) -> ::c_int; + pub fn unshare(flags: ::c_int) -> ::c_int; + pub fn umount(target: *const ::c_char) -> ::c_int; + pub fn sched_get_priority_max(policy: ::c_int) -> ::c_int; + pub fn tee(fd_in: ::c_int, + fd_out: ::c_int, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn settimeofday(tv: *const ::timeval, tz: *const ::timezone) -> ::c_int; + pub fn splice(fd_in: ::c_int, + off_in: *mut ::loff_t, + fd_out: ::c_int, + off_out: *mut ::loff_t, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int; + pub fn sched_rr_get_interval(pid: ::pid_t, tp: *mut ::timespec) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn sched_setparam(pid: ::pid_t, param: *const ::sched_param) -> ::c_int; + pub fn setns(fd: ::c_int, nstype: ::c_int) -> ::c_int; + pub fn swapoff(puath: *const ::c_char) -> ::c_int; + pub fn vmsplice(fd: ::c_int, + iov: *const ::iovec, + nr_segs: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + fstype: *const ::c_char, + flags: ::c_ulong, + data: *const ::c_void) -> ::c_int; + pub fn personality(persona: ::c_ulong) -> ::c_int; + pub fn prctl(option: ::c_int, ...) -> ::c_int; + pub fn sched_getparam(pid: ::pid_t, param: *mut ::sched_param) -> ::c_int; + pub fn ppoll(fds: *mut ::pollfd, + nfds: nfds_t, + timeout: *const ::timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn clone(cb: extern fn(*mut ::c_void) -> ::c_int, + child_stack: *mut ::c_void, + flags: ::c_int, + arg: *mut ::c_void, ...) -> ::c_int; + pub fn sched_getscheduler(pid: ::pid_t) -> ::c_int; + pub fn clock_nanosleep(clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn sched_get_priority_min(policy: ::c_int) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn sysinfo(info: *mut ::sysinfo) -> ::c_int; + pub fn umount2(target: *const ::c_char, flags: ::c_int) -> ::c_int; + pub fn pthread_setschedparam(native: ::pthread_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn swapon(path: *const ::c_char, swapflags: ::c_int) -> ::c_int; + pub fn sched_setscheduler(pid: ::pid_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn sendfile(out_fd: ::c_int, + in_fd: ::c_int, + offset: *mut off_t, + count: ::size_t) -> ::ssize_t; + pub fn sigsuspend(mask: *const ::sigset_t) -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + pub fn initgroups(user: *const ::c_char, group: ::gid_t) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_cancel(thread: ::pthread_t) -> ::c_int; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + pub fn getgrouplist(user: *const ::c_char, + group: ::gid_t, + groups: *mut ::gid_t, + ngroups: *mut ::c_int) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn faccessat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::c_int, flags: ::c_int) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn dl_iterate_phdr( + callback: ::Option ::c_int>, + data: *mut ::c_void + ) -> ::c_int; + + pub fn setmntent(filename: *const ::c_char, + ty: *const ::c_char) -> *mut ::FILE; + pub fn getmntent(stream: *mut ::FILE) -> *mut ::mntent; + pub fn addmntent(stream: *mut ::FILE, mnt: *const ::mntent) -> ::c_int; + pub fn endmntent(streamp: *mut ::FILE) -> ::c_int; + pub fn hasmntopt(mnt: *const ::mntent, + opt: *const ::c_char) -> *mut ::c_char; + + pub fn posix_spawn(pid: *mut ::pid_t, + path: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnp(pid: *mut ::pid_t, + file: *const ::c_char, + file_actions: *const ::posix_spawn_file_actions_t, + attrp: *const ::posix_spawnattr_t, + argv: *const *mut ::c_char, + envp: *const *mut ::c_char) -> ::c_int; + pub fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> ::c_int; + pub fn posix_spawnattr_getsigdefault(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigdefault(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getsigmask(attr: *const posix_spawnattr_t, + default: *mut ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_setsigmask(attr: *mut posix_spawnattr_t, + default: *const ::sigset_t) -> ::c_int; + pub fn posix_spawnattr_getflags(attr: *const posix_spawnattr_t, + flags: *mut ::c_short) -> ::c_int; + pub fn posix_spawnattr_setflags(attr: *mut posix_spawnattr_t, + flags: ::c_short) -> ::c_int; + pub fn posix_spawnattr_getpgroup(attr: *const posix_spawnattr_t, + flags: *mut ::pid_t) -> ::c_int; + pub fn posix_spawnattr_setpgroup(attr: *mut posix_spawnattr_t, + flags: ::pid_t) -> ::c_int; + pub fn posix_spawnattr_getschedpolicy(attr: *const posix_spawnattr_t, + flags: *mut ::c_int) -> ::c_int; + pub fn posix_spawnattr_setschedpolicy(attr: *mut posix_spawnattr_t, + flags: ::c_int) -> ::c_int; + pub fn posix_spawnattr_getschedparam( + attr: *const posix_spawnattr_t, + param: *mut ::sched_param, + ) -> ::c_int; + pub fn posix_spawnattr_setschedparam( + attr: *mut posix_spawnattr_t, + param: *const ::sched_param, + ) -> ::c_int; + + pub fn posix_spawn_file_actions_init( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_destroy( + actions: *mut posix_spawn_file_actions_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addopen( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + path: *const ::c_char, + oflag: ::c_int, + mode: ::mode_t, + ) -> ::c_int; + pub fn posix_spawn_file_actions_addclose( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + ) -> ::c_int; + pub fn posix_spawn_file_actions_adddup2( + actions: *mut posix_spawn_file_actions_t, + fd: ::c_int, + newfd: ::c_int, + ) -> ::c_int; + pub fn fread_unlocked(ptr: *mut ::c_void, + size: ::size_t, + nobj: ::size_t, + stream: *mut ::FILE + ) -> ::size_t; + pub fn inotify_rm_watch(fd: ::c_int, wd: ::c_int) -> ::c_int; + pub fn inotify_init() -> ::c_int; + pub fn inotify_init1(flags: ::c_int) -> ::c_int; + pub fn inotify_add_watch(fd: ::c_int, + path: *const ::c_char, + mask: ::uint32_t) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_env = "musl")] { + mod musl; + pub use self::musl::*; + } else if #[cfg(any(target_arch = "mips", + target_arch = "mips64"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(any(target_arch = "s390x"))] { + mod s390x; + pub use self::s390x::*; + } else { + mod other; + pub use self::other::*; + } +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} +expand_align!(); diff --git a/libc/src/unix/notbsd/linux/musl/b32/arm.rs b/libc/src/unix/notbsd/linux/musl/b32/arm.rs new file mode 100644 index 000000000..88d8798ec --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b32/arm.rs @@ -0,0 +1,843 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + __unused1: ::c_int, + pub shm_dtime: ::time_t, + __unused2: ::c_int, + pub shm_ctime: ::time_t, + __unused3: ::c_int, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + __unused1: ::c_int, + pub msg_rtime: ::time_t, + __unused2: ::c_int, + pub msg_ctime: ::time_t, + __unused3: ::c_int, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_LARGEFILE: ::c_int = 0o400000; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const EXTPROC: ::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const F_GETLK: ::c_int = 12; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 13; +pub const F_SETLKW: ::c_int = 14; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; + +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const TIOCGRS485: ::c_int = 0x542E; +pub const TIOCSRS485: ::c_int = 0x542F; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_pause: ::c_long = 29; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_pivot_root: ::c_long = 218; +pub const SYS_mincore: ::c_long = 219; +pub const SYS_madvise: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_io_setup: ::c_long = 243; +pub const SYS_io_destroy: ::c_long = 244; +pub const SYS_io_getevents: ::c_long = 245; +pub const SYS_io_submit: ::c_long = 246; +pub const SYS_io_cancel: ::c_long = 247; +pub const SYS_exit_group: ::c_long = 248; +pub const SYS_lookup_dcookie: ::c_long = 249; +pub const SYS_epoll_create: ::c_long = 250; +pub const SYS_epoll_ctl: ::c_long = 251; +pub const SYS_epoll_wait: ::c_long = 252; +pub const SYS_remap_file_pages: ::c_long = 253; +pub const SYS_set_tid_address: ::c_long = 256; +pub const SYS_timer_create: ::c_long = 257; +pub const SYS_timer_settime: ::c_long = 258; +pub const SYS_timer_gettime: ::c_long = 259; +pub const SYS_timer_getoverrun: ::c_long = 260; +pub const SYS_timer_delete: ::c_long = 261; +pub const SYS_clock_settime: ::c_long = 262; +pub const SYS_clock_gettime: ::c_long = 263; +pub const SYS_clock_getres: ::c_long = 264; +pub const SYS_clock_nanosleep: ::c_long = 265; +pub const SYS_statfs64: ::c_long = 266; +pub const SYS_fstatfs64: ::c_long = 267; +pub const SYS_tgkill: ::c_long = 268; +pub const SYS_utimes: ::c_long = 269; +pub const SYS_pciconfig_iobase: ::c_long = 271; +pub const SYS_pciconfig_read: ::c_long = 272; +pub const SYS_pciconfig_write: ::c_long = 273; +pub const SYS_mq_open: ::c_long = 274; +pub const SYS_mq_unlink: ::c_long = 275; +pub const SYS_mq_timedsend: ::c_long = 276; +pub const SYS_mq_timedreceive: ::c_long = 277; +pub const SYS_mq_notify: ::c_long = 278; +pub const SYS_mq_getsetattr: ::c_long = 279; +pub const SYS_waitid: ::c_long = 280; +pub const SYS_socket: ::c_long = 281; +pub const SYS_bind: ::c_long = 282; +pub const SYS_connect: ::c_long = 283; +pub const SYS_listen: ::c_long = 284; +pub const SYS_accept: ::c_long = 285; +pub const SYS_getsockname: ::c_long = 286; +pub const SYS_getpeername: ::c_long = 287; +pub const SYS_socketpair: ::c_long = 288; +pub const SYS_send: ::c_long = 289; +pub const SYS_sendto: ::c_long = 290; +pub const SYS_recv: ::c_long = 291; +pub const SYS_recvfrom: ::c_long = 292; +pub const SYS_shutdown: ::c_long = 293; +pub const SYS_setsockopt: ::c_long = 294; +pub const SYS_getsockopt: ::c_long = 295; +pub const SYS_sendmsg: ::c_long = 296; +pub const SYS_recvmsg: ::c_long = 297; +pub const SYS_semop: ::c_long = 298; +pub const SYS_semget: ::c_long = 299; +pub const SYS_semctl: ::c_long = 300; +pub const SYS_msgsnd: ::c_long = 301; +pub const SYS_msgrcv: ::c_long = 302; +pub const SYS_msgget: ::c_long = 303; +pub const SYS_msgctl: ::c_long = 304; +pub const SYS_shmat: ::c_long = 305; +pub const SYS_shmdt: ::c_long = 306; +pub const SYS_shmget: ::c_long = 307; +pub const SYS_shmctl: ::c_long = 308; +pub const SYS_add_key: ::c_long = 309; +pub const SYS_request_key: ::c_long = 310; +pub const SYS_keyctl: ::c_long = 311; +pub const SYS_semtimedop: ::c_long = 312; +pub const SYS_vserver: ::c_long = 313; +pub const SYS_ioprio_set: ::c_long = 314; +pub const SYS_ioprio_get: ::c_long = 315; +pub const SYS_inotify_init: ::c_long = 316; +pub const SYS_inotify_add_watch: ::c_long = 317; +pub const SYS_inotify_rm_watch: ::c_long = 318; +pub const SYS_mbind: ::c_long = 319; +pub const SYS_get_mempolicy: ::c_long = 320; +pub const SYS_set_mempolicy: ::c_long = 321; +pub const SYS_openat: ::c_long = 322; +pub const SYS_mkdirat: ::c_long = 323; +pub const SYS_mknodat: ::c_long = 324; +pub const SYS_fchownat: ::c_long = 325; +pub const SYS_futimesat: ::c_long = 326; +pub const SYS_fstatat64: ::c_long = 327; +pub const SYS_unlinkat: ::c_long = 328; +pub const SYS_renameat: ::c_long = 329; +pub const SYS_linkat: ::c_long = 330; +pub const SYS_symlinkat: ::c_long = 331; +pub const SYS_readlinkat: ::c_long = 332; +pub const SYS_fchmodat: ::c_long = 333; +pub const SYS_faccessat: ::c_long = 334; +pub const SYS_pselect6: ::c_long = 335; +pub const SYS_ppoll: ::c_long = 336; +pub const SYS_unshare: ::c_long = 337; +pub const SYS_set_robust_list: ::c_long = 338; +pub const SYS_get_robust_list: ::c_long = 339; +pub const SYS_splice: ::c_long = 340; +pub const SYS_tee: ::c_long = 342; +pub const SYS_vmsplice: ::c_long = 343; +pub const SYS_move_pages: ::c_long = 344; +pub const SYS_getcpu: ::c_long = 345; +pub const SYS_epoll_pwait: ::c_long = 346; +pub const SYS_kexec_load: ::c_long = 347; +pub const SYS_utimensat: ::c_long = 348; +pub const SYS_signalfd: ::c_long = 349; +pub const SYS_timerfd_create: ::c_long = 350; +pub const SYS_eventfd: ::c_long = 351; +pub const SYS_fallocate: ::c_long = 352; +pub const SYS_timerfd_settime: ::c_long = 353; +pub const SYS_timerfd_gettime: ::c_long = 354; +pub const SYS_signalfd4: ::c_long = 355; +pub const SYS_eventfd2: ::c_long = 356; +pub const SYS_epoll_create1: ::c_long = 357; +pub const SYS_dup3: ::c_long = 358; +pub const SYS_pipe2: ::c_long = 359; +pub const SYS_inotify_init1: ::c_long = 360; +pub const SYS_preadv: ::c_long = 361; +pub const SYS_pwritev: ::c_long = 362; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 363; +pub const SYS_perf_event_open: ::c_long = 364; +pub const SYS_recvmmsg: ::c_long = 365; +pub const SYS_accept4: ::c_long = 366; +pub const SYS_fanotify_init: ::c_long = 367; +pub const SYS_fanotify_mark: ::c_long = 368; +pub const SYS_prlimit64: ::c_long = 369; +pub const SYS_name_to_handle_at: ::c_long = 370; +pub const SYS_open_by_handle_at: ::c_long = 371; +pub const SYS_clock_adjtime: ::c_long = 372; +pub const SYS_syncfs: ::c_long = 373; +pub const SYS_sendmmsg: ::c_long = 374; +pub const SYS_setns: ::c_long = 375; +pub const SYS_process_vm_readv: ::c_long = 376; +pub const SYS_process_vm_writev: ::c_long = 377; +pub const SYS_kcmp: ::c_long = 378; +pub const SYS_finit_module: ::c_long = 379; +pub const SYS_sched_setattr: ::c_long = 380; +pub const SYS_sched_getattr: ::c_long = 381; +pub const SYS_renameat2: ::c_long = 382; +pub const SYS_seccomp: ::c_long = 383; +pub const SYS_getrandom: ::c_long = 384; +pub const SYS_memfd_create: ::c_long = 385; +pub const SYS_bpf: ::c_long = 386; +pub const SYS_execveat: ::c_long = 387; +pub const SYS_userfaultfd: ::c_long = 388; +pub const SYS_membarrier: ::c_long = 389; +pub const SYS_mlock2: ::c_long = 390; +pub const SYS_copy_file_range: ::c_long = 391; +pub const SYS_preadv2: ::c_long = 392; +pub const SYS_pwritev2: ::c_long = 393; +pub const SYS_pkey_mprotect: ::c_long = 394; +pub const SYS_pkey_alloc: ::c_long = 395; +pub const SYS_pkey_free: ::c_long = 396; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; diff --git a/libc/src/unix/notbsd/linux/musl/b32/mips.rs b/libc/src/unix/notbsd/linux/musl/b32/mips.rs new file mode 100644 index 000000000..37430af5f --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b32/mips.rs @@ -0,0 +1,853 @@ +pub type c_char = i8; +pub type wchar_t = ::c_int; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + __st_padding1: [::c_long; 2], + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_padding2: [::c_long; 2], + pub st_size: ::off_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + __st_padding3: ::c_long, + pub st_blocks: ::blkcnt_t, + __st_padding4: [::c_long; 14], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __st_padding1: [::c_long; 2], + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_padding2: [::c_long; 2], + pub st_size: ::off_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + __st_padding3: ::c_long, + pub st_blocks: ::blkcnt64_t, + __st_padding4: [::c_long; 14], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + #[cfg(target_endian = "big")] + __unused1: ::c_int, + pub msg_stime: ::time_t, + #[cfg(target_endian = "little")] + __unused1: ::c_int, + #[cfg(target_endian = "big")] + __unused2: ::c_int, + pub msg_rtime: ::time_t, + #[cfg(target_endian = "little")] + __unused2: ::c_int, + #[cfg(target_endian = "big")] + __unused3: ::c_int, + pub msg_ctime: ::time_t, + #[cfg(target_endian = "little")] + __unused3: ::c_int, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 5], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 5], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + #[cfg(target_endian = "little")] + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + #[cfg(target_endian = "big")] + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 23], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +pub const O_DIRECT: ::c_int = 0o100000; +pub const O_DIRECTORY: ::c_int = 0o200000; +pub const O_NOFOLLOW: ::c_int = 0o400000; +pub const O_ASYNC: ::c_int = 0o10000; +pub const O_LARGEFILE: ::c_int = 0x2000; + +pub const FIOCLEX: ::c_int = 0x6601; +pub const FIONBIO: ::c_int = 0x667E; + +pub const RLIMIT_RSS: ::c_int = 7; +pub const RLIMIT_NOFILE: ::c_int = 5; +pub const RLIMIT_AS: ::c_int = 6; +pub const RLIMIT_NPROC: ::c_int = 8; +pub const RLIMIT_MEMLOCK: ::c_int = 9; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const O_APPEND: ::c_int = 0o010; +pub const O_CREAT: ::c_int = 0o400; +pub const O_EXCL: ::c_int = 0o2000; +pub const O_NOCTTY: ::c_int = 0o4000; +pub const O_NONBLOCK: ::c_int = 0o200; +pub const O_SYNC: ::c_int = 0o40020; +pub const O_RSYNC: ::c_int = 0o40020; +pub const O_DSYNC: ::c_int = 0o020; + +pub const SOCK_NONBLOCK: ::c_int = 0o200; + +pub const MAP_ANON: ::c_int = 0x800; +pub const MAP_GROWSDOWN: ::c_int = 0x1000; +pub const MAP_DENYWRITE: ::c_int = 0x2000; +pub const MAP_EXECUTABLE: ::c_int = 0x4000; +pub const MAP_LOCKED: ::c_int = 0x8000; +pub const MAP_NORESERVE: ::c_int = 0x0400; +pub const MAP_POPULATE: ::c_int = 0x10000; +pub const MAP_NONBLOCK: ::c_int = 0x20000; +pub const MAP_STACK: ::c_int = 0x40000; + +pub const EDEADLK: ::c_int = 45; +pub const ENAMETOOLONG: ::c_int = 78; +pub const ENOLCK: ::c_int = 46; +pub const ENOSYS: ::c_int = 89; +pub const ENOTEMPTY: ::c_int = 93; +pub const ELOOP: ::c_int = 90; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const ECHRNG: ::c_int = 37; +pub const EL2NSYNC: ::c_int = 38; +pub const EL3HLT: ::c_int = 39; +pub const EL3RST: ::c_int = 40; +pub const ELNRNG: ::c_int = 41; +pub const EUNATCH: ::c_int = 42; +pub const ENOCSI: ::c_int = 43; +pub const EL2HLT: ::c_int = 44; +pub const EBADE: ::c_int = 50; +pub const EBADR: ::c_int = 51; +pub const EXFULL: ::c_int = 52; +pub const ENOANO: ::c_int = 53; +pub const EBADRQC: ::c_int = 54; +pub const EBADSLT: ::c_int = 55; +pub const EDEADLOCK: ::c_int = 56; +pub const EMULTIHOP: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 79; +pub const ENOTUNIQ: ::c_int = 80; +pub const EBADFD: ::c_int = 81; +pub const EBADMSG: ::c_int = 77; +pub const EREMCHG: ::c_int = 82; +pub const ELIBACC: ::c_int = 83; +pub const ELIBBAD: ::c_int = 84; +pub const ELIBSCN: ::c_int = 85; +pub const ELIBMAX: ::c_int = 86; +pub const ELIBEXEC: ::c_int = 87; +pub const EILSEQ: ::c_int = 88; +pub const ERESTART: ::c_int = 91; +pub const ESTRPIPE: ::c_int = 92; +pub const EUSERS: ::c_int = 94; +pub const ENOTSOCK: ::c_int = 95; +pub const EDESTADDRREQ: ::c_int = 96; +pub const EMSGSIZE: ::c_int = 97; +pub const EPROTOTYPE: ::c_int = 98; +pub const ENOPROTOOPT: ::c_int = 99; +pub const EPROTONOSUPPORT: ::c_int = 120; +pub const ESOCKTNOSUPPORT: ::c_int = 121; +pub const EOPNOTSUPP: ::c_int = 122; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 123; +pub const EAFNOSUPPORT: ::c_int = 124; +pub const EADDRINUSE: ::c_int = 125; +pub const EADDRNOTAVAIL: ::c_int = 126; +pub const ENETDOWN: ::c_int = 127; +pub const ENETUNREACH: ::c_int = 128; +pub const ENETRESET: ::c_int = 129; +pub const ECONNABORTED: ::c_int = 130; +pub const ECONNRESET: ::c_int = 131; +pub const ENOBUFS: ::c_int = 132; +pub const EISCONN: ::c_int = 133; +pub const ENOTCONN: ::c_int = 134; +pub const ESHUTDOWN: ::c_int = 143; +pub const ETOOMANYREFS: ::c_int = 144; +pub const ETIMEDOUT: ::c_int = 145; +pub const ECONNREFUSED: ::c_int = 146; +pub const EHOSTDOWN: ::c_int = 147; +pub const EHOSTUNREACH: ::c_int = 148; +pub const EALREADY: ::c_int = 149; +pub const EINPROGRESS: ::c_int = 150; +pub const ESTALE: ::c_int = 151; +pub const EUCLEAN: ::c_int = 135; +pub const ENOTNAM: ::c_int = 137; +pub const ENAVAIL: ::c_int = 138; +pub const EISNAM: ::c_int = 139; +pub const EREMOTEIO: ::c_int = 140; +pub const EDQUOT: ::c_int = 1133; +pub const ENOMEDIUM: ::c_int = 159; +pub const EMEDIUMTYPE: ::c_int = 160; +pub const ECANCELED: ::c_int = 158; +pub const ENOKEY: ::c_int = 161; +pub const EKEYEXPIRED: ::c_int = 162; +pub const EKEYREVOKED: ::c_int = 163; +pub const EKEYREJECTED: ::c_int = 164; +pub const EOWNERDEAD: ::c_int = 165; +pub const ENOTRECOVERABLE: ::c_int = 166; +pub const EHWPOISON: ::c_int = 168; +pub const ERFKILL: ::c_int = 167; + +pub const SOCK_STREAM: ::c_int = 2; +pub const SOCK_DGRAM: ::c_int = 1; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 65535; + +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_ACCEPTCONN: ::c_int = 0x1009; +pub const SO_PROTOCOL: ::c_int = 0x1028; +pub const SO_DOMAIN: ::c_int = 0x1029; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_PASSCRED: ::c_int = 17; +pub const SO_PEERCRED: ::c_int = 18; +pub const SO_SNDBUFFORCE: ::c_int = 31; +pub const SO_RCVBUFFORCE: ::c_int = 33; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 8; +pub const SA_NOCLDWAIT: ::c_int = 0x10000; + +pub const SIGCHLD: ::c_int = 18; +pub const SIGBUS: ::c_int = 10; +pub const SIGTTIN: ::c_int = 26; +pub const SIGTTOU: ::c_int = 27; +pub const SIGXCPU: ::c_int = 30; +pub const SIGXFSZ: ::c_int = 31; +pub const SIGVTALRM: ::c_int = 28; +pub const SIGPROF: ::c_int = 29; +pub const SIGWINCH: ::c_int = 20; +pub const SIGUSR1: ::c_int = 16; +pub const SIGUSR2: ::c_int = 17; +pub const SIGCONT: ::c_int = 25; +pub const SIGSTOP: ::c_int = 23; +pub const SIGTSTP: ::c_int = 24; +pub const SIGURG: ::c_int = 21; +pub const SIGIO: ::c_int = 22; +pub const SIGSYS: ::c_int = 12; +pub const SIGSTKFLT: ::c_int = 7; +pub const SIGPOLL: ::c_int = ::SIGIO; +pub const SIGPWR: ::c_int = 19; +pub const SIG_SETMASK: ::c_int = 3; +pub const SIG_BLOCK: ::c_int = 1; +pub const SIG_UNBLOCK: ::c_int = 2; + +pub const EXTPROC: ::tcflag_t = 0o200000; + +pub const MAP_HUGETLB: ::c_int = 0x80000; + +pub const F_GETLK: ::c_int = 33; +pub const F_GETOWN: ::c_int = 23; +pub const F_SETLK: ::c_int = 34; +pub const F_SETLKW: ::c_int = 35; +pub const F_SETOWN: ::c_int = 24; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: ::tcflag_t = 0o000400; +pub const TOSTOP: ::tcflag_t = 0o100000; +pub const FLUSHO: ::tcflag_t = 0o020000; + +pub const TCGETS: ::c_int = 0x540D; +pub const TCSETS: ::c_int = 0x540E; +pub const TCSETSW: ::c_int = 0x540F; +pub const TCSETSF: ::c_int = 0x5410; +pub const TCGETA: ::c_int = 0x5401; +pub const TCSETA: ::c_int = 0x5402; +pub const TCSETAW: ::c_int = 0x5403; +pub const TCSETAF: ::c_int = 0x5404; +pub const TCSBRK: ::c_int = 0x5405; +pub const TCXONC: ::c_int = 0x5406; +pub const TCFLSH: ::c_int = 0x5407; +pub const TIOCGSOFTCAR: ::c_int = 0x5481; +pub const TIOCSSOFTCAR: ::c_int = 0x5482; +pub const TIOCLINUX: ::c_int = 0x5483; +pub const TIOCGSERIAL: ::c_int = 0x5484; +pub const TIOCEXCL: ::c_int = 0x740D; +pub const TIOCNXCL: ::c_int = 0x740E; +pub const TIOCSCTTY: ::c_int = 0x5480; +pub const TIOCGPGRP: ::c_int = 0x40047477; +pub const TIOCSPGRP: ::c_int = 0x80047476; +pub const TIOCOUTQ: ::c_int = 0x7472; +pub const TIOCSTI: ::c_int = 0x5472; +pub const TIOCGWINSZ: ::c_int = 0x40087468; +pub const TIOCSWINSZ: ::c_int = 0x80087467; +pub const TIOCMGET: ::c_int = 0x741D; +pub const TIOCMBIS: ::c_int = 0x741B; +pub const TIOCMBIC: ::c_int = 0x741C; +pub const TIOCMSET: ::c_int = 0x741A; +pub const FIONREAD: ::c_int = 0x467F; +pub const TIOCCONS: ::c_int = 0x80047478; + +pub const TIOCGRS485: ::c_int = 0x4020542E; +pub const TIOCSRS485: ::c_int = 0xC020542F; + +pub const POLLWRNORM: ::c_short = 0x4; +pub const POLLWRBAND: ::c_short = 0x100; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x010; +pub const TIOCM_SR: ::c_int = 0x020; +pub const TIOCM_CTS: ::c_int = 0x040; +pub const TIOCM_CAR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RNG: ::c_int = 0x200; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; +pub const TIOCM_DSR: ::c_int = 0x400; + +pub const SYS_syscall: ::c_long = 4000 + 0; +pub const SYS_exit: ::c_long = 4000 + 1; +pub const SYS_fork: ::c_long = 4000 + 2; +pub const SYS_read: ::c_long = 4000 + 3; +pub const SYS_write: ::c_long = 4000 + 4; +pub const SYS_open: ::c_long = 4000 + 5; +pub const SYS_close: ::c_long = 4000 + 6; +pub const SYS_waitpid: ::c_long = 4000 + 7; +pub const SYS_creat: ::c_long = 4000 + 8; +pub const SYS_link: ::c_long = 4000 + 9; +pub const SYS_unlink: ::c_long = 4000 + 10; +pub const SYS_execve: ::c_long = 4000 + 11; +pub const SYS_chdir: ::c_long = 4000 + 12; +pub const SYS_time: ::c_long = 4000 + 13; +pub const SYS_mknod: ::c_long = 4000 + 14; +pub const SYS_chmod: ::c_long = 4000 + 15; +pub const SYS_lchown: ::c_long = 4000 + 16; +pub const SYS_break: ::c_long = 4000 + 17; +pub const SYS_lseek: ::c_long = 4000 + 19; +pub const SYS_getpid: ::c_long = 4000 + 20; +pub const SYS_mount: ::c_long = 4000 + 21; +pub const SYS_umount: ::c_long = 4000 + 22; +pub const SYS_setuid: ::c_long = 4000 + 23; +pub const SYS_getuid: ::c_long = 4000 + 24; +pub const SYS_stime: ::c_long = 4000 + 25; +pub const SYS_ptrace: ::c_long = 4000 + 26; +pub const SYS_alarm: ::c_long = 4000 + 27; +pub const SYS_pause: ::c_long = 4000 + 29; +pub const SYS_utime: ::c_long = 4000 + 30; +pub const SYS_stty: ::c_long = 4000 + 31; +pub const SYS_gtty: ::c_long = 4000 + 32; +pub const SYS_access: ::c_long = 4000 + 33; +pub const SYS_nice: ::c_long = 4000 + 34; +pub const SYS_ftime: ::c_long = 4000 + 35; +pub const SYS_sync: ::c_long = 4000 + 36; +pub const SYS_kill: ::c_long = 4000 + 37; +pub const SYS_rename: ::c_long = 4000 + 38; +pub const SYS_mkdir: ::c_long = 4000 + 39; +pub const SYS_rmdir: ::c_long = 4000 + 40; +pub const SYS_dup: ::c_long = 4000 + 41; +pub const SYS_pipe: ::c_long = 4000 + 42; +pub const SYS_times: ::c_long = 4000 + 43; +pub const SYS_prof: ::c_long = 4000 + 44; +pub const SYS_brk: ::c_long = 4000 + 45; +pub const SYS_setgid: ::c_long = 4000 + 46; +pub const SYS_getgid: ::c_long = 4000 + 47; +pub const SYS_signal: ::c_long = 4000 + 48; +pub const SYS_geteuid: ::c_long = 4000 + 49; +pub const SYS_getegid: ::c_long = 4000 + 50; +pub const SYS_acct: ::c_long = 4000 + 51; +pub const SYS_umount2: ::c_long = 4000 + 52; +pub const SYS_lock: ::c_long = 4000 + 53; +pub const SYS_ioctl: ::c_long = 4000 + 54; +pub const SYS_fcntl: ::c_long = 4000 + 55; +pub const SYS_mpx: ::c_long = 4000 + 56; +pub const SYS_setpgid: ::c_long = 4000 + 57; +pub const SYS_ulimit: ::c_long = 4000 + 58; +pub const SYS_umask: ::c_long = 4000 + 60; +pub const SYS_chroot: ::c_long = 4000 + 61; +pub const SYS_ustat: ::c_long = 4000 + 62; +pub const SYS_dup2: ::c_long = 4000 + 63; +pub const SYS_getppid: ::c_long = 4000 + 64; +pub const SYS_getpgrp: ::c_long = 4000 + 65; +pub const SYS_setsid: ::c_long = 4000 + 66; +pub const SYS_sigaction: ::c_long = 4000 + 67; +pub const SYS_sgetmask: ::c_long = 4000 + 68; +pub const SYS_ssetmask: ::c_long = 4000 + 69; +pub const SYS_setreuid: ::c_long = 4000 + 70; +pub const SYS_setregid: ::c_long = 4000 + 71; +pub const SYS_sigsuspend: ::c_long = 4000 + 72; +pub const SYS_sigpending: ::c_long = 4000 + 73; +pub const SYS_sethostname: ::c_long = 4000 + 74; +pub const SYS_setrlimit: ::c_long = 4000 + 75; +pub const SYS_getrlimit: ::c_long = 4000 + 76; +pub const SYS_getrusage: ::c_long = 4000 + 77; +pub const SYS_gettimeofday: ::c_long = 4000 + 78; +pub const SYS_settimeofday: ::c_long = 4000 + 79; +pub const SYS_getgroups: ::c_long = 4000 + 80; +pub const SYS_setgroups: ::c_long = 4000 + 81; +pub const SYS_symlink: ::c_long = 4000 + 83; +pub const SYS_readlink: ::c_long = 4000 + 85; +pub const SYS_uselib: ::c_long = 4000 + 86; +pub const SYS_swapon: ::c_long = 4000 + 87; +pub const SYS_reboot: ::c_long = 4000 + 88; +pub const SYS_readdir: ::c_long = 4000 + 89; +pub const SYS_mmap: ::c_long = 4000 + 90; +pub const SYS_munmap: ::c_long = 4000 + 91; +pub const SYS_truncate: ::c_long = 4000 + 92; +pub const SYS_ftruncate: ::c_long = 4000 + 93; +pub const SYS_fchmod: ::c_long = 4000 + 94; +pub const SYS_fchown: ::c_long = 4000 + 95; +pub const SYS_getpriority: ::c_long = 4000 + 96; +pub const SYS_setpriority: ::c_long = 4000 + 97; +pub const SYS_profil: ::c_long = 4000 + 98; +pub const SYS_statfs: ::c_long = 4000 + 99; +pub const SYS_fstatfs: ::c_long = 4000 + 100; +pub const SYS_ioperm: ::c_long = 4000 + 101; +pub const SYS_socketcall: ::c_long = 4000 + 102; +pub const SYS_syslog: ::c_long = 4000 + 103; +pub const SYS_setitimer: ::c_long = 4000 + 104; +pub const SYS_getitimer: ::c_long = 4000 + 105; +pub const SYS_stat: ::c_long = 4000 + 106; +pub const SYS_lstat: ::c_long = 4000 + 107; +pub const SYS_fstat: ::c_long = 4000 + 108; +pub const SYS_iopl: ::c_long = 4000 + 110; +pub const SYS_vhangup: ::c_long = 4000 + 111; +pub const SYS_idle: ::c_long = 4000 + 112; +pub const SYS_vm86: ::c_long = 4000 + 113; +pub const SYS_wait4: ::c_long = 4000 + 114; +pub const SYS_swapoff: ::c_long = 4000 + 115; +pub const SYS_sysinfo: ::c_long = 4000 + 116; +pub const SYS_ipc: ::c_long = 4000 + 117; +pub const SYS_fsync: ::c_long = 4000 + 118; +pub const SYS_sigreturn: ::c_long = 4000 + 119; +pub const SYS_clone: ::c_long = 4000 + 120; +pub const SYS_setdomainname: ::c_long = 4000 + 121; +pub const SYS_uname: ::c_long = 4000 + 122; +pub const SYS_modify_ldt: ::c_long = 4000 + 123; +pub const SYS_adjtimex: ::c_long = 4000 + 124; +pub const SYS_mprotect: ::c_long = 4000 + 125; +pub const SYS_sigprocmask: ::c_long = 4000 + 126; +pub const SYS_create_module: ::c_long = 4000 + 127; +pub const SYS_init_module: ::c_long = 4000 + 128; +pub const SYS_delete_module: ::c_long = 4000 + 129; +pub const SYS_get_kernel_syms: ::c_long = 4000 + 130; +pub const SYS_quotactl: ::c_long = 4000 + 131; +pub const SYS_getpgid: ::c_long = 4000 + 132; +pub const SYS_fchdir: ::c_long = 4000 + 133; +pub const SYS_bdflush: ::c_long = 4000 + 134; +pub const SYS_sysfs: ::c_long = 4000 + 135; +pub const SYS_personality: ::c_long = 4000 + 136; +pub const SYS_afs_syscall: ::c_long = 4000 + 137; +pub const SYS_setfsuid: ::c_long = 4000 + 138; +pub const SYS_setfsgid: ::c_long = 4000 + 139; +pub const SYS__llseek: ::c_long = 4000 + 140; +pub const SYS_getdents: ::c_long = 4000 + 141; +pub const SYS_flock: ::c_long = 4000 + 143; +pub const SYS_msync: ::c_long = 4000 + 144; +pub const SYS_readv: ::c_long = 4000 + 145; +pub const SYS_writev: ::c_long = 4000 + 146; +pub const SYS_cacheflush: ::c_long = 4000 + 147; +pub const SYS_cachectl: ::c_long = 4000 + 148; +pub const SYS_sysmips: ::c_long = 4000 + 149; +pub const SYS_getsid: ::c_long = 4000 + 151; +pub const SYS_fdatasync: ::c_long = 4000 + 152; +pub const SYS__sysctl: ::c_long = 4000 + 153; +pub const SYS_mlock: ::c_long = 4000 + 154; +pub const SYS_munlock: ::c_long = 4000 + 155; +pub const SYS_mlockall: ::c_long = 4000 + 156; +pub const SYS_munlockall: ::c_long = 4000 + 157; +pub const SYS_sched_setparam: ::c_long = 4000 + 158; +pub const SYS_sched_getparam: ::c_long = 4000 + 159; +pub const SYS_sched_setscheduler: ::c_long = 4000 + 160; +pub const SYS_sched_getscheduler: ::c_long = 4000 + 161; +pub const SYS_sched_yield: ::c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: ::c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: ::c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: ::c_long = 4000 + 165; +pub const SYS_nanosleep: ::c_long = 4000 + 166; +pub const SYS_mremap: ::c_long = 4000 + 167; +pub const SYS_accept: ::c_long = 4000 + 168; +pub const SYS_bind: ::c_long = 4000 + 169; +pub const SYS_connect: ::c_long = 4000 + 170; +pub const SYS_getpeername: ::c_long = 4000 + 171; +pub const SYS_getsockname: ::c_long = 4000 + 172; +pub const SYS_getsockopt: ::c_long = 4000 + 173; +pub const SYS_listen: ::c_long = 4000 + 174; +pub const SYS_recv: ::c_long = 4000 + 175; +pub const SYS_recvfrom: ::c_long = 4000 + 176; +pub const SYS_recvmsg: ::c_long = 4000 + 177; +pub const SYS_send: ::c_long = 4000 + 178; +pub const SYS_sendmsg: ::c_long = 4000 + 179; +pub const SYS_sendto: ::c_long = 4000 + 180; +pub const SYS_setsockopt: ::c_long = 4000 + 181; +pub const SYS_shutdown: ::c_long = 4000 + 182; +pub const SYS_socket: ::c_long = 4000 + 183; +pub const SYS_socketpair: ::c_long = 4000 + 184; +pub const SYS_setresuid: ::c_long = 4000 + 185; +pub const SYS_getresuid: ::c_long = 4000 + 186; +pub const SYS_query_module: ::c_long = 4000 + 187; +pub const SYS_poll: ::c_long = 4000 + 188; +pub const SYS_nfsservctl: ::c_long = 4000 + 189; +pub const SYS_setresgid: ::c_long = 4000 + 190; +pub const SYS_getresgid: ::c_long = 4000 + 191; +pub const SYS_prctl: ::c_long = 4000 + 192; +pub const SYS_rt_sigreturn: ::c_long = 4000 + 193; +pub const SYS_rt_sigaction: ::c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: ::c_long = 4000 + 195; +pub const SYS_rt_sigpending: ::c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: ::c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: ::c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: ::c_long = 4000 + 199; +pub const SYS_chown: ::c_long = 4000 + 202; +pub const SYS_getcwd: ::c_long = 4000 + 203; +pub const SYS_capget: ::c_long = 4000 + 204; +pub const SYS_capset: ::c_long = 4000 + 205; +pub const SYS_sigaltstack: ::c_long = 4000 + 206; +pub const SYS_sendfile: ::c_long = 4000 + 207; +pub const SYS_getpmsg: ::c_long = 4000 + 208; +pub const SYS_putpmsg: ::c_long = 4000 + 209; +pub const SYS_mmap2: ::c_long = 4000 + 210; +pub const SYS_truncate64: ::c_long = 4000 + 211; +pub const SYS_ftruncate64: ::c_long = 4000 + 212; +pub const SYS_stat64: ::c_long = 4000 + 213; +pub const SYS_lstat64: ::c_long = 4000 + 214; +pub const SYS_fstat64: ::c_long = 4000 + 215; +pub const SYS_pivot_root: ::c_long = 4000 + 216; +pub const SYS_mincore: ::c_long = 4000 + 217; +pub const SYS_madvise: ::c_long = 4000 + 218; +pub const SYS_getdents64: ::c_long = 4000 + 219; +pub const SYS_fcntl64: ::c_long = 4000 + 220; +pub const SYS_gettid: ::c_long = 4000 + 222; +pub const SYS_readahead: ::c_long = 4000 + 223; +pub const SYS_setxattr: ::c_long = 4000 + 224; +pub const SYS_lsetxattr: ::c_long = 4000 + 225; +pub const SYS_fsetxattr: ::c_long = 4000 + 226; +pub const SYS_getxattr: ::c_long = 4000 + 227; +pub const SYS_lgetxattr: ::c_long = 4000 + 228; +pub const SYS_fgetxattr: ::c_long = 4000 + 229; +pub const SYS_listxattr: ::c_long = 4000 + 230; +pub const SYS_llistxattr: ::c_long = 4000 + 231; +pub const SYS_flistxattr: ::c_long = 4000 + 232; +pub const SYS_removexattr: ::c_long = 4000 + 233; +pub const SYS_lremovexattr: ::c_long = 4000 + 234; +pub const SYS_fremovexattr: ::c_long = 4000 + 235; +pub const SYS_tkill: ::c_long = 4000 + 236; +pub const SYS_sendfile64: ::c_long = 4000 + 237; +pub const SYS_futex: ::c_long = 4000 + 238; +pub const SYS_sched_setaffinity: ::c_long = 4000 + 239; +pub const SYS_sched_getaffinity: ::c_long = 4000 + 240; +pub const SYS_io_setup: ::c_long = 4000 + 241; +pub const SYS_io_destroy: ::c_long = 4000 + 242; +pub const SYS_io_getevents: ::c_long = 4000 + 243; +pub const SYS_io_submit: ::c_long = 4000 + 244; +pub const SYS_io_cancel: ::c_long = 4000 + 245; +pub const SYS_exit_group: ::c_long = 4000 + 246; +pub const SYS_lookup_dcookie: ::c_long = 4000 + 247; +pub const SYS_epoll_create: ::c_long = 4000 + 248; +pub const SYS_epoll_ctl: ::c_long = 4000 + 249; +pub const SYS_epoll_wait: ::c_long = 4000 + 250; +pub const SYS_remap_file_pages: ::c_long = 4000 + 251; +pub const SYS_set_tid_address: ::c_long = 4000 + 252; +pub const SYS_restart_syscall: ::c_long = 4000 + 253; +pub const SYS_statfs64: ::c_long = 4000 + 255; +pub const SYS_fstatfs64: ::c_long = 4000 + 256; +pub const SYS_timer_create: ::c_long = 4000 + 257; +pub const SYS_timer_settime: ::c_long = 4000 + 258; +pub const SYS_timer_gettime: ::c_long = 4000 + 259; +pub const SYS_timer_getoverrun: ::c_long = 4000 + 260; +pub const SYS_timer_delete: ::c_long = 4000 + 261; +pub const SYS_clock_settime: ::c_long = 4000 + 262; +pub const SYS_clock_gettime: ::c_long = 4000 + 263; +pub const SYS_clock_getres: ::c_long = 4000 + 264; +pub const SYS_clock_nanosleep: ::c_long = 4000 + 265; +pub const SYS_tgkill: ::c_long = 4000 + 266; +pub const SYS_utimes: ::c_long = 4000 + 267; +pub const SYS_mbind: ::c_long = 4000 + 268; +pub const SYS_get_mempolicy: ::c_long = 4000 + 269; +pub const SYS_set_mempolicy: ::c_long = 4000 + 270; +pub const SYS_mq_open: ::c_long = 4000 + 271; +pub const SYS_mq_unlink: ::c_long = 4000 + 272; +pub const SYS_mq_timedsend: ::c_long = 4000 + 273; +pub const SYS_mq_timedreceive: ::c_long = 4000 + 274; +pub const SYS_mq_notify: ::c_long = 4000 + 275; +pub const SYS_mq_getsetattr: ::c_long = 4000 + 276; +pub const SYS_vserver: ::c_long = 4000 + 277; +pub const SYS_waitid: ::c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: ::c_long = 4000 + 279; */ +pub const SYS_add_key: ::c_long = 4000 + 280; +pub const SYS_request_key: ::c_long = 4000 + 281; +pub const SYS_keyctl: ::c_long = 4000 + 282; +pub const SYS_set_thread_area: ::c_long = 4000 + 283; +pub const SYS_inotify_init: ::c_long = 4000 + 284; +pub const SYS_inotify_add_watch: ::c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: ::c_long = 4000 + 286; +pub const SYS_migrate_pages: ::c_long = 4000 + 287; +pub const SYS_openat: ::c_long = 4000 + 288; +pub const SYS_mkdirat: ::c_long = 4000 + 289; +pub const SYS_mknodat: ::c_long = 4000 + 290; +pub const SYS_fchownat: ::c_long = 4000 + 291; +pub const SYS_futimesat: ::c_long = 4000 + 292; +pub const SYS_unlinkat: ::c_long = 4000 + 294; +pub const SYS_renameat: ::c_long = 4000 + 295; +pub const SYS_linkat: ::c_long = 4000 + 296; +pub const SYS_symlinkat: ::c_long = 4000 + 297; +pub const SYS_readlinkat: ::c_long = 4000 + 298; +pub const SYS_fchmodat: ::c_long = 4000 + 299; +pub const SYS_faccessat: ::c_long = 4000 + 300; +pub const SYS_pselect6: ::c_long = 4000 + 301; +pub const SYS_ppoll: ::c_long = 4000 + 302; +pub const SYS_unshare: ::c_long = 4000 + 303; +pub const SYS_splice: ::c_long = 4000 + 304; +pub const SYS_sync_file_range: ::c_long = 4000 + 305; +pub const SYS_tee: ::c_long = 4000 + 306; +pub const SYS_vmsplice: ::c_long = 4000 + 307; +pub const SYS_move_pages: ::c_long = 4000 + 308; +pub const SYS_set_robust_list: ::c_long = 4000 + 309; +pub const SYS_get_robust_list: ::c_long = 4000 + 310; +pub const SYS_kexec_load: ::c_long = 4000 + 311; +pub const SYS_getcpu: ::c_long = 4000 + 312; +pub const SYS_epoll_pwait: ::c_long = 4000 + 313; +pub const SYS_ioprio_set: ::c_long = 4000 + 314; +pub const SYS_ioprio_get: ::c_long = 4000 + 315; +pub const SYS_utimensat: ::c_long = 4000 + 316; +pub const SYS_signalfd: ::c_long = 4000 + 317; +pub const SYS_timerfd: ::c_long = 4000 + 318; +pub const SYS_eventfd: ::c_long = 4000 + 319; +pub const SYS_fallocate: ::c_long = 4000 + 320; +pub const SYS_timerfd_create: ::c_long = 4000 + 321; +pub const SYS_timerfd_gettime: ::c_long = 4000 + 322; +pub const SYS_timerfd_settime: ::c_long = 4000 + 323; +pub const SYS_signalfd4: ::c_long = 4000 + 324; +pub const SYS_eventfd2: ::c_long = 4000 + 325; +pub const SYS_epoll_create1: ::c_long = 4000 + 326; +pub const SYS_dup3: ::c_long = 4000 + 327; +pub const SYS_pipe2: ::c_long = 4000 + 328; +pub const SYS_inotify_init1: ::c_long = 4000 + 329; +pub const SYS_preadv: ::c_long = 4000 + 330; +pub const SYS_pwritev: ::c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 4000 + 332; +pub const SYS_perf_event_open: ::c_long = 4000 + 333; +pub const SYS_accept4: ::c_long = 4000 + 334; +pub const SYS_recvmmsg: ::c_long = 4000 + 335; +pub const SYS_fanotify_init: ::c_long = 4000 + 336; +pub const SYS_fanotify_mark: ::c_long = 4000 + 337; +pub const SYS_prlimit64: ::c_long = 4000 + 338; +pub const SYS_name_to_handle_at: ::c_long = 4000 + 339; +pub const SYS_open_by_handle_at: ::c_long = 4000 + 340; +pub const SYS_clock_adjtime: ::c_long = 4000 + 341; +pub const SYS_syncfs: ::c_long = 4000 + 342; +pub const SYS_sendmmsg: ::c_long = 4000 + 343; +pub const SYS_setns: ::c_long = 4000 + 344; +pub const SYS_process_vm_readv: ::c_long = 4000 + 345; +pub const SYS_process_vm_writev: ::c_long = 4000 + 346; +pub const SYS_kcmp: ::c_long = 4000 + 347; +pub const SYS_finit_module: ::c_long = 4000 + 348; +pub const SYS_sched_setattr: ::c_long = 4000 + 349; +pub const SYS_sched_getattr: ::c_long = 4000 + 350; +pub const SYS_renameat2: ::c_long = 4000 + 351; +pub const SYS_seccomp: ::c_long = 4000 + 352; +pub const SYS_getrandom: ::c_long = 4000 + 353; +pub const SYS_memfd_create: ::c_long = 4000 + 354; +pub const SYS_bpf: ::c_long = 4000 + 355; +pub const SYS_execveat: ::c_long = 4000 + 356; +pub const SYS_userfaultfd: ::c_long = 4000 + 357; +pub const SYS_membarrier: ::c_long = 4000 + 358; +pub const SYS_mlock2: ::c_long = 4000 + 359; +pub const SYS_copy_file_range: ::c_long = 4000 + 360; +pub const SYS_preadv2: ::c_long = 4000 + 361; +pub const SYS_pwritev2: ::c_long = 4000 + 362; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; diff --git a/libc/src/unix/notbsd/linux/musl/b32/mod.rs b/libc/src/unix/notbsd/linux/musl/b32/mod.rs new file mode 100644 index 000000000..4128a8e4d --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b32/mod.rs @@ -0,0 +1,62 @@ +pub type c_long = i32; +pub type c_ulong = u32; +pub type nlink_t = u32; +pub type blksize_t = ::c_long; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct pthread_attr_t { + __size: [u32; 9] + } + + pub struct sigset_t { + __val: [::c_ulong; 32], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::socklen_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct sem_t { + __val: [::c_int; 4], + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; + +pub const TIOCINQ: ::c_int = ::FIONREAD; + +extern { + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "x86"))] { + mod x86; + pub use self::x86::*; + } else if #[cfg(any(target_arch = "mips"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(any(target_arch = "arm"))] { + mod arm; + pub use self::arm::*; + } else if #[cfg(any(target_arch = "powerpc"))] { + mod powerpc; + pub use self::powerpc::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/linux/musl/b32/powerpc.rs b/libc/src/unix/notbsd/linux/musl/b32/powerpc.rs new file mode 100644 index 000000000..d0f2d6829 --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b32/powerpc.rs @@ -0,0 +1,869 @@ +pub type c_char = u8; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_short, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 2], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_short, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 2], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __pad1: ::c_int, + __pad2: ::c_longlong, + __pad3: ::c_longlong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + __unused1: ::c_int, + pub shm_atime: ::time_t, + __unused2: ::c_int, + pub shm_dtime: ::time_t, + __unused3: ::c_int, + pub shm_ctime: ::time_t, + __unused4: ::c_int, + pub shm_segsz: ::size_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + __unused1: ::c_int, + pub msg_stime: ::time_t, + __unused2: ::c_int, + pub msg_rtime: ::time_t, + __unused3: ::c_int, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + #[cfg(target_endian = "little")] + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + #[cfg(target_endian = "big")] + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_cc: [::cc_t; 19], + pub c_line: ::cc_t, + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const SIGSTKSZ: ::size_t = 10240; +pub const MINSIGSTKSZ: ::size_t = 4096; + +pub const O_DIRECT: ::c_int = 0x20000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_LARGEFILE: ::c_int = 0x10000; + +pub const FIOCLEX: ::c_int = 0x20006601; +pub const FIONBIO: ::c_int = 0x8004667E; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; +pub const RLIMIT_NLIMITS: ::c_int = 15; + +pub const MCL_CURRENT: ::c_int = 0x2000; +pub const MCL_FUTURE: ::c_int = 0x4000; +pub const CBAUD: ::tcflag_t = 0o0000377; +pub const TAB1: ::c_int = 0x00000400; +pub const TAB2: ::c_int = 0x00000800; +pub const TAB3: ::c_int = 0x00000C00; +pub const CR1: ::c_int = 0x00001000; +pub const CR2: ::c_int = 0x00002000; +pub const CR3: ::c_int = 0x00003000; +pub const FF1: ::c_int = 0x00004000; +pub const BS1: ::c_int = 0x00008000; +pub const VT1: ::c_int = 0x00010000; +pub const VWERASE: usize = 10; +pub const VREPRINT: usize = 11; +pub const VSUSP: usize = 12; +pub const VSTART: usize = 13; +pub const VSTOP: usize = 14; +pub const VDISCARD: usize = 16; +pub const VTIME: usize = 7; +pub const IXON: ::tcflag_t = 0x00000200; +pub const IXOFF: ::tcflag_t = 0x00000400; +pub const ONLCR: ::tcflag_t = 0x00000002; +pub const CSIZE: ::tcflag_t = 0x00000300; +pub const CS6: ::tcflag_t = 0x00000100; +pub const CS7: ::tcflag_t = 0x00000200; +pub const CS8: ::tcflag_t = 0x00000300; +pub const CSTOPB: ::tcflag_t = 0x00000400; +pub const CREAD: ::tcflag_t = 0x00000800; +pub const PARENB: ::tcflag_t = 0x00001000; +pub const PARODD: ::tcflag_t = 0x00002000; +pub const HUPCL: ::tcflag_t = 0x00004000; +pub const CLOCAL: ::tcflag_t = 0x00008000; +pub const ECHOKE: ::tcflag_t = 0x00000001; +pub const ECHOE: ::tcflag_t = 0x00000002; +pub const ECHOK: ::tcflag_t = 0x00000004; +pub const ECHONL: ::tcflag_t = 0x00000010; +pub const ECHOPRT: ::tcflag_t = 0x00000020; +pub const ECHOCTL: ::tcflag_t = 0x00000040; +pub const ISIG: ::tcflag_t = 0x00000080; +pub const ICANON: ::tcflag_t = 0x00000100; +pub const PENDIN: ::tcflag_t = 0x20000000; +pub const NOFLSH: ::tcflag_t = 0x80000000; +pub const CIBAUD: ::tcflag_t = 0o00077600000; +pub const CBAUDEX: ::tcflag_t = 0o000020; +pub const VSWTC: usize = 9; +pub const OLCUC: ::tcflag_t = 0o000004; +pub const NLDLY: ::tcflag_t = 0o001400; +pub const CRDLY: ::tcflag_t = 0o030000; +pub const TABDLY: ::tcflag_t = 0o006000; +pub const BSDLY: ::tcflag_t = 0o100000; +pub const FFDLY: ::tcflag_t = 0o040000; +pub const VTDLY: ::tcflag_t = 0o200000; +pub const XTABS: ::tcflag_t = 0o006000; +pub const B57600: ::speed_t = 0o000020; +pub const B115200: ::speed_t = 0o000021; +pub const B230400: ::speed_t = 0o000022; +pub const B460800: ::speed_t = 0o000023; +pub const B500000: ::speed_t = 0o000024; +pub const B576000: ::speed_t = 0o000025; +pub const B921600: ::speed_t = 0o000026; +pub const B1000000: ::speed_t = 0o000027; +pub const B1152000: ::speed_t = 0o000030; +pub const B1500000: ::speed_t = 0o000031; +pub const B2000000: ::speed_t = 0o000032; +pub const B2500000: ::speed_t = 0o000033; +pub const B3000000: ::speed_t = 0o000034; +pub const B3500000: ::speed_t = 0o000035; +pub const B4000000: ::speed_t = 0o000036; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x00080; +pub const MAP_NORESERVE: ::c_int = 0x00040; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = 58; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_RCVLOWAT: ::c_int = 16; +pub const SO_SNDLOWAT: ::c_int = 17; +pub const SO_RCVTIMEO: ::c_int = 18; +pub const SO_SNDTIMEO: ::c_int = 19; +pub const SO_PASSCRED: ::c_int = 20; +pub const SO_PEERCRED: ::c_int = 21; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const EXTPROC: ::tcflag_t = 0x10000000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const F_GETLK: ::c_int = 12; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 13; +pub const F_SETLKW: ::c_int = 14; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: ::tcflag_t = 0x00000400; +pub const TOSTOP: ::tcflag_t = 0x00400000; +pub const FLUSHO: ::tcflag_t = 0x00800000; + +pub const TCGETS: ::c_int = 0x402C7413; +pub const TCSETS: ::c_int = 0x802C7414; +pub const TCSETSW: ::c_int = 0x802C7415; +pub const TCSETSF: ::c_int = 0x802C7416; +pub const TCGETA: ::c_int = 0x40147417; +pub const TCSETA: ::c_int = 0x80147418; +pub const TCSETAW: ::c_int = 0x80147419; +pub const TCSETAF: ::c_int = 0x8014741C; +pub const TCSBRK: ::c_int = 0x2000741D; +pub const TCXONC: ::c_int = 0x2000741E; +pub const TCFLSH: ::c_int = 0x2000741F; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x40047477; +pub const TIOCSPGRP: ::c_int = 0x80047476; +pub const TIOCOUTQ: ::c_int = 0x40047473; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x40087468; +pub const TIOCSWINSZ: ::c_int = 0x80087467; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x4004667F; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const TIOCGRS485: ::c_int = 0x542e; +pub const TIOCSRS485: ::c_int = 0x542f; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_query_module: ::c_long = 166; +pub const SYS_poll: ::c_long = 167; +pub const SYS_nfsservctl: ::c_long = 168; +pub const SYS_setresgid: ::c_long = 169; +pub const SYS_getresgid: ::c_long = 170; +pub const SYS_prctl: ::c_long = 171; +pub const SYS_rt_sigreturn: ::c_long = 172; +pub const SYS_rt_sigaction: ::c_long = 173; +pub const SYS_rt_sigprocmask: ::c_long = 174; +pub const SYS_rt_sigpending: ::c_long = 175; +pub const SYS_rt_sigtimedwait: ::c_long = 176; +pub const SYS_rt_sigqueueinfo: ::c_long = 177; +pub const SYS_rt_sigsuspend: ::c_long = 178; +pub const SYS_pread64: ::c_long = 179; +pub const SYS_pwrite64: ::c_long = 180; +pub const SYS_chown: ::c_long = 181; +pub const SYS_getcwd: ::c_long = 182; +pub const SYS_capget: ::c_long = 183; +pub const SYS_capset: ::c_long = 184; +pub const SYS_sigaltstack: ::c_long = 185; +pub const SYS_sendfile: ::c_long = 186; +pub const SYS_getpmsg: ::c_long = 187; +pub const SYS_putpmsg: ::c_long = 188; +pub const SYS_vfork: ::c_long = 189; +pub const SYS_ugetrlimit: ::c_long = 190; +pub const SYS_readahead: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_pciconfig_read: ::c_long = 198; +pub const SYS_pciconfig_write: ::c_long = 199; +pub const SYS_pciconfig_iobase: ::c_long = 200; +pub const SYS_multiplexer: ::c_long = 201; +pub const SYS_getdents64: ::c_long = 202; +pub const SYS_pivot_root: ::c_long = 203; +pub const SYS_fcntl64: ::c_long = 204; +pub const SYS_madvise: ::c_long = 205; +pub const SYS_mincore: ::c_long = 206; +pub const SYS_gettid: ::c_long = 207; +pub const SYS_tkill: ::c_long = 208; +pub const SYS_setxattr: ::c_long = 209; +pub const SYS_lsetxattr: ::c_long = 210; +pub const SYS_fsetxattr: ::c_long = 211; +pub const SYS_getxattr: ::c_long = 212; +pub const SYS_lgetxattr: ::c_long = 213; +pub const SYS_fgetxattr: ::c_long = 214; +pub const SYS_listxattr: ::c_long = 215; +pub const SYS_llistxattr: ::c_long = 216; +pub const SYS_flistxattr: ::c_long = 217; +pub const SYS_removexattr: ::c_long = 218; +pub const SYS_lremovexattr: ::c_long = 219; +pub const SYS_fremovexattr: ::c_long = 220; +pub const SYS_futex: ::c_long = 221; +pub const SYS_sched_setaffinity: ::c_long = 222; +pub const SYS_sched_getaffinity: ::c_long = 223; +pub const SYS_tuxcall: ::c_long = 225; +pub const SYS_sendfile64: ::c_long = 226; +pub const SYS_io_setup: ::c_long = 227; +pub const SYS_io_destroy: ::c_long = 228; +pub const SYS_io_getevents: ::c_long = 229; +pub const SYS_io_submit: ::c_long = 230; +pub const SYS_io_cancel: ::c_long = 231; +pub const SYS_set_tid_address: ::c_long = 232; +pub const SYS_fadvise64: ::c_long = 233; +pub const SYS_exit_group: ::c_long = 234; +pub const SYS_lookup_dcookie: ::c_long = 235; +pub const SYS_epoll_create: ::c_long = 236; +pub const SYS_epoll_ctl: ::c_long = 237; +pub const SYS_epoll_wait: ::c_long = 238; +pub const SYS_remap_file_pages: ::c_long = 239; +pub const SYS_timer_create: ::c_long = 240; +pub const SYS_timer_settime: ::c_long = 241; +pub const SYS_timer_gettime: ::c_long = 242; +pub const SYS_timer_getoverrun: ::c_long = 243; +pub const SYS_timer_delete: ::c_long = 244; +pub const SYS_clock_settime: ::c_long = 245; +pub const SYS_clock_gettime: ::c_long = 246; +pub const SYS_clock_getres: ::c_long = 247; +pub const SYS_clock_nanosleep: ::c_long = 248; +pub const SYS_swapcontext: ::c_long = 249; +pub const SYS_tgkill: ::c_long = 250; +pub const SYS_utimes: ::c_long = 251; +pub const SYS_statfs64: ::c_long = 252; +pub const SYS_fstatfs64: ::c_long = 253; +pub const SYS_fadvise64_64: ::c_long = 254; +pub const SYS_rtas: ::c_long = 255; +pub const SYS_sys_debug_setcontext: ::c_long = 256; +pub const SYS_migrate_pages: ::c_long = 258; +pub const SYS_mbind: ::c_long = 259; +pub const SYS_get_mempolicy: ::c_long = 260; +pub const SYS_set_mempolicy: ::c_long = 261; +pub const SYS_mq_open: ::c_long = 262; +pub const SYS_mq_unlink: ::c_long = 263; +pub const SYS_mq_timedsend: ::c_long = 264; +pub const SYS_mq_timedreceive: ::c_long = 265; +pub const SYS_mq_notify: ::c_long = 266; +pub const SYS_mq_getsetattr: ::c_long = 267; +pub const SYS_kexec_load: ::c_long = 268; +pub const SYS_add_key: ::c_long = 269; +pub const SYS_request_key: ::c_long = 270; +pub const SYS_keyctl: ::c_long = 271; +pub const SYS_waitid: ::c_long = 272; +pub const SYS_ioprio_set: ::c_long = 273; +pub const SYS_ioprio_get: ::c_long = 274; +pub const SYS_inotify_init: ::c_long = 275; +pub const SYS_inotify_add_watch: ::c_long = 276; +pub const SYS_inotify_rm_watch: ::c_long = 277; +pub const SYS_spu_run: ::c_long = 278; +pub const SYS_spu_create: ::c_long = 279; +pub const SYS_pselect6: ::c_long = 280; +pub const SYS_ppoll: ::c_long = 281; +pub const SYS_unshare: ::c_long = 282; +pub const SYS_splice: ::c_long = 283; +pub const SYS_tee: ::c_long = 284; +pub const SYS_vmsplice: ::c_long = 285; +pub const SYS_openat: ::c_long = 286; +pub const SYS_mkdirat: ::c_long = 287; +pub const SYS_mknodat: ::c_long = 288; +pub const SYS_fchownat: ::c_long = 289; +pub const SYS_futimesat: ::c_long = 290; +pub const SYS_fstatat64: ::c_long = 291; +pub const SYS_unlinkat: ::c_long = 292; +pub const SYS_renameat: ::c_long = 293; +pub const SYS_linkat: ::c_long = 294; +pub const SYS_symlinkat: ::c_long = 295; +pub const SYS_readlinkat: ::c_long = 296; +pub const SYS_fchmodat: ::c_long = 297; +pub const SYS_faccessat: ::c_long = 298; +pub const SYS_get_robust_list: ::c_long = 299; +pub const SYS_set_robust_list: ::c_long = 300; +pub const SYS_move_pages: ::c_long = 301; +pub const SYS_getcpu: ::c_long = 302; +pub const SYS_epoll_pwait: ::c_long = 303; +pub const SYS_utimensat: ::c_long = 304; +pub const SYS_signalfd: ::c_long = 305; +pub const SYS_timerfd_create: ::c_long = 306; +pub const SYS_eventfd: ::c_long = 307; +pub const SYS_sync_file_range2: ::c_long = 308; +pub const SYS_fallocate: ::c_long = 309; +pub const SYS_subpage_prot: ::c_long = 310; +pub const SYS_timerfd_settime: ::c_long = 311; +pub const SYS_timerfd_gettime: ::c_long = 312; +pub const SYS_signalfd4: ::c_long = 313; +pub const SYS_eventfd2: ::c_long = 314; +pub const SYS_epoll_create1: ::c_long = 315; +pub const SYS_dup3: ::c_long = 316; +pub const SYS_pipe2: ::c_long = 317; +pub const SYS_inotify_init1: ::c_long = 318; +pub const SYS_perf_event_open: ::c_long = 319; +pub const SYS_preadv: ::c_long = 320; +pub const SYS_pwritev: ::c_long = 321; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 322; +pub const SYS_fanotify_init: ::c_long = 323; +pub const SYS_fanotify_mark: ::c_long = 324; +pub const SYS_prlimit64: ::c_long = 325; +pub const SYS_socket: ::c_long = 326; +pub const SYS_bind: ::c_long = 327; +pub const SYS_connect: ::c_long = 328; +pub const SYS_listen: ::c_long = 329; +pub const SYS_accept: ::c_long = 330; +pub const SYS_getsockname: ::c_long = 331; +pub const SYS_getpeername: ::c_long = 332; +pub const SYS_socketpair: ::c_long = 333; +pub const SYS_send: ::c_long = 334; +pub const SYS_sendto: ::c_long = 335; +pub const SYS_recv: ::c_long = 336; +pub const SYS_recvfrom: ::c_long = 337; +pub const SYS_shutdown: ::c_long = 338; +pub const SYS_setsockopt: ::c_long = 339; +pub const SYS_getsockopt: ::c_long = 340; +pub const SYS_sendmsg: ::c_long = 341; +pub const SYS_recvmsg: ::c_long = 342; +pub const SYS_recvmmsg: ::c_long = 343; +pub const SYS_accept4: ::c_long = 344; +pub const SYS_name_to_handle_at: ::c_long = 345; +pub const SYS_open_by_handle_at: ::c_long = 346; +pub const SYS_clock_adjtime: ::c_long = 347; +pub const SYS_syncfs: ::c_long = 348; +pub const SYS_sendmmsg: ::c_long = 349; +pub const SYS_setns: ::c_long = 350; +pub const SYS_process_vm_readv: ::c_long = 351; +pub const SYS_process_vm_writev: ::c_long = 352; +pub const SYS_finit_module: ::c_long = 353; +pub const SYS_kcmp: ::c_long = 354; +pub const SYS_sched_setattr: ::c_long = 355; +pub const SYS_sched_getattr: ::c_long = 356; +pub const SYS_renameat2: ::c_long = 357; +pub const SYS_seccomp: ::c_long = 358; +pub const SYS_getrandom: ::c_long = 359; +pub const SYS_memfd_create: ::c_long = 360; +pub const SYS_bpf: ::c_long = 361; +pub const SYS_execveat: ::c_long = 362; +pub const SYS_switch_endian: ::c_long = 363; +pub const SYS_userfaultfd: ::c_long = 364; +pub const SYS_membarrier: ::c_long = 365; +pub const SYS_mlock2: ::c_long = 378; +pub const SYS_copy_file_range: ::c_long = 379; +pub const SYS_preadv2: ::c_long = 380; +pub const SYS_pwritev2: ::c_long = 381; +pub const SYS_kexec_file_load: ::c_long = 382; +pub const SYS_statx: ::c_long = 383; +pub const SYS_pkey_alloc: ::c_long = 384; +pub const SYS_pkey_free: ::c_long = 385; +pub const SYS_pkey_mprotect: ::c_long = 386; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; diff --git a/libc/src/unix/notbsd/linux/musl/b32/x86.rs b/libc/src/unix/notbsd/linux/musl/b32/x86.rs new file mode 100644 index 000000000..8bfb60ba3 --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b32/x86.rs @@ -0,0 +1,951 @@ +pub type c_char = i8; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __st_dev_padding: ::c_int, + __st_ino_truncated: ::c_long, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __st_rdev_padding: ::c_int, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino_t, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + __unused1: ::c_int, + pub shm_dtime: ::time_t, + __unused2: ::c_int, + pub shm_ctime: ::time_t, + __unused3: ::c_int, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + __unused1: ::c_int, + pub msg_rtime: ::time_t, + __unused2: ::c_int, + pub msg_ctime: ::time_t, + __unused3: ::c_int, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct mcontext_t { + __private: [u32; 22] + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +s_no_extra_traits!{ + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + __private: [u8; 112], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for ucontext_t { + fn eq(&self, other: &ucontext_t) -> bool { + self.uc_flags == other.uc_flags + && self.uc_link == other.uc_link + && self.uc_stack == other.uc_stack + && self.uc_mcontext == other.uc_mcontext + && self.uc_sigmask == other.uc_sigmask + && self + .__private + .iter() + .zip(other.__private.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for ucontext_t {} + + impl ::fmt::Debug for ucontext_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ucontext_t") + .field("uc_flags", &self.uc_flags) + .field("uc_link", &self.uc_link) + .field("uc_stack", &self.uc_stack) + .field("uc_mcontext", &self.uc_mcontext) + .field("uc_sigmask", &self.uc_sigmask) + // Ignore __private field + .finish() + } + } + + impl ::hash::Hash for ucontext_t { + fn hash(&self, state: &mut H) { + self.uc_flags.hash(state); + self.uc_link.hash(state); + self.uc_stack.hash(state); + self.uc_mcontext.hash(state); + self.uc_sigmask.hash(state); + self.__private.hash(state); + } + } + } +} + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_LARGEFILE: ::c_int = 0o0100000; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const EXTPROC: ::tcflag_t = 0x00010000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; +pub const MAP_32BIT: ::c_int = 0x0040; + +pub const F_GETLK: ::c_int = 12; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 13; +pub const F_SETLKW: ::c_int = 14; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; + +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const TIOCGRS485: ::c_int = 0x542E; +pub const TIOCSRS485: ::c_int = 0x542F; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86old: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_vm86: ::c_long = 166; +pub const SYS_query_module: ::c_long = 167; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_getpmsg: ::c_long = 188; +pub const SYS_putpmsg: ::c_long = 189; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_pivot_root: ::c_long = 217; +pub const SYS_mincore: ::c_long = 218; +pub const SYS_madvise: ::c_long = 219; +pub const SYS_getdents64: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_set_thread_area: ::c_long = 243; +pub const SYS_get_thread_area: ::c_long = 244; +pub const SYS_io_setup: ::c_long = 245; +pub const SYS_io_destroy: ::c_long = 246; +pub const SYS_io_getevents: ::c_long = 247; +pub const SYS_io_submit: ::c_long = 248; +pub const SYS_io_cancel: ::c_long = 249; +pub const SYS_fadvise64: ::c_long = 250; +pub const SYS_exit_group: ::c_long = 252; +pub const SYS_lookup_dcookie: ::c_long = 253; +pub const SYS_epoll_create: ::c_long = 254; +pub const SYS_epoll_ctl: ::c_long = 255; +pub const SYS_epoll_wait: ::c_long = 256; +pub const SYS_remap_file_pages: ::c_long = 257; +pub const SYS_set_tid_address: ::c_long = 258; +pub const SYS_timer_create: ::c_long = 259; +pub const SYS_timer_settime: ::c_long = 260; +pub const SYS_timer_gettime: ::c_long = 261; +pub const SYS_timer_getoverrun: ::c_long = 262; +pub const SYS_timer_delete: ::c_long = 263; +pub const SYS_clock_settime: ::c_long = 264; +pub const SYS_clock_gettime: ::c_long = 265; +pub const SYS_clock_getres: ::c_long = 266; +pub const SYS_clock_nanosleep: ::c_long = 267; +pub const SYS_statfs64: ::c_long = 268; +pub const SYS_fstatfs64: ::c_long = 269; +pub const SYS_tgkill: ::c_long = 270; +pub const SYS_utimes: ::c_long = 271; +pub const SYS_fadvise64_64: ::c_long = 272; +pub const SYS_vserver: ::c_long = 273; +pub const SYS_mbind: ::c_long = 274; +pub const SYS_get_mempolicy: ::c_long = 275; +pub const SYS_set_mempolicy: ::c_long = 276; +pub const SYS_mq_open: ::c_long = 277; +pub const SYS_mq_unlink: ::c_long = 278; +pub const SYS_mq_timedsend: ::c_long = 279; +pub const SYS_mq_timedreceive: ::c_long = 280; +pub const SYS_mq_notify: ::c_long = 281; +pub const SYS_mq_getsetattr: ::c_long = 282; +pub const SYS_kexec_load: ::c_long = 283; +pub const SYS_waitid: ::c_long = 284; +pub const SYS_add_key: ::c_long = 286; +pub const SYS_request_key: ::c_long = 287; +pub const SYS_keyctl: ::c_long = 288; +pub const SYS_ioprio_set: ::c_long = 289; +pub const SYS_ioprio_get: ::c_long = 290; +pub const SYS_inotify_init: ::c_long = 291; +pub const SYS_inotify_add_watch: ::c_long = 292; +pub const SYS_inotify_rm_watch: ::c_long = 293; +pub const SYS_migrate_pages: ::c_long = 294; +pub const SYS_openat: ::c_long = 295; +pub const SYS_mkdirat: ::c_long = 296; +pub const SYS_mknodat: ::c_long = 297; +pub const SYS_fchownat: ::c_long = 298; +pub const SYS_futimesat: ::c_long = 299; +pub const SYS_fstatat64: ::c_long = 300; +pub const SYS_unlinkat: ::c_long = 301; +pub const SYS_renameat: ::c_long = 302; +pub const SYS_linkat: ::c_long = 303; +pub const SYS_symlinkat: ::c_long = 304; +pub const SYS_readlinkat: ::c_long = 305; +pub const SYS_fchmodat: ::c_long = 306; +pub const SYS_faccessat: ::c_long = 307; +pub const SYS_pselect6: ::c_long = 308; +pub const SYS_ppoll: ::c_long = 309; +pub const SYS_unshare: ::c_long = 310; +pub const SYS_set_robust_list: ::c_long = 311; +pub const SYS_get_robust_list: ::c_long = 312; +pub const SYS_splice: ::c_long = 313; +pub const SYS_sync_file_range: ::c_long = 314; +pub const SYS_tee: ::c_long = 315; +pub const SYS_vmsplice: ::c_long = 316; +pub const SYS_move_pages: ::c_long = 317; +pub const SYS_getcpu: ::c_long = 318; +pub const SYS_epoll_pwait: ::c_long = 319; +pub const SYS_utimensat: ::c_long = 320; +pub const SYS_signalfd: ::c_long = 321; +pub const SYS_timerfd_create: ::c_long = 322; +pub const SYS_eventfd: ::c_long = 323; +pub const SYS_fallocate: ::c_long = 324; +pub const SYS_timerfd_settime: ::c_long = 325; +pub const SYS_timerfd_gettime: ::c_long = 326; +pub const SYS_signalfd4: ::c_long = 327; +pub const SYS_eventfd2: ::c_long = 328; +pub const SYS_epoll_create1: ::c_long = 329; +pub const SYS_dup3: ::c_long = 330; +pub const SYS_pipe2: ::c_long = 331; +pub const SYS_inotify_init1: ::c_long = 332; +pub const SYS_preadv: ::c_long = 333; +pub const SYS_pwritev: ::c_long = 334; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 335; +pub const SYS_perf_event_open: ::c_long = 336; +pub const SYS_recvmmsg: ::c_long = 337; +pub const SYS_fanotify_init: ::c_long = 338; +pub const SYS_fanotify_mark: ::c_long = 339; +pub const SYS_prlimit64: ::c_long = 340; +pub const SYS_name_to_handle_at: ::c_long = 341; +pub const SYS_open_by_handle_at: ::c_long = 342; +pub const SYS_clock_adjtime: ::c_long = 343; +pub const SYS_syncfs: ::c_long = 344; +pub const SYS_sendmmsg: ::c_long = 345; +pub const SYS_setns: ::c_long = 346; +pub const SYS_process_vm_readv: ::c_long = 347; +pub const SYS_process_vm_writev: ::c_long = 348; +pub const SYS_kcmp: ::c_long = 349; +pub const SYS_finit_module: ::c_long = 350; +pub const SYS_sched_setattr: ::c_long = 351; +pub const SYS_sched_getattr: ::c_long = 352; +pub const SYS_renameat2: ::c_long = 353; +pub const SYS_seccomp: ::c_long = 354; +pub const SYS_getrandom: ::c_long = 355; +pub const SYS_memfd_create: ::c_long = 356; +pub const SYS_bpf: ::c_long = 357; +pub const SYS_execveat: ::c_long = 358; +pub const SYS_socket: ::c_long = 359; +pub const SYS_socketpair: ::c_long = 360; +pub const SYS_bind: ::c_long = 361; +pub const SYS_connect: ::c_long = 362; +pub const SYS_listen: ::c_long = 363; +pub const SYS_accept4: ::c_long = 364; +pub const SYS_getsockopt: ::c_long = 365; +pub const SYS_setsockopt: ::c_long = 366; +pub const SYS_getsockname: ::c_long = 367; +pub const SYS_getpeername: ::c_long = 368; +pub const SYS_sendto: ::c_long = 369; +pub const SYS_sendmsg: ::c_long = 370; +pub const SYS_recvfrom: ::c_long = 371; +pub const SYS_recvmsg: ::c_long = 372; +pub const SYS_shutdown: ::c_long = 373; +pub const SYS_userfaultfd: ::c_long = 374; +pub const SYS_membarrier: ::c_long = 375; +pub const SYS_mlock2: ::c_long = 376; +pub const SYS_copy_file_range: ::c_long = 377; +pub const SYS_preadv2: ::c_long = 378; +pub const SYS_pwritev2: ::c_long = 379; +// FIXME syscalls 380-382 have been added in musl 1.16 +// See discussion https://github.com/rust-lang/libc/pull/699 + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: ::c_int = 0; +pub const ECX: ::c_int = 1; +pub const EDX: ::c_int = 2; +pub const ESI: ::c_int = 3; +pub const EDI: ::c_int = 4; +pub const EBP: ::c_int = 5; +pub const EAX: ::c_int = 6; +pub const DS: ::c_int = 7; +pub const ES: ::c_int = 8; +pub const FS: ::c_int = 9; +pub const GS: ::c_int = 10; +pub const ORIG_EAX: ::c_int = 11; +pub const EIP: ::c_int = 12; +pub const CS: ::c_int = 13; +pub const EFL: ::c_int = 14; +pub const UESP: ::c_int = 15; +pub const SS: ::c_int = 16; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; diff --git a/libc/src/unix/notbsd/linux/musl/b64/aarch64.rs b/libc/src/unix/notbsd/linux/musl/b64/aarch64.rs new file mode 100644 index 000000000..f01a5c437 --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b64/aarch64.rs @@ -0,0 +1,479 @@ +pub type c_char = u8; +pub type __u64 = ::c_ulonglong; +pub type wchar_t = u32; +pub type nlink_t = u32; +pub type blksize_t = ::c_int; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad0: ::c_ulong, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + __pad1: ::c_int, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_uint; 2], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad0: ::c_ulong, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + __pad1: ::c_int, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_uint; 2], + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong, + } +} + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_LARGEFILE: ::c_int = 0x20000; +pub const O_NOFOLLOW: ::c_int = 0x8000; + +pub const MINSIGSTKSZ: ::size_t = 6144; +pub const SIGSTKSZ: ::size_t = 12288; + +#[doc(hidden)] +pub const PF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const AF_MAX: ::c_int = PF_MAX; + +pub const SYS_io_setup: ::c_long = 0; +pub const SYS_io_destroy: ::c_long = 1; +pub const SYS_io_submit: ::c_long = 2; +pub const SYS_io_cancel: ::c_long = 3; +pub const SYS_io_getevents: ::c_long = 4; +pub const SYS_setxattr: ::c_long = 5; +pub const SYS_lsetxattr: ::c_long = 6; +pub const SYS_fsetxattr: ::c_long = 7; +pub const SYS_getxattr: ::c_long = 8; +pub const SYS_lgetxattr: ::c_long = 9; +pub const SYS_fgetxattr: ::c_long = 10; +pub const SYS_listxattr: ::c_long = 11; +pub const SYS_llistxattr: ::c_long = 12; +pub const SYS_flistxattr: ::c_long = 13; +pub const SYS_removexattr: ::c_long = 14; +pub const SYS_lremovexattr: ::c_long = 15; +pub const SYS_fremovexattr: ::c_long = 16; +pub const SYS_getcwd: ::c_long = 17; +pub const SYS_lookup_dcookie: ::c_long = 18; +pub const SYS_eventfd2: ::c_long = 19; +pub const SYS_epoll_create1: ::c_long = 20; +pub const SYS_epoll_ctl: ::c_long = 21; +pub const SYS_epoll_pwait: ::c_long = 22; +pub const SYS_dup: ::c_long = 23; +pub const SYS_dup3: ::c_long = 24; +pub const SYS_inotify_init1: ::c_long = 26; +pub const SYS_inotify_add_watch: ::c_long = 27; +pub const SYS_inotify_rm_watch: ::c_long = 28; +pub const SYS_ioctl: ::c_long = 29; +pub const SYS_ioprio_set: ::c_long = 30; +pub const SYS_ioprio_get: ::c_long = 31; +pub const SYS_flock: ::c_long = 32; +pub const SYS_mknodat: ::c_long = 33; +pub const SYS_mkdirat: ::c_long = 34; +pub const SYS_unlinkat: ::c_long = 35; +pub const SYS_symlinkat: ::c_long = 36; +pub const SYS_linkat: ::c_long = 37; +pub const SYS_renameat: ::c_long = 38; +pub const SYS_umount2: ::c_long = 39; +pub const SYS_mount: ::c_long = 40; +pub const SYS_pivot_root: ::c_long = 41; +pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_fallocate: ::c_long = 47; +pub const SYS_faccessat: ::c_long = 48; +pub const SYS_chdir: ::c_long = 49; +pub const SYS_fchdir: ::c_long = 50; +pub const SYS_chroot: ::c_long = 51; +pub const SYS_fchmod: ::c_long = 52; +pub const SYS_fchmodat: ::c_long = 53; +pub const SYS_fchownat: ::c_long = 54; +pub const SYS_fchown: ::c_long = 55; +pub const SYS_openat: ::c_long = 56; +pub const SYS_close: ::c_long = 57; +pub const SYS_vhangup: ::c_long = 58; +pub const SYS_pipe2: ::c_long = 59; +pub const SYS_quotactl: ::c_long = 60; +pub const SYS_getdents64: ::c_long = 61; +pub const SYS_read: ::c_long = 63; +pub const SYS_write: ::c_long = 64; +pub const SYS_readv: ::c_long = 65; +pub const SYS_writev: ::c_long = 66; +pub const SYS_pread64: ::c_long = 67; +pub const SYS_pwrite64: ::c_long = 68; +pub const SYS_preadv: ::c_long = 69; +pub const SYS_pwritev: ::c_long = 70; +pub const SYS_pselect6: ::c_long = 72; +pub const SYS_ppoll: ::c_long = 73; +pub const SYS_signalfd4: ::c_long = 74; +pub const SYS_vmsplice: ::c_long = 75; +pub const SYS_splice: ::c_long = 76; +pub const SYS_tee: ::c_long = 77; +pub const SYS_readlinkat: ::c_long = 78; +pub const SYS_sync: ::c_long = 81; +pub const SYS_fsync: ::c_long = 82; +pub const SYS_fdatasync: ::c_long = 83; +pub const SYS_sync_file_range: ::c_long = 84; +pub const SYS_timerfd_create: ::c_long = 85; +pub const SYS_timerfd_settime: ::c_long = 86; +pub const SYS_timerfd_gettime: ::c_long = 87; +pub const SYS_utimensat: ::c_long = 88; +pub const SYS_acct: ::c_long = 89; +pub const SYS_capget: ::c_long = 90; +pub const SYS_capset: ::c_long = 91; +pub const SYS_personality: ::c_long = 92; +pub const SYS_exit: ::c_long = 93; +pub const SYS_exit_group: ::c_long = 94; +pub const SYS_waitid: ::c_long = 95; +pub const SYS_set_tid_address: ::c_long = 96; +pub const SYS_unshare: ::c_long = 97; +pub const SYS_futex: ::c_long = 98; +pub const SYS_set_robust_list: ::c_long = 99; +pub const SYS_get_robust_list: ::c_long = 100; +pub const SYS_nanosleep: ::c_long = 101; +pub const SYS_getitimer: ::c_long = 102; +pub const SYS_setitimer: ::c_long = 103; +pub const SYS_kexec_load: ::c_long = 104; +pub const SYS_init_module: ::c_long = 105; +pub const SYS_delete_module: ::c_long = 106; +pub const SYS_timer_create: ::c_long = 107; +pub const SYS_timer_gettime: ::c_long = 108; +pub const SYS_timer_getoverrun: ::c_long = 109; +pub const SYS_timer_settime: ::c_long = 110; +pub const SYS_timer_delete: ::c_long = 111; +pub const SYS_clock_settime: ::c_long = 112; +pub const SYS_clock_gettime: ::c_long = 113; +pub const SYS_clock_getres: ::c_long = 114; +pub const SYS_clock_nanosleep: ::c_long = 115; +pub const SYS_syslog: ::c_long = 116; +pub const SYS_ptrace: ::c_long = 117; +pub const SYS_sched_setparam: ::c_long = 118; +pub const SYS_sched_setscheduler: ::c_long = 119; +pub const SYS_sched_getscheduler: ::c_long = 120; +pub const SYS_sched_getparam: ::c_long = 121; +pub const SYS_sched_setaffinity: ::c_long = 122; +pub const SYS_sched_getaffinity: ::c_long = 123; +pub const SYS_sched_yield: ::c_long = 124; +pub const SYS_sched_get_priority_max: ::c_long = 125; +pub const SYS_sched_get_priority_min: ::c_long = 126; +pub const SYS_sched_rr_get_interval: ::c_long = 127; +pub const SYS_restart_syscall: ::c_long = 128; +pub const SYS_kill: ::c_long = 129; +pub const SYS_tkill: ::c_long = 130; +pub const SYS_tgkill: ::c_long = 131; +pub const SYS_sigaltstack: ::c_long = 132; +pub const SYS_rt_sigsuspend: ::c_long = 133; +pub const SYS_rt_sigaction: ::c_long = 134; +pub const SYS_rt_sigprocmask: ::c_long = 135; +pub const SYS_rt_sigpending: ::c_long = 136; +pub const SYS_rt_sigtimedwait: ::c_long = 137; +pub const SYS_rt_sigqueueinfo: ::c_long = 138; +pub const SYS_rt_sigreturn: ::c_long = 139; +pub const SYS_setpriority: ::c_long = 140; +pub const SYS_getpriority: ::c_long = 141; +pub const SYS_reboot: ::c_long = 142; +pub const SYS_setregid: ::c_long = 143; +pub const SYS_setgid: ::c_long = 144; +pub const SYS_setreuid: ::c_long = 145; +pub const SYS_setuid: ::c_long = 146; +pub const SYS_setresuid: ::c_long = 147; +pub const SYS_getresuid: ::c_long = 148; +pub const SYS_setresgid: ::c_long = 149; +pub const SYS_getresgid: ::c_long = 150; +pub const SYS_setfsuid: ::c_long = 151; +pub const SYS_setfsgid: ::c_long = 152; +pub const SYS_times: ::c_long = 153; +pub const SYS_setpgid: ::c_long = 154; +pub const SYS_getpgid: ::c_long = 155; +pub const SYS_getsid: ::c_long = 156; +pub const SYS_setsid: ::c_long = 157; +pub const SYS_getgroups: ::c_long = 158; +pub const SYS_setgroups: ::c_long = 159; +pub const SYS_uname: ::c_long = 160; +pub const SYS_sethostname: ::c_long = 161; +pub const SYS_setdomainname: ::c_long = 162; +pub const SYS_getrlimit: ::c_long = 163; +pub const SYS_setrlimit: ::c_long = 164; +pub const SYS_getrusage: ::c_long = 165; +pub const SYS_umask: ::c_long = 166; +pub const SYS_prctl: ::c_long = 167; +pub const SYS_getcpu: ::c_long = 168; +pub const SYS_gettimeofday: ::c_long = 169; +pub const SYS_settimeofday: ::c_long = 170; +pub const SYS_adjtimex: ::c_long = 171; +pub const SYS_getpid: ::c_long = 172; +pub const SYS_getppid: ::c_long = 173; +pub const SYS_getuid: ::c_long = 174; +pub const SYS_geteuid: ::c_long = 175; +pub const SYS_getgid: ::c_long = 176; +pub const SYS_getegid: ::c_long = 177; +pub const SYS_gettid: ::c_long = 178; +pub const SYS_sysinfo: ::c_long = 179; +pub const SYS_mq_open: ::c_long = 180; +pub const SYS_mq_unlink: ::c_long = 181; +pub const SYS_mq_timedsend: ::c_long = 182; +pub const SYS_mq_timedreceive: ::c_long = 183; +pub const SYS_mq_notify: ::c_long = 184; +pub const SYS_mq_getsetattr: ::c_long = 185; +pub const SYS_msgget: ::c_long = 186; +pub const SYS_msgctl: ::c_long = 187; +pub const SYS_msgrcv: ::c_long = 188; +pub const SYS_msgsnd: ::c_long = 189; +pub const SYS_semget: ::c_long = 190; +pub const SYS_semctl: ::c_long = 191; +pub const SYS_semtimedop: ::c_long = 192; +pub const SYS_semop: ::c_long = 193; +pub const SYS_shmget: ::c_long = 194; +pub const SYS_shmctl: ::c_long = 195; +pub const SYS_shmat: ::c_long = 196; +pub const SYS_shmdt: ::c_long = 197; +pub const SYS_socket: ::c_long = 198; +pub const SYS_socketpair: ::c_long = 199; +pub const SYS_bind: ::c_long = 200; +pub const SYS_listen: ::c_long = 201; +pub const SYS_accept: ::c_long = 202; +pub const SYS_connect: ::c_long = 203; +pub const SYS_getsockname: ::c_long = 204; +pub const SYS_getpeername: ::c_long = 205; +pub const SYS_sendto: ::c_long = 206; +pub const SYS_recvfrom: ::c_long = 207; +pub const SYS_setsockopt: ::c_long = 208; +pub const SYS_getsockopt: ::c_long = 209; +pub const SYS_shutdown: ::c_long = 210; +pub const SYS_sendmsg: ::c_long = 211; +pub const SYS_recvmsg: ::c_long = 212; +pub const SYS_readahead: ::c_long = 213; +pub const SYS_brk: ::c_long = 214; +pub const SYS_munmap: ::c_long = 215; +pub const SYS_mremap: ::c_long = 216; +pub const SYS_add_key: ::c_long = 217; +pub const SYS_request_key: ::c_long = 218; +pub const SYS_keyctl: ::c_long = 219; +pub const SYS_clone: ::c_long = 220; +pub const SYS_execve: ::c_long = 221; +pub const SYS_swapon: ::c_long = 224; +pub const SYS_swapoff: ::c_long = 225; +pub const SYS_mprotect: ::c_long = 226; +pub const SYS_msync: ::c_long = 227; +pub const SYS_mlock: ::c_long = 228; +pub const SYS_munlock: ::c_long = 229; +pub const SYS_mlockall: ::c_long = 230; +pub const SYS_munlockall: ::c_long = 231; +pub const SYS_mincore: ::c_long = 232; +pub const SYS_madvise: ::c_long = 233; +pub const SYS_remap_file_pages: ::c_long = 234; +pub const SYS_mbind: ::c_long = 235; +pub const SYS_get_mempolicy: ::c_long = 236; +pub const SYS_set_mempolicy: ::c_long = 237; +pub const SYS_migrate_pages: ::c_long = 238; +pub const SYS_move_pages: ::c_long = 239; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 240; +pub const SYS_perf_event_open: ::c_long = 241; +pub const SYS_accept4: ::c_long = 242; +pub const SYS_recvmmsg: ::c_long = 243; +pub const SYS_wait4: ::c_long = 260; +pub const SYS_prlimit64: ::c_long = 261; +pub const SYS_fanotify_init: ::c_long = 262; +pub const SYS_fanotify_mark: ::c_long = 263; +pub const SYS_name_to_handle_at: ::c_long = 264; +pub const SYS_open_by_handle_at: ::c_long = 265; +pub const SYS_clock_adjtime: ::c_long = 266; +pub const SYS_syncfs: ::c_long = 267; +pub const SYS_setns: ::c_long = 268; +pub const SYS_sendmmsg: ::c_long = 269; +pub const SYS_process_vm_readv: ::c_long = 270; +pub const SYS_process_vm_writev: ::c_long = 271; +pub const SYS_kcmp: ::c_long = 272; +pub const SYS_finit_module: ::c_long = 273; +pub const SYS_sched_setattr: ::c_long = 274; +pub const SYS_sched_getattr: ::c_long = 275; +pub const SYS_renameat2: ::c_long = 276; +pub const SYS_seccomp: ::c_long = 277; +pub const SYS_getrandom: ::c_long = 278; +pub const SYS_memfd_create: ::c_long = 279; +pub const SYS_bpf: ::c_long = 280; +pub const SYS_execveat: ::c_long = 281; +pub const SYS_userfaultfd: ::c_long = 282; +pub const SYS_membarrier: ::c_long = 283; +pub const SYS_mlock2: ::c_long = 284; +pub const SYS_copy_file_range: ::c_long = 285; +pub const SYS_preadv2: ::c_long = 286; +pub const SYS_pwritev2: ::c_long = 287; +pub const SYS_pkey_mprotect: ::c_long = 288; +pub const SYS_pkey_alloc: ::c_long = 289; +pub const SYS_pkey_free: ::c_long = 290; + +pub const RLIMIT_NLIMITS: ::c_int = 16; +pub const TIOCINQ: ::c_int = ::FIONREAD; +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; +pub const EDEADLK: ::c_int = 35; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const TIOCGRS485: ::c_int = 0x542E; +pub const TIOCSRS485: ::c_int = 0x542F; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +extern { + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/musl/b64/mod.rs b/libc/src/unix/notbsd/linux/musl/b64/mod.rs new file mode 100644 index 000000000..043ca8d97 --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b64/mod.rs @@ -0,0 +1,339 @@ +pub type c_long = i64; +pub type c_ulong = u64; + +s! { + pub struct statfs64 { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct pthread_attr_t { + __size: [u64; 7] + } + + pub struct sigset_t { + __val: [::c_ulong; 16], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::c_ulong, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __pad1: ::c_ulong, + __pad2: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_ulong, + pub f_bsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_flags: ::c_ulong, + pub f_spare: [::c_ulong; 4], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + #[cfg(target_endian = "big")] + __pad1: ::c_int, + pub msg_iovlen: ::c_int, + #[cfg(target_endian = "little")] + __pad1: ::c_int, + pub msg_control: *mut ::c_void, + #[cfg(target_endian = "big")] + __pad2: ::c_int, + pub msg_controllen: ::socklen_t, + #[cfg(target_endian = "little")] + __pad2: ::c_int, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + #[cfg(target_endian = "big")] + pub __pad1: ::c_int, + pub cmsg_len: ::socklen_t, + #[cfg(target_endian = "little")] + pub __pad1: ::c_int, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct sem_t { + __val: [::c_int; 8], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + _align: [usize; 0], + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; + +pub const O_ASYNC: ::c_int = 0x2000; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; + +pub const SOCK_NONBLOCK: ::c_int = 2048; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EBADMSG: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const ERFKILL: ::c_int = 132; +pub const EHWPOISON: ::c_int = 133; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; +pub const F_SETOWN: ::c_int = 8; + +pub const VEOF: usize = 4; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "powerpc64"))] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/linux/musl/b64/powerpc64.rs b/libc/src/unix/notbsd/linux/musl/b64/powerpc64.rs new file mode 100644 index 000000000..04eba48cc --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b64/powerpc64.rs @@ -0,0 +1,575 @@ +pub type c_char = u8; +pub type wchar_t = i32; +pub type __u64 = ::c_ulong; +pub type nlink_t = u64; +pub type blksize_t = ::c_long; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __reserved: [::c_long; 3], + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } +} + +pub const MAP_32BIT: ::c_int = 0x0040; +pub const O_DIRECT: ::c_int = 0x20000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_LARGEFILE: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x8000; + +pub const SIGSTKSZ: ::size_t = 10240; +pub const MINSIGSTKSZ: ::size_t = 4096; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 43; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_query_module: ::c_long = 166; +pub const SYS_poll: ::c_long = 167; +pub const SYS_nfsservctl: ::c_long = 168; +pub const SYS_setresgid: ::c_long = 169; +pub const SYS_getresgid: ::c_long = 170; +pub const SYS_prctl: ::c_long = 171; +pub const SYS_rt_sigreturn: ::c_long = 172; +pub const SYS_rt_sigaction: ::c_long = 173; +pub const SYS_rt_sigprocmask: ::c_long = 174; +pub const SYS_rt_sigpending: ::c_long = 175; +pub const SYS_rt_sigtimedwait: ::c_long = 176; +pub const SYS_rt_sigqueueinfo: ::c_long = 177; +pub const SYS_rt_sigsuspend: ::c_long = 178; +pub const SYS_pread64: ::c_long = 179; +pub const SYS_pwrite64: ::c_long = 180; +pub const SYS_chown: ::c_long = 181; +pub const SYS_getcwd: ::c_long = 182; +pub const SYS_capget: ::c_long = 183; +pub const SYS_capset: ::c_long = 184; +pub const SYS_sigaltstack: ::c_long = 185; +pub const SYS_sendfile: ::c_long = 186; +pub const SYS_getpmsg: ::c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: ::c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: ::c_long = 189; +pub const SYS_ugetrlimit: ::c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: ::c_long = 191; +pub const SYS_pciconfig_read: ::c_long = 198; +pub const SYS_pciconfig_write: ::c_long = 199; +pub const SYS_pciconfig_iobase: ::c_long = 200; +pub const SYS_multiplexer: ::c_long = 201; +pub const SYS_getdents64: ::c_long = 202; +pub const SYS_pivot_root: ::c_long = 203; +pub const SYS_madvise: ::c_long = 205; +pub const SYS_mincore: ::c_long = 206; +pub const SYS_gettid: ::c_long = 207; +pub const SYS_tkill: ::c_long = 208; +pub const SYS_setxattr: ::c_long = 209; +pub const SYS_lsetxattr: ::c_long = 210; +pub const SYS_fsetxattr: ::c_long = 211; +pub const SYS_getxattr: ::c_long = 212; +pub const SYS_lgetxattr: ::c_long = 213; +pub const SYS_fgetxattr: ::c_long = 214; +pub const SYS_listxattr: ::c_long = 215; +pub const SYS_llistxattr: ::c_long = 216; +pub const SYS_flistxattr: ::c_long = 217; +pub const SYS_removexattr: ::c_long = 218; +pub const SYS_lremovexattr: ::c_long = 219; +pub const SYS_fremovexattr: ::c_long = 220; +pub const SYS_futex: ::c_long = 221; +pub const SYS_sched_setaffinity: ::c_long = 222; +pub const SYS_sched_getaffinity: ::c_long = 223; +pub const SYS_tuxcall: ::c_long = 225; +pub const SYS_io_setup: ::c_long = 227; +pub const SYS_io_destroy: ::c_long = 228; +pub const SYS_io_getevents: ::c_long = 229; +pub const SYS_io_submit: ::c_long = 230; +pub const SYS_io_cancel: ::c_long = 231; +pub const SYS_set_tid_address: ::c_long = 232; +pub const SYS_exit_group: ::c_long = 234; +pub const SYS_lookup_dcookie: ::c_long = 235; +pub const SYS_epoll_create: ::c_long = 236; +pub const SYS_epoll_ctl: ::c_long = 237; +pub const SYS_epoll_wait: ::c_long = 238; +pub const SYS_remap_file_pages: ::c_long = 239; +pub const SYS_timer_create: ::c_long = 240; +pub const SYS_timer_settime: ::c_long = 241; +pub const SYS_timer_gettime: ::c_long = 242; +pub const SYS_timer_getoverrun: ::c_long = 243; +pub const SYS_timer_delete: ::c_long = 244; +pub const SYS_clock_settime: ::c_long = 245; +pub const SYS_clock_gettime: ::c_long = 246; +pub const SYS_clock_getres: ::c_long = 247; +pub const SYS_clock_nanosleep: ::c_long = 248; +pub const SYS_swapcontext: ::c_long = 249; +pub const SYS_tgkill: ::c_long = 250; +pub const SYS_utimes: ::c_long = 251; +pub const SYS_statfs64: ::c_long = 252; +pub const SYS_fstatfs64: ::c_long = 253; +pub const SYS_rtas: ::c_long = 255; +pub const SYS_sys_debug_setcontext: ::c_long = 256; +pub const SYS_migrate_pages: ::c_long = 258; +pub const SYS_mbind: ::c_long = 259; +pub const SYS_get_mempolicy: ::c_long = 260; +pub const SYS_set_mempolicy: ::c_long = 261; +pub const SYS_mq_open: ::c_long = 262; +pub const SYS_mq_unlink: ::c_long = 263; +pub const SYS_mq_timedsend: ::c_long = 264; +pub const SYS_mq_timedreceive: ::c_long = 265; +pub const SYS_mq_notify: ::c_long = 266; +pub const SYS_mq_getsetattr: ::c_long = 267; +pub const SYS_kexec_load: ::c_long = 268; +pub const SYS_add_key: ::c_long = 269; +pub const SYS_request_key: ::c_long = 270; +pub const SYS_keyctl: ::c_long = 271; +pub const SYS_waitid: ::c_long = 272; +pub const SYS_ioprio_set: ::c_long = 273; +pub const SYS_ioprio_get: ::c_long = 274; +pub const SYS_inotify_init: ::c_long = 275; +pub const SYS_inotify_add_watch: ::c_long = 276; +pub const SYS_inotify_rm_watch: ::c_long = 277; +pub const SYS_spu_run: ::c_long = 278; +pub const SYS_spu_create: ::c_long = 279; +pub const SYS_pselect6: ::c_long = 280; +pub const SYS_ppoll: ::c_long = 281; +pub const SYS_unshare: ::c_long = 282; +pub const SYS_splice: ::c_long = 283; +pub const SYS_tee: ::c_long = 284; +pub const SYS_vmsplice: ::c_long = 285; +pub const SYS_openat: ::c_long = 286; +pub const SYS_mkdirat: ::c_long = 287; +pub const SYS_mknodat: ::c_long = 288; +pub const SYS_fchownat: ::c_long = 289; +pub const SYS_futimesat: ::c_long = 290; +pub const SYS_newfstatat: ::c_long = 291; +pub const SYS_unlinkat: ::c_long = 292; +pub const SYS_renameat: ::c_long = 293; +pub const SYS_linkat: ::c_long = 294; +pub const SYS_symlinkat: ::c_long = 295; +pub const SYS_readlinkat: ::c_long = 296; +pub const SYS_fchmodat: ::c_long = 297; +pub const SYS_faccessat: ::c_long = 298; +pub const SYS_get_robust_list: ::c_long = 299; +pub const SYS_set_robust_list: ::c_long = 300; +pub const SYS_move_pages: ::c_long = 301; +pub const SYS_getcpu: ::c_long = 302; +pub const SYS_epoll_pwait: ::c_long = 303; +pub const SYS_utimensat: ::c_long = 304; +pub const SYS_signalfd: ::c_long = 305; +pub const SYS_timerfd_create: ::c_long = 306; +pub const SYS_eventfd: ::c_long = 307; +pub const SYS_sync_file_range2: ::c_long = 308; +pub const SYS_fallocate: ::c_long = 309; +pub const SYS_subpage_prot: ::c_long = 310; +pub const SYS_timerfd_settime: ::c_long = 311; +pub const SYS_timerfd_gettime: ::c_long = 312; +pub const SYS_signalfd4: ::c_long = 313; +pub const SYS_eventfd2: ::c_long = 314; +pub const SYS_epoll_create1: ::c_long = 315; +pub const SYS_dup3: ::c_long = 316; +pub const SYS_pipe2: ::c_long = 317; +pub const SYS_inotify_init1: ::c_long = 318; +pub const SYS_perf_event_open: ::c_long = 319; +pub const SYS_preadv: ::c_long = 320; +pub const SYS_pwritev: ::c_long = 321; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 322; +pub const SYS_fanotify_init: ::c_long = 323; +pub const SYS_fanotify_mark: ::c_long = 324; +pub const SYS_prlimit64: ::c_long = 325; +pub const SYS_socket: ::c_long = 326; +pub const SYS_bind: ::c_long = 327; +pub const SYS_connect: ::c_long = 328; +pub const SYS_listen: ::c_long = 329; +pub const SYS_accept: ::c_long = 330; +pub const SYS_getsockname: ::c_long = 331; +pub const SYS_getpeername: ::c_long = 332; +pub const SYS_socketpair: ::c_long = 333; +pub const SYS_send: ::c_long = 334; +pub const SYS_sendto: ::c_long = 335; +pub const SYS_recv: ::c_long = 336; +pub const SYS_recvfrom: ::c_long = 337; +pub const SYS_shutdown: ::c_long = 338; +pub const SYS_setsockopt: ::c_long = 339; +pub const SYS_getsockopt: ::c_long = 340; +pub const SYS_sendmsg: ::c_long = 341; +pub const SYS_recvmsg: ::c_long = 342; +pub const SYS_recvmmsg: ::c_long = 343; +pub const SYS_accept4: ::c_long = 344; +pub const SYS_name_to_handle_at: ::c_long = 345; +pub const SYS_open_by_handle_at: ::c_long = 346; +pub const SYS_clock_adjtime: ::c_long = 347; +pub const SYS_syncfs: ::c_long = 348; +pub const SYS_sendmmsg: ::c_long = 349; +pub const SYS_setns: ::c_long = 350; +pub const SYS_process_vm_readv: ::c_long = 351; +pub const SYS_process_vm_writev: ::c_long = 352; +pub const SYS_finit_module: ::c_long = 353; +pub const SYS_kcmp: ::c_long = 354; +pub const SYS_sched_setattr: ::c_long = 355; +pub const SYS_sched_getattr: ::c_long = 356; +pub const SYS_renameat2: ::c_long = 357; +pub const SYS_seccomp: ::c_long = 358; +pub const SYS_getrandom: ::c_long = 359; +pub const SYS_memfd_create: ::c_long = 360; +pub const SYS_bpf: ::c_long = 361; +pub const SYS_execveat: ::c_long = 362; +pub const SYS_switch_endian: ::c_long = 363; +pub const SYS_userfaultfd: ::c_long = 364; +pub const SYS_membarrier: ::c_long = 365; +pub const SYS_mlock2: ::c_long = 378; +pub const SYS_copy_file_range: ::c_long = 379; +pub const SYS_preadv2: ::c_long = 380; +pub const SYS_pwritev2: ::c_long = 381; +pub const SYS_kexec_file_load: ::c_long = 382; + +pub const FIOCLEX: ::c_int = 0x20006601; +pub const FIONBIO: ::c_int = 0x8004667e; +pub const EDEADLK: ::c_int = 58; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const SO_PASSCRED: ::c_int = 20; +pub const SO_PEERCRED: ::c_int = 21; +pub const SO_RCVLOWAT: ::c_int = 16; +pub const SO_SNDLOWAT: ::c_int = 17; +pub const SO_RCVTIMEO: ::c_int = 18; +pub const SO_SNDTIMEO: ::c_int = 19; +pub const EXTPROC: ::tcflag_t = 0x10000000; +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: ::tcflag_t = 0x00000400; +pub const TOSTOP: ::tcflag_t = 0x00400000; +pub const FLUSHO: ::tcflag_t = 0x00800000; +pub const TCGETS: ::c_int = 0x403c7413; +pub const TCSETS: ::c_int = 0x803c7414; +pub const TCSETSW: ::c_int = 0x803c7415; +pub const TCSETSF: ::c_int = 0x803c7416; +pub const TCGETA: ::c_int = 0x40147417; +pub const TCSETA: ::c_int = 0x80147418; +pub const TCSETAW: ::c_int = 0x80147419; +pub const TCSETAF: ::c_int = 0x8014741c; +pub const TCSBRK: ::c_int = 0x2000741d; +pub const TCXONC: ::c_int = 0x2000741e; +pub const TCFLSH: ::c_int = 0x2000741f; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x40047477; +pub const TIOCSPGRP: ::c_int = 0x80047476; +pub const TIOCOUTQ: ::c_int = 0x40047473; +pub const TIOCGWINSZ: ::c_int = 0x40087468; +pub const TIOCSWINSZ: ::c_int = 0x80087467; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x4004667f; +pub const TIOCCONS: ::c_int = 0x541D; +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +pub const TIOCGRS485: ::c_int = 0x542E; +pub const TIOCSRS485: ::c_int = 0x542F; + +pub const RLIMIT_NLIMITS: ::c_int = 15; +pub const TIOCINQ: ::c_int = ::FIONREAD; +pub const MCL_CURRENT: ::c_int = 0x2000; +pub const MCL_FUTURE: ::c_int = 0x4000; +pub const CBAUD: ::tcflag_t = 0xff; +pub const TAB1: ::c_int = 0x400; +pub const TAB2: ::c_int = 0x800; +pub const TAB3: ::c_int = 0xc00; +pub const CR1: ::c_int = 0x1000; +pub const CR2: ::c_int = 0x2000; +pub const CR3: ::c_int = 0x3000; +pub const FF1: ::c_int = 0x4000; +pub const BS1: ::c_int = 0x8000; +pub const VT1: ::c_int = 0x10000; +pub const VWERASE: usize = 10; +pub const VREPRINT: usize = 11; +pub const VSUSP: usize = 12; +pub const VSTART: usize = 13; +pub const VSTOP: usize = 14; +pub const VDISCARD: usize = 16; +pub const VTIME: usize = 7; +pub const IXON: ::tcflag_t = 0x00000200; +pub const IXOFF: ::tcflag_t = 0x00000400; +pub const ONLCR: ::tcflag_t = 0x2; +pub const CSIZE: ::tcflag_t = 0x00000300; + +pub const CS6: ::tcflag_t = 0x00000100; +pub const CS7: ::tcflag_t = 0x00000200; +pub const CS8: ::tcflag_t = 0x00000300; +pub const CSTOPB: ::tcflag_t = 0x00000400; +pub const CREAD: ::tcflag_t = 0x00000800; +pub const PARENB: ::tcflag_t = 0x00001000; +pub const PARODD: ::tcflag_t = 0x00002000; +pub const HUPCL: ::tcflag_t = 0x00004000; +pub const CLOCAL: ::tcflag_t = 0x00008000; +pub const ECHOKE: ::tcflag_t = 0x00000001; +pub const ECHOE: ::tcflag_t = 0x00000002; +pub const ECHOK: ::tcflag_t = 0x00000004; +pub const ECHONL: ::tcflag_t = 0x00000010; +pub const ECHOPRT: ::tcflag_t = 0x00000020; +pub const ECHOCTL: ::tcflag_t = 0x00000040; +pub const ISIG: ::tcflag_t = 0x00000080; +pub const ICANON: ::tcflag_t = 0x00000100; +pub const PENDIN: ::tcflag_t = 0x20000000; +pub const NOFLSH: ::tcflag_t = 0x80000000; + +pub const CIBAUD: ::tcflag_t = 0o77600000; +pub const CBAUDEX: ::tcflag_t = 0o0000020; +pub const VSWTC: usize = 9; +pub const OLCUC: ::tcflag_t = 0o000004; +pub const NLDLY: ::tcflag_t = 0o0001400; +pub const CRDLY: ::tcflag_t = 0o0030000; +pub const TABDLY: ::tcflag_t = 0o0006000; +pub const BSDLY: ::tcflag_t = 0o0100000; +pub const FFDLY: ::tcflag_t = 0o0040000; +pub const VTDLY: ::tcflag_t = 0o0200000; +pub const XTABS: ::tcflag_t = 0o00006000; + +pub const B57600: ::speed_t = 0o00020; +pub const B115200: ::speed_t = 0o00021; +pub const B230400: ::speed_t = 0o00022; +pub const B460800: ::speed_t = 0o00023; +pub const B500000: ::speed_t = 0o00024; +pub const B576000: ::speed_t = 0o00025; +pub const B921600: ::speed_t = 0o00026; +pub const B1000000: ::speed_t = 0o00027; +pub const B1152000: ::speed_t = 0o00030; +pub const B1500000: ::speed_t = 0o00031; +pub const B2000000: ::speed_t = 0o00032; +pub const B2500000: ::speed_t = 0o00033; +pub const B3000000: ::speed_t = 0o00034; +pub const B3500000: ::speed_t = 0o00035; +pub const B4000000: ::speed_t = 0o00036; + +extern { + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/musl/b64/x86_64.rs b/libc/src/unix/notbsd/linux/musl/b64/x86_64.rs new file mode 100644 index 000000000..94c5d88da --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/b64/x86_64.rs @@ -0,0 +1,634 @@ +pub type c_char = i8; +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = ::c_long; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __reserved: [::c_long; 3], + } + + pub struct mcontext_t { + __private: [u64; 32], + } + + pub struct ipc_perm { + pub __ipc_perm_key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_int, + __unused1: ::c_long, + __unused2: ::c_long + } +} + +s_no_extra_traits!{ + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + __private: [u8; 512], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for ucontext_t { + fn eq(&self, other: &ucontext_t) -> bool { + self.uc_flags == other.uc_flags + && self.uc_link == other.uc_link + && self.uc_stack == other.uc_stack + && self.uc_mcontext == other.uc_mcontext + && self.uc_sigmask == other.uc_sigmask + && self + .__private + .iter() + .zip(other.__private.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for ucontext_t {} + + impl ::fmt::Debug for ucontext_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ucontext_t") + .field("uc_flags", &self.uc_flags) + .field("uc_link", &self.uc_link) + .field("uc_stack", &self.uc_stack) + .field("uc_mcontext", &self.uc_mcontext) + .field("uc_sigmask", &self.uc_sigmask) + // Ignore __private field + .finish() + } + } + + impl ::hash::Hash for ucontext_t { + fn hash(&self, state: &mut H) { + self.uc_flags.hash(state); + self.uc_link.hash(state); + self.uc_stack.hash(state); + self.uc_mcontext.hash(state); + self.uc_sigmask.hash(state); + self.__private.hash(state); + } + } + } +} + +// Syscall table + +pub const SYS_read: ::c_long = 0; +pub const SYS_write: ::c_long = 1; +pub const SYS_open: ::c_long = 2; +pub const SYS_close: ::c_long = 3; +pub const SYS_stat: ::c_long = 4; +pub const SYS_fstat: ::c_long = 5; +pub const SYS_lstat: ::c_long = 6; +pub const SYS_poll: ::c_long = 7; +pub const SYS_lseek: ::c_long = 8; +pub const SYS_mmap: ::c_long = 9; +pub const SYS_mprotect: ::c_long = 10; +pub const SYS_munmap: ::c_long = 11; +pub const SYS_brk: ::c_long = 12; +pub const SYS_rt_sigaction: ::c_long = 13; +pub const SYS_rt_sigprocmask: ::c_long = 14; +pub const SYS_rt_sigreturn: ::c_long = 15; +pub const SYS_ioctl: ::c_long = 16; +pub const SYS_pread64: ::c_long = 17; +pub const SYS_pwrite64: ::c_long = 18; +pub const SYS_readv: ::c_long = 19; +pub const SYS_writev: ::c_long = 20; +pub const SYS_access: ::c_long = 21; +pub const SYS_pipe: ::c_long = 22; +pub const SYS_select: ::c_long = 23; +pub const SYS_sched_yield: ::c_long = 24; +pub const SYS_mremap: ::c_long = 25; +pub const SYS_msync: ::c_long = 26; +pub const SYS_mincore: ::c_long = 27; +pub const SYS_madvise: ::c_long = 28; +pub const SYS_shmget: ::c_long = 29; +pub const SYS_shmat: ::c_long = 30; +pub const SYS_shmctl: ::c_long = 31; +pub const SYS_dup: ::c_long = 32; +pub const SYS_dup2: ::c_long = 33; +pub const SYS_pause: ::c_long = 34; +pub const SYS_nanosleep: ::c_long = 35; +pub const SYS_getitimer: ::c_long = 36; +pub const SYS_alarm: ::c_long = 37; +pub const SYS_setitimer: ::c_long = 38; +pub const SYS_getpid: ::c_long = 39; +pub const SYS_sendfile: ::c_long = 40; +pub const SYS_socket: ::c_long = 41; +pub const SYS_connect: ::c_long = 42; +pub const SYS_accept: ::c_long = 43; +pub const SYS_sendto: ::c_long = 44; +pub const SYS_recvfrom: ::c_long = 45; +pub const SYS_sendmsg: ::c_long = 46; +pub const SYS_recvmsg: ::c_long = 47; +pub const SYS_shutdown: ::c_long = 48; +pub const SYS_bind: ::c_long = 49; +pub const SYS_listen: ::c_long = 50; +pub const SYS_getsockname: ::c_long = 51; +pub const SYS_getpeername: ::c_long = 52; +pub const SYS_socketpair: ::c_long = 53; +pub const SYS_setsockopt: ::c_long = 54; +pub const SYS_getsockopt: ::c_long = 55; +pub const SYS_clone: ::c_long = 56; +pub const SYS_fork: ::c_long = 57; +pub const SYS_vfork: ::c_long = 58; +pub const SYS_execve: ::c_long = 59; +pub const SYS_exit: ::c_long = 60; +pub const SYS_wait4: ::c_long = 61; +pub const SYS_kill: ::c_long = 62; +pub const SYS_uname: ::c_long = 63; +pub const SYS_semget: ::c_long = 64; +pub const SYS_semop: ::c_long = 65; +pub const SYS_semctl: ::c_long = 66; +pub const SYS_shmdt: ::c_long = 67; +pub const SYS_msgget: ::c_long = 68; +pub const SYS_msgsnd: ::c_long = 69; +pub const SYS_msgrcv: ::c_long = 70; +pub const SYS_msgctl: ::c_long = 71; +pub const SYS_fcntl: ::c_long = 72; +pub const SYS_flock: ::c_long = 73; +pub const SYS_fsync: ::c_long = 74; +pub const SYS_fdatasync: ::c_long = 75; +pub const SYS_truncate: ::c_long = 76; +pub const SYS_ftruncate: ::c_long = 77; +pub const SYS_getdents: ::c_long = 78; +pub const SYS_getcwd: ::c_long = 79; +pub const SYS_chdir: ::c_long = 80; +pub const SYS_fchdir: ::c_long = 81; +pub const SYS_rename: ::c_long = 82; +pub const SYS_mkdir: ::c_long = 83; +pub const SYS_rmdir: ::c_long = 84; +pub const SYS_creat: ::c_long = 85; +pub const SYS_link: ::c_long = 86; +pub const SYS_unlink: ::c_long = 87; +pub const SYS_symlink: ::c_long = 88; +pub const SYS_readlink: ::c_long = 89; +pub const SYS_chmod: ::c_long = 90; +pub const SYS_fchmod: ::c_long = 91; +pub const SYS_chown: ::c_long = 92; +pub const SYS_fchown: ::c_long = 93; +pub const SYS_lchown: ::c_long = 94; +pub const SYS_umask: ::c_long = 95; +pub const SYS_gettimeofday: ::c_long = 96; +pub const SYS_getrlimit: ::c_long = 97; +pub const SYS_getrusage: ::c_long = 98; +pub const SYS_sysinfo: ::c_long = 99; +pub const SYS_times: ::c_long = 100; +pub const SYS_ptrace: ::c_long = 101; +pub const SYS_getuid: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_getgid: ::c_long = 104; +pub const SYS_setuid: ::c_long = 105; +pub const SYS_setgid: ::c_long = 106; +pub const SYS_geteuid: ::c_long = 107; +pub const SYS_getegid: ::c_long = 108; +pub const SYS_setpgid: ::c_long = 109; +pub const SYS_getppid: ::c_long = 110; +pub const SYS_getpgrp: ::c_long = 111; +pub const SYS_setsid: ::c_long = 112; +pub const SYS_setreuid: ::c_long = 113; +pub const SYS_setregid: ::c_long = 114; +pub const SYS_getgroups: ::c_long = 115; +pub const SYS_setgroups: ::c_long = 116; +pub const SYS_setresuid: ::c_long = 117; +pub const SYS_getresuid: ::c_long = 118; +pub const SYS_setresgid: ::c_long = 119; +pub const SYS_getresgid: ::c_long = 120; +pub const SYS_getpgid: ::c_long = 121; +pub const SYS_setfsuid: ::c_long = 122; +pub const SYS_setfsgid: ::c_long = 123; +pub const SYS_getsid: ::c_long = 124; +pub const SYS_capget: ::c_long = 125; +pub const SYS_capset: ::c_long = 126; +pub const SYS_rt_sigpending: ::c_long = 127; +pub const SYS_rt_sigtimedwait: ::c_long = 128; +pub const SYS_rt_sigqueueinfo: ::c_long = 129; +pub const SYS_rt_sigsuspend: ::c_long = 130; +pub const SYS_sigaltstack: ::c_long = 131; +pub const SYS_utime: ::c_long = 132; +pub const SYS_mknod: ::c_long = 133; +pub const SYS_uselib: ::c_long = 134; +pub const SYS_personality: ::c_long = 135; +pub const SYS_ustat: ::c_long = 136; +pub const SYS_statfs: ::c_long = 137; +pub const SYS_fstatfs: ::c_long = 138; +pub const SYS_sysfs: ::c_long = 139; +pub const SYS_getpriority: ::c_long = 140; +pub const SYS_setpriority: ::c_long = 141; +pub const SYS_sched_setparam: ::c_long = 142; +pub const SYS_sched_getparam: ::c_long = 143; +pub const SYS_sched_setscheduler: ::c_long = 144; +pub const SYS_sched_getscheduler: ::c_long = 145; +pub const SYS_sched_get_priority_max: ::c_long = 146; +pub const SYS_sched_get_priority_min: ::c_long = 147; +pub const SYS_sched_rr_get_interval: ::c_long = 148; +pub const SYS_mlock: ::c_long = 149; +pub const SYS_munlock: ::c_long = 150; +pub const SYS_mlockall: ::c_long = 151; +pub const SYS_munlockall: ::c_long = 152; +pub const SYS_vhangup: ::c_long = 153; +pub const SYS_modify_ldt: ::c_long = 154; +pub const SYS_pivot_root: ::c_long = 155; +pub const SYS__sysctl: ::c_long = 156; +pub const SYS_prctl: ::c_long = 157; +pub const SYS_arch_prctl: ::c_long = 158; +pub const SYS_adjtimex: ::c_long = 159; +pub const SYS_setrlimit: ::c_long = 160; +pub const SYS_chroot: ::c_long = 161; +pub const SYS_sync: ::c_long = 162; +pub const SYS_acct: ::c_long = 163; +pub const SYS_settimeofday: ::c_long = 164; +pub const SYS_mount: ::c_long = 165; +pub const SYS_umount2: ::c_long = 166; +pub const SYS_swapon: ::c_long = 167; +pub const SYS_swapoff: ::c_long = 168; +pub const SYS_reboot: ::c_long = 169; +pub const SYS_sethostname: ::c_long = 170; +pub const SYS_setdomainname: ::c_long = 171; +pub const SYS_iopl: ::c_long = 172; +pub const SYS_ioperm: ::c_long = 173; +pub const SYS_create_module: ::c_long = 174; +pub const SYS_init_module: ::c_long = 175; +pub const SYS_delete_module: ::c_long = 176; +pub const SYS_get_kernel_syms: ::c_long = 177; +pub const SYS_query_module: ::c_long = 178; +pub const SYS_quotactl: ::c_long = 179; +pub const SYS_nfsservctl: ::c_long = 180; +pub const SYS_getpmsg: ::c_long = 181; +pub const SYS_putpmsg: ::c_long = 182; +pub const SYS_afs_syscall: ::c_long = 183; +pub const SYS_tuxcall: ::c_long = 184; +pub const SYS_security: ::c_long = 185; +pub const SYS_gettid: ::c_long = 186; +pub const SYS_readahead: ::c_long = 187; +pub const SYS_setxattr: ::c_long = 188; +pub const SYS_lsetxattr: ::c_long = 189; +pub const SYS_fsetxattr: ::c_long = 190; +pub const SYS_getxattr: ::c_long = 191; +pub const SYS_lgetxattr: ::c_long = 192; +pub const SYS_fgetxattr: ::c_long = 193; +pub const SYS_listxattr: ::c_long = 194; +pub const SYS_llistxattr: ::c_long = 195; +pub const SYS_flistxattr: ::c_long = 196; +pub const SYS_removexattr: ::c_long = 197; +pub const SYS_lremovexattr: ::c_long = 198; +pub const SYS_fremovexattr: ::c_long = 199; +pub const SYS_tkill: ::c_long = 200; +pub const SYS_time: ::c_long = 201; +pub const SYS_futex: ::c_long = 202; +pub const SYS_sched_setaffinity: ::c_long = 203; +pub const SYS_sched_getaffinity: ::c_long = 204; +pub const SYS_set_thread_area: ::c_long = 205; +pub const SYS_io_setup: ::c_long = 206; +pub const SYS_io_destroy: ::c_long = 207; +pub const SYS_io_getevents: ::c_long = 208; +pub const SYS_io_submit: ::c_long = 209; +pub const SYS_io_cancel: ::c_long = 210; +pub const SYS_get_thread_area: ::c_long = 211; +pub const SYS_lookup_dcookie: ::c_long = 212; +pub const SYS_epoll_create: ::c_long = 213; +pub const SYS_epoll_ctl_old: ::c_long = 214; +pub const SYS_epoll_wait_old: ::c_long = 215; +pub const SYS_remap_file_pages: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_set_tid_address: ::c_long = 218; +pub const SYS_restart_syscall: ::c_long = 219; +pub const SYS_semtimedop: ::c_long = 220; +pub const SYS_fadvise64: ::c_long = 221; +pub const SYS_timer_create: ::c_long = 222; +pub const SYS_timer_settime: ::c_long = 223; +pub const SYS_timer_gettime: ::c_long = 224; +pub const SYS_timer_getoverrun: ::c_long = 225; +pub const SYS_timer_delete: ::c_long = 226; +pub const SYS_clock_settime: ::c_long = 227; +pub const SYS_clock_gettime: ::c_long = 228; +pub const SYS_clock_getres: ::c_long = 229; +pub const SYS_clock_nanosleep: ::c_long = 230; +pub const SYS_exit_group: ::c_long = 231; +pub const SYS_epoll_wait: ::c_long = 232; +pub const SYS_epoll_ctl: ::c_long = 233; +pub const SYS_tgkill: ::c_long = 234; +pub const SYS_utimes: ::c_long = 235; +pub const SYS_vserver: ::c_long = 236; +pub const SYS_mbind: ::c_long = 237; +pub const SYS_set_mempolicy: ::c_long = 238; +pub const SYS_get_mempolicy: ::c_long = 239; +pub const SYS_mq_open: ::c_long = 240; +pub const SYS_mq_unlink: ::c_long = 241; +pub const SYS_mq_timedsend: ::c_long = 242; +pub const SYS_mq_timedreceive: ::c_long = 243; +pub const SYS_mq_notify: ::c_long = 244; +pub const SYS_mq_getsetattr: ::c_long = 245; +pub const SYS_kexec_load: ::c_long = 246; +pub const SYS_waitid: ::c_long = 247; +pub const SYS_add_key: ::c_long = 248; +pub const SYS_request_key: ::c_long = 249; +pub const SYS_keyctl: ::c_long = 250; +pub const SYS_ioprio_set: ::c_long = 251; +pub const SYS_ioprio_get: ::c_long = 252; +pub const SYS_inotify_init: ::c_long = 253; +pub const SYS_inotify_add_watch: ::c_long = 254; +pub const SYS_inotify_rm_watch: ::c_long = 255; +pub const SYS_migrate_pages: ::c_long = 256; +pub const SYS_openat: ::c_long = 257; +pub const SYS_mkdirat: ::c_long = 258; +pub const SYS_mknodat: ::c_long = 259; +pub const SYS_fchownat: ::c_long = 260; +pub const SYS_futimesat: ::c_long = 261; +pub const SYS_newfstatat: ::c_long = 262; +pub const SYS_unlinkat: ::c_long = 263; +pub const SYS_renameat: ::c_long = 264; +pub const SYS_linkat: ::c_long = 265; +pub const SYS_symlinkat: ::c_long = 266; +pub const SYS_readlinkat: ::c_long = 267; +pub const SYS_fchmodat: ::c_long = 268; +pub const SYS_faccessat: ::c_long = 269; +pub const SYS_pselect6: ::c_long = 270; +pub const SYS_ppoll: ::c_long = 271; +pub const SYS_unshare: ::c_long = 272; +pub const SYS_set_robust_list: ::c_long = 273; +pub const SYS_get_robust_list: ::c_long = 274; +pub const SYS_splice: ::c_long = 275; +pub const SYS_tee: ::c_long = 276; +pub const SYS_sync_file_range: ::c_long = 277; +pub const SYS_vmsplice: ::c_long = 278; +pub const SYS_move_pages: ::c_long = 279; +pub const SYS_utimensat: ::c_long = 280; +pub const SYS_epoll_pwait: ::c_long = 281; +pub const SYS_signalfd: ::c_long = 282; +pub const SYS_timerfd_create: ::c_long = 283; +pub const SYS_eventfd: ::c_long = 284; +pub const SYS_fallocate: ::c_long = 285; +pub const SYS_timerfd_settime: ::c_long = 286; +pub const SYS_timerfd_gettime: ::c_long = 287; +pub const SYS_accept4: ::c_long = 288; +pub const SYS_signalfd4: ::c_long = 289; +pub const SYS_eventfd2: ::c_long = 290; +pub const SYS_epoll_create1: ::c_long = 291; +pub const SYS_dup3: ::c_long = 292; +pub const SYS_pipe2: ::c_long = 293; +pub const SYS_inotify_init1: ::c_long = 294; +pub const SYS_preadv: ::c_long = 295; +pub const SYS_pwritev: ::c_long = 296; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 297; +pub const SYS_perf_event_open: ::c_long = 298; +pub const SYS_recvmmsg: ::c_long = 299; +pub const SYS_fanotify_init: ::c_long = 300; +pub const SYS_fanotify_mark: ::c_long = 301; +pub const SYS_prlimit64: ::c_long = 302; +pub const SYS_name_to_handle_at: ::c_long = 303; +pub const SYS_open_by_handle_at: ::c_long = 304; +pub const SYS_clock_adjtime: ::c_long = 305; +pub const SYS_syncfs: ::c_long = 306; +pub const SYS_sendmmsg: ::c_long = 307; +pub const SYS_setns: ::c_long = 308; +pub const SYS_getcpu: ::c_long = 309; +pub const SYS_process_vm_readv: ::c_long = 310; +pub const SYS_process_vm_writev: ::c_long = 311; +pub const SYS_kcmp: ::c_long = 312; +pub const SYS_finit_module: ::c_long = 313; +pub const SYS_sched_setattr: ::c_long = 314; +pub const SYS_sched_getattr: ::c_long = 315; +pub const SYS_renameat2: ::c_long = 316; +pub const SYS_seccomp: ::c_long = 317; +pub const SYS_getrandom: ::c_long = 318; +pub const SYS_memfd_create: ::c_long = 319; +pub const SYS_kexec_file_load: ::c_long = 320; +pub const SYS_bpf: ::c_long = 321; +pub const SYS_execveat: ::c_long = 322; +pub const SYS_userfaultfd: ::c_long = 323; +pub const SYS_membarrier: ::c_long = 324; +pub const SYS_mlock2: ::c_long = 325; +pub const SYS_copy_file_range: ::c_long = 326; +pub const SYS_preadv2: ::c_long = 327; +pub const SYS_pwritev2: ::c_long = 328; +// FIXME syscalls 329-331 have been added in musl 1.16 +// See discussion https://github.com/rust-lang/libc/pull/699 + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: ::c_int = 0; +pub const R14: ::c_int = 1; +pub const R13: ::c_int = 2; +pub const R12: ::c_int = 3; +pub const RBP: ::c_int = 4; +pub const RBX: ::c_int = 5; +pub const R11: ::c_int = 6; +pub const R10: ::c_int = 7; +pub const R9: ::c_int = 8; +pub const R8: ::c_int = 9; +pub const RAX: ::c_int = 10; +pub const RCX: ::c_int = 11; +pub const RDX: ::c_int = 12; +pub const RSI: ::c_int = 13; +pub const RDI: ::c_int = 14; +pub const ORIG_RAX: ::c_int = 15; +pub const RIP: ::c_int = 16; +pub const CS: ::c_int = 17; +pub const EFLAGS: ::c_int = 18; +pub const RSP: ::c_int = 19; +pub const SS: ::c_int = 20; +pub const FS_BASE: ::c_int = 21; +pub const GS_BASE: ::c_int = 22; +pub const DS: ::c_int = 23; +pub const ES: ::c_int = 24; +pub const FS: ::c_int = 25; +pub const GS: ::c_int = 26; + +pub const MAP_32BIT: ::c_int = 0x0040; +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_LARGEFILE: ::c_int = 0; +pub const O_NOFOLLOW: ::c_int = 0x20000; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +pub const RLIMIT_NLIMITS: ::c_int = 16; +pub const TIOCINQ: ::c_int = ::FIONREAD; +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const FIOCLEX: ::c_int = 0x5451; +pub const FIONBIO: ::c_int = 0x5421; +pub const EDEADLK: ::c_int = 35; +pub const EDEADLOCK: ::c_int = EDEADLK; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const TCGETS: ::c_int = 0x5401; +pub const TCSETS: ::c_int = 0x5402; +pub const TCSETSW: ::c_int = 0x5403; +pub const TCSETSF: ::c_int = 0x5404; +pub const TCGETA: ::c_int = 0x5405; +pub const TCSETA: ::c_int = 0x5406; +pub const TCSETAW: ::c_int = 0x5407; +pub const TCSETAF: ::c_int = 0x5408; +pub const TCSBRK: ::c_int = 0x5409; +pub const TCXONC: ::c_int = 0x540A; +pub const TCFLSH: ::c_int = 0x540B; +pub const TIOCGSOFTCAR: ::c_int = 0x5419; +pub const TIOCSSOFTCAR: ::c_int = 0x541A; +pub const TIOCLINUX: ::c_int = 0x541C; +pub const TIOCGSERIAL: ::c_int = 0x541E; +pub const TIOCEXCL: ::c_int = 0x540C; +pub const TIOCNXCL: ::c_int = 0x540D; +pub const TIOCSCTTY: ::c_int = 0x540E; +pub const TIOCGPGRP: ::c_int = 0x540F; +pub const TIOCSPGRP: ::c_int = 0x5410; +pub const TIOCOUTQ: ::c_int = 0x5411; +pub const TIOCSTI: ::c_int = 0x5412; +pub const TIOCGWINSZ: ::c_int = 0x5413; +pub const TIOCSWINSZ: ::c_int = 0x5414; +pub const TIOCMGET: ::c_int = 0x5415; +pub const TIOCMBIS: ::c_int = 0x5416; +pub const TIOCMBIC: ::c_int = 0x5417; +pub const TIOCMSET: ::c_int = 0x5418; +pub const FIONREAD: ::c_int = 0x541B; +pub const TIOCCONS: ::c_int = 0x541D; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +extern { + pub fn ioctl(fd: ::c_int, request: ::c_int, ...) -> ::c_int; +} + diff --git a/libc/src/unix/notbsd/linux/musl/mod.rs b/libc/src/unix/notbsd/linux/musl/mod.rs new file mode 100644 index 000000000..4f4a3d868 --- /dev/null +++ b/libc/src/unix/notbsd/linux/musl/mod.rs @@ -0,0 +1,350 @@ +pub type clock_t = c_long; +pub type time_t = c_long; +pub type suseconds_t = c_long; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; + +pub type shmatt_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type fsblkcnt_t = ::c_ulonglong; +pub type fsfilcnt_t = ::c_ulonglong; +pub type rlim_t = ::c_ulonglong; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __td: *mut ::c_void, + __lock: [::c_int; 2], + __err: ::c_int, + __ret: ::ssize_t, + pub aio_offset: off_t, + __next: *mut ::c_void, + __prev: *mut ::c_void, + #[cfg(target_pointer_width = "32")] + __dummy4: [::c_char; 24], + #[cfg(target_pointer_width = "64")] + __dummy4: [::c_char; 16], + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + pub sa_flags: ::c_int, + pub sa_restorer: ::Option, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: ::c_ulong, + #[cfg(target_pointer_width = "32")] + __f_unused: ::c_int, + #[cfg(target_endian = "big")] + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub __c_ispeed: ::speed_t, + pub __c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } +} + +s_no_extra_traits!{ + pub struct sysinfo { + pub uptime: ::c_ulong, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub __reserved: [::c_char; 256], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sysinfo { + fn eq(&self, other: &sysinfo) -> bool { + self.uptime == other.uptime + && self.loads == other.loads + && self.totalram == other.totalram + && self.freeram == other.freeram + && self.sharedram == other.sharedram + && self.bufferram == other.bufferram + && self.totalswap == other.totalswap + && self.freeswap == other.freeswap + && self.procs == other.procs + && self.pad == other.pad + && self.totalhigh == other.totalhigh + && self.freehigh == other.freehigh + && self.mem_unit == other.mem_unit + && self + .__reserved + .iter() + .zip(other.__reserved.iter()) + .all(|(a,b)| a == b) + } + } + + impl Eq for sysinfo {} + + impl ::fmt::Debug for sysinfo { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sysinfo") + .field("uptime", &self.uptime) + .field("loads", &self.loads) + .field("totalram", &self.totalram) + .field("freeram", &self.freeram) + .field("sharedram", &self.sharedram) + .field("bufferram", &self.bufferram) + .field("totalswap", &self.totalswap) + .field("freeswap", &self.freeswap) + .field("procs", &self.procs) + .field("pad", &self.pad) + .field("totalhigh", &self.totalhigh) + .field("freehigh", &self.freehigh) + .field("mem_unit", &self.mem_unit) + // FIXME: .field("__reserved", &self.__reserved) + .finish() + } + } + + impl ::hash::Hash for sysinfo { + fn hash(&self, state: &mut H) { + self.uptime.hash(state); + self.loads.hash(state); + self.totalram.hash(state); + self.freeram.hash(state); + self.sharedram.hash(state); + self.bufferram.hash(state); + self.totalswap.hash(state); + self.freeswap.hash(state); + self.procs.hash(state); + self.pad.hash(state); + self.totalhigh.hash(state); + self.freehigh.hash(state); + self.mem_unit.hash(state); + self.__reserved.hash(state); + } + } + } +} + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const BUFSIZ: ::c_uint = 1024; +pub const TMP_MAX: ::c_uint = 10000; +pub const FOPEN_MAX: ::c_uint = 1000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_EXEC: ::c_int = 0o10000000; +pub const O_SEARCH: ::c_int = 0o10000000; +pub const O_ACCMODE: ::c_int = 0o10000003; +pub const O_NDELAY: ::c_int = O_NONBLOCK; +pub const NI_MAXHOST: ::socklen_t = 255; +pub const PTHREAD_STACK_MIN: ::size_t = 2048; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; + +pub const POSIX_MADV_DONTNEED: ::c_int = 4; + +pub const RLIM_INFINITY: ::rlim_t = !0; +pub const RLIMIT_RTTIME: ::c_int = 15; + +pub const MAP_ANONYMOUS: ::c_int = MAP_ANON; + +pub const SOCK_DCCP: ::c_int = 6; +pub const SOCK_PACKET: ::c_int = 10; + +pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16; +pub const TCP_THIN_DUPACK: ::c_int = 17; +pub const TCP_USER_TIMEOUT: ::c_int = 18; +pub const TCP_REPAIR: ::c_int = 19; +pub const TCP_REPAIR_QUEUE: ::c_int = 20; +pub const TCP_QUEUE_SEQ: ::c_int = 21; +pub const TCP_REPAIR_OPTIONS: ::c_int = 22; +pub const TCP_FASTOPEN: ::c_int = 23; +pub const TCP_TIMESTAMP: ::c_int = 24; + +pub const SIGUNUSED: ::c_int = ::SIGSYS; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const CPU_SETSIZE: ::c_int = 128; + +pub const PTRACE_TRACEME: ::c_int = 0; +pub const PTRACE_PEEKTEXT: ::c_int = 1; +pub const PTRACE_PEEKDATA: ::c_int = 2; +pub const PTRACE_PEEKUSER: ::c_int = 3; +pub const PTRACE_POKETEXT: ::c_int = 4; +pub const PTRACE_POKEDATA: ::c_int = 5; +pub const PTRACE_POKEUSER: ::c_int = 6; +pub const PTRACE_CONT: ::c_int = 7; +pub const PTRACE_KILL: ::c_int = 8; +pub const PTRACE_SINGLESTEP: ::c_int = 9; +pub const PTRACE_GETREGS: ::c_int = 12; +pub const PTRACE_SETREGS: ::c_int = 13; +pub const PTRACE_GETFPREGS: ::c_int = 14; +pub const PTRACE_SETFPREGS: ::c_int = 15; +pub const PTRACE_ATTACH: ::c_int = 16; +pub const PTRACE_DETACH: ::c_int = 17; +pub const PTRACE_GETFPXREGS: ::c_int = 18; +pub const PTRACE_SETFPXREGS: ::c_int = 19; +pub const PTRACE_SYSCALL: ::c_int = 24; +pub const PTRACE_SETOPTIONS: ::c_int = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_int = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_int = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_int = 0x4203; +pub const PTRACE_GETREGSET: ::c_int = 0x4204; +pub const PTRACE_SETREGSET: ::c_int = 0x4205; +pub const PTRACE_SEIZE: ::c_int = 0x4206; +pub const PTRACE_INTERRUPT: ::c_int = 0x4207; +pub const PTRACE_LISTEN: ::c_int = 0x4208; +pub const PTRACE_PEEKSIGINFO: ::c_int = 0x4209; + +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const EFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const SFD_NONBLOCK: ::c_int = ::O_NONBLOCK; + +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; + +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_NOLOAD: ::c_int = 0x4; + +// TODO(#247) Temporarily musl-specific (available since musl 0.9.12 / Linux +// kernel 3.10). See also notbsd/mod.rs +pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +pub const CLOCK_TAI: ::clockid_t = 11; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; + +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_MARK: ::c_int = 36; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +extern { + pub fn ptrace(request: ::c_int, ...) -> ::c_long; + pub fn getpriority(which: ::c_int, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::id_t, prio: ::c_int) -> ::c_int; + pub fn pthread_getaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_setaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn sched_getcpu() -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64"))] { + mod b64; + pub use self::b64::*; + } else if #[cfg(any(target_arch = "x86", + target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] { + mod b32; + pub use self::b32::*; + } else { } +} diff --git a/libc/src/unix/notbsd/linux/no_align.rs b/libc/src/unix/notbsd/linux/no_align.rs new file mode 100644 index 000000000..1f5f2eea5 --- /dev/null +++ b/libc/src/unix/notbsd/linux/no_align.rs @@ -0,0 +1,80 @@ +macro_rules! expand_align { + () => { + s! { + pub struct pthread_mutexattr_t { + #[cfg(any(target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64", + all(target_arch = "aarch64", + target_env = "musl")))] + __align: [::c_int; 0], + #[cfg(not(any(target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64", + all(target_arch = "aarch64", + target_env = "musl"))))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_rwlockattr_t { + #[cfg(target_env = "musl")] + __align: [::c_int; 0], + #[cfg(not(target_env = "musl"))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCKATTR_T], + } + + pub struct pthread_condattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + pub struct pthread_cond_t { + #[cfg(target_env = "musl")] + __align: [*const ::c_void; 0], + #[cfg(not(target_env = "musl"))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + pub struct pthread_mutex_t { + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + all(target_arch = "x86_64", + target_pointer_width = "32")))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + all(target_arch = "x86_64", + target_pointer_width = "32"))))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_rwlock_t { + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + all(target_arch = "x86_64", + target_pointer_width = "32")))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc", + all(target_arch = "x86_64", + target_pointer_width = "32"))))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + } + } +} diff --git a/libc/src/unix/notbsd/linux/other/align.rs b/libc/src/unix/notbsd/linux/other/align.rs new file mode 100644 index 000000000..4a0e07460 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/align.rs @@ -0,0 +1,13 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/notbsd/linux/other/b32/arm.rs b/libc/src/unix/notbsd/linux/other/b32/arm.rs new file mode 100644 index 000000000..7f00d9a11 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b32/arm.rs @@ -0,0 +1,609 @@ +pub type c_char = u8; +pub type wchar_t = u32; + +s! { + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_ushort, + __pad1: ::c_ushort, + pub __seq: ::c_ushort, + __pad2: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __pad1: ::c_uint, + __st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad2: ::c_uint, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino64_t, + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + __unused1: ::c_ulong, + pub shm_dtime: ::time_t, + __unused2: ::c_ulong, + pub shm_ctime: ::time_t, + __unused3: ::c_ulong, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + __glibc_reserved1: ::c_ulong, + pub msg_rtime: ::time_t, + __glibc_reserved2: ::c_ulong, + pub msg_ctime: ::time_t, + __glibc_reserved3: ::c_ulong, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_LARGEFILE: ::c_int = 0o400000; + +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; + +pub const EDEADLOCK: ::c_int = 35; + +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; + +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FIONBIO: ::c_ulong = 0x5421; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCSETSW: ::c_ulong = 0x5403; +pub const TCSETSF: ::c_ulong = 0x5404; +pub const TCGETA: ::c_ulong = 0x5405; +pub const TCSETA: ::c_ulong = 0x5406; +pub const TCSETAW: ::c_ulong = 0x5407; +pub const TCSETAF: ::c_ulong = 0x5408; +pub const TCSBRK: ::c_ulong = 0x5409; +pub const TCXONC: ::c_ulong = 0x540A; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCINQ: ::c_ulong = 0x541B; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCOUTQ: ::c_ulong = 0x5411; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; +pub const FIONREAD: ::c_ulong = 0x541B; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_pause: ::c_long = 29; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_pivot_root: ::c_long = 218; +pub const SYS_mincore: ::c_long = 219; +pub const SYS_madvise: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_io_setup: ::c_long = 243; +pub const SYS_io_destroy: ::c_long = 244; +pub const SYS_io_getevents: ::c_long = 245; +pub const SYS_io_submit: ::c_long = 246; +pub const SYS_io_cancel: ::c_long = 247; +pub const SYS_exit_group: ::c_long = 248; +pub const SYS_lookup_dcookie: ::c_long = 249; +pub const SYS_epoll_create: ::c_long = 250; +pub const SYS_epoll_ctl: ::c_long = 251; +pub const SYS_epoll_wait: ::c_long = 252; +pub const SYS_remap_file_pages: ::c_long = 253; +pub const SYS_set_tid_address: ::c_long = 256; +pub const SYS_timer_create: ::c_long = 257; +pub const SYS_timer_settime: ::c_long = 258; +pub const SYS_timer_gettime: ::c_long = 259; +pub const SYS_timer_getoverrun: ::c_long = 260; +pub const SYS_timer_delete: ::c_long = 261; +pub const SYS_clock_settime: ::c_long = 262; +pub const SYS_clock_gettime: ::c_long = 263; +pub const SYS_clock_getres: ::c_long = 264; +pub const SYS_clock_nanosleep: ::c_long = 265; +pub const SYS_statfs64: ::c_long = 266; +pub const SYS_fstatfs64: ::c_long = 267; +pub const SYS_tgkill: ::c_long = 268; +pub const SYS_utimes: ::c_long = 269; +pub const SYS_arm_fadvise64_64: ::c_long = 270; +pub const SYS_pciconfig_iobase: ::c_long = 271; +pub const SYS_pciconfig_read: ::c_long = 272; +pub const SYS_pciconfig_write: ::c_long = 273; +pub const SYS_mq_open: ::c_long = 274; +pub const SYS_mq_unlink: ::c_long = 275; +pub const SYS_mq_timedsend: ::c_long = 276; +pub const SYS_mq_timedreceive: ::c_long = 277; +pub const SYS_mq_notify: ::c_long = 278; +pub const SYS_mq_getsetattr: ::c_long = 279; +pub const SYS_waitid: ::c_long = 280; +pub const SYS_socket: ::c_long = 281; +pub const SYS_bind: ::c_long = 282; +pub const SYS_connect: ::c_long = 283; +pub const SYS_listen: ::c_long = 284; +pub const SYS_accept: ::c_long = 285; +pub const SYS_getsockname: ::c_long = 286; +pub const SYS_getpeername: ::c_long = 287; +pub const SYS_socketpair: ::c_long = 288; +pub const SYS_send: ::c_long = 289; +pub const SYS_sendto: ::c_long = 290; +pub const SYS_recv: ::c_long = 291; +pub const SYS_recvfrom: ::c_long = 292; +pub const SYS_shutdown: ::c_long = 293; +pub const SYS_setsockopt: ::c_long = 294; +pub const SYS_getsockopt: ::c_long = 295; +pub const SYS_sendmsg: ::c_long = 296; +pub const SYS_recvmsg: ::c_long = 297; +pub const SYS_semop: ::c_long = 298; +pub const SYS_semget: ::c_long = 299; +pub const SYS_semctl: ::c_long = 300; +pub const SYS_msgsnd: ::c_long = 301; +pub const SYS_msgrcv: ::c_long = 302; +pub const SYS_msgget: ::c_long = 303; +pub const SYS_msgctl: ::c_long = 304; +pub const SYS_shmat: ::c_long = 305; +pub const SYS_shmdt: ::c_long = 306; +pub const SYS_shmget: ::c_long = 307; +pub const SYS_shmctl: ::c_long = 308; +pub const SYS_add_key: ::c_long = 309; +pub const SYS_request_key: ::c_long = 310; +pub const SYS_keyctl: ::c_long = 311; +pub const SYS_semtimedop: ::c_long = 312; +pub const SYS_vserver: ::c_long = 313; +pub const SYS_ioprio_set: ::c_long = 314; +pub const SYS_ioprio_get: ::c_long = 315; +pub const SYS_inotify_init: ::c_long = 316; +pub const SYS_inotify_add_watch: ::c_long = 317; +pub const SYS_inotify_rm_watch: ::c_long = 318; +pub const SYS_mbind: ::c_long = 319; +pub const SYS_get_mempolicy: ::c_long = 320; +pub const SYS_set_mempolicy: ::c_long = 321; +pub const SYS_openat: ::c_long = 322; +pub const SYS_mkdirat: ::c_long = 323; +pub const SYS_mknodat: ::c_long = 324; +pub const SYS_fchownat: ::c_long = 325; +pub const SYS_futimesat: ::c_long = 326; +pub const SYS_fstatat64: ::c_long = 327; +pub const SYS_unlinkat: ::c_long = 328; +pub const SYS_renameat: ::c_long = 329; +pub const SYS_linkat: ::c_long = 330; +pub const SYS_symlinkat: ::c_long = 331; +pub const SYS_readlinkat: ::c_long = 332; +pub const SYS_fchmodat: ::c_long = 333; +pub const SYS_faccessat: ::c_long = 334; +pub const SYS_pselect6: ::c_long = 335; +pub const SYS_ppoll: ::c_long = 336; +pub const SYS_unshare: ::c_long = 337; +pub const SYS_set_robust_list: ::c_long = 338; +pub const SYS_get_robust_list: ::c_long = 339; +pub const SYS_splice: ::c_long = 340; +pub const SYS_arm_sync_file_range: ::c_long = 341; +pub const SYS_tee: ::c_long = 342; +pub const SYS_vmsplice: ::c_long = 343; +pub const SYS_move_pages: ::c_long = 344; +pub const SYS_getcpu: ::c_long = 345; +pub const SYS_epoll_pwait: ::c_long = 346; +pub const SYS_kexec_load: ::c_long = 347; +pub const SYS_utimensat: ::c_long = 348; +pub const SYS_signalfd: ::c_long = 349; +pub const SYS_timerfd_create: ::c_long = 350; +pub const SYS_eventfd: ::c_long = 351; +pub const SYS_fallocate: ::c_long = 352; +pub const SYS_timerfd_settime: ::c_long = 353; +pub const SYS_timerfd_gettime: ::c_long = 354; +pub const SYS_signalfd4: ::c_long = 355; +pub const SYS_eventfd2: ::c_long = 356; +pub const SYS_epoll_create1: ::c_long = 357; +pub const SYS_dup3: ::c_long = 358; +pub const SYS_pipe2: ::c_long = 359; +pub const SYS_inotify_init1: ::c_long = 360; +pub const SYS_preadv: ::c_long = 361; +pub const SYS_pwritev: ::c_long = 362; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 363; +pub const SYS_perf_event_open: ::c_long = 364; +pub const SYS_recvmmsg: ::c_long = 365; +pub const SYS_accept4: ::c_long = 366; +pub const SYS_fanotify_init: ::c_long = 367; +pub const SYS_fanotify_mark: ::c_long = 368; +pub const SYS_prlimit64: ::c_long = 369; +pub const SYS_name_to_handle_at: ::c_long = 370; +pub const SYS_open_by_handle_at: ::c_long = 371; +pub const SYS_clock_adjtime: ::c_long = 372; +pub const SYS_syncfs: ::c_long = 373; +pub const SYS_sendmmsg: ::c_long = 374; +pub const SYS_setns: ::c_long = 375; +pub const SYS_process_vm_readv: ::c_long = 376; +pub const SYS_process_vm_writev: ::c_long = 377; +pub const SYS_kcmp: ::c_long = 378; +pub const SYS_finit_module: ::c_long = 379; +pub const SYS_sched_setattr: ::c_long = 380; +pub const SYS_sched_getattr: ::c_long = 381; +pub const SYS_renameat2: ::c_long = 382; +pub const SYS_seccomp: ::c_long = 383; +pub const SYS_getrandom: ::c_long = 384; +pub const SYS_memfd_create: ::c_long = 385; +pub const SYS_bpf: ::c_long = 386; +pub const SYS_execveat: ::c_long = 387; +pub const SYS_userfaultfd: ::c_long = 388; +pub const SYS_membarrier: ::c_long = 389; +pub const SYS_mlock2: ::c_long = 390; +pub const SYS_copy_file_range: ::c_long = 391; +pub const SYS_preadv2: ::c_long = 392; +pub const SYS_pwritev2: ::c_long = 393; +pub const SYS_pkey_mprotect: ::c_long = 394; +pub const SYS_pkey_alloc: ::c_long = 395; +pub const SYS_pkey_free: ::c_long = 396; diff --git a/libc/src/unix/notbsd/linux/other/b32/mod.rs b/libc/src/unix/notbsd/linux/other/b32/mod.rs new file mode 100644 index 000000000..d078f7537 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b32/mod.rs @@ -0,0 +1,388 @@ +//! 32-bit specific definitions for linux-like values + +use pthread_mutex_t; + +pub type c_long = i32; +pub type c_ulong = u32; +pub type clock_t = i32; +pub type time_t = i32; +pub type suseconds_t = i32; +pub type ino_t = u32; +pub type off_t = i32; +pub type blkcnt_t = i32; +pub type __fsword_t = i32; + +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type rlim_t = c_ulong; +pub type shmatt_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type blksize_t = i32; +pub type nlink_t = u32; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + __pad1: ::c_short, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad2: ::c_short, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused4: ::c_long, + __unused5: ::c_long, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u32; 9] + } + + pub struct sigset_t { + __val: [::c_ulong; 32], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 8], + } +} + +pub const TIOCGSOFTCAR: ::c_ulong = 0x5419; +pub const TIOCSSOFTCAR: ::c_ulong = 0x541A; + +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 6; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; +pub const O_FSYNC: ::c_int = 0x101000; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const MAP_GROWSDOWN: ::c_int = 0x0100; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EBADMSG: ::c_int = 74; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const EHWPOISON: ::c_int = 133; +pub const ERFKILL: ::c_int = 132; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; + +pub const PTRACE_DETACH: ::c_uint = 17; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const SFD_NONBLOCK: ::c_int = 0x0800; + +pub const TIOCEXCL: ::c_ulong = 0x540C; +pub const TIOCNXCL: ::c_ulong = 0x540D; +pub const TIOCSCTTY: ::c_ulong = 0x540E; +pub const TIOCSTI: ::c_ulong = 0x5412; +pub const TIOCMGET: ::c_ulong = 0x5415; +pub const TIOCMBIS: ::c_ulong = 0x5416; +pub const TIOCMBIC: ::c_ulong = 0x5417; +pub const TIOCMSET: ::c_ulong = 0x5418; +pub const TIOCCONS: ::c_ulong = 0x541D; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +align_const! { + #[cfg(target_endian = "little")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; +} + +pub const PTRACE_GETFPREGS: ::c_uint = 14; +pub const PTRACE_SETFPREGS: ::c_uint = 15; +pub const PTRACE_GETREGS: ::c_uint = 12; +pub const PTRACE_SETREGS: ::c_uint = 13; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; +} + +cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use self::x86::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else if #[cfg(target_arch = "powerpc")] { + mod powerpc; + pub use self::powerpc::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/linux/other/b32/powerpc.rs b/libc/src/unix/notbsd/linux/other/b32/powerpc.rs new file mode 100644 index 000000000..0ea903427 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b32/powerpc.rs @@ -0,0 +1,614 @@ +pub type c_char = u8; +pub type wchar_t = i32; + +s! { + pub struct ipc_perm { + __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + __seq: ::uint32_t, + __pad1: ::uint32_t, + __glibc_reserved1: ::uint64_t, + __glibc_reserved2: ::uint64_t, + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad2: ::c_ushort, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + __glibc_reserved1: ::c_uint, + pub shm_atime: ::time_t, + __glibc_reserved2: ::c_uint, + pub shm_dtime: ::time_t, + __glibc_reserved3: ::c_uint, + pub shm_ctime: ::time_t, + __glibc_reserved4: ::c_uint, + pub shm_segsz: ::size_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __glibc_reserved5: ::c_ulong, + __glibc_reserved6: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + __glibc_reserved1: ::c_uint, + pub msg_stime: ::time_t, + __glibc_reserved2: ::c_uint, + pub msg_rtime: ::time_t, + __glibc_reserved3: ::c_uint, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } +} + +pub const O_DIRECT: ::c_int = 0x20000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_LARGEFILE: ::c_int = 0o200000; + +pub const MAP_LOCKED: ::c_int = 0x00080; +pub const MAP_NORESERVE: ::c_int = 0x00040; + +pub const EDEADLOCK: ::c_int = 58; + +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_RCVLOWAT: ::c_int = 16; +pub const SO_SNDLOWAT: ::c_int = 17; +pub const SO_RCVTIMEO: ::c_int = 18; +pub const SO_SNDTIMEO: ::c_int = 19; +pub const SO_PASSCRED: ::c_int = 20; +pub const SO_PEERCRED: ::c_int = 21; + +pub const FIOCLEX: ::c_ulong = 0x20006601; +pub const FIONBIO: ::c_ulong = 0x8004667e; + +pub const MCL_CURRENT: ::c_int = 0x2000; +pub const MCL_FUTURE: ::c_int = 0x4000; + +pub const SIGSTKSZ: ::size_t = 0x4000; +pub const MINSIGSTKSZ: ::size_t = 4096; +pub const CBAUD: ::tcflag_t = 0xff; +pub const TAB1: ::c_int = 0x400; +pub const TAB2: ::c_int = 0x800; +pub const TAB3: ::c_int = 0xc00; +pub const CR1: ::c_int = 0x1000; +pub const CR2: ::c_int = 0x2000; +pub const CR3: ::c_int = 0x3000; +pub const FF1: ::c_int = 0x4000; +pub const BS1: ::c_int = 0x8000; +pub const VT1: ::c_int = 0x10000; +pub const VWERASE: usize = 0xa; +pub const VREPRINT: usize = 0xb; +pub const VSUSP: usize = 0xc; +pub const VSTART: usize = 0xd; +pub const VSTOP: usize = 0xe; +pub const VDISCARD: usize = 0x10; +pub const VTIME: usize = 0x7; +pub const IXON: ::tcflag_t = 0x200; +pub const IXOFF: ::tcflag_t = 0x400; +pub const ONLCR: ::tcflag_t = 0x2; +pub const CSIZE: ::tcflag_t = 0x300; +pub const CS6: ::tcflag_t = 0x100; +pub const CS7: ::tcflag_t = 0x200; +pub const CS8: ::tcflag_t = 0x300; +pub const CSTOPB: ::tcflag_t = 0x400; +pub const CREAD: ::tcflag_t = 0x800; +pub const PARENB: ::tcflag_t = 0x1000; +pub const PARODD: ::tcflag_t = 0x2000; +pub const HUPCL: ::tcflag_t = 0x4000; +pub const CLOCAL: ::tcflag_t = 0x8000; +pub const ECHOKE: ::tcflag_t = 0x1; +pub const ECHOE: ::tcflag_t = 0x2; +pub const ECHOK: ::tcflag_t = 0x4; +pub const ECHONL: ::tcflag_t = 0x10; +pub const ECHOPRT: ::tcflag_t = 0x20; +pub const ECHOCTL: ::tcflag_t = 0x40; +pub const ISIG: ::tcflag_t = 0x80; +pub const ICANON: ::tcflag_t = 0x100; +pub const PENDIN: ::tcflag_t = 0x20000000; +pub const NOFLSH: ::tcflag_t = 0x80000000; +pub const VSWTC: usize = 9; +pub const OLCUC: ::tcflag_t = 0o000004; +pub const NLDLY: ::tcflag_t = 0o001400; +pub const CRDLY: ::tcflag_t = 0o030000; +pub const TABDLY: ::tcflag_t = 0o006000; +pub const BSDLY: ::tcflag_t = 0o100000; +pub const FFDLY: ::tcflag_t = 0o040000; +pub const VTDLY: ::tcflag_t = 0o200000; +pub const XTABS: ::tcflag_t = 0o006000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const CBAUDEX: ::speed_t = 0o000020; +pub const B57600: ::speed_t = 0o0020; +pub const B115200: ::speed_t = 0o0021; +pub const B230400: ::speed_t = 0o0022; +pub const B460800: ::speed_t = 0o0023; +pub const B500000: ::speed_t = 0o0024; +pub const B576000: ::speed_t = 0o0025; +pub const B921600: ::speed_t = 0o0026; +pub const B1000000: ::speed_t = 0o0027; +pub const B1152000: ::speed_t = 0o0030; +pub const B1500000: ::speed_t = 0o0031; +pub const B2000000: ::speed_t = 0o0032; +pub const B2500000: ::speed_t = 0o0033; +pub const B3000000: ::speed_t = 0o0034; +pub const B3500000: ::speed_t = 0o0035; +pub const B4000000: ::speed_t = 0o0036; +pub const BOTHER: ::speed_t = 0o0037; + +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: ::tcflag_t = 0x400; +pub const TOSTOP: ::tcflag_t = 0x400000; +pub const FLUSHO: ::tcflag_t = 0x800000; +pub const EXTPROC: ::tcflag_t = 0x10000000; +pub const TCGETS: ::c_ulong = 0x403c7413; +pub const TCSETS: ::c_ulong = 0x803c7414; +pub const TCSETSW: ::c_ulong = 0x803c7415; +pub const TCSETSF: ::c_ulong = 0x803c7416; +pub const TCGETA: ::c_ulong = 0x40147417; +pub const TCSETA: ::c_ulong = 0x80147418; +pub const TCSETAW: ::c_ulong = 0x80147419; +pub const TCSETAF: ::c_ulong = 0x8014741c; +pub const TCSBRK: ::c_ulong = 0x2000741d; +pub const TCXONC: ::c_ulong = 0x2000741e; +pub const TCFLSH: ::c_ulong = 0x2000741f; +pub const TIOCINQ: ::c_ulong = 0x4004667f; +pub const TIOCGPGRP: ::c_ulong = 0x40047477; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCOUTQ: ::c_ulong = 0x40047473; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const FIONREAD: ::c_ulong = 0x4004667f; + +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_query_module: ::c_long = 166; +pub const SYS_poll: ::c_long = 167; +pub const SYS_nfsservctl: ::c_long = 168; +pub const SYS_setresgid: ::c_long = 169; +pub const SYS_getresgid: ::c_long = 170; +pub const SYS_prctl: ::c_long = 171; +pub const SYS_rt_sigreturn: ::c_long = 172; +pub const SYS_rt_sigaction: ::c_long = 173; +pub const SYS_rt_sigprocmask: ::c_long = 174; +pub const SYS_rt_sigpending: ::c_long = 175; +pub const SYS_rt_sigtimedwait: ::c_long = 176; +pub const SYS_rt_sigqueueinfo: ::c_long = 177; +pub const SYS_rt_sigsuspend: ::c_long = 178; +pub const SYS_pread64: ::c_long = 179; +pub const SYS_pwrite64: ::c_long = 180; +pub const SYS_chown: ::c_long = 181; +pub const SYS_getcwd: ::c_long = 182; +pub const SYS_capget: ::c_long = 183; +pub const SYS_capset: ::c_long = 184; +pub const SYS_sigaltstack: ::c_long = 185; +pub const SYS_sendfile: ::c_long = 186; +pub const SYS_getpmsg: ::c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: ::c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: ::c_long = 189; +pub const SYS_ugetrlimit: ::c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_pciconfig_read: ::c_long = 198; +pub const SYS_pciconfig_write: ::c_long = 199; +pub const SYS_pciconfig_iobase: ::c_long = 200; +pub const SYS_multiplexer: ::c_long = 201; +pub const SYS_getdents64: ::c_long = 202; +pub const SYS_pivot_root: ::c_long = 203; +pub const SYS_fcntl64: ::c_long = 204; +pub const SYS_madvise: ::c_long = 205; +pub const SYS_mincore: ::c_long = 206; +pub const SYS_gettid: ::c_long = 207; +pub const SYS_tkill: ::c_long = 208; +pub const SYS_setxattr: ::c_long = 209; +pub const SYS_lsetxattr: ::c_long = 210; +pub const SYS_fsetxattr: ::c_long = 211; +pub const SYS_getxattr: ::c_long = 212; +pub const SYS_lgetxattr: ::c_long = 213; +pub const SYS_fgetxattr: ::c_long = 214; +pub const SYS_listxattr: ::c_long = 215; +pub const SYS_llistxattr: ::c_long = 216; +pub const SYS_flistxattr: ::c_long = 217; +pub const SYS_removexattr: ::c_long = 218; +pub const SYS_lremovexattr: ::c_long = 219; +pub const SYS_fremovexattr: ::c_long = 220; +pub const SYS_futex: ::c_long = 221; +pub const SYS_sched_setaffinity: ::c_long = 222; +pub const SYS_sched_getaffinity: ::c_long = 223; +pub const SYS_tuxcall: ::c_long = 225; +pub const SYS_sendfile64: ::c_long = 226; +pub const SYS_io_setup: ::c_long = 227; +pub const SYS_io_destroy: ::c_long = 228; +pub const SYS_io_getevents: ::c_long = 229; +pub const SYS_io_submit: ::c_long = 230; +pub const SYS_io_cancel: ::c_long = 231; +pub const SYS_set_tid_address: ::c_long = 232; +pub const SYS_fadvise64: ::c_long = 233; +pub const SYS_exit_group: ::c_long = 234; +pub const SYS_lookup_dcookie: ::c_long = 235; +pub const SYS_epoll_create: ::c_long = 236; +pub const SYS_epoll_ctl: ::c_long = 237; +pub const SYS_epoll_wait: ::c_long = 238; +pub const SYS_remap_file_pages: ::c_long = 239; +pub const SYS_timer_create: ::c_long = 240; +pub const SYS_timer_settime: ::c_long = 241; +pub const SYS_timer_gettime: ::c_long = 242; +pub const SYS_timer_getoverrun: ::c_long = 243; +pub const SYS_timer_delete: ::c_long = 244; +pub const SYS_clock_settime: ::c_long = 245; +pub const SYS_clock_gettime: ::c_long = 246; +pub const SYS_clock_getres: ::c_long = 247; +pub const SYS_clock_nanosleep: ::c_long = 248; +pub const SYS_swapcontext: ::c_long = 249; +pub const SYS_tgkill: ::c_long = 250; +pub const SYS_utimes: ::c_long = 251; +pub const SYS_statfs64: ::c_long = 252; +pub const SYS_fstatfs64: ::c_long = 253; +pub const SYS_fadvise64_64: ::c_long = 254; +pub const SYS_rtas: ::c_long = 255; +pub const SYS_sys_debug_setcontext: ::c_long = 256; +pub const SYS_migrate_pages: ::c_long = 258; +pub const SYS_mbind: ::c_long = 259; +pub const SYS_get_mempolicy: ::c_long = 260; +pub const SYS_set_mempolicy: ::c_long = 261; +pub const SYS_mq_open: ::c_long = 262; +pub const SYS_mq_unlink: ::c_long = 263; +pub const SYS_mq_timedsend: ::c_long = 264; +pub const SYS_mq_timedreceive: ::c_long = 265; +pub const SYS_mq_notify: ::c_long = 266; +pub const SYS_mq_getsetattr: ::c_long = 267; +pub const SYS_kexec_load: ::c_long = 268; +pub const SYS_add_key: ::c_long = 269; +pub const SYS_request_key: ::c_long = 270; +pub const SYS_keyctl: ::c_long = 271; +pub const SYS_waitid: ::c_long = 272; +pub const SYS_ioprio_set: ::c_long = 273; +pub const SYS_ioprio_get: ::c_long = 274; +pub const SYS_inotify_init: ::c_long = 275; +pub const SYS_inotify_add_watch: ::c_long = 276; +pub const SYS_inotify_rm_watch: ::c_long = 277; +pub const SYS_spu_run: ::c_long = 278; +pub const SYS_spu_create: ::c_long = 279; +pub const SYS_pselect6: ::c_long = 280; +pub const SYS_ppoll: ::c_long = 281; +pub const SYS_unshare: ::c_long = 282; +pub const SYS_splice: ::c_long = 283; +pub const SYS_tee: ::c_long = 284; +pub const SYS_vmsplice: ::c_long = 285; +pub const SYS_openat: ::c_long = 286; +pub const SYS_mkdirat: ::c_long = 287; +pub const SYS_mknodat: ::c_long = 288; +pub const SYS_fchownat: ::c_long = 289; +pub const SYS_futimesat: ::c_long = 290; +pub const SYS_fstatat64: ::c_long = 291; +pub const SYS_unlinkat: ::c_long = 292; +pub const SYS_renameat: ::c_long = 293; +pub const SYS_linkat: ::c_long = 294; +pub const SYS_symlinkat: ::c_long = 295; +pub const SYS_readlinkat: ::c_long = 296; +pub const SYS_fchmodat: ::c_long = 297; +pub const SYS_faccessat: ::c_long = 298; +pub const SYS_get_robust_list: ::c_long = 299; +pub const SYS_set_robust_list: ::c_long = 300; +pub const SYS_move_pages: ::c_long = 301; +pub const SYS_getcpu: ::c_long = 302; +pub const SYS_epoll_pwait: ::c_long = 303; +pub const SYS_utimensat: ::c_long = 304; +pub const SYS_signalfd: ::c_long = 305; +pub const SYS_timerfd_create: ::c_long = 306; +pub const SYS_eventfd: ::c_long = 307; +pub const SYS_sync_file_range2: ::c_long = 308; +pub const SYS_fallocate: ::c_long = 309; +pub const SYS_subpage_prot: ::c_long = 310; +pub const SYS_timerfd_settime: ::c_long = 311; +pub const SYS_timerfd_gettime: ::c_long = 312; +pub const SYS_signalfd4: ::c_long = 313; +pub const SYS_eventfd2: ::c_long = 314; +pub const SYS_epoll_create1: ::c_long = 315; +pub const SYS_dup3: ::c_long = 316; +pub const SYS_pipe2: ::c_long = 317; +pub const SYS_inotify_init1: ::c_long = 318; +pub const SYS_perf_event_open: ::c_long = 319; +pub const SYS_preadv: ::c_long = 320; +pub const SYS_pwritev: ::c_long = 321; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 322; +pub const SYS_fanotify_init: ::c_long = 323; +pub const SYS_fanotify_mark: ::c_long = 324; +pub const SYS_prlimit64: ::c_long = 325; +pub const SYS_socket: ::c_long = 326; +pub const SYS_bind: ::c_long = 327; +pub const SYS_connect: ::c_long = 328; +pub const SYS_listen: ::c_long = 329; +pub const SYS_accept: ::c_long = 330; +pub const SYS_getsockname: ::c_long = 331; +pub const SYS_getpeername: ::c_long = 332; +pub const SYS_socketpair: ::c_long = 333; +pub const SYS_send: ::c_long = 334; +pub const SYS_sendto: ::c_long = 335; +pub const SYS_recv: ::c_long = 336; +pub const SYS_recvfrom: ::c_long = 337; +pub const SYS_shutdown: ::c_long = 338; +pub const SYS_setsockopt: ::c_long = 339; +pub const SYS_getsockopt: ::c_long = 340; +pub const SYS_sendmsg: ::c_long = 341; +pub const SYS_recvmsg: ::c_long = 342; +pub const SYS_recvmmsg: ::c_long = 343; +pub const SYS_accept4: ::c_long = 344; +pub const SYS_name_to_handle_at: ::c_long = 345; +pub const SYS_open_by_handle_at: ::c_long = 346; +pub const SYS_clock_adjtime: ::c_long = 347; +pub const SYS_syncfs: ::c_long = 348; +pub const SYS_sendmmsg: ::c_long = 349; +pub const SYS_setns: ::c_long = 350; +pub const SYS_process_vm_readv: ::c_long = 351; +pub const SYS_process_vm_writev: ::c_long = 352; +pub const SYS_finit_module: ::c_long = 353; +pub const SYS_kcmp: ::c_long = 354; +pub const SYS_sched_setattr: ::c_long = 355; +pub const SYS_sched_getattr: ::c_long = 356; +pub const SYS_renameat2: ::c_long = 357; +pub const SYS_seccomp: ::c_long = 358; +pub const SYS_getrandom: ::c_long = 359; +pub const SYS_memfd_create: ::c_long = 360; +pub const SYS_bpf: ::c_long = 361; +pub const SYS_execveat: ::c_long = 362; +pub const SYS_switch_endian: ::c_long = 363; +pub const SYS_userfaultfd: ::c_long = 364; +pub const SYS_membarrier: ::c_long = 365; +pub const SYS_mlock2: ::c_long = 378; +pub const SYS_copy_file_range: ::c_long = 379; +pub const SYS_preadv2: ::c_long = 380; +pub const SYS_pwritev2: ::c_long = 381; +pub const SYS_kexec_file_load: ::c_long = 382; diff --git a/libc/src/unix/notbsd/linux/other/b32/x86.rs b/libc/src/unix/notbsd/linux/other/b32/x86.rs new file mode 100644 index 000000000..e7c3b9a83 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b32/x86.rs @@ -0,0 +1,892 @@ +pub type c_char = i8; +pub type wchar_t = i32; +pub type greg_t = i32; + +s! { + pub struct _libc_fpreg { + pub significand: [u16; 4], + pub exponent: u16, + } + + pub struct _libc_fpstate { + pub cw: ::c_ulong, + pub sw: ::c_ulong, + pub tag: ::c_ulong, + pub ipoff: ::c_ulong, + pub cssel: ::c_ulong, + pub dataoff: ::c_ulong, + pub datasel: ::c_ulong, + pub _st: [_libc_fpreg; 8], + pub status: ::c_ulong, + } + + pub struct user_fpregs_struct { + pub cwd: ::c_long, + pub swd: ::c_long, + pub twd: ::c_long, + pub fip: ::c_long, + pub fcs: ::c_long, + pub foo: ::c_long, + pub fos: ::c_long, + pub st_space: [::c_long; 20], + } + + pub struct user_regs_struct { + pub ebx: ::c_long, + pub ecx: ::c_long, + pub edx: ::c_long, + pub esi: ::c_long, + pub edi: ::c_long, + pub ebp: ::c_long, + pub eax: ::c_long, + pub xds: ::c_long, + pub xes: ::c_long, + pub xfs: ::c_long, + pub xgs: ::c_long, + pub orig_eax: ::c_long, + pub eip: ::c_long, + pub xcs: ::c_long, + pub eflags: ::c_long, + pub esp: ::c_long, + pub xss: ::c_long, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: ::c_int, + pub i387: user_fpregs_struct, + pub u_tsize: ::c_ulong, + pub u_dsize: ::c_ulong, + pub u_ssize: ::c_ulong, + pub start_code: ::c_ulong, + pub start_stack: ::c_ulong, + pub signal: ::c_long, + __reserved: ::c_int, + pub u_ar0: *mut user_regs_struct, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: ::c_ulong, + pub u_comm: [c_char; 32], + pub u_debugreg: [::c_int; 8], + } + + pub struct mcontext_t { + pub gregs: [greg_t; 19], + pub fpregs: *mut _libc_fpstate, + pub oldmask: ::c_ulong, + pub cr2: ::c_ulong, + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_ushort, + __pad1: ::c_ushort, + pub __seq: ::c_ushort, + __pad2: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __pad1: ::c_uint, + __st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad2: ::c_uint, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_ino: ::ino64_t, + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + __f_unused: ::c_int, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + __unused1: ::c_ulong, + pub shm_dtime: ::time_t, + __unused2: ::c_ulong, + pub shm_ctime: ::time_t, + __unused3: ::c_ulong, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + __glibc_reserved1: ::c_ulong, + pub msg_rtime: ::time_t, + __glibc_reserved2: ::c_ulong, + pub msg_ctime: ::time_t, + __glibc_reserved3: ::c_ulong, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +s_no_extra_traits!{ + pub struct user_fpxregs_struct { + pub cwd: ::c_ushort, + pub swd: ::c_ushort, + pub twd: ::c_ushort, + pub fop: ::c_ushort, + pub fip: ::c_long, + pub fcs: ::c_long, + pub foo: ::c_long, + pub fos: ::c_long, + pub mxcsr: ::c_long, + __reserved: ::c_long, + pub st_space: [::c_long; 32], + pub xmm_space: [::c_long; 32], + padding: [::c_long; 56], + } + + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + __private: [u8; 112], + __ssp: [::c_ulong; 4], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for user_fpxregs_struct { + fn eq(&self, other: &user_fpxregs_struct) -> bool { + self.cwd == other.cwd + && self.swd == other.swd + && self.twd == other.twd + && self.fop == other.fop + && self.fip == other.fip + && self.fcs == other.fcs + && self.foo == other.foo + && self.fos == other.fos + && self.mxcsr == other.mxcsr + // Ignore __reserved field + && self.st_space == other.st_space + && self.xmm_space == other.xmm_space + // Ignore padding field + } + } + + impl Eq for user_fpxregs_struct {} + + impl ::fmt::Debug for user_fpxregs_struct { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("user_fpxregs_struct") + .field("cwd", &self.cwd) + .field("swd", &self.swd) + .field("twd", &self.twd) + .field("fop", &self.fop) + .field("fip", &self.fip) + .field("fcs", &self.fcs) + .field("foo", &self.foo) + .field("fos", &self.fos) + .field("mxcsr", &self.mxcsr) + // Ignore __reserved field + .field("st_space", &self.st_space) + .field("xmm_space", &self.xmm_space) + // Ignore padding field + .finish() + } + } + + impl ::hash::Hash for user_fpxregs_struct { + fn hash(&self, state: &mut H) { + self.cwd.hash(state); + self.swd.hash(state); + self.twd.hash(state); + self.fop.hash(state); + self.fip.hash(state); + self.fcs.hash(state); + self.foo.hash(state); + self.fos.hash(state); + self.mxcsr.hash(state); + // Ignore __reserved field + self.st_space.hash(state); + self.xmm_space.hash(state); + // Ignore padding field + } + } + + impl PartialEq for ucontext_t { + fn eq(&self, other: &ucontext_t) -> bool { + self.uc_flags == other.uc_flags + && self.uc_link == other.uc_link + && self.uc_stack == other.uc_stack + && self.uc_mcontext == other.uc_mcontext + && self.uc_sigmask == other.uc_sigmask + // Ignore __private field + } + } + + impl Eq for ucontext_t {} + + impl ::fmt::Debug for ucontext_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ucontext_t") + .field("uc_flags", &self.uc_flags) + .field("uc_link", &self.uc_link) + .field("uc_stack", &self.uc_stack) + .field("uc_mcontext", &self.uc_mcontext) + .field("uc_sigmask", &self.uc_sigmask) + // Ignore __private field + .finish() + } + } + + impl ::hash::Hash for ucontext_t { + fn hash(&self, state: &mut H) { + self.uc_flags.hash(state); + self.uc_link.hash(state); + self.uc_stack.hash(state); + self.uc_mcontext.hash(state); + self.uc_sigmask.hash(state); + // Ignore __private field + } + } + } +} + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const O_LARGEFILE: ::c_int = 0o0100000; + +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_32BIT: ::c_int = 0x0040; + +pub const EDEADLOCK: ::c_int = 35; + +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; + +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FIONBIO: ::c_ulong = 0x5421; + +pub const PTRACE_GETFPXREGS: ::c_uint = 18; +pub const PTRACE_SETFPXREGS: ::c_uint = 19; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCSETSW: ::c_ulong = 0x5403; +pub const TCSETSF: ::c_ulong = 0x5404; +pub const TCGETA: ::c_ulong = 0x5405; +pub const TCSETA: ::c_ulong = 0x5406; +pub const TCSETAW: ::c_ulong = 0x5407; +pub const TCSETAF: ::c_ulong = 0x5408; +pub const TCSBRK: ::c_ulong = 0x5409; +pub const TCXONC: ::c_ulong = 0x540A; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCINQ: ::c_ulong = 0x541B; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCOUTQ: ::c_ulong = 0x5411; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; +pub const FIONREAD: ::c_ulong = 0x541B; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86old: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_vm86: ::c_long = 166; +pub const SYS_query_module: ::c_long = 167; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_setresgid: ::c_long = 170; +pub const SYS_getresgid: ::c_long = 171; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_chown: ::c_long = 182; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_getpmsg: ::c_long = 188; +pub const SYS_putpmsg: ::c_long = 189; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_ugetrlimit: ::c_long = 191; +pub const SYS_mmap2: ::c_long = 192; +pub const SYS_truncate64: ::c_long = 193; +pub const SYS_ftruncate64: ::c_long = 194; +pub const SYS_stat64: ::c_long = 195; +pub const SYS_lstat64: ::c_long = 196; +pub const SYS_fstat64: ::c_long = 197; +pub const SYS_lchown32: ::c_long = 198; +pub const SYS_getuid32: ::c_long = 199; +pub const SYS_getgid32: ::c_long = 200; +pub const SYS_geteuid32: ::c_long = 201; +pub const SYS_getegid32: ::c_long = 202; +pub const SYS_setreuid32: ::c_long = 203; +pub const SYS_setregid32: ::c_long = 204; +pub const SYS_getgroups32: ::c_long = 205; +pub const SYS_setgroups32: ::c_long = 206; +pub const SYS_fchown32: ::c_long = 207; +pub const SYS_setresuid32: ::c_long = 208; +pub const SYS_getresuid32: ::c_long = 209; +pub const SYS_setresgid32: ::c_long = 210; +pub const SYS_getresgid32: ::c_long = 211; +pub const SYS_chown32: ::c_long = 212; +pub const SYS_setuid32: ::c_long = 213; +pub const SYS_setgid32: ::c_long = 214; +pub const SYS_setfsuid32: ::c_long = 215; +pub const SYS_setfsgid32: ::c_long = 216; +pub const SYS_pivot_root: ::c_long = 217; +pub const SYS_mincore: ::c_long = 218; +pub const SYS_madvise: ::c_long = 219; +pub const SYS_getdents64: ::c_long = 220; +pub const SYS_fcntl64: ::c_long = 221; +pub const SYS_gettid: ::c_long = 224; +pub const SYS_readahead: ::c_long = 225; +pub const SYS_setxattr: ::c_long = 226; +pub const SYS_lsetxattr: ::c_long = 227; +pub const SYS_fsetxattr: ::c_long = 228; +pub const SYS_getxattr: ::c_long = 229; +pub const SYS_lgetxattr: ::c_long = 230; +pub const SYS_fgetxattr: ::c_long = 231; +pub const SYS_listxattr: ::c_long = 232; +pub const SYS_llistxattr: ::c_long = 233; +pub const SYS_flistxattr: ::c_long = 234; +pub const SYS_removexattr: ::c_long = 235; +pub const SYS_lremovexattr: ::c_long = 236; +pub const SYS_fremovexattr: ::c_long = 237; +pub const SYS_tkill: ::c_long = 238; +pub const SYS_sendfile64: ::c_long = 239; +pub const SYS_futex: ::c_long = 240; +pub const SYS_sched_setaffinity: ::c_long = 241; +pub const SYS_sched_getaffinity: ::c_long = 242; +pub const SYS_set_thread_area: ::c_long = 243; +pub const SYS_get_thread_area: ::c_long = 244; +pub const SYS_io_setup: ::c_long = 245; +pub const SYS_io_destroy: ::c_long = 246; +pub const SYS_io_getevents: ::c_long = 247; +pub const SYS_io_submit: ::c_long = 248; +pub const SYS_io_cancel: ::c_long = 249; +pub const SYS_fadvise64: ::c_long = 250; +pub const SYS_exit_group: ::c_long = 252; +pub const SYS_lookup_dcookie: ::c_long = 253; +pub const SYS_epoll_create: ::c_long = 254; +pub const SYS_epoll_ctl: ::c_long = 255; +pub const SYS_epoll_wait: ::c_long = 256; +pub const SYS_remap_file_pages: ::c_long = 257; +pub const SYS_set_tid_address: ::c_long = 258; +pub const SYS_timer_create: ::c_long = 259; +pub const SYS_timer_settime: ::c_long = 260; +pub const SYS_timer_gettime: ::c_long = 261; +pub const SYS_timer_getoverrun: ::c_long = 262; +pub const SYS_timer_delete: ::c_long = 263; +pub const SYS_clock_settime: ::c_long = 264; +pub const SYS_clock_gettime: ::c_long = 265; +pub const SYS_clock_getres: ::c_long = 266; +pub const SYS_clock_nanosleep: ::c_long = 267; +pub const SYS_statfs64: ::c_long = 268; +pub const SYS_fstatfs64: ::c_long = 269; +pub const SYS_tgkill: ::c_long = 270; +pub const SYS_utimes: ::c_long = 271; +pub const SYS_fadvise64_64: ::c_long = 272; +pub const SYS_vserver: ::c_long = 273; +pub const SYS_mbind: ::c_long = 274; +pub const SYS_get_mempolicy: ::c_long = 275; +pub const SYS_set_mempolicy: ::c_long = 276; +pub const SYS_mq_open: ::c_long = 277; +pub const SYS_mq_unlink: ::c_long = 278; +pub const SYS_mq_timedsend: ::c_long = 279; +pub const SYS_mq_timedreceive: ::c_long = 280; +pub const SYS_mq_notify: ::c_long = 281; +pub const SYS_mq_getsetattr: ::c_long = 282; +pub const SYS_kexec_load: ::c_long = 283; +pub const SYS_waitid: ::c_long = 284; +pub const SYS_add_key: ::c_long = 286; +pub const SYS_request_key: ::c_long = 287; +pub const SYS_keyctl: ::c_long = 288; +pub const SYS_ioprio_set: ::c_long = 289; +pub const SYS_ioprio_get: ::c_long = 290; +pub const SYS_inotify_init: ::c_long = 291; +pub const SYS_inotify_add_watch: ::c_long = 292; +pub const SYS_inotify_rm_watch: ::c_long = 293; +pub const SYS_migrate_pages: ::c_long = 294; +pub const SYS_openat: ::c_long = 295; +pub const SYS_mkdirat: ::c_long = 296; +pub const SYS_mknodat: ::c_long = 297; +pub const SYS_fchownat: ::c_long = 298; +pub const SYS_futimesat: ::c_long = 299; +pub const SYS_fstatat64: ::c_long = 300; +pub const SYS_unlinkat: ::c_long = 301; +pub const SYS_renameat: ::c_long = 302; +pub const SYS_linkat: ::c_long = 303; +pub const SYS_symlinkat: ::c_long = 304; +pub const SYS_readlinkat: ::c_long = 305; +pub const SYS_fchmodat: ::c_long = 306; +pub const SYS_faccessat: ::c_long = 307; +pub const SYS_pselect6: ::c_long = 308; +pub const SYS_ppoll: ::c_long = 309; +pub const SYS_unshare: ::c_long = 310; +pub const SYS_set_robust_list: ::c_long = 311; +pub const SYS_get_robust_list: ::c_long = 312; +pub const SYS_splice: ::c_long = 313; +pub const SYS_sync_file_range: ::c_long = 314; +pub const SYS_tee: ::c_long = 315; +pub const SYS_vmsplice: ::c_long = 316; +pub const SYS_move_pages: ::c_long = 317; +pub const SYS_getcpu: ::c_long = 318; +pub const SYS_epoll_pwait: ::c_long = 319; +pub const SYS_utimensat: ::c_long = 320; +pub const SYS_signalfd: ::c_long = 321; +pub const SYS_timerfd_create: ::c_long = 322; +pub const SYS_eventfd: ::c_long = 323; +pub const SYS_fallocate: ::c_long = 324; +pub const SYS_timerfd_settime: ::c_long = 325; +pub const SYS_timerfd_gettime: ::c_long = 326; +pub const SYS_signalfd4: ::c_long = 327; +pub const SYS_eventfd2: ::c_long = 328; +pub const SYS_epoll_create1: ::c_long = 329; +pub const SYS_dup3: ::c_long = 330; +pub const SYS_pipe2: ::c_long = 331; +pub const SYS_inotify_init1: ::c_long = 332; +pub const SYS_preadv: ::c_long = 333; +pub const SYS_pwritev: ::c_long = 334; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 335; +pub const SYS_perf_event_open: ::c_long = 336; +pub const SYS_recvmmsg: ::c_long = 337; +pub const SYS_fanotify_init: ::c_long = 338; +pub const SYS_fanotify_mark: ::c_long = 339; +pub const SYS_prlimit64: ::c_long = 340; +pub const SYS_name_to_handle_at: ::c_long = 341; +pub const SYS_open_by_handle_at: ::c_long = 342; +pub const SYS_clock_adjtime: ::c_long = 343; +pub const SYS_syncfs: ::c_long = 344; +pub const SYS_sendmmsg: ::c_long = 345; +pub const SYS_setns: ::c_long = 346; +pub const SYS_process_vm_readv: ::c_long = 347; +pub const SYS_process_vm_writev: ::c_long = 348; +pub const SYS_kcmp: ::c_long = 349; +pub const SYS_finit_module: ::c_long = 350; +pub const SYS_sched_setattr: ::c_long = 351; +pub const SYS_sched_getattr: ::c_long = 352; +pub const SYS_renameat2: ::c_long = 353; +pub const SYS_seccomp: ::c_long = 354; +pub const SYS_getrandom: ::c_long = 355; +pub const SYS_memfd_create: ::c_long = 356; +pub const SYS_bpf: ::c_long = 357; +pub const SYS_execveat: ::c_long = 358; +pub const SYS_socket: ::c_long = 359; +pub const SYS_socketpair: ::c_long = 360; +pub const SYS_bind: ::c_long = 361; +pub const SYS_connect: ::c_long = 362; +pub const SYS_listen: ::c_long = 363; +pub const SYS_accept4: ::c_long = 364; +pub const SYS_getsockopt: ::c_long = 365; +pub const SYS_setsockopt: ::c_long = 366; +pub const SYS_getsockname: ::c_long = 367; +pub const SYS_getpeername: ::c_long = 368; +pub const SYS_sendto: ::c_long = 369; +pub const SYS_sendmsg: ::c_long = 370; +pub const SYS_recvfrom: ::c_long = 371; +pub const SYS_recvmsg: ::c_long = 372; +pub const SYS_shutdown: ::c_long = 373; +pub const SYS_userfaultfd: ::c_long = 374; +pub const SYS_membarrier: ::c_long = 375; +pub const SYS_mlock2: ::c_long = 376; +pub const SYS_copy_file_range: ::c_long = 377; +pub const SYS_preadv2: ::c_long = 378; +pub const SYS_pwritev2: ::c_long = 379; +pub const SYS_pkey_mprotect: ::c_long = 380; +pub const SYS_pkey_alloc: ::c_long = 381; +pub const SYS_pkey_free: ::c_long = 382; + +// offsets in user_regs_structs, from sys/reg.h +pub const EBX: ::c_int = 0; +pub const ECX: ::c_int = 1; +pub const EDX: ::c_int = 2; +pub const ESI: ::c_int = 3; +pub const EDI: ::c_int = 4; +pub const EBP: ::c_int = 5; +pub const EAX: ::c_int = 6; +pub const DS: ::c_int = 7; +pub const ES: ::c_int = 8; +pub const FS: ::c_int = 9; +pub const GS: ::c_int = 10; +pub const ORIG_EAX: ::c_int = 11; +pub const EIP: ::c_int = 12; +pub const CS: ::c_int = 13; +pub const EFL: ::c_int = 14; +pub const UESP: ::c_int = 15; +pub const SS: ::c_int = 16; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_GS: ::c_int = 0; +pub const REG_FS: ::c_int = 1; +pub const REG_ES: ::c_int = 2; +pub const REG_DS: ::c_int = 3; +pub const REG_EDI: ::c_int = 4; +pub const REG_ESI: ::c_int = 5; +pub const REG_EBP: ::c_int = 6; +pub const REG_ESP: ::c_int = 7; +pub const REG_EBX: ::c_int = 8; +pub const REG_EDX: ::c_int = 9; +pub const REG_ECX: ::c_int = 10; +pub const REG_EAX: ::c_int = 11; +pub const REG_TRAPNO: ::c_int = 12; +pub const REG_ERR: ::c_int = 13; +pub const REG_EIP: ::c_int = 14; +pub const REG_CS: ::c_int = 15; +pub const REG_EFL: ::c_int = 16; +pub const REG_UESP: ::c_int = 17; +pub const REG_SS: ::c_int = 18; + +extern { + pub fn getcontext(ucp: *mut ucontext_t) -> ::c_int; + pub fn setcontext(ucp: *const ucontext_t) -> ::c_int; + pub fn makecontext(ucp: *mut ucontext_t, + func: extern fn (), + argc: ::c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, + ucp: *const ucontext_t) -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/b64/aarch64.rs b/libc/src/unix/notbsd/linux/other/b64/aarch64.rs new file mode 100644 index 000000000..3bd2e02ee --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/aarch64.rs @@ -0,0 +1,830 @@ +//! AArch64-specific definitions for 64-bit linux-like values + +use pthread_mutex_t; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = u8; +pub type wchar_t = u32; +pub type nlink_t = u32; +pub type blksize_t = i32; +pub type suseconds_t = i64; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad1: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + __pad2: ::c_int, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_int; 2], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad1: ::dev_t, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + __pad2: ::c_int, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_int; 2], + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u64; 8] + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_uint, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +pub const TIOCGSOFTCAR: ::c_ulong = 0x5419; +pub const TIOCSSOFTCAR: ::c_ulong = 0x541A; + +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 6; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; +pub const O_FSYNC: ::c_int = 0x101000; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const MAP_GROWSDOWN: ::c_int = 0x0100; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EBADMSG: ::c_int = 74; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const EHWPOISON: ::c_int = 133; +pub const ERFKILL: ::c_int = 132; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_SECURITY_AUTHENTICATION: ::c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: ::c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: ::c_int = 24; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_ATTACH_FILTER: ::c_int = 26; +pub const SO_DETACH_FILTER: ::c_int = 27; +pub const SO_GET_FILTER: ::c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: ::c_int = 28; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_PEERSEC: ::c_int = 31; +pub const SO_PASSSEC: ::c_int = 34; +pub const SO_TIMESTAMPNS: ::c_int = 35; +pub const SCM_TIMESTAMPNS: ::c_int = SO_TIMESTAMPNS; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_WIFI_STATUS: ::c_int = 41; +pub const SCM_WIFI_STATUS: ::c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_NOFCS: ::c_int = 43; +pub const SO_LOCK_FILTER: ::c_int = 44; +pub const SO_SELECT_ERR_QUEUE: ::c_int = 45; +pub const SO_BUSY_POLL: ::c_int = 46; +pub const SO_MAX_PACING_RATE: ::c_int = 47; +pub const SO_BPF_EXTENSIONS: ::c_int = 48; +pub const SO_INCOMING_CPU: ::c_int = 49; +pub const SO_ATTACH_BPF: ::c_int = 50; +pub const SO_DETACH_BPF: ::c_int = SO_DETACH_FILTER; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; + +pub const PTRACE_DETACH: ::c_uint = 17; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const SFD_NONBLOCK: ::c_int = 0x0800; + +pub const TIOCEXCL: ::c_ulong = 0x540C; +pub const TIOCNXCL: ::c_ulong = 0x540D; +pub const TIOCSCTTY: ::c_ulong = 0x540E; +pub const TIOCSTI: ::c_ulong = 0x5412; +pub const TIOCMGET: ::c_ulong = 0x5415; +pub const TIOCMBIS: ::c_ulong = 0x5416; +pub const TIOCMBIC: ::c_ulong = 0x5417; +pub const TIOCMSET: ::c_ulong = 0x5418; +pub const TIOCCONS: ::c_ulong = 0x541D; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 48; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 8; + +align_const! { + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + ], + }; +} + +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; + +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; + +pub const EDEADLOCK: ::c_int = 35; + +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FIONBIO: ::c_ulong = 0x5421; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 16384; +pub const MINSIGSTKSZ: ::size_t = 5120; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCSETSW: ::c_ulong = 0x5403; +pub const TCSETSF: ::c_ulong = 0x5404; +pub const TCGETA: ::c_ulong = 0x5405; +pub const TCSETA: ::c_ulong = 0x5406; +pub const TCSETAW: ::c_ulong = 0x5407; +pub const TCSETAF: ::c_ulong = 0x5408; +pub const TCSBRK: ::c_ulong = 0x5409; +pub const TCXONC: ::c_ulong = 0x540A; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCINQ: ::c_ulong = 0x541B; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCOUTQ: ::c_ulong = 0x5411; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; +pub const FIONREAD: ::c_ulong = 0x541B; + +// Syscall table +pub const SYS_io_setup: ::c_long = 0; +pub const SYS_io_destroy: ::c_long = 1; +pub const SYS_io_submit: ::c_long = 2; +pub const SYS_io_cancel: ::c_long = 3; +pub const SYS_io_getevents: ::c_long = 4; +pub const SYS_setxattr: ::c_long = 5; +pub const SYS_lsetxattr: ::c_long = 6; +pub const SYS_fsetxattr: ::c_long = 7; +pub const SYS_getxattr: ::c_long = 8; +pub const SYS_lgetxattr: ::c_long = 9; +pub const SYS_fgetxattr: ::c_long = 10; +pub const SYS_listxattr: ::c_long = 11; +pub const SYS_llistxattr: ::c_long = 12; +pub const SYS_flistxattr: ::c_long = 13; +pub const SYS_removexattr: ::c_long = 14; +pub const SYS_lremovexattr: ::c_long = 15; +pub const SYS_fremovexattr: ::c_long = 16; +pub const SYS_getcwd: ::c_long = 17; +pub const SYS_lookup_dcookie: ::c_long = 18; +pub const SYS_eventfd2: ::c_long = 19; +pub const SYS_epoll_create1: ::c_long = 20; +pub const SYS_epoll_ctl: ::c_long = 21; +pub const SYS_epoll_pwait: ::c_long = 22; +pub const SYS_dup: ::c_long = 23; +pub const SYS_dup3: ::c_long = 24; +pub const SYS_fcntl: ::c_long = 25; +pub const SYS_inotify_init1: ::c_long = 26; +pub const SYS_inotify_add_watch: ::c_long = 27; +pub const SYS_inotify_rm_watch: ::c_long = 28; +pub const SYS_ioctl: ::c_long = 29; +pub const SYS_ioprio_set: ::c_long = 30; +pub const SYS_ioprio_get: ::c_long = 31; +pub const SYS_flock: ::c_long = 32; +pub const SYS_mknodat: ::c_long = 33; +pub const SYS_mkdirat: ::c_long = 34; +pub const SYS_unlinkat: ::c_long = 35; +pub const SYS_symlinkat: ::c_long = 36; +pub const SYS_linkat: ::c_long = 37; +pub const SYS_renameat: ::c_long = 38; +pub const SYS_umount2: ::c_long = 39; +pub const SYS_mount: ::c_long = 40; +pub const SYS_pivot_root: ::c_long = 41; +pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_fallocate: ::c_long = 47; +pub const SYS_faccessat: ::c_long = 48; +pub const SYS_chdir: ::c_long = 49; +pub const SYS_fchdir: ::c_long = 50; +pub const SYS_chroot: ::c_long = 51; +pub const SYS_fchmod: ::c_long = 52; +pub const SYS_fchmodat: ::c_long = 53; +pub const SYS_fchownat: ::c_long = 54; +pub const SYS_fchown: ::c_long = 55; +pub const SYS_openat: ::c_long = 56; +pub const SYS_close: ::c_long = 57; +pub const SYS_vhangup: ::c_long = 58; +pub const SYS_pipe2: ::c_long = 59; +pub const SYS_quotactl: ::c_long = 60; +pub const SYS_getdents64: ::c_long = 61; +pub const SYS_lseek: ::c_long = 62; +pub const SYS_read: ::c_long = 63; +pub const SYS_write: ::c_long = 64; +pub const SYS_readv: ::c_long = 65; +pub const SYS_writev: ::c_long = 66; +pub const SYS_pread64: ::c_long = 67; +pub const SYS_pwrite64: ::c_long = 68; +pub const SYS_preadv: ::c_long = 69; +pub const SYS_pwritev: ::c_long = 70; +pub const SYS_pselect6: ::c_long = 72; +pub const SYS_ppoll: ::c_long = 73; +pub const SYS_signalfd4: ::c_long = 74; +pub const SYS_vmsplice: ::c_long = 75; +pub const SYS_splice: ::c_long = 76; +pub const SYS_tee: ::c_long = 77; +pub const SYS_readlinkat: ::c_long = 78; +pub const SYS_newfstatat: ::c_long = 79; +pub const SYS_fstat: ::c_long = 80; +pub const SYS_sync: ::c_long = 81; +pub const SYS_fsync: ::c_long = 82; +pub const SYS_fdatasync: ::c_long = 83; +pub const SYS_sync_file_range: ::c_long = 84; +pub const SYS_timerfd_create: ::c_long = 85; +pub const SYS_timerfd_settime: ::c_long = 86; +pub const SYS_timerfd_gettime: ::c_long = 87; +pub const SYS_utimensat: ::c_long = 88; +pub const SYS_acct: ::c_long = 89; +pub const SYS_capget: ::c_long = 90; +pub const SYS_capset: ::c_long = 91; +pub const SYS_personality: ::c_long = 92; +pub const SYS_exit: ::c_long = 93; +pub const SYS_exit_group: ::c_long = 94; +pub const SYS_waitid: ::c_long = 95; +pub const SYS_set_tid_address: ::c_long = 96; +pub const SYS_unshare: ::c_long = 97; +pub const SYS_futex: ::c_long = 98; +pub const SYS_set_robust_list: ::c_long = 99; +pub const SYS_get_robust_list: ::c_long = 100; +pub const SYS_nanosleep: ::c_long = 101; +pub const SYS_getitimer: ::c_long = 102; +pub const SYS_setitimer: ::c_long = 103; +pub const SYS_kexec_load: ::c_long = 104; +pub const SYS_init_module: ::c_long = 105; +pub const SYS_delete_module: ::c_long = 106; +pub const SYS_timer_create: ::c_long = 107; +pub const SYS_timer_gettime: ::c_long = 108; +pub const SYS_timer_getoverrun: ::c_long = 109; +pub const SYS_timer_settime: ::c_long = 110; +pub const SYS_timer_delete: ::c_long = 111; +pub const SYS_clock_settime: ::c_long = 112; +pub const SYS_clock_gettime: ::c_long = 113; +pub const SYS_clock_getres: ::c_long = 114; +pub const SYS_clock_nanosleep: ::c_long = 115; +pub const SYS_syslog: ::c_long = 116; +pub const SYS_ptrace: ::c_long = 117; +pub const SYS_sched_setparam: ::c_long = 118; +pub const SYS_sched_setscheduler: ::c_long = 119; +pub const SYS_sched_getscheduler: ::c_long = 120; +pub const SYS_sched_getparam: ::c_long = 121; +pub const SYS_sched_setaffinity: ::c_long = 122; +pub const SYS_sched_getaffinity: ::c_long = 123; +pub const SYS_sched_yield: ::c_long = 124; +pub const SYS_sched_get_priority_max: ::c_long = 125; +pub const SYS_sched_get_priority_min: ::c_long = 126; +pub const SYS_sched_rr_get_interval: ::c_long = 127; +pub const SYS_restart_syscall: ::c_long = 128; +pub const SYS_kill: ::c_long = 129; +pub const SYS_tkill: ::c_long = 130; +pub const SYS_tgkill: ::c_long = 131; +pub const SYS_sigaltstack: ::c_long = 132; +pub const SYS_rt_sigsuspend: ::c_long = 133; +pub const SYS_rt_sigaction: ::c_long = 134; +pub const SYS_rt_sigprocmask: ::c_long = 135; +pub const SYS_rt_sigpending: ::c_long = 136; +pub const SYS_rt_sigtimedwait: ::c_long = 137; +pub const SYS_rt_sigqueueinfo: ::c_long = 138; +pub const SYS_rt_sigreturn: ::c_long = 139; +pub const SYS_setpriority: ::c_long = 140; +pub const SYS_getpriority: ::c_long = 141; +pub const SYS_reboot: ::c_long = 142; +pub const SYS_setregid: ::c_long = 143; +pub const SYS_setgid: ::c_long = 144; +pub const SYS_setreuid: ::c_long = 145; +pub const SYS_setuid: ::c_long = 146; +pub const SYS_setresuid: ::c_long = 147; +pub const SYS_getresuid: ::c_long = 148; +pub const SYS_setresgid: ::c_long = 149; +pub const SYS_getresgid: ::c_long = 150; +pub const SYS_setfsuid: ::c_long = 151; +pub const SYS_setfsgid: ::c_long = 152; +pub const SYS_times: ::c_long = 153; +pub const SYS_setpgid: ::c_long = 154; +pub const SYS_getpgid: ::c_long = 155; +pub const SYS_getsid: ::c_long = 156; +pub const SYS_setsid: ::c_long = 157; +pub const SYS_getgroups: ::c_long = 158; +pub const SYS_setgroups: ::c_long = 159; +pub const SYS_uname: ::c_long = 160; +pub const SYS_sethostname: ::c_long = 161; +pub const SYS_setdomainname: ::c_long = 162; +pub const SYS_getrlimit: ::c_long = 163; +pub const SYS_setrlimit: ::c_long = 164; +pub const SYS_getrusage: ::c_long = 165; +pub const SYS_umask: ::c_long = 166; +pub const SYS_prctl: ::c_long = 167; +pub const SYS_getcpu: ::c_long = 168; +pub const SYS_gettimeofday: ::c_long = 169; +pub const SYS_settimeofday: ::c_long = 170; +pub const SYS_adjtimex: ::c_long = 171; +pub const SYS_getpid: ::c_long = 172; +pub const SYS_getppid: ::c_long = 173; +pub const SYS_getuid: ::c_long = 174; +pub const SYS_geteuid: ::c_long = 175; +pub const SYS_getgid: ::c_long = 176; +pub const SYS_getegid: ::c_long = 177; +pub const SYS_gettid: ::c_long = 178; +pub const SYS_sysinfo: ::c_long = 179; +pub const SYS_mq_open: ::c_long = 180; +pub const SYS_mq_unlink: ::c_long = 181; +pub const SYS_mq_timedsend: ::c_long = 182; +pub const SYS_mq_timedreceive: ::c_long = 183; +pub const SYS_mq_notify: ::c_long = 184; +pub const SYS_mq_getsetattr: ::c_long = 185; +pub const SYS_msgget: ::c_long = 186; +pub const SYS_msgctl: ::c_long = 187; +pub const SYS_msgrcv: ::c_long = 188; +pub const SYS_msgsnd: ::c_long = 189; +pub const SYS_semget: ::c_long = 190; +pub const SYS_semctl: ::c_long = 191; +pub const SYS_semtimedop: ::c_long = 192; +pub const SYS_semop: ::c_long = 193; +pub const SYS_shmget: ::c_long = 194; +pub const SYS_shmctl: ::c_long = 195; +pub const SYS_shmat: ::c_long = 196; +pub const SYS_shmdt: ::c_long = 197; +pub const SYS_socket: ::c_long = 198; +pub const SYS_socketpair: ::c_long = 199; +pub const SYS_bind: ::c_long = 200; +pub const SYS_listen: ::c_long = 201; +pub const SYS_accept: ::c_long = 202; +pub const SYS_connect: ::c_long = 203; +pub const SYS_getsockname: ::c_long = 204; +pub const SYS_getpeername: ::c_long = 205; +pub const SYS_sendto: ::c_long = 206; +pub const SYS_recvfrom: ::c_long = 207; +pub const SYS_setsockopt: ::c_long = 208; +pub const SYS_getsockopt: ::c_long = 209; +pub const SYS_shutdown: ::c_long = 210; +pub const SYS_sendmsg: ::c_long = 211; +pub const SYS_recvmsg: ::c_long = 212; +pub const SYS_readahead: ::c_long = 213; +pub const SYS_brk: ::c_long = 214; +pub const SYS_munmap: ::c_long = 215; +pub const SYS_mremap: ::c_long = 216; +pub const SYS_add_key: ::c_long = 217; +pub const SYS_request_key: ::c_long = 218; +pub const SYS_keyctl: ::c_long = 219; +pub const SYS_clone: ::c_long = 220; +pub const SYS_execve: ::c_long = 221; +pub const SYS_mmap: ::c_long = 222; +pub const SYS_swapon: ::c_long = 224; +pub const SYS_swapoff: ::c_long = 225; +pub const SYS_mprotect: ::c_long = 226; +pub const SYS_msync: ::c_long = 227; +pub const SYS_mlock: ::c_long = 228; +pub const SYS_munlock: ::c_long = 229; +pub const SYS_mlockall: ::c_long = 230; +pub const SYS_munlockall: ::c_long = 231; +pub const SYS_mincore: ::c_long = 232; +pub const SYS_madvise: ::c_long = 233; +pub const SYS_remap_file_pages: ::c_long = 234; +pub const SYS_mbind: ::c_long = 235; +pub const SYS_get_mempolicy: ::c_long = 236; +pub const SYS_set_mempolicy: ::c_long = 237; +pub const SYS_migrate_pages: ::c_long = 238; +pub const SYS_move_pages: ::c_long = 239; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 240; +pub const SYS_perf_event_open: ::c_long = 241; +pub const SYS_accept4: ::c_long = 242; +pub const SYS_recvmmsg: ::c_long = 243; +pub const SYS_wait4: ::c_long = 260; +pub const SYS_prlimit64: ::c_long = 261; +pub const SYS_fanotify_init: ::c_long = 262; +pub const SYS_fanotify_mark: ::c_long = 263; +pub const SYS_name_to_handle_at: ::c_long = 264; +pub const SYS_open_by_handle_at: ::c_long = 265; +pub const SYS_clock_adjtime: ::c_long = 266; +pub const SYS_syncfs: ::c_long = 267; +pub const SYS_setns: ::c_long = 268; +pub const SYS_sendmmsg: ::c_long = 269; +pub const SYS_process_vm_readv: ::c_long = 270; +pub const SYS_process_vm_writev: ::c_long = 271; +pub const SYS_kcmp: ::c_long = 272; +pub const SYS_finit_module: ::c_long = 273; +pub const SYS_sched_setattr: ::c_long = 274; +pub const SYS_sched_getattr: ::c_long = 275; +pub const SYS_renameat2: ::c_long = 276; +pub const SYS_seccomp: ::c_long = 277; +pub const SYS_getrandom: ::c_long = 278; +pub const SYS_memfd_create: ::c_long = 279; +pub const SYS_bpf: ::c_long = 280; +pub const SYS_execveat: ::c_long = 281; +pub const SYS_userfaultfd: ::c_long = 282; +pub const SYS_membarrier: ::c_long = 283; +pub const SYS_mlock2: ::c_long = 284; +pub const SYS_copy_file_range: ::c_long = 285; +pub const SYS_preadv2: ::c_long = 286; +pub const SYS_pwritev2: ::c_long = 287; +pub const SYS_pkey_mprotect: ::c_long = 288; +pub const SYS_pkey_alloc: ::c_long = 289; +pub const SYS_pkey_free: ::c_long = 290; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/b64/mod.rs b/libc/src/unix/notbsd/linux/other/b64/mod.rs new file mode 100644 index 000000000..7fcf8ba76 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/mod.rs @@ -0,0 +1,85 @@ +//! 64-bit specific definitions for linux-like values + +pub type clock_t = i64; +pub type time_t = i64; +pub type ino_t = u64; +pub type off_t = i64; +pub type blkcnt_t = i64; +pub type __fsword_t = i64; +pub type shmatt_t = u64; +pub type msgqnum_t = u64; +pub type msglen_t = u64; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type rlim_t = u64; + +s! { + pub struct sigset_t { + #[cfg(target_pointer_width = "32")] + __val: [u32; 32], + #[cfg(target_pointer_width = "64")] + __val: [u64; 16], + } + + pub struct sysinfo { + pub uptime: i64, + pub loads: [u64; 3], + pub totalram: u64, + pub freeram: u64, + pub sharedram: u64, + pub bufferram: u64, + pub totalswap: u64, + pub freeswap: u64, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: u64, + pub freehigh: u64, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: u64, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: u64, + __glibc_reserved5: u64, + } +} + +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +pub const O_LARGEFILE: ::c_int = 0; + +cfg_if! { + if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub use self::aarch64::*; + } else if #[cfg(any(target_arch = "powerpc64"))] { + mod powerpc64; + pub use self::powerpc64::*; + } else if #[cfg(any(target_arch = "sparc64"))] { + mod sparc64; + pub use self::sparc64::*; + } else if #[cfg(any(target_arch = "x86_64"))] { + mod x86_64; + pub use self::x86_64::*; + cfg_if! { + if #[cfg(target_pointer_width = "32")] { + mod x32; + pub use self::x32::*; + } else { + mod not_x32; + pub use self::not_x32::*; + } + } + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/notbsd/linux/other/b64/not_x32.rs b/libc/src/unix/notbsd/linux/other/b64/not_x32.rs new file mode 100644 index 000000000..e3e449807 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/not_x32.rs @@ -0,0 +1,421 @@ +use pthread_mutex_t; + +pub type c_long = i64; +pub type c_ulong = u64; + +s! { + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } +} + +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +align_const! { + #[cfg(target_endian = "little")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +// Syscall table + +pub const SYS_read: ::c_long = 0; +pub const SYS_write: ::c_long = 1; +pub const SYS_open: ::c_long = 2; +pub const SYS_close: ::c_long = 3; +pub const SYS_stat: ::c_long = 4; +pub const SYS_fstat: ::c_long = 5; +pub const SYS_lstat: ::c_long = 6; +pub const SYS_poll: ::c_long = 7; +pub const SYS_lseek: ::c_long = 8; +pub const SYS_mmap: ::c_long = 9; +pub const SYS_mprotect: ::c_long = 10; +pub const SYS_munmap: ::c_long = 11; +pub const SYS_brk: ::c_long = 12; +pub const SYS_rt_sigaction: ::c_long = 13; +pub const SYS_rt_sigprocmask: ::c_long = 14; +pub const SYS_rt_sigreturn: ::c_long = 15; +pub const SYS_ioctl: ::c_long = 16; +pub const SYS_pread64: ::c_long = 17; +pub const SYS_pwrite64: ::c_long = 18; +pub const SYS_readv: ::c_long = 19; +pub const SYS_writev: ::c_long = 20; +pub const SYS_access: ::c_long = 21; +pub const SYS_pipe: ::c_long = 22; +pub const SYS_select: ::c_long = 23; +pub const SYS_sched_yield: ::c_long = 24; +pub const SYS_mremap: ::c_long = 25; +pub const SYS_msync: ::c_long = 26; +pub const SYS_mincore: ::c_long = 27; +pub const SYS_madvise: ::c_long = 28; +pub const SYS_shmget: ::c_long = 29; +pub const SYS_shmat: ::c_long = 30; +pub const SYS_shmctl: ::c_long = 31; +pub const SYS_dup: ::c_long = 32; +pub const SYS_dup2: ::c_long = 33; +pub const SYS_pause: ::c_long = 34; +pub const SYS_nanosleep: ::c_long = 35; +pub const SYS_getitimer: ::c_long = 36; +pub const SYS_alarm: ::c_long = 37; +pub const SYS_setitimer: ::c_long = 38; +pub const SYS_getpid: ::c_long = 39; +pub const SYS_sendfile: ::c_long = 40; +pub const SYS_socket: ::c_long = 41; +pub const SYS_connect: ::c_long = 42; +pub const SYS_accept: ::c_long = 43; +pub const SYS_sendto: ::c_long = 44; +pub const SYS_recvfrom: ::c_long = 45; +pub const SYS_sendmsg: ::c_long = 46; +pub const SYS_recvmsg: ::c_long = 47; +pub const SYS_shutdown: ::c_long = 48; +pub const SYS_bind: ::c_long = 49; +pub const SYS_listen: ::c_long = 50; +pub const SYS_getsockname: ::c_long = 51; +pub const SYS_getpeername: ::c_long = 52; +pub const SYS_socketpair: ::c_long = 53; +pub const SYS_setsockopt: ::c_long = 54; +pub const SYS_getsockopt: ::c_long = 55; +pub const SYS_clone: ::c_long = 56; +pub const SYS_fork: ::c_long = 57; +pub const SYS_vfork: ::c_long = 58; +pub const SYS_execve: ::c_long = 59; +pub const SYS_exit: ::c_long = 60; +pub const SYS_wait4: ::c_long = 61; +pub const SYS_kill: ::c_long = 62; +pub const SYS_uname: ::c_long = 63; +pub const SYS_semget: ::c_long = 64; +pub const SYS_semop: ::c_long = 65; +pub const SYS_semctl: ::c_long = 66; +pub const SYS_shmdt: ::c_long = 67; +pub const SYS_msgget: ::c_long = 68; +pub const SYS_msgsnd: ::c_long = 69; +pub const SYS_msgrcv: ::c_long = 70; +pub const SYS_msgctl: ::c_long = 71; +pub const SYS_fcntl: ::c_long = 72; +pub const SYS_flock: ::c_long = 73; +pub const SYS_fsync: ::c_long = 74; +pub const SYS_fdatasync: ::c_long = 75; +pub const SYS_truncate: ::c_long = 76; +pub const SYS_ftruncate: ::c_long = 77; +pub const SYS_getdents: ::c_long = 78; +pub const SYS_getcwd: ::c_long = 79; +pub const SYS_chdir: ::c_long = 80; +pub const SYS_fchdir: ::c_long = 81; +pub const SYS_rename: ::c_long = 82; +pub const SYS_mkdir: ::c_long = 83; +pub const SYS_rmdir: ::c_long = 84; +pub const SYS_creat: ::c_long = 85; +pub const SYS_link: ::c_long = 86; +pub const SYS_unlink: ::c_long = 87; +pub const SYS_symlink: ::c_long = 88; +pub const SYS_readlink: ::c_long = 89; +pub const SYS_chmod: ::c_long = 90; +pub const SYS_fchmod: ::c_long = 91; +pub const SYS_chown: ::c_long = 92; +pub const SYS_fchown: ::c_long = 93; +pub const SYS_lchown: ::c_long = 94; +pub const SYS_umask: ::c_long = 95; +pub const SYS_gettimeofday: ::c_long = 96; +pub const SYS_getrlimit: ::c_long = 97; +pub const SYS_getrusage: ::c_long = 98; +pub const SYS_sysinfo: ::c_long = 99; +pub const SYS_times: ::c_long = 100; +pub const SYS_ptrace: ::c_long = 101; +pub const SYS_getuid: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_getgid: ::c_long = 104; +pub const SYS_setuid: ::c_long = 105; +pub const SYS_setgid: ::c_long = 106; +pub const SYS_geteuid: ::c_long = 107; +pub const SYS_getegid: ::c_long = 108; +pub const SYS_setpgid: ::c_long = 109; +pub const SYS_getppid: ::c_long = 110; +pub const SYS_getpgrp: ::c_long = 111; +pub const SYS_setsid: ::c_long = 112; +pub const SYS_setreuid: ::c_long = 113; +pub const SYS_setregid: ::c_long = 114; +pub const SYS_getgroups: ::c_long = 115; +pub const SYS_setgroups: ::c_long = 116; +pub const SYS_setresuid: ::c_long = 117; +pub const SYS_getresuid: ::c_long = 118; +pub const SYS_setresgid: ::c_long = 119; +pub const SYS_getresgid: ::c_long = 120; +pub const SYS_getpgid: ::c_long = 121; +pub const SYS_setfsuid: ::c_long = 122; +pub const SYS_setfsgid: ::c_long = 123; +pub const SYS_getsid: ::c_long = 124; +pub const SYS_capget: ::c_long = 125; +pub const SYS_capset: ::c_long = 126; +pub const SYS_rt_sigpending: ::c_long = 127; +pub const SYS_rt_sigtimedwait: ::c_long = 128; +pub const SYS_rt_sigqueueinfo: ::c_long = 129; +pub const SYS_rt_sigsuspend: ::c_long = 130; +pub const SYS_sigaltstack: ::c_long = 131; +pub const SYS_utime: ::c_long = 132; +pub const SYS_mknod: ::c_long = 133; +pub const SYS_uselib: ::c_long = 134; +pub const SYS_personality: ::c_long = 135; +pub const SYS_ustat: ::c_long = 136; +pub const SYS_statfs: ::c_long = 137; +pub const SYS_fstatfs: ::c_long = 138; +pub const SYS_sysfs: ::c_long = 139; +pub const SYS_getpriority: ::c_long = 140; +pub const SYS_setpriority: ::c_long = 141; +pub const SYS_sched_setparam: ::c_long = 142; +pub const SYS_sched_getparam: ::c_long = 143; +pub const SYS_sched_setscheduler: ::c_long = 144; +pub const SYS_sched_getscheduler: ::c_long = 145; +pub const SYS_sched_get_priority_max: ::c_long = 146; +pub const SYS_sched_get_priority_min: ::c_long = 147; +pub const SYS_sched_rr_get_interval: ::c_long = 148; +pub const SYS_mlock: ::c_long = 149; +pub const SYS_munlock: ::c_long = 150; +pub const SYS_mlockall: ::c_long = 151; +pub const SYS_munlockall: ::c_long = 152; +pub const SYS_vhangup: ::c_long = 153; +pub const SYS_modify_ldt: ::c_long = 154; +pub const SYS_pivot_root: ::c_long = 155; +pub const SYS__sysctl: ::c_long = 156; +pub const SYS_prctl: ::c_long = 157; +pub const SYS_arch_prctl: ::c_long = 158; +pub const SYS_adjtimex: ::c_long = 159; +pub const SYS_setrlimit: ::c_long = 160; +pub const SYS_chroot: ::c_long = 161; +pub const SYS_sync: ::c_long = 162; +pub const SYS_acct: ::c_long = 163; +pub const SYS_settimeofday: ::c_long = 164; +pub const SYS_mount: ::c_long = 165; +pub const SYS_umount2: ::c_long = 166; +pub const SYS_swapon: ::c_long = 167; +pub const SYS_swapoff: ::c_long = 168; +pub const SYS_reboot: ::c_long = 169; +pub const SYS_sethostname: ::c_long = 170; +pub const SYS_setdomainname: ::c_long = 171; +pub const SYS_iopl: ::c_long = 172; +pub const SYS_ioperm: ::c_long = 173; +pub const SYS_create_module: ::c_long = 174; +pub const SYS_init_module: ::c_long = 175; +pub const SYS_delete_module: ::c_long = 176; +pub const SYS_get_kernel_syms: ::c_long = 177; +pub const SYS_query_module: ::c_long = 178; +pub const SYS_quotactl: ::c_long = 179; +pub const SYS_nfsservctl: ::c_long = 180; +pub const SYS_getpmsg: ::c_long = 181; +pub const SYS_putpmsg: ::c_long = 182; +pub const SYS_afs_syscall: ::c_long = 183; +pub const SYS_tuxcall: ::c_long = 184; +pub const SYS_security: ::c_long = 185; +pub const SYS_gettid: ::c_long = 186; +pub const SYS_readahead: ::c_long = 187; +pub const SYS_setxattr: ::c_long = 188; +pub const SYS_lsetxattr: ::c_long = 189; +pub const SYS_fsetxattr: ::c_long = 190; +pub const SYS_getxattr: ::c_long = 191; +pub const SYS_lgetxattr: ::c_long = 192; +pub const SYS_fgetxattr: ::c_long = 193; +pub const SYS_listxattr: ::c_long = 194; +pub const SYS_llistxattr: ::c_long = 195; +pub const SYS_flistxattr: ::c_long = 196; +pub const SYS_removexattr: ::c_long = 197; +pub const SYS_lremovexattr: ::c_long = 198; +pub const SYS_fremovexattr: ::c_long = 199; +pub const SYS_tkill: ::c_long = 200; +pub const SYS_time: ::c_long = 201; +pub const SYS_futex: ::c_long = 202; +pub const SYS_sched_setaffinity: ::c_long = 203; +pub const SYS_sched_getaffinity: ::c_long = 204; +pub const SYS_set_thread_area: ::c_long = 205; +pub const SYS_io_setup: ::c_long = 206; +pub const SYS_io_destroy: ::c_long = 207; +pub const SYS_io_getevents: ::c_long = 208; +pub const SYS_io_submit: ::c_long = 209; +pub const SYS_io_cancel: ::c_long = 210; +pub const SYS_get_thread_area: ::c_long = 211; +pub const SYS_lookup_dcookie: ::c_long = 212; +pub const SYS_epoll_create: ::c_long = 213; +pub const SYS_epoll_ctl_old: ::c_long = 214; +pub const SYS_epoll_wait_old: ::c_long = 215; +pub const SYS_remap_file_pages: ::c_long = 216; +pub const SYS_getdents64: ::c_long = 217; +pub const SYS_set_tid_address: ::c_long = 218; +pub const SYS_restart_syscall: ::c_long = 219; +pub const SYS_semtimedop: ::c_long = 220; +pub const SYS_fadvise64: ::c_long = 221; +pub const SYS_timer_create: ::c_long = 222; +pub const SYS_timer_settime: ::c_long = 223; +pub const SYS_timer_gettime: ::c_long = 224; +pub const SYS_timer_getoverrun: ::c_long = 225; +pub const SYS_timer_delete: ::c_long = 226; +pub const SYS_clock_settime: ::c_long = 227; +pub const SYS_clock_gettime: ::c_long = 228; +pub const SYS_clock_getres: ::c_long = 229; +pub const SYS_clock_nanosleep: ::c_long = 230; +pub const SYS_exit_group: ::c_long = 231; +pub const SYS_epoll_wait: ::c_long = 232; +pub const SYS_epoll_ctl: ::c_long = 233; +pub const SYS_tgkill: ::c_long = 234; +pub const SYS_utimes: ::c_long = 235; +pub const SYS_vserver: ::c_long = 236; +pub const SYS_mbind: ::c_long = 237; +pub const SYS_set_mempolicy: ::c_long = 238; +pub const SYS_get_mempolicy: ::c_long = 239; +pub const SYS_mq_open: ::c_long = 240; +pub const SYS_mq_unlink: ::c_long = 241; +pub const SYS_mq_timedsend: ::c_long = 242; +pub const SYS_mq_timedreceive: ::c_long = 243; +pub const SYS_mq_notify: ::c_long = 244; +pub const SYS_mq_getsetattr: ::c_long = 245; +pub const SYS_kexec_load: ::c_long = 246; +pub const SYS_waitid: ::c_long = 247; +pub const SYS_add_key: ::c_long = 248; +pub const SYS_request_key: ::c_long = 249; +pub const SYS_keyctl: ::c_long = 250; +pub const SYS_ioprio_set: ::c_long = 251; +pub const SYS_ioprio_get: ::c_long = 252; +pub const SYS_inotify_init: ::c_long = 253; +pub const SYS_inotify_add_watch: ::c_long = 254; +pub const SYS_inotify_rm_watch: ::c_long = 255; +pub const SYS_migrate_pages: ::c_long = 256; +pub const SYS_openat: ::c_long = 257; +pub const SYS_mkdirat: ::c_long = 258; +pub const SYS_mknodat: ::c_long = 259; +pub const SYS_fchownat: ::c_long = 260; +pub const SYS_futimesat: ::c_long = 261; +pub const SYS_newfstatat: ::c_long = 262; +pub const SYS_unlinkat: ::c_long = 263; +pub const SYS_renameat: ::c_long = 264; +pub const SYS_linkat: ::c_long = 265; +pub const SYS_symlinkat: ::c_long = 266; +pub const SYS_readlinkat: ::c_long = 267; +pub const SYS_fchmodat: ::c_long = 268; +pub const SYS_faccessat: ::c_long = 269; +pub const SYS_pselect6: ::c_long = 270; +pub const SYS_ppoll: ::c_long = 271; +pub const SYS_unshare: ::c_long = 272; +pub const SYS_set_robust_list: ::c_long = 273; +pub const SYS_get_robust_list: ::c_long = 274; +pub const SYS_splice: ::c_long = 275; +pub const SYS_tee: ::c_long = 276; +pub const SYS_sync_file_range: ::c_long = 277; +pub const SYS_vmsplice: ::c_long = 278; +pub const SYS_move_pages: ::c_long = 279; +pub const SYS_utimensat: ::c_long = 280; +pub const SYS_epoll_pwait: ::c_long = 281; +pub const SYS_signalfd: ::c_long = 282; +pub const SYS_timerfd_create: ::c_long = 283; +pub const SYS_eventfd: ::c_long = 284; +pub const SYS_fallocate: ::c_long = 285; +pub const SYS_timerfd_settime: ::c_long = 286; +pub const SYS_timerfd_gettime: ::c_long = 287; +pub const SYS_accept4: ::c_long = 288; +pub const SYS_signalfd4: ::c_long = 289; +pub const SYS_eventfd2: ::c_long = 290; +pub const SYS_epoll_create1: ::c_long = 291; +pub const SYS_dup3: ::c_long = 292; +pub const SYS_pipe2: ::c_long = 293; +pub const SYS_inotify_init1: ::c_long = 294; +pub const SYS_preadv: ::c_long = 295; +pub const SYS_pwritev: ::c_long = 296; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 297; +pub const SYS_perf_event_open: ::c_long = 298; +pub const SYS_recvmmsg: ::c_long = 299; +pub const SYS_fanotify_init: ::c_long = 300; +pub const SYS_fanotify_mark: ::c_long = 301; +pub const SYS_prlimit64: ::c_long = 302; +pub const SYS_name_to_handle_at: ::c_long = 303; +pub const SYS_open_by_handle_at: ::c_long = 304; +pub const SYS_clock_adjtime: ::c_long = 305; +pub const SYS_syncfs: ::c_long = 306; +pub const SYS_sendmmsg: ::c_long = 307; +pub const SYS_setns: ::c_long = 308; +pub const SYS_getcpu: ::c_long = 309; +pub const SYS_process_vm_readv: ::c_long = 310; +pub const SYS_process_vm_writev: ::c_long = 311; +pub const SYS_kcmp: ::c_long = 312; +pub const SYS_finit_module: ::c_long = 313; +pub const SYS_sched_setattr: ::c_long = 314; +pub const SYS_sched_getattr: ::c_long = 315; +pub const SYS_renameat2: ::c_long = 316; +pub const SYS_seccomp: ::c_long = 317; +pub const SYS_getrandom: ::c_long = 318; +pub const SYS_memfd_create: ::c_long = 319; +pub const SYS_kexec_file_load: ::c_long = 320; +pub const SYS_bpf: ::c_long = 321; +pub const SYS_execveat: ::c_long = 322; +pub const SYS_userfaultfd: ::c_long = 323; +pub const SYS_membarrier: ::c_long = 324; +pub const SYS_mlock2: ::c_long = 325; +pub const SYS_copy_file_range: ::c_long = 326; +pub const SYS_preadv2: ::c_long = 327; +pub const SYS_pwritev2: ::c_long = 328; +pub const SYS_pkey_mprotect: ::c_long = 329; +pub const SYS_pkey_alloc: ::c_long = 330; +pub const SYS_pkey_free: ::c_long = 331; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/b64/powerpc64.rs b/libc/src/unix/notbsd/linux/other/b64/powerpc64.rs new file mode 100644 index 000000000..bc5b01c5a --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/powerpc64.rs @@ -0,0 +1,930 @@ +//! PowerPC64-specific definitions for 64-bit linux-like values + +use pthread_mutex_t; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = u8; +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = i64; +pub type suseconds_t = i64; +pub type __u64 = ::c_ulong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __reserved: [::c_long; 3], + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u64; 7] + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::uint32_t, + __pad1: ::uint32_t, + __unused1: ::uint64_t, + __unused2: ::c_ulong, + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_segsz: ::size_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +pub const TIOCGSOFTCAR: ::c_ulong = 0x5419; +pub const TIOCSSOFTCAR: ::c_ulong = 0x541A; + +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 6; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; +pub const O_FSYNC: ::c_int = 0x101000; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const MAP_GROWSDOWN: ::c_int = 0x0100; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EBADMSG: ::c_int = 74; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const EHWPOISON: ::c_int = 133; +pub const ERFKILL: ::c_int = 132; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 20; +pub const SO_PEERCRED: ::c_int = 21; +pub const SO_RCVLOWAT: ::c_int = 16; +pub const SO_SNDLOWAT: ::c_int = 17; +pub const SO_RCVTIMEO: ::c_int = 18; +pub const SO_SNDTIMEO: ::c_int = 19; +pub const SO_SECURITY_AUTHENTICATION: ::c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: ::c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: ::c_int = 24; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_ATTACH_FILTER: ::c_int = 26; +pub const SO_DETACH_FILTER: ::c_int = 27; +pub const SO_GET_FILTER: ::c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: ::c_int = 28; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_PEERSEC: ::c_int = 31; +pub const SO_PASSSEC: ::c_int = 34; +pub const SO_TIMESTAMPNS: ::c_int = 35; +pub const SCM_TIMESTAMPNS: ::c_int = SO_TIMESTAMPNS; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_WIFI_STATUS: ::c_int = 41; +pub const SCM_WIFI_STATUS: ::c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_NOFCS: ::c_int = 43; +pub const SO_LOCK_FILTER: ::c_int = 44; +pub const SO_SELECT_ERR_QUEUE: ::c_int = 45; +pub const SO_BUSY_POLL: ::c_int = 46; +pub const SO_MAX_PACING_RATE: ::c_int = 47; +pub const SO_BPF_EXTENSIONS: ::c_int = 48; +pub const SO_INCOMING_CPU: ::c_int = 49; +pub const SO_ATTACH_BPF: ::c_int = 50; +pub const SO_DETACH_BPF: ::c_int = SO_DETACH_FILTER; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; + +pub const PTRACE_DETACH: ::c_uint = 17; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const SFD_NONBLOCK: ::c_int = 0x0800; + +pub const TIOCEXCL: ::c_ulong = 0x540C; +pub const TIOCNXCL: ::c_ulong = 0x540D; +pub const TIOCSCTTY: ::c_ulong = 0x540E; +pub const TIOCSTI: ::c_ulong = 0x5412; +pub const TIOCMGET: ::c_ulong = 0x5415; +pub const TIOCMBIS: ::c_ulong = 0x5416; +pub const TIOCMBIC: ::c_ulong = 0x5417; +pub const TIOCMSET: ::c_ulong = 0x5418; +pub const TIOCCONS: ::c_ulong = 0x541D; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + +align_const! { + #[cfg(target_endian = "little")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "little")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + #[cfg(target_endian = "big")] + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_DIRECT: ::c_int = 0x20000; + +pub const MAP_LOCKED: ::c_int = 0x00080; +pub const MAP_NORESERVE: ::c_int = 0x00040; + +pub const EDEADLOCK: ::c_int = 58; + +pub const FIOCLEX: ::c_ulong = 0x20006601; +pub const FIONBIO: ::c_ulong = 0x8004667e; + +pub const MCL_CURRENT: ::c_int = 0x2000; +pub const MCL_FUTURE: ::c_int = 0x4000; + +pub const SIGSTKSZ: ::size_t = 0x4000; +pub const MINSIGSTKSZ: ::size_t = 4096; +pub const CBAUD: ::tcflag_t = 0xff; +pub const TAB1: ::c_int = 0x400; +pub const TAB2: ::c_int = 0x800; +pub const TAB3: ::c_int = 0xc00; +pub const CR1: ::c_int = 0x1000; +pub const CR2: ::c_int = 0x2000; +pub const CR3: ::c_int = 0x3000; +pub const FF1: ::c_int = 0x4000; +pub const BS1: ::c_int = 0x8000; +pub const VT1: ::c_int = 0x10000; +pub const VWERASE: usize = 0xa; +pub const VREPRINT: usize = 0xb; +pub const VSUSP: usize = 0xc; +pub const VSTART: usize = 0xd; +pub const VSTOP: usize = 0xe; +pub const VDISCARD: usize = 0x10; +pub const VTIME: usize = 0x7; +pub const IXON: ::tcflag_t = 0x200; +pub const IXOFF: ::tcflag_t = 0x400; +pub const ONLCR: ::tcflag_t = 0x2; +pub const CSIZE: ::tcflag_t = 0x300; +pub const CS6: ::tcflag_t = 0x100; +pub const CS7: ::tcflag_t = 0x200; +pub const CS8: ::tcflag_t = 0x300; +pub const CSTOPB: ::tcflag_t = 0x400; +pub const CREAD: ::tcflag_t = 0x800; +pub const PARENB: ::tcflag_t = 0x1000; +pub const PARODD: ::tcflag_t = 0x2000; +pub const HUPCL: ::tcflag_t = 0x4000; +pub const CLOCAL: ::tcflag_t = 0x8000; +pub const ECHOKE: ::tcflag_t = 0x1; +pub const ECHOE: ::tcflag_t = 0x2; +pub const ECHOK: ::tcflag_t = 0x4; +pub const ECHONL: ::tcflag_t = 0x10; +pub const ECHOPRT: ::tcflag_t = 0x20; +pub const ECHOCTL: ::tcflag_t = 0x40; +pub const ISIG: ::tcflag_t = 0x80; +pub const ICANON: ::tcflag_t = 0x100; +pub const PENDIN: ::tcflag_t = 0x20000000; +pub const NOFLSH: ::tcflag_t = 0x80000000; +pub const VSWTC: usize = 9; +pub const OLCUC: ::tcflag_t = 0o000004; +pub const NLDLY: ::tcflag_t = 0o001400; +pub const CRDLY: ::tcflag_t = 0o030000; +pub const TABDLY: ::tcflag_t = 0o006000; +pub const BSDLY: ::tcflag_t = 0o100000; +pub const FFDLY: ::tcflag_t = 0o040000; +pub const VTDLY: ::tcflag_t = 0o200000; +pub const XTABS: ::tcflag_t = 0o006000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const CBAUDEX: ::speed_t = 0o000020; +pub const B57600: ::speed_t = 0o0020; +pub const B115200: ::speed_t = 0o0021; +pub const B230400: ::speed_t = 0o0022; +pub const B460800: ::speed_t = 0o0023; +pub const B500000: ::speed_t = 0o0024; +pub const B576000: ::speed_t = 0o0025; +pub const B921600: ::speed_t = 0o0026; +pub const B1000000: ::speed_t = 0o0027; +pub const B1152000: ::speed_t = 0o0030; +pub const B1500000: ::speed_t = 0o0031; +pub const B2000000: ::speed_t = 0o0032; +pub const B2500000: ::speed_t = 0o0033; +pub const B3000000: ::speed_t = 0o0034; +pub const B3500000: ::speed_t = 0o0035; +pub const B4000000: ::speed_t = 0o0036; +pub const BOTHER: ::speed_t = 0o0037; + +pub const VEOL: usize = 6; +pub const VEOL2: usize = 8; +pub const VMIN: usize = 5; +pub const IEXTEN: ::tcflag_t = 0x400; +pub const TOSTOP: ::tcflag_t = 0x400000; +pub const FLUSHO: ::tcflag_t = 0x800000; +pub const EXTPROC: ::tcflag_t = 0x10000000; +pub const TCGETS: ::c_ulong = 0x403c7413; +pub const TCSETS: ::c_ulong = 0x803c7414; +pub const TCSETSW: ::c_ulong = 0x803c7415; +pub const TCSETSF: ::c_ulong = 0x803c7416; +pub const TCGETA: ::c_ulong = 0x40147417; +pub const TCSETA: ::c_ulong = 0x80147418; +pub const TCSETAW: ::c_ulong = 0x80147419; +pub const TCSETAF: ::c_ulong = 0x8014741c; +pub const TCSBRK: ::c_ulong = 0x2000741d; +pub const TCXONC: ::c_ulong = 0x2000741e; +pub const TCFLSH: ::c_ulong = 0x2000741f; +pub const TIOCINQ: ::c_ulong = 0x4004667f; +pub const TIOCGPGRP: ::c_ulong = 0x40047477; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCOUTQ: ::c_ulong = 0x40047473; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const FIONREAD: ::c_ulong = 0x4004667f; + +// Syscall table +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_waitpid: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_time: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_break: ::c_long = 17; +pub const SYS_oldstat: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_stime: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_oldfstat: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_stty: ::c_long = 31; +pub const SYS_gtty: ::c_long = 32; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_ftime: ::c_long = 35; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_prof: ::c_long = 44; +pub const SYS_brk: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_lock: ::c_long = 53; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_mpx: ::c_long = 56; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_ulimit: ::c_long = 58; +pub const SYS_oldolduname: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sgetmask: ::c_long = 68; +pub const SYS_ssetmask: ::c_long = 69; +pub const SYS_setreuid: ::c_long = 70; +pub const SYS_setregid: ::c_long = 71; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrlimit: ::c_long = 76; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_getgroups: ::c_long = 80; +pub const SYS_setgroups: ::c_long = 81; +pub const SYS_select: ::c_long = 82; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_oldlstat: ::c_long = 84; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_fchown: ::c_long = 95; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_profil: ::c_long = 98; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_ioperm: ::c_long = 101; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_olduname: ::c_long = 109; +pub const SYS_iopl: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_vm86: ::c_long = 113; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_modify_ldt: ::c_long = 123; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_setfsuid: ::c_long = 138; +pub const SYS_setfsgid: ::c_long = 139; +pub const SYS__llseek: ::c_long = 140; +pub const SYS_getdents: ::c_long = 141; +pub const SYS__newselect: ::c_long = 142; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_setresuid: ::c_long = 164; +pub const SYS_getresuid: ::c_long = 165; +pub const SYS_query_module: ::c_long = 166; +pub const SYS_poll: ::c_long = 167; +pub const SYS_nfsservctl: ::c_long = 168; +pub const SYS_setresgid: ::c_long = 169; +pub const SYS_getresgid: ::c_long = 170; +pub const SYS_prctl: ::c_long = 171; +pub const SYS_rt_sigreturn: ::c_long = 172; +pub const SYS_rt_sigaction: ::c_long = 173; +pub const SYS_rt_sigprocmask: ::c_long = 174; +pub const SYS_rt_sigpending: ::c_long = 175; +pub const SYS_rt_sigtimedwait: ::c_long = 176; +pub const SYS_rt_sigqueueinfo: ::c_long = 177; +pub const SYS_rt_sigsuspend: ::c_long = 178; +pub const SYS_pread64: ::c_long = 179; +pub const SYS_pwrite64: ::c_long = 180; +pub const SYS_chown: ::c_long = 181; +pub const SYS_getcwd: ::c_long = 182; +pub const SYS_capget: ::c_long = 183; +pub const SYS_capset: ::c_long = 184; +pub const SYS_sigaltstack: ::c_long = 185; +pub const SYS_sendfile: ::c_long = 186; +pub const SYS_getpmsg: ::c_long = 187; /* some people actually want streams */ +pub const SYS_putpmsg: ::c_long = 188; /* some people actually want streams */ +pub const SYS_vfork: ::c_long = 189; +pub const SYS_ugetrlimit: ::c_long = 190; /* SuS compliant getrlimit */ +pub const SYS_readahead: ::c_long = 191; +pub const SYS_pciconfig_read: ::c_long = 198; +pub const SYS_pciconfig_write: ::c_long = 199; +pub const SYS_pciconfig_iobase: ::c_long = 200; +pub const SYS_multiplexer: ::c_long = 201; +pub const SYS_getdents64: ::c_long = 202; +pub const SYS_pivot_root: ::c_long = 203; +pub const SYS_madvise: ::c_long = 205; +pub const SYS_mincore: ::c_long = 206; +pub const SYS_gettid: ::c_long = 207; +pub const SYS_tkill: ::c_long = 208; +pub const SYS_setxattr: ::c_long = 209; +pub const SYS_lsetxattr: ::c_long = 210; +pub const SYS_fsetxattr: ::c_long = 211; +pub const SYS_getxattr: ::c_long = 212; +pub const SYS_lgetxattr: ::c_long = 213; +pub const SYS_fgetxattr: ::c_long = 214; +pub const SYS_listxattr: ::c_long = 215; +pub const SYS_llistxattr: ::c_long = 216; +pub const SYS_flistxattr: ::c_long = 217; +pub const SYS_removexattr: ::c_long = 218; +pub const SYS_lremovexattr: ::c_long = 219; +pub const SYS_fremovexattr: ::c_long = 220; +pub const SYS_futex: ::c_long = 221; +pub const SYS_sched_setaffinity: ::c_long = 222; +pub const SYS_sched_getaffinity: ::c_long = 223; +pub const SYS_tuxcall: ::c_long = 225; +pub const SYS_io_setup: ::c_long = 227; +pub const SYS_io_destroy: ::c_long = 228; +pub const SYS_io_getevents: ::c_long = 229; +pub const SYS_io_submit: ::c_long = 230; +pub const SYS_io_cancel: ::c_long = 231; +pub const SYS_set_tid_address: ::c_long = 232; +pub const SYS_exit_group: ::c_long = 234; +pub const SYS_lookup_dcookie: ::c_long = 235; +pub const SYS_epoll_create: ::c_long = 236; +pub const SYS_epoll_ctl: ::c_long = 237; +pub const SYS_epoll_wait: ::c_long = 238; +pub const SYS_remap_file_pages: ::c_long = 239; +pub const SYS_timer_create: ::c_long = 240; +pub const SYS_timer_settime: ::c_long = 241; +pub const SYS_timer_gettime: ::c_long = 242; +pub const SYS_timer_getoverrun: ::c_long = 243; +pub const SYS_timer_delete: ::c_long = 244; +pub const SYS_clock_settime: ::c_long = 245; +pub const SYS_clock_gettime: ::c_long = 246; +pub const SYS_clock_getres: ::c_long = 247; +pub const SYS_clock_nanosleep: ::c_long = 248; +pub const SYS_swapcontext: ::c_long = 249; +pub const SYS_tgkill: ::c_long = 250; +pub const SYS_utimes: ::c_long = 251; +pub const SYS_statfs64: ::c_long = 252; +pub const SYS_fstatfs64: ::c_long = 253; +pub const SYS_rtas: ::c_long = 255; +pub const SYS_sys_debug_setcontext: ::c_long = 256; +pub const SYS_migrate_pages: ::c_long = 258; +pub const SYS_mbind: ::c_long = 259; +pub const SYS_get_mempolicy: ::c_long = 260; +pub const SYS_set_mempolicy: ::c_long = 261; +pub const SYS_mq_open: ::c_long = 262; +pub const SYS_mq_unlink: ::c_long = 263; +pub const SYS_mq_timedsend: ::c_long = 264; +pub const SYS_mq_timedreceive: ::c_long = 265; +pub const SYS_mq_notify: ::c_long = 266; +pub const SYS_mq_getsetattr: ::c_long = 267; +pub const SYS_kexec_load: ::c_long = 268; +pub const SYS_add_key: ::c_long = 269; +pub const SYS_request_key: ::c_long = 270; +pub const SYS_keyctl: ::c_long = 271; +pub const SYS_waitid: ::c_long = 272; +pub const SYS_ioprio_set: ::c_long = 273; +pub const SYS_ioprio_get: ::c_long = 274; +pub const SYS_inotify_init: ::c_long = 275; +pub const SYS_inotify_add_watch: ::c_long = 276; +pub const SYS_inotify_rm_watch: ::c_long = 277; +pub const SYS_spu_run: ::c_long = 278; +pub const SYS_spu_create: ::c_long = 279; +pub const SYS_pselect6: ::c_long = 280; +pub const SYS_ppoll: ::c_long = 281; +pub const SYS_unshare: ::c_long = 282; +pub const SYS_splice: ::c_long = 283; +pub const SYS_tee: ::c_long = 284; +pub const SYS_vmsplice: ::c_long = 285; +pub const SYS_openat: ::c_long = 286; +pub const SYS_mkdirat: ::c_long = 287; +pub const SYS_mknodat: ::c_long = 288; +pub const SYS_fchownat: ::c_long = 289; +pub const SYS_futimesat: ::c_long = 290; +pub const SYS_newfstatat: ::c_long = 291; +pub const SYS_unlinkat: ::c_long = 292; +pub const SYS_renameat: ::c_long = 293; +pub const SYS_linkat: ::c_long = 294; +pub const SYS_symlinkat: ::c_long = 295; +pub const SYS_readlinkat: ::c_long = 296; +pub const SYS_fchmodat: ::c_long = 297; +pub const SYS_faccessat: ::c_long = 298; +pub const SYS_get_robust_list: ::c_long = 299; +pub const SYS_set_robust_list: ::c_long = 300; +pub const SYS_move_pages: ::c_long = 301; +pub const SYS_getcpu: ::c_long = 302; +pub const SYS_epoll_pwait: ::c_long = 303; +pub const SYS_utimensat: ::c_long = 304; +pub const SYS_signalfd: ::c_long = 305; +pub const SYS_timerfd_create: ::c_long = 306; +pub const SYS_eventfd: ::c_long = 307; +pub const SYS_sync_file_range2: ::c_long = 308; +pub const SYS_fallocate: ::c_long = 309; +pub const SYS_subpage_prot: ::c_long = 310; +pub const SYS_timerfd_settime: ::c_long = 311; +pub const SYS_timerfd_gettime: ::c_long = 312; +pub const SYS_signalfd4: ::c_long = 313; +pub const SYS_eventfd2: ::c_long = 314; +pub const SYS_epoll_create1: ::c_long = 315; +pub const SYS_dup3: ::c_long = 316; +pub const SYS_pipe2: ::c_long = 317; +pub const SYS_inotify_init1: ::c_long = 318; +pub const SYS_perf_event_open: ::c_long = 319; +pub const SYS_preadv: ::c_long = 320; +pub const SYS_pwritev: ::c_long = 321; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 322; +pub const SYS_fanotify_init: ::c_long = 323; +pub const SYS_fanotify_mark: ::c_long = 324; +pub const SYS_prlimit64: ::c_long = 325; +pub const SYS_socket: ::c_long = 326; +pub const SYS_bind: ::c_long = 327; +pub const SYS_connect: ::c_long = 328; +pub const SYS_listen: ::c_long = 329; +pub const SYS_accept: ::c_long = 330; +pub const SYS_getsockname: ::c_long = 331; +pub const SYS_getpeername: ::c_long = 332; +pub const SYS_socketpair: ::c_long = 333; +pub const SYS_send: ::c_long = 334; +pub const SYS_sendto: ::c_long = 335; +pub const SYS_recv: ::c_long = 336; +pub const SYS_recvfrom: ::c_long = 337; +pub const SYS_shutdown: ::c_long = 338; +pub const SYS_setsockopt: ::c_long = 339; +pub const SYS_getsockopt: ::c_long = 340; +pub const SYS_sendmsg: ::c_long = 341; +pub const SYS_recvmsg: ::c_long = 342; +pub const SYS_recvmmsg: ::c_long = 343; +pub const SYS_accept4: ::c_long = 344; +pub const SYS_name_to_handle_at: ::c_long = 345; +pub const SYS_open_by_handle_at: ::c_long = 346; +pub const SYS_clock_adjtime: ::c_long = 347; +pub const SYS_syncfs: ::c_long = 348; +pub const SYS_sendmmsg: ::c_long = 349; +pub const SYS_setns: ::c_long = 350; +pub const SYS_process_vm_readv: ::c_long = 351; +pub const SYS_process_vm_writev: ::c_long = 352; +pub const SYS_finit_module: ::c_long = 353; +pub const SYS_kcmp: ::c_long = 354; +pub const SYS_sched_setattr: ::c_long = 355; +pub const SYS_sched_getattr: ::c_long = 356; +pub const SYS_renameat2: ::c_long = 357; +pub const SYS_seccomp: ::c_long = 358; +pub const SYS_getrandom: ::c_long = 359; +pub const SYS_memfd_create: ::c_long = 360; +pub const SYS_bpf: ::c_long = 361; +pub const SYS_execveat: ::c_long = 362; +pub const SYS_switch_endian: ::c_long = 363; +pub const SYS_userfaultfd: ::c_long = 364; +pub const SYS_membarrier: ::c_long = 365; +pub const SYS_mlock2: ::c_long = 378; +pub const SYS_copy_file_range: ::c_long = 379; +pub const SYS_preadv2: ::c_long = 380; +pub const SYS_pwritev2: ::c_long = 381; +pub const SYS_kexec_file_load: ::c_long = 382; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/b64/sparc64.rs b/libc/src/unix/notbsd/linux/other/b64/sparc64.rs new file mode 100644 index 000000000..5d268658c --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/sparc64.rs @@ -0,0 +1,868 @@ +//! SPARC64-specific definitions for 64-bit linux-like values + +use pthread_mutex_t; + +pub type c_long = i64; +pub type c_ulong = u64; +pub type c_char = i8; +pub type wchar_t = i32; +pub type nlink_t = u32; +pub type blksize_t = i64; +pub type suseconds_t = i32; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + __pad0: u64, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad1: u64, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __unused: [::c_long; 2], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + __pad0: u64, + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + __pad2: ::c_int, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + __reserved: [::c_long; 2], + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + __size: [u64; 7] + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + __pad0: u16, + pub __seq: ::c_ushort, + __unused1: ::c_ulonglong, + __unused2: ::c_ulonglong, + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_segsz: ::size_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __reserved1: ::c_ulong, + __reserved2: ::c_ulong + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +pub const TIOCGSOFTCAR: ::c_ulong = 0x40047464; +pub const TIOCSSOFTCAR: ::c_ulong = 0x80047465; + +pub const RLIMIT_NOFILE: ::c_int = 6; +pub const RLIMIT_NPROC: ::c_int = 7; + +pub const O_APPEND: ::c_int = 0x8; +pub const O_CREAT: ::c_int = 0x200; +pub const O_EXCL: ::c_int = 0x800; +pub const O_NOCTTY: ::c_int = 0x8000; +pub const O_NONBLOCK: ::c_int = 0x4000; +pub const O_SYNC: ::c_int = 0x802000; +pub const O_RSYNC: ::c_int = 0x802000; +pub const O_DSYNC: ::c_int = 0x2000; +pub const O_FSYNC: ::c_int = 0x802000; +pub const O_NOATIME: ::c_int = 0x200000; +pub const O_PATH: ::c_int = 0x1000000; +pub const O_TMPFILE: ::c_int = 0x2000000 | O_DIRECTORY; + +pub const MAP_GROWSDOWN: ::c_int = 0x0200; + +pub const EDEADLK: ::c_int = 78; +pub const ENAMETOOLONG: ::c_int = 63; +pub const ENOLCK: ::c_int = 79; +pub const ENOSYS: ::c_int = 90; +pub const ENOTEMPTY: ::c_int = 66; +pub const ELOOP: ::c_int = 62; +pub const ENOMSG: ::c_int = 75; +pub const EIDRM: ::c_int = 77; +pub const ECHRNG: ::c_int = 94; +pub const EL2NSYNC: ::c_int = 95; +pub const EL3HLT: ::c_int = 96; +pub const EL3RST: ::c_int = 97; +pub const ELNRNG: ::c_int = 98; +pub const EUNATCH: ::c_int = 99; +pub const ENOCSI: ::c_int = 100; +pub const EL2HLT: ::c_int = 101; +pub const EBADE: ::c_int = 102; +pub const EBADR: ::c_int = 103; +pub const EXFULL: ::c_int = 104; +pub const ENOANO: ::c_int = 105; +pub const EBADRQC: ::c_int = 106; +pub const EBADSLT: ::c_int = 107; +pub const EMULTIHOP: ::c_int = 87; +pub const EOVERFLOW: ::c_int = 92; +pub const ENOTUNIQ: ::c_int = 115; +pub const EBADFD: ::c_int = 93; +pub const EBADMSG: ::c_int = 76; +pub const EREMCHG: ::c_int = 89; +pub const ELIBACC: ::c_int = 114; +pub const ELIBBAD: ::c_int = 112; +pub const ELIBSCN: ::c_int = 124; +pub const ELIBMAX: ::c_int = 123; +pub const ELIBEXEC: ::c_int = 110; +pub const EILSEQ: ::c_int = 122; +pub const ERESTART: ::c_int = 116; +pub const ESTRPIPE: ::c_int = 91; +pub const EUSERS: ::c_int = 68; +pub const ENOTSOCK: ::c_int = 38; +pub const EDESTADDRREQ: ::c_int = 39; +pub const EMSGSIZE: ::c_int = 40; +pub const EPROTOTYPE: ::c_int = 41; +pub const ENOPROTOOPT: ::c_int = 42; +pub const EPROTONOSUPPORT: ::c_int = 43; +pub const ESOCKTNOSUPPORT: ::c_int = 44; +pub const EOPNOTSUPP: ::c_int = 45; +pub const EPFNOSUPPORT: ::c_int = 46; +pub const EAFNOSUPPORT: ::c_int = 47; +pub const EADDRINUSE: ::c_int = 48; +pub const EADDRNOTAVAIL: ::c_int = 49; +pub const ENETDOWN: ::c_int = 50; +pub const ENETUNREACH: ::c_int = 51; +pub const ENETRESET: ::c_int = 52; +pub const ECONNABORTED: ::c_int = 53; +pub const ECONNRESET: ::c_int = 54; +pub const ENOBUFS: ::c_int = 55; +pub const EISCONN: ::c_int = 56; +pub const ENOTCONN: ::c_int = 57; +pub const ESHUTDOWN: ::c_int = 58; +pub const ETOOMANYREFS: ::c_int = 59; +pub const ETIMEDOUT: ::c_int = 60; +pub const ECONNREFUSED: ::c_int = 61; +pub const EHOSTDOWN: ::c_int = 64; +pub const EHOSTUNREACH: ::c_int = 65; +pub const EALREADY: ::c_int = 37; +pub const EINPROGRESS: ::c_int = 36; +pub const ESTALE: ::c_int = 70; +pub const EDQUOT: ::c_int = 69; +pub const ENOMEDIUM: ::c_int = 125; +pub const EMEDIUMTYPE: ::c_int = 126; +pub const ECANCELED: ::c_int = 127; +pub const ENOKEY: ::c_int = 128; +pub const EKEYEXPIRED: ::c_int = 129; +pub const EKEYREVOKED: ::c_int = 130; +pub const EKEYREJECTED: ::c_int = 131; +pub const EOWNERDEAD: ::c_int = 132; +pub const ENOTRECOVERABLE: ::c_int = 133; +pub const EHWPOISON: ::c_int = 135; +pub const ERFKILL: ::c_int = 134; + +pub const SOL_SOCKET: ::c_int = 0xffff; + +pub const SO_PASSCRED: ::c_int = 2; +pub const SO_REUSEADDR: ::c_int = 4; +pub const SO_BINDTODEVICE: ::c_int = 0x000d; +pub const SO_TIMESTAMP: ::c_int = 0x001d; +pub const SO_MARK: ::c_int = 0x0022; +pub const SO_RXQ_OVFL: ::c_int = 0x0024; +pub const SO_PEEK_OFF: ::c_int = 0x0026; +pub const SO_BUSY_POLL: ::c_int = 0x0030; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_DONTROUTE: ::c_int = 16; +pub const SO_BROADCAST: ::c_int = 32; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDBUFFORCE: ::c_int = 0x100a; +pub const SO_RCVBUFFORCE: ::c_int = 0x100b; +pub const SO_DOMAIN: ::c_int = 0x1029; +pub const SO_KEEPALIVE: ::c_int = 8; +pub const SO_OOBINLINE: ::c_int = 0x100; +pub const SO_LINGER: ::c_int = 128; +pub const SO_REUSEPORT: ::c_int = 0x200; +pub const SO_ACCEPTCONN: ::c_int = 0x8000; + +pub const SA_ONSTACK: ::c_int = 1; +pub const SA_SIGINFO: ::c_int = 0x200; +pub const SA_NOCLDWAIT: ::c_int = 0x100; + +pub const SIGCHLD: ::c_int = 20; +pub const SIGBUS: ::c_int = 10; +pub const SIGUSR1: ::c_int = 30; +pub const SIGUSR2: ::c_int = 31; +pub const SIGCONT: ::c_int = 19; +pub const SIGSTOP: ::c_int = 17; +pub const SIGTSTP: ::c_int = 18; +pub const SIGURG: ::c_int = 16; +pub const SIGIO: ::c_int = 23; +pub const SIGSYS: ::c_int = 12; +pub const SIGPOLL: ::c_int = 23; +pub const SIGPWR: ::c_int = 29; +pub const SIG_SETMASK: ::c_int = 4; +pub const SIG_BLOCK: ::c_int = 1; +pub const SIG_UNBLOCK: ::c_int = 2; + +pub const POLLWRNORM: ::c_short = 4; +pub const POLLWRBAND: ::c_short = 0x100; + +pub const O_ASYNC: ::c_int = 0x40; +pub const O_NDELAY: ::c_int = 0x4004; + +pub const PTRACE_DETACH: ::c_uint = 11; + +pub const EFD_NONBLOCK: ::c_int = 0x4000; + +pub const F_GETLK: ::c_int = 7; +pub const F_GETOWN: ::c_int = 5; +pub const F_SETOWN: ::c_int = 6; +pub const F_SETLK: ::c_int = 8; +pub const F_SETLKW: ::c_int = 9; + +pub const F_RDLCK: ::c_int = 1; +pub const F_WRLCK: ::c_int = 2; +pub const F_UNLCK: ::c_int = 3; + +pub const SFD_NONBLOCK: ::c_int = 0x4000; + +pub const TIOCEXCL: ::c_ulong = 0x2000740d; +pub const TIOCNXCL: ::c_ulong = 0x2000740e; +pub const TIOCSCTTY: ::c_ulong = 0x20007484; +pub const TIOCSTI: ::c_ulong = 0x80017472; +pub const TIOCMGET: ::c_ulong = 0x4004746a; +pub const TIOCMBIS: ::c_ulong = 0x8004746c; +pub const TIOCMBIC: ::c_ulong = 0x8004746b; +pub const TIOCMSET: ::c_ulong = 0x8004746d; +pub const TIOCCONS: ::c_ulong = 0x20007424; + +pub const SFD_CLOEXEC: ::c_int = 0x400000; + +pub const NCCS: usize = 17; +pub const O_TRUNC: ::c_int = 0x400; + +pub const O_CLOEXEC: ::c_int = 0x400000; + +pub const EBFONT: ::c_int = 109; +pub const ENOSTR: ::c_int = 72; +pub const ENODATA: ::c_int = 111; +pub const ETIME: ::c_int = 73; +pub const ENOSR: ::c_int = 74; +pub const ENONET: ::c_int = 80; +pub const ENOPKG: ::c_int = 113; +pub const EREMOTE: ::c_int = 71; +pub const ENOLINK: ::c_int = 82; +pub const EADV: ::c_int = 83; +pub const ESRMNT: ::c_int = 84; +pub const ECOMM: ::c_int = 85; +pub const EPROTO: ::c_int = 86; +pub const EDOTDOT: ::c_int = 88; + +pub const SA_NODEFER: ::c_int = 0x20; +pub const SA_RESETHAND: ::c_int = 0x4; +pub const SA_RESTART: ::c_int = 0x2; +pub const SA_NOCLDSTOP: ::c_int = 0x00000008; + +pub const EPOLL_CLOEXEC: ::c_int = 0x400000; + +pub const EFD_CLOEXEC: ::c_int = 0x400000; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + +align_const! { + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +pub const O_DIRECTORY: ::c_int = 0o200000; +pub const O_NOFOLLOW: ::c_int = 0o400000; +pub const O_DIRECT: ::c_int = 0x100000; + +pub const MAP_LOCKED: ::c_int = 0x0100; +pub const MAP_NORESERVE: ::c_int = 0x00040; + +pub const EDEADLOCK: ::c_int = 108; + +pub const SO_PEERCRED: ::c_int = 0x40; +pub const SO_RCVLOWAT: ::c_int = 0x800; +pub const SO_SNDLOWAT: ::c_int = 0x1000; +pub const SO_RCVTIMEO: ::c_int = 0x2000; +pub const SO_SNDTIMEO: ::c_int = 0x4000; + +pub const FIOCLEX: ::c_ulong = 0x20006601; +pub const FIONBIO: ::c_ulong = 0x8004667e; + +pub const MCL_CURRENT: ::c_int = 0x2000; +pub const MCL_FUTURE: ::c_int = 0x4000; + +pub const SIGSTKSZ: ::size_t = 16384; +pub const MINSIGSTKSZ: ::size_t = 4096; +pub const CBAUD: ::tcflag_t = 0x0000100f; +pub const TAB1: ::c_int = 0x800; +pub const TAB2: ::c_int = 0x1000; +pub const TAB3: ::c_int = 0x1800; +pub const CR1: ::c_int = 0x200; +pub const CR2: ::c_int = 0x400; +pub const CR3: ::c_int = 0x600; +pub const FF1: ::c_int = 0x8000; +pub const BS1: ::c_int = 0x2000; +pub const VT1: ::c_int = 0x4000; +pub const VWERASE: usize = 0xe; +pub const VREPRINT: usize = 0xc; +pub const VSUSP: usize = 0xa; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VDISCARD: usize = 0xd; +pub const VTIME: usize = 0x5; +pub const IXON: ::tcflag_t = 0x400; +pub const IXOFF: ::tcflag_t = 0x1000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x30; +pub const CS6: ::tcflag_t = 0x10; +pub const CS7: ::tcflag_t = 0x20; +pub const CS8: ::tcflag_t = 0x30; +pub const CSTOPB: ::tcflag_t = 0x40; +pub const CREAD: ::tcflag_t = 0x80; +pub const PARENB: ::tcflag_t = 0x100; +pub const PARODD: ::tcflag_t = 0x200; +pub const HUPCL: ::tcflag_t = 0x400; +pub const CLOCAL: ::tcflag_t = 0x800; +pub const ECHOKE: ::tcflag_t = 0x800; +pub const ECHOE: ::tcflag_t = 0x10; +pub const ECHOK: ::tcflag_t = 0x20; +pub const ECHONL: ::tcflag_t = 0x40; +pub const ECHOPRT: ::tcflag_t = 0x400; +pub const ECHOCTL: ::tcflag_t = 0x200; +pub const ISIG: ::tcflag_t = 0x1; +pub const ICANON: ::tcflag_t = 0x2; +pub const PENDIN: ::tcflag_t = 0x4000; +pub const NOFLSH: ::tcflag_t = 0x80; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0x00001000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0x1000; +pub const B57600: ::speed_t = 0x1001; +pub const B115200: ::speed_t = 0x1002; +pub const B230400: ::speed_t = 0x1003; +pub const B460800: ::speed_t = 0x1004; +pub const B76800: ::speed_t = 0x1005; +pub const B153600: ::speed_t = 0x1006; +pub const B307200: ::speed_t = 0x1007; +pub const B614400: ::speed_t = 0x1008; +pub const B921600: ::speed_t = 0x1009; +pub const B500000: ::speed_t = 0x100a; +pub const B576000: ::speed_t = 0x100b; +pub const B1000000: ::speed_t = 0x100c; +pub const B1152000: ::speed_t = 0x100d; +pub const B1500000: ::speed_t = 0x100e; +pub const B2000000: ::speed_t = 0x100f; + +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: ::tcflag_t = 0x8000; +pub const TOSTOP: ::tcflag_t = 0x100; +pub const FLUSHO: ::tcflag_t = 0x1000; +pub const EXTPROC: ::tcflag_t = 0x10000; +pub const TCGETS: ::c_ulong = 0x40245408; +pub const TCSETS: ::c_ulong = 0x80245409; +pub const TCSETSW: ::c_ulong = 0x8024540a; +pub const TCSETSF: ::c_ulong = 0x8024540b; +pub const TCGETA: ::c_ulong = 0x40125401; +pub const TCSETA: ::c_ulong = 0x80125402; +pub const TCSETAW: ::c_ulong = 0x80125403; +pub const TCSETAF: ::c_ulong = 0x80125404; +pub const TCSBRK: ::c_ulong = 0x20005405; +pub const TCXONC: ::c_ulong = 0x20005406; +pub const TCFLSH: ::c_ulong = 0x20005407; +pub const TIOCINQ: ::c_ulong = 0x4004667f; +pub const TIOCGPGRP: ::c_ulong = 0x40047483; +pub const TIOCSPGRP: ::c_ulong = 0x80047482; +pub const TIOCOUTQ: ::c_ulong = 0x40047473; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const FIONREAD: ::c_ulong = 0x4004667f; + +pub const SYS_restart_syscall: ::c_long = 0; +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_wait4: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execv: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_chown: ::c_long = 13; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lchown: ::c_long = 16; +pub const SYS_brk: ::c_long = 17; +pub const SYS_perfctr: ::c_long = 18; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_capget: ::c_long = 21; +pub const SYS_capset: ::c_long = 22; +pub const SYS_setuid: ::c_long = 23; +pub const SYS_getuid: ::c_long = 24; +pub const SYS_vmsplice: ::c_long = 25; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_sigaltstack: ::c_long = 28; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_stat: ::c_long = 38; +pub const SYS_sendfile: ::c_long = 39; +pub const SYS_lstat: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_umount2: ::c_long = 45; +pub const SYS_setgid: ::c_long = 46; +pub const SYS_getgid: ::c_long = 47; +pub const SYS_signal: ::c_long = 48; +pub const SYS_geteuid: ::c_long = 49; +pub const SYS_getegid: ::c_long = 50; +pub const SYS_acct: ::c_long = 51; +pub const SYS_memory_ordering: ::c_long = 52; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_reboot: ::c_long = 55; +pub const SYS_symlink: ::c_long = 57; +pub const SYS_readlink: ::c_long = 58; +pub const SYS_execve: ::c_long = 59; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_fstat: ::c_long = 62; +pub const SYS_fstat64: ::c_long = 63; +pub const SYS_getpagesize: ::c_long = 64; +pub const SYS_msync: ::c_long = 65; +pub const SYS_vfork: ::c_long = 66; +pub const SYS_pread64: ::c_long = 67; +pub const SYS_pwrite64: ::c_long = 68; +pub const SYS_mmap: ::c_long = 71; +pub const SYS_munmap: ::c_long = 73; +pub const SYS_mprotect: ::c_long = 74; +pub const SYS_madvise: ::c_long = 75; +pub const SYS_vhangup: ::c_long = 76; +pub const SYS_mincore: ::c_long = 78; +pub const SYS_getgroups: ::c_long = 79; +pub const SYS_setgroups: ::c_long = 80; +pub const SYS_getpgrp: ::c_long = 81; +pub const SYS_setitimer: ::c_long = 83; +pub const SYS_swapon: ::c_long = 85; +pub const SYS_getitimer: ::c_long = 86; +pub const SYS_sethostname: ::c_long = 88; +pub const SYS_dup2: ::c_long = 90; +pub const SYS_fcntl: ::c_long = 92; +pub const SYS_select: ::c_long = 93; +pub const SYS_fsync: ::c_long = 95; +pub const SYS_setpriority: ::c_long = 96; +pub const SYS_socket: ::c_long = 97; +pub const SYS_connect: ::c_long = 98; +pub const SYS_accept: ::c_long = 99; +pub const SYS_getpriority: ::c_long = 100; +pub const SYS_rt_sigreturn: ::c_long = 101; +pub const SYS_rt_sigaction: ::c_long = 102; +pub const SYS_rt_sigprocmask: ::c_long = 103; +pub const SYS_rt_sigpending: ::c_long = 104; +pub const SYS_rt_sigtimedwait: ::c_long = 105; +pub const SYS_rt_sigqueueinfo: ::c_long = 106; +pub const SYS_rt_sigsuspend: ::c_long = 107; +pub const SYS_setresuid: ::c_long = 108; +pub const SYS_getresuid: ::c_long = 109; +pub const SYS_setresgid: ::c_long = 110; +pub const SYS_getresgid: ::c_long = 111; +pub const SYS_recvmsg: ::c_long = 113; +pub const SYS_sendmsg: ::c_long = 114; +pub const SYS_gettimeofday: ::c_long = 116; +pub const SYS_getrusage: ::c_long = 117; +pub const SYS_getsockopt: ::c_long = 118; +pub const SYS_getcwd: ::c_long = 119; +pub const SYS_readv: ::c_long = 120; +pub const SYS_writev: ::c_long = 121; +pub const SYS_settimeofday: ::c_long = 122; +pub const SYS_fchown: ::c_long = 123; +pub const SYS_fchmod: ::c_long = 124; +pub const SYS_recvfrom: ::c_long = 125; +pub const SYS_setreuid: ::c_long = 126; +pub const SYS_setregid: ::c_long = 127; +pub const SYS_rename: ::c_long = 128; +pub const SYS_truncate: ::c_long = 129; +pub const SYS_ftruncate: ::c_long = 130; +pub const SYS_flock: ::c_long = 131; +pub const SYS_lstat64: ::c_long = 132; +pub const SYS_sendto: ::c_long = 133; +pub const SYS_shutdown: ::c_long = 134; +pub const SYS_socketpair: ::c_long = 135; +pub const SYS_mkdir: ::c_long = 136; +pub const SYS_rmdir: ::c_long = 137; +pub const SYS_utimes: ::c_long = 138; +pub const SYS_stat64: ::c_long = 139; +pub const SYS_sendfile64: ::c_long = 140; +pub const SYS_getpeername: ::c_long = 141; +pub const SYS_futex: ::c_long = 142; +pub const SYS_gettid: ::c_long = 143; +pub const SYS_getrlimit: ::c_long = 144; +pub const SYS_setrlimit: ::c_long = 145; +pub const SYS_pivot_root: ::c_long = 146; +pub const SYS_prctl: ::c_long = 147; +pub const SYS_pciconfig_read: ::c_long = 148; +pub const SYS_pciconfig_write: ::c_long = 149; +pub const SYS_getsockname: ::c_long = 150; +pub const SYS_inotify_init: ::c_long = 151; +pub const SYS_inotify_add_watch: ::c_long = 152; +pub const SYS_poll: ::c_long = 153; +pub const SYS_getdents64: ::c_long = 154; +pub const SYS_inotify_rm_watch: ::c_long = 156; +pub const SYS_statfs: ::c_long = 157; +pub const SYS_fstatfs: ::c_long = 158; +pub const SYS_umount: ::c_long = 159; +pub const SYS_sched_set_affinity: ::c_long = 160; +pub const SYS_sched_get_affinity: ::c_long = 161; +pub const SYS_getdomainname: ::c_long = 162; +pub const SYS_setdomainname: ::c_long = 163; +pub const SYS_utrap_install: ::c_long = 164; +pub const SYS_quotactl: ::c_long = 165; +pub const SYS_set_tid_address: ::c_long = 166; +pub const SYS_mount: ::c_long = 167; +pub const SYS_ustat: ::c_long = 168; +pub const SYS_setxattr: ::c_long = 169; +pub const SYS_lsetxattr: ::c_long = 170; +pub const SYS_fsetxattr: ::c_long = 171; +pub const SYS_getxattr: ::c_long = 172; +pub const SYS_lgetxattr: ::c_long = 173; +pub const SYS_getdents: ::c_long = 174; +pub const SYS_setsid: ::c_long = 175; +pub const SYS_fchdir: ::c_long = 176; +pub const SYS_fgetxattr: ::c_long = 177; +pub const SYS_listxattr: ::c_long = 178; +pub const SYS_llistxattr: ::c_long = 179; +pub const SYS_flistxattr: ::c_long = 180; +pub const SYS_removexattr: ::c_long = 181; +pub const SYS_lremovexattr: ::c_long = 182; +pub const SYS_sigpending: ::c_long = 183; +pub const SYS_query_module: ::c_long = 184; +pub const SYS_setpgid: ::c_long = 185; +pub const SYS_fremovexattr: ::c_long = 186; +pub const SYS_tkill: ::c_long = 187; +pub const SYS_exit_group: ::c_long = 188; +pub const SYS_uname: ::c_long = 189; +pub const SYS_init_module: ::c_long = 190; +pub const SYS_personality: ::c_long = 191; +pub const SYS_remap_file_pages: ::c_long = 192; +pub const SYS_epoll_create: ::c_long = 193; +pub const SYS_epoll_ctl: ::c_long = 194; +pub const SYS_epoll_wait: ::c_long = 195; +pub const SYS_ioprio_set: ::c_long = 196; +pub const SYS_getppid: ::c_long = 197; +pub const SYS_sigaction: ::c_long = 198; +pub const SYS_sgetmask: ::c_long = 199; +pub const SYS_ssetmask: ::c_long = 200; +pub const SYS_sigsuspend: ::c_long = 201; +pub const SYS_oldlstat: ::c_long = 202; +pub const SYS_uselib: ::c_long = 203; +pub const SYS_readdir: ::c_long = 204; +pub const SYS_readahead: ::c_long = 205; +pub const SYS_socketcall: ::c_long = 206; +pub const SYS_syslog: ::c_long = 207; +pub const SYS_lookup_dcookie: ::c_long = 208; +pub const SYS_fadvise64: ::c_long = 209; +pub const SYS_fadvise64_64: ::c_long = 210; +pub const SYS_tgkill: ::c_long = 211; +pub const SYS_waitpid: ::c_long = 212; +pub const SYS_swapoff: ::c_long = 213; +pub const SYS_sysinfo: ::c_long = 214; +pub const SYS_ipc: ::c_long = 215; +pub const SYS_sigreturn: ::c_long = 216; +pub const SYS_clone: ::c_long = 217; +pub const SYS_ioprio_get: ::c_long = 218; +pub const SYS_adjtimex: ::c_long = 219; +pub const SYS_sigprocmask: ::c_long = 220; +pub const SYS_create_module: ::c_long = 221; +pub const SYS_delete_module: ::c_long = 222; +pub const SYS_get_kernel_syms: ::c_long = 223; +pub const SYS_getpgid: ::c_long = 224; +pub const SYS_bdflush: ::c_long = 225; +pub const SYS_sysfs: ::c_long = 226; +pub const SYS_afs_syscall: ::c_long = 227; +pub const SYS_setfsuid: ::c_long = 228; +pub const SYS_setfsgid: ::c_long = 229; +pub const SYS__newselect: ::c_long = 230; +pub const SYS_splice: ::c_long = 232; +pub const SYS_stime: ::c_long = 233; +pub const SYS_statfs64: ::c_long = 234; +pub const SYS_fstatfs64: ::c_long = 235; +pub const SYS__llseek: ::c_long = 236; +pub const SYS_mlock: ::c_long = 237; +pub const SYS_munlock: ::c_long = 238; +pub const SYS_mlockall: ::c_long = 239; +pub const SYS_munlockall: ::c_long = 240; +pub const SYS_sched_setparam: ::c_long = 241; +pub const SYS_sched_getparam: ::c_long = 242; +pub const SYS_sched_setscheduler: ::c_long =243; +pub const SYS_sched_getscheduler: ::c_long =244; +pub const SYS_sched_yield: ::c_long = 245; +pub const SYS_sched_get_priority_max: ::c_long =246; +pub const SYS_sched_get_priority_min: ::c_long =247; +pub const SYS_sched_rr_get_interval: ::c_long = 248; +pub const SYS_nanosleep: ::c_long = 249; +pub const SYS_mremap: ::c_long = 250; +pub const SYS__sysctl: ::c_long = 251; +pub const SYS_getsid: ::c_long = 252; +pub const SYS_fdatasync: ::c_long = 253; +pub const SYS_nfsservctl: ::c_long = 254; +pub const SYS_sync_file_range: ::c_long = 255; +pub const SYS_clock_settime: ::c_long = 256; +pub const SYS_clock_gettime: ::c_long = 257; +pub const SYS_clock_getres: ::c_long = 258; +pub const SYS_clock_nanosleep: ::c_long = 259; +pub const SYS_sched_getaffinity: ::c_long = 260; +pub const SYS_sched_setaffinity: ::c_long = 261; +pub const SYS_timer_settime: ::c_long = 262; +pub const SYS_timer_gettime: ::c_long = 263; +pub const SYS_timer_getoverrun: ::c_long = 264; +pub const SYS_timer_delete: ::c_long = 265; +pub const SYS_timer_create: ::c_long = 266; +pub const SYS_io_setup: ::c_long = 268; +pub const SYS_io_destroy: ::c_long = 269; +pub const SYS_io_submit: ::c_long = 270; +pub const SYS_io_cancel: ::c_long = 271; +pub const SYS_io_getevents: ::c_long = 272; +pub const SYS_mq_open: ::c_long = 273; +pub const SYS_mq_unlink: ::c_long = 274; +pub const SYS_mq_timedsend: ::c_long = 275; +pub const SYS_mq_timedreceive: ::c_long = 276; +pub const SYS_mq_notify: ::c_long = 277; +pub const SYS_mq_getsetattr: ::c_long = 278; +pub const SYS_waitid: ::c_long = 279; +pub const SYS_tee: ::c_long = 280; +pub const SYS_add_key: ::c_long = 281; +pub const SYS_request_key: ::c_long = 282; +pub const SYS_keyctl: ::c_long = 283; +pub const SYS_openat: ::c_long = 284; +pub const SYS_mkdirat: ::c_long = 285; +pub const SYS_mknodat: ::c_long = 286; +pub const SYS_fchownat: ::c_long = 287; +pub const SYS_futimesat: ::c_long = 288; +pub const SYS_fstatat64: ::c_long = 289; +pub const SYS_unlinkat: ::c_long = 290; +pub const SYS_renameat: ::c_long = 291; +pub const SYS_linkat: ::c_long = 292; +pub const SYS_symlinkat: ::c_long = 293; +pub const SYS_readlinkat: ::c_long = 294; +pub const SYS_fchmodat: ::c_long = 295; +pub const SYS_faccessat: ::c_long = 296; +pub const SYS_pselect6: ::c_long = 297; +pub const SYS_ppoll: ::c_long = 298; +pub const SYS_unshare: ::c_long = 299; +pub const SYS_set_robust_list: ::c_long = 300; +pub const SYS_get_robust_list: ::c_long = 301; +pub const SYS_migrate_pages: ::c_long =302; +pub const SYS_mbind: ::c_long = 303; +pub const SYS_get_mempolicy: ::c_long = 304; +pub const SYS_set_mempolicy: ::c_long = 305; +pub const SYS_kexec_load: ::c_long = 306; +pub const SYS_move_pages: ::c_long = 307; +pub const SYS_getcpu: ::c_long = 308; +pub const SYS_epoll_pwait: ::c_long = 309; +pub const SYS_utimensat: ::c_long = 310; +pub const SYS_signalfd: ::c_long = 311; +pub const SYS_timerfd_create: ::c_long = 312; +pub const SYS_eventfd: ::c_long = 313; +pub const SYS_fallocate: ::c_long = 314; +pub const SYS_timerfd_settime: ::c_long = 315; +pub const SYS_timerfd_gettime: ::c_long = 316; +pub const SYS_signalfd4: ::c_long = 317; +pub const SYS_eventfd2: ::c_long = 318; +pub const SYS_epoll_create1: ::c_long = 319; +pub const SYS_dup3: ::c_long = 320; +pub const SYS_pipe2: ::c_long = 321; +pub const SYS_inotify_init1: ::c_long = 322; +pub const SYS_accept4: ::c_long = 323; +pub const SYS_preadv: ::c_long = 324; +pub const SYS_pwritev: ::c_long = 325; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 326; +pub const SYS_perf_event_open: ::c_long = 327; +pub const SYS_recvmmsg: ::c_long = 328; +pub const SYS_fanotify_init: ::c_long = 329; +pub const SYS_fanotify_mark: ::c_long = 330; +pub const SYS_prlimit64: ::c_long = 331; +pub const SYS_name_to_handle_at: ::c_long = 332; +pub const SYS_open_by_handle_at: ::c_long = 333; +pub const SYS_clock_adjtime: ::c_long = 334; +pub const SYS_syncfs: ::c_long = 335; +pub const SYS_sendmmsg: ::c_long = 336; +pub const SYS_setns: ::c_long = 337; +pub const SYS_process_vm_readv: ::c_long = 338; +pub const SYS_process_vm_writev: ::c_long = 339; +pub const SYS_kern_features: ::c_long = 340; +pub const SYS_kcmp: ::c_long = 341; +pub const SYS_finit_module: ::c_long = 342; +pub const SYS_sched_setattr: ::c_long = 343; +pub const SYS_sched_getattr: ::c_long = 344; +pub const SYS_renameat2: ::c_long = 345; +pub const SYS_seccomp: ::c_long = 346; +pub const SYS_getrandom: ::c_long = 347; +pub const SYS_memfd_create: ::c_long = 348; +pub const SYS_bpf: ::c_long = 349; +pub const SYS_execveat: ::c_long = 350; +pub const SYS_membarrier: ::c_long = 351; +pub const SYS_userfaultfd: ::c_long = 352; +pub const SYS_bind: ::c_long = 353; +pub const SYS_listen: ::c_long = 354; +pub const SYS_setsockopt: ::c_long = 355; +pub const SYS_mlock2: ::c_long = 356; +pub const SYS_copy_file_range: ::c_long = 357; +pub const SYS_preadv2: ::c_long = 358; +pub const SYS_pwritev2: ::c_long = 359; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/b64/x32.rs b/libc/src/unix/notbsd/linux/other/b64/x32.rs new file mode 100644 index 000000000..d88dbafed --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/x32.rs @@ -0,0 +1,374 @@ +use pthread_mutex_t; + +pub type c_long = i32; +pub type c_ulong = u32; + +s! { + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } +} + +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 44; + +align_const! { + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +// Syscall table + +pub const __X32_SYSCALL_BIT: ::c_long = 0x40000000; + +pub const SYS_read: ::c_long = __X32_SYSCALL_BIT + 0; +pub const SYS_write: ::c_long = __X32_SYSCALL_BIT + 1; +pub const SYS_open: ::c_long = __X32_SYSCALL_BIT + 2; +pub const SYS_close: ::c_long = __X32_SYSCALL_BIT + 3; +pub const SYS_stat: ::c_long = __X32_SYSCALL_BIT + 4; +pub const SYS_fstat: ::c_long = __X32_SYSCALL_BIT + 5; +pub const SYS_lstat: ::c_long = __X32_SYSCALL_BIT + 6; +pub const SYS_poll: ::c_long = __X32_SYSCALL_BIT + 7; +pub const SYS_lseek: ::c_long = __X32_SYSCALL_BIT + 8; +pub const SYS_mmap: ::c_long = __X32_SYSCALL_BIT + 9; +pub const SYS_mprotect: ::c_long = __X32_SYSCALL_BIT + 10; +pub const SYS_munmap: ::c_long = __X32_SYSCALL_BIT + 11; +pub const SYS_brk: ::c_long = __X32_SYSCALL_BIT + 12; +pub const SYS_rt_sigprocmask: ::c_long = __X32_SYSCALL_BIT + 14; +pub const SYS_pread64: ::c_long = __X32_SYSCALL_BIT + 17; +pub const SYS_pwrite64: ::c_long = __X32_SYSCALL_BIT + 18; +pub const SYS_access: ::c_long = __X32_SYSCALL_BIT + 21; +pub const SYS_pipe: ::c_long = __X32_SYSCALL_BIT + 22; +pub const SYS_select: ::c_long = __X32_SYSCALL_BIT + 23; +pub const SYS_sched_yield: ::c_long = __X32_SYSCALL_BIT + 24; +pub const SYS_mremap: ::c_long = __X32_SYSCALL_BIT + 25; +pub const SYS_msync: ::c_long = __X32_SYSCALL_BIT + 26; +pub const SYS_mincore: ::c_long = __X32_SYSCALL_BIT + 27; +pub const SYS_madvise: ::c_long = __X32_SYSCALL_BIT + 28; +pub const SYS_shmget: ::c_long = __X32_SYSCALL_BIT + 29; +pub const SYS_shmat: ::c_long = __X32_SYSCALL_BIT + 30; +pub const SYS_shmctl: ::c_long = __X32_SYSCALL_BIT + 31; +pub const SYS_dup: ::c_long = __X32_SYSCALL_BIT + 32; +pub const SYS_dup2: ::c_long = __X32_SYSCALL_BIT + 33; +pub const SYS_pause: ::c_long = __X32_SYSCALL_BIT + 34; +pub const SYS_nanosleep: ::c_long = __X32_SYSCALL_BIT + 35; +pub const SYS_getitimer: ::c_long = __X32_SYSCALL_BIT + 36; +pub const SYS_alarm: ::c_long = __X32_SYSCALL_BIT + 37; +pub const SYS_setitimer: ::c_long = __X32_SYSCALL_BIT + 38; +pub const SYS_getpid: ::c_long = __X32_SYSCALL_BIT + 39; +pub const SYS_sendfile: ::c_long = __X32_SYSCALL_BIT + 40; +pub const SYS_socket: ::c_long = __X32_SYSCALL_BIT + 41; +pub const SYS_connect: ::c_long = __X32_SYSCALL_BIT + 42; +pub const SYS_accept: ::c_long = __X32_SYSCALL_BIT + 43; +pub const SYS_sendto: ::c_long = __X32_SYSCALL_BIT + 44; +pub const SYS_shutdown: ::c_long = __X32_SYSCALL_BIT + 48; +pub const SYS_bind: ::c_long = __X32_SYSCALL_BIT + 49; +pub const SYS_listen: ::c_long = __X32_SYSCALL_BIT + 50; +pub const SYS_getsockname: ::c_long = __X32_SYSCALL_BIT + 51; +pub const SYS_getpeername: ::c_long = __X32_SYSCALL_BIT + 52; +pub const SYS_socketpair: ::c_long = __X32_SYSCALL_BIT + 53; +pub const SYS_clone: ::c_long = __X32_SYSCALL_BIT + 56; +pub const SYS_fork: ::c_long = __X32_SYSCALL_BIT + 57; +pub const SYS_vfork: ::c_long = __X32_SYSCALL_BIT + 58; +pub const SYS_exit: ::c_long = __X32_SYSCALL_BIT + 60; +pub const SYS_wait4: ::c_long = __X32_SYSCALL_BIT + 61; +pub const SYS_kill: ::c_long = __X32_SYSCALL_BIT + 62; +pub const SYS_uname: ::c_long = __X32_SYSCALL_BIT + 63; +pub const SYS_semget: ::c_long = __X32_SYSCALL_BIT + 64; +pub const SYS_semop: ::c_long = __X32_SYSCALL_BIT + 65; +pub const SYS_semctl: ::c_long = __X32_SYSCALL_BIT + 66; +pub const SYS_shmdt: ::c_long = __X32_SYSCALL_BIT + 67; +pub const SYS_msgget: ::c_long = __X32_SYSCALL_BIT + 68; +pub const SYS_msgsnd: ::c_long = __X32_SYSCALL_BIT + 69; +pub const SYS_msgrcv: ::c_long = __X32_SYSCALL_BIT + 70; +pub const SYS_msgctl: ::c_long = __X32_SYSCALL_BIT + 71; +pub const SYS_fcntl: ::c_long = __X32_SYSCALL_BIT + 72; +pub const SYS_flock: ::c_long = __X32_SYSCALL_BIT + 73; +pub const SYS_fsync: ::c_long = __X32_SYSCALL_BIT + 74; +pub const SYS_fdatasync: ::c_long = __X32_SYSCALL_BIT + 75; +pub const SYS_truncate: ::c_long = __X32_SYSCALL_BIT + 76; +pub const SYS_ftruncate: ::c_long = __X32_SYSCALL_BIT + 77; +pub const SYS_getdents: ::c_long = __X32_SYSCALL_BIT + 78; +pub const SYS_getcwd: ::c_long = __X32_SYSCALL_BIT + 79; +pub const SYS_chdir: ::c_long = __X32_SYSCALL_BIT + 80; +pub const SYS_fchdir: ::c_long = __X32_SYSCALL_BIT + 81; +pub const SYS_rename: ::c_long = __X32_SYSCALL_BIT + 82; +pub const SYS_mkdir: ::c_long = __X32_SYSCALL_BIT + 83; +pub const SYS_rmdir: ::c_long = __X32_SYSCALL_BIT + 84; +pub const SYS_creat: ::c_long = __X32_SYSCALL_BIT + 85; +pub const SYS_link: ::c_long = __X32_SYSCALL_BIT + 86; +pub const SYS_unlink: ::c_long = __X32_SYSCALL_BIT + 87; +pub const SYS_symlink: ::c_long = __X32_SYSCALL_BIT + 88; +pub const SYS_readlink: ::c_long = __X32_SYSCALL_BIT + 89; +pub const SYS_chmod: ::c_long = __X32_SYSCALL_BIT + 90; +pub const SYS_fchmod: ::c_long = __X32_SYSCALL_BIT + 91; +pub const SYS_chown: ::c_long = __X32_SYSCALL_BIT + 92; +pub const SYS_fchown: ::c_long = __X32_SYSCALL_BIT + 93; +pub const SYS_lchown: ::c_long = __X32_SYSCALL_BIT + 94; +pub const SYS_umask: ::c_long = __X32_SYSCALL_BIT + 95; +pub const SYS_gettimeofday: ::c_long = __X32_SYSCALL_BIT + 96; +pub const SYS_getrlimit: ::c_long = __X32_SYSCALL_BIT + 97; +pub const SYS_getrusage: ::c_long = __X32_SYSCALL_BIT + 98; +pub const SYS_sysinfo: ::c_long = __X32_SYSCALL_BIT + 99; +pub const SYS_times: ::c_long = __X32_SYSCALL_BIT + 100; +pub const SYS_getuid: ::c_long = __X32_SYSCALL_BIT + 102; +pub const SYS_syslog: ::c_long = __X32_SYSCALL_BIT + 103; +pub const SYS_getgid: ::c_long = __X32_SYSCALL_BIT + 104; +pub const SYS_setuid: ::c_long = __X32_SYSCALL_BIT + 105; +pub const SYS_setgid: ::c_long = __X32_SYSCALL_BIT + 106; +pub const SYS_geteuid: ::c_long = __X32_SYSCALL_BIT + 107; +pub const SYS_getegid: ::c_long = __X32_SYSCALL_BIT + 108; +pub const SYS_setpgid: ::c_long = __X32_SYSCALL_BIT + 109; +pub const SYS_getppid: ::c_long = __X32_SYSCALL_BIT + 110; +pub const SYS_getpgrp: ::c_long = __X32_SYSCALL_BIT + 111; +pub const SYS_setsid: ::c_long = __X32_SYSCALL_BIT + 112; +pub const SYS_setreuid: ::c_long = __X32_SYSCALL_BIT + 113; +pub const SYS_setregid: ::c_long = __X32_SYSCALL_BIT + 114; +pub const SYS_getgroups: ::c_long = __X32_SYSCALL_BIT + 115; +pub const SYS_setgroups: ::c_long = __X32_SYSCALL_BIT + 116; +pub const SYS_setresuid: ::c_long = __X32_SYSCALL_BIT + 117; +pub const SYS_getresuid: ::c_long = __X32_SYSCALL_BIT + 118; +pub const SYS_setresgid: ::c_long = __X32_SYSCALL_BIT + 119; +pub const SYS_getresgid: ::c_long = __X32_SYSCALL_BIT + 120; +pub const SYS_getpgid: ::c_long = __X32_SYSCALL_BIT + 121; +pub const SYS_setfsuid: ::c_long = __X32_SYSCALL_BIT + 122; +pub const SYS_setfsgid: ::c_long = __X32_SYSCALL_BIT + 123; +pub const SYS_getsid: ::c_long = __X32_SYSCALL_BIT + 124; +pub const SYS_capget: ::c_long = __X32_SYSCALL_BIT + 125; +pub const SYS_capset: ::c_long = __X32_SYSCALL_BIT + 126; +pub const SYS_rt_sigsuspend: ::c_long = __X32_SYSCALL_BIT + 130; +pub const SYS_utime: ::c_long = __X32_SYSCALL_BIT + 132; +pub const SYS_mknod: ::c_long = __X32_SYSCALL_BIT + 133; +pub const SYS_personality: ::c_long = __X32_SYSCALL_BIT + 135; +pub const SYS_ustat: ::c_long = __X32_SYSCALL_BIT + 136; +pub const SYS_statfs: ::c_long = __X32_SYSCALL_BIT + 137; +pub const SYS_fstatfs: ::c_long = __X32_SYSCALL_BIT + 138; +pub const SYS_sysfs: ::c_long = __X32_SYSCALL_BIT + 139; +pub const SYS_getpriority: ::c_long = __X32_SYSCALL_BIT + 140; +pub const SYS_setpriority: ::c_long = __X32_SYSCALL_BIT + 141; +pub const SYS_sched_setparam: ::c_long = __X32_SYSCALL_BIT + 142; +pub const SYS_sched_getparam: ::c_long = __X32_SYSCALL_BIT + 143; +pub const SYS_sched_setscheduler: ::c_long = __X32_SYSCALL_BIT + 144; +pub const SYS_sched_getscheduler: ::c_long = __X32_SYSCALL_BIT + 145; +pub const SYS_sched_get_priority_max: ::c_long = __X32_SYSCALL_BIT + 146; +pub const SYS_sched_get_priority_min: ::c_long = __X32_SYSCALL_BIT + 147; +pub const SYS_sched_rr_get_interval: ::c_long = __X32_SYSCALL_BIT + 148; +pub const SYS_mlock: ::c_long = __X32_SYSCALL_BIT + 149; +pub const SYS_munlock: ::c_long = __X32_SYSCALL_BIT + 150; +pub const SYS_mlockall: ::c_long = __X32_SYSCALL_BIT + 151; +pub const SYS_munlockall: ::c_long = __X32_SYSCALL_BIT + 152; +pub const SYS_vhangup: ::c_long = __X32_SYSCALL_BIT + 153; +pub const SYS_modify_ldt: ::c_long = __X32_SYSCALL_BIT + 154; +pub const SYS_pivot_root: ::c_long = __X32_SYSCALL_BIT + 155; +pub const SYS_prctl: ::c_long = __X32_SYSCALL_BIT + 157; +pub const SYS_arch_prctl: ::c_long = __X32_SYSCALL_BIT + 158; +pub const SYS_adjtimex: ::c_long = __X32_SYSCALL_BIT + 159; +pub const SYS_setrlimit: ::c_long = __X32_SYSCALL_BIT + 160; +pub const SYS_chroot: ::c_long = __X32_SYSCALL_BIT + 161; +pub const SYS_sync: ::c_long = __X32_SYSCALL_BIT + 162; +pub const SYS_acct: ::c_long = __X32_SYSCALL_BIT + 163; +pub const SYS_settimeofday: ::c_long = __X32_SYSCALL_BIT + 164; +pub const SYS_mount: ::c_long = __X32_SYSCALL_BIT + 165; +pub const SYS_umount2: ::c_long = __X32_SYSCALL_BIT + 166; +pub const SYS_swapon: ::c_long = __X32_SYSCALL_BIT + 167; +pub const SYS_swapoff: ::c_long = __X32_SYSCALL_BIT + 168; +pub const SYS_reboot: ::c_long = __X32_SYSCALL_BIT + 169; +pub const SYS_sethostname: ::c_long = __X32_SYSCALL_BIT + 170; +pub const SYS_setdomainname: ::c_long = __X32_SYSCALL_BIT + 171; +pub const SYS_iopl: ::c_long = __X32_SYSCALL_BIT + 172; +pub const SYS_ioperm: ::c_long = __X32_SYSCALL_BIT + 173; +pub const SYS_init_module: ::c_long = __X32_SYSCALL_BIT + 175; +pub const SYS_delete_module: ::c_long = __X32_SYSCALL_BIT + 176; +pub const SYS_quotactl: ::c_long = __X32_SYSCALL_BIT + 179; +pub const SYS_getpmsg: ::c_long = __X32_SYSCALL_BIT + 181; +pub const SYS_putpmsg: ::c_long = __X32_SYSCALL_BIT + 182; +pub const SYS_afs_syscall: ::c_long = __X32_SYSCALL_BIT + 183; +pub const SYS_tuxcall: ::c_long = __X32_SYSCALL_BIT + 184; +pub const SYS_security: ::c_long = __X32_SYSCALL_BIT + 185; +pub const SYS_gettid: ::c_long = __X32_SYSCALL_BIT + 186; +pub const SYS_readahead: ::c_long = __X32_SYSCALL_BIT + 187; +pub const SYS_setxattr: ::c_long = __X32_SYSCALL_BIT + 188; +pub const SYS_lsetxattr: ::c_long = __X32_SYSCALL_BIT + 189; +pub const SYS_fsetxattr: ::c_long = __X32_SYSCALL_BIT + 190; +pub const SYS_getxattr: ::c_long = __X32_SYSCALL_BIT + 191; +pub const SYS_lgetxattr: ::c_long = __X32_SYSCALL_BIT + 192; +pub const SYS_fgetxattr: ::c_long = __X32_SYSCALL_BIT + 193; +pub const SYS_listxattr: ::c_long = __X32_SYSCALL_BIT + 194; +pub const SYS_llistxattr: ::c_long = __X32_SYSCALL_BIT + 195; +pub const SYS_flistxattr: ::c_long = __X32_SYSCALL_BIT + 196; +pub const SYS_removexattr: ::c_long = __X32_SYSCALL_BIT + 197; +pub const SYS_lremovexattr: ::c_long = __X32_SYSCALL_BIT + 198; +pub const SYS_fremovexattr: ::c_long = __X32_SYSCALL_BIT + 199; +pub const SYS_tkill: ::c_long = __X32_SYSCALL_BIT + 200; +pub const SYS_time: ::c_long = __X32_SYSCALL_BIT + 201; +pub const SYS_futex: ::c_long = __X32_SYSCALL_BIT + 202; +pub const SYS_sched_setaffinity: ::c_long = __X32_SYSCALL_BIT + 203; +pub const SYS_sched_getaffinity: ::c_long = __X32_SYSCALL_BIT + 204; +pub const SYS_io_destroy: ::c_long = __X32_SYSCALL_BIT + 207; +pub const SYS_io_getevents: ::c_long = __X32_SYSCALL_BIT + 208; +pub const SYS_io_cancel: ::c_long = __X32_SYSCALL_BIT + 210; +pub const SYS_lookup_dcookie: ::c_long = __X32_SYSCALL_BIT + 212; +pub const SYS_epoll_create: ::c_long = __X32_SYSCALL_BIT + 213; +pub const SYS_remap_file_pages: ::c_long = __X32_SYSCALL_BIT + 216; +pub const SYS_getdents64: ::c_long = __X32_SYSCALL_BIT + 217; +pub const SYS_set_tid_address: ::c_long = __X32_SYSCALL_BIT + 218; +pub const SYS_restart_syscall: ::c_long = __X32_SYSCALL_BIT + 219; +pub const SYS_semtimedop: ::c_long = __X32_SYSCALL_BIT + 220; +pub const SYS_fadvise64: ::c_long = __X32_SYSCALL_BIT + 221; +pub const SYS_timer_settime: ::c_long = __X32_SYSCALL_BIT + 223; +pub const SYS_timer_gettime: ::c_long = __X32_SYSCALL_BIT + 224; +pub const SYS_timer_getoverrun: ::c_long = __X32_SYSCALL_BIT + 225; +pub const SYS_timer_delete: ::c_long = __X32_SYSCALL_BIT + 226; +pub const SYS_clock_settime: ::c_long = __X32_SYSCALL_BIT + 227; +pub const SYS_clock_gettime: ::c_long = __X32_SYSCALL_BIT + 228; +pub const SYS_clock_getres: ::c_long = __X32_SYSCALL_BIT + 229; +pub const SYS_clock_nanosleep: ::c_long = __X32_SYSCALL_BIT + 230; +pub const SYS_exit_group: ::c_long = __X32_SYSCALL_BIT + 231; +pub const SYS_epoll_wait: ::c_long = __X32_SYSCALL_BIT + 232; +pub const SYS_epoll_ctl: ::c_long = __X32_SYSCALL_BIT + 233; +pub const SYS_tgkill: ::c_long = __X32_SYSCALL_BIT + 234; +pub const SYS_utimes: ::c_long = __X32_SYSCALL_BIT + 235; +pub const SYS_mbind: ::c_long = __X32_SYSCALL_BIT + 237; +pub const SYS_set_mempolicy: ::c_long = __X32_SYSCALL_BIT + 238; +pub const SYS_get_mempolicy: ::c_long = __X32_SYSCALL_BIT + 239; +pub const SYS_mq_open: ::c_long = __X32_SYSCALL_BIT + 240; +pub const SYS_mq_unlink: ::c_long = __X32_SYSCALL_BIT + 241; +pub const SYS_mq_timedsend: ::c_long = __X32_SYSCALL_BIT + 242; +pub const SYS_mq_timedreceive: ::c_long = __X32_SYSCALL_BIT + 243; +pub const SYS_mq_getsetattr: ::c_long = __X32_SYSCALL_BIT + 245; +pub const SYS_add_key: ::c_long = __X32_SYSCALL_BIT + 248; +pub const SYS_request_key: ::c_long = __X32_SYSCALL_BIT + 249; +pub const SYS_keyctl: ::c_long = __X32_SYSCALL_BIT + 250; +pub const SYS_ioprio_set: ::c_long = __X32_SYSCALL_BIT + 251; +pub const SYS_ioprio_get: ::c_long = __X32_SYSCALL_BIT + 252; +pub const SYS_inotify_init: ::c_long = __X32_SYSCALL_BIT + 253; +pub const SYS_inotify_add_watch: ::c_long = __X32_SYSCALL_BIT + 254; +pub const SYS_inotify_rm_watch: ::c_long = __X32_SYSCALL_BIT + 255; +pub const SYS_migrate_pages: ::c_long = __X32_SYSCALL_BIT + 256; +pub const SYS_openat: ::c_long = __X32_SYSCALL_BIT + 257; +pub const SYS_mkdirat: ::c_long = __X32_SYSCALL_BIT + 258; +pub const SYS_mknodat: ::c_long = __X32_SYSCALL_BIT + 259; +pub const SYS_fchownat: ::c_long = __X32_SYSCALL_BIT + 260; +pub const SYS_futimesat: ::c_long = __X32_SYSCALL_BIT + 261; +pub const SYS_newfstatat: ::c_long = __X32_SYSCALL_BIT + 262; +pub const SYS_unlinkat: ::c_long = __X32_SYSCALL_BIT + 263; +pub const SYS_renameat: ::c_long = __X32_SYSCALL_BIT + 264; +pub const SYS_linkat: ::c_long = __X32_SYSCALL_BIT + 265; +pub const SYS_symlinkat: ::c_long = __X32_SYSCALL_BIT + 266; +pub const SYS_readlinkat: ::c_long = __X32_SYSCALL_BIT + 267; +pub const SYS_fchmodat: ::c_long = __X32_SYSCALL_BIT + 268; +pub const SYS_faccessat: ::c_long = __X32_SYSCALL_BIT + 269; +pub const SYS_pselect6: ::c_long = __X32_SYSCALL_BIT + 270; +pub const SYS_ppoll: ::c_long = __X32_SYSCALL_BIT + 271; +pub const SYS_unshare: ::c_long = __X32_SYSCALL_BIT + 272; +pub const SYS_splice: ::c_long = __X32_SYSCALL_BIT + 275; +pub const SYS_tee: ::c_long = __X32_SYSCALL_BIT + 276; +pub const SYS_sync_file_range: ::c_long = __X32_SYSCALL_BIT + 277; +pub const SYS_utimensat: ::c_long = __X32_SYSCALL_BIT + 280; +pub const SYS_epoll_pwait: ::c_long = __X32_SYSCALL_BIT + 281; +pub const SYS_signalfd: ::c_long = __X32_SYSCALL_BIT + 282; +pub const SYS_timerfd_create: ::c_long = __X32_SYSCALL_BIT + 283; +pub const SYS_eventfd: ::c_long = __X32_SYSCALL_BIT + 284; +pub const SYS_fallocate: ::c_long = __X32_SYSCALL_BIT + 285; +pub const SYS_timerfd_settime: ::c_long = __X32_SYSCALL_BIT + 286; +pub const SYS_timerfd_gettime: ::c_long = __X32_SYSCALL_BIT + 287; +pub const SYS_accept4: ::c_long = __X32_SYSCALL_BIT + 288; +pub const SYS_signalfd4: ::c_long = __X32_SYSCALL_BIT + 289; +pub const SYS_eventfd2: ::c_long = __X32_SYSCALL_BIT + 290; +pub const SYS_epoll_create1: ::c_long = __X32_SYSCALL_BIT + 291; +pub const SYS_dup3: ::c_long = __X32_SYSCALL_BIT + 292; +pub const SYS_pipe2: ::c_long = __X32_SYSCALL_BIT + 293; +pub const SYS_inotify_init1: ::c_long = __X32_SYSCALL_BIT + 294; +pub const SYS_perf_event_open: ::c_long = __X32_SYSCALL_BIT + 298; +pub const SYS_fanotify_init: ::c_long = __X32_SYSCALL_BIT + 300; +pub const SYS_fanotify_mark: ::c_long = __X32_SYSCALL_BIT + 301; +pub const SYS_prlimit64: ::c_long = __X32_SYSCALL_BIT + 302; +pub const SYS_name_to_handle_at: ::c_long = __X32_SYSCALL_BIT + 303; +pub const SYS_open_by_handle_at: ::c_long = __X32_SYSCALL_BIT + 304; +pub const SYS_clock_adjtime: ::c_long = __X32_SYSCALL_BIT + 305; +pub const SYS_syncfs: ::c_long = __X32_SYSCALL_BIT + 306; +pub const SYS_setns: ::c_long = __X32_SYSCALL_BIT + 308; +pub const SYS_getcpu: ::c_long = __X32_SYSCALL_BIT + 309; +pub const SYS_kcmp: ::c_long = __X32_SYSCALL_BIT + 312; +pub const SYS_finit_module: ::c_long = __X32_SYSCALL_BIT + 313; +pub const SYS_sched_setattr: ::c_long = __X32_SYSCALL_BIT + 314; +pub const SYS_sched_getattr: ::c_long = __X32_SYSCALL_BIT + 315; +pub const SYS_renameat2: ::c_long = __X32_SYSCALL_BIT + 316; +pub const SYS_seccomp: ::c_long = __X32_SYSCALL_BIT + 317; +pub const SYS_getrandom: ::c_long = __X32_SYSCALL_BIT + 318; +pub const SYS_memfd_create: ::c_long = __X32_SYSCALL_BIT + 319; +pub const SYS_kexec_file_load: ::c_long = __X32_SYSCALL_BIT + 320; +pub const SYS_bpf: ::c_long = __X32_SYSCALL_BIT + 321; +pub const SYS_userfaultfd: ::c_long = __X32_SYSCALL_BIT + 323; +pub const SYS_membarrier: ::c_long = __X32_SYSCALL_BIT + 324; +pub const SYS_mlock2: ::c_long = __X32_SYSCALL_BIT + 325; +pub const SYS_copy_file_range: ::c_long = __X32_SYSCALL_BIT + 326; +pub const SYS_pkey_mprotect: ::c_long = __X32_SYSCALL_BIT + 329; +pub const SYS_pkey_alloc: ::c_long = __X32_SYSCALL_BIT + 330; +pub const SYS_pkey_free: ::c_long = __X32_SYSCALL_BIT + 331; +pub const SYS_rt_sigaction: ::c_long = __X32_SYSCALL_BIT + 512; +pub const SYS_rt_sigreturn: ::c_long = __X32_SYSCALL_BIT + 513; +pub const SYS_ioctl: ::c_long = __X32_SYSCALL_BIT + 514; +pub const SYS_readv: ::c_long = __X32_SYSCALL_BIT + 515; +pub const SYS_writev: ::c_long = __X32_SYSCALL_BIT + 516; +pub const SYS_recvfrom: ::c_long = __X32_SYSCALL_BIT + 517; +pub const SYS_sendmsg: ::c_long = __X32_SYSCALL_BIT + 518; +pub const SYS_recvmsg: ::c_long = __X32_SYSCALL_BIT + 519; +pub const SYS_execve: ::c_long = __X32_SYSCALL_BIT + 520; +pub const SYS_ptrace: ::c_long = __X32_SYSCALL_BIT + 521; +pub const SYS_rt_sigpending: ::c_long = __X32_SYSCALL_BIT + 522; +pub const SYS_rt_sigtimedwait: ::c_long = __X32_SYSCALL_BIT + 523; +pub const SYS_rt_sigqueueinfo: ::c_long = __X32_SYSCALL_BIT + 524; +pub const SYS_sigaltstack: ::c_long = __X32_SYSCALL_BIT + 525; +pub const SYS_timer_create: ::c_long = __X32_SYSCALL_BIT + 526; +pub const SYS_mq_notify: ::c_long = __X32_SYSCALL_BIT + 527; +pub const SYS_kexec_load: ::c_long = __X32_SYSCALL_BIT + 528; +pub const SYS_waitid: ::c_long = __X32_SYSCALL_BIT + 529; +pub const SYS_set_robust_list: ::c_long = __X32_SYSCALL_BIT + 530; +pub const SYS_get_robust_list: ::c_long = __X32_SYSCALL_BIT + 531; +pub const SYS_vmsplice: ::c_long = __X32_SYSCALL_BIT + 532; +pub const SYS_move_pages: ::c_long = __X32_SYSCALL_BIT + 533; +pub const SYS_preadv: ::c_long = __X32_SYSCALL_BIT + 534; +pub const SYS_pwritev: ::c_long = __X32_SYSCALL_BIT + 535; +pub const SYS_rt_tgsigqueueinfo: ::c_long = __X32_SYSCALL_BIT + 536; +pub const SYS_recvmmsg: ::c_long = __X32_SYSCALL_BIT + 537; +pub const SYS_sendmmsg: ::c_long = __X32_SYSCALL_BIT + 538; +pub const SYS_process_vm_readv: ::c_long = __X32_SYSCALL_BIT + 539; +pub const SYS_process_vm_writev: ::c_long = __X32_SYSCALL_BIT + 540; +pub const SYS_setsockopt: ::c_long = __X32_SYSCALL_BIT + 541; +pub const SYS_getsockopt: ::c_long = __X32_SYSCALL_BIT + 542; +pub const SYS_io_setup: ::c_long = __X32_SYSCALL_BIT + 543; +pub const SYS_io_submit: ::c_long = __X32_SYSCALL_BIT + 544; +pub const SYS_execveat: ::c_long = __X32_SYSCALL_BIT + 545; +pub const SYS_preadv2: ::c_long = __X32_SYSCALL_BIT + 546; +pub const SYS_pwritev2: ::c_long = __X32_SYSCALL_BIT + 547; diff --git a/libc/src/unix/notbsd/linux/other/b64/x86_64.rs b/libc/src/unix/notbsd/linux/other/b64/x86_64.rs new file mode 100644 index 000000000..79f27e083 --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/b64/x86_64.rs @@ -0,0 +1,781 @@ +//! x86_64-specific definitions for 64-bit linux-like values + +pub type c_char = i8; +pub type wchar_t = i32; +pub type nlink_t = u64; +pub type blksize_t = i64; +pub type greg_t = i64; +pub type suseconds_t = i64; +pub type __u64 = ::c_ulonglong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: i64, + pub st_mtime: ::time_t, + pub st_mtime_nsec: i64, + pub st_ctime: ::time_t, + pub st_ctime_nsec: i64, + __unused: [i64; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + __pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: i64, + pub st_mtime: ::time_t, + pub st_mtime_nsec: i64, + pub st_ctime: ::time_t, + pub st_ctime_nsec: i64, + __reserved: [i64; 3], + } + + pub struct statfs64 { + pub f_type: ::__fsword_t, + pub f_bsize: ::__fsword_t, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::__fsword_t, + pub f_frsize: ::__fsword_t, + pub f_flags: ::__fsword_t, + pub f_spare: [::__fsword_t; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct pthread_attr_t { + #[cfg(target_pointer_width = "32")] + __size: [u32; 8], + #[cfg(target_pointer_width = "64")] + __size: [u64; 7] + } + + pub struct _libc_fpxreg { + pub significand: [u16; 4], + pub exponent: u16, + __private: [u16; 3], + } + + pub struct _libc_xmmreg { + pub element: [u32; 4], + } + + pub struct _libc_fpstate { + pub cwd: u16, + pub swd: u16, + pub ftw: u16, + pub fop: u16, + pub rip: u64, + pub rdp: u64, + pub mxcsr: u32, + pub mxcr_mask: u32, + pub _st: [_libc_fpxreg; 8], + pub _xmm: [_libc_xmmreg; 16], + __private: [u64; 12], + } + + pub struct user_regs_struct { + pub r15: ::c_ulonglong, + pub r14: ::c_ulonglong, + pub r13: ::c_ulonglong, + pub r12: ::c_ulonglong, + pub rbp: ::c_ulonglong, + pub rbx: ::c_ulonglong, + pub r11: ::c_ulonglong, + pub r10: ::c_ulonglong, + pub r9: ::c_ulonglong, + pub r8: ::c_ulonglong, + pub rax: ::c_ulonglong, + pub rcx: ::c_ulonglong, + pub rdx: ::c_ulonglong, + pub rsi: ::c_ulonglong, + pub rdi: ::c_ulonglong, + pub orig_rax: ::c_ulonglong, + pub rip: ::c_ulonglong, + pub cs: ::c_ulonglong, + pub eflags: ::c_ulonglong, + pub rsp: ::c_ulonglong, + pub ss: ::c_ulonglong, + pub fs_base: ::c_ulonglong, + pub gs_base: ::c_ulonglong, + pub ds: ::c_ulonglong, + pub es: ::c_ulonglong, + pub fs: ::c_ulonglong, + pub gs: ::c_ulonglong, + } + + pub struct user { + pub regs: user_regs_struct, + pub u_fpvalid: ::c_int, + pub i387: user_fpregs_struct, + pub u_tsize: ::c_ulonglong, + pub u_dsize: ::c_ulonglong, + pub u_ssize: ::c_ulonglong, + pub start_code: ::c_ulonglong, + pub start_stack: ::c_ulonglong, + pub signal: ::c_longlong, + __reserved: ::c_int, + #[cfg(target_pointer_width = "32")] + __pad1: u32, + pub u_ar0: *mut user_regs_struct, + #[cfg(target_pointer_width = "32")] + __pad2: u32, + pub u_fpstate: *mut user_fpregs_struct, + pub magic: ::c_ulonglong, + pub u_comm: [::c_char; 32], + pub u_debugreg: [::c_ulonglong; 8], + } + + pub struct mcontext_t { + pub gregs: [greg_t; 23], + pub fpregs: *mut _libc_fpstate, + __private: [u64; 8], + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_ushort, + __pad1: ::c_ushort, + pub __seq: ::c_ushort, + __pad2: ::c_ushort, + __unused1: u64, + __unused2: u64 + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: u64, + __unused5: u64 + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } +} + +s_no_extra_traits! { + pub struct user_fpregs_struct { + pub cwd: ::c_ushort, + pub swd: ::c_ushort, + pub ftw: ::c_ushort, + pub fop: ::c_ushort, + pub rip: ::c_ulonglong, + pub rdp: ::c_ulonglong, + pub mxcsr: ::c_uint, + pub mxcr_mask: ::c_uint, + pub st_space: [::c_uint; 32], + pub xmm_space: [::c_uint; 64], + padding: [::c_uint; 24], + } + + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + __private: [u8; 512], + __ssp: [::c_ulonglong; 4], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for user_fpregs_struct { + fn eq(&self, other: &user_fpregs_struct) -> bool { + self.cwd == other.cwd + && self.swd == other.swd + && self.ftw == other.ftw + && self.fop == other.fop + && self.rip == other.rip + && self.rdp == other.rdp + && self.mxcsr == other.mxcsr + && self.mxcr_mask == other.mxcr_mask + && self.st_space == other.st_space + && self + .xmm_space + .iter() + .zip(other.xmm_space.iter()) + .all(|(a,b)| a == b) + // Ignore padding field + } + } + + impl Eq for user_fpregs_struct {} + + impl ::fmt::Debug for user_fpregs_struct { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("user_fpregs_struct") + .field("cwd", &self.cwd) + .field("ftw", &self.ftw) + .field("fop", &self.fop) + .field("rip", &self.rip) + .field("rdp", &self.rdp) + .field("mxcsr", &self.mxcsr) + .field("mxcr_mask", &self.mxcr_mask) + .field("st_space", &self.st_space) + // FIXME: .field("xmm_space", &self.xmm_space) + // Ignore padding field + .finish() + } + } + + impl ::hash::Hash for user_fpregs_struct { + fn hash(&self, state: &mut H) { + self.cwd.hash(state); + self.ftw.hash(state); + self.fop.hash(state); + self.rip.hash(state); + self.rdp.hash(state); + self.mxcsr.hash(state); + self.mxcr_mask.hash(state); + self.st_space.hash(state); + self.xmm_space.hash(state); + // Ignore padding field + } + } + + impl PartialEq for ucontext_t { + fn eq(&self, other: &ucontext_t) -> bool { + self.uc_flags == other.uc_flags + && self.uc_link == other.uc_link + && self.uc_stack == other.uc_stack + && self.uc_mcontext == other.uc_mcontext + && self.uc_sigmask == other.uc_sigmask + // Ignore __private field + } + } + + impl Eq for ucontext_t {} + + impl ::fmt::Debug for ucontext_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("ucontext_t") + .field("uc_flags", &self.uc_flags) + .field("uc_link", &self.uc_link) + .field("uc_stack", &self.uc_stack) + .field("uc_mcontext", &self.uc_mcontext) + .field("uc_sigmask", &self.uc_sigmask) + // Ignore __private field + .finish() + } + } + + impl ::hash::Hash for ucontext_t { + fn hash(&self, state: &mut H) { + self.uc_flags.hash(state); + self.uc_link.hash(state); + self.uc_stack.hash(state); + self.uc_mcontext.hash(state); + self.uc_sigmask.hash(state); + // Ignore __private field + } + } + } +} + +pub const TIOCGSOFTCAR: ::c_ulong = 0x5419; +pub const TIOCSSOFTCAR: ::c_ulong = 0x541A; + +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 6; + +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NOCTTY: ::c_int = 256; +pub const O_NONBLOCK: ::c_int = 2048; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; +pub const O_FSYNC: ::c_int = 0x101000; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const MAP_GROWSDOWN: ::c_int = 0x0100; + +pub const EDEADLK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOSYS: ::c_int = 38; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EBADMSG: ::c_int = 74; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ENOTCONN: ::c_int = 107; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const EHWPOISON: ::c_int = 133; +pub const ERFKILL: ::c_int = 132; + +pub const SOL_SOCKET: ::c_int = 1; + +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_TYPE: ::c_int = 3; +pub const SO_ERROR: ::c_int = 4; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_SECURITY_AUTHENTICATION: ::c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: ::c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: ::c_int = 24; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_ATTACH_FILTER: ::c_int = 26; +pub const SO_DETACH_FILTER: ::c_int = 27; +pub const SO_GET_FILTER: ::c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: ::c_int = 28; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_PEERSEC: ::c_int = 31; +pub const SO_PASSSEC: ::c_int = 34; +pub const SO_TIMESTAMPNS: ::c_int = 35; +pub const SCM_TIMESTAMPNS: ::c_int = SO_TIMESTAMPNS; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_WIFI_STATUS: ::c_int = 41; +pub const SCM_WIFI_STATUS: ::c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_NOFCS: ::c_int = 43; +pub const SO_LOCK_FILTER: ::c_int = 44; +pub const SO_SELECT_ERR_QUEUE: ::c_int = 45; +pub const SO_BUSY_POLL: ::c_int = 46; +pub const SO_MAX_PACING_RATE: ::c_int = 47; +pub const SO_BPF_EXTENSIONS: ::c_int = 48; +pub const SO_INCOMING_CPU: ::c_int = 49; +pub const SO_ATTACH_BPF: ::c_int = 50; +pub const SO_DETACH_BPF: ::c_int = SO_DETACH_FILTER; + +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 0x00000004; +pub const SA_NOCLDWAIT: ::c_int = 0x00000002; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGBUS: ::c_int = 7; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; + +pub const PTRACE_DETACH: ::c_uint = 17; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; + +pub const SFD_NONBLOCK: ::c_int = 0x0800; + +pub const TIOCEXCL: ::c_ulong = 0x540C; +pub const TIOCNXCL: ::c_ulong = 0x540D; +pub const TIOCSCTTY: ::c_ulong = 0x540E; +pub const TIOCSTI: ::c_ulong = 0x5412; +pub const TIOCMGET: ::c_ulong = 0x5415; +pub const TIOCMBIS: ::c_ulong = 0x5416; +pub const TIOCMBIC: ::c_ulong = 0x5417; +pub const TIOCMSET: ::c_ulong = 0x5418; +pub const TIOCCONS: ::c_ulong = 0x541D; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; + +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_32BIT: ::c_int = 0x0040; + +pub const EDEADLOCK: ::c_int = 35; + +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FIONBIO: ::c_ulong = 0x5421; + +pub const PTRACE_GETFPREGS: ::c_uint = 14; +pub const PTRACE_SETFPREGS: ::c_uint = 15; +pub const PTRACE_GETFPXREGS: ::c_uint = 18; +pub const PTRACE_SETFPXREGS: ::c_uint = 19; +pub const PTRACE_GETREGS: ::c_uint = 12; +pub const PTRACE_SETREGS: ::c_uint = 13; +pub const PTRACE_PEEKSIGINFO_SHARED: ::c_uint = 1; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; +pub const CIBAUD: ::tcflag_t = 0o02003600000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const VSWTC: usize = 7; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; +pub const EXTPROC: ::tcflag_t = 0x00010000; +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCSETSW: ::c_ulong = 0x5403; +pub const TCSETSF: ::c_ulong = 0x5404; +pub const TCGETA: ::c_ulong = 0x5405; +pub const TCSETA: ::c_ulong = 0x5406; +pub const TCSETAW: ::c_ulong = 0x5407; +pub const TCSETAF: ::c_ulong = 0x5408; +pub const TCSBRK: ::c_ulong = 0x5409; +pub const TCXONC: ::c_ulong = 0x540A; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCINQ: ::c_ulong = 0x541B; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCOUTQ: ::c_ulong = 0x5411; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; +pub const FIONREAD: ::c_ulong = 0x541B; + +// offsets in user_regs_structs, from sys/reg.h +pub const R15: ::c_int = 0; +pub const R14: ::c_int = 1; +pub const R13: ::c_int = 2; +pub const R12: ::c_int = 3; +pub const RBP: ::c_int = 4; +pub const RBX: ::c_int = 5; +pub const R11: ::c_int = 6; +pub const R10: ::c_int = 7; +pub const R9: ::c_int = 8; +pub const R8: ::c_int = 9; +pub const RAX: ::c_int = 10; +pub const RCX: ::c_int = 11; +pub const RDX: ::c_int = 12; +pub const RSI: ::c_int = 13; +pub const RDI: ::c_int = 14; +pub const ORIG_RAX: ::c_int = 15; +pub const RIP: ::c_int = 16; +pub const CS: ::c_int = 17; +pub const EFLAGS: ::c_int = 18; +pub const RSP: ::c_int = 19; +pub const SS: ::c_int = 20; +pub const FS_BASE: ::c_int = 21; +pub const GS_BASE: ::c_int = 22; +pub const DS: ::c_int = 23; +pub const ES: ::c_int = 24; +pub const FS: ::c_int = 25; +pub const GS: ::c_int = 26; + +// offsets in mcontext_t.gregs from sys/ucontext.h +pub const REG_R8: ::c_int = 0; +pub const REG_R9: ::c_int = 1; +pub const REG_R10: ::c_int = 2; +pub const REG_R11: ::c_int = 3; +pub const REG_R12: ::c_int = 4; +pub const REG_R13: ::c_int = 5; +pub const REG_R14: ::c_int = 6; +pub const REG_R15: ::c_int = 7; +pub const REG_RDI: ::c_int = 8; +pub const REG_RSI: ::c_int = 9; +pub const REG_RBP: ::c_int = 10; +pub const REG_RBX: ::c_int = 11; +pub const REG_RDX: ::c_int = 12; +pub const REG_RAX: ::c_int = 13; +pub const REG_RCX: ::c_int = 14; +pub const REG_RSP: ::c_int = 15; +pub const REG_RIP: ::c_int = 16; +pub const REG_EFL: ::c_int = 17; +pub const REG_CSGSFS: ::c_int = 18; +pub const REG_ERR: ::c_int = 19; +pub const REG_TRAPNO: ::c_int = 20; +pub const REG_OLDMASK: ::c_int = 21; +pub const REG_CR2: ::c_int = 22; + +extern { + pub fn getcontext(ucp: *mut ucontext_t) -> ::c_int; + pub fn setcontext(ucp: *const ucontext_t) -> ::c_int; + pub fn makecontext(ucp: *mut ucontext_t, + func: extern fn (), + argc: ::c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, + ucp: *const ucontext_t) -> ::c_int; + pub fn iopl(level: ::c_int) -> ::c_int; + pub fn ioperm(from: ::c_ulong, num: ::c_ulong, + turn_on: ::c_int) -> ::c_int; +} diff --git a/libc/src/unix/notbsd/linux/other/mod.rs b/libc/src/unix/notbsd/linux/other/mod.rs new file mode 100644 index 000000000..1a97d1c8d --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/mod.rs @@ -0,0 +1,997 @@ +pub type __priority_which_t = ::c_uint; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __next_prio: *mut aiocb, + __abs_prio: ::c_int, + __policy: ::c_int, + __error_code: ::c_int, + __return_value: ::ssize_t, + pub aio_offset: off_t, + #[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))] + __unused1: [::c_char; 4], + __glibc_reserved: [::c_char; 32] + } + + pub struct __exit_status { + pub e_termination: ::c_short, + pub e_exit: ::c_short, + } + + pub struct __timeval { + pub tv_sec: ::int32_t, + pub tv_usec: ::int32_t, + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + pub sa_mask: ::sigset_t, + #[cfg(target_arch = "sparc64")] + __reserved0: ::c_int, + pub sa_flags: ::c_int, + pub sa_restorer: ::Option, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + #[deprecated( + since="0.2.54", + note="Please leave a comment on \ + https://github.com/rust-lang/libc/pull/1316 if you're using \ + this field" + )] + pub _pad: [::c_int; 29], + #[cfg(target_arch = "x86_64")] + _align: [u64; 0], + #[cfg(not(target_arch = "x86_64"))] + _align: [usize; 0], + } + + pub struct glob64_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut ::c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct statfs { + pub f_type: __fsword_t, + pub f_bsize: __fsword_t, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + + pub f_namelen: __fsword_t, + pub f_frsize: __fsword_t, + f_spare: [__fsword_t; 5], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + #[cfg(not(target_arch = "sparc64"))] + pub c_ispeed: ::speed_t, + #[cfg(not(target_arch = "sparc64"))] + pub c_ospeed: ::speed_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct mallinfo { + pub arena: ::c_int, + pub ordblks: ::c_int, + pub smblks: ::c_int, + pub hblks: ::c_int, + pub hblkhd: ::c_int, + pub usmblks: ::c_int, + pub fsmblks: ::c_int, + pub uordblks: ::c_int, + pub fordblks: ::c_int, + pub keepcost: ::c_int, + } + + pub struct nlmsghdr { + pub nlmsg_len: u32, + pub nlmsg_type: u16, + pub nlmsg_flags: u16, + pub nlmsg_seq: u32, + pub nlmsg_pid: u32, + } + + pub struct nlmsgerr { + pub error: ::c_int, + pub msg: nlmsghdr, + } + + pub struct nl_pktinfo { + pub group: u32, + } + + pub struct nl_mmap_req { + pub nm_block_size: ::c_uint, + pub nm_block_nr: ::c_uint, + pub nm_frame_size: ::c_uint, + pub nm_frame_nr: ::c_uint, + } + + pub struct nl_mmap_hdr { + pub nm_status: ::c_uint, + pub nm_len: ::c_uint, + pub nm_group: u32, + pub nm_pid: u32, + pub nm_uid: u32, + pub nm_gid: u32, + } + + pub struct nlattr { + pub nla_len: u16, + pub nla_type: u16, + } + + pub struct rtentry { + pub rt_pad1: ::c_ulong, + pub rt_dst: ::sockaddr, + pub rt_gateway: ::sockaddr, + pub rt_genmask: ::sockaddr, + pub rt_flags: ::c_ushort, + pub rt_pad2: ::c_short, + pub rt_pad3: ::c_ulong, + pub rt_tos: ::c_uchar, + pub rt_class: ::c_uchar, + #[cfg(target_pointer_width = "64")] + pub rt_pad4: [::c_short; 3usize], + #[cfg(not(target_pointer_width = "64"))] + pub rt_pad4: ::c_short, + pub rt_metric: ::c_short, + pub rt_dev: *mut ::c_char, + pub rt_mtu: ::c_ulong, + pub rt_window: ::c_ulong, + pub rt_irtt: ::c_ushort, + } +} + +impl siginfo_t { + pub unsafe fn si_addr(&self) -> *mut ::c_void { + #[repr(C)] + struct siginfo_sigfault { + _si_signo: ::c_int, + _si_errno: ::c_int, + _si_code: ::c_int, + si_addr: *mut ::c_void + } + (*(self as *const siginfo_t as *const siginfo_sigfault)).si_addr + } +} + +s_no_extra_traits! { + pub struct utmpx { + pub ut_type: ::c_short, + pub ut_pid: ::pid_t, + pub ut_line: [::c_char; __UT_LINESIZE], + pub ut_id: [::c_char; 4], + + pub ut_user: [::c_char; __UT_NAMESIZE], + pub ut_host: [::c_char; __UT_HOSTSIZE], + pub ut_exit: __exit_status, + + #[cfg(any(target_arch = "aarch64", + all(target_pointer_width = "32", + not(target_arch = "x86_64"))))] + pub ut_session: ::c_long, + #[cfg(any(target_arch = "aarch64", + all(target_pointer_width = "32", + not(target_arch = "x86_64"))))] + pub ut_tv: ::timeval, + + #[cfg(not(any(target_arch = "aarch64", + all(target_pointer_width = "32", + not(target_arch = "x86_64")))))] + pub ut_session: ::int32_t, + #[cfg(not(any(target_arch = "aarch64", + all(target_pointer_width = "32", + not(target_arch = "x86_64")))))] + pub ut_tv: __timeval, + + pub ut_addr_v6: [::int32_t; 4], + __glibc_reserved: [::c_char; 20], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for utmpx { + fn eq(&self, other: &utmpx) -> bool { + self.ut_type == other.ut_type + && self.ut_pid == other.ut_pid + && self.ut_line == other.ut_line + && self.ut_id == other.ut_id + && self.ut_user == other.ut_user + && self + .ut_host + .iter() + .zip(other.ut_host.iter()) + .all(|(a,b)| a == b) + && self.ut_exit == other.ut_exit + && self.ut_session == other.ut_session + && self.ut_tv == other.ut_tv + && self.ut_addr_v6 == other.ut_addr_v6 + && self.__glibc_reserved == other.__glibc_reserved + } + } + + impl Eq for utmpx {} + + impl ::fmt::Debug for utmpx { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utmpx") + .field("ut_type", &self.ut_type) + .field("ut_pid", &self.ut_pid) + .field("ut_line", &self.ut_line) + .field("ut_id", &self.ut_id) + .field("ut_user", &self.ut_user) + // FIXME: .field("ut_host", &self.ut_host) + .field("ut_exit", &self.ut_exit) + .field("ut_session", &self.ut_session) + .field("ut_tv", &self.ut_tv) + .field("ut_addr_v6", &self.ut_addr_v6) + .field("__glibc_reserved", &self.__glibc_reserved) + .finish() + } + } + + impl ::hash::Hash for utmpx { + fn hash(&self, state: &mut H) { + self.ut_type.hash(state); + self.ut_pid.hash(state); + self.ut_line.hash(state); + self.ut_id.hash(state); + self.ut_user.hash(state); + self.ut_host.hash(state); + self.ut_exit.hash(state); + self.ut_session.hash(state); + self.ut_tv.hash(state); + self.ut_addr_v6.hash(state); + self.__glibc_reserved.hash(state); + } + } + } +} + +pub const __UT_LINESIZE: usize = 32; +pub const __UT_NAMESIZE: usize = 32; +pub const __UT_HOSTSIZE: usize = 256; +pub const EMPTY: ::c_short = 0; +pub const RUN_LVL: ::c_short = 1; +pub const BOOT_TIME: ::c_short = 2; +pub const NEW_TIME: ::c_short = 3; +pub const OLD_TIME: ::c_short = 4; +pub const INIT_PROCESS: ::c_short = 5; +pub const LOGIN_PROCESS: ::c_short = 6; +pub const USER_PROCESS: ::c_short = 7; +pub const DEAD_PROCESS: ::c_short = 8; +pub const ACCOUNTING: ::c_short = 9; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_MEMLOCK: ::c_int = 8; +pub const RLIM_INFINITY: ::rlim_t = !0; +pub const RLIMIT_RTTIME: ::c_int = 15; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const SOCK_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const SOL_RXRPC: ::c_int = 272; +pub const SOL_PPPOL2TP: ::c_int = 273; +pub const SOL_PNPIPE: ::c_int = 275; +pub const SOL_RDS: ::c_int = 276; +pub const SOL_IUCV: ::c_int = 277; +pub const SOL_CAIF: ::c_int = 278; +pub const SOL_NFC: ::c_int = 280; +pub const SOL_XDP: ::c_int = 283; + +pub const MSG_TRYHARD: ::c_int = 4; + +pub const LC_PAPER: ::c_int = 7; +pub const LC_NAME: ::c_int = 8; +pub const LC_ADDRESS: ::c_int = 9; +pub const LC_TELEPHONE: ::c_int = 10; +pub const LC_MEASUREMENT: ::c_int = 11; +pub const LC_IDENTIFICATION: ::c_int = 12; +pub const LC_PAPER_MASK: ::c_int = (1 << LC_PAPER); +pub const LC_NAME_MASK: ::c_int = (1 << LC_NAME); +pub const LC_ADDRESS_MASK: ::c_int = (1 << LC_ADDRESS); +pub const LC_TELEPHONE_MASK: ::c_int = (1 << LC_TELEPHONE); +pub const LC_MEASUREMENT_MASK: ::c_int = (1 << LC_MEASUREMENT); +pub const LC_IDENTIFICATION_MASK: ::c_int = (1 << LC_IDENTIFICATION); +pub const LC_ALL_MASK: ::c_int = ::LC_CTYPE_MASK + | ::LC_NUMERIC_MASK + | ::LC_TIME_MASK + | ::LC_COLLATE_MASK + | ::LC_MONETARY_MASK + | ::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const MAP_ANON: ::c_int = 0x0020; +pub const MAP_ANONYMOUS: ::c_int = 0x0020; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; + +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_SEQPACKET: ::c_int = 5; +pub const SOCK_DCCP: ::c_int = 6; +pub const SOCK_PACKET: ::c_int = 10; + +pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16; +pub const TCP_THIN_DUPACK: ::c_int = 17; +pub const TCP_USER_TIMEOUT: ::c_int = 18; +pub const TCP_REPAIR: ::c_int = 19; +pub const TCP_REPAIR_QUEUE: ::c_int = 20; +pub const TCP_QUEUE_SEQ: ::c_int = 21; +pub const TCP_REPAIR_OPTIONS: ::c_int = 22; +pub const TCP_FASTOPEN: ::c_int = 23; +pub const TCP_TIMESTAMP: ::c_int = 24; + +/* DCCP socket options */ +pub const DCCP_SOCKOPT_PACKET_SIZE: ::c_int = 1; +pub const DCCP_SOCKOPT_SERVICE: ::c_int = 2; +pub const DCCP_SOCKOPT_CHANGE_L: ::c_int = 3; +pub const DCCP_SOCKOPT_CHANGE_R: ::c_int = 4; +pub const DCCP_SOCKOPT_GET_CUR_MPS: ::c_int = 5; +pub const DCCP_SOCKOPT_SERVER_TIMEWAIT: ::c_int = 6; +pub const DCCP_SOCKOPT_SEND_CSCOV: ::c_int = 10; +pub const DCCP_SOCKOPT_RECV_CSCOV: ::c_int = 11; +pub const DCCP_SOCKOPT_AVAILABLE_CCIDS: ::c_int = 12; +pub const DCCP_SOCKOPT_CCID: ::c_int = 13; +pub const DCCP_SOCKOPT_TX_CCID: ::c_int = 14; +pub const DCCP_SOCKOPT_RX_CCID: ::c_int = 15; +pub const DCCP_SOCKOPT_QPOLICY_ID: ::c_int = 16; +pub const DCCP_SOCKOPT_QPOLICY_TXQLEN: ::c_int = 17; +pub const DCCP_SOCKOPT_CCID_RX_INFO: ::c_int = 128; +pub const DCCP_SOCKOPT_CCID_TX_INFO: ::c_int = 192; + +/// maximum number of services provided on the same listening port +pub const DCCP_SERVICE_LIST_MAX_LEN: ::c_int = 32; + +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; + +pub const SIGEV_THREAD_ID: ::c_int = 4; + +pub const BUFSIZ: ::c_uint = 8192; +pub const TMP_MAX: ::c_uint = 238328; +pub const FOPEN_MAX: ::c_uint = 16; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; +pub const _SC_EQUIV_CLASS_MAX: ::c_int = 41; +pub const _SC_CHARCLASS_NAME_MAX: ::c_int = 45; +pub const _SC_PII: ::c_int = 53; +pub const _SC_PII_XTI: ::c_int = 54; +pub const _SC_PII_SOCKET: ::c_int = 55; +pub const _SC_PII_INTERNET: ::c_int = 56; +pub const _SC_PII_OSI: ::c_int = 57; +pub const _SC_POLL: ::c_int = 58; +pub const _SC_SELECT: ::c_int = 59; +pub const _SC_PII_INTERNET_STREAM: ::c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: ::c_int = 62; +pub const _SC_PII_OSI_COTS: ::c_int = 63; +pub const _SC_PII_OSI_CLTS: ::c_int = 64; +pub const _SC_PII_OSI_M: ::c_int = 65; +pub const _SC_T_IOV_MAX: ::c_int = 66; +pub const _SC_2_C_VERSION: ::c_int = 96; +pub const _SC_CHAR_BIT: ::c_int = 101; +pub const _SC_CHAR_MAX: ::c_int = 102; +pub const _SC_CHAR_MIN: ::c_int = 103; +pub const _SC_INT_MAX: ::c_int = 104; +pub const _SC_INT_MIN: ::c_int = 105; +pub const _SC_LONG_BIT: ::c_int = 106; +pub const _SC_WORD_BIT: ::c_int = 107; +pub const _SC_MB_LEN_MAX: ::c_int = 108; +pub const _SC_SSIZE_MAX: ::c_int = 110; +pub const _SC_SCHAR_MAX: ::c_int = 111; +pub const _SC_SCHAR_MIN: ::c_int = 112; +pub const _SC_SHRT_MAX: ::c_int = 113; +pub const _SC_SHRT_MIN: ::c_int = 114; +pub const _SC_UCHAR_MAX: ::c_int = 115; +pub const _SC_UINT_MAX: ::c_int = 116; +pub const _SC_ULONG_MAX: ::c_int = 117; +pub const _SC_USHRT_MAX: ::c_int = 118; +pub const _SC_NL_ARGMAX: ::c_int = 119; +pub const _SC_NL_LANGMAX: ::c_int = 120; +pub const _SC_NL_MSGMAX: ::c_int = 121; +pub const _SC_NL_NMAX: ::c_int = 122; +pub const _SC_NL_SETMAX: ::c_int = 123; +pub const _SC_NL_TEXTMAX: ::c_int = 124; +pub const _SC_BASE: ::c_int = 134; +pub const _SC_C_LANG_SUPPORT: ::c_int = 135; +pub const _SC_C_LANG_SUPPORT_R: ::c_int = 136; +pub const _SC_DEVICE_IO: ::c_int = 140; +pub const _SC_DEVICE_SPECIFIC: ::c_int = 141; +pub const _SC_DEVICE_SPECIFIC_R: ::c_int = 142; +pub const _SC_FD_MGMT: ::c_int = 143; +pub const _SC_FIFO: ::c_int = 144; +pub const _SC_PIPE: ::c_int = 145; +pub const _SC_FILE_ATTRIBUTES: ::c_int = 146; +pub const _SC_FILE_LOCKING: ::c_int = 147; +pub const _SC_FILE_SYSTEM: ::c_int = 148; +pub const _SC_MULTI_PROCESS: ::c_int = 150; +pub const _SC_SINGLE_PROCESS: ::c_int = 151; +pub const _SC_NETWORKING: ::c_int = 152; +pub const _SC_REGEX_VERSION: ::c_int = 156; +pub const _SC_SIGNALS: ::c_int = 158; +pub const _SC_SYSTEM_DATABASE: ::c_int = 162; +pub const _SC_SYSTEM_DATABASE_R: ::c_int = 163; +pub const _SC_USER_GROUPS: ::c_int = 166; +pub const _SC_USER_GROUPS_R: ::c_int = 167; +pub const _SC_LEVEL1_ICACHE_SIZE: ::c_int = 185; +pub const _SC_LEVEL1_ICACHE_ASSOC: ::c_int = 186; +pub const _SC_LEVEL1_ICACHE_LINESIZE: ::c_int = 187; +pub const _SC_LEVEL1_DCACHE_SIZE: ::c_int = 188; +pub const _SC_LEVEL1_DCACHE_ASSOC: ::c_int = 189; +pub const _SC_LEVEL1_DCACHE_LINESIZE: ::c_int = 190; +pub const _SC_LEVEL2_CACHE_SIZE: ::c_int = 191; +pub const _SC_LEVEL2_CACHE_ASSOC: ::c_int = 192; +pub const _SC_LEVEL2_CACHE_LINESIZE: ::c_int = 193; +pub const _SC_LEVEL3_CACHE_SIZE: ::c_int = 194; +pub const _SC_LEVEL3_CACHE_ASSOC: ::c_int = 195; +pub const _SC_LEVEL3_CACHE_LINESIZE: ::c_int = 196; +pub const _SC_LEVEL4_CACHE_SIZE: ::c_int = 197; +pub const _SC_LEVEL4_CACHE_ASSOC: ::c_int = 198; +pub const _SC_LEVEL4_CACHE_LINESIZE: ::c_int = 199; +pub const O_ACCMODE: ::c_int = 3; +pub const ST_RELATIME: ::c_ulong = 4096; +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const ADFS_SUPER_MAGIC: ::c_long = 0x0000adf5; +pub const AFFS_SUPER_MAGIC: ::c_long = 0x0000adff; +pub const CODA_SUPER_MAGIC: ::c_long = 0x73757245; +pub const CRAMFS_MAGIC: ::c_long = 0x28cd3d45; +pub const EFS_SUPER_MAGIC: ::c_long = 0x00414a53; +pub const EXT2_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT3_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT4_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const HPFS_SUPER_MAGIC: ::c_long = 0xf995e849; +pub const HUGETLBFS_MAGIC: ::c_long = 0x958458f6; +pub const ISOFS_SUPER_MAGIC: ::c_long = 0x00009660; +pub const JFFS2_SUPER_MAGIC: ::c_long = 0x000072b6; +pub const MINIX_SUPER_MAGIC: ::c_long = 0x0000137f; +pub const MINIX_SUPER_MAGIC2: ::c_long = 0x0000138f; +pub const MINIX2_SUPER_MAGIC: ::c_long = 0x00002468; +pub const MINIX2_SUPER_MAGIC2: ::c_long = 0x00002478; +pub const MSDOS_SUPER_MAGIC: ::c_long = 0x00004d44; +pub const NCP_SUPER_MAGIC: ::c_long = 0x0000564c; +pub const NFS_SUPER_MAGIC: ::c_long = 0x00006969; +pub const OPENPROM_SUPER_MAGIC: ::c_long = 0x00009fa1; +pub const PROC_SUPER_MAGIC: ::c_long = 0x00009fa0; +pub const QNX4_SUPER_MAGIC: ::c_long = 0x0000002f; +pub const REISERFS_SUPER_MAGIC: ::c_long = 0x52654973; +pub const SMB_SUPER_MAGIC: ::c_long = 0x0000517b; +pub const TMPFS_MAGIC: ::c_long = 0x01021994; +pub const USBDEVICE_SUPER_MAGIC: ::c_long = 0x00009fa2; + +pub const VEOF: usize = 4; + +pub const CPU_SETSIZE: ::c_int = 0x400; + +pub const PTRACE_TRACEME: ::c_uint = 0; +pub const PTRACE_PEEKTEXT: ::c_uint = 1; +pub const PTRACE_PEEKDATA: ::c_uint = 2; +pub const PTRACE_PEEKUSER: ::c_uint = 3; +pub const PTRACE_POKETEXT: ::c_uint = 4; +pub const PTRACE_POKEDATA: ::c_uint = 5; +pub const PTRACE_POKEUSER: ::c_uint = 6; +pub const PTRACE_CONT: ::c_uint = 7; +pub const PTRACE_KILL: ::c_uint = 8; +pub const PTRACE_SINGLESTEP: ::c_uint = 9; +pub const PTRACE_ATTACH: ::c_uint = 16; +pub const PTRACE_SYSCALL: ::c_uint = 24; +pub const PTRACE_SETOPTIONS: ::c_uint = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_uint = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_uint = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_uint = 0x4203; +pub const PTRACE_GETREGSET: ::c_uint = 0x4204; +pub const PTRACE_SETREGSET: ::c_uint = 0x4205; +pub const PTRACE_SEIZE: ::c_uint = 0x4206; +pub const PTRACE_INTERRUPT: ::c_uint = 0x4207; +pub const PTRACE_LISTEN: ::c_uint = 0x4208; +pub const PTRACE_PEEKSIGINFO: ::c_uint = 0x4209; + +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const SEEK_DATA: ::c_int = 3; +pub const SEEK_HOLE: ::c_int = 4; + +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; + +pub const TIOCLINUX: ::c_ulong = 0x541C; +pub const TIOCGSERIAL: ::c_ulong = 0x541E; + +pub const RTLD_DEEPBIND: ::c_int = 0x8; +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_NOLOAD: ::c_int = 0x4; + +pub const LINUX_REBOOT_MAGIC1: ::c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: ::c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: ::c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: ::c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: ::c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: ::c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: ::c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: ::c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: ::c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: ::c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543; + +pub const NETLINK_ROUTE: ::c_int = 0; +pub const NETLINK_UNUSED: ::c_int = 1; +pub const NETLINK_USERSOCK: ::c_int = 2; +pub const NETLINK_FIREWALL: ::c_int = 3; +pub const NETLINK_SOCK_DIAG: ::c_int = 4; +pub const NETLINK_NFLOG: ::c_int = 5; +pub const NETLINK_XFRM: ::c_int = 6; +pub const NETLINK_SELINUX: ::c_int = 7; +pub const NETLINK_ISCSI: ::c_int = 8; +pub const NETLINK_AUDIT: ::c_int = 9; +pub const NETLINK_FIB_LOOKUP: ::c_int = 10; +pub const NETLINK_CONNECTOR: ::c_int = 11; +pub const NETLINK_NETFILTER: ::c_int = 12; +pub const NETLINK_IP6_FW: ::c_int = 13; +pub const NETLINK_DNRTMSG: ::c_int = 14; +pub const NETLINK_KOBJECT_UEVENT: ::c_int = 15; +pub const NETLINK_GENERIC: ::c_int = 16; +pub const NETLINK_SCSITRANSPORT: ::c_int = 18; +pub const NETLINK_ECRYPTFS: ::c_int = 19; +pub const NETLINK_RDMA: ::c_int = 20; +pub const NETLINK_CRYPTO: ::c_int = 21; +pub const NETLINK_INET_DIAG: ::c_int = NETLINK_SOCK_DIAG; + +pub const MAX_LINKS: ::c_int = 32; + +pub const NLM_F_REQUEST: ::c_int = 1; +pub const NLM_F_MULTI: ::c_int = 2; +pub const NLM_F_ACK: ::c_int = 4; +pub const NLM_F_ECHO: ::c_int = 8; +pub const NLM_F_DUMP_INTR: ::c_int = 16; +pub const NLM_F_DUMP_FILTERED: ::c_int = 32; + +pub const NLM_F_ROOT: ::c_int = 0x100; +pub const NLM_F_MATCH: ::c_int = 0x200; +pub const NLM_F_ATOMIC: ::c_int = 0x400; +pub const NLM_F_DUMP: ::c_int = NLM_F_ROOT | NLM_F_MATCH; + +pub const NLM_F_REPLACE: ::c_int = 0x100; +pub const NLM_F_EXCL: ::c_int = 0x200; +pub const NLM_F_CREATE: ::c_int = 0x400; +pub const NLM_F_APPEND: ::c_int = 0x800; + +pub const NETLINK_ADD_MEMBERSHIP: ::c_int = 1; +pub const NETLINK_DROP_MEMBERSHIP: ::c_int = 2; +pub const NETLINK_PKTINFO: ::c_int = 3; +pub const NETLINK_BROADCAST_ERROR: ::c_int = 4; +pub const NETLINK_NO_ENOBUFS: ::c_int = 5; +pub const NETLINK_RX_RING: ::c_int = 6; +pub const NETLINK_TX_RING: ::c_int = 7; +pub const NETLINK_LISTEN_ALL_NSID: ::c_int = 8; +pub const NETLINK_LIST_MEMBERSHIPS: ::c_int = 9; +pub const NETLINK_CAP_ACK: ::c_int = 10; + +pub const NLA_F_NESTED: ::c_int = 1 << 15; +pub const NLA_F_NET_BYTEORDER: ::c_int = 1 << 14; +pub const NLA_TYPE_MASK: ::c_int = !(NLA_F_NESTED | NLA_F_NET_BYTEORDER); + +pub const NLA_ALIGNTO: ::c_int = 4; + +pub const GENL_UNS_ADMIN_PERM: ::c_int = 0x10; + +pub const GENL_ID_VFS_DQUOT: ::c_int = ::NLMSG_MIN_TYPE + 1; +pub const GENL_ID_PMCRAID: ::c_int = ::NLMSG_MIN_TYPE + 2; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +pub const NF_NETDEV_INGRESS: ::c_int = 0; +pub const NF_NETDEV_NUMHOOKS: ::c_int = 1; + +pub const NFPROTO_INET: ::c_int = 1; +pub const NFPROTO_NETDEV: ::c_int = 5; + +// linux/netfilter/nf_tables.h +pub const NFT_TABLE_MAXNAMELEN: ::c_int = 256; +pub const NFT_CHAIN_MAXNAMELEN: ::c_int = 256; +pub const NFT_SET_MAXNAMELEN: ::c_int = 256; +pub const NFT_OBJ_MAXNAMELEN: ::c_int = 256; +pub const NFT_USERDATA_MAXLEN: ::c_int = 256; + +pub const NFT_REG_VERDICT: ::c_int = 0; +pub const NFT_REG_1: ::c_int = 1; +pub const NFT_REG_2: ::c_int = 2; +pub const NFT_REG_3: ::c_int = 3; +pub const NFT_REG_4: ::c_int = 4; +pub const __NFT_REG_MAX: ::c_int = 5; +pub const NFT_REG32_00: ::c_int = 8; +pub const NFT_REG32_01: ::c_int = 9; +pub const NFT_REG32_02: ::c_int = 10; +pub const NFT_REG32_03: ::c_int = 11; +pub const NFT_REG32_04: ::c_int = 12; +pub const NFT_REG32_05: ::c_int = 13; +pub const NFT_REG32_06: ::c_int = 14; +pub const NFT_REG32_07: ::c_int = 15; +pub const NFT_REG32_08: ::c_int = 16; +pub const NFT_REG32_09: ::c_int = 17; +pub const NFT_REG32_10: ::c_int = 18; +pub const NFT_REG32_11: ::c_int = 19; +pub const NFT_REG32_12: ::c_int = 20; +pub const NFT_REG32_13: ::c_int = 21; +pub const NFT_REG32_14: ::c_int = 22; +pub const NFT_REG32_15: ::c_int = 23; + +pub const NFT_REG_SIZE: ::c_int = 16; +pub const NFT_REG32_SIZE: ::c_int = 4; + +pub const NFT_CONTINUE: ::c_int = -1; +pub const NFT_BREAK: ::c_int = -2; +pub const NFT_JUMP: ::c_int = -3; +pub const NFT_GOTO: ::c_int = -4; +pub const NFT_RETURN: ::c_int = -5; + +pub const NFT_MSG_NEWTABLE: ::c_int = 0; +pub const NFT_MSG_GETTABLE: ::c_int = 1; +pub const NFT_MSG_DELTABLE: ::c_int = 2; +pub const NFT_MSG_NEWCHAIN: ::c_int = 3; +pub const NFT_MSG_GETCHAIN: ::c_int = 4; +pub const NFT_MSG_DELCHAIN: ::c_int = 5; +pub const NFT_MSG_NEWRULE: ::c_int = 6; +pub const NFT_MSG_GETRULE: ::c_int = 7; +pub const NFT_MSG_DELRULE: ::c_int = 8; +pub const NFT_MSG_NEWSET: ::c_int = 9; +pub const NFT_MSG_GETSET: ::c_int = 10; +pub const NFT_MSG_DELSET: ::c_int = 11; +pub const NFT_MSG_NEWSETELEM: ::c_int = 12; +pub const NFT_MSG_GETSETELEM: ::c_int = 13; +pub const NFT_MSG_DELSETELEM: ::c_int = 14; +pub const NFT_MSG_NEWGEN: ::c_int = 15; +pub const NFT_MSG_GETGEN: ::c_int = 16; +pub const NFT_MSG_TRACE: ::c_int = 17; +cfg_if! { + if #[cfg(not(target_arch = "sparc64"))] { + pub const NFT_MSG_NEWOBJ: ::c_int = 18; + pub const NFT_MSG_GETOBJ: ::c_int = 19; + pub const NFT_MSG_DELOBJ: ::c_int = 20; + pub const NFT_MSG_GETOBJ_RESET: ::c_int = 21; + } +} +pub const NFT_MSG_MAX: ::c_int = 25; + +pub const NFT_SET_ANONYMOUS: ::c_int = 0x1; +pub const NFT_SET_CONSTANT: ::c_int = 0x2; +pub const NFT_SET_INTERVAL: ::c_int = 0x4; +pub const NFT_SET_MAP: ::c_int = 0x8; +pub const NFT_SET_TIMEOUT: ::c_int = 0x10; +pub const NFT_SET_EVAL: ::c_int = 0x20; + +pub const NFT_SET_POL_PERFORMANCE: ::c_int = 0; +pub const NFT_SET_POL_MEMORY: ::c_int = 1; + +pub const NFT_SET_ELEM_INTERVAL_END: ::c_int = 0x1; + +pub const NFT_DATA_VALUE: ::c_uint = 0; +pub const NFT_DATA_VERDICT: ::c_uint = 0xffffff00; + +pub const NFT_DATA_RESERVED_MASK: ::c_uint = 0xffffff00; + +pub const NFT_DATA_VALUE_MAXLEN: ::c_int = 64; + +pub const NFT_BYTEORDER_NTOH: ::c_int = 0; +pub const NFT_BYTEORDER_HTON: ::c_int = 1; + +pub const NFT_CMP_EQ: ::c_int = 0; +pub const NFT_CMP_NEQ: ::c_int = 1; +pub const NFT_CMP_LT: ::c_int = 2; +pub const NFT_CMP_LTE: ::c_int = 3; +pub const NFT_CMP_GT: ::c_int = 4; +pub const NFT_CMP_GTE: ::c_int = 5; + +pub const NFT_RANGE_EQ: ::c_int = 0; +pub const NFT_RANGE_NEQ: ::c_int = 1; + +pub const NFT_LOOKUP_F_INV: ::c_int = (1 << 0); + +pub const NFT_DYNSET_OP_ADD: ::c_int = 0; +pub const NFT_DYNSET_OP_UPDATE: ::c_int = 1; + +pub const NFT_DYNSET_F_INV: ::c_int = (1 << 0); + +pub const NFT_PAYLOAD_LL_HEADER: ::c_int = 0; +pub const NFT_PAYLOAD_NETWORK_HEADER: ::c_int = 1; +pub const NFT_PAYLOAD_TRANSPORT_HEADER: ::c_int = 2; + +pub const NFT_PAYLOAD_CSUM_NONE: ::c_int = 0; +pub const NFT_PAYLOAD_CSUM_INET: ::c_int = 1; + +pub const NFT_META_LEN: ::c_int = 0; +pub const NFT_META_PROTOCOL: ::c_int = 1; +pub const NFT_META_PRIORITY: ::c_int = 2; +pub const NFT_META_MARK: ::c_int = 3; +pub const NFT_META_IIF: ::c_int = 4; +pub const NFT_META_OIF: ::c_int = 5; +pub const NFT_META_IIFNAME: ::c_int = 6; +pub const NFT_META_OIFNAME: ::c_int = 7; +pub const NFT_META_IIFTYPE: ::c_int = 8; +pub const NFT_META_OIFTYPE: ::c_int = 9; +pub const NFT_META_SKUID: ::c_int = 10; +pub const NFT_META_SKGID: ::c_int = 11; +pub const NFT_META_NFTRACE: ::c_int = 12; +pub const NFT_META_RTCLASSID: ::c_int = 13; +pub const NFT_META_SECMARK: ::c_int = 14; +pub const NFT_META_NFPROTO: ::c_int = 15; +pub const NFT_META_L4PROTO: ::c_int = 16; +pub const NFT_META_BRI_IIFNAME: ::c_int = 17; +pub const NFT_META_BRI_OIFNAME: ::c_int = 18; +pub const NFT_META_PKTTYPE: ::c_int = 19; +pub const NFT_META_CPU: ::c_int = 20; +pub const NFT_META_IIFGROUP: ::c_int = 21; +pub const NFT_META_OIFGROUP: ::c_int = 22; +pub const NFT_META_CGROUP: ::c_int = 23; +pub const NFT_META_PRANDOM: ::c_int = 24; + +pub const NFT_CT_STATE: ::c_int = 0; +pub const NFT_CT_DIRECTION: ::c_int = 1; +pub const NFT_CT_STATUS: ::c_int = 2; +pub const NFT_CT_MARK: ::c_int = 3; +pub const NFT_CT_SECMARK: ::c_int = 4; +pub const NFT_CT_EXPIRATION: ::c_int = 5; +pub const NFT_CT_HELPER: ::c_int = 6; +pub const NFT_CT_L3PROTOCOL: ::c_int = 7; +pub const NFT_CT_SRC: ::c_int = 8; +pub const NFT_CT_DST: ::c_int = 9; +pub const NFT_CT_PROTOCOL: ::c_int = 10; +pub const NFT_CT_PROTO_SRC: ::c_int = 11; +pub const NFT_CT_PROTO_DST: ::c_int = 12; +pub const NFT_CT_LABELS: ::c_int = 13; +pub const NFT_CT_PKTS: ::c_int = 14; +pub const NFT_CT_BYTES: ::c_int = 15; + +pub const NFT_LIMIT_PKTS: ::c_int = 0; +pub const NFT_LIMIT_PKT_BYTES: ::c_int = 1; + +pub const NFT_LIMIT_F_INV: ::c_int = (1 << 0); + +pub const NFT_QUEUE_FLAG_BYPASS: ::c_int = 0x01; +pub const NFT_QUEUE_FLAG_CPU_FANOUT: ::c_int = 0x02; +pub const NFT_QUEUE_FLAG_MASK: ::c_int = 0x03; + +pub const NFT_QUOTA_F_INV: ::c_int = (1 << 0); + +pub const NFT_REJECT_ICMP_UNREACH: ::c_int = 0; +pub const NFT_REJECT_TCP_RST: ::c_int = 1; +pub const NFT_REJECT_ICMPX_UNREACH: ::c_int = 2; + +pub const NFT_REJECT_ICMPX_NO_ROUTE: ::c_int = 0; +pub const NFT_REJECT_ICMPX_PORT_UNREACH: ::c_int = 1; +pub const NFT_REJECT_ICMPX_HOST_UNREACH: ::c_int = 2; +pub const NFT_REJECT_ICMPX_ADMIN_PROHIBITED: ::c_int = 3; + +pub const NFT_NAT_SNAT: ::c_int = 0; +pub const NFT_NAT_DNAT: ::c_int = 1; + +pub const NFT_TRACETYPE_UNSPEC: ::c_int = 0; +pub const NFT_TRACETYPE_POLICY: ::c_int = 1; +pub const NFT_TRACETYPE_RETURN: ::c_int = 2; +pub const NFT_TRACETYPE_RULE: ::c_int = 3; + +pub const NFT_NG_INCREMENTAL: ::c_int = 0; +pub const NFT_NG_RANDOM: ::c_int = 1; + +pub const M_MXFAST: ::c_int = 1; +pub const M_NLBLKS: ::c_int = 2; +pub const M_GRAIN: ::c_int = 3; +pub const M_KEEP: ::c_int = 4; +pub const M_TRIM_THRESHOLD: ::c_int = -1; +pub const M_TOP_PAD: ::c_int = -2; +pub const M_MMAP_THRESHOLD: ::c_int = -3; +pub const M_MMAP_MAX: ::c_int = -4; +pub const M_CHECK_ACTION: ::c_int = -5; +pub const M_PERTURB: ::c_int = -6; +pub const M_ARENA_TEST: ::c_int = -7; +pub const M_ARENA_MAX: ::c_int = -8; + +#[doc(hidden)] +pub const AF_MAX: ::c_int = 42; +#[doc(hidden)] +pub const PF_MAX: ::c_int = AF_MAX; + +cfg_if! { + if #[cfg(any(target_arch = "arm", target_arch = "x86", + target_arch = "x86_64"))] { + pub const PTHREAD_STACK_MIN: ::size_t = 16384; + } else if #[cfg(target_arch = "sparc64")] { + pub const PTHREAD_STACK_MIN: ::size_t = 0x6000; + } else { + pub const PTHREAD_STACK_MIN: ::size_t = 131072; + } +} +pub const PTHREAD_MUTEX_ADAPTIVE_NP: ::c_int = 3; + +f! { + pub fn NLA_ALIGN(len: ::c_int) -> ::c_int { + return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1) + } +} + +extern { + pub fn utmpxname(file: *const ::c_char) -> ::c_int; + pub fn getutxent() -> *mut utmpx; + pub fn getutxid(ut: *const utmpx) -> *mut utmpx; + pub fn getutxline(ut: *const utmpx) -> *mut utmpx; + pub fn pututxline(ut: *const utmpx) -> *mut utmpx; + pub fn setutxent(); + pub fn endutxent(); + pub fn getpt() -> ::c_int; + pub fn mallopt(param: ::c_int, value: ::c_int) -> ::c_int; +} + +#[link(name = "util")] +extern { + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn backtrace(buf: *mut *mut ::c_void, + sz: ::c_int) -> ::c_int; + pub fn glob64(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut glob64_t) -> ::c_int; + pub fn globfree64(pglob: *mut glob64_t); + pub fn ptrace(request: ::c_uint, ...) -> ::c_long; + pub fn pthread_attr_getaffinity_np(attr: *const ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_attr_setaffinity_np(attr: *mut ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn getpriority(which: ::__priority_which_t, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::__priority_which_t, who: ::id_t, + prio: ::c_int) -> ::c_int; + pub fn pthread_getaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_setaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn pthread_rwlockattr_getkind_np(attr: *const ::pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setkind_np(attr: *mut ::pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn sched_getcpu() -> ::c_int; + pub fn mallinfo() -> ::mallinfo; + pub fn malloc_usable_size(ptr: *mut ::c_void) -> ::size_t; + pub fn getauxval(type_: ::c_ulong) -> ::c_ulong; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwent_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwent_r")] + pub fn getpwent_r(pwd: *mut ::unix::notbsd::linux::passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::unix::notbsd + ::linux::passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getgrent_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrent_r")] + pub fn getgrent_r(grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "x86", + target_arch = "arm", + target_arch = "powerpc"))] { + mod b32; + pub use self::b32::*; + } else if #[cfg(any(target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64", + target_arch = "sparc64"))] { + mod b64; + pub use self::b64::*; + } else { + // Unknown target_arch + } +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/notbsd/linux/other/no_align.rs b/libc/src/unix/notbsd/linux/other/no_align.rs new file mode 100644 index 000000000..e32bf673d --- /dev/null +++ b/libc/src/unix/notbsd/linux/other/no_align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} diff --git a/libc/src/unix/notbsd/linux/s390x/align.rs b/libc/src/unix/notbsd/linux/s390x/align.rs new file mode 100644 index 000000000..21e21907d --- /dev/null +++ b/libc/src/unix/notbsd/linux/s390x/align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/notbsd/linux/s390x/mod.rs b/libc/src/unix/notbsd/linux/s390x/mod.rs new file mode 100644 index 000000000..d4cf95678 --- /dev/null +++ b/libc/src/unix/notbsd/linux/s390x/mod.rs @@ -0,0 +1,1360 @@ +use ::pthread_mutex_t; + +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type fsblkcnt_t = u64; +pub type fsfilcnt_t = u64; +pub type ino_t = u64; +pub type nlink_t = u64; +pub type off_t = i64; +pub type rlim_t = u64; +pub type suseconds_t = i64; +pub type time_t = i64; +pub type wchar_t = i32; +pub type greg_t = u64; +pub type clock_t = i64; +pub type shmatt_t = ::c_ulong; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type __fsword_t = ::c_long; +pub type __priority_which_t = ::c_uint; +pub type __u64 = u64; + +s! { + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __next_prio: *mut aiocb, + __abs_prio: ::c_int, + __policy: ::c_int, + __error_code: ::c_int, + __return_value: ::ssize_t, + pub aio_offset: off_t, + #[cfg(target_pointer_width = "32")] + __unused1: [::c_char; 4], + __glibc_reserved: [::c_char; 32] + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + st_pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + __glibc_reserved: [::c_long; 3], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + pub st_ino: ::ino64_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + st_pad0: ::c_int, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + __glibc_reserved: [::c_long; 3], + } + + pub struct pthread_attr_t { + __size: [::c_ulong; 7] + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + __glibc_reserved0: ::c_int, + pub sa_flags: ::c_int, + pub sa_restorer: ::Option, + pub sa_mask: sigset_t, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t, + } + + pub struct sigset_t { + __size: [::c_ulong; 16], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + _pad: ::c_int, + _pad2: [::c_long; 14], + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::mode_t, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct statfs { + pub f_type: ::c_uint, + pub f_bsize: ::c_uint, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_uint, + pub f_frsize: ::c_uint, + pub f_flags: ::c_uint, + f_spare: [::c_uint; 4], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct termios2 { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; 19], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } + + pub struct glob64_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut ::c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct __psw_t { + pub mask: u64, + pub addr: u64, + } + + pub struct fpregset_t { + pub fpc: u32, + __pad: u32, + pub fprs: [fpreg_t; 16], + } + + pub struct mcontext_t { + pub psw: __psw_t, + pub gregs: [u64; 16], + pub aregs: [u32; 16], + pub fpregs: fpregset_t, + } + + pub struct ucontext_t { + pub uc_flags: ::c_ulong, + pub uc_link: *mut ucontext_t, + pub uc_stack: ::stack_t, + pub uc_mcontext: mcontext_t, + pub uc_sigmask: ::sigset_t, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs64 { + pub f_type: ::c_uint, + pub f_bsize: ::c_uint, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_uint, + pub f_frsize: ::c_uint, + pub f_flags: ::c_uint, + pub f_spare: [::c_uint; 4], + } + + pub struct statvfs64 { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_favail: u64, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } +} + +s_no_extra_traits!{ + // FIXME: This is actually a union. + pub struct fpreg_t { + pub d: ::c_double, + // f: ::c_float, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for fpreg_t { + fn eq(&self, other: &fpreg_t) -> bool { + self.d == other.d + } + } + + impl Eq for fpreg_t {} + + impl ::fmt::Debug for fpreg_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("fpreg_t") + .field("d", &self.d) + .finish() + } + } + + impl ::hash::Hash for fpreg_t { + fn hash(&self, state: &mut H) { + let d: u64 = unsafe { ::mem::transmute(self.d) }; + d.hash(state); + } + } + } +} + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; +pub const O_LARGEFILE: ::c_int = 0; +pub const O_NOATIME: ::c_int = 0o1000000; +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_PATH: ::c_int = 0o10000000; +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const POSIX_FADV_DONTNEED: ::c_int = 6; +pub const POSIX_FADV_NOREUSE: ::c_int = 7; + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; + +align_const! { + pub const PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + pub const PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP: ::pthread_mutex_t = + pthread_mutex_t { + size: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; +} + +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNREFUSED: ::c_int = 111; +pub const ECONNRESET: ::c_int = 104; +pub const EDEADLK: ::c_int = 35; +pub const ENOSYS: ::c_int = 38; +pub const ENOTCONN: ::c_int = 107; +pub const ETIMEDOUT: ::c_int = 110; +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FIONBIO: ::c_ulong = 0x5421; +pub const MAP_ANON: ::c_int = 0x20; +pub const O_ACCMODE: ::c_int = 3; +pub const O_APPEND: ::c_int = 1024; +pub const O_CREAT: ::c_int = 64; +pub const O_EXCL: ::c_int = 128; +pub const O_NONBLOCK: ::c_int = 2048; +pub const PTHREAD_STACK_MIN: ::size_t = 16384; +pub const PTHREAD_MUTEX_ADAPTIVE_NP: ::c_int = 3; +pub const RLIM_INFINITY: ::rlim_t = 0xffffffffffffffff; +pub const SA_NOCLDWAIT: ::c_int = 2; +pub const SA_ONSTACK: ::c_int = 0x08000000; +pub const SA_SIGINFO: ::c_int = 4; +pub const SIGBUS: ::c_int = 7; +pub const SIGSTKSZ: ::size_t = 0x2000; +pub const MINSIGSTKSZ: ::size_t = 2048; +pub const SIG_SETMASK: ::c_int = 2; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOCK_STREAM: ::c_int = 1; +pub const SOL_SOCKET: ::c_int = 1; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_ERROR: ::c_int = 4; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SO_MARK: ::c_int = 36; +pub const SO_PROTOCOL: ::c_int = 38; +pub const SO_DOMAIN: ::c_int = 39; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_BUSY_POLL: ::c_int = 46; + +pub const RLIMIT_RSS: ::c_int = 5; +pub const RLIMIT_NOFILE: ::c_int = 7; +pub const RLIMIT_AS: ::c_int = 9; +pub const RLIMIT_NPROC: ::c_int = 6; +pub const RLIMIT_MEMLOCK: ::c_int = 8; +pub const RLIMIT_RTTIME: ::c_int = 15; +pub const RLIMIT_NLIMITS: ::c_int = 16; + +pub const O_NOCTTY: ::c_int = 256; +pub const O_SYNC: ::c_int = 1052672; +pub const O_RSYNC: ::c_int = 1052672; +pub const O_DSYNC: ::c_int = 4096; +pub const O_FSYNC: ::c_int = 0x101000; +pub const O_DIRECT: ::c_int = 0x4000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; + +pub const SOCK_NONBLOCK: ::c_int = O_NONBLOCK; + +pub const LC_PAPER: ::c_int = 7; +pub const LC_NAME: ::c_int = 8; +pub const LC_ADDRESS: ::c_int = 9; +pub const LC_TELEPHONE: ::c_int = 10; +pub const LC_MEASUREMENT: ::c_int = 11; +pub const LC_IDENTIFICATION: ::c_int = 12; +pub const LC_PAPER_MASK: ::c_int = (1 << LC_PAPER); +pub const LC_NAME_MASK: ::c_int = (1 << LC_NAME); +pub const LC_ADDRESS_MASK: ::c_int = (1 << LC_ADDRESS); +pub const LC_TELEPHONE_MASK: ::c_int = (1 << LC_TELEPHONE); +pub const LC_MEASUREMENT_MASK: ::c_int = (1 << LC_MEASUREMENT); +pub const LC_IDENTIFICATION_MASK: ::c_int = (1 << LC_IDENTIFICATION); +pub const LC_ALL_MASK: ::c_int = ::LC_CTYPE_MASK + | ::LC_NUMERIC_MASK + | ::LC_TIME_MASK + | ::LC_COLLATE_MASK + | ::LC_MONETARY_MASK + | ::LC_MESSAGES_MASK + | LC_PAPER_MASK + | LC_NAME_MASK + | LC_ADDRESS_MASK + | LC_TELEPHONE_MASK + | LC_MEASUREMENT_MASK + | LC_IDENTIFICATION_MASK; + +pub const MAP_ANONYMOUS: ::c_int = 0x0020; +pub const MAP_GROWSDOWN: ::c_int = 0x0100; +pub const MAP_DENYWRITE: ::c_int = 0x0800; +pub const MAP_EXECUTABLE: ::c_int = 0x01000; +pub const MAP_LOCKED: ::c_int = 0x02000; +pub const MAP_NORESERVE: ::c_int = 0x04000; +pub const MAP_POPULATE: ::c_int = 0x08000; +pub const MAP_NONBLOCK: ::c_int = 0x010000; +pub const MAP_STACK: ::c_int = 0x020000; + +pub const EDEADLOCK: ::c_int = 35; +pub const ENAMETOOLONG: ::c_int = 36; +pub const ENOLCK: ::c_int = 37; +pub const ENOTEMPTY: ::c_int = 39; +pub const ELOOP: ::c_int = 40; +pub const ENOMSG: ::c_int = 42; +pub const EIDRM: ::c_int = 43; +pub const ECHRNG: ::c_int = 44; +pub const EL2NSYNC: ::c_int = 45; +pub const EL3HLT: ::c_int = 46; +pub const EL3RST: ::c_int = 47; +pub const ELNRNG: ::c_int = 48; +pub const EUNATCH: ::c_int = 49; +pub const ENOCSI: ::c_int = 50; +pub const EL2HLT: ::c_int = 51; +pub const EBADE: ::c_int = 52; +pub const EBADR: ::c_int = 53; +pub const EXFULL: ::c_int = 54; +pub const ENOANO: ::c_int = 55; +pub const EBADRQC: ::c_int = 56; +pub const EBADSLT: ::c_int = 57; +pub const EMULTIHOP: ::c_int = 72; +pub const EOVERFLOW: ::c_int = 75; +pub const ENOTUNIQ: ::c_int = 76; +pub const EBADFD: ::c_int = 77; +pub const EBADMSG: ::c_int = 74; +pub const EREMCHG: ::c_int = 78; +pub const ELIBACC: ::c_int = 79; +pub const ELIBBAD: ::c_int = 80; +pub const ELIBSCN: ::c_int = 81; +pub const ELIBMAX: ::c_int = 82; +pub const ELIBEXEC: ::c_int = 83; +pub const EILSEQ: ::c_int = 84; +pub const ERESTART: ::c_int = 85; +pub const ESTRPIPE: ::c_int = 86; +pub const EUSERS: ::c_int = 87; +pub const ENOTSOCK: ::c_int = 88; +pub const EDESTADDRREQ: ::c_int = 89; +pub const EMSGSIZE: ::c_int = 90; +pub const EPROTOTYPE: ::c_int = 91; +pub const ENOPROTOOPT: ::c_int = 92; +pub const EPROTONOSUPPORT: ::c_int = 93; +pub const ESOCKTNOSUPPORT: ::c_int = 94; +pub const EOPNOTSUPP: ::c_int = 95; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 96; +pub const EAFNOSUPPORT: ::c_int = 97; +pub const ENETDOWN: ::c_int = 100; +pub const ENETUNREACH: ::c_int = 101; +pub const ENETRESET: ::c_int = 102; +pub const ENOBUFS: ::c_int = 105; +pub const EISCONN: ::c_int = 106; +pub const ESHUTDOWN: ::c_int = 108; +pub const ETOOMANYREFS: ::c_int = 109; +pub const EHOSTDOWN: ::c_int = 112; +pub const EHOSTUNREACH: ::c_int = 113; +pub const EALREADY: ::c_int = 114; +pub const EINPROGRESS: ::c_int = 115; +pub const ESTALE: ::c_int = 116; +pub const EUCLEAN: ::c_int = 117; +pub const ENOTNAM: ::c_int = 118; +pub const ENAVAIL: ::c_int = 119; +pub const EISNAM: ::c_int = 120; +pub const EREMOTEIO: ::c_int = 121; +pub const EDQUOT: ::c_int = 122; +pub const ENOMEDIUM: ::c_int = 123; +pub const EMEDIUMTYPE: ::c_int = 124; +pub const ECANCELED: ::c_int = 125; +pub const ENOKEY: ::c_int = 126; +pub const EKEYEXPIRED: ::c_int = 127; +pub const EKEYREVOKED: ::c_int = 128; +pub const EKEYREJECTED: ::c_int = 129; +pub const EOWNERDEAD: ::c_int = 130; +pub const ENOTRECOVERABLE: ::c_int = 131; +pub const EHWPOISON: ::c_int = 133; +pub const ERFKILL: ::c_int = 132; + +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SO_TYPE: ::c_int = 3; +pub const SO_DONTROUTE: ::c_int = 5; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_OOBINLINE: ::c_int = 10; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_LINGER: ::c_int = 13; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_PASSCRED: ::c_int = 16; +pub const SO_PEERCRED: ::c_int = 17; +pub const SO_RCVLOWAT: ::c_int = 18; +pub const SO_SNDLOWAT: ::c_int = 19; +pub const SO_ACCEPTCONN: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 32; +pub const SO_RCVBUFFORCE: ::c_int = 33; + +pub const TCP_COOKIE_TRANSACTIONS: ::c_int = 15; +pub const TCP_THIN_LINEAR_TIMEOUTS: ::c_int = 16; +pub const TCP_THIN_DUPACK: ::c_int = 17; +pub const TCP_USER_TIMEOUT: ::c_int = 18; +pub const TCP_REPAIR: ::c_int = 19; +pub const TCP_REPAIR_QUEUE: ::c_int = 20; +pub const TCP_QUEUE_SEQ: ::c_int = 21; +pub const TCP_REPAIR_OPTIONS: ::c_int = 22; +pub const TCP_FASTOPEN: ::c_int = 23; +pub const TCP_TIMESTAMP: ::c_int = 24; + +pub const SIGCHLD: ::c_int = 17; +pub const SIGUSR1: ::c_int = 10; +pub const SIGUSR2: ::c_int = 12; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGURG: ::c_int = 23; +pub const SIGIO: ::c_int = 29; +pub const SIGSYS: ::c_int = 31; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGUNUSED: ::c_int = 31; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGPOLL: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIG_BLOCK: ::c_int = 0x000000; +pub const SIG_UNBLOCK: ::c_int = 0x01; + +pub const BUFSIZ: ::c_uint = 8192; +pub const TMP_MAX: ::c_uint = 238328; +pub const FOPEN_MAX: ::c_uint = 16; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; +pub const _SC_EQUIV_CLASS_MAX: ::c_int = 41; +pub const _SC_CHARCLASS_NAME_MAX: ::c_int = 45; +pub const _SC_PII: ::c_int = 53; +pub const _SC_PII_XTI: ::c_int = 54; +pub const _SC_PII_SOCKET: ::c_int = 55; +pub const _SC_PII_INTERNET: ::c_int = 56; +pub const _SC_PII_OSI: ::c_int = 57; +pub const _SC_POLL: ::c_int = 58; +pub const _SC_SELECT: ::c_int = 59; +pub const _SC_PII_INTERNET_STREAM: ::c_int = 61; +pub const _SC_PII_INTERNET_DGRAM: ::c_int = 62; +pub const _SC_PII_OSI_COTS: ::c_int = 63; +pub const _SC_PII_OSI_CLTS: ::c_int = 64; +pub const _SC_PII_OSI_M: ::c_int = 65; +pub const _SC_T_IOV_MAX: ::c_int = 66; +pub const _SC_2_C_VERSION: ::c_int = 96; +pub const _SC_CHAR_BIT: ::c_int = 101; +pub const _SC_CHAR_MAX: ::c_int = 102; +pub const _SC_CHAR_MIN: ::c_int = 103; +pub const _SC_INT_MAX: ::c_int = 104; +pub const _SC_INT_MIN: ::c_int = 105; +pub const _SC_LONG_BIT: ::c_int = 106; +pub const _SC_WORD_BIT: ::c_int = 107; +pub const _SC_MB_LEN_MAX: ::c_int = 108; +pub const _SC_SSIZE_MAX: ::c_int = 110; +pub const _SC_SCHAR_MAX: ::c_int = 111; +pub const _SC_SCHAR_MIN: ::c_int = 112; +pub const _SC_SHRT_MAX: ::c_int = 113; +pub const _SC_SHRT_MIN: ::c_int = 114; +pub const _SC_UCHAR_MAX: ::c_int = 115; +pub const _SC_UINT_MAX: ::c_int = 116; +pub const _SC_ULONG_MAX: ::c_int = 117; +pub const _SC_USHRT_MAX: ::c_int = 118; +pub const _SC_NL_ARGMAX: ::c_int = 119; +pub const _SC_NL_LANGMAX: ::c_int = 120; +pub const _SC_NL_MSGMAX: ::c_int = 121; +pub const _SC_NL_NMAX: ::c_int = 122; +pub const _SC_NL_SETMAX: ::c_int = 123; +pub const _SC_NL_TEXTMAX: ::c_int = 124; +pub const _SC_BASE: ::c_int = 134; +pub const _SC_C_LANG_SUPPORT: ::c_int = 135; +pub const _SC_C_LANG_SUPPORT_R: ::c_int = 136; +pub const _SC_DEVICE_IO: ::c_int = 140; +pub const _SC_DEVICE_SPECIFIC: ::c_int = 141; +pub const _SC_DEVICE_SPECIFIC_R: ::c_int = 142; +pub const _SC_FD_MGMT: ::c_int = 143; +pub const _SC_FIFO: ::c_int = 144; +pub const _SC_PIPE: ::c_int = 145; +pub const _SC_FILE_ATTRIBUTES: ::c_int = 146; +pub const _SC_FILE_LOCKING: ::c_int = 147; +pub const _SC_FILE_SYSTEM: ::c_int = 148; +pub const _SC_MULTI_PROCESS: ::c_int = 150; +pub const _SC_SINGLE_PROCESS: ::c_int = 151; +pub const _SC_NETWORKING: ::c_int = 152; +pub const _SC_REGEX_VERSION: ::c_int = 156; +pub const _SC_SIGNALS: ::c_int = 158; +pub const _SC_SYSTEM_DATABASE: ::c_int = 162; +pub const _SC_SYSTEM_DATABASE_R: ::c_int = 163; +pub const _SC_USER_GROUPS: ::c_int = 166; +pub const _SC_USER_GROUPS_R: ::c_int = 167; +pub const _SC_LEVEL1_ICACHE_SIZE: ::c_int = 185; +pub const _SC_LEVEL1_ICACHE_ASSOC: ::c_int = 186; +pub const _SC_LEVEL1_ICACHE_LINESIZE: ::c_int = 187; +pub const _SC_LEVEL1_DCACHE_SIZE: ::c_int = 188; +pub const _SC_LEVEL1_DCACHE_ASSOC: ::c_int = 189; +pub const _SC_LEVEL1_DCACHE_LINESIZE: ::c_int = 190; +pub const _SC_LEVEL2_CACHE_SIZE: ::c_int = 191; +pub const _SC_LEVEL2_CACHE_ASSOC: ::c_int = 192; +pub const _SC_LEVEL2_CACHE_LINESIZE: ::c_int = 193; +pub const _SC_LEVEL3_CACHE_SIZE: ::c_int = 194; +pub const _SC_LEVEL3_CACHE_ASSOC: ::c_int = 195; +pub const _SC_LEVEL3_CACHE_LINESIZE: ::c_int = 196; +pub const _SC_LEVEL4_CACHE_SIZE: ::c_int = 197; +pub const _SC_LEVEL4_CACHE_ASSOC: ::c_int = 198; +pub const _SC_LEVEL4_CACHE_LINESIZE: ::c_int = 199; +pub const O_ASYNC: ::c_int = 0x2000; +pub const O_NDELAY: ::c_int = 0x800; +pub const ST_RELATIME: ::c_ulong = 4096; +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const ADFS_SUPER_MAGIC: ::c_int = 0x0000adf5; +pub const AFFS_SUPER_MAGIC: ::c_int = 0x0000adff; +pub const CODA_SUPER_MAGIC: ::c_int = 0x73757245; +pub const CRAMFS_MAGIC: ::c_int = 0x28cd3d45; +pub const EFS_SUPER_MAGIC: ::c_int = 0x00414a53; +pub const EXT2_SUPER_MAGIC: ::c_int = 0x0000ef53; +pub const EXT3_SUPER_MAGIC: ::c_int = 0x0000ef53; +pub const EXT4_SUPER_MAGIC: ::c_int = 0x0000ef53; +pub const HPFS_SUPER_MAGIC: ::c_int = 0xf995e849; +pub const HUGETLBFS_MAGIC: ::c_int = 0x958458f6; +pub const ISOFS_SUPER_MAGIC: ::c_int = 0x00009660; +pub const JFFS2_SUPER_MAGIC: ::c_int = 0x000072b6; +pub const MINIX_SUPER_MAGIC: ::c_int = 0x0000137f; +pub const MINIX_SUPER_MAGIC2: ::c_int = 0x0000138f; +pub const MINIX2_SUPER_MAGIC: ::c_int = 0x00002468; +pub const MINIX2_SUPER_MAGIC2: ::c_int = 0x00002478; +pub const MSDOS_SUPER_MAGIC: ::c_int = 0x00004d44; +pub const NCP_SUPER_MAGIC: ::c_int = 0x0000564c; +pub const NFS_SUPER_MAGIC: ::c_int = 0x00006969; +pub const OPENPROM_SUPER_MAGIC: ::c_int = 0x00009fa1; +pub const PROC_SUPER_MAGIC: ::c_int = 0x00009fa0; +pub const QNX4_SUPER_MAGIC: ::c_int = 0x0000002f; +pub const REISERFS_SUPER_MAGIC: ::c_int = 0x52654973; +pub const SMB_SUPER_MAGIC: ::c_int = 0x0000517b; +pub const TMPFS_MAGIC: ::c_int = 0x01021994; +pub const USBDEVICE_SUPER_MAGIC: ::c_int = 0x00009fa2; + +pub const VEOF: usize = 4; +pub const VEOL: usize = 11; +pub const VEOL2: usize = 16; +pub const VMIN: usize = 6; +pub const IEXTEN: ::tcflag_t = 0x00008000; +pub const TOSTOP: ::tcflag_t = 0x00000100; +pub const FLUSHO: ::tcflag_t = 0x00001000; + +pub const CPU_SETSIZE: ::c_int = 0x400; + +pub const EXTPROC: ::tcflag_t = 0x00010000; + +pub const PTRACE_TRACEME: ::c_uint = 0; +pub const PTRACE_PEEKTEXT: ::c_uint = 1; +pub const PTRACE_PEEKDATA: ::c_uint = 2; +pub const PTRACE_PEEKUSER: ::c_uint = 3; +pub const PTRACE_POKETEXT: ::c_uint = 4; +pub const PTRACE_POKEDATA: ::c_uint = 5; +pub const PTRACE_POKEUSER: ::c_uint = 6; +pub const PTRACE_CONT: ::c_uint = 7; +pub const PTRACE_KILL: ::c_uint = 8; +pub const PTRACE_SINGLESTEP: ::c_uint = 9; +pub const PTRACE_ATTACH: ::c_uint = 16; +pub const PTRACE_DETACH: ::c_uint = 17; +pub const PTRACE_SYSCALL: ::c_uint = 24; +pub const PTRACE_SETOPTIONS: ::c_uint = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_uint = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_uint = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_uint = 0x4203; +pub const PTRACE_GETREGSET: ::c_uint = 0x4204; +pub const PTRACE_SETREGSET: ::c_uint = 0x4205; +pub const PTRACE_SEIZE: ::c_uint = 0x4206; +pub const PTRACE_INTERRUPT: ::c_uint = 0x4207; +pub const PTRACE_LISTEN: ::c_uint = 0x4208; +pub const PTRACE_PEEKSIGINFO: ::c_uint = 0x4209; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const EPOLLWAKEUP: ::c_int = 0x20000000; + +pub const MAP_HUGETLB: ::c_int = 0x040000; + +pub const EFD_NONBLOCK: ::c_int = 0x800; + +pub const F_RDLCK: ::c_int = 0; +pub const F_WRLCK: ::c_int = 1; +pub const F_UNLCK: ::c_int = 2; +pub const F_GETLK: ::c_int = 5; +pub const F_GETOWN: ::c_int = 9; +pub const F_SETOWN: ::c_int = 8; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const SEEK_DATA: ::c_int = 3; +pub const SEEK_HOLE: ::c_int = 4; + +pub const SFD_NONBLOCK: ::c_int = 0x0800; + +pub const TCSANOW: ::c_int = 0; +pub const TCSADRAIN: ::c_int = 1; +pub const TCSAFLUSH: ::c_int = 2; + +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCSETSW: ::c_ulong = 0x5403; +pub const TCSETSF: ::c_ulong = 0x5404; +pub const TCGETA: ::c_ulong = 0x5405; +pub const TCSETA: ::c_ulong = 0x5406; +pub const TCSETAW: ::c_ulong = 0x5407; +pub const TCSETAF: ::c_ulong = 0x5408; +pub const TCSBRK: ::c_ulong = 0x5409; +pub const TCXONC: ::c_ulong = 0x540A; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCGSOFTCAR: ::c_ulong = 0x5419; +pub const TIOCSSOFTCAR: ::c_ulong = 0x541A; +pub const TIOCINQ: ::c_ulong = 0x541B; +pub const TIOCLINUX: ::c_ulong = 0x541C; +pub const TIOCGSERIAL: ::c_ulong = 0x541E; +pub const TIOCEXCL: ::c_ulong = 0x540C; +pub const TIOCNXCL: ::c_ulong = 0x540D; +pub const TIOCSCTTY: ::c_ulong = 0x540E; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCOUTQ: ::c_ulong = 0x5411; +pub const TIOCSTI: ::c_ulong = 0x5412; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; +pub const TIOCMGET: ::c_ulong = 0x5415; +pub const TIOCMBIS: ::c_ulong = 0x5416; +pub const TIOCMBIC: ::c_ulong = 0x5417; +pub const TIOCMSET: ::c_ulong = 0x5418; +pub const FIONREAD: ::c_ulong = 0x541B; +pub const TIOCCONS: ::c_ulong = 0x541D; + +pub const RTLD_DEEPBIND: ::c_int = 0x8; +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_NOLOAD: ::c_int = 0x4; + +pub const LINUX_REBOOT_MAGIC1: ::c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: ::c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: ::c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: ::c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: ::c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: ::c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: ::c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: ::c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: ::c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: ::c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543; + +pub const VTIME: usize = 5; +pub const VSWTC: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const OLCUC: ::tcflag_t = 0o000002; +pub const ONLCR: ::tcflag_t = 0o000004; +pub const NLDLY: ::tcflag_t = 0o000400; +pub const CRDLY: ::tcflag_t = 0o003000; +pub const CR1: ::tcflag_t = 0x00000200; +pub const CR2: ::tcflag_t = 0x00000400; +pub const CR3: ::tcflag_t = 0x00000600; +pub const TABDLY: ::tcflag_t = 0o014000; +pub const TAB1: ::tcflag_t = 0x00000800; +pub const TAB2: ::tcflag_t = 0x00001000; +pub const TAB3: ::tcflag_t = 0x00001800; +pub const BSDLY: ::tcflag_t = 0o020000; +pub const BS1: ::tcflag_t = 0x00002000; +pub const FFDLY: ::tcflag_t = 0o100000; +pub const FF1: ::tcflag_t = 0x00008000; +pub const VTDLY: ::tcflag_t = 0o040000; +pub const VT1: ::tcflag_t = 0x00004000; +pub const XTABS: ::tcflag_t = 0o014000; + +pub const TIOCM_LE: ::c_int = 0x001; +pub const TIOCM_DTR: ::c_int = 0x002; +pub const TIOCM_RTS: ::c_int = 0x004; +pub const TIOCM_ST: ::c_int = 0x008; +pub const TIOCM_SR: ::c_int = 0x010; +pub const TIOCM_CTS: ::c_int = 0x020; +pub const TIOCM_CAR: ::c_int = 0x040; +pub const TIOCM_RNG: ::c_int = 0x080; +pub const TIOCM_DSR: ::c_int = 0x100; +pub const TIOCM_CD: ::c_int = TIOCM_CAR; +pub const TIOCM_RI: ::c_int = TIOCM_RNG; + +pub const SIGEV_THREAD_ID: ::c_int = 4; + +pub const CBAUD: ::speed_t = 0o010017; +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const CSIZE: ::tcflag_t = 0o000060; +pub const CS6: ::tcflag_t = 0o000020; +pub const CS7: ::tcflag_t = 0o000040; +pub const CS8: ::tcflag_t = 0o000060; +pub const CSTOPB: ::tcflag_t = 0o000100; +pub const CREAD: ::tcflag_t = 0o000200; +pub const PARENB: ::tcflag_t = 0o000400; +pub const PARODD: ::tcflag_t = 0o001000; +pub const HUPCL: ::tcflag_t = 0o002000; +pub const CLOCAL: ::tcflag_t = 0o004000; +pub const CBAUDEX: ::tcflag_t = 0o010000; +pub const BOTHER: ::speed_t = 0o010000; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; +pub const CIBAUD: ::tcflag_t = 0o02003600000; + +pub const ISIG: ::tcflag_t = 0o000001; +pub const ICANON: ::tcflag_t = 0o000002; +pub const XCASE: ::tcflag_t = 0o000004; +pub const ECHOE: ::tcflag_t = 0o000020; +pub const ECHOK: ::tcflag_t = 0o000040; +pub const ECHONL: ::tcflag_t = 0o000100; +pub const NOFLSH: ::tcflag_t = 0o000200; +pub const ECHOCTL: ::tcflag_t = 0o001000; +pub const ECHOPRT: ::tcflag_t = 0o002000; +pub const ECHOKE: ::tcflag_t = 0o004000; +pub const PENDIN: ::tcflag_t = 0o040000; + +pub const POLLWRNORM: ::c_short = 0x100; +pub const POLLWRBAND: ::c_short = 0x200; + +pub const IXON: ::tcflag_t = 0o002000; +pub const IXOFF: ::tcflag_t = 0o010000; + +pub const SYS_exit: ::c_long = 1; +pub const SYS_fork: ::c_long = 2; +pub const SYS_read: ::c_long = 3; +pub const SYS_write: ::c_long = 4; +pub const SYS_open: ::c_long = 5; +pub const SYS_close: ::c_long = 6; +pub const SYS_restart_syscall: ::c_long = 7; +pub const SYS_creat: ::c_long = 8; +pub const SYS_link: ::c_long = 9; +pub const SYS_unlink: ::c_long = 10; +pub const SYS_execve: ::c_long = 11; +pub const SYS_chdir: ::c_long = 12; +pub const SYS_mknod: ::c_long = 14; +pub const SYS_chmod: ::c_long = 15; +pub const SYS_lseek: ::c_long = 19; +pub const SYS_getpid: ::c_long = 20; +pub const SYS_mount: ::c_long = 21; +pub const SYS_umount: ::c_long = 22; +pub const SYS_ptrace: ::c_long = 26; +pub const SYS_alarm: ::c_long = 27; +pub const SYS_pause: ::c_long = 29; +pub const SYS_utime: ::c_long = 30; +pub const SYS_access: ::c_long = 33; +pub const SYS_nice: ::c_long = 34; +pub const SYS_sync: ::c_long = 36; +pub const SYS_kill: ::c_long = 37; +pub const SYS_rename: ::c_long = 38; +pub const SYS_mkdir: ::c_long = 39; +pub const SYS_rmdir: ::c_long = 40; +pub const SYS_dup: ::c_long = 41; +pub const SYS_pipe: ::c_long = 42; +pub const SYS_times: ::c_long = 43; +pub const SYS_brk: ::c_long = 45; +pub const SYS_signal: ::c_long = 48; +pub const SYS_acct: ::c_long = 51; +pub const SYS_umount2: ::c_long = 52; +pub const SYS_ioctl: ::c_long = 54; +pub const SYS_fcntl: ::c_long = 55; +pub const SYS_setpgid: ::c_long = 57; +pub const SYS_umask: ::c_long = 60; +pub const SYS_chroot: ::c_long = 61; +pub const SYS_ustat: ::c_long = 62; +pub const SYS_dup2: ::c_long = 63; +pub const SYS_getppid: ::c_long = 64; +pub const SYS_getpgrp: ::c_long = 65; +pub const SYS_setsid: ::c_long = 66; +pub const SYS_sigaction: ::c_long = 67; +pub const SYS_sigsuspend: ::c_long = 72; +pub const SYS_sigpending: ::c_long = 73; +pub const SYS_sethostname: ::c_long = 74; +pub const SYS_setrlimit: ::c_long = 75; +pub const SYS_getrusage: ::c_long = 77; +pub const SYS_gettimeofday: ::c_long = 78; +pub const SYS_settimeofday: ::c_long = 79; +pub const SYS_symlink: ::c_long = 83; +pub const SYS_readlink: ::c_long = 85; +pub const SYS_uselib: ::c_long = 86; +pub const SYS_swapon: ::c_long = 87; +pub const SYS_reboot: ::c_long = 88; +pub const SYS_readdir: ::c_long = 89; +pub const SYS_mmap: ::c_long = 90; +pub const SYS_munmap: ::c_long = 91; +pub const SYS_truncate: ::c_long = 92; +pub const SYS_ftruncate: ::c_long = 93; +pub const SYS_fchmod: ::c_long = 94; +pub const SYS_getpriority: ::c_long = 96; +pub const SYS_setpriority: ::c_long = 97; +pub const SYS_statfs: ::c_long = 99; +pub const SYS_fstatfs: ::c_long = 100; +pub const SYS_socketcall: ::c_long = 102; +pub const SYS_syslog: ::c_long = 103; +pub const SYS_setitimer: ::c_long = 104; +pub const SYS_getitimer: ::c_long = 105; +pub const SYS_stat: ::c_long = 106; +pub const SYS_lstat: ::c_long = 107; +pub const SYS_fstat: ::c_long = 108; +pub const SYS_lookup_dcookie: ::c_long = 110; +pub const SYS_vhangup: ::c_long = 111; +pub const SYS_idle: ::c_long = 112; +pub const SYS_wait4: ::c_long = 114; +pub const SYS_swapoff: ::c_long = 115; +pub const SYS_sysinfo: ::c_long = 116; +pub const SYS_ipc: ::c_long = 117; +pub const SYS_fsync: ::c_long = 118; +pub const SYS_sigreturn: ::c_long = 119; +pub const SYS_clone: ::c_long = 120; +pub const SYS_setdomainname: ::c_long = 121; +pub const SYS_uname: ::c_long = 122; +pub const SYS_adjtimex: ::c_long = 124; +pub const SYS_mprotect: ::c_long = 125; +pub const SYS_sigprocmask: ::c_long = 126; +pub const SYS_create_module: ::c_long = 127; +pub const SYS_init_module: ::c_long = 128; +pub const SYS_delete_module: ::c_long = 129; +pub const SYS_get_kernel_syms: ::c_long = 130; +pub const SYS_quotactl: ::c_long = 131; +pub const SYS_getpgid: ::c_long = 132; +pub const SYS_fchdir: ::c_long = 133; +pub const SYS_bdflush: ::c_long = 134; +pub const SYS_sysfs: ::c_long = 135; +pub const SYS_personality: ::c_long = 136; +pub const SYS_afs_syscall: ::c_long = 137; /* Syscall for Andrew File System */ +pub const SYS_getdents: ::c_long = 141; +pub const SYS_flock: ::c_long = 143; +pub const SYS_msync: ::c_long = 144; +pub const SYS_readv: ::c_long = 145; +pub const SYS_writev: ::c_long = 146; +pub const SYS_getsid: ::c_long = 147; +pub const SYS_fdatasync: ::c_long = 148; +pub const SYS__sysctl: ::c_long = 149; +pub const SYS_mlock: ::c_long = 150; +pub const SYS_munlock: ::c_long = 151; +pub const SYS_mlockall: ::c_long = 152; +pub const SYS_munlockall: ::c_long = 153; +pub const SYS_sched_setparam: ::c_long = 154; +pub const SYS_sched_getparam: ::c_long = 155; +pub const SYS_sched_setscheduler: ::c_long = 156; +pub const SYS_sched_getscheduler: ::c_long = 157; +pub const SYS_sched_yield: ::c_long = 158; +pub const SYS_sched_get_priority_max: ::c_long = 159; +pub const SYS_sched_get_priority_min: ::c_long = 160; +pub const SYS_sched_rr_get_interval: ::c_long = 161; +pub const SYS_nanosleep: ::c_long = 162; +pub const SYS_mremap: ::c_long = 163; +pub const SYS_query_module: ::c_long = 167; +pub const SYS_poll: ::c_long = 168; +pub const SYS_nfsservctl: ::c_long = 169; +pub const SYS_prctl: ::c_long = 172; +pub const SYS_rt_sigreturn: ::c_long = 173; +pub const SYS_rt_sigaction: ::c_long = 174; +pub const SYS_rt_sigprocmask: ::c_long = 175; +pub const SYS_rt_sigpending: ::c_long = 176; +pub const SYS_rt_sigtimedwait: ::c_long = 177; +pub const SYS_rt_sigqueueinfo: ::c_long = 178; +pub const SYS_rt_sigsuspend: ::c_long = 179; +pub const SYS_pread64: ::c_long = 180; +pub const SYS_pwrite64: ::c_long = 181; +pub const SYS_getcwd: ::c_long = 183; +pub const SYS_capget: ::c_long = 184; +pub const SYS_capset: ::c_long = 185; +pub const SYS_sigaltstack: ::c_long = 186; +pub const SYS_sendfile: ::c_long = 187; +pub const SYS_getpmsg: ::c_long = 188; +pub const SYS_putpmsg: ::c_long = 189; +pub const SYS_vfork: ::c_long = 190; +pub const SYS_pivot_root: ::c_long = 217; +pub const SYS_mincore: ::c_long = 218; +pub const SYS_madvise: ::c_long = 219; +pub const SYS_getdents64: ::c_long = 220; +pub const SYS_readahead: ::c_long = 222; +pub const SYS_setxattr: ::c_long = 224; +pub const SYS_lsetxattr: ::c_long = 225; +pub const SYS_fsetxattr: ::c_long = 226; +pub const SYS_getxattr: ::c_long = 227; +pub const SYS_lgetxattr: ::c_long = 228; +pub const SYS_fgetxattr: ::c_long = 229; +pub const SYS_listxattr: ::c_long = 230; +pub const SYS_llistxattr: ::c_long = 231; +pub const SYS_flistxattr: ::c_long = 232; +pub const SYS_removexattr: ::c_long = 233; +pub const SYS_lremovexattr: ::c_long = 234; +pub const SYS_fremovexattr: ::c_long = 235; +pub const SYS_gettid: ::c_long = 236; +pub const SYS_tkill: ::c_long = 237; +pub const SYS_futex: ::c_long = 238; +pub const SYS_sched_setaffinity: ::c_long = 239; +pub const SYS_sched_getaffinity: ::c_long = 240; +pub const SYS_tgkill: ::c_long = 241; +pub const SYS_io_setup: ::c_long = 243; +pub const SYS_io_destroy: ::c_long = 244; +pub const SYS_io_getevents: ::c_long = 245; +pub const SYS_io_submit: ::c_long = 246; +pub const SYS_io_cancel: ::c_long = 247; +pub const SYS_exit_group: ::c_long = 248; +pub const SYS_epoll_create: ::c_long = 249; +pub const SYS_epoll_ctl: ::c_long = 250; +pub const SYS_epoll_wait: ::c_long = 251; +pub const SYS_set_tid_address: ::c_long = 252; +pub const SYS_fadvise64: ::c_long = 253; +pub const SYS_timer_create: ::c_long = 254; +pub const SYS_timer_settime: ::c_long = 255; +pub const SYS_timer_gettime: ::c_long = 256; +pub const SYS_timer_getoverrun: ::c_long = 257; +pub const SYS_timer_delete: ::c_long = 258; +pub const SYS_clock_settime: ::c_long = 259; +pub const SYS_clock_gettime: ::c_long = 260; +pub const SYS_clock_getres: ::c_long = 261; +pub const SYS_clock_nanosleep: ::c_long = 262; +pub const SYS_statfs64: ::c_long = 265; +pub const SYS_fstatfs64: ::c_long = 266; +pub const SYS_remap_file_pages: ::c_long = 267; +pub const SYS_mbind: ::c_long = 268; +pub const SYS_get_mempolicy: ::c_long = 269; +pub const SYS_set_mempolicy: ::c_long = 270; +pub const SYS_mq_open: ::c_long = 271; +pub const SYS_mq_unlink: ::c_long = 272; +pub const SYS_mq_timedsend: ::c_long = 273; +pub const SYS_mq_timedreceive: ::c_long = 274; +pub const SYS_mq_notify: ::c_long = 275; +pub const SYS_mq_getsetattr: ::c_long = 276; +pub const SYS_kexec_load: ::c_long = 277; +pub const SYS_add_key: ::c_long = 278; +pub const SYS_request_key: ::c_long = 279; +pub const SYS_keyctl: ::c_long = 280; +pub const SYS_waitid: ::c_long = 281; +pub const SYS_ioprio_set: ::c_long = 282; +pub const SYS_ioprio_get: ::c_long = 283; +pub const SYS_inotify_init: ::c_long = 284; +pub const SYS_inotify_add_watch: ::c_long = 285; +pub const SYS_inotify_rm_watch: ::c_long = 286; +pub const SYS_migrate_pages: ::c_long = 287; +pub const SYS_openat: ::c_long = 288; +pub const SYS_mkdirat: ::c_long = 289; +pub const SYS_mknodat: ::c_long = 290; +pub const SYS_fchownat: ::c_long = 291; +pub const SYS_futimesat: ::c_long = 292; +pub const SYS_unlinkat: ::c_long = 294; +pub const SYS_renameat: ::c_long = 295; +pub const SYS_linkat: ::c_long = 296; +pub const SYS_symlinkat: ::c_long = 297; +pub const SYS_readlinkat: ::c_long = 298; +pub const SYS_fchmodat: ::c_long = 299; +pub const SYS_faccessat: ::c_long = 300; +pub const SYS_pselect6: ::c_long = 301; +pub const SYS_ppoll: ::c_long = 302; +pub const SYS_unshare: ::c_long = 303; +pub const SYS_set_robust_list: ::c_long = 304; +pub const SYS_get_robust_list: ::c_long = 305; +pub const SYS_splice: ::c_long = 306; +pub const SYS_sync_file_range: ::c_long = 307; +pub const SYS_tee: ::c_long = 308; +pub const SYS_vmsplice: ::c_long = 309; +pub const SYS_move_pages: ::c_long = 310; +pub const SYS_getcpu: ::c_long = 311; +pub const SYS_epoll_pwait: ::c_long = 312; +pub const SYS_utimes: ::c_long = 313; +pub const SYS_fallocate: ::c_long = 314; +pub const SYS_utimensat: ::c_long = 315; +pub const SYS_signalfd: ::c_long = 316; +pub const SYS_timerfd: ::c_long = 317; +pub const SYS_eventfd: ::c_long = 318; +pub const SYS_timerfd_create: ::c_long = 319; +pub const SYS_timerfd_settime: ::c_long = 320; +pub const SYS_timerfd_gettime: ::c_long = 321; +pub const SYS_signalfd4: ::c_long = 322; +pub const SYS_eventfd2: ::c_long = 323; +pub const SYS_inotify_init1: ::c_long = 324; +pub const SYS_pipe2: ::c_long = 325; +pub const SYS_dup3: ::c_long = 326; +pub const SYS_epoll_create1: ::c_long = 327; +pub const SYS_preadv: ::c_long = 328; +pub const SYS_pwritev: ::c_long = 329; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 330; +pub const SYS_perf_event_open: ::c_long = 331; +pub const SYS_fanotify_init: ::c_long = 332; +pub const SYS_fanotify_mark: ::c_long = 333; +pub const SYS_prlimit64: ::c_long = 334; +pub const SYS_name_to_handle_at: ::c_long = 335; +pub const SYS_open_by_handle_at: ::c_long = 336; +pub const SYS_clock_adjtime: ::c_long = 337; +pub const SYS_syncfs: ::c_long = 338; +pub const SYS_setns: ::c_long = 339; +pub const SYS_process_vm_readv: ::c_long = 340; +pub const SYS_process_vm_writev: ::c_long = 341; +pub const SYS_s390_runtime_instr: ::c_long = 342; +pub const SYS_kcmp: ::c_long = 343; +pub const SYS_finit_module: ::c_long = 344; +pub const SYS_sched_setattr: ::c_long = 345; +pub const SYS_sched_getattr: ::c_long = 346; +pub const SYS_renameat2: ::c_long = 347; +pub const SYS_seccomp: ::c_long = 348; +pub const SYS_getrandom: ::c_long = 349; +pub const SYS_memfd_create: ::c_long = 350; +pub const SYS_bpf: ::c_long = 351; +pub const SYS_s390_pci_mmio_write: ::c_long = 352; +pub const SYS_s390_pci_mmio_read: ::c_long = 353; +pub const SYS_execveat: ::c_long = 354; +pub const SYS_userfaultfd: ::c_long = 355; +pub const SYS_membarrier: ::c_long = 356; +pub const SYS_recvmmsg: ::c_long = 357; +pub const SYS_sendmmsg: ::c_long = 358; +pub const SYS_socket: ::c_long = 359; +pub const SYS_socketpair: ::c_long = 360; +pub const SYS_bind: ::c_long = 361; +pub const SYS_connect: ::c_long = 362; +pub const SYS_listen: ::c_long = 363; +pub const SYS_accept4: ::c_long = 364; +pub const SYS_getsockopt: ::c_long = 365; +pub const SYS_setsockopt: ::c_long = 366; +pub const SYS_getsockname: ::c_long = 367; +pub const SYS_getpeername: ::c_long = 368; +pub const SYS_sendto: ::c_long = 369; +pub const SYS_sendmsg: ::c_long = 370; +pub const SYS_recvfrom: ::c_long = 371; +pub const SYS_recvmsg: ::c_long = 372; +pub const SYS_shutdown: ::c_long = 373; +pub const SYS_mlock2: ::c_long = 374; +pub const SYS_copy_file_range: ::c_long = 375; +pub const SYS_preadv2: ::c_long = 376; +pub const SYS_pwritev2: ::c_long = 377; +pub const SYS_lchown: ::c_long = 198; +pub const SYS_setuid: ::c_long = 213; +pub const SYS_getuid: ::c_long = 199; +pub const SYS_setgid: ::c_long = 214; +pub const SYS_getgid: ::c_long = 200; +pub const SYS_geteuid: ::c_long = 201; +pub const SYS_setreuid: ::c_long = 203; +pub const SYS_setregid: ::c_long = 204; +pub const SYS_getrlimit: ::c_long = 191; +pub const SYS_getgroups: ::c_long = 205; +pub const SYS_fchown: ::c_long = 207; +pub const SYS_setresuid: ::c_long = 208; +pub const SYS_setresgid: ::c_long = 210; +pub const SYS_getresgid: ::c_long = 211; +pub const SYS_select: ::c_long = 142; +pub const SYS_getegid: ::c_long = 202; +pub const SYS_setgroups: ::c_long = 206; +pub const SYS_getresuid: ::c_long = 209; +pub const SYS_chown: ::c_long = 212; +pub const SYS_setfsuid: ::c_long = 215; +pub const SYS_setfsgid: ::c_long = 216; +pub const SYS_newfstatat: ::c_long = 293; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn backtrace(buf: *mut *mut ::c_void, + sz: ::c_int) -> ::c_int; + pub fn glob64(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut glob64_t) -> ::c_int; + pub fn globfree64(pglob: *mut glob64_t); + pub fn ptrace(request: ::c_uint, ...) -> ::c_long; + pub fn pthread_attr_getaffinity_np(attr: *const ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_attr_setaffinity_np(attr: *mut ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn getpriority(which: ::__priority_which_t, who: ::id_t) -> ::c_int; + pub fn setpriority(which: ::__priority_which_t, who: ::id_t, + prio: ::c_int) -> ::c_int; + pub fn pthread_getaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_setaffinity_np(thread: ::pthread_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; + pub fn sched_getcpu() -> ::c_int; + pub fn getcontext(ucp: *mut ucontext_t) -> ::c_int; + pub fn setcontext(ucp: *const ucontext_t) -> ::c_int; + pub fn makecontext(ucp: *mut ucontext_t, + func: extern fn (), + argc: ::c_int, ...); + pub fn swapcontext(uocp: *mut ucontext_t, + ucp: *const ucontext_t) -> ::c_int; +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/notbsd/linux/s390x/no_align.rs b/libc/src/unix/notbsd/linux/s390x/no_align.rs new file mode 100644 index 000000000..8909114cd --- /dev/null +++ b/libc/src/unix/notbsd/linux/s390x/no_align.rs @@ -0,0 +1,7 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} diff --git a/libc/src/unix/notbsd/mod.rs b/libc/src/unix/notbsd/mod.rs new file mode 100644 index 000000000..d0905e11f --- /dev/null +++ b/libc/src/unix/notbsd/mod.rs @@ -0,0 +1,1429 @@ +pub type sa_family_t = u16; +pub type pthread_key_t = ::c_uint; +pub type speed_t = ::c_uint; +pub type tcflag_t = ::c_uint; +pub type clockid_t = ::c_int; +pub type key_t = ::c_int; +pub type id_t = ::c_uint; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + + #[cfg(any(target_os = "linux", + target_os = "emscripten"))] + pub ai_addr: *mut ::sockaddr, + + pub ai_canonname: *mut c_char, + + #[cfg(target_os = "android")] + pub ai_addr: *mut ::sockaddr, + + pub ai_next: *mut addrinfo, + } + + pub struct sockaddr_nl { + pub nl_family: ::sa_family_t, + nl_pad: ::c_ushort, + pub nl_pid: u32, + pub nl_groups: u32 + } + + pub struct sockaddr_ll { + pub sll_family: ::c_ushort, + pub sll_protocol: ::c_ushort, + pub sll_ifindex: ::c_int, + pub sll_hatype: ::c_ushort, + pub sll_pkttype: ::c_uchar, + pub sll_halen: ::c_uchar, + pub sll_addr: [::c_uchar; 8] + } + + pub struct fd_set { + fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *const ::c_char, + } + + pub struct sched_param { + pub sched_priority: ::c_int, + #[cfg(any(target_env = "musl", target_os = "emscripten"))] + pub sched_ss_low_priority: ::c_int, + #[cfg(any(target_env = "musl", target_os = "emscripten"))] + pub sched_ss_repl_period: ::timespec, + #[cfg(any(target_env = "musl", target_os = "emscripten"))] + pub sched_ss_init_budget: ::timespec, + #[cfg(any(target_env = "musl", target_os = "emscripten"))] + pub sched_ss_max_repl: ::c_int, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct sigevent { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + // Actually a union. We only expose sigev_notify_thread_id because it's + // the most useful member + pub sigev_notify_thread_id: ::c_int, + #[cfg(target_pointer_width = "64")] + __unused1: [::c_int; 11], + #[cfg(target_pointer_width = "32")] + __unused1: [::c_int; 12] + } + + pub struct in_pktinfo { + pub ipi_ifindex: ::c_int, + pub ipi_spec_dst: ::in_addr, + pub ipi_addr: ::in_addr, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: ::c_uint, + pub ifa_addr: *mut ::sockaddr, + pub ifa_netmask: *mut ::sockaddr, + pub ifa_ifu: *mut ::sockaddr, // FIXME This should be a union + pub ifa_data: *mut ::c_void + } + + pub struct in6_rtmsg { + rtmsg_dst: ::in6_addr, + rtmsg_src: ::in6_addr, + rtmsg_gateway: ::in6_addr, + rtmsg_type: u32, + rtmsg_dst_len: u16, + rtmsg_src_len: u16, + rtmsg_metric: u32, + rtmsg_info: ::c_ulong, + rtmsg_flags: u32, + rtmsg_ifindex: ::c_int, + } + + pub struct arpreq { + pub arp_pa: ::sockaddr, + pub arp_ha: ::sockaddr, + pub arp_flags: ::c_int, + pub arp_netmask: ::sockaddr, + pub arp_dev: [::c_char; 16], + } + + pub struct arpreq_old { + pub arp_pa: ::sockaddr, + pub arp_ha: ::sockaddr, + pub arp_flags: ::c_int, + pub arp_netmask: ::sockaddr, + } + + pub struct arphdr { + pub ar_hrd: u16, + pub ar_pro: u16, + pub ar_hln: u8, + pub ar_pln: u8, + pub ar_op: u16, + } + + pub struct mmsghdr { + pub msg_hdr: ::msghdr, + pub msg_len: ::c_uint, + } +} + +s_no_extra_traits!{ + #[cfg_attr( + any( + all( + target_arch = "x86", + not(target_env = "musl"), + not(target_os = "android")), + target_arch = "x86_64"), + repr(packed))] + pub struct epoll_event { + pub events: ::uint32_t, + pub u64: ::uint64_t, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [::c_char; 108] + } + + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_align: ::size_t, + #[cfg(target_pointer_width = "32")] + __ss_pad2: [u8; 128 - 2 * 4], + #[cfg(target_pointer_width = "64")] + __ss_pad2: [u8; 128 - 2 * 8], + } + + pub struct utsname { + pub sysname: [::c_char; 65], + pub nodename: [::c_char; 65], + pub release: [::c_char; 65], + pub version: [::c_char; 65], + pub machine: [::c_char; 65], + pub domainname: [::c_char; 65] + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for epoll_event { + fn eq(&self, other: &epoll_event) -> bool { + self.events == other.events + && self.u64 == other.u64 + } + } + impl Eq for epoll_event {} + impl ::fmt::Debug for epoll_event { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let events = self.events; + let u64 = self.u64; + f.debug_struct("epoll_event") + .field("events", &events) + .field("u64", &u64) + .finish() + } + } + impl ::hash::Hash for epoll_event { + fn hash(&self, state: &mut H) { + let events = self.events; + let u64 = self.u64; + events.hash(state); + u64.hash(state); + } + } + + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_un {} + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_family == other.ss_family + && self + .__ss_pad2 + .iter() + .zip(other.__ss_pad2.iter()) + .all(|(a, b)| a == b) + } + } + + impl Eq for sockaddr_storage {} + + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_family", &self.ss_family) + .field("__ss_align", &self.__ss_align) + // FIXME: .field("__ss_pad2", &self.__ss_pad2) + .finish() + } + } + + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_family.hash(state); + self.__ss_pad2.hash(state); + } + } + + impl PartialEq for utsname { + fn eq(&self, other: &utsname) -> bool { + self.sysname + .iter() + .zip(other.sysname.iter()) + .all(|(a, b)| a == b) + && self + .nodename + .iter() + .zip(other.nodename.iter()) + .all(|(a, b)| a == b) + && self + .release + .iter() + .zip(other.release.iter()) + .all(|(a, b)| a == b) + && self + .version + .iter() + .zip(other.version.iter()) + .all(|(a, b)| a == b) + && self + .machine + .iter() + .zip(other.machine.iter()) + .all(|(a, b)| a == b) + && self + .domainname + .iter() + .zip(other.domainname.iter()) + .all(|(a, b)| a == b) + } + } + + impl Eq for utsname {} + + impl ::fmt::Debug for utsname { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utsname") + // FIXME: .field("sysname", &self.sysname) + // FIXME: .field("nodename", &self.nodename) + // FIXME: .field("release", &self.release) + // FIXME: .field("version", &self.version) + // FIXME: .field("machine", &self.machine) + // FIXME: .field("domainname", &self.domainname) + .finish() + } + } + + impl ::hash::Hash for utsname { + fn hash(&self, state: &mut H) { + self.sysname.hash(state); + self.nodename.hash(state); + self.release.hash(state); + self.version.hash(state); + self.machine.hash(state); + self.domainname.hash(state); + } + } + } +} + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 2147483647; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; + +// Linux-specific fcntls +pub const F_SETLEASE: ::c_int = 1024; +pub const F_GETLEASE: ::c_int = 1025; +pub const F_NOTIFY: ::c_int = 1026; +pub const F_CANCELLK: ::c_int = 1029; +pub const F_DUPFD_CLOEXEC: ::c_int = 1030; +pub const F_SETPIPE_SZ: ::c_int = 1031; +pub const F_GETPIPE_SZ: ::c_int = 1032; +pub const F_ADD_SEALS: ::c_int = 1033; +pub const F_GET_SEALS: ::c_int = 1034; + +pub const F_SEAL_SEAL: ::c_int = 0x0001; +pub const F_SEAL_SHRINK: ::c_int = 0x0002; +pub const F_SEAL_GROW: ::c_int = 0x0004; +pub const F_SEAL_WRITE: ::c_int = 0x0008; + +// TODO(#235): Include file sealing fcntls once we have a way to verify them. + +pub const SIGTRAP: ::c_int = 5; + +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 1; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_MONOTONIC: ::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 3; +pub const CLOCK_MONOTONIC_RAW: ::clockid_t = 4; +pub const CLOCK_REALTIME_COARSE: ::clockid_t = 5; +pub const CLOCK_MONOTONIC_COARSE: ::clockid_t = 6; +pub const CLOCK_BOOTTIME: ::clockid_t = 7; +pub const CLOCK_REALTIME_ALARM: ::clockid_t = 8; +pub const CLOCK_BOOTTIME_ALARM: ::clockid_t = 9; +// TODO(#247) Someday our Travis shall have glibc 2.21 (released in Sep +// 2014.) See also musl/mod.rs +// pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +// pub const CLOCK_TAI: ::clockid_t = 11; +pub const TIMER_ABSTIME: ::c_int = 1; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_LOCKS: ::c_int = 10; +pub const RLIMIT_SIGPENDING: ::c_int = 11; +pub const RLIMIT_MSGQUEUE: ::c_int = 12; +pub const RLIMIT_NICE: ::c_int = 13; +pub const RLIMIT_RTPRIO: ::c_int = 14; + +pub const RUSAGE_SELF: ::c_int = 0; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; + +pub const SOCK_CLOEXEC: ::c_int = O_CLOEXEC; + +pub const S_IFIFO: ::mode_t = 4096; +pub const S_IFCHR: ::mode_t = 8192; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IRWXU: ::mode_t = 448; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IRWXG: ::mode_t = 56; +pub const S_IXGRP: ::mode_t = 8; +pub const S_IWGRP: ::mode_t = 16; +pub const S_IRGRP: ::mode_t = 32; +pub const S_IRWXO: ::mode_t = 7; +pub const S_IXOTH: ::mode_t = 1; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IROTH: ::mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const LC_CTYPE: ::c_int = 0; +pub const LC_NUMERIC: ::c_int = 1; +pub const LC_TIME: ::c_int = 2; +pub const LC_COLLATE: ::c_int = 3; +pub const LC_MONETARY: ::c_int = 4; +pub const LC_MESSAGES: ::c_int = 5; +pub const LC_ALL: ::c_int = 6; +pub const LC_CTYPE_MASK: ::c_int = (1 << LC_CTYPE); +pub const LC_NUMERIC_MASK: ::c_int = (1 << LC_NUMERIC); +pub const LC_TIME_MASK: ::c_int = (1 << LC_TIME); +pub const LC_COLLATE_MASK: ::c_int = (1 << LC_COLLATE); +pub const LC_MONETARY_MASK: ::c_int = (1 << LC_MONETARY); +pub const LC_MESSAGES_MASK: ::c_int = (1 << LC_MESSAGES); +// LC_ALL_MASK defined per platform + +pub const MAP_FILE: ::c_int = 0x0000; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +// MS_ flags for msync(2) +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; +pub const MS_SYNC: ::c_int = 0x0004; + +// MS_ flags for mount(2) +pub const MS_RDONLY: ::c_ulong = 0x01; +pub const MS_NOSUID: ::c_ulong = 0x02; +pub const MS_NODEV: ::c_ulong = 0x04; +pub const MS_NOEXEC: ::c_ulong = 0x08; +pub const MS_SYNCHRONOUS: ::c_ulong = 0x10; +pub const MS_REMOUNT: ::c_ulong = 0x20; +pub const MS_MANDLOCK: ::c_ulong = 0x40; +pub const MS_DIRSYNC: ::c_ulong = 0x80; +pub const MS_NOATIME: ::c_ulong = 0x0400; +pub const MS_NODIRATIME: ::c_ulong = 0x0800; +pub const MS_BIND: ::c_ulong = 0x1000; +pub const MS_MOVE: ::c_ulong = 0x2000; +pub const MS_REC: ::c_ulong = 0x4000; +pub const MS_SILENT: ::c_ulong = 0x8000; +pub const MS_POSIXACL: ::c_ulong = 0x010000; +pub const MS_UNBINDABLE: ::c_ulong = 0x020000; +pub const MS_PRIVATE: ::c_ulong = 0x040000; +pub const MS_SLAVE: ::c_ulong = 0x080000; +pub const MS_SHARED: ::c_ulong = 0x100000; +pub const MS_RELATIME: ::c_ulong = 0x200000; +pub const MS_KERNMOUNT: ::c_ulong = 0x400000; +pub const MS_I_VERSION: ::c_ulong = 0x800000; +pub const MS_STRICTATIME: ::c_ulong = 0x1000000; +pub const MS_ACTIVE: ::c_ulong = 0x40000000; +pub const MS_NOUSER: ::c_ulong = 0x80000000; +pub const MS_MGC_VAL: ::c_ulong = 0xc0ed0000; +pub const MS_MGC_MSK: ::c_ulong = 0xffff0000; +pub const MS_RMT_MASK: ::c_ulong = 0x800051; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EWOULDBLOCK: ::c_int = EAGAIN; + +pub const SCM_RIGHTS: ::c_int = 0x01; +pub const SCM_CREDENTIALS: ::c_int = 0x02; + +pub const PROT_GROWSDOWN: ::c_int = 0x1000000; +pub const PROT_GROWSUP: ::c_int = 0x2000000; + +pub const MAP_TYPE: ::c_int = 0x000f; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_FREE: ::c_int = 8; +pub const MADV_REMOVE: ::c_int = 9; +pub const MADV_DONTFORK: ::c_int = 10; +pub const MADV_DOFORK: ::c_int = 11; +pub const MADV_MERGEABLE: ::c_int = 12; +pub const MADV_UNMERGEABLE: ::c_int = 13; +pub const MADV_HUGEPAGE: ::c_int = 14; +pub const MADV_NOHUGEPAGE: ::c_int = 15; +pub const MADV_DONTDUMP: ::c_int = 16; +pub const MADV_DODUMP: ::c_int = 17; +pub const MADV_HWPOISON: ::c_int = 100; +pub const MADV_SOFT_OFFLINE: ::c_int = 101; + +pub const IFF_UP: ::c_int = 0x1; +pub const IFF_BROADCAST: ::c_int = 0x2; +pub const IFF_DEBUG: ::c_int = 0x4; +pub const IFF_LOOPBACK: ::c_int = 0x8; +pub const IFF_POINTOPOINT: ::c_int = 0x10; +pub const IFF_NOTRAILERS: ::c_int = 0x20; +pub const IFF_RUNNING: ::c_int = 0x40; +pub const IFF_NOARP: ::c_int = 0x80; +pub const IFF_PROMISC: ::c_int = 0x100; +pub const IFF_ALLMULTI: ::c_int = 0x200; +pub const IFF_MASTER: ::c_int = 0x400; +pub const IFF_SLAVE: ::c_int = 0x800; +pub const IFF_MULTICAST: ::c_int = 0x1000; +pub const IFF_PORTSEL: ::c_int = 0x2000; +pub const IFF_AUTOMEDIA: ::c_int = 0x4000; +pub const IFF_DYNAMIC: ::c_int = 0x8000; + +pub const SOL_IP: ::c_int = 0; +pub const SOL_TCP: ::c_int = 6; +pub const SOL_UDP: ::c_int = 17; +pub const SOL_IPV6: ::c_int = 41; +pub const SOL_ICMPV6: ::c_int = 58; +pub const SOL_RAW: ::c_int = 255; +pub const SOL_DECNET: ::c_int = 261; +pub const SOL_X25: ::c_int = 262; +pub const SOL_PACKET: ::c_int = 263; +pub const SOL_ATM: ::c_int = 264; +pub const SOL_AAL: ::c_int = 265; +pub const SOL_IRDA: ::c_int = 266; +pub const SOL_NETBEUI: ::c_int = 267; +pub const SOL_LLC: ::c_int = 268; +pub const SOL_DCCP: ::c_int = 269; +pub const SOL_NETLINK: ::c_int = 270; +pub const SOL_TIPC: ::c_int = 271; +pub const SOL_BLUETOOTH: ::c_int = 274; +pub const SOL_ALG: ::c_int = 279; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_UNIX: ::c_int = 1; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_INET: ::c_int = 2; +pub const AF_AX25: ::c_int = 3; +pub const AF_IPX: ::c_int = 4; +pub const AF_APPLETALK: ::c_int = 5; +pub const AF_NETROM: ::c_int = 6; +pub const AF_BRIDGE: ::c_int = 7; +pub const AF_ATMPVC: ::c_int = 8; +pub const AF_X25: ::c_int = 9; +pub const AF_INET6: ::c_int = 10; +pub const AF_ROSE: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_NETBEUI: ::c_int = 13; +pub const AF_SECURITY: ::c_int = 14; +pub const AF_KEY: ::c_int = 15; +pub const AF_NETLINK: ::c_int = 16; +pub const AF_ROUTE: ::c_int = AF_NETLINK; +pub const AF_PACKET: ::c_int = 17; +pub const AF_ASH: ::c_int = 18; +pub const AF_ECONET: ::c_int = 19; +pub const AF_ATMSVC: ::c_int = 20; +pub const AF_RDS: ::c_int = 21; +pub const AF_SNA: ::c_int = 22; +pub const AF_IRDA: ::c_int = 23; +pub const AF_PPPOX: ::c_int = 24; +pub const AF_WANPIPE: ::c_int = 25; +pub const AF_LLC: ::c_int = 26; +pub const AF_CAN: ::c_int = 29; +pub const AF_TIPC: ::c_int = 30; +pub const AF_BLUETOOTH: ::c_int = 31; +pub const AF_IUCV: ::c_int = 32; +pub const AF_RXRPC: ::c_int = 33; +pub const AF_ISDN: ::c_int = 34; +pub const AF_PHONET: ::c_int = 35; +pub const AF_IEEE802154: ::c_int = 36; +pub const AF_CAIF: ::c_int = 37; +pub const AF_ALG: ::c_int = 38; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_UNIX: ::c_int = AF_UNIX; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_AX25: ::c_int = AF_AX25; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_NETROM: ::c_int = AF_NETROM; +pub const PF_BRIDGE: ::c_int = AF_BRIDGE; +pub const PF_ATMPVC: ::c_int = AF_ATMPVC; +pub const PF_X25: ::c_int = AF_X25; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_ROSE: ::c_int = AF_ROSE; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_NETBEUI: ::c_int = AF_NETBEUI; +pub const PF_SECURITY: ::c_int = AF_SECURITY; +pub const PF_KEY: ::c_int = AF_KEY; +pub const PF_NETLINK: ::c_int = AF_NETLINK; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_PACKET: ::c_int = AF_PACKET; +pub const PF_ASH: ::c_int = AF_ASH; +pub const PF_ECONET: ::c_int = AF_ECONET; +pub const PF_ATMSVC: ::c_int = AF_ATMSVC; +pub const PF_RDS: ::c_int = AF_RDS; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_IRDA: ::c_int = AF_IRDA; +pub const PF_PPPOX: ::c_int = AF_PPPOX; +pub const PF_WANPIPE: ::c_int = AF_WANPIPE; +pub const PF_LLC: ::c_int = AF_LLC; +pub const PF_CAN: ::c_int = AF_CAN; +pub const PF_TIPC: ::c_int = AF_TIPC; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_IUCV: ::c_int = AF_IUCV; +pub const PF_RXRPC: ::c_int = AF_RXRPC; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_PHONET: ::c_int = AF_PHONET; +pub const PF_IEEE802154: ::c_int = AF_IEEE802154; +pub const PF_CAIF: ::c_int = AF_CAIF; +pub const PF_ALG: ::c_int = AF_ALG; + +pub const SOMAXCONN: ::c_int = 128; + +pub const MSG_OOB: ::c_int = 1; +pub const MSG_PEEK: ::c_int = 2; +pub const MSG_DONTROUTE: ::c_int = 4; +pub const MSG_CTRUNC: ::c_int = 8; +pub const MSG_TRUNC: ::c_int = 0x20; +pub const MSG_DONTWAIT: ::c_int = 0x40; +pub const MSG_EOR: ::c_int = 0x80; +pub const MSG_WAITALL: ::c_int = 0x100; +pub const MSG_FIN: ::c_int = 0x200; +pub const MSG_SYN: ::c_int = 0x400; +pub const MSG_CONFIRM: ::c_int = 0x800; +pub const MSG_RST: ::c_int = 0x1000; +pub const MSG_ERRQUEUE: ::c_int = 0x2000; +pub const MSG_NOSIGNAL: ::c_int = 0x4000; +pub const MSG_MORE: ::c_int = 0x8000; +pub const MSG_WAITFORONE: ::c_int = 0x10000; +pub const MSG_FASTOPEN: ::c_int = 0x20000000; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x40000000; + +pub const SCM_TIMESTAMP: ::c_int = SO_TIMESTAMP; + +pub const SOCK_RAW: ::c_int = 3; +pub const SOCK_RDM: ::c_int = 4; +pub const IP_MULTICAST_IF: ::c_int = 32; +pub const IP_MULTICAST_TTL: ::c_int = 33; +pub const IP_MULTICAST_LOOP: ::c_int = 34; +pub const IP_TOS: ::c_int = 1; +pub const IP_TTL: ::c_int = 2; +pub const IP_HDRINCL: ::c_int = 3; +pub const IP_PKTINFO: ::c_int = 8; +pub const IP_RECVTOS: ::c_int = 13; +pub const IP_ADD_MEMBERSHIP: ::c_int = 35; +pub const IP_DROP_MEMBERSHIP: ::c_int = 36; +pub const IP_TRANSPARENT: ::c_int = 19; +pub const IPV6_UNICAST_HOPS: ::c_int = 16; +pub const IPV6_MULTICAST_IF: ::c_int = 17; +pub const IPV6_MULTICAST_HOPS: ::c_int = 18; +pub const IPV6_MULTICAST_LOOP: ::c_int = 19; +pub const IPV6_ADD_MEMBERSHIP: ::c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: ::c_int = 21; +pub const IPV6_V6ONLY: ::c_int = 26; +pub const IPV6_RECVPKTINFO: ::c_int = 49; +pub const IPV6_PKTINFO: ::c_int = 50; +pub const IPV6_RECVTCLASS: ::c_int = 66; +pub const IPV6_TCLASS: ::c_int = 67; + +pub const TCP_NODELAY: ::c_int = 1; +pub const TCP_MAXSEG: ::c_int = 2; +pub const TCP_CORK: ::c_int = 3; +pub const TCP_KEEPIDLE: ::c_int = 4; +pub const TCP_KEEPINTVL: ::c_int = 5; +pub const TCP_KEEPCNT: ::c_int = 6; +pub const TCP_SYNCNT: ::c_int = 7; +pub const TCP_LINGER2: ::c_int = 8; +pub const TCP_DEFER_ACCEPT: ::c_int = 9; +pub const TCP_WINDOW_CLAMP: ::c_int = 10; +pub const TCP_INFO: ::c_int = 11; +pub const TCP_QUICKACK: ::c_int = 12; +pub const TCP_CONGESTION: ::c_int = 13; + +pub const SO_DEBUG: ::c_int = 1; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const SS_ONSTACK: ::c_int = 1; +pub const SS_DISABLE: ::c_int = 2; + +pub const PATH_MAX: ::c_int = 4096; + +pub const FD_SETSIZE: usize = 1024; + +pub const EPOLLIN: ::c_int = 0x1; +pub const EPOLLPRI: ::c_int = 0x2; +pub const EPOLLOUT: ::c_int = 0x4; +pub const EPOLLRDNORM: ::c_int = 0x40; +pub const EPOLLRDBAND: ::c_int = 0x80; +pub const EPOLLWRNORM: ::c_int = 0x100; +pub const EPOLLWRBAND: ::c_int = 0x200; +pub const EPOLLMSG: ::c_int = 0x400; +pub const EPOLLERR: ::c_int = 0x8; +pub const EPOLLHUP: ::c_int = 0x10; +pub const EPOLLET: ::c_int = 0x80000000; + +pub const EPOLL_CTL_ADD: ::c_int = 1; +pub const EPOLL_CTL_MOD: ::c_int = 3; +pub const EPOLL_CTL_DEL: ::c_int = 2; + +pub const MNT_DETACH: ::c_int = 0x2; +pub const MNT_EXPIRE: ::c_int = 0x4; + +pub const Q_GETFMT: ::c_int = 0x800004; +pub const Q_GETINFO: ::c_int = 0x800005; +pub const Q_SETINFO: ::c_int = 0x800006; +pub const QIF_BLIMITS: ::uint32_t = 1; +pub const QIF_SPACE: ::uint32_t = 2; +pub const QIF_ILIMITS: ::uint32_t = 4; +pub const QIF_INODES: ::uint32_t = 8; +pub const QIF_BTIME: ::uint32_t = 16; +pub const QIF_ITIME: ::uint32_t = 32; +pub const QIF_LIMITS: ::uint32_t = 5; +pub const QIF_USAGE: ::uint32_t = 10; +pub const QIF_TIMES: ::uint32_t = 48; +pub const QIF_ALL: ::uint32_t = 63; + +pub const MNT_FORCE: ::c_int = 0x1; + +pub const Q_SYNC: ::c_int = 0x800001; +pub const Q_QUOTAON: ::c_int = 0x800002; +pub const Q_QUOTAOFF: ::c_int = 0x800003; +pub const Q_GETQUOTA: ::c_int = 0x800007; +pub const Q_SETQUOTA: ::c_int = 0x800008; + +pub const TCIOFF: ::c_int = 2; +pub const TCION: ::c_int = 3; +pub const TCOOFF: ::c_int = 0; +pub const TCOON: ::c_int = 1; +pub const TCIFLUSH: ::c_int = 0; +pub const TCOFLUSH: ::c_int = 1; +pub const TCIOFLUSH: ::c_int = 2; +pub const NL0: ::c_int = 0x00000000; +pub const NL1: ::c_int = 0x00000100; +pub const TAB0: ::c_int = 0x00000000; +pub const CR0: ::c_int = 0x00000000; +pub const FF0: ::c_int = 0x00000000; +pub const BS0: ::c_int = 0x00000000; +pub const VT0: ::c_int = 0x00000000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: ::tcflag_t = 0x00000001; +pub const BRKINT: ::tcflag_t = 0x00000002; +pub const IGNPAR: ::tcflag_t = 0x00000004; +pub const PARMRK: ::tcflag_t = 0x00000008; +pub const INPCK: ::tcflag_t = 0x00000010; +pub const ISTRIP: ::tcflag_t = 0x00000020; +pub const INLCR: ::tcflag_t = 0x00000040; +pub const IGNCR: ::tcflag_t = 0x00000080; +pub const ICRNL: ::tcflag_t = 0x00000100; +pub const IXANY: ::tcflag_t = 0x00000800; +pub const IMAXBEL: ::tcflag_t = 0x00002000; +pub const OPOST: ::tcflag_t = 0x1; +pub const CS5: ::tcflag_t = 0x00000000; +pub const CRTSCTS: ::tcflag_t = 0x80000000; +pub const ECHO: ::tcflag_t = 0x00000008; +pub const OCRNL: ::tcflag_t = 0o000010; +pub const ONOCR: ::tcflag_t = 0o000020; +pub const ONLRET: ::tcflag_t = 0o000040; +pub const OFILL: ::tcflag_t = 0o000100; +pub const OFDEL: ::tcflag_t = 0o000200; + +pub const CLONE_VM: ::c_int = 0x100; +pub const CLONE_FS: ::c_int = 0x200; +pub const CLONE_FILES: ::c_int = 0x400; +pub const CLONE_SIGHAND: ::c_int = 0x800; +pub const CLONE_PTRACE: ::c_int = 0x2000; +pub const CLONE_VFORK: ::c_int = 0x4000; +pub const CLONE_PARENT: ::c_int = 0x8000; +pub const CLONE_THREAD: ::c_int = 0x10000; +pub const CLONE_NEWNS: ::c_int = 0x20000; +pub const CLONE_SYSVSEM: ::c_int = 0x40000; +pub const CLONE_SETTLS: ::c_int = 0x80000; +pub const CLONE_PARENT_SETTID: ::c_int = 0x100000; +pub const CLONE_CHILD_CLEARTID: ::c_int = 0x200000; +pub const CLONE_DETACHED: ::c_int = 0x400000; +pub const CLONE_UNTRACED: ::c_int = 0x800000; +pub const CLONE_CHILD_SETTID: ::c_int = 0x01000000; +pub const CLONE_NEWUTS: ::c_int = 0x04000000; +pub const CLONE_NEWIPC: ::c_int = 0x08000000; +pub const CLONE_NEWUSER: ::c_int = 0x10000000; +pub const CLONE_NEWPID: ::c_int = 0x20000000; +pub const CLONE_NEWNET: ::c_int = 0x40000000; +pub const CLONE_IO: ::c_int = 0x80000000; +pub const CLONE_NEWCGROUP: ::c_int = 0x02000000; + +pub const WNOHANG: ::c_int = 0x00000001; +pub const WUNTRACED: ::c_int = 0x00000002; +pub const WSTOPPED: ::c_int = WUNTRACED; +pub const WEXITED: ::c_int = 0x00000004; +pub const WCONTINUED: ::c_int = 0x00000008; +pub const WNOWAIT: ::c_int = 0x01000000; + +// Options set using PTRACE_SETOPTIONS. +pub const PTRACE_O_TRACESYSGOOD: ::c_int = 0x00000001; +pub const PTRACE_O_TRACEFORK: ::c_int = 0x00000002; +pub const PTRACE_O_TRACEVFORK: ::c_int = 0x00000004; +pub const PTRACE_O_TRACECLONE: ::c_int = 0x00000008; +pub const PTRACE_O_TRACEEXEC: ::c_int = 0x00000010; +pub const PTRACE_O_TRACEVFORKDONE: ::c_int = 0x00000020; +pub const PTRACE_O_TRACEEXIT: ::c_int = 0x00000040; +pub const PTRACE_O_TRACESECCOMP: ::c_int = 0x00000080; +pub const PTRACE_O_EXITKILL: ::c_int = 0x00100000; +pub const PTRACE_O_SUSPEND_SECCOMP: ::c_int = 0x00200000; +pub const PTRACE_O_MASK: ::c_int = 0x003000ff; + +// Wait extended result codes for the above trace options. +pub const PTRACE_EVENT_FORK: ::c_int = 1; +pub const PTRACE_EVENT_VFORK: ::c_int = 2; +pub const PTRACE_EVENT_CLONE: ::c_int = 3; +pub const PTRACE_EVENT_EXEC: ::c_int = 4; +pub const PTRACE_EVENT_VFORK_DONE: ::c_int = 5; +pub const PTRACE_EVENT_EXIT: ::c_int = 6; +pub const PTRACE_EVENT_SECCOMP: ::c_int = 7; +// PTRACE_EVENT_STOP was added to glibc in 2.26 +// pub const PTRACE_EVENT_STOP: ::c_int = 128; + +pub const __WNOTHREAD: ::c_int = 0x20000000; +pub const __WALL: ::c_int = 0x40000000; +pub const __WCLONE: ::c_int = 0x80000000; + +pub const SPLICE_F_MOVE: ::c_uint = 0x01; +pub const SPLICE_F_NONBLOCK: ::c_uint = 0x02; +pub const SPLICE_F_MORE: ::c_uint = 0x04; +pub const SPLICE_F_GIFT: ::c_uint = 0x08; + +pub const RTLD_LOCAL: ::c_int = 0; +pub const RTLD_LAZY: ::c_int = 1; + +pub const POSIX_FADV_NORMAL: ::c_int = 0; +pub const POSIX_FADV_RANDOM: ::c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_FADV_WILLNEED: ::c_int = 3; + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x100; +pub const AT_REMOVEDIR: ::c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x400; +pub const AT_NO_AUTOMOUNT: ::c_int = 0x800; +pub const AT_EMPTY_PATH: ::c_int = 0x1000; + +pub const LOG_CRON: ::c_int = 9 << 3; +pub const LOG_AUTHPRIV: ::c_int = 10 << 3; +pub const LOG_FTP: ::c_int = 11 << 3; +pub const LOG_PERROR: ::c_int = 0x20; + +pub const PIPE_BUF: usize = 4096; + +pub const SI_LOAD_SHIFT: ::c_uint = 16; + +pub const SIGEV_SIGNAL: ::c_int = 0; +pub const SIGEV_NONE: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; +pub const POLLRDNORM: ::c_short = 0x040; +pub const POLLRDBAND: ::c_short = 0x080; + +pub const IPTOS_LOWDELAY: u8 = 0x10; +pub const IPTOS_THROUGHPUT: u8 = 0x08; +pub const IPTOS_RELIABILITY: u8 = 0x04; +pub const IPTOS_MINCOST: u8 = 0x02; + +pub const IPTOS_PREC_NETCONTROL: u8 = 0xe0; +pub const IPTOS_PREC_INTERNETCONTROL: u8 = 0xc0; +pub const IPTOS_PREC_CRITIC_ECP: u8 = 0xa0; +pub const IPTOS_PREC_FLASHOVERRIDE: u8 = 0x80; +pub const IPTOS_PREC_FLASH: u8 = 0x60; +pub const IPTOS_PREC_IMMEDIATE: u8 = 0x40; +pub const IPTOS_PREC_PRIORITY: u8 = 0x20; +pub const IPTOS_PREC_ROUTINE: u8 = 0x00; + +pub const IPTOS_ECN_MASK: u8 = 0x03; +pub const IPTOS_ECN_ECT1: u8 = 0x01; +pub const IPTOS_ECN_ECT0: u8 = 0x02; +pub const IPTOS_ECN_CE: u8 = 0x03; + +pub const IPOPT_COPY: u8 = 0x80; +pub const IPOPT_CLASS_MASK: u8 = 0x60; +pub const IPOPT_NUMBER_MASK: u8 = 0x1f; + +pub const IPOPT_CONTROL: u8 = 0x00; +pub const IPOPT_RESERVED1: u8 = 0x20; +pub const IPOPT_MEASUREMENT: u8 = 0x40; +pub const IPOPT_RESERVED2: u8 = 0x60; +pub const IPOPT_END: u8 = (0 |IPOPT_CONTROL); +pub const IPOPT_NOOP: u8 = (1 |IPOPT_CONTROL); +pub const IPOPT_SEC: u8 = (2 |IPOPT_CONTROL|IPOPT_COPY); +pub const IPOPT_LSRR: u8 = (3 |IPOPT_CONTROL|IPOPT_COPY); +pub const IPOPT_TIMESTAMP: u8 = (4 |IPOPT_MEASUREMENT); +pub const IPOPT_RR: u8 = (7 |IPOPT_CONTROL); +pub const IPOPT_SID: u8 = (8 |IPOPT_CONTROL|IPOPT_COPY); +pub const IPOPT_SSRR: u8 = (9 |IPOPT_CONTROL|IPOPT_COPY); +pub const IPOPT_RA: u8 = (20|IPOPT_CONTROL|IPOPT_COPY); +pub const IPVERSION: u8 = 4; +pub const MAXTTL: u8 = 255; +pub const IPDEFTTL: u8 = 64; +pub const IPOPT_OPTVAL: u8 = 0; +pub const IPOPT_OLEN: u8 = 1; +pub const IPOPT_OFFSET: u8 = 2; +pub const IPOPT_MINOFF: u8 = 4; +pub const MAX_IPOPTLEN: u8 = 40; +pub const IPOPT_NOP: u8 = IPOPT_NOOP; +pub const IPOPT_EOL: u8 = IPOPT_END; +pub const IPOPT_TS: u8 = IPOPT_TIMESTAMP; +pub const IPOPT_TS_TSONLY: u8 = 0; +pub const IPOPT_TS_TSANDADDR: u8 = 1; +pub const IPOPT_TS_PRESPEC: u8 = 3; + +pub const ARPOP_RREQUEST: u16 = 3; +pub const ARPOP_RREPLY: u16 = 4; +pub const ARPOP_InREQUEST: u16 = 8; +pub const ARPOP_InREPLY: u16 = 9; +pub const ARPOP_NAK: u16 = 10; + +pub const ATF_NETMASK: ::c_int = 0x20; +pub const ATF_DONTPUB: ::c_int = 0x40; + +pub const ARPHRD_NETROM: u16 = 0; +pub const ARPHRD_ETHER: u16 = 1; +pub const ARPHRD_EETHER: u16 = 2; +pub const ARPHRD_AX25: u16 = 3; +pub const ARPHRD_PRONET: u16 = 4; +pub const ARPHRD_CHAOS: u16 = 5; +pub const ARPHRD_IEEE802: u16 = 6; +pub const ARPHRD_ARCNET: u16 = 7; +pub const ARPHRD_APPLETLK: u16 = 8; +pub const ARPHRD_DLCI: u16 = 15; +pub const ARPHRD_ATM: u16 = 19; +pub const ARPHRD_METRICOM: u16 = 23; +pub const ARPHRD_IEEE1394: u16 = 24; +pub const ARPHRD_EUI64: u16 = 27; +pub const ARPHRD_INFINIBAND: u16 = 32; + +pub const ARPHRD_SLIP: u16 = 256; +pub const ARPHRD_CSLIP: u16 = 257; +pub const ARPHRD_SLIP6: u16 = 258; +pub const ARPHRD_CSLIP6: u16 = 259; +pub const ARPHRD_RSRVD: u16 = 260; +pub const ARPHRD_ADAPT: u16 = 264; +pub const ARPHRD_ROSE: u16 = 270; +pub const ARPHRD_X25: u16 = 271; +pub const ARPHRD_HWX25: u16 = 272; +pub const ARPHRD_PPP: u16 = 512; +pub const ARPHRD_CISCO: u16 = 513; +pub const ARPHRD_HDLC: u16 = ARPHRD_CISCO; +pub const ARPHRD_LAPB: u16 = 516; +pub const ARPHRD_DDCMP: u16 = 517; +pub const ARPHRD_RAWHDLC: u16 = 518; + +pub const ARPHRD_TUNNEL: u16 = 768; +pub const ARPHRD_TUNNEL6: u16 = 769; +pub const ARPHRD_FRAD: u16 = 770; +pub const ARPHRD_SKIP: u16 = 771; +pub const ARPHRD_LOOPBACK: u16 = 772; +pub const ARPHRD_LOCALTLK: u16 = 773; +pub const ARPHRD_FDDI: u16 = 774; +pub const ARPHRD_BIF: u16 = 775; +pub const ARPHRD_SIT: u16 = 776; +pub const ARPHRD_IPDDP: u16 = 777; +pub const ARPHRD_IPGRE: u16 = 778; +pub const ARPHRD_PIMREG: u16 = 779; +pub const ARPHRD_HIPPI: u16 = 780; +pub const ARPHRD_ASH: u16 = 781; +pub const ARPHRD_ECONET: u16 = 782; +pub const ARPHRD_IRDA: u16 = 783; +pub const ARPHRD_FCPP: u16 = 784; +pub const ARPHRD_FCAL: u16 = 785; +pub const ARPHRD_FCPL: u16 = 786; +pub const ARPHRD_FCFABRIC: u16 = 787; +pub const ARPHRD_IEEE802_TR: u16 = 800; +pub const ARPHRD_IEEE80211: u16 = 801; +pub const ARPHRD_IEEE80211_PRISM: u16 = 802; +pub const ARPHRD_IEEE80211_RADIOTAP: u16 = 803; +pub const ARPHRD_IEEE802154: u16 = 804; + +pub const ARPHRD_VOID: u16 = 0xFFFF; +pub const ARPHRD_NONE: u16 = 0xFFFE; + +fn CMSG_ALIGN(len: usize) -> usize { + len + ::mem::size_of::() - 1 & !(::mem::size_of::() - 1) +} + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= ::mem::size_of::() { + (*mhdr).msg_control as *mut cmsghdr + } else { + 0 as *mut cmsghdr + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut ::c_uchar { + cmsg.offset(1) as *mut ::c_uchar + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(::mem::size_of::())) + as ::c_uint + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + CMSG_ALIGN(::mem::size_of::()) as ::c_uint + length + } + + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0xffff + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7f + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0x7f) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x80) != 0 + } + + pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + (cmd << 8) | (type_ & 0x00ff) + } + + pub fn IPOPT_COPIED(o: u8) -> u8 { + o & IPOPT_COPY + } + + pub fn IPOPT_CLASS(o: u8) -> u8 { + o & IPOPT_CLASS_MASK + } + + pub fn IPOPT_NUMBER(o: u8) -> u8 { + o & IPOPT_NUMBER_MASK + } + + pub fn IPTOS_ECN(x: u8) -> u8 { + x & ::IPTOS_ECN_MASK + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn mincore(addr: *mut ::c_void, len: ::size_t, + vec: *mut ::c_uchar) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + + pub fn pthread_getattr_np(native: ::pthread_t, + attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + pub fn setgroups(ngroups: ::size_t, + ptr: *const ::gid_t) -> ::c_int; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn statfs64(path: *const ::c_char, buf: *mut statfs64) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + pub fn fstatfs64(fd: ::c_int, buf: *mut statfs64) -> ::c_int; + pub fn statvfs64(path: *const ::c_char, buf: *mut statvfs64) -> ::c_int; + pub fn fstatvfs64(fd: ::c_int, buf: *mut statvfs64) -> ::c_int; + pub fn memrchr(cx: *const ::c_void, + c: ::c_int, + n: ::size_t) -> *mut ::c_void; + + pub fn posix_fadvise(fd: ::c_int, offset: ::off_t, len: ::off_t, + advise: ::c_int) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn creat64(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fstat64(fildes: ::c_int, buf: *mut stat64) -> ::c_int; + pub fn fstatat64(dirfd: ::c_int, pathname: *const c_char, + buf: *mut stat64, flags: ::c_int) -> ::c_int; + pub fn ftruncate64(fd: ::c_int, length: off64_t) -> ::c_int; + pub fn getrlimit64(resource: ::c_int, rlim: *mut rlimit64) -> ::c_int; + pub fn lseek64(fd: ::c_int, offset: off64_t, whence: ::c_int) -> off64_t; + pub fn lstat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn mmap64(addr: *mut ::c_void, + len: ::size_t, + prot: ::c_int, + flags: ::c_int, + fd: ::c_int, + offset: off64_t) + -> *mut ::c_void; + pub fn open64(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn openat64(fd: ::c_int, + path: *const c_char, + oflag: ::c_int, ...) -> ::c_int; + pub fn pread64(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn preadv64(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off64_t) -> ::ssize_t; + pub fn pwrite64(fd: ::c_int, buf: *const ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn pwritev64(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off64_t) -> ::ssize_t; + pub fn readdir64(dirp: *mut ::DIR) -> *mut ::dirent64; + pub fn readdir64_r(dirp: *mut ::DIR, entry: *mut ::dirent64, + result: *mut *mut ::dirent64) -> ::c_int; + pub fn setrlimit64(resource: ::c_int, rlim: *const rlimit64) -> ::c_int; + pub fn stat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn truncate64(path: *const c_char, length: off64_t) -> ::c_int; + + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, + pshared: ::c_int) -> ::c_int; + pub fn accept4(fd: ::c_int, addr: *mut ::sockaddr, len: *mut ::socklen_t, + flg: ::c_int) -> ::c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn ptsname_r(fd: ::c_int, + buf: *mut ::c_char, + buflen: ::size_t) -> ::c_int; + pub fn clearenv() -> ::c_int; + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + pub fn setreuid(ruid: ::uid_t, euid: ::uid_t) -> ::c_int; + pub fn setregid(rgid: ::gid_t, egid: ::gid_t) -> ::c_int; + pub fn getresuid(ruid: *mut ::uid_t, euid: *mut ::uid_t, + suid: *mut ::uid_t) -> ::c_int; + pub fn getresgid(rgid: *mut ::gid_t, egid: *mut ::gid_t, + sgid: *mut ::gid_t) -> ::c_int; + pub fn acct(filename: *const ::c_char) -> ::c_int; + pub fn brk(addr: *mut ::c_void) -> ::c_int; + pub fn sbrk(increment: ::intptr_t) -> *mut ::c_void; + pub fn vfork() -> ::pid_t; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; + pub fn wait4(pid: ::pid_t, status: *mut ::c_int, options: ::c_int, + rusage: *mut ::rusage) -> ::pid_t; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *const termios, + winp: *const ::winsize) -> ::c_int; + pub fn forkpty(amaster: *mut ::c_int, + name: *mut ::c_char, + termp: *const termios, + winp: *const ::winsize) -> ::pid_t; + pub fn login_tty(fd: ::c_int) -> ::c_int; + pub fn execvpe(file: *const ::c_char, argv: *const *const ::c_char, + envp: *const *const ::c_char) -> ::c_int; + pub fn fexecve(fd: ::c_int, argv: *const *const ::c_char, + envp: *const *const ::c_char) + -> ::c_int; + pub fn getifaddrs(ifap: *mut *mut ::ifaddrs) -> ::c_int; + pub fn freeifaddrs(ifa: *mut ::ifaddrs); + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(target_os = "emscripten")] { + mod emscripten; + pub use self::emscripten::*; + } else if #[cfg(target_os = "linux")] { + mod linux; + pub use self::linux::*; + } else if #[cfg(target_os = "android")] { + mod android; + pub use self::android::*; + } else { + // Unknown target_os + } +} diff --git a/libc/src/unix/redox/mod.rs b/libc/src/unix/redox/mod.rs new file mode 100644 index 000000000..4bb1ab4ba --- /dev/null +++ b/libc/src/unix/redox/mod.rs @@ -0,0 +1,588 @@ +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type wchar_t = i32; + +pub type blkcnt_t = ::c_ulong; +pub type blksize_t = ::c_long; +pub type clock_t = ::c_long; +pub type clockid_t = ::c_int; +pub type dev_t = ::c_long; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type ino_t = ::c_ulong; +pub type mode_t = ::c_int; +pub type nfds_t = ::c_ulong; +pub type nlink_t = ::c_ulong; +pub type off_t = ::c_long; +pub type pthread_t = *mut ::c_void; +pub type pthread_attr_t = *mut ::c_void; +pub type pthread_cond_t = *mut ::c_void; +pub type pthread_condattr_t = *mut ::c_void; +// Must be usize due to libstd/sys_common/thread_local.rs, +// should technically be *mut ::c_void +pub type pthread_key_t = usize; +pub type pthread_mutex_t = *mut ::c_void; +pub type pthread_mutexattr_t = *mut ::c_void; +pub type pthread_rwlock_t = *mut ::c_void; +pub type pthread_rwlockattr_t = *mut ::c_void; +pub type rlim_t = ::c_ulonglong; +pub type sa_family_t = u16; +pub type sem_t = *mut ::c_void; +pub type sigset_t = ::c_ulong; +pub type socklen_t = u32; +pub type speed_t = u32; +pub type suseconds_t = ::c_int; +pub type tcflag_t = u32; +pub type time_t = ::c_long; + +s! { + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: ::size_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut ::addrinfo, + } + + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct epoll_event { + pub events: u32, + pub u64: u64, + pub _pad: u64, + } + + pub struct fd_set { + fds_bits: [::c_ulong; ::FD_SETSIZE / ULONG_SIZE], + } + + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: ::in_addr, + pub imr_interface: ::in_addr, + } + + pub struct lconv { + pub currency_symbol: *const ::c_char, + pub decimal_point: *const ::c_char, + pub frac_digits: ::c_char, + pub grouping: *const ::c_char, + pub int_curr_symbol: *const ::c_char, + pub int_frac_digits: ::c_char, + pub mon_decimal_point: *const ::c_char, + pub mon_grouping: *const ::c_char, + pub mon_thousands_sep: *const ::c_char, + pub negative_sign: *const ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub n_sign_posn: ::c_char, + pub positive_sign: *const ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub thousands_sep: *const ::c_char, + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct sigaction { + pub sa_handler: ::sighandler_t, + pub sa_flags: ::c_ulong, + pub sa_restorer: ::Option, + pub sa_mask: ::sigset_t, + } + + pub struct sockaddr { + pub sa_family: ::sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::c_char; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: ::sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct sockaddr_storage { + pub ss_family: ::sa_family_t, + __ss_padding: [ + u8; + 128 - + ::core::mem::size_of::() - + ::core::mem::size_of::() + ], + __ss_align: ::c_ulong, + } + + pub struct sockaddr_un { + pub sun_family: ::sa_family_t, + pub sun_path: [::c_char; 108] + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + _pad: [::c_char; 24], + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *const ::c_char, + } +} + +// TODO: relibc { + pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; +// } + +// dlfcn.h + +pub const RTLD_LAZY: ::c_int = 0x0001; +pub const RTLD_NOW: ::c_int = 0x0002; +pub const RTLD_GLOBAL: ::c_int = 0x0100; +pub const RTLD_LOCAL: ::c_int = 0x0000; + +// errno.h +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EDEADLK: ::c_int = 35; +pub const ENOSYS: ::c_int = 38; +pub const EWOULDBLOCK: ::c_int = 41; +pub const EADDRINUSE: ::c_int = 98; +pub const EADDRNOTAVAIL: ::c_int = 99; +pub const ECONNABORTED: ::c_int = 103; +pub const ECONNRESET: ::c_int = 104; +pub const ENOTCONN: ::c_int = 107; +pub const ETIMEDOUT: ::c_int = 110; +pub const ECONNREFUSED: ::c_int = 111; +pub const EINPROGRESS: ::c_int = 115; + +// fcntl.h +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; +// TODO: relibc { + pub const F_DUPFD_CLOEXEC: ::c_int = ::F_DUPFD; +// } +pub const FD_CLOEXEC: ::c_int = 0x0100_0000; +pub const O_RDONLY: ::c_int = 0x0001_0000; +pub const O_WRONLY: ::c_int = 0x0002_0000; +pub const O_RDWR: ::c_int = 0x0003_0000; +pub const O_ACCMODE: ::c_int = 0x0003_0000; +pub const O_NONBLOCK: ::c_int = 0x0004_0000; +pub const O_APPEND: ::c_int = 0x0008_0000; +pub const O_SHLOCK: ::c_int = 0x0010_0000; +pub const O_EXLOCK: ::c_int = 0x0020_0000; +pub const O_ASYNC: ::c_int = 0x0040_0000; +pub const O_FSYNC: ::c_int = 0x0080_0000; +pub const O_CLOEXEC: ::c_int = 0x0100_0000; +pub const O_CREAT: ::c_int = 0x0200_0000; +pub const O_TRUNC: ::c_int = 0x0400_0000; +pub const O_EXCL: ::c_int = 0x0800_0000; +pub const O_DIRECTORY: ::c_int = 0x1000_0000; +pub const O_PATH: ::c_int = 0x2000_0000; +pub const O_SYMLINK: ::c_int = 0x4000_0000; +// Negative to allow it to be used as int +// TODO: Fix negative values missing from includes +pub const O_NOFOLLOW: ::c_int = -0x8000_0000; + +// netdb.h +pub const EAI_SYSTEM: ::c_int = -11; + +// netinet/in.h +// TODO: relibc { + pub const IP_TTL: ::c_int = 2; + pub const IPV6_UNICAST_HOPS: ::c_int = 16; + pub const IPV6_MULTICAST_IF: ::c_int = 17; + pub const IPV6_MULTICAST_HOPS: ::c_int = 18; + pub const IPV6_MULTICAST_LOOP: ::c_int = 19; + pub const IPV6_ADD_MEMBERSHIP: ::c_int = 20; + pub const IPV6_DROP_MEMBERSHIP: ::c_int = 21; + pub const IPV6_V6ONLY: ::c_int = 26; + pub const IP_MULTICAST_IF: ::c_int = 32; + pub const IP_MULTICAST_TTL: ::c_int = 33; + pub const IP_MULTICAST_LOOP: ::c_int = 34; + pub const IP_ADD_MEMBERSHIP: ::c_int = 35; + pub const IP_DROP_MEMBERSHIP: ::c_int = 36; +// } + +// netinet/tcp.h +pub const TCP_NODELAY: ::c_int = 1; +// TODO: relibc { + pub const TCP_KEEPIDLE: ::c_int = 1; +// } + +// poll.h +pub const POLLIN: ::c_short = 0x001; +pub const POLLPRI: ::c_short = 0x002; +pub const POLLOUT: ::c_short = 0x004; +pub const POLLERR: ::c_short = 0x008; +pub const POLLHUP: ::c_short = 0x010; +pub const POLLNVAL: ::c_short = 0x020; + +// pthread.h +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_INITIALIZER: ::pthread_mutex_t = -1isize as *mut _; +pub const PTHREAD_COND_INITIALIZER: ::pthread_cond_t = -1isize as *mut _; +pub const PTHREAD_RWLOCK_INITIALIZER: ::pthread_rwlock_t = -1isize as *mut _; +pub const PTHREAD_STACK_MIN : ::size_t = 4096; + +// signal.h +pub const SIG_BLOCK: ::c_int = 0; +pub const SIG_UNBLOCK: ::c_int = 1; +pub const SIG_SETMASK: ::c_int = 2; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGTRAP: ::c_int = 5; +pub const SIGABRT: ::c_int = 6; +pub const SIGBUS: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGUSR1: ::c_int = 10; +pub const SIGSEGV: ::c_int = 11; +pub const SIGUSR2: ::c_int = 12; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; +pub const SIGSTKFLT: ::c_int = 16; +pub const SIGCHLD: ::c_int = 17; +pub const SIGCONT: ::c_int = 18; +pub const SIGSTOP: ::c_int = 19; +pub const SIGTSTP: ::c_int = 20; +pub const SIGTTIN: ::c_int = 21; +pub const SIGTTOU: ::c_int = 22; +pub const SIGURG: ::c_int = 23; +pub const SIGXCPU: ::c_int = 24; +pub const SIGXFSZ: ::c_int = 25; +pub const SIGVTALRM: ::c_int = 26; +pub const SIGPROF: ::c_int = 27; +pub const SIGWINCH: ::c_int = 28; +pub const SIGIO: ::c_int = 29; +pub const SIGPWR: ::c_int = 30; +pub const SIGSYS: ::c_int = 31; +pub const NSIG: ::c_int = 32; + +// sys/epoll.h +pub const EPOLL_CLOEXEC: ::c_int = 0x0100_0000; +pub const EPOLL_CTL_ADD: ::c_int = 1; +pub const EPOLL_CTL_DEL: ::c_int = 2; +pub const EPOLL_CTL_MOD: ::c_int = 3; +pub const EPOLLIN: ::c_int = 1; +pub const EPOLLPRI: ::c_int = 0; +pub const EPOLLOUT: ::c_int = 2; +pub const EPOLLRDNORM: ::c_int = 0; +pub const EPOLLNVAL: ::c_int = 0; +pub const EPOLLRDBAND: ::c_int = 0; +pub const EPOLLWRNORM: ::c_int = 0; +pub const EPOLLWRBAND: ::c_int = 0; +pub const EPOLLMSG: ::c_int = 0; +pub const EPOLLERR: ::c_int = 0; +pub const EPOLLHUP: ::c_int = 0; +pub const EPOLLRDHUP: ::c_int = 0; +pub const EPOLLEXCLUSIVE: ::c_int = 0; +pub const EPOLLWAKEUP: ::c_int = 0; +pub const EPOLLONESHOT: ::c_int = 0; +pub const EPOLLET: ::c_int = 0; + +// sys/stat.h +pub const S_IFMT: ::c_int = 0o0_170_000; +pub const S_IFDIR: ::c_int = 0o040_000; +pub const S_IFCHR: ::c_int = 0o020_000; +pub const S_IFBLK: ::c_int = 0o060_000; +pub const S_IFREG: ::c_int = 0o100_000; +pub const S_IFIFO: ::c_int = 0o010_000; +pub const S_IFLNK: ::c_int = 0o120_000; +pub const S_IFSOCK: ::c_int = 0o140_000; +pub const S_IRWXU: ::c_int = 0o0_700; +pub const S_IRUSR: ::c_int = 0o0_400; +pub const S_IWUSR: ::c_int = 0o0_200; +pub const S_IXUSR: ::c_int = 0o0_100; +pub const S_IRWXG: ::c_int = 0o0_070; +pub const S_IRGRP: ::c_int = 0o0_040; +pub const S_IWGRP: ::c_int = 0o0_020; +pub const S_IXGRP: ::c_int = 0o0_010; +pub const S_IRWXO: ::c_int = 0o0_007; +pub const S_IROTH: ::c_int = 0o0_004; +pub const S_IWOTH: ::c_int = 0o0_002; +pub const S_IXOTH: ::c_int = 0o0_001; + +// stdlib.h +pub const EXIT_SUCCESS: ::c_int = 0; +pub const EXIT_FAILURE: ::c_int = 1; + +// sys/ioctl.h +// TODO: relibc { + pub const FIONBIO: ::c_ulong = 0x5421; + pub const FIOCLEX: ::c_ulong = 0x5451; +// } +pub const TCGETS: ::c_ulong = 0x5401; +pub const TCSETS: ::c_ulong = 0x5402; +pub const TCFLSH: ::c_ulong = 0x540B; +pub const TIOCGPGRP: ::c_ulong = 0x540F; +pub const TIOCSPGRP: ::c_ulong = 0x5410; +pub const TIOCGWINSZ: ::c_ulong = 0x5413; +pub const TIOCSWINSZ: ::c_ulong = 0x5414; + +// sys/select.h +pub const FD_SETSIZE: usize = 1024; + +// sys/socket.h +pub const AF_UNIX: ::c_int = 1; +pub const AF_INET: ::c_int = 2; +pub const AF_INET6: ::c_int = 10; +pub const MSG_PEEK: ::c_int = 2; +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_ERROR: ::c_int = 4; +pub const SO_BROADCAST: ::c_int = 6; +pub const SO_SNDBUF: ::c_int = 7; +pub const SO_RCVBUF: ::c_int = 8; +pub const SO_KEEPALIVE: ::c_int = 9; +pub const SO_LINGER: ::c_int = 13; +pub const SO_REUSEPORT: ::c_int = 15; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const SOCK_STREAM: ::c_int = 1; +pub const SOCK_DGRAM: ::c_int = 2; +pub const SOL_SOCKET: ::c_int = 1; + +// sys/wait.h +pub const WNOHANG: ::c_int = 1; + +// termios.h +pub const NCCS: usize = 32; + +// time.h +pub const CLOCK_REALTIME: ::c_int = 1; +pub const CLOCK_MONOTONIC: ::c_int = 4; + +// unistd.h +pub const _SC_PAGESIZE: ::c_int = 30; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +// wait.h +pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0xff) == 0x7f +} + +pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff +} + +pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0xffff +} + +pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7f +} + +pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0x7f) == 0 +} + +pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff +} + +pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x80) != 0 +} + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +extern { + // malloc.h + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + + // pthread.h + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn pthread_create(tid: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + start: extern fn(*mut ::c_void) -> *mut ::c_void, + arg: *mut ::c_void) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + + // signal.h + pub fn pthread_sigmask(how: ::c_int, + set: *const ::sigset_t, + oldset: *mut ::sigset_t) -> ::c_int; + + // sys/epoll.h + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + + // sys/ioctl.h + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + + // sys/socket.h + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + + // sys/uio.h + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + // time.h + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; +} diff --git a/libc/src/unix/solarish/compat.rs b/libc/src/unix/solarish/compat.rs new file mode 100644 index 000000000..8631d6018 --- /dev/null +++ b/libc/src/unix/solarish/compat.rs @@ -0,0 +1,21 @@ +// Common functions that are unfortunately missing on illumos and +// Solaris, but often needed by other crates. + +use unix::solarish::*; + +pub unsafe fn cfmakeraw(termios: *mut ::termios) { + let mut t = *termios as ::termios; + t.c_iflag &= !(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t.c_oflag &= !OPOST; + t.c_lflag &= !(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + t.c_cflag &= !(CSIZE|PARENB); + t.c_cflag |= CS8; +} + +pub unsafe fn cfsetspeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int { + // Neither of these functions on illumos or Solaris actually ever + // return an error + ::cfsetispeed(termios, speed); + ::cfsetospeed(termios, speed); + 0 +} diff --git a/libc/src/unix/solarish/mod.rs b/libc/src/unix/solarish/mod.rs new file mode 100644 index 000000000..1092d152d --- /dev/null +++ b/libc/src/unix/solarish/mod.rs @@ -0,0 +1,2031 @@ +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; + +pub type clockid_t = ::c_int; +pub type blkcnt_t = ::c_long; +pub type clock_t = ::c_long; +pub type daddr_t = ::c_long; +pub type dev_t = ::c_ulong; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type ino_t = ::c_ulong; +pub type key_t = ::c_int; +pub type major_t = ::c_uint; +pub type minor_t = ::c_uint; +pub type mode_t = ::c_uint; +pub type nlink_t = ::c_uint; +pub type rlim_t = ::c_ulong; +pub type speed_t = ::c_uint; +pub type tcflag_t = ::c_uint; +pub type time_t = ::c_long; +pub type wchar_t = ::c_int; +pub type nfds_t = ::c_ulong; + +pub type suseconds_t = ::c_long; +pub type off_t = ::c_long; +pub type useconds_t = ::c_uint; +pub type socklen_t = ::c_uint; +pub type sa_family_t = u16; +pub type pthread_t = ::c_uint; +pub type pthread_key_t = ::c_uint; +pub type blksize_t = ::c_int; +pub type nl_item = ::c_int; +pub type id_t = ::c_int; +pub type idtype_t = ::c_uint; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [::c_char; 8] + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + pub __sin6_src_id: u32 + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_age: *mut ::c_char, + pub pw_comment: *mut ::c_char, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut ::c_char, + pub ifa_flags: ::c_ulong, + pub ifa_addr: *mut ::sockaddr, + pub ifa_netmask: *mut ::sockaddr, + pub ifa_dstaddr: *mut ::sockaddr, + pub ifa_data: *mut ::c_void + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::socklen_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct pthread_attr_t { + __pthread_attrp: *mut ::c_void + } + + pub struct pthread_mutex_t { + __pthread_mutex_flag1: u16, + __pthread_mutex_flag2: u8, + __pthread_mutex_ceiling: u8, + __pthread_mutex_type: u16, + __pthread_mutex_magic: u16, + __pthread_mutex_lock: u64, + __pthread_mutex_data: u64 + } + + pub struct pthread_mutexattr_t { + __pthread_mutexattrp: *mut ::c_void + } + + pub struct pthread_cond_t { + __pthread_cond_flag: [u8; 4], + __pthread_cond_type: u16, + __pthread_cond_magic: u16, + __pthread_cond_data: u64 + } + + pub struct pthread_condattr_t { + __pthread_condattrp: *mut ::c_void, + } + + pub struct pthread_rwlock_t { + __pthread_rwlock_readers: i32, + __pthread_rwlock_type: u16, + __pthread_rwlock_magic: u16, + __pthread_rwlock_mutex: ::pthread_mutex_t, + __pthread_rwlock_readercv: ::pthread_cond_t, + __pthread_rwlock_writercv: ::pthread_cond_t + } + + pub struct pthread_rwlockattr_t { + __pthread_rwlockattrp: *mut ::c_void, + } + + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: u16, + pub d_name: [::c_char; 3] + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut ::c_char, + pub gl_offs: ::size_t, + __unused1: *mut ::c_void, + __unused2: ::c_int, + __unused3: ::c_int, + __unused4: ::c_int, + __unused5: *mut ::c_void, + __unused6: *mut ::c_void, + __unused7: *mut ::c_void, + __unused8: *mut ::c_void, + __unused9: *mut ::c_void, + __unused10: *mut ::c_void, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + #[cfg(target_arch = "sparc64")] + __sparcv9_pad: ::c_int, + pub ai_addrlen: ::socklen_t, + pub ai_canonname: *mut ::c_char, + pub ai_addr: *mut ::sockaddr, + pub ai_next: *mut addrinfo, + } + + pub struct sigset_t { + bits: [u32; 4], + } + + pub struct sigaction { + pub sa_flags: ::c_int, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + pub ss_sp: *mut ::c_void, + pub sigev_notify_attributes: *const ::pthread_attr_t, + __sigev_pad2: ::c_int, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + pub f_fsid: ::c_ulong, + pub f_basetype: [::c_char; 16], + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + pub f_fstr: [::c_char; 32] + } + + pub struct sched_param { + pub sched_priority: ::c_int, + sched_pad: [::c_int; 8] + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct stat { + pub st_dev: ::dev_t, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_size: ::off_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + __unused: [::c_char; 16] + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_cc: [::cc_t; ::NCCS] + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct sem_t { + pub sem_count: u32, + pub sem_type: u16, + pub sem_magic: u16, + pub sem_pad1: [u64; 3], + pub sem_pad2: [u64; 2] + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_sysid: ::c_int, + pub l_pid: ::pid_t, + pub l_pad: [::c_long; 4] + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } + + pub struct port_event { + pub portev_events: ::c_int, + pub portev_source: ::c_ushort, + pub portev_pad: ::c_ushort, + pub portev_object: ::uintptr_t, + pub portev_user: *mut ::c_void, + } +} + +s_no_extra_traits! { + #[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))] + pub struct epoll_event { + pub events: ::uint32_t, + pub u64: ::uint64_t, + } + + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [c_char; 108] + } + + pub struct utsname { + pub sysname: [::c_char; 257], + pub nodename: [::c_char; 257], + pub release: [::c_char; 257], + pub version: [::c_char; 257], + pub machine: [::c_char; 257], + } + + pub struct fd_set { + #[cfg(target_pointer_width = "64")] + fds_bits: [i64; FD_SETSIZE / 64], + #[cfg(target_pointer_width = "32")] + fds_bits: [i32; FD_SETSIZE / 32], + } + + pub struct sockaddr_storage { + pub ss_family: ::sa_family_t, + __ss_pad1: [u8; 6], + __ss_align: i64, + __ss_pad2: [u8; 240], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub si_pad: ::c_int, + pub si_addr: *mut ::c_void, + __pad: [u8; 232], + } + + pub struct sockaddr_dl { + pub sdl_family: ::c_ushort, + pub sdl_index: ::c_ushort, + pub sdl_type: ::c_uchar, + pub sdl_nlen: ::c_uchar, + pub sdl_alen: ::c_uchar, + pub sdl_slen: ::c_uchar, + pub sdl_data: [::c_char; 244], + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for epoll_event { + fn eq(&self, other: &epoll_event) -> bool { + self.events == other.events + && self.u64 == other.u64 + } + } + impl Eq for epoll_event {} + impl ::fmt::Debug for epoll_event { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + let events = self.events; + let u64 = self.u64; + f.debug_struct("epoll_event") + .field("events", &events) + .field("u64", &u64) + .finish() + } + } + impl ::hash::Hash for epoll_event { + fn hash(&self, state: &mut H) { + let events = self.events; + let u64 = self.u64; + events.hash(state); + u64.hash(state); + } + } + + impl PartialEq for sockaddr_un { + fn eq(&self, other: &sockaddr_un) -> bool { + self.sun_family == other.sun_family + && self + .sun_path + .iter() + .zip(other.sun_path.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_un {} + impl ::fmt::Debug for sockaddr_un { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_un") + .field("sun_family", &self.sun_family) + // FIXME: .field("sun_path", &self.sun_path) + .finish() + } + } + impl ::hash::Hash for sockaddr_un { + fn hash(&self, state: &mut H) { + self.sun_family.hash(state); + self.sun_path.hash(state); + } + } + + impl PartialEq for utsname { + fn eq(&self, other: &utsname) -> bool { + self.sysname + .iter() + .zip(other.sysname.iter()) + .all(|(a, b)| a == b) + && self + .nodename + .iter() + .zip(other.nodename.iter()) + .all(|(a, b)| a == b) + && self + .release + .iter() + .zip(other.release.iter()) + .all(|(a, b)| a == b) + && self + .version + .iter() + .zip(other.version.iter()) + .all(|(a, b)| a == b) + && self + .machine + .iter() + .zip(other.machine.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for utsname {} + impl ::fmt::Debug for utsname { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("utsname") + // FIXME: .field("sysname", &self.sysname) + // FIXME: .field("nodename", &self.nodename) + // FIXME: .field("release", &self.release) + // FIXME: .field("version", &self.version) + // FIXME: .field("machine", &self.machine) + .finish() + } + } + impl ::hash::Hash for utsname { + fn hash(&self, state: &mut H) { + self.sysname.hash(state); + self.nodename.hash(state); + self.release.hash(state); + self.version.hash(state); + self.machine.hash(state); + } + } + + impl PartialEq for fd_set { + fn eq(&self, other: &fd_set) -> bool { + self.fds_bits + .iter() + .zip(other.fds_bits.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for fd_set {} + impl ::fmt::Debug for fd_set { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("fd_set") + // FIXME: .field("fds_bits", &self.fds_bits) + .finish() + } + } + impl ::hash::Hash for fd_set { + fn hash(&self, state: &mut H) { + self.fds_bits.hash(state); + } + } + + impl PartialEq for sockaddr_storage { + fn eq(&self, other: &sockaddr_storage) -> bool { + self.ss_family == other.ss_family + && self.__ss_pad1 == other.__ss_pad1 + && self.__ss_align == other.__ss_align + && self + .__ss_pad2 + .iter() + .zip(other.__ss_pad2.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for sockaddr_storage {} + impl ::fmt::Debug for sockaddr_storage { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_storage") + .field("ss_family", &self.ss_family) + .field("__ss_pad1", &self.__ss_pad1) + .field("__ss_align", &self.__ss_align) + // FIXME: .field("__ss_pad2", &self.__ss_pad2) + .finish() + } + } + impl ::hash::Hash for sockaddr_storage { + fn hash(&self, state: &mut H) { + self.ss_family.hash(state); + self.__ss_pad1.hash(state); + self.__ss_align.hash(state); + self.__ss_pad2.hash(state); + } + } + + impl PartialEq for siginfo_t { + fn eq(&self, other: &siginfo_t) -> bool { + self.si_signo == other.si_signo + && self.si_code == other.si_code + && self.si_errno == other.si_errno + && self.si_addr == other.si_addr + && self + .__pad + .iter() + .zip(other.__pad.iter()) + .all(|(a, b)| a == b) + } + } + impl Eq for siginfo_t {} + impl ::fmt::Debug for siginfo_t { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("siginfo_t") + .field("si_signo", &self.si_signo) + .field("si_code", &self.si_code) + .field("si_errno", &self.si_errno) + .field("si_addr", &self.si_addr) + // FIXME: .field("__pad", &self.__pad) + .finish() + } + } + impl ::hash::Hash for siginfo_t { + fn hash(&self, state: &mut H) { + self.si_signo.hash(state); + self.si_code.hash(state); + self.si_errno.hash(state); + self.si_addr.hash(state); + self.__pad.hash(state); + } + } + + impl PartialEq for sockaddr_dl { + fn eq(&self, other: &sockaddr_dl) -> bool { + self.sdl_family == other.sdl_family + && self.sdl_index == other.sdl_index + && self.sdl_type == other.sdl_type + && self.sdl_nlen == other.sdl_nlen + && self.sdl_alen == other.sdl_alen + && self.sdl_slen == other.sdl_slen + && self + .sdl_data + .iter() + .zip(other.sdl_data.iter()) + .all(|(a,b)| a == b) + } + } + impl Eq for sockaddr_dl {} + impl ::fmt::Debug for sockaddr_dl { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + f.debug_struct("sockaddr_dl") + .field("sdl_family", &self.sdl_family) + .field("sdl_index", &self.sdl_index) + .field("sdl_type", &self.sdl_type) + .field("sdl_nlen", &self.sdl_nlen) + .field("sdl_alen", &self.sdl_alen) + .field("sdl_slen", &self.sdl_slen) + // FIXME: .field("sdl_data", &self.sdl_data) + .finish() + } + } + impl ::hash::Hash for sockaddr_dl { + fn hash(&self, state: &mut H) { + self.sdl_family.hash(state); + self.sdl_index.hash(state); + self.sdl_type.hash(state); + self.sdl_nlen.hash(state); + self.sdl_alen.hash(state); + self.sdl_slen.hash(state); + self.sdl_data.hash(state); + } + } + } +} + +pub const LC_CTYPE: ::c_int = 0; +pub const LC_NUMERIC: ::c_int = 1; +pub const LC_TIME: ::c_int = 2; +pub const LC_COLLATE: ::c_int = 3; +pub const LC_MONETARY: ::c_int = 4; +pub const LC_MESSAGES: ::c_int = 5; +pub const LC_ALL: ::c_int = 6; +pub const LC_CTYPE_MASK: ::c_int = (1 << LC_CTYPE); +pub const LC_NUMERIC_MASK: ::c_int = (1 << LC_NUMERIC); +pub const LC_TIME_MASK: ::c_int = (1 << LC_TIME); +pub const LC_COLLATE_MASK: ::c_int = (1 << LC_COLLATE); +pub const LC_MONETARY_MASK: ::c_int = (1 << LC_MONETARY); +pub const LC_MESSAGES_MASK: ::c_int = (1 << LC_MESSAGES); +pub const LC_ALL_MASK: ::c_int = LC_CTYPE_MASK + | LC_NUMERIC_MASK + | LC_TIME_MASK + | LC_COLLATE_MASK + | LC_MONETARY_MASK + | LC_MESSAGES_MASK; + +pub const DAY_1: ::nl_item = 1; +pub const DAY_2: ::nl_item = 2; +pub const DAY_3: ::nl_item = 3; +pub const DAY_4: ::nl_item = 4; +pub const DAY_5: ::nl_item = 5; +pub const DAY_6: ::nl_item = 6; +pub const DAY_7: ::nl_item = 7; + +pub const ABDAY_1: ::nl_item = 8; +pub const ABDAY_2: ::nl_item = 9; +pub const ABDAY_3: ::nl_item = 10; +pub const ABDAY_4: ::nl_item = 11; +pub const ABDAY_5: ::nl_item = 12; +pub const ABDAY_6: ::nl_item = 13; +pub const ABDAY_7: ::nl_item = 14; + +pub const MON_1: ::nl_item = 15; +pub const MON_2: ::nl_item = 16; +pub const MON_3: ::nl_item = 17; +pub const MON_4: ::nl_item = 18; +pub const MON_5: ::nl_item = 19; +pub const MON_6: ::nl_item = 20; +pub const MON_7: ::nl_item = 21; +pub const MON_8: ::nl_item = 22; +pub const MON_9: ::nl_item = 23; +pub const MON_10: ::nl_item = 24; +pub const MON_11: ::nl_item = 25; +pub const MON_12: ::nl_item = 26; + +pub const ABMON_1: ::nl_item = 27; +pub const ABMON_2: ::nl_item = 28; +pub const ABMON_3: ::nl_item = 29; +pub const ABMON_4: ::nl_item = 30; +pub const ABMON_5: ::nl_item = 31; +pub const ABMON_6: ::nl_item = 32; +pub const ABMON_7: ::nl_item = 33; +pub const ABMON_8: ::nl_item = 34; +pub const ABMON_9: ::nl_item = 35; +pub const ABMON_10: ::nl_item = 36; +pub const ABMON_11: ::nl_item = 37; +pub const ABMON_12: ::nl_item = 38; + +pub const RADIXCHAR: ::nl_item = 39; +pub const THOUSEP: ::nl_item = 40; +pub const YESSTR: ::nl_item = 41; +pub const NOSTR: ::nl_item = 42; +pub const CRNCYSTR: ::nl_item = 43; + +pub const D_T_FMT: ::nl_item = 44; +pub const D_FMT: ::nl_item = 45; +pub const T_FMT: ::nl_item = 46; +pub const AM_STR: ::nl_item = 47; +pub const PM_STR: ::nl_item = 48; + +pub const CODESET: ::nl_item = 49; +pub const T_FMT_AMPM: ::nl_item = 50; +pub const ERA: ::nl_item = 51; +pub const ERA_D_FMT: ::nl_item = 52; +pub const ERA_D_T_FMT: ::nl_item = 53; +pub const ERA_T_FMT: ::nl_item = 54; +pub const ALT_DIGITS: ::nl_item = 55; +pub const YESEXPR: ::nl_item = 56; +pub const NOEXPR: ::nl_item = 57; +pub const _DATE_FMT: ::nl_item = 58; +pub const MAXSTRMSG: ::nl_item = 58; + +pub const PATH_MAX: ::c_int = 1024; + +pub const SA_ONSTACK: ::c_int = 0x00000001; +pub const SA_RESETHAND: ::c_int = 0x00000002; +pub const SA_RESTART: ::c_int = 0x00000004; +pub const SA_SIGINFO: ::c_int = 0x00000008; +pub const SA_NODEFER: ::c_int = 0x00000010; +pub const SA_NOCLDWAIT: ::c_int = 0x00010000; +pub const SA_NOCLDSTOP: ::c_int = 0x00020000; + +pub const SS_ONSTACK: ::c_int = 1; +pub const SS_DISABLE: ::c_int = 2; + +pub const FIOCLEX: ::c_int = 0x20006601; +pub const FIONCLEX: ::c_int = 0x20006602; +pub const FIONREAD: ::c_int = 0x4004667f; +pub const FIONBIO: ::c_int = 0x8004667e; +pub const FIOASYNC: ::c_int = 0x8004667d; +pub const FIOSETOWN: ::c_int = 0x8004667c; +pub const FIOGETOWN: ::c_int = 0x4004667b; + +pub const SIGCHLD: ::c_int = 18; +pub const SIGBUS: ::c_int = 10; +pub const SIGINFO: ::c_int = 41; +pub const SIG_BLOCK: ::c_int = 1; +pub const SIG_UNBLOCK: ::c_int = 2; +pub const SIG_SETMASK: ::c_int = 3; + +pub const SIGEV_NONE: ::c_int = 1; +pub const SIGEV_SIGNAL: ::c_int =2; +pub const SIGEV_THREAD: ::c_int = 3; + +pub const IPV6_UNICAST_HOPS: ::c_int = 0x5; +pub const IPV6_MULTICAST_IF: ::c_int = 0x6; +pub const IPV6_MULTICAST_HOPS: ::c_int = 0x7; +pub const IPV6_MULTICAST_LOOP: ::c_int = 0x8; +pub const IPV6_V6ONLY: ::c_int = 0x27; + +cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub const FD_SETSIZE: usize = 65536; + } else { + pub const FD_SETSIZE: usize = 1024; + } +} + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; + +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 32767; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 4; +pub const _IOLBF: ::c_int = 64; +pub const BUFSIZ: ::c_uint = 1024; +pub const FOPEN_MAX: ::c_uint = 20; +pub const FILENAME_MAX: ::c_uint = 1024; +pub const L_tmpnam: ::c_uint = 25; +pub const TMP_MAX: ::c_uint = 17576; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_NDELAY: ::c_int = 0x04; +pub const O_APPEND: ::c_int = 8; +pub const O_DSYNC: ::c_int = 0x40; +pub const O_CREAT: ::c_int = 256; +pub const O_EXCL: ::c_int = 1024; +pub const O_NOCTTY: ::c_int = 2048; +pub const O_TRUNC: ::c_int = 512; +pub const O_NOFOLLOW: ::c_int = 0x200000; +pub const O_SEARCH: ::c_int = 0x200000; +pub const O_EXEC: ::c_int = 0x400000; +pub const O_CLOEXEC: ::c_int = 0x800000; +pub const O_ACCMODE: ::c_int = 0x600003; +pub const S_IFIFO: mode_t = 4096; +pub const S_IFCHR: mode_t = 8192; +pub const S_IFBLK: mode_t = 24576; +pub const S_IFDIR: mode_t = 16384; +pub const S_IFREG: mode_t = 32768; +pub const S_IFLNK: mode_t = 40960; +pub const S_IFSOCK: mode_t = 49152; +pub const S_IFMT: mode_t = 61440; +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; +pub const S_IRWXU: mode_t = 448; +pub const S_IXUSR: mode_t = 64; +pub const S_IWUSR: mode_t = 128; +pub const S_IRUSR: mode_t = 256; +pub const S_IRWXG: mode_t = 56; +pub const S_IXGRP: mode_t = 8; +pub const S_IWGRP: mode_t = 16; +pub const S_IRGRP: mode_t = 32; +pub const S_IRWXO: mode_t = 7; +pub const S_IXOTH: mode_t = 1; +pub const S_IWOTH: mode_t = 2; +pub const S_IROTH: mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; +pub const F_DUPFD_CLOEXEC: ::c_int = 37; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; +pub const F_GETLK: ::c_int = 14; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGEMT: ::c_int = 7; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGSYS: ::c_int = 12; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; +pub const SIGUSR1: ::c_int = 16; +pub const SIGUSR2: ::c_int = 17; +pub const SIGPWR: ::c_int = 19; +pub const SIGWINCH: ::c_int = 20; +pub const SIGURG: ::c_int = 21; +pub const SIGPOLL: ::c_int = 22; +pub const SIGIO: ::c_int = SIGPOLL; +pub const SIGSTOP: ::c_int = 23; +pub const SIGTSTP: ::c_int = 24; +pub const SIGCONT: ::c_int = 25; +pub const SIGTTIN: ::c_int = 26; +pub const SIGTTOU: ::c_int = 27; +pub const SIGVTALRM: ::c_int = 28; +pub const SIGPROF: ::c_int = 29; +pub const SIGXCPU: ::c_int = 30; +pub const SIGXFSZ: ::c_int = 31; + +pub const WNOHANG: ::c_int = 0x40; +pub const WUNTRACED: ::c_int = 0x04; + +pub const WEXITED: ::c_int = 0x01; +pub const WTRAPPED: ::c_int = 0x02; +pub const WSTOPPED: ::c_int = WUNTRACED; +pub const WCONTINUED: ::c_int = 0x08; +pub const WNOWAIT: ::c_int = 0x80; + +pub const AT_FDCWD: ::c_int = 0xffd19553; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x1000; + +pub const P_PID: idtype_t = 0; +pub const P_PPID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; +pub const P_SID: idtype_t = 3; +pub const P_CID: idtype_t = 4; +pub const P_UID: idtype_t = 5; +pub const P_GID: idtype_t = 6; +pub const P_ALL: idtype_t = 7; +pub const P_LWPID: idtype_t = 8; +pub const P_TASKID: idtype_t = 9; +pub const P_PROJID: idtype_t = 10; +pub const P_POOLID: idtype_t = 11; +pub const P_ZONEID: idtype_t = 12; +pub const P_CTID: idtype_t = 13; +pub const P_CPUID: idtype_t = 14; +pub const P_PSETID: idtype_t = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const MAP_FILE: ::c_int = 0; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; +pub const MAP_NORESERVE: ::c_int = 0x40; +pub const MAP_ANON: ::c_int = 0x0100; +pub const MAP_RENAME: ::c_int = 0x20; +pub const MAP_ALIGN: ::c_int = 0x200; +pub const MAP_TEXT: ::c_int = 0x400; +pub const MAP_INITDATA: ::c_int = 0x800; +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const MS_SYNC: ::c_int = 0x0004; +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; +pub const MS_INVALCURPROC: ::c_int = 0x0008; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const ECHRNG: ::c_int = 37; +pub const EL2NSYNC: ::c_int = 38; +pub const EL3HLT: ::c_int = 39; +pub const EL3RST: ::c_int = 40; +pub const ELNRNG: ::c_int = 41; +pub const EUNATCH: ::c_int = 42; +pub const ENOCSI: ::c_int = 43; +pub const EL2HLT: ::c_int = 44; +pub const EDEADLK: ::c_int = 45; +pub const ENOLCK: ::c_int = 46; +pub const ECANCELED: ::c_int = 47; +pub const ENOTSUP: ::c_int = 48; +pub const EDQUOT: ::c_int = 49; +pub const EBADE: ::c_int = 50; +pub const EBADR: ::c_int = 51; +pub const EXFULL: ::c_int = 52; +pub const ENOANO: ::c_int = 53; +pub const EBADRQC: ::c_int = 54; +pub const EBADSLT: ::c_int = 55; +pub const EDEADLOCK: ::c_int = 56; +pub const EBFONT: ::c_int = 57; +pub const EOWNERDEAD: ::c_int = 58; +pub const ENOTRECOVERABLE: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const ELOCKUNMAPPED: ::c_int = 72; +pub const ENOTACTIVE: ::c_int = 73; +pub const EMULTIHOP: ::c_int = 74; +pub const EADI: ::c_int = 75; +pub const EBADMSG: ::c_int = 77; +pub const ENAMETOOLONG: ::c_int = 78; +pub const EOVERFLOW: ::c_int = 79; +pub const ENOTUNIQ: ::c_int = 80; +pub const EBADFD: ::c_int = 81; +pub const EREMCHG: ::c_int = 82; +pub const ELIBACC: ::c_int = 83; +pub const ELIBBAD: ::c_int = 84; +pub const ELIBSCN: ::c_int = 85; +pub const ELIBMAX: ::c_int = 86; +pub const ELIBEXEC: ::c_int = 87; +pub const EILSEQ: ::c_int = 88; +pub const ENOSYS: ::c_int = 89; +pub const ELOOP: ::c_int = 90; +pub const ERESTART: ::c_int = 91; +pub const ESTRPIPE: ::c_int = 92; +pub const ENOTEMPTY: ::c_int = 93; +pub const EUSERS: ::c_int = 94; +pub const ENOTSOCK: ::c_int = 95; +pub const EDESTADDRREQ: ::c_int = 96; +pub const EMSGSIZE: ::c_int = 97; +pub const EPROTOTYPE: ::c_int = 98; +pub const ENOPROTOOPT: ::c_int = 99; +pub const EPROTONOSUPPORT: ::c_int = 120; +pub const ESOCKTNOSUPPORT: ::c_int = 121; +pub const EOPNOTSUPP: ::c_int = 122; +pub const EPFNOSUPPORT: ::c_int = 123; +pub const EAFNOSUPPORT: ::c_int = 124; +pub const EADDRINUSE: ::c_int = 125; +pub const EADDRNOTAVAIL: ::c_int = 126; +pub const ENETDOWN: ::c_int = 127; +pub const ENETUNREACH: ::c_int = 128; +pub const ENETRESET: ::c_int = 129; +pub const ECONNABORTED: ::c_int = 130; +pub const ECONNRESET: ::c_int = 131; +pub const ENOBUFS: ::c_int = 132; +pub const EISCONN: ::c_int = 133; +pub const ENOTCONN: ::c_int = 134; +pub const ESHUTDOWN: ::c_int = 143; +pub const ETOOMANYREFS: ::c_int = 144; +pub const ETIMEDOUT: ::c_int = 145; +pub const ECONNREFUSED: ::c_int = 146; +pub const EHOSTDOWN: ::c_int = 147; +pub const EHOSTUNREACH: ::c_int = 148; +pub const EWOULDBLOCK: ::c_int = EAGAIN; +pub const EALREADY: ::c_int = 149; +pub const EINPROGRESS: ::c_int = 150; +pub const ESTALE: ::c_int = 151; + +pub const EAI_AGAIN: ::c_int = 2; +pub const EAI_BADFLAGS: ::c_int = 3; +pub const EAI_FAIL: ::c_int = 4; +pub const EAI_FAMILY: ::c_int = 5; +pub const EAI_MEMORY: ::c_int = 6; +pub const EAI_NODATA: ::c_int = 7; +pub const EAI_NONAME: ::c_int = 8; +pub const EAI_SERVICE: ::c_int = 9; +pub const EAI_SOCKTYPE: ::c_int = 10; +pub const EAI_SYSTEM: ::c_int = 11; +pub const EAI_OVERFLOW: ::c_int = 12; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; + +pub const SIGTRAP: ::c_int = 5; + +pub const GLOB_APPEND : ::c_int = 32; +pub const GLOB_DOOFFS : ::c_int = 16; +pub const GLOB_ERR : ::c_int = 1; +pub const GLOB_MARK : ::c_int = 2; +pub const GLOB_NOCHECK : ::c_int = 8; +pub const GLOB_NOSORT : ::c_int = 4; +pub const GLOB_NOESCAPE: ::c_int = 64; + +pub const GLOB_NOSPACE : ::c_int = -2; +pub const GLOB_ABORTED : ::c_int = -1; +pub const GLOB_NOMATCH : ::c_int = -3; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; +pub const POLLNORM: ::c_short = 0x0040; +pub const POLLRDNORM: ::c_short = 0x0040; +pub const POLLWRNORM: ::c_short = 0x4; /* POLLOUT */ +pub const POLLRDBAND: ::c_short = 0x0080; +pub const POLLWRBAND: ::c_short = 0x0100; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; + +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 0x40; +pub const PTHREAD_PROCESS_SHARED: ::c_int = 1; +pub const PTHREAD_PROCESS_PRIVATE: ::c_ushort = 0; +pub const PTHREAD_STACK_MIN: ::size_t = 4096; + +pub const SIGSTKSZ: ::size_t = 8192; + +// https://illumos.org/man/3c/clock_gettime +// https://github.com/illumos/illumos-gate/ +// blob/HEAD/usr/src/lib/libc/amd64/sys/__clock_gettime.s +// clock_gettime(3c) doesn't seem to accept anything other than CLOCK_REALTIME +// or __CLOCK_REALTIME0 +// +// https://github.com/illumos/illumos-gate/ +// blob/HEAD/usr/src/uts/common/sys/time_impl.h +// Confusing! CLOCK_HIGHRES==CLOCK_MONOTONIC==4 +// __CLOCK_REALTIME0==0 is an obsoleted version of CLOCK_REALTIME==3 +pub const CLOCK_REALTIME: ::clockid_t = 3; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; +pub const TIMER_RELTIME: ::c_int = 0; +pub const TIMER_ABSTIME: ::c_int = 1; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_NOFILE: ::c_int = 5; +pub const RLIMIT_VMEM: ::c_int = 6; +pub const RLIMIT_AS: ::c_int = RLIMIT_VMEM; + +pub const RLIM_NLIMITS: rlim_t = 7; +pub const RLIM_INFINITY: rlim_t = 0x7fffffff; + +pub const RUSAGE_SELF: ::c_int = 0; +pub const RUSAGE_CHILDREN: ::c_int = -1; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_FREE: ::c_int = 5; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_UNIX: ::c_int = 1; +pub const AF_LOCAL: ::c_int = 0; +pub const AF_FILE: ::c_int = 0; +pub const AF_INET: ::c_int = 2; +pub const AF_IMPLINK: ::c_int = 3; +pub const AF_PUP: ::c_int = 4; +pub const AF_CHAOS: ::c_int = 5; +pub const AF_NS: ::c_int = 6; +pub const AF_NBS: ::c_int = 7; +pub const AF_ECMA: ::c_int = 8; +pub const AF_DATAKIT: ::c_int = 9; +pub const AF_CCITT: ::c_int = 10; +pub const AF_SNA: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_DLI: ::c_int = 13; +pub const AF_LAT: ::c_int = 14; +pub const AF_HYLINK: ::c_int = 15; +pub const AF_APPLETALK: ::c_int = 16; +pub const AF_NIT: ::c_int = 17; +pub const AF_802: ::c_int = 18; +pub const AF_OSI: ::c_int = 19; +pub const AF_X25: ::c_int = 20; +pub const AF_OSINET: ::c_int = 21; +pub const AF_GOSIP: ::c_int = 22; +pub const AF_IPX: ::c_int = 23; +pub const AF_ROUTE: ::c_int = 24; +pub const AF_LINK: ::c_int = 25; +pub const AF_INET6: ::c_int = 26; +pub const AF_KEY: ::c_int = 27; +pub const AF_NCA: ::c_int = 28; +pub const AF_POLICY: ::c_int = 29; +pub const AF_INET_OFFLOAD: ::c_int = 30; +pub const AF_TRILL: ::c_int = 31; +pub const AF_PACKET: ::c_int = 32; +pub const AF_LX_NETLINK: ::c_int = 33; +pub const AF_MAX: ::c_int = 33; +pub const SOCK_DGRAM: ::c_int = 1; +pub const SOCK_STREAM: ::c_int = 2; +pub const SOCK_RAW: ::c_int = 4; +pub const SOCK_RDM: ::c_int = 5; +pub const SOCK_SEQPACKET: ::c_int = 6; +pub const IP_MULTICAST_IF: ::c_int = 16; +pub const IP_MULTICAST_TTL: ::c_int = 17; +pub const IP_MULTICAST_LOOP: ::c_int = 18; +pub const IP_TTL: ::c_int = 4; +pub const IP_HDRINCL: ::c_int = 2; +pub const IP_ADD_MEMBERSHIP: ::c_int = 19; +pub const IP_DROP_MEMBERSHIP: ::c_int = 20; +pub const IPV6_JOIN_GROUP: ::c_int = 9; +pub const IPV6_LEAVE_GROUP: ::c_int = 10; + +pub const TCP_NODELAY: ::c_int = 1; +pub const TCP_KEEPIDLE: ::c_int = 34; +pub const SOL_SOCKET: ::c_int = 0xffff; +pub const SO_DEBUG: ::c_int = 0x01; +pub const SO_ACCEPTCONN: ::c_int = 0x0002; +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_USELOOPBACK: ::c_int = 0x0040; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_TIMESTAMP: ::c_int = 0x1013; + +pub const SCM_RIGHTS: ::c_int = 0x1010; +pub const SCM_UCRED: ::c_int = 0x1012; +pub const SCM_TIMESTAMP: ::c_int = SO_TIMESTAMP; + +pub const MSG_OOB: ::c_int = 0x1; +pub const MSG_PEEK: ::c_int = 0x2; +pub const MSG_DONTROUTE: ::c_int = 0x4; +pub const MSG_EOR: ::c_int = 0x8; +pub const MSG_CTRUNC: ::c_int = 0x10; +pub const MSG_TRUNC: ::c_int = 0x20; +pub const MSG_WAITALL: ::c_int = 0x40; +pub const MSG_DONTWAIT: ::c_int = 0x80; +pub const MSG_NOTIFICATION: ::c_int = 0x100; +pub const MSG_NOSIGNAL: ::c_int = 0x200; +pub const MSG_DUPCTRL: ::c_int = 0x800; +pub const MSG_XPG4_2: ::c_int = 0x8000; +pub const MSG_MAXIOVLEN: ::c_int = 16; + +// https://docs.oracle.com/cd/E23824_01/html/821-1475/if-7p.html +pub const IFF_UP: ::c_int = 0x0000000001; // Address is up +pub const IFF_BROADCAST: ::c_int = 0x0000000002; // Broadcast address valid +pub const IFF_DEBUG: ::c_int = 0x0000000004; // Turn on debugging +pub const IFF_LOOPBACK: ::c_int = 0x0000000008; // Loopback net +pub const IFF_POINTOPOINT: ::c_int = 0x0000000010; // Interface is p-to-p +pub const IFF_NOTRAILERS: ::c_int = 0x0000000020; // Avoid use of trailers +pub const IFF_RUNNING: ::c_int = 0x0000000040; // Resources allocated +pub const IFF_NOARP: ::c_int = 0x0000000080; // No address res. protocol +pub const IFF_PROMISC: ::c_int = 0x0000000100; // Receive all packets +pub const IFF_ALLMULTI: ::c_int = 0x0000000200; // Receive all multicast pkts +pub const IFF_INTELLIGENT: ::c_int = 0x0000000400; // Protocol code on board +pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast +// Multicast using broadcst. add. +pub const IFF_MULTI_BCAST: ::c_int = 0x0000001000; +pub const IFF_UNNUMBERED: ::c_int = 0x0000002000; // Non-unique address +pub const IFF_DHCPRUNNING: ::c_int = 0x0000004000; // DHCP controls interface +pub const IFF_PRIVATE: ::c_int = 0x0000008000; // Do not advertise +pub const IFF_NOXMIT: ::c_int = 0x0000010000; // Do not transmit pkts +// No address - just on-link subnet +pub const IFF_NOLOCAL: ::c_int = 0x0000020000; +pub const IFF_DEPRECATED: ::c_int = 0x0000040000; // Address is deprecated +pub const IFF_ADDRCONF: ::c_int = 0x0000080000; // Addr. from stateless addrconf +pub const IFF_ROUTER: ::c_int = 0x0000100000; // Router on interface +pub const IFF_NONUD: ::c_int = 0x0000200000; // No NUD on interface +pub const IFF_ANYCAST: ::c_int = 0x0000400000; // Anycast address +pub const IFF_NORTEXCH: ::c_int = 0x0000800000; // Don't xchange rout. info +pub const IFF_IPV4: ::c_int = 0x0001000000; // IPv4 interface +pub const IFF_IPV6: ::c_int = 0x0002000000; // IPv6 interface +pub const IFF_NOFAILOVER: ::c_int = 0x0008000000; // in.mpathd test address +pub const IFF_FAILED: ::c_int = 0x0010000000; // Interface has failed +pub const IFF_STANDBY: ::c_int = 0x0020000000; // Interface is a hot-spare +pub const IFF_INACTIVE: ::c_int = 0x0040000000; // Functioning but not used +pub const IFF_OFFLINE: ::c_int = 0x0080000000; // Interface is offline +// If CoS marking is supported +pub const IFF_COS_ENABLED: ::c_longlong = 0x0200000000; +pub const IFF_PREFERRED: ::c_longlong = 0x0400000000; // Prefer as source addr. +pub const IFF_TEMPORARY: ::c_longlong = 0x0800000000; // RFC3041 +pub const IFF_FIXEDMTU: ::c_longlong = 0x1000000000; // MTU set with SIOCSLIFMTU +pub const IFF_VIRTUAL: ::c_longlong = 0x2000000000; // Cannot send/receive pkts +pub const IFF_DUPLICATE: ::c_longlong = 0x4000000000; // Local address in use +pub const IFF_IPMP: ::c_longlong = 0x8000000000; // IPMP IP interface + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const F_RDLCK: ::c_short = 1; +pub const F_WRLCK: ::c_short = 2; +pub const F_UNLCK: ::c_short = 3; + +pub const O_SYNC: ::c_int = 16; +pub const O_NONBLOCK: ::c_int = 128; + +pub const IPPROTO_RAW: ::c_int = 255; + +pub const _PC_LINK_MAX: ::c_int = 1; +pub const _PC_MAX_CANON: ::c_int = 2; +pub const _PC_MAX_INPUT: ::c_int = 3; +pub const _PC_NAME_MAX: ::c_int = 4; +pub const _PC_PATH_MAX: ::c_int = 5; +pub const _PC_PIPE_BUF: ::c_int = 6; +pub const _PC_NO_TRUNC: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 9; +pub const _PC_ASYNC_IO: ::c_int = 10; +pub const _PC_PRIO_IO: ::c_int = 11; +pub const _PC_SYNC_IO: ::c_int = 12; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 13; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 14; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 15; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 16; +pub const _PC_REC_XFER_ALIGN: ::c_int = 17; +pub const _PC_SYMLINK_MAX: ::c_int = 18; +pub const _PC_2_SYMLINKS: ::c_int = 19; +pub const _PC_ACL_ENABLED: ::c_int = 20; +pub const _PC_MIN_HOLE_SIZE: ::c_int = 21; +pub const _PC_CASE_BEHAVIOR: ::c_int = 22; +pub const _PC_SATTR_ENABLED: ::c_int = 23; +pub const _PC_SATTR_EXISTS: ::c_int = 24; +pub const _PC_ACCESS_FILTERING: ::c_int = 25; +pub const _PC_TIMESTAMP_RESOLUTION: ::c_int = 26; +pub const _PC_FILESIZEBITS: ::c_int = 67; +pub const _PC_XATTR_ENABLED: ::c_int = 100; +pub const _PC_LAST: ::c_int = 101; +pub const _PC_XATTR_EXISTS: ::c_int = 101; + +pub const _SC_ARG_MAX: ::c_int = 1; +pub const _SC_CHILD_MAX: ::c_int = 2; +pub const _SC_CLK_TCK: ::c_int = 3; +pub const _SC_NGROUPS_MAX: ::c_int = 4; +pub const _SC_OPEN_MAX: ::c_int = 5; +pub const _SC_JOB_CONTROL: ::c_int = 6; +pub const _SC_SAVED_IDS: ::c_int = 7; +pub const _SC_VERSION: ::c_int = 8; +pub const _SC_PASS_MAX: ::c_int = 9; +pub const _SC_LOGNAME_MAX: ::c_int = 10; +pub const _SC_PAGESIZE: ::c_int = 11; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_XOPEN_VERSION: ::c_int = 12; +pub const _SC_NPROCESSORS_CONF: ::c_int = 14; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 15; +pub const _SC_STREAM_MAX: ::c_int = 16; +pub const _SC_TZNAME_MAX: ::c_int = 17; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 18; +pub const _SC_AIO_MAX: ::c_int = 19; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 20; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 21; +pub const _SC_DELAYTIMER_MAX: ::c_int = 22; +pub const _SC_FSYNC: ::c_int = 23; +pub const _SC_MAPPED_FILES: ::c_int = 24; +pub const _SC_MEMLOCK: ::c_int = 25; +pub const _SC_MEMLOCK_RANGE: ::c_int = 26; +pub const _SC_MEMORY_PROTECTION: ::c_int = 27; +pub const _SC_MESSAGE_PASSING: ::c_int = 28; +pub const _SC_MQ_OPEN_MAX: ::c_int = 29; +pub const _SC_MQ_PRIO_MAX: ::c_int = 30; +pub const _SC_PRIORITIZED_IO: ::c_int = 31; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 32; +pub const _SC_REALTIME_SIGNALS: ::c_int = 33; +pub const _SC_RTSIG_MAX: ::c_int = 34; +pub const _SC_SEMAPHORES: ::c_int = 35; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 36; +pub const _SC_SEM_VALUE_MAX: ::c_int = 37; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 38; +pub const _SC_SIGQUEUE_MAX: ::c_int = 39; +pub const _SC_SIGRT_MIN: ::c_int = 40; +pub const _SC_SIGRT_MAX: ::c_int = 41; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 42; +pub const _SC_TIMERS: ::c_int = 43; +pub const _SC_TIMER_MAX: ::c_int = 44; +pub const _SC_2_C_BIND: ::c_int = 45; +pub const _SC_2_C_DEV: ::c_int = 46; +pub const _SC_2_C_VERSION: ::c_int = 47; +pub const _SC_2_FORT_DEV: ::c_int = 48; +pub const _SC_2_FORT_RUN: ::c_int = 49; +pub const _SC_2_LOCALEDEF: ::c_int = 50; +pub const _SC_2_SW_DEV: ::c_int = 51; +pub const _SC_2_UPE: ::c_int = 52; +pub const _SC_2_VERSION: ::c_int = 53; +pub const _SC_BC_BASE_MAX: ::c_int = 54; +pub const _SC_BC_DIM_MAX: ::c_int = 55; +pub const _SC_BC_SCALE_MAX: ::c_int = 56; +pub const _SC_BC_STRING_MAX: ::c_int = 57; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 58; +pub const _SC_EXPR_NEST_MAX: ::c_int = 59; +pub const _SC_LINE_MAX: ::c_int = 60; +pub const _SC_RE_DUP_MAX: ::c_int = 61; +pub const _SC_XOPEN_CRYPT: ::c_int = 62; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 63; +pub const _SC_XOPEN_SHM: ::c_int = 64; +pub const _SC_2_CHAR_TERM: ::c_int = 66; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 67; +pub const _SC_ATEXIT_MAX: ::c_int = 76; +pub const _SC_IOV_MAX: ::c_int = 77; +pub const _SC_XOPEN_UNIX: ::c_int = 78; +pub const _SC_T_IOV_MAX: ::c_int = 79; +pub const _SC_PHYS_PAGES: ::c_int = 500; +pub const _SC_AVPHYS_PAGES: ::c_int = 501; +pub const _SC_COHER_BLKSZ: ::c_int = 503; +pub const _SC_SPLIT_CACHE: ::c_int = 504; +pub const _SC_ICACHE_SZ: ::c_int = 505; +pub const _SC_DCACHE_SZ: ::c_int = 506; +pub const _SC_ICACHE_LINESZ: ::c_int = 507; +pub const _SC_DCACHE_LINESZ: ::c_int = 508; +pub const _SC_ICACHE_BLKSZ: ::c_int = 509; +pub const _SC_DCACHE_BLKSZ: ::c_int = 510; +pub const _SC_DCACHE_TBLKSZ: ::c_int = 511; +pub const _SC_ICACHE_ASSOC: ::c_int = 512; +pub const _SC_DCACHE_ASSOC: ::c_int = 513; +pub const _SC_MAXPID: ::c_int = 514; +pub const _SC_STACK_PROT: ::c_int = 515; +pub const _SC_NPROCESSORS_MAX: ::c_int = 516; +pub const _SC_CPUID_MAX: ::c_int = 517; +pub const _SC_EPHID_MAX: ::c_int = 518; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 568; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 569; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 570; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 571; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 572; +pub const _SC_THREAD_STACK_MIN: ::c_int = 573; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 574; +pub const _SC_TTY_NAME_MAX: ::c_int = 575; +pub const _SC_THREADS: ::c_int = 576; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 577; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 578; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 579; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 580; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 581; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 582; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 583; +pub const _SC_XOPEN_LEGACY: ::c_int = 717; +pub const _SC_XOPEN_REALTIME: ::c_int = 718; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 719; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 720; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 721; +pub const _SC_XBS5_LP64_OFF64: ::c_int = 722; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 723; +pub const _SC_2_PBS: ::c_int = 724; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 725; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 726; +pub const _SC_2_PBS_LOCATE: ::c_int = 728; +pub const _SC_2_PBS_MESSAGE: ::c_int = 729; +pub const _SC_2_PBS_TRACK: ::c_int = 730; +pub const _SC_ADVISORY_INFO: ::c_int = 731; +pub const _SC_BARRIERS: ::c_int = 732; +pub const _SC_CLOCK_SELECTION: ::c_int = 733; +pub const _SC_CPUTIME: ::c_int = 734; +pub const _SC_HOST_NAME_MAX: ::c_int = 735; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 736; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 737; +pub const _SC_REGEXP: ::c_int = 738; +pub const _SC_SHELL: ::c_int = 739; +pub const _SC_SPAWN: ::c_int = 740; +pub const _SC_SPIN_LOCKS: ::c_int = 741; +pub const _SC_SPORADIC_SERVER: ::c_int = 742; +pub const _SC_SS_REPL_MAX: ::c_int = 743; +pub const _SC_SYMLOOP_MAX: ::c_int = 744; +pub const _SC_THREAD_CPUTIME: ::c_int = 745; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 746; +pub const _SC_TIMEOUTS: ::c_int = 747; +pub const _SC_TRACE: ::c_int = 748; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 749; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 750; +pub const _SC_TRACE_INHERIT: ::c_int = 751; +pub const _SC_TRACE_LOG: ::c_int = 752; +pub const _SC_TRACE_NAME_MAX: ::c_int = 753; +pub const _SC_TRACE_SYS_MAX: ::c_int = 754; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 755; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 756; +pub const _SC_V6_ILP32_OFF32: ::c_int = 757; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 758; +pub const _SC_V6_LP64_OFF64: ::c_int = 759; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 760; +pub const _SC_XOPEN_STREAMS: ::c_int = 761; +pub const _SC_IPV6: ::c_int = 762; +pub const _SC_RAW_SOCKETS: ::c_int = 763; + +pub const _MUTEX_MAGIC: u16 = 0x4d58; // MX +pub const _COND_MAGIC: u16 = 0x4356; // CV +pub const _RWL_MAGIC: u16 = 0x5257; // RW + +pub const NCCS: usize = 19; + +pub const LOG_CRON: ::c_int = 15 << 3; + +pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + __pthread_mutex_flag1: 0, + __pthread_mutex_flag2: 0, + __pthread_mutex_ceiling: 0, + __pthread_mutex_type: PTHREAD_PROCESS_PRIVATE, + __pthread_mutex_magic: _MUTEX_MAGIC, + __pthread_mutex_lock: 0, + __pthread_mutex_data: 0 +}; +pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + __pthread_cond_flag: [0; 4], + __pthread_cond_type: PTHREAD_PROCESS_PRIVATE, + __pthread_cond_magic: _COND_MAGIC, + __pthread_cond_data: 0 +}; +pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + __pthread_rwlock_readers: 0, + __pthread_rwlock_type: PTHREAD_PROCESS_PRIVATE, + __pthread_rwlock_magic: _RWL_MAGIC, + __pthread_rwlock_mutex: PTHREAD_MUTEX_INITIALIZER, + __pthread_rwlock_readercv: PTHREAD_COND_INITIALIZER, + __pthread_rwlock_writercv: PTHREAD_COND_INITIALIZER +}; +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 4; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; + +pub const RTLD_NEXT: *mut ::c_void = -1isize as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = -2isize as *mut ::c_void; +pub const RTLD_SELF: *mut ::c_void = -3isize as *mut ::c_void; +pub const RTLD_PROBE: *mut ::c_void = -4isize as *mut ::c_void; + +pub const RTLD_LAZY: ::c_int = 0x1; +pub const RTLD_NOW: ::c_int = 0x2; +pub const RTLD_NOLOAD: ::c_int = 0x4; +pub const RTLD_GLOBAL: ::c_int = 0x100; +pub const RTLD_LOCAL: ::c_int = 0x0; +pub const RTLD_PARENT: ::c_int = 0x200; +pub const RTLD_GROUP: ::c_int = 0x400; +pub const RTLD_WORLD: ::c_int = 0x800; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_FIRST: ::c_int = 0x2000; +pub const RTLD_CONFGEN: ::c_int = 0x10000; + +pub const PORT_SOURCE_AIO: ::c_int = 1; +pub const PORT_SOURCE_TIMER: ::c_int = 2; +pub const PORT_SOURCE_USER: ::c_int = 3; +pub const PORT_SOURCE_FD: ::c_int = 4; +pub const PORT_SOURCE_ALERT: ::c_int = 5; +pub const PORT_SOURCE_MQ: ::c_int = 6; +pub const PORT_SOURCE_FILE: ::c_int = 7; +pub const PORT_SOURCE_POSTWAIT: ::c_int = 8; +pub const PORT_SOURCE_SIGNAL: ::c_int = 9; + +const _TIOC: ::c_int = ('T' as i32) << 8; +const tIOC: ::c_int = ('t' as i32) << 8; +pub const TCGETA: ::c_int = (_TIOC|1); +pub const TCSETA: ::c_int = (_TIOC|2); +pub const TCSETAW: ::c_int = (_TIOC|3); +pub const TCSETAF: ::c_int = (_TIOC|4); +pub const TCSBRK: ::c_int = (_TIOC|5); +pub const TCXONC: ::c_int = (_TIOC|6); +pub const TCFLSH: ::c_int = (_TIOC|7); +pub const TCDSET: ::c_int = (_TIOC|32); +pub const TCGETS: ::c_int = (_TIOC|13); +pub const TCSETS: ::c_int = (_TIOC|14); +pub const TCSANOW: ::c_int = (_TIOC|14); +pub const TCSETSW: ::c_int = (_TIOC|15); +pub const TCSADRAIN: ::c_int = (_TIOC|15); +pub const TCSETSF: ::c_int = (_TIOC|16); +pub const TCSAFLUSH: ::c_int = (_TIOC|16); +pub const TCIFLUSH: ::c_int = 0; +pub const TCOFLUSH: ::c_int = 1; +pub const TCIOFLUSH: ::c_int = 2; +pub const TCOOFF: ::c_int = 0; +pub const TCOON: ::c_int = 1; +pub const TCIOFF: ::c_int = 2; +pub const TCION: ::c_int = 3; +pub const TIOC: ::c_int = _TIOC; +pub const TIOCKBON: ::c_int = (_TIOC|8); +pub const TIOCKBOF: ::c_int = (_TIOC|9); +pub const TIOCGWINSZ: ::c_int = (_TIOC|104); +pub const TIOCSWINSZ: ::c_int = (_TIOC|103); +pub const TIOCGSOFTCAR: ::c_int = (_TIOC|105); +pub const TIOCSSOFTCAR: ::c_int = (_TIOC|106); +pub const TIOCSETLD: ::c_int = (_TIOC|123); +pub const TIOCGETLD: ::c_int = (_TIOC|124); +pub const TIOCGPPS: ::c_int = (_TIOC|125); +pub const TIOCSPPS: ::c_int = (_TIOC|126); +pub const TIOCGPPSEV: ::c_int = (_TIOC|127); +pub const TIOCGETD: ::c_int = (tIOC|0); +pub const TIOCSETD: ::c_int = (tIOC|1); +pub const TIOCHPCL: ::c_int = (tIOC|2); +pub const TIOCGETP: ::c_int = (tIOC|8); +pub const TIOCSETP: ::c_int = (tIOC|9); +pub const TIOCSETN: ::c_int = (tIOC|10); +pub const TIOCEXCL: ::c_int = (tIOC|13); +pub const TIOCNXCL: ::c_int = (tIOC|14); +pub const TIOCFLUSH: ::c_int = (tIOC|16); +pub const TIOCSETC: ::c_int = (tIOC|17); +pub const TIOCGETC: ::c_int = (tIOC|18); +pub const TIOCLBIS: ::c_int = (tIOC|127); +pub const TIOCLBIC: ::c_int = (tIOC|126); +pub const TIOCLSET: ::c_int = (tIOC|125); +pub const TIOCLGET: ::c_int = (tIOC|124); +pub const TIOCSBRK: ::c_int = (tIOC|123); +pub const TIOCCBRK: ::c_int = (tIOC|122); +pub const TIOCSDTR: ::c_int = (tIOC|121); +pub const TIOCCDTR: ::c_int = (tIOC|120); +pub const TIOCSLTC: ::c_int = (tIOC|117); +pub const TIOCGLTC: ::c_int = (tIOC|116); +pub const TIOCOUTQ: ::c_int = (tIOC|115); +pub const TIOCNOTTY: ::c_int = (tIOC|113); +pub const TIOCSCTTY: ::c_int = (tIOC|132); +pub const TIOCSTOP: ::c_int = (tIOC|111); +pub const TIOCSTART: ::c_int = (tIOC|110); +pub const TIOCSILOOP: ::c_int = (tIOC|109); +pub const TIOCCILOOP: ::c_int = (tIOC|108); +pub const TIOCGPGRP: ::c_int = (tIOC|20); +pub const TIOCSPGRP: ::c_int = (tIOC|21); +pub const TIOCGSID: ::c_int = (tIOC|22); +pub const TIOCSTI: ::c_int = (tIOC|23); +pub const TIOCMSET: ::c_int = (tIOC|26); +pub const TIOCMBIS: ::c_int = (tIOC|27); +pub const TIOCMBIC: ::c_int = (tIOC|28); +pub const TIOCMGET: ::c_int = (tIOC|29); +pub const TIOCREMOTE: ::c_int = (tIOC|30); +pub const TIOCSIGNAL: ::c_int = (tIOC|31); + +pub const EPOLLIN: ::c_int = 0x1; +pub const EPOLLPRI: ::c_int = 0x2; +pub const EPOLLOUT: ::c_int = 0x4; +pub const EPOLLRDNORM: ::c_int = 0x40; +pub const EPOLLRDBAND: ::c_int = 0x80; +pub const EPOLLWRNORM: ::c_int = 0x100; +pub const EPOLLWRBAND: ::c_int = 0x200; +pub const EPOLLMSG: ::c_int = 0x400; +pub const EPOLLERR: ::c_int = 0x8; +pub const EPOLLHUP: ::c_int = 0x10; +pub const EPOLLET: ::c_int = 0x80000000; +pub const EPOLLRDHUP: ::c_int = 0x2000; +pub const EPOLLEXCLUSIVE: ::c_int = 0x10000000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; +pub const EPOLL_CTL_ADD: ::c_int = 1; +pub const EPOLL_CTL_MOD: ::c_int = 3; +pub const EPOLL_CTL_DEL: ::c_int = 2; + +/* termios */ +pub const B0: speed_t = 0; +pub const B50: speed_t = 1; +pub const B75: speed_t = 2; +pub const B110: speed_t = 3; +pub const B134: speed_t = 4; +pub const B150: speed_t = 5; +pub const B200: speed_t = 6; +pub const B300: speed_t = 7; +pub const B600: speed_t = 8; +pub const B1200: speed_t = 9; +pub const B1800: speed_t = 10; +pub const B2400: speed_t = 11; +pub const B4800: speed_t = 12; +pub const B9600: speed_t = 13; +pub const B19200: speed_t = 14; +pub const B38400: speed_t = 15; +pub const B57600: speed_t = 16; +pub const B76800: speed_t = 17; +pub const B115200: speed_t = 18; +pub const B153600: speed_t = 19; +pub const B230400: speed_t = 20; +pub const B307200: speed_t = 21; +pub const B460800: speed_t = 22; +pub const B921600: speed_t = 23; +pub const CSTART: ::tcflag_t = 021; +pub const CSTOP: ::tcflag_t = 023; +pub const CSWTCH: ::tcflag_t = 032; +pub const CSIZE: ::tcflag_t = 0o000060; +pub const CS5: ::tcflag_t = 0; +pub const CS6: ::tcflag_t = 0o000020; +pub const CS7: ::tcflag_t = 0o000040; +pub const CS8: ::tcflag_t = 0o000060; +pub const CSTOPB: ::tcflag_t = 0o000100; +pub const ECHO: ::tcflag_t = 0o000010; +pub const ECHOE: ::tcflag_t = 0o000020; +pub const ECHOK: ::tcflag_t = 0o000040; +pub const ECHONL: ::tcflag_t = 0o000100; +pub const ECHOCTL: ::tcflag_t = 0o001000; +pub const ECHOPRT: ::tcflag_t = 0o002000; +pub const ECHOKE: ::tcflag_t = 0o004000; +pub const EXTPROC: ::tcflag_t = 0o200000; +pub const IGNBRK: ::tcflag_t = 0o000001; +pub const BRKINT: ::tcflag_t = 0o000002; +pub const IGNPAR: ::tcflag_t = 0o000004; +pub const PARMRK: ::tcflag_t = 0o000010; +pub const INPCK: ::tcflag_t = 0o000020; +pub const ISTRIP: ::tcflag_t = 0o000040; +pub const INLCR: ::tcflag_t = 0o000100; +pub const IGNCR: ::tcflag_t = 0o000200; +pub const ICRNL: ::tcflag_t = 0o000400; +pub const IXON: ::tcflag_t = 0o002000; +pub const IXOFF: ::tcflag_t = 0o010000; +pub const IXANY: ::tcflag_t = 0o004000; +pub const IMAXBEL: ::tcflag_t = 0o020000; +pub const OPOST: ::tcflag_t = 0o000001; +pub const ONLCR: ::tcflag_t = 0o000004; +pub const OCRNL: ::tcflag_t = 0o000010; +pub const ONOCR: ::tcflag_t = 0o000020; +pub const ONLRET: ::tcflag_t = 0o000040; +pub const CREAD: ::tcflag_t = 0o000200; +pub const PARENB: ::tcflag_t = 0o000400; +pub const PARODD: ::tcflag_t = 0o001000; +pub const HUPCL: ::tcflag_t = 0o002000; +pub const CLOCAL: ::tcflag_t = 0o004000; +pub const CRTSCTS: ::tcflag_t = 0o20000000000; +pub const ISIG: ::tcflag_t = 0o000001; +pub const ICANON: ::tcflag_t = 0o000002; +pub const IEXTEN: ::tcflag_t = 0o100000; +pub const TOSTOP: ::tcflag_t = 0o000400; +pub const FLUSHO: ::tcflag_t = 0o020000; +pub const PENDIN: ::tcflag_t = 0o040000; +pub const NOFLSH: ::tcflag_t = 0o000200; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VEOF: usize = 4; +pub const VEOL: usize = 5; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const VTIME: usize = 5; +pub const VSWTCH: usize = 7; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VSUSP: usize = 10; +pub const VDSUSP: usize = 11; +pub const VREPRINT: usize = 12; +pub const VDISCARD: usize = 13; +pub const VWERASE: usize = 14; +pub const VLNEXT: usize = 15; +pub const VSTATUS: usize = 16; +pub const VERASE2: usize = 17; + +f! { + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] &= !(1 << (fd % bits)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + return ((*set).fds_bits[fd / bits] & (1 << (fd % bits))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let bits = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + let fd = fd as usize; + (*set).fds_bits[fd / bits] |= 1 << (fd % bits); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0xFF) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xFF + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7F + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + (status & 0xffff) == 0xffff + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status & 0xff00) >> 8 + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status & 0xff) > 0) && (status & 0xff00 == 0) + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + ((status & 0xff) == 0x7f) && ((status & 0xff00) != 0) + } + + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x80) != 0 + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn abs(i: ::c_int) -> ::c_int; + pub fn acct(filename: *const ::c_char) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn getifaddrs(ifap: *mut *mut ::ifaddrs) -> ::c_int; + pub fn freeifaddrs(ifa: *mut ::ifaddrs); + + pub fn stack_getbounds(sp: *mut ::stack_t) -> ::c_int; + pub fn mincore(addr: *const ::c_void, len: ::size_t, + vec: *mut c_char) -> ::c_int; + pub fn initgroups(name: *const ::c_char, basegid: ::gid_t) -> ::c_int; + pub fn setgroups(ngroups: ::c_int, + ptr: *const ::gid_t) -> ::c_int; + pub fn ioctl(fildes: ::c_int, request: ::c_int, ...) -> ::c_int; + pub fn mprotect(addr: *const ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn ___errno() -> *mut ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_nanosleep(clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + pub fn getnameinfo(sa: *const ::sockaddr, + salen: ::socklen_t, + host: *mut ::c_char, + hostlen: ::socklen_t, + serv: *mut ::c_char, + sevlen: ::socklen_t, + flags: ::c_int) -> ::c_int; + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn getprogname() -> *const ::c_char; + pub fn setprogname(name: *const ::c_char); + pub fn getloadavg(loadavg: *mut ::c_double, nelem: ::c_int) -> ::c_int; + pub fn getpriority(which: ::c_int, who: ::c_int) -> ::c_int; + pub fn setpriority(which: ::c_int, who: ::c_int, prio: ::c_int) -> ::c_int; + + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::c_int) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + + pub fn glob(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + + pub fn globfree(pglob: *mut ::glob_t); + + pub fn posix_madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn shm_open(name: *const ::c_char, oflag: ::c_int, mode: ::mode_t) + -> ::c_int; + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn mkstemps(template: *mut ::c_char, suffixlen: ::c_int) -> ::c_int; + pub fn futimesat(fd: ::c_int, path: *const ::c_char, + times: *const ::timeval) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + #[cfg_attr(target_os = "illumos", link_name = "__xnet_bind")] + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + #[cfg_attr(target_os = "illumos", link_name = "__xnet_sendmsg")] + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + #[cfg_attr(target_os = "illumos", link_name = "__xnet_recvmsg")] + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + + pub fn port_create() -> ::c_int; + pub fn port_associate(port: ::c_int, source: ::c_int, object: ::uintptr_t, + events: ::c_int, user: *mut ::c_void) -> ::c_int; + pub fn port_dissociate(port: ::c_int, source: ::c_int, object: ::uintptr_t) + -> ::c_int; + pub fn port_get(port: ::c_int, pe: *mut port_event, + timeout: *mut ::timespec) -> ::c_int; + pub fn port_getn(port: ::c_int, pe_list: *mut port_event, max: ::c_uint, + nget: *mut ::c_uint, timeout: *mut ::timespec) + -> ::c_int; + pub fn fexecve(fd: ::c_int, argv: *const *const ::c_char, + envp: *const *const ::c_char) + -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + + // The epoll functions are actually only present on illumos. However, + // there are things using epoll on illumos (built using the + // x86_64-sun-solaris target) which would break until the illumos target is + // present in rustc. + pub fn epoll_pwait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int, + sigmask: *const ::sigset_t) -> ::c_int; + + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getpwent_r")] + pub fn getpwent_r(pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_getgrent_r")] + pub fn getgrent_r(grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), + link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + pub fn setgrent(); + pub fn endgrent(); + pub fn getgrent() -> *mut ::group; + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + + pub fn dup3(src: ::c_int, dst: ::c_int, flags: ::c_int) -> ::c_int; + pub fn uname(buf: *mut ::utsname) -> ::c_int; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; +} + +mod compat; +pub use self::compat::*; diff --git a/libc/src/unix/uclibc/align.rs b/libc/src/unix/uclibc/align.rs new file mode 100644 index 000000000..3307c9d16 --- /dev/null +++ b/libc/src/unix/uclibc/align.rs @@ -0,0 +1,66 @@ +macro_rules! expand_align { + () => { + s! { + #[cfg_attr(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64"), + repr(align(4)))] + #[cfg_attr(not(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64")), + repr(align(8)))] + pub struct pthread_mutexattr_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + #[repr(align(8))] + #[allow(missing_debug_implementations)] + pub struct pthread_cond_t { + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))), + repr(align(8)))] + #[allow(missing_debug_implementations)] + pub struct pthread_mutex_t { + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))), + repr(align(8)))] + #[allow(missing_debug_implementations)] + pub struct pthread_rwlock_t { + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + } + } +} diff --git a/libc/src/unix/uclibc/arm/align.rs b/libc/src/unix/uclibc/arm/align.rs new file mode 100644 index 000000000..4a0e07460 --- /dev/null +++ b/libc/src/unix/uclibc/arm/align.rs @@ -0,0 +1,13 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/uclibc/arm/mod.rs b/libc/src/unix/uclibc/arm/mod.rs new file mode 100644 index 000000000..b250fb539 --- /dev/null +++ b/libc/src/unix/uclibc/arm/mod.rs @@ -0,0 +1,687 @@ +pub type c_char = u8; +pub type wchar_t = ::c_uint; +pub type c_long = i32; +pub type c_ulong = u32; +pub type time_t = ::c_long; + +pub type clock_t = ::c_long; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type ino_t = ::c_ulong; +pub type off_t = ::c_long; +pub type pthread_t = ::c_ulong; +pub type rlim_t = ::c_ulong; +pub type suseconds_t = ::c_long; + +pub type nlink_t = ::c_uint; +pub type blksize_t = ::c_long; +pub type blkcnt_t = ::c_long; + +s! { + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::socklen_t, + pub msg_flags: ::c_int, + } + + pub struct pthread_attr_t { + __size: [::c_long; 9], + } + + pub struct stat { + pub st_dev: ::c_ulonglong, + pub __pad1: ::c_ushort, + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulonglong, + pub __pad2: ::c_ushort, + pub st_size: ::off_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atim: ::timespec, + pub st_mtim: ::timespec, + pub st_ctim: ::timespec, + pub __unused4: ::c_ulong, + pub __unused5: ::c_ulong, + } + + pub struct stat64 + { + pub st_dev: ::c_ulonglong, + pub __pad1: ::c_uint, + pub __st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulonglong, + pub __pad2: ::c_uint, + pub st_size: ::off64_t, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt64_t, + pub st_atim: ::timespec, + pub st_mtim: ::timespec, + pub st_ctim: ::timespec, + pub st_ino: ::ino64_t, + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_pid: ::pid_t, + } + + pub struct statfs { + pub f_type: ::c_int, + pub f_bsize: ::c_int, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + + pub f_fsid: ::fsid_t, + pub f_namelen: ::c_int, + pub f_frsize: ::c_int, + pub f_spare: [::c_int; 5], + } + + pub struct sigset_t { + __val: [::c_ulong; 2], + } + + pub struct sigaction { + pub sa_sigaction: ::sighandler_t, + // uClibc defines sa_flags as `unsigned long int`, + // but nix crate expects `int` + pub sa_flags: ::c_int, + pub sa_restorer: *mut ::c_void, + pub sa_mask: sigset_t, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + pub c_ispeed: ::speed_t, + pub c_ospeed: ::speed_t, + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_errno: ::c_int, + pub si_code: ::c_int, + pub _pad: [::c_int; 29], + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + ss_flags: ::c_int, + ss_size: ::size_t, + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_ushort, + pub __pad1: ::c_ushort, + pub __seq: ::c_ushort, + pub __pad2: ::c_ushort, + pub __unused1: ::c_ulong, + pub __unused2: ::c_ulong, + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub __unused1: ::c_ulong, + pub msg_rtime: ::time_t, + pub __unused2: ::c_ulong, + pub msg_ctime: ::time_t, + pub __unused3: ::c_ulong, + pub __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + pub __unused4: ::c_ulong, + pub __unused5: ::c_ulong, + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub __unused1: ::c_ulong, + pub shm_dtime: ::time_t, + pub __unused2: ::c_ulong, + pub shm_ctime: ::time_t, + pub __unused3: ::c_ulong, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + pub __unused4: ::c_ulong, + pub __unused5: ::c_ulong, + } + + pub struct ucred { + pub pid: ::pid_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + } + +} + +pub const O_CLOEXEC: ::c_int = 0o2000000; +pub const RLIM_INFINITY: rlim_t = !0; +pub const __SIZEOF_PTHREAD_ATTR_T: usize = 36; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_COND_COMPAT_T: usize = 12; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8; +pub const __SIZEOF_PTHREAD_BARRIER_T: usize = 20; +pub const __SIZEOF_PTHREAD_BARRIERATTR_T: usize = 4; +pub const NCCS: usize = 32; + +// I wasn't able to find those constants +// in uclibc build environment for armv7 +pub const AIO_ALLDONE: ::c_int = 2; // from linux/mod.rs +pub const AIO_CANCELED: ::c_int = 0; // from linux/mod.rs +pub const AIO_NOTCANCELED: ::c_int = 1; // from linux/mod.rs +pub const CLONE_NEWCGROUP: ::c_int = 0x02000000; // from linux/mod.rs +pub const EPOLLEXCLUSIVE: ::c_int = 0x10000000; // from linux/mod.rs +pub const EPOLLWAKEUP: ::c_int = 0x20000000; // from linux/other/mod.rs +pub const EXTPROC: ::tcflag_t = 0o200000; // from asm-generic/termbits.h +pub const F_GETPIPE_SZ: ::c_int = 1032; // from notbsd/mod.rs +pub const F_SETPIPE_SZ: ::c_int = 1031; // from notbsd/mod.rs +pub const LIO_NOP: ::c_int = 2; // from linux/mod.rs +pub const LIO_NOWAIT: ::c_int = 1; // from linux/mod.rs +pub const LIO_READ: ::c_int = 0; // from linux/mod.rs +pub const LIO_WAIT: ::c_int = 0; // from linux/mod.rs +pub const LIO_WRITE: ::c_int = 1; // from linux/mod.rs +pub const MAP_HUGETLB: ::c_int = 0x040000; // from linux/other/mod.rs +pub const O_TMPFILE: ::c_int = 0o20000000 | O_DIRECTORY; +pub const RB_KEXEC: ::c_int = 0x45584543u32 as i32; // from linux/mod.rs +pub const RB_SW_SUSPEND: ::c_int = 0xd000fce2u32 as i32; // from linux/mod.rs +pub const SO_BUSY_POLL: ::c_int = 46; // from src/unix/notbsd/mod.rs +pub const SO_PEEK_OFF: ::c_int = 42; // from src/unix/notbsd/mod.rs +pub const SO_REUSEPORT: ::c_int = 15; // from src/unix/notbsd/mod.rs +pub const SOL_NETLINK: ::c_int = 270; // from src/unix/notbsd/mod.rs +pub const _POSIX_VDISABLE: ::cc_t = 0; // from linux/mod.rs +pub const AT_EMPTY_PATH: ::c_int = 0x1000; // from notbsd/mod.rs + +// autogenerated constants with hand tuned types +pub const AT_NO_AUTOMOUNT: ::c_int = 0x800; +pub const B0: ::speed_t = 0; +pub const B1000000: ::speed_t = 0x1008; +pub const B110: ::speed_t = 0x3; +pub const B115200: ::speed_t = 0x1002; +pub const B1152000: ::speed_t = 0x1009; +pub const B1200: ::speed_t = 0x9; +pub const B134: ::speed_t = 0x4; +pub const B150: ::speed_t = 0x5; +pub const B1500000: ::speed_t = 0x100a; +pub const B1800: ::speed_t = 0xa; +pub const B19200: ::speed_t = 0xe; +pub const B200: ::speed_t = 0x6; +pub const B2000000: ::speed_t = 0x100b; +pub const B230400: ::speed_t = 0x1003; +pub const B2400: ::speed_t = 0xb; +pub const B2500000: ::speed_t = 0x100c; +pub const B300: ::speed_t = 0x7; +pub const B3000000: ::speed_t = 0x100d; +pub const B3500000: ::speed_t = 0x100e; +pub const B38400: ::speed_t = 0xf; +pub const B4000000: ::speed_t = 0x100f; +pub const B460800: ::speed_t = 0x1004; +pub const B4800: ::speed_t = 0xc; +pub const B50: ::speed_t = 0x1; +pub const B500000: ::speed_t = 0x1005; +pub const B57600: ::speed_t = 0x1001; +pub const B576000: ::speed_t = 0x1006; +pub const B600: ::speed_t = 0x8; +pub const B75: ::speed_t = 0x2; +pub const B921600: ::speed_t = 0x1007; +pub const B9600: ::speed_t = 0xd; +pub const BS1: ::c_int = 0x2000; +pub const BSDLY: ::c_int = 0x2000; +pub const CBAUD: ::tcflag_t = 0x100f; +pub const CBAUDEX: ::tcflag_t = 0x1000; +pub const CIBAUD: ::tcflag_t = 0x100f0000; +pub const CLOCAL: ::tcflag_t = 0x800; +pub const CMSPAR: ::tcflag_t = 0x40000000; +pub const CPU_SETSIZE: ::c_int = 0x400; +pub const CR1: ::c_int = 0x200; +pub const CR2: ::c_int = 0x400; +pub const CR3: ::c_int = 0x600; +pub const CRDLY: ::c_int = 0x600; +pub const CREAD: ::tcflag_t = 0x80; +pub const CS6: ::tcflag_t = 0x10; +pub const CS7: ::tcflag_t = 0x20; +pub const CS8: ::tcflag_t = 0x30; +pub const CSIZE: ::tcflag_t = 0x30; +pub const CSTOPB: ::tcflag_t = 0x40; +pub const EADDRINUSE: ::c_int = 0x62; +pub const EADDRNOTAVAIL: ::c_int = 0x63; +pub const EADV: ::c_int = 0x44; +pub const EAFNOSUPPORT: ::c_int = 0x61; +pub const EALREADY: ::c_int = 0x72; +pub const EBADE: ::c_int = 0x34; +pub const EBADFD: ::c_int = 0x4d; +pub const EBADMSG: ::c_int = 0x4a; +pub const EBADR: ::c_int = 0x35; +pub const EBADRQC: ::c_int = 0x38; +pub const EBADSLT: ::c_int = 0x39; +pub const EBFONT: ::c_int = 0x3b; +pub const ECANCELED: ::c_int = 0x7d; +pub const ECHOCTL: ::tcflag_t = 0x200; +pub const ECHOE: ::tcflag_t = 0x10; +pub const ECHOK: ::tcflag_t = 0x20; +pub const ECHOKE: ::tcflag_t = 0x800; +pub const ECHONL: ::tcflag_t = 0x40; +pub const ECHOPRT: ::tcflag_t = 0x400; +pub const ECHRNG: ::c_int = 0x2c; +pub const ECOMM: ::c_int = 0x46; +pub const ECONNABORTED: ::c_int = 0x67; +pub const ECONNREFUSED: ::c_int = 0x6f; +pub const ECONNRESET: ::c_int = 0x68; +pub const EDEADLK: ::c_int = 0x23; +pub const EDESTADDRREQ: ::c_int = 0x59; +pub const EDOTDOT: ::c_int = 0x49; +pub const EDQUOT: ::c_int = 0x7a; +pub const EFD_CLOEXEC: ::c_int = 0x80000; +pub const EFD_NONBLOCK: ::c_int = 0x800; +pub const EHOSTDOWN: ::c_int = 0x70; +pub const EHOSTUNREACH: ::c_int = 0x71; +pub const EHWPOISON: ::c_int = 0x85; +pub const EIDRM: ::c_int = 0x2b; +pub const EILSEQ: ::c_int = 0x54; +pub const EINPROGRESS: ::c_int = 0x73; +pub const EISCONN: ::c_int = 0x6a; +pub const EISNAM: ::c_int = 0x78; +pub const EKEYEXPIRED: ::c_int = 0x7f; +pub const EKEYREJECTED: ::c_int = 0x81; +pub const EKEYREVOKED: ::c_int = 0x80; +pub const EL2HLT: ::c_int = 0x33; +pub const EL2NSYNC: ::c_int = 0x2d; +pub const EL3HLT: ::c_int = 0x2e; +pub const EL3RST: ::c_int = 0x2f; +pub const ELIBACC: ::c_int = 0x4f; +pub const ELIBBAD: ::c_int = 0x50; +pub const ELIBEXEC: ::c_int = 0x53; +pub const ELIBMAX: ::c_int = 0x52; +pub const ELIBSCN: ::c_int = 0x51; +pub const ELNRNG: ::c_int = 0x30; +pub const ELOOP: ::c_int = 0x28; +pub const EMEDIUMTYPE: ::c_int = 0x7c; +pub const EMSGSIZE: ::c_int = 0x5a; +pub const EMULTIHOP: ::c_int = 0x48; +pub const ENAMETOOLONG: ::c_int = 0x24; +pub const ENAVAIL: ::c_int = 0x77; +pub const ENETDOWN: ::c_int = 0x64; +pub const ENETRESET: ::c_int = 0x66; +pub const ENETUNREACH: ::c_int = 0x65; +pub const ENOANO: ::c_int = 0x37; +pub const ENOBUFS: ::c_int = 0x69; +pub const ENOCSI: ::c_int = 0x32; +pub const ENODATA: ::c_int = 0x3d; +pub const ENOKEY: ::c_int = 0x7e; +pub const ENOLCK: ::c_int = 0x25; +pub const ENOLINK: ::c_int = 0x43; +pub const ENOMEDIUM: ::c_int = 0x7b; +pub const ENOMSG: ::c_int = 0x2a; +pub const ENONET: ::c_int = 0x40; +pub const ENOPKG: ::c_int = 0x41; +pub const ENOPROTOOPT: ::c_int = 0x5c; +pub const ENOSR: ::c_int = 0x3f; +pub const ENOSTR: ::c_int = 0x3c; +pub const ENOSYS: ::c_int = 0x26; +pub const ENOTCONN: ::c_int = 0x6b; +pub const ENOTEMPTY: ::c_int = 0x27; +pub const ENOTNAM: ::c_int = 0x76; +pub const ENOTRECOVERABLE: ::c_int = 0x83; +pub const ENOTSOCK: ::c_int = 0x58; +pub const ENOTUNIQ: ::c_int = 0x4c; +pub const EOPNOTSUPP: ::c_int = 0x5f; +pub const EOVERFLOW: ::c_int = 0x4b; +pub const EOWNERDEAD: ::c_int = 0x82; +pub const EPFNOSUPPORT: ::c_int = 0x60; +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; +pub const EPROTO: ::c_int = 0x47; +pub const EPROTONOSUPPORT: ::c_int = 0x5d; +pub const EPROTOTYPE: ::c_int = 0x5b; +pub const EREMCHG: ::c_int = 0x4e; +pub const EREMOTE: ::c_int = 0x42; +pub const EREMOTEIO: ::c_int = 0x79; +pub const ERESTART: ::c_int = 0x55; +pub const ERFKILL: ::c_int = 0x84; +pub const ESHUTDOWN: ::c_int = 0x6c; +pub const ESOCKTNOSUPPORT: ::c_int = 0x5e; +pub const ESRMNT: ::c_int = 0x45; +pub const ESTALE: ::c_int = 0x74; +pub const ESTRPIPE: ::c_int = 0x56; +pub const ETIME: ::c_int = 0x3e; +pub const ETIMEDOUT: ::c_int = 0x6e; +pub const ETOOMANYREFS: ::c_int = 0x6d; +pub const EUCLEAN: ::c_int = 0x75; +pub const EUNATCH: ::c_int = 0x31; +pub const EUSERS: ::c_int = 0x57; +pub const EXFULL: ::c_int = 0x36; +pub const FF1: ::c_int = 0x8000; +pub const FFDLY: ::c_int = 0x8000; +pub const FIONBIO: ::c_ulong = 0x5421; +pub const FIOCLEX: ::c_ulong = 0x5451; +pub const FLUSHO: ::tcflag_t = 0x1000; +pub const F_GETLK: ::c_int = 0x5; +pub const F_SETLK: ::c_int = 0x6; +pub const F_SETLKW: ::c_int = 0x7; +pub const HUPCL: ::tcflag_t = 0x400; +pub const ICANON: ::tcflag_t = 0x2; +pub const IEXTEN: ::tcflag_t = 0x8000; +pub const IPV6_MULTICAST_HOPS: ::c_int = 0x12; +pub const IPV6_MULTICAST_IF: ::c_int = 0x11; +pub const IPV6_UNICAST_HOPS: ::c_int = 0x10; +pub const IP_MULTICAST_IF: ::c_int = 0x20; +pub const ISIG: ::tcflag_t = 0x1; +pub const IUTF8: ::tcflag_t = 0x4000; +pub const IXOFF: ::tcflag_t = 0x1000; +pub const IXON: ::tcflag_t = 0x400; +pub const MAP_ANON: ::c_int = 0x20; +pub const MAP_ANONYMOUS: ::c_int = 0x20; +pub const MAP_DENYWRITE: ::c_int = 0x800; +pub const MAP_EXECUTABLE: ::c_int = 0x1000; +pub const MAP_GROWSDOWN: ::c_int = 0x100; +pub const MAP_LOCKED: ::c_int = 0x2000; +pub const MAP_NONBLOCK: ::c_int = 0x10000; +pub const MAP_NORESERVE: ::c_int = 0x4000; +pub const MAP_POPULATE: ::c_int = 0x8000; +pub const MAP_STACK: ::c_int = 0x20000; +pub const MS_ACTIVE: u32 = 0x40000000; +pub const MS_DIRSYNC: u32 = 0x80; +pub const MS_I_VERSION: u32 = 0x800000; +pub const MS_KERNMOUNT: u32 = 0x400000; +pub const MS_MOVE: u32 = 0x2000; +pub const MS_POSIXACL: u32 = 0x10000; +pub const MS_PRIVATE: u32 = 0x40000; +pub const MS_REC: u32 = 0x4000; +pub const MS_RELATIME: u32 = 0x200000; +pub const MS_SHARED: u32 = 0x100000; +pub const MS_SILENT: u32 = 0x8000; +pub const MS_SLAVE: u32 = 0x80000; +pub const MS_STRICTATIME: u32 = 0x1000000; +pub const MS_UNBINDABLE: u32 = 0x20000; +pub const NLDLY: ::tcflag_t = 0x100; +pub const NOFLSH: ::tcflag_t = 0x80; +pub const OCRNL: ::c_int = 0x8; +pub const OFDEL: ::c_int = 0x80; +pub const OFILL: ::c_int = 0x40; +pub const OLCUC: ::tcflag_t = 0x2; +pub const ONLCR: ::tcflag_t = 0x4; +pub const ONLRET: ::tcflag_t = 0x20; +pub const ONOCR: ::tcflag_t = 0x10; +pub const O_ACCMODE: ::c_int = 0x3; +pub const O_APPEND: ::c_int = 0x400; +pub const O_CREAT: ::c_int = 0x40; +pub const O_DIRECT: ::c_int = 0x10000; +pub const O_DIRECTORY: ::c_int = 0x4000; +pub const O_DSYNC: ::c_int = 0x1000; +pub const O_EXCL: ::c_int = 0x80; +pub const O_NDELAY: ::c_int = 0x800; +pub const O_NOCTTY: ::c_int = 0x100; +pub const O_NOFOLLOW: ::c_int = 0x8000; +pub const O_NONBLOCK: ::c_int = 0x800; +pub const O_SYNC: ::c_int = 0o10000; +pub const O_TRUNC: ::c_int = 0x200; +pub const PARENB: ::tcflag_t = 0x100; +pub const PARODD: ::tcflag_t = 0x200; +pub const PENDIN: ::tcflag_t = 0x4000; +pub const POLLRDBAND: ::c_short = 0x80; +pub const POLLRDNORM: ::c_short = 0x40; +pub const POLLWRBAND: ::c_short = 0x200; +pub const POLLWRNORM: ::c_short = 0x100; +pub const QIF_ALL: ::uint32_t = 0x3f; +pub const QIF_BLIMITS: ::uint32_t = 0x1; +pub const QIF_BTIME: ::uint32_t = 0x10; +pub const QIF_ILIMITS: ::uint32_t = 0x4; +pub const QIF_INODES: ::uint32_t = 0x8; +pub const QIF_ITIME: ::uint32_t = 0x20; +pub const QIF_LIMITS: ::uint32_t = 0x5; +pub const QIF_SPACE: ::uint32_t = 0x2; +pub const QIF_TIMES: ::uint32_t = 0x30; +pub const QIF_USAGE: ::uint32_t = 0xa; +pub const SA_NOCLDSTOP: ::c_int = 0x1; +pub const SA_NOCLDWAIT: ::c_int = 0x2; +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_ONSTACK: ::c_int = 0x8000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_SIGINFO: ::c_int = 0x4; +pub const SFD_CLOEXEC: ::c_int = 0x80000; +pub const SFD_NONBLOCK: ::c_int = 0x800; +pub const SIGBUS: ::c_int = 0x7; +pub const SIGCHLD: ::c_int = 0x11; +pub const SIGCONT: ::c_int = 0x12; +pub const SIGIO: ::c_int = 0x1d; +pub const SIGPROF: ::c_int = 0x1b; +pub const SIGPWR: ::c_int = 0x1e; +pub const SIGSTKFLT: ::c_int = 0x10; +pub const SIGSTOP: ::c_int = 0x13; +pub const SIGSYS: ::c_int = 0x1f; +pub const SIGTSTP: ::c_int = 0x14; +pub const SIGTTIN: ::c_int = 0x15; +pub const SIGTTOU: ::c_int = 0x16; +pub const SIGURG: ::c_int = 0x17; +pub const SIGUSR1: ::c_int = 0xa; +pub const SIGUSR2: ::c_int = 0xc; +pub const SIGVTALRM: ::c_int = 0x1a; +pub const SIGWINCH: ::c_int = 0x1c; +pub const SIGXCPU: ::c_int = 0x18; +pub const SIGXFSZ: ::c_int = 0x19; +pub const SIG_BLOCK: ::c_int = 0; +pub const SIG_SETMASK: ::c_int = 0x2; +pub const SIG_UNBLOCK: ::c_int = 0x1; +pub const SOCK_DGRAM: ::c_int = 0x2; +pub const SOCK_NONBLOCK: ::c_int = 0o0004000; +pub const SOCK_SEQPACKET: ::c_int = 0x5; +pub const SOCK_STREAM: ::c_int = 0x1; +pub const SOL_SOCKET: ::c_int = 0x1; +pub const SO_ACCEPTCONN: ::c_int = 0x1e; +pub const SO_BINDTODEVICE: ::c_int = 0x19; +pub const SO_BROADCAST: ::c_int = 0x6; +pub const SO_BSDCOMPAT: ::c_int = 0xe; +pub const SO_DOMAIN: ::c_int = 0x27; +pub const SO_DONTROUTE: ::c_int = 0x5; +pub const SO_ERROR: ::c_int = 0x4; +pub const SO_KEEPALIVE: ::c_int = 0x9; +pub const SO_LINGER: ::c_int = 0xd; +pub const SO_MARK: ::c_int = 0x24; +pub const SO_OOBINLINE: ::c_int = 0xa; +pub const SO_PASSCRED: ::c_int = 0x10; +pub const SO_PEERCRED: ::c_int = 0x11; +pub const SO_PRIORITY: ::c_int = 0xc; +pub const SO_PROTOCOL: ::c_int = 0x26; +pub const SO_RCVBUF: ::c_int = 0x8; +pub const SO_RCVLOWAT: ::c_int = 0x12; +pub const SO_RCVTIMEO: ::c_int = 0x14; +pub const SO_REUSEADDR: ::c_int = 0x2; +pub const SO_RXQ_OVFL: ::c_int = 0x28; +pub const SO_SNDBUF: ::c_int = 0x7; +pub const SO_SNDBUFFORCE: ::c_int = 0x20; +pub const SO_SNDLOWAT: ::c_int = 0x13; +pub const SO_SNDTIMEO: ::c_int = 0x15; +pub const SO_TIMESTAMP: ::c_int = 0x1d; +pub const SO_TYPE: ::c_int = 0x3; +pub const SYS_gettid: ::c_int = 0xe0; +pub const TAB1: ::c_int = 0x800; +pub const TAB2: ::c_int = 0x1000; +pub const TAB3: ::c_int = 0x1800; +pub const TABDLY: ::c_int = 0x1800; +pub const TCSADRAIN: ::c_int = 0x1; +pub const TCSAFLUSH: ::c_int = 0x2; +pub const TCSANOW: ::c_int = 0; +pub const TOSTOP: ::tcflag_t = 0x100; +pub const VDISCARD: usize = 0xd; +pub const VEOF: usize = 0x4; +pub const VEOL: usize = 0xb; +pub const VEOL2: usize = 0x10; +pub const VMIN: usize = 0x6; +pub const VREPRINT: usize = 0xc; +pub const VSTART: usize = 0x8; +pub const VSTOP: usize = 0x9; +pub const VSUSP: usize = 0xa; +pub const VSWTC: usize = 0x7; +pub const VT1: ::c_int = 0x4000; +pub const VTDLY: ::c_int = 0x4000; +pub const VTIME: usize = 0x5; +pub const VWERASE: usize = 0xe; +pub const XTABS: ::tcflag_t = 0x1800; +pub const _PC_2_SYMLINKS: ::c_int = 0x14; +pub const _PC_ALLOC_SIZE_MIN: ::c_int = 0x12; +pub const _PC_ASYNC_IO: ::c_int = 0xa; +pub const _PC_FILESIZEBITS: ::c_int = 0xd; +pub const _PC_PRIO_IO: ::c_int = 0xb; +pub const _PC_REC_INCR_XFER_SIZE: ::c_int = 0xe; +pub const _PC_REC_MAX_XFER_SIZE: ::c_int = 0xf; +pub const _PC_REC_MIN_XFER_SIZE: ::c_int = 0x10; +pub const _PC_REC_XFER_ALIGN: ::c_int = 0x11; +pub const _PC_SYMLINK_MAX: ::c_int = 0x13; +pub const _PC_SYNC_IO: ::c_int = 0x9; +pub const _SC_2_PBS: ::c_int = 0xa8; +pub const _SC_2_PBS_ACCOUNTING: ::c_int = 0xa9; +pub const _SC_2_PBS_CHECKPOINT: ::c_int = 0xaf; +pub const _SC_2_PBS_LOCATE: ::c_int = 0xaa; +pub const _SC_2_PBS_MESSAGE: ::c_int = 0xab; +pub const _SC_2_PBS_TRACK: ::c_int = 0xac; +pub const _SC_ADVISORY_INFO: ::c_int = 0x84; +pub const _SC_BARRIERS: ::c_int = 0x85; +pub const _SC_CLOCK_SELECTION: ::c_int = 0x89; +pub const _SC_CPUTIME: ::c_int = 0x8a; +pub const _SC_IPV6: ::c_int = 0xeb; +pub const _SC_MONOTONIC_CLOCK: ::c_int = 0x95; +pub const _SC_RAW_SOCKETS: ::c_int = 0xec; +pub const _SC_READER_WRITER_LOCKS: ::c_int = 0x99; +pub const _SC_REGEXP: ::c_int = 0x9b; +pub const _SC_SHELL: ::c_int = 0x9d; +pub const _SC_SPAWN: ::c_int = 0x9f; +pub const _SC_SPIN_LOCKS: ::c_int = 0x9a; +pub const _SC_SPORADIC_SERVER: ::c_int = 0xa0; +pub const _SC_SS_REPL_MAX: ::c_int = 0xf1; +pub const _SC_SYMLOOP_MAX: ::c_int = 0xad; +pub const _SC_THREAD_CPUTIME: ::c_int = 0x8b; +pub const _SC_THREAD_PROCESS_SHARED: ::c_int = 0x52; +pub const _SC_THREAD_ROBUST_PRIO_INHERIT: ::c_int = 0xf7; +pub const _SC_THREAD_ROBUST_PRIO_PROTECT: ::c_int = 0xf8; +pub const _SC_THREAD_SPORADIC_SERVER: ::c_int = 0xa1; +pub const _SC_TIMEOUTS: ::c_int = 0xa4; +pub const _SC_TRACE: ::c_int = 0xb5; +pub const _SC_TRACE_EVENT_FILTER: ::c_int = 0xb6; +pub const _SC_TRACE_EVENT_NAME_MAX: ::c_int = 0xf2; +pub const _SC_TRACE_INHERIT: ::c_int = 0xb7; +pub const _SC_TRACE_LOG: ::c_int = 0xb8; +pub const _SC_TRACE_NAME_MAX: ::c_int = 0xf3; +pub const _SC_TRACE_SYS_MAX: ::c_int = 0xf4; +pub const _SC_TRACE_USER_EVENT_MAX: ::c_int = 0xf5; +pub const _SC_TYPED_MEMORY_OBJECTS: ::c_int = 0xa5; +pub const _SC_V6_ILP32_OFF32: ::c_int = 0xb0; +pub const _SC_V6_ILP32_OFFBIG: ::c_int = 0xb1; +pub const _SC_V6_LP64_OFF64: ::c_int = 0xb2; +pub const _SC_V6_LPBIG_OFFBIG: ::c_int = 0xb3; +pub const _SC_XOPEN_STREAMS: ::c_int = 0xf6; + +fn CMSG_ALIGN(len: usize) -> usize { + len + ::mem::size_of::() - 1 & !(::mem::size_of::() - 1) +} + +f! { + pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr { + if (*mhdr).msg_controllen as usize >= ::mem::size_of::() { + (*mhdr).msg_control as *mut cmsghdr + } else { + 0 as *mut cmsghdr + } + } + + pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut ::c_uchar { + cmsg.offset(1) as *mut ::c_uchar + } + + pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint { + (CMSG_ALIGN(length as usize) + CMSG_ALIGN(::mem::size_of::())) + as ::c_uint + } + + pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint { + CMSG_ALIGN(::mem::size_of::()) as ::c_uint + length + } + + pub fn CMSG_NXTHDR(mhdr: *const msghdr, + cmsg: *const cmsghdr) -> *mut cmsghdr { + if ((*cmsg).cmsg_len as usize) < ::mem::size_of::() { + return 0 as *mut cmsghdr; + }; + let next = (cmsg as usize + + CMSG_ALIGN((*cmsg).cmsg_len as usize)) + as *mut cmsghdr; + let max = (*mhdr).msg_control as usize + + (*mhdr).msg_controllen as usize; + if (next.offset(1)) as usize > max || + next as usize + CMSG_ALIGN((*next).cmsg_len as usize) > max + { + 0 as *mut cmsghdr + } else { + next as *mut cmsghdr + } + } + +} + +extern { + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn openpty(amaster: *mut ::c_int, + aslave: *mut ::c_int, + name: *mut ::c_char, + termp: *mut termios, + winp: *mut ::winsize) -> ::c_int; + pub fn setns(fd: ::c_int, nstype: ::c_int) -> ::c_int; + pub fn pwritev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; + pub fn preadv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t) -> ::ssize_t; +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/uclibc/arm/no_align.rs b/libc/src/unix/uclibc/arm/no_align.rs new file mode 100644 index 000000000..e32bf673d --- /dev/null +++ b/libc/src/unix/uclibc/arm/no_align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} diff --git a/libc/src/unix/uclibc/mips/mips32/align.rs b/libc/src/unix/uclibc/mips/mips32/align.rs new file mode 100644 index 000000000..4a0e07460 --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips32/align.rs @@ -0,0 +1,13 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/uclibc/mips/mips32/mod.rs b/libc/src/unix/uclibc/mips/mips32/mod.rs new file mode 100644 index 000000000..410ab70c4 --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips32/mod.rs @@ -0,0 +1,627 @@ +pub type c_char = i8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type clock_t = i32; +pub type time_t = i32; +pub type suseconds_t = i32; +pub type wchar_t = i32; +pub type off_t = i32; +pub type ino_t = u32; +pub type blkcnt_t = i32; +pub type blksize_t = i32; +pub type nlink_t = u32; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type rlim_t = c_ulong; + +s! { + pub struct stat { + pub st_dev: ::dev_t, + st_pad1: [::c_long; 2], + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + pub st_pad2: [::c_long; 1], + pub st_size: ::off_t, + st_pad3: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + st_pad5: [::c_long; 14], + } + + pub struct stat64 { + pub st_dev: ::dev_t, + st_pad1: [::c_long; 2], + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::dev_t, + st_pad2: [::c_long; 2], + pub st_size: ::off64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad3: ::c_long, + pub st_blocks: ::blkcnt64_t, + st_pad5: [::c_long; 14], + } + + pub struct pthread_attr_t { + __size: [u32; 9] + } + + pub struct sigaction { + pub sa_flags: ::c_uint, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + _restorer: *mut ::c_void, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct sigset_t { + __val: [::c_ulong; 4], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + pub _pad: [::c_int; 29], + } + + pub struct glob64_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut ::c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_uint, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + #[cfg(target_endian = "big")] + __glibc_reserved1: ::c_ulong, + pub msg_stime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved1: ::c_ulong, + #[cfg(target_endian = "big")] + __glibc_reserved2: ::c_ulong, + pub msg_rtime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved2: ::c_ulong, + #[cfg(target_endian = "big")] + __glibc_reserved3: ::c_ulong, + pub msg_ctime: ::time_t, + #[cfg(target_endian = "little")] + __glibc_reserved3: ::c_ulong, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsblkcnt_t, + pub f_ffree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + + pub f_namelen: ::c_long, + f_spare: [::c_long; 6], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::c_int, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct flock { + pub l_type: ::c_short, + pub l_whence: ::c_short, + pub l_start: ::off_t, + pub l_len: ::off_t, + pub l_sysid: ::c_long, + pub l_pid: ::pid_t, + pad: [::c_long; 4], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 8], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 24; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; + +pub const RLIM_INFINITY: ::rlim_t = 0x7fffffff; + +pub const SYS_syscall: ::c_long = 4000 + 0; +pub const SYS_exit: ::c_long = 4000 + 1; +pub const SYS_fork: ::c_long = 4000 + 2; +pub const SYS_read: ::c_long = 4000 + 3; +pub const SYS_write: ::c_long = 4000 + 4; +pub const SYS_open: ::c_long = 4000 + 5; +pub const SYS_close: ::c_long = 4000 + 6; +pub const SYS_waitpid: ::c_long = 4000 + 7; +pub const SYS_creat: ::c_long = 4000 + 8; +pub const SYS_link: ::c_long = 4000 + 9; +pub const SYS_unlink: ::c_long = 4000 + 10; +pub const SYS_execve: ::c_long = 4000 + 11; +pub const SYS_chdir: ::c_long = 4000 + 12; +pub const SYS_time: ::c_long = 4000 + 13; +pub const SYS_mknod: ::c_long = 4000 + 14; +pub const SYS_chmod: ::c_long = 4000 + 15; +pub const SYS_lchown: ::c_long = 4000 + 16; +pub const SYS_break: ::c_long = 4000 + 17; +pub const SYS_lseek: ::c_long = 4000 + 19; +pub const SYS_getpid: ::c_long = 4000 + 20; +pub const SYS_mount: ::c_long = 4000 + 21; +pub const SYS_umount: ::c_long = 4000 + 22; +pub const SYS_setuid: ::c_long = 4000 + 23; +pub const SYS_getuid: ::c_long = 4000 + 24; +pub const SYS_stime: ::c_long = 4000 + 25; +pub const SYS_ptrace: ::c_long = 4000 + 26; +pub const SYS_alarm: ::c_long = 4000 + 27; +pub const SYS_pause: ::c_long = 4000 + 29; +pub const SYS_utime: ::c_long = 4000 + 30; +pub const SYS_stty: ::c_long = 4000 + 31; +pub const SYS_gtty: ::c_long = 4000 + 32; +pub const SYS_access: ::c_long = 4000 + 33; +pub const SYS_nice: ::c_long = 4000 + 34; +pub const SYS_ftime: ::c_long = 4000 + 35; +pub const SYS_sync: ::c_long = 4000 + 36; +pub const SYS_kill: ::c_long = 4000 + 37; +pub const SYS_rename: ::c_long = 4000 + 38; +pub const SYS_mkdir: ::c_long = 4000 + 39; +pub const SYS_rmdir: ::c_long = 4000 + 40; +pub const SYS_dup: ::c_long = 4000 + 41; +pub const SYS_pipe: ::c_long = 4000 + 42; +pub const SYS_times: ::c_long = 4000 + 43; +pub const SYS_prof: ::c_long = 4000 + 44; +pub const SYS_brk: ::c_long = 4000 + 45; +pub const SYS_setgid: ::c_long = 4000 + 46; +pub const SYS_getgid: ::c_long = 4000 + 47; +pub const SYS_signal: ::c_long = 4000 + 48; +pub const SYS_geteuid: ::c_long = 4000 + 49; +pub const SYS_getegid: ::c_long = 4000 + 50; +pub const SYS_acct: ::c_long = 4000 + 51; +pub const SYS_umount2: ::c_long = 4000 + 52; +pub const SYS_lock: ::c_long = 4000 + 53; +pub const SYS_ioctl: ::c_long = 4000 + 54; +pub const SYS_fcntl: ::c_long = 4000 + 55; +pub const SYS_mpx: ::c_long = 4000 + 56; +pub const SYS_setpgid: ::c_long = 4000 + 57; +pub const SYS_ulimit: ::c_long = 4000 + 58; +pub const SYS_umask: ::c_long = 4000 + 60; +pub const SYS_chroot: ::c_long = 4000 + 61; +pub const SYS_ustat: ::c_long = 4000 + 62; +pub const SYS_dup2: ::c_long = 4000 + 63; +pub const SYS_getppid: ::c_long = 4000 + 64; +pub const SYS_getpgrp: ::c_long = 4000 + 65; +pub const SYS_setsid: ::c_long = 4000 + 66; +pub const SYS_sigaction: ::c_long = 4000 + 67; +pub const SYS_sgetmask: ::c_long = 4000 + 68; +pub const SYS_ssetmask: ::c_long = 4000 + 69; +pub const SYS_setreuid: ::c_long = 4000 + 70; +pub const SYS_setregid: ::c_long = 4000 + 71; +pub const SYS_sigsuspend: ::c_long = 4000 + 72; +pub const SYS_sigpending: ::c_long = 4000 + 73; +pub const SYS_sethostname: ::c_long = 4000 + 74; +pub const SYS_setrlimit: ::c_long = 4000 + 75; +pub const SYS_getrlimit: ::c_long = 4000 + 76; +pub const SYS_getrusage: ::c_long = 4000 + 77; +pub const SYS_gettimeofday: ::c_long = 4000 + 78; +pub const SYS_settimeofday: ::c_long = 4000 + 79; +pub const SYS_getgroups: ::c_long = 4000 + 80; +pub const SYS_setgroups: ::c_long = 4000 + 81; +pub const SYS_symlink: ::c_long = 4000 + 83; +pub const SYS_readlink: ::c_long = 4000 + 85; +pub const SYS_uselib: ::c_long = 4000 + 86; +pub const SYS_swapon: ::c_long = 4000 + 87; +pub const SYS_reboot: ::c_long = 4000 + 88; +pub const SYS_readdir: ::c_long = 4000 + 89; +pub const SYS_mmap: ::c_long = 4000 + 90; +pub const SYS_munmap: ::c_long = 4000 + 91; +pub const SYS_truncate: ::c_long = 4000 + 92; +pub const SYS_ftruncate: ::c_long = 4000 + 93; +pub const SYS_fchmod: ::c_long = 4000 + 94; +pub const SYS_fchown: ::c_long = 4000 + 95; +pub const SYS_getpriority: ::c_long = 4000 + 96; +pub const SYS_setpriority: ::c_long = 4000 + 97; +pub const SYS_profil: ::c_long = 4000 + 98; +pub const SYS_statfs: ::c_long = 4000 + 99; +pub const SYS_fstatfs: ::c_long = 4000 + 100; +pub const SYS_ioperm: ::c_long = 4000 + 101; +pub const SYS_socketcall: ::c_long = 4000 + 102; +pub const SYS_syslog: ::c_long = 4000 + 103; +pub const SYS_setitimer: ::c_long = 4000 + 104; +pub const SYS_getitimer: ::c_long = 4000 + 105; +pub const SYS_stat: ::c_long = 4000 + 106; +pub const SYS_lstat: ::c_long = 4000 + 107; +pub const SYS_fstat: ::c_long = 4000 + 108; +pub const SYS_iopl: ::c_long = 4000 + 110; +pub const SYS_vhangup: ::c_long = 4000 + 111; +pub const SYS_idle: ::c_long = 4000 + 112; +pub const SYS_vm86: ::c_long = 4000 + 113; +pub const SYS_wait4: ::c_long = 4000 + 114; +pub const SYS_swapoff: ::c_long = 4000 + 115; +pub const SYS_sysinfo: ::c_long = 4000 + 116; +pub const SYS_ipc: ::c_long = 4000 + 117; +pub const SYS_fsync: ::c_long = 4000 + 118; +pub const SYS_sigreturn: ::c_long = 4000 + 119; +pub const SYS_clone: ::c_long = 4000 + 120; +pub const SYS_setdomainname: ::c_long = 4000 + 121; +pub const SYS_uname: ::c_long = 4000 + 122; +pub const SYS_modify_ldt: ::c_long = 4000 + 123; +pub const SYS_adjtimex: ::c_long = 4000 + 124; +pub const SYS_mprotect: ::c_long = 4000 + 125; +pub const SYS_sigprocmask: ::c_long = 4000 + 126; +pub const SYS_create_module: ::c_long = 4000 + 127; +pub const SYS_init_module: ::c_long = 4000 + 128; +pub const SYS_delete_module: ::c_long = 4000 + 129; +pub const SYS_get_kernel_syms: ::c_long = 4000 + 130; +pub const SYS_quotactl: ::c_long = 4000 + 131; +pub const SYS_getpgid: ::c_long = 4000 + 132; +pub const SYS_fchdir: ::c_long = 4000 + 133; +pub const SYS_bdflush: ::c_long = 4000 + 134; +pub const SYS_sysfs: ::c_long = 4000 + 135; +pub const SYS_personality: ::c_long = 4000 + 136; +pub const SYS_afs_syscall: ::c_long = 4000 + 137; +pub const SYS_setfsuid: ::c_long = 4000 + 138; +pub const SYS_setfsgid: ::c_long = 4000 + 139; +pub const SYS__llseek: ::c_long = 4000 + 140; +pub const SYS_getdents: ::c_long = 4000 + 141; +pub const SYS__newselect: ::c_long = 4000 + 142; +pub const SYS_flock: ::c_long = 4000 + 143; +pub const SYS_msync: ::c_long = 4000 + 144; +pub const SYS_readv: ::c_long = 4000 + 145; +pub const SYS_writev: ::c_long = 4000 + 146; +pub const SYS_cacheflush: ::c_long = 4000 + 147; +pub const SYS_cachectl: ::c_long = 4000 + 148; +pub const SYS_sysmips: ::c_long = 4000 + 149; +pub const SYS_getsid: ::c_long = 4000 + 151; +pub const SYS_fdatasync: ::c_long = 4000 + 152; +pub const SYS__sysctl: ::c_long = 4000 + 153; +pub const SYS_mlock: ::c_long = 4000 + 154; +pub const SYS_munlock: ::c_long = 4000 + 155; +pub const SYS_mlockall: ::c_long = 4000 + 156; +pub const SYS_munlockall: ::c_long = 4000 + 157; +pub const SYS_sched_setparam: ::c_long = 4000 + 158; +pub const SYS_sched_getparam: ::c_long = 4000 + 159; +pub const SYS_sched_setscheduler: ::c_long = 4000 + 160; +pub const SYS_sched_getscheduler: ::c_long = 4000 + 161; +pub const SYS_sched_yield: ::c_long = 4000 + 162; +pub const SYS_sched_get_priority_max: ::c_long = 4000 + 163; +pub const SYS_sched_get_priority_min: ::c_long = 4000 + 164; +pub const SYS_sched_rr_get_interval: ::c_long = 4000 + 165; +pub const SYS_nanosleep: ::c_long = 4000 + 166; +pub const SYS_mremap: ::c_long = 4000 + 167; +pub const SYS_accept: ::c_long = 4000 + 168; +pub const SYS_bind: ::c_long = 4000 + 169; +pub const SYS_connect: ::c_long = 4000 + 170; +pub const SYS_getpeername: ::c_long = 4000 + 171; +pub const SYS_getsockname: ::c_long = 4000 + 172; +pub const SYS_getsockopt: ::c_long = 4000 + 173; +pub const SYS_listen: ::c_long = 4000 + 174; +pub const SYS_recv: ::c_long = 4000 + 175; +pub const SYS_recvfrom: ::c_long = 4000 + 176; +pub const SYS_recvmsg: ::c_long = 4000 + 177; +pub const SYS_send: ::c_long = 4000 + 178; +pub const SYS_sendmsg: ::c_long = 4000 + 179; +pub const SYS_sendto: ::c_long = 4000 + 180; +pub const SYS_setsockopt: ::c_long = 4000 + 181; +pub const SYS_shutdown: ::c_long = 4000 + 182; +pub const SYS_socket: ::c_long = 4000 + 183; +pub const SYS_socketpair: ::c_long = 4000 + 184; +pub const SYS_setresuid: ::c_long = 4000 + 185; +pub const SYS_getresuid: ::c_long = 4000 + 186; +pub const SYS_query_module: ::c_long = 4000 + 187; +pub const SYS_poll: ::c_long = 4000 + 188; +pub const SYS_nfsservctl: ::c_long = 4000 + 189; +pub const SYS_setresgid: ::c_long = 4000 + 190; +pub const SYS_getresgid: ::c_long = 4000 + 191; +pub const SYS_prctl: ::c_long = 4000 + 192; +pub const SYS_rt_sigreturn: ::c_long = 4000 + 193; +pub const SYS_rt_sigaction: ::c_long = 4000 + 194; +pub const SYS_rt_sigprocmask: ::c_long = 4000 + 195; +pub const SYS_rt_sigpending: ::c_long = 4000 + 196; +pub const SYS_rt_sigtimedwait: ::c_long = 4000 + 197; +pub const SYS_rt_sigqueueinfo: ::c_long = 4000 + 198; +pub const SYS_rt_sigsuspend: ::c_long = 4000 + 199; +pub const SYS_pread64: ::c_long = 4000 + 200; +pub const SYS_pwrite64: ::c_long = 4000 + 201; +pub const SYS_chown: ::c_long = 4000 + 202; +pub const SYS_getcwd: ::c_long = 4000 + 203; +pub const SYS_capget: ::c_long = 4000 + 204; +pub const SYS_capset: ::c_long = 4000 + 205; +pub const SYS_sigaltstack: ::c_long = 4000 + 206; +pub const SYS_sendfile: ::c_long = 4000 + 207; +pub const SYS_getpmsg: ::c_long = 4000 + 208; +pub const SYS_putpmsg: ::c_long = 4000 + 209; +pub const SYS_mmap2: ::c_long = 4000 + 210; +pub const SYS_truncate64: ::c_long = 4000 + 211; +pub const SYS_ftruncate64: ::c_long = 4000 + 212; +pub const SYS_stat64: ::c_long = 4000 + 213; +pub const SYS_lstat64: ::c_long = 4000 + 214; +pub const SYS_fstat64: ::c_long = 4000 + 215; +pub const SYS_pivot_root: ::c_long = 4000 + 216; +pub const SYS_mincore: ::c_long = 4000 + 217; +pub const SYS_madvise: ::c_long = 4000 + 218; +pub const SYS_getdents64: ::c_long = 4000 + 219; +pub const SYS_fcntl64: ::c_long = 4000 + 220; +pub const SYS_gettid: ::c_long = 4000 + 222; +pub const SYS_readahead: ::c_long = 4000 + 223; +pub const SYS_setxattr: ::c_long = 4000 + 224; +pub const SYS_lsetxattr: ::c_long = 4000 + 225; +pub const SYS_fsetxattr: ::c_long = 4000 + 226; +pub const SYS_getxattr: ::c_long = 4000 + 227; +pub const SYS_lgetxattr: ::c_long = 4000 + 228; +pub const SYS_fgetxattr: ::c_long = 4000 + 229; +pub const SYS_listxattr: ::c_long = 4000 + 230; +pub const SYS_llistxattr: ::c_long = 4000 + 231; +pub const SYS_flistxattr: ::c_long = 4000 + 232; +pub const SYS_removexattr: ::c_long = 4000 + 233; +pub const SYS_lremovexattr: ::c_long = 4000 + 234; +pub const SYS_fremovexattr: ::c_long = 4000 + 235; +pub const SYS_tkill: ::c_long = 4000 + 236; +pub const SYS_sendfile64: ::c_long = 4000 + 237; +pub const SYS_futex: ::c_long = 4000 + 238; +pub const SYS_sched_setaffinity: ::c_long = 4000 + 239; +pub const SYS_sched_getaffinity: ::c_long = 4000 + 240; +pub const SYS_io_setup: ::c_long = 4000 + 241; +pub const SYS_io_destroy: ::c_long = 4000 + 242; +pub const SYS_io_getevents: ::c_long = 4000 + 243; +pub const SYS_io_submit: ::c_long = 4000 + 244; +pub const SYS_io_cancel: ::c_long = 4000 + 245; +pub const SYS_exit_group: ::c_long = 4000 + 246; +pub const SYS_lookup_dcookie: ::c_long = 4000 + 247; +pub const SYS_epoll_create: ::c_long = 4000 + 248; +pub const SYS_epoll_ctl: ::c_long = 4000 + 249; +pub const SYS_epoll_wait: ::c_long = 4000 + 250; +pub const SYS_remap_file_pages: ::c_long = 4000 + 251; +pub const SYS_set_tid_address: ::c_long = 4000 + 252; +pub const SYS_restart_syscall: ::c_long = 4000 + 253; +pub const SYS_fadvise64: ::c_long = 4000 + 254; +pub const SYS_statfs64: ::c_long = 4000 + 255; +pub const SYS_fstatfs64: ::c_long = 4000 + 256; +pub const SYS_timer_create: ::c_long = 4000 + 257; +pub const SYS_timer_settime: ::c_long = 4000 + 258; +pub const SYS_timer_gettime: ::c_long = 4000 + 259; +pub const SYS_timer_getoverrun: ::c_long = 4000 + 260; +pub const SYS_timer_delete: ::c_long = 4000 + 261; +pub const SYS_clock_settime: ::c_long = 4000 + 262; +pub const SYS_clock_gettime: ::c_long = 4000 + 263; +pub const SYS_clock_getres: ::c_long = 4000 + 264; +pub const SYS_clock_nanosleep: ::c_long = 4000 + 265; +pub const SYS_tgkill: ::c_long = 4000 + 266; +pub const SYS_utimes: ::c_long = 4000 + 267; +pub const SYS_mbind: ::c_long = 4000 + 268; +pub const SYS_get_mempolicy: ::c_long = 4000 + 269; +pub const SYS_set_mempolicy: ::c_long = 4000 + 270; +pub const SYS_mq_open: ::c_long = 4000 + 271; +pub const SYS_mq_unlink: ::c_long = 4000 + 272; +pub const SYS_mq_timedsend: ::c_long = 4000 + 273; +pub const SYS_mq_timedreceive: ::c_long = 4000 + 274; +pub const SYS_mq_notify: ::c_long = 4000 + 275; +pub const SYS_mq_getsetattr: ::c_long = 4000 + 276; +pub const SYS_vserver: ::c_long = 4000 + 277; +pub const SYS_waitid: ::c_long = 4000 + 278; +/* pub const SYS_sys_setaltroot: ::c_long = 4000 + 279; */ +pub const SYS_add_key: ::c_long = 4000 + 280; +pub const SYS_request_key: ::c_long = 4000 + 281; +pub const SYS_keyctl: ::c_long = 4000 + 282; +pub const SYS_set_thread_area: ::c_long = 4000 + 283; +pub const SYS_inotify_init: ::c_long = 4000 + 284; +pub const SYS_inotify_add_watch: ::c_long = 4000 + 285; +pub const SYS_inotify_rm_watch: ::c_long = 4000 + 286; +pub const SYS_migrate_pages: ::c_long = 4000 + 287; +pub const SYS_openat: ::c_long = 4000 + 288; +pub const SYS_mkdirat: ::c_long = 4000 + 289; +pub const SYS_mknodat: ::c_long = 4000 + 290; +pub const SYS_fchownat: ::c_long = 4000 + 291; +pub const SYS_futimesat: ::c_long = 4000 + 292; +pub const SYS_fstatat64: ::c_long = 4000 + 293; +pub const SYS_unlinkat: ::c_long = 4000 + 294; +pub const SYS_renameat: ::c_long = 4000 + 295; +pub const SYS_linkat: ::c_long = 4000 + 296; +pub const SYS_symlinkat: ::c_long = 4000 + 297; +pub const SYS_readlinkat: ::c_long = 4000 + 298; +pub const SYS_fchmodat: ::c_long = 4000 + 299; +pub const SYS_faccessat: ::c_long = 4000 + 300; +pub const SYS_pselect6: ::c_long = 4000 + 301; +pub const SYS_ppoll: ::c_long = 4000 + 302; +pub const SYS_unshare: ::c_long = 4000 + 303; +pub const SYS_splice: ::c_long = 4000 + 304; +pub const SYS_sync_file_range: ::c_long = 4000 + 305; +pub const SYS_tee: ::c_long = 4000 + 306; +pub const SYS_vmsplice: ::c_long = 4000 + 307; +pub const SYS_move_pages: ::c_long = 4000 + 308; +pub const SYS_set_robust_list: ::c_long = 4000 + 309; +pub const SYS_get_robust_list: ::c_long = 4000 + 310; +pub const SYS_kexec_load: ::c_long = 4000 + 311; +pub const SYS_getcpu: ::c_long = 4000 + 312; +pub const SYS_epoll_pwait: ::c_long = 4000 + 313; +pub const SYS_ioprio_set: ::c_long = 4000 + 314; +pub const SYS_ioprio_get: ::c_long = 4000 + 315; +pub const SYS_utimensat: ::c_long = 4000 + 316; +pub const SYS_signalfd: ::c_long = 4000 + 317; +pub const SYS_timerfd: ::c_long = 4000 + 318; +pub const SYS_eventfd: ::c_long = 4000 + 319; +pub const SYS_fallocate: ::c_long = 4000 + 320; +pub const SYS_timerfd_create: ::c_long = 4000 + 321; +pub const SYS_timerfd_gettime: ::c_long = 4000 + 322; +pub const SYS_timerfd_settime: ::c_long = 4000 + 323; +pub const SYS_signalfd4: ::c_long = 4000 + 324; +pub const SYS_eventfd2: ::c_long = 4000 + 325; +pub const SYS_epoll_create1: ::c_long = 4000 + 326; +pub const SYS_dup3: ::c_long = 4000 + 327; +pub const SYS_pipe2: ::c_long = 4000 + 328; +pub const SYS_inotify_init1: ::c_long = 4000 + 329; +pub const SYS_preadv: ::c_long = 4000 + 330; +pub const SYS_pwritev: ::c_long = 4000 + 331; +pub const SYS_rt_tgsigqueueinfo: ::c_long = 4000 + 332; +pub const SYS_perf_event_open: ::c_long = 4000 + 333; +pub const SYS_accept4: ::c_long = 4000 + 334; +pub const SYS_recvmmsg: ::c_long = 4000 + 335; +pub const SYS_fanotify_init: ::c_long = 4000 + 336; +pub const SYS_fanotify_mark: ::c_long = 4000 + 337; +pub const SYS_prlimit64: ::c_long = 4000 + 338; +pub const SYS_name_to_handle_at: ::c_long = 4000 + 339; +pub const SYS_open_by_handle_at: ::c_long = 4000 + 340; +pub const SYS_clock_adjtime: ::c_long = 4000 + 341; +pub const SYS_syncfs: ::c_long = 4000 + 342; +pub const SYS_sendmmsg: ::c_long = 4000 + 343; +pub const SYS_setns: ::c_long = 4000 + 344; +pub const SYS_process_vm_readv: ::c_long = 4000 + 345; +pub const SYS_process_vm_writev: ::c_long = 4000 + 346; +pub const SYS_kcmp: ::c_long = 4000 + 347; +pub const SYS_finit_module: ::c_long = 4000 + 348; +pub const SYS_sched_setattr: ::c_long = 4000 + 349; +pub const SYS_sched_getattr: ::c_long = 4000 + 350; +pub const SYS_renameat2: ::c_long = 4000 + 351; +pub const SYS_seccomp: ::c_long = 4000 + 352; +pub const SYS_getrandom: ::c_long = 4000 + 353; +pub const SYS_memfd_create: ::c_long = 4000 + 354; +pub const SYS_bpf: ::c_long = 4000 + 355; +pub const SYS_execveat: ::c_long = 4000 + 356; +pub const SYS_userfaultfd: ::c_long = 4000 + 357; +pub const SYS_membarrier: ::c_long = 4000 + 358; +pub const SYS_mlock2: ::c_long = 4000 + 359; +pub const SYS_copy_file_range: ::c_long = 4000 + 360; +pub const SYS_preadv2: ::c_long = 4000 + 361; +pub const SYS_pwritev2: ::c_long = 4000 + 362; +pub const SYS_pkey_mprotect: ::c_long = 4000 + 363; +pub const SYS_pkey_alloc: ::c_long = 4000 + 364; +pub const SYS_pkey_free: ::c_long = 4000 + 365; + +#[link(name = "util")] +extern { + pub fn sysctl(name: *mut ::c_int, + namelen: ::c_int, + oldp: *mut ::c_void, + oldlenp: *mut ::size_t, + newp: *mut ::c_void, + newlen: ::size_t) + -> ::c_int; + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; + pub fn backtrace(buf: *mut *mut ::c_void, + sz: ::c_int) -> ::c_int; + pub fn glob64(pattern: *const ::c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut glob64_t) -> ::c_int; + pub fn globfree64(pglob: *mut glob64_t); + pub fn ptrace(request: ::c_uint, ...) -> ::c_long; + pub fn pthread_attr_getaffinity_np(attr: *const ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *mut ::cpu_set_t) -> ::c_int; + pub fn pthread_attr_setaffinity_np(attr: *mut ::pthread_attr_t, + cpusetsize: ::size_t, + cpuset: *const ::cpu_set_t) -> ::c_int; +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/uclibc/mips/mips32/no_align.rs b/libc/src/unix/uclibc/mips/mips32/no_align.rs new file mode 100644 index 000000000..e32bf673d --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips32/no_align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} diff --git a/libc/src/unix/uclibc/mips/mips64/align.rs b/libc/src/unix/uclibc/mips/mips64/align.rs new file mode 100644 index 000000000..21e21907d --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips64/align.rs @@ -0,0 +1,10 @@ +s! { + // FIXME this is actually a union + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { + __size: [::c_char; 32], + } +} diff --git a/libc/src/unix/uclibc/mips/mips64/mod.rs b/libc/src/unix/uclibc/mips/mips64/mod.rs new file mode 100644 index 000000000..d80762e6c --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips64/mod.rs @@ -0,0 +1,213 @@ +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type c_char = i8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type ino_t = u64; +pub type nlink_t = u64; +pub type off_t = i64; +pub type rlim_t = ::c_ulong; +pub type suseconds_t = i64; +pub type time_t = i64; +pub type wchar_t = i32; + +s! { + pub struct stat { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 2], + pub st_ino: ::ino_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + st_pad2: [::c_ulong; 1], + pub st_size: ::off_t, + st_pad3: ::c_long, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad4: ::c_long, + pub st_blocks: ::blkcnt_t, + st_pad5: [::c_long; 7], + } + + pub struct stat64 { + pub st_dev: ::c_ulong, + st_pad1: [::c_long; 2], + pub st_ino: ::ino64_t, + pub st_mode: ::mode_t, + pub st_nlink: ::nlink_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, + st_pad2: [::c_long; 2], + pub st_size: ::off64_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_long, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_long, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_long, + pub st_blksize: ::blksize_t, + st_pad3: ::c_long, + pub st_blocks: ::blkcnt64_t, + st_pad5: [::c_long; 7], + } + + pub struct pthread_attr_t { + __size: [::c_ulong; 7] + } + + pub struct sigaction { + pub sa_flags: ::c_int, + pub sa_sigaction: ::sighandler_t, + pub sa_mask: sigset_t, + _restorer: *mut ::c_void, + } + + pub struct stack_t { + pub ss_sp: *mut ::c_void, + pub ss_size: ::size_t, + pub ss_flags: ::c_int, + } + + pub struct sigset_t { + __size: [::c_ulong; 16], + } + + pub struct siginfo_t { + pub si_signo: ::c_int, + pub si_code: ::c_int, + pub si_errno: ::c_int, + _pad: ::c_int, + _pad2: [::c_long; 14], + } + + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_uint, + pub __seq: ::c_ushort, + __pad1: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, + pub shm_atime: ::time_t, + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused4: ::c_ulong, + __unused5: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __glibc_reserved4: ::c_ulong, + __glibc_reserved5: ::c_ulong, + } + + pub struct statfs { + pub f_type: ::c_long, + pub f_bsize: ::c_long, + pub f_frsize: ::c_long, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_files: ::fsblkcnt_t, + pub f_ffree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_fsid: ::fsid_t, + + pub f_namelen: ::c_long, + f_spare: [::c_long; 6], + } + + pub struct msghdr { + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct cmsghdr { + pub cmsg_len: ::size_t, + pub cmsg_level: ::c_int, + pub cmsg_type: ::c_int, + } + + pub struct termios { + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct sysinfo { + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } +} + +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +pub const RLIM_INFINITY: ::rlim_t = 0xffff_ffff_ffff_ffff; + +pub const SYS_gettid: ::c_long = 5178; // Valid for n64 + +#[link(name = "util")] +extern { + pub fn ioctl(fd: ::c_int, request: ::c_ulong, ...) -> ::c_int; +} + +cfg_if! { + if #[cfg(libc_align)] { + mod align; + pub use self::align::*; + } else { + mod no_align; + pub use self::no_align::*; + } +} diff --git a/libc/src/unix/uclibc/mips/mips64/no_align.rs b/libc/src/unix/uclibc/mips/mips64/no_align.rs new file mode 100644 index 000000000..ee57ea886 --- /dev/null +++ b/libc/src/unix/uclibc/mips/mips64/no_align.rs @@ -0,0 +1,8 @@ +s! { + // FIXME this is actually a union + pub struct sem_t { + __size: [::c_char; 32], + __align: [::c_long; 0], + } +} + diff --git a/libc/src/unix/uclibc/mips/mod.rs b/libc/src/unix/uclibc/mips/mod.rs new file mode 100644 index 000000000..27f6fe584 --- /dev/null +++ b/libc/src/unix/uclibc/mips/mod.rs @@ -0,0 +1,478 @@ +pub type pthread_t = ::c_ulong; + +pub const SFD_CLOEXEC: ::c_int = 0x080000; + +pub const NCCS: usize = 32; + +pub const O_TRUNC: ::c_int = 512; + +pub const O_CLOEXEC: ::c_int = 0x80000; + +pub const EBFONT: ::c_int = 59; +pub const ENOSTR: ::c_int = 60; +pub const ENODATA: ::c_int = 61; +pub const ETIME: ::c_int = 62; +pub const ENOSR: ::c_int = 63; +pub const ENONET: ::c_int = 64; +pub const ENOPKG: ::c_int = 65; +pub const EREMOTE: ::c_int = 66; +pub const ENOLINK: ::c_int = 67; +pub const EADV: ::c_int = 68; +pub const ESRMNT: ::c_int = 69; +pub const ECOMM: ::c_int = 70; +pub const EPROTO: ::c_int = 71; +pub const EDOTDOT: ::c_int = 73; + +pub const SA_NODEFER: ::c_int = 0x40000000; +pub const SA_RESETHAND: ::c_int = 0x80000000; +pub const SA_RESTART: ::c_int = 0x10000000; +pub const SA_NOCLDSTOP: ::c_int = 0x00000001; + +pub const EPOLL_CLOEXEC: ::c_int = 0x80000; + +pub const EFD_CLOEXEC: ::c_int = 0x80000; + +pub const BUFSIZ: ::c_uint = 4096; +pub const TMP_MAX: ::c_uint = 238328; +pub const FOPEN_MAX: ::c_uint = 16; +pub const POSIX_FADV_DONTNEED: ::c_int = 4; +pub const POSIX_FADV_NOREUSE: ::c_int = 5; +pub const POSIX_MADV_DONTNEED: ::c_int = 4; +pub const _SC_2_C_VERSION: ::c_int = 96; +pub const O_ACCMODE: ::c_int = 3; +pub const O_DIRECT: ::c_int = 0x8000; +pub const O_DIRECTORY: ::c_int = 0x10000; +pub const O_NOFOLLOW: ::c_int = 0x20000; +pub const ST_RELATIME: ::c_ulong = 4096; +pub const NI_MAXHOST: ::socklen_t = 1025; + +pub const RLIMIT_NOFILE: ::c_int = 5; +pub const RLIMIT_AS: ::c_int = 6; +pub const RLIMIT_RSS: ::c_int = 7; +pub const RLIMIT_NPROC: ::c_int = 8; +pub const RLIMIT_MEMLOCK: ::c_int = 9; +pub const RLIMIT_NLIMITS: ::c_int = 15; + +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 256; +pub const O_EXCL: ::c_int = 1024; +pub const O_NOCTTY: ::c_int = 2048; +pub const O_NONBLOCK: ::c_int = 128; +pub const O_SYNC: ::c_int = 0x10; +pub const O_RSYNC: ::c_int = 0x10; +pub const O_DSYNC: ::c_int = 0x10; +pub const O_FSYNC: ::c_int = 0x10; +pub const O_ASYNC: ::c_int = 0x1000; +pub const O_NDELAY: ::c_int = 0x80; + +pub const SOCK_NONBLOCK: ::c_int = 128; + +pub const EDEADLK: ::c_int = 45; +pub const ENAMETOOLONG: ::c_int = 78; +pub const ENOLCK: ::c_int = 46; +pub const ENOSYS: ::c_int = 89; +pub const ENOTEMPTY: ::c_int = 93; +pub const ELOOP: ::c_int = 90; +pub const ENOMSG: ::c_int = 35; +pub const EIDRM: ::c_int = 36; +pub const ECHRNG: ::c_int = 37; +pub const EL2NSYNC: ::c_int = 38; +pub const EL3HLT: ::c_int = 39; +pub const EL3RST: ::c_int = 40; +pub const ELNRNG: ::c_int = 41; +pub const EUNATCH: ::c_int = 42; +pub const ENOCSI: ::c_int = 43; +pub const EL2HLT: ::c_int = 44; +pub const EBADE: ::c_int = 50; +pub const EBADR: ::c_int = 51; +pub const EXFULL: ::c_int = 52; +pub const ENOANO: ::c_int = 53; +pub const EBADRQC: ::c_int = 54; +pub const EBADSLT: ::c_int = 55; +pub const EDEADLOCK: ::c_int = 56; +pub const EMULTIHOP: ::c_int = 74; +pub const EOVERFLOW: ::c_int = 79; +pub const ENOTUNIQ: ::c_int = 80; +pub const EBADFD: ::c_int = 81; +pub const EBADMSG: ::c_int = 77; +pub const EREMCHG: ::c_int = 82; +pub const ELIBACC: ::c_int = 83; +pub const ELIBBAD: ::c_int = 84; +pub const ELIBSCN: ::c_int = 85; +pub const ELIBMAX: ::c_int = 86; +pub const ELIBEXEC: ::c_int = 87; +pub const EILSEQ: ::c_int = 88; +pub const ERESTART: ::c_int = 91; +pub const ESTRPIPE: ::c_int = 92; +pub const EUSERS: ::c_int = 94; +pub const ENOTSOCK: ::c_int = 95; +pub const EDESTADDRREQ: ::c_int = 96; +pub const EMSGSIZE: ::c_int = 97; +pub const EPROTOTYPE: ::c_int = 98; +pub const ENOPROTOOPT: ::c_int = 99; +pub const EPROTONOSUPPORT: ::c_int = 120; +pub const ESOCKTNOSUPPORT: ::c_int = 121; +pub const EOPNOTSUPP: ::c_int = 122; +pub const ENOTSUP: ::c_int = EOPNOTSUPP; +pub const EPFNOSUPPORT: ::c_int = 123; +pub const EAFNOSUPPORT: ::c_int = 124; +pub const EADDRINUSE: ::c_int = 125; +pub const EADDRNOTAVAIL: ::c_int = 126; +pub const ENETDOWN: ::c_int = 127; +pub const ENETUNREACH: ::c_int = 128; +pub const ENETRESET: ::c_int = 129; +pub const ECONNABORTED: ::c_int = 130; +pub const ECONNRESET: ::c_int = 131; +pub const ENOBUFS: ::c_int = 132; +pub const EISCONN: ::c_int = 133; +pub const ENOTCONN: ::c_int = 134; +pub const ESHUTDOWN: ::c_int = 143; +pub const ETOOMANYREFS: ::c_int = 144; +pub const ETIMEDOUT: ::c_int = 145; +pub const ECONNREFUSED: ::c_int = 146; +pub const EHOSTDOWN: ::c_int = 147; +pub const EHOSTUNREACH: ::c_int = 148; +pub const EALREADY: ::c_int = 149; +pub const EINPROGRESS: ::c_int = 150; +pub const ESTALE: ::c_int = 151; +pub const EUCLEAN: ::c_int = 135; +pub const ENOTNAM: ::c_int = 137; +pub const ENAVAIL: ::c_int = 138; +pub const EISNAM: ::c_int = 139; +pub const EREMOTEIO: ::c_int = 140; +pub const EDQUOT: ::c_int = 1133; +pub const ENOMEDIUM: ::c_int = 159; +pub const EMEDIUMTYPE: ::c_int = 160; +pub const ECANCELED: ::c_int = 158; +pub const ENOKEY: ::c_int = 161; +pub const EKEYEXPIRED: ::c_int = 162; +pub const EKEYREVOKED: ::c_int = 163; +pub const EKEYREJECTED: ::c_int = 164; +pub const EOWNERDEAD: ::c_int = 165; +pub const ENOTRECOVERABLE: ::c_int = 166; +pub const ERFKILL: ::c_int = 167; + +pub const MAP_NORESERVE: ::c_int = 0x400; +pub const MAP_ANON: ::c_int = 0x800; +pub const MAP_ANONYMOUS: ::c_int = 0x800; +pub const MAP_GROWSDOWN: ::c_int = 0x1000; +pub const MAP_DENYWRITE: ::c_int = 0x2000; +pub const MAP_EXECUTABLE: ::c_int = 0x4000; +pub const MAP_LOCKED: ::c_int = 0x8000; +pub const MAP_POPULATE: ::c_int = 0x10000; +pub const MAP_NONBLOCK: ::c_int = 0x20000; +pub const MAP_STACK: ::c_int = 0x40000; + +pub const SOCK_STREAM: ::c_int = 2; +pub const SOCK_DGRAM: ::c_int = 1; +pub const SOCK_SEQPACKET: ::c_int = 5; + +pub const SOL_SOCKET: ::c_int = 0xffff; + +pub const SO_REUSEADDR: ::c_int = 0x0004; +pub const SO_KEEPALIVE: ::c_int = 0x0008; +pub const SO_DONTROUTE: ::c_int = 0x0010; +pub const SO_BROADCAST: ::c_int = 0x0020; +pub const SO_LINGER: ::c_int = 0x0080; +pub const SO_OOBINLINE: ::c_int = 0x0100; +pub const SO_REUSEPORT: ::c_int = 0x0200; +pub const SO_TYPE: ::c_int = 0x1008; +pub const SO_STYLE: ::c_int = SO_TYPE; +pub const SO_ERROR: ::c_int = 0x1007; +pub const SO_SNDBUF: ::c_int = 0x1001; +pub const SO_RCVBUF: ::c_int = 0x1002; +pub const SO_SNDLOWAT: ::c_int = 0x1003; +pub const SO_RCVLOWAT: ::c_int = 0x1004; +pub const SO_SNDTIMEO: ::c_int = 0x1005; +pub const SO_RCVTIMEO: ::c_int = 0x1006; +pub const SO_ACCEPTCONN: ::c_int = 0x1009; +pub const SO_PROTOCOL: ::c_int = 0x1028; +pub const SO_DOMAIN: ::c_int = 0x1029; +pub const SO_NO_CHECK: ::c_int = 11; +pub const SO_PRIORITY: ::c_int = 12; +pub const SO_BSDCOMPAT: ::c_int = 14; +pub const SO_PASSCRED: ::c_int = 17; +pub const SO_PEERCRED: ::c_int = 18; +pub const SO_SECURITY_AUTHENTICATION: ::c_int = 22; +pub const SO_SECURITY_ENCRYPTION_TRANSPORT: ::c_int = 23; +pub const SO_SECURITY_ENCRYPTION_NETWORK: ::c_int = 24; +pub const SO_BINDTODEVICE: ::c_int = 25; +pub const SO_ATTACH_FILTER: ::c_int = 26; +pub const SO_DETACH_FILTER: ::c_int = 27; +pub const SO_GET_FILTER: ::c_int = SO_ATTACH_FILTER; +pub const SO_PEERNAME: ::c_int = 28; +pub const SO_TIMESTAMP: ::c_int = 29; +pub const SCM_TIMESTAMP: ::c_int = SO_TIMESTAMP; +pub const SO_PEERSEC: ::c_int = 30; +pub const SO_SNDBUFFORCE: ::c_int = 31; +pub const SO_RCVBUFFORCE: ::c_int = 33; +pub const SO_PASSSEC: ::c_int = 34; +pub const SO_TIMESTAMPNS: ::c_int = 35; +pub const SCM_TIMESTAMPNS: ::c_int = SO_TIMESTAMPNS; +pub const SO_MARK: ::c_int = 36; +pub const SO_TIMESTAMPING: ::c_int = 37; +pub const SCM_TIMESTAMPING: ::c_int = SO_TIMESTAMPING; +pub const SO_RXQ_OVFL: ::c_int = 40; +pub const SO_WIFI_STATUS: ::c_int = 41; +pub const SCM_WIFI_STATUS: ::c_int = SO_WIFI_STATUS; +pub const SO_PEEK_OFF: ::c_int = 42; +pub const SO_NOFCS: ::c_int = 43; +pub const SO_LOCK_FILTER: ::c_int = 44; +pub const SO_SELECT_ERR_QUEUE: ::c_int = 45; +pub const SO_BUSY_POLL: ::c_int = 46; +pub const SO_MAX_PACING_RATE: ::c_int = 47; +pub const SO_BPF_EXTENSIONS: ::c_int = 48; + +pub const FIOCLEX: ::c_ulong = 0x6601; +pub const FIONBIO: ::c_ulong = 0x667e; + +pub const SA_ONSTACK: ::c_uint = 0x08000000; +pub const SA_SIGINFO: ::c_uint = 0x00000008; +pub const SA_NOCLDWAIT: ::c_int = 0x00010000; + +pub const SIGCHLD: ::c_int = 18; +pub const SIGBUS: ::c_int = 10; +pub const SIGTTIN: ::c_int = 26; +pub const SIGTTOU: ::c_int = 27; +pub const SIGXCPU: ::c_int = 30; +pub const SIGXFSZ: ::c_int = 31; +pub const SIGVTALRM: ::c_int = 28; +pub const SIGPROF: ::c_int = 29; +pub const SIGWINCH: ::c_int = 20; +pub const SIGUSR1: ::c_int = 16; +pub const SIGUSR2: ::c_int = 17; +pub const SIGCONT: ::c_int = 25; +pub const SIGSTOP: ::c_int = 23; +pub const SIGTSTP: ::c_int = 24; +pub const SIGURG: ::c_int = 21; +pub const SIGIO: ::c_int = 22; +pub const SIGSYS: ::c_int = 12; +pub const SIGPOLL: ::c_int = 22; +pub const SIGPWR: ::c_int = 19; +pub const SIG_SETMASK: ::c_int = 3; +pub const SIG_BLOCK: ::c_int = 0x1; +pub const SIG_UNBLOCK: ::c_int = 0x2; + +pub const POLLRDNORM: ::c_short = 0x040; +pub const POLLWRNORM: ::c_short = 0x004; +pub const POLLRDBAND: ::c_short = 0x080; +pub const POLLWRBAND: ::c_short = 0x100; + +pub const PTHREAD_STACK_MIN: ::size_t = 16384; + +pub const ADFS_SUPER_MAGIC: ::c_long = 0x0000adf5; +pub const AFFS_SUPER_MAGIC: ::c_long = 0x0000adff; +pub const CODA_SUPER_MAGIC: ::c_long = 0x73757245; +pub const CRAMFS_MAGIC: ::c_long = 0x28cd3d45; +pub const EFS_SUPER_MAGIC: ::c_long = 0x00414a53; +pub const EXT2_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT3_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const EXT4_SUPER_MAGIC: ::c_long = 0x0000ef53; +pub const HPFS_SUPER_MAGIC: ::c_long = 0xf995e849; +pub const HUGETLBFS_MAGIC: ::c_long = 0x958458f6; +pub const ISOFS_SUPER_MAGIC: ::c_long = 0x00009660; +pub const JFFS2_SUPER_MAGIC: ::c_long = 0x000072b6; +pub const MINIX_SUPER_MAGIC: ::c_long = 0x0000137f; +pub const MINIX_SUPER_MAGIC2: ::c_long = 0x0000138f; +pub const MINIX2_SUPER_MAGIC: ::c_long = 0x00002468; +pub const MINIX2_SUPER_MAGIC2: ::c_long = 0x00002478; +pub const MSDOS_SUPER_MAGIC: ::c_long = 0x00004d44; +pub const NCP_SUPER_MAGIC: ::c_long = 0x0000564c; +pub const NFS_SUPER_MAGIC: ::c_long = 0x00006969; +pub const OPENPROM_SUPER_MAGIC: ::c_long = 0x00009fa1; +pub const PROC_SUPER_MAGIC: ::c_long = 0x00009fa0; +pub const QNX4_SUPER_MAGIC: ::c_long = 0x0000002f; +pub const REISERFS_SUPER_MAGIC: ::c_long = 0x52654973; +pub const SMB_SUPER_MAGIC: ::c_long = 0x0000517b; +pub const TMPFS_MAGIC: ::c_long = 0x01021994; +pub const USBDEVICE_SUPER_MAGIC: ::c_long = 0x00009fa2; + +pub const VEOF: usize = 16; +pub const VEOL: usize = 17; +pub const VEOL2: usize = 6; +pub const VMIN: usize = 4; +pub const IEXTEN: ::tcflag_t = 0x00000100; +pub const TOSTOP: ::tcflag_t = 0x00008000; +pub const FLUSHO: ::tcflag_t = 0x00002000; +pub const IUTF8: ::tcflag_t = 0x00004000; +pub const TCSANOW: ::c_int = 0x540e; +pub const TCSADRAIN: ::c_int = 0x540f; +pub const TCSAFLUSH: ::c_int = 0x5410; + +pub const CPU_SETSIZE: ::c_int = 0x400; + +pub const PTRACE_TRACEME: ::c_uint = 0; +pub const PTRACE_PEEKTEXT: ::c_uint = 1; +pub const PTRACE_PEEKDATA: ::c_uint = 2; +pub const PTRACE_PEEKUSER: ::c_uint = 3; +pub const PTRACE_POKETEXT: ::c_uint = 4; +pub const PTRACE_POKEDATA: ::c_uint = 5; +pub const PTRACE_POKEUSER: ::c_uint = 6; +pub const PTRACE_CONT: ::c_uint = 7; +pub const PTRACE_KILL: ::c_uint = 8; +pub const PTRACE_SINGLESTEP: ::c_uint = 9; +pub const PTRACE_ATTACH: ::c_uint = 16; +pub const PTRACE_DETACH: ::c_uint = 17; +pub const PTRACE_SYSCALL: ::c_uint = 24; +pub const PTRACE_SETOPTIONS: ::c_uint = 0x4200; +pub const PTRACE_GETEVENTMSG: ::c_uint = 0x4201; +pub const PTRACE_GETSIGINFO: ::c_uint = 0x4202; +pub const PTRACE_SETSIGINFO: ::c_uint = 0x4203; +pub const PTRACE_GETFPREGS: ::c_uint = 14; +pub const PTRACE_SETFPREGS: ::c_uint = 15; +pub const PTRACE_GETFPXREGS: ::c_uint = 18; +pub const PTRACE_SETFPXREGS: ::c_uint = 19; +pub const PTRACE_GETREGS: ::c_uint = 12; +pub const PTRACE_SETREGS: ::c_uint = 13; + +pub const EFD_NONBLOCK: ::c_int = 0x80; + +pub const F_GETLK: ::c_int = 14; +pub const F_GETOWN: ::c_int = 23; +pub const F_SETOWN: ::c_int = 24; +pub const F_SETLK: ::c_int = 6; +pub const F_SETLKW: ::c_int = 7; + +pub const SFD_NONBLOCK: ::c_int = 0x80; + +pub const TCGETS: ::c_ulong = 0x540d; +pub const TCSETS: ::c_ulong = 0x540e; +pub const TCSETSW: ::c_ulong = 0x540f; +pub const TCSETSF: ::c_ulong = 0x5410; +pub const TCGETA: ::c_ulong = 0x5401; +pub const TCSETA: ::c_ulong = 0x5402; +pub const TCSETAW: ::c_ulong = 0x5403; +pub const TCSETAF: ::c_ulong = 0x5404; +pub const TCSBRK: ::c_ulong = 0x5405; +pub const TCXONC: ::c_ulong = 0x5406; +pub const TCFLSH: ::c_ulong = 0x5407; +pub const TIOCGSOFTCAR: ::c_ulong = 0x5481; +pub const TIOCSSOFTCAR: ::c_ulong = 0x5482; +pub const TIOCINQ: ::c_ulong = 0x467f; +pub const TIOCLINUX: ::c_ulong = 0x5483; +pub const TIOCGSERIAL: ::c_ulong = 0x5484; +pub const TIOCEXCL: ::c_ulong = 0x740d; +pub const TIOCNXCL: ::c_ulong = 0x740e; +pub const TIOCSCTTY: ::c_ulong = 0x5480; +pub const TIOCGPGRP: ::c_ulong = 0x40047477; +pub const TIOCSPGRP: ::c_ulong = 0x80047476; +pub const TIOCOUTQ: ::c_ulong = 0x7472; +pub const TIOCSTI: ::c_ulong = 0x5472; +pub const TIOCGWINSZ: ::c_ulong = 0x40087468; +pub const TIOCSWINSZ: ::c_ulong = 0x80087467; +pub const TIOCMGET: ::c_ulong = 0x741d; +pub const TIOCMBIS: ::c_ulong = 0x741b; +pub const TIOCMBIC: ::c_ulong = 0x741c; +pub const TIOCMSET: ::c_ulong = 0x741a; +pub const FIONREAD: ::c_ulong = 0x467f; +pub const TIOCCONS: ::c_ulong = 0x80047478; + +pub const RTLD_DEEPBIND: ::c_int = 0x10; +pub const RTLD_GLOBAL: ::c_int = 0x4; +pub const RTLD_NOLOAD: ::c_int = 0x8; + +pub const LINUX_REBOOT_MAGIC1: ::c_int = 0xfee1dead; +pub const LINUX_REBOOT_MAGIC2: ::c_int = 672274793; +pub const LINUX_REBOOT_MAGIC2A: ::c_int = 85072278; +pub const LINUX_REBOOT_MAGIC2B: ::c_int = 369367448; +pub const LINUX_REBOOT_MAGIC2C: ::c_int = 537993216; + +pub const LINUX_REBOOT_CMD_RESTART: ::c_int = 0x01234567; +pub const LINUX_REBOOT_CMD_HALT: ::c_int = 0xCDEF0123; +pub const LINUX_REBOOT_CMD_CAD_ON: ::c_int = 0x89ABCDEF; +pub const LINUX_REBOOT_CMD_CAD_OFF: ::c_int = 0x00000000; +pub const LINUX_REBOOT_CMD_POWER_OFF: ::c_int = 0x4321FEDC; +pub const LINUX_REBOOT_CMD_RESTART2: ::c_int = 0xA1B2C3D4; +pub const LINUX_REBOOT_CMD_SW_SUSPEND: ::c_int = 0xD000FCE2; +pub const LINUX_REBOOT_CMD_KEXEC: ::c_int = 0x45584543; + +pub const MCL_CURRENT: ::c_int = 0x0001; +pub const MCL_FUTURE: ::c_int = 0x0002; + +pub const SIGSTKSZ: ::size_t = 8192; +pub const CBAUD: ::tcflag_t = 0o0010017; +pub const TAB1: ::c_int = 0x00000800; +pub const TAB2: ::c_int = 0x00001000; +pub const TAB3: ::c_int = 0x00001800; +pub const CR1: ::c_int = 0x00000200; +pub const CR2: ::c_int = 0x00000400; +pub const CR3: ::c_int = 0x00000600; +pub const FF1: ::c_int = 0x00008000; +pub const BS1: ::c_int = 0x00002000; +pub const VT1: ::c_int = 0x00004000; +pub const VWERASE: usize = 14; +pub const VREPRINT: usize = 12; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 8; +pub const VSTOP: usize = 9; +pub const VDISCARD: usize = 13; +pub const VTIME: usize = 5; +pub const IXON: ::tcflag_t = 0x00000400; +pub const IXOFF: ::tcflag_t = 0x00001000; +pub const ONLCR: ::tcflag_t = 0x4; +pub const CSIZE: ::tcflag_t = 0x00000030; +pub const CS6: ::tcflag_t = 0x00000010; +pub const CS7: ::tcflag_t = 0x00000020; +pub const CS8: ::tcflag_t = 0x00000030; +pub const CSTOPB: ::tcflag_t = 0x00000040; +pub const CREAD: ::tcflag_t = 0x00000080; +pub const PARENB: ::tcflag_t = 0x00000100; +pub const PARODD: ::tcflag_t = 0x00000200; +pub const HUPCL: ::tcflag_t = 0x00000400; +pub const CLOCAL: ::tcflag_t = 0x00000800; +pub const ECHOKE: ::tcflag_t = 0x00000800; +pub const ECHOE: ::tcflag_t = 0x00000010; +pub const ECHOK: ::tcflag_t = 0x00000020; +pub const ECHONL: ::tcflag_t = 0x00000040; +pub const ECHOPRT: ::tcflag_t = 0x00000400; +pub const ECHOCTL: ::tcflag_t = 0x00000200; +pub const ISIG: ::tcflag_t = 0x00000001; +pub const ICANON: ::tcflag_t = 0x00000002; +pub const PENDIN: ::tcflag_t = 0x00004000; +pub const NOFLSH: ::tcflag_t = 0x00000080; + +pub const B0: ::speed_t = 0o000000; +pub const B50: ::speed_t = 0o000001; +pub const B75: ::speed_t = 0o000002; +pub const B110: ::speed_t = 0o000003; +pub const B134: ::speed_t = 0o000004; +pub const B150: ::speed_t = 0o000005; +pub const B200: ::speed_t = 0o000006; +pub const B300: ::speed_t = 0o000007; +pub const B600: ::speed_t = 0o000010; +pub const B1200: ::speed_t = 0o000011; +pub const B1800: ::speed_t = 0o000012; +pub const B2400: ::speed_t = 0o000013; +pub const B4800: ::speed_t = 0o000014; +pub const B9600: ::speed_t = 0o000015; +pub const B19200: ::speed_t = 0o000016; +pub const B38400: ::speed_t = 0o000017; +pub const EXTA: ::speed_t = B19200; +pub const EXTB: ::speed_t = B38400; +pub const B57600: ::speed_t = 0o010001; +pub const B115200: ::speed_t = 0o010002; +pub const B230400: ::speed_t = 0o010003; +pub const B460800: ::speed_t = 0o010004; +pub const B500000: ::speed_t = 0o010005; +pub const B576000: ::speed_t = 0o010006; +pub const B921600: ::speed_t = 0o010007; +pub const B1000000: ::speed_t = 0o010010; +pub const B1152000: ::speed_t = 0o010011; +pub const B1500000: ::speed_t = 0o010012; +pub const B2000000: ::speed_t = 0o010013; +pub const B2500000: ::speed_t = 0o010014; +pub const B3000000: ::speed_t = 0o010015; +pub const B3500000: ::speed_t = 0o010016; +pub const B4000000: ::speed_t = 0o010017; + +cfg_if! { + if #[cfg(target_arch = "mips")] { + mod mips32; + pub use self::mips32::*; + } else if #[cfg(target_arch = "mips64")] { + mod mips64; + pub use self::mips64::*; + } else { + // Unknown target_arch + } +} diff --git a/libc/src/unix/uclibc/mod.rs b/libc/src/unix/uclibc/mod.rs new file mode 100644 index 000000000..e3baba061 --- /dev/null +++ b/libc/src/unix/uclibc/mod.rs @@ -0,0 +1,1926 @@ +pub type sa_family_t = u16; +pub type pthread_key_t = ::c_uint; +pub type speed_t = ::c_uint; +pub type tcflag_t = ::c_uint; +pub type loff_t = ::c_longlong; +pub type clockid_t = ::c_int; +pub type key_t = ::c_int; +pub type id_t = ::c_uint; +pub type useconds_t = u32; +pub type dev_t = u64; +pub type socklen_t = u32; +pub type mode_t = u32; +pub type ino64_t = u64; +pub type off64_t = i64; +pub type blkcnt64_t = i64; +pub type rlim64_t = u64; +pub type shmatt_t = ::c_ulong; +pub type mqd_t = ::c_int; +pub type msgqnum_t = ::c_ulong; +pub type msglen_t = ::c_ulong; +pub type nfds_t = ::c_ulong; +pub type nl_item = ::c_int; +pub type idtype_t = ::c_uint; + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos64_t {} // TODO: fill this out with a struct +impl ::Copy for fpos64_t {} +impl ::Clone for fpos64_t { + fn clone(&self) -> fpos64_t { *self } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} + +s! { + pub struct in_addr { + pub s_addr: ::in_addr_t, + } + + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + pub struct addrinfo { + pub ai_flags: ::c_int, + pub ai_family: ::c_int, + pub ai_socktype: ::c_int, + pub ai_protocol: ::c_int, + pub ai_addrlen: socklen_t, + + pub ai_addr: *mut ::sockaddr, + + pub ai_canonname: *mut c_char, + + pub ai_next: *mut addrinfo, + } + + pub struct sockaddr_nl { + pub nl_family: ::sa_family_t, + nl_pad: ::c_ushort, + pub nl_pid: u32, + pub nl_groups: u32 + } + + pub struct sockaddr_ll { + pub sll_family: ::c_ushort, + pub sll_protocol: ::c_ushort, + pub sll_ifindex: ::c_int, + pub sll_hatype: ::c_ushort, + pub sll_pkttype: ::c_uchar, + pub sll_halen: ::c_uchar, + pub sll_addr: [::c_uchar; 8] + } + + pub struct fd_set { + fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE], + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + pub tm_gmtoff: ::c_long, + pub tm_zone: *const ::c_char, + } + + pub struct sched_param { + pub sched_priority: ::c_int, + } + + pub struct Dl_info { + pub dli_fname: *const ::c_char, + pub dli_fbase: *mut ::c_void, + pub dli_sname: *const ::c_char, + pub dli_saddr: *mut ::c_void, + } + + pub struct lconv { + pub decimal_point: *mut ::c_char, + pub thousands_sep: *mut ::c_char, + pub grouping: *mut ::c_char, + pub int_curr_symbol: *mut ::c_char, + pub currency_symbol: *mut ::c_char, + pub mon_decimal_point: *mut ::c_char, + pub mon_thousands_sep: *mut ::c_char, + pub mon_grouping: *mut ::c_char, + pub positive_sign: *mut ::c_char, + pub negative_sign: *mut ::c_char, + pub int_frac_digits: ::c_char, + pub frac_digits: ::c_char, + pub p_cs_precedes: ::c_char, + pub p_sep_by_space: ::c_char, + pub n_cs_precedes: ::c_char, + pub n_sep_by_space: ::c_char, + pub p_sign_posn: ::c_char, + pub n_sign_posn: ::c_char, + pub int_p_cs_precedes: ::c_char, + pub int_p_sep_by_space: ::c_char, + pub int_n_cs_precedes: ::c_char, + pub int_n_sep_by_space: ::c_char, + pub int_p_sign_posn: ::c_char, + pub int_n_sign_posn: ::c_char, + } + + pub struct sigevent { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + // Actually a union. We only expose sigev_notify_thread_id because it's + // the most useful member + pub sigev_notify_thread_id: ::c_int, + #[cfg(target_pointer_width = "64")] + __unused1: [::c_int; 11], + #[cfg(target_pointer_width = "32")] + __unused1: [::c_int; 12] + } + + pub struct rlimit64 { + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct glob_t { + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct ifaddrs { + pub ifa_next: *mut ifaddrs, + pub ifa_name: *mut c_char, + pub ifa_flags: ::c_uint, + pub ifa_addr: *mut ::sockaddr, + pub ifa_netmask: *mut ::sockaddr, + pub ifa_ifu: *mut ::sockaddr, // FIXME This should be a union + pub ifa_data: *mut ::c_void + } + + pub struct pthread_rwlockattr_t { + __lockkind: ::c_int, + __pshared: ::c_int, + } + + pub struct passwd { + pub pw_name: *mut ::c_char, + pub pw_passwd: *mut ::c_char, + pub pw_uid: ::uid_t, + pub pw_gid: ::gid_t, + pub pw_gecos: *mut ::c_char, + pub pw_dir: *mut ::c_char, + pub pw_shell: *mut ::c_char, + } + + pub struct spwd { + pub sp_namp: *mut ::c_char, + pub sp_pwdp: *mut ::c_char, + pub sp_lstchg: ::c_long, + pub sp_min: ::c_long, + pub sp_max: ::c_long, + pub sp_warn: ::c_long, + pub sp_inact: ::c_long, + pub sp_expire: ::c_long, + pub sp_flag: ::c_ulong, + } + + pub struct statvfs { + pub f_bsize: ::c_ulong, + pub f_frsize: ::c_ulong, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_favail: ::fsfilcnt_t, + #[cfg(target_endian = "little")] + pub f_fsid: ::c_ulong, + #[cfg(target_pointer_width = "32")] + __f_unused: ::c_int, + #[cfg(target_endian = "big")] + pub f_fsid: ::c_ulong, + pub f_flag: ::c_ulong, + pub f_namemax: ::c_ulong, + __f_spare: [::c_int; 6], + } + + pub struct dqblk { + pub dqb_bhardlimit: ::uint32_t, + pub dqb_bsoftlimit: ::uint32_t, + pub dqb_curblocks: ::uint32_t, + pub dqb_ihardlimit: ::uint32_t, + pub dqb_isoftlimit: ::uint32_t, + pub dqb_curinodes: ::uint32_t, + pub dqb_btime: ::time_t, + pub dqb_itime: ::time_t, + } + + pub struct signalfd_siginfo { + pub ssi_signo: ::uint32_t, + pub ssi_errno: ::int32_t, + pub ssi_code: ::int32_t, + pub ssi_pid: ::uint32_t, + pub ssi_uid: ::uint32_t, + pub ssi_fd: ::int32_t, + pub ssi_tid: ::uint32_t, + pub ssi_band: ::uint32_t, + pub ssi_overrun: ::uint32_t, + pub ssi_trapno: ::uint32_t, + pub ssi_status: ::int32_t, + pub ssi_int: ::int32_t, + pub ssi_ptr: ::uint64_t, + pub ssi_utime: ::uint64_t, + pub ssi_stime: ::uint64_t, + pub ssi_addr: ::uint64_t, + pub ssi_addr_lsb: ::uint16_t, + _pad2: ::uint16_t, + pub ssi_syscall: ::int32_t, + pub ssi_call_addr: ::uint64_t, + pub ssi_arch: ::uint32_t, + _pad: [::uint8_t; 28], + } + + pub struct fsid_t { + __val: [::c_int; 2], + } + + pub struct mq_attr { + pub mq_flags: ::c_long, + pub mq_maxmsg: ::c_long, + pub mq_msgsize: ::c_long, + pub mq_curmsgs: ::c_long, + pad: [::c_long; 4] + } + + pub struct cpu_set_t { + #[cfg(target_pointer_width = "32")] + bits: [u32; 32], + #[cfg(target_pointer_width = "64")] + bits: [u64; 16], + } + + pub struct if_nameindex { + pub if_index: ::c_uint, + pub if_name: *mut ::c_char, + } + + // System V IPC + pub struct msginfo { + pub msgpool: ::c_int, + pub msgmap: ::c_int, + pub msgmax: ::c_int, + pub msgmnb: ::c_int, + pub msgmni: ::c_int, + pub msgssz: ::c_int, + pub msgtql: ::c_int, + pub msgseg: ::c_ushort, + } +} + +s_no_extra_traits! { + #[cfg_attr( + any(target_arch = "x86", target_arch = "x86_64"), + repr(packed) + )] + #[allow(missing_debug_implementations)] + pub struct epoll_event { + pub events: ::uint32_t, + pub u64: ::uint64_t, + } + + #[allow(missing_debug_implementations)] + pub struct sockaddr_un { + pub sun_family: sa_family_t, + pub sun_path: [::c_char; 108] + } + + #[allow(missing_debug_implementations)] + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + __ss_align: ::size_t, + #[cfg(target_pointer_width = "32")] + __ss_pad2: [u8; 128 - 2 * 4], + #[cfg(target_pointer_width = "64")] + __ss_pad2: [u8; 128 - 2 * 8], + } + + #[allow(missing_debug_implementations)] + pub struct utsname { + pub sysname: [::c_char; 65], + pub nodename: [::c_char; 65], + pub release: [::c_char; 65], + pub version: [::c_char; 65], + pub machine: [::c_char; 65], + pub domainname: [::c_char; 65] + } + + #[allow(missing_debug_implementations)] + pub struct dirent { + pub d_ino: ::ino_t, + pub d_off: ::off_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } + + #[allow(missing_debug_implementations)] + pub struct dirent64 { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: ::c_ushort, + pub d_type: ::c_uchar, + pub d_name: [::c_char; 256], + } +} + +// intentionally not public, only used for fd_set +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + const ULONG_SIZE: usize = 32; + } else if #[cfg(target_pointer_width = "64")] { + const ULONG_SIZE: usize = 64; + } else { + // Unknown target_pointer_width + } +} + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 2147483647; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 2; +pub const _IOLBF: ::c_int = 1; + +pub const F_DUPFD: ::c_int = 0; +pub const F_GETFD: ::c_int = 1; +pub const F_SETFD: ::c_int = 2; +pub const F_GETFL: ::c_int = 3; +pub const F_SETFL: ::c_int = 4; + +// Linux-specific fcntls +pub const F_SETLEASE: ::c_int = 1024; +pub const F_GETLEASE: ::c_int = 1025; +pub const F_NOTIFY: ::c_int = 1026; +pub const F_DUPFD_CLOEXEC: ::c_int = 1030; + +// TODO(#235): Include file sealing fcntls once we have a way to verify them. + +pub const SIGTRAP: ::c_int = 5; + +pub const PTHREAD_CREATE_JOINABLE: ::c_int = 0; +pub const PTHREAD_CREATE_DETACHED: ::c_int = 1; + +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_MONOTONIC: ::clockid_t = 1; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 2; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 3; +// TODO(#247) Someday our Travis shall have glibc 2.21 (released in Sep +// 2014.) See also musl/mod.rs +// pub const CLOCK_SGI_CYCLE: ::clockid_t = 10; +// pub const CLOCK_TAI: ::clockid_t = 11; +pub const TIMER_ABSTIME: ::c_int = 1; + +pub const RLIMIT_CPU: ::c_int = 0; +pub const RLIMIT_FSIZE: ::c_int = 1; +pub const RLIMIT_DATA: ::c_int = 2; +pub const RLIMIT_STACK: ::c_int = 3; +pub const RLIMIT_CORE: ::c_int = 4; +pub const RLIMIT_LOCKS: ::c_int = 10; +pub const RLIMIT_SIGPENDING: ::c_int = 11; +pub const RLIMIT_MSGQUEUE: ::c_int = 12; +pub const RLIMIT_NICE: ::c_int = 13; +pub const RLIMIT_RTPRIO: ::c_int = 14; + +pub const RUSAGE_SELF: ::c_int = 0; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; + +pub const SOCK_CLOEXEC: ::c_int = O_CLOEXEC; + +pub const S_IFIFO: ::mode_t = 4096; +pub const S_IFCHR: ::mode_t = 8192; +pub const S_IFBLK: ::mode_t = 24576; +pub const S_IFDIR: ::mode_t = 16384; +pub const S_IFREG: ::mode_t = 32768; +pub const S_IFLNK: ::mode_t = 40960; +pub const S_IFSOCK: ::mode_t = 49152; +pub const S_IFMT: ::mode_t = 61440; +pub const S_IRWXU: ::mode_t = 448; +pub const S_IXUSR: ::mode_t = 64; +pub const S_IWUSR: ::mode_t = 128; +pub const S_IRUSR: ::mode_t = 256; +pub const S_IRWXG: ::mode_t = 56; +pub const S_IXGRP: ::mode_t = 8; +pub const S_IWGRP: ::mode_t = 16; +pub const S_IRGRP: ::mode_t = 32; +pub const S_IRWXO: ::mode_t = 7; +pub const S_IXOTH: ::mode_t = 1; +pub const S_IWOTH: ::mode_t = 2; +pub const S_IROTH: ::mode_t = 4; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; +pub const SIGHUP: ::c_int = 1; +pub const SIGINT: ::c_int = 2; +pub const SIGQUIT: ::c_int = 3; +pub const SIGILL: ::c_int = 4; +pub const SIGABRT: ::c_int = 6; +pub const SIGFPE: ::c_int = 8; +pub const SIGKILL: ::c_int = 9; +pub const SIGSEGV: ::c_int = 11; +pub const SIGPIPE: ::c_int = 13; +pub const SIGALRM: ::c_int = 14; +pub const SIGTERM: ::c_int = 15; + +pub const PROT_NONE: ::c_int = 0; +pub const PROT_READ: ::c_int = 1; +pub const PROT_WRITE: ::c_int = 2; +pub const PROT_EXEC: ::c_int = 4; + +pub const LC_CTYPE: ::c_int = 0; +pub const LC_NUMERIC: ::c_int = 1; +pub const LC_MONETARY: ::c_int = 2; +pub const LC_TIME: ::c_int = 3; +pub const LC_COLLATE: ::c_int = 4; +pub const LC_MESSAGES: ::c_int = 5; +pub const LC_ALL: ::c_int = 6; +pub const LC_CTYPE_MASK: ::c_int = (1 << LC_CTYPE); +pub const LC_NUMERIC_MASK: ::c_int = (1 << LC_NUMERIC); +pub const LC_TIME_MASK: ::c_int = (1 << LC_TIME); +pub const LC_COLLATE_MASK: ::c_int = (1 << LC_COLLATE); +pub const LC_MONETARY_MASK: ::c_int = (1 << LC_MONETARY); +pub const LC_MESSAGES_MASK: ::c_int = (1 << LC_MESSAGES); +// LC_ALL_MASK defined per platform + +pub const MAP_FILE: ::c_int = 0x0000; +pub const MAP_SHARED: ::c_int = 0x0001; +pub const MAP_PRIVATE: ::c_int = 0x0002; +pub const MAP_FIXED: ::c_int = 0x0010; + +pub const MAP_FAILED: *mut ::c_void = !0 as *mut ::c_void; + +// MS_ flags for msync(2) +pub const MS_ASYNC: ::c_int = 0x0001; +pub const MS_INVALIDATE: ::c_int = 0x0002; +pub const MS_SYNC: ::c_int = 0x0004; + +// MS_ flags for mount(2) +pub const MS_RDONLY: ::c_ulong = 0x01; +pub const MS_NOSUID: ::c_ulong = 0x02; +pub const MS_NODEV: ::c_ulong = 0x04; +pub const MS_NOEXEC: ::c_ulong = 0x08; +pub const MS_SYNCHRONOUS: ::c_ulong = 0x10; +pub const MS_REMOUNT: ::c_ulong = 0x20; +pub const MS_MANDLOCK: ::c_ulong = 0x40; +pub const MS_NOATIME: ::c_ulong = 0x0400; +pub const MS_NODIRATIME: ::c_ulong = 0x0800; +pub const MS_BIND: ::c_ulong = 0x1000; +pub const MS_NOUSER: ::c_ulong = 0x80000000; +pub const MS_MGC_VAL: ::c_ulong = 0xc0ed0000; +pub const MS_MGC_MSK: ::c_ulong = 0xffff0000; +pub const MS_RMT_MASK: ::c_ulong = 0x800051; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const ENOTBLK: ::c_int = 15; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const ETXTBSY: ::c_int = 26; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EWOULDBLOCK: ::c_int = EAGAIN; + +pub const SCM_RIGHTS: ::c_int = 0x01; +pub const SCM_CREDENTIALS: ::c_int = 0x02; + +// netinet/in.h +// NOTE: These are in addition to the constants defined in src/unix/mod.rs + +// IPPROTO_IP defined in src/unix/mod.rs +/// Hop-by-hop option header +pub const IPPROTO_HOPOPTS: ::c_int = 0; +// IPPROTO_ICMP defined in src/unix/mod.rs +/// group mgmt protocol +pub const IPPROTO_IGMP: ::c_int = 2; +/// for compatibility +pub const IPPROTO_IPIP: ::c_int = 4; +// IPPROTO_TCP defined in src/unix/mod.rs +/// exterior gateway protocol +pub const IPPROTO_EGP: ::c_int = 8; +/// pup +pub const IPPROTO_PUP: ::c_int = 12; +// IPPROTO_UDP defined in src/unix/mod.rs +/// xns idp +pub const IPPROTO_IDP: ::c_int = 22; +/// tp-4 w/ class negotiation +pub const IPPROTO_TP: ::c_int = 29; +/// DCCP +pub const IPPROTO_DCCP: ::c_int = 33; +// IPPROTO_IPV6 defined in src/unix/mod.rs +/// IP6 routing header +pub const IPPROTO_ROUTING: ::c_int = 43; +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT: ::c_int = 44; +/// resource reservation +pub const IPPROTO_RSVP: ::c_int = 46; +/// General Routing Encap. +pub const IPPROTO_GRE: ::c_int = 47; +/// IP6 Encap Sec. Payload +pub const IPPROTO_ESP: ::c_int = 50; +/// IP6 Auth Header +pub const IPPROTO_AH: ::c_int = 51; +// IPPROTO_ICMPV6 defined in src/unix/mod.rs +/// IP6 no next header +pub const IPPROTO_NONE: ::c_int = 59; +/// IP6 destination option +pub const IPPROTO_DSTOPTS: ::c_int = 60; +pub const IPPROTO_MTP: ::c_int = 92; +pub const IPPROTO_BEETPH: ::c_int = 94; +/// encapsulation header +pub const IPPROTO_ENCAP: ::c_int = 98; +/// Protocol indep. multicast +pub const IPPROTO_PIM: ::c_int = 103; +/// IP Payload Comp. Protocol +pub const IPPROTO_COMP: ::c_int = 108; +/// SCTP +pub const IPPROTO_SCTP: ::c_int = 132; +pub const IPPROTO_MH: ::c_int = 135; +pub const IPPROTO_UDPLITE: ::c_int = 136; +pub const IPPROTO_MPLS: ::c_int = 137; +/// raw IP packet +pub const IPPROTO_RAW: ::c_int = 255; +pub const IPPROTO_MAX: ::c_int = 256; + +pub const PROT_GROWSDOWN: ::c_int = 0x1000000; +pub const PROT_GROWSUP: ::c_int = 0x2000000; + +pub const MAP_TYPE: ::c_int = 0x000f; + +pub const MADV_NORMAL: ::c_int = 0; +pub const MADV_RANDOM: ::c_int = 1; +pub const MADV_SEQUENTIAL: ::c_int = 2; +pub const MADV_WILLNEED: ::c_int = 3; +pub const MADV_DONTNEED: ::c_int = 4; +pub const MADV_REMOVE: ::c_int = 9; +pub const MADV_DONTFORK: ::c_int = 10; +pub const MADV_DOFORK: ::c_int = 11; +pub const MADV_MERGEABLE: ::c_int = 12; +pub const MADV_UNMERGEABLE: ::c_int = 13; +pub const MADV_HWPOISON: ::c_int = 100; + +// https://github.com/kraj/uClibc/blob/master/include/net/if.h#L44 +pub const IFF_UP: ::c_int = 0x1; // Interface is up. +pub const IFF_BROADCAST: ::c_int = 0x2; // Broadcast address valid. +pub const IFF_DEBUG: ::c_int = 0x4; // Turn on debugging. +pub const IFF_LOOPBACK: ::c_int = 0x8; // Is a loopback net. +pub const IFF_POINTOPOINT: ::c_int = 0x10; // Interface is point-to-point link. +pub const IFF_NOTRAILERS: ::c_int = 0x20; // Avoid use of trailers. +pub const IFF_RUNNING: ::c_int = 0x40; // Resources allocated. +pub const IFF_NOARP: ::c_int = 0x80; // No address resolution protocol. +pub const IFF_PROMISC: ::c_int = 0x100; // Receive all packets. +// Not supported +pub const IFF_ALLMULTI: ::c_int = 0x200; // Receive all multicast packets. +pub const IFF_MASTER: ::c_int = 0x400; // Master of a load balancer. +pub const IFF_SLAVE: ::c_int = 0x800; // Slave of a load balancer. +pub const IFF_MULTICAST: ::c_int = 0x1000; // Supports multicast. +pub const IFF_PORTSEL: ::c_int = 0x2000; // Can set media type. +pub const IFF_AUTOMEDIA: ::c_int = 0x4000; // Auto media select active. +// Dialup device with changing addresses. +pub const IFF_DYNAMIC: ::c_int = 0x8000; + +pub const SOL_IP: ::c_int = 0; +pub const SOL_TCP: ::c_int = 6; +pub const SOL_IPV6: ::c_int = 41; +pub const SOL_ICMPV6: ::c_int = 58; +pub const SOL_RAW: ::c_int = 255; +pub const SOL_DECNET: ::c_int = 261; +pub const SOL_X25: ::c_int = 262; +pub const SOL_PACKET: ::c_int = 263; +pub const SOL_ATM: ::c_int = 264; +pub const SOL_AAL: ::c_int = 265; +pub const SOL_IRDA: ::c_int = 266; + +pub const AF_UNSPEC: ::c_int = 0; +pub const AF_UNIX: ::c_int = 1; +pub const AF_LOCAL: ::c_int = 1; +pub const AF_INET: ::c_int = 2; +pub const AF_AX25: ::c_int = 3; +pub const AF_IPX: ::c_int = 4; +pub const AF_APPLETALK: ::c_int = 5; +pub const AF_NETROM: ::c_int = 6; +pub const AF_BRIDGE: ::c_int = 7; +pub const AF_ATMPVC: ::c_int = 8; +pub const AF_X25: ::c_int = 9; +pub const AF_INET6: ::c_int = 10; +pub const AF_ROSE: ::c_int = 11; +pub const AF_DECnet: ::c_int = 12; +pub const AF_NETBEUI: ::c_int = 13; +pub const AF_SECURITY: ::c_int = 14; +pub const AF_KEY: ::c_int = 15; +pub const AF_NETLINK: ::c_int = 16; +pub const AF_ROUTE: ::c_int = AF_NETLINK; +pub const AF_PACKET: ::c_int = 17; +pub const AF_ASH: ::c_int = 18; +pub const AF_ECONET: ::c_int = 19; +pub const AF_ATMSVC: ::c_int = 20; +pub const AF_SNA: ::c_int = 22; +pub const AF_IRDA: ::c_int = 23; +pub const AF_PPPOX: ::c_int = 24; +pub const AF_WANPIPE: ::c_int = 25; +pub const AF_LLC: ::c_int = 26; +pub const AF_CAN: ::c_int = 29; +pub const AF_TIPC: ::c_int = 30; +pub const AF_BLUETOOTH: ::c_int = 31; +pub const AF_IUCV: ::c_int = 32; +pub const AF_RXRPC: ::c_int = 33; +pub const AF_ISDN: ::c_int = 34; +pub const AF_PHONET: ::c_int = 35; +pub const AF_IEEE802154: ::c_int = 36; +pub const AF_CAIF: ::c_int = 37; +pub const AF_ALG: ::c_int = 38; + +pub const PF_UNSPEC: ::c_int = AF_UNSPEC; +pub const PF_UNIX: ::c_int = AF_UNIX; +pub const PF_LOCAL: ::c_int = AF_LOCAL; +pub const PF_INET: ::c_int = AF_INET; +pub const PF_AX25: ::c_int = AF_AX25; +pub const PF_IPX: ::c_int = AF_IPX; +pub const PF_APPLETALK: ::c_int = AF_APPLETALK; +pub const PF_NETROM: ::c_int = AF_NETROM; +pub const PF_BRIDGE: ::c_int = AF_BRIDGE; +pub const PF_ATMPVC: ::c_int = AF_ATMPVC; +pub const PF_X25: ::c_int = AF_X25; +pub const PF_INET6: ::c_int = AF_INET6; +pub const PF_ROSE: ::c_int = AF_ROSE; +pub const PF_DECnet: ::c_int = AF_DECnet; +pub const PF_NETBEUI: ::c_int = AF_NETBEUI; +pub const PF_SECURITY: ::c_int = AF_SECURITY; +pub const PF_KEY: ::c_int = AF_KEY; +pub const PF_NETLINK: ::c_int = AF_NETLINK; +pub const PF_ROUTE: ::c_int = AF_ROUTE; +pub const PF_PACKET: ::c_int = AF_PACKET; +pub const PF_ASH: ::c_int = AF_ASH; +pub const PF_ECONET: ::c_int = AF_ECONET; +pub const PF_ATMSVC: ::c_int = AF_ATMSVC; +pub const PF_SNA: ::c_int = AF_SNA; +pub const PF_IRDA: ::c_int = AF_IRDA; +pub const PF_PPPOX: ::c_int = AF_PPPOX; +pub const PF_WANPIPE: ::c_int = AF_WANPIPE; +pub const PF_LLC: ::c_int = AF_LLC; +pub const PF_CAN: ::c_int = AF_CAN; +pub const PF_TIPC: ::c_int = AF_TIPC; +pub const PF_BLUETOOTH: ::c_int = AF_BLUETOOTH; +pub const PF_IUCV: ::c_int = AF_IUCV; +pub const PF_RXRPC: ::c_int = AF_RXRPC; +pub const PF_ISDN: ::c_int = AF_ISDN; +pub const PF_PHONET: ::c_int = AF_PHONET; +pub const PF_IEEE802154: ::c_int = AF_IEEE802154; +pub const PF_CAIF: ::c_int = AF_CAIF; +pub const PF_ALG: ::c_int = AF_ALG; + +pub const SOMAXCONN: ::c_int = 128; + +pub const MSG_OOB: ::c_int = 1; +pub const MSG_PEEK: ::c_int = 2; +pub const MSG_DONTROUTE: ::c_int = 4; +pub const MSG_CTRUNC: ::c_int = 8; +pub const MSG_TRUNC: ::c_int = 0x20; +pub const MSG_DONTWAIT: ::c_int = 0x40; +pub const MSG_EOR: ::c_int = 0x80; +pub const MSG_WAITALL: ::c_int = 0x100; +pub const MSG_FIN: ::c_int = 0x200; +pub const MSG_SYN: ::c_int = 0x400; +pub const MSG_CONFIRM: ::c_int = 0x800; +pub const MSG_RST: ::c_int = 0x1000; +pub const MSG_ERRQUEUE: ::c_int = 0x2000; +pub const MSG_NOSIGNAL: ::c_int = 0x4000; +pub const MSG_MORE: ::c_int = 0x8000; +pub const MSG_WAITFORONE: ::c_int = 0x10000; +pub const MSG_CMSG_CLOEXEC: ::c_int = 0x40000000; + +pub const SOCK_RAW: ::c_int = 3; +pub const IP_MULTICAST_TTL: ::c_int = 33; +pub const IP_MULTICAST_LOOP: ::c_int = 34; +pub const IP_TTL: ::c_int = 2; +pub const IP_HDRINCL: ::c_int = 3; +pub const IP_ADD_MEMBERSHIP: ::c_int = 35; +pub const IP_DROP_MEMBERSHIP: ::c_int = 36; +pub const IPV6_ADD_MEMBERSHIP: ::c_int = 20; +pub const IPV6_DROP_MEMBERSHIP: ::c_int = 21; + +pub const IPV6_JOIN_GROUP: ::c_int = 20; +pub const IPV6_LEAVE_GROUP: ::c_int = 21; + +pub const TCP_NODELAY: ::c_int = 1; +pub const TCP_MAXSEG: ::c_int = 2; +pub const TCP_CORK: ::c_int = 3; +pub const TCP_KEEPIDLE: ::c_int = 4; +pub const TCP_KEEPINTVL: ::c_int = 5; +pub const TCP_KEEPCNT: ::c_int = 6; +pub const TCP_SYNCNT: ::c_int = 7; +pub const TCP_LINGER2: ::c_int = 8; +pub const TCP_DEFER_ACCEPT: ::c_int = 9; +pub const TCP_WINDOW_CLAMP: ::c_int = 10; +pub const TCP_INFO: ::c_int = 11; +pub const TCP_QUICKACK: ::c_int = 12; +pub const TCP_CONGESTION: ::c_int = 13; + +pub const IPV6_MULTICAST_LOOP: ::c_int = 19; +pub const IPV6_V6ONLY: ::c_int = 26; + +pub const SO_DEBUG: ::c_int = 1; + +pub const SHUT_RD: ::c_int = 0; +pub const SHUT_WR: ::c_int = 1; +pub const SHUT_RDWR: ::c_int = 2; + +pub const LOCK_SH: ::c_int = 1; +pub const LOCK_EX: ::c_int = 2; +pub const LOCK_NB: ::c_int = 4; +pub const LOCK_UN: ::c_int = 8; + +pub const SS_ONSTACK: ::c_int = 1; +pub const SS_DISABLE: ::c_int = 2; + +pub const PATH_MAX: ::c_int = 4096; + +pub const FD_SETSIZE: usize = 1024; + +pub const EPOLLIN: ::c_int = 0x1; +pub const EPOLLPRI: ::c_int = 0x2; +pub const EPOLLOUT: ::c_int = 0x4; +pub const EPOLLRDNORM: ::c_int = 0x40; +pub const EPOLLRDBAND: ::c_int = 0x80; +pub const EPOLLWRNORM: ::c_int = 0x100; +pub const EPOLLWRBAND: ::c_int = 0x200; +pub const EPOLLMSG: ::c_int = 0x400; +pub const EPOLLERR: ::c_int = 0x8; +pub const EPOLLHUP: ::c_int = 0x10; +pub const EPOLLET: ::c_int = 0x80000000; + +pub const EPOLL_CTL_ADD: ::c_int = 1; +pub const EPOLL_CTL_MOD: ::c_int = 3; +pub const EPOLL_CTL_DEL: ::c_int = 2; + +pub const MNT_DETACH: ::c_int = 0x2; +pub const MNT_EXPIRE: ::c_int = 0x4; + +pub const MNT_FORCE: ::c_int = 0x1; + +pub const Q_SYNC: ::c_int = 0x600; +pub const Q_QUOTAON: ::c_int = 0x100; +pub const Q_QUOTAOFF: ::c_int = 0x200; +pub const Q_GETQUOTA: ::c_int = 0x300; +pub const Q_SETQUOTA: ::c_int = 0x400; + +pub const TCIOFF: ::c_int = 2; +pub const TCION: ::c_int = 3; +pub const TCOOFF: ::c_int = 0; +pub const TCOON: ::c_int = 1; +pub const TCIFLUSH: ::c_int = 0; +pub const TCOFLUSH: ::c_int = 1; +pub const TCIOFLUSH: ::c_int = 2; +pub const NL0: ::c_int = 0x00000000; +pub const NL1: ::c_int = 0x00000100; +pub const TAB0: ::c_int = 0x00000000; +pub const CR0: ::c_int = 0x00000000; +pub const FF0: ::c_int = 0x00000000; +pub const BS0: ::c_int = 0x00000000; +pub const VT0: ::c_int = 0x00000000; +pub const VERASE: usize = 2; +pub const VKILL: usize = 3; +pub const VINTR: usize = 0; +pub const VQUIT: usize = 1; +pub const VLNEXT: usize = 15; +pub const IGNBRK: ::tcflag_t = 0x00000001; +pub const BRKINT: ::tcflag_t = 0x00000002; +pub const IGNPAR: ::tcflag_t = 0x00000004; +pub const PARMRK: ::tcflag_t = 0x00000008; +pub const INPCK: ::tcflag_t = 0x00000010; +pub const ISTRIP: ::tcflag_t = 0x00000020; +pub const INLCR: ::tcflag_t = 0x00000040; +pub const IGNCR: ::tcflag_t = 0x00000080; +pub const ICRNL: ::tcflag_t = 0x00000100; +pub const IXANY: ::tcflag_t = 0x00000800; +pub const IMAXBEL: ::tcflag_t = 0x00002000; +pub const OPOST: ::tcflag_t = 0x1; +pub const CS5: ::tcflag_t = 0x00000000; +pub const CRTSCTS: ::tcflag_t = 0x80000000; +pub const ECHO: ::tcflag_t = 0x00000008; + +pub const CLONE_VM: ::c_int = 0x100; +pub const CLONE_FS: ::c_int = 0x200; +pub const CLONE_FILES: ::c_int = 0x400; +pub const CLONE_SIGHAND: ::c_int = 0x800; +pub const CLONE_PTRACE: ::c_int = 0x2000; +pub const CLONE_VFORK: ::c_int = 0x4000; +pub const CLONE_PARENT: ::c_int = 0x8000; +pub const CLONE_THREAD: ::c_int = 0x10000; +pub const CLONE_NEWNS: ::c_int = 0x20000; +pub const CLONE_SYSVSEM: ::c_int = 0x40000; +pub const CLONE_SETTLS: ::c_int = 0x80000; +pub const CLONE_PARENT_SETTID: ::c_int = 0x100000; +pub const CLONE_CHILD_CLEARTID: ::c_int = 0x200000; +pub const CLONE_DETACHED: ::c_int = 0x400000; +pub const CLONE_UNTRACED: ::c_int = 0x800000; +pub const CLONE_CHILD_SETTID: ::c_int = 0x01000000; +pub const CLONE_NEWUTS: ::c_int = 0x04000000; +pub const CLONE_NEWIPC: ::c_int = 0x08000000; +pub const CLONE_NEWUSER: ::c_int = 0x10000000; +pub const CLONE_NEWPID: ::c_int = 0x20000000; +pub const CLONE_NEWNET: ::c_int = 0x40000000; +pub const CLONE_IO: ::c_int = 0x80000000; + +pub const WNOHANG: ::c_int = 0x00000001; +pub const WUNTRACED: ::c_int = 0x00000002; +pub const WSTOPPED: ::c_int = WUNTRACED; +pub const WEXITED: ::c_int = 0x00000004; +pub const WCONTINUED: ::c_int = 0x00000008; +pub const WNOWAIT: ::c_int = 0x01000000; + +pub const __WNOTHREAD: ::c_int = 0x20000000; +pub const __WALL: ::c_int = 0x40000000; +pub const __WCLONE: ::c_int = 0x80000000; + +pub const SPLICE_F_MOVE: ::c_uint = 0x01; +pub const SPLICE_F_NONBLOCK: ::c_uint = 0x02; +pub const SPLICE_F_MORE: ::c_uint = 0x04; +pub const SPLICE_F_GIFT: ::c_uint = 0x08; + +pub const RTLD_LOCAL: ::c_int = 0; +pub const RTLD_LAZY: ::c_int = 1; + +pub const POSIX_FADV_NORMAL: ::c_int = 0; +pub const POSIX_FADV_RANDOM: ::c_int = 1; +pub const POSIX_FADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_FADV_WILLNEED: ::c_int = 3; + +pub const AT_FDCWD: ::c_int = -100; +pub const AT_SYMLINK_NOFOLLOW: ::c_int = 0x100; +pub const AT_REMOVEDIR: ::c_int = 0x200; +pub const AT_SYMLINK_FOLLOW: ::c_int = 0x400; + +pub const LOG_CRON: ::c_int = 9 << 3; +pub const LOG_AUTHPRIV: ::c_int = 10 << 3; +pub const LOG_FTP: ::c_int = 11 << 3; +pub const LOG_PERROR: ::c_int = 0x20; + +pub const POLLIN: ::c_short = 0x1; +pub const POLLPRI: ::c_short = 0x2; +pub const POLLOUT: ::c_short = 0x4; +pub const POLLERR: ::c_short = 0x8; +pub const POLLHUP: ::c_short = 0x10; +pub const POLLNVAL: ::c_short = 0x20; + +pub const PIPE_BUF: usize = 4096; + +pub const SI_LOAD_SHIFT: ::c_uint = 16; + +pub const SIGEV_SIGNAL: ::c_int = 0; +pub const SIGEV_NONE: ::c_int = 1; +pub const SIGEV_THREAD: ::c_int = 2; + +pub const P_ALL: idtype_t = 0; +pub const P_PID: idtype_t = 1; +pub const P_PGID: idtype_t = 2; + +pub const UTIME_OMIT: c_long = 1073741822; +pub const UTIME_NOW: c_long = 1073741823; + +pub const L_tmpnam: ::c_uint = 20; +pub const _PC_LINK_MAX: ::c_int = 0; +pub const _PC_MAX_CANON: ::c_int = 1; +pub const _PC_MAX_INPUT: ::c_int = 2; +pub const _PC_NAME_MAX: ::c_int = 3; +pub const _PC_PATH_MAX: ::c_int = 4; +pub const _PC_PIPE_BUF: ::c_int = 5; +pub const _PC_CHOWN_RESTRICTED: ::c_int = 6; +pub const _PC_NO_TRUNC: ::c_int = 7; +pub const _PC_VDISABLE: ::c_int = 8; + +pub const _SC_ARG_MAX: ::c_int = 0; +pub const _SC_CHILD_MAX: ::c_int = 1; +pub const _SC_CLK_TCK: ::c_int = 2; +pub const _SC_NGROUPS_MAX: ::c_int = 3; +pub const _SC_OPEN_MAX: ::c_int = 4; +pub const _SC_STREAM_MAX: ::c_int = 5; +pub const _SC_TZNAME_MAX: ::c_int = 6; +pub const _SC_JOB_CONTROL: ::c_int = 7; +pub const _SC_SAVED_IDS: ::c_int = 8; +pub const _SC_REALTIME_SIGNALS: ::c_int = 9; +pub const _SC_PRIORITY_SCHEDULING: ::c_int = 10; +pub const _SC_TIMERS: ::c_int = 11; +pub const _SC_ASYNCHRONOUS_IO: ::c_int = 12; +pub const _SC_PRIORITIZED_IO: ::c_int = 13; +pub const _SC_SYNCHRONIZED_IO: ::c_int = 14; +pub const _SC_FSYNC: ::c_int = 15; +pub const _SC_MAPPED_FILES: ::c_int = 16; +pub const _SC_MEMLOCK: ::c_int = 17; +pub const _SC_MEMLOCK_RANGE: ::c_int = 18; +pub const _SC_MEMORY_PROTECTION: ::c_int = 19; +pub const _SC_MESSAGE_PASSING: ::c_int = 20; +pub const _SC_SEMAPHORES: ::c_int = 21; +pub const _SC_SHARED_MEMORY_OBJECTS: ::c_int = 22; +pub const _SC_AIO_LISTIO_MAX: ::c_int = 23; +pub const _SC_AIO_MAX: ::c_int = 24; +pub const _SC_AIO_PRIO_DELTA_MAX: ::c_int = 25; +pub const _SC_DELAYTIMER_MAX: ::c_int = 26; +pub const _SC_MQ_OPEN_MAX: ::c_int = 27; +pub const _SC_MQ_PRIO_MAX: ::c_int = 28; +pub const _SC_VERSION: ::c_int = 29; +pub const _SC_PAGESIZE: ::c_int = 30; +pub const _SC_PAGE_SIZE: ::c_int = _SC_PAGESIZE; +pub const _SC_RTSIG_MAX: ::c_int = 31; +pub const _SC_SEM_NSEMS_MAX: ::c_int = 32; +pub const _SC_SEM_VALUE_MAX: ::c_int = 33; +pub const _SC_SIGQUEUE_MAX: ::c_int = 34; +pub const _SC_TIMER_MAX: ::c_int = 35; +pub const _SC_BC_BASE_MAX: ::c_int = 36; +pub const _SC_BC_DIM_MAX: ::c_int = 37; +pub const _SC_BC_SCALE_MAX: ::c_int = 38; +pub const _SC_BC_STRING_MAX: ::c_int = 39; +pub const _SC_COLL_WEIGHTS_MAX: ::c_int = 40; +pub const _SC_EXPR_NEST_MAX: ::c_int = 42; +pub const _SC_LINE_MAX: ::c_int = 43; +pub const _SC_RE_DUP_MAX: ::c_int = 44; +pub const _SC_2_VERSION: ::c_int = 46; +pub const _SC_2_C_BIND: ::c_int = 47; +pub const _SC_2_C_DEV: ::c_int = 48; +pub const _SC_2_FORT_DEV: ::c_int = 49; +pub const _SC_2_FORT_RUN: ::c_int = 50; +pub const _SC_2_SW_DEV: ::c_int = 51; +pub const _SC_2_LOCALEDEF: ::c_int = 52; +pub const _SC_IOV_MAX: ::c_int = 60; +pub const _SC_THREADS: ::c_int = 67; +pub const _SC_THREAD_SAFE_FUNCTIONS: ::c_int = 68; +pub const _SC_GETGR_R_SIZE_MAX: ::c_int = 69; +pub const _SC_GETPW_R_SIZE_MAX: ::c_int = 70; +pub const _SC_LOGIN_NAME_MAX: ::c_int = 71; +pub const _SC_TTY_NAME_MAX: ::c_int = 72; +pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: ::c_int = 73; +pub const _SC_THREAD_KEYS_MAX: ::c_int = 74; +pub const _SC_THREAD_STACK_MIN: ::c_int = 75; +pub const _SC_THREAD_THREADS_MAX: ::c_int = 76; +pub const _SC_THREAD_ATTR_STACKADDR: ::c_int = 77; +pub const _SC_THREAD_ATTR_STACKSIZE: ::c_int = 78; +pub const _SC_THREAD_PRIORITY_SCHEDULING: ::c_int = 79; +pub const _SC_THREAD_PRIO_INHERIT: ::c_int = 80; +pub const _SC_THREAD_PRIO_PROTECT: ::c_int = 81; +pub const _SC_NPROCESSORS_ONLN: ::c_int = 84; +pub const _SC_ATEXIT_MAX: ::c_int = 87; +pub const _SC_XOPEN_VERSION: ::c_int = 89; +pub const _SC_XOPEN_XCU_VERSION: ::c_int = 90; +pub const _SC_XOPEN_UNIX: ::c_int = 91; +pub const _SC_XOPEN_CRYPT: ::c_int = 92; +pub const _SC_XOPEN_ENH_I18N: ::c_int = 93; +pub const _SC_XOPEN_SHM: ::c_int = 94; +pub const _SC_2_CHAR_TERM: ::c_int = 95; +pub const _SC_2_UPE: ::c_int = 97; +pub const _SC_XBS5_ILP32_OFF32: ::c_int = 125; +pub const _SC_XBS5_ILP32_OFFBIG: ::c_int = 126; +pub const _SC_XBS5_LPBIG_OFFBIG: ::c_int = 128; +pub const _SC_XOPEN_LEGACY: ::c_int = 129; +pub const _SC_XOPEN_REALTIME: ::c_int = 130; +pub const _SC_XOPEN_REALTIME_THREADS: ::c_int = 131; +pub const _SC_HOST_NAME_MAX: ::c_int = 180; + +pub const RLIM_SAVED_MAX: ::rlim_t = RLIM_INFINITY; +pub const RLIM_SAVED_CUR: ::rlim_t = RLIM_INFINITY; + +pub const GLOB_ERR: ::c_int = 1 << 0; +pub const GLOB_MARK: ::c_int = 1 << 1; +pub const GLOB_NOSORT: ::c_int = 1 << 2; +pub const GLOB_DOOFFS: ::c_int = 1 << 3; +pub const GLOB_NOCHECK: ::c_int = 1 << 4; +pub const GLOB_APPEND: ::c_int = 1 << 5; +pub const GLOB_NOESCAPE: ::c_int = 1 << 6; + +pub const GLOB_NOSPACE: ::c_int = 1; +pub const GLOB_ABORTED: ::c_int = 2; +pub const GLOB_NOMATCH: ::c_int = 3; + +pub const POSIX_MADV_NORMAL: ::c_int = 0; +pub const POSIX_MADV_RANDOM: ::c_int = 1; +pub const POSIX_MADV_SEQUENTIAL: ::c_int = 2; +pub const POSIX_MADV_WILLNEED: ::c_int = 3; + +pub const S_IEXEC: mode_t = 64; +pub const S_IWRITE: mode_t = 128; +pub const S_IREAD: mode_t = 256; + +pub const F_LOCK: ::c_int = 1; +pub const F_TEST: ::c_int = 3; +pub const F_TLOCK: ::c_int = 2; +pub const F_ULOCK: ::c_int = 0; + +pub const ST_RDONLY: ::c_ulong = 1; +pub const ST_NOSUID: ::c_ulong = 2; +pub const ST_NODEV: ::c_ulong = 4; +pub const ST_NOEXEC: ::c_ulong = 8; +pub const ST_SYNCHRONOUS: ::c_ulong = 16; +pub const ST_MANDLOCK: ::c_ulong = 64; +pub const ST_WRITE: ::c_ulong = 128; +pub const ST_APPEND: ::c_ulong = 256; +pub const ST_IMMUTABLE: ::c_ulong = 512; +pub const ST_NOATIME: ::c_ulong = 1024; +pub const ST_NODIRATIME: ::c_ulong = 2048; + +pub const RTLD_NEXT: *mut ::c_void = -1i64 as *mut ::c_void; +pub const RTLD_DEFAULT: *mut ::c_void = 0i64 as *mut ::c_void; +pub const RTLD_NODELETE: ::c_int = 0x1000; +pub const RTLD_NOW: ::c_int = 0x2; + +pub const TCP_MD5SIG: ::c_int = 14; + +align_const! { + pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t { + size: [0; __SIZEOF_PTHREAD_MUTEX_T], + }; + pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t { + size: [0; __SIZEOF_PTHREAD_COND_T], + }; + pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t { + size: [0; __SIZEOF_PTHREAD_RWLOCK_T], + }; +} +pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0; +pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1; +pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2; +pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; + +pub const SCHED_OTHER: ::c_int = 0; +pub const SCHED_FIFO: ::c_int = 1; +pub const SCHED_RR: ::c_int = 2; +pub const SCHED_BATCH: ::c_int = 3; +pub const SCHED_IDLE: ::c_int = 5; + +// System V IPC +pub const IPC_PRIVATE: ::key_t = 0; + +pub const IPC_CREAT: ::c_int = 0o1000; +pub const IPC_EXCL: ::c_int = 0o2000; +pub const IPC_NOWAIT: ::c_int = 0o4000; + +pub const IPC_RMID: ::c_int = 0; +pub const IPC_SET: ::c_int = 1; +pub const IPC_STAT: ::c_int = 2; +pub const IPC_INFO: ::c_int = 3; +pub const MSG_STAT: ::c_int = 11; +pub const MSG_INFO: ::c_int = 12; + +pub const MSG_NOERROR: ::c_int = 0o10000; +pub const MSG_EXCEPT: ::c_int = 0o20000; + +pub const SHM_R: ::c_int = 0o400; +pub const SHM_W: ::c_int = 0o200; + +pub const SHM_RDONLY: ::c_int = 0o10000; +pub const SHM_RND: ::c_int = 0o20000; +pub const SHM_REMAP: ::c_int = 0o40000; + +pub const SHM_LOCK: ::c_int = 11; +pub const SHM_UNLOCK: ::c_int = 12; + +pub const SHM_HUGETLB: ::c_int = 0o4000; +pub const SHM_NORESERVE: ::c_int = 0o10000; + +pub const EPOLLRDHUP: ::c_int = 0x2000; +pub const EPOLLONESHOT: ::c_int = 0x40000000; + +pub const QFMT_VFS_OLD: ::c_int = 1; +pub const QFMT_VFS_V0: ::c_int = 2; + +pub const EFD_SEMAPHORE: ::c_int = 0x1; + +pub const LOG_NFACILITIES: ::c_int = 24; + +pub const SEM_FAILED: *mut ::sem_t = 0 as *mut sem_t; + +pub const RB_AUTOBOOT: ::c_int = 0x01234567u32 as i32; +pub const RB_HALT_SYSTEM: ::c_int = 0xcdef0123u32 as i32; +pub const RB_ENABLE_CAD: ::c_int = 0x89abcdefu32 as i32; +pub const RB_DISABLE_CAD: ::c_int = 0x00000000u32 as i32; +pub const RB_POWER_OFF: ::c_int = 0x4321fedcu32 as i32; + +pub const AI_PASSIVE: ::c_int = 0x0001; +pub const AI_CANONNAME: ::c_int = 0x0002; +pub const AI_NUMERICHOST: ::c_int = 0x0004; +pub const AI_V4MAPPED: ::c_int = 0x0008; +pub const AI_ALL: ::c_int = 0x0010; +pub const AI_ADDRCONFIG: ::c_int = 0x0020; + +pub const AI_NUMERICSERV: ::c_int = 0x0400; + +pub const EAI_BADFLAGS: ::c_int = -1; +pub const EAI_NONAME: ::c_int = -2; +pub const EAI_AGAIN: ::c_int = -3; +pub const EAI_FAIL: ::c_int = -4; +pub const EAI_FAMILY: ::c_int = -6; +pub const EAI_SOCKTYPE: ::c_int = -7; +pub const EAI_SERVICE: ::c_int = -8; +pub const EAI_MEMORY: ::c_int = -10; +pub const EAI_OVERFLOW: ::c_int = -12; + +pub const NI_NUMERICHOST: ::c_int = 1; +pub const NI_NUMERICSERV: ::c_int = 2; +pub const NI_NOFQDN: ::c_int = 4; +pub const NI_NAMEREQD: ::c_int = 8; +pub const NI_DGRAM: ::c_int = 16; + +pub const SYNC_FILE_RANGE_WAIT_BEFORE: ::c_uint = 1; +pub const SYNC_FILE_RANGE_WRITE: ::c_uint = 2; +pub const SYNC_FILE_RANGE_WAIT_AFTER: ::c_uint = 4; + +pub const EAI_SYSTEM: ::c_int = -11; + +pub const MREMAP_MAYMOVE: ::c_int = 1; +pub const MREMAP_FIXED: ::c_int = 2; + +pub const PR_SET_PDEATHSIG: ::c_int = 1; +pub const PR_GET_PDEATHSIG: ::c_int = 2; + +pub const PR_GET_DUMPABLE: ::c_int = 3; +pub const PR_SET_DUMPABLE: ::c_int = 4; + +pub const PR_GET_UNALIGN: ::c_int = 5; +pub const PR_SET_UNALIGN: ::c_int = 6; +pub const PR_UNALIGN_NOPRINT: ::c_int = 1; +pub const PR_UNALIGN_SIGBUS: ::c_int = 2; + +pub const PR_GET_KEEPCAPS: ::c_int = 7; +pub const PR_SET_KEEPCAPS: ::c_int = 8; + +pub const PR_GET_FPEMU: ::c_int = 9; +pub const PR_SET_FPEMU: ::c_int = 10; +pub const PR_FPEMU_NOPRINT: ::c_int = 1; +pub const PR_FPEMU_SIGFPE: ::c_int = 2; + +pub const PR_GET_FPEXC: ::c_int = 11; +pub const PR_SET_FPEXC: ::c_int = 12; +pub const PR_FP_EXC_SW_ENABLE: ::c_int = 0x80; +pub const PR_FP_EXC_DIV: ::c_int = 0x010000; +pub const PR_FP_EXC_OVF: ::c_int = 0x020000; +pub const PR_FP_EXC_UND: ::c_int = 0x040000; +pub const PR_FP_EXC_RES: ::c_int = 0x080000; +pub const PR_FP_EXC_INV: ::c_int = 0x100000; +pub const PR_FP_EXC_DISABLED: ::c_int = 0; +pub const PR_FP_EXC_NONRECOV: ::c_int = 1; +pub const PR_FP_EXC_ASYNC: ::c_int = 2; +pub const PR_FP_EXC_PRECISE: ::c_int = 3; + +pub const PR_GET_TIMING: ::c_int = 13; +pub const PR_SET_TIMING: ::c_int = 14; +pub const PR_TIMING_STATISTICAL: ::c_int = 0; +pub const PR_TIMING_TIMESTAMP: ::c_int = 1; + +pub const PR_SET_NAME: ::c_int = 15; +pub const PR_GET_NAME: ::c_int = 16; + +pub const PR_GET_ENDIAN: ::c_int = 19; +pub const PR_SET_ENDIAN: ::c_int = 20; +pub const PR_ENDIAN_BIG: ::c_int = 0; +pub const PR_ENDIAN_LITTLE: ::c_int = 1; +pub const PR_ENDIAN_PPC_LITTLE: ::c_int = 2; + +pub const PR_GET_SECCOMP: ::c_int = 21; +pub const PR_SET_SECCOMP: ::c_int = 22; + +pub const PR_CAPBSET_READ: ::c_int = 23; +pub const PR_CAPBSET_DROP: ::c_int = 24; + +pub const PR_GET_TSC: ::c_int = 25; +pub const PR_SET_TSC: ::c_int = 26; +pub const PR_TSC_ENABLE: ::c_int = 1; +pub const PR_TSC_SIGSEGV: ::c_int = 2; + +pub const PR_GET_SECUREBITS: ::c_int = 27; +pub const PR_SET_SECUREBITS: ::c_int = 28; + +pub const PR_SET_TIMERSLACK: ::c_int = 29; +pub const PR_GET_TIMERSLACK: ::c_int = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE: ::c_int = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE: ::c_int = 32; + +pub const PR_MCE_KILL: ::c_int = 33; +pub const PR_MCE_KILL_CLEAR: ::c_int = 0; +pub const PR_MCE_KILL_SET: ::c_int = 1; + +pub const PR_MCE_KILL_LATE: ::c_int = 0; +pub const PR_MCE_KILL_EARLY: ::c_int = 1; +pub const PR_MCE_KILL_DEFAULT: ::c_int = 2; + +pub const PR_MCE_KILL_GET: ::c_int = 34; + +pub const PR_SET_MM: ::c_int = 35; +pub const PR_SET_MM_START_CODE: ::c_int = 1; +pub const PR_SET_MM_END_CODE: ::c_int = 2; +pub const PR_SET_MM_START_DATA: ::c_int = 3; +pub const PR_SET_MM_END_DATA: ::c_int = 4; +pub const PR_SET_MM_START_STACK: ::c_int = 5; +pub const PR_SET_MM_START_BRK: ::c_int = 6; +pub const PR_SET_MM_BRK: ::c_int = 7; +pub const PR_SET_MM_ARG_START: ::c_int = 8; +pub const PR_SET_MM_ARG_END: ::c_int = 9; +pub const PR_SET_MM_ENV_START: ::c_int = 10; +pub const PR_SET_MM_ENV_END: ::c_int = 11; +pub const PR_SET_MM_AUXV: ::c_int = 12; +pub const PR_SET_MM_EXE_FILE: ::c_int = 13; +pub const PR_SET_MM_MAP: ::c_int = 14; +pub const PR_SET_MM_MAP_SIZE: ::c_int = 15; + +pub const PR_SET_PTRACER: ::c_int = 0x59616d61; + +pub const PR_SET_CHILD_SUBREAPER: ::c_int = 36; +pub const PR_GET_CHILD_SUBREAPER: ::c_int = 37; + +pub const PR_SET_NO_NEW_PRIVS: ::c_int = 38; +pub const PR_GET_NO_NEW_PRIVS: ::c_int = 39; + +pub const PR_GET_TID_ADDRESS: ::c_int = 40; + +pub const PR_SET_THP_DISABLE: ::c_int = 41; +pub const PR_GET_THP_DISABLE: ::c_int = 42; + +pub const GRND_NONBLOCK: ::c_uint = 0x0001; +pub const GRND_RANDOM: ::c_uint = 0x0002; + +pub const ABDAY_1: ::nl_item = 0x300; +pub const ABDAY_2: ::nl_item = 0x301; +pub const ABDAY_3: ::nl_item = 0x302; +pub const ABDAY_4: ::nl_item = 0x303; +pub const ABDAY_5: ::nl_item = 0x304; +pub const ABDAY_6: ::nl_item = 0x305; +pub const ABDAY_7: ::nl_item = 0x306; + +pub const DAY_1: ::nl_item = 0x307; +pub const DAY_2: ::nl_item = 0x308; +pub const DAY_3: ::nl_item = 0x309; +pub const DAY_4: ::nl_item = 0x30A; +pub const DAY_5: ::nl_item = 0x30B; +pub const DAY_6: ::nl_item = 0x30C; +pub const DAY_7: ::nl_item = 0x30D; + +pub const ABMON_1: ::nl_item = 0x30E; +pub const ABMON_2: ::nl_item = 0x30F; +pub const ABMON_3: ::nl_item = 0x310; +pub const ABMON_4: ::nl_item = 0x311; +pub const ABMON_5: ::nl_item = 0x312; +pub const ABMON_6: ::nl_item = 0x313; +pub const ABMON_7: ::nl_item = 0x314; +pub const ABMON_8: ::nl_item = 0x315; +pub const ABMON_9: ::nl_item = 0x316; +pub const ABMON_10: ::nl_item = 0x317; +pub const ABMON_11: ::nl_item = 0x318; +pub const ABMON_12: ::nl_item = 0x319; + +pub const MON_1: ::nl_item = 0x31A; +pub const MON_2: ::nl_item = 0x31B; +pub const MON_3: ::nl_item = 0x31C; +pub const MON_4: ::nl_item = 0x31D; +pub const MON_5: ::nl_item = 0x31E; +pub const MON_6: ::nl_item = 0x31F; +pub const MON_7: ::nl_item = 0x320; +pub const MON_8: ::nl_item = 0x321; +pub const MON_9: ::nl_item = 0x322; +pub const MON_10: ::nl_item = 0x323; +pub const MON_11: ::nl_item = 0x324; +pub const MON_12: ::nl_item = 0x325; + +pub const AM_STR: ::nl_item = 0x326; +pub const PM_STR: ::nl_item = 0x327; + +pub const D_T_FMT: ::nl_item = 0x328; +pub const D_FMT: ::nl_item = 0x329; +pub const T_FMT: ::nl_item = 0x32A; +pub const T_FMT_AMPM: ::nl_item = 0x32B; + +pub const ERA: ::nl_item = 0x32C; +pub const ERA_D_FMT: ::nl_item = 0x32E; +pub const ALT_DIGITS: ::nl_item = 0x32F; +pub const ERA_D_T_FMT: ::nl_item = 0x330; +pub const ERA_T_FMT: ::nl_item = 0x331; + +pub const CODESET: ::nl_item = 10; + +pub const CRNCYSTR: ::nl_item = 0x215; + +pub const RADIXCHAR: ::nl_item = 0x100; +pub const THOUSEP: ::nl_item = 0x101; + +pub const NOEXPR: ::nl_item = 0x501; +pub const YESSTR: ::nl_item = 0x502; +pub const NOSTR: ::nl_item = 0x503; + +pub const FILENAME_MAX: ::c_uint = 4095; + +pub const AF_MAX: ::c_int = 39; + +f! { + pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] &= !(1 << (fd % size)); + return + } + + pub fn FD_ISSET(fd: ::c_int, set: *mut fd_set) -> bool { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + return ((*set).fds_bits[fd / size] & (1 << (fd % size))) != 0 + } + + pub fn FD_SET(fd: ::c_int, set: *mut fd_set) -> () { + let fd = fd as usize; + let size = ::mem::size_of_val(&(*set).fds_bits[0]) * 8; + (*set).fds_bits[fd / size] |= 1 << (fd % size); + return + } + + pub fn FD_ZERO(set: *mut fd_set) -> () { + for slot in (*set).fds_bits.iter_mut() { + *slot = 0; + } + } + + pub fn WIFSTOPPED(status: ::c_int) -> bool { + (status & 0xff) == 0x7f + } + + pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WIFCONTINUED(status: ::c_int) -> bool { + status == 0xffff + } + + pub fn WIFSIGNALED(status: ::c_int) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 + } + + pub fn WTERMSIG(status: ::c_int) -> ::c_int { + status & 0x7f + } + + pub fn WIFEXITED(status: ::c_int) -> bool { + (status & 0x7f) == 0 + } + + pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + (status >> 8) & 0xff + } + + pub fn WCOREDUMP(status: ::c_int) -> bool { + (status & 0x80) != 0 + } + + pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () { + for slot in cpuset.bits.iter_mut() { + *slot = 0; + } + } + + pub fn CPU_SET(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] |= 1 << offset; + () + } + + pub fn CPU_CLR(cpu: usize, cpuset: &mut cpu_set_t) -> () { + let size_in_bits + = 8 * ::mem::size_of_val(&cpuset.bits[0]); // 32, 64 etc + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + cpuset.bits[idx] &= !(1 << offset); + () + } + + pub fn CPU_ISSET(cpu: usize, cpuset: &cpu_set_t) -> bool { + let size_in_bits = 8 * ::mem::size_of_val(&cpuset.bits[0]); + let (idx, offset) = (cpu / size_in_bits, cpu % size_in_bits); + 0 != (cpuset.bits[idx] & (1 << offset)) + } + + pub fn CPU_EQUAL(set1: &cpu_set_t, set2: &cpu_set_t) -> bool { + set1.bits == set2.bits + } + + pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + (cmd << 8) | (type_ & 0x00ff) + } +} + +extern { + pub fn sem_destroy(sem: *mut sem_t) -> ::c_int; + pub fn sem_init(sem: *mut sem_t, + pshared: ::c_int, + value: ::c_uint) + -> ::c_int; + + pub fn abs(i: ::c_int) -> ::c_int; + pub fn atof(s: *const ::c_char) -> ::c_double; + pub fn labs(i: ::c_long) -> ::c_long; + pub fn rand() -> ::c_int; + pub fn srand(seed: ::c_uint); + + pub fn fdatasync(fd: ::c_int) -> ::c_int; + pub fn mincore(addr: *mut ::c_void, len: ::size_t, + vec: *mut ::c_uchar) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_nanosleep(clk_id: ::clockid_t, + flags: ::c_int, + rqtp: *const ::timespec, + rmtp: *mut ::timespec) -> ::c_int; + pub fn clock_settime(clk_id: ::clockid_t, tp: *const ::timespec) -> ::c_int; + pub fn prctl(option: ::c_int, ...) -> ::c_int; + pub fn pthread_getattr_np(native: ::pthread_t, + attr: *mut ::pthread_attr_t) -> ::c_int; + pub fn pthread_attr_getguardsize(attr: *const ::pthread_attr_t, + guardsize: *mut ::size_t) -> ::c_int; + pub fn pthread_attr_getstack(attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t) -> ::c_int; + pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void; + pub fn setgroups(ngroups: ::size_t, + ptr: *const ::gid_t) -> ::c_int; + pub fn initgroups(user: *const ::c_char, group: ::gid_t) -> ::c_int; + pub fn sched_setscheduler(pid: ::pid_t, + policy: ::c_int, + param: *const ::sched_param) -> ::c_int; + pub fn sched_getscheduler(pid: ::pid_t) -> ::c_int; + pub fn sched_get_priority_max(policy: ::c_int) -> ::c_int; + pub fn sched_get_priority_min(policy: ::c_int) -> ::c_int; + pub fn epoll_create(size: ::c_int) -> ::c_int; + pub fn epoll_create1(flags: ::c_int) -> ::c_int; + pub fn epoll_ctl(epfd: ::c_int, + op: ::c_int, + fd: ::c_int, + event: *mut ::epoll_event) -> ::c_int; + pub fn epoll_wait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int) -> ::c_int; + pub fn pipe2(fds: *mut ::c_int, flags: ::c_int) -> ::c_int; + pub fn mount(src: *const ::c_char, + target: *const ::c_char, + fstype: *const ::c_char, + flags: ::c_ulong, + data: *const ::c_void) -> ::c_int; + pub fn umount(target: *const ::c_char) -> ::c_int; + pub fn umount2(target: *const ::c_char, flags: ::c_int) -> ::c_int; + pub fn clone(cb: extern fn(*mut ::c_void) -> ::c_int, + child_stack: *mut ::c_void, + flags: ::c_int, + arg: *mut ::c_void, ...) -> ::c_int; + pub fn statfs(path: *const ::c_char, buf: *mut statfs) -> ::c_int; + pub fn fstatfs(fd: ::c_int, buf: *mut statfs) -> ::c_int; + pub fn memrchr(cx: *const ::c_void, + c: ::c_int, + n: ::size_t) -> *mut ::c_void; + pub fn syscall(num: ::c_long, ...) -> ::c_long; + pub fn sendfile(out_fd: ::c_int, + in_fd: ::c_int, + offset: *mut off_t, + count: ::size_t) -> ::ssize_t; + pub fn splice(fd_in: ::c_int, + off_in: *mut ::loff_t, + fd_out: ::c_int, + off_out: *mut ::loff_t, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn tee(fd_in: ::c_int, + fd_out: ::c_int, + len: ::size_t, + flags: ::c_uint) -> ::ssize_t; + pub fn vmsplice(fd: ::c_int, + iov: *const ::iovec, + nr_segs: ::size_t, + flags: ::c_uint) -> ::ssize_t; + + pub fn posix_fadvise(fd: ::c_int, offset: ::off_t, len: ::off_t, + advise: ::c_int) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat(dirfd: ::c_int, path: *const ::c_char, + times: *const ::timespec, flag: ::c_int) -> ::c_int; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn newlocale(mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn creat64(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fstat64(fildes: ::c_int, buf: *mut stat64) -> ::c_int; + pub fn fstatat64(fildes: ::c_int, path: *const ::c_char, + buf: *mut stat64, flag: ::c_int) -> ::c_int; + pub fn ftruncate64(fd: ::c_int, length: off64_t) -> ::c_int; + pub fn getrlimit64(resource: ::c_int, rlim: *mut rlimit64) -> ::c_int; + pub fn lseek64(fd: ::c_int, offset: off64_t, whence: ::c_int) -> off64_t; + pub fn lstat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn mmap64(addr: *mut ::c_void, + len: ::size_t, + prot: ::c_int, + flags: ::c_int, + fd: ::c_int, + offset: off64_t) + -> *mut ::c_void; + pub fn open64(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn openat64(fd: ::c_int, + path: *const c_char, + oflag: ::c_int, ...) -> ::c_int; + pub fn pread64(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn pwrite64(fd: ::c_int, buf: *const ::c_void, count: ::size_t, + offset: off64_t) -> ::ssize_t; + pub fn readdir64(dirp: *mut ::DIR) -> *mut ::dirent64; + pub fn readdir64_r(dirp: *mut ::DIR, entry: *mut ::dirent64, + result: *mut *mut ::dirent64) -> ::c_int; + pub fn setrlimit64(resource: ::c_int, rlim: *const rlimit64) -> ::c_int; + pub fn stat64(path: *const c_char, buf: *mut stat64) -> ::c_int; + pub fn truncate64(path: *const c_char, length: off64_t) -> ::c_int; + pub fn eventfd(init: ::c_uint, flags: ::c_int) -> ::c_int; + + pub fn mknodat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t, dev: dev_t) -> ::c_int; + pub fn ppoll(fds: *mut ::pollfd, + nfds: nfds_t, + timeout: *const ::timespec, + sigmask: *const sigset_t) -> ::c_int; + pub fn pthread_condattr_getclock(attr: *const pthread_condattr_t, + clock_id: *mut clockid_t) -> ::c_int; + pub fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, + clock_id: ::clockid_t) -> ::c_int; + pub fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn sched_getaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *mut cpu_set_t) -> ::c_int; + pub fn sched_setaffinity(pid: ::pid_t, + cpusetsize: ::size_t, + cpuset: *const cpu_set_t) -> ::c_int; + pub fn unshare(flags: ::c_int) -> ::c_int; + pub fn sem_timedwait(sem: *mut sem_t, + abstime: *const ::timespec) -> ::c_int; + pub fn sem_getvalue(sem: *mut sem_t, + sval: *mut ::c_int) -> ::c_int; + pub fn accept4(fd: ::c_int, addr: *mut ::sockaddr, len: *mut ::socklen_t, + flg: ::c_int) -> ::c_int; + pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, + abstime: *const ::timespec) -> ::c_int; + pub fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, + pshared: ::c_int) -> ::c_int; + pub fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, + pshared: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getkind_np(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setkind_np(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, + val: *mut ::c_int) -> ::c_int; + pub fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, + val: ::c_int) -> ::c_int; + pub fn ptsname_r(fd: ::c_int, + buf: *mut ::c_char, + buflen: ::size_t) -> ::c_int; + pub fn clearenv() -> ::c_int; + pub fn waitid(idtype: idtype_t, id: id_t, infop: *mut ::siginfo_t, + options: ::c_int) -> ::c_int; + + pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; + + pub fn setpwent(); + pub fn endpwent(); + pub fn getpwent() -> *mut passwd; + pub fn setspent(); + pub fn endspent(); + pub fn getspent() -> *mut spwd; + pub fn getspnam(__name: *const ::c_char) -> *mut spwd; + + pub fn shm_open(name: *const c_char, oflag: ::c_int, + mode: mode_t) -> ::c_int; + + // System V IPC + pub fn shmget(key: ::key_t, size: ::size_t, shmflg: ::c_int) -> ::c_int; + pub fn shmat(shmid: ::c_int, + shmaddr: *const ::c_void, + shmflg: ::c_int) -> *mut ::c_void; + pub fn shmdt(shmaddr: *const ::c_void) -> ::c_int; + pub fn shmctl(shmid: ::c_int, + cmd: ::c_int, + buf: *mut ::shmid_ds) -> ::c_int; + pub fn ftok(pathname: *const ::c_char, proj_id: ::c_int) -> ::key_t; + pub fn msgctl(msqid: ::c_int, cmd: ::c_int, buf: *mut msqid_ds) -> ::c_int; + pub fn msgget(key: ::key_t, msgflg: ::c_int) -> ::c_int; + pub fn msgrcv(msqid: ::c_int, msgp: *mut ::c_void, msgsz: ::size_t, + msgtyp: ::c_long, msgflg: ::c_int) -> ::ssize_t; + pub fn msgsnd(msqid: ::c_int, msgp: *const ::c_void, msgsz: ::size_t, + msgflg: ::c_int) -> ::c_int; + + pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) + -> ::c_int; + pub fn __errno_location() -> *mut ::c_int; + + pub fn fopen64(filename: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn freopen64(filename: *const c_char, mode: *const c_char, + file: *mut ::FILE) -> *mut ::FILE; + pub fn tmpfile64() -> *mut ::FILE; + pub fn fgetpos64(stream: *mut ::FILE, ptr: *mut fpos64_t) -> ::c_int; + pub fn fsetpos64(stream: *mut ::FILE, ptr: *const fpos64_t) -> ::c_int; + pub fn fseeko64(stream: *mut ::FILE, + offset: ::off64_t, + whence: ::c_int) -> ::c_int; + pub fn ftello64(stream: *mut ::FILE) -> ::off64_t; + pub fn readahead(fd: ::c_int, offset: ::off64_t, + count: ::size_t) -> ::ssize_t; + pub fn getxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn lgetxattr(path: *const c_char, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn fgetxattr(filedes: ::c_int, name: *const c_char, + value: *mut ::c_void, size: ::size_t) -> ::ssize_t; + pub fn setxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn lsetxattr(path: *const c_char, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn fsetxattr(filedes: ::c_int, name: *const c_char, + value: *const ::c_void, size: ::size_t, + flags: ::c_int) -> ::c_int; + pub fn listxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn llistxattr(path: *const c_char, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn flistxattr(filedes: ::c_int, list: *mut c_char, + size: ::size_t) -> ::ssize_t; + pub fn removexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn lremovexattr(path: *const c_char, name: *const c_char) -> ::c_int; + pub fn fremovexattr(filedes: ::c_int, name: *const c_char) -> ::c_int; + pub fn signalfd(fd: ::c_int, + mask: *const ::sigset_t, + flags: ::c_int) -> ::c_int; + pub fn quotactl(cmd: ::c_int, + special: *const ::c_char, + id: ::c_int, + data: *mut ::c_char) -> ::c_int; + pub fn mq_open(name: *const ::c_char, oflag: ::c_int, ...) -> ::mqd_t; + pub fn mq_close(mqd: ::mqd_t) -> ::c_int; + pub fn mq_unlink(name: *const ::c_char) -> ::c_int; + pub fn mq_receive(mqd: ::mqd_t, + msg_ptr: *mut ::c_char, + msg_len: ::size_t, + msq_prio: *mut ::c_uint) -> ::ssize_t; + pub fn mq_send(mqd: ::mqd_t, + msg_ptr: *const ::c_char, + msg_len: ::size_t, + msq_prio: ::c_uint) -> ::c_int; + pub fn mq_getattr(mqd: ::mqd_t, attr: *mut ::mq_attr) -> ::c_int; + pub fn mq_setattr(mqd: ::mqd_t, + newattr: *const ::mq_attr, + oldattr: *mut ::mq_attr) -> ::c_int; + pub fn epoll_pwait(epfd: ::c_int, + events: *mut ::epoll_event, + maxevents: ::c_int, + timeout: ::c_int, + sigmask: *const ::sigset_t) -> ::c_int; + pub fn sethostname(name: *const ::c_char, len: ::size_t) -> ::c_int; + pub fn sigtimedwait(set: *const sigset_t, + info: *mut siginfo_t, + timeout: *const ::timespec) -> ::c_int; + pub fn sigwaitinfo(set: *const sigset_t, + info: *mut siginfo_t) -> ::c_int; + pub fn nl_langinfo_l(item: ::nl_item, locale: ::locale_t) -> *mut ::c_char; + pub fn prlimit(pid: ::pid_t, resource: ::c_int, new_limit: *const ::rlimit, + old_limit: *mut ::rlimit) -> ::c_int; + pub fn prlimit64(pid: ::pid_t, + resource: ::c_int, + new_limit: *const ::rlimit64, + old_limit: *mut ::rlimit64) -> ::c_int; + pub fn reboot(how_to: ::c_int) -> ::c_int; + pub fn setfsgid(gid: ::gid_t) -> ::c_int; + pub fn setfsuid(uid: ::uid_t) -> ::c_int; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; + + // Not available now on Android + pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, + mode: ::mode_t) -> ::c_int; + pub fn if_nameindex() -> *mut if_nameindex; + pub fn if_freenameindex(ptr: *mut if_nameindex); + pub fn sync_file_range(fd: ::c_int, offset: ::off64_t, + nbytes: ::off64_t, flags: ::c_uint) -> ::c_int; + pub fn getifaddrs(ifap: *mut *mut ::ifaddrs) -> ::c_int; + pub fn freeifaddrs(ifa: *mut ::ifaddrs); + + pub fn mremap(addr: *mut ::c_void, + len: ::size_t, + new_len: ::size_t, + flags: ::c_int, + ...) -> *mut ::c_void; + + pub fn glob(pattern: *const c_char, + flags: ::c_int, + errfunc: ::Option ::c_int>, + pglob: *mut ::glob_t) -> ::c_int; + pub fn globfree(pglob: *mut ::glob_t); + + pub fn shm_unlink(name: *const ::c_char) -> ::c_int; + + pub fn seekdir(dirp: *mut ::DIR, loc: ::c_long); + + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + + pub fn telldir(dirp: *mut ::DIR) -> ::c_long; + pub fn madvise(addr: *mut ::c_void, len: ::size_t, advice: ::c_int) + -> ::c_int; + + pub fn msync(addr: *mut ::c_void, len: ::size_t, flags: ::c_int) -> ::c_int; + + pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t, + flags: ::c_int, addr: *mut ::sockaddr, + addrlen: *mut ::socklen_t) -> ::ssize_t; + pub fn nl_langinfo(item: ::nl_item) -> *mut ::c_char; + + pub fn bind(socket: ::c_int, address: *const ::sockaddr, + address_len: ::socklen_t) -> ::c_int; + + pub fn writev(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + pub fn readv(fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int) -> ::ssize_t; + + pub fn sendmsg(fd: ::c_int, + msg: *const ::msghdr, + flags: ::c_int) -> ::ssize_t; + pub fn recvmsg(fd: ::c_int, msg: *mut ::msghdr, flags: ::c_int) + -> ::ssize_t; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrgid_r")] + pub fn getgrgid_r(gid: ::gid_t, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "sigaltstack$UNIX2003")] + #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")] + pub fn sigaltstack(ss: *const stack_t, + oss: *mut stack_t) -> ::c_int; + pub fn sem_close(sem: *mut sem_t) -> ::c_int; + pub fn getdtablesize() -> ::c_int; + #[cfg_attr(target_os = "solaris", link_name = "__posix_getgrnam_r")] + pub fn getgrnam_r(name: *const ::c_char, + grp: *mut ::group, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut ::group) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "pthread_sigmask$UNIX2003")] + pub fn pthread_sigmask(how: ::c_int, set: *const sigset_t, + oldset: *mut sigset_t) -> ::c_int; + pub fn sem_open(name: *const ::c_char, oflag: ::c_int, ...) -> *mut sem_t; + pub fn getgrnam(name: *const ::c_char) -> *mut ::group; + pub fn pthread_kill(thread: ::pthread_t, sig: ::c_int) -> ::c_int; + pub fn sem_unlink(name: *const ::c_char) -> ::c_int; + pub fn daemon(nochdir: ::c_int, noclose: ::c_int) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwnam_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwnam_r")] + pub fn getpwnam_r(name: *const ::c_char, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_getpwuid_r")] + pub fn getpwuid_r(uid: ::uid_t, + pwd: *mut passwd, + buf: *mut ::c_char, + buflen: ::size_t, + result: *mut *mut passwd) -> ::c_int; + #[cfg_attr(all(target_os = "macos", target_arch ="x86"), + link_name = "sigwait$UNIX2003")] + #[cfg_attr(target_os = "solaris", link_name = "__posix_sigwait")] + pub fn sigwait(set: *const sigset_t, + sig: *mut ::c_int) -> ::c_int; + pub fn pthread_atfork(prepare: ::Option, + parent: ::Option, + child: ::Option) -> ::c_int; + pub fn pthread_create(native: *mut ::pthread_t, + attr: *const ::pthread_attr_t, + f: extern fn(*mut ::c_void) -> *mut ::c_void, + value: *mut ::c_void) -> ::c_int; + pub fn getgrgid(gid: ::gid_t) -> *mut ::group; + #[cfg_attr(all(target_os = "macos", target_arch = "x86"), + link_name = "popen$UNIX2003")] + pub fn popen(command: *const c_char, + mode: *const c_char) -> *mut ::FILE; + pub fn uname(buf: *mut ::utsname) -> ::c_int; +} + +cfg_if! { + if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] { + mod mips; + pub use self::mips::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86_64; + pub use self::x86_64::*; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub use self::arm::*; + } else { + pub use unsupported_target; + } +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} + +expand_align!(); diff --git a/libc/src/unix/uclibc/no_align.rs b/libc/src/unix/uclibc/no_align.rs new file mode 100644 index 000000000..a73dbded5 --- /dev/null +++ b/libc/src/unix/uclibc/no_align.rs @@ -0,0 +1,53 @@ +macro_rules! expand_align { + () => { + s! { + pub struct pthread_mutex_t { + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(any(libc_align, + target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_rwlock_t { + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(not(any( + target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + + pub struct pthread_mutexattr_t { + #[cfg(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64"))] + __align: [::c_int; 0], + #[cfg(not(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64")))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_cond_t { + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + pub struct pthread_condattr_t { + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + } +} diff --git a/libc/src/unix/uclibc/x86_64/align.rs b/libc/src/unix/uclibc/x86_64/align.rs new file mode 100644 index 000000000..8d4bbd59b --- /dev/null +++ b/libc/src/unix/uclibc/x86_64/align.rs @@ -0,0 +1,77 @@ +macro_rules! expand_align { + () => { + s! { + #[cfg_attr(target_pointer_width = "32", + repr(align(4)))] + #[cfg_attr(target_pointer_width = "64", + repr(align(8)))] + pub struct sem_t { // ToDo + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + } + + #[cfg_attr(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64"), + repr(align(4)))] + #[cfg_attr(not(any(target_pointer_width = "32", + target_arch = "x86_64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64")), + repr(align(8)))] + pub struct pthread_mutexattr_t { // ToDo + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + #[repr(align(4))] + pub struct pthread_condattr_t { // ToDo + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + } + + s_no_extra_traits! { + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(all(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))), + repr(align(8)))] + #[allow(missing_debug_implementations)] + pub struct pthread_mutex_t { // ToDo + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + #[repr(align(8))] + #[allow(missing_debug_implementations)] + pub struct pthread_cond_t { // ToDo + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + #[cfg_attr(all(target_pointer_width = "32", + any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")), + repr(align(4)))] + #[cfg_attr(any(target_pointer_width = "64", + not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))), + repr(align(8)))] + #[allow(missing_debug_implementations)] + pub struct pthread_rwlock_t { // ToDo + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + } + } +} diff --git a/libc/src/unix/uclibc/x86_64/l4re.rs b/libc/src/unix/uclibc/x86_64/l4re.rs new file mode 100644 index 000000000..16ec0ef96 --- /dev/null +++ b/libc/src/unix/uclibc/x86_64/l4re.rs @@ -0,0 +1,48 @@ +/// L4Re specifics +/// This module contains definitions required by various L4Re libc backends. +/// Some of them are formally not part of the libc, but are a dependency of the +/// libc and hence we should provide them here. + +pub type l4_umword_t = ::c_ulong; // Unsigned machine word. +pub type pthread_t = *mut ::c_void; + +s! { + /// CPU sets. + pub struct l4_sched_cpu_set_t { + // from the L4Re docs + /// Combination of granularity and offset. + /// + /// The granularity defines how many CPUs each bit in map describes. + /// The offset is the numer of the first CPU described by the first + /// bit in the bitmap. + /// offset must be a multiple of 2^graularity. + /// + /// | MSB | LSB | + /// | ---------------- | ------------------- | + /// | 8bit granularity | 24bit offset .. | + gran_offset: l4_umword_t , + /// Bitmap of CPUs. + map: l4_umword_t , + } +} + +#[cfg(target_os = "l4re")] +#[allow(missing_debug_implementations)] +pub struct pthread_attr_t { + pub __detachstate: ::c_int, + pub __schedpolicy: ::c_int, + pub __schedparam: super::__sched_param, + pub __inheritsched: ::c_int, + pub __scope: ::c_int, + pub __guardsize: ::size_t, + pub __stackaddr_set: ::c_int, + pub __stackaddr: *mut ::c_void, // better don't use it + pub __stacksize: ::size_t, + // L4Re specifics + pub affinity: l4_sched_cpu_set_t, + pub create_flags: ::c_uint, +} + +// L4Re requires a min stack size of 64k; that isn't defined in uClibc, but +// somewhere in the core libraries. uClibc wants 16k, but that's not enough. +pub const PTHREAD_STACK_MIN: usize = 65536; diff --git a/libc/src/unix/uclibc/x86_64/mod.rs b/libc/src/unix/uclibc/x86_64/mod.rs new file mode 100644 index 000000000..a8bb0794a --- /dev/null +++ b/libc/src/unix/uclibc/x86_64/mod.rs @@ -0,0 +1,312 @@ +//! Definitions for uclibc on 64bit systems +pub type blkcnt_t = i64; +pub type blksize_t = i64; +pub type clock_t = i64; +pub type c_char = u8; +pub type c_long = i64; +pub type c_ulong = u64; +pub type fsblkcnt_t = ::c_ulong; +pub type fsfilcnt_t = ::c_ulong; +pub type fsword_t = ::c_long; +pub type ino_t = ::c_ulong; +pub type nlink_t = ::c_uint; +pub type off_t = ::c_long; +pub type rlim_t = c_ulong; +pub type rlim64_t = u64; +// [uClibc docs] Note stat64 has the same shape as stat for x86-64. +pub type stat64 = stat; +pub type suseconds_t = ::c_long; +pub type time_t = ::c_int; +pub type wchar_t = ::c_int; + +s! { + pub struct ipc_perm { + pub __key: ::key_t, + pub uid: ::uid_t, + pub gid: ::gid_t, + pub cuid: ::uid_t, + pub cgid: ::gid_t, + pub mode: ::c_ushort, // read / write + __pad1: ::c_ushort, + pub __seq: ::c_ushort, + __pad2: ::c_ushort, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + #[cfg(not(target_os = "l4re"))] + pub struct pthread_attr_t { + __detachstate: ::c_int, + __schedpolicy: ::c_int, + __schedparam: __sched_param, + __inheritsched: ::c_int, + __scope: ::c_int, + __guardsize: ::size_t, + __stackaddr_set: ::c_int, + __stackaddr: *mut ::c_void, // better don't use it + __stacksize: ::size_t, + } + + pub struct __sched_param { + __sched_priority: ::c_int, + } + + pub struct siginfo_t { + si_signo: ::c_int, // signal number + si_errno: ::c_int, // if not zero: error value of signal, see errno.h + si_code: ::c_int, // signal code + pub _pad: [::c_int; 28], // unported union + _align: [usize; 0], + } + + pub struct shmid_ds { + pub shm_perm: ::ipc_perm, + pub shm_segsz: ::size_t, // segment size in bytes + pub shm_atime: ::time_t, // time of last shmat() + pub shm_dtime: ::time_t, + pub shm_ctime: ::time_t, + pub shm_cpid: ::pid_t, + pub shm_lpid: ::pid_t, + pub shm_nattch: ::shmatt_t, + __unused1: ::c_ulong, + __unused2: ::c_ulong + } + + pub struct msqid_ds { + pub msg_perm: ::ipc_perm, + pub msg_stime: ::time_t, + pub msg_rtime: ::time_t, + pub msg_ctime: ::time_t, + __msg_cbytes: ::c_ulong, + pub msg_qnum: ::msgqnum_t, + pub msg_qbytes: ::msglen_t, + pub msg_lspid: ::pid_t, + pub msg_lrpid: ::pid_t, + __ignored1: ::c_ulong, + __ignored2: ::c_ulong, + } + + pub struct sockaddr { + pub sa_family: ::sa_family_t, + pub sa_data: [::c_char; 14], + } + + pub struct sockaddr_in { + pub sin_family: ::sa_family_t, + pub sin_port: ::in_port_t, + pub sin_addr: ::in_addr, + pub sin_zero: [u8; 8], + } + + pub struct sockaddr_in6 { + pub sin6_family: ::sa_family_t, + pub sin6_port: ::in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: ::in6_addr, + pub sin6_scope_id: u32, + } + + // ------------------------------------------------------------ + // definitions below are *unverified* and might **break** the software +// pub struct in_addr { +// pub s_addr: in_addr_t, +// } +// +// pub struct in6_addr { +// pub s6_addr: [u8; 16], +// #[cfg(not(libc_align))] +// __align: [u32; 0], +// } + + pub struct stat { + pub st_dev: ::c_ulong, + pub st_ino: ::ino_t, + // According to uclibc/libc/sysdeps/linux/x86_64/bits/stat.h, order of + // nlink and mode are swapped on 64 bit systems. + pub st_nlink: ::nlink_t, + pub st_mode: ::mode_t, + pub st_uid: ::uid_t, + pub st_gid: ::gid_t, + pub st_rdev: ::c_ulong, // dev_t + pub st_size: off_t, // file size + pub st_blksize: ::blksize_t, + pub st_blocks: ::blkcnt_t, + pub st_atime: ::time_t, + pub st_atime_nsec: ::c_ulong, + pub st_mtime: ::time_t, + pub st_mtime_nsec: ::c_ulong, + pub st_ctime: ::time_t, + pub st_ctime_nsec: ::c_ulong, + st_pad4: [::c_long; 3] + } + + pub struct sigaction { + pub sa_handler: ::sighandler_t, + pub sa_flags: ::c_ulong, + pub sa_restorer: *mut ::c_void, + pub sa_mask: ::sigset_t, + } + + pub struct stack_t { // ToDo + pub ss_sp: *mut ::c_void, + pub ss_flags: ::c_int, + pub ss_size: ::size_t + } + + pub struct statfs { // ToDo + pub f_type: fsword_t, + pub f_bsize: fsword_t, + pub f_blocks: ::fsblkcnt_t, + pub f_bfree: ::fsblkcnt_t, + pub f_bavail: ::fsblkcnt_t, + pub f_files: ::fsfilcnt_t, + pub f_ffree: ::fsfilcnt_t, + pub f_fsid: ::fsid_t, + pub f_namelen: fsword_t, + pub f_frsize: fsword_t, + f_spare: [fsword_t; 5], + } + + pub struct msghdr { // ToDo + pub msg_name: *mut ::c_void, + pub msg_namelen: ::socklen_t, + pub msg_iov: *mut ::iovec, + pub msg_iovlen: ::size_t, + pub msg_control: *mut ::c_void, + pub msg_controllen: ::size_t, + pub msg_flags: ::c_int, + } + + pub struct termios { // ToDo + pub c_iflag: ::tcflag_t, + pub c_oflag: ::tcflag_t, + pub c_cflag: ::tcflag_t, + pub c_lflag: ::tcflag_t, + pub c_line: ::cc_t, + pub c_cc: [::cc_t; ::NCCS], + } + + pub struct sigset_t { // ToDo + __val: [::c_ulong; 16], + } + + pub struct sysinfo { // ToDo + pub uptime: ::c_long, + pub loads: [::c_ulong; 3], + pub totalram: ::c_ulong, + pub freeram: ::c_ulong, + pub sharedram: ::c_ulong, + pub bufferram: ::c_ulong, + pub totalswap: ::c_ulong, + pub freeswap: ::c_ulong, + pub procs: ::c_ushort, + pub pad: ::c_ushort, + pub totalhigh: ::c_ulong, + pub freehigh: ::c_ulong, + pub mem_unit: ::c_uint, + pub _f: [::c_char; 0], + } + + pub struct glob_t { // ToDo + pub gl_pathc: ::size_t, + pub gl_pathv: *mut *mut c_char, + pub gl_offs: ::size_t, + pub gl_flags: ::c_int, + __unused1: *mut ::c_void, + __unused2: *mut ::c_void, + __unused3: *mut ::c_void, + __unused4: *mut ::c_void, + __unused5: *mut ::c_void, + } + + pub struct rlimit64 { // ToDo + pub rlim_cur: rlim64_t, + pub rlim_max: rlim64_t, + } + + pub struct cpu_set_t { // ToDo + #[cfg(target_pointer_width = "32")] + bits: [u32; 32], + #[cfg(target_pointer_width = "64")] + bits: [u64; 16], + } + + pub struct fsid_t { // ToDo + __val: [::c_int; 2], + } +} + +s_no_extra_traits! { + #[allow(missing_debug_implementations)] + pub struct dirent { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: u16, + pub d_type: u8, + pub d_name: [::c_char; 256], + } + #[allow(missing_debug_implementations)] + pub struct dirent64 { + pub d_ino: ::ino64_t, + pub d_off: ::off64_t, + pub d_reclen: u16, + pub d_type: u8, + pub d_name: [::c_char; 256], + } +} + +// constants +pub const EADDRINUSE: ::c_int = 98; // Address already in use +pub const EADDRNOTAVAIL: ::c_int = 99; // Cannot assign requested address +pub const ECONNABORTED: ::c_int = 103; // Software caused connection abort +pub const ECONNREFUSED: ::c_int = 111; // Connection refused +pub const ECONNRESET: ::c_int = 104; // Connection reset by peer +pub const EDEADLK: ::c_int = 35; // Resource deadlock would occur +pub const ENOSYS: ::c_int = 38; // Function not implemented +pub const ENOTCONN: ::c_int = 107; // Transport endpoint is not connected +pub const ETIMEDOUT: ::c_int = 110; // connection timed out +pub const O_APPEND: ::c_int = 02000; +pub const O_ACCMODE: ::c_int = 0003; +pub const O_CLOEXEC: ::c_int = 0x80000; +pub const O_CREAT: ::c_int = 0100; +pub const O_DIRECTORY: ::c_int = 0200000; +pub const O_EXCL: ::c_int = 0200; +pub const O_NONBLOCK: ::c_int = 04000; +pub const O_TRUNC: ::c_int = 01000; +pub const NCCS: usize = 32; +pub const SIG_SETMASK: ::c_int = 2; // Set the set of blocked signals +pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40; +pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4; +pub const SO_BROADCAST: ::c_int = 6; +pub const SOCK_DGRAM: ::c_int = 2; // connectionless, unreliable datagrams +pub const SOCK_STREAM: ::c_int = 1; // …/common/bits/socket_type.h +pub const SO_ERROR: ::c_int = 4; +pub const SOL_SOCKET: ::c_int = 1; +pub const SO_RCVTIMEO: ::c_int = 20; +pub const SO_REUSEADDR: ::c_int = 2; +pub const SO_SNDTIMEO: ::c_int = 21; +pub const RLIM_INFINITY: u64 = 0xffffffffffffffff; +pub const __SIZEOF_PTHREAD_COND_T: usize = 48; +pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4; +pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56; + +cfg_if! { + if #[cfg(target_os = "l4re")] { + mod l4re; + pub use self::l4re::*; + } else { + mod other; + pub use other::*; + } +} + +cfg_if! { + if #[cfg(libc_align)] { + #[macro_use] + mod align; + } else { + #[macro_use] + mod no_align; + } +} +expand_align!(); diff --git a/libc/src/unix/uclibc/x86_64/no_align.rs b/libc/src/unix/uclibc/x86_64/no_align.rs new file mode 100644 index 000000000..422d78fac --- /dev/null +++ b/libc/src/unix/uclibc/x86_64/no_align.rs @@ -0,0 +1,59 @@ +macro_rules! expand_align { + () => { + s! { + pub struct sem_t { // ToDo + #[cfg(target_pointer_width = "32")] + __size: [::c_char; 16], + #[cfg(target_pointer_width = "64")] + __size: [::c_char; 32], + __align: [::c_long; 0], + } + + pub struct pthread_mutex_t { // ToDo + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEX_T], + } + + pub struct pthread_mutexattr_t { // ToDo + #[cfg(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64"))] + __align: [::c_int; 0], + #[cfg(not(any(target_arch = "x86_64", target_arch = "powerpc64", + target_arch = "mips64", target_arch = "s390x", + target_arch = "sparc64")))] + __align: [::c_long; 0], + size: [u8; ::__SIZEOF_PTHREAD_MUTEXATTR_T], + } + + pub struct pthread_cond_t { // ToDo + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_COND_T], + } + + pub struct pthread_condattr_t { // ToDo + __align: [::c_int; 0], + size: [u8; ::__SIZEOF_PTHREAD_CONDATTR_T], + } + + pub struct pthread_rwlock_t { // ToDo + #[cfg(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc"))] + __align: [::c_long; 0], + #[cfg(not(any(target_arch = "mips", + target_arch = "arm", + target_arch = "powerpc")))] + __align: [::c_longlong; 0], + size: [u8; ::__SIZEOF_PTHREAD_RWLOCK_T], + } + } + } +} diff --git a/libc/src/unix/uclibc/x86_64/other.rs b/libc/src/unix/uclibc/x86_64/other.rs new file mode 100644 index 000000000..481577cfc --- /dev/null +++ b/libc/src/unix/uclibc/x86_64/other.rs @@ -0,0 +1,5 @@ +// Thestyle checker discourages the use of #[cfg], so this has to go into a +// separate module +pub type pthread_t = ::c_ulong; + +pub const PTHREAD_STACK_MIN: usize = 16384; diff --git a/libc/src/wasi.rs b/libc/src/wasi.rs new file mode 100644 index 000000000..b93486129 --- /dev/null +++ b/libc/src/wasi.rs @@ -0,0 +1,1336 @@ +pub use ffi::c_void; + +pub type c_char = i8; +pub type c_uchar = u8; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_long = i32; +pub type c_ulong = u32; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; +pub type size_t = usize; +pub type ssize_t = isize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type off_t = i64; +pub type pid_t = i32; +pub type int8_t = i8; +pub type uint8_t = u8; +pub type int16_t = i16; +pub type uint16_t = u16; +pub type int32_t = i32; +pub type uint32_t = u32; +pub type int64_t = i64; +pub type uint64_t = u64; +pub type clock_t = c_longlong; +pub type time_t = c_longlong; +pub type c_double = f64; +pub type c_float = f32; +pub type ino_t = u64; +pub type sigset_t = c_uchar; +pub type suseconds_t = c_longlong; +pub type mode_t = u32; +pub type dev_t = u64; +pub type uid_t = u32; +pub type gid_t = u32; +pub type nlink_t = u64; +pub type blksize_t = c_long; +pub type blkcnt_t = i64; +pub type nfds_t = c_ulong; + +pub type __wasi_advice_t = u8; +pub type __wasi_clockid_t = u32; +pub type __wasi_device_t = u64; +pub type __wasi_dircookie_t = u64; +pub type __wasi_errno_t = u16; +pub type __wasi_eventrwflags_t = u16; +pub type __wasi_eventtype_t = u8; +pub type __wasi_exitcode_t = u32; +pub type __wasi_fd_t = u32; +pub type __wasi_fdflags_t = u16; +pub type __wasi_filedelta_t = i64; +pub type __wasi_filesize_t = u64; +pub type __wasi_filetype_t = u8; +pub type __wasi_fstflags_t = u16; +pub type __wasi_inode_t = u64; +pub type __wasi_linkcount_t = u32; +pub type __wasi_lookupflags_t = u32; +pub type __wasi_oflags_t = u16; +pub type __wasi_riflags_t = u16; +pub type __wasi_rights_t = u64; +pub type __wasi_roflags_t = u16; +pub type __wasi_sdflags_t = u8; +pub type __wasi_siflags_t = u16; +pub type __wasi_signal_t = u8; +pub type __wasi_subclockflags_t = u16; +pub type __wasi_timestamp_t = u64; +pub type __wasi_userdata_t = u64; +pub type __wasi_whence_t = u8; +pub type __wasi_preopentype_t = u8; + +#[allow(missing_copy_implementations)] +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum FILE {} +#[allow(missing_copy_implementations)] +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum DIR {} +#[allow(missing_copy_implementations)] +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum __locale_struct {} + +pub type locale_t = *mut __locale_struct; + +s! { + #[repr(align(8))] + pub struct fpos_t { + data: [u8; 16], + } + + pub struct tm { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, + pub tm_yday: c_int, + pub tm_isdst: c_int, + pub __tm_gmtoff: c_int, + pub __tm_zone: *const c_char, + pub __tm_nsec: c_int, + } + + pub struct timeval { + pub tv_sec: time_t, + pub tv_usec: suseconds_t, + } + + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + pub struct tms { + pub tms_utime: clock_t, + pub tms_stime: clock_t, + pub tms_cutime: clock_t, + pub tms_cstime: clock_t, + } + + pub struct itimerspec { + pub it_interval: timespec, + pub it_value: timespec, + } + + pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: size_t, + } + + pub struct lconv { + pub decimal_point: *mut c_char, + pub thousands_sep: *mut c_char, + pub grouping: *mut c_char, + pub int_curr_symbol: *mut c_char, + pub currency_symbol: *mut c_char, + pub mon_decimal_point: *mut c_char, + pub mon_thousands_sep: *mut c_char, + pub mon_grouping: *mut c_char, + pub positive_sign: *mut c_char, + pub negative_sign: *mut c_char, + pub int_frac_digits: c_char, + pub frac_digits: c_char, + pub p_cs_precedes: c_char, + pub p_sep_by_space: c_char, + pub n_cs_precedes: c_char, + pub n_sep_by_space: c_char, + pub p_sign_posn: c_char, + pub n_sign_posn: c_char, + pub int_p_cs_precedes: c_char, + pub int_p_sep_by_space: c_char, + pub int_n_cs_precedes: c_char, + pub int_n_sep_by_space: c_char, + pub int_p_sign_posn: c_char, + pub int_n_sign_posn: c_char, + } + + pub struct pollfd { + pub fd: c_int, + pub events: c_short, + pub revents: c_short, + } + + pub struct rusage { + pub ru_utime: timeval, + pub ru_stime: timeval, + } + + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_nlink: nlink_t, + pub st_mode: mode_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + __pad0: c_uint, + pub st_rdev: dev_t, + pub st_size: off_t, + pub st_blksize: blksize_t, + pub st_blocks: blkcnt_t, + pub st_atim: timespec, + pub st_mtim: timespec, + pub st_ctim: timespec, + __reserved: [c_longlong; 3], + } + + pub struct __wasi_dirent_t { + pub d_next: __wasi_dircookie_t, + pub d_ino: __wasi_inode_t, + pub d_namlen: u32, + pub d_type: __wasi_filetype_t, + } + + pub struct __wasi_event_u_fd_readwrite_t { + pub nbytes: __wasi_filesize_t, + pub flags: __wasi_eventrwflags_t, + } + + pub struct __wasi_fdstat_t { + pub fs_filetype: __wasi_filetype_t, + pub fs_flags: __wasi_fdflags_t, + pub fs_rights_base: __wasi_rights_t, + pub fs_rights_inheriting: __wasi_rights_t, + } + + pub struct __wasi_filestat_t { + pub st_dev: __wasi_device_t, + pub st_ino: __wasi_inode_t, + pub st_filetype: __wasi_filetype_t, + pub st_nlink: __wasi_linkcount_t, + pub st_size: __wasi_filesize_t, + pub st_atim: __wasi_timestamp_t, + pub st_mtim: __wasi_timestamp_t, + pub st_ctim: __wasi_timestamp_t, + } + + pub struct __wasi_ciovec_t { + pub buf: *const ::c_void, + pub buf_len: size_t, + } + + pub struct __wasi_iovec_t { + pub buf: *mut ::c_void, + pub buf_len: size_t, + } + + pub struct __wasi_subscription_u_clock_t { + pub identifier: __wasi_userdata_t, + pub clock_id: __wasi_clockid_t, + pub timeout: __wasi_timestamp_t, + pub precision: __wasi_timestamp_t, + pub flags: __wasi_subclockflags_t, + } + + pub struct __wasi_subscription_u_fd_readwrite_t { + pub fd: __wasi_fd_t, + } + + pub struct __wasi_prestat_u_dir_t { + pub pr_name_len: size_t, + } +} + +s_no_extra_traits! { + #[allow(missing_debug_implementations)] + pub struct __wasi_subscription_t { + pub userdata: __wasi_userdata_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_subscription_u, + } + + #[allow(missing_debug_implementations)] + pub struct __wasi_event_t { + pub userdata: __wasi_userdata_t, + pub error: __wasi_errno_t, + pub type_: __wasi_eventtype_t, + pub u: __wasi_event_u, + } + + #[allow(missing_debug_implementations)] + pub union __wasi_event_u { + pub fd_readwrite: __wasi_event_u_fd_readwrite_t, + _bindgen_union_align: [u64; 2], + } + + #[allow(missing_debug_implementations)] + pub union __wasi_subscription_u { + pub clock: __wasi_subscription_u_clock_t, + pub fd_readwrite: + __wasi_subscription_u_fd_readwrite_t, + _bindgen_union_align: [u64; 5], + } + + #[allow(missing_debug_implementations)] + pub struct __wasi_prestat_t { + pub pr_type: __wasi_preopentype_t, + pub u: __wasi_prestat_u, + } + + #[allow(missing_debug_implementations)] + pub union __wasi_prestat_u { + pub dir: __wasi_prestat_u_dir_t, + } + +} + +// Declare dirent outside of s! so that it doesn't implement Copy, Eq, Hash, +// etc., since it contains a flexible array member with a dynamic size. +#[repr(C)] +#[allow(missing_copy_implementations)] +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + /// d_name is declared in WASI libc as a flexible array member, which + /// can't be directly expressed in Rust. As an imperfect workaround, + /// declare it as a zero-length array instead. + pub d_name: [c_char; 0], +} + +pub const EXIT_SUCCESS: c_int = 0; +pub const EXIT_FAILURE: c_int = 1; +pub const STDIN_FILENO: c_int = 0; +pub const STDOUT_FILENO: c_int = 1; +pub const STDERR_FILENO: c_int = 2; +pub const SEEK_SET: c_int = 2; +pub const SEEK_CUR: c_int = 0; +pub const SEEK_END: c_int = 1; +pub const _IOFBF: c_int = 0; +pub const _IONBF: c_int = 2; +pub const _IOLBF: c_int = 1; +pub const FD_SETSIZE: size_t = 1024; +pub const O_APPEND: c_int = __WASI_FDFLAG_APPEND as c_int; +pub const O_DSYNC: c_int = __WASI_FDFLAG_DSYNC as c_int; +pub const O_NONBLOCK: c_int = __WASI_FDFLAG_NONBLOCK as c_int; +pub const O_RSYNC: c_int = __WASI_FDFLAG_RSYNC as c_int; +pub const O_SYNC: c_int = __WASI_FDFLAG_SYNC as c_int; +pub const O_CREAT: c_int = (__WASI_O_CREAT as c_int) << 12; +pub const O_DIRECTORY: c_int = (__WASI_O_DIRECTORY as c_int) << 12; +pub const O_EXCL: c_int = (__WASI_O_EXCL as c_int) << 12; +pub const O_TRUNC: c_int = (__WASI_O_TRUNC as c_int) << 12; +pub const O_NOFOLLOW: c_int = 0x01000000; +pub const O_EXEC: c_int = 0x02000000; +pub const O_RDONLY: c_int = 0x04000000; +pub const O_SEARCH: c_int = 0x08000000; +pub const O_WRONLY: c_int = 0x10000000; +pub const O_RDWR: c_int = O_WRONLY | O_RDONLY; +pub const O_ACCMODE: c_int = O_EXEC | O_RDWR | O_SEARCH; +pub const POSIX_FADV_DONTNEED: c_int = __WASI_ADVICE_DONTNEED as c_int; +pub const POSIX_FADV_NOREUSE: c_int = __WASI_ADVICE_NOREUSE as c_int; +pub const POSIX_FADV_NORMAL: c_int = __WASI_ADVICE_NORMAL as c_int; +pub const POSIX_FADV_RANDOM: c_int = __WASI_ADVICE_RANDOM as c_int; +pub const POSIX_FADV_SEQUENTIAL: c_int = __WASI_ADVICE_SEQUENTIAL as c_int; +pub const POSIX_FADV_WILLNEED: c_int = __WASI_ADVICE_WILLNEED as c_int; +pub const AT_EACCESS: c_int = 0x0; +pub const AT_SYMLINK_NOFOLLOW: c_int = 0x1; +pub const AT_SYMLINK_FOLLOW: c_int = 0x2; +pub const AT_REMOVEDIR: c_int = 0x4; + +pub const E2BIG: c_int = __WASI_E2BIG as c_int; +pub const EACCES: c_int = __WASI_EACCES as c_int; +pub const EADDRINUSE: c_int = __WASI_EADDRINUSE as c_int; +pub const EADDRNOTAVAIL: c_int = __WASI_EADDRNOTAVAIL as c_int; +pub const EAFNOSUPPORT: c_int = __WASI_EAFNOSUPPORT as c_int; +pub const EAGAIN: c_int = __WASI_EAGAIN as c_int; +pub const EALREADY: c_int = __WASI_EALREADY as c_int; +pub const EBADF: c_int = __WASI_EBADF as c_int; +pub const EBADMSG: c_int = __WASI_EBADMSG as c_int; +pub const EBUSY: c_int = __WASI_EBUSY as c_int; +pub const ECANCELED: c_int = __WASI_ECANCELED as c_int; +pub const ECHILD: c_int = __WASI_ECHILD as c_int; +pub const ECONNABORTED: c_int = __WASI_ECONNABORTED as c_int; +pub const ECONNREFUSED: c_int = __WASI_ECONNREFUSED as c_int; +pub const ECONNRESET: c_int = __WASI_ECONNRESET as c_int; +pub const EDEADLK: c_int = __WASI_EDEADLK as c_int; +pub const EDESTADDRREQ: c_int = __WASI_EDESTADDRREQ as c_int; +pub const EDOM: c_int = __WASI_EDOM as c_int; +pub const EDQUOT: c_int = __WASI_EDQUOT as c_int; +pub const EEXIST: c_int = __WASI_EEXIST as c_int; +pub const EFAULT: c_int = __WASI_EFAULT as c_int; +pub const EFBIG: c_int = __WASI_EFBIG as c_int; +pub const EHOSTUNREACH: c_int = __WASI_EHOSTUNREACH as c_int; +pub const EIDRM: c_int = __WASI_EIDRM as c_int; +pub const EILSEQ: c_int = __WASI_EILSEQ as c_int; +pub const EINPROGRESS: c_int = __WASI_EINPROGRESS as c_int; +pub const EINTR: c_int = __WASI_EINTR as c_int; +pub const EINVAL: c_int = __WASI_EINVAL as c_int; +pub const EIO: c_int = __WASI_EIO as c_int; +pub const EISCONN: c_int = __WASI_EISCONN as c_int; +pub const EISDIR: c_int = __WASI_EISDIR as c_int; +pub const ELOOP: c_int = __WASI_ELOOP as c_int; +pub const EMFILE: c_int = __WASI_EMFILE as c_int; +pub const EMLINK: c_int = __WASI_EMLINK as c_int; +pub const EMSGSIZE: c_int = __WASI_EMSGSIZE as c_int; +pub const EMULTIHOP: c_int = __WASI_EMULTIHOP as c_int; +pub const ENAMETOOLONG: c_int = __WASI_ENAMETOOLONG as c_int; +pub const ENETDOWN: c_int = __WASI_ENETDOWN as c_int; +pub const ENETRESET: c_int = __WASI_ENETRESET as c_int; +pub const ENETUNREACH: c_int = __WASI_ENETUNREACH as c_int; +pub const ENFILE: c_int = __WASI_ENFILE as c_int; +pub const ENOBUFS: c_int = __WASI_ENOBUFS as c_int; +pub const ENODEV: c_int = __WASI_ENODEV as c_int; +pub const ENOENT: c_int = __WASI_ENOENT as c_int; +pub const ENOEXEC: c_int = __WASI_ENOEXEC as c_int; +pub const ENOLCK: c_int = __WASI_ENOLCK as c_int; +pub const ENOLINK: c_int = __WASI_ENOLINK as c_int; +pub const ENOMEM: c_int = __WASI_ENOMEM as c_int; +pub const ENOMSG: c_int = __WASI_ENOMSG as c_int; +pub const ENOPROTOOPT: c_int = __WASI_ENOPROTOOPT as c_int; +pub const ENOSPC: c_int = __WASI_ENOSPC as c_int; +pub const ENOSYS: c_int = __WASI_ENOSYS as c_int; +pub const ENOTCONN: c_int = __WASI_ENOTCONN as c_int; +pub const ENOTDIR: c_int = __WASI_ENOTDIR as c_int; +pub const ENOTEMPTY: c_int = __WASI_ENOTEMPTY as c_int; +pub const ENOTRECOVERABLE: c_int = __WASI_ENOTRECOVERABLE as c_int; +pub const ENOTSOCK: c_int = __WASI_ENOTSOCK as c_int; +pub const ENOTSUP: c_int = __WASI_ENOTSUP as c_int; +pub const ENOTTY: c_int = __WASI_ENOTTY as c_int; +pub const ENXIO: c_int = __WASI_ENXIO as c_int; +pub const EOVERFLOW: c_int = __WASI_EOVERFLOW as c_int; +pub const EOWNERDEAD: c_int = __WASI_EOWNERDEAD as c_int; +pub const EPERM: c_int = __WASI_EPERM as c_int; +pub const EPIPE: c_int = __WASI_EPIPE as c_int; +pub const EPROTO: c_int = __WASI_EPROTO as c_int; +pub const EPROTONOSUPPORT: c_int = __WASI_EPROTONOSUPPORT as c_int; +pub const EPROTOTYPE: c_int = __WASI_EPROTOTYPE as c_int; +pub const ERANGE: c_int = __WASI_ERANGE as c_int; +pub const EROFS: c_int = __WASI_EROFS as c_int; +pub const ESPIPE: c_int = __WASI_ESPIPE as c_int; +pub const ESRCH: c_int = __WASI_ESRCH as c_int; +pub const ESTALE: c_int = __WASI_ESTALE as c_int; +pub const ETIMEDOUT: c_int = __WASI_ETIMEDOUT as c_int; +pub const ETXTBSY: c_int = __WASI_ETXTBSY as c_int; +pub const EXDEV: c_int = __WASI_EXDEV as c_int; +pub const ENOTCAPABLE: c_int = __WASI_ENOTCAPABLE as c_int; +pub const EOPNOTSUPP: c_int = ENOTSUP; +pub const EWOULDBLOCK: c_int = EAGAIN; + +pub const __WASI_ADVICE_NORMAL: u8 = 0; +pub const __WASI_ADVICE_SEQUENTIAL: u8 = 1; +pub const __WASI_ADVICE_RANDOM: u8 = 2; +pub const __WASI_ADVICE_WILLNEED: u8 = 3; +pub const __WASI_ADVICE_DONTNEED: u8 = 4; +pub const __WASI_ADVICE_NOREUSE: u8 = 5; +pub const __WASI_CLOCK_REALTIME: u32 = 0; +pub const __WASI_CLOCK_MONOTONIC: u32 = 1; +pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2; +pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3; +pub const __WASI_DIRCOOKIE_START: u64 = 0; +pub const __WASI_ESUCCESS: u16 = 0; +pub const __WASI_E2BIG: u16 = 1; +pub const __WASI_EACCES: u16 = 2; +pub const __WASI_EADDRINUSE: u16 = 3; +pub const __WASI_EADDRNOTAVAIL: u16 = 4; +pub const __WASI_EAFNOSUPPORT: u16 = 5; +pub const __WASI_EAGAIN: u16 = 6; +pub const __WASI_EALREADY: u16 = 7; +pub const __WASI_EBADF: u16 = 8; +pub const __WASI_EBADMSG: u16 = 9; +pub const __WASI_EBUSY: u16 = 10; +pub const __WASI_ECANCELED: u16 = 11; +pub const __WASI_ECHILD: u16 = 12; +pub const __WASI_ECONNABORTED: u16 = 13; +pub const __WASI_ECONNREFUSED: u16 = 14; +pub const __WASI_ECONNRESET: u16 = 15; +pub const __WASI_EDEADLK: u16 = 16; +pub const __WASI_EDESTADDRREQ: u16 = 17; +pub const __WASI_EDOM: u16 = 18; +pub const __WASI_EDQUOT: u16 = 19; +pub const __WASI_EEXIST: u16 = 20; +pub const __WASI_EFAULT: u16 = 21; +pub const __WASI_EFBIG: u16 = 22; +pub const __WASI_EHOSTUNREACH: u16 = 23; +pub const __WASI_EIDRM: u16 = 24; +pub const __WASI_EILSEQ: u16 = 25; +pub const __WASI_EINPROGRESS: u16 = 26; +pub const __WASI_EINTR: u16 = 27; +pub const __WASI_EINVAL: u16 = 28; +pub const __WASI_EIO: u16 = 29; +pub const __WASI_EISCONN: u16 = 30; +pub const __WASI_EISDIR: u16 = 31; +pub const __WASI_ELOOP: u16 = 32; +pub const __WASI_EMFILE: u16 = 33; +pub const __WASI_EMLINK: u16 = 34; +pub const __WASI_EMSGSIZE: u16 = 35; +pub const __WASI_EMULTIHOP: u16 = 36; +pub const __WASI_ENAMETOOLONG: u16 = 37; +pub const __WASI_ENETDOWN: u16 = 38; +pub const __WASI_ENETRESET: u16 = 39; +pub const __WASI_ENETUNREACH: u16 = 40; +pub const __WASI_ENFILE: u16 = 41; +pub const __WASI_ENOBUFS: u16 = 42; +pub const __WASI_ENODEV: u16 = 43; +pub const __WASI_ENOENT: u16 = 44; +pub const __WASI_ENOEXEC: u16 = 45; +pub const __WASI_ENOLCK: u16 = 46; +pub const __WASI_ENOLINK: u16 = 47; +pub const __WASI_ENOMEM: u16 = 48; +pub const __WASI_ENOMSG: u16 = 49; +pub const __WASI_ENOPROTOOPT: u16 = 50; +pub const __WASI_ENOSPC: u16 = 51; +pub const __WASI_ENOSYS: u16 = 52; +pub const __WASI_ENOTCONN: u16 = 53; +pub const __WASI_ENOTDIR: u16 = 54; +pub const __WASI_ENOTEMPTY: u16 = 55; +pub const __WASI_ENOTRECOVERABLE: u16 = 56; +pub const __WASI_ENOTSOCK: u16 = 57; +pub const __WASI_ENOTSUP: u16 = 58; +pub const __WASI_ENOTTY: u16 = 59; +pub const __WASI_ENXIO: u16 = 60; +pub const __WASI_EOVERFLOW: u16 = 61; +pub const __WASI_EOWNERDEAD: u16 = 62; +pub const __WASI_EPERM: u16 = 63; +pub const __WASI_EPIPE: u16 = 64; +pub const __WASI_EPROTO: u16 = 65; +pub const __WASI_EPROTONOSUPPORT: u16 = 66; +pub const __WASI_EPROTOTYPE: u16 = 67; +pub const __WASI_ERANGE: u16 = 68; +pub const __WASI_EROFS: u16 = 69; +pub const __WASI_ESPIPE: u16 = 70; +pub const __WASI_ESRCH: u16 = 71; +pub const __WASI_ESTALE: u16 = 72; +pub const __WASI_ETIMEDOUT: u16 = 73; +pub const __WASI_ETXTBSY: u16 = 74; +pub const __WASI_EXDEV: u16 = 75; +pub const __WASI_ENOTCAPABLE: u16 = 76; +pub const __WASI_EVENT_FD_READWRITE_HANGUP: u16 = 0x0001; +pub const __WASI_EVENTTYPE_CLOCK: u8 = 0; +pub const __WASI_EVENTTYPE_FD_READ: u8 = 1; +pub const __WASI_EVENTTYPE_FD_WRITE: u8 = 2; +pub const __WASI_FDFLAG_APPEND: u16 = 0x0001; +pub const __WASI_FDFLAG_DSYNC: u16 = 0x0002; +pub const __WASI_FDFLAG_NONBLOCK: u16 = 0x0004; +pub const __WASI_FDFLAG_RSYNC: u16 = 0x0008; +pub const __WASI_FDFLAG_SYNC: u16 = 0x0010; +pub const __WASI_FILETYPE_UNKNOWN: u8 = 0; +pub const __WASI_FILETYPE_BLOCK_DEVICE: u8 = 1; +pub const __WASI_FILETYPE_CHARACTER_DEVICE: u8 = 2; +pub const __WASI_FILETYPE_DIRECTORY: u8 = 3; +pub const __WASI_FILETYPE_REGULAR_FILE: u8 = 4; +pub const __WASI_FILETYPE_SOCKET_DGRAM: u8 = 5; +pub const __WASI_FILETYPE_SOCKET_STREAM: u8 = 6; +pub const __WASI_FILETYPE_SYMBOLIC_LINK: u8 = 7; +pub const __WASI_FILESTAT_SET_ATIM: u16 = 0x0001; +pub const __WASI_FILESTAT_SET_ATIM_NOW: u16 = 0x0002; +pub const __WASI_FILESTAT_SET_MTIM: u16 = 0x0004; +pub const __WASI_FILESTAT_SET_MTIM_NOW: u16 = 0x0008; +pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 0x00000001; +pub const __WASI_O_CREAT: u16 = 0x0001; +pub const __WASI_O_DIRECTORY: u16 = 0x0002; +pub const __WASI_O_EXCL: u16 = 0x0004; +pub const __WASI_O_TRUNC: u16 = 0x0008; +pub const __WASI_PREOPENTYPE_DIR: u8 = 0; +pub const __WASI_SOCK_RECV_PEEK: u16 = 0x0001; +pub const __WASI_SOCK_RECV_WAITALL: u16 = 0x0002; +pub const __WASI_RIGHT_FD_DATASYNC: u64 = 0x0000000000000001; +pub const __WASI_RIGHT_FD_READ: u64 = 0x0000000000000002; +pub const __WASI_RIGHT_FD_SEEK: u64 = 0x0000000000000004; +pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u64 = 0x0000000000000008; +pub const __WASI_RIGHT_FD_SYNC: u64 = 0x0000000000000010; +pub const __WASI_RIGHT_FD_TELL: u64 = 0x0000000000000020; +pub const __WASI_RIGHT_FD_WRITE: u64 = 0x0000000000000040; +pub const __WASI_RIGHT_FD_ADVISE: u64 = 0x0000000000000080; +pub const __WASI_RIGHT_FD_ALLOCATE: u64 = 0x0000000000000100; +pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u64 = 0x0000000000000200; +pub const __WASI_RIGHT_PATH_CREATE_FILE: u64 = 0x0000000000000400; +pub const __WASI_RIGHT_PATH_LINK_SOURCE: u64 = 0x0000000000000800; +pub const __WASI_RIGHT_PATH_LINK_TARGET: u64 = 0x0000000000001000; +pub const __WASI_RIGHT_PATH_OPEN: u64 = 0x0000000000002000; +pub const __WASI_RIGHT_FD_READDIR: u64 = 0x0000000000004000; +pub const __WASI_RIGHT_PATH_READLINK: u64 = 0x0000000000008000; +pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u64 = 0x0000000000010000; +pub const __WASI_RIGHT_PATH_RENAME_TARGET: u64 = 0x0000000000020000; +pub const __WASI_RIGHT_PATH_FILESTAT_GET: u64 = 0x0000000000040000; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u64 = 0x0000000000080000; +pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u64 = 0x0000000000100000; +pub const __WASI_RIGHT_FD_FILESTAT_GET: u64 = 0x0000000000200000; +pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u64 = 0x0000000000400000; +pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u64 = 0x0000000000800000; +pub const __WASI_RIGHT_PATH_SYMLINK: u64 = 0x0000000001000000; +pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u64 = 0x0000000002000000; +pub const __WASI_RIGHT_PATH_UNLINK_FILE: u64 = 0x0000000004000000; +pub const __WASI_RIGHT_POLL_FD_READWRITE: u64 = 0x0000000008000000; +pub const __WASI_RIGHT_SOCK_SHUTDOWN: u64 = 0x0000000010000000; +pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u16 = 0x0001; +pub const __WASI_SHUT_RD: u8 = 0x01; +pub const __WASI_SHUT_WR: u8 = 0x02; +pub const __WASI_SIGHUP: u8 = 1; +pub const __WASI_SIGINT: u8 = 2; +pub const __WASI_SIGQUIT: u8 = 3; +pub const __WASI_SIGILL: u8 = 4; +pub const __WASI_SIGTRAP: u8 = 5; +pub const __WASI_SIGABRT: u8 = 6; +pub const __WASI_SIGBUS: u8 = 7; +pub const __WASI_SIGFPE: u8 = 8; +pub const __WASI_SIGKILL: u8 = 9; +pub const __WASI_SIGUSR1: u8 = 10; +pub const __WASI_SIGSEGV: u8 = 11; +pub const __WASI_SIGUSR2: u8 = 12; +pub const __WASI_SIGPIPE: u8 = 13; +pub const __WASI_SIGALRM: u8 = 14; +pub const __WASI_SIGTERM: u8 = 15; +pub const __WASI_SIGCHLD: u8 = 16; +pub const __WASI_SIGCONT: u8 = 17; +pub const __WASI_SIGSTOP: u8 = 18; +pub const __WASI_SIGTSTP: u8 = 19; +pub const __WASI_SIGTTIN: u8 = 20; +pub const __WASI_SIGTTOU: u8 = 21; +pub const __WASI_SIGURG: u8 = 22; +pub const __WASI_SIGXCPU: u8 = 23; +pub const __WASI_SIGXFSZ: u8 = 24; +pub const __WASI_SIGVTALRM: u8 = 25; +pub const __WASI_SIGPROF: u8 = 26; +pub const __WASI_SIGWINCH: u8 = 27; +pub const __WASI_SIGPOLL: u8 = 28; +pub const __WASI_SIGPWR: u8 = 29; +pub const __WASI_SIGSYS: u8 = 30; +pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 0x0001; +pub const __WASI_WHENCE_CUR: u8 = 0; +pub const __WASI_WHENCE_END: u8 = 1; +pub const __WASI_WHENCE_SET: u8 = 2; + +#[cfg_attr( + feature = "rustc-dep-of-std", + link(name = "c", kind = "static", cfg(target_feature = "crt-static")) +)] +#[cfg_attr( + feature = "rustc-dep-of-std", + link(name = "c", cfg(not(target_feature = "crt-static"))) +)] +extern { + pub fn _Exit(code: c_int) -> !; + pub fn _exit(code: c_int) -> !; + pub fn abort() -> !; + pub fn aligned_alloc(a: size_t, b: size_t) -> *mut c_void; + pub fn calloc(amt: size_t, amt2: size_t) -> *mut c_void; + pub fn exit(code: c_int) -> !; + pub fn free(ptr: *mut c_void); + pub fn getenv(s: *const c_char) -> *mut c_char; + pub fn malloc(amt: size_t) -> *mut c_void; + pub fn malloc_usable_size(ptr: *mut c_void) -> size_t; + pub fn sbrk(increment: ::intptr_t) -> *mut ::c_void; + pub fn rand() -> c_int; + pub fn read(fd: c_int, ptr: *mut c_void, size: size_t) -> ssize_t; + pub fn realloc(ptr: *mut c_void, amt: size_t) -> *mut c_void; + pub fn setenv(k: *const c_char, v: *const c_char, a: c_int) -> c_int; + pub fn unsetenv(k: *const c_char) -> c_int; + pub fn clearenv() -> ::c_int; + pub fn write(fd: c_int, ptr: *const c_void, size: size_t) -> ssize_t; + pub static mut environ: *mut *mut c_char; + pub fn fopen(a: *const c_char, b: *const c_char) -> *mut FILE; + pub fn freopen( + a: *const c_char, + b: *const c_char, + f: *mut FILE, + ) -> *mut FILE; + pub fn fclose(f: *mut FILE) -> c_int; + pub fn remove(a: *const c_char) -> c_int; + pub fn rename(a: *const c_char, b: *const c_char) -> c_int; + pub fn feof(f: *mut FILE) -> c_int; + pub fn ferror(f: *mut FILE) -> c_int; + pub fn fflush(f: *mut FILE) -> c_int; + pub fn clearerr(f: *mut FILE); + pub fn fseek(f: *mut FILE, b: c_long, c: c_int) -> c_int; + pub fn ftell(f: *mut FILE) -> c_long; + pub fn rewind(f: *mut FILE); + pub fn fgetpos(f: *mut FILE, pos: *mut fpos_t) -> c_int; + pub fn fsetpos(f: *mut FILE, pos: *const fpos_t) -> c_int; + pub fn fread( + buf: *mut c_void, + a: size_t, + b: size_t, + f: *mut FILE, + ) -> size_t; + pub fn fwrite( + buf: *const c_void, + a: size_t, + b: size_t, + f: *mut FILE, + ) -> size_t; + pub fn fgetc(f: *mut FILE) -> c_int; + pub fn getc(f: *mut FILE) -> c_int; + pub fn getchar() -> c_int; + pub fn ungetc(a: c_int, f: *mut FILE) -> c_int; + pub fn fputc(a: c_int, f: *mut FILE) -> c_int; + pub fn putc(a: c_int, f: *mut FILE) -> c_int; + pub fn putchar(a: c_int) -> c_int; + pub fn fputs(a: *const c_char, f: *mut FILE) -> c_int; + pub fn puts(a: *const c_char) -> c_int; + pub fn perror(a: *const c_char); + pub fn srand(a: c_uint); + pub fn atexit(a: extern fn()) -> c_int; + pub fn at_quick_exit(a: extern fn()) -> c_int; + pub fn quick_exit(a: c_int) -> !; + pub fn posix_memalign(a: *mut *mut c_void, b: size_t, c: size_t) -> c_int; + pub fn rand_r(a: *mut c_uint) -> c_int; + pub fn random() -> c_long; + pub fn srandom(a: c_uint); + pub fn putenv(a: *mut c_char) -> c_int; + pub fn clock() -> clock_t; + pub fn time(a: *mut time_t) -> time_t; + pub fn difftime(a: time_t, b: time_t) -> c_double; + pub fn mktime(a: *mut tm) -> time_t; + pub fn strftime( + a: *mut c_char, + b: size_t, + c: *const c_char, + d: *const tm, + ) -> size_t; + pub fn gmtime(a: *const time_t) -> *mut tm; + pub fn gmtime_r(a: *const time_t, b: *mut tm) -> *mut tm; + pub fn localtime_r(a: *const time_t, b: *mut tm) -> *mut tm; + pub fn asctime_r(a: *const tm, b: *mut c_char) -> *mut c_char; + pub fn ctime_r(a: *const time_t, b: *mut c_char) -> *mut c_char; + + pub fn nanosleep(a: *const timespec, b: *mut timespec) -> c_int; + // pub fn clock_getres(a: clockid_t, b: *mut timespec) -> c_int; + // pub fn clock_gettime(a: clockid_t, b: *mut timespec) -> c_int; + // pub fn clock_nanosleep( + // a: clockid_t, + // a2: c_int, + // b: *const timespec, + // c: *mut timespec, + // ) -> c_int; + + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn setvbuf( + stream: *mut FILE, + buffer: *mut c_char, + mode: c_int, + size: size_t, + ) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) + -> *mut c_char; + pub fn atoi(s: *const c_char) -> c_int; + pub fn atof(s: *const c_char) -> c_double; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol( + s: *const c_char, + endp: *mut *mut c_char, + base: c_int, + ) -> c_long; + pub fn strtoul( + s: *const c_char, + endp: *mut *mut c_char, + base: c_int, + ) -> c_ulong; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy( + dst: *mut c_char, + src: *const c_char, + n: size_t, + ) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat( + s: *mut c_char, + ct: *const c_char, + n: size_t, + ) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int; + pub fn strncasecmp( + s1: *const c_char, + s2: *const c_char, + n: size_t, + ) -> c_int; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy( + dest: *mut c_void, + src: *const c_void, + n: size_t, + ) -> *mut c_void; + pub fn memmove( + dest: *mut c_void, + src: *const c_void, + n: size_t, + ) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn fprintf( + stream: *mut ::FILE, + format: *const ::c_char, + ... + ) -> ::c_int; + pub fn printf(format: *const ::c_char, ...) -> ::c_int; + pub fn snprintf( + s: *mut ::c_char, + n: ::size_t, + format: *const ::c_char, + ... + ) -> ::c_int; + pub fn sprintf(s: *mut ::c_char, format: *const ::c_char, ...) -> ::c_int; + pub fn fscanf( + stream: *mut ::FILE, + format: *const ::c_char, + ... + ) -> ::c_int; + pub fn scanf(format: *const ::c_char, ...) -> ::c_int; + pub fn sscanf(s: *const ::c_char, format: *const ::c_char, ...) + -> ::c_int; + pub fn getchar_unlocked() -> ::c_int; + pub fn putchar_unlocked(c: ::c_int) -> ::c_int; + + pub fn shutdown(socket: ::c_int, how: ::c_int) -> ::c_int; + pub fn fstat(fildes: ::c_int, buf: *mut stat) -> ::c_int; + pub fn mkdir(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn stat(path: *const c_char, buf: *mut stat) -> ::c_int; + pub fn fdopen(fd: ::c_int, mode: *const c_char) -> *mut ::FILE; + pub fn fileno(stream: *mut ::FILE) -> ::c_int; + pub fn open(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + pub fn creat(path: *const c_char, mode: mode_t) -> ::c_int; + pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int; + pub fn opendir(dirname: *const c_char) -> *mut ::DIR; + pub fn fdopendir(fd: ::c_int) -> *mut ::DIR; + pub fn readdir(dirp: *mut ::DIR) -> *mut ::dirent; + pub fn closedir(dirp: *mut ::DIR) -> ::c_int; + pub fn rewinddir(dirp: *mut ::DIR); + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; + + pub fn openat( + dirfd: ::c_int, + pathname: *const ::c_char, + flags: ::c_int, + ... + ) -> ::c_int; + pub fn fstatat( + dirfd: ::c_int, + pathname: *const ::c_char, + buf: *mut stat, + flags: ::c_int, + ) -> ::c_int; + pub fn linkat( + olddirfd: ::c_int, + oldpath: *const ::c_char, + newdirfd: ::c_int, + newpath: *const ::c_char, + flags: ::c_int, + ) -> ::c_int; + pub fn mkdirat( + dirfd: ::c_int, + pathname: *const ::c_char, + mode: ::mode_t, + ) -> ::c_int; + pub fn readlinkat( + dirfd: ::c_int, + pathname: *const ::c_char, + buf: *mut ::c_char, + bufsiz: ::size_t, + ) -> ::ssize_t; + pub fn renameat( + olddirfd: ::c_int, + oldpath: *const ::c_char, + newdirfd: ::c_int, + newpath: *const ::c_char, + ) -> ::c_int; + pub fn symlinkat( + target: *const ::c_char, + newdirfd: ::c_int, + linkpath: *const ::c_char, + ) -> ::c_int; + pub fn unlinkat( + dirfd: ::c_int, + pathname: *const ::c_char, + flags: ::c_int, + ) -> ::c_int; + + pub fn access(path: *const c_char, amode: ::c_int) -> ::c_int; + pub fn close(fd: ::c_int) -> ::c_int; + pub fn fpathconf(filedes: ::c_int, name: ::c_int) -> c_long; + pub fn getopt( + argc: ::c_int, + argv: *const *mut c_char, + optstr: *const c_char, + ) -> ::c_int; + pub fn isatty(fd: ::c_int) -> ::c_int; + pub fn link(src: *const c_char, dst: *const c_char) -> ::c_int; + pub fn lseek(fd: ::c_int, offset: off_t, whence: ::c_int) -> off_t; + pub fn pathconf(path: *const c_char, name: ::c_int) -> c_long; + pub fn pause() -> ::c_int; + pub fn rmdir(path: *const c_char) -> ::c_int; + pub fn sleep(secs: ::c_uint) -> ::c_uint; + pub fn unlink(c: *const c_char) -> ::c_int; + pub fn pread( + fd: ::c_int, + buf: *mut ::c_void, + count: ::size_t, + offset: off_t, + ) -> ::ssize_t; + pub fn pwrite( + fd: ::c_int, + buf: *const ::c_void, + count: ::size_t, + offset: off_t, + ) -> ::ssize_t; + + pub fn lstat(path: *const c_char, buf: *mut stat) -> ::c_int; + + pub fn fsync(fd: ::c_int) -> ::c_int; + pub fn fdatasync(fd: ::c_int) -> ::c_int; + + pub fn symlink(path1: *const c_char, path2: *const c_char) -> ::c_int; + + pub fn truncate(path: *const c_char, length: off_t) -> ::c_int; + pub fn ftruncate(fd: ::c_int, length: off_t) -> ::c_int; + + pub fn getrusage(resource: ::c_int, usage: *mut rusage) -> ::c_int; + + pub fn gettimeofday(tp: *mut ::timeval, tz: *mut ::c_void) -> ::c_int; + pub fn times(buf: *mut ::tms) -> ::clock_t; + + pub fn strerror_r( + errnum: ::c_int, + buf: *mut c_char, + buflen: ::size_t, + ) -> ::c_int; + + pub fn usleep(secs: ::c_uint) -> ::c_int; + pub fn send( + socket: ::c_int, + buf: *const ::c_void, + len: ::size_t, + flags: ::c_int, + ) -> ::ssize_t; + pub fn recv( + socket: ::c_int, + buf: *mut ::c_void, + len: ::size_t, + flags: ::c_int, + ) -> ::ssize_t; + pub fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: ::c_int) -> ::c_int; + pub fn setlocale( + category: ::c_int, + locale: *const ::c_char, + ) -> *mut ::c_char; + pub fn localeconv() -> *mut lconv; + + pub fn readlink( + path: *const c_char, + buf: *mut c_char, + bufsz: ::size_t, + ) -> ::ssize_t; + + pub fn timegm(tm: *mut ::tm) -> time_t; + + pub fn sysconf(name: ::c_int) -> ::c_long; + + pub fn fseeko( + stream: *mut ::FILE, + offset: ::off_t, + whence: ::c_int, + ) -> ::c_int; + pub fn ftello(stream: *mut ::FILE) -> ::off_t; + pub fn posix_fallocate( + fd: ::c_int, + offset: ::off_t, + len: ::off_t, + ) -> ::c_int; + + pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn getline( + lineptr: *mut *mut c_char, + n: *mut size_t, + stream: *mut FILE, + ) -> ssize_t; + + pub fn faccessat( + dirfd: ::c_int, + pathname: *const ::c_char, + mode: ::c_int, + flags: ::c_int, + ) -> ::c_int; + pub fn writev( + fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + ) -> ::ssize_t; + pub fn readv( + fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + ) -> ::ssize_t; + pub fn pwritev( + fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t, + ) -> ::ssize_t; + pub fn preadv( + fd: ::c_int, + iov: *const ::iovec, + iovcnt: ::c_int, + offset: ::off_t, + ) -> ::ssize_t; + pub fn posix_fadvise( + fd: ::c_int, + offset: ::off_t, + len: ::off_t, + advise: ::c_int, + ) -> ::c_int; + pub fn futimens(fd: ::c_int, times: *const ::timespec) -> ::c_int; + pub fn utimensat( + dirfd: ::c_int, + path: *const ::c_char, + times: *const ::timespec, + flag: ::c_int, + ) -> ::c_int; + pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int; + pub fn memrchr( + cx: *const ::c_void, + c: ::c_int, + n: ::size_t, + ) -> *mut ::c_void; + pub fn abs(i: c_int) -> c_int; + pub fn labs(i: c_long) -> c_long; + pub fn duplocale(base: ::locale_t) -> ::locale_t; + pub fn freelocale(loc: ::locale_t); + pub fn newlocale( + mask: ::c_int, + locale: *const ::c_char, + base: ::locale_t, + ) -> ::locale_t; + pub fn uselocale(loc: ::locale_t) -> ::locale_t; + pub fn sched_yield() -> ::c_int; + + pub fn __wasilibc_register_preopened_fd( + fd: c_int, + path: *const c_char, + ) -> c_int; + pub fn __wasilibc_fd_renumber(fd: c_int, newfd: c_int) -> c_int; + pub fn __wasilibc_unlinkat(fd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_rmdirat(fd: c_int, path: *const c_char) -> c_int; + pub fn __wasilibc_init_preopen(); + pub fn __wasilibc_find_relpath( + path: *const c_char, + rights_base: __wasi_rights_t, + rights_inheriting: __wasi_rights_t, + relative_path: *mut *const c_char, + ) -> c_int; + pub fn __wasilibc_tell(fd: c_int) -> ::off_t; + + pub fn arc4random() -> u32; + pub fn arc4random_buf(a: *mut c_void, b: size_t); + pub fn arc4random_uniform(a: u32) -> u32; +} + +#[link(wasm_import_module = "wasi_unstable")] +extern { + #[link_name = "clock_res_get"] + pub fn __wasi_clock_res_get( + clock_id: __wasi_clockid_t, + resolution: *mut __wasi_timestamp_t, + ) -> __wasi_errno_t; + #[link_name = "clock_time_get"] + pub fn __wasi_clock_time_get( + clock_id: __wasi_clockid_t, + precision: __wasi_timestamp_t, + time: *mut __wasi_timestamp_t, + ) -> __wasi_errno_t; + #[link_name = "fd_close"] + pub fn __wasi_fd_close(fd: __wasi_fd_t) -> __wasi_errno_t; + #[link_name = "fd_datasync"] + pub fn __wasi_fd_datasync(fd: __wasi_fd_t) -> __wasi_errno_t; + #[link_name = "fd_pread"] + pub fn __wasi_fd_pread( + fd: __wasi_fd_t, + iovs: *const __wasi_iovec_t, + iovs_len: size_t, + offset: __wasi_filesize_t, + nread: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_pwrite"] + pub fn __wasi_fd_pwrite( + fd: __wasi_fd_t, + iovs: *const __wasi_ciovec_t, + iovs_len: size_t, + offset: __wasi_filesize_t, + nwritten: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_read"] + pub fn __wasi_fd_read( + fd: __wasi_fd_t, + iovs: *const __wasi_iovec_t, + iovs_len: size_t, + nread: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_renumber"] + pub fn __wasi_fd_renumber( + from: __wasi_fd_t, + to: __wasi_fd_t, + ) -> __wasi_errno_t; + #[link_name = "fd_seek"] + pub fn __wasi_fd_seek( + fd: __wasi_fd_t, + offset: __wasi_filedelta_t, + whence: __wasi_whence_t, + newoffset: *mut __wasi_filesize_t, + ) -> __wasi_errno_t; + #[link_name = "fd_tell"] + pub fn __wasi_fd_tell( + fd: __wasi_fd_t, + newoffset: *mut __wasi_filesize_t, + ) -> __wasi_errno_t; + #[link_name = "fd_fdstat_get"] + pub fn __wasi_fd_fdstat_get( + fd: __wasi_fd_t, + buf: *mut __wasi_fdstat_t, + ) -> __wasi_errno_t; + #[link_name = "fd_fdstat_set_flags"] + pub fn __wasi_fd_fdstat_set_flags( + fd: __wasi_fd_t, + flags: __wasi_fdflags_t, + ) -> __wasi_errno_t; + #[link_name = "fd_fdstat_set_rights"] + pub fn __wasi_fd_fdstat_set_rights( + fd: __wasi_fd_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + ) -> __wasi_errno_t; + #[link_name = "fd_sync"] + pub fn __wasi_fd_sync(fd: __wasi_fd_t) -> __wasi_errno_t; + #[link_name = "fd_write"] + pub fn __wasi_fd_write( + fd: __wasi_fd_t, + iovs: *const __wasi_ciovec_t, + iovs_len: size_t, + nwritten: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_advise"] + pub fn __wasi_fd_advise( + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + advice: __wasi_advice_t, + ) -> __wasi_errno_t; + #[link_name = "fd_allocate"] + pub fn __wasi_fd_allocate( + fd: __wasi_fd_t, + offset: __wasi_filesize_t, + len: __wasi_filesize_t, + ) -> __wasi_errno_t; + #[link_name = "path_create_directory"] + pub fn __wasi_path_create_directory( + fd: __wasi_fd_t, + path: *const ::c_char, + path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "path_link"] + pub fn __wasi_path_link( + old_fd: __wasi_fd_t, + old_flags: __wasi_lookupflags_t, + old_path: *const ::c_char, + old_path_len: size_t, + new_fd: __wasi_fd_t, + new_path: *const ::c_char, + new_path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "path_open"] + pub fn __wasi_path_open( + dirfd: __wasi_fd_t, + dirflags: __wasi_lookupflags_t, + path: *const ::c_char, + path_len: size_t, + oflags: __wasi_oflags_t, + fs_rights_base: __wasi_rights_t, + fs_rights_inheriting: __wasi_rights_t, + fs_flags: __wasi_fdflags_t, + fd: *mut __wasi_fd_t, + ) -> __wasi_errno_t; + #[link_name = "fd_readdir"] + pub fn __wasi_fd_readdir( + fd: __wasi_fd_t, + buf: *mut ::c_void, + buf_len: size_t, + cookie: __wasi_dircookie_t, + bufused: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "path_readlink"] + pub fn __wasi_path_readlink( + fd: __wasi_fd_t, + path: *const ::c_char, + path_len: size_t, + buf: *mut ::c_char, + buf_len: size_t, + bufused: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "path_rename"] + pub fn __wasi_path_rename( + old_fd: __wasi_fd_t, + old_path: *const ::c_char, + old_path_len: size_t, + new_fd: __wasi_fd_t, + new_path: *const ::c_char, + new_path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_filestat_get"] + pub fn __wasi_fd_filestat_get( + fd: __wasi_fd_t, + buf: *mut __wasi_filestat_t, + ) -> __wasi_errno_t; + #[link_name = "fd_filestat_set_times"] + pub fn __wasi_fd_filestat_set_times( + fd: __wasi_fd_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fstflags: __wasi_fstflags_t, + ) -> __wasi_errno_t; + #[link_name = "fd_filestat_set_size"] + pub fn __wasi_fd_filestat_set_size( + fd: __wasi_fd_t, + st_size: __wasi_filesize_t, + ) -> __wasi_errno_t; + #[link_name = "path_filestat_get"] + pub fn __wasi_path_filestat_get( + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: *const ::c_char, + path_len: size_t, + buf: *mut __wasi_filestat_t, + ) -> __wasi_errno_t; + #[link_name = "path_filestat_set_times"] + pub fn __wasi_path_filestat_set_times( + fd: __wasi_fd_t, + flags: __wasi_lookupflags_t, + path: *const ::c_char, + path_len: size_t, + st_atim: __wasi_timestamp_t, + st_mtim: __wasi_timestamp_t, + fstflags: __wasi_fstflags_t, + ) -> __wasi_errno_t; + #[link_name = "path_symlink"] + pub fn __wasi_path_symlink( + old_path: *const ::c_char, + old_path_len: size_t, + fd: __wasi_fd_t, + new_path: *const ::c_char, + new_path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "path_unlink_file"] + pub fn __wasi_path_unlink_file( + fd: __wasi_fd_t, + path: *const ::c_char, + path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "path_remove_directory"] + pub fn __wasi_path_remove_directory( + fd: __wasi_fd_t, + path: *const ::c_char, + path_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "poll_oneoff"] + pub fn __wasi_poll_oneoff( + in_: *const __wasi_subscription_t, + out: *mut __wasi_event_t, + nsubscriptions: size_t, + nevents: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "proc_exit"] + pub fn __wasi_proc_exit(rval: __wasi_exitcode_t); + #[link_name = "proc_raise"] + pub fn __wasi_proc_raise(sig: __wasi_signal_t) -> __wasi_errno_t; + #[link_name = "random_get"] + pub fn __wasi_random_get( + buf: *mut ::c_void, + buf_len: size_t, + ) -> __wasi_errno_t; + #[link_name = "sock_recv"] + pub fn __wasi_sock_recv( + sock: __wasi_fd_t, + ri_data: *const __wasi_iovec_t, + ri_data_len: size_t, + ri_flags: __wasi_riflags_t, + ro_datalen: *mut size_t, + ro_flags: *mut __wasi_roflags_t, + ) -> __wasi_errno_t; + #[link_name = "sock_send"] + pub fn __wasi_sock_send( + sock: __wasi_fd_t, + si_data: *const __wasi_ciovec_t, + si_data_len: size_t, + si_flags: __wasi_siflags_t, + so_datalen: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "sock_shutdown"] + pub fn __wasi_sock_shutdown( + sock: __wasi_fd_t, + how: __wasi_sdflags_t, + ) -> __wasi_errno_t; + #[link_name = "sched_yield"] + pub fn __wasi_sched_yield() -> __wasi_errno_t; + #[link_name = "args_get"] + pub fn __wasi_args_get( + argv: *mut *mut c_char, + argv_buf: *mut c_char, + ) -> __wasi_errno_t; + #[link_name = "args_sizes_get"] + pub fn __wasi_args_sizes_get( + argc: *mut size_t, + argv_buf_size: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "environ_get"] + pub fn __wasi_environ_get( + environ: *mut *mut c_char, + environ_buf: *mut c_char, + ) -> __wasi_errno_t; + #[link_name = "environ_sizes_get"] + pub fn __wasi_environ_sizes_get( + environ_count: *mut size_t, + environ_buf_size: *mut size_t, + ) -> __wasi_errno_t; + #[link_name = "fd_prestat_get"] + pub fn __wasi_fd_prestat_get( + fd: __wasi_fd_t, + buf: *mut __wasi_prestat_t, + ) -> __wasi_errno_t; + #[link_name = "fd_prestat_dir_name"] + pub fn __wasi_fd_prestat_dir_name( + fd: __wasi_fd_t, + path: *mut c_char, + path_len: size_t, + ) -> __wasi_errno_t; +} diff --git a/libc/src/windows/gnu.rs b/libc/src/windows/gnu.rs new file mode 100644 index 000000000..45e7ddaea --- /dev/null +++ b/libc/src/windows/gnu.rs @@ -0,0 +1,13 @@ +pub const L_tmpnam: ::c_uint = 14; +pub const TMP_MAX: ::c_uint = 0x7fff; + +// stdio file descriptor numbers +pub const STDIN_FILENO: ::c_int = 0; +pub const STDOUT_FILENO: ::c_int = 1; +pub const STDERR_FILENO: ::c_int = 2; + +extern { + pub fn strcasecmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int; + pub fn strncasecmp(s1: *const ::c_char, s2: *const ::c_char, + n: ::size_t) -> ::c_int; +} diff --git a/libc/src/windows/mod.rs b/libc/src/windows/mod.rs new file mode 100644 index 000000000..70ca675bd --- /dev/null +++ b/libc/src/windows/mod.rs @@ -0,0 +1,466 @@ +//! Windows CRT definitions + +pub type int8_t = i8; +pub type int16_t = i16; +pub type int32_t = i32; +pub type int64_t = i64; +pub type uint8_t = u8; +pub type uint16_t = u16; +pub type uint32_t = u32; +pub type uint64_t = u64; + +pub type c_schar = i8; +pub type c_uchar = u8; +pub type c_short = i16; +pub type c_ushort = u16; +pub type c_int = i32; +pub type c_uint = u32; +pub type c_float = f32; +pub type c_double = f64; +pub type c_longlong = i64; +pub type c_ulonglong = u64; +pub type intmax_t = i64; +pub type uintmax_t = u64; + +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; +pub type uintptr_t = usize; +pub type ssize_t = isize; +pub type sighandler_t = usize; + +pub type c_char = i8; +pub type c_long = i32; +pub type c_ulong = u32; +pub type wchar_t = u16; + +pub type clock_t = i32; + +cfg_if! { + if #[cfg(all(target_arch = "x86", target_env = "gnu"))] { + pub type time_t = i32; + } else { + pub type time_t = i64; + } +} + +pub type off_t = i32; +pub type dev_t = u32; +pub type ino_t = u16; +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum timezone {} +impl ::Copy for timezone {} +impl ::Clone for timezone { + fn clone(&self) -> timezone { *self } +} +pub type time64_t = i64; + +pub type SOCKET = ::uintptr_t; + +s! { + // note this is the struct called stat64 in Windows. Not stat, nor stati64. + pub struct stat { + pub st_dev: dev_t, + pub st_ino: ino_t, + pub st_mode: u16, + pub st_nlink: ::c_short, + pub st_uid: ::c_short, + pub st_gid: ::c_short, + pub st_rdev: dev_t, + pub st_size: i64, + pub st_atime: time64_t, + pub st_mtime: time64_t, + pub st_ctime: time64_t, + } + + // note that this is called utimbuf64 in Windows + pub struct utimbuf { + pub actime: time64_t, + pub modtime: time64_t, + } + + pub struct tm { + pub tm_sec: ::c_int, + pub tm_min: ::c_int, + pub tm_hour: ::c_int, + pub tm_mday: ::c_int, + pub tm_mon: ::c_int, + pub tm_year: ::c_int, + pub tm_wday: ::c_int, + pub tm_yday: ::c_int, + pub tm_isdst: ::c_int, + } + + pub struct timeval { + pub tv_sec: c_long, + pub tv_usec: c_long, + } + + pub struct timespec { + pub tv_sec: time_t, + pub tv_nsec: c_long, + } + + pub struct sockaddr { + pub sa_family: c_ushort, + pub sa_data: [c_char; 14], + } +} + +pub const INT_MIN: c_int = -2147483648; +pub const INT_MAX: c_int = 2147483647; + +pub const EXIT_FAILURE: ::c_int = 1; +pub const EXIT_SUCCESS: ::c_int = 0; +pub const RAND_MAX: ::c_int = 32767; +pub const EOF: ::c_int = -1; +pub const SEEK_SET: ::c_int = 0; +pub const SEEK_CUR: ::c_int = 1; +pub const SEEK_END: ::c_int = 2; +pub const _IOFBF: ::c_int = 0; +pub const _IONBF: ::c_int = 4; +pub const _IOLBF: ::c_int = 64; +pub const BUFSIZ: ::c_uint = 512; +pub const FOPEN_MAX: ::c_uint = 20; +pub const FILENAME_MAX: ::c_uint = 260; + +pub const O_RDONLY: ::c_int = 0; +pub const O_WRONLY: ::c_int = 1; +pub const O_RDWR: ::c_int = 2; +pub const O_APPEND: ::c_int = 8; +pub const O_CREAT: ::c_int = 256; +pub const O_EXCL: ::c_int = 1024; +pub const O_TEXT: ::c_int = 16384; +pub const O_BINARY: ::c_int = 32768; +pub const O_NOINHERIT: ::c_int = 128; +pub const O_TRUNC: ::c_int = 512; +pub const S_IFCHR: ::c_int = 8192; +pub const S_IFDIR: ::c_int = 16384; +pub const S_IFREG: ::c_int = 32768; +pub const S_IFMT: ::c_int = 61440; +pub const S_IEXEC: ::c_int = 64; +pub const S_IWRITE: ::c_int = 128; +pub const S_IREAD: ::c_int = 256; + +pub const LC_ALL: ::c_int = 0; +pub const LC_COLLATE: ::c_int = 1; +pub const LC_CTYPE: ::c_int = 2; +pub const LC_MONETARY: ::c_int = 3; +pub const LC_NUMERIC: ::c_int = 4; +pub const LC_TIME: ::c_int = 5; + +pub const EPERM: ::c_int = 1; +pub const ENOENT: ::c_int = 2; +pub const ESRCH: ::c_int = 3; +pub const EINTR: ::c_int = 4; +pub const EIO: ::c_int = 5; +pub const ENXIO: ::c_int = 6; +pub const E2BIG: ::c_int = 7; +pub const ENOEXEC: ::c_int = 8; +pub const EBADF: ::c_int = 9; +pub const ECHILD: ::c_int = 10; +pub const EAGAIN: ::c_int = 11; +pub const ENOMEM: ::c_int = 12; +pub const EACCES: ::c_int = 13; +pub const EFAULT: ::c_int = 14; +pub const EBUSY: ::c_int = 16; +pub const EEXIST: ::c_int = 17; +pub const EXDEV: ::c_int = 18; +pub const ENODEV: ::c_int = 19; +pub const ENOTDIR: ::c_int = 20; +pub const EISDIR: ::c_int = 21; +pub const EINVAL: ::c_int = 22; +pub const ENFILE: ::c_int = 23; +pub const EMFILE: ::c_int = 24; +pub const ENOTTY: ::c_int = 25; +pub const EFBIG: ::c_int = 27; +pub const ENOSPC: ::c_int = 28; +pub const ESPIPE: ::c_int = 29; +pub const EROFS: ::c_int = 30; +pub const EMLINK: ::c_int = 31; +pub const EPIPE: ::c_int = 32; +pub const EDOM: ::c_int = 33; +pub const ERANGE: ::c_int = 34; +pub const EDEADLK: ::c_int = 36; +pub const EDEADLOCK: ::c_int = 36; +pub const ENAMETOOLONG: ::c_int = 38; +pub const ENOLCK: ::c_int = 39; +pub const ENOSYS: ::c_int = 40; +pub const ENOTEMPTY: ::c_int = 41; +pub const EILSEQ: ::c_int = 42; +pub const STRUNCATE: ::c_int = 80; + +// signal codes +pub const SIGINT: ::c_int = 2; +pub const SIGILL: ::c_int = 4; +pub const SIGFPE: ::c_int = 8; +pub const SIGSEGV: ::c_int = 11; +pub const SIGTERM: ::c_int = 15; +pub const SIGABRT: ::c_int = 22; +pub const NSIG: ::c_int = 23; +pub const SIG_ERR: ::c_int = -1; + +// inline comment below appeases style checker +#[cfg(all(target_env = "msvc", feature = "rustc-dep-of-std"))] // " if " +#[link(name = "msvcrt", cfg(not(target_feature = "crt-static")))] +#[link(name = "libcmt", cfg(target_feature = "crt-static"))] +extern {} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum FILE {} +impl ::Copy for FILE {} +impl ::Clone for FILE { + fn clone(&self) -> FILE { *self } +} +#[cfg_attr(feature = "extra_traits", derive(Debug))] +pub enum fpos_t {} // TODO: fill this out with a struct +impl ::Copy for fpos_t {} +impl ::Clone for fpos_t { + fn clone(&self) -> fpos_t { *self } +} + +extern { + pub fn isalnum(c: c_int) -> c_int; + pub fn isalpha(c: c_int) -> c_int; + pub fn iscntrl(c: c_int) -> c_int; + pub fn isdigit(c: c_int) -> c_int; + pub fn isgraph(c: c_int) -> c_int; + pub fn islower(c: c_int) -> c_int; + pub fn isprint(c: c_int) -> c_int; + pub fn ispunct(c: c_int) -> c_int; + pub fn isspace(c: c_int) -> c_int; + pub fn isupper(c: c_int) -> c_int; + pub fn isxdigit(c: c_int) -> c_int; + pub fn tolower(c: c_int) -> c_int; + pub fn toupper(c: c_int) -> c_int; + pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE; + pub fn freopen(filename: *const c_char, mode: *const c_char, + file: *mut FILE) -> *mut FILE; + pub fn fflush(file: *mut FILE) -> c_int; + pub fn fclose(file: *mut FILE) -> c_int; + pub fn remove(filename: *const c_char) -> c_int; + pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int; + pub fn tmpfile() -> *mut FILE; + pub fn setvbuf(stream: *mut FILE, buffer: *mut c_char, mode: c_int, + size: size_t) -> c_int; + pub fn setbuf(stream: *mut FILE, buf: *mut c_char); + pub fn getchar() -> c_int; + pub fn putchar(c: c_int) -> c_int; + pub fn fgetc(stream: *mut FILE) -> c_int; + pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char; + pub fn fputc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int; + pub fn puts(s: *const c_char) -> c_int; + pub fn ungetc(c: c_int, stream: *mut FILE) -> c_int; + pub fn fread(ptr: *mut c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fwrite(ptr: *const c_void, size: size_t, nobj: size_t, + stream: *mut FILE) -> size_t; + pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int; + pub fn ftell(stream: *mut FILE) -> c_long; + pub fn rewind(stream: *mut FILE); + pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int; + pub fn fsetpos(stream: *mut FILE, ptr: *const fpos_t) -> c_int; + pub fn feof(stream: *mut FILE) -> c_int; + pub fn ferror(stream: *mut FILE) -> c_int; + pub fn perror(s: *const c_char); + pub fn atoi(s: *const c_char) -> c_int; + pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double; + pub fn strtol(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_long; + pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, + base: c_int) -> c_ulong; + pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void; + pub fn malloc(size: size_t) -> *mut c_void; + pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn abort() -> !; + pub fn exit(status: c_int) -> !; + pub fn _exit(status: c_int) -> !; + pub fn atexit(cb: extern fn()) -> c_int; + pub fn system(s: *const c_char) -> c_int; + pub fn getenv(s: *const c_char) -> *mut c_char; + + pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char; + pub fn strncpy(dst: *mut c_char, src: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char; + pub fn strncat(s: *mut c_char, ct: *const c_char, + n: size_t) -> *mut c_char; + pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int; + pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int; + pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char; + pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t; + pub fn strdup(cs: *const c_char) -> *mut c_char; + pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char; + pub fn strlen(cs: *const c_char) -> size_t; + pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t; + pub fn strerror(n: c_int) -> *mut c_char; + pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char; + pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t; + pub fn wcslen(buf: *const wchar_t) -> size_t; + pub fn wcstombs(dest: *mut c_char, src: *const wchar_t, + n: size_t) -> ::size_t; + + pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void; + pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int; + pub fn memcpy(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memmove(dest: *mut c_void, src: *const c_void, + n: size_t) -> *mut c_void; + pub fn memset(dest: *mut c_void, c: c_int, n: size_t) -> *mut c_void; + + pub fn abs(i: c_int) -> c_int; + pub fn atof(s: *const c_char) -> c_double; + pub fn labs(i: c_long) -> c_long; + pub fn rand() -> c_int; + pub fn srand(seed: c_uint); + + pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t; + pub fn raise(signum: c_int) -> c_int; + + #[link_name = "_chmod"] + pub fn chmod(path: *const c_char, mode: ::c_int) -> ::c_int; + #[link_name = "_wchmod"] + pub fn wchmod(path: *const wchar_t, mode: ::c_int) -> ::c_int; + #[link_name = "_mkdir"] + pub fn mkdir(path: *const c_char) -> ::c_int; + #[link_name = "_wrmdir"] + pub fn wrmdir(path: *const wchar_t) -> ::c_int; + #[link_name = "_fstat64"] + pub fn fstat(fildes: ::c_int, buf: *mut stat) -> ::c_int; + #[link_name = "_stat64"] + pub fn stat(path: *const c_char, buf: *mut stat) -> ::c_int; + #[link_name = "_wstat64"] + pub fn wstat(path: *const wchar_t, buf: *mut stat) -> ::c_int; + #[link_name = "_wutime64"] + pub fn wutime(file: *const wchar_t, buf: *mut utimbuf) -> ::c_int; + #[link_name = "_popen"] + pub fn popen(command: *const c_char, mode: *const c_char) -> *mut ::FILE; + #[link_name = "_pclose"] + pub fn pclose(stream: *mut ::FILE) -> ::c_int; + #[link_name = "_fdopen"] + pub fn fdopen(fd: ::c_int, mode: *const c_char) -> *mut ::FILE; + #[link_name = "_fileno"] + pub fn fileno(stream: *mut ::FILE) -> ::c_int; + #[link_name = "_open"] + pub fn open(path: *const c_char, oflag: ::c_int, ...) -> ::c_int; + #[link_name = "_wopen"] + pub fn wopen(path: *const wchar_t, oflag: ::c_int, ...) -> ::c_int; + #[link_name = "_creat"] + pub fn creat(path: *const c_char, mode: ::c_int) -> ::c_int; + #[link_name = "_access"] + pub fn access(path: *const c_char, amode: ::c_int) -> ::c_int; + #[link_name = "_chdir"] + pub fn chdir(dir: *const c_char) -> ::c_int; + #[link_name = "_close"] + pub fn close(fd: ::c_int) -> ::c_int; + #[link_name = "_dup"] + pub fn dup(fd: ::c_int) -> ::c_int; + #[link_name = "_dup2"] + pub fn dup2(src: ::c_int, dst: ::c_int) -> ::c_int; + #[link_name = "_execv"] + pub fn execv(prog: *const c_char, argv: *const *const c_char) -> ::intptr_t; + #[link_name = "_execve"] + pub fn execve(prog: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> ::c_int; + #[link_name = "_execvp"] + pub fn execvp(c: *const c_char, argv: *const *const c_char) -> ::c_int; + #[link_name = "_execvpe"] + pub fn execvpe(c: *const c_char, argv: *const *const c_char, + envp: *const *const c_char) -> ::c_int; + #[link_name = "_getcwd"] + pub fn getcwd(buf: *mut c_char, size: ::c_int) -> *mut c_char; + #[link_name = "_getpid"] + pub fn getpid() -> ::c_int; + #[link_name = "_isatty"] + pub fn isatty(fd: ::c_int) -> ::c_int; + #[link_name = "_lseek"] + pub fn lseek(fd: ::c_int, offset: c_long, origin: ::c_int) -> c_long; + #[link_name = "_pipe"] + pub fn pipe(fds: *mut ::c_int, + psize: ::c_uint, + textmode: ::c_int) -> ::c_int; + #[link_name = "_read"] + pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::c_uint) -> ::c_int; + #[link_name = "_rmdir"] + pub fn rmdir(path: *const c_char) -> ::c_int; + #[link_name = "_unlink"] + pub fn unlink(c: *const c_char) -> ::c_int; + #[link_name = "_write"] + pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::c_uint) -> ::c_int; + #[link_name = "_commit"] + pub fn commit(fd: ::c_int) -> ::c_int; + #[link_name = "_get_osfhandle"] + pub fn get_osfhandle(fd: ::c_int) -> ::intptr_t; + #[link_name = "_open_osfhandle"] + pub fn open_osfhandle(osfhandle: ::intptr_t, flags: ::c_int) -> ::c_int; + pub fn setlocale(category: ::c_int, locale: *const c_char) -> *mut c_char; + #[link_name = "_wsetlocale"] + pub fn wsetlocale(category: ::c_int, + locale: *const wchar_t) -> *mut wchar_t; +} + +extern "system" { + pub fn listen(s: SOCKET, backlog: ::c_int) -> ::c_int; + pub fn accept(s: SOCKET, addr: *mut ::sockaddr, + addrlen: *mut ::c_int) -> SOCKET; + pub fn bind(s: SOCKET, name: *const ::sockaddr, + namelen: ::c_int) -> ::c_int; + pub fn connect(s: SOCKET, name: *const ::sockaddr, + namelen: ::c_int) -> ::c_int; + pub fn getpeername(s: SOCKET, name: *mut ::sockaddr, + nameln: *mut ::c_int) -> ::c_int; + pub fn getsockname(s: SOCKET, name: *mut ::sockaddr, + nameln: *mut ::c_int) -> ::c_int; + pub fn getsockopt(s: SOCKET, level: ::c_int, optname: ::c_int, + optval: *mut ::c_char, + optlen: *mut ::c_int) -> ::c_int; + pub fn recvfrom(s: SOCKET, buf: *mut ::c_char, len: ::c_int, + flags: ::c_int, from: *mut ::sockaddr, + fromlen: *mut ::c_int) -> ::c_int; + pub fn sendto(s: SOCKET, buf: *const ::c_char, len: ::c_int, + flags: ::c_int, to: *const ::sockaddr, + tolen: ::c_int) -> ::c_int; + pub fn setsockopt(s: SOCKET, level: ::c_int, optname: ::c_int, + optval: *const ::c_char, + optlen: ::c_int) -> ::c_int; + pub fn socket(af: ::c_int, socket_type: ::c_int, + protocol: ::c_int) -> SOCKET; +} + +cfg_if! { + if #[cfg(libc_core_cvoid)] { + pub use ::ffi::c_void; + } else { + // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help + // enable more optimization opportunities around it recognizing things + // like malloc/free. + #[repr(u8)] + #[allow(missing_copy_implementations)] + #[allow(missing_debug_implementations)] + pub enum c_void { + // Two dummy variants so the #[repr] attribute can be used. + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, + } + } +} + +cfg_if! { + if #[cfg(all(target_env = "gnu"))] { + mod gnu; + pub use self::gnu::*; + } else if #[cfg(all(target_env = "msvc"))] { + mod msvc; + pub use self::msvc::*; + } else { + // Unknown target_env + } +} diff --git a/libc/src/windows/msvc.rs b/libc/src/windows/msvc.rs new file mode 100644 index 000000000..1ebfcadd1 --- /dev/null +++ b/libc/src/windows/msvc.rs @@ -0,0 +1,10 @@ +pub const L_tmpnam: ::c_uint = 260; +pub const TMP_MAX: ::c_uint = 0x7fff_ffff; + +extern { + #[link_name = "_stricmp"] + pub fn stricmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int; + #[link_name = "_strnicmp"] + pub fn strnicmp(s1: *const ::c_char, s2: *const ::c_char, + n: ::size_t) -> ::c_int; +} diff --git a/libgit2-sys/.cargo-checksum.json b/libgit2-sys/.cargo-checksum.json new file mode 100644 index 000000000..322bcd1d2 --- /dev/null +++ b/libgit2-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1"} \ No newline at end of file diff --git a/libgit2-sys/.pc/.quilt_patches b/libgit2-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/libgit2-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/libgit2-sys/.pc/.quilt_series b/libgit2-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/libgit2-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/libgit2-sys/.pc/.version b/libgit2-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/libgit2-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/libgit2-sys/.pc/applied-patches b/libgit2-sys/.pc/applied-patches new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/libgit2-sys/.pc/applied-patches @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/libgit2-sys/.pc/no-special-snowflake-env.patch/.timestamp b/libgit2-sys/.pc/no-special-snowflake-env.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/libgit2-sys/.pc/no-special-snowflake-env.patch/build.rs b/libgit2-sys/.pc/no-special-snowflake-env.patch/build.rs new file mode 100644 index 000000000..20806c72a --- /dev/null +++ b/libgit2-sys/.pc/no-special-snowflake-env.patch/build.rs @@ -0,0 +1,194 @@ +extern crate cc; +extern crate pkg_config; + +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn main() { + let https = env::var("CARGO_FEATURE_HTTPS").is_ok(); + let ssh = env::var("CARGO_FEATURE_SSH").is_ok(); + let curl = env::var("CARGO_FEATURE_CURL").is_ok(); + + if env::var("LIBGIT2_SYS_USE_PKG_CONFIG").is_ok() { + if pkg_config::find_library("libgit2").is_ok() { + return + } + } + + if !Path::new("libgit2/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + let target = env::var("TARGET").unwrap(); + let windows = target.contains("windows"); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let include = dst.join("include"); + let mut cfg = cc::Build::new(); + fs::create_dir_all(&include).unwrap(); + + // Copy over all header files + cp_r("libgit2/include".as_ref(), &include); + + cfg.include(&include) + .include("libgit2/src") + .out_dir(dst.join("build")) + .warnings(false); + + // Include all cross-platform C files + add_c_files(&mut cfg, "libgit2/src".as_ref()); + add_c_files(&mut cfg, "libgit2/src/xdiff".as_ref()); + + // These are activated by feautres, but they're all unconditionally always + // compiled apparently and have internal #define's to make sure they're + // compiled correctly. + add_c_files(&mut cfg, "libgit2/src/transports".as_ref()); + add_c_files(&mut cfg, "libgit2/src/streams".as_ref()); + + // Always use bundled http-parser for now + cfg.include("libgit2/deps/http-parser") + .file("libgit2/deps/http-parser/http_parser.c"); + + // Always use bundled regex for now + cfg.include("libgit2/deps/regex") + .file("libgit2/deps/regex/regex.c"); + + if windows { + add_c_files(&mut cfg, "libgit2/src/win32".as_ref()); + cfg.define("STRSAFE_NO_DEPRECATE", None); + + // libgit2's build system claims that forks like mingw-w64 of MinGW + // still want this define to use C99 stdio functions automatically. + // Apparently libgit2 breaks at runtime if this isn't here? Who knows! + if target.contains("gnu") { + cfg.define("__USE_MINGW_ANSI_STDIO", "1"); + } + } else { + add_c_files(&mut cfg, "libgit2/src/unix".as_ref()); + cfg.flag("-fvisibility=hidden"); + } + if target.contains("solaris") { + cfg.define("_POSIX_C_SOURCE", "200112L"); + cfg.define("__EXTENSIONS__", None); + } + + let mut features = String::new(); + + features.push_str("#ifndef INCLUDE_features_h\n"); + features.push_str("#define INCLUDE_features_h\n"); + features.push_str("#define GIT_THREADS 1\n"); + + if !target.contains("android") { + features.push_str("#define GIT_USE_NSEC 1\n"); + } + + if target.contains("apple") { + features.push_str("#define GIT_USE_STAT_MTIMESPEC 1\n"); + } else { + features.push_str("#define GIT_USE_STAT_MTIM 1\n"); + } + + if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" { + features.push_str("#define GIT_ARCH_32 1\n"); + } else { + features.push_str("#define GIT_ARCH_64 1\n"); + } + + if ssh { + if let Some(path) = env::var_os("DEP_SSH2_INCLUDE") { + cfg.include(path); + } + features.push_str("#define GIT_SSH 1\n"); + features.push_str("#define GIT_SSH_MEMORY_CREDENTIALS 1\n"); + } + if https { + features.push_str("#define GIT_HTTPS 1\n"); + + if windows { + features.push_str("#define GIT_WINHTTP 1\n"); + features.push_str("#define GIT_SHA1_WIN32 1\n"); + cfg.file("libgit2/src/hash/hash_win32.c"); + } else if target.contains("apple") { + features.push_str("#define GIT_SECURE_TRANSPORT 1\n"); + features.push_str("#define GIT_SHA1_COMMON_CRYPTO 1\n"); + } else { + features.push_str("#define GIT_OPENSSL 1\n"); + features.push_str("#define GIT_SHA1_OPENSSL 1\n"); + if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { + cfg.include(path); + } + } + } else { + cfg.file("libgit2/src/hash/hash_generic.c"); + } + + if curl { + features.push_str("#define GIT_CURL 1\n"); + if let Some(path) = env::var_os("DEP_CURL_INCLUDE") { + cfg.include(path); + } + // Handle dllimport/dllexport on windows by making sure that if we built + // curl statically (as told to us by the `curl-sys` crate) we define the + // correct values for curl's header files. + if env::var_os("DEP_CURL_STATIC").is_some() { + cfg.define("CURL_STATICLIB", None); + } + } + if let Some(path) = env::var_os("DEP_Z_INCLUDE") { + cfg.include(path); + } + + if target.contains("apple") { + features.push_str("#define GIT_USE_ICONV 1\n"); + } + + features.push_str("#endif\n"); + fs::write(include.join("git2/sys/features.h"), features).unwrap(); + + cfg.compile("git2"); + + println!("cargo:root={}", dst.display()); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=winhttp"); + println!("cargo:rustc-link-lib=rpcrt4"); + println!("cargo:rustc-link-lib=ole32"); + println!("cargo:rustc-link-lib=crypt32"); + return + } + + if target.contains("apple") { + println!("cargo:rustc-link-lib=iconv"); + println!("cargo:rustc-link-lib=framework=Security"); + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + } +} + +fn cp_r(from: &Path, to: &Path) { + for e in from.read_dir().unwrap() { + let e = e.unwrap(); + let from = e.path(); + let to = to.join(e.file_name()); + if e.file_type().unwrap().is_dir() { + fs::create_dir_all(&to).unwrap(); + cp_r(&from, &to); + } else { + println!("{} => {}", from.display(), to.display()); + fs::copy(&from, &to).unwrap(); + } + } +} + +fn add_c_files(build: &mut cc::Build, path: &Path) { + for e in path.read_dir().unwrap() { + let e = e.unwrap(); + let path = e.path(); + if e.file_type().unwrap().is_dir() { + // skip dirs for now + } else if path.extension().and_then(|s| s.to_str()) == Some("c") { + build.file(&path); + } + } +} diff --git a/libgit2-sys/Cargo.toml b/libgit2-sys/Cargo.toml new file mode 100644 index 000000000..9173e6547 --- /dev/null +++ b/libgit2-sys/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libgit2-sys" +version = "0.7.11" +authors = ["Alex Crichton "] +build = "build.rs" +links = "git2" +exclude = ["libgit2/tests/*"] +description = "Native bindings to the libgit2 library" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/git2-rs" + +[lib] +name = "libgit2_sys" +path = "lib.rs" +[dependencies.curl-sys] +version = "0.4.10" +optional = true + +[dependencies.libc] +version = "0.2" + +[dependencies.libssh2-sys] +version = "0.2.11" +optional = true + +[dependencies.libz-sys] +version = "1.0.22" +[build-dependencies.cc] +version = "1.0.25" + +[build-dependencies.pkg-config] +version = "0.3" + +[features] +curl = ["curl-sys"] +https = ["openssl-sys"] +ssh = ["libssh2-sys"] +ssh_key_from_memory = [] +[target."cfg(unix)".dependencies.openssl-sys] +version = "0.9" +optional = true diff --git a/libgit2-sys/LICENSE-APACHE b/libgit2-sys/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/libgit2-sys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libgit2-sys/LICENSE-MIT b/libgit2-sys/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/libgit2-sys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libgit2-sys/build.rs b/libgit2-sys/build.rs new file mode 100644 index 000000000..eea446cf1 --- /dev/null +++ b/libgit2-sys/build.rs @@ -0,0 +1,192 @@ +extern crate cc; +extern crate pkg_config; + +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn main() { + let https = env::var("CARGO_FEATURE_HTTPS").is_ok(); + let ssh = env::var("CARGO_FEATURE_SSH").is_ok(); + let curl = env::var("CARGO_FEATURE_CURL").is_ok(); + + if pkg_config::find_library("libgit2").is_ok() { + return + } + + if !Path::new("libgit2/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + let target = env::var("TARGET").unwrap(); + let windows = target.contains("windows"); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let include = dst.join("include"); + let mut cfg = cc::Build::new(); + fs::create_dir_all(&include).unwrap(); + + // Copy over all header files + cp_r("libgit2/include".as_ref(), &include); + + cfg.include(&include) + .include("libgit2/src") + .out_dir(dst.join("build")) + .warnings(false); + + // Include all cross-platform C files + add_c_files(&mut cfg, "libgit2/src".as_ref()); + add_c_files(&mut cfg, "libgit2/src/xdiff".as_ref()); + + // These are activated by feautres, but they're all unconditionally always + // compiled apparently and have internal #define's to make sure they're + // compiled correctly. + add_c_files(&mut cfg, "libgit2/src/transports".as_ref()); + add_c_files(&mut cfg, "libgit2/src/streams".as_ref()); + + // Always use bundled http-parser for now + cfg.include("libgit2/deps/http-parser") + .file("libgit2/deps/http-parser/http_parser.c"); + + // Always use bundled regex for now + cfg.include("libgit2/deps/regex") + .file("libgit2/deps/regex/regex.c"); + + if windows { + add_c_files(&mut cfg, "libgit2/src/win32".as_ref()); + cfg.define("STRSAFE_NO_DEPRECATE", None); + + // libgit2's build system claims that forks like mingw-w64 of MinGW + // still want this define to use C99 stdio functions automatically. + // Apparently libgit2 breaks at runtime if this isn't here? Who knows! + if target.contains("gnu") { + cfg.define("__USE_MINGW_ANSI_STDIO", "1"); + } + } else { + add_c_files(&mut cfg, "libgit2/src/unix".as_ref()); + cfg.flag("-fvisibility=hidden"); + } + if target.contains("solaris") { + cfg.define("_POSIX_C_SOURCE", "200112L"); + cfg.define("__EXTENSIONS__", None); + } + + let mut features = String::new(); + + features.push_str("#ifndef INCLUDE_features_h\n"); + features.push_str("#define INCLUDE_features_h\n"); + features.push_str("#define GIT_THREADS 1\n"); + + if !target.contains("android") { + features.push_str("#define GIT_USE_NSEC 1\n"); + } + + if target.contains("apple") { + features.push_str("#define GIT_USE_STAT_MTIMESPEC 1\n"); + } else { + features.push_str("#define GIT_USE_STAT_MTIM 1\n"); + } + + if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" { + features.push_str("#define GIT_ARCH_32 1\n"); + } else { + features.push_str("#define GIT_ARCH_64 1\n"); + } + + if ssh { + if let Some(path) = env::var_os("DEP_SSH2_INCLUDE") { + cfg.include(path); + } + features.push_str("#define GIT_SSH 1\n"); + features.push_str("#define GIT_SSH_MEMORY_CREDENTIALS 1\n"); + } + if https { + features.push_str("#define GIT_HTTPS 1\n"); + + if windows { + features.push_str("#define GIT_WINHTTP 1\n"); + features.push_str("#define GIT_SHA1_WIN32 1\n"); + cfg.file("libgit2/src/hash/hash_win32.c"); + } else if target.contains("apple") { + features.push_str("#define GIT_SECURE_TRANSPORT 1\n"); + features.push_str("#define GIT_SHA1_COMMON_CRYPTO 1\n"); + } else { + features.push_str("#define GIT_OPENSSL 1\n"); + features.push_str("#define GIT_SHA1_OPENSSL 1\n"); + if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { + cfg.include(path); + } + } + } else { + cfg.file("libgit2/src/hash/hash_generic.c"); + } + + if curl { + features.push_str("#define GIT_CURL 1\n"); + if let Some(path) = env::var_os("DEP_CURL_INCLUDE") { + cfg.include(path); + } + // Handle dllimport/dllexport on windows by making sure that if we built + // curl statically (as told to us by the `curl-sys` crate) we define the + // correct values for curl's header files. + if env::var_os("DEP_CURL_STATIC").is_some() { + cfg.define("CURL_STATICLIB", None); + } + } + if let Some(path) = env::var_os("DEP_Z_INCLUDE") { + cfg.include(path); + } + + if target.contains("apple") { + features.push_str("#define GIT_USE_ICONV 1\n"); + } + + features.push_str("#endif\n"); + fs::write(include.join("git2/sys/features.h"), features).unwrap(); + + cfg.compile("git2"); + + println!("cargo:root={}", dst.display()); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=winhttp"); + println!("cargo:rustc-link-lib=rpcrt4"); + println!("cargo:rustc-link-lib=ole32"); + println!("cargo:rustc-link-lib=crypt32"); + return + } + + if target.contains("apple") { + println!("cargo:rustc-link-lib=iconv"); + println!("cargo:rustc-link-lib=framework=Security"); + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + } +} + +fn cp_r(from: &Path, to: &Path) { + for e in from.read_dir().unwrap() { + let e = e.unwrap(); + let from = e.path(); + let to = to.join(e.file_name()); + if e.file_type().unwrap().is_dir() { + fs::create_dir_all(&to).unwrap(); + cp_r(&from, &to); + } else { + println!("{} => {}", from.display(), to.display()); + fs::copy(&from, &to).unwrap(); + } + } +} + +fn add_c_files(build: &mut cc::Build, path: &Path) { + for e in path.read_dir().unwrap() { + let e = e.unwrap(); + let path = e.path(); + if e.file_type().unwrap().is_dir() { + // skip dirs for now + } else if path.extension().and_then(|s| s.to_str()) == Some("c") { + build.file(&path); + } + } +} diff --git a/libgit2-sys/debian/patches/no-special-snowflake-env.patch b/libgit2-sys/debian/patches/no-special-snowflake-env.patch new file mode 100644 index 000000000..b532c09eb --- /dev/null +++ b/libgit2-sys/debian/patches/no-special-snowflake-env.patch @@ -0,0 +1,17 @@ +Index: libgit2-sys/build.rs +=================================================================== +--- libgit2-sys.orig/build.rs ++++ libgit2-sys/build.rs +@@ -11,10 +11,8 @@ fn main() { + let ssh = env::var("CARGO_FEATURE_SSH").is_ok(); + let curl = env::var("CARGO_FEATURE_CURL").is_ok(); + +- if env::var("LIBGIT2_SYS_USE_PKG_CONFIG").is_ok() { +- if pkg_config::find_library("libgit2").is_ok() { +- return +- } ++ if pkg_config::find_library("libgit2").is_ok() { ++ return + } + + if !Path::new("libgit2/.git").exists() { diff --git a/libgit2-sys/debian/patches/series b/libgit2-sys/debian/patches/series new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/libgit2-sys/debian/patches/series @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/libgit2-sys/lib.rs b/libgit2-sys/lib.rs new file mode 100644 index 000000000..7bede4e4b --- /dev/null +++ b/libgit2-sys/lib.rs @@ -0,0 +1,3052 @@ +#![doc(html_root_url = "http://alexcrichton.com/git2-rs")] +#![allow(non_camel_case_types, unused_extern_crates)] + +extern crate libc; +#[cfg(feature = "ssh")] +extern crate libssh2_sys as libssh2; +#[cfg(feature = "curl")] +extern crate curl_sys; +#[cfg(all(unix, feature = "https"))] +extern crate openssl_sys; +extern crate libz_sys as libz; + +use libc::{c_int, c_char, c_uint, size_t, c_uchar, c_void}; + +pub const GIT_OID_RAWSZ: usize = 20; +pub const GIT_OID_HEXSZ: usize = GIT_OID_RAWSZ * 2; +pub const GIT_CLONE_OPTIONS_VERSION: c_uint = 1; +pub const GIT_STASH_APPLY_OPTIONS_VERSION: c_uint = 1; +pub const GIT_CHECKOUT_OPTIONS_VERSION: c_uint = 1; +pub const GIT_MERGE_OPTIONS_VERSION: c_uint = 1; +pub const GIT_REMOTE_CALLBACKS_VERSION: c_uint = 1; +pub const GIT_STATUS_OPTIONS_VERSION: c_uint = 1; +pub const GIT_BLAME_OPTIONS_VERSION: c_uint = 1; +pub const GIT_PROXY_OPTIONS_VERSION: c_uint = 1; +pub const GIT_SUBMODULE_UPDATE_OPTIONS_VERSION: c_uint = 1; +pub const GIT_ODB_BACKEND_VERSION: c_uint = 1; +pub const GIT_REFDB_BACKEND_VERSION: c_uint = 1; + +macro_rules! git_enum { + (pub enum $name:ident { $($variants:tt)* }) => { + #[cfg(target_env = "msvc")] + pub type $name = i32; + #[cfg(not(target_env = "msvc"))] + pub type $name = u32; + git_enum!(gen, $name, 0, $($variants)*); + }; + (pub enum $name:ident: $t:ty { $($variants:tt)* }) => { + pub type $name = $t; + git_enum!(gen, $name, 0, $($variants)*); + }; + (gen, $name:ident, $val:expr, $variant:ident, $($rest:tt)*) => { + pub const $variant: $name = $val; + git_enum!(gen, $name, $val+1, $($rest)*); + }; + (gen, $name:ident, $val:expr, $variant:ident = $e:expr, $($rest:tt)*) => { + pub const $variant: $name = $e; + git_enum!(gen, $name, $e+1, $($rest)*); + }; + (gen, $name:ident, $val:expr, ) => {} +} + +pub enum git_blob {} +pub enum git_branch_iterator {} +pub enum git_blame {} +pub enum git_commit {} +pub enum git_config {} +pub enum git_config_iterator {} +pub enum git_index {} +pub enum git_object {} +pub enum git_reference {} +pub enum git_reference_iterator {} +pub enum git_annotated_commit {} +pub enum git_refdb {} +pub enum git_refspec {} +pub enum git_remote {} +pub enum git_repository {} +pub enum git_revwalk {} +pub enum git_submodule {} +pub enum git_tag {} +pub enum git_tree {} +pub enum git_tree_entry {} +pub enum git_treebuilder {} +pub enum git_push {} +pub enum git_note {} +pub enum git_note_iterator {} +pub enum git_status_list {} +pub enum git_pathspec {} +pub enum git_pathspec_match_list {} +pub enum git_diff {} +pub enum git_diff_stats {} +pub enum git_patch {} +pub enum git_rebase {} +pub enum git_reflog {} +pub enum git_reflog_entry {} +pub enum git_describe_result {} +pub enum git_packbuilder {} +pub enum git_odb {} +pub enum git_odb_stream {} +pub enum git_odb_object {} +pub enum git_odb_writepack {} +pub enum git_worktree {} + +#[repr(C)] +pub struct git_revspec { + pub from: *mut git_object, + pub to: *mut git_object, + pub flags: c_uint, +} + +#[repr(C)] +pub struct git_error { + pub message: *mut c_char, + pub klass: c_int, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_oid { + pub id: [u8; GIT_OID_RAWSZ], +} + +#[repr(C)] +#[derive(Copy)] +pub struct git_strarray { + pub strings: *mut *mut c_char, + pub count: size_t, +} +impl Clone for git_strarray { + fn clone(&self) -> git_strarray { *self } +} + +#[repr(C)] +#[derive(Copy)] +pub struct git_oidarray { + pub ids: *mut git_oid, + pub count: size_t, +} +impl Clone for git_oidarray { + fn clone(&self) -> git_oidarray { *self } +} + +#[repr(C)] +pub struct git_signature { + pub name: *mut c_char, + pub email: *mut c_char, + pub when: git_time, +} + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct git_time { + pub time: git_time_t, + pub offset: c_int, + pub sign: c_char, +} + +pub type git_off_t = i64; +pub type git_time_t = i64; + +git_enum! { + pub enum git_revparse_mode_t { + GIT_REVPARSE_SINGLE = 1 << 0, + GIT_REVPARSE_RANGE = 1 << 1, + GIT_REVPARSE_MERGE_BASE = 1 << 2, + } +} + +git_enum! { + pub enum git_error_code: c_int { + GIT_OK = 0, + + GIT_ERROR = -1, + GIT_ENOTFOUND = -3, + GIT_EEXISTS = -4, + GIT_EAMBIGUOUS = -5, + GIT_EBUFS = -6, + GIT_EUSER = -7, + GIT_EBAREREPO = -8, + GIT_EUNBORNBRANCH = -9, + GIT_EUNMERGED = -10, + GIT_ENONFASTFORWARD = -11, + GIT_EINVALIDSPEC = -12, + GIT_ECONFLICT = -13, + GIT_ELOCKED = -14, + GIT_EMODIFIED = -15, + GIT_EAUTH = -16, + GIT_ECERTIFICATE = -17, + GIT_EAPPLIED = -18, + GIT_EPEEL = -19, + GIT_EEOF = -20, + GIT_EINVALID = -21, + GIT_EUNCOMMITTED = -22, + GIT_EDIRECTORY = -23, + GIT_EMERGECONFLICT = -24, + GIT_PASSTHROUGH = -30, + GIT_ITEROVER = -31, + } +} + +git_enum! { + pub enum git_error_t { + GITERR_NONE = 0, + GITERR_NOMEMORY, + GITERR_OS, + GITERR_INVALID, + GITERR_REFERENCE, + GITERR_ZLIB, + GITERR_REPOSITORY, + GITERR_CONFIG, + GITERR_REGEX, + GITERR_ODB, + GITERR_INDEX, + GITERR_OBJECT, + GITERR_NET, + GITERR_TAG, + GITERR_TREE, + GITERR_INDEXER, + GITERR_SSL, + GITERR_SUBMODULE, + GITERR_THREAD, + GITERR_STASH, + GITERR_CHECKOUT, + GITERR_FETCHHEAD, + GITERR_MERGE, + GITERR_SSH, + GITERR_FILTER, + GITERR_REVERT, + GITERR_CALLBACK, + GITERR_CHERRYPICK, + GITERR_DESCRIBE, + GITERR_REBASE, + GITERR_FILESYSTEM, + } +} + +git_enum! { + pub enum git_repository_state_t { + GIT_REPOSITORY_STATE_NONE, + GIT_REPOSITORY_STATE_MERGE, + GIT_REPOSITORY_STATE_REVERT, + GIT_REPOSITORY_STATE_REVERT_SEQUENCE, + GIT_REPOSITORY_STATE_CHERRYPICK, + GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE, + GIT_REPOSITORY_STATE_BISECT, + GIT_REPOSITORY_STATE_REBASE, + GIT_REPOSITORY_STATE_REBASE_INTERACTIVE, + GIT_REPOSITORY_STATE_REBASE_MERGE, + GIT_REPOSITORY_STATE_APPLY_MAILBOX, + GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE, + } +} + +git_enum! { + pub enum git_direction { + GIT_DIRECTION_FETCH, + GIT_DIRECTION_PUSH, + } +} + +#[repr(C)] +pub struct git_clone_options { + pub version: c_uint, + pub checkout_opts: git_checkout_options, + pub fetch_opts: git_fetch_options, + pub bare: c_int, + pub local: git_clone_local_t, + pub checkout_branch: *const c_char, + pub repository_cb: Option, + pub repository_cb_payload: *mut c_void, + pub remote_cb: Option, + pub remote_cb_payload: *mut c_void, +} + +git_enum! { + pub enum git_clone_local_t { + GIT_CLONE_LOCAL_AUTO, + GIT_CLONE_LOCAL, + GIT_CLONE_NO_LOCAL, + GIT_CLONE_LOCAL_NO_LINKS, + } +} + +#[repr(C)] +pub struct git_checkout_options { + pub version: c_uint, + pub checkout_strategy: c_uint, + pub disable_filters: c_int, + pub dir_mode: c_uint, + pub file_mode: c_uint, + pub file_open_flags: c_int, + pub notify_flags: c_uint, + pub notify_cb: Option, + pub notify_payload: *mut c_void, + pub progress_cb: Option, + pub progress_payload: *mut c_void, + pub paths: git_strarray, + pub baseline: *mut git_tree, + pub baseline_index: *mut git_index, + pub target_directory: *const c_char, + pub ancestor_label: *const c_char, + pub our_label: *const c_char, + pub their_label: *const c_char, + pub perfdata_cb: Option, + pub perfdata_payload: *mut c_void, +} + +pub type git_checkout_notify_cb = extern fn(git_checkout_notify_t, + *const c_char, + *const git_diff_file, + *const git_diff_file, + *const git_diff_file, + *mut c_void) -> c_int; +pub type git_checkout_progress_cb = extern fn(*const c_char, + size_t, + size_t, + *mut c_void); + +pub type git_checkout_perfdata_cb = extern fn(*const git_checkout_perfdata, + *mut c_void); + +#[repr(C)] +pub struct git_checkout_perfdata { + pub mkdir_calls: size_t, + pub stat_calls: size_t, + pub chmod_calls: size_t, +} + +#[repr(C)] +pub struct git_remote_callbacks { + pub version: c_uint, + pub sideband_progress: Option, + pub completion: Option c_int>, + pub credentials: Option, + pub certificate_check: Option, + pub transfer_progress: Option, + pub update_tips: Option c_int>, + pub pack_progress: Option, + pub push_transfer_progress: Option, + pub push_update_reference: Option, + pub push_negotiation: Option, + pub transport: Option, + pub payload: *mut c_void, +} + +#[repr(C)] +pub struct git_fetch_options { + pub version: c_int, + pub callbacks: git_remote_callbacks, + pub prune: git_fetch_prune_t, + pub update_fetchhead: c_int, + pub download_tags: git_remote_autotag_option_t, + pub proxy_opts: git_proxy_options, + pub custom_headers: git_strarray, +} + +git_enum! { + pub enum git_remote_autotag_option_t { + GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, + GIT_REMOTE_DOWNLOAD_TAGS_AUTO, + GIT_REMOTE_DOWNLOAD_TAGS_NONE, + GIT_REMOTE_DOWNLOAD_TAGS_ALL, + } +} + +git_enum! { + pub enum git_fetch_prune_t { + GIT_FETCH_PRUNE_UNSPECIFIED, + GIT_FETCH_PRUNE, + GIT_FETCH_NO_PRUNE, + } +} + +git_enum! { + pub enum git_remote_completion_type { + GIT_REMOTE_COMPLETION_DOWNLOAD, + GIT_REMOTE_COMPLETION_INDEXING, + GIT_REMOTE_COMPLETION_ERROR, + } +} + +pub type git_transport_message_cb = extern fn(*const c_char, c_int, + *mut c_void) -> c_int; +pub type git_cred_acquire_cb = extern fn(*mut *mut git_cred, + *const c_char, *const c_char, + c_uint, *mut c_void) -> c_int; +pub type git_transfer_progress_cb = extern fn(*const git_transfer_progress, + *mut c_void) -> c_int; +pub type git_packbuilder_progress = extern fn(git_packbuilder_stage_t, c_uint, + c_uint, *mut c_void) -> c_int; +pub type git_push_transfer_progress = extern fn(c_uint, c_uint, size_t, + *mut c_void) -> c_int; +pub type git_transport_certificate_check_cb = extern fn(*mut git_cert, + c_int, + *const c_char, + *mut c_void) -> c_int; +pub type git_push_negotiation = extern fn(*mut *const git_push_update, + size_t, + *mut c_void) -> c_int; + +pub type git_push_update_reference_cb = extern fn(*const c_char, + *const c_char, + *mut c_void) -> c_int; + +#[repr(C)] +pub struct git_push_update { + pub src_refname: *mut c_char, + pub dst_refname: *mut c_char, + pub src: git_oid, + pub dst: git_oid, +} + +git_enum! { + pub enum git_cert_t { + GIT_CERT_NONE, + GIT_CERT_X509, + GIT_CERT_HOSTKEY_LIBSSH2, + } +} + +#[repr(C)] +pub struct git_cert { + pub cert_type: git_cert_t, +} + +#[repr(C)] +pub struct git_cert_hostkey { + pub parent: git_cert, + pub kind: git_cert_ssh_t, + pub hash_md5: [u8; 16], + pub hash_sha1: [u8; 20], +} + +#[repr(C)] +pub struct git_cert_x509 { + pub parent: git_cert, + pub data: *mut c_void, + pub len: size_t, +} + +git_enum! { + pub enum git_cert_ssh_t { + GIT_CERT_SSH_MD5 = 1 << 0, + GIT_CERT_SSH_SHA1 = 1 << 1, + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_transfer_progress { + pub total_objects: c_uint, + pub indexed_objects: c_uint, + pub received_objects: c_uint, + pub local_objects: c_uint, + pub total_deltas: c_uint, + pub indexed_deltas: c_uint, + pub received_bytes: size_t, +} + +#[repr(C)] +pub struct git_diff_file { + pub id: git_oid, + pub path: *const c_char, + pub size: git_off_t, + pub flags: u32, + pub mode: u16, +} + +pub type git_repository_create_cb = extern fn(*mut *mut git_repository, + *const c_char, + c_int, *mut c_void) -> c_int; +pub type git_remote_create_cb = extern fn(*mut *mut git_remote, + *mut git_repository, + *const c_char, + *const c_char, + *mut c_void) -> c_int; + +git_enum! { + pub enum git_checkout_notify_t { + GIT_CHECKOUT_NOTIFY_NONE = 0, + GIT_CHECKOUT_NOTIFY_CONFLICT = (1 << 0), + GIT_CHECKOUT_NOTIFY_DIRTY = (1 << 1), + GIT_CHECKOUT_NOTIFY_UPDATED = (1 << 2), + GIT_CHECKOUT_NOTIFY_UNTRACKED = (1 << 3), + GIT_CHECKOUT_NOTIFY_IGNORED = (1 << 4), + + GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFF, + } +} + +git_enum! { + pub enum git_status_t { + GIT_STATUS_CURRENT = 0, + + GIT_STATUS_INDEX_NEW = (1 << 0), + GIT_STATUS_INDEX_MODIFIED = (1 << 1), + GIT_STATUS_INDEX_DELETED = (1 << 2), + GIT_STATUS_INDEX_RENAMED = (1 << 3), + GIT_STATUS_INDEX_TYPECHANGE = (1 << 4), + + GIT_STATUS_WT_NEW = (1 << 7), + GIT_STATUS_WT_MODIFIED = (1 << 8), + GIT_STATUS_WT_DELETED = (1 << 9), + GIT_STATUS_WT_TYPECHANGE = (1 << 10), + GIT_STATUS_WT_RENAMED = (1 << 11), + GIT_STATUS_WT_UNREADABLE = (1 << 12), + + GIT_STATUS_IGNORED = (1 << 14), + GIT_STATUS_CONFLICTED = (1 << 15), + } +} + +git_enum! { + pub enum git_status_opt_t { + GIT_STATUS_OPT_INCLUDE_UNTRACKED = (1 << 0), + GIT_STATUS_OPT_INCLUDE_IGNORED = (1 << 1), + GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1 << 2), + GIT_STATUS_OPT_EXCLUDE_SUBMODULES = (1 << 3), + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1 << 4), + GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH = (1 << 5), + GIT_STATUS_OPT_RECURSE_IGNORED_DIRS = (1 << 6), + GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX = (1 << 7), + GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR = (1 << 8), + GIT_STATUS_OPT_SORT_CASE_SENSITIVELY = (1 << 9), + GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1 << 10), + + GIT_STATUS_OPT_RENAMES_FROM_REWRITES = (1 << 11), + GIT_STATUS_OPT_NO_REFRESH = (1 << 12), + GIT_STATUS_OPT_UPDATE_INDEX = (1 << 13), + GIT_STATUS_OPT_INCLUDE_UNREADABLE = (1 << 14), + GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED = (1 << 15), + } +} + +git_enum! { + pub enum git_status_show_t { + GIT_STATUS_SHOW_INDEX_AND_WORKDIR = 0, + GIT_STATUS_SHOW_INDEX_ONLY = 1, + GIT_STATUS_SHOW_WORKDIR_ONLY = 2, + } +} + +git_enum! { + pub enum git_delta_t { + GIT_DELTA_UNMODIFIED, + GIT_DELTA_ADDED, + GIT_DELTA_DELETED, + GIT_DELTA_MODIFIED, + GIT_DELTA_RENAMED, + GIT_DELTA_COPIED, + GIT_DELTA_IGNORED, + GIT_DELTA_UNTRACKED, + GIT_DELTA_TYPECHANGE, + GIT_DELTA_UNREADABLE, + GIT_DELTA_CONFLICTED, + } +} + +#[repr(C)] +pub struct git_status_options { + pub version: c_uint, + pub show: git_status_show_t, + pub flags: c_uint, + pub pathspec: git_strarray, + pub baseline: *mut git_tree, +} + +#[repr(C)] +pub struct git_diff_delta { + pub status: git_delta_t, + pub flags: u32, + pub similarity: u16, + pub nfiles: u16, + pub old_file: git_diff_file, + pub new_file: git_diff_file, +} + +#[repr(C)] +pub struct git_status_entry { + pub status: git_status_t, + pub head_to_index: *mut git_diff_delta, + pub index_to_workdir: *mut git_diff_delta +} + +git_enum! { + pub enum git_checkout_strategy_t { + GIT_CHECKOUT_NONE = 0, + GIT_CHECKOUT_SAFE = (1 << 0), + GIT_CHECKOUT_FORCE = (1 << 1), + GIT_CHECKOUT_RECREATE_MISSING = (1 << 2), + GIT_CHECKOUT_ALLOW_CONFLICTS = (1 << 4), + GIT_CHECKOUT_REMOVE_UNTRACKED = (1 << 5), + GIT_CHECKOUT_REMOVE_IGNORED = (1 << 6), + GIT_CHECKOUT_UPDATE_ONLY = (1 << 7), + GIT_CHECKOUT_DONT_UPDATE_INDEX = (1 << 8), + GIT_CHECKOUT_NO_REFRESH = (1 << 9), + GIT_CHECKOUT_SKIP_UNMERGED = (1 << 10), + GIT_CHECKOUT_USE_OURS = (1 << 11), + GIT_CHECKOUT_USE_THEIRS = (1 << 12), + GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1 << 13), + GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES = (1 << 18), + GIT_CHECKOUT_DONT_OVERWRITE_IGNORED = (1 << 19), + GIT_CHECKOUT_CONFLICT_STYLE_MERGE = (1 << 20), + GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 = (1 << 21), + + GIT_CHECKOUT_UPDATE_SUBMODULES = (1 << 16), + GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = (1 << 17), + } +} + +git_enum! { + pub enum git_reset_t { + GIT_RESET_SOFT = 1, + GIT_RESET_MIXED = 2, + GIT_RESET_HARD = 3, + } +} + +git_enum! { + pub enum git_otype: c_int { + GIT_OBJ_ANY = -2, + GIT_OBJ_BAD = -1, + GIT_OBJ__EXT1 = 0, + GIT_OBJ_COMMIT = 1, + GIT_OBJ_TREE = 2, + GIT_OBJ_BLOB = 3, + GIT_OBJ_TAG = 4, + GIT_OBJ__EXT2 = 5, + GIT_OBJ_OFS_DELTA = 6, + GIT_OBJ_REF_DELTA = 7, + } +} + +git_enum! { + pub enum git_ref_t { + GIT_REF_INVALID = 0, + GIT_REF_OID = 1, + GIT_REF_SYMBOLIC = 2, + GIT_REF_LISTALL = GIT_REF_OID | GIT_REF_SYMBOLIC, + } +} + +git_enum! { + pub enum git_filemode_t { + GIT_FILEMODE_UNREADABLE = 0o000000, + GIT_FILEMODE_TREE = 0o040000, + GIT_FILEMODE_BLOB = 0o100644, + GIT_FILEMODE_BLOB_EXECUTABLE = 0o100755, + GIT_FILEMODE_LINK = 0o120000, + GIT_FILEMODE_COMMIT = 0o160000, + } +} + +git_enum! { + pub enum git_treewalk_mode { + GIT_TREEWALK_PRE = 0, + GIT_TREEWALK_POST = 1, + } +} + +pub type git_treewalk_cb = extern fn(*const c_char, *const git_tree_entry, + *mut c_void) -> c_int; +pub type git_treebuilder_filter_cb = extern fn(*const git_tree_entry, + *mut c_void) -> c_int; + +pub type git_revwalk_hide_cb = extern fn(*const git_oid, *mut c_void) -> c_int; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_buf { + pub ptr: *mut c_char, + pub asize: size_t, + pub size: size_t, +} + +git_enum! { + pub enum git_branch_t { + GIT_BRANCH_LOCAL = 1, + GIT_BRANCH_REMOTE = 2, + GIT_BRANCH_ALL = GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, + } +} + +pub const GIT_BLAME_NORMAL: u32 = 0; +pub const GIT_BLAME_TRACK_COPIES_SAME_FILE: u32 = 1<<0; +pub const GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES: u32 = 1<<1; +pub const GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES: u32 = 1<<2; +pub const GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES: u32 = 1<<3; +pub const GIT_BLAME_FIRST_PARENT: u32 = 1<<4; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_blame_options { + pub version: c_uint, + + pub flags: u32, + pub min_match_characters: u16, + pub newest_commit: git_oid, + pub oldest_commit: git_oid, + pub min_line: usize, + pub max_line: usize, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_blame_hunk { + pub lines_in_hunk: usize, + pub final_commit_id: git_oid, + pub final_start_line_number: usize, + pub final_signature: *mut git_signature, + pub orig_commit_id: git_oid, + pub orig_path: *const c_char, + pub orig_start_line_number: usize, + pub orig_signature: *mut git_signature, + pub boundary: c_char, +} + +pub type git_index_matched_path_cb = extern fn(*const c_char, *const c_char, + *mut c_void) -> c_int; + +git_enum! { + pub enum git_idxentry_extended_flag_t { + GIT_IDXENTRY_INTENT_TO_ADD = 1 << 13, + GIT_IDXENTRY_SKIP_WORKTREE = 1 << 14, + GIT_IDXENTRY_EXTENDED2 = 1 << 15, + + GIT_IDXENTRY_UPDATE = 1 << 0, + GIT_IDXENTRY_REMOVE = 1 << 1, + GIT_IDXENTRY_UPTODATE = 1 << 2, + GIT_IDXENTRY_ADDED = 1 << 3, + + GIT_IDXENTRY_HASHED = 1 << 4, + GIT_IDXENTRY_UNHASHED = 1 << 5, + GIT_IDXENTRY_WT_REMOVE = 1 << 6, + GIT_IDXENTRY_CONFLICTED = 1 << 7, + + GIT_IDXENTRY_UNPACKED = 1 << 8, + GIT_IDXENTRY_NEW_SKIP_WORKTREE = 1 << 9, + } +} + +git_enum! { + pub enum git_indxentry_flag_t { + GIT_IDXENTRY_EXTENDED = 0x4000, + GIT_IDXENTRY_VALID = 0x8000, + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct git_index_entry { + pub ctime: git_index_time, + pub mtime: git_index_time, + pub dev: u32, + pub ino: u32, + pub mode: u32, + pub uid: u32, + pub gid: u32, + pub file_size: u32, + pub id: git_oid, + pub flags: u16, + pub flags_extended: u16, + pub path: *const c_char, +} + +pub const GIT_IDXENTRY_NAMEMASK: u16 = 0xfff; +pub const GIT_IDXENTRY_STAGEMASK: u16 = 0x3000; +pub const GIT_IDXENTRY_STAGESHIFT: u16 = 12; + +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct git_index_time { + pub seconds: i32, + pub nanoseconds: u32, +} + +#[repr(C)] +pub struct git_config_entry { + pub name: *const c_char, + pub value: *const c_char, + pub include_depth: c_uint, + pub level: git_config_level_t, + pub free: extern fn(*mut git_config_entry), + pub payload: *mut c_void, +} + +git_enum! { + pub enum git_config_level_t: c_int { + GIT_CONFIG_LEVEL_PROGRAMDATA = 1, + GIT_CONFIG_LEVEL_SYSTEM = 2, + GIT_CONFIG_LEVEL_XDG = 3, + GIT_CONFIG_LEVEL_GLOBAL = 4, + GIT_CONFIG_LEVEL_LOCAL = 5, + GIT_CONFIG_LEVEL_APP = 6, + GIT_CONFIG_HIGHEST_LEVEL = -1, + } +} + +git_enum! { + pub enum git_submodule_update_t { + GIT_SUBMODULE_UPDATE_CHECKOUT = 1, + GIT_SUBMODULE_UPDATE_REBASE = 2, + GIT_SUBMODULE_UPDATE_MERGE = 3, + GIT_SUBMODULE_UPDATE_NONE = 4, + GIT_SUBMODULE_UPDATE_DEFAULT = 0, + } +} + +git_enum! { + pub enum git_submodule_ignore_t: c_int { + GIT_SUBMODULE_IGNORE_UNSPECIFIED = -1, + + GIT_SUBMODULE_IGNORE_NONE = 1, + GIT_SUBMODULE_IGNORE_UNTRACKED = 2, + GIT_SUBMODULE_IGNORE_DIRTY = 3, + GIT_SUBMODULE_IGNORE_ALL = 4, + } +} + +pub type git_submodule_cb = extern fn(*mut git_submodule, + *const c_char, + *mut c_void) -> c_int; + +#[repr(C)] +pub struct git_submodule_update_options { + pub version: c_uint, + pub checkout_opts: git_checkout_options, + pub fetch_opts: git_fetch_options, + pub allow_fetch: c_int, +} + +#[repr(C)] +pub struct git_writestream { + pub write: extern fn(*mut git_writestream, + *const c_char, + size_t) -> c_int, + pub close: extern fn(*mut git_writestream) -> c_int, + pub free: extern fn(*mut git_writestream), +} + +#[repr(C)] +pub struct git_cred { + pub credtype: git_credtype_t, + pub free: extern fn(*mut git_cred), +} + +git_enum! { + pub enum git_credtype_t { + GIT_CREDTYPE_USERPASS_PLAINTEXT = 1 << 0, + GIT_CREDTYPE_SSH_KEY = 1 << 1, + GIT_CREDTYPE_SSH_CUSTOM = 1 << 2, + GIT_CREDTYPE_DEFAULT = 1 << 3, + GIT_CREDTYPE_SSH_INTERACTIVE = 1 << 4, + GIT_CREDTYPE_USERNAME = 1 << 5, + GIT_CREDTYPE_SSH_MEMORY = 1 << 6, + } +} + +pub type git_cred_ssh_interactive_callback = extern fn( + name: *const c_char, + name_len: c_int, + instruction: *const c_char, + instruction_len: c_int, + num_prompts: c_int, + prompts: *const LIBSSH2_USERAUTH_KBDINT_PROMPT, + responses: *mut LIBSSH2_USERAUTH_KBDINT_RESPONSE, + abstrakt: *mut *mut c_void +); + +pub type git_cred_sign_callback = extern fn( + session: *mut LIBSSH2_SESSION, + sig: *mut *mut c_uchar, + sig_len: *mut size_t, + data: *const c_uchar, + data_len: size_t, + abstrakt: *mut *mut c_void, +); + +pub enum LIBSSH2_SESSION {} +pub enum LIBSSH2_USERAUTH_KBDINT_PROMPT {} +pub enum LIBSSH2_USERAUTH_KBDINT_RESPONSE {} + +#[repr(C)] +pub struct git_push_options { + pub version: c_uint, + pub pb_parallelism: c_uint, + pub callbacks: git_remote_callbacks, + pub proxy_opts: git_proxy_options, + pub custom_headers: git_strarray, +} + +pub type git_tag_foreach_cb = extern fn(name: *const c_char, + oid: *mut git_oid, + payload: *mut c_void) -> c_int; + +git_enum! { + pub enum git_index_add_option_t { + GIT_INDEX_ADD_DEFAULT = 0, + GIT_INDEX_ADD_FORCE = 1 << 0, + GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH = 1 << 1, + GIT_INDEX_ADD_CHECK_PATHSPEC = 1 << 2, + } +} + +git_enum! { + pub enum git_repository_open_flag_t { + GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0), + GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1), + GIT_REPOSITORY_OPEN_BARE = (1 << 2), + GIT_REPOSITORY_OPEN_NO_DOTGIT = (1 << 3), + GIT_REPOSITORY_OPEN_FROM_ENV = (1 << 4), + } +} + +#[repr(C)] +pub struct git_repository_init_options { + pub version: c_uint, + pub flags: u32, + pub mode: u32, + pub workdir_path: *const c_char, + pub description: *const c_char, + pub template_path: *const c_char, + pub initial_head: *const c_char, + pub origin_url: *const c_char, +} + +pub const GIT_REPOSITORY_INIT_OPTIONS_VERSION: c_uint = 1; + +git_enum! { + pub enum git_repository_init_flag_t { + GIT_REPOSITORY_INIT_BARE = (1 << 0), + GIT_REPOSITORY_INIT_NO_REINIT = (1 << 1), + GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = (1 << 2), + GIT_REPOSITORY_INIT_MKDIR = (1 << 3), + GIT_REPOSITORY_INIT_MKPATH = (1 << 4), + GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = (1 << 5), + } +} + +git_enum! { + pub enum git_repository_init_mode_t { + GIT_REPOSITORY_INIT_SHARED_UMASK = 0, + GIT_REPOSITORY_INIT_SHARED_GROUP = 0o002775, + GIT_REPOSITORY_INIT_SHARED_ALL = 0o002777, + } +} + +git_enum! { + pub enum git_sort_t { + GIT_SORT_NONE = 0, + GIT_SORT_TOPOLOGICAL = (1 << 0), + GIT_SORT_TIME = (1 << 1), + GIT_SORT_REVERSE = (1 << 2), + } +} + +git_enum! { + pub enum git_submodule_status_t { + GIT_SUBMODULE_STATUS_IN_HEAD = 1 << 0, + GIT_SUBMODULE_STATUS_IN_INDEX = 1 << 1, + GIT_SUBMODULE_STATUS_IN_CONFIG = 1 << 2, + GIT_SUBMODULE_STATUS_IN_WD = 1 << 3, + GIT_SUBMODULE_STATUS_INDEX_ADDED = 1 << 4, + GIT_SUBMODULE_STATUS_INDEX_DELETED = 1 << 5, + GIT_SUBMODULE_STATUS_INDEX_MODIFIED = 1 << 6, + GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = 1 << 7, + GIT_SUBMODULE_STATUS_WD_ADDED = 1 << 8, + GIT_SUBMODULE_STATUS_WD_DELETED = 1 << 9, + GIT_SUBMODULE_STATUS_WD_MODIFIED = 1 << 10, + GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = 1 << 11, + GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = 1 << 12, + GIT_SUBMODULE_STATUS_WD_UNTRACKED = 1 << 13, + } +} + +#[repr(C)] +pub struct git_remote_head { + pub local: c_int, + pub oid: git_oid, + pub loid: git_oid, + pub name: *mut c_char, + pub symref_target: *mut c_char, +} + +git_enum! { + pub enum git_pathspec_flag_t { + GIT_PATHSPEC_DEFAULT = 0, + GIT_PATHSPEC_IGNORE_CASE = 1 << 0, + GIT_PATHSPEC_USE_CASE = 1 << 1, + GIT_PATHSPEC_NO_GLOB = 1 << 2, + GIT_PATHSPEC_NO_MATCH_ERROR = 1 << 3, + GIT_PATHSPEC_FIND_FAILURES = 1 << 4, + GIT_PATHSPEC_FAILURES_ONLY = 1 << 5, + } +} + +pub type git_diff_file_cb = extern fn(*const git_diff_delta, f32, *mut c_void) + -> c_int; +pub type git_diff_hunk_cb = extern fn(*const git_diff_delta, + *const git_diff_hunk, + *mut c_void) -> c_int; +pub type git_diff_line_cb = extern fn(*const git_diff_delta, + *const git_diff_hunk, + *const git_diff_line, + *mut c_void) -> c_int; +pub type git_diff_binary_cb = extern fn(*const git_diff_delta, + *const git_diff_binary, + *mut c_void) -> c_int; + +#[repr(C)] +pub struct git_diff_hunk { + pub old_start: c_int, + pub old_lines: c_int, + pub new_start: c_int, + pub new_lines: c_int, + pub header_len: size_t, + pub header: [c_char; 128], +} + +git_enum! { + pub enum git_diff_line_t { + GIT_DIFF_LINE_CONTEXT = b' ' as git_diff_line_t, + GIT_DIFF_LINE_ADDITION = b'+' as git_diff_line_t, + GIT_DIFF_LINE_DELETION = b'-' as git_diff_line_t, + GIT_DIFF_LINE_CONTEXT_EOFNL = b'=' as git_diff_line_t, + GIT_DIFF_LINE_ADD_EOFNL = b'>' as git_diff_line_t, + GIT_DIFF_LINE_DEL_EOFNL = b'<' as git_diff_line_t, + GIT_DIFF_LINE_FILE_HDR = b'F' as git_diff_line_t, + GIT_DIFF_LINE_HUNK_HDR = b'H' as git_diff_line_t, + GIT_DIFF_LINE_BINARY = b'B' as git_diff_line_t, + } +} + +#[repr(C)] +pub struct git_diff_line { + pub origin: c_char, + pub old_lineno: c_int, + pub new_lineno: c_int, + pub num_lines: c_int, + pub content_len: size_t, + pub content_offset: git_off_t, + pub content: *const c_char, +} + +#[repr(C)] +pub struct git_diff_options { + pub version: c_uint, + pub flags: u32, + pub ignore_submodules: git_submodule_ignore_t, + pub pathspec: git_strarray, + pub notify_cb: git_diff_notify_cb, + pub progress_cb: git_diff_progress_cb, + pub payload: *mut c_void, + pub context_lines: u32, + pub interhunk_lines: u32, + pub id_abbrev: u16, + pub max_size: git_off_t, + pub old_prefix: *const c_char, + pub new_prefix: *const c_char, +} + +git_enum! { + pub enum git_diff_format_t { + GIT_DIFF_FORMAT_PATCH = 1, + GIT_DIFF_FORMAT_PATCH_HEADER = 2, + GIT_DIFF_FORMAT_RAW = 3, + GIT_DIFF_FORMAT_NAME_ONLY = 4, + GIT_DIFF_FORMAT_NAME_STATUS = 5, + } +} + +git_enum! { + pub enum git_diff_stats_format_t { + GIT_DIFF_STATS_NONE = 0, + GIT_DIFF_STATS_FULL = 1 << 0, + GIT_DIFF_STATS_SHORT = 1 << 1, + GIT_DIFF_STATS_NUMBER = 1 << 2, + GIT_DIFF_STATS_INCLUDE_SUMMARY = 1 << 3, + } +} + +pub type git_diff_notify_cb = extern fn(*const git_diff, + *const git_diff_delta, + *const c_char, + *mut c_void) -> c_int; + +pub type git_diff_progress_cb = extern fn (*const git_diff, + *const c_char, + *const c_char, + *mut c_void) -> c_int; + +pub type git_diff_option_t = i32; +pub const GIT_DIFF_NORMAL: git_diff_option_t = 0; +pub const GIT_DIFF_REVERSE: git_diff_option_t = 1 << 0; +pub const GIT_DIFF_INCLUDE_IGNORED: git_diff_option_t = 1 << 1; +pub const GIT_DIFF_RECURSE_IGNORED_DIRS: git_diff_option_t = 1 << 2; +pub const GIT_DIFF_INCLUDE_UNTRACKED: git_diff_option_t = 1 << 3; +pub const GIT_DIFF_RECURSE_UNTRACKED_DIRS: git_diff_option_t = 1 << 4; +pub const GIT_DIFF_INCLUDE_UNMODIFIED: git_diff_option_t = 1 << 5; +pub const GIT_DIFF_INCLUDE_TYPECHANGE: git_diff_option_t = 1 << 6; +pub const GIT_DIFF_INCLUDE_TYPECHANGE_TREES: git_diff_option_t = 1 << 7; +pub const GIT_DIFF_IGNORE_FILEMODE: git_diff_option_t = 1 << 8; +pub const GIT_DIFF_IGNORE_SUBMODULES: git_diff_option_t = 1 << 9; +pub const GIT_DIFF_IGNORE_CASE: git_diff_option_t = 1 << 10; +pub const GIT_DIFF_DISABLE_PATHSPEC_MATCH: git_diff_option_t = 1 << 12; +pub const GIT_DIFF_SKIP_BINARY_CHECK: git_diff_option_t = 1 << 13; +pub const GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS: git_diff_option_t = 1 << 14; +pub const GIT_DIFF_UPDATE_INDEX: git_diff_option_t = 1 << 15; +pub const GIT_DIFF_INCLUDE_UNREADABLE: git_diff_option_t = 1 << 16; +pub const GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED: git_diff_option_t = 1 << 17; +pub const GIT_DIFF_FORCE_TEXT: git_diff_option_t = 1 << 20; +pub const GIT_DIFF_FORCE_BINARY: git_diff_option_t = 1 << 21; +pub const GIT_DIFF_IGNORE_WHITESPACE: git_diff_option_t = 1 << 22; +pub const GIT_DIFF_IGNORE_WHITESPACE_CHANGE: git_diff_option_t = 1 << 23; +pub const GIT_DIFF_IGNORE_WHITESPACE_EOL: git_diff_option_t = 1 << 24; +pub const GIT_DIFF_SHOW_UNTRACKED_CONTENT: git_diff_option_t = 1 << 25; +pub const GIT_DIFF_SHOW_UNMODIFIED: git_diff_option_t = 1 << 26; +pub const GIT_DIFF_PATIENCE: git_diff_option_t = 1 << 28; +pub const GIT_DIFF_MINIMAL: git_diff_option_t = 1 << 29; +pub const GIT_DIFF_SHOW_BINARY: git_diff_option_t = 1 << 30; +pub const GIT_DIFF_INDENT_HEURISTIC: git_diff_option_t = 1 << 31; + +#[repr(C)] +pub struct git_diff_find_options { + pub version: c_uint, + pub flags: u32, + pub rename_threshold: u16, + pub rename_from_rewrite_threshold: u16, + pub copy_threshold: u16, + pub break_rewrite_threshold: u16, + pub rename_limit: size_t, + pub metric: *mut git_diff_similarity_metric, +} + +#[repr(C)] +pub struct git_diff_similarity_metric { + pub file_signature: extern fn(*mut *mut c_void, + *const git_diff_file, + *const c_char, + *mut c_void) -> c_int, + pub buffer_signature: extern fn(*mut *mut c_void, + *const git_diff_file, + *const c_char, + size_t, + *mut c_void) -> c_int, + pub free_signature: extern fn(*mut c_void, *mut c_void), + pub similarity: extern fn(*mut c_int, *mut c_void, *mut c_void, + *mut c_void) -> c_int, + pub payload: *mut c_void, +} + +pub const GIT_DIFF_FIND_OPTIONS_VERSION: c_uint = 1; + +pub const GIT_DIFF_FIND_BY_CONFIG: u32 = 0; +pub const GIT_DIFF_FIND_RENAMES: u32 = 1 << 0; +pub const GIT_DIFF_FIND_RENAMES_FROM_REWRITES: u32 = 1 << 1; +pub const GIT_DIFF_FIND_COPIES: u32 = 1 << 2; +pub const GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED: u32 = 1 << 3; +pub const GIT_DIFF_FIND_REWRITES: u32 = 1 << 4; +pub const GIT_DIFF_BREAK_REWRITES: u32 = 1 << 5; +pub const GIT_DIFF_FIND_AND_BREAK_REWRITES: u32 = + GIT_DIFF_FIND_REWRITES | GIT_DIFF_BREAK_REWRITES; +pub const GIT_DIFF_FIND_FOR_UNTRACKED: u32 = 1 << 6; +pub const GIT_DIFF_FIND_ALL: u32 = 0x0ff; +pub const GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE: u32 = 0; +pub const GIT_DIFF_FIND_IGNORE_WHITESPACE: u32 = 1 << 12; +pub const GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE: u32 = 1 << 13; +pub const GIT_DIFF_FIND_EXACT_MATCH_ONLY: u32 = 1 << 14; +pub const GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY : u32 = 1 << 15; +pub const GIT_DIFF_FIND_REMOVE_UNMODIFIED: u32 = 1 << 16; + +#[repr(C)] +pub struct git_diff_binary { + pub contains_data: c_uint, + pub old_file: git_diff_binary_file, + pub new_file: git_diff_binary_file, +} + +#[repr(C)] +pub struct git_diff_binary_file { + pub kind: git_diff_binary_t, + pub data: *const c_char, + pub datalen: size_t, + pub inflatedlen: size_t, +} + +git_enum! { + pub enum git_diff_binary_t { + GIT_DIFF_BINARY_NONE, + GIT_DIFF_BINARY_LITERAL, + GIT_DIFF_BINARY_DELTA, + } +} + +#[repr(C)] +pub struct git_merge_options { + pub version: c_uint, + pub flags: git_merge_flag_t, + pub rename_threshold: c_uint, + pub target_limit: c_uint, + pub metric: *mut git_diff_similarity_metric, + pub recursion_limit: c_uint, + pub default_driver: *const c_char, + pub file_favor: git_merge_file_favor_t, + pub file_flags: git_merge_file_flag_t, +} + +git_enum! { + pub enum git_merge_flag_t { + GIT_MERGE_FIND_RENAMES = 1 << 0, + GIT_MERGE_FAIL_ON_CONFLICT = 1 << 1, + GIT_MERGE_SKIP_REUC = 1 << 2, + GIT_MERGE_NO_RECURSIVE = 1 << 3, + } +} + +git_enum! { + pub enum git_merge_file_favor_t { + GIT_MERGE_FILE_FAVOR_NORMAL = 0, + GIT_MERGE_FILE_FAVOR_OURS = 1, + GIT_MERGE_FILE_FAVOR_THEIRS = 2, + GIT_MERGE_FILE_FAVOR_UNION = 3, + } +} + +git_enum! { + pub enum git_merge_file_flag_t { + GIT_MERGE_FILE_DEFAULT = 0, + GIT_MERGE_FILE_STYLE_MERGE = (1 << 0), + GIT_MERGE_FILE_STYLE_DIFF3 = (1 << 1), + GIT_MERGE_FILE_SIMPLIFY_ALNUM = (1 << 2), + GIT_MERGE_FILE_IGNORE_WHITESPACE = (1 << 3), + GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE = (1 << 4), + GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL = (1 << 5), + GIT_MERGE_FILE_DIFF_PATIENCE = (1 << 6), + GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7), + } +} + +git_enum! { + pub enum git_merge_analysis_t { + GIT_MERGE_ANALYSIS_NONE = 0, + GIT_MERGE_ANALYSIS_NORMAL = (1 << 0), + GIT_MERGE_ANALYSIS_UP_TO_DATE = (1 << 1), + GIT_MERGE_ANALYSIS_FASTFORWARD = (1 << 2), + GIT_MERGE_ANALYSIS_UNBORN = (1 << 3), + } +} + +git_enum! { + pub enum git_merge_preference_t { + GIT_MERGE_PREFERENCE_NONE = 0, + GIT_MERGE_PREFERENCE_NO_FASTFORWARD = (1 << 0), + GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY = (1 << 1), + } +} + +pub type git_transport_cb = extern fn(out: *mut *mut git_transport, + owner: *mut git_remote, + param: *mut c_void) -> c_int; + +#[repr(C)] +pub struct git_transport { + pub version: c_uint, + pub set_callbacks: extern fn(*mut git_transport, + git_transport_message_cb, + git_transport_message_cb, + git_transport_certificate_check_cb, + *mut c_void) -> c_int, + pub set_custom_headers: extern fn(*mut git_transport, + *const git_strarray) -> c_int, + pub connect: extern fn(*mut git_transport, + *const c_char, + git_cred_acquire_cb, + *mut c_void, + *const git_proxy_options, + c_int, c_int) -> c_int, + pub ls: extern fn(*mut *mut *const git_remote_head, + *mut size_t, + *mut git_transport) -> c_int, + pub push: extern fn(*mut git_transport, + *mut git_push, + *const git_remote_callbacks) -> c_int, + pub negotiate_fetch: extern fn(*mut git_transport, + *mut git_repository, + *const *const git_remote_head, + size_t) -> c_int, + pub download_pack: extern fn(*mut git_transport, + *mut git_repository, + *mut git_transfer_progress, + git_transfer_progress_cb, + *mut c_void) -> c_int, + pub is_connected: extern fn(*mut git_transport) -> c_int, + pub read_flags: extern fn(*mut git_transport, *mut c_int) -> c_int, + pub cancel: extern fn(*mut git_transport), + pub close: extern fn(*mut git_transport) -> c_int, + pub free: extern fn(*mut git_transport), +} + +#[repr(C)] +pub struct git_odb_backend { + pub version: c_uint, + pub odb: *mut git_odb, + pub read: extern fn(*mut *mut c_void, + *mut size_t, + *mut git_otype, + *mut git_odb_backend, + *const git_oid) -> c_int, + + pub read_prefix: extern fn(*mut git_oid, + *mut *mut c_void, + *mut size_t, + *mut git_otype, + *mut git_odb_backend, + *const git_oid, + size_t) -> c_int, + pub read_header: extern fn(*mut size_t, + *mut git_otype, + *mut git_odb_backend, + *const git_oid) -> c_int, + + pub write: extern fn(*mut git_odb_backend, + *const git_oid, + *const c_void, + size_t, + git_otype) -> c_int, + + pub writestream: extern fn(*mut *mut git_odb_stream, + *mut git_odb_backend, + git_off_t, + git_otype) -> c_int, + + pub readstream: extern fn(*mut *mut git_odb_stream, + *mut size_t, + *mut git_otype, + *mut git_odb_backend, + *const git_oid) -> c_int, + + pub exists: extern fn(*mut git_odb_backend, + *const git_oid) -> c_int, + + pub exists_prefix: extern fn(*mut git_oid, + *mut git_odb_backend, + *const git_oid, + size_t) -> c_int, + + pub refresh: extern fn(*mut git_odb_backend) -> c_int, + + pub foreach: extern fn(*mut git_odb_backend, + git_odb_foreach_cb, + *mut c_void) -> c_int, + + pub writepack: extern fn(*mut *mut git_odb_writepack, + *mut git_odb_backend, + *mut git_odb, + git_transfer_progress_cb, + *mut c_void) -> c_int, + + pub freshen: extern fn(*mut git_odb_backend, + *const git_oid) -> c_int, + + pub free: extern fn(*mut git_odb_backend), +} + +#[repr(C)] +pub struct git_refdb_backend { + pub version: c_uint, + pub exists: extern fn(*mut c_int, + *mut git_refdb_backend, + *const c_char) -> c_int, + pub lookup: extern fn(*mut *mut git_reference, + *mut git_refdb_backend, + *const c_char) -> c_int, + pub iterator: extern fn(*mut *mut git_reference_iterator, + *mut git_refdb_backend, + *const c_char) -> c_int, + pub write: extern fn(*mut git_refdb_backend, + *const git_reference, + c_int, + *const git_signature, + *const c_char, + *const git_oid, + *const c_char) -> c_int, + pub rename: extern fn(*mut *mut git_reference, + *mut git_refdb_backend, + *const c_char, + *const c_char, + c_int, + *const git_signature, + *const c_char) -> c_int, + pub del: extern fn(*mut git_refdb_backend, + *const c_char, + *const git_oid, + *const c_char) -> c_int, + pub compress: extern fn(*mut git_refdb_backend) -> c_int, + pub has_log: extern fn(*mut git_refdb_backend, + *const c_char) -> c_int, + pub ensure_log: extern fn(*mut git_refdb_backend, + *const c_char) -> c_int, + pub free: extern fn(*mut git_refdb_backend), + pub reflog_read: extern fn(*mut *mut git_reflog, + *mut git_refdb_backend, + *const c_char) -> c_int, + pub reflog_write: extern fn(*mut git_refdb_backend, + *mut git_reflog) -> c_int, + pub reflog_rename: extern fn(*mut git_refdb_backend, + *const c_char, + *const c_char) -> c_int, + pub reflog_delete: extern fn(*mut git_refdb_backend, + *const c_char) -> c_int, + pub lock: extern fn(*mut *mut c_void, + *mut git_refdb_backend, + *const c_char) -> c_int, + pub unlock: extern fn(*mut git_refdb_backend, + *mut c_void, + c_int, + c_int, + *const git_reference, + *const git_signature, + *const c_char) -> c_int +} + +#[repr(C)] +pub struct git_proxy_options { + pub version: c_uint, + pub kind: git_proxy_t, + pub url: *const c_char, + pub credentials: Option, + pub certificate_check: Option, + pub payload: *mut c_void, +} + +git_enum! { + pub enum git_proxy_t { + GIT_PROXY_NONE = 0, + GIT_PROXY_AUTO = 1, + GIT_PROXY_SPECIFIED = 2, + } +} + +git_enum! { + pub enum git_smart_service_t { + GIT_SERVICE_UPLOADPACK_LS = 1, + GIT_SERVICE_UPLOADPACK = 2, + GIT_SERVICE_RECEIVEPACK_LS = 3, + GIT_SERVICE_RECEIVEPACK = 4, + } +} + +#[repr(C)] +pub struct git_smart_subtransport_stream { + pub subtransport: *mut git_smart_subtransport, + pub read: extern fn(*mut git_smart_subtransport_stream, + *mut c_char, + size_t, + *mut size_t) -> c_int, + pub write: extern fn(*mut git_smart_subtransport_stream, + *const c_char, + size_t) -> c_int, + pub free: extern fn(*mut git_smart_subtransport_stream), +} + +#[repr(C)] +pub struct git_smart_subtransport { + pub action: extern fn(*mut *mut git_smart_subtransport_stream, + *mut git_smart_subtransport, + *const c_char, + git_smart_service_t) -> c_int, + pub close: extern fn(*mut git_smart_subtransport) -> c_int, + pub free: extern fn(*mut git_smart_subtransport), +} + +pub type git_smart_subtransport_cb = extern fn(*mut *mut git_smart_subtransport, + *mut git_transport, + *mut c_void) -> c_int; + +#[repr(C)] +pub struct git_smart_subtransport_definition { + pub callback: git_smart_subtransport_cb, + pub rpc: c_uint, + pub param: *mut c_void, +} + +#[repr(C)] +pub struct git_describe_options { + pub version: c_uint, + pub max_candidates_tags: c_uint, + pub describe_strategy: c_uint, + pub pattern: *const c_char, + pub only_follow_first_parent: c_int, + pub show_commit_oid_as_fallback: c_int, +} + +git_enum! { + pub enum git_describe_strategy_t { + GIT_DESCRIBE_DEFAULT, + GIT_DESCRIBE_TAGS, + GIT_DESCRIBE_ALL, + } +} + +#[repr(C)] +pub struct git_describe_format_options { + pub version: c_uint, + pub abbreviated_size: c_uint, + pub always_use_long_format: c_int, + pub dirty_suffix: *const c_char, +} + +git_enum! { + pub enum git_packbuilder_stage_t { + GIT_PACKBUILDER_ADDING_OBJECTS, + GIT_PACKBUILDER_DELTAFICATION, + } +} + +git_enum! { + pub enum git_stash_flags { + GIT_STASH_DEFAULT = 0, + GIT_STASH_KEEP_INDEX = 1 << 0, + GIT_STASH_INCLUDE_UNTRACKED = 1 << 1, + GIT_STASH_INCLUDE_IGNORED = 1 << 2, + } +} + +git_enum! { + pub enum git_stash_apply_flags { + GIT_STASH_APPLY_DEFAULT = 0, + GIT_STASH_APPLY_REINSTATE_INDEX = 1 << 0, + } +} + +git_enum! { + pub enum git_stash_apply_progress_t { + GIT_STASH_APPLY_PROGRESS_NONE = 0, + GIT_STASH_APPLY_PROGRESS_LOADING_STASH, + GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX, + GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED, + GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED, + GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED, + GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED, + GIT_STASH_APPLY_PROGRESS_DONE, + } +} + +#[repr(C)] +pub struct git_stash_apply_options { + pub version: c_uint, + pub flags: git_stash_apply_flags, + pub checkout_options: git_checkout_options, + pub progress_cb: git_stash_apply_progress_cb, + pub progress_payload: *mut c_void, +} + +pub type git_stash_apply_progress_cb = extern fn(progress: git_stash_apply_progress_t, + payload: *mut c_void) -> c_int; + +pub type git_stash_cb = extern fn(index: size_t, + message: *const c_char, + stash_id: *const git_oid, + payload: *mut c_void) -> c_int; + +pub type git_packbuilder_foreach_cb = extern fn(*const c_void, size_t, + *mut c_void) -> c_int; + +pub type git_odb_foreach_cb = extern fn(id: *const git_oid, payload: *mut c_void) -> c_int; + +pub const GIT_REBASE_NO_OPERATION: usize = usize::max_value(); + +#[repr(C)] +pub struct git_rebase_options { + pub version: c_uint, + pub quiet: c_int, + pub inmemory: c_int, + pub rewrite_notes_ref: *const c_char, + pub merge_options: git_merge_options, + pub checkout_options: git_checkout_options, +} + +git_enum! { + pub enum git_rebase_operation_t { + GIT_REBASE_OPERATION_PICK = 0, + GIT_REBASE_OPERATION_REWORD, + GIT_REBASE_OPERATION_EDIT, + GIT_REBASE_OPERATION_SQUASH, + GIT_REBASE_OPERATION_FIXUP, + GIT_REBASE_OPERATION_EXEC, + } +} + +#[repr(C)] +pub struct git_rebase_operation { + pub kind: git_rebase_operation_t, + pub id: git_oid, + pub exec: *const c_char, +} + +extern { + // threads + pub fn git_libgit2_init() -> c_int; + pub fn git_libgit2_shutdown() -> c_int; + + // repository + pub fn git_repository_new(out: *mut *mut git_repository) -> c_int; + pub fn git_repository_free(repo: *mut git_repository); + pub fn git_repository_open(repo: *mut *mut git_repository, + path: *const c_char) -> c_int; + pub fn git_repository_open_bare(repo: *mut *mut git_repository, + path: *const c_char) -> c_int; + pub fn git_repository_open_ext(repo: *mut *mut git_repository, + path: *const c_char, + flags: c_uint, + ceiling_dirs: *const c_char) -> c_int; + pub fn git_repository_open_from_worktree(repo: *mut *mut git_repository, + worktree: *mut git_worktree) -> c_int; + pub fn git_repository_wrap_odb(repo: *mut *mut git_repository, + odb: *mut git_odb) -> c_int; + pub fn git_repository_init(repo: *mut *mut git_repository, + path: *const c_char, + is_bare: c_uint) -> c_int; + pub fn git_repository_init_ext(out: *mut *mut git_repository, + repo_path: *const c_char, + opts: *mut git_repository_init_options) + -> c_int; + pub fn git_repository_init_init_options(opts: *mut git_repository_init_options, + version: c_uint) -> c_int; + pub fn git_repository_get_namespace(repo: *mut git_repository) + -> *const c_char; + pub fn git_repository_set_namespace(repo: *mut git_repository, + namespace: *const c_char) -> c_int; + pub fn git_repository_head(out: *mut *mut git_reference, + repo: *mut git_repository) -> c_int; + pub fn git_repository_set_head(repo: *mut git_repository, + refname: *const c_char) -> c_int; + + pub fn git_repository_head_detached(repo: *mut git_repository) -> c_int; + pub fn git_repository_set_head_detached(repo: *mut git_repository, + commitish: *const git_oid) -> c_int; + pub fn git_repository_set_bare(repo: *mut git_repository) -> c_int; + pub fn git_repository_is_worktree(repo: *const git_repository) -> c_int; + pub fn git_repository_is_bare(repo: *const git_repository) -> c_int; + pub fn git_repository_is_empty(repo: *mut git_repository) -> c_int; + pub fn git_repository_is_shallow(repo: *mut git_repository) -> c_int; + pub fn git_repository_path(repo: *const git_repository) -> *const c_char; + pub fn git_repository_state(repo: *mut git_repository) -> c_int; + pub fn git_repository_workdir(repo: *const git_repository) -> *const c_char; + pub fn git_repository_set_workdir(repo: *mut git_repository, + workdir: *const c_char, + update_gitlink: c_int) -> c_int; + pub fn git_repository_index(out: *mut *mut git_index, + repo: *mut git_repository) -> c_int; + pub fn git_repository_set_index(repo: *mut git_repository, + index: *mut git_index); + + pub fn git_repository_message(buf: *mut git_buf, + repo: *mut git_repository) -> c_int; + + pub fn git_repository_message_remove(repo: *mut git_repository) -> c_int; + pub fn git_repository_config(out: *mut *mut git_config, + repo: *mut git_repository) -> c_int; + pub fn git_repository_set_config(repo: *mut git_repository, + config: *mut git_config); + pub fn git_repository_config_snapshot(out: *mut *mut git_config, + repo: *mut git_repository) -> c_int; + pub fn git_repository_discover(out: *mut git_buf, + start_path: *const c_char, + across_fs: c_int, + ceiling_dirs: *const c_char) -> c_int; + pub fn git_repository_set_odb(repo: *mut git_repository, + odb: *mut git_odb); + + pub fn git_repository_refdb(out: *mut *mut git_refdb, + repo: *mut git_repository) -> c_int; + pub fn git_repository_set_refdb(repo: *mut git_repository, + refdb: *mut git_refdb); + + pub fn git_repository_reinit_filesystem(repo: *mut git_repository, + recurse_submodules: c_int) -> c_int; + pub fn git_ignore_add_rule(repo: *mut git_repository, + rules: *const c_char) -> c_int; + pub fn git_ignore_clear_internal_rules(repo: *mut git_repository) -> c_int; + pub fn git_ignore_path_is_ignored(ignored: *mut c_int, + repo: *mut git_repository, + path: *const c_char) -> c_int; + + // revparse + pub fn git_revparse(revspec: *mut git_revspec, + repo: *mut git_repository, + spec: *const c_char) -> c_int; + pub fn git_revparse_single(out: *mut *mut git_object, + repo: *mut git_repository, + spec: *const c_char) -> c_int; + pub fn git_revparse_ext(object_out: *mut *mut git_object, + reference_out: *mut *mut git_reference, + repo: *mut git_repository, + spec: *const c_char) -> c_int; + + // object + pub fn git_object_dup(dest: *mut *mut git_object, + source: *mut git_object) -> c_int; + pub fn git_object_id(obj: *const git_object) -> *const git_oid; + pub fn git_object_free(object: *mut git_object); + pub fn git_object_lookup(dest: *mut *mut git_object, + repo: *mut git_repository, + id: *const git_oid, + kind: git_otype) -> c_int; + pub fn git_object_type(obj: *const git_object) -> git_otype; + pub fn git_object_peel(peeled: *mut *mut git_object, + object: *const git_object, + target_type: git_otype) -> c_int; + pub fn git_object_short_id(out: *mut git_buf, + obj: *const git_object) -> c_int; + pub fn git_object_type2string(kind: git_otype) -> *const c_char; + pub fn git_object_string2type(s: *const c_char) -> git_otype; + pub fn git_object_typeisloose(kind: git_otype) -> c_int; + + // oid + pub fn git_oid_fromraw(out: *mut git_oid, raw: *const c_uchar); + pub fn git_oid_fromstrn(out: *mut git_oid, str: *const c_char, + len: size_t) -> c_int; + pub fn git_oid_tostr(out: *mut c_char, n: size_t, + id: *const git_oid) -> *mut c_char; + pub fn git_oid_cmp(a: *const git_oid, b: *const git_oid) -> c_int; + pub fn git_oid_equal(a: *const git_oid, b: *const git_oid) -> c_int; + pub fn git_oid_streq(id: *const git_oid, str: *const c_char) -> c_int; + pub fn git_oid_iszero(id: *const git_oid) -> c_int; + + // giterr + pub fn giterr_last() -> *const git_error; + pub fn giterr_clear(); + pub fn giterr_set_str(error_class: c_int, string: *const c_char); + + // remote + pub fn git_remote_create(out: *mut *mut git_remote, + repo: *mut git_repository, + name: *const c_char, + url: *const c_char) -> c_int; + pub fn git_remote_lookup(out: *mut *mut git_remote, + repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_remote_create_anonymous(out: *mut *mut git_remote, + repo: *mut git_repository, + url: *const c_char) -> c_int; + pub fn git_remote_delete(repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_remote_free(remote: *mut git_remote); + pub fn git_remote_name(remote: *const git_remote) -> *const c_char; + pub fn git_remote_pushurl(remote: *const git_remote) -> *const c_char; + pub fn git_remote_refspec_count(remote: *const git_remote) -> size_t; + pub fn git_remote_url(remote: *const git_remote) -> *const c_char; + pub fn git_remote_connect(remote: *mut git_remote, + dir: git_direction, + callbacks: *const git_remote_callbacks, + proxy_opts: *const git_proxy_options, + custom_headers: *const git_strarray) -> c_int; + pub fn git_remote_connected(remote: *const git_remote) -> c_int; + pub fn git_remote_disconnect(remote: *mut git_remote); + pub fn git_remote_add_fetch(repo: *mut git_repository, + remote: *const c_char, + refspec: *const c_char) -> c_int; + pub fn git_remote_add_push(repo: *mut git_repository, + remote: *const c_char, + refspec: *const c_char) -> c_int; + pub fn git_remote_download(remote: *mut git_remote, + refspecs: *const git_strarray, + opts: *const git_fetch_options) -> c_int; + pub fn git_remote_stop(remote: *mut git_remote); + pub fn git_remote_dup(dest: *mut *mut git_remote, + source: *mut git_remote) -> c_int; + pub fn git_remote_get_fetch_refspecs(array: *mut git_strarray, + remote: *const git_remote) -> c_int; + pub fn git_remote_get_push_refspecs(array: *mut git_strarray, + remote: *const git_remote) -> c_int; + pub fn git_remote_get_refspec(remote: *const git_remote, + n: size_t) -> *const git_refspec; + pub fn git_remote_is_valid_name(remote_name: *const c_char) -> c_int; + pub fn git_remote_list(out: *mut git_strarray, + repo: *mut git_repository) -> c_int; + pub fn git_remote_rename(problems: *mut git_strarray, + repo: *mut git_repository, + name: *const c_char, + new_name: *const c_char) -> c_int; + pub fn git_remote_fetch(remote: *mut git_remote, + refspecs: *const git_strarray, + opts: *const git_fetch_options, + reflog_message: *const c_char) -> c_int; + pub fn git_remote_push(remote: *mut git_remote, + refspecs: *const git_strarray, + opts: *const git_push_options) -> c_int; + pub fn git_remote_update_tips(remote: *mut git_remote, + callbacks: *const git_remote_callbacks, + update_fetchead: c_int, + download_tags: git_remote_autotag_option_t, + reflog_message: *const c_char) -> c_int; + pub fn git_remote_set_url(repo: *mut git_repository, + remote: *const c_char, + url: *const c_char) -> c_int; + pub fn git_remote_set_pushurl(repo: *mut git_repository, + remote: *const c_char, + pushurl: *const c_char) -> c_int; + pub fn git_remote_init_callbacks(opts: *mut git_remote_callbacks, + version: c_uint) -> c_int; + pub fn git_fetch_init_options(opts: *mut git_fetch_options, + version: c_uint) -> c_int; + pub fn git_remote_stats(remote: *mut git_remote) + -> *const git_transfer_progress; + pub fn git_remote_ls(out: *mut *mut *const git_remote_head, + size: *mut size_t, + remote: *mut git_remote) -> c_int; + pub fn git_remote_set_autotag(repo: *mut git_repository, + remote: *const c_char, + value: git_remote_autotag_option_t) -> c_int; + pub fn git_remote_prune(remote: *mut git_remote, + callbacks: *const git_remote_callbacks) -> c_int; + + // refspec + pub fn git_refspec_direction(spec: *const git_refspec) -> git_direction; + pub fn git_refspec_dst(spec: *const git_refspec) -> *const c_char; + pub fn git_refspec_dst_matches(spec: *const git_refspec, + refname: *const c_char) -> c_int; + pub fn git_refspec_src(spec: *const git_refspec) -> *const c_char; + pub fn git_refspec_src_matches(spec: *const git_refspec, + refname: *const c_char) -> c_int; + pub fn git_refspec_force(spec: *const git_refspec) -> c_int; + pub fn git_refspec_string(spec: *const git_refspec) -> *const c_char; + + // strarray + pub fn git_strarray_free(array: *mut git_strarray); + + // oidarray + pub fn git_oidarray_free(array: *mut git_oidarray); + + // signature + pub fn git_signature_default(out: *mut *mut git_signature, + repo: *mut git_repository) -> c_int; + pub fn git_signature_free(sig: *mut git_signature); + pub fn git_signature_new(out: *mut *mut git_signature, + name: *const c_char, + email: *const c_char, + time: git_time_t, + offset: c_int) -> c_int; + pub fn git_signature_now(out: *mut *mut git_signature, + name: *const c_char, + email: *const c_char) -> c_int; + pub fn git_signature_dup(dest: *mut *mut git_signature, + sig: *const git_signature) -> c_int; + + // status + pub fn git_status_list_new(out: *mut *mut git_status_list, + repo: *mut git_repository, + options: *const git_status_options) -> c_int; + pub fn git_status_list_entrycount(list: *mut git_status_list) -> size_t; + pub fn git_status_byindex(statuslist: *mut git_status_list, + idx: size_t) -> *const git_status_entry; + pub fn git_status_list_free(list: *mut git_status_list); + pub fn git_status_init_options(opts: *mut git_status_options, + version: c_uint) -> c_int; + pub fn git_status_file(status_flags: *mut c_uint, + repo: *mut git_repository, + path: *const c_char) -> c_int; + pub fn git_status_should_ignore(ignored: *mut c_int, + repo: *mut git_repository, + path: *const c_char) -> c_int; + + // clone + pub fn git_clone(out: *mut *mut git_repository, + url: *const c_char, + local_path: *const c_char, + options: *const git_clone_options) -> c_int; + pub fn git_clone_init_options(opts: *mut git_clone_options, + version: c_uint) -> c_int; + + // reset + pub fn git_reset(repo: *mut git_repository, + target: *const git_object, + reset_type: git_reset_t, + checkout_opts: *const git_checkout_options) -> c_int; + pub fn git_reset_default(repo: *mut git_repository, + target: *const git_object, + pathspecs: *const git_strarray) -> c_int; + + // reference + pub fn git_reference_cmp(ref1: *const git_reference, + ref2: *const git_reference) -> c_int; + pub fn git_reference_delete(r: *mut git_reference) -> c_int; + pub fn git_reference_free(r: *mut git_reference); + pub fn git_reference_is_branch(r: *const git_reference) -> c_int; + pub fn git_reference_is_note(r: *const git_reference) -> c_int; + pub fn git_reference_is_remote(r: *const git_reference) -> c_int; + pub fn git_reference_is_tag(r: *const git_reference) -> c_int; + pub fn git_reference_is_valid_name(name: *const c_char) -> c_int; + pub fn git_reference_lookup(out: *mut *mut git_reference, + repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_reference_name(r: *const git_reference) -> *const c_char; + pub fn git_reference_name_to_id(out: *mut git_oid, + repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_reference_peel(out: *mut *mut git_object, + r: *mut git_reference, + otype: git_otype) -> c_int; + pub fn git_reference_rename(new_ref: *mut *mut git_reference, + r: *mut git_reference, + new_name: *const c_char, + force: c_int, + log_message: *const c_char) -> c_int; + pub fn git_reference_resolve(out: *mut *mut git_reference, + r: *const git_reference) -> c_int; + pub fn git_reference_shorthand(r: *const git_reference) -> *const c_char; + pub fn git_reference_symbolic_target(r: *const git_reference) -> *const c_char; + pub fn git_reference_target(r: *const git_reference) -> *const git_oid; + pub fn git_reference_target_peel(r: *const git_reference) -> *const git_oid; + pub fn git_reference_set_target(out: *mut *mut git_reference, + r: *mut git_reference, + id: *const git_oid, + log_message: *const c_char) -> c_int; + pub fn git_reference_type(r: *const git_reference) -> git_ref_t; + pub fn git_reference_iterator_new(out: *mut *mut git_reference_iterator, + repo: *mut git_repository) -> c_int; + pub fn git_reference_iterator_glob_new(out: *mut *mut git_reference_iterator, + repo: *mut git_repository, + glob: *const c_char) -> c_int; + pub fn git_reference_iterator_free(iter: *mut git_reference_iterator); + pub fn git_reference_next(out: *mut *mut git_reference, + iter: *mut git_reference_iterator) -> c_int; + pub fn git_reference_next_name(out: *mut *const c_char, + iter: *mut git_reference_iterator) -> c_int; + pub fn git_reference_create(out: *mut *mut git_reference, + repo: *mut git_repository, + name: *const c_char, + id: *const git_oid, + force: c_int, + log_message: *const c_char) -> c_int; + pub fn git_reference_symbolic_create(out: *mut *mut git_reference, + repo: *mut git_repository, + name: *const c_char, + target: *const c_char, + force: c_int, + log_message: *const c_char) -> c_int; + pub fn git_reference_create_matching(out: *mut *mut git_reference, + repo: *mut git_repository, + name: *const c_char, + id: *const git_oid, + force: c_int, + current_id: *const git_oid, + log_message: *const c_char) -> c_int; + pub fn git_reference_symbolic_create_matching(out: *mut *mut git_reference, + repo: *mut git_repository, + name: *const c_char, + target: *const c_char, + force: c_int, + current_id: *const c_char, + log_message: *const c_char) + -> c_int; + pub fn git_reference_has_log(repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_reference_ensure_log(repo: *mut git_repository, + name: *const c_char) -> c_int; + + // stash + pub fn git_stash_save(out: *mut git_oid, + repo: *mut git_repository, + stasher: *const git_signature, + message: *const c_char, + flags: c_uint) -> c_int; + + pub fn git_stash_apply_init_options(opts: *mut git_stash_apply_options, + version: c_uint) -> c_int; + + pub fn git_stash_apply(repo: *mut git_repository, + index: size_t, + options: *const git_stash_apply_options) -> c_int; + + pub fn git_stash_foreach(repo: *mut git_repository, + callback: git_stash_cb, + payload: *mut c_void) -> c_int; + + pub fn git_stash_drop(repo: *mut git_repository, + index: size_t) -> c_int; + + pub fn git_stash_pop(repo: *mut git_repository, + index: size_t, + options: *const git_stash_apply_options) -> c_int; + + // submodules + pub fn git_submodule_add_finalize(submodule: *mut git_submodule) -> c_int; + pub fn git_submodule_add_setup(submodule: *mut *mut git_submodule, + repo: *mut git_repository, + url: *const c_char, + path: *const c_char, + use_gitlink: c_int) -> c_int; + pub fn git_submodule_add_to_index(submodule: *mut git_submodule, + write_index: c_int) -> c_int; + pub fn git_submodule_branch(submodule: *mut git_submodule) -> *const c_char; + pub fn git_submodule_foreach(repo: *mut git_repository, + callback: git_submodule_cb, + payload: *mut c_void) -> c_int; + pub fn git_submodule_free(submodule: *mut git_submodule); + pub fn git_submodule_head_id(submodule: *mut git_submodule) -> *const git_oid; + pub fn git_submodule_index_id(submodule: *mut git_submodule) -> *const git_oid; + pub fn git_submodule_init(submodule: *mut git_submodule, + overwrite: c_int) -> c_int; + pub fn git_submodule_location(status: *mut c_uint, + submodule: *mut git_submodule) -> c_int; + pub fn git_submodule_lookup(out: *mut *mut git_submodule, + repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_submodule_name(submodule: *mut git_submodule) -> *const c_char; + pub fn git_submodule_open(repo: *mut *mut git_repository, + submodule: *mut git_submodule) -> c_int; + pub fn git_submodule_path(submodule: *mut git_submodule) -> *const c_char; + pub fn git_submodule_reload(submodule: *mut git_submodule, + force: c_int) -> c_int; + pub fn git_submodule_set_ignore(repo: *mut git_repository, + name: *const c_char, + ignore: git_submodule_ignore_t) + -> c_int; + pub fn git_submodule_set_update(repo: *mut git_repository, + name: *const c_char, + update: git_submodule_update_t) + -> c_int; + pub fn git_submodule_set_url(repo: *mut git_repository, + name: *const c_char, + url: *const c_char) -> c_int; + pub fn git_submodule_sync(submodule: *mut git_submodule) -> c_int; + pub fn git_submodule_update_strategy(submodule: *mut git_submodule) + -> git_submodule_update_t; + pub fn git_submodule_update(submodule: *mut git_submodule, + init: c_int, + options: *mut git_submodule_update_options) + -> c_int; + pub fn git_submodule_update_init_options(options: *mut git_submodule_update_options, + version: c_uint) -> c_int; + pub fn git_submodule_url(submodule: *mut git_submodule) -> *const c_char; + pub fn git_submodule_wd_id(submodule: *mut git_submodule) -> *const git_oid; + pub fn git_submodule_status(status: *mut c_uint, + repo: *mut git_repository, + name: *const c_char, + ignore: git_submodule_ignore_t) -> c_int; + pub fn git_submodule_set_branch(repo: *mut git_repository, + name: *const c_char, + branch: *const c_char) -> c_int; + + // blob + pub fn git_blob_free(blob: *mut git_blob); + pub fn git_blob_id(blob: *const git_blob) -> *const git_oid; + pub fn git_blob_is_binary(blob: *const git_blob) -> c_int; + pub fn git_blob_lookup(blob: *mut *mut git_blob, repo: *mut git_repository, + id: *const git_oid) -> c_int; + pub fn git_blob_lookup_prefix(blob: *mut *mut git_blob, + repo: *mut git_repository, + id: *const git_oid, + len: size_t) -> c_int; + pub fn git_blob_rawcontent(blob: *const git_blob) -> *const c_void; + pub fn git_blob_rawsize(blob: *const git_blob) -> git_off_t; + pub fn git_blob_create_frombuffer(id: *mut git_oid, + repo: *mut git_repository, + buffer: *const c_void, + len: size_t) -> c_int; + pub fn git_blob_create_fromdisk(id: *mut git_oid, + repo: *mut git_repository, + path: *const c_char) -> c_int; + pub fn git_blob_create_fromworkdir(id: *mut git_oid, + repo: *mut git_repository, + relative_path: *const c_char) -> c_int; + pub fn git_blob_create_fromstream(out: *mut *mut git_writestream, + repo: *mut git_repository, + hintpath: *const c_char) -> c_int; + pub fn git_blob_create_fromstream_commit(id: *mut git_oid, + stream: *mut git_writestream) -> c_int; + + // tree + pub fn git_tree_entry_byid(tree: *const git_tree, + id: *const git_oid) -> *const git_tree_entry; + pub fn git_tree_entry_byindex(tree: *const git_tree, + idx: size_t) -> *const git_tree_entry; + pub fn git_tree_entry_byname(tree: *const git_tree, + filename: *const c_char) -> *const git_tree_entry; + pub fn git_tree_entry_bypath(out: *mut *mut git_tree_entry, + tree: *const git_tree, + filename: *const c_char) -> c_int; + pub fn git_tree_entry_cmp(e1: *const git_tree_entry, + e2: *const git_tree_entry) -> c_int; + pub fn git_tree_entry_dup(dest: *mut *mut git_tree_entry, + src: *const git_tree_entry) -> c_int; + pub fn git_tree_entry_filemode(entry: *const git_tree_entry) -> git_filemode_t; + pub fn git_tree_entry_filemode_raw(entry: *const git_tree_entry) -> git_filemode_t; + pub fn git_tree_entry_free(entry: *mut git_tree_entry); + pub fn git_tree_entry_id(entry: *const git_tree_entry) -> *const git_oid; + pub fn git_tree_entry_name(entry: *const git_tree_entry) -> *const c_char; + pub fn git_tree_entry_to_object(out: *mut *mut git_object, + repo: *mut git_repository, + entry: *const git_tree_entry) -> c_int; + pub fn git_tree_entry_type(entry: *const git_tree_entry) -> git_otype; + pub fn git_tree_entrycount(tree: *const git_tree) -> size_t; + pub fn git_tree_free(tree: *mut git_tree); + pub fn git_tree_id(tree: *const git_tree) -> *const git_oid; + pub fn git_tree_lookup(tree: *mut *mut git_tree, + repo: *mut git_repository, + id: *const git_oid) -> c_int; + pub fn git_tree_walk(tree: *const git_tree, + mode: git_treewalk_mode, + callback: git_treewalk_cb, + payload: *mut c_void) -> c_int; + + // treebuilder + pub fn git_treebuilder_new(out: *mut *mut git_treebuilder, + repo: *mut git_repository, + source: *const git_tree) -> c_int; + pub fn git_treebuilder_clear(bld: *mut git_treebuilder); + pub fn git_treebuilder_entrycount(bld: *mut git_treebuilder) -> c_uint; + pub fn git_treebuilder_free(bld: *mut git_treebuilder); + pub fn git_treebuilder_get(bld: *mut git_treebuilder, + filename: *const c_char) -> *const git_tree_entry; + pub fn git_treebuilder_insert(out: *mut *const git_tree_entry, + bld: *mut git_treebuilder, + filename: *const c_char, + id: *const git_oid, + filemode: git_filemode_t) -> c_int; + pub fn git_treebuilder_remove(bld: *mut git_treebuilder, + filename: *const c_char) -> c_int; + pub fn git_treebuilder_filter(bld: *mut git_treebuilder, + filter: git_treebuilder_filter_cb, + payload: *mut c_void); + pub fn git_treebuilder_write(id: *mut git_oid, + bld: *mut git_treebuilder) -> c_int; + + // buf + pub fn git_buf_free(buffer: *mut git_buf); + pub fn git_buf_grow(buffer: *mut git_buf, target_size: size_t) -> c_int; + pub fn git_buf_set(buffer: *mut git_buf, data: *const c_void, + datalen: size_t) -> c_int; + + // commit + pub fn git_commit_author(commit: *const git_commit) -> *const git_signature; + pub fn git_commit_committer(commit: *const git_commit) -> *const git_signature; + pub fn git_commit_free(commit: *mut git_commit); + pub fn git_commit_id(commit: *const git_commit) -> *const git_oid; + pub fn git_commit_lookup(commit: *mut *mut git_commit, + repo: *mut git_repository, + id: *const git_oid) -> c_int; + pub fn git_commit_message(commit: *const git_commit) -> *const c_char; + pub fn git_commit_message_encoding(commit: *const git_commit) -> *const c_char; + pub fn git_commit_message_raw(commit: *const git_commit) -> *const c_char; + pub fn git_commit_nth_gen_ancestor(commit: *mut *mut git_commit, + commit: *const git_commit, + n: c_uint) -> c_int; + pub fn git_commit_parent(out: *mut *mut git_commit, + commit: *const git_commit, + n: c_uint) -> c_int; + pub fn git_commit_parent_id(commit: *const git_commit, + n: c_uint) -> *const git_oid; + pub fn git_commit_parentcount(commit: *const git_commit) -> c_uint; + pub fn git_commit_raw_header(commit: *const git_commit) -> *const c_char; + pub fn git_commit_summary(commit: *mut git_commit) -> *const c_char; + pub fn git_commit_time(commit: *const git_commit) -> git_time_t; + pub fn git_commit_time_offset(commit: *const git_commit) -> c_int; + pub fn git_commit_tree(tree_out: *mut *mut git_tree, + commit: *const git_commit) -> c_int; + pub fn git_commit_tree_id(commit: *const git_commit) -> *const git_oid; + pub fn git_commit_amend(id: *mut git_oid, + commit_to_amend: *const git_commit, + update_ref: *const c_char, + author: *const git_signature, + committer: *const git_signature, + message_encoding: *const c_char, + message: *const c_char, + tree: *const git_tree) -> c_int; + pub fn git_commit_create(id: *mut git_oid, + repo: *mut git_repository, + update_ref: *const c_char, + author: *const git_signature, + committer: *const git_signature, + message_encoding: *const c_char, + message: *const c_char, + tree: *const git_tree, + parent_count: size_t, + parents: *mut *const git_commit) -> c_int; + pub fn git_commit_header_field(out: *mut git_buf, + commit: *const git_commit, + field: *const c_char) -> c_int; + pub fn git_annotated_commit_lookup(out: *mut *mut git_annotated_commit, + repo: *mut git_repository, + id: *const git_oid) -> c_int; + pub fn git_commit_create_with_signature(id: *mut git_oid, + repo: *mut git_repository, + commit_content: *const c_char, + signature: *const c_char, + signature_field: *const c_char) -> c_int; + pub fn git_commit_extract_signature(signature: *mut git_buf, + signed_data: *mut git_buf, + repo: *mut git_repository, + commit_id: *mut git_oid, + field: *const c_char) -> c_int; + + // branch + pub fn git_branch_create(out: *mut *mut git_reference, + repo: *mut git_repository, + branch_name: *const c_char, + target: *const git_commit, + force: c_int) -> c_int; + pub fn git_branch_delete(branch: *mut git_reference) -> c_int; + pub fn git_branch_is_head(branch: *const git_reference) -> c_int; + pub fn git_branch_iterator_free(iter: *mut git_branch_iterator); + pub fn git_branch_iterator_new(iter: *mut *mut git_branch_iterator, + repo: *mut git_repository, + list_flags: git_branch_t) -> c_int; + pub fn git_branch_lookup(out: *mut *mut git_reference, + repo: *mut git_repository, + branch_name: *const c_char, + branch_type: git_branch_t) -> c_int; + pub fn git_branch_move(out: *mut *mut git_reference, + branch: *mut git_reference, + new_branch_name: *const c_char, + force: c_int) -> c_int; + pub fn git_branch_name(out: *mut *const c_char, + branch: *const git_reference) -> c_int; + pub fn git_branch_next(out: *mut *mut git_reference, + out_type: *mut git_branch_t, + iter: *mut git_branch_iterator) -> c_int; + pub fn git_branch_set_upstream(branch: *mut git_reference, + upstream_name: *const c_char) -> c_int; + pub fn git_branch_upstream(out: *mut *mut git_reference, + branch: *const git_reference) -> c_int; + + // index + pub fn git_index_add(index: *mut git_index, + entry: *const git_index_entry) -> c_int; + pub fn git_index_add_all(index: *mut git_index, + pathspec: *const git_strarray, + flags: c_uint, + callback: Option, + payload: *mut c_void) -> c_int; + pub fn git_index_add_bypath(index: *mut git_index, + path: *const c_char) -> c_int; + pub fn git_index_add_frombuffer(index: *mut git_index, + entry: *const git_index_entry, + buffer: *const c_void, + len: size_t) -> c_int; + pub fn git_index_conflict_add(index: *mut git_index, + ancestor_entry: *const git_index_entry, + our_entry: *const git_index_entry, + their_entry: *const git_index_entry) -> c_int; + pub fn git_index_clear(index: *mut git_index) -> c_int; + pub fn git_index_entry_stage(entry: *const git_index_entry) -> c_int; + pub fn git_index_entrycount(entry: *const git_index) -> size_t; + pub fn git_index_find(at_pos: *mut size_t, + index: *mut git_index, + path: *const c_char) -> c_int; + pub fn git_index_free(index: *mut git_index); + pub fn git_index_get_byindex(index: *mut git_index, + n: size_t) -> *const git_index_entry; + pub fn git_index_get_bypath(index: *mut git_index, + path: *const c_char, + stage: c_int) -> *const git_index_entry; + pub fn git_index_has_conflicts(index: *const git_index) -> c_int; + pub fn git_index_new(index: *mut *mut git_index) -> c_int; + pub fn git_index_open(index: *mut *mut git_index, + index_path: *const c_char) -> c_int; + pub fn git_index_path(index: *const git_index) -> *const c_char; + pub fn git_index_read(index: *mut git_index, force: c_int) -> c_int; + pub fn git_index_read_tree(index: *mut git_index, + tree: *const git_tree) -> c_int; + pub fn git_index_remove(index: *mut git_index, + path: *const c_char, + stage: c_int) -> c_int; + pub fn git_index_remove_all(index: *mut git_index, + pathspec: *const git_strarray, + callback: Option, + payload: *mut c_void) -> c_int; + pub fn git_index_remove_bypath(index: *mut git_index, + path: *const c_char) -> c_int; + pub fn git_index_remove_directory(index: *mut git_index, + dir: *const c_char, + stage: c_int) -> c_int; + pub fn git_index_update_all(index: *mut git_index, + pathspec: *const git_strarray, + callback: Option, + payload: *mut c_void) -> c_int; + pub fn git_index_write(index: *mut git_index) -> c_int; + pub fn git_index_write_tree(out: *mut git_oid, + index: *mut git_index) -> c_int; + pub fn git_index_write_tree_to(out: *mut git_oid, + index: *mut git_index, + repo: *mut git_repository) -> c_int; + + // config + pub fn git_config_add_file_ondisk(cfg: *mut git_config, + path: *const c_char, + level: git_config_level_t, + repo: *const git_repository, + force: c_int) -> c_int; + pub fn git_config_delete_entry(cfg: *mut git_config, + name: *const c_char) -> c_int; + pub fn git_config_delete_multivar(cfg: *mut git_config, + name: *const c_char, + regexp: *const c_char) -> c_int; + pub fn git_config_find_programdata(out: *mut git_buf) -> c_int; + pub fn git_config_find_global(out: *mut git_buf) -> c_int; + pub fn git_config_find_system(out: *mut git_buf) -> c_int; + pub fn git_config_find_xdg(out: *mut git_buf) -> c_int; + pub fn git_config_free(cfg: *mut git_config); + pub fn git_config_get_bool(out: *mut c_int, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_entry(out: *mut *mut git_config_entry, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_int32(out: *mut i32, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_int64(out: *mut i64, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_string(out: *mut *const c_char, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_string_buf(out: *mut git_buf, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_get_path(out: *mut git_buf, + cfg: *const git_config, + name: *const c_char) -> c_int; + pub fn git_config_iterator_free(iter: *mut git_config_iterator); + pub fn git_config_iterator_glob_new(out: *mut *mut git_config_iterator, + cfg: *const git_config, + regexp: *const c_char) -> c_int; + pub fn git_config_iterator_new(out: *mut *mut git_config_iterator, + cfg: *const git_config) -> c_int; + pub fn git_config_new(out: *mut *mut git_config) -> c_int; + pub fn git_config_next(entry: *mut *mut git_config_entry, + iter: *mut git_config_iterator) -> c_int; + pub fn git_config_open_default(out: *mut *mut git_config) -> c_int; + pub fn git_config_open_global(out: *mut *mut git_config, + config: *mut git_config) -> c_int; + pub fn git_config_open_level(out: *mut *mut git_config, + parent: *const git_config, + level: git_config_level_t) -> c_int; + pub fn git_config_open_ondisk(out: *mut *mut git_config, + path: *const c_char) -> c_int; + pub fn git_config_parse_bool(out: *mut c_int, + value: *const c_char) -> c_int; + pub fn git_config_parse_int32(out: *mut i32, + value: *const c_char) -> c_int; + pub fn git_config_parse_int64(out: *mut i64, + value: *const c_char) -> c_int; + pub fn git_config_set_bool(cfg: *mut git_config, + name: *const c_char, + value: c_int) -> c_int; + pub fn git_config_set_int32(cfg: *mut git_config, + name: *const c_char, + value: i32) -> c_int; + pub fn git_config_set_int64(cfg: *mut git_config, + name: *const c_char, + value: i64) -> c_int; + pub fn git_config_set_multivar(cfg: *mut git_config, + name: *const c_char, + regexp: *const c_char, + value: *const c_char) -> c_int; + pub fn git_config_set_string(cfg: *mut git_config, + name: *const c_char, + value: *const c_char) -> c_int; + pub fn git_config_snapshot(out: *mut *mut git_config, + config: *mut git_config) -> c_int; + pub fn git_config_entry_free(entry: *mut git_config_entry); + + // cred + pub fn git_cred_default_new(out: *mut *mut git_cred) -> c_int; + pub fn git_cred_has_username(cred: *mut git_cred) -> c_int; + pub fn git_cred_ssh_custom_new(out: *mut *mut git_cred, + username: *const c_char, + publickey: *const c_char, + publickey_len: size_t, + sign_callback: git_cred_sign_callback, + payload: *mut c_void) -> c_int; + pub fn git_cred_ssh_interactive_new(out: *mut *mut git_cred, + username: *const c_char, + prompt_callback: git_cred_ssh_interactive_callback, + payload: *mut c_void) -> c_int; + pub fn git_cred_ssh_key_from_agent(out: *mut *mut git_cred, + username: *const c_char) -> c_int; + pub fn git_cred_ssh_key_new(out: *mut *mut git_cred, + username: *const c_char, + publickey: *const c_char, + privatekey: *const c_char, + passphrase: *const c_char) -> c_int; + pub fn git_cred_ssh_key_memory_new(out: *mut *mut git_cred, + username: *const c_char, + publickey: *const c_char, + privatekey: *const c_char, + passphrase: *const c_char) -> c_int; + pub fn git_cred_userpass(cred: *mut *mut git_cred, + url: *const c_char, + user_from_url: *const c_char, + allowed_types: c_uint, + payload: *mut c_void) -> c_int; + pub fn git_cred_userpass_plaintext_new(out: *mut *mut git_cred, + username: *const c_char, + password: *const c_char) -> c_int; + pub fn git_cred_username_new(cred: *mut *mut git_cred, + username: *const c_char) -> c_int; + + // tags + pub fn git_tag_annotation_create(oid: *mut git_oid, + repo: *mut git_repository, + tag_name: *const c_char, + target: *const git_object, + tagger: *const git_signature, + message: *const c_char) -> c_int; + pub fn git_tag_create(oid: *mut git_oid, + repo: *mut git_repository, + tag_name: *const c_char, + target: *const git_object, + tagger: *const git_signature, + message: *const c_char, + force: c_int) -> c_int; + pub fn git_tag_create_frombuffer(oid: *mut git_oid, + repo: *mut git_repository, + buffer: *const c_char, + force: c_int) -> c_int; + pub fn git_tag_create_lightweight(oid: *mut git_oid, + repo: *mut git_repository, + tag_name: *const c_char, + target: *const git_object, + force: c_int) -> c_int; + pub fn git_tag_delete(repo: *mut git_repository, + tag_name: *const c_char) -> c_int; + pub fn git_tag_foreach(repo: *mut git_repository, + callback: git_tag_foreach_cb, + payload: *mut c_void) -> c_int; + pub fn git_tag_free(tag: *mut git_tag); + pub fn git_tag_id(tag: *const git_tag) -> *const git_oid; + pub fn git_tag_list(tag_names: *mut git_strarray, + repo: *mut git_repository) -> c_int; + pub fn git_tag_list_match(tag_names: *mut git_strarray, + pattern: *const c_char, + repo: *mut git_repository) -> c_int; + pub fn git_tag_lookup(out: *mut *mut git_tag, + repo: *mut git_repository, + id: *const git_oid) -> c_int; + pub fn git_tag_lookup_prefix(out: *mut *mut git_tag, + repo: *mut git_repository, + id: *const git_oid, + len: size_t) -> c_int; + pub fn git_tag_message(tag: *const git_tag) -> *const c_char; + pub fn git_tag_name(tag: *const git_tag) -> *const c_char; + pub fn git_tag_peel(tag_target_out: *mut *mut git_object, + tag: *const git_tag) -> c_int; + pub fn git_tag_tagger(tag: *const git_tag) -> *const git_signature; + pub fn git_tag_target(target_out: *mut *mut git_object, + tag: *const git_tag) -> c_int; + pub fn git_tag_target_id(tag: *const git_tag) -> *const git_oid; + pub fn git_tag_target_type(tag: *const git_tag) -> git_otype; + + // checkout + pub fn git_checkout_head(repo: *mut git_repository, + opts: *const git_checkout_options) -> c_int; + pub fn git_checkout_index(repo: *mut git_repository, + index: *mut git_index, + opts: *const git_checkout_options) -> c_int; + pub fn git_checkout_tree(repo: *mut git_repository, + treeish: *const git_object, + opts: *const git_checkout_options) -> c_int; + pub fn git_checkout_init_options(opts: *mut git_checkout_options, + version: c_uint) -> c_int; + + // merge + pub fn git_annotated_commit_id(commit: *const git_annotated_commit) + -> *const git_oid; + pub fn git_annotated_commit_from_ref(out: *mut *mut git_annotated_commit, + repo: *mut git_repository, + reference: *const git_reference) + -> c_int; + pub fn git_annotated_commit_free(commit: *mut git_annotated_commit); + pub fn git_merge_init_options(opts: *mut git_merge_options, + version: c_uint) -> c_int; + pub fn git_merge(repo: *mut git_repository, + their_heads: *mut *const git_annotated_commit, + len: size_t, + merge_opts: *const git_merge_options, + checkout_opts: *const git_checkout_options) -> c_int; + pub fn git_merge_commits(out: *mut *mut git_index, + repo: *mut git_repository, + our_commit: *const git_commit, + their_commit: *const git_commit, + opts: *const git_merge_options) -> c_int; + pub fn git_merge_trees(out: *mut *mut git_index, + repo: *mut git_repository, + ancestor_tree: *const git_tree, + our_tree: *const git_tree, + their_tree: *const git_tree, + opts: *const git_merge_options) -> c_int; + pub fn git_repository_state_cleanup(repo: *mut git_repository) -> c_int; + + // merge analysis + + pub fn git_merge_analysis(analysis_out: *mut git_merge_analysis_t, + pref_out: *mut git_merge_preference_t, + repo: *mut git_repository, + their_heads: *mut *const git_annotated_commit, + their_heads_len: usize) -> c_int; + + // notes + pub fn git_note_author(note: *const git_note) -> *const git_signature; + pub fn git_note_committer(note: *const git_note) -> *const git_signature; + pub fn git_note_create(out: *mut git_oid, + repo: *mut git_repository, + notes_ref: *const c_char, + author: *const git_signature, + committer: *const git_signature, + oid: *const git_oid, + note: *const c_char, + force: c_int) -> c_int; + pub fn git_note_default_ref(out: *mut git_buf, + repo: *mut git_repository) -> c_int; + pub fn git_note_free(note: *mut git_note); + pub fn git_note_id(note: *const git_note) -> *const git_oid; + pub fn git_note_iterator_free(it: *mut git_note_iterator); + pub fn git_note_iterator_new(out: *mut *mut git_note_iterator, + repo: *mut git_repository, + notes_ref: *const c_char) -> c_int; + pub fn git_note_message(note: *const git_note) -> *const c_char; + pub fn git_note_next(note_id: *mut git_oid, + annotated_id: *mut git_oid, + it: *mut git_note_iterator) -> c_int; + pub fn git_note_read(out: *mut *mut git_note, + repo: *mut git_repository, + notes_ref: *const c_char, + oid: *const git_oid) -> c_int; + pub fn git_note_remove(repo: *mut git_repository, + notes_ref: *const c_char, + author: *const git_signature, + committer: *const git_signature, + oid: *const git_oid) -> c_int; + + // blame + pub fn git_blame_file(out: *mut *mut git_blame, + repo: *mut git_repository, + path: *const c_char, + options: *mut git_blame_options) -> c_int; + pub fn git_blame_free(blame: *mut git_blame); + + pub fn git_blame_init_options(opts: *mut git_blame_options, + version: c_uint) -> c_int; + pub fn git_blame_get_hunk_count(blame: *mut git_blame) -> u32; + + pub fn git_blame_get_hunk_byline(blame: *mut git_blame, + lineno: usize) -> *const git_blame_hunk; + pub fn git_blame_get_hunk_byindex(blame: *mut git_blame, + index: u32) -> *const git_blame_hunk; + + // revwalk + pub fn git_revwalk_new(out: *mut *mut git_revwalk, + repo: *mut git_repository) -> c_int; + pub fn git_revwalk_free(walk: *mut git_revwalk); + + pub fn git_revwalk_reset(walk: *mut git_revwalk); + + pub fn git_revwalk_sorting(walk: *mut git_revwalk, sort_mode: c_uint); + + pub fn git_revwalk_push_head(walk: *mut git_revwalk) -> c_int; + pub fn git_revwalk_push(walk: *mut git_revwalk, + oid: *const git_oid) -> c_int; + pub fn git_revwalk_push_ref(walk: *mut git_revwalk, + refname: *const c_char) -> c_int; + pub fn git_revwalk_push_glob(walk: *mut git_revwalk, + glob: *const c_char) -> c_int; + pub fn git_revwalk_push_range(walk: *mut git_revwalk, + range: *const c_char) -> c_int; + pub fn git_revwalk_simplify_first_parent(walk: *mut git_revwalk); + + pub fn git_revwalk_hide_head(walk: *mut git_revwalk) -> c_int; + pub fn git_revwalk_hide(walk: *mut git_revwalk, + oid: *const git_oid) -> c_int; + pub fn git_revwalk_hide_ref(walk: *mut git_revwalk, + refname: *const c_char) -> c_int; + pub fn git_revwalk_hide_glob(walk: *mut git_revwalk, + refname: *const c_char) -> c_int; + pub fn git_revwalk_add_hide_cb(walk: *mut git_revwalk, + hide_cb: git_revwalk_hide_cb, + payload: *mut c_void) -> c_int; + + pub fn git_revwalk_next(out: *mut git_oid, walk: *mut git_revwalk) -> c_int; + + // merge + pub fn git_merge_base(out: *mut git_oid, + repo: *mut git_repository, + one: *const git_oid, + two: *const git_oid) -> c_int; + + pub fn git_merge_bases(out: *mut git_oidarray, + repo: *mut git_repository, + one: *const git_oid, + two: *const git_oid) -> c_int; + + // pathspec + pub fn git_pathspec_free(ps: *mut git_pathspec); + pub fn git_pathspec_match_diff(out: *mut *mut git_pathspec_match_list, + diff: *mut git_diff, + flags: u32, + ps: *mut git_pathspec) -> c_int; + pub fn git_pathspec_match_index(out: *mut *mut git_pathspec_match_list, + index: *mut git_index, + flags: u32, + ps: *mut git_pathspec) -> c_int; + pub fn git_pathspec_match_list_diff_entry(m: *const git_pathspec_match_list, + pos: size_t) -> *const git_diff_delta; + pub fn git_pathspec_match_list_entry(m: *const git_pathspec_match_list, + pos: size_t) -> *const c_char; + pub fn git_pathspec_match_list_entrycount(m: *const git_pathspec_match_list) + -> size_t; + pub fn git_pathspec_match_list_failed_entry(m: *const git_pathspec_match_list, + pos: size_t) -> *const c_char; + pub fn git_pathspec_match_list_failed_entrycount( + m: *const git_pathspec_match_list) -> size_t; + pub fn git_pathspec_match_list_free(m: *mut git_pathspec_match_list); + pub fn git_pathspec_match_tree(out: *mut *mut git_pathspec_match_list, + tree: *mut git_tree, + flags: u32, + ps: *mut git_pathspec) -> c_int; + pub fn git_pathspec_match_workdir(out: *mut *mut git_pathspec_match_list, + repo: *mut git_repository, + flags: u32, + ps: *mut git_pathspec) -> c_int; + pub fn git_pathspec_matches_path(ps: *const git_pathspec, + flags: u32, + path: *const c_char) -> c_int; + pub fn git_pathspec_new(out: *mut *mut git_pathspec, + pathspec: *const git_strarray) -> c_int; + + // diff + pub fn git_diff_blob_to_buffer(old_blob: *const git_blob, + old_as_path: *const c_char, + buffer: *const c_char, + buffer_len: size_t, + buffer_as_path: *const c_char, + options: *const git_diff_options, + file_cb: git_diff_file_cb, + binary_cb: git_diff_binary_cb, + hunk_cb: git_diff_hunk_cb, + line_cb: git_diff_line_cb, + payload: *mut c_void) -> c_int; + pub fn git_diff_blobs(old_blob: *const git_blob, + old_as_path: *const c_char, + new_blob: *const git_blob, + new_as_path: *const c_char, + options: *const git_diff_options, + file_cb: git_diff_file_cb, + binary_cb: git_diff_binary_cb, + hunk_cb: git_diff_hunk_cb, + line_cb: git_diff_line_cb, + payload: *mut c_void) -> c_int; + pub fn git_diff_buffers(old_buffer: *const c_void, + old_len: size_t, + old_as_path: *const c_char, + new_buffer: *const c_void, + new_len: size_t, + new_as_path: *const c_char, + options: *const git_diff_options, + file_cb: git_diff_file_cb, + binary_cb: git_diff_binary_cb, + hunk_cb: git_diff_hunk_cb, + line_cb: git_diff_line_cb, + payload: *mut c_void) -> c_int; + pub fn git_diff_find_similar(diff: *mut git_diff, + options: *const git_diff_find_options) -> c_int; + pub fn git_diff_find_init_options(opts: *mut git_diff_find_options, + version: c_uint) -> c_int; + pub fn git_diff_foreach(diff: *mut git_diff, + file_cb: git_diff_file_cb, + binary_cb: Option, + hunk_cb: Option, + line_cb: Option, + payload: *mut c_void) -> c_int; + pub fn git_diff_free(diff: *mut git_diff); + pub fn git_diff_get_delta(diff: *const git_diff, + idx: size_t) -> *const git_diff_delta; + pub fn git_diff_get_stats(out: *mut *mut git_diff_stats, + diff: *mut git_diff) -> c_int; + pub fn git_diff_index_to_index(diff: *mut *mut git_diff, + repo: *mut git_repository, + old_index: *mut git_index, + new_index: *mut git_index, + opts: *const git_diff_options) -> c_int; + pub fn git_diff_index_to_workdir(diff: *mut *mut git_diff, + repo: *mut git_repository, + index: *mut git_index, + opts: *const git_diff_options) -> c_int; + pub fn git_diff_init_options(opts: *mut git_diff_options, + version: c_uint) -> c_int; + pub fn git_diff_is_sorted_icase(diff: *const git_diff) -> c_int; + pub fn git_diff_merge(onto: *mut git_diff, + from: *const git_diff) -> c_int; + pub fn git_diff_num_deltas(diff: *const git_diff) -> size_t; + pub fn git_diff_num_deltas_of_type(diff: *const git_diff, + delta: git_delta_t) -> size_t; + pub fn git_diff_print(diff: *mut git_diff, + format: git_diff_format_t, + print_cb: git_diff_line_cb, + payload: *mut c_void) -> c_int; + pub fn git_diff_stats_deletions(stats: *const git_diff_stats) -> size_t; + pub fn git_diff_stats_files_changed(stats: *const git_diff_stats) -> size_t; + pub fn git_diff_stats_free(stats: *mut git_diff_stats); + pub fn git_diff_stats_insertions(stats: *const git_diff_stats) -> size_t; + pub fn git_diff_stats_to_buf(out: *mut git_buf, + stats: *const git_diff_stats, + format: git_diff_stats_format_t, + width: size_t) -> c_int; + pub fn git_diff_status_char(status: git_delta_t) -> c_char; + pub fn git_diff_tree_to_index(diff: *mut *mut git_diff, + repo: *mut git_repository, + old_tree: *mut git_tree, + index: *mut git_index, + opts: *const git_diff_options) -> c_int; + pub fn git_diff_tree_to_tree(diff: *mut *mut git_diff, + repo: *mut git_repository, + old_tree: *mut git_tree, + new_tree: *mut git_tree, + opts: *const git_diff_options) -> c_int; + pub fn git_diff_tree_to_workdir(diff: *mut *mut git_diff, + repo: *mut git_repository, + old_tree: *mut git_tree, + opts: *const git_diff_options) -> c_int; + pub fn git_diff_tree_to_workdir_with_index(diff: *mut *mut git_diff, + repo: *mut git_repository, + old_tree: *mut git_tree, + opts: *const git_diff_options) + -> c_int; + + pub fn git_graph_ahead_behind(ahead: *mut size_t, behind: *mut size_t, + repo: *mut git_repository, + local: *const git_oid, upstream: *const git_oid) + -> c_int; + + pub fn git_graph_descendant_of(repo: *mut git_repository, + commit: *const git_oid, ancestor: *const git_oid) + -> c_int; + + // patch + pub fn git_patch_from_diff(out: *mut *mut git_patch, + diff: *mut git_diff, + idx: size_t) -> c_int; + pub fn git_patch_from_blobs(out: *mut *mut git_patch, + old_blob: *const git_blob, + old_as_path: *const c_char, + new_blob: *const git_blob, + new_as_path: *const c_char, + opts: *const git_diff_options) -> c_int; + pub fn git_patch_from_blob_and_buffer(out: *mut *mut git_patch, + old_blob: *const git_blob, + old_as_path: *const c_char, + buffer: *const c_void, + buffer_len: size_t, + buffer_as_path: *const c_char, + opts: *const git_diff_options) -> c_int; + pub fn git_patch_from_buffers(out: *mut *mut git_patch, + old_buffer: *const c_void, + old_len: size_t, + old_as_path: *const c_char, + new_buffer: *const c_void, + new_len: size_t, + new_as_path: *const c_char, + opts: *const git_diff_options) -> c_int; + pub fn git_patch_free(patch: *mut git_patch); + pub fn git_patch_get_delta(patch: *const git_patch) -> *const git_diff_delta; + pub fn git_patch_num_hunks(patch: *const git_patch) -> size_t; + pub fn git_patch_line_stats(total_context: *mut size_t, + total_additions: *mut size_t, + total_deletions: *mut size_t, + patch: *const git_patch) -> c_int; + pub fn git_patch_get_hunk(out: *mut *const git_diff_hunk, + lines_in_hunk: *mut size_t, + patch: *mut git_patch, + hunk_idx: size_t) -> c_int; + pub fn git_patch_num_lines_in_hunk(patch: *const git_patch, + hunk_idx: size_t) -> c_int; + pub fn git_patch_get_line_in_hunk(out: *mut *const git_diff_line, + patch: *mut git_patch, + hunk_idx: size_t, + line_of_hunk: size_t) -> c_int; + pub fn git_patch_size(patch: *mut git_patch, + include_context: c_int, + include_hunk_headers: c_int, + include_file_headers: c_int) -> size_t; + pub fn git_patch_print(patch: *mut git_patch, + print_cb: git_diff_line_cb, + payload: *mut c_void) -> c_int; + pub fn git_patch_to_buf(buf: *mut git_buf, + patch: *mut git_patch) -> c_int; + + // reflog + pub fn git_reflog_append(reflog: *mut git_reflog, + id: *const git_oid, + committer: *const git_signature, + msg: *const c_char) -> c_int; + pub fn git_reflog_delete(repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_reflog_drop(reflog: *mut git_reflog, + idx: size_t, + rewrite_previous_entry: c_int) -> c_int; + pub fn git_reflog_entry_byindex(reflog: *const git_reflog, + idx: size_t) -> *const git_reflog_entry; + pub fn git_reflog_entry_committer(entry: *const git_reflog_entry) + -> *const git_signature; + pub fn git_reflog_entry_id_new(entry: *const git_reflog_entry) + -> *const git_oid; + pub fn git_reflog_entry_id_old(entry: *const git_reflog_entry) + -> *const git_oid; + pub fn git_reflog_entry_message(entry: *const git_reflog_entry) + -> *const c_char; + pub fn git_reflog_entrycount(reflog: *mut git_reflog) -> size_t; + pub fn git_reflog_free(reflog: *mut git_reflog); + pub fn git_reflog_read(out: *mut *mut git_reflog, + repo: *mut git_repository, + name: *const c_char) -> c_int; + pub fn git_reflog_rename(repo: *mut git_repository, + old_name: *const c_char, + name: *const c_char) -> c_int; + pub fn git_reflog_write(reflog: *mut git_reflog) -> c_int; + + // transport + pub fn git_transport_register(prefix: *const c_char, + cb: git_transport_cb, + param: *mut c_void) -> c_int; + pub fn git_transport_unregister(prefix: *const c_char) -> c_int; + pub fn git_transport_smart(out: *mut *mut git_transport, + owner: *mut git_remote, + payload: *mut c_void) -> c_int; + + // describe + pub fn git_describe_commit(result: *mut *mut git_describe_result, + object: *mut git_object, + opts: *mut git_describe_options) -> c_int; + pub fn git_describe_format(buf: *mut git_buf, + result: *const git_describe_result, + opts: *const git_describe_format_options) -> c_int; + pub fn git_describe_result_free(result: *mut git_describe_result); + pub fn git_describe_workdir(out: *mut *mut git_describe_result, + repo: *mut git_repository, + opts: *mut git_describe_options) -> c_int; + + // message + pub fn git_message_prettify(out: *mut git_buf, + message: *const c_char, + strip_comments: c_int, + comment_char: c_char) -> c_int; + + // packbuilder + pub fn git_packbuilder_new(out: *mut *mut git_packbuilder, + repo: *mut git_repository) -> c_int; + pub fn git_packbuilder_set_threads(pb: *mut git_packbuilder, + n: c_uint) -> c_uint; + pub fn git_packbuilder_insert(pb: *mut git_packbuilder, + id: *const git_oid, + name: *const c_char) -> c_int; + pub fn git_packbuilder_insert_tree(pb: *mut git_packbuilder, + id: *const git_oid) -> c_int; + pub fn git_packbuilder_insert_commit(pb: *mut git_packbuilder, + id: *const git_oid) -> c_int; + pub fn git_packbuilder_insert_walk(pb: *mut git_packbuilder, + walk: *mut git_revwalk) -> c_int; + pub fn git_packbuilder_insert_recur(pb: *mut git_packbuilder, + id: *const git_oid, + name: *const c_char) -> c_int; + pub fn git_packbuilder_write_buf(buf: *mut git_buf, + pb: *mut git_packbuilder) -> c_int; + pub fn git_packbuilder_write(pb: *mut git_packbuilder, + path: *const c_char, + mode: c_uint, + progress_cb: Option, + progress_cb_payload: *mut c_void) -> c_int; + pub fn git_packbuilder_hash(pb: *mut git_packbuilder) -> *const git_oid; + pub fn git_packbuilder_foreach(pb: *mut git_packbuilder, + cb: git_packbuilder_foreach_cb, + payload: *mut c_void) -> c_int; + pub fn git_packbuilder_object_count(pb: *mut git_packbuilder) -> size_t; + pub fn git_packbuilder_written(pb: *mut git_packbuilder) -> size_t; + pub fn git_packbuilder_set_callbacks(pb: *mut git_packbuilder, + progress_cb: Option, + progress_cb_payload: *mut c_void) -> c_int; + pub fn git_packbuilder_free(pb: *mut git_packbuilder); + + // odb + pub fn git_repository_odb(out: *mut *mut git_odb, + repo: *mut git_repository) -> c_int; + pub fn git_odb_new(db: *mut *mut git_odb) -> c_int; + pub fn git_odb_free(db: *mut git_odb); + pub fn git_odb_open_rstream(out: *mut *mut git_odb_stream, + len: *mut size_t, + otype: *mut git_otype, + db: *mut git_odb, + oid: *const git_oid) -> c_int; + pub fn git_odb_stream_read(stream: *mut git_odb_stream, + buffer: *mut c_char, + len: size_t) -> c_int; + pub fn git_odb_open_wstream(out: *mut *mut git_odb_stream, + db: *mut git_odb, + size: git_off_t, + obj_type: git_otype) -> c_int; + pub fn git_odb_stream_write(stream: *mut git_odb_stream, + buffer: *const c_char, + len: size_t) -> c_int; + pub fn git_odb_stream_finalize_write(id: *mut git_oid, + stream: *mut git_odb_stream) -> c_int; + pub fn git_odb_stream_free(stream: *mut git_odb_stream); + pub fn git_odb_foreach(db: *mut git_odb, cb: git_odb_foreach_cb, payload: *mut c_void) -> c_int; + + pub fn git_odb_read(out: *mut *mut git_odb_object, + odb: *mut git_odb, + oid: *const git_oid) -> c_int; + + pub fn git_odb_read_header(len_out: *mut size_t, + type_out: *mut git_otype, + odb: *mut git_odb, + oid: *const git_oid) -> c_int; + + pub fn git_odb_write(out: *mut git_oid, + odb: *mut git_odb, + data: *const c_void, + len: size_t, + otype: git_otype) -> c_int; + + pub fn git_odb_hash(out: *mut git_oid, + data: *const c_void, + len: size_t, + otype: git_otype) -> c_int; + + pub fn git_odb_hashfile(out: *mut git_oid, + path: *const c_char, + otype: git_otype) -> c_int; + + pub fn git_odb_exists_prefix(out: *mut git_oid, + odb: *mut git_odb, + short_oid: *const git_oid, + len: size_t) -> c_int; + + pub fn git_odb_exists(odb: *mut git_odb, + oid: *const git_oid) -> c_int; + + pub fn git_odb_refresh(odb: *mut git_odb) -> c_int; + + pub fn git_odb_object_id(obj: *mut git_odb_object) -> *const git_oid; + pub fn git_odb_object_size(obj: *mut git_odb_object) -> size_t; + pub fn git_odb_object_type(obj: *mut git_odb_object) -> git_otype; + pub fn git_odb_object_data(obj: *mut git_odb_object) -> *const c_void; + pub fn git_odb_object_dup(out: *mut *mut git_odb_object, + obj: *mut git_odb_object) -> c_int; + pub fn git_odb_object_free(obj: *mut git_odb_object); + + pub fn git_odb_init_backend(odb: *mut git_odb_backend, + version: c_uint) -> c_int; + + pub fn git_odb_add_backend(odb: *mut git_odb, + backend: *mut git_odb_backend, + priority: c_int) -> c_int; + + pub fn git_odb_backend_pack(out: *mut *mut git_odb_backend, + objects_dir: *const c_char) -> c_int; + + pub fn git_odb_backend_one_pack(out: *mut *mut git_odb_backend, + objects_dir: *const c_char) -> c_int; + + pub fn git_odb_add_disk_alternate(odb: *mut git_odb, + path: *const c_char) -> c_int; + + pub fn git_odb_backend_loose(out: *mut *mut git_odb_backend, + objects_dir: *const c_char, + compression_level: c_int, + do_fsync: c_int, + dir_mode: c_uint, + file_mode: c_uint) -> c_int; + + pub fn git_odb_add_alternate(odb: *mut git_odb, + backend: *mut git_odb_backend, + priority: c_int) -> c_int; + + pub fn git_odb_backend_malloc(backend: *mut git_odb_backend, + len: size_t) -> *mut c_void; + + pub fn git_odb_num_backends(odb: *mut git_odb) -> size_t; + pub fn git_odb_get_backend(backend: *mut *mut git_odb_backend, + odb: *mut git_odb, + position: size_t) -> c_int; + + // mempack + pub fn git_mempack_new(out: *mut *mut git_odb_backend) -> c_int; + pub fn git_mempack_reset(backend: *mut git_odb_backend); + pub fn git_mempack_dump(pack: *mut git_buf, + repo: *mut git_repository, + backend: *mut git_odb_backend) -> c_int; + + // refdb + pub fn git_refdb_new(out: *mut *mut git_refdb, repo: *mut git_repository) -> c_int; + pub fn git_refdb_open(out: *mut *mut git_refdb, repo: *mut git_repository) -> c_int; + pub fn git_refdb_backend_fs(out: *mut *mut git_refdb_backend, repo: *mut git_repository) -> c_int; + pub fn git_refdb_init_backend(backend: *mut git_refdb_backend, version: c_uint) -> c_int; + pub fn git_refdb_set_backend(refdb: *mut git_refdb, backend: *mut git_refdb_backend) -> c_int; + pub fn git_refdb_compress(refdb: *mut git_refdb) -> c_int; + pub fn git_refdb_free(refdb: *mut git_refdb); + + // rebase + pub fn git_rebase_init_options(opts: *mut git_rebase_options, version: c_uint) -> c_int; + pub fn git_rebase_init(out: *mut *mut git_rebase, + repo: *mut git_repository, + branch: *const git_annotated_commit, + upstream: *const git_annotated_commit, + onto: *const git_annotated_commit, + opts: *const git_rebase_options) -> c_int; + pub fn git_rebase_open(out: *mut *mut git_rebase, repo: *mut git_repository, opts: *const git_rebase_options) -> c_int; + pub fn git_rebase_operation_entrycount(rebase: *mut git_rebase) -> size_t; + pub fn git_rebase_operation_current(rebase: *mut git_rebase) -> size_t; + pub fn git_rebase_operation_byindex(rebase: *mut git_rebase, idx: size_t) -> *mut git_rebase_operation; + pub fn git_rebase_next(operation: *mut *mut git_rebase_operation, rebase: *mut git_rebase) -> c_int; + pub fn git_rebase_inmemory_index(index: *mut *mut git_index, rebase: *mut git_rebase) -> c_int; + pub fn git_rebase_commit(id: *mut git_oid, + rebase: *mut git_rebase, + author: *const git_signature, + committer: *const git_signature, + message_encoding: *const c_char, + message: *const c_char) -> c_int; + pub fn git_rebase_abort(rebase: *mut git_rebase) -> c_int; + pub fn git_rebase_finish(rebase: *mut git_rebase, signature: *const git_signature) -> c_int; + pub fn git_rebase_free(rebase: *mut git_rebase); +} + +pub fn init() { + use std::sync::{Once, ONCE_INIT}; + + static INIT: Once = ONCE_INIT; + INIT.call_once(|| unsafe { + openssl_init(); + ssh_init(); + let r = git_libgit2_init(); + assert!(r >= 0, + "couldn't initialize the libgit2 library: {}", r); + + // Note that we intentionally never schedule `git_libgit2_shutdown` to + // get called. There's not really a great time to call that and #276 has + // some more info about how automatically doing it can cause problems. + }); +} + +#[cfg(all(unix, feature = "https"))] +#[doc(hidden)] +pub fn openssl_init() { + openssl_sys::init(); +} + +#[cfg(any(windows, not(feature = "https")))] +#[doc(hidden)] +pub fn openssl_init() {} + +#[cfg(feature = "ssh")] +fn ssh_init() { + libssh2::init(); +} + +#[cfg(not(feature = "ssh"))] +fn ssh_init() {} diff --git a/libnghttp2-sys/.cargo-checksum.json b/libnghttp2-sys/.cargo-checksum.json new file mode 100644 index 000000000..8a665e822 --- /dev/null +++ b/libnghttp2-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d75d7966bda4730b722d1eab8e668df445368a24394bae9fc1e8dc0ab3dbe4f4"} \ No newline at end of file diff --git a/libnghttp2-sys/.pc/.quilt_patches b/libnghttp2-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/libnghttp2-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/libnghttp2-sys/.pc/.quilt_series b/libnghttp2-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/libnghttp2-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/libnghttp2-sys/.pc/.version b/libnghttp2-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/libnghttp2-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/libnghttp2-sys/.pc/applied-patches b/libnghttp2-sys/.pc/applied-patches new file mode 100644 index 000000000..c5aaa710b --- /dev/null +++ b/libnghttp2-sys/.pc/applied-patches @@ -0,0 +1 @@ +use-system-lib.patch diff --git a/libnghttp2-sys/.pc/use-system-lib.patch/.timestamp b/libnghttp2-sys/.pc/use-system-lib.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/libnghttp2-sys/.pc/use-system-lib.patch/Cargo.toml b/libnghttp2-sys/.pc/use-system-lib.patch/Cargo.toml new file mode 100644 index 000000000..70b08e68b --- /dev/null +++ b/libnghttp2-sys/.pc/use-system-lib.patch/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libnghttp2-sys" +version = "0.1.1" +authors = ["Alex Crichton "] +links = "nghttp2" +description = "FFI bindings for libnghttp2 (nghttp2)\n" +homepage = "https://github.com/alexcrichton/nghttp2-rs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/nghttp2-rs" + +[lib] +doctest = false +[dependencies.libc] +version = "0.2" +[build-dependencies.cc] +version = "1.0.24" diff --git a/libnghttp2-sys/Cargo.toml b/libnghttp2-sys/Cargo.toml new file mode 100644 index 000000000..743d3f30a --- /dev/null +++ b/libnghttp2-sys/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libnghttp2-sys" +version = "0.1.1" +authors = ["Alex Crichton "] +links = "nghttp2" +description = "FFI bindings for libnghttp2 (nghttp2)\n" +homepage = "https://github.com/alexcrichton/nghttp2-rs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/nghttp2-rs" + +[lib] +doctest = false +[dependencies.libc] +version = "0.2" +[build-dependencies.pkg-config] +version = "0.3" diff --git a/libnghttp2-sys/LICENSE-APACHE b/libnghttp2-sys/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/libnghttp2-sys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libnghttp2-sys/LICENSE-MIT b/libnghttp2-sys/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/libnghttp2-sys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libnghttp2-sys/README.md b/libnghttp2-sys/README.md new file mode 100644 index 000000000..2555df586 --- /dev/null +++ b/libnghttp2-sys/README.md @@ -0,0 +1,52 @@ +# nghttp2-sys + +A common library for linking `nghttp2` to rust programs (also known as +libnghttp2). + +[![Build Status](https://travis-ci.com/alexcrichton/nghttp2-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/nghttp2-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/6au13yb0fkfckpjn/branch/master?svg=true)](https://ci.appveyor.com/project/alexcrichton/nghttp2-rs/branch/master) + +## Generating bindings + +Before `bindgen`: + +* Copy `nghttp2ver.h.in` to `nghttp2ver.h` +* Edit `nghttp2ver.h` to remove `@FOO@`, replacing with 0 + +```sh +$ bindgen \ + ./nghttp2/lib/includes/nghttp2/nghttp2.h \ + -o src/lib.rs \ + --no-layout-tests \ + --distrust-clang-mangling \ + --no-prepend-enum-name \ + --rustfmt-bindings \ + --whitelist-function '.*nghttp2.*' \ + --whitelist-type '.*nghttp2.*' \ + --whitelist-var '.*nghttp2.*' \ + -- \ + -I ./nghttp2/lib/includes +``` + +Afterwards + +* Remove `*vprintf*` +* Remove `va_list`-related things +* Add `#![allow(bad_style)]` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `nghttp2-sys` by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/libnghttp2-sys/build.rs b/libnghttp2-sys/build.rs new file mode 100644 index 000000000..e0f5612bd --- /dev/null +++ b/libnghttp2-sys/build.rs @@ -0,0 +1,7 @@ +extern crate pkg_config; + +pub fn main() { + if pkg_config::probe_library("libnghttp2").is_ok() { + return; + } +} diff --git a/libnghttp2-sys/build.rs.orig b/libnghttp2-sys/build.rs.orig new file mode 100644 index 000000000..2d46f2207 --- /dev/null +++ b/libnghttp2-sys/build.rs.orig @@ -0,0 +1,83 @@ +extern crate cc; + +use std::env; +use std::fs; +use std::path::PathBuf; + +const VERSION: &str = "1.33.90"; + +fn main() { + let target = env::var("TARGET").unwrap(); + let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let ver = fs::read_to_string("nghttp2/lib/includes/nghttp2/nghttp2ver.h.in") + .unwrap() + .replace("@PACKAGE_VERSION@", VERSION) + .replace("@PACKAGE_VERSION_NUM@", "0x01214a"); + + let install = out_dir.join("i"); + let include = install.join("include"); + let lib = install.join("lib"); + let pkgconfig = lib.join("pkgconfig"); + fs::create_dir_all(include.join("nghttp2")).unwrap(); + fs::create_dir_all(&pkgconfig).unwrap(); + fs::write(include.join("nghttp2/nghttp2ver.h"), ver).unwrap(); + + let mut cfg = cc::Build::new(); + cfg.include("nghttp2/lib/includes") + .include(&include) + .file("nghttp2/lib/nghttp2_buf.c") + .file("nghttp2/lib/nghttp2_callbacks.c") + .file("nghttp2/lib/nghttp2_debug.c") + .file("nghttp2/lib/nghttp2_frame.c") + .file("nghttp2/lib/nghttp2_hd.c") + .file("nghttp2/lib/nghttp2_hd_huffman.c") + .file("nghttp2/lib/nghttp2_hd_huffman_data.c") + .file("nghttp2/lib/nghttp2_helper.c") + .file("nghttp2/lib/nghttp2_http.c") + .file("nghttp2/lib/nghttp2_map.c") + .file("nghttp2/lib/nghttp2_mem.c") + .file("nghttp2/lib/nghttp2_npn.c") + .file("nghttp2/lib/nghttp2_option.c") + .file("nghttp2/lib/nghttp2_outbound_item.c") + .file("nghttp2/lib/nghttp2_pq.c") + .file("nghttp2/lib/nghttp2_priority_spec.c") + .file("nghttp2/lib/nghttp2_queue.c") + .file("nghttp2/lib/nghttp2_rcbuf.c") + .file("nghttp2/lib/nghttp2_session.c") + .file("nghttp2/lib/nghttp2_stream.c") + .file("nghttp2/lib/nghttp2_submit.c") + .file("nghttp2/lib/nghttp2_version.c") + .warnings(false) + .define("NGHTTP2_STATICLIB", None) + .define("HAVE_NETINET_IN", None) + .out_dir(&lib); + + if target.contains("windows") { + // Apparently MSVC doesn't have `ssize_t` defined as a type + if target.contains("msvc") { + match &env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap()[..] { + "64" => { cfg.define("ssize_t", "int64_t"); } + "32" => { cfg.define("ssize_t", "int32_t"); } + s => panic!("unknown pointer size: {}", s), + } + } + } else { + cfg.define("HAVE_ARPA_INET_H", None); + } + cfg.compile("nghttp2"); + + println!("cargo:root={}", install.display()); + + let pc = fs::read_to_string("nghttp2/lib/libnghttp2.pc.in") + .unwrap() + .replace("@prefix@", install.to_str().unwrap()) + .replace("@exec_prefix@", "") + .replace("@libdir@", lib.to_str().unwrap()) + .replace("@includedir@", include.to_str().unwrap()) + .replace("@VERSION@", VERSION); + fs::write(pkgconfig.join("libnghttp2.pc"), pc).unwrap(); + fs::copy( + "nghttp2/lib/includes/nghttp2/nghttp2.h", + include.join("nghttp2/nghttp2.h"), + ).unwrap(); +} diff --git a/libnghttp2-sys/debian/patches/series b/libnghttp2-sys/debian/patches/series new file mode 100644 index 000000000..c5aaa710b --- /dev/null +++ b/libnghttp2-sys/debian/patches/series @@ -0,0 +1 @@ +use-system-lib.patch diff --git a/libnghttp2-sys/debian/patches/use-system-lib.patch b/libnghttp2-sys/debian/patches/use-system-lib.patch new file mode 100644 index 000000000..3fd491a29 --- /dev/null +++ b/libnghttp2-sys/debian/patches/use-system-lib.patch @@ -0,0 +1,10 @@ +--- a/Cargo.toml 2018-12-07 21:23:58.793977939 -0800 ++++ b/Cargo.toml 2018-12-07 21:24:35.522546433 -0800 +@@ -25,5 +25,5 @@ + doctest = false + [dependencies.libc] + version = "0.2" +-[build-dependencies.cc] +-version = "1.0.24" ++[build-dependencies.pkg-config] ++version = "0.3" diff --git a/libnghttp2-sys/examples/smoke.rs b/libnghttp2-sys/examples/smoke.rs new file mode 100644 index 000000000..0a45f0153 --- /dev/null +++ b/libnghttp2-sys/examples/smoke.rs @@ -0,0 +1,7 @@ +extern crate libnghttp2_sys as ffi; + +fn main() { + unsafe { + ffi::nghttp2_version(0); + } +} diff --git a/libnghttp2-sys/src/lib.rs b/libnghttp2-sys/src/lib.rs new file mode 100644 index 000000000..2b85d3b1b --- /dev/null +++ b/libnghttp2-sys/src/lib.rs @@ -0,0 +1,4820 @@ +#![allow(bad_style)] +/* automatically generated by rust-bindgen, then hand edited */ + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_session { + _unused: [u8; 0], +} +/// @struct +/// +/// This struct is what `nghttp2_version()` returns. It holds +/// information about the particular nghttp2 version. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_info { + /// Age of this struct. This instance of nghttp2 sets it to + /// :macro:`NGHTTP2_VERSION_AGE` but a future version may bump it and + /// add more struct fields at the bottom + pub age: ::std::os::raw::c_int, + /// the :macro:`NGHTTP2_VERSION_NUM` number (since age ==1) + pub version_num: ::std::os::raw::c_int, + /// points to the :macro:`NGHTTP2_VERSION` string (since age ==1) + pub version_str: *const ::std::os::raw::c_char, + /// points to the :macro:`NGHTTP2_PROTO_VERSION_ID` string this + /// instance implements (since age ==1) + pub proto_str: *const ::std::os::raw::c_char, +} +/// Invalid argument passed. +pub const NGHTTP2_ERR_INVALID_ARGUMENT: nghttp2_error = -501; +/// Out of buffer space. +pub const NGHTTP2_ERR_BUFFER_ERROR: nghttp2_error = -502; +/// The specified protocol version is not supported. +pub const NGHTTP2_ERR_UNSUPPORTED_VERSION: nghttp2_error = -503; +/// Used as a return value from :type:`nghttp2_send_callback`, +/// :type:`nghttp2_recv_callback` and +/// :type:`nghttp2_send_data_callback` to indicate that the operation +/// would block. +pub const NGHTTP2_ERR_WOULDBLOCK: nghttp2_error = -504; +/// General protocol error +pub const NGHTTP2_ERR_PROTO: nghttp2_error = -505; +/// The frame is invalid. +pub const NGHTTP2_ERR_INVALID_FRAME: nghttp2_error = -506; +/// The peer performed a shutdown on the connection. +pub const NGHTTP2_ERR_EOF: nghttp2_error = -507; +/// Used as a return value from +/// :func:`nghttp2_data_source_read_callback` to indicate that data +/// transfer is postponed. See +/// :func:`nghttp2_data_source_read_callback` for details. +pub const NGHTTP2_ERR_DEFERRED: nghttp2_error = -508; +/// Stream ID has reached the maximum value. Therefore no stream ID +/// is available. +pub const NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE: nghttp2_error = -509; +/// The stream is already closed; or the stream ID is invalid. +pub const NGHTTP2_ERR_STREAM_CLOSED: nghttp2_error = -510; +/// RST_STREAM has been added to the outbound queue. The stream is +/// in closing state. +pub const NGHTTP2_ERR_STREAM_CLOSING: nghttp2_error = -511; +/// The transmission is not allowed for this stream (e.g., a frame +/// with END_STREAM flag set has already sent). +pub const NGHTTP2_ERR_STREAM_SHUT_WR: nghttp2_error = -512; +/// The stream ID is invalid. +pub const NGHTTP2_ERR_INVALID_STREAM_ID: nghttp2_error = -513; +/// The state of the stream is not valid (e.g., DATA cannot be sent +/// to the stream if response HEADERS has not been sent). +pub const NGHTTP2_ERR_INVALID_STREAM_STATE: nghttp2_error = -514; +/// Another DATA frame has already been deferred. +pub const NGHTTP2_ERR_DEFERRED_DATA_EXIST: nghttp2_error = -515; +/// Starting new stream is not allowed (e.g., GOAWAY has been sent +/// and/or received). +pub const NGHTTP2_ERR_START_STREAM_NOT_ALLOWED: nghttp2_error = -516; +/// GOAWAY has already been sent. +pub const NGHTTP2_ERR_GOAWAY_ALREADY_SENT: nghttp2_error = -517; +/// The received frame contains the invalid header block (e.g., There +/// are duplicate header names; or the header names are not encoded +/// in US-ASCII character set and not lower cased; or the header name +/// is zero-length string; or the header value contains multiple +/// in-sequence NUL bytes). +pub const NGHTTP2_ERR_INVALID_HEADER_BLOCK: nghttp2_error = -518; +/// Indicates that the context is not suitable to perform the +/// requested operation. +pub const NGHTTP2_ERR_INVALID_STATE: nghttp2_error = -519; +/// The user callback function failed due to the temporal error. +pub const NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: nghttp2_error = -521; +/// The length of the frame is invalid, either too large or too small. +pub const NGHTTP2_ERR_FRAME_SIZE_ERROR: nghttp2_error = -522; +/// Header block inflate/deflate error. +pub const NGHTTP2_ERR_HEADER_COMP: nghttp2_error = -523; +/// Flow control error +pub const NGHTTP2_ERR_FLOW_CONTROL: nghttp2_error = -524; +/// Insufficient buffer size given to function. +pub const NGHTTP2_ERR_INSUFF_BUFSIZE: nghttp2_error = -525; +/// Callback was paused by the application +pub const NGHTTP2_ERR_PAUSE: nghttp2_error = -526; +/// There are too many in-flight SETTING frame and no more +/// transmission of SETTINGS is allowed. +pub const NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS: nghttp2_error = -527; +/// The server push is disabled. +pub const NGHTTP2_ERR_PUSH_DISABLED: nghttp2_error = -528; +/// DATA or HEADERS frame for a given stream has been already +/// submitted and has not been fully processed yet. Application +/// should wait for the transmission of the previously submitted +/// frame before submitting another. +pub const NGHTTP2_ERR_DATA_EXIST: nghttp2_error = -529; +/// The current session is closing due to a connection error or +/// `nghttp2_session_terminate_session()` is called. +pub const NGHTTP2_ERR_SESSION_CLOSING: nghttp2_error = -530; +/// Invalid HTTP header field was received and stream is going to be +/// closed. +pub const NGHTTP2_ERR_HTTP_HEADER: nghttp2_error = -531; +/// Violation in HTTP messaging rule. +pub const NGHTTP2_ERR_HTTP_MESSAGING: nghttp2_error = -532; +/// Stream was refused. +pub const NGHTTP2_ERR_REFUSED_STREAM: nghttp2_error = -533; +/// Unexpected internal error, but recovered. +pub const NGHTTP2_ERR_INTERNAL: nghttp2_error = -534; +/// Indicates that a processing was canceled. +pub const NGHTTP2_ERR_CANCEL: nghttp2_error = -535; +/// When a local endpoint expects to receive SETTINGS frame, it +/// receives an other type of frame. +pub const NGHTTP2_ERR_SETTINGS_EXPECTED: nghttp2_error = -536; +/// The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is +/// under unexpected condition and processing was terminated (e.g., +/// out of memory). If application receives this error code, it must +/// stop using that :type:`nghttp2_session` object and only allowed +/// operation for that object is deallocate it using +/// `nghttp2_session_del()`. +pub const NGHTTP2_ERR_FATAL: nghttp2_error = -900; +/// Out of memory. This is a fatal error. +pub const NGHTTP2_ERR_NOMEM: nghttp2_error = -901; +/// The user callback function failed. This is a fatal error. +pub const NGHTTP2_ERR_CALLBACK_FAILURE: nghttp2_error = -902; +/// Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was +/// received and further processing is not possible. +pub const NGHTTP2_ERR_BAD_CLIENT_MAGIC: nghttp2_error = -903; +/// Possible flooding by peer was detected in this HTTP/2 session. +/// Flooding is measured by how many PING and SETTINGS frames with +/// ACK flag set are queued for transmission. These frames are +/// response for the peer initiated frames, and peer can cause memory +/// exhaustion on server side to send these frames forever and does +/// not read network. +pub const NGHTTP2_ERR_FLOODED: nghttp2_error = -904; +/// @enum +/// +/// Error codes used in this library. The code range is [-999, -500], +/// inclusive. The following values are defined: +pub type nghttp2_error = i32; +/// @struct +/// +/// The object representing single contiguous buffer. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_vec { + /// The pointer to the buffer. + pub base: *mut u8, + /// The length of the buffer. + pub len: usize, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_rcbuf { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Increments the reference count of |rcbuf| by 1. + pub fn nghttp2_rcbuf_incref(rcbuf: *mut nghttp2_rcbuf); +} +extern "C" { + /// @function + /// + /// Decrements the reference count of |rcbuf| by 1. If the reference + /// count becomes zero, the object pointed by |rcbuf| will be freed. + /// In this case, application must not use |rcbuf| again. + pub fn nghttp2_rcbuf_decref(rcbuf: *mut nghttp2_rcbuf); +} +extern "C" { + /// @function + /// + /// Returns the underlying buffer managed by |rcbuf|. + pub fn nghttp2_rcbuf_get_buf(rcbuf: *mut nghttp2_rcbuf) -> nghttp2_vec; +} +extern "C" { + /// @function + /// + /// Returns nonzero if the underlying buffer is statically allocated, + /// and 0 otherwise. This can be useful for language bindings that wish + /// to avoid creating duplicate strings for these buffers. + pub fn nghttp2_rcbuf_is_static(rcbuf: *const nghttp2_rcbuf) -> ::std::os::raw::c_int; +} +/// No flag set. +pub const NGHTTP2_NV_FLAG_NONE: nghttp2_nv_flag = 0; +/// Indicates that this name/value pair must not be indexed ("Literal +/// Header Field never Indexed" representation must be used in HPACK +/// encoding). Other implementation calls this bit as "sensitive". +pub const NGHTTP2_NV_FLAG_NO_INDEX: nghttp2_nv_flag = 1; +/// This flag is set solely by application. If this flag is set, the +/// library does not make a copy of header field name. This could +/// improve performance. +pub const NGHTTP2_NV_FLAG_NO_COPY_NAME: nghttp2_nv_flag = 2; +/// This flag is set solely by application. If this flag is set, the +/// library does not make a copy of header field value. This could +/// improve performance. +pub const NGHTTP2_NV_FLAG_NO_COPY_VALUE: nghttp2_nv_flag = 4; +/// @enum +/// +/// The flags for header field name/value pair. +pub type nghttp2_nv_flag = u32; +/// @struct +/// +/// The name/value pair, which mainly used to represent header fields. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_nv { + /// The |name| byte string. If this struct is presented from library + /// (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is + /// guaranteed to be NULL-terminated. For some callbacks + /// (:type:`nghttp2_before_frame_send_callback`, + /// :type:`nghttp2_on_frame_send_callback`, and + /// :type:`nghttp2_on_frame_not_send_callback`), it may not be + /// NULL-terminated if header field is passed from application with + /// the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`). When application + /// is constructing this struct, |name| is not required to be + /// NULL-terminated. + pub name: *mut u8, + /// The |value| byte string. If this struct is presented from + /// library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value| + /// is guaranteed to be NULL-terminated. For some callbacks + /// (:type:`nghttp2_before_frame_send_callback`, + /// :type:`nghttp2_on_frame_send_callback`, and + /// :type:`nghttp2_on_frame_not_send_callback`), it may not be + /// NULL-terminated if header field is passed from application with + /// the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`). When + /// application is constructing this struct, |value| is not required + /// to be NULL-terminated. + pub value: *mut u8, + /// The length of the |name|, excluding terminating NULL. + pub namelen: usize, + /// The length of the |value|, excluding terminating NULL. + pub valuelen: usize, + /// Bitwise OR of one or more of :type:`nghttp2_nv_flag`. + pub flags: u8, +} +/// The DATA frame. +pub const NGHTTP2_DATA: nghttp2_frame_type = 0; +/// The HEADERS frame. +pub const NGHTTP2_HEADERS: nghttp2_frame_type = 1; +/// The PRIORITY frame. +pub const NGHTTP2_PRIORITY: nghttp2_frame_type = 2; +/// The RST_STREAM frame. +pub const NGHTTP2_RST_STREAM: nghttp2_frame_type = 3; +/// The SETTINGS frame. +pub const NGHTTP2_SETTINGS: nghttp2_frame_type = 4; +/// The PUSH_PROMISE frame. +pub const NGHTTP2_PUSH_PROMISE: nghttp2_frame_type = 5; +/// The PING frame. +pub const NGHTTP2_PING: nghttp2_frame_type = 6; +/// The GOAWAY frame. +pub const NGHTTP2_GOAWAY: nghttp2_frame_type = 7; +/// The WINDOW_UPDATE frame. +pub const NGHTTP2_WINDOW_UPDATE: nghttp2_frame_type = 8; +/// The CONTINUATION frame. This frame type won't be passed to any +/// callbacks because the library processes this frame type and its +/// preceding HEADERS/PUSH_PROMISE as a single frame. +pub const NGHTTP2_CONTINUATION: nghttp2_frame_type = 9; +/// The ALTSVC frame, which is defined in `RFC 7383 +/// `_. +pub const NGHTTP2_ALTSVC: nghttp2_frame_type = 10; +/// The ORIGIN frame, which is defined by `RFC 8336 +/// `_. +pub const NGHTTP2_ORIGIN: nghttp2_frame_type = 12; +/// @enum +/// +/// The frame types in HTTP/2 specification. +pub type nghttp2_frame_type = u32; +/// No flag set. +pub const NGHTTP2_FLAG_NONE: nghttp2_flag = 0; +/// The END_STREAM flag. +pub const NGHTTP2_FLAG_END_STREAM: nghttp2_flag = 1; +/// The END_HEADERS flag. +pub const NGHTTP2_FLAG_END_HEADERS: nghttp2_flag = 4; +/// The ACK flag. +pub const NGHTTP2_FLAG_ACK: nghttp2_flag = 1; +/// The PADDED flag. +pub const NGHTTP2_FLAG_PADDED: nghttp2_flag = 8; +/// The PRIORITY flag. +pub const NGHTTP2_FLAG_PRIORITY: nghttp2_flag = 32; +/// @enum +/// +/// The flags for HTTP/2 frames. This enum defines all flags for all +/// frames. +pub type nghttp2_flag = u32; +/// SETTINGS_HEADER_TABLE_SIZE +pub const NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: nghttp2_settings_id = 1; +/// SETTINGS_ENABLE_PUSH +pub const NGHTTP2_SETTINGS_ENABLE_PUSH: nghttp2_settings_id = 2; +/// SETTINGS_MAX_CONCURRENT_STREAMS +pub const NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: nghttp2_settings_id = 3; +/// SETTINGS_INITIAL_WINDOW_SIZE +pub const NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: nghttp2_settings_id = 4; +/// SETTINGS_MAX_FRAME_SIZE +pub const NGHTTP2_SETTINGS_MAX_FRAME_SIZE: nghttp2_settings_id = 5; +/// SETTINGS_MAX_HEADER_LIST_SIZE +pub const NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: nghttp2_settings_id = 6; +/// @enum +/// The SETTINGS ID. +pub type nghttp2_settings_id = u32; +/// No errors. +pub const NGHTTP2_NO_ERROR: nghttp2_error_code = 0; +/// PROTOCOL_ERROR +pub const NGHTTP2_PROTOCOL_ERROR: nghttp2_error_code = 1; +/// INTERNAL_ERROR +pub const NGHTTP2_INTERNAL_ERROR: nghttp2_error_code = 2; +/// FLOW_CONTROL_ERROR +pub const NGHTTP2_FLOW_CONTROL_ERROR: nghttp2_error_code = 3; +/// SETTINGS_TIMEOUT +pub const NGHTTP2_SETTINGS_TIMEOUT: nghttp2_error_code = 4; +/// STREAM_CLOSED +pub const NGHTTP2_STREAM_CLOSED: nghttp2_error_code = 5; +/// FRAME_SIZE_ERROR +pub const NGHTTP2_FRAME_SIZE_ERROR: nghttp2_error_code = 6; +/// REFUSED_STREAM +pub const NGHTTP2_REFUSED_STREAM: nghttp2_error_code = 7; +/// CANCEL +pub const NGHTTP2_CANCEL: nghttp2_error_code = 8; +/// COMPRESSION_ERROR +pub const NGHTTP2_COMPRESSION_ERROR: nghttp2_error_code = 9; +/// CONNECT_ERROR +pub const NGHTTP2_CONNECT_ERROR: nghttp2_error_code = 10; +/// ENHANCE_YOUR_CALM +pub const NGHTTP2_ENHANCE_YOUR_CALM: nghttp2_error_code = 11; +/// INADEQUATE_SECURITY +pub const NGHTTP2_INADEQUATE_SECURITY: nghttp2_error_code = 12; +/// HTTP_1_1_REQUIRED +pub const NGHTTP2_HTTP_1_1_REQUIRED: nghttp2_error_code = 13; +/// @enum +/// The status codes for the RST_STREAM and GOAWAY frames. +pub type nghttp2_error_code = u32; +/// @struct +/// The frame header. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_frame_hd { + /// The length field of this frame, excluding frame header. + pub length: usize, + /// The stream identifier (aka, stream ID) + pub stream_id: i32, + /// The type of this frame. See `nghttp2_frame_type`. + pub type_: u8, + /// The flags. + pub flags: u8, + /// Reserved bit in frame header. Currently, this is always set to 0 + /// and application should not expect something useful in here. + pub reserved: u8, +} +/// @union +/// +/// This union represents the some kind of data source passed to +/// :type:`nghttp2_data_source_read_callback`. +#[repr(C)] +#[derive(Copy, Clone)] +pub union nghttp2_data_source { + /// The integer field, suitable for a file descriptor. + pub fd: ::std::os::raw::c_int, + /// The pointer to an arbitrary object. + pub ptr: *mut ::std::os::raw::c_void, + _bindgen_union_align: u64, +} +/// No flag set. +pub const NGHTTP2_DATA_FLAG_NONE: nghttp2_data_flag = 0; +/// Indicates EOF was sensed. +pub const NGHTTP2_DATA_FLAG_EOF: nghttp2_data_flag = 1; +/// Indicates that END_STREAM flag must not be set even if +/// NGHTTP2_DATA_FLAG_EOF is set. Usually this flag is used to send +/// trailer fields with `nghttp2_submit_request()` or +/// `nghttp2_submit_response()`. +pub const NGHTTP2_DATA_FLAG_NO_END_STREAM: nghttp2_data_flag = 2; +/// Indicates that application will send complete DATA frame in +/// :type:`nghttp2_send_data_callback`. +pub const NGHTTP2_DATA_FLAG_NO_COPY: nghttp2_data_flag = 4; +/// @enum +/// +/// The flags used to set in |data_flags| output parameter in +/// :type:`nghttp2_data_source_read_callback`. +pub type nghttp2_data_flag = u32; +/// @functypedef +/// +/// Callback function invoked when the library wants to read data from +/// the |source|. The read data is sent in the stream |stream_id|. +/// The implementation of this function must read at most |length| +/// bytes of data from |source| (or possibly other places) and store +/// them in |buf| and return number of data stored in |buf|. If EOF is +/// reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|. +/// +/// Sometime it is desirable to avoid copying data into |buf| and let +/// application to send data directly. To achieve this, set +/// :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly +/// other flags, just like when we do copy), and return the number of +/// bytes to send without copying data into |buf|. The library, seeing +/// :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke +/// :type:`nghttp2_send_data_callback`. The application must send +/// complete DATA frame in that callback. +/// +/// If this callback is set by `nghttp2_submit_request()`, +/// `nghttp2_submit_response()` or `nghttp2_submit_headers()` and +/// `nghttp2_submit_data()` with flag parameter +/// :enum:`NGHTTP2_FLAG_END_STREAM` set, and +/// :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA +/// frame will have END_STREAM flag set. Usually, this is expected +/// behaviour and all are fine. One exception is send trailer fields. +/// You cannot send trailer fields after sending frame with END_STREAM +/// set. To avoid this problem, one can set +/// :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with +/// :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set +/// END_STREAM in DATA frame. Then application can use +/// `nghttp2_submit_trailer()` to send trailer fields. +/// `nghttp2_submit_trailer()` can be called inside this callback. +/// +/// If the application wants to postpone DATA frames (e.g., +/// asynchronous I/O, or reading data blocks for long time), it is +/// achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading +/// any data in this invocation. The library removes DATA frame from +/// the outgoing queue temporarily. To move back deferred DATA frame +/// to outgoing queue, call `nghttp2_session_resume_data()`. +/// +/// By default, |length| is limited to 16KiB at maximum. If peer +/// allows larger frames, application can enlarge transmission buffer +/// size. See :type:`nghttp2_data_source_read_length_callback` for +/// more details. +/// +/// If the application just wants to return from +/// `nghttp2_session_send()` or `nghttp2_session_mem_send()` without +/// sending anything, return :enum:`NGHTTP2_ERR_PAUSE`. +/// +/// In case of error, there are 2 choices. Returning +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream +/// by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a +/// different error code is desirable, use +/// `nghttp2_submit_rst_stream()` with a desired error code and then +/// return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Returning +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session +/// failure. +pub type nghttp2_data_source_read_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + stream_id: i32, + buf: *mut u8, + length: usize, + data_flags: *mut u32, + source: *mut nghttp2_data_source, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @struct +/// +/// This struct represents the data source and the way to read a chunk +/// of data from it. +#[repr(C)] +#[derive(Copy, Clone)] +pub struct nghttp2_data_provider { + /// The data source. + pub source: nghttp2_data_source, + /// The callback function to read a chunk of data from the |source|. + pub read_callback: nghttp2_data_source_read_callback, +} +/// @struct +/// +/// The DATA frame. The received data is delivered via +/// :type:`nghttp2_on_data_chunk_recv_callback`. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_data { + pub hd: nghttp2_frame_hd, + /// The length of the padding in this frame. This includes PAD_HIGH + /// and PAD_LOW. + pub padlen: usize, +} +/// The HEADERS frame is opening new stream, which is analogous to +/// SYN_STREAM in SPDY. +pub const NGHTTP2_HCAT_REQUEST: nghttp2_headers_category = 0; +/// The HEADERS frame is the first response headers, which is +/// analogous to SYN_REPLY in SPDY. +pub const NGHTTP2_HCAT_RESPONSE: nghttp2_headers_category = 1; +/// The HEADERS frame is the first headers sent against reserved +/// stream. +pub const NGHTTP2_HCAT_PUSH_RESPONSE: nghttp2_headers_category = 2; +/// The HEADERS frame which does not apply for the above categories, +/// which is analogous to HEADERS in SPDY. If non-final response +/// (e.g., status 1xx) is used, final response HEADERS frame will be +/// categorized here. +pub const NGHTTP2_HCAT_HEADERS: nghttp2_headers_category = 3; +/// @enum +/// +/// The category of HEADERS, which indicates the role of the frame. In +/// HTTP/2 spec, request, response, push response and other arbitrary +/// headers (e.g., trailer fields) are all called just HEADERS. To +/// give the application the role of incoming HEADERS frame, we define +/// several categories. +pub type nghttp2_headers_category = u32; +/// @struct +/// +/// The structure to specify stream dependency. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_priority_spec { + /// The stream ID of the stream to depend on. Specifying 0 makes + /// stream not depend any other stream. + pub stream_id: i32, + /// The weight of this dependency. + pub weight: i32, + /// nonzero means exclusive dependency + pub exclusive: u8, +} +/// @struct +/// +/// The HEADERS frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_headers { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The length of the padding in this frame. This includes PAD_HIGH + /// and PAD_LOW. + pub padlen: usize, + /// The priority specification + pub pri_spec: nghttp2_priority_spec, + /// The name/value pairs. + pub nva: *mut nghttp2_nv, + /// The number of name/value pairs in |nva|. + pub nvlen: usize, + /// The category of this HEADERS frame. + pub cat: nghttp2_headers_category, +} +/// @struct +/// +/// The PRIORITY frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_priority { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The priority specification. + pub pri_spec: nghttp2_priority_spec, +} +/// @struct +/// +/// The RST_STREAM frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_rst_stream { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The error code. See :type:`nghttp2_error_code`. + pub error_code: u32, +} +/// @struct +/// +/// The SETTINGS ID/Value pair. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_settings_entry { + /// The SETTINGS ID. See :type:`nghttp2_settings_id`. + pub settings_id: i32, + /// The value of this entry. + pub value: u32, +} +/// @struct +/// +/// The SETTINGS frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_settings { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The number of SETTINGS ID/Value pairs in |iv|. + pub niv: usize, + /// The pointer to the array of SETTINGS ID/Value pair. + pub iv: *mut nghttp2_settings_entry, +} +/// @struct +/// +/// The PUSH_PROMISE frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_push_promise { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The length of the padding in this frame. This includes PAD_HIGH + /// and PAD_LOW. + pub padlen: usize, + /// The name/value pairs. + pub nva: *mut nghttp2_nv, + /// The number of name/value pairs in |nva|. + pub nvlen: usize, + /// The promised stream ID + pub promised_stream_id: i32, + /// Reserved bit. Currently this is always set to 0 and application + /// should not expect something useful in here. + pub reserved: u8, +} +/// @struct +/// +/// The PING frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_ping { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The opaque data + pub opaque_data: [u8; 8usize], +} +/// @struct +/// +/// The GOAWAY frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_goaway { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The last stream stream ID. + pub last_stream_id: i32, + /// The error code. See :type:`nghttp2_error_code`. + pub error_code: u32, + /// The additional debug data + pub opaque_data: *mut u8, + /// The length of |opaque_data| member. + pub opaque_data_len: usize, + /// Reserved bit. Currently this is always set to 0 and application + /// should not expect something useful in here. + pub reserved: u8, +} +/// @struct +/// +/// The WINDOW_UPDATE frame. It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_window_update { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The window size increment. + pub window_size_increment: i32, + /// Reserved bit. Currently this is always set to 0 and application + /// should not expect something useful in here. + pub reserved: u8, +} +/// @struct +/// +/// The extension frame. It has following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_extension { + /// The frame header. + pub hd: nghttp2_frame_hd, + /// The pointer to extension payload. The exact pointer type is + /// determined by hd.type. + /// + /// Currently, no extension is supported. This is a place holder for + /// the future extensions. + pub payload: *mut ::std::os::raw::c_void, +} +/// @union +/// +/// This union includes all frames to pass them to various function +/// calls as nghttp2_frame type. The CONTINUATION frame is omitted +/// from here because the library deals with it internally. +#[repr(C)] +#[derive(Copy, Clone)] +pub union nghttp2_frame { + /// The frame header, which is convenient to inspect frame header. + pub hd: nghttp2_frame_hd, + /// The DATA frame. + pub data: nghttp2_data, + /// The HEADERS frame. + pub headers: nghttp2_headers, + /// The PRIORITY frame. + pub priority: nghttp2_priority, + /// The RST_STREAM frame. + pub rst_stream: nghttp2_rst_stream, + /// The SETTINGS frame. + pub settings: nghttp2_settings, + /// The PUSH_PROMISE frame. + pub push_promise: nghttp2_push_promise, + /// The PING frame. + pub ping: nghttp2_ping, + /// The GOAWAY frame. + pub goaway: nghttp2_goaway, + /// The WINDOW_UPDATE frame. + pub window_update: nghttp2_window_update, + /// The extension frame. + pub ext: nghttp2_extension, + _bindgen_union_align: [u64; 8usize], +} +/// @functypedef +/// +/// Callback function invoked when |session| wants to send data to the +/// remote peer. The implementation of this function must send at most +/// |length| bytes of data stored in |data|. The |flags| is currently +/// not used and always 0. It must return the number of bytes sent if +/// it succeeds. If it cannot send any single byte without blocking, +/// it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`. For other errors, +/// it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The +/// |user_data| pointer is the third argument passed in to the call to +/// `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. +/// +/// This callback is required if the application uses +/// `nghttp2_session_send()` to send data to the remote endpoint. If +/// the application uses solely `nghttp2_session_mem_send()` instead, +/// this callback function is unnecessary. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_send_callback()`. +/// +/// .. note:: +/// +/// The |length| may be very small. If that is the case, and +/// application disables Nagle algorithm (``TCP_NODELAY``), then just +/// writing |data| to the network stack leads to very small packet, +/// and it is very inefficient. An application should be responsible +/// to buffer up small chunks of data as necessary to avoid this +/// situation. +pub type nghttp2_send_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + data: *const u8, + length: usize, + flags: ::std::os::raw::c_int, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @functypedef +/// +/// Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is +/// used in :type:`nghttp2_data_source_read_callback` to send complete +/// DATA frame. +/// +/// The |frame| is a DATA frame to send. The |framehd| is the +/// serialized frame header (9 bytes). The |length| is the length of +/// application data to send (this does not include padding). The +/// |source| is the same pointer passed to +/// :type:`nghttp2_data_source_read_callback`. +/// +/// The application first must send frame header |framehd| of length 9 +/// bytes. If ``frame->data.padlen > 0``, send 1 byte of value +/// ``frame->data.padlen - 1``. Then send exactly |length| bytes of +/// application data. Finally, if ``frame->data.padlen > 1``, send +/// ``frame->data.padlen - 1`` bytes of zero as padding. +/// +/// The application has to send complete DATA frame in this callback. +/// If all data were written successfully, return 0. +/// +/// If it cannot send any data at all, just return +/// :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback +/// with the same parameters later (It is recommended to send complete +/// DATA frame at once in this function to deal with error; if partial +/// frame data has already sent, it is impossible to send another data +/// in that state, and all we can do is tear down connection). When +/// data is fully processed, but application wants to make +/// `nghttp2_session_mem_send()` or `nghttp2_session_send()` return +/// immediately without processing next frames, return +/// :enum:`NGHTTP2_ERR_PAUSE`. If application decided to reset this +/// stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then +/// the library will send RST_STREAM with INTERNAL_ERROR as error code. +/// The application can also return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in +/// connection closure. Returning any other value is treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. +pub type nghttp2_send_data_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *mut nghttp2_frame, + framehd: *const u8, + length: usize, + source: *mut nghttp2_data_source, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when |session| wants to receive data from +/// the remote peer. The implementation of this function must read at +/// most |length| bytes of data and store it in |buf|. The |flags| is +/// currently not used and always 0. It must return the number of +/// bytes written in |buf| if it succeeds. If it cannot read any +/// single byte without blocking, it must return +/// :enum:`NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF before it reads any +/// single byte, it must return :enum:`NGHTTP2_ERR_EOF`. For other +/// errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`. The +/// |user_data| pointer is the third argument passed in to the call to +/// `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. +/// +/// This callback is required if the application uses +/// `nghttp2_session_recv()` to receive data from the remote endpoint. +/// If the application uses solely `nghttp2_session_mem_recv()` +/// instead, this callback function is unnecessary. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_recv_callback()`. +pub type nghttp2_recv_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + buf: *mut u8, + length: usize, + flags: ::std::os::raw::c_int, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @functypedef +/// +/// Callback function invoked by `nghttp2_session_recv()` and +/// `nghttp2_session_mem_recv()` when a frame is received. The +/// |user_data| pointer is the third argument passed in to the call to +/// `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. +/// +/// If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` +/// member of their data structure are always ``NULL`` and 0 +/// respectively. The header name/value pairs are emitted via +/// :type:`nghttp2_on_header_callback`. +/// +/// For HEADERS, PUSH_PROMISE and DATA frames, this callback may be +/// called after stream is closed (see +/// :type:`nghttp2_on_stream_close_callback`). The application should +/// check that stream is still alive using its own stream management or +/// :func:`nghttp2_session_get_stream_user_data()`. +/// +/// Only HEADERS and DATA frame can signal the end of incoming data. +/// If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the +/// |frame| is the last frame from the remote peer in this stream. +/// +/// This callback won't be called for CONTINUATION frames. +/// HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero value is returned, it is treated as fatal error and +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_frame_recv_callback()`. +pub type nghttp2_on_frame_recv_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked by `nghttp2_session_recv()` and +/// `nghttp2_session_mem_recv()` when an invalid non-DATA frame is +/// received. The error is indicated by the |lib_error_code|, which is +/// one of the values defined in :type:`nghttp2_error`. When this +/// callback function is invoked, the library automatically submits +/// either RST_STREAM or GOAWAY frame. The |user_data| pointer is the +/// third argument passed in to the call to +/// `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. +/// +/// If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen`` +/// member of their data structure are always ``NULL`` and 0 +/// respectively. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero is returned, it is treated as fatal error and +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`. +pub type nghttp2_on_invalid_frame_recv_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + lib_error_code: ::std::os::raw::c_int, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when a chunk of data in DATA frame is +/// received. The |stream_id| is the stream ID this DATA frame belongs +/// to. The |flags| is the flags of DATA frame which this data chunk +/// is contained. ``(flags & NGHTTP2_FLAG_END_STREAM) != 0`` does not +/// necessarily mean this chunk of data is the last one in the stream. +/// You should use :type:`nghttp2_on_frame_recv_callback` to know all +/// data frames are received. The |user_data| pointer is the third +/// argument passed in to the call to `nghttp2_session_client_new()` or +/// `nghttp2_session_server_new()`. +/// +/// If the application uses `nghttp2_session_mem_recv()`, it can return +/// :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` +/// return without processing further input bytes. The memory by +/// pointed by the |data| is retained until +/// `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. +/// The application must retain the input bytes which was used to +/// produce the |data| parameter, because it may refer to the memory +/// region included in the input bytes. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero is returned, it is treated as fatal error, and +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`. +pub type nghttp2_on_data_chunk_recv_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + data: *const u8, + len: usize, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked just before the non-DATA frame |frame| is +/// sent. The |user_data| pointer is the third argument passed in to +/// the call to `nghttp2_session_client_new()` or +/// `nghttp2_session_server_new()`. +/// +/// The implementation of this function must return 0 if it succeeds. +/// It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the +/// transmission of the given frame. +/// +/// If there is a fatal error while executing this callback, the +/// implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, +/// which makes `nghttp2_session_send()` and +/// `nghttp2_session_mem_send()` functions immediately return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// If the other value is returned, it is treated as if +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. But the +/// implementation should not rely on this since the library may define +/// new return value to extend its capability. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_before_frame_send_callback()`. +pub type nghttp2_before_frame_send_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked after the frame |frame| is sent. The +/// |user_data| pointer is the third argument passed in to the call to +/// `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero is returned, it is treated as fatal error and +/// `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_frame_send_callback()`. +pub type nghttp2_on_frame_send_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked after the non-DATA frame |frame| is not +/// sent because of the error. The error is indicated by the +/// |lib_error_code|, which is one of the values defined in +/// :type:`nghttp2_error`. The |user_data| pointer is the third +/// argument passed in to the call to `nghttp2_session_client_new()` or +/// `nghttp2_session_server_new()`. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero is returned, it is treated as fatal error and +/// `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// `nghttp2_session_get_stream_user_data()` can be used to get +/// associated data. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_frame_not_send_callback()`. +pub type nghttp2_on_frame_not_send_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + lib_error_code: ::std::os::raw::c_int, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when the stream |stream_id| is closed. +/// The reason of closure is indicated by the |error_code|. The +/// |error_code| is usually one of :enum:`nghttp2_error_code`, but that +/// is not guaranteed. The stream_user_data, which was specified in +/// `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still +/// available in this function. The |user_data| pointer is the third +/// argument passed in to the call to `nghttp2_session_client_new()` or +/// `nghttp2_session_server_new()`. +/// +/// This function is also called for a stream in reserved state. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero is returned, it is treated as fatal error and +/// `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`, +/// `nghttp2_session_send()`, and `nghttp2_session_mem_send()` +/// functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_stream_close_callback()`. +pub type nghttp2_on_stream_close_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + stream_id: i32, + error_code: u32, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when the reception of header block in +/// HEADERS or PUSH_PROMISE is started. Each header name/value pair +/// will be emitted by :type:`nghttp2_on_header_callback`. +/// +/// The ``frame->hd.flags`` may not have +/// :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one +/// or more CONTINUATION frames are involved. But the application does +/// not need to care about that because the header name/value pairs are +/// emitted transparently regardless of CONTINUATION frames. +/// +/// The server applications probably create an object to store +/// information about new stream if ``frame->hd.type == +/// NGHTTP2_HEADERS`` and ``frame->headers.cat == +/// NGHTTP2_HCAT_REQUEST``. If |session| is configured as server side, +/// ``frame->headers.cat`` is either ``NGHTTP2_HCAT_REQUEST`` +/// containing request headers or ``NGHTTP2_HCAT_HEADERS`` containing +/// trailer fields and never get PUSH_PROMISE in this callback. +/// +/// For the client applications, ``frame->hd.type`` is either +/// ``NGHTTP2_HEADERS`` or ``NGHTTP2_PUSH_PROMISE``. In case of +/// ``NGHTTP2_HEADERS``, ``frame->headers.cat == +/// NGHTTP2_HCAT_RESPONSE`` means that it is the first response +/// headers, but it may be non-final response which is indicated by 1xx +/// status code. In this case, there may be zero or more HEADERS frame +/// with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` which has +/// non-final response code and finally client gets exactly one HEADERS +/// frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` +/// containing final response headers (non-1xx status code). The +/// trailer fields also has ``frame->headers.cat == +/// NGHTTP2_HCAT_HEADERS`` which does not contain any status code. +/// +/// Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close +/// the stream (promised stream if frame is PUSH_PROMISE) by issuing +/// RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, +/// :type:`nghttp2_on_header_callback` and +/// :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a +/// different error code is desirable, use +/// `nghttp2_submit_rst_stream()` with a desired error code and then +/// return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use +/// ``frame->push_promise.promised_stream_id`` as stream_id parameter +/// in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. +/// +/// The implementation of this function must return 0 if it succeeds. +/// It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to +/// reset the stream (promised stream if frame is PUSH_PROMISE). For +/// critical errors, it must return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the other value is +/// returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` +/// is returned. If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, +/// `nghttp2_session_mem_recv()` function will immediately return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_begin_headers_callback()`. +pub type nghttp2_on_begin_headers_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when a header name/value pair is received +/// for the |frame|. The |name| of length |namelen| is header name. +/// The |value| of length |valuelen| is header value. The |flags| is +/// bitwise OR of one or more of :type:`nghttp2_nv_flag`. +/// +/// If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver +/// must not index this name/value pair when forwarding it to the next +/// hop. More specifically, "Literal Header Field never Indexed" +/// representation must be used in HPACK encoding. +/// +/// When this callback is invoked, ``frame->hd.type`` is either +/// :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all +/// header name/value pairs are processed with this callback, and no +/// error has been detected, :type:`nghttp2_on_frame_recv_callback` +/// will be invoked. If there is an error in decompression, +/// :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be +/// invoked. +/// +/// Both |name| and |value| are guaranteed to be NULL-terminated. The +/// |namelen| and |valuelen| do not include terminal NULL. If +/// `nghttp2_option_set_no_http_messaging()` is used with nonzero +/// value, NULL character may be included in |name| or |value| before +/// terminating NULL. +/// +/// Please note that unless `nghttp2_option_set_no_http_messaging()` is +/// used, nghttp2 library does perform validation against the |name| +/// and the |value| using `nghttp2_check_header_name()` and +/// `nghttp2_check_header_value()`. In addition to this, nghttp2 +/// performs validation based on HTTP Messaging rule, which is briefly +/// explained in :ref:`http-messaging` section. +/// +/// If the application uses `nghttp2_session_mem_recv()`, it can return +/// :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` +/// return without processing further input bytes. The memory pointed +/// by |frame|, |name| and |value| parameters are retained until +/// `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. +/// The application must retain the input bytes which was used to +/// produce these parameters, because it may refer to the memory region +/// included in the input bytes. +/// +/// Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close +/// the stream (promised stream if frame is PUSH_PROMISE) by issuing +/// RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, +/// :type:`nghttp2_on_header_callback` and +/// :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a +/// different error code is desirable, use +/// `nghttp2_submit_rst_stream()` with a desired error code and then +/// return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use +/// ``frame->push_promise.promised_stream_id`` as stream_id parameter +/// in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. +/// +/// The implementation of this function must return 0 if it succeeds. +/// It may return :enum:`NGHTTP2_ERR_PAUSE` or +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical +/// failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If +/// the other nonzero value is returned, it is treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_header_callback()`. +/// +/// .. warning:: +/// +/// Application should properly limit the total buffer size to store +/// incoming header fields. Without it, peer may send large number +/// of header fields or large header fields to cause out of memory in +/// local endpoint. Due to how HPACK works, peer can do this +/// effectively without using much memory on their own. +pub type nghttp2_on_header_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + name: *const u8, + namelen: usize, + value: *const u8, + valuelen: usize, + flags: u8, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when a header name/value pair is received +/// for the |frame|. The |name| is header name. The |value| is header +/// value. The |flags| is bitwise OR of one or more of +/// :type:`nghttp2_nv_flag`. +/// +/// This callback behaves like :type:`nghttp2_on_header_callback`, +/// except that |name| and |value| are stored in reference counted +/// buffer. If application wishes to keep these references without +/// copying them, use `nghttp2_rcbuf_incref()` to increment their +/// reference count. It is the application's responsibility to call +/// `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so +/// as not to leak memory. If the |session| is created by +/// `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`, +/// the function to free memory is the one belongs to the mem +/// parameter. As long as this free function alives, |name| and +/// |value| can live after |session| was destroyed. +pub type nghttp2_on_header_callback2 = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + name: *mut nghttp2_rcbuf, + value: *mut nghttp2_rcbuf, + flags: u8, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when a invalid header name/value pair is +/// received for the |frame|. +/// +/// The parameter and behaviour are similar to +/// :type:`nghttp2_on_header_callback`. The difference is that this +/// callback is only invoked when a invalid header name/value pair is +/// received which is treated as stream error if this callback is not +/// set. Only invalid regular header field are passed to this +/// callback. In other words, invalid pseudo header field is not +/// passed to this callback. Also header fields which includes upper +/// cased latter are also treated as error without passing them to this +/// callback. +/// +/// This callback is only considered if HTTP messaging validation is +/// turned on (which is on by default, see +/// `nghttp2_option_set_no_http_messaging()`). +/// +/// With this callback, application inspects the incoming invalid +/// field, and it also can reset stream from this callback by returning +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the +/// error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error +/// code, call `nghttp2_submit_rst_stream()` with the error code of +/// choice in addition to returning +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. +/// +/// If 0 is returned, the header field is ignored, and the stream is +/// not reset. +pub type nghttp2_on_invalid_header_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + name: *const u8, + namelen: usize, + value: *const u8, + valuelen: usize, + flags: u8, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when a invalid header name/value pair is +/// received for the |frame|. +/// +/// The parameter and behaviour are similar to +/// :type:`nghttp2_on_header_callback2`. The difference is that this +/// callback is only invoked when a invalid header name/value pair is +/// received which is silently ignored if this callback is not set. +/// Only invalid regular header field are passed to this callback. In +/// other words, invalid pseudo header field is not passed to this +/// callback. Also header fields which includes upper cased latter are +/// also treated as error without passing them to this callback. +/// +/// This callback is only considered if HTTP messaging validation is +/// turned on (which is on by default, see +/// `nghttp2_option_set_no_http_messaging()`). +/// +/// With this callback, application inspects the incoming invalid +/// field, and it also can reset stream from this callback by returning +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the +/// error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error +/// code, call `nghttp2_submit_rst_stream()` with the error code of +/// choice in addition to returning +/// :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. +pub type nghttp2_on_invalid_header_callback2 = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + name: *mut nghttp2_rcbuf, + value: *mut nghttp2_rcbuf, + flags: u8, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when the library asks application how +/// many padding bytes are required for the transmission of the +/// |frame|. The application must choose the total length of payload +/// including padded bytes in range [frame->hd.length, max_payloadlen], +/// inclusive. Choosing number not in this range will be treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning +/// ``frame->hd.length`` means no padding is added. Returning +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make +/// `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_select_padding_callback()`. +pub type nghttp2_select_padding_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame: *const nghttp2_frame, + max_payloadlen: usize, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @functypedef +/// +/// Callback function invoked when library wants to get max length of +/// data to send data to the remote peer. The implementation of this +/// function should return a value in the following range. [1, +/// min(|session_remote_window_size|, |stream_remote_window_size|, +/// |remote_max_frame_size|)]. If a value greater than this range is +/// returned than the max allow value will be used. Returning a value +/// smaller than this range is treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The |frame_type| is provided +/// for future extensibility and identifies the type of frame (see +/// :type:`nghttp2_frame_type`) for which to get the length for. +/// Currently supported frame types are: :enum:`NGHTTP2_DATA`. +/// +/// This callback can be used to control the length in bytes for which +/// :type:`nghttp2_data_source_read_callback` is allowed to send to the +/// remote endpoint. This callback is optional. Returning +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session +/// failure. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_data_source_read_length_callback()`. +pub type nghttp2_data_source_read_length_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + frame_type: u8, + stream_id: i32, + session_remote_window_size: i32, + stream_remote_window_size: i32, + remote_max_frame_size: u32, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @functypedef +/// +/// Callback function invoked when a frame header is received. The +/// |hd| points to received frame header. +/// +/// Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will +/// also be called when frame header of CONTINUATION frame is received. +/// +/// If both :type:`nghttp2_on_begin_frame_callback` and +/// :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or +/// PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback` +/// will be called first. +/// +/// The implementation of this function must return 0 if it succeeds. +/// If nonzero value is returned, it is treated as fatal error and +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +/// +/// To set this callback to :type:`nghttp2_session_callbacks`, use +/// `nghttp2_session_callbacks_set_on_begin_frame_callback()`. +pub type nghttp2_on_begin_frame_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + hd: *const nghttp2_frame_hd, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when chunk of extension frame payload is +/// received. The |hd| points to frame header. The received +/// chunk is |data| of length |len|. +/// +/// The implementation of this function must return 0 if it succeeds. +/// +/// To abort processing this extension frame, return +/// :enum:`NGHTTP2_ERR_CANCEL`. +/// +/// If fatal error occurred, application should return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the +/// other values are returned, currently they are treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +pub type nghttp2_on_extension_chunk_recv_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + hd: *const nghttp2_frame_hd, + data: *const u8, + len: usize, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when library asks the application to +/// unpack extension payload from its wire format. The extension +/// payload has been passed to the application using +/// :type:`nghttp2_on_extension_chunk_recv_callback`. The frame header +/// is already unpacked by the library and provided as |hd|. +/// +/// To receive extension frames, the application must tell desired +/// extension frame type to the library using +/// `nghttp2_option_set_user_recv_extension_type()`. +/// +/// The implementation of this function may store the pointer to the +/// created object as a result of unpacking in |*payload|, and returns +/// 0. The pointer stored in |*payload| is opaque to the library, and +/// the library does not own its pointer. |*payload| is initialized as +/// ``NULL``. The |*payload| is available as ``frame->ext.payload`` in +/// :type:`nghttp2_on_frame_recv_callback`. Therefore if application +/// can free that memory inside :type:`nghttp2_on_frame_recv_callback` +/// callback. Of course, application has a liberty not ot use +/// |*payload|, and do its own mechanism to process extension frames. +/// +/// To abort processing this extension frame, return +/// :enum:`NGHTTP2_ERR_CANCEL`. +/// +/// If fatal error occurred, application should return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, +/// `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the +/// other values are returned, currently they are treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +pub type nghttp2_unpack_extension_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + payload: *mut *mut ::std::os::raw::c_void, + hd: *const nghttp2_frame_hd, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when library asks the application to pack +/// extension payload in its wire format. The frame header will be +/// packed by library. Application must pack payload only. +/// ``frame->ext.payload`` is the object passed to +/// `nghttp2_submit_extension()` as payload parameter. Application +/// must pack extension payload to the |buf| of its capacity |len| +/// bytes. The |len| is at least 16KiB. +/// +/// The implementation of this function should return the number of +/// bytes written into |buf| when it succeeds. +/// +/// To abort processing this extension frame, return +/// :enum:`NGHTTP2_ERR_CANCEL`, and +/// :type:`nghttp2_on_frame_not_send_callback` will be invoked. +/// +/// If fatal error occurred, application should return +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, +/// `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions +/// immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the +/// other values are returned, currently they are treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is +/// strictly larger than |len|, it is treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. +pub type nghttp2_pack_extension_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + buf: *mut u8, + len: usize, + frame: *const nghttp2_frame, + user_data: *mut ::std::os::raw::c_void, + ) -> isize, +>; +/// @functypedef +/// +/// Callback function invoked when library provides the error message +/// intended for human consumption. This callback is solely for +/// debugging purpose. The |msg| is typically NULL-terminated string +/// of length |len|. |len| does not include the sentinel NULL +/// character. +/// +/// This function is deprecated. The new application should use +/// :type:`nghttp2_error_callback2`. +/// +/// The format of error message may change between nghttp2 library +/// versions. The application should not depend on the particular +/// format. +/// +/// Normally, application should return 0 from this callback. If fatal +/// error occurred while doing something in this callback, application +/// should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, +/// library will return immediately with return value +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value +/// is returned from this callback, they are treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not +/// rely on this details. +pub type nghttp2_error_callback = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + msg: *const ::std::os::raw::c_char, + len: usize, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +/// @functypedef +/// +/// Callback function invoked when library provides the error code, and +/// message. This callback is solely for debugging purpose. +/// |lib_error_code| is one of error code defined in +/// :enum:`nghttp2_error`. The |msg| is typically NULL-terminated +/// string of length |len|, and intended for human consumption. |len| +/// does not include the sentinel NULL character. +/// +/// The format of error message may change between nghttp2 library +/// versions. The application should not depend on the particular +/// format. +/// +/// Normally, application should return 0 from this callback. If fatal +/// error occurred while doing something in this callback, application +/// should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, +/// library will return immediately with return value +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value +/// is returned from this callback, they are treated as +/// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not +/// rely on this details. +pub type nghttp2_error_callback2 = ::std::option::Option< + unsafe extern "C" fn( + session: *mut nghttp2_session, + lib_error_code: ::std::os::raw::c_int, + msg: *const ::std::os::raw::c_char, + len: usize, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, +>; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_session_callbacks { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Initializes |*callbacks_ptr| with NULL values. + /// + /// The initialized object can be used when initializing multiple + /// :type:`nghttp2_session` objects. + /// + /// When the application finished using this object, it can use + /// `nghttp2_session_callbacks_del()` to free its memory. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_callbacks_new( + callbacks_ptr: *mut *mut nghttp2_session_callbacks, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Frees any resources allocated for |callbacks|. If |callbacks| is + /// ``NULL``, this function does nothing. + pub fn nghttp2_session_callbacks_del(callbacks: *mut nghttp2_session_callbacks); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a session wants to send data to + /// the remote peer. This callback is not necessary if the application + /// uses solely `nghttp2_session_mem_send()` to serialize data to + /// transmit. + pub fn nghttp2_session_callbacks_set_send_callback( + cbs: *mut nghttp2_session_callbacks, + send_callback: nghttp2_send_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the a session wants to receive + /// data from the remote peer. This callback is not necessary if the + /// application uses solely `nghttp2_session_mem_recv()` to process + /// received data. + pub fn nghttp2_session_callbacks_set_recv_callback( + cbs: *mut nghttp2_session_callbacks, + recv_callback: nghttp2_recv_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked by `nghttp2_session_recv()` and + /// `nghttp2_session_mem_recv()` when a frame is received. + pub fn nghttp2_session_callbacks_set_on_frame_recv_callback( + cbs: *mut nghttp2_session_callbacks, + on_frame_recv_callback: nghttp2_on_frame_recv_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked by `nghttp2_session_recv()` and + /// `nghttp2_session_mem_recv()` when an invalid non-DATA frame is + /// received. + pub fn nghttp2_session_callbacks_set_on_invalid_frame_recv_callback( + cbs: *mut nghttp2_session_callbacks, + on_invalid_frame_recv_callback: nghttp2_on_invalid_frame_recv_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a chunk of data in DATA frame + /// is received. + pub fn nghttp2_session_callbacks_set_on_data_chunk_recv_callback( + cbs: *mut nghttp2_session_callbacks, + on_data_chunk_recv_callback: nghttp2_on_data_chunk_recv_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked before a non-DATA frame is sent. + pub fn nghttp2_session_callbacks_set_before_frame_send_callback( + cbs: *mut nghttp2_session_callbacks, + before_frame_send_callback: nghttp2_before_frame_send_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked after a frame is sent. + pub fn nghttp2_session_callbacks_set_on_frame_send_callback( + cbs: *mut nghttp2_session_callbacks, + on_frame_send_callback: nghttp2_on_frame_send_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a non-DATA frame is not sent + /// because of an error. + pub fn nghttp2_session_callbacks_set_on_frame_not_send_callback( + cbs: *mut nghttp2_session_callbacks, + on_frame_not_send_callback: nghttp2_on_frame_not_send_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the stream is closed. + pub fn nghttp2_session_callbacks_set_on_stream_close_callback( + cbs: *mut nghttp2_session_callbacks, + on_stream_close_callback: nghttp2_on_stream_close_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the reception of header block + /// in HEADERS or PUSH_PROMISE is started. + pub fn nghttp2_session_callbacks_set_on_begin_headers_callback( + cbs: *mut nghttp2_session_callbacks, + on_begin_headers_callback: nghttp2_on_begin_headers_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a header name/value pair is + /// received. If both + /// `nghttp2_session_callbacks_set_on_header_callback()` and + /// `nghttp2_session_callbacks_set_on_header_callback2()` are used to + /// set callbacks, the latter has the precedence. + pub fn nghttp2_session_callbacks_set_on_header_callback( + cbs: *mut nghttp2_session_callbacks, + on_header_callback: nghttp2_on_header_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a header name/value pair is + /// received. + pub fn nghttp2_session_callbacks_set_on_header_callback2( + cbs: *mut nghttp2_session_callbacks, + on_header_callback2: nghttp2_on_header_callback2, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a invalid header name/value + /// pair is received. If both + /// `nghttp2_session_callbacks_set_on_invalid_header_callback()` and + /// `nghttp2_session_callbacks_set_on_invalid_header_callback2()` are + /// used to set callbacks, the latter takes the precedence. + pub fn nghttp2_session_callbacks_set_on_invalid_header_callback( + cbs: *mut nghttp2_session_callbacks, + on_invalid_header_callback: nghttp2_on_invalid_header_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a invalid header name/value + /// pair is received. + pub fn nghttp2_session_callbacks_set_on_invalid_header_callback2( + cbs: *mut nghttp2_session_callbacks, + on_invalid_header_callback2: nghttp2_on_invalid_header_callback2, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the library asks application + /// how many padding bytes are required for the transmission of the + /// given frame. + pub fn nghttp2_session_callbacks_set_select_padding_callback( + cbs: *mut nghttp2_session_callbacks, + select_padding_callback: nghttp2_select_padding_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function determine the length allowed in + /// :type:`nghttp2_data_source_read_callback`. + pub fn nghttp2_session_callbacks_set_data_source_read_length_callback( + cbs: *mut nghttp2_session_callbacks, + data_source_read_length_callback: nghttp2_data_source_read_length_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when a frame header is received. + pub fn nghttp2_session_callbacks_set_on_begin_frame_callback( + cbs: *mut nghttp2_session_callbacks, + on_begin_frame_callback: nghttp2_on_begin_frame_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when + /// :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in + /// :type:`nghttp2_data_source_read_callback` to avoid data copy. + pub fn nghttp2_session_callbacks_set_send_data_callback( + cbs: *mut nghttp2_session_callbacks, + send_data_callback: nghttp2_send_data_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the library asks the + /// application to pack extension frame payload in wire format. + pub fn nghttp2_session_callbacks_set_pack_extension_callback( + cbs: *mut nghttp2_session_callbacks, + pack_extension_callback: nghttp2_pack_extension_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when the library asks the + /// application to unpack extension frame payload from wire format. + pub fn nghttp2_session_callbacks_set_unpack_extension_callback( + cbs: *mut nghttp2_session_callbacks, + unpack_extension_callback: nghttp2_unpack_extension_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when chunk of extension frame + /// payload is received. + pub fn nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( + cbs: *mut nghttp2_session_callbacks, + on_extension_chunk_recv_callback: nghttp2_on_extension_chunk_recv_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when library tells error message to + /// the application. + /// + /// This function is deprecated. The new application should use + /// `nghttp2_session_callbacks_set_error_callback2()`. + /// + /// If both :type:`nghttp2_error_callback` and + /// :type:`nghttp2_error_callback2` are set, the latter takes + /// precedence. + pub fn nghttp2_session_callbacks_set_error_callback( + cbs: *mut nghttp2_session_callbacks, + error_callback: nghttp2_error_callback, + ); +} +extern "C" { + /// @function + /// + /// Sets callback function invoked when library tells error code, and + /// message to the application. + /// + /// If both :type:`nghttp2_error_callback` and + /// :type:`nghttp2_error_callback2` are set, the latter takes + /// precedence. + pub fn nghttp2_session_callbacks_set_error_callback2( + cbs: *mut nghttp2_session_callbacks, + error_callback2: nghttp2_error_callback2, + ); +} +/// @functypedef +/// +/// Custom memory allocator to replace malloc(). The |mem_user_data| +/// is the mem_user_data member of :type:`nghttp2_mem` structure. +pub type nghttp2_malloc = ::std::option::Option< + unsafe extern "C" fn(size: usize, mem_user_data: *mut ::std::os::raw::c_void) + -> *mut ::std::os::raw::c_void, +>; +/// @functypedef +/// +/// Custom memory allocator to replace free(). The |mem_user_data| is +/// the mem_user_data member of :type:`nghttp2_mem` structure. +pub type nghttp2_free = ::std::option::Option< + unsafe extern "C" fn( + ptr: *mut ::std::os::raw::c_void, + mem_user_data: *mut ::std::os::raw::c_void, + ), +>; +/// @functypedef +/// +/// Custom memory allocator to replace calloc(). The |mem_user_data| +/// is the mem_user_data member of :type:`nghttp2_mem` structure. +pub type nghttp2_calloc = ::std::option::Option< + unsafe extern "C" fn(nmemb: usize, size: usize, mem_user_data: *mut ::std::os::raw::c_void) + -> *mut ::std::os::raw::c_void, +>; +/// @functypedef +/// +/// Custom memory allocator to replace realloc(). The |mem_user_data| +/// is the mem_user_data member of :type:`nghttp2_mem` structure. +pub type nghttp2_realloc = ::std::option::Option< + unsafe extern "C" fn( + ptr: *mut ::std::os::raw::c_void, + size: usize, + mem_user_data: *mut ::std::os::raw::c_void, + ) -> *mut ::std::os::raw::c_void, +>; +/// @struct +/// +/// Custom memory allocator functions and user defined pointer. The +/// |mem_user_data| member is passed to each allocator function. This +/// can be used, for example, to achieve per-session memory pool. +/// +/// In the following example code, ``my_malloc``, ``my_free``, +/// ``my_calloc`` and ``my_realloc`` are the replacement of the +/// standard allocators ``malloc``, ``free``, ``calloc`` and +/// ``realloc`` respectively:: +/// +/// void *my_malloc_cb(size_t size, void *mem_user_data) { +/// return my_malloc(size); +/// } +/// +/// void my_free_cb(void *ptr, void *mem_user_data) { my_free(ptr); } +/// +/// void *my_calloc_cb(size_t nmemb, size_t size, void *mem_user_data) { +/// return my_calloc(nmemb, size); +/// } +/// +/// void *my_realloc_cb(void *ptr, size_t size, void *mem_user_data) { +/// return my_realloc(ptr, size); +/// } +/// +/// void session_new() { +/// nghttp2_session *session; +/// nghttp2_session_callbacks *callbacks; +/// nghttp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb, +/// my_realloc_cb}; +/// +/// ... +/// +/// nghttp2_session_client_new3(&session, callbacks, NULL, NULL, &mem); +/// +/// ... +/// } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_mem { + /// An arbitrary user supplied data. This is passed to each + /// allocator function. + pub mem_user_data: *mut ::std::os::raw::c_void, + /// Custom allocator function to replace malloc(). + pub malloc: nghttp2_malloc, + /// Custom allocator function to replace free(). + pub free: nghttp2_free, + /// Custom allocator function to replace calloc(). + pub calloc: nghttp2_calloc, + /// Custom allocator function to replace realloc(). + pub realloc: nghttp2_realloc, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_option { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Initializes |*option_ptr| with default values. + /// + /// When the application finished using this object, it can use + /// `nghttp2_option_del()` to free its memory. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_option_new(option_ptr: *mut *mut nghttp2_option) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Frees any resources allocated for |option|. If |option| is + /// ``NULL``, this function does nothing. + pub fn nghttp2_option_del(option: *mut nghttp2_option); +} +extern "C" { + /// @function + /// + /// This option prevents the library from sending WINDOW_UPDATE for a + /// connection automatically. If this option is set to nonzero, the + /// library won't send WINDOW_UPDATE for DATA until application calls + /// `nghttp2_session_consume()` to indicate the consumed amount of + /// data. Don't use `nghttp2_submit_window_update()` for this purpose. + /// By default, this option is set to zero. + pub fn nghttp2_option_set_no_auto_window_update( + option: *mut nghttp2_option, + val: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of + /// remote endpoint as if it is received in SETTINGS frame. Without + /// specifying this option, the maximum number of outgoing concurrent + /// streams is initially limited to 100 to avoid issues when the local + /// endpoint submits lots of requests before receiving initial SETTINGS + /// frame from the remote endpoint, since sending them at once to the + /// remote endpoint could lead to rejection of some of the requests. + /// This value will be overwritten when the local endpoint receives + /// initial SETTINGS frame from the remote endpoint, either to the + /// value advertised in SETTINGS_MAX_CONCURRENT_STREAMS or to the + /// default value (unlimited) if none was advertised. + pub fn nghttp2_option_set_peer_max_concurrent_streams(option: *mut nghttp2_option, val: u32); +} +extern "C" { + /// @function + /// + /// By default, nghttp2 library, if configured as server, requires + /// first 24 bytes of client magic byte string (MAGIC). In most cases, + /// this will simplify the implementation of server. But sometimes + /// server may want to detect the application protocol based on first + /// few bytes on clear text communication. + /// + /// If this option is used with nonzero |val|, nghttp2 library does not + /// handle MAGIC. It still checks following SETTINGS frame. This + /// means that applications should deal with MAGIC by themselves. + /// + /// If this option is not used or used with zero value, if MAGIC does + /// not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()` + /// and `nghttp2_session_mem_recv()` will return error + /// :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error. + pub fn nghttp2_option_set_no_recv_client_magic( + option: *mut nghttp2_option, + val: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// By default, nghttp2 library enforces subset of HTTP Messaging rules + /// described in `HTTP/2 specification, section 8 + /// `_. See + /// :ref:`http-messaging` section for details. For those applications + /// who use nghttp2 library as non-HTTP use, give nonzero to |val| to + /// disable this enforcement. Please note that disabling this feature + /// does not change the fundamental client and server model of HTTP. + /// That is, even if the validation is disabled, only client can send + /// requests. + pub fn nghttp2_option_set_no_http_messaging( + option: *mut nghttp2_option, + val: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// RFC 7540 does not enforce any limit on the number of incoming + /// reserved streams (in RFC 7540 terms, streams in reserved (remote) + /// state). This only affects client side, since only server can push + /// streams. Malicious server can push arbitrary number of streams, + /// and make client's memory exhausted. This option can set the + /// maximum number of such incoming streams to avoid possible memory + /// exhaustion. If this option is set, and pushed streams are + /// automatically closed on reception, without calling user provided + /// callback, if they exceed the given limit. The default value is + /// 200. If session is configured as server side, this option has no + /// effect. Server can control the number of streams to push. + pub fn nghttp2_option_set_max_reserved_remote_streams(option: *mut nghttp2_option, val: u32); +} +extern "C" { + /// @function + /// + /// Sets extension frame type the application is willing to handle with + /// user defined callbacks (see + /// :type:`nghttp2_on_extension_chunk_recv_callback` and + /// :type:`nghttp2_unpack_extension_callback`). The |type| is + /// extension frame type, and must be strictly greater than 0x9. + /// Otherwise, this function does nothing. The application can call + /// this function multiple times to set more than one frame type to + /// receive. The application does not have to call this function if it + /// just sends extension frames. + pub fn nghttp2_option_set_user_recv_extension_type(option: *mut nghttp2_option, type_: u8); +} +extern "C" { + /// @function + /// + /// Sets extension frame type the application is willing to receive + /// using builtin handler. The |type| is the extension frame type to + /// receive, and must be strictly greater than 0x9. Otherwise, this + /// function does nothing. The application can call this function + /// multiple times to set more than one frame type to receive. The + /// application does not have to call this function if it just sends + /// extension frames. + /// + /// If same frame type is passed to both + /// `nghttp2_option_set_builtin_recv_extension_type()` and + /// `nghttp2_option_set_user_recv_extension_type()`, the latter takes + /// precedence. + pub fn nghttp2_option_set_builtin_recv_extension_type(option: *mut nghttp2_option, type_: u8); +} +extern "C" { + /// @function + /// + /// This option prevents the library from sending PING frame with ACK + /// flag set automatically when PING frame without ACK flag set is + /// received. If this option is set to nonzero, the library won't send + /// PING frame with ACK flag set in the response for incoming PING + /// frame. The application can send PING frame with ACK flag set using + /// `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags + /// parameter. + pub fn nghttp2_option_set_no_auto_ping_ack( + option: *mut nghttp2_option, + val: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// This option sets the maximum length of header block (a set of + /// header fields per one HEADERS frame) to send. The length of a + /// given set of header fields is calculated using + /// `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If + /// application attempts to send header fields larger than this limit, + /// the transmission of the frame fails with error code + /// :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`. + pub fn nghttp2_option_set_max_send_header_block_length(option: *mut nghttp2_option, val: usize); +} +extern "C" { + /// @function + /// + /// This option sets the maximum dynamic table size for deflating + /// header fields. The default value is 4KiB. In HTTP/2, receiver of + /// deflated header block can specify maximum dynamic table size. The + /// actual maximum size is the minimum of the size receiver specified + /// and this option value. + pub fn nghttp2_option_set_max_deflate_dynamic_table_size( + option: *mut nghttp2_option, + val: usize, + ); +} +extern "C" { + /// @function + /// + /// This option prevents the library from retaining closed streams to + /// maintain the priority tree. If this option is set to nonzero, + /// applications can discard closed stream completely to save memory. + pub fn nghttp2_option_set_no_closed_streams( + option: *mut nghttp2_option, + val: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// Initializes |*session_ptr| for client use. The all members of + /// |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| + /// does not store |callbacks|. The |user_data| is an arbitrary user + /// supplied data, which will be passed to the callback functions. + /// + /// The :type:`nghttp2_send_callback` must be specified. If the + /// application code uses `nghttp2_session_recv()`, the + /// :type:`nghttp2_recv_callback` must be specified. The other members + /// of |callbacks| can be ``NULL``. + /// + /// If this function fails, |*session_ptr| is left untouched. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_client_new( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Initializes |*session_ptr| for server use. The all members of + /// |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| + /// does not store |callbacks|. The |user_data| is an arbitrary user + /// supplied data, which will be passed to the callback functions. + /// + /// The :type:`nghttp2_send_callback` must be specified. If the + /// application code uses `nghttp2_session_recv()`, the + /// :type:`nghttp2_recv_callback` must be specified. The other members + /// of |callbacks| can be ``NULL``. + /// + /// If this function fails, |*session_ptr| is left untouched. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_server_new( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_client_new()`, but with additional options + /// specified in the |option|. + /// + /// The |option| can be ``NULL`` and the call is equivalent to + /// `nghttp2_session_client_new()`. + /// + /// This function does not take ownership |option|. The application is + /// responsible for freeing |option| if it finishes using the object. + /// + /// The library code does not refer to |option| after this function + /// returns. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_client_new2( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + option: *const nghttp2_option, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_server_new()`, but with additional options + /// specified in the |option|. + /// + /// The |option| can be ``NULL`` and the call is equivalent to + /// `nghttp2_session_server_new()`. + /// + /// This function does not take ownership |option|. The application is + /// responsible for freeing |option| if it finishes using the object. + /// + /// The library code does not refer to |option| after this function + /// returns. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_server_new2( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + option: *const nghttp2_option, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_client_new2()`, but with additional custom + /// memory allocator specified in the |mem|. + /// + /// The |mem| can be ``NULL`` and the call is equivalent to + /// `nghttp2_session_client_new2()`. + /// + /// This function does not take ownership |mem|. The application is + /// responsible for freeing |mem|. + /// + /// The library code does not refer to |mem| pointer after this + /// function returns, so the application can safely free it. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_client_new3( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + option: *const nghttp2_option, + mem: *mut nghttp2_mem, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_server_new2()`, but with additional custom + /// memory allocator specified in the |mem|. + /// + /// The |mem| can be ``NULL`` and the call is equivalent to + /// `nghttp2_session_server_new2()`. + /// + /// This function does not take ownership |mem|. The application is + /// responsible for freeing |mem|. + /// + /// The library code does not refer to |mem| pointer after this + /// function returns, so the application can safely free it. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_server_new3( + session_ptr: *mut *mut nghttp2_session, + callbacks: *const nghttp2_session_callbacks, + user_data: *mut ::std::os::raw::c_void, + option: *const nghttp2_option, + mem: *mut nghttp2_mem, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Frees any resources allocated for |session|. If |session| is + /// ``NULL``, this function does nothing. + pub fn nghttp2_session_del(session: *mut nghttp2_session); +} +extern "C" { + /// @function + /// + /// Sends pending frames to the remote peer. + /// + /// This function retrieves the highest prioritized frame from the + /// outbound queue and sends it to the remote peer. It does this as + /// many as possible until the user callback + /// :type:`nghttp2_send_callback` returns + /// :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty. + /// This function calls several callback functions which are passed + /// when initializing the |session|. Here is the simple time chart + /// which tells when each callback is invoked: + /// + /// 1. Get the next frame to send from outbound queue. + /// + /// 2. Prepare transmission of the frame. + /// + /// 3. If the control frame cannot be sent because some preconditions + /// are not met (e.g., request HEADERS cannot be sent after GOAWAY), + /// :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort + /// the following steps. + /// + /// 4. If the frame is HEADERS, PUSH_PROMISE or DATA, + /// :type:`nghttp2_select_padding_callback` is invoked. + /// + /// 5. If the frame is request HEADERS, the stream is opened here. + /// + /// 6. :type:`nghttp2_before_frame_send_callback` is invoked. + /// + /// 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from + /// :type:`nghttp2_before_frame_send_callback`, the current frame + /// transmission is canceled, and + /// :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort + /// the following steps. + /// + /// 8. :type:`nghttp2_send_callback` is invoked one or more times to + /// send the frame. + /// + /// 9. :type:`nghttp2_on_frame_send_callback` is invoked. + /// + /// 10. If the transmission of the frame triggers closure of the + /// stream, the stream is closed and + /// :type:`nghttp2_on_stream_close_callback` is invoked. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + /// The callback function failed. + pub fn nghttp2_session_send(session: *mut nghttp2_session) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the serialized data to send. + /// + /// This function behaves like `nghttp2_session_send()` except that it + /// does not use :type:`nghttp2_send_callback` to transmit data. + /// Instead, it assigns the pointer to the serialized data to the + /// |*data_ptr| and returns its length. The other callbacks are called + /// in the same way as they are in `nghttp2_session_send()`. + /// + /// If no data is available to send, this function returns 0. + /// + /// This function may not return all serialized data in one invocation. + /// To get all data, call this function repeatedly until it returns 0 + /// or one of negative error codes. + /// + /// The assigned |*data_ptr| is valid until the next call of + /// `nghttp2_session_mem_send()` or `nghttp2_session_send()`. + /// + /// The caller must send all data before sending the next chunk of + /// data. + /// + /// This function returns the length of the data pointed by the + /// |*data_ptr| if it succeeds, or one of the following negative error + /// codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// + /// .. note:: + /// + /// This function may produce very small byte string. If that is the + /// case, and application disables Nagle algorithm (``TCP_NODELAY``), + /// then writing this small chunk leads to very small packet, and it + /// is very inefficient. An application should be responsible to + /// buffer up small chunks of data as necessary to avoid this + /// situation. + pub fn nghttp2_session_mem_send( + session: *mut nghttp2_session, + data_ptr: *mut *const u8, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Receives frames from the remote peer. + /// + /// This function receives as many frames as possible until the user + /// callback :type:`nghttp2_recv_callback` returns + /// :enum:`NGHTTP2_ERR_WOULDBLOCK`. This function calls several + /// callback functions which are passed when initializing the + /// |session|. Here is the simple time chart which tells when each + /// callback is invoked: + /// + /// 1. :type:`nghttp2_recv_callback` is invoked one or more times to + /// receive frame header. + /// + /// 2. When frame header is received, + /// :type:`nghttp2_on_begin_frame_callback` is invoked. + /// + /// 3. If the frame is DATA frame: + /// + /// 1. :type:`nghttp2_recv_callback` is invoked to receive DATA + /// payload. For each chunk of data, + /// :type:`nghttp2_on_data_chunk_recv_callback` is invoked. + /// + /// 2. If one DATA frame is completely received, + /// :type:`nghttp2_on_frame_recv_callback` is invoked. If the + /// reception of the frame triggers the closure of the stream, + /// :type:`nghttp2_on_stream_close_callback` is invoked. + /// + /// 4. If the frame is the control frame: + /// + /// 1. :type:`nghttp2_recv_callback` is invoked one or more times to + /// receive whole frame. + /// + /// 2. If the received frame is valid, then following actions are + /// taken. If the frame is either HEADERS or PUSH_PROMISE, + /// :type:`nghttp2_on_begin_headers_callback` is invoked. Then + /// :type:`nghttp2_on_header_callback` is invoked for each header + /// name/value pair. For invalid header field, + /// :type:`nghttp2_on_invalid_header_callback` is called. After + /// all name/value pairs are emitted successfully, + /// :type:`nghttp2_on_frame_recv_callback` is invoked. For other + /// frames, :type:`nghttp2_on_frame_recv_callback` is invoked. + /// If the reception of the frame triggers the closure of the + /// stream, :type:`nghttp2_on_stream_close_callback` is invoked. + /// + /// 3. If the received frame is unpacked but is interpreted as + /// invalid, :type:`nghttp2_on_invalid_frame_recv_callback` is + /// invoked. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_EOF` + /// The remote peer did shutdown on the connection. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + /// The callback function failed. + /// :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + /// Invalid client magic was detected. This error only returns + /// when |session| was configured as server and + /// `nghttp2_option_set_no_recv_client_magic()` is not used with + /// nonzero value. + /// :enum:`NGHTTP2_ERR_FLOODED` + /// Flooding was detected in this HTTP/2 session, and it must be + /// closed. This is most likely caused by misbehaviour of peer. + pub fn nghttp2_session_recv(session: *mut nghttp2_session) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Processes data |in| as an input from the remote endpoint. The + /// |inlen| indicates the number of bytes in the |in|. + /// + /// This function behaves like `nghttp2_session_recv()` except that it + /// does not use :type:`nghttp2_recv_callback` to receive data; the + /// |in| is the only data for the invocation of this function. If all + /// bytes are processed, this function returns. The other callbacks + /// are called in the same way as they are in `nghttp2_session_recv()`. + /// + /// In the current implementation, this function always tries to + /// processes all input data unless either an error occurs or + /// :enum:`NGHTTP2_ERR_PAUSE` is returned from + /// :type:`nghttp2_on_header_callback` or + /// :type:`nghttp2_on_data_chunk_recv_callback`. If + /// :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the + /// number of bytes which was used to produce the data or frame for the + /// callback. + /// + /// This function returns the number of processed bytes, or one of the + /// following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + /// The callback function failed. + /// :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + /// Invalid client magic was detected. This error only returns + /// when |session| was configured as server and + /// `nghttp2_option_set_no_recv_client_magic()` is not used with + /// nonzero value. + /// :enum:`NGHTTP2_ERR_FLOODED` + /// Flooding was detected in this HTTP/2 session, and it must be + /// closed. This is most likely caused by misbehaviour of peer. + pub fn nghttp2_session_mem_recv( + session: *mut nghttp2_session, + in_: *const u8, + inlen: usize, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Puts back previously deferred DATA frame in the stream |stream_id| + /// to the outbound queue. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The stream does not exist; or no deferred data exist. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_resume_data( + session: *mut nghttp2_session, + stream_id: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns nonzero value if |session| wants to receive data from the + /// remote peer. + /// + /// If both `nghttp2_session_want_read()` and + /// `nghttp2_session_want_write()` return 0, the application should + /// drop the connection. + pub fn nghttp2_session_want_read(session: *mut nghttp2_session) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns nonzero value if |session| wants to send data to the remote + /// peer. + /// + /// If both `nghttp2_session_want_read()` and + /// `nghttp2_session_want_write()` return 0, the application should + /// drop the connection. + pub fn nghttp2_session_want_write(session: *mut nghttp2_session) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns stream_user_data for the stream |stream_id|. The + /// stream_user_data is provided by `nghttp2_submit_request()`, + /// `nghttp2_submit_headers()` or + /// `nghttp2_session_set_stream_user_data()`. Unless it is set using + /// `nghttp2_session_set_stream_user_data()`, if the stream is + /// initiated by the remote endpoint, stream_user_data is always + /// ``NULL``. If the stream does not exist, this function returns + /// ``NULL``. + pub fn nghttp2_session_get_stream_user_data( + session: *mut nghttp2_session, + stream_id: i32, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + /// @function + /// + /// Sets the |stream_user_data| to the stream denoted by the + /// |stream_id|. If a stream user data is already set to the stream, + /// it is replaced with the |stream_user_data|. It is valid to specify + /// ``NULL`` in the |stream_user_data|, which nullifies the associated + /// data pointer. + /// + /// It is valid to set the |stream_user_data| to the stream reserved by + /// PUSH_PROMISE frame. + /// + /// This function returns 0 if it succeeds, or one of following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The stream does not exist + pub fn nghttp2_session_set_stream_user_data( + session: *mut nghttp2_session, + stream_id: i32, + stream_user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Sets |user_data| to |session|, overwriting the existing user data + /// specified in `nghttp2_session_client_new()`, or + /// `nghttp2_session_server_new()`. + pub fn nghttp2_session_set_user_data( + session: *mut nghttp2_session, + user_data: *mut ::std::os::raw::c_void, + ); +} +extern "C" { + /// @function + /// + /// Returns the number of frames in the outbound queue. This does not + /// include the deferred DATA frames. + pub fn nghttp2_session_get_outbound_queue_size(session: *mut nghttp2_session) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the number of DATA payload in bytes received without + /// WINDOW_UPDATE transmission for the stream |stream_id|. The local + /// (receive) window size can be adjusted by + /// `nghttp2_submit_window_update()`. This function takes into account + /// that and returns effective data length. In particular, if the + /// local window size is reduced by submitting negative + /// window_size_increment with `nghttp2_submit_window_update()`, this + /// function returns the number of bytes less than actually received. + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_stream_effective_recv_data_length( + session: *mut nghttp2_session, + stream_id: i32, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the local (receive) window size for the stream |stream_id|. + /// The local window size can be adjusted by + /// `nghttp2_submit_window_update()`. This function takes into account + /// that and returns effective window size. + /// + /// This function does not take into account the amount of received + /// data from the remote endpoint. Use + /// `nghttp2_session_get_stream_local_window_size()` to know the amount + /// of data the remote endpoint can send without receiving stream level + /// WINDOW_UPDATE frame. Note that each stream is still subject to the + /// connection level flow control. + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_stream_effective_local_window_size( + session: *mut nghttp2_session, + stream_id: i32, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the amount of flow-controlled payload (e.g., DATA) that the + /// remote endpoint can send without receiving stream level + /// WINDOW_UPDATE frame. It is also subject to the connection level + /// flow control. So the actual amount of data to send is + /// min(`nghttp2_session_get_stream_local_window_size()`, + /// `nghttp2_session_get_local_window_size()`). + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_stream_local_window_size( + session: *mut nghttp2_session, + stream_id: i32, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the number of DATA payload in bytes received without + /// WINDOW_UPDATE transmission for a connection. The local (receive) + /// window size can be adjusted by `nghttp2_submit_window_update()`. + /// This function takes into account that and returns effective data + /// length. In particular, if the local window size is reduced by + /// submitting negative window_size_increment with + /// `nghttp2_submit_window_update()`, this function returns the number + /// of bytes less than actually received. + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_effective_recv_data_length(session: *mut nghttp2_session) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the local (receive) window size for a connection. The + /// local window size can be adjusted by + /// `nghttp2_submit_window_update()`. This function takes into account + /// that and returns effective window size. + /// + /// This function does not take into account the amount of received + /// data from the remote endpoint. Use + /// `nghttp2_session_get_local_window_size()` to know the amount of + /// data the remote endpoint can send without receiving + /// connection-level WINDOW_UPDATE frame. Note that each stream is + /// still subject to the stream level flow control. + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_effective_local_window_size(session: *mut nghttp2_session) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the amount of flow-controlled payload (e.g., DATA) that the + /// remote endpoint can send without receiving connection level + /// WINDOW_UPDATE frame. Note that each stream is still subject to the + /// stream level flow control (see + /// `nghttp2_session_get_stream_local_window_size()`). + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_local_window_size(session: *mut nghttp2_session) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the remote window size for a given stream |stream_id|. + /// + /// This is the amount of flow-controlled payload (e.g., DATA) that the + /// local endpoint can send without stream level WINDOW_UPDATE. There + /// is also connection level flow control, so the effective size of + /// payload that the local endpoint can actually send is + /// min(`nghttp2_session_get_stream_remote_window_size()`, + /// `nghttp2_session_get_remote_window_size()`). + /// + /// This function returns -1 if it fails. + pub fn nghttp2_session_get_stream_remote_window_size( + session: *mut nghttp2_session, + stream_id: i32, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the remote window size for a connection. + /// + /// This function always succeeds. + pub fn nghttp2_session_get_remote_window_size(session: *mut nghttp2_session) -> i32; +} +extern "C" { + /// @function + /// + /// Returns 1 if local peer half closed the given stream |stream_id|. + /// Returns 0 if it did not. Returns -1 if no such stream exists. + pub fn nghttp2_session_get_stream_local_close( + session: *mut nghttp2_session, + stream_id: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns 1 if remote peer half closed the given stream |stream_id|. + /// Returns 0 if it did not. Returns -1 if no such stream exists. + pub fn nghttp2_session_get_stream_remote_close( + session: *mut nghttp2_session, + stream_id: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the current dynamic table size of HPACK inflater, including + /// the overhead 32 bytes per entry described in RFC 7541. + pub fn nghttp2_session_get_hd_inflate_dynamic_table_size( + session: *mut nghttp2_session, + ) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the current dynamic table size of HPACK deflater including + /// the overhead 32 bytes per entry described in RFC 7541. + pub fn nghttp2_session_get_hd_deflate_dynamic_table_size( + session: *mut nghttp2_session, + ) -> usize; +} +extern "C" { + /// @function + /// + /// Signals the session so that the connection should be terminated. + /// + /// The last stream ID is the minimum value between the stream ID of a + /// stream for which :type:`nghttp2_on_frame_recv_callback` was called + /// most recently and the last stream ID we have sent to the peer + /// previously. + /// + /// The |error_code| is the error code of this GOAWAY frame. The + /// pre-defined error code is one of :enum:`nghttp2_error_code`. + /// + /// After the transmission, both `nghttp2_session_want_read()` and + /// `nghttp2_session_want_write()` return 0. + /// + /// This function should be called when the connection should be + /// terminated after sending GOAWAY. If the remaining streams should + /// be processed after GOAWAY, use `nghttp2_submit_goaway()` instead. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_terminate_session( + session: *mut nghttp2_session, + error_code: u32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Signals the session so that the connection should be terminated. + /// + /// This function behaves like `nghttp2_session_terminate_session()`, + /// but the last stream ID can be specified by the application for fine + /// grained control of stream. The HTTP/2 specification does not allow + /// last_stream_id to be increased. So the actual value sent as + /// last_stream_id is the minimum value between the given + /// |last_stream_id| and the last_stream_id we have previously sent to + /// the peer. + /// + /// The |last_stream_id| is peer's stream ID or 0. So if |session| is + /// initialized as client, |last_stream_id| must be even or 0. If + /// |session| is initialized as server, |last_stream_id| must be odd or + /// 0. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |last_stream_id| is invalid. + pub fn nghttp2_session_terminate_session2( + session: *mut nghttp2_session, + last_stream_id: i32, + error_code: u32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Signals to the client that the server started graceful shutdown + /// procedure. + /// + /// This function is only usable for server. If this function is + /// called with client side session, this function returns + /// :enum:`NGHTTP2_ERR_INVALID_STATE`. + /// + /// To gracefully shutdown HTTP/2 session, server should call this + /// function to send GOAWAY with last_stream_id (1u << 31) - 1. And + /// after some delay (e.g., 1 RTT), send another GOAWAY with the stream + /// ID that the server has some processing using + /// `nghttp2_submit_goaway()`. See also + /// `nghttp2_session_get_last_proc_stream_id()`. + /// + /// Unlike `nghttp2_submit_goaway()`, this function just sends GOAWAY + /// and does nothing more. This is a mere indication to the client + /// that session shutdown is imminent. The application should call + /// `nghttp2_submit_goaway()` with appropriate last_stream_id after + /// this call. + /// + /// If one or more GOAWAY frame have been already sent by either + /// `nghttp2_submit_goaway()` or `nghttp2_session_terminate_session()`, + /// this function has no effect. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// The |session| is initialized as client. + pub fn nghttp2_submit_shutdown_notice(session: *mut nghttp2_session) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the value of SETTINGS |id| notified by a remote endpoint. + /// The |id| must be one of values defined in + /// :enum:`nghttp2_settings_id`. + pub fn nghttp2_session_get_remote_settings( + session: *mut nghttp2_session, + id: nghttp2_settings_id, + ) -> u32; +} +extern "C" { + /// @function + /// + /// Returns the value of SETTINGS |id| of local endpoint acknowledged + /// by the remote endpoint. The |id| must be one of the values defined + /// in :enum:`nghttp2_settings_id`. + pub fn nghttp2_session_get_local_settings( + session: *mut nghttp2_session, + id: nghttp2_settings_id, + ) -> u32; +} +extern "C" { + /// @function + /// + /// Tells the |session| that next stream ID is |next_stream_id|. The + /// |next_stream_id| must be equal or greater than the value returned + /// by `nghttp2_session_get_next_stream_id()`. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |next_stream_id| is strictly less than the value + /// `nghttp2_session_get_next_stream_id()` returns; or + /// |next_stream_id| is invalid (e.g., even integer for client, or + /// odd integer for server). + pub fn nghttp2_session_set_next_stream_id( + session: *mut nghttp2_session, + next_stream_id: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the next outgoing stream ID. Notice that return type is + /// uint32_t. If we run out of stream ID for this session, this + /// function returns 1 << 31. + pub fn nghttp2_session_get_next_stream_id(session: *mut nghttp2_session) -> u32; +} +extern "C" { + /// @function + /// + /// Tells the |session| that |size| bytes for a stream denoted by + /// |stream_id| were consumed by application and are ready to + /// WINDOW_UPDATE. The consumed bytes are counted towards both + /// connection and stream level WINDOW_UPDATE (see + /// `nghttp2_session_consume_connection()` and + /// `nghttp2_session_consume_stream()` to update consumption + /// independently). This function is intended to be used without + /// automatic window update (see + /// `nghttp2_option_set_no_auto_window_update()`). + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// Automatic WINDOW_UPDATE is not disabled. + pub fn nghttp2_session_consume( + session: *mut nghttp2_session, + stream_id: i32, + size: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_consume()`, but this only tells library that + /// |size| bytes were consumed only for connection level. Note that + /// HTTP/2 maintains connection and stream level flow control windows + /// independently. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// Automatic WINDOW_UPDATE is not disabled. + pub fn nghttp2_session_consume_connection( + session: *mut nghttp2_session, + size: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_session_consume()`, but this only tells library that + /// |size| bytes were consumed only for stream denoted by |stream_id|. + /// Note that HTTP/2 maintains connection and stream level flow control + /// windows independently. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// Automatic WINDOW_UPDATE is not disabled. + pub fn nghttp2_session_consume_stream( + session: *mut nghttp2_session, + stream_id: i32, + size: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Changes priority of existing stream denoted by |stream_id|. The + /// new priority specification is |pri_spec|. + /// + /// The priority is changed silently and instantly, and no PRIORITY + /// frame will be sent to notify the peer of this change. This + /// function may be useful for server to change the priority of pushed + /// stream. + /// + /// If |session| is initialized as server, and ``pri_spec->stream_id`` + /// points to the idle stream, the idle stream is created if it does + /// not exist. The created idle stream will depend on root stream + /// (stream 0) with weight 16. + /// + /// Otherwise, if stream denoted by ``pri_spec->stream_id`` is not + /// found, we use default priority instead of given |pri_spec|. That + /// is make stream depend on root stream with weight 16. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// Attempted to depend on itself; or no stream exist for the given + /// |stream_id|; or |stream_id| is 0 + pub fn nghttp2_session_change_stream_priority( + session: *mut nghttp2_session, + stream_id: i32, + pri_spec: *const nghttp2_priority_spec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Creates idle stream with the given |stream_id|, and priority + /// |pri_spec|. + /// + /// The stream creation is done without sending PRIORITY frame, which + /// means that peer does not know about the existence of this idle + /// stream in the local endpoint. + /// + /// RFC 7540 does not disallow the use of creation of idle stream with + /// odd or even stream ID regardless of client or server. So this + /// function can create odd or even stream ID regardless of client or + /// server. But probably it is a bit safer to use the stream ID the + /// local endpoint can initiate (in other words, use odd stream ID for + /// client, and even stream ID for server), to avoid potential + /// collision from peer's instruction. Also we can use + /// `nghttp2_session_set_next_stream_id()` to avoid to open created + /// idle streams accidentally if we follow this recommendation. + /// + /// If |session| is initialized as server, and ``pri_spec->stream_id`` + /// points to the idle stream, the idle stream is created if it does + /// not exist. The created idle stream will depend on root stream + /// (stream 0) with weight 16. + /// + /// Otherwise, if stream denoted by ``pri_spec->stream_id`` is not + /// found, we use default priority instead of given |pri_spec|. That + /// is make stream depend on root stream with weight 16. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// Attempted to depend on itself; or stream denoted by |stream_id| + /// already exists; or |stream_id| cannot be used to create idle + /// stream (in other words, local endpoint has already opened + /// stream ID greater than or equal to the given stream ID; or + /// |stream_id| is 0 + pub fn nghttp2_session_create_idle_stream( + session: *mut nghttp2_session, + stream_id: i32, + pri_spec: *const nghttp2_priority_spec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Performs post-process of HTTP Upgrade request. This function can + /// be called from both client and server, but the behavior is very + /// different in each other. + /// + /// .. warning:: + /// + /// This function is deprecated in favor of + /// `nghttp2_session_upgrade2()`, because this function lacks the + /// parameter to tell the library the request method used in the + /// original HTTP request. This information is required for client + /// to validate actual response body length against content-length + /// header field (see `nghttp2_option_set_no_http_messaging()`). If + /// HEAD is used in request, the length of response body must be 0 + /// regardless of value included in content-length header field. + /// + /// If called from client side, the |settings_payload| must be the + /// value sent in ``HTTP2-Settings`` header field and must be decoded + /// by base64url decoder. The |settings_payloadlen| is the length of + /// |settings_payload|. The |settings_payload| is unpacked and its + /// setting values will be submitted using `nghttp2_submit_settings()`. + /// This means that the client application code does not need to submit + /// SETTINGS by itself. The stream with stream ID=1 is opened and the + /// |stream_user_data| is used for its stream_user_data. The opened + /// stream becomes half-closed (local) state. + /// + /// If called from server side, the |settings_payload| must be the + /// value received in ``HTTP2-Settings`` header field and must be + /// decoded by base64url decoder. The |settings_payloadlen| is the + /// length of |settings_payload|. It is treated as if the SETTINGS + /// frame with that payload is received. Thus, callback functions for + /// the reception of SETTINGS frame will be invoked. The stream with + /// stream ID=1 is opened. The |stream_user_data| is ignored. The + /// opened stream becomes half-closed (remote). + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |settings_payload| is badly formed. + /// :enum:`NGHTTP2_ERR_PROTO` + /// The stream ID 1 is already used or closed; or is not available. + pub fn nghttp2_session_upgrade( + session: *mut nghttp2_session, + settings_payload: *const u8, + settings_payloadlen: usize, + stream_user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Performs post-process of HTTP Upgrade request. This function can + /// be called from both client and server, but the behavior is very + /// different in each other. + /// + /// If called from client side, the |settings_payload| must be the + /// value sent in ``HTTP2-Settings`` header field and must be decoded + /// by base64url decoder. The |settings_payloadlen| is the length of + /// |settings_payload|. The |settings_payload| is unpacked and its + /// setting values will be submitted using `nghttp2_submit_settings()`. + /// This means that the client application code does not need to submit + /// SETTINGS by itself. The stream with stream ID=1 is opened and the + /// |stream_user_data| is used for its stream_user_data. The opened + /// stream becomes half-closed (local) state. + /// + /// If called from server side, the |settings_payload| must be the + /// value received in ``HTTP2-Settings`` header field and must be + /// decoded by base64url decoder. The |settings_payloadlen| is the + /// length of |settings_payload|. It is treated as if the SETTINGS + /// frame with that payload is received. Thus, callback functions for + /// the reception of SETTINGS frame will be invoked. The stream with + /// stream ID=1 is opened. The |stream_user_data| is ignored. The + /// opened stream becomes half-closed (remote). + /// + /// If the request method is HEAD, pass nonzero value to + /// |head_request|. Otherwise, pass 0. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |settings_payload| is badly formed. + /// :enum:`NGHTTP2_ERR_PROTO` + /// The stream ID 1 is already used or closed; or is not available. + pub fn nghttp2_session_upgrade2( + session: *mut nghttp2_session, + settings_payload: *const u8, + settings_payloadlen: usize, + head_request: ::std::os::raw::c_int, + stream_user_data: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Serializes the SETTINGS values |iv| in the |buf|. The size of the + /// |buf| is specified by |buflen|. The number of entries in the |iv| + /// array is given by |niv|. The required space in |buf| for the |niv| + /// entries is ``6*niv`` bytes and if the given buffer is too small, an + /// error is returned. This function is used mainly for creating a + /// SETTINGS payload to be sent with the ``HTTP2-Settings`` header + /// field in an HTTP Upgrade request. The data written in |buf| is NOT + /// base64url encoded and the application is responsible for encoding. + /// + /// This function returns the number of bytes written in |buf|, or one + /// of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |iv| contains duplicate settings ID or invalid value. + /// + /// :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + /// The provided |buflen| size is too small to hold the output. + pub fn nghttp2_pack_settings_payload( + buf: *mut u8, + buflen: usize, + iv: *const nghttp2_settings_entry, + niv: usize, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Returns string describing the |lib_error_code|. The + /// |lib_error_code| must be one of the :enum:`nghttp2_error`. + pub fn nghttp2_strerror(lib_error_code: ::std::os::raw::c_int) + -> *const ::std::os::raw::c_char; +} +extern "C" { + /// @function + /// + /// Returns string representation of HTTP/2 error code |error_code| + /// (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code == + /// NGHTTP2_PROTOCOL_ERROR``). If string representation is unknown for + /// given |error_code|, this function returns string ``unknown``. + pub fn nghttp2_http2_strerror(error_code: u32) -> *const ::std::os::raw::c_char; +} +extern "C" { + /// @function + /// + /// Initializes |pri_spec| with the |stream_id| of the stream to depend + /// on with |weight| and its exclusive flag. If |exclusive| is + /// nonzero, exclusive flag is set. + /// + /// The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + /// :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. + pub fn nghttp2_priority_spec_init( + pri_spec: *mut nghttp2_priority_spec, + stream_id: i32, + weight: i32, + exclusive: ::std::os::raw::c_int, + ); +} +extern "C" { + /// @function + /// + /// Initializes |pri_spec| with the default values. The default values + /// are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and + /// exclusive = 0. + pub fn nghttp2_priority_spec_default_init(pri_spec: *mut nghttp2_priority_spec); +} +extern "C" { + /// @function + /// + /// Returns nonzero if the |pri_spec| is filled with default values. + pub fn nghttp2_priority_spec_check_default( + pri_spec: *const nghttp2_priority_spec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits HEADERS frame and optionally one or more DATA frames. + /// + /// The |pri_spec| is priority specification of this request. ``NULL`` + /// means the default priority (see + /// `nghttp2_priority_spec_default_init()`). To specify the priority, + /// use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, + /// this function will copy its data members. + /// + /// The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + /// :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + /// strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + /// :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + /// :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + /// + /// The |nva| is an array of name/value pair :type:`nghttp2_nv` with + /// |nvlen| elements. The application is responsible to include + /// required pseudo-header fields (header field whose name starts with + /// ":") in |nva| and must place pseudo-headers before regular header + /// fields. + /// + /// This function creates copies of all name/value pairs in |nva|. It + /// also lower-cases all names in |nva|. The order of elements in + /// |nva| is preserved. For header fields with + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + /// and value are not copied respectively. With + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + /// pass header field name in lowercase. The application should + /// maintain the references to them until + /// :type:`nghttp2_on_frame_send_callback` or + /// :type:`nghttp2_on_frame_not_send_callback` is called. + /// + /// HTTP/2 specification has requirement about header fields in the + /// request HEADERS. See the specification for more details. + /// + /// If |data_prd| is not ``NULL``, it provides data which will be sent + /// in subsequent DATA frames. In this case, a method that allows + /// request message bodies + /// (https://tools.ietf.org/html/rfc7231#section-4) must be specified + /// with ``:method`` key in |nva| (e.g. ``POST``). This function does + /// not take ownership of the |data_prd|. The function copies the + /// members of the |data_prd|. If |data_prd| is ``NULL``, HEADERS have + /// END_STREAM set. The |stream_user_data| is data associated to the + /// stream opened by this request and can be an arbitrary pointer, + /// which can be retrieved later by + /// `nghttp2_session_get_stream_user_data()`. + /// + /// This function returns assigned stream ID if it succeeds, or one of + /// the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + /// No stream ID is available because maximum stream ID was + /// reached. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// Trying to depend on itself (new stream ID equals + /// ``pri_spec->stream_id``). + /// :enum:`NGHTTP2_ERR_PROTO` + /// The |session| is server session. + /// + /// .. warning:: + /// + /// This function returns assigned stream ID if it succeeds. But + /// that stream is not created yet. The application must not submit + /// frame to that stream ID before + /// :type:`nghttp2_before_frame_send_callback` is called for this + /// frame. This means `nghttp2_session_get_stream_user_data()` does + /// not work before the callback. But + /// `nghttp2_session_set_stream_user_data()` handles this situation + /// specially, and it can set data to a stream during this period. + /// + pub fn nghttp2_submit_request( + session: *mut nghttp2_session, + pri_spec: *const nghttp2_priority_spec, + nva: *const nghttp2_nv, + nvlen: usize, + data_prd: *const nghttp2_data_provider, + stream_user_data: *mut ::std::os::raw::c_void, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Submits response HEADERS frame and optionally one or more DATA + /// frames against the stream |stream_id|. + /// + /// The |nva| is an array of name/value pair :type:`nghttp2_nv` with + /// |nvlen| elements. The application is responsible to include + /// required pseudo-header fields (header field whose name starts with + /// ":") in |nva| and must place pseudo-headers before regular header + /// fields. + /// + /// This function creates copies of all name/value pairs in |nva|. It + /// also lower-cases all names in |nva|. The order of elements in + /// |nva| is preserved. For header fields with + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + /// and value are not copied respectively. With + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + /// pass header field name in lowercase. The application should + /// maintain the references to them until + /// :type:`nghttp2_on_frame_send_callback` or + /// :type:`nghttp2_on_frame_not_send_callback` is called. + /// + /// HTTP/2 specification has requirement about header fields in the + /// response HEADERS. See the specification for more details. + /// + /// If |data_prd| is not ``NULL``, it provides data which will be sent + /// in subsequent DATA frames. This function does not take ownership + /// of the |data_prd|. The function copies the members of the + /// |data_prd|. If |data_prd| is ``NULL``, HEADERS will have + /// END_STREAM flag set. + /// + /// This method can be used as normal HTTP response and push response. + /// When pushing a resource using this function, the |session| must be + /// configured using `nghttp2_session_server_new()` or its variants and + /// the target stream denoted by the |stream_id| must be reserved using + /// `nghttp2_submit_push_promise()`. + /// + /// To send non-final response headers (e.g., HTTP status 101), don't + /// use this function because this function half-closes the outbound + /// stream. Instead, use `nghttp2_submit_headers()` for this purpose. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + /// :enum:`NGHTTP2_ERR_DATA_EXIST` + /// DATA or HEADERS has been already submitted and not fully + /// processed yet. Normally, this does not happen, but when + /// application wrongly calls `nghttp2_submit_response()` twice, + /// this may happen. + /// :enum:`NGHTTP2_ERR_PROTO` + /// The |session| is client session. + /// + /// .. warning:: + /// + /// Calling this function twice for the same stream ID may lead to + /// program crash. It is generally considered to a programming error + /// to commit response twice. + pub fn nghttp2_submit_response( + session: *mut nghttp2_session, + stream_id: i32, + nva: *const nghttp2_nv, + nvlen: usize, + data_prd: *const nghttp2_data_provider, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits trailer fields HEADERS against the stream |stream_id|. + /// + /// The |nva| is an array of name/value pair :type:`nghttp2_nv` with + /// |nvlen| elements. The application must not include pseudo-header + /// fields (headers whose names starts with ":") in |nva|. + /// + /// This function creates copies of all name/value pairs in |nva|. It + /// also lower-cases all names in |nva|. The order of elements in + /// |nva| is preserved. For header fields with + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + /// and value are not copied respectively. With + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + /// pass header field name in lowercase. The application should + /// maintain the references to them until + /// :type:`nghttp2_on_frame_send_callback` or + /// :type:`nghttp2_on_frame_not_send_callback` is called. + /// + /// For server, trailer fields must follow response HEADERS or response + /// DATA without END_STREAM flat set. The library does not enforce + /// this requirement, and applications should do this for themselves. + /// If `nghttp2_submit_trailer()` is called before any response HEADERS + /// submission (usually by `nghttp2_submit_response()`), the content of + /// |nva| will be sent as response headers, which will result in error. + /// + /// This function has the same effect with `nghttp2_submit_headers()`, + /// with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and + /// stream_user_data to NULL. + /// + /// To submit trailer fields after `nghttp2_submit_response()` is + /// called, the application has to specify + /// :type:`nghttp2_data_provider` to `nghttp2_submit_response()`. + /// Inside of :type:`nghttp2_data_source_read_callback`, when setting + /// :enum:`NGHTTP2_DATA_FLAG_EOF`, also set + /// :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`. After that, the + /// application can send trailer fields using + /// `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used + /// inside :type:`nghttp2_data_source_read_callback`. + /// + /// This function returns 0 if it succeeds and |stream_id| is -1. + /// Otherwise, this function returns 0 if it succeeds, or one of the + /// following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + pub fn nghttp2_submit_trailer( + session: *mut nghttp2_session, + stream_id: i32, + nva: *const nghttp2_nv, + nvlen: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits HEADERS frame. The |flags| is bitwise OR of the + /// following values: + /// + /// * :enum:`NGHTTP2_FLAG_END_STREAM` + /// + /// If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has + /// END_STREAM flag set. + /// + /// The library handles the CONTINUATION frame internally and it + /// correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE + /// or CONTINUATION frame. + /// + /// If the |stream_id| is -1, this frame is assumed as request (i.e., + /// request HEADERS frame which opens new stream). In this case, the + /// assigned stream ID will be returned. Otherwise, specify stream ID + /// in |stream_id|. + /// + /// The |pri_spec| is priority specification of this request. ``NULL`` + /// means the default priority (see + /// `nghttp2_priority_spec_default_init()`). To specify the priority, + /// use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, + /// this function will copy its data members. + /// + /// The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + /// :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + /// strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + /// :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + /// :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + /// + /// The |nva| is an array of name/value pair :type:`nghttp2_nv` with + /// |nvlen| elements. The application is responsible to include + /// required pseudo-header fields (header field whose name starts with + /// ":") in |nva| and must place pseudo-headers before regular header + /// fields. + /// + /// This function creates copies of all name/value pairs in |nva|. It + /// also lower-cases all names in |nva|. The order of elements in + /// |nva| is preserved. For header fields with + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + /// and value are not copied respectively. With + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + /// pass header field name in lowercase. The application should + /// maintain the references to them until + /// :type:`nghttp2_on_frame_send_callback` or + /// :type:`nghttp2_on_frame_not_send_callback` is called. + /// + /// The |stream_user_data| is a pointer to an arbitrary data which is + /// associated to the stream this frame will open. Therefore it is + /// only used if this frame opens streams, in other words, it changes + /// stream state from idle or reserved to open. + /// + /// This function is low-level in a sense that the application code can + /// specify flags directly. For usual HTTP request, + /// `nghttp2_submit_request()` is useful. Likewise, for HTTP response, + /// prefer `nghttp2_submit_response()`. + /// + /// This function returns newly assigned stream ID if it succeeds and + /// |stream_id| is -1. Otherwise, this function returns 0 if it + /// succeeds, or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + /// No stream ID is available because maximum stream ID was + /// reached. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0; or trying to depend on itself (stream ID + /// equals ``pri_spec->stream_id``). + /// :enum:`NGHTTP2_ERR_DATA_EXIST` + /// DATA or HEADERS has been already submitted and not fully + /// processed yet. This happens if stream denoted by |stream_id| + /// is in reserved state. + /// :enum:`NGHTTP2_ERR_PROTO` + /// The |stream_id| is -1, and |session| is server session. + /// + /// .. warning:: + /// + /// This function returns assigned stream ID if it succeeds and + /// |stream_id| is -1. But that stream is not opened yet. The + /// application must not submit frame to that stream ID before + /// :type:`nghttp2_before_frame_send_callback` is called for this + /// frame. + /// + pub fn nghttp2_submit_headers( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + pri_spec: *const nghttp2_priority_spec, + nva: *const nghttp2_nv, + nvlen: usize, + stream_user_data: *mut ::std::os::raw::c_void, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Submits one or more DATA frames to the stream |stream_id|. The + /// data to be sent are provided by |data_prd|. If |flags| contains + /// :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM + /// flag set. + /// + /// This function does not take ownership of the |data_prd|. The + /// function copies the members of the |data_prd|. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_DATA_EXIST` + /// DATA or HEADERS has been already submitted and not fully + /// processed yet. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + /// :enum:`NGHTTP2_ERR_STREAM_CLOSED` + /// The stream was already closed; or the |stream_id| is invalid. + /// + /// .. note:: + /// + /// Currently, only one DATA or HEADERS is allowed for a stream at a + /// time. Submitting these frames more than once before first DATA + /// or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST` + /// error code. The earliest callback which tells that previous + /// frame is done is :type:`nghttp2_on_frame_send_callback`. In side + /// that callback, new data can be submitted using + /// `nghttp2_submit_data()`. Of course, all data except for last one + /// must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in + /// |flags|. This sounds a bit complicated, and we recommend to use + /// `nghttp2_submit_request()` and `nghttp2_submit_response()` to + /// avoid this cascading issue. The experience shows that for HTTP + /// use, these two functions are enough to implement both client and + /// server. + pub fn nghttp2_submit_data( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + data_prd: *const nghttp2_data_provider, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits PRIORITY frame to change the priority of stream |stream_id| + /// to the priority specification |pri_spec|. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// The |pri_spec| is priority specification of this request. ``NULL`` + /// is not allowed for this function. To specify the priority, use + /// `nghttp2_priority_spec_init()`. This function will copy its data + /// members. + /// + /// The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + /// :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is + /// strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + /// :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + /// :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0; or the |pri_spec| is NULL; or trying to + /// depend on itself. + pub fn nghttp2_submit_priority( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + pri_spec: *const nghttp2_priority_spec, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits RST_STREAM frame to cancel/reject the stream |stream_id| + /// with the error code |error_code|. + /// + /// The pre-defined error code is one of :enum:`nghttp2_error_code`. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0. + pub fn nghttp2_submit_rst_stream( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + error_code: u32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Stores local settings and submits SETTINGS frame. The |iv| is the + /// pointer to the array of :type:`nghttp2_settings_entry`. The |niv| + /// indicates the number of :type:`nghttp2_settings_entry`. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// This function does not take ownership of the |iv|. This function + /// copies all the elements in the |iv|. + /// + /// While updating individual stream's local window size, if the window + /// size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, + /// RST_STREAM is issued against such a stream. + /// + /// SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted + /// by the library and application could not send it at its will. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |iv| contains invalid value (e.g., initial window size + /// strictly greater than (1 << 31) - 1. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_submit_settings( + session: *mut nghttp2_session, + flags: u8, + iv: *const nghttp2_settings_entry, + niv: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits PUSH_PROMISE frame. + /// + /// The |flags| is currently ignored. The library handles the + /// CONTINUATION frame internally and it correctly sets END_HEADERS to + /// the last sequence of the PUSH_PROMISE or CONTINUATION frame. + /// + /// The |stream_id| must be client initiated stream ID. + /// + /// The |nva| is an array of name/value pair :type:`nghttp2_nv` with + /// |nvlen| elements. The application is responsible to include + /// required pseudo-header fields (header field whose name starts with + /// ":") in |nva| and must place pseudo-headers before regular header + /// fields. + /// + /// This function creates copies of all name/value pairs in |nva|. It + /// also lower-cases all names in |nva|. The order of elements in + /// |nva| is preserved. For header fields with + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + /// and value are not copied respectively. With + /// :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + /// pass header field name in lowercase. The application should + /// maintain the references to them until + /// :type:`nghttp2_on_frame_send_callback` or + /// :type:`nghttp2_on_frame_not_send_callback` is called. + /// + /// The |promised_stream_user_data| is a pointer to an arbitrary data + /// which is associated to the promised stream this frame will open and + /// make it in reserved state. It is available using + /// `nghttp2_session_get_stream_user_data()`. The application can + /// access it in :type:`nghttp2_before_frame_send_callback` and + /// :type:`nghttp2_on_frame_send_callback` of this frame. + /// + /// The client side is not allowed to use this function. + /// + /// To submit response headers and data, use + /// `nghttp2_submit_response()`. + /// + /// This function returns assigned promised stream ID if it succeeds, + /// or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_PROTO` + /// This function was invoked when |session| is initialized as + /// client. + /// :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + /// No stream ID is available because maximum stream ID was + /// reached. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is 0; The |stream_id| does not designate stream + /// that peer initiated. + /// :enum:`NGHTTP2_ERR_STREAM_CLOSED` + /// The stream was already closed; or the |stream_id| is invalid. + /// + /// .. warning:: + /// + /// This function returns assigned promised stream ID if it succeeds. + /// As of 1.16.0, stream object for pushed resource is created when + /// this function succeeds. In that case, the application can submit + /// push response for the promised frame. + /// + /// In 1.15.0 or prior versions, pushed stream is not opened yet when + /// this function succeeds. The application must not submit frame to + /// that stream ID before :type:`nghttp2_before_frame_send_callback` + /// is called for this frame. + /// + pub fn nghttp2_submit_push_promise( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + nva: *const nghttp2_nv, + nvlen: usize, + promised_stream_user_data: *mut ::std::os::raw::c_void, + ) -> i32; +} +extern "C" { + /// @function + /// + /// Submits PING frame. You don't have to send PING back when you + /// received PING frame. The library automatically submits PING frame + /// in this case. + /// + /// The |flags| is bitwise OR of 0 or more of the following value. + /// + /// * :enum:`NGHTTP2_FLAG_ACK` + /// + /// Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags| + /// should be :enum:`NGHTTP2_FLAG_NONE`. + /// + /// If the |opaque_data| is non ``NULL``, then it should point to the 8 + /// bytes array of memory to specify opaque data to send with PING + /// frame. If the |opaque_data| is ``NULL``, zero-cleared 8 bytes will + /// be sent as opaque data. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_submit_ping( + session: *mut nghttp2_session, + flags: u8, + opaque_data: *const u8, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits GOAWAY frame with the last stream ID |last_stream_id| and + /// the error code |error_code|. + /// + /// The pre-defined error code is one of :enum:`nghttp2_error_code`. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// The |last_stream_id| is peer's stream ID or 0. So if |session| is + /// initialized as client, |last_stream_id| must be even or 0. If + /// |session| is initialized as server, |last_stream_id| must be odd or + /// 0. + /// + /// The HTTP/2 specification says last_stream_id must not be increased + /// from the value previously sent. So the actual value sent as + /// last_stream_id is the minimum value between the given + /// |last_stream_id| and the last_stream_id previously sent to the + /// peer. + /// + /// If the |opaque_data| is not ``NULL`` and |opaque_data_len| is not + /// zero, those data will be sent as additional debug data. The + /// library makes a copy of the memory region pointed by |opaque_data| + /// with the length |opaque_data_len|, so the caller does not need to + /// keep this memory after the return of this function. If the + /// |opaque_data_len| is 0, the |opaque_data| could be ``NULL``. + /// + /// After successful transmission of GOAWAY, following things happen. + /// All incoming streams having strictly more than |last_stream_id| are + /// closed. All incoming HEADERS which starts new stream are simply + /// ignored. After all active streams are handled, both + /// `nghttp2_session_want_read()` and `nghttp2_session_want_write()` + /// return 0 and the application can close session. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |opaque_data_len| is too large; the |last_stream_id| is + /// invalid. + pub fn nghttp2_submit_goaway( + session: *mut nghttp2_session, + flags: u8, + last_stream_id: i32, + error_code: u32, + opaque_data: *const u8, + opaque_data_len: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the last stream ID of a stream for which + /// :type:`nghttp2_on_frame_recv_callback` was invoked most recently. + /// The returned value can be used as last_stream_id parameter for + /// `nghttp2_submit_goaway()` and + /// `nghttp2_session_terminate_session2()`. + /// + /// This function always succeeds. + pub fn nghttp2_session_get_last_proc_stream_id(session: *mut nghttp2_session) -> i32; +} +extern "C" { + /// @function + /// + /// Returns nonzero if new request can be sent from local endpoint. + /// + /// This function return 0 if request is not allowed for this session. + /// There are several reasons why request is not allowed. Some of the + /// reasons are: session is server; stream ID has been spent; GOAWAY + /// has been sent or received. + /// + /// The application can call `nghttp2_submit_request()` without + /// consulting this function. In that case, `nghttp2_submit_request()` + /// may return error. Or, request is failed to sent, and + /// :type:`nghttp2_on_stream_close_callback` is called. + pub fn nghttp2_session_check_request_allowed( + session: *mut nghttp2_session, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns nonzero if |session| is initialized as server side session. + pub fn nghttp2_session_check_server_session( + session: *mut nghttp2_session, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits WINDOW_UPDATE frame. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// The |stream_id| is the stream ID to send this WINDOW_UPDATE. To + /// send connection level WINDOW_UPDATE, specify 0 to |stream_id|. + /// + /// If the |window_size_increment| is positive, the WINDOW_UPDATE with + /// that value as window_size_increment is queued. If the + /// |window_size_increment| is larger than the received bytes from the + /// remote endpoint, the local window size is increased by that + /// difference. If the sole purpose is to increase the local window + /// size, consider to use `nghttp2_session_set_local_window_size()`. + /// + /// If the |window_size_increment| is negative, the local window size + /// is decreased by -|window_size_increment|. If automatic + /// WINDOW_UPDATE is enabled + /// (`nghttp2_option_set_no_auto_window_update()`), and the library + /// decided that the WINDOW_UPDATE should be submitted, then + /// WINDOW_UPDATE is queued with the current received bytes count. If + /// the sole purpose is to decrease the local window size, consider to + /// use `nghttp2_session_set_local_window_size()`. + /// + /// If the |window_size_increment| is 0, the function does nothing and + /// returns 0. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_FLOW_CONTROL` + /// The local window size overflow or gets negative. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_submit_window_update( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + window_size_increment: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Set local window size (local endpoints's window size) to the given + /// |window_size| for the given stream denoted by |stream_id|. To + /// change connection level window size, specify 0 to |stream_id|. To + /// increase window size, this function may submit WINDOW_UPDATE frame + /// to transmission queue. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// This sounds similar to `nghttp2_submit_window_update()`, but there + /// are 2 differences. The first difference is that this function + /// takes the absolute value of window size to set, rather than the + /// delta. To change the window size, this may be easier to use since + /// the application just declares the intended window size, rather than + /// calculating delta. The second difference is that + /// `nghttp2_submit_window_update()` affects the received bytes count + /// which has not acked yet. By the specification of + /// `nghttp2_submit_window_update()`, to strictly increase the local + /// window size, we have to submit delta including all received bytes + /// count, which might not be desirable in some cases. On the other + /// hand, this function does not affect the received bytes count. It + /// just sets the local window size to the given value. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The |stream_id| is negative. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_session_set_local_window_size( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + window_size: i32, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Submits extension frame. + /// + /// Application can pass arbitrary frame flags and stream ID in |flags| + /// and |stream_id| respectively. The |payload| is opaque pointer, and + /// it can be accessible though ``frame->ext.payload`` in + /// :type:`nghttp2_pack_extension_callback`. The library will not own + /// passed |payload| pointer. + /// + /// The application must set :type:`nghttp2_pack_extension_callback` + /// using `nghttp2_session_callbacks_set_pack_extension_callback()`. + /// + /// The application should retain the memory pointed by |payload| until + /// the transmission of extension frame is done (which is indicated by + /// :type:`nghttp2_on_frame_send_callback`), or transmission fails + /// (which is indicated by :type:`nghttp2_on_frame_not_send_callback`). + /// If application does not touch this memory region after packing it + /// into a wire format, application can free it inside + /// :type:`nghttp2_pack_extension_callback`. + /// + /// The standard HTTP/2 frame cannot be sent with this function, so + /// |type| must be strictly grater than 0x9. Otherwise, this function + /// will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// If :type:`nghttp2_pack_extension_callback` is not set. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// If |type| specifies standard HTTP/2 frame type. The frame + /// types in the rage [0x0, 0x9], both inclusive, are standard + /// HTTP/2 frame type, and cannot be sent using this function. + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory + pub fn nghttp2_submit_extension( + session: *mut nghttp2_session, + type_: u8, + flags: u8, + stream_id: i32, + payload: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +/// @struct +/// +/// The payload of ALTSVC frame. ALTSVC frame is a non-critical +/// extension to HTTP/2. If this frame is received, and +/// `nghttp2_option_set_user_recv_extension_type()` is not set, and +/// `nghttp2_option_set_builtin_recv_extension_type()` is set for +/// :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to +/// this struct. +/// +/// It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_ext_altsvc { + /// The pointer to origin which this alternative service is + /// associated with. This is not necessarily NULL-terminated. + pub origin: *mut u8, + /// The length of the |origin|. + pub origin_len: usize, + /// The pointer to Alt-Svc field value contained in ALTSVC frame. + /// This is not necessarily NULL-terminated. + pub field_value: *mut u8, + /// The length of the |field_value|. + pub field_value_len: usize, +} +extern "C" { + /// @function + /// + /// Submits ALTSVC frame. + /// + /// ALTSVC frame is a non-critical extension to HTTP/2, and defined in + /// `RFC 7383 `_. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// The |origin| points to the origin this alternative service is + /// associated with. The |origin_len| is the length of the origin. If + /// |stream_id| is 0, the origin must be specified. If |stream_id| is + /// not zero, the origin must be empty (in other words, |origin_len| + /// must be 0). + /// + /// The ALTSVC frame is only usable from server side. If this function + /// is invoked with client side session, this function returns + /// :enum:`NGHTTP2_ERR_INVALID_STATE`. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// The function is called from client side session + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// The sum of |origin_len| and |field_value_len| is larger than + /// 16382; or |origin_len| is 0 while |stream_id| is 0; or + /// |origin_len| is not 0 while |stream_id| is not 0. + pub fn nghttp2_submit_altsvc( + session: *mut nghttp2_session, + flags: u8, + stream_id: i32, + origin: *const u8, + origin_len: usize, + field_value: *const u8, + field_value_len: usize, + ) -> ::std::os::raw::c_int; +} +/// @struct +/// +/// The single entry of an origin. +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_origin_entry { + /// The pointer to origin. No validation is made against this field + /// by the library. This is not necessarily NULL-terminated. + pub origin: *mut u8, + /// The length of the |origin|. + pub origin_len: usize, +} +/// @struct +/// +/// The payload of ORIGIN frame. ORIGIN frame is a non-critical +/// extension to HTTP/2 and defined by `RFC 8336 +/// `_. +/// +/// If this frame is received, and +/// `nghttp2_option_set_user_recv_extension_type()` is not set, and +/// `nghttp2_option_set_builtin_recv_extension_type()` is set for +/// :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to +/// this struct. +/// +/// It has the following members: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_ext_origin { + /// The number of origins contained in |ov|. + pub nov: usize, + /// The pointer to the array of origins contained in ORIGIN frame. + pub ov: *mut nghttp2_origin_entry, +} +extern "C" { + /// @function + /// + /// Submits ORIGIN frame. + /// + /// ORIGIN frame is a non-critical extension to HTTP/2 and defined by + /// `RFC 8336 `_. + /// + /// The |flags| is currently ignored and should be + /// :enum:`NGHTTP2_FLAG_NONE`. + /// + /// The |ov| points to the array of origins. The |nov| specifies the + /// number of origins included in |ov|. This function creates copies + /// of all elements in |ov|. + /// + /// The ORIGIN frame is only usable by a server. If this function is + /// invoked with client side session, this function returns + /// :enum:`NGHTTP2_ERR_INVALID_STATE`. + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// The function is called from client side session. + /// :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + /// There are too many origins, or an origin is too large to fit + /// into a default frame payload. + pub fn nghttp2_submit_origin( + session: *mut nghttp2_session, + flags: u8, + ov: *const nghttp2_origin_entry, + nov: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Compares ``lhs->name`` of length ``lhs->namelen`` bytes and + /// ``rhs->name`` of length ``rhs->namelen`` bytes. Returns negative + /// integer if ``lhs->name`` is found to be less than ``rhs->name``; or + /// returns positive integer if ``lhs->name`` is found to be greater + /// than ``rhs->name``; or returns 0 otherwise. + pub fn nghttp2_nv_compare_name( + lhs: *const nghttp2_nv, + rhs: *const nghttp2_nv, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// A helper function for dealing with NPN in client side or ALPN in + /// server side. The |in| contains peer's protocol list in preferable + /// order. The format of |in| is length-prefixed and not + /// null-terminated. For example, ``h2`` and + /// ``http/1.1`` stored in |in| like this:: + /// + /// in[0] = 2 + /// in[1..2] = "h2" + /// in[3] = 8 + /// in[4..11] = "http/1.1" + /// inlen = 12 + /// + /// The selection algorithm is as follows: + /// + /// 1. If peer's list contains HTTP/2 protocol the library supports, + /// it is selected and returns 1. The following step is not taken. + /// + /// 2. If peer's list contains ``http/1.1``, this function selects + /// ``http/1.1`` and returns 0. The following step is not taken. + /// + /// 3. This function selects nothing and returns -1 (So called + /// non-overlap case). In this case, |out| and |outlen| are left + /// untouched. + /// + /// Selecting ``h2`` means that ``h2`` is written into |*out| and its + /// length (which is 2) is assigned to |*outlen|. + /// + /// For ALPN, refer to https://tools.ietf.org/html/rfc7301 + /// + /// See http://technotes.googlecode.com/git/nextprotoneg.html for more + /// details about NPN. + /// + /// For NPN, to use this method you should do something like:: + /// + /// static int select_next_proto_cb(SSL* ssl, + /// unsigned char **out, + /// unsigned char *outlen, + /// const unsigned char *in, + /// unsigned int inlen, + /// void *arg) + /// { + /// int rv; + /// rv = nghttp2_select_next_protocol(out, outlen, in, inlen); + /// if (rv == -1) { + /// return SSL_TLSEXT_ERR_NOACK; + /// } + /// if (rv == 1) { + /// ((MyType*)arg)->http2_selected = 1; + /// } + /// return SSL_TLSEXT_ERR_OK; + /// } + /// ... + /// SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj); + /// + pub fn nghttp2_select_next_protocol( + out: *mut *mut ::std::os::raw::c_uchar, + outlen: *mut ::std::os::raw::c_uchar, + in_: *const ::std::os::raw::c_uchar, + inlen: ::std::os::raw::c_uint, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns a pointer to a nghttp2_info struct with version information + /// about the run-time library in use. The |least_version| argument + /// can be set to a 24 bit numerical value for the least accepted + /// version number and if the condition is not met, this function will + /// return a ``NULL``. Pass in 0 to skip the version checking. + pub fn nghttp2_version(least_version: ::std::os::raw::c_int) -> *mut nghttp2_info; +} +extern "C" { + /// @function + /// + /// Returns nonzero if the :type:`nghttp2_error` library error code + /// |lib_error| is fatal. + pub fn nghttp2_is_fatal(lib_error_code: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns nonzero if HTTP header field name |name| of length |len| is + /// valid according to http://tools.ietf.org/html/rfc7230#section-3.2 + /// + /// Because this is a header field name in HTTP2, the upper cased alphabet + /// is treated as error. + pub fn nghttp2_check_header_name(name: *const u8, len: usize) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns nonzero if HTTP header field value |value| of length |len| + /// is valid according to + /// http://tools.ietf.org/html/rfc7230#section-3.2 + pub fn nghttp2_check_header_value(value: *const u8, len: usize) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_hd_deflater { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Initializes |*deflater_ptr| for deflating name/values pairs. + /// + /// The |max_deflate_dynamic_table_size| is the upper bound of header + /// table size the deflater will use. + /// + /// If this function fails, |*deflater_ptr| is left untouched. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_hd_deflate_new( + deflater_ptr: *mut *mut nghttp2_hd_deflater, + max_deflate_dynamic_table_size: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_hd_deflate_new()`, but with additional custom memory + /// allocator specified in the |mem|. + /// + /// The |mem| can be ``NULL`` and the call is equivalent to + /// `nghttp2_hd_deflate_new()`. + /// + /// This function does not take ownership |mem|. The application is + /// responsible for freeing |mem|. + /// + /// The library code does not refer to |mem| pointer after this + /// function returns, so the application can safely free it. + pub fn nghttp2_hd_deflate_new2( + deflater_ptr: *mut *mut nghttp2_hd_deflater, + max_deflate_dynamic_table_size: usize, + mem: *mut nghttp2_mem, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Deallocates any resources allocated for |deflater|. + pub fn nghttp2_hd_deflate_del(deflater: *mut nghttp2_hd_deflater); +} +extern "C" { + /// @function + /// + /// Changes header table size of the |deflater| to + /// |settings_max_dynamic_table_size| bytes. This may trigger eviction + /// in the dynamic table. + /// + /// The |settings_max_dynamic_table_size| should be the value received + /// in SETTINGS_HEADER_TABLE_SIZE. + /// + /// The deflater never uses more memory than + /// ``max_deflate_dynamic_table_size`` bytes specified in + /// `nghttp2_hd_deflate_new()`. Therefore, if + /// |settings_max_dynamic_table_size| > + /// ``max_deflate_dynamic_table_size``, resulting maximum table size + /// becomes ``max_deflate_dynamic_table_size``. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_hd_deflate_change_table_size( + deflater: *mut nghttp2_hd_deflater, + settings_max_dynamic_table_size: usize, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Deflates the |nva|, which has the |nvlen| name/value pairs, into + /// the |buf| of length |buflen|. + /// + /// If |buf| is not large enough to store the deflated header block, + /// this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The + /// caller should use `nghttp2_hd_deflate_bound()` to know the upper + /// bound of buffer size required to deflate given header name/value + /// pairs. + /// + /// Once this function fails, subsequent call of this function always + /// returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + /// + /// After this function returns, it is safe to delete the |nva|. + /// + /// This function returns the number of bytes written to |buf| if it + /// succeeds, or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_HEADER_COMP` + /// Deflation process has failed. + /// :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + /// The provided |buflen| size is too small to hold the output. + pub fn nghttp2_hd_deflate_hd( + deflater: *mut nghttp2_hd_deflater, + buf: *mut u8, + buflen: usize, + nva: *const nghttp2_nv, + nvlen: usize, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Deflates the |nva|, which has the |nvlen| name/value pairs, into + /// the |veclen| size of buf vector |vec|. The each size of buffer + /// must be set in len field of :type:`nghttp2_vec`. If and only if + /// one chunk is filled up completely, next chunk will be used. If + /// |vec| is not large enough to store the deflated header block, this + /// function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller + /// should use `nghttp2_hd_deflate_bound()` to know the upper bound of + /// buffer size required to deflate given header name/value pairs. + /// + /// Once this function fails, subsequent call of this function always + /// returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + /// + /// After this function returns, it is safe to delete the |nva|. + /// + /// This function returns the number of bytes written to |vec| if it + /// succeeds, or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_HEADER_COMP` + /// Deflation process has failed. + /// :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + /// The provided |buflen| size is too small to hold the output. + pub fn nghttp2_hd_deflate_hd_vec( + deflater: *mut nghttp2_hd_deflater, + vec: *const nghttp2_vec, + veclen: usize, + nva: *const nghttp2_nv, + nvlen: usize, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Returns an upper bound on the compressed size after deflation of + /// |nva| of length |nvlen|. + pub fn nghttp2_hd_deflate_bound( + deflater: *mut nghttp2_hd_deflater, + nva: *const nghttp2_nv, + nvlen: usize, + ) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the number of entries that header table of |deflater| + /// contains. This is the sum of the number of static table and + /// dynamic table, so the return value is at least 61. + pub fn nghttp2_hd_deflate_get_num_table_entries(deflater: *mut nghttp2_hd_deflater) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the table entry denoted by |idx| from header table of + /// |deflater|. The |idx| is 1-based, and idx=1 returns first entry of + /// static table. idx=62 returns first entry of dynamic table if it + /// exists. Specifying idx=0 is error, and this function returns NULL. + /// If |idx| is strictly greater than the number of entries the tables + /// contain, this function returns NULL. + pub fn nghttp2_hd_deflate_get_table_entry( + deflater: *mut nghttp2_hd_deflater, + idx: usize, + ) -> *const nghttp2_nv; +} +extern "C" { + /// @function + /// + /// Returns the used dynamic table size, including the overhead 32 + /// bytes per entry described in RFC 7541. + pub fn nghttp2_hd_deflate_get_dynamic_table_size(deflater: *mut nghttp2_hd_deflater) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the maximum dynamic table size. + pub fn nghttp2_hd_deflate_get_max_dynamic_table_size( + deflater: *mut nghttp2_hd_deflater, + ) -> usize; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_hd_inflater { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Initializes |*inflater_ptr| for inflating name/values pairs. + /// + /// If this function fails, |*inflater_ptr| is left untouched. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + pub fn nghttp2_hd_inflate_new( + inflater_ptr: *mut *mut nghttp2_hd_inflater, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Like `nghttp2_hd_inflate_new()`, but with additional custom memory + /// allocator specified in the |mem|. + /// + /// The |mem| can be ``NULL`` and the call is equivalent to + /// `nghttp2_hd_inflate_new()`. + /// + /// This function does not take ownership |mem|. The application is + /// responsible for freeing |mem|. + /// + /// The library code does not refer to |mem| pointer after this + /// function returns, so the application can safely free it. + pub fn nghttp2_hd_inflate_new2( + inflater_ptr: *mut *mut nghttp2_hd_inflater, + mem: *mut nghttp2_mem, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Deallocates any resources allocated for |inflater|. + pub fn nghttp2_hd_inflate_del(inflater: *mut nghttp2_hd_inflater); +} +extern "C" { + /// @function + /// + /// Changes header table size in the |inflater|. This may trigger + /// eviction in the dynamic table. + /// + /// The |settings_max_dynamic_table_size| should be the value + /// transmitted in SETTINGS_HEADER_TABLE_SIZE. + /// + /// This function must not be called while header block is being + /// inflated. In other words, this function must be called after + /// initialization of |inflater|, but before calling + /// `nghttp2_hd_inflate_hd2()`, or after + /// `nghttp2_hd_inflate_end_headers()`. Otherwise, + /// `NGHTTP2_ERR_INVALID_STATE` was returned. + /// + /// This function returns 0 if it succeeds, or one of the following + /// negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_INVALID_STATE` + /// The function is called while header block is being inflated. + /// Probably, application missed to call + /// `nghttp2_hd_inflate_end_headers()`. + pub fn nghttp2_hd_inflate_change_table_size( + inflater: *mut nghttp2_hd_inflater, + settings_max_dynamic_table_size: usize, + ) -> ::std::os::raw::c_int; +} +/// No flag set. +pub const NGHTTP2_HD_INFLATE_NONE: nghttp2_hd_inflate_flag = 0; +/// Indicates all headers were inflated. +pub const NGHTTP2_HD_INFLATE_FINAL: nghttp2_hd_inflate_flag = 1; +/// Indicates a header was emitted. +pub const NGHTTP2_HD_INFLATE_EMIT: nghttp2_hd_inflate_flag = 2; +/// @enum +/// +/// The flags for header inflation. +pub type nghttp2_hd_inflate_flag = u32; +extern "C" { + /// @function + /// + /// .. warning:: + /// + /// Deprecated. Use `nghttp2_hd_inflate_hd2()` instead. + /// + /// Inflates name/value block stored in |in| with length |inlen|. This + /// function performs decompression. For each successful emission of + /// header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + /// |*inflate_flags| and name/value pair is assigned to the |nv_out| + /// and the function returns. The caller must not free the members of + /// |nv_out|. + /// + /// The |nv_out| may include pointers to the memory region in the |in|. + /// The caller must retain the |in| while the |nv_out| is used. + /// + /// The application should call this function repeatedly until the + /// ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and + /// return value is non-negative. This means the all input values are + /// processed successfully. Then the application must call + /// `nghttp2_hd_inflate_end_headers()` to prepare for the next header + /// block input. + /// + /// The caller can feed complete compressed header block. It also can + /// feed it in several chunks. The caller must set |in_final| to + /// nonzero if the given input is the last block of the compressed + /// header. + /// + /// This function returns the number of bytes processed if it succeeds, + /// or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_HEADER_COMP` + /// Inflation process has failed. + /// :enum:`NGHTTP2_ERR_BUFFER_ERROR` + /// The header field name or value is too large. + /// + /// Example follows:: + /// + /// int inflate_header_block(nghttp2_hd_inflater *hd_inflater, + /// uint8_t *in, size_t inlen, int final) + /// { + /// ssize_t rv; + /// + /// for(;;) { + /// nghttp2_nv nv; + /// int inflate_flags = 0; + /// + /// rv = nghttp2_hd_inflate_hd(hd_inflater, &nv, &inflate_flags, + /// in, inlen, final); + /// + /// if(rv < 0) { + /// fprintf(stderr, "inflate failed with error code %zd", rv); + /// return -1; + /// } + /// + /// in += rv; + /// inlen -= rv; + /// + /// if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + /// fwrite(nv.name, nv.namelen, 1, stderr); + /// fprintf(stderr, ": "); + /// fwrite(nv.value, nv.valuelen, 1, stderr); + /// fprintf(stderr, "\n"); + /// } + /// if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + /// nghttp2_hd_inflate_end_headers(hd_inflater); + /// break; + /// } + /// if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && + /// inlen == 0) { + /// break; + /// } + /// } + /// + /// return 0; + /// } + /// + pub fn nghttp2_hd_inflate_hd( + inflater: *mut nghttp2_hd_inflater, + nv_out: *mut nghttp2_nv, + inflate_flags: *mut ::std::os::raw::c_int, + in_: *mut u8, + inlen: usize, + in_final: ::std::os::raw::c_int, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Inflates name/value block stored in |in| with length |inlen|. This + /// function performs decompression. For each successful emission of + /// header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + /// |*inflate_flags| and name/value pair is assigned to the |nv_out| + /// and the function returns. The caller must not free the members of + /// |nv_out|. + /// + /// The |nv_out| may include pointers to the memory region in the |in|. + /// The caller must retain the |in| while the |nv_out| is used. + /// + /// The application should call this function repeatedly until the + /// ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and + /// return value is non-negative. If that happens, all given input + /// data (|inlen| bytes) are processed successfully. Then the + /// application must call `nghttp2_hd_inflate_end_headers()` to prepare + /// for the next header block input. + /// + /// In other words, if |in_final| is nonzero, and this function returns + /// |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is + /// set in |*inflate_flags|. + /// + /// The caller can feed complete compressed header block. It also can + /// feed it in several chunks. The caller must set |in_final| to + /// nonzero if the given input is the last block of the compressed + /// header. + /// + /// This function returns the number of bytes processed if it succeeds, + /// or one of the following negative error codes: + /// + /// :enum:`NGHTTP2_ERR_NOMEM` + /// Out of memory. + /// :enum:`NGHTTP2_ERR_HEADER_COMP` + /// Inflation process has failed. + /// :enum:`NGHTTP2_ERR_BUFFER_ERROR` + /// The header field name or value is too large. + /// + /// Example follows:: + /// + /// int inflate_header_block(nghttp2_hd_inflater *hd_inflater, + /// uint8_t *in, size_t inlen, int final) + /// { + /// ssize_t rv; + /// + /// for(;;) { + /// nghttp2_nv nv; + /// int inflate_flags = 0; + /// + /// rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags, + /// in, inlen, final); + /// + /// if(rv < 0) { + /// fprintf(stderr, "inflate failed with error code %zd", rv); + /// return -1; + /// } + /// + /// in += rv; + /// inlen -= rv; + /// + /// if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + /// fwrite(nv.name, nv.namelen, 1, stderr); + /// fprintf(stderr, ": "); + /// fwrite(nv.value, nv.valuelen, 1, stderr); + /// fprintf(stderr, "\n"); + /// } + /// if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + /// nghttp2_hd_inflate_end_headers(hd_inflater); + /// break; + /// } + /// if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && + /// inlen == 0) { + /// break; + /// } + /// } + /// + /// return 0; + /// } + /// + pub fn nghttp2_hd_inflate_hd2( + inflater: *mut nghttp2_hd_inflater, + nv_out: *mut nghttp2_nv, + inflate_flags: *mut ::std::os::raw::c_int, + in_: *const u8, + inlen: usize, + in_final: ::std::os::raw::c_int, + ) -> isize; +} +extern "C" { + /// @function + /// + /// Signals the end of decompression for one header block. + /// + /// This function returns 0 if it succeeds. Currently this function + /// always succeeds. + pub fn nghttp2_hd_inflate_end_headers( + inflater: *mut nghttp2_hd_inflater, + ) -> ::std::os::raw::c_int; +} +extern "C" { + /// @function + /// + /// Returns the number of entries that header table of |inflater| + /// contains. This is the sum of the number of static table and + /// dynamic table, so the return value is at least 61. + pub fn nghttp2_hd_inflate_get_num_table_entries(inflater: *mut nghttp2_hd_inflater) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the table entry denoted by |idx| from header table of + /// |inflater|. The |idx| is 1-based, and idx=1 returns first entry of + /// static table. idx=62 returns first entry of dynamic table if it + /// exists. Specifying idx=0 is error, and this function returns NULL. + /// If |idx| is strictly greater than the number of entries the tables + /// contain, this function returns NULL. + pub fn nghttp2_hd_inflate_get_table_entry( + inflater: *mut nghttp2_hd_inflater, + idx: usize, + ) -> *const nghttp2_nv; +} +extern "C" { + /// @function + /// + /// Returns the used dynamic table size, including the overhead 32 + /// bytes per entry described in RFC 7541. + pub fn nghttp2_hd_inflate_get_dynamic_table_size(inflater: *mut nghttp2_hd_inflater) -> usize; +} +extern "C" { + /// @function + /// + /// Returns the maximum dynamic table size. + pub fn nghttp2_hd_inflate_get_max_dynamic_table_size( + inflater: *mut nghttp2_hd_inflater, + ) -> usize; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nghttp2_stream { + _unused: [u8; 0], +} +extern "C" { + /// @function + /// + /// Returns pointer to :type:`nghttp2_stream` object denoted by + /// |stream_id|. If stream was not found, returns NULL. + /// + /// Returns imaginary root stream (see + /// `nghttp2_session_get_root_stream()`) if 0 is given in |stream_id|. + /// + /// Unless |stream_id| == 0, the returned pointer is valid until next + /// call of `nghttp2_session_send()`, `nghttp2_session_mem_send()`, + /// `nghttp2_session_recv()`, and `nghttp2_session_mem_recv()`. + pub fn nghttp2_session_find_stream( + session: *mut nghttp2_session, + stream_id: i32, + ) -> *mut nghttp2_stream; +} +/// idle state. +pub const NGHTTP2_STREAM_STATE_IDLE: nghttp2_stream_proto_state = 1; +/// open state. +pub const NGHTTP2_STREAM_STATE_OPEN: nghttp2_stream_proto_state = 2; +/// reserved (local) state. +pub const NGHTTP2_STREAM_STATE_RESERVED_LOCAL: nghttp2_stream_proto_state = 3; +/// reserved (remote) state. +pub const NGHTTP2_STREAM_STATE_RESERVED_REMOTE: nghttp2_stream_proto_state = 4; +/// half closed (local) state. +pub const NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL: nghttp2_stream_proto_state = 5; +/// half closed (remote) state. +pub const NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE: nghttp2_stream_proto_state = 6; +/// closed state. +pub const NGHTTP2_STREAM_STATE_CLOSED: nghttp2_stream_proto_state = 7; +/// @enum +/// +/// State of stream as described in RFC 7540. +pub type nghttp2_stream_proto_state = u32; +extern "C" { + /// @function + /// + /// Returns state of |stream|. The root stream retrieved by + /// `nghttp2_session_get_root_stream()` will have stream state + /// :enum:`NGHTTP2_STREAM_STATE_IDLE`. + pub fn nghttp2_stream_get_state(stream: *mut nghttp2_stream) -> nghttp2_stream_proto_state; +} +extern "C" { + /// @function + /// + /// Returns root of dependency tree, which is imaginary stream with + /// stream ID 0. The returned pointer is valid until |session| is + /// freed by `nghttp2_session_del()`. + pub fn nghttp2_session_get_root_stream(session: *mut nghttp2_session) -> *mut nghttp2_stream; +} +extern "C" { + /// @function + /// + /// Returns the parent stream of |stream| in dependency tree. Returns + /// NULL if there is no such stream. + pub fn nghttp2_stream_get_parent(stream: *mut nghttp2_stream) -> *mut nghttp2_stream; +} +extern "C" { + pub fn nghttp2_stream_get_stream_id(stream: *mut nghttp2_stream) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the next sibling stream of |stream| in dependency tree. + /// Returns NULL if there is no such stream. + pub fn nghttp2_stream_get_next_sibling(stream: *mut nghttp2_stream) -> *mut nghttp2_stream; +} +extern "C" { + /// @function + /// + /// Returns the previous sibling stream of |stream| in dependency tree. + /// Returns NULL if there is no such stream. + pub fn nghttp2_stream_get_previous_sibling(stream: *mut nghttp2_stream) -> *mut nghttp2_stream; +} +extern "C" { + /// @function + /// + /// Returns the first child stream of |stream| in dependency tree. + /// Returns NULL if there is no such stream. + pub fn nghttp2_stream_get_first_child(stream: *mut nghttp2_stream) -> *mut nghttp2_stream; +} +extern "C" { + /// @function + /// + /// Returns dependency weight to the parent stream of |stream|. + pub fn nghttp2_stream_get_weight(stream: *mut nghttp2_stream) -> i32; +} +extern "C" { + /// @function + /// + /// Returns the sum of the weight for |stream|'s children. + pub fn nghttp2_stream_get_sum_dependency_weight(stream: *mut nghttp2_stream) -> i32; +} diff --git a/libssh2-sys/.cargo-checksum.json b/libssh2-sys/.cargo-checksum.json new file mode 100644 index 000000000..e32a2e6af --- /dev/null +++ b/libssh2-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d"} \ No newline at end of file diff --git a/libssh2-sys/.pc/.quilt_patches b/libssh2-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/libssh2-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/libssh2-sys/.pc/.quilt_series b/libssh2-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/libssh2-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/libssh2-sys/.pc/.version b/libssh2-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/libssh2-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/libssh2-sys/.pc/applied-patches b/libssh2-sys/.pc/applied-patches new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/libssh2-sys/.pc/applied-patches @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/libssh2-sys/.pc/no-special-snowflake-env.patch/.timestamp b/libssh2-sys/.pc/no-special-snowflake-env.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/libssh2-sys/.pc/no-special-snowflake-env.patch/build.rs b/libssh2-sys/.pc/no-special-snowflake-env.patch/build.rs new file mode 100644 index 000000000..baff2397a --- /dev/null +++ b/libssh2-sys/.pc/no-special-snowflake-env.patch/build.rs @@ -0,0 +1,180 @@ +extern crate pkg_config; +extern crate cc; + +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::fs; +use std::env; +use std::path::{PathBuf, Path}; +use std::process::Command; + +fn main() { + if try_vcpkg() { + return; + } + + // The system copy of libssh2 is not used by default because it + // can lead to having two copies of libssl loaded at once. + // See https://github.com/alexcrichton/ssh2-rs/pull/88 + if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() { + if let Ok(lib) = pkg_config::find_library("libssh2") { + for path in &lib.include_paths { + println!("cargo:include={}", path.display()); + } + return + } + } + + if !Path::new("libssh2/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + let target = env::var("TARGET").unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let mut cfg = cc::Build::new(); + + let include = dst.join("include"); + println!("cargo:include={}", include.display()); + println!("cargo:root={}", dst.display()); + let build = dst.join("build"); + cfg.out_dir(&build); + fs::create_dir_all(&build).unwrap(); + fs::create_dir_all(&include).unwrap(); + + fs::copy("libssh2/include/libssh2.h", include.join("libssh2.h")).unwrap(); + fs::copy("libssh2/include/libssh2_publickey.h", include.join("libssh2_publickey.h")).unwrap(); + fs::copy("libssh2/include/libssh2_sftp.h", include.join("libssh2_sftp.h")).unwrap(); + + cfg.file("libssh2/src/agent.c") + .file("libssh2/src/bcrypt_pbkdf.c") + .file("libssh2/src/blowfish.c") + .file("libssh2/src/channel.c") + .file("libssh2/src/comp.c") + .file("libssh2/src/crypt.c") + .file("libssh2/src/global.c") + .file("libssh2/src/hostkey.c") + .file("libssh2/src/keepalive.c") + .file("libssh2/src/kex.c") + .file("libssh2/src/knownhost.c") + .file("libssh2/src/mac.c") + .file("libssh2/src/misc.c") + .file("libssh2/src/packet.c") + .file("libssh2/src/pem.c") + .file("libssh2/src/publickey.c") + .file("libssh2/src/scp.c") + .file("libssh2/src/session.c") + .file("libssh2/src/sftp.c") + .file("libssh2/src/transport.c") + .file("libssh2/src/userauth.c") + .include(&include) + .include("libssh2/src"); + + cfg.define("HAVE_LONGLONG", None); + + if target.contains("windows") { + cfg.include("libssh2/win32"); + cfg.define("LIBSSH2_WINCNG", None); + cfg.file("libssh2/src/wincng.c"); + } else { + cfg.flag("-fvisibility=hidden"); + cfg.define("HAVE_SNPRINTF", None); + cfg.define("HAVE_UNISTD_H", None); + cfg.define("HAVE_INTTYPES_H", None); + cfg.define("HAVE_STDLIB_H", None); + cfg.define("HAVE_SYS_SELECT_H", None); + cfg.define("HAVE_SYS_SOCKET_H", None); + cfg.define("HAVE_SYS_IOCTL_H", None); + cfg.define("HAVE_SYS_TIME_H", None); + cfg.define("HAVE_SYS_UN_H", None); + cfg.define("HAVE_O_NONBLOCK", None); + cfg.define("LIBSSH2_OPENSSL", None); + cfg.define("HAVE_LIBCRYPT32", None); + cfg.define("HAVE_EVP_AES_128_CTR", None); + + cfg.file("libssh2/src/openssl.c"); + + // Create `libssh2_config.h` + let config = fs::read_to_string("libssh2/src/libssh2_config_cmake.h.in") + .unwrap(); + let config = config.lines() + .filter(|l| !l.contains("#cmakedefine")) + .collect::>() + .join("\n"); + fs::write(build.join("libssh2_config.h"), &config).unwrap(); + cfg.include(&build); + } + + cfg.define("LIBSSH2_HAVE_ZLIB", None); + if let Some(path) = env::var_os("DEP_Z_INCLUDE") { + cfg.include(path); + } + + if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { + if let Some(path) = env::split_paths(&path).next() { + if let Some(path) = path.to_str() { + if path.len() > 0 { + cfg.include(path); + } + } + } + } + + let libssh2h = fs::read_to_string("libssh2/include/libssh2.h").unwrap(); + let version_line = libssh2h.lines() + .find(|l| l.contains("LIBSSH2_VERSION")) + .unwrap(); + let version = &version_line[version_line.find('"').unwrap() + 1..version_line.len() - 1]; + + let pkgconfig = dst.join("lib/pkgconfig"); + fs::create_dir_all(&pkgconfig).unwrap(); + fs::write( + pkgconfig.join("libssh2.pc"), + fs::read_to_string("libssh2/libssh2.pc.in") + .unwrap() + .replace("@prefix@", dst.to_str().unwrap()) + .replace("@exec_prefix@", "") + .replace("@libdir@", dst.join("lib").to_str().unwrap()) + .replace("@includedir@", include.to_str().unwrap()) + .replace("@LIBS@", "") + .replace("@LIBSREQUIRED@", "") + .replace("@LIBSSH2VER@", version), + ).unwrap(); + + cfg.warnings(false); + cfg.compile("ssh2"); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=bcrypt"); + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=user32"); + } +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> bool { false } + +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> bool { + vcpkg::Config::new() + .emit_includes(true) + .probe("libssh2").map(|_| { + + // found libssh2 which depends on openssl and zlib + vcpkg::Config::new() + .lib_name("libeay32") + .lib_name("ssleay32") + .probe("openssl").expect("configured libssh2 from vcpkg but could not \ + find openssl libraries that it depends on"); + + vcpkg::Config::new() + .lib_names("zlib", "zlib1") + .probe("zlib").expect("configured libssh2 from vcpkg but could not \ + find the zlib library that it depends on"); + + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=user32"); + }).is_ok() +} diff --git a/libssh2-sys/Cargo.toml b/libssh2-sys/Cargo.toml new file mode 100644 index 000000000..3671dc818 --- /dev/null +++ b/libssh2-sys/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libssh2-sys" +version = "0.2.11" +authors = ["Alex Crichton "] +build = "build.rs" +links = "ssh2" +description = "Native bindings to the libssh2 library" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/ssh2-rs" + +[lib] +name = "libssh2_sys" +path = "lib.rs" +[dependencies.libc] +version = "0.2" + +[dependencies.libz-sys] +version = "1.0.21" +[build-dependencies.cc] +version = "1.0.25" + +[build-dependencies.pkg-config] +version = "0.3.11" +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" +[target."cfg(unix)".dependencies.openssl-sys] +version = "0.9.35" diff --git a/libssh2-sys/build.rs b/libssh2-sys/build.rs new file mode 100644 index 000000000..57a1de481 --- /dev/null +++ b/libssh2-sys/build.rs @@ -0,0 +1,181 @@ +extern crate pkg_config; +extern crate cc; + +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::fs; +use std::env; +use std::path::{PathBuf, Path}; +use std::process::Command; + +fn main() { + if try_vcpkg() { + return; + } + + // The system copy of libssh2 is not used by default because it + // can lead to having two copies of libssl loaded at once. + // See https://github.com/alexcrichton/ssh2-rs/pull/88 + // if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() { + if let Ok(lib) = pkg_config::find_library("libssh2") { + for path in &lib.include_paths { + println!("cargo:include={}", path.display()); + } + return; + } + // } + + // if !Path::new("libssh2/.git").exists() { + // let _ = Command::new("git") + // .args(&["submodule", "update", "--init"]) + // .status(); + // } + + let target = env::var("TARGET").unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let mut cfg = cc::Build::new(); + + let include = dst.join("include"); + println!("cargo:include={}", include.display()); + println!("cargo:root={}", dst.display()); + let build = dst.join("build"); + cfg.out_dir(&build); + fs::create_dir_all(&build).unwrap(); + fs::create_dir_all(&include).unwrap(); + + fs::copy("libssh2/include/libssh2.h", include.join("libssh2.h")).unwrap(); + fs::copy("libssh2/include/libssh2_publickey.h", include.join("libssh2_publickey.h")).unwrap(); + fs::copy("libssh2/include/libssh2_sftp.h", include.join("libssh2_sftp.h")).unwrap(); + + cfg.file("libssh2/src/agent.c") + .file("libssh2/src/bcrypt_pbkdf.c") + .file("libssh2/src/blowfish.c") + .file("libssh2/src/channel.c") + .file("libssh2/src/comp.c") + .file("libssh2/src/crypt.c") + .file("libssh2/src/global.c") + .file("libssh2/src/hostkey.c") + .file("libssh2/src/keepalive.c") + .file("libssh2/src/kex.c") + .file("libssh2/src/knownhost.c") + .file("libssh2/src/mac.c") + .file("libssh2/src/misc.c") + .file("libssh2/src/packet.c") + .file("libssh2/src/pem.c") + .file("libssh2/src/publickey.c") + .file("libssh2/src/scp.c") + .file("libssh2/src/session.c") + .file("libssh2/src/sftp.c") + .file("libssh2/src/transport.c") + .file("libssh2/src/userauth.c") + .include(&include) + .include("libssh2/src"); + + cfg.define("HAVE_LONGLONG", None); + + if target.contains("windows") { + cfg.include("libssh2/win32"); + cfg.define("LIBSSH2_WINCNG", None); + cfg.file("libssh2/src/wincng.c"); + } else { + cfg.flag("-fvisibility=hidden"); + cfg.define("HAVE_SNPRINTF", None); + cfg.define("HAVE_UNISTD_H", None); + cfg.define("HAVE_INTTYPES_H", None); + cfg.define("HAVE_STDLIB_H", None); + cfg.define("HAVE_SYS_SELECT_H", None); + cfg.define("HAVE_SYS_SOCKET_H", None); + cfg.define("HAVE_SYS_IOCTL_H", None); + cfg.define("HAVE_SYS_TIME_H", None); + cfg.define("HAVE_SYS_UN_H", None); + cfg.define("HAVE_O_NONBLOCK", None); + cfg.define("LIBSSH2_OPENSSL", None); + cfg.define("HAVE_LIBCRYPT32", None); + cfg.define("HAVE_EVP_AES_128_CTR", None); + + cfg.file("libssh2/src/openssl.c"); + + // Create `libssh2_config.h` + let config = fs::read_to_string("libssh2/src/libssh2_config_cmake.h.in") + .unwrap(); + let config = config.lines() + .filter(|l| !l.contains("#cmakedefine")) + .collect::>() + .join("\n"); + fs::write(build.join("libssh2_config.h"), &config).unwrap(); + cfg.include(&build); + } + + cfg.define("LIBSSH2_HAVE_ZLIB", None); + if let Some(path) = env::var_os("DEP_Z_INCLUDE") { + cfg.include(path); + } + + if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { + if let Some(path) = env::split_paths(&path).next() { + if let Some(path) = path.to_str() { + if path.len() > 0 { + cfg.include(path); + } + } + } + } + + let libssh2h = fs::read_to_string("libssh2/include/libssh2.h").unwrap(); + let version_line = libssh2h.lines() + .find(|l| l.contains("LIBSSH2_VERSION")) + .unwrap(); + let version = &version_line[version_line.find('"').unwrap() + 1..version_line.len() - 1]; + + let pkgconfig = dst.join("lib/pkgconfig"); + fs::create_dir_all(&pkgconfig).unwrap(); + fs::write( + pkgconfig.join("libssh2.pc"), + fs::read_to_string("libssh2/libssh2.pc.in") + .unwrap() + .replace("@prefix@", dst.to_str().unwrap()) + .replace("@exec_prefix@", "") + .replace("@libdir@", dst.join("lib").to_str().unwrap()) + .replace("@includedir@", include.to_str().unwrap()) + .replace("@LIBS@", "") + .replace("@LIBSREQUIRED@", "") + .replace("@LIBSSH2VER@", version), + ).unwrap(); + + cfg.warnings(false); + cfg.compile("ssh2"); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=bcrypt"); + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=user32"); + } +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> bool { false } + +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> bool { + vcpkg::Config::new() + .emit_includes(true) + .probe("libssh2").map(|_| { + + // found libssh2 which depends on openssl and zlib + vcpkg::Config::new() + .lib_name("libeay32") + .lib_name("ssleay32") + .probe("openssl").expect("configured libssh2 from vcpkg but could not \ + find openssl libraries that it depends on"); + + vcpkg::Config::new() + .lib_names("zlib", "zlib1") + .probe("zlib").expect("configured libssh2 from vcpkg but could not \ + find the zlib library that it depends on"); + + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=user32"); + }).is_ok() +} diff --git a/libssh2-sys/debian/patches/no-special-snowflake-env.patch b/libssh2-sys/debian/patches/no-special-snowflake-env.patch new file mode 100644 index 000000000..9b7a6bd74 --- /dev/null +++ b/libssh2-sys/debian/patches/no-special-snowflake-env.patch @@ -0,0 +1,41 @@ +Description: Use libssh2 from system by default +Author: Vasudev Kamath +Bug: https://github.com/alexcrichton/ssh2-rs/issues/88 +Forwarded: not-needed +Last-Update: 2018-07-28 + +Index: libssh2-sys/build.rs +=================================================================== +--- libssh2-sys.orig/build.rs ++++ libssh2-sys/build.rs +@@ -17,19 +17,20 @@ fn main() { + // The system copy of libssh2 is not used by default because it + // can lead to having two copies of libssl loaded at once. + // See https://github.com/alexcrichton/ssh2-rs/pull/88 +- if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() { +- if let Ok(lib) = pkg_config::find_library("libssh2") { +- for path in &lib.include_paths { +- println!("cargo:include={}", path.display()); +- } +- return ++ // if env::var("LIBSSH2_SYS_USE_PKG_CONFIG").is_ok() { ++ if let Ok(lib) = pkg_config::find_library("libssh2") { ++ for path in &lib.include_paths { ++ println!("cargo:include={}", path.display()); + } ++ return; + } ++ // } + +- if !Path::new("libssh2/.git").exists() { +- let _ = Command::new("git").args(&["submodule", "update", "--init"]) +- .status(); +- } ++ // if !Path::new("libssh2/.git").exists() { ++ // let _ = Command::new("git") ++ // .args(&["submodule", "update", "--init"]) ++ // .status(); ++ // } + + let target = env::var("TARGET").unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); diff --git a/libssh2-sys/debian/patches/series b/libssh2-sys/debian/patches/series new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/libssh2-sys/debian/patches/series @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/libssh2-sys/lib.rs b/libssh2-sys/lib.rs new file mode 100644 index 000000000..5c2dea43b --- /dev/null +++ b/libssh2-sys/lib.rs @@ -0,0 +1,600 @@ +#![doc(html_root_url = "http://alexcrichton.com/ssh2-rs")] +#![allow(bad_style)] +#![allow(unused_extern_crates)] + +extern crate libc; + +extern crate libz_sys; +#[cfg(unix)] +extern crate openssl_sys; + +use libc::{c_int, size_t, c_void, c_char, c_long, c_uchar, c_uint, c_ulong}; +use libc::ssize_t; + +pub const SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT: c_int = 1; +pub const SSH_DISCONNECT_PROTOCOL_ERROR: c_int = 2; +pub const SSH_DISCONNECT_KEY_EXCHANGE_FAILED: c_int = 3; +pub const SSH_DISCONNECT_RESERVED: c_int = 4; +pub const SSH_DISCONNECT_MAC_ERROR: c_int = 5; +pub const SSH_DISCONNECT_COMPRESSION_ERROR: c_int = 6; +pub const SSH_DISCONNECT_SERVICE_NOT_AVAILABLE: c_int = 7; +pub const SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED: c_int = 8; +pub const SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE: c_int = 9; +pub const SSH_DISCONNECT_CONNECTION_LOST: c_int = 10; +pub const SSH_DISCONNECT_BY_APPLICATION: c_int = 11; +pub const SSH_DISCONNECT_TOO_MANY_CONNECTIONS: c_int = 12; +pub const SSH_DISCONNECT_AUTH_CANCELLED_BY_USER: c_int = 13; +pub const SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE: c_int = 14; +pub const SSH_DISCONNECT_ILLEGAL_USER_NAME: c_int = 15; + +pub const LIBSSH2_FLAG_SIGPIPE: c_int = 1; +pub const LIBSSH2_FLAG_COMPRESS: c_int = 2; + +pub const LIBSSH2_HOSTKEY_TYPE_UNKNOWN: c_int = 0; +pub const LIBSSH2_HOSTKEY_TYPE_RSA: c_int = 1; +pub const LIBSSH2_HOSTKEY_TYPE_DSS: c_int = 2; + +pub const LIBSSH2_METHOD_KEX: c_int = 0; +pub const LIBSSH2_METHOD_HOSTKEY: c_int = 1; +pub const LIBSSH2_METHOD_CRYPT_CS: c_int = 2; +pub const LIBSSH2_METHOD_CRYPT_SC: c_int = 3; +pub const LIBSSH2_METHOD_MAC_CS: c_int = 4; +pub const LIBSSH2_METHOD_MAC_SC: c_int = 5; +pub const LIBSSH2_METHOD_COMP_CS: c_int = 6; +pub const LIBSSH2_METHOD_COMP_SC: c_int = 7; +pub const LIBSSH2_METHOD_LANG_CS: c_int = 8; +pub const LIBSSH2_METHOD_LANG_SC: c_int = 9; + +pub const LIBSSH2_CHANNEL_PACKET_DEFAULT: c_uint = 32768; +pub const LIBSSH2_CHANNEL_WINDOW_DEFAULT: c_uint = 2 * 1024 * 1024; + +pub const LIBSSH2_ERROR_BANNER_RECV: c_int = -2; +pub const LIBSSH2_ERROR_BANNER_SEND: c_int = -3; +pub const LIBSSH2_ERROR_INVALID_MAC: c_int = -4; +pub const LIBSSH2_ERROR_KEX_FAILURE: c_int = -5; +pub const LIBSSH2_ERROR_ALLOC: c_int = -6; +pub const LIBSSH2_ERROR_SOCKET_SEND: c_int = -7; +pub const LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE: c_int = -8; +pub const LIBSSH2_ERROR_TIMEOUT: c_int = -9; +pub const LIBSSH2_ERROR_HOSTKEY_INIT: c_int = -10; +pub const LIBSSH2_ERROR_HOSTKEY_SIGN: c_int = -11; +pub const LIBSSH2_ERROR_DECRYPT: c_int = -12; +pub const LIBSSH2_ERROR_SOCKET_DISCONNECT: c_int = -13; +pub const LIBSSH2_ERROR_PROTO: c_int = -14; +pub const LIBSSH2_ERROR_PASSWORD_EXPIRED: c_int = -15; +pub const LIBSSH2_ERROR_FILE: c_int = -16; +pub const LIBSSH2_ERROR_METHOD_NONE: c_int = -17; +pub const LIBSSH2_ERROR_AUTHENTICATION_FAILED: c_int = -18; +pub const LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED: c_int = + LIBSSH2_ERROR_AUTHENTICATION_FAILED; +pub const LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED: c_int = -19; +pub const LIBSSH2_ERROR_CHANNEL_OUTOFORDER: c_int = -20; +pub const LIBSSH2_ERROR_CHANNEL_FAILURE: c_int = -21; +pub const LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED: c_int = -22; +pub const LIBSSH2_ERROR_CHANNEL_UNKNOWN: c_int = -23; +pub const LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED: c_int = -24; +pub const LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED: c_int = -25; +pub const LIBSSH2_ERROR_CHANNEL_CLOSED: c_int = -26; +pub const LIBSSH2_ERROR_CHANNEL_EOF_SENT: c_int = -27; +pub const LIBSSH2_ERROR_SCP_PROTOCOL: c_int = -28; +pub const LIBSSH2_ERROR_ZLIB: c_int = -29; +pub const LIBSSH2_ERROR_SOCKET_TIMEOUT: c_int = -30; +pub const LIBSSH2_ERROR_SFTP_PROTOCOL: c_int = -31; +pub const LIBSSH2_ERROR_REQUEST_DENIED: c_int = -32; +pub const LIBSSH2_ERROR_METHOD_NOT_SUPPORTED: c_int = -33; +pub const LIBSSH2_ERROR_INVAL: c_int = -34; +pub const LIBSSH2_ERROR_INVALID_POLL_TYPE: c_int = -35; +pub const LIBSSH2_ERROR_PUBLICKEY_PROTOCOL: c_int = -36; +pub const LIBSSH2_ERROR_EAGAIN: c_int = -37; +pub const LIBSSH2_ERROR_BUFFER_TOO_SMALL: c_int = -38; +pub const LIBSSH2_ERROR_BAD_USE: c_int = -39; +pub const LIBSSH2_ERROR_COMPRESS: c_int = -40; +pub const LIBSSH2_ERROR_OUT_OF_BOUNDARY: c_int = -41; +pub const LIBSSH2_ERROR_AGENT_PROTOCOL: c_int = -42; +pub const LIBSSH2_ERROR_SOCKET_RECV: c_int = -43; +pub const LIBSSH2_ERROR_ENCRYPT: c_int = -44; +pub const LIBSSH2_ERROR_BAD_SOCKET: c_int = -45; +pub const LIBSSH2_ERROR_KNOWN_HOSTS: c_int = -46; + +pub const LIBSSH2_FX_EOF: c_int = 1; +pub const LIBSSH2_FX_NO_SUCH_FILE: c_int = 2; +pub const LIBSSH2_FX_PERMISSION_DENIED: c_int = 3; +pub const LIBSSH2_FX_FAILURE: c_int = 4; +pub const LIBSSH2_FX_BAD_MESSAGE: c_int = 5; +pub const LIBSSH2_FX_NO_CONNECTION: c_int = 6; +pub const LIBSSH2_FX_CONNECTION_LOST: c_int = 7; +pub const LIBSSH2_FX_OP_UNSUPPORTED: c_int = 8; +pub const LIBSSH2_FX_INVALID_HANDLE: c_int = 9; +pub const LIBSSH2_FX_NO_SUCH_PATH: c_int = 10; +pub const LIBSSH2_FX_FILE_ALREADY_EXISTS: c_int = 11; +pub const LIBSSH2_FX_WRITE_PROTECT: c_int = 12; +pub const LIBSSH2_FX_NO_MEDIA: c_int = 13; +pub const LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM: c_int = 14; +pub const LIBSSH2_FX_QUOTA_EXCEEDED: c_int = 15; +pub const LIBSSH2_FX_UNKNOWN_PRINCIPAL: c_int = 16; +pub const LIBSSH2_FX_LOCK_CONFLICT: c_int = 17; +pub const LIBSSH2_FX_DIR_NOT_EMPTY: c_int = 18; +pub const LIBSSH2_FX_NOT_A_DIRECTORY: c_int = 19; +pub const LIBSSH2_FX_INVALID_FILENAME: c_int = 20; +pub const LIBSSH2_FX_LINK_LOOP: c_int = 21; + +pub const LIBSSH2_HOSTKEY_HASH_MD5: c_int = 1; +pub const LIBSSH2_HOSTKEY_HASH_SHA1: c_int = 2; + +pub const LIBSSH2_KNOWNHOST_FILE_OPENSSH: c_int = 1; + +pub const LIBSSH2_KNOWNHOST_CHECK_MATCH: c_int = 0; +pub const LIBSSH2_KNOWNHOST_CHECK_MISMATCH: c_int = 1; +pub const LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: c_int = 2; +pub const LIBSSH2_KNOWNHOST_CHECK_FAILURE: c_int = 3; + +pub const LIBSSH2_KNOWNHOST_TYPE_PLAIN: c_int = 1; +pub const LIBSSH2_KNOWNHOST_TYPE_SHA1: c_int = 2; +pub const LIBSSH2_KNOWNHOST_TYPE_CUSTOM: c_int = 3; +pub const LIBSSH2_KNOWNHOST_KEYENC_RAW: c_int = 1 << 16; +pub const LIBSSH2_KNOWNHOST_KEYENC_BASE64: c_int = 2 << 16; +pub const LIBSSH2_KNOWNHOST_KEY_RSA1: c_int = 1 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_SSHRSA: c_int = 2 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_SSHDSS: c_int = 3 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_256: c_int = 4 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_384: c_int = 5 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_ECDSA_521: c_int = 6 << 18; +pub const LIBSSH2_KNOWNHOST_KEY_UNKNOWN: c_int = 15 << 18; + +pub const LIBSSH2_FXF_READ: c_ulong = 0x00000001; +pub const LIBSSH2_FXF_WRITE: c_ulong = 0x00000002; +pub const LIBSSH2_FXF_APPEND: c_ulong = 0x00000004; +pub const LIBSSH2_FXF_CREAT: c_ulong = 0x00000008; +pub const LIBSSH2_FXF_TRUNC: c_ulong = 0x00000010; +pub const LIBSSH2_FXF_EXCL: c_ulong = 0x00000020; + +pub const LIBSSH2_SFTP_OPENFILE: c_int = 0; +pub const LIBSSH2_SFTP_OPENDIR: c_int = 1; + +pub const LIBSSH2_SFTP_ATTR_SIZE: c_ulong = 0x00000001; +pub const LIBSSH2_SFTP_ATTR_UIDGID: c_ulong = 0x00000002; +pub const LIBSSH2_SFTP_ATTR_PERMISSIONS: c_ulong = 0x00000004; +pub const LIBSSH2_SFTP_ATTR_ACMODTIME: c_ulong = 0x00000008; +pub const LIBSSH2_SFTP_ATTR_EXTENDED: c_ulong = 0x80000000; + +pub const LIBSSH2_SFTP_STAT: c_int = 0; +pub const LIBSSH2_SFTP_LSTAT: c_int = 1; +pub const LIBSSH2_SFTP_SETSTAT: c_int = 2; + +pub const LIBSSH2_SFTP_SYMLINK: c_int = 0; +pub const LIBSSH2_SFTP_READLINK: c_int = 1; +pub const LIBSSH2_SFTP_REALPATH: c_int = 2; + +pub const LIBSSH2_SFTP_RENAME_OVERWRITE: c_long = 0x1; +pub const LIBSSH2_SFTP_RENAME_ATOMIC: c_long = 0x2; +pub const LIBSSH2_SFTP_RENAME_NATIVE: c_long = 0x4; + +pub const LIBSSH2_INIT_NO_CRYPTO: c_int = 0x1; + +pub const LIBSSH2_SFTP_S_IFMT: c_ulong = 0o170000; +pub const LIBSSH2_SFTP_S_IFDIR: c_ulong = 0o040000; +pub const LIBSSH2_SFTP_S_IFREG: c_ulong = 0o100000; +pub const LIBSSH2_SFTP_S_IFLNK: c_ulong = 0o120000; + +pub enum LIBSSH2_SESSION {} +pub enum LIBSSH2_AGENT {} +pub enum LIBSSH2_CHANNEL {} +pub enum LIBSSH2_LISTENER {} +pub enum LIBSSH2_KNOWNHOSTS {} +pub enum LIBSSH2_SFTP {} +pub enum LIBSSH2_SFTP_HANDLE {} + +pub type libssh2_int64_t = i64; +pub type libssh2_uint64_t = u64; + +#[repr(C)] +pub struct libssh2_agent_publickey { + pub magic: c_uint, + pub node: *mut c_void, + pub blob: *mut c_uchar, + pub blob_len: size_t, + pub comment: *mut c_char, +} + +#[repr(C)] +pub struct libssh2_knownhost { + pub magic: c_uint, + pub node: *mut c_void, + pub name: *mut c_char, + pub key: *mut c_char, + pub typemask: c_int, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct LIBSSH2_SFTP_ATTRIBUTES { + pub flags: c_ulong, + pub filesize: libssh2_uint64_t, + pub uid: c_ulong, + pub gid: c_ulong, + pub permissions: c_ulong, + pub atime: c_ulong, + pub mtime: c_ulong, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct LIBSSH2_SFTP_STATVFS { + pub f_bsize: libssh2_uint64_t, + pub f_frsize: libssh2_uint64_t, + pub f_blocks: libssh2_uint64_t, + pub f_bfree: libssh2_uint64_t, + pub f_bavail: libssh2_uint64_t, + pub f_files: libssh2_uint64_t, + pub f_ffree: libssh2_uint64_t, + pub f_favail: libssh2_uint64_t, + pub f_fsid: libssh2_uint64_t, + pub f_flag: libssh2_uint64_t, + pub f_namemax: libssh2_uint64_t, +} + +pub type LIBSSH2_ALLOC_FUNC = extern fn(size_t, *mut *mut c_void) -> *mut c_void; +pub type LIBSSH2_FREE_FUNC = extern fn(*mut c_void, *mut *mut c_void); +pub type LIBSSH2_REALLOC_FUNC = extern fn(*mut c_void, size_t, *mut *mut c_void) + -> *mut c_void; +pub type LIBSSH2_PASSWD_CHANGEREQ_FUNC = extern fn(sess: *mut LIBSSH2_SESSION, + newpw: *mut *mut c_char, + newpw_len: *mut c_int, + abstrakt: *mut *mut c_void); + +#[cfg(unix)] +pub type libssh2_socket_t = c_int; +#[cfg(all(windows, target_arch = "x86"))] +pub type libssh2_socket_t = u32; +#[cfg(all(windows, target_arch = "x86_64"))] +pub type libssh2_socket_t = u64; + +extern { + // misc + pub fn libssh2_init(flag: c_int) -> c_int; + pub fn libssh2_exit(); + pub fn libssh2_free(sess: *mut LIBSSH2_SESSION, ptr: *mut c_void); + pub fn libssh2_hostkey_hash(session: *mut LIBSSH2_SESSION, + hash_type: c_int) -> *const c_char; + + // session + pub fn libssh2_session_init_ex(alloc: Option, + free: Option, + realloc: Option, + abstrakt: *mut c_void) + -> *mut LIBSSH2_SESSION; + pub fn libssh2_session_free(sess: *mut LIBSSH2_SESSION) -> c_int; + pub fn libssh2_session_banner_get(sess: *mut LIBSSH2_SESSION) -> *const c_char; + pub fn libssh2_session_banner_set(sess: *mut LIBSSH2_SESSION, + banner: *const c_char) -> c_int; + pub fn libssh2_session_disconnect_ex(sess: *mut LIBSSH2_SESSION, + reason: c_int, + description: *const c_char, + lang: *const c_char) -> c_int; + pub fn libssh2_session_flag(sess: *mut LIBSSH2_SESSION, + flag: c_int, value: c_int) -> c_int; + pub fn libssh2_session_get_blocking(session: *mut LIBSSH2_SESSION) -> c_int; + pub fn libssh2_session_get_timeout(sess: *mut LIBSSH2_SESSION) -> c_long; + pub fn libssh2_session_hostkey(sess: *mut LIBSSH2_SESSION, + len: *mut size_t, + kind: *mut c_int) -> *const c_char; + pub fn libssh2_session_method_pref(sess: *mut LIBSSH2_SESSION, + method_type: c_int, + prefs: *const c_char) -> c_int; + pub fn libssh2_session_methods(sess: *mut LIBSSH2_SESSION, + method_type: c_int) -> *const c_char; + pub fn libssh2_session_set_blocking(session: *mut LIBSSH2_SESSION, + blocking: c_int); + pub fn libssh2_session_set_timeout(session: *mut LIBSSH2_SESSION, + timeout: c_long); + pub fn libssh2_session_supported_algs(session: *mut LIBSSH2_SESSION, + method_type: c_int, + algs: *mut *mut *const c_char) -> c_int; + pub fn libssh2_session_last_error(sess: *mut LIBSSH2_SESSION, + msg: *mut *mut c_char, + len: *mut c_int, + want_buf: c_int) -> c_int; + pub fn libssh2_session_handshake(sess: *mut LIBSSH2_SESSION, + socket: libssh2_socket_t) -> c_int; + pub fn libssh2_keepalive_config(sess: *mut LIBSSH2_SESSION, + want_reply: c_int, + interval: c_uint); + pub fn libssh2_keepalive_send(sess: *mut LIBSSH2_SESSION, + seconds_to_next: *mut c_int) -> c_int; + + // agent + pub fn libssh2_agent_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_AGENT; + pub fn libssh2_agent_free(agent: *mut LIBSSH2_AGENT); + pub fn libssh2_agent_connect(agent: *mut LIBSSH2_AGENT) -> c_int; + pub fn libssh2_agent_disconnect(agent: *mut LIBSSH2_AGENT) -> c_int; + pub fn libssh2_agent_list_identities(agent: *mut LIBSSH2_AGENT) -> c_int; + pub fn libssh2_agent_get_identity(agent: *mut LIBSSH2_AGENT, + store: *mut *mut libssh2_agent_publickey, + prev: *mut libssh2_agent_publickey) + -> c_int; + pub fn libssh2_agent_userauth(agent: *mut LIBSSH2_AGENT, + username: *const c_char, + identity: *mut libssh2_agent_publickey) -> c_int; + + // channels + pub fn libssh2_channel_free(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_close(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_wait_closed(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_wait_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_process_startup(chan: *mut LIBSSH2_CHANNEL, + req: *const c_char, + req_len: c_uint, + msg: *const c_char, + msg_len: c_uint) -> c_int; + pub fn libssh2_channel_flush_ex(chan: *mut LIBSSH2_CHANNEL, + streamid: c_int) -> c_int; + pub fn libssh2_channel_write_ex(chan: *mut LIBSSH2_CHANNEL, + stream_id: c_int, + buf: *const c_char, + buflen: size_t) -> ssize_t; + pub fn libssh2_channel_get_exit_signal(chan: *mut LIBSSH2_CHANNEL, + exitsignal: *mut *mut c_char, + exitsignal_len: *mut size_t, + errmsg: *mut *mut c_char, + errmsg_len: *mut size_t, + langtag: *mut *mut c_char, + langtag_len: *mut size_t) -> c_int; + pub fn libssh2_channel_get_exit_status(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_open_ex(sess: *mut LIBSSH2_SESSION, + channel_type: *const c_char, + channel_type_len: c_uint, + window_size: c_uint, + packet_size: c_uint, + message: *const c_char, + message_len: c_uint) -> *mut LIBSSH2_CHANNEL; + pub fn libssh2_channel_read_ex(chan: *mut LIBSSH2_CHANNEL, + stream_id: c_int, + buf: *mut c_char, + buflen: size_t) -> ssize_t; + pub fn libssh2_channel_setenv_ex(chan: *mut LIBSSH2_CHANNEL, + var: *const c_char, + varlen: c_uint, + val: *const c_char, + vallen: c_uint) -> c_int; + pub fn libssh2_channel_send_eof(chan: *mut LIBSSH2_CHANNEL) -> c_int; + pub fn libssh2_channel_request_pty_ex(chan: *mut LIBSSH2_CHANNEL, + term: *const c_char, + termlen: c_uint, + modes: *const c_char, + modeslen: c_uint, + width: c_int, + height: c_int, + width_px: c_int, + height_px: c_int) -> c_int; + pub fn libssh2_channel_request_pty_size_ex(chan: *mut LIBSSH2_CHANNEL, + width: c_int, + height: c_int, + width_px: c_int, + height_px: c_int) -> c_int; + pub fn libssh2_channel_window_read_ex(chan: *mut LIBSSH2_CHANNEL, + read_avail: *mut c_ulong, + window_size_initial: *mut c_ulong) + -> c_ulong; + pub fn libssh2_channel_window_write_ex(chan: *mut LIBSSH2_CHANNEL, + window_size_initial: *mut c_ulong) + -> c_ulong; + pub fn libssh2_channel_receive_window_adjust2(chan: *mut LIBSSH2_CHANNEL, + adjust: c_ulong, + force: c_uchar, + window: *mut c_uint) -> c_int; + pub fn libssh2_channel_direct_tcpip_ex(ses: *mut LIBSSH2_SESSION, + host: *const c_char, + port: c_int, + shost: *const c_char, + sport: c_int) + -> *mut LIBSSH2_CHANNEL; + pub fn libssh2_channel_forward_accept(listener: *mut LIBSSH2_LISTENER) + -> *mut LIBSSH2_CHANNEL; + pub fn libssh2_channel_forward_cancel(listener: *mut LIBSSH2_LISTENER) + -> c_int; + pub fn libssh2_channel_forward_listen_ex(sess: *mut LIBSSH2_SESSION, + host: *const c_char, + port: c_int, + bound_port: *mut c_int, + queue_maxsize: c_int) + -> *mut LIBSSH2_LISTENER; + + // userauth + pub fn libssh2_userauth_authenticated(sess: *mut LIBSSH2_SESSION) -> c_int; + pub fn libssh2_userauth_list(sess: *mut LIBSSH2_SESSION, + username: *const c_char, + username_len: c_uint) -> *mut c_char; + pub fn libssh2_userauth_hostbased_fromfile_ex(sess: *mut LIBSSH2_SESSION, + username: *const c_char, + username_len: c_uint, + publickey: *const c_char, + privatekey: *const c_char, + passphrase: *const c_char, + hostname: *const c_char, + hostname_len: c_uint, + local_username: *const c_char, + local_len: c_uint) -> c_int; + pub fn libssh2_userauth_publickey_fromfile_ex(sess: *mut LIBSSH2_SESSION, + username: *const c_char, + username_len: c_uint, + publickey: *const c_char, + privatekey: *const c_char, + passphrase: *const c_char) + -> c_int; + pub fn libssh2_userauth_publickey_frommemory(sess: *mut LIBSSH2_SESSION, + username: *const c_char, + username_len: size_t, + publickeydata: *const c_char, + publickeydata_len: size_t, + privatekeydata: *const c_char, + privatekeydata_len: size_t, + passphrase: *const c_char) + -> c_int; + pub fn libssh2_userauth_password_ex(session: *mut LIBSSH2_SESSION, + username: *const c_char, + username_len: c_uint, + password: *const c_char, + password_len: c_uint, + password_change_cb: + Option) + -> c_int; + + // knownhost + pub fn libssh2_knownhost_free(hosts: *mut LIBSSH2_KNOWNHOSTS); + pub fn libssh2_knownhost_addc(hosts: *mut LIBSSH2_KNOWNHOSTS, + host: *const c_char, + salt: *const c_char, + key: *const c_char, + keylen: size_t, + comment: *const c_char, + commentlen: size_t, + typemask: c_int, + store: *mut *mut libssh2_knownhost) -> c_int; + pub fn libssh2_knownhost_check(hosts: *mut LIBSSH2_KNOWNHOSTS, + host: *const c_char, + key: *const c_char, + keylen: size_t, + typemask: c_int, + knownhost: *mut *mut libssh2_knownhost) + -> c_int; + pub fn libssh2_knownhost_checkp(hosts: *mut LIBSSH2_KNOWNHOSTS, + host: *const c_char, + port: c_int, + key: *const c_char, + keylen: size_t, + typemask: c_int, + knownhost: *mut *mut libssh2_knownhost) + -> c_int; + pub fn libssh2_knownhost_del(hosts: *mut LIBSSH2_KNOWNHOSTS, + entry: *mut libssh2_knownhost) -> c_int; + pub fn libssh2_knownhost_get(hosts: *mut LIBSSH2_KNOWNHOSTS, + store: *mut *mut libssh2_knownhost, + prev: *mut libssh2_knownhost) -> c_int; + pub fn libssh2_knownhost_readfile(hosts: *mut LIBSSH2_KNOWNHOSTS, + filename: *const c_char, + kind: c_int) -> c_int; + pub fn libssh2_knownhost_readline(hosts: *mut LIBSSH2_KNOWNHOSTS, + line: *const c_char, + len: size_t, + kind: c_int) -> c_int; + pub fn libssh2_knownhost_writefile(hosts: *mut LIBSSH2_KNOWNHOSTS, + filename: *const c_char, + kind: c_int) -> c_int; + pub fn libssh2_knownhost_writeline(hosts: *mut LIBSSH2_KNOWNHOSTS, + known: *mut libssh2_knownhost, + buffer: *mut c_char, + buflen: size_t, + outlen: *mut size_t, + kind: c_int) -> c_int; + pub fn libssh2_knownhost_init(sess: *mut LIBSSH2_SESSION) + -> *mut LIBSSH2_KNOWNHOSTS; + + // scp + pub fn libssh2_scp_recv(sess: *mut LIBSSH2_SESSION, + path: *const c_char, + sb: *mut libc::stat) -> *mut LIBSSH2_CHANNEL; + pub fn libssh2_scp_send64(sess: *mut LIBSSH2_SESSION, + path: *const c_char, + mode: c_int, + size: libssh2_int64_t, + mtime: libc::time_t, + atime: libc::time_t) -> *mut LIBSSH2_CHANNEL; + + // sftp + pub fn libssh2_sftp_init(sess: *mut LIBSSH2_SESSION) -> *mut LIBSSH2_SFTP; + pub fn libssh2_sftp_shutdown(sftp: *mut LIBSSH2_SFTP) -> c_int; + pub fn libssh2_sftp_last_error(sftp: *mut LIBSSH2_SFTP) -> c_ulong; + pub fn libssh2_sftp_open_ex(sftp: *mut LIBSSH2_SFTP, + filename: *const c_char, + filename_len: c_uint, + flags: c_ulong, + mode: c_long, + open_type: c_int) -> *mut LIBSSH2_SFTP_HANDLE; + pub fn libssh2_sftp_close_handle(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_int; + pub fn libssh2_sftp_mkdir_ex(sftp: *mut LIBSSH2_SFTP, + path: *const c_char, + path_len: c_uint, + mode: c_long) -> c_int; + pub fn libssh2_sftp_fsync(handle: *mut LIBSSH2_SFTP_HANDLE) -> c_int; + pub fn libssh2_sftp_fstat_ex(handle: *mut LIBSSH2_SFTP_HANDLE, + attrs: *mut LIBSSH2_SFTP_ATTRIBUTES, + setstat: c_int) -> c_int; + pub fn libssh2_sftp_fstatvfs(handle: *mut LIBSSH2_SFTP_HANDLE, + attrs: *mut LIBSSH2_SFTP_STATVFS) -> c_int; + pub fn libssh2_sftp_stat_ex(sftp: *mut LIBSSH2_SFTP, + path: *const c_char, + path_len: c_uint, + stat_type: c_int, + attrs: *mut LIBSSH2_SFTP_ATTRIBUTES) -> c_int; + pub fn libssh2_sftp_read(handle: *mut LIBSSH2_SFTP_HANDLE, + buf: *mut c_char, + len: size_t) -> ssize_t; + pub fn libssh2_sftp_symlink_ex(sftp: *mut LIBSSH2_SFTP, + path: *const c_char, + path_len: c_uint, + target: *mut c_char, + target_len: c_uint, + link_type: c_int) -> c_int; + pub fn libssh2_sftp_rename_ex(sftp: *mut LIBSSH2_SFTP, + src: *const c_char, + src_len: c_uint, + dst: *const c_char, + dst_len: c_uint, + flags: c_long) -> c_int; + pub fn libssh2_sftp_rmdir_ex(sftp: *mut LIBSSH2_SFTP, + path: *const c_char, + path_len: c_uint) -> c_int; + pub fn libssh2_sftp_write(handle: *mut LIBSSH2_SFTP_HANDLE, + buffer: *const c_char, + len: size_t) -> ssize_t; + pub fn libssh2_sftp_tell64(handle: *mut LIBSSH2_SFTP_HANDLE) + -> libssh2_uint64_t; + pub fn libssh2_sftp_seek64(handle: *mut LIBSSH2_SFTP_HANDLE, + off: libssh2_uint64_t); + pub fn libssh2_sftp_readdir_ex(handle: *mut LIBSSH2_SFTP_HANDLE, + buffer: *mut c_char, + buffer_len: size_t, + longentry: *mut c_char, + longentry_len: size_t, + attrs: *mut LIBSSH2_SFTP_ATTRIBUTES) -> c_int; + pub fn libssh2_sftp_unlink_ex(sftp: *mut LIBSSH2_SFTP, + filename: *const c_char, + filename_len: c_uint) -> c_int; +} + +#[test] +fn smoke() { + unsafe { libssh2_init(0) }; +} + +#[doc(hidden)] +pub fn issue_14344_workaround() {} + +pub fn init() { + use std::sync::{Once, ONCE_INIT}; + + static INIT: Once = ONCE_INIT; + INIT.call_once(|| unsafe { + platform_init(); + assert_eq!(libc::atexit(shutdown), 0); + }); + extern fn shutdown() { unsafe { libssh2_exit(); } } + + #[cfg(unix)] + unsafe fn platform_init() { + // On Unix we want to funnel through openssl_sys to initialize OpenSSL, + // so be sure to tell libssh2 to not do its own thing as we've already + // taken care of it. + openssl_sys::init(); + assert_eq!(libssh2_init(LIBSSH2_INIT_NO_CRYPTO), 0); + } + + #[cfg(windows)] + unsafe fn platform_init() { + // On Windows we want to be sure to tell libssh2 to initialize + // everything, as we're not managing crypto elsewhere ourselves. Also to + // fix alexcrichton/git2-rs#202 + assert_eq!(libssh2_init(0), 0); + } +} diff --git a/libz-sys/.cargo-checksum.json b/libz-sys/.cargo-checksum.json new file mode 100644 index 000000000..15bf44bd4 --- /dev/null +++ b/libz-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"} \ No newline at end of file diff --git a/libz-sys/Cargo.toml b/libz-sys/Cargo.toml new file mode 100644 index 000000000..0c2477cc5 --- /dev/null +++ b/libz-sys/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "libz-sys" +version = "1.0.25" +authors = ["Alex Crichton "] +build = "build.rs" +links = "z" +description = "Bindings to the system libz library (also known as zlib).\n" +documentation = "https://docs.rs/libz-sys" +categories = ["external-ffi-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/libz-sys" +[dependencies.libc] +version = "0.2.43" +[build-dependencies.cc] +version = "1.0.18" + +[build-dependencies.pkg-config] +version = "0.3.9" + +[features] +asm = [] +static = [] +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" diff --git a/libz-sys/LICENSE-APACHE b/libz-sys/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/libz-sys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libz-sys/LICENSE-MIT b/libz-sys/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/libz-sys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libz-sys/README.md b/libz-sys/README.md new file mode 100644 index 000000000..d350ea0c3 --- /dev/null +++ b/libz-sys/README.md @@ -0,0 +1,25 @@ +# libz-sys + +A common library for linking `libz` to rust programs (also known as zlib). + +[![Build Status](https://travis-ci.org/alexcrichton/libz-sys.svg?branch=master)](https://travis-ci.org/alexcrichton/libz-sys) +[![Build status](https://ci.appveyor.com/api/projects/status/et3ae5mgpbokh9g9?svg=true)](https://ci.appveyor.com/project/alexcrichton/libz-sys) + +[Documentation](https://docs.rs/libz-sys) + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `libz-sys` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/libz-sys/appveyor.yml b/libz-sys/appveyor.yml new file mode 100644 index 000000000..163823306 --- /dev/null +++ b/libz-sys/appveyor.yml @@ -0,0 +1,30 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS_BITS: 32 + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc + VCPKG_DEFAULT_TRIPLET: x64-windows-static + RUSTFLAGS: -Ctarget-feature=+crt-static +install: + - git submodule update --init --recursive + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin + - rustc -V + - cargo -V + - if defined VCPKG_DEFAULT_TRIPLET git clone https://github.com/Microsoft/vcpkg c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET c:\projects\vcpkg\bootstrap-vcpkg.bat + - if defined VCPKG_DEFAULT_TRIPLET set VCPKG_ROOT=c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET echo yes > %VCPKG_ROOT%\Downloads\AlwaysAllowDownloads + - if defined VCPKG_DEFAULT_TRIPLET %VCPKG_ROOT%\vcpkg.exe install zlib + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo run --manifest-path systest/Cargo.toml --target %TARGET% diff --git a/libz-sys/build.rs b/libz-sys/build.rs new file mode 100644 index 000000000..75c043adb --- /dev/null +++ b/libz-sys/build.rs @@ -0,0 +1,194 @@ +extern crate pkg_config; +#[cfg(target_env = "msvc")] +extern crate vcpkg; +extern crate cc; + +use std::env; +use std::fs; +use std::path::PathBuf; +use std::process::Command; + +fn main() { + println!("cargo:rerun-if-env-changed=LIBZ_SYS_STATIC"); + println!("cargo:rerun-if-changed=build.rs"); + let host = env::var("HOST").unwrap(); + let target = env::var("TARGET").unwrap(); + let wants_asm = cfg!(feature = "asm"); + + let host_and_target_contain = |s| host.contains(s) && target.contains(s); + + // Don't run pkg-config if we're linking statically (we'll build below) and + // also don't run pkg-config on macOS/FreeBSD/DragonFly. That'll end up printing + // `-L /usr/lib` which wreaks havoc with linking to an OpenSSL in /usr/local/lib + // (Homebrew, Ports, etc.) + let want_static = + cfg!(feature = "static") || env::var("LIBZ_SYS_STATIC").unwrap_or(String::new()) == "1"; + if !wants_asm && + !want_static && + !target.contains("msvc") && // pkg-config just never works here + !(host_and_target_contain("apple") || + host_and_target_contain("freebsd") || + host_and_target_contain("dragonfly")) && + pkg_config::Config::new().cargo_metadata(true).probe("zlib").is_ok() { + return + } + + if target.contains("msvc") { + if !wants_asm && try_vcpkg() { + return; + } + } + + // All android compilers should come with libz by default, so let's just use + // the one already there. + if !wants_asm && target.contains("android") { + println!("cargo:rustc-link-lib=z"); + return + } + + let mut cfg = cc::Build::new(); + + // Whitelist a bunch of situations where we build unconditionally. + // + // MSVC basically never has it preinstalled, MinGW picks up a bunch of weird + // paths we don't like, `want_static` may force us, cross compiling almost + // never has a prebuilt version, and musl is almost always static. + if wants_asm || + target.contains("msvc") || + target.contains("pc-windows-gnu") || + want_static || + target != host || + target.contains("musl") + { + return build_zlib(&mut cfg, &target); + } + + // If we've gotten this far we're probably a pretty standard platform. + // Almost all platforms here ship libz by default, but some don't have + // pkg-config files that we would find above. + // + // In any case test if zlib is actually installed and if so we link to it, + // otherwise continue below to build things. + if zlib_installed(&mut cfg) { + println!("cargo:rustc-link-lib=z"); + return + } + + build_zlib(&mut cfg, &target) +} + +fn build_zlib(cfg: &mut cc::Build, target: &str) { + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let build = dst.join("build"); + let asm = cfg!(feature = "asm"); + + cfg.warnings(false) + .out_dir(&build) + .include("src/zlib"); + + cfg.file("src/zlib/adler32.c") + .file("src/zlib/compress.c") + .file("src/zlib/crc32.c") + .file("src/zlib/deflate.c") + .file("src/zlib/gzclose.c") + .file("src/zlib/gzlib.c") + .file("src/zlib/gzread.c") + .file("src/zlib/gzwrite.c") + .file("src/zlib/infback.c") + .file("src/zlib/inffast.c") + .file("src/zlib/inflate.c") + .file("src/zlib/inftrees.c") + .file("src/zlib/trees.c") + .file("src/zlib/uncompr.c") + .file("src/zlib/zutil.c"); + if !target.contains("windows") { + cfg.define("STDC", None); + cfg.define("_LARGEFILE64_SOURCE", None); + cfg.define("_POSIX_SOURCE", None); + cfg.flag("-fvisibility=hidden"); + } + if target.contains("ios") { + cfg.define("_C99_SOURCE", None); + } + if target.contains("solaris") { + cfg.define("_XOPEN_SOURCE", "700"); + } + + if asm { + if target.contains("windows-msvc") { + if target.starts_with("x86_64") { + cfg.file("src/zlib/contrib/masmx64/inffasx64.asm") + .file("src/zlib/contrib/masmx64/gvmat64.asm") + .define("ASMV", None) + .define("ASMINF", None); + } else if target.starts_with("i686") { + cfg.file("src/zlib/contrib/masmx86/inffas32.asm") + .file("src/zlib/contrib/masmx86/match686.asm") + .define("ASMV", None) + .define("ASMINF", None); + } + } else { + if target.starts_with("x86_64") { + cfg.file("src/zlib/contrib/amd64/amd64-match.S") + .define("ASMV", None); + } else if target.starts_with("i686") { + cfg.file("src/zlib/contrib/inflate86/inffast.S") + .define("ASMINF", None); + } + } + } + + cfg.compile("z"); + + fs::create_dir_all(dst.join("lib/pkgconfig")).unwrap(); + fs::create_dir_all(dst.join("include")).unwrap(); + fs::copy("src/zlib/zlib.h", dst.join("include/zlib.h")).unwrap(); + fs::copy("src/zlib/zconf.h", dst.join("include/zconf.h")).unwrap(); + + fs::write( + dst.join("lib/pkgconfig/zlib.pc"), + fs::read_to_string("src/zlib/zlib.pc.in") + .unwrap() + .replace("@prefix@", dst.to_str().unwrap()), + ).unwrap(); + + println!("cargo:root={}", dst.to_str().unwrap()); + println!("cargo:include={}/include", dst.to_str().unwrap()); +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> bool { + false +} + +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> bool { + // see if there is a vcpkg tree with zlib installed + match vcpkg::Config::new() + .emit_includes(true) + .lib_names("zlib", "zlib1") + .probe("zlib") { + Ok(_) => { true }, + Err(e) => { + println!("note, vcpkg did not find zlib: {}", e); + false + }, + } +} + +fn zlib_installed(cfg: &mut cc::Build) -> bool { + let compiler = cfg.get_compiler(); + let mut cmd = Command::new(compiler.path()); + cmd.arg("src/smoke.c") + .arg("-o").arg("/dev/null") + .arg("-lz"); + + println!("running {:?}", cmd); + if let Ok(status) = cmd.status() { + if status.success() { + return true + } + } + + false +} diff --git a/libz-sys/ci/Dockerfile b/libz-sys/ci/Dockerfile new file mode 100644 index 000000000..ae1599c05 --- /dev/null +++ b/libz-sys/ci/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:18.04 + +RUN apt-get update -y && apt-get install -y --no-install-recommends \ + gcc \ + libc6-dev \ + ca-certificates + diff --git a/libz-sys/ci/run-docker.sh b/libz-sys/ci/run-docker.sh new file mode 100755 index 000000000..cc7ce291f --- /dev/null +++ b/libz-sys/ci/run-docker.sh @@ -0,0 +1,18 @@ +set -ex + +mkdir -p target + +docker build --rm -t libz-sys-ci ci +docker run \ + --rm \ + --init \ + --user $(id -u):$(id -g) \ + --volume `rustc --print sysroot`:/usr/local:ro \ + --volume `pwd`:/src:ro \ + --volume `pwd`/target:/src/target \ + --workdir /src \ + --env CARGO_HOME=/cargo \ + --volume $HOME/.cargo:/cargo \ + -it \ + libz-sys-ci \ + cargo run --manifest-path systest/Cargo.toml -vv diff --git a/libz-sys/src/lib.rs b/libz-sys/src/lib.rs new file mode 100644 index 000000000..93442218f --- /dev/null +++ b/libz-sys/src/lib.rs @@ -0,0 +1,231 @@ +#![doc(html_root_url = "https://docs.rs/libz-sys/1.0")] +#![allow(non_camel_case_types)] + +extern crate libc; + +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void}; + +pub type alloc_func = unsafe extern fn (voidpf, uInt, uInt) -> voidpf; +pub type Bytef = u8; +pub type free_func = unsafe extern fn (voidpf, voidpf); +pub type gzFile = *mut gzFile_s; +pub type in_func = unsafe extern fn (*mut c_void, *mut *const c_uchar) -> c_uint; +pub type out_func = unsafe extern fn (*mut c_void, *mut c_uchar, c_uint) -> c_int; +pub type uInt = c_uint; +pub type uLong = c_ulong; +pub type uLongf = c_ulong; +pub type voidp = *mut c_void; +pub type voidpc = *const c_void; +pub type voidpf = *mut c_void; + +pub enum gzFile_s {} +pub enum internal_state {} + +#[cfg(unix)] pub type z_off_t = libc::off_t; +#[cfg(not(unix))] pub type z_off_t = c_long; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct gz_header { + pub text: c_int, + pub time: uLong, + pub xflags: c_int, + pub os: c_int, + pub extra: *mut Bytef, + pub extra_len: uInt, + pub extra_max: uInt, + pub name: *mut Bytef, + pub name_max: uInt, + pub comment: *mut Bytef, + pub comm_max: uInt, + pub hcrc: c_int, + pub done: c_int, +} +pub type gz_headerp = *mut gz_header; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct z_stream { + pub next_in: *mut Bytef, + pub avail_in: uInt, + pub total_in: uLong, + pub next_out: *mut Bytef, + pub avail_out: uInt, + pub total_out: uLong, + pub msg: *mut c_char, + pub state: *mut internal_state, + pub zalloc: alloc_func, + pub zfree: free_func, + pub opaque: voidpf, + pub data_type: c_int, + pub adler: uLong, + pub reserved: uLong, +} +pub type z_streamp = *mut z_stream; + +macro_rules! fns { + ($($arg:tt)*) => { + item! { + extern { $($arg)* } + } + } +} + +macro_rules! item { + ($i:item) => ($i) +} + +fns! { + pub fn adler32(adler: uLong, buf: *const Bytef, len: uInt) -> uLong; + pub fn adler32_combine(adler1: uLong, adler2: uLong, len2: z_off_t) -> uLong; + pub fn compress(dest: *mut Bytef, destLen: *mut uLongf, + source: *const Bytef, sourceLen: uLong) -> c_int; + pub fn compress2(dest: *mut Bytef, destLen: *mut uLongf, + source: *const Bytef, sourceLen: uLong, + level: c_int) -> c_int; + pub fn compressBound(sourceLen: uLong) -> uLong; + pub fn crc32(crc: uLong, buf: *const Bytef, len: uInt) -> uLong; + pub fn crc32_combine(crc1: uLong, crc2: uLong, len2: z_off_t) -> uLong; + pub fn deflate(strm: z_streamp, flush: c_int) -> c_int; + pub fn deflateBound(strm: z_streamp, sourceLen: uLong) -> uLong; + pub fn deflateCopy(dest: z_streamp, source: z_streamp) -> c_int; + pub fn deflateEnd(strm: z_streamp) -> c_int; + pub fn deflateInit_(strm: z_streamp, level: c_int, + version: *const c_char, + stream_size: c_int) -> c_int; + pub fn deflateInit2_(strm: z_streamp, + level: c_int, + method: c_int, + windowBits: c_int, + memLevel: c_int, + strategy: c_int, + version: *const c_char, + stream_size: c_int) -> c_int; + pub fn deflateParams(strm: z_streamp, + level: c_int, + strategy: c_int) -> c_int; + pub fn deflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int; + pub fn deflateReset(strm: z_streamp) -> c_int; + pub fn deflateSetDictionary(strm: z_streamp, + dictionary: *const Bytef, + dictLength: uInt) -> c_int; + pub fn deflateSetHeader(strm: z_streamp, head: gz_headerp) -> c_int; + pub fn deflateTune(strm: z_streamp, + good_length: c_int, + max_lazy: c_int, + nice_length: c_int, + max_chain: c_int) -> c_int; + pub fn gzdirect(file: gzFile) -> c_int; + pub fn gzdopen(fd: c_int, mode: *const c_char) -> gzFile; + pub fn gzclearerr(file: gzFile); + pub fn gzclose(file: gzFile) -> c_int; + pub fn gzeof(file: gzFile) -> c_int; + pub fn gzerror(file: gzFile, errnum: *mut c_int) -> *const c_char; + pub fn gzflush(file: gzFile, flush: c_int) -> c_int; + pub fn gzgetc(file: gzFile) -> c_int; + pub fn gzgets(file: gzFile, buf: *mut c_char, len: c_int) -> *mut c_char; + pub fn gzopen(path: *const c_char, mode: *const c_char) -> gzFile; + pub fn gzputc(file: gzFile, c: c_int) -> c_int; + pub fn gzputs(file: gzFile, s: *const c_char) -> c_int; + pub fn gzread(file: gzFile, buf: voidp, len: c_uint) -> c_int; + pub fn gzrewind(file: gzFile) -> c_int; + pub fn gzseek(file: gzFile, offset: z_off_t, whence: c_int) -> z_off_t; + pub fn gzsetparams(file: gzFile, level: c_int, strategy: c_int) -> c_int; + pub fn gztell(file: gzFile) -> z_off_t; + pub fn gzungetc(c: c_int, file: gzFile) -> c_int; + pub fn gzwrite(file: gzFile, buf: voidpc, len: c_uint) -> c_int; + pub fn inflate(strm: z_streamp, flush: c_int) -> c_int; + pub fn inflateBack(strm: z_streamp, + _in: in_func, + in_desc: *mut c_void, + out: out_func, + out_desc: *mut c_void) -> c_int; + pub fn inflateBackEnd(strm: z_streamp) -> c_int; + pub fn inflateBackInit_(strm: z_streamp, + windowBits: c_int, + window: *mut c_uchar, + version: *const c_char, + stream_size: c_int) -> c_int; + pub fn inflateCopy(dest: z_streamp, source: z_streamp) -> c_int; + pub fn inflateEnd(strm: z_streamp) -> c_int; + pub fn inflateGetHeader(strm: z_streamp, head: gz_headerp) -> c_int; + pub fn inflateInit_(strm: z_streamp, + version: *const c_char, + stream_size: c_int) -> c_int; + pub fn inflateInit2_(strm: z_streamp, + windowBits: c_int, + version: *const c_char, + stream_size: c_int) -> c_int; + pub fn inflateMark(strm: z_streamp) -> c_long; + pub fn inflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int; + pub fn inflateReset(strm: z_streamp) -> c_int; + pub fn inflateReset2(strm: z_streamp, windowBits: c_int) -> c_int; + pub fn inflateSetDictionary(strm: z_streamp, + dictionary: *const Bytef, + dictLength: uInt) -> c_int; + pub fn inflateSync(strm: z_streamp) -> c_int; + pub fn uncompress(dest: *mut Bytef, + destLen: *mut uLongf, + source: *const Bytef, + sourceLen: uLong) -> c_int; + pub fn zlibCompileFlags() -> uLong; + pub fn zlibVersion() -> *const c_char; + + +// The above set of functions currently target 1.2.3.4 (what's present on Ubuntu +// 12.04, but there's some other APIs that were added later. Should figure out +// how to expose them... +// +// Added in 1.2.5.1 +// +// pub fn deflatePending(strm: z_streamp, +// pending: *mut c_uint, +// bits: *mut c_int) -> c_int; +// +// Addedin 1.2.7.1 +// pub fn inflateGetDictionary(strm: z_streamp, +// dictionary: *mut Bytef, +// dictLength: *mut uInt) -> c_int; +// +// Added in 1.2.3.5 +// pub fn gzbuffer(file: gzFile, size: c_uint) -> c_int; +// pub fn gzclose_r(file: gzFile) -> c_int; +// pub fn gzclose_w(file: gzFile) -> c_int; +// pub fn gzoffset(file: gzFile) -> z_off_t; +} + +pub const Z_NO_FLUSH: c_int = 0; +pub const Z_PARTIAL_FLUSH: c_int = 1; +pub const Z_SYNC_FLUSH: c_int = 2; +pub const Z_FULL_FLUSH: c_int = 3; +pub const Z_FINISH: c_int = 4; +pub const Z_BLOCK: c_int = 5; +pub const Z_TREES: c_int = 6; + +pub const Z_OK: c_int = 0; +pub const Z_STREAM_END: c_int = 1; +pub const Z_NEED_DICT: c_int = 2; +pub const Z_ERRNO: c_int = -1; +pub const Z_STREAM_ERROR: c_int = -2; +pub const Z_DATA_ERROR: c_int = -3; +pub const Z_MEM_ERROR: c_int = -4; +pub const Z_BUF_ERROR: c_int = -5; +pub const Z_VERSION_ERROR: c_int = -6; + +pub const Z_NO_COMPRESSION: c_int = 0; +pub const Z_BEST_SPEED: c_int = 1; +pub const Z_BEST_COMPRESSION: c_int = 9; +pub const Z_DEFAULT_COMPRESSION: c_int = -1; + +pub const Z_FILTERED: c_int = 1; +pub const Z_HUFFMAN_ONLY: c_int = 2; +pub const Z_RLE: c_int = 3; +pub const Z_FIXED: c_int = 4; +pub const Z_DEFAULT_STRATEGY: c_int = 0; + +pub const Z_BINARY: c_int = 0; +pub const Z_TEXT: c_int = 1; +pub const Z_ASCII: c_int = Z_TEXT; +pub const Z_UNKNOWN: c_int = 2; + +pub const Z_DEFLATED: c_int = 8; diff --git a/libz-sys/src/smoke.c b/libz-sys/src/smoke.c new file mode 100644 index 000000000..f659aa77c --- /dev/null +++ b/libz-sys/src/smoke.c @@ -0,0 +1,5 @@ +#include + +int main() { + return (int) adler32; +} diff --git a/log/.cargo-checksum.json b/log/.cargo-checksum.json new file mode 100644 index 000000000..0b6f11bf1 --- /dev/null +++ b/log/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"} \ No newline at end of file diff --git a/log/CHANGELOG.md b/log/CHANGELOG.md new file mode 100644 index 000000000..edc161783 --- /dev/null +++ b/log/CHANGELOG.md @@ -0,0 +1,123 @@ +# Change Log + +## [Unreleased] + +## [0.4.6] - 2018-10-27 + +### Improved + +* Support 2018-style macro import for the `log_enabled!` macro. + +## [0.4.5] - 2018-09-03 + +### Improved + +* Make `log`'s internal helper macros less likely to conflict with user-defined + macros. + +## [0.4.4] - 2018-08-17 + +### Improved + +* Support 2018-style imports of the log macros. + +## [0.4.3] - 2018-06-29 + +### Improved + +* More code generation improvements. + +## [0.4.2] - 2018-06-05 + +### Improved + +* Log invocations now generate less code. + +### Fixed + +* Example Logger implementations now properly set the max log level. + +## [0.4.1] - 2017-12-30 + +### Fixed + +* Some doc links were fixed. + +## [0.4.0] - 2017-12-24 + +The changes in this release include cleanup of some obscure functionality and a more robust public +API designed to support bridges to other logging systems, and provide more flexibility to new +features in the future. + +### Compatibility + +Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force +the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along +with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow +crates using either version to coexist without losing messages from one side or the other. + +There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging +implementation using 0.3.x will not have a file name or module path. Applications affected by this +can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The +other direction does not lose any information, fortunately! + +**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking +change. Applications may need to update their logging implementation (e.g. env-logger) to a newer +version using log 0.4.x to avoid losing module and file information. + +### New + +* The crate is now `no_std` by default. +* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is + enabled. +* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API. +* The `logger` free function returns a reference to the logger implementation. This, along with the + ability to construct `Record`s, makes it possible to bridge from another logging framework to + this one without digging into the private internals of the crate. The standard `error!` `warn!`, + etc, macros now exclusively use the public API of the crate rather than "secret" internal APIs. +* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all + "in flight" log events have been persisted. This can be used, for example, just before an + application exits to ensure that asynchronous log sinks finish their work. + +### Removed + +* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly + complicated the implementation and imposed a performance cost on each logging operation. +* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the + [log-panics](https://crates.io/crates/log-panics) instead. + +### Changed + +* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now + `LevelFilter`, and `LogRecord` is now `Record`. +* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function. +* The `set_logger` free functions have been restructured. The logger is now directly passed to the + functions rather than a closure which returns the logger. `set_logger` now takes a `&'static + Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger` + is a convenience function which takes a `Box` but otherwise acts like `set_logger`. It + requires the `std` feature. +* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support + integration with other logging frameworks that don't provide a `'static` lifetime for the + equivalent values. +* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration + with other logging frameworks that don't provide those values. + +### In the Future + +* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of + information in a log event in addition to the normal string message. This should be able to be + added in a backwards compatible manner to the 0.4.x series when the design is worked out. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.6...HEAD +[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6 +[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5 +[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4 +[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3 +[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2 +[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1 +[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0 +[release tags]: https://github.com/rust-lang-nursery/log/releases diff --git a/log/Cargo.toml b/log/Cargo.toml new file mode 100644 index 000000000..c589af93b --- /dev/null +++ b/log/Cargo.toml @@ -0,0 +1,59 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "log" +version = "0.4.6" +authors = ["The Rust Project Developers"] +description = "A lightweight logging facade for Rust\n" +homepage = "https://github.com/rust-lang/log" +documentation = "https://docs.rs/log" +readme = "README.md" +keywords = ["logging"] +categories = ["development-tools::debugging"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/log" +[package.metadata.docs.rs] +features = ["std", "serde"] + +[[test]] +name = "filters" +harness = false +[dependencies.cfg-if] +version = "0.1.2" + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false +[dev-dependencies.serde_test] +version = "1.0" + +[features] +max_level_debug = [] +max_level_error = [] +max_level_info = [] +max_level_off = [] +max_level_trace = [] +max_level_warn = [] +release_max_level_debug = [] +release_max_level_error = [] +release_max_level_info = [] +release_max_level_off = [] +release_max_level_trace = [] +release_max_level_warn = [] +std = [] +[badges.appveyor] +repository = "alexcrichton/log" + +[badges.travis-ci] +repository = "rust-lang-nursery/log" diff --git a/log/LICENSE-APACHE b/log/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/log/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/log/LICENSE-MIT b/log/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/log/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/log/README.md b/log/README.md new file mode 100644 index 000000000..b7884ad83 --- /dev/null +++ b/log/README.md @@ -0,0 +1,88 @@ +log +=== + +A Rust library providing a lightweight logging *facade*. + +[![Build Status](https://travis-ci.org/rust-lang-nursery/log.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/log) +[![Build status](https://ci.appveyor.com/api/projects/status/nopdjmmjt45xcrki?svg=true)](https://ci.appveyor.com/project/alexcrichton/log) +[![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log) +[![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log) +![License](https://img.shields.io/crates/l/log.svg) + +* [`log` documentation](https://docs.rs/log) + +A logging facade provides a single logging API that abstracts over the actual +logging implementation. Libraries can use the logging API provided by this +crate, and the consumer of those libraries can choose the logging +implementation that is most suitable for its use case. + +## Usage + +## In libraries + +Libraries should link only to the `log` crate, and use the provided macros to +log whatever information will be useful to downstream consumers: + +```toml +[dependencies] +log = "0.4" +``` + +```rust +#[macro_use] +extern crate log; + +pub fn shave_the_yak(yak: &mut Yak) { + trace!("Commencing yak shaving"); + + loop { + match find_a_razor() { + Ok(razor) => { + info!("Razor located: {}", razor); + yak.shave(razor); + break; + } + Err(err) => { + warn!("Unable to locate a razor: {}, retrying", err); + } + } + } +} +``` + +If you use Rust 2018, you can use instead the following code to import the crate macros: + +```rust +use log::{info, trace, warn}; + +pub fn shave_the_yak(yak: &mut Yak) { + // … +} +``` + +## In executables + +In order to produce log output executables have to use a logger implementation compatible with the facade. +There are many available implementations to chose from, here are some of the most popular ones: + +* Simple minimal loggers: + * [`env_logger`](https://docs.rs/env_logger/*/env_logger/) + * [`simple_logger`](https://github.com/borntyping/rust-simple_logger) + * [`simplelog`](https://github.com/drakulix/simplelog.rs) + * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/) + * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/) + * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/) +* Complex configurable frameworks: + * [`log4rs`](https://docs.rs/log4rs/*/log4rs/) + * [`fern`](https://docs.rs/fern/*/fern/) +* Adaptors for other facilities: + * [`syslog`](https://docs.rs/syslog/*/syslog/) + * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/) + * [`android_log`](https://docs.rs/android_log/*/android_log/) + +Executables should choose a logger implementation and initialize it early in the +runtime of the program. Logger implementations will typically include a +function to do this. Any log messages generated before the logger is +initialized will be ignored. + +The executable itself may use the `log` crate to log as well. diff --git a/log/appveyor.yml b/log/appveyor.yml new file mode 100644 index 000000000..eb6786dd1 --- /dev/null +++ b/log/appveyor.yml @@ -0,0 +1,19 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose + - cargo test --verbose --features serde + - cargo test --verbose --features std diff --git a/log/src/lib.rs b/log/src/lib.rs new file mode 100644 index 000000000..af4de3a7f --- /dev/null +++ b/log/src/lib.rs @@ -0,0 +1,1469 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A lightweight logging facade. +//! +//! The `log` crate provides a single logging API that abstracts over the +//! actual logging implementation. Libraries can use the logging API provided +//! by this crate, and the consumer of those libraries can choose the logging +//! implementation that is most suitable for its use case. +//! +//! If no logging implementation is selected, the facade falls back to a "noop" +//! implementation that ignores all log messages. The overhead in this case +//! is very small - just an integer load, comparison and jump. +//! +//! A log request consists of a _target_, a _level_, and a _body_. A target is a +//! string which defaults to the module path of the location of the log request, +//! though that default may be overridden. Logger implementations typically use +//! the target to filter requests based on some user configuration. +//! +//! # Use +//! +//! The basic use of the log crate is through the five logging macros: [`error!`], +//! [`warn!`], [`info!`], [`debug!`] and [`trace!`] +//! where `error!` represents the highest-priority log messages +//! and `trace!` the lowest. The log messages are filtered by configuring +//! the log level to exclude messages with a lower priority. +//! Each of these macros accept format strings similarly to [`println!`]. +//! +//! +//! [`error!`]: ./macro.error.html +//! [`warn!`]: ./macro.warn.html +//! [`info!`]: ./macro.info.html +//! [`debug!`]: ./macro.debug.html +//! [`trace!`]: ./macro.trace.html +//! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html +//! +//! ## In libraries +//! +//! Libraries should link only to the `log` crate, and use the provided +//! macros to log whatever information will be useful to downstream consumers. +//! +//! ### Examples +//! +//! ```rust +//! # #![allow(unstable)] +//! #[macro_use] +//! extern crate log; +//! +//! # #[derive(Debug)] pub struct Yak(String); +//! # impl Yak { fn shave(&mut self, _: u32) {} } +//! # fn find_a_razor() -> Result { Ok(1) } +//! pub fn shave_the_yak(yak: &mut Yak) { +//! info!(target: "yak_events", "Commencing yak shaving for {:?}", yak); +//! +//! loop { +//! match find_a_razor() { +//! Ok(razor) => { +//! info!("Razor located: {}", razor); +//! yak.shave(razor); +//! break; +//! } +//! Err(err) => { +//! warn!("Unable to locate a razor: {}, retrying", err); +//! } +//! } +//! } +//! } +//! # fn main() {} +//! ``` +//! +//! ## In executables +//! +//! Executables should choose a logging implementation and initialize it early in the +//! runtime of the program. Logging implementations will typically include a +//! function to do this. Any log messages generated before +//! the implementation is initialized will be ignored. +//! +//! The executable itself may use the `log` crate to log as well. +//! +//! ### Warning +//! +//! The logging system may only be initialized once. +//! +//! # Available logging implementations +//! +//! In order to produce log output executables have to use +//! a logger implementation compatible with the facade. +//! There are many available implementations to choose from, +//! here are some of the most popular ones: +//! +//! * Simple minimal loggers: +//! * [env_logger] +//! * [simple_logger] +//! * [simplelog] +//! * [pretty_env_logger] +//! * [stderrlog] +//! * [flexi_logger] +//! * Complex configurable frameworks: +//! * [log4rs] +//! * [fern] +//! * Adaptors for other facilities: +//! * [syslog] +//! * [slog-stdlog] +//! +//! # Implementing a Logger +//! +//! Loggers implement the [`Log`] trait. Here's a very basic example that simply +//! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or +//! [`Info`][level_link] levels to stdout: +//! +//! ```rust +//! extern crate log; +//! +//! use log::{Record, Level, Metadata}; +//! +//! struct SimpleLogger; +//! +//! impl log::Log for SimpleLogger { +//! fn enabled(&self, metadata: &Metadata) -> bool { +//! metadata.level() <= Level::Info +//! } +//! +//! fn log(&self, record: &Record) { +//! if self.enabled(record.metadata()) { +//! println!("{} - {}", record.level(), record.args()); +//! } +//! } +//! +//! fn flush(&self) {} +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Loggers are installed by calling the [`set_logger`] function. The maximum +//! log level also needs to be adjusted via the [`set_max_level`] function. The +//! logging facade uses this as an optimization to improve performance of log +//! messages at levels that are disabled. It's important to set it, as it +//! defaults to [`Off`][filter_link], so no log messages will ever be captured! +//! In the case of our example logger, we'll want to set the maximum log level +//! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or +//! [`Trace`][level_link] level log messages. A logging implementation should +//! provide a function that wraps a call to [`set_logger`] and +//! [`set_max_level`], handling initialization of the logger: +//! +//! ```rust +//! # extern crate log; +//! # use log::{Level, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! use log::{SetLoggerError, LevelFilter}; +//! +//! static LOGGER: SimpleLogger = SimpleLogger; +//! +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_logger(&LOGGER) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! Implementations that adjust their configurations at runtime should take care +//! to adjust the maximum log level as well. +//! +//! # Use with `std` +//! +//! `set_logger` requires you to provide a `&'static Log`, which can be hard to +//! obtain if your logger depends on some runtime configuration. The +//! `set_boxed_logger` function is available with the `std` Cargo feature. It is +//! identical to `set_logger` except that it takes a `Box` rather than a +//! `&'static Log`: +//! +//! ```rust +//! # extern crate log; +//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata}; +//! # struct SimpleLogger; +//! # impl log::Log for SimpleLogger { +//! # fn enabled(&self, _: &Metadata) -> bool { false } +//! # fn log(&self, _: &log::Record) {} +//! # fn flush(&self) {} +//! # } +//! # fn main() {} +//! # #[cfg(feature = "std")] +//! pub fn init() -> Result<(), SetLoggerError> { +//! log::set_boxed_logger(Box::new(SimpleLogger)) +//! .map(|()| log::set_max_level(LevelFilter::Info)) +//! } +//! ``` +//! +//! # Compile time filters +//! +//! Log levels can be statically disabled at compile time via Cargo features. Log invocations at +//! disabled levels will be skipped and will not even be present in the resulting binary unless the +//! log level is specified dynamically. This level is configured separately for release and debug +//! builds. The features are: +//! +//! * `max_level_off` +//! * `max_level_error` +//! * `max_level_warn` +//! * `max_level_info` +//! * `max_level_debug` +//! * `max_level_trace` +//! * `release_max_level_off` +//! * `release_max_level_error` +//! * `release_max_level_warn` +//! * `release_max_level_info` +//! * `release_max_level_debug` +//! * `release_max_level_trace` +//! +//! These features control the value of the `STATIC_MAX_LEVEL` constant. The logging macros check +//! this value before logging a message. By default, no levels are disabled. +//! +//! For example, a crate can disable trace level logs in debug builds and trace, debug, and info +//! level logs in release builds with the following configuration: +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] } +//! ``` +//! # Crate Feature Flags +//! +//! The following crate feature flags are avaliable in addition to the filters. They are +//! configured in your `Cargo.toml`. +//! +//! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and +//! `set_boxed_logger` functionality. +//! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`. +//! +//! ```toml +//! [dependencies] +//! log = { version = "0.4", features = ["std", "serde"] } +//! ``` +//! +//! # Version compatibility +//! +//! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages +//! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log +//! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the +//! module path and file name information associated with the message will unfortunately be lost. +//! +//! [`Log`]: trait.Log.html +//! [level_link]: enum.Level.html +//! [filter_link]: enum.LevelFilter.html +//! [`set_logger`]: fn.set_logger.html +//! [`set_max_level`]: fn.set_max_level.html +//! [`try_set_logger_raw`]: fn.try_set_logger_raw.html +//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html +//! [env_logger]: https://docs.rs/env_logger/*/env_logger/ +//! [simple_logger]: https://github.com/borntyping/rust-simple_logger +//! [simplelog]: https://github.com/drakulix/simplelog.rs +//! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/ +//! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/ +//! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/ +//! [syslog]: https://docs.rs/syslog/*/syslog/ +//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/ +//! [log4rs]: https://docs.rs/log4rs/*/log4rs/ +//! [fern]: https://docs.rs/fern/*/fern/ + +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/log/0.4.6" +)] +#![warn(missing_docs)] +#![deny(missing_debug_implementations)] +#![cfg_attr(not(feature = "std"), no_std)] +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +#[cfg(not(feature = "std"))] +extern crate core as std; + +#[macro_use] +extern crate cfg_if; + +use std::cmp; +#[cfg(feature = "std")] +use std::error; +use std::fmt; +use std::mem; +use std::str::FromStr; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + +#[macro_use] +mod macros; +mod serde; + +// The LOGGER static holds a pointer to the global logger. It is protected by +// the STATE static which determines whether LOGGER has been initialized yet. +static mut LOGGER: &'static Log = &NopLogger; +static STATE: AtomicUsize = ATOMIC_USIZE_INIT; + +// There are three different states that we care about: the logger's +// uninitialized, the logger's initializing (set_logger's been called but +// LOGGER hasn't actually been set yet), or the logger's active. +const UNINITIALIZED: usize = 0; +const INITIALIZING: usize = 1; +const INITIALIZED: usize = 2; + +static MAX_LOG_LEVEL_FILTER: AtomicUsize = ATOMIC_USIZE_INIT; + +static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; + +static SET_LOGGER_ERROR: &'static str = "attempted to set a logger after the logging system \ + was already initialized"; +static LEVEL_PARSE_ERROR: &'static str = + "attempted to convert a string that doesn't match an existing log level"; + +/// An enum representing the available verbosity levels of the logger. +/// +/// Typical usage includes: checking if a certain `Level` is enabled with +/// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of +/// [`log!`](macro.log.html), and comparing a `Level` directly to a +/// [`LevelFilter`](enum.LevelFilter.html). +#[repr(usize)] +#[derive(Copy, Eq, Debug, Hash)] +pub enum Level { + /// The "error" level. + /// + /// Designates very serious errors. + Error = 1, // This way these line up with the discriminants for LevelFilter below + /// The "warn" level. + /// + /// Designates hazardous situations. + Warn, + /// The "info" level. + /// + /// Designates useful information. + Info, + /// The "debug" level. + /// + /// Designates lower priority information. + Debug, + /// The "trace" level. + /// + /// Designates very low priority, often extremely verbose, information. + Trace, +} + +impl Clone for Level { + #[inline] + fn clone(&self) -> Level { + *self + } +} + +impl PartialEq for Level { + #[inline] + fn eq(&self, other: &Level) -> bool { + *self as usize == *other as usize + } +} + +impl PartialEq for Level { + #[inline] + fn eq(&self, other: &LevelFilter) -> bool { + *self as usize == *other as usize + } +} + +impl PartialOrd for Level { + #[inline] + fn partial_cmp(&self, other: &Level) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &Level) -> bool { + (*self as usize) < *other as usize + } + + #[inline] + fn le(&self, other: &Level) -> bool { + *self as usize <= *other as usize + } + + #[inline] + fn gt(&self, other: &Level) -> bool { + *self as usize > *other as usize + } + + #[inline] + fn ge(&self, other: &Level) -> bool { + *self as usize >= *other as usize + } +} + +impl PartialOrd for Level { + #[inline] + fn partial_cmp(&self, other: &LevelFilter) -> Option { + Some((*self as usize).cmp(&(*other as usize))) + } + + #[inline] + fn lt(&self, other: &LevelFilter) -> bool { + (*self as usize) < *other as usize + } + + #[inline] + fn le(&self, other: &LevelFilter) -> bool { + *self as usize <= *other as usize + } + + #[inline] + fn gt(&self, other: &LevelFilter) -> bool { + *self as usize > *other as usize + } + + #[inline] + fn ge(&self, other: &LevelFilter) -> bool { + *self as usize >= *other as usize + } +} + +impl Ord for Level { + #[inline] + fn cmp(&self, other: &Level) -> cmp::Ordering { + (*self as usize).cmp(&(*other as usize)) + } +} + +fn ok_or(t: Option, e: E) -> Result { + match t { + Some(t) => Ok(t), + None => Err(e), + } +} + +// Reimplemented here because std::ascii is not available in libcore +fn eq_ignore_ascii_case(a: &str, b: &str) -> bool { + fn to_ascii_uppercase(c: u8) -> u8 { + if c >= b'a' && c <= b'z' { + c - b'a' + b'A' + } else { + c + } + } + + if a.len() == b.len() { + a.bytes() + .zip(b.bytes()) + .all(|(a, b)| to_ascii_uppercase(a) == to_ascii_uppercase(b)) + } else { + false + } +} + +impl FromStr for Level { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result { + ok_or( + LOG_LEVEL_NAMES + .iter() + .position(|&name| eq_ignore_ascii_case(name, level)) + .into_iter() + .filter(|&idx| idx != 0) + .map(|idx| Level::from_usize(idx).unwrap()) + .next(), + ParseLevelError(()), + ) + } +} + +impl fmt::Display for Level { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.pad(LOG_LEVEL_NAMES[*self as usize]) + } +} + +impl Level { + fn from_usize(u: usize) -> Option { + match u { + 1 => Some(Level::Error), + 2 => Some(Level::Warn), + 3 => Some(Level::Info), + 4 => Some(Level::Debug), + 5 => Some(Level::Trace), + _ => None, + } + } + + /// Returns the most verbose logging level. + #[inline] + pub fn max() -> Level { + Level::Trace + } + + /// Converts the `Level` to the equivalent `LevelFilter`. + #[inline] + pub fn to_level_filter(&self) -> LevelFilter { + LevelFilter::from_usize(*self as usize).unwrap() + } +} + +/// An enum representing the available verbosity level filters of the logger. +/// +/// A `LevelFilter` may be compared directly to a [`Level`]. Use this type +/// to get and set the maximum log level with [`max_level()`] and [`set_max_level`]. +/// +/// [`Level`]: enum.Level.html +/// [`max_level()`]: fn.max_level.html +/// [`set_max_level`]: fn.set_max_level.html +#[repr(usize)] +#[derive(Copy, Eq, Debug, Hash)] +pub enum LevelFilter { + /// A level lower than all log levels. + Off, + /// Corresponds to the `Error` log level. + Error, + /// Corresponds to the `Warn` log level. + Warn, + /// Corresponds to the `Info` log level. + Info, + /// Corresponds to the `Debug` log level. + Debug, + /// Corresponds to the `Trace` log level. + Trace, +} + +// Deriving generates terrible impls of these traits + +impl Clone for LevelFilter { + #[inline] + fn clone(&self) -> LevelFilter { + *self + } +} + +impl PartialEq for LevelFilter { + #[inline] + fn eq(&self, other: &LevelFilter) -> bool { + *self as usize == *other as usize + } +} + +impl PartialEq for LevelFilter { + #[inline] + fn eq(&self, other: &Level) -> bool { + other.eq(self) + } +} + +impl PartialOrd for LevelFilter { + #[inline] + fn partial_cmp(&self, other: &LevelFilter) -> Option { + Some(self.cmp(other)) + } + + #[inline] + fn lt(&self, other: &LevelFilter) -> bool { + (*self as usize) < *other as usize + } + + #[inline] + fn le(&self, other: &LevelFilter) -> bool { + *self as usize <= *other as usize + } + + #[inline] + fn gt(&self, other: &LevelFilter) -> bool { + *self as usize > *other as usize + } + + #[inline] + fn ge(&self, other: &LevelFilter) -> bool { + *self as usize >= *other as usize + } +} + +impl PartialOrd for LevelFilter { + #[inline] + fn partial_cmp(&self, other: &Level) -> Option { + Some((*self as usize).cmp(&(*other as usize))) + } + + #[inline] + fn lt(&self, other: &Level) -> bool { + (*self as usize) < *other as usize + } + + #[inline] + fn le(&self, other: &Level) -> bool { + *self as usize <= *other as usize + } + + #[inline] + fn gt(&self, other: &Level) -> bool { + *self as usize > *other as usize + } + + #[inline] + fn ge(&self, other: &Level) -> bool { + *self as usize >= *other as usize + } +} + +impl Ord for LevelFilter { + #[inline] + fn cmp(&self, other: &LevelFilter) -> cmp::Ordering { + (*self as usize).cmp(&(*other as usize)) + } +} + +impl FromStr for LevelFilter { + type Err = ParseLevelError; + fn from_str(level: &str) -> Result { + ok_or( + LOG_LEVEL_NAMES + .iter() + .position(|&name| eq_ignore_ascii_case(name, level)) + .map(|p| LevelFilter::from_usize(p).unwrap()), + ParseLevelError(()), + ) + } +} + +impl fmt::Display for LevelFilter { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", LOG_LEVEL_NAMES[*self as usize]) + } +} + +impl LevelFilter { + fn from_usize(u: usize) -> Option { + match u { + 0 => Some(LevelFilter::Off), + 1 => Some(LevelFilter::Error), + 2 => Some(LevelFilter::Warn), + 3 => Some(LevelFilter::Info), + 4 => Some(LevelFilter::Debug), + 5 => Some(LevelFilter::Trace), + _ => None, + } + } + /// Returns the most verbose logging level filter. + #[inline] + pub fn max() -> LevelFilter { + LevelFilter::Trace + } + + /// Converts `self` to the equivalent `Level`. + /// + /// Returns `None` if `self` is `LevelFilter::Off`. + #[inline] + pub fn to_level(&self) -> Option { + Level::from_usize(*self as usize) + } +} + +/// The "payload" of a log message. +/// +/// # Use +/// +/// `Record` structures are passed as parameters to the [`log`][method.log] +/// method of the [`Log`] trait. Logger implementors manipulate these +/// structures in order to display log messages. `Record`s are automatically +/// created by the [`log!`] macro and so are not seen by log users. +/// +/// Note that the [`level()`] and [`target()`] accessors are equivalent to +/// `self.metadata().level()` and `self.metadata().target()` respectively. +/// These methods are provided as a convenience for users of this structure. +/// +/// # Example +/// +/// The following example shows a simple logger that displays the level, +/// module path, and message of any `Record` that is passed to it. +/// +/// ```rust +/// # extern crate log; +/// struct SimpleLogger; +/// +/// impl log::Log for SimpleLogger { +/// fn enabled(&self, metadata: &log::Metadata) -> bool { +/// true +/// } +/// +/// fn log(&self, record: &log::Record) { +/// if !self.enabled(record.metadata()) { +/// return; +/// } +/// +/// println!("{}:{} -- {}", +/// record.level(), +/// record.target(), +/// record.args()); +/// } +/// fn flush(&self) {} +/// } +/// ``` +/// +/// [method.log]: trait.Log.html#tymethod.log +/// [`Log`]: trait.Log.html +/// [`log!`]: macro.log.html +/// [`level()`]: struct.Record.html#method.level +/// [`target()`]: struct.Record.html#method.target +#[derive(Clone, Debug)] +pub struct Record<'a> { + metadata: Metadata<'a>, + args: fmt::Arguments<'a>, + module_path: Option<&'a str>, + file: Option<&'a str>, + line: Option, +} + +impl<'a> Record<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> RecordBuilder<'a> { + RecordBuilder::new() + } + + /// The message body. + #[inline] + pub fn args(&self) -> &fmt::Arguments<'a> { + &self.args + } + + /// Metadata about the log directive. + #[inline] + pub fn metadata(&self) -> &Metadata<'a> { + &self.metadata + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.metadata.level() + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.metadata.target() + } + + /// The module path of the message. + #[inline] + pub fn module_path(&self) -> Option<&'a str> { + self.module_path + } + + /// The source file containing the message. + #[inline] + pub fn file(&self) -> Option<&'a str> { + self.file + } + + /// The line containing the message. + #[inline] + pub fn line(&self) -> Option { + self.line + } +} + +/// Builder for [`Record`](struct.Record.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `RecordBuilder` can set the different parameters of `Record` object, and returns +/// the created object when `build` is called. +/// +/// # Examples +/// +/// +/// ```rust +/// use log::{Level, Record}; +/// +/// let record = Record::builder() +/// .args(format_args!("Error!")) +/// .level(Level::Error) +/// .target("myApp") +/// .file(Some("server.rs")) +/// .line(Some(144)) +/// .module_path(Some("server")) +/// .build(); +/// ``` +/// +/// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html): +/// +/// ```rust +/// use log::{Record, Level, MetadataBuilder}; +/// +/// let error_metadata = MetadataBuilder::new() +/// .target("myApp") +/// .level(Level::Error) +/// .build(); +/// +/// let record = Record::builder() +/// .metadata(error_metadata) +/// .args(format_args!("Error!")) +/// .line(Some(433)) +/// .file(Some("app.rs")) +/// .module_path(Some("server")) +/// .build(); +/// ``` +#[derive(Debug)] +pub struct RecordBuilder<'a> { + record: Record<'a>, +} + +impl<'a> RecordBuilder<'a> { + /// Construct new `RecordBuilder`. + /// + /// The default options are: + /// + /// - `args`: [`format_args!("")`] + /// - `metadata`: [`Metadata::builder().build()`] + /// - `module_path`: `None` + /// - `file`: `None` + /// - `line`: `None` + /// + /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html + /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build + #[inline] + pub fn new() -> RecordBuilder<'a> { + RecordBuilder { + record: Record { + args: format_args!(""), + metadata: Metadata::builder().build(), + module_path: None, + file: None, + line: None, + }, + } + } + + /// Set [`args`](struct.Record.html#method.args). + #[inline] + pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> { + self.record.args = args; + self + } + + /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html). + #[inline] + pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> { + self.record.metadata = metadata; + self + } + + /// Set [`Metadata::level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> { + self.record.metadata.level = level; + self + } + + /// Set [`Metadata::target`](struct.Metadata.html#method.target) + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> { + self.record.metadata.target = target; + self + } + + /// Set [`module_path`](struct.Record.html#method.module_path) + #[inline] + pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.module_path = path; + self + } + + /// Set [`file`](struct.Record.html#method.file) + #[inline] + pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> { + self.record.file = file; + self + } + + /// Set [`line`](struct.Record.html#method.line) + #[inline] + pub fn line(&mut self, line: Option) -> &mut RecordBuilder<'a> { + self.record.line = line; + self + } + + /// Invoke the builder and return a `Record` + #[inline] + pub fn build(&self) -> Record<'a> { + self.record.clone() + } +} + +/// Metadata about a log message. +/// +/// # Use +/// +/// `Metadata` structs are created when users of the library use +/// logging macros. +/// +/// They are consumed by implementations of the `Log` trait in the +/// `enabled` method. +/// +/// `Record`s use `Metadata` to determine the log message's severity +/// and target. +/// +/// Users should use the `log_enabled!` macro in their code to avoid +/// constructing expensive log messages. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # +/// use log::{Record, Level, Metadata}; +/// +/// struct MyLogger; +/// +/// impl log::Log for MyLogger { +/// fn enabled(&self, metadata: &Metadata) -> bool { +/// metadata.level() <= Level::Info +/// } +/// +/// fn log(&self, record: &Record) { +/// if self.enabled(record.metadata()) { +/// println!("{} - {}", record.level(), record.args()); +/// } +/// } +/// fn flush(&self) {} +/// } +/// +/// # fn main(){} +/// ``` +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct Metadata<'a> { + level: Level, + target: &'a str, +} + +impl<'a> Metadata<'a> { + /// Returns a new builder. + #[inline] + pub fn builder() -> MetadataBuilder<'a> { + MetadataBuilder::new() + } + + /// The verbosity level of the message. + #[inline] + pub fn level(&self) -> Level { + self.level + } + + /// The name of the target of the directive. + #[inline] + pub fn target(&self) -> &'a str { + self.target + } +} + +/// Builder for [`Metadata`](struct.Metadata.html). +/// +/// Typically should only be used by log library creators or for testing and "shim loggers". +/// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns +/// the created object when `build` is called. +/// +/// # Example +/// +/// ```rust +/// let target = "myApp"; +/// use log::{Level, MetadataBuilder}; +/// let metadata = MetadataBuilder::new() +/// .level(Level::Debug) +/// .target(target) +/// .build(); +/// ``` +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub struct MetadataBuilder<'a> { + metadata: Metadata<'a>, +} + +impl<'a> MetadataBuilder<'a> { + /// Construct a new `MetadataBuilder`. + /// + /// The default options are: + /// + /// - `level`: `Level::Info` + /// - `target`: `""` + #[inline] + pub fn new() -> MetadataBuilder<'a> { + MetadataBuilder { + metadata: Metadata { + level: Level::Info, + target: "", + }, + } + } + + /// Setter for [`level`](struct.Metadata.html#method.level). + #[inline] + pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> { + self.metadata.level = arg; + self + } + + /// Setter for [`target`](struct.Metadata.html#method.target). + #[inline] + pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> { + self.metadata.target = target; + self + } + + /// Returns a `Metadata` object. + #[inline] + pub fn build(&self) -> Metadata<'a> { + self.metadata.clone() + } +} + +/// A trait encapsulating the operations required of a logger. +pub trait Log: Sync + Send { + /// Determines if a log message with the specified metadata would be + /// logged. + /// + /// This is used by the `log_enabled!` macro to allow callers to avoid + /// expensive computation of log message arguments if the message would be + /// discarded anyway. + fn enabled(&self, metadata: &Metadata) -> bool; + + /// Logs the `Record`. + /// + /// Note that `enabled` is *not* necessarily called before this method. + /// Implementations of `log` should perform all necessary filtering + /// internally. + fn log(&self, record: &Record); + + /// Flushes any buffered records. + fn flush(&self); +} + +// Just used as a dummy initial value for LOGGER +struct NopLogger; + +impl Log for NopLogger { + fn enabled(&self, _: &Metadata) -> bool { + false + } + + fn log(&self, _: &Record) {} + fn flush(&self) {} +} + +/// Sets the global maximum log level. +/// +/// Generally, this should only be called by the active logging implementation. +#[inline] +pub fn set_max_level(level: LevelFilter) { + MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::SeqCst) +} + +/// Returns the current maximum log level. +/// +/// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check +/// this value and discard any message logged at a higher level. The maximum +/// log level is set by the [`set_max_level`] function. +/// +/// [`log!`]: macro.log.html +/// [`error!`]: macro.error.html +/// [`warn!`]: macro.warn.html +/// [`info!`]: macro.info.html +/// [`debug!`]: macro.debug.html +/// [`trace!`]: macro.trace.html +/// [`set_max_level`]: fn.set_max_level.html +#[inline(always)] +pub fn max_level() -> LevelFilter { + unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) } +} + +/// Sets the global logger to a `Box`. +/// +/// This is a simple convenience wrapper over `set_logger`, which takes a +/// `Box` rather than a `&'static Log`. See the documentation for +/// [`set_logger`] for more details. +/// +/// Requires the `std` feature. +/// +/// # Errors +/// +/// An error is returned if a logger has already been set. +/// +/// [`set_logger`]: fn.set_logger.html +#[cfg(feature = "std")] +pub fn set_boxed_logger(logger: Box) -> Result<(), SetLoggerError> { + set_logger_inner(|| unsafe { &*Box::into_raw(logger) }) +} + +/// Sets the global logger to a `&'static Log`. +/// +/// This function may only be called once in the lifetime of a program. Any log +/// events that occur before the call to `set_logger` completes will be ignored. +/// +/// This function does not typically need to be called manually. Logger +/// implementations should provide an initialization method that installs the +/// logger internally. +/// +/// # Errors +/// +/// An error is returned if a logger has already been set. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # +/// use log::{Record, Level, Metadata, LevelFilter}; +/// +/// static MY_LOGGER: MyLogger = MyLogger; +/// +/// struct MyLogger; +/// +/// impl log::Log for MyLogger { +/// fn enabled(&self, metadata: &Metadata) -> bool { +/// metadata.level() <= Level::Info +/// } +/// +/// fn log(&self, record: &Record) { +/// if self.enabled(record.metadata()) { +/// println!("{} - {}", record.level(), record.args()); +/// } +/// } +/// fn flush(&self) {} +/// } +/// +/// # fn main(){ +/// log::set_logger(&MY_LOGGER).unwrap(); +/// log::set_max_level(LevelFilter::Info); +/// +/// info!("hello log"); +/// warn!("warning"); +/// error!("oops"); +/// # } +/// ``` +pub fn set_logger(logger: &'static Log) -> Result<(), SetLoggerError> { + set_logger_inner(|| logger) +} + +fn set_logger_inner(make_logger: F) -> Result<(), SetLoggerError> +where + F: FnOnce() -> &'static Log, +{ + unsafe { + match STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) { + UNINITIALIZED => { + LOGGER = make_logger(); + STATE.store(INITIALIZED, Ordering::SeqCst); + Ok(()) + } + INITIALIZING => { + while STATE.load(Ordering::SeqCst) == INITIALIZING {} + Err(SetLoggerError(())) + } + _ => Err(SetLoggerError(())), + } + } +} + +/// The type returned by [`set_logger`] if [`set_logger`] has already been called. +/// +/// [`set_logger`]: fn.set_logger.html +#[allow(missing_copy_implementations)] +#[derive(Debug)] +pub struct SetLoggerError(()); + +impl fmt::Display for SetLoggerError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(SET_LOGGER_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for SetLoggerError { + fn description(&self) -> &str { + SET_LOGGER_ERROR + } +} + +/// The type returned by [`from_str`] when the string doesn't match any of the log levels. +/// +/// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str +#[allow(missing_copy_implementations)] +#[derive(Debug, PartialEq)] +pub struct ParseLevelError(()); + +impl fmt::Display for ParseLevelError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(LEVEL_PARSE_ERROR) + } +} + +// The Error trait is not available in libcore +#[cfg(feature = "std")] +impl error::Error for ParseLevelError { + fn description(&self) -> &str { + LEVEL_PARSE_ERROR + } +} + +/// Returns a reference to the logger. +/// +/// If a logger has not been set, a no-op implementation is returned. +pub fn logger() -> &'static Log { + unsafe { + if STATE.load(Ordering::SeqCst) != INITIALIZED { + static NOP: NopLogger = NopLogger; + &NOP + } else { + LOGGER + } + } +} + +// WARNING: this is not part of the crate's public API and is subject to change at any time +#[doc(hidden)] +pub fn __private_api_log( + args: fmt::Arguments, + level: Level, + &(target, module_path, file, line): &(&str, &str, &str, u32), +) { + logger().log( + &Record::builder() + .args(args) + .level(level) + .target(target) + .module_path(Some(module_path)) + .file(Some(file)) + .line(Some(line)) + .build(), + ); +} + +// WARNING: this is not part of the crate's public API and is subject to change at any time +#[doc(hidden)] +pub fn __private_api_enabled(level: Level, target: &str) -> bool { + logger().enabled(&Metadata::builder().level(level).target(target).build()) +} + +/// The statically resolved maximum log level. +/// +/// See the crate level documentation for information on how to configure this. +/// +/// This value is checked by the log macros, but not by the `Log`ger returned by +/// the [`logger`] function. Code that manually calls functions on that value +/// should compare the level against this value. +/// +/// [`logger`]: fn.logger.html +pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL_INNER; + +cfg_if! { + if #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Off; + } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Error; + } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Warn; + } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Info; + } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Debug; + } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Trace; + } else if #[cfg(feature = "max_level_off")] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Off; + } else if #[cfg(feature = "max_level_error")] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Error; + } else if #[cfg(feature = "max_level_warn")] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Warn; + } else if #[cfg(feature = "max_level_info")] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Info; + } else if #[cfg(feature = "max_level_debug")] { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Debug; + } else { + const MAX_LEVEL_INNER: LevelFilter = LevelFilter::Trace; + } +} + +#[cfg(test)] +mod tests { + extern crate std; + use super::{Level, LevelFilter, ParseLevelError}; + use tests::std::string::ToString; + + #[test] + fn test_levelfilter_from_str() { + let tests = [ + ("off", Ok(LevelFilter::Off)), + ("error", Ok(LevelFilter::Error)), + ("warn", Ok(LevelFilter::Warn)), + ("info", Ok(LevelFilter::Info)), + ("debug", Ok(LevelFilter::Debug)), + ("trace", Ok(LevelFilter::Trace)), + ("OFF", Ok(LevelFilter::Off)), + ("ERROR", Ok(LevelFilter::Error)), + ("WARN", Ok(LevelFilter::Warn)), + ("INFO", Ok(LevelFilter::Info)), + ("DEBUG", Ok(LevelFilter::Debug)), + ("TRACE", Ok(LevelFilter::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_from_str() { + let tests = [ + ("OFF", Err(ParseLevelError(()))), + ("error", Ok(Level::Error)), + ("warn", Ok(Level::Warn)), + ("info", Ok(Level::Info)), + ("debug", Ok(Level::Debug)), + ("trace", Ok(Level::Trace)), + ("ERROR", Ok(Level::Error)), + ("WARN", Ok(Level::Warn)), + ("INFO", Ok(Level::Info)), + ("DEBUG", Ok(Level::Debug)), + ("TRACE", Ok(Level::Trace)), + ("asdf", Err(ParseLevelError(()))), + ]; + for &(s, ref expected) in &tests { + assert_eq!(expected, &s.parse()); + } + } + + #[test] + fn test_level_show() { + assert_eq!("INFO", Level::Info.to_string()); + assert_eq!("ERROR", Level::Error.to_string()); + } + + #[test] + fn test_levelfilter_show() { + assert_eq!("OFF", LevelFilter::Off.to_string()); + assert_eq!("ERROR", LevelFilter::Error.to_string()); + } + + #[test] + fn test_cross_cmp() { + assert!(Level::Debug > LevelFilter::Error); + assert!(LevelFilter::Warn < Level::Trace); + assert!(LevelFilter::Off < Level::Error); + } + + #[test] + fn test_cross_eq() { + assert!(Level::Error == LevelFilter::Error); + assert!(LevelFilter::Off != Level::Error); + assert!(Level::Trace == LevelFilter::Trace); + } + + #[test] + fn test_to_level() { + assert_eq!(Some(Level::Error), LevelFilter::Error.to_level()); + assert_eq!(None, LevelFilter::Off.to_level()); + assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level()); + } + + #[test] + fn test_to_level_filter() { + assert_eq!(LevelFilter::Error, Level::Error.to_level_filter()); + assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter()); + } + + #[test] + #[cfg(feature = "std")] + fn test_error_trait() { + use super::SetLoggerError; + use std::error::Error; + let e = SetLoggerError(()); + assert_eq!( + e.description(), + "attempted to set a logger after the logging system \ + was already initialized" + ); + } + + #[test] + fn test_metadata_builder() { + use super::MetadataBuilder; + let target = "myApp"; + let metadata_test = MetadataBuilder::new() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_metadata_convenience_builder() { + use super::Metadata; + let target = "myApp"; + let metadata_test = Metadata::builder() + .level(Level::Debug) + .target(target) + .build(); + assert_eq!(metadata_test.level(), Level::Debug); + assert_eq!(metadata_test.target(), "myApp"); + } + + #[test] + fn test_record_builder() { + use super::{MetadataBuilder, RecordBuilder}; + let target = "myApp"; + let metadata = MetadataBuilder::new().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = RecordBuilder::new() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.metadata().target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_convenience_builder() { + use super::{Metadata, Record}; + let target = "myApp"; + let metadata = Metadata::builder().target(target).build(); + let fmt_args = format_args!("hello"); + let record_test = Record::builder() + .args(fmt_args) + .metadata(metadata) + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } + + #[test] + fn test_record_complete_builder() { + use super::{Level, Record}; + let target = "myApp"; + let record_test = Record::builder() + .module_path(Some("foo")) + .file(Some("bar")) + .line(Some(30)) + .target(target) + .level(Level::Error) + .build(); + assert_eq!(record_test.target(), "myApp"); + assert_eq!(record_test.level(), Level::Error); + assert_eq!(record_test.module_path(), Some("foo")); + assert_eq!(record_test.file(), Some("bar")); + assert_eq!(record_test.line(), Some(30)); + } +} diff --git a/log/src/macros.rs b/log/src/macros.rs new file mode 100644 index 000000000..06ce65a57 --- /dev/null +++ b/log/src/macros.rs @@ -0,0 +1,253 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The standard logging macro. +/// +/// This macro will generically log with the specified `Level` and `format!` +/// based argument list. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// use log::Level; +/// +/// # fn main() { +/// let data = (42, "Forty-two"); +/// let private_data = "private"; +/// +/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1); +/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}", +/// data.0, data.1, private_data); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! log { + (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({ + let lvl = $lvl; + if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { + $crate::__private_api_log( + __log_format_args!($($arg)+), + lvl, + &($target, __log_module_path!(), __log_file!(), __log_line!()), + ); + } + }); + ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+)) +} + +/// Logs a message at the error level. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # fn main() { +/// let (err_info, port) = ("No connection", 22); +/// +/// error!("Error: {} on port {}", err_info, port); +/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! error { + (target: $target:expr, $($arg:tt)*) => ( + log!(target: $target, $crate::Level::Error, $($arg)*); + ); + ($($arg:tt)*) => ( + log!($crate::Level::Error, $($arg)*); + ) +} + +/// Logs a message at the warn level. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # fn main() { +/// let warn_description = "Invalid Input"; +/// +/// warn!("Warning! {}!", warn_description); +/// warn!(target: "input_events", "App received warning: {}", warn_description); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! warn { + (target: $target:expr, $($arg:tt)*) => ( + log!(target: $target, $crate::Level::Warn, $($arg)*); + ); + ($($arg:tt)*) => ( + log!($crate::Level::Warn, $($arg)*); + ) +} + +/// Logs a message at the info level. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # fn main() { +/// # struct Connection { port: u32, speed: f32 } +/// let conn_info = Connection { port: 40, speed: 3.20 }; +/// +/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); +/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}", +/// conn_info.port, conn_info.speed); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! info { + (target: $target:expr, $($arg:tt)*) => ( + log!(target: $target, $crate::Level::Info, $($arg)*); + ); + ($($arg:tt)*) => ( + log!($crate::Level::Info, $($arg)*); + ) +} + +/// Logs a message at the debug level. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # fn main() { +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// debug!("New position: x: {}, y: {}", pos.x, pos.y); +/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! debug { + (target: $target:expr, $($arg:tt)*) => ( + log!(target: $target, $crate::Level::Debug, $($arg)*); + ); + ($($arg:tt)*) => ( + log!($crate::Level::Debug, $($arg)*); + ) +} + +/// Logs a message at the trace level. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// # fn main() { +/// # struct Position { x: f32, y: f32 } +/// let pos = Position { x: 3.234, y: -1.223 }; +/// +/// trace!("Position is: x: {}, y: {}", pos.x, pos.y); +/// trace!(target: "app_events", "x is {} and y is {}", +/// if pos.x >= 0.0 { "positive" } else { "negative" }, +/// if pos.y >= 0.0 { "positive" } else { "negative" }); +/// # } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! trace { + (target: $target:expr, $($arg:tt)*) => ( + log!(target: $target, $crate::Level::Trace, $($arg)*); + ); + ($($arg:tt)*) => ( + log!($crate::Level::Trace, $($arg)*); + ) +} + +/// Determines if a message logged at the specified level in that module will +/// be logged. +/// +/// This can be used to avoid expensive computation of log message arguments if +/// the message would be ignored anyway. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] +/// # extern crate log; +/// use log::Level::Debug; +/// +/// # fn foo() { +/// if log_enabled!(Debug) { +/// let data = expensive_call(); +/// debug!("expensive debug data: {} {}", data.x, data.y); +/// } +/// if log_enabled!(target: "Global", Debug) { +/// let data = expensive_call(); +/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y); +/// } +/// # } +/// # struct Data { x: u32, y: u32 } +/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } } +/// # fn main() {} +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! log_enabled { + (target: $target:expr, $lvl:expr) => {{ + let lvl = $lvl; + lvl <= $crate::STATIC_MAX_LEVEL + && lvl <= $crate::max_level() + && $crate::__private_api_enabled(lvl, $target) + }}; + ($lvl:expr) => { + log_enabled!(target: __log_module_path!(), $lvl) + }; +} + +// The log macro above cannot invoke format_args directly because it uses +// local_inner_macros. A format_args invocation there would resolve to +// $crate::format_args which does not exist. Instead invoke format_args here +// outside of local_inner_macros so that it resolves (probably) to +// core::format_args or std::format_args. Same for the several macros that +// follow. +// +// This is a workaround until we drop support for pre-1.30 compilers. At that +// point we can remove use of local_inner_macros, use $crate:: when invoking +// local macros, and invoke format_args directly. +#[doc(hidden)] +#[macro_export] +macro_rules! __log_format_args { + ($($args:tt)*) => { + format_args!($($args)*) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_module_path { + () => { + module_path!() + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_file { + () => { + file!() + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __log_line { + () => { + line!() + }; +} diff --git a/log/src/serde.rs b/log/src/serde.rs new file mode 100644 index 000000000..176f9f411 --- /dev/null +++ b/log/src/serde.rs @@ -0,0 +1,327 @@ +#![cfg(feature = "serde")] + +extern crate serde; +use self::serde::ser::{Serialize, Serializer}; +use self::serde::de::{Deserialize, DeserializeSeed, Deserializer, Visitor, EnumAccess, + Unexpected, VariantAccess, Error}; + +use {Level, LevelFilter, LOG_LEVEL_NAMES}; + +use std::fmt; +use std::str::{self, FromStr}; + +// The Deserialize impls are handwritten to be case insensitive using FromStr. + +impl Serialize for Level { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"), + Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"), + Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"), + Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"), + Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for Level { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct LevelIdentifier; + + impl<'de> Visitor<'de> for LevelIdentifier { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + // Case insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..])) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelIdentifier { + type Value = Level; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelIdentifier) + } + } + + struct LevelEnum; + + impl<'de> Visitor<'de> for LevelEnum { + type Value = Level; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level") + } + + fn visit_enum(self, value: A) -> Result + where + A: EnumAccess<'de>, + { + let (level, variant) = value.variant_seed(LevelIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level) + } + } + + deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum) + } +} + +impl Serialize for LevelFilter { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"), + LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"), + LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"), + LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"), + LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"), + LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"), + } + } +} + +impl<'de> Deserialize<'de> for LevelFilter { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct LevelFilterIdentifier; + + impl<'de> Visitor<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_str(self, s: &str) -> Result + where + E: Error, + { + // Case insensitive. + FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES)) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: Error, + { + let variant = str::from_utf8(value) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; + + self.visit_str(variant) + } + } + + impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier { + type Value = LevelFilter; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_identifier(LevelFilterIdentifier) + } + } + + struct LevelFilterEnum; + + impl<'de> Visitor<'de> for LevelFilterEnum { + type Value = LevelFilter; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("log level filter") + } + + fn visit_enum(self, value: A) -> Result + where + A: EnumAccess<'de>, + { + let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?; + // Every variant is a unit variant. + variant.unit_variant()?; + Ok(level_filter) + } + } + + deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum) + } +} + +#[cfg(test)] +mod tests { + extern crate serde_test; + use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; + + use {Level, LevelFilter}; + + fn level_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "Level", + variant: variant, + } + } + + fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { name: "Level" }, + Token::Bytes(variant), + Token::Unit, + ] + } + + fn level_filter_token(variant: &'static str) -> Token { + Token::UnitVariant { + name: "LevelFilter", + variant: variant, + } + } + + fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { + [ + Token::Enum { + name: "LevelFilter", + }, + Token::Bytes(variant), + Token::Unit, + ] + } + + #[test] + fn test_level_ser_de() { + let cases = [ + (Level::Error, [level_token("ERROR")]), + (Level::Warn, [level_token("WARN")]), + (Level::Info, [level_token("INFO")]), + (Level::Debug, [level_token("DEBUG")]), + (Level::Trace, [level_token("TRACE")]), + ]; + + for &(s, expected) in &cases { + assert_tokens(&s, &expected); + } + } + + #[test] + fn test_level_case_insensitive() { + let cases = [ + (Level::Error, [level_token("error")]), + (Level::Warn, [level_token("warn")]), + (Level::Info, [level_token("info")]), + (Level::Debug, [level_token("debug")]), + (Level::Trace, [level_token("trace")]), + ]; + + for &(s, expected) in &cases { + assert_de_tokens(&s, &expected); + } + } + + #[test] + fn test_level_de_bytes() { + let cases = [ + (Level::Error, level_bytes_tokens(b"ERROR")), + (Level::Warn, level_bytes_tokens(b"WARN")), + (Level::Info, level_bytes_tokens(b"INFO")), + (Level::Debug, level_bytes_tokens(b"DEBUG")), + (Level::Trace, level_bytes_tokens(b"TRACE")), + ]; + + for &(value, tokens) in &cases { + assert_de_tokens(&value, &tokens); + } + } + + #[test] + fn test_level_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::(&[level_token("errorx")], msg); + } + + #[test] + fn test_level_filter_ser_de() { + let cases = [ + (LevelFilter::Off, [level_filter_token("OFF")]), + (LevelFilter::Error, [level_filter_token("ERROR")]), + (LevelFilter::Warn, [level_filter_token("WARN")]), + (LevelFilter::Info, [level_filter_token("INFO")]), + (LevelFilter::Debug, [level_filter_token("DEBUG")]), + (LevelFilter::Trace, [level_filter_token("TRACE")]), + ]; + + for &(s, expected) in &cases { + assert_tokens(&s, &expected); + } + } + + #[test] + fn test_level_filter_case_insensitive() { + let cases = [ + (LevelFilter::Off, [level_filter_token("off")]), + (LevelFilter::Error, [level_filter_token("error")]), + (LevelFilter::Warn, [level_filter_token("warn")]), + (LevelFilter::Info, [level_filter_token("info")]), + (LevelFilter::Debug, [level_filter_token("debug")]), + (LevelFilter::Trace, [level_filter_token("trace")]), + ]; + + for &(s, expected) in &cases { + assert_de_tokens(&s, &expected); + } + } + + #[test] + fn test_level_filter_de_bytes() { + let cases = [ + (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")), + (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")), + (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")), + (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")), + (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")), + (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")), + ]; + + for &(value, tokens) in &cases { + assert_de_tokens(&value, &tokens); + } + } + + #[test] + fn test_level_filter_de_error() { + let msg = "unknown variant `errorx`, expected one of \ + `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; + assert_de_tokens_error::(&[level_filter_token("errorx")], msg); + } +} diff --git a/log/tests/filters.rs b/log/tests/filters.rs new file mode 100644 index 000000000..84449ccfe --- /dev/null +++ b/log/tests/filters.rs @@ -0,0 +1,66 @@ +#[macro_use] +extern crate log; + +use std::sync::{Arc, Mutex}; +use log::{Level, LevelFilter, Log, Record, Metadata}; + +#[cfg(feature = "std")] +use log::set_boxed_logger; + +#[cfg(not(feature = "std"))] +fn set_boxed_logger(logger: Box) -> Result<(), log::SetLoggerError> { + log::set_logger(unsafe { &*Box::into_raw(logger) }) +} + +struct State { + last_log: Mutex>, +} + +struct Logger(Arc); + +impl Log for Logger { + fn enabled(&self, _: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + *self.0.last_log.lock().unwrap() = Some(record.level()); + } + fn flush(&self) {} +} + +fn main() { + let me = Arc::new(State { last_log: Mutex::new(None) }); + let a = me.clone(); + set_boxed_logger(Box::new(Logger(me))).unwrap(); + + test(&a, LevelFilter::Off); + test(&a, LevelFilter::Error); + test(&a, LevelFilter::Warn); + test(&a, LevelFilter::Info); + test(&a, LevelFilter::Debug); + test(&a, LevelFilter::Trace); +} + +fn test(a: &State, filter: LevelFilter) { + log::set_max_level(filter); + error!(""); + last(&a, t(Level::Error, filter)); + warn!(""); + last(&a, t(Level::Warn, filter)); + info!(""); + last(&a, t(Level::Info, filter)); + debug!(""); + last(&a, t(Level::Debug, filter)); + trace!(""); + last(&a, t(Level::Trace, filter)); + + fn t(lvl: Level, filter: LevelFilter) -> Option { + if lvl <= filter { Some(lvl) } else { None } + } +} + +fn last(state: &State, expected: Option) { + let lvl = state.last_log.lock().unwrap().take(); + assert_eq!(lvl, expected); +} diff --git a/matches/.cargo-checksum.json b/matches/.cargo-checksum.json new file mode 100644 index 000000000..74e888a80 --- /dev/null +++ b/matches/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"} \ No newline at end of file diff --git a/matches/Cargo.toml b/matches/Cargo.toml new file mode 100644 index 000000000..030159e73 --- /dev/null +++ b/matches/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "matches" +version = "0.1.8" +authors = ["Simon Sapin "] +description = "A macro to evaluate, as a boolean, whether an expression matches a pattern." +documentation = "https://docs.rs/matches/" +license = "MIT" +repository = "https://github.com/SimonSapin/rust-std-candidates" + +[lib] +name = "matches" +path = "lib.rs" diff --git a/matches/LICENSE b/matches/LICENSE new file mode 100644 index 000000000..a7b759a49 --- /dev/null +++ b/matches/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2014-2016 Simon Sapin + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/matches/lib.rs b/matches/lib.rs new file mode 100644 index 000000000..b183925fb --- /dev/null +++ b/matches/lib.rs @@ -0,0 +1,126 @@ +/// Check if an expression matches a refutable pattern. +/// +/// Syntax: `matches!(` *expression* `,` *pattern* `)` +/// +/// Return a boolean, true if the expression matches the pattern, false otherwise. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate matches; +/// +/// pub enum Foo { +/// A, +/// B(T), +/// } +/// +/// impl Foo { +/// pub fn is_a(&self) -> bool { +/// matches!(*self, Foo::A) +/// } +/// +/// pub fn is_b(&self) -> bool { +/// matches!(*self, Foo::B(_)) +/// } +/// } +/// +/// # fn main() { } +/// ``` +#[macro_export] +macro_rules! matches { + ($expression:expr, $($pattern:tt)+) => { + match $expression { + $($pattern)+ => true, + _ => false + } + } +} + +/// Assert that an expression matches a refutable pattern. +/// +/// Syntax: `assert_matches!(` *expression* `,` *pattern* `)` +/// +/// Panic with a message that shows the expression if it does not match the +/// pattern. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate matches; +/// +/// fn main() { +/// let data = [1, 2, 3]; +/// assert_matches!(data.get(1), Some(_)); +/// } +/// ``` +#[macro_export] +macro_rules! assert_matches { + ($expression:expr, $($pattern:tt)+) => { + match $expression { + $($pattern)+ => (), + ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)), + } + } +} + +/// Assert that an expression matches a refutable pattern using debug assertions. +/// +/// Syntax: `debug_assert_matches!(` *expression* `,` *pattern* `)` +/// +/// If debug assertions are enabled, panic with a message that shows the +/// expression if it does not match the pattern. +/// +/// When debug assertions are not enabled, this macro does nothing. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate matches; +/// +/// fn main() { +/// let data = [1, 2, 3]; +/// debug_assert_matches!(data.get(1), Some(_)); +/// } +/// ``` +#[macro_export] +macro_rules! debug_assert_matches { + ($expression:expr, $($pattern:tt)+) => { + if cfg!(debug_assertions) { + match $expression { + $($pattern)+ => (), + ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($pattern)+)), + } + } + } +} + +#[test] +fn matches_works() { + let foo = Some("-12"); + assert!(matches!(foo, Some(bar) if + matches!(bar.as_bytes()[0], b'+' | b'-') && + matches!(bar.as_bytes()[1], b'0'...b'9') + )); +} + +#[test] +fn assert_matches_works() { + let foo = Some("-12"); + assert_matches!(foo, Some(bar) if + matches!(bar.as_bytes()[0], b'+' | b'-') && + matches!(bar.as_bytes()[1], b'0'...b'9') + ); +} + +#[test] +#[should_panic(expected = "assertion failed: `Some(\"-AB\")` does not match ")] +fn assert_matches_panics() { + let foo = Some("-AB"); + assert_matches!(foo, Some(bar) if + matches!(bar.as_bytes()[0], b'+' | b'-') && + matches!(bar.as_bytes()[1], b'0'...b'9') + ); +} diff --git a/matches/tests/macro_use_one.rs b/matches/tests/macro_use_one.rs new file mode 100644 index 000000000..a527a89ce --- /dev/null +++ b/matches/tests/macro_use_one.rs @@ -0,0 +1,11 @@ +// https://github.com/SimonSapin/rust-std-candidates/issues/12 +#[macro_use(matches)] extern crate matches; + +#[test] +fn matches_works() { + let foo = Some("-12"); + assert!(matches!(foo, Some(bar) if + matches!(bar.as_bytes()[0], b'+' | b'-') && + matches!(bar.as_bytes()[1], b'0'...b'9') + )); +} diff --git a/memchr/.cargo-checksum.json b/memchr/.cargo-checksum.json new file mode 100644 index 000000000..09eb3f869 --- /dev/null +++ b/memchr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"} \ No newline at end of file diff --git a/memchr/COPYING b/memchr/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/memchr/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/memchr/Cargo.toml b/memchr/Cargo.toml new file mode 100644 index 000000000..e918f9e16 --- /dev/null +++ b/memchr/Cargo.toml @@ -0,0 +1,46 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "memchr" +version = "2.2.0" +authors = ["Andrew Gallant ", "bluss"] +exclude = ["/ci/*", "/.travis.yml", "/Makefile", "/appveyor.yml"] +description = "Safe interface to memchr." +homepage = "https://github.com/BurntSushi/rust-memchr" +documentation = "https://docs.rs/memchr/" +readme = "README.md" +keywords = ["memchr", "char", "scan", "strchr", "string"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/rust-memchr" +[profile.test] +opt-level = 3 + +[lib] +name = "memchr" +bench = false +[dependencies.libc] +version = "0.2.18" +optional = true +default-features = false +[dev-dependencies.quickcheck] +version = "0.8" +default-features = false + +[features] +default = ["use_std"] +use_std = [] +[badges.appveyor] +repository = "BurntSushi/rust-memchr" + +[badges.travis-ci] +repository = "BurntSushi/rust-memchr" diff --git a/memchr/LICENSE-MIT b/memchr/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/memchr/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/memchr/README.md b/memchr/README.md new file mode 100644 index 000000000..3e7ff3333 --- /dev/null +++ b/memchr/README.md @@ -0,0 +1,50 @@ +memchr +====== +The `memchr` crate provides heavily optimized routines for searching bytes. + +[![Build status](https://api.travis-ci.org/BurntSushi/rust-memchr.png)](https://travis-ci.org/BurntSushi/rust-memchr) +[![Build status](https://ci.appveyor.com/api/projects/status/8i9484t8l4w7uql0/branch/master?svg=true)](https://ci.appveyor.com/project/BurntSushi/rust-memchr/branch/master) +[![](http://meritbadge.herokuapp.com/memchr)](https://crates.io/crates/memchr) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +[https://docs.rs/memchr](https://docs.rs/memchr) + + +### Overview + +The `memchr` function is traditionally provided by libc, however, the +performance of `memchr` can vary significantly depending on the specific +implementation of libc that is used. They can range from manually tuned +Assembly implementations (like that found in GNU's libc) all the way to +non-vectorized C implementations (like that found in MUSL). + +To smooth out the differences between implementations of libc, at least +on `x86_64` for Rust 1.27+, this crate provides its own implementation of +`memchr` that should perform competitively with the one found in GNU's libc. +The implementation is in pure Rust and has no dependency on a C compiler or an +Assembler. + +Additionally, GNU libc also provides an extension, `memrchr`. This crate +provides its own implementation of `memrchr` as well, on top of `memchr2`, +`memchr3`, `memrchr2` and `memrchr3`. The difference between `memchr` and +`memchr2` is that that `memchr2` permits finding all occurrences of two bytes +instead of one. Similarly for `memchr3`. + +### Compiling without the standard library + +memchr links to the standard library by default, but you can disable the +`use_std` feature if you want to use it in a `#![no_std]` crate: + +```toml +[dependencies] +memchr = { version = "2", default-features = false } +``` + +On x86 platforms, when the `use_std` feature is disabled, the SSE2 +implementation of memchr will be used in compilers that support it. When +`use_std` is enabled, the AVX implementation of memchr will be used if the CPU +is determined to support it at runtime. diff --git a/memchr/UNLICENSE b/memchr/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/memchr/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/memchr/build.rs b/memchr/build.rs new file mode 100644 index 000000000..35f06f969 --- /dev/null +++ b/memchr/build.rs @@ -0,0 +1,134 @@ +use std::env; +use std::ffi::OsString; +use std::process::Command; + +fn main() { + let version = match Version::read() { + Ok(version) => version, + Err(err) => { + eprintln!("failed to parse `rustc --version`: {}", err); + return; + } + }; + enable_simd_optimizations(version); + enable_libc(); +} + +// This adds various simd cfgs if this compiler supports it. +// +// This can be disabled with RUSTFLAGS="--cfg memchr_disable_auto_simd", but +// this is generally only intended for testing. +fn enable_simd_optimizations(version: Version) { + if is_env_set("CARGO_CFG_MEMCHR_DISABLE_AUTO_SIMD") { + return; + } + if version < (Version { major: 1, minor: 27, patch: 0 }) { + return; + } + + println!("cargo:rustc-cfg=memchr_runtime_simd"); + println!("cargo:rustc-cfg=memchr_runtime_sse2"); + println!("cargo:rustc-cfg=memchr_runtime_sse42"); + println!("cargo:rustc-cfg=memchr_runtime_avx"); +} + +// This adds a `memchr_libc` cfg if and only if libc can be used, if no other +// better option is available. +// +// This could be performed in the source code, but it's simpler to do it once +// here and consolidate it into one cfg knob. +// +// Basically, we use libc only if its enabled and if we aren't targeting a +// known bad platform. For example, wasm32 doesn't have a libc and the +// performance of memchr on Windows is seemingly worse than the fallback +// implementation. +fn enable_libc() { + const NO_ARCH: &'static [&'static str] = &["wasm32", "windows"]; + const NO_ENV: &'static [&'static str] = &["sgx"]; + + if !is_feature_set("LIBC") { + return; + } + + let arch = match env::var("CARGO_CFG_TARGET_ARCH") { + Err(_) => return, + Ok(arch) => arch, + }; + let env = match env::var("CARGO_CFG_TARGET_ENV") { + Err(_) => return, + Ok(env) => env, + }; + if NO_ARCH.contains(&&*arch) || NO_ENV.contains(&&*env) { + return; + } + + println!("cargo:rustc-cfg=memchr_libc"); +} + +fn is_feature_set(name: &str) -> bool { + is_env_set(&format!("CARGO_FEATURE_{}", name)) +} + +fn is_env_set(name: &str) -> bool { + env::var_os(name).is_some() +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +struct Version { + major: u32, + minor: u32, + patch: u32, +} + +impl Version { + fn read() -> Result { + let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); + let output = Command::new(&rustc) + .arg("--version") + .output() + .unwrap() + .stdout; + Version::parse(&String::from_utf8(output).unwrap()) + } + + fn parse(mut s: &str) -> Result { + if !s.starts_with("rustc ") { + return Err(format!("unrecognized version string: {}", s)); + } + s = &s["rustc ".len()..]; + + let parts: Vec<&str> = s.split(".").collect(); + if parts.len() < 3 { + return Err(format!("not enough version parts: {:?}", parts)); + } + + let mut num = String::new(); + for c in parts[0].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let major = num.parse::().map_err(|e| e.to_string())?; + + num.clear(); + for c in parts[1].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let minor = num.parse::().map_err(|e| e.to_string())?; + + num.clear(); + for c in parts[2].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let patch = num.parse::().map_err(|e| e.to_string())?; + + Ok(Version { major, minor, patch }) + } +} diff --git a/memchr/src/c.rs b/memchr/src/c.rs new file mode 100644 index 000000000..63feca979 --- /dev/null +++ b/memchr/src/c.rs @@ -0,0 +1,44 @@ +// This module defines safe wrappers around memchr (POSIX) and memrchr (GNU +// extension). + +#![allow(dead_code)] + +extern crate libc; + +use self::libc::{c_int, c_void, size_t}; + +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const c_void, + needle as c_int, + haystack.len() as size_t, + ) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } +} + +// memrchr is a GNU extension. We know it's available on Linux, so start there. +#[cfg(target_os = "linux")] +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + // GNU's memrchr() will - unlike memchr() - error if haystack is empty. + if haystack.is_empty() { + return None; + } + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const c_void, + needle as c_int, + haystack.len() as size_t, + ) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } +} diff --git a/memchr/src/fallback.rs b/memchr/src/fallback.rs new file mode 100644 index 000000000..3fcfc898b --- /dev/null +++ b/memchr/src/fallback.rs @@ -0,0 +1,346 @@ +// This module defines pure Rust platform independent implementations of all +// the memchr routines. We do our best to make them fast. Some of them may even +// get auto-vectorized. + +use core::cmp; +use core::ptr; +use core::usize; + +#[cfg(target_pointer_width = "32")] +const USIZE_BYTES: usize = 4; + +#[cfg(target_pointer_width = "64")] +const USIZE_BYTES: usize = 8; + +// The number of bytes to loop at in one iteration of memchr/memrchr. +const LOOP_SIZE: usize = 2 * USIZE_BYTES; + +/// Return `true` if `x` contains any zero byte. +/// +/// From *Matters Computational*, J. Arndt +/// +/// "The idea is to subtract one from each of the bytes and then look for +/// bytes where the borrow propagated all the way to the most significant +/// bit." +#[inline(always)] +fn contains_zero_byte(x: usize) -> bool { + const LO_U64: u64 = 0x0101010101010101; + const HI_U64: u64 = 0x8080808080808080; + + const LO_USIZE: usize = LO_U64 as usize; + const HI_USIZE: usize = HI_U64 as usize; + + x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 +} + +/// Repeat the given byte into a word size number. That is, every 8 bits +/// is equivalent to the given byte. For example, if `b` is `\x4E` or +/// `01001110` in binary, then the returned value on a 32-bit system would be: +/// `01001110_01001110_01001110_01001110`. +#[inline(always)] +fn repeat_byte(b: u8) -> usize { + (b as usize) * (usize::MAX / 255) +} + +pub fn memchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let confirm = |byte| byte == n1; + let loop_size = cmp::min(LOOP_SIZE, haystack.len()); + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr); + if contains_zero_byte(chunk ^ vn1) { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = ptr_add(ptr, USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(ptr_sub(end_ptr, USIZE_BYTES) >= start_ptr); + while loop_size == LOOP_SIZE && ptr <= ptr_sub(end_ptr, loop_size) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr as *const usize); + let b = *(ptr_add(ptr, USIZE_BYTES) as *const usize); + let eqa = contains_zero_byte(a ^ vn1); + let eqb = contains_zero_byte(b ^ vn1); + if eqa || eqb { + break; + } + ptr = ptr_add(ptr, LOOP_SIZE); + } + forward_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Like `memchr`, but searches for two bytes instead of one. +pub fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let vn2 = repeat_byte(n2); + let confirm = |byte| byte == n1 || byte == n2; + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + if eq1 || eq2 { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = ptr_add(ptr, USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(ptr_sub(end_ptr, USIZE_BYTES) >= start_ptr); + while ptr <= ptr_sub(end_ptr, USIZE_BYTES) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let chunk = *(ptr as *const usize); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + if eq1 || eq2 { + break; + } + ptr = ptr_add(ptr, USIZE_BYTES); + } + forward_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Like `memchr`, but searches for three bytes instead of one. +pub fn memchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let vn2 = repeat_byte(n2); + let vn3 = repeat_byte(n3); + let confirm = |byte| byte == n1 || byte == n2 || byte == n3; + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + let eq3 = contains_zero_byte(chunk ^ vn3); + if eq1 || eq2 || eq3 { + return forward_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = ptr_add(ptr, USIZE_BYTES - (start_ptr as usize & align)); + debug_assert!(ptr > start_ptr); + debug_assert!(ptr_sub(end_ptr, USIZE_BYTES) >= start_ptr); + while ptr <= ptr_sub(end_ptr, USIZE_BYTES) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let chunk = *(ptr as *const usize); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + let eq3 = contains_zero_byte(chunk ^ vn3); + if eq1 || eq2 || eq3 { + break; + } + ptr = ptr_add(ptr, USIZE_BYTES); + } + forward_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Return the last index matching the byte `x` in `text`. +pub fn memrchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let confirm = |byte| byte == n1; + let loop_size = cmp::min(LOOP_SIZE, haystack.len()); + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr_sub(ptr, USIZE_BYTES)); + if contains_zero_byte(chunk ^ vn1) { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = (end_ptr as usize & !align) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE && ptr >= ptr_add(start_ptr, loop_size) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let a = *(ptr_sub(ptr, 2 * USIZE_BYTES) as *const usize); + let b = *(ptr_sub(ptr, 1 * USIZE_BYTES) as *const usize); + let eqa = contains_zero_byte(a ^ vn1); + let eqb = contains_zero_byte(b ^ vn1); + if eqa || eqb { + break; + } + ptr = ptr_sub(ptr, loop_size); + } + reverse_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Like `memrchr`, but searches for two bytes instead of one. +pub fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let vn2 = repeat_byte(n2); + let confirm = |byte| byte == n1 || byte == n2; + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr_sub(ptr, USIZE_BYTES)); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + if eq1 || eq2 { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = (end_ptr as usize & !align) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while ptr >= ptr_add(start_ptr, USIZE_BYTES) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let chunk = *(ptr_sub(ptr, USIZE_BYTES) as *const usize); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + if eq1 || eq2 { + break; + } + ptr = ptr_sub(ptr, USIZE_BYTES); + } + reverse_search(start_ptr, end_ptr, ptr, confirm) + } +} + +/// Like `memrchr`, but searches for three bytes instead of one. +pub fn memrchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + let vn1 = repeat_byte(n1); + let vn2 = repeat_byte(n2); + let vn3 = repeat_byte(n3); + let confirm = |byte| byte == n1 || byte == n2 || byte == n3; + let align = USIZE_BYTES - 1; + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + unsafe { + if haystack.len() < USIZE_BYTES { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + let chunk = read_unaligned_usize(ptr_sub(ptr, USIZE_BYTES)); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + let eq3 = contains_zero_byte(chunk ^ vn3); + if eq1 || eq2 || eq3 { + return reverse_search(start_ptr, end_ptr, ptr, confirm); + } + + ptr = (end_ptr as usize & !align) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while ptr >= ptr_add(start_ptr, USIZE_BYTES) { + debug_assert_eq!(0, (ptr as usize) % USIZE_BYTES); + + let chunk = *(ptr_sub(ptr, USIZE_BYTES) as *const usize); + let eq1 = contains_zero_byte(chunk ^ vn1); + let eq2 = contains_zero_byte(chunk ^ vn2); + let eq3 = contains_zero_byte(chunk ^ vn3); + if eq1 || eq2 || eq3 { + break; + } + ptr = ptr_sub(ptr, USIZE_BYTES); + } + reverse_search(start_ptr, end_ptr, ptr, confirm) + } +} + +#[inline(always)] +unsafe fn forward_search bool>( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, + confirm: F, +) -> Option { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr < end_ptr { + if confirm(*ptr) { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + None +} + +#[inline(always)] +unsafe fn reverse_search bool>( + start_ptr: *const u8, + end_ptr: *const u8, + mut ptr: *const u8, + confirm: F, +) -> Option { + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr); + + while ptr > start_ptr { + ptr = ptr.offset(-1); + if confirm(*ptr) { + return Some(sub(ptr, start_ptr)); + } + } + None +} + +/// Increment the given pointer by the given amount. +unsafe fn ptr_add(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset(amt as isize) +} + +/// Decrement the given pointer by the given amount. +unsafe fn ptr_sub(ptr: *const u8, amt: usize) -> *const u8 { + debug_assert!(amt < ::core::isize::MAX as usize); + ptr.offset((amt as isize).wrapping_neg()) +} + +unsafe fn read_unaligned_usize(ptr: *const u8) -> usize { + let mut n: usize = 0; + ptr::copy_nonoverlapping(ptr, &mut n as *mut _ as *mut u8, USIZE_BYTES); + n +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} diff --git a/memchr/src/iter.rs b/memchr/src/iter.rs new file mode 100644 index 000000000..0ee5f86a8 --- /dev/null +++ b/memchr/src/iter.rs @@ -0,0 +1,177 @@ +use {memchr, memchr2, memchr3, memrchr, memrchr2, memrchr3}; + +macro_rules! iter_next { + // Common code for the memchr iterators: + // update haystack and position and produce the index + // + // self: &mut Self where Self is the iterator + // search_result: Option which is the result of the corresponding + // memchr function. + // + // Returns Option (the next iterator element) + ($self_:expr, $search_result:expr) => { + $search_result.map(move |index| { + // split and take the remaining back half + $self_.haystack = $self_.haystack.split_at(index + 1).1; + let found_position = $self_.position + index; + $self_.position = found_position + 1; + found_position + }) + } +} + +macro_rules! iter_next_back { + ($self_:expr, $search_result:expr) => { + $search_result.map(move |index| { + // split and take the remaining front half + $self_.haystack = $self_.haystack.split_at(index).0; + $self_.position + index + }) + } +} + +/// An iterator for `memchr`. +pub struct Memchr<'a> { + needle: u8, + // The haystack to iterate over + haystack: &'a [u8], + // The index + position: usize, +} + +impl<'a> Memchr<'a> { + /// Creates a new iterator that yields all positions of needle in haystack. + #[inline] + pub fn new(needle: u8, haystack: &[u8]) -> Memchr { + Memchr { + needle: needle, + haystack: haystack, + position: 0, + } + } +} + +impl<'a> Iterator for Memchr<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + iter_next!(self, memchr(self.needle, self.haystack)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.haystack.len())) + } +} + +impl<'a> DoubleEndedIterator for Memchr<'a> { + #[inline] + fn next_back(&mut self) -> Option { + iter_next_back!(self, memrchr(self.needle, self.haystack)) + } +} + +/// An iterator for `memchr2`. +pub struct Memchr2<'a> { + needle1: u8, + needle2: u8, + // The haystack to iterate over + haystack: &'a [u8], + // The index + position: usize, +} + +impl<'a> Memchr2<'a> { + /// Creates a new iterator that yields all positions of needle in haystack. + #[inline] + pub fn new(needle1: u8, needle2: u8, haystack: &[u8]) -> Memchr2 { + Memchr2 { + needle1: needle1, + needle2: needle2, + haystack: haystack, + position: 0, + } + } +} + +impl<'a> Iterator for Memchr2<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + iter_next!(self, memchr2(self.needle1, self.needle2, self.haystack)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.haystack.len())) + } +} + +impl<'a> DoubleEndedIterator for Memchr2<'a> { + #[inline] + fn next_back(&mut self) -> Option { + iter_next_back!( + self, + memrchr2(self.needle1, self.needle2, self.haystack) + ) + } +} + +/// An iterator for `memchr3`. +pub struct Memchr3<'a> { + needle1: u8, + needle2: u8, + needle3: u8, + // The haystack to iterate over + haystack: &'a [u8], + // The index + position: usize, +} + +impl<'a> Memchr3<'a> { + /// Create a new `Memchr3` that's initialized to zero with a haystack + #[inline] + pub fn new( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], + ) -> Memchr3 { + Memchr3 { + needle1: needle1, + needle2: needle2, + needle3: needle3, + haystack: haystack, + position: 0, + } + } +} + +impl<'a> Iterator for Memchr3<'a> { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + iter_next!( + self, + memchr3(self.needle1, self.needle2, self.needle3, self.haystack) + ) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.haystack.len())) + } +} + +impl<'a> DoubleEndedIterator for Memchr3<'a> { + #[inline] + fn next_back(&mut self) -> Option { + iter_next_back!( + self, + memrchr3(self.needle1, self.needle2, self.needle3, self.haystack) + ) + } +} diff --git a/memchr/src/lib.rs b/memchr/src/lib.rs new file mode 100644 index 000000000..b828475f5 --- /dev/null +++ b/memchr/src/lib.rs @@ -0,0 +1,312 @@ +/*! +The `memchr` crate provides heavily optimized routines for searching bytes. + +The `memchr` function is traditionally provided by libc, however, the +performance of `memchr` can vary significantly depending on the specific +implementation of libc that is used. They can range from manually tuned +Assembly implementations (like that found in GNU's libc) all the way to +non-vectorized C implementations (like that found in MUSL). + +To smooth out the differences between implementations of libc, at least +on `x86_64` for Rust 1.27+, this crate provides its own implementation of +`memchr` that should perform competitively with the one found in GNU's libc. +The implementation is in pure Rust and has no dependency on a C compiler or an +Assembler. + +Additionally, GNU libc also provides an extension, `memrchr`. This crate +provides its own implementation of `memrchr` as well, on top of `memchr2`, +`memchr3`, `memrchr2` and `memrchr3`. The difference between `memchr` and +`memchr2` is that that `memchr2` permits finding all occurrences of two bytes +instead of one. Similarly for `memchr3`. +*/ + +#![cfg_attr(not(feature = "use_std"), no_std)] + +#![deny(missing_docs)] +#![doc(html_root_url = "https://docs.rs/memchr/2.0.0")] + +// Supporting 16-bit would be fine. If you need it, please submit a bug report +// at https://github.com/BurntSushi/rust-memchr +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("memchr currently not supported on non-32 or non-64 bit"); + +#[cfg(feature = "use_std")] +extern crate core; + +#[cfg(test)] +#[macro_use] +extern crate quickcheck; + +use core::iter::Rev; + +pub use iter::{Memchr, Memchr2, Memchr3}; + +// N.B. If you're looking for the cfg knobs for libc, see build.rs. +#[cfg(memchr_libc)] +mod c; +#[allow(dead_code)] +mod fallback; +mod iter; +mod naive; +#[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] +mod x86; +#[cfg(test)] +mod tests; + +/// An iterator over all occurrences of the needle in a haystack. +#[inline] +pub fn memchr_iter(needle: u8, haystack: &[u8]) -> Memchr { + Memchr::new(needle, haystack) +} + +/// An iterator over all occurrences of the needles in a haystack. +#[inline] +pub fn memchr2_iter( + needle1: u8, + needle2: u8, + haystack: &[u8], +) -> Memchr2 { + Memchr2::new(needle1, needle2, haystack) +} + +/// An iterator over all occurrences of the needles in a haystack. +#[inline] +pub fn memchr3_iter( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Memchr3 { + Memchr3::new(needle1, needle2, needle3, haystack) +} + +/// An iterator over all occurrences of the needle in a haystack, in reverse. +#[inline] +pub fn memrchr_iter(needle: u8, haystack: &[u8]) -> Rev { + Memchr::new(needle, haystack).rev() +} + +/// An iterator over all occurrences of the needles in a haystack, in reverse. +#[inline] +pub fn memrchr2_iter( + needle1: u8, + needle2: u8, + haystack: &[u8], +) -> Rev { + Memchr2::new(needle1, needle2, haystack).rev() +} + +/// An iterator over all occurrences of the needles in a haystack, in reverse. +#[inline] +pub fn memrchr3_iter( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Rev { + Memchr3::new(needle1, needle2, needle3, haystack).rev() +} + +/// Search for the first occurrence of a byte in a slice. +/// +/// This returns the index corresponding to the first occurrence of `needle` in +/// `haystack`, or `None` if one is not found. +/// +/// While this is operationally the same as something like +/// `haystack.iter().position(|&b| b == needle)`, `memchr` will use a highly +/// optimized routine that can be up to an order of magnitude faster in some +/// cases. +/// +/// # Example +/// +/// This shows how to find the first position of a byte in a byte string. +/// +/// ``` +/// use memchr::memchr; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memchr(b'k', haystack), Some(8)); +/// ``` +#[inline] +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + x86::memchr(n1, haystack) + } + + #[cfg(all( + memchr_libc, + not(all(target_arch = "x86_64", memchr_runtime_simd)) + ))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + c::memchr(n1, haystack) + } + + #[cfg(all( + not(memchr_libc), + not(all(target_arch = "x86_64", memchr_runtime_simd)) + ))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + fallback::memchr(n1, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle, haystack) + } +} + +/// Like `memchr`, but searches for two bytes instead of one. +#[inline] +pub fn memchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, n2: u8, haystack: &[u8]) -> Option { + x86::memchr2(n1, n2, haystack) + } + + #[cfg(not(all(target_arch = "x86_64", memchr_runtime_simd)))] + #[inline(always)] + fn imp(n1: u8, n2: u8, haystack: &[u8]) -> Option { + fallback::memchr2(n1, n2, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle1, needle2, haystack) + } +} + +/// Like `memchr`, but searches for three bytes instead of one. +#[inline] +pub fn memchr3( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + x86::memchr3(n1, n2, n3, haystack) + } + + #[cfg(not(all(target_arch = "x86_64", memchr_runtime_simd)))] + #[inline(always)] + fn imp(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + fallback::memchr3(n1, n2, n3, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle1, needle2, needle3, haystack) + } +} + +/// Search for the last occurrence of a byte in a slice. +/// +/// This returns the index corresponding to the last occurrence of `needle` in +/// `haystack`, or `None` if one is not found. +/// +/// While this is operationally the same as something like +/// `haystack.iter().rposition(|&b| b == needle)`, `memrchr` will use a highly +/// optimized routine that can be up to an order of magnitude faster in some +/// cases. +/// +/// # Example +/// +/// This shows how to find the last position of a byte in a byte string. +/// +/// ``` +/// use memchr::memrchr; +/// +/// let haystack = b"the quick brown fox"; +/// assert_eq!(memrchr(b'o', haystack), Some(17)); +/// ``` +#[inline] +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + x86::memrchr(n1, haystack) + } + + #[cfg(all( + all(memchr_libc, target_os = "linux"), + not(all(target_arch = "x86_64", memchr_runtime_simd)) + ))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + c::memrchr(n1, haystack) + } + + #[cfg(all( + not(all(memchr_libc, target_os = "linux")), + not(all(target_arch = "x86_64", memchr_runtime_simd)) + ))] + #[inline(always)] + fn imp(n1: u8, haystack: &[u8]) -> Option { + fallback::memrchr(n1, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle, haystack) + } +} + +/// Like `memrchr`, but searches for two bytes instead of one. +#[inline] +pub fn memrchr2(needle1: u8, needle2: u8, haystack: &[u8]) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, n2: u8, haystack: &[u8]) -> Option { + x86::memrchr2(n1, n2, haystack) + } + + #[cfg(not(all(target_arch = "x86_64", memchr_runtime_simd)))] + #[inline(always)] + fn imp(n1: u8, n2: u8, haystack: &[u8]) -> Option { + fallback::memrchr2(n1, n2, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle1, needle2, haystack) + } +} + +/// Like `memrchr`, but searches for three bytes instead of one. +#[inline] +pub fn memrchr3( + needle1: u8, + needle2: u8, + needle3: u8, + haystack: &[u8], +) -> Option { + #[cfg(all(target_arch = "x86_64", memchr_runtime_simd))] + #[inline(always)] + fn imp(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + x86::memrchr3(n1, n2, n3, haystack) + } + + #[cfg(not(all(target_arch = "x86_64", memchr_runtime_simd)))] + #[inline(always)] + fn imp(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + fallback::memrchr3(n1, n2, n3, haystack) + } + + if haystack.is_empty() { + None + } else { + imp(needle1, needle2, needle3, haystack) + } +} diff --git a/memchr/src/naive.rs b/memchr/src/naive.rs new file mode 100644 index 000000000..68cecf02a --- /dev/null +++ b/memchr/src/naive.rs @@ -0,0 +1,37 @@ +#![allow(dead_code)] + +pub fn memchr(n1: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .position(|&b| b == n1) +} + +pub fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .position(|&b| b == n1 || b == n2) +} + +pub fn memchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .position(|&b| b == n1 || b == n2 || b == n3) +} + +pub fn memrchr(n1: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .rposition(|&b| b == n1) +} + +pub fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .rposition(|&b| b == n1 || b == n2) +} + +pub fn memrchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + haystack + .iter() + .rposition(|&b| b == n1 || b == n2 || b == n3) +} diff --git a/memchr/src/tests/iter.rs b/memchr/src/tests/iter.rs new file mode 100644 index 000000000..33c85652c --- /dev/null +++ b/memchr/src/tests/iter.rs @@ -0,0 +1,228 @@ +use tests::memchr_tests; +use {Memchr, Memchr2, Memchr3}; + +#[test] +fn memchr1_iter() { + for test in memchr_tests() { + test.iter_one(false, Memchr::new); + } +} + +#[test] +fn memchr2_iter() { + for test in memchr_tests() { + test.iter_two(false, Memchr2::new); + } +} + +#[test] +fn memchr3_iter() { + for test in memchr_tests() { + test.iter_three(false, Memchr3::new); + } +} + +#[test] +fn memrchr1_iter() { + for test in memchr_tests() { + test.iter_one(true, |n1, corpus| Memchr::new(n1, corpus).rev()); + } +} + +#[test] +fn memrchr2_iter() { + for test in memchr_tests() { + test.iter_two(true, |n1, n2, corpus| { + Memchr2::new(n1, n2, corpus).rev() + }) + } +} + +#[test] +fn memrchr3_iter() { + for test in memchr_tests() { + test.iter_three(true, |n1, n2, n3, corpus| { + Memchr3::new(n1, n2, n3, corpus).rev() + }) + } +} + +quickcheck! { + fn qc_memchr_double_ended_iter( + needle: u8, data: Vec, take_side: Vec + ) -> bool { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let iter = Memchr::new(needle, &data); + let all_found = double_ended_take( + iter, take_side.iter().cycle().cloned()); + + all_found.iter().cloned().eq(positions1(needle, &data)) + } + + fn qc_memchr2_double_ended_iter( + needle1: u8, needle2: u8, data: Vec, take_side: Vec + ) -> bool { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let iter = Memchr2::new(needle1, needle2, &data); + let all_found = double_ended_take( + iter, take_side.iter().cycle().cloned()); + + all_found.iter().cloned().eq(positions2(needle1, needle2, &data)) + } + + fn qc_memchr3_double_ended_iter( + needle1: u8, needle2: u8, needle3: u8, + data: Vec, take_side: Vec + ) -> bool { + // make nonempty + let mut take_side = take_side; + if take_side.is_empty() { take_side.push(true) }; + + let iter = Memchr3::new(needle1, needle2, needle3, &data); + let all_found = double_ended_take( + iter, take_side.iter().cycle().cloned()); + + all_found + .iter() + .cloned() + .eq(positions3(needle1, needle2, needle3, &data)) + } + + fn qc_memchr1_iter(data: Vec) -> bool { + let needle = 0; + let answer = positions1(needle, &data); + answer.eq(Memchr::new(needle, &data)) + } + + fn qc_memchr1_rev_iter(data: Vec) -> bool { + let needle = 0; + let answer = positions1(needle, &data); + answer.rev().eq(Memchr::new(needle, &data).rev()) + } + + fn qc_memchr2_iter(data: Vec) -> bool { + let needle1 = 0; + let needle2 = 1; + let answer = positions2(needle1, needle2, &data); + answer.eq(Memchr2::new(needle1, needle2, &data)) + } + + fn qc_memchr2_rev_iter(data: Vec) -> bool { + let needle1 = 0; + let needle2 = 1; + let answer = positions2(needle1, needle2, &data); + answer.rev().eq(Memchr2::new(needle1, needle2, &data).rev()) + } + + fn qc_memchr3_iter(data: Vec) -> bool { + let needle1 = 0; + let needle2 = 1; + let needle3 = 2; + let answer = positions3(needle1, needle2, needle3, &data); + answer.eq(Memchr3::new(needle1, needle2, needle3, &data)) + } + + fn qc_memchr3_rev_iter(data: Vec) -> bool { + let needle1 = 0; + let needle2 = 1; + let needle3 = 2; + let answer = positions3(needle1, needle2, needle3, &data); + answer.rev().eq(Memchr3::new(needle1, needle2, needle3, &data).rev()) + } + + fn qc_memchr1_iter_size_hint(data: Vec) -> bool { + // test that the size hint is within reasonable bounds + let needle = 0; + let mut iter = Memchr::new(needle, &data); + let mut real_count = data + .iter() + .filter(|&&elt| elt == needle) + .count(); + + while let Some(index) = iter.next() { + real_count -= 1; + let (lower, upper) = iter.size_hint(); + assert!(lower <= real_count); + assert!(upper.unwrap() >= real_count); + assert!(upper.unwrap() <= data.len() - index); + } + true + } +} + +// take items from a DEI, taking front for each true and back for each false. +// Return a vector with the concatenation of the fronts and the reverse of the +// backs. +fn double_ended_take(mut iter: I, take_side: J) -> Vec + where I: DoubleEndedIterator, + J: Iterator, +{ + let mut found_front = Vec::new(); + let mut found_back = Vec::new(); + + for take_front in take_side { + if take_front { + if let Some(pos) = iter.next() { + found_front.push(pos); + } else { + break; + } + } else { + if let Some(pos) = iter.next_back() { + found_back.push(pos); + } else { + break; + } + }; + } + + let mut all_found = found_front; + all_found.extend(found_back.into_iter().rev()); + all_found +} + +// return an iterator of the 0-based indices of haystack that match the needle +fn positions1<'a>( + n1: u8, + haystack: &'a [u8], +) -> Box + 'a> { + let it = haystack + .iter() + .enumerate() + .filter(move |&(_, &b)| b == n1) + .map(|t| t.0); + Box::new(it) +} + +fn positions2<'a>( + n1: u8, + n2: u8, + haystack: &'a [u8], +) -> Box + 'a> { + let it = haystack + .iter() + .enumerate() + .filter(move |&(_, &b)| b == n1 || b == n2) + .map(|t| t.0); + Box::new(it) +} + +fn positions3<'a>( + n1: u8, + n2: u8, + n3: u8, + haystack: &'a [u8], +) -> Box + 'a> { + let it = haystack + .iter() + .enumerate() + .filter(move |&(_, &b)| b == n1 || b == n2 || b == n3) + .map(|t| t.0); + Box::new(it) +} diff --git a/memchr/src/tests/memchr.rs b/memchr/src/tests/memchr.rs new file mode 100644 index 000000000..87d3d14ed --- /dev/null +++ b/memchr/src/tests/memchr.rs @@ -0,0 +1,131 @@ +use fallback; +use naive; +use {memchr, memchr2, memchr3, memrchr, memrchr2, memrchr3}; + +use tests::memchr_tests; + +#[test] +fn memchr1_find() { + for test in memchr_tests() { + test.one(false, memchr); + } +} + +#[test] +fn memchr1_fallback_find() { + for test in memchr_tests() { + test.one(false, fallback::memchr); + } +} + +#[test] +fn memchr2_find() { + for test in memchr_tests() { + test.two(false, memchr2); + } +} + +#[test] +fn memchr2_fallback_find() { + for test in memchr_tests() { + test.two(false, fallback::memchr2); + } +} + +#[test] +fn memchr3_find() { + for test in memchr_tests() { + test.three(false, memchr3); + } +} + +#[test] +fn memchr3_fallback_find() { + for test in memchr_tests() { + test.three(false, fallback::memchr3); + } +} + +#[test] +fn memrchr1_find() { + for test in memchr_tests() { + test.one(true, memrchr); + } +} + +#[test] +fn memrchr1_fallback_find() { + for test in memchr_tests() { + test.one(true, fallback::memrchr); + } +} + +#[test] +fn memrchr2_find() { + for test in memchr_tests() { + test.two(true, memrchr2); + } +} + +#[test] +fn memrchr2_fallback_find() { + for test in memchr_tests() { + test.two(true, fallback::memrchr2); + } +} + +#[test] +fn memrchr3_find() { + for test in memchr_tests() { + test.three(true, memrchr3); + } +} + +#[test] +fn memrchr3_fallback_find() { + for test in memchr_tests() { + test.three(true, fallback::memrchr3); + } +} + +quickcheck! { + fn qc_memchr1_matches_naive(n1: u8, corpus: Vec) -> bool { + memchr(n1, &corpus) == naive::memchr(n1, &corpus) + } +} + +quickcheck! { + fn qc_memchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> bool { + memchr2(n1, n2, &corpus) == naive::memchr2(n1, n2, &corpus) + } +} + +quickcheck! { + fn qc_memchr3_matches_naive( + n1: u8, n2: u8, n3: u8, + corpus: Vec + ) -> bool { + memchr3(n1, n2, n3, &corpus) == naive::memchr3(n1, n2, n3, &corpus) + } +} + +quickcheck! { + fn qc_memrchr1_matches_naive(n1: u8, corpus: Vec) -> bool { + memrchr(n1, &corpus) == naive::memrchr(n1, &corpus) + } +} + +quickcheck! { + fn qc_memrchr2_matches_naive(n1: u8, n2: u8, corpus: Vec) -> bool { + memrchr2(n1, n2, &corpus) == naive::memrchr2(n1, n2, &corpus) + } +} + +quickcheck! { + fn qc_memrchr3_matches_naive( + n1: u8, n2: u8, n3: u8, + corpus: Vec + ) -> bool { + memrchr3(n1, n2, n3, &corpus) == naive::memrchr3(n1, n2, n3, &corpus) + } +} diff --git a/memchr/src/tests/mod.rs b/memchr/src/tests/mod.rs new file mode 100644 index 000000000..7033e2e80 --- /dev/null +++ b/memchr/src/tests/mod.rs @@ -0,0 +1,422 @@ +use std::iter::repeat; + +mod iter; +mod memchr; + +#[cfg(target_endian = "little")] +#[test] +fn byte_order() { + eprintln!("LITTLE ENDIAN"); +} + +#[cfg(target_endian = "big")] +#[test] +fn byte_order() { + eprintln!("BIG ENDIAN"); +} + +/// Create a sequence of tests that should be run by memchr implementations. +fn memchr_tests() -> Vec { + let mut tests = Vec::new(); + for statict in MEMCHR_TESTS { + assert!(!statict.corpus.contains("%"), "% is not allowed in corpora"); + assert!(!statict.corpus.contains("#"), "# is not allowed in corpora"); + assert!(!statict.needles.contains(&b'%'), "% is an invalid needle"); + assert!(!statict.needles.contains(&b'#'), "# is an invalid needle"); + + let t = MemchrTest { + corpus: statict.corpus.to_string(), + needles: statict.needles.to_vec(), + positions: statict.positions.to_vec(), + }; + tests.push(t.clone()); + tests.extend(t.expand()); + } + tests +} + +/// A set of tests for memchr-like functions. +/// +/// These tests mostly try to cover the short string cases. We cover the longer +/// string cases via the benchmarks (which are tests themselves), via +/// quickcheck tests and via automatic expansion of each test case (by +/// increasing the corpus size). Finally, we cover different alignment cases +/// in the tests by varying the starting point of the slice. +const MEMCHR_TESTS: &[MemchrTestStatic] = &[ + // one needle (applied to memchr + memchr2 + memchr3) + MemchrTestStatic { + corpus: "a", + needles: &[b'a'], + positions: &[0], + }, + MemchrTestStatic { + corpus: "aa", + needles: &[b'a'], + positions: &[0, 1], + }, + MemchrTestStatic { + corpus: "aaa", + needles: &[b'a'], + positions: &[0, 1, 2], + }, + MemchrTestStatic { + corpus: "", + needles: &[b'a'], + positions: &[], + }, + MemchrTestStatic { + corpus: "z", + needles: &[b'a'], + positions: &[], + }, + MemchrTestStatic { + corpus: "zz", + needles: &[b'a'], + positions: &[], + }, + MemchrTestStatic { + corpus: "zza", + needles: &[b'a'], + positions: &[2], + }, + MemchrTestStatic { + corpus: "zaza", + needles: &[b'a'], + positions: &[1, 3], + }, + MemchrTestStatic { + corpus: "zzza", + needles: &[b'a'], + positions: &[3], + }, + MemchrTestStatic { + corpus: "\x00a", + needles: &[b'a'], + positions: &[1], + }, + MemchrTestStatic { + corpus: "\x00", + needles: &[b'\x00'], + positions: &[0], + }, + MemchrTestStatic { + corpus: "\x00\x00", + needles: &[b'\x00'], + positions: &[0, 1], + }, + MemchrTestStatic { + corpus: "\x00a\x00", + needles: &[b'\x00'], + positions: &[0, 2], + }, + MemchrTestStatic { + corpus: "zzzzzzzzzzzzzzzza", + needles: &[b'a'], + positions: &[16], + }, + MemchrTestStatic { + corpus: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzza", + needles: &[b'a'], + positions: &[32], + }, + + // two needles (applied to memchr2 + memchr3) + MemchrTestStatic { + corpus: "az", + needles: &[b'a', b'z'], + positions: &[0, 1], + }, + MemchrTestStatic { + corpus: "az", + needles: &[b'a', b'z'], + positions: &[0, 1], + }, + MemchrTestStatic { + corpus: "az", + needles: &[b'x', b'y'], + positions: &[], + }, + MemchrTestStatic { + corpus: "az", + needles: &[b'a', b'y'], + positions: &[0], + }, + MemchrTestStatic { + corpus: "az", + needles: &[b'x', b'z'], + positions: &[1], + }, + MemchrTestStatic { + corpus: "yyyyaz", + needles: &[b'a', b'z'], + positions: &[4, 5], + }, + MemchrTestStatic { + corpus: "yyyyaz", + needles: &[b'z', b'a'], + positions: &[4, 5], + }, + + // three needles (applied to memchr3) + MemchrTestStatic { + corpus: "xyz", + needles: &[b'x', b'y', b'z'], + positions: &[0, 1, 2], + }, + MemchrTestStatic { + corpus: "zxy", + needles: &[b'x', b'y', b'z'], + positions: &[0, 1, 2], + }, + MemchrTestStatic { + corpus: "zxy", + needles: &[b'x', b'a', b'z'], + positions: &[0, 1], + }, + MemchrTestStatic { + corpus: "zxy", + needles: &[b't', b'a', b'z'], + positions: &[0], + }, + MemchrTestStatic { + corpus: "yxz", + needles: &[b't', b'a', b'z'], + positions: &[2], + }, +]; + +/// A description of a test on a memchr like function. +#[derive(Clone, Debug)] +struct MemchrTest { + /// The thing to search. We use `&str` instead of `&[u8]` because they + /// are nicer to write in tests, and we don't miss much since memchr + /// doesn't care about UTF-8. + /// + /// Corpora cannot contain either '%' or '#'. We use these bytes when + /// expanding test cases into many test cases, and we assume they are not + /// used. If they are used, `memchr_tests` will panic. + corpus: String, + /// The needles to search for. This is intended to be an "alternation" of + /// needles. The number of needles may cause this test to be skipped for + /// some memchr variants. For example, a test with 2 needles cannot be used + /// to test `memchr`, but can be used to test `memchr2` and `memchr3`. + /// However, a test with only 1 needle can be used to test all of `memchr`, + /// `memchr2` and `memchr3`. We achieve this by filling in the needles with + /// bytes that we never used in the corpus (such as '#'). + needles: Vec, + /// The positions expected to match for all of the needles. + positions: Vec, +} + +/// Like MemchrTest, but easier to define as a constant. +#[derive(Clone, Debug)] +struct MemchrTestStatic { + corpus: &'static str, + needles: &'static [u8], + positions: &'static [usize], +} + +impl MemchrTest { + fn one Option>( + &self, + reverse: bool, + f: F, + ) { + let needles = match self.needles(1) { + None => return, + Some(needles) => needles, + }; + // We test different alignments here. Since some implementations use + // AVX2, which can read 32 bytes at a time, we test at least that. + // Moreover, with loop unrolling, we sometimes process 64 (sse2) or 128 + // (avx) bytes at a time, so we include that in our offsets as well. + // + // You might think this would cause most needles to not be found, but + // we actually expand our tests to include corpus sizes all the way up + // to >500 bytes, so we should exericse most branches. + for align in 0..130 { + let corpus = self.corpus(align); + assert_eq!( + self.positions(align, reverse).get(0).cloned(), + f(needles[0], corpus.as_bytes()), + "search for {:?} failed in: {:?} (len: {}, alignment: {})", + needles[0] as char, + corpus, + corpus.len(), + align + ); + } + } + + fn two Option>( + &self, + reverse: bool, + f: F, + ) { + let needles = match self.needles(2) { + None => return, + Some(needles) => needles, + }; + for align in 0..130 { + let corpus = self.corpus(align); + assert_eq!( + self.positions(align, reverse).get(0).cloned(), + f(needles[0], needles[1], corpus.as_bytes()), + "search for {:?}|{:?} failed in: {:?} \ + (len: {}, alignment: {})", + needles[0] as char, + needles[1] as char, + corpus, + corpus.len(), + align + ); + } + } + + fn three Option>( + &self, + reverse: bool, + f: F, + ) { + let needles = match self.needles(3) { + None => return, + Some(needles) => needles, + }; + for align in 0..130 { + let corpus = self.corpus(align); + assert_eq!( + self.positions(align, reverse).get(0).cloned(), + f(needles[0], needles[1], needles[2], corpus.as_bytes()), + "search for {:?}|{:?}|{:?} failed in: {:?} \ + (len: {}, alignment: {})", + needles[0] as char, + needles[1] as char, + needles[2] as char, + corpus, + corpus.len(), + align + ); + } + } + + fn iter_one<'a, I, F>(&'a self, reverse: bool, f: F) + where F: FnOnce(u8, &'a [u8]) -> I, + I: Iterator + { + if let Some(ns) = self.needles(1) { + self.iter(reverse, f(ns[0], self.corpus.as_bytes())); + } + } + + fn iter_two<'a, I, F>(&'a self, reverse: bool, f: F) + where F: FnOnce(u8, u8, &'a [u8]) -> I, + I: Iterator + { + if let Some(ns) = self.needles(2) { + self.iter(reverse, f(ns[0], ns[1], self.corpus.as_bytes())); + } + } + + fn iter_three<'a, I, F>(&'a self, reverse: bool, f: F) + where F: FnOnce(u8, u8, u8, &'a [u8]) -> I, + I: Iterator + { + if let Some(ns) = self.needles(3) { + self.iter(reverse, f(ns[0], ns[1], ns[2], self.corpus.as_bytes())); + } + } + + /// Test that the positions yielded by the given iterator match the + /// positions in this test. If reverse is true, then reverse the positions + /// before comparing them. + fn iter>(&self, reverse: bool, it: I) { + assert_eq!( + self.positions(0, reverse), + it.collect::>(), + r"search for {:?} failed in: {:?}", + self.needles.iter().map(|&b| b as char).collect::>(), + self.corpus + ); + } + + /// Expand this test into many variations of the same test. + /// + /// In particular, this will generate more tests with larger corpus sizes. + /// The expected positions are updated to maintain the integrity of the + /// test. + /// + /// This is important in testing a memchr implementation, because there are + /// often different cases depending on the length of the corpus. + /// + /// Note that we extend the corpus by adding `%` bytes, which we + /// don't otherwise use as a needle. + fn expand(&self) -> Vec { + let mut more = Vec::new(); + + // Add bytes to the start of the corpus. + for i in 1..515 { + let mut t = self.clone(); + let mut new_corpus: String = repeat('%').take(i).collect(); + new_corpus.push_str(&t.corpus); + t.corpus = new_corpus; + t.positions = t.positions.into_iter().map(|p| p + i).collect(); + more.push(t); + } + // Add bytes to the end of the corpus. + for i in 1..515 { + let mut t = self.clone(); + let mut padding: String = repeat('%').take(i).collect(); + t.corpus.push_str(&padding); + more.push(t); + } + + more + } + + /// Return the corpus at the given alignment. + /// + /// If the alignment exceeds the length of the corpus, then this returns + /// an empty slice. + fn corpus(&self, align: usize) -> &str { + self.corpus.get(align..).unwrap_or("") + } + + /// Return exactly `count` needles from this test. If this test has less + /// than `count` needles, then add `#` until the number of needles + /// matches `count`. If this test has more than `count` needles, then + /// return `None` (because there is no way to use this test data for a + /// search using fewer needles). + fn needles(&self, count: usize) -> Option> { + if self.needles.len() > count { + return None; + } + + let mut needles = self.needles.to_vec(); + for _ in needles.len()..count { + // we assume # is never used in tests. + needles.push(b'#'); + } + Some(needles) + } + + /// Return the positions in this test, reversed if `reverse` is true. + /// + /// If alignment is given, then all positions greater than or equal to that + /// alignment are offset by the alignment. Positions less than the + /// alignment are dropped. + fn positions(&self, align: usize, reverse: bool) -> Vec { + let positions = + if reverse { + let mut positions = self.positions.to_vec(); + positions.reverse(); + positions + } else { + self.positions.to_vec() + }; + positions + .into_iter() + .filter(|&p| p >= align) + .map(|p| p - align) + .collect() + } +} diff --git a/memchr/src/x86/avx.rs b/memchr/src/x86/avx.rs new file mode 100644 index 000000000..e5b4a62ff --- /dev/null +++ b/memchr/src/x86/avx.rs @@ -0,0 +1,739 @@ +use core::arch::x86_64::*; +use core::cmp; +use core::mem::size_of; + +use x86::sse2; + +const VECTOR_SIZE: usize = size_of::<__m256i>(); +const VECTOR_ALIGN: usize = VECTOR_SIZE - 1; + +// The number of bytes to loop at in one iteration of memchr/memrchr. +const LOOP_SIZE: usize = 4 * VECTOR_SIZE; + +// The number of bytes to loop at in one iteration of memchr2/memrchr2 and +// memchr3/memrchr3. There was no observable difference between 128 and 64 +// bytes in benchmarks. memchr3 in particular only gets a very slight speed up +// from the loop unrolling. +const LOOP_SIZE2: usize = 2 * VECTOR_SIZE; + +#[target_feature(enable = "avx2")] +pub unsafe fn memchr(n1: u8, haystack: &[u8]) -> Option { + // For a high level explanation for how this algorithm works, see the + // sse2 implementation. The avx implementation here is the same, but with + // 256-bit vectors instead of 128-bit vectors. + + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + // For small haystacks, defer to the SSE2 implementation. Codegen + // suggests this completely avoids touching the AVX vectors. + return sse2::memchr(n1, haystack); + } + + let vn1 = _mm256_set1_epi8(n1 as i8); + let loop_size = cmp::min(LOOP_SIZE, haystack.len()); + if let Some(i) = forward_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let c = _mm256_load_si256(ptr.add(2 * VECTOR_SIZE) as *const __m256i); + let d = _mm256_load_si256(ptr.add(3 * VECTOR_SIZE) as *const __m256i); + let eqa = _mm256_cmpeq_epi8(vn1, a); + let eqb = _mm256_cmpeq_epi8(vn1, b); + let eqc = _mm256_cmpeq_epi8(vn1, c); + let eqd = _mm256_cmpeq_epi8(vn1, d); + let or1 = _mm256_or_si256(eqa, eqb); + let or2 = _mm256_or_si256(eqc, eqd); + let or3 = _mm256_or_si256(or1, or2); + if _mm256_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask = _mm256_movemask_epi8(eqa); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqb); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqc); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqd); + debug_assert!(mask != 0); + return Some(at + forward_pos(mask)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + debug_assert!(sub(end_ptr, ptr) >= VECTOR_SIZE); + + if let Some(i) = forward_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search1(start_ptr, end_ptr, ptr, vn1); + } + None +} + +#[target_feature(enable = "avx2")] +pub unsafe fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = _mm256_set1_epi8(n1 as i8); + let vn2 = _mm256_set1_epi8(n2 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 || *ptr == n2 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + + if let Some(i) = forward_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE2 && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let eqa1 = _mm256_cmpeq_epi8(vn1, a); + let eqb1 = _mm256_cmpeq_epi8(vn1, b); + let eqa2 = _mm256_cmpeq_epi8(vn2, a); + let eqb2 = _mm256_cmpeq_epi8(vn2, b); + let or1 = _mm256_or_si256(eqa1, eqb1); + let or2 = _mm256_or_si256(eqa2, eqb2); + let or3 = _mm256_or_si256(or1, or2); + if _mm256_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask1 = _mm256_movemask_epi8(eqa1); + let mask2 = _mm256_movemask_epi8(eqa2); + if mask1 != 0 || mask2 != 0 { + return Some(at + forward_pos2(mask1, mask2)); + } + + at += VECTOR_SIZE; + let mask1 = _mm256_movemask_epi8(eqb1); + let mask2 = _mm256_movemask_epi8(eqb2); + return Some(at + forward_pos2(mask1, mask2)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + if let Some(i) = forward_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search2(start_ptr, end_ptr, ptr, vn1, vn2); + } + None +} + +#[target_feature(enable = "avx2")] +pub unsafe fn memchr3( + n1: u8, n2: u8, n3: u8, + haystack: &[u8] +) -> Option { + let vn1 = _mm256_set1_epi8(n1 as i8); + let vn2 = _mm256_set1_epi8(n2 as i8); + let vn3 = _mm256_set1_epi8(n3 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 || *ptr == n2 || *ptr == n3 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + + if let Some(i) = forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE2 && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let eqa1 = _mm256_cmpeq_epi8(vn1, a); + let eqb1 = _mm256_cmpeq_epi8(vn1, b); + let eqa2 = _mm256_cmpeq_epi8(vn2, a); + let eqb2 = _mm256_cmpeq_epi8(vn2, b); + let eqa3 = _mm256_cmpeq_epi8(vn3, a); + let eqb3 = _mm256_cmpeq_epi8(vn3, b); + let or1 = _mm256_or_si256(eqa1, eqb1); + let or2 = _mm256_or_si256(eqa2, eqb2); + let or3 = _mm256_or_si256(eqa3, eqb3); + let or4 = _mm256_or_si256(or1, or2); + let or5 = _mm256_or_si256(or3, or4); + if _mm256_movemask_epi8(or5) != 0 { + let mut at = sub(ptr, start_ptr); + let mask1 = _mm256_movemask_epi8(eqa1); + let mask2 = _mm256_movemask_epi8(eqa2); + let mask3 = _mm256_movemask_epi8(eqa3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + + at += VECTOR_SIZE; + let mask1 = _mm256_movemask_epi8(eqb1); + let mask2 = _mm256_movemask_epi8(eqb2); + let mask3 = _mm256_movemask_epi8(eqb3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + + at += VECTOR_SIZE; + let mask1 = _mm256_movemask_epi8(eqb1); + let mask2 = _mm256_movemask_epi8(eqb2); + let mask3 = _mm256_movemask_epi8(eqb3); + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + if let Some(i) = forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3); + } + None +} + +#[target_feature(enable = "avx2")] +pub unsafe fn memrchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = _mm256_set1_epi8(n1 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let c = _mm256_load_si256(ptr.add(2 * VECTOR_SIZE) as *const __m256i); + let d = _mm256_load_si256(ptr.add(3 * VECTOR_SIZE) as *const __m256i); + let eqa = _mm256_cmpeq_epi8(vn1, a); + let eqb = _mm256_cmpeq_epi8(vn1, b); + let eqc = _mm256_cmpeq_epi8(vn1, c); + let eqd = _mm256_cmpeq_epi8(vn1, d); + let or1 = _mm256_or_si256(eqa, eqb); + let or2 = _mm256_or_si256(eqc, eqd); + let or3 = _mm256_or_si256(or1, or2); + if _mm256_movemask_epi8(or3) != 0 { + let mut at = sub(ptr.add(3 * VECTOR_SIZE), start_ptr); + let mask = _mm256_movemask_epi8(eqd); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqc); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqb); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm256_movemask_epi8(eqa); + debug_assert!(mask != 0); + return Some(at + reverse_pos(mask)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search1(start_ptr, end_ptr, start_ptr, vn1); + } + None +} + +#[target_feature(enable = "avx2")] +pub unsafe fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = _mm256_set1_epi8(n1 as i8); + let vn2 = _mm256_set1_epi8(n2 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 || *ptr == n2 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE2 && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let eqa1 = _mm256_cmpeq_epi8(vn1, a); + let eqb1 = _mm256_cmpeq_epi8(vn1, b); + let eqa2 = _mm256_cmpeq_epi8(vn2, a); + let eqb2 = _mm256_cmpeq_epi8(vn2, b); + let or1 = _mm256_or_si256(eqa1, eqb1); + let or2 = _mm256_or_si256(eqa2, eqb2); + let or3 = _mm256_or_si256(or1, or2); + if _mm256_movemask_epi8(or3) != 0 { + let mut at = sub(ptr.add(VECTOR_SIZE), start_ptr); + let mask1 = _mm256_movemask_epi8(eqb1); + let mask2 = _mm256_movemask_epi8(eqb2); + if mask1 != 0 || mask2 != 0 { + return Some(at + reverse_pos2(mask1, mask2)); + } + + at -= VECTOR_SIZE; + let mask1 = _mm256_movemask_epi8(eqa1); + let mask2 = _mm256_movemask_epi8(eqa2); + return Some(at + reverse_pos2(mask1, mask2)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search2(start_ptr, end_ptr, start_ptr, vn1, vn2); + } + None +} + +#[target_feature(enable = "avx2")] +pub unsafe fn memrchr3( + n1: u8, n2: u8, n3: u8, + haystack: &[u8], +) -> Option { + let vn1 = _mm256_set1_epi8(n1 as i8); + let vn2 = _mm256_set1_epi8(n2 as i8); + let vn3 = _mm256_set1_epi8(n3 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 || *ptr == n2 || *ptr == n3 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE2 && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm256_load_si256(ptr as *const __m256i); + let b = _mm256_load_si256(ptr.add(VECTOR_SIZE) as *const __m256i); + let eqa1 = _mm256_cmpeq_epi8(vn1, a); + let eqb1 = _mm256_cmpeq_epi8(vn1, b); + let eqa2 = _mm256_cmpeq_epi8(vn2, a); + let eqb2 = _mm256_cmpeq_epi8(vn2, b); + let eqa3 = _mm256_cmpeq_epi8(vn3, a); + let eqb3 = _mm256_cmpeq_epi8(vn3, b); + let or1 = _mm256_or_si256(eqa1, eqb1); + let or2 = _mm256_or_si256(eqa2, eqb2); + let or3 = _mm256_or_si256(eqa3, eqb3); + let or4 = _mm256_or_si256(or1, or2); + let or5 = _mm256_or_si256(or3, or4); + if _mm256_movemask_epi8(or5) != 0 { + let mut at = sub(ptr.add(VECTOR_SIZE), start_ptr); + let mask1 = _mm256_movemask_epi8(eqb1); + let mask2 = _mm256_movemask_epi8(eqb2); + let mask3 = _mm256_movemask_epi8(eqb3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + reverse_pos3(mask1, mask2, mask3)); + } + + at -= VECTOR_SIZE; + let mask1 = _mm256_movemask_epi8(eqa1); + let mask2 = _mm256_movemask_epi8(eqa2); + let mask3 = _mm256_movemask_epi8(eqa3); + return Some(at + reverse_pos3(mask1, mask2, mask3)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search3(start_ptr, end_ptr, start_ptr, vn1, vn2, vn3); + } + None +} + +#[target_feature(enable = "avx2")] +unsafe fn forward_search1( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(chunk, vn1)); + if mask != 0 { + Some(sub(ptr, start_ptr) + forward_pos(mask)) + } else { + None + } +} + +#[target_feature(enable = "avx2")] +unsafe fn forward_search2( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, + vn2: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let eq1 = _mm256_cmpeq_epi8(chunk, vn1); + let eq2 = _mm256_cmpeq_epi8(chunk, vn2); + if _mm256_movemask_epi8(_mm256_or_si256(eq1, eq2)) != 0 { + let mask1 = _mm256_movemask_epi8(eq1); + let mask2 = _mm256_movemask_epi8(eq2); + Some(sub(ptr, start_ptr) + forward_pos2(mask1, mask2)) + } else { + None + } +} + +#[target_feature(enable = "avx2")] +unsafe fn forward_search3( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, + vn2: __m256i, + vn3: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let eq1 = _mm256_cmpeq_epi8(chunk, vn1); + let eq2 = _mm256_cmpeq_epi8(chunk, vn2); + let eq3 = _mm256_cmpeq_epi8(chunk, vn3); + let or = _mm256_or_si256(eq1, eq2); + if _mm256_movemask_epi8(_mm256_or_si256(or, eq3)) != 0 { + let mask1 = _mm256_movemask_epi8(eq1); + let mask2 = _mm256_movemask_epi8(eq2); + let mask3 = _mm256_movemask_epi8(eq3); + Some(sub(ptr, start_ptr) + forward_pos3(mask1, mask2, mask3)) + } else { + None + } +} + +#[target_feature(enable = "avx2")] +unsafe fn reverse_search1( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let mask = _mm256_movemask_epi8(_mm256_cmpeq_epi8(vn1, chunk)); + if mask != 0 { + Some(sub(ptr, start_ptr) + reverse_pos(mask)) + } else { + None + } +} + +#[target_feature(enable = "avx2")] +unsafe fn reverse_search2( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, + vn2: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let eq1 = _mm256_cmpeq_epi8(chunk, vn1); + let eq2 = _mm256_cmpeq_epi8(chunk, vn2); + if _mm256_movemask_epi8(_mm256_or_si256(eq1, eq2)) != 0 { + let mask1 = _mm256_movemask_epi8(eq1); + let mask2 = _mm256_movemask_epi8(eq2); + Some(sub(ptr, start_ptr) + reverse_pos2(mask1, mask2)) + } else { + None + } +} + +#[target_feature(enable = "avx2")] +unsafe fn reverse_search3( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m256i, + vn2: __m256i, + vn3: __m256i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm256_loadu_si256(ptr as *const __m256i); + let eq1 = _mm256_cmpeq_epi8(chunk, vn1); + let eq2 = _mm256_cmpeq_epi8(chunk, vn2); + let eq3 = _mm256_cmpeq_epi8(chunk, vn3); + let or = _mm256_or_si256(eq1, eq2); + if _mm256_movemask_epi8(_mm256_or_si256(or, eq3)) != 0 { + let mask1 = _mm256_movemask_epi8(eq1); + let mask2 = _mm256_movemask_epi8(eq2); + let mask3 = _mm256_movemask_epi8(eq3); + Some(sub(ptr, start_ptr) + reverse_pos3(mask1, mask2, mask3)) + } else { + None + } +} + +/// Compute the position of the first matching byte from the given mask. The +/// position returned is always in the range [0, 31]. +/// +/// The mask given is expected to be the result of _mm256_movemask_epi8. +fn forward_pos(mask: i32) -> usize { + // We are dealing with little endian here, where the most significant byte + // is at a higher address. That means the least significant bit that is set + // corresponds to the position of our first matching byte. That position + // corresponds to the number of zeros after the least significant bit. + mask.trailing_zeros() as usize +} + +/// Compute the position of the first matching byte from the given masks. The +/// position returned is always in the range [0, 31]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm256_movemask_epi8, +/// where at least one of the masks is non-zero (i.e., indicates a match). +fn forward_pos2(mask1: i32, mask2: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0); + + let i1 = forward_pos(mask1); + let i2 = forward_pos(mask2); + if i1 < i2 { i1 } else { i2 } +} + +/// Compute the position of the first matching byte from the given masks. The +/// position returned is always in the range [0, 31]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm256_movemask_epi8, +/// where at least one of the masks is non-zero (i.e., indicates a match). +fn forward_pos3(mask1: i32, mask2: i32, mask3: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0 || mask3 != 0); + + let i1 = forward_pos(mask1); + let i2 = forward_pos(mask2); + let i3 = forward_pos(mask3); + if i1 < i2 && i1 < i3 { + i1 + } else if i2 < i3 { + i2 + } else { + i3 + } +} + +/// Compute the position of the last matching byte from the given mask. The +/// position returned is always in the range [0, 31]. +/// +/// The mask given is expected to be the result of _mm256_movemask_epi8. +fn reverse_pos(mask: i32) -> usize { + // We are dealing with little endian here, where the most significant byte + // is at a higher address. That means the most significant bit that is set + // corresponds to the position of our last matching byte. The position from + // the end of the mask is therefore the number of leading zeros in a 32 + // bit integer, and the position from the start of the mask is therefore + // 32 - (leading zeros) - 1. + VECTOR_SIZE - (mask as u32).leading_zeros() as usize - 1 +} + +/// Compute the position of the last matching byte from the given masks. The +/// position returned is always in the range [0, 31]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm256_movemask_epi8, +/// where at least one of the masks is non-zero (i.e., indicates a match). +fn reverse_pos2(mask1: i32, mask2: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0); + + if mask1 == 0 { + reverse_pos(mask2) + } else if mask2 == 0 { + reverse_pos(mask1) + } else { + let i1 = reverse_pos(mask1); + let i2 = reverse_pos(mask2); + if i1 > i2 { i1 } else { i2 } + } +} + +/// Compute the position of the last matching byte from the given masks. The +/// position returned is always in the range [0, 31]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm256_movemask_epi8, +/// where at least one of the masks is non-zero (i.e., indicates a match). +fn reverse_pos3(mask1: i32, mask2: i32, mask3: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0 || mask3 != 0); + + if mask1 == 0 { + reverse_pos2(mask2, mask3) + } else if mask2 == 0 { + reverse_pos2(mask1, mask3) + } else if mask3 == 0 { + reverse_pos2(mask1, mask2) + } else { + let i1 = reverse_pos(mask1); + let i2 = reverse_pos(mask2); + let i3 = reverse_pos(mask3); + if i1 > i2 && i1 > i3 { + i1 + } else if i2 > i3 { + i2 + } else { + i3 + } + } +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} diff --git a/memchr/src/x86/mod.rs b/memchr/src/x86/mod.rs new file mode 100644 index 000000000..6599da3fd --- /dev/null +++ b/memchr/src/x86/mod.rs @@ -0,0 +1,105 @@ +use fallback; + +// We only use AVX when we can detect at runtime whether it's available, which +// requires std. +#[cfg(feature = "use_std")] +mod avx; +mod sse2; + +// This macro employs a gcc-like "ifunc" trick where by upon first calling +// `memchr` (for example), CPU feature detection will be performed at runtime +// to determine the best implementation to use. After CPU feature detection +// is done, we replace `memchr`'s function pointer with the selection. Upon +// subsequent invocations, the CPU-specific routine is invoked directly, which +// skips the CPU feature detection and subsequent branch that's required. +// +// While this typically doesn't matter for rare occurrences or when used on +// larger haystacks, `memchr` can be called in tight loops where the overhead +// of this branch can actually add up *and is measurable*. This trick was +// necessary to bring this implementation up to glibc's speeds for the 'tiny' +// benchmarks, for example. +// +// At some point, I expect the Rust ecosystem will get a nice macro for doing +// exactly this, at which point, we can replace our hand-jammed version of it. +// +// N.B. The ifunc strategy does prevent function inlining of course, but on +// modern CPUs, you'll probably end up with the AVX2 implementation, which +// probably can't be inlined anyway---unless you've compiled your entire +// program with AVX2 enabled. However, even then, the various memchr +// implementations aren't exactly small, so inlining might not help anyway! +#[cfg(feature = "use_std")] +macro_rules! ifunc { + ($fnty:ty, $name:ident, $haystack:ident, $($needle:ident),+) => {{ + use std::mem; + use std::sync::atomic::{AtomicPtr, Ordering}; + + type FnRaw = *mut (); + + static FN: AtomicPtr<()> = AtomicPtr::new(detect as FnRaw); + + fn detect($($needle: u8),+, haystack: &[u8]) -> Option { + let fun = + if cfg!(memchr_runtime_avx) && is_x86_feature_detected!("avx2") { + avx::$name as FnRaw + } else if cfg!(memchr_runtime_sse2) { + sse2::$name as FnRaw + } else { + fallback::$name as FnRaw + }; + FN.store(fun as FnRaw, Ordering::Relaxed); + unsafe { + mem::transmute::(fun)($($needle),+, haystack) + } + } + + unsafe { + let fun = FN.load(Ordering::Relaxed); + mem::transmute::(fun)($($needle),+, $haystack) + } + }} +} + +// When std isn't enable (which provides runtime CPU feature detection), or if +// runtime CPU feature detection has been explicitly disabled, then just call +// our optimized SSE2 routine directly. SSE2 is avalbale on all x86_64 targets, +// so no CPU feature detection is necessary. +#[cfg(not(feature = "use_std"))] +macro_rules! ifunc { + ($fnty:ty, $name:ident, $haystack:ident, $($needle:ident),+) => {{ + if cfg!(memchr_runtime_sse2) { + unsafe { sse2::$name($($needle),+, $haystack) } + } else { + fallback::$name($($needle),+, $haystack) + } + }} +} + +#[inline(always)] +pub fn memchr(n1: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, &[u8]) -> Option, memchr, haystack, n1) +} + +#[inline(always)] +pub fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, u8, &[u8]) -> Option, memchr2, haystack, n1, n2) +} + +#[inline(always)] +pub fn memchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, u8, u8, &[u8]) -> Option, memchr3, haystack, n1, n2, n3) +} + +#[inline(always)] +pub fn memrchr(n1: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, &[u8]) -> Option, memrchr, haystack, n1) +} + +#[inline(always)] +pub fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, u8, &[u8]) -> Option, memrchr2, haystack, n1, n2) +} + +#[inline(always)] +pub fn memrchr3(n1: u8, n2: u8, n3: u8, haystack: &[u8]) -> Option { + ifunc!(fn(u8, u8, u8, &[u8]) -> Option, memrchr3, haystack, n1, n2, n3) +} diff --git a/memchr/src/x86/sse2.rs b/memchr/src/x86/sse2.rs new file mode 100644 index 000000000..a988d9acb --- /dev/null +++ b/memchr/src/x86/sse2.rs @@ -0,0 +1,827 @@ +use core::arch::x86_64::*; +use core::cmp; +use core::mem::size_of; + +const VECTOR_SIZE: usize = size_of::<__m128i>(); +const VECTOR_ALIGN: usize = VECTOR_SIZE - 1; + +// The number of bytes to loop at in one iteration of memchr/memrchr. +const LOOP_SIZE: usize = 4 * VECTOR_SIZE; + +// The number of bytes to loop at in one iteration of memchr2/memrchr2 and +// memchr3/memrchr3. There was no observable difference between 64 and 32 bytes +// in benchmarks. memchr3 in particular only gets a very slight speed up from +// the loop unrolling. +const LOOP_SIZE2: usize = 2 * VECTOR_SIZE; + +#[target_feature(enable = "sse2")] +pub unsafe fn memchr(n1: u8, haystack: &[u8]) -> Option { + // What follows is a fast SSE2-only algorithm to detect the position of + // `n1` in `haystack` if it exists. From what I know, this is the "classic" + // algorithm. I believe it can be found in places like glibc and Go's + // standard library. It appears to be well known and is elaborated on in + // more detail here: https://gms.tf/stdfind-and-memchr-optimizations.html + // + // While this routine is very long, the basic idea is actually very simple + // and can be expressed straight-forwardly in pseudo code: + // + // needle = (n1 << 15) | (n1 << 14) | ... | (n1 << 1) | n1 + // while i <= haystack.len() - 16: + // // A 16 byte vector. Each byte in chunk corresponds to a byte in + // // the haystack. + // chunk = haystack[i:i+16] + // // Compare bytes in needle with bytes in chunk. The result is a 16 + // // byte chunk where each byte is 0xFF if the corresponding bytes + // // in needle and chunk were equal, or 0x00 otherwise. + // eqs = cmpeq(needle, chunk) + // // Return a 32 bit integer where the most significant 16 bits + // // are always 0 and the lower 16 bits correspond to whether the + // // most significant bit in the correspond byte in `eqs` is set. + // // In other words, `mask as u16` has bit i set if and only if + // // needle[i] == chunk[i]. + // mask = movemask(eqs) + // + // // Mask is 0 if there is no match, and non-zero otherwise. + // if mask != 0: + // // trailing_zeros tells us the position of the least significant + // // bit that is set. + // return i + trailing_zeros(mask) + // + // // haystack length may not be a multiple of 16, so search the rest. + // while i < haystack.len(): + // if haystack[i] == n1: + // return i + // + // // No match found. + // return NULL + // + // In fact, we could loosely translate the above code to Rust line-for-line + // and it would be a pretty fast algorithm. But, we pull out all the stops + // to go as fast as possible: + // + // 1. We use aligned loads. That is, we do some finagling to make sure our + // primary loop not only proceeds in increments of 16 bytes, but that + // the address of haystack's pointer that we dereference is aligned to + // 16 bytes. 16 is a magic number here because it is the size of SSE2 + // 128-bit vector. (For the AVX2 algorithm, 32 is the magic number.) + // Therefore, to get aligned loads, our pointer's address must be evenly + // divisible by 16. + // 2. Our primary loop proceeds 64 bytes at a time instead of 16. It's + // kind of like loop unrolling, but we combine the equality comparisons + // using a vector OR such that we only need to extract a single mask to + // determine whether a match exists or not. If so, then we do some + // book-keeping to determine the precise location but otherwise mush on. + // 3. We use our "chunk" comparison routine in as many places as possible, + // even if it means using unaligned loads. In particular, if haystack + // starts with an unaligned address, then we do an unaligned load to + // search the first 16 bytes. We then start our primary loop at the + // smallest subsequent aligned address, which will actually overlap with + // previously searched bytes. But we're OK with that. We do a similar + // dance at the end of our primary loop. Finally, to avoid a + // byte-at-a-time loop at the end, we do a final 16 byte unaligned load + // that may overlap with a previous load. This is OK because it converts + // a loop into a small number of very fast vector instructions. + // + // The primary downside of this algorithm is that it's effectively + // completely unsafe. Therefore, we have to be super careful to avoid + // undefined behavior: + // + // 1. We use raw pointers everywhere. Not only does dereferencing a pointer + // require the pointer to be valid, but we actually can't even store the + // address of an invalid pointer (unless it's 1 past the end of + // haystack) without sacrificing performance. + // 2. _mm_loadu_si128 is used when you don't care about alignment, and + // _mm_load_si128 is used when you do care. You cannot use the latter + // on unaligned pointers. + // 3. We make liberal use of debug_assert! to check assumptions. + // 4. We make a concerted effort to stick with pointers instead of indices. + // Indices are nicer because there's less to worry about with them (see + // above about pointer offsets), but I could not get the compiler to + // produce as good of code as what the below produces. In any case, + // pointers are what we really care about here, and alignment is + // expressed a bit more naturally with them. + // + // In general, most of the algorithms in this crate have a similar + // structure to what you see below, so this comment applies fairly well to + // all of them. + + let vn1 = _mm_set1_epi8(n1 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + + if let Some(i) = forward_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let c = _mm_load_si128(ptr.add(2 * VECTOR_SIZE) as *const __m128i); + let d = _mm_load_si128(ptr.add(3 * VECTOR_SIZE) as *const __m128i); + let eqa = _mm_cmpeq_epi8(vn1, a); + let eqb = _mm_cmpeq_epi8(vn1, b); + let eqc = _mm_cmpeq_epi8(vn1, c); + let eqd = _mm_cmpeq_epi8(vn1, d); + let or1 = _mm_or_si128(eqa, eqb); + let or2 = _mm_or_si128(eqc, eqd); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask = _mm_movemask_epi8(eqa); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqb); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqc); + if mask != 0 { + return Some(at + forward_pos(mask)); + } + + at += VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqd); + debug_assert!(mask != 0); + return Some(at + forward_pos(mask)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + debug_assert!(sub(end_ptr, ptr) >= VECTOR_SIZE); + + if let Some(i) = forward_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search1(start_ptr, end_ptr, ptr, vn1); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn memchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let vn2 = _mm_set1_epi8(n2 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 || *ptr == n2 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + + if let Some(i) = forward_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE2 && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let eqa1 = _mm_cmpeq_epi8(vn1, a); + let eqb1 = _mm_cmpeq_epi8(vn1, b); + let eqa2 = _mm_cmpeq_epi8(vn2, a); + let eqb2 = _mm_cmpeq_epi8(vn2, b); + let or1 = _mm_or_si128(eqa1, eqb1); + let or2 = _mm_or_si128(eqa2, eqb2); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr, start_ptr); + let mask1 = _mm_movemask_epi8(eqa1); + let mask2 = _mm_movemask_epi8(eqa2); + if mask1 != 0 || mask2 != 0 { + return Some(at + forward_pos2(mask1, mask2)); + } + + at += VECTOR_SIZE; + let mask1 = _mm_movemask_epi8(eqb1); + let mask2 = _mm_movemask_epi8(eqb2); + return Some(at + forward_pos2(mask1, mask2)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + if let Some(i) = forward_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search2(start_ptr, end_ptr, ptr, vn1, vn2); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn memchr3( + n1: u8, n2: u8, n3: u8, + haystack: &[u8] +) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let vn2 = _mm_set1_epi8(n2 as i8); + let vn3 = _mm_set1_epi8(n3 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 || *ptr == n2 || *ptr == n3 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + + if let Some(i) = forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + + ptr = ptr.add(VECTOR_SIZE - (start_ptr as usize & VECTOR_ALIGN)); + debug_assert!(ptr > start_ptr && end_ptr.sub(VECTOR_SIZE) >= start_ptr); + while loop_size == LOOP_SIZE2 && ptr <= end_ptr.sub(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let eqa1 = _mm_cmpeq_epi8(vn1, a); + let eqb1 = _mm_cmpeq_epi8(vn1, b); + let eqa2 = _mm_cmpeq_epi8(vn2, a); + let eqb2 = _mm_cmpeq_epi8(vn2, b); + let eqa3 = _mm_cmpeq_epi8(vn3, a); + let eqb3 = _mm_cmpeq_epi8(vn3, b); + let or1 = _mm_or_si128(eqa1, eqb1); + let or2 = _mm_or_si128(eqa2, eqb2); + let or3 = _mm_or_si128(eqa3, eqb3); + let or4 = _mm_or_si128(or1, or2); + let or5 = _mm_or_si128(or3, or4); + if _mm_movemask_epi8(or5) != 0 { + let mut at = sub(ptr, start_ptr); + let mask1 = _mm_movemask_epi8(eqa1); + let mask2 = _mm_movemask_epi8(eqa2); + let mask3 = _mm_movemask_epi8(eqa3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + + at += VECTOR_SIZE; + let mask1 = _mm_movemask_epi8(eqb1); + let mask2 = _mm_movemask_epi8(eqb2); + let mask3 = _mm_movemask_epi8(eqb3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + + at += VECTOR_SIZE; + let mask1 = _mm_movemask_epi8(eqb1); + let mask2 = _mm_movemask_epi8(eqb2); + let mask3 = _mm_movemask_epi8(eqb3); + return Some(at + forward_pos3(mask1, mask2, mask3)); + } + ptr = ptr.add(loop_size); + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + if let Some(i) = forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn memrchr(n1: u8, haystack: &[u8]) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let c = _mm_load_si128(ptr.add(2 * VECTOR_SIZE) as *const __m128i); + let d = _mm_load_si128(ptr.add(3 * VECTOR_SIZE) as *const __m128i); + let eqa = _mm_cmpeq_epi8(vn1, a); + let eqb = _mm_cmpeq_epi8(vn1, b); + let eqc = _mm_cmpeq_epi8(vn1, c); + let eqd = _mm_cmpeq_epi8(vn1, d); + let or1 = _mm_or_si128(eqa, eqb); + let or2 = _mm_or_si128(eqc, eqd); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr.add(3 * VECTOR_SIZE), start_ptr); + let mask = _mm_movemask_epi8(eqd); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqc); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqb); + if mask != 0 { + return Some(at + reverse_pos(mask)); + } + + at -= VECTOR_SIZE; + let mask = _mm_movemask_epi8(eqa); + debug_assert!(mask != 0); + return Some(at + reverse_pos(mask)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search1(start_ptr, end_ptr, ptr, vn1) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search1(start_ptr, end_ptr, start_ptr, vn1); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn memrchr2(n1: u8, n2: u8, haystack: &[u8]) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let vn2 = _mm_set1_epi8(n2 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 || *ptr == n2 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE2 && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let eqa1 = _mm_cmpeq_epi8(vn1, a); + let eqb1 = _mm_cmpeq_epi8(vn1, b); + let eqa2 = _mm_cmpeq_epi8(vn2, a); + let eqb2 = _mm_cmpeq_epi8(vn2, b); + let or1 = _mm_or_si128(eqa1, eqb1); + let or2 = _mm_or_si128(eqa2, eqb2); + let or3 = _mm_or_si128(or1, or2); + if _mm_movemask_epi8(or3) != 0 { + let mut at = sub(ptr.add(VECTOR_SIZE), start_ptr); + let mask1 = _mm_movemask_epi8(eqb1); + let mask2 = _mm_movemask_epi8(eqb2); + if mask1 != 0 || mask2 != 0 { + return Some(at + reverse_pos2(mask1, mask2)); + } + + at -= VECTOR_SIZE; + let mask1 = _mm_movemask_epi8(eqa1); + let mask2 = _mm_movemask_epi8(eqa2); + return Some(at + reverse_pos2(mask1, mask2)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search2(start_ptr, end_ptr, ptr, vn1, vn2) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search2(start_ptr, end_ptr, start_ptr, vn1, vn2); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn memrchr3( + n1: u8, n2: u8, n3: u8, + haystack: &[u8], +) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let vn2 = _mm_set1_epi8(n2 as i8); + let vn3 = _mm_set1_epi8(n3 as i8); + let len = haystack.len(); + let loop_size = cmp::min(LOOP_SIZE2, len); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = end_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr > start_ptr { + ptr = ptr.offset(-1); + if *ptr == n1 || *ptr == n2 || *ptr == n3 { + return Some(sub(ptr, start_ptr)); + } + } + return None; + } + + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + + ptr = (end_ptr as usize & !VECTOR_ALIGN) as *const u8; + debug_assert!(start_ptr <= ptr && ptr <= end_ptr); + while loop_size == LOOP_SIZE2 && ptr >= start_ptr.add(loop_size) { + debug_assert_eq!(0, (ptr as usize) % VECTOR_SIZE); + + ptr = ptr.sub(loop_size); + let a = _mm_load_si128(ptr as *const __m128i); + let b = _mm_load_si128(ptr.add(VECTOR_SIZE) as *const __m128i); + let eqa1 = _mm_cmpeq_epi8(vn1, a); + let eqb1 = _mm_cmpeq_epi8(vn1, b); + let eqa2 = _mm_cmpeq_epi8(vn2, a); + let eqb2 = _mm_cmpeq_epi8(vn2, b); + let eqa3 = _mm_cmpeq_epi8(vn3, a); + let eqb3 = _mm_cmpeq_epi8(vn3, b); + let or1 = _mm_or_si128(eqa1, eqb1); + let or2 = _mm_or_si128(eqa2, eqb2); + let or3 = _mm_or_si128(eqa3, eqb3); + let or4 = _mm_or_si128(or1, or2); + let or5 = _mm_or_si128(or3, or4); + if _mm_movemask_epi8(or5) != 0 { + let mut at = sub(ptr.add(VECTOR_SIZE), start_ptr); + let mask1 = _mm_movemask_epi8(eqb1); + let mask2 = _mm_movemask_epi8(eqb2); + let mask3 = _mm_movemask_epi8(eqb3); + if mask1 != 0 || mask2 != 0 || mask3 != 0 { + return Some(at + reverse_pos3(mask1, mask2, mask3)); + } + + at -= VECTOR_SIZE; + let mask1 = _mm_movemask_epi8(eqa1); + let mask2 = _mm_movemask_epi8(eqa2); + let mask3 = _mm_movemask_epi8(eqa3); + return Some(at + reverse_pos3(mask1, mask2, mask3)); + } + } + while ptr >= start_ptr.add(VECTOR_SIZE) { + ptr = ptr.sub(VECTOR_SIZE); + if let Some(i) = reverse_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3) { + return Some(i); + } + } + if ptr > start_ptr { + debug_assert!(sub(ptr, start_ptr) < VECTOR_SIZE); + return reverse_search3(start_ptr, end_ptr, start_ptr, vn1, vn2, vn3); + } + None +} + +#[target_feature(enable = "sse2")] +pub unsafe fn forward_search1( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(_mm_cmpeq_epi8(chunk, vn1)); + if mask != 0 { + Some(sub(ptr, start_ptr) + forward_pos(mask)) + } else { + None + } +} + +#[target_feature(enable = "sse2")] +unsafe fn forward_search2( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, + vn2: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let eq1 = _mm_cmpeq_epi8(chunk, vn1); + let eq2 = _mm_cmpeq_epi8(chunk, vn2); + if _mm_movemask_epi8(_mm_or_si128(eq1, eq2)) != 0 { + let mask1 = _mm_movemask_epi8(eq1); + let mask2 = _mm_movemask_epi8(eq2); + Some(sub(ptr, start_ptr) + forward_pos2(mask1, mask2)) + } else { + None + } +} + +#[target_feature(enable = "sse2")] +pub unsafe fn forward_search3( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, + vn2: __m128i, + vn3: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let eq1 = _mm_cmpeq_epi8(chunk, vn1); + let eq2 = _mm_cmpeq_epi8(chunk, vn2); + let eq3 = _mm_cmpeq_epi8(chunk, vn3); + let or = _mm_or_si128(eq1, eq2); + if _mm_movemask_epi8(_mm_or_si128(or, eq3)) != 0 { + let mask1 = _mm_movemask_epi8(eq1); + let mask2 = _mm_movemask_epi8(eq2); + let mask3 = _mm_movemask_epi8(eq3); + Some(sub(ptr, start_ptr) + forward_pos3(mask1, mask2, mask3)) + } else { + None + } +} + +#[target_feature(enable = "sse2")] +unsafe fn reverse_search1( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let mask = _mm_movemask_epi8(_mm_cmpeq_epi8(vn1, chunk)); + if mask != 0 { + Some(sub(ptr, start_ptr) + reverse_pos(mask)) + } else { + None + } +} + +#[target_feature(enable = "sse2")] +unsafe fn reverse_search2( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, + vn2: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let eq1 = _mm_cmpeq_epi8(chunk, vn1); + let eq2 = _mm_cmpeq_epi8(chunk, vn2); + if _mm_movemask_epi8(_mm_or_si128(eq1, eq2)) != 0 { + let mask1 = _mm_movemask_epi8(eq1); + let mask2 = _mm_movemask_epi8(eq2); + Some(sub(ptr, start_ptr) + reverse_pos2(mask1, mask2)) + } else { + None + } +} + +#[target_feature(enable = "sse2")] +unsafe fn reverse_search3( + start_ptr: *const u8, + end_ptr: *const u8, + ptr: *const u8, + vn1: __m128i, + vn2: __m128i, + vn3: __m128i, +) -> Option { + debug_assert!(sub(end_ptr, start_ptr) >= VECTOR_SIZE); + debug_assert!(start_ptr <= ptr); + debug_assert!(ptr <= end_ptr.sub(VECTOR_SIZE)); + + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let eq1 = _mm_cmpeq_epi8(chunk, vn1); + let eq2 = _mm_cmpeq_epi8(chunk, vn2); + let eq3 = _mm_cmpeq_epi8(chunk, vn3); + let or = _mm_or_si128(eq1, eq2); + if _mm_movemask_epi8(_mm_or_si128(or, eq3)) != 0 { + let mask1 = _mm_movemask_epi8(eq1); + let mask2 = _mm_movemask_epi8(eq2); + let mask3 = _mm_movemask_epi8(eq3); + Some(sub(ptr, start_ptr) + reverse_pos3(mask1, mask2, mask3)) + } else { + None + } +} + +/// Compute the position of the first matching byte from the given mask. The +/// position returned is always in the range [0, 15]. +/// +/// The mask given is expected to be the result of _mm_movemask_epi8. +fn forward_pos(mask: i32) -> usize { + // We are dealing with little endian here, where the most significant byte + // is at a higher address. That means the least significant bit that is set + // corresponds to the position of our first matching byte. That position + // corresponds to the number of zeros after the least significant bit. + mask.trailing_zeros() as usize +} + +/// Compute the position of the first matching byte from the given masks. The +/// position returned is always in the range [0, 15]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm_movemask_epi8, where +/// at least one of the masks is non-zero (i.e., indicates a match). +fn forward_pos2(mask1: i32, mask2: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0); + + let i1 = forward_pos(mask1); + let i2 = forward_pos(mask2); + if i1 < i2 { i1 } else { i2 } +} + +/// Compute the position of the first matching byte from the given masks. The +/// position returned is always in the range [0, 15]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm_movemask_epi8, where +/// at least one of the masks is non-zero (i.e., indicates a match). +fn forward_pos3(mask1: i32, mask2: i32, mask3: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0 || mask3 != 0); + + let i1 = forward_pos(mask1); + let i2 = forward_pos(mask2); + let i3 = forward_pos(mask3); + if i1 < i2 && i1 < i3 { + i1 + } else if i2 < i3 { + i2 + } else { + i3 + } +} + +/// Compute the position of the last matching byte from the given mask. The +/// position returned is always in the range [0, 15]. +/// +/// The mask given is expected to be the result of _mm_movemask_epi8. +fn reverse_pos(mask: i32) -> usize { + // We are dealing with little endian here, where the most significant byte + // is at a higher address. That means the most significant bit that is set + // corresponds to the position of our last matching byte. The position from + // the end of the mask is therefore the number of leading zeros in a 16 + // bit integer, and the position from the start of the mask is therefore + // 16 - (leading zeros) - 1. + VECTOR_SIZE - (mask as u16).leading_zeros() as usize - 1 +} + +/// Compute the position of the last matching byte from the given masks. The +/// position returned is always in the range [0, 15]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm_movemask_epi8, where +/// at least one of the masks is non-zero (i.e., indicates a match). +fn reverse_pos2(mask1: i32, mask2: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0); + + if mask1 == 0 { + reverse_pos(mask2) + } else if mask2 == 0 { + reverse_pos(mask1) + } else { + let i1 = reverse_pos(mask1); + let i2 = reverse_pos(mask2); + if i1 > i2 { i1 } else { i2 } + } +} + +/// Compute the position of the last matching byte from the given masks. The +/// position returned is always in the range [0, 15]. Each mask corresponds to +/// the equality comparison of a single byte. +/// +/// The masks given are expected to be the result of _mm_movemask_epi8, where +/// at least one of the masks is non-zero (i.e., indicates a match). +fn reverse_pos3(mask1: i32, mask2: i32, mask3: i32) -> usize { + debug_assert!(mask1 != 0 || mask2 != 0 || mask3 != 0); + + if mask1 == 0 { + reverse_pos2(mask2, mask3) + } else if mask2 == 0 { + reverse_pos2(mask1, mask3) + } else if mask3 == 0 { + reverse_pos2(mask1, mask2) + } else { + let i1 = reverse_pos(mask1); + let i2 = reverse_pos(mask2); + let i3 = reverse_pos(mask3); + if i1 > i2 && i1 > i3 { + i1 + } else if i2 > i3 { + i2 + } else { + i3 + } + } +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} diff --git a/memchr/src/x86/sse42.rs b/memchr/src/x86/sse42.rs new file mode 100644 index 000000000..78a9b3797 --- /dev/null +++ b/memchr/src/x86/sse42.rs @@ -0,0 +1,75 @@ +// This code is unused. PCMPESTRI is gratuitously slow. I imagine it might +// start winning with a hypothetical memchr4 (or greater). This technique might +// also be good for exposing searches over ranges of bytes, but that departs +// from the standard memchr API, so it's not clear whether we actually want +// that or not. +// +// N.B. PCMPISTRI appears to be about twice as fast as PCMPESTRI, which is kind +// of neat. Unfortunately, UTF-8 strings can contain NUL bytes, which means +// I don't see a way of effectively using PCMPISTRI unless there's some fast +// way to replace zero bytes with a byte that is not not a needle byte. + +use core::arch::x86_64::*; +use core::mem::size_of; + +use x86::sse2; + +const VECTOR_SIZE: usize = size_of::<__m128i>(); +const CONTROL_ANY: i32 = + _SIDD_UBYTE_OPS + | _SIDD_CMP_EQUAL_ANY + | _SIDD_POSITIVE_POLARITY + | _SIDD_LEAST_SIGNIFICANT; + +#[target_feature(enable = "sse4.2")] +pub unsafe fn memchr3( + n1: u8, n2: u8, n3: u8, + haystack: &[u8] +) -> Option { + let vn1 = _mm_set1_epi8(n1 as i8); + let vn2 = _mm_set1_epi8(n2 as i8); + let vn3 = _mm_set1_epi8(n3 as i8); + let vn = _mm_setr_epi8( + n1 as i8, n2 as i8, n3 as i8, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ); + let len = haystack.len(); + let start_ptr = haystack.as_ptr(); + let end_ptr = haystack[haystack.len()..].as_ptr(); + let mut ptr = start_ptr; + + if haystack.len() < VECTOR_SIZE { + while ptr < end_ptr { + if *ptr == n1 || *ptr == n2 || *ptr == n3 { + return Some(sub(ptr, start_ptr)); + } + ptr = ptr.offset(1); + } + return None; + } + while ptr <= end_ptr.sub(VECTOR_SIZE) { + let chunk = _mm_loadu_si128(ptr as *const __m128i); + let res = _mm_cmpestri(vn, 3, chunk, 16, CONTROL_ANY); + if res < 16 { + return Some(sub(ptr, start_ptr) + res as usize); + } + ptr = ptr.add(VECTOR_SIZE); + } + if ptr < end_ptr { + debug_assert!(sub(end_ptr, ptr) < VECTOR_SIZE); + ptr = ptr.sub(VECTOR_SIZE - sub(end_ptr, ptr)); + debug_assert_eq!(sub(end_ptr, ptr), VECTOR_SIZE); + + return sse2::forward_search3(start_ptr, end_ptr, ptr, vn1, vn2, vn3); + } + None +} + +/// Subtract `b` from `a` and return the difference. `a` should be greater than +/// or equal to `b`. +fn sub(a: *const u8, b: *const u8) -> usize { + debug_assert!(a >= b); + (a as usize) - (b as usize) +} diff --git a/miow/.cargo-checksum.json b/miow/.cargo-checksum.json new file mode 100644 index 000000000..d684e23d5 --- /dev/null +++ b/miow/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"} \ No newline at end of file diff --git a/miow/Cargo.toml b/miow/Cargo.toml new file mode 100644 index 000000000..23ed2bccb --- /dev/null +++ b/miow/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "miow" +version = "0.3.3" +authors = ["Alex Crichton "] +description = "A zero overhead I/O library for Windows, focusing on IOCP and Async I/O\nabstractions.\n" +homepage = "https://github.com/alexcrichton/miow" +documentation = "https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/miow/" +readme = "README.md" +keywords = ["iocp", "windows", "io", "overlapped"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/miow" +[dependencies.socket2] +version = "0.3" + +[dependencies.winapi] +version = "0.3.3" +features = ["std", "fileapi", "handleapi", "ioapiset", "minwindef", "namedpipeapi", "ntdef", "synchapi", "winerror", "winsock2", "ws2def", "ws2ipdef"] +[dev-dependencies.rand] +version = "0.4" diff --git a/miow/LICENSE-APACHE b/miow/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/miow/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/miow/LICENSE-MIT b/miow/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/miow/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/miow/README.md b/miow/README.md new file mode 100644 index 000000000..be4ecb002 --- /dev/null +++ b/miow/README.md @@ -0,0 +1,31 @@ +# miow + +[![Build status](https://ci.appveyor.com/api/projects/status/tc5lsxokjk86949l?svg=true)](https://ci.appveyor.com/project/alexcrichton/miow) + +[Documentation](https://docs.rs/miow/0.1/x86_64-pc-windows-msvc/miow/) + +A zero overhead Windows I/O library focusing on IOCP and other async I/O +features. + +```toml +# Cargo.toml +[dependencies] +miow = "0.3" +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in miow by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/miow/appveyor.yml b/miow/appveyor.yml new file mode 100644 index 000000000..2700e425c --- /dev/null +++ b/miow/appveyor.yml @@ -0,0 +1,20 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu + GH_TOKEN: + secure: nHB4fVo+y/Aak+L0nYfrT8Rcs8OfUNm0F2xcIVFVYJ9ehf0CzvCmSMUvWguM0kKp + +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% diff --git a/miow/src/handle.rs b/miow/src/handle.rs new file mode 100644 index 000000000..809c1c678 --- /dev/null +++ b/miow/src/handle.rs @@ -0,0 +1,164 @@ +use std::io; +use std::cmp; +use std::ptr; + +use winapi::shared::minwindef::*; +use winapi::shared::ntdef::{ + BOOLEAN, + FALSE, + HANDLE, + TRUE, +}; +use winapi::shared::winerror::*; +use winapi::um::fileapi::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use winapi::um::minwinbase::*; + +#[derive(Debug)] +pub struct Handle(HANDLE); + +unsafe impl Send for Handle {} +unsafe impl Sync for Handle {} + +impl Handle { + pub fn new(handle: HANDLE) -> Handle { + Handle(handle) + } + + pub fn raw(&self) -> HANDLE { self.0 } + + pub fn into_raw(self) -> HANDLE { + use std::mem; + + let ret = self.0; + mem::forget(self); + ret + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let mut bytes = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + try!(::cvt(unsafe { + WriteFile(self.0, buf.as_ptr() as *const _, len, &mut bytes, + 0 as *mut _) + })); + Ok(bytes as usize) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let mut bytes = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + try!(::cvt(unsafe { + ReadFile(self.0, buf.as_mut_ptr() as *mut _, len, &mut bytes, + 0 as *mut _) + })); + Ok(bytes as usize) + } + + pub unsafe fn read_overlapped(&self, buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + self.read_overlapped_helper(buf, overlapped, FALSE) + } + + pub unsafe fn read_overlapped_wait(&self, buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result { + match self.read_overlapped_helper(buf, overlapped, TRUE) { + Ok(Some(bytes)) => Ok(bytes), + Ok(None) => panic!("logic error"), + Err(e) => Err(e), + } + } + + pub unsafe fn read_overlapped_helper(&self, buf: &mut [u8], + overlapped: *mut OVERLAPPED, + wait: BOOLEAN) + -> io::Result> { + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + let res = ::cvt({ + ReadFile(self.0, + buf.as_mut_ptr() as *mut _, + len, + ptr::null_mut(), + overlapped) + }); + match res { + Ok(_) => (), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) + => (), + Err(e) => return Err(e), + } + + let mut bytes = 0; + let res = ::cvt({ + GetOverlappedResult(self.0, + overlapped, + &mut bytes, + wait as BOOL) + }); + match res { + Ok(_) => Ok(Some(bytes as usize)), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE + => Ok(None), + Err(e) => Err(e), + } + } + + pub unsafe fn write_overlapped(&self, buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + self.write_overlapped_helper(buf, overlapped, FALSE) + } + + pub unsafe fn write_overlapped_wait(&self, buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result { + match self.write_overlapped_helper(buf, overlapped, TRUE) { + Ok(Some(bytes)) => Ok(bytes), + Ok(None) => panic!("logic error"), + Err(e) => Err(e), + } + } + + unsafe fn write_overlapped_helper(&self, buf: &[u8], + overlapped: *mut OVERLAPPED, + wait: BOOLEAN) + -> io::Result> { + let len = cmp::min(buf.len(), ::max_value() as usize) as DWORD; + let res = ::cvt({ + WriteFile(self.0, + buf.as_ptr() as *const _, + len, + ptr::null_mut(), + overlapped) + }); + match res { + Ok(_) => (), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) + => (), + Err(e) => return Err(e), + } + + let mut bytes = 0; + let res = ::cvt({ + GetOverlappedResult(self.0, + overlapped, + &mut bytes, + wait as BOOL) + }); + match res { + Ok(_) => Ok(Some(bytes as usize)), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_INCOMPLETE as i32) && wait == FALSE + => Ok(None), + Err(e) => Err(e), + } + } +} + +impl Drop for Handle { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} diff --git a/miow/src/iocp.rs b/miow/src/iocp.rs new file mode 100644 index 000000000..1404be9aa --- /dev/null +++ b/miow/src/iocp.rs @@ -0,0 +1,324 @@ +//! Bindings to IOCP, I/O Completion Ports + +use std::cmp; +use std::fmt; +use std::io; +use std::mem; +use std::os::windows::io::*; +use std::time::Duration; + +use handle::Handle; +use winapi::shared::basetsd::*; +use winapi::shared::ntdef::*; +use winapi::um::minwinbase::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use Overlapped; + +/// A handle to an Windows I/O Completion Port. +#[derive(Debug)] +pub struct CompletionPort { + handle: Handle, +} + +/// A status message received from an I/O completion port. +/// +/// These statuses can be created via the `new` or `empty` constructors and then +/// provided to a completion port, or they are read out of a completion port. +/// The fields of each status are read through its accessor methods. +#[derive(Clone, Copy)] +pub struct CompletionStatus(OVERLAPPED_ENTRY); + +impl fmt::Debug for CompletionStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CompletionStatus(OVERLAPPED_ENTRY)") + } +} + +unsafe impl Send for CompletionStatus {} +unsafe impl Sync for CompletionStatus {} + +impl CompletionPort { + /// Creates a new I/O completion port with the specified concurrency value. + /// + /// The number of threads given corresponds to the level of concurrency + /// allowed for threads associated with this port. Consult the Windows + /// documentation for more information about this value. + pub fn new(threads: u32) -> io::Result { + let ret = unsafe { + CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0 as *mut _, + 0, threads) + }; + if ret.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CompletionPort { handle: Handle::new(ret) }) + } + } + + /// Associates a new `HANDLE` to this I/O completion port. + /// + /// This function will associate the given handle to this port with the + /// given `token` to be returned in status messages whenever it receives a + /// notification. + /// + /// Any object which is convertible to a `HANDLE` via the `AsRawHandle` + /// trait can be provided to this function, such as `std::fs::File` and + /// friends. + pub fn add_handle(&self, token: usize, + t: &T) -> io::Result<()> { + self._add(token, t.as_raw_handle()) + } + + /// Associates a new `SOCKET` to this I/O completion port. + /// + /// This function will associate the given socket to this port with the + /// given `token` to be returned in status messages whenever it receives a + /// notification. + /// + /// Any object which is convertible to a `SOCKET` via the `AsRawSocket` + /// trait can be provided to this function, such as `std::net::TcpStream` + /// and friends. + pub fn add_socket(&self, token: usize, + t: &T) -> io::Result<()> { + self._add(token, t.as_raw_socket() as HANDLE) + } + + fn _add(&self, token: usize, handle: HANDLE) -> io::Result<()> { + assert_eq!(mem::size_of_val(&token), mem::size_of::()); + let ret = unsafe { + CreateIoCompletionPort(handle, self.handle.raw(), + token as ULONG_PTR, 0) + }; + if ret.is_null() { + Err(io::Error::last_os_error()) + } else { + debug_assert_eq!(ret, self.handle.raw()); + Ok(()) + } + } + + /// Dequeue a completion status from this I/O completion port. + /// + /// This function will associate the calling thread with this completion + /// port and then wait for a status message to become available. The precise + /// semantics on when this function returns depends on the concurrency value + /// specified when the port was created. + /// + /// A timeout can optionally be specified to this function. If `None` is + /// provided this function will not time out, and otherwise it will time out + /// after the specified duration has passed. + /// + /// On success this will return the status message which was dequeued from + /// this completion port. + pub fn get(&self, timeout: Option) -> io::Result { + let mut bytes = 0; + let mut token = 0; + let mut overlapped = 0 as *mut _; + let timeout = ::dur2ms(timeout); + let ret = unsafe { + GetQueuedCompletionStatus(self.handle.raw(), + &mut bytes, + &mut token, + &mut overlapped, + timeout) + }; + ::cvt(ret).map(|_| { + CompletionStatus(OVERLAPPED_ENTRY { + dwNumberOfBytesTransferred: bytes, + lpCompletionKey: token, + lpOverlapped: overlapped, + Internal: 0, + }) + }) + } + + /// Dequeues a number of completion statuses from this I/O completion port. + /// + /// This function is the same as `get` except that it may return more than + /// one status. A buffer of "zero" statuses is provided (the contents are + /// not read) and then on success this function will return a sub-slice of + /// statuses which represent those which were dequeued from this port. This + /// function does not wait to fill up the entire list of statuses provided. + /// + /// Like with `get`, a timeout may be specified for this operation. + pub fn get_many<'a>(&self, + list: &'a mut [CompletionStatus], + timeout: Option) + -> io::Result<&'a mut [CompletionStatus]> + { + debug_assert_eq!(mem::size_of::(), + mem::size_of::()); + let mut removed = 0; + let timeout = ::dur2ms(timeout); + let len = cmp::min(list.len(), ::max_value() as usize) as ULONG; + let ret = unsafe { + GetQueuedCompletionStatusEx(self.handle.raw(), + list.as_ptr() as *mut _, + len, + &mut removed, + timeout, + FALSE as i32) + }; + match ::cvt(ret) { + Ok(_) => Ok(&mut list[..removed as usize]), + Err(e) => Err(e), + } + } + + /// Posts a new completion status onto this I/O completion port. + /// + /// This function will post the given status, with custom parameters, to the + /// port. Threads blocked in `get` or `get_many` will eventually receive + /// this status. + pub fn post(&self, status: CompletionStatus) -> io::Result<()> { + let ret = unsafe { + PostQueuedCompletionStatus(self.handle.raw(), + status.0.dwNumberOfBytesTransferred, + status.0.lpCompletionKey, + status.0.lpOverlapped) + }; + ::cvt(ret).map(|_| ()) + } +} + +impl AsRawHandle for CompletionPort { + fn as_raw_handle(&self) -> HANDLE { + self.handle.raw() + } +} + +impl FromRawHandle for CompletionPort { + unsafe fn from_raw_handle(handle: HANDLE) -> CompletionPort { + CompletionPort { handle: Handle::new(handle) } + } +} + +impl IntoRawHandle for CompletionPort { + fn into_raw_handle(self) -> HANDLE { + self.handle.into_raw() + } +} + +impl CompletionStatus { + /// Creates a new completion status with the provided parameters. + /// + /// This function is useful when creating a status to send to a port with + /// the `post` method. The parameters are opaquely passed through and not + /// interpreted by the system at all. + pub fn new(bytes: u32, token: usize, overlapped: *mut Overlapped) + -> CompletionStatus { + assert_eq!(mem::size_of_val(&token), mem::size_of::()); + CompletionStatus(OVERLAPPED_ENTRY { + dwNumberOfBytesTransferred: bytes, + lpCompletionKey: token as ULONG_PTR, + lpOverlapped: overlapped as *mut _, + Internal: 0, + }) + } + + /// Creates a new borrowed completion status from the borrowed + /// `OVERLAPPED_ENTRY` argument provided. + /// + /// This method will wrap the `OVERLAPPED_ENTRY` in a `CompletionStatus`, + /// returning the wrapped structure. + pub fn from_entry(entry: &OVERLAPPED_ENTRY) -> &CompletionStatus { + unsafe { &*(entry as *const _ as *const _) } + } + + /// Creates a new "zero" completion status. + /// + /// This function is useful when creating a stack buffer or vector of + /// completion statuses to be passed to the `get_many` function. + pub fn zero() -> CompletionStatus { + CompletionStatus::new(0, 0, 0 as *mut _) + } + + /// Returns the number of bytes that were transferred for the I/O operation + /// associated with this completion status. + pub fn bytes_transferred(&self) -> u32 { + self.0.dwNumberOfBytesTransferred + } + + /// Returns the completion key value associated with the file handle whose + /// I/O operation has completed. + /// + /// A completion key is a per-handle key that is specified when it is added + /// to an I/O completion port via `add_handle` or `add_socket`. + pub fn token(&self) -> usize { + self.0.lpCompletionKey as usize + } + + /// Returns a pointer to the `Overlapped` structure that was specified when + /// the I/O operation was started. + pub fn overlapped(&self) -> *mut OVERLAPPED { + self.0.lpOverlapped + } + + /// Returns a pointer to the internal `OVERLAPPED_ENTRY` object. + pub fn entry(&self) -> &OVERLAPPED_ENTRY { + &self.0 + } +} + +#[cfg(test)] +mod tests { + use std::mem; + use std::time::Duration; + + use winapi::shared::basetsd::*; + use winapi::shared::winerror::*; + + use iocp::{CompletionPort, CompletionStatus}; + + #[test] + fn is_send_sync() { + fn is_send_sync() {} + is_send_sync::(); + } + + #[test] + fn token_right_size() { + assert_eq!(mem::size_of::(), mem::size_of::()); + } + + #[test] + fn timeout() { + let c = CompletionPort::new(1).unwrap(); + let err = c.get(Some(Duration::from_millis(1))).unwrap_err(); + assert_eq!(err.raw_os_error(), Some(WAIT_TIMEOUT as i32)); + } + + #[test] + fn get() { + let c = CompletionPort::new(1).unwrap(); + c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); + let s = c.get(None).unwrap(); + assert_eq!(s.bytes_transferred(), 1); + assert_eq!(s.token(), 2); + assert_eq!(s.overlapped(), 3 as *mut _); + } + + #[test] + fn get_many() { + let c = CompletionPort::new(1).unwrap(); + + c.post(CompletionStatus::new(1, 2, 3 as *mut _)).unwrap(); + c.post(CompletionStatus::new(4, 5, 6 as *mut _)).unwrap(); + + let mut s = vec![CompletionStatus::zero(); 4]; + { + let s = c.get_many(&mut s, None).unwrap(); + assert_eq!(s.len(), 2); + assert_eq!(s[0].bytes_transferred(), 1); + assert_eq!(s[0].token(), 2); + assert_eq!(s[0].overlapped(), 3 as *mut _); + assert_eq!(s[1].bytes_transferred(), 4); + assert_eq!(s[1].token(), 5); + assert_eq!(s[1].overlapped(), 6 as *mut _); + } + assert_eq!(s[2].bytes_transferred(), 0); + assert_eq!(s[2].token(), 0); + assert_eq!(s[2].overlapped(), 0 as *mut _); + } +} diff --git a/miow/src/lib.rs b/miow/src/lib.rs new file mode 100644 index 000000000..a0d53113c --- /dev/null +++ b/miow/src/lib.rs @@ -0,0 +1,57 @@ +//! A zero overhead Windows I/O library + +#![cfg(windows)] +#![deny(missing_docs)] +#![allow(bad_style)] +#![doc(html_root_url = "https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/")] + +extern crate socket2; +extern crate winapi; + +#[cfg(test)] extern crate rand; + +use std::cmp; +use std::io; +use std::time::Duration; + +use winapi::shared::minwindef::*; +use winapi::um::winbase::*; + +#[cfg(test)] +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + }) +} + +mod handle; +mod overlapped; + +pub mod iocp; +pub mod net; +pub mod pipe; + +pub use overlapped::Overlapped; + +fn cvt(i: BOOL) -> io::Result { + if i == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(i) + } +} + +fn dur2ms(dur: Option) -> u32 { + let dur = match dur { + Some(dur) => dur, + None => return INFINITE, + }; + let ms = dur.as_secs().checked_mul(1_000); + let ms_extra = dur.subsec_nanos() / 1_000_000; + ms.and_then(|ms| { + ms.checked_add(ms_extra as u64) + }).map(|ms| { + cmp::min(u32::max_value() as u64, ms) as u32 + }).unwrap_or(INFINITE - 1) +} diff --git a/miow/src/net.rs b/miow/src/net.rs new file mode 100644 index 000000000..37ca51bea --- /dev/null +++ b/miow/src/net.rs @@ -0,0 +1,1140 @@ +//! Extensions and types for the standard networking primitives. +//! +//! This module contains a number of extension traits for the types in +//! `std::net` for Windows-specific functionality. + +use std::cmp; +use std::io; +use std::mem; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; +use std::net::{TcpStream, UdpSocket, SocketAddr, TcpListener}; +use std::net::{SocketAddrV4, Ipv4Addr, SocketAddrV6, Ipv6Addr}; +use std::os::windows::prelude::*; + +use winapi::ctypes::*; +use winapi::shared::guiddef::*; +use winapi::shared::minwindef::*; +use winapi::shared::minwindef::{FALSE, TRUE}; +use winapi::shared::ntdef::*; +use winapi::shared::ws2def::*; +use winapi::shared::ws2def::SOL_SOCKET; +use winapi::shared::ws2ipdef::*; +use winapi::um::minwinbase::*; +use winapi::um::winsock2::*; + +/// A type to represent a buffer in which a socket address will be stored. +/// +/// This type is used with the `recv_from_overlapped` function on the +/// `UdpSocketExt` trait to provide space for the overlapped I/O operation to +/// fill in the address upon completion. +#[derive(Clone, Copy)] +pub struct SocketAddrBuf { + buf: SOCKADDR_STORAGE, + len: c_int, +} + +/// A type to represent a buffer in which an accepted socket's address will be +/// stored. +/// +/// This type is used with the `accept_overlapped` method on the +/// `TcpListenerExt` trait to provide space for the overlapped I/O operation to +/// fill in the socket addresses upon completion. +#[repr(C)] +pub struct AcceptAddrsBuf { + // For AcceptEx we've got the restriction that the addresses passed in that + // buffer need to be at least 16 bytes more than the maximum address length + // for the protocol in question, so add some extra here and there + local: SOCKADDR_STORAGE, + _pad1: [u8; 16], + remote: SOCKADDR_STORAGE, + _pad2: [u8; 16], +} + +/// The parsed return value of `AcceptAddrsBuf`. +pub struct AcceptAddrs<'a> { + local: LPSOCKADDR, + local_len: c_int, + remote: LPSOCKADDR, + remote_len: c_int, + _data: &'a AcceptAddrsBuf, +} + +struct WsaExtension { + guid: GUID, + val: AtomicUsize, +} + +/// Additional methods for the `TcpStream` type in the standard library. +pub trait TcpStreamExt { + /// Execute an overlapped read I/O operation on this TCP stream. + /// + /// This function will issue an overlapped I/O read (via `WSARecv`) on this + /// socket. The provided buffer will be filled in when the operation + /// completes and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned indicating how + /// many bytes were read. If the operation returns an error indicating that + /// the I/O is currently pending, `Ok(None)` is returned. Otherwise, the + /// error associated with the operation is returned and no overlapped + /// operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn read_overlapped(&self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Execute an overlapped write I/O operation on this TCP stream. + /// + /// This function will issue an overlapped I/O write (via `WSASend`) on this + /// socket. The provided buffer will be written when the operation completes + /// and the given `OVERLAPPED` instance is used to track the overlapped + /// operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were written. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn write_overlapped(&self, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Attempt to consume the internal socket in this builder by executing an + /// overlapped connect operation. + /// + /// This function will issue a connect operation to the address specified on + /// the underlying socket, flagging it as an overlapped operation which will + /// complete asynchronously. If successful this function will return the + /// corresponding TCP stream. + /// + /// The `buf` argument provided is an initial buffer of data that should be + /// sent after the connection is initiated. It's acceptable to + /// pass an empty slice here. + /// + /// This function will also return whether the connect immediately + /// succeeded or not. If `None` is returned then the I/O operation is still + /// pending and will complete at a later date, and if `Some(bytes)` is + /// returned then that many bytes were transferred. + /// + /// Note that to succeed this requires that the underlying socket has + /// previously been bound via a call to `bind` to a local address. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `overlapped` and `buf` pointers to be valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for + /// this I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that this pointer is + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + unsafe fn connect_overlapped(&self, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Once a `connect_overlapped` has finished, this function needs to be + /// called to finish the connect operation. + /// + /// Currently this just calls `setsockopt` with `SO_UPDATE_CONNECT_CONTEXT` + /// to ensure that further functions like `getpeername` and `getsockname` + /// work correctly. + fn connect_complete(&self) -> io::Result<()>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)>; +} + +/// Additional methods for the `UdpSocket` type in the standard library. +pub trait UdpSocketExt { + /// Execute an overlapped receive I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O read (via `WSARecvFrom`) on + /// this socket. The provided buffer will be filled in when the operation + /// completes, the source from where the data came from will be written to + /// `addr`, and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were read. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf`, + /// `addr`, and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn recv_from_overlapped(&self, + buf: &mut [u8], + addr: *mut SocketAddrBuf, + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Execute an overlapped receive I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O read (via `WSARecv`) on + /// this socket. The provided buffer will be filled in when the operation + /// completes, the source from where the data came from will be written to + /// `addr`, and the given `OVERLAPPED` instance is used to track the + /// overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n))` is returned where `n` is the + /// number of bytes that were read. If the operation returns an error + /// indicating that the I/O is currently pending, `Ok(None)` is returned. + /// Otherwise, the error associated with the operation is returned and no + /// overlapped operation is enqueued. + /// + /// The number of bytes read will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf`, + /// and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn recv_overlapped(&self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Execute an overlapped send I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O write (via `WSASendTo`) on + /// this socket to the address specified by `addr`. The provided buffer will + /// be written when the operation completes and the given `OVERLAPPED` + /// instance is used to track the overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte + /// were written. If the operation returns an error indicating that the I/O + /// is currently pending, `Ok(None)` is returned. Otherwise, the error + /// associated with the operation is returned and no overlapped operation + /// is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn send_to_overlapped(&self, + buf: &[u8], + addr: &SocketAddr, + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Execute an overlapped send I/O operation on this UDP socket. + /// + /// This function will issue an overlapped I/O write (via `WSASend`) on + /// this socket to the address it was previously connected to. The provided + /// buffer will be written when the operation completes and the given `OVERLAPPED` + /// instance is used to track the overlapped operation. + /// + /// If the operation succeeds, `Ok(Some(n0)` is returned where `n` byte + /// were written. If the operation returns an error indicating that the I/O + /// is currently pending, `Ok(None)` is returned. Otherwise, the error + /// associated with the operation is returned and no overlapped operation + /// is enqueued. + /// + /// The number of bytes written will be returned as part of the completion + /// notification when the I/O finishes. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers are valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that these two input + /// pointers are valid until the I/O operation is completed, typically via + /// completion ports and waiting to receive the completion notification on + /// the port. + unsafe fn send_overlapped(&self, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)>; +} + +/// Additional methods for the `TcpListener` type in the standard library. +pub trait TcpListenerExt { + /// Perform an accept operation on this listener, accepting a connection in + /// an overlapped fashion. + /// + /// This function will issue an I/O request to accept an incoming connection + /// with the specified overlapped instance. The `socket` provided must be a + /// configured but not bound or connected socket, and if successful this + /// will consume the internal socket of the builder to return a TCP stream. + /// + /// The `addrs` buffer provided will be filled in with the local and remote + /// addresses of the connection upon completion. + /// + /// If the accept succeeds immediately, `Ok(true)` is returned. If + /// the connect indicates that the I/O is currently pending, `Ok(false)` is + /// returned. Otherwise, the error associated with the operation is + /// returned and no overlapped operation is enqueued. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `addrs` and `overlapped` pointers are valid until the end of the I/O + /// operation. The kernel also requires that `overlapped` is unique for this + /// I/O operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + unsafe fn accept_overlapped(&self, + socket: &TcpStream, + addrs: &mut AcceptAddrsBuf, + overlapped: *mut OVERLAPPED) + -> io::Result; + + /// Once an `accept_overlapped` has finished, this function needs to be + /// called to finish the accept operation. + /// + /// Currently this just calls `setsockopt` with `SO_UPDATE_ACCEPT_CONTEXT` + /// to ensure that further functions like `getpeername` and `getsockname` + /// work correctly. + fn accept_complete(&self, socket: &TcpStream) -> io::Result<()>; + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred, along with the results of the `lpFlags` parameter of + /// the relevant operation, if applicable. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `OVERLAPPED` instance. + /// + /// # Panics + /// + /// This function will panic + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)>; +} + +#[doc(hidden)] +trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +// fn hton(i: I) -> I { i.to_be() } +fn ntoh(i: I) -> I { I::from_be(i) } + +fn last_err() -> io::Result> { + let err = unsafe { WSAGetLastError() }; + if err == WSA_IO_PENDING as i32 { + Ok(None) + } else { + Err(io::Error::from_raw_os_error(err)) + } +} + +fn cvt(i: c_int, size: DWORD) -> io::Result> { + if i == SOCKET_ERROR { + last_err() + } else { + Ok(Some(size as usize)) + } +} + +fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) { + match *addr { + SocketAddr::V4(ref a) => { + (a as *const _ as *const _, mem::size_of::() as c_int) + } + SocketAddr::V6(ref a) => { + (a as *const _ as *const _, mem::size_of::() as c_int) + } + } +} + +unsafe fn ptrs_to_socket_addr(ptr: *const SOCKADDR, + len: c_int) -> Option { + if (len as usize) < mem::size_of::() { + return None + } + match (*ptr).sa_family as i32 { + AF_INET if len as usize >= mem::size_of::() => { + let b = &*(ptr as *const SOCKADDR_IN); + let ip = ntoh(*b.sin_addr.S_un.S_addr()); + let ip = Ipv4Addr::new((ip >> 24) as u8, + (ip >> 16) as u8, + (ip >> 8) as u8, + (ip >> 0) as u8); + Some(SocketAddr::V4(SocketAddrV4::new(ip, ntoh(b.sin_port)))) + } + AF_INET6 if len as usize >= mem::size_of::() => { + let b = &*(ptr as *const SOCKADDR_IN6_LH); + let arr = b.sin6_addr.u.Byte(); + let ip = Ipv6Addr::new( + ((arr[0] as u16) << 8) | (arr[1] as u16), + ((arr[2] as u16) << 8) | (arr[3] as u16), + ((arr[4] as u16) << 8) | (arr[5] as u16), + ((arr[6] as u16) << 8) | (arr[7] as u16), + ((arr[8] as u16) << 8) | (arr[9] as u16), + ((arr[10] as u16) << 8) | (arr[11] as u16), + ((arr[12] as u16) << 8) | (arr[13] as u16), + ((arr[14] as u16) << 8) | (arr[15] as u16)); + let addr = SocketAddrV6::new(ip, ntoh(b.sin6_port), + ntoh(b.sin6_flowinfo), + ntoh(*b.u.sin6_scope_id())); + Some(SocketAddr::V6(addr)) + } + _ => None + } +} + +unsafe fn slice2buf(slice: &[u8]) -> WSABUF { + WSABUF { + len: cmp::min(slice.len(), ::max_value() as usize) as u_long, + buf: slice.as_ptr() as *mut _, + } +} + +unsafe fn result(socket: SOCKET, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)> { + let mut transferred = 0; + let mut flags = 0; + let r = WSAGetOverlappedResult(socket, + overlapped, + &mut transferred, + FALSE, + &mut flags); + if r == 0 { + Err(io::Error::last_os_error()) + } else { + Ok((transferred as usize, flags)) + } +} + +impl TcpStreamExt for TcpStream { + unsafe fn read_overlapped(&self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut bytes_read: DWORD = 0; + let r = WSARecv(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut bytes_read, &mut flags, overlapped, None); + cvt(r, bytes_read) + } + + unsafe fn write_overlapped(&self, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + let mut buf = slice2buf(buf); + let mut bytes_written = 0; + + // Note here that we capture the number of bytes written. The + // documentation on MSDN, however, states: + // + // > Use NULL for this parameter if the lpOverlapped parameter is not + // > NULL to avoid potentially erroneous results. This parameter can be + // > NULL only if the lpOverlapped parameter is not NULL. + // + // If we're not passing a null overlapped pointer here, then why are we + // then capturing the number of bytes! Well so it turns out that this is + // clearly faster to learn the bytes here rather than later calling + // `WSAGetOverlappedResult`, and in practice almost all implementations + // use this anyway [1]. + // + // As a result we use this to and report back the result. + // + // [1]: https://github.com/carllerche/mio/pull/520#issuecomment-273983823 + let r = WSASend(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut bytes_written, 0, overlapped, None); + cvt(r, bytes_written) + } + + unsafe fn connect_overlapped(&self, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + connect_overlapped(self.as_raw_socket() as SOCKET, addr, buf, overlapped) + } + + fn connect_complete(&self) -> io::Result<()> { + const SO_UPDATE_CONNECT_CONTEXT: c_int = 0x7010; + let result = unsafe { + setsockopt(self.as_raw_socket() as SOCKET, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + 0 as *const _, + 0) + }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +unsafe fn connect_overlapped(socket: SOCKET, + addr: &SocketAddr, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + static CONNECTEX: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0x25a207b9, + Data2: 0xddf3, + Data3: 0x4660, + Data4: [0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e], + }, + val: ATOMIC_USIZE_INIT, + }; + type ConnectEx = unsafe extern "system" fn(SOCKET, *const SOCKADDR, + c_int, PVOID, DWORD, LPDWORD, + LPOVERLAPPED) -> BOOL; + + let ptr = try!(CONNECTEX.get(socket)); + assert!(ptr != 0); + let connect_ex = mem::transmute::<_, ConnectEx>(ptr); + + let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); + let mut bytes_sent: DWORD = 0; + let r = connect_ex(socket, addr_buf, addr_len, + buf.as_ptr() as *mut _, + buf.len() as u32, + &mut bytes_sent, overlapped); + if r == TRUE { + Ok(Some(bytes_sent as usize)) + } else { + last_err() + } +} + +impl UdpSocketExt for UdpSocket { + unsafe fn recv_from_overlapped(&self, + buf: &mut [u8], + addr: *mut SocketAddrBuf, + overlapped: *mut OVERLAPPED) + -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut received_bytes: DWORD = 0; + let r = WSARecvFrom(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut received_bytes, &mut flags, + &mut (*addr).buf as *mut _ as *mut _, + &mut (*addr).len, + overlapped, None); + cvt(r, received_bytes) + } + + unsafe fn recv_overlapped(&self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + let mut buf = slice2buf(buf); + let mut flags = 0; + let mut received_bytes: DWORD = 0; + let r = WSARecv(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut received_bytes, &mut flags, + overlapped, None); + cvt(r, received_bytes) + } + + unsafe fn send_to_overlapped(&self, + buf: &[u8], + addr: &SocketAddr, + overlapped: *mut OVERLAPPED) + -> io::Result> { + let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); + let mut buf = slice2buf(buf); + let mut sent_bytes = 0; + let r = WSASendTo(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut sent_bytes, 0, + addr_buf as *const _, addr_len, + overlapped, None); + cvt(r, sent_bytes) + } + + unsafe fn send_overlapped(&self, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + let mut buf = slice2buf(buf); + let mut sent_bytes = 0; + let r = WSASend(self.as_raw_socket() as SOCKET, &mut buf, 1, + &mut sent_bytes, 0, + overlapped, None); + cvt(r, sent_bytes) + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +impl TcpListenerExt for TcpListener { + unsafe fn accept_overlapped(&self, + socket: &TcpStream, + addrs: &mut AcceptAddrsBuf, + overlapped: *mut OVERLAPPED) + -> io::Result { + static ACCEPTEX: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0xb5367df1, + Data2: 0xcbac, + Data3: 0x11cf, + Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], + }, + val: ATOMIC_USIZE_INIT, + }; + type AcceptEx = unsafe extern "system" fn(SOCKET, SOCKET, PVOID, + DWORD, DWORD, DWORD, LPDWORD, + LPOVERLAPPED) -> BOOL; + + let ptr = try!(ACCEPTEX.get(self.as_raw_socket() as SOCKET)); + assert!(ptr != 0); + let accept_ex = mem::transmute::<_, AcceptEx>(ptr); + + let mut bytes = 0; + let (a, b, c, d) = (*addrs).args(); + let r = accept_ex(self.as_raw_socket() as SOCKET, socket.as_raw_socket() as SOCKET, + a, b, c, d, &mut bytes, overlapped); + let succeeded = if r == TRUE { + true + } else { + try!(last_err()); + false + }; + Ok(succeeded) + } + + fn accept_complete(&self, socket: &TcpStream) -> io::Result<()> { + const SO_UPDATE_ACCEPT_CONTEXT: c_int = 0x700B; + let me = self.as_raw_socket(); + let result = unsafe { + setsockopt(socket.as_raw_socket() as SOCKET, + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + &me as *const _ as *const _, + mem::size_of_val(&me) as c_int) + }; + if result == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + + unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result<(usize, u32)> { + result(self.as_raw_socket() as SOCKET, overlapped) + } +} + +impl SocketAddrBuf { + /// Creates a new blank socket address buffer. + /// + /// This should be used before a call to `recv_from_overlapped` overlapped + /// to create an instance to pass down. + pub fn new() -> SocketAddrBuf { + SocketAddrBuf { + buf: unsafe { mem::zeroed() }, + len: mem::size_of::() as c_int, + } + } + + /// Parses this buffer to return a standard socket address. + /// + /// This function should be called after the buffer has been filled in with + /// a call to `recv_from_overlapped` being completed. It will interpret the + /// address filled in and return the standard socket address type. + /// + /// If an error is encountered then `None` is returned. + pub fn to_socket_addr(&self) -> Option { + unsafe { + ptrs_to_socket_addr(&self.buf as *const _ as *const _, self.len) + } + } +} + +static GETACCEPTEXSOCKADDRS: WsaExtension = WsaExtension { + guid: GUID { + Data1: 0xb5367df2, + Data2: 0xcbac, + Data3: 0x11cf, + Data4: [0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92], + }, + val: ATOMIC_USIZE_INIT, +}; +type GetAcceptExSockaddrs = unsafe extern "system" fn(PVOID, DWORD, DWORD, DWORD, + *mut LPSOCKADDR, LPINT, + *mut LPSOCKADDR, LPINT); + +impl AcceptAddrsBuf { + /// Creates a new blank buffer ready to be passed to a call to + /// `accept_overlapped`. + pub fn new() -> AcceptAddrsBuf { + unsafe { mem::zeroed() } + } + + /// Parses the data contained in this address buffer, returning the parsed + /// result if successful. + /// + /// This function can be called after a call to `accept_overlapped` has + /// succeeded to parse out the data that was written in. + pub fn parse(&self, socket: &TcpListener) -> io::Result { + let mut ret = AcceptAddrs { + local: 0 as *mut _, local_len: 0, + remote: 0 as *mut _, remote_len: 0, + _data: self, + }; + let ptr = try!(GETACCEPTEXSOCKADDRS.get(socket.as_raw_socket() as SOCKET)); + assert!(ptr != 0); + unsafe { + let get_sockaddrs = mem::transmute::<_, GetAcceptExSockaddrs>(ptr); + let (a, b, c, d) = self.args(); + get_sockaddrs(a, b, c, d, + &mut ret.local, &mut ret.local_len, + &mut ret.remote, &mut ret.remote_len); + Ok(ret) + } + } + + fn args(&self) -> (PVOID, DWORD, DWORD, DWORD) { + let remote_offset = unsafe { + &(*(0 as *const AcceptAddrsBuf)).remote as *const _ as usize + }; + (self as *const _ as *mut _, 0, remote_offset as DWORD, + (mem::size_of_val(self) - remote_offset) as DWORD) + } +} + +impl<'a> AcceptAddrs<'a> { + /// Returns the local socket address contained in this buffer. + pub fn local(&self) -> Option { + unsafe { ptrs_to_socket_addr(self.local, self.local_len) } + } + + /// Returns the remote socket address contained in this buffer. + pub fn remote(&self) -> Option { + unsafe { ptrs_to_socket_addr(self.remote, self.remote_len) } + } +} + +impl WsaExtension { + fn get(&self, socket: SOCKET) -> io::Result { + let prev = self.val.load(Ordering::SeqCst); + if prev != 0 && !cfg!(debug_assertions) { + return Ok(prev) + } + let mut ret = 0 as usize; + let mut bytes = 0; + let r = unsafe { + WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, + &self.guid as *const _ as *mut _, + mem::size_of_val(&self.guid) as DWORD, + &mut ret as *mut _ as *mut _, + mem::size_of_val(&ret) as DWORD, + &mut bytes, + 0 as *mut _, None) + }; + cvt(r, 0).map(|_| { + debug_assert_eq!(bytes as usize, mem::size_of_val(&ret)); + debug_assert!(prev == 0 || prev == ret); + self.val.store(ret, Ordering::SeqCst); + ret + }) + + } +} + +#[cfg(test)] +mod tests { + use std::net::{TcpListener, UdpSocket, TcpStream, SocketAddr}; + use std::thread; + use std::io::prelude::*; + + use socket2::{Socket, Type, Domain}; + + use Overlapped; + use iocp::CompletionPort; + use net::{TcpStreamExt, UdpSocketExt, SocketAddrBuf}; + use net::{TcpListenerExt, AcceptAddrsBuf}; + + fn each_ip(f: &mut FnMut(SocketAddr)) { + f(t!("127.0.0.1:0".parse())); + f(t!("[::1]:0".parse())); + } + + #[test] + fn tcp_read() { + each_ip(&mut |addr| { + let l = t!(TcpListener::bind(addr)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let mut a = t!(l.accept()).0; + t!(a.write_all(&[1, 2, 3])); + }); + + let cp = t!(CompletionPort::new(1)); + let s = t!(TcpStream::connect(addr)); + t!(cp.add_socket(1, &s)); + + let mut b = [0; 10]; + let a = Overlapped::zero(); + unsafe { + t!(s.read_overlapped(&mut b, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&b[0..3], &[1, 2, 3]); + + t!(t.join()); + }) + } + + #[test] + fn tcp_write() { + each_ip(&mut |addr| { + let l = t!(TcpListener::bind(addr)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let mut a = t!(l.accept()).0; + let mut b = [0; 10]; + let n = t!(a.read(&mut b)); + assert_eq!(n, 3); + assert_eq!(&b[0..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + let s = t!(TcpStream::connect(addr)); + t!(cp.add_socket(1, &s)); + + let b = [1, 2, 3]; + let a = Overlapped::zero(); + unsafe { + t!(s.write_overlapped(&b, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn tcp_connect() { + each_ip(&mut |addr_template| { + let l = t!(TcpListener::bind(addr_template)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + t!(l.accept()); + }); + + let cp = t!(CompletionPort::new(1)); + let domain = match addr { + SocketAddr::V4(..) => Domain::ipv4(), + SocketAddr::V6(..) => Domain::ipv6(), + }; + let socket = t!(Socket::new(domain, Type::stream(), None)); + t!(socket.bind(&addr_template.into())); + let socket = socket.into_tcp_stream(); + t!(cp.add_socket(1, &socket)); + + let a = Overlapped::zero(); + unsafe { + t!(socket.connect_overlapped(&addr, &[], a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + t!(socket.connect_complete()); + + t!(t.join()); + }) + } + + #[test] + fn udp_recv_from() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + let t = thread::spawn(move || { + t!(a.send_to(&[1, 2, 3], b_addr)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let mut buf = [0; 10]; + let a = Overlapped::zero(); + let mut addr = SocketAddrBuf::new(); + unsafe { + t!(b.recv_from_overlapped(&mut buf, &mut addr, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&buf[..3], &[1, 2, 3]); + assert_eq!(addr.to_socket_addr(), Some(a_addr)); + + t!(t.join()); + }) + } + + #[test] + fn udp_recv() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + assert!(b.connect(a_addr).is_ok()); + assert!(a.connect(b_addr).is_ok()); + let t = thread::spawn(move || { + t!(a.send_to(&[1, 2, 3], b_addr)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let mut buf = [0; 10]; + let a = Overlapped::zero(); + unsafe { + t!(b.recv_overlapped(&mut buf, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + assert_eq!(&buf[..3], &[1, 2, 3]); + + t!(t.join()); + }) + } + + #[test] + fn udp_send_to() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + let t = thread::spawn(move || { + let mut b = [0; 100]; + let (n, addr) = t!(a.recv_from(&mut b)); + assert_eq!(n, 3); + assert_eq!(addr, b_addr); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let a = Overlapped::zero(); + unsafe { + t!(b.send_to_overlapped(&[1, 2, 3], &a_addr, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn udp_send() { + each_ip(&mut |addr| { + let a = t!(UdpSocket::bind(addr)); + let b = t!(UdpSocket::bind(addr)); + let a_addr = t!(a.local_addr()); + let b_addr = t!(b.local_addr()); + assert!(b.connect(a_addr).is_ok()); + assert!(a.connect(b_addr).is_ok()); + let t = thread::spawn(move || { + let mut b = [0; 100]; + let (n, addr) = t!(a.recv_from(&mut b)); + assert_eq!(n, 3); + assert_eq!(addr, b_addr); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_socket(1, &b)); + + let a = Overlapped::zero(); + unsafe { + t!(b.send_overlapped(&[1, 2, 3], a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + + t!(t.join()); + }) + } + + #[test] + fn tcp_accept() { + each_ip(&mut |addr_template| { + let l = t!(TcpListener::bind(addr_template)); + let addr = t!(l.local_addr()); + let t = thread::spawn(move || { + let socket = t!(TcpStream::connect(addr)); + (socket.local_addr().unwrap(), socket.peer_addr().unwrap()) + }); + + let cp = t!(CompletionPort::new(1)); + let domain = match addr { + SocketAddr::V4(..) => Domain::ipv4(), + SocketAddr::V6(..) => Domain::ipv6(), + }; + let socket = t!(Socket::new(domain, Type::stream(), None)) + .into_tcp_stream(); + t!(cp.add_socket(1, &l)); + + let a = Overlapped::zero(); + let mut addrs = AcceptAddrsBuf::new(); + unsafe { + t!(l.accept_overlapped(&socket, &mut addrs, a.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 1); + assert_eq!(status.overlapped(), a.raw()); + t!(l.accept_complete(&socket)); + + let (remote, local) = t!(t.join()); + let addrs = addrs.parse(&l).unwrap(); + assert_eq!(addrs.local(), Some(local)); + assert_eq!(addrs.remote(), Some(remote)); + }) + } +} diff --git a/miow/src/overlapped.rs b/miow/src/overlapped.rs new file mode 100644 index 000000000..68c54df3b --- /dev/null +++ b/miow/src/overlapped.rs @@ -0,0 +1,95 @@ +use std::fmt; +use std::io; +use std::mem; +use std::ptr; + +use winapi::shared::ntdef::{ + HANDLE, + NULL, +}; +use winapi::um::minwinbase::*; +use winapi::um::synchapi::*; + +/// A wrapper around `OVERLAPPED` to provide "rustic" accessors and +/// initializers. +pub struct Overlapped(OVERLAPPED); + +impl fmt::Debug for Overlapped { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OVERLAPPED") + } +} + +unsafe impl Send for Overlapped {} +unsafe impl Sync for Overlapped {} + +impl Overlapped { + /// Creates a new zeroed out instance of an overlapped I/O tracking state. + /// + /// This is suitable for passing to methods which will then later get + /// notified via an I/O Completion Port. + pub fn zero() -> Overlapped { + Overlapped(unsafe { mem::zeroed() }) + } + + /// Creates a new `Overlapped` with an initialized non-null `hEvent`. The caller is + /// responsible for calling `CloseHandle` on the `hEvent` field of the returned + /// `Overlapped`. The event is created with `bManualReset` set to `FALSE`, meaning after a + /// single thread waits on the event, it will be reset. + pub fn initialize_with_autoreset_event() -> io::Result { + let event = unsafe {CreateEventW(ptr::null_mut(), 0i32, 0i32, ptr::null())}; + if event == NULL { + return Err(io::Error::last_os_error()); + } + let mut overlapped = Self::zero(); + overlapped.set_event(event); + Ok(overlapped) + } + + /// Creates a new `Overlapped` function pointer from the underlying + /// `OVERLAPPED`, wrapping in the "rusty" wrapper for working with + /// accessors. + /// + /// # Unsafety + /// + /// This function doesn't validate `ptr` nor the lifetime of the returned + /// pointer at all, it's recommended to use this method with extreme + /// caution. + pub unsafe fn from_raw<'a>(ptr: *mut OVERLAPPED) -> &'a mut Overlapped { + &mut *(ptr as *mut Overlapped) + } + + /// Gain access to the raw underlying data + pub fn raw(&self) -> *mut OVERLAPPED { + &self.0 as *const _ as *mut _ + } + + /// Sets the offset inside this overlapped structure. + /// + /// Note that for I/O operations in general this only has meaning for I/O + /// handles that are on a seeking device that supports the concept of an + /// offset. + pub fn set_offset(&mut self, offset: u64) { + let s = unsafe { self.0.u.s_mut() }; + s.Offset = offset as u32; + s.OffsetHigh = (offset >> 32) as u32; + } + + /// Reads the offset inside this overlapped structure. + pub fn offset(&self) -> u64 { + let s = unsafe { self.0.u.s() }; + (s.Offset as u64) | ((s.OffsetHigh as u64) << 32) + } + + /// Sets the `hEvent` field of this structure. + /// + /// The event specified can be null. + pub fn set_event(&mut self, event: HANDLE) { + self.0.hEvent = event; + } + + /// Reads the `hEvent` field of this structure, may return null. + pub fn event(&self) -> HANDLE { + self.0.hEvent + } +} diff --git a/miow/src/pipe.rs b/miow/src/pipe.rs new file mode 100644 index 000000000..479789287 --- /dev/null +++ b/miow/src/pipe.rs @@ -0,0 +1,716 @@ +//! Named pipes + +use std::cell::RefCell; +use std::ffi::OsStr; +use std::fs::{OpenOptions, File}; +use std::io::prelude::*; +use std::io; +use std::os::windows::ffi::*; +use std::os::windows::io::*; +use std::time::Duration; + +use winapi::shared::ntdef::HANDLE; +use winapi::shared::minwindef::*; +use winapi::shared::winerror::*; +use winapi::um::fileapi::*; +use winapi::um::handleapi::*; +use winapi::um::ioapiset::*; +use winapi::um::minwinbase::*; +use winapi::um::namedpipeapi::*; +use winapi::um::winbase::*; +use handle::Handle; +use overlapped::Overlapped; + +/// Readable half of an anonymous pipe. +#[derive(Debug)] +pub struct AnonRead(Handle); + +/// Writable half of an anonymous pipe. +#[derive(Debug)] +pub struct AnonWrite(Handle); + +/// A named pipe that can accept connections. +#[derive(Debug)] +pub struct NamedPipe(Handle); + +/// A builder structure for creating a new named pipe. +#[derive(Debug)] +pub struct NamedPipeBuilder { + name: Vec, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, +} + +/// Creates a new anonymous in-memory pipe, returning the read/write ends of the +/// pipe. +/// +/// The buffer size for this pipe may also be specified, but the system will +/// normally use this as a suggestion and it's not guaranteed that the buffer +/// will be precisely this size. +pub fn anonymous(buffer_size: u32) -> io::Result<(AnonRead, AnonWrite)> { + let mut read = 0 as HANDLE; + let mut write = 0 as HANDLE; + try!(::cvt(unsafe { + CreatePipe(&mut read, &mut write, 0 as *mut _, buffer_size) + })); + Ok((AnonRead(Handle::new(read)), AnonWrite(Handle::new(write)))) +} + +impl Read for AnonRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } +} +impl<'a> Read for &'a AnonRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } +} + +impl AsRawHandle for AnonRead { + fn as_raw_handle(&self) -> HANDLE { self.0.raw() } +} +impl FromRawHandle for AnonRead { + unsafe fn from_raw_handle(handle: HANDLE) -> AnonRead { + AnonRead(Handle::new(handle)) + } +} +impl IntoRawHandle for AnonRead { + fn into_raw_handle(self) -> HANDLE { self.0.into_raw() } +} + +impl Write for AnonWrite { + fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} +impl<'a> Write for &'a AnonWrite { + fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +impl AsRawHandle for AnonWrite { + fn as_raw_handle(&self) -> HANDLE { self.0.raw() } +} +impl FromRawHandle for AnonWrite { + unsafe fn from_raw_handle(handle: HANDLE) -> AnonWrite { + AnonWrite(Handle::new(handle)) + } +} +impl IntoRawHandle for AnonWrite { + fn into_raw_handle(self) -> HANDLE { self.0.into_raw() } +} + +/// A convenience function to connect to a named pipe. +/// +/// This function will block the calling process until it can connect to the +/// pipe server specified by `addr`. This will use `NamedPipe::wait` internally +/// to block until it can connect. +pub fn connect>(addr: A) -> io::Result { + _connect(addr.as_ref()) +} + +fn _connect(addr: &OsStr) -> io::Result { + let mut r = OpenOptions::new(); + let mut w = OpenOptions::new(); + let mut rw = OpenOptions::new(); + r.read(true); + w.write(true); + rw.read(true).write(true); + loop { + let res = rw.open(addr).or_else(|_| r.open(addr)) + .or_else(|_| w.open(addr)); + match res { + Ok(f) => return Ok(f), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) + => {} + Err(e) => return Err(e), + } + + try!(NamedPipe::wait(addr, Some(Duration::new(20, 0)))); + } +} + +impl NamedPipe { + /// Creates a new initial named pipe. + /// + /// This function is equivalent to: + /// + /// ``` + /// use miow::pipe::NamedPipeBuilder; + /// + /// # let addr = "foo"; + /// NamedPipeBuilder::new(addr) + /// .first(true) + /// .inbound(true) + /// .outbound(true) + /// .out_buffer_size(65536) + /// .in_buffer_size(65536) + /// .create(); + /// ``` + pub fn new>(addr: A) -> io::Result { + NamedPipeBuilder::new(addr).create() + } + + /// Waits until either a time-out interval elapses or an instance of the + /// specified named pipe is available for connection. + /// + /// If this function succeeds the process can create a `File` to connect to + /// the named pipe. + pub fn wait>(addr: A, timeout: Option) + -> io::Result<()> { + NamedPipe::_wait(addr.as_ref(), timeout) + } + + fn _wait(addr: &OsStr, timeout: Option) -> io::Result<()> { + let addr = addr.encode_wide().chain(Some(0)).collect::>(); + let timeout = ::dur2ms(timeout); + ::cvt(unsafe { + WaitNamedPipeW(addr.as_ptr(), timeout) + }).map(|_| ()) + } + + /// Connects this named pipe to a client, blocking until one becomes + /// available. + /// + /// This function will call the `ConnectNamedPipe` function to await for a + /// client to connect. This can be called immediately after the pipe is + /// created, or after it has been disconnected from a previous client. + pub fn connect(&self) -> io::Result<()> { + match ::cvt(unsafe { ConnectNamedPipe(self.0.raw(), 0 as *mut _) }) { + Ok(_) => Ok(()), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) + => Ok(()), + Err(e) => Err(e), + } + } + + /// Issue a connection request with the specified overlapped operation. + /// + /// This function will issue a request to connect a client to this server, + /// returning immediately after starting the overlapped operation. + /// + /// If this function immediately succeeds then `Ok(true)` is returned. If + /// the overlapped operation is enqueued and pending, then `Ok(false)` is + /// returned. Otherwise an error is returned indicating what went wrong. + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the + /// `overlapped` pointer is valid until the end of the I/O operation. The + /// kernel also requires that `overlapped` is unique for this I/O operation + /// and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that this pointer is + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn connect_overlapped(&self, overlapped: *mut OVERLAPPED) + -> io::Result { + match ::cvt(ConnectNamedPipe(self.0.raw(), overlapped)) { + Ok(_) => Ok(true), + Err(ref e) if e.raw_os_error() == Some(ERROR_PIPE_CONNECTED as i32) + => Ok(true), + Err(ref e) if e.raw_os_error() == Some(ERROR_IO_PENDING as i32) + => Ok(false), + Err(e) => Err(e), + } + } + + /// Disconnects this named pipe from any connected client. + pub fn disconnect(&self) -> io::Result<()> { + ::cvt(unsafe { + DisconnectNamedPipe(self.0.raw()) + }).map(|_| ()) + } + + /// Issues an overlapped read operation to occur on this pipe. + /// + /// This function will issue an asynchronous read to occur in an overlapped + /// fashion, returning immediately. The `buf` provided will be filled in + /// with data and the request is tracked by the `overlapped` function + /// provided. + /// + /// If the operation succeeds immediately, `Ok(Some(n))` is returned where + /// `n` is the number of bytes read. If an asynchronous operation is + /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred + /// it is returned. + /// + /// When this operation completes (or if it completes immediately), another + /// mechanism must be used to learn how many bytes were transferred (such as + /// looking at the filed in the IOCP status message). + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers to be valid until the end of the I/O operation. + /// The kernel also requires that `overlapped` is unique for this I/O + /// operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn read_overlapped(&self, + buf: &mut [u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + self.0.read_overlapped(buf, overlapped) + } + + /// Issues an overlapped write operation to occur on this pipe. + /// + /// This function will issue an asynchronous write to occur in an overlapped + /// fashion, returning immediately. The `buf` provided will be filled in + /// with data and the request is tracked by the `overlapped` function + /// provided. + /// + /// If the operation succeeds immediately, `Ok(Some(n))` is returned where + /// `n` is the number of bytes written. If an asynchronous operation is + /// enqueued, then `Ok(None)` is returned. Otherwise if an error occurred + /// it is returned. + /// + /// When this operation completes (or if it completes immediately), another + /// mechanism must be used to learn how many bytes were transferred (such as + /// looking at the filed in the IOCP status message). + /// + /// # Unsafety + /// + /// This function is unsafe because the kernel requires that the `buf` and + /// `overlapped` pointers to be valid until the end of the I/O operation. + /// The kernel also requires that `overlapped` is unique for this I/O + /// operation and is not in use for any other I/O. + /// + /// To safely use this function callers must ensure that the pointers are + /// valid until the I/O operation is completed, typically via completion + /// ports and waiting to receive the completion notification on the port. + pub unsafe fn write_overlapped(&self, + buf: &[u8], + overlapped: *mut OVERLAPPED) + -> io::Result> { + self.0.write_overlapped(buf, overlapped) + } + + /// Calls the `GetOverlappedResult` function to get the result of an + /// overlapped operation for this handle. + /// + /// This function takes the `OVERLAPPED` argument which must have been used + /// to initiate an overlapped I/O operation, and returns either the + /// successful number of bytes transferred during the operation or an error + /// if one occurred. + /// + /// # Unsafety + /// + /// This function is unsafe as `overlapped` must have previously been used + /// to execute an operation for this handle, and it must also be a valid + /// pointer to an `Overlapped` instance. + /// + /// # Panics + /// + /// This function will panic + pub unsafe fn result(&self, overlapped: *mut OVERLAPPED) + -> io::Result { + let mut transferred = 0; + let r = GetOverlappedResult(self.0.raw(), + overlapped, + &mut transferred, + FALSE); + if r == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(transferred as usize) + } + } +} + +thread_local! { + static NAMED_PIPE_OVERLAPPED: RefCell> = RefCell::new(None); +} + +/// Call a function with a threadlocal `Overlapped`. The function `f` should be +/// sure that the event is reset, either manually or by a thread being released. +fn with_threadlocal_overlapped(f: F) -> io::Result + where F: FnOnce(&Overlapped) -> io::Result +{ + NAMED_PIPE_OVERLAPPED.with(|overlapped| { + let mut mborrow = overlapped.borrow_mut(); + if let None = *mborrow { + let op = Overlapped::initialize_with_autoreset_event()?; + *mborrow = Some(op); + } + f(mborrow.as_ref().unwrap()) + }) +} + +impl Read for NamedPipe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0.read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } +} +impl<'a> Read for &'a NamedPipe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0.read_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } +} + +impl Write for NamedPipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0.write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } + fn flush(&mut self) -> io::Result<()> { + <&NamedPipe as Write>::flush(&mut &*self) + } +} +impl<'a> Write for &'a NamedPipe { + fn write(&mut self, buf: &[u8]) -> io::Result { + // This is necessary because the pipe is opened with `FILE_FLAG_OVERLAPPED`. + with_threadlocal_overlapped(|overlapped| unsafe { + self.0.write_overlapped_wait(buf, overlapped.raw() as *mut OVERLAPPED) + }) + } + fn flush(&mut self) -> io::Result<()> { + ::cvt(unsafe { FlushFileBuffers(self.0.raw()) }).map(|_| ()) + } +} + +impl AsRawHandle for NamedPipe { + fn as_raw_handle(&self) -> HANDLE { self.0.raw() } +} +impl FromRawHandle for NamedPipe { + unsafe fn from_raw_handle(handle: HANDLE) -> NamedPipe { + NamedPipe(Handle::new(handle)) + } +} +impl IntoRawHandle for NamedPipe { + fn into_raw_handle(self) -> HANDLE { self.0.into_raw() } +} + +fn flag(slot: &mut DWORD, on: bool, val: DWORD) { + if on { + *slot |= val; + } else { + *slot &= !val; + } +} + +impl NamedPipeBuilder { + /// Creates a new named pipe builder with the default settings. + pub fn new>(addr: A) -> NamedPipeBuilder { + NamedPipeBuilder { + name: addr.as_ref().encode_wide().chain(Some(0)).collect(), + dwOpenMode: PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | + FILE_FLAG_OVERLAPPED, + dwPipeMode: PIPE_TYPE_BYTE, + nMaxInstances: PIPE_UNLIMITED_INSTANCES, + nOutBufferSize: 65536, + nInBufferSize: 65536, + nDefaultTimeOut: 0, + } + } + + /// Indicates whether data is allowed to flow from the client to the server. + pub fn inbound(&mut self, allowed: bool) -> &mut Self { + flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_INBOUND); + self + } + + /// Indicates whether data is allowed to flow from the server to the client. + pub fn outbound(&mut self, allowed: bool) -> &mut Self { + flag(&mut self.dwOpenMode, allowed, PIPE_ACCESS_OUTBOUND); + self + } + + /// Indicates that this pipe must be the first instance. + /// + /// If set to true, then creation will fail if there's already an instance + /// elsewhere. + pub fn first(&mut self, first: bool) -> &mut Self { + flag(&mut self.dwOpenMode, first, FILE_FLAG_FIRST_PIPE_INSTANCE); + self + } + + /// Indicates whether this server can accept remote clients or not. + pub fn accept_remote(&mut self, accept: bool) -> &mut Self { + flag(&mut self.dwPipeMode, !accept, PIPE_REJECT_REMOTE_CLIENTS); + self + } + + /// Specifies the maximum number of instances of the server pipe that are + /// allowed. + /// + /// The first instance of a pipe can specify this value. A value of 255 + /// indicates that there is no limit to the number of instances. + pub fn max_instances(&mut self, instances: u8) -> &mut Self { + self.nMaxInstances = instances as DWORD; + self + } + + /// Specifies the number of bytes to reserver for the output buffer + pub fn out_buffer_size(&mut self, buffer: u32) -> &mut Self { + self.nOutBufferSize = buffer as DWORD; + self + } + + /// Specifies the number of bytes to reserver for the input buffer + pub fn in_buffer_size(&mut self, buffer: u32) -> &mut Self { + self.nInBufferSize = buffer as DWORD; + self + } + + /// Using the options in this builder, attempt to create a new named pipe. + /// + /// This function will call the `CreateNamedPipe` function and return the + /// result. + pub fn create(&mut self) -> io::Result { + unsafe { self.with_security_attributes(::std::ptr::null_mut()) } + } + + /// Using the options in the builder and the provided security attributes, attempt to create a + /// new named pipe. This function has to be called with a valid pointer to a + /// `SECURITY_ATTRIBUTES` struct that will stay valid for the lifetime of this function or a + /// null pointer. + /// + /// This function will call the `CreateNamedPipe` function and return the + /// result. + pub unsafe fn with_security_attributes(&mut self, attrs: *mut SECURITY_ATTRIBUTES) -> io::Result { + let h = CreateNamedPipeW(self.name.as_ptr(), + self.dwOpenMode, self.dwPipeMode, + self.nMaxInstances, self.nOutBufferSize, + self.nInBufferSize, self.nDefaultTimeOut, + attrs); + + if h == INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) + } else { + Ok(NamedPipe(Handle::new(h))) + } + } +} + +#[cfg(test)] +mod tests { + use std::fs::{File, OpenOptions}; + use std::io::prelude::*; + use std::sync::mpsc::channel; + use std::thread; + use std::time::Duration; + + use rand::{thread_rng, Rng}; + + use super::{anonymous, NamedPipe, NamedPipeBuilder}; + use iocp::CompletionPort; + use Overlapped; + + fn name() -> String { + let name = thread_rng().gen_ascii_chars().take(30).collect::(); + format!(r"\\.\pipe\{}", name) + } + + #[test] + fn anon() { + let (mut read, mut write) = t!(anonymous(256)); + assert_eq!(t!(write.write(&[1, 2, 3])), 3); + let mut b = [0; 10]; + assert_eq!(t!(read.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + } + + #[test] + fn named_not_first() { + let name = name(); + let _a = t!(NamedPipe::new(&name)); + assert!(NamedPipe::new(&name).is_err()); + + t!(NamedPipeBuilder::new(&name).first(false).create()); + } + + #[test] + fn named_connect() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + t!(File::open(name)); + }); + + t!(a.connect()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_wait() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let (tx, rx) = channel(); + let t = thread::spawn(move || { + t!(NamedPipe::wait(&name, None)); + t!(File::open(&name)); + assert!(NamedPipe::wait(&name, Some(Duration::from_millis(1))).is_err()); + t!(tx.send(())); + }); + + t!(a.connect()); + t!(rx.recv()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_connect_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + t!(File::open(name)); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(2, &a)); + + let over = Overlapped::zero(); + unsafe { + t!(a.connect_overlapped(over.raw())); + } + + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 0); + assert_eq!(status.token(), 2); + assert_eq!(status.overlapped(), over.raw()); + t!(t.join()); + } + + #[test] + fn named_read_write() { + let name = name(); + let mut a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(OpenOptions::new().read(true).write(true).open(name)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + t!(a.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a.write_all(&[1, 2, 3])); + t!(a.flush()); + t!(a.disconnect()); + t!(t.join()); + } + + #[test] + fn named_read_write_multi() { + for _ in 0..5 { + named_read_write() + } + } + + #[test] + fn named_read_write_multi_same_thread() { + let name1 = name(); + let mut a1 = t!(NamedPipe::new(&name1)); + let name2 = name(); + let mut a2 = t!(NamedPipe::new(&name2)); + + let t = thread::spawn(move || { + let mut f = t!(OpenOptions::new().read(true).write(true).open(name1)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + + let mut f = t!(OpenOptions::new().read(true).write(true).open(name2)); + t!(f.write_all(&[1, 2, 3])); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + }); + + t!(a1.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a1.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a1.write_all(&[1, 2, 3])); + t!(a1.flush()); + t!(a1.disconnect()); + + t!(a2.connect()); + let mut b = [0; 10]; + assert_eq!(t!(a2.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]); + t!(a2.write_all(&[1, 2, 3])); + t!(a2.flush()); + t!(a2.disconnect()); + + t!(t.join()); + } + + #[test] + fn named_read_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(File::create(name)); + t!(f.write_all(&[1, 2, 3])); + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(3, &a)); + t!(a.connect()); + + let mut b = [0; 10]; + let over = Overlapped::zero(); + unsafe { + t!(a.read_overlapped(&mut b, over.raw())); + } + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 3); + assert_eq!(status.overlapped(), over.raw()); + assert_eq!(&b[..3], &[1, 2, 3]); + + t!(t.join()); + } + + #[test] + fn named_write_overlapped() { + let name = name(); + let a = t!(NamedPipe::new(&name)); + + let t = thread::spawn(move || { + let mut f = t!(super::connect(name)); + let mut b = [0; 10]; + assert_eq!(t!(f.read(&mut b)), 3); + assert_eq!(&b[..3], &[1, 2, 3]) + }); + + let cp = t!(CompletionPort::new(1)); + t!(cp.add_handle(3, &a)); + t!(a.connect()); + + let over = Overlapped::zero(); + unsafe { + t!(a.write_overlapped(&[1, 2, 3], over.raw())); + } + + let status = t!(cp.get(None)); + assert_eq!(status.bytes_transferred(), 3); + assert_eq!(status.token(), 3); + assert_eq!(status.overlapped(), over.raw()); + + t!(t.join()); + } +} diff --git a/num-integer/.cargo-checksum.json b/num-integer/.cargo-checksum.json new file mode 100644 index 000000000..8c7b34235 --- /dev/null +++ b/num-integer/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"} \ No newline at end of file diff --git a/num-integer/Cargo.toml b/num-integer/Cargo.toml new file mode 100644 index 000000000..3937fa147 --- /dev/null +++ b/num-integer/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "num-integer" +version = "0.1.41" +authors = ["The Rust Project Developers"] +build = "build.rs" +exclude = ["/ci/*", "/.travis.yml", "/bors.toml"] +description = "Integer traits and functions" +homepage = "https://github.com/rust-num/num-integer" +documentation = "https://docs.rs/num-integer" +readme = "README.md" +keywords = ["mathematics", "numerics"] +categories = ["algorithms", "science", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-num/num-integer" +[package.metadata.docs.rs] +features = ["std"] +[dependencies.num-traits] +version = "0.2.4" +default-features = false +[build-dependencies.autocfg] +version = "0.1.3" + +[features] +default = ["std"] +i128 = ["num-traits/i128"] +std = ["num-traits/std"] diff --git a/num-integer/LICENSE-APACHE b/num-integer/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/num-integer/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/num-integer/LICENSE-MIT b/num-integer/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/num-integer/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/num-integer/README.md b/num-integer/README.md new file mode 100644 index 000000000..4b3d42e72 --- /dev/null +++ b/num-integer/README.md @@ -0,0 +1,50 @@ +# num-integer + +[![crate](https://img.shields.io/crates/v/num-integer.svg)](https://crates.io/crates/num-integer) +[![documentation](https://docs.rs/num-integer/badge.svg)](https://docs.rs/num-integer) +![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg) +[![Travis status](https://travis-ci.org/rust-num/num-integer.svg?branch=master)](https://travis-ci.org/rust-num/num-integer) + +`Integer` trait and functions for Rust. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +num-integer = "0.1" +``` + +and this to your crate root: + +```rust +extern crate num_integer; +``` + +## Features + +This crate can be used without the standard library (`#![no_std]`) by disabling +the default `std` feature. Use this in `Cargo.toml`: + +```toml +[dependencies.num-integer] +version = "0.1.36" +default-features = false +``` + +There is no functional difference with and without `std` at this time, but +there may be in the future. + +Implementations for `i128` and `u128` are only available with Rust 1.26 and +later. The build script automatically detects this, but you can make it +mandatory by enabling the `i128` crate feature. + + +## Releases + +Release notes are available in [RELEASES.md](RELEASES.md). + +## Compatibility + +The `num-integer` crate is tested for rustc 1.8 and greater. diff --git a/num-integer/RELEASES.md b/num-integer/RELEASES.md new file mode 100644 index 000000000..ebc19f76c --- /dev/null +++ b/num-integer/RELEASES.md @@ -0,0 +1,71 @@ +# Release 0.1.41 (2019-05-21) + +- [Fixed feature detection on `no_std` targets][25]. + +**Contributors**: @cuviper + +[25]: https://github.com/rust-num/num-integer/pull/25 + +# Release 0.1.40 (2019-05-20) + +- [Optimized primitive `gcd` by avoiding memory swaps][11]. +- [Fixed `lcm(0, 0)` to return `0`, rather than panicking][18]. +- [Added `Integer::div_ceil`, `next_multiple_of`, and `prev_multiple_of`][16]. +- [Added `Integer::gcd_lcm`, `extended_gcd`, and `extended_gcd_lcm`][19]. + +**Contributors**: @cuviper, @ignatenkobrain, @smarnach, @strake + +[11]: https://github.com/rust-num/num-integer/pull/11 +[16]: https://github.com/rust-num/num-integer/pull/16 +[18]: https://github.com/rust-num/num-integer/pull/18 +[19]: https://github.com/rust-num/num-integer/pull/19 + +# Release 0.1.39 (2018-06-20) + +- [The new `Roots` trait provides `sqrt`, `cbrt`, and `nth_root` methods][9], + calculating an `Integer`'s principal roots rounded toward zero. + +**Contributors**: @cuviper + +[9]: https://github.com/rust-num/num-integer/pull/9 + +# Release 0.1.38 (2018-05-11) + +- [Support for 128-bit integers is now automatically detected and enabled.][8] + Setting the `i128` crate feature now causes the build script to panic if such + support is not detected. + +**Contributors**: @cuviper + +[8]: https://github.com/rust-num/num-integer/pull/8 + +# Release 0.1.37 (2018-05-10) + +- [`Integer` is now implemented for `i128` and `u128`][7] starting with Rust + 1.26, enabled by the new `i128` crate feature. + +**Contributors**: @cuviper + +[7]: https://github.com/rust-num/num-integer/pull/7 + +# Release 0.1.36 (2018-02-06) + +- [num-integer now has its own source repository][num-356] at [rust-num/num-integer][home]. +- [Corrected the argument order documented in `Integer::is_multiple_of`][1] +- [There is now a `std` feature][5], enabled by default, along with the implication + that building *without* this feature makes this a `#[no_std]` crate. + - There is no difference in the API at this time. + +**Contributors**: @cuviper, @jaystrictor + +[home]: https://github.com/rust-num/num-integer +[num-356]: https://github.com/rust-num/num/pull/356 +[1]: https://github.com/rust-num/num-integer/pull/1 +[5]: https://github.com/rust-num/num-integer/pull/5 + + +# Prior releases + +No prior release notes were kept. Thanks all the same to the many +contributors that have made this crate what it is! + diff --git a/num-integer/benches/gcd.rs b/num-integer/benches/gcd.rs new file mode 100644 index 000000000..082d5ee09 --- /dev/null +++ b/num-integer/benches/gcd.rs @@ -0,0 +1,176 @@ +//! Benchmark comparing the current GCD implemtation against an older one. + +#![feature(test)] + +extern crate num_integer; +extern crate num_traits; +extern crate test; + +use num_integer::Integer; +use num_traits::{AsPrimitive, Bounded, Signed}; +use test::{black_box, Bencher}; + +trait GcdOld: Integer { + fn gcd_old(&self, other: &Self) -> Self; +} + +macro_rules! impl_gcd_old_for_isize { + ($T:ty) => { + impl GcdOld for $T { + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd_old(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return (m | n).abs(); + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // The algorithm needs positive numbers, but the minimum value + // can't be represented as a positive one. + // It's also a power of two, so the gcd can be + // calculated by bitshifting in that case + + // Assuming two's complement, the number created by the shift + // is positive for all numbers except gcd = abs(min value) + // The call to .abs() causes a panic in debug mode + if m == Self::min_value() || n == Self::min_value() { + return (1 << shift).abs(); + } + + // guaranteed to be positive now, rest like unsigned algorithm + m = m.abs(); + n = n.abs(); + + // divide n and m by 2 until odd + // m inside loop + n >>= n.trailing_zeros(); + + while m != 0 { + m >>= m.trailing_zeros(); + if n > m { + std::mem::swap(&mut n, &mut m) + } + m -= n; + } + + n << shift + } + } + }; +} + +impl_gcd_old_for_isize!(i8); +impl_gcd_old_for_isize!(i16); +impl_gcd_old_for_isize!(i32); +impl_gcd_old_for_isize!(i64); +impl_gcd_old_for_isize!(isize); +impl_gcd_old_for_isize!(i128); + +macro_rules! impl_gcd_old_for_usize { + ($T:ty) => { + impl GcdOld for $T { + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd_old(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return m | n; + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // divide n and m by 2 until odd + // m inside loop + n >>= n.trailing_zeros(); + + while m != 0 { + m >>= m.trailing_zeros(); + if n > m { + std::mem::swap(&mut n, &mut m) + } + m -= n; + } + + n << shift + } + } + }; +} + +impl_gcd_old_for_usize!(u8); +impl_gcd_old_for_usize!(u16); +impl_gcd_old_for_usize!(u32); +impl_gcd_old_for_usize!(u64); +impl_gcd_old_for_usize!(usize); +impl_gcd_old_for_usize!(u128); + +/// Return an iterator that yields all Fibonacci numbers fitting into a u128. +fn fibonacci() -> impl Iterator { + (0..185).scan((0, 1), |&mut (ref mut a, ref mut b), _| { + let tmp = *a; + *a = *b; + *b += tmp; + Some(*b) + }) +} + +fn run_bench(b: &mut Bencher, gcd: fn(&T, &T) -> T) +where + T: AsPrimitive, + u128: AsPrimitive, +{ + let max_value: u128 = T::max_value().as_(); + let pairs: Vec<(T, T)> = fibonacci() + .collect::>() + .windows(2) + .filter(|&pair| pair[0] <= max_value && pair[1] <= max_value) + .map(|pair| (pair[0].as_(), pair[1].as_())) + .collect(); + b.iter(|| { + for &(ref m, ref n) in &pairs { + black_box(gcd(m, n)); + } + }); +} + +macro_rules! bench_gcd { + ($T:ident) => { + mod $T { + use crate::{run_bench, GcdOld}; + use num_integer::Integer; + use test::Bencher; + + #[bench] + fn bench_gcd(b: &mut Bencher) { + run_bench(b, $T::gcd); + } + + #[bench] + fn bench_gcd_old(b: &mut Bencher) { + run_bench(b, $T::gcd_old); + } + } + }; +} + +bench_gcd!(u8); +bench_gcd!(u16); +bench_gcd!(u32); +bench_gcd!(u64); +bench_gcd!(u128); + +bench_gcd!(i8); +bench_gcd!(i16); +bench_gcd!(i32); +bench_gcd!(i64); +bench_gcd!(i128); diff --git a/num-integer/benches/roots.rs b/num-integer/benches/roots.rs new file mode 100644 index 000000000..7f672786a --- /dev/null +++ b/num-integer/benches/roots.rs @@ -0,0 +1,170 @@ +//! Benchmark sqrt and cbrt + +#![feature(test)] + +extern crate num_integer; +extern crate num_traits; +extern crate test; + +use num_integer::Integer; +use num_traits::checked_pow; +use num_traits::{AsPrimitive, PrimInt, WrappingAdd, WrappingMul}; +use test::{black_box, Bencher}; + +trait BenchInteger: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} + +impl BenchInteger for T where T: Integer + PrimInt + WrappingAdd + WrappingMul + 'static {} + +fn bench(b: &mut Bencher, v: &[T], f: F, n: u32) +where + T: BenchInteger, + F: Fn(&T) -> T, +{ + // Pre-validate the results... + for i in v { + let rt = f(i); + if *i >= T::zero() { + let rt1 = rt + T::one(); + assert!(rt.pow(n) <= *i); + if let Some(x) = checked_pow(rt1, n as usize) { + assert!(*i < x); + } + } else { + let rt1 = rt - T::one(); + assert!(rt < T::zero()); + assert!(*i <= rt.pow(n)); + if let Some(x) = checked_pow(rt1, n as usize) { + assert!(x < *i); + } + }; + } + + // Now just run as fast as we can! + b.iter(|| { + for i in v { + black_box(f(i)); + } + }); +} + +// Simple PRNG so we don't have to worry about rand compatibility +fn lcg(x: T) -> T +where + u32: AsPrimitive, + T: BenchInteger, +{ + // LCG parameters from Numerical Recipes + // (but we're applying it to arbitrary sizes) + const LCG_A: u32 = 1664525; + const LCG_C: u32 = 1013904223; + x.wrapping_mul(&LCG_A.as_()).wrapping_add(&LCG_C.as_()) +} + +fn bench_rand(b: &mut Bencher, f: F, n: u32) +where + u32: AsPrimitive, + T: BenchInteger, + F: Fn(&T) -> T, +{ + let mut x: T = 3u32.as_(); + let v: Vec = (0..1000) + .map(|_| { + x = lcg(x); + x + }) + .collect(); + bench(b, &v, f, n); +} + +fn bench_rand_pos(b: &mut Bencher, f: F, n: u32) +where + u32: AsPrimitive, + T: BenchInteger, + F: Fn(&T) -> T, +{ + let mut x: T = 3u32.as_(); + let v: Vec = (0..1000) + .map(|_| { + x = lcg(x); + while x < T::zero() { + x = lcg(x); + } + x + }) + .collect(); + bench(b, &v, f, n); +} + +fn bench_small(b: &mut Bencher, f: F, n: u32) +where + u32: AsPrimitive, + T: BenchInteger, + F: Fn(&T) -> T, +{ + let v: Vec = (0..1000).map(|i| i.as_()).collect(); + bench(b, &v, f, n); +} + +fn bench_small_pos(b: &mut Bencher, f: F, n: u32) +where + u32: AsPrimitive, + T: BenchInteger, + F: Fn(&T) -> T, +{ + let v: Vec = (0..1000) + .map(|i| i.as_().mod_floor(&T::max_value())) + .collect(); + bench(b, &v, f, n); +} + +macro_rules! bench_roots { + ($($T:ident),*) => {$( + mod $T { + use test::Bencher; + use num_integer::Roots; + + #[bench] + fn sqrt_rand(b: &mut Bencher) { + ::bench_rand_pos(b, $T::sqrt, 2); + } + + #[bench] + fn sqrt_small(b: &mut Bencher) { + ::bench_small_pos(b, $T::sqrt, 2); + } + + #[bench] + fn cbrt_rand(b: &mut Bencher) { + ::bench_rand(b, $T::cbrt, 3); + } + + #[bench] + fn cbrt_small(b: &mut Bencher) { + ::bench_small(b, $T::cbrt, 3); + } + + #[bench] + fn fourth_root_rand(b: &mut Bencher) { + ::bench_rand_pos(b, |x: &$T| x.nth_root(4), 4); + } + + #[bench] + fn fourth_root_small(b: &mut Bencher) { + ::bench_small_pos(b, |x: &$T| x.nth_root(4), 4); + } + + #[bench] + fn fifth_root_rand(b: &mut Bencher) { + ::bench_rand(b, |x: &$T| x.nth_root(5), 5); + } + + #[bench] + fn fifth_root_small(b: &mut Bencher) { + ::bench_small(b, |x: &$T| x.nth_root(5), 5); + } + } + )*} +} + +bench_roots!(i8, i16, i32, i64, i128); +bench_roots!(u8, u16, u32, u64, u128); diff --git a/num-integer/build.rs b/num-integer/build.rs new file mode 100644 index 000000000..15590bbc1 --- /dev/null +++ b/num-integer/build.rs @@ -0,0 +1,14 @@ +extern crate autocfg; + +use std::env; + +fn main() { + let ac = autocfg::new(); + if ac.probe_type("i128") { + println!("cargo:rustc-cfg=has_i128"); + } else if env::var_os("CARGO_FEATURE_I128").is_some() { + panic!("i128 support was not detected!"); + } + + autocfg::rerun_path(file!()); +} diff --git a/num-integer/src/lib.rs b/num-integer/src/lib.rs new file mode 100644 index 000000000..aa12ba68c --- /dev/null +++ b/num-integer/src/lib.rs @@ -0,0 +1,1340 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Integer trait and functions. +//! +//! ## Compatibility +//! +//! The `num-integer` crate is tested for rustc 1.8 and greater. + +#![doc(html_root_url = "https://docs.rs/num-integer/0.1")] +#![no_std] +#[cfg(feature = "std")] +extern crate std; + +extern crate num_traits as traits; + +use core::mem; +use core::ops::Add; + +use traits::{Num, Signed, Zero}; + +mod roots; +pub use roots::Roots; +pub use roots::{cbrt, nth_root, sqrt}; + +pub trait Integer: Sized + Num + PartialOrd + Ord + Eq { + /// Floored integer division. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert!(( 8).div_floor(& 3) == 2); + /// assert!(( 8).div_floor(&-3) == -3); + /// assert!((-8).div_floor(& 3) == -3); + /// assert!((-8).div_floor(&-3) == 2); + /// + /// assert!(( 1).div_floor(& 2) == 0); + /// assert!(( 1).div_floor(&-2) == -1); + /// assert!((-1).div_floor(& 2) == -1); + /// assert!((-1).div_floor(&-2) == 0); + /// ~~~ + fn div_floor(&self, other: &Self) -> Self; + + /// Floored integer modulo, satisfying: + /// + /// ~~~ + /// # use num_integer::Integer; + /// # let n = 1; let d = 1; + /// assert!(n.div_floor(&d) * d + n.mod_floor(&d) == n) + /// ~~~ + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert!(( 8).mod_floor(& 3) == 2); + /// assert!(( 8).mod_floor(&-3) == -1); + /// assert!((-8).mod_floor(& 3) == 1); + /// assert!((-8).mod_floor(&-3) == -2); + /// + /// assert!(( 1).mod_floor(& 2) == 1); + /// assert!(( 1).mod_floor(&-2) == -1); + /// assert!((-1).mod_floor(& 2) == 1); + /// assert!((-1).mod_floor(&-2) == -1); + /// ~~~ + fn mod_floor(&self, other: &Self) -> Self; + + /// Ceiled integer division. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 8).div_ceil( &3), 3); + /// assert_eq!(( 8).div_ceil(&-3), -2); + /// assert_eq!((-8).div_ceil( &3), -2); + /// assert_eq!((-8).div_ceil(&-3), 3); + /// + /// assert_eq!(( 1).div_ceil( &2), 1); + /// assert_eq!(( 1).div_ceil(&-2), 0); + /// assert_eq!((-1).div_ceil( &2), 0); + /// assert_eq!((-1).div_ceil(&-2), 1); + /// ~~~ + fn div_ceil(&self, other: &Self) -> Self { + let (q, r) = self.div_mod_floor(other); + if r.is_zero() { + q + } else { + q + Self::one() + } + } + + /// Greatest Common Divisor (GCD). + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(6.gcd(&8), 2); + /// assert_eq!(7.gcd(&3), 1); + /// ~~~ + fn gcd(&self, other: &Self) -> Self; + + /// Lowest Common Multiple (LCM). + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(7.lcm(&3), 21); + /// assert_eq!(2.lcm(&4), 4); + /// assert_eq!(0.lcm(&0), 0); + /// ~~~ + fn lcm(&self, other: &Self) -> Self; + + /// Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) together. + /// + /// Potentially more efficient than calling `gcd` and `lcm` + /// individually for identical inputs. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(10.gcd_lcm(&4), (2, 20)); + /// assert_eq!(8.gcd_lcm(&9), (1, 72)); + /// ~~~ + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + (self.gcd(other), self.lcm(other)) + } + + /// Greatest common divisor and Bézout coefficients. + /// + /// # Examples + /// + /// ~~~ + /// # extern crate num_integer; + /// # extern crate num_traits; + /// # fn main() { + /// # use num_integer::{ExtendedGcd, Integer}; + /// # use num_traits::NumAssign; + /// fn check(a: A, b: A) -> bool { + /// let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); + /// gcd == x * a + y * b + /// } + /// assert!(check(10isize, 4isize)); + /// assert!(check(8isize, 9isize)); + /// # } + /// ~~~ + #[inline] + fn extended_gcd(&self, other: &Self) -> ExtendedGcd + where + Self: Clone, + { + let mut s = (Self::zero(), Self::one()); + let mut t = (Self::one(), Self::zero()); + let mut r = (other.clone(), self.clone()); + + while !r.0.is_zero() { + let q = r.1.clone() / r.0.clone(); + let f = |mut r: (Self, Self)| { + mem::swap(&mut r.0, &mut r.1); + r.0 = r.0 - q.clone() * r.1.clone(); + r + }; + r = f(r); + s = f(s); + t = f(t); + } + + if r.1 >= Self::zero() { + ExtendedGcd { + gcd: r.1, + x: s.1, + y: t.1, + _hidden: (), + } + } else { + ExtendedGcd { + gcd: Self::zero() - r.1, + x: Self::zero() - s.1, + y: Self::zero() - t.1, + _hidden: (), + } + } + } + + /// Greatest common divisor, least common multiple, and Bézout coefficients. + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) + where + Self: Clone + Signed, + { + (self.extended_gcd(other), self.lcm(other)) + } + + /// Deprecated, use `is_multiple_of` instead. + fn divides(&self, other: &Self) -> bool; + + /// Returns `true` if `self` is a multiple of `other`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(9.is_multiple_of(&3), true); + /// assert_eq!(3.is_multiple_of(&9), false); + /// ~~~ + fn is_multiple_of(&self, other: &Self) -> bool; + + /// Returns `true` if the number is even. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(3.is_even(), false); + /// assert_eq!(4.is_even(), true); + /// ~~~ + fn is_even(&self) -> bool; + + /// Returns `true` if the number is odd. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(3.is_odd(), true); + /// assert_eq!(4.is_odd(), false); + /// ~~~ + fn is_odd(&self) -> bool; + + /// Simultaneous truncated integer division and modulus. + /// Returns `(quotient, remainder)`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 8).div_rem( &3), ( 2, 2)); + /// assert_eq!(( 8).div_rem(&-3), (-2, 2)); + /// assert_eq!((-8).div_rem( &3), (-2, -2)); + /// assert_eq!((-8).div_rem(&-3), ( 2, -2)); + /// + /// assert_eq!(( 1).div_rem( &2), ( 0, 1)); + /// assert_eq!(( 1).div_rem(&-2), ( 0, 1)); + /// assert_eq!((-1).div_rem( &2), ( 0, -1)); + /// assert_eq!((-1).div_rem(&-2), ( 0, -1)); + /// ~~~ + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self); + + /// Simultaneous floored integer division and modulus. + /// Returns `(quotient, remainder)`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 8).div_mod_floor( &3), ( 2, 2)); + /// assert_eq!(( 8).div_mod_floor(&-3), (-3, -1)); + /// assert_eq!((-8).div_mod_floor( &3), (-3, 1)); + /// assert_eq!((-8).div_mod_floor(&-3), ( 2, -2)); + /// + /// assert_eq!(( 1).div_mod_floor( &2), ( 0, 1)); + /// assert_eq!(( 1).div_mod_floor(&-2), (-1, -1)); + /// assert_eq!((-1).div_mod_floor( &2), (-1, 1)); + /// assert_eq!((-1).div_mod_floor(&-2), ( 0, -1)); + /// ~~~ + fn div_mod_floor(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) + } + + /// Rounds up to nearest multiple of argument. + /// + /// # Notes + /// + /// For signed types, `a.next_multiple_of(b) = a.prev_multiple_of(b.neg())`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 16).next_multiple_of(& 8), 16); + /// assert_eq!(( 23).next_multiple_of(& 8), 24); + /// assert_eq!(( 16).next_multiple_of(&-8), 16); + /// assert_eq!(( 23).next_multiple_of(&-8), 16); + /// assert_eq!((-16).next_multiple_of(& 8), -16); + /// assert_eq!((-23).next_multiple_of(& 8), -16); + /// assert_eq!((-16).next_multiple_of(&-8), -16); + /// assert_eq!((-23).next_multiple_of(&-8), -24); + /// ~~~ + #[inline] + fn next_multiple_of(&self, other: &Self) -> Self + where + Self: Clone, + { + let m = self.mod_floor(other); + self.clone() + + if m.is_zero() { + Self::zero() + } else { + other.clone() - m + } + } + + /// Rounds down to nearest multiple of argument. + /// + /// # Notes + /// + /// For signed types, `a.prev_multiple_of(b) = a.next_multiple_of(b.neg())`. + /// + /// # Examples + /// + /// ~~~ + /// # use num_integer::Integer; + /// assert_eq!(( 16).prev_multiple_of(& 8), 16); + /// assert_eq!(( 23).prev_multiple_of(& 8), 16); + /// assert_eq!(( 16).prev_multiple_of(&-8), 16); + /// assert_eq!(( 23).prev_multiple_of(&-8), 24); + /// assert_eq!((-16).prev_multiple_of(& 8), -16); + /// assert_eq!((-23).prev_multiple_of(& 8), -24); + /// assert_eq!((-16).prev_multiple_of(&-8), -16); + /// assert_eq!((-23).prev_multiple_of(&-8), -16); + /// ~~~ + #[inline] + fn prev_multiple_of(&self, other: &Self) -> Self + where + Self: Clone, + { + self.clone() - self.mod_floor(other) + } +} + +/// Greatest common divisor and Bézout coefficients +/// +/// ```no_build +/// let e = isize::extended_gcd(a, b); +/// assert_eq!(e.gcd, e.x*a + e.y*b); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ExtendedGcd { + pub gcd: A, + pub x: A, + pub y: A, + _hidden: (), +} + +/// Simultaneous integer division and modulus +#[inline] +pub fn div_rem(x: T, y: T) -> (T, T) { + x.div_rem(&y) +} +/// Floored integer division +#[inline] +pub fn div_floor(x: T, y: T) -> T { + x.div_floor(&y) +} +/// Floored integer modulus +#[inline] +pub fn mod_floor(x: T, y: T) -> T { + x.mod_floor(&y) +} +/// Simultaneous floored integer division and modulus +#[inline] +pub fn div_mod_floor(x: T, y: T) -> (T, T) { + x.div_mod_floor(&y) +} +/// Ceiled integer division +#[inline] +pub fn div_ceil(x: T, y: T) -> T { + x.div_ceil(&y) +} + +/// Calculates the Greatest Common Divisor (GCD) of the number and `other`. The +/// result is always positive. +#[inline(always)] +pub fn gcd(x: T, y: T) -> T { + x.gcd(&y) +} +/// Calculates the Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] +pub fn lcm(x: T, y: T) -> T { + x.lcm(&y) +} + +/// Calculates the Greatest Common Divisor (GCD) and +/// Lowest Common Multiple (LCM) of the number and `other`. +#[inline(always)] +pub fn gcd_lcm(x: T, y: T) -> (T, T) { + x.gcd_lcm(&y) +} + +macro_rules! impl_integer_for_isize { + ($T:ty, $test_mod:ident) => { + impl Integer for $T { + /// Floored integer division + #[inline] + fn div_floor(&self, other: &Self) -> Self { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + d - 1 + } else { + d + } + } + + /// Floored integer modulo + #[inline] + fn mod_floor(&self, other: &Self) -> Self { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + let r = *self % *other; + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + r + *other + } else { + r + } + } + + /// Calculates `div_floor` and `mod_floor` simultaneously + #[inline] + fn div_mod_floor(&self, other: &Self) -> (Self, Self) { + // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, + // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) + let (d, r) = self.div_rem(other); + if (r > 0 && *other < 0) || (r < 0 && *other > 0) { + (d - 1, r + *other) + } else { + (d, r) + } + } + + #[inline] + fn div_ceil(&self, other: &Self) -> Self { + let (d, r) = self.div_rem(other); + if (r > 0 && *other > 0) || (r < 0 && *other < 0) { + d + 1 + } else { + d + } + } + + /// Calculates the Greatest Common Divisor (GCD) of the number and + /// `other`. The result is always positive. + #[inline] + fn gcd(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return (m | n).abs(); + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // The algorithm needs positive numbers, but the minimum value + // can't be represented as a positive one. + // It's also a power of two, so the gcd can be + // calculated by bitshifting in that case + + // Assuming two's complement, the number created by the shift + // is positive for all numbers except gcd = abs(min value) + // The call to .abs() causes a panic in debug mode + if m == Self::min_value() || n == Self::min_value() { + return (1 << shift).abs(); + } + + // guaranteed to be positive now, rest like unsigned algorithm + m = m.abs(); + n = n.abs(); + + // divide n and m by 2 until odd + m >>= m.trailing_zeros(); + n >>= n.trailing_zeros(); + + while m != n { + if m > n { + m -= n; + m >>= m.trailing_zeros(); + } else { + n -= m; + n >>= n.trailing_zeros(); + } + } + m << shift + } + + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { + let egcd = self.extended_gcd(other); + // should not have to recalculate abs + let lcm = if egcd.gcd.is_zero() { + Self::zero() + } else { + (*self * (*other / egcd.gcd)).abs() + }; + (egcd, lcm) + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and + /// `other`. + #[inline] + fn lcm(&self, other: &Self) -> Self { + self.gcd_lcm(other).1 + } + + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Self::zero()); + } + let gcd = self.gcd(other); + // should not have to recalculate abs + let lcm = (*self * (*other / gcd)).abs(); + (gcd, lcm) + } + + /// Deprecated, use `is_multiple_of` instead. + #[inline] + fn divides(&self, other: &Self) -> bool { + self.is_multiple_of(other) + } + + /// Returns `true` if the number is a multiple of `other`. + #[inline] + fn is_multiple_of(&self, other: &Self) -> bool { + *self % *other == 0 + } + + /// Returns `true` if the number is divisible by `2` + #[inline] + fn is_even(&self) -> bool { + (*self) & 1 == 0 + } + + /// Returns `true` if the number is not divisible by `2` + #[inline] + fn is_odd(&self) -> bool { + !self.is_even() + } + + /// Simultaneous truncated integer division and modulus. + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (*self / *other, *self % *other) + } + } + + #[cfg(test)] + mod $test_mod { + use core::mem; + use Integer; + + /// Checks that the division rule holds for: + /// + /// - `n`: numerator (dividend) + /// - `d`: denominator (divisor) + /// - `qr`: quotient and remainder + #[cfg(test)] + fn test_division_rule((n, d): ($T, $T), (q, r): ($T, $T)) { + assert_eq!(d * q + r, n); + } + + #[test] + fn test_div_rem() { + fn test_nd_dr(nd: ($T, $T), qr: ($T, $T)) { + let (n, d) = nd; + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); + + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); + + test_division_rule(nd, separate_div_rem); + test_division_rule(nd, combined_div_rem); + } + + test_nd_dr((8, 3), (2, 2)); + test_nd_dr((8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), (2, -2)); + + test_nd_dr((1, 2), (0, 1)); + test_nd_dr((1, -2), (0, 1)); + test_nd_dr((-1, 2), (0, -1)); + test_nd_dr((-1, -2), (0, -1)); + } + + #[test] + fn test_div_mod_floor() { + fn test_nd_dm(nd: ($T, $T), dm: ($T, $T)) { + let (n, d) = nd; + let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); + let combined_div_mod_floor = n.div_mod_floor(&d); + + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); + + test_division_rule(nd, separate_div_mod_floor); + test_division_rule(nd, combined_div_mod_floor); + } + + test_nd_dm((8, 3), (2, 2)); + test_nd_dm((8, -3), (-3, -1)); + test_nd_dm((-8, 3), (-3, 1)); + test_nd_dm((-8, -3), (2, -2)); + + test_nd_dm((1, 2), (0, 1)); + test_nd_dm((1, -2), (-1, -1)); + test_nd_dm((-1, 2), (-1, 1)); + test_nd_dm((-1, -2), (0, -1)); + } + + #[test] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + assert_eq!((3 as $T).gcd(&-3), 3 as $T); + assert_eq!((-6 as $T).gcd(&3), 3 as $T); + assert_eq!((-4 as $T).gcd(&-2), 2 as $T); + } + + #[test] + fn test_gcd_cmp_with_euclidean() { + fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { + while m != 0 { + mem::swap(&mut m, &mut n); + m %= n; + } + + n.abs() + } + + // gcd(-128, b) = 128 is not representable as positive value + // for i8 + for i in -127..127 { + for j in -127..127 { + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); + } + } + + // last value + // FIXME: Use inclusive ranges for above loop when implemented + let i = 127; + for j in -127..127 { + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); + } + assert_eq!(127.gcd(&127), 127); + } + + #[test] + fn test_gcd_min_val() { + let min = <$T>::min_value(); + let max = <$T>::max_value(); + let max_pow2 = max / 2 + 1; + assert_eq!(min.gcd(&max), 1 as $T); + assert_eq!(max.gcd(&min), 1 as $T); + assert_eq!(min.gcd(&max_pow2), max_pow2); + assert_eq!(max_pow2.gcd(&min), max_pow2); + assert_eq!(min.gcd(&42), 2 as $T); + assert_eq!((42 as $T).gcd(&min), 2 as $T); + } + + #[test] + #[should_panic] + fn test_gcd_min_val_min_val() { + let min = <$T>::min_value(); + assert!(min.gcd(&min) >= 0); + } + + #[test] + #[should_panic] + fn test_gcd_min_val_0() { + let min = <$T>::min_value(); + assert!(min.gcd(&0) >= 0); + } + + #[test] + #[should_panic] + fn test_gcd_0_min_val() { + let min = <$T>::min_value(); + assert!((0 as $T).gcd(&min) >= 0); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((-1 as $T).lcm(&1), 1 as $T); + assert_eq!((1 as $T).lcm(&-1), 1 as $T); + assert_eq!((-1 as $T).lcm(&-1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + } + + #[test] + fn test_gcd_lcm() { + use core::iter::once; + for i in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + for j in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + + #[test] + fn test_extended_gcd_lcm() { + use core::fmt::Debug; + use traits::NumAssign; + use ExtendedGcd; + + fn check(a: A, b: A) { + let ExtendedGcd { gcd, x, y, .. } = a.extended_gcd(&b); + assert_eq!(gcd, x * a + y * b); + } + + use core::iter::once; + for i in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + for j in once(0) + .chain((1..).take(127).flat_map(|a| once(a).chain(once(-a)))) + .chain(once(-128)) + { + check(i, j); + let (ExtendedGcd { gcd, .. }, lcm) = i.extended_gcd_lcm(&j); + assert_eq!((gcd, lcm), (i.gcd(&j), i.lcm(&j))); + } + } + } + + #[test] + fn test_even() { + assert_eq!((-4 as $T).is_even(), true); + assert_eq!((-3 as $T).is_even(), false); + assert_eq!((-2 as $T).is_even(), true); + assert_eq!((-1 as $T).is_even(), false); + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((-4 as $T).is_odd(), false); + assert_eq!((-3 as $T).is_odd(), true); + assert_eq!((-2 as $T).is_odd(), false); + assert_eq!((-1 as $T).is_odd(), true); + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + }; +} + +impl_integer_for_isize!(i8, test_integer_i8); +impl_integer_for_isize!(i16, test_integer_i16); +impl_integer_for_isize!(i32, test_integer_i32); +impl_integer_for_isize!(i64, test_integer_i64); +impl_integer_for_isize!(isize, test_integer_isize); +#[cfg(has_i128)] +impl_integer_for_isize!(i128, test_integer_i128); + +macro_rules! impl_integer_for_usize { + ($T:ty, $test_mod:ident) => { + impl Integer for $T { + /// Unsigned integer division. Returns the same result as `div` (`/`). + #[inline] + fn div_floor(&self, other: &Self) -> Self { + *self / *other + } + + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + #[inline] + fn mod_floor(&self, other: &Self) -> Self { + *self % *other + } + + #[inline] + fn div_ceil(&self, other: &Self) -> Self { + *self / *other + (0 != *self % *other) as Self + } + + /// Calculates the Greatest Common Divisor (GCD) of the number and `other` + #[inline] + fn gcd(&self, other: &Self) -> Self { + // Use Stein's algorithm + let mut m = *self; + let mut n = *other; + if m == 0 || n == 0 { + return m | n; + } + + // find common factors of 2 + let shift = (m | n).trailing_zeros(); + + // divide n and m by 2 until odd + m >>= m.trailing_zeros(); + n >>= n.trailing_zeros(); + + while m != n { + if m > n { + m -= n; + m >>= m.trailing_zeros(); + } else { + n -= m; + n >>= n.trailing_zeros(); + } + } + m << shift + } + + #[inline] + fn extended_gcd_lcm(&self, other: &Self) -> (ExtendedGcd, Self) { + let egcd = self.extended_gcd(other); + // should not have to recalculate abs + let lcm = if egcd.gcd.is_zero() { + Self::zero() + } else { + *self * (*other / egcd.gcd) + }; + (egcd, lcm) + } + + /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn lcm(&self, other: &Self) -> Self { + self.gcd_lcm(other).1 + } + + /// Calculates the Greatest Common Divisor (GCD) and + /// Lowest Common Multiple (LCM) of the number and `other`. + #[inline] + fn gcd_lcm(&self, other: &Self) -> (Self, Self) { + if self.is_zero() && other.is_zero() { + return (Self::zero(), Self::zero()); + } + let gcd = self.gcd(other); + let lcm = *self * (*other / gcd); + (gcd, lcm) + } + + /// Deprecated, use `is_multiple_of` instead. + #[inline] + fn divides(&self, other: &Self) -> bool { + self.is_multiple_of(other) + } + + /// Returns `true` if the number is a multiple of `other`. + #[inline] + fn is_multiple_of(&self, other: &Self) -> bool { + *self % *other == 0 + } + + /// Returns `true` if the number is divisible by `2`. + #[inline] + fn is_even(&self) -> bool { + *self % 2 == 0 + } + + /// Returns `true` if the number is not divisible by `2`. + #[inline] + fn is_odd(&self) -> bool { + !self.is_even() + } + + /// Simultaneous truncated integer division and modulus. + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (*self / *other, *self % *other) + } + } + + #[cfg(test)] + mod $test_mod { + use core::mem; + use Integer; + + #[test] + fn test_div_mod_floor() { + assert_eq!((10 as $T).div_floor(&(3 as $T)), 3 as $T); + assert_eq!((10 as $T).mod_floor(&(3 as $T)), 1 as $T); + assert_eq!((10 as $T).div_mod_floor(&(3 as $T)), (3 as $T, 1 as $T)); + assert_eq!((5 as $T).div_floor(&(5 as $T)), 1 as $T); + assert_eq!((5 as $T).mod_floor(&(5 as $T)), 0 as $T); + assert_eq!((5 as $T).div_mod_floor(&(5 as $T)), (1 as $T, 0 as $T)); + assert_eq!((3 as $T).div_floor(&(7 as $T)), 0 as $T); + assert_eq!((3 as $T).mod_floor(&(7 as $T)), 3 as $T); + assert_eq!((3 as $T).div_mod_floor(&(7 as $T)), (0 as $T, 3 as $T)); + } + + #[test] + fn test_gcd() { + assert_eq!((10 as $T).gcd(&2), 2 as $T); + assert_eq!((10 as $T).gcd(&3), 1 as $T); + assert_eq!((0 as $T).gcd(&3), 3 as $T); + assert_eq!((3 as $T).gcd(&3), 3 as $T); + assert_eq!((56 as $T).gcd(&42), 14 as $T); + } + + #[test] + fn test_gcd_cmp_with_euclidean() { + fn euclidean_gcd(mut m: $T, mut n: $T) -> $T { + while m != 0 { + mem::swap(&mut m, &mut n); + m %= n; + } + n + } + + for i in 0..255 { + for j in 0..255 { + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); + } + } + + // last value + // FIXME: Use inclusive ranges for above loop when implemented + let i = 255; + for j in 0..255 { + assert_eq!(euclidean_gcd(i, j), i.gcd(&j)); + } + assert_eq!(255.gcd(&255), 255); + } + + #[test] + fn test_lcm() { + assert_eq!((1 as $T).lcm(&0), 0 as $T); + assert_eq!((0 as $T).lcm(&1), 0 as $T); + assert_eq!((1 as $T).lcm(&1), 1 as $T); + assert_eq!((8 as $T).lcm(&9), 72 as $T); + assert_eq!((11 as $T).lcm(&5), 55 as $T); + assert_eq!((15 as $T).lcm(&17), 255 as $T); + } + + #[test] + fn test_gcd_lcm() { + for i in (0..).take(256) { + for j in (0..).take(256) { + assert_eq!(i.gcd_lcm(&j), (i.gcd(&j), i.lcm(&j))); + } + } + } + + #[test] + fn test_is_multiple_of() { + assert!((6 as $T).is_multiple_of(&(6 as $T))); + assert!((6 as $T).is_multiple_of(&(3 as $T))); + assert!((6 as $T).is_multiple_of(&(1 as $T))); + } + + #[test] + fn test_even() { + assert_eq!((0 as $T).is_even(), true); + assert_eq!((1 as $T).is_even(), false); + assert_eq!((2 as $T).is_even(), true); + assert_eq!((3 as $T).is_even(), false); + assert_eq!((4 as $T).is_even(), true); + } + + #[test] + fn test_odd() { + assert_eq!((0 as $T).is_odd(), false); + assert_eq!((1 as $T).is_odd(), true); + assert_eq!((2 as $T).is_odd(), false); + assert_eq!((3 as $T).is_odd(), true); + assert_eq!((4 as $T).is_odd(), false); + } + } + }; +} + +impl_integer_for_usize!(u8, test_integer_u8); +impl_integer_for_usize!(u16, test_integer_u16); +impl_integer_for_usize!(u32, test_integer_u32); +impl_integer_for_usize!(u64, test_integer_u64); +impl_integer_for_usize!(usize, test_integer_usize); +#[cfg(has_i128)] +impl_integer_for_usize!(u128, test_integer_u128); + +/// An iterator over binomial coefficients. +pub struct IterBinomial { + a: T, + n: T, + k: T, +} + +impl IterBinomial +where + T: Integer, +{ + /// For a given n, iterate over all binomial coefficients binomial(n, k), for k=0...n. + /// + /// Note that this might overflow, depending on `T`. For the primitive + /// integer types, the following n are the largest ones for which there will + /// be no overflow: + /// + /// type | n + /// -----|--- + /// u8 | 10 + /// i8 | 9 + /// u16 | 18 + /// i16 | 17 + /// u32 | 34 + /// i32 | 33 + /// u64 | 67 + /// i64 | 66 + /// + /// For larger n, `T` should be a bigint type. + pub fn new(n: T) -> IterBinomial { + IterBinomial { + k: T::zero(), + a: T::one(), + n: n, + } + } +} + +impl Iterator for IterBinomial +where + T: Integer + Clone, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.k > self.n { + return None; + } + self.a = if !self.k.is_zero() { + multiply_and_divide( + self.a.clone(), + self.n.clone() - self.k.clone() + T::one(), + self.k.clone(), + ) + } else { + T::one() + }; + self.k = self.k.clone() + T::one(); + Some(self.a.clone()) + } +} + +/// Calculate r * a / b, avoiding overflows and fractions. +/// +/// Assumes that b divides r * a evenly. +fn multiply_and_divide(r: T, a: T, b: T) -> T { + // See http://blog.plover.com/math/choose-2.html for the idea. + let g = gcd(r.clone(), b.clone()); + r / g.clone() * (a / (b / g)) +} + +/// Calculate the binomial coefficient. +/// +/// Note that this might overflow, depending on `T`. For the primitive integer +/// types, the following n are the largest ones possible such that there will +/// be no overflow for any k: +/// +/// type | n +/// -----|--- +/// u8 | 10 +/// i8 | 9 +/// u16 | 18 +/// i16 | 17 +/// u32 | 34 +/// i32 | 33 +/// u64 | 67 +/// i64 | 66 +/// +/// For larger n, consider using a bigint type for `T`. +pub fn binomial(mut n: T, k: T) -> T { + // See http://blog.plover.com/math/choose.html for the idea. + if k > n { + return T::zero(); + } + if k > n.clone() - k.clone() { + return binomial(n.clone(), n - k); + } + let mut r = T::one(); + let mut d = T::one(); + loop { + if d > k { + break; + } + r = multiply_and_divide(r, n.clone(), d.clone()); + n = n - T::one(); + d = d + T::one(); + } + r +} + +/// Calculate the multinomial coefficient. +pub fn multinomial(k: &[T]) -> T +where + for<'a> T: Add<&'a T, Output = T>, +{ + let mut r = T::one(); + let mut p = T::zero(); + for i in k { + p = p + i; + r = r * binomial(p.clone(), i.clone()); + } + r +} + +#[test] +fn test_lcm_overflow() { + macro_rules! check { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ + let x: $t = $x; + let y: $t = $y; + let o = x.checked_mul(y); + assert!( + o.is_none(), + "sanity checking that {} input {} * {} overflows", + stringify!($t), + x, + y + ); + assert_eq!(x.lcm(&y), $r); + assert_eq!(y.lcm(&x), $r); + }}; + } + + // Original bug (Issue #166) + check!(i64, 46656000000000000, 600, 46656000000000000); + + check!(i8, 0x40, 0x04, 0x40); + check!(u8, 0x80, 0x02, 0x80); + check!(i16, 0x40_00, 0x04, 0x40_00); + check!(u16, 0x80_00, 0x02, 0x80_00); + check!(i32, 0x4000_0000, 0x04, 0x4000_0000); + check!(u32, 0x8000_0000, 0x02, 0x8000_0000); + check!(i64, 0x4000_0000_0000_0000, 0x04, 0x4000_0000_0000_0000); + check!(u64, 0x8000_0000_0000_0000, 0x02, 0x8000_0000_0000_0000); +} + +#[test] +fn test_iter_binomial() { + macro_rules! check_simple { + ($t:ty) => {{ + let n: $t = 3; + let expected = [1, 3, 3, 1]; + for (b, &e) in IterBinomial::new(n).zip(&expected) { + assert_eq!(b, e); + } + }}; + } + + check_simple!(u8); + check_simple!(i8); + check_simple!(u16); + check_simple!(i16); + check_simple!(u32); + check_simple!(i32); + check_simple!(u64); + check_simple!(i64); + + macro_rules! check_binomial { + ($t:ty, $n:expr) => {{ + let n: $t = $n; + let mut k: $t = 0; + for b in IterBinomial::new(n) { + assert_eq!(b, binomial(n, k)); + k += 1; + } + }}; + } + + // Check the largest n for which there is no overflow. + check_binomial!(u8, 10); + check_binomial!(i8, 9); + check_binomial!(u16, 18); + check_binomial!(i16, 17); + check_binomial!(u32, 34); + check_binomial!(i32, 33); + check_binomial!(u64, 67); + check_binomial!(i64, 66); +} + +#[test] +fn test_binomial() { + macro_rules! check { + ($t:ty, $x:expr, $y:expr, $r:expr) => {{ + let x: $t = $x; + let y: $t = $y; + let expected: $t = $r; + assert_eq!(binomial(x, y), expected); + if y <= x { + assert_eq!(binomial(x, x - y), expected); + } + }}; + } + check!(u8, 9, 4, 126); + check!(u8, 0, 0, 1); + check!(u8, 2, 3, 0); + + check!(i8, 9, 4, 126); + check!(i8, 0, 0, 1); + check!(i8, 2, 3, 0); + + check!(u16, 100, 2, 4950); + check!(u16, 14, 4, 1001); + check!(u16, 0, 0, 1); + check!(u16, 2, 3, 0); + + check!(i16, 100, 2, 4950); + check!(i16, 14, 4, 1001); + check!(i16, 0, 0, 1); + check!(i16, 2, 3, 0); + + check!(u32, 100, 2, 4950); + check!(u32, 35, 11, 417225900); + check!(u32, 14, 4, 1001); + check!(u32, 0, 0, 1); + check!(u32, 2, 3, 0); + + check!(i32, 100, 2, 4950); + check!(i32, 35, 11, 417225900); + check!(i32, 14, 4, 1001); + check!(i32, 0, 0, 1); + check!(i32, 2, 3, 0); + + check!(u64, 100, 2, 4950); + check!(u64, 35, 11, 417225900); + check!(u64, 14, 4, 1001); + check!(u64, 0, 0, 1); + check!(u64, 2, 3, 0); + + check!(i64, 100, 2, 4950); + check!(i64, 35, 11, 417225900); + check!(i64, 14, 4, 1001); + check!(i64, 0, 0, 1); + check!(i64, 2, 3, 0); +} + +#[test] +fn test_multinomial() { + macro_rules! check_binomial { + ($t:ty, $k:expr) => {{ + let n: $t = $k.iter().fold(0, |acc, &x| acc + x); + let k: &[$t] = $k; + assert_eq!(k.len(), 2); + assert_eq!(multinomial(k), binomial(n, k[0])); + }}; + } + + check_binomial!(u8, &[4, 5]); + + check_binomial!(i8, &[4, 5]); + + check_binomial!(u16, &[2, 98]); + check_binomial!(u16, &[4, 10]); + + check_binomial!(i16, &[2, 98]); + check_binomial!(i16, &[4, 10]); + + check_binomial!(u32, &[2, 98]); + check_binomial!(u32, &[11, 24]); + check_binomial!(u32, &[4, 10]); + + check_binomial!(i32, &[2, 98]); + check_binomial!(i32, &[11, 24]); + check_binomial!(i32, &[4, 10]); + + check_binomial!(u64, &[2, 98]); + check_binomial!(u64, &[11, 24]); + check_binomial!(u64, &[4, 10]); + + check_binomial!(i64, &[2, 98]); + check_binomial!(i64, &[11, 24]); + check_binomial!(i64, &[4, 10]); + + macro_rules! check_multinomial { + ($t:ty, $k:expr, $r:expr) => {{ + let k: &[$t] = $k; + let expected: $t = $r; + assert_eq!(multinomial(k), expected); + }}; + } + + check_multinomial!(u8, &[2, 1, 2], 30); + check_multinomial!(u8, &[2, 3, 0], 10); + + check_multinomial!(i8, &[2, 1, 2], 30); + check_multinomial!(i8, &[2, 3, 0], 10); + + check_multinomial!(u16, &[2, 1, 2], 30); + check_multinomial!(u16, &[2, 3, 0], 10); + + check_multinomial!(i16, &[2, 1, 2], 30); + check_multinomial!(i16, &[2, 3, 0], 10); + + check_multinomial!(u32, &[2, 1, 2], 30); + check_multinomial!(u32, &[2, 3, 0], 10); + + check_multinomial!(i32, &[2, 1, 2], 30); + check_multinomial!(i32, &[2, 3, 0], 10); + + check_multinomial!(u64, &[2, 1, 2], 30); + check_multinomial!(u64, &[2, 3, 0], 10); + + check_multinomial!(i64, &[2, 1, 2], 30); + check_multinomial!(i64, &[2, 3, 0], 10); + + check_multinomial!(u64, &[], 1); + check_multinomial!(u64, &[0], 1); + check_multinomial!(u64, &[12345], 1); +} diff --git a/num-integer/src/roots.rs b/num-integer/src/roots.rs new file mode 100644 index 000000000..a9eec1a93 --- /dev/null +++ b/num-integer/src/roots.rs @@ -0,0 +1,391 @@ +use core; +use core::mem; +use traits::checked_pow; +use traits::PrimInt; +use Integer; + +/// Provides methods to compute an integer's square root, cube root, +/// and arbitrary `n`th root. +pub trait Roots: Integer { + /// Returns the truncated principal `n`th root of an integer + /// -- `if x >= 0 { ⌊ⁿ√x⌋ } else { ⌈ⁿ√x⌉ }` + /// + /// This is solving for `r` in `rⁿ = x`, rounding toward zero. + /// If `x` is positive, the result will satisfy `rⁿ ≤ x < (r+1)ⁿ`. + /// If `x` is negative and `n` is odd, then `(r-1)ⁿ < x ≤ rⁿ`. + /// + /// # Panics + /// + /// Panics if `n` is zero: + /// + /// ```should_panic + /// # use num_integer::Roots; + /// println!("can't compute ⁰√x : {}", 123.nth_root(0)); + /// ``` + /// + /// or if `n` is even and `self` is negative: + /// + /// ```should_panic + /// # use num_integer::Roots; + /// println!("no imaginary numbers... {}", (-1).nth_root(10)); + /// ``` + /// + /// # Examples + /// + /// ``` + /// use num_integer::Roots; + /// + /// let x: i32 = 12345; + /// assert_eq!(x.nth_root(1), x); + /// assert_eq!(x.nth_root(2), x.sqrt()); + /// assert_eq!(x.nth_root(3), x.cbrt()); + /// assert_eq!(x.nth_root(4), 10); + /// assert_eq!(x.nth_root(13), 2); + /// assert_eq!(x.nth_root(14), 1); + /// assert_eq!(x.nth_root(std::u32::MAX), 1); + /// + /// assert_eq!(std::i32::MAX.nth_root(30), 2); + /// assert_eq!(std::i32::MAX.nth_root(31), 1); + /// assert_eq!(std::i32::MIN.nth_root(31), -2); + /// assert_eq!((std::i32::MIN + 1).nth_root(31), -1); + /// + /// assert_eq!(std::u32::MAX.nth_root(31), 2); + /// assert_eq!(std::u32::MAX.nth_root(32), 1); + /// ``` + fn nth_root(&self, n: u32) -> Self; + + /// Returns the truncated principal square root of an integer -- `⌊√x⌋` + /// + /// This is solving for `r` in `r² = x`, rounding toward zero. + /// The result will satisfy `r² ≤ x < (r+1)²`. + /// + /// # Panics + /// + /// Panics if `self` is less than zero: + /// + /// ```should_panic + /// # use num_integer::Roots; + /// println!("no imaginary numbers... {}", (-1).sqrt()); + /// ``` + /// + /// # Examples + /// + /// ``` + /// use num_integer::Roots; + /// + /// let x: i32 = 12345; + /// assert_eq!((x * x).sqrt(), x); + /// assert_eq!((x * x + 1).sqrt(), x); + /// assert_eq!((x * x - 1).sqrt(), x - 1); + /// ``` + #[inline] + fn sqrt(&self) -> Self { + self.nth_root(2) + } + + /// Returns the truncated principal cube root of an integer -- + /// `if x >= 0 { ⌊∛x⌋ } else { ⌈∛x⌉ }` + /// + /// This is solving for `r` in `r³ = x`, rounding toward zero. + /// If `x` is positive, the result will satisfy `r³ ≤ x < (r+1)³`. + /// If `x` is negative, then `(r-1)³ < x ≤ r³`. + /// + /// # Examples + /// + /// ``` + /// use num_integer::Roots; + /// + /// let x: i32 = 1234; + /// assert_eq!((x * x * x).cbrt(), x); + /// assert_eq!((x * x * x + 1).cbrt(), x); + /// assert_eq!((x * x * x - 1).cbrt(), x - 1); + /// + /// assert_eq!((-(x * x * x)).cbrt(), -x); + /// assert_eq!((-(x * x * x + 1)).cbrt(), -x); + /// assert_eq!((-(x * x * x - 1)).cbrt(), -(x - 1)); + /// ``` + #[inline] + fn cbrt(&self) -> Self { + self.nth_root(3) + } +} + +/// Returns the truncated principal square root of an integer -- +/// see [Roots::sqrt](trait.Roots.html#method.sqrt). +#[inline] +pub fn sqrt(x: T) -> T { + x.sqrt() +} + +/// Returns the truncated principal cube root of an integer -- +/// see [Roots::cbrt](trait.Roots.html#method.cbrt). +#[inline] +pub fn cbrt(x: T) -> T { + x.cbrt() +} + +/// Returns the truncated principal `n`th root of an integer -- +/// see [Roots::nth_root](trait.Roots.html#tymethod.nth_root). +#[inline] +pub fn nth_root(x: T, n: u32) -> T { + x.nth_root(n) +} + +macro_rules! signed_roots { + ($T:ty, $U:ty) => { + impl Roots for $T { + #[inline] + fn nth_root(&self, n: u32) -> Self { + if *self >= 0 { + (*self as $U).nth_root(n) as Self + } else { + assert!(n.is_odd(), "even roots of a negative are imaginary"); + -((self.wrapping_neg() as $U).nth_root(n) as Self) + } + } + + #[inline] + fn sqrt(&self) -> Self { + assert!(*self >= 0, "the square root of a negative is imaginary"); + (*self as $U).sqrt() as Self + } + + #[inline] + fn cbrt(&self) -> Self { + if *self >= 0 { + (*self as $U).cbrt() as Self + } else { + -((self.wrapping_neg() as $U).cbrt() as Self) + } + } + } + }; +} + +signed_roots!(i8, u8); +signed_roots!(i16, u16); +signed_roots!(i32, u32); +signed_roots!(i64, u64); +#[cfg(has_i128)] +signed_roots!(i128, u128); +signed_roots!(isize, usize); + +#[inline] +fn fixpoint(mut x: T, f: F) -> T +where + T: Integer + Copy, + F: Fn(T) -> T, +{ + let mut xn = f(x); + while x < xn { + x = xn; + xn = f(x); + } + while x > xn { + x = xn; + xn = f(x); + } + x +} + +#[inline] +fn bits() -> u32 { + 8 * mem::size_of::() as u32 +} + +#[inline] +fn log2(x: T) -> u32 { + debug_assert!(x > T::zero()); + bits::() - 1 - x.leading_zeros() +} + +macro_rules! unsigned_roots { + ($T:ident) => { + impl Roots for $T { + #[inline] + fn nth_root(&self, n: u32) -> Self { + fn go(a: $T, n: u32) -> $T { + // Specialize small roots + match n { + 0 => panic!("can't find a root of degree 0!"), + 1 => return a, + 2 => return a.sqrt(), + 3 => return a.cbrt(), + _ => (), + } + + // The root of values less than 2ⁿ can only be 0 or 1. + if bits::<$T>() <= n || a < (1 << n) { + return (a > 0) as $T; + } + + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `nth_root` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).nth_root(n) as $T + } else { + let lo = (a >> n).nth_root(n) << 1; + let hi = lo + 1; + // 128-bit `checked_mul` also involves division, but we can't always + // compute `hiⁿ` without risking overflow. Try to avoid it though... + if hi.next_power_of_two().trailing_zeros() * n >= bits::<$T>() { + match checked_pow(hi, n as usize) { + Some(x) if x <= a => hi, + _ => lo, + } + } else { + if hi.pow(n) <= a { + hi + } else { + lo + } + } + }; + } + + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T, n: u32) -> $T { + // for smaller inputs, `f64` doesn't justify its cost. + if bits::<$T>() <= 32 || x <= core::u32::MAX as $T { + 1 << ((log2(x) + n - 1) / n) + } else { + ((x as f64).ln() / f64::from(n)).exp() as $T + } + } + + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T, n: u32) -> $T { + 1 << ((log2(x) + n - 1) / n) + } + + // https://en.wikipedia.org/wiki/Nth_root_algorithm + let n1 = n - 1; + let next = |x: $T| { + let y = match checked_pow(x, n1 as usize) { + Some(ax) => a / ax, + None => 0, + }; + (y + x * n1 as $T) / n as $T + }; + fixpoint(guess(a, n), next) + } + go(*self, n) + } + + #[inline] + fn sqrt(&self) -> Self { + fn go(a: $T) -> $T { + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `sqrt` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).sqrt() as $T + } else { + let lo = (a >> 2u32).sqrt() << 1; + let hi = lo + 1; + if hi * hi <= a { + hi + } else { + lo + } + }; + } + + if a < 4 { + return (a > 0) as $T; + } + + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T) -> $T { + (x as f64).sqrt() as $T + } + + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T) -> $T { + 1 << ((log2(x) + 1) / 2) + } + + // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method + let next = |x: $T| (a / x + x) >> 1; + fixpoint(guess(a), next) + } + go(*self) + } + + #[inline] + fn cbrt(&self) -> Self { + fn go(a: $T) -> $T { + if bits::<$T>() > 64 { + // 128-bit division is slow, so do a bitwise `cbrt` until it's small enough. + return if a <= core::u64::MAX as $T { + (a as u64).cbrt() as $T + } else { + let lo = (a >> 3u32).cbrt() << 1; + let hi = lo + 1; + if hi * hi * hi <= a { + hi + } else { + lo + } + }; + } + + if bits::<$T>() <= 32 { + // Implementation based on Hacker's Delight `icbrt2` + let mut x = a; + let mut y2 = 0; + let mut y = 0; + let smax = bits::<$T>() / 3; + for s in (0..smax + 1).rev() { + let s = s * 3; + y2 *= 4; + y *= 2; + let b = 3 * (y2 + y) + 1; + if x >> s >= b { + x -= b << s; + y2 += 2 * y + 1; + y += 1; + } + } + return y; + } + + if a < 8 { + return (a > 0) as $T; + } + if a <= core::u32::MAX as $T { + return (a as u32).cbrt() as $T; + } + + #[cfg(feature = "std")] + #[inline] + fn guess(x: $T) -> $T { + (x as f64).cbrt() as $T + } + + #[cfg(not(feature = "std"))] + #[inline] + fn guess(x: $T) -> $T { + 1 << ((log2(x) + 2) / 3) + } + + // https://en.wikipedia.org/wiki/Cube_root#Numerical_methods + let next = |x: $T| (a / (x * x) + x * 2) / 3; + fixpoint(guess(a), next) + } + go(*self) + } + } + }; +} + +unsigned_roots!(u8); +unsigned_roots!(u16); +unsigned_roots!(u32); +unsigned_roots!(u64); +#[cfg(has_i128)] +unsigned_roots!(u128); +unsigned_roots!(usize); diff --git a/num-integer/tests/roots.rs b/num-integer/tests/roots.rs new file mode 100644 index 000000000..f85f9e021 --- /dev/null +++ b/num-integer/tests/roots.rs @@ -0,0 +1,272 @@ +extern crate num_integer; +extern crate num_traits; + +use num_integer::Roots; +use num_traits::checked_pow; +use num_traits::{AsPrimitive, PrimInt, Signed}; +use std::f64::MANTISSA_DIGITS; +use std::fmt::Debug; +use std::mem; + +trait TestInteger: Roots + PrimInt + Debug + AsPrimitive + 'static {} + +impl TestInteger for T where T: Roots + PrimInt + Debug + AsPrimitive + 'static {} + +/// Check that each root is correct +/// +/// If `x` is positive, check `rⁿ ≤ x < (r+1)ⁿ`. +/// If `x` is negative, check `(r-1)ⁿ < x ≤ rⁿ`. +fn check(v: &[T], n: u32) +where + T: TestInteger, +{ + for i in v { + let rt = i.nth_root(n); + // println!("nth_root({:?}, {}) = {:?}", i, n, rt); + if n == 2 { + assert_eq!(rt, i.sqrt()); + } else if n == 3 { + assert_eq!(rt, i.cbrt()); + } + if *i >= T::zero() { + let rt1 = rt + T::one(); + assert!(rt.pow(n) <= *i); + if let Some(x) = checked_pow(rt1, n as usize) { + assert!(*i < x); + } + } else { + let rt1 = rt - T::one(); + assert!(rt < T::zero()); + assert!(*i <= rt.pow(n)); + if let Some(x) = checked_pow(rt1, n as usize) { + assert!(x < *i); + } + }; + } +} + +/// Get the maximum value that will round down as `f64` (if any), +/// and its successor that will round up. +/// +/// Important because the `std` implementations cast to `f64` to +/// get a close approximation of the roots. +fn mantissa_max() -> Option<(T, T)> +where + T: TestInteger, +{ + let bits = if T::min_value().is_zero() { + 8 * mem::size_of::() + } else { + 8 * mem::size_of::() - 1 + }; + if bits > MANTISSA_DIGITS as usize { + let rounding_bit = T::one() << (bits - MANTISSA_DIGITS as usize - 1); + let x = T::max_value() - rounding_bit; + + let x1 = x + T::one(); + let x2 = x1 + T::one(); + assert!(x.as_() < x1.as_()); + assert_eq!(x1.as_(), x2.as_()); + + Some((x, x1)) + } else { + None + } +} + +fn extend(v: &mut Vec, start: T, end: T) +where + T: TestInteger, +{ + let mut i = start; + while i < end { + v.push(i); + i = i + T::one(); + } + v.push(i); +} + +fn extend_shl(v: &mut Vec, start: T, end: T, mask: T) +where + T: TestInteger, +{ + let mut i = start; + while i != end { + v.push(i); + i = (i << 1) & mask; + } +} + +fn extend_shr(v: &mut Vec, start: T, end: T) +where + T: TestInteger, +{ + let mut i = start; + while i != end { + v.push(i); + i = i >> 1; + } +} + +fn pos() -> Vec +where + T: TestInteger, + i8: AsPrimitive, +{ + let mut v: Vec = vec![]; + if mem::size_of::() == 1 { + extend(&mut v, T::zero(), T::max_value()); + } else { + extend(&mut v, T::zero(), i8::max_value().as_()); + extend( + &mut v, + T::max_value() - i8::max_value().as_(), + T::max_value(), + ); + if let Some((i, j)) = mantissa_max::() { + v.push(i); + v.push(j); + } + extend_shl(&mut v, T::max_value(), T::zero(), !T::min_value()); + extend_shr(&mut v, T::max_value(), T::zero()); + } + v +} + +fn neg() -> Vec +where + T: TestInteger + Signed, + i8: AsPrimitive, +{ + let mut v: Vec = vec![]; + if mem::size_of::() <= 1 { + extend(&mut v, T::min_value(), T::zero()); + } else { + extend(&mut v, i8::min_value().as_(), T::zero()); + extend( + &mut v, + T::min_value(), + T::min_value() - i8::min_value().as_(), + ); + if let Some((i, j)) = mantissa_max::() { + v.push(-i); + v.push(-j); + } + extend_shl(&mut v, -T::one(), T::min_value(), !T::zero()); + extend_shr(&mut v, T::min_value(), -T::one()); + } + v +} + +macro_rules! test_roots { + ($I:ident, $U:ident) => { + mod $I { + use check; + use neg; + use num_integer::Roots; + use pos; + use std::mem; + + #[test] + #[should_panic] + fn zeroth_root() { + (123 as $I).nth_root(0); + } + + #[test] + fn sqrt() { + check(&pos::<$I>(), 2); + } + + #[test] + #[should_panic] + fn sqrt_neg() { + (-123 as $I).sqrt(); + } + + #[test] + fn cbrt() { + check(&pos::<$I>(), 3); + } + + #[test] + fn cbrt_neg() { + check(&neg::<$I>(), 3); + } + + #[test] + fn nth_root() { + let bits = 8 * mem::size_of::<$I>() as u32 - 1; + let pos = pos::<$I>(); + for n in 4..bits { + check(&pos, n); + } + } + + #[test] + fn nth_root_neg() { + let bits = 8 * mem::size_of::<$I>() as u32 - 1; + let neg = neg::<$I>(); + for n in 2..bits / 2 { + check(&neg, 2 * n + 1); + } + } + + #[test] + fn bit_size() { + let bits = 8 * mem::size_of::<$I>() as u32 - 1; + assert_eq!($I::max_value().nth_root(bits - 1), 2); + assert_eq!($I::max_value().nth_root(bits), 1); + assert_eq!($I::min_value().nth_root(bits), -2); + assert_eq!(($I::min_value() + 1).nth_root(bits), -1); + } + } + + mod $U { + use check; + use num_integer::Roots; + use pos; + use std::mem; + + #[test] + #[should_panic] + fn zeroth_root() { + (123 as $U).nth_root(0); + } + + #[test] + fn sqrt() { + check(&pos::<$U>(), 2); + } + + #[test] + fn cbrt() { + check(&pos::<$U>(), 3); + } + + #[test] + fn nth_root() { + let bits = 8 * mem::size_of::<$I>() as u32 - 1; + let pos = pos::<$I>(); + for n in 4..bits { + check(&pos, n); + } + } + + #[test] + fn bit_size() { + let bits = 8 * mem::size_of::<$U>() as u32; + assert_eq!($U::max_value().nth_root(bits - 1), 2); + assert_eq!($U::max_value().nth_root(bits), 1); + } + } + }; +} + +test_roots!(i8, u8); +test_roots!(i16, u16); +test_roots!(i32, u32); +test_roots!(i64, u64); +#[cfg(has_i128)] +test_roots!(i128, u128); +test_roots!(isize, usize); diff --git a/num-traits/.cargo-checksum.json b/num-traits/.cargo-checksum.json new file mode 100644 index 000000000..e06e40521 --- /dev/null +++ b/num-traits/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"} \ No newline at end of file diff --git a/num-traits/Cargo.toml b/num-traits/Cargo.toml new file mode 100644 index 000000000..71f05ca07 --- /dev/null +++ b/num-traits/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "num-traits" +version = "0.2.8" +authors = ["The Rust Project Developers"] +build = "build.rs" +exclude = ["/ci/*", "/.travis.yml", "/bors.toml"] +description = "Numeric traits for generic mathematics" +homepage = "https://github.com/rust-num/num-traits" +documentation = "https://docs.rs/num-traits" +readme = "README.md" +keywords = ["mathematics", "numerics"] +categories = ["algorithms", "science", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-num/num-traits" +[package.metadata.docs.rs] +features = ["std"] + +[dependencies] +[build-dependencies.autocfg] +version = "0.1.3" + +[features] +default = ["std"] +i128 = [] +std = [] diff --git a/num-traits/LICENSE-APACHE b/num-traits/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/num-traits/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/num-traits/LICENSE-MIT b/num-traits/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/num-traits/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/num-traits/README.md b/num-traits/README.md new file mode 100644 index 000000000..d2ea0d0a6 --- /dev/null +++ b/num-traits/README.md @@ -0,0 +1,51 @@ +# num-traits + +[![crate](https://img.shields.io/crates/v/num-traits.svg)](https://crates.io/crates/num-traits) +[![documentation](https://docs.rs/num-traits/badge.svg)](https://docs.rs/num-traits) +![minimum rustc 1.8](https://img.shields.io/badge/rustc-1.8+-red.svg) +[![Travis status](https://travis-ci.org/rust-num/num-traits.svg?branch=master)](https://travis-ci.org/rust-num/num-traits) + +Numeric traits for generic mathematics in Rust. + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +num-traits = "0.2" +``` + +and this to your crate root: + +```rust +extern crate num_traits; +``` + +## Features + +This crate can be used without the standard library (`#![no_std]`) by disabling +the default `std` feature. Use this in `Cargo.toml`: + +```toml +[dependencies.num-traits] +version = "0.2" +default-features = false +``` + +The `Float` and `Real` traits are only available when `std` is enabled. The +`FloatCore` trait is always available. `MulAdd` and `MulAddAssign` for `f32` +and `f64` also require `std`, as do implementations of signed and floating- +point exponents in `Pow`. + +Implementations for `i128` and `u128` are only available with Rust 1.26 and +later. The build script automatically detects this, but you can make it +mandatory by enabling the `i128` crate feature. + +## Releases + +Release notes are available in [RELEASES.md](RELEASES.md). + +## Compatibility + +The `num-traits` crate is tested for rustc 1.8 and greater. diff --git a/num-traits/RELEASES.md b/num-traits/RELEASES.md new file mode 100644 index 000000000..fe1bd1763 --- /dev/null +++ b/num-traits/RELEASES.md @@ -0,0 +1,154 @@ +# Release 0.2.8 (2019-05-21) + +- [Fixed feature detection on `no_std` targets][116]. + +**Contributors**: @cuviper + +[116]: https://github.com/rust-num/num-traits/pull/116 + +# Release 0.2.7 (2019-05-20) + +- [Documented when `CheckedShl` and `CheckedShr` return `None`][90]. +- [The new `Zero::set_zero` and `One::set_one`][104] will set values to their + identities in place, possibly optimized better than direct assignment. +- [Documented general features and intentions of `PrimInt`][108]. + +**Contributors**: @cuviper, @dvdhrm, @ignatenkobrain, @lcnr, @samueltardieu + +[90]: https://github.com/rust-num/num-traits/pull/90 +[104]: https://github.com/rust-num/num-traits/pull/104 +[108]: https://github.com/rust-num/num-traits/pull/108 + +# Release 0.2.6 (2018-09-13) + +- [Documented that `pow(0, 0)` returns `1`][79]. Mathematically, this is not + strictly defined, but the current behavior is a pragmatic choice that has + precedent in Rust `core` for the primitives and in many other languages. +- [The new `WrappingShl` and `WrappingShr` traits][81] will wrap the shift count + if it exceeds the bit size of the type. + +**Contributors**: @cuviper, @edmccard, @meltinglava + +[79]: https://github.com/rust-num/num-traits/pull/79 +[81]: https://github.com/rust-num/num-traits/pull/81 + +# Release 0.2.5 (2018-06-20) + +- [Documentation for `mul_add` now clarifies that it's not always faster.][70] +- [The default methods in `FromPrimitive` and `ToPrimitive` are more robust.][73] + +**Contributors**: @cuviper, @frewsxcv + +[70]: https://github.com/rust-num/num-traits/pull/70 +[73]: https://github.com/rust-num/num-traits/pull/73 + +# Release 0.2.4 (2018-05-11) + +- [Support for 128-bit integers is now automatically detected and enabled.][69] + Setting the `i128` crate feature now causes the build script to panic if such + support is not detected. + +**Contributors**: @cuviper + +[69]: https://github.com/rust-num/num-traits/pull/69 + +# Release 0.2.3 (2018-05-10) + +- [The new `CheckedNeg` and `CheckedRem` traits][63] perform checked `Neg` and + `Rem`, returning `Some(output)` or `None` on overflow. +- [The `no_std` implementation of `FloatCore::to_degrees` for `f32`][61] now + uses a constant for greater accuracy, mirroring [rust#47919]. (With `std` it + just calls the inherent `f32::to_degrees` in the standard library.) +- [The new `MulAdd` and `MulAddAssign` traits][59] perform a fused multiply- + add. For integer types this is just a convenience, but for floating point + types this produces a more accurate result than the separate operations. +- [All applicable traits are now implemented for 128-bit integers][60] starting + with Rust 1.26, enabled by the new `i128` crate feature. The `FromPrimitive` + and `ToPrimitive` traits now also have corresponding 128-bit methods, which + default to converting via 64-bit integers for compatibility. + +**Contributors**: @cuviper, @LEXUGE, @regexident, @vks + +[59]: https://github.com/rust-num/num-traits/pull/59 +[60]: https://github.com/rust-num/num-traits/pull/60 +[61]: https://github.com/rust-num/num-traits/pull/61 +[63]: https://github.com/rust-num/num-traits/pull/63 +[rust#47919]: https://github.com/rust-lang/rust/pull/47919 + +# Release 0.2.2 (2018-03-18) + +- [Casting from floating point to integers now returns `None` on overflow][52], + avoiding [rustc's undefined behavior][rust-10184]. This applies to the `cast` + function and the traits `NumCast`, `FromPrimitive`, and `ToPrimitive`. + +**Contributors**: @apopiak, @cuviper, @dbarella + +[52]: https://github.com/rust-num/num-traits/pull/52 +[rust-10184]: https://github.com/rust-lang/rust/issues/10184 + + +# Release 0.2.1 (2018-03-01) + +- [The new `FloatCore` trait][32] offers a subset of `Float` for `#![no_std]` use. + [This includes everything][41] except the transcendental functions and FMA. +- [The new `Inv` trait][37] returns the multiplicative inverse, or reciprocal. +- [The new `Pow` trait][37] performs exponentiation, much like the existing `pow` + function, but with generic exponent types. +- [The new `One::is_one` method][39] tests if a value equals 1. Implementers + should override this method if there's a more efficient way to check for 1, + rather than comparing with a temporary `one()`. + +**Contributors**: @clarcharr, @cuviper, @vks + +[32]: https://github.com/rust-num/num-traits/pull/32 +[37]: https://github.com/rust-num/num-traits/pull/37 +[39]: https://github.com/rust-num/num-traits/pull/39 +[41]: https://github.com/rust-num/num-traits/pull/41 + + +# Release 0.2.0 (2018-02-06) + +- **breaking change**: [There is now a `std` feature][30], enabled by default, along + with the implication that building *without* this feature makes this a + `#![no_std]` crate. + - The `Float` and `Real` traits are only available when `std` is enabled. + - Otherwise, the API is unchanged, and num-traits 0.1.43 now re-exports its + items from num-traits 0.2 for compatibility (the [semver-trick]). + +**Contributors**: @cuviper, @termoshtt, @vks + +[semver-trick]: https://github.com/dtolnay/semver-trick +[30]: https://github.com/rust-num/num-traits/pull/30 + + +# Release 0.1.43 (2018-02-06) + +- All items are now [re-exported from num-traits 0.2][31] for compatibility. + +[31]: https://github.com/rust-num/num-traits/pull/31 + + +# Release 0.1.42 (2018-01-22) + +- [num-traits now has its own source repository][num-356] at [rust-num/num-traits][home]. +- [`ParseFloatError` now implements `Display`][22]. +- [The new `AsPrimitive` trait][17] implements generic casting with the `as` operator. +- [The new `CheckedShl` and `CheckedShr` traits][21] implement generic + support for the `checked_shl` and `checked_shr` methods on primitive integers. +- [The new `Real` trait][23] offers a subset of `Float` functionality that may be applicable to more + types, with a blanket implementation for all existing `T: Float` types. + +Thanks to @cuviper, @Enet4, @fabianschuiki, @svartalf, and @yoanlcq for their contributions! + +[home]: https://github.com/rust-num/num-traits +[num-356]: https://github.com/rust-num/num/pull/356 +[17]: https://github.com/rust-num/num-traits/pull/17 +[21]: https://github.com/rust-num/num-traits/pull/21 +[22]: https://github.com/rust-num/num-traits/pull/22 +[23]: https://github.com/rust-num/num-traits/pull/23 + + +# Prior releases + +No prior release notes were kept. Thanks all the same to the many +contributors that have made this crate what it is! diff --git a/num-traits/build.rs b/num-traits/build.rs new file mode 100644 index 000000000..15590bbc1 --- /dev/null +++ b/num-traits/build.rs @@ -0,0 +1,14 @@ +extern crate autocfg; + +use std::env; + +fn main() { + let ac = autocfg::new(); + if ac.probe_type("i128") { + println!("cargo:rustc-cfg=has_i128"); + } else if env::var_os("CARGO_FEATURE_I128").is_some() { + panic!("i128 support was not detected!"); + } + + autocfg::rerun_path(file!()); +} diff --git a/num-traits/src/bounds.rs b/num-traits/src/bounds.rs new file mode 100644 index 000000000..a133d7a92 --- /dev/null +++ b/num-traits/src/bounds.rs @@ -0,0 +1,127 @@ +use core::num::Wrapping; +use core::{f32, f64}; +#[cfg(has_i128)] +use core::{i128, u128}; +use core::{i16, i32, i64, i8, isize}; +use core::{u16, u32, u64, u8, usize}; + +/// Numbers which have upper and lower bounds +pub trait Bounded { + // FIXME (#5527): These should be associated constants + /// returns the smallest finite number this type can represent + fn min_value() -> Self; + /// returns the largest finite number this type can represent + fn max_value() -> Self; +} + +macro_rules! bounded_impl { + ($t:ty, $min:expr, $max:expr) => { + impl Bounded for $t { + #[inline] + fn min_value() -> $t { + $min + } + + #[inline] + fn max_value() -> $t { + $max + } + } + }; +} + +bounded_impl!(usize, usize::MIN, usize::MAX); +bounded_impl!(u8, u8::MIN, u8::MAX); +bounded_impl!(u16, u16::MIN, u16::MAX); +bounded_impl!(u32, u32::MIN, u32::MAX); +bounded_impl!(u64, u64::MIN, u64::MAX); +#[cfg(has_i128)] +bounded_impl!(u128, u128::MIN, u128::MAX); + +bounded_impl!(isize, isize::MIN, isize::MAX); +bounded_impl!(i8, i8::MIN, i8::MAX); +bounded_impl!(i16, i16::MIN, i16::MAX); +bounded_impl!(i32, i32::MIN, i32::MAX); +bounded_impl!(i64, i64::MIN, i64::MAX); +#[cfg(has_i128)] +bounded_impl!(i128, i128::MIN, i128::MAX); + +impl Bounded for Wrapping { + fn min_value() -> Self { + Wrapping(T::min_value()) + } + fn max_value() -> Self { + Wrapping(T::max_value()) + } +} + +bounded_impl!(f32, f32::MIN, f32::MAX); + +macro_rules! for_each_tuple_ { + ( $m:ident !! ) => ( + $m! { } + ); + ( $m:ident !! $h:ident, $($t:ident,)* ) => ( + $m! { $h $($t)* } + for_each_tuple_! { $m !! $($t,)* } + ); +} +macro_rules! for_each_tuple { + ($m:ident) => { + for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, } + }; +} + +macro_rules! bounded_tuple { + ( $($name:ident)* ) => ( + impl<$($name: Bounded,)*> Bounded for ($($name,)*) { + #[inline] + fn min_value() -> Self { + ($($name::min_value(),)*) + } + #[inline] + fn max_value() -> Self { + ($($name::max_value(),)*) + } + } + ); +} + +for_each_tuple!(bounded_tuple); +bounded_impl!(f64, f64::MIN, f64::MAX); + +#[test] +fn wrapping_bounded() { + macro_rules! test_wrapping_bounded { + ($($t:ty)+) => { + $( + assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value()); + assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value()); + )+ + }; + } + + test_wrapping_bounded!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[cfg(has_i128)] +#[test] +fn wrapping_bounded_i128() { + macro_rules! test_wrapping_bounded { + ($($t:ty)+) => { + $( + assert_eq!(Wrapping::<$t>::min_value().0, <$t>::min_value()); + assert_eq!(Wrapping::<$t>::max_value().0, <$t>::max_value()); + )+ + }; + } + + test_wrapping_bounded!(u128 i128); +} + +#[test] +fn wrapping_is_bounded() { + fn require_bounded(_: &T) {} + require_bounded(&Wrapping(42_u32)); + require_bounded(&Wrapping(-42)); +} diff --git a/num-traits/src/cast.rs b/num-traits/src/cast.rs new file mode 100644 index 000000000..20e93405f --- /dev/null +++ b/num-traits/src/cast.rs @@ -0,0 +1,762 @@ +use core::mem::size_of; +use core::num::Wrapping; +use core::{f32, f64}; +#[cfg(has_i128)] +use core::{i128, u128}; +use core::{i16, i32, i64, i8, isize}; +use core::{u16, u32, u64, u8, usize}; + +use float::FloatCore; + +/// A generic trait for converting a value to a number. +pub trait ToPrimitive { + /// Converts the value of `self` to an `isize`. + #[inline] + fn to_isize(&self) -> Option { + self.to_i64().as_ref().and_then(ToPrimitive::to_isize) + } + + /// Converts the value of `self` to an `i8`. + #[inline] + fn to_i8(&self) -> Option { + self.to_i64().as_ref().and_then(ToPrimitive::to_i8) + } + + /// Converts the value of `self` to an `i16`. + #[inline] + fn to_i16(&self) -> Option { + self.to_i64().as_ref().and_then(ToPrimitive::to_i16) + } + + /// Converts the value of `self` to an `i32`. + #[inline] + fn to_i32(&self) -> Option { + self.to_i64().as_ref().and_then(ToPrimitive::to_i32) + } + + /// Converts the value of `self` to an `i64`. + fn to_i64(&self) -> Option; + + /// Converts the value of `self` to an `i128`. + /// + /// This method is only available with feature `i128` enabled on Rust >= 1.26. + /// + /// The default implementation converts through `to_i64()`. Types implementing + /// this trait should override this method if they can represent a greater range. + #[inline] + #[cfg(has_i128)] + fn to_i128(&self) -> Option { + self.to_i64().map(From::from) + } + + /// Converts the value of `self` to a `usize`. + #[inline] + fn to_usize(&self) -> Option { + self.to_u64().as_ref().and_then(ToPrimitive::to_usize) + } + + /// Converts the value of `self` to an `u8`. + #[inline] + fn to_u8(&self) -> Option { + self.to_u64().as_ref().and_then(ToPrimitive::to_u8) + } + + /// Converts the value of `self` to an `u16`. + #[inline] + fn to_u16(&self) -> Option { + self.to_u64().as_ref().and_then(ToPrimitive::to_u16) + } + + /// Converts the value of `self` to an `u32`. + #[inline] + fn to_u32(&self) -> Option { + self.to_u64().as_ref().and_then(ToPrimitive::to_u32) + } + + /// Converts the value of `self` to an `u64`. + #[inline] + fn to_u64(&self) -> Option; + + /// Converts the value of `self` to an `u128`. + /// + /// This method is only available with feature `i128` enabled on Rust >= 1.26. + /// + /// The default implementation converts through `to_u64()`. Types implementing + /// this trait should override this method if they can represent a greater range. + #[inline] + #[cfg(has_i128)] + fn to_u128(&self) -> Option { + self.to_u64().map(From::from) + } + + /// Converts the value of `self` to an `f32`. + #[inline] + fn to_f32(&self) -> Option { + self.to_f64().as_ref().and_then(ToPrimitive::to_f32) + } + + /// Converts the value of `self` to an `f64`. + #[inline] + fn to_f64(&self) -> Option { + match self.to_i64() { + Some(i) => i.to_f64(), + None => self.to_u64().as_ref().and_then(ToPrimitive::to_f64), + } + } +} + +macro_rules! impl_to_primitive_int_to_int { + ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$DstT> { + let min = $DstT::MIN as $SrcT; + let max = $DstT::MAX as $SrcT; + if size_of::<$SrcT>() <= size_of::<$DstT>() || (min <= *self && *self <= max) { + Some(*self as $DstT) + } else { + None + } + } + )*} +} + +macro_rules! impl_to_primitive_int_to_uint { + ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$DstT> { + let max = $DstT::MAX as $SrcT; + if 0 <= *self && (size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max) { + Some(*self as $DstT) + } else { + None + } + } + )*} +} + +macro_rules! impl_to_primitive_int { + ($T:ident) => { + impl ToPrimitive for $T { + impl_to_primitive_int_to_int! { $T: + fn to_isize -> isize; + fn to_i8 -> i8; + fn to_i16 -> i16; + fn to_i32 -> i32; + fn to_i64 -> i64; + #[cfg(has_i128)] + fn to_i128 -> i128; + } + + impl_to_primitive_int_to_uint! { $T: + fn to_usize -> usize; + fn to_u8 -> u8; + fn to_u16 -> u16; + fn to_u32 -> u32; + fn to_u64 -> u64; + #[cfg(has_i128)] + fn to_u128 -> u128; + } + + #[inline] + fn to_f32(&self) -> Option { + Some(*self as f32) + } + #[inline] + fn to_f64(&self) -> Option { + Some(*self as f64) + } + } + }; +} + +impl_to_primitive_int!(isize); +impl_to_primitive_int!(i8); +impl_to_primitive_int!(i16); +impl_to_primitive_int!(i32); +impl_to_primitive_int!(i64); +#[cfg(has_i128)] +impl_to_primitive_int!(i128); + +macro_rules! impl_to_primitive_uint_to_int { + ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$DstT> { + let max = $DstT::MAX as $SrcT; + if size_of::<$SrcT>() < size_of::<$DstT>() || *self <= max { + Some(*self as $DstT) + } else { + None + } + } + )*} +} + +macro_rules! impl_to_primitive_uint_to_uint { + ($SrcT:ident : $( $(#[$cfg:meta])* fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$DstT> { + let max = $DstT::MAX as $SrcT; + if size_of::<$SrcT>() <= size_of::<$DstT>() || *self <= max { + Some(*self as $DstT) + } else { + None + } + } + )*} +} + +macro_rules! impl_to_primitive_uint { + ($T:ident) => { + impl ToPrimitive for $T { + impl_to_primitive_uint_to_int! { $T: + fn to_isize -> isize; + fn to_i8 -> i8; + fn to_i16 -> i16; + fn to_i32 -> i32; + fn to_i64 -> i64; + #[cfg(has_i128)] + fn to_i128 -> i128; + } + + impl_to_primitive_uint_to_uint! { $T: + fn to_usize -> usize; + fn to_u8 -> u8; + fn to_u16 -> u16; + fn to_u32 -> u32; + fn to_u64 -> u64; + #[cfg(has_i128)] + fn to_u128 -> u128; + } + + #[inline] + fn to_f32(&self) -> Option { + Some(*self as f32) + } + #[inline] + fn to_f64(&self) -> Option { + Some(*self as f64) + } + } + }; +} + +impl_to_primitive_uint!(usize); +impl_to_primitive_uint!(u8); +impl_to_primitive_uint!(u16); +impl_to_primitive_uint!(u32); +impl_to_primitive_uint!(u64); +#[cfg(has_i128)] +impl_to_primitive_uint!(u128); + +macro_rules! impl_to_primitive_float_to_float { + ($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$( + #[inline] + fn $method(&self) -> Option<$DstT> { + // Only finite values that are reducing size need to worry about overflow. + if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite(*self) { + let n = *self as f64; + if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 { + return None; + } + } + // We can safely cast NaN, +-inf, and finite values in range. + Some(*self as $DstT) + } + )*} +} + +macro_rules! impl_to_primitive_float_to_signed_int { + ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$i> { + // Float as int truncates toward zero, so we want to allow values + // in the exclusive range `(MIN-1, MAX+1)`. + if size_of::<$f>() > size_of::<$i>() { + // With a larger size, we can represent the range exactly. + const MIN_M1: $f = $i::MIN as $f - 1.0; + const MAX_P1: $f = $i::MAX as $f + 1.0; + if *self > MIN_M1 && *self < MAX_P1 { + return Some(*self as $i); + } + } else { + // We can't represent `MIN-1` exactly, but there's no fractional part + // at this magnitude, so we can just use a `MIN` inclusive boundary. + const MIN: $f = $i::MIN as $f; + // We can't represent `MAX` exactly, but it will round up to exactly + // `MAX+1` (a power of two) when we cast it. + const MAX_P1: $f = $i::MAX as $f; + if *self >= MIN && *self < MAX_P1 { + return Some(*self as $i); + } + } + None + } + )*} +} + +macro_rules! impl_to_primitive_float_to_unsigned_int { + ($f:ident : $( $(#[$cfg:meta])* fn $method:ident -> $u:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$u> { + // Float as int truncates toward zero, so we want to allow values + // in the exclusive range `(-1, MAX+1)`. + if size_of::<$f>() > size_of::<$u>() { + // With a larger size, we can represent the range exactly. + const MAX_P1: $f = $u::MAX as $f + 1.0; + if *self > -1.0 && *self < MAX_P1 { + return Some(*self as $u); + } + } else { + // We can't represent `MAX` exactly, but it will round up to exactly + // `MAX+1` (a power of two) when we cast it. + // (`u128::MAX as f32` is infinity, but this is still ok.) + const MAX_P1: $f = $u::MAX as $f; + if *self > -1.0 && *self < MAX_P1 { + return Some(*self as $u); + } + } + None + } + )*} +} + +macro_rules! impl_to_primitive_float { + ($T:ident) => { + impl ToPrimitive for $T { + impl_to_primitive_float_to_signed_int! { $T: + fn to_isize -> isize; + fn to_i8 -> i8; + fn to_i16 -> i16; + fn to_i32 -> i32; + fn to_i64 -> i64; + #[cfg(has_i128)] + fn to_i128 -> i128; + } + + impl_to_primitive_float_to_unsigned_int! { $T: + fn to_usize -> usize; + fn to_u8 -> u8; + fn to_u16 -> u16; + fn to_u32 -> u32; + fn to_u64 -> u64; + #[cfg(has_i128)] + fn to_u128 -> u128; + } + + impl_to_primitive_float_to_float! { $T: + fn to_f32 -> f32; + fn to_f64 -> f64; + } + } + }; +} + +impl_to_primitive_float!(f32); +impl_to_primitive_float!(f64); + +/// A generic trait for converting a number to a value. +pub trait FromPrimitive: Sized { + /// Convert an `isize` to return an optional value of this type. If the + /// value cannot be represented by this value, then `None` is returned. + #[inline] + fn from_isize(n: isize) -> Option { + n.to_i64().and_then(FromPrimitive::from_i64) + } + + /// Convert an `i8` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_i8(n: i8) -> Option { + FromPrimitive::from_i64(From::from(n)) + } + + /// Convert an `i16` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_i16(n: i16) -> Option { + FromPrimitive::from_i64(From::from(n)) + } + + /// Convert an `i32` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_i32(n: i32) -> Option { + FromPrimitive::from_i64(From::from(n)) + } + + /// Convert an `i64` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + fn from_i64(n: i64) -> Option; + + /// Convert an `i128` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + /// + /// This method is only available with feature `i128` enabled on Rust >= 1.26. + /// + /// The default implementation converts through `from_i64()`. Types implementing + /// this trait should override this method if they can represent a greater range. + #[inline] + #[cfg(has_i128)] + fn from_i128(n: i128) -> Option { + n.to_i64().and_then(FromPrimitive::from_i64) + } + + /// Convert a `usize` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_usize(n: usize) -> Option { + n.to_u64().and_then(FromPrimitive::from_u64) + } + + /// Convert an `u8` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_u8(n: u8) -> Option { + FromPrimitive::from_u64(From::from(n)) + } + + /// Convert an `u16` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_u16(n: u16) -> Option { + FromPrimitive::from_u64(From::from(n)) + } + + /// Convert an `u32` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_u32(n: u32) -> Option { + FromPrimitive::from_u64(From::from(n)) + } + + /// Convert an `u64` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + fn from_u64(n: u64) -> Option; + + /// Convert an `u128` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + /// + /// This method is only available with feature `i128` enabled on Rust >= 1.26. + /// + /// The default implementation converts through `from_u64()`. Types implementing + /// this trait should override this method if they can represent a greater range. + #[inline] + #[cfg(has_i128)] + fn from_u128(n: u128) -> Option { + n.to_u64().and_then(FromPrimitive::from_u64) + } + + /// Convert a `f32` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_f32(n: f32) -> Option { + FromPrimitive::from_f64(From::from(n)) + } + + /// Convert a `f64` to return an optional value of this type. If the + /// type cannot be represented by this value, then `None` is returned. + #[inline] + fn from_f64(n: f64) -> Option { + match n.to_i64() { + Some(i) => FromPrimitive::from_i64(i), + None => n.to_u64().and_then(FromPrimitive::from_u64), + } + } +} + +macro_rules! impl_from_primitive { + ($T:ty, $to_ty:ident) => { + #[allow(deprecated)] + impl FromPrimitive for $T { + #[inline] + fn from_isize(n: isize) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_i8(n: i8) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_i16(n: i16) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_i32(n: i32) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_i64(n: i64) -> Option<$T> { + n.$to_ty() + } + #[cfg(has_i128)] + #[inline] + fn from_i128(n: i128) -> Option<$T> { + n.$to_ty() + } + + #[inline] + fn from_usize(n: usize) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_u8(n: u8) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_u16(n: u16) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_u32(n: u32) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_u64(n: u64) -> Option<$T> { + n.$to_ty() + } + #[cfg(has_i128)] + #[inline] + fn from_u128(n: u128) -> Option<$T> { + n.$to_ty() + } + + #[inline] + fn from_f32(n: f32) -> Option<$T> { + n.$to_ty() + } + #[inline] + fn from_f64(n: f64) -> Option<$T> { + n.$to_ty() + } + } + }; +} + +impl_from_primitive!(isize, to_isize); +impl_from_primitive!(i8, to_i8); +impl_from_primitive!(i16, to_i16); +impl_from_primitive!(i32, to_i32); +impl_from_primitive!(i64, to_i64); +#[cfg(has_i128)] +impl_from_primitive!(i128, to_i128); +impl_from_primitive!(usize, to_usize); +impl_from_primitive!(u8, to_u8); +impl_from_primitive!(u16, to_u16); +impl_from_primitive!(u32, to_u32); +impl_from_primitive!(u64, to_u64); +#[cfg(has_i128)] +impl_from_primitive!(u128, to_u128); +impl_from_primitive!(f32, to_f32); +impl_from_primitive!(f64, to_f64); + +macro_rules! impl_to_primitive_wrapping { + ($( $(#[$cfg:meta])* fn $method:ident -> $i:ident ; )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(&self) -> Option<$i> { + (self.0).$method() + } + )*} +} + +impl ToPrimitive for Wrapping { + impl_to_primitive_wrapping! { + fn to_isize -> isize; + fn to_i8 -> i8; + fn to_i16 -> i16; + fn to_i32 -> i32; + fn to_i64 -> i64; + #[cfg(has_i128)] + fn to_i128 -> i128; + + fn to_usize -> usize; + fn to_u8 -> u8; + fn to_u16 -> u16; + fn to_u32 -> u32; + fn to_u64 -> u64; + #[cfg(has_i128)] + fn to_u128 -> u128; + + fn to_f32 -> f32; + fn to_f64 -> f64; + } +} + +macro_rules! impl_from_primitive_wrapping { + ($( $(#[$cfg:meta])* fn $method:ident ( $i:ident ); )*) => {$( + #[inline] + $(#[$cfg])* + fn $method(n: $i) -> Option { + T::$method(n).map(Wrapping) + } + )*} +} + +impl FromPrimitive for Wrapping { + impl_from_primitive_wrapping! { + fn from_isize(isize); + fn from_i8(i8); + fn from_i16(i16); + fn from_i32(i32); + fn from_i64(i64); + #[cfg(has_i128)] + fn from_i128(i128); + + fn from_usize(usize); + fn from_u8(u8); + fn from_u16(u16); + fn from_u32(u32); + fn from_u64(u64); + #[cfg(has_i128)] + fn from_u128(u128); + + fn from_f32(f32); + fn from_f64(f64); + } +} + +/// Cast from one machine scalar to another. +/// +/// # Examples +/// +/// ``` +/// # use num_traits as num; +/// let twenty: f32 = num::cast(0x14).unwrap(); +/// assert_eq!(twenty, 20f32); +/// ``` +/// +#[inline] +pub fn cast(n: T) -> Option { + NumCast::from(n) +} + +/// An interface for casting between machine scalars. +pub trait NumCast: Sized + ToPrimitive { + /// Creates a number from another value that can be converted into + /// a primitive via the `ToPrimitive` trait. + fn from(n: T) -> Option; +} + +macro_rules! impl_num_cast { + ($T:ty, $conv:ident) => { + impl NumCast for $T { + #[inline] + #[allow(deprecated)] + fn from(n: N) -> Option<$T> { + // `$conv` could be generated using `concat_idents!`, but that + // macro seems to be broken at the moment + n.$conv() + } + } + }; +} + +impl_num_cast!(u8, to_u8); +impl_num_cast!(u16, to_u16); +impl_num_cast!(u32, to_u32); +impl_num_cast!(u64, to_u64); +#[cfg(has_i128)] +impl_num_cast!(u128, to_u128); +impl_num_cast!(usize, to_usize); +impl_num_cast!(i8, to_i8); +impl_num_cast!(i16, to_i16); +impl_num_cast!(i32, to_i32); +impl_num_cast!(i64, to_i64); +#[cfg(has_i128)] +impl_num_cast!(i128, to_i128); +impl_num_cast!(isize, to_isize); +impl_num_cast!(f32, to_f32); +impl_num_cast!(f64, to_f64); + +impl NumCast for Wrapping { + fn from(n: U) -> Option { + T::from(n).map(Wrapping) + } +} + +/// A generic interface for casting between machine scalars with the +/// `as` operator, which admits narrowing and precision loss. +/// Implementers of this trait AsPrimitive should behave like a primitive +/// numeric type (e.g. a newtype around another primitive), and the +/// intended conversion must never fail. +/// +/// # Examples +/// +/// ``` +/// # use num_traits::AsPrimitive; +/// let three: i32 = (3.14159265f32).as_(); +/// assert_eq!(three, 3); +/// ``` +/// +/// # Safety +/// +/// Currently, some uses of the `as` operator are not entirely safe. +/// In particular, it is undefined behavior if: +/// +/// - A truncated floating point value cannot fit in the target integer +/// type ([#10184](https://github.com/rust-lang/rust/issues/10184)); +/// +/// ```ignore +/// # use num_traits::AsPrimitive; +/// let x: u8 = (1.04E+17).as_(); // UB +/// ``` +/// +/// - Or a floating point value does not fit in another floating +/// point type ([#15536](https://github.com/rust-lang/rust/issues/15536)). +/// +/// ```ignore +/// # use num_traits::AsPrimitive; +/// let x: f32 = (1e300f64).as_(); // UB +/// ``` +/// +pub trait AsPrimitive: 'static + Copy +where + T: 'static + Copy, +{ + /// Convert a value to another, using the `as` operator. + fn as_(self) -> T; +} + +macro_rules! impl_as_primitive { + (@ $T: ty => $(#[$cfg:meta])* impl $U: ty ) => { + $(#[$cfg])* + impl AsPrimitive<$U> for $T { + #[inline] fn as_(self) -> $U { self as $U } + } + }; + (@ $T: ty => { $( $U: ty ),* } ) => {$( + impl_as_primitive!(@ $T => impl $U); + )*}; + ($T: ty => { $( $U: ty ),* } ) => { + impl_as_primitive!(@ $T => { $( $U ),* }); + impl_as_primitive!(@ $T => { u8, u16, u32, u64, usize }); + impl_as_primitive!(@ $T => #[cfg(has_i128)] impl u128); + impl_as_primitive!(@ $T => { i8, i16, i32, i64, isize }); + impl_as_primitive!(@ $T => #[cfg(has_i128)] impl i128); + }; +} + +impl_as_primitive!(u8 => { char, f32, f64 }); +impl_as_primitive!(i8 => { f32, f64 }); +impl_as_primitive!(u16 => { f32, f64 }); +impl_as_primitive!(i16 => { f32, f64 }); +impl_as_primitive!(u32 => { f32, f64 }); +impl_as_primitive!(i32 => { f32, f64 }); +impl_as_primitive!(u64 => { f32, f64 }); +impl_as_primitive!(i64 => { f32, f64 }); +#[cfg(has_i128)] +impl_as_primitive!(u128 => { f32, f64 }); +#[cfg(has_i128)] +impl_as_primitive!(i128 => { f32, f64 }); +impl_as_primitive!(usize => { f32, f64 }); +impl_as_primitive!(isize => { f32, f64 }); +impl_as_primitive!(f32 => { f32, f64 }); +impl_as_primitive!(f64 => { f32, f64 }); +impl_as_primitive!(char => { char }); +impl_as_primitive!(bool => {}); diff --git a/num-traits/src/float.rs b/num-traits/src/float.rs new file mode 100644 index 000000000..c91233cb7 --- /dev/null +++ b/num-traits/src/float.rs @@ -0,0 +1,2024 @@ +use core::mem; +use core::num::FpCategory; +use core::ops::Neg; + +use core::f32; +use core::f64; + +use {Num, NumCast, ToPrimitive}; + +/// Generic trait for floating point numbers that works with `no_std`. +/// +/// This trait implements a subset of the `Float` trait. +pub trait FloatCore: Num + NumCast + Neg + PartialOrd + Copy { + /// Returns positive infinity. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::infinity() == x); + /// } + /// + /// check(f32::INFINITY); + /// check(f64::INFINITY); + /// ``` + fn infinity() -> Self; + + /// Returns negative infinity. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::neg_infinity() == x); + /// } + /// + /// check(f32::NEG_INFINITY); + /// check(f64::NEG_INFINITY); + /// ``` + fn neg_infinity() -> Self; + + /// Returns NaN. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// + /// fn check() { + /// let n = T::nan(); + /// assert!(n != n); + /// } + /// + /// check::(); + /// check::(); + /// ``` + fn nan() -> Self; + + /// Returns `-0.0`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(n: T) { + /// let z = T::neg_zero(); + /// assert!(z.is_zero()); + /// assert!(T::one() / z == n); + /// } + /// + /// check(f32::NEG_INFINITY); + /// check(f64::NEG_INFINITY); + /// ``` + fn neg_zero() -> Self; + + /// Returns the smallest finite value that this type can represent. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::min_value() == x); + /// } + /// + /// check(f32::MIN); + /// check(f64::MIN); + /// ``` + fn min_value() -> Self; + + /// Returns the smallest positive, normalized value that this type can represent. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::min_positive_value() == x); + /// } + /// + /// check(f32::MIN_POSITIVE); + /// check(f64::MIN_POSITIVE); + /// ``` + fn min_positive_value() -> Self; + + /// Returns epsilon, a small positive value. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::epsilon() == x); + /// } + /// + /// check(f32::EPSILON); + /// check(f64::EPSILON); + /// ``` + fn epsilon() -> Self; + + /// Returns the largest finite value that this type can represent. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T) { + /// assert!(T::max_value() == x); + /// } + /// + /// check(f32::MAX); + /// check(f64::MAX); + /// ``` + fn max_value() -> Self; + + /// Returns `true` if the number is NaN. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_nan() == p); + /// } + /// + /// check(f32::NAN, true); + /// check(f32::INFINITY, false); + /// check(f64::NAN, true); + /// check(0.0f64, false); + /// ``` + #[inline] + fn is_nan(self) -> bool { + self != self + } + + /// Returns `true` if the number is infinite. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_infinite() == p); + /// } + /// + /// check(f32::INFINITY, true); + /// check(f32::NEG_INFINITY, true); + /// check(f32::NAN, false); + /// check(f64::INFINITY, true); + /// check(f64::NEG_INFINITY, true); + /// check(0.0f64, false); + /// ``` + #[inline] + fn is_infinite(self) -> bool { + self == Self::infinity() || self == Self::neg_infinity() + } + + /// Returns `true` if the number is neither infinite or NaN. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_finite() == p); + /// } + /// + /// check(f32::INFINITY, false); + /// check(f32::MAX, true); + /// check(f64::NEG_INFINITY, false); + /// check(f64::MIN_POSITIVE, true); + /// check(f64::NAN, false); + /// ``` + #[inline] + fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } + + /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_normal() == p); + /// } + /// + /// check(f32::INFINITY, false); + /// check(f32::MAX, true); + /// check(f64::NEG_INFINITY, false); + /// check(f64::MIN_POSITIVE, true); + /// check(0.0f64, false); + /// ``` + #[inline] + fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// use std::num::FpCategory; + /// + /// fn check(x: T, c: FpCategory) { + /// assert!(x.classify() == c); + /// } + /// + /// check(f32::INFINITY, FpCategory::Infinite); + /// check(f32::MAX, FpCategory::Normal); + /// check(f64::NAN, FpCategory::Nan); + /// check(f64::MIN_POSITIVE, FpCategory::Normal); + /// check(f64::MIN_POSITIVE / 2.0, FpCategory::Subnormal); + /// check(0.0f64, FpCategory::Zero); + /// ``` + fn classify(self) -> FpCategory; + + /// Returns the largest integer less than or equal to a number. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.floor() == y); + /// } + /// + /// check(f32::INFINITY, f32::INFINITY); + /// check(0.9f32, 0.0); + /// check(1.0f32, 1.0); + /// check(1.1f32, 1.0); + /// check(-0.0f64, 0.0); + /// check(-0.9f64, -1.0); + /// check(-1.0f64, -1.0); + /// check(-1.1f64, -2.0); + /// check(f64::MIN, f64::MIN); + /// ``` + #[inline] + fn floor(self) -> Self { + let f = self.fract(); + if f.is_nan() || f.is_zero() { + self + } else if self < Self::zero() { + self - f - Self::one() + } else { + self - f + } + } + + /// Returns the smallest integer greater than or equal to a number. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.ceil() == y); + /// } + /// + /// check(f32::INFINITY, f32::INFINITY); + /// check(0.9f32, 1.0); + /// check(1.0f32, 1.0); + /// check(1.1f32, 2.0); + /// check(-0.0f64, 0.0); + /// check(-0.9f64, -0.0); + /// check(-1.0f64, -1.0); + /// check(-1.1f64, -1.0); + /// check(f64::MIN, f64::MIN); + /// ``` + #[inline] + fn ceil(self) -> Self { + let f = self.fract(); + if f.is_nan() || f.is_zero() { + self + } else if self > Self::zero() { + self - f + Self::one() + } else { + self - f + } + } + + /// Returns the nearest integer to a number. Round half-way cases away from `0.0`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.round() == y); + /// } + /// + /// check(f32::INFINITY, f32::INFINITY); + /// check(0.4f32, 0.0); + /// check(0.5f32, 1.0); + /// check(0.6f32, 1.0); + /// check(-0.4f64, 0.0); + /// check(-0.5f64, -1.0); + /// check(-0.6f64, -1.0); + /// check(f64::MIN, f64::MIN); + /// ``` + #[inline] + fn round(self) -> Self { + let one = Self::one(); + let h = Self::from(0.5).expect("Unable to cast from 0.5"); + let f = self.fract(); + if f.is_nan() || f.is_zero() { + self + } else if self > Self::zero() { + if f < h { + self - f + } else { + self - f + one + } + } else { + if -f < h { + self - f + } else { + self - f - one + } + } + } + + /// Return the integer part of a number. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.trunc() == y); + /// } + /// + /// check(f32::INFINITY, f32::INFINITY); + /// check(0.9f32, 0.0); + /// check(1.0f32, 1.0); + /// check(1.1f32, 1.0); + /// check(-0.0f64, 0.0); + /// check(-0.9f64, -0.0); + /// check(-1.0f64, -1.0); + /// check(-1.1f64, -1.0); + /// check(f64::MIN, f64::MIN); + /// ``` + #[inline] + fn trunc(self) -> Self { + let f = self.fract(); + if f.is_nan() { + self + } else { + self - f + } + } + + /// Returns the fractional part of a number. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.fract() == y); + /// } + /// + /// check(f32::MAX, 0.0); + /// check(0.75f32, 0.75); + /// check(1.0f32, 0.0); + /// check(1.25f32, 0.25); + /// check(-0.0f64, 0.0); + /// check(-0.75f64, -0.75); + /// check(-1.0f64, 0.0); + /// check(-1.25f64, -0.25); + /// check(f64::MIN, 0.0); + /// ``` + #[inline] + fn fract(self) -> Self { + if self.is_zero() { + Self::zero() + } else { + self % Self::one() + } + } + + /// Computes the absolute value of `self`. Returns `FloatCore::nan()` if the + /// number is `FloatCore::nan()`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.abs() == y); + /// } + /// + /// check(f32::INFINITY, f32::INFINITY); + /// check(1.0f32, 1.0); + /// check(0.0f64, 0.0); + /// check(-0.0f64, 0.0); + /// check(-1.0f64, 1.0); + /// check(f64::MIN, f64::MAX); + /// ``` + #[inline] + fn abs(self) -> Self { + if self.is_sign_positive() { + return self; + } + if self.is_sign_negative() { + return -self; + } + Self::nan() + } + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `FloatCore::infinity()` + /// - `-1.0` if the number is negative, `-0.0` or `FloatCore::neg_infinity()` + /// - `FloatCore::nan()` if the number is `FloatCore::nan()` + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.signum() == y); + /// } + /// + /// check(f32::INFINITY, 1.0); + /// check(3.0f32, 1.0); + /// check(0.0f32, 1.0); + /// check(-0.0f64, -1.0); + /// check(-3.0f64, -1.0); + /// check(f64::MIN, -1.0); + /// ``` + #[inline] + fn signum(self) -> Self { + if self.is_nan() { + Self::nan() + } else if self.is_sign_negative() { + -Self::one() + } else { + Self::one() + } + } + + /// Returns `true` if `self` is positive, including `+0.0` and + /// `FloatCore::infinity()`, and since Rust 1.20 also + /// `FloatCore::nan()`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_sign_positive() == p); + /// } + /// + /// check(f32::INFINITY, true); + /// check(f32::MAX, true); + /// check(0.0f32, true); + /// check(-0.0f64, false); + /// check(f64::NEG_INFINITY, false); + /// check(f64::MIN_POSITIVE, true); + /// check(-f64::NAN, false); + /// ``` + #[inline] + fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } + + /// Returns `true` if `self` is negative, including `-0.0` and + /// `FloatCore::neg_infinity()`, and since Rust 1.20 also + /// `-FloatCore::nan()`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, p: bool) { + /// assert!(x.is_sign_negative() == p); + /// } + /// + /// check(f32::INFINITY, false); + /// check(f32::MAX, false); + /// check(0.0f32, false); + /// check(-0.0f64, true); + /// check(f64::NEG_INFINITY, true); + /// check(f64::MIN_POSITIVE, false); + /// check(f64::NAN, false); + /// ``` + #[inline] + fn is_sign_negative(self) -> bool { + let (_, _, sign) = self.integer_decode(); + sign < 0 + } + + /// Returns the minimum of the two numbers. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T, min: T) { + /// assert!(x.min(y) == min); + /// } + /// + /// check(1.0f32, 2.0, 1.0); + /// check(f32::NAN, 2.0, 2.0); + /// check(1.0f64, -2.0, -2.0); + /// check(1.0f64, f64::NAN, 1.0); + /// ``` + #[inline] + fn min(self, other: Self) -> Self { + if self.is_nan() { + return other; + } + if other.is_nan() { + return self; + } + if self < other { + self + } else { + other + } + } + + /// Returns the maximum of the two numbers. + /// + /// If one of the arguments is NaN, then the other argument is returned. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T, min: T) { + /// assert!(x.max(y) == min); + /// } + /// + /// check(1.0f32, 2.0, 2.0); + /// check(1.0f32, f32::NAN, 1.0); + /// check(-1.0f64, 2.0, 2.0); + /// check(-1.0f64, f64::NAN, -1.0); + /// ``` + #[inline] + fn max(self, other: Self) -> Self { + if self.is_nan() { + return other; + } + if other.is_nan() { + return self; + } + if self > other { + self + } else { + other + } + } + + /// Returns the reciprocal (multiplicative inverse) of the number. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, y: T) { + /// assert!(x.recip() == y); + /// assert!(y.recip() == x); + /// } + /// + /// check(f32::INFINITY, 0.0); + /// check(2.0f32, 0.5); + /// check(-0.25f64, -4.0); + /// check(-0.0f64, f64::NEG_INFINITY); + /// ``` + #[inline] + fn recip(self) -> Self { + Self::one() / self + } + + /// Raise a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// + /// fn check(x: T, exp: i32, powi: T) { + /// assert!(x.powi(exp) == powi); + /// } + /// + /// check(9.0f32, 2, 81.0); + /// check(1.0f32, -2, 1.0); + /// check(10.0f64, 20, 1e20); + /// check(4.0f64, -2, 0.0625); + /// check(-1.0f64, std::i32::MIN, 1.0); + /// ``` + #[inline] + fn powi(mut self, mut exp: i32) -> Self { + if exp < 0 { + exp = exp.wrapping_neg(); + self = self.recip(); + } + // It should always be possible to convert a positive `i32` to a `usize`. + // Note, `i32::MIN` will wrap and still be negative, so we need to convert + // to `u32` without sign-extension before growing to `usize`. + super::pow(self, (exp as u32).to_usize().unwrap()) + } + + /// Converts to degrees, assuming the number is in radians. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(rad: T, deg: T) { + /// assert!(rad.to_degrees() == deg); + /// } + /// + /// check(0.0f32, 0.0); + /// check(f32::consts::PI, 180.0); + /// check(f64::consts::FRAC_PI_4, 45.0); + /// check(f64::INFINITY, f64::INFINITY); + /// ``` + fn to_degrees(self) -> Self; + + /// Converts to radians, assuming the number is in degrees. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(deg: T, rad: T) { + /// assert!(deg.to_radians() == rad); + /// } + /// + /// check(0.0f32, 0.0); + /// check(180.0, f32::consts::PI); + /// check(45.0, f64::consts::FRAC_PI_4); + /// check(f64::INFINITY, f64::INFINITY); + /// ``` + fn to_radians(self) -> Self; + + /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. + /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::float::FloatCore; + /// use std::{f32, f64}; + /// + /// fn check(x: T, m: u64, e: i16, s:i8) { + /// let (mantissa, exponent, sign) = x.integer_decode(); + /// assert_eq!(mantissa, m); + /// assert_eq!(exponent, e); + /// assert_eq!(sign, s); + /// } + /// + /// check(2.0f32, 1 << 23, -22, 1); + /// check(-2.0f32, 1 << 23, -22, -1); + /// check(f32::INFINITY, 1 << 23, 105, 1); + /// check(f64::NEG_INFINITY, 1 << 52, 972, -1); + /// ``` + fn integer_decode(self) -> (u64, i16, i8); +} + +impl FloatCore for f32 { + constant! { + infinity() -> f32::INFINITY; + neg_infinity() -> f32::NEG_INFINITY; + nan() -> f32::NAN; + neg_zero() -> -0.0; + min_value() -> f32::MIN; + min_positive_value() -> f32::MIN_POSITIVE; + epsilon() -> f32::EPSILON; + max_value() -> f32::MAX; + } + + #[inline] + fn integer_decode(self) -> (u64, i16, i8) { + integer_decode_f32(self) + } + + #[inline] + #[cfg(not(feature = "std"))] + fn classify(self) -> FpCategory { + const EXP_MASK: u32 = 0x7f800000; + const MAN_MASK: u32 = 0x007fffff; + + let bits: u32 = unsafe { mem::transmute(self) }; + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } + + #[inline] + #[cfg(not(feature = "std"))] + fn to_degrees(self) -> Self { + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 + } + + #[inline] + #[cfg(not(feature = "std"))] + fn to_radians(self) -> Self { + self * (f32::consts::PI / 180.0) + } + + #[cfg(feature = "std")] + forward! { + Self::is_nan(self) -> bool; + Self::is_infinite(self) -> bool; + Self::is_finite(self) -> bool; + Self::is_normal(self) -> bool; + Self::classify(self) -> FpCategory; + Self::floor(self) -> Self; + Self::ceil(self) -> Self; + Self::round(self) -> Self; + Self::trunc(self) -> Self; + Self::fract(self) -> Self; + Self::abs(self) -> Self; + Self::signum(self) -> Self; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::min(self, other: Self) -> Self; + Self::max(self, other: Self) -> Self; + Self::recip(self) -> Self; + Self::powi(self, n: i32) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + } +} + +impl FloatCore for f64 { + constant! { + infinity() -> f64::INFINITY; + neg_infinity() -> f64::NEG_INFINITY; + nan() -> f64::NAN; + neg_zero() -> -0.0; + min_value() -> f64::MIN; + min_positive_value() -> f64::MIN_POSITIVE; + epsilon() -> f64::EPSILON; + max_value() -> f64::MAX; + } + + #[inline] + fn integer_decode(self) -> (u64, i16, i8) { + integer_decode_f64(self) + } + + #[inline] + #[cfg(not(feature = "std"))] + fn classify(self) -> FpCategory { + const EXP_MASK: u64 = 0x7ff0000000000000; + const MAN_MASK: u64 = 0x000fffffffffffff; + + let bits: u64 = unsafe { mem::transmute(self) }; + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } + + #[inline] + #[cfg(not(feature = "std"))] + fn to_degrees(self) -> Self { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) + self * (180.0 / f64::consts::PI) + } + + #[inline] + #[cfg(not(feature = "std"))] + fn to_radians(self) -> Self { + self * (f64::consts::PI / 180.0) + } + + #[cfg(feature = "std")] + forward! { + Self::is_nan(self) -> bool; + Self::is_infinite(self) -> bool; + Self::is_finite(self) -> bool; + Self::is_normal(self) -> bool; + Self::classify(self) -> FpCategory; + Self::floor(self) -> Self; + Self::ceil(self) -> Self; + Self::round(self) -> Self; + Self::trunc(self) -> Self; + Self::fract(self) -> Self; + Self::abs(self) -> Self; + Self::signum(self) -> Self; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::min(self, other: Self) -> Self; + Self::max(self, other: Self) -> Self; + Self::recip(self) -> Self; + Self::powi(self, n: i32) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + } +} + +// FIXME: these doctests aren't actually helpful, because they're using and +// testing the inherent methods directly, not going through `Float`. + +/// Generic trait for floating point numbers +/// +/// This trait is only available with the `std` feature. +#[cfg(feature = "std")] +pub trait Float: Num + Copy + NumCast + PartialOrd + Neg { + /// Returns the `NaN` value. + /// + /// ``` + /// use num_traits::Float; + /// + /// let nan: f32 = Float::nan(); + /// + /// assert!(nan.is_nan()); + /// ``` + fn nan() -> Self; + /// Returns the infinite value. + /// + /// ``` + /// use num_traits::Float; + /// use std::f32; + /// + /// let infinity: f32 = Float::infinity(); + /// + /// assert!(infinity.is_infinite()); + /// assert!(!infinity.is_finite()); + /// assert!(infinity > f32::MAX); + /// ``` + fn infinity() -> Self; + /// Returns the negative infinite value. + /// + /// ``` + /// use num_traits::Float; + /// use std::f32; + /// + /// let neg_infinity: f32 = Float::neg_infinity(); + /// + /// assert!(neg_infinity.is_infinite()); + /// assert!(!neg_infinity.is_finite()); + /// assert!(neg_infinity < f32::MIN); + /// ``` + fn neg_infinity() -> Self; + /// Returns `-0.0`. + /// + /// ``` + /// use num_traits::{Zero, Float}; + /// + /// let inf: f32 = Float::infinity(); + /// let zero: f32 = Zero::zero(); + /// let neg_zero: f32 = Float::neg_zero(); + /// + /// assert_eq!(zero, neg_zero); + /// assert_eq!(7.0f32/inf, zero); + /// assert_eq!(zero * 10.0, zero); + /// ``` + fn neg_zero() -> Self; + + /// Returns the smallest finite value that this type can represent. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x: f64 = Float::min_value(); + /// + /// assert_eq!(x, f64::MIN); + /// ``` + fn min_value() -> Self; + + /// Returns the smallest positive, normalized value that this type can represent. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x: f64 = Float::min_positive_value(); + /// + /// assert_eq!(x, f64::MIN_POSITIVE); + /// ``` + fn min_positive_value() -> Self; + + /// Returns epsilon, a small positive value. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x: f64 = Float::epsilon(); + /// + /// assert_eq!(x, f64::EPSILON); + /// ``` + /// + /// # Panics + /// + /// The default implementation will panic if `f32::EPSILON` cannot + /// be cast to `Self`. + fn epsilon() -> Self { + Self::from(f32::EPSILON).expect("Unable to cast from f32::EPSILON") + } + + /// Returns the largest finite value that this type can represent. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x: f64 = Float::max_value(); + /// assert_eq!(x, f64::MAX); + /// ``` + fn max_value() -> Self; + + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + fn is_nan(self) -> bool; + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use num_traits::Float; + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf: f32 = Float::infinity(); + /// let neg_inf: f32 = Float::neg_infinity(); + /// let nan: f32 = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + fn is_infinite(self) -> bool; + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf: f32 = Float::infinity(); + /// let neg_inf: f32 = Float::neg_infinity(); + /// let nan: f32 = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + fn is_finite(self) -> bool; + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number + fn is_normal(self) -> bool; + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use num_traits::Float; + /// use std::num::FpCategory; + /// use std::f32; + /// + /// let num = 12.4f32; + /// let inf = f32::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + fn classify(self) -> FpCategory; + + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 3.99; + /// let g = 3.0; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// ``` + fn floor(self) -> Self; + + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 3.01; + /// let g = 4.0; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` + fn ceil(self) -> Self; + + /// Returns the nearest integer to a number. Round half-way cases away from + /// `0.0`. + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 3.3; + /// let g = -3.3; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// ``` + fn round(self) -> Self; + + /// Return the integer part of a number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 3.3; + /// let g = -3.7; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), -3.0); + /// ``` + fn trunc(self) -> Self; + + /// Returns the fractional part of a number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 3.5; + /// let y = -3.5; + /// let abs_difference_x = (x.fract() - 0.5).abs(); + /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + fn fract(self) -> Self; + + /// Computes the absolute value of `self`. Returns `Float::nan()` if the + /// number is `Float::nan()`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = 3.5; + /// let y = -3.5; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// + /// assert!(f64::NAN.abs().is_nan()); + /// ``` + fn abs(self) -> Self; + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` + /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` + /// - `Float::nan()` if the number is `Float::nan()` + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let f = 3.5; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + fn signum(self) -> Self; + + /// Returns `true` if `self` is positive, including `+0.0`, + /// `Float::infinity()`, and since Rust 1.20 also `Float::nan()`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let neg_nan: f64 = -f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// assert!(!neg_nan.is_sign_positive()); + /// ``` + fn is_sign_positive(self) -> bool; + + /// Returns `true` if `self` is negative, including `-0.0`, + /// `Float::neg_infinity()`, and since Rust 1.20 also `-Float::nan()`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let nan: f64 = f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// assert!(!nan.is_sign_negative()); + /// ``` + fn is_sign_negative(self) -> bool; + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. + /// + /// ``` + /// use num_traits::Float; + /// + /// let m = 10.0; + /// let x = 4.0; + /// let b = 60.0; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn mul_add(self, a: Self, b: Self) -> Self; + /// Take the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn recip(self) -> Self; + + /// Raise a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.powi(2) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn powi(self, n: i32) -> Self; + + /// Raise a number to a floating point power. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 2.0; + /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn powf(self, n: Self) -> Self; + + /// Take the square root of a number. + /// + /// Returns NaN if `self` is a negative number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let positive = 4.0; + /// let negative = -4.0; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(negative.sqrt().is_nan()); + /// ``` + fn sqrt(self) -> Self; + + /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// use num_traits::Float; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp(self) -> Self; + + /// Returns `2^(self)`. + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 2.0; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp2(self) -> Self; + + /// Returns the natural logarithm of the number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn ln(self) -> Self; + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// ``` + /// use num_traits::Float; + /// + /// let ten = 10.0; + /// let two = 2.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// assert!(abs_difference_10 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn log(self, base: Self) -> Self; + + /// Returns the base 2 logarithm of the number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let two = 2.0; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log2(self) -> Self; + + /// Returns the base 10 logarithm of the number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let ten = 10.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log10(self) -> Self; + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[inline] + fn to_degrees(self) -> Self { + let halfpi = Self::zero().acos(); + let ninety = Self::from(90u8).unwrap(); + self * ninety / halfpi + } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[inline] + fn to_radians(self) -> Self { + let halfpi = Self::zero().acos(); + let ninety = Self::from(90u8).unwrap(); + self * halfpi / ninety + } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.max(y), y); + /// ``` + fn max(self, other: Self) -> Self; + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.min(y), x); + /// ``` + fn min(self, other: Self) -> Self; + + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 3.0; + /// let y = -3.0; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + fn abs_sub(self, other: Self) -> Self; + + /// Take the cubic root of a number. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 8.0; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cbrt(self) -> Self; + + /// Calculate the length of the hypotenuse of a right-angle triangle given + /// legs of length `x` and `y`. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 2.0; + /// let y = 3.0; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn hypot(self, other: Self) -> Self; + + /// Computes the sine of a number (in radians). + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sin(self) -> Self; + + /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = 2.0*f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cos(self) -> Self; + + /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + fn tan(self) -> Self; + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let f = f64::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn asin(self) -> Self; + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let f = f64::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn acos(self) -> Self; + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// ``` + /// use num_traits::Float; + /// + /// let f = 1.0; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn atan(self) -> Self; + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let pi = f64::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0; + /// let y1 = -3.0; + /// + /// // 135 deg clockwise + /// let x2 = -3.0; + /// let y2 = 3.0; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn atan2(self, other: Self) -> Self; + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_0 < 1e-10); + /// ``` + fn sin_cos(self) -> (Self, Self); + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 7.0; + /// + /// // e^(ln(7)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp_m1(self) -> Self; + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let x = f64::consts::E - 1.0; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let abs_difference = (x.ln_1p() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn ln_1p(self) -> Self; + + /// Hyperbolic sine function. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = (e*e - 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sinh(self) -> Self; + + /// Hyperbolic cosine function. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = (e*e + 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn cosh(self) -> Self; + + /// Hyperbolic tangent function. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn tanh(self) -> Self; + + /// Inverse hyperbolic sine function. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 1.0; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn asinh(self) -> Self; + + /// Inverse hyperbolic cosine function. + /// + /// ``` + /// use num_traits::Float; + /// + /// let x = 1.0; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn acosh(self) -> Self; + + /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use num_traits::Float; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn atanh(self) -> Self; + + /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. + /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. + /// + /// ``` + /// use num_traits::Float; + /// + /// let num = 2.0f32; + /// + /// // (8388608, -22, 1) + /// let (mantissa, exponent, sign) = Float::integer_decode(num); + /// let sign_f = sign as f32; + /// let mantissa_f = mantissa as f32; + /// let exponent_f = num.powf(exponent as f32); + /// + /// // 1 * 8388608 * 2^(-22) == 2 + /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn integer_decode(self) -> (u64, i16, i8); +} + +#[cfg(feature = "std")] +macro_rules! float_impl { + ($T:ident $decode:ident) => { + impl Float for $T { + constant! { + nan() -> $T::NAN; + infinity() -> $T::INFINITY; + neg_infinity() -> $T::NEG_INFINITY; + neg_zero() -> -0.0; + min_value() -> $T::MIN; + min_positive_value() -> $T::MIN_POSITIVE; + epsilon() -> $T::EPSILON; + max_value() -> $T::MAX; + } + + #[inline] + #[allow(deprecated)] + fn abs_sub(self, other: Self) -> Self { + <$T>::abs_sub(self, other) + } + + #[inline] + fn integer_decode(self) -> (u64, i16, i8) { + $decode(self) + } + + forward! { + Self::is_nan(self) -> bool; + Self::is_infinite(self) -> bool; + Self::is_finite(self) -> bool; + Self::is_normal(self) -> bool; + Self::classify(self) -> FpCategory; + Self::floor(self) -> Self; + Self::ceil(self) -> Self; + Self::round(self) -> Self; + Self::trunc(self) -> Self; + Self::fract(self) -> Self; + Self::abs(self) -> Self; + Self::signum(self) -> Self; + Self::is_sign_positive(self) -> bool; + Self::is_sign_negative(self) -> bool; + Self::mul_add(self, a: Self, b: Self) -> Self; + Self::recip(self) -> Self; + Self::powi(self, n: i32) -> Self; + Self::powf(self, n: Self) -> Self; + Self::sqrt(self) -> Self; + Self::exp(self) -> Self; + Self::exp2(self) -> Self; + Self::ln(self) -> Self; + Self::log(self, base: Self) -> Self; + Self::log2(self) -> Self; + Self::log10(self) -> Self; + Self::to_degrees(self) -> Self; + Self::to_radians(self) -> Self; + Self::max(self, other: Self) -> Self; + Self::min(self, other: Self) -> Self; + Self::cbrt(self) -> Self; + Self::hypot(self, other: Self) -> Self; + Self::sin(self) -> Self; + Self::cos(self) -> Self; + Self::tan(self) -> Self; + Self::asin(self) -> Self; + Self::acos(self) -> Self; + Self::atan(self) -> Self; + Self::atan2(self, other: Self) -> Self; + Self::sin_cos(self) -> (Self, Self); + Self::exp_m1(self) -> Self; + Self::ln_1p(self) -> Self; + Self::sinh(self) -> Self; + Self::cosh(self) -> Self; + Self::tanh(self) -> Self; + Self::asinh(self) -> Self; + Self::acosh(self) -> Self; + Self::atanh(self) -> Self; + } + } + }; +} + +fn integer_decode_f32(f: f32) -> (u64, i16, i8) { + let bits: u32 = unsafe { mem::transmute(f) }; + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = if exponent == 0 { + (bits & 0x7fffff) << 1 + } else { + (bits & 0x7fffff) | 0x800000 + }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) +} + +fn integer_decode_f64(f: f64) -> (u64, i16, i8) { + let bits: u64 = unsafe { mem::transmute(f) }; + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) +} + +#[cfg(feature = "std")] +float_impl!(f32 integer_decode_f32); +#[cfg(feature = "std")] +float_impl!(f64 integer_decode_f64); + +macro_rules! float_const_impl { + ($(#[$doc:meta] $constant:ident,)+) => ( + #[allow(non_snake_case)] + pub trait FloatConst { + $(#[$doc] fn $constant() -> Self;)+ + } + float_const_impl! { @float f32, $($constant,)+ } + float_const_impl! { @float f64, $($constant,)+ } + ); + (@float $T:ident, $($constant:ident,)+) => ( + impl FloatConst for $T { + constant! { + $( $constant() -> $T::consts::$constant; )+ + } + } + ); +} + +float_const_impl! { + #[doc = "Return Euler’s number."] + E, + #[doc = "Return `1.0 / π`."] + FRAC_1_PI, + #[doc = "Return `1.0 / sqrt(2.0)`."] + FRAC_1_SQRT_2, + #[doc = "Return `2.0 / π`."] + FRAC_2_PI, + #[doc = "Return `2.0 / sqrt(π)`."] + FRAC_2_SQRT_PI, + #[doc = "Return `π / 2.0`."] + FRAC_PI_2, + #[doc = "Return `π / 3.0`."] + FRAC_PI_3, + #[doc = "Return `π / 4.0`."] + FRAC_PI_4, + #[doc = "Return `π / 6.0`."] + FRAC_PI_6, + #[doc = "Return `π / 8.0`."] + FRAC_PI_8, + #[doc = "Return `ln(10.0)`."] + LN_10, + #[doc = "Return `ln(2.0)`."] + LN_2, + #[doc = "Return `log10(e)`."] + LOG10_E, + #[doc = "Return `log2(e)`."] + LOG2_E, + #[doc = "Return Archimedes’ constant."] + PI, + #[doc = "Return `sqrt(2.0)`."] + SQRT_2, +} + +#[cfg(test)] +mod tests { + use core::f64::consts; + + const DEG_RAD_PAIRS: [(f64, f64); 7] = [ + (0.0, 0.), + (22.5, consts::FRAC_PI_8), + (30.0, consts::FRAC_PI_6), + (45.0, consts::FRAC_PI_4), + (60.0, consts::FRAC_PI_3), + (90.0, consts::FRAC_PI_2), + (180.0, consts::PI), + ]; + + #[test] + fn convert_deg_rad() { + use float::FloatCore; + + for &(deg, rad) in &DEG_RAD_PAIRS { + assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-6); + assert!((FloatCore::to_radians(deg) - rad).abs() < 1e-6); + + let (deg, rad) = (deg as f32, rad as f32); + assert!((FloatCore::to_degrees(rad) - deg).abs() < 1e-5); + assert!((FloatCore::to_radians(deg) - rad).abs() < 1e-5); + } + } + + #[cfg(feature = "std")] + #[test] + fn convert_deg_rad_std() { + for &(deg, rad) in &DEG_RAD_PAIRS { + use Float; + + assert!((Float::to_degrees(rad) - deg).abs() < 1e-6); + assert!((Float::to_radians(deg) - rad).abs() < 1e-6); + + let (deg, rad) = (deg as f32, rad as f32); + assert!((Float::to_degrees(rad) - deg).abs() < 1e-5); + assert!((Float::to_radians(deg) - rad).abs() < 1e-5); + } + } + + #[test] + // This fails with the forwarded `std` implementation in Rust 1.8. + // To avoid the failure, the test is limited to `no_std` builds. + #[cfg(not(feature = "std"))] + fn to_degrees_rounding() { + use float::FloatCore; + + assert_eq!( + FloatCore::to_degrees(1_f32), + 57.2957795130823208767981548141051703 + ); + } +} diff --git a/num-traits/src/identities.rs b/num-traits/src/identities.rs new file mode 100644 index 000000000..eadd01883 --- /dev/null +++ b/num-traits/src/identities.rs @@ -0,0 +1,207 @@ +use core::num::Wrapping; +use core::ops::{Add, Mul}; + +/// Defines an additive identity element for `Self`. +/// +/// # Laws +/// +/// ```{.text} +/// a + 0 = a ∀ a ∈ Self +/// 0 + a = a ∀ a ∈ Self +/// ``` +pub trait Zero: Sized + Add { + /// Returns the additive identity element of `Self`, `0`. + /// # Purity + /// + /// This function should return the same result at all times regardless of + /// external mutable state, for example values stored in TLS or in + /// `static mut`s. + // This cannot be an associated constant, because of bignums. + fn zero() -> Self; + + /// Sets `self` to the additive identity element of `Self`, `0`. + fn set_zero(&mut self) { + *self = Zero::zero(); + } + + /// Returns `true` if `self` is equal to the additive identity. + #[inline] + fn is_zero(&self) -> bool; +} + +macro_rules! zero_impl { + ($t:ty, $v:expr) => { + impl Zero for $t { + #[inline] + fn zero() -> $t { + $v + } + #[inline] + fn is_zero(&self) -> bool { + *self == $v + } + } + }; +} + +zero_impl!(usize, 0); +zero_impl!(u8, 0); +zero_impl!(u16, 0); +zero_impl!(u32, 0); +zero_impl!(u64, 0); +#[cfg(has_i128)] +zero_impl!(u128, 0); + +zero_impl!(isize, 0); +zero_impl!(i8, 0); +zero_impl!(i16, 0); +zero_impl!(i32, 0); +zero_impl!(i64, 0); +#[cfg(has_i128)] +zero_impl!(i128, 0); + +zero_impl!(f32, 0.0); +zero_impl!(f64, 0.0); + +impl Zero for Wrapping +where + Wrapping: Add>, +{ + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + fn set_zero(&mut self) { + self.0.set_zero(); + } + + fn zero() -> Self { + Wrapping(T::zero()) + } +} + +/// Defines a multiplicative identity element for `Self`. +/// +/// # Laws +/// +/// ```{.text} +/// a * 1 = a ∀ a ∈ Self +/// 1 * a = a ∀ a ∈ Self +/// ``` +pub trait One: Sized + Mul { + /// Returns the multiplicative identity element of `Self`, `1`. + /// + /// # Purity + /// + /// This function should return the same result at all times regardless of + /// external mutable state, for example values stored in TLS or in + /// `static mut`s. + // This cannot be an associated constant, because of bignums. + fn one() -> Self; + + /// Sets `self` to the multiplicative identity element of `Self`, `1`. + fn set_one(&mut self) { + *self = One::one(); + } + + /// Returns `true` if `self` is equal to the multiplicative identity. + /// + /// For performance reasons, it's best to implement this manually. + /// After a semver bump, this method will be required, and the + /// `where Self: PartialEq` bound will be removed. + #[inline] + fn is_one(&self) -> bool + where + Self: PartialEq, + { + *self == Self::one() + } +} + +macro_rules! one_impl { + ($t:ty, $v:expr) => { + impl One for $t { + #[inline] + fn one() -> $t { + $v + } + #[inline] + fn is_one(&self) -> bool { + *self == $v + } + } + }; +} + +one_impl!(usize, 1); +one_impl!(u8, 1); +one_impl!(u16, 1); +one_impl!(u32, 1); +one_impl!(u64, 1); +#[cfg(has_i128)] +one_impl!(u128, 1); + +one_impl!(isize, 1); +one_impl!(i8, 1); +one_impl!(i16, 1); +one_impl!(i32, 1); +one_impl!(i64, 1); +#[cfg(has_i128)] +one_impl!(i128, 1); + +one_impl!(f32, 1.0); +one_impl!(f64, 1.0); + +impl One for Wrapping +where + Wrapping: Mul>, +{ + fn set_one(&mut self) { + self.0.set_one(); + } + + fn one() -> Self { + Wrapping(T::one()) + } +} + +// Some helper functions provided for backwards compatibility. + +/// Returns the additive identity, `0`. +#[inline(always)] +pub fn zero() -> T { + Zero::zero() +} + +/// Returns the multiplicative identity, `1`. +#[inline(always)] +pub fn one() -> T { + One::one() +} + +#[test] +fn wrapping_identities() { + macro_rules! test_wrapping_identities { + ($($t:ty)+) => { + $( + assert_eq!(zero::<$t>(), zero::>().0); + assert_eq!(one::<$t>(), one::>().0); + assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero()); + assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero()); + )+ + }; + } + + test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64); +} + +#[test] +fn wrapping_is_zero() { + fn require_zero(_: &T) {} + require_zero(&Wrapping(42)); +} +#[test] +fn wrapping_is_one() { + fn require_one(_: &T) {} + require_one(&Wrapping(42)); +} diff --git a/num-traits/src/int.rs b/num-traits/src/int.rs new file mode 100644 index 000000000..26d5a9a39 --- /dev/null +++ b/num-traits/src/int.rs @@ -0,0 +1,409 @@ +use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; + +use bounds::Bounded; +use ops::checked::*; +use ops::saturating::Saturating; +use {Num, NumCast}; + +/// Generic trait for primitive integers. +/// +/// The `PrimInt` trait is an abstraction over the builtin primitive integer types (e.g., `u8`, +/// `u32`, `isize`, `i128`, ...). It inherits the basic numeric traits and extends them with +/// bitwise operators and non-wrapping arithmetic. +/// +/// The trait explicitly inherits `Copy`, `Eq`, `Ord`, and `Sized`. The intention is that all +/// types implementing this trait behave like primitive types that are passed by value by default +/// and behave like builtin integers. Furthermore, the types are expected to expose the integer +/// value in binary representation and support bitwise operators. The standard bitwise operations +/// (e.g., bitwise-and, bitwise-or, right-shift, left-shift) are inherited and the trait extends +/// these with introspective queries (e.g., `PrimInt::count_ones()`, `PrimInt::leading_zeros()`), +/// bitwise combinators (e.g., `PrimInt::rotate_left()`), and endianness converters (e.g., +/// `PrimInt::to_be()`). +/// +/// All `PrimInt` types are expected to be fixed-width binary integers. The width can be queried +/// via `T::zero().count_zeros()`. The trait currently lacks a way to query the width at +/// compile-time. +/// +/// While a default implementation for all builtin primitive integers is provided, the trait is in +/// no way restricted to these. Other integer types that fulfil the requirements are free to +/// implement the trait was well. +/// +/// This trait and many of the method names originate in the unstable `core::num::Int` trait from +/// the rust standard library. The original trait was never stabilized and thus removed from the +/// standard library. +pub trait PrimInt: + Sized + + Copy + + Num + + NumCast + + Bounded + + PartialOrd + + Ord + + Eq + + Not + + BitAnd + + BitOr + + BitXor + + Shl + + Shr + + CheckedAdd + + CheckedSub + + CheckedMul + + CheckedDiv + + Saturating +{ + /// Returns the number of ones in the binary representation of `self`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0b01001100u8; + /// + /// assert_eq!(n.count_ones(), 3); + /// ``` + fn count_ones(self) -> u32; + + /// Returns the number of zeros in the binary representation of `self`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0b01001100u8; + /// + /// assert_eq!(n.count_zeros(), 5); + /// ``` + fn count_zeros(self) -> u32; + + /// Returns the number of leading zeros in the binary representation + /// of `self`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0b0101000u16; + /// + /// assert_eq!(n.leading_zeros(), 10); + /// ``` + fn leading_zeros(self) -> u32; + + /// Returns the number of trailing zeros in the binary representation + /// of `self`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0b0101000u16; + /// + /// assert_eq!(n.trailing_zeros(), 3); + /// ``` + fn trailing_zeros(self) -> u32; + + /// Shifts the bits to the left by a specified amount amount, `n`, wrapping + /// the truncated bits to the end of the resulting integer. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0x3456789ABCDEF012u64; + /// + /// assert_eq!(n.rotate_left(12), m); + /// ``` + fn rotate_left(self, n: u32) -> Self; + + /// Shifts the bits to the right by a specified amount amount, `n`, wrapping + /// the truncated bits to the beginning of the resulting integer. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0xDEF0123456789ABCu64; + /// + /// assert_eq!(n.rotate_right(12), m); + /// ``` + fn rotate_right(self, n: u32) -> Self; + + /// Shifts the bits to the left by a specified amount amount, `n`, filling + /// zeros in the least significant bits. + /// + /// This is bitwise equivalent to signed `Shl`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0x3456789ABCDEF000u64; + /// + /// assert_eq!(n.signed_shl(12), m); + /// ``` + fn signed_shl(self, n: u32) -> Self; + + /// Shifts the bits to the right by a specified amount amount, `n`, copying + /// the "sign bit" in the most significant bits even for unsigned types. + /// + /// This is bitwise equivalent to signed `Shr`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0xFEDCBA9876543210u64; + /// let m = 0xFFFFEDCBA9876543u64; + /// + /// assert_eq!(n.signed_shr(12), m); + /// ``` + fn signed_shr(self, n: u32) -> Self; + + /// Shifts the bits to the left by a specified amount amount, `n`, filling + /// zeros in the least significant bits. + /// + /// This is bitwise equivalent to unsigned `Shl`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFi64; + /// let m = 0x3456789ABCDEF000i64; + /// + /// assert_eq!(n.unsigned_shl(12), m); + /// ``` + fn unsigned_shl(self, n: u32) -> Self; + + /// Shifts the bits to the right by a specified amount amount, `n`, filling + /// zeros in the most significant bits. + /// + /// This is bitwise equivalent to unsigned `Shr`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = -8i8; // 0b11111000 + /// let m = 62i8; // 0b00111110 + /// + /// assert_eq!(n.unsigned_shr(2), m); + /// ``` + fn unsigned_shr(self, n: u32) -> Self; + + /// Reverses the byte order of the integer. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// let m = 0xEFCDAB8967452301u64; + /// + /// assert_eq!(n.swap_bytes(), m); + /// ``` + fn swap_bytes(self) -> Self; + + /// Convert an integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(u64::from_be(n), n) + /// } else { + /// assert_eq!(u64::from_be(n), n.swap_bytes()) + /// } + /// ``` + fn from_be(x: Self) -> Self; + + /// Convert an integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(u64::from_le(n), n) + /// } else { + /// assert_eq!(u64::from_le(n), n.swap_bytes()) + /// } + /// ``` + fn from_le(x: Self) -> Self; + + /// Convert `self` to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are swapped. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n) + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()) + /// } + /// ``` + fn to_be(self) -> Self; + + /// Convert `self` to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are swapped. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// let n = 0x0123456789ABCDEFu64; + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n) + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()) + /// } + /// ``` + fn to_le(self) -> Self; + + /// Raises self to the power of `exp`, using exponentiation by squaring. + /// + /// # Examples + /// + /// ``` + /// use num_traits::PrimInt; + /// + /// assert_eq!(2i32.pow(4), 16); + /// ``` + fn pow(self, exp: u32) -> Self; +} + +macro_rules! prim_int_impl { + ($T:ty, $S:ty, $U:ty) => { + impl PrimInt for $T { + #[inline] + fn count_ones(self) -> u32 { + <$T>::count_ones(self) + } + + #[inline] + fn count_zeros(self) -> u32 { + <$T>::count_zeros(self) + } + + #[inline] + fn leading_zeros(self) -> u32 { + <$T>::leading_zeros(self) + } + + #[inline] + fn trailing_zeros(self) -> u32 { + <$T>::trailing_zeros(self) + } + + #[inline] + fn rotate_left(self, n: u32) -> Self { + <$T>::rotate_left(self, n) + } + + #[inline] + fn rotate_right(self, n: u32) -> Self { + <$T>::rotate_right(self, n) + } + + #[inline] + fn signed_shl(self, n: u32) -> Self { + ((self as $S) << n) as $T + } + + #[inline] + fn signed_shr(self, n: u32) -> Self { + ((self as $S) >> n) as $T + } + + #[inline] + fn unsigned_shl(self, n: u32) -> Self { + ((self as $U) << n) as $T + } + + #[inline] + fn unsigned_shr(self, n: u32) -> Self { + ((self as $U) >> n) as $T + } + + #[inline] + fn swap_bytes(self) -> Self { + <$T>::swap_bytes(self) + } + + #[inline] + fn from_be(x: Self) -> Self { + <$T>::from_be(x) + } + + #[inline] + fn from_le(x: Self) -> Self { + <$T>::from_le(x) + } + + #[inline] + fn to_be(self) -> Self { + <$T>::to_be(self) + } + + #[inline] + fn to_le(self) -> Self { + <$T>::to_le(self) + } + + #[inline] + fn pow(self, exp: u32) -> Self { + <$T>::pow(self, exp) + } + } + }; +} + +// prim_int_impl!(type, signed, unsigned); +prim_int_impl!(u8, i8, u8); +prim_int_impl!(u16, i16, u16); +prim_int_impl!(u32, i32, u32); +prim_int_impl!(u64, i64, u64); +#[cfg(has_i128)] +prim_int_impl!(u128, i128, u128); +prim_int_impl!(usize, isize, usize); +prim_int_impl!(i8, i8, u8); +prim_int_impl!(i16, i16, u16); +prim_int_impl!(i32, i32, u32); +prim_int_impl!(i64, i64, u64); +#[cfg(has_i128)] +prim_int_impl!(i128, i128, u128); +prim_int_impl!(isize, isize, usize); diff --git a/num-traits/src/lib.rs b/num-traits/src/lib.rs new file mode 100644 index 000000000..172e71466 --- /dev/null +++ b/num-traits/src/lib.rs @@ -0,0 +1,473 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Numeric traits for generic mathematics +//! +//! ## Compatibility +//! +//! The `num-traits` crate is tested for rustc 1.8 and greater. + +#![doc(html_root_url = "https://docs.rs/num-traits/0.2")] +#![deny(unconditional_recursion)] +#![no_std] +#[cfg(feature = "std")] +extern crate std; + +use core::fmt; +use core::num::Wrapping; +use core::ops::{Add, Div, Mul, Rem, Sub}; +use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; + +pub use bounds::Bounded; +#[cfg(feature = "std")] +pub use float::Float; +pub use float::FloatConst; +// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. +pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; +pub use identities::{one, zero, One, Zero}; +pub use int::PrimInt; +pub use ops::checked::{ + CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, +}; +pub use ops::inv::Inv; +pub use ops::mul_add::{MulAdd, MulAddAssign}; +pub use ops::saturating::Saturating; +pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub}; +pub use pow::{checked_pow, pow, Pow}; +pub use sign::{abs, abs_sub, signum, Signed, Unsigned}; + +#[macro_use] +mod macros; + +pub mod bounds; +pub mod cast; +pub mod float; +pub mod identities; +pub mod int; +pub mod ops; +pub mod pow; +#[cfg(feature = "std")] +pub mod real; +pub mod sign; + +/// The base trait for numeric types, covering `0` and `1` values, +/// comparisons, basic numeric operations, and string conversion. +pub trait Num: PartialEq + Zero + One + NumOps { + type FromStrRadixErr; + + /// Convert from a string and radix <= 36. + /// + /// # Examples + /// + /// ```rust + /// use num_traits::Num; + /// + /// let result = ::from_str_radix("27", 10); + /// assert_eq!(result, Ok(27)); + /// + /// let result = ::from_str_radix("foo", 10); + /// assert!(result.is_err()); + /// ``` + fn from_str_radix(str: &str, radix: u32) -> Result; +} + +/// The trait for types implementing basic numeric operations +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumOps: + Add + + Sub + + Mul + + Div + + Rem +{ +} + +impl NumOps for T where + T: Add + + Sub + + Mul + + Div + + Rem +{ +} + +/// The trait for `Num` types which also implement numeric operations taking +/// the second operand by reference. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumRef: Num + for<'r> NumOps<&'r Self> {} +impl NumRef for T where T: Num + for<'r> NumOps<&'r T> {} + +/// The trait for references which implement numeric operations, taking the +/// second operand either by value or by reference. +/// +/// This is automatically implemented for types which implement the operators. +pub trait RefNum: NumOps + for<'r> NumOps<&'r Base, Base> {} +impl RefNum for T where T: NumOps + for<'r> NumOps<&'r Base, Base> {} + +/// The trait for types implementing numeric assignment operators (like `+=`). +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssignOps: + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign +{ +} + +impl NumAssignOps for T where + T: AddAssign + SubAssign + MulAssign + DivAssign + RemAssign +{ +} + +/// The trait for `Num` types which also implement assignment operators. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssign: Num + NumAssignOps {} +impl NumAssign for T where T: Num + NumAssignOps {} + +/// The trait for `NumAssign` types which also implement assignment operations +/// taking the second operand by reference. +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {} +impl NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {} + +macro_rules! int_trait_impl { + ($name:ident for $($t:ty)*) => ($( + impl $name for $t { + type FromStrRadixErr = ::core::num::ParseIntError; + #[inline] + fn from_str_radix(s: &str, radix: u32) + -> Result + { + <$t>::from_str_radix(s, radix) + } + } + )*) +} +int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64); +#[cfg(has_i128)] +int_trait_impl!(Num for u128 i128); + +impl Num for Wrapping +where + Wrapping: Add> + + Sub> + + Mul> + + Div> + + Rem>, +{ + type FromStrRadixErr = T::FromStrRadixErr; + fn from_str_radix(str: &str, radix: u32) -> Result { + T::from_str_radix(str, radix).map(Wrapping) + } +} + +#[derive(Debug)] +pub enum FloatErrorKind { + Empty, + Invalid, +} +// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us, +// so there's not really any way for us to reuse it. +#[derive(Debug)] +pub struct ParseFloatError { + pub kind: FloatErrorKind, +} + +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let description = match self.kind { + FloatErrorKind::Empty => "cannot parse float from empty string", + FloatErrorKind::Invalid => "invalid float literal", + }; + + description.fmt(f) + } +} + +// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck +// with this implementation ourselves until we want to make a breaking change. +// (would have to drop it from `Num` though) +macro_rules! float_trait_impl { + ($name:ident for $($t:ident)*) => ($( + impl $name for $t { + type FromStrRadixErr = ParseFloatError; + + fn from_str_radix(src: &str, radix: u32) + -> Result + { + use self::FloatErrorKind::*; + use self::ParseFloatError as PFE; + + // Special values + match src { + "inf" => return Ok(core::$t::INFINITY), + "-inf" => return Ok(core::$t::NEG_INFINITY), + "NaN" => return Ok(core::$t::NAN), + _ => {}, + } + + fn slice_shift_char(src: &str) -> Option<(char, &str)> { + src.chars().nth(0).map(|ch| (ch, &src[1..])) + } + + let (is_positive, src) = match slice_shift_char(src) { + None => return Err(PFE { kind: Empty }), + Some(('-', "")) => return Err(PFE { kind: Empty }), + Some(('-', src)) => (false, src), + Some((_, _)) => (true, src), + }; + + // The significand to accumulate + let mut sig = if is_positive { 0.0 } else { -0.0 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, usize)>; + + // Parse the integer part of the significand + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // shift significand one digit left + sig = sig * (radix as $t); + + // add/subtract current digit depending on sign + if is_positive { + sig = sig + ((digit as isize) as $t); + } else { + sig = sig - ((digit as isize) as $t); + } + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if prev_sig != 0.0 { + if is_positive && sig <= prev_sig + { return Ok(core::$t::INFINITY); } + if !is_positive && sig >= prev_sig + { return Ok(core::$t::NEG_INFINITY); } + + // Detect overflow by reversing the shift-and-add process + if is_positive && (prev_sig != (sig - digit as $t) / radix as $t) + { return Ok(core::$t::INFINITY); } + if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t) + { return Ok(core::$t::NEG_INFINITY); } + } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = 1.0; + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // Decrease power one order of magnitude + power = power / (radix as $t); + // add/subtract current digit depending on sign + sig = if is_positive { + sig + (digit as $t) * power + } else { + sig - (digit as $t) * power + }; + // Detect overflow by comparing to last value + if is_positive && sig < prev_sig + { return Ok(core::$t::INFINITY); } + if !is_positive && sig > prev_sig + { return Ok(core::$t::NEG_INFINITY); } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + } + + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base = match c { + 'E' | 'e' if radix == 10 => 10.0, + 'P' | 'p' if radix == 16 => 2.0, + _ => return Err(PFE { kind: Invalid }), + }; + + // Parse the exponent as decimal integer + let src = &src[offset..]; + let (is_positive, exp) = match slice_shift_char(src) { + Some(('-', src)) => (false, src.parse::()), + Some(('+', src)) => (true, src.parse::()), + Some((_, _)) => (true, src.parse::()), + None => return Err(PFE { kind: Invalid }), + }; + + #[cfg(feature = "std")] + fn pow(base: $t, exp: usize) -> $t { + Float::powi(base, exp as i32) + } + // otherwise uses the generic `pow` from the root + + match (is_positive, exp) { + (true, Ok(exp)) => pow(base, exp), + (false, Ok(exp)) => 1.0 / pow(base, exp), + (_, Err(_)) => return Err(PFE { kind: Invalid }), + } + }, + None => 1.0, // no exponent + }; + + Ok(sig * exp) + } + } + )*) +} +float_trait_impl!(Num for f32 f64); + +/// A value bounded by a minimum and a maximum +/// +/// If input is less than min then this returns min. +/// If input is greater than max then this returns max. +/// Otherwise this returns input. +#[inline] +pub fn clamp(input: T, min: T, max: T) -> T { + debug_assert!(min <= max, "min must be less than or equal to max"); + if input < min { + min + } else if input > max { + max + } else { + input + } +} + +#[test] +fn clamp_test() { + // Int test + assert_eq!(1, clamp(1, -1, 2)); + assert_eq!(-1, clamp(-2, -1, 2)); + assert_eq!(2, clamp(3, -1, 2)); + + // Float test + assert_eq!(1.0, clamp(1.0, -1.0, 2.0)); + assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0)); + assert_eq!(2.0, clamp(3.0, -1.0, 2.0)); +} + +#[test] +fn from_str_radix_unwrap() { + // The Result error must impl Debug to allow unwrap() + + let i: i32 = Num::from_str_radix("0", 10).unwrap(); + assert_eq!(i, 0); + + let f: f32 = Num::from_str_radix("0.0", 10).unwrap(); + assert_eq!(f, 0.0); +} + +#[test] +fn wrapping_is_num() { + fn require_num(_: &T) {} + require_num(&Wrapping(42_u32)); + require_num(&Wrapping(-42)); +} + +#[test] +fn wrapping_from_str_radix() { + macro_rules! test_wrapping_from_str_radix { + ($($t:ty)+) => { + $( + for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] { + let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0); + assert_eq!(w, <$t as Num>::from_str_radix(s, r)); + } + )+ + }; + } + + test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[test] +fn check_num_ops() { + fn compute(x: T, y: T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, 2), 1) +} + +#[test] +fn check_numref_ops() { + fn compute(x: T, y: &T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, &2), 1) +} + +#[test] +fn check_refnum_ops() { + fn compute(x: &T, y: T) -> T + where + for<'a> &'a T: RefNum, + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, 2), 1) +} + +#[test] +fn check_refref_ops() { + fn compute(x: &T, y: &T) -> T + where + for<'a> &'a T: RefNum, + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, &2), 1) +} + +#[test] +fn check_numassign_ops() { + fn compute(mut x: T, y: T) -> T { + x *= y; + x /= y; + x %= y; + x += y; + x -= y; + x + } + assert_eq!(compute(1, 2), 1) +} + +// TODO test `NumAssignRef`, but even the standard numeric types don't +// implement this yet. (see rust pr41336) diff --git a/num-traits/src/macros.rs b/num-traits/src/macros.rs new file mode 100644 index 000000000..4330cdfd8 --- /dev/null +++ b/num-traits/src/macros.rs @@ -0,0 +1,37 @@ +// not all are used in all features configurations +#![allow(unused)] + +/// Forward a method to an inherent method or a base trait method. +macro_rules! forward { + ($( Self :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) + => {$( + #[inline] + fn $method(self $( , $arg : $ty )* ) -> $ret { + Self::$method(self $( , $arg )* ) + } + )*}; + ($( $base:ident :: $method:ident ( self $( , $arg:ident : $ty:ty )* ) -> $ret:ty ; )*) + => {$( + #[inline] + fn $method(self $( , $arg : $ty )* ) -> $ret { + ::$method(self $( , $arg )* ) + } + )*}; + ($( $base:ident :: $method:ident ( $( $arg:ident : $ty:ty ),* ) -> $ret:ty ; )*) + => {$( + #[inline] + fn $method( $( $arg : $ty ),* ) -> $ret { + ::$method( $( $arg ),* ) + } + )*} +} + +macro_rules! constant { + ($( $method:ident () -> $ret:expr ; )*) + => {$( + #[inline] + fn $method() -> Self { + $ret + } + )*}; +} diff --git a/num-traits/src/ops/checked.rs b/num-traits/src/ops/checked.rs new file mode 100644 index 000000000..386557003 --- /dev/null +++ b/num-traits/src/ops/checked.rs @@ -0,0 +1,277 @@ +use core::ops::{Add, Div, Mul, Rem, Shl, Shr, Sub}; + +/// Performs addition that returns `None` instead of wrapping around on +/// overflow. +pub trait CheckedAdd: Sized + Add { + /// Adds two numbers, checking for overflow. If overflow happens, `None` is + /// returned. + fn checked_add(&self, v: &Self) -> Option; +} + +macro_rules! checked_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, v: &$t) -> Option<$t> { + <$t>::$method(*self, *v) + } + } + }; +} + +checked_impl!(CheckedAdd, checked_add, u8); +checked_impl!(CheckedAdd, checked_add, u16); +checked_impl!(CheckedAdd, checked_add, u32); +checked_impl!(CheckedAdd, checked_add, u64); +checked_impl!(CheckedAdd, checked_add, usize); +#[cfg(has_i128)] +checked_impl!(CheckedAdd, checked_add, u128); + +checked_impl!(CheckedAdd, checked_add, i8); +checked_impl!(CheckedAdd, checked_add, i16); +checked_impl!(CheckedAdd, checked_add, i32); +checked_impl!(CheckedAdd, checked_add, i64); +checked_impl!(CheckedAdd, checked_add, isize); +#[cfg(has_i128)] +checked_impl!(CheckedAdd, checked_add, i128); + +/// Performs subtraction that returns `None` instead of wrapping around on underflow. +pub trait CheckedSub: Sized + Sub { + /// Subtracts two numbers, checking for underflow. If underflow happens, + /// `None` is returned. + fn checked_sub(&self, v: &Self) -> Option; +} + +checked_impl!(CheckedSub, checked_sub, u8); +checked_impl!(CheckedSub, checked_sub, u16); +checked_impl!(CheckedSub, checked_sub, u32); +checked_impl!(CheckedSub, checked_sub, u64); +checked_impl!(CheckedSub, checked_sub, usize); +#[cfg(has_i128)] +checked_impl!(CheckedSub, checked_sub, u128); + +checked_impl!(CheckedSub, checked_sub, i8); +checked_impl!(CheckedSub, checked_sub, i16); +checked_impl!(CheckedSub, checked_sub, i32); +checked_impl!(CheckedSub, checked_sub, i64); +checked_impl!(CheckedSub, checked_sub, isize); +#[cfg(has_i128)] +checked_impl!(CheckedSub, checked_sub, i128); + +/// Performs multiplication that returns `None` instead of wrapping around on underflow or +/// overflow. +pub trait CheckedMul: Sized + Mul { + /// Multiplies two numbers, checking for underflow or overflow. If underflow + /// or overflow happens, `None` is returned. + fn checked_mul(&self, v: &Self) -> Option; +} + +checked_impl!(CheckedMul, checked_mul, u8); +checked_impl!(CheckedMul, checked_mul, u16); +checked_impl!(CheckedMul, checked_mul, u32); +checked_impl!(CheckedMul, checked_mul, u64); +checked_impl!(CheckedMul, checked_mul, usize); +#[cfg(has_i128)] +checked_impl!(CheckedMul, checked_mul, u128); + +checked_impl!(CheckedMul, checked_mul, i8); +checked_impl!(CheckedMul, checked_mul, i16); +checked_impl!(CheckedMul, checked_mul, i32); +checked_impl!(CheckedMul, checked_mul, i64); +checked_impl!(CheckedMul, checked_mul, isize); +#[cfg(has_i128)] +checked_impl!(CheckedMul, checked_mul, i128); + +/// Performs division that returns `None` instead of panicking on division by zero and instead of +/// wrapping around on underflow and overflow. +pub trait CheckedDiv: Sized + Div { + /// Divides two numbers, checking for underflow, overflow and division by + /// zero. If any of that happens, `None` is returned. + fn checked_div(&self, v: &Self) -> Option; +} + +checked_impl!(CheckedDiv, checked_div, u8); +checked_impl!(CheckedDiv, checked_div, u16); +checked_impl!(CheckedDiv, checked_div, u32); +checked_impl!(CheckedDiv, checked_div, u64); +checked_impl!(CheckedDiv, checked_div, usize); +#[cfg(has_i128)] +checked_impl!(CheckedDiv, checked_div, u128); + +checked_impl!(CheckedDiv, checked_div, i8); +checked_impl!(CheckedDiv, checked_div, i16); +checked_impl!(CheckedDiv, checked_div, i32); +checked_impl!(CheckedDiv, checked_div, i64); +checked_impl!(CheckedDiv, checked_div, isize); +#[cfg(has_i128)] +checked_impl!(CheckedDiv, checked_div, i128); + +/// Performs an integral remainder that returns `None` instead of panicking on division by zero and +/// instead of wrapping around on underflow and overflow. +pub trait CheckedRem: Sized + Rem { + /// Finds the remainder of dividing two numbers, checking for underflow, overflow and division + /// by zero. If any of that happens, `None` is returned. + /// + /// # Examples + /// + /// ``` + /// use num_traits::CheckedRem; + /// use std::i32::MIN; + /// + /// assert_eq!(CheckedRem::checked_rem(&10, &7), Some(3)); + /// assert_eq!(CheckedRem::checked_rem(&10, &-7), Some(3)); + /// assert_eq!(CheckedRem::checked_rem(&-10, &7), Some(-3)); + /// assert_eq!(CheckedRem::checked_rem(&-10, &-7), Some(-3)); + /// + /// assert_eq!(CheckedRem::checked_rem(&10, &0), None); + /// + /// assert_eq!(CheckedRem::checked_rem(&MIN, &1), Some(0)); + /// assert_eq!(CheckedRem::checked_rem(&MIN, &-1), None); + /// ``` + fn checked_rem(&self, v: &Self) -> Option; +} + +checked_impl!(CheckedRem, checked_rem, u8); +checked_impl!(CheckedRem, checked_rem, u16); +checked_impl!(CheckedRem, checked_rem, u32); +checked_impl!(CheckedRem, checked_rem, u64); +checked_impl!(CheckedRem, checked_rem, usize); +#[cfg(has_i128)] +checked_impl!(CheckedRem, checked_rem, u128); + +checked_impl!(CheckedRem, checked_rem, i8); +checked_impl!(CheckedRem, checked_rem, i16); +checked_impl!(CheckedRem, checked_rem, i32); +checked_impl!(CheckedRem, checked_rem, i64); +checked_impl!(CheckedRem, checked_rem, isize); +#[cfg(has_i128)] +checked_impl!(CheckedRem, checked_rem, i128); + +macro_rules! checked_impl_unary { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self) -> Option<$t> { + <$t>::$method(*self) + } + } + }; +} + +/// Performs negation that returns `None` if the result can't be represented. +pub trait CheckedNeg: Sized { + /// Negates a number, returning `None` for results that can't be represented, like signed `MIN` + /// values that can't be positive, or non-zero unsigned values that can't be negative. + /// + /// # Examples + /// + /// ``` + /// use num_traits::CheckedNeg; + /// use std::i32::MIN; + /// + /// assert_eq!(CheckedNeg::checked_neg(&1_i32), Some(-1)); + /// assert_eq!(CheckedNeg::checked_neg(&-1_i32), Some(1)); + /// assert_eq!(CheckedNeg::checked_neg(&MIN), None); + /// + /// assert_eq!(CheckedNeg::checked_neg(&0_u32), Some(0)); + /// assert_eq!(CheckedNeg::checked_neg(&1_u32), None); + /// ``` + fn checked_neg(&self) -> Option; +} + +checked_impl_unary!(CheckedNeg, checked_neg, u8); +checked_impl_unary!(CheckedNeg, checked_neg, u16); +checked_impl_unary!(CheckedNeg, checked_neg, u32); +checked_impl_unary!(CheckedNeg, checked_neg, u64); +checked_impl_unary!(CheckedNeg, checked_neg, usize); +#[cfg(has_i128)] +checked_impl_unary!(CheckedNeg, checked_neg, u128); + +checked_impl_unary!(CheckedNeg, checked_neg, i8); +checked_impl_unary!(CheckedNeg, checked_neg, i16); +checked_impl_unary!(CheckedNeg, checked_neg, i32); +checked_impl_unary!(CheckedNeg, checked_neg, i64); +checked_impl_unary!(CheckedNeg, checked_neg, isize); +#[cfg(has_i128)] +checked_impl_unary!(CheckedNeg, checked_neg, i128); + +/// Performs a left shift that returns `None` on shifts larger than +/// the type width. +pub trait CheckedShl: Sized + Shl { + /// Checked shift left. Computes `self << rhs`, returning `None` + /// if `rhs` is larger than or equal to the number of bits in `self`. + /// + /// ``` + /// use num_traits::CheckedShl; + /// + /// let x: u16 = 0x0001; + /// + /// assert_eq!(CheckedShl::checked_shl(&x, 0), Some(0x0001)); + /// assert_eq!(CheckedShl::checked_shl(&x, 1), Some(0x0002)); + /// assert_eq!(CheckedShl::checked_shl(&x, 15), Some(0x8000)); + /// assert_eq!(CheckedShl::checked_shl(&x, 16), None); + /// ``` + fn checked_shl(&self, rhs: u32) -> Option; +} + +macro_rules! checked_shift_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, rhs: u32) -> Option<$t> { + <$t>::$method(*self, rhs) + } + } + }; +} + +checked_shift_impl!(CheckedShl, checked_shl, u8); +checked_shift_impl!(CheckedShl, checked_shl, u16); +checked_shift_impl!(CheckedShl, checked_shl, u32); +checked_shift_impl!(CheckedShl, checked_shl, u64); +checked_shift_impl!(CheckedShl, checked_shl, usize); +#[cfg(has_i128)] +checked_shift_impl!(CheckedShl, checked_shl, u128); + +checked_shift_impl!(CheckedShl, checked_shl, i8); +checked_shift_impl!(CheckedShl, checked_shl, i16); +checked_shift_impl!(CheckedShl, checked_shl, i32); +checked_shift_impl!(CheckedShl, checked_shl, i64); +checked_shift_impl!(CheckedShl, checked_shl, isize); +#[cfg(has_i128)] +checked_shift_impl!(CheckedShl, checked_shl, i128); + +/// Performs a right shift that returns `None` on shifts larger than +/// the type width. +pub trait CheckedShr: Sized + Shr { + /// Checked shift right. Computes `self >> rhs`, returning `None` + /// if `rhs` is larger than or equal to the number of bits in `self`. + /// + /// ``` + /// use num_traits::CheckedShr; + /// + /// let x: u16 = 0x8000; + /// + /// assert_eq!(CheckedShr::checked_shr(&x, 0), Some(0x8000)); + /// assert_eq!(CheckedShr::checked_shr(&x, 1), Some(0x4000)); + /// assert_eq!(CheckedShr::checked_shr(&x, 15), Some(0x0001)); + /// assert_eq!(CheckedShr::checked_shr(&x, 16), None); + /// ``` + fn checked_shr(&self, rhs: u32) -> Option; +} + +checked_shift_impl!(CheckedShr, checked_shr, u8); +checked_shift_impl!(CheckedShr, checked_shr, u16); +checked_shift_impl!(CheckedShr, checked_shr, u32); +checked_shift_impl!(CheckedShr, checked_shr, u64); +checked_shift_impl!(CheckedShr, checked_shr, usize); +#[cfg(has_i128)] +checked_shift_impl!(CheckedShr, checked_shr, u128); + +checked_shift_impl!(CheckedShr, checked_shr, i8); +checked_shift_impl!(CheckedShr, checked_shr, i16); +checked_shift_impl!(CheckedShr, checked_shr, i32); +checked_shift_impl!(CheckedShr, checked_shr, i64); +checked_shift_impl!(CheckedShr, checked_shr, isize); +#[cfg(has_i128)] +checked_shift_impl!(CheckedShr, checked_shr, i128); diff --git a/num-traits/src/ops/inv.rs b/num-traits/src/ops/inv.rs new file mode 100644 index 000000000..7087d09d0 --- /dev/null +++ b/num-traits/src/ops/inv.rs @@ -0,0 +1,47 @@ +/// Unary operator for retrieving the multiplicative inverse, or reciprocal, of a value. +pub trait Inv { + /// The result after applying the operator. + type Output; + + /// Returns the multiplicative inverse of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::f64::INFINITY; + /// use num_traits::Inv; + /// + /// assert_eq!(7.0.inv() * 7.0, 1.0); + /// assert_eq!((-0.0).inv(), -INFINITY); + /// ``` + fn inv(self) -> Self::Output; +} + +impl Inv for f32 { + type Output = f32; + #[inline] + fn inv(self) -> f32 { + 1.0 / self + } +} +impl Inv for f64 { + type Output = f64; + #[inline] + fn inv(self) -> f64 { + 1.0 / self + } +} +impl<'a> Inv for &'a f32 { + type Output = f32; + #[inline] + fn inv(self) -> f32 { + 1.0 / *self + } +} +impl<'a> Inv for &'a f64 { + type Output = f64; + #[inline] + fn inv(self) -> f64 { + 1.0 / *self + } +} diff --git a/num-traits/src/ops/mod.rs b/num-traits/src/ops/mod.rs new file mode 100644 index 000000000..fd1695d99 --- /dev/null +++ b/num-traits/src/ops/mod.rs @@ -0,0 +1,5 @@ +pub mod checked; +pub mod inv; +pub mod mul_add; +pub mod saturating; +pub mod wrapping; diff --git a/num-traits/src/ops/mul_add.rs b/num-traits/src/ops/mul_add.rs new file mode 100644 index 000000000..6e43f2f29 --- /dev/null +++ b/num-traits/src/ops/mul_add.rs @@ -0,0 +1,151 @@ +/// Fused multiply-add. Computes `(self * a) + b` with only one rounding +/// error, yielding a more accurate result than an unfused multiply-add. +/// +/// Using `mul_add` can be more performant than an unfused multiply-add if +/// the target architecture has a dedicated `fma` CPU instruction. +/// +/// Note that `A` and `B` are `Self` by default, but this is not mandatory. +/// +/// # Example +/// +/// ``` +/// use std::f32; +/// +/// let m = 10.0_f32; +/// let x = 4.0_f32; +/// let b = 60.0_f32; +/// +/// // 100.0 +/// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); +/// +/// assert!(abs_difference <= f32::EPSILON); +/// ``` +pub trait MulAdd { + /// The resulting type after applying the fused multiply-add. + type Output; + + /// Performs the fused multiply-add operation. + fn mul_add(self, a: A, b: B) -> Self::Output; +} + +/// The fused multiply-add assignment operation. +pub trait MulAddAssign { + /// Performs the fused multiply-add operation. + fn mul_add_assign(&mut self, a: A, b: B); +} + +#[cfg(feature = "std")] +impl MulAdd for f32 { + type Output = Self; + + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self::Output { + f32::mul_add(self, a, b) + } +} + +#[cfg(feature = "std")] +impl MulAdd for f64 { + type Output = Self; + + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self::Output { + f64::mul_add(self, a, b) + } +} + +macro_rules! mul_add_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + type Output = Self; + + #[inline] + fn mul_add(self, a: Self, b: Self) -> Self::Output { + (self * a) + b + } + } + )*} +} + +mul_add_impl!(MulAdd for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +#[cfg(has_i128)] +mul_add_impl!(MulAdd for i128 u128); + +#[cfg(feature = "std")] +impl MulAddAssign for f32 { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = f32::mul_add(*self, a, b) + } +} + +#[cfg(feature = "std")] +impl MulAddAssign for f64 { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = f64::mul_add(*self, a, b) + } +} + +macro_rules! mul_add_assign_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn mul_add_assign(&mut self, a: Self, b: Self) { + *self = (*self * a) + b + } + } + )*} +} + +mul_add_assign_impl!(MulAddAssign for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +#[cfg(has_i128)] +mul_add_assign_impl!(MulAddAssign for i128 u128); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn mul_add_integer() { + macro_rules! test_mul_add { + ($($t:ident)+) => { + $( + { + let m: $t = 2; + let x: $t = 3; + let b: $t = 4; + + assert_eq!(MulAdd::mul_add(m, x, b), (m*x + b)); + } + )+ + }; + } + + test_mul_add!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); + } + + #[test] + #[cfg(feature = "std")] + fn mul_add_float() { + macro_rules! test_mul_add { + ($($t:ident)+) => { + $( + { + use core::$t; + + let m: $t = 12.0; + let x: $t = 3.4; + let b: $t = 5.6; + + let abs_difference = (MulAdd::mul_add(m, x, b) - (m*x + b)).abs(); + + assert!(abs_difference <= $t::EPSILON); + } + )+ + }; + } + + test_mul_add!(f32 f64); + } +} diff --git a/num-traits/src/ops/saturating.rs b/num-traits/src/ops/saturating.rs new file mode 100644 index 000000000..fdce18977 --- /dev/null +++ b/num-traits/src/ops/saturating.rs @@ -0,0 +1,30 @@ +/// Saturating math operations +pub trait Saturating { + /// Saturating addition operator. + /// Returns a+b, saturating at the numeric bounds instead of overflowing. + fn saturating_add(self, v: Self) -> Self; + + /// Saturating subtraction operator. + /// Returns a-b, saturating at the numeric bounds instead of overflowing. + fn saturating_sub(self, v: Self) -> Self; +} + +macro_rules! saturating_impl { + ($trait_name:ident for $($t:ty)*) => {$( + impl $trait_name for $t { + #[inline] + fn saturating_add(self, v: Self) -> Self { + Self::saturating_add(self, v) + } + + #[inline] + fn saturating_sub(self, v: Self) -> Self { + Self::saturating_sub(self, v) + } + } + )*} +} + +saturating_impl!(Saturating for isize usize i8 u8 i16 u16 i32 u32 i64 u64); +#[cfg(has_i128)] +saturating_impl!(Saturating for i128 u128); diff --git a/num-traits/src/ops/wrapping.rs b/num-traits/src/ops/wrapping.rs new file mode 100644 index 000000000..5ce16af53 --- /dev/null +++ b/num-traits/src/ops/wrapping.rs @@ -0,0 +1,272 @@ +use core::num::Wrapping; +use core::ops::{Add, Mul, Shl, Shr, Sub}; + +macro_rules! wrapping_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, v: &Self) -> Self { + <$t>::$method(*self, *v) + } + } + }; + ($trait_name:ident, $method:ident, $t:ty, $rhs:ty) => { + impl $trait_name<$rhs> for $t { + #[inline] + fn $method(&self, v: &$rhs) -> Self { + <$t>::$method(*self, *v) + } + } + }; +} + +/// Performs addition that wraps around on overflow. +pub trait WrappingAdd: Sized + Add { + /// Wrapping (modular) addition. Computes `self + other`, wrapping around at the boundary of + /// the type. + fn wrapping_add(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingAdd, wrapping_add, u8); +wrapping_impl!(WrappingAdd, wrapping_add, u16); +wrapping_impl!(WrappingAdd, wrapping_add, u32); +wrapping_impl!(WrappingAdd, wrapping_add, u64); +wrapping_impl!(WrappingAdd, wrapping_add, usize); +#[cfg(has_i128)] +wrapping_impl!(WrappingAdd, wrapping_add, u128); + +wrapping_impl!(WrappingAdd, wrapping_add, i8); +wrapping_impl!(WrappingAdd, wrapping_add, i16); +wrapping_impl!(WrappingAdd, wrapping_add, i32); +wrapping_impl!(WrappingAdd, wrapping_add, i64); +wrapping_impl!(WrappingAdd, wrapping_add, isize); +#[cfg(has_i128)] +wrapping_impl!(WrappingAdd, wrapping_add, i128); + +/// Performs subtraction that wraps around on overflow. +pub trait WrappingSub: Sized + Sub { + /// Wrapping (modular) subtraction. Computes `self - other`, wrapping around at the boundary + /// of the type. + fn wrapping_sub(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingSub, wrapping_sub, u8); +wrapping_impl!(WrappingSub, wrapping_sub, u16); +wrapping_impl!(WrappingSub, wrapping_sub, u32); +wrapping_impl!(WrappingSub, wrapping_sub, u64); +wrapping_impl!(WrappingSub, wrapping_sub, usize); +#[cfg(has_i128)] +wrapping_impl!(WrappingSub, wrapping_sub, u128); + +wrapping_impl!(WrappingSub, wrapping_sub, i8); +wrapping_impl!(WrappingSub, wrapping_sub, i16); +wrapping_impl!(WrappingSub, wrapping_sub, i32); +wrapping_impl!(WrappingSub, wrapping_sub, i64); +wrapping_impl!(WrappingSub, wrapping_sub, isize); +#[cfg(has_i128)] +wrapping_impl!(WrappingSub, wrapping_sub, i128); + +/// Performs multiplication that wraps around on overflow. +pub trait WrappingMul: Sized + Mul { + /// Wrapping (modular) multiplication. Computes `self * other`, wrapping around at the boundary + /// of the type. + fn wrapping_mul(&self, v: &Self) -> Self; +} + +wrapping_impl!(WrappingMul, wrapping_mul, u8); +wrapping_impl!(WrappingMul, wrapping_mul, u16); +wrapping_impl!(WrappingMul, wrapping_mul, u32); +wrapping_impl!(WrappingMul, wrapping_mul, u64); +wrapping_impl!(WrappingMul, wrapping_mul, usize); +#[cfg(has_i128)] +wrapping_impl!(WrappingMul, wrapping_mul, u128); + +wrapping_impl!(WrappingMul, wrapping_mul, i8); +wrapping_impl!(WrappingMul, wrapping_mul, i16); +wrapping_impl!(WrappingMul, wrapping_mul, i32); +wrapping_impl!(WrappingMul, wrapping_mul, i64); +wrapping_impl!(WrappingMul, wrapping_mul, isize); +#[cfg(has_i128)] +wrapping_impl!(WrappingMul, wrapping_mul, i128); + +macro_rules! wrapping_shift_impl { + ($trait_name:ident, $method:ident, $t:ty) => { + impl $trait_name for $t { + #[inline] + fn $method(&self, rhs: u32) -> $t { + <$t>::$method(*self, rhs) + } + } + }; +} + +/// Performs a left shift that does not panic. +pub trait WrappingShl: Sized + Shl { + /// Panic-free bitwise shift-left; yields `self << mask(rhs)`, + /// where `mask` removes any high order bits of `rhs` that would + /// cause the shift to exceed the bitwidth of the type. + /// + /// ``` + /// use num_traits::WrappingShl; + /// + /// let x: u16 = 0x0001; + /// + /// assert_eq!(WrappingShl::wrapping_shl(&x, 0), 0x0001); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 1), 0x0002); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 15), 0x8000); + /// assert_eq!(WrappingShl::wrapping_shl(&x, 16), 0x0001); + /// ``` + fn wrapping_shl(&self, rhs: u32) -> Self; +} + +wrapping_shift_impl!(WrappingShl, wrapping_shl, u8); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u16); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u32); +wrapping_shift_impl!(WrappingShl, wrapping_shl, u64); +wrapping_shift_impl!(WrappingShl, wrapping_shl, usize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShl, wrapping_shl, u128); + +wrapping_shift_impl!(WrappingShl, wrapping_shl, i8); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i16); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i32); +wrapping_shift_impl!(WrappingShl, wrapping_shl, i64); +wrapping_shift_impl!(WrappingShl, wrapping_shl, isize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShl, wrapping_shl, i128); + +/// Performs a right shift that does not panic. +pub trait WrappingShr: Sized + Shr { + /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, + /// where `mask` removes any high order bits of `rhs` that would + /// cause the shift to exceed the bitwidth of the type. + /// + /// ``` + /// use num_traits::WrappingShr; + /// + /// let x: u16 = 0x8000; + /// + /// assert_eq!(WrappingShr::wrapping_shr(&x, 0), 0x8000); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 1), 0x4000); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 15), 0x0001); + /// assert_eq!(WrappingShr::wrapping_shr(&x, 16), 0x8000); + /// ``` + fn wrapping_shr(&self, rhs: u32) -> Self; +} + +wrapping_shift_impl!(WrappingShr, wrapping_shr, u8); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u16); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u32); +wrapping_shift_impl!(WrappingShr, wrapping_shr, u64); +wrapping_shift_impl!(WrappingShr, wrapping_shr, usize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShr, wrapping_shr, u128); + +wrapping_shift_impl!(WrappingShr, wrapping_shr, i8); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i16); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i32); +wrapping_shift_impl!(WrappingShr, wrapping_shr, i64); +wrapping_shift_impl!(WrappingShr, wrapping_shr, isize); +#[cfg(has_i128)] +wrapping_shift_impl!(WrappingShr, wrapping_shr, i128); + +// Well this is a bit funny, but all the more appropriate. +impl WrappingAdd for Wrapping +where + Wrapping: Add>, +{ + fn wrapping_add(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_add(&v.0)) + } +} +impl WrappingSub for Wrapping +where + Wrapping: Sub>, +{ + fn wrapping_sub(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_sub(&v.0)) + } +} +impl WrappingMul for Wrapping +where + Wrapping: Mul>, +{ + fn wrapping_mul(&self, v: &Self) -> Self { + Wrapping(self.0.wrapping_mul(&v.0)) + } +} +impl WrappingShl for Wrapping +where + Wrapping: Shl>, +{ + fn wrapping_shl(&self, rhs: u32) -> Self { + Wrapping(self.0.wrapping_shl(rhs)) + } +} +impl WrappingShr for Wrapping +where + Wrapping: Shr>, +{ + fn wrapping_shr(&self, rhs: u32) -> Self { + Wrapping(self.0.wrapping_shr(rhs)) + } +} + +#[test] +fn test_wrapping_traits() { + fn wrapping_add(a: T, b: T) -> T { + a.wrapping_add(&b) + } + fn wrapping_sub(a: T, b: T) -> T { + a.wrapping_sub(&b) + } + fn wrapping_mul(a: T, b: T) -> T { + a.wrapping_mul(&b) + } + fn wrapping_shl(a: T, b: u32) -> T { + a.wrapping_shl(b) + } + fn wrapping_shr(a: T, b: u32) -> T { + a.wrapping_shr(b) + } + assert_eq!(wrapping_add(255, 1), 0u8); + assert_eq!(wrapping_sub(0, 1), 255u8); + assert_eq!(wrapping_mul(255, 2), 254u8); + assert_eq!(wrapping_shl(255, 8), 255u8); + assert_eq!(wrapping_shr(255, 8), 255u8); + assert_eq!(wrapping_add(255, 1), (Wrapping(255u8) + Wrapping(1u8)).0); + assert_eq!(wrapping_sub(0, 1), (Wrapping(0u8) - Wrapping(1u8)).0); + assert_eq!(wrapping_mul(255, 2), (Wrapping(255u8) * Wrapping(2u8)).0); + assert_eq!(wrapping_shl(255, 8), (Wrapping(255u8) << 8).0); + assert_eq!(wrapping_shr(255, 8), (Wrapping(255u8) >> 8).0); +} + +#[test] +fn wrapping_is_wrappingadd() { + fn require_wrappingadd(_: &T) {} + require_wrappingadd(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingsub() { + fn require_wrappingsub(_: &T) {} + require_wrappingsub(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingmul() { + fn require_wrappingmul(_: &T) {} + require_wrappingmul(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingshl() { + fn require_wrappingshl(_: &T) {} + require_wrappingshl(&Wrapping(42)); +} + +#[test] +fn wrapping_is_wrappingshr() { + fn require_wrappingshr(_: &T) {} + require_wrappingshr(&Wrapping(42)); +} diff --git a/num-traits/src/pow.rs b/num-traits/src/pow.rs new file mode 100644 index 000000000..daecb8e15 --- /dev/null +++ b/num-traits/src/pow.rs @@ -0,0 +1,261 @@ +use core::num::Wrapping; +use core::ops::Mul; +use {CheckedMul, One}; + +/// Binary operator for raising a value to a power. +pub trait Pow { + /// The result after applying the operator. + type Output; + + /// Returns `self` to the power `rhs`. + /// + /// # Examples + /// + /// ``` + /// use num_traits::Pow; + /// assert_eq!(Pow::pow(10u32, 2u32), 100); + /// ``` + fn pow(self, rhs: RHS) -> Self::Output; +} + +macro_rules! pow_impl { + ($t:ty) => { + pow_impl!($t, u8); + pow_impl!($t, usize); + + // FIXME: these should be possible + // pow_impl!($t, u16); + // pow_impl!($t, u32); + // pow_impl!($t, u64); + }; + ($t:ty, $rhs:ty) => { + pow_impl!($t, $rhs, usize, pow); + }; + ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => { + impl Pow<$rhs> for $t { + type Output = $t; + #[inline] + fn pow(self, rhs: $rhs) -> $t { + ($method)(self, <$desired_rhs>::from(rhs)) + } + } + + impl<'a> Pow<&'a $rhs> for $t { + type Output = $t; + #[inline] + fn pow(self, rhs: &'a $rhs) -> $t { + ($method)(self, <$desired_rhs>::from(*rhs)) + } + } + + impl<'a> Pow<$rhs> for &'a $t { + type Output = $t; + #[inline] + fn pow(self, rhs: $rhs) -> $t { + ($method)(*self, <$desired_rhs>::from(rhs)) + } + } + + impl<'a, 'b> Pow<&'a $rhs> for &'b $t { + type Output = $t; + #[inline] + fn pow(self, rhs: &'a $rhs) -> $t { + ($method)(*self, <$desired_rhs>::from(*rhs)) + } + } + }; +} + +pow_impl!(u8, u8, u32, u8::pow); +pow_impl!(u8, u16, u32, u8::pow); +pow_impl!(u8, u32, u32, u8::pow); +pow_impl!(u8, usize); +pow_impl!(i8, u8, u32, i8::pow); +pow_impl!(i8, u16, u32, i8::pow); +pow_impl!(i8, u32, u32, i8::pow); +pow_impl!(i8, usize); +pow_impl!(u16, u8, u32, u16::pow); +pow_impl!(u16, u16, u32, u16::pow); +pow_impl!(u16, u32, u32, u16::pow); +pow_impl!(u16, usize); +pow_impl!(i16, u8, u32, i16::pow); +pow_impl!(i16, u16, u32, i16::pow); +pow_impl!(i16, u32, u32, i16::pow); +pow_impl!(i16, usize); +pow_impl!(u32, u8, u32, u32::pow); +pow_impl!(u32, u16, u32, u32::pow); +pow_impl!(u32, u32, u32, u32::pow); +pow_impl!(u32, usize); +pow_impl!(i32, u8, u32, i32::pow); +pow_impl!(i32, u16, u32, i32::pow); +pow_impl!(i32, u32, u32, i32::pow); +pow_impl!(i32, usize); +pow_impl!(u64, u8, u32, u64::pow); +pow_impl!(u64, u16, u32, u64::pow); +pow_impl!(u64, u32, u32, u64::pow); +pow_impl!(u64, usize); +pow_impl!(i64, u8, u32, i64::pow); +pow_impl!(i64, u16, u32, i64::pow); +pow_impl!(i64, u32, u32, i64::pow); +pow_impl!(i64, usize); + +#[cfg(has_i128)] +pow_impl!(u128, u8, u32, u128::pow); +#[cfg(has_i128)] +pow_impl!(u128, u16, u32, u128::pow); +#[cfg(has_i128)] +pow_impl!(u128, u32, u32, u128::pow); +#[cfg(has_i128)] +pow_impl!(u128, usize); + +#[cfg(has_i128)] +pow_impl!(i128, u8, u32, i128::pow); +#[cfg(has_i128)] +pow_impl!(i128, u16, u32, i128::pow); +#[cfg(has_i128)] +pow_impl!(i128, u32, u32, i128::pow); +#[cfg(has_i128)] +pow_impl!(i128, usize); + +pow_impl!(usize, u8, u32, usize::pow); +pow_impl!(usize, u16, u32, usize::pow); +pow_impl!(usize, u32, u32, usize::pow); +pow_impl!(usize, usize); +pow_impl!(isize, u8, u32, isize::pow); +pow_impl!(isize, u16, u32, isize::pow); +pow_impl!(isize, u32, u32, isize::pow); +pow_impl!(isize, usize); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); +#[cfg(has_i128)] +pow_impl!(Wrapping); +#[cfg(has_i128)] +pow_impl!(Wrapping); +pow_impl!(Wrapping); +pow_impl!(Wrapping); + +// FIXME: these should be possible +// pow_impl!(u8, u64); +// pow_impl!(i16, u64); +// pow_impl!(i8, u64); +// pow_impl!(u16, u64); +// pow_impl!(u32, u64); +// pow_impl!(i32, u64); +// pow_impl!(u64, u64); +// pow_impl!(i64, u64); +// pow_impl!(usize, u64); +// pow_impl!(isize, u64); + +#[cfg(feature = "std")] +mod float_impls { + use super::Pow; + + pow_impl!(f32, i8, i32, f32::powi); + pow_impl!(f32, u8, i32, f32::powi); + pow_impl!(f32, i16, i32, f32::powi); + pow_impl!(f32, u16, i32, f32::powi); + pow_impl!(f32, i32, i32, f32::powi); + pow_impl!(f64, i8, i32, f64::powi); + pow_impl!(f64, u8, i32, f64::powi); + pow_impl!(f64, i16, i32, f64::powi); + pow_impl!(f64, u16, i32, f64::powi); + pow_impl!(f64, i32, i32, f64::powi); + pow_impl!(f32, f32, f32, f32::powf); + pow_impl!(f64, f32, f64, f64::powf); + pow_impl!(f64, f64, f64, f64::powf); +} + +/// Raises a value to the power of exp, using exponentiation by squaring. +/// +/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined. +/// +/// # Example +/// +/// ```rust +/// use num_traits::pow; +/// +/// assert_eq!(pow(2i8, 4), 16); +/// assert_eq!(pow(6u8, 3), 216); +/// assert_eq!(pow(0u8, 0), 1); // Be aware if this case affects you +/// ``` +#[inline] +pub fn pow>(mut base: T, mut exp: usize) -> T { + if exp == 0 { + return T::one(); + } + + while exp & 1 == 0 { + base = base.clone() * base; + exp >>= 1; + } + if exp == 1 { + return base; + } + + let mut acc = base.clone(); + while exp > 1 { + exp >>= 1; + base = base.clone() * base; + if exp & 1 == 1 { + acc = acc * base.clone(); + } + } + acc +} + +/// Raises a value to the power of exp, returning `None` if an overflow occurred. +/// +/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined. +/// +/// Otherwise same as the `pow` function. +/// +/// # Example +/// +/// ```rust +/// use num_traits::checked_pow; +/// +/// assert_eq!(checked_pow(2i8, 4), Some(16)); +/// assert_eq!(checked_pow(7i8, 8), None); +/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801)); +/// assert_eq!(checked_pow(0u32, 0), Some(1)); // Be aware if this case affect you +/// ``` +#[inline] +pub fn checked_pow(mut base: T, mut exp: usize) -> Option { + if exp == 0 { + return Some(T::one()); + } + + macro_rules! optry { + ($expr:expr) => { + if let Some(val) = $expr { + val + } else { + return None; + } + }; + } + + while exp & 1 == 0 { + base = optry!(base.checked_mul(&base)); + exp >>= 1; + } + if exp == 1 { + return Some(base); + } + + let mut acc = base.clone(); + while exp > 1 { + exp >>= 1; + base = optry!(base.checked_mul(&base)); + if exp & 1 == 1 { + acc = optry!(acc.checked_mul(&base)); + } + } + Some(acc) +} diff --git a/num-traits/src/real.rs b/num-traits/src/real.rs new file mode 100644 index 000000000..23ac6b8fd --- /dev/null +++ b/num-traits/src/real.rs @@ -0,0 +1,832 @@ +use std::ops::Neg; + +use {Float, Num, NumCast}; + +// NOTE: These doctests have the same issue as those in src/float.rs. +// They're testing the inherent methods directly, and not those of `Real`. + +/// A trait for real number types that do not necessarily have +/// floating-point-specific characteristics such as NaN and infinity. +/// +/// See [this Wikipedia article](https://en.wikipedia.org/wiki/Real_data_type) +/// for a list of data types that could meaningfully implement this trait. +/// +/// This trait is only available with the `std` feature. +pub trait Real: Num + Copy + NumCast + PartialOrd + Neg { + /// Returns the smallest finite value that this type can represent. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x: f64 = Real::min_value(); + /// + /// assert_eq!(x, f64::MIN); + /// ``` + fn min_value() -> Self; + + /// Returns the smallest positive, normalized value that this type can represent. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x: f64 = Real::min_positive_value(); + /// + /// assert_eq!(x, f64::MIN_POSITIVE); + /// ``` + fn min_positive_value() -> Self; + + /// Returns epsilon, a small positive value. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x: f64 = Real::epsilon(); + /// + /// assert_eq!(x, f64::EPSILON); + /// ``` + /// + /// # Panics + /// + /// The default implementation will panic if `f32::EPSILON` cannot + /// be cast to `Self`. + fn epsilon() -> Self; + + /// Returns the largest finite value that this type can represent. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x: f64 = Real::max_value(); + /// assert_eq!(x, f64::MAX); + /// ``` + fn max_value() -> Self; + + /// Returns the largest integer less than or equal to a number. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 3.99; + /// let g = 3.0; + /// + /// assert_eq!(f.floor(), 3.0); + /// assert_eq!(g.floor(), 3.0); + /// ``` + fn floor(self) -> Self; + + /// Returns the smallest integer greater than or equal to a number. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 3.01; + /// let g = 4.0; + /// + /// assert_eq!(f.ceil(), 4.0); + /// assert_eq!(g.ceil(), 4.0); + /// ``` + fn ceil(self) -> Self; + + /// Returns the nearest integer to a number. Round half-way cases away from + /// `0.0`. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 3.3; + /// let g = -3.3; + /// + /// assert_eq!(f.round(), 3.0); + /// assert_eq!(g.round(), -3.0); + /// ``` + fn round(self) -> Self; + + /// Return the integer part of a number. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 3.3; + /// let g = -3.7; + /// + /// assert_eq!(f.trunc(), 3.0); + /// assert_eq!(g.trunc(), -3.0); + /// ``` + fn trunc(self) -> Self; + + /// Returns the fractional part of a number. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 3.5; + /// let y = -3.5; + /// let abs_difference_x = (x.fract() - 0.5).abs(); + /// let abs_difference_y = (y.fract() - (-0.5)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + fn fract(self) -> Self; + + /// Computes the absolute value of `self`. Returns `Float::nan()` if the + /// number is `Float::nan()`. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = 3.5; + /// let y = -3.5; + /// + /// let abs_difference_x = (x.abs() - x).abs(); + /// let abs_difference_y = (y.abs() - (-y)).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// + /// assert!(::num_traits::Float::is_nan(f64::NAN.abs())); + /// ``` + fn abs(self) -> Self; + + /// Returns a number that represents the sign of `self`. + /// + /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` + /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` + /// - `Float::nan()` if the number is `Float::nan()` + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let f = 3.5; + /// + /// assert_eq!(f.signum(), 1.0); + /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); + /// + /// assert!(f64::NAN.signum().is_nan()); + /// ``` + fn signum(self) -> Self; + + /// Returns `true` if `self` is positive, including `+0.0`, + /// `Float::infinity()`, and with newer versions of Rust `f64::NAN`. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let neg_nan: f64 = -f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// assert!(!neg_nan.is_sign_positive()); + /// ``` + fn is_sign_positive(self) -> bool; + + /// Returns `true` if `self` is negative, including `-0.0`, + /// `Float::neg_infinity()`, and with newer versions of Rust `-f64::NAN`. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let nan: f64 = f64::NAN; + /// + /// let f = 7.0; + /// let g = -7.0; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// assert!(!nan.is_sign_negative()); + /// ``` + fn is_sign_negative(self) -> bool; + + /// Fused multiply-add. Computes `(self * a) + b` with only one rounding + /// error, yielding a more accurate result than an unfused multiply-add. + /// + /// Using `mul_add` can be more performant than an unfused multiply-add if + /// the target architecture has a dedicated `fma` CPU instruction. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let m = 10.0; + /// let x = 4.0; + /// let b = 60.0; + /// + /// // 100.0 + /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn mul_add(self, a: Self, b: Self) -> Self; + + /// Take the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 2.0; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn recip(self) -> Self; + + /// Raise a number to an integer power. + /// + /// Using this function is generally faster than using `powf` + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 2.0; + /// let abs_difference = (x.powi(2) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn powi(self, n: i32) -> Self; + + /// Raise a number to a real number power. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 2.0; + /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn powf(self, n: Self) -> Self; + + /// Take the square root of a number. + /// + /// Returns NaN if `self` is a negative floating-point number. + /// + /// # Panics + /// + /// If the implementing type doesn't support NaN, this method should panic if `self < 0`. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let positive = 4.0; + /// let negative = -4.0; + /// + /// let abs_difference = (positive.sqrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// assert!(::num_traits::Float::is_nan(negative.sqrt())); + /// ``` + fn sqrt(self) -> Self; + + /// Returns `e^(self)`, (the exponential function). + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp(self) -> Self; + + /// Returns `2^(self)`. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 2.0; + /// + /// // 2^2 - 4 == 0 + /// let abs_difference = (f.exp2() - 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp2(self) -> Self; + + /// Returns the natural logarithm of the number. + /// + /// # Panics + /// + /// If `self <= 0` and this type does not support a NaN representation, this function should panic. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let one = 1.0; + /// // e^1 + /// let e = one.exp(); + /// + /// // ln(e) - 1 == 0 + /// let abs_difference = (e.ln() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn ln(self) -> Self; + + /// Returns the logarithm of the number with respect to an arbitrary base. + /// + /// # Panics + /// + /// If `self <= 0` and this type does not support a NaN representation, this function should panic. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let ten = 10.0; + /// let two = 2.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); + /// + /// // log2(2) - 1 == 0 + /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); + /// + /// assert!(abs_difference_10 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn log(self, base: Self) -> Self; + + /// Returns the base 2 logarithm of the number. + /// + /// # Panics + /// + /// If `self <= 0` and this type does not support a NaN representation, this function should panic. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let two = 2.0; + /// + /// // log2(2) - 1 == 0 + /// let abs_difference = (two.log2() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log2(self) -> Self; + + /// Returns the base 10 logarithm of the number. + /// + /// # Panics + /// + /// If `self <= 0` and this type does not support a NaN representation, this function should panic. + /// + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let ten = 10.0; + /// + /// // log10(10) - 1 == 0 + /// let abs_difference = (ten.log10() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn log10(self) -> Self; + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn to_degrees(self) -> Self; + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn to_radians(self) -> Self; + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.max(y), y); + /// ``` + fn max(self, other: Self) -> Self; + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 1.0; + /// let y = 2.0; + /// + /// assert_eq!(x.min(y), x); + /// ``` + fn min(self, other: Self) -> Self; + + /// The positive difference of two numbers. + /// + /// * If `self <= other`: `0:0` + /// * Else: `self - other` + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 3.0; + /// let y = -3.0; + /// + /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); + /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); + /// + /// assert!(abs_difference_x < 1e-10); + /// assert!(abs_difference_y < 1e-10); + /// ``` + fn abs_sub(self, other: Self) -> Self; + + /// Take the cubic root of a number. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 8.0; + /// + /// // x^(1/3) - 2 == 0 + /// let abs_difference = (x.cbrt() - 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cbrt(self) -> Self; + + /// Calculate the length of the hypotenuse of a right-angle triangle given + /// legs of length `x` and `y`. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 2.0; + /// let y = 3.0; + /// + /// // sqrt(x^2 + y^2) + /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn hypot(self, other: Self) -> Self; + + /// Computes the sine of a number (in radians). + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/2.0; + /// + /// let abs_difference = (x.sin() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sin(self) -> Self; + + /// Computes the cosine of a number (in radians). + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = 2.0*f64::consts::PI; + /// + /// let abs_difference = (x.cos() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn cos(self) -> Self; + + /// Computes the tangent of a number (in radians). + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let abs_difference = (x.tan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-14); + /// ``` + fn tan(self) -> Self; + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Panics + /// + /// If this type does not support a NaN representation, this function should panic + /// if the number is outside the range [-1, 1]. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let f = f64::consts::PI / 2.0; + /// + /// // asin(sin(pi/2)) + /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn asin(self) -> Self; + + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + /// + /// # Panics + /// + /// If this type does not support a NaN representation, this function should panic + /// if the number is outside the range [-1, 1]. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let f = f64::consts::PI / 4.0; + /// + /// // acos(cos(pi/4)) + /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn acos(self) -> Self; + + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let f = 1.0; + /// + /// // atan(tan(1)) + /// let abs_difference = (f.tan().atan() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn atan(self) -> Self; + + /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). + /// + /// * `x = 0`, `y = 0`: `0` + /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let pi = f64::consts::PI; + /// // All angles from horizontal right (+x) + /// // 45 deg counter-clockwise + /// let x1 = 3.0; + /// let y1 = -3.0; + /// + /// // 135 deg clockwise + /// let x2 = -3.0; + /// let y2 = 3.0; + /// + /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// + /// assert!(abs_difference_1 < 1e-10); + /// assert!(abs_difference_2 < 1e-10); + /// ``` + fn atan2(self, other: Self) -> Self; + + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = f64::consts::PI/4.0; + /// let f = x.sin_cos(); + /// + /// let abs_difference_0 = (f.0 - x.sin()).abs(); + /// let abs_difference_1 = (f.1 - x.cos()).abs(); + /// + /// assert!(abs_difference_0 < 1e-10); + /// assert!(abs_difference_0 < 1e-10); + /// ``` + fn sin_cos(self) -> (Self, Self); + + /// Returns `e^(self) - 1` in a way that is accurate even if the + /// number is close to zero. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 7.0; + /// + /// // e^(ln(7)) - 1 + /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn exp_m1(self) -> Self; + + /// Returns `ln(1+n)` (natural logarithm) more accurately than if + /// the operations were performed separately. + /// + /// # Panics + /// + /// If this type does not support a NaN representation, this function should panic + /// if `self-1 <= 0`. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let x = f64::consts::E - 1.0; + /// + /// // ln(1 + (e - 1)) == ln(e) == 1 + /// let abs_difference = (x.ln_1p() - 1.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn ln_1p(self) -> Self; + + /// Hyperbolic sine function. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.sinh(); + /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` + /// let g = (e*e - 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + fn sinh(self) -> Self; + + /// Hyperbolic cosine function. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// let f = x.cosh(); + /// // Solving cosh() at 1 gives this result + /// let g = (e*e + 1.0)/(2.0*e); + /// let abs_difference = (f - g).abs(); + /// + /// // Same result + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn cosh(self) -> Self; + + /// Hyperbolic tangent function. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let x = 1.0; + /// + /// let f = x.tanh(); + /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` + /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let abs_difference = (f - g).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn tanh(self) -> Self; + + /// Inverse hyperbolic sine function. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 1.0; + /// let f = x.sinh().asinh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn asinh(self) -> Self; + + /// Inverse hyperbolic cosine function. + /// + /// ``` + /// use num_traits::real::Real; + /// + /// let x = 1.0; + /// let f = x.cosh().acosh(); + /// + /// let abs_difference = (f - x).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn acosh(self) -> Self; + + /// Inverse hyperbolic tangent function. + /// + /// ``` + /// use num_traits::real::Real; + /// use std::f64; + /// + /// let e = f64::consts::E; + /// let f = e.tanh().atanh(); + /// + /// let abs_difference = (f - e).abs(); + /// + /// assert!(abs_difference < 1.0e-10); + /// ``` + fn atanh(self) -> Self; +} + +impl Real for T { + forward! { + Float::min_value() -> Self; + Float::min_positive_value() -> Self; + Float::epsilon() -> Self; + Float::max_value() -> Self; + } + forward! { + Float::floor(self) -> Self; + Float::ceil(self) -> Self; + Float::round(self) -> Self; + Float::trunc(self) -> Self; + Float::fract(self) -> Self; + Float::abs(self) -> Self; + Float::signum(self) -> Self; + Float::is_sign_positive(self) -> bool; + Float::is_sign_negative(self) -> bool; + Float::mul_add(self, a: Self, b: Self) -> Self; + Float::recip(self) -> Self; + Float::powi(self, n: i32) -> Self; + Float::powf(self, n: Self) -> Self; + Float::sqrt(self) -> Self; + Float::exp(self) -> Self; + Float::exp2(self) -> Self; + Float::ln(self) -> Self; + Float::log(self, base: Self) -> Self; + Float::log2(self) -> Self; + Float::log10(self) -> Self; + Float::to_degrees(self) -> Self; + Float::to_radians(self) -> Self; + Float::max(self, other: Self) -> Self; + Float::min(self, other: Self) -> Self; + Float::abs_sub(self, other: Self) -> Self; + Float::cbrt(self) -> Self; + Float::hypot(self, other: Self) -> Self; + Float::sin(self) -> Self; + Float::cos(self) -> Self; + Float::tan(self) -> Self; + Float::asin(self) -> Self; + Float::acos(self) -> Self; + Float::atan(self) -> Self; + Float::atan2(self, other: Self) -> Self; + Float::sin_cos(self) -> (Self, Self); + Float::exp_m1(self) -> Self; + Float::ln_1p(self) -> Self; + Float::sinh(self) -> Self; + Float::cosh(self) -> Self; + Float::tanh(self) -> Self; + Float::asinh(self) -> Self; + Float::acosh(self) -> Self; + Float::atanh(self) -> Self; + } +} diff --git a/num-traits/src/sign.rs b/num-traits/src/sign.rs new file mode 100644 index 000000000..26d44c500 --- /dev/null +++ b/num-traits/src/sign.rs @@ -0,0 +1,225 @@ +use core::num::Wrapping; +use core::ops::Neg; + +use float::FloatCore; +use Num; + +/// Useful functions for signed numbers (i.e. numbers that can be negative). +pub trait Signed: Sized + Num + Neg { + /// Computes the absolute value. + /// + /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`. + /// + /// For signed integers, `::MIN` will be returned if the number is `::MIN`. + fn abs(&self) -> Self; + + /// The positive difference of two numbers. + /// + /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference + /// between `self` and `other` is returned. + fn abs_sub(&self, other: &Self) -> Self; + + /// Returns the sign of the number. + /// + /// For `f32` and `f64`: + /// + /// * `1.0` if the number is positive, `+0.0` or `INFINITY` + /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// * `NaN` if the number is `NaN` + /// + /// For signed integers: + /// + /// * `0` if the number is zero + /// * `1` if the number is positive + /// * `-1` if the number is negative + fn signum(&self) -> Self; + + /// Returns true if the number is positive and false if the number is zero or negative. + fn is_positive(&self) -> bool; + + /// Returns true if the number is negative and false if the number is zero or positive. + fn is_negative(&self) -> bool; +} + +macro_rules! signed_impl { + ($($t:ty)*) => ($( + impl Signed for $t { + #[inline] + fn abs(&self) -> $t { + if self.is_negative() { -*self } else { *self } + } + + #[inline] + fn abs_sub(&self, other: &$t) -> $t { + if *self <= *other { 0 } else { *self - *other } + } + + #[inline] + fn signum(&self) -> $t { + match *self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + + #[inline] + fn is_positive(&self) -> bool { *self > 0 } + + #[inline] + fn is_negative(&self) -> bool { *self < 0 } + } + )*) +} + +signed_impl!(isize i8 i16 i32 i64); + +#[cfg(has_i128)] +signed_impl!(i128); + +impl Signed for Wrapping +where + Wrapping: Num + Neg>, +{ + #[inline] + fn abs(&self) -> Self { + Wrapping(self.0.abs()) + } + + #[inline] + fn abs_sub(&self, other: &Self) -> Self { + Wrapping(self.0.abs_sub(&other.0)) + } + + #[inline] + fn signum(&self) -> Self { + Wrapping(self.0.signum()) + } + + #[inline] + fn is_positive(&self) -> bool { + self.0.is_positive() + } + + #[inline] + fn is_negative(&self) -> bool { + self.0.is_negative() + } +} + +macro_rules! signed_float_impl { + ($t:ty) => { + impl Signed for $t { + /// Computes the absolute value. Returns `NAN` if the number is `NAN`. + #[inline] + fn abs(&self) -> $t { + FloatCore::abs(*self) + } + + /// The positive difference of two numbers. Returns `0.0` if the number is + /// less than or equal to `other`, otherwise the difference between`self` + /// and `other` is returned. + #[inline] + fn abs_sub(&self, other: &$t) -> $t { + if *self <= *other { + 0. + } else { + *self - *other + } + } + + /// # Returns + /// + /// - `1.0` if the number is positive, `+0.0` or `INFINITY` + /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` + /// - `NAN` if the number is NaN + #[inline] + fn signum(&self) -> $t { + FloatCore::signum(*self) + } + + /// Returns `true` if the number is positive, including `+0.0` and `INFINITY` + #[inline] + fn is_positive(&self) -> bool { + FloatCore::is_sign_positive(*self) + } + + /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY` + #[inline] + fn is_negative(&self) -> bool { + FloatCore::is_sign_negative(*self) + } + } + }; +} + +signed_float_impl!(f32); +signed_float_impl!(f64); + +/// Computes the absolute value. +/// +/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN` +/// +/// For signed integers, `::MIN` will be returned if the number is `::MIN`. +#[inline(always)] +pub fn abs(value: T) -> T { + value.abs() +} + +/// The positive difference of two numbers. +/// +/// Returns zero if `x` is less than or equal to `y`, otherwise the difference +/// between `x` and `y` is returned. +#[inline(always)] +pub fn abs_sub(x: T, y: T) -> T { + x.abs_sub(&y) +} + +/// Returns the sign of the number. +/// +/// For `f32` and `f64`: +/// +/// * `1.0` if the number is positive, `+0.0` or `INFINITY` +/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` +/// * `NaN` if the number is `NaN` +/// +/// For signed integers: +/// +/// * `0` if the number is zero +/// * `1` if the number is positive +/// * `-1` if the number is negative +#[inline(always)] +pub fn signum(value: T) -> T { + value.signum() +} + +/// A trait for values which cannot be negative +pub trait Unsigned: Num {} + +macro_rules! empty_trait_impl { + ($name:ident for $($t:ty)*) => ($( + impl $name for $t {} + )*) +} + +empty_trait_impl!(Unsigned for usize u8 u16 u32 u64); +#[cfg(has_i128)] +empty_trait_impl!(Unsigned for u128); + +impl Unsigned for Wrapping where Wrapping: Num {} + +#[test] +fn unsigned_wrapping_is_unsigned() { + fn require_unsigned(_: &T) {} + require_unsigned(&Wrapping(42_u32)); +} +/* +// Commenting this out since it doesn't compile on Rust 1.8, +// because on this version Wrapping doesn't implement Neg and therefore can't +// implement Signed. +#[test] +fn signed_wrapping_is_signed() { + fn require_signed(_: &T) {} + require_signed(&Wrapping(-42)); +} +*/ diff --git a/num-traits/tests/cast.rs b/num-traits/tests/cast.rs new file mode 100644 index 000000000..b3f3108e7 --- /dev/null +++ b/num-traits/tests/cast.rs @@ -0,0 +1,396 @@ +//! Tests of `num_traits::cast`. + +#![no_std] + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +extern crate num_traits; + +use num_traits::cast::*; +use num_traits::Bounded; + +use core::{f32, f64}; +#[cfg(has_i128)] +use core::{i128, u128}; +use core::{i16, i32, i64, i8, isize}; +use core::{u16, u32, u64, u8, usize}; + +use core::fmt::Debug; +use core::mem; +use core::num::Wrapping; + +#[test] +fn to_primitive_float() { + let f32_toolarge = 1e39f64; + assert_eq!(f32_toolarge.to_f32(), None); + assert_eq!((f32::MAX as f64).to_f32(), Some(f32::MAX)); + assert_eq!((-f32::MAX as f64).to_f32(), Some(-f32::MAX)); + assert_eq!(f64::INFINITY.to_f32(), Some(f32::INFINITY)); + assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY)); + assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan())); +} + +#[test] +fn wrapping_to_primitive() { + macro_rules! test_wrapping_to_primitive { + ($($t:ty)+) => { + $({ + let i: $t = 0; + let w = Wrapping(i); + assert_eq!(i.to_u8(), w.to_u8()); + assert_eq!(i.to_u16(), w.to_u16()); + assert_eq!(i.to_u32(), w.to_u32()); + assert_eq!(i.to_u64(), w.to_u64()); + assert_eq!(i.to_usize(), w.to_usize()); + assert_eq!(i.to_i8(), w.to_i8()); + assert_eq!(i.to_i16(), w.to_i16()); + assert_eq!(i.to_i32(), w.to_i32()); + assert_eq!(i.to_i64(), w.to_i64()); + assert_eq!(i.to_isize(), w.to_isize()); + assert_eq!(i.to_f32(), w.to_f32()); + assert_eq!(i.to_f64(), w.to_f64()); + })+ + }; + } + + test_wrapping_to_primitive!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); +} + +#[test] +fn wrapping_is_toprimitive() { + fn require_toprimitive(_: &T) {} + require_toprimitive(&Wrapping(42)); +} + +#[test] +fn wrapping_is_fromprimitive() { + fn require_fromprimitive(_: &T) {} + require_fromprimitive(&Wrapping(42)); +} + +#[test] +fn wrapping_is_numcast() { + fn require_numcast(_: &T) {} + require_numcast(&Wrapping(42)); +} + +#[test] +fn as_primitive() { + let x: f32 = (1.625f64).as_(); + assert_eq!(x, 1.625f32); + + let x: f32 = (3.14159265358979323846f64).as_(); + assert_eq!(x, 3.1415927f32); + + let x: u8 = (768i16).as_(); + assert_eq!(x, 0); +} + +#[test] +fn float_to_integer_checks_overflow() { + // This will overflow an i32 + let source: f64 = 1.0e+123f64; + + // Expect the overflow to be caught + assert_eq!(cast::(source), None); +} + +#[test] +fn cast_to_int_checks_overflow() { + let big_f: f64 = 1.0e123; + let normal_f: f64 = 1.0; + let small_f: f64 = -1.0e123; + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + + assert_eq!(Some(normal_f as isize), cast::(normal_f)); + assert_eq!(Some(normal_f as i8), cast::(normal_f)); + assert_eq!(Some(normal_f as i16), cast::(normal_f)); + assert_eq!(Some(normal_f as i32), cast::(normal_f)); + assert_eq!(Some(normal_f as i64), cast::(normal_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); +} + +#[test] +fn cast_to_unsigned_int_checks_overflow() { + let big_f: f64 = 1.0e123; + let normal_f: f64 = 1.0; + let small_f: f64 = -1.0e123; + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + + assert_eq!(Some(normal_f as usize), cast::(normal_f)); + assert_eq!(Some(normal_f as u8), cast::(normal_f)); + assert_eq!(Some(normal_f as u16), cast::(normal_f)); + assert_eq!(Some(normal_f as u32), cast::(normal_f)); + assert_eq!(Some(normal_f as u64), cast::(normal_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); +} + +#[test] +#[cfg(has_i128)] +fn cast_to_i128_checks_overflow() { + let big_f: f64 = 1.0e123; + let normal_f: f64 = 1.0; + let small_f: f64 = -1.0e123; + assert_eq!(None, cast::(big_f)); + assert_eq!(None, cast::(big_f)); + + assert_eq!(Some(normal_f as i128), cast::(normal_f)); + assert_eq!(Some(normal_f as u128), cast::(normal_f)); + + assert_eq!(None, cast::(small_f)); + assert_eq!(None, cast::(small_f)); +} + +#[cfg(feature = "std")] +fn dbg(args: ::core::fmt::Arguments) { + println!("{}", args); +} + +#[cfg(not(feature = "std"))] +fn dbg(_: ::core::fmt::Arguments) {} + +// Rust 1.8 doesn't handle cfg on macros correctly +macro_rules! dbg { ($($tok:tt)*) => { dbg(format_args!($($tok)*)) } } + +macro_rules! float_test_edge { + ($f:ident -> $($t:ident)+) => { $({ + dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t)); + + let small = if $t::MIN == 0 || mem::size_of::<$t>() < mem::size_of::<$f>() { + $t::MIN as $f - 1.0 + } else { + ($t::MIN as $f).raw_offset(1).floor() + }; + let fmin = small.raw_offset(-1); + dbg!(" testing min {}\n\tvs. {:.0}\n\tand {:.0}", $t::MIN, fmin, small); + assert_eq!(Some($t::MIN), cast::<$f, $t>($t::MIN as $f)); + assert_eq!(Some($t::MIN), cast::<$f, $t>(fmin)); + assert_eq!(None, cast::<$f, $t>(small)); + + let (max, large) = if mem::size_of::<$t>() < mem::size_of::<$f>() { + ($t::MAX, $t::MAX as $f + 1.0) + } else { + let large = $t::MAX as $f; // rounds up! + let max = large.raw_offset(-1) as $t; // the next smallest possible + assert_eq!(max.count_ones(), $f::MANTISSA_DIGITS); + (max, large) + }; + let fmax = large.raw_offset(-1); + dbg!(" testing max {}\n\tvs. {:.0}\n\tand {:.0}", max, fmax, large); + assert_eq!(Some(max), cast::<$f, $t>(max as $f)); + assert_eq!(Some(max), cast::<$f, $t>(fmax)); + assert_eq!(None, cast::<$f, $t>(large)); + + dbg!(" testing non-finite values"); + assert_eq!(None, cast::<$f, $t>($f::NAN)); + assert_eq!(None, cast::<$f, $t>($f::INFINITY)); + assert_eq!(None, cast::<$f, $t>($f::NEG_INFINITY)); + })+} +} + +trait RawOffset: Sized { + type Raw; + fn raw_offset(self, offset: Self::Raw) -> Self; +} + +impl RawOffset for f32 { + type Raw = i32; + fn raw_offset(self, offset: Self::Raw) -> Self { + unsafe { + let raw: Self::Raw = mem::transmute(self); + mem::transmute(raw + offset) + } + } +} + +impl RawOffset for f64 { + type Raw = i64; + fn raw_offset(self, offset: Self::Raw) -> Self { + unsafe { + let raw: Self::Raw = mem::transmute(self); + mem::transmute(raw + offset) + } + } +} + +#[test] +fn cast_float_to_int_edge_cases() { + float_test_edge!(f32 -> isize i8 i16 i32 i64); + float_test_edge!(f32 -> usize u8 u16 u32 u64); + float_test_edge!(f64 -> isize i8 i16 i32 i64); + float_test_edge!(f64 -> usize u8 u16 u32 u64); +} + +#[test] +#[cfg(has_i128)] +fn cast_float_to_i128_edge_cases() { + float_test_edge!(f32 -> i128 u128); + float_test_edge!(f64 -> i128 u128); +} + +macro_rules! int_test_edge { + ($f:ident -> { $($t:ident)+ } with $BigS:ident $BigU:ident ) => { $({ + fn test_edge() { + dbg!("testing cast edge cases for {} -> {}", stringify!($f), stringify!($t)); + + match ($f::MIN as $BigS).cmp(&($t::MIN as $BigS)) { + Greater => { + assert_eq!(Some($f::MIN as $t), cast::<$f, $t>($f::MIN)); + } + Equal => { + assert_eq!(Some($t::MIN), cast::<$f, $t>($f::MIN)); + } + Less => { + let min = $t::MIN as $f; + assert_eq!(Some($t::MIN), cast::<$f, $t>(min)); + assert_eq!(None, cast::<$f, $t>(min - 1)); + } + } + + match ($f::MAX as $BigU).cmp(&($t::MAX as $BigU)) { + Greater => { + let max = $t::MAX as $f; + assert_eq!(Some($t::MAX), cast::<$f, $t>(max)); + assert_eq!(None, cast::<$f, $t>(max + 1)); + } + Equal => { + assert_eq!(Some($t::MAX), cast::<$f, $t>($f::MAX)); + } + Less => { + assert_eq!(Some($f::MAX as $t), cast::<$f, $t>($f::MAX)); + } + } + } + test_edge(); + })+} +} + +#[test] +fn cast_int_to_int_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $from:ident )+) => { $({ + int_test_edge!($from -> { isize i8 i16 i32 i64 } with i64 u64); + int_test_edge!($from -> { usize u8 u16 u32 u64 } with i64 u64); + })+} + } + + test_edge!(isize i8 i16 i32 i64); + test_edge!(usize u8 u16 u32 u64); +} + +#[test] +#[cfg(has_i128)] +fn cast_int_to_128_edge_cases() { + use core::cmp::Ordering::*; + + macro_rules! test_edge { + ($( $t:ident )+) => { + $( + int_test_edge!($t -> { i128 u128 } with i128 u128); + )+ + int_test_edge!(i128 -> { $( $t )+ } with i128 u128); + int_test_edge!(u128 -> { $( $t )+ } with i128 u128); + } + } + + test_edge!(isize i8 i16 i32 i64 i128); + test_edge!(usize u8 u16 u32 u64 u128); +} + +#[test] +fn newtype_from_primitive() { + #[derive(PartialEq, Debug)] + struct New(T); + + // minimal impl + impl FromPrimitive for New { + fn from_i64(n: i64) -> Option { + T::from_i64(n).map(New) + } + + fn from_u64(n: u64) -> Option { + T::from_u64(n).map(New) + } + } + + macro_rules! assert_eq_from { + ($( $from:ident )+) => {$( + assert_eq!(T::$from(Bounded::min_value()).map(New), + New::::$from(Bounded::min_value())); + assert_eq!(T::$from(Bounded::max_value()).map(New), + New::::$from(Bounded::max_value())); + )+} + } + + fn check() { + assert_eq_from!(from_i8 from_i16 from_i32 from_i64 from_isize); + assert_eq_from!(from_u8 from_u16 from_u32 from_u64 from_usize); + assert_eq_from!(from_f32 from_f64); + } + + macro_rules! check { + ($( $ty:ty )+) => {$( check::<$ty>(); )+} + } + check!(i8 i16 i32 i64 isize); + check!(u8 u16 u32 u64 usize); +} + +#[test] +fn newtype_to_primitive() { + #[derive(PartialEq, Debug)] + struct New(T); + + // minimal impl + impl ToPrimitive for New { + fn to_i64(&self) -> Option { + self.0.to_i64() + } + + fn to_u64(&self) -> Option { + self.0.to_u64() + } + } + + macro_rules! assert_eq_to { + ($( $to:ident )+) => {$( + assert_eq!(T::$to(&Bounded::min_value()), + New::::$to(&New(Bounded::min_value()))); + assert_eq!(T::$to(&Bounded::max_value()), + New::::$to(&New(Bounded::max_value()))); + )+} + } + + fn check() { + assert_eq_to!(to_i8 to_i16 to_i32 to_i64 to_isize); + assert_eq_to!(to_u8 to_u16 to_u32 to_u64 to_usize); + assert_eq_to!(to_f32 to_f64); + } + + macro_rules! check { + ($( $ty:ty )+) => {$( check::<$ty>(); )+} + } + check!(i8 i16 i32 i64 isize); + check!(u8 u16 u32 u64 usize); +} diff --git a/num_cpus/.cargo-checksum.json b/num_cpus/.cargo-checksum.json new file mode 100644 index 000000000..2aeb011f5 --- /dev/null +++ b/num_cpus/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"} \ No newline at end of file diff --git a/num_cpus/CHANGELOG.md b/num_cpus/CHANGELOG.md new file mode 100644 index 000000000..93710a7dc --- /dev/null +++ b/num_cpus/CHANGELOG.md @@ -0,0 +1,95 @@ +## v1.10.0 + +#### Features + +- add `illumos` target OS support +- add default fallback if target is unknown to `1` + +## v1.9.0 + +#### Features + +- add `sgx` target env support + +## v1.8.0 + +#### Features + +- add `wasm-unknown-unknown` target support + +## v1.7.0 + +#### Features + +- add `get_physical` support for macOS + +#### Fixes + +- use `_SC_NPROCESSORS_CONF` on Unix targets + +### v1.6.2 + +#### Fixes + +- revert 1.6.1 for now + +### v1.6.1 + +#### Fixes + +- fixes sometimes incorrect num on Android/ARM Linux (#45) + +## v1.6.0 + +#### Features + +- `get_physical` gains Windows support + +### v1.5.1 + +#### Fixes + +- fix `get` to return 1 if `sysconf(_SC_NPROCESSORS_ONLN)` failed + +## v1.5.0 + +#### Features + +- `get()` now checks `sched_affinity` on Linux + +## v1.4.0 + +#### Features + +- add `haiku` target support + +## v1.3.0 + +#### Features + +- add `redox` target support + +### v1.2.1 + +#### Fixes + +- fixes `get_physical` count (454ff1b) + +## v1.2.0 + +#### Features + +- add `emscripten` target support +- add `fuchsia` target support + +## v1.1.0 + +#### Features + +- added `get_physical` function to return number of physical CPUs found + +# v1.0.0 + +#### Features + +- `get` function returns number of CPUs (physical and virtual) of current platform diff --git a/num_cpus/CONTRIBUTING.md b/num_cpus/CONTRIBUTING.md new file mode 100644 index 000000000..5685b08c6 --- /dev/null +++ b/num_cpus/CONTRIBUTING.md @@ -0,0 +1,16 @@ +# Contributing + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/num_cpus/Cargo.toml b/num_cpus/Cargo.toml new file mode 100644 index 000000000..f2f7a34cb --- /dev/null +++ b/num_cpus/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "num_cpus" +version = "1.10.0" +authors = ["Sean McArthur "] +description = "Get the number of CPUs on a machine." +documentation = "https://docs.rs/num_cpus" +readme = "README.md" +keywords = ["cpu", "cpus", "cores"] +categories = ["hardware-support"] +license = "MIT/Apache-2.0" +repository = "https://github.com/seanmonstar/num_cpus" +[dependencies.libc] +version = "0.2.26" diff --git a/num_cpus/LICENSE-APACHE b/num_cpus/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/num_cpus/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/num_cpus/LICENSE-MIT b/num_cpus/LICENSE-MIT new file mode 100644 index 000000000..8e91dc998 --- /dev/null +++ b/num_cpus/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/num_cpus/README.md b/num_cpus/README.md new file mode 100644 index 000000000..a0bbe97c1 --- /dev/null +++ b/num_cpus/README.md @@ -0,0 +1,28 @@ +# num_cpus + +[![crates.io](http://meritbadge.herokuapp.com/num_cpus)](https://crates.io/crates/num_cpus) +[![Travis CI Status](https://travis-ci.org/seanmonstar/num_cpus.svg?branch=master)](https://travis-ci.org/seanmonstar/num_cpus) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/qn8t6grhko5jwno6?svg=true)](https://ci.appveyor.com/project/seanmonstar/num-cpus) + +- [Documentation](https://docs.rs/num_cpus) +- [CHANGELOG](CHANGELOG.md) + +Count the number of CPUs on the current machine. + +## Usage + +Add to Cargo.toml: + +```toml +[dependencies] +num_cpus = "1.0" +``` + +In your `main.rs` or `lib.rs`: + +```rust +extern crate num_cpus; + +// count logical cores this process could try to use +let num = num_cpus::get(); +``` diff --git a/num_cpus/src/lib.rs b/num_cpus/src/lib.rs new file mode 100644 index 000000000..0ab8fb57e --- /dev/null +++ b/num_cpus/src/lib.rs @@ -0,0 +1,425 @@ +//! A crate with utilities to determine the number of CPUs available on the +//! current system. +//! +//! Sometimes the CPU will exaggerate the number of CPUs it contains, because it can use +//! [processor tricks] to deliver increased performance when there are more threads. This +//! crate provides methods to get both the logical and physical numbers of cores. +//! +//! This information can be used as a guide to how many tasks can be run in parallel. +//! There are many properties of the system architecture that will affect parallelism, +//! for example memory access speeds (for all the caches and RAM) and the physical +//! architecture of the processor, so the number of CPUs should be used as a rough guide +//! only. +//! +//! +//! ## Examples +//! +//! Fetch the number of logical CPUs. +//! +//! ``` +//! let cpus = num_cpus::get(); +//! ``` +//! +//! See [`rayon::Threadpool`] for an example of where the number of CPUs could be +//! used when setting up parallel jobs (Where the threadpool example uses a fixed +//! number 8, it could use the number of CPUs). +//! +//! [processor tricks]: https://en.wikipedia.org/wiki/Simultaneous_multithreading +//! [`rayon::ThreadPool`]: https://docs.rs/rayon/1.*/rayon/struct.ThreadPool.html +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] +#![doc(html_root_url = "https://docs.rs/num_cpus/1.10.0")] +#![allow(non_snake_case)] + +#[cfg(not(windows))] +extern crate libc; + + +/// Returns the number of available CPUs of the current system. +/// +/// This function will get the number of logical cores. Sometimes this is different from the number +/// of physical cores (See [Simultaneous multithreading on Wikipedia][smt]). +/// +/// # Examples +/// +/// ``` +/// let cpus = num_cpus::get(); +/// if cpus > 1 { +/// println!("We are on a multicore system with {} CPUs", cpus); +/// } else { +/// println!("We are on a single core system"); +/// } +/// ``` +/// +/// # Note +/// +/// This will check [sched affinity] on Linux, showing a lower number of CPUs if the current +/// thread does not have access to all the computer's CPUs. +/// +/// [smt]: https://en.wikipedia.org/wiki/Simultaneous_multithreading +/// [sched affinity]: http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html +#[inline] +pub fn get() -> usize { + get_num_cpus() +} + +/// Returns the number of physical cores of the current system. +/// +/// # Note +/// +/// Physical count is supported only on Linux, mac OS and Windows platforms. +/// On other platforms, or if the physical count fails on supported platforms, +/// this function returns the same as [`get()`], which is the number of logical +/// CPUS. +/// +/// # Examples +/// +/// ``` +/// let logical_cpus = num_cpus::get(); +/// let physical_cpus = num_cpus::get_physical(); +/// if logical_cpus > physical_cpus { +/// println!("We have simultaneous multithreading with about {:.2} \ +/// logical cores to 1 physical core.", +/// (logical_cpus as f64) / (physical_cpus as f64)); +/// } else if logical_cpus == physical_cpus { +/// println!("Either we don't have simultaneous multithreading, or our \ +/// system doesn't support getting the number of physical CPUs."); +/// } else { +/// println!("We have less logical CPUs than physical CPUs, maybe we only have access to \ +/// some of the CPUs on our system."); +/// } +/// ``` +/// +/// [`get()`]: fn.get.html +#[inline] +pub fn get_physical() -> usize { + get_num_physical_cpus() +} + + +#[cfg(not(any(target_os = "linux", target_os = "windows", target_os="macos")))] +#[inline] +fn get_num_physical_cpus() -> usize { + // Not implemented, fall back + get_num_cpus() +} + +#[cfg(target_os = "windows")] +fn get_num_physical_cpus() -> usize { + match get_num_physical_cpus_windows() { + Some(num) => num, + None => get_num_cpus() + } +} + +#[cfg(target_os = "windows")] +fn get_num_physical_cpus_windows() -> Option { + // Inspired by https://msdn.microsoft.com/en-us/library/ms683194 + + use std::ptr; + use std::mem; + + #[allow(non_upper_case_globals)] + const RelationProcessorCore: u32 = 0; + + #[repr(C)] + #[allow(non_camel_case_types)] + struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + mask: usize, + relationship: u32, + _unused: [u64; 2] + } + + extern "system" { + fn GetLogicalProcessorInformation( + info: *mut SYSTEM_LOGICAL_PROCESSOR_INFORMATION, + length: &mut u32 + ) -> u32; + } + + // First we need to determine how much space to reserve. + + // The required size of the buffer, in bytes. + let mut needed_size = 0; + + unsafe { + GetLogicalProcessorInformation(ptr::null_mut(), &mut needed_size); + } + + let struct_size = mem::size_of::() as u32; + + // Could be 0, or some other bogus size. + if needed_size == 0 || needed_size < struct_size || needed_size % struct_size != 0 { + return None; + } + + let count = needed_size / struct_size; + + // Allocate some memory where we will store the processor info. + let mut buf = Vec::with_capacity(count as usize); + + let result; + + unsafe { + result = GetLogicalProcessorInformation(buf.as_mut_ptr(), &mut needed_size); + } + + // Failed for any reason. + if result == 0 { + return None; + } + + let count = needed_size / struct_size; + + unsafe { + buf.set_len(count as usize); + } + + let phys_proc_count = buf.iter() + // Only interested in processor packages (physical processors.) + .filter(|proc_info| proc_info.relationship == RelationProcessorCore) + .count(); + + if phys_proc_count == 0 { + None + } else { + Some(phys_proc_count) + } +} + +#[cfg(target_os = "linux")] +fn get_num_physical_cpus() -> usize { + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; + use std::collections::HashSet; + + let file = match File::open("/proc/cpuinfo") { + Ok(val) => val, + Err(_) => {return get_num_cpus()}, + }; + let reader = BufReader::new(file); + let mut set = HashSet::new(); + let mut coreid: u32 = 0; + let mut physid: u32 = 0; + let mut chgcount = 0; + for line in reader.lines().filter_map(|result| result.ok()) { + let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect(); + if parts.len() != 2 { + continue + } + if parts[0] == "core id" || parts[0] == "physical id" { + let value = match parts[1].trim().parse() { + Ok(val) => val, + Err(_) => break, + }; + match parts[0] { + "core id" => coreid = value, + "physical id" => physid = value, + _ => {}, + } + chgcount += 1; + } + if chgcount == 2 { + set.insert((physid, coreid)); + chgcount = 0; + } + } + let count = set.len(); + if count == 0 { get_num_cpus() } else { count } +} + +#[cfg(windows)] +fn get_num_cpus() -> usize { + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: u16, + wReserved: u16, + dwPageSize: u32, + lpMinimumApplicationAddress: *mut u8, + lpMaximumApplicationAddress: *mut u8, + dwActiveProcessorMask: *mut u8, + dwNumberOfProcessors: u32, + dwProcessorType: u32, + dwAllocationGranularity: u32, + wProcessorLevel: u16, + wProcessorRevision: u16, + } + + extern "system" { + fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut sysinfo: SYSTEM_INFO = std::mem::uninitialized(); + GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + } +} + +#[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd"))] +fn get_num_cpus() -> usize { + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + + unsafe { + cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; + } + if cpus < 1 { + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + unsafe { + libc::sysctl(mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + 0 as *mut _, + 0); + } + if cpus < 1 { + cpus = 1; + } + } + cpus as usize +} + +#[cfg(target_os = "openbsd")] +fn get_num_cpus() -> usize { + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + unsafe { + libc::sysctl(mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + 0 as *mut _, + 0); + } + if cpus < 1 { + cpus = 1; + } + cpus as usize +} + + +#[cfg(target_os = "macos")] +fn get_num_physical_cpus() -> usize { + use std::ffi::CStr; + use std::ptr; + + let mut cpus: i32 = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + + let sysctl_name = CStr::from_bytes_with_nul(b"hw.physicalcpu\0") + .expect("byte literal is missing NUL"); + + unsafe { + if 0 != libc::sysctlbyname(sysctl_name.as_ptr(), + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0) { + return get_num_cpus(); + } + } + cpus as usize +} + +#[cfg(target_os = "linux")] +fn get_num_cpus() -> usize { + let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() }; + if unsafe { libc::sched_getaffinity(0, std::mem::size_of::(), &mut set) } == 0 { + let mut count: u32 = 0; + for i in 0..libc::CPU_SETSIZE as usize { + if unsafe { libc::CPU_ISSET(i, &set) } { + count += 1 + } + } + count as usize + } else { + let cpus = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) }; + if cpus < 1 { + 1 + } else { + cpus as usize + } + } +} + +#[cfg(any( + target_os = "nacl", + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia") +)] +fn get_num_cpus() -> usize { + // On ARM targets, processors could be turned off to save power. + // Use `_SC_NPROCESSORS_CONF` to get the real number. + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + const CONF_NAME: libc::c_int = libc::_SC_NPROCESSORS_CONF; + #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] + const CONF_NAME: libc::c_int = libc::_SC_NPROCESSORS_ONLN; + + let cpus = unsafe { libc::sysconf(CONF_NAME) }; + if cpus < 1 { + 1 + } else { + cpus as usize + } +} + +#[cfg(not(any( + target_os = "nacl", + target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "linux", + target_os = "openbsd", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd", + windows, +)))] +fn get_num_cpus() -> usize { + 1 +} + +#[cfg(test)] +mod tests { + fn env_var(name: &'static str) -> Option { + ::std::env::var(name).ok().map(|val| val.parse().unwrap()) + } + + #[test] + fn test_get() { + let num = super::get(); + if let Some(n) = env_var("NUM_CPUS_TEST_GET") { + assert_eq!(num, n); + } else { + assert!(num > 0); + assert!(num < 236_451); + } + } + + #[test] + fn test_get_physical() { + let num = super::get_physical(); + if let Some(n) = env_var("NUM_CPUS_TEST_GET_PHYSICAL") { + assert_eq!(num, n); + } else { + assert!(num > 0); + assert!(num < 236_451); + } + } +} diff --git a/numtoa/.cargo-checksum.json b/numtoa/.cargo-checksum.json new file mode 100644 index 000000000..c86d95f04 --- /dev/null +++ b/numtoa/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"} \ No newline at end of file diff --git a/numtoa/Cargo.toml b/numtoa/Cargo.toml new file mode 100644 index 000000000..7a026a1b5 --- /dev/null +++ b/numtoa/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "numtoa" +version = "0.1.0" +authors = ["Michael Aaron Murphy "] +description = "Convert numbers into stack-allocated byte arrays" +documentation = "https://docs.rs/numtoa" +readme = "README.md" +keywords = ["numbers", "convert", "numtoa", "itoa", "no_std"] +categories = ["value-formatting"] +license = "MIT OR Apache-2.0" +repository = "https://gitlab.com/mmstick/numtoa" + +[features] +std = [] diff --git a/numtoa/LICENSE-APACHE b/numtoa/LICENSE-APACHE new file mode 100644 index 000000000..57bc88a15 --- /dev/null +++ b/numtoa/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/numtoa/LICENSE-MIT b/numtoa/LICENSE-MIT new file mode 100644 index 000000000..492da6317 --- /dev/null +++ b/numtoa/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Michael Aaron Murphy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/numtoa/README.md b/numtoa/README.md new file mode 100644 index 000000000..497e906a3 --- /dev/null +++ b/numtoa/README.md @@ -0,0 +1,65 @@ +# NumToA + +## `#![no_std]` Compatible with Zero Heap Allocations + +The standard library provides a convenient method of converting numbers into strings, but these strings are +heap-allocated. If you have an application which needs to convert large volumes of numbers into strings, but don't +want to pay the price of heap allocation, this crate provides an efficient `no_std`-compatible method of heaplessly converting numbers +into their string representations, storing the representation within a reusable byte array. + +## Supports Multiple Bases + +In addition to supporting the standard base 10 conversion, this implementation allows you to select the base of +your choice. Therefore, if you want a binary representation, set the base to 2. If you want hexadecimal, set the +base to 16. + +## No Unsafe + +Both the standard library and itoa crate rely on unsafe functions, but this implementation has been able to avoid +the use of unsafe entirely. + +## Fast + +Performance is roughly identical to that of the `itoa` crate when performing base 10 conversions. Below is a benchmark +of printing 0 through 5,000,000 to `/dev/null` + +``` +std: 1150615048 ns +itoa: 838556714 ns +numtoa: 825544518 ns +``` + +## Base 10 Example + +```rust +use numtoa::NumToA; +use std::io::{self, Write}; + +let stdout = io::stdout(); +let mut stdout = stdout.lock(); +let mut buffer = [0u8; 20]; + +let number: u32 = 162392; +let mut start_index = number.numtoa(10, &mut buffer); +let _ = stdout.write(&buffer[start_index..]); +let _ = stdout.write(b"\n"); +assert_eq!(&buffer[start_index..], b"162392"); + +let other_number: i32 = -6235; +start_index = other_number.numtoa(10, &mut buffer); +let _ = stdout.write(&buffer[start_index..]); +let _ = stdout.write(b"\n"); +assert_eq!(&buffer[start_index..], b"-6235"); + +let large_num: u64 = 35320842; +start_index = large_num.numtoa(10, &mut buffer); +let _ = stdout.write(&buffer[start_index..]); +let _ = stdout.write(b"\n"); +assert_eq!(&buffer[start_index..], b"35320842"); + +let max_u64: u64 = 18446744073709551615; +start_index = max_u64.numtoa(10, &mut buffer); +let _ = stdout.write(&buffer[start_index..]); +let _ = stdout.write(b"\n"); +assert_eq!(&buffer[start_index..], b"18446744073709551615"); +``` diff --git a/numtoa/src/lib.rs b/numtoa/src/lib.rs new file mode 100644 index 000000000..c15b23f09 --- /dev/null +++ b/numtoa/src/lib.rs @@ -0,0 +1,540 @@ +//! The standard library provides a convenient method of converting numbers into strings, but these strings are +//! heap-allocated. If you have an application which needs to convert large volumes of numbers into strings, but don't +//! want to pay the price of heap allocation, this crate provides an efficient `no_std`-compatible method of heaplessly converting numbers +//! into their string representations, storing the representation within a reusable byte array. +//! +//! In addition to supporting the standard base 10 conversion, this implementation allows you to select the base of +//! your choice. Therefore, if you want a binary representation, set the base to 2. If you want hexadecimal, set the +//! base to 16. +//! +//! # Convenience Example +//! +//! ``` +//! use numtoa::NumToA; +//! +//! let mut buf = [0u8; 20]; +//! let mut string = String::new(); +//! +//! for number in (1..10) { +//! string.push_str(number.numtoa_str(10, &mut buf)); +//! string.push('\n'); +//! } +//! +//! println!("{}", string); +//! ``` +//! +//! ## Base 10 Example +//! ``` +//! use numtoa::NumToA; +//! use std::io::{self, Write}; +//! +//! let stdout = io::stdout(); +//! let mut stdout = stdout.lock(); +//! let mut buffer = [0u8; 20]; +//! +//! let number: u32 = 162392; +//! let mut start_indice = number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"162392"); +//! +//! let other_number: i32 = -6235; +//! start_indice = other_number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"-6235"); +//! +//! let other_number: i8 = -128; +//! start_indice = other_number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"-128"); +//! +//! let other_number: i8 = 53; +//! start_indice = other_number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"53"); +//! +//! let other_number: i16 = -256; +//! start_indice = other_number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"-256"); +//! +//! let other_number: i16 = -32768; +//! start_indice = other_number.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"-32768"); +//! +//! let large_num: u64 = 35320842; +//! start_indice = large_num.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"35320842"); +//! +//! let max_u64: u64 = 18446744073709551615; +//! start_indice = max_u64.numtoa(10, &mut buffer); +//! let _ = stdout.write(&buffer[start_indice..]); +//! let _ = stdout.write(b"\n"); +//! assert_eq!(&buffer[start_indice..], b"18446744073709551615"); +//! ``` + +#![no_std] +use core::mem::size_of; + +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "std")] +use std::str; + +/// Converts a number into a string representation, storing the conversion into a mutable byte slice. +pub trait NumToA { + /// Given a base for encoding and a mutable byte slice, write the number into the byte slice and return the + /// indice where the inner string begins. The inner string can be extracted by slicing the byte slice from + /// that indice. + /// + /// # Panics + /// If the supplied buffer is smaller than the number of bytes needed to write the integer, this will panic. + /// On debug builds, this function will perform a check on base 10 conversions to ensure that the input array + /// is large enough to hold the largest possible value in digits. + /// + /// # Example + /// ``` + /// use numtoa::NumToA; + /// use std::io::{self, Write}; + /// + /// let stdout = io::stdout(); + /// let stdout = &mut io::stdout(); + /// + /// let mut buffer = [0u8; 20]; + /// let number = 15325; + /// let start_indice = number.numtoa(10, &mut buffer); + /// let _ = stdout.write(&buffer[start_indice..]); + /// assert_eq!(&buffer[start_indice..], b"15325"); + /// ``` + fn numtoa(self, base: T, string: &mut [u8]) -> usize; + + #[cfg(feature = "std")] + /// Convenience method for quickly getting a string from the input's array buffer. + fn numtoa_str(self, base: T, buf: &mut [u8; 20]) -> &str; +} + +// A lookup table to prevent the need for conditional branching +// The value of the remainder of each step will be used as the index +const LOOKUP: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +// A lookup table optimized for decimal lookups. Each two indices represents one possible number. +const DEC_LOOKUP: &[u8; 200] = b"0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +macro_rules! base_10 { + ($number:ident, $index:ident, $string:ident) => { + // Decode four characters at the same time + while $number > 9999 { + let rem = ($number % 10000) as u16; + let (frst, scnd) = ((rem / 100) * 2, (rem % 100) * 2); + $string[$index-3..$index-1].copy_from_slice(&DEC_LOOKUP[frst as usize..frst as usize+2]); + $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[scnd as usize..scnd as usize+2]); + $index = $index.wrapping_sub(4); + $number /= 10000; + } + + if $number > 999 { + let (frst, scnd) = (($number / 100) * 2, ($number % 100) * 2); + $string[$index-3..$index-1].copy_from_slice(&DEC_LOOKUP[frst as usize..frst as usize+2]); + $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[scnd as usize..scnd as usize+2]); + $index = $index.wrapping_sub(4); + } else if $number > 99 { + let section = ($number as u16 / 10) * 2; + $string[$index-2..$index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); + $string[$index] = LOOKUP[($number % 10) as usize]; + $index = $index.wrapping_sub(3); + } else if $number > 9 { + $number *= 2; + $string[$index-1..$index+1].copy_from_slice(&DEC_LOOKUP[$number as usize..$number as usize+2]); + $index = $index.wrapping_sub(2); + } else { + $string[$index] = LOOKUP[$number as usize]; + $index = $index.wrapping_sub(1); + } + } +} + +macro_rules! impl_unsized_numtoa_for { + ($t:ty) => { + impl NumToA<$t> for $t { + fn numtoa(mut self, base: $t, string: &mut [u8]) -> usize { + // Check if the buffer is large enough and panic on debug builds if it isn't + if cfg!(debug_assertions) { + if base == 10 { + match size_of::<$t>() { + 2 => debug_assert!(string.len() >= 5, "u16 base 10 conversions require at least 5 bytes"), + 4 => debug_assert!(string.len() >= 10, "u32 base 10 conversions require at least 10 bytes"), + 8 => debug_assert!(string.len() >= 20, "u64 base 10 conversions require at least 20 bytes"), + _ => unreachable!() + } + } + } + + let mut index = string.len() - 1; + if self == 0 { + string[index] = b'0'; + return index; + } + + if base == 10 { + // Convert using optimized base 10 algorithm + base_10!(self, index, string); + } else { + while self != 0 { + let rem = self % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + self /= base; + } + } + + index.wrapping_add(1) + } + + #[cfg(feature = "std")] + fn numtoa_str(self, base: $t, buf: &mut [u8; 20]) -> &str { + let s = self.numtoa(base, buf); + unsafe { str::from_utf8_unchecked(&buf[s..]) } + } + } + } +} + +macro_rules! impl_sized_numtoa_for { + ($t:ty) => { + impl NumToA<$t> for $t { + fn numtoa(mut self, base: $t, string: &mut [u8]) -> usize { + if cfg!(debug_assertions) { + if base == 10 { + match size_of::<$t>() { + 2 => debug_assert!(string.len() >= 6, "i16 base 10 conversions require at least 6 bytes"), + 4 => debug_assert!(string.len() >= 11, "i32 base 10 conversions require at least 11 bytes"), + 8 => debug_assert!(string.len() >= 20, "i64 base 10 conversions require at least 20 bytes"), + _ => unreachable!() + } + } + } + + let mut index = string.len() - 1; + let mut is_negative = false; + + if self < 0 { + is_negative = true; + self = match self.checked_abs() { + Some(value) => value, + None => { + let value = <$t>::max_value(); + string[index] = LOOKUP[((value % base + 1) % base) as usize]; + index -= 1; + value / base + ((value % base == base - 1) as $t) + } + }; + } else if self == 0 { + string[index] = b'0'; + return index; + } + + if base == 10 { + // Convert using optimized base 10 algorithm + base_10!(self, index, string); + } else { + while self != 0 { + let rem = self % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + self /= base; + } + } + + if is_negative { + string[index] = b'-'; + index = index.wrapping_sub(1); + } + + index.wrapping_add(1) + } + + #[cfg(feature = "std")] + fn numtoa_str(self, base: $t, buf: &mut [u8; 20]) -> &str { + let s = self.numtoa(base, buf); + unsafe { str::from_utf8_unchecked(&buf[s..]) } + } + } + } +} + +impl_sized_numtoa_for!(i16); +impl_sized_numtoa_for!(i32); +impl_sized_numtoa_for!(i64); +impl_sized_numtoa_for!(isize); +impl_unsized_numtoa_for!(u16); +impl_unsized_numtoa_for!(u32); +impl_unsized_numtoa_for!(u64); +impl_unsized_numtoa_for!(usize); + +impl NumToA for i8 { + fn numtoa(mut self, base: i8, string: &mut [u8]) -> usize { + if cfg!(debug_assertions) { + if base == 10 { + debug_assert!(string.len() >= 4, "i8 conversions need at least 4 bytes"); + } + } + + let mut index = string.len() - 1; + let mut is_negative = false; + + if self < 0 { + is_negative = true; + self = match self.checked_abs() { + Some(value) => value, + None => { + let value = ::max_value(); + string[index] = LOOKUP[((value % base + 1) % base) as usize]; + index -= 1; + value / base + ((value % base == base - 1) as i8) + } + }; + } else if self == 0 { + string[index] = b'0'; + return index; + } + + if base == 10 { + if self > 99 { + let section = (self / 10) * 2; + string[index-2..index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); + string[index] = LOOKUP[(self % 10) as usize]; + index = index.wrapping_sub(3); + } else if self > 9 { + self *= 2; + string[index-1..index+1].copy_from_slice(&DEC_LOOKUP[self as usize..self as usize+2]); + index = index.wrapping_sub(2); + } else { + string[index] = LOOKUP[self as usize]; + index = index.wrapping_sub(1); + } + } else { + while self != 0 { + let rem = self % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + self /= base; + } + } + + if is_negative { + string[index] = b'-'; + index = index.wrapping_sub(1); + } + + index.wrapping_add(1) + } + + #[cfg(feature = "std")] + fn numtoa_str(self, base: Self, buf: &mut [u8; 20]) -> &str { + let s = self.numtoa(base, buf); + unsafe { str::from_utf8_unchecked(&buf[s..]) } + } +} + +impl NumToA for u8 { + fn numtoa(mut self, base: u8, string: &mut [u8]) -> usize { + if cfg!(debug_assertions) { + if base == 10 { + debug_assert!(string.len() >= 3, "u8 conversions need at least 3 bytes"); + } + } + + let mut index = string.len() - 1; + if self == 0 { + string[index] = b'0'; + return index; + } + + if base == 10 { + if self > 99 { + let section = (self / 10) * 2; + string[index-2..index].copy_from_slice(&DEC_LOOKUP[section as usize..section as usize+2]); + string[index] = LOOKUP[(self % 10) as usize]; + index = index.wrapping_sub(3); + } else if self > 9 { + self *= 2; + string[index-1..index+1].copy_from_slice(&DEC_LOOKUP[self as usize..self as usize+2]); + index = index.wrapping_sub(2); + } else { + string[index] = LOOKUP[self as usize]; + index = index.wrapping_sub(1); + } + } else { + while self != 0 { + let rem = self % base; + string[index] = LOOKUP[rem as usize]; + index = index.wrapping_sub(1); + self /= base; + } + } + + index.wrapping_add(1) + } + + #[cfg(feature = "std")] + fn numtoa_str(self, base: Self, buf: &mut [u8; 20]) -> &str { + let s = self.numtoa(base, buf); + unsafe { str::from_utf8_unchecked(&buf[s..]) } + } +} + +#[test] +fn str_convenience() { + let mut buffer = [0u8; 20]; + assert_eq!("256123", 256123.numtoa_str(10, &mut buffer)); +} + +#[test] +#[should_panic] +fn base10_u8_array_too_small() { + let mut buffer = [0u8; 2]; + let _ = 0u8.numtoa(10, &mut buffer); +} + +#[test] +fn base10_u8_array_just_right() { + let mut buffer = [0u8; 3]; + let _ = 0u8.numtoa(10, &mut buffer); +} + +#[test] +#[should_panic] +fn base10_i8_array_too_small() { + let mut buffer = [0u8; 3]; + let _ = 0i8.numtoa(10, &mut buffer); +} + +#[test] +fn base10_i8_array_just_right() { + let mut buffer = [0u8; 4]; + let i = (-127i8).numtoa(10, &mut buffer); + assert_eq!(&buffer[i..], b"-127"); +} + +#[test] +#[should_panic] +fn base10_i16_array_too_small() { + let mut buffer = [0u8; 5]; + let _ = 0i16.numtoa(10, &mut buffer); +} + +#[test] +fn base10_i16_array_just_right() { + let mut buffer = [0u8; 6]; + let i = (-12768i16).numtoa(10, &mut buffer); + assert_eq!(&buffer[i..], b"-12768"); +} + +#[test] +#[should_panic] +fn base10_u16_array_too_small() { + let mut buffer = [0u8; 4]; + let _ = 0u16.numtoa(10, &mut buffer); +} + +#[test] +fn base10_u16_array_just_right() { + let mut buffer = [0u8; 5]; + let _ = 0u16.numtoa(10, &mut buffer); +} + +#[test] +#[should_panic] +fn base10_i32_array_too_small() { + let mut buffer = [0u8; 10]; + let _ = 0i32.numtoa(10, &mut buffer); +} + +#[test] +fn base10_i32_array_just_right() { + let mut buffer = [0u8; 11]; + let _ = 0i32.numtoa(10, &mut buffer); +} + +#[test] +#[should_panic] +fn base10_u32_array_too_small() { + let mut buffer = [0u8; 9]; + let _ = 0u32.numtoa(10, &mut buffer); +} + +#[test] +fn base10_u32_array_just_right() { + let mut buffer = [0u8; 10]; + let _ = 0u32.numtoa(10, &mut buffer); +} + +#[test] +#[should_panic] +fn base10_i64_array_too_small() { + let mut buffer = [0u8; 19]; + let _ = 0i64.numtoa(10, &mut buffer); +} + +#[test] +fn base10_i64_array_just_right() { + let mut buffer = [0u8; 20]; + let _ = 0i64.numtoa(10, &mut buffer); +} + +#[test] +#[should_panic] +fn base10_u64_array_too_small() { + let mut buffer = [0u8; 19]; + let _ = 0u64.numtoa(10, &mut buffer); +} + +#[test] +fn base10_u64_array_just_right() { + let mut buffer = [0u8; 20]; + let _ = 0u64.numtoa(10, &mut buffer); +} + +#[test] +fn base8_min_signed_number() { + let mut buffer = [0u8; 30]; + let i = (-128i8).numtoa(8, &mut buffer); + assert_eq!(&buffer[i..], b"-200"); + + let i = (-32768i16).numtoa(8, &mut buffer); + assert_eq!(&buffer[i..], b"-100000"); + + let i = (-2147483648i32).numtoa(8, &mut buffer); + assert_eq!(&buffer[i..], b"-20000000000"); + + let i = (-9223372036854775808i64).numtoa(8, &mut buffer); + assert_eq!(&buffer[i..], b"-1000000000000000000000"); +} + +#[test] +fn base16_min_signed_number() { + let mut buffer = [0u8; 20]; + let i = (-128i8).numtoa(16, &mut buffer); + assert_eq!(&buffer[i..], b"-80"); + + let i = (-32768i16).numtoa(16, &mut buffer); + assert_eq!(&buffer[i..], b"-8000"); + + let i = (-2147483648i32).numtoa(16, &mut buffer); + assert_eq!(&buffer[i..], b"-80000000"); + + let i = (-9223372036854775808i64).numtoa(16, &mut buffer); + assert_eq!(&buffer[i..], b"-8000000000000000"); +} diff --git a/opener/.cargo-checksum.json b/opener/.cargo-checksum.json new file mode 100644 index 000000000..aa846c2e5 --- /dev/null +++ b/opener/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"04b1d6b086d9b3009550f9b6f81b10ad9428cf14f404b8e1a3a06f6f012c8ec9"} \ No newline at end of file diff --git a/opener/.pc/.quilt_patches b/opener/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/opener/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/opener/.pc/.quilt_series b/opener/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/opener/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/opener/.pc/.version b/opener/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/opener/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/opener/.pc/applied-patches b/opener/.pc/applied-patches new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/opener/.pc/applied-patches @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/opener/.pc/disable-vendor.patch/.timestamp b/opener/.pc/disable-vendor.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/opener/.pc/disable-vendor.patch/src/lib.rs b/opener/.pc/disable-vendor.patch/src/lib.rs new file mode 100644 index 000000000..56542a4d7 --- /dev/null +++ b/opener/.pc/disable-vendor.patch/src/lib.rs @@ -0,0 +1,212 @@ +//! This crate provides the [`open`] function, which opens a file or link with the default program +//! configured on the system. +//! +//! ```no_run +//! # fn main() -> Result<(), ::opener::OpenError> { +//! // open a website +//! opener::open("https://www.rust-lang.org")?; +//! +//! // open a file +//! opener::open("../Cargo.toml")?; +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Platform Implementation Details +//! On Windows the `ShellExecuteW` Windows API function is used. On Mac the system `open` command is +//! used. On other platforms, the `xdg-open` script is used. The system `xdg-open` is not used; +//! instead a version is embedded within this library. +extern crate failure; +#[macro_use] +extern crate failure_derive; + +#[cfg(target_os = "windows")] +extern crate winapi; + +#[cfg(target_os = "windows")] +use windows::open_sys; + +use std::{ + ffi::OsStr, + fmt::{self, Display, Formatter}, + io, + process::ExitStatus, +}; + +/// An error type representing the failure to open a path. Possibly returned by the [`open`] +/// function. +/// +/// The `ExitStatus` variant will never be returned on Windows. +#[derive(Debug, Fail)] +pub enum OpenError { + /// An IO error occurred. + #[cause] + Io(io::Error), + + /// The command exited with a non-zero exit status. + ExitStatus { + /// A string that identifies the command. + cmd: &'static str, + + /// The failed process's exit status. + status: ExitStatus, + + /// Anything the process wrote to stderr. + stderr: String, + }, +} + +impl Display for OpenError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + OpenError::Io(_) => { + write!(f, "IO error")?; + } + OpenError::ExitStatus { + cmd, + status, + stderr, + } => { + write!( + f, + "command '{}' did not execute successfully; {}", + cmd, status + )?; + + let stderr = stderr.trim(); + if !stderr.is_empty() { + write!(f, "\ncommand stderr:\n{}", stderr)?; + } + } + } + + Ok(()) + } +} + +impl From for OpenError { + fn from(err: io::Error) -> Self { + OpenError::Io(err) + } +} + +/// Opens a file or link with the system default program. +/// +/// Note that a path like "rustup.rs" could potentially refer to either a file or a website. If you +/// want to open the website, you should add the "http://" prefix, for example. +/// +/// Also note that a result of `Ok(())` just means a way of opening the path was found, and no error +/// occurred as a direct result of opening the path. Errors beyond that point aren't caught. For +/// example, `Ok(())` would be returned even if a file was opened with a program that can't read the +/// file, or a dead link was opened in a browser. +pub fn open

(path: P) -> Result<(), OpenError> +where + P: AsRef, +{ + open_sys(path.as_ref()) +} + +#[cfg(target_os = "windows")] +mod windows { + use super::OpenError; + use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr}; + use winapi::{ctypes::c_int, um::shellapi::ShellExecuteW}; + + pub fn open_sys(path: &OsStr) -> Result<(), OpenError> { + const SW_SHOW: c_int = 5; + + let path = convert_path(path)?; + let operation: Vec = OsStr::new("open\0").encode_wide().collect(); + let result = unsafe { + ShellExecuteW( + ptr::null_mut(), + operation.as_ptr(), + path.as_ptr(), + ptr::null(), + ptr::null(), + SW_SHOW, + ) + }; + if result as c_int > 32 { + Ok(()) + } else { + Err(io::Error::last_os_error().into()) + } + } + + fn convert_path(path: &OsStr) -> io::Result> { + let mut maybe_result: Vec = path.encode_wide().collect(); + if maybe_result.iter().any(|&u| u == 0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path contains NUL byte(s)", + )); + } + maybe_result.push(0); + Ok(maybe_result) + } +} + +#[cfg(target_os = "macos")] +fn open_sys(path: &OsStr) -> Result<(), OpenError> { + open_not_windows("open", path, &[], None, "open") +} + +#[cfg(not(any(target_os = "windows", target_os = "macos")))] +fn open_sys(path: &OsStr) -> Result<(), OpenError> { + const XDG_OPEN_SCRIPT: &[u8] = include_bytes!("xdg-open"); + + open_not_windows( + "sh", + path, + &["-s"], + Some(XDG_OPEN_SCRIPT), + "xdg-open (internal)", + ) +} + +#[cfg(not(target_os = "windows"))] +fn open_not_windows( + cmd: &str, + path: &OsStr, + extra_args: &[&str], + piped_input: Option<&[u8]>, + cmd_friendly_name: &'static str, +) -> Result<(), OpenError> { + use std::{ + io::{Read, Write}, + process::{Command, Stdio}, + }; + + let stdin_type = if piped_input.is_some() { + Stdio::piped() + } else { + Stdio::null() + }; + + let mut cmd = Command::new(cmd) + .args(extra_args) + .arg(path) + .stdin(stdin_type) + .stdout(Stdio::null()) + .stderr(Stdio::piped()) + .spawn()?; + + if let Some(stdin) = cmd.stdin.as_mut() { + stdin.write_all(piped_input.unwrap())?; + } + + let exit_status = cmd.wait()?; + if exit_status.success() { + Ok(()) + } else { + let mut stderr = String::new(); + cmd.stderr.as_mut().unwrap().read_to_string(&mut stderr)?; + + Err(OpenError::ExitStatus { + cmd: cmd_friendly_name, + status: exit_status, + stderr, + }) + } +} diff --git a/opener/Cargo.toml b/opener/Cargo.toml new file mode 100644 index 000000000..95e9c66b1 --- /dev/null +++ b/opener/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "opener" +version = "0.3.2" +authors = ["Brian Bowman "] +description = "Open a file or link using the system default program." +readme = "../README.md" +keywords = ["open", "default", "launcher", "browser"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/Seeker14491/opener" +[dependencies.failure] +version = "0.1.2" + +[dependencies.failure_derive] +version = "0.1.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["shellapi"] +[badges.appveyor] +branch = "master" +repository = "Seeker14491/opener" +service = "github" + +[badges.travis-ci] +branch = "master" +repository = "Seeker14491/opener" diff --git a/opener/LICENSE-APACHE b/opener/LICENSE-APACHE new file mode 100644 index 000000000..0bb4882b1 --- /dev/null +++ b/opener/LICENSE-APACHE @@ -0,0 +1,199 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/opener/LICENSE-MIT b/opener/LICENSE-MIT new file mode 100644 index 000000000..4174b30f9 --- /dev/null +++ b/opener/LICENSE-MIT @@ -0,0 +1,19 @@ +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/opener/LICENSE-THIRD-PARTY b/opener/LICENSE-THIRD-PARTY new file mode 100644 index 000000000..7bcc89ce3 --- /dev/null +++ b/opener/LICENSE-THIRD-PARTY @@ -0,0 +1,19 @@ +- xdg-utils: https://cgit.freedesktop.org/xdg/xdg-utils/plain/LICENSE + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + # + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + # + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/opener/debian/patches/disable-vendor.patch b/opener/debian/patches/disable-vendor.patch new file mode 100644 index 000000000..be8357c7d --- /dev/null +++ b/opener/debian/patches/disable-vendor.patch @@ -0,0 +1,30 @@ +--- opener/src/lib.rs 2018-11-14 20:19:39.517533843 -0800 ++++ opener/src/lib.rs 2018-11-14 20:21:18.918936155 -0800 +@@ -14,7 +14,7 @@ + //! + //! ## Platform Implementation Details + //! On Windows the `ShellExecuteW` Windows API function is used. On Mac the system `open` command is +-//! used. On other platforms, the `xdg-open` script is used. The system `xdg-open` is not used; ++//! used. On other platforms, the system `xdg-open` script is used. + //! instead a version is embedded within this library. + extern crate failure; + #[macro_use] +@@ -154,14 +154,12 @@ + + #[cfg(not(any(target_os = "windows", target_os = "macos")))] + fn open_sys(path: &OsStr) -> Result<(), OpenError> { +- const XDG_OPEN_SCRIPT: &[u8] = include_bytes!("xdg-open"); +- + open_not_windows( +- "sh", ++ "xdg-open", + path, +- &["-s"], +- Some(XDG_OPEN_SCRIPT), +- "xdg-open (internal)", ++ &[], ++ None, ++ "xdg-open", + ) + } + diff --git a/opener/debian/patches/series b/opener/debian/patches/series new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/opener/debian/patches/series @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/opener/src/lib.rs b/opener/src/lib.rs new file mode 100644 index 000000000..42f853752 --- /dev/null +++ b/opener/src/lib.rs @@ -0,0 +1,210 @@ +//! This crate provides the [`open`] function, which opens a file or link with the default program +//! configured on the system. +//! +//! ```no_run +//! # fn main() -> Result<(), ::opener::OpenError> { +//! // open a website +//! opener::open("https://www.rust-lang.org")?; +//! +//! // open a file +//! opener::open("../Cargo.toml")?; +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Platform Implementation Details +//! On Windows the `ShellExecuteW` Windows API function is used. On Mac the system `open` command is +//! used. On other platforms, the system `xdg-open` script is used. +//! instead a version is embedded within this library. +extern crate failure; +#[macro_use] +extern crate failure_derive; + +#[cfg(target_os = "windows")] +extern crate winapi; + +#[cfg(target_os = "windows")] +use windows::open_sys; + +use std::{ + ffi::OsStr, + fmt::{self, Display, Formatter}, + io, + process::ExitStatus, +}; + +/// An error type representing the failure to open a path. Possibly returned by the [`open`] +/// function. +/// +/// The `ExitStatus` variant will never be returned on Windows. +#[derive(Debug, Fail)] +pub enum OpenError { + /// An IO error occurred. + #[cause] + Io(io::Error), + + /// The command exited with a non-zero exit status. + ExitStatus { + /// A string that identifies the command. + cmd: &'static str, + + /// The failed process's exit status. + status: ExitStatus, + + /// Anything the process wrote to stderr. + stderr: String, + }, +} + +impl Display for OpenError { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + OpenError::Io(_) => { + write!(f, "IO error")?; + } + OpenError::ExitStatus { + cmd, + status, + stderr, + } => { + write!( + f, + "command '{}' did not execute successfully; {}", + cmd, status + )?; + + let stderr = stderr.trim(); + if !stderr.is_empty() { + write!(f, "\ncommand stderr:\n{}", stderr)?; + } + } + } + + Ok(()) + } +} + +impl From for OpenError { + fn from(err: io::Error) -> Self { + OpenError::Io(err) + } +} + +/// Opens a file or link with the system default program. +/// +/// Note that a path like "rustup.rs" could potentially refer to either a file or a website. If you +/// want to open the website, you should add the "http://" prefix, for example. +/// +/// Also note that a result of `Ok(())` just means a way of opening the path was found, and no error +/// occurred as a direct result of opening the path. Errors beyond that point aren't caught. For +/// example, `Ok(())` would be returned even if a file was opened with a program that can't read the +/// file, or a dead link was opened in a browser. +pub fn open

(path: P) -> Result<(), OpenError> +where + P: AsRef, +{ + open_sys(path.as_ref()) +} + +#[cfg(target_os = "windows")] +mod windows { + use super::OpenError; + use std::{ffi::OsStr, io, os::windows::ffi::OsStrExt, ptr}; + use winapi::{ctypes::c_int, um::shellapi::ShellExecuteW}; + + pub fn open_sys(path: &OsStr) -> Result<(), OpenError> { + const SW_SHOW: c_int = 5; + + let path = convert_path(path)?; + let operation: Vec = OsStr::new("open\0").encode_wide().collect(); + let result = unsafe { + ShellExecuteW( + ptr::null_mut(), + operation.as_ptr(), + path.as_ptr(), + ptr::null(), + ptr::null(), + SW_SHOW, + ) + }; + if result as c_int > 32 { + Ok(()) + } else { + Err(io::Error::last_os_error().into()) + } + } + + fn convert_path(path: &OsStr) -> io::Result> { + let mut maybe_result: Vec = path.encode_wide().collect(); + if maybe_result.iter().any(|&u| u == 0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path contains NUL byte(s)", + )); + } + maybe_result.push(0); + Ok(maybe_result) + } +} + +#[cfg(target_os = "macos")] +fn open_sys(path: &OsStr) -> Result<(), OpenError> { + open_not_windows("open", path, &[], None, "open") +} + +#[cfg(not(any(target_os = "windows", target_os = "macos")))] +fn open_sys(path: &OsStr) -> Result<(), OpenError> { + open_not_windows( + "xdg-open", + path, + &[], + None, + "xdg-open", + ) +} + +#[cfg(not(target_os = "windows"))] +fn open_not_windows( + cmd: &str, + path: &OsStr, + extra_args: &[&str], + piped_input: Option<&[u8]>, + cmd_friendly_name: &'static str, +) -> Result<(), OpenError> { + use std::{ + io::{Read, Write}, + process::{Command, Stdio}, + }; + + let stdin_type = if piped_input.is_some() { + Stdio::piped() + } else { + Stdio::null() + }; + + let mut cmd = Command::new(cmd) + .args(extra_args) + .arg(path) + .stdin(stdin_type) + .stdout(Stdio::null()) + .stderr(Stdio::piped()) + .spawn()?; + + if let Some(stdin) = cmd.stdin.as_mut() { + stdin.write_all(piped_input.unwrap())?; + } + + let exit_status = cmd.wait()?; + if exit_status.success() { + Ok(()) + } else { + let mut stderr = String::new(); + cmd.stderr.as_mut().unwrap().read_to_string(&mut stderr)?; + + Err(OpenError::ExitStatus { + cmd: cmd_friendly_name, + status: exit_status, + stderr, + }) + } +} diff --git a/openssl-probe/.cargo-checksum.json b/openssl-probe/.cargo-checksum.json new file mode 100644 index 000000000..57a82f5e1 --- /dev/null +++ b/openssl-probe/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"} \ No newline at end of file diff --git a/openssl-probe/Cargo.toml b/openssl-probe/Cargo.toml new file mode 100644 index 000000000..ab25540a5 --- /dev/null +++ b/openssl-probe/Cargo.toml @@ -0,0 +1,21 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "openssl-probe" +version = "0.1.2" +authors = ["Alex Crichton "] +description = "Tool for helping to find SSL certificate locations on the system for OpenSSL\n" +homepage = "https://github.com/alexcrichton/openssl-probe" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/openssl-probe" diff --git a/openssl-probe/LICENSE-APACHE b/openssl-probe/LICENSE-APACHE new file mode 100644 index 000000000..f47c94114 --- /dev/null +++ b/openssl-probe/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/openssl-probe/LICENSE-MIT b/openssl-probe/LICENSE-MIT new file mode 100644 index 000000000..a22128a47 --- /dev/null +++ b/openssl-probe/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/openssl-probe/README.md b/openssl-probe/README.md new file mode 100644 index 000000000..c692288d1 --- /dev/null +++ b/openssl-probe/README.md @@ -0,0 +1,33 @@ +# openssl-probe + +Tool for helping to find SSL certificate locations on the system for OpenSSL + +[![Crates.io](https://img.shields.io/crates/v/openssl-probe.svg?maxAge=2592000)](https://crates.io/crates/openssl-probe) +[![docs.rs](https://docs.rs/openssl-probe/badge.svg)](https://docs.rs/openssl-probe/) + +## Usage + +First, add this to your `Cargo.toml`: + +```toml +[dependencies] +openssl-probe = "0.1.2" +``` + +Then add this to your crate: + +```rust +extern crate openssl_probe; + +fn main() { + openssl_probe::init_ssl_cert_env_vars(); + //... your code +} +``` + +## License + +`openssl-probe` is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), +with portions covered by various BSD-like licenses. + +See [LICENSE-APACHE](./LICENSE-APACHE), and [LICENSE-MIT](LICENSE-MIT) for details. diff --git a/openssl-probe/src/lib.rs b/openssl-probe/src/lib.rs new file mode 100644 index 000000000..513fdff36 --- /dev/null +++ b/openssl-probe/src/lib.rs @@ -0,0 +1,83 @@ +use std::env; +use std::fs; +use std::path::PathBuf; + +pub struct ProbeResult { + pub cert_file: Option, + pub cert_dir: Option, +} + +/// Probe the system for the directory in which CA certificates should likely be +/// found. +/// +/// This will only search known system locations. +pub fn find_certs_dirs() -> Vec { + // see http://gagravarr.org/writing/openssl-certs/others.shtml + [ + "/var/ssl", + "/usr/share/ssl", + "/usr/local/ssl", + "/usr/local/openssl", + "/usr/local/share", + "/usr/lib/ssl", + "/usr/ssl", + "/etc/openssl", + "/etc/pki/ca-trust/extracted/pem", + "/etc/pki/tls", + "/etc/ssl", + "/data/data/com.termux/files/usr/etc/tls", + "/boot/system/data/ssl", + ].iter().map(|s| PathBuf::from(*s)).filter(|p| { + fs::metadata(p).is_ok() + }).collect() +} + +pub fn init_ssl_cert_env_vars() { + let ProbeResult { cert_file, cert_dir } = probe(); + match cert_file { + Some(path) => put("SSL_CERT_FILE", path), + None => {} + } + match cert_dir { + Some(path) => put("SSL_CERT_DIR", path), + None => {} + } + + fn put(var: &str, path: PathBuf) { + // Don't stomp over what anyone else has set + match env::var(var) { + Ok(..) => {} + Err(..) => env::set_var(var, &path), + } + } +} + +pub fn probe() -> ProbeResult { + let mut result = ProbeResult { + cert_file: env::var_os("SSL_CERT_FILE").map(PathBuf::from), + cert_dir: env::var_os("SSL_CERT_DIR").map(PathBuf::from), + }; + for certs_dir in find_certs_dirs().iter() { + // cert.pem looks to be an openssl 1.0.1 thing, while + // certs/ca-certificates.crt appears to be a 0.9.8 thing + for cert in [ + "cert.pem", + "certs.pem", + "certs/ca-certificates.crt", + "certs/ca-root-nss.crt", + "certs/ca-bundle.crt", + "CARootCertificates.pem", + "tls-ca-bundle.pem", + ].iter() { + try(&mut result.cert_file, certs_dir.join(cert)); + } + try(&mut result.cert_dir, certs_dir.join("certs")); + } + result +} + +fn try(dst: &mut Option, val: PathBuf) { + if dst.is_none() && fs::metadata(&val).is_ok() { + *dst = Some(val); + } +} diff --git a/openssl-sys/.cargo-checksum.json b/openssl-sys/.cargo-checksum.json new file mode 100644 index 000000000..7d8182514 --- /dev/null +++ b/openssl-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"75bdd6dbbb4958d38e47a1d2348847ad1eb4dc205dc5d37473ae504391865acc"} \ No newline at end of file diff --git a/openssl-sys/.pc/.quilt_patches b/openssl-sys/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/openssl-sys/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/openssl-sys/.pc/.quilt_series b/openssl-sys/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/openssl-sys/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/openssl-sys/.pc/.version b/openssl-sys/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/openssl-sys/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/openssl-sys/.pc/applied-patches b/openssl-sys/.pc/applied-patches new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/openssl-sys/.pc/applied-patches @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/openssl-sys/.pc/disable-vendor.patch/.timestamp b/openssl-sys/.pc/disable-vendor.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/openssl-sys/.pc/disable-vendor.patch/Cargo.toml b/openssl-sys/.pc/disable-vendor.patch/Cargo.toml new file mode 100644 index 000000000..1c5df98be --- /dev/null +++ b/openssl-sys/.pc/disable-vendor.patch/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "openssl-sys" +version = "0.9.47" +authors = ["Alex Crichton ", "Steven Fackler "] +build = "build/main.rs" +links = "openssl" +description = "FFI bindings to OpenSSL" +readme = "README.md" +categories = ["cryptography", "external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/sfackler/rust-openssl" +[package.metadata.pkg-config] +openssl = "1.0.1" +[dependencies.libc] +version = "0.2" +[build-dependencies.autocfg] +version = "0.1.2" + +[build-dependencies.cc] +version = "1.0" + +[build-dependencies.openssl-src] +version = "111.0.1" +optional = true + +[build-dependencies.pkg-config] +version = "0.3.9" + +[features] +vendored = ["openssl-src"] +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" diff --git a/openssl-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md new file mode 100644 index 000000000..352dd5a28 --- /dev/null +++ b/openssl-sys/CHANGELOG.md @@ -0,0 +1,48 @@ +# Change Log + +## [Unreleased] + +## [v0.9.47] - 2019-05-18 + +### Added + +* Added `SSL_CTX_add_client_CA`. + +## [v0.9.46] - 2019-05-08 + +### Added + +* Added support for the LibreSSL 2.9.x series. + +## [v0.9.45] - 2019-05-03 + +### Fixed + +* Reverted a change to windows-gnu library names that caused regressions. + +## [v0.9.44] - 2019-04-30 + +### Added + +* The `DEP_OPENSSL_VENDORED` environment variable tells downstream build scripts if the vendored feature was enabled. +* Added `EVP_SealInit`, `EVP_SealFinal`, `EVP_EncryptUpdate`, `EVP_OpenInit`, `EVP_OpenFinal`, and `EVP_DecryptUpdate`. +* Added `EVP_PKEY_size`. + +### Fixed + +* Fixed library names when targeting windows-gnu and pkg-config fails. + +## [v0.9.43] - 2019-03-20 + +### Added + +* Added `d2i_CMS_ContentInfo` and `CMS_encrypt`. +* Added `X509_verify` and `X509_REQ_verify`. +* Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`. + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.47...master +[v0.9.47]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.46...openssl-sys-v0.9.47 +[v0.9.46]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.45...openssl-sys-v0.9.46 +[v0.9.45]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.44...openssl-sys-v0.9.45 +[v0.9.44]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.43...openssl-sys-v0.9.44 +[v0.9.43]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.42...openssl-sys-v0.9.43 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml new file mode 100644 index 000000000..420460c54 --- /dev/null +++ b/openssl-sys/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "openssl-sys" +version = "0.9.47" +authors = ["Alex Crichton ", "Steven Fackler "] +build = "build/main.rs" +links = "openssl" +description = "FFI bindings to OpenSSL" +readme = "README.md" +categories = ["cryptography", "external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/sfackler/rust-openssl" +[package.metadata.pkg-config] +openssl = "1.0.1" +[dependencies.libc] +version = "0.2" +[build-dependencies.autocfg] +version = "0.1.2" + +[build-dependencies.cc] +version = "1.0" + +[build-dependencies.pkg-config] +version = "0.3.9" + +[features] +vendored = ["openssl-src"] +openssl-src = [] +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" diff --git a/openssl-sys/LICENSE-MIT b/openssl-sys/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/openssl-sys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/openssl-sys/README.md b/openssl-sys/README.md new file mode 100644 index 000000000..2c37c0f78 --- /dev/null +++ b/openssl-sys/README.md @@ -0,0 +1,24 @@ +# rust-openssl + +[![CircleCI](https://circleci.com/gh/sfackler/rust-openssl.svg?style=shield)](https://circleci.com/gh/sfackler/rust-openssl) +[![Build status](https://ci.appveyor.com/api/projects/status/d1knobws948pyynk/branch/master?svg=true)](https://ci.appveyor.com/project/sfackler/rust-openssl/branch/master) +[![crates.io](https://img.shields.io/crates/v/openssl.svg)](https://crates.io/crates/openssl) + +OpenSSL bindings for the Rust programming language. + +[Documentation](https://docs.rs/openssl). + +## Release Support + +The current supported release is 0.10. + +New major versions will be published at most once per year. After a new +release, the previous major version will be partially supported with bug +fixes for 3 months, after which support will be dropped entirely. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed under the terms of both the Apache License, +Version 2.0 and the MIT license without any additional terms or conditions. diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs new file mode 100644 index 000000000..c74c2bb0d --- /dev/null +++ b/openssl-sys/build/cfgs.rs @@ -0,0 +1,64 @@ +pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { + let mut cfgs = vec![]; + + if let Some(libressl_version) = libressl_version { + cfgs.push("libressl"); + + if libressl_version >= 0x2_05_01_00_0 { + cfgs.push("libressl251"); + } + if libressl_version >= 0x2_06_01_00_0 { + cfgs.push("libressl261"); + } + if libressl_version >= 0x2_07_00_00_0 { + cfgs.push("libressl270"); + } + if libressl_version >= 0x2_07_01_00_0 { + cfgs.push("libressl271"); + } + if libressl_version >= 0x2_07_03_00_0 { + cfgs.push("libressl273"); + } + if libressl_version >= 0x2_08_00_00_0 { + cfgs.push("libressl280"); + } + if libressl_version >= 0x2_08_01_00_0 { + cfgs.push("libressl281"); + } + if libressl_version >= 0x2_09_01_00_0 { + cfgs.push("libressl291"); + } + } else { + let openssl_version = openssl_version.unwrap(); + + if openssl_version >= 0x1_00_01_00_0 { + cfgs.push("ossl101"); + } + if openssl_version >= 0x1_00_02_00_0 { + cfgs.push("ossl102"); + } + if openssl_version >= 0x1_00_02_06_0 { + cfgs.push("ossl102f"); + } + if openssl_version >= 0x1_00_02_08_0 { + cfgs.push("ossl102h"); + } + if openssl_version >= 0x1_01_00_00_0 { + cfgs.push("ossl110"); + } + if openssl_version >= 0x1_01_00_06_0 { + cfgs.push("ossl110f"); + } + if openssl_version >= 0x1_01_00_07_0 { + cfgs.push("ossl110g"); + } + if openssl_version >= 0x1_01_01_00_0 { + cfgs.push("ossl111"); + } + if openssl_version >= 0x1_01_01_02_0 { + cfgs.push("ossl111b"); + } + } + + cfgs +} diff --git a/openssl-sys/build/expando.c b/openssl-sys/build/expando.c new file mode 100644 index 000000000..c8bfac879 --- /dev/null +++ b/openssl-sys/build/expando.c @@ -0,0 +1,67 @@ +#include +#include + +#define VERSION2(n, v) RUST_VERSION_##n##_##v +#define VERSION(n, v) VERSION2(n, v) + +#ifdef LIBRESSL_VERSION_NUMBER +VERSION(LIBRESSL, LIBRESSL_VERSION_NUMBER) +#else +VERSION(OPENSSL, OPENSSL_VERSION_NUMBER) +#endif + +#ifdef OPENSSL_NO_BUF_FREELISTS +RUST_CONF_OPENSSL_NO_BUF_FREELISTS +#endif + +#ifdef OPENSSL_NO_COMP +RUST_CONF_OPENSSL_NO_COMP +#endif + +#ifdef OPENSSL_NO_EC +RUST_CONF_OPENSSL_NO_EC +#endif + +#ifdef OPENSSL_NO_EC2M +RUST_CONF_OPENSSL_NO_EC2M +#endif + +#ifdef OPENSSL_NO_ENGINE +RUST_CONF_OPENSSL_NO_ENGINE +#endif + +#ifdef OPENSSL_NO_KRB5 +RUST_CONF_OPENSSL_NO_KRB5 +#endif + +#ifdef OPENSSL_NO_NEXTPROTONEG +RUST_CONF_OPENSSL_NO_NEXTPROTONEG +#endif + +#ifdef OPENSSL_NO_PSK +RUST_CONF_OPENSSL_NO_PSK +#endif + +#ifdef OPENSSL_NO_RFC3779 +RUST_CONF_OPENSSL_NO_RFC3779 +#endif + +#ifdef OPENSSL_NO_SHA +RUST_CONF_OPENSSL_NO_SHA +#endif + +#ifdef OPENSSL_NO_SRP +RUST_CONF_OPENSSL_NO_SRP +#endif + +#ifdef OPENSSL_NO_SSL3_METHOD +RUST_CONF_OPENSSL_NO_SSL3_METHOD +#endif + +#ifdef OPENSSL_NO_TLSEXT +RUST_CONF_OPENSSL_NO_TLSEXT +#endif + +#ifdef OPENSSL_NO_STDIO +RUST_CONF_OPENSSL_NO_STDIO +#endif diff --git a/openssl-sys/build/find_normal.rs b/openssl-sys/build/find_normal.rs new file mode 100644 index 000000000..4338fcefa --- /dev/null +++ b/openssl-sys/build/find_normal.rs @@ -0,0 +1,251 @@ +use pkg_config; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::process::{self, Command}; + +use super::env; + +pub fn get_openssl(target: &str) -> (PathBuf, PathBuf) { + let lib_dir = env("OPENSSL_LIB_DIR").map(PathBuf::from); + let include_dir = env("OPENSSL_INCLUDE_DIR").map(PathBuf::from); + + if lib_dir.is_none() || include_dir.is_none() { + let openssl_dir = env("OPENSSL_DIR").unwrap_or_else(|| find_openssl_dir(&target)); + let openssl_dir = Path::new(&openssl_dir); + let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib")); + let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include")); + (lib_dir, include_dir) + } else { + (lib_dir.unwrap(), include_dir.unwrap()) + } +} + +fn find_openssl_dir(target: &str) -> OsString { + let host = env::var("HOST").unwrap(); + + if host == target && target.contains("apple-darwin") { + // Check up default Homebrew installation location first + // for quick resolution if possible. + let homebrew = Path::new("/usr/local/opt/openssl@1.1"); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + let homebrew = Path::new("/usr/local/opt/openssl"); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + // Calling `brew --prefix ` command usually slow and + // takes seconds, and will be used only as a last resort. + let output = execute_command_and_get_output("brew", &["--prefix", "openssl@1.1"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } + let output = execute_command_and_get_output("brew", &["--prefix", "openssl"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } + } + + try_pkg_config(); + try_vcpkg(); + + // FreeBSD ships with OpenSSL but doesn't include a pkg-config file :( + if host == target && target.contains("freebsd") { + return OsString::from("/usr"); + } + + let mut msg = format!( + " + +Could not find directory of OpenSSL installation, and this `-sys` crate cannot +proceed without this knowledge. If OpenSSL is installed and this crate had +trouble finding it, you can set the `OPENSSL_DIR` environment variable for the +compilation process. + +Make sure you also have the development packages of openssl installed. +For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora. + +If you're in a situation where you think the directory *should* be found +automatically, please open a bug at https://github.com/sfackler/rust-openssl +and include information about your system as well as this message. + +$HOST = {} +$TARGET = {} +openssl-sys = {} + +", + host, + target, + env!("CARGO_PKG_VERSION") + ); + + if host.contains("apple-darwin") && target.contains("apple-darwin") { + let system = Path::new("/usr/lib/libssl.0.9.8.dylib"); + if system.exists() { + msg.push_str(&format!( + " + +It looks like you're compiling on macOS, where the system contains a version of +OpenSSL 0.9.8. This crate no longer supports OpenSSL 0.9.8. + +As a consumer of this crate, you can fix this error by using Homebrew to +install the `openssl` package, or as a maintainer you can use the openssl-sys +0.7 crate for support with OpenSSL 0.9.8. + +Unfortunately though the compile cannot continue, so aborting. + +" + )); + } + } + + if host.contains("unknown-linux") && target.contains("unknown-linux-gnu") { + if Command::new("pkg-config").output().is_err() { + msg.push_str(&format!( + " +It looks like you're compiling on Linux and also targeting Linux. Currently this +requires the `pkg-config` utility to find OpenSSL but unfortunately `pkg-config` +could not be found. If you have OpenSSL installed you can likely fix this by +installing `pkg-config`. + +" + )); + } + } + + if host.contains("windows") && target.contains("windows-gnu") { + msg.push_str(&format!( + " +It looks like you're compiling for MinGW but you may not have either OpenSSL or +pkg-config installed. You can install these two dependencies with: + +pacman -S openssl-devel pkg-config + +and try building this crate again. + +" + )); + } + + if host.contains("windows") && target.contains("windows-msvc") { + msg.push_str(&format!( + " +It looks like you're compiling for MSVC but we couldn't detect an OpenSSL +installation. If there isn't one installed then you can try the rust-openssl +README for more information about how to download precompiled binaries of +OpenSSL: + +https://github.com/sfackler/rust-openssl#windows + +" + )); + } + + panic!(msg); +} + +/// Attempt to find OpenSSL through pkg-config. +/// +/// Note that if this succeeds then the function does not return as pkg-config +/// typically tells us all the information that we need. +fn try_pkg_config() { + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + + // If we're going to windows-gnu we can use pkg-config, but only so long as + // we're coming from a windows host. + // + // Otherwise if we're going to windows we probably can't use pkg-config. + if target.contains("windows-gnu") && host.contains("windows") { + env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); + } else if target.contains("windows") { + return; + } + + let lib = match pkg_config::Config::new() + .print_system_libs(false) + .find("openssl") + { + Ok(lib) => lib, + Err(e) => { + println!("run pkg_config fail: {:?}", e); + return; + } + }; + + super::validate_headers(&lib.include_paths); + + for include in lib.include_paths.iter() { + println!("cargo:include={}", include.display()); + } + + process::exit(0); +} + +/// Attempt to find OpenSSL through vcpkg. +/// +/// Note that if this succeeds then the function does not return as vcpkg +/// should emit all of the cargo metadata that we need. +#[cfg(target_env = "msvc")] +fn try_vcpkg() { + use vcpkg; + + // vcpkg will not emit any metadata if it can not find libraries + // appropriate for the target triple with the desired linkage. + + let mut lib = vcpkg::Config::new() + .emit_includes(true) + .lib_name("libcrypto") + .lib_name("libssl") + .probe("openssl"); + + if let Err(e) = lib { + println!( + "note: vcpkg did not find openssl as libcrypto and libssl: {}", + e + ); + lib = vcpkg::Config::new() + .emit_includes(true) + .lib_name("libeay32") + .lib_name("ssleay32") + .probe("openssl"); + } + if let Err(e) = lib { + println!( + "note: vcpkg did not find openssl as ssleay32 and libeay32: {}", + e + ); + return; + } + + let lib = lib.unwrap(); + super::validate_headers(&lib.include_paths); + + println!("cargo:rustc-link-lib=user32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=crypt32"); + + process::exit(0); +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() {} + +fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { + let out = Command::new(cmd).args(args).output(); + if let Ok(ref r1) = out { + if r1.status.success() { + let r2 = String::from_utf8(r1.stdout.clone()); + if let Ok(r3) = r2 { + return Some(r3.trim().to_string()); + } + } + } + return None; +} diff --git a/openssl-sys/build/find_vendored.rs b/openssl-sys/build/find_vendored.rs new file mode 100644 index 000000000..bd5fbfb05 --- /dev/null +++ b/openssl-sys/build/find_vendored.rs @@ -0,0 +1,11 @@ +use openssl_src; +use std::path::PathBuf; + +pub fn get_openssl(_target: &str) -> (PathBuf, PathBuf) { + let artifacts = openssl_src::Build::new().build(); + println!("cargo:vendored=1"); + ( + artifacts.lib_dir().to_path_buf(), + artifacts.include_dir().to_path_buf(), + ) +} diff --git a/openssl-sys/build/main.rs b/openssl-sys/build/main.rs new file mode 100644 index 000000000..7f803a5b3 --- /dev/null +++ b/openssl-sys/build/main.rs @@ -0,0 +1,312 @@ +extern crate cc; +#[cfg(feature = "vendored")] +extern crate openssl_src; +extern crate pkg_config; +extern crate autocfg; +#[cfg(target_env = "msvc")] +extern crate vcpkg; + +use std::collections::HashSet; +use std::env; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; + +mod cfgs; + +#[cfg_attr(feature = "vendored", path = "find_vendored.rs")] +#[cfg_attr(not(feature = "vendored"), path = "find_normal.rs")] +mod find; + +enum Version { + Openssl11x, + Openssl10x, + Libressl, +} + +fn env_inner(name: &str) -> Option { + let var = env::var_os(name); + println!("cargo:rerun-if-env-changed={}", name); + + match var { + Some(ref v) => println!("{} = {}", name, v.to_string_lossy()), + None => println!("{} unset", name), + } + + var +} + +fn env(name: &str) -> Option { + let prefix = env::var("TARGET").unwrap().to_uppercase().replace("-", "_"); + let prefixed = format!("{}_{}", prefix, name); + env_inner(&prefixed).or_else(|| env_inner(name)) +} + +fn main() { + check_rustc_versions(); + + let target = env::var("TARGET").unwrap(); + + let (lib_dir, include_dir) = find::get_openssl(&target); + + if !Path::new(&lib_dir).exists() { + panic!( + "OpenSSL library directory does not exist: {}", + lib_dir.to_string_lossy() + ); + } + if !Path::new(&include_dir).exists() { + panic!( + "OpenSSL include directory does not exist: {}", + include_dir.to_string_lossy() + ); + } + + println!( + "cargo:rustc-link-search=native={}", + lib_dir.to_string_lossy() + ); + println!("cargo:include={}", include_dir.to_string_lossy()); + + let version = validate_headers(&[include_dir.clone().into()]); + + let libs_env = env("OPENSSL_LIBS"); + let libs = match libs_env.as_ref().and_then(|s| s.to_str()) { + Some(ref v) => v.split(":").collect(), + None => match version { + Version::Openssl10x if target.contains("windows") => vec!["ssleay32", "libeay32"], + Version::Openssl11x if target.contains("windows") => vec!["libssl", "libcrypto"], + _ => vec!["ssl", "crypto"], + }, + }; + + let kind = determine_mode(Path::new(&lib_dir), &libs); + for lib in libs.into_iter() { + println!("cargo:rustc-link-lib={}={}", kind, lib); + } + + if kind == "static" && target.contains("windows") { + println!("cargo:rustc-link-lib=dylib=gdi32"); + println!("cargo:rustc-link-lib=dylib=user32"); + println!("cargo:rustc-link-lib=dylib=crypt32"); + println!("cargo:rustc-link-lib=dylib=ws2_32"); + println!("cargo:rustc-link-lib=dylib=advapi32"); + } +} + +fn check_rustc_versions() { + let cfg = autocfg::new(); + + if cfg.probe_rustc_version(1, 31) { + println!("cargo:rustc-cfg=const_fn"); + } +} + +/// Validates the header files found in `include_dir` and then returns the +/// version string of OpenSSL. +fn validate_headers(include_dirs: &[PathBuf]) -> Version { + // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To + // correctly expose the right API from this crate, take a look at + // `opensslv.h` to see what version OpenSSL claims to be. + // + // OpenSSL has a number of build-time configuration options which affect + // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem + // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. + // + // To handle all this conditional compilation we slurp up the configuration + // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines + // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can + // account for compile differences and such. + let mut gcc = cc::Build::new(); + for include_dir in include_dirs { + gcc.include(include_dir); + } + let expanded = match gcc.file("build/expando.c").try_expand() { + Ok(expanded) => expanded, + Err(e) => { + panic!( + " +Header expansion error: +{:?} + +Failed to find OpenSSL development headers. + +You can try fixing this setting the `OPENSSL_DIR` environment variable +pointing to your OpenSSL installation or installing OpenSSL headers package +specific to your distribution: + + # On Ubuntu + sudo apt-get install libssl-dev + # On Arch Linux + sudo pacman -S openssl + # On Fedora + sudo dnf install openssl-devel + +See rust-openssl README for more information: + + https://github.com/sfackler/rust-openssl#linux +", + e + ); + } + }; + let expanded = String::from_utf8(expanded).unwrap(); + + let mut enabled = vec![]; + let mut openssl_version = None; + let mut libressl_version = None; + for line in expanded.lines() { + let line = line.trim(); + + let openssl_prefix = "RUST_VERSION_OPENSSL_"; + let libressl_prefix = "RUST_VERSION_LIBRESSL_"; + let conf_prefix = "RUST_CONF_"; + if line.starts_with(openssl_prefix) { + let version = &line[openssl_prefix.len()..]; + openssl_version = Some(parse_version(version)); + } else if line.starts_with(libressl_prefix) { + let version = &line[libressl_prefix.len()..]; + libressl_version = Some(parse_version(version)); + } else if line.starts_with(conf_prefix) { + enabled.push(&line[conf_prefix.len()..]); + } + } + + for enabled in &enabled { + println!("cargo:rustc-cfg=osslconf=\"{}\"", enabled); + } + println!("cargo:conf={}", enabled.join(",")); + + for cfg in cfgs::get(openssl_version, libressl_version) { + println!("cargo:rustc-cfg={}", cfg); + } + + if let Some(libressl_version) = libressl_version { + println!("cargo:libressl_version_number={:x}", libressl_version); + + let minor = (libressl_version >> 20) as u8; + let fix = (libressl_version >> 12) as u8; + let (minor, fix) = match (minor, fix) { + (5, 0) => ('5', '0'), + (5, 1) => ('5', '1'), + (5, 2) => ('5', '2'), + (5, _) => ('5', 'x'), + (6, 0) => ('6', '0'), + (6, 1) => ('6', '1'), + (6, 2) => ('6', '2'), + (6, _) => ('6', 'x'), + (7, _) => ('7', 'x'), + (8, 0) => ('8', '0'), + (8, 1) => ('8', '1'), + (8, _) => ('8', 'x'), + (9, 0) => ('9', '0'), + (9, _) => ('9', 'x'), + _ => version_error(), + }; + + println!("cargo:libressl=true"); + println!("cargo:libressl_version=2{}{}", minor, fix); + println!("cargo:version=101"); + Version::Libressl + } else { + let openssl_version = openssl_version.unwrap(); + println!("cargo:version_number={:x}", openssl_version); + + if openssl_version >= 0x1_01_02_00_0 { + version_error() + } else if openssl_version >= 0x1_01_01_00_0 { + println!("cargo:version=111"); + Version::Openssl11x + } else if openssl_version >= 0x1_01_00_06_0 { + println!("cargo:version=110"); + println!("cargo:patch=f"); + Version::Openssl11x + } else if openssl_version >= 0x1_01_00_00_0 { + println!("cargo:version=110"); + Version::Openssl11x + } else if openssl_version >= 0x1_00_02_00_0 { + println!("cargo:version=102"); + Version::Openssl10x + } else if openssl_version >= 0x1_00_01_00_0 { + println!("cargo:version=101"); + Version::Openssl10x + } else { + version_error() + } + } +} + +fn version_error() -> ! { + panic!( + " + +This crate is only compatible with OpenSSL 1.0.1 through 1.1.1, or LibreSSL 2.5 +through 2.9.x, but a different version of OpenSSL was found. The build is now aborting +due to this version mismatch. + +" + ); +} + +// parses a string that looks like "0x100020cfL" +#[allow(deprecated)] // trim_right_matches is now trim_end_matches +fn parse_version(version: &str) -> u64 { + // cut off the 0x prefix + assert!(version.starts_with("0x")); + let version = &version[2..]; + + // and the type specifier suffix + let version = version.trim_right_matches(|c: char| match c { + '0'...'9' | 'a'...'f' | 'A'...'F' => false, + _ => true, + }); + + u64::from_str_radix(version, 16).unwrap() +} + +/// Given a libdir for OpenSSL (where artifacts are located) as well as the name +/// of the libraries we're linking to, figure out whether we should link them +/// statically or dynamically. +fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { + // First see if a mode was explicitly requested + let kind = env("OPENSSL_STATIC"); + match kind.as_ref().and_then(|s| s.to_str()).map(|s| &s[..]) { + Some("0") => return "dylib", + Some(_) => return "static", + None => {} + } + + // Next, see what files we actually have to link against, and see what our + // possibilities even are. + let files = libdir + .read_dir() + .unwrap() + .map(|e| e.unwrap()) + .map(|e| e.file_name()) + .filter_map(|e| e.into_string().ok()) + .collect::>(); + let can_static = libs + .iter() + .all(|l| files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l))); + let can_dylib = libs.iter().all(|l| { + files.contains(&format!("lib{}.so", l)) + || files.contains(&format!("{}.dll", l)) + || files.contains(&format!("lib{}.dylib", l)) + }); + match (can_static, can_dylib) { + (true, false) => return "static", + (false, true) => return "dylib", + (false, false) => { + panic!( + "OpenSSL libdir at `{}` does not contain the required files \ + to either statically or dynamically link OpenSSL", + libdir.display() + ); + } + (true, true) => {} + } + + // Ok, we've got not explicit preference and can *either* link statically or + // link dynamically. In the interest of "security upgrades" and/or "best + // practices with security libs", let's link dynamically. + "dylib" +} diff --git a/openssl-sys/debian/patches/disable-vendor.patch b/openssl-sys/debian/patches/disable-vendor.patch new file mode 100644 index 000000000..45a0d3699 --- /dev/null +++ b/openssl-sys/debian/patches/disable-vendor.patch @@ -0,0 +1,18 @@ +--- a/Cargo.toml 2018-09-03 21:17:45.506177066 -0700 ++++ b/Cargo.toml 2018-09-03 21:18:00.573513575 -0700 +@@ -28,14 +28,11 @@ + [build-dependencies.cc] + version = "1.0" + +-[build-dependencies.openssl-src] +-version = "111.0.1" +-optional = true +- + [build-dependencies.pkg-config] + version = "0.3.9" + + [features] + vendored = ["openssl-src"] ++openssl-src = [] + [target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] + version = "0.2" diff --git a/openssl-sys/debian/patches/series b/openssl-sys/debian/patches/series new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/openssl-sys/debian/patches/series @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/openssl-sys/src/aes.rs b/openssl-sys/src/aes.rs new file mode 100644 index 000000000..cbb289c61 --- /dev/null +++ b/openssl-sys/src/aes.rs @@ -0,0 +1,28 @@ +use libc::*; + +pub const AES_ENCRYPT: c_int = 1; +pub const AES_DECRYPT: c_int = 0; + +pub const AES_MAXNR: c_int = 14; +pub const AES_BLOCK_SIZE: c_int = 16; + +#[repr(C)] +pub struct AES_KEY { + // There is some business with AES_LONG which is there to ensure the values here are 32 bits + rd_key: [u32; 4 * (AES_MAXNR as usize + 1)], + rounds: c_int, +} + +extern "C" { + pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + + pub fn AES_ige_encrypt( + in_: *const c_uchar, + out: *mut c_uchar, + length: size_t, + key: *const AES_KEY, + ivec: *mut c_uchar, + enc: c_int, + ); +} diff --git a/openssl-sys/src/asn1.rs b/openssl-sys/src/asn1.rs new file mode 100644 index 000000000..042b3eca8 --- /dev/null +++ b/openssl-sys/src/asn1.rs @@ -0,0 +1,66 @@ +use libc::*; + +use *; + +pub const V_ASN1_UTCTIME: c_int = 23; +pub const V_ASN1_GENERALIZEDTIME: c_int = 24; + +pub const MBSTRING_FLAG: c_int = 0x1000; +pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; +pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; +pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; +pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; + +#[repr(C)] +pub struct ASN1_ENCODING { + pub enc: *mut c_uchar, + pub len: c_long, + pub modified: c_int, +} + +extern "C" { + pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); +} + +stack!(stack_st_ASN1_OBJECT); + +extern "C" { + pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; + #[cfg(any(ossl110, libressl273))] + pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; + #[cfg(any(all(ossl101, not(ossl110)), libressl))] + pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; + + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + + pub fn ASN1_STRING_free(x: *mut ASN1_STRING); + pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + + pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); + pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; + pub fn ASN1_TIME_new() -> *mut ASN1_TIME; + pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); + pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; + + pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); + pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; + pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn BN_to_ASN1_INTEGER(bn: *const BIGNUM, ai: *mut ASN1_INTEGER) -> *mut ASN1_INTEGER; + pub fn ASN1_INTEGER_to_BN(ai: *const ASN1_INTEGER, bn: *mut BIGNUM) -> *mut BIGNUM; + + pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + #[cfg(ossl111)] + pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *const ASN1_STRING) -> c_int; + } + } else { + extern "C" { + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ASN1_STRING) -> c_int; + } + } +} diff --git a/openssl-sys/src/bio.rs b/openssl-sys/src/bio.rs new file mode 100644 index 000000000..e2bfbc0c4 --- /dev/null +++ b/openssl-sys/src/bio.rs @@ -0,0 +1,151 @@ +use libc::*; + +use *; + +pub const BIO_TYPE_NONE: c_int = 0; + +pub const BIO_CTRL_EOF: c_int = 2; +pub const BIO_CTRL_INFO: c_int = 3; +pub const BIO_CTRL_FLUSH: c_int = 11; +pub const BIO_C_SET_BUF_MEM_EOF_RETURN: c_int = 130; + +extern "C" { + pub fn BIO_set_flags(b: *mut BIO, flags: c_int); + pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); +} + +pub unsafe fn BIO_set_retry_read(b: *mut BIO) { + BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY) +} + +pub unsafe fn BIO_set_retry_write(b: *mut BIO) { + BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) +} + +pub unsafe fn BIO_clear_retry_flags(b: *mut BIO) { + BIO_clear_flags(b, BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY) +} + +pub const BIO_FLAGS_READ: c_int = 0x01; +pub const BIO_FLAGS_WRITE: c_int = 0x02; +pub const BIO_FLAGS_IO_SPECIAL: c_int = 0x04; +pub const BIO_FLAGS_RWS: c_int = BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL; +pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08; + +pub type bio_info_cb = + Option; + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum BIO_METHOD {} + } else { + #[repr(C)] + pub struct BIO_METHOD { + pub type_: c_int, + pub name: *const c_char, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, + } + } +} + +pub unsafe fn BIO_get_mem_data(b: *mut BIO, pp: *mut *mut c_char) -> c_long { + BIO_ctrl(b, BIO_CTRL_INFO, 0, pp as *mut c_void) +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn BIO_s_file() -> *const BIO_METHOD; + pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; + } + } else { + extern "C" { + pub fn BIO_s_file() -> *mut BIO_METHOD; + pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; + } + } +} +extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_STDIO"))] + pub fn BIO_new_fp(stream: *mut FILE, close_flag: c_int) -> *mut BIO; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_set_data(a: *mut ::BIO, data: *mut c_void); + #[cfg(any(ossl110, libressl273))] + pub fn BIO_get_data(a: *mut ::BIO) -> *mut c_void; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_set_init(a: *mut ::BIO, init: c_int); + pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; + pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; + pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn BIO_free_all(b: *mut BIO); +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn BIO_s_mem() -> *const BIO_METHOD; + } + } else { + extern "C" { + pub fn BIO_s_mem() -> *mut BIO_METHOD; + } + } +} +cfg_if! { + if #[cfg(any(ossl102, libressl280))] { + extern "C" { + pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; + } + } else { + extern "C" { + pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; + } + } +} + +extern "C" { + pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; + + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_new(type_: c_int, name: *const c_char) -> *mut BIO_METHOD; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_free(biom: *mut BIO_METHOD); + // FIXME should wrap in Option + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_write( + biom: *mut BIO_METHOD, + write: unsafe extern "C" fn(*mut BIO, *const c_char, c_int) -> c_int, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_read( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, *mut c_char, c_int) -> c_int, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_puts( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, *const c_char) -> c_int, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_ctrl( + biom: *mut BIO_METHOD, + read: unsafe extern "C" fn(*mut BIO, c_int, c_long, *mut c_void) -> c_long, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_create( + biom: *mut BIO_METHOD, + create: unsafe extern "C" fn(*mut BIO) -> c_int, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn BIO_meth_set_destroy( + biom: *mut BIO_METHOD, + destroy: unsafe extern "C" fn(*mut BIO) -> c_int, + ) -> c_int; +} diff --git a/openssl-sys/src/bn.rs b/openssl-sys/src/bn.rs new file mode 100644 index 000000000..59c1e7f1b --- /dev/null +++ b/openssl-sys/src/bn.rs @@ -0,0 +1,160 @@ +use libc::*; + +use *; + +#[cfg(target_pointer_width = "64")] +pub type BN_ULONG = c_ulonglong; +#[cfg(target_pointer_width = "32")] +pub type BN_ULONG = c_uint; + +extern "C" { + pub fn BN_CTX_new() -> *mut BN_CTX; + pub fn BN_CTX_free(ctx: *mut BN_CTX); + pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + pub fn BN_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *const BIGNUM) -> c_int; + pub fn BN_new() -> *mut BIGNUM; + pub fn BN_num_bits(bn: *const BIGNUM) -> c_int; + pub fn BN_clear_free(bn: *mut BIGNUM); + pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; + pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_mul(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_sqr(r: *mut BIGNUM, a: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); + #[cfg(ossl110)] + pub fn BN_is_negative(b: *const ::BIGNUM) -> c_int; + + pub fn BN_div( + dv: *mut BIGNUM, + rem: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_nnmod( + rem: *mut BIGNUM, + a: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_add( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_sub( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_mul( + r: *mut BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + pub fn BN_mod_sqr( + r: *mut BIGNUM, + a: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn BN_mod_word(r: *const BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_div_word(r: *mut BIGNUM, w: BN_ULONG) -> BN_ULONG; + pub fn BN_mul_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_add_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_sub_word(r: *mut BIGNUM, w: BN_ULONG) -> c_int; + pub fn BN_set_word(bn: *mut BIGNUM, n: BN_ULONG) -> c_int; + + pub fn BN_cmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_free(bn: *mut BIGNUM); + pub fn BN_is_bit_set(a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; + pub fn BN_exp(r: *mut BIGNUM, a: *const BIGNUM, p: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + + pub fn BN_mod_exp( + r: *mut BIGNUM, + a: *const BIGNUM, + p: *const BIGNUM, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift(r: *mut BIGNUM, a: *const BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift1(r: *mut BIGNUM, a: *const BIGNUM) -> c_int; + pub fn BN_bn2hex(a: *const BIGNUM) -> *mut c_char; + pub fn BN_bn2dec(a: *const BIGNUM) -> *mut c_char; + pub fn BN_hex2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_dec2bn(a: *mut *mut BIGNUM, s: *const c_char) -> c_int; + pub fn BN_gcd(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_inverse( + r: *mut BIGNUM, + a: *const BIGNUM, + n: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut BIGNUM; + pub fn BN_clear(bn: *mut BIGNUM); + pub fn BN_dup(n: *const BIGNUM) -> *mut BIGNUM; + pub fn BN_ucmp(a: *const BIGNUM, b: *const BIGNUM) -> c_int; + pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; + + pub fn BN_generate_prime_ex( + r: *mut BIGNUM, + bits: c_int, + safe: c_int, + add: *const BIGNUM, + rem: *const BIGNUM, + cb: *mut BN_GENCB, + ) -> c_int; + pub fn BN_is_prime_ex( + p: *const BIGNUM, + checks: c_int, + ctx: *mut BN_CTX, + cb: *mut BN_GENCB, + ) -> c_int; + pub fn BN_is_prime_fasttest_ex( + p: *const BIGNUM, + checks: c_int, + ctx: *mut BN_CTX, + do_trial_division: c_int, + cb: *mut BN_GENCB, + ) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn BN_get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + } + } else { + extern "C" { + pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + } + } +} diff --git a/openssl-sys/src/cms.rs b/openssl-sys/src/cms.rs new file mode 100644 index 000000000..b310ceabe --- /dev/null +++ b/openssl-sys/src/cms.rs @@ -0,0 +1,91 @@ +use libc::*; +use *; + +pub enum CMS_ContentInfo {} + +extern "C" { + #[cfg(ossl101)] + pub fn CMS_ContentInfo_free(cms: *mut ::CMS_ContentInfo); + #[cfg(ossl101)] + pub fn i2d_CMS_ContentInfo(a: *mut ::CMS_ContentInfo, pp: *mut *mut c_uchar) -> c_int; + + #[cfg(ossl101)] + pub fn d2i_CMS_ContentInfo(a: *mut *mut ::CMS_ContentInfo, pp: *mut *const c_uchar, length: c_long) -> *mut ::CMS_ContentInfo; +} + +#[cfg(ossl101)] +pub const CMS_TEXT: c_uint = 0x1; +#[cfg(ossl101)] +pub const CMS_NOCERTS: c_uint = 0x2; +#[cfg(ossl101)] +pub const CMS_NO_CONTENT_VERIFY: c_uint = 0x4; +#[cfg(ossl101)] +pub const CMS_NO_ATTR_VERIFY: c_uint = 0x8; +#[cfg(ossl101)] +pub const CMS_NOSIGS: c_uint = 0x4 | 0x8; +#[cfg(ossl101)] +pub const CMS_NOINTERN: c_uint = 0x10; +#[cfg(ossl101)] +pub const CMS_NO_SIGNER_CERT_VERIFY: c_uint = 0x20; +#[cfg(ossl101)] +pub const CMS_NOVERIFY: c_uint = 0x20; +#[cfg(ossl101)] +pub const CMS_DETACHED: c_uint = 0x40; +#[cfg(ossl101)] +pub const CMS_BINARY: c_uint = 0x80; +#[cfg(ossl101)] +pub const CMS_NOATTR: c_uint = 0x100; +#[cfg(ossl101)] +pub const CMS_NOSMIMECAP: c_uint = 0x200; +#[cfg(ossl101)] +pub const CMS_NOOLDMIMETYPE: c_uint = 0x400; +#[cfg(ossl101)] +pub const CMS_CRLFEOL: c_uint = 0x800; +#[cfg(ossl101)] +pub const CMS_STREAM: c_uint = 0x1000; +#[cfg(ossl101)] +pub const CMS_NOCRL: c_uint = 0x2000; +#[cfg(ossl101)] +pub const CMS_PARTIAL: c_uint = 0x4000; +#[cfg(ossl101)] +pub const CMS_REUSE_DIGEST: c_uint = 0x8000; +#[cfg(ossl101)] +pub const CMS_USE_KEYID: c_uint = 0x10000; +#[cfg(ossl101)] +pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; +#[cfg(ossl102)] +pub const CMS_KEY_PARAM: c_uint = 0x40000; +#[cfg(ossl110)] +pub const CMS_ASCIICRLF: c_uint = 0x80000; + +extern "C" { + #[cfg(ossl101)] + pub fn SMIME_read_CMS(bio: *mut ::BIO, bcont: *mut *mut ::BIO) -> *mut ::CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_sign( + signcert: *mut ::X509, + pkey: *mut ::EVP_PKEY, + certs: *mut ::stack_st_X509, + data: *mut ::BIO, + flags: c_uint, + ) -> *mut ::CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_encrypt( + certs: *mut stack_st_X509, + data: *mut ::BIO, + cipher: *const EVP_CIPHER, + flags: c_uint + ) -> *mut ::CMS_ContentInfo; + + #[cfg(ossl101)] + pub fn CMS_decrypt( + cms: *mut ::CMS_ContentInfo, + pkey: *mut ::EVP_PKEY, + cert: *mut ::X509, + dcont: *mut ::BIO, + out: *mut ::BIO, + flags: c_uint, + ) -> c_int; +} diff --git a/openssl-sys/src/conf.rs b/openssl-sys/src/conf.rs new file mode 100644 index 000000000..9b9d4b26f --- /dev/null +++ b/openssl-sys/src/conf.rs @@ -0,0 +1,7 @@ +use *; + +extern "C" { + pub fn NCONF_new(meth: *mut CONF_METHOD) -> *mut CONF; + pub fn NCONF_default() -> *mut CONF_METHOD; + pub fn NCONF_free(conf: *mut CONF); +} diff --git a/openssl-sys/src/crypto.rs b/openssl-sys/src/crypto.rs new file mode 100644 index 000000000..24e495cd2 --- /dev/null +++ b/openssl-sys/src/crypto.rs @@ -0,0 +1,128 @@ +use libc::*; + +use *; + +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_X509: c_int = 3; +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; +#[cfg(not(ossl110))] +pub const CRYPTO_LOCK_SSL_SESSION: c_int = 14; + +stack!(stack_st_void); + +cfg_if! { + if #[cfg(ossl110)] { + pub const CRYPTO_EX_INDEX_SSL: c_int = 0; + pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 1; + } else if #[cfg(libressl)] { + pub const CRYPTO_EX_INDEX_SSL: c_int = 1; + pub const CRYPTO_EX_INDEX_SSL_CTX: c_int = 2; + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl271))] { + extern "C" { + pub fn OpenSSL_version_num() -> c_ulong; + pub fn OpenSSL_version(key: c_int) -> *const c_char; + } + pub const OPENSSL_VERSION: c_int = 0; + pub const OPENSSL_CFLAGS: c_int = 1; + pub const OPENSSL_BUILT_ON: c_int = 2; + pub const OPENSSL_PLATFORM: c_int = 3; + pub const OPENSSL_DIR: c_int = 4; + } else { + extern "C" { + pub fn SSLeay() -> c_ulong; + pub fn SSLeay_version(key: c_int) -> *const c_char; + } + pub const SSLEAY_VERSION: c_int = 0; + pub const SSLEAY_CFLAGS: c_int = 2; + pub const SSLEAY_BUILT_ON: c_int = 3; + pub const SSLEAY_PLATFORM: c_int = 4; + pub const SSLEAY_DIR: c_int = 5; + } +} + +// FIXME should be options +pub type CRYPTO_EX_new = unsafe extern "C" fn( + parent: *mut c_void, + ptr: *mut c_void, + ad: *const CRYPTO_EX_DATA, + idx: c_int, + argl: c_long, + argp: *const c_void, +) -> c_int; +pub type CRYPTO_EX_dup = unsafe extern "C" fn( + to: *mut CRYPTO_EX_DATA, + from: *mut CRYPTO_EX_DATA, + from_d: *mut c_void, + idx: c_int, + argl: c_long, + argp: *mut c_void, +) -> c_int; +pub type CRYPTO_EX_free = unsafe extern "C" fn( + parent: *mut c_void, + ptr: *mut c_void, + ad: *mut CRYPTO_EX_DATA, + idx: c_int, + argl: c_long, + argp: *mut c_void, +); +extern "C" { + #[cfg(any(ossl110, libressl))] + pub fn CRYPTO_get_ex_new_index( + class_index: c_int, + argl: c_long, + argp: *mut c_void, + new_func: Option, + dup_func: Option, + free_func: Option, + ) -> c_int; +} + +pub const CRYPTO_LOCK: c_int = 1; + +extern "C" { + #[cfg(not(ossl110))] + pub fn CRYPTO_num_locks() -> c_int; + #[cfg(not(ossl110))] + pub fn CRYPTO_set_locking_callback( + func: unsafe extern "C" fn(mode: c_int, n: c_int, file: *const c_char, line: c_int), + ); + + #[cfg(not(ossl110))] + pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); + + #[cfg(not(ossl110))] + pub fn CRYPTO_add_lock( + pointer: *mut c_int, + amount: c_int, + type_: c_int, + file: *const c_char, + line: c_int, + ) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void; + pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); + } + } else { + extern "C" { + pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; + pub fn CRYPTO_free(buf: *mut c_void); + } + } +} + +extern "C" { + #[cfg(ossl101)] + pub fn FIPS_mode() -> c_int; + #[cfg(ossl101)] + pub fn FIPS_mode_set(onoff: c_int) -> c_int; + + pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, len: size_t) -> c_int; +} diff --git a/openssl-sys/src/dh.rs b/openssl-sys/src/dh.rs new file mode 100644 index 000000000..d6866871a --- /dev/null +++ b/openssl-sys/src/dh.rs @@ -0,0 +1,19 @@ +use *; + +extern "C" { + pub fn DH_new() -> *mut DH; + pub fn DH_free(dh: *mut DH); + + pub fn d2i_DHparams(k: *mut *mut DH, pp: *mut *const c_uchar, length: c_long) -> *mut DH; + pub fn i2d_DHparams(dh: *const DH, pp: *mut *mut c_uchar) -> c_int; + + #[cfg(ossl102)] + pub fn DH_get_1024_160() -> *mut DH; + #[cfg(ossl102)] + pub fn DH_get_2048_224() -> *mut DH; + #[cfg(ossl102)] + pub fn DH_get_2048_256() -> *mut DH; + + #[cfg(any(ossl110, libressl273))] + pub fn DH_set0_pqg(dh: *mut DH, p: *mut BIGNUM, q: *mut BIGNUM, g: *mut BIGNUM) -> c_int; +} diff --git a/openssl-sys/src/dsa.rs b/openssl-sys/src/dsa.rs new file mode 100644 index 000000000..604c68f03 --- /dev/null +++ b/openssl-sys/src/dsa.rs @@ -0,0 +1,58 @@ +use libc::*; + +use *; + +extern "C" { + pub fn DSA_new() -> *mut DSA; + pub fn DSA_free(dsa: *mut DSA); + pub fn DSA_up_ref(dsa: *mut DSA) -> c_int; + pub fn DSA_size(dsa: *const DSA) -> c_int; + pub fn DSA_sign( + dummy: c_int, + dgst: *const c_uchar, + len: c_int, + sigret: *mut c_uchar, + siglen: *mut c_uint, + dsa: *mut DSA, + ) -> c_int; + pub fn DSA_verify( + dummy: c_int, + dgst: *const c_uchar, + len: c_int, + sigbuf: *const c_uchar, + siglen: c_int, + dsa: *mut DSA, + ) -> c_int; + + pub fn d2i_DSAPublicKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) + -> *mut DSA; + + pub fn DSA_generate_parameters_ex( + dsa: *mut DSA, + bits: c_int, + seed: *const c_uchar, + seed_len: c_int, + counter_ref: *mut c_int, + h_ret: *mut c_ulong, + cb: *mut BN_GENCB, + ) -> c_int; + + pub fn DSA_generate_key(dsa: *mut DSA) -> c_int; + pub fn i2d_DSAPublicKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + + #[cfg(any(ossl110, libressl273))] + pub fn DSA_get0_pqg( + d: *const DSA, + p: *mut *const BIGNUM, + q: *mut *const BIGNUM, + q: *mut *const BIGNUM, + ); + #[cfg(any(ossl110, libressl273))] + pub fn DSA_set0_pqg(d: *mut DSA, p: *mut BIGNUM, q: *mut BIGNUM, q: *mut BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn DSA_get0_key(d: *const DSA, pub_key: *mut *const BIGNUM, priv_key: *mut *const BIGNUM); + #[cfg(any(ossl110, libressl273))] + pub fn DSA_set0_key(d: *mut DSA, pub_key: *mut BIGNUM, priv_key: *mut BIGNUM) -> c_int; +} diff --git a/openssl-sys/src/dtls1.rs b/openssl-sys/src/dtls1.rs new file mode 100644 index 000000000..08b7a489c --- /dev/null +++ b/openssl-sys/src/dtls1.rs @@ -0,0 +1,3 @@ +use libc::*; + +pub const DTLS1_COOKIE_LENGTH: c_uint = 256; diff --git a/openssl-sys/src/ec.rs b/openssl-sys/src/ec.rs new file mode 100644 index 000000000..ca4c09ea5 --- /dev/null +++ b/openssl-sys/src/ec.rs @@ -0,0 +1,213 @@ +use libc::*; + +use *; + +#[repr(C)] +#[derive(Copy, Clone)] +pub enum point_conversion_form_t { + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6, +} + +pub enum EC_METHOD {} +pub enum EC_GROUP {} +pub enum EC_POINT {} + +pub const OPENSSL_EC_NAMED_CURVE: c_int = 1; + +extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GF2m_simple_method() -> *const EC_METHOD; + + pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; + + pub fn EC_GROUP_free(group: *mut EC_GROUP); + + pub fn EC_GROUP_get_order( + group: *const EC_GROUP, + order: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_GROUP_get_curve_name(group: *const EC_GROUP) -> c_int; + + pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); + + pub fn EC_GROUP_get_curve_GFp( + group: *const EC_GROUP, + p: *mut BIGNUM, + a: *mut BIGNUM, + b: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GROUP_get_curve_GF2m( + group: *const EC_GROUP, + p: *mut BIGNUM, + a: *mut BIGNUM, + b: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; + + pub fn EC_GROUP_new_curve_GFp( + p: *const BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut EC_GROUP; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_GROUP_new_curve_GF2m( + p: *const BIGNUM, + a: *const BIGNUM, + b: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut EC_GROUP; + + pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; + + pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; + + pub fn EC_POINT_free(point: *mut EC_POINT); + + pub fn EC_POINT_get_affine_coordinates_GFp( + group: *const EC_GROUP, + p: *const EC_POINT, + x: *mut BIGNUM, + y: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn EC_POINT_get_affine_coordinates_GF2m( + group: *const EC_GROUP, + p: *const EC_POINT, + x: *mut BIGNUM, + y: *mut BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_point2oct( + group: *const EC_GROUP, + p: *const EC_POINT, + form: point_conversion_form_t, + buf: *mut c_uchar, + len: size_t, + ctx: *mut BN_CTX, + ) -> size_t; + + pub fn EC_POINT_oct2point( + group: *const EC_GROUP, + p: *mut EC_POINT, + buf: *const c_uchar, + len: size_t, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_add( + group: *const EC_GROUP, + r: *mut EC_POINT, + a: *const EC_POINT, + b: *const EC_POINT, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int; + + pub fn EC_POINT_cmp( + group: *const EC_GROUP, + a: *const EC_POINT, + b: *const EC_POINT, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_POINT_mul( + group: *const EC_GROUP, + r: *mut EC_POINT, + n: *const BIGNUM, + q: *const EC_POINT, + m: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> c_int; + + pub fn EC_KEY_new() -> *mut EC_KEY; + + pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + + pub fn EC_KEY_free(key: *mut EC_KEY); + + pub fn EC_KEY_dup(key: *const EC_KEY) -> *mut EC_KEY; + + pub fn EC_KEY_up_ref(key: *mut EC_KEY) -> c_int; + + pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + + pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int; + + pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; + + pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; + + pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + + pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int; + + pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; + + pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; + + pub fn EC_KEY_set_public_key_affine_coordinates( + key: *mut EC_KEY, + x: *mut BIGNUM, + y: *mut BIGNUM, + ) -> c_int; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum ECDSA_SIG {} + } else { + #[repr(C)] + pub struct ECDSA_SIG { + pub r: *mut BIGNUM, + pub s: *mut BIGNUM, + } + } +} + +extern "C" { + pub fn ECDSA_SIG_new() -> *mut ECDSA_SIG; + + pub fn ECDSA_SIG_free(sig: *mut ECDSA_SIG); + + #[cfg(any(ossl110, libressl273))] + pub fn ECDSA_SIG_get0(sig: *const ECDSA_SIG, pr: *mut *const BIGNUM, ps: *mut *const BIGNUM); + + #[cfg(any(ossl110, libressl273))] + pub fn ECDSA_SIG_set0(sig: *mut ECDSA_SIG, pr: *mut BIGNUM, ps: *mut BIGNUM) -> c_int; + + pub fn ECDSA_do_sign( + dgst: *const c_uchar, + dgst_len: c_int, + eckey: *mut EC_KEY, + ) -> *mut ECDSA_SIG; + + pub fn ECDSA_do_verify( + dgst: *const c_uchar, + dgst_len: c_int, + sig: *const ECDSA_SIG, + eckey: *mut EC_KEY, + ) -> c_int; + + pub fn d2i_ECDSA_SIG( + sig: *mut *mut ECDSA_SIG, + inp: *mut *const c_uchar, + length: c_long, + ) -> *mut ECDSA_SIG; + + pub fn i2d_ECDSA_SIG(sig: *const ECDSA_SIG, out: *mut *mut c_uchar) -> c_int; +} diff --git a/openssl-sys/src/err.rs b/openssl-sys/src/err.rs new file mode 100644 index 000000000..ecaec3ed0 --- /dev/null +++ b/openssl-sys/src/err.rs @@ -0,0 +1,58 @@ +use libc::*; + +pub const ERR_TXT_MALLOCED: c_int = 0x01; +pub const ERR_TXT_STRING: c_int = 0x02; + +pub const ERR_LIB_PEM: c_int = 9; + +const_fn! { + pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { + ((l as c_ulong & 0x0FF) << 24) | + ((f as c_ulong & 0xFFF) << 12) | + ((r as c_ulong & 0xFFF)) + } + + pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { + ((l >> 24) & 0x0FF) as c_int + } + + pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { + ((l >> 12) & 0xFFF) as c_int + } + + pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { + (l & 0xFFF) as c_int + } +} + +#[repr(C)] +pub struct ERR_STRING_DATA { + pub error: c_ulong, + pub string: *const c_char, +} + +extern "C" { + pub fn ERR_put_error(lib: c_int, func: c_int, reason: c_int, file: *const c_char, line: c_int); + pub fn ERR_set_error_data(data: *mut c_char, flags: c_int); + + pub fn ERR_get_error() -> c_ulong; + pub fn ERR_get_error_line_data( + file: *mut *const c_char, + line: *mut c_int, + data: *mut *const c_char, + flags: *mut c_int, + ) -> c_ulong; + pub fn ERR_peek_last_error() -> c_ulong; + pub fn ERR_clear_error(); + pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; + #[cfg(ossl110)] + pub fn ERR_load_strings(lib: c_int, str: *mut ERR_STRING_DATA) -> c_int; + #[cfg(not(ossl110))] + pub fn ERR_load_strings(lib: c_int, str: *mut ERR_STRING_DATA); + #[cfg(not(ossl110))] + pub fn ERR_load_crypto_strings(); + + pub fn ERR_get_next_error_library() -> c_int; +} diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs new file mode 100644 index 000000000..2d06e827f --- /dev/null +++ b/openssl-sys/src/evp.rs @@ -0,0 +1,367 @@ +use libc::*; +use *; + +pub const EVP_MAX_MD_SIZE: c_uint = 64; + +pub const PKCS5_SALT_LEN: c_int = 8; +pub const PKCS12_DEFAULT_ITER: c_int = 2048; + +pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; +pub const EVP_PKEY_DSA: c_int = NID_dsa; +pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; +pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; +pub const EVP_PKEY_HMAC: c_int = NID_hmac; +pub const EVP_PKEY_CMAC: c_int = NID_cmac; + +pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; +pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; +pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11; + +pub unsafe fn EVP_get_digestbynid(type_: c_int) -> *const EVP_MD { + EVP_get_digestbyname(OBJ_nid2sn(type_)) +} + +extern "C" { + pub fn EVP_MD_size(md: *const EVP_MD) -> c_int; + pub fn EVP_MD_type(md: *const EVP_MD) -> c_int; + + pub fn EVP_CIPHER_key_length(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_block_size(cipher: *const EVP_CIPHER) -> c_int; + pub fn EVP_CIPHER_iv_length(cipher: *const EVP_CIPHER) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX); + } + } else { + extern "C" { + pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + } + } +} + +extern "C" { + pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) + -> c_int; + pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const c_void, n: size_t) -> c_int; + pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; + pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD) -> c_int; + pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; + #[cfg(ossl111)] + pub fn EVP_DigestFinalXOF(ctx: *mut EVP_MD_CTX, res: *mut u8, len: usize) -> c_int; + + pub fn EVP_BytesToKey( + typ: *const EVP_CIPHER, + md: *const EVP_MD, + salt: *const u8, + data: *const u8, + datalen: c_int, + count: c_int, + key: *mut u8, + iv: *mut u8, + ) -> c_int; + + pub fn EVP_CipherInit( + ctx: *mut EVP_CIPHER_CTX, + evp: *const EVP_CIPHER, + key: *const u8, + iv: *const u8, + mode: c_int, + ) -> c_int; + pub fn EVP_CipherInit_ex( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + impl_: *mut ENGINE, + key: *const c_uchar, + iv: *const c_uchar, + enc: c_int, + ) -> c_int; + pub fn EVP_CipherUpdate( + ctx: *mut EVP_CIPHER_CTX, + outbuf: *mut u8, + outlen: *mut c_int, + inbuf: *const u8, + inlen: c_int, + ) -> c_int; + pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: *mut c_int) -> c_int; + + pub fn EVP_DigestSignInit( + ctx: *mut EVP_MD_CTX, + pctx: *mut *mut EVP_PKEY_CTX, + type_: *const EVP_MD, + e: *mut ENGINE, + pkey: *mut EVP_PKEY, + ) -> c_int; + pub fn EVP_DigestSignFinal( + ctx: *mut EVP_MD_CTX, + sig: *mut c_uchar, + siglen: *mut size_t, + ) -> c_int; + pub fn EVP_DigestVerifyInit( + ctx: *mut EVP_MD_CTX, + pctx: *mut *mut EVP_PKEY_CTX, + type_: *const EVP_MD, + e: *mut ENGINE, + pkey: *mut EVP_PKEY, + ) -> c_int; + pub fn EVP_SealInit( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + ek: *mut *mut c_uchar, + ekl: *mut c_int, + iv: *mut c_uchar, + pubk: *mut *mut EVP_PKEY, + npubk: c_int, + ) -> c_int; + pub fn EVP_SealFinal(ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int) -> c_int; + pub fn EVP_EncryptUpdate( + ctx: *mut EVP_CIPHER_CTX, + out: *mut c_uchar, + outl: *mut c_int, + in_: *const u8, + inl: c_int, + ) -> c_int; + pub fn EVP_OpenInit( + ctx: *mut EVP_CIPHER_CTX, + type_: *const EVP_CIPHER, + ek: *const c_uchar, + ekl: c_int, + iv: *const c_uchar, + priv_: *mut EVP_PKEY, + ) -> c_int; + pub fn EVP_OpenFinal(ctx: *mut EVP_CIPHER_CTX, out: *mut c_uchar, outl: *mut c_int) -> c_int; + pub fn EVP_DecryptUpdate( + ctx: *mut EVP_CIPHER_CTX, + out: *mut c_uchar, + outl: *mut c_int, + in_: *const u8, + inl: c_int, + ) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl111b, libressl280))] { + extern "C" { + pub fn EVP_PKEY_size(pkey: *const EVP_PKEY) -> c_int; + } + } else { + extern "C" { + pub fn EVP_PKEY_size(pkey: *mut EVP_PKEY) -> c_int; + } + } +} +cfg_if! { + if #[cfg(any(ossl102, libressl280))] { + extern "C" { + pub fn EVP_DigestVerifyFinal( + ctx: *mut EVP_MD_CTX, + sigret: *const c_uchar, + siglen: size_t, + ) -> c_int; + } + } else { + extern "C" { + pub fn EVP_DigestVerifyFinal( + ctx: *mut EVP_MD_CTX, + sigret: *mut c_uchar, + siglen: size_t, + ) -> c_int; + } + } +} + +extern "C" { + pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; + pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); + pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; + pub fn EVP_CIPHER_CTX_set_key_length(ctx: *mut EVP_CIPHER_CTX, keylen: c_int) -> c_int; + pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int; + pub fn EVP_CIPHER_CTX_ctrl( + ctx: *mut EVP_CIPHER_CTX, + type_: c_int, + arg: c_int, + ptr: *mut c_void, + ) -> c_int; + + pub fn EVP_md5() -> *const EVP_MD; + pub fn EVP_sha1() -> *const EVP_MD; + pub fn EVP_sha224() -> *const EVP_MD; + pub fn EVP_sha256() -> *const EVP_MD; + pub fn EVP_sha384() -> *const EVP_MD; + pub fn EVP_sha512() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_224() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_256() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_384() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_sha3_512() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_shake128() -> *const EVP_MD; + #[cfg(ossl111)] + pub fn EVP_shake256() -> *const EVP_MD; + pub fn EVP_ripemd160() -> *const EVP_MD; + pub fn EVP_des_ecb() -> *const EVP_CIPHER; + pub fn EVP_des_ede3() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_cbc() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_cfb64() -> *const EVP_CIPHER; + pub fn EVP_des_cbc() -> *const EVP_CIPHER; + pub fn EVP_rc4() -> *const EVP_CIPHER; + pub fn EVP_bf_ecb() -> *const EVP_CIPHER; + pub fn EVP_bf_cbc() -> *const EVP_CIPHER; + pub fn EVP_bf_cfb64() -> *const EVP_CIPHER; + pub fn EVP_bf_ofb() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb1() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb8() -> *const EVP_CIPHER; + pub fn EVP_aes_128_cfb128() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ctr() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ccm() -> *const EVP_CIPHER; + pub fn EVP_aes_128_gcm() -> *const EVP_CIPHER; + pub fn EVP_aes_128_xts() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER; + pub fn EVP_aes_256_cfb128() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ctr() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ccm() -> *const EVP_CIPHER; + pub fn EVP_aes_256_gcm() -> *const EVP_CIPHER; + pub fn EVP_aes_256_xts() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_chacha20() -> *const ::EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_chacha20_poly1305() -> *const ::EVP_CIPHER; + + #[cfg(not(ossl110))] + pub fn OPENSSL_add_all_algorithms_noconf(); + + pub fn EVP_get_digestbyname(name: *const c_char) -> *const EVP_MD; + pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER; + + pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int; + } + } else { + extern "C" { + pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; + } + } +} +extern "C" { + pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *mut c_void) -> c_int; + + pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; + pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; + pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; + pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH; + pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY; + + pub fn EVP_PKEY_new() -> *mut EVP_PKEY; + pub fn EVP_PKEY_free(k: *mut EVP_PKEY); + + pub fn d2i_AutoPrivateKey( + a: *mut *mut EVP_PKEY, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut EVP_PKEY; + + pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; + + pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int; + + pub fn PKCS5_PBKDF2_HMAC_SHA1( + pass: *const c_char, + passlen: c_int, + salt: *const u8, + saltlen: c_int, + iter: c_int, + keylen: c_int, + out: *mut u8, + ) -> c_int; + pub fn PKCS5_PBKDF2_HMAC( + pass: *const c_char, + passlen: c_int, + salt: *const c_uchar, + saltlen: c_int, + iter: c_int, + digest: *const EVP_MD, + keylen: c_int, + out: *mut u8, + ) -> c_int; + + #[cfg(ossl110)] + pub fn EVP_PBE_scrypt( + pass: *const c_char, + passlen: size_t, + salt: *const c_uchar, + saltlen: size_t, + N: u64, + r: u64, + p: u64, + maxmem: u64, + key: *mut c_uchar, + keylen: size_t, + ) -> c_int; +} + +pub const EVP_PKEY_OP_KEYGEN: c_int = 1 << 2; +pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3; +pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4; +pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5; +pub const EVP_PKEY_OP_SIGNCTX: c_int = 1 << 6; +pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7; +pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8; +pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9; + +pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN + | EVP_PKEY_OP_VERIFY + | EVP_PKEY_OP_VERIFYRECOVER + | EVP_PKEY_OP_SIGNCTX + | EVP_PKEY_OP_VERIFYCTX; + +pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT; + +pub const EVP_PKEY_CTRL_SET_MAC_KEY: c_int = 6; + +pub const EVP_PKEY_CTRL_CIPHER: c_int = 12; + +pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000; + +extern "C" { + pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; + pub fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut ENGINE) -> *mut EVP_PKEY_CTX; + pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX); + + pub fn EVP_PKEY_CTX_ctrl( + ctx: *mut EVP_PKEY_CTX, + keytype: c_int, + optype: c_int, + cmd: c_int, + p1: c_int, + p2: *mut c_void, + ) -> c_int; + + pub fn EVP_PKEY_new_mac_key( + type_: c_int, + e: *mut ENGINE, + key: *const c_uchar, + keylen: c_int, + ) -> *mut EVP_PKEY; + + pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int; + pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int; + + pub fn EVP_PKEY_keygen_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int; +} diff --git a/openssl-sys/src/hmac.rs b/openssl-sys/src/hmac.rs new file mode 100644 index 000000000..11e38ec35 --- /dev/null +++ b/openssl-sys/src/hmac.rs @@ -0,0 +1,30 @@ +use libc::*; + +use *; + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn HMAC_CTX_new() -> *mut HMAC_CTX; + pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); + } + } else { + extern "C" { + pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); + pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); + } + } +} + +extern "C" { + pub fn HMAC_Init_ex( + ctx: *mut HMAC_CTX, + key: *const c_void, + len: c_int, + md: *const EVP_MD, + impl_: *mut ENGINE, + ) -> c_int; + pub fn HMAC_Update(ctx: *mut HMAC_CTX, data: *const c_uchar, len: size_t) -> c_int; + pub fn HMAC_Final(ctx: *mut HMAC_CTX, md: *mut c_uchar, len: *mut c_uint) -> c_int; + pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; +} diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs new file mode 100644 index 000000000..5a768a446 --- /dev/null +++ b/openssl-sys/src/lib.rs @@ -0,0 +1,170 @@ +#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] +#![allow(dead_code, overflowing_literals, unused_imports)] +#![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] + +extern crate libc; + +use libc::*; + +pub use aes::*; +pub use asn1::*; +pub use bio::*; +pub use bn::*; +pub use cms::*; +pub use conf::*; +pub use crypto::*; +pub use dh::*; +pub use dsa::*; +pub use dtls1::*; +pub use ec::*; +pub use err::*; +pub use evp::*; +pub use hmac::*; +pub use obj_mac::*; +pub use object::*; +pub use ocsp::*; +pub use ossl_typ::*; +pub use pem::*; +pub use pkcs12::*; +pub use pkcs7::*; +pub use rand::*; +pub use rsa::*; +pub use safestack::*; +pub use sha::*; +pub use srtp::*; +pub use ssl::*; +pub use ssl3::*; +pub use stack::*; +pub use tls1::*; +pub use x509::*; +pub use x509_vfy::*; +pub use x509v3::*; + +#[macro_use] +mod macros; + +mod aes; +mod asn1; +mod bio; +mod bn; +mod cms; +mod conf; +mod crypto; +mod dh; +mod dsa; +mod dtls1; +mod ec; +mod err; +mod evp; +mod hmac; +mod obj_mac; +mod object; +mod ocsp; +mod ossl_typ; +mod pem; +mod pkcs12; +mod pkcs7; +mod rand; +mod rsa; +mod safestack; +mod sha; +mod srtp; +mod ssl; +mod ssl3; +mod stack; +mod tls1; +mod x509; +mod x509_vfy; +mod x509v3; + +// FIXME remove +pub type PasswordCallback = unsafe extern "C" fn( + buf: *mut c_char, + size: c_int, + rwflag: c_int, + user_data: *mut c_void, +) -> c_int; + +#[cfg(ossl110)] +pub fn init() { + use std::ptr; + use std::sync::{Once, ONCE_INIT}; + + // explicitly initialize to work around https://github.com/openssl/openssl/issues/3505 + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| unsafe { + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, ptr::null_mut()); + }) +} + +#[cfg(not(ossl110))] +pub fn init() { + use std::io::{self, Write}; + use std::mem; + use std::process; + use std::sync::{Mutex, MutexGuard, Once, ONCE_INIT}; + + static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; + static mut GUARDS: *mut Vec>> = + 0 as *mut Vec>>; + + unsafe extern "C" fn locking_function( + mode: c_int, + n: c_int, + _file: *const c_char, + _line: c_int, + ) { + let mutex = &(*MUTEXES)[n as usize]; + + if mode & ::CRYPTO_LOCK != 0 { + (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); + } else { + if let None = (*GUARDS)[n as usize].take() { + let _ = writeln!( + io::stderr(), + "BUG: rust-openssl lock {} already unlocked, aborting", + n + ); + process::abort(); + } + } + } + + cfg_if! { + if #[cfg(unix)] { + fn set_id_callback() { + unsafe extern "C" fn thread_id() -> c_ulong { + ::libc::pthread_self() as c_ulong + } + + unsafe { + CRYPTO_set_id_callback(thread_id); + } + } + } else { + fn set_id_callback() {} + } + } + + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| unsafe { + SSL_library_init(); + SSL_load_error_strings(); + OPENSSL_add_all_algorithms_noconf(); + + let num_locks = ::CRYPTO_num_locks(); + let mut mutexes = Box::new(Vec::new()); + for _ in 0..num_locks { + mutexes.push(Mutex::new(())); + } + MUTEXES = mem::transmute(mutexes); + let guards: Box>>> = + Box::new((0..num_locks).map(|_| None).collect()); + GUARDS = mem::transmute(guards); + + CRYPTO_set_locking_callback(locking_function); + set_id_callback(); + }) +} diff --git a/openssl-sys/src/macros.rs b/openssl-sys/src/macros.rs new file mode 100644 index 000000000..84320b726 --- /dev/null +++ b/openssl-sys/src/macros.rs @@ -0,0 +1,87 @@ +// vendored from the cfg-if crate to avoid breaking ctest +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an approprate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +macro_rules! stack { + ($t:ident) => { + cfg_if! { + if #[cfg(ossl110)] { + pub enum $t {} + } else { + #[repr(C)] + pub struct $t { + pub stack: ::_STACK, + } + } + } + }; +} + +#[cfg(const_fn)] +macro_rules! const_fn { + ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { + $( + pub const fn $name($($arg: $t),*) -> $ret $b + )* + } +} + +#[cfg(not(const_fn))] +macro_rules! const_fn { + ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { + $( + pub fn $name($($arg: $t),*) -> $ret $b + )* + } +} diff --git a/openssl-sys/src/obj_mac.rs b/openssl-sys/src/obj_mac.rs new file mode 100644 index 000000000..60c5767da --- /dev/null +++ b/openssl-sys/src/obj_mac.rs @@ -0,0 +1,914 @@ +use libc::*; + +pub const NID_undef: c_int = 0; +pub const NID_itu_t: c_int = 645; +pub const NID_ccitt: c_int = 404; +pub const NID_iso: c_int = 181; +pub const NID_joint_iso_itu_t: c_int = 646; +pub const NID_joint_iso_ccitt: c_int = 393; +pub const NID_member_body: c_int = 182; +pub const NID_identified_organization: c_int = 676; +pub const NID_hmac_md5: c_int = 780; +pub const NID_hmac_sha1: c_int = 781; +pub const NID_certicom_arc: c_int = 677; +pub const NID_international_organizations: c_int = 647; +pub const NID_wap: c_int = 678; +pub const NID_wap_wsg: c_int = 679; +pub const NID_selected_attribute_types: c_int = 394; +pub const NID_clearance: c_int = 395; +pub const NID_ISO_US: c_int = 183; +pub const NID_X9_57: c_int = 184; +pub const NID_X9cm: c_int = 185; +pub const NID_dsa: c_int = 116; +pub const NID_dsaWithSHA1: c_int = 113; +pub const NID_ansi_X9_62: c_int = 405; +pub const NID_X9_62_prime_field: c_int = 406; +pub const NID_X9_62_characteristic_two_field: c_int = 407; +pub const NID_X9_62_id_characteristic_two_basis: c_int = 680; +pub const NID_X9_62_onBasis: c_int = 681; +pub const NID_X9_62_tpBasis: c_int = 682; +pub const NID_X9_62_ppBasis: c_int = 683; +pub const NID_X9_62_id_ecPublicKey: c_int = 408; +pub const NID_X9_62_c2pnb163v1: c_int = 684; +pub const NID_X9_62_c2pnb163v2: c_int = 685; +pub const NID_X9_62_c2pnb163v3: c_int = 686; +pub const NID_X9_62_c2pnb176v1: c_int = 687; +pub const NID_X9_62_c2tnb191v1: c_int = 688; +pub const NID_X9_62_c2tnb191v2: c_int = 689; +pub const NID_X9_62_c2tnb191v3: c_int = 690; +pub const NID_X9_62_c2onb191v4: c_int = 691; +pub const NID_X9_62_c2onb191v5: c_int = 692; +pub const NID_X9_62_c2pnb208w1: c_int = 693; +pub const NID_X9_62_c2tnb239v1: c_int = 694; +pub const NID_X9_62_c2tnb239v2: c_int = 695; +pub const NID_X9_62_c2tnb239v3: c_int = 696; +pub const NID_X9_62_c2onb239v4: c_int = 697; +pub const NID_X9_62_c2onb239v5: c_int = 698; +pub const NID_X9_62_c2pnb272w1: c_int = 699; +pub const NID_X9_62_c2pnb304w1: c_int = 700; +pub const NID_X9_62_c2tnb359v1: c_int = 701; +pub const NID_X9_62_c2pnb368w1: c_int = 702; +pub const NID_X9_62_c2tnb431r1: c_int = 703; +pub const NID_X9_62_prime192v1: c_int = 409; +pub const NID_X9_62_prime192v2: c_int = 410; +pub const NID_X9_62_prime192v3: c_int = 411; +pub const NID_X9_62_prime239v1: c_int = 412; +pub const NID_X9_62_prime239v2: c_int = 413; +pub const NID_X9_62_prime239v3: c_int = 414; +pub const NID_X9_62_prime256v1: c_int = 415; +pub const NID_ecdsa_with_SHA1: c_int = 416; +pub const NID_ecdsa_with_Recommended: c_int = 791; +pub const NID_ecdsa_with_Specified: c_int = 792; +pub const NID_ecdsa_with_SHA224: c_int = 793; +pub const NID_ecdsa_with_SHA256: c_int = 794; +pub const NID_ecdsa_with_SHA384: c_int = 795; +pub const NID_ecdsa_with_SHA512: c_int = 796; +pub const NID_secp112r1: c_int = 704; +pub const NID_secp112r2: c_int = 705; +pub const NID_secp128r1: c_int = 706; +pub const NID_secp128r2: c_int = 707; +pub const NID_secp160k1: c_int = 708; +pub const NID_secp160r1: c_int = 709; +pub const NID_secp160r2: c_int = 710; +pub const NID_secp192k1: c_int = 711; +pub const NID_secp224k1: c_int = 712; +pub const NID_secp224r1: c_int = 713; +pub const NID_secp256k1: c_int = 714; +pub const NID_secp384r1: c_int = 715; +pub const NID_secp521r1: c_int = 716; +pub const NID_sect113r1: c_int = 717; +pub const NID_sect113r2: c_int = 718; +pub const NID_sect131r1: c_int = 719; +pub const NID_sect131r2: c_int = 720; +pub const NID_sect163k1: c_int = 721; +pub const NID_sect163r1: c_int = 722; +pub const NID_sect163r2: c_int = 723; +pub const NID_sect193r1: c_int = 724; +pub const NID_sect193r2: c_int = 725; +pub const NID_sect233k1: c_int = 726; +pub const NID_sect233r1: c_int = 727; +pub const NID_sect239k1: c_int = 728; +pub const NID_sect283k1: c_int = 729; +pub const NID_sect283r1: c_int = 730; +pub const NID_sect409k1: c_int = 731; +pub const NID_sect409r1: c_int = 732; +pub const NID_sect571k1: c_int = 733; +pub const NID_sect571r1: c_int = 734; +pub const NID_wap_wsg_idm_ecid_wtls1: c_int = 735; +pub const NID_wap_wsg_idm_ecid_wtls3: c_int = 736; +pub const NID_wap_wsg_idm_ecid_wtls4: c_int = 737; +pub const NID_wap_wsg_idm_ecid_wtls5: c_int = 738; +pub const NID_wap_wsg_idm_ecid_wtls6: c_int = 739; +pub const NID_wap_wsg_idm_ecid_wtls7: c_int = 740; +pub const NID_wap_wsg_idm_ecid_wtls8: c_int = 741; +pub const NID_wap_wsg_idm_ecid_wtls9: c_int = 742; +pub const NID_wap_wsg_idm_ecid_wtls10: c_int = 743; +pub const NID_wap_wsg_idm_ecid_wtls11: c_int = 744; +pub const NID_wap_wsg_idm_ecid_wtls12: c_int = 745; +pub const NID_cast5_cbc: c_int = 108; +pub const NID_cast5_ecb: c_int = 109; +pub const NID_cast5_cfb64: c_int = 110; +pub const NID_cast5_ofb64: c_int = 111; +pub const NID_pbeWithMD5AndCast5_CBC: c_int = 112; +pub const NID_id_PasswordBasedMAC: c_int = 782; +pub const NID_id_DHBasedMac: c_int = 783; +pub const NID_rsadsi: c_int = 1; +pub const NID_pkcs: c_int = 2; +pub const NID_pkcs1: c_int = 186; +pub const NID_rsaEncryption: c_int = 6; +pub const NID_md2WithRSAEncryption: c_int = 7; +pub const NID_md4WithRSAEncryption: c_int = 396; +pub const NID_md5WithRSAEncryption: c_int = 8; +pub const NID_sha1WithRSAEncryption: c_int = 65; +pub const NID_rsaesOaep: c_int = 919; +pub const NID_mgf1: c_int = 911; +pub const NID_rsassaPss: c_int = 912; +pub const NID_sha256WithRSAEncryption: c_int = 668; +pub const NID_sha384WithRSAEncryption: c_int = 669; +pub const NID_sha512WithRSAEncryption: c_int = 670; +pub const NID_sha224WithRSAEncryption: c_int = 671; +pub const NID_pkcs3: c_int = 27; +pub const NID_dhKeyAgreement: c_int = 28; +pub const NID_pkcs5: c_int = 187; +pub const NID_pbeWithMD2AndDES_CBC: c_int = 9; +pub const NID_pbeWithMD5AndDES_CBC: c_int = 10; +pub const NID_pbeWithMD2AndRC2_CBC: c_int = 168; +pub const NID_pbeWithMD5AndRC2_CBC: c_int = 169; +pub const NID_pbeWithSHA1AndDES_CBC: c_int = 170; +pub const NID_pbeWithSHA1AndRC2_CBC: c_int = 68; +pub const NID_id_pbkdf2: c_int = 69; +pub const NID_pbes2: c_int = 161; +pub const NID_pbmac1: c_int = 162; +pub const NID_pkcs7: c_int = 20; +pub const NID_pkcs7_data: c_int = 21; +pub const NID_pkcs7_signed: c_int = 22; +pub const NID_pkcs7_enveloped: c_int = 23; +pub const NID_pkcs7_signedAndEnveloped: c_int = 24; +pub const NID_pkcs7_digest: c_int = 25; +pub const NID_pkcs7_encrypted: c_int = 26; +pub const NID_pkcs9: c_int = 47; +pub const NID_pkcs9_emailAddress: c_int = 48; +pub const NID_pkcs9_unstructuredName: c_int = 49; +pub const NID_pkcs9_contentType: c_int = 50; +pub const NID_pkcs9_messageDigest: c_int = 51; +pub const NID_pkcs9_signingTime: c_int = 52; +pub const NID_pkcs9_countersignature: c_int = 53; +pub const NID_pkcs9_challengePassword: c_int = 54; +pub const NID_pkcs9_unstructuredAddress: c_int = 55; +pub const NID_pkcs9_extCertAttributes: c_int = 56; +pub const NID_ext_req: c_int = 172; +pub const NID_SMIMECapabilities: c_int = 167; +pub const NID_SMIME: c_int = 188; +pub const NID_id_smime_mod: c_int = 189; +pub const NID_id_smime_ct: c_int = 190; +pub const NID_id_smime_aa: c_int = 191; +pub const NID_id_smime_alg: c_int = 192; +pub const NID_id_smime_cd: c_int = 193; +pub const NID_id_smime_spq: c_int = 194; +pub const NID_id_smime_cti: c_int = 195; +pub const NID_id_smime_mod_cms: c_int = 196; +pub const NID_id_smime_mod_ess: c_int = 197; +pub const NID_id_smime_mod_oid: c_int = 198; +pub const NID_id_smime_mod_msg_v3: c_int = 199; +pub const NID_id_smime_mod_ets_eSignature_88: c_int = 200; +pub const NID_id_smime_mod_ets_eSignature_97: c_int = 201; +pub const NID_id_smime_mod_ets_eSigPolicy_88: c_int = 202; +pub const NID_id_smime_mod_ets_eSigPolicy_97: c_int = 203; +pub const NID_id_smime_ct_receipt: c_int = 204; +pub const NID_id_smime_ct_authData: c_int = 205; +pub const NID_id_smime_ct_publishCert: c_int = 206; +pub const NID_id_smime_ct_TSTInfo: c_int = 207; +pub const NID_id_smime_ct_TDTInfo: c_int = 208; +pub const NID_id_smime_ct_contentInfo: c_int = 209; +pub const NID_id_smime_ct_DVCSRequestData: c_int = 210; +pub const NID_id_smime_ct_DVCSResponseData: c_int = 211; +pub const NID_id_smime_ct_compressedData: c_int = 786; +pub const NID_id_ct_asciiTextWithCRLF: c_int = 787; +pub const NID_id_smime_aa_receiptRequest: c_int = 212; +pub const NID_id_smime_aa_securityLabel: c_int = 213; +pub const NID_id_smime_aa_mlExpandHistory: c_int = 214; +pub const NID_id_smime_aa_contentHint: c_int = 215; +pub const NID_id_smime_aa_msgSigDigest: c_int = 216; +pub const NID_id_smime_aa_encapContentType: c_int = 217; +pub const NID_id_smime_aa_contentIdentifier: c_int = 218; +pub const NID_id_smime_aa_macValue: c_int = 219; +pub const NID_id_smime_aa_equivalentLabels: c_int = 220; +pub const NID_id_smime_aa_contentReference: c_int = 221; +pub const NID_id_smime_aa_encrypKeyPref: c_int = 222; +pub const NID_id_smime_aa_signingCertificate: c_int = 223; +pub const NID_id_smime_aa_smimeEncryptCerts: c_int = 224; +pub const NID_id_smime_aa_timeStampToken: c_int = 225; +pub const NID_id_smime_aa_ets_sigPolicyId: c_int = 226; +pub const NID_id_smime_aa_ets_commitmentType: c_int = 227; +pub const NID_id_smime_aa_ets_signerLocation: c_int = 228; +pub const NID_id_smime_aa_ets_signerAttr: c_int = 229; +pub const NID_id_smime_aa_ets_otherSigCert: c_int = 230; +pub const NID_id_smime_aa_ets_contentTimestamp: c_int = 231; +pub const NID_id_smime_aa_ets_CertificateRefs: c_int = 232; +pub const NID_id_smime_aa_ets_RevocationRefs: c_int = 233; +pub const NID_id_smime_aa_ets_certValues: c_int = 234; +pub const NID_id_smime_aa_ets_revocationValues: c_int = 235; +pub const NID_id_smime_aa_ets_escTimeStamp: c_int = 236; +pub const NID_id_smime_aa_ets_certCRLTimestamp: c_int = 237; +pub const NID_id_smime_aa_ets_archiveTimeStamp: c_int = 238; +pub const NID_id_smime_aa_signatureType: c_int = 239; +pub const NID_id_smime_aa_dvcs_dvc: c_int = 240; +pub const NID_id_smime_alg_ESDHwith3DES: c_int = 241; +pub const NID_id_smime_alg_ESDHwithRC2: c_int = 242; +pub const NID_id_smime_alg_3DESwrap: c_int = 243; +pub const NID_id_smime_alg_RC2wrap: c_int = 244; +pub const NID_id_smime_alg_ESDH: c_int = 245; +pub const NID_id_smime_alg_CMS3DESwrap: c_int = 246; +pub const NID_id_smime_alg_CMSRC2wrap: c_int = 247; +pub const NID_id_alg_PWRI_KEK: c_int = 893; +pub const NID_id_smime_cd_ldap: c_int = 248; +pub const NID_id_smime_spq_ets_sqt_uri: c_int = 249; +pub const NID_id_smime_spq_ets_sqt_unotice: c_int = 250; +pub const NID_id_smime_cti_ets_proofOfOrigin: c_int = 251; +pub const NID_id_smime_cti_ets_proofOfReceipt: c_int = 252; +pub const NID_id_smime_cti_ets_proofOfDelivery: c_int = 253; +pub const NID_id_smime_cti_ets_proofOfSender: c_int = 254; +pub const NID_id_smime_cti_ets_proofOfApproval: c_int = 255; +pub const NID_id_smime_cti_ets_proofOfCreation: c_int = 256; +pub const NID_friendlyName: c_int = 156; +pub const NID_localKeyID: c_int = 157; +pub const NID_ms_csp_name: c_int = 417; +pub const NID_LocalKeySet: c_int = 856; +pub const NID_x509Certificate: c_int = 158; +pub const NID_sdsiCertificate: c_int = 159; +pub const NID_x509Crl: c_int = 160; +pub const NID_pbe_WithSHA1And128BitRC4: c_int = 144; +pub const NID_pbe_WithSHA1And40BitRC4: c_int = 145; +pub const NID_pbe_WithSHA1And3_Key_TripleDES_CBC: c_int = 146; +pub const NID_pbe_WithSHA1And2_Key_TripleDES_CBC: c_int = 147; +pub const NID_pbe_WithSHA1And128BitRC2_CBC: c_int = 148; +pub const NID_pbe_WithSHA1And40BitRC2_CBC: c_int = 149; +pub const NID_keyBag: c_int = 150; +pub const NID_pkcs8ShroudedKeyBag: c_int = 151; +pub const NID_certBag: c_int = 152; +pub const NID_crlBag: c_int = 153; +pub const NID_secretBag: c_int = 154; +pub const NID_safeContentsBag: c_int = 155; +pub const NID_md2: c_int = 3; +pub const NID_md4: c_int = 257; +pub const NID_md5: c_int = 4; +pub const NID_md5_sha1: c_int = 114; +pub const NID_hmacWithMD5: c_int = 797; +pub const NID_hmacWithSHA1: c_int = 163; +pub const NID_hmacWithSHA224: c_int = 798; +pub const NID_hmacWithSHA256: c_int = 799; +pub const NID_hmacWithSHA384: c_int = 800; +pub const NID_hmacWithSHA512: c_int = 801; +pub const NID_rc2_cbc: c_int = 37; +pub const NID_rc2_ecb: c_int = 38; +pub const NID_rc2_cfb64: c_int = 39; +pub const NID_rc2_ofb64: c_int = 40; +pub const NID_rc2_40_cbc: c_int = 98; +pub const NID_rc2_64_cbc: c_int = 166; +pub const NID_rc4: c_int = 5; +pub const NID_rc4_40: c_int = 97; +pub const NID_des_ede3_cbc: c_int = 44; +pub const NID_rc5_cbc: c_int = 120; +pub const NID_rc5_ecb: c_int = 121; +pub const NID_rc5_cfb64: c_int = 122; +pub const NID_rc5_ofb64: c_int = 123; +pub const NID_ms_ext_req: c_int = 171; +pub const NID_ms_code_ind: c_int = 134; +pub const NID_ms_code_com: c_int = 135; +pub const NID_ms_ctl_sign: c_int = 136; +pub const NID_ms_sgc: c_int = 137; +pub const NID_ms_efs: c_int = 138; +pub const NID_ms_smartcard_login: c_int = 648; +pub const NID_ms_upn: c_int = 649; +pub const NID_idea_cbc: c_int = 34; +pub const NID_idea_ecb: c_int = 36; +pub const NID_idea_cfb64: c_int = 35; +pub const NID_idea_ofb64: c_int = 46; +pub const NID_bf_cbc: c_int = 91; +pub const NID_bf_ecb: c_int = 92; +pub const NID_bf_cfb64: c_int = 93; +pub const NID_bf_ofb64: c_int = 94; +pub const NID_id_pkix: c_int = 127; +pub const NID_id_pkix_mod: c_int = 258; +pub const NID_id_pe: c_int = 175; +pub const NID_id_qt: c_int = 259; +pub const NID_id_kp: c_int = 128; +pub const NID_id_it: c_int = 260; +pub const NID_id_pkip: c_int = 261; +pub const NID_id_alg: c_int = 262; +pub const NID_id_cmc: c_int = 263; +pub const NID_id_on: c_int = 264; +pub const NID_id_pda: c_int = 265; +pub const NID_id_aca: c_int = 266; +pub const NID_id_qcs: c_int = 267; +pub const NID_id_cct: c_int = 268; +pub const NID_id_ppl: c_int = 662; +pub const NID_id_ad: c_int = 176; +pub const NID_id_pkix1_explicit_88: c_int = 269; +pub const NID_id_pkix1_implicit_88: c_int = 270; +pub const NID_id_pkix1_explicit_93: c_int = 271; +pub const NID_id_pkix1_implicit_93: c_int = 272; +pub const NID_id_mod_crmf: c_int = 273; +pub const NID_id_mod_cmc: c_int = 274; +pub const NID_id_mod_kea_profile_88: c_int = 275; +pub const NID_id_mod_kea_profile_93: c_int = 276; +pub const NID_id_mod_cmp: c_int = 277; +pub const NID_id_mod_qualified_cert_88: c_int = 278; +pub const NID_id_mod_qualified_cert_93: c_int = 279; +pub const NID_id_mod_attribute_cert: c_int = 280; +pub const NID_id_mod_timestamp_protocol: c_int = 281; +pub const NID_id_mod_ocsp: c_int = 282; +pub const NID_id_mod_dvcs: c_int = 283; +pub const NID_id_mod_cmp2000: c_int = 284; +pub const NID_info_access: c_int = 177; +pub const NID_biometricInfo: c_int = 285; +pub const NID_qcStatements: c_int = 286; +pub const NID_ac_auditEntity: c_int = 287; +pub const NID_ac_targeting: c_int = 288; +pub const NID_aaControls: c_int = 289; +pub const NID_sbgp_ipAddrBlock: c_int = 290; +pub const NID_sbgp_autonomousSysNum: c_int = 291; +pub const NID_sbgp_routerIdentifier: c_int = 292; +pub const NID_ac_proxying: c_int = 397; +pub const NID_sinfo_access: c_int = 398; +pub const NID_proxyCertInfo: c_int = 663; +pub const NID_id_qt_cps: c_int = 164; +pub const NID_id_qt_unotice: c_int = 165; +pub const NID_textNotice: c_int = 293; +pub const NID_server_auth: c_int = 129; +pub const NID_client_auth: c_int = 130; +pub const NID_code_sign: c_int = 131; +pub const NID_email_protect: c_int = 132; +pub const NID_ipsecEndSystem: c_int = 294; +pub const NID_ipsecTunnel: c_int = 295; +pub const NID_ipsecUser: c_int = 296; +pub const NID_time_stamp: c_int = 133; +pub const NID_OCSP_sign: c_int = 180; +pub const NID_dvcs: c_int = 297; +pub const NID_id_it_caProtEncCert: c_int = 298; +pub const NID_id_it_signKeyPairTypes: c_int = 299; +pub const NID_id_it_encKeyPairTypes: c_int = 300; +pub const NID_id_it_preferredSymmAlg: c_int = 301; +pub const NID_id_it_caKeyUpdateInfo: c_int = 302; +pub const NID_id_it_currentCRL: c_int = 303; +pub const NID_id_it_unsupportedOIDs: c_int = 304; +pub const NID_id_it_subscriptionRequest: c_int = 305; +pub const NID_id_it_subscriptionResponse: c_int = 306; +pub const NID_id_it_keyPairParamReq: c_int = 307; +pub const NID_id_it_keyPairParamRep: c_int = 308; +pub const NID_id_it_revPassphrase: c_int = 309; +pub const NID_id_it_implicitConfirm: c_int = 310; +pub const NID_id_it_confirmWaitTime: c_int = 311; +pub const NID_id_it_origPKIMessage: c_int = 312; +pub const NID_id_it_suppLangTags: c_int = 784; +pub const NID_id_regCtrl: c_int = 313; +pub const NID_id_regInfo: c_int = 314; +pub const NID_id_regCtrl_regToken: c_int = 315; +pub const NID_id_regCtrl_authenticator: c_int = 316; +pub const NID_id_regCtrl_pkiPublicationInfo: c_int = 317; +pub const NID_id_regCtrl_pkiArchiveOptions: c_int = 318; +pub const NID_id_regCtrl_oldCertID: c_int = 319; +pub const NID_id_regCtrl_protocolEncrKey: c_int = 320; +pub const NID_id_regInfo_utf8Pairs: c_int = 321; +pub const NID_id_regInfo_certReq: c_int = 322; +pub const NID_id_alg_des40: c_int = 323; +pub const NID_id_alg_noSignature: c_int = 324; +pub const NID_id_alg_dh_sig_hmac_sha1: c_int = 325; +pub const NID_id_alg_dh_pop: c_int = 326; +pub const NID_id_cmc_statusInfo: c_int = 327; +pub const NID_id_cmc_identification: c_int = 328; +pub const NID_id_cmc_identityProof: c_int = 329; +pub const NID_id_cmc_dataReturn: c_int = 330; +pub const NID_id_cmc_transactionId: c_int = 331; +pub const NID_id_cmc_senderNonce: c_int = 332; +pub const NID_id_cmc_recipientNonce: c_int = 333; +pub const NID_id_cmc_addExtensions: c_int = 334; +pub const NID_id_cmc_encryptedPOP: c_int = 335; +pub const NID_id_cmc_decryptedPOP: c_int = 336; +pub const NID_id_cmc_lraPOPWitness: c_int = 337; +pub const NID_id_cmc_getCert: c_int = 338; +pub const NID_id_cmc_getCRL: c_int = 339; +pub const NID_id_cmc_revokeRequest: c_int = 340; +pub const NID_id_cmc_regInfo: c_int = 341; +pub const NID_id_cmc_responseInfo: c_int = 342; +pub const NID_id_cmc_queryPending: c_int = 343; +pub const NID_id_cmc_popLinkRandom: c_int = 344; +pub const NID_id_cmc_popLinkWitness: c_int = 345; +pub const NID_id_cmc_confirmCertAcceptance: c_int = 346; +pub const NID_id_on_personalData: c_int = 347; +pub const NID_id_on_permanentIdentifier: c_int = 858; +pub const NID_id_pda_dateOfBirth: c_int = 348; +pub const NID_id_pda_placeOfBirth: c_int = 349; +pub const NID_id_pda_gender: c_int = 351; +pub const NID_id_pda_countryOfCitizenship: c_int = 352; +pub const NID_id_pda_countryOfResidence: c_int = 353; +pub const NID_id_aca_authenticationInfo: c_int = 354; +pub const NID_id_aca_accessIdentity: c_int = 355; +pub const NID_id_aca_chargingIdentity: c_int = 356; +pub const NID_id_aca_group: c_int = 357; +pub const NID_id_aca_role: c_int = 358; +pub const NID_id_aca_encAttrs: c_int = 399; +pub const NID_id_qcs_pkixQCSyntax_v1: c_int = 359; +pub const NID_id_cct_crs: c_int = 360; +pub const NID_id_cct_PKIData: c_int = 361; +pub const NID_id_cct_PKIResponse: c_int = 362; +pub const NID_id_ppl_anyLanguage: c_int = 664; +pub const NID_id_ppl_inheritAll: c_int = 665; +pub const NID_Independent: c_int = 667; +pub const NID_ad_OCSP: c_int = 178; +pub const NID_ad_ca_issuers: c_int = 179; +pub const NID_ad_timeStamping: c_int = 363; +pub const NID_ad_dvcs: c_int = 364; +pub const NID_caRepository: c_int = 785; +pub const NID_id_pkix_OCSP_basic: c_int = 365; +pub const NID_id_pkix_OCSP_Nonce: c_int = 366; +pub const NID_id_pkix_OCSP_CrlID: c_int = 367; +pub const NID_id_pkix_OCSP_acceptableResponses: c_int = 368; +pub const NID_id_pkix_OCSP_noCheck: c_int = 369; +pub const NID_id_pkix_OCSP_archiveCutoff: c_int = 370; +pub const NID_id_pkix_OCSP_serviceLocator: c_int = 371; +pub const NID_id_pkix_OCSP_extendedStatus: c_int = 372; +pub const NID_id_pkix_OCSP_valid: c_int = 373; +pub const NID_id_pkix_OCSP_path: c_int = 374; +pub const NID_id_pkix_OCSP_trustRoot: c_int = 375; +pub const NID_algorithm: c_int = 376; +pub const NID_md5WithRSA: c_int = 104; +pub const NID_des_ecb: c_int = 29; +pub const NID_des_cbc: c_int = 31; +pub const NID_des_ofb64: c_int = 45; +pub const NID_des_cfb64: c_int = 30; +pub const NID_rsaSignature: c_int = 377; +pub const NID_dsa_2: c_int = 67; +pub const NID_dsaWithSHA: c_int = 66; +pub const NID_shaWithRSAEncryption: c_int = 42; +pub const NID_des_ede_ecb: c_int = 32; +pub const NID_des_ede3_ecb: c_int = 33; +pub const NID_des_ede_cbc: c_int = 43; +pub const NID_des_ede_cfb64: c_int = 60; +pub const NID_des_ede3_cfb64: c_int = 61; +pub const NID_des_ede_ofb64: c_int = 62; +pub const NID_des_ede3_ofb64: c_int = 63; +pub const NID_desx_cbc: c_int = 80; +pub const NID_sha: c_int = 41; +pub const NID_sha1: c_int = 64; +pub const NID_dsaWithSHA1_2: c_int = 70; +pub const NID_sha1WithRSA: c_int = 115; +pub const NID_ripemd160: c_int = 117; +pub const NID_ripemd160WithRSA: c_int = 119; +pub const NID_sxnet: c_int = 143; +pub const NID_X500: c_int = 11; +pub const NID_X509: c_int = 12; +pub const NID_commonName: c_int = 13; +pub const NID_surname: c_int = 100; +pub const NID_serialNumber: c_int = 105; +pub const NID_countryName: c_int = 14; +pub const NID_localityName: c_int = 15; +pub const NID_stateOrProvinceName: c_int = 16; +pub const NID_streetAddress: c_int = 660; +pub const NID_organizationName: c_int = 17; +pub const NID_organizationalUnitName: c_int = 18; +pub const NID_title: c_int = 106; +pub const NID_description: c_int = 107; +pub const NID_searchGuide: c_int = 859; +pub const NID_businessCategory: c_int = 860; +pub const NID_postalAddress: c_int = 861; +pub const NID_postalCode: c_int = 661; +pub const NID_postOfficeBox: c_int = 862; +pub const NID_physicalDeliveryOfficeName: c_int = 863; +pub const NID_telephoneNumber: c_int = 864; +pub const NID_telexNumber: c_int = 865; +pub const NID_teletexTerminalIdentifier: c_int = 866; +pub const NID_facsimileTelephoneNumber: c_int = 867; +pub const NID_x121Address: c_int = 868; +pub const NID_internationaliSDNNumber: c_int = 869; +pub const NID_registeredAddress: c_int = 870; +pub const NID_destinationIndicator: c_int = 871; +pub const NID_preferredDeliveryMethod: c_int = 872; +pub const NID_presentationAddress: c_int = 873; +pub const NID_supportedApplicationContext: c_int = 874; +pub const NID_member: c_int = 875; +pub const NID_owner: c_int = 876; +pub const NID_roleOccupant: c_int = 877; +pub const NID_seeAlso: c_int = 878; +pub const NID_userPassword: c_int = 879; +pub const NID_userCertificate: c_int = 880; +pub const NID_cACertificate: c_int = 881; +pub const NID_authorityRevocationList: c_int = 882; +pub const NID_certificateRevocationList: c_int = 883; +pub const NID_crossCertificatePair: c_int = 884; +pub const NID_name: c_int = 173; +pub const NID_givenName: c_int = 99; +pub const NID_initials: c_int = 101; +pub const NID_generationQualifier: c_int = 509; +pub const NID_x500UniqueIdentifier: c_int = 503; +pub const NID_dnQualifier: c_int = 174; +pub const NID_enhancedSearchGuide: c_int = 885; +pub const NID_protocolInformation: c_int = 886; +pub const NID_distinguishedName: c_int = 887; +pub const NID_uniqueMember: c_int = 888; +pub const NID_houseIdentifier: c_int = 889; +pub const NID_supportedAlgorithms: c_int = 890; +pub const NID_deltaRevocationList: c_int = 891; +pub const NID_dmdName: c_int = 892; +pub const NID_pseudonym: c_int = 510; +pub const NID_role: c_int = 400; +pub const NID_X500algorithms: c_int = 378; +pub const NID_rsa: c_int = 19; +pub const NID_mdc2WithRSA: c_int = 96; +pub const NID_mdc2: c_int = 95; +pub const NID_id_ce: c_int = 81; +pub const NID_subject_directory_attributes: c_int = 769; +pub const NID_subject_key_identifier: c_int = 82; +pub const NID_key_usage: c_int = 83; +pub const NID_private_key_usage_period: c_int = 84; +pub const NID_subject_alt_name: c_int = 85; +pub const NID_issuer_alt_name: c_int = 86; +pub const NID_basic_constraints: c_int = 87; +pub const NID_crl_number: c_int = 88; +pub const NID_crl_reason: c_int = 141; +pub const NID_invalidity_date: c_int = 142; +pub const NID_delta_crl: c_int = 140; +pub const NID_issuing_distribution_point: c_int = 770; +pub const NID_certificate_issuer: c_int = 771; +pub const NID_name_constraints: c_int = 666; +pub const NID_crl_distribution_points: c_int = 103; +pub const NID_certificate_policies: c_int = 89; +pub const NID_any_policy: c_int = 746; +pub const NID_policy_mappings: c_int = 747; +pub const NID_authority_key_identifier: c_int = 90; +pub const NID_policy_constraints: c_int = 401; +pub const NID_ext_key_usage: c_int = 126; +pub const NID_freshest_crl: c_int = 857; +pub const NID_inhibit_any_policy: c_int = 748; +pub const NID_target_information: c_int = 402; +pub const NID_no_rev_avail: c_int = 403; +pub const NID_anyExtendedKeyUsage: c_int = 910; +pub const NID_netscape: c_int = 57; +pub const NID_netscape_cert_extension: c_int = 58; +pub const NID_netscape_data_type: c_int = 59; +pub const NID_netscape_cert_type: c_int = 71; +pub const NID_netscape_base_url: c_int = 72; +pub const NID_netscape_revocation_url: c_int = 73; +pub const NID_netscape_ca_revocation_url: c_int = 74; +pub const NID_netscape_renewal_url: c_int = 75; +pub const NID_netscape_ca_policy_url: c_int = 76; +pub const NID_netscape_ssl_server_name: c_int = 77; +pub const NID_netscape_comment: c_int = 78; +pub const NID_netscape_cert_sequence: c_int = 79; +pub const NID_ns_sgc: c_int = 139; +pub const NID_org: c_int = 379; +pub const NID_dod: c_int = 380; +pub const NID_iana: c_int = 381; +pub const NID_Directory: c_int = 382; +pub const NID_Management: c_int = 383; +pub const NID_Experimental: c_int = 384; +pub const NID_Private: c_int = 385; +pub const NID_Security: c_int = 386; +pub const NID_SNMPv2: c_int = 387; +pub const NID_Mail: c_int = 388; +pub const NID_Enterprises: c_int = 389; +pub const NID_dcObject: c_int = 390; +pub const NID_mime_mhs: c_int = 504; +pub const NID_mime_mhs_headings: c_int = 505; +pub const NID_mime_mhs_bodies: c_int = 506; +pub const NID_id_hex_partial_message: c_int = 507; +pub const NID_id_hex_multipart_message: c_int = 508; +pub const NID_zlib_compression: c_int = 125; +pub const NID_aes_128_ecb: c_int = 418; +pub const NID_aes_128_cbc: c_int = 419; +pub const NID_aes_128_ofb128: c_int = 420; +pub const NID_aes_128_cfb128: c_int = 421; +pub const NID_id_aes128_wrap: c_int = 788; +pub const NID_aes_128_gcm: c_int = 895; +pub const NID_aes_128_ccm: c_int = 896; +pub const NID_id_aes128_wrap_pad: c_int = 897; +pub const NID_aes_192_ecb: c_int = 422; +pub const NID_aes_192_cbc: c_int = 423; +pub const NID_aes_192_ofb128: c_int = 424; +pub const NID_aes_192_cfb128: c_int = 425; +pub const NID_id_aes192_wrap: c_int = 789; +pub const NID_aes_192_gcm: c_int = 898; +pub const NID_aes_192_ccm: c_int = 899; +pub const NID_id_aes192_wrap_pad: c_int = 900; +pub const NID_aes_256_ecb: c_int = 426; +pub const NID_aes_256_cbc: c_int = 427; +pub const NID_aes_256_ofb128: c_int = 428; +pub const NID_aes_256_cfb128: c_int = 429; +pub const NID_id_aes256_wrap: c_int = 790; +pub const NID_aes_256_gcm: c_int = 901; +pub const NID_aes_256_ccm: c_int = 902; +pub const NID_id_aes256_wrap_pad: c_int = 903; +pub const NID_aes_128_cfb1: c_int = 650; +pub const NID_aes_192_cfb1: c_int = 651; +pub const NID_aes_256_cfb1: c_int = 652; +pub const NID_aes_128_cfb8: c_int = 653; +pub const NID_aes_192_cfb8: c_int = 654; +pub const NID_aes_256_cfb8: c_int = 655; +pub const NID_aes_128_ctr: c_int = 904; +pub const NID_aes_192_ctr: c_int = 905; +pub const NID_aes_256_ctr: c_int = 906; +pub const NID_aes_128_xts: c_int = 913; +pub const NID_aes_256_xts: c_int = 914; +pub const NID_des_cfb1: c_int = 656; +pub const NID_des_cfb8: c_int = 657; +pub const NID_des_ede3_cfb1: c_int = 658; +pub const NID_des_ede3_cfb8: c_int = 659; +pub const NID_sha256: c_int = 672; +pub const NID_sha384: c_int = 673; +pub const NID_sha512: c_int = 674; +pub const NID_sha224: c_int = 675; +pub const NID_dsa_with_SHA224: c_int = 802; +pub const NID_dsa_with_SHA256: c_int = 803; +pub const NID_hold_instruction_code: c_int = 430; +pub const NID_hold_instruction_none: c_int = 431; +pub const NID_hold_instruction_call_issuer: c_int = 432; +pub const NID_hold_instruction_reject: c_int = 433; +pub const NID_data: c_int = 434; +pub const NID_pss: c_int = 435; +pub const NID_ucl: c_int = 436; +pub const NID_pilot: c_int = 437; +pub const NID_pilotAttributeType: c_int = 438; +pub const NID_pilotAttributeSyntax: c_int = 439; +pub const NID_pilotObjectClass: c_int = 440; +pub const NID_pilotGroups: c_int = 441; +pub const NID_iA5StringSyntax: c_int = 442; +pub const NID_caseIgnoreIA5StringSyntax: c_int = 443; +pub const NID_pilotObject: c_int = 444; +pub const NID_pilotPerson: c_int = 445; +pub const NID_account: c_int = 446; +pub const NID_document: c_int = 447; +pub const NID_room: c_int = 448; +pub const NID_documentSeries: c_int = 449; +pub const NID_Domain: c_int = 392; +pub const NID_rFC822localPart: c_int = 450; +pub const NID_dNSDomain: c_int = 451; +pub const NID_domainRelatedObject: c_int = 452; +pub const NID_friendlyCountry: c_int = 453; +pub const NID_simpleSecurityObject: c_int = 454; +pub const NID_pilotOrganization: c_int = 455; +pub const NID_pilotDSA: c_int = 456; +pub const NID_qualityLabelledData: c_int = 457; +pub const NID_userId: c_int = 458; +pub const NID_textEncodedORAddress: c_int = 459; +pub const NID_rfc822Mailbox: c_int = 460; +pub const NID_info: c_int = 461; +pub const NID_favouriteDrink: c_int = 462; +pub const NID_roomNumber: c_int = 463; +pub const NID_photo: c_int = 464; +pub const NID_userClass: c_int = 465; +pub const NID_host: c_int = 466; +pub const NID_manager: c_int = 467; +pub const NID_documentIdentifier: c_int = 468; +pub const NID_documentTitle: c_int = 469; +pub const NID_documentVersion: c_int = 470; +pub const NID_documentAuthor: c_int = 471; +pub const NID_documentLocation: c_int = 472; +pub const NID_homeTelephoneNumber: c_int = 473; +pub const NID_secretary: c_int = 474; +pub const NID_otherMailbox: c_int = 475; +pub const NID_lastModifiedTime: c_int = 476; +pub const NID_lastModifiedBy: c_int = 477; +pub const NID_domainComponent: c_int = 391; +pub const NID_aRecord: c_int = 478; +pub const NID_pilotAttributeType27: c_int = 479; +pub const NID_mXRecord: c_int = 480; +pub const NID_nSRecord: c_int = 481; +pub const NID_sOARecord: c_int = 482; +pub const NID_cNAMERecord: c_int = 483; +pub const NID_associatedDomain: c_int = 484; +pub const NID_associatedName: c_int = 485; +pub const NID_homePostalAddress: c_int = 486; +pub const NID_personalTitle: c_int = 487; +pub const NID_mobileTelephoneNumber: c_int = 488; +pub const NID_pagerTelephoneNumber: c_int = 489; +pub const NID_friendlyCountryName: c_int = 490; +pub const NID_organizationalStatus: c_int = 491; +pub const NID_janetMailbox: c_int = 492; +pub const NID_mailPreferenceOption: c_int = 493; +pub const NID_buildingName: c_int = 494; +pub const NID_dSAQuality: c_int = 495; +pub const NID_singleLevelQuality: c_int = 496; +pub const NID_subtreeMinimumQuality: c_int = 497; +pub const NID_subtreeMaximumQuality: c_int = 498; +pub const NID_personalSignature: c_int = 499; +pub const NID_dITRedirect: c_int = 500; +pub const NID_audio: c_int = 501; +pub const NID_documentPublisher: c_int = 502; +pub const NID_id_set: c_int = 512; +pub const NID_set_ctype: c_int = 513; +pub const NID_set_msgExt: c_int = 514; +pub const NID_set_attr: c_int = 515; +pub const NID_set_policy: c_int = 516; +pub const NID_set_certExt: c_int = 517; +pub const NID_set_brand: c_int = 518; +pub const NID_setct_PANData: c_int = 519; +pub const NID_setct_PANToken: c_int = 520; +pub const NID_setct_PANOnly: c_int = 521; +pub const NID_setct_OIData: c_int = 522; +pub const NID_setct_PI: c_int = 523; +pub const NID_setct_PIData: c_int = 524; +pub const NID_setct_PIDataUnsigned: c_int = 525; +pub const NID_setct_HODInput: c_int = 526; +pub const NID_setct_AuthResBaggage: c_int = 527; +pub const NID_setct_AuthRevReqBaggage: c_int = 528; +pub const NID_setct_AuthRevResBaggage: c_int = 529; +pub const NID_setct_CapTokenSeq: c_int = 530; +pub const NID_setct_PInitResData: c_int = 531; +pub const NID_setct_PI_TBS: c_int = 532; +pub const NID_setct_PResData: c_int = 533; +pub const NID_setct_AuthReqTBS: c_int = 534; +pub const NID_setct_AuthResTBS: c_int = 535; +pub const NID_setct_AuthResTBSX: c_int = 536; +pub const NID_setct_AuthTokenTBS: c_int = 537; +pub const NID_setct_CapTokenData: c_int = 538; +pub const NID_setct_CapTokenTBS: c_int = 539; +pub const NID_setct_AcqCardCodeMsg: c_int = 540; +pub const NID_setct_AuthRevReqTBS: c_int = 541; +pub const NID_setct_AuthRevResData: c_int = 542; +pub const NID_setct_AuthRevResTBS: c_int = 543; +pub const NID_setct_CapReqTBS: c_int = 544; +pub const NID_setct_CapReqTBSX: c_int = 545; +pub const NID_setct_CapResData: c_int = 546; +pub const NID_setct_CapRevReqTBS: c_int = 547; +pub const NID_setct_CapRevReqTBSX: c_int = 548; +pub const NID_setct_CapRevResData: c_int = 549; +pub const NID_setct_CredReqTBS: c_int = 550; +pub const NID_setct_CredReqTBSX: c_int = 551; +pub const NID_setct_CredResData: c_int = 552; +pub const NID_setct_CredRevReqTBS: c_int = 553; +pub const NID_setct_CredRevReqTBSX: c_int = 554; +pub const NID_setct_CredRevResData: c_int = 555; +pub const NID_setct_PCertReqData: c_int = 556; +pub const NID_setct_PCertResTBS: c_int = 557; +pub const NID_setct_BatchAdminReqData: c_int = 558; +pub const NID_setct_BatchAdminResData: c_int = 559; +pub const NID_setct_CardCInitResTBS: c_int = 560; +pub const NID_setct_MeAqCInitResTBS: c_int = 561; +pub const NID_setct_RegFormResTBS: c_int = 562; +pub const NID_setct_CertReqData: c_int = 563; +pub const NID_setct_CertReqTBS: c_int = 564; +pub const NID_setct_CertResData: c_int = 565; +pub const NID_setct_CertInqReqTBS: c_int = 566; +pub const NID_setct_ErrorTBS: c_int = 567; +pub const NID_setct_PIDualSignedTBE: c_int = 568; +pub const NID_setct_PIUnsignedTBE: c_int = 569; +pub const NID_setct_AuthReqTBE: c_int = 570; +pub const NID_setct_AuthResTBE: c_int = 571; +pub const NID_setct_AuthResTBEX: c_int = 572; +pub const NID_setct_AuthTokenTBE: c_int = 573; +pub const NID_setct_CapTokenTBE: c_int = 574; +pub const NID_setct_CapTokenTBEX: c_int = 575; +pub const NID_setct_AcqCardCodeMsgTBE: c_int = 576; +pub const NID_setct_AuthRevReqTBE: c_int = 577; +pub const NID_setct_AuthRevResTBE: c_int = 578; +pub const NID_setct_AuthRevResTBEB: c_int = 579; +pub const NID_setct_CapReqTBE: c_int = 580; +pub const NID_setct_CapReqTBEX: c_int = 581; +pub const NID_setct_CapResTBE: c_int = 582; +pub const NID_setct_CapRevReqTBE: c_int = 583; +pub const NID_setct_CapRevReqTBEX: c_int = 584; +pub const NID_setct_CapRevResTBE: c_int = 585; +pub const NID_setct_CredReqTBE: c_int = 586; +pub const NID_setct_CredReqTBEX: c_int = 587; +pub const NID_setct_CredResTBE: c_int = 588; +pub const NID_setct_CredRevReqTBE: c_int = 589; +pub const NID_setct_CredRevReqTBEX: c_int = 590; +pub const NID_setct_CredRevResTBE: c_int = 591; +pub const NID_setct_BatchAdminReqTBE: c_int = 592; +pub const NID_setct_BatchAdminResTBE: c_int = 593; +pub const NID_setct_RegFormReqTBE: c_int = 594; +pub const NID_setct_CertReqTBE: c_int = 595; +pub const NID_setct_CertReqTBEX: c_int = 596; +pub const NID_setct_CertResTBE: c_int = 597; +pub const NID_setct_CRLNotificationTBS: c_int = 598; +pub const NID_setct_CRLNotificationResTBS: c_int = 599; +pub const NID_setct_BCIDistributionTBS: c_int = 600; +pub const NID_setext_genCrypt: c_int = 601; +pub const NID_setext_miAuth: c_int = 602; +pub const NID_setext_pinSecure: c_int = 603; +pub const NID_setext_pinAny: c_int = 604; +pub const NID_setext_track2: c_int = 605; +pub const NID_setext_cv: c_int = 606; +pub const NID_set_policy_root: c_int = 607; +pub const NID_setCext_hashedRoot: c_int = 608; +pub const NID_setCext_certType: c_int = 609; +pub const NID_setCext_merchData: c_int = 610; +pub const NID_setCext_cCertRequired: c_int = 611; +pub const NID_setCext_tunneling: c_int = 612; +pub const NID_setCext_setExt: c_int = 613; +pub const NID_setCext_setQualf: c_int = 614; +pub const NID_setCext_PGWYcapabilities: c_int = 615; +pub const NID_setCext_TokenIdentifier: c_int = 616; +pub const NID_setCext_Track2Data: c_int = 617; +pub const NID_setCext_TokenType: c_int = 618; +pub const NID_setCext_IssuerCapabilities: c_int = 619; +pub const NID_setAttr_Cert: c_int = 620; +pub const NID_setAttr_PGWYcap: c_int = 621; +pub const NID_setAttr_TokenType: c_int = 622; +pub const NID_setAttr_IssCap: c_int = 623; +pub const NID_set_rootKeyThumb: c_int = 624; +pub const NID_set_addPolicy: c_int = 625; +pub const NID_setAttr_Token_EMV: c_int = 626; +pub const NID_setAttr_Token_B0Prime: c_int = 627; +pub const NID_setAttr_IssCap_CVM: c_int = 628; +pub const NID_setAttr_IssCap_T2: c_int = 629; +pub const NID_setAttr_IssCap_Sig: c_int = 630; +pub const NID_setAttr_GenCryptgrm: c_int = 631; +pub const NID_setAttr_T2Enc: c_int = 632; +pub const NID_setAttr_T2cleartxt: c_int = 633; +pub const NID_setAttr_TokICCsig: c_int = 634; +pub const NID_setAttr_SecDevSig: c_int = 635; +pub const NID_set_brand_IATA_ATA: c_int = 636; +pub const NID_set_brand_Diners: c_int = 637; +pub const NID_set_brand_AmericanExpress: c_int = 638; +pub const NID_set_brand_JCB: c_int = 639; +pub const NID_set_brand_Visa: c_int = 640; +pub const NID_set_brand_MasterCard: c_int = 641; +pub const NID_set_brand_Novus: c_int = 642; +pub const NID_des_cdmf: c_int = 643; +pub const NID_rsaOAEPEncryptionSET: c_int = 644; +pub const NID_ipsec3: c_int = 749; +pub const NID_ipsec4: c_int = 750; +pub const NID_whirlpool: c_int = 804; +pub const NID_cryptopro: c_int = 805; +pub const NID_cryptocom: c_int = 806; +pub const NID_id_GostR3411_94_with_GostR3410_2001: c_int = 807; +pub const NID_id_GostR3411_94_with_GostR3410_94: c_int = 808; +pub const NID_id_GostR3411_94: c_int = 809; +pub const NID_id_HMACGostR3411_94: c_int = 810; +pub const NID_id_GostR3410_2001: c_int = 811; +pub const NID_id_GostR3410_94: c_int = 812; +pub const NID_id_Gost28147_89: c_int = 813; +pub const NID_gost89_cnt: c_int = 814; +pub const NID_id_Gost28147_89_MAC: c_int = 815; +pub const NID_id_GostR3411_94_prf: c_int = 816; +pub const NID_id_GostR3410_2001DH: c_int = 817; +pub const NID_id_GostR3410_94DH: c_int = 818; +pub const NID_id_Gost28147_89_CryptoPro_KeyMeshing: c_int = 819; +pub const NID_id_Gost28147_89_None_KeyMeshing: c_int = 820; +pub const NID_id_GostR3411_94_TestParamSet: c_int = 821; +pub const NID_id_GostR3411_94_CryptoProParamSet: c_int = 822; +pub const NID_id_Gost28147_89_TestParamSet: c_int = 823; +pub const NID_id_Gost28147_89_CryptoPro_A_ParamSet: c_int = 824; +pub const NID_id_Gost28147_89_CryptoPro_B_ParamSet: c_int = 825; +pub const NID_id_Gost28147_89_CryptoPro_C_ParamSet: c_int = 826; +pub const NID_id_Gost28147_89_CryptoPro_D_ParamSet: c_int = 827; +pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet: c_int = 828; +pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet: c_int = 829; +pub const NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet: c_int = 830; +pub const NID_id_GostR3410_94_TestParamSet: c_int = 831; +pub const NID_id_GostR3410_94_CryptoPro_A_ParamSet: c_int = 832; +pub const NID_id_GostR3410_94_CryptoPro_B_ParamSet: c_int = 833; +pub const NID_id_GostR3410_94_CryptoPro_C_ParamSet: c_int = 834; +pub const NID_id_GostR3410_94_CryptoPro_D_ParamSet: c_int = 835; +pub const NID_id_GostR3410_94_CryptoPro_XchA_ParamSet: c_int = 836; +pub const NID_id_GostR3410_94_CryptoPro_XchB_ParamSet: c_int = 837; +pub const NID_id_GostR3410_94_CryptoPro_XchC_ParamSet: c_int = 838; +pub const NID_id_GostR3410_2001_TestParamSet: c_int = 839; +pub const NID_id_GostR3410_2001_CryptoPro_A_ParamSet: c_int = 840; +pub const NID_id_GostR3410_2001_CryptoPro_B_ParamSet: c_int = 841; +pub const NID_id_GostR3410_2001_CryptoPro_C_ParamSet: c_int = 842; +pub const NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet: c_int = 843; +pub const NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet: c_int = 844; +pub const NID_id_GostR3410_94_a: c_int = 845; +pub const NID_id_GostR3410_94_aBis: c_int = 846; +pub const NID_id_GostR3410_94_b: c_int = 847; +pub const NID_id_GostR3410_94_bBis: c_int = 848; +pub const NID_id_Gost28147_89_cc: c_int = 849; +pub const NID_id_GostR3410_94_cc: c_int = 850; +pub const NID_id_GostR3410_2001_cc: c_int = 851; +pub const NID_id_GostR3411_94_with_GostR3410_94_cc: c_int = 852; +pub const NID_id_GostR3411_94_with_GostR3410_2001_cc: c_int = 853; +pub const NID_id_GostR3410_2001_ParamSet_cc: c_int = 854; +pub const NID_camellia_128_cbc: c_int = 751; +pub const NID_camellia_192_cbc: c_int = 752; +pub const NID_camellia_256_cbc: c_int = 753; +pub const NID_id_camellia128_wrap: c_int = 907; +pub const NID_id_camellia192_wrap: c_int = 908; +pub const NID_id_camellia256_wrap: c_int = 909; +pub const NID_camellia_128_ecb: c_int = 754; +pub const NID_camellia_128_ofb128: c_int = 766; +pub const NID_camellia_128_cfb128: c_int = 757; +pub const NID_camellia_192_ecb: c_int = 755; +pub const NID_camellia_192_ofb128: c_int = 767; +pub const NID_camellia_192_cfb128: c_int = 758; +pub const NID_camellia_256_ecb: c_int = 756; +pub const NID_camellia_256_ofb128: c_int = 768; +pub const NID_camellia_256_cfb128: c_int = 759; +pub const NID_camellia_128_cfb1: c_int = 760; +pub const NID_camellia_192_cfb1: c_int = 761; +pub const NID_camellia_256_cfb1: c_int = 762; +pub const NID_camellia_128_cfb8: c_int = 763; +pub const NID_camellia_192_cfb8: c_int = 764; +pub const NID_camellia_256_cfb8: c_int = 765; +pub const NID_kisa: c_int = 773; +pub const NID_seed_ecb: c_int = 776; +pub const NID_seed_cbc: c_int = 777; +pub const NID_seed_cfb128: c_int = 779; +pub const NID_seed_ofb128: c_int = 778; +pub const NID_hmac: c_int = 855; +pub const NID_cmac: c_int = 894; +pub const NID_rc4_hmac_md5: c_int = 915; +pub const NID_aes_128_cbc_hmac_sha1: c_int = 916; +pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; +pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; diff --git a/openssl-sys/src/object.rs b/openssl-sys/src/object.rs new file mode 100644 index 000000000..814b83031 --- /dev/null +++ b/openssl-sys/src/object.rs @@ -0,0 +1,18 @@ +use libc::*; + +use *; + +extern "C" { + pub fn OBJ_nid2ln(nid: c_int) -> *const c_char; + pub fn OBJ_nid2sn(nid: c_int) -> *const c_char; + pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int; + pub fn OBJ_obj2txt( + buf: *mut c_char, + buf_len: c_int, + a: *const ASN1_OBJECT, + no_name: c_int, + ) -> c_int; + + pub fn OBJ_find_sigid_algs(signid: c_int, pdig_nid: *mut c_int, ppkey_nid: *mut c_int) + -> c_int; +} diff --git a/openssl-sys/src/ocsp.rs b/openssl-sys/src/ocsp.rs new file mode 100644 index 000000000..82157f32f --- /dev/null +++ b/openssl-sys/src/ocsp.rs @@ -0,0 +1,118 @@ +use libc::*; + +use *; + +pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1; +pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0; +pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1; +pub const OCSP_REVOKED_STATUS_CACOMPROMISE: c_int = 2; +pub const OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: c_int = 3; +pub const OCSP_REVOKED_STATUS_SUPERSEDED: c_int = 4; +pub const OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: c_int = 5; +pub const OCSP_REVOKED_STATUS_CERTIFICATEHOLD: c_int = 6; +pub const OCSP_REVOKED_STATUS_REMOVEFROMCRL: c_int = 8; + +pub const OCSP_NOCERTS: c_ulong = 0x1; +pub const OCSP_NOINTERN: c_ulong = 0x2; +pub const OCSP_NOSIGS: c_ulong = 0x4; +pub const OCSP_NOCHAIN: c_ulong = 0x8; +pub const OCSP_NOVERIFY: c_ulong = 0x10; +pub const OCSP_NOEXPLICIT: c_ulong = 0x20; +pub const OCSP_NOCASIGN: c_ulong = 0x40; +pub const OCSP_NODELEGATED: c_ulong = 0x80; +pub const OCSP_NOCHECKS: c_ulong = 0x100; +pub const OCSP_TRUSTOTHER: c_ulong = 0x200; +pub const OCSP_RESPID_KEY: c_ulong = 0x400; +pub const OCSP_NOTIME: c_ulong = 0x800; + +pub enum OCSP_CERTID {} + +pub enum OCSP_ONEREQ {} + +pub enum OCSP_REQUEST {} + +pub const OCSP_RESPONSE_STATUS_SUCCESSFUL: c_int = 0; +pub const OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: c_int = 1; +pub const OCSP_RESPONSE_STATUS_INTERNALERROR: c_int = 2; +pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3; +pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; +pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; + +pub const V_OCSP_CERTSTATUS_GOOD: c_int = 0; +pub const V_OCSP_CERTSTATUS_REVOKED: c_int = 1; +pub const V_OCSP_CERTSTATUS_UNKNOWN: c_int = 2; + +pub enum OCSP_BASICRESP {} + +cfg_if! { + if #[cfg(any(ossl110, libressl281))] { + extern "C" { + pub fn OCSP_cert_to_id( + dgst: *const EVP_MD, + subject: *const X509, + issuer: *const X509, + ) -> *mut OCSP_CERTID; + } + } else { + extern "C" { + pub fn OCSP_cert_to_id( + dgst: *const EVP_MD, + subject: *mut X509, + issuer: *mut X509, + ) -> *mut ::OCSP_CERTID; + } + } +} + +extern "C" { + pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ; + + pub fn OCSP_resp_find_status( + bs: *mut OCSP_BASICRESP, + id: *mut OCSP_CERTID, + status: *mut c_int, + reason: *mut c_int, + revtime: *mut *mut ASN1_GENERALIZEDTIME, + thisupd: *mut *mut ASN1_GENERALIZEDTIME, + nextupd: *mut *mut ASN1_GENERALIZEDTIME, + ) -> c_int; + pub fn OCSP_check_validity( + thisupd: *mut ASN1_GENERALIZEDTIME, + nextupd: *mut ASN1_GENERALIZEDTIME, + sec: c_long, + maxsec: c_long, + ) -> c_int; + + pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int; + pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP; + + pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE; + + pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; + pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); + pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE; + pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE); + pub fn i2d_OCSP_RESPONSE(a: *mut OCSP_RESPONSE, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_OCSP_RESPONSE( + a: *mut *mut OCSP_RESPONSE, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut OCSP_RESPONSE; + pub fn OCSP_ONEREQ_free(r: *mut OCSP_ONEREQ); + pub fn OCSP_CERTID_free(id: *mut OCSP_CERTID); + pub fn OCSP_REQUEST_new() -> *mut OCSP_REQUEST; + pub fn OCSP_REQUEST_free(r: *mut OCSP_REQUEST); + pub fn i2d_OCSP_REQUEST(a: *mut OCSP_REQUEST, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_OCSP_REQUEST( + a: *mut *mut OCSP_REQUEST, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut OCSP_REQUEST; + + pub fn OCSP_basic_verify( + bs: *mut OCSP_BASICRESP, + certs: *mut stack_st_X509, + st: *mut X509_STORE, + flags: c_ulong, + ) -> c_int; +} diff --git a/openssl-sys/src/ossl_typ.rs b/openssl-sys/src/ossl_typ.rs new file mode 100644 index 000000000..adf72684d --- /dev/null +++ b/openssl-sys/src/ossl_typ.rs @@ -0,0 +1,991 @@ +use libc::*; + +#[allow(unused_imports)] +use *; + +pub enum ASN1_INTEGER {} +pub enum ASN1_GENERALIZEDTIME {} +pub enum ASN1_STRING {} +pub enum ASN1_BIT_STRING {} +pub enum ASN1_TIME {} +pub enum ASN1_TYPE {} +pub enum ASN1_OBJECT {} +pub enum ASN1_OCTET_STRING {} + +pub enum bio_st {} // FIXME remove +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum BIO {} + } else { + #[repr(C)] + pub struct BIO { + pub method: *mut BIO_METHOD, + pub callback: Option< + unsafe extern "C" fn(*mut BIO, c_int, *const c_char, c_int, c_long, c_long) -> c_long, + >, + pub cb_arg: *mut c_char, + pub init: c_int, + pub shutdown: c_int, + pub flags: c_int, + pub retry_reason: c_int, + pub num: c_int, + pub ptr: *mut c_void, + pub next_bio: *mut BIO, + pub prev_bio: *mut BIO, + pub references: c_int, + pub num_read: c_ulong, + pub num_write: c_ulong, + pub ex_data: CRYPTO_EX_DATA, + } + } +} +cfg_if! { + if #[cfg(ossl110)] { + pub enum BIGNUM {} + } else { + #[repr(C)] + pub struct BIGNUM { + pub d: *mut BN_ULONG, + pub top: c_int, + pub dmax: c_int, + pub neg: c_int, + pub flags: c_int, + } + } +} +pub enum BN_BLINDING {} +pub enum BN_MONT_CTX {} + +pub enum BN_CTX {} +pub enum BN_GENCB {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_CIPHER {} + } else { + #[repr(C)] + pub struct EVP_CIPHER { + pub nid: c_int, + pub block_size: c_int, + pub key_len: c_int, + pub iv_len: c_int, + pub flags: c_ulong, + pub init: Option< + unsafe extern "C" fn(*mut EVP_CIPHER_CTX, *const c_uchar, *const c_uchar, c_int) -> c_int, + >, + pub do_cipher: Option< + unsafe extern "C" fn(*mut EVP_CIPHER_CTX, *mut c_uchar, *const c_uchar, size_t) -> c_int, + >, + pub cleanup: Option c_int>, + pub ctx_size: c_int, + pub set_asn1_parameters: + Option c_int>, + pub get_asn1_parameters: + Option c_int>, + pub ctrl: + Option c_int>, + pub app_data: *mut c_void, + } + } +} +pub enum EVP_CIPHER_CTX {} +pub enum EVP_MD {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_MD_CTX {} + } else { + #[repr(C)] + pub struct EVP_MD_CTX { + digest: *mut EVP_MD, + engine: *mut ENGINE, + flags: c_ulong, + md_data: *mut c_void, + pctx: *mut EVP_PKEY_CTX, + update: *mut c_void, + } + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum EVP_PKEY {} + } else { + #[repr(C)] + pub struct EVP_PKEY { + pub type_: c_int, + pub save_type: c_int, + pub references: c_int, + pub ameth: *const EVP_PKEY_ASN1_METHOD, + pub engine: *mut ENGINE, + pub pkey: *mut c_void, + pub save_parameters: c_int, + pub attributes: *mut stack_st_X509_ATTRIBUTE, + } + } +} + +pub enum EVP_PKEY_ASN1_METHOD {} + +pub enum EVP_PKEY_CTX {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum HMAC_CTX {} + } else { + #[repr(C)] + pub struct HMAC_CTX { + md: *mut EVP_MD, + md_ctx: EVP_MD_CTX, + i_ctx: EVP_MD_CTX, + o_ctx: EVP_MD_CTX, + key_length: c_uint, + key: [c_uchar; 128], + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum DH {} + } else { + #[repr(C)] + pub struct DH { + pub pad: c_int, + pub version: c_int, + pub p: *mut ::BIGNUM, + pub g: *mut ::BIGNUM, + pub length: c_long, + pub pub_key: *mut ::BIGNUM, + pub priv_key: *mut ::BIGNUM, + pub flags: c_int, + pub method_mont_p: *mut ::BN_MONT_CTX, + pub q: *mut ::BIGNUM, + pub j: *mut ::BIGNUM, + pub seed: *mut c_uchar, + pub seedlen: c_int, + pub counter: *mut ::BIGNUM, + pub references: c_int, + pub ex_data: ::CRYPTO_EX_DATA, + pub meth: *const ::DH_METHOD, + pub engine: *mut ::ENGINE, + } + } +} +pub enum DH_METHOD {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum DSA {} + } else { + #[repr(C)] + pub struct DSA { + pub pad: c_int, + pub version: c_long, + pub write_params: c_int, + + pub p: *mut BIGNUM, + pub q: *mut BIGNUM, + pub g: *mut BIGNUM, + pub pub_key: *mut BIGNUM, + pub priv_key: *mut BIGNUM, + pub kinv: *mut BIGNUM, + pub r: *mut BIGNUM, + + pub flags: c_int, + pub method_mont_p: *mut BN_MONT_CTX, + pub references: c_int, + pub ex_data: CRYPTO_EX_DATA, + pub meth: *const DSA_METHOD, + pub engine: *mut ENGINE, + } + } +} +pub enum DSA_METHOD {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum RSA {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const ::RSA_METHOD, + + pub engine: *mut ::ENGINE, + pub n: *mut ::BIGNUM, + pub e: *mut ::BIGNUM, + pub d: *mut ::BIGNUM, + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub dmp1: *mut ::BIGNUM, + pub dmq1: *mut ::BIGNUM, + pub iqmp: *mut ::BIGNUM, + + pub ex_data: ::CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut ::BN_MONT_CTX, + pub _method_mod_p: *mut ::BN_MONT_CTX, + pub _method_mod_q: *mut ::BN_MONT_CTX, + + pub blinding: *mut ::BN_BLINDING, + pub mt_blinding: *mut ::BN_BLINDING, + } + } else { + #[repr(C)] + pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const ::RSA_METHOD, + + pub engine: *mut ::ENGINE, + pub n: *mut ::BIGNUM, + pub e: *mut ::BIGNUM, + pub d: *mut ::BIGNUM, + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub dmp1: *mut ::BIGNUM, + pub dmq1: *mut ::BIGNUM, + pub iqmp: *mut ::BIGNUM, + + pub ex_data: ::CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut ::BN_MONT_CTX, + pub _method_mod_p: *mut ::BN_MONT_CTX, + pub _method_mod_q: *mut ::BN_MONT_CTX, + + pub bignum_data: *mut c_char, + pub blinding: *mut ::BN_BLINDING, + pub mt_blinding: *mut ::BN_BLINDING, + } + } +} +pub enum RSA_METHOD {} + +pub enum EC_KEY {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum X509 {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct X509 { + pub cert_info: *mut X509_CINF, + pub sig_alg: *mut ::X509_ALGOR, + pub signature: *mut ::ASN1_BIT_STRING, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: ::CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, + } + } else { + #[repr(C)] + pub struct X509 { + pub cert_info: *mut X509_CINF, + pub sig_alg: *mut X509_ALGOR, + pub signature: *mut ASN1_BIT_STRING, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_addr: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_asid: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, + } + } +} +cfg_if! { + if #[cfg(ossl110)] { + pub enum X509_ALGOR {} + } else { + #[repr(C)] + pub struct X509_ALGOR { + pub algorithm: *mut ::ASN1_OBJECT, + parameter: *mut c_void, + } + } +} +pub enum X509_CRL {} +pub enum X509_NAME {} +pub enum X509_STORE {} +pub enum X509_STORE_CTX {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum X509_VERIFY_PARAM {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + id: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + //pub id: *mut X509_VERIFY_PARAM_ID, + } + } else if #[cfg(ossl102)] { + #[repr(C)] + pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + pub id: *mut X509_VERIFY_PARAM_ID, + } + } +} + +#[repr(C)] +pub struct X509V3_CTX { + flags: c_int, + issuer_cert: *mut c_void, + subject_cert: *mut c_void, + subject_req: *mut c_void, + crl: *mut c_void, + db_meth: *mut c_void, + db: *mut c_void, + // I like the last comment line, it is copied from OpenSSL sources: + // Maybe more here +} +pub enum CONF {} +#[cfg(ossl110)] +pub enum OPENSSL_INIT_SETTINGS {} + +pub enum ENGINE {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL { + version: c_int, + method: *const ::SSL_METHOD, + rbio: *mut ::BIO, + wbio: *mut ::BIO, + bbio: *mut ::BIO, + pub server: c_int, + s3: *mut c_void, + d1: *mut c_void, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut ::SSL_SESSION, + verify_mode: c_int, + error: c_int, + error_code: c_int, + ctx: *mut ::SSL_CTX, + verify_result: c_long, + references: c_int, + client_version: c_int, + max_send_fragment: c_uint, + tlsext_hostname: *mut c_char, + tlsext_status_type: c_int, + initial_ctx: *mut ::SSL_CTX, + enc_read_ctx: *mut ::EVP_CIPHER_CTX, + read_hash: *mut EVP_MD_CTX, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL { + version: c_int, + type_: c_int, + method: *const ::SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_shutdown: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option< + unsafe extern "C" fn(c_int, + c_int, + c_int, + *const c_void, + size_t, + *mut SSL, + *mut c_void), + >, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + aead_read_ctx: *mut c_void, + enc_read_ctx: *mut ::EVP_CIPHER_CTX, + read_hash: *mut ::EVP_MD_CTX, + aead_write_ctx: *mut c_void, + enc_write_ctx: *mut ::EVP_CIPHER_CTX, + write_hash: *mut ::EVP_MD_CTX, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut ::SSL_SESSION, + generate_session_id: ::GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + ctx: *mut ::SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: ::CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + tlsext_debug_cb: + Option, + tlsext_debug_arg: *mut c_void, + tlsext_hostname: *mut c_char, + servername_done: c_int, + tlsext_status_type: c_int, + tlsext_status_expected: c_int, + tlsext_ocsp_ids: *mut c_void, + tlsext_ocsp_exts: *mut c_void, + tlsext_ocsp_resp: *mut c_uchar, + tlsext_ocsp_resplen: c_int, + tlsext_ticket_expected: c_int, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut c_uchar, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut c_uchar, + tlsext_session_ticket: *mut c_void, + tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + tls_session_ticket_ext_cb_arg: *mut c_void, + tls_session_secret_cb: ::tls_session_secret_cb_fn, + tls_session_secret_cb_arg: *mut c_void, + initial_ctx: *mut ::SSL_CTX, + next_proto_negotiated: *mut c_uchar, + next_proto_negotiated_len: c_uchar, + srtp_profiles: *mut c_void, + srtp_profile: *mut c_void, + tlsext_heartbeat: c_uint, + tlsext_hb_pending: c_uint, + tlsext_hb_seq: c_uint, + alpn_client_proto_list: *mut c_uchar, + alpn_client_proto_list_len: c_uint, + renegotiate: c_int, + } + } else { + #[repr(C)] + pub struct SSL { + version: c_int, + type_: c_int, + method: *const ::SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_session: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s2: *mut c_void, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option< + unsafe extern "C" fn(c_int, c_int, c_int, *const c_void, size_t, *mut SSL, *mut c_void), + >, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + enc_read_ctx: *mut ::EVP_CIPHER_CTX, + read_hash: *mut ::EVP_MD_CTX, + expand: *mut c_void, + enc_write_ctx: *mut ::EVP_CIPHER_CTX, + write_hash: *mut ::EVP_MD_CTX, + compress: *mut c_void, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut ::SSL_SESSION, + generate_session_id: ::GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + kssl_ctx: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: Option< + unsafe extern "C" fn(*mut SSL, *const c_char, *mut c_char, c_uint, *mut c_uchar, c_uint) + -> c_uint, + >, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: + Option c_uint>, + ctx: *mut ::SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: ::CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_cb: + Option, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + servername_done: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_type: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_expected: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_ids: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_exts: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resp: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resplen: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_expected: c_int, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_len: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_ticket_ext_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb: ::tls_session_secret_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + initial_ctx: *mut ::SSL_CTX, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_negotiated: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_negotiated_len: c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profiles: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profile: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_heartbeat: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_pending: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_seq: c_uint, + renegotiate: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: ::SRP_CTX, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + } + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL_CTX {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL_CTX { + method: *const ::SSL_METHOD, + cipher_list: *mut stack_st_SSL_CIPHER, + cert_store: *mut c_void, + session_timeout: c_long, + pub references: c_int, + extra_certs: *mut stack_st_X509, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + param: *mut ::X509_VERIFY_PARAM, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: ::CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + tlsext_servername_callback: *mut c_void, + tlsect_servername_arg: *mut c_void, + tlsext_tick_key_name: [c_uchar; 16], + tlsext_tick_hmac_key: [c_uchar; 16], + tlsext_tick_aes_key: [c_uchar; 16], + tlsext_ticket_key_cb: *mut c_void, + tlsext_status_cb: *mut c_void, + tlsext_status_arg: *mut c_void, + tlsext_opaque_prf_input_callback: *mut c_void, + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + next_protos_advertised_cb: *mut c_void, + next_protos_advertised_cb_arg: *mut c_void, + next_proto_select_cb: *mut c_void, + next_proto_select_cb_arg: *mut c_void, + + srtp_profiles: *mut c_void, + } + } else { + #[repr(C)] + pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: ::CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_servername_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsect_servername_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_key_name: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_hmac_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_aes_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_key_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + freelist_max_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + wbuf_freelist: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + rbuf_freelist: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: SRP_CTX, + + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_protos_advertised_cb: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_protos_advertised_cb_arg: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_select_cb: *mut c_void, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_NEXTPROTONEG") + ))] + next_proto_select_cb_arg: *mut c_void, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] + srtp_profiles: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC"), + ossl102 + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + } + + #[repr(C)] + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + pub struct SRP_CTX { + SRP_cb_arg: *mut c_void, + TLS_ext_srp_username_callback: *mut c_void, + SRP_verify_param_callback: *mut c_void, + SRP_give_srp_client_pwd_callback: *mut c_void, + login: *mut c_void, + N: *mut c_void, + g: *mut c_void, + s: *mut c_void, + B: *mut c_void, + A: *mut c_void, + a: *mut c_void, + b: *mut c_void, + v: *mut c_void, + info: *mut c_void, + stringth: c_int, + srp_Mask: c_ulong, + } + } +} + +pub enum COMP_METHOD {} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum CRYPTO_EX_DATA {} + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct CRYPTO_EX_DATA { + pub sk: *mut ::stack_st_void, + } + } else { + #[repr(C)] + pub struct CRYPTO_EX_DATA { + pub sk: *mut stack_st_void, + pub dummy: c_int, + } + } +} + +pub enum OCSP_RESPONSE {} diff --git a/openssl-sys/src/pem.rs b/openssl-sys/src/pem.rs new file mode 100644 index 000000000..dce6e0b38 --- /dev/null +++ b/openssl-sys/src/pem.rs @@ -0,0 +1,151 @@ +use libc::*; + +use *; + +pub type pem_password_cb = Option< + unsafe extern "C" fn( + buf: *mut c_char, + size: c_int, + rwflag: c_int, + user_data: *mut c_void, + ) -> c_int, +>; + +extern "C" { + pub fn PEM_read_bio_X509( + bio: *mut BIO, + out: *mut *mut X509, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut X509; + pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; + pub fn PEM_read_bio_X509_REQ( + bio: *mut BIO, + out: *mut *mut X509_REQ, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut X509_REQ; + pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; + pub fn PEM_read_bio_RSAPrivateKey( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_write_bio_RSAPrivateKey( + bp: *mut BIO, + rsa: *mut RSA, + cipher: *const EVP_CIPHER, + kstr: *mut c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_read_bio_RSAPublicKey( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_write_bio_RSAPublicKey(bp: *mut BIO, rsa: *const RSA) -> c_int; + pub fn PEM_read_bio_RSA_PUBKEY( + bio: *mut BIO, + rsa: *mut *mut RSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut RSA; + pub fn PEM_write_bio_RSA_PUBKEY(bp: *mut BIO, rsa: *mut RSA) -> c_int; + pub fn PEM_read_bio_DSAPrivateKey( + bp: *mut BIO, + dsa: *mut *mut DSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DSA; + pub fn PEM_write_bio_DSAPrivateKey( + bp: *mut BIO, + dsa: *mut DSA, + cipher: *const EVP_CIPHER, + kstr: *mut c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_read_bio_DSA_PUBKEY( + bp: *mut BIO, + dsa: *mut *mut DSA, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DSA; + pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut DSA) -> c_int; + pub fn PEM_read_bio_ECPrivateKey( + bio: *mut BIO, + key: *mut *mut EC_KEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EC_KEY; + pub fn PEM_write_bio_ECPrivateKey( + bio: *mut BIO, + key: *mut EC_KEY, + cipher: *const EVP_CIPHER, + kstr: *mut c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_read_bio_DHparams( + bio: *mut BIO, + out: *mut *mut DH, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut DH; + pub fn PEM_write_bio_DHparams(bio: *mut BIO, x: *const DH) -> c_int; + pub fn PEM_read_bio_PrivateKey( + bio: *mut BIO, + out: *mut *mut EVP_PKEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EVP_PKEY; + pub fn PEM_write_bio_PrivateKey( + bio: *mut BIO, + pkey: *mut EVP_PKEY, + cipher: *const EVP_CIPHER, + kstr: *mut c_uchar, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn PEM_read_bio_PUBKEY( + bio: *mut BIO, + out: *mut *mut EVP_PKEY, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> *mut EVP_PKEY; + pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int; + + pub fn PEM_write_bio_PKCS8PrivateKey( + bio: *mut BIO, + pkey: *mut EVP_PKEY, + cipher: *const EVP_CIPHER, + kstr: *mut c_char, + klen: c_int, + callback: pem_password_cb, + user_data: *mut c_void, + ) -> c_int; + pub fn d2i_PKCS8PrivateKey_bio( + bp: *mut BIO, + x: *mut *mut EVP_PKEY, + cb: pem_password_cb, + u: *mut c_void, + ) -> *mut EVP_PKEY; + + pub fn PEM_read_bio_PKCS7( + bio: *mut BIO, + out: *mut *mut PKCS7, + cb: pem_password_cb, + u: *mut c_void, + ) -> *mut PKCS7; + + pub fn PEM_write_bio_PKCS7(bp: *mut BIO, x: *mut PKCS7) -> c_int; +} + +pub const PEM_R_NO_START_LINE: c_int = 108; diff --git a/openssl-sys/src/pkcs12.rs b/openssl-sys/src/pkcs12.rs new file mode 100644 index 000000000..9cdba7e1d --- /dev/null +++ b/openssl-sys/src/pkcs12.rs @@ -0,0 +1,56 @@ +use libc::*; + +use *; + +pub enum PKCS12 {} + +extern "C" { + pub fn PKCS12_free(p12: *mut PKCS12); + pub fn i2d_PKCS12(a: *mut PKCS12, buf: *mut *mut u8) -> c_int; + pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; + + pub fn PKCS12_parse( + p12: *mut PKCS12, + pass: *const c_char, + pkey: *mut *mut EVP_PKEY, + cert: *mut *mut X509, + ca: *mut *mut stack_st_X509, + ) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn PKCS12_create( + pass: *const c_char, + friendly_name: *const c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int, + ) -> *mut PKCS12; + } + } else { + extern "C" { + pub fn PKCS12_create( + pass: *mut c_char, + friendly_name: *mut c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int, + ) -> *mut PKCS12; + } + } +} + +extern "C" { + pub fn i2d_PKCS12_bio(b: *mut BIO, a: *mut PKCS12) -> c_int; +} diff --git a/openssl-sys/src/pkcs7.rs b/openssl-sys/src/pkcs7.rs new file mode 100644 index 000000000..454a04dfc --- /dev/null +++ b/openssl-sys/src/pkcs7.rs @@ -0,0 +1,74 @@ +use libc::*; + +use *; + +pub enum PKCS7_SIGNED {} +pub enum PKCS7_ENVELOPE {} +pub enum PKCS7_SIGN_ENVELOPE {} +pub enum PKCS7_DIGEST {} +pub enum PKCS7_ENCRYPT {} +pub enum PKCS7 {} + +pub const PKCS7_TEXT: c_int = 0x1; +pub const PKCS7_NOCERTS: c_int = 0x2; +pub const PKCS7_NOSIGS: c_int = 0x4; +pub const PKCS7_NOCHAIN: c_int = 0x8; +pub const PKCS7_NOINTERN: c_int = 0x10; +pub const PKCS7_NOVERIFY: c_int = 0x20; +pub const PKCS7_DETACHED: c_int = 0x40; +pub const PKCS7_BINARY: c_int = 0x80; +pub const PKCS7_NOATTR: c_int = 0x100; +pub const PKCS7_NOSMIMECAP: c_int = 0x200; +pub const PKCS7_NOOLDMIMETYPE: c_int = 0x400; +pub const PKCS7_CRLFEOL: c_int = 0x800; +pub const PKCS7_STREAM: c_int = 0x1000; +pub const PKCS7_NOCRL: c_int = 0x2000; +pub const PKCS7_PARTIAL: c_int = 0x4000; +pub const PKCS7_REUSE_DIGEST: c_int = 0x8000; +#[cfg(not(any(ossl101, ossl102, libressl)))] +pub const PKCS7_NO_DUAL_CONTENT: c_int = 0x10000; + +extern "C" { + pub fn PKCS7_encrypt( + certs: *mut stack_st_X509, + b: *mut BIO, + cipher: *const EVP_CIPHER, + flags: c_int, + ) -> *mut PKCS7; + + pub fn PKCS7_verify( + pkcs7: *mut PKCS7, + certs: *mut stack_st_X509, + store: *mut X509_STORE, + indata: *mut BIO, + out: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn PKCS7_sign( + signcert: *mut X509, + pkey: *mut EVP_PKEY, + certs: *mut stack_st_X509, + data: *mut BIO, + flags: c_int, + ) -> *mut PKCS7; + + pub fn PKCS7_decrypt( + pkcs7: *mut PKCS7, + pkey: *mut EVP_PKEY, + cert: *mut X509, + data: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn PKCS7_free(pkcs7: *mut PKCS7); + + pub fn SMIME_write_PKCS7( + out: *mut BIO, + pkcs7: *mut PKCS7, + data: *mut BIO, + flags: c_int, + ) -> c_int; + + pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; +} diff --git a/openssl-sys/src/rand.rs b/openssl-sys/src/rand.rs new file mode 100644 index 000000000..7380702dc --- /dev/null +++ b/openssl-sys/src/rand.rs @@ -0,0 +1,10 @@ +use libc::*; + +extern "C" { + pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; + + #[cfg(ossl111)] + pub fn RAND_keep_random_devices_open(keep: c_int); + + pub fn RAND_status() -> c_int; +} diff --git a/openssl-sys/src/rsa.rs b/openssl-sys/src/rsa.rs new file mode 100644 index 000000000..9b6ab82fb --- /dev/null +++ b/openssl-sys/src/rsa.rs @@ -0,0 +1,179 @@ +use libc::*; +use std::ptr; + +use *; + +pub const RSA_F4: c_long = 0x10001; + +pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + -1, + EVP_PKEY_CTRL_RSA_PADDING, + pad, + ptr::null_mut(), + ) +} + +pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + -1, + EVP_PKEY_CTRL_GET_RSA_PADDING, + 0, + ppad as *mut c_void, + ) +} + +pub unsafe fn EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx: *mut EVP_PKEY_CTX, len: c_int) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY, + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, + len, + ptr::null_mut(), + ) +} + +pub unsafe fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + ctx, + EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, + 0, + md as *mut c_void, + ) +} + +pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; +pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2; + +pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5; + +pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; + +pub const RSA_PKCS1_PADDING: c_int = 1; +pub const RSA_SSLV23_PADDING: c_int = 2; +pub const RSA_NO_PADDING: c_int = 3; +pub const RSA_PKCS1_OAEP_PADDING: c_int = 4; +pub const RSA_X931_PADDING: c_int = 5; +pub const RSA_PKCS1_PSS_PADDING: c_int = 6; + +extern "C" { + pub fn RSA_new() -> *mut RSA; + pub fn RSA_size(k: *const RSA) -> c_int; + + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_key( + r: *mut ::RSA, + n: *mut ::BIGNUM, + e: *mut ::BIGNUM, + d: *mut ::BIGNUM, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_factors(r: *mut ::RSA, p: *mut ::BIGNUM, q: *mut ::BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_set0_crt_params( + r: *mut ::RSA, + dmp1: *mut ::BIGNUM, + dmq1: *mut ::BIGNUM, + iqmp: *mut ::BIGNUM, + ) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_key( + r: *const ::RSA, + n: *mut *const ::BIGNUM, + e: *mut *const ::BIGNUM, + d: *mut *const ::BIGNUM, + ); + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_factors(r: *const ::RSA, p: *mut *const ::BIGNUM, q: *mut *const ::BIGNUM); + #[cfg(any(ossl110, libressl273))] + pub fn RSA_get0_crt_params( + r: *const ::RSA, + dmp1: *mut *const ::BIGNUM, + dmq1: *mut *const ::BIGNUM, + iqmp: *mut *const ::BIGNUM, + ); + + #[cfg(not(ossl110))] + pub fn RSA_generate_key( + modsz: c_int, + e: c_ulong, + cb: Option, + cbarg: *mut c_void, + ) -> *mut RSA; + + pub fn RSA_generate_key_ex( + rsa: *mut RSA, + bits: c_int, + e: *mut BIGNUM, + cb: *mut BN_GENCB, + ) -> c_int; + + pub fn RSA_public_encrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_private_encrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_public_decrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_private_decrypt( + flen: c_int, + from: *const u8, + to: *mut u8, + k: *mut RSA, + pad: c_int, + ) -> c_int; + pub fn RSA_check_key(r: *const ::RSA) -> c_int; + pub fn RSA_free(rsa: *mut RSA); + pub fn RSA_up_ref(rsa: *mut RSA) -> c_int; + + pub fn i2d_RSAPublicKey(k: *const RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSAPublicKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + + pub fn RSA_sign( + t: c_int, + m: *const u8, + mlen: c_uint, + sig: *mut u8, + siglen: *mut c_uint, + k: *mut RSA, + ) -> c_int; + pub fn RSA_verify( + t: c_int, + m: *const u8, + mlen: c_uint, + sig: *const u8, + siglen: c_uint, + k: *mut RSA, + ) -> c_int; + + pub fn RSA_padding_check_PKCS1_type_2( + to: *mut c_uchar, + tlen: c_int, + f: *const c_uchar, + fl: c_int, + rsa_len: c_int, + ) -> c_int; +} diff --git a/openssl-sys/src/safestack.rs b/openssl-sys/src/safestack.rs new file mode 100644 index 000000000..0bee90d96 --- /dev/null +++ b/openssl-sys/src/safestack.rs @@ -0,0 +1 @@ +stack!(stack_st_OPENSSL_STRING); diff --git a/openssl-sys/src/sha.rs b/openssl-sys/src/sha.rs new file mode 100644 index 000000000..a9e7b15c2 --- /dev/null +++ b/openssl-sys/src/sha.rs @@ -0,0 +1,70 @@ +use libc::*; + +pub type SHA_LONG = c_uint; + +pub const SHA_LBLOCK: c_int = 16; + +#[repr(C)] +pub struct SHA_CTX { + pub h0: SHA_LONG, + pub h1: SHA_LONG, + pub h2: SHA_LONG, + pub h3: SHA_LONG, + pub h4: SHA_LONG, + pub Nl: SHA_LONG, + pub Nh: SHA_LONG, + pub data: [SHA_LONG; SHA_LBLOCK as usize], + pub num: c_uint, +} + +extern "C" { + pub fn SHA1_Init(c: *mut SHA_CTX) -> c_int; + pub fn SHA1_Update(c: *mut SHA_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA1_Final(md: *mut c_uchar, c: *mut SHA_CTX) -> c_int; + pub fn SHA1(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; +} + +#[repr(C)] +pub struct SHA256_CTX { + pub h: [SHA_LONG; 8], + pub Nl: SHA_LONG, + pub Nh: SHA_LONG, + pub data: [SHA_LONG; SHA_LBLOCK as usize], + pub num: c_uint, + pub md_len: c_uint, +} + +extern "C" { + pub fn SHA224_Init(c: *mut SHA256_CTX) -> c_int; + pub fn SHA224_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA224_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; + pub fn SHA224(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + pub fn SHA256_Init(c: *mut SHA256_CTX) -> c_int; + pub fn SHA256_Update(c: *mut SHA256_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA256_Final(md: *mut c_uchar, c: *mut SHA256_CTX) -> c_int; + pub fn SHA256(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; +} + +pub type SHA_LONG64 = u64; + +#[repr(C)] +pub struct SHA512_CTX { + pub h: [SHA_LONG64; 8], + pub Nl: SHA_LONG64, + pub Nh: SHA_LONG64, + // this is a union but we don't want to require 1.19 + u: [SHA_LONG64; SHA_LBLOCK as usize], + pub num: c_uint, + pub md_len: c_uint, +} + +extern "C" { + pub fn SHA384_Init(c: *mut SHA512_CTX) -> c_int; + pub fn SHA384_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA384_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; + pub fn SHA384(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; + pub fn SHA512_Init(c: *mut SHA512_CTX) -> c_int; + pub fn SHA512_Update(c: *mut SHA512_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn SHA512_Final(md: *mut c_uchar, c: *mut SHA512_CTX) -> c_int; + pub fn SHA512(d: *const c_uchar, n: size_t, md: *mut c_uchar) -> *mut c_uchar; +} diff --git a/openssl-sys/src/srtp.rs b/openssl-sys/src/srtp.rs new file mode 100644 index 000000000..d31aa06e7 --- /dev/null +++ b/openssl-sys/src/srtp.rs @@ -0,0 +1,18 @@ +use libc::*; + +use *; + +pub const SRTP_AES128_CM_SHA1_80: c_ulong = 0x0001; +pub const SRTP_AES128_CM_SHA1_32: c_ulong = 0x0002; +pub const SRTP_AES128_F8_SHA1_80: c_ulong = 0x0003; +pub const SRTP_AES128_F8_SHA1_32: c_ulong = 0x0004; +pub const SRTP_NULL_SHA1_80: c_ulong = 0x0005; +pub const SRTP_NULL_SHA1_32: c_ulong = 0x0006; + +extern "C" { + pub fn SSL_CTX_set_tlsext_use_srtp(ctx: *mut SSL_CTX, profiles: *const c_char) -> c_int; + pub fn SSL_set_tlsext_use_srtp(ssl: *mut SSL, profiles: *const c_char) -> c_int; + + pub fn SSL_get_srtp_profiles(ssl: *mut SSL) -> *mut stack_st_SRTP_PROTECTION_PROFILE; + pub fn SSL_get_selected_srtp_profile(ssl: *mut SSL) -> *mut SRTP_PROTECTION_PROFILE; +} diff --git a/openssl-sys/src/ssl.rs b/openssl-sys/src/ssl.rs new file mode 100644 index 000000000..257d380bf --- /dev/null +++ b/openssl-sys/src/ssl.rs @@ -0,0 +1,1345 @@ +use libc::*; +use std::ptr; + +use *; + +#[cfg(not(any(libressl, ossl110)))] +pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256; + +#[cfg(not(ossl110))] +pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; +#[cfg(not(ossl110))] +pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; + +#[cfg(not(any(libressl, ossl110)))] +pub const SSL_MAX_KEY_ARG_LENGTH: c_int = 8; +#[cfg(not(ossl110))] +pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; + +pub const SSL_SENT_SHUTDOWN: c_int = 1; +pub const SSL_RECEIVED_SHUTDOWN: c_int = 2; + +pub const SSL_FILETYPE_PEM: c_int = X509_FILETYPE_PEM; +pub const SSL_FILETYPE_ASN1: c_int = X509_FILETYPE_ASN1; + +pub enum SSL_METHOD {} +pub enum SSL_CIPHER {} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + pub enum SSL_SESSION {} + } else if #[cfg(libressl251)] { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; ::SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + peer: *mut ::X509, + verify_result: c_long, + timeout: c_long, + time: time_t, + pub references: c_int, + cipher: *const ::SSL_CIPHER, + cipher_id: c_long, + ciphers: *mut stack_st_SSL_CIPHER, + tlsext_hostname: *mut c_char, + tlsext_tick: *mut c_uchar, + tlsext_ticklen: size_t, + tlsext_tick_lifetime_int: c_long, + internal: *mut c_void, + } + } else if #[cfg(libressl)] { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + timeout: c_long, + time: time_t, + pub references: c_int, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: ::CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + tlsext_hostname: *mut c_char, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut u8, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut u16, + tlsext_tick: *mut c_uchar, + tlsext_ticklen: size_t, + tlsext_tick_lifetime_hint: c_long, + } + } else { + #[repr(C)] + pub struct SSL_SESSION { + ssl_version: c_int, + key_arg_length: c_uint, + key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize], + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH as usize], + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity: *mut c_char, + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + pub references: c_int, + timeout: c_long, + time: c_long, + compress_meth: c_uint, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: ::CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all( + not(osslconf = "OPENSSL_NO_TLSEXT"), + not(osslconf = "OPENSSL_NO_EC") + ))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticklen: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_lifetime_hint: c_long, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_username: *mut c_char, + } + } +} + +stack!(stack_st_SSL_CIPHER); + +#[repr(C)] +pub struct SRTP_PROTECTION_PROFILE { + pub name: *const c_char, + pub id: c_ulong, +} + +stack!(stack_st_SRTP_PROTECTION_PROFILE); + +pub type tls_session_ticket_ext_cb_fn = + Option c_int>; +pub type tls_session_secret_cb_fn = Option< + unsafe extern "C" fn( + *mut SSL, + *mut c_void, + *mut c_int, + *mut stack_st_SSL_CIPHER, + *mut *mut SSL_CIPHER, + *mut c_void, + ) -> c_int, +>; + +#[cfg(ossl111)] +pub const SSL_EXT_TLS_ONLY: c_uint = 0x0001; +/* This extension is only allowed in DTLS */ +#[cfg(ossl111)] +pub const SSL_EXT_DTLS_ONLY: c_uint = 0x0002; +/* Some extensions may be allowed in DTLS but we don't implement them for it */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS_IMPLEMENTATION_ONLY: c_uint = 0x0004; +/* Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is */ +#[cfg(ossl111)] +pub const SSL_EXT_SSL3_ALLOWED: c_uint = 0x0008; +/* Extension is only defined for TLS1.2 and below */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_2_AND_BELOW_ONLY: c_uint = 0x0010; +/* Extension is only defined for TLS1.3 and above */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_ONLY: c_uint = 0x0020; +/* Ignore this extension during parsing if we are resuming */ +#[cfg(ossl111)] +pub const SSL_EXT_IGNORE_ON_RESUMPTION: c_uint = 0x0040; +#[cfg(ossl111)] +pub const SSL_EXT_CLIENT_HELLO: c_uint = 0x0080; +/* Really means TLS1.2 or below */ +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_2_SERVER_HELLO: c_uint = 0x0100; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_SERVER_HELLO: c_uint = 0x0200; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS: c_uint = 0x0400; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST: c_uint = 0x0800; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_CERTIFICATE: c_uint = 0x1000; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000; +#[cfg(ossl111)] +pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000; + +#[cfg(ossl111)] +pub type SSL_custom_ext_add_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + x: *mut ::X509, + chainidx: size_t, + al: *mut c_int, + add_arg: *mut c_void, + ) -> c_int, +>; + +#[cfg(ossl111)] +pub type SSL_custom_ext_free_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + out: *mut *const c_uchar, + add_arg: *mut c_void, + ), +>; + +#[cfg(ossl111)] +pub type SSL_custom_ext_parse_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + input: *const c_uchar, + inlen: size_t, + x: *mut ::X509, + chainidx: size_t, + al: *mut c_int, + parse_arg: *mut c_void, + ) -> c_int, +>; + +pub const SSL_OP_LEGACY_SERVER_CONNECT: c_ulong = 0x00000004; +cfg_if! { + if #[cfg(libressl261)] { + pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x0; + } else if #[cfg(any(ossl102, libressl))] { + pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x10; + } +} +#[cfg(ossl101)] +pub const SSL_OP_SAFARI_ECDHE_ECDSA_BUG: c_ulong = 0x00000040; + +pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; + +pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; +pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; +pub const SSL_OP_NO_TICKET: c_ulong = 0x00004000; +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; + } else { + pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0; + } +} + +pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_ulong = 0x00010000; +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; + pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; + } else { + pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0; + pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x0; + } +} + +#[cfg(ossl111)] +pub const SSL_OP_ENABLE_MIDDLEBOX_COMPAT: c_ulong = 0x00100000; + +pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_ulong = 0x00400000; +cfg_if! { + if #[cfg(libressl280)] { + pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0; + } else { + pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0x00800000; + } +} + +cfg_if! { + if #[cfg(ossl101)] { + pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; + } else { + pub const SSL_OP_NO_SSLv3: c_ulong = 0x0; + } +} +pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000; +pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; + +pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; +#[cfg(ossl102)] +pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000; +#[cfg(ossl102)] +pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000; +#[cfg(ossl111)] +pub const SSL_OP_NO_TLSv1_3: c_ulong = 0x20000000; + +cfg_if! { + if #[cfg(ossl111)] { + pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 + | SSL_OP_NO_SSLv3 + | SSL_OP_NO_TLSv1 + | SSL_OP_NO_TLSv1_1 + | SSL_OP_NO_TLSv1_2 + | SSL_OP_NO_TLSv1_3; + } else if #[cfg(ossl102)] { + pub const SSL_OP_NO_SSL_MASK: c_ulong = + SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; + } +} + +cfg_if! { + if #[cfg(libressl261)] { + pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x0; + } else { + pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x80000000; + } +} + +cfg_if! { + if #[cfg(ossl110f)] { + pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG + | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + | SSL_OP_LEGACY_SERVER_CONNECT + | SSL_OP_TLSEXT_PADDING + | SSL_OP_SAFARI_ECDHE_ECDSA_BUG; + } else if #[cfg(libressl261)] { + pub const SSL_OP_ALL: c_ulong = 0x4; + } else if #[cfg(libressl)] { + pub const SSL_OP_ALL: c_ulong = 0x80000014; + } else { + pub const SSL_OP_ALL: c_ulong = 0x80000BFF; + } +} + +cfg_if! { + if #[cfg(ossl110)] { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000000; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000000; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000000; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000000; + pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000000; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000000; + pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00000000; + pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00000000; + pub const SSL_OP_NO_SSLv2: c_ulong = 0x00000000; + } else if #[cfg(ossl101)] { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000001; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000002; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000008; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000020; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000080; + pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000100; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000200; + pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; + pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; + pub const SSL_OP_NO_SSLv2: c_ulong = 0x01000000; + } else { + pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x0; + pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x0; + pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x0; + pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0; + pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0; + pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0; + pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0; + #[cfg(libressl261)] + pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x0; + #[cfg(not(libressl261))] + pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; + pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; + pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; + } +} + +pub const SSL_MODE_ENABLE_PARTIAL_WRITE: c_long = 0x1; +pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2; +pub const SSL_MODE_AUTO_RETRY: c_long = 0x4; +pub const SSL_MODE_NO_AUTO_CHAIN: c_long = 0x8; +pub const SSL_MODE_RELEASE_BUFFERS: c_long = 0x10; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_SERVERHELLO_TIME: c_long = 0x40; +#[cfg(ossl101)] +pub const SSL_MODE_SEND_FALLBACK_SCSV: c_long = 0x80; + +pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut()) +} + +#[cfg(ossl111)] +pub const SSL_COOKIE_LENGTH: c_int = 4096; + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn SSL_CTX_get_options(ctx: *const SSL_CTX) -> c_ulong; + pub fn SSL_CTX_set_options(ctx: *mut SSL_CTX, op: c_ulong) -> c_ulong; + pub fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, op: c_ulong) -> c_ulong; + } + } else { + pub unsafe fn SSL_CTX_get_options(ctx: *const SSL_CTX) -> c_ulong { + SSL_CTX_ctrl(ctx as *mut _, SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong + } + + pub unsafe fn SSL_CTX_set_options(ctx: *const SSL_CTX, op: c_ulong) -> c_ulong { + SSL_CTX_ctrl( + ctx as *mut _, + SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong + } + + pub unsafe fn SSL_CTX_clear_options(ctx: *const SSL_CTX, op: c_ulong) -> c_ulong { + SSL_CTX_ctrl( + ctx as *mut _, + SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong + } + } +} + +pub type GEN_SESSION_CB = + Option c_int>; + +pub const SSL_SESS_CACHE_OFF: c_long = 0x0; +pub const SSL_SESS_CACHE_CLIENT: c_long = 0x1; +pub const SSL_SESS_CACHE_SERVER: c_long = 0x2; +pub const SSL_SESS_CACHE_BOTH: c_long = SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER; +pub const SSL_SESS_CACHE_NO_AUTO_CLEAR: c_long = 0x80; +pub const SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: c_long = 0x100; +pub const SSL_SESS_CACHE_NO_INTERNAL_STORE: c_long = 0x200; +pub const SSL_SESS_CACHE_NO_INTERNAL: c_long = + SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE; + +extern "C" { + pub fn SSL_CTX_sess_set_new_cb( + ctx: *mut SSL_CTX, + new_session_cb: Option c_int>, + ); + pub fn SSL_CTX_sess_set_remove_cb( + ctx: *mut SSL_CTX, + remove_session_cb: Option, + ); +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn SSL_CTX_sess_set_get_cb( + ctx: *mut ::SSL_CTX, + get_session_cb: Option< + unsafe extern "C" fn(*mut ::SSL, *const c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + >, + ); + } + } else { + extern "C" { + pub fn SSL_CTX_sess_set_get_cb( + ctx: *mut ::SSL_CTX, + get_session_cb: Option< + unsafe extern "C" fn(*mut ::SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, + >, + ); + } + } +} +extern "C" { + // FIXME change to unsafe extern "C" fn + pub fn SSL_CTX_set_cookie_generate_cb( + s: *mut SSL_CTX, + cb: Option< + extern "C" fn(ssl: *mut SSL, cookie: *mut c_uchar, cookie_len: *mut c_uint) -> c_int, + >, + ); +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn SSL_CTX_set_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option< + extern "C" fn(ssl: *mut SSL, cookie: *const c_uchar, cookie_len: c_uint) -> c_int, + >, + ); + } + } else { + extern "C" { + pub fn SSL_CTX_set_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option c_int>, + ); + } + } +} + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_stateless_cookie_generate_cb( + s: *mut SSL_CTX, + cb: Option< + unsafe extern "C" fn( + ssl: *mut SSL, + cookie: *mut c_uchar, + cookie_len: *mut size_t, + ) -> c_int, + >, + ); + #[cfg(ossl111)] + pub fn SSL_CTX_set_stateless_cookie_verify_cb( + s: *mut SSL_CTX, + cb: Option< + unsafe extern "C" fn( + ssl: *mut SSL, + cookie: *const c_uchar, + cookie_len: size_t, + ) -> c_int, + >, + ); + + pub fn SSL_CTX_set_next_protos_advertised_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); + pub fn SSL_CTX_set_next_proto_select_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *mut c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); + pub fn SSL_get0_next_proto_negotiated( + s: *const SSL, + data: *mut *const c_uchar, + len: *mut c_uint, + ); + + pub fn SSL_select_next_proto( + out: *mut *mut c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + client: *const c_uchar, + client_len: c_uint, + ) -> c_int; +} + +pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0; +pub const OPENSSL_NPN_NEGOTIATED: c_int = 1; +pub const OPENSSL_NPN_NO_OVERLAP: c_int = 2; + +extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; + #[cfg(any(ossl102, libressl261))] + pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; + // FIXME should take an Option + #[cfg(any(ossl102, libressl261))] + pub fn SSL_CTX_set_alpn_select_cb( + ssl: *mut SSL_CTX, + cb: extern "C" fn( + ssl: *mut SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + arg: *mut c_void, + ) -> c_int, + arg: *mut c_void, + ); + #[cfg(any(ossl102, libressl261))] + pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +extern "C" { + pub fn SSL_CTX_set_psk_client_callback( + ssl: *mut SSL_CTX, + psk_client_cb: Option< + extern "C" fn( + *mut SSL, + *const c_char, + *mut c_char, + c_uint, + *mut c_uchar, + c_uint, + ) -> c_uint, + >, + ); + pub fn SSL_CTX_set_psk_server_callback( + ssl: *mut SSL_CTX, + psk_server_cb: Option< + extern "C" fn(*mut SSL, *const c_char, *mut c_uchar, c_uint) -> c_uint, + >, + ); +} + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_add_custom_ext( + ctx: *mut ::SSL_CTX, + ext_type: c_uint, + context: c_uint, + add_cb: SSL_custom_ext_add_cb_ex, + free_cb: SSL_custom_ext_free_cb_ex, + add_arg: *mut c_void, + parse_cb: SSL_custom_ext_parse_cb_ex, + parse_arg: *mut c_void, + ) -> c_int; + + #[cfg(ossl102)] + pub fn SSL_extension_supported(ext_type: c_uint) -> c_int; +} + +#[cfg(ossl111)] +pub type SSL_CTX_keylog_cb_func = + Option; + +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_keylog_callback(ctx: *mut SSL_CTX, cb: SSL_CTX_keylog_cb_func); + + #[cfg(ossl111)] + pub fn SSL_CTX_set_max_early_data(ctx: *mut SSL_CTX, max_early_data: u32) -> c_int; + #[cfg(ossl111)] + pub fn SSL_CTX_get_max_early_data(ctx: *const SSL_CTX) -> u32; + #[cfg(ossl111)] + pub fn SSL_set_max_early_data(ctx: *mut SSL, max_early_data: u32) -> c_int; + #[cfg(ossl111)] + pub fn SSL_get_max_early_data(ctx: *const SSL) -> u32; + + pub fn SSL_get_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; + pub fn SSL_get_peer_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; +} + +pub const SSL_AD_ILLEGAL_PARAMETER: c_int = SSL3_AD_ILLEGAL_PARAMETER; +pub const SSL_AD_DECODE_ERROR: c_int = TLS1_AD_DECODE_ERROR; +pub const SSL_AD_UNRECOGNIZED_NAME: c_int = TLS1_AD_UNRECOGNIZED_NAME; +pub const SSL_ERROR_NONE: c_int = 0; +pub const SSL_ERROR_SSL: c_int = 1; +pub const SSL_ERROR_SYSCALL: c_int = 5; +pub const SSL_ERROR_WANT_ACCEPT: c_int = 8; +pub const SSL_ERROR_WANT_CONNECT: c_int = 7; +pub const SSL_ERROR_WANT_READ: c_int = 2; +pub const SSL_ERROR_WANT_WRITE: c_int = 3; +pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; +pub const SSL_ERROR_ZERO_RETURN: c_int = 6; +#[cfg(ossl111)] +pub const SSL_ERROR_WANT_CLIENT_HELLO_CB: c_int = 11; +pub const SSL_VERIFY_NONE: c_int = 0; +pub const SSL_VERIFY_PEER: c_int = 1; +pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; +pub const SSL_CTRL_SET_TMP_DH: c_int = 3; +pub const SSL_CTRL_SET_TMP_ECDH: c_int = 4; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_GET_SESSION_REUSED: c_int = 8; +pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_OPTIONS: c_int = 32; +pub const SSL_CTRL_MODE: c_int = 33; +pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; +pub const SSL_CTRL_SET_SESS_CACHE_SIZE: c_int = 42; +pub const SSL_CTRL_GET_SESS_CACHE_SIZE: c_int = 43; +pub const SSL_CTRL_SET_SESS_CACHE_MODE: c_int = 44; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; +pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; +pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: c_int = 63; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: c_int = 64; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: c_int = 65; +pub const SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 70; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71; +#[cfg(any(libressl, all(ossl101, not(ossl110))))] +pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; +pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82; +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; +#[cfg(ossl102)] +pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; +#[cfg(ossl110)] +pub const SSL_CTRL_SET_MIN_PROTO_VERSION: c_int = 123; +#[cfg(ossl110)] +pub const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124; +#[cfg(ossl110g)] +pub const SSL_CTRL_GET_MIN_PROTO_VERSION: c_int = 130; +#[cfg(ossl110g)] +pub const SSL_CTRL_GET_MAX_PROTO_VERSION: c_int = 131; + +pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) +} + +pub unsafe fn SSL_CTX_set_tmp_ecdh(ctx: *mut SSL_CTX, key: *mut EC_KEY) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) +} + +pub unsafe fn SSL_set_tmp_dh(ssl: *mut SSL, dh: *mut DH) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) +} + +pub unsafe fn SSL_set_tmp_ecdh(ssl: *mut SSL, key: *mut EC_KEY) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) +} + +pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) +} + +pub unsafe fn SSL_CTX_get_extra_chain_certs( + ctx: *mut SSL_CTX, + chain: *mut *mut stack_st_X509, +) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_EXTRA_CHAIN_CERTS, 0, chain as *mut c_void) +} + +#[cfg(ossl102)] +pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) +} + +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut(), + ) as c_int +} + +#[cfg(any(libress, all(ossl102, not(ossl110))))] +pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { + SSL_ctrl( + ssl, + SSL_CTRL_SET_ECDH_AUTO, + onoff as c_long, + ptr::null_mut(), + ) as c_int +} + +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_CTX_set_min_proto_version(ctx: *mut SSL_CTX, version: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_MIN_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + + pub unsafe fn SSL_CTX_set_max_proto_version(ctx: *mut SSL_CTX, version: c_int) -> c_int { + SSL_CTX_ctrl( + ctx, + SSL_CTRL_SET_MAX_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int + } + } else if #[cfg(libressl261)] { + extern "C" { + pub fn SSL_CTX_set_min_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + pub fn SSL_CTX_set_max_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(ossl110g)] { + #[cfg(ossl110g)] + pub unsafe fn SSL_CTX_get_min_proto_version(ctx: *mut SSL_CTX) -> c_int { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_MIN_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + + #[cfg(ossl110g)] + pub unsafe fn SSL_CTX_get_max_proto_version(ctx: *mut SSL_CTX) -> c_int { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_MAX_PROTO_VERSION, 0, ptr::null_mut()) as c_int + } + } else if #[cfg(libressl270)] { + extern "C" { + pub fn SSL_CTX_get_min_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + pub fn SSL_CTX_get_max_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + } + } +} + +#[cfg(ossl110)] +pub unsafe fn SSL_set_min_proto_version(s: *mut SSL, version: c_int) -> c_int { + SSL_ctrl( + s, + SSL_CTRL_SET_MIN_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int +} + +#[cfg(ossl110)] +pub unsafe fn SSL_set_max_proto_version(s: *mut SSL, version: c_int) -> c_int { + SSL_ctrl( + s, + SSL_CTRL_SET_MAX_PROTO_VERSION, + version as c_long, + ptr::null_mut(), + ) as c_int +} + +#[cfg(ossl110g)] +pub unsafe fn SSL_get_min_proto_version(s: *mut SSL) -> c_int { + SSL_ctrl(s, SSL_CTRL_GET_MIN_PROTO_VERSION, 0, ptr::null_mut()) as c_int +} + +#[cfg(ossl110g)] +pub unsafe fn SSL_get_max_proto_version(s: *mut SSL) -> c_int { + SSL_ctrl(s, SSL_CTRL_GET_MAX_PROTO_VERSION, 0, ptr::null_mut()) as c_int +} + +extern "C" { + pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; + pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; + pub fn SSL_CTX_free(ctx: *mut SSL_CTX); + #[cfg(any(ossl110, libressl273))] + pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE; + + pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; + pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn SSL_CIPHER_get_version(cipher: *const SSL_CIPHER) -> *const c_char; + } + } else { + extern "C" { + pub fn SSL_CIPHER_get_version(cipher: *const SSL_CIPHER) -> *mut c_char; + } + } +} +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CIPHER_get_handshake_digest(cipher: *const ::SSL_CIPHER) -> *const ::EVP_MD; + pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn SSL_CIPHER_standard_name(cipher: *const SSL_CIPHER) -> *const c_char; + #[cfg(ossl111)] + pub fn OPENSSL_cipher_name(rfc_name: *const c_char) -> *const c_char; + + pub fn SSL_pending(ssl: *const SSL) -> c_int; + pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); + pub fn SSL_get_rbio(ssl: *const SSL) -> *mut BIO; + pub fn SSL_get_wbio(ssl: *const SSL) -> *mut BIO; + #[cfg(ossl111)] + pub fn SSL_CTX_set_ciphersuites(ctx: *mut SSL_CTX, str: *const c_char) -> c_int; + #[cfg(ossl111)] + pub fn SSL_set_ciphersuites(ssl: *mut ::SSL, str: *const c_char) -> c_int; + pub fn SSL_set_verify( + ssl: *mut SSL, + mode: c_int, + // FIXME should be unsafe + verify_callback: Option c_int>, + ); + pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; + pub fn SSL_CTX_use_certificate(ctx: *mut SSL_CTX, cert: *mut X509) -> c_int; + + pub fn SSL_CTX_use_PrivateKey_file( + ctx: *mut SSL_CTX, + key_file: *const c_char, + file_type: c_int, + ) -> c_int; + pub fn SSL_CTX_use_certificate_file( + ctx: *mut SSL_CTX, + cert_file: *const c_char, + file_type: c_int, + ) -> c_int; + pub fn SSL_CTX_use_certificate_chain_file( + ctx: *mut SSL_CTX, + cert_chain_file: *const c_char, + ) -> c_int; + pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; + + #[cfg(not(ossl110))] + pub fn SSL_load_error_strings(); + pub fn SSL_state_string(ssl: *const SSL) -> *const c_char; + pub fn SSL_state_string_long(ssl: *const SSL) -> *const c_char; + + pub fn SSL_SESSION_get_time(s: *const SSL_SESSION) -> c_long; + pub fn SSL_SESSION_get_timeout(s: *const SSL_SESSION) -> c_long; + #[cfg(ossl110)] + pub fn SSL_SESSION_get_protocol_version(s: *const SSL_SESSION) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_SESSION_set_max_early_data(ctx: *mut SSL_SESSION, max_early_data: u32) -> c_int; + #[cfg(ossl111)] + pub fn SSL_SESSION_get_max_early_data(ctx: *const SSL_SESSION) -> u32; + + pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; + #[cfg(any(ossl110, libressl273))] + pub fn SSL_SESSION_up_ref(ses: *mut SSL_SESSION) -> c_int; + pub fn SSL_SESSION_free(s: *mut SSL_SESSION); + pub fn i2d_SSL_SESSION(s: *mut SSL_SESSION, pp: *mut *mut c_uchar) -> c_int; + pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; + pub fn SSL_CTX_add_session(ctx: *mut SSL_CTX, session: *mut SSL_SESSION) -> c_int; + pub fn SSL_CTX_remove_session(ctx: *mut SSL_CTX, session: *mut SSL_SESSION) -> c_int; + pub fn d2i_SSL_SESSION( + a: *mut *mut SSL_SESSION, + pp: *mut *const c_uchar, + len: c_long, + ) -> *mut SSL_SESSION; + + pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509; + + pub fn SSL_get_peer_cert_chain(ssl: *const SSL) -> *mut stack_st_X509; + + pub fn SSL_CTX_set_verify( + ctx: *mut SSL_CTX, + mode: c_int, + verify_callback: Option c_int>, + ); + pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); + + pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; + + pub fn SSL_CTX_set_session_id_context( + ssl: *mut SSL_CTX, + sid_ctx: *const c_uchar, + sid_ctx_len: c_uint, + ) -> c_int; + + pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; + + #[cfg(any(ossl102, libressl261))] + pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; +} + +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1; +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_ERROR: c_int = 0; +#[cfg(ossl111)] +pub const SSL_CLIENT_HELLO_RETRY: c_int = -1; + +#[cfg(ossl111)] +pub type SSL_client_hello_cb_fn = + Option c_int>; +extern "C" { + #[cfg(ossl111)] + pub fn SSL_CTX_set_client_hello_cb( + c: *mut SSL_CTX, + cb: SSL_client_hello_cb_fn, + arg: *mut c_void, + ); + #[cfg(ossl111)] + pub fn SSL_client_hello_isv2(s: *mut SSL) -> c_int; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_legacy_version(s: *mut SSL) -> c_uint; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_random(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_session_id(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_ciphers(s: *mut SSL, out: *mut *const c_uchar) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_compression_methods( + s: *mut SSL, + out: *mut *const c_uchar, + ) -> size_t; + #[cfg(ossl111)] + pub fn SSL_client_hello_get1_extensions_present( + s: *mut SSL, + out: *mut *mut c_int, + outlen: *mut size_t, + ) -> c_int; + #[cfg(ossl111)] + pub fn SSL_client_hello_get0_ext( + s: *mut SSL, + type_: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + ) -> c_int; + + pub fn SSL_free(ssl: *mut SSL); + pub fn SSL_accept(ssl: *mut SSL) -> c_int; + #[cfg(ossl111)] + pub fn SSL_stateless(s: *mut SSL) -> c_int; + pub fn SSL_connect(ssl: *mut SSL) -> c_int; + pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; + #[cfg(ossl111)] + pub fn SSL_read_early_data( + s: *mut ::SSL, + buf: *mut c_void, + num: size_t, + readbytes: *mut size_t, + ) -> c_int; +} + +#[cfg(ossl111)] +pub const SSL_READ_EARLY_DATA_ERROR: c_int = 0; +#[cfg(ossl111)] +pub const SSL_READ_EARLY_DATA_SUCCESS: c_int = 1; +#[cfg(ossl111)] +pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2; + +extern "C" { + pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; + #[cfg(ossl111)] + pub fn SSL_write_early_data( + s: *mut SSL, + buf: *const c_void, + num: size_t, + written: *mut size_t, + ) -> c_int; + pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn SSL_CTX_callback_ctrl( + ctx: *mut SSL_CTX, + cmd: c_int, + fp: Option, + ) -> c_long; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl291))] { + extern "C" { + pub fn TLS_method() -> *const SSL_METHOD; + + pub fn DTLS_method() -> *const SSL_METHOD; + } + } else { + extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))] + pub fn SSLv3_method() -> *const SSL_METHOD; + + pub fn SSLv23_method() -> *const SSL_METHOD; + + pub fn TLSv1_method() -> *const SSL_METHOD; + + pub fn TLSv1_1_method() -> *const SSL_METHOD; + + pub fn TLSv1_2_method() -> *const SSL_METHOD; + + pub fn DTLSv1_method() -> *const SSL_METHOD; + + #[cfg(ossl102)] + pub fn DTLSv1_2_method() -> *const SSL_METHOD; + } + } +} + +extern "C" { + pub fn SSL_get_error(ssl: *const SSL, ret: c_int) -> c_int; + pub fn SSL_get_version(ssl: *const SSL) -> *const c_char; + + pub fn SSL_do_handshake(ssl: *mut SSL) -> c_int; + pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; + + pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); + + #[cfg(not(libressl))] + pub fn SSL_CTX_add_client_CA(ctx: *mut SSL_CTX, cacert: *mut X509) -> c_int; + + pub fn SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int; + pub fn SSL_CTX_load_verify_locations( + ctx: *mut SSL_CTX, + CAfile: *const c_char, + CApath: *const c_char, + ) -> c_int; +} + +cfg_if! { + if #[cfg(ossl111b)] { + extern "C" { + pub fn SSL_get_ssl_method(ssl: *const SSL) -> *const SSL_METHOD; + } + } else { + extern "C" { + pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; + } + } +} + +extern "C" { + pub fn SSL_set_connect_state(s: *mut SSL); + pub fn SSL_set_accept_state(s: *mut SSL); + + #[cfg(not(ossl110))] + pub fn SSL_library_init() -> c_int; + + pub fn SSL_CIPHER_description( + cipher: *const SSL_CIPHER, + buf: *mut c_char, + size: c_int, + ) -> *mut c_char; + + pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; +} +cfg_if! { + if #[cfg(any(ossl102, libressl280))] { + extern "C" { + pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; + } + } else { + extern "C" { + pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; + } + } +} + +extern "C" { + #[cfg(ossl102)] + pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; + #[cfg(ossl102)] + pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; + + pub fn SSL_set_shutdown(ss: *mut SSL, mode: c_int); + pub fn SSL_get_shutdown(ssl: *const SSL) -> c_int; + pub fn SSL_version(ssl: *const SSL) -> c_int; + pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; + pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX; + pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; + + pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; + #[cfg(ossl110)] + pub fn SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509; + + #[cfg(ossl110)] + pub fn SSL_get_client_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + #[cfg(ossl110)] + pub fn SSL_get_server_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + #[cfg(any(ossl110, libressl273))] + pub fn SSL_SESSION_get_master_key( + session: *const SSL_SESSION, + out: *mut c_uchar, + outlen: size_t, + ) -> size_t; +} + +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_get_ex_new_index( + l: c_long, + p: *mut c_void, + newf: Option, + dupf: Option, + freef: Option, + ) -> c_int { + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, l, p, newf, dupf, freef) + } + } else { + extern "C" { + pub fn SSL_get_ex_new_index( + argl: c_long, + argp: *mut c_void, + new_func: Option, + dup_func: Option, + free_func: Option, + ) -> c_int; + } + } +} +extern "C" { + pub fn SSL_set_ex_data(ssl: *mut SSL, idx: c_int, data: *mut c_void) -> c_int; + pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; +} +cfg_if! { + if #[cfg(ossl110)] { + pub unsafe fn SSL_CTX_get_ex_new_index( + l: c_long, + p: *mut c_void, + newf: Option, + dupf: Option, + freef: Option, + ) -> c_int { + CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, l, p, newf, dupf, freef) + } + } else { + extern "C" { + pub fn SSL_CTX_get_ex_new_index( + argl: c_long, + argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>, + ) -> c_int; + } + } +} +extern "C" { + pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int; + pub fn SSL_CTX_get_ex_data(ctx: *const SSL_CTX, idx: c_int) -> *mut c_void; + + pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; +} + +pub unsafe fn SSL_CTX_sess_set_cache_size(ctx: *mut SSL_CTX, t: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_SIZE, t, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_sess_get_cache_size(ctx: *mut SSL_CTX) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_SESS_CACHE_SIZE, 0, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_set_session_cache_mode(ctx: *mut SSL_CTX, m: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SESS_CACHE_MODE, m, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_set_read_ahead(ctx: *mut SSL_CTX, m: c_long) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_READ_AHEAD, m, ptr::null_mut()) +} + +extern "C" { + // FIXME should take an option + pub fn SSL_CTX_set_tmp_dh_callback( + ctx: *mut SSL_CTX, + dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + ); + // FIXME should take an option + pub fn SSL_set_tmp_dh_callback( + ctx: *mut SSL, + dh: unsafe extern "C" fn(ssl: *mut SSL, is_export: c_int, keylength: c_int) -> *mut DH, + ); + // FIXME should take an option + #[cfg(not(ossl110))] + pub fn SSL_CTX_set_tmp_ecdh_callback( + ctx: *mut ::SSL_CTX, + ecdh: unsafe extern "C" fn( + ssl: *mut ::SSL, + is_export: c_int, + keylength: c_int, + ) -> *mut ::EC_KEY, + ); + // FIXME should take an option + #[cfg(not(ossl110))] + pub fn SSL_set_tmp_ecdh_callback( + ssl: *mut SSL, + ecdh: unsafe extern "C" fn( + ssl: *mut SSL, + is_export: c_int, + keylength: c_int, + ) -> *mut EC_KEY, + ); +} + +cfg_if! { + if #[cfg(libressl)] { + extern "C" { + pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const libc::c_void; + } + } else if #[cfg(osslconf = "OPENSSL_NO_COMP")] { + } else if #[cfg(ossl111b)] { + extern "C" { + pub fn SSL_get_current_compression(ssl: *const SSL) -> *const COMP_METHOD; + } + } else { + extern "C" { + pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; + } + } +} +cfg_if! { + if #[cfg(libressl)] { + extern "C" { + pub fn SSL_COMP_get_name(comp: *const libc::c_void) -> *const c_char; + } + } else if #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] { + extern "C" { + pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; + } + } +} + +extern "C" { + #[cfg(ossl110)] + pub fn SSL_CIPHER_get_cipher_nid(c: *const SSL_CIPHER) -> c_int; + #[cfg(ossl110)] + pub fn SSL_CIPHER_get_digest_nid(c: *const SSL_CIPHER) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn SSL_session_reused(ssl: *mut SSL) -> c_int; + } + } else { + pub unsafe fn SSL_session_reused(ssl: *mut SSL) -> c_int { + SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int + } + } +} +cfg_if! { + if #[cfg(any(ossl110f, libressl273))] { + extern "C" { + pub fn SSL_is_server(s: *const SSL) -> c_int; + } + } else if #[cfg(ossl102)] { + extern "C" { + pub fn SSL_is_server(s: *mut SSL) -> c_int; + } + } +} + +#[cfg(ossl110)] +pub const OPENSSL_INIT_LOAD_SSL_STRINGS: u64 = 0x00200000; + +extern "C" { + #[cfg(ossl110)] + pub fn OPENSSL_init_ssl(opts: u64, settings: *const OPENSSL_INIT_SETTINGS) -> c_int; +} diff --git a/openssl-sys/src/ssl3.rs b/openssl-sys/src/ssl3.rs new file mode 100644 index 000000000..822613eb2 --- /dev/null +++ b/openssl-sys/src/ssl3.rs @@ -0,0 +1,5 @@ +use libc::*; + +pub const SSL3_VERSION: c_int = 0x300; + +pub const SSL3_AD_ILLEGAL_PARAMETER: c_int = 47; diff --git a/openssl-sys/src/stack.rs b/openssl-sys/src/stack.rs new file mode 100644 index 000000000..7f2feef6d --- /dev/null +++ b/openssl-sys/src/stack.rs @@ -0,0 +1,45 @@ +use libc::*; + +cfg_if! { + if #[cfg(ossl110)] { + pub enum OPENSSL_STACK {} + } else { + #[repr(C)] + pub struct _STACK { + pub num: c_int, + pub data: *mut *mut c_char, + pub sorted: c_int, + pub num_alloc: c_int, + pub comp: Option c_int>, + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn OPENSSL_sk_num(stack: *const OPENSSL_STACK) -> c_int; + pub fn OPENSSL_sk_value(stack: *const OPENSSL_STACK, idx: c_int) -> *mut c_void; + + pub fn OPENSSL_sk_new_null() -> *mut OPENSSL_STACK; + pub fn OPENSSL_sk_free(st: *mut OPENSSL_STACK); + pub fn OPENSSL_sk_pop_free( + st: *mut OPENSSL_STACK, + free: Option, + ); + pub fn OPENSSL_sk_push(st: *mut OPENSSL_STACK, data: *const c_void) -> c_int; + pub fn OPENSSL_sk_pop(st: *mut OPENSSL_STACK) -> *mut c_void; + } + } else { + extern "C" { + pub fn sk_num(st: *const _STACK) -> c_int; + pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; + + pub fn sk_new_null() -> *mut _STACK; + pub fn sk_free(st: *mut _STACK); + pub fn sk_pop_free(st: *mut _STACK, free: Option); + pub fn sk_push(st: *mut _STACK, data: *mut c_void) -> c_int; + pub fn sk_pop(st: *mut _STACK) -> *mut c_void; + } + } +} diff --git a/openssl-sys/src/tls1.rs b/openssl-sys/src/tls1.rs new file mode 100644 index 000000000..c336257d4 --- /dev/null +++ b/openssl-sys/src/tls1.rs @@ -0,0 +1,111 @@ +use libc::*; +use std::mem; +use std::ptr; + +use *; + +pub const TLS1_VERSION: c_int = 0x301; +pub const TLS1_1_VERSION: c_int = 0x302; +pub const TLS1_2_VERSION: c_int = 0x303; +#[cfg(ossl111)] +pub const TLS1_3_VERSION: c_int = 0x304; + +pub const TLS1_AD_DECODE_ERROR: c_int = 50; +pub const TLS1_AD_UNRECOGNIZED_NAME: c_int = 112; + +pub const TLSEXT_NAMETYPE_host_name: c_int = 0; +pub const TLSEXT_STATUSTYPE_ocsp: c_int = 1; + +extern "C" { + pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; + + pub fn SSL_export_keying_material( + s: *mut SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + use_context: c_int, + ) -> c_int; + + #[cfg(ossl111)] + pub fn SSL_export_keying_material_early( + s: *mut ::SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + ) -> c_int; +} + +pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long { + SSL_ctrl( + s, + SSL_CTRL_SET_TLSEXT_HOSTNAME, + TLSEXT_NAMETYPE_host_name as c_long, + name as *mut c_void, + ) +} + +pub unsafe fn SSL_set_tlsext_status_type(s: *mut SSL, type_: c_int) -> c_long { + SSL_ctrl( + s, + SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, + type_ as c_long, + ptr::null_mut(), + ) +} + +pub unsafe fn SSL_get_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut *mut c_uchar) -> c_long { + SSL_ctrl( + ssl, + SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, + 0, + resp as *mut c_void, + ) +} + +pub unsafe fn SSL_set_tlsext_status_ocsp_resp( + ssl: *mut SSL, + resp: *mut c_uchar, + len: c_long, +) -> c_long { + SSL_ctrl( + ssl, + SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, + len, + resp as *mut c_void, + ) +} + +pub unsafe fn SSL_CTX_set_tlsext_servername_callback( + ctx: *mut SSL_CTX, + // FIXME should have the right signature + cb: Option, +) -> c_long { + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb) +} + +pub const SSL_TLSEXT_ERR_OK: c_int = 0; +pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; +pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; +pub const SSL_TLSEXT_ERR_NOACK: c_int = 3; + +pub unsafe fn SSL_CTX_set_tlsext_servername_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_cb( + ctx: *mut SSL_CTX, + cb: Option c_int>, +) -> c_long { + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, mem::transmute(cb)) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG, 0, arg) +} diff --git a/openssl-sys/src/x509.rs b/openssl-sys/src/x509.rs new file mode 100644 index 000000000..d9f4aae41 --- /dev/null +++ b/openssl-sys/src/x509.rs @@ -0,0 +1,349 @@ +use libc::*; + +use *; + +pub const X509_FILETYPE_PEM: c_int = 1; +pub const X509_FILETYPE_ASN1: c_int = 2; +pub const X509_FILETYPE_DEFAULT: c_int = 3; + +#[repr(C)] +pub struct X509_VAL { + pub notBefore: *mut ASN1_TIME, + pub notAfter: *mut ASN1_TIME, +} + +pub enum X509_NAME_ENTRY {} + +stack!(stack_st_X509_NAME); + +pub enum X509_EXTENSION {} + +stack!(stack_st_X509_EXTENSION); + +stack!(stack_st_X509_ATTRIBUTE); + +cfg_if! { + if #[cfg(ossl110)] { + pub enum X509_REQ_INFO {} + } else { + #[repr(C)] + pub struct X509_REQ_INFO { + pub enc: ASN1_ENCODING, + pub version: *mut ::ASN1_INTEGER, + pub subject: *mut ::X509_NAME, + pubkey: *mut c_void, + pub attributes: *mut stack_st_X509_ATTRIBUTE, + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + pub enum X509_REQ {} + } else { + #[repr(C)] + pub struct X509_REQ { + pub req_info: *mut X509_REQ_INFO, + sig_alg: *mut c_void, + signature: *mut c_void, + references: c_int, + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + pub enum X509_CINF {} + } else { + #[repr(C)] + pub struct X509_CINF { + version: *mut c_void, + serialNumber: *mut c_void, + signature: *mut c_void, + issuer: *mut c_void, + pub validity: *mut X509_VAL, + subject: *mut c_void, + key: *mut c_void, + issuerUID: *mut c_void, + subjectUID: *mut c_void, + pub extensions: *mut stack_st_X509_EXTENSION, + enc: ASN1_ENCODING, + } + } +} + +stack!(stack_st_X509); + +extern "C" { + pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char; + + pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + + pub fn X509_digest( + x: *const X509, + digest: *const EVP_MD, + buf: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; + + pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + + pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; + pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; + pub fn i2d_PrivateKey_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; + pub fn i2d_PUBKEY_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; + + pub fn i2d_PUBKEY(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; + pub fn d2i_PUBKEY(k: *mut *mut EVP_PKEY, buf: *mut *const u8, len: c_long) -> *mut EVP_PKEY; + pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int; + pub fn d2i_DSA_PUBKEY(k: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn i2d_DSA_PUBKEY(a: *mut DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn i2d_PrivateKey(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; + + pub fn d2i_ECPrivateKey( + k: *mut *mut EC_KEY, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut EC_KEY; + pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int; +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn X509_ALGOR_get0( + paobj: *mut *const ASN1_OBJECT, + pptype: *mut c_int, + ppval: *mut *const c_void, + alg: *const X509_ALGOR, + ); + } + } else if #[cfg(ossl102)] { + extern "C" { + pub fn X509_ALGOR_get0( + paobj: *mut *mut ASN1_OBJECT, + pptype: *mut c_int, + ppval: *mut *mut c_void, + alg: *mut X509_ALGOR, + ); + } + } +} + +extern "C" { + pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; + + pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; + + pub fn X509_ALGOR_free(x: *mut X509_ALGOR); + + pub fn X509_REQ_new() -> *mut X509_REQ; + pub fn X509_REQ_free(x: *mut X509_REQ); + pub fn d2i_X509_REQ( + a: *mut *mut X509_REQ, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_REQ; + pub fn i2d_X509_REQ(x: *mut X509_REQ, buf: *mut *mut u8) -> c_int; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + extern "C" { + pub fn X509_get0_signature( + psig: *mut *const ASN1_BIT_STRING, + palg: *mut *const X509_ALGOR, + x: *const X509, + ); + } + } else if #[cfg(ossl102)] { + extern "C" { + pub fn X509_get0_signature( + psig: *mut *mut ASN1_BIT_STRING, + palg: *mut *mut X509_ALGOR, + x: *const X509, + ); + } + } +} +extern "C" { + #[cfg(ossl102)] + pub fn X509_get_signature_nid(x: *const X509) -> c_int; + + pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + + pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); + + pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_free(x: *mut X509_NAME); + + pub fn X509_new() -> *mut X509; + pub fn X509_free(x: *mut X509); + pub fn i2d_X509(x: *mut X509, buf: *mut *mut u8) -> c_int; + pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; + + pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY; + + pub fn X509_set_version(x: *mut X509, version: c_long) -> c_int; + pub fn X509_set_serialNumber(x: *mut X509, sn: *mut ASN1_INTEGER) -> c_int; + pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; + pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509_get_issuer_name(x: *const ::X509) -> *mut ::X509_NAME; + } + } else { + extern "C" { + pub fn X509_get_issuer_name(x: *mut ::X509) -> *mut ::X509_NAME; + } + } +} +extern "C" { + pub fn X509_set_subject_name(x: *mut X509, name: *mut X509_NAME) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509_get_subject_name(x: *const ::X509) -> *mut ::X509_NAME; + } + } else { + extern "C" { + pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; + } + } +} +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn X509_set1_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set1_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + } + } else { + extern "C" { + pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + } + } +} +extern "C" { + #[cfg(ossl110)] + pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long; + pub fn X509_REQ_set_version(req: *mut X509_REQ, version: c_long) -> c_int; + #[cfg(ossl110)] + pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut X509_NAME; + pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut X509_NAME) -> c_int; + pub fn X509_REQ_set_pubkey(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_REQ_get_pubkey(req: *mut X509_REQ) -> *mut EVP_PKEY; + pub fn X509_REQ_get_extensions(req: *mut X509_REQ) -> *mut stack_st_X509_EXTENSION; + pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) + -> c_int; + pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; + #[cfg(any(ossl110, libressl273))] + pub fn X509_getm_notBefore(x: *const X509) -> *mut ASN1_TIME; + #[cfg(any(ossl110, libressl273))] + pub fn X509_getm_notAfter(x: *const X509) -> *mut ASN1_TIME; + #[cfg(any(ossl110, libressl273))] + pub fn X509_up_ref(x: *mut X509) -> c_int; + + #[cfg(ossl110)] + pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509_NAME_entry_count(n: *const X509_NAME) -> c_int; + } + } else { + extern "C" { + pub fn X509_NAME_entry_count(n: *mut X509_NAME) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(libressl280)] { + extern "C" { + pub fn X509_NAME_get_index_by_NID(n: *const X509_NAME, nid: c_int, last_pos: c_int) -> c_int; + } + } else { + extern "C" { + pub fn X509_NAME_get_index_by_NID(n: *mut X509_NAME, nid: c_int, last_pos: c_int) -> c_int; + } + } +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509_NAME_get_entry(n: *const X509_NAME, loc: c_int) -> *mut X509_NAME_ENTRY; + pub fn X509_NAME_add_entry_by_NID( + x: *mut X509_NAME, + field: c_int, + ty: c_int, + bytes: *const c_uchar, + len: c_int, + loc: c_int, + set: c_int, + ) -> c_int; + pub fn X509_NAME_ENTRY_get_object(ne: *const X509_NAME_ENTRY) -> *mut ASN1_OBJECT; + pub fn X509_NAME_ENTRY_get_data(ne: *const X509_NAME_ENTRY) -> *mut ASN1_STRING; + } + } else { + extern "C" { + pub fn X509_NAME_get_entry(n: *mut X509_NAME, loc: c_int) -> *mut X509_NAME_ENTRY; + pub fn X509_NAME_add_entry_by_NID( + x: *mut X509_NAME, + field: c_int, + ty: c_int, + bytes: *mut c_uchar, + len: c_int, + loc: c_int, + set: c_int, + ) -> c_int; + pub fn X509_NAME_ENTRY_get_object(ne: *mut X509_NAME_ENTRY) -> *mut ASN1_OBJECT; + pub fn X509_NAME_ENTRY_get_data(ne: *mut X509_NAME_ENTRY) -> *mut ASN1_STRING; + } + } +} +extern "C" { + pub fn X509_NAME_add_entry_by_txt( + x: *mut X509_NAME, + field: *const c_char, + ty: c_int, + bytes: *const c_uchar, + len: c_int, + loc: c_int, + set: c_int, + ) -> c_int; + + pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; +} +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509_get_ext_d2i( + x: *const ::X509, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + } + } else { + extern "C" { + pub fn X509_get_ext_d2i( + x: *mut ::X509, + nid: c_int, + crit: *mut c_int, + idx: *mut c_int, + ) -> *mut c_void; + } + } +} + +extern "C" { + pub fn X509_verify_cert(ctx: *mut X509_STORE_CTX) -> c_int; +} diff --git a/openssl-sys/src/x509_vfy.rs b/openssl-sys/src/x509_vfy.rs new file mode 100644 index 000000000..73d97091d --- /dev/null +++ b/openssl-sys/src/x509_vfy.rs @@ -0,0 +1,153 @@ +use libc::*; + +use *; + +#[cfg(any(libressl, all(ossl102, not(ossl110))))] +pub enum X509_VERIFY_PARAM_ID {} + +pub const X509_V_OK: c_int = 0; +#[cfg(ossl102f)] +pub const X509_V_ERR_UNSPECIFIED: c_int = 1; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; +pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; +pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; +pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; +pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; +pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; +pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; +pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; +pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; +pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; +pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; +pub const X509_V_ERR_OUT_OF_MEM: c_int = 17; +pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; +pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; +pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; +pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; +pub const X509_V_ERR_CERT_REVOKED: c_int = 23; +pub const X509_V_ERR_INVALID_CA: c_int = 24; +pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; +pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26; +pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27; +pub const X509_V_ERR_CERT_REJECTED: c_int = 28; +pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; +pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; +pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; +pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; +pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; +pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; +pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; +pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; +pub const X509_V_ERR_INVALID_NON_CA: c_int = 37; +pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; +pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; +pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; +pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41; +pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; +pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; +pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; +pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; +pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; +pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; +pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; +pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49; +pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; +pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; +pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_VERSION: c_int = 56; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_ALGORITHM: c_int = 57; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_CURVE: c_int = 58; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: c_int = 59; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: c_int = 60; +#[cfg(ossl102)] +pub const X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: c_int = 61; +#[cfg(ossl102)] +pub const X509_V_ERR_HOSTNAME_MISMATCH: c_int = 62; +#[cfg(ossl102)] +pub const X509_V_ERR_EMAIL_MISMATCH: c_int = 63; +#[cfg(ossl102)] +pub const X509_V_ERR_IP_ADDRESS_MISMATCH: c_int = 64; +cfg_if! { + if #[cfg(ossl110)] { + pub const X509_V_ERR_DANE_NO_MATCH: c_int = 65; + pub const X509_V_ERR_EE_KEY_TOO_SMALL: c_int = 66; + pub const X509_V_ERR_CA_KEY_TOO_SMALL: c_int = 67; + pub const X509_V_ERR_CA_MD_TOO_WEAK: c_int = 68; + pub const X509_V_ERR_INVALID_CALL: c_int = 69; + pub const X509_V_ERR_STORE_LOOKUP: c_int = 70; + pub const X509_V_ERR_NO_VALID_SCTS: c_int = 71; + } else if #[cfg(ossl102h)] { + pub const X509_V_ERR_INVALID_CALL: c_int = 65; + pub const X509_V_ERR_STORE_LOOKUP: c_int = 66; + pub const X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION: c_int = 67; + } +} + +extern "C" { + pub fn X509_STORE_new() -> *mut X509_STORE; + pub fn X509_STORE_free(store: *mut X509_STORE); + + pub fn X509_STORE_CTX_new() -> *mut X509_STORE_CTX; + + pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX); + pub fn X509_STORE_CTX_init( + ctx: *mut X509_STORE_CTX, + store: *mut X509_STORE, + x509: *mut X509, + chain: *mut stack_st_X509, + ) -> c_int; + pub fn X509_STORE_CTX_cleanup(ctx: *mut X509_STORE_CTX); + + pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int; + + pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int; + + pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; + pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; + pub fn X509_STORE_CTX_set_error(ctx: *mut X509_STORE_CTX, error: c_int); + pub fn X509_STORE_CTX_get_error_depth(ctx: *mut X509_STORE_CTX) -> c_int; + pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509; +} +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn X509_STORE_CTX_get0_chain(ctx: *mut X509_STORE_CTX) -> *mut stack_st_X509; + } + } else { + extern "C" { + pub fn X509_STORE_CTX_get_chain(ctx: *mut X509_STORE_CTX) -> *mut stack_st_X509; + } + } +} + +extern "C" { + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); + + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set1_host( + param: *mut X509_VERIFY_PARAM, + name: *const c_char, + namelen: size_t, + ) -> c_int; + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); + #[cfg(any(ossl102, libressl261))] + pub fn X509_VERIFY_PARAM_set1_ip( + param: *mut X509_VERIFY_PARAM, + ip: *const c_uchar, + iplen: size_t, + ) -> c_int; +} diff --git a/openssl-sys/src/x509v3.rs b/openssl-sys/src/x509v3.rs new file mode 100644 index 000000000..dc936c4ce --- /dev/null +++ b/openssl-sys/src/x509v3.rs @@ -0,0 +1,93 @@ +use libc::*; + +use *; + +pub enum CONF_METHOD {} + +pub const GEN_OTHERNAME: c_int = 0; +pub const GEN_EMAIL: c_int = 1; +pub const GEN_DNS: c_int = 2; +pub const GEN_X400: c_int = 3; +pub const GEN_DIRNAME: c_int = 4; +pub const GEN_EDIPARTY: c_int = 5; +pub const GEN_URI: c_int = 6; +pub const GEN_IPADD: c_int = 7; +pub const GEN_RID: c_int = 8; + +#[repr(C)] +pub struct GENERAL_NAME { + pub type_: c_int, + // FIXME should be a union + pub d: *mut c_void, +} + +stack!(stack_st_GENERAL_NAME); + +extern "C" { + pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); +} + +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; +#[cfg(any(ossl102, libressl261))] +pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; +#[cfg(ossl110)] +pub const X509_CHECK_FLAG_NEVER_CHECK_SUBJECT: c_uint = 0x20; + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn X509V3_EXT_nconf_nid( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + ext_nid: c_int, + value: *const c_char, + ) -> *mut X509_EXTENSION; + pub fn X509V3_EXT_nconf( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + name: *const c_char, + value: *const c_char, + ) -> *mut X509_EXTENSION; + } + } else { + extern "C" { + pub fn X509V3_EXT_nconf_nid( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + ext_nid: c_int, + value: *mut c_char, + ) -> *mut X509_EXTENSION; + pub fn X509V3_EXT_nconf( + conf: *mut CONF, + ctx: *mut X509V3_CTX, + name: *mut c_char, + value: *mut c_char, + ) -> *mut X509_EXTENSION; + } + } +} + +extern "C" { + pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int; + pub fn X509_verify(req: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + + pub fn X509V3_set_nconf(ctx: *mut X509V3_CTX, conf: *mut CONF); + + pub fn X509V3_set_ctx( + ctx: *mut X509V3_CTX, + issuer: *mut X509, + subject: *mut X509, + req: *mut X509_REQ, + crl: *mut X509_CRL, + flags: c_int, + ); + + pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING; +} diff --git a/openssl/.cargo-checksum.json b/openssl/.cargo-checksum.json new file mode 100644 index 000000000..228b42fde --- /dev/null +++ b/openssl/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"97c140cbb82f3b3468193dd14c1b88def39f341f68257f8a7fe8ed9ed3f628a5"} \ No newline at end of file diff --git a/openssl/.pc/.quilt_patches b/openssl/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/openssl/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/openssl/.pc/.quilt_series b/openssl/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/openssl/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/openssl/.pc/.version b/openssl/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/openssl/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/openssl/.pc/applied-patches b/openssl/.pc/applied-patches new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/openssl/.pc/applied-patches @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/openssl/.pc/disable-vendor.patch/.timestamp b/openssl/.pc/disable-vendor.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/openssl/.pc/disable-vendor.patch/Cargo.toml b/openssl/.pc/disable-vendor.patch/Cargo.toml new file mode 100644 index 000000000..2c7ed3307 --- /dev/null +++ b/openssl/.pc/disable-vendor.patch/Cargo.toml @@ -0,0 +1,51 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "openssl" +version = "0.10.23" +authors = ["Steven Fackler "] +description = "OpenSSL bindings" +readme = "README.md" +keywords = ["crypto", "tls", "ssl", "dtls"] +categories = ["cryptography", "api-bindings"] +license = "Apache-2.0" +repository = "https://github.com/sfackler/rust-openssl" +[dependencies.bitflags] +version = "1.0" + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.foreign-types] +version = "0.3.1" + +[dependencies.lazy_static] +version = "1" + +[dependencies.libc] +version = "0.2" + +[dependencies.openssl-sys] +version = "0.9.47" +[dev-dependencies.hex] +version = "0.3" + +[dev-dependencies.tempdir] +version = "0.3" + +[features] +v101 = [] +v102 = [] +v110 = [] +v111 = [] +vendored = ["openssl-sys/vendored"] diff --git a/openssl/CHANGELOG.md b/openssl/CHANGELOG.md new file mode 100644 index 000000000..53cf1ec74 --- /dev/null +++ b/openssl/CHANGELOG.md @@ -0,0 +1,397 @@ +# Change Log + +## [Unreleased] + +## [v0.10.23] + +### Fixed + +* Fixed session callbacks when an `Ssl`'s context is replaced. + +### Added + +* Added `SslContextBuilder::add_client_ca`. + +## [v0.10.22] + +### Added + +* Added support for the LibreSSL 2.9.x series. + +## [v0.10.21] - 2019-04-30 + +### Fixed + +* Fixed overly conservatifve buffer size checks in `Crypter` when using stream ciphers. + +### Added + +* Added bindings to envelope encryption APIs. +* Added `PkeyRef::size`. + +## [v0.10.20] - 2019-03-20 + +### Added + +* Added `CmsContentInfo::from_der` and `CmsContentInfo::encrypt`. +* Added `X509Ref::verify` and `X509ReqRef::verify`. +* Implemented `PartialEq` and `Eq` for `MessageDigest`. +* Added `MessageDigest::type_` and `EcGroupRef::curve_name`. + +## [v0.10.19] - 2019-03-01 + +### Added + +* The openssl-sys build script now logs the values of environment variables. +* Added `ERR_PACK` to openssl-sys. +* The `ERR_*` functions in openssl-sys are const functions when building against newer Rust versions. +* Implemented `Clone` for `Dsa`. +* Added `SslContextRef::add_session` and `SslContextRef::remove_session`. +* Added `SslSessionRef::time`, `SslSessionRef::timeout`, and `SslSessionRef::protocol_version`. +* Added `SslContextBuilder::set_session_cache_size` and `SslContextRef::session_cache_size`. + +## [v0.10.18] - 2019-02-22 + +### Fixed + +* Fixed the return type of `ssl::cipher_name`. + +## [v0.10.17] - 2019-02-22 + +### Added + +* Implemented `AsRef` and `AsRef<[u8]>` for `OpenSslString`. +* Added `Asn1Integer::from_bn`. +* Added `RsaRef::check_key`. +* Added `Asn1Time::from_str` and `Asn1Time::from_str_x509`. +* Added `Rsa::generate_with_e`. +* Added `Cipher::des_ede3_cfb64`. +* Added `SslCipherRef::standard_name` and `ssl::cipher_name`. + +## [v0.10.16] - 2018-12-16 + +### Added + +* Added SHA3 and SHAKE to `MessageDigest`. +* Added `rand::keep_random_devices_open`. +* Added support for LibreSSL 2.9.0. + +## [v0.10.15] - 2018-10-22 + +### Added + +* Implemented `DoubleEndedIterator` for stack iterators. + +## [v0.10.14] - 2018-10-18 + +### Fixed + +* Made some accidentally exposed internal functions private. + +### Added + +* Added support for LibreSSL 2.8. + +### Changed + +* The OpenSSL version used with the `vendored` feature has been upgraded from 1.1.0 to 1.1.1. + +## [v0.10.13] - 2018-10-14 + +### Fixed + +* Fixed a double-free in the `SslContextBuilder::set_get_session_callback` API. + +### Added + +* Added `SslContextBuilder::set_client_hello_callback`. +* Added support for LibreSSL 2.8.1. +* Added `EcdsaSig::from_der` and `EcdsaSig::to_der`. +* Added PKCS#7 support. + +## [v0.10.12] - 2018-09-13 + +### Fixed + +* Fixed handling of SNI callbacks during renegotiation. + +### Added + +* Added `SslRef::get_shutdown` and `SslRef::set_shutdown`. +* Added support for SRTP in DTLS sessions. +* Added support for LibreSSL 2.8.0. + +## [v0.10.11] - 2018-08-04 + +### Added + +* The new `vendored` cargo feature will cause openssl-sys to compile and statically link to a + vendored copy of OpenSSL. +* Added `SslContextBuilder::set_psk_server_callback`. +* Added `DsaRef::pub_key` and `DsaRef::priv_key`. +* Added `Dsa::from_private_components` and `Dsa::from_public_components`. +* Added `X509NameRef::entries`. + +### Deprecated + +* `SslContextBuilder::set_psk_callback` has been renamed to + `SslContextBuilder::set_psk_client_callback` and deprecated. + +## [v0.10.10] - 2018-06-06 + +### Added + +* Added `SslRef::set_alpn_protos`. +* Added `SslContextBuilder::set_ciphersuites`. + +## [v0.10.9] - 2018-06-01 + +### Fixed + +* Fixed a use-after-free in `CmsContentInfo::sign`. +* `SslRef::servername` now returns `None` rather than panicking on a non-UTF8 name. + +### Added + +* Added `MessageDigest::from_nid`. +* Added `Nid::signature_algorithms`, `Nid::long_name`, and `Nid::short_name`. +* Added early data and early keying material export support for TLS 1.3. +* Added `SslRef::verified_chain`. +* Added `SslRef::servername_raw` which returns a `&[u8]` rather than `&str`. +* Added `SslRef::finished` and `SslRef::peer_finished`. +* Added `X509Ref::digest` to replace `X509Ref::fingerprint`. +* `X509StoreBuilder` and `X509Store` now implement `Sync` and `Send`. + +### Deprecated + +* `X509Ref::fingerprint` has been deprecated in favor of `X509Ref::digest`. + +## [v0.10.8] - 2018-05-20 + +### Fixed + +* `openssl-sys` will now detect Homebrew-installed OpenSSL when installed to a non-default + directory. +* The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and + `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when + building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` are only present + when building against 1.1.0g and up rather than 1.1.0. + +### Added + +* Added `CmsContentInfo::sign`. +* Added `Clone` and `ToOwned` implementations to `Rsa` and `RsaRef` respectively. +* The `min_proto_version` and `max_proto_version` methods are available when linking against + LibreSSL 2.6.1 and up in addition to OpenSSL. +* `X509VerifyParam` is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* ALPN support is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* `Stack` and `StackRef` are now `Sync` and `Send`. + +## [v0.10.7] - 2018-04-30 + +### Added + +* Added `X509Req::public_key` and `X509Req::extensions`. +* Added `RsaPrivateKeyBuilder` to allow control over initialization of optional components of an RSA + private key. +* Added DER encode/decode support to `SslSession`. +* openssl-sys now provides the `DEP_OPENSSL_VERSION_NUMBER` and + `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` environment variables to downstream build scripts which + contains the hex-encoded version number of the OpenSSL or LibreSSL distribution being built + against. The other variables are deprecated. + +## [v0.10.6] - 2018-03-05 + +### Added + +* Added `SslOptions::ENABLE_MIDDLEBOX_COMPAT`. +* Added more `Sync` and `Send` implementations. +* Added `PKeyRef::id`. +* Added `Padding::PKCS1_PSS`. +* Added `Signer::set_rsa_pss_saltlen`, `Signer::set_rsa_mgf1_md`, `Signer::set_rsa_pss_saltlen`, and + `Signer::set_rsa_mgf1_md` +* Added `X509StoreContextRef::verify` to directly verify certificates. +* Added low level ECDSA support. +* Added support for TLSv1.3 custom extensions. (OpenSSL 1.1.1 only) +* Added AES-CCM support. +* Added `EcKey::from_private_components`. +* Added CMAC support. +* Added support for LibreSSL 2.7. +* Added `X509Ref::serial_number`. +* Added `Asn1IntegerRef::to_bn`. +* Added support for TLSv1.3 stateless handshakes. (OpenSSL 1.1.1 only) + +### Changed + +* The Cargo features previously used to gate access to version-specific OpenSSL APIs have been + removed. Those APIs will be available automatically when building against an appropriate OpenSSL + version. +* Fixed `PKey::private_key_from_der` to return a `PKey` rather than a `PKey`. This + is technically a breaking change but the function was pretty useless previously. + +### Deprecated + +* `X509CheckFlags::FLAG_NO_WILDCARDS` has been renamed to `X509CheckFlags::NO_WILDCARDS` and the old + name deprecated. + +## [v0.10.5] - 2018-02-28 + +### Fixed + +* `ErrorStack`'s `Display` implementation no longer writes an empty string if it contains no errors. + +### Added + +* Added `SslRef::version2`. +* Added `Cipher::des_ede3_cbc`. +* Added `SslRef::export_keying_material`. +* Added the ability to push an `Error` or `ErrorStack` back onto OpenSSL's error stack. Various + callback bindings use this to propagate errors properly. +* Added `SslContextBuilder::set_cookie_generate_cb` and `SslContextBuilder::set_cookie_verify_cb`. +* Added `SslContextBuilder::set_max_proto_version`, `SslContextBuilder::set_min_proto_version`, + `SslContextBuilder::max_proto_version`, and `SslContextBuilder::min_proto_version`. + +### Changed + +* Updated `SslConnector`'s default cipher list to match Python's. + +### Deprecated + +* `SslRef::version` has been deprecated. Use `SslRef::version_str` instead. + +## [v0.10.4] - 2018-02-18 + +### Added + +* Added OpenSSL 1.1.1 support. +* Added `Rsa::public_key_from_pem_pkcs1`. +* Added `SslOptions::NO_TLSV1_3`. (OpenSSL 1.1.1 only) +* Added `SslVersion`. +* Added `SslSessionCacheMode` and `SslContextBuilder::set_session_cache_mode`. +* Added `SslContextBuilder::set_new_session_callback`, + `SslContextBuilder::set_remove_session_callback`, and + `SslContextBuilder::set_get_session_callback`. +* Added `SslContextBuilder::set_keylog_callback`. (OpenSSL 1.1.1 only) +* Added `SslRef::client_random` and `SslRef::server_random`. (OpenSSL 1.1.0+ only) + +### Fixed + +* The `SslAcceptorBuilder::mozilla_modern` constructor now disables TLSv1.0 and TLSv1.1 in + accordance with Mozilla's recommendations. + +## [v0.10.3] - 2018-02-12 + +### Added + +* OpenSSL is now automatically detected on FreeBSD systems. +* Added `GeneralName` accessors for `rfc822Name` and `uri` variants. +* Added DES-EDE3 support. + +### Fixed + +* Fixed a memory leak in `X509StoreBuilder::add_cert`. + +## [v0.10.2] - 2018-01-11 + +### Added + +* Added `ConnectConfiguration::set_use_server_name_indication` and + `ConnectConfiguration::set_verify_hostname` for use in contexts where you don't have ownership + of the `ConnectConfiguration`. + +## [v0.10.1] - 2018-01-10 + +### Added + +* Added a `From for ssl::Error` implementation. + +## [v0.10.0] - 2018-01-10 + +### Compatibility + +* openssl 0.10 still uses openssl-sys 0.9, so openssl 0.9 and 0.10 can coexist without issue. + +### Added + +* The `ssl::select_next_proto` function can be used to easily implement the ALPN selection callback + in a "standard" way. +* FIPS mode support is available in the `fips` module. +* Accessors for the Issuer and Issuer Alternative Name fields of X509 certificates have been added. +* The `X509VerifyResult` can now be set in the certificate verification callback via + `X509StoreContextRef::set_error`. + +### Changed + +* All constants have been moved to associated constants of their type. For example, `bn::MSB_ONE` + is now `bn::MsbOption::ONE`. +* Asymmetric key types are now parameterized over what they contain. In OpenSSL, the same type is + used for key parameters, public keys, and private keys. Unfortunately, some APIs simply assume + that certain components are present and will segfault trying to use things that aren't there. + + The `pkey` module contains new tag types named `Params`, `Public`, and `Private`, and the + `Dh`, `Dsa`, `EcKey`, `Rsa`, and `PKey` have a type parameter set to one of those values. This + allows the `Signer` constructor to indicate that it requires a private key at compile time for + example. Previously, `Signer` would simply segfault if provided a key without private + components. +* ALPN support has been changed to more directly model OpenSSL's own APIs. Instead of a single + method used for both the server and client sides which performed everything automatically, the + `SslContextBuilder::set_alpn_protos` and `SslContextBuilder::set_alpn_select_callback` handle + the client and server sides respectively. +* `SslConnector::danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication` + has been removed in favor of new methods which provide more control. The + `ConnectConfiguration::use_server_name_indication` method controls the use of Server Name + Indication (SNI), and the `ConnectConfiguration::verify_hostname` method controls the use of + hostname verification. These can be controlled independently, and if both are disabled, the + domain argument to `ConnectConfiguration::connect` is ignored. +* Shared secret derivation is now handled by the new `derive::Deriver` type rather than + `pkey::PKeyContext`, which has been removed. +* `ssl::Error` is now no longer an enum, and provides more direct access to the relevant state. +* `SslConnectorBuilder::new` has been moved and renamed to `SslConnector::builder`. +* `SslAcceptorBuilder::mozilla_intermediate` and `SslAcceptorBuilder::mozilla_modern` have been + moved to `SslAcceptor` and no longer take the private key and certificate chain. Install those + manually after creating the builder. +* `X509VerifyError` is now `X509VerifyResult` and can now have the "ok" value in addition to error + values. +* `x509::X509FileType` is now `ssl::SslFiletype`. +* Asymmetric key serialization and deserialization methods now document the formats that they + correspond to, and some have been renamed to better indicate that. + +### Removed + +* All deprecated APIs have been removed. +* NPN support has been removed. It has been supersceded by ALPN, and is hopefully no longer being + used in practice. If you still depend on it, please file an issue! +* `SslRef::compression` has been removed. +* Some `ssl::SslOptions` flags have been removed as they no longer do anything. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.23...master +[v0.10.23]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.22...openssl-v0.10.23 +[v0.10.22]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.21...openssl-v0.10.22 +[v0.10.21]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.20...openssl-v0.10.21 +[v0.10.20]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.19...openssl-v0.10.20 +[v0.10.19]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.18...openssl-v0.10.19 +[v0.10.18]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.17...openssl-v0.10.18 +[v0.10.17]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.16...openssl-v0.10.17 +[v0.10.16]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.15...openssl-v0.10.16 +[v0.10.15]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.14...openssl-v0.10.15 +[v0.10.14]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.13...openssl-v0.10.14 +[v0.10.13]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.12...openssl-v0.10.13 +[v0.10.12]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.11...openssl-v0.10.12 +[v0.10.11]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.10...openssl-v0.10.11 +[v0.10.10]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.9...openssl-v0.10.10 +[v0.10.9]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.9 +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 +[v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 +[v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 +[v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 +[v0.10.4]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.3...openssl-v0.10.4 +[v0.10.3]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.2...openssl-v0.10.3 +[v0.10.2]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.1...openssl-v0.10.2 +[v0.10.1]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.0...openssl-v0.10.1 +[v0.10.0]: https://github.com/sfackler/rust-openssl/compare/v0.9.23...openssl-v0.10.0 +[release tags]: https://github.com/sfackler/rust-openssl/releases diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml new file mode 100644 index 000000000..0cc372308 --- /dev/null +++ b/openssl/Cargo.toml @@ -0,0 +1,51 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "openssl" +version = "0.10.23" +authors = ["Steven Fackler "] +description = "OpenSSL bindings" +readme = "README.md" +keywords = ["crypto", "tls", "ssl", "dtls"] +categories = ["cryptography", "api-bindings"] +license = "Apache-2.0" +repository = "https://github.com/sfackler/rust-openssl" +[dependencies.bitflags] +version = "1.0" + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.foreign-types] +version = "0.3.1" + +[dependencies.lazy_static] +version = "1" + +[dependencies.libc] +version = "0.2" + +[dependencies.openssl-sys] +version = "0.9.47" +[dev-dependencies.hex] +version = "0.3" + +[dev-dependencies.tempdir] +version = "0.3" + +[features] +v101 = [] +v102 = [] +v110 = [] +v111 = [] +vendored = [] diff --git a/openssl/LICENSE b/openssl/LICENSE new file mode 100644 index 000000000..f259067e9 --- /dev/null +++ b/openssl/LICENSE @@ -0,0 +1,15 @@ +Copyright 2011-2017 Google Inc. + 2013 Jack Lloyd + 2013-2014 Steven Fackler + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/openssl/README.md b/openssl/README.md new file mode 100644 index 000000000..2c37c0f78 --- /dev/null +++ b/openssl/README.md @@ -0,0 +1,24 @@ +# rust-openssl + +[![CircleCI](https://circleci.com/gh/sfackler/rust-openssl.svg?style=shield)](https://circleci.com/gh/sfackler/rust-openssl) +[![Build status](https://ci.appveyor.com/api/projects/status/d1knobws948pyynk/branch/master?svg=true)](https://ci.appveyor.com/project/sfackler/rust-openssl/branch/master) +[![crates.io](https://img.shields.io/crates/v/openssl.svg)](https://crates.io/crates/openssl) + +OpenSSL bindings for the Rust programming language. + +[Documentation](https://docs.rs/openssl). + +## Release Support + +The current supported release is 0.10. + +New major versions will be published at most once per year. After a new +release, the previous major version will be partially supported with bug +fixes for 3 months, after which support will be dropped entirely. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed under the terms of both the Apache License, +Version 2.0 and the MIT license without any additional terms or conditions. diff --git a/openssl/build.rs b/openssl/build.rs new file mode 100644 index 000000000..c1a5ccff6 --- /dev/null +++ b/openssl/build.rs @@ -0,0 +1,65 @@ +use std::env; + +fn main() { + if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { + println!("cargo:rustc-cfg=libressl"); + } + + if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION") { + println!("cargo:rustc-cfg=libressl{}", v); + } + + if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { + for var in vars.split(",") { + println!("cargo:rustc-cfg=osslconf=\"{}\"", var); + } + } + + if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x1_00_01_00_0 { + println!("cargo:rustc-cfg=ossl101"); + } + if version >= 0x1_00_02_00_0 { + println!("cargo:rustc-cfg=ossl102"); + } + if version >= 0x1_01_00_00_0 { + println!("cargo:rustc-cfg=ossl110"); + } + if version >= 0x1_01_00_07_0 { + println!("cargo:rustc-cfg=ossl110g"); + } + if version >= 0x1_01_01_00_0 { + println!("cargo:rustc-cfg=ossl111"); + } + } + + if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x2_06_01_00_0 { + println!("cargo:rustc-cfg=libressl261"); + } + + if version >= 0x2_07_00_00_0 { + println!("cargo:rustc-cfg=libressl270"); + } + + if version >= 0x2_07_01_00_0 { + println!("cargo:rustc-cfg=libressl271"); + } + + if version >= 0x2_07_03_00_0 { + println!("cargo:rustc-cfg=libressl273"); + } + + if version >= 0x2_08_00_00_0 { + println!("cargo:rustc-cfg=libressl280"); + } + + if version >= 0x2_09_01_00_0 { + println!("cargo:rustc-cfg=libressl291"); + } + } +} diff --git a/openssl/debian/patches/disable-vendor.patch b/openssl/debian/patches/disable-vendor.patch new file mode 100644 index 000000000..ea37ca5af --- /dev/null +++ b/openssl/debian/patches/disable-vendor.patch @@ -0,0 +1,8 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -51,4 +51,4 @@ + v102 = [] + v110 = [] + v111 = [] +-vendored = ["openssl-sys/vendored"] ++vendored = [] diff --git a/openssl/debian/patches/series b/openssl/debian/patches/series new file mode 100644 index 000000000..1c3e74a43 --- /dev/null +++ b/openssl/debian/patches/series @@ -0,0 +1 @@ +disable-vendor.patch diff --git a/openssl/examples/mk_certs.rs b/openssl/examples/mk_certs.rs new file mode 100644 index 000000000..5c9ec682a --- /dev/null +++ b/openssl/examples/mk_certs.rs @@ -0,0 +1,160 @@ +//! A program that generates ca certs, certs verified by the ca, and public +//! and private keys. + +extern crate openssl; + +use openssl::asn1::Asn1Time; +use openssl::bn::{BigNum, MsbOption}; +use openssl::error::ErrorStack; +use openssl::hash::MessageDigest; +use openssl::pkey::{PKey, PKeyRef, Private}; +use openssl::rsa::Rsa; +use openssl::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; + +/// Make a CA certificate and private key +fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { + let rsa = Rsa::generate(2048)?; + let privkey = PKey::from_rsa(rsa)?; + + let mut x509_name = X509NameBuilder::new()?; + x509_name.append_entry_by_text("C", "US")?; + x509_name.append_entry_by_text("ST", "TX")?; + x509_name.append_entry_by_text("O", "Some CA organization")?; + x509_name.append_entry_by_text("CN", "ca test")?; + let x509_name = x509_name.build(); + + let mut cert_builder = X509::builder()?; + cert_builder.set_version(2)?; + let serial_number = { + let mut serial = BigNum::new()?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; + serial.to_asn1_integer()? + }; + cert_builder.set_serial_number(&serial_number)?; + cert_builder.set_subject_name(&x509_name)?; + cert_builder.set_issuer_name(&x509_name)?; + cert_builder.set_pubkey(&privkey)?; + let not_before = Asn1Time::days_from_now(0)?; + cert_builder.set_not_before(¬_before)?; + let not_after = Asn1Time::days_from_now(365)?; + cert_builder.set_not_after(¬_after)?; + + cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .key_cert_sign() + .crl_sign() + .build()?, + )?; + + let subject_key_identifier = + SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; + cert_builder.append_extension(subject_key_identifier)?; + + cert_builder.sign(&privkey, MessageDigest::sha256())?; + let cert = cert_builder.build(); + + Ok((cert, privkey)) +} + +/// Make a X509 request with the given private key +fn mk_request(privkey: &PKey) -> Result { + let mut req_builder = X509ReqBuilder::new()?; + req_builder.set_pubkey(&privkey)?; + + let mut x509_name = X509NameBuilder::new()?; + x509_name.append_entry_by_text("C", "US")?; + x509_name.append_entry_by_text("ST", "TX")?; + x509_name.append_entry_by_text("O", "Some organization")?; + x509_name.append_entry_by_text("CN", "www.example.com")?; + let x509_name = x509_name.build(); + req_builder.set_subject_name(&x509_name)?; + + req_builder.sign(&privkey, MessageDigest::sha256())?; + let req = req_builder.build(); + Ok(req) +} + +/// Make a certificate and private key signed by the given CA cert and private key +fn mk_ca_signed_cert( + ca_cert: &X509Ref, + ca_privkey: &PKeyRef, +) -> Result<(X509, PKey), ErrorStack> { + let rsa = Rsa::generate(2048)?; + let privkey = PKey::from_rsa(rsa)?; + + let req = mk_request(&privkey)?; + + let mut cert_builder = X509::builder()?; + cert_builder.set_version(2)?; + let serial_number = { + let mut serial = BigNum::new()?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; + serial.to_asn1_integer()? + }; + cert_builder.set_serial_number(&serial_number)?; + cert_builder.set_subject_name(req.subject_name())?; + cert_builder.set_issuer_name(ca_cert.subject_name())?; + cert_builder.set_pubkey(&privkey)?; + let not_before = Asn1Time::days_from_now(0)?; + cert_builder.set_not_before(¬_before)?; + let not_after = Asn1Time::days_from_now(365)?; + cert_builder.set_not_after(¬_after)?; + + cert_builder.append_extension(BasicConstraints::new().build()?)?; + + cert_builder.append_extension( + KeyUsage::new() + .critical() + .non_repudiation() + .digital_signature() + .key_encipherment() + .build()?, + )?; + + let subject_key_identifier = + SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(subject_key_identifier)?; + + let auth_key_identifier = AuthorityKeyIdentifier::new() + .keyid(false) + .issuer(false) + .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(auth_key_identifier)?; + + let subject_alt_name = SubjectAlternativeName::new() + .dns("*.example.com") + .dns("hello.com") + .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(subject_alt_name)?; + + cert_builder.sign(&ca_privkey, MessageDigest::sha256())?; + let cert = cert_builder.build(); + + Ok((cert, privkey)) +} + +fn real_main() -> Result<(), ErrorStack> { + let (ca_cert, ca_privkey) = mk_ca_cert()?; + let (cert, _privkey) = mk_ca_signed_cert(&ca_cert, &ca_privkey)?; + + // Verify that this cert was issued by this ca + match ca_cert.issued(&cert) { + X509VerifyResult::OK => println!("Certificate verified!"), + ver_err => println!("Failed to verify certificate: {}", ver_err), + }; + + Ok(()) +} + +fn main() { + match real_main() { + Ok(()) => println!("Finished."), + Err(e) => println!("Error: {}", e), + }; +} diff --git a/openssl/src/aes.rs b/openssl/src/aes.rs new file mode 100644 index 000000000..de45d2ca6 --- /dev/null +++ b/openssl/src/aes.rs @@ -0,0 +1,169 @@ +//! Low level AES IGE functionality +//! +//! AES ECB, CBC, XTS, CTR, CFB, GCM and other conventional symmetric encryption +//! modes are found in [`symm`]. This is the implementation of AES IGE. +//! +//! Advanced Encryption Standard (AES) provides symmetric key cipher that +//! the same key is used to encrypt and decrypt data. This implementation +//! uses 128, 192, or 256 bit keys. This module provides functions to +//! create a new key with [`new_encrypt`] and perform an encryption/decryption +//! using that key with [`aes_ige`]. +//! +//! [`new_encrypt`]: struct.AesKey.html#method.new_encrypt +//! [`aes_ige`]: fn.aes_ige.html +//! +//! The [`symm`] module should be used in preference to this module in most cases. +//! The IGE block cypher is a non-traditional cipher mode. More traditional AES +//! encryption methods are found in the [`Crypter`] and [`Cipher`] structs. +//! +//! [`symm`]: ../symm/index.html +//! [`Crypter`]: ../symm/struct.Crypter.html +//! [`Cipher`]: ../symm/struct.Cipher.html +//! +//! # Examples +//! +//! ```rust +//! use openssl::aes::{AesKey, aes_ige}; +//! use openssl::symm::Mode; +//! +//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +//! let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56"; +//! let mut iv = *b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\ +//! \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; +//! +//! let key = AesKey::new_encrypt(key).unwrap(); +//! let mut output = [0u8; 16]; +//! aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt); +//! assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32"); +use ffi; +use libc::c_int; +use std::mem; + +use symm::Mode; + +/// Provides Error handling for parsing keys. +#[derive(Debug)] +pub struct KeyError(()); + +/// The key used to encrypt or decrypt cipher blocks. +pub struct AesKey(ffi::AES_KEY); + +impl AesKey { + /// Prepares a key for encryption. + /// + /// # Failure + /// + /// Returns an error if the key is not 128, 192, or 256 bits. + pub fn new_encrypt(key: &[u8]) -> Result { + unsafe { + assert!(key.len() <= c_int::max_value() as usize / 8); + + let mut aes_key = mem::uninitialized(); + let r = ffi::AES_set_encrypt_key( + key.as_ptr() as *const _, + key.len() as c_int * 8, + &mut aes_key, + ); + if r == 0 { + Ok(AesKey(aes_key)) + } else { + Err(KeyError(())) + } + } + } + + /// Prepares a key for decryption. + /// + /// # Failure + /// + /// Returns an error if the key is not 128, 192, or 256 bits. + pub fn new_decrypt(key: &[u8]) -> Result { + unsafe { + assert!(key.len() <= c_int::max_value() as usize / 8); + + let mut aes_key = mem::uninitialized(); + let r = ffi::AES_set_decrypt_key( + key.as_ptr() as *const _, + key.len() as c_int * 8, + &mut aes_key, + ); + + if r == 0 { + Ok(AesKey(aes_key)) + } else { + Err(KeyError(())) + } + } + } +} + +/// Performs AES IGE encryption or decryption +/// +/// AES IGE (Infinite Garble Extension) is a form of AES block cipher utilized in +/// OpenSSL. Infinite Garble referes to propogating forward errors. IGE, like other +/// block ciphers implemented for AES requires an initalization vector. The IGE mode +/// allows a stream of blocks to be encrypted or decrypted without having the entire +/// plaintext available. For more information, visit [AES IGE Encryption]. +/// +/// This block cipher uses 16 byte blocks. The rust implmentation will panic +/// if the input or output does not meet this 16-byte boundry. Attention must +/// be made in this low level implementation to pad the value to the 128-bit boundry. +/// +/// [AES IGE Encryption]: http://www.links.org/files/openssl-ige.pdf +/// +/// # Panics +/// +/// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if +/// `iv` is not at least 32 bytes. +pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) { + unsafe { + assert!(in_.len() == out.len()); + assert!(in_.len() % ffi::AES_BLOCK_SIZE as usize == 0); + assert!(iv.len() >= ffi::AES_BLOCK_SIZE as usize * 2); + + let mode = match mode { + Mode::Encrypt => ffi::AES_ENCRYPT, + Mode::Decrypt => ffi::AES_DECRYPT, + }; + ffi::AES_ige_encrypt( + in_.as_ptr() as *const _, + out.as_mut_ptr() as *mut _, + in_.len(), + &key.0, + iv.as_mut_ptr() as *mut _, + mode, + ); + } +} + +#[cfg(test)] +mod test { + use hex::FromHex; + + use super::*; + use symm::Mode; + + // From https://www.mgp25.com/AESIGE/ + #[test] + fn ige_vector_1() { + let raw_key = "000102030405060708090A0B0C0D0E0F"; + let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; + let raw_pt = "0000000000000000000000000000000000000000000000000000000000000000"; + let raw_ct = "1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB"; + + let key = AesKey::new_encrypt(&Vec::from_hex(raw_key).unwrap()).unwrap(); + let mut iv = Vec::from_hex(raw_iv).unwrap(); + let pt = Vec::from_hex(raw_pt).unwrap(); + let ct = Vec::from_hex(raw_ct).unwrap(); + + let mut ct_actual = vec![0; ct.len()]; + aes_ige(&pt, &mut ct_actual, &key, &mut iv, Mode::Encrypt); + assert_eq!(ct_actual, ct); + + let key = AesKey::new_decrypt(&Vec::from_hex(raw_key).unwrap()).unwrap(); + let mut iv = Vec::from_hex(raw_iv).unwrap(); + let mut pt_actual = vec![0; pt.len()]; + aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt); + assert_eq!(pt_actual, pt); + } +} diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs new file mode 100644 index 000000000..c06a800fe --- /dev/null +++ b/openssl/src/asn1.rs @@ -0,0 +1,394 @@ +#![deny(missing_docs)] + +//! Defines the format of certificiates +//! +//! This module is used by [`x509`] and other certificate building functions +//! to describe time, strings, and objects. +//! +//! Abstract Syntax Notation One is an interface description language. +//! The specification comes from [X.208] by OSI, and rewritten in X.680. +//! ASN.1 describes properties of an object with a type set. Those types +//! can be atomic, structured, choice, and other (CHOICE and ANY). These +//! types are expressed as a number and the assignment operator ::= gives +//! the type a name. +//! +//! The implementation here provides a subset of the ASN.1 types that OpenSSL +//! uses, especially in the properties of a certificate used in HTTPS. +//! +//! [X.208]: https://www.itu.int/rec/T-REC-X.208-198811-W/en +//! [`x509`]: ../x509/struct.X509Builder.html +//! +//! ## Examples +//! +//! ``` +//! use openssl::asn1::Asn1Time; +//! let tomorrow = Asn1Time::days_from_now(1); +//! ``` +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_char, c_int, c_long}; +use std::ffi::CString; +use std::fmt; +use std::ptr; +use std::slice; +use std::str; + +use bio::MemBio; +use bn::{BigNum, BigNumRef}; +use error::ErrorStack; +use nid::Nid; +use string::OpensslString; +use {cvt, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_GENERALIZEDTIME; + fn drop = ffi::ASN1_GENERALIZEDTIME_free; + + /// Non-UTC representation of time + /// + /// If a time can be represented by UTCTime, UTCTime is used + /// otherwise, ASN1_GENERALIZEDTIME is used. This would be, for + /// example outside the year range of 1950-2049. + /// + /// [ASN1_GENERALIZEDTIME_set] documentation from OpenSSL provides + /// further details of implmentation. Note: these docs are from the master + /// branch as documentation on the 1.1.0 branch did not include this page. + /// + /// [ASN1_GENERALIZEDTIME_set]: https://www.openssl.org/docs/manmaster/man3/ASN1_GENERALIZEDTIME_set.html + pub struct Asn1GeneralizedTime; + /// Reference to a [`Asn1GeneralizedTime`] + /// + /// [`Asn1GeneralizedTime`]: struct.Asn1GeneralizedTime.html + pub struct Asn1GeneralizedTimeRef; +} + +impl fmt::Display for Asn1GeneralizedTimeRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let mem_bio = MemBio::new()?; + cvt(ffi::ASN1_GENERALIZEDTIME_print( + mem_bio.as_ptr(), + self.as_ptr(), + ))?; + write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_TIME; + fn drop = ffi::ASN1_TIME_free; + /// Time storage and comparison + /// + /// Asn1Time should be used to store and share time information + /// using certificates. If Asn1Time is set using a string, it must + /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format. + /// + /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementaiton + /// used by OpenSSL. + /// + /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html + pub struct Asn1Time; + /// Reference to an [`Asn1Time`] + /// + /// [`Asn1Time`]: struct.Asn1Time.html + pub struct Asn1TimeRef; +} + +impl fmt::Display for Asn1TimeRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let mem_bio = MemBio::new()?; + cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()))?; + write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + } + } +} + +impl Asn1Time { + fn new() -> Result { + ffi::init(); + + unsafe { + let handle = cvt_p(ffi::ASN1_TIME_new())?; + Ok(Asn1Time::from_ptr(handle)) + } + } + + fn from_period(period: c_long) -> Result { + ffi::init(); + + unsafe { + let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?; + Ok(Asn1Time::from_ptr(handle)) + } + } + + /// Creates a new time on specified interval in days from now + pub fn days_from_now(days: u32) -> Result { + Asn1Time::from_period(days as c_long * 60 * 60 * 24) + } + + /// Creates a new time corresponding to the specified ASN1 time string. + /// + /// This corresponds to [`ASN1_TIME_set_string`]. + /// + /// [`ASN1_TIME_set_string`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html + pub fn from_str(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } + + /// Creates a new time corresponding to the specified X509 time string. + /// + /// This corresponds to [`ASN1_TIME_set_string_X509`]. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// [`ASN1_TIME_set_string_X509`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html + #[cfg(ossl111)] + pub fn from_str_x509(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_STRING; + fn drop = ffi::ASN1_STRING_free; + /// Primary ASN.1 type used by OpenSSL + /// + /// Almost all ASN.1 types in OpenSSL are represented by ASN1_STRING + /// structures. This implementation uses [ASN1_STRING-to_UTF8] to preserve + /// compatibility with Rust's String. + /// + /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html + pub struct Asn1String; + /// Reference to [`Asn1String`] + /// + /// [`Asn1String`]: struct.Asn1String.html + pub struct Asn1StringRef; +} + +impl Asn1StringRef { + /// Converts the ASN.1 underlying format to UTF8 + /// + /// ASN.1 strings may utilize UTF-16, ASCII, BMP, or UTF8. This is important to + /// consume the string in a meaningful way without knowing the underlying + /// format. + pub fn as_utf8(&self) -> Result { + unsafe { + let mut ptr = ptr::null_mut(); + let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); + if len < 0 { + return Err(ErrorStack::get()); + } + + Ok(OpensslString::from_ptr(ptr as *mut c_char)) + } + } + + /// Return the string as an array of bytes + /// + /// The bytes do not directly corespond to UTF-8 encoding. To interact with + /// strings in rust, it is preferable to use [`as_utf8`] + /// + /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } + } + + /// Return the length of the Asn1String (number of bytes) + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_INTEGER; + fn drop = ffi::ASN1_INTEGER_free; + + /// Numeric representation + /// + /// Integers in ASN.1 may include BigNum, int64 or uint64. BigNum implementation + /// can be found within [`bn`] module. + /// + /// OpenSSL documentation includes [`ASN1_INTEGER_set`]. + /// + /// [`bn`]: ../bn/index.html + /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html + pub struct Asn1Integer; + /// Reference to [`Asn1Integer`] + /// + /// [`Asn1Integer`]: struct.Asn1Integer.html + pub struct Asn1IntegerRef; +} + +impl Asn1Integer { + /// Converts a bignum to an `Asn1Integer`. + /// + /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see + /// [`BigNumRef::to_asn1_integer`]. + /// + /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_to_ASN1_INTEGER.html + /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer + pub fn from_bn(bn: &BigNumRef) -> Result { + bn.to_asn1_integer() + } +} + +impl Asn1IntegerRef { + #[allow(missing_docs)] + #[deprecated(since = "0.10.6", note = "use to_bn instead")] + pub fn get(&self) -> i64 { + unsafe { ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } + } + + /// Converts the integer to a `BigNum`. + /// + /// This corresponds to [`ASN1_INTEGER_to_BN`]. + /// + /// [`ASN1_INTEGER_to_BN`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_get.html + pub fn to_bn(&self) -> Result { + unsafe { + cvt_p(::ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut())) + .map(|p| BigNum::from_ptr(p)) + } + } + + /// Sets the ASN.1 value to the value of a signed 32-bit integer, for larger numbers + /// see [`bn`]. + /// + /// OpenSSL documentation at [`ASN1_INTEGER_set`] + /// + /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer + /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html + pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { + unsafe { cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_BIT_STRING; + fn drop = ffi::ASN1_BIT_STRING_free; + /// Sequence of bytes + /// + /// Asn1BitString is used in [`x509`] certificates for the signature. + /// The bit string acts as a collection of bytes. + /// + /// [`x509`]: ../x509/struct.X509.html#method.signature + pub struct Asn1BitString; + /// Reference to [`Asn1BitString`] + /// + /// [`Asn1BitString`]: struct.Asn1BitString.html + pub struct Asn1BitStringRef; +} + +impl Asn1BitStringRef { + /// Returns the Asn1BitString as a slice + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } + } + /// Length of Asn1BitString in number of bytes. + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_OBJECT; + fn drop = ffi::ASN1_OBJECT_free; + + /// Object Identifier + /// + /// Represents an ASN.1 Object. Typically, NIDs, or numeric identifiers + /// are stored as a table within the [`Nid`] module. These constants are + /// used to determine attributes of a certificate, such as mapping the + /// attribute "CommonName" to "CN" which is represented as the OID of 13. + /// This attribute is a constant in the [`nid::COMMONNAME`]. + /// + /// OpenSSL documentation at [`OBJ_nid2obj`] + /// + /// [`Nid`]: ../nid/index.html + /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html + /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html + pub struct Asn1Object; + /// Reference to [`Asn1Object`] + /// + /// [`Asn1Object`]: struct.Asn1Object.html + pub struct Asn1ObjectRef; +} + +impl Asn1ObjectRef { + /// Returns the NID associated with this OID. + pub fn nid(&self) -> Nid { + unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) } + } +} + +impl fmt::Display for Asn1ObjectRef { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let mut buf = [0; 80]; + let len = ffi::OBJ_obj2txt( + buf.as_mut_ptr() as *mut _, + buf.len() as c_int, + self.as_ptr(), + 0, + ); + let s = str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)?; + fmt.write_str(s) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::ASN1_STRING_get0_data; + } else { + #[allow(bad_style)] + unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { + ffi::ASN1_STRING_data(s) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use bn::BigNum; + + /// Tests conversion between BigNum and Asn1Integer. + #[test] + fn bn_cvt() { + fn roundtrip(bn: BigNum) { + let large = Asn1Integer::from_bn(&bn).unwrap(); + assert_eq!(large.to_bn().unwrap(), bn); + } + + roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(BigNum::from_u32(1234).unwrap()); + roundtrip(-BigNum::from_u32(1234).unwrap()); + } + + #[test] + fn time_from_str() { + Asn1Time::from_str("99991231235959Z").unwrap(); + #[cfg(ossl111)] + Asn1Time::from_str_x509("99991231235959Z").unwrap(); + } +} diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs new file mode 100644 index 000000000..4c2f1ff20 --- /dev/null +++ b/openssl/src/bio.rs @@ -0,0 +1,84 @@ +use ffi; +use libc::c_int; +use std::marker::PhantomData; +use std::ptr; +use std::slice; + +use cvt_p; +use error::ErrorStack; + +pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>); + +impl<'a> Drop for MemBioSlice<'a> { + fn drop(&mut self) { + unsafe { + ffi::BIO_free_all(self.0); + } + } +} + +impl<'a> MemBioSlice<'a> { + pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { + ffi::init(); + + assert!(buf.len() <= c_int::max_value() as usize); + let bio = unsafe { + cvt_p(BIO_new_mem_buf( + buf.as_ptr() as *const _, + buf.len() as c_int, + ))? + }; + + Ok(MemBioSlice(bio, PhantomData)) + } + + pub fn as_ptr(&self) -> *mut ffi::BIO { + self.0 + } +} + +pub struct MemBio(*mut ffi::BIO); + +impl Drop for MemBio { + fn drop(&mut self) { + unsafe { + ffi::BIO_free_all(self.0); + } + } +} + +impl MemBio { + pub fn new() -> Result { + ffi::init(); + + let bio = unsafe { cvt_p(ffi::BIO_new(ffi::BIO_s_mem()))? }; + Ok(MemBio(bio)) + } + + pub fn as_ptr(&self) -> *mut ffi::BIO { + self.0 + } + + pub fn get_buf(&self) -> &[u8] { + unsafe { + let mut ptr = ptr::null_mut(); + let len = ffi::BIO_get_mem_data(self.0, &mut ptr); + slice::from_raw_parts(ptr as *const _ as *const _, len as usize) + } + } + + pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio { + MemBio(bio) + } +} + +cfg_if! { + if #[cfg(ossl102)] { + use ffi::BIO_new_mem_buf; + } else { + #[allow(bad_style)] + unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { + ffi::BIO_new_mem_buf(buf as *mut _, len) + } + } +} diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs new file mode 100644 index 000000000..1f949a97e --- /dev/null +++ b/openssl/src/bn.rs @@ -0,0 +1,1424 @@ +//! BigNum implementation +//! +//! Large numbers are important for a cryptographic library. OpenSSL implementation +//! of BigNum uses dynamically assigned memory to store an array of bit chunks. This +//! allows numbers of any size to be compared and mathematical functions performed. +//! +//! OpenSSL wiki describes the [`BIGNUM`] data structure. +//! +//! # Examples +//! +//! ``` +//! use openssl::bn::BigNum; +//! use openssl::error::ErrorStack; +//! +//! fn bignums() -> Result<(), ErrorStack> { +//! let a = BigNum::new()?; // a = 0 +//! let b = BigNum::from_dec_str("1234567890123456789012345")?; +//! let c = &a * &b; +//! assert_eq!(a, c); +//! Ok(()) +//! } +//! # fn main() { +//! # bignums(); +//! # } +//! ``` +//! +//! [`BIGNUM`]: https://wiki.openssl.org/index.php/Manual:Bn_internal(3) +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::cmp::Ordering; +use std::ffi::CString; +use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; +use std::{fmt, ptr}; + +use asn1::Asn1Integer; +use error::ErrorStack; +use string::OpensslString; +use {cvt, cvt_n, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, + BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, + BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192, BN_is_negative, + }; + } else { + use ffi::{ + get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, + get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, + get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, + get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, + get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, + get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, + get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, + get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192, + }; + + #[allow(bad_style)] + unsafe fn BN_is_negative(bn: *const ffi::BIGNUM) -> c_int { + (*bn).neg + } + } +} + +/// Options for the most significant bits of a randomly generated `BigNum`. +pub struct MsbOption(c_int); + +impl MsbOption { + /// The most significant bit of the number may be 0. + pub const MAYBE_ZERO: MsbOption = MsbOption(-1); + + /// The most significant bit of the number must be 1. + pub const ONE: MsbOption = MsbOption(0); + + /// The most significant two bits of the number must be 1. + /// + /// The number of bits in the product of two such numbers will always be exactly twice the + /// number of bits in the original numbers. + pub const TWO_ONES: MsbOption = MsbOption(1); +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::BN_CTX; + fn drop = ffi::BN_CTX_free; + + /// Temporary storage for BigNums on the secure heap + /// + /// BigNum values are stored dynamically and therefore can be expensive + /// to allocate. BigNumContext and the OpenSSL [`BN_CTX`] structure are used + /// internally when passing BigNum values between subroutines. + /// + /// [`BN_CTX`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html + pub struct BigNumContext; + /// Reference to [`BigNumContext`] + /// + /// [`BigNumContext`]: struct.BigNumContext.html + pub struct BigNumContextRef; +} + +impl BigNumContext { + /// Returns a new `BigNumContext`. + /// + /// See OpenSSL documentation at [`BN_CTX_new`]. + /// + /// [`BN_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::BN_CTX_new()).map(BigNumContext) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::BIGNUM; + fn drop = ffi::BN_free; + + /// Dynamically sized large number impelementation + /// + /// Perform large number mathematics. Create a new BigNum + /// with [`new`]. Perform standard mathematics on large numbers using + /// methods from [`Dref`] + /// + /// OpenSSL documenation at [`BN_new`]. + /// + /// [`new`]: struct.BigNum.html#method.new + /// [`Dref`]: struct.BigNum.html#deref-methods + /// [`BN_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_new.html + /// + /// # Examples + /// ``` + /// use openssl::bn::BigNum; + /// # use openssl::error::ErrorStack; + /// # fn bignums() -> Result< (), ErrorStack > { + /// let little_big = BigNum::from_u32(std::u32::MAX)?; + /// assert_eq!(*&little_big.num_bytes(), 4); + /// # Ok(()) + /// # } + /// # fn main () { bignums(); } + /// ``` + pub struct BigNum; + /// Reference to a [`BigNum`] + /// + /// [`BigNum`]: struct.BigNum.html + pub struct BigNumRef; +} + +impl BigNumRef { + /// Erases the memory used by this `BigNum`, resetting its value to 0. + /// + /// This can be used to destroy sensitive data such as keys when they are no longer needed. + /// + /// OpenSSL documentation at [`BN_clear`] + /// + /// [`BN_clear`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear.html + pub fn clear(&mut self) { + unsafe { ffi::BN_clear(self.as_ptr()) } + } + + /// Adds a `u32` to `self`. + /// + /// OpenSSL documentation at [`BN_add_word`] + /// + /// [`BN_add_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add_word.html + pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } + } + + /// Subtracts a `u32` from `self`. + /// + /// OpenSSL documentation at [`BN_sub_word`] + /// + /// [`BN_sub_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub_word.html + pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } + } + + /// Multiplies a `u32` by `self`. + /// + /// OpenSSL documentation at [`BN_mul_word`] + /// + /// [`BN_mul_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul_word.html + pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } + } + + /// Divides `self` by a `u32`, returning the remainder. + /// + /// OpenSSL documentation at [`BN_div_word`] + /// + /// [`BN_div_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div_word.html + pub fn div_word(&mut self, w: u32) -> Result { + unsafe { + let r = ffi::BN_div_word(self.as_ptr(), w.into()); + if r == ffi::BN_ULONG::max_value() { + Err(ErrorStack::get()) + } else { + Ok(r.into()) + } + } + } + + /// Returns the result of `self` modulo `w`. + /// + /// OpenSSL documentation at [`BN_mod_word`] + /// + /// [`BN_mod_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_word.html + pub fn mod_word(&self, w: u32) -> Result { + unsafe { + let r = ffi::BN_mod_word(self.as_ptr(), w.into()); + if r == ffi::BN_ULONG::max_value() { + Err(ErrorStack::get()) + } else { + Ok(r.into()) + } + } + } + + /// Places a cryptographically-secure pseudo-random nonnegative + /// number less than `self` in `rnd`. + /// + /// OpenSSL documentation at [`BN_rand_range`] + /// + /// [`BN_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand_range.html + pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } + } + + /// The cryptographically weak counterpart to `rand_in_range`. + /// + /// OpenSSL documentation at [`BN_pseudo_rand_range`] + /// + /// [`BN_pseudo_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand_range.html + pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } + } + + /// Sets bit `n`. Equivalent to `self |= (1 << n)`. + /// + /// When setting a bit outside of `self`, it is expanded. + /// + /// OpenSSL documentation at [`BN_set_bit`] + /// + /// [`BN_set_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_bit.html + pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) } + } + + /// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`. + /// + /// When clearing a bit outside of `self`, an error is returned. + /// + /// OpenSSL documentation at [`BN_clear_bit`] + /// + /// [`BN_clear_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear_bit.html + pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) } + } + + /// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise. + /// + /// OpenSSL documentation at [`BN_is_bit_set`] + /// + /// [`BN_is_bit_set`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_bit_set.html + pub fn is_bit_set(&self, n: i32) -> bool { + unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 } + } + + /// Truncates `self` to the lowest `n` bits. + /// + /// An error occurs if `self` is already shorter than `n` bits. + /// + /// OpenSSL documentation at [`BN_mask_bits`] + /// + /// [`BN_mask_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mask_bits.html + pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) } + } + + /// Places `a << 1` in `self`. Equivalent to `self * 2`. + /// + /// OpenSSL documentation at [`BN_lshift1`] + /// + /// [`BN_lshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift1.html + pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } + } + + /// Places `a >> 1` in `self`. Equivalent to `self / 2`. + /// + /// OpenSSL documentation at [`BN_rshift1`] + /// + /// [`BN_rshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift1.html + pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } + } + + /// Places `a + b` in `self`. [`core::ops::Add`] is also implemented for `BigNumRef`. + /// + /// OpenSSL documentation at [`BN_add`] + /// + /// [`core::ops::Add`]: struct.BigNumRef.html#method.add + /// [`BN_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add.html + pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } + } + + /// Places `a - b` in `self`. [`core::ops::Sub`] is also implemented for `BigNumRef`. + /// + /// OpenSSL documentation at [`BN_sub`] + /// + /// [`core::ops::Sub`]: struct.BigNumRef.html#method.sub + /// [`BN_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub.html + pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } + } + + /// Places `a << n` in `self`. Equivalent to `a * 2 ^ n`. + /// + /// OpenSSL documentation at [`BN_lshift`] + /// + /// [`BN_lshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift.html + pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } + } + + /// Places `a >> n` in `self`. Equivalent to `a / 2 ^ n`. + /// + /// OpenSSL documentation at [`BN_rshift`] + /// + /// [`BN_rshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift.html + pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } + } + + /// Creates a new BigNum with the same value. + /// + /// OpenSSL documentation at [`BN_dup`] + /// + /// [`BN_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dup.html + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) } + } + + /// Sets the sign of `self`. Pass true to set `self` to a negative. False sets + /// `self` positive. + pub fn set_negative(&mut self, negative: bool) { + unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) } + } + + /// Compare the absolute values of `self` and `oth`. + /// + /// OpenSSL documentation at [`BN_ucmp`] + /// + /// [`BN_ucmp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_ucmp.html + /// + /// # Examples + /// + /// ``` + /// # use openssl::bn::BigNum; + /// # use std::cmp::Ordering; + /// let s = -BigNum::from_u32(8).unwrap(); + /// let o = BigNum::from_u32(8).unwrap(); + /// + /// assert_eq!(s.ucmp(&o), Ordering::Equal); + /// ``` + pub fn ucmp(&self, oth: &BigNumRef) -> Ordering { + unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) } + } + + /// Returns `true` if `self` is negative. + pub fn is_negative(&self) -> bool { + unsafe { BN_is_negative(self.as_ptr()) == 1 } + } + + /// Returns the number of significant bits in `self`. + /// + /// OpenSSL documentation at [`BN_num_bits`] + /// + /// [`BN_num_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_num_bits.html + pub fn num_bits(&self) -> i32 { + unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } + } + + /// Returns the size of `self` in bytes. Implemented natively. + pub fn num_bytes(&self) -> i32 { + (self.num_bits() + 7) / 8 + } + + /// Generates a cryptographically strong pseudo-random `BigNum`, placing it in `self`. + /// + /// # Parameters + /// + /// * `bits`: Length of the number in bits. + /// * `msb`: The desired properties of the most significant bit. See [`constants`]. + /// * `odd`: If `true`, the generated number will be odd. + /// + /// # Examples + /// + /// ``` + /// use openssl::bn::{BigNum, MsbOption}; + /// use openssl::error::ErrorStack; + /// + /// fn generate_random() -> Result< BigNum, ErrorStack > { + /// let mut big = BigNum::new()?; + /// + /// // Generates a 128-bit odd random number + /// big.rand(128, MsbOption::MAYBE_ZERO, true); + /// Ok((big)) + /// } + /// ``` + /// + /// OpenSSL documentation at [`BN_rand`] + /// + /// [`constants`]: index.html#constants + /// [`BN_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand.html + pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_rand( + self.as_ptr(), + bits.into(), + msb.0, + odd as c_int, + )) + .map(|_| ()) + } + } + + /// The cryptographically weak counterpart to `rand`. Not suitable for key generation. + /// + /// OpenSSL documentation at [`BN_psuedo_rand`] + /// + /// [`BN_psuedo_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand.html + pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_pseudo_rand( + self.as_ptr(), + bits.into(), + msb.0, + odd as c_int, + )) + .map(|_| ()) + } + } + + /// Generates a prime number, placing it in `self`. + /// + /// # Parameters + /// + /// * `bits`: The length of the prime in bits (lower bound). + /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime. + /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the + /// generated prime and `rem` is `1` if not specified (`None`). + /// + /// # Examples + /// + /// ``` + /// use openssl::bn::BigNum; + /// use openssl::error::ErrorStack; + /// + /// fn generate_weak_prime() -> Result< BigNum, ErrorStack > { + /// let mut big = BigNum::new()?; + /// + /// // Generates a 128-bit simple prime number + /// big.generate_prime(128, false, None, None); + /// Ok((big)) + /// } + /// ``` + /// + /// OpenSSL documentation at [`BN_generate_prime_ex`] + /// + /// [`BN_generate_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_generate_prime_ex.html + pub fn generate_prime( + &mut self, + bits: i32, + safe: bool, + add: Option<&BigNumRef>, + rem: Option<&BigNumRef>, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_generate_prime_ex( + self.as_ptr(), + bits as c_int, + safe as c_int, + add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), + rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), + ptr::null_mut(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a * b` in `self`. + /// [`core::ops::Mul`] is also implemented for `BigNumRef`. + /// + /// OpenSSL documentation at [`BN_mul`] + /// + /// [`core::ops::Mul`]: struct.BigNumRef.html#method.mul + /// [`BN_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul.html + pub fn checked_mul( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mul( + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a / b` in `self`. The remainder is discarded. + /// [`core::ops::Div`] is also implemented for `BigNumRef`. + /// + /// OpenSSL documentation at [`BN_div`] + /// + /// [`core::ops::Div`]: struct.BigNumRef.html#method.div + /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + pub fn checked_div( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_div( + self.as_ptr(), + ptr::null_mut(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a % b` in `self`. + /// + /// OpenSSL documentation at [`BN_div`] + /// + /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + pub fn checked_rem( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_div( + ptr::null_mut(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a / b` in `self` and `a % b` in `rem`. + /// + /// OpenSSL documentation at [`BN_div`] + /// + /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html + pub fn div_rem( + &mut self, + rem: &mut BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_div( + self.as_ptr(), + rem.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a²` in `self`. + /// + /// OpenSSL documentation at [`BN_sqr`] + /// + /// [`BN_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sqr.html + pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) } + } + + /// Places the result of `a mod m` in `self`. As opposed to `div_rem` + /// the result is non-negative. + /// + /// OpenSSL documentation at [`BN_nnmod`] + /// + /// [`BN_nnmod`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_nnmod.html + pub fn nnmod( + &mut self, + a: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_nnmod( + self.as_ptr(), + a.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `(a + b) mod m` in `self`. + /// + /// OpenSSL documentation at [`BN_mod_add`] + /// + /// [`BN_mod_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_add.html + pub fn mod_add( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_add( + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `(a - b) mod m` in `self`. + /// + /// OpenSSL documentation at [`BN_mod_sub`] + /// + /// [`BN_mod_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sub.html + pub fn mod_sub( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_sub( + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `(a * b) mod m` in `self`. + /// + /// OpenSSL documentation at [`BN_mod_mul`] + /// + /// [`BN_mod_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_mul.html + pub fn mod_mul( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_mul( + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a² mod m` in `self`. + /// + /// OpenSSL documentation at [`BN_mod_sqr`] + /// + /// [`BN_mod_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sqr.html + pub fn mod_sqr( + &mut self, + a: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_sqr( + self.as_ptr(), + a.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a^p` in `self`. + /// + /// OpenSSL documentation at [`BN_exp`] + /// + /// [`BN_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_exp.html + pub fn exp( + &mut self, + a: &BigNumRef, + p: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_exp( + self.as_ptr(), + a.as_ptr(), + p.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the result of `a^p mod m` in `self`. + /// + /// OpenSSL documentation at [`BN_mod_exp`] + /// + /// [`BN_mod_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_exp.html + pub fn mod_exp( + &mut self, + a: &BigNumRef, + p: &BigNumRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_mod_exp( + self.as_ptr(), + a.as_ptr(), + p.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the inverse of `a` modulo `n` in `self`. + pub fn mod_inverse( + &mut self, + a: &BigNumRef, + n: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt_p(ffi::BN_mod_inverse( + self.as_ptr(), + a.as_ptr(), + n.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the greatest common denominator of `a` and `b` in `self`. + /// + /// OpenSSL documentation at [`BN_gcd`] + /// + /// [`BN_gcd`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_gcd.html + pub fn gcd( + &mut self, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::BN_gcd( + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Checks whether `self` is prime. + /// + /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations. + /// + /// OpenSSL documentation at [`BN_is_prime_ex`] + /// + /// [`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_ex.html + /// + /// # Return Value + /// + /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. + + pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result { + unsafe { + cvt_n(ffi::BN_is_prime_ex( + self.as_ptr(), + checks.into(), + ctx.as_ptr(), + ptr::null_mut(), + )) + .map(|r| r != 0) + } + } + + /// Checks whether `self` is prime with optional trial division. + /// + /// If `do_trial_division` is `true`, first performs trial division by a number of small primes. + /// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks` + /// iterations. + /// + /// OpenSSL documentation at [`BN_is_prime_fasttest_ex`] + /// + /// [`BN_is_prime_fasttest_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_fasttest_ex.html + /// + /// # Return Value + /// + /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. + pub fn is_prime_fasttest( + &self, + checks: i32, + ctx: &mut BigNumContextRef, + do_trial_division: bool, + ) -> Result { + unsafe { + cvt_n(ffi::BN_is_prime_fasttest_ex( + self.as_ptr(), + checks.into(), + ctx.as_ptr(), + do_trial_division as c_int, + ptr::null_mut(), + )) + .map(|r| r != 0) + } + } + + /// Returns a big-endian byte vector representation of the absolute value of `self`. + /// + /// `self` can be recreated by using `from_slice`. + /// + /// ``` + /// # use openssl::bn::BigNum; + /// let s = -BigNum::from_u32(4543).unwrap(); + /// let r = BigNum::from_u32(4543).unwrap(); + /// + /// let s_vec = s.to_vec(); + /// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r); + /// ``` + pub fn to_vec(&self) -> Vec { + let size = self.num_bytes() as usize; + let mut v = Vec::with_capacity(size); + unsafe { + ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr()); + v.set_len(size); + } + v + } + + /// Returns a decimal string representation of `self`. + /// + /// ``` + /// # use openssl::bn::BigNum; + /// let s = -BigNum::from_u32(12345).unwrap(); + /// + /// assert_eq!(&**s.to_dec_str().unwrap(), "-12345"); + /// ``` + pub fn to_dec_str(&self) -> Result { + unsafe { + let buf = cvt_p(ffi::BN_bn2dec(self.as_ptr()))?; + Ok(OpensslString::from_ptr(buf)) + } + } + + /// Returns a hexadecimal string representation of `self`. + /// + /// ``` + /// # use openssl::bn::BigNum; + /// let s = -BigNum::from_u32(0x99ff).unwrap(); + /// + /// assert_eq!(&**s.to_hex_str().unwrap(), "-99FF"); + /// ``` + pub fn to_hex_str(&self) -> Result { + unsafe { + let buf = cvt_p(ffi::BN_bn2hex(self.as_ptr()))?; + Ok(OpensslString::from_ptr(buf)) + } + } + + /// Returns an `Asn1Integer` containing the value of `self`. + pub fn to_asn1_integer(&self) -> Result { + unsafe { + cvt_p(ffi::BN_to_ASN1_INTEGER(self.as_ptr(), ptr::null_mut())) + .map(|p| Asn1Integer::from_ptr(p)) + } + } +} + +impl BigNum { + /// Creates a new `BigNum` with the value 0. + pub fn new() -> Result { + unsafe { + ffi::init(); + let v = cvt_p(ffi::BN_new())?; + Ok(BigNum::from_ptr(v)) + } + } + + /// Creates a new `BigNum` with the given value. + /// + /// OpenSSL documentation at [`BN_set_word`] + /// + /// [`BN_set_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_word.html + pub fn from_u32(n: u32) -> Result { + BigNum::new().and_then(|v| unsafe { + cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v) + }) + } + + /// Creates a `BigNum` from a decimal string. + /// + /// OpenSSL documentation at [`BN_dec2bn`] + /// + /// [`BN_dec2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dec2bn.html + pub fn from_dec_str(s: &str) -> Result { + unsafe { + ffi::init(); + let c_str = CString::new(s.as_bytes()).unwrap(); + let mut bn = ptr::null_mut(); + cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _))?; + Ok(BigNum::from_ptr(bn)) + } + } + + /// Creates a `BigNum` from a hexadecimal string. + /// + /// OpenSSL documentation at [`BN_hex2bn`] + /// + /// [`BN_hex2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_hex2bn.html + pub fn from_hex_str(s: &str) -> Result { + unsafe { + ffi::init(); + let c_str = CString::new(s.as_bytes()).unwrap(); + let mut bn = ptr::null_mut(); + cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _))?; + Ok(BigNum::from_ptr(bn)) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 2409`]. This prime number is in + /// the order of magnitude of `2 ^ 768`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled Oakley group id 1. + /// + /// OpenSSL documentation at [`BN_get_rfc2409_prime_768`] + /// + /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 + /// [`BN_get_rfc2409_prime_768`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_768.html + pub fn get_rfc2409_prime_768() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc2409_prime_768(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 2409`]. This prime number is in + /// the order of magnitude of `2 ^ 1024`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled Oakly group 2. + /// + /// OpenSSL documentation at [`BN_get_rfc2409_prime_1024`] + /// + /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 + /// [`BN_get_rfc2409_prime_1024`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_1024.html + pub fn get_rfc2409_prime_1024() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc2409_prime_1024(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 1536`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 5. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_1536`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 + /// [`BN_get_rfc3526_prime_1536`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_1536.html + pub fn get_rfc3526_prime_1536() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_1536(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 2048`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 14. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_2048`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 + /// [`BN_get_rfc3526_prime_2048`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_2048.html + pub fn get_rfc3526_prime_2048() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_2048(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 3072`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 15. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_3072`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 + /// [`BN_get_rfc3526_prime_3072`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_3072.html + pub fn get_rfc3526_prime_3072() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_3072(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 4096`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 16. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_4096`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 + /// [`BN_get_rfc3526_prime_4096`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_4096.html + pub fn get_rfc3526_prime_4096() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_4096(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 6144`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 17. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_6144`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 + /// [`BN_get_rfc3526_prime_6144`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_6144.html + pub fn get_rfc3526_prime_6144() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_6144(ptr::null_mut())).map(BigNum) + } + } + + /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order + /// of magnitude of `2 ^ 8192`. This number is used during calculated key + /// exchanges such as Diffie-Hellman. This number is labeled MODP group 18. + /// + /// OpenSSL documentation at [`BN_get_rfc3526_prime_8192`] + /// + /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 + /// [`BN_get_rfc3526_prime_8192`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_8192.html + pub fn get_rfc3526_prime_8192() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_8192(ptr::null_mut())).map(BigNum) + } + } + + /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length. + /// + /// OpenSSL documentation at [`BN_bin2bn`] + /// + /// [`BN_bin2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_bin2bn.html + /// + /// ``` + /// # use openssl::bn::BigNum; + /// let bignum = BigNum::from_slice(&[0x12, 0x00, 0x34]).unwrap(); + /// + /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); + /// ``` + pub fn from_slice(n: &[u8]) -> Result { + unsafe { + ffi::init(); + assert!(n.len() <= c_int::max_value() as usize); + cvt_p(ffi::BN_bin2bn( + n.as_ptr(), + n.len() as c_int, + ptr::null_mut(), + )) + .map(|p| BigNum::from_ptr(p)) + } + } +} + +impl fmt::Debug for BigNumRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.to_dec_str() { + Ok(s) => f.write_str(&s), + Err(e) => Err(e.into()), + } + } +} + +impl fmt::Debug for BigNum { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.to_dec_str() { + Ok(s) => f.write_str(&s), + Err(e) => Err(e.into()), + } + } +} + +impl fmt::Display for BigNumRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.to_dec_str() { + Ok(s) => f.write_str(&s), + Err(e) => Err(e.into()), + } + } +} + +impl fmt::Display for BigNum { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.to_dec_str() { + Ok(s) => f.write_str(&s), + Err(e) => Err(e.into()), + } + } +} + +impl PartialEq for BigNumRef { + fn eq(&self, oth: &BigNumRef) -> bool { + self.cmp(oth) == Ordering::Equal + } +} + +impl PartialEq for BigNumRef { + fn eq(&self, oth: &BigNum) -> bool { + self.eq(oth.deref()) + } +} + +impl Eq for BigNumRef {} + +impl PartialEq for BigNum { + fn eq(&self, oth: &BigNum) -> bool { + self.deref().eq(oth) + } +} + +impl PartialEq for BigNum { + fn eq(&self, oth: &BigNumRef) -> bool { + self.deref().eq(oth) + } +} + +impl Eq for BigNum {} + +impl PartialOrd for BigNumRef { + fn partial_cmp(&self, oth: &BigNumRef) -> Option { + Some(self.cmp(oth)) + } +} + +impl PartialOrd for BigNumRef { + fn partial_cmp(&self, oth: &BigNum) -> Option { + Some(self.cmp(oth.deref())) + } +} + +impl Ord for BigNumRef { + fn cmp(&self, oth: &BigNumRef) -> Ordering { + unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) } + } +} + +impl PartialOrd for BigNum { + fn partial_cmp(&self, oth: &BigNum) -> Option { + self.deref().partial_cmp(oth.deref()) + } +} + +impl PartialOrd for BigNum { + fn partial_cmp(&self, oth: &BigNumRef) -> Option { + self.deref().partial_cmp(oth) + } +} + +impl Ord for BigNum { + fn cmp(&self, oth: &BigNum) -> Ordering { + self.deref().cmp(oth.deref()) + } +} + +macro_rules! delegate { + ($t:ident, $m:ident) => { + impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef { + type Output = BigNum; + + fn $m(self, oth: &BigNum) -> BigNum { + $t::$m(self, oth.deref()) + } + } + + impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum { + type Output = BigNum; + + fn $m(self, oth: &BigNumRef) -> BigNum { + $t::$m(self.deref(), oth) + } + } + + impl<'a, 'b> $t<&'b BigNum> for &'a BigNum { + type Output = BigNum; + + fn $m(self, oth: &BigNum) -> BigNum { + $t::$m(self.deref(), oth.deref()) + } + } + }; +} + +impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef { + type Output = BigNum; + + fn add(self, oth: &BigNumRef) -> BigNum { + let mut r = BigNum::new().unwrap(); + r.checked_add(self, oth).unwrap(); + r + } +} + +delegate!(Add, add); + +impl<'a, 'b> Sub<&'b BigNumRef> for &'a BigNumRef { + type Output = BigNum; + + fn sub(self, oth: &BigNumRef) -> BigNum { + let mut r = BigNum::new().unwrap(); + r.checked_sub(self, oth).unwrap(); + r + } +} + +delegate!(Sub, sub); + +impl<'a, 'b> Mul<&'b BigNumRef> for &'a BigNumRef { + type Output = BigNum; + + fn mul(self, oth: &BigNumRef) -> BigNum { + let mut ctx = BigNumContext::new().unwrap(); + let mut r = BigNum::new().unwrap(); + r.checked_mul(self, oth, &mut ctx).unwrap(); + r + } +} + +delegate!(Mul, mul); + +impl<'a, 'b> Div<&'b BigNumRef> for &'a BigNumRef { + type Output = BigNum; + + fn div(self, oth: &'b BigNumRef) -> BigNum { + let mut ctx = BigNumContext::new().unwrap(); + let mut r = BigNum::new().unwrap(); + r.checked_div(self, oth, &mut ctx).unwrap(); + r + } +} + +delegate!(Div, div); + +impl<'a, 'b> Rem<&'b BigNumRef> for &'a BigNumRef { + type Output = BigNum; + + fn rem(self, oth: &'b BigNumRef) -> BigNum { + let mut ctx = BigNumContext::new().unwrap(); + let mut r = BigNum::new().unwrap(); + r.checked_rem(self, oth, &mut ctx).unwrap(); + r + } +} + +delegate!(Rem, rem); + +impl<'a> Shl for &'a BigNumRef { + type Output = BigNum; + + fn shl(self, n: i32) -> BigNum { + let mut r = BigNum::new().unwrap(); + r.lshift(self, n).unwrap(); + r + } +} + +impl<'a> Shl for &'a BigNum { + type Output = BigNum; + + fn shl(self, n: i32) -> BigNum { + self.deref().shl(n) + } +} + +impl<'a> Shr for &'a BigNumRef { + type Output = BigNum; + + fn shr(self, n: i32) -> BigNum { + let mut r = BigNum::new().unwrap(); + r.rshift(self, n).unwrap(); + r + } +} + +impl<'a> Shr for &'a BigNum { + type Output = BigNum; + + fn shr(self, n: i32) -> BigNum { + self.deref().shr(n) + } +} + +impl<'a> Neg for &'a BigNumRef { + type Output = BigNum; + + fn neg(self) -> BigNum { + self.to_owned().unwrap().neg() + } +} + +impl<'a> Neg for &'a BigNum { + type Output = BigNum; + + fn neg(self) -> BigNum { + self.deref().neg() + } +} + +impl Neg for BigNum { + type Output = BigNum; + + fn neg(mut self) -> BigNum { + let negative = self.is_negative(); + self.set_negative(!negative); + self + } +} + +#[cfg(test)] +mod tests { + use bn::{BigNum, BigNumContext}; + + #[test] + fn test_to_from_slice() { + let v0 = BigNum::from_u32(10203004).unwrap(); + let vec = v0.to_vec(); + let v1 = BigNum::from_slice(&vec).unwrap(); + + assert!(v0 == v1); + } + + #[test] + fn test_negation() { + let a = BigNum::from_u32(909829283).unwrap(); + + assert!(!a.is_negative()); + assert!((-a).is_negative()); + } + + #[test] + fn test_shift() { + let a = BigNum::from_u32(909829283).unwrap(); + use std::ops::{Shl, Shr}; + + assert!(a == a.shl(1).shr(1)); + } + + #[test] + fn test_rand_range() { + let range = BigNum::from_u32(909829283).unwrap(); + let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); + range.rand_range(&mut result).unwrap(); + assert!(result >= BigNum::from_u32(0).unwrap() && result < range); + } + + #[test] + fn test_pseudo_rand_range() { + let range = BigNum::from_u32(909829283).unwrap(); + let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); + range.pseudo_rand_range(&mut result).unwrap(); + assert!(result >= BigNum::from_u32(0).unwrap() && result < range); + } + + #[test] + fn test_prime_numbers() { + let a = BigNum::from_u32(19029017).unwrap(); + let mut p = BigNum::new().unwrap(); + p.generate_prime(128, true, None, Some(&a)).unwrap(); + + let mut ctx = BigNumContext::new().unwrap(); + assert!(p.is_prime(100, &mut ctx).unwrap()); + assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap()); + } +} diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs new file mode 100644 index 000000000..45f4dd654 --- /dev/null +++ b/openssl/src/cms.rs @@ -0,0 +1,239 @@ +//! SMIME implementation using CMS +//! +//! CMS (PKCS#7) is an encyption standard. It allows signing and ecrypting data using +//! X.509 certificates. The OpenSSL implementation of CMS is used in email encryption +//! generated from a `Vec` of bytes. This `Vec` follows the smime protocol standards. +//! Data accepted by this module will be smime type `enveloped-data`. + +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use std::ptr; + +use bio::{MemBio, MemBioSlice}; +use error::ErrorStack; +use libc::c_uint; +use pkey::{HasPrivate, PKeyRef}; +use stack::StackRef; +use x509::{X509Ref, X509}; +use symm::Cipher; +use {cvt, cvt_p}; + +bitflags! { + pub struct CMSOptions : c_uint { + const TEXT = ffi::CMS_TEXT; + const CMS_NOCERTS = ffi::CMS_NOCERTS; + const NO_CONTENT_VERIFY = ffi::CMS_NO_CONTENT_VERIFY; + const NO_ATTR_VERIFY = ffi::CMS_NO_ATTR_VERIFY; + const NOSIGS = ffi::CMS_NOSIGS; + const NOINTERN = ffi::CMS_NOINTERN; + const NO_SIGNER_CERT_VERIFY = ffi::CMS_NO_SIGNER_CERT_VERIFY; + const NOVERIFY = ffi::CMS_NOVERIFY; + const DETACHED = ffi::CMS_DETACHED; + const BINARY = ffi::CMS_BINARY; + const NOATTR = ffi::CMS_NOATTR; + const NOSMIMECAP = ffi::CMS_NOSMIMECAP; + const NOOLDMIMETYPE = ffi::CMS_NOOLDMIMETYPE; + const CRLFEOL = ffi::CMS_CRLFEOL; + const STREAM = ffi::CMS_STREAM; + const NOCRL = ffi::CMS_NOCRL; + const PARTIAL = ffi::CMS_PARTIAL; + const REUSE_DIGEST = ffi::CMS_REUSE_DIGEST; + const USE_KEYID = ffi::CMS_USE_KEYID; + const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; + #[cfg(all(not(libressl), not(ossl101)))] + const KEY_PARAM = ffi::CMS_KEY_PARAM; + #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] + const ASCIICRLF = ffi::CMS_ASCIICRLF; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::CMS_ContentInfo; + fn drop = ffi::CMS_ContentInfo_free; + + /// High level CMS wrapper + /// + /// CMS supports nesting various types of data, including signatures, certificates, + /// encrypted data, smime messages (encrypted email), and data digest. The ContentInfo + /// content type is the encapsulation of all those content types. [`RFC 5652`] describes + /// CMS and OpenSSL follows this RFC's implmentation. + /// + /// [`RFC 5652`]: https://tools.ietf.org/html/rfc5652#page-6 + pub struct CmsContentInfo; + /// Reference to [`CMSContentInfo`] + /// + /// [`CMSContentInfo`]:struct.CmsContentInfo.html + pub struct CmsContentInfoRef; +} + +impl CmsContentInfoRef { + /// Given the sender's private key, `pkey` and the recipient's certificiate, `cert`, + /// decrypt the data in `self`. + /// + /// OpenSSL documentation at [`CMS_decrypt`] + /// + /// [`CMS_decrypt`]: https://www.openssl.org/docs/man1.1.0/crypto/CMS_decrypt.html + pub fn decrypt(&self, pkey: &PKeyRef, cert: &X509) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + let pkey = pkey.as_ptr(); + let cert = cert.as_ptr(); + let out = MemBio::new()?; + let flags: u32 = 0; + + cvt(ffi::CMS_decrypt( + self.as_ptr(), + pkey, + cert, + ptr::null_mut(), + out.as_ptr(), + flags.into(), + ))?; + + Ok(out.get_buf().to_owned()) + } + } + + to_der! { + /// Serializes this CmsContentInfo using DER. + /// + /// OpenSSL documentation at [`i2d_CMS_ContentInfo`] + /// + /// [`i2d_CMS_ContentInfo`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_CMS_ContentInfo.html + to_der, + ffi::i2d_CMS_ContentInfo + } +} + +impl CmsContentInfo { + /// Parses a smime formatted `vec` of bytes into a `CmsContentInfo`. + /// + /// OpenSSL documentation at [`SMIME_read_CMS`] + /// + /// [`SMIME_read_CMS`]: https://www.openssl.org/docs/man1.0.2/crypto/SMIME_read_CMS.html + pub fn smime_read_cms(smime: &[u8]) -> Result { + unsafe { + let bio = MemBioSlice::new(smime)?; + + let cms = cvt_p(ffi::SMIME_read_CMS(bio.as_ptr(), ptr::null_mut()))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } + + from_der! { + /// Deserializes a DER-encoded ContentInfo structure. + /// + /// This corresponds to [`d2i_CMS_ContentInfo`]. + /// + /// [`d2i_CMS_ContentInfo`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html + from_der, + CmsContentInfo, + ffi::d2i_CMS_ContentInfo + } + + /// Given a signing cert `signcert`, private key `pkey`, a certificate stack `certs`, + /// data `data` and flags `flags`, create a CmsContentInfo struct. + /// + /// All arguments are optional. + /// + /// OpenSSL documentation at [`CMS_sign`] + /// + /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html + pub fn sign( + signcert: Option<&X509Ref>, + pkey: Option<&PKeyRef>, + certs: Option<&StackRef>, + data: Option<&[u8]>, + flags: CMSOptions, + ) -> Result + where + T: HasPrivate, + { + unsafe { + let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); + let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); + let data_bio = match data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); + + let cms = cvt_p(ffi::CMS_sign( + signcert, + pkey, + certs, + data_bio_ptr, + flags.bits(), + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } + + /// Given a certificate stack `certs`, data `data`, cipher `cipher` and flags `flags`, + /// create a CmsContentInfo struct. + /// + /// OpenSSL documentation at [`CMS_encrypt`] + /// + /// [`CMS_encrypt`]: https://www.openssl.org/docs/manmaster/man3/CMS_encrypt.html + pub fn encrypt( + certs: &StackRef, + data: &[u8], + cipher: Cipher, + flags: CMSOptions, + ) -> Result + { + unsafe { + let data_bio = MemBioSlice::new(data)?; + + let cms = cvt_p(ffi::CMS_encrypt( + certs.as_ptr(), + data_bio.as_ptr(), + cipher.as_ptr(), + flags.bits(), + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use stack::Stack; + use x509::X509; + use pkcs12::Pkcs12; + + #[test] + fn cms_encrypt_decrypt() { + // load cert with public key only + let pub_cert_bytes = include_bytes!("../test/cms_pubkey.der"); + let pub_cert = X509::from_der(pub_cert_bytes).expect("failed to load pub cert"); + + // load cert with private key + let priv_cert_bytes = include_bytes!("../test/cms.p12"); + let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); + let priv_cert = priv_cert.parse("mypass").expect("failed to parse priv cert"); + + // encrypt cms message using public key cert + let input = String::from("My Message"); + let mut cert_stack = Stack::new().expect("failed to create stack"); + cert_stack.push(pub_cert).expect("failed to add pub cert to stack"); + + let encrypt = CmsContentInfo::encrypt(&cert_stack, &input.as_bytes(), Cipher::des_ede3_cbc(), CMSOptions::empty()) + .expect("failed create encrypted cms"); + let encrypt = encrypt.to_der().expect("failed to create der from cms"); + + // decrypt cms message using private key cert + let decrypt = CmsContentInfo::from_der(&encrypt).expect("failed read cms from der"); + let decrypt = decrypt.decrypt(&priv_cert.pkey, &priv_cert.cert).expect("failed to decrypt cms"); + let decrypt = String::from_utf8(decrypt).expect("failed to create string from cms content"); + + assert_eq!(input, decrypt); + } +} diff --git a/openssl/src/conf.rs b/openssl/src/conf.rs new file mode 100644 index 000000000..fb5d4f3c0 --- /dev/null +++ b/openssl/src/conf.rs @@ -0,0 +1,52 @@ +//! Interface for processing OpenSSL configuration files. +use ffi; + +use cvt_p; +use error::ErrorStack; + +pub struct ConfMethod(*mut ffi::CONF_METHOD); + +impl ConfMethod { + /// Retrieve handle to the default OpenSSL configuration file processing function. + pub fn default() -> ConfMethod { + unsafe { + ffi::init(); + // `NCONF` stands for "New Conf", as described in crypto/conf/conf_lib.c. This is + // a newer API than the "CONF classic" functions. + ConfMethod(ffi::NCONF_default()) + } + } + + /// Construct from raw pointer. + pub unsafe fn from_ptr(ptr: *mut ffi::CONF_METHOD) -> ConfMethod { + ConfMethod(ptr) + } + + /// Convert to raw pointer. + pub fn as_ptr(&self) -> *mut ffi::CONF_METHOD { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::CONF; + fn drop = ffi::NCONF_free; + + pub struct Conf; + pub struct ConfRef; +} + +impl Conf { + /// Create a configuration parser. + /// + /// # Examples + /// + /// ``` + /// use openssl::conf::{Conf, ConfMethod}; + /// + /// let conf = Conf::new(ConfMethod::default()); + /// ``` + pub fn new(method: ConfMethod) -> Result { + unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) } + } +} diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs new file mode 100644 index 000000000..197e80dcb --- /dev/null +++ b/openssl/src/derive.rs @@ -0,0 +1,124 @@ +//! Shared secret derivation. +use ffi; +use foreign_types::ForeignTypeRef; +use std::marker::PhantomData; +use std::ptr; + +use error::ErrorStack; +use pkey::{HasPrivate, HasPublic, PKeyRef}; +use {cvt, cvt_p}; + +/// A type used to derive a shared secret between two keys. +pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); + +unsafe impl<'a> Sync for Deriver<'a> {} +unsafe impl<'a> Send for Deriver<'a> {} + +impl<'a> Deriver<'a> { + /// Creates a new `Deriver` using the provided private key. + /// + /// This corresponds to [`EVP_PKEY_derive_init`]. + /// + /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + pub fn new(key: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut())) + .map(|p| Deriver(p, PhantomData)) + .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx)) + } + } + + /// Sets the peer key used for secret derivation. + /// + /// This corresponds to [`EVP_PKEY_derive_set_peer`]: + /// + /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } + } + + /// Returns the size of the shared secret. + /// + /// It can be used to size the buffer passed to [`Deriver::derive`]. + /// + /// This corresponds to [`EVP_PKEY_derive`]. + /// + /// [`Deriver::derive`]: #method.derive + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + pub fn len(&mut self) -> Result { + unsafe { + let mut len = 0; + cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len) + } + } + + /// Derives a shared secret between the two keys, writing it into the buffer. + /// + /// Returns the number of bytes written. + /// + /// This corresponds to [`EVP_PKEY_derive`]. + /// + /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + pub fn derive(&mut self, buf: &mut [u8]) -> Result { + let mut len = buf.len(); + unsafe { + cvt(ffi::EVP_PKEY_derive( + self.0, + buf.as_mut_ptr() as *mut _, + &mut len, + )) + .map(|_| len) + } + } + + /// A convenience function which derives a shared secret and returns it in a new buffer. + /// + /// This simply wraps [`Deriver::len`] and [`Deriver::derive`]. + /// + /// [`Deriver::len`]: #method.len + /// [`Deriver::derive`]: #method.derive + pub fn derive_to_vec(&mut self) -> Result, ErrorStack> { + let len = self.len()?; + let mut buf = vec![0; len]; + let len = self.derive(&mut buf)?; + buf.truncate(len); + Ok(buf) + } +} + +#[cfg(test)] +mod test { + use super::*; + + use ec::{EcGroup, EcKey}; + use nid::Nid; + use pkey::PKey; + + #[test] + fn derive_without_peer() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.derive_to_vec().unwrap_err(); + } + + #[test] + fn test_ec_key_derive() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let ec_key2 = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.set_peer(&pkey2).unwrap(); + let shared = deriver.derive_to_vec().unwrap(); + assert!(!shared.is_empty()); + } +} diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs new file mode 100644 index 000000000..ef1633106 --- /dev/null +++ b/openssl/src/dh.rs @@ -0,0 +1,188 @@ +use error::ErrorStack; +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use std::mem; +use std::ptr; + +use bn::BigNum; +use pkey::{HasParams, Params}; +use {cvt, cvt_p}; + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::DH; + fn drop = ffi::DH_free; + + pub struct Dh; + + pub struct DhRef; +} + +impl DhRef +where + T: HasParams, +{ + to_pem! { + /// Serializes the parameters into a PEM-encoded PKCS#3 DHparameter structure. + /// + /// The output will have a header of `-----BEGIN DH PARAMETERS-----`. + /// + /// This corresponds to [`PEM_write_bio_DHparams`]. + /// + /// [`PEM_write_bio_DHparams`]: https://www.openssl.org/docs/manmaster/man3/PEM_write_bio_DHparams.html + params_to_pem, + ffi::PEM_write_bio_DHparams + } + + to_der! { + /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. + /// + /// This corresponds to [`i2d_DHparams`]. + /// + /// [`i2d_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DHparams.html + params_to_der, + ffi::i2d_DHparams + } +} + +impl Dh { + pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result, ErrorStack> { + unsafe { + let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); + cvt(DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, g, q)); + Ok(dh) + } + } + + from_pem! { + /// Deserializes a PEM-encoded PKCS#3 DHpararameters structure. + /// + /// The input should have a header of `-----BEGIN DH PARAMETERS-----`. + /// + /// This corresponds to [`PEM_read_bio_DHparams`]. + /// + /// [`PEM_read_bio_DHparams`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DHparams.html + params_from_pem, + Dh, + ffi::PEM_read_bio_DHparams + } + + from_der! { + /// Deserializes a DER-encoded PKCS#3 DHparameters structure. + /// + /// This corresponds to [`d2i_DHparams`]. + /// + /// [`d2i_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_DHparams.html + params_from_der, + Dh, + ffi::d2i_DHparams + } + + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(any(ossl102, ossl110))] + pub fn get_1024_160() -> Result, ErrorStack> { + unsafe { + ffi::init(); + cvt_p(ffi::DH_get_1024_160()).map(|p| Dh::from_ptr(p)) + } + } + + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(any(ossl102, ossl110))] + pub fn get_2048_224() -> Result, ErrorStack> { + unsafe { + ffi::init(); + cvt_p(ffi::DH_get_2048_224()).map(|p| Dh::from_ptr(p)) + } + } + + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(any(ossl102, ossl110))] + pub fn get_2048_256() -> Result, ErrorStack> { + unsafe { + ffi::init(); + cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::DH_set0_pqg; + } else { + #[allow(bad_style)] + unsafe fn DH_set0_pqg( + dh: *mut ffi::DH, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM, + ) -> ::libc::c_int { + (*dh).p = p; + (*dh).q = q; + (*dh).g = g; + 1 + } + } +} + +#[cfg(test)] +mod tests { + use bn::BigNum; + use dh::Dh; + use ssl::{SslContext, SslMethod}; + + #[test] + #[cfg(any(ossl102, ossl110))] + fn test_dh_rfc5114() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let dh1 = Dh::get_1024_160().unwrap(); + ctx.set_tmp_dh(&dh1).unwrap(); + let dh2 = Dh::get_2048_224().unwrap(); + ctx.set_tmp_dh(&dh2).unwrap(); + let dh3 = Dh::get_2048_256().unwrap(); + ctx.set_tmp_dh(&dh3).unwrap(); + } + + #[test] + fn test_dh() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let p = BigNum::from_hex_str( + "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\ + 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\ + 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\ + 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\ + 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\ + C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", + ).unwrap(); + let g = BigNum::from_hex_str( + "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\ + 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\ + 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\ + 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\ + 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\ + B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", + ).unwrap(); + let q = BigNum::from_hex_str( + "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", + ) + .unwrap(); + let dh = Dh::from_params(p, g, q).unwrap(); + ctx.set_tmp_dh(&dh).unwrap(); + } + + #[test] + fn test_dh_from_pem() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let params = include_bytes!("../test/dhparams.pem"); + let dh = Dh::params_from_pem(params).unwrap(); + ctx.set_tmp_dh(&dh).unwrap(); + } + + #[test] + fn test_dh_from_der() { + let params = include_bytes!("../test/dhparams.pem"); + let dh = Dh::params_from_pem(params).unwrap(); + let der = dh.params_to_der().unwrap(); + Dh::params_from_der(&der).unwrap(); + } +} diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs new file mode 100644 index 000000000..1b55d12e6 --- /dev/null +++ b/openssl/src/dsa.rs @@ -0,0 +1,438 @@ +//! Digital Signatures +//! +//! DSA ensures a message originated from a known sender, and was not modified. +//! DSA uses asymetrical keys and an algorithm to output a signature of the message +//! using the private key that can be validated with the public key but not be generated +//! without the private key. + +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::fmt; +use std::mem; +use std::ptr; + +use bn::{BigNum, BigNumRef}; +use error::ErrorStack; +use pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; +use {cvt, cvt_p}; + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::DSA; + fn drop = ffi::DSA_free; + + /// Object representing DSA keys. + /// + /// A DSA object contains the parameters p, q, and g. There is a private + /// and public key. The values p, g, and q are: + /// + /// * `p`: DSA prime parameter + /// * `q`: DSA sub-prime parameter + /// * `g`: DSA base parameter + /// + /// These values are used to calculate a pair of asymetrical keys used for + /// signing. + /// + /// OpenSSL documentation at [`DSA_new`] + /// + /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html + /// + /// # Examples + /// + /// ``` + /// use openssl::dsa::Dsa; + /// use openssl::error::ErrorStack; + /// use openssl::pkey::Private; + /// + /// fn create_dsa() -> Result, ErrorStack> { + /// let sign = Dsa::generate(2048)?; + /// Ok(sign) + /// } + /// # fn main() { + /// # create_dsa(); + /// # } + /// ``` + pub struct Dsa; + /// Reference to [`Dsa`]. + /// + /// [`Dsa`]: struct.Dsa.html + pub struct DsaRef; +} + +impl Clone for Dsa { + fn clone(&self) -> Dsa { + (**self).to_owned() + } +} + +impl ToOwned for DsaRef { + type Owned = Dsa; + + fn to_owned(&self) -> Dsa { + unsafe { + ffi::DSA_up_ref(self.as_ptr()); + Dsa::from_ptr(self.as_ptr()) + } + } +} + +impl DsaRef +where + T: HasPublic, +{ + to_pem! { + /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_DSA_PUBKEY`]. + /// + /// [`PEM_write_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSA_PUBKEY.html + public_key_to_pem, + ffi::PEM_write_bio_DSA_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + /// + /// This corresponds to [`i2d_DSA_PUBKEY`]. + /// + /// [`i2d_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DSA_PUBKEY.html + public_key_to_der, + ffi::i2d_DSA_PUBKEY + } + + /// Returns a reference to the public key component of `self`. + pub fn pub_key(&self) -> &BigNumRef { + unsafe { + let mut pub_key = ptr::null(); + DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); + BigNumRef::from_ptr(pub_key as *mut _) + } + } +} + +impl DsaRef +where + T: HasPrivate, +{ + /// Returns a reference to the private key component of `self`. + pub fn priv_key(&self) -> &BigNumRef { + unsafe { + let mut priv_key = ptr::null(); + DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); + BigNumRef::from_ptr(priv_key as *mut _) + } + } +} + +impl DsaRef +where + T: HasParams, +{ + /// Returns the maximum size of the signature output by `self` in bytes. + /// + /// OpenSSL documentation at [`DSA_size`] + /// + /// [`DSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_size.html + pub fn size(&self) -> u32 { + unsafe { ffi::DSA_size(self.as_ptr()) as u32 } + } + + /// Returns the DSA prime parameter of `self`. + pub fn p(&self) -> &BigNumRef { + unsafe { + let mut p = ptr::null(); + DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_ptr(p as *mut _) + } + } + + /// Returns the DSA sub-prime parameter of `self`. + pub fn q(&self) -> &BigNumRef { + unsafe { + let mut q = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); + BigNumRef::from_ptr(q as *mut _) + } + } + + /// Returns the DSA base parameter of `self`. + pub fn g(&self) -> &BigNumRef { + unsafe { + let mut g = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); + BigNumRef::from_ptr(g as *mut _) + } + } +} + +impl Dsa { + /// Generate a DSA key pair. + /// + /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. + /// These values are used to generate the key pair with [`DSA_generate_key`]. + /// + /// The `bits` parameter corresponds to the length of the prime `p`. + /// + /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html + /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html + pub fn generate(bits: u32) -> Result, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(ffi::DSA_generate_parameters_ex( + dsa.0, + bits as c_int, + ptr::null(), + 0, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ))?; + cvt(ffi::DSA_generate_key(dsa.0))?; + Ok(dsa) + } + } + + /// Create a DSA key pair with the given parameters + /// + /// `p`, `q` and `g` are the common parameters. + /// `priv_key` is the private component of the key pair. + /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p` + pub fn from_private_components( + p: BigNum, + q: BigNum, + g: BigNum, + priv_key: BigNum, + pub_key: BigNum, + ) -> Result, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((pub_key, priv_key)); + Ok(dsa) + } + } +} + +impl Dsa { + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_read_bio_DSA_PUBKEY`]. + /// + /// [`PEM_read_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DSA_PUBKEY.html + public_key_from_pem, + Dsa, + ffi::PEM_read_bio_DSA_PUBKEY + } + + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. + /// + /// This corresponds to [`d2i_DSA_PUBKEY`]. + /// + /// [`d2i_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_DSA_PUBKEY.html + public_key_from_der, + Dsa, + ffi::d2i_DSA_PUBKEY + } + + /// Create a new DSA key with only public components. + /// + /// `p`, `q` and `g` are the common parameters. + /// `pub_key` is the public component of the key. + pub fn from_public_components( + p: BigNum, + q: BigNum, + g: BigNum, + pub_key: BigNum, + ) -> Result, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget(pub_key); + Ok(dsa) + } + } +} + +impl fmt::Debug for Dsa { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DSA") + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM) + { + if !p.is_null() { + *p = (*d).p; + } + if !q.is_null() { + *q = (*d).q; + } + if !g.is_null() { + *g = (*d).g; + } + } + + #[allow(bad_style)] + unsafe fn DSA_get0_key( + d: *mut ffi::DSA, + pub_key: *mut *const ffi::BIGNUM, + priv_key: *mut *const ffi::BIGNUM) + { + if !pub_key.is_null() { + *pub_key = (*d).pub_key; + } + if !priv_key.is_null() { + *priv_key = (*d).priv_key; + } + } + + #[allow(bad_style)] + unsafe fn DSA_set0_key( + d: *mut ffi::DSA, + pub_key: *mut ffi::BIGNUM, + priv_key: *mut ffi::BIGNUM) -> c_int + { + (*d).pub_key = pub_key; + (*d).priv_key = priv_key; + 1 + } + + #[allow(bad_style)] + unsafe fn DSA_set0_pqg( + d: *mut ffi::DSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM) -> c_int + { + (*d).p = p; + (*d).q = q; + (*d).g = g; + 1 + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use bn::BigNumContext; + use hash::MessageDigest; + use pkey::PKey; + use sign::{Signer, Verifier}; + + #[test] + pub fn test_generate() { + Dsa::generate(1024).unwrap(); + } + + #[test] + fn test_pubkey_generation() { + let dsa = Dsa::generate(1024).unwrap(); + let p = dsa.p(); + let g = dsa.g(); + let priv_key = dsa.priv_key(); + let pub_key = dsa.pub_key(); + let mut ctx = BigNumContext::new().unwrap(); + let mut calc = BigNum::new().unwrap(); + calc.mod_exp(g, priv_key, p, &mut ctx).unwrap(); + assert_eq!(&calc, pub_key) + } + + #[test] + fn test_priv_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let priv_key = BigNum::from_u32(15).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + fn test_pub_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); + } + + #[test] + fn test_signature() { + const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let dsa_ref = Dsa::generate(1024).unwrap(); + + let p = dsa_ref.p(); + let q = dsa_ref.q(); + let g = dsa_ref.g(); + + let pub_key = dsa_ref.pub_key(); + let priv_key = dsa_ref.priv_key(); + + let priv_key = Dsa::from_private_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(priv_key).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let priv_key = PKey::from_dsa(priv_key).unwrap(); + + let pub_key = Dsa::from_public_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); + let pub_key = PKey::from_dsa(pub_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); + signer.update(TEST_DATA).unwrap(); + + let signature = signer.sign_to_vec().unwrap(); + let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + verifier.update(TEST_DATA).unwrap(); + assert!(verifier.verify(&signature[..]).unwrap()); + } + + #[test] + fn clone() { + let key = Dsa::generate(2048).unwrap(); + drop(key.clone()); + } +} diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs new file mode 100644 index 000000000..d757e3ed7 --- /dev/null +++ b/openssl/src/ec.rs @@ -0,0 +1,952 @@ +//! Elliptic Curve +//! +//! Cryptology relies on the difficulty of solving mathematical problems, such as the factor +//! of large integers composed of two large prime numbers and the discrete logarithm of a +//! random eliptic curve. This module provides low-level features of the latter. +//! Elliptic Curve protocols can provide the same security with smaller keys. +//! +//! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible +//! trinomial or pentanomial . Being a generic interface to a wide range of algorithms, +//! the cuves are generally referenced by [`EcGroup`]. There are many built in groups +//! found in [`Nid`]. +//! +//! OpenSSL Wiki explains the fields and curves in detail at [Eliptic Curve Cryptography]. +//! +//! [`EcGroup`]: struct.EcGroup.html +//! [`Nid`]: ../nid/struct.Nid.html +//! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography +//! +//! # Examples +//! +//! ``` +//! use openssl::ec::{EcGroup, EcPoint}; +//! use openssl::nid::Nid; +//! use openssl::error::ErrorStack; +//! fn get_ec_point() -> Result { +//! let group = EcGroup::from_curve_name(Nid::SECP224R1)?; +//! let point = EcPoint::new(&group)?; +//! Ok(point) +//! } +//! # fn main() { +//! # let _ = get_ec_point(); +//! # } +//! ``` +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::ptr; + +use bn::{BigNumContextRef, BigNumRef}; +use error::ErrorStack; +use nid::Nid; +use pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; +use {cvt, cvt_n, cvt_p, init}; + +/// Compressed or Uncompressed conversion +/// +/// Conversion from the binary value of the point on the curve is performed in one of +/// compressed, uncompressed, or hybrid conversions. The default is compressed, except +/// for binary curves. +/// +/// Further documentation is available in the [X9.62] standard. +/// +/// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf +#[derive(Copy, Clone)] +pub struct PointConversionForm(ffi::point_conversion_form_t); + +impl PointConversionForm { + /// Compressed conversion from point value. + pub const COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + + /// Uncompressed conversion from point value. + pub const UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + + /// Performs both compressed and uncompressed conversions. + pub const HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); +} + +/// Named Curve or Explicit +/// +/// This type acts as a boolean as to whether the `EcGroup` is named or explicit. +#[derive(Copy, Clone)] +pub struct Asn1Flag(c_int); + +impl Asn1Flag { + /// Curve defined using polynomial parameters + /// + /// Most applications use a named EC_GROUP curve, however, support + /// is included to explicitly define the curve used to calculate keys + /// This information would need to be known by both endpoint to make communication + /// effective. + /// + /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. + /// Man page documents that 0 can be used in older versions. + /// + /// OpenSSL documentation at [`EC_GROUP`] + /// + /// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html + pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); + + /// Standard Curves + /// + /// Curves that make up the typical encryption use cases. The collection of curves + /// are well known but extensible. + /// + /// OpenSSL documentation at [`EC_GROUP`] + /// + /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html + pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::EC_GROUP; + fn drop = ffi::EC_GROUP_free; + + /// Describes the curve + /// + /// A curve can be of the named curve type. These curves can be discovered + /// using openssl binary `openssl ecparam -list_curves`. Other operations + /// are available in the [wiki]. These named curves are available in the + /// [`Nid`] module. + /// + /// Curves can also be generated using prime field parameters or a binary field. + /// + /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary + /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have + /// assured security. To prevent accidental vulnerabilities, they should + /// be prefered. + /// + /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations + /// [`Nid`]: ../nid/index.html + pub struct EcGroup; + /// Reference to [`EcGroup`] + /// + /// [`EcGroup`]: struct.EcGroup.html + pub struct EcGroupRef; +} + +impl EcGroup { + /// Returns the group of a standard named curve. + /// + /// OpenSSL documentation at [`EC_GROUP_new`]. + /// + /// [`EC_GROUP_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_new.html + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) + } + } +} + +impl EcGroupRef { + /// Places the components of a curve over a prime field in the provided `BigNum`s. + /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. + /// + /// OpenSSL documentation available at [`EC_GROUP_get_curve_GFp`] + /// + /// [`EC_GROUP_get_curve_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GFp.html + pub fn components_gfp( + &self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GFp( + self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Places the components of a curve over a binary field in the provided `BigNum`s. + /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`. + /// + /// In this form `p` relates to the irreducible polynomial. Each bit represents + /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on + /// using a trinomial or pentanomial. + /// + /// OpenSSL documentation at [`EC_GROUP_get_curve_GF2m`]. + /// + /// [`EC_GROUP_get_curve_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GF2m.html + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn components_gf2m( + &self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GF2m( + self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Returns the degree of the curve. + /// + /// OpenSSL documentation at [`EC_GROUP_get_degree`] + /// + /// [`EC_GROUP_get_degree`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_degree.html + pub fn degree(&self) -> u32 { + unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } + } + + /// Places the order of the curve in the provided `BigNum`. + /// + /// OpenSSL documentation at [`EC_GROUP_get_order`] + /// + /// [`EC_GROUP_get_order`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_order.html + pub fn order( + &self, + order: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_order( + self.as_ptr(), + order.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the flag determining if the group corresponds to a named curve or must be explicitly + /// parameterized. + /// + /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL + /// 1.1.0. + pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { + unsafe { + ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); + } + } + + /// Returns the name of the curve, if a name is associated. + /// + /// OpenSSL documentation at [`EC_GROUP_get_curve_name`] + /// + /// [`EC_GROUP_get_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_name.html + pub fn curve_name(&self) -> Option { + let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; + if nid > 0 { Some(Nid::from_raw(nid)) } else { None } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::EC_POINT; + fn drop = ffi::EC_POINT_free; + + /// Represents a point on the curve + /// + /// OpenSSL documentation at [`EC_POINT_new`] + /// + /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html + pub struct EcPoint; + /// Reference to [`EcPoint`] + /// + /// [`EcPoint`]: struct.EcPoint.html + pub struct EcPointRef; +} + +impl EcPointRef { + /// Computes `a + b`, storing the result in `self`. + /// + /// OpenSSL documentation at [`EC_POINT_add`] + /// + /// [`EC_POINT_add`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_add.html + pub fn add( + &mut self, + group: &EcGroupRef, + a: &EcPointRef, + b: &EcPointRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_add( + group.as_ptr(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Computes `q * m`, storing the result in `self`. + /// + /// OpenSSL documentation at [`EC_POINT_mul`] + /// + /// [`EC_POINT_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_mul.html + pub fn mul( + &mut self, + group: &EcGroupRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul( + group.as_ptr(), + self.as_ptr(), + ptr::null(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Computes `generator * n`, storing the result ing `self`. + pub fn mul_generator( + &mut self, + group: &EcGroupRef, + n: &BigNumRef, + ctx: &BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul( + group.as_ptr(), + self.as_ptr(), + n.as_ptr(), + ptr::null(), + ptr::null(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_full( + &mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul( + group.as_ptr(), + self.as_ptr(), + n.as_ptr(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Inverts `self`. + /// + /// OpenSSL documentation at [`EC_POINT_invert`] + /// + /// [`EC_POINT_invert`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_invert.html + pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_invert( + group.as_ptr(), + self.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Serializes the point to a binary representation. + /// + /// OpenSSL documentation at [`EC_POINT_point2oct`] + /// + /// [`EC_POINT_point2oct`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_point2oct.html + pub fn to_bytes( + &self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef, + ) -> Result, ErrorStack> { + unsafe { + let len = ffi::EC_POINT_point2oct( + group.as_ptr(), + self.as_ptr(), + form.0, + ptr::null_mut(), + 0, + ctx.as_ptr(), + ); + if len == 0 { + return Err(ErrorStack::get()); + } + let mut buf = vec![0; len]; + let len = ffi::EC_POINT_point2oct( + group.as_ptr(), + self.as_ptr(), + form.0, + buf.as_mut_ptr(), + len, + ctx.as_ptr(), + ); + if len == 0 { + Err(ErrorStack::get()) + } else { + Ok(buf) + } + } + } + + /// Determines if this point is equal to another. + /// + /// OpenSSL doucmentation at [`EC_POINT_cmp`] + /// + /// [`EC_POINT_cmp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_cmp.html + pub fn eq( + &self, + group: &EcGroupRef, + other: &EcPointRef, + ctx: &mut BigNumContextRef, + ) -> Result { + unsafe { + let res = cvt_n(ffi::EC_POINT_cmp( + group.as_ptr(), + self.as_ptr(), + other.as_ptr(), + ctx.as_ptr(), + ))?; + Ok(res == 0) + } + } + + /// Place affine coordinates of a curve over a prime field in the provided + /// `x` and `y` `BigNum`s + /// + /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GFp`] + /// + /// [`EC_POINT_get_affine_coordinates_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GFp.html + pub fn affine_coordinates_gfp( + &self, + group: &EcGroupRef, + x: &mut BigNumRef, + y: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_get_affine_coordinates_GFp( + group.as_ptr(), + self.as_ptr(), + x.as_ptr(), + y.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Place affine coordinates of a curve over a binary field in the provided + /// `x` and `y` `BigNum`s + /// + /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`] + /// + /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html + #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] + pub fn affine_coordinates_gf2m( + &self, + group: &EcGroupRef, + x: &mut BigNumRef, + y: &mut BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_get_affine_coordinates_GF2m( + group.as_ptr(), + self.as_ptr(), + x.as_ptr(), + y.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } +} + +impl EcPoint { + /// Creates a new point on the specified curve. + /// + /// OpenSSL documentation at [`EC_POINT_new`] + /// + /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html + pub fn new(group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } + } + + /// Creates point from a binary representation + /// + /// OpenSSL documentation at [`EC_POINT_oct2point`] + /// + /// [`EC_POINT_oct2point`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_oct2point.html + pub fn from_bytes( + group: &EcGroupRef, + buf: &[u8], + ctx: &mut BigNumContextRef, + ) -> Result { + let point = EcPoint::new(group)?; + unsafe { + cvt(ffi::EC_POINT_oct2point( + group.as_ptr(), + point.as_ptr(), + buf.as_ptr(), + buf.len(), + ctx.as_ptr(), + ))?; + } + Ok(point) + } +} + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::EC_KEY; + fn drop = ffi::EC_KEY_free; + + /// Public and optional Private key on the given curve + /// + /// OpenSSL documentation at [`EC_KEY_new`] + /// + /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html + pub struct EcKey; + + /// Reference to [`EcKey`] + /// + /// [`EcKey`]: struct.EcKey.html + pub struct EcKeyRef; +} + +impl EcKeyRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded ECPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. + /// + /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. + /// + /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html + private_key_to_pem_passphrase, + ffi::PEM_write_bio_ECPrivateKey + } + + to_der! { + /// Serializes the private key into a DER-encoded ECPrivateKey structure. + /// + /// This corresponds to [`i2d_ECPrivateKey`]. + /// + /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html + private_key_to_der, + ffi::i2d_ECPrivateKey + } + + /// Return [`EcPoint`] associated with the private key + /// + /// OpenSSL documentation at [`EC_KEY_get0_private_key`] + /// + /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html + pub fn private_key(&self) -> &BigNumRef { + unsafe { + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + BigNumRef::from_ptr(ptr as *mut _) + } + } +} + +impl EcKeyRef +where + T: HasPublic, +{ + /// Returns the public key. + /// + /// OpenSSL documentation at [`EC_KEY_get0_pubic_key`] + /// + /// [`EC_KEY_get0_pubic_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html + pub fn public_key(&self) -> &EcPointRef { + unsafe { + let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); + EcPointRef::from_ptr(ptr as *mut _) + } + } +} + +impl EcKeyRef +where + T: HasParams, +{ + /// Return [`EcGroup`] of the `EcKey` + /// + /// OpenSSL documentation at [`EC_KEY_get0_group`] + /// + /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html + pub fn group(&self) -> &EcGroupRef { + unsafe { + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + EcGroupRef::from_ptr(ptr as *mut _) + } + } + + /// Checks the key for validity. + /// + /// OpenSSL documenation at [`EC_KEY_check_key`] + /// + /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html + pub fn check_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } + } +} + +impl ToOwned for EcKeyRef { + type Owned = EcKey; + + fn to_owned(&self) -> EcKey { + unsafe { + let r = ffi::EC_KEY_up_ref(self.as_ptr()); + assert!(r == 1); + EcKey::from_ptr(self.as_ptr()) + } + } +} + +impl EcKey { + /// Constructs an `EcKey` corresponding to a known curve. + /// + /// It will not have an associated public or private key. This kind of key is primarily useful + /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. + /// + /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`] + /// + /// [`EC_KEY_new_by_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new_by_curve_name.html + pub fn from_curve_name(nid: Nid) -> Result, ErrorStack> { + unsafe { + init(); + cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) + } + } + + /// Constructs an `EcKey` corresponding to a curve. + /// + /// This corresponds to [`EC_KEY_set_group`]. + /// + /// [`EC_KEY_set_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html + pub fn from_group(group: &EcGroupRef) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + } + } +} + +impl EcKey { + /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key. + /// + /// This will only have the associated public_key. + /// + /// # Example + /// + /// ```no_run + /// use openssl::bn::BigNumContext; + /// use openssl::ec::*; + /// use openssl::nid::Nid; + /// use openssl::pkey::PKey; + /// + /// // get bytes from somewhere, i.e. this will not produce a valid key + /// let public_key: Vec = vec![]; + /// + /// // create an EcKey from the binary form of a EcPoint + /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); + /// let mut ctx = BigNumContext::new().unwrap(); + /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap(); + /// let key = EcKey::from_public_key(&group, &point); + /// ``` + pub fn from_public_key( + group: &EcGroupRef, + public_key: &EcPointRef, + ) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key( + key.as_ptr(), + public_key.as_ptr(), + )) + .map(|_| key) + }) + } + } + + /// Constructs a public key from its affine coordinates. + pub fn from_public_key_affine_coordinates( + group: &EcGroupRef, + x: &BigNumRef, + y: &BigNumRef, + ) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key_affine_coordinates( + key.as_ptr(), + x.as_ptr(), + y.as_ptr(), + )) + .map(|_| key) + }) + } + } +} + +impl EcKey { + /// Generates a new public/private key pair on the specified curve. + pub fn generate(group: &EcGroupRef) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) + } + } + + /// Constructs an public/private key pair given a curve, a private key and a public key point. + pub fn from_private_components( + group: &EcGroupRef, + private_number: &BigNumRef, + public_key: &EcPointRef, + ) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::EC_KEY_new()) + .map(|p| EcKey::from_ptr(p)) + .and_then(|key| { + cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_private_key( + key.as_ptr(), + private_number.as_ptr(), + )) + .map(|_| key) + }) + .and_then(|key| { + cvt(ffi::EC_KEY_set_public_key( + key.as_ptr(), + public_key.as_ptr(), + )) + .map(|_| key) + }) + } + } + + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + /// + /// This corresponds to `PEM_read_bio_ECPrivateKey`. + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + /// + /// This corresponds to `PEM_read_bio_ECPrivateKey`. + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. + /// + /// The callback should fill the password into the provided buffer and return its length. + /// + /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. + /// + /// This corresponds to `PEM_read_bio_ECPrivateKey`. + private_key_from_pem_callback, + EcKey, + ffi::PEM_read_bio_ECPrivateKey + } + + from_der! { + /// Decodes a DER-encoded elliptic curve private key structure. + /// + /// This corresponds to [`d2i_ECPrivateKey`]. + /// + /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html + private_key_from_der, + EcKey, + ffi::d2i_ECPrivateKey + } +} + +impl Clone for EcKey { + fn clone(&self) -> EcKey { + (**self).to_owned() + } +} + +#[cfg(test)] +mod test { + use hex::FromHex; + + use super::*; + use bn::{BigNum, BigNumContext}; + use nid::Nid; + + #[test] + fn key_new_by_curve_name() { + EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + } + + #[test] + fn generate() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + EcKey::generate(&group).unwrap(); + } + + #[test] + fn dup() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + drop(key.clone()); + } + + #[test] + fn point_new() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + EcPoint::new(&group).unwrap(); + } + + #[test] + fn point_bytes() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = point + .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) + .unwrap(); + let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } + + #[test] + fn mul_generator() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let mut public_key = EcPoint::new(&group).unwrap(); + public_key + .mul_generator(&group, key.private_key(), &mut ctx) + .unwrap(); + assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); + } + + #[test] + fn key_from_public_key() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = key + .public_key() + .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) + .unwrap(); + + drop(key); + let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); + assert!(ec_key.check_key().is_ok()); + } + + #[test] + fn key_from_private_components() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + + let dup_key = + EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); + let res = dup_key.check_key().unwrap(); + + assert!(res == ()); + assert!(key.private_key() == dup_key.private_key()); + } + + #[test] + fn key_from_affine_coordinates() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") + .unwrap(); + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") + .unwrap(); + + let xbn = BigNum::from_slice(&x).unwrap(); + let ybn = BigNum::from_slice(&y).unwrap(); + + let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); + assert!(ec_key.check_key().is_ok()); + } + + #[test] + fn get_affine_coordinates() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") + .unwrap(); + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") + .unwrap(); + + let xbn = BigNum::from_slice(&x).unwrap(); + let ybn = BigNum::from_slice(&y).unwrap(); + + let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); + + let mut xbn2 = BigNum::new().unwrap(); + let mut ybn2 = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let ec_key_pk = ec_key.public_key(); + ec_key_pk + .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) + .unwrap(); + assert_eq!(xbn2, xbn); + assert_eq!(ybn2, ybn); + } +} diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs new file mode 100644 index 000000000..06be274f9 --- /dev/null +++ b/openssl/src/ecdsa.rs @@ -0,0 +1,238 @@ +//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::mem; +use std::ptr; + +use bn::{BigNum, BigNumRef}; +use ec::EcKeyRef; +use error::ErrorStack; +use pkey::{Private, Public}; +use {cvt_n, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::ECDSA_SIG; + fn drop = ffi::ECDSA_SIG_free; + + /// A low level interface to ECDSA + /// + /// OpenSSL documentation at [`ECDSA_sign`] + /// + /// [`ECDSA_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_sign.html + pub struct EcdsaSig; + /// Reference to [`EcdsaSig`] + /// + /// [`EcdsaSig`]: struct.EcdsaSig.html + pub struct EcdsaSigRef; +} + +impl EcdsaSig { + /// Computes a digital signature of the hash value `data` using the private EC key eckey. + /// + /// OpenSSL documentation at [`ECDSA_do_sign`] + /// + /// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html + pub fn sign(data: &[u8], eckey: &EcKeyRef) -> Result { + unsafe { + assert!(data.len() <= c_int::max_value() as usize); + let sig = cvt_p(ffi::ECDSA_do_sign( + data.as_ptr(), + data.len() as c_int, + eckey.as_ptr(), + ))?; + Ok(EcdsaSig::from_ptr(sig as *mut _)) + } + } + + /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a + /// ECDSA signature. + /// + /// OpenSSL documentation at [`ECDSA_SIG_set0`] + /// + /// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html + pub fn from_private_components(r: BigNum, s: BigNum) -> Result { + unsafe { + let sig = cvt_p(ffi::ECDSA_SIG_new())?; + ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); + mem::forget((r, s)); + Ok(EcdsaSig::from_ptr(sig as *mut _)) + } + } + + /// Verifies if the signature is a valid ECDSA signature using the given public key. + /// + /// OpenSSL documentation at [`ECDSA_do_verify`] + /// + /// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html + pub fn verify(&self, data: &[u8], eckey: &EcKeyRef) -> Result { + unsafe { + assert!(data.len() <= c_int::max_value() as usize); + cvt_n(ffi::ECDSA_do_verify( + data.as_ptr(), + data.len() as c_int, + self.as_ptr(), + eckey.as_ptr(), + )) + .map(|x| x == 1) + } + } + + /// Returns internal component: `r` of a `EcdsaSig`. (See X9.62 or FIPS 186-2) + /// + /// OpenSSL documentation at [`ECDSA_SIG_get0`] + /// + /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html + pub fn r(&self) -> &BigNumRef { + unsafe { + let mut r = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); + BigNumRef::from_ptr(r as *mut _) + } + } + + /// Returns internal components: `s` of a `EcdsaSig`. (See X9.62 or FIPS 186-2) + /// + /// OpenSSL documentation at [`ECDSA_SIG_get0`] + /// + /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html + pub fn s(&self) -> &BigNumRef { + unsafe { + let mut s = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); + BigNumRef::from_ptr(s as *mut _) + } + } + + from_der! { + /// Decodes a DER-encoded ECDSA signature. + /// + /// This corresponds to [`d2i_ECDSA_SIG`]. + /// + /// [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html + from_der, + EcdsaSig, + ffi::d2i_ECDSA_SIG + } +} + +impl EcdsaSigRef { + to_der! { + /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. + /// + /// This corresponds to [`i2d_ECDSA_SIG`]. + /// + /// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html + to_der, + ffi::i2d_ECDSA_SIG + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; + } else { + #[allow(bad_style)] + unsafe fn ECDSA_SIG_set0( + sig: *mut ffi::ECDSA_SIG, + r: *mut ffi::BIGNUM, + s: *mut ffi::BIGNUM, + ) -> c_int { + (*sig).r = r; + (*sig).s = s; + 1 + } + + #[allow(bad_style)] + unsafe fn ECDSA_SIG_get0( + sig: *const ffi::ECDSA_SIG, + pr: *mut *const ffi::BIGNUM, + ps: *mut *const ffi::BIGNUM) + { + if !pr.is_null() { + (*pr) = (*sig).r; + } + if !ps.is_null() { + (*ps) = (*sig).s; + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use ec::EcGroup; + use ec::EcKey; + use nid::Nid; + + fn get_public_key(group: &EcGroup, x: &EcKey) -> Result, ErrorStack> { + let public_key_point = x.public_key(); + Ok(EcKey::from_public_key(group, public_key_point)?) + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn sign_and_verify() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + + let private_key2 = EcKey::generate(&group).unwrap(); + let public_key2 = get_public_key(&group, &private_key2).unwrap(); + + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + // Signature can be verified using the correct data & correct public key + let verification = res.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + + // Signature will not be verified using the incorrect data but the correct public key + let verification2 = res + .verify(String::from("hello2").as_bytes(), &public_key) + .unwrap(); + assert!(verification2 == false); + + // Signature will not be verified using the correct data but the incorrect public key + let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap(); + assert!(verification3 == false); + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn check_private_components() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + let verification = res.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + + let r = res.r().to_owned().unwrap(); + let s = res.s().to_owned().unwrap(); + + let res2 = EcdsaSig::from_private_components(r, s).unwrap(); + let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification2); + } + + #[test] + #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] + fn serialize_deserialize() { + let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); + let private_key = EcKey::generate(&group).unwrap(); + let public_key = get_public_key(&group, &private_key).unwrap(); + + let data = String::from("hello"); + let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); + + let der = res.to_der().unwrap(); + let sig = EcdsaSig::from_der(&der).unwrap(); + + let verification = sig.verify(data.as_bytes(), &public_key).unwrap(); + assert!(verification); + } +} diff --git a/openssl/src/envelope.rs b/openssl/src/envelope.rs new file mode 100644 index 000000000..1101cde75 --- /dev/null +++ b/openssl/src/envelope.rs @@ -0,0 +1,282 @@ +//! Envelope encryption. +//! +//! # Example +//! +//! ```rust +//! +//! extern crate openssl; +//! +//! use openssl::rsa::Rsa; +//! use openssl::envelope::Seal; +//! use openssl::pkey::PKey; +//! use openssl::symm::Cipher; +//! +//! fn main() { +//! let rsa = Rsa::generate(2048).unwrap(); +//! let key = PKey::from_rsa(rsa).unwrap(); +//! +//! let cipher = Cipher::aes_256_cbc(); +//! let mut seal = Seal::new(cipher, &[key]).unwrap(); +//! +//! let secret = b"My secret message"; +//! let mut encrypted = vec![0; secret.len() + cipher.block_size()]; +//! +//! let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); +//! enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); +//! encrypted.truncate(enc_len); +//! } +//! ``` +use error::ErrorStack; +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; +use std::cmp; +use std::ptr; +use symm::Cipher; +use {cvt, cvt_p}; + +/// Represents an EVP_Seal context. +pub struct Seal { + ctx: *mut ffi::EVP_CIPHER_CTX, + block_size: usize, + iv: Option>, + enc_keys: Vec>, +} + +impl Seal { + /// Creates a new `Seal`. + pub fn new(cipher: Cipher, pub_keys: &[PKey]) -> Result + where + T: HasPublic, + { + unsafe { + assert!(pub_keys.len() <= c_int::max_value() as usize); + + let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + let mut enc_key_ptrs = vec![]; + let mut pub_key_ptrs = vec![]; + let mut enc_keys = vec![]; + for key in pub_keys { + let mut enc_key = vec![0; key.size()]; + let enc_key_ptr = enc_key.as_mut_ptr(); + enc_keys.push(enc_key); + enc_key_ptrs.push(enc_key_ptr); + pub_key_ptrs.push(key.as_ptr()); + } + let mut iv = cipher.iv_len().map(|len| Vec::with_capacity(len)); + let iv_ptr = iv.as_mut().map_or(ptr::null_mut(), |v| v.as_mut_ptr()); + let mut enc_key_lens = vec![0; enc_keys.len()]; + + cvt(ffi::EVP_SealInit( + ctx, + cipher.as_ptr(), + enc_key_ptrs.as_mut_ptr(), + enc_key_lens.as_mut_ptr(), + iv_ptr, + pub_key_ptrs.as_mut_ptr(), + pub_key_ptrs.len() as c_int, + ))?; + + for (buf, len) in enc_keys.iter_mut().zip(&enc_key_lens) { + buf.truncate(*len as usize); + } + + Ok(Seal { + ctx, + block_size: cipher.block_size(), + iv, + enc_keys, + }) + } + } + + /// Returns the initialization vector, if the cipher uses one. + pub fn iv(&self) -> Option<&[u8]> { + self.iv.as_ref().map(|v| &**v) + } + + /// Returns the encrypted keys. + pub fn encrypted_keys(&self) -> &[Vec] { + &self.enc_keys + } + + /// Feeds data from `input` through the cipher, writing encrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where `block_size` is + /// the block size of the cipher (see `Cipher::block_size`), or if + /// `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= input.len() + self.block_size); + assert!(output.len() <= c_int::max_value() as usize); + let mut outl = output.len() as c_int; + let inl = input.len() as c_int; + cvt(ffi::EVP_EncryptUpdate( + self.ctx, + output.as_mut_ptr(), + &mut outl, + input.as_ptr(), + inl, + ))?; + Ok(outl as usize) + } + } + + /// Finishes the encryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= self.block_size); + let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; + + cvt(ffi::EVP_SealFinal(self.ctx, output.as_mut_ptr(), &mut outl))?; + + Ok(outl as usize) + } + } +} + +impl Drop for Seal { + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_CTX_free(self.ctx); + } + } +} + +/// Represents an EVP_Open context. +pub struct Open { + ctx: *mut ffi::EVP_CIPHER_CTX, + block_size: usize, +} + +impl Open { + /// Creates a new `Open`. + pub fn new( + cipher: Cipher, + priv_key: &PKeyRef, + iv: Option<&[u8]>, + encrypted_key: &[u8], + ) -> Result + where + T: HasPrivate, + { + unsafe { + assert!(encrypted_key.len() <= c_int::max_value() as usize); + assert!(cipher.iv_len().is_none() || iv.is_some()); + + let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + cvt(ffi::EVP_OpenInit( + ctx, + cipher.as_ptr(), + encrypted_key.as_ptr(), + encrypted_key.len() as c_int, + iv.map_or(ptr::null(), |v| v.as_ptr()), + priv_key.as_ptr(), + ))?; + Ok(Open { + ctx, + block_size: cipher.block_size(), + }) + } + } + + /// Feeds data from `input` through the cipher, writing decrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where + /// `block_size` is the block size of the cipher (see `Cipher::block_size`), + /// or if `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= input.len() + self.block_size); + assert!(output.len() <= c_int::max_value() as usize); + let mut outl = output.len() as c_int; + let inl = input.len() as c_int; + cvt(ffi::EVP_DecryptUpdate( + self.ctx, + output.as_mut_ptr(), + &mut outl, + input.as_ptr(), + inl, + ))?; + Ok(outl as usize) + } + } + + /// Finishes the decryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= self.block_size); + let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; + + cvt(ffi::EVP_OpenFinal(self.ctx, output.as_mut_ptr(), &mut outl))?; + + Ok(outl as usize) + } + } +} + +impl Drop for Open { + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_CTX_free(self.ctx); + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use pkey::PKey; + use symm::Cipher; + + #[test] + fn public_encrypt_private_decrypt() { + let private_pem = include_bytes!("../test/rsa.pem"); + let public_pem = include_bytes!("../test/rsa.pem.pub"); + let private_key = PKey::private_key_from_pem(private_pem).unwrap(); + let public_key = PKey::public_key_from_pem(public_pem).unwrap(); + let cipher = Cipher::aes_256_cbc(); + let secret = b"My secret message"; + + let mut seal = Seal::new(cipher, &[public_key]).unwrap(); + let mut encrypted = vec![0; secret.len() + cipher.block_size()]; + let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); + enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); + let iv = seal.iv(); + let encrypted_key = &seal.encrypted_keys()[0]; + + let mut open = Open::new(cipher, &private_key, iv, &encrypted_key).unwrap(); + let mut decrypted = vec![0; enc_len + cipher.block_size()]; + let mut dec_len = open.update(&encrypted[..enc_len], &mut decrypted).unwrap(); + dec_len += open.finalize(&mut decrypted[dec_len..]).unwrap(); + + assert_eq!(&secret[..], &decrypted[..dec_len]); + } +} diff --git a/openssl/src/error.rs b/openssl/src/error.rs new file mode 100644 index 000000000..f272da67a --- /dev/null +++ b/openssl/src/error.rs @@ -0,0 +1,292 @@ +//! Errors returned by OpenSSL library. +//! +//! OpenSSL errors are stored in an `ErrorStack`. Most methods in the crate +//! returns a `Result` type. +//! +//! # Examples +//! +//! ``` +//! use openssl::error::ErrorStack; +//! use openssl::bn::BigNum; +//! +//! let an_error = BigNum::from_dec_str("Cannot parse letters"); +//! match an_error { +//! Ok(_) => (), +//! Err(e) => println!("Parsing Error: {:?}", e), +//! } +//! ``` +use libc::{c_char, c_int, c_ulong}; +use std::borrow::Cow; +use std::error; +use std::ffi::CStr; +use std::fmt; +use std::io; +use std::ptr; +use std::str; + +use ffi; + +/// Collection of [`Error`]s from OpenSSL. +/// +/// [`Error`]: struct.Error.html +#[derive(Debug, Clone)] +pub struct ErrorStack(Vec); + +impl ErrorStack { + /// Returns the contents of the OpenSSL error stack. + pub fn get() -> ErrorStack { + let mut vec = vec![]; + while let Some(err) = Error::get() { + vec.push(err); + } + ErrorStack(vec) + } + + /// Pushes the errors back onto the OpenSSL error stack. + pub fn put(&self) { + for error in self.errors() { + error.put(); + } + } +} + +impl ErrorStack { + /// Returns the errors in the stack. + pub fn errors(&self) -> &[Error] { + &self.0 + } +} + +impl fmt::Display for ErrorStack { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if self.0.is_empty() { + return fmt.write_str("OpenSSL error"); + } + + let mut first = true; + for err in &self.0 { + if !first { + fmt.write_str(", ")?; + } + write!(fmt, "{}", err)?; + first = false; + } + Ok(()) + } +} + +impl error::Error for ErrorStack { + fn description(&self) -> &str { + "An OpenSSL error stack" + } +} + +impl From for io::Error { + fn from(e: ErrorStack) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for fmt::Error { + fn from(_: ErrorStack) -> fmt::Error { + fmt::Error + } +} + +/// An error reported from OpenSSL. +#[derive(Clone)] +pub struct Error { + code: c_ulong, + file: *const c_char, + line: c_int, + data: Option>, +} + +unsafe impl Sync for Error {} +unsafe impl Send for Error {} + +impl Error { + /// Returns the first error on the OpenSSL error stack. + pub fn get() -> Option { + unsafe { + ffi::init(); + + let mut file = ptr::null(); + let mut line = 0; + let mut data = ptr::null(); + let mut flags = 0; + match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) { + 0 => None, + code => { + // The memory referenced by data is only valid until that slot is overwritten + // in the error stack, so we'll need to copy it off if it's dynamic + let data = if flags & ffi::ERR_TXT_STRING != 0 { + let bytes = CStr::from_ptr(data as *const _).to_bytes(); + let data = str::from_utf8(bytes).unwrap(); + let data = if flags & ffi::ERR_TXT_MALLOCED != 0 { + Cow::Owned(data.to_string()) + } else { + Cow::Borrowed(data) + }; + Some(data) + } else { + None + }; + Some(Error { + code, + file, + line, + data, + }) + } + } + } + } + + /// Pushes the error back onto the OpenSSL error stack. + pub fn put(&self) { + unsafe { + ffi::ERR_put_error( + ffi::ERR_GET_LIB(self.code), + ffi::ERR_GET_FUNC(self.code), + ffi::ERR_GET_REASON(self.code), + self.file, + self.line, + ); + let data = match self.data { + Some(Cow::Borrowed(data)) => Some((data.as_ptr() as *mut c_char, 0)), + Some(Cow::Owned(ref data)) => { + let ptr = ffi::CRYPTO_malloc( + (data.len() + 1) as _, + concat!(file!(), "\0").as_ptr() as _, + line!() as _, + ) as *mut c_char; + if ptr.is_null() { + None + } else { + ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len()); + *ptr.offset(data.len() as isize) = 0; + Some((ptr, ffi::ERR_TXT_MALLOCED)) + } + } + None => None, + }; + if let Some((ptr, flags)) = data { + ffi::ERR_set_error_data(ptr, flags | ffi::ERR_TXT_STRING); + } + } + } + + /// Returns the raw OpenSSL error code for this error. + pub fn code(&self) -> c_ulong { + self.code + } + + /// Returns the name of the library reporting the error, if available. + pub fn library(&self) -> Option<&'static str> { + unsafe { + let cstr = ffi::ERR_lib_error_string(self.code); + if cstr.is_null() { + return None; + } + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + Some(str::from_utf8(bytes).unwrap()) + } + } + + /// Returns the name of the function reporting the error. + pub fn function(&self) -> Option<&'static str> { + unsafe { + let cstr = ffi::ERR_func_error_string(self.code); + if cstr.is_null() { + return None; + } + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + Some(str::from_utf8(bytes).unwrap()) + } + } + + /// Returns the reason for the error. + pub fn reason(&self) -> Option<&'static str> { + unsafe { + let cstr = ffi::ERR_reason_error_string(self.code); + if cstr.is_null() { + return None; + } + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + Some(str::from_utf8(bytes).unwrap()) + } + } + + /// Returns the name of the source file which encountered the error. + pub fn file(&self) -> &'static str { + unsafe { + assert!(!self.file.is_null()); + let bytes = CStr::from_ptr(self.file as *const _).to_bytes(); + str::from_utf8(bytes).unwrap() + } + } + + /// Returns the line in the source file which encountered the error. + pub fn line(&self) -> u32 { + self.line as u32 + } + + /// Returns additional data describing the error. + pub fn data(&self) -> Option<&str> { + self.data.as_ref().map(|s| &**s) + } +} + +impl fmt::Debug for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("Error"); + builder.field("code", &self.code()); + if let Some(library) = self.library() { + builder.field("library", &library); + } + if let Some(function) = self.function() { + builder.field("function", &function); + } + if let Some(reason) = self.reason() { + builder.field("reason", &reason); + } + builder.field("file", &self.file()); + builder.field("line", &self.line()); + if let Some(data) = self.data() { + builder.field("data", &data); + } + builder.finish() + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "error:{:08X}", self.code())?; + match self.library() { + Some(l) => write!(fmt, ":{}", l)?, + None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?, + } + match self.function() { + Some(f) => write!(fmt, ":{}", f)?, + None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?, + } + match self.reason() { + Some(r) => write!(fmt, ":{}", r)?, + None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))?, + } + write!( + fmt, + ":{}:{}:{}", + self.file(), + self.line(), + self.data().unwrap_or("") + ) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + "an OpenSSL error" + } +} diff --git a/openssl/src/ex_data.rs b/openssl/src/ex_data.rs new file mode 100644 index 000000000..450dd113f --- /dev/null +++ b/openssl/src/ex_data.rs @@ -0,0 +1,26 @@ +use libc::c_int; +use std::marker::PhantomData; + +/// A slot in a type's "extra data" structure. +/// +/// It is parameterized over the type containing the extra data as well as the +/// type of the data in the slot. +pub struct Index(c_int, PhantomData<(T, U)>); + +impl Copy for Index {} + +impl Clone for Index { + fn clone(&self) -> Index { + *self + } +} + +impl Index { + pub unsafe fn from_raw(idx: c_int) -> Index { + Index(idx, PhantomData) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} diff --git a/openssl/src/fips.rs b/openssl/src/fips.rs new file mode 100644 index 000000000..374a82991 --- /dev/null +++ b/openssl/src/fips.rs @@ -0,0 +1,22 @@ +//! FIPS 140-2 support. +//! +//! See [OpenSSL's documentation] for details. +//! +//! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf +use cvt; +use error::ErrorStack; +use ffi; + +/// Moves the library into or out of the FIPS 140-2 mode of operation. +/// +/// This corresponds to `FIPS_mode_set`. +pub fn enable(enabled: bool) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::FIPS_mode_set(enabled as _)).map(|_| ()) } +} + +/// Determines if the library is running in the FIPS 140-2 mode of operation. +/// +/// This corresponds to `FIPS_mode`. +pub fn enabled() -> bool { + unsafe { ffi::FIPS_mode() != 0 } +} diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs new file mode 100644 index 000000000..5025de19d --- /dev/null +++ b/openssl/src/hash.rs @@ -0,0 +1,603 @@ +use ffi; +use std::fmt; +use std::io; +use std::io::prelude::*; +use std::ops::{Deref, DerefMut}; + +use error::ErrorStack; +use nid::Nid; +use {cvt, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct MessageDigest(*const ffi::EVP_MD); + +impl MessageDigest { + pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { + MessageDigest(x) + } + + /// Returns the `MessageDigest` corresponding to an `Nid`. + /// + /// This corresponds to [`EVP_get_digestbynid`]. + /// + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + pub fn from_nid(type_: Nid) -> Option { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MessageDigest(ptr)) + } + } + } + + pub fn md5() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_md5()) } + } + + pub fn sha1() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha1()) } + } + + pub fn sha224() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha224()) } + } + + pub fn sha256() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha256()) } + } + + pub fn sha384() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha384()) } + } + + pub fn sha512() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha512()) } + } + + #[cfg(ossl111)] + pub fn sha3_224() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_224()) } + } + + #[cfg(ossl111)] + pub fn sha3_256() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_256()) } + } + + #[cfg(ossl111)] + pub fn sha3_384() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_384()) } + } + + #[cfg(ossl111)] + pub fn sha3_512() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_sha3_512()) } + } + + #[cfg(ossl111)] + pub fn shake_128() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_shake128()) } + } + + #[cfg(ossl111)] + pub fn shake_256() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_shake256()) } + } + + pub fn ripemd160() -> MessageDigest { + unsafe { MessageDigest(ffi::EVP_ripemd160()) } + } + + pub fn as_ptr(&self) -> *const ffi::EVP_MD { + self.0 + } + + /// The size of the digest in bytes + pub fn size(&self) -> usize { + unsafe { ffi::EVP_MD_size(self.0) as usize } + } + + /// The name of the digest + pub fn type_(&self) -> Nid { + Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) }) + } +} + +unsafe impl Sync for MessageDigest {} +unsafe impl Send for MessageDigest {} + +#[derive(PartialEq, Copy, Clone)] +enum State { + Reset, + Updated, + Finalized, +} + +use self::State::*; + +/// Provides message digest (hash) computation. +/// +/// # Examples +/// +/// Calculate a hash in one go: +/// +/// ``` +/// use openssl::hash::{hash, MessageDigest}; +/// +/// let data = b"\x42\xF4\x97\xE0"; +/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; +/// let res = hash(MessageDigest::md5(), data).unwrap(); +/// assert_eq!(&*res, spec); +/// ``` +/// +/// Supply the input in chunks: +/// +/// ``` +/// use openssl::hash::{Hasher, MessageDigest}; +/// +/// let data = [b"\x42\xF4", b"\x97\xE0"]; +/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; +/// let mut h = Hasher::new(MessageDigest::md5()).unwrap(); +/// h.update(data[0]).unwrap(); +/// h.update(data[1]).unwrap(); +/// let res = h.finish().unwrap(); +/// assert_eq!(&*res, spec); +/// ``` +/// +/// Use an XOF hasher (OpenSSL 1.1.1+): +/// +/// ``` +/// #[cfg(ossl111)] +/// { +/// use openssl::hash::{hash_xof, MessageDigest}; +/// +/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73"; +/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35"; +/// let mut buf = vec![0; 16]; +/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap(); +/// assert_eq!(buf, spec); +/// } +/// ``` +/// +/// # Warning +/// +/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. +/// +/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead. +/// +/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead +/// of finish and provide a buf to store the hash. The hash will be as long as the buf. +pub struct Hasher { + ctx: *mut ffi::EVP_MD_CTX, + md: *const ffi::EVP_MD, + type_: MessageDigest, + state: State, +} + +unsafe impl Sync for Hasher {} +unsafe impl Send for Hasher {} + +impl Hasher { + /// Creates a new `Hasher` with the specified hash type. + pub fn new(ty: MessageDigest) -> Result { + ffi::init(); + + let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? }; + + let mut h = Hasher { + ctx: ctx, + md: ty.as_ptr(), + type_: ty, + state: Finalized, + }; + h.init()?; + Ok(h) + } + + fn init(&mut self) -> Result<(), ErrorStack> { + match self.state { + Reset => return Ok(()), + Updated => { + self.finish()?; + } + Finalized => (), + } + unsafe { + cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _))?; + } + self.state = Reset; + Ok(()) + } + + /// Feeds data into the hasher. + pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { + if self.state == Finalized { + self.init()?; + } + unsafe { + cvt(ffi::EVP_DigestUpdate( + self.ctx, + data.as_ptr() as *mut _, + data.len(), + ))?; + } + self.state = Updated; + Ok(()) + } + + /// Returns the hash of the data written and resets the non-XOF hasher. + pub fn finish(&mut self) -> Result { + if self.state == Finalized { + self.init()?; + } + unsafe { + let mut len = ffi::EVP_MAX_MD_SIZE; + let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize]; + cvt(ffi::EVP_DigestFinal_ex( + self.ctx, + buf.as_mut_ptr(), + &mut len, + ))?; + self.state = Finalized; + Ok(DigestBytes { + buf: buf, + len: len as usize, + }) + } + } + + /// Writes the hash of the data into the supplied buf and resets the XOF hasher. + /// The hash will be as long as the buf. + #[cfg(ossl111)] + pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> { + if self.state == Finalized { + self.init()?; + } + unsafe { + cvt(ffi::EVP_DigestFinalXOF( + self.ctx, + buf.as_mut_ptr(), + buf.len(), + ))?; + self.state = Finalized; + Ok(()) + } + } +} + +impl Write for Hasher { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.update(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Clone for Hasher { + fn clone(&self) -> Hasher { + let ctx = unsafe { + let ctx = EVP_MD_CTX_new(); + assert!(!ctx.is_null()); + let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); + assert_eq!(r, 1); + ctx + }; + Hasher { + ctx: ctx, + md: self.md, + type_: self.type_, + state: self.state, + } + } +} + +impl Drop for Hasher { + fn drop(&mut self) { + unsafe { + if self.state != Finalized { + drop(self.finish()); + } + EVP_MD_CTX_free(self.ctx); + } + } +} + +/// The resulting bytes of a digest. +/// +/// This type derefs to a byte slice - it exists to avoid allocating memory to +/// store the digest data. +#[derive(Copy)] +pub struct DigestBytes { + pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], + pub(crate) len: usize, +} + +impl Clone for DigestBytes { + #[inline] + fn clone(&self) -> DigestBytes { + *self + } +} + +impl Deref for DigestBytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.buf[..self.len] + } +} + +impl DerefMut for DigestBytes { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.buf[..self.len] + } +} + +impl AsRef<[u8]> for DigestBytes { + #[inline] + fn as_ref(&self) -> &[u8] { + self.deref() + } +} + +impl fmt::Debug for DigestBytes { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, fmt) + } +} + +/// Computes the hash of the `data` with the non-XOF hasher `t`. +pub fn hash(t: MessageDigest, data: &[u8]) -> Result { + let mut h = Hasher::new(t)?; + h.update(data)?; + h.finish() +} + +/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`. +#[cfg(ossl111)] +pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> { + let mut h = Hasher::new(t)?; + h.update(data)?; + h.finish_xof(buf) +} + +#[cfg(test)] +mod tests { + use hex::{self, FromHex}; + use std::io::prelude::*; + + use super::*; + + fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { + let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap(); + assert_eq!(hex::encode(res), hashtest.1); + } + + #[cfg(ossl111)] + fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { + let expected = Vec::from_hex(hashtest.1).unwrap(); + let mut buf = vec![0; expected.len()]; + hash_xof( + hashtype, + &Vec::from_hex(hashtest.0).unwrap(), + buf.as_mut_slice(), + ) + .unwrap(); + assert_eq!(buf, expected); + } + + fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { + let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); + let res = h.finish().unwrap(); + assert_eq!(hex::encode(res), hashtest.1); + } + + // Test vectors from http://www.nsrl.nist.gov/testdata/ + #[allow(non_upper_case_globals)] + const md5_tests: [(&'static str, &'static str); 13] = [ + ("", "d41d8cd98f00b204e9800998ecf8427e"), + ("7F", "83acb6e67e50e31db6ed341dd2de1595"), + ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), + ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), + ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), + ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), + ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), + ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), + ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), + ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), + ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), + ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), + ( + "AAED18DBE8938C19ED734A8D", + "6f80fb775f27e0a4ce5c2f42fc72c5f1", + ), + ]; + + #[test] + fn test_md5() { + for test in md5_tests.iter() { + hash_test(MessageDigest::md5(), test); + } + } + + #[test] + fn test_md5_recycle() { + let mut h = Hasher::new(MessageDigest::md5()).unwrap(); + for test in md5_tests.iter() { + hash_recycle_test(&mut h, test); + } + } + + #[test] + fn test_finish_twice() { + let mut h = Hasher::new(MessageDigest::md5()).unwrap(); + h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap()) + .unwrap(); + h.finish().unwrap(); + let res = h.finish().unwrap(); + let null = hash(MessageDigest::md5(), &[]).unwrap(); + assert_eq!(&*res, &*null); + } + + #[test] + fn test_clone() { + let i = 7; + let inp = Vec::from_hex(md5_tests[i].0).unwrap(); + assert!(inp.len() > 2); + let p = inp.len() / 2; + let h0 = Hasher::new(MessageDigest::md5()).unwrap(); + + println!("Clone a new hasher"); + let mut h1 = h0.clone(); + h1.write_all(&inp[..p]).unwrap(); + { + println!("Clone an updated hasher"); + let mut h2 = h1.clone(); + h2.write_all(&inp[p..]).unwrap(); + let res = h2.finish().unwrap(); + assert_eq!(hex::encode(res), md5_tests[i].1); + } + h1.write_all(&inp[p..]).unwrap(); + let res = h1.finish().unwrap(); + assert_eq!(hex::encode(res), md5_tests[i].1); + + println!("Clone a finished hasher"); + let mut h3 = h1.clone(); + h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()) + .unwrap(); + let res = h3.finish().unwrap(); + assert_eq!(hex::encode(res), md5_tests[i + 1].1); + } + + #[test] + fn test_sha1() { + let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")]; + + for test in tests.iter() { + hash_test(MessageDigest::sha1(), test); + } + } + + #[test] + fn test_sha256() { + let tests = [( + "616263", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha256(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_sha3_224() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_224(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_sha3_256() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61", + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_256(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_sha3_384() { + let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\ + ef2008ff16" + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_384(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_sha3_512() { + let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\ + 807caee3a79f8eb02dcd61589fbbdf5f40c8787a72" + )]; + + for test in tests.iter() { + hash_test(MessageDigest::sha3_512(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_shake_128() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "49d0697ff508111d8b84f15e46daf135", + )]; + + for test in tests.iter() { + hash_xof_test(MessageDigest::shake_128(), test); + } + } + + #[cfg(ossl111)] + #[test] + fn test_shake_256() { + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697", + )]; + + for test in tests.iter() { + hash_xof_test(MessageDigest::shake_256(), test); + } + } + + #[test] + fn test_ripemd160() { + let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; + + for test in tests.iter() { + hash_test(MessageDigest::ripemd160(), test); + } + } + + #[test] + fn from_nid() { + assert_eq!( + MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), + MessageDigest::sha256().as_ptr() + ); + } +} diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs new file mode 100644 index 000000000..e9ee2e216 --- /dev/null +++ b/openssl/src/lib.rs @@ -0,0 +1,199 @@ +//! Bindings to OpenSSL +//! +//! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through +//! 1.1.1 and LibreSSL versions 2.5 through 2.8 are supported. +//! +//! # Building +//! +//! Both OpenSSL libraries and headers are required to build this crate. There are multiple options available to locate +//! OpenSSL. +//! +//! ## Vendored +//! +//! If the `vendored` Cargo feature is enabled, the `openssl-src` crate will be used to compile and statically link to +//! a copy of OpenSSL. The build process requires a C compiler, perl, and make. The OpenSSL version will generally track +//! the newest OpenSSL release, and changes to the version are *not* considered breaking changes. +//! +//! ```toml +//! [dependencies] +//! openssl = { version = "0.10", features = ["vendored"] } +//! ``` +//! +//! The vendored copy will not be configured to automatically find the system's root certificates, but the +//! `openssl-probe` crate can be used to do that instead. +//! +//! ## Automatic +//! +//! The `openssl-sys` crate will automatically detect OpenSSL installations via Homebrew on macOS and vcpkg on Windows. +//! Additionally, it will use `pkg-config` on Unix-like systems to find the system installation. +//! +//! ```not_rust +//! # macOS +//! $ brew install openssl@1.1 +//! +//! # Arch Linux +//! $ sudo pacman -S pkg-config openssl +//! +//! # Debian and Ubuntu +//! $ sudo apt-get install pkg-config libssl-dev +//! +//! # Fedora +//! $ sudo dnf install pkg-config openssl-devel +//! ``` +//! +//! ## Manual +//! +//! A set of environment variables can be used to point `openssl-sys` towards an OpenSSL installation. They will +//! override the automatic detection logic. +//! +//! * `OPENSSL_DIR` - If specified, the directory of an OpenSSL installation. The directory should contain `lib` and +//! `include` subdirectories containing the libraries and headers respectively. +//! * `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` - If specified, the directories containing the OpenSSL libraries and +//! headers respectively. This can be used if the OpenSSL installation is split in a nonstandard directory layout. +//! * `OPENSSL_STATIC` - If set, the crate will statically link to OpenSSL rather than dynamically link. +//! * `OPENSSL_LIBS` - If set, a `:`-separated list of library names to link to (e.g. `ssl:crypto`). This can be used +//! if nonstandard library names were used for whatever reason. +//! +//! Additionally, these variables can be prefixed with the upper-cased target architecture (e.g. +//! `X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`), which can be useful when cross compiling. +//! +//! # Feature Detection +//! +//! APIs have been added to and removed from the various supported OpenSSL versions, and this library exposes the +//! functionality available in the version being linked against. This means that methods, constants, and even modules +//! will be present when building against one version of OpenSSL but not when building against another! APIs will +//! document any version-specific availability restrictions. +//! +//! A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys` +//! crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` +//! environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version: +//! `0xMNNFFPPS`. For example, version 1.0.2g's encoding is `0x1_00_02_07_0`. +//! +//! For example, let's say we want to adjust the TLSv1.3 cipher suites used by a client, but also want to compile +//! against OpenSSL versions that don't support TLSv1.3: +//! +//! Cargo.toml: +//! +//! ```toml +//! [dependencies] +//! openssl-sys = "0.9" +//! openssl = "0.10" +//! ``` +//! +//! build.rs: +//! +//! ``` +//! use std::env; +//! +//! fn main() { +//! if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") { +//! let version = u64::from_str_radix(&v, 16).unwrap(); +//! +//! if version >= 0x1_01_01_00_0 { +//! println!("cargo:rustc-cfg=openssl111"); +//! } +//! } +//! } +//! ``` +//! +//! lib.rs: +//! +//! ``` +//! use openssl::ssl::{SslConnector, SslMethod}; +//! +//! let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap(); +//! +//! // set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version +//! #[cfg(openssl111)] +//! ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap(); +//! ``` +#![doc(html_root_url = "https://docs.rs/openssl/0.10")] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate cfg_if; +#[macro_use] +extern crate foreign_types; +#[macro_use] +extern crate lazy_static; +extern crate libc; +extern crate openssl_sys as ffi; + +#[cfg(test)] +extern crate hex; +#[cfg(test)] +extern crate tempdir; + +#[doc(inline)] +pub use ffi::init; + +use libc::c_int; + +use error::ErrorStack; + +#[macro_use] +mod macros; + +mod bio; +#[macro_use] +mod util; +pub mod aes; +pub mod asn1; +pub mod bn; +#[cfg(not(libressl))] +pub mod cms; +pub mod conf; +pub mod derive; +pub mod dh; +pub mod dsa; +pub mod ec; +pub mod ecdsa; +pub mod envelope; +pub mod error; +pub mod ex_data; +#[cfg(not(libressl))] +pub mod fips; +pub mod hash; +pub mod memcmp; +pub mod nid; +pub mod ocsp; +pub mod pkcs12; +pub mod pkcs5; +pub mod pkcs7; +pub mod pkey; +pub mod rand; +pub mod rsa; +pub mod sha; +pub mod sign; +pub mod srtp; +pub mod ssl; +pub mod stack; +pub mod string; +pub mod symm; +pub mod version; +pub mod x509; + +fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { + if r.is_null() { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} + +fn cvt(r: c_int) -> Result { + if r <= 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} + +fn cvt_n(r: c_int) -> Result { + if r < 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs new file mode 100644 index 000000000..3d6854843 --- /dev/null +++ b/openssl/src/macros.rs @@ -0,0 +1,269 @@ +macro_rules! private_key_from_pem { + ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $(#[$m3:meta])* $n3:ident, $t:ty, $f:path) => { + from_pem!($(#[$m])* $n, $t, $f); + + $(#[$m2])* + pub fn $n2(pem: &[u8], passphrase: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ffi::init(); + let bio = try!(::bio::MemBioSlice::new(pem)); + let passphrase = ::std::ffi::CString::new(passphrase).unwrap(); + cvt_p($f(bio.as_ptr(), + ptr::null_mut(), + None, + passphrase.as_ptr() as *const _ as *mut _)) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) + } + } + + $(#[$m3])* + pub fn $n3(pem: &[u8], callback: F) -> Result<$t, ::error::ErrorStack> + where F: FnOnce(&mut [u8]) -> Result + { + unsafe { + ffi::init(); + let mut cb = ::util::CallbackState::new(callback); + let bio = try!(::bio::MemBioSlice::new(pem)); + cvt_p($f(bio.as_ptr(), + ptr::null_mut(), + Some(::util::invoke_passwd_cb::), + &mut cb as *mut _ as *mut _)) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) + } + } + } +} + +macro_rules! private_key_to_pem { + ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(::bio::MemBio::new()); + try!(cvt($f(bio.as_ptr(), + self.as_ptr(), + ptr::null(), + ptr::null_mut(), + -1, + None, + ptr::null_mut()))); + Ok(bio.get_buf().to_owned()) + } + } + + $(#[$m2])* + pub fn $n2( + &self, + cipher: ::symm::Cipher, + passphrase: &[u8] + ) -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(::bio::MemBio::new()); + assert!(passphrase.len() <= ::libc::c_int::max_value() as usize); + try!(cvt($f(bio.as_ptr(), + self.as_ptr(), + cipher.as_ptr(), + passphrase.as_ptr() as *const _ as *mut _, + passphrase.len() as ::libc::c_int, + None, + ptr::null_mut()))); + Ok(bio.get_buf().to_owned()) + } + } + } +} + +macro_rules! to_pem { + ($(#[$m:meta])* $n:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(::bio::MemBio::new()); + try!(cvt($f(bio.as_ptr(), self.as_ptr()))); + Ok(bio.get_buf().to_owned()) + } + } + } +} + +macro_rules! to_der { + ($(#[$m:meta])* $n:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self) -> Result, ::error::ErrorStack> { + unsafe { + let len = try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + }; +} + +macro_rules! from_der { + ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { + $(#[$m])* + pub fn $n(der: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ::ffi::init(); + let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; + ::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len)) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) + } + } + } +} + +macro_rules! from_pem { + ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { + $(#[$m])* + pub fn $n(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ::init(); + let bio = try!(::bio::MemBioSlice::new(pem)); + cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) + .map(|p| ::foreign_types::ForeignType::from_ptr(p)) + } + } + } +} + +macro_rules! foreign_type_and_impl_send_sync { + ( + $(#[$impl_attr:meta])* + type CType = $ctype:ty; + fn drop = $drop:expr; + $(fn clone = $clone:expr;)* + + $(#[$owned_attr:meta])* + pub struct $owned:ident; + $(#[$borrowed_attr:meta])* + pub struct $borrowed:ident; + ) + => { + foreign_type! { + $(#[$impl_attr])* + type CType = $ctype; + fn drop = $drop; + $(fn clone = $clone;)* + $(#[$owned_attr])* + pub struct $owned; + $(#[$borrowed_attr])* + pub struct $borrowed; + } + + unsafe impl Send for $owned{} + unsafe impl Send for $borrowed{} + unsafe impl Sync for $owned{} + unsafe impl Sync for $borrowed{} + }; +} + +macro_rules! generic_foreign_type_and_impl_send_sync { + ( + $(#[$impl_attr:meta])* + type CType = $ctype:ty; + fn drop = $drop:expr; + $(fn clone = $clone:expr;)* + + $(#[$owned_attr:meta])* + pub struct $owned:ident; + $(#[$borrowed_attr:meta])* + pub struct $borrowed:ident; + ) => { + $(#[$owned_attr])* + pub struct $owned(*mut $ctype, ::std::marker::PhantomData); + + $(#[$impl_attr])* + impl ::foreign_types::ForeignType for $owned { + type CType = $ctype; + type Ref = $borrowed; + + #[inline] + unsafe fn from_ptr(ptr: *mut $ctype) -> $owned { + $owned(ptr, ::std::marker::PhantomData) + } + + #[inline] + fn as_ptr(&self) -> *mut $ctype { + self.0 + } + } + + impl Drop for $owned { + #[inline] + fn drop(&mut self) { + unsafe { $drop(self.0) } + } + } + + $( + impl Clone for $owned { + #[inline] + fn clone(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone(self.0); + ::foreign_types::ForeignType::from_ptr(handle) + } + } + } + + impl ::std::borrow::ToOwned for $borrowed { + type Owned = $owned; + #[inline] + fn to_owned(&self) -> $owned { + unsafe { + let handle: *mut $ctype = + $clone(::foreign_types::ForeignTypeRef::as_ptr(self)); + $crate::ForeignType::from_ptr(handle) + } + } + } + )* + + impl ::std::ops::Deref for $owned { + type Target = $borrowed; + + #[inline] + fn deref(&self) -> &$borrowed { + unsafe { ::foreign_types::ForeignTypeRef::from_ptr(self.0) } + } + } + + impl ::std::ops::DerefMut for $owned { + #[inline] + fn deref_mut(&mut self) -> &mut $borrowed { + unsafe { ::foreign_types::ForeignTypeRef::from_ptr_mut(self.0) } + } + } + + impl ::std::borrow::Borrow<$borrowed> for $owned { + #[inline] + fn borrow(&self) -> &$borrowed { + &**self + } + } + + impl ::std::convert::AsRef<$borrowed> for $owned { + #[inline] + fn as_ref(&self) -> &$borrowed { + &**self + } + } + + $(#[$borrowed_attr])* + pub struct $borrowed(::foreign_types::Opaque, ::std::marker::PhantomData); + + $(#[$impl_attr])* + impl ::foreign_types::ForeignTypeRef for $borrowed { + type CType = $ctype; + } + + unsafe impl Send for $owned{} + unsafe impl Send for $borrowed{} + unsafe impl Sync for $owned{} + unsafe impl Sync for $borrowed{} + }; +} diff --git a/openssl/src/memcmp.rs b/openssl/src/memcmp.rs new file mode 100644 index 000000000..3b7bf3b28 --- /dev/null +++ b/openssl/src/memcmp.rs @@ -0,0 +1,92 @@ +//! Utilities to safely compare cryptographic values. +//! +//! Extra care must be taken when comparing values in +//! cryptographic code. If done incorrectly, it can lead +//! to a [timing attack](https://en.wikipedia.org/wiki/Timing_attack). +//! By analyzing the time taken to execute parts of a cryptographic +//! algorithm, and attacker can attempt to compromise the +//! cryptosystem. +//! +//! The utilities in this module are designed to be resistant +//! to this type of attack. +//! +//! # Examples +//! +//! To perform a constant-time comparision of two arrays of the same length but different +//! values: +//! +//! ``` +//! use openssl::memcmp::eq; +//! +//! // We want to compare `a` to `b` and `c`, without giving +//! // away through timing analysis that `c` is more similar to `a` +//! // than `b`. +//! let a = [0, 0, 0]; +//! let b = [1, 1, 1]; +//! let c = [0, 0, 1]; +//! +//! // These statements will execute in the same amount of time. +//! assert!(!eq(&a, &b)); +//! assert!(!eq(&a, &c)); +//! ``` +use ffi; +use libc::size_t; + +/// Returns `true` iff `a` and `b` contain the same bytes. +/// +/// This operation takes an amount of time dependent on the length of the two +/// arrays given, but is independent of the contents of a and b. +/// +/// # Panics +/// +/// This function will panic the current task if `a` and `b` do not have the same +/// length. +/// +/// # Examples +/// +/// To perform a constant-time comparision of two arrays of the same length but different +/// values: +/// +/// ``` +/// use openssl::memcmp::eq; +/// +/// // We want to compare `a` to `b` and `c`, without giving +/// // away through timing analysis that `c` is more similar to `a` +/// // than `b`. +/// let a = [0, 0, 0]; +/// let b = [1, 1, 1]; +/// let c = [0, 0, 1]; +/// +/// // These statements will execute in the same amount of time. +/// assert!(!eq(&a, &b)); +/// assert!(!eq(&a, &c)); +/// ``` +pub fn eq(a: &[u8], b: &[u8]) -> bool { + assert!(a.len() == b.len()); + let ret = unsafe { + ffi::CRYPTO_memcmp( + a.as_ptr() as *const _, + b.as_ptr() as *const _, + a.len() as size_t, + ) + }; + ret == 0 +} + +#[cfg(test)] +mod tests { + use super::eq; + + #[test] + fn test_eq() { + assert!(eq(&[], &[])); + assert!(eq(&[1], &[1])); + assert!(!eq(&[1, 2, 3], &[1, 2, 4])); + } + + #[test] + #[should_panic] + fn test_diff_lens() { + eq(&[], &[1]); + } +} diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs new file mode 100644 index 000000000..6f480254a --- /dev/null +++ b/openssl/src/nid.rs @@ -0,0 +1,1120 @@ +//! A collection of numerical identifiers for OpenSSL objects. +use ffi; +use libc::{c_char, c_int}; + +use std::ffi::CStr; +use std::str; + +use cvt_p; +use error::ErrorStack; + +/// The digest and public-key algorithms associated with a signature. +pub struct SignatureAlgorithms { + /// The signature's digest. + /// + /// If the signature does not specify a digest, this will be `NID::UNDEF`. + pub digest: Nid, + + /// The signature's public-key. + pub pkey: Nid, +} + +/// A numerical identifier for an OpenSSL object. +/// +/// Objects in OpenSSL can have a short name, a long name, and +/// a numerical identifier (NID). For convenience, objects +/// are usually represented in source code using these numeric +/// identifiers. +/// +/// Users should generally not need to create new `Nid`s. +/// +/// # Examples +/// +/// To view the integer representation of a `Nid`: +/// +/// ``` +/// use openssl::nid::Nid; +/// +/// assert!(Nid::AES_256_GCM.as_raw() == 901); +/// ``` +/// +/// # External Documentation +/// +/// The following documentation provides context about `Nid`s and their usage +/// in OpenSSL. +/// +/// - [Obj_nid2obj](https://www.openssl.org/docs/man1.1.0/crypto/OBJ_create.html) +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Nid(c_int); + +#[allow(non_snake_case)] +impl Nid { + /// Create a `Nid` from an integer representation. + pub fn from_raw(raw: c_int) -> Nid { + Nid(raw) + } + + /// Return the integer representation of a `Nid`. + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. + /// + /// This corresponds to `OBJ_find_sigid_algs`. + pub fn signature_algorithms(&self) -> Option { + unsafe { + let mut digest = 0; + let mut pkey = 0; + if ffi::OBJ_find_sigid_algs(self.0, &mut digest, &mut pkey) == 1 { + Some(SignatureAlgorithms { + digest: Nid(digest), + pkey: Nid(pkey), + }) + } else { + None + } + } + } + + /// Return the string representation of a `Nid` (long) + /// This corresponds to [`OBJ_nid2ln`] + /// + /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html + pub fn long_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + + /// Return the string representation of a `Nid` (short) + /// This corresponds to [`OBJ_nid2sn`] + /// + /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html + pub fn short_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + + pub const UNDEF: Nid = Nid(ffi::NID_undef); + pub const ITU_T: Nid = Nid(ffi::NID_itu_t); + pub const CCITT: Nid = Nid(ffi::NID_ccitt); + pub const ISO: Nid = Nid(ffi::NID_iso); + pub const JOINT_ISO_ITU_T: Nid = Nid(ffi::NID_joint_iso_itu_t); + pub const JOINT_ISO_CCITT: Nid = Nid(ffi::NID_joint_iso_ccitt); + pub const MEMBER_BODY: Nid = Nid(ffi::NID_member_body); + pub const IDENTIFIED_ORGANIZATION: Nid = Nid(ffi::NID_identified_organization); + pub const HMAC_MD5: Nid = Nid(ffi::NID_hmac_md5); + pub const HMAC_SHA1: Nid = Nid(ffi::NID_hmac_sha1); + pub const CERTICOM_ARC: Nid = Nid(ffi::NID_certicom_arc); + pub const INTERNATIONAL_ORGANIZATIONS: Nid = Nid(ffi::NID_international_organizations); + pub const WAP: Nid = Nid(ffi::NID_wap); + pub const WAP_WSG: Nid = Nid(ffi::NID_wap_wsg); + pub const SELECTED_ATTRIBUTE_TYPES: Nid = Nid(ffi::NID_selected_attribute_types); + pub const CLEARANCE: Nid = Nid(ffi::NID_clearance); + pub const ISO_US: Nid = Nid(ffi::NID_ISO_US); + pub const X9_57: Nid = Nid(ffi::NID_X9_57); + pub const X9CM: Nid = Nid(ffi::NID_X9cm); + pub const DSA: Nid = Nid(ffi::NID_dsa); + pub const DSAWITHSHA1: Nid = Nid(ffi::NID_dsaWithSHA1); + pub const ANSI_X9_62: Nid = Nid(ffi::NID_ansi_X9_62); + pub const X9_62_PRIME_FIELD: Nid = Nid(ffi::NID_X9_62_prime_field); + pub const X9_62_CHARACTERISTIC_TWO_FIELD: Nid = Nid(ffi::NID_X9_62_characteristic_two_field); + pub const X9_62_ID_CHARACTERISTIC_TWO_BASIS: Nid = + Nid(ffi::NID_X9_62_id_characteristic_two_basis); + pub const X9_62_ONBASIS: Nid = Nid(ffi::NID_X9_62_onBasis); + pub const X9_62_TPBASIS: Nid = Nid(ffi::NID_X9_62_tpBasis); + pub const X9_62_PPBASIS: Nid = Nid(ffi::NID_X9_62_ppBasis); + pub const X9_62_ID_ECPUBLICKEY: Nid = Nid(ffi::NID_X9_62_id_ecPublicKey); + pub const X9_62_C2PNB163V1: Nid = Nid(ffi::NID_X9_62_c2pnb163v1); + pub const X9_62_C2PNB163V2: Nid = Nid(ffi::NID_X9_62_c2pnb163v2); + pub const X9_62_C2PNB163V3: Nid = Nid(ffi::NID_X9_62_c2pnb163v3); + pub const X9_62_C2PNB176V1: Nid = Nid(ffi::NID_X9_62_c2pnb176v1); + pub const X9_62_C2TNB191V1: Nid = Nid(ffi::NID_X9_62_c2tnb191v1); + pub const X9_62_C2TNB191V2: Nid = Nid(ffi::NID_X9_62_c2tnb191v2); + pub const X9_62_C2TNB191V3: Nid = Nid(ffi::NID_X9_62_c2tnb191v3); + pub const X9_62_C2ONB191V4: Nid = Nid(ffi::NID_X9_62_c2onb191v4); + pub const X9_62_C2ONB191V5: Nid = Nid(ffi::NID_X9_62_c2onb191v5); + pub const X9_62_C2PNB208W1: Nid = Nid(ffi::NID_X9_62_c2pnb208w1); + pub const X9_62_C2TNB239V1: Nid = Nid(ffi::NID_X9_62_c2tnb239v1); + pub const X9_62_C2TNB239V2: Nid = Nid(ffi::NID_X9_62_c2tnb239v2); + pub const X9_62_C2TNB239V3: Nid = Nid(ffi::NID_X9_62_c2tnb239v3); + pub const X9_62_C2ONB239V4: Nid = Nid(ffi::NID_X9_62_c2onb239v4); + pub const X9_62_C2ONB239V5: Nid = Nid(ffi::NID_X9_62_c2onb239v5); + pub const X9_62_C2PNB272W1: Nid = Nid(ffi::NID_X9_62_c2pnb272w1); + pub const X9_62_C2PNB304W1: Nid = Nid(ffi::NID_X9_62_c2pnb304w1); + pub const X9_62_C2TNB359V1: Nid = Nid(ffi::NID_X9_62_c2tnb359v1); + pub const X9_62_C2PNB368W1: Nid = Nid(ffi::NID_X9_62_c2pnb368w1); + pub const X9_62_C2TNB431R1: Nid = Nid(ffi::NID_X9_62_c2tnb431r1); + pub const X9_62_PRIME192V1: Nid = Nid(ffi::NID_X9_62_prime192v1); + pub const X9_62_PRIME192V2: Nid = Nid(ffi::NID_X9_62_prime192v2); + pub const X9_62_PRIME192V3: Nid = Nid(ffi::NID_X9_62_prime192v3); + pub const X9_62_PRIME239V1: Nid = Nid(ffi::NID_X9_62_prime239v1); + pub const X9_62_PRIME239V2: Nid = Nid(ffi::NID_X9_62_prime239v2); + pub const X9_62_PRIME239V3: Nid = Nid(ffi::NID_X9_62_prime239v3); + pub const X9_62_PRIME256V1: Nid = Nid(ffi::NID_X9_62_prime256v1); + pub const ECDSA_WITH_SHA1: Nid = Nid(ffi::NID_ecdsa_with_SHA1); + pub const ECDSA_WITH_RECOMMENDED: Nid = Nid(ffi::NID_ecdsa_with_Recommended); + pub const ECDSA_WITH_SPECIFIED: Nid = Nid(ffi::NID_ecdsa_with_Specified); + pub const ECDSA_WITH_SHA224: Nid = Nid(ffi::NID_ecdsa_with_SHA224); + pub const ECDSA_WITH_SHA256: Nid = Nid(ffi::NID_ecdsa_with_SHA256); + pub const ECDSA_WITH_SHA384: Nid = Nid(ffi::NID_ecdsa_with_SHA384); + pub const ECDSA_WITH_SHA512: Nid = Nid(ffi::NID_ecdsa_with_SHA512); + pub const SECP112R1: Nid = Nid(ffi::NID_secp112r1); + pub const SECP112R2: Nid = Nid(ffi::NID_secp112r2); + pub const SECP128R1: Nid = Nid(ffi::NID_secp128r1); + pub const SECP128R2: Nid = Nid(ffi::NID_secp128r2); + pub const SECP160K1: Nid = Nid(ffi::NID_secp160k1); + pub const SECP160R1: Nid = Nid(ffi::NID_secp160r1); + pub const SECP160R2: Nid = Nid(ffi::NID_secp160r2); + pub const SECP192K1: Nid = Nid(ffi::NID_secp192k1); + pub const SECP224K1: Nid = Nid(ffi::NID_secp224k1); + pub const SECP224R1: Nid = Nid(ffi::NID_secp224r1); + pub const SECP256K1: Nid = Nid(ffi::NID_secp256k1); + pub const SECP384R1: Nid = Nid(ffi::NID_secp384r1); + pub const SECP521R1: Nid = Nid(ffi::NID_secp521r1); + pub const SECT113R1: Nid = Nid(ffi::NID_sect113r1); + pub const SECT113R2: Nid = Nid(ffi::NID_sect113r2); + pub const SECT131R1: Nid = Nid(ffi::NID_sect131r1); + pub const SECT131R2: Nid = Nid(ffi::NID_sect131r2); + pub const SECT163K1: Nid = Nid(ffi::NID_sect163k1); + pub const SECT163R1: Nid = Nid(ffi::NID_sect163r1); + pub const SECT163R2: Nid = Nid(ffi::NID_sect163r2); + pub const SECT193R1: Nid = Nid(ffi::NID_sect193r1); + pub const SECT193R2: Nid = Nid(ffi::NID_sect193r2); + pub const SECT233K1: Nid = Nid(ffi::NID_sect233k1); + pub const SECT233R1: Nid = Nid(ffi::NID_sect233r1); + pub const SECT239K1: Nid = Nid(ffi::NID_sect239k1); + pub const SECT283K1: Nid = Nid(ffi::NID_sect283k1); + pub const SECT283R1: Nid = Nid(ffi::NID_sect283r1); + pub const SECT409K1: Nid = Nid(ffi::NID_sect409k1); + pub const SECT409R1: Nid = Nid(ffi::NID_sect409r1); + pub const SECT571K1: Nid = Nid(ffi::NID_sect571k1); + pub const SECT571R1: Nid = Nid(ffi::NID_sect571r1); + pub const WAP_WSG_IDM_ECID_WTLS1: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls1); + pub const WAP_WSG_IDM_ECID_WTLS3: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls3); + pub const WAP_WSG_IDM_ECID_WTLS4: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls4); + pub const WAP_WSG_IDM_ECID_WTLS5: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls5); + pub const WAP_WSG_IDM_ECID_WTLS6: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls6); + pub const WAP_WSG_IDM_ECID_WTLS7: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls7); + pub const WAP_WSG_IDM_ECID_WTLS8: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls8); + pub const WAP_WSG_IDM_ECID_WTLS9: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls9); + pub const WAP_WSG_IDM_ECID_WTLS10: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls10); + pub const WAP_WSG_IDM_ECID_WTLS11: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls11); + pub const WAP_WSG_IDM_ECID_WTLS12: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls12); + pub const CAST5_CBC: Nid = Nid(ffi::NID_cast5_cbc); + pub const CAST5_ECB: Nid = Nid(ffi::NID_cast5_ecb); + pub const CAST5_CFB64: Nid = Nid(ffi::NID_cast5_cfb64); + pub const CAST5_OFB64: Nid = Nid(ffi::NID_cast5_ofb64); + pub const PBEWITHMD5ANDCAST5_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndCast5_CBC); + pub const ID_PASSWORDBASEDMAC: Nid = Nid(ffi::NID_id_PasswordBasedMAC); + pub const ID_DHBASEDMAC: Nid = Nid(ffi::NID_id_DHBasedMac); + pub const RSADSI: Nid = Nid(ffi::NID_rsadsi); + pub const PKCS: Nid = Nid(ffi::NID_pkcs); + pub const PKCS1: Nid = Nid(ffi::NID_pkcs1); + pub const RSAENCRYPTION: Nid = Nid(ffi::NID_rsaEncryption); + pub const MD2WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md2WithRSAEncryption); + pub const MD4WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md4WithRSAEncryption); + pub const MD5WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md5WithRSAEncryption); + pub const SHA1WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha1WithRSAEncryption); + pub const RSAESOAEP: Nid = Nid(ffi::NID_rsaesOaep); + pub const MGF1: Nid = Nid(ffi::NID_mgf1); + pub const RSASSAPSS: Nid = Nid(ffi::NID_rsassaPss); + pub const SHA256WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha256WithRSAEncryption); + pub const SHA384WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha384WithRSAEncryption); + pub const SHA512WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha512WithRSAEncryption); + pub const SHA224WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha224WithRSAEncryption); + pub const PKCS3: Nid = Nid(ffi::NID_pkcs3); + pub const DHKEYAGREEMENT: Nid = Nid(ffi::NID_dhKeyAgreement); + pub const PKCS5: Nid = Nid(ffi::NID_pkcs5); + pub const PBEWITHMD2ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndDES_CBC); + pub const PBEWITHMD5ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndDES_CBC); + pub const PBEWITHMD2ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndRC2_CBC); + pub const PBEWITHMD5ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndRC2_CBC); + pub const PBEWITHSHA1ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndDES_CBC); + pub const PBEWITHSHA1ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndRC2_CBC); + pub const ID_PBKDF2: Nid = Nid(ffi::NID_id_pbkdf2); + pub const PBES2: Nid = Nid(ffi::NID_pbes2); + pub const PBMAC1: Nid = Nid(ffi::NID_pbmac1); + pub const PKCS7: Nid = Nid(ffi::NID_pkcs7); + pub const PKCS7_DATA: Nid = Nid(ffi::NID_pkcs7_data); + pub const PKCS7_SIGNED: Nid = Nid(ffi::NID_pkcs7_signed); + pub const PKCS7_ENVELOPED: Nid = Nid(ffi::NID_pkcs7_enveloped); + pub const PKCS7_SIGNEDANDENVELOPED: Nid = Nid(ffi::NID_pkcs7_signedAndEnveloped); + pub const PKCS7_DIGEST: Nid = Nid(ffi::NID_pkcs7_digest); + pub const PKCS7_ENCRYPTED: Nid = Nid(ffi::NID_pkcs7_encrypted); + pub const PKCS9: Nid = Nid(ffi::NID_pkcs9); + pub const PKCS9_EMAILADDRESS: Nid = Nid(ffi::NID_pkcs9_emailAddress); + pub const PKCS9_UNSTRUCTUREDNAME: Nid = Nid(ffi::NID_pkcs9_unstructuredName); + pub const PKCS9_CONTENTTYPE: Nid = Nid(ffi::NID_pkcs9_contentType); + pub const PKCS9_MESSAGEDIGEST: Nid = Nid(ffi::NID_pkcs9_messageDigest); + pub const PKCS9_SIGNINGTIME: Nid = Nid(ffi::NID_pkcs9_signingTime); + pub const PKCS9_COUNTERSIGNATURE: Nid = Nid(ffi::NID_pkcs9_countersignature); + pub const PKCS9_CHALLENGEPASSWORD: Nid = Nid(ffi::NID_pkcs9_challengePassword); + pub const PKCS9_UNSTRUCTUREDADDRESS: Nid = Nid(ffi::NID_pkcs9_unstructuredAddress); + pub const PKCS9_EXTCERTATTRIBUTES: Nid = Nid(ffi::NID_pkcs9_extCertAttributes); + pub const EXT_REQ: Nid = Nid(ffi::NID_ext_req); + pub const SMIMECAPABILITIES: Nid = Nid(ffi::NID_SMIMECapabilities); + pub const SMIME: Nid = Nid(ffi::NID_SMIME); + pub const ID_SMIME_MOD: Nid = Nid(ffi::NID_id_smime_mod); + pub const ID_SMIME_CT: Nid = Nid(ffi::NID_id_smime_ct); + pub const ID_SMIME_AA: Nid = Nid(ffi::NID_id_smime_aa); + pub const ID_SMIME_ALG: Nid = Nid(ffi::NID_id_smime_alg); + pub const ID_SMIME_CD: Nid = Nid(ffi::NID_id_smime_cd); + pub const ID_SMIME_SPQ: Nid = Nid(ffi::NID_id_smime_spq); + pub const ID_SMIME_CTI: Nid = Nid(ffi::NID_id_smime_cti); + pub const ID_SMIME_MOD_CMS: Nid = Nid(ffi::NID_id_smime_mod_cms); + pub const ID_SMIME_MOD_ESS: Nid = Nid(ffi::NID_id_smime_mod_ess); + pub const ID_SMIME_MOD_OID: Nid = Nid(ffi::NID_id_smime_mod_oid); + pub const ID_SMIME_MOD_MSG_V3: Nid = Nid(ffi::NID_id_smime_mod_msg_v3); + pub const ID_SMIME_MOD_ETS_ESIGNATURE_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_88); + pub const ID_SMIME_MOD_ETS_ESIGNATURE_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_97); + pub const ID_SMIME_MOD_ETS_ESIGPOLICY_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_88); + pub const ID_SMIME_MOD_ETS_ESIGPOLICY_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_97); + pub const ID_SMIME_CT_RECEIPT: Nid = Nid(ffi::NID_id_smime_ct_receipt); + pub const ID_SMIME_CT_AUTHDATA: Nid = Nid(ffi::NID_id_smime_ct_authData); + pub const ID_SMIME_CT_PUBLISHCERT: Nid = Nid(ffi::NID_id_smime_ct_publishCert); + pub const ID_SMIME_CT_TSTINFO: Nid = Nid(ffi::NID_id_smime_ct_TSTInfo); + pub const ID_SMIME_CT_TDTINFO: Nid = Nid(ffi::NID_id_smime_ct_TDTInfo); + pub const ID_SMIME_CT_CONTENTINFO: Nid = Nid(ffi::NID_id_smime_ct_contentInfo); + pub const ID_SMIME_CT_DVCSREQUESTDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSRequestData); + pub const ID_SMIME_CT_DVCSRESPONSEDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSResponseData); + pub const ID_SMIME_CT_COMPRESSEDDATA: Nid = Nid(ffi::NID_id_smime_ct_compressedData); + pub const ID_CT_ASCIITEXTWITHCRLF: Nid = Nid(ffi::NID_id_ct_asciiTextWithCRLF); + pub const ID_SMIME_AA_RECEIPTREQUEST: Nid = Nid(ffi::NID_id_smime_aa_receiptRequest); + pub const ID_SMIME_AA_SECURITYLABEL: Nid = Nid(ffi::NID_id_smime_aa_securityLabel); + pub const ID_SMIME_AA_MLEXPANDHISTORY: Nid = Nid(ffi::NID_id_smime_aa_mlExpandHistory); + pub const ID_SMIME_AA_CONTENTHINT: Nid = Nid(ffi::NID_id_smime_aa_contentHint); + pub const ID_SMIME_AA_MSGSIGDIGEST: Nid = Nid(ffi::NID_id_smime_aa_msgSigDigest); + pub const ID_SMIME_AA_ENCAPCONTENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_encapContentType); + pub const ID_SMIME_AA_CONTENTIDENTIFIER: Nid = Nid(ffi::NID_id_smime_aa_contentIdentifier); + pub const ID_SMIME_AA_MACVALUE: Nid = Nid(ffi::NID_id_smime_aa_macValue); + pub const ID_SMIME_AA_EQUIVALENTLABELS: Nid = Nid(ffi::NID_id_smime_aa_equivalentLabels); + pub const ID_SMIME_AA_CONTENTREFERENCE: Nid = Nid(ffi::NID_id_smime_aa_contentReference); + pub const ID_SMIME_AA_ENCRYPKEYPREF: Nid = Nid(ffi::NID_id_smime_aa_encrypKeyPref); + pub const ID_SMIME_AA_SIGNINGCERTIFICATE: Nid = Nid(ffi::NID_id_smime_aa_signingCertificate); + pub const ID_SMIME_AA_SMIMEENCRYPTCERTS: Nid = Nid(ffi::NID_id_smime_aa_smimeEncryptCerts); + pub const ID_SMIME_AA_TIMESTAMPTOKEN: Nid = Nid(ffi::NID_id_smime_aa_timeStampToken); + pub const ID_SMIME_AA_ETS_SIGPOLICYID: Nid = Nid(ffi::NID_id_smime_aa_ets_sigPolicyId); + pub const ID_SMIME_AA_ETS_COMMITMENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_ets_commitmentType); + pub const ID_SMIME_AA_ETS_SIGNERLOCATION: Nid = Nid(ffi::NID_id_smime_aa_ets_signerLocation); + pub const ID_SMIME_AA_ETS_SIGNERATTR: Nid = Nid(ffi::NID_id_smime_aa_ets_signerAttr); + pub const ID_SMIME_AA_ETS_OTHERSIGCERT: Nid = Nid(ffi::NID_id_smime_aa_ets_otherSigCert); + pub const ID_SMIME_AA_ETS_CONTENTTIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_contentTimestamp); + pub const ID_SMIME_AA_ETS_CERTIFICATEREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_CertificateRefs); + pub const ID_SMIME_AA_ETS_REVOCATIONREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_RevocationRefs); + pub const ID_SMIME_AA_ETS_CERTVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_certValues); + pub const ID_SMIME_AA_ETS_REVOCATIONVALUES: Nid = + Nid(ffi::NID_id_smime_aa_ets_revocationValues); + pub const ID_SMIME_AA_ETS_ESCTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_escTimeStamp); + pub const ID_SMIME_AA_ETS_CERTCRLTIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_certCRLTimestamp); + pub const ID_SMIME_AA_ETS_ARCHIVETIMESTAMP: Nid = + Nid(ffi::NID_id_smime_aa_ets_archiveTimeStamp); + pub const ID_SMIME_AA_SIGNATURETYPE: Nid = Nid(ffi::NID_id_smime_aa_signatureType); + pub const ID_SMIME_AA_DVCS_DVC: Nid = Nid(ffi::NID_id_smime_aa_dvcs_dvc); + pub const ID_SMIME_ALG_ESDHWITH3DES: Nid = Nid(ffi::NID_id_smime_alg_ESDHwith3DES); + pub const ID_SMIME_ALG_ESDHWITHRC2: Nid = Nid(ffi::NID_id_smime_alg_ESDHwithRC2); + pub const ID_SMIME_ALG_3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_3DESwrap); + pub const ID_SMIME_ALG_RC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_RC2wrap); + pub const ID_SMIME_ALG_ESDH: Nid = Nid(ffi::NID_id_smime_alg_ESDH); + pub const ID_SMIME_ALG_CMS3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_CMS3DESwrap); + pub const ID_SMIME_ALG_CMSRC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_CMSRC2wrap); + pub const ID_ALG_PWRI_KEK: Nid = Nid(ffi::NID_id_alg_PWRI_KEK); + pub const ID_SMIME_CD_LDAP: Nid = Nid(ffi::NID_id_smime_cd_ldap); + pub const ID_SMIME_SPQ_ETS_SQT_URI: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_uri); + pub const ID_SMIME_SPQ_ETS_SQT_UNOTICE: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_unotice); + pub const ID_SMIME_CTI_ETS_PROOFOFORIGIN: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfOrigin); + pub const ID_SMIME_CTI_ETS_PROOFOFRECEIPT: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfReceipt); + pub const ID_SMIME_CTI_ETS_PROOFOFDELIVERY: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfDelivery); + pub const ID_SMIME_CTI_ETS_PROOFOFSENDER: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfSender); + pub const ID_SMIME_CTI_ETS_PROOFOFAPPROVAL: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfApproval); + pub const ID_SMIME_CTI_ETS_PROOFOFCREATION: Nid = + Nid(ffi::NID_id_smime_cti_ets_proofOfCreation); + pub const FRIENDLYNAME: Nid = Nid(ffi::NID_friendlyName); + pub const LOCALKEYID: Nid = Nid(ffi::NID_localKeyID); + pub const MS_CSP_NAME: Nid = Nid(ffi::NID_ms_csp_name); + pub const LOCALKEYSET: Nid = Nid(ffi::NID_LocalKeySet); + pub const X509CERTIFICATE: Nid = Nid(ffi::NID_x509Certificate); + pub const SDSICERTIFICATE: Nid = Nid(ffi::NID_sdsiCertificate); + pub const X509CRL: Nid = Nid(ffi::NID_x509Crl); + pub const PBE_WITHSHA1AND128BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC4); + pub const PBE_WITHSHA1AND40BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC4); + pub const PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC: Nid = + Nid(ffi::NID_pbe_WithSHA1And3_Key_TripleDES_CBC); + pub const PBE_WITHSHA1AND2_KEY_TRIPLEDES_CBC: Nid = + Nid(ffi::NID_pbe_WithSHA1And2_Key_TripleDES_CBC); + pub const PBE_WITHSHA1AND128BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC2_CBC); + pub const PBE_WITHSHA1AND40BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC2_CBC); + pub const KEYBAG: Nid = Nid(ffi::NID_keyBag); + pub const PKCS8SHROUDEDKEYBAG: Nid = Nid(ffi::NID_pkcs8ShroudedKeyBag); + pub const CERTBAG: Nid = Nid(ffi::NID_certBag); + pub const CRLBAG: Nid = Nid(ffi::NID_crlBag); + pub const SECRETBAG: Nid = Nid(ffi::NID_secretBag); + pub const SAFECONTENTSBAG: Nid = Nid(ffi::NID_safeContentsBag); + pub const MD2: Nid = Nid(ffi::NID_md2); + pub const MD4: Nid = Nid(ffi::NID_md4); + pub const MD5: Nid = Nid(ffi::NID_md5); + pub const MD5_SHA1: Nid = Nid(ffi::NID_md5_sha1); + pub const HMACWITHMD5: Nid = Nid(ffi::NID_hmacWithMD5); + pub const HMACWITHSHA1: Nid = Nid(ffi::NID_hmacWithSHA1); + pub const HMACWITHSHA224: Nid = Nid(ffi::NID_hmacWithSHA224); + pub const HMACWITHSHA256: Nid = Nid(ffi::NID_hmacWithSHA256); + pub const HMACWITHSHA384: Nid = Nid(ffi::NID_hmacWithSHA384); + pub const HMACWITHSHA512: Nid = Nid(ffi::NID_hmacWithSHA512); + pub const RC2_CBC: Nid = Nid(ffi::NID_rc2_cbc); + pub const RC2_ECB: Nid = Nid(ffi::NID_rc2_ecb); + pub const RC2_CFB64: Nid = Nid(ffi::NID_rc2_cfb64); + pub const RC2_OFB64: Nid = Nid(ffi::NID_rc2_ofb64); + pub const RC2_40_CBC: Nid = Nid(ffi::NID_rc2_40_cbc); + pub const RC2_64_CBC: Nid = Nid(ffi::NID_rc2_64_cbc); + pub const RC4: Nid = Nid(ffi::NID_rc4); + pub const RC4_40: Nid = Nid(ffi::NID_rc4_40); + pub const DES_EDE3_CBC: Nid = Nid(ffi::NID_des_ede3_cbc); + pub const RC5_CBC: Nid = Nid(ffi::NID_rc5_cbc); + pub const RC5_ECB: Nid = Nid(ffi::NID_rc5_ecb); + pub const RC5_CFB64: Nid = Nid(ffi::NID_rc5_cfb64); + pub const RC5_OFB64: Nid = Nid(ffi::NID_rc5_ofb64); + pub const MS_EXT_REQ: Nid = Nid(ffi::NID_ms_ext_req); + pub const MS_CODE_IND: Nid = Nid(ffi::NID_ms_code_ind); + pub const MS_CODE_COM: Nid = Nid(ffi::NID_ms_code_com); + pub const MS_CTL_SIGN: Nid = Nid(ffi::NID_ms_ctl_sign); + pub const MS_SGC: Nid = Nid(ffi::NID_ms_sgc); + pub const MS_EFS: Nid = Nid(ffi::NID_ms_efs); + pub const MS_SMARTCARD_LOGIN: Nid = Nid(ffi::NID_ms_smartcard_login); + pub const MS_UPN: Nid = Nid(ffi::NID_ms_upn); + pub const IDEA_CBC: Nid = Nid(ffi::NID_idea_cbc); + pub const IDEA_ECB: Nid = Nid(ffi::NID_idea_ecb); + pub const IDEA_CFB64: Nid = Nid(ffi::NID_idea_cfb64); + pub const IDEA_OFB64: Nid = Nid(ffi::NID_idea_ofb64); + pub const BF_CBC: Nid = Nid(ffi::NID_bf_cbc); + pub const BF_ECB: Nid = Nid(ffi::NID_bf_ecb); + pub const BF_CFB64: Nid = Nid(ffi::NID_bf_cfb64); + pub const BF_OFB64: Nid = Nid(ffi::NID_bf_ofb64); + pub const ID_PKIX: Nid = Nid(ffi::NID_id_pkix); + pub const ID_PKIX_MOD: Nid = Nid(ffi::NID_id_pkix_mod); + pub const ID_PE: Nid = Nid(ffi::NID_id_pe); + pub const ID_QT: Nid = Nid(ffi::NID_id_qt); + pub const ID_KP: Nid = Nid(ffi::NID_id_kp); + pub const ID_IT: Nid = Nid(ffi::NID_id_it); + pub const ID_PKIP: Nid = Nid(ffi::NID_id_pkip); + pub const ID_ALG: Nid = Nid(ffi::NID_id_alg); + pub const ID_CMC: Nid = Nid(ffi::NID_id_cmc); + pub const ID_ON: Nid = Nid(ffi::NID_id_on); + pub const ID_PDA: Nid = Nid(ffi::NID_id_pda); + pub const ID_ACA: Nid = Nid(ffi::NID_id_aca); + pub const ID_QCS: Nid = Nid(ffi::NID_id_qcs); + pub const ID_CCT: Nid = Nid(ffi::NID_id_cct); + pub const ID_PPL: Nid = Nid(ffi::NID_id_ppl); + pub const ID_AD: Nid = Nid(ffi::NID_id_ad); + pub const ID_PKIX1_EXPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_explicit_88); + pub const ID_PKIX1_IMPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_implicit_88); + pub const ID_PKIX1_EXPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_explicit_93); + pub const ID_PKIX1_IMPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_implicit_93); + pub const ID_MOD_CRMF: Nid = Nid(ffi::NID_id_mod_crmf); + pub const ID_MOD_CMC: Nid = Nid(ffi::NID_id_mod_cmc); + pub const ID_MOD_KEA_PROFILE_88: Nid = Nid(ffi::NID_id_mod_kea_profile_88); + pub const ID_MOD_KEA_PROFILE_93: Nid = Nid(ffi::NID_id_mod_kea_profile_93); + pub const ID_MOD_CMP: Nid = Nid(ffi::NID_id_mod_cmp); + pub const ID_MOD_QUALIFIED_CERT_88: Nid = Nid(ffi::NID_id_mod_qualified_cert_88); + pub const ID_MOD_QUALIFIED_CERT_93: Nid = Nid(ffi::NID_id_mod_qualified_cert_93); + pub const ID_MOD_ATTRIBUTE_CERT: Nid = Nid(ffi::NID_id_mod_attribute_cert); + pub const ID_MOD_TIMESTAMP_PROTOCOL: Nid = Nid(ffi::NID_id_mod_timestamp_protocol); + pub const ID_MOD_OCSP: Nid = Nid(ffi::NID_id_mod_ocsp); + pub const ID_MOD_DVCS: Nid = Nid(ffi::NID_id_mod_dvcs); + pub const ID_MOD_CMP2000: Nid = Nid(ffi::NID_id_mod_cmp2000); + pub const INFO_ACCESS: Nid = Nid(ffi::NID_info_access); + pub const BIOMETRICINFO: Nid = Nid(ffi::NID_biometricInfo); + pub const QCSTATEMENTS: Nid = Nid(ffi::NID_qcStatements); + pub const AC_AUDITENTITY: Nid = Nid(ffi::NID_ac_auditEntity); + pub const AC_TARGETING: Nid = Nid(ffi::NID_ac_targeting); + pub const AACONTROLS: Nid = Nid(ffi::NID_aaControls); + pub const SBGP_IPADDRBLOCK: Nid = Nid(ffi::NID_sbgp_ipAddrBlock); + pub const SBGP_AUTONOMOUSSYSNUM: Nid = Nid(ffi::NID_sbgp_autonomousSysNum); + pub const SBGP_ROUTERIDENTIFIER: Nid = Nid(ffi::NID_sbgp_routerIdentifier); + pub const AC_PROXYING: Nid = Nid(ffi::NID_ac_proxying); + pub const SINFO_ACCESS: Nid = Nid(ffi::NID_sinfo_access); + pub const PROXYCERTINFO: Nid = Nid(ffi::NID_proxyCertInfo); + pub const ID_QT_CPS: Nid = Nid(ffi::NID_id_qt_cps); + pub const ID_QT_UNOTICE: Nid = Nid(ffi::NID_id_qt_unotice); + pub const TEXTNOTICE: Nid = Nid(ffi::NID_textNotice); + pub const SERVER_AUTH: Nid = Nid(ffi::NID_server_auth); + pub const CLIENT_AUTH: Nid = Nid(ffi::NID_client_auth); + pub const CODE_SIGN: Nid = Nid(ffi::NID_code_sign); + pub const EMAIL_PROTECT: Nid = Nid(ffi::NID_email_protect); + pub const IPSECENDSYSTEM: Nid = Nid(ffi::NID_ipsecEndSystem); + pub const IPSECTUNNEL: Nid = Nid(ffi::NID_ipsecTunnel); + pub const IPSECUSER: Nid = Nid(ffi::NID_ipsecUser); + pub const TIME_STAMP: Nid = Nid(ffi::NID_time_stamp); + pub const OCSP_SIGN: Nid = Nid(ffi::NID_OCSP_sign); + pub const DVCS: Nid = Nid(ffi::NID_dvcs); + pub const ID_IT_CAPROTENCCERT: Nid = Nid(ffi::NID_id_it_caProtEncCert); + pub const ID_IT_SIGNKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_signKeyPairTypes); + pub const ID_IT_ENCKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_encKeyPairTypes); + pub const ID_IT_PREFERREDSYMMALG: Nid = Nid(ffi::NID_id_it_preferredSymmAlg); + pub const ID_IT_CAKEYUPDATEINFO: Nid = Nid(ffi::NID_id_it_caKeyUpdateInfo); + pub const ID_IT_CURRENTCRL: Nid = Nid(ffi::NID_id_it_currentCRL); + pub const ID_IT_UNSUPPORTEDOIDS: Nid = Nid(ffi::NID_id_it_unsupportedOIDs); + pub const ID_IT_SUBSCRIPTIONREQUEST: Nid = Nid(ffi::NID_id_it_subscriptionRequest); + pub const ID_IT_SUBSCRIPTIONRESPONSE: Nid = Nid(ffi::NID_id_it_subscriptionResponse); + pub const ID_IT_KEYPAIRPARAMREQ: Nid = Nid(ffi::NID_id_it_keyPairParamReq); + pub const ID_IT_KEYPAIRPARAMREP: Nid = Nid(ffi::NID_id_it_keyPairParamRep); + pub const ID_IT_REVPASSPHRASE: Nid = Nid(ffi::NID_id_it_revPassphrase); + pub const ID_IT_IMPLICITCONFIRM: Nid = Nid(ffi::NID_id_it_implicitConfirm); + pub const ID_IT_CONFIRMWAITTIME: Nid = Nid(ffi::NID_id_it_confirmWaitTime); + pub const ID_IT_ORIGPKIMESSAGE: Nid = Nid(ffi::NID_id_it_origPKIMessage); + pub const ID_IT_SUPPLANGTAGS: Nid = Nid(ffi::NID_id_it_suppLangTags); + pub const ID_REGCTRL: Nid = Nid(ffi::NID_id_regCtrl); + pub const ID_REGINFO: Nid = Nid(ffi::NID_id_regInfo); + pub const ID_REGCTRL_REGTOKEN: Nid = Nid(ffi::NID_id_regCtrl_regToken); + pub const ID_REGCTRL_AUTHENTICATOR: Nid = Nid(ffi::NID_id_regCtrl_authenticator); + pub const ID_REGCTRL_PKIPUBLICATIONINFO: Nid = Nid(ffi::NID_id_regCtrl_pkiPublicationInfo); + pub const ID_REGCTRL_PKIARCHIVEOPTIONS: Nid = Nid(ffi::NID_id_regCtrl_pkiArchiveOptions); + pub const ID_REGCTRL_OLDCERTID: Nid = Nid(ffi::NID_id_regCtrl_oldCertID); + pub const ID_REGCTRL_PROTOCOLENCRKEY: Nid = Nid(ffi::NID_id_regCtrl_protocolEncrKey); + pub const ID_REGINFO_UTF8PAIRS: Nid = Nid(ffi::NID_id_regInfo_utf8Pairs); + pub const ID_REGINFO_CERTREQ: Nid = Nid(ffi::NID_id_regInfo_certReq); + pub const ID_ALG_DES40: Nid = Nid(ffi::NID_id_alg_des40); + pub const ID_ALG_NOSIGNATURE: Nid = Nid(ffi::NID_id_alg_noSignature); + pub const ID_ALG_DH_SIG_HMAC_SHA1: Nid = Nid(ffi::NID_id_alg_dh_sig_hmac_sha1); + pub const ID_ALG_DH_POP: Nid = Nid(ffi::NID_id_alg_dh_pop); + pub const ID_CMC_STATUSINFO: Nid = Nid(ffi::NID_id_cmc_statusInfo); + pub const ID_CMC_IDENTIFICATION: Nid = Nid(ffi::NID_id_cmc_identification); + pub const ID_CMC_IDENTITYPROOF: Nid = Nid(ffi::NID_id_cmc_identityProof); + pub const ID_CMC_DATARETURN: Nid = Nid(ffi::NID_id_cmc_dataReturn); + pub const ID_CMC_TRANSACTIONID: Nid = Nid(ffi::NID_id_cmc_transactionId); + pub const ID_CMC_SENDERNONCE: Nid = Nid(ffi::NID_id_cmc_senderNonce); + pub const ID_CMC_RECIPIENTNONCE: Nid = Nid(ffi::NID_id_cmc_recipientNonce); + pub const ID_CMC_ADDEXTENSIONS: Nid = Nid(ffi::NID_id_cmc_addExtensions); + pub const ID_CMC_ENCRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_encryptedPOP); + pub const ID_CMC_DECRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_decryptedPOP); + pub const ID_CMC_LRAPOPWITNESS: Nid = Nid(ffi::NID_id_cmc_lraPOPWitness); + pub const ID_CMC_GETCERT: Nid = Nid(ffi::NID_id_cmc_getCert); + pub const ID_CMC_GETCRL: Nid = Nid(ffi::NID_id_cmc_getCRL); + pub const ID_CMC_REVOKEREQUEST: Nid = Nid(ffi::NID_id_cmc_revokeRequest); + pub const ID_CMC_REGINFO: Nid = Nid(ffi::NID_id_cmc_regInfo); + pub const ID_CMC_RESPONSEINFO: Nid = Nid(ffi::NID_id_cmc_responseInfo); + pub const ID_CMC_QUERYPENDING: Nid = Nid(ffi::NID_id_cmc_queryPending); + pub const ID_CMC_POPLINKRANDOM: Nid = Nid(ffi::NID_id_cmc_popLinkRandom); + pub const ID_CMC_POPLINKWITNESS: Nid = Nid(ffi::NID_id_cmc_popLinkWitness); + pub const ID_CMC_CONFIRMCERTACCEPTANCE: Nid = Nid(ffi::NID_id_cmc_confirmCertAcceptance); + pub const ID_ON_PERSONALDATA: Nid = Nid(ffi::NID_id_on_personalData); + pub const ID_ON_PERMANENTIDENTIFIER: Nid = Nid(ffi::NID_id_on_permanentIdentifier); + pub const ID_PDA_DATEOFBIRTH: Nid = Nid(ffi::NID_id_pda_dateOfBirth); + pub const ID_PDA_PLACEOFBIRTH: Nid = Nid(ffi::NID_id_pda_placeOfBirth); + pub const ID_PDA_GENDER: Nid = Nid(ffi::NID_id_pda_gender); + pub const ID_PDA_COUNTRYOFCITIZENSHIP: Nid = Nid(ffi::NID_id_pda_countryOfCitizenship); + pub const ID_PDA_COUNTRYOFRESIDENCE: Nid = Nid(ffi::NID_id_pda_countryOfResidence); + pub const ID_ACA_AUTHENTICATIONINFO: Nid = Nid(ffi::NID_id_aca_authenticationInfo); + pub const ID_ACA_ACCESSIDENTITY: Nid = Nid(ffi::NID_id_aca_accessIdentity); + pub const ID_ACA_CHARGINGIDENTITY: Nid = Nid(ffi::NID_id_aca_chargingIdentity); + pub const ID_ACA_GROUP: Nid = Nid(ffi::NID_id_aca_group); + pub const ID_ACA_ROLE: Nid = Nid(ffi::NID_id_aca_role); + pub const ID_ACA_ENCATTRS: Nid = Nid(ffi::NID_id_aca_encAttrs); + pub const ID_QCS_PKIXQCSYNTAX_V1: Nid = Nid(ffi::NID_id_qcs_pkixQCSyntax_v1); + pub const ID_CCT_CRS: Nid = Nid(ffi::NID_id_cct_crs); + pub const ID_CCT_PKIDATA: Nid = Nid(ffi::NID_id_cct_PKIData); + pub const ID_CCT_PKIRESPONSE: Nid = Nid(ffi::NID_id_cct_PKIResponse); + pub const ID_PPL_ANYLANGUAGE: Nid = Nid(ffi::NID_id_ppl_anyLanguage); + pub const ID_PPL_INHERITALL: Nid = Nid(ffi::NID_id_ppl_inheritAll); + pub const INDEPENDENT: Nid = Nid(ffi::NID_Independent); + pub const AD_OCSP: Nid = Nid(ffi::NID_ad_OCSP); + pub const AD_CA_ISSUERS: Nid = Nid(ffi::NID_ad_ca_issuers); + pub const AD_TIMESTAMPING: Nid = Nid(ffi::NID_ad_timeStamping); + pub const AD_DVCS: Nid = Nid(ffi::NID_ad_dvcs); + pub const CAREPOSITORY: Nid = Nid(ffi::NID_caRepository); + pub const ID_PKIX_OCSP_BASIC: Nid = Nid(ffi::NID_id_pkix_OCSP_basic); + pub const ID_PKIX_OCSP_NONCE: Nid = Nid(ffi::NID_id_pkix_OCSP_Nonce); + pub const ID_PKIX_OCSP_CRLID: Nid = Nid(ffi::NID_id_pkix_OCSP_CrlID); + pub const ID_PKIX_OCSP_ACCEPTABLERESPONSES: Nid = + Nid(ffi::NID_id_pkix_OCSP_acceptableResponses); + pub const ID_PKIX_OCSP_NOCHECK: Nid = Nid(ffi::NID_id_pkix_OCSP_noCheck); + pub const ID_PKIX_OCSP_ARCHIVECUTOFF: Nid = Nid(ffi::NID_id_pkix_OCSP_archiveCutoff); + pub const ID_PKIX_OCSP_SERVICELOCATOR: Nid = Nid(ffi::NID_id_pkix_OCSP_serviceLocator); + pub const ID_PKIX_OCSP_EXTENDEDSTATUS: Nid = Nid(ffi::NID_id_pkix_OCSP_extendedStatus); + pub const ID_PKIX_OCSP_VALID: Nid = Nid(ffi::NID_id_pkix_OCSP_valid); + pub const ID_PKIX_OCSP_PATH: Nid = Nid(ffi::NID_id_pkix_OCSP_path); + pub const ID_PKIX_OCSP_TRUSTROOT: Nid = Nid(ffi::NID_id_pkix_OCSP_trustRoot); + pub const ALGORITHM: Nid = Nid(ffi::NID_algorithm); + pub const MD5WITHRSA: Nid = Nid(ffi::NID_md5WithRSA); + pub const DES_ECB: Nid = Nid(ffi::NID_des_ecb); + pub const DES_CBC: Nid = Nid(ffi::NID_des_cbc); + pub const DES_OFB64: Nid = Nid(ffi::NID_des_ofb64); + pub const DES_CFB64: Nid = Nid(ffi::NID_des_cfb64); + pub const RSASIGNATURE: Nid = Nid(ffi::NID_rsaSignature); + pub const DSA_2: Nid = Nid(ffi::NID_dsa_2); + pub const DSAWITHSHA: Nid = Nid(ffi::NID_dsaWithSHA); + pub const SHAWITHRSAENCRYPTION: Nid = Nid(ffi::NID_shaWithRSAEncryption); + pub const DES_EDE_ECB: Nid = Nid(ffi::NID_des_ede_ecb); + pub const DES_EDE3_ECB: Nid = Nid(ffi::NID_des_ede3_ecb); + pub const DES_EDE_CBC: Nid = Nid(ffi::NID_des_ede_cbc); + pub const DES_EDE_CFB64: Nid = Nid(ffi::NID_des_ede_cfb64); + pub const DES_EDE3_CFB64: Nid = Nid(ffi::NID_des_ede3_cfb64); + pub const DES_EDE_OFB64: Nid = Nid(ffi::NID_des_ede_ofb64); + pub const DES_EDE3_OFB64: Nid = Nid(ffi::NID_des_ede3_ofb64); + pub const DESX_CBC: Nid = Nid(ffi::NID_desx_cbc); + pub const SHA: Nid = Nid(ffi::NID_sha); + pub const SHA1: Nid = Nid(ffi::NID_sha1); + pub const DSAWITHSHA1_2: Nid = Nid(ffi::NID_dsaWithSHA1_2); + pub const SHA1WITHRSA: Nid = Nid(ffi::NID_sha1WithRSA); + pub const RIPEMD160: Nid = Nid(ffi::NID_ripemd160); + pub const RIPEMD160WITHRSA: Nid = Nid(ffi::NID_ripemd160WithRSA); + pub const SXNET: Nid = Nid(ffi::NID_sxnet); + pub const X500: Nid = Nid(ffi::NID_X500); + pub const X509: Nid = Nid(ffi::NID_X509); + pub const COMMONNAME: Nid = Nid(ffi::NID_commonName); + pub const SURNAME: Nid = Nid(ffi::NID_surname); + pub const SERIALNUMBER: Nid = Nid(ffi::NID_serialNumber); + pub const COUNTRYNAME: Nid = Nid(ffi::NID_countryName); + pub const LOCALITYNAME: Nid = Nid(ffi::NID_localityName); + pub const STATEORPROVINCENAME: Nid = Nid(ffi::NID_stateOrProvinceName); + pub const STREETADDRESS: Nid = Nid(ffi::NID_streetAddress); + pub const ORGANIZATIONNAME: Nid = Nid(ffi::NID_organizationName); + pub const ORGANIZATIONALUNITNAME: Nid = Nid(ffi::NID_organizationalUnitName); + pub const TITLE: Nid = Nid(ffi::NID_title); + pub const DESCRIPTION: Nid = Nid(ffi::NID_description); + pub const SEARCHGUIDE: Nid = Nid(ffi::NID_searchGuide); + pub const BUSINESSCATEGORY: Nid = Nid(ffi::NID_businessCategory); + pub const POSTALADDRESS: Nid = Nid(ffi::NID_postalAddress); + pub const POSTALCODE: Nid = Nid(ffi::NID_postalCode); + pub const POSTOFFICEBOX: Nid = Nid(ffi::NID_postOfficeBox); + pub const PHYSICALDELIVERYOFFICENAME: Nid = Nid(ffi::NID_physicalDeliveryOfficeName); + pub const TELEPHONENUMBER: Nid = Nid(ffi::NID_telephoneNumber); + pub const TELEXNUMBER: Nid = Nid(ffi::NID_telexNumber); + pub const TELETEXTERMINALIDENTIFIER: Nid = Nid(ffi::NID_teletexTerminalIdentifier); + pub const FACSIMILETELEPHONENUMBER: Nid = Nid(ffi::NID_facsimileTelephoneNumber); + pub const X121ADDRESS: Nid = Nid(ffi::NID_x121Address); + pub const INTERNATIONALISDNNUMBER: Nid = Nid(ffi::NID_internationaliSDNNumber); + pub const REGISTEREDADDRESS: Nid = Nid(ffi::NID_registeredAddress); + pub const DESTINATIONINDICATOR: Nid = Nid(ffi::NID_destinationIndicator); + pub const PREFERREDDELIVERYMETHOD: Nid = Nid(ffi::NID_preferredDeliveryMethod); + pub const PRESENTATIONADDRESS: Nid = Nid(ffi::NID_presentationAddress); + pub const SUPPORTEDAPPLICATIONCONTEXT: Nid = Nid(ffi::NID_supportedApplicationContext); + pub const MEMBER: Nid = Nid(ffi::NID_member); + pub const OWNER: Nid = Nid(ffi::NID_owner); + pub const ROLEOCCUPANT: Nid = Nid(ffi::NID_roleOccupant); + pub const SEEALSO: Nid = Nid(ffi::NID_seeAlso); + pub const USERPASSWORD: Nid = Nid(ffi::NID_userPassword); + pub const USERCERTIFICATE: Nid = Nid(ffi::NID_userCertificate); + pub const CACERTIFICATE: Nid = Nid(ffi::NID_cACertificate); + pub const AUTHORITYREVOCATIONLIST: Nid = Nid(ffi::NID_authorityRevocationList); + pub const CERTIFICATEREVOCATIONLIST: Nid = Nid(ffi::NID_certificateRevocationList); + pub const CROSSCERTIFICATEPAIR: Nid = Nid(ffi::NID_crossCertificatePair); + pub const NAME: Nid = Nid(ffi::NID_name); + pub const GIVENNAME: Nid = Nid(ffi::NID_givenName); + pub const INITIALS: Nid = Nid(ffi::NID_initials); + pub const GENERATIONQUALIFIER: Nid = Nid(ffi::NID_generationQualifier); + pub const X500UNIQUEIDENTIFIER: Nid = Nid(ffi::NID_x500UniqueIdentifier); + pub const DNQUALIFIER: Nid = Nid(ffi::NID_dnQualifier); + pub const ENHANCEDSEARCHGUIDE: Nid = Nid(ffi::NID_enhancedSearchGuide); + pub const PROTOCOLINFORMATION: Nid = Nid(ffi::NID_protocolInformation); + pub const DISTINGUISHEDNAME: Nid = Nid(ffi::NID_distinguishedName); + pub const UNIQUEMEMBER: Nid = Nid(ffi::NID_uniqueMember); + pub const HOUSEIDENTIFIER: Nid = Nid(ffi::NID_houseIdentifier); + pub const SUPPORTEDALGORITHMS: Nid = Nid(ffi::NID_supportedAlgorithms); + pub const DELTAREVOCATIONLIST: Nid = Nid(ffi::NID_deltaRevocationList); + pub const DMDNAME: Nid = Nid(ffi::NID_dmdName); + pub const PSEUDONYM: Nid = Nid(ffi::NID_pseudonym); + pub const ROLE: Nid = Nid(ffi::NID_role); + pub const X500ALGORITHMS: Nid = Nid(ffi::NID_X500algorithms); + pub const RSA: Nid = Nid(ffi::NID_rsa); + pub const MDC2WITHRSA: Nid = Nid(ffi::NID_mdc2WithRSA); + pub const MDC2: Nid = Nid(ffi::NID_mdc2); + pub const ID_CE: Nid = Nid(ffi::NID_id_ce); + pub const SUBJECT_DIRECTORY_ATTRIBUTES: Nid = Nid(ffi::NID_subject_directory_attributes); + pub const SUBJECT_KEY_IDENTIFIER: Nid = Nid(ffi::NID_subject_key_identifier); + pub const KEY_USAGE: Nid = Nid(ffi::NID_key_usage); + pub const PRIVATE_KEY_USAGE_PERIOD: Nid = Nid(ffi::NID_private_key_usage_period); + pub const SUBJECT_ALT_NAME: Nid = Nid(ffi::NID_subject_alt_name); + pub const ISSUER_ALT_NAME: Nid = Nid(ffi::NID_issuer_alt_name); + pub const BASIC_CONSTRAINTS: Nid = Nid(ffi::NID_basic_constraints); + pub const CRL_NUMBER: Nid = Nid(ffi::NID_crl_number); + pub const CRL_REASON: Nid = Nid(ffi::NID_crl_reason); + pub const INVALIDITY_DATE: Nid = Nid(ffi::NID_invalidity_date); + pub const DELTA_CRL: Nid = Nid(ffi::NID_delta_crl); + pub const ISSUING_DISTRIBUTION_POINT: Nid = Nid(ffi::NID_issuing_distribution_point); + pub const CERTIFICATE_ISSUER: Nid = Nid(ffi::NID_certificate_issuer); + pub const NAME_CONSTRAINTS: Nid = Nid(ffi::NID_name_constraints); + pub const CRL_DISTRIBUTION_POINTS: Nid = Nid(ffi::NID_crl_distribution_points); + pub const CERTIFICATE_POLICIES: Nid = Nid(ffi::NID_certificate_policies); + pub const ANY_POLICY: Nid = Nid(ffi::NID_any_policy); + pub const POLICY_MAPPINGS: Nid = Nid(ffi::NID_policy_mappings); + pub const AUTHORITY_KEY_IDENTIFIER: Nid = Nid(ffi::NID_authority_key_identifier); + pub const POLICY_CONSTRAINTS: Nid = Nid(ffi::NID_policy_constraints); + pub const EXT_KEY_USAGE: Nid = Nid(ffi::NID_ext_key_usage); + pub const FRESHEST_CRL: Nid = Nid(ffi::NID_freshest_crl); + pub const INHIBIT_ANY_POLICY: Nid = Nid(ffi::NID_inhibit_any_policy); + pub const TARGET_INFORMATION: Nid = Nid(ffi::NID_target_information); + pub const NO_REV_AVAIL: Nid = Nid(ffi::NID_no_rev_avail); + pub const ANYEXTENDEDKEYUSAGE: Nid = Nid(ffi::NID_anyExtendedKeyUsage); + pub const NETSCAPE: Nid = Nid(ffi::NID_netscape); + pub const NETSCAPE_CERT_EXTENSION: Nid = Nid(ffi::NID_netscape_cert_extension); + pub const NETSCAPE_DATA_TYPE: Nid = Nid(ffi::NID_netscape_data_type); + pub const NETSCAPE_CERT_TYPE: Nid = Nid(ffi::NID_netscape_cert_type); + pub const NETSCAPE_BASE_URL: Nid = Nid(ffi::NID_netscape_base_url); + pub const NETSCAPE_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_revocation_url); + pub const NETSCAPE_CA_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_ca_revocation_url); + pub const NETSCAPE_RENEWAL_URL: Nid = Nid(ffi::NID_netscape_renewal_url); + pub const NETSCAPE_CA_POLICY_URL: Nid = Nid(ffi::NID_netscape_ca_policy_url); + pub const NETSCAPE_SSL_SERVER_NAME: Nid = Nid(ffi::NID_netscape_ssl_server_name); + pub const NETSCAPE_COMMENT: Nid = Nid(ffi::NID_netscape_comment); + pub const NETSCAPE_CERT_SEQUENCE: Nid = Nid(ffi::NID_netscape_cert_sequence); + pub const NS_SGC: Nid = Nid(ffi::NID_ns_sgc); + pub const ORG: Nid = Nid(ffi::NID_org); + pub const DOD: Nid = Nid(ffi::NID_dod); + pub const IANA: Nid = Nid(ffi::NID_iana); + pub const DIRECTORY: Nid = Nid(ffi::NID_Directory); + pub const MANAGEMENT: Nid = Nid(ffi::NID_Management); + pub const EXPERIMENTAL: Nid = Nid(ffi::NID_Experimental); + pub const PRIVATE: Nid = Nid(ffi::NID_Private); + pub const SECURITY: Nid = Nid(ffi::NID_Security); + pub const SNMPV2: Nid = Nid(ffi::NID_SNMPv2); + pub const MAIL: Nid = Nid(ffi::NID_Mail); + pub const ENTERPRISES: Nid = Nid(ffi::NID_Enterprises); + pub const DCOBJECT: Nid = Nid(ffi::NID_dcObject); + pub const MIME_MHS: Nid = Nid(ffi::NID_mime_mhs); + pub const MIME_MHS_HEADINGS: Nid = Nid(ffi::NID_mime_mhs_headings); + pub const MIME_MHS_BODIES: Nid = Nid(ffi::NID_mime_mhs_bodies); + pub const ID_HEX_PARTIAL_MESSAGE: Nid = Nid(ffi::NID_id_hex_partial_message); + pub const ID_HEX_MULTIPART_MESSAGE: Nid = Nid(ffi::NID_id_hex_multipart_message); + pub const ZLIB_COMPRESSION: Nid = Nid(ffi::NID_zlib_compression); + pub const AES_128_ECB: Nid = Nid(ffi::NID_aes_128_ecb); + pub const AES_128_CBC: Nid = Nid(ffi::NID_aes_128_cbc); + pub const AES_128_OFB128: Nid = Nid(ffi::NID_aes_128_ofb128); + pub const AES_128_CFB128: Nid = Nid(ffi::NID_aes_128_cfb128); + pub const ID_AES128_WRAP: Nid = Nid(ffi::NID_id_aes128_wrap); + pub const AES_128_GCM: Nid = Nid(ffi::NID_aes_128_gcm); + pub const AES_128_CCM: Nid = Nid(ffi::NID_aes_128_ccm); + pub const ID_AES128_WRAP_PAD: Nid = Nid(ffi::NID_id_aes128_wrap_pad); + pub const AES_192_ECB: Nid = Nid(ffi::NID_aes_192_ecb); + pub const AES_192_CBC: Nid = Nid(ffi::NID_aes_192_cbc); + pub const AES_192_OFB128: Nid = Nid(ffi::NID_aes_192_ofb128); + pub const AES_192_CFB128: Nid = Nid(ffi::NID_aes_192_cfb128); + pub const ID_AES192_WRAP: Nid = Nid(ffi::NID_id_aes192_wrap); + pub const AES_192_GCM: Nid = Nid(ffi::NID_aes_192_gcm); + pub const AES_192_CCM: Nid = Nid(ffi::NID_aes_192_ccm); + pub const ID_AES192_WRAP_PAD: Nid = Nid(ffi::NID_id_aes192_wrap_pad); + pub const AES_256_ECB: Nid = Nid(ffi::NID_aes_256_ecb); + pub const AES_256_CBC: Nid = Nid(ffi::NID_aes_256_cbc); + pub const AES_256_OFB128: Nid = Nid(ffi::NID_aes_256_ofb128); + pub const AES_256_CFB128: Nid = Nid(ffi::NID_aes_256_cfb128); + pub const ID_AES256_WRAP: Nid = Nid(ffi::NID_id_aes256_wrap); + pub const AES_256_GCM: Nid = Nid(ffi::NID_aes_256_gcm); + pub const AES_256_CCM: Nid = Nid(ffi::NID_aes_256_ccm); + pub const ID_AES256_WRAP_PAD: Nid = Nid(ffi::NID_id_aes256_wrap_pad); + pub const AES_128_CFB1: Nid = Nid(ffi::NID_aes_128_cfb1); + pub const AES_192_CFB1: Nid = Nid(ffi::NID_aes_192_cfb1); + pub const AES_256_CFB1: Nid = Nid(ffi::NID_aes_256_cfb1); + pub const AES_128_CFB8: Nid = Nid(ffi::NID_aes_128_cfb8); + pub const AES_192_CFB8: Nid = Nid(ffi::NID_aes_192_cfb8); + pub const AES_256_CFB8: Nid = Nid(ffi::NID_aes_256_cfb8); + pub const AES_128_CTR: Nid = Nid(ffi::NID_aes_128_ctr); + pub const AES_192_CTR: Nid = Nid(ffi::NID_aes_192_ctr); + pub const AES_256_CTR: Nid = Nid(ffi::NID_aes_256_ctr); + pub const AES_128_XTS: Nid = Nid(ffi::NID_aes_128_xts); + pub const AES_256_XTS: Nid = Nid(ffi::NID_aes_256_xts); + pub const DES_CFB1: Nid = Nid(ffi::NID_des_cfb1); + pub const DES_CFB8: Nid = Nid(ffi::NID_des_cfb8); + pub const DES_EDE3_CFB1: Nid = Nid(ffi::NID_des_ede3_cfb1); + pub const DES_EDE3_CFB8: Nid = Nid(ffi::NID_des_ede3_cfb8); + pub const SHA256: Nid = Nid(ffi::NID_sha256); + pub const SHA384: Nid = Nid(ffi::NID_sha384); + pub const SHA512: Nid = Nid(ffi::NID_sha512); + pub const SHA224: Nid = Nid(ffi::NID_sha224); + pub const DSA_WITH_SHA224: Nid = Nid(ffi::NID_dsa_with_SHA224); + pub const DSA_WITH_SHA256: Nid = Nid(ffi::NID_dsa_with_SHA256); + pub const HOLD_INSTRUCTION_CODE: Nid = Nid(ffi::NID_hold_instruction_code); + pub const HOLD_INSTRUCTION_NONE: Nid = Nid(ffi::NID_hold_instruction_none); + pub const HOLD_INSTRUCTION_CALL_ISSUER: Nid = Nid(ffi::NID_hold_instruction_call_issuer); + pub const HOLD_INSTRUCTION_REJECT: Nid = Nid(ffi::NID_hold_instruction_reject); + pub const DATA: Nid = Nid(ffi::NID_data); + pub const PSS: Nid = Nid(ffi::NID_pss); + pub const UCL: Nid = Nid(ffi::NID_ucl); + pub const PILOT: Nid = Nid(ffi::NID_pilot); + pub const PILOTATTRIBUTETYPE: Nid = Nid(ffi::NID_pilotAttributeType); + pub const PILOTATTRIBUTESYNTAX: Nid = Nid(ffi::NID_pilotAttributeSyntax); + pub const PILOTOBJECTCLASS: Nid = Nid(ffi::NID_pilotObjectClass); + pub const PILOTGROUPS: Nid = Nid(ffi::NID_pilotGroups); + pub const IA5STRINGSYNTAX: Nid = Nid(ffi::NID_iA5StringSyntax); + pub const CASEIGNOREIA5STRINGSYNTAX: Nid = Nid(ffi::NID_caseIgnoreIA5StringSyntax); + pub const PILOTOBJECT: Nid = Nid(ffi::NID_pilotObject); + pub const PILOTPERSON: Nid = Nid(ffi::NID_pilotPerson); + pub const ACCOUNT: Nid = Nid(ffi::NID_account); + pub const DOCUMENT: Nid = Nid(ffi::NID_document); + pub const ROOM: Nid = Nid(ffi::NID_room); + pub const DOCUMENTSERIES: Nid = Nid(ffi::NID_documentSeries); + pub const DOMAIN: Nid = Nid(ffi::NID_Domain); + pub const RFC822LOCALPART: Nid = Nid(ffi::NID_rFC822localPart); + pub const DNSDOMAIN: Nid = Nid(ffi::NID_dNSDomain); + pub const DOMAINRELATEDOBJECT: Nid = Nid(ffi::NID_domainRelatedObject); + pub const FRIENDLYCOUNTRY: Nid = Nid(ffi::NID_friendlyCountry); + pub const SIMPLESECURITYOBJECT: Nid = Nid(ffi::NID_simpleSecurityObject); + pub const PILOTORGANIZATION: Nid = Nid(ffi::NID_pilotOrganization); + pub const PILOTDSA: Nid = Nid(ffi::NID_pilotDSA); + pub const QUALITYLABELLEDDATA: Nid = Nid(ffi::NID_qualityLabelledData); + pub const USERID: Nid = Nid(ffi::NID_userId); + pub const TEXTENCODEDORADDRESS: Nid = Nid(ffi::NID_textEncodedORAddress); + pub const RFC822MAILBOX: Nid = Nid(ffi::NID_rfc822Mailbox); + pub const INFO: Nid = Nid(ffi::NID_info); + pub const FAVOURITEDRINK: Nid = Nid(ffi::NID_favouriteDrink); + pub const ROOMNUMBER: Nid = Nid(ffi::NID_roomNumber); + pub const PHOTO: Nid = Nid(ffi::NID_photo); + pub const USERCLASS: Nid = Nid(ffi::NID_userClass); + pub const HOST: Nid = Nid(ffi::NID_host); + pub const MANAGER: Nid = Nid(ffi::NID_manager); + pub const DOCUMENTIDENTIFIER: Nid = Nid(ffi::NID_documentIdentifier); + pub const DOCUMENTTITLE: Nid = Nid(ffi::NID_documentTitle); + pub const DOCUMENTVERSION: Nid = Nid(ffi::NID_documentVersion); + pub const DOCUMENTAUTHOR: Nid = Nid(ffi::NID_documentAuthor); + pub const DOCUMENTLOCATION: Nid = Nid(ffi::NID_documentLocation); + pub const HOMETELEPHONENUMBER: Nid = Nid(ffi::NID_homeTelephoneNumber); + pub const SECRETARY: Nid = Nid(ffi::NID_secretary); + pub const OTHERMAILBOX: Nid = Nid(ffi::NID_otherMailbox); + pub const LASTMODIFIEDTIME: Nid = Nid(ffi::NID_lastModifiedTime); + pub const LASTMODIFIEDBY: Nid = Nid(ffi::NID_lastModifiedBy); + pub const DOMAINCOMPONENT: Nid = Nid(ffi::NID_domainComponent); + pub const ARECORD: Nid = Nid(ffi::NID_aRecord); + pub const PILOTATTRIBUTETYPE27: Nid = Nid(ffi::NID_pilotAttributeType27); + pub const MXRECORD: Nid = Nid(ffi::NID_mXRecord); + pub const NSRECORD: Nid = Nid(ffi::NID_nSRecord); + pub const SOARECORD: Nid = Nid(ffi::NID_sOARecord); + pub const CNAMERECORD: Nid = Nid(ffi::NID_cNAMERecord); + pub const ASSOCIATEDDOMAIN: Nid = Nid(ffi::NID_associatedDomain); + pub const ASSOCIATEDNAME: Nid = Nid(ffi::NID_associatedName); + pub const HOMEPOSTALADDRESS: Nid = Nid(ffi::NID_homePostalAddress); + pub const PERSONALTITLE: Nid = Nid(ffi::NID_personalTitle); + pub const MOBILETELEPHONENUMBER: Nid = Nid(ffi::NID_mobileTelephoneNumber); + pub const PAGERTELEPHONENUMBER: Nid = Nid(ffi::NID_pagerTelephoneNumber); + pub const FRIENDLYCOUNTRYNAME: Nid = Nid(ffi::NID_friendlyCountryName); + pub const ORGANIZATIONALSTATUS: Nid = Nid(ffi::NID_organizationalStatus); + pub const JANETMAILBOX: Nid = Nid(ffi::NID_janetMailbox); + pub const MAILPREFERENCEOPTION: Nid = Nid(ffi::NID_mailPreferenceOption); + pub const BUILDINGNAME: Nid = Nid(ffi::NID_buildingName); + pub const DSAQUALITY: Nid = Nid(ffi::NID_dSAQuality); + pub const SINGLELEVELQUALITY: Nid = Nid(ffi::NID_singleLevelQuality); + pub const SUBTREEMINIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMinimumQuality); + pub const SUBTREEMAXIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMaximumQuality); + pub const PERSONALSIGNATURE: Nid = Nid(ffi::NID_personalSignature); + pub const DITREDIRECT: Nid = Nid(ffi::NID_dITRedirect); + pub const AUDIO: Nid = Nid(ffi::NID_audio); + pub const DOCUMENTPUBLISHER: Nid = Nid(ffi::NID_documentPublisher); + pub const ID_SET: Nid = Nid(ffi::NID_id_set); + pub const SET_CTYPE: Nid = Nid(ffi::NID_set_ctype); + pub const SET_MSGEXT: Nid = Nid(ffi::NID_set_msgExt); + pub const SET_ATTR: Nid = Nid(ffi::NID_set_attr); + pub const SET_POLICY: Nid = Nid(ffi::NID_set_policy); + pub const SET_CERTEXT: Nid = Nid(ffi::NID_set_certExt); + pub const SET_BRAND: Nid = Nid(ffi::NID_set_brand); + pub const SETCT_PANDATA: Nid = Nid(ffi::NID_setct_PANData); + pub const SETCT_PANTOKEN: Nid = Nid(ffi::NID_setct_PANToken); + pub const SETCT_PANONLY: Nid = Nid(ffi::NID_setct_PANOnly); + pub const SETCT_OIDATA: Nid = Nid(ffi::NID_setct_OIData); + pub const SETCT_PI: Nid = Nid(ffi::NID_setct_PI); + pub const SETCT_PIDATA: Nid = Nid(ffi::NID_setct_PIData); + pub const SETCT_PIDATAUNSIGNED: Nid = Nid(ffi::NID_setct_PIDataUnsigned); + pub const SETCT_HODINPUT: Nid = Nid(ffi::NID_setct_HODInput); + pub const SETCT_AUTHRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthResBaggage); + pub const SETCT_AUTHREVREQBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevReqBaggage); + pub const SETCT_AUTHREVRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevResBaggage); + pub const SETCT_CAPTOKENSEQ: Nid = Nid(ffi::NID_setct_CapTokenSeq); + pub const SETCT_PINITRESDATA: Nid = Nid(ffi::NID_setct_PInitResData); + pub const SETCT_PI_TBS: Nid = Nid(ffi::NID_setct_PI_TBS); + pub const SETCT_PRESDATA: Nid = Nid(ffi::NID_setct_PResData); + pub const SETCT_AUTHREQTBS: Nid = Nid(ffi::NID_setct_AuthReqTBS); + pub const SETCT_AUTHRESTBS: Nid = Nid(ffi::NID_setct_AuthResTBS); + pub const SETCT_AUTHRESTBSX: Nid = Nid(ffi::NID_setct_AuthResTBSX); + pub const SETCT_AUTHTOKENTBS: Nid = Nid(ffi::NID_setct_AuthTokenTBS); + pub const SETCT_CAPTOKENDATA: Nid = Nid(ffi::NID_setct_CapTokenData); + pub const SETCT_CAPTOKENTBS: Nid = Nid(ffi::NID_setct_CapTokenTBS); + pub const SETCT_ACQCARDCODEMSG: Nid = Nid(ffi::NID_setct_AcqCardCodeMsg); + pub const SETCT_AUTHREVREQTBS: Nid = Nid(ffi::NID_setct_AuthRevReqTBS); + pub const SETCT_AUTHREVRESDATA: Nid = Nid(ffi::NID_setct_AuthRevResData); + pub const SETCT_AUTHREVRESTBS: Nid = Nid(ffi::NID_setct_AuthRevResTBS); + pub const SETCT_CAPREQTBS: Nid = Nid(ffi::NID_setct_CapReqTBS); + pub const SETCT_CAPREQTBSX: Nid = Nid(ffi::NID_setct_CapReqTBSX); + pub const SETCT_CAPRESDATA: Nid = Nid(ffi::NID_setct_CapResData); + pub const SETCT_CAPREVREQTBS: Nid = Nid(ffi::NID_setct_CapRevReqTBS); + pub const SETCT_CAPREVREQTBSX: Nid = Nid(ffi::NID_setct_CapRevReqTBSX); + pub const SETCT_CAPREVRESDATA: Nid = Nid(ffi::NID_setct_CapRevResData); + pub const SETCT_CREDREQTBS: Nid = Nid(ffi::NID_setct_CredReqTBS); + pub const SETCT_CREDREQTBSX: Nid = Nid(ffi::NID_setct_CredReqTBSX); + pub const SETCT_CREDRESDATA: Nid = Nid(ffi::NID_setct_CredResData); + pub const SETCT_CREDREVREQTBS: Nid = Nid(ffi::NID_setct_CredRevReqTBS); + pub const SETCT_CREDREVREQTBSX: Nid = Nid(ffi::NID_setct_CredRevReqTBSX); + pub const SETCT_CREDREVRESDATA: Nid = Nid(ffi::NID_setct_CredRevResData); + pub const SETCT_PCERTREQDATA: Nid = Nid(ffi::NID_setct_PCertReqData); + pub const SETCT_PCERTRESTBS: Nid = Nid(ffi::NID_setct_PCertResTBS); + pub const SETCT_BATCHADMINREQDATA: Nid = Nid(ffi::NID_setct_BatchAdminReqData); + pub const SETCT_BATCHADMINRESDATA: Nid = Nid(ffi::NID_setct_BatchAdminResData); + pub const SETCT_CARDCINITRESTBS: Nid = Nid(ffi::NID_setct_CardCInitResTBS); + pub const SETCT_MEAQCINITRESTBS: Nid = Nid(ffi::NID_setct_MeAqCInitResTBS); + pub const SETCT_REGFORMRESTBS: Nid = Nid(ffi::NID_setct_RegFormResTBS); + pub const SETCT_CERTREQDATA: Nid = Nid(ffi::NID_setct_CertReqData); + pub const SETCT_CERTREQTBS: Nid = Nid(ffi::NID_setct_CertReqTBS); + pub const SETCT_CERTRESDATA: Nid = Nid(ffi::NID_setct_CertResData); + pub const SETCT_CERTINQREQTBS: Nid = Nid(ffi::NID_setct_CertInqReqTBS); + pub const SETCT_ERRORTBS: Nid = Nid(ffi::NID_setct_ErrorTBS); + pub const SETCT_PIDUALSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIDualSignedTBE); + pub const SETCT_PIUNSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIUnsignedTBE); + pub const SETCT_AUTHREQTBE: Nid = Nid(ffi::NID_setct_AuthReqTBE); + pub const SETCT_AUTHRESTBE: Nid = Nid(ffi::NID_setct_AuthResTBE); + pub const SETCT_AUTHRESTBEX: Nid = Nid(ffi::NID_setct_AuthResTBEX); + pub const SETCT_AUTHTOKENTBE: Nid = Nid(ffi::NID_setct_AuthTokenTBE); + pub const SETCT_CAPTOKENTBE: Nid = Nid(ffi::NID_setct_CapTokenTBE); + pub const SETCT_CAPTOKENTBEX: Nid = Nid(ffi::NID_setct_CapTokenTBEX); + pub const SETCT_ACQCARDCODEMSGTBE: Nid = Nid(ffi::NID_setct_AcqCardCodeMsgTBE); + pub const SETCT_AUTHREVREQTBE: Nid = Nid(ffi::NID_setct_AuthRevReqTBE); + pub const SETCT_AUTHREVRESTBE: Nid = Nid(ffi::NID_setct_AuthRevResTBE); + pub const SETCT_AUTHREVRESTBEB: Nid = Nid(ffi::NID_setct_AuthRevResTBEB); + pub const SETCT_CAPREQTBE: Nid = Nid(ffi::NID_setct_CapReqTBE); + pub const SETCT_CAPREQTBEX: Nid = Nid(ffi::NID_setct_CapReqTBEX); + pub const SETCT_CAPRESTBE: Nid = Nid(ffi::NID_setct_CapResTBE); + pub const SETCT_CAPREVREQTBE: Nid = Nid(ffi::NID_setct_CapRevReqTBE); + pub const SETCT_CAPREVREQTBEX: Nid = Nid(ffi::NID_setct_CapRevReqTBEX); + pub const SETCT_CAPREVRESTBE: Nid = Nid(ffi::NID_setct_CapRevResTBE); + pub const SETCT_CREDREQTBE: Nid = Nid(ffi::NID_setct_CredReqTBE); + pub const SETCT_CREDREQTBEX: Nid = Nid(ffi::NID_setct_CredReqTBEX); + pub const SETCT_CREDRESTBE: Nid = Nid(ffi::NID_setct_CredResTBE); + pub const SETCT_CREDREVREQTBE: Nid = Nid(ffi::NID_setct_CredRevReqTBE); + pub const SETCT_CREDREVREQTBEX: Nid = Nid(ffi::NID_setct_CredRevReqTBEX); + pub const SETCT_CREDREVRESTBE: Nid = Nid(ffi::NID_setct_CredRevResTBE); + pub const SETCT_BATCHADMINREQTBE: Nid = Nid(ffi::NID_setct_BatchAdminReqTBE); + pub const SETCT_BATCHADMINRESTBE: Nid = Nid(ffi::NID_setct_BatchAdminResTBE); + pub const SETCT_REGFORMREQTBE: Nid = Nid(ffi::NID_setct_RegFormReqTBE); + pub const SETCT_CERTREQTBE: Nid = Nid(ffi::NID_setct_CertReqTBE); + pub const SETCT_CERTREQTBEX: Nid = Nid(ffi::NID_setct_CertReqTBEX); + pub const SETCT_CERTRESTBE: Nid = Nid(ffi::NID_setct_CertResTBE); + pub const SETCT_CRLNOTIFICATIONTBS: Nid = Nid(ffi::NID_setct_CRLNotificationTBS); + pub const SETCT_CRLNOTIFICATIONRESTBS: Nid = Nid(ffi::NID_setct_CRLNotificationResTBS); + pub const SETCT_BCIDISTRIBUTIONTBS: Nid = Nid(ffi::NID_setct_BCIDistributionTBS); + pub const SETEXT_GENCRYPT: Nid = Nid(ffi::NID_setext_genCrypt); + pub const SETEXT_MIAUTH: Nid = Nid(ffi::NID_setext_miAuth); + pub const SETEXT_PINSECURE: Nid = Nid(ffi::NID_setext_pinSecure); + pub const SETEXT_PINANY: Nid = Nid(ffi::NID_setext_pinAny); + pub const SETEXT_TRACK2: Nid = Nid(ffi::NID_setext_track2); + pub const SETEXT_CV: Nid = Nid(ffi::NID_setext_cv); + pub const SET_POLICY_ROOT: Nid = Nid(ffi::NID_set_policy_root); + pub const SETCEXT_HASHEDROOT: Nid = Nid(ffi::NID_setCext_hashedRoot); + pub const SETCEXT_CERTTYPE: Nid = Nid(ffi::NID_setCext_certType); + pub const SETCEXT_MERCHDATA: Nid = Nid(ffi::NID_setCext_merchData); + pub const SETCEXT_CCERTREQUIRED: Nid = Nid(ffi::NID_setCext_cCertRequired); + pub const SETCEXT_TUNNELING: Nid = Nid(ffi::NID_setCext_tunneling); + pub const SETCEXT_SETEXT: Nid = Nid(ffi::NID_setCext_setExt); + pub const SETCEXT_SETQUALF: Nid = Nid(ffi::NID_setCext_setQualf); + pub const SETCEXT_PGWYCAPABILITIES: Nid = Nid(ffi::NID_setCext_PGWYcapabilities); + pub const SETCEXT_TOKENIDENTIFIER: Nid = Nid(ffi::NID_setCext_TokenIdentifier); + pub const SETCEXT_TRACK2DATA: Nid = Nid(ffi::NID_setCext_Track2Data); + pub const SETCEXT_TOKENTYPE: Nid = Nid(ffi::NID_setCext_TokenType); + pub const SETCEXT_ISSUERCAPABILITIES: Nid = Nid(ffi::NID_setCext_IssuerCapabilities); + pub const SETATTR_CERT: Nid = Nid(ffi::NID_setAttr_Cert); + pub const SETATTR_PGWYCAP: Nid = Nid(ffi::NID_setAttr_PGWYcap); + pub const SETATTR_TOKENTYPE: Nid = Nid(ffi::NID_setAttr_TokenType); + pub const SETATTR_ISSCAP: Nid = Nid(ffi::NID_setAttr_IssCap); + pub const SET_ROOTKEYTHUMB: Nid = Nid(ffi::NID_set_rootKeyThumb); + pub const SET_ADDPOLICY: Nid = Nid(ffi::NID_set_addPolicy); + pub const SETATTR_TOKEN_EMV: Nid = Nid(ffi::NID_setAttr_Token_EMV); + pub const SETATTR_TOKEN_B0PRIME: Nid = Nid(ffi::NID_setAttr_Token_B0Prime); + pub const SETATTR_ISSCAP_CVM: Nid = Nid(ffi::NID_setAttr_IssCap_CVM); + pub const SETATTR_ISSCAP_T2: Nid = Nid(ffi::NID_setAttr_IssCap_T2); + pub const SETATTR_ISSCAP_SIG: Nid = Nid(ffi::NID_setAttr_IssCap_Sig); + pub const SETATTR_GENCRYPTGRM: Nid = Nid(ffi::NID_setAttr_GenCryptgrm); + pub const SETATTR_T2ENC: Nid = Nid(ffi::NID_setAttr_T2Enc); + pub const SETATTR_T2CLEARTXT: Nid = Nid(ffi::NID_setAttr_T2cleartxt); + pub const SETATTR_TOKICCSIG: Nid = Nid(ffi::NID_setAttr_TokICCsig); + pub const SETATTR_SECDEVSIG: Nid = Nid(ffi::NID_setAttr_SecDevSig); + pub const SET_BRAND_IATA_ATA: Nid = Nid(ffi::NID_set_brand_IATA_ATA); + pub const SET_BRAND_DINERS: Nid = Nid(ffi::NID_set_brand_Diners); + pub const SET_BRAND_AMERICANEXPRESS: Nid = Nid(ffi::NID_set_brand_AmericanExpress); + pub const SET_BRAND_JCB: Nid = Nid(ffi::NID_set_brand_JCB); + pub const SET_BRAND_VISA: Nid = Nid(ffi::NID_set_brand_Visa); + pub const SET_BRAND_MASTERCARD: Nid = Nid(ffi::NID_set_brand_MasterCard); + pub const SET_BRAND_NOVUS: Nid = Nid(ffi::NID_set_brand_Novus); + pub const DES_CDMF: Nid = Nid(ffi::NID_des_cdmf); + pub const RSAOAEPENCRYPTIONSET: Nid = Nid(ffi::NID_rsaOAEPEncryptionSET); + pub const IPSEC3: Nid = Nid(ffi::NID_ipsec3); + pub const IPSEC4: Nid = Nid(ffi::NID_ipsec4); + pub const WHIRLPOOL: Nid = Nid(ffi::NID_whirlpool); + pub const CRYPTOPRO: Nid = Nid(ffi::NID_cryptopro); + pub const CRYPTOCOM: Nid = Nid(ffi::NID_cryptocom); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_94: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94); + pub const ID_GOSTR3411_94: Nid = Nid(ffi::NID_id_GostR3411_94); + pub const ID_HMACGOSTR3411_94: Nid = Nid(ffi::NID_id_HMACGostR3411_94); + pub const ID_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3410_2001); + pub const ID_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3410_94); + pub const ID_GOST28147_89: Nid = Nid(ffi::NID_id_Gost28147_89); + pub const GOST89_CNT: Nid = Nid(ffi::NID_gost89_cnt); + pub const ID_GOST28147_89_MAC: Nid = Nid(ffi::NID_id_Gost28147_89_MAC); + pub const ID_GOSTR3411_94_PRF: Nid = Nid(ffi::NID_id_GostR3411_94_prf); + pub const ID_GOSTR3410_2001DH: Nid = Nid(ffi::NID_id_GostR3410_2001DH); + pub const ID_GOSTR3410_94DH: Nid = Nid(ffi::NID_id_GostR3410_94DH); + pub const ID_GOST28147_89_CRYPTOPRO_KEYMESHING: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_KeyMeshing); + pub const ID_GOST28147_89_NONE_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_None_KeyMeshing); + pub const ID_GOSTR3411_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_TestParamSet); + pub const ID_GOSTR3411_94_CRYPTOPROPARAMSET: Nid = + Nid(ffi::NID_id_GostR3411_94_CryptoProParamSet); + pub const ID_GOST28147_89_TESTPARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_TestParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_A_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_B_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_C_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_D_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_D_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_1_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_0_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet); + pub const ID_GOST28147_89_CRYPTOPRO_RIC_1_PARAMSET: Nid = + Nid(ffi::NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet); + pub const ID_GOSTR3410_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_TestParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_A_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_B_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_C_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_D_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_D_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHA_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchA_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHB_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchB_ParamSet); + pub const ID_GOSTR3410_94_CRYPTOPRO_XCHC_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchC_ParamSet); + pub const ID_GOSTR3410_2001_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_TestParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_A_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_A_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_B_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_B_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_C_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_C_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHA_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet); + pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHB_PARAMSET: Nid = + Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet); + pub const ID_GOSTR3410_94_A: Nid = Nid(ffi::NID_id_GostR3410_94_a); + pub const ID_GOSTR3410_94_ABIS: Nid = Nid(ffi::NID_id_GostR3410_94_aBis); + pub const ID_GOSTR3410_94_B: Nid = Nid(ffi::NID_id_GostR3410_94_b); + pub const ID_GOSTR3410_94_BBIS: Nid = Nid(ffi::NID_id_GostR3410_94_bBis); + pub const ID_GOST28147_89_CC: Nid = Nid(ffi::NID_id_Gost28147_89_cc); + pub const ID_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3410_94_cc); + pub const ID_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_cc); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_94_CC: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94_cc); + pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001_CC: Nid = + Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001_cc); + pub const ID_GOSTR3410_2001_PARAMSET_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_ParamSet_cc); + pub const CAMELLIA_128_CBC: Nid = Nid(ffi::NID_camellia_128_cbc); + pub const CAMELLIA_192_CBC: Nid = Nid(ffi::NID_camellia_192_cbc); + pub const CAMELLIA_256_CBC: Nid = Nid(ffi::NID_camellia_256_cbc); + pub const ID_CAMELLIA128_WRAP: Nid = Nid(ffi::NID_id_camellia128_wrap); + pub const ID_CAMELLIA192_WRAP: Nid = Nid(ffi::NID_id_camellia192_wrap); + pub const ID_CAMELLIA256_WRAP: Nid = Nid(ffi::NID_id_camellia256_wrap); + pub const CAMELLIA_128_ECB: Nid = Nid(ffi::NID_camellia_128_ecb); + pub const CAMELLIA_128_OFB128: Nid = Nid(ffi::NID_camellia_128_ofb128); + pub const CAMELLIA_128_CFB128: Nid = Nid(ffi::NID_camellia_128_cfb128); + pub const CAMELLIA_192_ECB: Nid = Nid(ffi::NID_camellia_192_ecb); + pub const CAMELLIA_192_OFB128: Nid = Nid(ffi::NID_camellia_192_ofb128); + pub const CAMELLIA_192_CFB128: Nid = Nid(ffi::NID_camellia_192_cfb128); + pub const CAMELLIA_256_ECB: Nid = Nid(ffi::NID_camellia_256_ecb); + pub const CAMELLIA_256_OFB128: Nid = Nid(ffi::NID_camellia_256_ofb128); + pub const CAMELLIA_256_CFB128: Nid = Nid(ffi::NID_camellia_256_cfb128); + pub const CAMELLIA_128_CFB1: Nid = Nid(ffi::NID_camellia_128_cfb1); + pub const CAMELLIA_192_CFB1: Nid = Nid(ffi::NID_camellia_192_cfb1); + pub const CAMELLIA_256_CFB1: Nid = Nid(ffi::NID_camellia_256_cfb1); + pub const CAMELLIA_128_CFB8: Nid = Nid(ffi::NID_camellia_128_cfb8); + pub const CAMELLIA_192_CFB8: Nid = Nid(ffi::NID_camellia_192_cfb8); + pub const CAMELLIA_256_CFB8: Nid = Nid(ffi::NID_camellia_256_cfb8); + pub const KISA: Nid = Nid(ffi::NID_kisa); + pub const SEED_ECB: Nid = Nid(ffi::NID_seed_ecb); + pub const SEED_CBC: Nid = Nid(ffi::NID_seed_cbc); + pub const SEED_CFB128: Nid = Nid(ffi::NID_seed_cfb128); + pub const SEED_OFB128: Nid = Nid(ffi::NID_seed_ofb128); + pub const HMAC: Nid = Nid(ffi::NID_hmac); + pub const CMAC: Nid = Nid(ffi::NID_cmac); + pub const RC4_HMAC_MD5: Nid = Nid(ffi::NID_rc4_hmac_md5); + pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1); + pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1); + pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1); +} + +#[cfg(test)] +mod test { + use super::Nid; + + #[test] + fn signature_digest() { + let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); + assert_eq!(algs.digest, Nid::SHA256); + assert_eq!(algs.pkey, Nid::RSAENCRYPTION); + } + + #[test] + fn test_long_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.long_name().unwrap(), "commonName"); + assert_eq!( + organizational_unit_name.long_name().unwrap(), + "organizationalUnitName" + ); + assert_eq!( + aes256_cbc_hmac_sha1.long_name().unwrap(), + "aes-256-cbc-hmac-sha1" + ); + assert_eq!( + id_cmc_lrapopwitness.long_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!( + ms_ctl_sign.long_name().unwrap(), + "Microsoft Trust List Signing" + ); + assert!( + undefined_nid.long_name().is_err(), + "undefined_nid should not return a valid value" + ); + } + + #[test] + fn test_short_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.short_name().unwrap(), "CN"); + assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); + assert_eq!( + aes256_cbc_hmac_sha1.short_name().unwrap(), + "AES-256-CBC-HMAC-SHA1" + ); + assert_eq!( + id_cmc_lrapopwitness.short_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); + assert!( + undefined_nid.short_name().is_err(), + "undefined_nid should not return a valid value" + ); + } +} diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs new file mode 100644 index 000000000..310c3dbe4 --- /dev/null +++ b/openssl/src/ocsp.rs @@ -0,0 +1,351 @@ +use ffi; +use foreign_types::ForeignTypeRef; +use libc::{c_int, c_long, c_ulong}; +use std::mem; +use std::ptr; + +use asn1::Asn1GeneralizedTimeRef; +use error::ErrorStack; +use hash::MessageDigest; +use stack::StackRef; +use x509::store::X509StoreRef; +use x509::{X509Ref, X509}; +use {cvt, cvt_p}; + +bitflags! { + pub struct OcspFlag: c_ulong { + const NO_CERTS = ffi::OCSP_NOCERTS; + const NO_INTERN = ffi::OCSP_NOINTERN; + const NO_CHAIN = ffi::OCSP_NOCHAIN; + const NO_VERIFY = ffi::OCSP_NOVERIFY; + const NO_EXPLICIT = ffi::OCSP_NOEXPLICIT; + const NO_CA_SIGN = ffi::OCSP_NOCASIGN; + const NO_DELEGATED = ffi::OCSP_NODELEGATED; + const NO_CHECKS = ffi::OCSP_NOCHECKS; + const TRUST_OTHER = ffi::OCSP_TRUSTOTHER; + const RESPID_KEY = ffi::OCSP_RESPID_KEY; + const NO_TIME = ffi::OCSP_NOTIME; + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspResponseStatus(c_int); + +impl OcspResponseStatus { + pub fn from_raw(raw: c_int) -> OcspResponseStatus { + OcspResponseStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } + + pub const SUCCESSFUL: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); + pub const MALFORMED_REQUEST: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); + pub const INTERNAL_ERROR: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); + pub const TRY_LATER: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); + pub const SIG_REQUIRED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); + pub const UNAUTHORIZED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspCertStatus(c_int); + +impl OcspCertStatus { + pub fn from_raw(raw: c_int) -> OcspCertStatus { + OcspCertStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } + + pub const GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); + pub const REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); + pub const UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspRevokedStatus(c_int); + +impl OcspRevokedStatus { + pub fn from_raw(raw: c_int) -> OcspRevokedStatus { + OcspRevokedStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } + + pub const NO_STATUS: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); + pub const UNSPECIFIED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); + pub const KEY_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); + pub const CA_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); + pub const AFFILIATION_CHANGED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); + pub const STATUS_SUPERSEDED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); + pub const STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); + pub const STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); + pub const REMOVE_FROM_CRL: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); +} + +pub struct OcspStatus<'a> { + /// The overall status of the response. + pub status: OcspCertStatus, + /// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation. + pub reason: OcspRevokedStatus, + /// If `status` is `CERT_STATUS_REVOKED`, the time at which the certificate was revoked. + pub revocation_time: Option<&'a Asn1GeneralizedTimeRef>, + /// The time that this revocation check was performed. + pub this_update: &'a Asn1GeneralizedTimeRef, + /// The time at which this revocation check expires. + pub next_update: &'a Asn1GeneralizedTimeRef, +} + +impl<'a> OcspStatus<'a> { + /// Checks validity of the `this_update` and `next_update` fields. + /// + /// The `nsec` parameter specifies an amount of slack time that will be used when comparing + /// those times with the current time to account for delays and clock skew. + /// + /// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit + /// very old responses. + pub fn check_validity(&self, nsec: u32, maxsec: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::OCSP_check_validity( + self.this_update.as_ptr(), + self.next_update.as_ptr(), + nsec as c_long, + maxsec.map(|n| n as c_long).unwrap_or(-1), + )) + .map(|_| ()) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::OCSP_BASICRESP; + fn drop = ffi::OCSP_BASICRESP_free; + + pub struct OcspBasicResponse; + pub struct OcspBasicResponseRef; +} + +impl OcspBasicResponseRef { + /// Verifies the validity of the response. + /// + /// The `certs` parameter contains a set of certificates that will be searched when locating the + /// OCSP response signing certificate. Some responders do not include this in the response. + pub fn verify( + &self, + certs: &StackRef, + store: &X509StoreRef, + flags: OcspFlag, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::OCSP_basic_verify( + self.as_ptr(), + certs.as_ptr(), + store.as_ptr(), + flags.bits(), + )) + .map(|_| ()) + } + } + + /// Looks up the status for the specified certificate ID. + pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option> { + unsafe { + let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN; + let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS; + let mut revocation_time = ptr::null_mut(); + let mut this_update = ptr::null_mut(); + let mut next_update = ptr::null_mut(); + + let r = ffi::OCSP_resp_find_status( + self.as_ptr(), + id.as_ptr(), + &mut status, + &mut reason, + &mut revocation_time, + &mut this_update, + &mut next_update, + ); + if r == 1 { + let revocation_time = if revocation_time.is_null() { + None + } else { + Some(Asn1GeneralizedTimeRef::from_ptr(revocation_time)) + }; + Some(OcspStatus { + status: OcspCertStatus(status), + reason: OcspRevokedStatus(status), + revocation_time: revocation_time, + this_update: Asn1GeneralizedTimeRef::from_ptr(this_update), + next_update: Asn1GeneralizedTimeRef::from_ptr(next_update), + }) + } else { + None + } + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::OCSP_CERTID; + fn drop = ffi::OCSP_CERTID_free; + + pub struct OcspCertId; + pub struct OcspCertIdRef; +} + +impl OcspCertId { + /// Constructs a certificate ID for certificate `subject`. + pub fn from_cert( + digest: MessageDigest, + subject: &X509Ref, + issuer: &X509Ref, + ) -> Result { + unsafe { + cvt_p(ffi::OCSP_cert_to_id( + digest.as_ptr(), + subject.as_ptr(), + issuer.as_ptr(), + )) + .map(OcspCertId) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::OCSP_RESPONSE; + fn drop = ffi::OCSP_RESPONSE_free; + + pub struct OcspResponse; + pub struct OcspResponseRef; +} + +impl OcspResponse { + /// Creates an OCSP response from the status and optional body. + /// + /// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`. + pub fn create( + status: OcspResponseStatus, + body: Option<&OcspBasicResponseRef>, + ) -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::OCSP_response_create( + status.as_raw(), + body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()), + )) + .map(OcspResponse) + } + } + + from_der! { + /// Deserializes a DER-encoded OCSP response. + /// + /// This corresponds to [`d2i_OCSP_RESPONSE`]. + /// + /// [`d2i_OCSP_RESPONSE`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_OCSP_RESPONSE.html + from_der, + OcspResponse, + ffi::d2i_OCSP_RESPONSE + } +} + +impl OcspResponseRef { + to_der! { + /// Serializes the response to its standard DER encoding. + /// + /// This corresponds to [`i2d_OCSP_RESPONSE`]. + /// + /// [`i2d_OCSP_RESPONSE`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_OCSP_RESPONSE.html + to_der, + ffi::i2d_OCSP_RESPONSE + } + + /// Returns the status of the response. + pub fn status(&self) -> OcspResponseStatus { + unsafe { OcspResponseStatus(ffi::OCSP_response_status(self.as_ptr())) } + } + + /// Returns the basic response. + /// + /// This will only succeed if `status()` returns `RESPONSE_STATUS_SUCCESSFUL`. + pub fn basic(&self) -> Result { + unsafe { cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::OCSP_REQUEST; + fn drop = ffi::OCSP_REQUEST_free; + + pub struct OcspRequest; + pub struct OcspRequestRef; +} + +impl OcspRequest { + pub fn new() -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest) + } + } + + from_der! { + /// Deserializes a DER-encoded OCSP request. + /// + /// This corresponds to [`d2i_OCSP_REQUEST`]. + /// + /// [`d2i_OCSP_REQUEST`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_OCSP_REQUEST.html + from_der, + OcspRequest, + ffi::d2i_OCSP_REQUEST + } +} + +impl OcspRequestRef { + to_der! { + /// Serializes the request to its standard DER encoding. + /// + /// This corresponds to [`i2d_OCSP_REQUEST`]. + /// + /// [`i2d_OCSP_REQUEST`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_OCSP_REQUEST.html + to_der, + ffi::i2d_OCSP_REQUEST + } + + pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> { + unsafe { + let ptr = cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr()))?; + mem::forget(id); + Ok(OcspOneReqRef::from_ptr_mut(ptr)) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::OCSP_ONEREQ; + fn drop = ffi::OCSP_ONEREQ_free; + + pub struct OcspOneReq; + pub struct OcspOneReqRef; +} diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs new file mode 100644 index 000000000..f01a9b22a --- /dev/null +++ b/openssl/src/pkcs12.rs @@ -0,0 +1,289 @@ +//! PKCS #12 archives. + +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::ffi::CString; +use std::ptr; + +use error::ErrorStack; +use nid::Nid; +use pkey::{HasPrivate, PKey, PKeyRef, Private}; +use stack::Stack; +use x509::{X509Ref, X509}; +use {cvt, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::PKCS12; + fn drop = ffi::PKCS12_free; + + pub struct Pkcs12; + pub struct Pkcs12Ref; +} + +impl Pkcs12Ref { + to_der! { + /// Serializes the `Pkcs12` to its standard DER encoding. + /// + /// This corresponds to [`i2d_PKCS12`]. + /// + /// [`i2d_PKCS12`]: https://www.openssl.org/docs/manmaster/man3/i2d_PKCS12.html + to_der, + ffi::i2d_PKCS12 + } + + /// Extracts the contents of the `Pkcs12`. + pub fn parse(&self, pass: &str) -> Result { + unsafe { + let pass = CString::new(pass.as_bytes()).unwrap(); + + let mut pkey = ptr::null_mut(); + let mut cert = ptr::null_mut(); + let mut chain = ptr::null_mut(); + + cvt(ffi::PKCS12_parse( + self.as_ptr(), + pass.as_ptr(), + &mut pkey, + &mut cert, + &mut chain, + ))?; + + let pkey = PKey::from_ptr(pkey); + let cert = X509::from_ptr(cert); + + let chain = if chain.is_null() { + None + } else { + Some(Stack::from_ptr(chain)) + }; + + Ok(ParsedPkcs12 { + pkey: pkey, + cert: cert, + chain: chain, + }) + } + } +} + +impl Pkcs12 { + from_der! { + /// Deserializes a DER-encoded PKCS#12 archive. + /// + /// This corresponds to [`d2i_PKCS12`]. + /// + /// [`d2i_PKCS12`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PKCS12.html + from_der, + Pkcs12, + ffi::d2i_PKCS12 + } + + /// Creates a new builder for a protected pkcs12 certificate. + /// + /// This uses the defaults from the OpenSSL library: + /// + /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` + /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` + /// * `iter` - `2048` + /// * `mac_iter` - `2048` + pub fn builder() -> Pkcs12Builder { + ffi::init(); + + Pkcs12Builder { + nid_key: Nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, + nid_cert: Nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, + iter: ffi::PKCS12_DEFAULT_ITER, + mac_iter: ffi::PKCS12_DEFAULT_ITER, + ca: None, + } + } +} + +pub struct ParsedPkcs12 { + pub pkey: PKey, + pub cert: X509, + pub chain: Option>, +} + +pub struct Pkcs12Builder { + nid_key: Nid, + nid_cert: Nid, + iter: c_int, + mac_iter: c_int, + ca: Option>, +} + +impl Pkcs12Builder { + /// The encryption algorithm that should be used for the key + pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self { + self.nid_key = nid; + self + } + + /// The encryption algorithm that should be used for the cert + pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self { + self.nid_cert = nid; + self + } + + /// Key iteration count, default is 2048 as of this writing + pub fn key_iter(&mut self, iter: u32) -> &mut Self { + self.iter = iter as c_int; + self + } + + /// MAC iteration count, default is the same as key_iter. + /// + /// Old implementations don't understand MAC iterations greater than 1, (pre 1.0.1?), if such + /// compatibility is required this should be set to 1. + pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self { + self.mac_iter = mac_iter as c_int; + self + } + + /// An additional set of certificates to include in the archive beyond the one provided to + /// `build`. + pub fn ca(&mut self, ca: Stack) -> &mut Self { + self.ca = Some(ca); + self + } + + /// Builds the PKCS #12 object + /// + /// # Arguments + /// + /// * `password` - the password used to encrypt the key and certificate + /// * `friendly_name` - user defined name for the certificate + /// * `pkey` - key to store + /// * `cert` - certificate to store + pub fn build( + self, + password: &str, + friendly_name: &str, + pkey: &PKeyRef, + cert: &X509Ref, + ) -> Result + where + T: HasPrivate, + { + unsafe { + let pass = CString::new(password).unwrap(); + let friendly_name = CString::new(friendly_name).unwrap(); + let pkey = pkey.as_ptr(); + let cert = cert.as_ptr(); + let ca = self + .ca + .as_ref() + .map(|ca| ca.as_ptr()) + .unwrap_or(ptr::null_mut()); + let nid_key = self.nid_key.as_raw(); + let nid_cert = self.nid_cert.as_raw(); + + // According to the OpenSSL docs, keytype is a non-standard extension for MSIE, + // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information: + // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html + let keytype = 0; + + cvt_p(ffi::PKCS12_create( + pass.as_ptr() as *const _ as *mut _, + friendly_name.as_ptr() as *const _ as *mut _, + pkey, + cert, + ca, + nid_key, + nid_cert, + self.iter, + self.mac_iter, + keytype, + )) + .map(Pkcs12) + } + } +} + +#[cfg(test)] +mod test { + use hash::MessageDigest; + use hex; + + use asn1::Asn1Time; + use nid::Nid; + use pkey::PKey; + use rsa::Rsa; + use x509::extension::KeyUsage; + use x509::{X509Name, X509}; + + use super::*; + + #[test] + fn parse() { + let der = include_bytes!("../test/identity.p12"); + let pkcs12 = Pkcs12::from_der(der).unwrap(); + let parsed = pkcs12.parse("mypass").unwrap(); + + assert_eq!( + hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()), + "59172d9313e84459bcff27f967e79e6e9217e584" + ); + + let chain = parsed.chain.unwrap(); + assert_eq!(chain.len(), 1); + assert_eq!( + hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), + "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" + ); + } + + #[test] + fn parse_empty_chain() { + let der = include_bytes!("../test/keystore-empty-chain.p12"); + let pkcs12 = Pkcs12::from_der(der).unwrap(); + let parsed = pkcs12.parse("cassandra").unwrap(); + assert!(parsed.chain.is_none()); + } + + #[test] + fn create() { + let subject_name = "ns.example.com"; + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, subject_name) + .unwrap(); + let name = name.build(); + + let key_usage = KeyUsage::new().digital_signature().build().unwrap(); + + let mut builder = X509::builder().unwrap(); + builder.set_version(2).unwrap(); + builder + .set_not_before(&Asn1Time::days_from_now(0).unwrap()) + .unwrap(); + builder + .set_not_after(&Asn1Time::days_from_now(365).unwrap()) + .unwrap(); + builder.set_subject_name(&name).unwrap(); + builder.set_issuer_name(&name).unwrap(); + builder.append_extension(key_usage).unwrap(); + builder.set_pubkey(&pkey).unwrap(); + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + let cert = builder.build(); + + let pkcs12_builder = Pkcs12::builder(); + let pkcs12 = pkcs12_builder + .build("mypass", subject_name, &pkey, &cert) + .unwrap(); + let der = pkcs12.to_der().unwrap(); + + let pkcs12 = Pkcs12::from_der(&der).unwrap(); + let parsed = pkcs12.parse("mypass").unwrap(); + + assert_eq!( + &*parsed.cert.digest(MessageDigest::sha1()).unwrap(), + &*cert.digest(MessageDigest::sha1()).unwrap() + ); + assert!(parsed.pkey.public_eq(&pkey)); + } +} diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs new file mode 100644 index 000000000..d9704b51a --- /dev/null +++ b/openssl/src/pkcs5.rs @@ -0,0 +1,304 @@ +use ffi; +use libc::c_int; +use std::ptr; + +use cvt; +use error::ErrorStack; +use hash::MessageDigest; +use symm::Cipher; + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub struct KeyIvPair { + pub key: Vec, + pub iv: Option>, +} + +/// Derives a key and an IV from various parameters. +/// +/// If specified, `salt` must be 8 bytes in length. +/// +/// If the total key and IV length is less than 16 bytes and MD5 is used then +/// the algorithm is compatible with the key derivation algorithm from PKCS#5 +/// v1.5 or PBKDF1 from PKCS#5 v2.0. +/// +/// New applications should not use this and instead use +/// `pbkdf2_hmac` or another more modern key derivation algorithm. +pub fn bytes_to_key( + cipher: Cipher, + digest: MessageDigest, + data: &[u8], + salt: Option<&[u8]>, + count: i32, +) -> Result { + unsafe { + assert!(data.len() <= c_int::max_value() as usize); + let salt_ptr = match salt { + Some(salt) => { + assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize); + salt.as_ptr() + } + None => ptr::null(), + }; + + ffi::init(); + + let mut iv = cipher.iv_len().map(|l| vec![0; l]); + + let cipher = cipher.as_ptr(); + let digest = digest.as_ptr(); + + let len = cvt(ffi::EVP_BytesToKey( + cipher, + digest, + salt_ptr, + ptr::null(), + data.len() as c_int, + count.into(), + ptr::null_mut(), + ptr::null_mut(), + ))?; + + let mut key = vec![0; len as usize]; + let iv_ptr = iv + .as_mut() + .map(|v| v.as_mut_ptr()) + .unwrap_or(ptr::null_mut()); + + cvt(ffi::EVP_BytesToKey( + cipher, + digest, + salt_ptr, + data.as_ptr(), + data.len() as c_int, + count as c_int, + key.as_mut_ptr(), + iv_ptr, + ))?; + + Ok(KeyIvPair { key: key, iv: iv }) + } +} + +/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. +pub fn pbkdf2_hmac( + pass: &[u8], + salt: &[u8], + iter: usize, + hash: MessageDigest, + key: &mut [u8], +) -> Result<(), ErrorStack> { + unsafe { + assert!(pass.len() <= c_int::max_value() as usize); + assert!(salt.len() <= c_int::max_value() as usize); + assert!(key.len() <= c_int::max_value() as usize); + + ffi::init(); + cvt(ffi::PKCS5_PBKDF2_HMAC( + pass.as_ptr() as *const _, + pass.len() as c_int, + salt.as_ptr(), + salt.len() as c_int, + iter as c_int, + hash.as_ptr(), + key.len() as c_int, + key.as_mut_ptr(), + )) + .map(|_| ()) + } +} + +/// Derives a key from a password and salt using the scrypt algorithm. +/// +/// Requires OpenSSL 1.1.0 or newer. +#[cfg(any(ossl110))] +pub fn scrypt( + pass: &[u8], + salt: &[u8], + n: u64, + r: u64, + p: u64, + maxmem: u64, + key: &mut [u8], +) -> Result<(), ErrorStack> { + unsafe { + ffi::init(); + cvt(ffi::EVP_PBE_scrypt( + pass.as_ptr() as *const _, + pass.len(), + salt.as_ptr() as *const _, + salt.len(), + n, + r, + p, + maxmem, + key.as_mut_ptr() as *mut _, + key.len(), + )) + .map(|_| ()) + } +} + +#[cfg(test)] +mod tests { + use hash::MessageDigest; + use symm::Cipher; + + // Test vectors from + // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c + #[test] + fn pbkdf2_hmac_sha256() { + let mut buf = [0; 16]; + + super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap(); + assert_eq!( + buf, + &[ + 0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, 0xec_u8, + 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8, + ][..] + ); + + super::pbkdf2_hmac( + b"Password", + b"NaCl", + 80000, + MessageDigest::sha256(), + &mut buf, + ) + .unwrap(); + assert_eq!( + buf, + &[ + 0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, 0x83_u8, + 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8, + ][..] + ); + } + + // Test vectors from + // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c + #[test] + fn pbkdf2_hmac_sha512() { + let mut buf = [0; 64]; + + super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap(); + assert_eq!( + &buf[..], + &[ + 0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, 0x94_u8, + 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8, + 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8, + 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, + 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, + 0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, + 0x5e_u8, 0x9f_u8, 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, + 0x06_u8, + ][..] + ); + + super::pbkdf2_hmac( + b"pass\0word", + b"sa\0lt", + 1, + MessageDigest::sha512(), + &mut buf, + ) + .unwrap(); + assert_eq!( + &buf[..], + &[ + 0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, 0x8b_u8, + 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8, + 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8, + 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, + 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, + 0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, + 0x5a_u8, 0xb5_u8, 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, + 0xa7_u8, + ][..] + ); + + super::pbkdf2_hmac( + b"passwordPASSWORDpassword", + b"salt\0\0\0", + 50, + MessageDigest::sha512(), + &mut buf, + ) + .unwrap(); + assert_eq!( + &buf[..], + &[ + 0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, 0x85_u8, + 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8, + 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8, + 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, + 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, + 0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, + 0x4b_u8, 0x1a_u8, 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, + 0x39_u8, + ][..] + ); + } + + #[test] + fn bytes_to_key() { + let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; + + let data = [ + 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, + 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, + 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, + ]; + + let expected_key = vec![ + 249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8, 87_u8, 234_u8, + 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, + 229_u8, 161_u8, 183_u8, 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8, + ]; + let expected_iv = vec![ + 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, + 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, + ]; + + assert_eq!( + super::bytes_to_key( + Cipher::aes_256_cbc(), + MessageDigest::sha1(), + &data, + Some(&salt), + 1, + ) + .unwrap(), + super::KeyIvPair { + key: expected_key, + iv: Some(expected_iv), + } + ); + } + + #[test] + #[cfg(any(ossl110))] + fn scrypt() { + use hex; + + let pass = "pleaseletmein"; + let salt = "SodiumChloride"; + let expected = + "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\ + f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"; + + let mut actual = [0; 64]; + super::scrypt( + pass.as_bytes(), + salt.as_bytes(), + 16384, + 8, + 1, + 0, + &mut actual, + ) + .unwrap(); + assert_eq!(hex::encode(&actual[..]), expected); + } +} diff --git a/openssl/src/pkcs7.rs b/openssl/src/pkcs7.rs new file mode 100644 index 000000000..7cb39f779 --- /dev/null +++ b/openssl/src/pkcs7.rs @@ -0,0 +1,389 @@ +use bio::{MemBio, MemBioSlice}; +use error::ErrorStack; +use ffi; +use foreign_types::ForeignTypeRef; +use libc::c_int; +use pkey::{HasPrivate, PKeyRef}; +use stack::StackRef; +use std::ptr; +use symm::Cipher; +use x509::store::X509StoreRef; +use x509::{X509Ref, X509}; +use {cvt, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::PKCS7; + fn drop = ffi::PKCS7_free; + + /// A PKCS#7 structure. + /// + /// Contains signed and/or encrypted data. + pub struct Pkcs7; + + /// Reference to `Pkcs7` + pub struct Pkcs7Ref; +} + +bitflags! { + pub struct Pkcs7Flags: c_int { + const TEXT = ffi::PKCS7_TEXT; + const NOCERTS = ffi::PKCS7_NOCERTS; + const NOSIGS = ffi::PKCS7_NOSIGS; + const NOCHAIN = ffi::PKCS7_NOCHAIN; + const NOINTERN = ffi::PKCS7_NOINTERN; + const NOVERIFY = ffi::PKCS7_NOVERIFY; + const DETACHED = ffi::PKCS7_DETACHED; + const BINARY = ffi::PKCS7_BINARY; + const NOATTR = ffi::PKCS7_NOATTR; + const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP; + const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE; + const CRLFEOL = ffi::PKCS7_CRLFEOL; + const STREAM = ffi::PKCS7_STREAM; + const NOCRL = ffi::PKCS7_NOCRL; + const PARTIAL = ffi::PKCS7_PARTIAL; + const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST; + #[cfg(not(any(ossl101, ossl102, libressl)))] + const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT; + } +} + +impl Pkcs7 { + from_pem! { + /// Deserializes a PEM-encoded PKCS#7 signature + /// + /// The input should have a header of `-----BEGIN PKCS7-----`. + /// + /// This corresponds to [`PEM_read_bio_PKCS7`]. + /// + /// [`PEM_read_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PKCS7.html + from_pem, + Pkcs7, + ffi::PEM_read_bio_PKCS7 + } + + /// Parses a message in S/MIME format. + /// + /// Returns the loaded signature, along with the cleartext message (if + /// available). + /// + /// This corresponds to [`SMIME_read_PKCS7`]. + /// + /// [`SMIME_read_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_read_PKCS7.html + pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option>), ErrorStack> { + ffi::init(); + + let input_bio = MemBioSlice::new(input)?; + let mut bcont_bio = ptr::null_mut(); + unsafe { + let pkcs7 = + cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio)).map(Pkcs7)?; + let out = if !bcont_bio.is_null() { + let bcont_bio = MemBio::from_ptr(bcont_bio); + Some(bcont_bio.get_buf().to_vec()) + } else { + None + }; + Ok((pkcs7, out)) + } + } + + /// Creates and returns a PKCS#7 `envelopedData` structure. + /// + /// `certs` is a list of recipient certificates. `input` is the content to be + /// encrypted. `cipher` is the symmetric cipher to use. `flags` is an optional + /// set of flags. + /// + /// This corresponds to [`PKCS7_encrypt`]. + /// + /// [`PKCS7_encrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_encrypt.html + pub fn encrypt( + certs: &StackRef, + input: &[u8], + cipher: Cipher, + flags: Pkcs7Flags, + ) -> Result { + let input_bio = MemBioSlice::new(input)?; + + unsafe { + cvt_p(ffi::PKCS7_encrypt( + certs.as_ptr(), + input_bio.as_ptr(), + cipher.as_ptr(), + flags.bits, + )) + .map(Pkcs7) + } + } + + /// Creates and returns a PKCS#7 `signedData` structure. + /// + /// `signcert` is the certificate to sign with, `pkey` is the corresponding + /// private key. `certs` is an optional additional set of certificates to + /// include in the PKCS#7 structure (for example any intermediate CAs in the + /// chain). + /// + /// This corresponds to [`PKCS7_sign`]. + /// + /// [`PKCS7_sign`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_sign.html + pub fn sign( + signcert: &X509Ref, + pkey: &PKeyRef, + certs: &StackRef, + input: &[u8], + flags: Pkcs7Flags, + ) -> Result + where + PT: HasPrivate, + { + let input_bio = MemBioSlice::new(input)?; + unsafe { + cvt_p(ffi::PKCS7_sign( + signcert.as_ptr(), + pkey.as_ptr(), + certs.as_ptr(), + input_bio.as_ptr(), + flags.bits, + )) + .map(Pkcs7) + } + } +} + +impl Pkcs7Ref { + /// Converts PKCS#7 structure to S/MIME format + /// + /// This corresponds to [`SMIME_write_PKCS7`]. + /// + /// [`SMIME_write_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_write_PKCS7.html + pub fn to_smime(&self, input: &[u8], flags: Pkcs7Flags) -> Result, ErrorStack> { + let input_bio = MemBioSlice::new(input)?; + let output = MemBio::new()?; + unsafe { + cvt(ffi::SMIME_write_PKCS7( + output.as_ptr(), + self.as_ptr(), + input_bio.as_ptr(), + flags.bits, + )) + .map(|_| output.get_buf().to_owned()) + } + } + + to_pem! { + /// Serializes the data into a PEM-encoded PKCS#7 structure. + /// + /// The output will have a header of `-----BEGIN PKCS7-----`. + /// + /// This corresponds to [`PEM_write_bio_PKCS7`]. + /// + /// [`PEM_write_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS7.html + to_pem, + ffi::PEM_write_bio_PKCS7 + } + + /// Decrypts data using the provided private key. + /// + /// `pkey` is the recipient's private key, and `cert` is the recipient's + /// certificate. + /// + /// Returns the decrypted message. + /// + /// This corresponds to [`PKCS7_decrypt`]. + /// + /// [`PKCS7_decrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_decrypt.html + pub fn decrypt( + &self, + pkey: &PKeyRef, + cert: &X509Ref, + flags: Pkcs7Flags, + ) -> Result, ErrorStack> + where + PT: HasPrivate, + { + let output = MemBio::new()?; + + unsafe { + cvt(ffi::PKCS7_decrypt( + self.as_ptr(), + pkey.as_ptr(), + cert.as_ptr(), + output.as_ptr(), + flags.bits, + )) + .map(|_| output.get_buf().to_owned()) + } + } + + /// Verifies the PKCS#7 `signedData` structure contained by `&self`. + /// + /// `certs` is a set of certificates in which to search for the signer's + /// certificate. `store` is a trusted certificate store (used for chain + /// verification). `indata` is the signed data if the content is not present + /// in `&self`. The content is written to `out` if it is not `None`. + /// + /// This corresponds to [`PKCS7_verify`]. + /// + /// [`PKCS7_verify`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_verify.html + pub fn verify( + &self, + certs: &StackRef, + store: &X509StoreRef, + indata: Option<&[u8]>, + out: Option<&mut Vec>, + flags: Pkcs7Flags, + ) -> Result<(), ErrorStack> { + let out_bio = MemBio::new()?; + + let indata_bio = match indata { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, + }; + let indata_bio_ptr = indata_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + + unsafe { + cvt(ffi::PKCS7_verify( + self.as_ptr(), + certs.as_ptr(), + store.as_ptr(), + indata_bio_ptr, + out_bio.as_ptr(), + flags.bits, + )) + .map(|_| ())? + } + + if let Some(data) = out { + data.clear(); + data.extend_from_slice(out_bio.get_buf()); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use pkcs7::{Pkcs7, Pkcs7Flags}; + use pkey::PKey; + use stack::Stack; + use symm::Cipher; + use x509::store::X509StoreBuilder; + use x509::X509; + + #[test] + fn encrypt_decrypt_test() { + let cert = include_bytes!("../test/certs.pem"); + let cert = X509::from_pem(cert).unwrap(); + let mut certs = Stack::new().unwrap(); + certs.push(cert.clone()).unwrap(); + let message: String = String::from("foo"); + let cypher = Cipher::des_ede3_cbc(); + let flags = Pkcs7Flags::STREAM; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + + let pkcs7 = + Pkcs7::encrypt(&certs, message.as_bytes(), cypher, flags).expect("should succeed"); + + let encrypted = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + + let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed"); + + let decoded = pkcs7_decoded + .decrypt(&pkey, &cert, Pkcs7Flags::empty()) + .expect("should succeed"); + + assert_eq!(decoded, message.into_bytes()); + } + + #[test] + fn sign_verify_test_detached() { + let cert = include_bytes!("../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let certs = Stack::new().unwrap(); + let message: String = String::from("foo"); + let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + let root_ca = include_bytes!("../test/root-ca.pem"); + let root_ca = X509::from_pem(root_ca).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + + let store = store_builder.build(); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + println!("{:?}", String::from_utf8(signed.clone()).unwrap()); + let (pkcs7_decoded, content) = + Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); + + let mut output = Vec::new(); + pkcs7_decoded + .verify( + &certs, + &store, + Some(message.as_bytes()), + Some(&mut output), + flags, + ) + .expect("should succeed"); + + assert_eq!(message.clone().into_bytes(), output); + assert_eq!( + message.clone().into_bytes(), + content.expect("should be non-empty") + ); + } + + #[test] + fn sign_verify_test_normal() { + let cert = include_bytes!("../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let certs = Stack::new().unwrap(); + let message: String = String::from("foo"); + let flags = Pkcs7Flags::STREAM; + let pkey = include_bytes!("../test/key.pem"); + let pkey = PKey::private_key_from_pem(pkey).unwrap(); + let mut store_builder = X509StoreBuilder::new().expect("should succeed"); + + let root_ca = include_bytes!("../test/root-ca.pem"); + let root_ca = X509::from_pem(root_ca).unwrap(); + store_builder.add_cert(root_ca).expect("should succeed"); + + let store = store_builder.build(); + + let pkcs7 = + Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); + + let signed = pkcs7 + .to_smime(message.as_bytes(), flags) + .expect("should succeed"); + + let (pkcs7_decoded, content) = + Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); + + let mut output = Vec::new(); + pkcs7_decoded + .verify(&certs, &store, None, Some(&mut output), flags) + .expect("should succeed"); + + assert_eq!(message.clone().into_bytes(), output); + assert!(content.is_none()); + } + + #[test] + fn invalid_from_smime() { + let input = String::from("Invalid SMIME Message"); + let result = Pkcs7::from_smime(input.as_bytes()); + + assert_eq!(result.is_err(), true) + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs new file mode 100644 index 000000000..0b562d748 --- /dev/null +++ b/openssl/src/pkey.rs @@ -0,0 +1,663 @@ +//! Public/private key processing. +//! +//! Asymmetric public key algorithms solve the problem of establishing and sharing +//! secret keys to securely send and receive messages. +//! This system uses a pair of keys: a public key, which can be freely +//! distributed, and a private key, which is kept to oneself. An entity may +//! encrypt information using a user's public key. The encrypted information can +//! only be deciphered using that user's private key. +//! +//! This module offers support for five popular algorithms: +//! +//! * RSA +//! +//! * DSA +//! +//! * Diffie-Hellman +//! +//! * Elliptic Curves +//! +//! * HMAC +//! +//! These algorithms rely on hard mathematical problems - namely integer factorization, +//! discrete logarithms, and elliptic curve relationships - that currently do not +//! yield efficient solutions. This property ensures the security of these +//! cryptographic algorithms. +//! +//! # Example +//! +//! Generate a 2048-bit RSA public/private key pair and print the public key. +//! +//! ```rust +//! +//! extern crate openssl; +//! +//! use openssl::rsa::Rsa; +//! use openssl::pkey::PKey; +//! use std::str; +//! +//! fn main() { +//! let rsa = Rsa::generate(2048).unwrap(); +//! let pkey = PKey::from_rsa(rsa).unwrap(); +//! +//! let pub_key: Vec = pkey.public_key_to_pem().unwrap(); +//! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap()); +//! } +//! ``` + +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::ffi::CString; +use std::mem; +use std::ptr; + +use bio::MemBioSlice; +use dh::Dh; +use dsa::Dsa; +use ec::EcKey; +use error::ErrorStack; +use rsa::Rsa; +use util::{invoke_passwd_cb, CallbackState}; +use {cvt, cvt_p}; + +/// A tag type indicating that a key only has parameters. +pub enum Params {} + +/// A tag type indicating that a key only has public components. +pub enum Public {} + +/// A tag type indicating that a key has private components. +pub enum Private {} + +/// An identifier of a kind of key. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Id(c_int); + +impl Id { + /// Creates a `Id` from an integer representation. + pub fn from_raw(value: c_int) -> Id { + Id(value) + } + + /// Returns the integer representation of the `Id`. + pub fn as_raw(&self) -> c_int { + self.0 + } + + pub const RSA: Id = Id(ffi::EVP_PKEY_RSA); + pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC); + pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); + pub const DH: Id = Id(ffi::EVP_PKEY_DH); + pub const EC: Id = Id(ffi::EVP_PKEY_EC); +} + +/// A trait indicating that a key has parameters. +pub unsafe trait HasParams {} + +unsafe impl HasParams for Params {} + +unsafe impl HasParams for T where T: HasPublic {} + +/// A trait indicating that a key has public components. +pub unsafe trait HasPublic {} + +unsafe impl HasPublic for Public {} + +unsafe impl HasPublic for T where T: HasPrivate {} + +/// A trait indicating that a key has private components. +pub unsafe trait HasPrivate {} + +unsafe impl HasPrivate for Private {} + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_PKEY; + fn drop = ffi::EVP_PKEY_free; + + /// A public or private key. + pub struct PKey; + /// Reference to `PKey`. + pub struct PKeyRef; +} + +impl PKeyRef { + /// Returns a copy of the internal RSA key. + /// + /// This corresponds to [`EVP_PKEY_get1_RSA`]. + /// + /// [`EVP_PKEY_get1_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_RSA.html + pub fn rsa(&self) -> Result, ErrorStack> { + unsafe { + let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?; + Ok(Rsa::from_ptr(rsa)) + } + } + + /// Returns a copy of the internal DSA key. + /// + /// This corresponds to [`EVP_PKEY_get1_DSA`]. + /// + /// [`EVP_PKEY_get1_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DSA.html + pub fn dsa(&self) -> Result, ErrorStack> { + unsafe { + let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?; + Ok(Dsa::from_ptr(dsa)) + } + } + + /// Returns a copy of the internal DH key. + /// + /// This corresponds to [`EVP_PKEY_get1_DH`]. + /// + /// [`EVP_PKEY_get1_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DH.html + pub fn dh(&self) -> Result, ErrorStack> { + unsafe { + let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?; + Ok(Dh::from_ptr(dh)) + } + } + + /// Returns a copy of the internal elliptic curve key. + /// + /// This corresponds to [`EVP_PKEY_get1_EC_KEY`]. + /// + /// [`EVP_PKEY_get1_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_EC_KEY.html + pub fn ec_key(&self) -> Result, ErrorStack> { + unsafe { + let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?; + Ok(EcKey::from_ptr(ec_key)) + } + } + + /// Returns the `Id` that represents the type of this key. + /// + /// This corresponds to [`EVP_PKEY_id`]. + /// + /// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html + pub fn id(&self) -> Id { + unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) } + } + + /// Returns the maximum size of a signature in bytes. + /// + /// This corresponds to [`EVP_PKEY_size`]. + /// + /// [`EVP_PKEY_size`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_size.html + pub fn size(&self) -> usize { + unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize } + } +} + +impl PKeyRef +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_PUBKEY`]. + /// + /// [`PEM_write_bio_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PUBKEY.html + public_key_to_pem, + ffi::PEM_write_bio_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + /// + /// This corresponds to [`i2d_PUBKEY`]. + /// + /// [`i2d_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_PUBKEY.html + public_key_to_der, + ffi::i2d_PUBKEY + } + + /// Returns the size of the key. + /// + /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the + /// group order for an elliptic curve key, for example. + pub fn bits(&self) -> u32 { + unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } + } + + /// Compares the public component of this key with another. + pub fn public_eq(&self, other: &PKeyRef) -> bool + where + U: HasPublic, + { + unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } + } +} + +impl PKeyRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. + /// + /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html + private_key_to_pem_pkcs8, + /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. + /// + /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html + private_key_to_pem_pkcs8_passphrase, + ffi::PEM_write_bio_PKCS8PrivateKey + } + + to_der! { + /// Serializes the private key to a DER-encoded key type specific format. + /// + /// This corresponds to [`i2d_PrivateKey`]. + /// + /// [`i2d_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_PrivateKey.html + private_key_to_der, + ffi::i2d_PrivateKey + } +} + +impl PKey { + /// Creates a new `PKey` containing an RSA key. + /// + /// This corresponds to [`EVP_PKEY_assign_RSA`]. + /// + /// [`EVP_PKEY_assign_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_RSA.html + pub fn from_rsa(rsa: Rsa) -> Result, ErrorStack> { + unsafe { + let evp = cvt_p(ffi::EVP_PKEY_new())?; + let pkey = PKey::from_ptr(evp); + cvt(ffi::EVP_PKEY_assign( + pkey.0, + ffi::EVP_PKEY_RSA, + rsa.as_ptr() as *mut _, + ))?; + mem::forget(rsa); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing a DSA key. + /// + /// This corresponds to [`EVP_PKEY_assign_DSA`]. + /// + /// [`EVP_PKEY_assign_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DSA.html + pub fn from_dsa(dsa: Dsa) -> Result, ErrorStack> { + unsafe { + let evp = cvt_p(ffi::EVP_PKEY_new())?; + let pkey = PKey::from_ptr(evp); + cvt(ffi::EVP_PKEY_assign( + pkey.0, + ffi::EVP_PKEY_DSA, + dsa.as_ptr() as *mut _, + ))?; + mem::forget(dsa); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing a Diffie-Hellman key. + /// + /// This corresponds to [`EVP_PKEY_assign_DH`]. + /// + /// [`EVP_PKEY_assign_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DH.html + pub fn from_dh(dh: Dh) -> Result, ErrorStack> { + unsafe { + let evp = cvt_p(ffi::EVP_PKEY_new())?; + let pkey = PKey::from_ptr(evp); + cvt(ffi::EVP_PKEY_assign( + pkey.0, + ffi::EVP_PKEY_DH, + dh.as_ptr() as *mut _, + ))?; + mem::forget(dh); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing an elliptic curve key. + /// + /// This corresponds to [`EVP_PKEY_assign_EC_KEY`]. + /// + /// [`EVP_PKEY_assign_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_EC_KEY.html + pub fn from_ec_key(ec_key: EcKey) -> Result, ErrorStack> { + unsafe { + let evp = cvt_p(ffi::EVP_PKEY_new())?; + let pkey = PKey::from_ptr(evp); + cvt(ffi::EVP_PKEY_assign( + pkey.0, + ffi::EVP_PKEY_EC, + ec_key.as_ptr() as *mut _, + ))?; + mem::forget(ec_key); + Ok(pkey) + } + } +} + +impl PKey { + /// Creates a new `PKey` containing an HMAC key. + /// + /// # Note + /// + /// To compute HMAC values, use the `sign` module. + pub fn hmac(key: &[u8]) -> Result, ErrorStack> { + unsafe { + assert!(key.len() <= c_int::max_value() as usize); + let key = cvt_p(ffi::EVP_PKEY_new_mac_key( + ffi::EVP_PKEY_HMAC, + ptr::null_mut(), + key.as_ptr() as *const _, + key.len() as c_int, + ))?; + Ok(PKey::from_ptr(key)) + } + } + + /// Creates a new `PKey` containing a CMAC key. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// # Note + /// + /// To compute CMAC values, use the `sign` module. + #[cfg(ossl110)] + pub fn cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result, ErrorStack> { + unsafe { + assert!(key.len() <= c_int::max_value() as usize); + let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id( + ffi::EVP_PKEY_CMAC, + ptr::null_mut(), + ))?; + + let ret = (|| { + cvt(ffi::EVP_PKEY_keygen_init(kctx))?; + + // Set cipher for cmac + cvt(ffi::EVP_PKEY_CTX_ctrl( + kctx, + -1, + ffi::EVP_PKEY_OP_KEYGEN, + ffi::EVP_PKEY_CTRL_CIPHER, + 0, + cipher.as_ptr() as *mut _, + ))?; + + // Set the key data + cvt(ffi::EVP_PKEY_CTX_ctrl( + kctx, + -1, + ffi::EVP_PKEY_OP_KEYGEN, + ffi::EVP_PKEY_CTRL_SET_MAC_KEY, + key.len() as c_int, + key.as_ptr() as *mut _, + ))?; + Ok(()) + })(); + + if let Err(e) = ret { + // Free memory + ffi::EVP_PKEY_CTX_free(kctx); + return Err(e); + } + + // Generate key + let mut key = ptr::null_mut(); + let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key)); + + // Free memory + ffi::EVP_PKEY_CTX_free(kctx); + + if let Err(e) = ret { + return Err(e); + } + + Ok(PKey::from_ptr(key)) + } + } + + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded key type specific format. + /// + /// This corresponds to [`PEM_read_bio_PrivateKey`]. + /// + /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted key type specific format. + /// + /// This corresponds to [`PEM_read_bio_PrivateKey`]. + /// + /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted key type specific format. + /// + /// The callback should fill the password into the provided buffer and return its length. + /// + /// This corresponds to [`PEM_read_bio_PrivateKey`]. + /// + /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + private_key_from_pem_callback, + PKey, + ffi::PEM_read_bio_PrivateKey + } + + from_der! { + /// Decodes a DER-encoded private key. + /// + /// This function will automatically attempt to detect the underlying key format, and + /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific + /// formats. + /// + /// This corresponds to [`d2i_AutoPrivateKey`]. + /// + /// [`d2i_AutoPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_AutoPrivateKey.html + private_key_from_der, + PKey, + ffi::d2i_AutoPrivateKey + } + + /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password + /// if the key is encrpyted. + /// + /// The callback should copy the password into the provided buffer and return the number of + /// bytes written. + pub fn private_key_from_pkcs8_callback( + der: &[u8], + callback: F, + ) -> Result, ErrorStack> + where + F: FnOnce(&mut [u8]) -> Result, + { + unsafe { + ffi::init(); + let mut cb = CallbackState::new(callback); + let bio = MemBioSlice::new(der)?; + cvt_p(ffi::d2i_PKCS8PrivateKey_bio( + bio.as_ptr(), + ptr::null_mut(), + Some(invoke_passwd_cb::), + &mut cb as *mut _ as *mut _, + )) + .map(|p| PKey::from_ptr(p)) + } + } + + /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is + /// encrypted. + /// + /// # Panics + /// + /// Panics if `passphrase` contains an embedded null. + pub fn private_key_from_pkcs8_passphrase( + der: &[u8], + passphrase: &[u8], + ) -> Result, ErrorStack> { + unsafe { + ffi::init(); + let bio = MemBioSlice::new(der)?; + let passphrase = CString::new(passphrase).unwrap(); + cvt_p(ffi::d2i_PKCS8PrivateKey_bio( + bio.as_ptr(), + ptr::null_mut(), + None, + passphrase.as_ptr() as *const _ as *mut _, + )) + .map(|p| PKey::from_ptr(p)) + } + } +} + +impl PKey { + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_read_bio_PUBKEY`]. + /// + /// [`PEM_read_bio_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PUBKEY.html + public_key_from_pem, + PKey, + ffi::PEM_read_bio_PUBKEY + } + + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure. + /// + /// This corresponds to [`d2i_PUBKEY`]. + /// + /// [`d2i_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PUBKEY.html + public_key_from_der, + PKey, + ffi::d2i_PUBKEY + } +} + +#[cfg(test)] +mod tests { + use dh::Dh; + use dsa::Dsa; + use ec::EcKey; + use nid::Nid; + use rsa::Rsa; + use symm::Cipher; + + use super::*; + + #[test] + fn test_to_password() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let pem = pkey + .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar") + .unwrap(); + PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); + assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); + } + + #[test] + fn test_encrypted_pkcs8_passphrase() { + let key = include_bytes!("../test/pkcs8.der"); + PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap(); + } + + #[test] + fn test_encrypted_pkcs8_callback() { + let mut password_queried = false; + let key = include_bytes!("../test/pkcs8.der"); + PKey::private_key_from_pkcs8_callback(key, |password| { + password_queried = true; + password[..6].copy_from_slice(b"mypass"); + Ok(6) + }) + .unwrap(); + assert!(password_queried); + } + + #[test] + fn test_private_key_from_pem() { + let key = include_bytes!("../test/key.pem"); + PKey::private_key_from_pem(key).unwrap(); + } + + #[test] + fn test_public_key_from_pem() { + let key = include_bytes!("../test/key.pem.pub"); + PKey::public_key_from_pem(key).unwrap(); + } + + #[test] + fn test_public_key_from_der() { + let key = include_bytes!("../test/key.der.pub"); + PKey::public_key_from_der(key).unwrap(); + } + + #[test] + fn test_private_key_from_der() { + let key = include_bytes!("../test/key.der"); + PKey::private_key_from_der(key).unwrap(); + } + + #[test] + fn test_pem() { + let key = include_bytes!("../test/key.pem"); + let key = PKey::private_key_from_pem(key).unwrap(); + + let priv_key = key.private_key_to_pem_pkcs8().unwrap(); + let pub_key = key.public_key_to_pem().unwrap(); + + // As a super-simple verification, just check that the buffers contain + // the `PRIVATE KEY` or `PUBLIC KEY` strings. + assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY")); + assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY")); + } + + #[test] + fn test_rsa_accessor() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + pkey.rsa().unwrap(); + assert_eq!(pkey.id(), Id::RSA); + assert!(pkey.dsa().is_err()); + } + + #[test] + fn test_dsa_accessor() { + let dsa = Dsa::generate(2048).unwrap(); + let pkey = PKey::from_dsa(dsa).unwrap(); + pkey.dsa().unwrap(); + assert_eq!(pkey.id(), Id::DSA); + assert!(pkey.rsa().is_err()); + } + + #[test] + fn test_dh_accessor() { + let dh = include_bytes!("../test/dhparams.pem"); + let dh = Dh::params_from_pem(dh).unwrap(); + let pkey = PKey::from_dh(dh).unwrap(); + pkey.dh().unwrap(); + assert_eq!(pkey.id(), Id::DH); + assert!(pkey.rsa().is_err()); + } + + #[test] + fn test_ec_key_accessor() { + let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + pkey.ec_key().unwrap(); + assert_eq!(pkey.id(), Id::EC); + assert!(pkey.rsa().is_err()); + } +} diff --git a/openssl/src/rand.rs b/openssl/src/rand.rs new file mode 100644 index 000000000..88011de7b --- /dev/null +++ b/openssl/src/rand.rs @@ -0,0 +1,66 @@ +//! Utilities for secure random number generation. +//! +//! # Examples +//! +//! To generate a buffer with cryptographically strong bytes: +//! +//! ``` +//! use openssl::rand::rand_bytes; +//! +//! let mut buf = [0; 256]; +//! rand_bytes(&mut buf).unwrap(); +//! ``` +use ffi; +use libc::c_int; + +use cvt; +use error::ErrorStack; + +/// Fill buffer with cryptographically strong pseudo-random bytes. +/// +/// This corresponds to [`RAND_bytes`]. +/// +/// # Examples +/// +/// To generate a buffer with cryptographically strong bytes: +/// +/// ``` +/// use openssl::rand::rand_bytes; +/// +/// let mut buf = [0; 256]; +/// rand_bytes(&mut buf).unwrap(); +/// ``` +/// +/// [`RAND_bytes`]: https://www.openssl.org/docs/man1.1.0/crypto/RAND_bytes.html +pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> { + unsafe { + ffi::init(); + assert!(buf.len() <= c_int::max_value() as usize); + cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int)).map(|_| ()) + } +} + +/// Controls random device file descriptor behavior. +/// +/// Requires OpenSSL 1.1.1 or newer. +/// +/// This corresponds to [`RAND_keep_random_devices_open`]. +/// +/// [`RAND_keep_random_devices_open`]: https://www.openssl.org/docs/manmaster/man3/RAND_keep_random_devices_open.html +#[cfg(ossl111)] +pub fn keep_random_devices_open(keep: bool) { + unsafe { + ffi::RAND_keep_random_devices_open(keep as c_int); + } +} + +#[cfg(test)] +mod tests { + use super::rand_bytes; + + #[test] + fn test_rand_bytes() { + let mut buf = [0; 32]; + rand_bytes(&mut buf).unwrap(); + } +} diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs new file mode 100644 index 000000000..f35b56e59 --- /dev/null +++ b/openssl/src/rsa.rs @@ -0,0 +1,944 @@ +//! Rivest–Shamir–Adleman cryptosystem +//! +//! RSA is one of the earliest asymmetric public key encryption schemes. +//! Like many other cryptosystems, RSA relies on the presumed difficulty of a hard +//! mathematical problem, namely factorization of the product of two large prime +//! numbers. At the moment there does not exist an algorithm that can factor such +//! large numbers in reasonable time. RSA is used in a wide variety of +//! applications including digital signatures and key exchanges such as +//! establishing a TLS/SSL connection. +//! +//! The RSA acronym is derived from the first letters of the surnames of the +//! algorithm's founding trio. +//! +//! # Example +//! +//! Generate a 2048-bit RSA key pair and use the public key to encrypt some data. +//! +//! ```rust +//! +//! extern crate openssl; +//! +//! use openssl::rsa::{Rsa, Padding}; +//! +//! fn main() { +//! let rsa = Rsa::generate(2048).unwrap(); +//! let data = b"foobar"; +//! let mut buf = vec![0; rsa.size() as usize]; +//! let encrypted_len = rsa.public_encrypt(data, &mut buf, Padding::PKCS1).unwrap(); +//! } +//! ``` +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::fmt; +use std::mem; +use std::ptr; + +use bn::{BigNum, BigNumRef}; +use error::ErrorStack; +use pkey::{HasPrivate, HasPublic, Private, Public}; +use {cvt, cvt_n, cvt_p}; + +/// Type of encryption padding to use. +/// +/// Random length padding is primarily used to prevent attackers from +/// predicting or knowing the exact length of a plaintext message that +/// can possibly lead to breaking encryption. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Padding(c_int); + +impl Padding { + /// Creates a `Padding` from an integer representation. + pub fn from_raw(value: c_int) -> Padding { + Padding(value) + } + + /// Returns the integer representation of `Padding`. + pub fn as_raw(&self) -> c_int { + self.0 + } + + pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING); + pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING); + pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); + pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING); +} + +generic_foreign_type_and_impl_send_sync! { + type CType = ffi::RSA; + fn drop = ffi::RSA_free; + + /// An RSA key. + pub struct Rsa; + + /// Reference to `RSA` + pub struct RsaRef; +} + +impl Clone for Rsa { + fn clone(&self) -> Rsa { + (**self).to_owned() + } +} + +impl ToOwned for RsaRef { + type Owned = Rsa; + + fn to_owned(&self) -> Rsa { + unsafe { + ffi::RSA_up_ref(self.as_ptr()); + Rsa::from_ptr(self.as_ptr()) + } + } +} + +impl RsaRef +where + T: HasPrivate, +{ + private_key_to_pem! { + /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. + /// + /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html + private_key_to_pem, + /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. + /// + /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html + private_key_to_pem_passphrase, + ffi::PEM_write_bio_RSAPrivateKey + } + + to_der! { + /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure. + /// + /// This corresponds to [`i2d_RSAPrivateKey`]. + /// + /// [`i2d_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPrivateKey.html + private_key_to_der, + ffi::i2d_RSAPrivateKey + } + + /// Decrypts data using the private key, returning the number of decrypted bytes. + /// + /// # Panics + /// + /// Panics if `self` has no private components, or if `to` is smaller + /// than `self.size()`. + pub fn private_decrypt( + &self, + from: &[u8], + to: &mut [u8], + padding: Padding, + ) -> Result { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size() as usize); + + unsafe { + let len = cvt_n(ffi::RSA_private_decrypt( + from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.as_ptr(), + padding.0, + ))?; + Ok(len as usize) + } + } + + /// Encrypts data using the private key, returning the number of encrypted bytes. + /// + /// # Panics + /// + /// Panics if `self` has no private components, or if `to` is smaller + /// than `self.size()`. + pub fn private_encrypt( + &self, + from: &[u8], + to: &mut [u8], + padding: Padding, + ) -> Result { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size() as usize); + + unsafe { + let len = cvt_n(ffi::RSA_private_encrypt( + from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.as_ptr(), + padding.0, + ))?; + Ok(len as usize) + } + } + + /// Returns a reference to the private exponent of the key. + /// + /// This corresponds to [`RSA_get0_key`]. + /// + /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn d(&self) -> &BigNumRef { + unsafe { + let mut d = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d); + BigNumRef::from_ptr(d as *mut _) + } + } + + /// Returns a reference to the first factor of the exponent of the key. + /// + /// This corresponds to [`RSA_get0_factors`]. + /// + /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn p(&self) -> Option<&BigNumRef> { + unsafe { + let mut p = ptr::null(); + RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut()); + if p.is_null() { + None + } else { + Some(BigNumRef::from_ptr(p as *mut _)) + } + } + } + + /// Returns a reference to the second factor of the exponent of the key. + /// + /// This corresponds to [`RSA_get0_factors`]. + /// + /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn q(&self) -> Option<&BigNumRef> { + unsafe { + let mut q = ptr::null(); + RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q); + if q.is_null() { + None + } else { + Some(BigNumRef::from_ptr(q as *mut _)) + } + } + } + + /// Returns a reference to the first exponent used for CRT calculations. + /// + /// This corresponds to [`RSA_get0_crt_params`]. + /// + /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn dmp1(&self) -> Option<&BigNumRef> { + unsafe { + let mut dp = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut()); + if dp.is_null() { + None + } else { + Some(BigNumRef::from_ptr(dp as *mut _)) + } + } + } + + /// Returns a reference to the second exponent used for CRT calculations. + /// + /// This corresponds to [`RSA_get0_crt_params`]. + /// + /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn dmq1(&self) -> Option<&BigNumRef> { + unsafe { + let mut dq = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut()); + if dq.is_null() { + None + } else { + Some(BigNumRef::from_ptr(dq as *mut _)) + } + } + } + + /// Returns a reference to the coefficient used for CRT calculations. + /// + /// This corresponds to [`RSA_get0_crt_params`]. + /// + /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn iqmp(&self) -> Option<&BigNumRef> { + unsafe { + let mut qi = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi); + if qi.is_null() { + None + } else { + Some(BigNumRef::from_ptr(qi as *mut _)) + } + } + } + + /// Validates RSA parameters for correctness + /// + /// This corresponds to [`RSA_check_key`]. + /// + /// [`RSA_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_check_key.html + pub fn check_key(&self) -> Result { + unsafe { + let result = ffi::RSA_check_key(self.as_ptr()) as i32; + if result == -1 { + Err(ErrorStack::get()) + } else { + Ok(result == 1) + } + } + } +} + +impl RsaRef +where + T: HasPublic, +{ + to_pem! { + /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. + /// + /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_RSA_PUBKEY`]. + /// + /// [`PEM_write_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html + public_key_to_pem, + ffi::PEM_write_bio_RSA_PUBKEY + } + + to_der! { + /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. + /// + /// This corresponds to [`i2d_RSA_PUBKEY`]. + /// + /// [`i2d_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSA_PUBKEY.html + public_key_to_der, + ffi::i2d_RSA_PUBKEY + } + + to_pem! { + /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure. + /// + /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_write_bio_RSAPublicKey`]. + /// + /// [`PEM_write_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html + public_key_to_pem_pkcs1, + ffi::PEM_write_bio_RSAPublicKey + } + + to_der! { + /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure. + /// + /// This corresponds to [`i2d_RSAPublicKey`]. + /// + /// [`i2d_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPublicKey.html + public_key_to_der_pkcs1, + ffi::i2d_RSAPublicKey + } + + /// Returns the size of the modulus in bytes. + /// + /// This corresponds to [`RSA_size`]. + /// + /// [`RSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_size.html + pub fn size(&self) -> u32 { + unsafe { ffi::RSA_size(self.as_ptr()) as u32 } + } + + /// Decrypts data using the public key, returning the number of decrypted bytes. + /// + /// # Panics + /// + /// Panics if `to` is smaller than `self.size()`. + pub fn public_decrypt( + &self, + from: &[u8], + to: &mut [u8], + padding: Padding, + ) -> Result { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size() as usize); + + unsafe { + let len = cvt_n(ffi::RSA_public_decrypt( + from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.as_ptr(), + padding.0, + ))?; + Ok(len as usize) + } + } + + /// Encrypts data using the public key, returning the number of encrypted bytes. + /// + /// # Panics + /// + /// Panics if `to` is smaller than `self.size()`. + pub fn public_encrypt( + &self, + from: &[u8], + to: &mut [u8], + padding: Padding, + ) -> Result { + assert!(from.len() <= i32::max_value() as usize); + assert!(to.len() >= self.size() as usize); + + unsafe { + let len = cvt_n(ffi::RSA_public_encrypt( + from.len() as c_int, + from.as_ptr(), + to.as_mut_ptr(), + self.as_ptr(), + padding.0, + ))?; + Ok(len as usize) + } + } + + /// Returns a reference to the modulus of the key. + /// + /// This corresponds to [`RSA_get0_key`]. + /// + /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn n(&self) -> &BigNumRef { + unsafe { + let mut n = ptr::null(); + RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut()); + BigNumRef::from_ptr(n as *mut _) + } + } + + /// Returns a reference to the public exponent of the key. + /// + /// This corresponds to [`RSA_get0_key`]. + /// + /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + pub fn e(&self) -> &BigNumRef { + unsafe { + let mut e = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut()); + BigNumRef::from_ptr(e as *mut _) + } + } +} + +impl Rsa { + /// Creates a new RSA key with only public components. + /// + /// `n` is the modulus common to both public and private key. + /// `e` is the public exponent. + /// + /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. + /// + /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html + /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html + pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { + unsafe { + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut()); + mem::forget((n, e)); + Ok(Rsa::from_ptr(rsa)) + } + } + + from_pem! { + /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key. + /// + /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_read_bio_RSA_PUBKEY`]. + /// + /// [`PEM_read_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSA_PUBKEY.html + public_key_from_pem, + Rsa, + ffi::PEM_read_bio_RSA_PUBKEY + } + + from_pem! { + /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure. + /// + /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`. + /// + /// This corresponds to [`PEM_read_bio_RSAPublicKey`]. + /// + /// [`PEM_read_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSAPublicKey.html + public_key_from_pem_pkcs1, + Rsa, + ffi::PEM_read_bio_RSAPublicKey + } + + from_der! { + /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key. + /// + /// This corresponds to [`d2i_RSA_PUBKEY`]. + /// + /// [`d2i_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + public_key_from_der, + Rsa, + ffi::d2i_RSA_PUBKEY + } + + from_der! { + /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure. + /// + /// This corresponds to [`d2i_RSAPublicKey`]. + /// + /// [`d2i_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + public_key_from_der_pkcs1, + Rsa, + ffi::d2i_RSAPublicKey + } +} + +pub struct RsaPrivateKeyBuilder { + rsa: Rsa, +} + +impl RsaPrivateKeyBuilder { + /// Creates a new `RsaPrivateKeyBuilder`. + /// + /// `n` is the modulus common to both public and private key. + /// `e` is the public exponent and `d` is the private exponent. + /// + /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. + /// + /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html + /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html + pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { + unsafe { + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr()); + mem::forget((n, e, d)); + Ok(RsaPrivateKeyBuilder { + rsa: Rsa::from_ptr(rsa), + }) + } + } + + /// Sets the factors of the Rsa key. + /// + /// `p` and `q` are the first and second factors of `n`. + /// + /// This correspond to [`RSA_set0_factors`]. + /// + /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html + // FIXME should be infallible + pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { + unsafe { + RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); + mem::forget((p, q)); + } + Ok(self) + } + + /// Sets the Chinese Remainder Theorem params of the Rsa key. + /// + /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for + /// CRT calculations which is used to speed up RSA operations. + /// + /// This correspond to [`RSA_set0_crt_params`]. + /// + /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html + // FIXME should be infallible + pub fn set_crt_params( + self, + dmp1: BigNum, + dmq1: BigNum, + iqmp: BigNum, + ) -> Result { + unsafe { + RSA_set0_crt_params( + self.rsa.as_ptr(), + dmp1.as_ptr(), + dmq1.as_ptr(), + iqmp.as_ptr(), + ); + mem::forget((dmp1, dmq1, iqmp)); + } + Ok(self) + } + + /// Returns the Rsa key. + pub fn build(self) -> Rsa { + self.rsa + } +} + +impl Rsa { + /// Creates a new RSA key with private components (public components are assumed). + /// + /// This a convenience method over + /// `Rsa::build(n, e, d)?.set_factors(p, q)?.set_crt_params(dmp1, dmq1, iqmp)?.build()` + pub fn from_private_components( + n: BigNum, + e: BigNum, + d: BigNum, + p: BigNum, + q: BigNum, + dmp1: BigNum, + dmq1: BigNum, + iqmp: BigNum, + ) -> Result, ErrorStack> { + Ok(RsaPrivateKeyBuilder::new(n, e, d)? + .set_factors(p, q)? + .set_crt_params(dmp1, dmq1, iqmp)? + .build()) + } + + /// Generates a public/private key pair with the specified size. + /// + /// The public exponent will be 65537. + /// + /// This corresponds to [`RSA_generate_key_ex`]. + /// + /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html + pub fn generate(bits: u32) -> Result, ErrorStack> { + let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; + Rsa::generate_with_e(bits, &e) + } + + /// Generates a public/private key pair with the specified size and a custom exponent. + /// + /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead. + /// + /// This corresponds to [`RSA_generate_key_ex`]. + /// + /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html + pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result, ErrorStack> { + unsafe { + let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); + cvt(ffi::RSA_generate_key_ex( + rsa.0, + bits as c_int, + e.as_ptr(), + ptr::null_mut(), + ))?; + Ok(rsa) + } + } + + // FIXME these need to identify input formats + private_key_from_pem! { + /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure. + /// + /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. + /// + /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + private_key_from_pem, + + /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + /// + /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. + /// + /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + private_key_from_pem_passphrase, + + /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. + /// + /// The callback should fill the password into the provided buffer and return its length. + /// + /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. + /// + /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + private_key_from_pem_callback, + Rsa, + ffi::PEM_read_bio_RSAPrivateKey + } + + from_der! { + /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure. + /// + /// This corresponds to [`d2i_RSAPrivateKey`]. + /// + /// [`d2i_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + private_key_from_der, + Rsa, + ffi::d2i_RSAPrivateKey + } +} + +impl fmt::Debug for Rsa { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Rsa") + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{ + RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, + RSA_set0_crt_params, + }; + } else { + #[allow(bad_style)] + unsafe fn RSA_get0_key( + r: *const ffi::RSA, + n: *mut *const ffi::BIGNUM, + e: *mut *const ffi::BIGNUM, + d: *mut *const ffi::BIGNUM, + ) { + if !n.is_null() { + *n = (*r).n; + } + if !e.is_null() { + *e = (*r).e; + } + if !d.is_null() { + *d = (*r).d; + } + } + + #[allow(bad_style)] + unsafe fn RSA_get0_factors( + r: *const ffi::RSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + ) { + if !p.is_null() { + *p = (*r).p; + } + if !q.is_null() { + *q = (*r).q; + } + } + + #[allow(bad_style)] + unsafe fn RSA_get0_crt_params( + r: *const ffi::RSA, + dmp1: *mut *const ffi::BIGNUM, + dmq1: *mut *const ffi::BIGNUM, + iqmp: *mut *const ffi::BIGNUM, + ) { + if !dmp1.is_null() { + *dmp1 = (*r).dmp1; + } + if !dmq1.is_null() { + *dmq1 = (*r).dmq1; + } + if !iqmp.is_null() { + *iqmp = (*r).iqmp; + } + } + + #[allow(bad_style)] + unsafe fn RSA_set0_key( + r: *mut ffi::RSA, + n: *mut ffi::BIGNUM, + e: *mut ffi::BIGNUM, + d: *mut ffi::BIGNUM, + ) -> c_int { + (*r).n = n; + (*r).e = e; + (*r).d = d; + 1 + } + + #[allow(bad_style)] + unsafe fn RSA_set0_factors( + r: *mut ffi::RSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + ) -> c_int { + (*r).p = p; + (*r).q = q; + 1 + } + + #[allow(bad_style)] + unsafe fn RSA_set0_crt_params( + r: *mut ffi::RSA, + dmp1: *mut ffi::BIGNUM, + dmq1: *mut ffi::BIGNUM, + iqmp: *mut ffi::BIGNUM, + ) -> c_int { + (*r).dmp1 = dmp1; + (*r).dmq1 = dmq1; + (*r).iqmp = iqmp; + 1 + } + } +} + +#[cfg(test)] +mod test { + use symm::Cipher; + + use super::*; + + #[test] + fn test_from_password() { + let key = include_bytes!("../test/rsa-encrypted.pem"); + Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); + } + + #[test] + fn test_from_password_callback() { + let mut password_queried = false; + let key = include_bytes!("../test/rsa-encrypted.pem"); + Rsa::private_key_from_pem_callback(key, |password| { + password_queried = true; + password[..6].copy_from_slice(b"mypass"); + Ok(6) + }) + .unwrap(); + + assert!(password_queried); + } + + #[test] + fn test_to_password() { + let key = Rsa::generate(2048).unwrap(); + let pem = key + .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") + .unwrap(); + Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); + assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); + } + + #[test] + fn test_public_encrypt_private_decrypt_with_padding() { + let key = include_bytes!("../test/rsa.pem.pub"); + let public_key = Rsa::public_key_from_pem(key).unwrap(); + + let mut result = vec![0; public_key.size() as usize]; + let original_data = b"This is test"; + let len = public_key + .public_encrypt(original_data, &mut result, Padding::PKCS1) + .unwrap(); + assert_eq!(len, 256); + + let pkey = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(pkey).unwrap(); + let mut dec_result = vec![0; private_key.size() as usize]; + let len = private_key + .private_decrypt(&result, &mut dec_result, Padding::PKCS1) + .unwrap(); + + assert_eq!(&dec_result[..len], original_data); + } + + #[test] + fn test_private_encrypt() { + let k0 = super::Rsa::generate(512).unwrap(); + let k0pkey = k0.public_key_to_pem().unwrap(); + let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap(); + + let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; + + let mut emesg = vec![0; k0.size() as usize]; + k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1) + .unwrap(); + let mut dmesg = vec![0; k1.size() as usize]; + let len = k1 + .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + .unwrap(); + assert_eq!(msg, &dmesg[..len]); + } + + #[test] + fn test_public_encrypt() { + let k0 = super::Rsa::generate(512).unwrap(); + let k0pkey = k0.private_key_to_pem().unwrap(); + let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap(); + + let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; + + let mut emesg = vec![0; k0.size() as usize]; + k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap(); + let mut dmesg = vec![0; k1.size() as usize]; + let len = k1 + .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + .unwrap(); + assert_eq!(msg, &dmesg[..len]); + } + + #[test] + fn test_public_key_from_pem_pkcs1() { + let key = include_bytes!("../test/pkcs1.pem.pub"); + Rsa::public_key_from_pem_pkcs1(key).unwrap(); + } + + #[test] + #[should_panic] + fn test_public_key_from_pem_pkcs1_file_panic() { + let key = include_bytes!("../test/key.pem.pub"); + Rsa::public_key_from_pem_pkcs1(key).unwrap(); + } + + #[test] + fn test_public_key_to_pem_pkcs1() { + let keypair = super::Rsa::generate(512).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + } + + #[test] + #[should_panic] + fn test_public_key_from_pem_pkcs1_generate_panic() { + let keypair = super::Rsa::generate(512).unwrap(); + let pubkey_pem = keypair.public_key_to_pem().unwrap(); + super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + } + + #[test] + fn test_pem_pkcs1_encrypt() { + let keypair = super::Rsa::generate(2048).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + let msg = "Hello, world!".as_bytes(); + + let mut encrypted = vec![0; pubkey.size() as usize]; + let len = pubkey + .public_encrypt(&msg, &mut encrypted, Padding::PKCS1) + .unwrap(); + assert!(len > msg.len()); + let mut decrypted = vec![0; keypair.size() as usize]; + let len = keypair + .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1) + .unwrap(); + assert_eq!(len, msg.len()); + assert_eq!("Hello, world!", String::from_utf8_lossy(&decrypted[..len])); + } + + #[test] + fn test_pem_pkcs1_padding() { + let keypair = super::Rsa::generate(2048).unwrap(); + let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); + let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); + let msg = "foo".as_bytes(); + + let mut encrypted1 = vec![0; pubkey.size() as usize]; + let mut encrypted2 = vec![0; pubkey.size() as usize]; + let len1 = pubkey + .public_encrypt(&msg, &mut encrypted1, Padding::PKCS1) + .unwrap(); + let len2 = pubkey + .public_encrypt(&msg, &mut encrypted2, Padding::PKCS1) + .unwrap(); + assert!(len1 > (msg.len() + 1)); + assert_eq!(len1, len2); + assert_ne!(encrypted1, encrypted2); + } + + #[test] + fn clone() { + let key = Rsa::generate(2048).unwrap(); + drop(key.clone()); + } + + #[test] + fn generate_with_e() { + let e = BigNum::from_u32(0x10001).unwrap(); + Rsa::generate_with_e(2048, &e).unwrap(); + } +} diff --git a/openssl/src/sha.rs b/openssl/src/sha.rs new file mode 100644 index 000000000..e3c4c2e81 --- /dev/null +++ b/openssl/src/sha.rs @@ -0,0 +1,390 @@ +//! The SHA family of hashes. +//! +//! SHA, or Secure Hash Algorithms, are a family of cryptographic hashing algorithms published by +//! the National Institute of Standards and Technology (NIST). Hash algorithms such as those in +//! the SHA family are used to map data of an arbitrary size to a fixed-size string of bytes. +//! As cryptographic hashing algorithms, these mappings have the property of being irreversable. +//! This property makes hash algorithms like these excellent for uses such as verifying the +//! contents of a file- if you know the hash you expect beforehand, then you can verify that the +//! data you have is correct if it hashes to the same value. +//! +//! # Examples +//! +//! When dealing with data that becomes available in chunks, such as while buffering data from IO, +//! you can create a hasher that you can repeatedly update to add bytes to. +//! +//! ```rust +//! extern crate openssl; +//! extern crate hex; +//! +//! use openssl::sha; +//! +//! fn main() { +//! let mut hasher = sha::Sha256::new(); +//! +//! hasher.update(b"Hello, "); +//! hasher.update(b"world"); +//! +//! let hash = hasher.finish(); +//! println!("Hashed \"Hello, world\" to {}", hex::encode(hash)); +//! } +//! ``` +//! +//! On the other hand, if you already have access to all of the data you woud like to hash, you +//! may prefer to use the slightly simpler method of simply calling the hash function corresponding +//! to the algorithm you want to use. +//! +//! ```rust +//! extern crate openssl; +//! extern crate hex; +//! +//! use openssl::sha::sha256; +//! +//! fn main() { +//! let hash = sha256(b"your data or message"); +//! println!("Hash = {}", hex::encode(hash)); +//! } +//! ``` +use ffi; +use libc::c_void; +use std::mem; + +/// Computes the SHA1 hash of some data. +/// +/// # Warning +/// +/// SHA1 is known to be insecure - it should not be used unless required for +/// compatibility with existing systems. +#[inline] +pub fn sha1(data: &[u8]) -> [u8; 20] { + unsafe { + let mut hash: [u8; 20] = mem::uninitialized(); + ffi::SHA1(data.as_ptr(), data.len(), hash.as_mut_ptr()); + hash + } +} + +/// Computes the SHA224 hash of some data. +#[inline] +pub fn sha224(data: &[u8]) -> [u8; 28] { + unsafe { + let mut hash: [u8; 28] = mem::uninitialized(); + ffi::SHA224(data.as_ptr(), data.len(), hash.as_mut_ptr()); + hash + } +} + +/// Computes the SHA256 hash of some data. +#[inline] +pub fn sha256(data: &[u8]) -> [u8; 32] { + unsafe { + let mut hash: [u8; 32] = mem::uninitialized(); + ffi::SHA256(data.as_ptr(), data.len(), hash.as_mut_ptr()); + hash + } +} + +/// Computes the SHA384 hash of some data. +#[inline] +pub fn sha384(data: &[u8]) -> [u8; 48] { + unsafe { + let mut hash: [u8; 48] = mem::uninitialized(); + ffi::SHA384(data.as_ptr(), data.len(), hash.as_mut_ptr()); + hash + } +} + +/// Computes the SHA512 hash of some data. +#[inline] +pub fn sha512(data: &[u8]) -> [u8; 64] { + unsafe { + let mut hash: [u8; 64] = mem::uninitialized(); + ffi::SHA512(data.as_ptr(), data.len(), hash.as_mut_ptr()); + hash + } +} + +/// An object which calculates a SHA1 hash of some data. +/// +/// # Warning +/// +/// SHA1 is known to be insecure - it should not be used unless required for +/// compatibility with existing systems. +pub struct Sha1(ffi::SHA_CTX); + +impl Sha1 { + /// Creates a new hasher. + #[inline] + pub fn new() -> Sha1 { + unsafe { + let mut ctx = mem::uninitialized(); + ffi::SHA1_Init(&mut ctx); + Sha1(ctx) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA1_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[inline] + pub fn finish(mut self) -> [u8; 20] { + unsafe { + let mut hash: [u8; 20] = mem::uninitialized(); + ffi::SHA1_Final(hash.as_mut_ptr(), &mut self.0); + hash + } + } +} + +/// An object which calculates a SHA224 hash of some data. +pub struct Sha224(ffi::SHA256_CTX); + +impl Sha224 { + /// Creates a new hasher. + #[inline] + pub fn new() -> Sha224 { + unsafe { + let mut ctx = mem::uninitialized(); + ffi::SHA224_Init(&mut ctx); + Sha224(ctx) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA224_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[inline] + pub fn finish(mut self) -> [u8; 28] { + unsafe { + let mut hash: [u8; 28] = mem::uninitialized(); + ffi::SHA224_Final(hash.as_mut_ptr(), &mut self.0); + hash + } + } +} + +/// An object which calculates a SHA256 hash of some data. +pub struct Sha256(ffi::SHA256_CTX); + +impl Sha256 { + /// Creates a new hasher. + #[inline] + pub fn new() -> Sha256 { + unsafe { + let mut ctx = mem::uninitialized(); + ffi::SHA256_Init(&mut ctx); + Sha256(ctx) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA256_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[inline] + pub fn finish(mut self) -> [u8; 32] { + unsafe { + let mut hash: [u8; 32] = mem::uninitialized(); + ffi::SHA256_Final(hash.as_mut_ptr(), &mut self.0); + hash + } + } +} + +/// An object which calculates a SHA384 hash of some data. +pub struct Sha384(ffi::SHA512_CTX); + +impl Sha384 { + /// Creates a new hasher. + #[inline] + pub fn new() -> Sha384 { + unsafe { + let mut ctx = mem::uninitialized(); + ffi::SHA384_Init(&mut ctx); + Sha384(ctx) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA384_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[inline] + pub fn finish(mut self) -> [u8; 48] { + unsafe { + let mut hash: [u8; 48] = mem::uninitialized(); + ffi::SHA384_Final(hash.as_mut_ptr(), &mut self.0); + hash + } + } +} + +/// An object which calculates a SHA512 hash of some data. +pub struct Sha512(ffi::SHA512_CTX); + +impl Sha512 { + /// Creates a new hasher. + #[inline] + pub fn new() -> Sha512 { + unsafe { + let mut ctx = mem::uninitialized(); + ffi::SHA512_Init(&mut ctx); + Sha512(ctx) + } + } + + /// Feeds some data into the hasher. + /// + /// This can be called multiple times. + #[inline] + pub fn update(&mut self, buf: &[u8]) { + unsafe { + ffi::SHA512_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); + } + } + + /// Returns the hash of the data. + #[inline] + pub fn finish(mut self) -> [u8; 64] { + unsafe { + let mut hash: [u8; 64] = mem::uninitialized(); + ffi::SHA512_Final(hash.as_mut_ptr(), &mut self.0); + hash + } + } +} + +#[cfg(test)] +mod test { + use hex; + + use super::*; + + #[test] + fn standalone_1() { + let data = b"abc"; + let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; + + assert_eq!(hex::encode(sha1(data)), expected); + } + + #[test] + fn struct_1() { + let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; + + let mut hasher = Sha1::new(); + hasher.update(b"a"); + hasher.update(b"bc"); + assert_eq!(hex::encode(hasher.finish()), expected); + } + + #[test] + fn standalone_224() { + let data = b"abc"; + let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; + + assert_eq!(hex::encode(sha224(data)), expected); + } + + #[test] + fn struct_224() { + let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; + + let mut hasher = Sha224::new(); + hasher.update(b"a"); + hasher.update(b"bc"); + assert_eq!(hex::encode(hasher.finish()), expected); + } + + #[test] + fn standalone_256() { + let data = b"abc"; + let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + + assert_eq!(hex::encode(sha256(data)), expected); + } + + #[test] + fn struct_256() { + let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + + let mut hasher = Sha256::new(); + hasher.update(b"a"); + hasher.update(b"bc"); + assert_eq!(hex::encode(hasher.finish()), expected); + } + + #[test] + fn standalone_384() { + let data = b"abc"; + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; + + assert_eq!(hex::encode(&sha384(data)[..]), expected); + } + + #[test] + fn struct_384() { + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; + + let mut hasher = Sha384::new(); + hasher.update(b"a"); + hasher.update(b"bc"); + assert_eq!(hex::encode(&hasher.finish()[..]), expected); + } + + #[test] + fn standalone_512() { + let data = b"abc"; + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + + assert_eq!(hex::encode(&sha512(data)[..]), expected); + } + + #[test] + fn struct_512() { + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + + let mut hasher = Sha512::new(); + hasher.update(b"a"); + hasher.update(b"bc"); + assert_eq!(hex::encode(&hasher.finish()[..]), expected); + } +} diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs new file mode 100644 index 000000000..a3a58bfe0 --- /dev/null +++ b/openssl/src/sign.rs @@ -0,0 +1,732 @@ +//! Message signatures. +//! +//! The `Signer` allows for the computation of cryptographic signatures of +//! data given a private key. The `Verifier` can then be used with the +//! corresponding public key to verify the integrity and authenticity of that +//! data given the signature. +//! +//! # Examples +//! +//! Sign and verify data given an RSA keypair: +//! +//! ```rust +//! use openssl::sign::{Signer, Verifier}; +//! use openssl::rsa::Rsa; +//! use openssl::pkey::PKey; +//! use openssl::hash::MessageDigest; +//! +//! // Generate a keypair +//! let keypair = Rsa::generate(2048).unwrap(); +//! let keypair = PKey::from_rsa(keypair).unwrap(); +//! +//! let data = b"hello, world!"; +//! let data2 = b"hola, mundo!"; +//! +//! // Sign the data +//! let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap(); +//! signer.update(data).unwrap(); +//! signer.update(data2).unwrap(); +//! let signature = signer.sign_to_vec().unwrap(); +//! +//! // Verify the data +//! let mut verifier = Verifier::new(MessageDigest::sha256(), &keypair).unwrap(); +//! verifier.update(data).unwrap(); +//! verifier.update(data2).unwrap(); +//! assert!(verifier.verify(&signature).unwrap()); +//! ``` +//! +//! Compute an HMAC: +//! +//! ```rust +//! use openssl::hash::MessageDigest; +//! use openssl::memcmp; +//! use openssl::pkey::PKey; +//! use openssl::sign::Signer; +//! +//! // Create a PKey +//! let key = PKey::hmac(b"my secret").unwrap(); +//! +//! let data = b"hello, world!"; +//! let data2 = b"hola, mundo!"; +//! +//! // Compute the HMAC +//! let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); +//! signer.update(data).unwrap(); +//! signer.update(data2).unwrap(); +//! let hmac = signer.sign_to_vec().unwrap(); +//! +//! // `Verifier` cannot be used with HMACs; use the `memcmp::eq` function instead +//! // +//! // Do not simply check for equality with `==`! +//! # let target = hmac.clone(); +//! assert!(memcmp::eq(&hmac, &target)); +//! ``` +use ffi; +use foreign_types::ForeignTypeRef; +use libc::c_int; +use std::io::{self, Write}; +use std::marker::PhantomData; +use std::ptr; + +use error::ErrorStack; +use hash::MessageDigest; +use pkey::{HasPrivate, HasPublic, PKeyRef}; +use rsa::Padding; +use {cvt, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} + +/// Salt lengths that must be used with `set_rsa_pss_saltlen`. +pub struct RsaPssSaltlen(c_int); + +impl RsaPssSaltlen { + /// Returns the integer representation of `RsaPssSaltlen`. + fn as_raw(&self) -> c_int { + self.0 + } + + /// Sets the salt length to the given value. + pub fn custom(val: c_int) -> RsaPssSaltlen { + RsaPssSaltlen(val) + } + + /// The salt length is set to the digest length. + /// Corresponds to the special value `-1`. + pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1); + /// The salt length is set to the maximum permissible value. + /// Corresponds to the special value `-2`. + pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2); +} + +/// A type which computes cryptographic signatures of data. +pub struct Signer<'a> { + md_ctx: *mut ffi::EVP_MD_CTX, + pctx: *mut ffi::EVP_PKEY_CTX, + _p: PhantomData<&'a ()>, +} + +unsafe impl<'a> Sync for Signer<'a> {} +unsafe impl<'a> Send for Signer<'a> {} + +impl<'a> Drop for Signer<'a> { + fn drop(&mut self) { + // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. + unsafe { + EVP_MD_CTX_free(self.md_ctx); + } + } +} + +impl<'a> Signer<'a> { + /// Creates a new `Signer`. + /// + /// OpenSSL documentation at [`EVP_DigestSignInit`]. + /// + /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html + pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + Self::new_intern(Some(type_), pkey) + } + + /// Creates a new `Signer` without a digest. + /// + /// This can be used to create a CMAC. + /// OpenSSL documentation at [`EVP_DigestSignInit`]. + /// + /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html + pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPrivate, + { + Self::new_intern(None, pkey) + } + + pub fn new_intern( + type_: Option, + pkey: &'a PKeyRef, + ) -> Result, ErrorStack> + where + T: HasPrivate, + { + unsafe { + ffi::init(); + + let ctx = cvt_p(EVP_MD_CTX_new())?; + let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); + let r = ffi::EVP_DigestSignInit( + ctx, + &mut pctx, + type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()), + ptr::null_mut(), + pkey.as_ptr(), + ); + if r != 1 { + EVP_MD_CTX_free(ctx); + return Err(ErrorStack::get()); + } + + assert!(!pctx.is_null()); + + Ok(Signer { + md_ctx: ctx, + pctx, + _p: PhantomData, + }) + } + } + + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA PSS salt length. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( + self.pctx, + len.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Feeds more data into the `Signer`. + /// + /// OpenSSL documentation at [`EVP_DigestUpdate`]. + /// + /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html + pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestUpdate( + self.md_ctx, + buf.as_ptr() as *const _, + buf.len(), + )) + .map(|_| ()) + } + } + + /// Computes an upper bound on the signature length. + /// + /// The actual signature may be shorter than this value. Check the return value of + /// `sign` to get the exact length. + /// + /// OpenSSL documentation at [`EVP_DigestSignFinal`]. + /// + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + pub fn len(&self) -> Result { + unsafe { + let mut len = 0; + cvt(ffi::EVP_DigestSignFinal( + self.md_ctx, + ptr::null_mut(), + &mut len, + ))?; + Ok(len) + } + } + + /// Writes the signature into the provided buffer, returning the number of bytes written. + /// + /// This method will fail if the buffer is not large enough for the signature. Use the `len` + /// method to get an upper bound on the required size. + /// + /// OpenSSL documentation at [`EVP_DigestSignFinal`]. + /// + /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + pub fn sign(&self, buf: &mut [u8]) -> Result { + unsafe { + let mut len = buf.len(); + cvt(ffi::EVP_DigestSignFinal( + self.md_ctx, + buf.as_mut_ptr() as *mut _, + &mut len, + ))?; + Ok(len) + } + } + + /// Returns the signature. + /// + /// This is a simple convenience wrapper over `len` and `sign`. + pub fn sign_to_vec(&self) -> Result, ErrorStack> { + let mut buf = vec![0; self.len()?]; + let len = self.sign(&mut buf)?; + // The advertised length is not always equal to the real length for things like DSA + buf.truncate(len); + Ok(buf) + } +} + +impl<'a> Write for Signer<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.update(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub struct Verifier<'a> { + md_ctx: *mut ffi::EVP_MD_CTX, + pctx: *mut ffi::EVP_PKEY_CTX, + pkey_pd: PhantomData<&'a ()>, +} + +unsafe impl<'a> Sync for Verifier<'a> {} +unsafe impl<'a> Send for Verifier<'a> {} + +impl<'a> Drop for Verifier<'a> { + fn drop(&mut self) { + // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. + unsafe { + EVP_MD_CTX_free(self.md_ctx); + } + } +} + +/// A type which verifies cryptographic signatures of data. +impl<'a> Verifier<'a> { + /// Creates a new `Verifier`. + /// + /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. + /// + /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html + pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + where + T: HasPublic, + { + unsafe { + ffi::init(); + + let ctx = cvt_p(EVP_MD_CTX_new())?; + let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); + let r = ffi::EVP_DigestVerifyInit( + ctx, + &mut pctx, + type_.as_ptr(), + ptr::null_mut(), + pkey.as_ptr(), + ); + if r != 1 { + EVP_MD_CTX_free(ctx); + return Err(ErrorStack::get()); + } + + assert!(!pctx.is_null()); + + Ok(Verifier { + md_ctx: ctx, + pctx, + pkey_pd: PhantomData, + }) + } + } + + /// Returns the RSA padding mode in use. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + pub fn rsa_padding(&self) -> Result { + unsafe { + let mut pad = 0; + cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) + .map(|_| Padding::from_raw(pad)) + } + } + + /// Sets the RSA padding mode. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( + self.pctx, + padding.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA PSS salt length. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( + self.pctx, + len.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the RSA MGF1 algorithm. + /// + /// This is only useful for RSA keys. + /// + /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. + /// + /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( + self.pctx, + md.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Feeds more data into the `Verifier`. + /// + /// OpenSSL documentation at [`EVP_DigestUpdate`]. + /// + /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html + pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_DigestUpdate( + self.md_ctx, + buf.as_ptr() as *const _, + buf.len(), + )) + .map(|_| ()) + } + } + + /// Determines if the data fed into the `Verifier` matches the provided signature. + /// + /// OpenSSL documentation at [`EVP_DigestVerifyFinal`]. + /// + /// [`EVP_DigestVerifyFinal`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyFinal.html + pub fn verify(&self, signature: &[u8]) -> Result { + unsafe { + let r = + EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *mut _, signature.len()); + match r { + 1 => Ok(true), + 0 => { + ErrorStack::get(); // discard error stack + Ok(false) + } + _ => Err(ErrorStack::get()), + } + } + } +} + +impl<'a> Write for Verifier<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.update(buf)?; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(not(ossl101))] +use ffi::EVP_DigestVerifyFinal; + +#[cfg(ossl101)] +#[allow(bad_style)] +unsafe fn EVP_DigestVerifyFinal( + ctx: *mut ffi::EVP_MD_CTX, + sigret: *const ::libc::c_uchar, + siglen: ::libc::size_t, +) -> ::libc::c_int { + ffi::EVP_DigestVerifyFinal(ctx, sigret as *mut _, siglen) +} + +#[cfg(test)] +mod test { + use hex::{self, FromHex}; + use std::iter; + + use ec::{EcGroup, EcKey}; + use hash::MessageDigest; + use nid::Nid; + use pkey::PKey; + use rsa::{Padding, Rsa}; + use sign::{RsaPssSaltlen, Signer, Verifier}; + + const INPUT: &'static str = + "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ + 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ + 6d4e76625339706331397962323930496a7030636e566c6651"; + + const SIGNATURE: &'static str = + "702e218943e88fd11eb5d82dbf7845f34106ae1b81fff7731116add1717d83656d420afd3c96eedd73a2663e51\ + 66687b000b87226e0187ed1073f945e582adfcef16d85a798ee8c66ddb3db8975b17d09402beedd5d9d9700710\ + 8db28160d5f8040ca7445762b81fbe7ff9d92e0ae76f24f25b33bbe6f44ae61eb1040acb20044d3ef9128ed401\ + 30795bd4bd3b41eecad066ab651981fde48df77f372dc38b9fafdd3befb18b5da3cc3c2eb02f9e3a41d612caad\ + 15911273a05f23b9e838faaf849d698429ef5a1e88798236c3d40e604522a544c8f27a7a2db80663d16cf7caea\ + 56de405cb2215a45b2c25566b55ac1a748a070dfc8a32a469543d019eefb47"; + + #[test] + fn rsa_sign() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); + assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1); + signer.set_rsa_padding(Padding::PKCS1).unwrap(); + signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + let result = signer.sign_to_vec().unwrap(); + + assert_eq!(hex::encode(result), SIGNATURE); + } + + #[test] + fn rsa_verify_ok() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); + assert_eq!(verifier.rsa_padding().unwrap(), Padding::PKCS1); + verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + assert!(verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); + } + + #[test] + fn rsa_verify_invalid() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); + verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + verifier.update(b"foobar").unwrap(); + assert!(!verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); + } + + fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { + for &(ref key, ref data, ref res) in tests.iter() { + let pkey = PKey::hmac(key).unwrap(); + let mut signer = Signer::new(ty, &pkey).unwrap(); + signer.update(data).unwrap(); + assert_eq!(signer.sign_to_vec().unwrap(), *res); + } + } + + #[test] + fn hmac_md5() { + // test vectors from RFC 2202 + let tests: [(Vec, Vec, Vec); 7] = [ + ( + iter::repeat(0x0b_u8).take(16).collect(), + b"Hi There".to_vec(), + Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap(), + ), + ( + b"Jefe".to_vec(), + b"what do ya want for nothing?".to_vec(), + Vec::from_hex("750c783e6ab0b503eaa86e310a5db738").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(16).collect(), + iter::repeat(0xdd_u8).take(50).collect(), + Vec::from_hex("56be34521d144c88dbb8c733f0e8b3f6").unwrap(), + ), + ( + Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), + iter::repeat(0xcd_u8).take(50).collect(), + Vec::from_hex("697eaf0aca3a3aea3a75164746ffaa79").unwrap(), + ), + ( + iter::repeat(0x0c_u8).take(16).collect(), + b"Test With Truncation".to_vec(), + Vec::from_hex("56461ef2342edc00f9bab995690efd4c").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(80).collect(), + b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), + Vec::from_hex("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(80).collect(), + b"Test Using Larger Than Block-Size Key \ + and Larger Than One Block-Size Data" + .to_vec(), + Vec::from_hex("6f630fad67cda0ee1fb1f562db3aa53e").unwrap(), + ), + ]; + + test_hmac(MessageDigest::md5(), &tests); + } + + #[test] + fn hmac_sha1() { + // test vectors from RFC 2202 + let tests: [(Vec, Vec, Vec); 7] = [ + ( + iter::repeat(0x0b_u8).take(20).collect(), + b"Hi There".to_vec(), + Vec::from_hex("b617318655057264e28bc0b6fb378c8ef146be00").unwrap(), + ), + ( + b"Jefe".to_vec(), + b"what do ya want for nothing?".to_vec(), + Vec::from_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(20).collect(), + iter::repeat(0xdd_u8).take(50).collect(), + Vec::from_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3").unwrap(), + ), + ( + Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), + iter::repeat(0xcd_u8).take(50).collect(), + Vec::from_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da").unwrap(), + ), + ( + iter::repeat(0x0c_u8).take(20).collect(), + b"Test With Truncation".to_vec(), + Vec::from_hex("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(80).collect(), + b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), + Vec::from_hex("aa4ae5e15272d00e95705637ce8a3b55ed402112").unwrap(), + ), + ( + iter::repeat(0xaa_u8).take(80).collect(), + b"Test Using Larger Than Block-Size Key \ + and Larger Than One Block-Size Data" + .to_vec(), + Vec::from_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91").unwrap(), + ), + ]; + + test_hmac(MessageDigest::sha1(), &tests); + } + + #[test] + #[cfg(ossl110)] + fn test_cmac() { + let cipher = ::symm::Cipher::aes_128_cbc(); + let key = Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap(); + let pkey = PKey::cmac(&cipher, &key).unwrap(); + let mut signer = Signer::new_without_digest(&pkey).unwrap(); + + let data = b"Hi There"; + signer.update(data as &[u8]).unwrap(); + + let expected = vec![ + 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19, + ]; + assert_eq!(signer.sign_to_vec().unwrap(), expected); + } + + #[test] + fn ec() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let key = PKey::from_ec_key(key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); + signer.update(b"hello world").unwrap(); + let signature = signer.sign_to_vec().unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &key).unwrap(); + verifier.update(b"hello world").unwrap(); + assert!(verifier.verify(&signature).unwrap()); + } + + #[test] + fn rsa_sign_verify() { + let key = include_bytes!("../test/rsa.pem"); + let private_key = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(private_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); + signer.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1_PSS); + signer + .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) + .unwrap(); + signer.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); + signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + let signature = signer.sign_to_vec().unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); + verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + verifier + .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) + .unwrap(); + verifier.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); + verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); + assert!(verifier.verify(&signature).unwrap()); + } +} diff --git a/openssl/src/srtp.rs b/openssl/src/srtp.rs new file mode 100644 index 000000000..03b722aca --- /dev/null +++ b/openssl/src/srtp.rs @@ -0,0 +1,57 @@ +use ffi; +use foreign_types::ForeignTypeRef; +use libc::c_ulong; +use stack::Stackable; +use std::ffi::CStr; +use std::str; + +/// fake free method, since SRTP_PROTECTION_PROFILE is static +unsafe fn free(_profile: *mut ffi::SRTP_PROTECTION_PROFILE) {} + +#[allow(unused_unsafe)] +foreign_type_and_impl_send_sync! { + type CType = ffi::SRTP_PROTECTION_PROFILE; + fn drop = free; + + pub struct SrtpProtectionProfile; + /// Reference to `SrtpProtectionProfile`. + pub struct SrtpProtectionProfileRef; +} + +impl Stackable for SrtpProtectionProfile { + type StackType = ffi::stack_st_SRTP_PROTECTION_PROFILE; +} + +impl SrtpProtectionProfileRef { + pub fn id(&self) -> SrtpProfileId { + SrtpProfileId::from_raw(unsafe { (*self.as_ptr()).id }) + } + pub fn name(&self) -> &'static str { + unsafe { CStr::from_ptr((*self.as_ptr()).name as *const _) } + .to_str() + .expect("should be UTF-8") + } +} + +/// An identifier of an SRTP protection profile. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SrtpProfileId(c_ulong); + +impl SrtpProfileId { + /// Creates a `SrtpProfileId` from an integer representation. + pub fn from_raw(value: c_ulong) -> SrtpProfileId { + SrtpProfileId(value) + } + + /// Returns the integer representation of `SrtpProfileId`. + pub fn as_raw(&self) -> c_ulong { + self.0 + } + + pub const SRTP_AES128_CM_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_80); + pub const SRTP_AES128_CM_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_32); + pub const SRTP_AES128_F8_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_80); + pub const SRTP_AES128_F8_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_32); + pub const SRTP_NULL_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_80); + pub const SRTP_NULL_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_32); +} diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs new file mode 100644 index 000000000..c1c5f8712 --- /dev/null +++ b/openssl/src/ssl/bio.rs @@ -0,0 +1,275 @@ +use ffi::{ + self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, + BIO_CTRL_FLUSH, +}; +use libc::{c_char, c_int, c_long, c_void, strlen}; +use std::any::Any; +use std::io; +use std::io::prelude::*; +use std::mem; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::ptr; +use std::slice; + +use cvt_p; +use error::ErrorStack; + +pub struct StreamState { + pub stream: S, + pub error: Option, + pub panic: Option>, +} + +/// Safe wrapper for BIO_METHOD +pub struct BioMethod(BIO_METHOD); + +impl BioMethod { + fn new() -> BioMethod { + BioMethod(BIO_METHOD::new::()) + } +} + +unsafe impl Sync for BioMethod {} +unsafe impl Send for BioMethod {} + +pub fn new(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> { + let method = BioMethod::new::(); + + let state = Box::new(StreamState { + stream: stream, + error: None, + panic: None, + }); + + unsafe { + let bio = cvt_p(BIO_new(method.0.get()))?; + BIO_set_data(bio, Box::into_raw(state) as *mut _); + BIO_set_init(bio, 1); + + return Ok((bio, method)); + } +} + +pub unsafe fn take_error(bio: *mut BIO) -> Option { + let state = state::(bio); + state.error.take() +} + +pub unsafe fn take_panic(bio: *mut BIO) -> Option> { + let state = state::(bio); + state.panic.take() +} + +pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { + let state: &'a StreamState = mem::transmute(BIO_get_data(bio)); + &state.stream +} + +pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { + &mut state(bio).stream +} + +unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { + &mut *(BIO_get_data(bio) as *mut _) +} + +unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { + BIO_clear_retry_flags(bio); + + let state = state::(bio); + let buf = slice::from_raw_parts(buf as *const _, len as usize); + + match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) { + Ok(Ok(len)) => len as c_int, + Ok(Err(err)) => { + if retriable_error(&err) { + BIO_set_retry_write(bio); + } + state.error = Some(err); + -1 + } + Err(err) => { + state.panic = Some(err); + -1 + } + } +} + +unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { + BIO_clear_retry_flags(bio); + + let state = state::(bio); + let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); + + match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) { + Ok(Ok(len)) => len as c_int, + Ok(Err(err)) => { + if retriable_error(&err) { + BIO_set_retry_read(bio); + } + state.error = Some(err); + -1 + } + Err(err) => { + state.panic = Some(err); + -1 + } + } +} + +fn retriable_error(err: &io::Error) -> bool { + match err.kind() { + io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true, + _ => false, + } +} + +unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { + bwrite::(bio, s, strlen(s) as c_int) +} + +unsafe extern "C" fn ctrl( + bio: *mut BIO, + cmd: c_int, + _num: c_long, + _ptr: *mut c_void, +) -> c_long { + if cmd == BIO_CTRL_FLUSH { + let state = state::(bio); + + match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) { + Ok(Ok(())) => 1, + Ok(Err(err)) => { + state.error = Some(err); + 0 + } + Err(err) => { + state.panic = Some(err); + 0 + } + } + } else { + 0 + } +} + +unsafe extern "C" fn create(bio: *mut BIO) -> c_int { + BIO_set_init(bio, 0); + BIO_set_num(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_flags(bio, 0); + 1 +} + +unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { + if bio.is_null() { + return 0; + } + + let data = BIO_get_data(bio); + assert!(!data.is_null()); + Box::>::from_raw(data as *mut _); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_init(bio, 0); + 1 +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init}; + + #[allow(bad_style)] + unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} + + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> BIO_METHOD { + unsafe { + let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); + assert!(!ptr.is_null()); + let ret = BIO_METHOD(ptr); + assert!(ffi::BIO_meth_set_write(ptr, bwrite::) != 0); + assert!(ffi::BIO_meth_set_read(ptr, bread::) != 0); + assert!(ffi::BIO_meth_set_puts(ptr, bputs::) != 0); + assert!(ffi::BIO_meth_set_ctrl(ptr, ctrl::) != 0); + assert!(ffi::BIO_meth_set_create(ptr, create) != 0); + assert!(ffi::BIO_meth_set_destroy(ptr, destroy::) != 0); + return ret; + } + } + + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 + } + } + + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + ffi::BIO_meth_free(self.0); + } + } + } + } else { + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> BIO_METHOD { + let ptr = Box::new(ffi::BIO_METHOD { + type_: ffi::BIO_TYPE_NONE, + name: b"rust\0".as_ptr() as *const _, + bwrite: Some(bwrite::), + bread: Some(bread::), + bputs: Some(bputs::), + bgets: None, + ctrl: Some(ctrl::), + create: Some(create), + destroy: Some(destroy::), + callback_ctrl: None, + }); + + BIO_METHOD(Box::into_raw(ptr)) + } + + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 + } + } + + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + Box::::from_raw(self.0); + } + } + } + + #[allow(bad_style)] + unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { + (*bio).init = init; + } + + #[allow(bad_style)] + unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { + (*bio).flags = flags; + } + + #[allow(bad_style)] + unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { + (*bio).ptr + } + + #[allow(bad_style)] + unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { + (*bio).ptr = data; + } + + #[allow(bad_style)] + unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { + (*bio).num = num; + } + } +} diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs new file mode 100644 index 000000000..b02518343 --- /dev/null +++ b/openssl/src/ssl/callbacks.rs @@ -0,0 +1,686 @@ +use ffi; +use foreign_types::ForeignType; +use foreign_types::ForeignTypeRef; +#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] +use libc::c_char; +#[cfg(ossl111)] +use libc::size_t; +use libc::{c_int, c_uchar, c_uint, c_void}; +#[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] +use std::ffi::CStr; +use std::mem; +use std::ptr; +use std::slice; +#[cfg(ossl111)] +use std::str; +use std::sync::Arc; + +use dh::Dh; +#[cfg(all(ossl101, not(ossl110)))] +use ec::EcKey; +use error::ErrorStack; +use pkey::Params; +#[cfg(any(ossl102, libressl261))] +use ssl::AlpnError; +#[cfg(ossl111)] +use ssl::{ClientHelloResponse, ExtensionContext}; +use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef, SESSION_CTX_INDEX}; +#[cfg(ossl111)] +use x509::X509Ref; +use x509::{X509StoreContext, X509StoreContextRef}; + +pub extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int +where + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, +{ + unsafe { + let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); + let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); + let verify_idx = SslContext::cached_ex_index::(); + + // raw pointer shenanigans to break the borrow of ctx + // the callback can't mess with its own ex_data slot so this is safe + let verify = ctx + .ex_data(ssl_idx) + .expect("BUG: store context missing ssl") + .ssl_context() + .ex_data(verify_idx) + .expect("BUG: verify callback missing") as *const F; + + (*verify)(preverify_ok != 0, ctx) as c_int + } +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +pub extern "C" fn raw_client_psk( + ssl: *mut ffi::SSL, + hint: *const c_char, + identity: *mut c_char, + max_identity_len: c_uint, + psk: *mut c_uchar, + max_psk_len: c_uint, +) -> c_uint +where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + + 'static + + Sync + + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback_idx = SslContext::cached_ex_index::(); + + let callback = ssl + .ssl_context() + .ex_data(callback_idx) + .expect("BUG: psk callback missing") as *const F; + let hint = if !hint.is_null() { + Some(CStr::from_ptr(hint).to_bytes()) + } else { + None + }; + // Give the callback mutable slices into which it can write the identity and psk. + let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize); + let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + match (*callback)(ssl, hint, identity_sl, psk_sl) { + Ok(psk_len) => psk_len as u32, + Err(e) => { + e.put(); + 0 + } + } + } +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +pub extern "C" fn raw_server_psk( + ssl: *mut ffi::SSL, + identity: *const c_char, + psk: *mut c_uchar, + max_psk_len: c_uint, +) -> c_uint +where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + + 'static + + Sync + + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback_idx = SslContext::cached_ex_index::(); + + let callback = ssl + .ssl_context() + .ex_data(callback_idx) + .expect("BUG: psk callback missing") as *const F; + let identity = if identity != ptr::null() { + Some(CStr::from_ptr(identity).to_bytes()) + } else { + None + }; + // Give the callback mutable slices into which it can write the psk. + let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + match (*callback)(ssl, identity, psk_sl) { + Ok(psk_len) => psk_len as u32, + Err(e) => { + e.put(); + 0 + } + } + } +} + +pub extern "C" fn ssl_raw_verify( + preverify_ok: c_int, + x509_ctx: *mut ffi::X509_STORE_CTX, +) -> c_int +where + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, +{ + unsafe { + let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); + let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); + let callback_idx = Ssl::cached_ex_index::>(); + + let callback = ctx + .ex_data(ssl_idx) + .expect("BUG: store context missing ssl") + .ex_data(callback_idx) + .expect("BUG: ssl verify callback missing") + .clone(); + + callback(preverify_ok != 0, ctx) as c_int + } +} + +pub extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void) -> c_int +where + F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = arg as *const F; + let mut alert = SslAlert(*al); + + let r = (*callback)(ssl, &mut alert); + *al = alert.0; + match r { + Ok(()) => ffi::SSL_TLSEXT_ERR_OK, + Err(e) => e.0, + } + } +} + +#[cfg(any(ossl102, libressl261))] +pub extern "C" fn raw_alpn_select( + ssl: *mut ffi::SSL, + out: *mut *const c_uchar, + outlen: *mut c_uchar, + inbuf: *const c_uchar, + inlen: c_uint, + _arg: *mut c_void, +) -> c_int +where + F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: alpn callback missing") as *const F; + let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); + + match (*callback)(ssl, protos) { + Ok(proto) => { + *out = proto.as_ptr() as *const c_uchar; + *outlen = proto.len() as c_uchar; + ffi::SSL_TLSEXT_ERR_OK + } + Err(e) => e.0, + } + } +} + +pub unsafe extern "C" fn raw_tmp_dh( + ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int, +) -> *mut ffi::DH +where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: tmp dh callback missing") as *const F; + + match (*callback)(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(e) => { + e.put(); + ptr::null_mut() + } + } +} + +#[cfg(all(ossl101, not(ossl110)))] +pub unsafe extern "C" fn raw_tmp_ecdh( + ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int, +) -> *mut ffi::EC_KEY +where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: tmp ecdh callback missing") as *const F; + + match (*callback)(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(e) => { + e.put(); + ptr::null_mut() + } + } +} + +pub unsafe extern "C" fn raw_tmp_dh_ssl( + ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int, +) -> *mut ffi::DH +where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) + .expect("BUG: ssl tmp dh callback missing") + .clone(); + + match callback(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(e) => { + e.put(); + ptr::null_mut() + } + } +} + +#[cfg(all(ossl101, not(ossl110)))] +pub unsafe extern "C" fn raw_tmp_ecdh_ssl( + ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int, +) -> *mut ffi::EC_KEY +where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) + .expect("BUG: ssl tmp ecdh callback missing") + .clone(); + + match callback(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(e) => { + e.put(); + ptr::null_mut() + } + } +} + +pub unsafe extern "C" fn raw_tlsext_status(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int +where + F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: ocsp callback missing") as *const F; + let ret = (*callback)(ssl); + + if ssl.is_server() { + match ret { + Ok(true) => ffi::SSL_TLSEXT_ERR_OK, + Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK, + Err(e) => { + e.put(); + ffi::SSL_TLSEXT_ERR_ALERT_FATAL + } + } + } else { + match ret { + Ok(true) => 1, + Ok(false) => 0, + Err(e) => { + e.put(); + -1 + } + } + } +} + +pub unsafe extern "C" fn raw_new_session( + ssl: *mut ffi::SSL, + session: *mut ffi::SSL_SESSION, +) -> c_int +where + F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(*SESSION_CTX_INDEX) + .expect("BUG: session context missing") + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: new session callback missing") as *const F; + let session = SslSession::from_ptr(session); + + (*callback)(ssl, session); + + // the return code doesn't indicate error vs success, but whether or not we consumed the session + 1 +} + +pub unsafe extern "C" fn raw_remove_session( + ctx: *mut ffi::SSL_CTX, + session: *mut ffi::SSL_SESSION, +) where + F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, +{ + let ctx = SslContextRef::from_ptr(ctx); + let callback = ctx + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: remove session callback missing"); + let session = SslSessionRef::from_ptr(session); + + callback(ctx, session) +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + type DataPtr = *const c_uchar; + } else { + type DataPtr = *mut c_uchar; + } +} + +pub unsafe extern "C" fn raw_get_session( + ssl: *mut ffi::SSL, + data: DataPtr, + len: c_int, + copy: *mut c_int, +) -> *mut ffi::SSL_SESSION +where + F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ex_data(*SESSION_CTX_INDEX) + .expect("BUG: session context missing") + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: get session callback missing") as *const F; + let data = slice::from_raw_parts(data as *const u8, len as usize); + + match (*callback)(ssl, data) { + Some(session) => { + let p = session.as_ptr(); + mem::forget(session); + *copy = 0; + p + } + None => ptr::null_mut(), + } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_keylog(ssl: *const ffi::SSL, line: *const c_char) +where + F: Fn(&SslRef, &str) + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr(ssl as *mut _); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: get session callback missing"); + let line = CStr::from_ptr(line).to_bytes(); + let line = str::from_utf8_unchecked(line); + + callback(ssl, line); +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_stateless_cookie_generate( + ssl: *mut ffi::SSL, + cookie: *mut c_uchar, + cookie_len: *mut size_t, +) -> c_int +where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: stateless cookie generate callback missing") as *const F; + let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); + match (*callback)(ssl, slice) { + Ok(len) => { + *cookie_len = len as size_t; + 1 + } + Err(e) => { + e.put(); + 0 + } + } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_stateless_cookie_verify( + ssl: *mut ffi::SSL, + cookie: *const c_uchar, + cookie_len: size_t, +) -> c_int +where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: stateless cookie verify callback missing") as *const F; + let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); + (*callback)(ssl, slice) as c_int +} + +pub extern "C" fn raw_cookie_generate( + ssl: *mut ffi::SSL, + cookie: *mut c_uchar, + cookie_len: *mut c_uint, +) -> c_int +where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: cookie generate callback missing") as *const F; + // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for + // compatibility. See comments in dtls1.h. + let slice = + slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1); + match (*callback)(ssl, slice) { + Ok(len) => { + *cookie_len = len as c_uint; + 1 + } + Err(e) => { + e.put(); + 0 + } + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + type CookiePtr = *const c_uchar; + } else { + type CookiePtr = *mut c_uchar; + } +} + +pub extern "C" fn raw_cookie_verify( + ssl: *mut ffi::SSL, + cookie: CookiePtr, + cookie_len: c_uint, +) -> c_int +where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: cookie verify callback missing") as *const F; + let slice = + slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); + (*callback)(ssl, slice) as c_int + } +} + +#[cfg(ossl111)] +pub struct CustomExtAddState(Option); + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_add( + ssl: *mut ffi::SSL, + _: c_uint, + context: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + x: *mut ffi::X509, + chainidx: size_t, + al: *mut c_int, + _: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) -> Result, SslAlert> + + 'static + + Sync + + Send, + T: AsRef<[u8]> + 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: custom ext add callback missing") as *const F; + let ectx = ExtensionContext::from_bits_truncate(context); + let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { + Some((chainidx, X509Ref::from_ptr(x))) + } else { + None + }; + match (*callback)(ssl, ectx, cert) { + Ok(None) => 0, + Ok(Some(buf)) => { + *outlen = buf.as_ref().len(); + *out = buf.as_ref().as_ptr(); + + let idx = Ssl::cached_ex_index::>(); + let mut buf = Some(buf); + let new = match ssl.ex_data_mut(idx) { + Some(state) => { + state.0 = buf.take(); + false + } + None => true, + }; + if new { + ssl.set_ex_data(idx, CustomExtAddState(buf)); + } + 1 + } + Err(alert) => { + *al = alert.0; + -1 + } + } + } +} + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_free( + ssl: *mut ffi::SSL, + _: c_uint, + _: c_uint, + _: *mut *const c_uchar, + _: *mut c_void, +) where + T: 'static + Sync + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let idx = Ssl::cached_ex_index::>(); + if let Some(state) = ssl.ex_data_mut(idx) { + state.0 = None; + } + } +} + +#[cfg(ossl111)] +pub extern "C" fn raw_custom_ext_parse( + ssl: *mut ffi::SSL, + _: c_uint, + context: c_uint, + input: *const c_uchar, + inlen: size_t, + x: *mut ffi::X509, + chainidx: size_t, + al: *mut c_int, + _: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert> + + 'static + + Sync + + Send, +{ + unsafe { + let ssl = SslRef::from_ptr_mut(ssl); + let callback = ssl + .ssl_context() + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: custom ext parse callback missing") as *const F; + let ectx = ExtensionContext::from_bits_truncate(context); + let slice = slice::from_raw_parts(input as *const u8, inlen as usize); + let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { + Some((chainidx, X509Ref::from_ptr(x))) + } else { + None + }; + match (*callback)(ssl, ectx, slice, cert) { + Ok(()) => 1, + Err(alert) => { + *al = alert.0; + 0 + } + } + } +} + +#[cfg(ossl111)] +pub unsafe extern "C" fn raw_client_hello( + ssl: *mut ffi::SSL, + al: *mut c_int, + arg: *mut c_void, +) -> c_int +where + F: Fn(&mut SslRef, &mut SslAlert) -> Result + + 'static + + Sync + + Send, +{ + let ssl = SslRef::from_ptr_mut(ssl); + let callback = arg as *const F; + let mut alert = SslAlert(*al); + + let r = (*callback)(ssl, &mut alert); + *al = alert.0; + match r { + Ok(c) => c.0, + Err(e) => { + e.put(); + ffi::SSL_CLIENT_HELLO_ERROR + } + } +} diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs new file mode 100644 index 000000000..5def68b21 --- /dev/null +++ b/openssl/src/ssl/connector.rs @@ -0,0 +1,507 @@ +use std::io::{Read, Write}; +use std::ops::{Deref, DerefMut}; + +use dh::Dh; +use error::ErrorStack; +use ssl::{ + HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, SslRef, + SslStream, SslVerifyMode, +}; +use version; + +fn ctx(method: SslMethod) -> Result { + let mut ctx = SslContextBuilder::new(method)?; + + let mut opts = SslOptions::ALL + | SslOptions::NO_COMPRESSION + | SslOptions::NO_SSLV2 + | SslOptions::NO_SSLV3 + | SslOptions::SINGLE_DH_USE + | SslOptions::SINGLE_ECDH_USE + | SslOptions::CIPHER_SERVER_PREFERENCE; + opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS; + + ctx.set_options(opts); + + let mut mode = + SslMode::AUTO_RETRY | SslMode::ACCEPT_MOVING_WRITE_BUFFER | SslMode::ENABLE_PARTIAL_WRITE; + + // This is quite a useful optimization for saving memory, but historically + // caused CVEs in OpenSSL pre-1.0.1h, according to + // https://bugs.python.org/issue25672 + if version::number() >= 0x1_00_01_08_0 { + mode |= SslMode::RELEASE_BUFFERS; + } + + ctx.set_mode(mode); + + Ok(ctx) +} + +/// A type which wraps client-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, hostname verification, and more. +/// +/// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, +/// and a custom implementation is used when linking against OpenSSL 1.0.1. +#[derive(Clone)] +pub struct SslConnector(SslContext); + +impl SslConnector { + /// Creates a new builder for TLS connections. + /// + /// The default configuration is subject to change, and is currently derived from Python. + pub fn builder(method: SslMethod) -> Result { + let mut ctx = ctx(method)?; + ctx.set_default_verify_paths()?; + ctx.set_cipher_list( + "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK", + )?; + setup_verify(&mut ctx); + + Ok(SslConnectorBuilder(ctx)) + } + + /// Initiates a client-side TLS session on a stream. + /// + /// The domain is used for SNI and hostname verification. + pub fn connect(&self, domain: &str, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + self.configure()?.connect(domain, stream) + } + + /// Returns a structure allowing for configuration of a single TLS session before connection. + pub fn configure(&self) -> Result { + Ssl::new(&self.0).map(|ssl| ConnectConfiguration { + ssl, + sni: true, + verify_hostname: true, + }) + } +} + +/// A builder for `SslConnector`s. +pub struct SslConnectorBuilder(SslContextBuilder); + +impl SslConnectorBuilder { + /// Consumes the builder, returning an `SslConnector`. + pub fn build(self) -> SslConnector { + SslConnector(self.0.build()) + } +} + +impl Deref for SslConnectorBuilder { + type Target = SslContextBuilder; + + fn deref(&self) -> &SslContextBuilder { + &self.0 + } +} + +impl DerefMut for SslConnectorBuilder { + fn deref_mut(&mut self) -> &mut SslContextBuilder { + &mut self.0 + } +} + +/// A type which allows for configuration of a client-side TLS session before connection. +pub struct ConnectConfiguration { + ssl: Ssl, + sni: bool, + verify_hostname: bool, +} + +impl ConnectConfiguration { + /// A builder-style version of `set_use_server_name_indication`. + pub fn use_server_name_indication(mut self, use_sni: bool) -> ConnectConfiguration { + self.set_use_server_name_indication(use_sni); + self + } + + /// Configures the use of Server Name Indication (SNI) when connecting. + /// + /// Defaults to `true`. + pub fn set_use_server_name_indication(&mut self, use_sni: bool) { + self.sni = use_sni; + } + + /// A builder-style version of `set_verify_hostname`. + pub fn verify_hostname(mut self, verify_hostname: bool) -> ConnectConfiguration { + self.set_verify_hostname(verify_hostname); + self + } + + /// Configures the use of hostname verification when connecting. + /// + /// Defaults to `true`. + /// + /// # Warning + /// + /// You should think very carefully before you use this method. If hostname verification is not + /// used, *any* valid certificate for *any* site will be trusted for use from any other. This + /// introduces a significant vulnerability to man-in-the-middle attacks. + pub fn set_verify_hostname(&mut self, verify_hostname: bool) { + self.verify_hostname = verify_hostname; + } + + /// Initiates a client-side TLS session on a stream. + /// + /// The domain is used for SNI and hostname verification if enabled. + pub fn connect(mut self, domain: &str, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + if self.sni { + self.ssl.set_hostname(domain)?; + } + + if self.verify_hostname { + setup_verify_hostname(&mut self.ssl, domain)?; + } + + self.ssl.connect(stream) + } +} + +impl Deref for ConnectConfiguration { + type Target = SslRef; + + fn deref(&self) -> &SslRef { + &self.ssl + } +} + +impl DerefMut for ConnectConfiguration { + fn deref_mut(&mut self) -> &mut SslRef { + &mut self.ssl + } +} + +/// A type which wraps server-side streams in a TLS session. +/// +/// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL +/// structures, configuring cipher suites, session options, and more. +#[derive(Clone)] +pub struct SslAcceptor(SslContext); + +impl SslAcceptor { + /// Creates a new builder configured to connect to non-legacy clients. This should generally be + /// considered a reasonable default choice. + /// + /// This corresponds to the intermediate configuration of Mozilla's server side TLS + /// recommendations. See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + pub fn mozilla_intermediate(method: SslMethod) -> Result { + let mut ctx = ctx(method)?; + #[cfg(ossl111)] + ctx.set_options(SslOptions::NO_TLSV1_3); + let dh = Dh::params_from_pem( + b" +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== +-----END DH PARAMETERS----- +", + )?; + ctx.set_tmp_dh(&dh)?; + setup_curves(&mut ctx)?; + ctx.set_cipher_list( + "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\ + ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ + DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\ + ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\ + ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\ + DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ + EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\ + AES256-SHA:DES-CBC3-SHA:!DSS", + )?; + Ok(SslAcceptorBuilder(ctx)) + } + + /// Creates a new builder configured to connect to modern clients. + /// + /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. + /// See its [documentation][docs] for more details on specifics. + /// + /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS + pub fn mozilla_modern(method: SslMethod) -> Result { + let mut ctx = ctx(method)?; + ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1); + #[cfg(ossl111)] + ctx.set_options(SslOptions::NO_TLSV1_3); + setup_curves(&mut ctx)?; + ctx.set_cipher_list( + "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:\ + ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ + ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", + )?; + Ok(SslAcceptorBuilder(ctx)) + } + + /// Initiates a server-side TLS session on a stream. + pub fn accept(&self, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + let ssl = Ssl::new(&self.0)?; + ssl.accept(stream) + } +} + +/// A builder for `SslAcceptor`s. +pub struct SslAcceptorBuilder(SslContextBuilder); + +impl SslAcceptorBuilder { + /// Consumes the builder, returning a `SslAcceptor`. + pub fn build(self) -> SslAcceptor { + SslAcceptor(self.0.build()) + } +} + +impl Deref for SslAcceptorBuilder { + type Target = SslContextBuilder; + + fn deref(&self) -> &SslContextBuilder { + &self.0 + } +} + +impl DerefMut for SslAcceptorBuilder { + fn deref_mut(&mut self) -> &mut SslContextBuilder { + &mut self.0 + } +} + +cfg_if! { + if #[cfg(ossl110)] { + fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { + Ok(()) + } + } else if #[cfg(any(ossl102, libressl))] { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + ctx.set_ecdh_auto(true) + } + } else { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + use ec::EcKey; + use nid::Nid; + + let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; + ctx.set_tmp_ecdh(&curve) + } + } +} + +cfg_if! { + if #[cfg(any(ossl102, libressl261))] { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify(SslVerifyMode::PEER); + } + + fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> { + use x509::verify::X509CheckFlags; + + let param = ssl.param_mut(); + param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + match domain.parse() { + Ok(ip) => param.set_ip(ip), + Err(_) => param.set_host(domain), + } + } + } else { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); + } + + fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { + let domain = domain.to_string(); + ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); + Ok(()) + } + + mod verify { + use std::net::IpAddr; + use std::str; + + use ex_data::Index; + use nid::Nid; + use ssl::Ssl; + use stack::Stack; + use x509::{ + GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, + X509VerifyResult, + }; + + lazy_static! { + pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); + } + + pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { + if !preverify_ok || x509_ctx.error_depth() != 0 { + return preverify_ok; + } + + let ok = match ( + x509_ctx.current_cert(), + X509StoreContext::ssl_idx() + .ok() + .and_then(|idx| x509_ctx.ex_data(idx)) + .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), + ) { + (Some(x509), Some(domain)) => verify_hostname(domain, &x509), + _ => true, + }; + + if !ok { + x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } + + ok + } + + fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { + match cert.subject_alt_names() { + Some(names) => verify_subject_alt_names(domain, names), + None => verify_subject_name(domain, &cert.subject_name()), + } + } + + fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { + let ip = domain.parse(); + + for name in &names { + match ip { + Ok(ip) => { + if let Some(actual) = name.ipaddress() { + if matches_ip(&ip, actual) { + return true; + } + } + } + Err(_) => { + if let Some(pattern) = name.dnsname() { + if matches_dns(pattern, domain) { + return true; + } + } + } + } + } + + false + } + + fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { + match subject_name.entries_by_nid(Nid::COMMONNAME).next() { + Some(pattern) => { + let pattern = match str::from_utf8(pattern.data().as_slice()) { + Ok(pattern) => pattern, + Err(_) => return false, + }; + + // Unlike SANs, IP addresses in the subject name don't have a + // different encoding. + match domain.parse::() { + Ok(ip) => pattern + .parse::() + .ok() + .map_or(false, |pattern| pattern == ip), + Err(_) => matches_dns(pattern, domain), + } + } + None => false, + } + } + + fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { + // first strip trailing . off of pattern and hostname to normalize + if pattern.ends_with('.') { + pattern = &pattern[..pattern.len() - 1]; + } + if hostname.ends_with('.') { + hostname = &hostname[..hostname.len() - 1]; + } + + matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) + } + + fn matches_wildcard(pattern: &str, hostname: &str) -> Option { + // internationalized domains can't involved in wildcards + if pattern.starts_with("xn--") { + return None; + } + + let wildcard_location = match pattern.find('*') { + Some(l) => l, + None => return None, + }; + + let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); + let wildcard_end = match dot_idxs.next() { + Some(l) => l, + None => return None, + }; + + // Never match wildcards if the pattern has less than 2 '.'s (no *.com) + // + // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. + // Chrome has a black- and white-list for this, but Firefox (via NSS) does + // the same thing we do here. + // + // The Public Suffix (https://www.publicsuffix.org/) list could + // potentially be used here, but it's both huge and updated frequently + // enough that management would be a PITA. + if dot_idxs.next().is_none() { + return None; + } + + // Wildcards can only be in the first component + if wildcard_location > wildcard_end { + return None; + } + + let hostname_label_end = match hostname.find('.') { + Some(l) => l, + None => return None, + }; + + // check that the non-wildcard parts are identical + if pattern[wildcard_end..] != hostname[hostname_label_end..] { + return Some(false); + } + + let wildcard_prefix = &pattern[..wildcard_location]; + let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + + let hostname_label = &hostname[..hostname_label_end]; + + // check the prefix of the first label + if !hostname_label.starts_with(wildcard_prefix) { + return Some(false); + } + + // and the suffix + if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { + return Some(false); + } + + Some(true) + } + + fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { + match *expected { + IpAddr::V4(ref addr) => actual == addr.octets(), + IpAddr::V6(ref addr) => actual == addr.octets(), + } + } + } + } +} diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs new file mode 100644 index 000000000..e5e8991a1 --- /dev/null +++ b/openssl/src/ssl/error.rs @@ -0,0 +1,191 @@ +use ffi; +use libc::c_int; +use std::error; +use std::error::Error as StdError; +use std::fmt; +use std::io; + +use error::ErrorStack; +use ssl::MidHandshakeSslStream; +use x509::X509VerifyResult; + +/// An error code returned from SSL functions. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ErrorCode(c_int); + +impl ErrorCode { + pub fn from_raw(raw: c_int) -> ErrorCode { + ErrorCode(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// The SSL session has been closed. + pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN); + + /// An attempt to read data from the underlying socket returned `WouldBlock`. + /// + /// Wait for read readiness and retry the operation. + pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ); + + /// An attempt to write data to the underlying socket returned `WouldBlock`. + /// + /// Wait for write readiness and retry the operation. + pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE); + + /// A non-recoverable IO error occurred. + pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL); + + /// An error occurred in the SSL library. + pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); + + /// The client hello callback indicated that it needed to be retried. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[cfg(ossl111)] + pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); +} + +#[derive(Debug)] +pub(crate) enum InnerError { + Io(io::Error), + Ssl(ErrorStack), +} + +/// An SSL error. +#[derive(Debug)] +pub struct Error { + pub(crate) code: ErrorCode, + pub(crate) cause: Option, +} + +impl Error { + pub fn code(&self) -> ErrorCode { + self.code + } + + pub fn io_error(&self) -> Option<&io::Error> { + match self.cause { + Some(InnerError::Io(ref e)) => Some(e), + _ => None, + } + } + + pub fn into_io_error(self) -> Result { + match self.cause { + Some(InnerError::Io(e)) => Ok(e), + _ => Err(self), + } + } + + pub fn ssl_error(&self) -> Option<&ErrorStack> { + match self.cause { + Some(InnerError::Ssl(ref e)) => Some(e), + _ => None, + } + } +} + +impl From for Error { + fn from(e: ErrorStack) -> Error { + Error { + code: ErrorCode::SSL, + cause: Some(InnerError::Ssl(e)), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.code { + ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"), + ErrorCode::WANT_READ => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking read call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, + ErrorCode::WANT_WRITE => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking write call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, + ErrorCode::SYSCALL => match self.io_error() { + Some(err) => write!(fmt, "{}", err), + None => fmt.write_str("unexpected EOF"), + }, + ErrorCode::SSL => match self.ssl_error() { + Some(e) => write!(fmt, "{}", e), + None => fmt.write_str("OpenSSL error"), + }, + ErrorCode(code) => write!(fmt, "unknown error code {}", code), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + "an OpenSSL error" + } + + fn cause(&self) -> Option<&error::Error> { + match self.cause { + Some(InnerError::Io(ref e)) => Some(e), + Some(InnerError::Ssl(ref e)) => Some(e), + None => None, + } + } +} + +/// An error or intermediate state after a TLS handshake attempt. +// FIXME overhaul +#[derive(Debug)] +pub enum HandshakeError { + /// Setup failed. + SetupFailure(ErrorStack), + /// The handshake failed. + Failure(MidHandshakeSslStream), + /// The handshake encountered a `WouldBlock` error midway through. + /// + /// This error will never be returned for blocking streams. + WouldBlock(MidHandshakeSslStream), +} + +impl StdError for HandshakeError { + fn description(&self) -> &str { + match *self { + HandshakeError::SetupFailure(_) => "stream setup failed", + HandshakeError::Failure(_) => "the handshake failed", + HandshakeError::WouldBlock(_) => "the handshake was interrupted", + } + } + + fn cause(&self) -> Option<&StdError> { + match *self { + HandshakeError::SetupFailure(ref e) => Some(e), + HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()), + } + } +} + +impl fmt::Display for HandshakeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(StdError::description(self))?; + match *self { + HandshakeError::SetupFailure(ref e) => write!(f, ": {}", e)?, + HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => { + write!(f, ": {}", s.error())?; + let verify = s.ssl().verify_result(); + if verify != X509VerifyResult::OK { + write!(f, ": {}", verify)?; + } + } + } + Ok(()) + } +} + +impl From for HandshakeError { + fn from(e: ErrorStack) -> HandshakeError { + HandshakeError::SetupFailure(e) + } +} diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs new file mode 100644 index 000000000..c1b86abf9 --- /dev/null +++ b/openssl/src/ssl/mod.rs @@ -0,0 +1,3895 @@ +//! SSL/TLS support. +//! +//! `SslConnector` and `SslAcceptor` should be used in most cases - they handle +//! configuration of the OpenSSL primitives for you. +//! +//! # Examples +//! +//! To connect as a client to a remote server: +//! +//! ```no_run +//! use openssl::ssl::{SslMethod, SslConnector}; +//! use std::io::{Read, Write}; +//! use std::net::TcpStream; +//! +//! let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); +//! +//! let stream = TcpStream::connect("google.com:443").unwrap(); +//! let mut stream = connector.connect("google.com", stream).unwrap(); +//! +//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); +//! let mut res = vec![]; +//! stream.read_to_end(&mut res).unwrap(); +//! println!("{}", String::from_utf8_lossy(&res)); +//! ``` +//! +//! To accept connections as a server from remote clients: +//! +//! ```no_run +//! use openssl::ssl::{SslMethod, SslAcceptor, SslStream, SslFiletype}; +//! use std::net::{TcpListener, TcpStream}; +//! use std::sync::Arc; +//! use std::thread; +//! +//! +//! let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); +//! acceptor.set_private_key_file("key.pem", SslFiletype::PEM).unwrap(); +//! acceptor.set_certificate_chain_file("certs.pem").unwrap(); +//! acceptor.check_private_key().unwrap(); +//! let acceptor = Arc::new(acceptor.build()); +//! +//! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); +//! +//! fn handle_client(stream: SslStream) { +//! // ... +//! } +//! +//! for stream in listener.incoming() { +//! match stream { +//! Ok(stream) => { +//! let acceptor = acceptor.clone(); +//! thread::spawn(move || { +//! let stream = acceptor.accept(stream).unwrap(); +//! handle_client(stream); +//! }); +//! } +//! Err(e) => { /* connection failed */ } +//! } +//! } +//! ``` +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void}; +use std::any::TypeId; +use std::cmp; +use std::collections::HashMap; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::io; +use std::io::prelude::*; +use std::marker::PhantomData; +use std::mem::{self, ManuallyDrop}; +use std::ops::{Deref, DerefMut}; +use std::panic::resume_unwind; +use std::path::Path; +use std::ptr; +use std::slice; +use std::str; +use std::sync::{Arc, Mutex}; + +use dh::{Dh, DhRef}; +#[cfg(all(ossl101, not(ossl110)))] +use ec::EcKey; +use ec::EcKeyRef; +use error::ErrorStack; +use ex_data::Index; +#[cfg(ossl111)] +use hash::MessageDigest; +#[cfg(ossl110)] +use nid::Nid; +use pkey::{HasPrivate, PKeyRef, Params, Private}; +use srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; +use ssl::bio::BioMethod; +use ssl::callbacks::*; +use ssl::error::InnerError; +use stack::{Stack, StackRef}; +#[cfg(ossl102)] +use x509::store::X509Store; +use x509::store::{X509StoreBuilderRef, X509StoreRef}; +#[cfg(any(ossl102, libressl261))] +use x509::verify::X509VerifyParamRef; +use x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509}; +use {cvt, cvt_n, cvt_p, init}; + +pub use ssl::connector::{ + ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, +}; +pub use ssl::error::{Error, ErrorCode, HandshakeError}; + +mod bio; +mod callbacks; +mod connector; +mod error; +#[cfg(test)] +mod test; + +/// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name. +/// +/// If the cipher has no corresponding OpenSSL name, the string `(NONE)` is returned. +/// +/// Requires OpenSSL 1.1.1 or newer. +/// +/// This corresponds to [`OPENSSL_cipher_name`] +/// +/// [`OPENSSL_cipher_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html +#[cfg(ossl111)] +pub fn cipher_name(std_name: &str) -> &'static str { + unsafe { + ffi::init(); + + let s = CString::new(std_name).unwrap(); + let ptr = ffi::OPENSSL_cipher_name(s.as_ptr()); + CStr::from_ptr(ptr).to_str().unwrap() + } +} + +bitflags! { + /// Options controlling the behavior of an `SslContext`. + pub struct SslOptions: c_ulong { + /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers. + const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + + /// A "reasonable default" set of options which enables compatibility flags. + const ALL = ffi::SSL_OP_ALL; + + /// Do not query the MTU. + /// + /// Only affects DTLS connections. + const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU; + + /// Enables Cookie Exchange as described in [RFC 4347 Section 4.2.1]. + /// + /// Only affects DTLS connections. + /// + /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1 + const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE; + + /// Disables the use of session tickets for session resumption. + const NO_TICKET = ffi::SSL_OP_NO_TICKET; + + /// Always start a new session when performing a renegotiation on the server side. + const NO_SESSION_RESUMPTION_ON_RENEGOTIATION = + ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; + + /// Disables the use of TLS compression. + const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION; + + /// Allow legacy insecure renegotiation with servers or clients that do not support secure + /// renegotiation. + const ALLOW_UNSAFE_LEGACY_RENEGOTIATION = + ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; + + /// Creates a new key for each session when using ECDHE. + /// + /// This is always enabled in OpenSSL 1.1.0. + const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE; + + /// Creates a new key for each session when using DHE. + /// + /// This is always enabled in OpenSSL 1.1.0. + const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE; + + /// Use the server's preferences rather than the client's when selecting a cipher. + /// + /// This has no effect on the client side. + const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE; + + /// Disables version rollback attach detection. + const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG; + + /// Disables the use of SSLv2. + const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2; + + /// Disables the use of SSLv3. + const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3; + + /// Disables the use of TLSv1.0. + const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1; + + /// Disables the use of TLSv1.1. + const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1; + + /// Disables the use of TLSv1.2. + const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2; + + /// Disables the use of TLSv1.3. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[cfg(ossl111)] + const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3; + + /// Disables the use of DTLSv1.0 + /// + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(any(ossl102, ossl110))] + const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1; + + /// Disables the use of DTLSv1.2. + /// + /// Requires OpenSSL 1.0.2, or newer. + #[cfg(any(ossl102, ossl110))] + const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2; + + /// Disables the use of all (D)TLS protocol versions. + /// + /// This can be used as a mask when whitelisting protocol versions. + /// + /// Requires OpenSSL 1.0.2 or newer. + /// + /// # Examples + /// + /// Only support TLSv1.2: + /// + /// ```rust + /// use openssl::ssl::SslOptions; + /// + /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2; + /// ``` + #[cfg(any(ossl102, ossl110))] + const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK; + + /// Enable TLSv1.3 Compatibility mode. + /// + /// Requires OpenSSL 1.1.1 or newer. This is on by default in 1.1.1, but a future version + /// may have this disabled by default. + #[cfg(ossl111)] + const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT; + } +} + +bitflags! { + /// Options controlling the behavior of an `SslContext`. + pub struct SslMode: c_long { + /// Enables "short writes". + /// + /// Normally, a write in OpenSSL will always write out all of the requested data, even if it + /// requires more than one TLS record or write to the underlying stream. This option will + /// cause a write to return after writing a single TLS record instead. + const ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE; + + /// Disables a check that the data buffer has not moved between calls when operating in a + /// nonblocking context. + const ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; + + /// Enables automatic retries after TLS session events such as renegotiations or heartbeats. + /// + /// By default, OpenSSL will return a `WantRead` error after a renegotiation or heartbeat. + /// This option will cause OpenSSL to automatically continue processing the requested + /// operation instead. + /// + /// Note that `SslStream::read` and `SslStream::write` will automatically retry regardless + /// of the state of this option. It only affects `SslStream::ssl_read` and + /// `SslStream::ssl_write`. + const AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY; + + /// Disables automatic chain building when verifying a peer's certificate. + /// + /// TLS peers are responsible for sending the entire certificate chain from the leaf to a + /// trusted root, but some will incorrectly not do so. OpenSSL will try to build the chain + /// out of certificates it knows of, and this option will disable that behavior. + const NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN; + + /// Release memory buffers when the session does not need them. + /// + /// This saves ~34 KiB of memory for idle streams. + const RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS; + + /// Sends the fake `TLS_FALLBACK_SCSV` cipher suite in the ClientHello message of a + /// handshake. + /// + /// This should only be enabled if a client has failed to connect to a server which + /// attempted to downgrade the protocol version of the session. + /// + /// Do not use this unless you know what you're doing! + #[cfg(not(libressl))] + const SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV; + } +} + +/// A type specifying the kind of protocol an `SslContext` will speak. +#[derive(Copy, Clone)] +pub struct SslMethod(*const ffi::SSL_METHOD); + +impl SslMethod { + /// Support all versions of the TLS protocol. + /// + /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` + /// on OpenSSL 1.0.x. + pub fn tls() -> SslMethod { + unsafe { SslMethod(TLS_method()) } + } + + /// Support all versions of the DTLS protocol. + /// + /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` + /// on OpenSSL 1.0.x. + pub fn dtls() -> SslMethod { + unsafe { SslMethod(DTLS_method()) } + } + + /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. + pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod { + SslMethod(ptr) + } + + /// Returns a pointer to the underlying OpenSSL value. + pub fn as_ptr(&self) -> *const ffi::SSL_METHOD { + self.0 + } +} + +unsafe impl Sync for SslMethod {} +unsafe impl Send for SslMethod {} + +bitflags! { + /// Options controling the behavior of certificate verification. + pub struct SslVerifyMode: i32 { + /// Verifies that the peer's certificate is trusted. + /// + /// On the server side, this will cause OpenSSL to request a certificate from the client. + const PEER = ffi::SSL_VERIFY_PEER; + + /// Disables verification of the peer's certificate. + /// + /// On the server side, this will cause OpenSSL to not request a certificate from the + /// client. On the client side, the certificate will be checked for validity, but the + /// negotiation will continue regardless of the result of that check. + const NONE = ffi::SSL_VERIFY_NONE; + + /// On the server side, abort the handshake if the client did not send a certificate. + /// + /// This should be paired with `SSL_VERIFY_PEER`. It has no effect on the client side. + const FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + } +} + +bitflags! { + /// Options controlling the behavior of session caching. + pub struct SslSessionCacheMode: c_long { + /// No session caching for the client or server takes place. + const OFF = ffi::SSL_SESS_CACHE_OFF; + + /// Enable session caching on the client side. + /// + /// OpenSSL has no way of identifying the proper session to reuse automatically, so the + /// application is responsible for setting it explicitly via [`SslRef::set_session`]. + /// + /// [`SslRef::set_session`]: struct.SslRef.html#method.set_session + const CLIENT = ffi::SSL_SESS_CACHE_CLIENT; + + /// Enable session caching on the server side. + /// + /// This is the default mode. + const SERVER = ffi::SSL_SESS_CACHE_SERVER; + + /// Enable session caching on both the client and server side. + const BOTH = ffi::SSL_SESS_CACHE_BOTH; + + /// Disable automatic removal of expired sessions from the session cache. + const NO_AUTO_CLEAR = ffi::SSL_SESS_CACHE_NO_AUTO_CLEAR; + + /// Disable use of the internal session cache for session lookups. + const NO_INTERNAL_LOOKUP = ffi::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; + + /// Disable use of the internal session cache for session storage. + const NO_INTERNAL_STORE = ffi::SSL_SESS_CACHE_NO_INTERNAL_STORE; + + /// Disable use of the internal session cache for storage and lookup. + const NO_INTERNAL = ffi::SSL_SESS_CACHE_NO_INTERNAL; + } +} + +#[cfg(ossl111)] +bitflags! { + /// Which messages and under which conditions an extension should be added or expected. + pub struct ExtensionContext: c_uint { + /// This extension is only allowed in TLS + const TLS_ONLY = ffi::SSL_EXT_TLS_ONLY; + /// This extension is only allowed in DTLS + const DTLS_ONLY = ffi::SSL_EXT_DTLS_ONLY; + /// Some extensions may be allowed in DTLS but we don't implement them for it + const TLS_IMPLEMENTATION_ONLY = ffi::SSL_EXT_TLS_IMPLEMENTATION_ONLY; + /// Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is + const SSL3_ALLOWED = ffi::SSL_EXT_SSL3_ALLOWED; + /// Extension is only defined for TLS1.2 and below + const TLS1_2_AND_BELOW_ONLY = ffi::SSL_EXT_TLS1_2_AND_BELOW_ONLY; + /// Extension is only defined for TLS1.3 and above + const TLS1_3_ONLY = ffi::SSL_EXT_TLS1_3_ONLY; + /// Ignore this extension during parsing if we are resuming + const IGNORE_ON_RESUMPTION = ffi::SSL_EXT_IGNORE_ON_RESUMPTION; + const CLIENT_HELLO = ffi::SSL_EXT_CLIENT_HELLO; + /// Really means TLS1.2 or below + const TLS1_2_SERVER_HELLO = ffi::SSL_EXT_TLS1_2_SERVER_HELLO; + const TLS1_3_SERVER_HELLO = ffi::SSL_EXT_TLS1_3_SERVER_HELLO; + const TLS1_3_ENCRYPTED_EXTENSIONS = ffi::SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS; + const TLS1_3_HELLO_RETRY_REQUEST = ffi::SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST; + const TLS1_3_CERTIFICATE = ffi::SSL_EXT_TLS1_3_CERTIFICATE; + const TLS1_3_NEW_SESSION_TICKET = ffi::SSL_EXT_TLS1_3_NEW_SESSION_TICKET; + const TLS1_3_CERTIFICATE_REQUEST = ffi::SSL_EXT_TLS1_3_CERTIFICATE_REQUEST; + } +} + +/// An identifier of the format of a certificate or key file. +#[derive(Copy, Clone)] +pub struct SslFiletype(c_int); + +impl SslFiletype { + /// Constructs an `SslFiletype` from a raw OpenSSL value. + pub fn from_raw(raw: c_int) -> SslFiletype { + SslFiletype(raw) + } + + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// The PEM format. + /// + /// This corresponds to `SSL_FILETYPE_PEM`. + pub const PEM: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_PEM); + + /// The ASN1 format. + /// + /// This corresponds to `SSL_FILETYPE_ASN1`. + pub const ASN1: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_ASN1); +} + +/// An identifier of a certificate status type. +#[derive(Copy, Clone)] +pub struct StatusType(c_int); + +impl StatusType { + /// Constructs a `StatusType` from a raw OpenSSL value. + pub fn from_raw(raw: c_int) -> StatusType { + StatusType(raw) + } + + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// An OSCP status. + pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); +} + +/// An identifier of a session name type. +#[derive(Copy, Clone)] +pub struct NameType(c_int); + +impl NameType { + /// Constructs a `StatusType` from a raw OpenSSL value. + pub fn from_raw(raw: c_int) -> StatusType { + StatusType(raw) + } + + /// Returns the raw OpenSSL value represented by this type. + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// A host name. + pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name); +} + +lazy_static! { + static ref INDEXES: Mutex> = Mutex::new(HashMap::new()); + static ref SSL_INDEXES: Mutex> = Mutex::new(HashMap::new()); + + static ref SESSION_CTX_INDEX: Index = Ssl::new_ex_index().unwrap(); +} + +unsafe extern "C" fn free_data_box( + _parent: *mut c_void, + ptr: *mut c_void, + _ad: *mut ffi::CRYPTO_EX_DATA, + _idx: c_int, + _argl: c_long, + _argp: *mut c_void, +) { + if !ptr.is_null() { + Box::::from_raw(ptr as *mut T); + } +} + +/// An error returned from the SNI callback. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SniError(c_int); + +impl SniError { + /// Abort the handshake with a fatal alert. + pub const ALERT_FATAL: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); + + /// Send a warning alert to the client and continue the handshake. + pub const ALERT_WARNING: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_WARNING); + + pub const NOACK: SniError = SniError(ffi::SSL_TLSEXT_ERR_NOACK); +} + +/// An SSL/TLS alert. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SslAlert(c_int); + +impl SslAlert { + /// Alert 112 - `unrecognized_name`. + pub const UNRECOGNIZED_NAME: SslAlert = SslAlert(ffi::SSL_AD_UNRECOGNIZED_NAME); + pub const ILLEGAL_PARAMETER: SslAlert = SslAlert(ffi::SSL_AD_ILLEGAL_PARAMETER); + pub const DECODE_ERROR: SslAlert = SslAlert(ffi::SSL_AD_DECODE_ERROR); +} + +/// An error returned from an ALPN selection callback. +/// +/// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. +#[cfg(any(ossl102, libressl261))] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct AlpnError(c_int); + +#[cfg(any(ossl102, libressl261))] +impl AlpnError { + /// Terminate the handshake with a fatal alert. + /// + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); + + /// Do not select a protocol, but continue the handshake. + pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK); +} + +/// The result of a client hello callback. +/// +/// Requires OpenSSL 1.1.1 or newer. +#[cfg(ossl111)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ClientHelloResponse(c_int); + +#[cfg(ossl111)] +impl ClientHelloResponse { + /// Continue the handshake. + pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS); + + /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error. + pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY); +} + +/// An SSL/TLS protocol version. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct SslVersion(c_int); + +impl SslVersion { + /// SSLv3 + pub const SSL3: SslVersion = SslVersion(ffi::SSL3_VERSION); + + /// TLSv1.0 + pub const TLS1: SslVersion = SslVersion(ffi::TLS1_VERSION); + + /// TLSv1.1 + pub const TLS1_1: SslVersion = SslVersion(ffi::TLS1_1_VERSION); + + /// TLSv1.2 + pub const TLS1_2: SslVersion = SslVersion(ffi::TLS1_2_VERSION); + + /// TLSv1.3 + /// + /// Requires OpenSSL 1.1.1 or newer. + #[cfg(ossl111)] + pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION); +} + +/// A standard implementation of protocol selection for Application Layer Protocol Negotiation +/// (ALPN). +/// +/// `server` should contain the server's list of supported protocols and `client` the client's. They +/// must both be in the ALPN wire format. See the documentation for +/// [`SslContextBuilder::set_alpn_protos`] for details. +/// +/// It will select the first protocol supported by the server which is also supported by the client. +/// +/// This corresponds to [`SSL_select_next_proto`]. +/// +/// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos +/// [`SSL_select_next_proto`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html +pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> { + unsafe { + let mut out = ptr::null_mut(); + let mut outlen = 0; + let r = ffi::SSL_select_next_proto( + &mut out, + &mut outlen, + server.as_ptr(), + server.len() as c_uint, + client.as_ptr(), + client.len() as c_uint, + ); + if r == ffi::OPENSSL_NPN_NEGOTIATED { + Some(slice::from_raw_parts(out as *const u8, outlen as usize)) + } else { + None + } + } +} + +/// A builder for `SslContext`s. +pub struct SslContextBuilder(SslContext); + +impl SslContextBuilder { + /// Creates a new `SslContextBuilder`. + /// + /// This corresponds to [`SSL_CTX_new`]. + /// + /// [`SSL_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_new.html + pub fn new(method: SslMethod) -> Result { + unsafe { + init(); + let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?; + + Ok(SslContextBuilder::from_ptr(ctx)) + } + } + + /// Creates an `SslContextBuilder` from a pointer to a raw OpenSSL value. + pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder { + SslContextBuilder(SslContext::from_ptr(ctx)) + } + + /// Returns a pointer to the raw OpenSSL value. + pub fn as_ptr(&self) -> *mut ffi::SSL_CTX { + self.0.as_ptr() + } + + /// Configures the certificate verification method for new connections. + /// + /// This corresponds to [`SSL_CTX_set_verify`]. + /// + /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + pub fn set_verify(&mut self, mode: SslVerifyMode) { + unsafe { + ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None); + } + } + + /// Configures the certificate verification method for new connections and + /// registers a verification callback. + /// + /// The callback is passed a boolean indicating if OpenSSL's internal verification succeeded as + /// well as a reference to the `X509StoreContext` which can be used to examine the certificate + /// chain. It should return a boolean indicating if verification succeeded. + /// + /// This corresponds to [`SSL_CTX_set_verify`]. + /// + /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) + where + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), verify); + ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::)); + } + } + + /// Configures the server name indication (SNI) callback for new connections. + /// + /// SNI is used to allow a single server to handle requests for multiple domains, each of which + /// has its own certificate chain and configuration. + /// + /// Obtain the server name with the `servername` method and then set the corresponding context + /// with `set_ssl_context` + /// + /// This corresponds to [`SSL_CTX_set_tlsext_servername_callback`]. + /// + /// [`SSL_CTX_set_tlsext_servername_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_tlsext_servername_callback.html + // FIXME tlsext prefix? + pub fn set_servername_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, + { + unsafe { + // The SNI callback is somewhat unique in that the callback associated with the original + // context associated with an SSL can be used even if the SSL's context has been swapped + // out. When that happens, we wouldn't be able to look up the callback's state in the + // context's ex data. Instead, pass the pointer directly as the servername arg. It's + // still stored in ex data to manage the lifetime. + let arg = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg); + + let f: extern "C" fn(_, _, _) -> _ = raw_sni::; + let f: extern "C" fn() = mem::transmute(f); + ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f)); + } + } + + /// Sets the certificate verification depth. + /// + /// If the peer's certificate chain is longer than this value, verification will fail. + /// + /// This corresponds to [`SSL_CTX_set_verify_depth`]. + /// + /// [`SSL_CTX_set_verify_depth`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify_depth.html + pub fn set_verify_depth(&mut self, depth: u32) { + unsafe { + ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int); + } + } + + /// Sets a custom certificate store for verifying peer certificates. + /// + /// Requires OpenSSL 1.0.2 or newer. + /// + /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. + /// + /// [`SSL_CTX_set0_verify_cert_store`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set0_verify_cert_store.html + #[cfg(any(ossl102, ossl110))] + pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { + unsafe { + let ptr = cert_store.as_ptr(); + cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?; + mem::forget(cert_store); + + Ok(()) + } + } + + /// Controls read ahead behavior. + /// + /// If enabled, OpenSSL will read as much data as is available from the underlying stream, + /// instead of a single record at a time. + /// + /// It has no effect when used with DTLS. + /// + /// This corresponds to [`SSL_CTX_set_read_ahead`]. + /// + /// [`SSL_CTX_set_read_ahead`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_read_ahead.html + pub fn set_read_ahead(&mut self, read_ahead: bool) { + unsafe { + ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_long); + } + } + + /// Sets the mode used by the context, returning the previous mode. + /// + /// This corresponds to [`SSL_CTX_set_mode`]. + /// + /// [`SSL_CTX_set_mode`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_mode.html + pub fn set_mode(&mut self, mode: SslMode) -> SslMode { + unsafe { + let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits()); + SslMode { bits } + } + } + + /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange. + /// + /// This corresponds to [`SSL_CTX_set_tmp_dh`]. + /// + /// [`SSL_CTX_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html + pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } + } + + /// Sets the callback which will generate parameters to be used during ephemeral Diffie-Hellman + /// key exchange. + /// + /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean + /// indicating if the selected cipher is export-grade, and the key length. The export and key + /// length options are archaic and should be ignored in almost all cases. + /// + /// This corresponds to [`SSL_CTX_set_tmp_dh_callback`]. + /// + /// [`SSL_CTX_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html + pub fn set_tmp_dh_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh::); + } + } + + /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange. + /// + /// This corresponds to `SSL_CTX_set_tmp_ecdh`. + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } + } + + /// Sets the callback which will generate parameters to be used during ephemeral elliptic curve + /// Diffie-Hellman key exchange. + /// + /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean + /// indicating if the selected cipher is export-grade, and the key length. The export and key + /// length options are archaic and should be ignored in almost all cases. + /// + /// Requires OpenSSL 1.0.1 or 1.0.2. + /// + /// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`. + #[cfg(all(ossl101, not(ossl110)))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh::); + } + } + + /// Use the default locations of trusted certificates for verification. + /// + /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables + /// if present, or defaults specified at OpenSSL build time otherwise. + /// + /// This corresponds to [`SSL_CTX_set_default_verify_paths`]. + /// + /// [`SSL_CTX_set_default_verify_paths`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_default_verify_paths.html + pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) } + } + + /// Loads trusted root certificates from a file. + /// + /// The file should contain a sequence of PEM-formatted CA certificates. + /// + /// This corresponds to [`SSL_CTX_load_verify_locations`]. + /// + /// [`SSL_CTX_load_verify_locations`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_load_verify_locations.html + pub fn set_ca_file>(&mut self, file: P) -> Result<(), ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_load_verify_locations( + self.as_ptr(), + file.as_ptr() as *const _, + ptr::null(), + )) + .map(|_| ()) + } + } + + /// Sets the list of CA names sent to the client. + /// + /// The CA certificates must still be added to the trust root - they are not automatically set + /// as trusted by this method. + /// + /// This corresponds to [`SSL_CTX_set_client_CA_list`]. + /// + /// [`SSL_CTX_set_client_CA_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html + pub fn set_client_ca_list(&mut self, list: Stack) { + unsafe { + ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr()); + mem::forget(list); + } + } + + /// Add the provided CA certificate to the list sent by the server to the client when + /// requesting client-side TLS authentication. + /// + /// This corresponds to [`SSL_CTX_add_client_CA`]. + /// + /// [`SSL_CTX_add_client_CA`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_client_CA_list.html + #[cfg(not(libressl))] + pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_add_client_CA( + self.as_ptr(), + cacert.as_ptr() + )) + .map(|_| ()) + } + } + + /// Set the context identifier for sessions. + /// + /// This value identifies the server's session cache to clients, telling them when they're + /// able to reuse sessions. It should be be set to a unique value per server, unless multiple + /// servers share a session cache. + /// + /// This value should be set when using client certificates, or each request will fail its + /// handshake and need to be restarted. + /// + /// This corresponds to [`SSL_CTX_set_session_id_context`]. + /// + /// [`SSL_CTX_set_session_id_context`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_session_id_context.html + pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(sid_ctx.len() <= c_uint::max_value() as usize); + cvt(ffi::SSL_CTX_set_session_id_context( + self.as_ptr(), + sid_ctx.as_ptr(), + sid_ctx.len() as c_uint, + )) + .map(|_| ()) + } + } + + /// Loads a leaf certificate from a file. + /// + /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder + /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a + /// single file. + /// + /// This corresponds to [`SSL_CTX_use_certificate_file`]. + /// + /// [`SSL_CTX_use_certificate_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + pub fn set_certificate_file>( + &mut self, + file: P, + file_type: SslFiletype, + ) -> Result<(), ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_use_certificate_file( + self.as_ptr(), + file.as_ptr() as *const _, + file_type.as_raw(), + )) + .map(|_| ()) + } + } + + /// Loads a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf + /// certificate, and the remainder forming the chain of certificates up to and including the + /// trusted root certificate. + /// + /// This corresponds to [`SSL_CTX_use_certificate_chain_file`]. + /// + /// [`SSL_CTX_use_certificate_chain_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + pub fn set_certificate_chain_file>( + &mut self, + file: P, + ) -> Result<(), ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_use_certificate_chain_file( + self.as_ptr(), + file.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Sets the leaf certificate. + /// + /// Use `add_extra_chain_cert` to add the remainder of the certificate chain. + /// + /// This corresponds to [`SSL_CTX_use_certificate`]. + /// + /// [`SSL_CTX_use_certificate`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } + } + + /// Appends a certificate to the certificate chain. + /// + /// This chain should contain all certificates necessary to go from the certificate specified by + /// `set_certificate` to a trusted root. + /// + /// This corresponds to [`SSL_CTX_add_extra_chain_cert`]. + /// + /// [`SSL_CTX_add_extra_chain_cert`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html + pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?; + mem::forget(cert); + Ok(()) + } + } + + /// Loads the private key from a file. + /// + /// This corresponds to [`SSL_CTX_use_PrivateKey_file`]. + /// + /// [`SSL_CTX_use_PrivateKey_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html + pub fn set_private_key_file>( + &mut self, + file: P, + file_type: SslFiletype, + ) -> Result<(), ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_use_PrivateKey_file( + self.as_ptr(), + file.as_ptr() as *const _, + file_type.as_raw(), + )) + .map(|_| ()) + } + } + + /// Sets the private key. + /// + /// This corresponds to [`SSL_CTX_use_PrivateKey`]. + /// + /// [`SSL_CTX_use_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html + pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPrivate, + { + unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } + } + + /// Sets the list of supported ciphers for protocols before TLSv1.3. + /// + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. + /// + /// See [`ciphers`] for details on the format. + /// + /// This corresponds to [`SSL_CTX_set_cipher_list`]. + /// + /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html + /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_ciphers.html + pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set_cipher_list( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Sets the list of supported ciphers for the TLSv1.3 protocol. + /// + /// The `set_cipher_list` method controls lthe cipher suites for protocols before TLSv1.3. + /// + /// The format consists of TLSv1.3 ciphersuite names separated by `:` characters in order of + /// preference. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_ciphersuites`]. + /// + /// [`SSL_CTX_set_ciphersuites`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_ciphersuites.html + #[cfg(ossl111)] + pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set_ciphersuites( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + + /// Enables ECDHE key exchange with an automatically chosen curve list. + /// + /// Requires OpenSSL 1.0.2. + /// + /// This corresponds to [`SSL_CTX_set_ecdh_auto`]. + /// + /// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html + #[cfg(any(libressl, all(ossl102, not(ossl110))))] + pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } + } + + /// Sets the options used by the context, returning the old set. + /// + /// This corresponds to [`SSL_CTX_set_options`]. + /// + /// # Note + /// + /// This *enables* the specified options, but does not disable unspecified options. Use + /// `clear_options` for that. + /// + /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + pub fn set_options(&mut self, option: SslOptions) -> SslOptions { + let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; + SslOptions { bits } + } + + /// Returns the options used by the context. + /// + /// This corresponds to [`SSL_CTX_get_options`]. + /// + /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + pub fn options(&self) -> SslOptions { + let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; + SslOptions { bits } + } + + /// Clears the options used by the context, returning the old set. + /// + /// This corresponds to [`SSL_CTX_clear_options`]. + /// + /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { + let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; + SslOptions { bits } + } + + /// Sets the minimum supported protocol version. + /// + /// A value of `None` will enable protocol versions down the the lowest version supported by + /// OpenSSL. + /// + /// This corresponds to [`SSL_CTX_set_min_proto_version`]. + /// + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. + /// + /// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110, libressl261))] + pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_set_min_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Sets the maximum supported protocol version. + /// + /// A value of `None` will enable protocol versions down the the highest version supported by + /// OpenSSL. + /// + /// This corresponds to [`SSL_CTX_set_max_proto_version`]. + /// + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. + /// + /// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110, libressl261))] + pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_set_max_proto_version( + self.as_ptr(), + version.map_or(0, |v| v.0 as _), + )) + .map(|_| ()) + } + } + + /// Gets the minimum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the lowest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_min_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn min_proto_version(&mut self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + + /// Gets the maximum supported protocol version. + /// + /// A value of `None` indicates that all versions down the the highest version supported by + /// OpenSSL are enabled. + /// + /// This corresponds to [`SSL_CTX_get_max_proto_version`]. + /// + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. + /// + /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[cfg(any(ossl110g, libressl270))] + pub fn max_proto_version(&mut self) -> Option { + unsafe { + let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + + /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN). + /// + /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol + /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1` + /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by + /// preference. + /// + /// This corresponds to [`SSL_CTX_set_alpn_protos`]. + /// + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + /// + /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(protocols.len() <= c_uint::max_value() as usize); + let r = ffi::SSL_CTX_set_alpn_protos( + self.as_ptr(), + protocols.as_ptr(), + protocols.len() as c_uint, + ); + // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + } + + /// Enables the DTLS extension "use_srtp" as defined in RFC5764. + /// + /// This corresponds to [`SSL_CTX_set_tlsext_use_srtp`]. + /// + /// [`SSL_CTX_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { + unsafe { + let cstr = CString::new(protocols).unwrap(); + + let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); + // fun fact, set_tlsext_use_srtp has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + } + + /// Sets the callback used by a server to select a protocol for Application Layer Protocol + /// Negotiation (ALPN). + /// + /// The callback is provided with the client's protocol list in ALPN wire format. See the + /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one + /// of those protocols on success. The [`select_next_proto`] function implements the standard + /// protocol selection algorithm. + /// + /// This corresponds to [`SSL_CTX_set_alpn_select_cb`]. + /// + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + /// + /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos + /// [`select_next_proto`]: fn.select_next_proto.html + /// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_select_callback(&mut self, callback: F) + where + F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_alpn_select_cb( + self.as_ptr(), + callbacks::raw_alpn_select::, + ptr::null_mut(), + ); + } + } + + /// Checks for consistency between the private key and certificate. + /// + /// This corresponds to [`SSL_CTX_check_private_key`]. + /// + /// [`SSL_CTX_check_private_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_check_private_key.html + pub fn check_private_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } + } + + /// Returns a shared reference to the context's certificate store. + /// + /// This corresponds to [`SSL_CTX_get_cert_store`]. + /// + /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + pub fn cert_store(&self) -> &X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + + /// Returns a mutable reference to the context's certificate store. + /// + /// This corresponds to [`SSL_CTX_get_cert_store`]. + /// + /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + + /// Sets the callback dealing with OCSP stapling. + /// + /// On the client side, this callback is responsible for validating the OCSP status response + /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method. + /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of + /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be + /// terminated. + /// + /// On the server side, this callback is resopnsible for setting the OCSP status response to be + /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A + /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and + /// `Ok(false)` indicates that the status should not be returned to the client. + /// + /// This corresponds to [`SSL_CTX_set_tlsext_status_cb`]. + /// + /// [`SSL_CTX_set_tlsext_status_cb`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tlsext_status_cb.html + pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> + where + F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + cvt( + ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::)) + as c_int, + ) + .map(|_| ()) + } + } + + /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client. + /// + /// The callback will be called with the SSL context, an identity hint if one was provided + /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The + /// identity must be written as a null-terminated C string. + /// + /// This corresponds to [`SSL_CTX_set_psk_client_callback`]. + /// + /// [`SSL_CTX_set_psk_client_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_client_callback.html + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + pub fn set_psk_client_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + + 'static + + Sync + + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::)); + } + } + + #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")] + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + pub fn set_psk_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + + 'static + + Sync + + Send, + { + self.set_psk_client_callback(callback) + } + + /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server. + /// + /// The callback will be called with the SSL context, an identity provided by the client, + /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of + /// bytes in the pre-shared key. + /// + /// This corresponds to [`SSL_CTX_set_psk_server_callback`]. + /// + /// [`SSL_CTX_set_psk_server_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_server_callback.html + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + pub fn set_psk_server_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + + 'static + + Sync + + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::)); + } + } + + /// Sets the callback which is called when new sessions are negotiated. + /// + /// This can be used by clients to implement session caching. While in TLSv1.2 the session is + /// available to access via [`SslRef::session`] immediately after the handshake completes, this + /// is not the case for TLSv1.3. There, a session is not generally available immediately, and + /// the server may provide multiple session tokens to the client over a single session. The new + /// session callback is a portable way to deal with both cases. + /// + /// Note that session caching must be enabled for the callback to be invoked, and it defaults + /// off for clients. [`set_session_cache_mode`] controls that behavior. + /// + /// This corresponds to [`SSL_CTX_sess_set_new_cb`]. + /// + /// [`SslRef::session`]: struct.SslRef.html#method.session + /// [`set_session_cache_mode`]: #method.set_session_cache_mode + /// [`SSL_CTX_sess_set_new_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + pub fn set_new_session_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::)); + } + } + + /// Sets the callback which is called when sessions are removed from the context. + /// + /// Sessions can be removed because they have timed out or because they are considered faulty. + /// + /// This corresponds to [`SSL_CTX_sess_set_remove_cb`]. + /// + /// [`SSL_CTX_sess_set_remove_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + pub fn set_remove_session_callback(&mut self, callback: F) + where + F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_remove_cb( + self.as_ptr(), + Some(callbacks::raw_remove_session::), + ); + } + } + + /// Sets the callback which is called when a client proposed to resume a session but it was not + /// found in the internal cache. + /// + /// The callback is passed a reference to the session ID provided by the client. It should + /// return the session corresponding to that ID if available. This is only used for servers, not + /// clients. + /// + /// This corresponds to [`SSL_CTX_sess_set_get_cb`]. + /// + /// # Safety + /// + /// The returned `SslSession` must not be associated with a different `SslContext`. + /// + /// [`SSL_CTX_sess_set_get_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + pub unsafe fn set_get_session_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, + { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::)); + } + + /// Sets the TLS key logging callback. + /// + /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS + /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message + /// traffic. The line does not contain a trailing newline. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_keylog_callback`]. + /// + /// [`SSL_CTX_set_keylog_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_keylog_callback.html + #[cfg(ossl111)] + pub fn set_keylog_callback(&mut self, callback: F) + where + F: Fn(&SslRef, &str) + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::)); + } + } + + /// Sets the session caching mode use for connections made with the context. + /// + /// Returns the previous session caching mode. + /// + /// This corresponds to [`SSL_CTX_set_session_cache_mode`]. + /// + /// [`SSL_CTX_set_session_cache_mode`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_session_cache_mode.html + pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode { + unsafe { + let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits()); + SslSessionCacheMode { bits } + } + } + + /// Sets the callback for generating an application cookie for TLS1.3 + /// stateless handshakes. + /// + /// The callback will be called with the SSL context and a slice into which the cookie + /// should be written. The callback should return the number of bytes written. + /// + /// This corresponds to `SSL_CTX_set_stateless_cookie_generate_cb`. + #[cfg(ossl111)] + pub fn set_stateless_cookie_generate_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_stateless_cookie_generate_cb( + self.as_ptr(), + Some(raw_stateless_cookie_generate::), + ); + } + } + + /// Sets the callback for verifying an application cookie for TLS1.3 + /// stateless handshakes. + /// + /// The callback will be called with the SSL context and the cookie supplied by the + /// client. It should return true if and only if the cookie is valid. + /// + /// Note that the OpenSSL implementation independently verifies the integrity of + /// application cookies using an HMAC before invoking the supplied callback. + /// + /// This corresponds to `SSL_CTX_set_stateless_cookie_verify_cb`. + #[cfg(ossl111)] + pub fn set_stateless_cookie_verify_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_stateless_cookie_verify_cb( + self.as_ptr(), + Some(raw_stateless_cookie_verify::), + ) + } + } + + /// Sets the callback for generating a DTLSv1 cookie + /// + /// The callback will be called with the SSL context and a slice into which the cookie + /// should be written. The callback should return the number of bytes written. + /// + /// This corresponds to `SSL_CTX_set_cookie_generate_cb`. + pub fn set_cookie_generate_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::)); + } + } + + /// Sets the callback for verifying a DTLSv1 cookie + /// + /// The callback will be called with the SSL context and the cookie supplied by the + /// client. It should return true if and only if the cookie is valid. + /// + /// This corresponds to `SSL_CTX_set_cookie_verify_cb`. + pub fn set_cookie_verify_cb(&mut self, callback: F) + where + F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, + { + unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::)); + } + } + + /// Sets the extra data at the specified index. + /// + /// This can be used to provide data to callbacks registered with the context. Use the + /// `SslContext::new_ex_index` method to create an `Index`. + /// + /// This corresponds to [`SSL_CTX_set_ex_data`]. + /// + /// [`SSL_CTX_set_ex_data`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ex_data.html + pub fn set_ex_data(&mut self, index: Index, data: T) { + self.set_ex_data_inner(index, data); + } + + fn set_ex_data_inner(&mut self, index: Index, data: T) -> *mut c_void { + unsafe { + let data = Box::into_raw(Box::new(data)) as *mut c_void; + ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data); + data + } + } + + /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_add_custom_ext`]. + /// + /// [`SSL_CTX_add_custom_ext`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_custom_ext.html + #[cfg(ossl111)] + pub fn add_custom_ext( + &mut self, + ext_type: u16, + context: ExtensionContext, + add_cb: AddFn, + parse_cb: ParseFn, + ) -> Result<(), ErrorStack> + where + AddFn: Fn( + &mut SslRef, + ExtensionContext, + Option<(usize, &X509Ref)>, + ) -> Result, SslAlert> + + 'static + + Sync + + Send, + T: AsRef<[u8]> + 'static + Sync + Send, + ParseFn: Fn( + &mut SslRef, + ExtensionContext, + &[u8], + Option<(usize, &X509Ref)>, + ) -> Result<(), SslAlert> + + 'static + + Sync + + Send, + { + let ret = unsafe { + self.set_ex_data(SslContext::cached_ex_index::(), add_cb); + self.set_ex_data(SslContext::cached_ex_index::(), parse_cb); + + ffi::SSL_CTX_add_custom_ext( + self.as_ptr(), + ext_type as c_uint, + context.bits(), + Some(raw_custom_ext_add::), + Some(raw_custom_ext_free::), + ptr::null_mut(), + Some(raw_custom_ext_parse::), + ptr::null_mut(), + ) + }; + if ret == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Sets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Defaults to 0. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_max_early_data`]. + /// + /// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Sets a callback which will be invoked just after the client's hello message is received. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_client_hello_cb`]. + /// + /// [`SSL_CTX_set_client_hello_cb`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn set_client_hello_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &mut SslAlert) -> Result + + 'static + + Sync + + Send, + { + unsafe { + let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_client_hello_cb( + self.as_ptr(), + Some(callbacks::raw_client_hello::), + ptr, + ); + } + } + + /// Sets the context's session cache size limit, returning the previous limit. + /// + /// A value of 0 means that the cache size is unbounded. + /// + /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. + /// + /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + pub fn set_session_cache_size(&mut self, size: i32) -> i64 { + unsafe { ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size.into()).into() } + } + + /// Consumes the builder, returning a new `SslContext`. + pub fn build(self) -> SslContext { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::SSL_CTX; + fn drop = ffi::SSL_CTX_free; + + /// A context object for TLS streams. + /// + /// Applications commonly configure a single `SslContext` that is shared by all of its + /// `SslStreams`. + pub struct SslContext; + + /// Reference to [`SslContext`] + /// + /// [`SslContext`]: struct.SslContext.html + pub struct SslContextRef; +} + +impl Clone for SslContext { + fn clone(&self) -> Self { + unsafe { + SSL_CTX_up_ref(self.as_ptr()); + SslContext::from_ptr(self.as_ptr()) + } + } +} + +// TODO: add useful info here +impl fmt::Debug for SslContext { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SslContext") + } +} + +impl SslContext { + /// Creates a new builder object for an `SslContext`. + pub fn builder(method: SslMethod) -> Result { + SslContextBuilder::new(method) + } + + /// Returns a new extra data index. + /// + /// Each invocation of this function is guaranteed to return a distinct index. These can be used + /// to store data in the context that can be retrieved later by callbacks, for example. + /// + /// This corresponds to [`SSL_CTX_get_ex_new_index`]. + /// + /// [`SSL_CTX_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get_ex_new_index.html + pub fn new_ex_index() -> Result, ErrorStack> + where + T: 'static + Sync + Send, + { + unsafe { + ffi::init(); + let idx = cvt_n(get_new_idx(free_data_box::))?; + Ok(Index::from_raw(idx)) + } + } + + // FIXME should return a result? + fn cached_ex_index() -> Index + where + T: 'static + Sync + Send, + { + unsafe { + let idx = *INDEXES + .lock() + .unwrap_or_else(|e| e.into_inner()) + .entry(TypeId::of::()) + .or_insert_with(|| SslContext::new_ex_index::().unwrap().as_raw()); + Index::from_raw(idx) + } + } +} + +impl SslContextRef { + /// Returns the certificate associated with this `SslContext`, if present. + /// + /// Requires OpenSSL 1.0.2 or newer. + /// + /// This corresponds to [`SSL_CTX_get0_certificate`]. + /// + /// [`SSL_CTX_get0_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html + #[cfg(any(ossl102, ossl110))] + pub fn certificate(&self) -> Option<&X509Ref> { + unsafe { + let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(X509Ref::from_ptr(ptr)) + } + } + } + + /// Returns the private key associated with this `SslContext`, if present. + /// + /// Requires OpenSSL 1.0.2 or newer. + /// + /// This corresponds to [`SSL_CTX_get0_privatekey`]. + /// + /// [`SSL_CTX_get0_privatekey`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html + #[cfg(any(ossl102, ossl110))] + pub fn private_key(&self) -> Option<&PKeyRef> { + unsafe { + let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(PKeyRef::from_ptr(ptr)) + } + } + } + + /// Returns a shared reference to the certificate store used for verification. + /// + /// This corresponds to [`SSL_CTX_get_cert_store`]. + /// + /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + pub fn cert_store(&self) -> &X509StoreRef { + unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + + /// Returns a shared reference to the stack of certificates making up the chain from the leaf. + /// + /// This corresponds to `SSL_CTX_get_extra_chain_certs`. + pub fn extra_chain_certs(&self) -> &StackRef { + unsafe { + let mut chain = ptr::null_mut(); + ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain); + assert!(!chain.is_null()); + StackRef::from_ptr(chain) + } + } + + /// Returns a reference to the extra data at the specified index. + /// + /// This corresponds to [`SSL_CTX_get_ex_data`]. + /// + /// [`SSL_CTX_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ex_data.html + pub fn ex_data(&self, index: Index) -> Option<&T> { + unsafe { + let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&*(data as *const T)) + } + } + } + + /// Gets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_get_max_early_data`]. + /// + /// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) } + } + + /// Adds a session to the context's cache. + /// + /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present. + /// + /// This corresponds to [`SSL_CTX_add_session`]. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + /// + /// [`SSL_CTX_add_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Removes a session from the context's cache and marks it as non-resumable. + /// + /// Returns `true` if the session was successfully found and removed, and `false` otherwise. + /// + /// This corresponds to [`SSL_CTX_remove_session`]. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + /// + /// [`SSL_CTX_remove_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Returns the context's session cache size limit. + /// + /// A value of 0 means that the cache size is unbounded. + /// + /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. + /// + /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + pub fn session_cache_size(&self) -> i64 { + unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()).into() } + } +} + +/// Information about the state of a cipher. +pub struct CipherBits { + /// The number of secret bits used for the cipher. + pub secret: i32, + + /// The number of bits processed by the chosen algorithm. + pub algorithm: i32, +} + +/// Information about a cipher. +pub struct SslCipher(*mut ffi::SSL_CIPHER); + +impl ForeignType for SslCipher { + type CType = ffi::SSL_CIPHER; + type Ref = SslCipherRef; + + #[inline] + unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher { + SslCipher(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut ffi::SSL_CIPHER { + self.0 + } +} + +impl Deref for SslCipher { + type Target = SslCipherRef; + + fn deref(&self) -> &SslCipherRef { + unsafe { SslCipherRef::from_ptr(self.0) } + } +} + +impl DerefMut for SslCipher { + fn deref_mut(&mut self) -> &mut SslCipherRef { + unsafe { SslCipherRef::from_ptr_mut(self.0) } + } +} + +/// Reference to an [`SslCipher`]. +/// +/// [`SslCipher`]: struct.SslCipher.html +pub struct SslCipherRef(Opaque); + +impl ForeignTypeRef for SslCipherRef { + type CType = ffi::SSL_CIPHER; +} + +impl SslCipherRef { + /// Returns the name of the cipher. + /// + /// This corresponds to [`SSL_CIPHER_get_name`]. + /// + /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + pub fn name(&self) -> &'static str { + unsafe { + let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); + CStr::from_ptr(ptr).to_str().unwrap() + } + } + + /// Returns the RFC-standard name of the cipher, if one exists. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CIPHER_standard_name`]. + /// + /// [`SSL_CIPHER_standard_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[cfg(ossl111)] + pub fn standard_name(&self) -> Option<&'static str> { + unsafe { + let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } + } + + /// Returns the SSL/TLS protocol version that first defined the cipher. + /// + /// This corresponds to [`SSL_CIPHER_get_version`]. + /// + /// [`SSL_CIPHER_get_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + pub fn version(&self) -> &'static str { + let version = unsafe { + let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr()); + CStr::from_ptr(ptr as *const _) + }; + + str::from_utf8(version.to_bytes()).unwrap() + } + + /// Returns the number of bits used for the cipher. + /// + /// This corresponds to [`SSL_CIPHER_get_bits`]. + /// + /// [`SSL_CIPHER_get_bits`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + pub fn bits(&self) -> CipherBits { + unsafe { + let mut algo_bits = 0; + let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits); + CipherBits { + secret: secret_bits.into(), + algorithm: algo_bits.into(), + } + } + } + + /// Returns a textual description of the cipher. + /// + /// This corresponds to [`SSL_CIPHER_description`]. + /// + /// [`SSL_CIPHER_description`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + pub fn description(&self) -> String { + unsafe { + // SSL_CIPHER_description requires a buffer of at least 128 bytes. + let mut buf = [0; 128]; + let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128); + String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap() + } + } + + /// Returns the handshake digest of the cipher. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CIPHER_get_handshake_digest`]. + /// + /// [`SSL_CIPHER_get_handshake_digest`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CIPHER_get_handshake_digest.html + #[cfg(ossl111)] + pub fn handshake_digest(&self) -> Option { + unsafe { + let ptr = ffi::SSL_CIPHER_get_handshake_digest(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(MessageDigest::from_ptr(ptr)) + } + } + } + + /// Returns the NID corresponding to the cipher. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_CIPHER_get_cipher_nid`]. + /// + /// [`SSL_CIPHER_get_cipher_nid`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CIPHER_get_cipher_nid.html + #[cfg(any(ossl110))] + pub fn cipher_nid(&self) -> Option { + let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) }; + if n == 0 { + None + } else { + Some(Nid::from_raw(n)) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::SSL_SESSION; + fn drop = ffi::SSL_SESSION_free; + + /// An encoded SSL session. + /// + /// These can be cached to share sessions across connections. + pub struct SslSession; + + /// Reference to [`SslSession`]. + /// + /// [`SslSession`]: struct.SslSession.html + pub struct SslSessionRef; +} + +impl Clone for SslSession { + fn clone(&self) -> SslSession { + SslSessionRef::to_owned(self) + } +} + +impl SslSession { + from_der! { + /// Deserializes a DER-encoded session structure. + /// + /// This corresponds to [`d2i_SSL_SESSION`]. + /// + /// [`d2i_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/d2i_SSL_SESSION.html + from_der, + SslSession, + ffi::d2i_SSL_SESSION + } +} + +impl ToOwned for SslSessionRef { + type Owned = SslSession; + + fn to_owned(&self) -> SslSession { + unsafe { + SSL_SESSION_up_ref(self.as_ptr()); + SslSession(self.as_ptr()) + } + } +} + +impl SslSessionRef { + /// Returns the SSL session ID. + /// + /// This corresponds to [`SSL_SESSION_get_id`]. + /// + /// [`SSL_SESSION_get_id`]: https://www.openssl.org/docs/manmaster/man3/SSL_SESSION_get_id.html + pub fn id(&self) -> &[u8] { + unsafe { + let mut len = 0; + let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); + slice::from_raw_parts(p as *const u8, len as usize) + } + } + + /// Returns the length of the master key. + /// + /// This corresponds to [`SSL_SESSION_get_master_key`]. + /// + /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html + pub fn master_key_len(&self) -> usize { + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + } + + /// Copies the master key into the provided buffer. + /// + /// Returns the number of bytes written, or the size of the master key if the buffer is empty. + /// + /// This corresponds to [`SSL_SESSION_get_master_key`]. + /// + /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html + pub fn master_key(&self, buf: &mut [u8]) -> usize { + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + } + + /// Gets the maximum amount of early data that can be sent on this session. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_SESSION_get_max_early_data`]. + /// + /// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) } + } + + /// Returns the time at which the session was established, in seconds since the Unix epoch. + /// + /// This corresponds to [`SSL_SESSION_get_time`]. + /// + /// [`SSL_SESSION_get_time`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + pub fn time(&self) -> i64 { + unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()).into() } + } + + /// Returns the sessions timeout, in seconds. + /// + /// A session older than this time should not be used for session resumption. + /// + /// This corresponds to [`SSL_SESSION_get_timeout`]. + /// + /// [`SSL_SESSION_get_timeout`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + pub fn timeout(&self) -> i64 { + unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()).into() } + } + + /// Returns the session's TLS protocol version. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_SESSION_get_protocol_version`]. + /// + /// [`SSL_SESSION_get_protocol_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + #[cfg(ossl110)] + pub fn protocol_version(&self) -> SslVersion { + unsafe { + let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr()); + SslVersion(version) + } + } + + to_der! { + /// Serializes the session into a DER-encoded structure. + /// + /// This corresponds to [`i2d_SSL_SESSION`]. + /// + /// [`i2d_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/i2d_SSL_SESSION.html + to_der, + ffi::i2d_SSL_SESSION + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::SSL; + fn drop = ffi::SSL_free; + + /// The state of an SSL/TLS session. + /// + /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults. + /// These defaults can be overridden on a per-`Ssl` basis, however. + /// + /// [`SslContext`]: struct.SslContext.html + pub struct Ssl; + + /// Reference to an [`Ssl`]. + /// + /// [`Ssl`]: struct.Ssl.html + pub struct SslRef; +} + +impl fmt::Debug for Ssl { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, fmt) + } +} + +impl Ssl { + /// Returns a new extra data index. + /// + /// Each invocation of this function is guaranteed to return a distinct index. These can be used + /// to store data in the context that can be retrieved later by callbacks, for example. + /// + /// This corresponds to [`SSL_get_ex_new_index`]. + /// + /// [`SSL_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_ex_new_index.html + pub fn new_ex_index() -> Result, ErrorStack> + where + T: 'static + Sync + Send, + { + unsafe { + ffi::init(); + let idx = cvt_n(get_new_ssl_idx(free_data_box::))?; + Ok(Index::from_raw(idx)) + } + } + + // FIXME should return a result? + fn cached_ex_index() -> Index + where + T: 'static + Sync + Send, + { + unsafe { + let idx = *SSL_INDEXES + .lock() + .unwrap_or_else(|e| e.into_inner()) + .entry(TypeId::of::()) + .or_insert_with(|| Ssl::new_ex_index::().unwrap().as_raw()); + Index::from_raw(idx) + } + } + + /// Creates a new `Ssl`. + /// + /// This corresponds to [`SSL_new`]. + /// + /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html + // FIXME should take &SslContextRef + pub fn new(ctx: &SslContext) -> Result { + unsafe { + let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; + let mut ssl = Ssl::from_ptr(ptr); + ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.clone()); + + Ok(ssl) + } + } + + /// Initiates a client-side TLS handshake. + /// + /// This corresponds to [`SSL_connect`]. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. + /// + /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html + pub fn connect(self, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + SslStreamBuilder::new(self, stream).connect() + } + + /// Initiates a server-side TLS handshake. + /// + /// This corresponds to [`SSL_accept`]. + /// + /// # Warning + /// + /// OpenSSL's default configuration is insecure. It is highly recommended to use + /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. + /// + /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html + pub fn accept(self, stream: S) -> Result, HandshakeError> + where + S: Read + Write, + { + SslStreamBuilder::new(self, stream).accept() + } +} + +impl fmt::Debug for SslRef { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Ssl") + .field("state", &self.state_string_long()) + .field("verify_result", &self.verify_result()) + .finish() + } +} + +impl SslRef { + fn get_raw_rbio(&self) -> *mut ffi::BIO { + unsafe { ffi::SSL_get_rbio(self.as_ptr()) } + } + + fn read(&mut self, buf: &mut [u8]) -> c_int { + let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; + unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) } + } + + fn write(&mut self, buf: &[u8]) -> c_int { + let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; + unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) } + } + + fn get_error(&self, ret: c_int) -> ErrorCode { + unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } + } + + /// Like [`SslContextBuilder::set_verify`]. + /// + /// This corresponds to [`SSL_set_verify`]. + /// + /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify + /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + pub fn set_verify(&mut self, mode: SslVerifyMode) { + unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) } + } + + /// Like [`SslContextBuilder::set_verify_callback`]. + /// + /// This corresponds to [`SSL_set_verify`]. + /// + /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback + /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) + where + F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, + { + unsafe { + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify)); + ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::)); + } + } + + /// Like [`SslContextBuilder::set_tmp_dh`]. + /// + /// This corresponds to [`SSL_set_tmp_dh`]. + /// + /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh + /// [`SSL_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html + pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } + } + + /// Like [`SslContextBuilder::set_tmp_dh_callback`]. + /// + /// This corresponds to [`SSL_set_tmp_dh_callback`]. + /// + /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback + /// [`SSL_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html + pub fn set_tmp_dh_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, + { + unsafe { + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); + ffi::SSL_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh_ssl::); + } + } + + /// Like [`SslContextBuilder::set_tmp_ecdh`]. + /// + /// This corresponds to `SSL_set_tmp_ecdh`. + /// + /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } + } + + /// Like [`SslContextBuilder::set_tmp_ecdh_callback`]. + /// + /// Requires OpenSSL 1.0.1 or 1.0.2. + /// + /// This corresponds to `SSL_set_tmp_ecdh_callback`. + /// + /// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback + #[cfg(any(all(ossl101, not(ossl110))))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, + { + unsafe { + // this needs to be in an Arc since the callback can register a new callback! + self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); + ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh_ssl::); + } + } + + /// Like [`SslContextBuilder::set_ecdh_auto`]. + /// + /// Requires OpenSSL 1.0.2. + /// + /// This corresponds to [`SSL_set_ecdh_auto`]. + /// + /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh + /// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html + #[cfg(all(ossl102, not(ossl110)))] + pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } + } + + /// Like [`SslContextBuilder::set_alpn_protos`]. + /// + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + /// + /// This corresponds to [`SSL_set_alpn_protos`]. + /// + /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos + /// [`SSL_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_alpn_protos.html + #[cfg(any(ossl102, libressl261))] + pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(protocols.len() <= c_uint::max_value() as usize); + let r = ffi::SSL_set_alpn_protos( + self.as_ptr(), + protocols.as_ptr(), + protocols.len() as c_uint, + ); + // fun fact, SSL_set_alpn_protos has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + } + + /// Returns the current cipher if the session is active. + /// + /// This corresponds to [`SSL_get_current_cipher`]. + /// + /// [`SSL_get_current_cipher`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_current_cipher.html + pub fn current_cipher(&self) -> Option<&SslCipherRef> { + unsafe { + let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); + + if ptr.is_null() { + None + } else { + Some(SslCipherRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Returns a short string describing the state of the session. + /// + /// This corresponds to [`SSL_state_string`]. + /// + /// [`SSL_state_string`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_state_string.html + pub fn state_string(&self) -> &'static str { + let state = unsafe { + let ptr = ffi::SSL_state_string(self.as_ptr()); + CStr::from_ptr(ptr as *const _) + }; + + str::from_utf8(state.to_bytes()).unwrap() + } + + /// Returns a longer string describing the state of the session. + /// + /// This corresponds to [`SSL_state_string_long`]. + /// + /// [`SSL_state_string_long`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_state_string_long.html + pub fn state_string_long(&self) -> &'static str { + let state = unsafe { + let ptr = ffi::SSL_state_string_long(self.as_ptr()); + CStr::from_ptr(ptr as *const _) + }; + + str::from_utf8(state.to_bytes()).unwrap() + } + + /// Sets the host name to be sent to the server for Server Name Indication (SNI). + /// + /// It has no effect for a server-side connection. + /// + /// This corresponds to [`SSL_set_tlsext_host_name`]. + /// + /// [`SSL_set_tlsext_host_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername_type.html + pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> { + let cstr = CString::new(hostname).unwrap(); + unsafe { + cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int) + .map(|_| ()) + } + } + + /// Returns the peer's certificate, if present. + /// + /// This corresponds to [`SSL_get_peer_certificate`]. + /// + /// [`SSL_get_peer_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_certificate.html + pub fn peer_certificate(&self) -> Option { + unsafe { + let ptr = ffi::SSL_get_peer_certificate(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(X509::from_ptr(ptr)) + } + } + } + + /// Returns the certificate chain of the peer, if present. + /// + /// On the client side, the chain includes the leaf certificate, but on the server side it does + /// not. Fun! + /// + /// This corresponds to [`SSL_get_peer_cert_chain`]. + /// + /// [`SSL_get_peer_cert_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_cert_chain.html + pub fn peer_cert_chain(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(StackRef::from_ptr(ptr)) + } + } + } + + /// Returns the verified certificate chani of the peer, including the leaf certificate. + /// + /// If verification was not successful (i.e. [`verify_result`] does not return + /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_get0_verified_chain`]. + /// + /// [`verify_result`]: #method.verify_result + /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK + /// [`SSL_get0_verified_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get0_verified_chain.html + #[cfg(ossl110)] + pub fn verified_chain(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::SSL_get0_verified_chain(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(StackRef::from_ptr(ptr)) + } + } + } + + /// Like [`SslContext::certificate`]. + /// + /// This corresponds to `SSL_get_certificate`. + /// + /// [`SslContext::certificate`]: struct.SslContext.html#method.certificate + pub fn certificate(&self) -> Option<&X509Ref> { + unsafe { + let ptr = ffi::SSL_get_certificate(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(X509Ref::from_ptr(ptr)) + } + } + } + + /// Like [`SslContext::private_key`]. + /// + /// This corresponds to `SSL_get_privatekey`. + /// + /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key + pub fn private_key(&self) -> Option<&PKeyRef> { + unsafe { + let ptr = ffi::SSL_get_privatekey(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(PKeyRef::from_ptr(ptr)) + } + } + } + + #[deprecated(since = "0.10.5", note = "renamed to `version_str`")] + pub fn version(&self) -> &str { + self.version_str() + } + + /// Returns the protocol version of the session. + /// + /// This corresponds to [`SSL_version`]. + /// + /// [`SSL_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_version.html + pub fn version2(&self) -> Option { + unsafe { + let r = ffi::SSL_version(self.as_ptr()); + if r == 0 { + None + } else { + Some(SslVersion(r)) + } + } + } + + /// Returns a string describing the protocol version of the session. + /// + /// This corresponds to [`SSL_get_version`]. + /// + /// [`SSL_get_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_version.html + pub fn version_str(&self) -> &'static str { + let version = unsafe { + let ptr = ffi::SSL_get_version(self.as_ptr()); + CStr::from_ptr(ptr as *const _) + }; + + str::from_utf8(version.to_bytes()).unwrap() + } + + /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN). + /// + /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client + /// to interpret it. + /// + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. + /// + /// This corresponds to [`SSL_get0_alpn_selected`]. + /// + /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html + #[cfg(any(ossl102, libressl261))] + pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { + unsafe { + let mut data: *const c_uchar = ptr::null(); + let mut len: c_uint = 0; + // Get the negotiated protocol from the SSL instance. + // `data` will point at a `c_uchar` array; `len` will contain the length of this array. + ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len); + + if data.is_null() { + None + } else { + Some(slice::from_raw_parts(data, len as usize)) + } + } + } + + /// Enables the DTLS extension "use_srtp" as defined in RFC5764. + /// + /// This corresponds to [`SSL_set_tlsext_use_srtp`]. + /// + /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { + unsafe { + let cstr = CString::new(protocols).unwrap(); + + let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); + // fun fact, set_tlsext_use_srtp has a reversed return code D: + if r == 0 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + } + + /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp + /// + /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. + /// + /// This corresponds to [`SSL_get_srtp_profiles`]. + /// + /// [`SSL_get_srtp_profiles`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + pub fn srtp_profiles(&self) -> Option<&StackRef> { + unsafe { + let chain = ffi::SSL_get_srtp_profiles(self.as_ptr()); + + if chain.is_null() { + None + } else { + Some(StackRef::from_ptr(chain)) + } + } + } + + /// Gets the SRTP profile selected by handshake. + /// + /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. + /// + /// This corresponds to [`SSL_get_selected_srtp_profile`]. + /// + /// [`SSL_get_selected_srtp_profile`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> { + unsafe { + let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr()); + + if profile.is_null() { + None + } else { + Some(SrtpProtectionProfileRef::from_ptr(profile as *mut _)) + } + } + } + + /// Returns the number of bytes remaining in the currently processed TLS record. + /// + /// If this is greater than 0, the next call to `read` will not call down to the underlying + /// stream. + /// + /// This corresponds to [`SSL_pending`]. + /// + /// [`SSL_pending`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_pending.html + pub fn pending(&self) -> usize { + unsafe { ffi::SSL_pending(self.as_ptr()) as usize } + } + + /// Returns the servername sent by the client via Server Name Indication (SNI). + /// + /// It is only useful on the server side. + /// + /// This corresponds to [`SSL_get_servername`]. + /// + /// # Note + /// + /// While the SNI specification requires that servernames be valid domain names (and therefore + /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client + /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns + /// the raw bytes and does not have this restriction. + /// + /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + // FIXME maybe rethink in 0.11? + pub fn servername(&self, type_: NameType) -> Option<&str> { + self.servername_raw(type_) + .and_then(|b| str::from_utf8(b).ok()) + } + + /// Returns the servername sent by the client via Server Name Indication (SNI). + /// + /// It is only useful on the server side. + /// + /// This corresponds to [`SSL_get_servername`]. + /// + /// # Note + /// + /// Unlike `servername`, this method does not require the name be valid UTF-8. + /// + /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { + unsafe { + let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); + if name == ptr::null() { + None + } else { + Some(CStr::from_ptr(name as *const _).to_bytes()) + } + } + } + + /// Changes the context corresponding to the current connection. + /// + /// It is most commonly used in the Server Name Indication (SNI) callback. + /// + /// This corresponds to `SSL_set_SSL_CTX`. + pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> { + unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } + } + + /// Returns the context corresponding to the current connection. + /// + /// This corresponds to [`SSL_get_SSL_CTX`]. + /// + /// [`SSL_get_SSL_CTX`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_SSL_CTX.html + pub fn ssl_context(&self) -> &SslContextRef { + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); + SslContextRef::from_ptr(ssl_ctx) + } + } + + /// Returns a mutable reference to the X509 verification configuration. + /// + /// Requires OpenSSL 1.0.2 or newer. + /// + /// This corresponds to [`SSL_get0_param`]. + /// + /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html + #[cfg(any(ossl102, libressl261))] + pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { + unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } + } + + /// Returns the certificate verification result. + /// + /// This corresponds to [`SSL_get_verify_result`]. + /// + /// [`SSL_get_verify_result`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html + pub fn verify_result(&self) -> X509VerifyResult { + unsafe { X509VerifyResult::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) } + } + + /// Returns a shared reference to the SSL session. + /// + /// This corresponds to [`SSL_get_session`]. + /// + /// [`SSL_get_session`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_session.html + pub fn session(&self) -> Option<&SslSessionRef> { + unsafe { + let p = ffi::SSL_get_session(self.as_ptr()); + if p.is_null() { + None + } else { + Some(SslSessionRef::from_ptr(p)) + } + } + } + + /// Copies the client_random value sent by the client in the TLS handshake into a buffer. + /// + /// Returns the number of bytes copied, or if the buffer is empty, the size of the client_random + /// value. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_get_client_random`]. + /// + /// [`SSL_get_client_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html + #[cfg(any(ossl110))] + pub fn client_random(&self, buf: &mut [u8]) -> usize { + unsafe { + ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) + } + } + + /// Copies the server_random value sent by the server in the TLS handshake into a buffer. + /// + /// Returns the number of bytes copied, or if the buffer is empty, the size of the server_random + /// value. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_get_server_random`]. + /// + /// [`SSL_get_server_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html + #[cfg(any(ossl110))] + pub fn server_random(&self, buf: &mut [u8]) -> usize { + unsafe { + ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) + } + } + + /// Derives keying material for application use in accordance to RFC 5705. + /// + /// This corresponds to [`SSL_export_keying_material`]. + /// + /// [`SSL_export_keying_material`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material.html + pub fn export_keying_material( + &self, + out: &mut [u8], + label: &str, + context: Option<&[u8]>, + ) -> Result<(), ErrorStack> { + unsafe { + let (context, contextlen, use_context) = match context { + Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1), + None => (ptr::null(), 0, 0), + }; + cvt(ffi::SSL_export_keying_material( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context, + contextlen, + use_context, + )) + .map(|_| ()) + } + } + + /// Derives keying material for application use in accordance to RFC 5705. + /// + /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no + /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_export_keying_material_early`]. + /// + /// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html + #[cfg(ossl111)] + pub fn export_keying_material_early( + &self, + out: &mut [u8], + label: &str, + context: &[u8], + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_export_keying_material_early( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context.as_ptr() as *const c_uchar, + context.len(), + )) + .map(|_| ()) + } + } + + /// Sets the session to be used. + /// + /// This should be called before the handshake to attempt to reuse a previously established + /// session. If the server is not willing to reuse the session, a new one will be transparently + /// negotiated. + /// + /// This corresponds to [`SSL_set_session`]. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session is associated + /// with the same `SslContext` as this `Ssl`. + /// + /// [`SSL_set_session`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_session.html + pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { + cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) + } + + /// Determines if the session provided to `set_session` was successfully reused. + /// + /// This corresponds to [`SSL_session_reused`]. + /// + /// [`SSL_session_reused`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_session_reused.html + pub fn session_reused(&self) -> bool { + unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 } + } + + /// Sets the status response a client wishes the server to reply with. + /// + /// This corresponds to [`SSL_set_tlsext_status_type`]. + /// + /// [`SSL_set_tlsext_status_type`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) + } + } + + /// Returns the server's OCSP response, if present. + /// + /// This corresponds to [`SSL_get_tlsext_status_ocsp_resp`]. + /// + /// [`SSL_get_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + pub fn ocsp_status(&self) -> Option<&[u8]> { + unsafe { + let mut p = ptr::null_mut(); + let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p); + + if len < 0 { + None + } else { + Some(slice::from_raw_parts(p as *const u8, len as usize)) + } + } + } + + /// Sets the OCSP response to be returned to the client. + /// + /// This corresponds to [`SSL_set_tlsext_status_ocsp_resp`]. + /// + /// [`SSL_set_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(response.len() <= c_int::max_value() as usize); + let p = cvt_p(ffi::CRYPTO_malloc( + response.len() as _, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as c_int, + ))?; + ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); + cvt(ffi::SSL_set_tlsext_status_ocsp_resp( + self.as_ptr(), + p as *mut c_uchar, + response.len() as c_long, + ) as c_int) + .map(|_| ()) + } + } + + /// Determines if this `Ssl` is configured for server-side or client-side use. + /// + /// This corresponds to [`SSL_is_server`]. + /// + /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html + pub fn is_server(&self) -> bool { + unsafe { SSL_is_server(self.as_ptr()) != 0 } + } + + /// Sets the extra data at the specified index. + /// + /// This can be used to provide data to callbacks registered with the context. Use the + /// `Ssl::new_ex_index` method to create an `Index`. + /// + /// This corresponds to [`SSL_set_ex_data`]. + /// + /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + pub fn set_ex_data(&mut self, index: Index, data: T) { + unsafe { + let data = Box::new(data); + ffi::SSL_set_ex_data( + self.as_ptr(), + index.as_raw(), + Box::into_raw(data) as *mut c_void, + ); + } + } + + /// Returns a reference to the extra data at the specified index. + /// + /// This corresponds to [`SSL_get_ex_data`]. + /// + /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + pub fn ex_data(&self, index: Index) -> Option<&T> { + unsafe { + let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&*(data as *const T)) + } + } + } + + /// Returns a mutable reference to the extra data at the specified index. + /// + /// This corresponds to [`SSL_get_ex_data`]. + /// + /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + pub fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { + unsafe { + let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&mut *(data as *mut T)) + } + } + } + + /// Sets the maximum amount of early data that will be accepted on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_set_max_early_data`]. + /// + /// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Gets the maximum amount of early data that can be sent on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_get_max_early_data`]. + /// + /// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } + } + + /// Copies the contents of the last Finished message sent to the peer into the provided buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn finished(&self, buf: &mut [u8]) -> usize { + unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } + } + + /// Copies the contents of the last Finished message received from the peer into the provided + /// buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn peer_finished(&self, buf: &mut [u8]) -> usize { + unsafe { + ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) + } + } + + /// Determines if the client's hello message is in the SSLv2 format. + /// + /// This can only be used inside of the client hello callback. Otherwise, `false` is returned. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_isv2`]. + /// + /// [`SSL_client_hello_isv2`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_isv2(&self) -> bool { + unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 } + } + + /// Returns the legacy version field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_get0_legacy_version`]. + /// + /// [`SSL_client_hello_get0_legacy_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_legacy_version(&self) -> Option { + unsafe { + let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr()); + if version == 0 { + None + } else { + Some(SslVersion(version as c_int)) + } + } + } + + /// Returns the random field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_get0_random`]. + /// + /// [`SSL_client_hello_get0_random`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_random(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the session ID field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_get0_session_id`]. + /// + /// [`SSL_client_hello_get0_session_id`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_session_id(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the ciphers field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_get0_ciphers`]. + /// + /// [`SSL_client_hello_get0_ciphers`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_ciphers(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } + + /// Returns the compression methods field of the client's hello message. + /// + /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_client_hello_get0_compression_methods`]. + /// + /// [`SSL_client_hello_get0_compression_methods`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html + #[cfg(ossl111)] + pub fn client_hello_compression_methods(&self) -> Option<&[u8]> { + unsafe { + let mut ptr = ptr::null(); + let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr); + if len == 0 { + None + } else { + Some(slice::from_raw_parts(ptr, len)) + } + } + } +} + +/// An SSL stream midway through the handshake process. +#[derive(Debug)] +pub struct MidHandshakeSslStream { + stream: SslStream, + error: Error, +} + +impl MidHandshakeSslStream { + /// Returns a shared reference to the inner stream. + pub fn get_ref(&self) -> &S { + self.stream.get_ref() + } + + /// Returns a mutable reference to the inner stream. + pub fn get_mut(&mut self) -> &mut S { + self.stream.get_mut() + } + + /// Returns a shared reference to the `Ssl` of the stream. + pub fn ssl(&self) -> &SslRef { + self.stream.ssl() + } + + /// Returns the underlying error which interrupted this handshake. + pub fn error(&self) -> &Error { + &self.error + } + + /// Consumes `self`, returning its error. + pub fn into_error(self) -> Error { + self.error + } + + /// Restarts the handshake process. + /// + /// This corresponds to [`SSL_do_handshake`]. + /// + /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + pub fn handshake(mut self) -> Result, HandshakeError> { + let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(self.stream) + } else { + self.error = self.stream.make_error(ret); + match self.error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(self)) + } + _ => Err(HandshakeError::Failure(self)), + } + } + } +} + +/// A TLS session over a stream. +pub struct SslStream { + ssl: ManuallyDrop, + method: ManuallyDrop, + _p: PhantomData, +} + +impl Drop for SslStream { + fn drop(&mut self) { + // ssl holds a reference to method internally so it has to drop first + unsafe { + ManuallyDrop::drop(&mut self.ssl); + ManuallyDrop::drop(&mut self.method); + } + } +} + +impl fmt::Debug for SslStream +where + S: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("SslStream") + .field("stream", &self.get_ref()) + .field("ssl", &self.ssl()) + .finish() + } +} + +impl SslStream { + fn new_base(ssl: Ssl, stream: S) -> Self { + unsafe { + let (bio, method) = bio::new(stream).unwrap(); + ffi::SSL_set_bio(ssl.as_ptr(), bio, bio); + + SslStream { + ssl: ManuallyDrop::new(ssl), + method: ManuallyDrop::new(method), + _p: PhantomData, + } + } + } + + /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. + /// + /// It is particularly useful with a nonblocking socket, where the error value will identify if + /// OpenSSL is waiting on read or write readiness. + /// + /// This corresponds to [`SSL_read`]. + /// + /// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html + pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { + // The intepretation of the return code here is a little odd with a + // zero-length write. OpenSSL will likely correctly report back to us + // that it read zero bytes, but zero is also the sentinel for "error". + // To avoid that confusion short-circuit that logic and return quickly + // if `buf` has a length of zero. + if buf.len() == 0 { + return Ok(0); + } + + let ret = self.ssl.read(buf); + if ret > 0 { + Ok(ret as usize) + } else { + Err(self.make_error(ret)) + } + } + + /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`. + /// + /// It is particularly useful with a nonblocking socket, where the error value will identify if + /// OpenSSL is waiting on read or write readiness. + /// + /// This corresponds to [`SSL_write`]. + /// + /// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html + pub fn ssl_write(&mut self, buf: &[u8]) -> Result { + // See above for why we short-circuit on zero-length buffers + if buf.len() == 0 { + return Ok(0); + } + + let ret = self.ssl.write(buf); + if ret > 0 { + Ok(ret as usize) + } else { + Err(self.make_error(ret)) + } + } + + /// Shuts down the session. + /// + /// The shutdown process consists of two steps. The first step sends a close notify message to + /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt + /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned. + /// + /// While the connection may be closed after the first step, it is recommended to fully shut the + /// session down. In particular, it must be fully shut down if the connection is to be used for + /// further communication in the future. + /// + /// This corresponds to [`SSL_shutdown`]. + /// + /// [`SSL_shutdown`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_shutdown.html + pub fn shutdown(&mut self) -> Result { + match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } { + 0 => Ok(ShutdownResult::Sent), + 1 => Ok(ShutdownResult::Received), + n => Err(self.make_error(n)), + } + } + + /// Returns the session's shutdown state. + /// + /// This corresponds to [`SSL_get_shutdown`]. + /// + /// [`SSL_get_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html + pub fn get_shutdown(&mut self) -> ShutdownState { + unsafe { + let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr()); + ShutdownState { bits } + } + } + + /// Sets the session's shutdown state. + /// + /// This can be used to tell OpenSSL that the session should be cached even if a full two-way + /// shutdown was not completed. + /// + /// This corresponds to [`SSL_set_shutdown`]. + /// + /// [`SSL_set_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html + pub fn set_shutdown(&mut self, state: ShutdownState) { + unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) } + } +} + +impl SslStream { + fn make_error(&mut self, ret: c_int) -> Error { + self.check_panic(); + + let code = self.ssl.get_error(ret); + + let cause = match code { + ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())), + ErrorCode::SYSCALL => { + let errs = ErrorStack::get(); + if errs.errors().is_empty() { + self.get_bio_error().map(InnerError::Io) + } else { + Some(InnerError::Ssl(errs)) + } + } + ErrorCode::ZERO_RETURN => None, + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + self.get_bio_error().map(InnerError::Io) + } + _ => None, + }; + + Error { code, cause } + } + + fn check_panic(&mut self) { + if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { + resume_unwind(err) + } + } + + fn get_bio_error(&mut self) -> Option { + unsafe { bio::take_error::(self.ssl.get_raw_rbio()) } + } + + /// Returns a shared reference to the underlying stream. + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_ref(bio) + } + } + + /// Returns a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read from or write to the underlying stream as it + /// will most likely corrupt the SSL session. + pub fn get_mut(&mut self) -> &mut S { + unsafe { + let bio = self.ssl.get_raw_rbio(); + bio::get_mut(bio) + } + } + + /// Returns a shared reference to the `Ssl` object associated with this stream. + pub fn ssl(&self) -> &SslRef { + &self.ssl + } +} + +impl Read for SslStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + loop { + match self.ssl_read(buf) { + Ok(n) => return Ok(n), + Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0), + Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => { + return Ok(0); + } + Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} + Err(e) => { + return Err(e + .into_io_error() + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); + } + } + } + } +} + +impl Write for SslStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + loop { + match self.ssl_write(buf) { + Ok(n) => return Ok(n), + Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} + Err(e) => { + return Err(e + .into_io_error() + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); + } + } + } + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +/// A partially constructed `SslStream`, useful for unusual handshakes. +pub struct SslStreamBuilder { + inner: SslStream, +} + +impl SslStreamBuilder +where + S: Read + Write, +{ + /// Begin creating an `SslStream` atop `stream` + pub fn new(ssl: Ssl, stream: S) -> Self { + Self { + inner: SslStream::new_base(ssl, stream), + } + } + + /// Perform a stateless server-side handshake + /// + /// Requires that cookie generation and verification callbacks were + /// set on the SSL context. + /// + /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie + /// was read, in which case the handshake should be continued via + /// `accept`. If a HelloRetryRequest containing a fresh cookie was + /// transmitted, `Ok(false)` is returned instead. If the handshake cannot + /// proceed at all, `Err` is returned. + /// + /// This corresponds to [`SSL_stateless`] + /// + /// [`SSL_stateless`]: https://www.openssl.org/docs/manmaster/man3/SSL_stateless.html + #[cfg(ossl111)] + pub fn stateless(&mut self) -> Result { + match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } { + 1 => Ok(true), + 0 => Ok(false), + -1 => Err(ErrorStack::get()), + _ => unreachable!(), + } + } + + /// Configure as an outgoing stream from a client. + /// + /// This corresponds to [`SSL_set_connect_state`]. + /// + /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html + pub fn set_connect_state(&mut self) { + unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } + } + + /// Configure as an incoming stream to a server. + /// + /// This corresponds to [`SSL_set_accept_state`]. + /// + /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html + pub fn set_accept_state(&mut self) { + unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } + } + + /// See `Ssl::connect` + pub fn connect(self) -> Result, HandshakeError> { + let mut stream = self.inner; + let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(stream) + } else { + let error = stream.make_error(ret); + match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream, + error, + })), + } + } + } + + /// See `Ssl::accept` + pub fn accept(self) -> Result, HandshakeError> { + let mut stream = self.inner; + let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(stream) + } else { + let error = stream.make_error(ret); + match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream, + error, + })), + } + } + } + + /// Initiates the handshake. + /// + /// This will fail if `set_accept_state` or `set_connect_state` was not called first. + /// + /// This corresponds to [`SSL_do_handshake`]. + /// + /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + pub fn handshake(self) -> Result, HandshakeError> { + let mut stream = self.inner; + let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(stream) + } else { + let error = stream.make_error(ret); + match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(HandshakeError::WouldBlock(MidHandshakeSslStream { + stream, + error, + })) + } + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream, + error, + })), + } + } + } + + /// Read application data transmitted by a client before handshake + /// completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_accept_state` first. + /// + /// Returns `Ok(0)` if all early data has been read. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_read_early_data`]. + /// + /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html + #[cfg(ossl111)] + pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { + let mut read = 0; + let ret = unsafe { + ffi::SSL_read_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *mut c_void, + buf.len(), + &mut read, + ) + }; + match ret { + ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)), + ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), + ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0), + _ => unreachable!(), + } + } + + /// Send data to the server without blocking on handshake completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_connect_state` first. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_write_early_data`]. + /// + /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html + #[cfg(ossl111)] + pub fn write_early_data(&mut self, buf: &[u8]) -> Result { + let mut written = 0; + let ret = unsafe { + ffi::SSL_write_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *const c_void, + buf.len(), + &mut written, + ) + }; + if ret > 0 { + Ok(written as usize) + } else { + Err(self.inner.make_error(ret)) + } + } +} + +impl SslStreamBuilder { + /// Returns a shared reference to the underlying stream. + pub fn get_ref(&self) -> &S { + unsafe { + let bio = self.inner.ssl.get_raw_rbio(); + bio::get_ref(bio) + } + } + + /// Returns a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read from or write to the underlying stream as it + /// will most likely corrupt the SSL session. + pub fn get_mut(&mut self) -> &mut S { + unsafe { + let bio = self.inner.ssl.get_raw_rbio(); + bio::get_mut(bio) + } + } + + /// Returns a shared reference to the `Ssl` object associated with this builder. + pub fn ssl(&self) -> &SslRef { + &self.inner.ssl + } +} + +/// The result of a shutdown request. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ShutdownResult { + /// A close notify message has been sent to the peer. + Sent, + + /// A close notify response message has been received from the peer. + Received, +} + +bitflags! { + /// The shutdown state of a session. + pub struct ShutdownState: c_int { + /// A close notify message has been sent to the peer. + const SENT = ffi::SSL_SENT_SHUTDOWN; + /// A close notify message has been received from the peer. + const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN; + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server}; + } else { + #[allow(bad_style)] + pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ssl).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } + + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_get_master_key( + session: *const ffi::SSL_SESSION, + out: *mut c_uchar, + mut outlen: usize, + ) -> usize { + if outlen == 0 { + return (*session).master_key_length as usize; + } + if outlen > (*session).master_key_length as usize { + outlen = (*session).master_key_length as usize; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen + } + + #[allow(bad_style)] + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } + + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ses).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl291))] { + use ffi::{TLS_method, DTLS_method}; + } else { + use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method}; + } +} +cfg_if! { + if #[cfg(ossl110)] { + unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL_CTX, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } + + unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } + } else { + unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } + + unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } + } +} diff --git a/openssl/src/ssl/test/mod.rs b/openssl/src/ssl/test/mod.rs new file mode 100644 index 000000000..c1f730ec4 --- /dev/null +++ b/openssl/src/ssl/test/mod.rs @@ -0,0 +1,1413 @@ +#![allow(unused_imports)] + +use hex; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufReader}; +use std::iter; +use std::mem; +use std::net::UdpSocket; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::path::Path; +use std::process::{Child, ChildStdin, Command, Stdio}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::Duration; +use tempdir::TempDir; + +use dh::Dh; +use hash::MessageDigest; +use ocsp::{OcspResponse, OcspResponseStatus}; +use pkey::PKey; +use srtp::SrtpProfileId; +use ssl; +use ssl::test::server::Server; +#[cfg(any(ossl110, ossl111, libressl261))] +use ssl::SslVersion; +#[cfg(ossl111)] +use ssl::{ClientHelloResponse, ExtensionContext}; +use ssl::{ + Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor, + SslConnector, SslContext, SslFiletype, SslMethod, SslOptions, SslSessionCacheMode, SslStream, + SslVerifyMode, StatusType, SslContextBuilder +}; +#[cfg(ossl102)] +use x509::store::X509StoreBuilder; +#[cfg(ossl102)] +use x509::verify::X509CheckFlags; +use x509::{X509Name, X509StoreContext, X509VerifyResult, X509}; + +mod server; + +static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem"); +static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); +static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); + +#[test] +fn verify_untrusted() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect_err(); +} + +#[test] +fn verify_trusted() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_trusted_with_set_cert() { + let server = Server::builder().build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + client.ctx().set_verify_cert_store(store.build()).unwrap(); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_trusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_callback_load_certs() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_eq!(x509.error(), X509VerifyResult::OK); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_err() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_ne!(x509.error(), X509VerifyResult::OK); + false + }); + + client.connect_err(); +} + +#[test] +fn verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); + let cert = x509.current_cert().unwrap(); + let digest = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!(hex::encode(&digest), expected); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn ssl_verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client().build().builder(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ssl() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); + let cert = x509.current_cert().unwrap(); + let digest = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!(hex::encode(&digest), expected); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn get_ctx_options() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.options(); +} + +#[test] +fn set_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let opts = ctx.set_options(SslOptions::NO_TICKET); + assert!(opts.contains(SslOptions::NO_TICKET)); +} + +#[test] +fn clear_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_options(SslOptions::ALL); + let opts = ctx.clear_options(SslOptions::ALL); + assert!(!opts.contains(SslOptions::ALL)); +} + +#[test] +fn zero_length_buffers() { + let server = Server::builder().build(); + + let mut s = server.client().connect(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.read(&mut []).unwrap(), 0); +} + +#[test] +fn peer_certificate() { + let server = Server::builder().build(); + + let s = server.client().connect(); + let cert = s.ssl().peer_certificate().unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!( + hex::encode(fingerprint), + "59172d9313e84459bcff27f967e79e6e9217e584" + ); +} + +#[test] +fn pending() { + let mut server = Server::builder(); + server.io_cb(|mut s| s.write_all(&[0; 10]).unwrap()); + let server = server.build(); + + let mut s = server.client().connect(); + s.read_exact(&mut [0]).unwrap(); + + assert_eq!(s.ssl().pending(), 9); + assert_eq!(s.read(&mut [0; 10]).unwrap(), 9); +} + +#[test] +fn state() { + let server = Server::builder().build(); + + let s = server.client().connect(); + assert_eq!(s.ssl().state_string(), "SSLOK "); + assert_eq!( + s.ssl().state_string_long(), + "SSL negotiation finished successfully" + ); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +#[cfg_attr(libressl291, ignore)] +fn test_connect_with_srtp_ctx() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +#[cfg_attr(libressl291, ignore)] +fn test_connect_with_srtp_ssl() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let mut profilenames = String::new(); + for profile in ssl.srtp_profiles().unwrap() { + if profilenames.len() > 0 { + profilenames.push(':'); + } + profilenames += profile.name(); + } + assert_eq!( + "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", + profilenames + ); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when the `SslStream` is created as a server stream, the protocols +/// are correctly advertised to the client. +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_advertise_multiple() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x08spdy/3.1").unwrap(); + let s = client.connect(); + assert_eq!(s.ssl().selected_alpn_protocol(), Some(&b"spdy/3.1"[..])); +} + +#[test] +#[cfg(any(ossl110))] +fn test_alpn_server_select_none_fatal() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client) + .ok_or(ssl::AlpnError::ALERT_FATAL) + }); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + client.connect_err(); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_select_none() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_unilateral() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[should_panic(expected = "blammo")] +fn write_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, _: &[u8]) -> io::Result { + panic!("blammo"); + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[should_panic(expected = "blammo")] +fn read_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, _: &mut [u8]) -> io::Result { + panic!("blammo"); + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[should_panic(expected = "blammo")] +fn flush_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + panic!("blammo"); + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +fn refcount_ssl_context() { + let mut ssl = { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ssl::Ssl::new(&ctx.build()).unwrap() + }; + + { + let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); + let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); + } +} + +#[test] +#[cfg_attr(libressl250, ignore)] +#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] +fn default_verify_paths() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_default_verify_paths().unwrap(); + ctx.set_verify(SslVerifyMode::PEER); + let ctx = ctx.build(); + let s = TcpStream::connect("google.com:443").unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_hostname("google.com").unwrap(); + let mut socket = ssl.connect(s).unwrap(); + + socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut result = vec![]; + socket.read_to_end(&mut result).unwrap(); + + println!("{}", String::from_utf8_lossy(&result)); + assert!(result.starts_with(b"HTTP/1.0")); + assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); +} + +#[test] +fn add_extra_chain_cert() { + let cert = X509::from_pem(CERT).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.add_extra_chain_cert(cert).unwrap(); +} + +#[test] +#[cfg(ossl102)] +fn verify_valid_hostname() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("foobar.com").unwrap(); + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("bogus.com").unwrap(); + client.connect_err(); +} + +#[test] +fn connector_valid_hostname() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector.build().connect("foobar.com", s).unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + connector.build().connect("bogus.com", s).unwrap_err(); +} + +#[test] +fn connector_invalid_no_hostname_verification() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .verify_hostname(false) + .connect("bogus.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_no_hostname_still_verifies() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); + + let s = server.connect_tcp(); + assert!(connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("fizzbuzz.com", s) + .is_err()); +} + +#[test] +fn connector_no_hostname_can_disable_verify() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_verify(SslVerifyMode::NONE); + let connector = connector.build(); + + let s = server.connect_tcp(); + let mut s = connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("foobar.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_client_server_mozilla_intermediate() { + let listener = TcpListener::bind("127.0.0.1:1234").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let t = thread::spawn(move || { + let key = PKey::private_key_from_pem(KEY).unwrap(); + let cert = X509::from_pem(CERT).unwrap(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); + let stream = listener.accept().unwrap().0; + let mut stream = acceptor.accept(stream).unwrap(); + + stream.write_all(b"hello").unwrap(); + }); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + let connector = connector.build(); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut stream = connector.connect("foobar.com", stream).unwrap(); + + let mut buf = [0; 5]; + stream.read_exact(&mut buf).unwrap(); + assert_eq!(b"hello", &buf); + + t.join().unwrap(); +} + +#[test] +fn connector_client_server_mozilla_modern() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let t = thread::spawn(move || { + let key = PKey::private_key_from_pem(KEY).unwrap(); + let cert = X509::from_pem(CERT).unwrap(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); + let stream = listener.accept().unwrap().0; + let mut stream = acceptor.accept(stream).unwrap(); + + stream.write_all(b"hello").unwrap(); + }); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + let connector = connector.build(); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut stream = connector.connect("foobar.com", stream).unwrap(); + + let mut buf = [0; 5]; + stream.read_exact(&mut buf).unwrap(); + assert_eq!(b"hello", &buf); + + t.join().unwrap(); +} + +#[test] +fn shutdown() { + let mut server = Server::builder(); + server.io_cb(|mut s| { + assert_eq!(s.read(&mut [0]).unwrap(), 0); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + }); + let server = server.build(); + + let mut s = server.client().connect(); + + assert_eq!(s.get_shutdown(), ShutdownState::empty()); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Sent); + assert_eq!(s.get_shutdown(), ShutdownState::SENT); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + assert_eq!( + s.get_shutdown(), + ShutdownState::SENT | ShutdownState::RECEIVED + ); +} + +#[test] +fn client_ca_list() { + let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); + assert_eq!(names.len(), 1); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_client_ca_list(names); +} + +#[test] +fn cert_store() { + let server = Server::builder().build(); + + let mut client = server.client(); + let cert = X509::from_pem(ROOT_CERT).unwrap(); + client.ctx().cert_store_mut().add_cert(cert).unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect(); +} + +#[test] +fn tmp_dh_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +fn tmp_ecdh_callback() { + use ec::EcKey; + use nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn tmp_dh_callback_ssl() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +fn tmp_ecdh_callback_ssl() { + use ec::EcKey; + use nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn idle_session() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.session().is_none()); +} + +#[test] +fn active_session() { + let server = Server::builder().build(); + + let s = server.client().connect(); + + let session = s.ssl().session().unwrap(); + let len = session.master_key_len(); + let mut buf = vec![0; len - 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, buf.len()); + let mut buf = vec![0; len + 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, len); +} + +#[test] +fn status_callbacks() { + static CALLED_BACK_SERVER: AtomicBool = AtomicBool::new(false); + static CALLED_BACK_CLIENT: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_SERVER.store(true, Ordering::SeqCst); + let response = OcspResponse::create(OcspResponseStatus::UNAUTHORIZED, None).unwrap(); + let response = response.to_der().unwrap(); + ssl.set_ocsp_status(&response).unwrap(); + Ok(true) + }) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); + let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); + assert_eq!(response.status(), OcspResponseStatus::UNAUTHORIZED); + Ok(true) + }) + .unwrap(); + + let mut client = client.build().builder(); + client.ssl().set_status_type(StatusType::OCSP).unwrap(); + + client.connect(); + + assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); + assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); +} + +#[test] +fn new_session_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn new_session_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + let mut client = client.build().builder(); + + let ctx = SslContextBuilder::new(SslMethod::tls()).unwrap().build(); + client.ssl().set_ssl_context(&ctx).unwrap(); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn keying_export() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let label = "EXPERIMENTAL test"; + let context = b"my context"; + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf, buf2); +} + +#[test] +#[cfg(any(ossl110, libressl261))] +fn no_version_overlap() { + let mut server = Server::builder(); + server.ctx().set_min_proto_version(None).unwrap(); + server + .ctx() + .set_max_proto_version(Some(SslVersion::TLS1_1)) + .unwrap(); + #[cfg(any(ossl110g, libressl270))] + assert_eq!(server.ctx().max_proto_version(), Some(SslVersion::TLS1_1)); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_min_proto_version(Some(SslVersion::TLS1_2)) + .unwrap(); + #[cfg(ossl110g)] + assert_eq!(client.ctx().min_proto_version(), Some(SslVersion::TLS1_2)); + client.ctx().set_max_proto_version(None).unwrap(); + + client.connect_err(); +} + +#[test] +#[cfg(ossl111)] +fn custom_extensions() { + static FOUND_EXTENSION: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .add_custom_ext( + 12345, + ExtensionContext::CLIENT_HELLO, + |_, _, _| -> Result, _> { unreachable!() }, + |_, _, data, _| { + FOUND_EXTENSION.store(data == b"hello", Ordering::SeqCst); + Ok(()) + }, + ) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .add_custom_ext( + 12345, + ssl::ExtensionContext::CLIENT_HELLO, + |_, _, _| Ok(Some(b"hello")), + |_, _, _, _| unreachable!(), + ) + .unwrap(); + + client.connect(); + + assert!(FOUND_EXTENSION.load(Ordering::SeqCst)); +} + +fn _check_kinds() { + fn is_send() {} + fn is_sync() {} + + is_send::>(); + is_sync::>(); +} + +#[test] +#[cfg(ossl111)] +fn stateless() { + use super::SslOptions; + + #[derive(Debug)] + struct MemoryStream { + incoming: io::Cursor>, + outgoing: Vec, + } + + impl MemoryStream { + pub fn new() -> Self { + Self { + incoming: io::Cursor::new(Vec::new()), + outgoing: Vec::new(), + } + } + + pub fn extend_incoming(&mut self, data: &[u8]) { + self.incoming.get_mut().extend_from_slice(data); + } + + pub fn take_outgoing(&mut self) -> Outgoing { + Outgoing(&mut self.outgoing) + } + } + + impl Read for MemoryStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = self.incoming.read(buf)?; + if self.incoming.position() == self.incoming.get_ref().len() as u64 { + self.incoming.set_position(0); + self.incoming.get_mut().clear(); + } + if n == 0 { + return Err(io::Error::new( + io::ErrorKind::WouldBlock, + "no data available", + )); + } + Ok(n) + } + } + + impl Write for MemoryStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.outgoing.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + pub struct Outgoing<'a>(&'a mut Vec); + + impl<'a> Drop for Outgoing<'a> { + fn drop(&mut self) { + self.0.clear(); + } + } + + impl<'a> ::std::ops::Deref for Outgoing<'a> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.0 + } + } + + impl<'a> AsRef<[u8]> for Outgoing<'a> { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + fn send(from: &mut MemoryStream, to: &mut MemoryStream) { + to.extend_incoming(&from.take_outgoing()); + } + + fn hs( + stream: Result, HandshakeError>, + ) -> Result, MidHandshakeSslStream> { + match stream { + Ok(stream) => Ok(stream), + Err(HandshakeError::WouldBlock(stream)) => Err(stream), + Err(e) => panic!("unexpected error: {:?}", e), + } + } + + // + // Setup + // + + let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT); + let client_stream = Ssl::new(&client_ctx.build()).unwrap(); + + let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + server_ctx + .set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + server_ctx + .set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + const COOKIE: &[u8] = b"chocolate chip"; + server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| { + buf[0..COOKIE.len()].copy_from_slice(COOKIE); + Ok(COOKIE.len()) + }); + server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE); + let mut server_stream = + ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()); + + // + // Handshake + // + + // Initial ClientHello + let mut client_stream = hs(client_stream.connect(MemoryStream::new())).unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // HelloRetryRequest + assert!(!server_stream.stateless().unwrap()); + send(server_stream.get_mut(), client_stream.get_mut()); + // Second ClientHello + let mut client_stream = hs(client_stream.handshake()).unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // OldServerHello + assert!(server_stream.stateless().unwrap()); + let mut server_stream = hs(server_stream.accept()).unwrap_err(); + send(server_stream.get_mut(), client_stream.get_mut()); + // Finished + let mut client_stream = hs(client_stream.handshake()).unwrap(); + send(client_stream.get_mut(), server_stream.get_mut()); + hs(server_stream.handshake()).unwrap(); +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +#[test] +fn psk_ciphers() { + const CIPHER: &'static str = "PSK-AES128-CBC-SHA"; + const PSK: &[u8] = b"thisisaverysecurekey"; + const CLIENT_IDENT: &[u8] = b"thisisaclient"; + static CLIENT_CALLED: AtomicBool = AtomicBool::new(false); + static SERVER_CALLED: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_cipher_list(CIPHER).unwrap(); + server.ctx().set_psk_server_callback(|_, identity, psk| { + assert!(identity.unwrap_or(&[]) == CLIENT_IDENT); + psk[..PSK.len()].copy_from_slice(PSK); + SERVER_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + let server = server.build(); + + let mut client = server.client(); + // This test relies on TLS 1.2 suites + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list(CIPHER).unwrap(); + client + .ctx() + .set_psk_client_callback(move |_, _, identity, psk| { + identity[..CLIENT_IDENT.len()].copy_from_slice(&CLIENT_IDENT); + identity[CLIENT_IDENT.len()] = 0; + psk[..PSK.len()].copy_from_slice(PSK); + CLIENT_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + client.connect(); + + assert!(CLIENT_CALLED.load(Ordering::SeqCst) && SERVER_CALLED.load(Ordering::SeqCst)); +} + +#[test] +fn sni_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_servername_callback(|_, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + + let keyed_ctx = mem::replace(server.ctx(), ctx).build(); + server.ssl_cb(move |ssl| ssl.set_ssl_context(&keyed_ctx).unwrap()); + + let server = server.build(); + + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn client_hello() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_client_hello_callback(|ssl, _| { + assert!(!ssl.client_hello_isv2()); + assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); + assert!(ssl.client_hello_random().is_some()); + assert!(ssl.client_hello_session_id().is_some()); + assert!(ssl.client_hello_ciphers().is_some()); + assert!(ssl.client_hello_compression_methods().is_some()); + + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(ClientHelloResponse::SUCCESS) + }); + + let server = server.build(); + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn openssl_cipher_name() { + assert_eq!( + super::cipher_name("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), + "ECDHE-RSA-AES256-SHA384", + ); + + assert_eq!(super::cipher_name("asdf"), "(NONE)"); +} + +#[test] +fn session_cache_size() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_session_cache_size(1234); + let ctx = ctx.build(); + assert_eq!(ctx.session_cache_size(), 1234); +} diff --git a/openssl/src/ssl/test/server.rs b/openssl/src/ssl/test/server.rs new file mode 100644 index 000000000..acd9b6850 --- /dev/null +++ b/openssl/src/ssl/test/server.rs @@ -0,0 +1,167 @@ +use std::io::{Read, Write}; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::thread::{self, JoinHandle}; + +use ssl::{Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslRef, SslStream}; + +pub struct Server { + handle: Option>, + addr: SocketAddr, +} + +impl Drop for Server { + fn drop(&mut self) { + if !thread::panicking() { + self.handle.take().unwrap().join().unwrap(); + } + } +} + +impl Server { + pub fn builder() -> Builder { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_chain_file("test/cert.pem").unwrap(); + ctx.set_private_key_file("test/key.pem", SslFiletype::PEM) + .unwrap(); + + Builder { + ctx, + ssl_cb: Box::new(|_| {}), + io_cb: Box::new(|_| {}), + should_error: false, + } + } + + pub fn client(&self) -> ClientBuilder { + ClientBuilder { + ctx: SslContext::builder(SslMethod::tls()).unwrap(), + addr: self.addr, + } + } + + pub fn connect_tcp(&self) -> TcpStream { + TcpStream::connect(self.addr).unwrap() + } +} + +pub struct Builder { + ctx: SslContextBuilder, + ssl_cb: Box, + io_cb: Box) + Send>, + should_error: bool, +} + +impl Builder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn ssl_cb(&mut self, cb: F) + where + F: 'static + FnMut(&mut SslRef) + Send, + { + self.ssl_cb = Box::new(cb); + } + + pub fn io_cb(&mut self, cb: F) + where + F: 'static + FnMut(SslStream) + Send, + { + self.io_cb = Box::new(cb); + } + + pub fn should_error(&mut self) { + self.should_error = true; + } + + pub fn build(self) -> Server { + let ctx = self.ctx.build(); + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + let mut ssl_cb = self.ssl_cb; + let mut io_cb = self.io_cb; + let should_error = self.should_error; + + let handle = thread::spawn(move || { + let socket = socket.accept().unwrap().0; + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl_cb(&mut ssl); + let r = ssl.accept(socket); + if should_error { + r.unwrap_err(); + } else { + let mut socket = r.unwrap(); + socket.write_all(&[0]).unwrap(); + io_cb(socket); + } + }); + + Server { + handle: Some(handle), + addr, + } + } +} + +pub struct ClientBuilder { + ctx: SslContextBuilder, + addr: SocketAddr, +} + +impl ClientBuilder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn build(self) -> Client { + Client { + ctx: self.ctx.build(), + addr: self.addr, + } + } + + pub fn connect(self) -> SslStream { + self.build().builder().connect() + } + + pub fn connect_err(self) { + self.build().builder().connect_err(); + } +} + +pub struct Client { + ctx: SslContext, + addr: SocketAddr, +} + +impl Client { + pub fn builder(&self) -> ClientSslBuilder { + ClientSslBuilder { + ssl: Ssl::new(&self.ctx).unwrap(), + addr: self.addr, + } + } +} + +pub struct ClientSslBuilder { + ssl: Ssl, + addr: SocketAddr, +} + +impl ClientSslBuilder { + pub fn ssl(&mut self) -> &mut SslRef { + &mut self.ssl + } + + pub fn connect(self) -> SslStream { + let socket = TcpStream::connect(self.addr).unwrap(); + let mut s = self.ssl.connect(socket).unwrap(); + s.read_exact(&mut [0]).unwrap(); + s + } + + pub fn connect_err(self) { + let socket = TcpStream::connect(self.addr).unwrap(); + self.ssl.connect(socket).unwrap_err(); + } +} diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs new file mode 100644 index 000000000..a13490925 --- /dev/null +++ b/openssl/src/stack.rs @@ -0,0 +1,369 @@ +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +use libc::c_int; +use std::borrow::Borrow; +use std::convert::AsRef; +use std::iter; +use std::marker::PhantomData; +use std::mem; +use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; + +use error::ErrorStack; +use {cvt, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, + OPENSSL_sk_new_null, OPENSSL_sk_push, + }; + } else { + use ffi::{ + sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, + sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push, + }; + } +} + +/// Trait implemented by types which can be placed in a stack. +/// +/// It should not be implemented for any type outside of this crate. +pub trait Stackable: ForeignType { + /// The C stack type for this element. + /// + /// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the + /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API. + type StackType; +} + +/// An owned stack of `T`. +pub struct Stack(*mut T::StackType); + +unsafe impl Send for Stack {} +unsafe impl Sync for Stack {} + +impl Drop for Stack { + fn drop(&mut self) { + unsafe { + while let Some(_) = self.pop() {} + OPENSSL_sk_free(self.0 as *mut _); + } + } +} + +impl Stack { + pub fn new() -> Result, ErrorStack> { + unsafe { + ffi::init(); + let ptr = cvt_p(OPENSSL_sk_new_null())?; + Ok(Stack(ptr as *mut _)) + } + } +} + +impl iter::IntoIterator for Stack { + type IntoIter = IntoIter; + type Item = T; + + fn into_iter(self) -> IntoIter { + let it = IntoIter { + stack: self.0, + idxs: 0..self.len() as c_int, + }; + mem::forget(self); + it + } +} + +impl AsRef> for Stack { + fn as_ref(&self) -> &StackRef { + &*self + } +} + +impl Borrow> for Stack { + fn borrow(&self) -> &StackRef { + &*self + } +} + +impl ForeignType for Stack { + type CType = T::StackType; + type Ref = StackRef; + + #[inline] + unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack { + assert!( + !ptr.is_null(), + "Must not instantiate a Stack from a null-ptr - use Stack::new() in \ + that case" + ); + Stack(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut T::StackType { + self.0 + } +} + +impl Deref for Stack { + type Target = StackRef; + + fn deref(&self) -> &StackRef { + unsafe { StackRef::from_ptr(self.0) } + } +} + +impl DerefMut for Stack { + fn deref_mut(&mut self) -> &mut StackRef { + unsafe { StackRef::from_ptr_mut(self.0) } + } +} + +pub struct IntoIter { + stack: *mut T::StackType, + idxs: Range, +} + +impl Drop for IntoIter { + fn drop(&mut self) { + unsafe { + while let Some(_) = self.next() {} + OPENSSL_sk_free(self.stack as *mut _); + } + } +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + unsafe { + self.idxs + .next() + .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) + } + } + + fn size_hint(&self) -> (usize, Option) { + self.idxs.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + unsafe { + self.idxs + .next_back() + .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) + } + } +} + +impl ExactSizeIterator for IntoIter {} + +pub struct StackRef(Opaque, PhantomData); + +unsafe impl Send for StackRef {} +unsafe impl Sync for StackRef {} + +impl ForeignTypeRef for StackRef { + type CType = T::StackType; +} + +impl StackRef { + fn as_stack(&self) -> *mut OPENSSL_STACK { + self.as_ptr() as *mut _ + } + + /// Returns the number of items in the stack + pub fn len(&self) -> usize { + unsafe { OPENSSL_sk_num(self.as_stack()) as usize } + } + + pub fn iter(&self) -> Iter { + Iter { + stack: self, + idxs: 0..self.len() as c_int, + } + } + + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + idxs: 0..self.len() as c_int, + stack: self, + } + } + + /// Returns a reference to the element at the given index in the + /// stack or `None` if the index is out of bounds + pub fn get(&self, idx: usize) -> Option<&T::Ref> { + unsafe { + if idx >= self.len() { + return None; + } + + Some(T::Ref::from_ptr(self._get(idx))) + } + } + + /// Returns a mutable reference to the element at the given index in the + /// stack or `None` if the index is out of bounds + pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> { + unsafe { + if idx >= self.len() { + return None; + } + + Some(T::Ref::from_ptr_mut(self._get(idx))) + } + } + + /// Pushes a value onto the top of the stack. + pub fn push(&mut self, data: T) -> Result<(), ErrorStack> { + unsafe { + cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _))?; + mem::forget(data); + Ok(()) + } + } + + /// Removes the last element from the stack and returns it. + pub fn pop(&mut self) -> Option { + unsafe { + let ptr = OPENSSL_sk_pop(self.as_stack()); + if ptr.is_null() { + None + } else { + Some(T::from_ptr(ptr as *mut _)) + } + } + } + + unsafe fn _get(&self, idx: usize) -> *mut T::CType { + OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ + } +} + +impl Index for StackRef { + type Output = T::Ref; + + fn index(&self, index: usize) -> &T::Ref { + self.get(index).unwrap() + } +} + +impl IndexMut for StackRef { + fn index_mut(&mut self, index: usize) -> &mut T::Ref { + self.get_mut(index).unwrap() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef { + type Item = &'a T::Ref; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef { + type Item = &'a mut T::Ref; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a Stack { + type Item = &'a T::Ref; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { + type Item = &'a mut T::Ref; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +/// An iterator over the stack's contents. +pub struct Iter<'a, T: Stackable> +where + T: 'a, +{ + stack: &'a StackRef, + idxs: Range, +} + +impl<'a, T: Stackable> Iterator for Iter<'a, T> { + type Item = &'a T::Ref; + + fn next(&mut self) -> Option<&'a T::Ref> { + unsafe { + self.idxs + .next() + .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } + } + + fn size_hint(&self) -> (usize, Option) { + self.idxs.size_hint() + } +} + +impl<'a, T: Stackable> DoubleEndedIterator for Iter<'a, T> { + fn next_back(&mut self) -> Option<&'a T::Ref> { + unsafe { + self.idxs + .next_back() + .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } + } +} + +impl<'a, T: Stackable> ExactSizeIterator for Iter<'a, T> {} + +/// A mutable iterator over the stack's contents. +pub struct IterMut<'a, T: Stackable + 'a> { + stack: &'a mut StackRef, + idxs: Range, +} + +impl<'a, T: Stackable> Iterator for IterMut<'a, T> { + type Item = &'a mut T::Ref; + + fn next(&mut self) -> Option<&'a mut T::Ref> { + unsafe { + self.idxs + .next() + .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } + } + + fn size_hint(&self) -> (usize, Option) { + self.idxs.size_hint() + } +} + +impl<'a, T: Stackable> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option<&'a mut T::Ref> { + unsafe { + self.idxs + .next_back() + .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) + } + } +} + +impl<'a, T: Stackable> ExactSizeIterator for IterMut<'a, T> {} diff --git a/openssl/src/string.rs b/openssl/src/string.rs new file mode 100644 index 000000000..9796500a9 --- /dev/null +++ b/openssl/src/string.rs @@ -0,0 +1,95 @@ +use ffi; +use foreign_types::ForeignTypeRef; +use libc::{c_char, c_void}; +use std::convert::AsRef; +use std::ffi::CStr; +use std::fmt; +use std::ops::Deref; +use std::str; + +use stack::Stackable; + +foreign_type_and_impl_send_sync! { + type CType = c_char; + fn drop = free; + + pub struct OpensslString; + pub struct OpensslStringRef; +} + +impl fmt::Display for OpensslString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl fmt::Debug for OpensslString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl Stackable for OpensslString { + type StackType = ffi::stack_st_OPENSSL_STRING; +} + +impl AsRef for OpensslString { + fn as_ref(&self) -> &str { + &**self + } +} + +impl AsRef<[u8]> for OpensslString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Deref for OpensslStringRef { + type Target = str; + + fn deref(&self) -> &str { + unsafe { + let slice = CStr::from_ptr(self.as_ptr()).to_bytes(); + str::from_utf8_unchecked(slice) + } + } +} + +impl AsRef for OpensslStringRef { + fn as_ref(&self) -> &str { + &*self + } +} + +impl AsRef<[u8]> for OpensslStringRef { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl fmt::Display for OpensslStringRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +impl fmt::Debug for OpensslStringRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[cfg(not(ossl110))] +unsafe fn free(buf: *mut c_char) { + ::ffi::CRYPTO_free(buf as *mut c_void); +} + +#[cfg(ossl110)] +unsafe fn free(buf: *mut c_char) { + ::ffi::CRYPTO_free( + buf as *mut c_void, + concat!(file!(), "\0").as_ptr() as *const c_char, + line!() as ::libc::c_int, + ); +} diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs new file mode 100644 index 000000000..726917a58 --- /dev/null +++ b/openssl/src/symm.rs @@ -0,0 +1,1310 @@ +//! High level interface to certain symmetric ciphers. +//! +//! # Examples +//! +//! Encrypt data in AES128 CBC mode +//! +//! ``` +//! use openssl::symm::{encrypt, Cipher}; +//! +//! let cipher = Cipher::aes_128_cbc(); +//! let data = b"Some Crypto Text"; +//! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +//! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +//! let ciphertext = encrypt( +//! cipher, +//! key, +//! Some(iv), +//! data).unwrap(); +//! +//! assert_eq!( +//! b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ +//! \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", +//! &ciphertext[..]); +//! ``` +//! +//! Encrypting an asymmetric key with a symmetric cipher +//! +//! ``` +//! use openssl::rsa::{Padding, Rsa}; +//! use openssl::symm::Cipher; +//! +//! // Generate keypair and encrypt private key: +//! let keypair = Rsa::generate(2048).unwrap(); +//! let cipher = Cipher::aes_256_cbc(); +//! let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); +//! let privkey_pem = keypair.private_key_to_pem_passphrase(cipher, b"Rust").unwrap(); +//! // pubkey_pem and privkey_pem could be written to file here. +//! +//! // Load private and public key from string: +//! let pubkey = Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); +//! let privkey = Rsa::private_key_from_pem_passphrase(&privkey_pem, b"Rust").unwrap(); +//! +//! // Use the asymmetric keys to encrypt and decrypt a short message: +//! let msg = b"Foo bar"; +//! let mut encrypted = vec![0; pubkey.size() as usize]; +//! let mut decrypted = vec![0; privkey.size() as usize]; +//! let len = pubkey.public_encrypt(msg, &mut encrypted, Padding::PKCS1).unwrap(); +//! assert!(len > msg.len()); +//! let len = privkey.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1).unwrap(); +//! let output_string = String::from_utf8(decrypted[..len].to_vec()).unwrap(); +//! assert_eq!("Foo bar", output_string); +//! println!("Decrypted: '{}'", output_string); +//! ``` + +use ffi; +use libc::c_int; +use std::cmp; +use std::ptr; + +use error::ErrorStack; +use nid::Nid; +use {cvt, cvt_p}; + +#[derive(Copy, Clone)] +pub enum Mode { + Encrypt, + Decrypt, +} + +/// Represents a particular cipher algorithm. +/// +/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms. +/// +/// [`EVP_EncryptInit`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptInit.html +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Cipher(*const ffi::EVP_CIPHER); + +impl Cipher { + /// Looks up the cipher for a certain nid. + /// + /// This corresponds to [`EVP_get_cipherbynid`] + /// + /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_get_cipherbyname.html + pub fn from_nid(nid: Nid) -> Option { + let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; + if ptr.is_null() { + None + } else { + Some(Cipher(ptr)) + } + } + + pub fn aes_128_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ecb()) } + } + + pub fn aes_128_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_cbc()) } + } + + pub fn aes_128_xts() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_xts()) } + } + + pub fn aes_128_ctr() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ctr()) } + } + + pub fn aes_128_cfb1() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_cfb1()) } + } + + pub fn aes_128_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_cfb128()) } + } + + pub fn aes_128_cfb8() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_cfb8()) } + } + + pub fn aes_128_gcm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_gcm()) } + } + + pub fn aes_128_ccm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_128_ccm()) } + } + + pub fn aes_256_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ecb()) } + } + + pub fn aes_256_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_cbc()) } + } + + pub fn aes_256_xts() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_xts()) } + } + + pub fn aes_256_ctr() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ctr()) } + } + + pub fn aes_256_cfb1() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_cfb1()) } + } + + pub fn aes_256_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_cfb128()) } + } + + pub fn aes_256_cfb8() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_cfb8()) } + } + + pub fn aes_256_gcm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_gcm()) } + } + + pub fn aes_256_ccm() -> Cipher { + unsafe { Cipher(ffi::EVP_aes_256_ccm()) } + } + + pub fn bf_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_cbc()) } + } + + pub fn bf_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_ecb()) } + } + + pub fn bf_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_cfb64()) } + } + + pub fn bf_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_ofb()) } + } + + pub fn des_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_des_cbc()) } + } + + pub fn des_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ecb()) } + } + + pub fn des_ede3() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3()) } + } + + pub fn des_ede3_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cbc()) } + } + + pub fn des_ede3_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } + } + + pub fn rc4() -> Cipher { + unsafe { Cipher(ffi::EVP_rc4()) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + pub fn chacha20() -> Cipher { + unsafe { Cipher(ffi::EVP_chacha20()) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + pub fn chacha20_poly1305() -> Cipher { + unsafe { Cipher(ffi::EVP_chacha20_poly1305()) } + } + + pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher { + Cipher(ptr) + } + + pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER { + self.0 + } + + /// Returns the length of keys used with this cipher. + pub fn key_len(&self) -> usize { + unsafe { EVP_CIPHER_key_length(self.0) as usize } + } + + /// Returns the length of the IV used with this cipher, or `None` if the + /// cipher does not use an IV. + pub fn iv_len(&self) -> Option { + unsafe { + let len = EVP_CIPHER_iv_length(self.0) as usize; + if len == 0 { + None + } else { + Some(len) + } + } + } + + /// Returns the block size of the cipher. + /// + /// # Note + /// + /// Stream ciphers such as RC4 have a block size of 1. + pub fn block_size(&self) -> usize { + unsafe { EVP_CIPHER_block_size(self.0) as usize } + } + + /// Determines whether the cipher is using CCM mode + fn is_ccm(&self) -> bool { + // NOTE: OpenSSL returns pointers to static structs, which makes this work as expected + *self == Cipher::aes_128_ccm() || *self == Cipher::aes_256_ccm() + } +} + +unsafe impl Sync for Cipher {} +unsafe impl Send for Cipher {} + +/// Represents a symmetric cipher context. +/// +/// Padding is enabled by default. +/// +/// # Examples +/// +/// Encrypt some plaintext in chunks, then decrypt the ciphertext back into plaintext, in AES 128 +/// CBC mode. +/// +/// ``` +/// use openssl::symm::{Cipher, Mode, Crypter}; +/// +/// let plaintexts: [&[u8]; 2] = [b"Some Stream of", b" Crypto Text"]; +/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +/// let data_len = plaintexts.iter().fold(0, |sum, x| sum + x.len()); +/// +/// // Create a cipher context for encryption. +/// let mut encrypter = Crypter::new( +/// Cipher::aes_128_cbc(), +/// Mode::Encrypt, +/// key, +/// Some(iv)).unwrap(); +/// +/// let block_size = Cipher::aes_128_cbc().block_size(); +/// let mut ciphertext = vec![0; data_len + block_size]; +/// +/// // Encrypt 2 chunks of plaintexts successively. +/// let mut count = encrypter.update(plaintexts[0], &mut ciphertext).unwrap(); +/// count += encrypter.update(plaintexts[1], &mut ciphertext[count..]).unwrap(); +/// count += encrypter.finalize(&mut ciphertext[count..]).unwrap(); +/// ciphertext.truncate(count); +/// +/// assert_eq!( +/// b"\x0F\x21\x83\x7E\xB2\x88\x04\xAF\xD9\xCC\xE2\x03\x49\xB4\x88\xF6\xC4\x61\x0E\x32\x1C\xF9\ +/// \x0D\x66\xB1\xE6\x2C\x77\x76\x18\x8D\x99", +/// &ciphertext[..] +/// ); +/// +/// +/// // Let's pretend we don't know the plaintext, and now decrypt the ciphertext. +/// let data_len = ciphertext.len(); +/// let ciphertexts = [&ciphertext[..9], &ciphertext[9..]]; +/// +/// // Create a cipher context for decryption. +/// let mut decrypter = Crypter::new( +/// Cipher::aes_128_cbc(), +/// Mode::Decrypt, +/// key, +/// Some(iv)).unwrap(); +/// let mut plaintext = vec![0; data_len + block_size]; +/// +/// // Decrypt 2 chunks of ciphertexts successively. +/// let mut count = decrypter.update(ciphertexts[0], &mut plaintext).unwrap(); +/// count += decrypter.update(ciphertexts[1], &mut plaintext[count..]).unwrap(); +/// count += decrypter.finalize(&mut plaintext[count..]).unwrap(); +/// plaintext.truncate(count); +/// +/// assert_eq!(b"Some Stream of Crypto Text", &plaintext[..]); +/// ``` +pub struct Crypter { + ctx: *mut ffi::EVP_CIPHER_CTX, + block_size: usize, +} + +unsafe impl Sync for Crypter {} +unsafe impl Send for Crypter {} + +impl Crypter { + /// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain + /// types of `Cipher`. + /// + /// # Panics + /// + /// Panics if an IV is required by the cipher but not provided. Also make sure that the key + /// and IV size are appropriate for your cipher. + pub fn new( + t: Cipher, + mode: Mode, + key: &[u8], + iv: Option<&[u8]>, + ) -> Result { + ffi::init(); + + unsafe { + let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + let crypter = Crypter { + ctx: ctx, + block_size: t.block_size(), + }; + + let mode = match mode { + Mode::Encrypt => 1, + Mode::Decrypt => 0, + }; + + cvt(ffi::EVP_CipherInit_ex( + crypter.ctx, + t.as_ptr(), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + mode, + ))?; + + assert!(key.len() <= c_int::max_value() as usize); + cvt(ffi::EVP_CIPHER_CTX_set_key_length( + crypter.ctx, + key.len() as c_int, + ))?; + + let key = key.as_ptr() as *mut _; + let iv = match (iv, t.iv_len()) { + (Some(iv), Some(len)) => { + if iv.len() != len { + assert!(iv.len() <= c_int::max_value() as usize); + cvt(ffi::EVP_CIPHER_CTX_ctrl( + crypter.ctx, + ffi::EVP_CTRL_GCM_SET_IVLEN, + iv.len() as c_int, + ptr::null_mut(), + ))?; + } + iv.as_ptr() as *mut _ + } + (Some(_), None) | (None, None) => ptr::null_mut(), + (None, Some(_)) => panic!("an IV is required for this cipher"), + }; + cvt(ffi::EVP_CipherInit_ex( + crypter.ctx, + ptr::null(), + ptr::null_mut(), + key, + iv, + mode, + ))?; + + Ok(crypter) + } + } + + /// Enables or disables padding. + /// + /// If padding is disabled, total amount of data encrypted/decrypted must + /// be a multiple of the cipher's block size. + pub fn pad(&mut self, padding: bool) { + unsafe { + ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); + } + } + + /// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM. + /// + /// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`. + pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(tag.len() <= c_int::max_value() as usize); + // NB: this constant is actually more general than just GCM. + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.ctx, + ffi::EVP_CTRL_GCM_SET_TAG, + tag.len() as c_int, + tag.as_ptr() as *mut _, + )) + .map(|_| ()) + } + } + + /// Sets the length of the authentication tag to generate in AES CCM. + /// + /// When encrypting with AES CCM, the tag length needs to be explicitly set in order + /// to use a value different than the default 12 bytes. + pub fn set_tag_len(&mut self, tag_len: usize) -> Result<(), ErrorStack> { + unsafe { + assert!(tag_len <= c_int::max_value() as usize); + // NB: this constant is actually more general than just GCM. + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.ctx, + ffi::EVP_CTRL_GCM_SET_TAG, + tag_len as c_int, + ptr::null_mut(), + )) + .map(|_| ()) + } + } + + /// Feeds total plaintext length to the cipher. + /// + /// The total plaintext or ciphertext length MUST be passed to the cipher when it operates in + /// CCM mode. + pub fn set_data_len(&mut self, data_len: usize) -> Result<(), ErrorStack> { + unsafe { + assert!(data_len <= c_int::max_value() as usize); + let mut len = 0; + cvt(ffi::EVP_CipherUpdate( + self.ctx, + ptr::null_mut(), + &mut len, + ptr::null_mut(), + data_len as c_int, + )) + .map(|_| ()) + } + } + + /// Feeds Additional Authenticated Data (AAD) through the cipher. + /// + /// This can only be used with AEAD ciphers such as AES GCM. Data fed in is not encrypted, but + /// is factored into the authentication tag. It must be called before the first call to + /// `update`. + pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(input.len() <= c_int::max_value() as usize); + let mut len = 0; + cvt(ffi::EVP_CipherUpdate( + self.ctx, + ptr::null_mut(), + &mut len, + input.as_ptr(), + input.len() as c_int, + )) + .map(|_| ()) + } + } + + /// Feeds data from `input` through the cipher, writing encrypted/decrypted + /// bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics for stream ciphers if `output.len() < input.len()`. + /// + /// Panics for block ciphers if `output.len() < input.len() + block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). + /// + /// Panics if `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + unsafe { + let block_size = if self.block_size > 1 { self.block_size } else { 0 }; + assert!(output.len() >= input.len() + block_size); + assert!(output.len() <= c_int::max_value() as usize); + let mut outl = output.len() as c_int; + let inl = input.len() as c_int; + + cvt(ffi::EVP_CipherUpdate( + self.ctx, + output.as_mut_ptr(), + &mut outl, + input.as_ptr(), + inl, + ))?; + + Ok(outl as usize) + } + } + + /// Finishes the encryption/decryption process, writing any remaining data + /// to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics for block ciphers if `output.len() < block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + unsafe { + if self.block_size > 1 { assert!(output.len() >= self.block_size); } + let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; + + cvt(ffi::EVP_CipherFinal( + self.ctx, + output.as_mut_ptr(), + &mut outl, + ))?; + + Ok(outl as usize) + } + } + + /// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such + /// as AES GCM. + /// + /// When encrypting data with an AEAD cipher, this must be called after `finalize`. + /// + /// The size of the buffer indicates the required size of the tag. While some ciphers support a + /// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 + /// bytes, for example. + pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(tag.len() <= c_int::max_value() as usize); + cvt(ffi::EVP_CIPHER_CTX_ctrl( + self.ctx, + ffi::EVP_CTRL_GCM_GET_TAG, + tag.len() as c_int, + tag.as_mut_ptr() as *mut _, + )) + .map(|_| ()) + } + } +} + +impl Drop for Crypter { + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_CTX_free(self.ctx); + } + } +} + +/// Encrypts data in one go, and returns the encrypted data. +/// +/// Data is encrypted using the specified cipher type `t` in encrypt mode with the specified `key` +/// and initailization vector `iv`. Padding is enabled. +/// +/// This is a convenient interface to `Crypter` to encrypt all data in one go. To encrypt a stream +/// of data increamentally , use `Crypter` instead. +/// +/// # Examples +/// +/// Encrypt data in AES128 CBC mode +/// +/// ``` +/// use openssl::symm::{encrypt, Cipher}; +/// +/// let cipher = Cipher::aes_128_cbc(); +/// let data = b"Some Crypto Text"; +/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +/// let ciphertext = encrypt( +/// cipher, +/// key, +/// Some(iv), +/// data).unwrap(); +/// +/// assert_eq!( +/// b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ +/// \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", +/// &ciphertext[..]); +/// ``` +pub fn encrypt( + t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + data: &[u8], +) -> Result, ErrorStack> { + cipher(t, Mode::Encrypt, key, iv, data) +} + +/// Decrypts data in one go, and returns the decrypted data. +/// +/// Data is decrypted using the specified cipher type `t` in decrypt mode with the specified `key` +/// and initailization vector `iv`. Padding is enabled. +/// +/// This is a convenient interface to `Crypter` to decrypt all data in one go. To decrypt a stream +/// of data increamentally , use `Crypter` instead. +/// +/// # Examples +/// +/// Decrypt data in AES128 CBC mode +/// +/// ``` +/// use openssl::symm::{decrypt, Cipher}; +/// +/// let cipher = Cipher::aes_128_cbc(); +/// let data = b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\ +/// \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1"; +/// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; +/// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; +/// let ciphertext = decrypt( +/// cipher, +/// key, +/// Some(iv), +/// data).unwrap(); +/// +/// assert_eq!( +/// b"Some Crypto Text", +/// &ciphertext[..]); +/// ``` +pub fn decrypt( + t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + data: &[u8], +) -> Result, ErrorStack> { + cipher(t, Mode::Decrypt, key, iv, data) +} + +fn cipher( + t: Cipher, + mode: Mode, + key: &[u8], + iv: Option<&[u8]>, + data: &[u8], +) -> Result, ErrorStack> { + let mut c = Crypter::new(t, mode, key, iv)?; + let mut out = vec![0; data.len() + t.block_size()]; + let count = c.update(data, &mut out)?; + let rest = c.finalize(&mut out[count..])?; + out.truncate(count + rest); + Ok(out) +} + +/// Like `encrypt`, but for AEAD ciphers such as AES GCM. +/// +/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag +/// will be copied into the `tag` field. +/// +/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support +/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, +/// for example. +pub fn encrypt_aead( + t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + aad: &[u8], + data: &[u8], + tag: &mut [u8], +) -> Result, ErrorStack> { + let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?; + let mut out = vec![0; data.len() + t.block_size()]; + + if t.is_ccm() { + c.set_tag_len(tag.len())?; + c.set_data_len(data.len())?; + } + + c.aad_update(aad)?; + let count = c.update(data, &mut out)?; + let rest = c.finalize(&mut out[count..])?; + c.get_tag(tag)?; + out.truncate(count + rest); + Ok(out) +} + +/// Like `decrypt`, but for AEAD ciphers such as AES GCM. +/// +/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag +/// should be provided in the `tag` field. +pub fn decrypt_aead( + t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + aad: &[u8], + data: &[u8], + tag: &[u8], +) -> Result, ErrorStack> { + let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?; + let mut out = vec![0; data.len() + t.block_size()]; + + if t.is_ccm() { + c.set_tag(tag)?; + c.set_data_len(data.len())?; + } + + c.aad_update(aad)?; + let count = c.update(data, &mut out)?; + let mut rest = 0; + + if !t.is_ccm() { + c.set_tag(tag)?; + rest = c.finalize(&mut out[count..])?; + } + + out.truncate(count + rest); + Ok(out) +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; + } else { + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).iv_len + } + + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).block_size + } + + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).key_len + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use hex::{self, FromHex}; + + #[test] + fn test_stream_cipher_output() { + let key = [0u8; 16]; + let iv = [0u8; 16]; + let mut c = super::Crypter::new( + super::Cipher::aes_128_ctr(), + super::Mode::Encrypt, + &key, + Some(&iv), + ).unwrap(); + + assert_eq!(c.update(&[0u8; 15], &mut [0u8; 15]).unwrap(), 15); + assert_eq!(c.update(&[0u8; 1], &mut [0u8; 1]).unwrap(), 1); + assert_eq!(c.finalize(&mut [0u8; 0]).unwrap(), 0); + } + + // Test vectors from FIPS-197: + // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + #[test] + fn test_aes_256_ecb() { + let k0 = [ + 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8, + 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, + 0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8, + ]; + let p0 = [ + 0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8, + 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8, + ]; + let c0 = [ + 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, + 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8, + ]; + let mut c = super::Crypter::new( + super::Cipher::aes_256_ecb(), + super::Mode::Encrypt, + &k0, + None, + ) + .unwrap(); + c.pad(false); + let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()]; + let count = c.update(&p0, &mut r0).unwrap(); + let rest = c.finalize(&mut r0[count..]).unwrap(); + r0.truncate(count + rest); + assert_eq!(hex::encode(&r0), hex::encode(c0)); + + let mut c = super::Crypter::new( + super::Cipher::aes_256_ecb(), + super::Mode::Decrypt, + &k0, + None, + ) + .unwrap(); + c.pad(false); + let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()]; + let count = c.update(&r0, &mut p1).unwrap(); + let rest = c.finalize(&mut p1[count..]).unwrap(); + p1.truncate(count + rest); + assert_eq!(hex::encode(p1), hex::encode(p0)); + } + + #[test] + fn test_aes_256_cbc_decrypt() { + let iv = [ + 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, + 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, + ]; + let data = [ + 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, + 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, + 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, + ]; + let ciphered_data = [ + 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8, + 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8, + ]; + let mut cr = super::Crypter::new( + super::Cipher::aes_256_cbc(), + super::Mode::Decrypt, + &data, + Some(&iv), + ) + .unwrap(); + cr.pad(false); + let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()]; + let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap(); + let rest = cr.finalize(&mut unciphered_data[count..]).unwrap(); + unciphered_data.truncate(count + rest); + + let expected_unciphered_data = b"I love turtles.\x01"; + + assert_eq!(&unciphered_data, expected_unciphered_data); + } + + fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { + let pt = Vec::from_hex(pt).unwrap(); + let ct = Vec::from_hex(ct).unwrap(); + let key = Vec::from_hex(key).unwrap(); + let iv = Vec::from_hex(iv).unwrap(); + + let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap(); + let expected = pt; + + if computed != expected { + println!("Computed: {}", hex::encode(&computed)); + println!("Expected: {}", hex::encode(&expected)); + if computed.len() != expected.len() { + println!( + "Lengths differ: {} in computed vs {} expected", + computed.len(), + expected.len() + ); + } + panic!("test failure"); + } + } + + fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { + let pt = Vec::from_hex(pt).unwrap(); + let ct = Vec::from_hex(ct).unwrap(); + let key = Vec::from_hex(key).unwrap(); + let iv = Vec::from_hex(iv).unwrap(); + + let computed = { + let mut c = Crypter::new(ciphertype, Mode::Decrypt, &key, Some(&iv)).unwrap(); + c.pad(false); + let mut out = vec![0; ct.len() + ciphertype.block_size()]; + let count = c.update(&ct, &mut out).unwrap(); + let rest = c.finalize(&mut out[count..]).unwrap(); + out.truncate(count + rest); + out + }; + let expected = pt; + + if computed != expected { + println!("Computed: {}", hex::encode(&computed)); + println!("Expected: {}", hex::encode(&expected)); + if computed.len() != expected.len() { + println!( + "Lengths differ: {} in computed vs {} expected", + computed.len(), + expected.len() + ); + } + panic!("test failure"); + } + } + + #[test] + fn test_rc4() { + let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000"; + let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4"; + let key = "97CD440324DA5FD1F7955C1C13B6B466"; + let iv = ""; + + cipher_test(super::Cipher::rc4(), pt, ct, key, iv); + } + + #[test] + fn test_aes256_xts() { + // Test case 174 from + // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip + let pt = "77f4ef63d734ebd028508da66c22cdebdd52ecd6ee2ab0a50bc8ad0cfd692ca5fcd4e6dedc45df7f\ + 6503f462611dc542"; + let ct = "ce7d905a7776ac72f240d22aafed5e4eb7566cdc7211220e970da634ce015f131a5ecb8d400bc9e8\ + 4f0b81d8725dbbc7"; + let key = "b6bfef891f83b5ff073f2231267be51eb084b791fa19a154399c0684c8b2dfcb37de77d28bbda3b\ + 4180026ad640b74243b3133e7b9fae629403f6733423dae28"; + let iv = "db200efb7eaaa737dbdf40babb68953f"; + + cipher_test(super::Cipher::aes_256_xts(), pt, ct, key, iv); + } + + #[test] + fn test_aes128_ctr() { + let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\ + E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710"; + let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E\ + 5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE"; + let key = "2B7E151628AED2A6ABF7158809CF4F3C"; + let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; + + cipher_test(super::Cipher::aes_128_ctr(), pt, ct, key, iv); + } + + #[test] + fn test_aes128_cfb1() { + // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + let pt = "6bc1"; + let ct = "68b3"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_128_cfb1(), pt, ct, key, iv); + } + + #[test] + fn test_aes128_cfb128() { + let pt = "6bc1bee22e409f96e93d7e117393172a"; + let ct = "3b3fd92eb72dad20333449f8e83cfb4a"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_128_cfb128(), pt, ct, key, iv); + } + + #[test] + fn test_aes128_cfb8() { + let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; + let ct = "3b79424c9c0dd436bace9e0ed4586a4f32b9"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_128_cfb8(), pt, ct, key, iv); + } + + #[test] + fn test_aes256_cfb1() { + let pt = "6bc1"; + let ct = "9029"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_256_cfb1(), pt, ct, key, iv); + } + + #[test] + fn test_aes256_cfb128() { + let pt = "6bc1bee22e409f96e93d7e117393172a"; + let ct = "dc7e84bfda79164b7ecd8486985d3860"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_256_cfb128(), pt, ct, key, iv); + } + + #[test] + fn test_aes256_cfb8() { + let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; + let ct = "dc1f1a8520a64db55fcc8ac554844e889700"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "000102030405060708090a0b0c0d0e0f"; + + cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv); + } + + #[test] + fn test_bf_cbc() { + // https://www.schneier.com/code/vectors.txt + + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000000000"; + let ct = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_cbc(), pt, ct, key, iv); + } + + #[test] + fn test_bf_ecb() { + let pt = "5CD54CA83DEF57DA"; + let ct = "B1B8CC0B250F09A0"; + let key = "0131D9619DC1376E"; + let iv = "0000000000000000"; + + cipher_test_nopad(super::Cipher::bf_ecb(), pt, ct, key, iv); + } + + #[test] + fn test_bf_cfb64() { + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; + let ct = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_cfb64(), pt, ct, key, iv); + } + + #[test] + fn test_bf_ofb() { + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; + let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_ofb(), pt, ct, key, iv); + } + + #[test] + fn test_des_cbc() { + let pt = "54686973206973206120746573742e"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv); + } + + #[test] + fn test_des_ecb() { + let pt = "54686973206973206120746573742e"; + let ct = "0050ab8aecec758843fe157b4dde938c"; + let key = "7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv); + } + + #[test] + fn test_des_ede3() { + let pt = "9994f4c69d40ae4f34ff403b5cf39d4c8207ea5d3e19a5fd"; + let ct = "9e5c4297d60582f81071ac8ab7d0698d4c79de8b94c519858207ea5d3e19a5fd"; + let key = "010203040506070801020304050607080102030405060708"; + let iv = "5cc118306dc702e4"; + + cipher_test(super::Cipher::des_ede3(), pt, ct, key, iv); + } + + #[test] + fn test_des_ede3_cbc() { + let pt = "54686973206973206120746573742e"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ede3_cbc(), pt, ct, key, iv); + } + + #[test] + fn test_des_ede3_cfb64() { + let pt = "2b1773784b5889dc788477367daa98ad"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ede3_cfb64(), pt, ct, key, iv); + } + + #[test] + fn test_aes128_gcm() { + let key = "0e00c76561d2bd9b40c3c15427e2b08f"; + let iv = "492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\ + 4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\ + d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496"; + let pt = "fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\ + a9c0195721476b85"; + let aad = "d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\ + c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\ + 8f1f56c0"; + let ct = "4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\ + f4fc97416ee52abe"; + let tag = "e20b6655"; + + // this tag is smaller than you'd normally want, but I pulled this test from the part of + // the NIST test vectors that cover 4 byte tags. + let mut actual_tag = [0; 4]; + let out = encrypt_aead( + Cipher::aes_128_gcm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_128_gcm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + fn test_aes128_ccm() { + let key = "3ee186594f110fb788a8bf8aa8be5d4a"; + let nonce = "44f705d52acf27b7f17196aa9b"; + let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; + + let pt = "d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1"; + let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; + let tag = "d6965f5aa6e31302a9cc2b36"; + + let mut actual_tag = [0; 12]; + let out = encrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + fn test_aes128_ccm_verify_fail() { + let key = "3ee186594f110fb788a8bf8aa8be5d4a"; + let nonce = "44f705d52acf27b7f17196aa9b"; + let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; + + let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; + let tag = "00005f5aa6e31302a9cc2b36"; + + let out = decrypt_aead( + Cipher::aes_128_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ); + assert!(out.is_err()); + } + + #[test] + fn test_aes256_ccm() { + let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; + let nonce = "dde2a362ce81b2b6913abc3095"; + let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; + + let pt = "7ebef26bf4ecf6f0ebb2eb860edbf900f27b75b4a6340fdb"; + let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; + let tag = "2927a053c9244d3217a7ad05"; + + let mut actual_tag = [0; 12]; + let out = encrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } + + #[test] + fn test_aes256_ccm_verify_fail() { + let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; + let nonce = "dde2a362ce81b2b6913abc3095"; + let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; + + let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; + let tag = "0000a053c9244d3217a7ad05"; + + let out = decrypt_aead( + Cipher::aes_256_ccm(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(nonce).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ); + assert!(out.is_err()); + } + + #[test] + #[cfg(any(ossl110))] + fn test_chacha20() { + let key = "0000000000000000000000000000000000000000000000000000000000000000"; + let iv = "00000000000000000000000000000000"; + let pt = + "000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + 00000000000000000000000000000000000000000000000"; + let ct = + "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\ + 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"; + + cipher_test(Cipher::chacha20(), pt, ct, key, iv); + } + + #[test] + #[cfg(any(ossl110))] + fn test_chacha20_poly1305() { + let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; + let iv = "070000004041424344454647"; + let aad = "50515253c0c1c2c3c4c5c6c7"; + let pt = + "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\ + a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\ + 6865206675747572652c2073756e73637265656e20776f756c642062652069742e"; + let ct = + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\ + 2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\ + b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116"; + let tag = "1ae10b594f09e26a7e902ecbd0600691"; + + let mut actual_tag = [0; 16]; + let out = encrypt_aead( + Cipher::chacha20_poly1305(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag, + ) + .unwrap(); + assert_eq!(ct, hex::encode(out)); + assert_eq!(tag, hex::encode(actual_tag)); + + let out = decrypt_aead( + Cipher::chacha20_poly1305(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap(), + ) + .unwrap(); + assert_eq!(pt, hex::encode(out)); + } +} diff --git a/openssl/src/util.rs b/openssl/src/util.rs new file mode 100644 index 000000000..8c8d41a9d --- /dev/null +++ b/openssl/src/util.rs @@ -0,0 +1,67 @@ +use libc::{c_char, c_int, c_void}; +use std::any::Any; +use std::panic::{self, AssertUnwindSafe}; +use std::slice; + +use error::ErrorStack; + +/// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI +/// frames are on the stack). +/// +/// When dropped, checks if the callback has panicked, and resumes unwinding if so. +pub struct CallbackState { + /// The user callback. Taken out of the `Option` when called. + cb: Option, + /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL + /// returns. + panic: Option>, +} + +impl CallbackState { + pub fn new(callback: F) -> Self { + CallbackState { + cb: Some(callback), + panic: None, + } + } +} + +impl Drop for CallbackState { + fn drop(&mut self) { + if let Some(panic) = self.panic.take() { + panic::resume_unwind(panic); + } + } +} + +/// Password callback function, passed to private key loading functions. +/// +/// `cb_state` is expected to be a pointer to a `CallbackState`. +pub unsafe extern "C" fn invoke_passwd_cb( + buf: *mut c_char, + size: c_int, + _rwflag: c_int, + cb_state: *mut c_void, +) -> c_int +where + F: FnOnce(&mut [u8]) -> Result, +{ + let callback = &mut *(cb_state as *mut CallbackState); + + let result = panic::catch_unwind(AssertUnwindSafe(|| { + let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); + callback.cb.take().unwrap()(pass_slice) + })); + + match result { + Ok(Ok(len)) => len as c_int, + Ok(Err(_)) => { + // FIXME restore error stack + 0 + } + Err(err) => { + callback.panic = Some(err); + 0 + } + } +} diff --git a/openssl/src/version.rs b/openssl/src/version.rs new file mode 100644 index 000000000..0d2d5bb6a --- /dev/null +++ b/openssl/src/version.rs @@ -0,0 +1,131 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +use std::ffi::CStr; + +cfg_if! { + if #[cfg(any(ossl110, libressl271))] { + use ffi::{ + OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, + OpenSSL_version_num, OpenSSL_version, + }; + } else { + use ffi::{ + SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, + SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, + SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, + SSLeay_version as OpenSSL_version, + }; + } +} + +/// OPENSSL_VERSION_NUMBER is a numeric release version identifier: +/// +/// `MNNFFPPS: major minor fix patch status` +/// +/// The status nibble has one of the values 0 for development, 1 to e for betas 1 to 14, and f for release. +/// +/// for example +/// +/// `0x000906000 == 0.9.6 dev` +/// `0x000906023 == 0.9.6b beta 3` +/// `0x00090605f == 0.9.6e release` +/// +/// Versions prior to 0.9.3 have identifiers < 0x0930. Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation: +/// +/// `MMNNFFRBB major minor fix final beta/patch` +/// +/// for example +/// +/// `0x000904100 == 0.9.4 release` +/// `0x000905000 == 0.9.5 dev` +/// +/// Version 0.9.5a had an interim interpretation that is like the current one, except the patch level got the highest bit set, to keep continuity. The number was therefore 0x0090581f +/// +/// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems. +pub fn number() -> i64 { + unsafe { OpenSSL_version_num() as i64 } +} + +/// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000". +pub fn version() -> &'static str { + unsafe { + CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)) + .to_str() + .unwrap() + } +} + +/// The compiler flags set for the compilation process in the form "compiler: ..." if available or +/// "compiler: information not available" otherwise. +pub fn c_flags() -> &'static str { + unsafe { + CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)) + .to_str() + .unwrap() + } +} + +/// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise. +pub fn built_on() -> &'static str { + unsafe { + CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)) + .to_str() + .unwrap() + } +} + +/// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise. +pub fn platform() -> &'static str { + unsafe { + CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)) + .to_str() + .unwrap() + } +} + +/// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise. +pub fn dir() -> &'static str { + unsafe { + CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)) + .to_str() + .unwrap() + } +} + +/// This test ensures that we do not segfault when calling the functions of this module +/// and that the strings respect a reasonable format. +#[test] +fn test_versions() { + println!("Number: '{}'", number()); + println!("Version: '{}'", version()); + println!("C flags: '{}'", c_flags()); + println!("Built on: '{}'", built_on()); + println!("Platform: '{}'", platform()); + println!("Dir: '{}'", dir()); + + #[cfg(not(libressl))] + fn expected_name() -> &'static str { + "OpenSSL" + } + #[cfg(libressl)] + fn expected_name() -> &'static str { + "LibreSSL" + } + + assert!(number() > 0); + assert!(version().starts_with(expected_name())); + assert!(c_flags().starts_with("compiler:")); + assert!(built_on().starts_with("built on:")); + assert!(dir().starts_with("OPENSSLDIR:")); +} diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs new file mode 100644 index 000000000..222bce505 --- /dev/null +++ b/openssl/src/x509/extension.rs @@ -0,0 +1,520 @@ +//! Add extensions to an `X509` certificate or certificate request. +//! +//! The extensions defined for X.509 v3 certificates provide methods for +//! associating additional attributes with users or public keys and for +//! managing relationships between CAs. The extensions created using this +//! module can be used with `X509v3Context` objects. +//! +//! # Example +//! +//! ```rust +//! extern crate openssl; +//! +//! use openssl::x509::extension::BasicConstraints; +//! use openssl::x509::X509Extension; +//! +//! fn main() { +//! let mut bc = BasicConstraints::new(); +//! let bc = bc.critical().ca().pathlen(1); +//! +//! let extension: X509Extension = bc.build().unwrap(); +//! } +//! ``` +use std::fmt::Write; + +use error::ErrorStack; +use nid::Nid; +use x509::{X509Extension, X509v3Context}; + +/// An extension which indicates whether a certificate is a CA certificate. +pub struct BasicConstraints { + critical: bool, + ca: bool, + pathlen: Option, +} + +impl BasicConstraints { + /// Construct a new `BasicConstraints` extension. + pub fn new() -> BasicConstraints { + BasicConstraints { + critical: false, + ca: false, + pathlen: None, + } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut BasicConstraints { + self.critical = true; + self + } + + /// Sets the `ca` flag to `true`. + pub fn ca(&mut self) -> &mut BasicConstraints { + self.ca = true; + self + } + + /// Sets the pathlen to an optional non-negative value. The pathlen is the + /// maximum number of CAs that can appear below this one in a chain. + pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints { + self.pathlen = Some(pathlen); + self + } + + /// Return the `BasicConstraints` extension as an `X509Extension`. + pub fn build(&self) -> Result { + let mut value = String::new(); + if self.critical { + value.push_str("critical,"); + } + value.push_str("CA:"); + if self.ca { + value.push_str("TRUE"); + } else { + value.push_str("FALSE"); + } + if let Some(pathlen) = self.pathlen { + write!(value, ",pathlen:{}", pathlen).unwrap(); + } + X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value) + } +} + +/// An extension consisting of a list of names of the permitted key usages. +pub struct KeyUsage { + critical: bool, + digital_signature: bool, + non_repudiation: bool, + key_encipherment: bool, + data_encipherment: bool, + key_agreement: bool, + key_cert_sign: bool, + crl_sign: bool, + encipher_only: bool, + decipher_only: bool, +} + +impl KeyUsage { + /// Construct a new `KeyUsage` extension. + pub fn new() -> KeyUsage { + KeyUsage { + critical: false, + digital_signature: false, + non_repudiation: false, + key_encipherment: false, + data_encipherment: false, + key_agreement: false, + key_cert_sign: false, + crl_sign: false, + encipher_only: false, + decipher_only: false, + } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut KeyUsage { + self.critical = true; + self + } + + /// Sets the `digitalSignature` flag to `true`. + pub fn digital_signature(&mut self) -> &mut KeyUsage { + self.digital_signature = true; + self + } + + /// Sets the `nonRepudiation` flag to `true`. + pub fn non_repudiation(&mut self) -> &mut KeyUsage { + self.non_repudiation = true; + self + } + + /// Sets the `keyEncipherment` flag to `true`. + pub fn key_encipherment(&mut self) -> &mut KeyUsage { + self.key_encipherment = true; + self + } + + /// Sets the `dataEncipherment` flag to `true`. + pub fn data_encipherment(&mut self) -> &mut KeyUsage { + self.data_encipherment = true; + self + } + + /// Sets the `keyAgreement` flag to `true`. + pub fn key_agreement(&mut self) -> &mut KeyUsage { + self.key_agreement = true; + self + } + + /// Sets the `keyCertSign` flag to `true`. + pub fn key_cert_sign(&mut self) -> &mut KeyUsage { + self.key_cert_sign = true; + self + } + + /// Sets the `cRLSign` flag to `true`. + pub fn crl_sign(&mut self) -> &mut KeyUsage { + self.crl_sign = true; + self + } + + /// Sets the `encipherOnly` flag to `true`. + pub fn encipher_only(&mut self) -> &mut KeyUsage { + self.encipher_only = true; + self + } + + /// Sets the `decipherOnly` flag to `true`. + pub fn decipher_only(&mut self) -> &mut KeyUsage { + self.decipher_only = true; + self + } + + /// Return the `KeyUsage` extension as an `X509Extension`. + pub fn build(&self) -> Result { + let mut value = String::new(); + let mut first = true; + append(&mut value, &mut first, self.critical, "critical"); + append( + &mut value, + &mut first, + self.digital_signature, + "digitalSignature", + ); + append( + &mut value, + &mut first, + self.non_repudiation, + "nonRepudiation", + ); + append( + &mut value, + &mut first, + self.key_encipherment, + "keyEncipherment", + ); + append( + &mut value, + &mut first, + self.data_encipherment, + "dataEncipherment", + ); + append(&mut value, &mut first, self.key_agreement, "keyAgreement"); + append(&mut value, &mut first, self.key_cert_sign, "keyCertSign"); + append(&mut value, &mut first, self.crl_sign, "cRLSign"); + append(&mut value, &mut first, self.encipher_only, "encipherOnly"); + append(&mut value, &mut first, self.decipher_only, "decipherOnly"); + X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value) + } +} + +/// An extension consisting of a list of usages indicating purposes +/// for which the certificate public key can be used for. +pub struct ExtendedKeyUsage { + critical: bool, + server_auth: bool, + client_auth: bool, + code_signing: bool, + email_protection: bool, + time_stamping: bool, + ms_code_ind: bool, + ms_code_com: bool, + ms_ctl_sign: bool, + ms_sgc: bool, + ms_efs: bool, + ns_sgc: bool, + other: Vec, +} + +impl ExtendedKeyUsage { + /// Construct a new `ExtendedKeyUsage` extension. + pub fn new() -> ExtendedKeyUsage { + ExtendedKeyUsage { + critical: false, + server_auth: false, + client_auth: false, + code_signing: false, + email_protection: false, + time_stamping: false, + ms_code_ind: false, + ms_code_com: false, + ms_ctl_sign: false, + ms_sgc: false, + ms_efs: false, + ns_sgc: false, + other: vec![], + } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut ExtendedKeyUsage { + self.critical = true; + self + } + + /// Sets the `serverAuth` flag to `true`. + pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage { + self.server_auth = true; + self + } + + /// Sets the `clientAuth` flag to `true`. + pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage { + self.client_auth = true; + self + } + + /// Sets the `codeSigning` flag to `true`. + pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage { + self.code_signing = true; + self + } + + /// Sets the `timeStamping` flag to `true`. + pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage { + self.time_stamping = true; + self + } + + /// Sets the `msCodeInd` flag to `true`. + pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { + self.ms_code_ind = true; + self + } + + /// Sets the `msCodeCom` flag to `true`. + pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage { + self.ms_code_com = true; + self + } + + /// Sets the `msCTLSign` flag to `true`. + pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage { + self.ms_ctl_sign = true; + self + } + + /// Sets the `msSGC` flag to `true`. + pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage { + self.ms_sgc = true; + self + } + + /// Sets the `msEFS` flag to `true`. + pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage { + self.ms_efs = true; + self + } + + /// Sets the `nsSGC` flag to `true`. + pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage { + self.ns_sgc = true; + self + } + + /// Sets a flag not already defined. + pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { + self.other.push(other.to_owned()); + self + } + + /// Return the `ExtendedKeyUsage` extension as an `X509Extension`. + pub fn build(&self) -> Result { + let mut value = String::new(); + let mut first = true; + append(&mut value, &mut first, self.critical, "critical"); + append(&mut value, &mut first, self.server_auth, "serverAuth"); + append(&mut value, &mut first, self.client_auth, "clientAuth"); + append(&mut value, &mut first, self.code_signing, "codeSigning"); + append( + &mut value, + &mut first, + self.email_protection, + "emailProtection", + ); + append(&mut value, &mut first, self.time_stamping, "timeStamping"); + append(&mut value, &mut first, self.ms_code_ind, "msCodeInd"); + append(&mut value, &mut first, self.ms_code_com, "msCodeCom"); + append(&mut value, &mut first, self.ms_ctl_sign, "msCTLSign"); + append(&mut value, &mut first, self.ms_sgc, "msSGC"); + append(&mut value, &mut first, self.ms_efs, "msEFS"); + append(&mut value, &mut first, self.ns_sgc, "nsSGC"); + for other in &self.other { + append(&mut value, &mut first, true, other); + } + X509Extension::new_nid(None, None, Nid::EXT_KEY_USAGE, &value) + } +} + +/// An extension that provides a means of identifying certificates that contain a +/// particular public key. +pub struct SubjectKeyIdentifier { + critical: bool, +} + +impl SubjectKeyIdentifier { + /// Construct a new `SubjectKeyIdentifier` extension. + pub fn new() -> SubjectKeyIdentifier { + SubjectKeyIdentifier { critical: false } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut SubjectKeyIdentifier { + self.critical = true; + self + } + + /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context) -> Result { + let mut value = String::new(); + let mut first = true; + append(&mut value, &mut first, self.critical, "critical"); + append(&mut value, &mut first, true, "hash"); + X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value) + } +} + +/// An extension that provides a means of identifying the public key corresponding +/// to the private key used to sign a CRL. +pub struct AuthorityKeyIdentifier { + critical: bool, + keyid: Option, + issuer: Option, +} + +impl AuthorityKeyIdentifier { + /// Construct a new `AuthorityKeyIdentifier` extension. + pub fn new() -> AuthorityKeyIdentifier { + AuthorityKeyIdentifier { + critical: false, + keyid: None, + issuer: None, + } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier { + self.critical = true; + self + } + + /// Sets the `keyid` flag. + pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { + self.keyid = Some(always); + self + } + + /// Sets the `issuer` flag. + pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { + self.issuer = Some(always); + self + } + + /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context) -> Result { + let mut value = String::new(); + let mut first = true; + append(&mut value, &mut first, self.critical, "critical"); + match self.keyid { + Some(true) => append(&mut value, &mut first, true, "keyid:always"), + Some(false) => append(&mut value, &mut first, true, "keyid"), + None => {} + } + match self.issuer { + Some(true) => append(&mut value, &mut first, true, "issuer:always"), + Some(false) => append(&mut value, &mut first, true, "issuer"), + None => {} + } + X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value) + } +} + +/// An extension that allows additional identities to be bound to the subject +/// of the certificate. +pub struct SubjectAlternativeName { + critical: bool, + names: Vec, +} + +impl SubjectAlternativeName { + /// Construct a new `SubjectAlternativeName` extension. + pub fn new() -> SubjectAlternativeName { + SubjectAlternativeName { + critical: false, + names: vec![], + } + } + + /// Sets the `critical` flag to `true`. The extension will be critical. + pub fn critical(&mut self) -> &mut SubjectAlternativeName { + self.critical = true; + self + } + + /// Sets the `email` flag. + pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("email:{}", email)); + self + } + + /// Sets the `uri` flag. + pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("URI:{}", uri)); + self + } + + /// Sets the `dns` flag. + pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("DNS:{}", dns)); + self + } + + /// Sets the `rid` flag. + pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("RID:{}", rid)); + self + } + + /// Sets the `ip` flag. + pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("IP:{}", ip)); + self + } + + /// Sets the `dirName` flag. + pub fn dir_name(&mut self, dir_name: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("dirName:{}", dir_name)); + self + } + + /// Sets the `otherName` flag. + pub fn other_name(&mut self, other_name: &str) -> &mut SubjectAlternativeName { + self.names.push(format!("otherName:{}", other_name)); + self + } + + /// Return a `SubjectAlternativeName` extension as an `X509Extension`. + pub fn build(&self, ctx: &X509v3Context) -> Result { + let mut value = String::new(); + let mut first = true; + append(&mut value, &mut first, self.critical, "critical"); + for name in &self.names { + append(&mut value, &mut first, true, name); + } + X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_ALT_NAME, &value) + } +} + +fn append(value: &mut String, first: &mut bool, should: bool, element: &str) { + if !should { + return; + } + + if !*first { + value.push(','); + } + *first = false; + value.push_str(element); +} diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs new file mode 100644 index 000000000..f156269f2 --- /dev/null +++ b/openssl/src/x509/mod.rs @@ -0,0 +1,1398 @@ +//! The standard defining the format of public key certificates. +//! +//! An `X509` certificate binds an identity to a public key, and is either +//! signed by a certificate authority (CA) or self-signed. An entity that gets +//! a hold of a certificate can both verify your identity (via a CA) and encrypt +//! data with the included public key. `X509` certificates are used in many +//! Internet protocols, including SSL/TLS, which is the basis for HTTPS, +//! the secure protocol for browsing the web. + +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_int, c_long}; +use std::error::Error; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::path::Path; +use std::ptr; +use std::slice; +use std::str; + +use asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef}; +use bio::MemBioSlice; +use conf::ConfRef; +use error::ErrorStack; +use ex_data::Index; +use hash::{DigestBytes, MessageDigest}; +use nid::Nid; +use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; +use ssl::SslRef; +use stack::{Stack, StackRef, Stackable}; +use string::OpensslString; +use {cvt, cvt_n, cvt_p}; + +#[cfg(any(ossl102, libressl261))] +pub mod verify; + +pub mod extension; +pub mod store; + +#[cfg(test)] +mod tests; + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_STORE_CTX; + fn drop = ffi::X509_STORE_CTX_free; + + /// An `X509` certificate store context. + pub struct X509StoreContext; + + /// Reference to `X509StoreContext`. + pub struct X509StoreContextRef; +} + +impl X509StoreContext { + /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a + /// context. + pub fn ssl_idx() -> Result, ErrorStack> { + unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } + } + + /// Creates a new `X509StoreContext` instance. + /// + /// This corresponds to [`X509_STORE_CTX_new`]. + /// + /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext(p)) + } + } +} + +impl X509StoreContextRef { + /// Returns application data pertaining to an `X509` store context. + /// + /// This corresponds to [`X509_STORE_CTX_get_ex_data`]. + /// + /// [`X509_STORE_CTX_get_ex_data`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_ex_data.html + pub fn ex_data(&self, index: Index) -> Option<&T> { + unsafe { + let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&*(data as *const T)) + } + } + } + + /// Returns the error code of the context. + /// + /// This corresponds to [`X509_STORE_CTX_get_error`]. + /// + /// [`X509_STORE_CTX_get_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error.html + pub fn error(&self) -> X509VerifyResult { + unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } + } + + /// Initializes this context with the given certificate, certificates chain and certificate + /// store. After initializing the context, the `with_context` closure is called with the prepared + /// context. As long as the closure is running, the context stays initialized and can be used + /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. + /// + /// * `trust` - The certificate store with the trusted certificates. + /// * `cert` - The certificate that should be verified. + /// * `cert_chain` - The certificates chain. + /// * `with_context` - The closure that is called with the initialized context. + /// + /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to + /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. + /// + /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html + /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html + pub fn init( + &mut self, + trust: &store::X509StoreRef, + cert: &X509Ref, + cert_chain: &StackRef, + with_context: F, + ) -> Result + where + F: FnOnce(&mut X509StoreContextRef) -> Result, + { + struct Cleanup<'a>(&'a mut X509StoreContextRef); + + impl<'a> Drop for Cleanup<'a> { + fn drop(&mut self) { + unsafe { + ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); + } + } + } + + unsafe { + cvt(ffi::X509_STORE_CTX_init( + self.as_ptr(), + trust.as_ptr(), + cert.as_ptr(), + cert_chain.as_ptr(), + ))?; + + let cleanup = Cleanup(self); + with_context(cleanup.0) + } + } + + /// Verifies the stored certificate. + /// + /// Returns `true` if verification succeeds. The `error` method will return the specific + /// validation error if the certificate was not valid. + /// + /// This will only work inside of a call to `init`. + /// + /// This corresponds to [`X509_verify_cert`]. + /// + /// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html + pub fn verify_cert(&mut self) -> Result { + unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } + } + + /// Set the error code of the context. + /// + /// This corresponds to [`X509_STORE_CTX_set_error`]. + /// + /// [`X509_STORE_CTX_set_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_set_error.html + pub fn set_error(&mut self, result: X509VerifyResult) { + unsafe { + ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); + } + } + + /// Returns a reference to the certificate which caused the error or None if + /// no certificate is relevant to the error. + /// + /// This corresponds to [`X509_STORE_CTX_get_current_cert`]. + /// + /// [`X509_STORE_CTX_get_current_cert`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_current_cert.html + pub fn current_cert(&self) -> Option<&X509Ref> { + unsafe { + let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(X509Ref::from_ptr(ptr)) + } + } + } + + /// Returns a non-negative integer representing the depth in the certificate + /// chain where the error occurred. If it is zero it occurred in the end + /// entity certificate, one if it is the certificate which signed the end + /// entity certificate and so on. + /// + /// This corresponds to [`X509_STORE_CTX_get_error_depth`]. + /// + /// [`X509_STORE_CTX_get_error_depth`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error_depth.html + pub fn error_depth(&self) -> u32 { + unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } + } + + /// Returns a reference to a complete valid `X509` certificate chain. + /// + /// This corresponds to [`X509_STORE_CTX_get0_chain`]. + /// + /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html + pub fn chain(&self) -> Option<&StackRef> { + unsafe { + let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); + + if chain.is_null() { + None + } else { + Some(StackRef::from_ptr(chain)) + } + } + } +} + +/// A builder used to construct an `X509`. +pub struct X509Builder(X509); + +impl X509Builder { + /// Creates a new builder. + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) + } + } + + /// Sets the notAfter constraint on the certificate. + pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { + unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } + } + + /// Sets the notBefore constraint on the certificate. + pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { + unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } + } + + /// Sets the version of the certificate. + /// + /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of + /// the X.509 standard should pass `2` to this method. + pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } + } + + /// Sets the serial number of the certificate. + pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_set_serialNumber( + self.0.as_ptr(), + serial_number.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the issuer name of the certificate. + pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_set_issuer_name( + self.0.as_ptr(), + issuer_name.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the subject name of the certificate. + /// + /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools. + /// The `CN` field is used for the common name, such as a DNS name. + /// + /// ``` + /// use openssl::x509::{X509, X509NameBuilder}; + /// + /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap(); + /// x509_name.append_entry_by_text("C", "US").unwrap(); + /// x509_name.append_entry_by_text("ST", "CA").unwrap(); + /// x509_name.append_entry_by_text("O", "Some organization").unwrap(); + /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap(); + /// let x509_name = x509_name.build(); + /// + /// let mut x509 = openssl::x509::X509::builder().unwrap(); + /// x509.set_subject_name(&x509_name).unwrap(); + /// ``` + pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_set_subject_name( + self.0.as_ptr(), + subject_name.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the public key associated with the certificate. + pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } + } + + /// Returns a context object which is needed to create certain X509 extension values. + /// + /// Set `issuer` to `None` if the certificate will be self-signed. + pub fn x509v3_context<'a>( + &'a self, + issuer: Option<&'a X509Ref>, + conf: Option<&'a ConfRef>, + ) -> X509v3Context<'a> { + unsafe { + let mut ctx = mem::zeroed(); + + let issuer = match issuer { + Some(issuer) => issuer.as_ptr(), + None => self.0.as_ptr(), + }; + let subject = self.0.as_ptr(); + ffi::X509V3_set_ctx( + &mut ctx, + issuer, + subject, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + + // nodb case taken care of since we zeroed ctx above + if let Some(conf) = conf { + ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); + } + + X509v3Context(ctx, PhantomData) + } + } + + /// Adds an X509 extension value to the certificate. + pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; + mem::forget(extension); + Ok(()) + } + } + + /// Signs the certificate with a private key. + pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> + where + T: HasPrivate, + { + unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } + } + + /// Consumes the builder, returning the certificate. + pub fn build(self) -> X509 { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509; + fn drop = ffi::X509_free; + + /// An `X509` public key certificate. + pub struct X509; + /// Reference to `X509`. + pub struct X509Ref; +} + +impl X509Ref { + /// Returns this certificate's subject name. + /// + /// This corresponds to [`X509_get_subject_name`]. + /// + /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html + pub fn subject_name(&self) -> &X509NameRef { + unsafe { + let name = ffi::X509_get_subject_name(self.as_ptr()); + assert!(!name.is_null()); + X509NameRef::from_ptr(name) + } + } + + /// Returns this certificate's issuer name. + /// + /// This corresponds to [`X509_get_issuer_name`]. + /// + /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html + pub fn issuer_name(&self) -> &X509NameRef { + unsafe { + let name = ffi::X509_get_issuer_name(self.as_ptr()); + assert!(!name.is_null()); + X509NameRef::from_ptr(name) + } + } + + /// Returns this certificate's subject alternative name entries, if they exist. + /// + /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. + /// + /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html + pub fn subject_alt_names(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_subject_alt_name, + ptr::null_mut(), + ptr::null_mut(), + ); + if stack.is_null() { + None + } else { + Some(Stack::from_ptr(stack as *mut _)) + } + } + } + + /// Returns this certificate's issuer alternative name entries, if they exist. + /// + /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. + /// + /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html + pub fn issuer_alt_names(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_issuer_alt_name, + ptr::null_mut(), + ptr::null_mut(), + ); + if stack.is_null() { + None + } else { + Some(Stack::from_ptr(stack as *mut _)) + } + } + } + + pub fn public_key(&self) -> Result, ErrorStack> { + unsafe { + let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; + Ok(PKey::from_ptr(pkey)) + } + } + + /// Returns a digest of the DER representation of the certificate. + /// + /// This corresponds to [`X509_digest`]. + /// + /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html + pub fn digest(&self, hash_type: MessageDigest) -> Result { + unsafe { + let mut digest = DigestBytes { + buf: [0; ffi::EVP_MAX_MD_SIZE as usize], + len: ffi::EVP_MAX_MD_SIZE as usize, + }; + let mut len = ffi::EVP_MAX_MD_SIZE; + cvt(ffi::X509_digest( + self.as_ptr(), + hash_type.as_ptr(), + digest.buf.as_mut_ptr() as *mut _, + &mut len, + ))?; + digest.len = len as usize; + + Ok(digest) + } + } + + #[deprecated(since = "0.10.9", note = "renamed to digest")] + pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + self.digest(hash_type).map(|b| b.to_vec()) + } + + /// Returns the certificate's Not After validity period. + pub fn not_after(&self) -> &Asn1TimeRef { + unsafe { + let date = X509_getm_notAfter(self.as_ptr()); + assert!(!date.is_null()); + Asn1TimeRef::from_ptr(date) + } + } + + /// Returns the certificate's Not Before validity period. + pub fn not_before(&self) -> &Asn1TimeRef { + unsafe { + let date = X509_getm_notBefore(self.as_ptr()); + assert!(!date.is_null()); + Asn1TimeRef::from_ptr(date) + } + } + + /// Returns the certificate's signature + pub fn signature(&self) -> &Asn1BitStringRef { + unsafe { + let mut signature = ptr::null(); + X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); + assert!(!signature.is_null()); + Asn1BitStringRef::from_ptr(signature as *mut _) + } + } + + /// Returns the certificate's signature algorithm. + pub fn signature_algorithm(&self) -> &X509AlgorithmRef { + unsafe { + let mut algor = ptr::null(); + X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); + assert!(!algor.is_null()); + X509AlgorithmRef::from_ptr(algor as *mut _) + } + } + + /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information + /// Access field. + pub fn ocsp_responders(&self) -> Result, ErrorStack> { + unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } + } + + /// Checks that this certificate issued `subject`. + pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { + unsafe { + let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); + X509VerifyResult::from_raw(r) + } + } + + /// Check if the certificate is signed using the given public key. + /// + /// Only the signature is checked: no other checks (such as certificate chain validity) + /// are performed. + /// + /// Returns `true` if verification succeeds. + /// + /// This corresponds to [`X509_verify"]. + /// + /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + + /// Returns this certificate's serial number. + /// + /// This corresponds to [`X509_get_serialNumber`]. + /// + /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html + pub fn serial_number(&self) -> &Asn1IntegerRef { + unsafe { + let r = ffi::X509_get_serialNumber(self.as_ptr()); + assert!(!r.is_null()); + Asn1IntegerRef::from_ptr(r) + } + } + + to_pem! { + /// Serializes the certificate into a PEM-encoded X509 structure. + /// + /// The output will have a header of `-----BEGIN CERTIFICATE-----`. + /// + /// This corresponds to [`PEM_write_bio_X509`]. + /// + /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html + to_pem, + ffi::PEM_write_bio_X509 + } + + to_der! { + /// Serializes the certificate into a DER-encoded X509 structure. + /// + /// This corresponds to [`i2d_X509`]. + /// + /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html + to_der, + ffi::i2d_X509 + } +} + +impl ToOwned for X509Ref { + type Owned = X509; + + fn to_owned(&self) -> X509 { + unsafe { + X509_up_ref(self.as_ptr()); + X509::from_ptr(self.as_ptr()) + } + } +} + +impl X509 { + /// Returns a new builder. + pub fn builder() -> Result { + X509Builder::new() + } + + from_pem! { + /// Deserializes a PEM-encoded X509 structure. + /// + /// The input should have a header of `-----BEGIN CERTIFICATE-----`. + /// + /// This corresponds to [`PEM_read_bio_X509`]. + /// + /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html + from_pem, + X509, + ffi::PEM_read_bio_X509 + } + + from_der! { + /// Deserializes a DER-encoded X509 structure. + /// + /// This corresponds to [`d2i_X509`]. + /// + /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html + from_der, + X509, + ffi::d2i_X509 + } + + /// Deserializes a list of PEM-formatted certificates. + pub fn stack_from_pem(pem: &[u8]) -> Result, ErrorStack> { + unsafe { + ffi::init(); + let bio = MemBioSlice::new(pem)?; + + let mut certs = vec![]; + loop { + let r = + ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); + if r.is_null() { + let err = ffi::ERR_peek_last_error(); + if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM + && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE + { + ffi::ERR_clear_error(); + break; + } + + return Err(ErrorStack::get()); + } else { + certs.push(X509(r)); + } + } + + Ok(certs) + } + } +} + +impl Clone for X509 { + fn clone(&self) -> X509 { + X509Ref::to_owned(self) + } +} + +impl AsRef for X509Ref { + fn as_ref(&self) -> &X509Ref { + self + } +} + +impl Stackable for X509 { + type StackType = ffi::stack_st_X509; +} + +/// A context object required to construct certain `X509` extension values. +pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); + +impl<'a> X509v3Context<'a> { + pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { + &self.0 as *const _ as *mut _ + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_EXTENSION; + fn drop = ffi::X509_EXTENSION_free; + + /// Permit additional fields to be added to an `X509` v3 certificate. + pub struct X509Extension; + /// Reference to `X509Extension`. + pub struct X509ExtensionRef; +} + +impl Stackable for X509Extension { + type StackType = ffi::stack_st_X509_EXTENSION; +} + +impl X509Extension { + /// Constructs an X509 extension value. See `man x509v3_config` for information on supported + /// names and their value formats. + /// + /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be + /// provided. + /// + /// See the extension module for builder types which will construct certain common extensions. + pub fn new( + conf: Option<&ConfRef>, + context: Option<&X509v3Context>, + name: &str, + value: &str, + ) -> Result { + let name = CString::new(name).unwrap(); + let value = CString::new(value).unwrap(); + unsafe { + ffi::init(); + let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); + let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); + let name = name.as_ptr() as *mut _; + let value = value.as_ptr() as *mut _; + + cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) + } + } + + /// Constructs an X509 extension value. See `man x509v3_config` for information on supported + /// extensions and their value formats. + /// + /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to + /// be provided. + /// + /// See the extension module for builder types which will construct certain common extensions. + pub fn new_nid( + conf: Option<&ConfRef>, + context: Option<&X509v3Context>, + name: Nid, + value: &str, + ) -> Result { + let value = CString::new(value).unwrap(); + unsafe { + ffi::init(); + let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); + let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); + let name = name.as_raw(); + let value = value.as_ptr() as *mut _; + + cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) + } + } +} + +/// A builder used to construct an `X509Name`. +pub struct X509NameBuilder(X509Name); + +impl X509NameBuilder { + /// Creates a new builder. + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) + } + } + + /// Add a field entry by str. + /// + /// This corresponds to [`X509_NAME_add_entry_by_txt`]. + /// + /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html + pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { + unsafe { + let field = CString::new(field).unwrap(); + assert!(value.len() <= c_int::max_value() as usize); + cvt(ffi::X509_NAME_add_entry_by_txt( + self.0.as_ptr(), + field.as_ptr() as *mut _, + ffi::MBSTRING_UTF8, + value.as_ptr(), + value.len() as c_int, + -1, + 0, + )) + .map(|_| ()) + } + } + + /// Add a field entry by NID. + /// + /// This corresponds to [`X509_NAME_add_entry_by_NID`]. + /// + /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html + pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { + unsafe { + assert!(value.len() <= c_int::max_value() as usize); + cvt(ffi::X509_NAME_add_entry_by_NID( + self.0.as_ptr(), + field.as_raw(), + ffi::MBSTRING_UTF8, + value.as_ptr() as *mut _, + value.len() as c_int, + -1, + 0, + )) + .map(|_| ()) + } + } + + /// Return an `X509Name`. + pub fn build(self) -> X509Name { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_NAME; + fn drop = ffi::X509_NAME_free; + + /// The names of an `X509` certificate. + pub struct X509Name; + /// Reference to `X509Name`. + pub struct X509NameRef; +} + +impl X509Name { + /// Returns a new builder. + pub fn builder() -> Result { + X509NameBuilder::new() + } + + /// Loads subject names from a file containing PEM-formatted certificates. + /// + /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`. + pub fn load_client_ca_file>(file: P) -> Result, ErrorStack> { + let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); + unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } + } +} + +impl Stackable for X509Name { + type StackType = ffi::stack_st_X509_NAME; +} + +impl X509NameRef { + /// Returns the name entries by the nid. + pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { + X509NameEntries { + name: self, + nid: Some(nid), + loc: -1, + } + } + + /// Returns an iterator over all `X509NameEntry` values + pub fn entries<'a>(&'a self) -> X509NameEntries<'a> { + X509NameEntries { + name: self, + nid: None, + loc: -1, + } + } +} + +/// A type to destructure and examine an `X509Name`. +pub struct X509NameEntries<'a> { + name: &'a X509NameRef, + nid: Option, + loc: c_int, +} + +impl<'a> Iterator for X509NameEntries<'a> { + type Item = &'a X509NameEntryRef; + + fn next(&mut self) -> Option<&'a X509NameEntryRef> { + unsafe { + match self.nid { + Some(nid) => { + // There is a `Nid` specified to search for + self.loc = + ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); + if self.loc == -1 { + return None; + } + } + None => { + // Iterate over all `Nid`s + self.loc += 1; + if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { + return None; + } + } + } + + let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); + assert!(!entry.is_null()); + + Some(X509NameEntryRef::from_ptr(entry)) + } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_NAME_ENTRY; + fn drop = ffi::X509_NAME_ENTRY_free; + + /// A name entry associated with a `X509Name`. + pub struct X509NameEntry; + /// Reference to `X509NameEntry`. + pub struct X509NameEntryRef; +} + +impl X509NameEntryRef { + /// Returns the field value of an `X509NameEntry`. + /// + /// This corresponds to [`X509_NAME_ENTRY_get_data`]. + /// + /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html + pub fn data(&self) -> &Asn1StringRef { + unsafe { + let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); + Asn1StringRef::from_ptr(data) + } + } + + /// Returns the `Asn1Object` value of an `X509NameEntry`. + /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. + /// + /// This corresponds to [`X509_NAME_ENTRY_get_object`]. + /// + /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html + pub fn object(&self) -> &Asn1ObjectRef { + unsafe { + let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); + Asn1ObjectRef::from_ptr(object) + } + } +} + +/// A builder used to construct an `X509Req`. +pub struct X509ReqBuilder(X509Req); + +impl X509ReqBuilder { + /// Returns a builder for a certificate request. + /// + /// This corresponds to [`X509_REQ_new`]. + /// + ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) + } + } + + /// Set the numerical value of the version field. + /// + /// This corresponds to [`X509_REQ_set_version`]. + /// + ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html + pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } + } + + /// Set the issuer name. + /// + /// This corresponds to [`X509_REQ_set_subject_name`]. + /// + /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html + pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_REQ_set_subject_name( + self.0.as_ptr(), + subject_name.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Set the public key. + /// + /// This corresponds to [`X509_REQ_set_pubkey`]. + /// + /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html + pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } + } + + /// Return an `X509v3Context`. This context object can be used to construct + /// certain `X509` extensions. + pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { + unsafe { + let mut ctx = mem::zeroed(); + + ffi::X509V3_set_ctx( + &mut ctx, + ptr::null_mut(), + ptr::null_mut(), + self.0.as_ptr(), + ptr::null_mut(), + 0, + ); + + // nodb case taken care of since we zeroed ctx above + if let Some(conf) = conf { + ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); + } + + X509v3Context(ctx, PhantomData) + } + } + + /// Permits any number of extension fields to be added to the certificate. + pub fn add_extensions( + &mut self, + extensions: &StackRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_REQ_add_extensions( + self.0.as_ptr(), + extensions.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sign the request using a private key. + /// + /// This corresponds to [`X509_REQ_sign`]. + /// + /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html + pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> + where + T: HasPrivate, + { + unsafe { + cvt(ffi::X509_REQ_sign( + self.0.as_ptr(), + key.as_ptr(), + hash.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Returns the `X509Req`. + pub fn build(self) -> X509Req { + self.0 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_REQ; + fn drop = ffi::X509_REQ_free; + + /// An `X509` certificate request. + pub struct X509Req; + /// Reference to `X509Req`. + pub struct X509ReqRef; +} + +impl X509Req { + /// A builder for `X509Req`. + pub fn builder() -> Result { + X509ReqBuilder::new() + } + + from_pem! { + /// Deserializes a PEM-encoded PKCS#10 certificate request structure. + /// + /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. + /// + /// This corresponds to [`PEM_read_bio_X509_REQ`]. + /// + /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html + from_pem, + X509Req, + ffi::PEM_read_bio_X509_REQ + } + + from_der! { + /// Deserializes a DER-encoded PKCS#10 certificate request structure. + /// + /// This corresponds to [`d2i_X509_REQ`]. + /// + /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html + from_der, + X509Req, + ffi::d2i_X509_REQ + } +} + +impl X509ReqRef { + to_pem! { + /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. + /// + /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. + /// + /// This corresponds to [`PEM_write_bio_X509_REQ`]. + /// + /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html + to_pem, + ffi::PEM_write_bio_X509_REQ + } + + to_der! { + /// Serializes the certificate request to a DER-encoded PKCS#10 structure. + /// + /// This corresponds to [`i2d_X509_REQ`]. + /// + /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html + to_der, + ffi::i2d_X509_REQ + } + + /// Returns the numerical value of the version field of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_version`] + /// + /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html + pub fn version(&self) -> i32 { + unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } + } + + /// Returns the subject name of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_subject_name`] + /// + /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html + pub fn subject_name(&self) -> &X509NameRef { + unsafe { + let name = X509_REQ_get_subject_name(self.as_ptr()); + assert!(!name.is_null()); + X509NameRef::from_ptr(name) + } + } + + /// Returns the public key of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_pubkey"] + /// + /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html + pub fn public_key(&self) -> Result, ErrorStack> { + unsafe { + let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; + Ok(PKey::from_ptr(key)) + } + } + + /// Check if the certificate request is signed using the given public key. + /// + /// Returns `true` if verification succeeds. + /// + /// This corresponds to [`X509_REQ_verify"]. + /// + /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + + /// Returns the extensions of the certificate request. + /// + /// This corresponds to [`X509_REQ_get_extensions"] + pub fn extensions(&self) -> Result, ErrorStack> { + unsafe { + let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; + Ok(Stack::from_ptr(extensions)) + } + } +} + +/// The result of peer certificate verification. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct X509VerifyResult(c_int); + +impl fmt::Debug for X509VerifyResult { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("X509VerifyResult") + .field("code", &self.0) + .field("error", &self.error_string()) + .finish() + } +} + +impl fmt::Display for X509VerifyResult { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.error_string()) + } +} + +impl Error for X509VerifyResult { + fn description(&self) -> &str { + "an X509 validation error" + } +} + +impl X509VerifyResult { + /// Creates an `X509VerifyResult` from a raw error number. + /// + /// # Safety + /// + /// Some methods on `X509VerifyResult` are not thread safe if the error + /// number is invalid. + pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { + X509VerifyResult(err) + } + + /// Return the integer representation of an `X509VerifyResult`. + pub fn as_raw(&self) -> c_int { + self.0 + } + + /// Return a human readable error string from the verification error. + /// + /// This corresponds to [`X509_verify_cert_error_string`]. + /// + /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html + pub fn error_string(&self) -> &'static str { + ffi::init(); + + unsafe { + let s = ffi::X509_verify_cert_error_string(self.0 as c_long); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } + + /// Successful peer certifiate verification. + pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); + /// Application verification failure. + pub const APPLICATION_VERIFICATION: X509VerifyResult = + X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::GENERAL_NAME; + fn drop = ffi::GENERAL_NAME_free; + + /// An `X509` certificate alternative names. + pub struct GeneralName; + /// Reference to `GeneralName`. + pub struct GeneralNameRef; +} + +impl GeneralNameRef { + fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { + unsafe { + if (*self.as_ptr()).type_ != ffi_type { + return None; + } + + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); + let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); + + let slice = slice::from_raw_parts(ptr as *const u8, len as usize); + // IA5Strings are stated to be ASCII (specifically IA5). Hopefully + // OpenSSL checks that when loading a certificate but if not we'll + // use this instead of from_utf8_unchecked just in case. + str::from_utf8(slice).ok() + } + } + + /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. + pub fn email(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_EMAIL) + } + + /// Returns the contents of this `GeneralName` if it is a `dNSName`. + pub fn dnsname(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_DNS) + } + + /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. + pub fn uri(&self) -> Option<&str> { + self.ia5_string(ffi::GEN_URI) + } + + /// Returns the contents of this `GeneralName` if it is an `iPAddress`. + pub fn ipaddress(&self) -> Option<&[u8]> { + unsafe { + if (*self.as_ptr()).type_ != ffi::GEN_IPADD { + return None; + } + + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); + let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); + + Some(slice::from_raw_parts(ptr as *const u8, len as usize)) + } + } +} + +impl Stackable for GeneralName { + type StackType = ffi::stack_st_GENERAL_NAME; +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_ALGOR; + fn drop = ffi::X509_ALGOR_free; + + /// An `X509` certificate signature algorithm. + pub struct X509Algorithm; + /// Reference to `X509Algorithm`. + pub struct X509AlgorithmRef; +} + +impl X509AlgorithmRef { + /// Returns the ASN.1 OID of this algorithm. + pub fn object(&self) -> &Asn1ObjectRef { + unsafe { + let mut oid = ptr::null(); + X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); + assert!(!oid.is_null()); + Asn1ObjectRef::from_ptr(oid as *mut _) + } + } +} + +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; + } else { + #[allow(bad_style)] + unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notAfter + } + + #[allow(bad_style)] + unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notBefore + } + + #[allow(bad_style)] + unsafe fn X509_up_ref(x: *mut ffi::X509) { + ffi::CRYPTO_add_lock( + &mut (*x).references, + 1, + ffi::CRYPTO_LOCK_X509, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + } + + #[allow(bad_style)] + unsafe fn X509_get0_signature( + psig: *mut *const ffi::ASN1_BIT_STRING, + palg: *mut *const ffi::X509_ALGOR, + x: *const ffi::X509, + ) { + if !psig.is_null() { + *psig = (*x).signature; + } + if !palg.is_null() { + *palg = (*x).sig_alg; + } + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, + X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, + }; + } else { + use ffi::{ + ASN1_STRING_data as ASN1_STRING_get0_data, + X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, + X509_set_notAfter as X509_set1_notAfter, + X509_set_notBefore as X509_set1_notBefore, + }; + + #[allow(bad_style)] + unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { + ffi::ASN1_INTEGER_get((*(*x).req_info).version) + } + + #[allow(bad_style)] + unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { + (*(*x).req_info).subject + } + + #[allow(bad_style)] + unsafe fn X509_ALGOR_get0( + paobj: *mut *const ffi::ASN1_OBJECT, + pptype: *mut c_int, + pval: *mut *mut ::libc::c_void, + alg: *const ffi::X509_ALGOR, + ) { + if !paobj.is_null() { + *paobj = (*alg).algorithm; + } + assert!(pptype.is_null()); + assert!(pval.is_null()); + } + } +} diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs new file mode 100644 index 000000000..f533d9c76 --- /dev/null +++ b/openssl/src/x509/store.rs @@ -0,0 +1,106 @@ +//! Describe a context in which to verify an `X509` certificate. +//! +//! The `X509` certificate store holds trusted CA certificates used to verify +//! peer certificates. +//! +//! # Example +//! +//! ```rust +//! +//! extern crate openssl; +//! +//! use openssl::x509::store::{X509StoreBuilder, X509Store}; +//! use openssl::x509::{X509, X509Name}; +//! use openssl::pkey::PKey; +//! use openssl::hash::MessageDigest; +//! use openssl::rsa::Rsa; +//! use openssl::nid::Nid; +//! +//! fn main() { +//! let rsa = Rsa::generate(2048).unwrap(); +//! let pkey = PKey::from_rsa(rsa).unwrap(); +//! +//! let mut name = X509Name::builder().unwrap(); +//! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap(); +//! let name = name.build(); +//! +//! let mut builder = X509::builder().unwrap(); +//! builder.set_version(2).unwrap(); +//! builder.set_subject_name(&name).unwrap(); +//! builder.set_issuer_name(&name).unwrap(); +//! builder.set_pubkey(&pkey).unwrap(); +//! builder.sign(&pkey, MessageDigest::sha256()).unwrap(); +//! +//! let certificate: X509 = builder.build(); +//! +//! let mut builder = X509StoreBuilder::new().unwrap(); +//! let _ = builder.add_cert(certificate); +//! +//! let store: X509Store = builder.build(); +//! } +//! ``` + +use ffi; +use foreign_types::ForeignTypeRef; +use std::mem; + +use error::ErrorStack; +use x509::X509; +use {cvt, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_STORE; + fn drop = ffi::X509_STORE_free; + + /// A builder type used to construct an `X509Store`. + pub struct X509StoreBuilder; + /// Reference to an `X509StoreBuilder`. + pub struct X509StoreBuilderRef; +} + +impl X509StoreBuilder { + /// Returns a builder for a certificate store. + /// + /// The store is initially empty. + pub fn new() -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder) + } + } + + /// Constructs the `X509Store`. + pub fn build(self) -> X509Store { + let store = X509Store(self.0); + mem::forget(self); + store + } +} + +impl X509StoreBuilderRef { + /// Adds a certificate to the certificate store. + // FIXME should take an &X509Ref + pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } + } + + /// Load certificates from their default locations. + /// + /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` + /// environment variables if present, or defaults specified at OpenSSL + /// build time otherwise. + pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_STORE; + fn drop = ffi::X509_STORE_free; + + /// A certificate store to hold trusted `X509` certificates. + pub struct X509Store; + /// Reference to an `X509Store`. + pub struct X509StoreRef; +} diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs new file mode 100644 index 000000000..4bd3e5f3e --- /dev/null +++ b/openssl/src/x509/tests.rs @@ -0,0 +1,366 @@ +use hex::{self, FromHex}; + +use asn1::Asn1Time; +use bn::{BigNum, MsbOption}; +use hash::MessageDigest; +use nid::Nid; +use pkey::{PKey, Private}; +use rsa::Rsa; +use stack::Stack; +use x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use x509::store::X509StoreBuilder; +use x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509}; + +fn pkey() -> PKey { + let rsa = Rsa::generate(2048).unwrap(); + PKey::from_rsa(rsa).unwrap() +} + +#[test] +fn test_cert_loading() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + + let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; + let hash_vec = Vec::from_hex(hash_str).unwrap(); + + assert_eq!(hash_vec, &*fingerprint); +} + +#[test] +fn test_cert_issue_validity() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + let not_before = cert.not_before().to_string(); + let not_after = cert.not_after().to_string(); + + assert_eq!(not_before, "Aug 14 17:00:03 2016 GMT"); + assert_eq!(not_after, "Aug 12 17:00:03 2026 GMT"); +} + +#[test] +fn test_save_der() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + + let der = cert.to_der().unwrap(); + assert!(!der.is_empty()); +} + +#[test] +fn test_subject_read_cn() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); + assert_eq!(cn.data().as_slice(), b"foobar.com") +} + +#[test] +fn test_nid_values() { + let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + + let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); + assert_eq!(cn.data().as_slice(), b"example.com"); + + let email = subject + .entries_by_nid(Nid::PKCS9_EMAILADDRESS) + .next() + .unwrap(); + assert_eq!(email.data().as_slice(), b"test@example.com"); + + let friendly = subject.entries_by_nid(Nid::FRIENDLYNAME).next().unwrap(); + assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); +} + +#[test] +fn test_nameref_iterator() { + let cert = include_bytes!("../../test/nid_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + let mut all_entries = subject.entries(); + + let email = all_entries.next().unwrap(); + assert_eq!( + email.object().nid().as_raw(), + Nid::PKCS9_EMAILADDRESS.as_raw() + ); + assert_eq!(email.data().as_slice(), b"test@example.com"); + + let cn = all_entries.next().unwrap(); + assert_eq!(cn.object().nid().as_raw(), Nid::COMMONNAME.as_raw()); + assert_eq!(cn.data().as_slice(), b"example.com"); + + let friendly = all_entries.next().unwrap(); + assert_eq!(friendly.object().nid().as_raw(), Nid::FRIENDLYNAME.as_raw()); + assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); + + if let Some(_) = all_entries.next() { + assert!(false); + } +} + +#[test] +fn test_nid_uid_value() { + let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + + let cn = subject.entries_by_nid(Nid::USERID).next().unwrap(); + assert_eq!(cn.data().as_slice(), b"this is the userId"); +} + +#[test] +fn test_subject_alt_name() { + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let subject_alt_names = cert.subject_alt_names().unwrap(); + assert_eq!(5, subject_alt_names.len()); + assert_eq!(Some("example.com"), subject_alt_names[0].dnsname()); + assert_eq!(subject_alt_names[1].ipaddress(), Some(&[127, 0, 0, 1][..])); + assert_eq!( + subject_alt_names[2].ipaddress(), + Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) + ); + assert_eq!(Some("test@example.com"), subject_alt_names[3].email()); + assert_eq!(Some("http://www.example.com"), subject_alt_names[4].uri()); +} + +#[test] +fn test_subject_alt_name_iter() { + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); + + let subject_alt_names = cert.subject_alt_names().unwrap(); + let mut subject_alt_names_iter = subject_alt_names.iter(); + assert_eq!( + subject_alt_names_iter.next().unwrap().dnsname(), + Some("example.com") + ); + assert_eq!( + subject_alt_names_iter.next().unwrap().ipaddress(), + Some(&[127, 0, 0, 1][..]) + ); + assert_eq!( + subject_alt_names_iter.next().unwrap().ipaddress(), + Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) + ); + assert_eq!( + subject_alt_names_iter.next().unwrap().email(), + Some("test@example.com") + ); + assert_eq!( + subject_alt_names_iter.next().unwrap().uri(), + Some("http://www.example.com") + ); + assert!(subject_alt_names_iter.next().is_none()); +} + +#[test] +fn x509_builder() { + let pkey = pkey(); + + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") + .unwrap(); + let name = name.build(); + + let mut builder = X509::builder().unwrap(); + builder.set_version(2).unwrap(); + builder.set_subject_name(&name).unwrap(); + builder.set_issuer_name(&name).unwrap(); + builder + .set_not_before(&Asn1Time::days_from_now(0).unwrap()) + .unwrap(); + builder + .set_not_after(&Asn1Time::days_from_now(365).unwrap()) + .unwrap(); + builder.set_pubkey(&pkey).unwrap(); + + let mut serial = BigNum::new().unwrap(); + serial.rand(128, MsbOption::MAYBE_ZERO, false).unwrap(); + builder + .set_serial_number(&serial.to_asn1_integer().unwrap()) + .unwrap(); + + let basic_constraints = BasicConstraints::new().critical().ca().build().unwrap(); + builder.append_extension(basic_constraints).unwrap(); + let key_usage = KeyUsage::new() + .digital_signature() + .key_encipherment() + .build() + .unwrap(); + builder.append_extension(key_usage).unwrap(); + let ext_key_usage = ExtendedKeyUsage::new() + .client_auth() + .server_auth() + .other("2.999.1") + .build() + .unwrap(); + builder.append_extension(ext_key_usage).unwrap(); + let subject_key_identifier = SubjectKeyIdentifier::new() + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(subject_key_identifier).unwrap(); + let authority_key_identifier = AuthorityKeyIdentifier::new() + .keyid(true) + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(authority_key_identifier).unwrap(); + let subject_alternative_name = SubjectAlternativeName::new() + .dns("example.com") + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(subject_alternative_name).unwrap(); + + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + + let x509 = builder.build(); + + assert!(pkey.public_eq(&x509.public_key().unwrap())); + assert!(x509.verify(&pkey).unwrap()); + + let cn = x509 + .subject_name() + .entries_by_nid(Nid::COMMONNAME) + .next() + .unwrap(); + assert_eq!("foobar.com".as_bytes(), cn.data().as_slice()); + assert_eq!(serial, x509.serial_number().to_bn().unwrap()); +} + +#[test] +fn x509_req_builder() { + let pkey = pkey(); + + let mut name = X509Name::builder().unwrap(); + name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") + .unwrap(); + let name = name.build(); + + let mut builder = X509Req::builder().unwrap(); + builder.set_version(2).unwrap(); + builder.set_subject_name(&name).unwrap(); + builder.set_pubkey(&pkey).unwrap(); + + let mut extensions = Stack::new().unwrap(); + let key_usage = KeyUsage::new() + .digital_signature() + .key_encipherment() + .build() + .unwrap(); + extensions.push(key_usage).unwrap(); + let subject_alternative_name = SubjectAlternativeName::new() + .dns("example.com") + .build(&builder.x509v3_context(None)) + .unwrap(); + extensions.push(subject_alternative_name).unwrap(); + builder.add_extensions(&extensions).unwrap(); + + builder.sign(&pkey, MessageDigest::sha256()).unwrap(); + + let req = builder.build(); + assert!(req.public_key().unwrap().public_eq(&pkey)); + assert_eq!(req.extensions().unwrap().len(), extensions.len()); + assert!(req.verify(&pkey).unwrap()); +} + +#[test] +fn test_stack_from_pem() { + let certs = include_bytes!("../../test/certs.pem"); + let certs = X509::stack_from_pem(certs).unwrap(); + + assert_eq!(certs.len(), 2); + assert_eq!( + hex::encode(certs[0].digest(MessageDigest::sha1()).unwrap()), + "59172d9313e84459bcff27f967e79e6e9217e584" + ); + assert_eq!( + hex::encode(certs[1].digest(MessageDigest::sha1()).unwrap()), + "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" + ); +} + +#[test] +fn issued() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + + assert_eq!(ca.issued(&cert), X509VerifyResult::OK); + assert_ne!(cert.issued(&cert), X509VerifyResult::OK); +} + +#[test] +fn signature() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let signature = cert.signature(); + assert_eq!( + hex::encode(signature.as_slice()), + "4af607b889790b43470442cfa551cdb8b6d0b0340d2958f76b9e3ef6ad4992230cead6842587f0ecad5\ + 78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\ + 4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\ + ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\ + 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ + f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ + e121997410d37c" + ); + let algorithm = cert.signature_algorithm(); + assert_eq!(algorithm.object().nid(), Nid::SHA256WITHRSAENCRYPTION); + assert_eq!(algorithm.object().to_string(), "sha256WithRSAEncryption"); +} + +#[test] +fn clone_x509() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + drop(cert.clone()); +} + +#[test] +fn test_verify_cert() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); +} + +#[test] +fn test_verify_fails() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/alt_name_cert.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(!context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); +} diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs new file mode 100644 index 000000000..3fce03c17 --- /dev/null +++ b/openssl/src/x509/verify.rs @@ -0,0 +1,90 @@ +use ffi; +use foreign_types::ForeignTypeRef; +use libc::c_uint; +use std::net::IpAddr; + +use cvt; +use error::ErrorStack; + +bitflags! { + /// Flags used to check an `X509` certificate. + pub struct X509CheckFlags: c_uint { + const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; + const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; + const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; + const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; + const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(any(ossl110))] + const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; + + #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")] + const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::X509_VERIFY_PARAM; + fn drop = ffi::X509_VERIFY_PARAM_free; + + /// Adjust parameters associated with certificate verification. + pub struct X509VerifyParam; + /// Reference to `X509VerifyParam`. + pub struct X509VerifyParamRef; +} + +impl X509VerifyParamRef { + /// Set the host flags. + /// + /// This corresponds to [`X509_VERIFY_PARAM_set_hostflags`]. + /// + /// [`X509_VERIFY_PARAM_set_hostflags`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set_hostflags.html + pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { + unsafe { + ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits); + } + } + + /// Set the expected DNS hostname. + /// + /// This corresponds to [`X509_VERIFY_PARAM_set1_host`]. + /// + /// [`X509_VERIFY_PARAM_set1_host`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set1_host.html + pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_VERIFY_PARAM_set1_host( + self.as_ptr(), + host.as_ptr() as *const _, + host.len(), + )) + .map(|_| ()) + } + } + + /// Set the expected IPv4 or IPv6 address. + /// + /// This corresponds to [`X509_VERIFY_PARAM_set1_ip`]. + /// + /// [`X509_VERIFY_PARAM_set1_ip`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set1_ip.html + pub fn set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack> { + unsafe { + let mut buf = [0; 16]; + let len = match ip { + IpAddr::V4(addr) => { + buf[..4].copy_from_slice(&addr.octets()); + 4 + } + IpAddr::V6(addr) => { + buf.copy_from_slice(&addr.octets()); + 16 + } + }; + cvt(ffi::X509_VERIFY_PARAM_set1_ip( + self.as_ptr(), + buf.as_ptr() as *const _, + len, + )) + .map(|_| ()) + } + } +} diff --git a/openssl/test/alt_name_cert.pem b/openssl/test/alt_name_cert.pem new file mode 100644 index 000000000..d9e9f90e1 --- /dev/null +++ b/openssl/test/alt_name_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDsDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTET +MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTE4MDExNTExMDcwM1oXDTI4MDExMzExMDcwM1owfDELMAkGA1UE +BhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9yazEVMBMGA1UECgwM +RXhhbXBsZSwgTExDMTYwNAYDVQQDDC1FeGFtcGxlIENvbXBhbnkvZW1haWxBZGRy +ZXNzPXRlc3RAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCo9CWMRLMXo1CF/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErpl +xfLkt0pJqcoiZG8g9NU0kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10 +uSDk6V9aJSX1vKwONVNSwiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1V +fOugka7UktYnk9mrBbAMjmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1G +bN4AtDuhs252eqE9E4iTHk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U +3KTfhO/mTlAUWVyg9tCtOzboKgs1AgMBAAGjdDByMAkGA1UdEwQCMAAwCwYDVR0P +BAQDAgWgMFgGA1UdEQRRME+CC2V4YW1wbGUuY29thwR/AAABhxAAAAAAAAAAAAAA +AAAAAAABgRB0ZXN0QGV4YW1wbGUuY29thhZodHRwOi8vd3d3LmV4YW1wbGUuY29t +MA0GCSqGSIb3DQEBCwUAA4IBAQAx14G99z/MnSbs8h5jSos+dgLvhc2IQB/3CChE +hPyELc7iyw1iteRs7bS1m2NZx6gv6TZ6VydDrK1dnWSatQ7sskXTO+zfC6qjMwXl +IV+u7T8EREwciniIA82d8GWs60BGyBL3zp2iUOr5ULG4+c/S6OLdlyJv+fDKv+Xo +fKv1UGDi5rcvUBikeNkpEPTN9UsE9/A8XJfDyq+4RKuDW19EtzOOeVx4xpHOMnAy +VVAQVMKJzhoXtLF4k2j409na+f6FIcZSBet+plmzfB+WZNIgUUi/7MQIXOFQRkj4 +zH3SnsPm/IYpJzlH2vHhlqIBdaSoTWpGVWPq7D+H8OS3mmXF +-----END CERTIFICATE----- diff --git a/openssl/test/cert.pem b/openssl/test/cert.pem new file mode 100644 index 000000000..032fe60e9 --- /dev/null +++ b/openssl/test/cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- diff --git a/openssl/test/certs.pem b/openssl/test/certs.pem new file mode 100644 index 000000000..9d3516620 --- /dev/null +++ b/openssl/test/certs.pem @@ -0,0 +1,40 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G +ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV +eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr +7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 +aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc +klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN +XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn +BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv +Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 +AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy +OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 +mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 +GA== +-----END CERTIFICATE----- diff --git a/openssl/test/cms.p12 b/openssl/test/cms.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c4f96b6996e41e31fb19f982c59a8a0fad90462b GIT binary patch literal 1709 zcmY+DdpHvcAIEpIHn+LVn7c`1ZjY9B3L8 zjw|#n{HOuk1r&0iF%S;)#10O_bHLQUBB+o9_T5255D>7l2!AC&yfIYuKOfYAP`oAt z=CNcSqgcI!0fAtEd=6NvkuSk#s^qLM4fYzT)`$021R*6ukUX`nrU1JEH}>)EcXsPU zg-pBTda9))RCK2vRGlO@C4X=}LG)fw)ak9vetvfTIiVe5fs44L(O_&^APyl<8H2um z()M+}wK5_tWSivIzB1+y{08i}oay!IU`&+gG~RO}#Y-U1Om0q}hW={fW^6h#v{~xx z8S5N`?hw^s`;}VGNFyH&Ugsls9JM($cUxB6`iY3xFnW-fXN%$rCE*tOXX*8mD@R7- zcgH-zWng89$T`JdgjDip{Gy zpX^#5_(y<8O4lQ&nNiSzxI1mJC1b93beM~-0;!)K43}<3}rqxg-&UbyI3c!nC!e%y2r)*oJKjT9i>8QHCsB0kjp(^Fd{UX%*W9lcE>ljVg@lT`mjduj) z*)8@MFr9zVW;5%?=IMUsi}gTWf+p=5t!`I8D51Hg?Vhu8;=8wTKMMrcbgI3KS~5=Z z#YF^~eM78DG>KZ1Mpa*29`^2g;|)YdM@;Trg(Y5uS13P5!}-2a&5^;b!>tR`iScVQ z-5+}jLH(8aXe+(#{f1S@qJ`z%*dyg+?e{paXhnR4Hh>0azO7O9FTkm&+p7ERPDbysRBVeVdD-I{mnA)7t1=+ z^B=lGy?9?N+d0oaU_0b)ax1tmaZ2e|nTyw{yclv)YX9A`y16cePjcf=)i)yUoME(% zGLgM%MVXVdm{7ydL1GpkeB6)M3iB|tKDyMhIFgZG$IY6?jXG+?Rc2UaxhLInU#r0( z`AKvD%1qQJ&Pz7nYX_A{*G>K0jKWqJgPfLvaXJn&r}hH8EFdxx1|)I2uWB@|Ell>O zdJaBu!JG;>RLkA6HJiB5G<=XW+}0Cv=<`h+fwZMNeu$-QuuA{n@0PA5dOw1=Q8rjj zQ9qwYW}%}ZW|AR1^SR4Bl7Cb&ys7EO>eGyy^VpYC0O}*LfnF)&e!z;U^GQI}Dwc!K z3#b*jYdfs!L?;K}LhWA8QGeBcqaB?`mA+-n%#J zl~ZoBX$$H+!}IhG8w!9;H96`CvrrqW)rt<$?Rgi=HHTkdI@V=u z>1Yq|sZ~AR*Uk16r)P(G62i=6>5VMYZvE~a4EG!KD%im{VY)2pbMm6ya}y82?Ua3p zhv$X{mvT=8zF%oa6cofy2*T#Dwfpn+Sdzj8Zt3+bvYS*~IAJ^n5-x_R0LMRo0 z*RJi%s2aTo%o-wA4;W4_x0Z;fbmW`+!GK1S1>L6m)4Q{(F>n55&vpxtNi7g*_sSz% z>RuhWweS)?H)7~#ATZgSWP1ep$hX(>7A<5s$3U~Cj)!5a;n+ijz$zd(576gUcP4Q3 z9QMrEL}XoK>)X4QWhHyrP1Ox9Ni0b<6g3bA33Bo95k8Ii+zvawsseGB7vx zG8i;=GBq|b91ixXOq=@5P_p*Z{*#&#i#~3ZJixg5*=_$P7iAJ;+nD`Uu_yjsdvVS6 zO}84OSf1#Ko%?t(ZPTQ4euL*)v6 z{2w!J@V~k2me-m_xvs!&(Fm?xT(i7({F*E3xc@@cq3p9KYfmdxGBGnUFfI-@2sDrd zhPf;six`WDZQI)&OWtkB6}P{#&E7M4+S3PZiU#r^X=N4(1F;6|3iv?^gc%wCv#=U4 z11V%b17n^U=vh`@iLz7ean;Xlr)T>0)rr*|(A&(qcs+CQvaBLCf%Yq+OH^_~nm+2N zzURr`6Y=@W+j-lRPJa+zHR+az%5>*XtSgpU`RXn6wf->mf0yT?-O+#E`UbVG@VG2+ tW?ACCKBeQVC4U&%Q=dw1?Y^TnvwffI2CFTpMrSMo9ruMg_=E&x0|0_v@QnZf literal 0 HcmV?d00001 diff --git a/openssl/test/dhparams.pem b/openssl/test/dhparams.pem new file mode 100644 index 000000000..6e4d4c68c --- /dev/null +++ b/openssl/test/dhparams.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAh3Betv+hf5jNsOmGXU8oxuABD2B8r0yU8FVgjnCZBSVo61qJ0A2d +J6r8rYKbjtolnrZN/V4IPSzYvxurHbu8nbiFVyhOySPchI2Fu+YT/HsSe/0MH9bW +gJTNzmutWoy9VxtWLCmXnOSZHep3MZ1ZNimno6Kh2qQ7VJr0+KF8GbxUKOPv4SqK +NBwouIQXFc0pE9kGhcGKbr7TnHhyJFCRLNP1OVDQZbcoKjk1Vh+5sy7vM2VUTQmM +yOToT2LEZVAUJXNumcYMki9MIwfYCwYZbNt0ZEolyHzUEesuyHfU1eJd6+sKEjUz +5GteQIR7AehxZIS+cytu7BXO7B0owLJ2awIBAg== +-----END DH PARAMETERS----- diff --git a/openssl/test/dsa.pem b/openssl/test/dsa.pem new file mode 100644 index 000000000..9b5501848 --- /dev/null +++ b/openssl/test/dsa.pem @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42 +eabSGkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2 +ZRQur6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgS +PE43lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVW +yXnP/OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Eal +sm5nloC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiE +LnKcifgCgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8NB/BIx9EZ/dzE23ivNW8dq1A +eecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGOe+blFHwO3eAwoyRn/t3DZDHh +FjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGTveIDED1MPG+J6c8CFCJAUlEl +4nHvbC15xLXXpd46zycY +-----END DSA PRIVATE KEY----- diff --git a/openssl/test/dsa.pem.pub b/openssl/test/dsa.pem.pub new file mode 100644 index 000000000..ae298d093 --- /dev/null +++ b/openssl/test/dsa.pem.pub @@ -0,0 +1,12 @@ +-----BEGIN PUBLIC KEY----- +MIIBtzCCASsGByqGSM44BAEwggEeAoGBAKQp7+O1gok1Bp9oTuSDZpok4Q9RXQOi +LjnWORcenlR8uHr63jZ5ptIaQT1YECUguBoHzIdyQt737OjM3f35JQOn3iRvavfz +/zD/0V+Fux6n26LI6PZlFC6vpKSkpAMpycB3ogxldly91KA8L3QDqqtphRkqrsKy +OfreBsL4i9cfAhUAiBI8TjeVcPz+sZjGizhzEKAYYDECgYBIxXnpaEu9VC1YxUjf +pZIjFtmcLYSyc0gp5VbJec/86Y8naZ17MbuLVqVzCw7ZOdItu+O8Y+XLMipnMe9Y +LwSYOqx9tT6fzB78RqWybmeWgLyb0QJaltPNs12+sACP1Q9VaNwPCDuCsAYbKyHq +UZsG/k/7jMv+eKrVSIQucpyJ+AOBhQACgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8 +NB/BIx9EZ/dzE23ivNW8dq1AeecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGO +e+blFHwO3eAwoyRn/t3DZDHhFjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGT +veIDED1MPG+J6c8= +-----END PUBLIC KEY----- diff --git a/openssl/test/dsaparam.pem b/openssl/test/dsaparam.pem new file mode 100644 index 000000000..53bda543b --- /dev/null +++ b/openssl/test/dsaparam.pem @@ -0,0 +1,9 @@ +-----BEGIN DSA PARAMETERS----- +MIIBHgKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42eabS +GkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2ZRQu +r6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgSPE43 +lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVWyXnP +/OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Ealsm5n +loC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiELnKc +ifg= +-----END DSA PARAMETERS----- diff --git a/openssl/test/identity.p12 b/openssl/test/identity.p12 new file mode 100644 index 0000000000000000000000000000000000000000..d16abb8c70627bd959667495e578fb6f010a7f1d GIT binary patch literal 3386 zcmY+Fc{CIb*T-kZ%-F^$D#rP(jjrM6DXq;ULSwJ0;C7#;$Z7w z9PHO$c@c@DfAsGWG#5wj^;dEO0RexD!@nm$qyUuZe?P#0P$Vmufe?7XI$4!A4gxU% zusC`o{$ASWtHZ!%6&Yr};{6u`2KLv+>Oc-hrRqJ_6t51LvyFjb*MY2v@UpI}BEGHo zvK<0`n{R9EEh2758@vOSP&dDqOy0%>n)6OY2s1K@{ZZ4dUib$1=yGu{qy4)68IXNX zkk#_0j(a5M*dt*Sb*_j1P%B2^j47C!ky#GS(OVUXx=1c`4$i|hrFN!o2AI7yk$-hcE5vQ_4v$r`H0%4V>8 z@eO82W_dR!EPHOKwd{tqnGp6|1N4%pQ^bZ&wmM^1xKK`mmp5~Z!-*jOxzzTtyjI@N znR!#3*mi1n<$H_gljnHMOm{8 zY+OW$1dI#%nC00mv=w|&H?Ds_&Q&>zV$~?as>se&LcGBkC+KuH))CEF+bqRg55Y-3 z?~vHFBT!PxQJ=a_tK7s`O43jI#enGN$Sir<+d_5iA)Nn{pocY~r%FKRo?P!z?Yz^^ltS`1rG&W|$}6 zIK1R;ZV;$x`_4!Z3O$S$y|fdG=LX_+wEsUm|gb|J|R6=$2&5w5;*9HoUf+ zLC&xB@i{S7wciFKq`HokLs&MYUDh;a#&Nq`>{RQv)JdX8iEVvb{5|aGL9i^^AOpXY z&L6LF6u+99$t7+kFys94TO$8LR-yenXgMarH6$3GlTQl|GYr#AJ*J8<*w1~fu~s1O zdhUXpvVUHaLYgm_R_B=VPu;^q1k37|S#Az*#kI@%`yAGFcpg*|9J$55Dn2i3qil7T z#{o*c=&(?Um6=WCnJ<;C^yU0Wn5+U;LCTeF5LRZG`&7h5u>K>DCz^!_kAQ+Uk_>p^ZJ-AG#sMX^}swaF9O348d8KL2>E z)<=Onr|{6URV7{c-I=%8nti`|U(Z3YP74t0c_K)3>xS6vW%e^B29#WNrqLHAUIEy{ zzB?q&G}1_h*%0C4?15@moi|7#SL*3DFn*TcNo)PGTXh0X35{``dR4uHIDDveSU-f9 z{K;uqKl-Nv+V4mA(kBrDEVii_A1b!KJS}U4Iyn5L=6`(p(ctU_de;X1DiO>4u2__k zVlWt+97!S9u=F;5c}*O*ufnS{X8;m3K*h#T0PXmn;cX%gWvELfIb5GGobB|9yhDDpE&NP`u@Gnp&0 zQZLqLDBx6TpRdU#?(psb%LU%s+uHH3^q4!9CoL-jgzIVo56|~LFj*Dya8o&rW&R9f z#MCF&8DNgw4~2m6o|%0c4_>q*LnYa8v7A*R-OG2mtCse5WW>N06;mbHTJR0ly~=vb zjkL_*lL_>a|0oF63*HEu&>67XeZie|`a^`89-;zuIMvx0wZDKHFrH{;{>A+ay$ZLY zQ&)*|(POvl>U&=z{Tg-ooGiyts!|CuF0TS^0VgtL{JJ0I`v@^G`!EHbzFi}2 zL*x~uu?J$3fnQa7=3r+w1G;jan4eqgmvr-O)nlM%Da;H8qk?wE67l%lcqMyzw_r@o02)63je6Xu1-n29!*PLHn-90_SxMGSU5yp=aUNgAPf&JU@M3Mr*>n3*Qfs4@UZdr)3<49u!j(8;{>P^eE^Osav(h>l?db zz-D`eK9#oSSADv+c=1$Wl1_5pV%p++fJluaNC@?&3cRf~mUihw;wH~1NpD-OAhEp@ zp%J>UkR&rBuE;-O(>>(RI-$%WT}_LVD?y;mD%UYD&1i4MAzBQ}1OKO=ov1 zqOb6W(VoB8*XL$(xwOFE$}X1Q4kfSMF15mhjE{%TXEK8mEZLjGl#c@Kdami3&$?8R z3X0QOt>y=BbRV!lHr4bxPL(_bvynK6$A17e7YDHh;~?gLW%S=PgfjmhZkd3fTpV}< zi36|x7lrBmq3~Tpke%T}RQEp=2IIiJs)bH-t;&|}Fh+NaTeU~I+z6U$_st%d4& z-GhEwwpii2MIE&MtZ#2+NiaN#V8qoDMFa~9WuL=dYyA0VF!^rHt`>`@lvQaI9rjF% zf>&A5%p>?lyx=A)lifEe-ZTF_&hx;HqdgC=j^D`xrXHl2F1=@bAN8)917)sJ6!*me z<7HAMfY#b&Kyj?9V{7jX0ex*Do!y1*jQ4BlZqzj@WpzG)?+b1vXK$aw@ws>CE|ZxA z5+_}aqAICBLaX0@Sx&A-B{8F6=5ieD+o4bn7mz)?DFYwS9ISfcSkc1D?^7F(MYzNFqebD~<*>|~&C#$*Y)t41%< zSUb^f@Dm)@x`dT(>NzTU>>Qbs5c=rJ4Yz`@*9~DI<0a2AHA?iN*a+E!i8J>{0~PG?gk>1>Zj*jW^JtpfIAm$MRWkXoi1Cv@Ar>b zH0;ah2{C4g3|27>74O!U!X+684ZU@I&-k@Ud2^qCUNAL{TZwyyN$G#HNDrFsP#65c zrxf~mk;jg7wV|ONPtWwMdR6?%)Ot`$mI?|@QaMOVx=?!cXeO8~Fz9+qIZ5WmPKHb7 zgofgUUSjO+ua`8j{?2gr-`{@-43inOgBoKao68B6iAOcPQPh6Q%T2XayOCFbynb>X zH$308=bjoRmehcbbLNXtZBq z0J~mAB-w(EFUlR4pRu`v?GEVIWM&zLpe{CcX2(DI&Sy^R84J751Y9rEzC(o6CO0>y z=E{ugtGsQie~J(y5De$j6$PK5iB=^dz9SE8W5!8={%vccv}UmILPt41Z;;(tc^)R{ zZ=k`tzDp0hSkCT9WhKp4h)^M!%VaxWo6p-gp4Xnu=HqXHv&7k?hh-$IK1 zzdJH=%5w>F0z3c@{)P*{8Q=$y1-Sn0@Bil#LY@oEY0E8>a&AS}wv{Gv=((Kjlgzys zg_K7MBN?F(X;wNA9|QpA+;x-8N-+3rFwTsLlk6hIQoAssV1}Dt>u@5F2fhDT>Hh%N CKSRy{ literal 0 HcmV?d00001 diff --git a/openssl/test/key.der b/openssl/test/key.der new file mode 100644 index 0000000000000000000000000000000000000000..6b6209fd1fbe809a335cf29b263d9ffd5d1b9da0 GIT binary patch literal 1193 zcmV;a1XlYnf&`@k0RRGm0RaH0^d*c$vlpXKh5jRvhtPO78%Y=cEl1Pk8{TX-{Fb={ zKk_%;zwa{=x@E=k(3-KDiZ)_T^+L$? z>Y2<1&2+gSWzNU}-9~KQ z0JJ-yvu<{Jp*<6blO9gR*Ngy5QdX+|y6O~O7<%Spk+IVh6EoY-4^hqL-IUy<--Pex zPEZtCT%h*Qtvfd8Dho9N0|5X50)hbn0HWjQgNX#C=#|Xr&A$|rAR_`nfqF|^vE_8` z2c;+Xic=e9axd|18_NU|`$ffBzVJy-gC)6avm8%*V7+ z1_t59C&GpC32iN`4t(E-NYO%S826Zkzq)RE-9;wc-Dij33EfeuV78P~IUh%vwBN$d zUuB8qY|+1c=rJpFKxztASvyT0VYFz>Ale5sRNp4S{nINLoMDnh=E1$>Sj%&We`-04 zD6-p!AX~h6p-Yy6u@-u^M}Wq};R1ny0NAAnWQ2}*Vp0Xd$s`2|+6&-Z^Jw64)*}Oe z_ZN-bl4Y`U<$d+gHhH?YTP@XHpnS=_BWd)T@pQ{zf1mZnNv|7%7taIPbaQBV@>vVq zlnF=rT5HUlPd}Js`tzJjjqL`sMzU8@_HXu73mwh=6n7FH11b$&pV_g%67N_VEdqgo z0LP_7AoFjmabS**yghHl8Mb3mflu0`YEQeF@TZ_gdtw zEc(=g$haaDlImCWw1;_$@)Tfl=wXrA&5!v9SK+2j=d}R*Us=Y3ml_81q}yMRZ0lo68qD3r%wQ}z zCh$?VD_8lNJ;)IZEa5cszT}I=-Vin!#_nK~-yQfqD9Qx}WJE1n9G8VxsXpFnHLng~ z0)c@5$3<8fBcg?ttnc3gA>8||Z7*>D~Kv+I$4zvy%An0)c@5lTMfFGT$Uqdt4*iAJD?I-!9|> zzMbamG^Li-7cR;pil@zMtqV5(6vNh9$_2EtOFf*w{_oidMMYJv9np`#NYn@sB~M&Z zz?Rudqk|Hf$ThqmY;O335u@G`JIt;LBKLY&wcpw~C?sGlQ0ondAf&n5h4F(A+hDe6@4FLfG1potr0S^E$f&mHwf&l>luU6MGn_40Ri}dwN z@vhb=Z^HB98^rxJ@#6tOl=Mn-(3yI4L%sqMDBLwcAdMQ8ond&)XdY^&MKU(RSH~_s@BghpE?S-IiLB>jW0gZG_YR$c2X>vw0s{d60bXc_hyVZp literal 0 HcmV?d00001 diff --git a/openssl/test/key.pem b/openssl/test/key.pem new file mode 100644 index 000000000..d381795d3 --- /dev/null +++ b/openssl/test/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk +3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN +DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM +x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 +H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm +wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ +JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ +n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL +Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL +Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r +YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE +I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo +YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 +yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH +RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F +hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx +qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf +0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d +0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T +mEq154s5rmqh+h+XRIf7Au0SLw== +-----END PRIVATE KEY----- diff --git a/openssl/test/key.pem.pub b/openssl/test/key.pem.pub new file mode 100644 index 000000000..2a8225696 --- /dev/null +++ b/openssl/test/key.pem.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr1bXMptaIgOL9PVL8a7W +KG/C8+IbxP018eMBQZT0SnPQmXp0Q8Aai/F+AEDE7b5sO5U7WdxU4GRYw0wqkQNF +si78KNfoj2ZMlx6NRfl4UKuzrpGTPgQxuKDYedngPpWcbmW4P3zEL2Y7b18n9NJr +atRUzH1Zh/ReRO525Xadu58aviPw1Mzgse7cKyzb03Gll9noLnYNIIpO8jL+QyrD +8qNmfacmR20U0a6XDTtmsmk7AitGETICbTT0KRf+oAP0yIHoonllPpNLUEPZQjrp +ClS/S/wKdj7gaq9TaMbHULhFMjbCV8cuPu//rUAuWp3riaznZGOVQyn3Dp2CB3ad +yQIDAQAB +-----END PUBLIC KEY----- diff --git a/openssl/test/keystore-empty-chain.p12 b/openssl/test/keystore-empty-chain.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c39930a5cb4f003f48ab94cc87f9435730540f24 GIT binary patch literal 2514 zcmY+Ec{tPy7sm%PYGy29l6{>Jnwto_x^F7^PKPZobP|CE5VLn=X=W_4eD5|T+WbPU?{wz^ zH>yNRB3)^xvxrw`6y9QzEe&Ir3xrv&)=9$}Ojm zp87&GAzImu81Q6Or6jiZBY>eoBA1%QB6d{Jv>u<1l`Cb;gsPFlEaz{~(}R~?&nn-@ zf``oK!#6k^Q(`9^iuLc2oos8z%QGJ^X{^DhauJ?wl}EB6o1v&Mt_^YYcyTgf=vJJm zOYzw5`(x0ZukQ!rnPyLhV+2AIeG;tdyecnz*875iCFW6Sd^cU=R9r@h*H0N)Ygf(B zT{~hs_tAQ? zpqnyo)W(i0oo#W8v>#H{aCl(CnniSv5GL~TgsSL>+!;~GPHcVhyxEg9HT!O3hQ#Jz zK!UCDrnL>b^@p-9j}2QYI6-PF<9Z6No+Db2n^T0^>y--ZWJ6qyHSx5N^6d3FuJCVUF?n@%oB|JI?3ZQbL*|$Ze;*FF>BxCJY-woQq6^ya!)N6N!p{3 z!p}`FRd28+K^8$xOVhFLEPed+(#WMRzZ+n^UayqqfFZmN<#=v(RdARpWpN^-x);v% zX|2z6%W-|~o5uJRyU3~uhxqS}h}x1=EDHuFy$F#x)DBNnS8Rak=hQa1vczEgV;uo^ zSuX504fh%!tBmaN>C4KVQ4k^Le9H~Zy4<|gI#2BL($kTOa}L|ePk8vCxsdT{tR3be(;s@>0W_9e_qr=&0gJjch7@p zd24}H+J)D<$vVY37Jlc;^mJwk?iu#&8V5x#Eb|$iMxciAU;hknf`l{<+zg+Ysx!SQ z^kRmxSvtV;CaARArawN8oL28z@o;wTU8uRq1f4E7lAp}q8u;!*Wt${UiZip!lK6ej zppxlTYMR=H#}LH)+%G6^Hr7gwrvsg}h5tEp|H3TePt2kl$o8!oe@SY%#wJnH#R#F)9L!J5Mgk0_ z+A>$>d{P6qA0&iEAz6Nc&ac8-BMdsViNc z08tj)MOm~O*mj`P?Ym0EGqfmP+JDX+=jO^c&>~w>S2gzeG5j>WP~>e8sp2 zni?~rZG{z0z4Ww`jr0upA9Zpk*(RmjMkjtY+yn=@WhkL~-CUicfURyv&_xO;N@y2l zW9c^7s2esbFg=+rD^iM&iACCCN{q&*M>yQ0ij9ZrgCNy+qo3NGU%M5a(9Li+<)d|CUPcXZR9SLr)CR-ZO`nPVgUY+B&=tKL3}*w9s)m zi{{pf19HH=mC%1br%b9fz;mjvhG?c{o4L`7=RTOzBpLhj5+vp9y5pHW#E1J+kK2cA z*IBTj>qeI|de>hfmXnWAvs%`Xr^`NV7`v8?UA zgketBHv*Dh9>yESCZu548vQ;#S@`kr)g`-TgTT2;(dRnyOrvts=GMt@2}07C`M4Z6 zCsol(_oTozF{<%d9croZo4Re&wF~brEk?8#RkTyy=BQ5@ZKJ`Cg~P5Cw<_%)F+F9t z7W-F)$LWOCeU)Aky!00+))0>#-*m{Vqb1qpLvDba}yh0 zTEHEbx;=aAPbHEM@_f`dRPP&LNQU&4g?6H{RVY&!jdHd z0tf&w6b1+?hDe6@4Fd-R2r=!d)&+UZtptJu$a&yr7EYiZl}%pX)s+2=UWe8d(yTAgryfPqPHtHz;;ifXGYSsJTOHe zI(!>JUNs`2U?!0HCoRn17PBy|;%NW)$%T0+U3=Lk)uHBwtQG#BiZAiFspr*Y#Gwy5 zGg42zET6*^K33jH; zvxc`zbs}$E+1Zrx^EoZ7I?_`<1WO<%uQ`!y2DW*}zQPv=DJ2aNno8b4{lR>aoG#-& zISxgK?dIbRXXCU)N6N{9YWlcnL2qC*_p8v+#EeJL8wvNwUv+Ho^C^3S+*D`!X#HK* zNT|q@IRB@1U7X8S4FxzyI3r3{gShC3{lvGvK}?kW4_2%xh@d!ppy-$^jxW!E^v@WO zU#-yV0a~)9TjWC+V@Y@d=F-Z5y9=oc)U?jDTsUgV-FrV)U{V|->seixdB?% zDJ?}s-jzNuXe+Z&Keo9AU6H^1`+}L%>*`d>yO<{mPg+Ki`CN&7am%+a2E9CGhh?@t z%)n;cRW0%gMLmykt(2+_$IH22606T=!BD&cMU`cx$HB08d7dzryn-T{V3foZ&fwkfAxTlY7JTX;!pY#?TqE zy<%dt>hj;;71!fhK2t-cHN1{mmS}OlH4QlquCHV||K1s#zRN0DN5loo%xB(NtrQ-I zK@As?EzP=W83$>T>dT32iOp(A2shg{-?K-FFcoqmT@9*IZ*}^C{Uo+kNGL5kIUKYC zn5#!5pEd&XST1fC33Ooy3gL(tpS`PKexi=nbJed=0QCYaqkEds9;Q5naavFIx<%dI IwLU>-bsH6IkN^Mx literal 0 HcmV?d00001 diff --git a/openssl/test/root-ca.key b/openssl/test/root-ca.key new file mode 100644 index 000000000..746ae2a68 --- /dev/null +++ b/openssl/test/root-ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/ +1Kzox+2GZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd +7SBXieIVeIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQ +r4XsZuQr7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdW +pGTNVZ92aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrk +gRob6eBcklDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABAoIBAGZrnd/dC2kp11uq +Sg8SHk3GMdPPjTf/lq51sVJAU4fdV2Eso0XCiCzdKDcqR6F+jiu8jHp4YO0riW8N +b1pkjohGjyOaddIaaVsZ80/OkgDz20Ird9XQ7uoEODvopA12+755BDH5PDwqHVeM +nKfPiwAK6Jz6CxGO9bq9ZNoBiSyO1uofaB4Cpp8t74XVeAuPiI/Bb6WJ8TW5K5dt +x0Jihdo46QgZR+z4PnyWIoACkhSoQmtTb9NUrpKceBcxdCrZ/kEmYpnPq/PuSw6g +6HthjYP/H9Xulz69UR5Ez6z+1pU1rKFmQ46qK7X3zVHg233MlGekMzxdmShEjzCP +BMGYpQECgYEA5tqTZsUJwx3HDhkaZ/XOtaQqwOnZm9wPwTjGbV1t4+NUJzsl5gjP +ho+I8ZSGZ6MnNSh+ClpYhUHYBq0rTuAAYL2arcMOuOs1GrMmiZJbXm8zq8M7gYr5 +V99H/7akSx66WV/agPkLIvh/BWxlWgQcoVAIzZibbLUxr7Ye50pCLfECgYEAwDLn +mFz0mFMvGtaSp8RnTDTFCz9czCeDt0GujCxG1epdvtuxlg/S1QH+mGzA/AHkiu7z +uzCwGKWozNTdRkqVwYoJTB+AYHseSkuGP+a1zr39w+xBW/vESb2oP95GIwprXcG2 +b/qdeQVzuLQhYoqWI2u8CBwlHFfpQO4Bp2ea+ocCgYEAurIgLSfCqlpFpiAlG9hN +8NYwgU1d4E+LKj+JMd8yRO+PGh8amjub4X3pST5NqDjpN3Nk42iHWFWUqGmZsbM0 +ewg7tLUgDeqiStKBoxaK8AdMqWc9k5lZ53e6mZISsnHKUQdVBaLjH8gJqdAs8yyK +HudEB0mYwMSUxz6pJXIHrXECgYEAhJkaCpXm8chB8UQj/baUhZDKeI4IWZjRWHbq +Ey7g1+hPMMOk6yCTlf1ARqyRH8u2ftuIL5bRhs+Te21IE5yVYOb4rxn0mZuXNC6S +ujdTKwUMtESkeu9hZnaAQz/4J2ii1hY05WCDj+DhC4bKmY9/MYS8PuQb/kfwVqld +Xr8tvrUCgYEAmslHocXBUFXyRDkEOx/aKo+t9fPBr95PBZzFUt9ejrTP4PXsLa46 +3/PNOCGdrQxh5qHHcvLwR4bPL++Dj+qMUTJXANrArKPDpE2WqH6pqWIC6yaZvzUk +17QbpXR6bHcdJV045pWpw40UCStTocVynY1lBfOw8VqxBIBlpVBBzew= +-----END RSA PRIVATE KEY----- diff --git a/openssl/test/root-ca.pem b/openssl/test/root-ca.pem new file mode 100644 index 000000000..4ec2f5388 --- /dev/null +++ b/openssl/test/root-ca.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G +ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV +eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr +7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 +aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc +klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN +XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn +BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv +Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 +AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy +OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 +mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 +GA== +-----END CERTIFICATE----- diff --git a/openssl/test/rsa-encrypted.pem b/openssl/test/rsa-encrypted.pem new file mode 100644 index 000000000..a62499972 --- /dev/null +++ b/openssl/test/rsa-encrypted.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,E2F16153E2BA3D617285A68C896BA6AF + +vO9SnhtGjGe8pG1pN//vsONnvJr+DjU+lFCiSqGMPT7tezDnbehLfS+9kus2HV7r +HmI14JvVG9O7NpF7zMyBRlHYdWcCCWED9Yar0NsWN9419e5pMe/bqIXAzAiJbtT4 +OB9U5XF3m+349zjN1dVXPPLGRmMC1pcHAlofeb5nIUFTvUi5xcsbe1itGjgkkvHb +Bt8NioHTBun8kKrlsFQOuB55ylBU/eWG8DQBtvFOmQ7iWp0RnGQfh8k5e5rcZNpQ +fD9ygc7UVISl0xTrIG4IH15g34H+nrBauKtIPOpNPuXQPOMHCZv3XH8wnhrWHHwT +ZFnQBdXbSpQtMsRh0phG2G+VIlyCgSn4+CxjCJ+TgFtsoK/tU0unmRYc59QnTxxb +qkHYsPs3E0NApQAgH1ENEGl1M+FGLYQH7gftjc3ophBTeRA17sRmD7Y4QBInggsq +Gv6tImPVBdekAjz/Ls/EyMwjAvvrL5eAokqrIsAarGo+zmbJKHzknw2KUz2En0+k +YYaxB4oy9u7bzuQlvio6xYHJEb4K197bby4Dldmqv7YCCJBJwhOBAInMD687viKv +vcUwL8YuS6cW5E8MbvEENlY4+lvKKj3M8Bnyb79cYIPQe92EuCwXU9DZXPRMLwwM +oFEJpF5E/PmNJzu+B52ahHtDrh83WSx71fWqjdTqwkPZhAYo3ztsfFkb/UqUcq8u +rBSebeUjZh0XZ9B04eshZQ5vJUcXGtYIe/77beV3Pv89/fw+zTZjpiP9Q3sZALzf +Qt0YGp0/6qBuqR1tcqdu65AS2hun7yFw7uRavqYKvww4axRiz2do+xWmZFuoCAwD +EWktaUujltpvAc1lo7lg4C6nByefJB9Xqk22N/vpqOsWr1NbAntT42Qj/HF9BVWR +osvN3yMnKYWYe6oSTVnNBDM5obWAIHd3I9gcxTOTb1KsEwt2RrDs5EpB5ptS3Fjo +JfBRhNZQ3cXttrIIhsHgDn9BDNg865/xpIgktKj0gEd60Abx0PqkAIm6IZTh4Efg +7uZwfzxB+saOcddbrW2gNdzVZMC0s2Ye3sqHhtLbAJ3BlXYTxE4CAvTg54Ny+5hF +IjvjlOKgXceSG1cSfk21/wyp9RY3Ft0AEYvvp0kZScWZaoA2aSFDUrchXVhgrEbn +lJ7UptjefwRFIreAlwbKSbIDDNWnyzvIWyHfQ2aYqgnb7W7XqNPSgH9cALCfzirI +dlRHjha0bMUtrjPCC/YfMXzJBVniy0gG6Pd5uC7vz/Awn6/6HRQVNaTQASphPBQ7 +bJuz+JTfzI9OUVCMRMdnb6b35U4P9tibFmnPvzTIPe+3WUmf8aRsLS3NN3G1Webd +PMYVZpMycPaAI0Ht87axhsOzlxCWHYWjdHa+WoNNc1J90TxLCmAHquh5BDaWvjMK +0DySftJZjV7Tf1p2KosmU83LRl39B5NHMbZb1xOEZl9IWwhT/PVKTVZ25xdxWLfb +hF4l8rfvKehIp5r4t8zW1bvI2Hl6vrUvmcUVWt3BfKjxlgwRVD0vvwonMt1INesF +204vUBeXbDsUUicLwOyUgaFvJ3XU3dOyvL9MhOgM5OgoFRRhG+4AS8a5JCD8iLtq +-----END RSA PRIVATE KEY----- diff --git a/openssl/test/rsa.pem b/openssl/test/rsa.pem new file mode 100644 index 000000000..d8185fed6 --- /dev/null +++ b/openssl/test/rsa.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd/wWJcyQoTbji9k0 +l8W26mPddxHmfHQp+Vaw+4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL+yRT+SFd2lZS+pC +gNMsD1W/YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb/7OMg0LOL+bSf63kpaSHSX +ndS5z5rexMdbBYUsLA9e+KXBdQOS+UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uD +Zlxvb3qCo5ZwKh9kG4LT6/I5IhlJH7aGhyxXFvUK+DWNmoudF8NAco9/h9iaGNj8 +q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQIDAQABAoIBABKucaRpzQorw35S +bEUAVx8dYXUdZOlJcHtiWQ+dC6V8ljxAHj/PLyzTveyI5QO/xkObCyjIL303l2cf +UhPu2MFaJdjVzqACXuOrLot/eSFvxjvqVidTtAZExqFRJ9mylUVAoLvhowVWmC1O +n95fZCXxTUtxNEG1Xcc7m0rtzJKs45J+N/V9DP1edYH6USyPSWGp6wuA+KgHRnKK +Vf9GRx80JQY7nVNkL17eHoTWEwga+lwi0FEoW9Y7lDtWXYmKBWhUE+U8PGxlJf8f +40493HDw1WRQ/aSLoS4QTp3rn7gYgeHEvfJdkkf0UMhlknlo53M09EFPdadQ4TlU +bjqKc50CgYEA4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH/5IB3jw3bcxGn6QLvnE +tfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw/Py5PJdTJNPY8cQn7ouZ2KKDcmnPG +BY5t7yLc1QlQ5xHdwW1VhvKn+nXqhJTBgIPgtldC+KDV5z+y2XDwGUcCgYEAuQPE +fgmVtjL0Uyyx88GZFF1fOunH3+7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYs +p1ZSe7zFYHj7C6ul7TjeLQeZD/YwD66t62wDmpe/HlB+TnBA+njbglfIsRLtXlnD +zQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdcCgYAHAp9XcCSrn8wVkMVkKdb7 +DOX4IKjzdahm+ctDAJN4O/y7OW5FKebvUjdAIt2GuoTZ71iTG+7F0F+lP88jtjP4 +U4qe7VHoewl4MKOfXZKTe+YCS1XbNvfgwJ3Ltyl1OH9hWvu2yza7q+d5PCsDzqtm +27kxuvULVeya+TEdAB1ijQKBgQCH/3r6YrVH/uCWGy6bzV1nGNOdjKc9tmkfOJmN +54dxdixdpozCQ6U4OxZrsj3FcOhHBsqAHvX2uuYjagqvo3cOj1TRqNocX40omfCC +Mx3bD1yPPf/6TI2XECva/ggqEY2mYzmIiA5LVVmc5nrybr+lssFKneeyxN2Wq93S +0iJMdQKBgCGHewxzoa1r8ZMD0LETNrToK423K377UCYqXfg5XMclbrjPbEC3YI1Z +NqMtuhdBJqUnBi6tjKMF+34Xf0CUN8ncuXGO2CAYvO8PdyCixHX52ybaDjy1FtCE +6yUXjoKNXKvUm7MWGsAYH6f4IegOetN5NvmUMFStCSkh7ixZLkN1 +-----END RSA PRIVATE KEY----- diff --git a/openssl/test/rsa.pem.pub b/openssl/test/rsa.pem.pub new file mode 100644 index 000000000..093f2ba12 --- /dev/null +++ b/openssl/test/rsa.pem.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAofgWCuLjybRlzo0tZWJj +NiuSfb4p4fAkd/wWJcyQoTbji9k0l8W26mPddxHmfHQp+Vaw+4qPCJrcS2mJPMEz +P1Pt0Bm4d4QlL+yRT+SFd2lZS+pCgNMsD1W/YpRPEwOWvG6b32690r2jZ47soMZo +9wGzjb/7OMg0LOL+bSf63kpaSHSXndS5z5rexMdbBYUsLA9e+KXBdQOS+UTo7WTB +EMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6/I5IhlJH7aGhyxX +FvUK+DWNmoudF8NAco9/h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXp +oQIDAQAB +-----END PUBLIC KEY----- diff --git a/percent-encoding/.cargo-checksum.json b/percent-encoding/.cargo-checksum.json new file mode 100644 index 000000000..77dd33396 --- /dev/null +++ b/percent-encoding/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"} \ No newline at end of file diff --git a/percent-encoding/Cargo.toml b/percent-encoding/Cargo.toml new file mode 100644 index 000000000..bae0da0da --- /dev/null +++ b/percent-encoding/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "percent-encoding" +version = "1.0.1" +authors = ["The rust-url developers"] +description = "Percent encoding and decoding" +license = "MIT/Apache-2.0" +repository = "https://github.com/servo/rust-url/" + +[lib] +path = "lib.rs" +test = false +doctest = false diff --git a/percent-encoding/LICENSE-APACHE b/percent-encoding/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/percent-encoding/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/percent-encoding/LICENSE-MIT b/percent-encoding/LICENSE-MIT new file mode 100644 index 000000000..24de6b418 --- /dev/null +++ b/percent-encoding/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2013-2016 The rust-url developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/percent-encoding/lib.rs b/percent-encoding/lib.rs new file mode 100644 index 000000000..16d37ada6 --- /dev/null +++ b/percent-encoding/lib.rs @@ -0,0 +1,442 @@ +// Copyright 2013-2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! URLs use special chacters to indicate the parts of the request. For example, a forward slash +//! indicates a path. In order for that charcter to exist outside of a path separator, that +//! charcter would need to be encoded. +//! +//! Percent encoding replaces reserved charcters with the `%` escape charcter followed by hexidecimal +//! ASCII representaton. For non-ASCII charcters that are percent encoded, a UTF-8 byte sequence +//! becomes percent encoded. A simple example can be seen when the space literal is replaced with +//! `%20`. +//! +//! Percent encoding is further complicated by the fact that different parts of an URL have +//! different encoding requirements. In order to support the variety of encoding requirements, +//! `url::percent_encoding` includes different *encode sets*. +//! See [URL Standard](https://url.spec.whatwg.org/#percent-encoded-bytes) for details. +//! +//! This module provides some `*_ENCODE_SET` constants. +//! If a different set is required, it can be created with +//! the [`define_encode_set!`](../macro.define_encode_set!.html) macro. +//! +//! # Examples +//! +//! ``` +//! use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; +//! +//! assert_eq!(utf8_percent_encode("foo bar?", DEFAULT_ENCODE_SET).to_string(), "foo%20bar%3F"); +//! ``` + +use std::ascii::AsciiExt; +use std::borrow::Cow; +use std::fmt; +use std::slice; +use std::str; + +/// Represents a set of characters / bytes that should be percent-encoded. +/// +/// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set). +/// +/// Different characters need to be encoded in different parts of an URL. +/// For example, a literal `?` question mark in an URL’s path would indicate +/// the start of the query string. +/// A question mark meant to be part of the path therefore needs to be percent-encoded. +/// In the query string however, a question mark does not have any special meaning +/// and does not need to be percent-encoded. +/// +/// A few sets are defined in this module. +/// Use the [`define_encode_set!`](../macro.define_encode_set!.html) macro to define different ones. +pub trait EncodeSet: Clone { + /// Called with UTF-8 bytes rather than code points. + /// Should return true for all non-ASCII bytes. + fn contains(&self, byte: u8) -> bool; +} + +/// Define a new struct +/// that implements the [`EncodeSet`](percent_encoding/trait.EncodeSet.html) trait, +/// for use in [`percent_decode()`](percent_encoding/fn.percent_encode.html) +/// and related functions. +/// +/// Parameters are characters to include in the set in addition to those of the base set. +/// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set). +/// +/// Example +/// ======= +/// +/// ```rust +/// #[macro_use] extern crate percent_encoding; +/// use percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET}; +/// define_encode_set! { +/// /// This encode set is used in the URL parser for query strings. +/// pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'} +/// } +/// # fn main() { +/// assert_eq!(utf8_percent_encode("foo bar", QUERY_ENCODE_SET).collect::(), "foo%20bar"); +/// # } +/// ``` +#[macro_export] +macro_rules! define_encode_set { + ($(#[$attr: meta])* pub $name: ident = [$base_set: expr] | {$($ch: pat),*}) => { + $(#[$attr])* + #[derive(Copy, Clone, Debug)] + #[allow(non_camel_case_types)] + pub struct $name; + + impl $crate::EncodeSet for $name { + #[inline] + fn contains(&self, byte: u8) -> bool { + match byte as char { + $( + $ch => true, + )* + _ => $base_set.contains(byte) + } + } + } + } +} + +/// This encode set is used for the path of cannot-be-a-base URLs. +/// +/// All ASCII charcters less than hexidecimal 20 and greater than 7E are encoded. This includes +/// special charcters such as line feed, carriage return, NULL, etc. +#[derive(Copy, Clone, Debug)] +#[allow(non_camel_case_types)] +pub struct SIMPLE_ENCODE_SET; + +impl EncodeSet for SIMPLE_ENCODE_SET { + #[inline] + fn contains(&self, byte: u8) -> bool { + byte < 0x20 || byte > 0x7E + } +} + +define_encode_set! { + /// This encode set is used in the URL parser for query strings. + /// + /// Aside from special chacters defined in the [`SIMPLE_ENCODE_SET`](struct.SIMPLE_ENCODE_SET.html), + /// space, double quote ("), hash (#), and inequality qualifiers (<), (>) are encoded. + pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'} +} + +define_encode_set! { + /// This encode set is used for path components. + /// + /// Aside from special chacters defined in the [`SIMPLE_ENCODE_SET`](struct.SIMPLE_ENCODE_SET.html), + /// space, double quote ("), hash (#), inequality qualifiers (<), (>), backtick (`), + /// question mark (?), and curly brackets ({), (}) are encoded. + pub DEFAULT_ENCODE_SET = [QUERY_ENCODE_SET] | {'`', '?', '{', '}'} +} + +define_encode_set! { + /// This encode set is used for on '/'-separated path segment + /// + /// Aside from special chacters defined in the [`SIMPLE_ENCODE_SET`](struct.SIMPLE_ENCODE_SET.html), + /// space, double quote ("), hash (#), inequality qualifiers (<), (>), backtick (`), + /// question mark (?), and curly brackets ({), (}), percent sign (%), forward slash (/) are + /// encoded. + pub PATH_SEGMENT_ENCODE_SET = [DEFAULT_ENCODE_SET] | {'%', '/'} +} + +define_encode_set! { + /// This encode set is used for username and password. + /// + /// Aside from special chacters defined in the [`SIMPLE_ENCODE_SET`](struct.SIMPLE_ENCODE_SET.html), + /// space, double quote ("), hash (#), inequality qualifiers (<), (>), backtick (`), + /// question mark (?), and curly brackets ({), (}), forward slash (/), colon (:), semi-colon (;), + /// equality (=), at (@), backslash (\\), square brackets ([), (]), caret (\^), and pipe (|) are + /// encoded. + pub USERINFO_ENCODE_SET = [DEFAULT_ENCODE_SET] | { + '/', ':', ';', '=', '@', '[', '\\', ']', '^', '|' + } +} + +/// Return the percent-encoding of the given bytes. +/// +/// This is unconditional, unlike `percent_encode()` which uses an encode set. +/// +/// # Examples +/// +/// ``` +/// use url::percent_encoding::percent_encode_byte; +/// +/// assert_eq!("foo bar".bytes().map(percent_encode_byte).collect::(), +/// "%66%6F%6F%20%62%61%72"); +/// ``` +pub fn percent_encode_byte(byte: u8) -> &'static str { + let index = usize::from(byte) * 3; + &"\ + %00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F\ + %10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F\ + %20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F\ + %30%31%32%33%34%35%36%37%38%39%3A%3B%3C%3D%3E%3F\ + %40%41%42%43%44%45%46%47%48%49%4A%4B%4C%4D%4E%4F\ + %50%51%52%53%54%55%56%57%58%59%5A%5B%5C%5D%5E%5F\ + %60%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F\ + %70%71%72%73%74%75%76%77%78%79%7A%7B%7C%7D%7E%7F\ + %80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F\ + %90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F\ + %A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF\ + %B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF\ + %C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF\ + %D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF\ + %E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF\ + %F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF\ + "[index..index + 3] +} + +/// Percent-encode the given bytes with the given encode set. +/// +/// The encode set define which bytes (in addition to non-ASCII and controls) +/// need to be percent-encoded. +/// The choice of this set depends on context. +/// For example, `?` needs to be encoded in an URL path but not in a query string. +/// +/// The return value is an iterator of `&str` slices (so it has a `.collect::()` method) +/// that also implements `Display` and `Into>`. +/// The latter returns `Cow::Borrowed` when none of the bytes in `input` +/// are in the given encode set. +/// +/// # Examples +/// +/// ``` +/// use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET}; +/// +/// assert_eq!(percent_encode(b"foo bar?", DEFAULT_ENCODE_SET).to_string(), "foo%20bar%3F"); +/// ``` +#[inline] +pub fn percent_encode(input: &[u8], encode_set: E) -> PercentEncode { + PercentEncode { + bytes: input, + encode_set: encode_set, + } +} + +/// Percent-encode the UTF-8 encoding of the given string. +/// +/// See `percent_encode()` for how to use the return value. +/// +/// # Examples +/// +/// ``` +/// use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; +/// +/// assert_eq!(utf8_percent_encode("foo bar?", DEFAULT_ENCODE_SET).to_string(), "foo%20bar%3F"); +/// ``` +#[inline] +pub fn utf8_percent_encode(input: &str, encode_set: E) -> PercentEncode { + percent_encode(input.as_bytes(), encode_set) +} + +/// The return type of `percent_encode()` and `utf8_percent_encode()`. +#[derive(Clone, Debug)] +pub struct PercentEncode<'a, E: EncodeSet> { + bytes: &'a [u8], + encode_set: E, +} + +impl<'a, E: EncodeSet> Iterator for PercentEncode<'a, E> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + if let Some((&first_byte, remaining)) = self.bytes.split_first() { + if self.encode_set.contains(first_byte) { + self.bytes = remaining; + Some(percent_encode_byte(first_byte)) + } else { + assert!(first_byte.is_ascii()); + for (i, &byte) in remaining.iter().enumerate() { + if self.encode_set.contains(byte) { + // 1 for first_byte + i for previous iterations of this loop + let (unchanged_slice, remaining) = self.bytes.split_at(1 + i); + self.bytes = remaining; + return Some(unsafe { str::from_utf8_unchecked(unchanged_slice) }) + } else { + assert!(byte.is_ascii()); + } + } + let unchanged_slice = self.bytes; + self.bytes = &[][..]; + Some(unsafe { str::from_utf8_unchecked(unchanged_slice) }) + } + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.bytes.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.bytes.len())) + } + } +} + +impl<'a, E: EncodeSet> fmt::Display for PercentEncode<'a, E> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + for c in (*self).clone() { + formatter.write_str(c)? + } + Ok(()) + } +} + +impl<'a, E: EncodeSet> From> for Cow<'a, str> { + fn from(mut iter: PercentEncode<'a, E>) -> Self { + match iter.next() { + None => "".into(), + Some(first) => { + match iter.next() { + None => first.into(), + Some(second) => { + let mut string = first.to_owned(); + string.push_str(second); + string.extend(iter); + string.into() + } + } + } + } + } +} + +/// Percent-decode the given bytes. +/// +/// The return value is an iterator of decoded `u8` bytes +/// that also implements `Into>` +/// (which returns `Cow::Borrowed` when `input` contains no percent-encoded sequence) +/// and has `decode_utf8()` and `decode_utf8_lossy()` methods. +/// +/// # Examples +/// +/// ``` +/// use url::percent_encoding::percent_decode; +/// +/// assert_eq!(percent_decode(b"foo%20bar%3F").decode_utf8().unwrap(), "foo bar?"); +/// ``` +#[inline] +pub fn percent_decode(input: &[u8]) -> PercentDecode { + PercentDecode { + bytes: input.iter() + } +} + +/// The return type of `percent_decode()`. +#[derive(Clone, Debug)] +pub struct PercentDecode<'a> { + bytes: slice::Iter<'a, u8>, +} + +fn after_percent_sign(iter: &mut slice::Iter) -> Option { + let initial_iter = iter.clone(); + let h = iter.next().and_then(|&b| (b as char).to_digit(16)); + let l = iter.next().and_then(|&b| (b as char).to_digit(16)); + if let (Some(h), Some(l)) = (h, l) { + Some(h as u8 * 0x10 + l as u8) + } else { + *iter = initial_iter; + None + } +} + +impl<'a> Iterator for PercentDecode<'a> { + type Item = u8; + + fn next(&mut self) -> Option { + self.bytes.next().map(|&byte| { + if byte == b'%' { + after_percent_sign(&mut self.bytes).unwrap_or(byte) + } else { + byte + } + }) + } + + fn size_hint(&self) -> (usize, Option) { + let bytes = self.bytes.len(); + (bytes / 3, Some(bytes)) + } +} + +impl<'a> From> for Cow<'a, [u8]> { + fn from(iter: PercentDecode<'a>) -> Self { + match iter.if_any() { + Some(vec) => Cow::Owned(vec), + None => Cow::Borrowed(iter.bytes.as_slice()), + } + } +} + +impl<'a> PercentDecode<'a> { + /// If the percent-decoding is different from the input, return it as a new bytes vector. + pub fn if_any(&self) -> Option> { + let mut bytes_iter = self.bytes.clone(); + while bytes_iter.any(|&b| b == b'%') { + if let Some(decoded_byte) = after_percent_sign(&mut bytes_iter) { + let initial_bytes = self.bytes.as_slice(); + let unchanged_bytes_len = initial_bytes.len() - bytes_iter.len() - 3; + let mut decoded = initial_bytes[..unchanged_bytes_len].to_owned(); + decoded.push(decoded_byte); + decoded.extend(PercentDecode { + bytes: bytes_iter + }); + return Some(decoded) + } + } + // Nothing to decode + None + } + + /// Decode the result of percent-decoding as UTF-8. + /// + /// This is return `Err` when the percent-decoded bytes are not well-formed in UTF-8. + pub fn decode_utf8(self) -> Result, str::Utf8Error> { + match self.clone().into() { + Cow::Borrowed(bytes) => { + match str::from_utf8(bytes) { + Ok(s) => Ok(s.into()), + Err(e) => Err(e), + } + } + Cow::Owned(bytes) => { + match String::from_utf8(bytes) { + Ok(s) => Ok(s.into()), + Err(e) => Err(e.utf8_error()), + } + } + } + } + + /// Decode the result of percent-decoding as UTF-8, lossily. + /// + /// Invalid UTF-8 percent-encoded byte sequences will be replaced � U+FFFD, + /// the replacement character. + pub fn decode_utf8_lossy(self) -> Cow<'a, str> { + decode_utf8_lossy(self.clone().into()) + } +} + +fn decode_utf8_lossy(input: Cow<[u8]>) -> Cow { + match input { + Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes), + Cow::Owned(bytes) => { + let raw_utf8: *const [u8]; + match String::from_utf8_lossy(&bytes) { + Cow::Borrowed(utf8) => raw_utf8 = utf8.as_bytes(), + Cow::Owned(s) => return s.into(), + } + // from_utf8_lossy returned a borrow of `bytes` unchanged. + debug_assert!(raw_utf8 == &*bytes as *const [u8]); + // Reuse the existing `Vec` allocation. + unsafe { String::from_utf8_unchecked(bytes) }.into() + } + } +} + + diff --git a/pkg-config/.cargo-checksum.json b/pkg-config/.cargo-checksum.json new file mode 100644 index 000000000..cea5d5b0d --- /dev/null +++ b/pkg-config/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"} \ No newline at end of file diff --git a/pkg-config/.pc/.quilt_patches b/pkg-config/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/pkg-config/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/pkg-config/.pc/.quilt_series b/pkg-config/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/pkg-config/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/pkg-config/.pc/.version b/pkg-config/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/pkg-config/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/pkg-config/.pc/applied-patches b/pkg-config/.pc/applied-patches new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/pkg-config/.pc/applied-patches @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/pkg-config/.pc/no-special-snowflake-env.patch/.timestamp b/pkg-config/.pc/no-special-snowflake-env.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/pkg-config/.pc/no-special-snowflake-env.patch/src/lib.rs b/pkg-config/.pc/no-special-snowflake-env.patch/src/lib.rs new file mode 100644 index 000000000..88dd31008 --- /dev/null +++ b/pkg-config/.pc/no-special-snowflake-env.patch/src/lib.rs @@ -0,0 +1,630 @@ +//! A build dependency for Cargo libraries to find system artifacts through the +//! `pkg-config` utility. +//! +//! This library will shell out to `pkg-config` as part of build scripts and +//! probe the system to determine how to link to a specified library. The +//! `Config` structure serves as a method of configuring how `pkg-config` is +//! invoked in a builder style. +//! +//! A number of environment variables are available to globally configure how +//! this crate will invoke `pkg-config`: +//! +//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config` +//! will automatically be disabled for all cross compiles. +//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when +//! probing for the library named `foo`. +//! +//! There are also a number of environment variables which can configure how a +//! library is linked to (dynamically vs statically). These variables control +//! whether the `--static` flag is passed. Note that this behavior can be +//! overridden by configuring explicitly on `Config`. The variables are checked +//! in the following order: +//! +//! * `FOO_STATIC` - pass `--static` for the library `foo` +//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo` +//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries +//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries +//! +//! After running `pkg-config` all appropriate Cargo metadata will be printed on +//! stdout if the search was successful. +//! +//! # Example +//! +//! Find the system library named `foo`, with minimum version 1.2.3: +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::Config::new().atleast_version("1.2.3").probe("foo").unwrap(); +//! } +//! ``` +//! +//! Find the system library named `foo`, with no version requirement (not +//! recommended): +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::probe_library("foo").unwrap(); +//! } +//! ``` +//! +//! Configure how library `foo` is linked to. +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::Config::new().atleast_version("1.2.3").statik(true).probe("foo").unwrap(); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/pkg-config/0.3")] + +#[allow(unused_imports)] // Required for Rust <1.23 +use std::ascii::AsciiExt; +use std::collections::HashMap; +use std::env; +use std::error; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::io; +use std::path::{PathBuf, Path}; +use std::process::{Command, Output}; +use std::str; + +pub fn target_supported() -> bool { + let target = env::var("TARGET").unwrap_or_else(|_| String::new()); + let host = env::var("HOST").unwrap_or_else(|_| String::new()); + + // Only use pkg-config in host == target situations by default (allowing an + // override). + (host == target || env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()) +} + +#[derive(Clone, Default)] +pub struct Config { + statik: Option, + atleast_version: Option, + extra_args: Vec, + cargo_metadata: bool, + env_metadata: bool, + print_system_libs: bool, +} + +#[derive(Debug)] +pub struct Library { + pub libs: Vec, + pub link_paths: Vec, + pub frameworks: Vec, + pub framework_paths: Vec, + pub include_paths: Vec, + pub defines: HashMap>, + pub version: String, + _priv: (), +} + +/// Represents all reasons `pkg-config` might not succeed or be run at all. +pub enum Error { + /// Aborted because of `*_NO_PKG_CONFIG` environment variable. + /// + /// Contains the name of the responsible environment variable. + EnvNoPkgConfig(String), + + /// Cross compilation detected. + /// + /// Override with `PKG_CONFIG_ALLOW_CROSS=1`. + CrossCompilation, + + /// Failed to run `pkg-config`. + /// + /// Contains the command and the cause. + Command { command: String, cause: io::Error }, + + /// `pkg-config` did not exit sucessfully. + /// + /// Contains the command and output. + Failure { command: String, output: Output }, + + #[doc(hidden)] + // please don't match on this, we're likely to add more variants over time + __Nonexhaustive, +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::EnvNoPkgConfig(_) => "pkg-config requested to be aborted", + Error::CrossCompilation => { + "pkg-config doesn't handle cross compilation. \ + Use PKG_CONFIG_ALLOW_CROSS=1 to override" + } + Error::Command { .. } => "failed to run pkg-config", + Error::Failure { .. } => "pkg-config did not exit sucessfully", + Error::__Nonexhaustive => panic!(), + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Command { ref cause, .. } => Some(cause), + _ => None, + } + } +} + +// Workaround for temporary lack of impl Debug for Output in stable std +struct OutputDebugger<'a>(&'a Output); + +// Lifted from 1.7 std +impl<'a> fmt::Debug for OutputDebugger<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let stdout_utf8 = str::from_utf8(&self.0.stdout); + let stdout_debug: &fmt::Debug = match stdout_utf8 { + Ok(ref str) => str, + Err(_) => &self.0.stdout + }; + + let stderr_utf8 = str::from_utf8(&self.0.stderr); + let stderr_debug: &fmt::Debug = match stderr_utf8 { + Ok(ref str) => str, + Err(_) => &self.0.stderr + }; + + fmt.debug_struct("Output") + .field("status", &self.0.status) + .field("stdout", stdout_debug) + .field("stderr", stderr_debug) + .finish() + } +} + +// Workaround for temporary lack of impl Debug for Output in stable std, continued +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::EnvNoPkgConfig(ref name) => { + f.debug_tuple("EnvNoPkgConfig") + .field(name) + .finish() + } + Error::CrossCompilation => write!(f, "CrossCompilation"), + Error::Command { ref command, ref cause } => { + f.debug_struct("Command") + .field("command", command) + .field("cause", cause) + .finish() + } + Error::Failure { ref command, ref output } => { + f.debug_struct("Failure") + .field("command", command) + .field("output", &OutputDebugger(output)) + .finish() + } + Error::__Nonexhaustive => panic!(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::EnvNoPkgConfig(ref name) => { + write!(f, "Aborted because {} is set", name) + } + Error::CrossCompilation => { + write!(f, "Cross compilation detected. \ + Use PKG_CONFIG_ALLOW_CROSS=1 to override") + } + Error::Command { ref command, ref cause } => { + write!(f, "Failed to run `{}`: {}", command, cause) + } + Error::Failure { ref command, ref output } => { + let stdout = str::from_utf8(&output.stdout).unwrap(); + let stderr = str::from_utf8(&output.stderr).unwrap(); + write!(f, "`{}` did not exit successfully: {}", command, output.status)?; + if !stdout.is_empty() { + write!(f, "\n--- stdout\n{}", stdout)?; + } + if !stderr.is_empty() { + write!(f, "\n--- stderr\n{}", stderr)?; + } + Ok(()) + } + Error::__Nonexhaustive => panic!(), + } + } +} + +/// Deprecated in favor of the probe_library function +#[doc(hidden)] +pub fn find_library(name: &str) -> Result { + probe_library(name).map_err(|e| e.to_string()) +} + +/// Simple shortcut for using all default options for finding a library. +pub fn probe_library(name: &str) -> Result { + Config::new().probe(name) +} + +/// Run `pkg-config` to get the value of a variable from a package using +/// --variable. +pub fn get_variable(package: &str, variable: &str) -> Result { + let arg = format!("--variable={}", variable); + let cfg = Config::new(); + let out = run(cfg.command(package, &[&arg]))?; + Ok(str::from_utf8(&out).unwrap().trim_right().to_owned()) +} + +impl Config { + /// Creates a new set of configuration options which are all initially set + /// to "blank". + pub fn new() -> Config { + Config { + statik: None, + atleast_version: None, + extra_args: vec![], + print_system_libs: true, + cargo_metadata: true, + env_metadata: false, + } + } + + /// Indicate whether the `--static` flag should be passed. + /// + /// This will override the inference from environment variables described in + /// the crate documentation. + pub fn statik(&mut self, statik: bool) -> &mut Config { + self.statik = Some(statik); + self + } + + /// Indicate that the library must be at least version `vers`. + pub fn atleast_version(&mut self, vers: &str) -> &mut Config { + self.atleast_version = Some(vers.to_string()); + self + } + + /// Add an argument to pass to pkg-config. + /// + /// It's placed after all of the arguments generated by this library. + pub fn arg>(&mut self, arg: S) -> &mut Config { + self.extra_args.push(arg.as_ref().to_os_string()); + self + } + + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Config { + self.cargo_metadata = cargo_metadata; + self + } + + /// Define whether metadata should be emitted for cargo allowing to + /// automatically rebuild when environment variables change. Defaults to + /// `false`. + pub fn env_metadata(&mut self, env_metadata: bool) -> &mut Config { + self.env_metadata = env_metadata; + self + } + + /// Enable or disable the `PKG_CONFIG_ALLOW_SYSTEM_LIBS` environment + /// variable. + /// + /// This env var is enabled by default. + pub fn print_system_libs(&mut self, print: bool) -> &mut Config { + self.print_system_libs = print; + self + } + + /// Deprecated in favor fo the `probe` function + #[doc(hidden)] + pub fn find(&self, name: &str) -> Result { + self.probe(name).map_err(|e| e.to_string()) + } + + /// Run `pkg-config` to find the library `name`. + /// + /// This will use all configuration previously set to specify how + /// `pkg-config` is run. + pub fn probe(&self, name: &str) -> Result { + let abort_var_name = format!("{}_NO_PKG_CONFIG", envify(name)); + if self.env_var_os(&abort_var_name).is_some() { + return Err(Error::EnvNoPkgConfig(abort_var_name)) + } else if !target_supported() { + return Err(Error::CrossCompilation); + } + + let mut library = Library::new(); + + let output = run(self.command(name, &["--libs", "--cflags"]))?; + library.parse_libs_cflags(name, &output, self); + + let output = run(self.command(name, &["--modversion"]))?; + library.parse_modversion(str::from_utf8(&output).unwrap()); + + Ok(library) + } + + /// Deprecated in favor of the top level `get_variable` function + #[doc(hidden)] + pub fn get_variable(package: &str, variable: &str) -> Result { + get_variable(package, variable).map_err(|e| e.to_string()) + } + + fn targetted_env_var(&self, var_base: &str) -> Result { + if let Ok(target) = env::var("TARGET") { + let host = env::var("HOST")?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + + self.env_var(&format!("{}_{}", var_base, target)) + .or_else(|_| self.env_var(&format!("{}_{}", var_base, target_u))) + .or_else(|_| self.env_var(&format!("{}_{}", kind, var_base))) + .or_else(|_| self.env_var(var_base)) + } else { + self.env_var(var_base) + } + } + + fn env_var(&self, name: &str) -> Result { + if self.env_metadata { + println!("cargo:rerun-if-env-changed={}", name); + } + env::var(name) + } + + fn env_var_os(&self, name: &str) -> Option { + if self.env_metadata { + println!("cargo:rerun-if-env-changed={}", name); + } + env::var_os(name) + } + + fn is_static(&self, name: &str) -> bool { + self.statik.unwrap_or_else(|| self.infer_static(name)) + } + + fn command(&self, name: &str, args: &[&str]) -> Command { + let exe = self.env_var("PKG_CONFIG").unwrap_or_else(|_| String::from("pkg-config")); + let mut cmd = Command::new(exe); + if self.is_static(name) { + cmd.arg("--static"); + } + cmd.args(args) + .args(&self.extra_args); + + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_PATH") { + cmd.env("PKG_CONFIG_PATH", value); + } + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_LIBDIR") { + cmd.env("PKG_CONFIG_LIBDIR", value); + } + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_SYSROOT_DIR") { + cmd.env("PKG_CONFIG_SYSROOT_DIR", value); + } + if self.print_system_libs { + cmd.env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1"); + } + if let Some(ref version) = self.atleast_version { + cmd.arg(&format!("{} >= {}", name, version)); + } else { + cmd.arg(name); + } + cmd + } + + fn print_metadata(&self, s: &str) { + if self.cargo_metadata { + println!("cargo:{}", s); + } + } + + fn infer_static(&self, name: &str) -> bool { + let name = envify(name); + if self.env_var_os(&format!("{}_STATIC", name)).is_some() { + true + } else if self.env_var_os(&format!("{}_DYNAMIC", name)).is_some() { + false + } else if self.env_var_os("PKG_CONFIG_ALL_STATIC").is_some() { + true + } else if self.env_var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() { + false + } else { + false + } + } +} + +impl Library { + fn new() -> Library { + Library { + libs: Vec::new(), + link_paths: Vec::new(), + include_paths: Vec::new(), + frameworks: Vec::new(), + framework_paths: Vec::new(), + defines: HashMap::new(), + version: String::new(), + _priv: (), + } + } + + fn parse_libs_cflags(&mut self, name: &str, output: &[u8], config: &Config) { + let mut is_msvc = false; + if let Ok(target) = env::var("TARGET") { + if target.contains("msvc") { + is_msvc = true; + } + } + + let words = split_flags(output); + let parts = words.iter() + .filter(|l| l.len() > 2) + .map(|arg| (&arg[0..2], &arg[2..])) + .collect::>(); + + let mut dirs = Vec::new(); + let statik = config.is_static(name); + for &(flag, val) in &parts { + match flag { + "-L" => { + let meta = format!("rustc-link-search=native={}", val); + config.print_metadata(&meta); + dirs.push(PathBuf::from(val)); + self.link_paths.push(PathBuf::from(val)); + } + "-F" => { + let meta = format!("rustc-link-search=framework={}", val); + config.print_metadata(&meta); + self.framework_paths.push(PathBuf::from(val)); + } + "-I" => { + self.include_paths.push(PathBuf::from(val)); + } + "-l" => { + // These are provided by the CRT with MSVC + if is_msvc && ["m", "c", "pthread"].contains(&val) { + continue; + } + + if statik && is_static_available(val, &dirs) { + let meta = format!("rustc-link-lib=static={}", val); + config.print_metadata(&meta); + } else { + let meta = format!("rustc-link-lib={}", val); + config.print_metadata(&meta); + } + + self.libs.push(val.to_string()); + } + "-D" => { + let mut iter = val.split("="); + self.defines.insert(iter.next().unwrap().to_owned(), iter.next().map(|s| s.to_owned())); + } + _ => {} + } + } + + let mut iter = words.iter() + .flat_map(|arg| if arg.starts_with("-Wl,") { + arg[4..].split(',').collect() + } else { + vec![arg.as_ref()] + }); + while let Some(part) = iter.next() { + if part != "-framework" { + continue + } + if let Some(lib) = iter.next() { + let meta = format!("rustc-link-lib=framework={}", lib); + config.print_metadata(&meta); + self.frameworks.push(lib.to_string()); + } + } + } + + fn parse_modversion(&mut self, output: &str) { + self.version.push_str(output.trim()); + } +} + +fn envify(name: &str) -> String { + name.chars().map(|c| c.to_ascii_uppercase()).map(|c| { + if c == '-' {'_'} else {c} + }).collect() +} + +/// System libraries should only be linked dynamically +fn is_static_available(name: &str, dirs: &[PathBuf]) -> bool { + let libname = format!("lib{}.a", name); + let system_roots = if cfg!(target_os = "macos") { + vec![Path::new("/Library"), Path::new("/System")] + } else { + vec![Path::new("/usr")] + }; + + dirs.iter().any(|dir| { + !system_roots.iter().any(|sys| dir.starts_with(sys)) && + dir.join(&libname).exists() + }) +} + +fn run(mut cmd: Command) -> Result, Error> { + match cmd.output() { + Ok(output) => { + if output.status.success() { + Ok(output.stdout) + } else { + Err(Error::Failure { + command: format!("{:?}", cmd), + output: output, + }) + } + } + Err(cause) => Err(Error::Command { + command: format!("{:?}", cmd), + cause: cause, + }), + } +} + +/// Split output produced by pkg-config --cflags and / or --libs into separate flags. +/// +/// Backslash in output is used to preserve literal meaning of following byte. Different words are +/// separated by unescaped space. Other whitespace characters generally should not occur unescaped +/// at all, apart from the newline at the end of output. For compatibility with what others +/// consumers of pkg-config output would do in this scenario, they are used here for splitting as +/// well. +fn split_flags(output: &[u8]) -> Vec { + let mut word = Vec::new(); + let mut words = Vec::new(); + let mut escaped = false; + + for &b in output { + match b { + _ if escaped => { + escaped = false; + word.push(b); + } + b'\\' => { + escaped = true + } + b'\t' | b'\n' | b'\r' | b' ' => { + if !word.is_empty() { + words.push(String::from_utf8(word).unwrap()); + word = Vec::new(); + } + } + _ => word.push(b), + } + } + + if !word.is_empty() { + words.push(String::from_utf8(word).unwrap()); + } + + words +} + +#[test] +#[cfg(target_os = "macos")] +fn system_library_mac_test() { + assert!(!is_static_available("PluginManager", &[PathBuf::from("/Library/Frameworks")])); + assert!(!is_static_available("python2.7", &[PathBuf::from("/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config")])); + assert!(!is_static_available("ffi_convenience", &[PathBuf::from("/Library/Ruby/Gems/2.0.0/gems/ffi-1.9.10/ext/ffi_c/libffi-x86_64/.libs")])); + + // Homebrew is in /usr/local, and it's not a part of the OS + if Path::new("/usr/local/lib/libpng16.a").exists() { + assert!(is_static_available("png16", &[PathBuf::from("/usr/local/lib")])); + } +} + +#[test] +#[cfg(target_os = "linux")] +fn system_library_linux_test() { + assert!(!is_static_available("util", &[PathBuf::from("/usr/lib/x86_64-linux-gnu")])); + assert!(!is_static_available("dialog", &[PathBuf::from("/usr/lib")])); +} diff --git a/pkg-config/.pc/no-special-snowflake-env.patch/tests/test.rs b/pkg-config/.pc/no-special-snowflake-env.patch/tests/test.rs new file mode 100644 index 000000000..fad0fcfdf --- /dev/null +++ b/pkg-config/.pc/no-special-snowflake-env.patch/tests/test.rs @@ -0,0 +1,118 @@ +extern crate pkg_config; +#[macro_use] +extern crate lazy_static; + +use pkg_config::Error; +use std::env; +use std::sync::Mutex; +use std::path::PathBuf; + +lazy_static! { + static ref LOCK: Mutex<()> = Mutex::new(()); +} + +fn reset() { + for (k, _) in env::vars() { + if k.contains("DYNAMIC") || + k.contains("STATIC") || + k.contains("PKG_CONFIG_ALLOW_CROSS") || + k.contains("FOO_NO_PKG_CONFIG") { + env::remove_var(&k); + } + } + env::remove_var("TARGET"); + env::remove_var("HOST"); + env::set_var("PKG_CONFIG_PATH", &env::current_dir().unwrap().join("tests")); +} + +fn find(name: &str) -> Result { + pkg_config::probe_library(name) +} + +#[test] +fn cross_disabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("TARGET", "foo"); + env::set_var("HOST", "bar"); + match find("foo") { + Err(Error::CrossCompilation) => {}, + x => panic!("Error::CrossCompilation expected, found `{:?}`", x), + } +} + +#[test] +fn cross_enabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("TARGET", "foo"); + env::set_var("HOST", "bar"); + env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); + find("foo").unwrap(); +} + +#[test] +fn package_disabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("FOO_NO_PKG_CONFIG", "1"); + match find("foo") { + Err(Error::EnvNoPkgConfig(name)) => { + assert_eq!(name, "FOO_NO_PKG_CONFIG") + } + x => panic!("Error::EnvNoPkgConfig expected, found `{:?}`", x), + } +} + +#[test] +fn output_ok() { + let _g = LOCK.lock(); + reset(); + let lib = find("foo").unwrap(); + assert!(lib.libs.contains(&"gcc".to_string())); + assert!(lib.libs.contains(&"coregrind-amd64-linux".to_string())); + assert!(lib.link_paths.contains(&PathBuf::from("/usr/lib/valgrind"))); +} + +#[test] +fn escapes() { + let _g = LOCK.lock(); + reset(); + let lib = find("escape").unwrap(); + assert!(lib.include_paths.contains(&PathBuf::from("include path with spaces"))); + assert!(lib.link_paths.contains(&PathBuf::from("link path with spaces"))); + assert_eq!(lib.defines.get("A"), + Some(&Some("\"escaped string' literal\"".to_owned()))); + assert_eq!(lib.defines.get("B"), + Some(&Some("ESCAPED IDENTIFIER".to_owned()))); + assert_eq!(lib.defines.get("FOX"), + Some(&Some("🦊".to_owned()))); +} + +#[test] +fn framework() { + let _g = LOCK.lock(); + reset(); + let lib = find("framework").unwrap(); + assert!(lib.frameworks.contains(&"foo".to_string())); + assert!(lib.frameworks.contains(&"bar".to_string())); + assert!(lib.frameworks.contains(&"baz".to_string())); + assert!(lib.frameworks.contains(&"foobar".to_string())); + assert!(lib.frameworks.contains(&"foobaz".to_string())); + assert!(lib.framework_paths.contains(&PathBuf::from("/usr/lib"))); +} + +#[test] +fn get_variable() { + let _g = LOCK.lock(); + reset(); + let prefix = pkg_config::get_variable("foo", "prefix").unwrap(); + assert_eq!(prefix, "/usr"); +} + +#[test] +fn version() { + let _g = LOCK.lock(); + reset(); + assert_eq!(&find("foo").unwrap().version[..], "3.10.0.SVN"); +} diff --git a/pkg-config/CHANGELOG.md b/pkg-config/CHANGELOG.md new file mode 100644 index 000000000..3f56db10d --- /dev/null +++ b/pkg-config/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [0.3.10] - 2018-04-23 + +### Added +- Allow static linking of /usr/ on macOS (#42) +- Add support for parsing `-Wl,` style framework flags (#48) +- Parse defines in `pkg-config` output (#49) +- Rerun on `PKG_CONFIG_PATH` changes (#50) +- Introduce target-scoped variables (#58) +- Respect pkg-config escaping rules used with --cflags and --libs (#61) + +### Changed +- Use `?` instead of `try!()` in the codebase (#63) diff --git a/pkg-config/Cargo.toml b/pkg-config/Cargo.toml new file mode 100644 index 000000000..78de2ff48 --- /dev/null +++ b/pkg-config/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "pkg-config" +version = "0.3.14" +authors = ["Alex Crichton "] +description = "A library to run the pkg-config system tool at build time in order to be used in\nCargo build scripts.\n" +documentation = "https://docs.rs/pkg-config" +keywords = ["build-dependencies"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/pkg-config-rs" +[dev-dependencies.lazy_static] +version = "1" +[badges.travis-ci] +repository = "alexcrichton/pkg-config-rs" diff --git a/pkg-config/LICENSE-APACHE b/pkg-config/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/pkg-config/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/pkg-config/LICENSE-MIT b/pkg-config/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/pkg-config/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/pkg-config/README.md b/pkg-config/README.md new file mode 100644 index 000000000..cb9ebd583 --- /dev/null +++ b/pkg-config/README.md @@ -0,0 +1,73 @@ +# pkg-config-rs + +[![Build Status](https://travis-ci.org/alexcrichton/pkg-config-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/pkg-config-rs) +[![Rust](https://img.shields.io/badge/rust-1.13%2B-blue.svg?maxAge=3600)](https://github.com/alexcrichton/pkg-config-rs/) + +[Documentation](https://docs.rs/pkg-config) + +A simple library meant to be used as a build dependency with Cargo packages in +order to use the system `pkg-config` tool (if available) to determine where a +library is located. + +You can use this crate directly to probe for specific libraries, or use +[metadeps](https://github.com/joshtriplett/metadeps) to declare all your +`pkg-config` dependencies in `Cargo.toml`. + +This library requires Rust 1.13+. + +# Example + +Find the system library named `foo`, with minimum version 1.2.3: + +```rust +extern crate pkg_config; + +fn main() { + pkg_config::Config::new().atleast_version("1.2.3").probe("foo").unwrap(); +} +``` + +Find the system library named `foo`, with no version requirement (not +recommended): + +```rust +extern crate pkg_config; + +fn main() { + pkg_config::probe_library("foo").unwrap(); +} +``` + +# External configuration via target-scoped environment variables + +In cross-compilation context, it is useful to manage separately PKG_CONFIG_PATH +and a few other variables for the `host` and the `target` platform. + +The supported variables are: `PKG_CONFIG_PATH`, `PKG_CONFIG_LIBDIR`, and +`PKG_CONFIG_SYSROOT_DIR`. + +Each of these variables can also be supplied with certain prefixes and suffixes, in the following prioritized order: + +1. `_` - for example, `PKG_CONFIG_PATH_x86_64-unknown-linux-gnu` +2. `_` - for example, `PKG_CONFIG_PATH_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_PKG_CONFIG_PATH` or `TARGET_PKG_CONFIG_PATH` +4. `` - a plain `PKG_CONFIG_PATH` + +Also note that `PKG_CONFIG_ALLOW_CROSS` must always be set in cross-compilation context. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/pkg-config/debian/patches/no-special-snowflake-env.patch b/pkg-config/debian/patches/no-special-snowflake-env.patch new file mode 100644 index 000000000..56338bad9 --- /dev/null +++ b/pkg-config/debian/patches/no-special-snowflake-env.patch @@ -0,0 +1,98 @@ +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -9,8 +9,6 @@ + //! A number of environment variables are available to globally configure how + //! this crate will invoke `pkg-config`: + //! +-//! * `PKG_CONFIG_ALLOW_CROSS` - if this variable is not set, then `pkg-config` +-//! will automatically be disabled for all cross compiles. + //! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when + //! probing for the library named `foo`. + //! +@@ -81,7 +79,7 @@ + + // Only use pkg-config in host == target situations by default (allowing an + // override). +- (host == target || env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()) ++ (host == target || true) + } + + #[derive(Clone, Default)] +@@ -113,9 +111,8 @@ + /// Contains the name of the responsible environment variable. + EnvNoPkgConfig(String), + +- /// Cross compilation detected. +- /// +- /// Override with `PKG_CONFIG_ALLOW_CROSS=1`. ++ /// Cross compilation detected. Kept for compatibility; ++ /// the Debian package never emits this. + CrossCompilation, + + /// Failed to run `pkg-config`. +@@ -137,13 +134,9 @@ + fn description(&self) -> &str { + match *self { + Error::EnvNoPkgConfig(_) => "pkg-config requested to be aborted", +- Error::CrossCompilation => { +- "pkg-config doesn't handle cross compilation. \ +- Use PKG_CONFIG_ALLOW_CROSS=1 to override" +- } + Error::Command { .. } => "failed to run pkg-config", + Error::Failure { .. } => "pkg-config did not exit sucessfully", +- Error::__Nonexhaustive => panic!(), ++ Error::CrossCompilation | Error::__Nonexhaustive => panic!(), + } + } + +@@ -214,10 +207,6 @@ + Error::EnvNoPkgConfig(ref name) => { + write!(f, "Aborted because {} is set", name) + } +- Error::CrossCompilation => { +- write!(f, "Cross compilation detected. \ +- Use PKG_CONFIG_ALLOW_CROSS=1 to override") +- } + Error::Command { ref command, ref cause } => { + write!(f, "Failed to run `{}`: {}", command, cause) + } +@@ -233,7 +222,7 @@ + } + Ok(()) + } +- Error::__Nonexhaustive => panic!(), ++ Error::CrossCompilation | Error::__Nonexhaustive => panic!(), + } + } + } +@@ -388,7 +377,11 @@ + } + + fn command(&self, name: &str, args: &[&str]) -> Command { +- let exe = self.env_var("PKG_CONFIG").unwrap_or_else(|_| String::from("pkg-config")); ++ let exe = self.env_var("PKG_CONFIG").unwrap_or_else(|_| { ++ self.env_var("DEB_HOST_GNU_TYPE") ++ .map(|t| t.to_string() + "-pkg-config") ++ .unwrap_or_else(|_| String::from("pkg-config")) ++ }); + let mut cmd = Command::new(exe); + if self.is_static(name) { + cmd.arg("--static"); +--- a/tests/test.rs ++++ b/tests/test.rs +@@ -29,7 +29,6 @@ + pkg_config::probe_library(name) + } + +-#[test] + fn cross_disabled() { + let _g = LOCK.lock(); + reset(); +@@ -41,7 +40,6 @@ + } + } + +-#[test] + fn cross_enabled() { + let _g = LOCK.lock(); + reset(); diff --git a/pkg-config/debian/patches/series b/pkg-config/debian/patches/series new file mode 100644 index 000000000..206beed4b --- /dev/null +++ b/pkg-config/debian/patches/series @@ -0,0 +1 @@ +no-special-snowflake-env.patch diff --git a/pkg-config/src/lib.rs b/pkg-config/src/lib.rs new file mode 100644 index 000000000..021d4bb28 --- /dev/null +++ b/pkg-config/src/lib.rs @@ -0,0 +1,623 @@ +//! A build dependency for Cargo libraries to find system artifacts through the +//! `pkg-config` utility. +//! +//! This library will shell out to `pkg-config` as part of build scripts and +//! probe the system to determine how to link to a specified library. The +//! `Config` structure serves as a method of configuring how `pkg-config` is +//! invoked in a builder style. +//! +//! A number of environment variables are available to globally configure how +//! this crate will invoke `pkg-config`: +//! +//! * `FOO_NO_PKG_CONFIG` - if set, this will disable running `pkg-config` when +//! probing for the library named `foo`. +//! +//! There are also a number of environment variables which can configure how a +//! library is linked to (dynamically vs statically). These variables control +//! whether the `--static` flag is passed. Note that this behavior can be +//! overridden by configuring explicitly on `Config`. The variables are checked +//! in the following order: +//! +//! * `FOO_STATIC` - pass `--static` for the library `foo` +//! * `FOO_DYNAMIC` - do not pass `--static` for the library `foo` +//! * `PKG_CONFIG_ALL_STATIC` - pass `--static` for all libraries +//! * `PKG_CONFIG_ALL_DYNAMIC` - do not pass `--static` for all libraries +//! +//! After running `pkg-config` all appropriate Cargo metadata will be printed on +//! stdout if the search was successful. +//! +//! # Example +//! +//! Find the system library named `foo`, with minimum version 1.2.3: +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::Config::new().atleast_version("1.2.3").probe("foo").unwrap(); +//! } +//! ``` +//! +//! Find the system library named `foo`, with no version requirement (not +//! recommended): +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::probe_library("foo").unwrap(); +//! } +//! ``` +//! +//! Configure how library `foo` is linked to. +//! +//! ```no_run +//! extern crate pkg_config; +//! +//! fn main() { +//! pkg_config::Config::new().atleast_version("1.2.3").statik(true).probe("foo").unwrap(); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/pkg-config/0.3")] + +#[allow(unused_imports)] // Required for Rust <1.23 +use std::ascii::AsciiExt; +use std::collections::HashMap; +use std::env; +use std::error; +use std::ffi::{OsStr, OsString}; +use std::fmt; +use std::io; +use std::path::{PathBuf, Path}; +use std::process::{Command, Output}; +use std::str; + +pub fn target_supported() -> bool { + let target = env::var("TARGET").unwrap_or_else(|_| String::new()); + let host = env::var("HOST").unwrap_or_else(|_| String::new()); + + // Only use pkg-config in host == target situations by default (allowing an + // override). + (host == target || true) +} + +#[derive(Clone, Default)] +pub struct Config { + statik: Option, + atleast_version: Option, + extra_args: Vec, + cargo_metadata: bool, + env_metadata: bool, + print_system_libs: bool, +} + +#[derive(Debug)] +pub struct Library { + pub libs: Vec, + pub link_paths: Vec, + pub frameworks: Vec, + pub framework_paths: Vec, + pub include_paths: Vec, + pub defines: HashMap>, + pub version: String, + _priv: (), +} + +/// Represents all reasons `pkg-config` might not succeed or be run at all. +pub enum Error { + /// Aborted because of `*_NO_PKG_CONFIG` environment variable. + /// + /// Contains the name of the responsible environment variable. + EnvNoPkgConfig(String), + + /// Cross compilation detected. Kept for compatibility; + /// the Debian package never emits this. + CrossCompilation, + + /// Failed to run `pkg-config`. + /// + /// Contains the command and the cause. + Command { command: String, cause: io::Error }, + + /// `pkg-config` did not exit sucessfully. + /// + /// Contains the command and output. + Failure { command: String, output: Output }, + + #[doc(hidden)] + // please don't match on this, we're likely to add more variants over time + __Nonexhaustive, +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::EnvNoPkgConfig(_) => "pkg-config requested to be aborted", + Error::Command { .. } => "failed to run pkg-config", + Error::Failure { .. } => "pkg-config did not exit sucessfully", + Error::CrossCompilation | Error::__Nonexhaustive => panic!(), + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Command { ref cause, .. } => Some(cause), + _ => None, + } + } +} + +// Workaround for temporary lack of impl Debug for Output in stable std +struct OutputDebugger<'a>(&'a Output); + +// Lifted from 1.7 std +impl<'a> fmt::Debug for OutputDebugger<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let stdout_utf8 = str::from_utf8(&self.0.stdout); + let stdout_debug: &fmt::Debug = match stdout_utf8 { + Ok(ref str) => str, + Err(_) => &self.0.stdout + }; + + let stderr_utf8 = str::from_utf8(&self.0.stderr); + let stderr_debug: &fmt::Debug = match stderr_utf8 { + Ok(ref str) => str, + Err(_) => &self.0.stderr + }; + + fmt.debug_struct("Output") + .field("status", &self.0.status) + .field("stdout", stdout_debug) + .field("stderr", stderr_debug) + .finish() + } +} + +// Workaround for temporary lack of impl Debug for Output in stable std, continued +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::EnvNoPkgConfig(ref name) => { + f.debug_tuple("EnvNoPkgConfig") + .field(name) + .finish() + } + Error::CrossCompilation => write!(f, "CrossCompilation"), + Error::Command { ref command, ref cause } => { + f.debug_struct("Command") + .field("command", command) + .field("cause", cause) + .finish() + } + Error::Failure { ref command, ref output } => { + f.debug_struct("Failure") + .field("command", command) + .field("output", &OutputDebugger(output)) + .finish() + } + Error::__Nonexhaustive => panic!(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::EnvNoPkgConfig(ref name) => { + write!(f, "Aborted because {} is set", name) + } + Error::Command { ref command, ref cause } => { + write!(f, "Failed to run `{}`: {}", command, cause) + } + Error::Failure { ref command, ref output } => { + let stdout = str::from_utf8(&output.stdout).unwrap(); + let stderr = str::from_utf8(&output.stderr).unwrap(); + write!(f, "`{}` did not exit successfully: {}", command, output.status)?; + if !stdout.is_empty() { + write!(f, "\n--- stdout\n{}", stdout)?; + } + if !stderr.is_empty() { + write!(f, "\n--- stderr\n{}", stderr)?; + } + Ok(()) + } + Error::CrossCompilation | Error::__Nonexhaustive => panic!(), + } + } +} + +/// Deprecated in favor of the probe_library function +#[doc(hidden)] +pub fn find_library(name: &str) -> Result { + probe_library(name).map_err(|e| e.to_string()) +} + +/// Simple shortcut for using all default options for finding a library. +pub fn probe_library(name: &str) -> Result { + Config::new().probe(name) +} + +/// Run `pkg-config` to get the value of a variable from a package using +/// --variable. +pub fn get_variable(package: &str, variable: &str) -> Result { + let arg = format!("--variable={}", variable); + let cfg = Config::new(); + let out = run(cfg.command(package, &[&arg]))?; + Ok(str::from_utf8(&out).unwrap().trim_right().to_owned()) +} + +impl Config { + /// Creates a new set of configuration options which are all initially set + /// to "blank". + pub fn new() -> Config { + Config { + statik: None, + atleast_version: None, + extra_args: vec![], + print_system_libs: true, + cargo_metadata: true, + env_metadata: false, + } + } + + /// Indicate whether the `--static` flag should be passed. + /// + /// This will override the inference from environment variables described in + /// the crate documentation. + pub fn statik(&mut self, statik: bool) -> &mut Config { + self.statik = Some(statik); + self + } + + /// Indicate that the library must be at least version `vers`. + pub fn atleast_version(&mut self, vers: &str) -> &mut Config { + self.atleast_version = Some(vers.to_string()); + self + } + + /// Add an argument to pass to pkg-config. + /// + /// It's placed after all of the arguments generated by this library. + pub fn arg>(&mut self, arg: S) -> &mut Config { + self.extra_args.push(arg.as_ref().to_os_string()); + self + } + + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Config { + self.cargo_metadata = cargo_metadata; + self + } + + /// Define whether metadata should be emitted for cargo allowing to + /// automatically rebuild when environment variables change. Defaults to + /// `false`. + pub fn env_metadata(&mut self, env_metadata: bool) -> &mut Config { + self.env_metadata = env_metadata; + self + } + + /// Enable or disable the `PKG_CONFIG_ALLOW_SYSTEM_LIBS` environment + /// variable. + /// + /// This env var is enabled by default. + pub fn print_system_libs(&mut self, print: bool) -> &mut Config { + self.print_system_libs = print; + self + } + + /// Deprecated in favor fo the `probe` function + #[doc(hidden)] + pub fn find(&self, name: &str) -> Result { + self.probe(name).map_err(|e| e.to_string()) + } + + /// Run `pkg-config` to find the library `name`. + /// + /// This will use all configuration previously set to specify how + /// `pkg-config` is run. + pub fn probe(&self, name: &str) -> Result { + let abort_var_name = format!("{}_NO_PKG_CONFIG", envify(name)); + if self.env_var_os(&abort_var_name).is_some() { + return Err(Error::EnvNoPkgConfig(abort_var_name)) + } else if !target_supported() { + return Err(Error::CrossCompilation); + } + + let mut library = Library::new(); + + let output = run(self.command(name, &["--libs", "--cflags"]))?; + library.parse_libs_cflags(name, &output, self); + + let output = run(self.command(name, &["--modversion"]))?; + library.parse_modversion(str::from_utf8(&output).unwrap()); + + Ok(library) + } + + /// Deprecated in favor of the top level `get_variable` function + #[doc(hidden)] + pub fn get_variable(package: &str, variable: &str) -> Result { + get_variable(package, variable).map_err(|e| e.to_string()) + } + + fn targetted_env_var(&self, var_base: &str) -> Result { + if let Ok(target) = env::var("TARGET") { + let host = env::var("HOST")?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + + self.env_var(&format!("{}_{}", var_base, target)) + .or_else(|_| self.env_var(&format!("{}_{}", var_base, target_u))) + .or_else(|_| self.env_var(&format!("{}_{}", kind, var_base))) + .or_else(|_| self.env_var(var_base)) + } else { + self.env_var(var_base) + } + } + + fn env_var(&self, name: &str) -> Result { + if self.env_metadata { + println!("cargo:rerun-if-env-changed={}", name); + } + env::var(name) + } + + fn env_var_os(&self, name: &str) -> Option { + if self.env_metadata { + println!("cargo:rerun-if-env-changed={}", name); + } + env::var_os(name) + } + + fn is_static(&self, name: &str) -> bool { + self.statik.unwrap_or_else(|| self.infer_static(name)) + } + + fn command(&self, name: &str, args: &[&str]) -> Command { + let exe = self.env_var("PKG_CONFIG").unwrap_or_else(|_| { + self.env_var("DEB_HOST_GNU_TYPE") + .map(|t| t.to_string() + "-pkg-config") + .unwrap_or_else(|_| String::from("pkg-config")) + }); + let mut cmd = Command::new(exe); + if self.is_static(name) { + cmd.arg("--static"); + } + cmd.args(args) + .args(&self.extra_args); + + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_PATH") { + cmd.env("PKG_CONFIG_PATH", value); + } + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_LIBDIR") { + cmd.env("PKG_CONFIG_LIBDIR", value); + } + if let Ok(value) = self.targetted_env_var("PKG_CONFIG_SYSROOT_DIR") { + cmd.env("PKG_CONFIG_SYSROOT_DIR", value); + } + if self.print_system_libs { + cmd.env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1"); + } + if let Some(ref version) = self.atleast_version { + cmd.arg(&format!("{} >= {}", name, version)); + } else { + cmd.arg(name); + } + cmd + } + + fn print_metadata(&self, s: &str) { + if self.cargo_metadata { + println!("cargo:{}", s); + } + } + + fn infer_static(&self, name: &str) -> bool { + let name = envify(name); + if self.env_var_os(&format!("{}_STATIC", name)).is_some() { + true + } else if self.env_var_os(&format!("{}_DYNAMIC", name)).is_some() { + false + } else if self.env_var_os("PKG_CONFIG_ALL_STATIC").is_some() { + true + } else if self.env_var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() { + false + } else { + false + } + } +} + +impl Library { + fn new() -> Library { + Library { + libs: Vec::new(), + link_paths: Vec::new(), + include_paths: Vec::new(), + frameworks: Vec::new(), + framework_paths: Vec::new(), + defines: HashMap::new(), + version: String::new(), + _priv: (), + } + } + + fn parse_libs_cflags(&mut self, name: &str, output: &[u8], config: &Config) { + let mut is_msvc = false; + if let Ok(target) = env::var("TARGET") { + if target.contains("msvc") { + is_msvc = true; + } + } + + let words = split_flags(output); + let parts = words.iter() + .filter(|l| l.len() > 2) + .map(|arg| (&arg[0..2], &arg[2..])) + .collect::>(); + + let mut dirs = Vec::new(); + let statik = config.is_static(name); + for &(flag, val) in &parts { + match flag { + "-L" => { + let meta = format!("rustc-link-search=native={}", val); + config.print_metadata(&meta); + dirs.push(PathBuf::from(val)); + self.link_paths.push(PathBuf::from(val)); + } + "-F" => { + let meta = format!("rustc-link-search=framework={}", val); + config.print_metadata(&meta); + self.framework_paths.push(PathBuf::from(val)); + } + "-I" => { + self.include_paths.push(PathBuf::from(val)); + } + "-l" => { + // These are provided by the CRT with MSVC + if is_msvc && ["m", "c", "pthread"].contains(&val) { + continue; + } + + if statik && is_static_available(val, &dirs) { + let meta = format!("rustc-link-lib=static={}", val); + config.print_metadata(&meta); + } else { + let meta = format!("rustc-link-lib={}", val); + config.print_metadata(&meta); + } + + self.libs.push(val.to_string()); + } + "-D" => { + let mut iter = val.split("="); + self.defines.insert(iter.next().unwrap().to_owned(), iter.next().map(|s| s.to_owned())); + } + _ => {} + } + } + + let mut iter = words.iter() + .flat_map(|arg| if arg.starts_with("-Wl,") { + arg[4..].split(',').collect() + } else { + vec![arg.as_ref()] + }); + while let Some(part) = iter.next() { + if part != "-framework" { + continue + } + if let Some(lib) = iter.next() { + let meta = format!("rustc-link-lib=framework={}", lib); + config.print_metadata(&meta); + self.frameworks.push(lib.to_string()); + } + } + } + + fn parse_modversion(&mut self, output: &str) { + self.version.push_str(output.trim()); + } +} + +fn envify(name: &str) -> String { + name.chars().map(|c| c.to_ascii_uppercase()).map(|c| { + if c == '-' {'_'} else {c} + }).collect() +} + +/// System libraries should only be linked dynamically +fn is_static_available(name: &str, dirs: &[PathBuf]) -> bool { + let libname = format!("lib{}.a", name); + let system_roots = if cfg!(target_os = "macos") { + vec![Path::new("/Library"), Path::new("/System")] + } else { + vec![Path::new("/usr")] + }; + + dirs.iter().any(|dir| { + !system_roots.iter().any(|sys| dir.starts_with(sys)) && + dir.join(&libname).exists() + }) +} + +fn run(mut cmd: Command) -> Result, Error> { + match cmd.output() { + Ok(output) => { + if output.status.success() { + Ok(output.stdout) + } else { + Err(Error::Failure { + command: format!("{:?}", cmd), + output: output, + }) + } + } + Err(cause) => Err(Error::Command { + command: format!("{:?}", cmd), + cause: cause, + }), + } +} + +/// Split output produced by pkg-config --cflags and / or --libs into separate flags. +/// +/// Backslash in output is used to preserve literal meaning of following byte. Different words are +/// separated by unescaped space. Other whitespace characters generally should not occur unescaped +/// at all, apart from the newline at the end of output. For compatibility with what others +/// consumers of pkg-config output would do in this scenario, they are used here for splitting as +/// well. +fn split_flags(output: &[u8]) -> Vec { + let mut word = Vec::new(); + let mut words = Vec::new(); + let mut escaped = false; + + for &b in output { + match b { + _ if escaped => { + escaped = false; + word.push(b); + } + b'\\' => { + escaped = true + } + b'\t' | b'\n' | b'\r' | b' ' => { + if !word.is_empty() { + words.push(String::from_utf8(word).unwrap()); + word = Vec::new(); + } + } + _ => word.push(b), + } + } + + if !word.is_empty() { + words.push(String::from_utf8(word).unwrap()); + } + + words +} + +#[test] +#[cfg(target_os = "macos")] +fn system_library_mac_test() { + assert!(!is_static_available("PluginManager", &[PathBuf::from("/Library/Frameworks")])); + assert!(!is_static_available("python2.7", &[PathBuf::from("/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config")])); + assert!(!is_static_available("ffi_convenience", &[PathBuf::from("/Library/Ruby/Gems/2.0.0/gems/ffi-1.9.10/ext/ffi_c/libffi-x86_64/.libs")])); + + // Homebrew is in /usr/local, and it's not a part of the OS + if Path::new("/usr/local/lib/libpng16.a").exists() { + assert!(is_static_available("png16", &[PathBuf::from("/usr/local/lib")])); + } +} + +#[test] +#[cfg(target_os = "linux")] +fn system_library_linux_test() { + assert!(!is_static_available("util", &[PathBuf::from("/usr/lib/x86_64-linux-gnu")])); + assert!(!is_static_available("dialog", &[PathBuf::from("/usr/lib")])); +} diff --git a/pkg-config/tests/escape.pc b/pkg-config/tests/escape.pc new file mode 100644 index 000000000..701c4bf73 --- /dev/null +++ b/pkg-config/tests/escape.pc @@ -0,0 +1,5 @@ +Name: Escape +Version: 4.2.0 +Description: Escape utility library +Libs: -Llink\ path\ with\ spaces +Cflags: -Iinclude\ path\ with\ spaces -DA=\"escaped\ string\'\ literal\" -DB=ESCAPED\ IDENTIFIER -DFOX=🦊 diff --git a/pkg-config/tests/foo.pc b/pkg-config/tests/foo.pc new file mode 100644 index 000000000..b1ae3d8ce --- /dev/null +++ b/pkg-config/tests/foo.pc @@ -0,0 +1,16 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include/valgrind +arch=amd64 +os=linux +platform=amd64-linux +valt_load_address=0x38000000 + +Name: Valgrind +Description: A dynamic binary instrumentation framework +Version: 3.10.0.SVN +Requires: +Libs: -L${libdir}/valgrind -lcoregrind-amd64-linux -lvex-amd64-linux -lgcc +Cflags: -I${includedir} + diff --git a/pkg-config/tests/framework.pc b/pkg-config/tests/framework.pc new file mode 100644 index 000000000..fec17f47a --- /dev/null +++ b/pkg-config/tests/framework.pc @@ -0,0 +1,16 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include/valgrind +arch=amd64 +os=linux +platform=amd64-linux +valt_load_address=0x38000000 + +Name: Valgrind +Description: A dynamic binary instrumentation framework +Version: 3.10.0.SVN +Requires: +Libs: -F${libdir} -framework foo -Wl,-framework,bar -Wl,-framework -Wl,baz -Wl,-framework,foobar,-framework,foobaz +Cflags: -I${includedir} + diff --git a/pkg-config/tests/test.rs b/pkg-config/tests/test.rs new file mode 100644 index 000000000..69300ef6b --- /dev/null +++ b/pkg-config/tests/test.rs @@ -0,0 +1,116 @@ +extern crate pkg_config; +#[macro_use] +extern crate lazy_static; + +use pkg_config::Error; +use std::env; +use std::sync::Mutex; +use std::path::PathBuf; + +lazy_static! { + static ref LOCK: Mutex<()> = Mutex::new(()); +} + +fn reset() { + for (k, _) in env::vars() { + if k.contains("DYNAMIC") || + k.contains("STATIC") || + k.contains("PKG_CONFIG_ALLOW_CROSS") || + k.contains("FOO_NO_PKG_CONFIG") { + env::remove_var(&k); + } + } + env::remove_var("TARGET"); + env::remove_var("HOST"); + env::set_var("PKG_CONFIG_PATH", &env::current_dir().unwrap().join("tests")); +} + +fn find(name: &str) -> Result { + pkg_config::probe_library(name) +} + +fn cross_disabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("TARGET", "foo"); + env::set_var("HOST", "bar"); + match find("foo") { + Err(Error::CrossCompilation) => {}, + x => panic!("Error::CrossCompilation expected, found `{:?}`", x), + } +} + +fn cross_enabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("TARGET", "foo"); + env::set_var("HOST", "bar"); + env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); + find("foo").unwrap(); +} + +#[test] +fn package_disabled() { + let _g = LOCK.lock(); + reset(); + env::set_var("FOO_NO_PKG_CONFIG", "1"); + match find("foo") { + Err(Error::EnvNoPkgConfig(name)) => { + assert_eq!(name, "FOO_NO_PKG_CONFIG") + } + x => panic!("Error::EnvNoPkgConfig expected, found `{:?}`", x), + } +} + +#[test] +fn output_ok() { + let _g = LOCK.lock(); + reset(); + let lib = find("foo").unwrap(); + assert!(lib.libs.contains(&"gcc".to_string())); + assert!(lib.libs.contains(&"coregrind-amd64-linux".to_string())); + assert!(lib.link_paths.contains(&PathBuf::from("/usr/lib/valgrind"))); +} + +#[test] +fn escapes() { + let _g = LOCK.lock(); + reset(); + let lib = find("escape").unwrap(); + assert!(lib.include_paths.contains(&PathBuf::from("include path with spaces"))); + assert!(lib.link_paths.contains(&PathBuf::from("link path with spaces"))); + assert_eq!(lib.defines.get("A"), + Some(&Some("\"escaped string' literal\"".to_owned()))); + assert_eq!(lib.defines.get("B"), + Some(&Some("ESCAPED IDENTIFIER".to_owned()))); + assert_eq!(lib.defines.get("FOX"), + Some(&Some("🦊".to_owned()))); +} + +#[test] +fn framework() { + let _g = LOCK.lock(); + reset(); + let lib = find("framework").unwrap(); + assert!(lib.frameworks.contains(&"foo".to_string())); + assert!(lib.frameworks.contains(&"bar".to_string())); + assert!(lib.frameworks.contains(&"baz".to_string())); + assert!(lib.frameworks.contains(&"foobar".to_string())); + assert!(lib.frameworks.contains(&"foobaz".to_string())); + assert!(lib.framework_paths.contains(&PathBuf::from("/usr/lib"))); +} + +#[test] +fn get_variable() { + let _g = LOCK.lock(); + reset(); + let prefix = pkg_config::get_variable("foo", "prefix").unwrap(); + assert_eq!(prefix, "/usr"); +} + +#[test] +fn version() { + let _g = LOCK.lock(); + reset(); + assert_eq!(&find("foo").unwrap().version[..], "3.10.0.SVN"); +} diff --git a/pretty_env_logger/.cargo-checksum.json b/pretty_env_logger/.cargo-checksum.json new file mode 100644 index 000000000..54a67bfc8 --- /dev/null +++ b/pretty_env_logger/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"} \ No newline at end of file diff --git a/pretty_env_logger/Cargo.toml b/pretty_env_logger/Cargo.toml new file mode 100644 index 000000000..a8fef8e3a --- /dev/null +++ b/pretty_env_logger/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "pretty_env_logger" +version = "0.3.0" +authors = ["Sean McArthur "] +include = ["Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "src/**/*"] +description = "a visually pretty env_logger" +readme = "README.md" +keywords = ["log", "logger", "logging"] +categories = ["development-tools::debugging"] +license = "MIT/Apache-2.0" +repository = "https://github.com/seanmonstar/pretty-env-logger" +[dependencies.chrono] +version = "0.4.4" + +[dependencies.env_logger] +version = "0.6" + +[dependencies.log] +version = "0.4" diff --git a/pretty_env_logger/LICENSE-APACHE b/pretty_env_logger/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/pretty_env_logger/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/pretty_env_logger/LICENSE-MIT b/pretty_env_logger/LICENSE-MIT new file mode 100644 index 000000000..5745ebdec --- /dev/null +++ b/pretty_env_logger/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2017 Sean McArthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/pretty_env_logger/src/lib.rs b/pretty_env_logger/src/lib.rs new file mode 100644 index 000000000..c72003d8a --- /dev/null +++ b/pretty_env_logger/src/lib.rs @@ -0,0 +1,217 @@ +#![deny(warnings)] +#![deny(missing_docs)] + +//! A logger configured via an environment variable which writes to standard +//! error with nice colored output for log levels. +//! +//! ## Example +//! +//! ``` +//! extern crate pretty_env_logger; +//! #[macro_use] extern crate log; +//! +//! fn main() { +//! pretty_env_logger::init(); +//! +//! trace!("a trace example"); +//! debug!("deboogging"); +//! info!("such information"); +//! warn!("o_O"); +//! error!("boom"); +//! } +//! ``` + +extern crate env_logger; +extern crate log; +extern crate chrono; + +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + +use chrono::Local; +use env_logger::{fmt::{Color, Style, StyledValue}, Builder}; +use log::Level; + +fn colored_level<'a>(style: &'a mut Style, level: Level) -> StyledValue<'a, &'static str> { + match level { + Level::Trace => style.set_color(Color::Magenta).value("TRACE"), + Level::Debug => style.set_color(Color::Blue).value("DEBUG"), + Level::Info => style.set_color(Color::Green).value("INFO "), + Level::Warn => style.set_color(Color::Yellow).value("WARN "), + Level::Error => style.set_color(Color::Red).value("ERROR"), + } +} + +static MAX_MODULE_WIDTH: AtomicUsize = ATOMIC_USIZE_INIT; + +/// Initializes the global logger with a pretty env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Panics +/// +/// This function fails to set the global logger if one has already been set. +#[inline] +pub fn init() { + try_init().unwrap(); +} + +/// Initializes the global logger with a timed pretty env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Panics +/// +/// This function fails to set the global logger if one has already been set. +#[inline] +pub fn init_timed() { + try_init_timed().unwrap(); +} + +/// Initializes the global logger with a pretty env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Errors +/// +/// This function fails to set the global logger if one has already been set. +pub fn try_init() -> Result<(), log::SetLoggerError> { + try_init_custom_env("RUST_LOG") +} + +/// Initializes the global logger with a timed pretty env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Errors +/// +/// This function fails to set the global logger if one has already been set. +pub fn try_init_timed() -> Result<(), log::SetLoggerError> { + try_init_timed_custom_env("RUST_LOG") +} + +/// Initialized the global logger with a pretty env logger, with a custom variable name. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Panics +/// +/// This function fails to set the global logger if one has already been set. +pub fn init_custom_env(environment_variable_name: &str) { + try_init_custom_env(environment_variable_name).unwrap(); +} + +/// Initialized the global logger with a pretty env logger, with a custom variable name. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Errors +/// +/// This function fails to set the global logger if one has already been set. +pub fn try_init_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError> { + let mut builder = formatted_builder(); + + if let Ok(s) = ::std::env::var(environment_variable_name) { + builder.parse(&s); + } + + builder.try_init() +} + +/// Initialized the global logger with a timed pretty env logger, with a custom variable name. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +/// +/// # Errors +/// +/// This function fails to set the global logger if one has already been set. +pub fn try_init_timed_custom_env(environment_variable_name: &str) -> Result<(), log::SetLoggerError> { + let mut builder = formatted_timed_builder(); + + if let Ok(s) = ::std::env::var(environment_variable_name) { + builder.parse(&s); + } + + builder.try_init() +} + +/// Returns a `env_logger::Builder` for further customization. +/// +/// This method will return a colored and formatted `env_logger::Builder` +/// for further customization. Refer to env_logger::Build crate documentation +/// for further details and usage. +pub fn formatted_builder() -> Builder { + let mut builder = Builder::new(); + + builder.format(|f, record| { + use std::io::Write; + let target = record.target(); + let mut max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed); + if max_width < target.len() { + MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed); + max_width = target.len(); + } + + + let mut style = f.style(); + let level = colored_level(&mut style, record.level()); + let mut style = f.style(); + let target = style.set_bold(true).value(format!("{: {}", + level, + target, + record.args(), + ) + }); + + builder +} + +/// Returns a `env_logger::Builder` for further customization. +/// +/// This method will return a colored and time formatted `env_logger::Builder` +/// for further customization. Refer to env_logger::Build crate documentation +/// for further details and usage. +pub fn formatted_timed_builder() -> Builder { + let mut builder = Builder::new(); + + builder.format(|f, record| { + use std::io::Write; + let target = record.target(); + let mut max_width = MAX_MODULE_WIDTH.load(Ordering::Relaxed); + if max_width < target.len() { + MAX_MODULE_WIDTH.store(target.len(), Ordering::Relaxed); + max_width = target.len(); + } + + let mut style = f.style(); + let level = colored_level(&mut style, record.level()); + let mut style = f.style(); + let target = style.set_bold(true).value(format!("{: {}", + Local::now().format("%Y-%m-%d %H:%M:%S"), + level, + target, + record.args(), + ) + }); + + builder +} diff --git a/proc-macro2/.cargo-checksum.json b/proc-macro2/.cargo-checksum.json new file mode 100644 index 000000000..9dfd919d1 --- /dev/null +++ b/proc-macro2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"} \ No newline at end of file diff --git a/proc-macro2/Cargo.toml b/proc-macro2/Cargo.toml new file mode 100644 index 000000000..da5378f02 --- /dev/null +++ b/proc-macro2/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "proc-macro2" +version = "0.4.30" +authors = ["Alex Crichton "] +build = "build.rs" +description = "A stable implementation of the upcoming new `proc_macro` API. Comes with an\noption, off by default, to also reimplement itself in terms of the upstream\nunstable API.\n" +homepage = "https://github.com/alexcrichton/proc-macro2" +documentation = "https://docs.rs/proc-macro2" +readme = "README.md" +keywords = ["macros"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/proc-macro2" +[package.metadata.docs.rs] +rustc-args = ["--cfg", "procmacro2_semver_exempt"] +rustdoc-args = ["--cfg", "procmacro2_semver_exempt"] +[dependencies.unicode-xid] +version = "0.1" +[dev-dependencies.quote] +version = "0.6" + +[features] +default = ["proc-macro"] +nightly = [] +proc-macro = [] +span-locations = [] +[badges.travis-ci] +repository = "alexcrichton/proc-macro2" diff --git a/proc-macro2/LICENSE-APACHE b/proc-macro2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/proc-macro2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/proc-macro2/LICENSE-MIT b/proc-macro2/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/proc-macro2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/proc-macro2/README.md b/proc-macro2/README.md new file mode 100644 index 000000000..67d523dc3 --- /dev/null +++ b/proc-macro2/README.md @@ -0,0 +1,100 @@ +# proc-macro2 + +[![Build Status](https://api.travis-ci.com/alexcrichton/proc-macro2.svg?branch=master)](https://travis-ci.com/alexcrichton/proc-macro2) +[![Latest Version](https://img.shields.io/crates/v/proc-macro2.svg)](https://crates.io/crates/proc-macro2) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/proc-macro2) + +A wrapper around the procedural macro API of the compiler's `proc_macro` crate. +This library serves three purposes: + +- **Bring proc-macro-like functionality to other contexts like build.rs and + main.rs.** Types from `proc_macro` are entirely specific to procedural macros + and cannot ever exist in code outside of a procedural macro. Meanwhile + `proc_macro2` types may exist anywhere including non-macro code. By developing + foundational libraries like [syn] and [quote] against `proc_macro2` rather + than `proc_macro`, the procedural macro ecosystem becomes easily applicable to + many other use cases and we avoid reimplementing non-macro equivalents of + those libraries. + +- **Make procedural macros unit testable.** As a consequence of being specific + to procedural macros, nothing that uses `proc_macro` can be executed from a + unit test. In order for helper libraries or components of a macro to be + testable in isolation, they must be implemented using `proc_macro2`. + +- **Provide the latest and greatest APIs across all compiler versions.** + Procedural macros were first introduced to Rust in 1.15.0 with an extremely + minimal interface. Since then, many improvements have landed to make macros + more flexible and easier to write. This library tracks the procedural macro + API of the most recent stable compiler but employs a polyfill to provide that + API consistently across any compiler since 1.15.0. + +[syn]: https://github.com/dtolnay/syn +[quote]: https://github.com/dtolnay/quote + +## Usage + +```toml +[dependencies] +proc-macro2 = "0.4" +``` + +The skeleton of a typical procedural macro typically looks like this: + +```rust +extern crate proc_macro; + +#[proc_macro_derive(MyDerive)] +pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = proc_macro2::TokenStream::from(input); + + let output: proc_macro2::TokenStream = { + /* transform input */ + }; + + proc_macro::TokenStream::from(output) +} +``` + +If parsing with [Syn], you'll use [`parse_macro_input!`] instead to propagate +parse errors correctly back to the compiler when parsing fails. + +[`parse_macro_input!`]: https://docs.rs/syn/0.15/syn/macro.parse_macro_input.html + +## Unstable features + +The default feature set of proc-macro2 tracks the most recent stable compiler +API. Functionality in `proc_macro` that is not yet stable is not exposed by +proc-macro2 by default. + +To opt into the additional APIs available in the most recent nightly compiler, +the `procmacro2_semver_exempt` config flag must be passed to rustc. As usual, we +will polyfill those nightly-only APIs all the way back to Rust 1.15.0. As these +are unstable APIs that track the nightly compiler, minor versions of proc-macro2 +may make breaking changes to them at any time. + +``` +RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build +``` + +Note that this must not only be done for your crate, but for any crate that +depends on your crate. This infectious nature is intentional, as it serves as a +reminder that you are outside of the normal semver guarantees. + +Semver exempt methods are marked as such in the proc-macro2 documentation. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/proc-macro2/build.rs b/proc-macro2/build.rs new file mode 100644 index 000000000..187255f2f --- /dev/null +++ b/proc-macro2/build.rs @@ -0,0 +1,157 @@ +// rustc-cfg emitted by the build script: +// +// "u128" +// Include u128 and i128 constructors for proc_macro2::Literal. Enabled on +// any compiler 1.26+. +// +// "use_proc_macro" +// Link to extern crate proc_macro. Available on any compiler and any target +// except wasm32. Requires "proc-macro" Cargo cfg to be enabled (default is +// enabled). On wasm32 we never link to proc_macro even if "proc-macro" cfg +// is enabled. +// +// "wrap_proc_macro" +// Wrap types from libproc_macro rather than polyfilling the whole API. +// Enabled on rustc 1.29+ as long as procmacro2_semver_exempt is not set, +// because we can't emulate the unstable API without emulating everything +// else. Also enabled unconditionally on nightly, in which case the +// procmacro2_semver_exempt surface area is implemented by using the +// nightly-only proc_macro API. +// +// "slow_extend" +// Fallback when `impl Extend for TokenStream` is not available. These impls +// were added one version later than the rest of the proc_macro token API. +// Enabled on rustc 1.29 only. +// +// "proc_macro_span" +// Enable non-dummy behavior of Span::start and Span::end methods which +// requires an unstable compiler feature. Enabled when building with +// nightly, unless `-Z allow-feature` in RUSTFLAGS disallows unstable +// features. +// +// "super_unstable" +// Implement the semver exempt API in terms of the nightly-only proc_macro +// API. Enabled when using procmacro2_semver_exempt on a nightly compiler. +// +// "span_locations" +// Provide methods Span::start and Span::end which give the line/column +// location of a token. Enabled by procmacro2_semver_exempt or the +// "span-locations" Cargo cfg. This is behind a cfg because tracking +// location inside spans is a performance hit. + +use std::env; +use std::process::Command; +use std::str; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let target = env::var("TARGET").unwrap(); + + let version = match rustc_version() { + Some(version) => version, + None => return, + }; + + if version.minor >= 26 { + println!("cargo:rustc-cfg=u128"); + } + + let semver_exempt = cfg!(procmacro2_semver_exempt); + if semver_exempt { + // https://github.com/alexcrichton/proc-macro2/issues/147 + println!("cargo:rustc-cfg=procmacro2_semver_exempt"); + } + + if semver_exempt || cfg!(feature = "span-locations") { + println!("cargo:rustc-cfg=span_locations"); + } + + if !enable_use_proc_macro(&target) { + return; + } + + println!("cargo:rustc-cfg=use_proc_macro"); + + // Rust 1.29 stabilized the necessary APIs in the `proc_macro` crate + if version.nightly || version.minor >= 29 && !semver_exempt { + println!("cargo:rustc-cfg=wrap_proc_macro"); + } + + if version.minor == 29 { + println!("cargo:rustc-cfg=slow_extend"); + } + + if version.nightly && feature_allowed("proc_macro_span") { + println!("cargo:rustc-cfg=proc_macro_span"); + } + + if semver_exempt && version.nightly { + println!("cargo:rustc-cfg=super_unstable"); + } +} + +fn enable_use_proc_macro(target: &str) -> bool { + // wasm targets don't have the `proc_macro` crate, disable this feature. + if target.contains("wasm32") { + return false; + } + + // Otherwise, only enable it if our feature is actually enabled. + cfg!(feature = "proc-macro") +} + +struct RustcVersion { + minor: u32, + nightly: bool, +} + +fn rustc_version() -> Option { + macro_rules! otry { + ($e:expr) => { + match $e { + Some(e) => e, + None => return None, + } + }; + } + + let rustc = otry!(env::var_os("RUSTC")); + let output = otry!(Command::new(rustc).arg("--version").output().ok()); + let version = otry!(str::from_utf8(&output.stdout).ok()); + let nightly = version.contains("nightly"); + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + let minor = otry!(pieces.next()); + let minor = otry!(minor.parse().ok()); + + Some(RustcVersion { + minor: minor, + nightly: nightly, + }) +} + +fn feature_allowed(feature: &str) -> bool { + // Recognized formats: + // + // -Z allow-features=feature1,feature2 + // + // -Zallow-features=feature1,feature2 + + if let Some(rustflags) = env::var_os("RUSTFLAGS") { + for mut flag in rustflags.to_string_lossy().split(' ') { + if flag.starts_with("-Z") { + flag = &flag["-Z".len()..]; + } + if flag.starts_with("allow-features=") { + flag = &flag["allow-features=".len()..]; + return flag.split(',').any(|allowed| allowed == feature); + } + } + } + + // No allow-features= flag, allowed by default. + true +} diff --git a/proc-macro2/src/fallback.rs b/proc-macro2/src/fallback.rs new file mode 100644 index 000000000..f40a87461 --- /dev/null +++ b/proc-macro2/src/fallback.rs @@ -0,0 +1,1435 @@ +#[cfg(span_locations)] +use std::cell::RefCell; +#[cfg(procmacro2_semver_exempt)] +use std::cmp; +use std::fmt; +use std::iter; +#[cfg(procmacro2_semver_exempt)] +use std::path::Path; +use std::path::PathBuf; +use std::str::FromStr; +use std::vec; + +use strnom::{block_comment, skip_whitespace, whitespace, word_break, Cursor, PResult}; +use unicode_xid::UnicodeXID; + +use {Delimiter, Punct, Spacing, TokenTree}; + +#[derive(Clone)] +pub struct TokenStream { + inner: Vec, +} + +#[derive(Debug)] +pub struct LexError; + +impl TokenStream { + pub fn new() -> TokenStream { + TokenStream { inner: Vec::new() } + } + + pub fn is_empty(&self) -> bool { + self.inner.len() == 0 + } +} + +#[cfg(span_locations)] +fn get_cursor(src: &str) -> Cursor { + // Create a dummy file & add it to the source map + SOURCE_MAP.with(|cm| { + let mut cm = cm.borrow_mut(); + let name = format!("", cm.files.len()); + let span = cm.add_file(&name, src); + Cursor { + rest: src, + off: span.lo, + } + }) +} + +#[cfg(not(span_locations))] +fn get_cursor(src: &str) -> Cursor { + Cursor { rest: src } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + // Create a dummy file & add it to the source map + let cursor = get_cursor(src); + + match token_stream(cursor) { + Ok((input, output)) => { + if skip_whitespace(input).len() != 0 { + Err(LexError) + } else { + Ok(output) + } + } + Err(LexError) => Err(LexError), + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut joint = false; + for (i, tt) in self.inner.iter().enumerate() { + if i != 0 && !joint { + write!(f, " ")?; + } + joint = false; + match *tt { + TokenTree::Group(ref tt) => { + let (start, end) = match tt.delimiter() { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + if tt.stream().into_iter().next().is_none() { + write!(f, "{} {}", start, end)? + } else { + write!(f, "{} {} {}", start, tt.stream(), end)? + } + } + TokenTree::Ident(ref tt) => write!(f, "{}", tt)?, + TokenTree::Punct(ref tt) => { + write!(f, "{}", tt.as_char())?; + match tt.spacing() { + Spacing::Alone => {} + Spacing::Joint => joint = true, + } + } + TokenTree::Literal(ref tt) => write!(f, "{}", tt)?, + } + } + + Ok(()) + } +} + +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("TokenStream ")?; + f.debug_list().entries(self.clone()).finish() + } +} + +#[cfg(use_proc_macro)] +impl From<::proc_macro::TokenStream> for TokenStream { + fn from(inner: ::proc_macro::TokenStream) -> TokenStream { + inner + .to_string() + .parse() + .expect("compiler token stream parse failed") + } +} + +#[cfg(use_proc_macro)] +impl From for ::proc_macro::TokenStream { + fn from(inner: TokenStream) -> ::proc_macro::TokenStream { + inner + .to_string() + .parse() + .expect("failed to parse to compiler tokens") + } +} + +impl From for TokenStream { + fn from(tree: TokenTree) -> TokenStream { + TokenStream { inner: vec![tree] } + } +} + +impl iter::FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let mut v = Vec::new(); + + for token in streams.into_iter() { + v.push(token); + } + + TokenStream { inner: v } + } +} + +impl iter::FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let mut v = Vec::new(); + + for stream in streams.into_iter() { + v.extend(stream.inner); + } + + TokenStream { inner: v } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner.extend(streams); + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner + .extend(streams.into_iter().flat_map(|stream| stream)); + } +} + +pub type TokenTreeIter = vec::IntoIter; + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + self.inner.into_iter() + } +} + +#[derive(Clone, PartialEq, Eq)] +pub struct SourceFile { + path: PathBuf, +} + +impl SourceFile { + /// Get the path to this source file as a string. + pub fn path(&self) -> PathBuf { + self.path.clone() + } + + pub fn is_real(&self) -> bool { + // XXX(nika): Support real files in the future? + false + } +} + +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SourceFile") + .field("path", &self.path()) + .field("is_real", &self.is_real()) + .finish() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LineColumn { + pub line: usize, + pub column: usize, +} + +#[cfg(span_locations)] +thread_local! { + static SOURCE_MAP: RefCell = RefCell::new(SourceMap { + // NOTE: We start with a single dummy file which all call_site() and + // def_site() spans reference. + files: vec![{ + #[cfg(procmacro2_semver_exempt)] + { + FileInfo { + name: "".to_owned(), + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } + + #[cfg(not(procmacro2_semver_exempt))] + { + FileInfo { + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } + }], + }); +} + +#[cfg(span_locations)] +struct FileInfo { + #[cfg(procmacro2_semver_exempt)] + name: String, + span: Span, + lines: Vec, +} + +#[cfg(span_locations)] +impl FileInfo { + fn offset_line_column(&self, offset: usize) -> LineColumn { + assert!(self.span_within(Span { + lo: offset as u32, + hi: offset as u32 + })); + let offset = offset - self.span.lo as usize; + match self.lines.binary_search(&offset) { + Ok(found) => LineColumn { + line: found + 1, + column: 0, + }, + Err(idx) => LineColumn { + line: idx, + column: offset - self.lines[idx - 1], + }, + } + } + + fn span_within(&self, span: Span) -> bool { + span.lo >= self.span.lo && span.hi <= self.span.hi + } +} + +/// Computesthe offsets of each line in the given source string. +#[cfg(span_locations)] +fn lines_offsets(s: &str) -> Vec { + let mut lines = vec![0]; + let mut prev = 0; + while let Some(len) = s[prev..].find('\n') { + prev += len + 1; + lines.push(prev); + } + lines +} + +#[cfg(span_locations)] +struct SourceMap { + files: Vec, +} + +#[cfg(span_locations)] +impl SourceMap { + fn next_start_pos(&self) -> u32 { + // Add 1 so there's always space between files. + // + // We'll always have at least 1 file, as we initialize our files list + // with a dummy file. + self.files.last().unwrap().span.hi + 1 + } + + fn add_file(&mut self, name: &str, src: &str) -> Span { + let lines = lines_offsets(src); + let lo = self.next_start_pos(); + // XXX(nika): Shouild we bother doing a checked cast or checked add here? + let span = Span { + lo: lo, + hi: lo + (src.len() as u32), + }; + + #[cfg(procmacro2_semver_exempt)] + self.files.push(FileInfo { + name: name.to_owned(), + span: span, + lines: lines, + }); + + #[cfg(not(procmacro2_semver_exempt))] + self.files.push(FileInfo { + span: span, + lines: lines, + }); + let _ = name; + + span + } + + fn fileinfo(&self, span: Span) -> &FileInfo { + for file in &self.files { + if file.span_within(span) { + return file; + } + } + panic!("Invalid span with no related FileInfo!"); + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Span { + #[cfg(span_locations)] + lo: u32, + #[cfg(span_locations)] + hi: u32, +} + +impl Span { + #[cfg(not(span_locations))] + pub fn call_site() -> Span { + Span {} + } + + #[cfg(span_locations)] + pub fn call_site() -> Span { + Span { lo: 0, hi: 0 } + } + + #[cfg(procmacro2_semver_exempt)] + pub fn def_site() -> Span { + Span::call_site() + } + + #[cfg(procmacro2_semver_exempt)] + pub fn resolved_at(&self, _other: Span) -> Span { + // Stable spans consist only of line/column information, so + // `resolved_at` and `located_at` only select which span the + // caller wants line/column information from. + *self + } + + #[cfg(procmacro2_semver_exempt)] + pub fn located_at(&self, other: Span) -> Span { + other + } + + #[cfg(procmacro2_semver_exempt)] + pub fn source_file(&self) -> SourceFile { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + SourceFile { + path: Path::new(&fi.name).to_owned(), + } + }) + } + + #[cfg(span_locations)] + pub fn start(&self) -> LineColumn { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + fi.offset_line_column(self.lo as usize) + }) + } + + #[cfg(span_locations)] + pub fn end(&self) -> LineColumn { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + let fi = cm.fileinfo(*self); + fi.offset_line_column(self.hi as usize) + }) + } + + #[cfg(procmacro2_semver_exempt)] + pub fn join(&self, other: Span) -> Option { + SOURCE_MAP.with(|cm| { + let cm = cm.borrow(); + // If `other` is not within the same FileInfo as us, return None. + if !cm.fileinfo(*self).span_within(other) { + return None; + } + Some(Span { + lo: cmp::min(self.lo, other.lo), + hi: cmp::max(self.hi, other.hi), + }) + }) + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(procmacro2_semver_exempt)] + return write!(f, "bytes({}..{})", self.lo, self.hi); + + #[cfg(not(procmacro2_semver_exempt))] + write!(f, "Span") + } +} + +pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + if cfg!(procmacro2_semver_exempt) { + debug.field("span", &span); + } +} + +#[derive(Clone)] +pub struct Group { + delimiter: Delimiter, + stream: TokenStream, + span: Span, +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + Group { + delimiter: delimiter, + stream: stream, + span: Span::call_site(), + } + } + + pub fn delimiter(&self) -> Delimiter { + self.delimiter + } + + pub fn stream(&self) -> TokenStream { + self.stream.clone() + } + + pub fn span(&self) -> Span { + self.span + } + + #[cfg(procmacro2_semver_exempt)] + pub fn span_open(&self) -> Span { + self.span + } + + #[cfg(procmacro2_semver_exempt)] + pub fn span_close(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl fmt::Display for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (left, right) = match self.delimiter { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Brace => ("{", "}"), + Delimiter::Bracket => ("[", "]"), + Delimiter::None => ("", ""), + }; + + f.write_str(left)?; + self.stream.fmt(f)?; + f.write_str(right)?; + + Ok(()) + } +} + +impl fmt::Debug for Group { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Group"); + debug.field("delimiter", &self.delimiter); + debug.field("stream", &self.stream); + #[cfg(procmacro2_semver_exempt)] + debug.field("span", &self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub struct Ident { + sym: String, + span: Span, + raw: bool, +} + +impl Ident { + fn _new(string: &str, raw: bool, span: Span) -> Ident { + validate_ident(string); + + Ident { + sym: string.to_owned(), + span: span, + raw: raw, + } + } + + pub fn new(string: &str, span: Span) -> Ident { + Ident::_new(string, false, span) + } + + pub fn new_raw(string: &str, span: Span) -> Ident { + Ident::_new(string, true, span) + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +#[inline] +fn is_ident_start(c: char) -> bool { + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || c == '_' + || (c > '\x7f' && UnicodeXID::is_xid_start(c)) +} + +#[inline] +fn is_ident_continue(c: char) -> bool { + ('a' <= c && c <= 'z') + || ('A' <= c && c <= 'Z') + || c == '_' + || ('0' <= c && c <= '9') + || (c > '\x7f' && UnicodeXID::is_xid_continue(c)) +} + +fn validate_ident(string: &str) { + let validate = string; + if validate.is_empty() { + panic!("Ident is not allowed to be empty; use Option"); + } + + if validate.bytes().all(|digit| digit >= b'0' && digit <= b'9') { + panic!("Ident cannot be a number; use Literal instead"); + } + + fn ident_ok(string: &str) -> bool { + let mut chars = string.chars(); + let first = chars.next().unwrap(); + if !is_ident_start(first) { + return false; + } + for ch in chars { + if !is_ident_continue(ch) { + return false; + } + } + true + } + + if !ident_ok(validate) { + panic!("{:?} is not a valid Ident", string); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.sym == other.sym && self.raw == other.raw + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + if self.raw { + other.starts_with("r#") && self.sym == other[2..] + } else { + self.sym == other + } + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.raw { + "r#".fmt(f)?; + } + self.sym.fmt(f) + } +} + +impl fmt::Debug for Ident { + // Ident(proc_macro), Ident(r#union) + #[cfg(not(procmacro2_semver_exempt))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_tuple("Ident"); + debug.field(&format_args!("{}", self)); + debug.finish() + } + + // Ident { + // sym: proc_macro, + // span: bytes(128..138) + // } + #[cfg(procmacro2_semver_exempt)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", self)); + debug.field("span", &self.span); + debug.finish() + } +} + +#[derive(Clone)] +pub struct Literal { + text: String, + span: Span, +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + Literal::_new(format!(concat!("{}", stringify!($kind)), n)) + } + )*) +} + +macro_rules! unsuffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + Literal::_new(n.to_string()) + } + )*) +} + +impl Literal { + fn _new(text: String) -> Literal { + Literal { + text: text, + span: Span::call_site(), + } + } + + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + #[cfg(u128)] + suffixed_numbers! { + u128_suffixed => u128, + i128_suffixed => i128, + } + + unsuffixed_numbers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + isize_unsuffixed => isize, + } + + #[cfg(u128)] + unsuffixed_numbers! { + u128_unsuffixed => u128, + i128_unsuffixed => i128, + } + + pub fn f32_unsuffixed(f: f32) -> Literal { + let mut s = f.to_string(); + if !s.contains(".") { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub fn f64_unsuffixed(f: f64) -> Literal { + let mut s = f.to_string(); + if !s.contains(".") { + s.push_str(".0"); + } + Literal::_new(s) + } + + pub fn string(t: &str) -> Literal { + let mut text = String::with_capacity(t.len() + 2); + text.push('"'); + for c in t.chars() { + if c == '\'' { + // escape_default turns this into "\'" which is unnecessary. + text.push(c); + } else { + text.extend(c.escape_default()); + } + } + text.push('"'); + Literal::_new(text) + } + + pub fn character(t: char) -> Literal { + let mut text = String::new(); + text.push('\''); + if t == '"' { + // escape_default turns this into '\"' which is unnecessary. + text.push(t); + } else { + text.extend(t.escape_default()); + } + text.push('\''); + Literal::_new(text) + } + + pub fn byte_string(bytes: &[u8]) -> Literal { + let mut escaped = "b\"".to_string(); + for b in bytes { + match *b { + b'\0' => escaped.push_str(r"\0"), + b'\t' => escaped.push_str(r"\t"), + b'\n' => escaped.push_str(r"\n"), + b'\r' => escaped.push_str(r"\r"), + b'"' => escaped.push_str("\\\""), + b'\\' => escaped.push_str("\\\\"), + b'\x20'...b'\x7E' => escaped.push(*b as char), + _ => escaped.push_str(&format!("\\x{:02X}", b)), + } + } + escaped.push('"'); + Literal::_new(escaped) + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.text.fmt(f) + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Literal"); + debug.field("lit", &format_args!("{}", self.text)); + #[cfg(procmacro2_semver_exempt)] + debug.field("span", &self.span); + debug.finish() + } +} + +fn token_stream(mut input: Cursor) -> PResult { + let mut trees = Vec::new(); + loop { + let input_no_ws = skip_whitespace(input); + if input_no_ws.rest.len() == 0 { + break; + } + if let Ok((a, tokens)) = doc_comment(input_no_ws) { + input = a; + trees.extend(tokens); + continue; + } + + let (a, tt) = match token_tree(input_no_ws) { + Ok(p) => p, + Err(_) => break, + }; + trees.push(tt); + input = a; + } + Ok((input, TokenStream { inner: trees })) +} + +#[cfg(not(span_locations))] +fn spanned<'a, T>( + input: Cursor<'a>, + f: fn(Cursor<'a>) -> PResult<'a, T>, +) -> PResult<'a, (T, ::Span)> { + let (a, b) = f(skip_whitespace(input))?; + Ok((a, ((b, ::Span::_new_stable(Span::call_site()))))) +} + +#[cfg(span_locations)] +fn spanned<'a, T>( + input: Cursor<'a>, + f: fn(Cursor<'a>) -> PResult<'a, T>, +) -> PResult<'a, (T, ::Span)> { + let input = skip_whitespace(input); + let lo = input.off; + let (a, b) = f(input)?; + let hi = a.off; + let span = ::Span::_new_stable(Span { lo: lo, hi: hi }); + Ok((a, (b, span))) +} + +fn token_tree(input: Cursor) -> PResult { + let (rest, (mut tt, span)) = spanned(input, token_kind)?; + tt.set_span(span); + Ok((rest, tt)) +} + +named!(token_kind -> TokenTree, alt!( + map!(group, |g| TokenTree::Group(::Group::_new_stable(g))) + | + map!(literal, |l| TokenTree::Literal(::Literal::_new_stable(l))) // must be before symbol + | + map!(op, TokenTree::Punct) + | + symbol_leading_ws +)); + +named!(group -> Group, alt!( + delimited!( + punct!("("), + token_stream, + punct!(")") + ) => { |ts| Group::new(Delimiter::Parenthesis, ts) } + | + delimited!( + punct!("["), + token_stream, + punct!("]") + ) => { |ts| Group::new(Delimiter::Bracket, ts) } + | + delimited!( + punct!("{"), + token_stream, + punct!("}") + ) => { |ts| Group::new(Delimiter::Brace, ts) } +)); + +fn symbol_leading_ws(input: Cursor) -> PResult { + symbol(skip_whitespace(input)) +} + +fn symbol(input: Cursor) -> PResult { + let mut chars = input.char_indices(); + + let raw = input.starts_with("r#"); + if raw { + chars.next(); + chars.next(); + } + + match chars.next() { + Some((_, ch)) if is_ident_start(ch) => {} + _ => return Err(LexError), + } + + let mut end = input.len(); + for (i, ch) in chars { + if !is_ident_continue(ch) { + end = i; + break; + } + } + + let a = &input.rest[..end]; + if a == "r#_" { + Err(LexError) + } else { + let ident = if raw { + ::Ident::_new_raw(&a[2..], ::Span::call_site()) + } else { + ::Ident::new(a, ::Span::call_site()) + }; + Ok((input.advance(end), ident.into())) + } +} + +fn literal(input: Cursor) -> PResult { + let input_no_ws = skip_whitespace(input); + + match literal_nocapture(input_no_ws) { + Ok((a, ())) => { + let start = input.len() - input_no_ws.len(); + let len = input_no_ws.len() - a.len(); + let end = start + len; + Ok((a, Literal::_new(input.rest[start..end].to_string()))) + } + Err(LexError) => Err(LexError), + } +} + +named!(literal_nocapture -> (), alt!( + string + | + byte_string + | + byte + | + character + | + float + | + int +)); + +named!(string -> (), alt!( + quoted_string + | + preceded!( + punct!("r"), + raw_string + ) => { |_| () } +)); + +named!(quoted_string -> (), delimited!( + punct!("\""), + cooked_string, + tag!("\"") +)); + +fn cooked_string(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices().peekable(); + while let Some((byte_offset, ch)) = chars.next() { + match ch { + '"' => { + return Ok((input.advance(byte_offset), ())); + } + '\r' => { + if let Some((_, '\n')) = chars.next() { + // ... + } else { + break; + } + } + '\\' => match chars.next() { + Some((_, 'x')) => { + if !backslash_x_char(&mut chars) { + break; + } + } + Some((_, 'n')) | Some((_, 'r')) | Some((_, 't')) | Some((_, '\\')) + | Some((_, '\'')) | Some((_, '"')) | Some((_, '0')) => {} + Some((_, 'u')) => { + if !backslash_u(&mut chars) { + break; + } + } + Some((_, '\n')) | Some((_, '\r')) => { + while let Some(&(_, ch)) = chars.peek() { + if ch.is_whitespace() { + chars.next(); + } else { + break; + } + } + } + _ => break, + }, + _ch => {} + } + } + Err(LexError) +} + +named!(byte_string -> (), alt!( + delimited!( + punct!("b\""), + cooked_byte_string, + tag!("\"") + ) => { |_| () } + | + preceded!( + punct!("br"), + raw_string + ) => { |_| () } +)); + +fn cooked_byte_string(mut input: Cursor) -> PResult<()> { + let mut bytes = input.bytes().enumerate(); + 'outer: while let Some((offset, b)) = bytes.next() { + match b { + b'"' => { + return Ok((input.advance(offset), ())); + } + b'\r' => { + if let Some((_, b'\n')) = bytes.next() { + // ... + } else { + break; + } + } + b'\\' => match bytes.next() { + Some((_, b'x')) => { + if !backslash_x_byte(&mut bytes) { + break; + } + } + Some((_, b'n')) | Some((_, b'r')) | Some((_, b't')) | Some((_, b'\\')) + | Some((_, b'0')) | Some((_, b'\'')) | Some((_, b'"')) => {} + Some((newline, b'\n')) | Some((newline, b'\r')) => { + let rest = input.advance(newline + 1); + for (offset, ch) in rest.char_indices() { + if !ch.is_whitespace() { + input = rest.advance(offset); + bytes = input.bytes().enumerate(); + continue 'outer; + } + } + break; + } + _ => break, + }, + b if b < 0x80 => {} + _ => break, + } + } + Err(LexError) +} + +fn raw_string(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices(); + let mut n = 0; + while let Some((byte_offset, ch)) = chars.next() { + match ch { + '"' => { + n = byte_offset; + break; + } + '#' => {} + _ => return Err(LexError), + } + } + for (byte_offset, ch) in chars { + match ch { + '"' if input.advance(byte_offset + 1).starts_with(&input.rest[..n]) => { + let rest = input.advance(byte_offset + 1 + n); + return Ok((rest, ())); + } + '\r' => {} + _ => {} + } + } + Err(LexError) +} + +named!(byte -> (), do_parse!( + punct!("b") >> + tag!("'") >> + cooked_byte >> + tag!("'") >> + (()) +)); + +fn cooked_byte(input: Cursor) -> PResult<()> { + let mut bytes = input.bytes().enumerate(); + let ok = match bytes.next().map(|(_, b)| b) { + Some(b'\\') => match bytes.next().map(|(_, b)| b) { + Some(b'x') => backslash_x_byte(&mut bytes), + Some(b'n') | Some(b'r') | Some(b't') | Some(b'\\') | Some(b'0') | Some(b'\'') + | Some(b'"') => true, + _ => false, + }, + b => b.is_some(), + }; + if ok { + match bytes.next() { + Some((offset, _)) => { + if input.chars().as_str().is_char_boundary(offset) { + Ok((input.advance(offset), ())) + } else { + Err(LexError) + } + } + None => Ok((input.advance(input.len()), ())), + } + } else { + Err(LexError) + } +} + +named!(character -> (), do_parse!( + punct!("'") >> + cooked_char >> + tag!("'") >> + (()) +)); + +fn cooked_char(input: Cursor) -> PResult<()> { + let mut chars = input.char_indices(); + let ok = match chars.next().map(|(_, ch)| ch) { + Some('\\') => match chars.next().map(|(_, ch)| ch) { + Some('x') => backslash_x_char(&mut chars), + Some('u') => backslash_u(&mut chars), + Some('n') | Some('r') | Some('t') | Some('\\') | Some('0') | Some('\'') | Some('"') => { + true + } + _ => false, + }, + ch => ch.is_some(), + }; + if ok { + match chars.next() { + Some((idx, _)) => Ok((input.advance(idx), ())), + None => Ok((input.advance(input.len()), ())), + } + } else { + Err(LexError) + } +} + +macro_rules! next_ch { + ($chars:ident @ $pat:pat $(| $rest:pat)*) => { + match $chars.next() { + Some((_, ch)) => match ch { + $pat $(| $rest)* => ch, + _ => return false, + }, + None => return false + } + }; +} + +fn backslash_x_char(chars: &mut I) -> bool +where + I: Iterator, +{ + next_ch!(chars @ '0'...'7'); + next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F'); + true +} + +fn backslash_x_byte(chars: &mut I) -> bool +where + I: Iterator, +{ + next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F'); + next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F'); + true +} + +fn backslash_u(chars: &mut I) -> bool +where + I: Iterator, +{ + next_ch!(chars @ '{'); + next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F'); + loop { + let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '_' | '}'); + if c == '}' { + return true; + } + } +} + +fn float(input: Cursor) -> PResult<()> { + let (rest, ()) = float_digits(input)?; + for suffix in &["f32", "f64"] { + if rest.starts_with(suffix) { + return word_break(rest.advance(suffix.len())); + } + } + word_break(rest) +} + +fn float_digits(input: Cursor) -> PResult<()> { + let mut chars = input.chars().peekable(); + match chars.next() { + Some(ch) if ch >= '0' && ch <= '9' => {} + _ => return Err(LexError), + } + + let mut len = 1; + let mut has_dot = false; + let mut has_exp = false; + while let Some(&ch) = chars.peek() { + match ch { + '0'...'9' | '_' => { + chars.next(); + len += 1; + } + '.' => { + if has_dot { + break; + } + chars.next(); + if chars + .peek() + .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch)) + .unwrap_or(false) + { + return Err(LexError); + } + len += 1; + has_dot = true; + } + 'e' | 'E' => { + chars.next(); + len += 1; + has_exp = true; + break; + } + _ => break, + } + } + + let rest = input.advance(len); + if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) { + return Err(LexError); + } + + if has_exp { + let mut has_exp_value = false; + while let Some(&ch) = chars.peek() { + match ch { + '+' | '-' => { + if has_exp_value { + break; + } + chars.next(); + len += 1; + } + '0'...'9' => { + chars.next(); + len += 1; + has_exp_value = true; + } + '_' => { + chars.next(); + len += 1; + } + _ => break, + } + } + if !has_exp_value { + return Err(LexError); + } + } + + Ok((input.advance(len), ())) +} + +fn int(input: Cursor) -> PResult<()> { + let (rest, ()) = digits(input)?; + for suffix in &[ + "isize", "i8", "i16", "i32", "i64", "i128", "usize", "u8", "u16", "u32", "u64", "u128", + ] { + if rest.starts_with(suffix) { + return word_break(rest.advance(suffix.len())); + } + } + word_break(rest) +} + +fn digits(mut input: Cursor) -> PResult<()> { + let base = if input.starts_with("0x") { + input = input.advance(2); + 16 + } else if input.starts_with("0o") { + input = input.advance(2); + 8 + } else if input.starts_with("0b") { + input = input.advance(2); + 2 + } else { + 10 + }; + + let mut len = 0; + let mut empty = true; + for b in input.bytes() { + let digit = match b { + b'0'...b'9' => (b - b'0') as u64, + b'a'...b'f' => 10 + (b - b'a') as u64, + b'A'...b'F' => 10 + (b - b'A') as u64, + b'_' => { + if empty && base == 10 { + return Err(LexError); + } + len += 1; + continue; + } + _ => break, + }; + if digit >= base { + return Err(LexError); + } + len += 1; + empty = false; + } + if empty { + Err(LexError) + } else { + Ok((input.advance(len), ())) + } +} + +fn op(input: Cursor) -> PResult { + let input = skip_whitespace(input); + match op_char(input) { + Ok((rest, '\'')) => { + symbol(rest)?; + Ok((rest, Punct::new('\'', Spacing::Joint))) + } + Ok((rest, ch)) => { + let kind = match op_char(rest) { + Ok(_) => Spacing::Joint, + Err(LexError) => Spacing::Alone, + }; + Ok((rest, Punct::new(ch, kind))) + } + Err(LexError) => Err(LexError), + } +} + +fn op_char(input: Cursor) -> PResult { + if input.starts_with("//") || input.starts_with("/*") { + // Do not accept `/` of a comment as an op. + return Err(LexError); + } + + let mut chars = input.chars(); + let first = match chars.next() { + Some(ch) => ch, + None => { + return Err(LexError); + } + }; + let recognized = "~!@#$%^&*-=+|;:,<.>/?'"; + if recognized.contains(first) { + Ok((input.advance(first.len_utf8()), first)) + } else { + Err(LexError) + } +} + +fn doc_comment(input: Cursor) -> PResult> { + let mut trees = Vec::new(); + let (rest, ((comment, inner), span)) = spanned(input, doc_comment_contents)?; + trees.push(TokenTree::Punct(Punct::new('#', Spacing::Alone))); + if inner { + trees.push(Punct::new('!', Spacing::Alone).into()); + } + let mut stream = vec![ + TokenTree::Ident(::Ident::new("doc", span)), + TokenTree::Punct(Punct::new('=', Spacing::Alone)), + TokenTree::Literal(::Literal::string(comment)), + ]; + for tt in stream.iter_mut() { + tt.set_span(span); + } + let group = Group::new(Delimiter::Bracket, stream.into_iter().collect()); + trees.push(::Group::_new_stable(group).into()); + for tt in trees.iter_mut() { + tt.set_span(span); + } + Ok((rest, trees)) +} + +named!(doc_comment_contents -> (&str, bool), alt!( + do_parse!( + punct!("//!") >> + s: take_until_newline_or_eof!() >> + ((s, true)) + ) + | + do_parse!( + option!(whitespace) >> + peek!(tag!("/*!")) >> + s: block_comment >> + ((s, true)) + ) + | + do_parse!( + punct!("///") >> + not!(tag!("/")) >> + s: take_until_newline_or_eof!() >> + ((s, false)) + ) + | + do_parse!( + option!(whitespace) >> + peek!(tuple!(tag!("/**"), not!(tag!("*")))) >> + s: block_comment >> + ((s, false)) + ) +)); diff --git a/proc-macro2/src/lib.rs b/proc-macro2/src/lib.rs new file mode 100644 index 000000000..7181455c8 --- /dev/null +++ b/proc-macro2/src/lib.rs @@ -0,0 +1,1156 @@ +//! A wrapper around the procedural macro API of the compiler's [`proc_macro`] +//! crate. This library serves three purposes: +//! +//! [`proc_macro`]: https://doc.rust-lang.org/proc_macro/ +//! +//! - **Bring proc-macro-like functionality to other contexts like build.rs and +//! main.rs.** Types from `proc_macro` are entirely specific to procedural +//! macros and cannot ever exist in code outside of a procedural macro. +//! Meanwhile `proc_macro2` types may exist anywhere including non-macro code. +//! By developing foundational libraries like [syn] and [quote] against +//! `proc_macro2` rather than `proc_macro`, the procedural macro ecosystem +//! becomes easily applicable to many other use cases and we avoid +//! reimplementing non-macro equivalents of those libraries. +//! +//! - **Make procedural macros unit testable.** As a consequence of being +//! specific to procedural macros, nothing that uses `proc_macro` can be +//! executed from a unit test. In order for helper libraries or components of +//! a macro to be testable in isolation, they must be implemented using +//! `proc_macro2`. +//! +//! - **Provide the latest and greatest APIs across all compiler versions.** +//! Procedural macros were first introduced to Rust in 1.15.0 with an +//! extremely minimal interface. Since then, many improvements have landed to +//! make macros more flexible and easier to write. This library tracks the +//! procedural macro API of the most recent stable compiler but employs a +//! polyfill to provide that API consistently across any compiler since +//! 1.15.0. +//! +//! [syn]: https://github.com/dtolnay/syn +//! [quote]: https://github.com/dtolnay/quote +//! +//! # Usage +//! +//! The skeleton of a typical procedural macro typically looks like this: +//! +//! ```edition2018 +//! extern crate proc_macro; +//! +//! # const IGNORE: &str = stringify! { +//! #[proc_macro_derive(MyDerive)] +//! # }; +//! pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +//! let input = proc_macro2::TokenStream::from(input); +//! +//! let output: proc_macro2::TokenStream = { +//! /* transform input */ +//! # input +//! }; +//! +//! proc_macro::TokenStream::from(output) +//! } +//! ``` +//! +//! If parsing with [Syn], you'll use [`parse_macro_input!`] instead to +//! propagate parse errors correctly back to the compiler when parsing fails. +//! +//! [`parse_macro_input!`]: https://docs.rs/syn/0.15/syn/macro.parse_macro_input.html +//! +//! # Unstable features +//! +//! The default feature set of proc-macro2 tracks the most recent stable +//! compiler API. Functionality in `proc_macro` that is not yet stable is not +//! exposed by proc-macro2 by default. +//! +//! To opt into the additional APIs available in the most recent nightly +//! compiler, the `procmacro2_semver_exempt` config flag must be passed to +//! rustc. As usual, we will polyfill those nightly-only APIs all the way back +//! to Rust 1.15.0. As these are unstable APIs that track the nightly compiler, +//! minor versions of proc-macro2 may make breaking changes to them at any time. +//! +//! ```sh +//! RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo build +//! ``` +//! +//! Note that this must not only be done for your crate, but for any crate that +//! depends on your crate. This infectious nature is intentional, as it serves +//! as a reminder that you are outside of the normal semver guarantees. +//! +//! Semver exempt methods are marked as such in the proc-macro2 documentation. + +// Proc-macro2 types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/proc-macro2/0.4.30")] +#![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))] +#![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))] + +#[cfg(use_proc_macro)] +extern crate proc_macro; +extern crate unicode_xid; + +use std::cmp::Ordering; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; +use std::marker; +#[cfg(procmacro2_semver_exempt)] +use std::path::PathBuf; +use std::rc::Rc; +use std::str::FromStr; + +#[macro_use] +mod strnom; +mod fallback; + +#[cfg(not(wrap_proc_macro))] +use fallback as imp; +#[path = "wrapper.rs"] +#[cfg(wrap_proc_macro)] +mod imp; + +/// An abstract stream of tokens, or more concretely a sequence of token trees. +/// +/// This type provides interfaces for iterating over token trees and for +/// collecting token trees into one stream. +/// +/// Token stream is both the input and output of `#[proc_macro]`, +/// `#[proc_macro_attribute]` and `#[proc_macro_derive]` definitions. +#[derive(Clone)] +pub struct TokenStream { + inner: imp::TokenStream, + _marker: marker::PhantomData>, +} + +/// Error returned from `TokenStream::from_str`. +pub struct LexError { + inner: imp::LexError, + _marker: marker::PhantomData>, +} + +impl TokenStream { + fn _new(inner: imp::TokenStream) -> TokenStream { + TokenStream { + inner: inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::TokenStream) -> TokenStream { + TokenStream { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + /// Returns an empty `TokenStream` containing no token trees. + pub fn new() -> TokenStream { + TokenStream::_new(imp::TokenStream::new()) + } + + #[deprecated(since = "0.4.4", note = "please use TokenStream::new")] + pub fn empty() -> TokenStream { + TokenStream::new() + } + + /// Checks if this `TokenStream` is empty. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + +/// `TokenStream::default()` returns an empty stream, +/// i.e. this is equivalent with `TokenStream::new()`. +impl Default for TokenStream { + fn default() -> Self { + TokenStream::new() + } +} + +/// Attempts to break the string into tokens and parse those tokens into a token +/// stream. +/// +/// May fail for a number of reasons, for example, if the string contains +/// unbalanced delimiters or characters not existing in the language. +/// +/// NOTE: Some errors may cause panics instead of returning `LexError`. We +/// reserve the right to change these errors into `LexError`s later. +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + let e = src.parse().map_err(|e| LexError { + inner: e, + _marker: marker::PhantomData, + })?; + Ok(TokenStream::_new(e)) + } +} + +#[cfg(use_proc_macro)] +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> TokenStream { + TokenStream::_new(inner.into()) + } +} + +#[cfg(use_proc_macro)] +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> proc_macro::TokenStream { + inner.inner.into() + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner.extend(streams) + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + self.inner + .extend(streams.into_iter().map(|stream| stream.inner)) + } +} + +/// Collects a number of token trees into a single stream. +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().collect()) + } +} +impl FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + TokenStream::_new(streams.into_iter().map(|i| i.inner).collect()) + } +} + +/// Prints the token stream as a string that is supposed to be losslessly +/// convertible back into the same token stream (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// Prints token in a form convenient for debugging. +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// The source file of a given `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg(procmacro2_semver_exempt)] +#[derive(Clone, PartialEq, Eq)] +pub struct SourceFile { + inner: imp::SourceFile, + _marker: marker::PhantomData>, +} + +#[cfg(procmacro2_semver_exempt)] +impl SourceFile { + fn _new(inner: imp::SourceFile) -> Self { + SourceFile { + inner: inner, + _marker: marker::PhantomData, + } + } + + /// Get the path to this source file. + /// + /// ### Note + /// + /// If the code span associated with this `SourceFile` was generated by an + /// external macro, this may not be an actual path on the filesystem. Use + /// [`is_real`] to check. + /// + /// Also note that even if `is_real` returns `true`, if + /// `--remap-path-prefix` was passed on the command line, the path as given + /// may not actually be valid. + /// + /// [`is_real`]: #method.is_real + pub fn path(&self) -> PathBuf { + self.inner.path() + } + + /// Returns `true` if this source file is a real source file, and not + /// generated by an external macro's expansion. + pub fn is_real(&self) -> bool { + self.inner.is_real() + } +} + +#[cfg(procmacro2_semver_exempt)] +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A line-column pair representing the start or end of a `Span`. +/// +/// This type is semver exempt and not exposed by default. +#[cfg(span_locations)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LineColumn { + /// The 1-indexed line in the source file on which the span starts or ends + /// (inclusive). + pub line: usize, + /// The 0-indexed column (in UTF-8 characters) in the source file on which + /// the span starts or ends (inclusive). + pub column: usize, +} + +/// A region of source code, along with macro expansion information. +#[derive(Copy, Clone)] +pub struct Span { + inner: imp::Span, + _marker: marker::PhantomData>, +} + +impl Span { + fn _new(inner: imp::Span) -> Span { + Span { + inner: inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::Span) -> Span { + Span { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + /// The span of the invocation of the current procedural macro. + /// + /// Identifiers created with this span will be resolved as if they were + /// written directly at the macro call location (call-site hygiene) and + /// other code at the macro call site will be able to refer to them as well. + pub fn call_site() -> Span { + Span::_new(imp::Span::call_site()) + } + + /// A span that resolves at the macro definition site. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn def_site() -> Span { + Span::_new(imp::Span::def_site()) + } + + /// Creates a new span with the same line/column information as `self` but + /// that resolves symbols as though it were at `other`. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn resolved_at(&self, other: Span) -> Span { + Span::_new(self.inner.resolved_at(other.inner)) + } + + /// Creates a new span with the same name resolution behavior as `self` but + /// with the line/column information of `other`. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn located_at(&self, other: Span) -> Span { + Span::_new(self.inner.located_at(other.inner)) + } + + /// Convert `proc_macro2::Span` to `proc_macro::Span`. + /// + /// This method is available when building with a nightly compiler, or when + /// building with rustc 1.29+ *without* semver exempt features. + /// + /// # Panics + /// + /// Panics if called from outside of a procedural macro. Unlike + /// `proc_macro2::Span`, the `proc_macro::Span` type can only exist within + /// the context of a procedural macro invocation. + #[cfg(wrap_proc_macro)] + pub fn unwrap(self) -> proc_macro::Span { + self.inner.unwrap() + } + + // Soft deprecated. Please use Span::unwrap. + #[cfg(wrap_proc_macro)] + #[doc(hidden)] + pub fn unstable(self) -> proc_macro::Span { + self.unwrap() + } + + /// The original source file into which this span points. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn source_file(&self) -> SourceFile { + SourceFile::_new(self.inner.source_file()) + } + + /// Get the starting line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] + pub fn start(&self) -> LineColumn { + let imp::LineColumn { line, column } = self.inner.start(); + LineColumn { + line: line, + column: column, + } + } + + /// Get the ending line/column in the source file for this span. + /// + /// This method requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] + pub fn end(&self) -> LineColumn { + let imp::LineColumn { line, column } = self.inner.end(); + LineColumn { + line: line, + column: column, + } + } + + /// Create a new span encompassing `self` and `other`. + /// + /// Returns `None` if `self` and `other` are from different files. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn join(&self, other: Span) -> Option { + self.inner.join(other.inner).map(Span::_new) + } + + /// Compares to spans to see if they're equal. + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn eq(&self, other: &Span) -> bool { + self.inner.eq(&other.inner) + } +} + +/// Prints a span in a form convenient for debugging. +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). +#[derive(Clone)] +pub enum TokenTree { + /// A token stream surrounded by bracket delimiters. + Group(Group), + /// An identifier. + Ident(Ident), + /// A single punctuation character (`+`, `,`, `$`, etc.). + Punct(Punct), + /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. + Literal(Literal), +} + +impl TokenTree { + /// Returns the span of this tree, delegating to the `span` method of + /// the contained token or a delimited stream. + pub fn span(&self) -> Span { + match *self { + TokenTree::Group(ref t) => t.span(), + TokenTree::Ident(ref t) => t.span(), + TokenTree::Punct(ref t) => t.span(), + TokenTree::Literal(ref t) => t.span(), + } + } + + /// Configures the span for *only this token*. + /// + /// Note that if this token is a `Group` then this method will not configure + /// the span of each of the internal tokens, this will simply delegate to + /// the `set_span` method of each variant. + pub fn set_span(&mut self, span: Span) { + match *self { + TokenTree::Group(ref mut t) => t.set_span(span), + TokenTree::Ident(ref mut t) => t.set_span(span), + TokenTree::Punct(ref mut t) => t.set_span(span), + TokenTree::Literal(ref mut t) => t.set_span(span), + } + } +} + +impl From for TokenTree { + fn from(g: Group) -> TokenTree { + TokenTree::Group(g) + } +} + +impl From for TokenTree { + fn from(g: Ident) -> TokenTree { + TokenTree::Ident(g) + } +} + +impl From for TokenTree { + fn from(g: Punct) -> TokenTree { + TokenTree::Punct(g) + } +} + +impl From for TokenTree { + fn from(g: Literal) -> TokenTree { + TokenTree::Literal(g) + } +} + +/// Prints the token tree as a string that is supposed to be losslessly +/// convertible back into the same token tree (modulo spans), except for +/// possibly `TokenTree::Group`s with `Delimiter::None` delimiters and negative +/// numeric literals. +impl fmt::Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TokenTree::Group(ref t) => t.fmt(f), + TokenTree::Ident(ref t) => t.fmt(f), + TokenTree::Punct(ref t) => t.fmt(f), + TokenTree::Literal(ref t) => t.fmt(f), + } + } +} + +/// Prints token tree in a form convenient for debugging. +impl fmt::Debug for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Each of these has the name in the struct type in the derived debug, + // so don't bother with an extra layer of indirection + match *self { + TokenTree::Group(ref t) => t.fmt(f), + TokenTree::Ident(ref t) => { + let mut debug = f.debug_struct("Ident"); + debug.field("sym", &format_args!("{}", t)); + imp::debug_span_field_if_nontrivial(&mut debug, t.span().inner); + debug.finish() + } + TokenTree::Punct(ref t) => t.fmt(f), + TokenTree::Literal(ref t) => t.fmt(f), + } + } +} + +/// A delimited token stream. +/// +/// A `Group` internally contains a `TokenStream` which is surrounded by +/// `Delimiter`s. +#[derive(Clone)] +pub struct Group { + inner: imp::Group, +} + +/// Describes how a sequence of token trees is delimited. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Delimiter { + /// `( ... )` + Parenthesis, + /// `{ ... }` + Brace, + /// `[ ... ]` + Bracket, + /// `Ø ... Ø` + /// + /// An implicit delimiter, that may, for example, appear around tokens + /// coming from a "macro variable" `$var`. It is important to preserve + /// operator priorities in cases like `$var * 3` where `$var` is `1 + 2`. + /// Implicit delimiters may not survive roundtrip of a token stream through + /// a string. + None, +} + +impl Group { + fn _new(inner: imp::Group) -> Self { + Group { inner: inner } + } + + fn _new_stable(inner: fallback::Group) -> Self { + Group { + inner: inner.into(), + } + } + + /// Creates a new `Group` with the given delimiter and token stream. + /// + /// This constructor will set the span for this group to + /// `Span::call_site()`. To change the span you can use the `set_span` + /// method below. + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + Group { + inner: imp::Group::new(delimiter, stream.inner), + } + } + + /// Returns the delimiter of this `Group` + pub fn delimiter(&self) -> Delimiter { + self.inner.delimiter() + } + + /// Returns the `TokenStream` of tokens that are delimited in this `Group`. + /// + /// Note that the returned token stream does not include the delimiter + /// returned above. + pub fn stream(&self) -> TokenStream { + TokenStream::_new(self.inner.stream()) + } + + /// Returns the span for the delimiters of this token stream, spanning the + /// entire `Group`. + /// + /// ```text + /// pub fn span(&self) -> Span { + /// ^^^^^^^ + /// ``` + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Returns the span pointing to the opening delimiter of this group. + /// + /// ```text + /// pub fn span_open(&self) -> Span { + /// ^ + /// ``` + #[cfg(procmacro2_semver_exempt)] + pub fn span_open(&self) -> Span { + Span::_new(self.inner.span_open()) + } + + /// Returns the span pointing to the closing delimiter of this group. + /// + /// ```text + /// pub fn span_close(&self) -> Span { + /// ^ + /// ``` + #[cfg(procmacro2_semver_exempt)] + pub fn span_close(&self) -> Span { + Span::_new(self.inner.span_close()) + } + + /// Configures the span for this `Group`'s delimiters, but not its internal + /// tokens. + /// + /// This method will **not** set the span of all the internal tokens spanned + /// by this group, but rather it will only set the span of the delimiter + /// tokens at the level of the `Group`. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner) + } +} + +/// Prints the group as a string that should be losslessly convertible back +/// into the same group (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters. +impl fmt::Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, formatter) + } +} + +impl fmt::Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +/// An `Punct` is an single punctuation character like `+`, `-` or `#`. +/// +/// Multicharacter operators like `+=` are represented as two instances of +/// `Punct` with different forms of `Spacing` returned. +#[derive(Clone)] +pub struct Punct { + op: char, + spacing: Spacing, + span: Span, +} + +/// Whether an `Punct` is followed immediately by another `Punct` or followed by +/// another token or whitespace. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Spacing { + /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. + Alone, + /// E.g. `+` is `Joint` in `+=` or `'#`. + /// + /// Additionally, single quote `'` can join with identifiers to form + /// lifetimes `'ident`. + Joint, +} + +impl Punct { + /// Creates a new `Punct` from the given character and spacing. + /// + /// The `ch` argument must be a valid punctuation character permitted by the + /// language, otherwise the function will panic. + /// + /// The returned `Punct` will have the default span of `Span::call_site()` + /// which can be further configured with the `set_span` method below. + pub fn new(op: char, spacing: Spacing) -> Punct { + Punct { + op: op, + spacing: spacing, + span: Span::call_site(), + } + } + + /// Returns the value of this punctuation character as `char`. + pub fn as_char(&self) -> char { + self.op + } + + /// Returns the spacing of this punctuation character, indicating whether + /// it's immediately followed by another `Punct` in the token stream, so + /// they can potentially be combined into a multicharacter operator + /// (`Joint`), or it's followed by some other token or whitespace (`Alone`) + /// so the operator has certainly ended. + pub fn spacing(&self) -> Spacing { + self.spacing + } + + /// Returns the span for this punctuation character. + pub fn span(&self) -> Span { + self.span + } + + /// Configure the span for this punctuation character. + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + +/// Prints the punctuation character as a string that should be losslessly +/// convertible back into the same character. +impl fmt::Display for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.op.fmt(f) + } +} + +impl fmt::Debug for Punct { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut debug = fmt.debug_struct("Punct"); + debug.field("op", &self.op); + debug.field("spacing", &self.spacing); + imp::debug_span_field_if_nontrivial(&mut debug, self.span.inner); + debug.finish() + } +} + +/// A word of Rust code, which may be a keyword or legal variable name. +/// +/// An identifier consists of at least one Unicode code point, the first of +/// which has the XID_Start property and the rest of which have the XID_Continue +/// property. +/// +/// - The empty string is not an identifier. Use `Option`. +/// - A lifetime is not an identifier. Use `syn::Lifetime` instead. +/// +/// An identifier constructed with `Ident::new` is permitted to be a Rust +/// keyword, though parsing one through its [`Parse`] implementation rejects +/// Rust keywords. Use `input.call(Ident::parse_any)` when parsing to match the +/// behaviour of `Ident::new`. +/// +/// [`Parse`]: https://docs.rs/syn/0.15/syn/parse/trait.Parse.html +/// +/// # Examples +/// +/// A new ident can be created from a string using the `Ident::new` function. +/// A span must be provided explicitly which governs the name resolution +/// behavior of the resulting identifier. +/// +/// ```edition2018 +/// use proc_macro2::{Ident, Span}; +/// +/// fn main() { +/// let call_ident = Ident::new("calligraphy", Span::call_site()); +/// +/// println!("{}", call_ident); +/// } +/// ``` +/// +/// An ident can be interpolated into a token stream using the `quote!` macro. +/// +/// ```edition2018 +/// use proc_macro2::{Ident, Span}; +/// use quote::quote; +/// +/// fn main() { +/// let ident = Ident::new("demo", Span::call_site()); +/// +/// // Create a variable binding whose name is this ident. +/// let expanded = quote! { let #ident = 10; }; +/// +/// // Create a variable binding with a slightly different name. +/// let temp_ident = Ident::new(&format!("new_{}", ident), Span::call_site()); +/// let expanded = quote! { let #temp_ident = 10; }; +/// } +/// ``` +/// +/// A string representation of the ident is available through the `to_string()` +/// method. +/// +/// ```edition2018 +/// # use proc_macro2::{Ident, Span}; +/// # +/// # let ident = Ident::new("another_identifier", Span::call_site()); +/// # +/// // Examine the ident as a string. +/// let ident_string = ident.to_string(); +/// if ident_string.len() > 60 { +/// println!("Very long identifier: {}", ident_string) +/// } +/// ``` +#[derive(Clone)] +pub struct Ident { + inner: imp::Ident, + _marker: marker::PhantomData>, +} + +impl Ident { + fn _new(inner: imp::Ident) -> Ident { + Ident { + inner: inner, + _marker: marker::PhantomData, + } + } + + /// Creates a new `Ident` with the given `string` as well as the specified + /// `span`. + /// + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. + /// + /// Note that `span`, currently in rustc, configures the hygiene information + /// for this identifier. + /// + /// As of this time `Span::call_site()` explicitly opts-in to "call-site" + /// hygiene meaning that identifiers created with this span will be resolved + /// as if they were written directly at the location of the macro call, and + /// other code at the macro call site will be able to refer to them as well. + /// + /// Later spans like `Span::def_site()` will allow to opt-in to + /// "definition-site" hygiene meaning that identifiers created with this + /// span will be resolved at the location of the macro definition and other + /// code at the macro call site will not be able to refer to them. + /// + /// Due to the current importance of hygiene this constructor, unlike other + /// tokens, requires a `Span` to be specified at construction. + /// + /// # Panics + /// + /// Panics if the input string is neither a keyword nor a legal variable + /// name. If you are not sure whether the string contains an identifier and + /// need to handle an error case, use + /// syn::parse_str::<Ident> + /// rather than `Ident::new`. + pub fn new(string: &str, span: Span) -> Ident { + Ident::_new(imp::Ident::new(string, span.inner)) + } + + /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). + /// + /// This method is semver exempt and not exposed by default. + #[cfg(procmacro2_semver_exempt)] + pub fn new_raw(string: &str, span: Span) -> Ident { + Ident::_new_raw(string, span) + } + + fn _new_raw(string: &str, span: Span) -> Ident { + Ident::_new(imp::Ident::new_raw(string, span.inner)) + } + + /// Returns the span of this `Ident`. + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + /// Configures the span of this `Ident`, possibly changing its hygiene + /// context. + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + self.inner == other.inner + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + self.inner == other + } +} + +impl Eq for Ident {} + +impl PartialOrd for Ident { + fn partial_cmp(&self, other: &Ident) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Ident { + fn cmp(&self, other: &Ident) -> Ordering { + self.to_string().cmp(&other.to_string()) + } +} + +impl Hash for Ident { + fn hash(&self, hasher: &mut H) { + self.to_string().hash(hasher) + } +} + +/// Prints the identifier as a string that should be losslessly convertible back +/// into the same identifier. +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// A literal string (`"hello"`), byte string (`b"hello"`), character (`'a'`), +/// byte character (`b'a'`), an integer or floating point number with or without +/// a suffix (`1`, `1u8`, `2.3`, `2.3f32`). +/// +/// Boolean literals like `true` and `false` do not belong here, they are +/// `Ident`s. +#[derive(Clone)] +pub struct Literal { + inner: imp::Literal, + _marker: marker::PhantomData>, +} + +macro_rules! suffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new suffixed integer literal with the specified value. + /// + /// This function will create an integer like `1u32` where the integer + /// value specified is the first part of the token and the integral is + /// also suffixed at the end. Literals created from negative numbers may + /// not survive rountrips through `TokenStream` or strings and may be + /// broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +macro_rules! unsuffixed_int_literals { + ($($name:ident => $kind:ident,)*) => ($( + /// Creates a new unsuffixed integer literal with the specified value. + /// + /// This function will create an integer like `1` where the integer + /// value specified is the first part of the token. No suffix is + /// specified on this token, meaning that invocations like + /// `Literal::i8_unsuffixed(1)` are equivalent to + /// `Literal::u32_unsuffixed(1)`. Literals created from negative numbers + /// may not survive rountrips through `TokenStream` or strings and may + /// be broken into two tokens (`-` and positive literal). + /// + /// Literals created through this method have the `Span::call_site()` + /// span by default, which can be configured with the `set_span` method + /// below. + pub fn $name(n: $kind) -> Literal { + Literal::_new(imp::Literal::$name(n)) + } + )*) +} + +impl Literal { + fn _new(inner: imp::Literal) -> Literal { + Literal { + inner: inner, + _marker: marker::PhantomData, + } + } + + fn _new_stable(inner: fallback::Literal) -> Literal { + Literal { + inner: inner.into(), + _marker: marker::PhantomData, + } + } + + suffixed_int_literals! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + isize_suffixed => isize, + } + + #[cfg(u128)] + suffixed_int_literals! { + u128_suffixed => u128, + i128_suffixed => i128, + } + + unsuffixed_int_literals! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + isize_unsuffixed => isize, + } + + #[cfg(u128)] + unsuffixed_int_literals! { + u128_unsuffixed => u128, + i128_unsuffixed => i128, + } + + pub fn f64_unsuffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_unsuffixed(f)) + } + + pub fn f64_suffixed(f: f64) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f64_suffixed(f)) + } + + /// Creates a new unsuffixed floating-point literal. + /// + /// This constructor is similar to those like `Literal::i8_unsuffixed` where + /// the float's value is emitted directly into the token but no suffix is + /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and + /// positive literal). + /// + /// # Panics + /// + /// This function requires that the specified float is finite, for example + /// if it is infinity or NaN this function will panic. + pub fn f32_unsuffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_unsuffixed(f)) + } + + pub fn f32_suffixed(f: f32) -> Literal { + assert!(f.is_finite()); + Literal::_new(imp::Literal::f32_suffixed(f)) + } + + pub fn string(string: &str) -> Literal { + Literal::_new(imp::Literal::string(string)) + } + + pub fn character(ch: char) -> Literal { + Literal::_new(imp::Literal::character(ch)) + } + + pub fn byte_string(s: &[u8]) -> Literal { + Literal::_new(imp::Literal::byte_string(s)) + } + + pub fn span(&self) -> Span { + Span::_new(self.inner.span()) + } + + pub fn set_span(&mut self, span: Span) { + self.inner.set_span(span.inner); + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +/// Public implementation details for the `TokenStream` type, such as iterators. +pub mod token_stream { + use std::fmt; + use std::marker; + use std::rc::Rc; + + use imp; + pub use TokenStream; + use TokenTree; + + /// An iterator over `TokenStream`'s `TokenTree`s. + /// + /// The iteration is "shallow", e.g. the iterator doesn't recurse into + /// delimited groups, and returns whole groups as token trees. + #[derive(Clone)] + pub struct IntoIter { + inner: imp::TokenTreeIter, + _marker: marker::PhantomData>, + } + + impl Iterator for IntoIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + self.inner.next() + } + } + + impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } + } + + impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.inner.into_iter(), + _marker: marker::PhantomData, + } + } + } +} diff --git a/proc-macro2/src/strnom.rs b/proc-macro2/src/strnom.rs new file mode 100644 index 000000000..96789d569 --- /dev/null +++ b/proc-macro2/src/strnom.rs @@ -0,0 +1,393 @@ +//! Adapted from [`nom`](https://github.com/Geal/nom). + +use std::str::{Bytes, CharIndices, Chars}; + +use unicode_xid::UnicodeXID; + +use fallback::LexError; + +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Cursor<'a> { + pub rest: &'a str, + #[cfg(span_locations)] + pub off: u32, +} + +impl<'a> Cursor<'a> { + #[cfg(not(span_locations))] + pub fn advance(&self, amt: usize) -> Cursor<'a> { + Cursor { + rest: &self.rest[amt..], + } + } + #[cfg(span_locations)] + pub fn advance(&self, amt: usize) -> Cursor<'a> { + Cursor { + rest: &self.rest[amt..], + off: self.off + (amt as u32), + } + } + + pub fn find(&self, p: char) -> Option { + self.rest.find(p) + } + + pub fn starts_with(&self, s: &str) -> bool { + self.rest.starts_with(s) + } + + pub fn is_empty(&self) -> bool { + self.rest.is_empty() + } + + pub fn len(&self) -> usize { + self.rest.len() + } + + pub fn as_bytes(&self) -> &'a [u8] { + self.rest.as_bytes() + } + + pub fn bytes(&self) -> Bytes<'a> { + self.rest.bytes() + } + + pub fn chars(&self) -> Chars<'a> { + self.rest.chars() + } + + pub fn char_indices(&self) -> CharIndices<'a> { + self.rest.char_indices() + } +} + +pub type PResult<'a, O> = Result<(Cursor<'a>, O), LexError>; + +pub fn whitespace(input: Cursor) -> PResult<()> { + if input.is_empty() { + return Err(LexError); + } + + let bytes = input.as_bytes(); + let mut i = 0; + while i < bytes.len() { + let s = input.advance(i); + if bytes[i] == b'/' { + if s.starts_with("//") + && (!s.starts_with("///") || s.starts_with("////")) + && !s.starts_with("//!") + { + if let Some(len) = s.find('\n') { + i += len + 1; + continue; + } + break; + } else if s.starts_with("/**/") { + i += 4; + continue; + } else if s.starts_with("/*") + && (!s.starts_with("/**") || s.starts_with("/***")) + && !s.starts_with("/*!") + { + let (_, com) = block_comment(s)?; + i += com.len(); + continue; + } + } + match bytes[i] { + b' ' | 0x09...0x0d => { + i += 1; + continue; + } + b if b <= 0x7f => {} + _ => { + let ch = s.chars().next().unwrap(); + if is_whitespace(ch) { + i += ch.len_utf8(); + continue; + } + } + } + return if i > 0 { Ok((s, ())) } else { Err(LexError) }; + } + Ok((input.advance(input.len()), ())) +} + +pub fn block_comment(input: Cursor) -> PResult<&str> { + if !input.starts_with("/*") { + return Err(LexError); + } + + let mut depth = 0; + let bytes = input.as_bytes(); + let mut i = 0; + let upper = bytes.len() - 1; + while i < upper { + if bytes[i] == b'/' && bytes[i + 1] == b'*' { + depth += 1; + i += 1; // eat '*' + } else if bytes[i] == b'*' && bytes[i + 1] == b'/' { + depth -= 1; + if depth == 0 { + return Ok((input.advance(i + 2), &input.rest[..i + 2])); + } + i += 1; // eat '/' + } + i += 1; + } + Err(LexError) +} + +pub fn skip_whitespace(input: Cursor) -> Cursor { + match whitespace(input) { + Ok((rest, _)) => rest, + Err(LexError) => input, + } +} + +fn is_whitespace(ch: char) -> bool { + // Rust treats left-to-right mark and right-to-left mark as whitespace + ch.is_whitespace() || ch == '\u{200e}' || ch == '\u{200f}' +} + +pub fn word_break(input: Cursor) -> PResult<()> { + match input.chars().next() { + Some(ch) if UnicodeXID::is_xid_continue(ch) => Err(LexError), + Some(_) | None => Ok((input, ())), + } +} + +macro_rules! named { + ($name:ident -> $o:ty, $submac:ident!( $($args:tt)* )) => { + fn $name<'a>(i: Cursor<'a>) -> $crate::strnom::PResult<'a, $o> { + $submac!(i, $($args)*) + } + }; +} + +macro_rules! alt { + ($i:expr, $e:ident | $($rest:tt)*) => { + alt!($i, call!($e) | $($rest)*) + }; + + ($i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => { + match $subrule!($i, $($args)*) { + res @ Ok(_) => res, + _ => alt!($i, $($rest)*) + } + }; + + ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)+) => { + match $subrule!($i, $($args)*) { + Ok((i, o)) => Ok((i, $gen(o))), + Err(LexError) => alt!($i, $($rest)*) + } + }; + + ($i:expr, $e:ident => { $gen:expr } | $($rest:tt)*) => { + alt!($i, call!($e) => { $gen } | $($rest)*) + }; + + ($i:expr, $e:ident => { $gen:expr }) => { + alt!($i, call!($e) => { $gen }) + }; + + ($i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr }) => { + match $subrule!($i, $($args)*) { + Ok((i, o)) => Ok((i, $gen(o))), + Err(LexError) => Err(LexError), + } + }; + + ($i:expr, $e:ident) => { + alt!($i, call!($e)) + }; + + ($i:expr, $subrule:ident!( $($args:tt)*)) => { + $subrule!($i, $($args)*) + }; +} + +macro_rules! do_parse { + ($i:expr, ( $($rest:expr),* )) => { + Ok(($i, ( $($rest),* ))) + }; + + ($i:expr, $e:ident >> $($rest:tt)*) => { + do_parse!($i, call!($e) >> $($rest)*) + }; + + ($i:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, _)) => do_parse!(i, $($rest)*), + } + }; + + ($i:expr, $field:ident : $e:ident >> $($rest:tt)*) => { + do_parse!($i, $field: call!($e) >> $($rest)*) + }; + + ($i:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => { + let $field = o; + do_parse!(i, $($rest)*) + }, + } + }; +} + +macro_rules! peek { + ($i:expr, $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Ok((_, o)) => Ok(($i, o)), + Err(LexError) => Err(LexError), + } + }; +} + +macro_rules! call { + ($i:expr, $fun:expr $(, $args:expr)*) => { + $fun($i $(, $args)*) + }; +} + +macro_rules! option { + ($i:expr, $f:expr) => { + match $f($i) { + Ok((i, o)) => Ok((i, Some(o))), + Err(LexError) => Ok(($i, None)), + } + }; +} + +macro_rules! take_until_newline_or_eof { + ($i:expr,) => {{ + if $i.len() == 0 { + Ok(($i, "")) + } else { + match $i.find('\n') { + Some(i) => Ok(($i.advance(i), &$i.rest[..i])), + None => Ok(($i.advance($i.len()), &$i.rest[..$i.len()])), + } + } + }}; +} + +macro_rules! tuple { + ($i:expr, $($rest:tt)*) => { + tuple_parser!($i, (), $($rest)*) + }; +} + +/// Do not use directly. Use `tuple!`. +macro_rules! tuple_parser { + ($i:expr, ($($parsed:tt),*), $e:ident, $($rest:tt)*) => { + tuple_parser!($i, ($($parsed),*), call!($e), $($rest)*) + }; + + ($i:expr, (), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => tuple_parser!(i, (o), $($rest)*), + } + }; + + ($i:expr, ($($parsed:tt)*), $submac:ident!( $($args:tt)* ), $($rest:tt)*) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => tuple_parser!(i, ($($parsed)* , o), $($rest)*), + } + }; + + ($i:expr, ($($parsed:tt),*), $e:ident) => { + tuple_parser!($i, ($($parsed),*), call!($e)) + }; + + ($i:expr, (), $submac:ident!( $($args:tt)* )) => { + $submac!($i, $($args)*) + }; + + ($i:expr, ($($parsed:expr),*), $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => Ok((i, ($($parsed),*, o))) + } + }; + + ($i:expr, ($($parsed:expr),*)) => { + Ok(($i, ($($parsed),*))) + }; +} + +macro_rules! not { + ($i:expr, $submac:ident!( $($args:tt)* )) => { + match $submac!($i, $($args)*) { + Ok((_, _)) => Err(LexError), + Err(LexError) => Ok(($i, ())), + } + }; +} + +macro_rules! tag { + ($i:expr, $tag:expr) => { + if $i.starts_with($tag) { + Ok(($i.advance($tag.len()), &$i.rest[..$tag.len()])) + } else { + Err(LexError) + } + }; +} + +macro_rules! punct { + ($i:expr, $punct:expr) => { + $crate::strnom::punct($i, $punct) + }; +} + +/// Do not use directly. Use `punct!`. +pub fn punct<'a>(input: Cursor<'a>, token: &'static str) -> PResult<'a, &'a str> { + let input = skip_whitespace(input); + if input.starts_with(token) { + Ok((input.advance(token.len()), token)) + } else { + Err(LexError) + } +} + +macro_rules! preceded { + ($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => { + match tuple!($i, $submac!($($args)*), $submac2!($($args2)*)) { + Ok((remaining, (_, o))) => Ok((remaining, o)), + Err(LexError) => Err(LexError), + } + }; + + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { + preceded!($i, $submac!($($args)*), call!($g)) + }; +} + +macro_rules! delimited { + ($i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)+) => { + match tuple_parser!($i, (), $submac!($($args)*), $($rest)*) { + Err(LexError) => Err(LexError), + Ok((i1, (_, o, _))) => Ok((i1, o)) + } + }; +} + +macro_rules! map { + ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => { + match $submac!($i, $($args)*) { + Err(LexError) => Err(LexError), + Ok((i, o)) => Ok((i, call!(o, $g))) + } + }; + + ($i:expr, $f:expr, $g:expr) => { + map!($i, call!($f), $g) + }; +} diff --git a/proc-macro2/src/wrapper.rs b/proc-macro2/src/wrapper.rs new file mode 100644 index 000000000..994ed24d8 --- /dev/null +++ b/proc-macro2/src/wrapper.rs @@ -0,0 +1,928 @@ +use std::fmt; +use std::iter; +use std::panic::{self, PanicInfo}; +#[cfg(super_unstable)] +use std::path::PathBuf; +use std::str::FromStr; + +use fallback; +use proc_macro; + +use {Delimiter, Punct, Spacing, TokenTree}; + +#[derive(Clone)] +pub enum TokenStream { + Compiler(proc_macro::TokenStream), + Fallback(fallback::TokenStream), +} + +pub enum LexError { + Compiler(proc_macro::LexError), + Fallback(fallback::LexError), +} + +fn nightly_works() -> bool { + use std::sync::atomic::*; + use std::sync::Once; + + #[allow(deprecated)] + static WORKS: AtomicUsize = ATOMIC_USIZE_INIT; + static INIT: Once = Once::new(); + + match WORKS.load(Ordering::SeqCst) { + 1 => return false, + 2 => return true, + _ => {} + } + + // Swap in a null panic hook to avoid printing "thread panicked" to stderr, + // then use catch_unwind to determine whether the compiler's proc_macro is + // working. When proc-macro2 is used from outside of a procedural macro all + // of the proc_macro crate's APIs currently panic. + // + // The Once is to prevent the possibility of this ordering: + // + // thread 1 calls take_hook, gets the user's original hook + // thread 1 calls set_hook with the null hook + // thread 2 calls take_hook, thinks null hook is the original hook + // thread 2 calls set_hook with the null hook + // thread 1 calls set_hook with the actual original hook + // thread 2 calls set_hook with what it thinks is the original hook + // + // in which the user's hook has been lost. + // + // There is still a race condition where a panic in a different thread can + // happen during the interval that the user's original panic hook is + // unregistered such that their hook is incorrectly not called. This is + // sufficiently unlikely and less bad than printing panic messages to stderr + // on correct use of this crate. Maybe there is a libstd feature request + // here. For now, if a user needs to guarantee that this failure mode does + // not occur, they need to call e.g. `proc_macro2::Span::call_site()` from + // the main thread before launching any other threads. + INIT.call_once(|| { + type PanicHook = Fn(&PanicInfo) + Sync + Send + 'static; + + let null_hook: Box = Box::new(|_panic_info| { /* ignore */ }); + let sanity_check = &*null_hook as *const PanicHook; + let original_hook = panic::take_hook(); + panic::set_hook(null_hook); + + let works = panic::catch_unwind(|| proc_macro::Span::call_site()).is_ok(); + WORKS.store(works as usize + 1, Ordering::SeqCst); + + let hopefully_null_hook = panic::take_hook(); + panic::set_hook(original_hook); + if sanity_check != &*hopefully_null_hook { + panic!("observed race condition in proc_macro2::nightly_works"); + } + }); + nightly_works() +} + +fn mismatch() -> ! { + panic!("stable/nightly mismatch") +} + +impl TokenStream { + pub fn new() -> TokenStream { + if nightly_works() { + TokenStream::Compiler(proc_macro::TokenStream::new()) + } else { + TokenStream::Fallback(fallback::TokenStream::new()) + } + } + + pub fn is_empty(&self) -> bool { + match self { + TokenStream::Compiler(tts) => tts.is_empty(), + TokenStream::Fallback(tts) => tts.is_empty(), + } + } + + fn unwrap_nightly(self) -> proc_macro::TokenStream { + match self { + TokenStream::Compiler(s) => s, + TokenStream::Fallback(_) => mismatch(), + } + } + + fn unwrap_stable(self) -> fallback::TokenStream { + match self { + TokenStream::Compiler(_) => mismatch(), + TokenStream::Fallback(s) => s, + } + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + if nightly_works() { + Ok(TokenStream::Compiler(src.parse()?)) + } else { + Ok(TokenStream::Fallback(src.parse()?)) + } + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => tts.fmt(f), + TokenStream::Fallback(tts) => tts.fmt(f), + } + } +} + +impl From for TokenStream { + fn from(inner: proc_macro::TokenStream) -> TokenStream { + TokenStream::Compiler(inner) + } +} + +impl From for proc_macro::TokenStream { + fn from(inner: TokenStream) -> proc_macro::TokenStream { + match inner { + TokenStream::Compiler(inner) => inner, + TokenStream::Fallback(inner) => inner.to_string().parse().unwrap(), + } + } +} + +impl From for TokenStream { + fn from(inner: fallback::TokenStream) -> TokenStream { + TokenStream::Fallback(inner) + } +} + +impl From for TokenStream { + fn from(token: TokenTree) -> TokenStream { + if !nightly_works() { + return TokenStream::Fallback(token.into()); + } + let tt: proc_macro::TokenTree = match token { + TokenTree::Group(tt) => tt.inner.unwrap_nightly().into(), + TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + Spacing::Joint => proc_macro::Spacing::Joint, + Spacing::Alone => proc_macro::Spacing::Alone, + }; + let mut op = proc_macro::Punct::new(tt.as_char(), spacing); + op.set_span(tt.span().inner.unwrap_nightly()); + op.into() + } + TokenTree::Ident(tt) => tt.inner.unwrap_nightly().into(), + TokenTree::Literal(tt) => tt.inner.unwrap_nightly().into(), + }; + TokenStream::Compiler(tt.into()) + } +} + +impl iter::FromIterator for TokenStream { + fn from_iter>(trees: I) -> Self { + if nightly_works() { + let trees = trees + .into_iter() + .map(TokenStream::from) + .flat_map(|t| match t { + TokenStream::Compiler(s) => s, + TokenStream::Fallback(_) => mismatch(), + }); + TokenStream::Compiler(trees.collect()) + } else { + TokenStream::Fallback(trees.into_iter().collect()) + } + } +} + +impl iter::FromIterator for TokenStream { + fn from_iter>(streams: I) -> Self { + let mut streams = streams.into_iter(); + match streams.next() { + #[cfg(slow_extend)] + Some(TokenStream::Compiler(first)) => { + let stream = iter::once(first) + .chain(streams.map(|s| match s { + TokenStream::Compiler(s) => s, + TokenStream::Fallback(_) => mismatch(), + })) + .collect(); + TokenStream::Compiler(stream) + } + #[cfg(not(slow_extend))] + Some(TokenStream::Compiler(mut first)) => { + first.extend(streams.map(|s| match s { + TokenStream::Compiler(s) => s, + TokenStream::Fallback(_) => mismatch(), + })); + TokenStream::Compiler(first) + } + Some(TokenStream::Fallback(mut first)) => { + first.extend(streams.map(|s| match s { + TokenStream::Fallback(s) => s, + TokenStream::Compiler(_) => mismatch(), + })); + TokenStream::Fallback(first) + } + None => TokenStream::new(), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + match self { + TokenStream::Compiler(tts) => { + #[cfg(not(slow_extend))] + { + tts.extend( + streams + .into_iter() + .map(|t| TokenStream::from(t).unwrap_nightly()), + ); + } + #[cfg(slow_extend)] + { + *tts = + tts.clone() + .into_iter() + .chain(streams.into_iter().map(TokenStream::from).flat_map( + |t| match t { + TokenStream::Compiler(tts) => tts.into_iter(), + _ => mismatch(), + }, + )) + .collect(); + } + } + TokenStream::Fallback(tts) => tts.extend(streams), + } + } +} + +impl Extend for TokenStream { + fn extend>(&mut self, streams: I) { + match self { + TokenStream::Compiler(tts) => { + #[cfg(not(slow_extend))] + { + tts.extend(streams.into_iter().map(|stream| stream.unwrap_nightly())); + } + #[cfg(slow_extend)] + { + *tts = tts + .clone() + .into_iter() + .chain(streams.into_iter().flat_map(|t| match t { + TokenStream::Compiler(tts) => tts.into_iter(), + _ => mismatch(), + })) + .collect(); + } + } + TokenStream::Fallback(tts) => { + tts.extend(streams.into_iter().map(|stream| stream.unwrap_stable())) + } + } + } +} + +impl fmt::Debug for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TokenStream::Compiler(tts) => tts.fmt(f), + TokenStream::Fallback(tts) => tts.fmt(f), + } + } +} + +impl From for LexError { + fn from(e: proc_macro::LexError) -> LexError { + LexError::Compiler(e) + } +} + +impl From for LexError { + fn from(e: fallback::LexError) -> LexError { + LexError::Fallback(e) + } +} + +impl fmt::Debug for LexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LexError::Compiler(e) => e.fmt(f), + LexError::Fallback(e) => e.fmt(f), + } + } +} + +#[derive(Clone)] +pub enum TokenTreeIter { + Compiler(proc_macro::token_stream::IntoIter), + Fallback(fallback::TokenTreeIter), +} + +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + match self { + TokenStream::Compiler(tts) => TokenTreeIter::Compiler(tts.into_iter()), + TokenStream::Fallback(tts) => TokenTreeIter::Fallback(tts.into_iter()), + } + } +} + +impl Iterator for TokenTreeIter { + type Item = TokenTree; + + fn next(&mut self) -> Option { + let token = match self { + TokenTreeIter::Compiler(iter) => iter.next()?, + TokenTreeIter::Fallback(iter) => return iter.next(), + }; + Some(match token { + proc_macro::TokenTree::Group(tt) => ::Group::_new(Group::Compiler(tt)).into(), + proc_macro::TokenTree::Punct(tt) => { + let spacing = match tt.spacing() { + proc_macro::Spacing::Joint => Spacing::Joint, + proc_macro::Spacing::Alone => Spacing::Alone, + }; + let mut o = Punct::new(tt.as_char(), spacing); + o.set_span(::Span::_new(Span::Compiler(tt.span()))); + o.into() + } + proc_macro::TokenTree::Ident(s) => ::Ident::_new(Ident::Compiler(s)).into(), + proc_macro::TokenTree::Literal(l) => ::Literal::_new(Literal::Compiler(l)).into(), + }) + } + + fn size_hint(&self) -> (usize, Option) { + match self { + TokenTreeIter::Compiler(tts) => tts.size_hint(), + TokenTreeIter::Fallback(tts) => tts.size_hint(), + } + } +} + +impl fmt::Debug for TokenTreeIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TokenTreeIter").finish() + } +} + +#[derive(Clone, PartialEq, Eq)] +#[cfg(super_unstable)] +pub enum SourceFile { + Compiler(proc_macro::SourceFile), + Fallback(fallback::SourceFile), +} + +#[cfg(super_unstable)] +impl SourceFile { + fn nightly(sf: proc_macro::SourceFile) -> Self { + SourceFile::Compiler(sf) + } + + /// Get the path to this source file as a string. + pub fn path(&self) -> PathBuf { + match self { + SourceFile::Compiler(a) => a.path(), + SourceFile::Fallback(a) => a.path(), + } + } + + pub fn is_real(&self) -> bool { + match self { + SourceFile::Compiler(a) => a.is_real(), + SourceFile::Fallback(a) => a.is_real(), + } + } +} + +#[cfg(super_unstable)] +impl fmt::Debug for SourceFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + SourceFile::Compiler(a) => a.fmt(f), + SourceFile::Fallback(a) => a.fmt(f), + } + } +} + +#[cfg(any(super_unstable, feature = "span-locations"))] +pub struct LineColumn { + pub line: usize, + pub column: usize, +} + +#[derive(Copy, Clone)] +pub enum Span { + Compiler(proc_macro::Span), + Fallback(fallback::Span), +} + +impl Span { + pub fn call_site() -> Span { + if nightly_works() { + Span::Compiler(proc_macro::Span::call_site()) + } else { + Span::Fallback(fallback::Span::call_site()) + } + } + + #[cfg(super_unstable)] + pub fn def_site() -> Span { + if nightly_works() { + Span::Compiler(proc_macro::Span::def_site()) + } else { + Span::Fallback(fallback::Span::def_site()) + } + } + + #[cfg(super_unstable)] + pub fn resolved_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)), + _ => mismatch(), + } + } + + #[cfg(super_unstable)] + pub fn located_at(&self, other: Span) -> Span { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)), + _ => mismatch(), + } + } + + pub fn unwrap(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => panic!("proc_macro::Span is only available in procedural macros"), + } + } + + #[cfg(super_unstable)] + pub fn source_file(&self) -> SourceFile { + match self { + Span::Compiler(s) => SourceFile::nightly(s.source_file()), + Span::Fallback(s) => SourceFile::Fallback(s.source_file()), + } + } + + #[cfg(any(super_unstable, feature = "span-locations"))] + pub fn start(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => { + let proc_macro::LineColumn { line, column } = s.start(); + LineColumn { line, column } + } + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => { + let fallback::LineColumn { line, column } = s.start(); + LineColumn { line, column } + } + } + } + + #[cfg(any(super_unstable, feature = "span-locations"))] + pub fn end(&self) -> LineColumn { + match self { + #[cfg(proc_macro_span)] + Span::Compiler(s) => { + let proc_macro::LineColumn { line, column } = s.end(); + LineColumn { line, column } + } + #[cfg(not(proc_macro_span))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, + Span::Fallback(s) => { + let fallback::LineColumn { line, column } = s.end(); + LineColumn { line, column } + } + } + } + + #[cfg(super_unstable)] + pub fn join(&self, other: Span) -> Option { + let ret = match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.join(b)?), + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.join(b)?), + _ => return None, + }; + Some(ret) + } + + #[cfg(super_unstable)] + pub fn eq(&self, other: &Span) -> bool { + match (self, other) { + (Span::Compiler(a), Span::Compiler(b)) => a.eq(b), + (Span::Fallback(a), Span::Fallback(b)) => a.eq(b), + _ => false, + } + } + + fn unwrap_nightly(self) -> proc_macro::Span { + match self { + Span::Compiler(s) => s, + Span::Fallback(_) => mismatch(), + } + } +} + +impl From for ::Span { + fn from(proc_span: proc_macro::Span) -> ::Span { + ::Span::_new(Span::Compiler(proc_span)) + } +} + +impl From for Span { + fn from(inner: fallback::Span) -> Span { + Span::Fallback(inner) + } +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Span::Compiler(s) => s.fmt(f), + Span::Fallback(s) => s.fmt(f), + } + } +} + +pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { + match span { + Span::Compiler(s) => { + debug.field("span", &s); + } + Span::Fallback(s) => fallback::debug_span_field_if_nontrivial(debug, s), + } +} + +#[derive(Clone)] +pub enum Group { + Compiler(proc_macro::Group), + Fallback(fallback::Group), +} + +impl Group { + pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { + match stream { + TokenStream::Compiler(stream) => { + let delimiter = match delimiter { + Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis, + Delimiter::Bracket => proc_macro::Delimiter::Bracket, + Delimiter::Brace => proc_macro::Delimiter::Brace, + Delimiter::None => proc_macro::Delimiter::None, + }; + Group::Compiler(proc_macro::Group::new(delimiter, stream)) + } + TokenStream::Fallback(stream) => { + Group::Fallback(fallback::Group::new(delimiter, stream)) + } + } + } + + pub fn delimiter(&self) -> Delimiter { + match self { + Group::Compiler(g) => match g.delimiter() { + proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis, + proc_macro::Delimiter::Bracket => Delimiter::Bracket, + proc_macro::Delimiter::Brace => Delimiter::Brace, + proc_macro::Delimiter::None => Delimiter::None, + }, + Group::Fallback(g) => g.delimiter(), + } + } + + pub fn stream(&self) -> TokenStream { + match self { + Group::Compiler(g) => TokenStream::Compiler(g.stream()), + Group::Fallback(g) => TokenStream::Fallback(g.stream()), + } + } + + pub fn span(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span()), + Group::Fallback(g) => Span::Fallback(g.span()), + } + } + + #[cfg(super_unstable)] + pub fn span_open(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span_open()), + Group::Fallback(g) => Span::Fallback(g.span_open()), + } + } + + #[cfg(super_unstable)] + pub fn span_close(&self) -> Span { + match self { + Group::Compiler(g) => Span::Compiler(g.span_close()), + Group::Fallback(g) => Span::Fallback(g.span_close()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Group::Compiler(g), Span::Compiler(s)) => g.set_span(s), + (Group::Fallback(g), Span::Fallback(s)) => g.set_span(s), + _ => mismatch(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Group { + match self { + Group::Compiler(g) => g, + Group::Fallback(_) => mismatch(), + } + } +} + +impl From for Group { + fn from(g: fallback::Group) -> Self { + Group::Fallback(g) + } +} + +impl fmt::Display for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => group.fmt(formatter), + Group::Fallback(group) => group.fmt(formatter), + } + } +} + +impl fmt::Debug for Group { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Group::Compiler(group) => group.fmt(formatter), + Group::Fallback(group) => group.fmt(formatter), + } + } +} + +#[derive(Clone)] +pub enum Ident { + Compiler(proc_macro::Ident), + Fallback(fallback::Ident), +} + +impl Ident { + pub fn new(string: &str, span: Span) -> Ident { + match span { + Span::Compiler(s) => Ident::Compiler(proc_macro::Ident::new(string, s)), + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new(string, s)), + } + } + + pub fn new_raw(string: &str, span: Span) -> Ident { + match span { + Span::Compiler(s) => { + let p: proc_macro::TokenStream = string.parse().unwrap(); + let ident = match p.into_iter().next() { + Some(proc_macro::TokenTree::Ident(mut i)) => { + i.set_span(s); + i + } + _ => panic!(), + }; + Ident::Compiler(ident) + } + Span::Fallback(s) => Ident::Fallback(fallback::Ident::new_raw(string, s)), + } + } + + pub fn span(&self) -> Span { + match self { + Ident::Compiler(t) => Span::Compiler(t.span()), + Ident::Fallback(t) => Span::Fallback(t.span()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Ident::Compiler(t), Span::Compiler(s)) => t.set_span(s), + (Ident::Fallback(t), Span::Fallback(s)) => t.set_span(s), + _ => mismatch(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Ident { + match self { + Ident::Compiler(s) => s, + Ident::Fallback(_) => mismatch(), + } + } +} + +impl PartialEq for Ident { + fn eq(&self, other: &Ident) -> bool { + match (self, other) { + (Ident::Compiler(t), Ident::Compiler(o)) => t.to_string() == o.to_string(), + (Ident::Fallback(t), Ident::Fallback(o)) => t == o, + _ => mismatch(), + } + } +} + +impl PartialEq for Ident +where + T: ?Sized + AsRef, +{ + fn eq(&self, other: &T) -> bool { + let other = other.as_ref(); + match self { + Ident::Compiler(t) => t.to_string() == other, + Ident::Fallback(t) => t == other, + } + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => t.fmt(f), + Ident::Fallback(t) => t.fmt(f), + } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ident::Compiler(t) => t.fmt(f), + Ident::Fallback(t) => t.fmt(f), + } + } +} + +#[derive(Clone)] +pub enum Literal { + Compiler(proc_macro::Literal), + Fallback(fallback::Literal), +} + +macro_rules! suffixed_numbers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +macro_rules! unsuffixed_integers { + ($($name:ident => $kind:ident,)*) => ($( + pub fn $name(n: $kind) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::$name(n)) + } else { + Literal::Fallback(fallback::Literal::$name(n)) + } + } + )*) +} + +impl Literal { + suffixed_numbers! { + u8_suffixed => u8, + u16_suffixed => u16, + u32_suffixed => u32, + u64_suffixed => u64, + usize_suffixed => usize, + i8_suffixed => i8, + i16_suffixed => i16, + i32_suffixed => i32, + i64_suffixed => i64, + isize_suffixed => isize, + + f32_suffixed => f32, + f64_suffixed => f64, + } + + #[cfg(u128)] + suffixed_numbers! { + i128_suffixed => i128, + u128_suffixed => u128, + } + + unsuffixed_integers! { + u8_unsuffixed => u8, + u16_unsuffixed => u16, + u32_unsuffixed => u32, + u64_unsuffixed => u64, + usize_unsuffixed => usize, + i8_unsuffixed => i8, + i16_unsuffixed => i16, + i32_unsuffixed => i32, + i64_unsuffixed => i64, + isize_unsuffixed => isize, + } + + #[cfg(u128)] + unsuffixed_integers! { + i128_unsuffixed => i128, + u128_unsuffixed => u128, + } + + pub fn f32_unsuffixed(f: f32) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::f32_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f32_unsuffixed(f)) + } + } + + pub fn f64_unsuffixed(f: f64) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::f64_unsuffixed(f)) + } else { + Literal::Fallback(fallback::Literal::f64_unsuffixed(f)) + } + } + + pub fn string(t: &str) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::string(t)) + } else { + Literal::Fallback(fallback::Literal::string(t)) + } + } + + pub fn character(t: char) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::character(t)) + } else { + Literal::Fallback(fallback::Literal::character(t)) + } + } + + pub fn byte_string(bytes: &[u8]) -> Literal { + if nightly_works() { + Literal::Compiler(proc_macro::Literal::byte_string(bytes)) + } else { + Literal::Fallback(fallback::Literal::byte_string(bytes)) + } + } + + pub fn span(&self) -> Span { + match self { + Literal::Compiler(lit) => Span::Compiler(lit.span()), + Literal::Fallback(lit) => Span::Fallback(lit.span()), + } + } + + pub fn set_span(&mut self, span: Span) { + match (self, span) { + (Literal::Compiler(lit), Span::Compiler(s)) => lit.set_span(s), + (Literal::Fallback(lit), Span::Fallback(s)) => lit.set_span(s), + _ => mismatch(), + } + } + + fn unwrap_nightly(self) -> proc_macro::Literal { + match self { + Literal::Compiler(s) => s, + Literal::Fallback(_) => mismatch(), + } + } +} + +impl From for Literal { + fn from(s: fallback::Literal) -> Literal { + Literal::Fallback(s) + } +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => t.fmt(f), + Literal::Fallback(t) => t.fmt(f), + } + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Compiler(t) => t.fmt(f), + Literal::Fallback(t) => t.fmt(f), + } + } +} diff --git a/proc-macro2/tests/marker.rs b/proc-macro2/tests/marker.rs new file mode 100644 index 000000000..7bb502762 --- /dev/null +++ b/proc-macro2/tests/marker.rs @@ -0,0 +1,61 @@ +extern crate proc_macro2; + +use proc_macro2::*; + +macro_rules! assert_impl { + ($ty:ident is $($marker:ident) and +) => { + #[test] + #[allow(non_snake_case)] + fn $ty() { + fn assert_implemented() {} + assert_implemented::<$ty>(); + } + }; + + ($ty:ident is not $($marker:ident) or +) => { + #[test] + #[allow(non_snake_case)] + fn $ty() { + $( + { + // Implemented for types that implement $marker. + trait IsNotImplemented { + fn assert_not_implemented() {} + } + impl IsNotImplemented for T {} + + // Implemented for the type being tested. + trait IsImplemented { + fn assert_not_implemented() {} + } + impl IsImplemented for $ty {} + + // If $ty does not implement $marker, there is no ambiguity + // in the following trait method call. + <$ty>::assert_not_implemented(); + } + )+ + } + }; +} + +assert_impl!(Delimiter is Send and Sync); +assert_impl!(Spacing is Send and Sync); + +assert_impl!(Group is not Send or Sync); +assert_impl!(Ident is not Send or Sync); +assert_impl!(LexError is not Send or Sync); +assert_impl!(Literal is not Send or Sync); +assert_impl!(Punct is not Send or Sync); +assert_impl!(Span is not Send or Sync); +assert_impl!(TokenStream is not Send or Sync); +assert_impl!(TokenTree is not Send or Sync); + +#[cfg(procmacro2_semver_exempt)] +mod semver_exempt { + use super::*; + + assert_impl!(LineColumn is Send and Sync); + + assert_impl!(SourceFile is not Send or Sync); +} diff --git a/proc-macro2/tests/test.rs b/proc-macro2/tests/test.rs new file mode 100644 index 000000000..370392b65 --- /dev/null +++ b/proc-macro2/tests/test.rs @@ -0,0 +1,452 @@ +extern crate proc_macro2; + +use std::str::{self, FromStr}; + +use proc_macro2::{Ident, Literal, Spacing, Span, TokenStream, TokenTree}; + +#[test] +fn idents() { + assert_eq!( + Ident::new("String", Span::call_site()).to_string(), + "String" + ); + assert_eq!(Ident::new("fn", Span::call_site()).to_string(), "fn"); + assert_eq!(Ident::new("_", Span::call_site()).to_string(), "_"); +} + +#[test] +#[cfg(procmacro2_semver_exempt)] +fn raw_idents() { + assert_eq!( + Ident::new_raw("String", Span::call_site()).to_string(), + "r#String" + ); + assert_eq!(Ident::new_raw("fn", Span::call_site()).to_string(), "r#fn"); + assert_eq!(Ident::new_raw("_", Span::call_site()).to_string(), "r#_"); +} + +#[test] +#[should_panic(expected = "Ident is not allowed to be empty; use Option")] +fn ident_empty() { + Ident::new("", Span::call_site()); +} + +#[test] +#[should_panic(expected = "Ident cannot be a number; use Literal instead")] +fn ident_number() { + Ident::new("255", Span::call_site()); +} + +#[test] +#[should_panic(expected = "\"a#\" is not a valid Ident")] +fn ident_invalid() { + Ident::new("a#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn raw_ident_empty() { + Ident::new("r#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn raw_ident_number() { + Ident::new("r#255", Span::call_site()); +} + +#[test] +#[should_panic(expected = "\"r#a#\" is not a valid Ident")] +fn raw_ident_invalid() { + Ident::new("r#a#", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn lifetime_empty() { + Ident::new("'", Span::call_site()); +} + +#[test] +#[should_panic(expected = "not a valid Ident")] +fn lifetime_number() { + Ident::new("'255", Span::call_site()); +} + +#[test] +#[should_panic(expected = r#""\'a#" is not a valid Ident"#)] +fn lifetime_invalid() { + Ident::new("'a#", Span::call_site()); +} + +#[test] +fn literal_string() { + assert_eq!(Literal::string("foo").to_string(), "\"foo\""); + assert_eq!(Literal::string("\"").to_string(), "\"\\\"\""); + assert_eq!(Literal::string("didn't").to_string(), "\"didn't\""); +} + +#[test] +fn literal_character() { + assert_eq!(Literal::character('x').to_string(), "'x'"); + assert_eq!(Literal::character('\'').to_string(), "'\\''"); + assert_eq!(Literal::character('"').to_string(), "'\"'"); +} + +#[test] +fn literal_float() { + assert_eq!(Literal::f32_unsuffixed(10.0).to_string(), "10.0"); +} + +#[test] +fn roundtrip() { + fn roundtrip(p: &str) { + println!("parse: {}", p); + let s = p.parse::().unwrap().to_string(); + println!("first: {}", s); + let s2 = s.to_string().parse::().unwrap().to_string(); + assert_eq!(s, s2); + } + roundtrip("a"); + roundtrip("<<"); + roundtrip("<<="); + roundtrip( + " + 1 + 1.0 + 1f32 + 2f64 + 1usize + 4isize + 4e10 + 1_000 + 1_0i32 + 8u8 + 9 + 0 + 0xffffffffffffffffffffffffffffffff + ", + ); + roundtrip("'a"); + roundtrip("'_"); + roundtrip("'static"); + roundtrip("'\\u{10__FFFF}'"); + roundtrip("\"\\u{10_F0FF__}foo\\u{1_0_0_0__}\""); +} + +#[test] +fn fail() { + fn fail(p: &str) { + if let Ok(s) = p.parse::() { + panic!("should have failed to parse: {}\n{:#?}", p, s); + } + } + fail("1x"); + fail("1u80"); + fail("1f320"); + fail("' static"); + fail("r#1"); + fail("r#_"); +} + +#[cfg(span_locations)] +#[test] +fn span_test() { + use proc_macro2::TokenTree; + + fn check_spans(p: &str, mut lines: &[(usize, usize, usize, usize)]) { + let ts = p.parse::().unwrap(); + check_spans_internal(ts, &mut lines); + } + + fn check_spans_internal(ts: TokenStream, lines: &mut &[(usize, usize, usize, usize)]) { + for i in ts { + if let Some((&(sline, scol, eline, ecol), rest)) = lines.split_first() { + *lines = rest; + + let start = i.span().start(); + assert_eq!(start.line, sline, "sline did not match for {}", i); + assert_eq!(start.column, scol, "scol did not match for {}", i); + + let end = i.span().end(); + assert_eq!(end.line, eline, "eline did not match for {}", i); + assert_eq!(end.column, ecol, "ecol did not match for {}", i); + + match i { + TokenTree::Group(ref g) => { + check_spans_internal(g.stream().clone(), lines); + } + _ => {} + } + } + } + } + + check_spans( + "\ +/// This is a document comment +testing 123 +{ + testing 234 +}", + &[ + (1, 0, 1, 30), // # + (1, 0, 1, 30), // [ ... ] + (1, 0, 1, 30), // doc + (1, 0, 1, 30), // = + (1, 0, 1, 30), // "This is..." + (2, 0, 2, 7), // testing + (2, 8, 2, 11), // 123 + (3, 0, 5, 1), // { ... } + (4, 2, 4, 9), // testing + (4, 10, 4, 13), // 234 + ], + ); +} + +#[cfg(procmacro2_semver_exempt)] +#[cfg(not(nightly))] +#[test] +fn default_span() { + let start = Span::call_site().start(); + assert_eq!(start.line, 1); + assert_eq!(start.column, 0); + let end = Span::call_site().end(); + assert_eq!(end.line, 1); + assert_eq!(end.column, 0); + let source_file = Span::call_site().source_file(); + assert_eq!(source_file.path().to_string_lossy(), ""); + assert!(!source_file.is_real()); +} + +#[cfg(procmacro2_semver_exempt)] +#[test] +fn span_join() { + let source1 = "aaa\nbbb" + .parse::() + .unwrap() + .into_iter() + .collect::>(); + let source2 = "ccc\nddd" + .parse::() + .unwrap() + .into_iter() + .collect::>(); + + assert!(source1[0].span().source_file() != source2[0].span().source_file()); + assert_eq!( + source1[0].span().source_file(), + source1[1].span().source_file() + ); + + let joined1 = source1[0].span().join(source1[1].span()); + let joined2 = source1[0].span().join(source2[0].span()); + assert!(joined1.is_some()); + assert!(joined2.is_none()); + + let start = joined1.unwrap().start(); + let end = joined1.unwrap().end(); + assert_eq!(start.line, 1); + assert_eq!(start.column, 0); + assert_eq!(end.line, 2); + assert_eq!(end.column, 3); + + assert_eq!( + joined1.unwrap().source_file(), + source1[0].span().source_file() + ); +} + +#[test] +fn no_panic() { + let s = str::from_utf8(b"b\'\xc2\x86 \x00\x00\x00^\"").unwrap(); + assert!(s.parse::().is_err()); +} + +#[test] +fn tricky_doc_comment() { + let stream = "/**/".parse::().unwrap(); + let tokens = stream.into_iter().collect::>(); + assert!(tokens.is_empty(), "not empty -- {:?}", tokens); + + let stream = "/// doc".parse::().unwrap(); + let tokens = stream.into_iter().collect::>(); + assert!(tokens.len() == 2, "not length 2 -- {:?}", tokens); + match tokens[0] { + proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '#'), + _ => panic!("wrong token {:?}", tokens[0]), + } + let mut tokens = match tokens[1] { + proc_macro2::TokenTree::Group(ref tt) => { + assert_eq!(tt.delimiter(), proc_macro2::Delimiter::Bracket); + tt.stream().into_iter() + } + _ => panic!("wrong token {:?}", tokens[0]), + }; + + match tokens.next().unwrap() { + proc_macro2::TokenTree::Ident(ref tt) => assert_eq!(tt.to_string(), "doc"), + t => panic!("wrong token {:?}", t), + } + match tokens.next().unwrap() { + proc_macro2::TokenTree::Punct(ref tt) => assert_eq!(tt.as_char(), '='), + t => panic!("wrong token {:?}", t), + } + match tokens.next().unwrap() { + proc_macro2::TokenTree::Literal(ref tt) => { + assert_eq!(tt.to_string(), "\" doc\""); + } + t => panic!("wrong token {:?}", t), + } + assert!(tokens.next().is_none()); + + let stream = "//! doc".parse::().unwrap(); + let tokens = stream.into_iter().collect::>(); + assert!(tokens.len() == 3, "not length 3 -- {:?}", tokens); +} + +#[test] +fn op_before_comment() { + let mut tts = TokenStream::from_str("~// comment").unwrap().into_iter(); + match tts.next().unwrap() { + TokenTree::Punct(tt) => { + assert_eq!(tt.as_char(), '~'); + assert_eq!(tt.spacing(), Spacing::Alone); + } + wrong => panic!("wrong token {:?}", wrong), + } +} + +#[test] +fn raw_identifier() { + let mut tts = TokenStream::from_str("r#dyn").unwrap().into_iter(); + match tts.next().unwrap() { + TokenTree::Ident(raw) => assert_eq!("r#dyn", raw.to_string()), + wrong => panic!("wrong token {:?}", wrong), + } + assert!(tts.next().is_none()); +} + +#[test] +fn test_debug_ident() { + let ident = Ident::new("proc_macro", Span::call_site()); + + #[cfg(not(procmacro2_semver_exempt))] + let expected = "Ident(proc_macro)"; + + #[cfg(procmacro2_semver_exempt)] + let expected = "Ident { sym: proc_macro, span: bytes(0..0) }"; + + assert_eq!(expected, format!("{:?}", ident)); +} + +#[test] +fn test_debug_tokenstream() { + let tts = TokenStream::from_str("[a + 1]").unwrap(); + + #[cfg(not(procmacro2_semver_exempt))] + let expected = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + }, + Punct { + op: '+', + spacing: Alone, + }, + Literal { + lit: 1, + }, + ], + }, +]\ + "; + + #[cfg(not(procmacro2_semver_exempt))] + let expected_before_trailing_commas = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a + }, + Punct { + op: '+', + spacing: Alone + }, + Literal { + lit: 1 + } + ] + } +]\ + "; + + #[cfg(procmacro2_semver_exempt)] + let expected = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + span: bytes(2..3), + }, + Punct { + op: '+', + spacing: Alone, + span: bytes(4..5), + }, + Literal { + lit: 1, + span: bytes(6..7), + }, + ], + span: bytes(1..8), + }, +]\ + "; + + #[cfg(procmacro2_semver_exempt)] + let expected_before_trailing_commas = "\ +TokenStream [ + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + sym: a, + span: bytes(2..3) + }, + Punct { + op: '+', + spacing: Alone, + span: bytes(4..5) + }, + Literal { + lit: 1, + span: bytes(6..7) + } + ], + span: bytes(1..8) + } +]\ + "; + + let actual = format!("{:#?}", tts); + if actual.ends_with(",\n]") { + assert_eq!(expected, actual); + } else { + assert_eq!(expected_before_trailing_commas, actual); + } +} + +#[test] +fn default_tokenstream_is_empty() { + let default_token_stream: TokenStream = Default::default(); + + assert!(default_token_stream.is_empty()); +} diff --git a/proptest/.cargo-checksum.json b/proptest/.cargo-checksum.json new file mode 100644 index 000000000..4ed051987 --- /dev/null +++ b/proptest/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"926d0604475349f463fe44130aae73f2294b5309ab2ca0310b998bd334ef191f"} \ No newline at end of file diff --git a/proptest/CHANGELOG.md b/proptest/CHANGELOG.md new file mode 100644 index 000000000..9cb0858ab --- /dev/null +++ b/proptest/CHANGELOG.md @@ -0,0 +1,638 @@ +## 0.8.7 + +### New Additions + +- Add `max_shrink_iters` and `max_shrink_time` options to test configuration to + allow capping the resources expended on shrinking test cases. + +- Add `verbose` option to make proptest give details about what is happening as + the test executes. + +- When a failure is saved to the persistence file, the message now also + includes the seed that was saved so that it can manually be added to the + appropriate file should the test have run somewhere where the updated file is + not accessible (for example, on a CI system). + +### Bug Fixes + +- `any::()` now generates random values centred on the UNIX epoch + rather than always producing the current time. + +### Other Notes + +- When using forking, proptest will now detect conditions which cause the child + process to crash without running any tests, and will fail quickly instead of + respawning child processes. + +## 0.8.6 + +### New Additions + +- `Vec where S: Strategy` is now itself a `Strategy` for producing + fixed-size `Vec`s whose values are derived from the respective strategies. + +- It is now possible to configure the test runner to cache test results to + avoid spending time running identical tests. See `Config.result_cache`. + +- Add `sample::Index`, a type for generating indices into runtime-sized slices + and vectors. + +- Add `sample::Selector`, a type for picking items out of dynamically-created + iterables. + +### Bug Fixes + +- Fix panic when using `sample::subsequence` with an empty vector. + +- Fix panic when using `sample::subsequence` with a size equal to the size of + the input vector. + +- Fix sampled bitset strategies on integers not allowing to generate exactly + the same number of bits as the integer is wide. + +### Other Notes + +- Passing empty size ranges to functions requiring a non-empty size range now + panic with an explicit message immediately rather than causing an arithmetic + error when generating input values. + +- There were a few cases where proptest would accept a `SizeRange` with an + inclusive maximum value of `usize::MAX`. Size ranges are now always clamped + to `usize::MAX - 1`. + +## 0.8.5 + +### Bug Fixes + +- Fix build when nightly features are enabled. + +## 0.8.4 + +### Bug Fixes + +- Nightly and no_std support work against latest nightly once again. + +### New Additions + +- Added `bits::bool_vec` for generating `Vec` as a bit set. + +### Nightly-only breakage + +- `impl Arbitrary for CollectionAllocErr` is temporarily removed pending it + being available outside the `alloc` crate again. + +- `bits::bitset` is no longer available without the `bit-set` feature (enabled + by default), which is [not compatible with `#[no_std]` + environments](https://github.com/contain-rs/bit-vec/pull/51). + +## 0.8.3 + +### Bug Fixes + +- Fix that regex-based string generation could transpose the order of a literal + and a non-literal component. + +## 0.8.2 + +### New Additions + +- Macros which previously accepted `pattern in strategy` syntax to specify + arguments now also accept `pattern: type` syntax as shorthand for + `pattern in any::()`. + +- Closure-style `proptest!` invocation no longer requires the body to use block + syntax. + +- Closure-style `proptest!` invocation now accepts custom configurations. + +## 0.8.1 + +### New Additions + +- `proptest!` now has form that accepts a closure. See the documentation for + the macro for more details. + +### Bug Fixes + +- Fix spurious warning about corrupt regression files. The files were not + corrupt but the parser was failing to handle the blank line at the end. + +- The `multiplex_alloc!` and `multiplex_core!` macros which were + unintentionally exported in 0.8.0 are no longer exported. This is not + considered a breaking change since they were not supposed to be accessible, + and in any case would not have expanded into valid code in most other crates. + +## 0.8.0 + +### New Additions + +- A combinator `.prop_filter_map` has been added to `Strategy`. + It is similar to `.filter_map` for `Iterator` in that it is the + combination of `.prop_filter` and `.prop_map`. + +- `i128` and `u128` are now supported without any feature flags and on stable. + +- More implementations of `Arbitrary` are supported for `alloc` + `no_std` users. + +- `size_range` now accepts inclusive ranges of form `low..=high` and `..=high`. + Thus, you can construct a `vec` strategy as: `vec(elt_strategy, low..=high)` + and `vec(elt_strategy, ..=high)`. This also applies to other functions + accepting `Into`. + +- `..= high` is now a valid strategy. Please note that `..= 1` will naturally + include numbers lower than `0` for sized types. + +- `low..=high` is also a valid strategy. + +- `Arbitrary` is implemented for `RangeInclusive`, `RangeToInclusive`, + and `DecodeUtf16` on stable. + +- Bitset strategies and `subsequence` now accept all range syntaxes. + +### Bug Fixes + +- Fix a race condition where a test failing due to running ever so slightly + over the set timeout could cause the test harness to converge to the + incorrect failing value, a non-failing value, or panic. + +### Deprecations + +- The type alias `ValueFor` is now deprecated and will be removed in + version 0.9. You should just use `S::Value` instead. + +### Breaking changes + +- A minimum version of 1.27 of Rust is now required. + +- `regex-syntax` version 0.6 is now used. + +- `rand` version 0.5 is now used. + +- As a consequence, the `FailurePersistence` trait will now use `[u8; 16]` seeds + instead of `[u32; 4]`. However, the stored failure persistence files using + the default `FileFailurePersistence` will still use `[u32; 4]` so your old + failure persistence files should still work. + +- The RNG used by proptest has been changed to a PRNG `TestRng` which proptest + exposes. This is currently a simple new-type wrapper around `XorShiftRng`. + In the future, this will give us more freedom to make changes without breakage. + +- The feature flag `i128_support` has been removed. The features it added are + now always supported. + +- The associated type `Value` of `Strategy` has been renamed to `Tree`. + A new associated type `Value` has been added to `Strategy` which always refers + to the same type as `::Value` for some strategy `S`. + This change allows you to write `-> impl Strategy` for functions + returning a `Strategy` generating `T`s. This is more ergonomic to use than + `-> impl Strategy>`. + +- The method `new_value` in `Strategy` has been renamed to `new_tree` to mirror + the renaming of `Value` to `Tree`. + +- As a consequence change, the associated type `ValueTree` has been removed from + `Arbitrary`. + +- The methods `run` and `run_one` on `TestRunner` now takes a function-under-test + that accepts the generated type by value instead of by reference instead. + This means that you don't need to write `ref value in my_strategy` and can + write `value in my_strategy` instead even if `typeof(value)` doesn't implement + `Copy`. This is also a step in the direction of allowing strategies to generate + references when generic associated types (GATs) land. + However, `ref value in my_strategy` will still be accepted, so not a lot of + breakage should come of this if you've used `proptest! { .. }`. + +- `prop_compose!` no longer applies `.boxed()` to the strategy produced. + Therefore, `-> BoxedStrategy` is no longer the correct type. + The new return type is `-> impl Strategy`. + If you want the old behaviour, you can use `.boxed()` yourself. + +- `Arbitrary` for `SizeRange` changed its associated type to use `RangeInclusive`. + Same applies for `CString`. + +- Many APIs now use `impl Trait` in argument position, which could affect code + using turbofishes to specify types explicitly. + +- `char` APIs which formerly represented a range as `(start, end)` now require + `start..=end`. + +### Nightly-only breakage + +- As `std::io::{Chars, CharsError}` have been deprecated on nightly, + their `Arbitrary` implementations have been removed. + +## 0.7.2 + +### Bug Fixes + +- Fix that `bool` would not shrink correctly, leading to hangs when tests + taking `bool` parameters would fail in certain circumstances. + +## 0.7.1 + +### New Additions + +- It is now possible to run test cases in sub-processes. This allows using + proptest to test functions which may cause the test process to terminate + abruptly, such as by calling `abort()` or even suffering a segmentation + fault. This requires the "fork" feature, enabled by default. + +- Added support for setting a timeout which applies on a per-test-case (i.e., + single input rather than the whole test) basis. This allows using proptest to + find inputs which cause code to get stuck in infinite loops or exhibit other + pathological performance behaviour. This requires the "timeout" feature (and + transitively, the "fork" feature), enabled by default. + +See also [the documentation](README.md#forking-and-timeouts) for these +features. + +### Bug Fixes + +- Fix that failure persistence file would be written to the incorrect location + in projects using workspaces. See + [#24](https://github.com/AltSysrq/proptest/issues/24) for more details and + instructions on how to migrate any persistence files that had been written to + the wrong location. + +- Fix a case where `any::()` or `any::()` could panic on + Windows. + +### Nightly-only breakage + +- Support for the `hashmap_core` crate is removed pending + https://github.com/Amanieu/hashmap_core/issues/3. + +## 0.7.0 + +### Potential Breaking Changes + +- The persistence system has been refactored to allow for + non-file-system based persistence. `FailurePersistence` + is now a trait, and the prior file-based enum which fulfilled + that purpose is now called `FileFailurePersistence` and implements + the generic trait. The default behavior has not changed. + +- Reflecting the change to persistence, `Config.failure_persistence` + is now of type `Option>`. + +- The `source_file` used as an optional reference point to the location of the + calling test is now tracked on the `Config` struct rather than the + `TestRunner`. + +### New Additions + +- Experimental support on nightly for working in `#![no_std]` environments has + been added. To use it, one must disable the default-features for proptest and + use the new "alloc" and "nightly" features. Currently access to a heap + allocator is still required. + +## 0.6.0 + +### Potential Breaking Changes + +- There is a small change of breakage if you've relied on `Recursive` using an + `Arc>` as `Recursive` now internally uses `BoxedStrategy` + instead as well as expecting a `Fn(BoxedStrategy) -> R` instead of + `Fn(Arc>) -> R`. In addition, the type of recursive + strategies has changed from `Recursive, F>` to just + `Recursive`. + +### Minor changes + +- Reduced indirections and heap allocations inside `Recursive` somewhat. + +- `BoxedStrategy` and `SBoxedStrategy` now use `Arc` internally instead of + using `Box`. While this has marginal overhead, it also reduces the overhead + in `Recursive`. The upside to this change is also that you can very + cheaply clone strategies. + +- `Filter` is marginally faster. + +### Bug Fixes + +- Removed `impl Arbitrary for LocalKeyState` since `LocalKeyState` no longer + exists in the nightly compiler. + +- Unstable features compile on latest nightly again. + +## 0.5.1 + +### New Additions + +- `proptest::strategy::Union` and `proptest::strategy::TupleUnion` now work + with weighted strategies even if the sum of the weights overflows a `u32`. + +- Added `SIGNALING_NAN` strategy to generate signalling NaNs if supported by + the platform. Note that this is _not_ included in `ANY`. + +### Bug Fixes + +- Fixed values produced via `prop_recursive()` not shrinking from the recursive + to the non-recursive case. + +- Fix that `QUIET_NAN` would generate signalling NaNs on most platforms on Rust + 1.24.0 and later. + +## 0.5.0 + +### Potential Breaking Changes + +- There is a small chance of breakage if you've relied on the constraints put + on type inference by the closure in `leaf.prop_recursive(..)` having a fixed + output type. The output type is now any strategy that generates the same type + as `leaf`. This change is intended to make working with recursive types a bit + easier as you no longer have to use `.boxed()` inside the closure you pass to + `.prop_recursive(..)`. + +- There is a small chance of breakage wrt. type inference due to the + introduction of `SizeRange`. + +- There is a small chance of breakage wrt. type inference due to the + introduction of `Probability`. + +- `BoxedStrategy` and `SBoxedStrategy` are now newtypes instead of being type + aliases. You will only experience breaking changes if you've directly + used `.boxed()` and not `(S)BoxedStrategy` but rather + `Box>>>`. The probability of + breakage is very small, but still possible. The benefit of this change + is that calling `.boxed()` or `.sboxed()` twice only boxes once. This can + happen in situations where you have functions `Strategy -> BoxedStrategy` or + with code generation. + +- `proptest::char::ANY` has been removed. Any remaining uses must be replaced + by `proptest::char::any()`. + +- `proptest::strategy::Singleton` has been removed. Any remaining uses must be + replaced by `proptest::strategy::Just`. + +### New Additions + +- Proptest now has an `Arbitrary` trait in `proptest::arbitrary` and re-exported + in the `proptest::prelude`. `Arbitrary` has also been `impl`emented for most + of the standard library. The trait provides a mechanism to define a canonical + `Strategy` for a given type just like `Arbitrary` in Haskell's QuickCheck. + Deriving for this trait will also be provided soon in the crate + `proptest_derive`. To use the canonical strategy for a certain type `T`, + you can simply use `any::()`. This is the major new addition of this release. + +- The `any_with`, `arbitrary`, `arbitrary_with` free functions in + the module `proptest::arbitrary`. + +- The `ArbitraryF1` and `ArbitraryF2` traits in `proptest::arbitrary::functor`. + These are "higher order" `Arbitrary` traits that correspond to the `Arbitrary1` + and `Arbitrary2` type classes in Haskell's QuickCheck. They are mainly provided + to support a common set of container-like types in custom deriving self-recursive + types in `proptest_derive`. More on this later releases. + +- The strategies in `proptest::option` and `proptest::result` now accept a type + `Probability` which is a wrapper around `f64`. Convertions from types such as + `f64` are provided to make the interface ergonomic to use. Users may also use + the `proptest::option::prob` function to explicitly construct the type. + +- The strategies in `proptest::collections` now accept a type `SizeRange` + which is a wrapper around `Range`. Convertions from types + such as `usize` and `Range` are provided to make the interface + ergonomic to use. Users may also use the `proptest::collections::size_bounds` + function to explicitly construct the type. + +- A `.prop_map_into()` operation on all strategies that map + using `Into`. This is a clerarer and cheaper + operation than using `.prop_map(OutputType::from)`. + +- A nonshrinking `LazyJust` strategy that can be used instead of `Just` when you + have non-`Clone` types. + +- Anything that can be coerced to `fn() -> T` where `T: Debug` is a `Strategy` + where `ValueFor T> == T`. This is intended to make it easier to reuse + proptest for unit tests with manual input space partition where `fn() -> T` + provides fixtures. + +### Minor changes + +- Relaxed the constraints of `btree_map` removing `'static`. + +- Reduced the heap allocation inside `Recursive` somewhat. + +## 0.4.2 + +### Bug Fixes + +- The `unstable` feature now works again. + +## 0.4.1 + +### New Additions + +- The `proptest::num::f32` and `proptest::num::f64` modules now have additional + constants (e.g., `POSITIVE`, `SUBNORMAL`, `INFINITE`) which can be used to + generate subsets of the floating-point domain by class and sign. + +### Bug Fixes + +- `proptest::num::f32::ANY` and `proptest::num::f64::ANY` now actually produce + arbitrary values. Previously, they had the same effect as `0.0..1.0`. While + this fix is a very substantial change in behaviour, it was not considered a + breaking change since (a) the new behaviour is consistent with the + documentation and expectations, (b) it's quite unlikely anyone was depending + on the old behaviour since anyone who wanted that range would have written it + out, and (c) Proptest isn't generally a transitive dependency so the chance + of this update happening "by surprise" is low. + +## 0.4.0 + +### Deprecations and Potential Breaking Changes + +- `proptest::char::ANY` replaced with `proptest::char::any()`. + `proptest::char::ANY` is present but deprecated, and will be removed in + proptest 0.5.0. + +- Instead of returning `-> Result`, strategies are + expected to return `-> Result` instead. `Reason` reduces + the amount of heap allocations, especially for `.prop_filter(..)` where you + may now also pass in `&'static str`. You will only experience breaks if + you've written your own strategy types or if you've used + `TestCaseError::Reject` or `TestCaseError::Fail` explicitly. + +- Update of externally-visible crate `rand` to `0.4.2`. + +### New Additions + +- Added `proptest::test_runner::Reason` which allows you to avoid heap + allocation in some places and may be used to make the API richer in the + future without incurring more breaking changes. + +- Added a type alias `proptest::strategy::NewTree` where `S: Strategy` + defined as: `type NewTree = Result<::Value, Rejection>`. + +## 0.3.4 + +### Bug Fixes + +- Cases where `file!()` returns a relative path, such as on Windows, are now + handled more reasonably. See + [#24](https://github.com/AltSysrq/proptest/issues/24) for more details and + instructions on how to migrate any persistence files that had been written to + the wrong location. + +## 0.3.3 + +Boxing Day Special + +### New Additions + +- Added support for `i128` and `u128`. Since this is an unstable feature in + Rust, this is hidden behind the feature `unstable` which you have to + explicitly opt into in your `Cargo.toml` file. + +- Failing case persistence. By default, when a test fails, Proptest will now + save the seed for the failing test to a file, and later runs will test the + persisted failing cases before generating new ones. + +- Added `UniformArrayStrategy` and helper functions to simplify generating + homogeneous arrays with non-`Copy` inner strategies. + +- Trait `rand::Rng` and struct `rand::XorShiftRng` are now included in + `proptest::prelude`. + +### Bug Fixes + +- Fix a case where certain combinations of strategies, like two + `prop_shuffle()`s in close proximity, could result in low-quality randomness. + +## 0.3.2 + +### New Additions + +- Added `SampledBitSetStrategy` to generate bit sets based on size + distribution. + +- Added `Strategy::sboxed()` and `SBoxedStrategy` to make `Send + Sync` boxed + strategies. + +- `RegexGeneratorStrategy` is now `Send` and `Sync`. + +- Added a type alias `ValueFor` where `S: Strategy`. This is a shorter way + to refer to: `<::Value as ValueTree>::Value`. + +- Added a type alias `type W = (u32, T)` for a weighted strategy `T` in the + context of union strategies. + +- `TestRunner` now implements `Default`. + +- Added `Config::with_cases(number_of_cases: u32) -> Config` for simpler + construction of a `Config` that only differs by the number of test cases. + +- All default fields of `Config` can now be overridden by setting environment + variables. See the docs of that struct for more details. + +- Bumped dependency `rand = "0.3.18"`. + +- Added `proptest::sample::subsequence` which returns a strategy generating + subsequences, of the source `Vec`, with a size within the given `Range`. + +- Added `proptest::sample::select` which returns a strategy selecting exactly + one value from another collection. + +- Added `prop_perturb` strategy combinator. + +- Added `strategy::check_strategy_sanity()` function to do sanity checks on the + shrinking implementation of a strategy. + +- Added `prop_shuffle` strategy combinator. + +- Added `strategy::Fuse` adaptor. + +### Bug Fixes + +- Fix bug where `Vec`, array and tuple shrinking could corrupt the state of + their inner values, for example leading to out-of-range integers. + +- Fix bug where `Flatten` (a.k.a. the `prop_flat_map` combinator) could fail to + converge to a failing test case during shrinking. + +- Fix `TupleUnion` sometimes panicking during shrinking if there were more than + two choices. + +## 0.3.1 + +### New Additions + +- Added `CharStrategy::new_borrowed`. + +## 0.3.0 + +### New Additions + +- `Union` now supports weighting via `Union::new_weighted`. Corresponding + syntax to specify weights is also available in `prop_oneof!`. + +- Added `TupleUnion`, which works like `Union` but permits doing static + dispatch even with heterogeneous delegate strategies. + +- `prop_oneof!` is smarter about how it combines the input strategies. + +- Added `option` module to generate weighted or unweighted `Option` types. + +- Added `result` module to generate weighted or unweighted `Result` types. + +- All `bits` submodules now have a `masked` function to create a strategy for + generating subsets of an arbitrary bitmask. + +### Potential Breaking Changes + +- `Union::new` now has a generic argument type which could impact type + inference. + +- The concrete types produced by `prop_oneof!` have changed. + +- API functions which used to return `BoxedStrategy` now return a specific + type. + +- `BitSetStrategy` is no longer `Copy` for non-`Copy` types `T` nor `Debug` + for non-`Debug` types `T`. + +- `BitSetLike::max` has been renamed to `BitSetLike::len`. + +## 0.2.1 + +### New Additions + +- Added `prop_assert!` macro family to assert without panicking, for quieter + test failure modes. + +- New `prelude` module for easier importing of important things. + +- Renamed `Singleton` to `Just`. (The old name is still available.) + +- Failure messages produced by `proptest!` are now much more readable. + +- Added in-depth tutorial. + +## 0.2.0 + +### Breaking Changes + +- `Strategy` now requires `std::fmt::Debug`. + +### New Additions + +- `Strategy` now has a family of `prop_flat_map()` combinators for producing + dynamic and higher-order strategies. + +- `Strategy` has a `prop_recursive()` combinator which allows generating + recursive structures. + +- Added `proptest::bool::weighted()` to pull booleans from a weighted + distribution. + +- New `prop_oneof!` macro makes it easier to select from one of several + strategies. + +- New `prop_compose!` macro to simplify writing most types of custom + strategies. + +## 0.1.1 + +### New Additions + +Add `strategy::NoShrink`, `Strategy::no_shrink()`. diff --git a/proptest/Cargo.toml b/proptest/Cargo.toml new file mode 100644 index 000000000..809e6a02d --- /dev/null +++ b/proptest/Cargo.toml @@ -0,0 +1,81 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "proptest" +version = "0.8.7" +authors = ["Jason Lingle"] +description = "Hypothesis-like property-based testing and shrinking.\n" +documentation = "https://altsysrq.github.io/rustdoc/proptest/0.8.7/proptest/" +readme = "README.md" +keywords = ["property", "testing", "quickcheck", "fuzz", "hypothesis"] +categories = ["development-tools::testing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/altsysrq/proptest" +[dependencies.bit-set] +version = "0.5.0" +optional = true + +[dependencies.bitflags] +version = "1.0.1" + +[dependencies.byteorder] +version = "1.2.3" +default-features = false + +[dependencies.lazy_static] +version = "1.0.0" +default-features = false + +[dependencies.num-traits] +version = "0.2.2" +default-features = false + +[dependencies.quick-error] +version = "1.2.1" +optional = true + +[dependencies.rand] +version = "0.5.0" +features = ["alloc", "i128_support"] +default-features = false + +[dependencies.regex-syntax] +version = "0.6.0" +optional = true + +[dependencies.rusty-fork] +version = "0.2.1" +optional = true +default-features = false + +[dependencies.tempfile] +version = "3.0" +optional = true +[dev-dependencies.regex] +version = "1.0" + +[features] +alloc = [] +default = ["std", "fork", "timeout", "bit-set"] +fork = ["std", "rusty-fork", "tempfile"] +nightly = ["lazy_static/spin_no_std"] +std = ["rand/std", "byteorder/std", "quick-error", "regex-syntax", "num-traits/std"] +timeout = ["fork", "rusty-fork/timeout"] +unstable = ["rand/i128_support"] +[badges.appveyor] +branch = "master" +repository = "AltSysrq/proptest" +service = "github" + +[badges.travis-ci] +repository = "AltSysrq/proptest" diff --git a/proptest/LICENSE-APACHE b/proptest/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/proptest/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/proptest/LICENSE-MIT b/proptest/LICENSE-MIT new file mode 100644 index 000000000..63ceeec5c --- /dev/null +++ b/proptest/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 FullContact, Inc + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/proptest/README.md b/proptest/README.md new file mode 100644 index 000000000..53de6c6e8 --- /dev/null +++ b/proptest/README.md @@ -0,0 +1,527 @@ +# Proptest + +[![Build Status](https://travis-ci.org/AltSysrq/proptest.svg?branch=master)](https://travis-ci.org/AltSysrq/proptest) +[![Build status](https://ci.appveyor.com/api/projects/status/ofe98xfthbx1m608/branch/master?svg=true)](https://ci.appveyor.com/project/AltSysrq/proptest/branch/master) +[![](http://meritbadge.herokuapp.com/proptest)](https://crates.io/crates/proptest) + +Proptest is a property testing framework (i.e., the QuickCheck family) +inspired by the [Hypothesis](http://hypothesis.works/) framework for +Python. It allows to test that certain properties of your code hold for +arbitrary inputs, and if a failure is found, automatically finds the +minimal test case to reproduce the problem. Unlike QuickCheck, generation +and shrinking is defined on a per-value basis instead of per-type, which +makes it more flexible and simplifies composition. + +If you have dependencies which provide QuickCheck `Arbitrary` +implementations, see also the related +[`proptest-quickcheck-interop`](https://crates.io/crates/proptest-quickcheck-interop) +crates which enables reusing those implementations with proptest. + +## Status of this crate + +The majority of the functionality offered by proptest is in active use and +is known to work well. + +The API is unlikely to see drastic breaking changes, but there may still be +minor breaking changes here and there, particularly when "impl Trait" +becomes stable and after the upcoming redesign of the `rand` crate. + +See the [changelog](https://github.com/AltSysrq/proptest/blob/master/CHANGELOG.md) +for a full list of substantial historical changes, breaking and otherwise. + +## Introduction + +_Property testing_ is a system of testing code by checking that certain +properties of its output or behaviour are fulfilled for all inputs. These +inputs are generated automatically, and, critically, when a failing input +is found, the input is automatically reduced to a _minimal_ test case. + +Property testing is best used to compliment traditional unit testing (i.e., +using specific inputs chosen by hand). Traditional tests can test specific +known edge cases, simple inputs, and inputs that were known in the past to +reveal bugs, whereas property tests will search for more complicated inputs +that cause problems. + +## Getting Started + +Let's say we want to make a function that parses dates of the form +`YYYY-MM-DD`. We're not going to worry about _validating_ the date, any +triple of integers is fine. So let's bang something out real quick. + +```rust +fn parse_date(s: &str) -> Option<(u32, u32, u32)> { + if 10 != s.len() { return None; } + if "-" != &s[4..5] || "-" != &s[7..8] { return None; } + + let year = &s[0..4]; + let month = &s[6..7]; + let day = &s[8..10]; + + year.parse::().ok().and_then( + |y| month.parse::().ok().and_then( + |m| day.parse::().ok().map( + |d| (y, m, d)))) +} +``` + +It compiles, that means it works, right? Maybe not, let's add some tests. + +```rust +#[test] +fn test_parse_date() { + assert_eq!(None, parse_date("2017-06-1")); + assert_eq!(None, parse_date("2017-06-170")); + assert_eq!(None, parse_date("2017006-17")); + assert_eq!(None, parse_date("2017-06017")); + assert_eq!(Some((2017, 06, 17)), parse_date("2017-06-17")); +} +``` + +Tests pass, deploy to production! But now your application starts crashing, +and people are upset that you moved Christmas to February. Maybe we need to +be a bit more thorough. + +In `Cargo.toml`, add + +```toml +[dev-dependencies] +proptest = "0.8.7" +``` + +and at the top of `main.rs` or `lib.rs`: + +```rust +#[macro_use] extern crate proptest; +``` + +Now we can add some property tests to our date parser. But how do we test +the date parser for arbitrary inputs, without making another date parser in +the test to validate it? We won't need to as long as we choose our inputs +and properties correctly. But before correctness, there's actually an even +simpler property to test: _The function should not crash._ Let's start +there. + +```rust +proptest! { + #[test] + fn doesnt_crash(s in "\\PC*") { + parse_date(s); + } +} +``` + +What this does is take a literally random `&String` (ignore `\\PC*` for the +moment, we'll get back to that — if you've already figured it out, contain +your excitement for a bit) and give it to `parse_date()` and then throw the +output away. + +When we run this, we get a bunch of scary-looking output, eventually ending +with + +```text +thread 'main' panicked at 'Test failed: byte index 4 is not a char boundary; it is inside 'ௗ' (bytes 2..5) of `aAௗ0㌀0`; minimal failing input: s = "aAௗ0㌀0" + successes: 102 + local rejects: 0 + global rejects: 0 +' +``` + +If we look at the top directory after the test fails, we'll see a new +`proptest-regressions` directory, which contains some files corresponding +to source files containing failing test cases. These are [_failure +persistence_](#failure-persistence) files. The first thing we should do is +add these to source control. + +```text +$ git add proptest-regressions +``` + +The next thing we should do is copy the failing case to a traditional unit +test since it has exposed a bug not similar to what we've tested in the +past. + +```rust +#[test] +fn test_unicode_gibberish() { + assert_eq!(None, parse_date("aAௗ0㌀0")); +} +``` + +Now, let's see what happened... we forgot about UTF-8! You can't just +blindly slice strings since you could split a character, in this case that +Tamil diacritic placed atop other characters in the string. + +In the interest of making the code changes as small as possible, we'll just +check that the string is ASCII and reject anything that isn't. + +```rust +fn parse_date(s: &str) -> Option<(u32, u32, u32)> { + if 10 != s.len() { return None; } + + // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. + if !s.is_ascii() { return None; } + + if "-" != &s[4..5] || "-" != &s[7..8] { return None; } + + let year = &s[0..4]; + let month = &s[6..7]; + let day = &s[8..10]; + + year.parse::().ok().and_then( + |y| month.parse::().ok().and_then( + |m| day.parse::().ok().map( + |d| (y, m, d)))) +} +``` + +The tests pass now! But we know there are still more problems, so let's +test more properties. + +Another property we want from our code is that it parses every valid date. +We can add another test to the `proptest!` section: + +```rust +proptest! { + // snip... + + #[test] + fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") { + parse_date(s).unwrap(); + } +} +``` + +The thing to the right-hand side of `in` is actually a *regular +expression*, and `s` is chosen from strings which match it. So in our +previous test, `"\\PC*"` was generating arbitrary strings composed of +arbitrary non-control characters. Now, we generate things in the YYYY-MM-DD +format. + +The new test passes, so let's move on to something else. + +The final property we want to check is that the dates are actually parsed +_correctly_. Now, we can't do this by generating strings — we'd end up just +reimplementing the date parser in the test! Instead, we start from the +expected output, generate the string, and check that it gets parsed back. + +```rust +proptest! { + // snip... + + #[test] + fn parses_date_back_to_original(y in 0u32..10000, + m in 1u32..13, d in 1u32..32) { + let (y2, m2, d2) = parse_date( + &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); + // prop_assert_eq! is basically the same as assert_eq!, but doesn't + // cause a bunch of panic messages to be printed on intermediate + // test failures. Which one to use is largely a matter of taste. + prop_assert_eq!((y, m, d), (y2, m2, d2)); + } +} +``` + +Here, we see that besides regexes, we can use any expression which is a +`proptest::strategy::Strategy`, in this case, integer ranges. + +The test fails when we run it. Though there's not much output this time. + +```text +thread 'main' panicked at 'Test failed: assertion failed: `(left == right)` (left: `(0, 10, 1)`, right: `(0, 0, 1)`) at examples/dateparser_v2.rs:46; minimal failing input: y = 0, m = 10, d = 1 + successes: 2 + local rejects: 0 + global rejects: 0 +', examples/dateparser_v2.rs:33 +note: Run with `RUST_BACKTRACE=1` for a backtrace. +``` + +The failing input is `(y, m, d) = (0, 10, 1)`, which is a rather specific +output. Before thinking about why this breaks the code, let's look at what +proptest did to arrive at this value. At the start of our test function, +insert + +```rust + println!("y = {}, m = {}, d = {}", y, m, d); +``` + +Running the test again, we get something like this: + +```text +y = 2497, m = 8, d = 27 +y = 9641, m = 8, d = 18 +y = 7360, m = 12, d = 20 +y = 3680, m = 12, d = 20 +y = 1840, m = 12, d = 20 +y = 920, m = 12, d = 20 +y = 460, m = 12, d = 20 +y = 230, m = 12, d = 20 +y = 115, m = 12, d = 20 +y = 57, m = 12, d = 20 +y = 28, m = 12, d = 20 +y = 14, m = 12, d = 20 +y = 7, m = 12, d = 20 +y = 3, m = 12, d = 20 +y = 1, m = 12, d = 20 +y = 0, m = 12, d = 20 +y = 0, m = 6, d = 20 +y = 0, m = 9, d = 20 +y = 0, m = 11, d = 20 +y = 0, m = 10, d = 20 +y = 0, m = 10, d = 10 +y = 0, m = 10, d = 5 +y = 0, m = 10, d = 3 +y = 0, m = 10, d = 2 +y = 0, m = 10, d = 1 +``` + +The test failure message said there were two successful cases; we see these +at the very top, `2497-08-27` and `9641-08-18`. The next case, +`7360-12-20`, failed. There's nothing immediately obviously special about +this date. Fortunately, proptest reduced it to a much simpler case. First, +it rapidly reduced the `y` input to `0` at the beginning, and similarly +reduced the `d` input to the minimum allowable value of `1` at the end. +Between those two, though, we see something different: it tried to shrink +`12` to `6`, but then ended up raising it back up to `10`. This is because +the `0000-06-20` and `0000-09-20` test cases _passed_. + +In the end, we get the date `0000-10-01`, which apparently gets parsed as +`0000-00-01`. Again, this failing case was added to the failure persistence +file, and we should add this as its own unit test: + +```text +$ git add proptest-regressions +``` + +```rust +#[test] +fn test_october_first() { + assert_eq!(Some(0, 10, 1), parse_date("0000-10-01")); +} +``` + +Now to figure out what's broken in the code. Even without the intermediate +input, we can say with reasonable confidence that the year and day parts +don't come into the picture since both were reduced to the minimum +allowable input. The month input was _not_, but was reduced to `10`. This +means we can infer that there's something special about `10` that doesn't +hold for `9`. In this case, that "special something" is being two digits +wide. In our code: + +```rust + let month = &s[6..7]; +``` + +We were off by one, and need to use the range `5..7`. After fixing this, +the test passes. + +The `proptest!` macro has some additional syntax, including for setting +configuration for things like the number of test cases to generate. See its +[documentation](https://altsysrq.github.io/rustdoc/proptest/latest/proptest/macro.proptest.html) +for more details. + +There is a more in-depth tutorial +[in the crate documentation](https://altsysrq.github.io/rustdoc/proptest/latest/proptest/#in-depth-tutorial). + +## Differences between QuickCheck and Proptest + +QuickCheck and Proptest are similar in many ways: both generate random +inputs for a function to check certain properties, and automatically shrink +inputs to minimal failing cases. + +The one big difference is that QuickCheck generates and shrinks values +based on type alone, whereas Proptest uses explicit `Strategy` objects. The +QuickCheck approach has a lot of disadvantages in comparison: + +- QuickCheck can only define one generator and shrinker per type. If you +need a custom generation strategy, you need to wrap it in a newtype and +implement traits on that by hand. In Proptest, you can define arbitrarily +many different strategies for the same type, and there are plenty built-in. + +- For the same reason, QuickCheck has a single "size" configuration that +tries to define the range of values generated. If you need an integer +between 0 and 100 and another between 0 and 1000, you probably need to do +another newtype. In Proptest, you can directly just express that you want a +`0..100` integer and a `0..1000` integer. + +- Types in QuickCheck are not easily composable. Defining `Arbitrary` and +`Shrink` for a new struct which is simply produced by the composition of +its fields requires implementing both by hand, including a bidirectional +mapping between the struct and a tuple of its fields. In Proptest, you can +make a tuple of the desired components and then `prop_map` it into the +desired form. Shrinking happens automatically in terms of the input types. + +- Because constraints on values cannot be expressed in QuickCheck, +generation and shrinking may lead to a lot of input rejections. Strategies +in Proptest are aware of simple constraints and do not generate or shrink +to values that violate them. + +The author of Hypothesis also has an [article on this +topic](http://hypothesis.works/articles/integrated-shrinking/). + +Of course, there's also some relative downsides that fall out of what +Proptest does differently: + +- Generating complex values in Proptest can be up to an order of magnitude +slower than in QuickCheck. This is because QuickCheck performs stateless +shrinking based on the output value, whereas Proptest must hold on to all +the intermediate states and relationships in order for its richer shrinking +model to work. + +## Limitations of Property Testing + +Given infinite time, property testing will eventually explore the whole +input space to a test. However, time is not infinite, so only a randomly +sampled portion of the input space can be explored. This means that +property testing is extremely unlikely to find single-value edge cases in a +large space. For example, the following test will virtually always pass: + +```rust +#[macro_use] extern crate proptest; +use proptest::prelude::*; + +proptest! { + #[test] + fn i64_abs_is_never_negative(a: i64) { + // This actually fails if a == i64::MIN, but randomly picking one + // specific value out of 2⁶⁴ is overwhelmingly unlikely. + assert!(a.abs() >= 0); + } +} +``` + +Because of this, traditional unit testing with intelligently selected cases +is still necessary for many kinds of problems. + +Similarly, in some cases it can be hard or impossible to define a strategy +which actually produces useful inputs. A strategy of `.{1,4096}` may be +great to fuzz a C parser, but is highly unlikely to produce anything that +makes it to a code generator. + +## Failure Persistence + +By default, when Proptest finds a failing test case, it _persists_ that +failing case in a file named after the source containing the failing test, +but in a separate directory tree rooted at `proptest-regressions`† . Later +runs of tests will replay those test cases before generating novel cases. +This ensures that the test will not fail on one run and then spuriously +pass on the next, and also exposes similar tests to the same +known-problematic input. + +(† If you do not have an obvious source directory, you may instead find +files next to the source files, with a different extension.) + +It is recommended to check these files in to your source control so that +other test runners (e.g., collaborators or a CI system) also replay these +cases. + +Note that, by default, all tests in the same crate will share that one +persistence file. If you have a very large number of tests, it may be +desirable to separate them into smaller groups so the number of extra test +cases that get run is reduced. This can be done by adjusting the +`failure_persistence` flag on `Config`. + +There are two ways this persistence could theoretically be done. + +The immediately obvious option is to persist a representation of the value +itself, for example by using Serde. While this has some advantages, +particularly being resistant to changes like tweaking the input strategy, +it also has a lot of problems. Most importantly, there is no way to +determine whether any given value is actually within the domain of the +strategy that produces it. Thus, some (likely extremely fragile) mechanism +to ensure that the strategy that produced the value exactly matches the one +in use in a test case would be required. + +The other option is to store the _seed_ that was used to produce the +failing test case. This approach requires no support from the strategy or +the produced value. If the strategy in use differs from the one used to +produce failing case that was persisted, the seed may or may not produce +the problematic value, but nonetheless produces a valid value. Due to these +advantages, this is the approach Proptest uses. + +## Forking and Timeouts + +By default, proptest tests are run in-process and are allowed to run for +however long it takes them. This is resource-efficient and produces the +nicest test output, and for many use cases is sufficient. However, problems +like overflowing the stack, aborting the process, or getting stuck in an +infinite will simply break the entire test process and prevent proptest +from determining a minimal reproducible case. + +As of version 0.7.1, proptest has optional "fork" and "timeout" features +(both enabled by default), which make it possible to run your test cases in +a subprocess and limit how long they may run. This is generally slower, +may make using a debugger more difficult, and makes test output harder to +interpret, but allows proptest to find and minimise test cases for these +situations as well. + +To enable these features, simply set the `fork` and/or `timeout` fields on +the `Config`. (Setting `timeout` implies `fork`.) + +Here is a simple example of using both features: + +```rust +#[macro_use] extern crate proptest; +use proptest::prelude::*; + +// The worst possible way to calculate Fibonacci numbers +fn fib(n: u64) -> u64 { + if n <= 1 { + n + } else { + fib(n - 1) + fib(n - 2) + } +} + +proptest! { + #![proptest_config(ProptestConfig { + // Setting both fork and timeout is redundant since timeout implies + // fork, but both are shown for clarity. + fork: true, + timeout: 1000, + .. ProptestConfig::default() + })] + + #[test] + fn test_fib(n: u64) { + // For large n, this will variously run for an extremely long time, + // overflow the stack, or panic due to integer overflow. + assert!(fib(n) >= n); + } +} +``` + +The exact value of the test failure depends heavily on the performance of +the host system, the rust version, and compiler flags, but on the system +where it was originally tested, it found that the maximum value that +`fib()` could handle was 39, despite having dozens of processes dump core +due to stack overflow or time out along the way. + +If you just want to run tests in subprocesses or with a timeout every now +and then, you can do that by setting the `PROPTEST_FORK` or +`PROPTEST_TIMEOUT` environment variables to alter the default +configuration. For example, on Unix, + +```sh +# Run all the proptest tests in subprocesses with no timeout. +# Individual tests can still opt out by setting `fork: false` in their +# own configuration. +PROPTEST_FORK=true cargo test +# Run all the proptest tests in subprocesses with a 1 second timeout. +# Tests can still opt out or use a different timeout by setting `timeout: 0` +# or another timeout in their own configuration. +PROPTEST_TIMEOUT=1000 cargo test +``` + + +# Acknowledgements + +This crate wouldn't have come into existence had it not been for the [Rust port +of QuickCheck](https://github.com/burntsushi/quickcheck) and the +[`regex_generate`](https://github.com/CryptArchy/regex_generate) crate which +gave wonderful examples of what is possible. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/proptest/appveyor.yml b/proptest/appveyor.yml new file mode 100644 index 000000000..ee3b6d632 --- /dev/null +++ b/proptest/appveyor.yml @@ -0,0 +1,18 @@ +environment: + matrix: + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + - TARGET: nightly-x86_64-pc-windows-gnu + - TARGET: nightly-i686-pc-windows-gnu + - TARGET: 1.27.0-x86_64-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe" + - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - rustc -vV + - cargo -vV +build_script: + - cargo build +test_script: + - cargo test + - cd test-persistence-location & run-tests.bat diff --git a/proptest/examples/config-defaults.rs b/proptest/examples/config-defaults.rs new file mode 100644 index 000000000..d7552ac7f --- /dev/null +++ b/proptest/examples/config-defaults.rs @@ -0,0 +1,16 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate proptest; + +use proptest::test_runner::Config; + +fn main() { + println!("Default config: {:?}", Config::default()); +} diff --git a/proptest/examples/dateparser_v1.rs b/proptest/examples/dateparser_v1.rs new file mode 100644 index 000000000..baf54a304 --- /dev/null +++ b/proptest/examples/dateparser_v1.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_use] +extern crate proptest; + +fn parse_date(s: &str) -> Option<(u32, u32, u32)> { + if 10 != s.len() { + return None; + } + // ! + if "-" != &s[4..5] || "-" != &s[7..8] { + return None; + } + + let year = &s[0..4]; + let month = &s[6..7]; // ! + let day = &s[8..10]; + + year.parse::().ok().and_then(|y| { + month + .parse::() + .ok() + .and_then(|m| day.parse::().ok().map(|d| (y, m, d))) + }) +} + +// NB We omit #[test] on these functions so that main() can call them. +proptest! { + fn doesnt_crash(ref s in "\\PC*") { + parse_date(s); + } +} + +fn main() { + assert_eq!(None, parse_date("2017-06-1")); + assert_eq!(None, parse_date("2017-06-170")); + assert_eq!(None, parse_date("2017006-17")); + assert_eq!(None, parse_date("2017-06017")); + assert_eq!(Some((2017, 6, 17)), parse_date("2017-06-17")); + + doesnt_crash(); +} diff --git a/proptest/examples/dateparser_v2.rs b/proptest/examples/dateparser_v2.rs new file mode 100644 index 000000000..50c820b2d --- /dev/null +++ b/proptest/examples/dateparser_v2.rs @@ -0,0 +1,67 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_use] +extern crate proptest; + +fn parse_date(s: &str) -> Option<(u32, u32, u32)> { + if 10 != s.len() { + return None; + } + + // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. + if !s.is_ascii() { + return None; + } + + if "-" != &s[4..5] || "-" != &s[7..8] { + return None; + } + + let year = &s[0..4]; + let month = &s[6..7]; // ! + let day = &s[8..10]; + + year.parse::().ok().and_then(|y| { + month + .parse::() + .ok() + .and_then(|m| day.parse::().ok().map(|d| (y, m, d))) + }) +} + +// NB We omit #[test] on these functions so that main() can call them. +proptest! { + fn doesnt_crash(ref s in "\\PC*") { + parse_date(s); + } + + fn parses_all_valid_dates(ref s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") { + parse_date(s).unwrap(); + } + + fn parses_date_back_to_original(y in 0u32..10_000, + m in 1u32..13, d in 1u32..32) { + let (y2, m2, d2) = parse_date( + &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); + prop_assert_eq!((y, m, d), (y2, m2, d2)); + } +} + +fn main() { + assert_eq!(None, parse_date("2017-06-1")); + assert_eq!(None, parse_date("2017-06-170")); + assert_eq!(None, parse_date("2017006-17")); + assert_eq!(None, parse_date("2017-06017")); + assert_eq!(Some((2017, 6, 17)), parse_date("2017-06-17")); + + doesnt_crash(); + parses_all_valid_dates(); + parses_date_back_to_original(); +} diff --git a/proptest/examples/fib.rs b/proptest/examples/fib.rs new file mode 100644 index 000000000..0e8a466cb --- /dev/null +++ b/proptest/examples/fib.rs @@ -0,0 +1,53 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_use] extern crate proptest; + +// This #[cfg] is only here so that CI can test building proptest with the +// timeout feature disabled. You do not need it in your code. +#[cfg(feature = "timeout")] +mod fib { + use proptest::prelude::*; + + // The worst possible way to calculate Fibonacci numbers + fn fib(n: u64) -> u64 { + if n <= 1 { + n + } else { + fib(n - 1) + fib(n - 2) + } + } + + proptest! { + #![proptest_config(ProptestConfig { + // Setting both fork and timeout is redundant since timeout implies + // fork, but both are shown for clarity. + fork: true, + timeout: 1000, + .. ProptestConfig::default() + })] + + // NB We omit #[test] on the test function so that main() can call it. + fn test_fib(n in prop::num::u64::ANY) { + // For large n, this will variously run for an extremely long time, + // overflow the stack, or panic due to integer overflow. + assert!(fib(n) >= n); + } + } + + // This is just here so that main can call it + pub fn do_test_fib() { + test_fib(); + } +} + +fn main() { + #[cfg(feature = "timeout")] + fib::do_test_fib(); +} diff --git a/proptest/examples/tutorial-simplify-play.rs b/proptest/examples/tutorial-simplify-play.rs new file mode 100644 index 000000000..8d1284f0f --- /dev/null +++ b/proptest/examples/tutorial-simplify-play.rs @@ -0,0 +1,29 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Shows how to pick values from a strategy and simplify them. +// +// This is *not* how proptest is normally used; it is simply used to play +// around with value generation. + +extern crate proptest; + +use proptest::strategy::{Strategy, ValueTree}; +use proptest::test_runner::TestRunner; + +fn main() { + let mut runner = TestRunner::default(); + let mut str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" + .new_tree(&mut runner) + .unwrap(); + println!("str_val = {}", str_val.current()); + while str_val.simplify() { + println!(" = {}", str_val.current()); + } +} diff --git a/proptest/examples/tutorial-strategy-play.rs b/proptest/examples/tutorial-strategy-play.rs new file mode 100644 index 000000000..22b4e2c56 --- /dev/null +++ b/proptest/examples/tutorial-strategy-play.rs @@ -0,0 +1,31 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Shows how to pick values from a strategy. +// +// This is *not* how proptest is normally used; it is simply used to play +// around with value generation. + +extern crate proptest; + +use proptest::strategy::{Strategy, ValueTree}; +use proptest::test_runner::TestRunner; + +fn main() { + let mut runner = TestRunner::default(); + let int_val = (0..100i32).new_tree(&mut runner).unwrap(); + let str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" + .new_tree(&mut runner) + .unwrap(); + println!( + "int_val = {}, str_val = {}", + int_val.current(), + str_val.current() + ); +} diff --git a/proptest/gen-readme.sh b/proptest/gen-readme.sh new file mode 100755 index 000000000..054ed37d7 --- /dev/null +++ b/proptest/gen-readme.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +# Generate `README.md` from the crate documentation, plus some extra stuff. + +cat readme-prologue.md >README.md +>README.md +cat readme-antelogue.md >>README.md diff --git a/proptest/proptest-regressions/arbitrary/_std/env.txt b/proptest/proptest-regressions/arbitrary/_std/env.txt new file mode 100644 index 000000000..f15e33a4e --- /dev/null +++ b/proptest/proptest-regressions/arbitrary/_std/env.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 1820944860 846518628 1859875405 4214131038 # shrinks to mut buf = [55296, 0, 56320], p = 1 diff --git a/proptest/readme-antelogue.md b/proptest/readme-antelogue.md new file mode 100644 index 000000000..774dff1c3 --- /dev/null +++ b/proptest/readme-antelogue.md @@ -0,0 +1,13 @@ + +# Acknowledgements + +This crate wouldn't have come into existence had it not been for the [Rust port +of QuickCheck](https://github.com/burntsushi/quickcheck) and the +[`regex_generate`](https://github.com/CryptArchy/regex_generate) crate which +gave wonderful examples of what is possible. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/proptest/readme-prologue.md b/proptest/readme-prologue.md new file mode 100644 index 000000000..39aa17f2d --- /dev/null +++ b/proptest/readme-prologue.md @@ -0,0 +1,6 @@ +# Proptest + +[![Build Status](https://travis-ci.org/AltSysrq/proptest.svg?branch=master)](https://travis-ci.org/AltSysrq/proptest) +[![Build status](https://ci.appveyor.com/api/projects/status/ofe98xfthbx1m608/branch/master?svg=true)](https://ci.appveyor.com/project/AltSysrq/proptest/branch/master) +[![](http://meritbadge.herokuapp.com/proptest)](https://crates.io/crates/proptest) + diff --git a/proptest/src/arbitrary/_alloc/alloc.rs b/proptest/src/arbitrary/_alloc/alloc.rs new file mode 100644 index 000000000..bb4adc220 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/alloc.rs @@ -0,0 +1,56 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::hash`. + +use core::cmp; +use core::ops::Range; +use core::usize; + +multiplex_alloc!(alloc::alloc, ::std::alloc); + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!(alloc::CannotReallocInPlace; alloc::CannotReallocInPlace); +arbitrary!(alloc::Global; alloc::Global); + +// Not Debug. +//lazy_just!(System, || System); + +arbitrary!(alloc::Layout, SFnPtrMap<(Range, StrategyFor), Self>; + // 1. align must be a power of two and <= (1 << 31): + // 2. "when rounded up to the nearest multiple of align, must not overflow". + static_map((0u8..32u8, any::()), |(align_power, size)| { + let align = 1usize << align_power; + let max_size = 0usize.wrapping_sub(align); + // Not quite a uniform distribution due to clamping, + // but probably good enough + alloc::Layout::from_size_align(cmp::min(max_size, size), align).unwrap() + }) +); + +arbitrary!(alloc::AllocErr, Just; Just(alloc::AllocErr)); +/* 2018-07-28 CollectionAllocErr is not currently available outside of using + * the `alloc` crate, which would require a different nightly feature. For now, + * disable. +arbitrary!(alloc::collections::CollectionAllocErr, TupleUnion<(W>, W>)>; + prop_oneof![Just(alloc::collections::CollectionAllocErr::AllocErr), + Just(alloc::collections::CollectionAllocErr::CapacityOverflow)]); + */ + +#[cfg(test)] +mod test { + no_panic_test!( + layout => alloc::Layout, + alloc_err => alloc::AllocErr + //collection_alloc_err => alloc::collections::CollectionAllocErr + ); +} diff --git a/proptest/src/arbitrary/_alloc/borrow.rs b/proptest/src/arbitrary/_alloc/borrow.rs new file mode 100644 index 000000000..8c1c3639f --- /dev/null +++ b/proptest/src/arbitrary/_alloc/borrow.rs @@ -0,0 +1,27 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for std::borrow. + +use core::borrow::Borrow; +use std_facade::{ToOwned, Cow}; +use std_facade::fmt; + +use strategy::statics::static_map; +use arbitrary::{any_with, SMapped, Arbitrary}; + +arbitrary!( + [A: Arbitrary + Borrow, B: ToOwned + fmt::Debug] + Cow<'static, B>, SMapped, A::Parameters; + args => static_map(any_with::(args), Cow::Owned) +); + +lift1!([Borrow + 'static, B: ToOwned + fmt::Debug] + Cow<'static, B>; base => static_map(base, Cow::Owned) +); diff --git a/proptest/src/arbitrary/_alloc/boxed.rs b/proptest/src/arbitrary/_alloc/boxed.rs new file mode 100644 index 000000000..01463d8cb --- /dev/null +++ b/proptest/src/arbitrary/_alloc/boxed.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::boxed`. + +use std_facade::Box; + +wrap_from!(Box); + +#[cfg(test)] +mod test { + no_panic_test!(boxed => Box); +} diff --git a/proptest/src/arbitrary/_alloc/char.rs b/proptest/src/arbitrary/_alloc/char.rs new file mode 100644 index 000000000..6cda3b6f1 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/char.rs @@ -0,0 +1,84 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::char`. + +use core::char::*; +use core::iter::once; +use core::ops::Range; +use std_facade::Vec; + +use collection::vec; + +multiplex_alloc! { + core::char::DecodeUtf16, std::char::DecodeUtf16, + core::char::DecodeUtf16Error, std::char::DecodeUtf16Error, + core::char::decode_utf16, std::char::decode_utf16 +} + +const VEC_MAX: usize = ::core::u16::MAX as usize; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +macro_rules! impl_wrap_char { + ($type: ty, $mapper: expr) => { + arbitrary!($type, SMapped; + static_map(any::(), $mapper)); + }; +} + +impl_wrap_char!(EscapeDebug, char::escape_debug); +impl_wrap_char!(EscapeDefault, char::escape_default); +impl_wrap_char!(EscapeUnicode, char::escape_unicode); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToLowercase, char::to_lowercase); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToUppercase, char::to_uppercase); + +arbitrary!(DecodeUtf16< as IntoIterator>::IntoIter>, + SMapped, Self>; + static_map(vec(any::(), ..VEC_MAX), decode_utf16) +); + +arbitrary!(ParseCharError, IndFlatten>>; + any::().prop_ind_flat_map(|is_two| + Just((if is_two { "__" } else { "" }).parse::().unwrap_err())) +); + +#[cfg(feature = "unstable")] +arbitrary!(CharTryFromError; { + use core::convert::TryFrom; + char::try_from(0xD800 as u32).unwrap_err() +}); + +arbitrary!(DecodeUtf16Error, SFnPtrMap, Self>; + static_map(0xD800..0xE000, |x| + decode_utf16(once(x)).next().unwrap().unwrap_err()) +); + +#[cfg(test)] +mod test { + no_panic_test!( + escape_debug => EscapeDebug, + escape_default => EscapeDefault, + escape_unicode => EscapeUnicode, + parse_char_error => ParseCharError, + decode_utf16 => DecodeUtf16< as IntoIterator>::IntoIter>, + decode_utf16_error => DecodeUtf16Error + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + to_lowercase => ToLowercase, + to_uppercase => ToUppercase, + char_try_from_error => CharTryFromError + ); +} diff --git a/proptest/src/arbitrary/_alloc/collections.rs b/proptest/src/arbitrary/_alloc/collections.rs new file mode 100644 index 000000000..904fd02b9 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/collections.rs @@ -0,0 +1,290 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::collections`. + +//#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] + +//============================================================================== +// Imports: +//============================================================================== + +use core::ops::{RangeInclusive, Bound}; +use core::hash::Hash; +use std_facade::{ + fmt, Box, Rc, Arc, Vec, vec, BTreeMap, BTreeSet, btree_map, btree_set, + BinaryHeap, binary_heap, VecDeque, vec_deque, LinkedList, linked_list, +}; + +#[cfg(feature = "std")] +use std_facade::{hash_map, HashMap, hash_set, HashSet}; + +use strategy::*; +use strategy::statics::static_map; +use collection::*; +use arbitrary::*; + +//============================================================================== +// Macros: +//============================================================================== + +/// Parameters for configuring the generation of `StrategyFor<...>`. +type RangedParams1 = product_type![SizeRange, A]; + +/// Parameters for configuring the generation of `StrategyFor<...>`. +type RangedParams2 = product_type![SizeRange, A, B]; + +macro_rules! impl_1 { + ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { + arbitrary!([A: Arbitrary $(+ $bound)*] $typ, + $strat, RangedParams1; + args => { + let product_unpack![range, a] = args; + $fun(any_with::(a), range) + }); + + lift1!([$($bound+)*] $typ, SizeRange; + base, args => $fun(base, args)); + }; +} + +arbitrary!(SizeRange, MapInto>, Self>; + any::>().prop_map_into() +); + +//============================================================================== +// Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: +//============================================================================== + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!([A: Arbitrary] $w<[A]>, + MapInto>, Self>, + as Arbitrary>::Parameters; + a => any_with::>(a).prop_map_into() + );)* + }; +} + +impl_1!(Vec, VecStrategy, => vec); +dst_wrapped!(Box, Rc, Arc); +impl_1!(VecDeque, VecDequeStrategy, => vec_deque); +impl_1!(LinkedList, LinkedListStrategy, => linked_list); +impl_1!(BTreeSet, BTreeSetStrategy, Ord => btree_set); +impl_1!(BinaryHeap, BinaryHeapStrategy, Ord => binary_heap); +#[cfg(feature = "std")] +impl_1!(HashSet, HashSetStrategy, Hash, Eq => hash_set); + +//============================================================================== +// IntoIterator: +//============================================================================== + +macro_rules! into_iter_1 { + ($module: ident, $type: ident $(, $bound : path)*) => { + arbitrary!([A: Arbitrary $(+ $bound)*] + $module::IntoIter, + SMapped<$type, Self>, + <$type as Arbitrary>::Parameters; + args => static_map(any_with::<$type>(args), $type::into_iter)); + + lift1!(['static + $($bound+)*] $module::IntoIter, SizeRange; + base, args => + $module(base, args).prop_map($type::into_iter)); + }; +} + +into_iter_1!(vec, Vec); +into_iter_1!(vec_deque, VecDeque); +into_iter_1!(linked_list, LinkedList); +into_iter_1!(btree_set, BTreeSet, Ord); +into_iter_1!(binary_heap, BinaryHeap, Ord); +#[cfg(feature = "std")] +into_iter_1!(hash_set, HashSet, Hash, Eq); + +//============================================================================== +// HashMap: +//============================================================================== + +#[cfg(feature = "std")] +arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] HashMap, + HashMapStrategy, + RangedParams2; + args => { + let product_unpack![range, a, b] = args; + hash_map(any_with::(a), any_with::(b), range) + }); + +#[cfg(feature = "std")] +arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), HashMap::into_iter)); + +#[cfg(feature = "std")] +lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + hash_map(any_with::(k), base, range) + } +); + +#[cfg(feature = "std")] +lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + static_map(hash_map(any_with::(k), base, range), HashMap::into_iter) + } +); + +#[cfg(feature = "std")] +impl functor::ArbitraryF2 +for HashMap { + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + hash_map(fst, snd, args).boxed() + } +} + +#[cfg(feature = "std")] +impl + functor::ArbitraryF2 +for hash_map::IntoIter { + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() + } +} + +//============================================================================== +// BTreeMap: +//============================================================================== + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap, + BTreeMapStrategy, + RangedParams2; + args => { + let product_unpack![range, a, b] = args; + btree_map(any_with::(a), any_with::(b), range) + }); + +lift1!([, K: Ord + Arbitrary + 'static] BTreeMap, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + btree_map(any_with::(k), base, range) + } +); + +impl functor::ArbitraryF2 +for BTreeMap { + type Parameters = SizeRange; + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + btree_map(fst, snd, args).boxed() + } +} + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), BTreeMap::into_iter)); + +impl + functor::ArbitraryF2 +for btree_map::IntoIter { + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() + } +} + +//============================================================================== +// Bound: +//============================================================================== + +arbitrary!([A: Arbitrary] Bound, + TupleUnion<( + W, Self>>, + W, Self>>, + W> + )>, + A::Parameters; + args => { + let base = Arc::new(any_with::(args)); + prop_oneof![ + 2 => static_map(base.clone(), Bound::Included), + 2 => static_map(base, Bound::Excluded), + 1 => LazyJust::new(|| Bound::Unbounded), + ] + } +); + +lift1!(['static] Bound; base => { + let base = Rc::new(base); + prop_oneof![ + 2 => base.clone().prop_map(Bound::Included), + 2 => base.prop_map(Bound::Excluded), + 1 => LazyJustFn::new(|| Bound::Unbounded), + ] +}); + +#[cfg(test)] +mod test { + no_panic_test!( + size_bounds => SizeRange, + vec => Vec, + box_slice => Box<[u8]>, + rc_slice => Rc<[u8]>, + arc_slice => Arc<[u8]>, + vec_deque => VecDeque, + linked_list => LinkedList, + btree_set => BTreeSet, + btree_map => BTreeMap, + bound => Bound, + binary_heap => BinaryHeap, + into_iter_vec => vec::IntoIter, + into_iter_vec_deque => vec_deque::IntoIter, + into_iter_linked_list => linked_list::IntoIter, + into_iter_binary_heap => binary_heap::IntoIter, + into_iter_btree_set => btree_set::IntoIter, + into_iter_btree_map => btree_map::IntoIter + ); + + #[cfg(feature = "std")] + no_panic_test!( + hash_set => HashSet, + hash_map => HashMap, + into_iter_hash_set => hash_set::IntoIter, + into_iter_hash_map => hash_map::IntoIter + ); +} diff --git a/proptest/src/arbitrary/_alloc/hash.rs b/proptest/src/arbitrary/_alloc/hash.rs new file mode 100644 index 000000000..0f2aadf27 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/hash.rs @@ -0,0 +1,32 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::hash`. + +use core::hash::{BuildHasherDefault, Hasher}; +#[cfg(feature = "std")] +use std_facade::hash_map::{DefaultHasher, RandomState}; + +// NOTE: don't impl for std::hash::SipHasher.. since deprecated! + +// over-constrain on purpose! +arbitrary!([H: Default + Hasher] BuildHasherDefault; Default::default()); + +#[cfg(feature = "std")] +lazy_just!(DefaultHasher, Default::default; RandomState, Default::default); + +#[cfg(test)] +mod test { + #[cfg(feature = "std")] + no_panic_test!( + default_hasher => DefaultHasher, + random_state => RandomState, + build_hasher_default => BuildHasherDefault + ); +} diff --git a/proptest/src/arbitrary/_alloc/mod.rs b/proptest/src/arbitrary/_alloc/mod.rs new file mode 100644 index 000000000..f286cab6d --- /dev/null +++ b/proptest/src/arbitrary/_alloc/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for liballoc. + +#[cfg(feature = "unstable")] +mod alloc; +mod borrow; +mod boxed; +mod char; +mod collections; +mod hash; +mod ops; +mod rc; +mod str; +mod sync; diff --git a/proptest/src/arbitrary/_alloc/ops.rs b/proptest/src/arbitrary/_alloc/ops.rs new file mode 100644 index 000000000..0caffd836 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/ops.rs @@ -0,0 +1,100 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ops`. + +use core::ops::*; +use std_facade::Arc; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!(RangeFull; ..); +wrap_ctor!(RangeFrom, |a| a..); +wrap_ctor!(RangeTo, |a| ..a); + +wrap_ctor!(RangeToInclusive, |a| ..=a); + +arbitrary!( + [A: PartialOrd + Arbitrary] RangeInclusive, + SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; + args => static_map(any_with::<(A, A)>(args), + |(a, b)| if b < a { b..=a } else { a..=b }) +); + +lift1!([PartialOrd] RangeInclusive; base => { + let base = Arc::new(base); + (base.clone(), base).prop_map(|(a, b)| if b < a { b..=a } else { a..=b }) +}); + +arbitrary!( + [A: PartialOrd + Arbitrary] Range, + SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; + args => static_map(any_with::<(A, A)>(args), + |(a, b)| if b < a { b..a } else { a..b }) +); + +lift1!([PartialOrd] Range; base => { + let base = Arc::new(base); + (base.clone(), base).prop_map(|(a, b)| if b < a { b..a } else { a..b }) +}); + +#[cfg(feature = "unstable")] +arbitrary!( + [Y: Arbitrary, R: Arbitrary] GeneratorState, + TupleUnion<(W>, W>)>, + product_type![Y::Parameters, R::Parameters]; + args => { + let product_unpack![y, r] = args; + prop_oneof![ + static_map(any_with::(y), GeneratorState::Yielded), + static_map(any_with::(r), GeneratorState::Complete) + ] + } +); + +#[cfg(feature = "unstable")] +use core::fmt; + +#[cfg(feature = "unstable")] +impl + functor::ArbitraryF2 +for GeneratorState { + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + prop_oneof![ + fst.prop_map(GeneratorState::Yielded), + snd.prop_map(GeneratorState::Complete) + ].boxed() + } +} + +#[cfg(test)] +mod test { + no_panic_test!( + range_full => RangeFull, + range_from => RangeFrom, + range_to => RangeTo, + range => Range, + range_inclusive => RangeInclusive, + range_to_inclusive => RangeToInclusive + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + generator_state => GeneratorState + ); +} diff --git a/proptest/src/arbitrary/_alloc/rc.rs b/proptest/src/arbitrary/_alloc/rc.rs new file mode 100644 index 000000000..506f55f7a --- /dev/null +++ b/proptest/src/arbitrary/_alloc/rc.rs @@ -0,0 +1,21 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::rc`. + +use std_facade::Rc; + +// Weak would always give None on upgrade since there's no owned Rc. + +wrap_from!(Rc); + +#[cfg(test)] +mod test { + no_panic_test!(rc => Rc); +} diff --git a/proptest/src/arbitrary/_alloc/str.rs b/proptest/src/arbitrary/_alloc/str.rs new file mode 100644 index 000000000..7a22efe28 --- /dev/null +++ b/proptest/src/arbitrary/_alloc/str.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::str`. + +use core::iter::repeat; +use core::str::{ParseBoolError, Utf8Error, from_utf8}; +use std_facade::Vec; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!(ParseBoolError; "".parse::().unwrap_err()); + +type ELSeq = W>; +type ELSeqs = TupleUnion<(ELSeq, ELSeq, ELSeq, ELSeq)>; + +fn gen_el_seqs() -> ELSeqs { + prop_oneof![ + Just(&[0xC2]), // None + Just(&[0x80]), // Some(1) + Just(&[0xE0, 0xA0, 0x00]), // Some(2) + Just(&[0xF0, 0x90, 0x80, 0x00]) // Some(3) + ] +} + +arbitrary!(Utf8Error, SFnPtrMap<(StrategyFor, ELSeqs), Utf8Error>; + static_map((any::(), gen_el_seqs()), |(vut, elseq)| { + let v = repeat(b'_').take(vut as usize) + .chain(elseq.iter().cloned()) + .collect::>(); + from_utf8(&v).unwrap_err() + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + parse_bool_errror => ParseBoolError, + utf8_error => Utf8Error + ); +} diff --git a/proptest/src/arbitrary/_alloc/sync.rs b/proptest/src/arbitrary/_alloc/sync.rs new file mode 100644 index 000000000..2c479950e --- /dev/null +++ b/proptest/src/arbitrary/_alloc/sync.rs @@ -0,0 +1,69 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::sync`. + +use core::sync::atomic::*; +use std_facade::Arc; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +wrap_from!(Arc); + +macro_rules! atomic { + ($($type: ident, $base: ty);+) => { + $(arbitrary!($type, SMapped<$base, Self>; + static_map(any::<$base>(), $type::new) + );)+ + }; +} + +// impl_wrap_gen!(AtomicPtr); // We don't have impl Arbitrary for *mut T yet. +atomic!(AtomicBool, bool; AtomicIsize, isize; AtomicUsize, usize); + +#[cfg(feature = "unstable")] +atomic!(AtomicI8, i8; AtomicI16, i16; AtomicI32, i32; AtomicI64, i64; + AtomicU8, u8; AtomicU16, u16; AtomicU32, u32; AtomicU64, u64); + +arbitrary!(Ordering, + TupleUnion<(W>, W>, W>, + W>, W>)>; + prop_oneof![ + Just(Ordering::Relaxed), + Just(Ordering::Release), + Just(Ordering::Acquire), + Just(Ordering::AcqRel), + Just(Ordering::SeqCst) + ] +); + +#[cfg(test)] +mod test { + no_panic_test!( + arc => Arc, + atomic_bool => AtomicBool, + atomic_isize => AtomicIsize, + atomic_usize => AtomicUsize, + ordering => Ordering + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + atomic_i8 => AtomicI8, + atomic_i16 => AtomicI16, + atomic_i32 => AtomicI32, + atomic_i64 => AtomicI64, + atomic_u8 => AtomicU8, + atomic_u16 => AtomicU16, + atomic_u32 => AtomicU32, + atomic_u64 => AtomicU64 + ); +} diff --git a/proptest/src/arbitrary/_core/ascii.rs b/proptest/src/arbitrary/_core/ascii.rs new file mode 100644 index 000000000..8176841c7 --- /dev/null +++ b/proptest/src/arbitrary/_core/ascii.rs @@ -0,0 +1,23 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ascii`. + +use core::ascii::{EscapeDefault, escape_default}; + +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!(EscapeDefault, SMapped; + static_map(any::(), escape_default)); + +#[cfg(test)] +mod test { + no_panic_test!(escape_default => EscapeDefault); +} diff --git a/proptest/src/arbitrary/_core/cell.rs b/proptest/src/arbitrary/_core/cell.rs new file mode 100644 index 000000000..35dda7bfd --- /dev/null +++ b/proptest/src/arbitrary/_core/cell.rs @@ -0,0 +1,48 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::cell`. + +use core::cell::{Cell, RefCell, UnsafeCell, BorrowError, BorrowMutError}; + +wrap_from!([Copy] Cell); +wrap_from!(RefCell); +wrap_from!(UnsafeCell); + +lazy_just!(BorrowError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow().expect_err("reborrowed RefCell"); + ret + } +}); +lazy_just!(BorrowMutError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow_mut().expect_err("reborrowed RefCell"); + ret + } +}); + +#[cfg(test)] +mod test { + no_panic_test!( + cell => Cell, + ref_cell => RefCell, + unsafe_cell => UnsafeCell + ); +} diff --git a/proptest/src/arbitrary/_core/cmp.rs b/proptest/src/arbitrary/_core/cmp.rs new file mode 100644 index 000000000..7db338beb --- /dev/null +++ b/proptest/src/arbitrary/_core/cmp.rs @@ -0,0 +1,33 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::cmp`. + +use core::cmp::{Reverse, Ordering}; + +use strategy::{Just, TupleUnion, W}; + +wrap_ctor!(Reverse, Reverse); + +type WJO = W>; +arbitrary!(Ordering, TupleUnion<(WJO, WJO, WJO)>; + prop_oneof![ + Just(Ordering::Equal), + Just(Ordering::Less), + Just(Ordering::Greater) + ] +); + +#[cfg(test)] +mod test { + no_panic_test!( + reverse => Reverse, + ordering => Ordering + ); +} diff --git a/proptest/src/arbitrary/_core/convert.rs b/proptest/src/arbitrary/_core/convert.rs new file mode 100644 index 000000000..b74d78620 --- /dev/null +++ b/proptest/src/arbitrary/_core/convert.rs @@ -0,0 +1,16 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::convert`. + +// No sensible Arbitrary impl exists for void-like types like +// std::convert::Infallible. +// +// Auto-deriving should take care to simply not include such +// types in generation instead! diff --git a/proptest/src/arbitrary/_core/fmt.rs b/proptest/src/arbitrary/_core/fmt.rs new file mode 100644 index 000000000..b16b8968c --- /dev/null +++ b/proptest/src/arbitrary/_core/fmt.rs @@ -0,0 +1,18 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::fmt`. + +use core::fmt::Error; +arbitrary!(Error; Error); + +#[cfg(test)] +mod test { + no_panic_test!(error => Error); +} diff --git a/proptest/src/arbitrary/_core/iter.rs b/proptest/src/arbitrary/_core/iter.rs new file mode 100644 index 000000000..bbb980dcf --- /dev/null +++ b/proptest/src/arbitrary/_core/iter.rs @@ -0,0 +1,177 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::iter`. + +use core::fmt; +use core::iter::*; +use core::iter::Fuse; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +// TODO: Filter, FilterMap, FlatMap, Map, Inspect, Scan, SkipWhile +// Might be possible with CoArbitrary + +wrap_ctor!(Once, once); +wrap_ctor!([Clone] Repeat, repeat); +wrap_ctor!([Iterator + Clone] Cycle, Iterator::cycle); +wrap_ctor!([Iterator] Enumerate, Iterator::enumerate); +wrap_ctor!([Iterator] Fuse, Iterator::fuse); +wrap_ctor!([Iterator, T: fmt::Debug] Peekable, Iterator::peekable); +wrap_ctor!([DoubleEndedIterator] Rev, Iterator::rev); + +arbitrary!(['a, T: 'a + Clone, A: Arbitrary + Iterator] + Cloned, SMapped, A::Parameters; + args => static_map(any_with::(args), Iterator::cloned)); + +impl<'a, T: 'static + Clone, A: fmt::Debug + 'static + Iterator> + functor::ArbitraryF1 +for Cloned { + type Parameters = (); + + fn lift1_with(base: S, _args: Self::Parameters) -> BoxedStrategy + where + S: Strategy + 'static, + { + base.prop_map(Iterator::cloned).boxed() + } +} + +arbitrary!([A] Empty; empty()); + +arbitrary!( + [A: Arbitrary + Iterator, B: Arbitrary + Iterator] + Zip, SMapped<(A, B), Self>, + product_type![A::Parameters, B::Parameters]; + args => static_map(any_with::<(A, B)>(args), |(a, b)| a.zip(b)) +); + +lift1!( + [fmt::Debug + 'static + Iterator, B: 'static + Arbitrary + Iterator] + Zip, + B::Parameters; + base, args => + (any_with::(args), base).prop_map(|(b, a)| b.zip(a)).boxed() +); + +impl + functor::ArbitraryF2 +for Zip { + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + (fst, snd).prop_map(|(a, b)| a.zip(b)).boxed() + } +} + +arbitrary!( + [T, + A: Arbitrary + Iterator, + B: Arbitrary + Iterator] + Chain, SMapped<(A, B), Self>, + product_type![A::Parameters, B::Parameters]; + args => static_map(any_with::<(A, B)>(args), |(a, b)| a.chain(b)) +); + +lift1!([fmt::Debug + 'static + Iterator, + B: 'static + Arbitrary + Iterator, + T] + Chain, + B::Parameters; + base, args => + (any_with::(args), base).prop_map(|(b, a)| b.chain(a)).boxed() +); + +impl, B: fmt::Debug + Iterator> + functor::ArbitraryF2 +for Chain { + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + (fst, snd).prop_map(|(a, b)| a.chain(b)).boxed() + } +} + +macro_rules! usize_mod { + ($type: ident, $mapper: ident) => { + arbitrary!([A: Arbitrary + Iterator] $type, + SMapped<(A, usize), Self>, A::Parameters; + a => static_map( + any_with::<(A, usize)>(product_pack![a, ()]), + |(a, b)| a.$mapper(b) + ) + ); + + lift1!([Iterator] $type; + base => (base, any::()).prop_map(|(a, b)| a.$mapper(b)) + ); + }; +} + +usize_mod!(Skip, skip); +usize_mod!(Take, take); + +#[cfg(feature = "unstable")] +usize_mod!(StepBy, step_by); + +#[cfg(test)] +mod test { + use super::*; + + use std::ops::Range; + const DUMMY: &'static [u8] = &[0, 1, 2, 3, 4]; + #[derive(Debug)] + struct Dummy(u8); + arbitrary!(Dummy, SFnPtrMap, Self>; static_map(0..5, Dummy)); + impl Iterator for Dummy { + type Item = &'static u8; + fn next(&mut self) -> Option { + if self.0 < 5 { + let r = &DUMMY[self.0 as usize]; + self.0 += 1; + Some(r) + } else { + None + } + } + } + + no_panic_test!( + empty => Empty, + once => Once, + repeat => Repeat, + cloned => Cloned, + cycle => Cycle>, + enumerate => Enumerate>, + fuse => Fuse>, + peekable => Peekable>, + rev => Rev<::std::vec::IntoIter>, + zip => Zip, Repeat>, + chain => Chain, Once>, + skip => Skip>, + take => Take> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + step_by => StepBy> + ); +} diff --git a/proptest/src/arbitrary/_core/marker.rs b/proptest/src/arbitrary/_core/marker.rs new file mode 100644 index 000000000..6558f57ab --- /dev/null +++ b/proptest/src/arbitrary/_core/marker.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::marker`. + +use core::marker::PhantomData; + +arbitrary!([T: ?Sized] PhantomData; PhantomData); + +#[cfg(test)] +mod test { + no_panic_test!(phantom_data => PhantomData); +} diff --git a/proptest/src/arbitrary/_core/mem.rs b/proptest/src/arbitrary/_core/mem.rs new file mode 100644 index 000000000..adafc7b47 --- /dev/null +++ b/proptest/src/arbitrary/_core/mem.rs @@ -0,0 +1,42 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::mem`. + +use core::mem::*; + +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!([A: Arbitrary] Discriminant, + SMapped, A::Parameters; + args => static_map(any_with::(args), |x| discriminant(&x)) +); + +lift1!(['static] Discriminant; + base => static_map(base, |x| discriminant(&x)) +); + +// Not supported at the moment since the user won't be able to call +// https://doc.rust-lang.org/nightly/std/mem/union.ManuallyDrop.html#method.drop +// in any case so the use case is not great for this. +//wrap_ctor!(ManuallyDrop); + +#[cfg(test)] +mod test { + #[derive(Copy, Clone, Debug)] + struct DummyStruct; + arbitrary!(DummyStruct; DummyStruct); + + no_panic_test!( + //manually_drop => ManuallyDrop, // Trivial destructor. + discriminant_struct => Discriminant, + discriminant_enum => Discriminant<::std::num::FpCategory> + ); +} diff --git a/proptest/src/arbitrary/_core/mod.rs b/proptest/src/arbitrary/_core/mod.rs new file mode 100644 index 000000000..5fc3742e4 --- /dev/null +++ b/proptest/src/arbitrary/_core/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for libcore. + +mod ascii; +mod cell; +mod cmp; +mod convert; +mod fmt; +mod iter; +mod marker; +mod mem; +mod num; +mod option; +mod result; diff --git a/proptest/src/arbitrary/_core/num.rs b/proptest/src/arbitrary/_core/num.rs new file mode 100644 index 000000000..53a6e4f9c --- /dev/null +++ b/proptest/src/arbitrary/_core/num.rs @@ -0,0 +1,55 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::num`. + +use core::num::*; + +use strategy::*; + +arbitrary!(ParseFloatError; "".parse::().unwrap_err()); +arbitrary!(ParseIntError; "".parse::().unwrap_err()); + +#[cfg(feature = "unstable")] +arbitrary!(TryFromIntError; { + use core::convert::TryFrom; + u8::try_from(-1).unwrap_err() +}); + +wrap_ctor!(Wrapping, Wrapping); + +arbitrary!(FpCategory, + TupleUnion<(W>, W>, W>, + W>, W>)>; + { + use core::num::FpCategory::*; + prop_oneof![ + Just(Nan), + Just(Infinite), + Just(Zero), + Just(Subnormal), + Just(Normal), + ] + } +); + +#[cfg(test)] +mod test { + no_panic_test!( + parse_float_error => ParseFloatError, + parse_int_error => ParseIntError, + wrapping => Wrapping, + fp_category => FpCategory + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + try_from_int_error => TryFromIntError + ); +} diff --git a/proptest/src/arbitrary/_core/option.rs b/proptest/src/arbitrary/_core/option.rs new file mode 100644 index 000000000..63ccc3ead --- /dev/null +++ b/proptest/src/arbitrary/_core/option.rs @@ -0,0 +1,60 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::option`. + +use core::option as opt; +use core::ops::RangeInclusive; +use std_facade::string; + +use option::{weighted, OptionStrategy, Probability}; +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +arbitrary!(Probability, MapInto, Self>; + (0.0..=1.0).prop_map_into() +); + +// These are Option impls: + +arbitrary!(Option; None); +#[cfg(feature = "unstable")] +arbitrary!(Option; None); + +arbitrary!([A: Arbitrary] opt::Option, OptionStrategy, + product_type![Probability, A::Parameters]; + args => { + let product_unpack![prob, a] = args; + weighted(prob, any_with::(a)) + } +); + +lift1!([] Option, Probability; base, prob => weighted(prob, base)); + +arbitrary!([A: Arbitrary] opt::IntoIter, SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), Option::into_iter)); + +lift1!(['static] opt::IntoIter, Probability; + base, prob => weighted(prob, base).prop_map(Option::into_iter) +); + +#[cfg(feature = "unstable")] +arbitrary!(opt::NoneError; opt::NoneError); + +#[cfg(test)] +mod test { + no_panic_test!( + probability => Probability, + option => Option, + option_iter => opt::IntoIter, + option_parse_error => Option + ); +} diff --git a/proptest/src/arbitrary/_core/result.rs b/proptest/src/arbitrary/_core/result.rs new file mode 100644 index 000000000..aa9be8443 --- /dev/null +++ b/proptest/src/arbitrary/_core/result.rs @@ -0,0 +1,106 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::result`. + +use core::fmt; +use core::result::IntoIter; +use std_facade::string; + +use strategy::*; +use strategy::statics::static_map; +use result::*; +use arbitrary::*; + +// These are Result with uninhabited type in some variant: +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Ok) +); +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Err) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Ok) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Err) +); + +lift1!([] Result; Result::Ok); +#[cfg(feature = "unstable")] +lift1!([] Result; Result::Ok); + +// We assume that `MaybeOk` is canonical as it's the most likely Strategy +// a user wants. + +arbitrary!([A: Arbitrary, B: Arbitrary] Result, + MaybeOk, + product_type![Probability, A::Parameters, B::Parameters]; + args => { + let product_unpack![prob, a, b] = args; + let (p, a, b) = (prob, any_with::(a), any_with::(b)); + maybe_ok_weighted(p, a, b) + } +); + +impl functor::ArbitraryF1 for Result +where + E::Strategy: 'static +{ + type Parameters = product_type![Probability, E::Parameters]; + + fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + { + let product_unpack![prob, e] = args; + let (p, a, e) = (prob, base, any_with::(e)); + maybe_ok_weighted(p, a, e).boxed() + } +} + +impl functor::ArbitraryF2 +for Result { + type Parameters = Probability; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + maybe_ok_weighted(args, fst, snd).boxed() + } +} + +arbitrary!([A: Arbitrary] IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), Result::into_iter) +); + +lift1!(['static] IntoIter, Probability; base, args => { + maybe_ok_weighted(args, base, Just(())).prop_map(Result::into_iter) +}); + +#[cfg(test)] +mod test { + no_panic_test!( + result => Result, + into_iter => IntoIter, + result_a_parse_error => Result, + result_parse_error_a => Result<::std::string::ParseError, u8> + ); +} diff --git a/proptest/src/arbitrary/_std/env.rs b/proptest/src/arbitrary/_std/env.rs new file mode 100644 index 000000000..24b86860f --- /dev/null +++ b/proptest/src/arbitrary/_std/env.rs @@ -0,0 +1,134 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::env`. + +use std::env::*; +use std::iter::once; +use std::ffi::OsString; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +// FIXME: SplitPaths when lifetimes in strategies are possible. + +lazy_just!( + Args, args; + ArgsOs, args_os; + Vars, vars; + VarsOs, vars_os; + JoinPathsError, jpe +); + +#[cfg(not(target_os = "windows"))] +fn jpe() -> JoinPathsError { + join_paths(once(":")).unwrap_err() +} + +#[cfg(target_os = "windows")] +fn jpe() -> JoinPathsError { + join_paths(once("\"")).unwrap_err() +} + +// Algorithm from: https://stackoverflow.com/questions/47749164 +#[cfg(any(target_os = "windows", test))] +fn make_utf16_invalid(buf: &mut [u16], p: usize) { + // Verify that length is non-empty. + // An empty string is always valid UTF-16. + assert!(buf.len() > 0); + + // If first elem or previous entry is not a leading surrogate. + let gen_trail = 0 == p || 0xd800 != (buf[p - 1] & 0xfc00); + // If last element or succeeding entry is not a traililng surrogate. + let gen_lead = p == buf.len() - 1 || 0xdc00 != (buf[p + 1] & 0xfc00); + let (force_bits_mask, force_bits_value) = if gen_trail { + if gen_lead { + // Trailing or leading surrogate. + (0xf800, 0xd800) + } else { + // Trailing surrogate. + (0xfc00, 0xdc00) + } + } else { + // Leading surrogate. + // Note that `gen_lead` and `gen_trail` could both be false here if `p` + // lies exactly between a leading and a trailing surrogate. In this + // case, it doesn't matter what we do because the UTF-16 will be + // invalid regardless, so just always force a leading surrogate. + (0xfc00, 0xd800) + }; + debug_assert_eq!(0, (force_bits_value & !force_bits_mask)); + buf[p] = (buf[p] & !force_bits_mask) | force_bits_value; +} + +/// Generates the set of `WTF-16 \ UTF-16` and makes +/// an `OsString` that is not a valid String from it. +#[cfg(target_os = "windows")] +fn osstring_invalid_string() -> impl Strategy { + use std::os::windows::ffi::OsStringExt; + let size = 1..::std::u16::MAX as usize; + let vec_gen = ::collection::vec(..::std::u16::MAX, size.clone()); + (size, vec_gen).prop_map(|(p, mut sbuf)| { + // Not quite a uniform distribution due to clamping, + // but probably good enough + let p = ::std::cmp::min(p, sbuf.len() - 1); + make_utf16_invalid(&mut sbuf, p); + OsString::from_wide(sbuf.as_slice()).into_string().unwrap_err() + }) +} + +#[cfg(not(target_os = "windows"))] +fn osstring_invalid_string() -> impl Strategy { + use std::os::unix::ffi::OsStringExt; + use arbitrary::_std::string::not_utf8_bytes; + static_map(not_utf8_bytes(true), OsString::from_vec) +} + +arbitrary!(VarError, + TupleUnion<( + W>, + W, Self>> + )>; + prop_oneof![ + Just(VarError::NotPresent), + static_map(osstring_invalid_string().boxed(), VarError::NotUnicode) + ] +); + +#[cfg(test)] +mod test { + use super::*; + use num; + use test_runner::Config; + + no_panic_test!( + args => Args, + args_os => ArgsOs, + vars => Vars, + vars_os => VarsOs, + join_paths_error => JoinPathsError, + var_error => VarError + ); + + proptest! { + #![proptest_config(Config { + cases: 65536, + .. Config::default() + })] + + #[test] + fn make_utf16_invalid_doesnt_panic( + mut buf in [num::u16::ANY; 3], + p in 0usize..3 + ) { + make_utf16_invalid(&mut buf, p); + } + } +} diff --git a/proptest/src/arbitrary/_std/ffi.rs b/proptest/src/arbitrary/_std/ffi.rs new file mode 100644 index 000000000..6db4d9cb5 --- /dev/null +++ b/proptest/src/arbitrary/_std/ffi.rs @@ -0,0 +1,100 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ffi`. + +use std::ffi::*; +use std::ops::RangeInclusive; +use std_facade::{Box, Vec, String}; + +use strategy::*; +use strategy::statics::static_map; +use collection::*; +use arbitrary::*; + +use super::string::not_utf8_bytes; + +arbitrary!(CString, + SFnPtrMap>, Self>, SizeRange; + args => static_map(vec(1..=::std::u8::MAX, args + 1), |mut vec| { + vec.pop().unwrap(); + // Could use: Self::from_vec_unchecked(vec) safely. + Self::new(vec).unwrap() + }) +); + +arbitrary!(OsString, MapInto, Self>, + ::Parameters; + a => any_with::(a).prop_map_into() +); + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!($w, MapInto, Self>, SizeRange; + a => any_with::(a).prop_map_into() + );)* + $(arbitrary!($w, MapInto, Self>, + ::Parameters; + a => any_with::(a).prop_map_into() + );)* + }; +} + +dst_wrapped!(Box); + +#[cfg(feature = "unstable")] +use std::rc::Rc; +#[cfg(feature = "unstable")] +use std::sync::Arc; +#[cfg(feature = "unstable")] +dst_wrapped!(Rc, Arc); + +arbitrary!(FromBytesWithNulError, SMapped, Self>; { + static_map(any::>(), |opt_pos| { + // We make some assumptions about the internal structure of + // FromBytesWithNulError. However, these assumptions do not + // involve any non-public API. + if let Some(pos) = opt_pos { + let pos = pos as usize; + // Allocate pos + 2 so that we never reallocate: + let mut v = Vec::::with_capacity(pos + 2); + v.extend(::std::iter::repeat(1).take(pos)); + v.push(0); + v.push(1); + CStr::from_bytes_with_nul(v.as_slice()).unwrap_err() + } else { + CStr::from_bytes_with_nul(b"").unwrap_err() + } + }) +}); + +arbitrary!(IntoStringError, SFnPtrMap>, Self>; + static_map(not_utf8_bytes(false).boxed(), |bytes| + CString::new(bytes).unwrap().into_string().unwrap_err() + ) +); + +#[cfg(test)] +mod test { + no_panic_test!( + c_string => CString, + os_string => OsString, + box_c_str => Box, + box_os_str => Box, + into_string_error => IntoStringError, + from_bytes_with_nul => FromBytesWithNulError + ); + #[cfg(feature = "unstable")] + no_panic_test!( + rc_c_str => Rc, + rc_os_str => Rc, + arc_c_str => Arc, + arc_os_str => Arc + ); +} diff --git a/proptest/src/arbitrary/_std/fs.rs b/proptest/src/arbitrary/_std/fs.rs new file mode 100644 index 000000000..642fdf2f8 --- /dev/null +++ b/proptest/src/arbitrary/_std/fs.rs @@ -0,0 +1,30 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::fs`. + +use std::fs::{DirBuilder}; + +use strategy::statics::static_map; +use arbitrary::{any, SMapped}; + +// TODO: other parts (figure out workable semantics). + +arbitrary!(DirBuilder, SMapped; { + static_map(any::(), |recursive| { + let mut db = DirBuilder::new(); + db.recursive(recursive); + db + }) +}); + +#[cfg(test)] +mod test { + no_panic_test!(dir_builder => DirBuilder); +} diff --git a/proptest/src/arbitrary/_std/io.rs b/proptest/src/arbitrary/_std/io.rs new file mode 100644 index 000000000..b9e547633 --- /dev/null +++ b/proptest/src/arbitrary/_std/io.rs @@ -0,0 +1,164 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::io`. + +use std::io::*; +use std::io::ErrorKind::*; +#[cfg(test)] +use std_facade::Vec; +use std_facade::String; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +// TODO: IntoInnerError +// Consider: std::io::Initializer + +macro_rules! buffer { + ($type: ident, $bound: path) => { + arbitrary!( + [A: Arbitrary + $bound] $type, + SMapped<(A, Option), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(inner, cap)| { + if let Some(cap) = cap { + $type::with_capacity(cap as usize, inner) + } else { + $type::new(inner) + } + } + ) + ); + + lift1!([$bound] $type; base => + (base, any::>()).prop_map(|(inner, cap)| { + if let Some(cap) = cap { + $type::with_capacity(cap as usize, inner) + } else { + $type::new(inner) + } + }) + ); + }; +} + +buffer!(BufReader, Read); +buffer!(BufWriter, Write); +buffer!(LineWriter, Write); + +arbitrary!( + [A: Read + Arbitrary, B: Read + Arbitrary] Chain, + SMapped<(A, B), Self>, product_type![A::Parameters, B::Parameters]; + args => static_map(arbitrary_with(args), |(a, b)| a.chain(b)) +); + +wrap_ctor!(Cursor); + +lazy_just!( + Empty, empty + ; Sink, sink + ; Stderr, stderr + ; Stdin, stdin + ; Stdout, stdout +); + +wrap_ctor!([BufRead] Lines, BufRead::lines); + +arbitrary!(Repeat, SMapped; static_map(any::(), repeat)); + +arbitrary!( + [A: BufRead + Arbitrary] Split, SMapped<(A, u8), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(a, b)| a.split(b) + ) +); +lift1!(['static + BufRead] Split; + base => (base, any::()).prop_map(|(a, b)| a.split(b))); + +arbitrary!( + [A: Read + Arbitrary] Take, SMapped<(A, u64), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(a, b)| a.take(b) + ) +); +lift1!(['static + Read] Take; + base => (base, any::()).prop_map(|(a, b)| a.take(b))); + +arbitrary!(ErrorKind, Union>; + Union::new( + [ NotFound + , PermissionDenied + , ConnectionRefused + , ConnectionReset + , ConnectionAborted + , NotConnected + , AddrInUse + , AddrNotAvailable + , BrokenPipe + , AlreadyExists + , WouldBlock + , InvalidInput + , InvalidData + , TimedOut + , WriteZero + , Interrupted + , Other + , UnexpectedEof + // TODO: watch this type for variant-additions. + ].into_iter().cloned().map(Just)) +); + +arbitrary!( + SeekFrom, + TupleUnion<( + W>, + W>, + W>, + )>; + prop_oneof![ + static_map(any::(), SeekFrom::Start), + static_map(any::(), SeekFrom::End), + static_map(any::(), SeekFrom::Current) + ] +); + +arbitrary!(Error, SMapped<(ErrorKind, Option), Self>; + static_map(arbitrary(), |(k, os)| + if let Some(s) = os { Error::new(k, s) } else { k.into() } + ) +); + +#[cfg(test)] +mod test { + + no_panic_test!( + buf_reader => BufReader, + buf_writer => BufWriter, + line_writer => LineWriter, + chain => Chain>, + cursor => Cursor, + empty => Empty, + sink => Sink, + stderr => Stderr, + stdin => Stdin, + stdout => Stdout, + lines => Lines, + repeat => Repeat, + split => Split>>, + take => Take, + error_kind => ErrorKind, + seek_from => SeekFrom, + error => Error + ); +} diff --git a/proptest/src/arbitrary/_std/mod.rs b/proptest/src/arbitrary/_std/mod.rs new file mode 100644 index 000000000..4360f5e07 --- /dev/null +++ b/proptest/src/arbitrary/_std/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for libstd. + +mod env; +mod ffi; +mod fs; +mod io; +mod net; +mod panic; +mod path; +mod string; +mod sync; +mod thread; +mod time; diff --git a/proptest/src/arbitrary/_std/net.rs b/proptest/src/arbitrary/_std/net.rs new file mode 100644 index 000000000..7cfa4dbbc --- /dev/null +++ b/proptest/src/arbitrary/_std/net.rs @@ -0,0 +1,116 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::net`. + +use std::net::*; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +// TODO: Can we design a workable semantic for PBT wrt. actual networking +// connections? + +arbitrary!(AddrParseError; "".parse::().unwrap_err()); + +arbitrary!(Ipv4Addr, + TupleUnion<( + W>, + W>, + W, Self>> + )>; + prop_oneof![ + 1 => Just(Self::new(0, 0, 0, 0)), + 4 => Just(Self::new(127, 0, 0, 1)), + 10 => any::().prop_map_into() + ] +); + +arbitrary!(Ipv6Addr, + TupleUnion<( + W>, + W, Self>> + )>; + prop_oneof![ + 2 => static_map(any::(), |ip| ip.to_ipv6_mapped()), + 1 => any::<[u16; 8]>().prop_map_into() + ] +); + +arbitrary!(SocketAddrV4, SMapped<(Ipv4Addr, u16), Self>; + static_map(any::<(Ipv4Addr, u16)>(), |(a, b)| Self::new(a, b)) +); + +arbitrary!(SocketAddrV6, SMapped<(Ipv6Addr, u16, u32, u32), Self>; + static_map(any::<(Ipv6Addr, u16, u32, u32)>(), + |(a, b, c, d)| Self::new(a, b, c, d)) +); + +arbitrary!(IpAddr, + TupleUnion<(W, Self>>, + W, Self>>)>; + prop_oneof![ + any::().prop_map_into(), + any::().prop_map_into() + ] +); + +arbitrary!(Shutdown, + TupleUnion<(W>, W>, W>)>; + { + use std::net::Shutdown::*; + prop_oneof![Just(Both), Just(Read), Just(Write)] + } +); +arbitrary!(SocketAddr, + TupleUnion<(W, Self>>, + W, Self>>)>; + prop_oneof![ + any::().prop_map_into(), + any::().prop_map_into() + ] +); + +#[cfg(feature = "unstable")] +arbitrary!(Ipv6MulticastScope, + TupleUnion<( W>, W>, W> + , W>, W>, W>, W>)>; + { + use std::net::Ipv6MulticastScope::*; + prop_oneof![ + Just(InterfaceLocal), + Just(LinkLocal), + Just(RealmLocal), + Just(AdminLocal), + Just(SiteLocal), + Just(OrganizationLocal), + Just(Global), + ] + } +); + +#[cfg(test)] +mod test { + no_panic_test!( + addr_parse_error => AddrParseError, + ipv4_addr => Ipv4Addr, + ipv6_addr => Ipv6Addr, + socket_addr_v4 => SocketAddrV4, + socket_addr_v6 => SocketAddrV6, + ip_addr => IpAddr, + shutdown => Shutdown, + socket_addr => SocketAddr + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + ipv6_multicast_scope => Ipv6MulticastScope + ); +} diff --git a/proptest/src/arbitrary/_std/panic.rs b/proptest/src/arbitrary/_std/panic.rs new file mode 100644 index 000000000..c2bd40cd4 --- /dev/null +++ b/proptest/src/arbitrary/_std/panic.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::panic`. + +use std::panic::AssertUnwindSafe; + +wrap_ctor!(AssertUnwindSafe, AssertUnwindSafe); + +#[cfg(test)] +mod test { + no_panic_test!(assert_unwind_safe => AssertUnwindSafe); +} diff --git a/proptest/src/arbitrary/_std/path.rs b/proptest/src/arbitrary/_std/path.rs new file mode 100644 index 000000000..e7d063c17 --- /dev/null +++ b/proptest/src/arbitrary/_std/path.rs @@ -0,0 +1,23 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::path`. + +use std::path::*; + +// TODO: Figure out PathBuf and then Box/Rc/Box. + +arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); + +#[cfg(test)] +mod test { + no_panic_test!( + strip_prefix_error => StripPrefixError + ); +} diff --git a/proptest/src/arbitrary/_std/string.rs b/proptest/src/arbitrary/_std/string.rs new file mode 100644 index 000000000..4feacbdb3 --- /dev/null +++ b/proptest/src/arbitrary/_std/string.rs @@ -0,0 +1,296 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::string`. + +use std::iter; +use std::slice; +use std::rc::Rc; +use std::sync::Arc; +use std_facade::{Box, Vec, String}; + +multiplex_alloc! { + alloc::string::FromUtf8Error, ::std::string::FromUtf8Error, + alloc::string::FromUtf16Error, ::std::string::FromUtf16Error +} + +use strategy::*; +use strategy::statics::static_map; +use collection; +use arbitrary::*; +use string::StringParam; + +impl Arbitrary for String { + type Parameters = StringParam; + type Strategy = &'static str; + + /// ## Panics + /// + /// This implementation panics if the input is not a valid regex proptest + /// can handle. + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + args.into() + } +} + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!($w, MapInto, Self>, StringParam; + a => any_with::(a).prop_map_into() + );)* + }; +} + +dst_wrapped!(Box, Rc, Arc); + +lazy_just!(FromUtf16Error, || String::from_utf16(&[0xD800]).unwrap_err()); + +// This is a void-like type, it needs to be handled by the user of +// the type by simply never constructing the variant in an enum or for +// structs by inductively not generating the struct. +// The same applies to ! and Infallible. +// generator!(ParseError, || panic!()); + +arbitrary!(FromUtf8Error, SFnPtrMap>, Self>; + static_map(not_utf8_bytes(true).boxed(), + |bs| String::from_utf8(bs).unwrap_err()) +); + +/// This strategy produces sequences of bytes that are guaranteed to be illegal +/// wrt. UTF-8 with the goal of producing a suffix of bytes in the end of +/// an otherwise legal UTF-8 string that causes the string to be illegal. +/// This is used primarily to generate the `Utf8Error` type and similar. +pub(crate) fn not_utf8_bytes(allow_null: bool) -> impl Strategy> { + let prefix = collection::vec(any::(), ..::std::u16::MAX as usize); + let suffix = gen_el_bytes(allow_null); + (prefix, suffix).prop_map(move |(prefix_bytes, el_bytes)| { + let iter = prefix_bytes.iter(); + let string: String = if allow_null { + iter.collect() + } else { + iter.filter(|&&x| x != '\u{0}').collect() + }; + let mut bytes = string.into_bytes(); + bytes.extend(el_bytes.into_iter()); + bytes + }) +} + +/// Stands for "error_length" bytes and contains a suffix of bytes that +/// will cause the whole string to become invalid UTF-8. +/// See `gen_el_bytes` for more details. +#[derive(Debug)] +enum ELBytes { + B1([u8; 1]), + B2([u8; 2]), + B3([u8; 3]), + B4([u8; 4]) +} + +impl<'a> IntoIterator for &'a ELBytes { + type Item = u8; + type IntoIter = iter::Cloned>; + fn into_iter(self) -> Self::IntoIter { + use self::ELBytes::*; + (match *self { + B1(ref a) => a.iter(), + B2(ref a) => a.iter(), + B3(ref a) => a.iter(), + B4(ref a) => a.iter(), + }).cloned() + } +} + +// By analysis of run_utf8_validation defined at: +// https://doc.rust-lang.org/nightly/src/core/str/mod.rs.html#1429 +// we know that .error_len() \in {None, Some(1), Some(2), Some(3)}. +// We represent this with the range [0..4) and generate a valid +// sequence from that. +fn gen_el_bytes(allow_null: bool) -> impl Strategy { + fn b1(a: u8) -> ELBytes { ELBytes::B1([a]) } + fn b2(a: (u8, u8)) -> ELBytes { ELBytes::B2([a.0, a.1]) } + fn b3(a: ((u8, u8), u8)) -> ELBytes { ELBytes::B3([(a.0).0, (a.0).1, a.1]) } + fn b4(a: ((u8, u8), u8, u8)) -> ELBytes { + ELBytes::B4([(a.0).0, (a.0).1, a.1, a.2]) + } + + /* + // https://tools.ietf.org/html/rfc3629 + static UTF8_CHAR_WIDTH: [u8; 256] = [ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF + 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF + 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF + ]; + + /// Mask of the value bits of a continuation byte. + const CONT_MASK: u8 = 0b0011_1111; + /// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. + const TAG_CONT_U8: u8 = 0b1000_0000; + */ + + // Continuation byte: + let succ_byte = 0x80u8..0xC0u8; + + // Do we allow the nul byte or not? + let start_byte = if allow_null { 0x00u8 } else { 0x01u8 }; + + // Invalid continuation byte: + let fail_byte = prop_oneof![start_byte..0x7Fu8, 0xC1u8..]; + + // Matches zero in the UTF8_CHAR_WIDTH table above. + let byte0_w0 = prop_oneof![0x80u8..0xC0u8, 0xF5u8..]; + + // Start of a 3 (width) byte sequence: + // Leads here: https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1479 + let byte0_w2 = 0xC2u8..0xE0u8; + + // Start of a 3 (width) byte sequence: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1484 + // See the left column in the match. + let byte0_w3 = 0xE0u8..0xF0u8; + + // Start of a 4 (width) byte sequence: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1495 + // See the left column in the match. + let byte0_w4 = 0xF0u8..0xF5u8; + + // The 2 first (valid) bytes of a 3 (width) byte sequence: + // The first byte is byte0_w3. The second is the ones produced on the right. + let byte01_w3 = byte0_w3.clone().prop_flat_map(|x| (Just(x), match x { + 0xE0u8 => 0xA0u8..0xC0u8, + 0xE1u8...0xECu8 => 0x80u8..0xC0u8, + 0xEDu8 => 0x80u8..0xA0u8, + 0xEEu8...0xEFu8 => 0x80u8..0xA0u8, + _ => panic!(), + })); + + // In a 3 (width) byte sequence, an invalid second byte is chosen such that + // it will yield an error length of Some(1). The second byte is on + // the right of the match arms. + let byte01_w3_e1 = byte0_w3.clone().prop_flat_map(move |x| (Just(x), match x { + 0xE0u8 => prop_oneof![start_byte..0xA0u8, 0xC0u8..], + 0xE1u8...0xECu8 => prop_oneof![start_byte..0x80u8, 0xC0u8..], + 0xEDu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + 0xEEu8...0xEFu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + _ => panic!(), + })); + + // In a 4 (width) byte sequence, an invalid second byte is chosen such that + // it will yield an error length of Some(1). The second byte is on + // the right of the match arms. + let byte01_w4_e1 = byte0_w4.clone().prop_flat_map(move |x| (Just(x), match x { + 0xF0u8 => prop_oneof![start_byte..0x90u8, 0xA0u8..], + 0xF1u8...0xF3u8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + 0xF4u8 => prop_oneof![start_byte..0x80u8, 0x90u8..], + _ => panic!() + })); + + // The 2 first (valid) bytes of a 4 (width) byte sequence: + // The first byte is byte0_w4. The second is the ones produced on the right. + let byte01_w4 = byte0_w4.clone().prop_flat_map(|x| (Just(x), match x { + 0xF0u8 => 0x90u8..0xA0u8, + 0xF1u8...0xF3u8 => 0x80u8..0xA0u8, + 0xF4u8 => 0x80u8..0x90u8, + _ => panic!() + })); + + prop_oneof![ + // error_len = None + // These are all happen when next!() fails to provide a byte. + prop_oneof![ + // width = 2 + // lacking 1 bytes: + static_map(byte0_w2.clone(), b1), + + // width = 3 + // lacking 2 bytes: + static_map(byte0_w3, b1), + + // lacking 1 bytes: + static_map(byte01_w3.clone(), b2), + + // width = 4 + // lacking 3 bytes: + static_map(byte0_w4, b1), + + // lacking 2 bytes: + static_map(byte01_w4.clone(), b2), + + // lacking 1 byte: + static_map((byte01_w4.clone(), succ_byte.clone()), b3), + ], + + // error_len = Some(1) + prop_oneof![ + // width = 1 is not represented. + // width = 0 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1508 + static_map(byte0_w0, b1), + + // width = 2 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1480 + static_map((byte0_w2, fail_byte.clone()), b2), + + // width = 3 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1488 + static_map(byte01_w3_e1, b2), + + // width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1499 + static_map(byte01_w4_e1, b2), + ], + + // error_len = Some(2) + static_map(prop_oneof![ + // width = 3 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1491 + (byte01_w3, fail_byte.clone()), + + // width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1502 + (byte01_w4.clone(), fail_byte.clone()) + ], b3), + + // error_len = Some(3), width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1505 + static_map((byte01_w4, succ_byte, fail_byte), b4), + ].boxed() +} + +#[cfg(test)] +mod test { + no_panic_test!( + string => String, + str_box => Box, + str_rc => Rc, + str_arc => Arc, + from_utf16_error => FromUtf16Error, + from_utf8_error => FromUtf8Error + ); +} diff --git a/proptest/src/arbitrary/_std/sync.rs b/proptest/src/arbitrary/_std/sync.rs new file mode 100644 index 000000000..52b5fbe0d --- /dev/null +++ b/proptest/src/arbitrary/_std/sync.rs @@ -0,0 +1,168 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::sync`. + +use std::fmt; +use std::sync::*; +use std::sync::mpsc::*; +use std::thread; +use std::time::Duration; + +use strategy::*; +use strategy::statics::static_map; +use arbitrary::*; + +// OnceState can not escape Once::call_once_force. +// PoisonError depends implicitly on the lifetime on MutexGuard, etc. +// This transitively applies to TryLockError. + +// Not doing Weak because .upgrade() would always return None. + +#[cfg(not(feature = "unstable"))] +wrap_ctor!(Mutex); +#[cfg(feature = "unstable")] +wrap_from!(Mutex); + +#[cfg(not(feature = "unstable"))] +wrap_ctor!(RwLock); +#[cfg(feature = "unstable")] +wrap_from!(RwLock); + +arbitrary!(Barrier, SMapped; // usize would be extreme! + static_map(any::(), |n| Barrier::new(n as usize)) +); + +arbitrary!(BarrierWaitResult, + TupleUnion<(W>, W>)>; + prop_oneof![LazyJust::new(bwr_true), LazyJust::new(bwr_false)] +); + +lazy_just!( + Condvar, Default::default; + Once, Once::new +); + +arbitrary!(WaitTimeoutResult, TupleUnion<(W>, W>)>; + prop_oneof![Just(wtr_true()), Just(wtr_false())] +); + +fn bwr_true() -> BarrierWaitResult { + Barrier::new(1).wait() +} + +fn bwr_false() -> BarrierWaitResult { + let barrier = Arc::new(Barrier::new(2)); + let b2 = barrier.clone(); + let jh = thread::spawn(move|| { b2.wait() }); + let bwr1 = barrier.wait(); + let bwr2 = jh.join().unwrap(); + if bwr1.is_leader() { bwr2 } else { bwr1 } +} + +fn wtr_false() -> WaitTimeoutResult { + let cvar = Arc::new(Condvar::new()); + let cvar2 = cvar.clone(); + thread::spawn(move|| { cvar2.notify_one(); }); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1)); + let (_, wtr) = wt.unwrap(); + wtr +} + +fn wtr_true() -> WaitTimeoutResult { + let cvar = Condvar::new(); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0)); + let (_, wtr) = wt.unwrap(); + wtr +} + +arbitrary!(RecvError; RecvError); + +arbitrary!([T: Arbitrary] SendError, SMapped, T::Parameters; + args => static_map(any_with::(args), SendError) +); + +arbitrary!(RecvTimeoutError, TupleUnion<(W>, W>)>; + prop_oneof![ + Just(RecvTimeoutError::Disconnected), + Just(RecvTimeoutError::Timeout) + ] +); + +arbitrary!(TryRecvError, TupleUnion<(W>, W>)>; + prop_oneof![ + Just(TryRecvError::Disconnected), + Just(TryRecvError::Empty) + ] +); + +arbitrary!( + [P: Clone + Default, T: Arbitrary] TrySendError, + TupleUnion<(W>, W>)>, P; + args => prop_oneof![ + static_map(any_with::(args.clone()), TrySendError::Disconnected), + static_map(any_with::(args), TrySendError::Full), + ] +); + +#[cfg(feature = "unstable")] +lazy_just!(Select, Select::new); + +// If only half of a pair is generated then you will get a hang-up. +// Thus the only meaningful impls are in pairs. +arbitrary!([A] (Sender, Receiver), LazyJustFn; + LazyJust::new(channel) +); + +arbitrary!([A: fmt::Debug] (Sender, IntoIter), LazyJustFn; + LazyJust::new(|| { + let (rx, tx) = channel(); + (rx, tx.into_iter()) + }) +); + +arbitrary!([A] (SyncSender, Receiver), SMapped; + static_map(any::(), |size| sync_channel(size as usize)) +); + +arbitrary!([A: fmt::Debug] (SyncSender, IntoIter), SMapped; + static_map(any::(), |size| { + let (rx, tx) = sync_channel(size as usize); + (rx, tx.into_iter()) + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + mutex => Mutex, + rw_lock => RwLock, + barrier => Barrier, + barrier_wait_result => BarrierWaitResult, + condvar => Condvar, + once => Once, + wait_timeout_result => WaitTimeoutResult, + recv_error => RecvError, + send_error => SendError, + recv_timeout_error => RecvTimeoutError, + try_recv_error => TryRecvError, + try_send_error => TrySendError, + rx_tx => (Sender, Receiver), + rx_txiter => (Sender, IntoIter), + syncrx_tx => (SyncSender, Receiver), + syncrx_txiter => (SyncSender, IntoIter) + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + select => Select + ); +} diff --git a/proptest/src/arbitrary/_std/thread.rs b/proptest/src/arbitrary/_std/thread.rs new file mode 100644 index 000000000..635b31861 --- /dev/null +++ b/proptest/src/arbitrary/_std/thread.rs @@ -0,0 +1,81 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::thread`. + +use std::thread::*; +use std_facade::String; + +use strategy::statics::static_map; +use option::prob; +use arbitrary::*; + +arbitrary!(Builder, SMapped<(Option, Option), Self>; { + let prob = prob(0.7); + let args = product_pack![ + product_pack![prob, Default::default()], + product_pack![prob, Default::default()] + ]; + static_map(arbitrary_with(args), |(os, on)| { + let mut b = Builder::new(); + b = if let Some(size) = os { b.stack_size(size) } else { b }; + if let Some(name) = on { b.name(name) } else { b } + }) +}); + +/* + * The usefulness of this impl is debatable - as are its semantics. + * Perhaps a CoArbitrary-based solution is preferable. + +arbitrary!([A: 'static + Send + Arbitrary<'a>] JoinHandle, + SMapped<'a, (A, Option<()>, u8), Self>, A::Parameters; + args => { + let prob = prob(0.1); + let args2 = product_pack![ + args, + product_pack![prob, default()], + default() + ]; + any_with_smap(args2, |(val, panic, sleep)| thread::spawn(move || { + // Sleep a random amount: + use std::time::Duration; + thread::sleep(Duration::from_millis(sleep as u64)); + + // Randomly panic: + if panic.is_some() { + panic!("Arbitrary for JoinHandle randomly paniced!"); + } + + // Move value into thread and then just return it: + val + })) + } +); +*/ + +#[cfg(test)] +mod test { + no_panic_test!( + builder => Builder + ); + + /* + use super::*; + proptest! { + #[test] + fn join_handle_works(ref jh in any::>()) { + use std::panic::catch_unwind; + catch_unwind(|| { + jh.join(); + () + }) + } + } + */ +} diff --git a/proptest/src/arbitrary/_std/time.rs b/proptest/src/arbitrary/_std/time.rs new file mode 100644 index 000000000..e423808ec --- /dev/null +++ b/proptest/src/arbitrary/_std/time.rs @@ -0,0 +1,50 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::time`. + +use std::time::*; +use core::ops::Range; + +use strategy::statics::{self, static_map}; +use arbitrary::*; +use num; + +arbitrary!(Duration, SMapped<(u64, u32), Self>; + static_map(any::<(u64, u32)>(), |(a, b)| Duration::new(a, b)) +); + +// Instant::now() "never" returns the same Instant, so no shrinking may occur! +arbitrary!(Instant; Self::now()); + +arbitrary!( + // We can't use `any::()` because the addition to `SystemTime` + // can overflow and panic. To be conservative, we only allow seconds to go + // to i32::MAX since a certain popular OS still uses `i32` to represent the + // seconds counter. + SystemTime, statics::Map<(num::i32::Any, Range), + fn ((i32, u32)) -> SystemTime>; + static_map((num::i32::ANY, 0..1_000_000_000u32), + |(sec, ns)| { + if sec >= 0 { + UNIX_EPOCH + Duration::new(sec as u64, ns) + } else { + UNIX_EPOCH - Duration::new((-(sec as i64)) as u64, ns) + } + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + duration => Duration, + instant => Instant, + system_time => SystemTime + ); +} diff --git a/proptest/src/arbitrary/arrays.rs b/proptest/src/arbitrary/arrays.rs new file mode 100644 index 000000000..40026d258 --- /dev/null +++ b/proptest/src/arbitrary/arrays.rs @@ -0,0 +1,36 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for arrays. + +use arbitrary::{Arbitrary, any_with}; +use array::UniformArrayStrategy; + +macro_rules! array { + ($($n: expr),*) => { $( + impl Arbitrary for [A; $n] { + type Parameters = A::Parameters; + type Strategy = UniformArrayStrategy; + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let base = any_with::(args); + UniformArrayStrategy::new(base) + } + } + )* }; +} + +array!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + +#[cfg(test)] +mod test { + no_panic_test!( + array_16 => [u8; 16] + ); +} diff --git a/proptest/src/arbitrary/functor.rs b/proptest/src/arbitrary/functor.rs new file mode 100644 index 000000000..5dcedf3b5 --- /dev/null +++ b/proptest/src/arbitrary/functor.rs @@ -0,0 +1,212 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Provides higher order `Arbitrary` traits. +//! This is mainly for use by `proptest_derive`. +//! +//! ## Stability note +//! +//! This trait is mainly defined for `proptest_derive` to simplify the +//! mechanics of deriving recursive types. If you have custom containers +//! and want to support recursive for those, it is a good idea to implement +//! this trait. +//! +//! There are clearer and terser ways that work better with +//! inference such as using `proptest::collection::vec(..)` +//! to achieve the same result. +//! +//! For these reasons, the traits here are deliberatly +//! not exported in a convenient way. + +use std_facade::fmt; + +use strategy::{Strategy, BoxedStrategy}; + +/// `ArbitraryF1` lets you lift a [`Strategy`] to unary +/// type constructors such as `Box`, `Vec`, and `Option`. +/// +/// The trait corresponds to +/// [Haskell QuickCheck's `Arbitrary1` type class][HaskellQC]. +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary1 +/// +/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html +pub trait ArbitraryF1: fmt::Debug + Sized { + //========================================================================== + // Implementation note #1 + //========================================================================== + // It might be better to do this with generic associated types by + // having an associated type: + // + // `type Strategy: Strategy;` + // + // But with this setup we will likely loose the ability to add bounds + // such as `Hash + Eq` on `A` which is needed for `HashSet`. We might + // be able to regain this ability with a ConstraintKinds feature. + // + // This alternate formulation will likely work better with type inference. + // + //========================================================================== + // Implementation note #2 + //========================================================================== + // + // Until `-> impl Trait` has been stabilized, `BoxedStrategy` must be + // used. This incurs an unfortunate performance penalty - but since + // we are dealing with testing, it is better to provide slowed down and + // somewhat less general functionality than no functionality at all. + // Implementations should just use `.boxed()` in the end. + //========================================================================== + + /// The type of parameters that [`lift1_with`] accepts for + /// configuration of the lifted and generated [`Strategy`]. Parameters + /// must implement [`Default`]. + /// + /// [`lift1_with`]: + /// trait.ArbitraryF1.html#tymethod.lift1_with + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `SomeType` + /// to a container such as `Vec`. + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::lift1_with(base, Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`X::lift1_with(base, Default::default())`]: + /// trait.ArbitraryF1.html#tymethod.lift1_with + fn lift1(base: AS) -> BoxedStrategy + where AS: Strategy + 'static { + Self::lift1_with(base, Self::Parameters::default()) + } + + /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `SomeType` + /// to a container such as `Vec` of `SomeType`. The composite strategy is + /// passed the arguments given in `args`. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`lift1`] instead. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`lift1`]: trait.ArbitraryF1.html#method.lift1 + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy + where AS: Strategy + 'static; +} + +/// `ArbitraryF2` lets you lift [`Strategy`] to binary +/// type constructors such as `Result`, `HashMap`. +/// +/// The trait corresponds to +/// [Haskell QuickCheck's `Arbitrary2` type class][HaskellQC]. +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary2 +/// +/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html +pub trait ArbitraryF2: fmt::Debug + Sized { + /// The type of parameters that [`lift2_with`] accepts for + /// configuration of the lifted and generated [`Strategy`]. Parameters + /// must implement [`Default`]. + /// + /// [`lift2_with`]: trait.ArbitraryF2.html#tymethod.lift2_with + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Lifts two given strategies to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `Type1` + /// and one for `Type2` to a container such as `HashMap`. + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::lift2_with(base, Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`X::lift2_with(base, Default::default())`]: + /// trait.Arbitrary.html#tymethod.lift2_with + fn lift2(fst: AS, snd: BS) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + Self::lift2_with(fst, snd, Self::Parameters::default()) + } + + /// Lifts two given strategies to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `Type1` + /// and one for `Type2` to a container such as `HashMap`. + /// The composite strategy is passed the arguments given in `args`. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`lift2`] instead. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`lift2`]: trait.ArbitraryF2.html#method.lift2 + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) + -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static; +} + +macro_rules! lift1 { + ([$($bounds : tt)*] $typ: ty, $params: ty; + $base: ident, $args: ident => $logic: expr) => { + impl + $crate::arbitrary::functor::ArbitraryF1 + for $typ { + type Parameters = $params; + + fn lift1_with($base: S, $args: Self::Parameters) + -> $crate::strategy::BoxedStrategy + where + S: $crate::strategy::Strategy + 'static + { + $crate::strategy::Strategy::boxed($logic) + } + } + }; + ([$($bounds : tt)*] $typ: ty; $base: ident => $logic: expr) => { + lift1!([$($bounds)*] $typ, (); $base, _args => $logic); + }; + ([$($bounds : tt)*] $typ: ty; $mapper: expr) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map(base, $mapper)); + }; + ([$($bounds : tt)*] $typ: ty) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map_into(base)); + }; +} diff --git a/proptest/src/arbitrary/macros.rs b/proptest/src/arbitrary/macros.rs new file mode 100644 index 000000000..8edf2a6ea --- /dev/null +++ b/proptest/src/arbitrary/macros.rs @@ -0,0 +1,115 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(feature = "std"), allow(unused_macros))] + +//============================================================================== +// Macros for quick implementing: +//============================================================================== + +macro_rules! arbitrary { + ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; + $args: ident => $logic: expr) => { + impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ { + type Parameters = $params; + type Strategy = $strat; + fn arbitrary_with($args: Self::Parameters) -> Self::Strategy { + $logic + } + } + }; + ([$($bounds : tt)*] $typ: ty, $strat: ty; $logic: expr) => { + arbitrary!([$($bounds)*] $typ, $strat, (); _args => $logic); + }; + ([$($bounds : tt)*] $typ: ty; $logic: expr) => { + arbitrary!([$($bounds)*] $typ, + $crate::strategy::Just, (); + _args => $crate::strategy::Just($logic) + ); + }; + ($typ: ty, $strat: ty, $params: ty; $args: ident => $logic: expr) => { + arbitrary!([] $typ, $strat, $params; $args => $logic); + }; + ($typ: ty, $strat: ty; $logic: expr) => { + arbitrary!([] $typ, $strat; $logic); + }; + ($strat: ty; $logic: expr) => { + arbitrary!([] $strat; $logic); + }; + ($($typ: ident),*) => { + $(arbitrary!($typ, $typ::Any; $typ::ANY);)* + }; +} + +macro_rules! wrap_ctor { + ($wrap: ident) => { + wrap_ctor!([] $wrap); + }; + ($wrap: ident, $maker: expr) => { + wrap_ctor!([] $wrap, $maker); + }; + ([$($bound : tt)*] $wrap: ident) => { + wrap_ctor!([$($bound)*] $wrap, $wrap::new); + }; + ([$($bound : tt)*] $wrap: ident, $maker: expr) => { + arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, + $crate::arbitrary::SMapped, A::Parameters; + args => $crate::strategy::statics::static_map( + $crate::arbitrary::any_with::(args), $maker)); + + lift1!([$($bound)*] $wrap; $maker); + }; +} + +macro_rules! wrap_from { + ($wrap: ident) => { + wrap_from!([] $wrap); + }; + ([$($bound : tt)*] $wrap: ident) => { + arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, + $crate::strategy::MapInto, A::Parameters; + args => $crate::strategy::Strategy::prop_map_into( + $crate::arbitrary::any_with::(args))); + + lift1!([$($bound)*] $wrap); + }; +} + +macro_rules! lazy_just { + ($($self: ty, $fun: expr);+) => { + $( + arbitrary!($self, $crate::strategy::LazyJust Self>; + $crate::strategy::LazyJust::new($fun)); + )+ + }; +} + +//============================================================================== +// Macros for testing: +//============================================================================== + +/// We are mostly interested in ensuring that generating input from our +/// strategies is able to construct a value, therefore ensuring that +/// no panic occurs is mostly sufficient. Shrinking for strategies that +/// use special shrinking methods can be handled separately. +#[cfg(test)] +macro_rules! no_panic_test { + ($($module: ident => $self: ty),+) => { + $( + mod $module { + #[allow(unused_imports)] + use super::super::*; + proptest! { + #[test] + fn no_panic(_ in $crate::arbitrary::any::<$self>()) {} + } + } + )+ + }; +} diff --git a/proptest/src/arbitrary/mod.rs b/proptest/src/arbitrary/mod.rs new file mode 100644 index 000000000..0f875a829 --- /dev/null +++ b/proptest/src/arbitrary/mod.rs @@ -0,0 +1,63 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines the [`Arbitrary`] trait and related free functions +//! and type aliases. See the trait for more information. +//! +//! [`Arbitrary`]: trait.Arbitrary.html + +use strategy::{Map, Strategy}; +use strategy::statics; + +//============================================================================== +// Trait and impls +//============================================================================== + +mod traits; + +#[macro_use] pub mod functor; + +#[macro_use] mod macros; + +mod primitives; +mod arrays; +mod tuples; +mod sample; + +mod _core; + +#[cfg(any(feature = "std", feature = "alloc"))] +mod _alloc; + +#[cfg(feature = "std")] +mod _std; + +pub use self::traits::*; + +//============================================================================== +// SMapped + Mapped aliases to make documentation clearer. +//============================================================================== + +pub(crate) type SFnPtrMap = statics::Map::Value) -> O>; + +/// A static map from a strategy of `I` to `O`. +/// +/// # Stability +/// +/// This is provided to make documentation more readable. +/// Do not rely on it existing in your own code. +pub type SMapped = statics::Map, fn(I) -> O>; + +/// A normal map from a strategy of `I` to `O`. +/// +/// # Stability +/// +/// This is provided to make documentation more readable. +/// Do not rely on it existing in your own code. +pub type Mapped = Map, fn(I) -> O>; diff --git a/proptest/src/arbitrary/primitives.rs b/proptest/src/arbitrary/primitives.rs new file mode 100644 index 000000000..619c8835d --- /dev/null +++ b/proptest/src/arbitrary/primitives.rs @@ -0,0 +1,44 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for primitive types. + +use bool; +use char; +use num::{isize, usize, f32, f64, i16, i32, i64, i8, u16, u32, u64, u8, + u128, i128}; + +arbitrary!( + bool, + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize +); + +// Note that for floating point types we limit the space since a lot of code +// isn't prepared for (and is not intended to be) things like NaN and infinity. +arbitrary!(f32, f32::Any; { + f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL +}); +arbitrary!(f64, f64::Any; { + f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL +}); + +arbitrary!(char, char::CharStrategy<'static>; char::any()); + +#[cfg(test)] +mod test { + no_panic_test!( + bool => bool, + char => char, + f32 => f32, f64 => f64, + isize => isize, usize => usize, + i8 => i8, i16 => i16, i32 => i32, i64 => i64, i128 => i128, + u8 => u8, u16 => u16, u32 => u32, u64 => u64, u128 => u128 + ); +} diff --git a/proptest/src/arbitrary/sample.rs b/proptest/src/arbitrary/sample.rs new file mode 100644 index 000000000..94f8796c6 --- /dev/null +++ b/proptest/src/arbitrary/sample.rs @@ -0,0 +1,31 @@ +//- +// Copyright 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sample::{Index, IndexStrategy, Selector, SelectorStrategy}; +use arbitrary::Arbitrary; + +impl Arbitrary for Index { + type Parameters = (); + + type Strategy = IndexStrategy; + + fn arbitrary_with(_: ()) -> IndexStrategy { + IndexStrategy::new() + } +} + +impl Arbitrary for Selector { + type Parameters = (); + + type Strategy = SelectorStrategy; + + fn arbitrary_with(_: ()) -> SelectorStrategy { + SelectorStrategy::new() + } +} diff --git a/proptest/src/arbitrary/traits.rs b/proptest/src/arbitrary/traits.rs new file mode 100644 index 000000000..3ac7e1405 --- /dev/null +++ b/proptest/src/arbitrary/traits.rs @@ -0,0 +1,297 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::fmt; + +use strategy::Strategy; + +//============================================================================== +// Arbitrary trait +//============================================================================== + +/// Arbitrary determines a canonical [`Strategy`] for the implementing type. +/// +/// It provides the method `arbitrary_with` which generates a `Strategy` for +/// producing arbitrary values of the implementing type *(`Self`)*. In general, +/// these strategies will produce the entire set of values possible for the +/// type, up to some size limitation or constraints set by their parameters. +/// When this is not desired, strategies to produce the desired values can be +/// built by combining [`Strategy`]s as described in the crate documentation. +/// +/// This trait analogous to +/// [Haskell QuickCheck's implementation of `Arbitrary`][HaskellQC]. +/// In this interpretation of `Arbitrary`, `Strategy` is the equivalent of +/// the `Gen` monad. Unlike in QuickCheck, `Arbitrary` is not a core component; +/// types do not need to implement `Arbitrary` unless one wants to use +/// [`any`](fn.any.html) or other free functions in this module. +/// +/// `Arbitrary` currently only works for types which represent owned data as +/// opposed to borrowed data. This is a fundamental restriction of `proptest` +/// which may be lifted in the future as the [generic associated types (GAT)] +/// feature of Rust is implemented and stabilized. +/// +/// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 +/// +/// [`Strategy`]: ../strategy/trait.Strategy.html +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck-Arbitrary.html +pub trait Arbitrary: Sized + fmt::Debug { + /// The type of parameters that [`arbitrary_with`] accepts for configuration + /// of the generated [`Strategy`]. Parameters must implement [`Default`]. + /// + /// [`arbitrary_with`]: trait.Arbitrary.html#tymethod.arbitrary_with + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Generates a [`Strategy`] for producing arbitrary values + /// of type the implementing type (`Self`). + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::arbitrary_with(Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`X::arbitrary_with(Default::default())`]: + /// trait.Arbitrary.html#tymethod.arbitrary_with + fn arbitrary() -> Self::Strategy { + Self::arbitrary_with(Default::default()) + } + + /// Generates a [`Strategy`] for producing arbitrary values of type the + /// implementing type (`Self`). The strategy is passed the arguments given + /// in args. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`arbitrary`] instead. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// + /// [`arbitrary`]: trait.Arbitrary.html#method.arbitrary + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy; + + /// The type of [`Strategy`] used to generate values of type `Self`. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + type Strategy: Strategy; +} + +//============================================================================== +// Type aliases for associated types +//============================================================================== + +/// `StrategyFor` allows you to mention the type of [`Strategy`] for the input +/// type `A` without directly using associated types or without resorting to +/// existential types. This way, if implementation of [`Arbitrary`] changes, +/// your tests should not break. This can be especially beneficial when the +/// type of `Strategy` that you are dealing with is very long in name +/// (the case with generics). +/// +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +pub type StrategyFor = ::Strategy; + +/// `ParamsFor` allows you to mention the type of [`Parameters`] for the input +/// type `A` without directly using associated types or without resorting to +/// existential types. This way, if implementation of [`Arbitrary`] changes, +/// your tests should not break. +/// +/// [`Parameters`]: trait.Arbitrary.html#associatedtype.Parameters +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +pub type ParamsFor = ::Parameters; + +//============================================================================== +// Free functions that people should use +//============================================================================== + +/// Generates a [`Strategy`] producing [`Arbitrary`][trait Arbitrary] values of +/// `A`. Unlike [`arbitrary`][fn arbitrary], it should be used for being +/// explicit on what `A` is. For clarity, this may be a good idea. +/// +/// Use this version instead of [`arbitrary`][fn arbitrary] if you want to be +/// clear which type you want to generate a `Strategy` for, or if you don't +/// have an anchoring type for type inference to work with. +/// +/// If you want to customize how the strategy is generated, use +/// [`any_with::(args)`] where `args` are any arguments accepted by +/// the `Arbitrary` impl in question. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::any; +/// +/// proptest! { +/// fn reverse_reverse_is_identity(ref vec in any::>()) { +/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any_with::(args)`]: fn.any_with.html +/// [fn arbitrary]: fn.arbitrary.html +/// [trait Arbitrary]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn any() -> StrategyFor { + // ^-- We use a shorter name so that turbofish becomes more ergonomic. + A::arbitrary() +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the +/// given configuration arguments passed in `args`. Unlike [`arbitrary_with`], +/// it should be used for being explicit on what `A` is. +/// For clarity, this may be a good idea. +/// +/// Use this version instead of [`arbitrary_with`] if you want to be clear which +/// type you want to generate a `Strategy` for, or if you don't have an anchoring +/// type for type inference to work with. +/// +/// If you don't want to specify any arguments and instead use the default +/// behavior, you should use [`any::()`]. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::any_with; +/// use proptest::collection::size_range; +/// +/// proptest! { +/// fn reverse_reverse_is_identity +/// (ref vec in any_with::>(size_range(1000).lift())) +/// { +/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any::()`]: fn.any.html +/// [`arbitrary_with`]: fn.arbitrary_with.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn any_with(args: ParamsFor) -> StrategyFor { + // ^-- We use a shorter name so that turbofish becomes more ergonomic. + A::arbitrary_with(args) +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A`. +/// Works better with type inference than [`any::()`]. +/// +/// With this version, you shouldn't need to specify any of the (many) type +/// parameters explicitly. This can have a positive effect on type inference. +/// However, if you want specify `A`, you should use [`any::()`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any::()`] can be a good idea. +/// +/// If you want to customize how the strategy is generated, use +/// [`arbitrary_with(args)`] where `args` is of type +/// `::Parameters`. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// extern crate proptest; +/// use proptest::arbitrary::{arbitrary, StrategyFor}; +/// +/// fn gen_vec_usize() -> StrategyFor> { +/// arbitrary() +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`arbitrary_with(args)`]: fn.arbitrary_with.html +/// [`any::()`]: fn.any.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn arbitrary() -> S +where + // The backlinking here cause an injection which helps type inference. + S: Strategy, + A: Arbitrary, +{ + A::arbitrary() +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the +/// given configuration arguments passed in `args`. +/// Works better with type inference than [`any_with::(args)`]. +/// +/// With this version, you shouldn't need to specify any of the (many) type +/// parameters explicitly. This can have a positive effect on type inference. +/// However, if you want specify `A`, you should use +/// [`any_with::(args)`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any_with::(args)`] can be a good idea. +/// +/// If you don't want to specify any arguments and instead use the default +/// behavior, you should use [`arbitrary()`]. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// extern crate proptest; +/// use proptest::arbitrary::{arbitrary_with, StrategyFor}; +/// use proptest::collection::size_range; +/// +/// fn gen_vec_10_u32() -> StrategyFor> { +/// arbitrary_with(size_range(10).lift()) +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`any_with::(args)`]: fn.any_with.html +/// [`arbitrary()`]: fn.arbitrary.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn arbitrary_with(args: P) -> S +where + P: Default, + // The backlinking here cause an injection which helps type inference. + S: Strategy, + A: Arbitrary, +{ + A::arbitrary_with(args) +} diff --git a/proptest/src/arbitrary/tuples.rs b/proptest/src/arbitrary/tuples.rs new file mode 100644 index 000000000..3eb4317fb --- /dev/null +++ b/proptest/src/arbitrary/tuples.rs @@ -0,0 +1,45 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for tuples. + +use arbitrary::{Arbitrary, any_with}; + +macro_rules! impl_tuple { + ($($typ: ident),*) => { + impl<$($typ : Arbitrary),*> Arbitrary for ($($typ,)*) { + type Parameters = product_type![$($typ::Parameters,)*]; + type Strategy = ($($typ::Strategy,)*); + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + #[allow(non_snake_case)] + let product_unpack![$($typ),*] = args; + ($(any_with::<$typ>($typ)),*,) + } + } + }; +} + +arbitrary!((); ()); +impl_tuple!(T0); +impl_tuple!(T0, T1); +impl_tuple!(T0, T1, T2); +impl_tuple!(T0, T1, T2, T3); +impl_tuple!(T0, T1, T2, T3, T4); +impl_tuple!(T0, T1, T2, T3, T4, T5); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); + +#[cfg(test)] +mod test { + no_panic_test!( + tuple_n10 => ((), bool, u8, u16, u32, u64, i8, i16, i32, i64) + ); +} diff --git a/proptest/src/array.rs b/proptest/src/array.rs new file mode 100644 index 000000000..09ea70907 --- /dev/null +++ b/proptest/src/array.rs @@ -0,0 +1,292 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for strategies producing fixed-length arrays. +//! +//! An array of strategies (but only length 1 to 32 for now) is itself a +//! strategy which generates arrays of that size drawing elements from the +//! corresponding input strategies. +//! +//! See also [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for +//! easily making a strategy for an array drawn from one strategy. +//! +//! General implementations are available for sizes 1 through 32. + +use core::marker::PhantomData; + +use strategy::*; +use test_runner::*; + +/// A `Strategy` which generates fixed-size arrays containing values drawn from +/// an inner strategy. +/// +/// `T` must be an array type of length 1 to 32 whose values are produced by +/// strategy `S`. Instances of this type are normally created by the various +/// `uniformXX` functions in this module. +/// +/// This is mainly useful when the inner strategy is not `Copy`, precluding +/// expressing the strategy as `[myStrategy; 32]`, for example. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// proptest! { +/// #[test] +/// fn test_something(a in prop::array::uniform32(1u32..)) { +/// let unexpected = [0u32;32]; +/// // `a` is also a [u32;32], so we can compare them directly +/// assert_ne!(unexpected, a); +/// } +/// } +/// # fn main() { } +/// ``` +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Copy, Debug)] +pub struct UniformArrayStrategy { + strategy: S, + _marker: PhantomData, +} + +impl UniformArrayStrategy { + /// Directly create a `UniformArrayStrategy`. + /// + /// This is only intended for advanced use, since the only way to specify + /// the array size is with the turbofish operator and explicitly naming the + /// type of the values in the array and the strategy itself. + /// + /// Prefer the `uniformXX` functions at module-level unless something + /// precludes their use. + pub fn new(strategy: S) -> Self { + UniformArrayStrategy { + strategy, + _marker: PhantomData, + } + } +} + +/// A `ValueTree` operating over a fixed-size array. +#[derive(Clone, Copy, Debug)] +pub struct ArrayValueTree { + tree: T, + shrinker: usize, + last_shrinker: Option, +} + +macro_rules! small_array { + ($n:tt $uni:ident : $($ix:expr),*) => { + /// Create a strategy to generate fixed-length arrays. + /// + /// All values within the new strategy are generated using the given + /// strategy. The length of the array corresponds to the suffix of the + /// name of this function. + /// + /// See [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for + /// example usage. + pub fn $uni + (strategy: S) -> UniformArrayStrategy + { + UniformArrayStrategy { + strategy, + _marker: PhantomData + } + } + + impl Strategy for [S; $n] { + type Tree = ArrayValueTree<[S::Tree; $n]>; + type Value = [S::Value; $n]; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(ArrayValueTree { + tree: [$(self[$ix].new_tree(runner)?,)*], + shrinker: 0, + last_shrinker: None, + }) + } + } + + impl Strategy + for UniformArrayStrategy { + type Tree = ArrayValueTree<[S::Tree; $n]>; + type Value = [S::Value; $n]; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(ArrayValueTree { + tree: [$({ + let _ = $ix; + self.strategy.new_tree(runner)? + },)*], + shrinker: 0, + last_shrinker: None, + }) + } + } + + impl ValueTree for ArrayValueTree<[T;$n]> { + type Value = [T::Value;$n]; + + fn current(&self) -> [T::Value;$n] { + [$(self.tree[$ix].current(),)*] + } + + fn simplify(&mut self) -> bool { + while self.shrinker < $n { + if self.tree[self.shrinker].simplify() { + self.last_shrinker = Some(self.shrinker); + return true; + } else { + self.shrinker += 1; + } + } + + false + } + + fn complicate(&mut self) -> bool { + if let Some(shrinker) = self.last_shrinker { + self.shrinker = shrinker; + if self.tree[shrinker].complicate() { + true + } else { + self.last_shrinker = None; + false + } + } else { + false + } + } + } + } +} + +small_array!(1 uniform1: + 0); +small_array!(2 uniform2: + 0, 1); +small_array!(3 uniform3: + 0, 1, 2); +small_array!(4 uniform4: + 0, 1, 2, 3); +small_array!(5 uniform5: + 0, 1, 2, 3, 4); +small_array!(6 uniform6: + 0, 1, 2, 3, 4, 5); +small_array!(7 uniform7: + 0, 1, 2, 3, 4, 5, 6); +small_array!(8 uniform8: + 0, 1, 2, 3, 4, 5, 6, 7); +small_array!(9 uniform9: + 0, 1, 2, 3, 4, 5, 6, 7, 8); +small_array!(10 uniform10: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); +small_array!(11 uniform11: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +small_array!(12 uniform12: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); +small_array!(13 uniform13: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); +small_array!(14 uniform14: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); +small_array!(15 uniform15: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14); +small_array!(16 uniform16: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); +small_array!(17 uniform17: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); +small_array!(18 uniform18: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); +small_array!(19 uniform19: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18); +small_array!(20 uniform20: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19); +small_array!(21 uniform21: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20); +small_array!(22 uniform22: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21); +small_array!(23 uniform23: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22); +small_array!(24 uniform24: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23); +small_array!(25 uniform25: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24); +small_array!(26 uniform26: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25); +small_array!(27 uniform27: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26); +small_array!(28 uniform28: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27); +small_array!(29 uniform29: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28); +small_array!(30 uniform30: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29); +small_array!(31 uniform31: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30); +small_array!(32 uniform32: + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn shrinks_fully_ltr() { + fn pass(a: [i32;2]) -> bool { + a[0] * a[1] <= 9 + } + + let input = [0..32, 0..32]; + let mut runner = TestRunner::default(); + + let mut cases_tested = 0; + for _ in 0..256 { + // Find a failing test case + let mut case = input.new_tree(&mut runner).unwrap(); + if pass(case.current()) { continue; } + + loop { + if pass(case.current()) { + if !case.complicate() { break; } + } else { + if !case.simplify() { break; } + } + } + + let last = case.current(); + assert!(!pass(last)); + // Maximally shrunken + assert!(pass([last[0] - 1, last[1]])); + assert!(pass([last[0], last[1] - 1])); + + cases_tested += 1; + } + + assert!(cases_tested > 32, "Didn't find enough test cases"); + } + + #[test] + fn test_sanity() { + check_strategy_sanity([(0i32..1000),(1i32..1000)], None); + } +} diff --git a/proptest/src/bits.rs b/proptest/src/bits.rs new file mode 100644 index 000000000..5d85c244b --- /dev/null +++ b/proptest/src/bits.rs @@ -0,0 +1,654 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for working with bit sets. +//! +//! Besides `BitSet` itself, this also defines strategies for all the primitive +//! integer types. These strategies are appropriate for integers which are used +//! as bit flags, etc; e.g., where the most reasonable simplification of `64` +//! is `0` (clearing one bit) and not `63` (clearing one bit but setting 6 +//! others). For integers treated as numeric values, see the corresponding +//! modules of the `num` module instead. + +use core::marker::PhantomData; +use core::mem; +use std_facade::{fmt, Vec}; + +#[cfg(feature = "bit-set")] +use bit_set::BitSet; +use rand::{self, Rng}; + +use collection::SizeRange; +use num::sample_uniform_incl; +use strategy::*; +use test_runner::*; + +/// Trait for types which can be handled with `BitSetStrategy`. +#[cfg_attr(feature="cargo-clippy", allow(len_without_is_empty))] +pub trait BitSetLike : Clone + fmt::Debug { + /// Create a new value of `Self` with space for up to `max` bits, all + /// initialised to zero. + fn new_bitset(max: usize) -> Self; + /// Return an upper bound on the greatest bit set _plus one_. + fn len(&self) -> usize; + /// Test whether the given bit is set. + fn test(&self, ix: usize) -> bool; + /// Set the given bit. + fn set(&mut self, ix: usize); + /// Clear the given bit. + fn clear(&mut self, ix: usize); + /// Return the number of bits set. + /// + /// This has a default for backwards compatibility, which simply does a + /// linear scan through the bits. Implementations are strongly encouraged + /// to override this. + fn count(&self) -> usize { + let mut n = 0; + for i in 0..self.len() { + if self.test(i) { + n += 1; + } + } + n + } +} + +macro_rules! int_bitset { + ($typ:ty) => { + impl BitSetLike for $typ { + fn new_bitset(_: usize) -> Self { 0 } + fn len(&self) -> usize { mem::size_of::<$typ>()*8 } + fn test(&self, ix: usize) -> bool { + 0 != (*self & ((1 as $typ) << ix)) + } + fn set(&mut self, ix: usize) { + *self |= (1 as $typ) << ix; + } + fn clear(&mut self, ix: usize) { + *self &= !((1 as $typ) << ix); + } + fn count(&self) -> usize { + self.count_ones() as usize + } + } + } +} +int_bitset!(u8); +int_bitset!(u16); +int_bitset!(u32); +int_bitset!(u64); +int_bitset!(usize); +int_bitset!(i8); +int_bitset!(i16); +int_bitset!(i32); +int_bitset!(i64); +int_bitset!(isize); + +#[cfg(feature = "bit-set")] +impl BitSetLike for BitSet { + fn new_bitset(max: usize) -> Self { + BitSet::with_capacity(max) + } + + fn len(&self) -> usize { + self.capacity() + } + + fn test(&self, bit: usize) -> bool { + self.contains(bit) + } + + fn set(&mut self, bit: usize) { + self.insert(bit); + } + + fn clear(&mut self, bit: usize) { + self.remove(bit); + } + + fn count(&self) -> usize { + self.len() + } +} + +impl BitSetLike for Vec { + fn new_bitset(max: usize) -> Self { + vec![false; max] + } + + fn len(&self) -> usize { + self.len() + } + + fn test(&self, bit: usize) -> bool { + if bit >= self.len() { + false + } else { + self[bit] + } + } + + fn set(&mut self, bit: usize) { + if bit >= self.len() { + self.resize(bit + 1, false); + } + + self[bit] = true; + } + + fn clear(&mut self, bit: usize) { + if bit < self.len() { + self[bit] = false; + } + } + + fn count(&self) -> usize { + self.iter().filter(|&&b| b).count() + } +} + +/// Generates values as a set of bits between the two bounds. +/// +/// Values are generated by uniformly setting individual bits to 0 +/// or 1 between the bounds. Shrinking iteratively clears bits. +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Copy, Debug)] +pub struct BitSetStrategy { + min: usize, + max: usize, + mask: Option +} + +impl BitSetStrategy { + /// Create a strategy which generates values where bits between `min` + /// (inclusive) and `max` (exclusive) may be set. + /// + /// Due to the generics, the functions in the typed submodules are usually + /// preferable to calling this directly. + pub fn new(min: usize, max: usize) -> Self { + BitSetStrategy { + min, max, mask: None, + } + } + + /// Create a strategy which generates values where any bits set (and only + /// those bits) in `mask` may be set. + pub fn masked(mask: T) -> Self { + BitSetStrategy { + min: 0, + max: mask.len(), + mask: Some(mask) + } + } +} + +impl Strategy for BitSetStrategy { + type Tree = BitSetValueTree; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let mut inner = T::new_bitset(self.max); + for bit in self.min..self.max { + if self.mask.as_ref().map_or(true, |mask| mask.test(bit)) && + runner.rng().gen() + { + inner.set(bit); + } + } + + Ok(BitSetValueTree { + inner, + shrink: self.min, + prev_shrink: None, + min_count: 0 + }) + } +} + +/// Generates bit sets with a particular number of bits set. +/// +/// Specifically, this strategy is given both a size range and a bit range. To +/// produce a new value, it selects a size, then uniformly selects that many +/// bits from within the bit range. +/// +/// Shrinking happens as with [`BitSetStrategy`](struct.BitSetStrategy.html). +#[derive(Clone, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct SampledBitSetStrategy { + size: SizeRange, + bits: SizeRange, + _marker: PhantomData, +} + +impl SampledBitSetStrategy { + /// Create a strategy which generates values where bits within the bounds + /// given by `bits` may be set. The number of bits that are set is chosen + /// to be in the range given by `size`. + /// + /// Due to the generics, the functions in the typed submodules are usually + /// preferable to calling this directly. + /// + /// ## Panics + /// + /// Panics if `size` includes a value that is greater than the number of + /// bits in `bits`. + pub fn new(size: impl Into, bits: impl Into) + -> Self { + let size = size.into(); + let bits = bits.into(); + size.assert_nonempty(); + + let available_bits = bits.end_excl() - bits.start(); + assert!(size.end_excl() <= available_bits + 1, + "Illegal SampledBitSetStrategy: have {} bits available, \ + but requested size is {}..{}", + available_bits, size.start(), size.end_excl()); + SampledBitSetStrategy { + size, bits, _marker: PhantomData + } + } +} + +impl Strategy for SampledBitSetStrategy { + type Tree = BitSetValueTree; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let mut bits = T::new_bitset(self.bits.end_excl()); + let count = sample_uniform_incl( + runner, self.size.start(), self.size.end_incl()); + for bit in + rand::seq::sample_iter(runner.rng(), self.bits.iter(), count) + .expect("not enough bits to sample") + { + bits.set(bit); + } + + Ok(BitSetValueTree { + inner: bits, + shrink: self.bits.start(), + prev_shrink: None, + min_count: self.size.start(), + }) + } +} + +/// Value tree produced by `BitSetStrategy` and `SampledBitSetStrategy`. +#[derive(Clone, Copy, Debug)] +pub struct BitSetValueTree { + inner: T, + shrink: usize, + prev_shrink: Option, + min_count: usize, +} + +impl ValueTree for BitSetValueTree { + type Value = T; + + fn current(&self) -> T { + self.inner.clone() + } + + fn simplify(&mut self) -> bool { + if self.inner.count() <= self.min_count { + return false; + } + + while self.shrink < self.inner.len() && + !self.inner.test(self.shrink) + { self.shrink += 1; } + + if self.shrink >= self.inner.len() { + self.prev_shrink = None; + false + } else { + self.prev_shrink = Some(self.shrink); + self.inner.clear(self.shrink); + self.shrink += 1; + true + } + } + + fn complicate(&mut self) -> bool { + if let Some(bit) = self.prev_shrink.take() { + self.inner.set(bit); + true + } else { + false + } + } +} + +macro_rules! int_api { + ($typ:ident, $max:expr) => { + #[allow(missing_docs)] + pub mod $typ { + use super::*; + + /// Generates integers where all bits may be set. + pub const ANY: BitSetStrategy<$typ> = BitSetStrategy { + min: 0, + max: $max, + mask: None, + }; + + /// Generates values where bits between the given bounds may be + /// set. + pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> { + BitSetStrategy::new(min, max) + } + + /// Generates values where any bits set in `mask` (and no others) + /// may be set. + pub fn masked(mask: $typ) -> BitSetStrategy<$typ> { + BitSetStrategy::masked(mask) + } + + /// Create a strategy which generates values where bits within the + /// bounds given by `bits` may be set. The number of bits that are + /// set is chosen to be in the range given by `size`. + /// + /// ## Panics + /// + /// Panics if `size` includes a value that is greater than the + /// number of bits in `bits`. + pub fn sampled(size: impl Into, bits: impl Into) + -> SampledBitSetStrategy<$typ> { + SampledBitSetStrategy::new(size, bits) + } + } + } +} + +int_api!(u8, 8); +int_api!(u16, 16); +int_api!(u32, 32); +int_api!(u64, 64); +int_api!(i8, 8); +int_api!(i16, 16); +int_api!(i32, 32); +int_api!(i64, 64); + +macro_rules! minimal_api { + ($md:ident, $typ:ty) => { + #[allow(missing_docs)] + pub mod $md { + use super::*; + + /// Generates values where bits between the given bounds may be + /// set. + pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> { + BitSetStrategy::new(min, max) + } + + /// Generates values where any bits set in `mask` (and no others) + /// may be set. + pub fn masked(mask: $typ) -> BitSetStrategy<$typ> { + BitSetStrategy::masked(mask) + } + + /// Create a strategy which generates values where bits within the + /// bounds given by `bits` may be set. The number of bits that are + /// set is chosen to be in the range given by `size`. + /// + /// ## Panics + /// + /// Panics if `size` includes a value that is greater than the + /// number of bits in `bits`. + pub fn sampled(size: impl Into, bits: impl Into) + -> SampledBitSetStrategy<$typ> { + SampledBitSetStrategy::new(size, bits) + } + } + } +} +minimal_api!(usize, usize); +minimal_api!(isize, isize); +#[cfg(feature = "bit-set")] +minimal_api!(bitset, BitSet); +minimal_api!(bool_vec, Vec); + +pub(crate) mod varsize { + use super::*; + use core::iter::FromIterator; + + #[cfg(feature = "bit-set")] + type Inner = BitSet; + #[cfg(not(feature = "bit-set"))] + type Inner = Vec; + + #[derive(Debug, Clone)] + pub(crate) struct VarBitSet(Inner); + + impl VarBitSet { + pub(crate) fn saturated(len: usize) -> Self { + (0..len).collect::() + } + + #[cfg(not(feature = "bit-set"))] + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + (0..self.len()).into_iter().filter(move |&ix| self.test(ix)) + } + + + #[cfg(feature = "bit-set")] + pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { + self.0.iter() + } + } + + impl BitSetLike for VarBitSet { + fn new_bitset(max: usize) -> Self { + VarBitSet(Inner::new_bitset(max)) + } + + fn len(&self) -> usize { + BitSetLike::len(&self.0) + } + + fn test(&self, bit: usize) -> bool { + BitSetLike::test(&self.0, bit) + } + + fn set(&mut self, bit: usize) { + BitSetLike::set(&mut self.0, bit); + } + + fn clear(&mut self, bit: usize) { + BitSetLike::clear(&mut self.0, bit); + } + + fn count(&self) -> usize { + BitSetLike::count(&self.0) + } + } + + impl FromIterator for VarBitSet { + fn from_iter>(iter: T) -> Self { + let mut bits = VarBitSet::new_bitset(0); + for bit in iter { + bits.set(bit); + } + bits + } + } + + /* + pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy { + BitSetStrategy::new(min, max) + } + + pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy { + BitSetStrategy::masked(mask) + } + */ + + pub(crate) fn sampled(size: impl Into, bits: impl Into) + -> SampledBitSetStrategy { + SampledBitSetStrategy::new(size, bits) + } +} + +pub(crate) use self::varsize::VarBitSet; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn generates_values_in_range() { + let input = u32::between(4, 8); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let value = input.new_tree(&mut runner).unwrap().current(); + assert!(0 == value & !0xF0u32, + "Generate value {}", value); + } + } + + #[test] + fn generates_values_in_mask() { + let mut accum = 0; + + let mut runner = TestRunner::default(); + let input = u32::masked(0xdeadbeef); + for _ in 0..1024 { + accum |= input.new_tree(&mut runner).unwrap().current(); + } + + assert_eq!(0xdeadbeef, accum); + } + + #[cfg(feature = "bit-set")] + #[test] + fn mask_bounds_for_bitset_correct() { + let mut seen_0 = false; + let mut seen_2 = false; + + let mut mask = BitSet::new(); + mask.insert(0); + mask.insert(2); + + let mut runner = TestRunner::default(); + let input = bitset::masked(mask); + for _ in 0..32 { + let v = input.new_tree(&mut runner).unwrap().current(); + seen_0 |= v.contains(0); + seen_2 |= v.contains(2); + } + + assert!(seen_0); + assert!(seen_2); + } + + #[test] + fn mask_bounds_for_vecbool_correct() { + let mut seen_0 = false; + let mut seen_2 = false; + + let mask = vec![true, false, true, false]; + + let mut runner = TestRunner::default(); + let input = bool_vec::masked(mask); + for _ in 0..32 { + let v = input.new_tree(&mut runner).unwrap().current(); + assert_eq!(4, v.len()); + seen_0 |= v[0]; + seen_2 |= v[2]; + } + + assert!(seen_0); + assert!(seen_2); + } + + #[test] + fn shrinks_to_zero() { + let input = u32::between(4, 24); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let mut value = input.new_tree(&mut runner).unwrap(); + let mut prev = value.current(); + while value.simplify() { + let v = value.current(); + assert!(1 == (prev & !v).count_ones(), + "Shrank from {} to {}", prev, v); + prev = v; + } + + assert_eq!(0, value.current()); + } + } + + #[test] + fn complicates_to_previous() { + let input = u32::between(4, 24); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let mut value = input.new_tree(&mut runner).unwrap(); + let orig = value.current(); + if value.simplify() { + assert!(value.complicate()); + assert_eq!(orig, value.current()); + } + } + } + + #[test] + fn sampled_selects_correct_sizes_and_bits() { + let input = u32::sampled(4..8, 10..20); + let mut seen_counts = [0; 32]; + let mut seen_bits = [0; 32]; + + let mut runner = TestRunner::default(); + for _ in 0..2048 { + let value = input.new_tree(&mut runner).unwrap().current(); + let count = value.count_ones() as usize; + assert!(count >= 4 && count < 8); + seen_counts[count] += 1; + + for bit in 0..32 { + if 0 != value & (1 << bit) { + assert!(bit >= 10 && bit < 20); + seen_bits[bit] += value; + } + } + } + + for i in 4..8 { + assert!(seen_counts[i] >= 256 && seen_counts[i] < 1024); + } + + let least_seen_bit_count = + seen_bits[10..20].iter().cloned().min().unwrap(); + let most_seen_bit_count = + seen_bits[10..20].iter().cloned().max().unwrap(); + assert_eq!(1, most_seen_bit_count / least_seen_bit_count); + } + + #[test] + fn sampled_doesnt_shrink_below_min_size() { + let input = u32::sampled(4..8, 10..20); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let mut value = input.new_tree(&mut runner).unwrap(); + while value.simplify() { } + + assert_eq!(4, value.current().count_ones()); + } + } + + #[test] + fn test_sanity() { + check_strategy_sanity(u32::masked(0xdeadbeef), None); + } +} diff --git a/proptest/src/bool.rs b/proptest/src/bool.rs new file mode 100644 index 000000000..bb8dab2f4 --- /dev/null +++ b/proptest/src/bool.rs @@ -0,0 +1,136 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `bool` values. + +use strategy::*; +use test_runner::*; + +use rand::Rng; + +/// The type of the `ANY` constant. +#[derive(Clone, Copy, Debug)] +pub struct Any(()); + +/// Generates boolean values by picking `true` or `false` uniformly. +/// +/// Shrinks `true` to `false`. +pub const ANY: Any = Any(()); + +impl Strategy for Any { + type Tree = BoolValueTree; + type Value = bool; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BoolValueTree::new(runner.rng().gen())) + } +} + +/// Generates boolean values by picking `true` with the given `probability` +/// (1.0 = always true, 0.0 = always false). +/// +/// Shrinks `true` to `false`. +pub fn weighted(probability: f64) -> Weighted { + Weighted(probability) +} + +/// The return type from `weighted()`. +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Copy, Debug)] +pub struct Weighted(f64); + +impl Strategy for Weighted { + type Tree = BoolValueTree; + type Value = bool; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BoolValueTree::new(runner.rng().gen_bool(self.0))) + } +} + +/// The `ValueTree` to shrink booleans to false. +#[derive(Clone, Copy, Debug)] +pub struct BoolValueTree { + current: bool, + state: ShrinkState, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +enum ShrinkState { + Untouched, Simplified, Final +} + +impl BoolValueTree { + fn new(current: bool) -> Self { + BoolValueTree { current, state: ShrinkState::Untouched } + } +} + +impl ValueTree for BoolValueTree { + type Value = bool; + + fn current(&self) -> bool { self.current } + fn simplify(&mut self) -> bool { + match self.state { + ShrinkState::Untouched if self.current => { + self.current = false; + self.state = ShrinkState::Simplified; + true + }, + + ShrinkState::Untouched | ShrinkState::Simplified | + ShrinkState::Final => { + self.state = ShrinkState::Final; + false + }, + } + } + fn complicate(&mut self) -> bool { + match self.state { + ShrinkState::Untouched | ShrinkState::Final => { + self.state = ShrinkState::Final; + false + }, + + ShrinkState::Simplified => { + self.current = true; + self.state = ShrinkState::Final; + true + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_sanity() { + check_strategy_sanity(ANY, None); + } + + #[test] + fn shrinks_properly() { + let mut tree = BoolValueTree::new(true); + assert!(tree.simplify()); + assert!(!tree.current()); + assert!(!tree.clone().simplify()); + assert!(tree.complicate()); + assert!(!tree.clone().complicate()); + assert!(tree.current()); + assert!(!tree.simplify()); + assert!(tree.current()); + + tree = BoolValueTree::new(false); + assert!(!tree.clone().simplify()); + assert!(!tree.clone().complicate()); + assert!(!tree.current()); + } +} diff --git a/proptest/src/char.rs b/proptest/src/char.rs new file mode 100644 index 000000000..3b9ea874b --- /dev/null +++ b/proptest/src/char.rs @@ -0,0 +1,381 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `char` values. +//! +//! Unlike most strategies in Proptest, character generation is by default +//! biased to particular values known to be difficult to handle in various +//! circumstances. +//! +//! The main things of interest are `any()` to generate truly arbitrary +//! characters, and `range()` and `ranges()` to select characters from +//! inclusive ranges. + +use core::ops::RangeInclusive; +use std_facade::Cow; + +use rand::Rng; + +use num; +use strategy::*; +use test_runner::*; + +/// An inclusive char range from fst to snd. +type CharRange = RangeInclusive; + +/// A default set of characters to consider as "special" during character +/// generation. +/// +/// Most of the characters here were chosen specifically because they are +/// difficult to handle in particular contexts. +pub const DEFAULT_SPECIAL_CHARS: &[char] = &[ + // Things to give shell scripts and filesystem logic difficulties + '/', '\\', '$', '.', '*', '{', '\'', '"', '`', ':', + // Characters with special significance in URLs and elsewhere + '?', '%', '=', '&', '<', + // Interesting ASCII control characters + // NUL, HT, CR, LF, VT ESC DEL + '\x00', '\t', '\r', '\n', '\x0B', '\x1B', '\x7F', + // ¥ both to test simple Unicode handling and because it has interesting + // properties on MS Shift-JIS systems. + '¥', + // No non-Unicode encoding has both ¥ and Ѩ + 'Ѩ', + // More Unicode edge-cases: BOM, replacement character, and non-BMP + '\u{FEFF}', '\u{FFFD}', '🕴', +]; + +/// A default sequence of ranges used preferentially when generating random +/// characters. +pub const DEFAULT_PREFERRED_RANGES: &[CharRange] = &[ + // ASCII printable + ' '..='~', ' '..='~', ' '..='~', ' '..='~', ' '..='~', + // Latin-1 + '\u{0040}'..='\u{00ff}', +]; + +/// Selects a random character the way `CharStrategy` does. +/// +/// If `special` is non-empty, there is a 50% chance that a character from this +/// array is chosen randomly, and will be returned if that character falls +/// within `ranges`. +/// +/// If `preferred` is non-empty, there is a 50% chance that any generation +/// which gets past the `special` step picks a random element from this list, +/// then a random character from within that range (both endpoints inclusive). +/// That character will be returned if it falls within `ranges`. +/// +/// In all other cases, an element is picked randomly from `ranges` and a +/// random character within the range (both endpoints inclusive) is chosen and +/// returned. +/// +/// Notice that in all cases, `ranges` completely defines the set of characters +/// that can possibly be defined. +/// +/// It is legal for ranges in all cases to contain non-characters. +/// +/// Both `preferred` and `ranges` bias selection towards characters in smaller +/// ranges. This is deliberate. `preferred` is usually tuned to select +/// particular characters anyway. `ranges` is usually derived from some +/// external property, and the fact that a range is small often means it is +/// more interesting. +pub fn select_char(rnd: &mut impl Rng, + special: &[char], + preferred: &[CharRange], + ranges: &[CharRange]) -> char { + let (base, offset) = select_range_index(rnd, special, preferred, ranges); + ::core::char::from_u32(base + offset).expect("bad character selected") +} + +fn select_range_index(rnd: &mut impl Rng, + special: &[char], + preferred: &[CharRange], + ranges: &[CharRange]) + -> (u32, u32) { + fn in_range(ranges: &[CharRange], ch: char) -> Option<(u32, u32)> { + ranges.iter().find(|r| ch >= *r.start() && ch <= *r.end()).map( + |r| (*r.start() as u32, ch as u32 - *r.start() as u32)) + } + + if !special.is_empty() && rnd.gen() { + let s = special[rnd.gen_range(0, special.len())]; + if let Some(ret) = in_range(ranges, s) { return ret; } + } + + if !preferred.is_empty() && rnd.gen() { + let range = preferred[rnd.gen_range(0, preferred.len())].clone(); + if let Some(ch) = ::core::char::from_u32( + rnd.gen_range(*range.start() as u32, *range.end() as u32 + 1)) + { + if let Some(ret) = in_range(ranges, ch) { return ret; } + } + } + + for _ in 0..65_536 { + let range = ranges[rnd.gen_range(0, ranges.len())].clone(); + if let Some(ch) = ::core::char::from_u32( + rnd.gen_range(*range.start() as u32, *range.end() as u32 + 1)) + { return (*range.start() as u32, ch as u32 - *range.start() as u32); } + } + + // Give up and return a character we at least know is valid. + (*ranges[0].start() as u32, 0) +} + +/// Strategy for generating `char`s. +/// +/// Character selection is more sophisticated than integer selection. Naïve +/// selection (particularly in the larger context of generating strings) would +/// result in starting inputs like `ꂡ螧轎ቶᢹ糦狥芹ᘆ㶏曊ᒀ踔虙ჲ` and "simplified" +/// inputs consisting mostly of control characters. It also has difficulty +/// locating edge cases, since the vast majority of code points (such as the +/// enormous CJK regions) don't cause problems for anything with even basic +/// Unicode support. +/// +/// Instead, character selection is always based on explicit ranges, and is +/// designed to bias to specifically chosen characters and character ranges to +/// produce inputs that are both more useful and easier for humans to +/// understand. There are also hard-wired simplification targets based on ASCII +/// instead of simply simplifying towards NUL to avoid problematic inputs being +/// reduced to a bunch of NUL characters. +/// +/// Shrinking never crosses ranges. If you have a complex range like `[A-Za-z]` +/// and the starting point `x` is chosen, it will not shrink to the first `A-Z` +/// group, but rather simply to `a`. +/// +/// The usual way to get instances of this class is with the module-level `ANY` +/// constant or `range` function. Directly constructing a `CharStrategy` is +/// only necessary for complex ranges or to override the default biases. +#[derive(Debug, Clone)] +#[must_use = "strategies do nothing unless used"] +pub struct CharStrategy<'a> { + special: Cow<'a, [char]>, + preferred: Cow<'a, [CharRange]>, + ranges: Cow<'a, [CharRange]>, +} + +impl<'a> CharStrategy<'a> { + /// Construct a new `CharStrategy` with the parameters it will pass to the + /// function underlying `select_char()`. + /// + /// All arguments as per `select_char()`. + pub fn new(special: Cow<'a, [char]>, + preferred: Cow<'a, [CharRange]>, + ranges: Cow<'a, [CharRange]>) -> Self { + CharStrategy { special, preferred, ranges } + } + + /// Same as `CharStrategy::new()` but using `Cow::Borrowed` for all parts. + pub fn new_borrowed(special: &'a [char], + preferred: &'a [CharRange], + ranges: &'a [CharRange]) -> Self { + CharStrategy::new( + Cow::Borrowed(special), + Cow::Borrowed(preferred), + Cow::Borrowed(ranges), + ) + } +} + +const WHOLE_RANGE: &[CharRange] = &[ + '\x00' ..= ::core::char::MAX +]; + +/// Creates a `CharStrategy` which picks from literally any character, with the +/// default biases. +pub fn any() -> CharStrategy<'static> { + CharStrategy { + special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), + preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), + ranges: Cow::Borrowed(WHOLE_RANGE), + } +} + +/// Creates a `CharStrategy` which selects characters within the given +/// endpoints, inclusive, using the default biases. +pub fn range(start: char, end: char) -> CharStrategy<'static> { + CharStrategy { + special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), + preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), + ranges: Cow::Owned(vec![start..=end]), + } +} + +/// Creates a `CharStrategy` which selects characters within the given ranges, +/// all inclusive, using the default biases. +pub fn ranges(ranges: Cow<[CharRange]>) -> CharStrategy { + CharStrategy { + special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), + preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), + ranges, + } +} + +/// The `ValueTree` corresponding to `CharStrategy`. +#[derive(Debug, Clone, Copy)] +pub struct CharValueTree { + value: num::u32::BinarySearch, +} + +impl<'a> Strategy for CharStrategy<'a> { + type Tree = CharValueTree; + type Value = char; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let (base, offset) = select_range_index( + runner.rng(), &self.special, &self.preferred, &self.ranges); + + // Select a minimum point more convenient than 0 + let start = base + offset; + let bottom = if start >= '¡' as u32 && base < '¡' as u32 { + '¡' as u32 + } else if start >= 'a' as u32 && base < 'a' as u32 { + 'a' as u32 + } else if start >= 'A' as u32 && base < 'A' as u32 { + 'A' as u32 + } else if start >= '0' as u32 && base < '0' as u32 { + '0' as u32 + } else if start >= ' ' as u32 && base < ' ' as u32 { + ' ' as u32 + } else { + base + }; + + Ok(CharValueTree { + value: num::u32::BinarySearch::new_above(bottom, start) + }) + } +} + +impl CharValueTree { + fn reposition(&mut self) { + while ::core::char::from_u32(self.value.current()).is_none() { + if !self.value.complicate() { + panic!("Converged to non-char value"); + } + } + } +} + +impl ValueTree for CharValueTree { + type Value = char; + + fn current(&self) -> char { + ::core::char::from_u32(self.value.current()).expect( + "Generated non-char value") + } + + fn simplify(&mut self) -> bool { + if self.value.simplify() { + self.reposition(); + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.value.complicate() { + self.reposition(); + true + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use std::cmp::{min, max}; + use std::vec::Vec; + + use super::*; + use collection; + + #[test] + fn stays_in_range() { + let meta_input = collection::vec( + (0..::std::char::MAX as u32, + 0..::std::char::MAX as u32), + 1..5); + TestRunner::default().run( + &meta_input, |input_ranges| { + let input = ranges(Cow::Owned(input_ranges.iter().map( + |&(lo, hi)| ::std::char::from_u32(lo).and_then( + |lo| ::std::char::from_u32(hi).map( + |hi| min(lo, hi) ..= max(lo, hi))) + .ok_or_else(|| TestCaseError::reject("non-char"))) + .collect::,_>>()?)); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let mut value = input.new_tree(&mut runner).unwrap(); + loop { + let ch = value.current() as u32; + assert!(input_ranges.iter().any( + |&(lo, hi)| ch >= min(lo, hi) && + ch <= max(lo, hi))); + + if !value.simplify() { break; } + } + } + + Ok(()) + }).unwrap() + } + + #[test] + fn applies_desired_bias() { + let mut men_in_business_suits_levitating = 0; + let mut ascii_printable = 0; + let mut runner = TestRunner::default(); + + for _ in 0..1024 { + let ch = any().new_tree(&mut runner).unwrap().current(); + if '🕴' == ch { + men_in_business_suits_levitating += 1; + } else if ch >= ' ' && ch <= '~' { + ascii_printable += 1; + } + } + + assert!(ascii_printable >= 256); + assert!(men_in_business_suits_levitating >= 1); + } + + #[test] + fn doesnt_shrink_to_ascii_control() { + let mut accepted = 0; + let mut runner = TestRunner::default(); + + for _ in 0..256 { + let mut value = any().new_tree(&mut runner).unwrap(); + + if value.current() <= ' ' { continue; } + + while value.simplify() { } + + assert!(value.current() >= ' '); + accepted += 1; + } + + assert!(accepted >= 200); + } + + #[test] + fn test_sanity() { + check_strategy_sanity(any(), Some(CheckStrategySanityOptions { + // `simplify()` can itself `complicate()` back to the starting + // position, so the overly strict complicate-after-simplify check + // must be disabled. + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } +} diff --git a/proptest/src/collection.rs b/proptest/src/collection.rs new file mode 100644 index 000000000..56cb6bc1e --- /dev/null +++ b/proptest/src/collection.rs @@ -0,0 +1,731 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `std::collections` of values. + +use core::cmp::Ord; +use core::hash::Hash; +use core::ops::{Add, Range, RangeTo, RangeInclusive, RangeToInclusive}; +use core::usize; + +use std_facade::{fmt, Vec, VecDeque, BinaryHeap, BTreeMap, BTreeSet, LinkedList}; + +#[cfg(feature = "std")] +use std_facade::{HashMap, HashSet}; + +use bits::{BitSetLike, VarBitSet}; +use num::sample_uniform_incl; +use strategy::*; +use tuple::TupleValueTree; +use test_runner::*; + +//============================================================================== +// SizeRange +//============================================================================== + +/// The minimum and maximum range/bounds on the size of a collection. +/// The interval must form a subset of `[0, std::usize::MAX)`. +/// +/// A value like `0..=std::usize::MAX` will still be accepted but will silently +/// truncate the maximum to `std::usize::MAX - 1`. +/// +/// The `Default` is `0..100`. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct SizeRange(Range); + +/// Creates a `SizeRange` from some value that is convertible into it. +pub fn size_range(from: impl Into) -> SizeRange { + from.into() +} + +impl Default for SizeRange { + /// Constructs a `SizeRange` equivalent to `size_range(0..100)`. + fn default() -> Self { + size_range(0..100) + } +} + +impl SizeRange { + /// Creates a `SizeBounds` from a `RangeInclusive`. + pub fn new(range: RangeInclusive) -> Self { + range.into() + } + + // Don't rely on these existing internally: + + /// Merges self together with some other argument producing a product + /// type expected by some impelementations of `A: Arbitrary` in + /// `A::Parameters`. This can be more ergonomic to work with and may + /// help type inference. + pub fn with(self, and: X) -> product_type![Self, X] { + product_pack![self, and] + } + + /// Merges self together with some other argument generated with a + /// default value producing a product type expected by some + /// impelementations of `A: Arbitrary` in `A::Parameters`. + /// This can be more ergonomic to work with and may help type inference. + pub fn lift(self) -> product_type![Self, X] { + self.with(Default::default()) + } + + pub(crate) fn start(&self) -> usize { + self.0.start + } + + /// Extract the ends `[low, high]` of a `SizeRange`. + pub(crate) fn start_end_incl(&self) -> (usize, usize) { + (self.start(), self.end_incl()) + } + + pub(crate) fn end_incl(&self) -> usize { + self.0.end - 1 + } + + pub(crate) fn end_excl(&self) -> usize { + self.0.end + } + + pub(crate) fn iter(&self) -> impl Iterator { + self.0.clone().into_iter() + } + + pub(crate) fn is_empty(&self) -> bool { + self.start() == self.end_excl() + } + + pub(crate) fn assert_nonempty(&self) { + if self.is_empty() { + panic!("Invalid use of empty size range. (hint: did you \ + accidentally write {}..{} where you meant {}..={} \ + somewhere?)", self.start(), self.end_excl(), + self.start(), self.end_excl()); + } + } +} + +/// Given `(low: usize, high: usize)`, +/// then a size range of `[low..high)` is the result. +impl From<(usize, usize)> for SizeRange { + fn from((low, high): (usize, usize)) -> Self { size_range(low..high) } +} + +/// Given `exact`, then a size range of `[exact, exact]` is the result. +impl From for SizeRange { + fn from(exact: usize) -> Self { size_range(exact..=exact) } +} + +/// Given `..high`, then a size range `[0, high)` is the result. +impl From> for SizeRange { + fn from(high: RangeTo) -> Self { size_range(0..high.end) } +} + +/// Given `low .. high`, then a size range `[low, high)` is the result. +impl From> for SizeRange { + fn from(r: Range) -> Self { SizeRange(r) } +} + +/// Given `low ..= high`, then a size range `[low, high]` is the result. +impl From> for SizeRange { + fn from(r: RangeInclusive) -> Self { + size_range(*r.start()..r.end().saturating_add(1)) + } +} + +/// Given `..=high`, then a size range `[0, high]` is the result. +impl From> for SizeRange { + fn from(high: RangeToInclusive) -> Self { size_range(0..=high.end) } +} + +impl From for Range { + fn from(sr: SizeRange) -> Self { + sr.start()..sr.end_excl() + } +} + +/// Given a size range `[low, high]`, then a range `low..=high` is returned. +impl From for RangeInclusive { + fn from(sr: SizeRange) -> Self { sr.start()..=sr.end_incl() } +} + +#[cfg(feature = "frunk")] +impl Generic for SizeRange { + type Repr = RangeInclusive; + + /// Converts the `SizeRange` into `Range`. + fn into(self) -> Self::Repr { self.0 } + + /// Converts `RangeInclusive` into `SizeRange`. + fn from(r: Self::Repr) -> Self { r.into() } +} + +/// Adds `usize` to both start and end of the bounds. +/// +/// Panics if adding to either end overflows `usize`. +impl Add for SizeRange { + type Output = SizeRange; + + fn add(self, rhs: usize) -> Self::Output { + let (start, end) = self.start_end_incl(); + size_range((start + rhs)..=(end + rhs)) + } +} + +//============================================================================== +// Strategies +//============================================================================== + +/// Strategy to create `Vec`s with a length in a certain range. +/// +/// Created by the `vec()` function in the same module. +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Debug)] +pub struct VecStrategy { + element: T, + size: SizeRange, +} + +/// Create a strategy to generate `Vec`s containing elements drawn from +/// `element` and with a size range given by `size`. +/// +/// To make a `Vec` with a fixed number of elements, each with its own +/// strategy, you can instead make a `Vec` of strategies (boxed if necessary). +pub fn vec(element: T, size: impl Into) + -> VecStrategy { + let size = size.into(); + size.assert_nonempty(); + VecStrategy { element, size } +} + +mapfn! { + [] fn VecToDeque[](vec: Vec) -> VecDeque { + vec.into() + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `VecDeque`s with a length in a certain range. + /// + /// Created by the `vec_deque()` function in the same module. + #[derive(Clone, Debug)] + pub struct VecDequeStrategy[][where T : Strategy]( + statics::Map, VecToDeque>) + -> VecDequeValueTree; + /// `ValueTree` corresponding to `VecDequeStrategy`. + #[derive(Clone, Debug)] + pub struct VecDequeValueTree[][where T : ValueTree]( + statics::Map, VecToDeque>) + -> VecDeque; +} + +/// Create a strategy to generate `VecDeque`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn vec_deque(element: T, size: impl Into) + -> VecDequeStrategy +{ + VecDequeStrategy(statics::Map::new(vec(element, size), VecToDeque)) +} + +mapfn! { + [] fn VecToLl[](vec: Vec) -> LinkedList { + vec.into_iter().collect() + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `LinkedList`s with a length in a certain range. + /// + /// Created by the `linkedlist()` function in the same module. + #[derive(Clone, Debug)] + pub struct LinkedListStrategy[][where T : Strategy]( + statics::Map, VecToLl>) + -> LinkedListValueTree; + /// `ValueTree` corresponding to `LinkedListStrategy`. + #[derive(Clone, Debug)] + pub struct LinkedListValueTree[][where T : ValueTree]( + statics::Map, VecToLl>) + -> LinkedList; +} + +/// Create a strategy to generate `LinkedList`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn linked_list(element: T, size: impl Into) + -> LinkedListStrategy +{ + LinkedListStrategy(statics::Map::new(vec(element, size), VecToLl)) +} + +mapfn! { + [] fn VecToBinHeap[](vec: Vec) -> BinaryHeap { + vec.into() + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `BinaryHeap`s with a length in a certain range. + /// + /// Created by the `binary_heap()` function in the same module. + #[derive(Clone, Debug)] + pub struct BinaryHeapStrategy[][where T : Strategy, T::Value : Ord]( + statics::Map, VecToBinHeap>) + -> BinaryHeapValueTree; + /// `ValueTree` corresponding to `BinaryHeapStrategy`. + #[derive(Clone, Debug)] + pub struct BinaryHeapValueTree[][where T : ValueTree, T::Value : Ord]( + statics::Map, VecToBinHeap>) + -> BinaryHeap; +} + +/// Create a strategy to generate `BinaryHeap`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn binary_heap(element: T, size: impl Into) + -> BinaryHeapStrategy +where T::Value : Ord { + BinaryHeapStrategy(statics::Map::new(vec(element, size), VecToBinHeap)) +} + +mapfn! { + {#[cfg(feature = "std")]} + [] fn VecToHashSet[](vec: Vec) + -> HashSet { + vec.into_iter().collect() + } +} + +#[derive(Debug, Clone, Copy)] +struct MinSize(usize); + +#[cfg(feature = "std")] +impl statics::FilterFn> for MinSize { + fn apply(&self, set: &HashSet) -> bool { + set.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + {#[cfg(feature = "std")]} + /// Strategy to create `HashSet`s with a length in a certain range. + /// + /// Created by the `hash_set()` function in the same module. + #[derive(Clone, Debug)] + pub struct HashSetStrategy[][where T : Strategy, T::Value : Hash + Eq]( + statics::Filter, VecToHashSet>, MinSize>) + -> HashSetValueTree; + /// `ValueTree` corresponding to `HashSetStrategy`. + #[derive(Clone, Debug)] + pub struct HashSetValueTree[][where T : ValueTree, T::Value : Hash + Eq]( + statics::Filter, VecToHashSet>, MinSize>) + -> HashSet; +} + +/// Create a strategy to generate `HashSet`s containing elements drawn from +/// `element` and with a size range given by `size`. +/// +/// This strategy will implicitly do local rejects to ensure that the `HashSet` +/// has at least the minimum number of elements, in case `element` should +/// produce duplicate values. +#[cfg(feature = "std")] +pub fn hash_set(element: T, size: impl Into) + -> HashSetStrategy +where T::Value : Hash + Eq { + let size = size.into(); + HashSetStrategy(statics::Filter::new( + statics::Map::new(vec(element, size.clone()), VecToHashSet), + "HashSet minimum size".into(), + MinSize(size.start()))) +} + +mapfn! { + [] fn VecToBTreeSet[](vec: Vec) + -> BTreeSet { + vec.into_iter().collect() + } +} + +impl statics::FilterFn> for MinSize { + fn apply(&self, set: &BTreeSet) -> bool { + set.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `BTreeSet`s with a length in a certain range. + /// + /// Created by the `btree_set()` function in the same module. + #[derive(Clone, Debug)] + pub struct BTreeSetStrategy[][where T : Strategy, T::Value : Ord]( + statics::Filter, VecToBTreeSet>, MinSize>) + -> BTreeSetValueTree; + /// `ValueTree` corresponding to `BTreeSetStrategy`. + #[derive(Clone, Debug)] + pub struct BTreeSetValueTree[][where T : ValueTree, T::Value : Ord]( + statics::Filter, VecToBTreeSet>, MinSize>) + -> BTreeSet; +} + +/// Create a strategy to generate `BTreeSet`s containing elements drawn from +/// `element` and with a size range given by `size`. +/// +/// This strategy will implicitly do local rejects to ensure that the +/// `BTreeSet` has at least the minimum number of elements, in case `element` +/// should produce duplicate values. +pub fn btree_set(element: T, size: impl Into) + -> BTreeSetStrategy +where T::Value : Ord { + let size = size.into(); + BTreeSetStrategy(statics::Filter::new( + statics::Map::new(vec(element, size.clone()), VecToBTreeSet), + "BTreeSet minimum size".into(), + MinSize(size.start()))) +} + +mapfn! { + {#[cfg(feature = "std")]} + [] fn VecToHashMap[] + (vec: Vec<(K, V)>) -> HashMap + { + vec.into_iter().collect() + } +} + +#[cfg(feature = "std")] +impl statics::FilterFn> for MinSize { + fn apply(&self, map: &HashMap) -> bool { + map.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + {#[cfg(feature = "std")]} + /// Strategy to create `HashMap`s with a length in a certain range. + /// + /// Created by the `hash_map()` function in the same module. + #[derive(Clone, Debug)] + pub struct HashMapStrategy[] + [where K : Strategy, V : Strategy, K::Value : Hash + Eq]( + statics::Filter, + VecToHashMap>, MinSize>) + -> HashMapValueTree; + /// `ValueTree` corresponding to `HashMapStrategy`. + #[derive(Clone, Debug)] + pub struct HashMapValueTree[] + [where K : ValueTree, V : ValueTree, K::Value : Hash + Eq]( + statics::Filter>, + VecToHashMap>, MinSize>) + -> HashMap; +} + +/// Create a strategy to generate `HashMap`s containing keys and values drawn +/// from `key` and `value` respectively, and with a size within the given +/// range. +/// +/// This strategy will implicitly do local rejects to ensure that the `HashMap` +/// has at least the minimum number of elements, in case `key` should produce +/// duplicate values. +#[cfg(feature = "std")] +pub fn hash_map + (key: K, value: V, size: impl Into) -> HashMapStrategy +where K::Value : Hash + Eq { + let size = size.into(); + HashMapStrategy(statics::Filter::new( + statics::Map::new(vec((key, value), size.clone()), VecToHashMap), + "HashMap minimum size".into(), + MinSize(size.start()))) +} + +mapfn! { + [] fn VecToBTreeMap[] + (vec: Vec<(K, V)>) -> BTreeMap + { + vec.into_iter().collect() + } +} + +impl statics::FilterFn> for MinSize { + fn apply(&self, map: &BTreeMap) -> bool { + map.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `BTreeMap`s with a length in a certain range. + /// + /// Created by the `btree_map()` function in the same module. + #[derive(Clone, Debug)] + pub struct BTreeMapStrategy[] + [where K : Strategy, V : Strategy, K::Value : Ord]( + statics::Filter, + VecToBTreeMap>, MinSize>) + -> BTreeMapValueTree; + /// `ValueTree` corresponding to `BTreeMapStrategy`. + #[derive(Clone, Debug)] + pub struct BTreeMapValueTree[] + [where K : ValueTree, V : ValueTree, K::Value : Ord]( + statics::Filter>, + VecToBTreeMap>, MinSize>) + -> BTreeMap; +} + +/// Create a strategy to generate `BTreeMap`s containing keys and values drawn +/// from `key` and `value` respectively, and with a size within the given +/// range. +/// +/// This strategy will implicitly do local rejects to ensure that the +/// `BTreeMap` has at least the minimum number of elements, in case `key` +/// should produce duplicate values. +pub fn btree_map + (key: K, value: V, size: impl Into) -> BTreeMapStrategy +where K::Value : Ord { + let size = size.into(); + BTreeMapStrategy(statics::Filter::new( + statics::Map::new(vec((key, value), size.clone()), VecToBTreeMap), + "BTreeMap minimum size".into(), + MinSize(size.start()))) +} + +#[derive(Clone, Copy, Debug)] +enum Shrink { + DeleteElement(usize), + ShrinkElement(usize), +} + +/// `ValueTree` corresponding to `VecStrategy`. +#[derive(Clone, Debug)] +pub struct VecValueTree { + elements: Vec, + included_elements: VarBitSet, + min_size: usize, + shrink: Shrink, + prev_shrink: Option, +} + +impl Strategy for VecStrategy { + type Tree = VecValueTree; + type Value = Vec; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let (start, end) = self.size.start_end_incl(); + let max_size = sample_uniform_incl(runner, start, end); + let mut elements = Vec::with_capacity(max_size); + while elements.len() < max_size { + elements.push(self.element.new_tree(runner)?); + } + + Ok(VecValueTree { + elements, + included_elements: VarBitSet::saturated(max_size), + min_size: start, + shrink: Shrink::DeleteElement(0), + prev_shrink: None, + }) + } +} + +impl Strategy for Vec { + type Tree = VecValueTree; + type Value = Vec; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let len = self.len(); + let elements = self.iter().map( + |t| t.new_tree(runner)).collect::, Reason>>()?; + + Ok(VecValueTree { + elements, + included_elements: VarBitSet::saturated(len), + min_size: len, + shrink: Shrink::ShrinkElement(0), + prev_shrink: None, + }) + } +} + +impl ValueTree for VecValueTree { + type Value = Vec; + + fn current(&self) -> Vec { + self.elements.iter().enumerate() + .filter(|&(ix, _)| self.included_elements.test(ix)) + .map(|(_, element)| element.current()) + .collect() + } + + fn simplify(&mut self) -> bool { + // The overall strategy here is to iteratively delete elements from the + // list until we can do so no further, then to shrink each remaining + // element in sequence. + // + // For `complicate()`, we simply undo the last shrink operation, if + // there was any. + if let Shrink::DeleteElement(ix) = self.shrink { + // Can't delete an element if beyond the end of the vec or if it + // would put us under the minimum length. + if ix >= self.elements.len() || + self.included_elements.count() == self.min_size + { + self.shrink = Shrink::ShrinkElement(0); + } else { + self.included_elements.clear(ix); + self.prev_shrink = Some(self.shrink); + self.shrink = Shrink::DeleteElement(ix + 1); + return true; + } + } + + while let Shrink::ShrinkElement(ix) = self.shrink { + if ix >= self.elements.len() { + // Nothing more we can do + return false; + } + + if !self.included_elements.test(ix) { + // No use shrinking something we're not including. + self.shrink = Shrink::ShrinkElement(ix + 1); + continue; + } + + if !self.elements[ix].simplify() { + // Move on to the next element + self.shrink = Shrink::ShrinkElement(ix + 1); + } else { + self.prev_shrink = Some(self.shrink); + return true; + } + } + + panic!("Unexpected shrink state"); + } + + fn complicate(&mut self) -> bool { + match self.prev_shrink { + None => false, + Some(Shrink::DeleteElement(ix)) => { + // Undo the last item we deleted. Can't complicate any further, + // so unset prev_shrink. + self.included_elements.set(ix); + self.prev_shrink = None; + true + }, + Some(Shrink::ShrinkElement(ix)) => { + if self.elements[ix].complicate() { + // Don't unset prev_shrink; we may be able to complicate + // again. + true + } else { + // Can't complicate the last element any further. + self.prev_shrink = None; + false + } + } + } + } +} + +//============================================================================== +// Tests +//============================================================================== + +#[cfg(test)] +mod test { + use super::*; + + use bits; + + #[test] + fn test_vec() { + let input = vec(1usize..20usize, 5..20); + let mut num_successes = 0; + + for _ in 0..256 { + let mut runner = TestRunner::default(); + let case = input.new_tree(&mut runner).unwrap(); + let start = case.current(); + // Has correct length + assert!(start.len() >= 5 && start.len() < 20); + // Has at least 2 distinct values + assert!(start.iter().map(|&v| v).collect::().len() >= 2); + + let result = runner.run_one(case, |v| { + prop_assert!(v.iter().map(|&v| v).sum::() < 9, + "greater than 8"); + Ok(()) + }); + + match result { + Ok(true) => num_successes += 1, + Err(TestError::Fail(_, value)) => { + // The minimal case always has between 5 (due to min + // length) and 9 (min element value = 1) elements, and + // always sums to exactly 9. + assert!(value.len() >= 5 && value.len() <= 9 && + value.iter().map(|&v| v).sum::() == 9, + "Unexpected minimal value: {:?}", value); + }, + e => panic!("Unexpected result: {:?}", e), + } + } + + assert!(num_successes < 256); + } + + #[test] + fn test_vec_sanity() { + check_strategy_sanity(vec(0i32..1000, 5..10), None); + } + + #[test] + fn test_parallel_vec() { + let input = vec![ + (1u32..10).boxed(), + bits::u32::masked(0xF0u32).boxed(), + ]; + + for _ in 0..256 { + let mut runner = TestRunner::default(); + let mut case = input.new_tree(&mut runner).unwrap(); + + loop { + let current = case.current(); + assert_eq!(2, current.len()); + assert!(current[0] >= 1 && current[0] <= 10); + assert_eq!(0, (current[1] & !0xF0)); + + if !case.simplify() { + break; + } + } + } + } + + #[cfg(feature = "std")] + #[test] + fn test_map() { + // Only 8 possible keys + let input = hash_map("[ab]{3}", "a", 2..3); + let mut runner = TestRunner::default(); + + for _ in 0..256 { + let v = input.new_tree(&mut runner).unwrap().current(); + assert_eq!(2, v.len()); + } + } + + #[cfg(feature = "std")] + #[test] + fn test_set() { + // Only 8 possible values + let input = hash_set("[ab]{3}", 2..3); + let mut runner = TestRunner::default(); + + for _ in 0..256 { + let v = input.new_tree(&mut runner).unwrap().current(); + assert_eq!(2, v.len()); + } + } +} diff --git a/proptest/src/file-preamble b/proptest/src/file-preamble new file mode 100644 index 000000000..13abfcdc0 --- /dev/null +++ b/proptest/src/file-preamble @@ -0,0 +1,8 @@ +//- +// Copyright 2017 +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. diff --git a/proptest/src/lib.rs b/proptest/src/lib.rs new file mode 100644 index 000000000..fb6638ca2 --- /dev/null +++ b/proptest/src/lib.rs @@ -0,0 +1,1756 @@ +//- +// Copyright 2017, 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Proptest is a property testing framework (i.e., the QuickCheck family) +//! inspired by the [Hypothesis](http://hypothesis.works/) framework for +//! Python. It allows to test that certain properties of your code hold for +//! arbitrary inputs, and if a failure is found, automatically finds the +//! minimal test case to reproduce the problem. Unlike QuickCheck, generation +//! and shrinking is defined on a per-value basis instead of per-type, which +//! makes it more flexible and simplifies composition. +//! +//! If you have dependencies which provide QuickCheck `Arbitrary` +//! implementations, see also the related +//! [`proptest-quickcheck-interop`](https://crates.io/crates/proptest-quickcheck-interop) +//! crates which enables reusing those implementations with proptest. +//! +//! +//! +//! ## Introduction +//! +//! _Property testing_ is a system of testing code by checking that certain +//! properties of its output or behaviour are fulfilled for all inputs. These +//! inputs are generated automatically, and, critically, when a failing input +//! is found, the input is automatically reduced to a _minimal_ test case. +//! +//! Property testing is best used to compliment traditional unit testing (i.e., +//! using specific inputs chosen by hand). Traditional tests can test specific +//! known edge cases, simple inputs, and inputs that were known in the past to +//! reveal bugs, whereas property tests will search for more complicated inputs +//! that cause problems. +//! +//! ## Getting Started +//! +//! Let's say we want to make a function that parses dates of the form +//! `YYYY-MM-DD`. We're not going to worry about _validating_ the date, any +//! triple of integers is fine. So let's bang something out real quick. +//! +//! ```rust,no_run +//! fn parse_date(s: &str) -> Option<(u32, u32, u32)> { +//! if 10 != s.len() { return None; } +//! if "-" != &s[4..5] || "-" != &s[7..8] { return None; } +//! +//! let year = &s[0..4]; +//! let month = &s[6..7]; +//! let day = &s[8..10]; +//! +//! year.parse::().ok().and_then( +//! |y| month.parse::().ok().and_then( +//! |m| day.parse::().ok().map( +//! |d| (y, m, d)))) +//! } +//! ``` +//! +//! It compiles, that means it works, right? Maybe not, let's add some tests. +//! +//! ```rust,ignore +//! #[test] +//! fn test_parse_date() { +//! assert_eq!(None, parse_date("2017-06-1")); +//! assert_eq!(None, parse_date("2017-06-170")); +//! assert_eq!(None, parse_date("2017006-17")); +//! assert_eq!(None, parse_date("2017-06017")); +//! assert_eq!(Some((2017, 06, 17)), parse_date("2017-06-17")); +//! } +//! ``` +//! +//! Tests pass, deploy to production! But now your application starts crashing, +//! and people are upset that you moved Christmas to February. Maybe we need to +//! be a bit more thorough. +//! +//! In `Cargo.toml`, add +//! +//! ```toml +//! [dev-dependencies] +//! proptest = "0.8.7" +//! ``` +//! +//! and at the top of `main.rs` or `lib.rs`: +//! +//! ```rust,ignore +//! #[macro_use] extern crate proptest; +//! ``` +//! +//! Now we can add some property tests to our date parser. But how do we test +//! the date parser for arbitrary inputs, without making another date parser in +//! the test to validate it? We won't need to as long as we choose our inputs +//! and properties correctly. But before correctness, there's actually an even +//! simpler property to test: _The function should not crash._ Let's start +//! there. +//! +//! ```rust,ignore +//! proptest! { +//! #[test] +//! fn doesnt_crash(s in "\\PC*") { +//! parse_date(s); +//! } +//! } +//! ``` +//! +//! What this does is take a literally random `&String` (ignore `\\PC*` for the +//! moment, we'll get back to that — if you've already figured it out, contain +//! your excitement for a bit) and give it to `parse_date()` and then throw the +//! output away. +//! +//! When we run this, we get a bunch of scary-looking output, eventually ending +//! with +//! +//! ```text +//! thread 'main' panicked at 'Test failed: byte index 4 is not a char boundary; it is inside 'ௗ' (bytes 2..5) of `aAௗ0㌀0`; minimal failing input: s = "aAௗ0㌀0" +//! successes: 102 +//! local rejects: 0 +//! global rejects: 0 +//! ' +//! ``` +//! +//! If we look at the top directory after the test fails, we'll see a new +//! `proptest-regressions` directory, which contains some files corresponding +//! to source files containing failing test cases. These are [_failure +//! persistence_](#failure-persistence) files. The first thing we should do is +//! add these to source control. +//! +//! ```text +//! $ git add proptest-regressions +//! ``` +//! +//! The next thing we should do is copy the failing case to a traditional unit +//! test since it has exposed a bug not similar to what we've tested in the +//! past. +//! +//! ```rust,ignore +//! #[test] +//! fn test_unicode_gibberish() { +//! assert_eq!(None, parse_date("aAௗ0㌀0")); +//! } +//! ``` +//! +//! Now, let's see what happened... we forgot about UTF-8! You can't just +//! blindly slice strings since you could split a character, in this case that +//! Tamil diacritic placed atop other characters in the string. +//! +//! In the interest of making the code changes as small as possible, we'll just +//! check that the string is ASCII and reject anything that isn't. +//! +//! ```rust,no_run +//! # use std::ascii::AsciiExt; //NOREADME +//! # // NOREADME +//! fn parse_date(s: &str) -> Option<(u32, u32, u32)> { +//! if 10 != s.len() { return None; } +//! +//! // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. +//! if !s.is_ascii() { return None; } +//! +//! if "-" != &s[4..5] || "-" != &s[7..8] { return None; } +//! +//! let year = &s[0..4]; +//! let month = &s[6..7]; +//! let day = &s[8..10]; +//! +//! year.parse::().ok().and_then( +//! |y| month.parse::().ok().and_then( +//! |m| day.parse::().ok().map( +//! |d| (y, m, d)))) +//! } +//! ``` +//! +//! The tests pass now! But we know there are still more problems, so let's +//! test more properties. +//! +//! Another property we want from our code is that it parses every valid date. +//! We can add another test to the `proptest!` section: +//! +//! ```rust,ignore +//! proptest! { +//! // snip... +//! +//! #[test] +//! fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") { +//! parse_date(s).unwrap(); +//! } +//! } +//! ``` +//! +//! The thing to the right-hand side of `in` is actually a *regular +//! expression*, and `s` is chosen from strings which match it. So in our +//! previous test, `"\\PC*"` was generating arbitrary strings composed of +//! arbitrary non-control characters. Now, we generate things in the YYYY-MM-DD +//! format. +//! +//! The new test passes, so let's move on to something else. +//! +//! The final property we want to check is that the dates are actually parsed +//! _correctly_. Now, we can't do this by generating strings — we'd end up just +//! reimplementing the date parser in the test! Instead, we start from the +//! expected output, generate the string, and check that it gets parsed back. +//! +//! ```rust,ignore +//! proptest! { +//! // snip... +//! +//! #[test] +//! fn parses_date_back_to_original(y in 0u32..10000, +//! m in 1u32..13, d in 1u32..32) { +//! let (y2, m2, d2) = parse_date( +//! &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); +//! // prop_assert_eq! is basically the same as assert_eq!, but doesn't +//! // cause a bunch of panic messages to be printed on intermediate +//! // test failures. Which one to use is largely a matter of taste. +//! prop_assert_eq!((y, m, d), (y2, m2, d2)); +//! } +//! } +//! ``` +//! +//! Here, we see that besides regexes, we can use any expression which is a +//! `proptest::strategy::Strategy`, in this case, integer ranges. +//! +//! The test fails when we run it. Though there's not much output this time. +//! +//! ```text +//! thread 'main' panicked at 'Test failed: assertion failed: `(left == right)` (left: `(0, 10, 1)`, right: `(0, 0, 1)`) at examples/dateparser_v2.rs:46; minimal failing input: y = 0, m = 10, d = 1 +//! successes: 2 +//! local rejects: 0 +//! global rejects: 0 +//! ', examples/dateparser_v2.rs:33 +//! note: Run with `RUST_BACKTRACE=1` for a backtrace. +//! ``` +//! +//! The failing input is `(y, m, d) = (0, 10, 1)`, which is a rather specific +//! output. Before thinking about why this breaks the code, let's look at what +//! proptest did to arrive at this value. At the start of our test function, +//! insert +//! +//! ```rust,ignore +//! println!("y = {}, m = {}, d = {}", y, m, d); +//! ``` +//! +//! Running the test again, we get something like this: +//! +//! ```text +//! y = 2497, m = 8, d = 27 +//! y = 9641, m = 8, d = 18 +//! y = 7360, m = 12, d = 20 +//! y = 3680, m = 12, d = 20 +//! y = 1840, m = 12, d = 20 +//! y = 920, m = 12, d = 20 +//! y = 460, m = 12, d = 20 +//! y = 230, m = 12, d = 20 +//! y = 115, m = 12, d = 20 +//! y = 57, m = 12, d = 20 +//! y = 28, m = 12, d = 20 +//! y = 14, m = 12, d = 20 +//! y = 7, m = 12, d = 20 +//! y = 3, m = 12, d = 20 +//! y = 1, m = 12, d = 20 +//! y = 0, m = 12, d = 20 +//! y = 0, m = 6, d = 20 +//! y = 0, m = 9, d = 20 +//! y = 0, m = 11, d = 20 +//! y = 0, m = 10, d = 20 +//! y = 0, m = 10, d = 10 +//! y = 0, m = 10, d = 5 +//! y = 0, m = 10, d = 3 +//! y = 0, m = 10, d = 2 +//! y = 0, m = 10, d = 1 +//! ``` +//! +//! The test failure message said there were two successful cases; we see these +//! at the very top, `2497-08-27` and `9641-08-18`. The next case, +//! `7360-12-20`, failed. There's nothing immediately obviously special about +//! this date. Fortunately, proptest reduced it to a much simpler case. First, +//! it rapidly reduced the `y` input to `0` at the beginning, and similarly +//! reduced the `d` input to the minimum allowable value of `1` at the end. +//! Between those two, though, we see something different: it tried to shrink +//! `12` to `6`, but then ended up raising it back up to `10`. This is because +//! the `0000-06-20` and `0000-09-20` test cases _passed_. +//! +//! In the end, we get the date `0000-10-01`, which apparently gets parsed as +//! `0000-00-01`. Again, this failing case was added to the failure persistence +//! file, and we should add this as its own unit test: +//! +//! ```text +//! $ git add proptest-regressions +//! ``` +//! +//! ```rust,ignore +//! #[test] +//! fn test_october_first() { +//! assert_eq!(Some(0, 10, 1), parse_date("0000-10-01")); +//! } +//! ``` +//! +//! Now to figure out what's broken in the code. Even without the intermediate +//! input, we can say with reasonable confidence that the year and day parts +//! don't come into the picture since both were reduced to the minimum +//! allowable input. The month input was _not_, but was reduced to `10`. This +//! means we can infer that there's something special about `10` that doesn't +//! hold for `9`. In this case, that "special something" is being two digits +//! wide. In our code: +//! +//! ```rust,ignore +//! let month = &s[6..7]; +//! ``` +//! +//! We were off by one, and need to use the range `5..7`. After fixing this, +//! the test passes. +//! +//! The `proptest!` macro has some additional syntax, including for setting +//! configuration for things like the number of test cases to generate. See its +//! [documentation](macro.proptest.html) +//! for more details. +//! +//! There is a more in-depth tutorial +//! [further down](#in-depth-tutorial). +//! +//! ## Differences between QuickCheck and Proptest +//! +//! QuickCheck and Proptest are similar in many ways: both generate random +//! inputs for a function to check certain properties, and automatically shrink +//! inputs to minimal failing cases. +//! +//! The one big difference is that QuickCheck generates and shrinks values +//! based on type alone, whereas Proptest uses explicit `Strategy` objects. The +//! QuickCheck approach has a lot of disadvantages in comparison: +//! +//! - QuickCheck can only define one generator and shrinker per type. If you +//! need a custom generation strategy, you need to wrap it in a newtype and +//! implement traits on that by hand. In Proptest, you can define arbitrarily +//! many different strategies for the same type, and there are plenty built-in. +//! +//! - For the same reason, QuickCheck has a single "size" configuration that +//! tries to define the range of values generated. If you need an integer +//! between 0 and 100 and another between 0 and 1000, you probably need to do +//! another newtype. In Proptest, you can directly just express that you want a +//! `0..100` integer and a `0..1000` integer. +//! +//! - Types in QuickCheck are not easily composable. Defining `Arbitrary` and +//! `Shrink` for a new struct which is simply produced by the composition of +//! its fields requires implementing both by hand, including a bidirectional +//! mapping between the struct and a tuple of its fields. In Proptest, you can +//! make a tuple of the desired components and then `prop_map` it into the +//! desired form. Shrinking happens automatically in terms of the input types. +//! +//! - Because constraints on values cannot be expressed in QuickCheck, +//! generation and shrinking may lead to a lot of input rejections. Strategies +//! in Proptest are aware of simple constraints and do not generate or shrink +//! to values that violate them. +//! +//! The author of Hypothesis also has an [article on this +//! topic](http://hypothesis.works/articles/integrated-shrinking/). +//! +//! Of course, there's also some relative downsides that fall out of what +//! Proptest does differently: +//! +//! - Generating complex values in Proptest can be up to an order of magnitude +//! slower than in QuickCheck. This is because QuickCheck performs stateless +//! shrinking based on the output value, whereas Proptest must hold on to all +//! the intermediate states and relationships in order for its richer shrinking +//! model to work. +//! +//! ## Limitations of Property Testing +//! +//! Given infinite time, property testing will eventually explore the whole +//! input space to a test. However, time is not infinite, so only a randomly +//! sampled portion of the input space can be explored. This means that +//! property testing is extremely unlikely to find single-value edge cases in a +//! large space. For example, the following test will virtually always pass: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! proptest! { +//! # /* NOREADME +//! #[test] +//! # NOREADME */ +//! fn i64_abs_is_never_negative(a: i64) { +//! // This actually fails if a == i64::MIN, but randomly picking one +//! // specific value out of 2⁶⁴ is overwhelmingly unlikely. +//! assert!(a.abs() >= 0); +//! } +//! } +//! # // NOREADME +//! # fn main() { i64_abs_is_never_negative(); } // NOREADME +//! ``` +//! +//! Because of this, traditional unit testing with intelligently selected cases +//! is still necessary for many kinds of problems. +//! +//! Similarly, in some cases it can be hard or impossible to define a strategy +//! which actually produces useful inputs. A strategy of `.{1,4096}` may be +//! great to fuzz a C parser, but is highly unlikely to produce anything that +//! makes it to a code generator. +//! +//! ## Failure Persistence +//! +//! By default, when Proptest finds a failing test case, it _persists_ that +//! failing case in a file named after the source containing the failing test, +//! but in a separate directory tree rooted at `proptest-regressions`† . Later +//! runs of tests will replay those test cases before generating novel cases. +//! This ensures that the test will not fail on one run and then spuriously +//! pass on the next, and also exposes similar tests to the same +//! known-problematic input. +//! +//! († If you do not have an obvious source directory, you may instead find +//! files next to the source files, with a different extension.) +//! +//! It is recommended to check these files in to your source control so that +//! other test runners (e.g., collaborators or a CI system) also replay these +//! cases. +//! +//! Note that, by default, all tests in the same crate will share that one +//! persistence file. If you have a very large number of tests, it may be +//! desirable to separate them into smaller groups so the number of extra test +//! cases that get run is reduced. This can be done by adjusting the +//! `failure_persistence` flag on `Config`. +//! +//! There are two ways this persistence could theoretically be done. +//! +//! The immediately obvious option is to persist a representation of the value +//! itself, for example by using Serde. While this has some advantages, +//! particularly being resistant to changes like tweaking the input strategy, +//! it also has a lot of problems. Most importantly, there is no way to +//! determine whether any given value is actually within the domain of the +//! strategy that produces it. Thus, some (likely extremely fragile) mechanism +//! to ensure that the strategy that produced the value exactly matches the one +//! in use in a test case would be required. +//! +//! The other option is to store the _seed_ that was used to produce the +//! failing test case. This approach requires no support from the strategy or +//! the produced value. If the strategy in use differs from the one used to +//! produce failing case that was persisted, the seed may or may not produce +//! the problematic value, but nonetheless produces a valid value. Due to these +//! advantages, this is the approach Proptest uses. +//! +//! ## Forking and Timeouts +//! +//! By default, proptest tests are run in-process and are allowed to run for +//! however long it takes them. This is resource-efficient and produces the +//! nicest test output, and for many use cases is sufficient. However, problems +//! like overflowing the stack, aborting the process, or getting stuck in an +//! infinite will simply break the entire test process and prevent proptest +//! from determining a minimal reproducible case. +//! +//! As of version 0.7.1, proptest has optional "fork" and "timeout" features +//! (both enabled by default), which make it possible to run your test cases in +//! a subprocess and limit how long they may run. This is generally slower, +//! may make using a debugger more difficult, and makes test output harder to +//! interpret, but allows proptest to find and minimise test cases for these +//! situations as well. +//! +//! To enable these features, simply set the `fork` and/or `timeout` fields on +//! the `Config`. (Setting `timeout` implies `fork`.) +//! +//! Here is a simple example of using both features: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! // The worst possible way to calculate Fibonacci numbers +//! fn fib(n: u64) -> u64 { +//! if n <= 1 { +//! n +//! } else { +//! fib(n - 1) + fib(n - 2) +//! } +//! } +//! +//! proptest! { +//! #![proptest_config(ProptestConfig { +//! // Setting both fork and timeout is redundant since timeout implies +//! // fork, but both are shown for clarity. +//! fork: true, +//! timeout: 1000, +//! .. ProptestConfig::default() +//! })] +//! +//! # /* NOREADME +//! #[test] +//! # NOREADME */ +//! fn test_fib(n: u64) { +//! // For large n, this will variously run for an extremely long time, +//! // overflow the stack, or panic due to integer overflow. +//! assert!(fib(n) >= n); +//! } +//! } +//! # //NOREADME +//! # fn main() { } //NOREADME +//! ``` +//! +//! The exact value of the test failure depends heavily on the performance of +//! the host system, the rust version, and compiler flags, but on the system +//! where it was originally tested, it found that the maximum value that +//! `fib()` could handle was 39, despite having dozens of processes dump core +//! due to stack overflow or time out along the way. +//! +//! If you just want to run tests in subprocesses or with a timeout every now +//! and then, you can do that by setting the `PROPTEST_FORK` or +//! `PROPTEST_TIMEOUT` environment variables to alter the default +//! configuration. For example, on Unix, +//! +//! ```sh +//! # Run all the proptest tests in subprocesses with no timeout. +//! # Individual tests can still opt out by setting `fork: false` in their +//! # own configuration. +//! PROPTEST_FORK=true cargo test +//! # Run all the proptest tests in subprocesses with a 1 second timeout. +//! # Tests can still opt out or use a different timeout by setting `timeout: 0` +//! # or another timeout in their own configuration. +//! PROPTEST_TIMEOUT=1000 cargo test +//! ``` +//! +//! +//! +//! ## In-Depth Tutorial +//! +//! This tutorial will introduce proptest from the bottom up, starting from the +//! basic building blocks, in the hopes of making the model as a whole clear. +//! In particular, we'll start off without using the macros so that the macros +//! can later be understood in terms of what they expand into rather than +//! magic. But as a result, the first part is _not_ representative of how +//! proptest is normally used. If bottom-up isn't your style, you may wish to +//! skim the first few sections. +//! +//! Also note that the examples here focus on the usage of proptest itself, and +//! as such generally have trivial test bodies. In real code, you would +//! obviously have assertions and so forth in the test bodies. +//! +//! ### Strategy Basics +//! +//! The [_Strategy_](strategy/trait.Strategy.html) is the most fundamental +//! concept in proptest. A strategy defines two things: +//! +//! - How to generate random values of a particular type from a random number +//! generator. +//! +//! - How to "shrink" such values into "simpler" forms. +//! +//! Proptest ships with a substantial library of strategies. Some of these are +//! defined in terms of built-in types; for example, `0..100i32` is a strategy +//! to generate `i32`s between 0, inclusive, and 100, exclusive. As we've +//! already seen, strings are themselves strategies for generating strings +//! which match the former as a regular expression. +//! +//! Generating a value is a two-step process. First, a `TestRunner` is passed +//! to the `new_tree()` method of the `Strategy`; this returns a `ValueTree`, +//! which we'll look at in more detail momentarily. Calling the `current()` +//! method on the `ValueTree` produces the actual value. Knowing that, we can +//! put the pieces together and generate values. The below is the +//! `tutoral-strategy-play.rs` example: +//! +//! ```rust +//! extern crate proptest; +//! +//! use proptest::test_runner::TestRunner; +//! use proptest::strategy::{Strategy, ValueTree}; +//! +//! fn main() { +//! let mut runner = TestRunner::default(); +//! let int_val = (0..100i32).new_tree(&mut runner).unwrap(); +//! let str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" +//! .new_tree(&mut runner).unwrap(); +//! println!("int_val = {}, str_val = {}", +//! int_val.current(), str_val.current()); +//! } +//! ``` +//! +//! If you run this a few times, you'll get output similar to the following: +//! +//! ```text +//! $ target/debug/examples/tutorial-strategy-play +//! int_val = 99, str_val = vѨͿἕΌ +//! $ target/debug/examples/tutorial-strategy-play +//! int_val = 25, str_val = cwᵸійΉ +//! $ target/debug/examples/tutorial-strategy-play +//! int_val = 5, str_val = oegiᴫᵸӈᵸὛΉ +//! ``` +//! +//! This knowledge is sufficient to build an extremely primitive fuzzing test. +//! +//! ```rust,no_run +//! extern crate proptest; +//! +//! use proptest::test_runner::TestRunner; +//! use proptest::strategy::{Strategy, ValueTree}; +//! +//! fn some_function(v: i32) { +//! // Do a bunch of stuff, but crash if v > 500 +//! assert!(v <= 500); +//! } +//! +//! # /* +//! #[test] +//! # */ +//! fn some_function_doesnt_crash() { +//! let mut runner = TestRunner::default(); +//! for _ in 0..256 { +//! let val = (0..10000i32).new_tree(&mut runner).unwrap(); +//! some_function(val.current()); +//! } +//! } +//! # fn main() { } +//! ``` +//! +//! This _works_, but when the test fails, we don't get much context, and even +//! if we recover the input, we see some arbitrary-looking value like 1771 +//! rather than the boundary condition of 501. For a function taking just an +//! integer, this is probably still good enough, but as inputs get more +//! complex, interpreting completely random values becomes increasingly +//! difficult. +//! +//! ### Shrinking Basics +//! +//! Finding the "simplest" input that causes a test failure is referred to as +//! _shrinking_. This is where the intermediate `ValueTree` type comes in. +//! Besides `current()`, it provides two methods — `simplify()` and +//! `complicate()` — which together allow binary searching over the input +//! space. The `tutorial-simplify-play.rs` example shows how repeated calls to +//! `simplify()` produce incrementally "simpler" outputs, both in terms of size +//! and in characters used. +//! +//! ```rust +//! extern crate proptest; +//! +//! use proptest::test_runner::TestRunner; +//! use proptest::strategy::{Strategy, ValueTree}; +//! +//! fn main() { +//! let mut runner = TestRunner::default(); +//! let mut str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" +//! .new_tree(&mut runner).unwrap(); +//! println!("str_val = {}", str_val.current()); +//! while str_val.simplify() { +//! println!(" = {}", str_val.current()); +//! } +//! } +//! ``` +//! +//! A couple runs: +//! +//! ```text +//! $ target/debug/examples/tutorial-simplify-play +//! str_val = vy꙲ꙈᴫѱΆῨῨ +//! = y꙲ꙈᴫѱΆῨῨ +//! = y꙲ꙈᴫѱΆῨῨ +//! = m꙲ꙈᴫѱΆῨῨ +//! = g꙲ꙈᴫѱΆῨῨ +//! = d꙲ꙈᴫѱΆῨῨ +//! = b꙲ꙈᴫѱΆῨῨ +//! = a꙲ꙈᴫѱΆῨῨ +//! = aꙈᴫѱΆῨῨ +//! = aᴫѱΆῨῨ +//! = aѱΆῨῨ +//! = aѱΆῨῨ +//! = aѱΆῨῨ +//! = aиΆῨῨ +//! = aМΆῨῨ +//! = aЎΆῨῨ +//! = aЇΆῨῨ +//! = aЃΆῨῨ +//! = aЁΆῨῨ +//! = aЀΆῨῨ +//! = aЀῨῨ +//! = aЀῨ +//! = aЀῨ +//! = aЀῢ +//! = aЀ῟ +//! = aЀ῞ +//! = aЀ῝ +//! $ target/debug/examples/tutorial-simplify-play +//! str_val = dyiꙭᾪῇΊ +//! = yiꙭᾪῇΊ +//! = iꙭᾪῇΊ +//! = iꙭᾪῇΊ +//! = iꙭᾪῇΊ +//! = eꙭᾪῇΊ +//! = cꙭᾪῇΊ +//! = bꙭᾪῇΊ +//! = aꙭᾪῇΊ +//! = aꙖᾪῇΊ +//! = aꙋᾪῇΊ +//! = aꙅᾪῇΊ +//! = aꙂᾪῇΊ +//! = aꙁᾪῇΊ +//! = aꙀᾪῇΊ +//! = aꙀῇΊ +//! = aꙀΊ +//! = aꙀΊ +//! = aꙀΊ +//! = aꙀΉ +//! = aꙀΈ +//! ``` +//! +//! Note that shrinking never shrinks a value to something outside the range +//! the strategy describes. Notice the strings in the above example still match +//! the regular expression even in the end. An integer drawn from +//! `100..1000i32` will shrink towards zero, but will stop at 100 since that is +//! the minimum value. +//! +//! `simplify()` and `complicate()` can be used to adapt our primitive fuzz +//! test to actually find the boundary condition. +//! +//! ```rust +//! extern crate proptest; +//! +//! use proptest::test_runner::TestRunner; +//! use proptest::strategy::{Strategy, ValueTree}; +//! +//! fn some_function(v: i32) -> bool { +//! // Do a bunch of stuff, but crash if v > 500 +//! // assert!(v <= 500); +//! // But return a boolean instead of panicking for simplicity +//! v <= 500 +//! } +//! +//! // We know the function is broken, so use a purpose-built main function to +//! // find the breaking point. +//! fn main() { +//! let mut runner = TestRunner::default(); +//! for _ in 0..256 { +//! let mut val = (0..10000i32).new_tree(&mut runner).unwrap(); +//! if some_function(val.current()) { +//! // Test case passed +//! continue; +//! } +//! +//! // We found our failing test case, simplify it as much as possible. +//! loop { +//! if !some_function(val.current()) { +//! // Still failing, find a simpler case +//! if !val.simplify() { +//! // No more simplification possible; we're done +//! break; +//! } +//! } else { +//! // Passed this input, back up a bit +//! if !val.complicate() { +//! break; +//! } +//! } +//! } +//! +//! println!("The minimal failing case is {}", val.current()); +//! assert_eq!(501, val.current()); +//! return; +//! } +//! panic!("Didn't find a failing test case"); +//! } +//! ``` +//! +//! This code reliably finds the boundary of the failure, 501. +//! +//! ### Using the Test Runner +//! +//! The above is quite a bit of code though, and it can't handle things like +//! panics. Fortunately, proptest's +//! [`TestRunner`](test_runner/struct.TestRunner.html) provides this +//! functionality for us. The method we're interested in is `run`. We simply +//! give it the strategy and a function to test inputs and it takes care of the +//! rest. +//! +//! ```rust +//! extern crate proptest; +//! +//! use proptest::test_runner::{Config, FileFailurePersistence, +//! TestError, TestRunner}; +//! +//! fn some_function(v: i32) { +//! // Do a bunch of stuff, but crash if v > 500. +//! // We return to normal `assert!` here since `TestRunner` catches +//! // panics. +//! assert!(v <= 500); +//! } +//! +//! // We know the function is broken, so use a purpose-built main function to +//! // find the breaking point. +//! fn main() { +//! let mut runner = TestRunner::new(Config { +//! // Turn failure persistence off for demonstration +//! failure_persistence: Some(Box::new(FileFailurePersistence::Off)), +//! .. Config::default() +//! }); +//! let result = runner.run(&(0..10000i32), |v| { +//! some_function(v); +//! Ok(()) +//! }); +//! match result { +//! Err(TestError::Fail(_, value)) => { +//! println!("Found minimal failing case: {}", value); +//! assert_eq!(501, value); +//! }, +//! result => panic!("Unexpected result: {:?}", result), +//! } +//! } +//! ``` +//! +//! That's a lot better! Still a bit boilerplatey; the `proptest!` macro will +//! help with that, but it does some other stuff we haven't covered yet, so for +//! the moment we'll keep using `TestRunner` directly. +//! +//! ### Compound Strategies +//! +//! Testing functions that take single arguments of primitive types is nice and +//! all, but is kind of underwhelming. Back when we were writing the whole +//! stack by hand, extending the technique to, say, _two_ integers was clear, +//! if verbose. But `TestRunner` only takes a single `Strategy`; how can we +//! test a function that needs inputs from more than one? +//! +//! ```rust,ignore +//! use proptest::test_runner::TestRunner; +//! +//! fn add(a: i32, b: i32) -> i32 { +//! a + b +//! } +//! +//! # /* +//! #[test] +//! # */ +//! fn test_add() { +//! let mut runner = TestRunner::default(); +//! runner.run(/* uhhm... */).unwrap(); +//! } +//! # +//! # fn main() { test_add(); } +//! ``` +//! +//! The key is that strategies are _composable_. The simplest form of +//! composition is "compound strategies", where we take multiple strategies and +//! combine their values into one value that holds each input separately. There +//! are several of these. The simplest is a tuple; a tuple of strategies is +//! itself a strategy for tuples of the values those strategies produce. For +//! example, `(0..100i32,100..1000i32)` is a strategy for pairs of integers +//! where the first value is between 0 and 100 and the second is between 100 +//! and 1000. +//! +//! So for our two-argument function, our strategy is simply a tuple of ranges. +//! +//! ```rust +//! use proptest::test_runner::TestRunner; +//! +//! fn add(a: i32, b: i32) -> i32 { +//! a + b +//! } +//! +//! # /* +//! #[test] +//! # */ +//! fn test_add() { +//! let mut runner = TestRunner::default(); +//! // Combine our two inputs into a strategy for one tuple. Our test +//! // function then destructures the generated tuples back into separate +//! // `a` and `b` variables to be passed in to `add()`. +//! runner.run(&(0..1000i32, 0..1000i32), |(a, b)| { +//! let sum = add(a, b); +//! assert!(sum >= a); +//! assert!(sum >= b); +//! Ok(()) +//! }).unwrap(); +//! } +//! # +//! # fn main() { test_add(); } +//! ``` +//! +//! Other compound strategies include fixed-sizes arrays of strategies and +//! `Vec`s of strategies (which produce arrays or `Vec`s of values parallel to +//! the strategy collection), as well as the various strategies provided in the +//! [collection](collection/index.html) module. +//! +//! ### Syntax Sugar: `proptest!` +//! +//! Now that we know about compound strategies, we can understand how the +//! [`proptest!`](macro.proptest.html) macro works. Our example from the prior +//! section can be rewritten using that macro like so: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! +//! fn add(a: i32, b: i32) -> i32 { +//! a + b +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_add(a in 0..1000i32, b in 0..1000i32) { +//! let sum = add(a, b); +//! assert!(sum >= a); +//! assert!(sum >= b); +//! } +//! } +//! # +//! # fn main() { test_add(); } +//! ``` +//! +//! Conceptually, the desugaring process is fairly simple. At the start of the +//! test function, a new `TestRunner` is constructed. The input strategies +//! (after the `in` keyword) are grouped into a tuple. That tuple is passed in +//! to the `TestRunner` as the input strategy. The test body has `Ok(())` added +//! to the end, then is put into a lambda that destructures the generated input +//! tuple back into the named parameters and then runs the body. The end result +//! is extremely similar to what we wrote by hand in the prior section. +//! +//! `proptest!` actually does a few other things in order to make failure +//! output easier to read and to overcome the 10-tuple limit. +//! +//! ### Transforming Strategies +//! +//! Suppose you have a function that takes a string which needs to be the +//! `Display` format of an arbitrary `u32`. A first attempt to providing this +//! argument might be to use a regular expression, like so: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! +//! fn do_stuff(v: String) { +//! let i: u32 = v.parse().unwrap(); +//! let s = i.to_string(); +//! assert_eq!(s, v); +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff(v in "[1-9][0-9]{0,8}") { +//! do_stuff(v); +//! } +//! } +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! This kind of works, but it has problems. For one, it does not explore the +//! whole `u32` space. It is possible to write a regular expression that does, +//! but such an expression is rather long, and also results in a pretty odd +//! distribution of values. The input also doesn't shrink correctly, since +//! proptest tries to shrink it in terms of a string rather than an integer. +//! +//! What you really want to do is generate a `u32` and then pass in its string +//! representation. One way to do this is to just take `u32` as an input to the +//! test and then transform it to a string within the test code. This approach +//! works fine, but isn't reusable or composable. Ideally, we could get a +//! _strategy_ that does this. +//! +//! The thing we're looking for is the first strategy _combinator_, `prop_map`. +//! We need to ensure `Strategy` is in scope to use it. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! // Grab `Strategy` and a shorter namespace prefix +//! use proptest::prelude::*; +//! +//! fn do_stuff(v: String) { +//! let i: u32 = v.parse().unwrap(); +//! let s = i.to_string(); +//! assert_eq!(s, v); +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff(v in any::().prop_map(|v| v.to_string())) { +//! do_stuff(v); +//! } +//! } +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! Calling `prop_map` on a `Strategy` creates a new strategy which transforms +//! every generated value using the provided function. Proptest retains the +//! relationship between the original `Strategy` and the transformed one; as a +//! result, shrinking occurs in terms of `u32`, even though we're generating a +//! `String`. +//! +//! `prop_map` is also the principal way to define strategies for new types, +//! since most types are simply composed of other, simpler values. +//! +//! Let's update our code so it takes a more interesting structure. +//! +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! #[derive(Clone, Debug)] +//! struct Order { +//! id: String, +//! // Some other fields, though the test doesn't do anything with them +//! item: String, +//! quantity: u32, +//! } +//! +//! fn do_stuff(order: Order) { +//! let i: u32 = order.id.parse().unwrap(); +//! let s = i.to_string(); +//! assert_eq!(s, order.id); +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff( +//! order in +//! (any::().prop_map(|v| v.to_string()), +//! "[a-z]*", 1..1000u32).prop_map( +//! |(id, item, quantity)| Order { id, item, quantity }) +//! ) { +//! do_stuff(order); +//! } +//! } +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! Notice how we were able to take the output from `prop_map` and put it in a +//! tuple, then call `prop_map` on _that_ tuple to produce yet another value. +//! +//! But that's quite a mouthful in the argument list. Fortunately, strategies +//! are normal values, so we can extract it to a function. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! // snip +//! # +//! # #[derive(Clone, Debug)] +//! # struct Order { +//! # id: String, +//! # // Some other fields, though the test doesn't do anything with them +//! # item: String, +//! # quantity: u32, +//! # } +//! # +//! # fn do_stuff(order: Order) { +//! # let i: u32 = order.id.parse().unwrap(); +//! # let s = i.to_string(); +//! # assert_eq!(s, order.id); +//! # } +//! +//! fn arb_order(max_quantity: u32) -> BoxedStrategy { +//! (any::().prop_map(|v| v.to_string()), +//! "[a-z]*", 1..max_quantity) +//! .prop_map(|(id, item, quantity)| Order { id, item, quantity }) +//! .boxed() +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff(order in arb_order(1000)) { +//! do_stuff(order); +//! } +//! } +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! We `boxed()` the strategy in the function since otherwise the type would +//! not be nameable, and even if it were, it would be very hard to read or +//! write. Boxing a `Strategy` turns both it and its `ValueTree`s into trait +//! objects, which both makes the types simpler and can be used to mix +//! heterogeneous `Strategy` types as long as they produce the same value +//! types. +//! +//! The `arb_order()` function is also _parameterised_, which is another +//! advantage of extracting strategies to separate functions. In this case, if +//! we have a test that needs an `Order` with no more than a dozen items, we +//! can simply call `arb_order(12)` rather than needing to write out a whole +//! new strategy. +//! +//! We can also use `-> impl Strategy` instead to avoid the +//! overhead as in the following example. You should use `-> impl Strategy<..>` +//! unless you need the dynamic dispatch. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! // snip +//! # +//! # #[derive(Clone, Debug)] +//! # struct Order { +//! # id: String, +//! # // Some other fields, though the test doesn't do anything with them +//! # item: String, +//! # quantity: u32, +//! # } +//! # +//! +//! # fn do_stuff(order: Order) { +//! # let i: u32 = order.id.parse().unwrap(); +//! # let s = i.to_string(); +//! # assert_eq!(s, order.id); +//! # } +//! +//! fn arb_order(max_quantity: u32) -> impl Strategy { +//! (any::().prop_map(|v| v.to_string()), +//! "[a-z]*", 1..max_quantity) +//! .prop_map(|(id, item, quantity)| Order { id, item, quantity }) +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff(order in arb_order(1000)) { +//! do_stuff(order); +//! } +//! } +//! +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! ### Syntax Sugar: `prop_compose!` +//! +//! Defining strategy-returning functions like this is extremely useful, but +//! the code above is a bit verbose, as well as hard to read for similar +//! reasons to writing test functions by hand. +//! +//! To simplify this task, proptest includes the +//! [`prop_compose!`](macro.prop_compose.html) macro. Before going into +//! details, here's our code from above rewritten to use it. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! // snip +//! # +//! # #[derive(Clone, Debug)] +//! # struct Order { +//! # id: String, +//! # // Some other fields, though the test doesn't do anything with them +//! # item: String, +//! # quantity: u32, +//! # } +//! # +//! # fn do_stuff(order: Order) { +//! # let i: u32 = order.id.parse().unwrap(); +//! # let s = i.to_string(); +//! # assert_eq!(s, order.id); +//! # } +//! +//! prop_compose! { +//! fn arb_order_id()(id in any::()) -> String { +//! id.to_string() +//! } +//! } +//! prop_compose! { +//! fn arb_order(max_quantity: u32) +//! (id in arb_order_id(), item in "[a-z]*", +//! quantity in 1..max_quantity) +//! -> Order { +//! Order { id, item, quantity } +//! } +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_do_stuff(order in arb_order(1000)) { +//! do_stuff(order); +//! } +//! } +//! # fn main() { test_do_stuff(); } +//! ``` +//! +//! We had to extract `arb_order_id()` out into its own function, but otherwise +//! this desugars to almost exactly what we wrote in the previous section. The +//! generated function takes the first parameter list as arguments. These +//! arguments are used to select the strategies in the second argument list. +//! Values are then drawn from those strategies and transformed by the function +//! body. The actual function has a return type of `impl Strategy` +//! where `T` is the declared return type. +//! +//! ### Generating Enums +//! +//! The syntax sugar for defining strategies for `enum`s is currently somewhat +//! limited. Creating such strategies with `prop_compose!` is possible but +//! generally is not very readable, so in most cases defining the function by +//! hand is preferable. +//! +//! The core building block is the [`prop_oneof!`](macro.prop_oneof.html) +//! macro, in which you list one case for each case in your `enum`. For `enum`s +//! which have no data, the strategy for each case is +//! `Just(YourEnum::TheCase)`. Enum cases with data generally require putting +//! the data in a tuple and then using `prop_map` to map it into the enum case. +//! +//! Here is a simple example: +//! +//! ```rust,no_run +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! #[derive(Debug, Clone)] +//! enum MyEnum { +//! SimpleCase, +//! CaseWithSingleDatum(u32), +//! CaseWithMultipleData(u32, String), +//! } +//! +//! fn my_enum_strategy() -> impl Strategy { +//! prop_oneof![ +//! // For cases without data, `Just` is all you need +//! Just(MyEnum::SimpleCase), +//! +//! // For cases with data, write a strategy for the interior data, then +//! // map into the actual enum case. +//! any::().prop_map(MyEnum::CaseWithSingleDatum), +//! +//! (any::(), ".*").prop_map( +//! |(a, b)| MyEnum::CaseWithMultipleData(a, b)), +//! ] +//! } +//! # +//! # fn main() { } +//! ``` +//! +//! In general, it is best to list the enum cases in order from "simplest" to +//! "most complex", since shrinking will shrink down toward items earlier in +//! the list. +//! +//! For particularly complex enum cases, it can be helpful to extract the +//! strategy for that case to a separate strategy. Here, +//! [`prop_compose!`](macro.prop_compose.html) can be of use. +//! +//! ```rust,no_run +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! #[derive(Debug, Clone)] +//! enum MyComplexEnum { +//! SimpleCase, +//! AnotherSimpleCase, +//! ComplexCase { +//! product_code: String, +//! id: u64, +//! chapter: String, +//! }, +//! } +//! +//! prop_compose! { +//! fn my_complex_enum_complex_case()( +//! product_code in "[0-9A-Z]{10,20}", +//! id in 1u64..10000u64, +//! chapter in "X{0,2}(V?I{1,3}|IV|IX)", +//! ) -> MyComplexEnum { +//! MyComplexEnum::ComplexCase { product_code, id, chapter } +//! } +//! } +//! +//! fn my_enum_strategy() -> BoxedStrategy { +//! prop_oneof![ +//! Just(MyComplexEnum::SimpleCase), +//! Just(MyComplexEnum::AnotherSimpleCase), +//! my_complex_enum_complex_case(), +//! ].boxed() +//! } +//! # +//! # fn main() { } +//! ``` +//! +//! ### Filtering +//! +//! Sometimes, you have a case where your input values have some sort of +//! "irregular" constraint on them. For example, an integer needing to be even, +//! or two values needing to be non-equal. +//! +//! In general, the ideal solution is to find a way to take a seed value and +//! then use `prop_map` to transform it into the desired, irregular domain. For +//! example, to generate even integers, use something like +//! +//! ```rust,no_run +//! # #[macro_use] extern crate proptest; +//! prop_compose! { +//! // Generate arbitrary integers up to half the maximum desired value, +//! // then multiply them by 2, thus producing only even integers in the +//! // desired range. +//! fn even_integer(max: i32)(base in 0..max/2) -> i32 { base * 2 } +//! } +//! # fn main() { } +//! ``` +//! +//! For the cases where this is not viable, it is possible to filter +//! strategies. Proptest actually divides filters into two categories: +//! +//! - "Local" filters apply to a single strategy. If a value is rejected, +//! a new value is drawn from that strategy only. +//! +//! - "Global" filters apply to the whole test case. If the test case is +//! rejected, the whole thing is regenerated. +//! +//! The distinction is somewhat arbitrary, since something like a "global +//! filter" could be created by just putting a "local filter" around the whole +//! input strategy. In practise, the distinction is as to what code performs +//! the rejection. +//! +//! A local filter is created with the `prop_filter` combinator. Besides a +//! function indicating whether to accept the value, it also takes a value of +//! type `&'static str`, `String`, .., which it uses to record where/why the +//! rejection happened. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn some_test( +//! v in (0..1000u32) +//! .prop_filter("Values must not divisible by 7 xor 11", +//! |v| !((0 == v % 7) ^ (0 == v % 11))) +//! ) { +//! assert_eq!(0 == v % 7, 0 == v % 11); +//! } +//! } +//! # fn main() { some_test(); } +//! ``` +//! +//! Global filtering results when a test itself returns +//! `Err(TestCaseError::Reject)`. The [`prop_assume!`](macro.prop_assume.html) +//! macro provides an easy way to do this. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! +//! fn frob(a: i32, b: i32) -> (i32, i32) { +//! let d = (a - b).abs(); +//! (a / d, b / d) +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_frob(a in -1000..1000, b in -1000..1000) { +//! // Input illegal if a==b. +//! // Equivalent to +//! // if (a == b) { return Err(TestCaseError::Reject(...)); } +//! prop_assume!(a != b); +//! +//! let (a2, b2) = frob(a, b); +//! assert!(a2.abs() <= a.abs()); +//! assert!(b2.abs() <= b.abs()); +//! } +//! } +//! # fn main() { test_frob(); } +//! ``` +//! +//! While useful, filtering has a lot of disadvantages: +//! +//! - Since it is simply rejection sampling, it will slow down generation of +//! test cases since values need to be generated additional times to satisfy +//! the filter. In the case where a filter always returns false, a test could +//! theoretically never generate a result. +//! +//! - Proptest tracks how many local and global rejections have happened, and +//! aborts if they exceed a certain number. This prevents a test taking an +//! extremely long time due to rejections, but means not all filters are viable +//! in the default configuration. The limits for local and global rejections +//! are different; by default, proptest allows a large number of local +//! rejections but a fairly small number of global rejections, on the premise +//! that the former are cheap but potentially common (having been built into +//! the strategy) but the latter are expensive but rare (being an edge case in +//! the particular test). +//! +//! - Shrinking and filtering do not play well together. When shrinking, if a +//! value winds up being rejected, there is no pass/fail information to +//! continue shrinking properly. Instead, proptest treats such a rejection the +//! same way it handles a shrink that results in a passing test: by backing +//! away from simplification with a call to `complicate()`. Thus encountering a +//! filter rejection during shrinking prevents shrinking from continuing to any +//! simpler values, even if there are some that would be accepted by the +//! filter. +//! +//! ### Generating Recursive Data +//! [generating-recursive-data]: #generating-recursive-data +//! +//! Randomly generating recursive data structures is trickier than it sounds. +//! For example, the below is a naïve attempt at generating a JSON AST by using +//! recursion. This also uses the [`prop_oneof!`](macro.prop_oneof.html), which +//! we haven't seen yet but should be self-explanatory. +//! +//! ```rust,no_run +//! #[macro_use] extern crate proptest; +//! +//! use std::collections::HashMap; +//! use proptest::prelude::*; +//! +//! #[derive(Clone, Debug)] +//! enum Json { +//! Null, +//! Bool(bool), +//! Number(f64), +//! String(String), +//! Array(Vec), +//! Map(HashMap), +//! } +//! +//! fn arb_json() -> impl Strategy { +//! prop_oneof![ +//! Just(Json::Null), +//! any::().prop_map(Json::Bool), +//! any::().prop_map(Json::Number), +//! ".*".prop_map(Json::String), +//! prop::collection::vec(arb_json(), 0..10).prop_map(Json::Array), +//! prop::collection::hash_map( +//! ".*", arb_json(), 0..10).prop_map(Json::Map), +//! ] +//! } +//! # fn main() { } +//! ``` +//! +//! Upon closer consideration, this obviously can't work because `arb_json()` +//! recurses unconditionally. +//! +//! A more sophisticated attempt is to define one strategy for each level of +//! nesting up to some maximum. This doesn't overflow the stack, but as defined +//! here, even four levels of nesting will produce trees with _thousands_ of +//! nodes; by eight levels, we get to tens of _millions_. +//! +//! Proptest provides a more reliable solution in the form of the +//! `prop_recursive` combinator. To use this, we create a strategy for the +//! non-recursive case, then give the combinator that strategy, some size +//! parameters, and a function to transform a nested strategy into a recursive +//! strategy. +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! +//! use std::collections::HashMap; +//! use proptest::prelude::*; +//! +//! #[derive(Clone, Debug)] +//! enum Json { +//! Null, +//! Bool(bool), +//! Number(f64), +//! String(String), +//! Array(Vec), +//! Map(HashMap), +//! } +//! +//! fn arb_json() -> impl Strategy { +//! let leaf = prop_oneof![ +//! Just(Json::Null), +//! any::().prop_map(Json::Bool), +//! any::().prop_map(Json::Number), +//! ".*".prop_map(Json::String), +//! ]; +//! leaf.prop_recursive( +//! 8, // 8 levels deep +//! 256, // Shoot for maximum size of 256 nodes +//! 10, // We put up to 10 items per collection +//! |inner| prop_oneof![ +//! // Take the inner strategy and make the two recursive cases. +//! prop::collection::vec(inner.clone(), 0..10) +//! .prop_map(Json::Array), +//! prop::collection::hash_map(".*", inner, 0..10) +//! .prop_map(Json::Map), +//! ]) +//! } +//! # fn main() { } +//! ``` +//! +//! ### Higher-Order Strategies +//! +//! A _higher-order strategy_ is a strategy which is generated by another +//! strategy. That sounds kind of scary, so let's consider an example first. +//! +//! Say you have a function you want to test that takes a slice and an index +//! into that slice. If we use a fixed size for the slice, it's easy, but maybe +//! we need to test with different slice sizes. We could try something with a +//! filter: +//! +//! ```rust,ignore +//! fn some_function(stuff: &[String], index: usize) { /* do stuff */ } +//! +//! proptest! { +//! #[test] +//! fn test_some_function( +//! stuff in prop::collection::vec(".*", 1..100), +//! index in 0..100usize +//! ) { +//! prop_assume!(index < stuff.len()); +//! some_function(stuff, index); +//! } +//! } +//! ``` +//! +//! This doesn't work very well. First off, you get a lot of global rejections +//! since `index` will be outside of `stuff` 50% of the time. But secondly, it +//! will be rare to actually get a small `stuff` vector, since it would have to +//! randomly choose a small `index` at the same time. +//! +//! The solution is the `prop_flat_map` combinator. This is sort of like +//! `prop_map`, except that the transform returns a _strategy_ instead of a +//! value. This is more easily understood by implementing our example: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::prelude::*; +//! +//! fn some_function(stuff: Vec, index: usize) { +//! let _ = &stuff[index]; +//! // Do stuff +//! } +//! +//! fn vec_and_index() -> impl Strategy, usize)> { +//! prop::collection::vec(".*", 1..100) +//! .prop_flat_map(|vec| { +//! let len = vec.len(); +//! (Just(vec), 0..len) +//! }) +//! } +//! +//! proptest! { +//! # /* +//! #[test] +//! # */ +//! fn test_some_function((vec, index) in vec_and_index()) { +//! some_function(vec, index); +//! } +//! } +//! # fn main() { test_some_function(); } +//! ``` +//! +//! In `vec_and_index()`, we make a strategy to produce an arbitrary vector. +//! But then we derive a new strategy based on _values_ produced by the first +//! one. The new strategy produces the generated vector unchanged, but also +//! adds a valid index into that vector, which we can do by picking the +//! strategy for that index based on the size of the vector. +//! +//! Even though the new strategy specifies the singleton `Just(vec)` strategy +//! for the vector, proptest still understands the connection to the original +//! strategy and will shrink `vec` as well. All the while, `index` continues to +//! be a valid index into `vec`. +//! +//! `prop_compose!` actually allows making second-order strategies like this by +//! simply providing three argument lists instead of two. The below desugars to +//! something much like what we wrote by hand above, except that the index and +//! vector's positions are internally reversed due to borrowing limitations. +//! +//! ```rust,no_run +//! # #[macro_use] extern crate proptest; +//! # use proptest::prelude::*; +//! prop_compose! { +//! fn vec_and_index()(vec in prop::collection::vec(".*", 1..100)) +//! (index in 0..vec.len(), vec in Just(vec)) +//! -> (Vec, usize) { +//! (vec, index) +//! } +//! } +//! # fn main() { } +//! ``` +//! +//! ### Defining a canonical `Strategy` for a type +//! +//! We previously used the function `any` as in `any::()` to generate a +//! strategy for all `u32`s. This function works with the trait `Arbitrary`, +//! which QuickCheck users may be familiar with. In proptest, this trait +//! is already implemented for most owned types in the standard library, +//! but you can of course implement it for your own types. +//! +//! In some cases, where it makes sense to define a canonical strategy, such +//! as in the [JSON AST example][generating-recursive-data], it is a good +//! idea to implement `Arbitrary`. +//! +//! Stay tuned for more information about this. Soon you will be able to +//! derive `Arbitrary` for a lot of cases. +//! +//! ### Configuring the number of tests cases requried +//! +//! The default number of successful test cases that must execute for a test +//! as a whole to pass is currently 256. If you are not satisfied with this +//! and want to run more or fewer, there are a few ways to do this. +//! +//! The first way is to set the environment-variable `PROPTEST_CASES` to a +//! value that can be successfully parsed as a `u32`. The value you set to this +//! variable is now the new default. +//! +//! Another way is to use `#![proptest_config(expr)]` inside `proptest!` where +//! `expr : Config`. To only change the number of test cases, you can simply +//! write: +//! +//! ```rust +//! #[macro_use] extern crate proptest; +//! use proptest::test_runner::Config; +//! +//! fn add(a: i32, b: i32) -> i32 { a + b } +//! +//! proptest! { +//! // The next line modifies the number of tests. +//! #![proptest_config(Config::with_cases(1000))] +//! # /* +//! #[test] +//! # */ +//! fn test_add(a in 0..1000i32, b in 0..1000i32) { +//! let sum = add(a, b); +//! assert!(sum >= a); +//! assert!(sum >= b); +//! } +//! } +//! # +//! # fn main() { test_add(); } +//! ``` +//! +//! Through the same `proptest_config` mechanism you may fine-tune your +//! configuration through the `Config` type. See its documentation for more +//! information. +//! +//! ### Conclusion +//! +//! That's it for the tutorial, at least for now. There are more details for +//! the features discussed above on their individual documentation pages, and +//! you can find out about all the strategies provided out-of-the-box by +//! perusing the module tree below. + +#![deny(missing_docs, bare_trait_objects)] +#![no_std] +#![cfg_attr(feature = "cargo-clippy", allow( + doc_markdown, + // We have a lot of these lints for associated types... And we don't care. + type_complexity +))] +#![cfg_attr(feature = "unstable", feature( + allocator_api, + try_trait, + generator_trait, + try_from, + integer_atomics, + never_type, + try_reserve +))] +#![cfg_attr(all(feature = "std", feature = "unstable"), feature( + mpsc_select, + ip +))] +#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature( + alloc, + core_intrinsics +))] + +// FIXME: remove this after refactoring! +#![allow(renamed_and_removed_lints)] + +#[macro_use] +mod std_facade; + +#[cfg(any(feature = "std", test))] +#[macro_use] +extern crate std; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] +extern crate alloc; + +//#[cfg(all(feature = "alloc", not(feature = "std")))] +//extern crate hashmap_core; + +extern crate byteorder; + +#[cfg(feature = "frunk")] +#[macro_use] +extern crate frunk_core; + +#[cfg(feature = "frunk")] +#[macro_use] +mod product_frunk; + +#[cfg(not(feature = "frunk"))] +#[macro_use] +mod product_tuple; + +#[macro_use] +extern crate bitflags; +#[cfg(feature = "bit-set")] +extern crate bit_set; +#[macro_use] +extern crate lazy_static; + +extern crate num_traits; + +// Only required for the string module. +#[cfg(feature = "std")] +#[macro_use] +extern crate quick_error; +// Only required for the string module. +#[cfg(feature = "std")] +extern crate regex_syntax; +extern crate rand; + +#[cfg(feature = "fork")] +#[macro_use] +extern crate rusty_fork; + +#[cfg(feature = "fork")] +extern crate tempfile; + +#[cfg(test)] +extern crate regex; + +#[macro_use] +mod macros; + +#[doc(hidden)] +#[macro_use] +pub mod sugar; + +pub mod arbitrary; +pub mod array; +pub mod bits; +pub mod bool; +pub mod char; +pub mod collection; +pub mod num; +pub mod strategy; +pub mod test_runner; +pub mod tuple; + +pub mod option; +pub mod result; +pub mod sample; +#[cfg(feature = "std")] +pub mod string; + +pub mod prelude; diff --git a/proptest/src/macros.rs b/proptest/src/macros.rs new file mode 100644 index 000000000..62d4b3d83 --- /dev/null +++ b/proptest/src/macros.rs @@ -0,0 +1,93 @@ +//- +// Copyright 2017, 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Macros for internal use to reduce boilerplate. + +// Pervasive internal sugar +macro_rules! mapfn { + ($({#[$allmeta:meta]})* $(#[$meta:meta])* [$($vis:tt)*] + fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty { + $($body:tt)* + }) => { + $(#[$allmeta])* $(#[$meta])* + #[derive(Clone, Copy, Debug)] + $($vis)* struct $name; + $(#[$allmeta])* + impl $($gen)* ::strategy::statics::MapFn<$input> for $name { + type Output = $output; + fn apply(&self, $parm: $input) -> $output { + $($body)* + } + } + } +} + +macro_rules! delegate_vt_0 { + () => { + fn current(&self) -> Self::Value { + self.0.current() + } + + fn simplify(&mut self) -> bool { + self.0.simplify() + } + + fn complicate(&mut self) -> bool { + self.0.complicate() + } + } +} + +macro_rules! opaque_strategy_wrapper { + ($({#[$allmeta:meta]})* + $(#[$smeta:meta])* + pub struct $stratname:ident + [$($sgen:tt)*][$($swhere:tt)*] + ($innerstrat:ty) -> $stratvtty:ty; + + $(#[$vmeta:meta])* pub struct $vtname:ident + [$($vgen:tt)*][$($vwhere:tt)*] + ($innervt:ty) -> $actualty:ty; + ) => { + $(#[$allmeta])* + $(#[$smeta])* + #[must_use = "strategies do nothing unless used"] + pub struct $stratname $($sgen)* ($innerstrat) + $($swhere)*; + + $(#[$allmeta])* + $(#[$vmeta])* pub struct $vtname $($vgen)* ($innervt) $($vwhere)*; + + $(#[$allmeta])* + impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* { + type Tree = $stratvtty; + type Value = $actualty; + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner).map($vtname) + } + } + + $(#[$allmeta])* + impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* { + type Value = $actualty; + + delegate_vt_0!(); + } + } +} + +// Example: unwrap_or!(result, err => handle_err(err)); +macro_rules! unwrap_or { + ($unwrap: expr, $err: ident => $on_err: expr) => { + match $unwrap { + Ok(ok) => ok, + Err($err) => $on_err, + } + }; +} diff --git a/proptest/src/num.rs b/proptest/src/num.rs new file mode 100644 index 000000000..8caa436f4 --- /dev/null +++ b/proptest/src/num.rs @@ -0,0 +1,1313 @@ +//- +// Copyright 2017, 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies to generate numeric values (as opposed to integers used as bit +//! fields). +//! +//! All strategies in this module shrink by binary searching towards 0. + +use rand::distributions::{Distribution, Standard}; +use rand::distributions::uniform::{Uniform, SampleUniform}; +use core::ops::Range; +use test_runner::TestRunner; + +pub(crate) fn sample_uniform + (run: &mut TestRunner, range: Range) -> X { + Uniform::new(range.start, range.end).sample(run.rng()) +} + +pub(crate) fn sample_uniform_incl + (run: &mut TestRunner, start: X, end: X) -> X +{ + Uniform::new_inclusive(start, end).sample(run.rng()) +} + +macro_rules! int_any { + ($typ: ident) => { + /// Type of the `ANY` constant. + #[derive(Clone, Copy, Debug)] + #[must_use = "strategies do nothing unless used"] + pub struct Any(()); + /// Generates integers with completely arbitrary values, uniformly + /// distributed over the whole range. + pub const ANY: Any = Any(()); + + impl Strategy for Any { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new(runner.rng().gen())) + } + } + } +} + +macro_rules! numeric_api { + ($typ:ident, $epsilon:expr) => { + impl Strategy for ::core::ops::Range<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + self.start, + $crate::num::sample_uniform(runner, self.clone()), + self.end - $epsilon)) + } + } + + impl Strategy for ::core::ops::RangeInclusive<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + *self.start(), + $crate::num::sample_uniform_incl(runner, *self.start(), *self.end()), + *self.end())) + } + } + + impl Strategy for ::core::ops::RangeFrom<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + self.start, + $crate::num::sample_uniform_incl( + runner, self.start, ::core::$typ::MAX), + ::core::$typ::MAX)) + } + } + + impl Strategy for ::core::ops::RangeTo<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + ::core::$typ::MIN, + $crate::num::sample_uniform( + runner, ::core::$typ::MIN..self.end), + self.end)) + } + } + + impl Strategy for ::core::ops::RangeToInclusive<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + ::core::$typ::MIN, + $crate::num::sample_uniform_incl( + runner, ::core::$typ::MIN, self.end), + self.end + )) + } + } + } +} + +macro_rules! signed_integer_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + use rand::Rng; + + use strategy::*; + use test_runner::TestRunner; + + int_any!($typ); + + /// Shrinks an integer towards 0, using binary search to find + /// boundary points. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + lo: $typ, + curr: $typ, + hi: $typ, + } + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { + lo: 0, + curr: start, + hi: start, + } + } + + /// Creates a new binary searcher which will not produce values + /// on the other side of `lo` or `hi` from `start`. `lo` is + /// inclusive, `hi` is exclusive. + fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { + use core::cmp::{min, max}; + + BinarySearch { + lo: if start < 0 { min(0, hi-1) } else { max(0, lo) }, + hi: start, + curr: start, + } + } + + fn reposition(&mut self) -> bool { + // Won't ever overflow since lo starts at 0 and advances + // towards hi. + let interval = self.hi - self.lo; + let new_mid = self.lo + interval/2; + + if new_mid == self.curr { + false + } else { + self.curr = new_mid; + true + } + } + + fn magnitude_greater(lhs: $typ, rhs: $typ) -> bool { + if 0 == lhs { + false + } else if lhs < 0 { + lhs < rhs + } else { + lhs > rhs + } + } + } + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + if !BinarySearch::magnitude_greater(self.hi, self.lo) { + return false; + } + + self.hi = self.curr; + self.reposition() + } + + fn complicate(&mut self) -> bool { + if !BinarySearch::magnitude_greater(self.hi, self.lo) { + return false; + } + + self.lo = self.curr + if self.hi < 0 { + -1 + } else { + 1 + }; + + self.reposition() + } + } + + numeric_api!($typ, 1); + } + } +} + +macro_rules! unsigned_integer_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + use rand::Rng; + + use strategy::*; + use test_runner::TestRunner; + + int_any!($typ); + + /// Shrinks an integer towards 0, using binary search to find + /// boundary points. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + lo: $typ, + curr: $typ, + hi: $typ, + } + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { + lo: 0, + curr: start, + hi: start, + } + } + + /// Creates a new binary searcher which will not search below + /// the given `lo` value. + fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self { + BinarySearch { + lo: lo, + curr: start, + hi: start, + } + } + + /// Creates a new binary searcher which will not search below + /// the given `lo` value. + pub fn new_above(lo: $typ, start: $typ) -> Self { + BinarySearch::new_clamped(lo, start, start) + } + + fn reposition(&mut self) -> bool { + let interval = self.hi - self.lo; + let new_mid = self.lo + interval/2; + + if new_mid == self.curr { + false + } else { + self.curr = new_mid; + true + } + } + } + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + if self.hi <= self.lo { return false; } + + self.hi = self.curr; + self.reposition() + } + + fn complicate(&mut self) -> bool { + if self.hi <= self.lo { return false; } + + self.lo = self.curr + 1; + self.reposition() + } + } + + numeric_api!($typ, 1); + } + } +} + +signed_integer_bin_search!(i8); +signed_integer_bin_search!(i16); +signed_integer_bin_search!(i32); +signed_integer_bin_search!(i64); +signed_integer_bin_search!(i128); +signed_integer_bin_search!(isize); +unsigned_integer_bin_search!(u8); +unsigned_integer_bin_search!(u16); +unsigned_integer_bin_search!(u32); +unsigned_integer_bin_search!(u64); +unsigned_integer_bin_search!(u128); +unsigned_integer_bin_search!(usize); + +bitflags! { + pub(crate) struct FloatTypes: u32 { + const POSITIVE = 0b0000_0001; + const NEGATIVE = 0b0000_0010; + const NORMAL = 0b0000_0100; + const SUBNORMAL = 0b0000_1000; + const ZERO = 0b0001_0000; + const INFINITE = 0b0010_0000; + const QUIET_NAN = 0b0100_0000; + const SIGNALING_NAN = 0b1000_0000; + const ANY = + Self::POSITIVE.bits | + Self::NEGATIVE.bits | + Self::NORMAL.bits | + Self::SUBNORMAL.bits | + Self::ZERO.bits | + Self::INFINITE.bits | + Self::QUIET_NAN.bits; + } +} + +impl FloatTypes { + fn normalise(mut self) -> Self { + if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { + self |= FloatTypes::POSITIVE; + } + + if !self.intersects(FloatTypes::NORMAL | FloatTypes::SUBNORMAL | + FloatTypes::ZERO | FloatTypes::INFINITE | + FloatTypes::QUIET_NAN | FloatTypes::SIGNALING_NAN) { + self |= FloatTypes::NORMAL; + } + self + } +} + +trait FloatLayout +where + Standard: Distribution, +{ + type Bits: Copy; + + const SIGN_MASK: Self::Bits; + const EXP_MASK: Self::Bits; + const EXP_ZERO: Self::Bits; + const MANTISSA_MASK: Self::Bits; +} + +impl FloatLayout for f32 { + type Bits = u32; + + const SIGN_MASK: u32 = 0x8000_0000; + const EXP_MASK: u32 = 0x7F80_0000; + const EXP_ZERO: u32 = 0x3F80_0000; + const MANTISSA_MASK: u32 = 0x007F_FFFF; +} + +impl FloatLayout for f64 { + type Bits = u64; + + const SIGN_MASK: u64 = 0x8000_0000_0000_0000; + const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; + const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000; + const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; +} + +macro_rules! float_any { + ($typ:ident) => { + /// Strategies which produce floating-point values from particular + /// classes. See the various `Any`-typed constants in this module. + /// + /// Note that this usage is fairly advanced and primarily useful to + /// implementors of algorithms that need to handle wild values in a + /// particular way. For testing things like graphics processing or game + /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more + /// practical. + /// + /// `Any` can be OR'ed to combine multiple classes. For example, + /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN + /// floats, including positive infinity (but not negative infinity, of + /// course). + /// + /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any` + /// but a type to be generated requires a sign, `POSITIVE` is assumed. + /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or + /// `NEGATIVE` are given), `NORMAL` is assumed. + /// + /// The various float classes are assigned fixed weights for generation + /// which are believed to be reasonable for most applications. Roughly: + /// + /// - If `POSITIE | NEGATIVE`, the sign is evenly distributed between + /// both options. + /// + /// - Classes are weighted as follows, in descending order: + /// `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` = + /// `SIGNALING_NAN`. + #[derive(Clone, Copy, Debug)] + #[must_use = "strategies do nothing unless used"] + pub struct Any(FloatTypes); + + #[cfg(test)] + impl Any { + pub(crate) fn from_bits(bits: u32) -> Self { + Any(FloatTypes::from_bits_truncate(bits)) + } + + pub(crate) fn normal_bits(&self) -> FloatTypes { + self.0.normalise() + } + } + + impl ops::BitOr for Any { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Any(self.0 | rhs.0) + } + } + + impl ops::BitOrAssign for Any { + fn bitor_assign(&mut self, rhs: Self) { + self.0 |= rhs.0 + } + } + + /// Generates positive floats + /// + /// By itself, implies the `NORMAL` class, unless another class is + /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will + /// generate arbitrary values between the type's `MIN_POSITIVE` and + /// `MAX`, while `POSITIVE | INFINITE` would only allow generating + /// positive infinity. + pub const POSITIVE: Any = Any(FloatTypes::POSITIVE); + /// Generates negative floats. + /// + /// By itself, implies the `NORMAL` class, unless another class is + /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will + /// generate arbitrary values between the type's `MIN` and + /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow + /// generating positive infinity. + pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE); + /// Generates "normal" floats. + /// + /// These are finite values where the first bit of the mantissa is an + /// implied `1`. When positive, this represents the range + /// `MIN_POSITIVE` through `MAX`, both inclusive. + /// + /// Generated values are uniform over the discrete floating-point + /// space, which means the numeric distribution is an inverse + /// exponential step function. For example, values between 1.0 and 2.0 + /// are generated with the same frequency as values between 2.0 and + /// 4.0, even though the latter covers twice the numeric range. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const NORMAL: Any = Any(FloatTypes::NORMAL); + /// Generates subnormal floats. + /// + /// These are finite non-zero values where the first bit of the + /// mantissa is not an implied zero. When positive, this represents the + /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive. + /// + /// Subnormals are generated with a uniform distribution both in terms + /// of discrete floating-point space and numerically. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL); + /// Generates zero-valued floats. + /// + /// Note that IEEE floats support both positive and negative zero, so + /// this class does interact with the sign flags. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const ZERO: Any = Any(FloatTypes::ZERO); + /// Generates infinity floats. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const INFINITE: Any = Any(FloatTypes::INFINITE); + /// Generates "Quiet NaN" floats. + /// + /// Operations on quiet NaNs generally simply propagate the NaN rather + /// than invoke any exception mechanism. + /// + /// The payload of the NaN is uniformly distributed over the possible + /// values which safe Rust allows, including the sign bit (as + /// controlled by `POSITIVE` and `NEGATIVE`). + /// + /// Note however that in Rust 1.23.0 and earlier, this constitutes only + /// one particular payload due to apparent issues with particular MIPS + /// and PA-RISC processors which fail to implement IEEE 754-2008 + /// correctly. + /// + /// On Rust 1.24.0 and later, this does produce arbitrary payloads as + /// documented. + /// + /// On platforms where the CPU and the IEEE standard disagree on the + /// format of a quiet NaN, values generated conform to the hardware's + /// expectations. + pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN); + /// Generates "Signaling NaN" floats if allowed by the platform. + /// + /// On most platforms, signalling NaNs by default behave the same as + /// quiet NaNs, but it is possible to configure the OS or CPU to raise + /// an asynchronous exception if an operation is performed on a + /// signalling NaN. + /// + /// In Rust 1.23.0 and earlier, this silently behaves the same as + /// [`QUIET_NAN`](const.QUIET_NAN.html). + /// + /// On platforms where the CPU and the IEEE standard disagree on the + /// format of a quiet NaN, values generated conform to the hardware's + /// expectations. + /// + /// Note that certain platforms — most notably, x86/AMD64 — allow the + /// architecture to turn a signalling NaN into a quiet NaN with the + /// same payload. Whether this happens can depend on what registers the + /// compiler decides to use to pass the value around, what CPU flags + /// are set, and what compiler settings are in use. + pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN); + + /// Generates literally arbitrary floating-point values, including + /// infinities and quiet NaNs (but not signaling NaNs). + /// + /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO | + /// INFINITE | QUIET_NAN`. + /// + /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to + /// generate signalling NaNs. This signalling NaNs are not included by + /// default since in most contexts they either make no difference, or + /// if the process enabled the relevant CPU mode, result in + /// hardware-triggered exceptions that usually just abort the process. + /// + /// Before proptest 0.4.1, this erroneously generated values in the + /// range 0.0..1.0. + pub const ANY: Any = Any(FloatTypes::ANY); + + impl Strategy for Any { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let flags = self.0.normalise(); + let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { + $typ::SIGN_MASK + } else { + 0 + }; + let sign_or = if flags.contains(FloatTypes::POSITIVE) { + 0 + } else { + $typ::SIGN_MASK + }; + + macro_rules! weight { + ($case:ident, $weight:expr) => { + if flags.contains(FloatTypes::$case) { + $weight + } else { + 0 + } + } + } + + // A few CPUs disagree with IEEE about the meaning of the + // signalling bit. Assume the `NAN` constant is a quiet NaN as + // interpreted by the hardware and generate values based on + // that. + let quiet_or = ::core::$typ::NAN.to_bits() & + ($typ::EXP_MASK | ($typ::EXP_MASK >> 1)); + let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) | + $typ::EXP_MASK; + + let (class_mask, class_or, allow_edge_exp, allow_zero_mant) = + prop_oneof![ + weight!(NORMAL, 20) => Just( + ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0, + false, true)), + weight!(SUBNORMAL, 3) => Just( + ($typ::MANTISSA_MASK, 0, true, false)), + weight!(ZERO, 4) => Just( + (0, 0, true, true)), + weight!(INFINITE, 2) => Just( + (0, $typ::EXP_MASK, true, true)), + weight!(QUIET_NAN, 1) => Just( + ($typ::MANTISSA_MASK >> 1, quiet_or, + true, false)), + weight!(SIGNALING_NAN, 1) => Just( + ($typ::MANTISSA_MASK >> 1, signaling_or, + true, false)), + ].new_tree(runner)?.current(); + + let mut generated_value: <$typ as FloatLayout>::Bits = + runner.rng().gen(); + generated_value &= sign_mask | class_mask; + generated_value |= sign_or | class_or; + let exp = generated_value & $typ::EXP_MASK; + if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) { + generated_value &= !$typ::EXP_MASK; + generated_value |= $typ::EXP_ZERO; + } + if !allow_zero_mant && + 0 == generated_value & $typ::MANTISSA_MASK + { + generated_value |= 1; + } + + Ok(BinarySearch::new_with_types( + $typ::from_bits(generated_value), flags)) + } + } + } +} + +macro_rules! float_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + use core::ops; + #[cfg(not(feature = "std"))] + use num_traits::float::FloatCore; + + use rand::Rng; + + use strategy::*; + use test_runner::TestRunner; + use super::{FloatTypes, FloatLayout}; + + float_any!($typ); + + /// Shrinks a float towards 0, using binary search to find boundary + /// points. + /// + /// Non-finite values immediately shrink to 0. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + lo: $typ, + curr: $typ, + hi: $typ, + allowed: FloatTypes, + } + + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { + lo: 0.0, + curr: start, + hi: start, + allowed: FloatTypes::all(), + } + } + + fn new_with_types(start: $typ, allowed: FloatTypes) -> Self { + BinarySearch { + lo: 0.0, + curr: start, + hi: start, + allowed, + } + } + + /// Creates a new binary searcher which will not produce values + /// on the other side of `lo` or `hi` from `start`. `lo` is + /// inclusive, `hi` is exclusive. + fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { + BinarySearch { + lo: if start.is_sign_negative() { + hi.min(0.0) + } else { + lo.max(0.0) + }, + hi: start, + curr: start, + allowed: FloatTypes::all(), + } + } + + fn current_allowed(&self) -> bool { + use core::num::FpCategory::*; + + // Don't reposition if the new value is not allowed + let class_allowed = match self.curr.classify() { + Nan => + // We don't need to inspect whether the + // signallingness of the NaN matches the allowed + // set, as we never try to switch between them, + // instead shrinking to 0. + self.allowed.contains(FloatTypes::QUIET_NAN) || + self.allowed.contains(FloatTypes::SIGNALING_NAN), + Infinite => self.allowed.contains(FloatTypes::INFINITE), + Zero => self.allowed.contains(FloatTypes::ZERO), + Subnormal => self.allowed.contains(FloatTypes::SUBNORMAL), + Normal => self.allowed.contains(FloatTypes::NORMAL), + }; + let signum = self.curr.signum(); + let sign_allowed = if signum > 0.0 { + self.allowed.contains(FloatTypes::POSITIVE) + } else if signum < 0.0 { + self.allowed.contains(FloatTypes::NEGATIVE) + } else { + true + }; + + class_allowed && sign_allowed + } + + fn ensure_acceptable(&mut self) { + while !self.current_allowed() { + if !self.complicate_once() { + panic!("Unable to complicate floating-point back \ + to acceptable value"); + } + } + } + + fn reposition(&mut self) -> bool { + let interval = self.hi - self.lo; + let interval = if interval.is_finite() { + interval + } else { + 0.0 + }; + let new_mid = self.lo + interval/2.0; + + let new_mid = if new_mid == self.curr || 0.0 == interval { + new_mid + } else { + self.lo + }; + + if new_mid == self.curr { + false + } else { + self.curr = new_mid; + true + } + } + + fn done(lo: $typ, hi: $typ) -> bool { + (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan() + } + + fn complicate_once(&mut self) -> bool { + if BinarySearch::done(self.lo, self.hi) { + return false; + } + + self.lo = if self.curr == self.lo { + self.hi + } else { + self.curr + }; + + self.reposition() + } + } + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + if BinarySearch::done(self.lo, self.hi) { + return false; + } + + self.hi = self.curr; + if self.reposition() { + self.ensure_acceptable(); + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.complicate_once() { + self.ensure_acceptable(); + true + } else { + false + } + } + } + + numeric_api!($typ, 0.0); + } + } +} + +float_bin_search!(f32); +float_bin_search!(f64); + +#[cfg(test)] +mod test { + use strategy::*; + use test_runner::*; + + use super::*; + + #[test] + fn u8_inclusive_end_included() { + let mut runner = TestRunner::default(); + let mut ok = 0; + for _ in 0..20 { + let tree = (0..=1).new_tree(&mut runner).unwrap(); + let test = runner.run_one(tree, |v| { + prop_assert_eq!(v, 1); + Ok(()) + }); + if test.is_ok() { + ok += 1; + } + } + assert!(ok > 1, "inclusive end not included."); + } + + #[test] + fn u8_inclusive_to_end_included() { + let mut runner = TestRunner::default(); + let mut ok = 0; + for _ in 0..20 { + let tree = (..=1u8).new_tree(&mut runner).unwrap(); + let test = runner.run_one(tree, |v| { + prop_assert_eq!(v, 1); + Ok(()) + }); + if test.is_ok() { + ok += 1; + } + } + assert!(ok > 1, "inclusive end not included."); + } + + #[test] + fn i8_binary_search_always_converges() { + fn assert_converges

bool>(start: i8, pass: P) { + let mut state = i8::BinarySearch::new(start); + loop { + if !pass(state.current() as i32) { + if !state.simplify() { + break; + } + } else { + if !state.complicate() { + break; + } + } + } + + assert!(!pass(state.current() as i32)); + assert!(pass(state.current() as i32 - 1) || + pass(state.current() as i32 + 1)); + } + + for start in -128..0 { + for target in start+1..1 { + assert_converges(start as i8, |v| v > target); + } + } + + for start in 0..128 { + for target in 0..start { + assert_converges(start as i8, |v| v < target); + } + } + } + + #[test] + fn u8_binary_search_always_converges() { + fn assert_converges

bool>(start: u8, pass: P) { + let mut state = u8::BinarySearch::new(start); + loop { + if !pass(state.current() as u32) { + if !state.simplify() { + break; + } + } else { + if !state.complicate() { + break; + } + } + } + + assert!(!pass(state.current() as u32)); + assert!(pass(state.current() as u32 - 1)); + } + + for start in 0..255 { + for target in 0..start { + assert_converges(start as u8, |v| v <= target); + } + } + } + + #[test] + fn signed_integer_range_including_zero_converges_to_zero() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= -42 && init_value < 64); + + while state.simplify() { + let v = state.current(); + assert!(v >= -42 && v < 64); + } + + assert_eq!(0, state.current()); + } + } + + #[test] + fn negative_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (..-42i32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value < -42); + + while state.simplify() { + assert!(state.current() < -42, + "Violated bounds: {}", state.current()); + } + + assert_eq!(-43, state.current()); + } + } + + #[test] + fn positive_signed_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (42i32..).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= 42); + + while state.simplify() { + assert!(state.current() >= 42, + "Violated bounds: {}", state.current()); + } + + assert_eq!(42, state.current()); + } + } + + #[test] + fn unsigned_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (42u32..56u32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= 42 && init_value < 56); + + while state.simplify() { + assert!(state.current() >= 42, + "Violated bounds: {}", state.current()); + } + + assert_eq!(42, state.current()); + } + } + + mod contract_sanity { + macro_rules! contract_sanity { + ($t:tt) => { + mod $t { + use strategy::check_strategy_sanity; + + const FOURTY_TWO: $t = 42 as $t; + const FIFTY_SIX: $t = 56 as $t; + + #[test] + fn range() { + check_strategy_sanity(FOURTY_TWO..FIFTY_SIX, None); + } + + #[test] + fn range_inclusive() { + check_strategy_sanity(FOURTY_TWO..=FIFTY_SIX, None); + } + + #[test] + fn range_to() { + check_strategy_sanity(..FIFTY_SIX, None); + } + + #[test] + fn range_to_inclusive() { + check_strategy_sanity(..=FIFTY_SIX, None); + } + + #[test] + fn range_from() { + check_strategy_sanity(FOURTY_TWO.., None); + } + } + } + } + contract_sanity!(u8); + contract_sanity!(i8); + contract_sanity!(u16); + contract_sanity!(i16); + contract_sanity!(u32); + contract_sanity!(i32); + contract_sanity!(u64); + contract_sanity!(i64); + contract_sanity!(usize); + contract_sanity!(isize); + contract_sanity!(f32); + contract_sanity!(f64); + } + + #[test] + fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() { + check_strategy_sanity(0u32..1000u32, None); + check_strategy_sanity(0u32..1u32, None); + } + + #[test] + fn signed_integer_binsearch_simplify_complicate_contract_upheld() { + check_strategy_sanity(0i32..1000i32, None); + check_strategy_sanity(0i32..1i32, None); + } + + #[test] + fn positive_float_simplifies_to_zero() { + let mut runner = TestRunner::default(); + let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap(); + + while value.simplify() { } + + assert_eq!(0.0, value.current()); + } + + #[test] + fn positive_float_simplifies_to_base() { + let mut runner = TestRunner::default(); + let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); + + while value.simplify() { } + + assert_eq!(1.0, value.current()); + } + + #[test] + fn negative_float_simplifies_to_zero() { + let mut runner = TestRunner::default(); + let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap(); + + while value.simplify() { } + + assert_eq!(0.0, value.current()); + } + + #[test] + fn positive_float_complicates_to_original() { + let mut runner = TestRunner::default(); + let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); + let orig = value.current(); + + assert!(value.simplify()); + while value.complicate() { } + + assert_eq!(orig, value.current()); + } + + #[test] + fn positive_infinity_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::INFINITY); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert_eq!(::std::f64::INFINITY, value.current()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn negative_infinity_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert_eq!(::std::f64::NEG_INFINITY, value.current()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn nan_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::NAN); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert!(value.current().is_nan()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn float_simplifies_to_smallest_normal() { + let mut runner = TestRunner::default(); + let mut value = (::std::f64::MIN_POSITIVE..2.0) + .new_tree(&mut runner).unwrap(); + + while value.simplify() { } + + assert_eq!(::std::f64::MIN_POSITIVE, value.current()); + } + + macro_rules! float_generation_test_body { + ($strategy:ident, $typ:ident) => { + use std::num::FpCategory; + + let strategy = $strategy; + let bits = strategy.normal_bits(); + + let mut seen_positive = 0; + let mut seen_negative = 0; + let mut seen_normal = 0; + let mut seen_subnormal = 0; + let mut seen_zero = 0; + let mut seen_infinite = 0; + let mut seen_quiet_nan = 0; + let mut seen_signaling_nan = 0; + let mut runner = TestRunner::default(); + + // Check whether this version of Rust honours the NaN payload in + // from_bits + let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits(); + let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits(); + let nan_fidelity = fidelity_1 != fidelity_2; + + for _ in 0..1024 { + let mut tree = strategy.new_tree(&mut runner).unwrap(); + let mut increment = 1; + + loop { + let value = tree.current(); + + let sign = value.signum(); // So we correctly handle -0 + if sign < 0.0 { + prop_assert!(bits.contains(FloatTypes::NEGATIVE)); + seen_negative += increment; + } else if sign > 0.0 { // i.e., not NaN + prop_assert!(bits.contains(FloatTypes::POSITIVE)); + seen_positive += increment; + } + + match value.classify() { + FpCategory::Nan if nan_fidelity => { + let raw = value.to_bits(); + let is_negative = raw << 1 >> 1 != raw; + if is_negative { + prop_assert!( + bits.contains(FloatTypes::NEGATIVE)); + seen_negative += increment; + } else { + prop_assert!( + bits.contains(FloatTypes::POSITIVE)); + seen_positive += increment; + } + + let is_quiet = + raw & ($typ::EXP_MASK >> 1) == + ::std::$typ::NAN.to_bits() & ($typ::EXP_MASK >> 1); + if is_quiet { + // x86/AMD64 turn signalling NaNs into quiet + // NaNs quite aggressively depending on what + // registers LLVM decides to use to pass the + // value around, so accept either case here. + prop_assert!( + bits.contains(FloatTypes::QUIET_NAN) || + bits.contains(FloatTypes::SIGNALING_NAN)); + seen_quiet_nan += increment; + seen_signaling_nan += increment; + } else { + prop_assert!( + bits.contains(FloatTypes::SIGNALING_NAN)); + seen_signaling_nan += increment; + } + }, + + FpCategory::Nan => { + // Since safe Rust doesn't currently allow + // generating any NaN other than one particular + // payload, don't check the sign or signallingness + // and consider this to be both signs and + // signallingness for counting purposes. + seen_positive += increment; + seen_negative += increment; + seen_quiet_nan += increment; + seen_signaling_nan += increment; + prop_assert!( + bits.contains(FloatTypes::QUIET_NAN) || + bits.contains(FloatTypes::SIGNALING_NAN)); + }, + FpCategory::Infinite => { + prop_assert!(bits.contains(FloatTypes::INFINITE)); + seen_infinite += increment; + }, + FpCategory::Zero => { + prop_assert!(bits.contains(FloatTypes::ZERO)); + seen_zero += increment; + }, + FpCategory::Subnormal => { + prop_assert!(bits.contains(FloatTypes::SUBNORMAL)); + seen_subnormal += increment; + }, + FpCategory::Normal => { + prop_assert!(bits.contains(FloatTypes::NORMAL)); + seen_normal += increment; + }, + } + + // Don't count simplified values towards the counts + increment = 0; + if !tree.simplify() { break; } + } + } + + if bits.contains(FloatTypes::POSITIVE) { + prop_assert!(seen_positive > 200); + } + if bits.contains(FloatTypes::NEGATIVE) { + prop_assert!(seen_negative > 200); + } + if bits.contains(FloatTypes::NORMAL) { + prop_assert!(seen_normal > 100); + } + if bits.contains(FloatTypes::SUBNORMAL) { + prop_assert!(seen_subnormal > 5); + } + if bits.contains(FloatTypes::ZERO) { + prop_assert!(seen_zero > 5); + } + if bits.contains(FloatTypes::INFINITE) { + prop_assert!(seen_infinite > 0); + } + if bits.contains(FloatTypes::QUIET_NAN) { + prop_assert!(seen_quiet_nan > 0); + } + if bits.contains(FloatTypes::SIGNALING_NAN) { + prop_assert!(seen_signaling_nan > 0); + } + } + } + + proptest! { + #![proptest_config(::test_runner::Config::with_cases(1024))] + + #[test] + fn f32_any_generates_desired_values( + strategy in ::bits::u32::ANY.prop_map(f32::Any::from_bits) + ) { + float_generation_test_body!(strategy, f32); + } + + #[test] + fn f32_any_sanity( + strategy in ::bits::u32::ANY.prop_map(f32::Any::from_bits) + ) { + check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } + + #[test] + fn f64_any_generates_desired_values( + strategy in ::bits::u32::ANY.prop_map(f64::Any::from_bits) + ) { + float_generation_test_body!(strategy, f64); + } + + #[test] + fn f64_any_sanity( + strategy in ::bits::u32::ANY.prop_map(f64::Any::from_bits) + ) { + check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } + } +} diff --git a/proptest/src/option.rs b/proptest/src/option.rs new file mode 100644 index 000000000..78f1be615 --- /dev/null +++ b/proptest/src/option.rs @@ -0,0 +1,234 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `std::Option` values. + +#![cfg_attr(feature="cargo-clippy", allow(expl_impl_clone_on_copy))] + +use core::fmt; +use core::marker::PhantomData; + +use strategy::*; +use test_runner::*; + +//============================================================================== +// Probability +//============================================================================== + +/// Creates a `Probability` from some value that is convertible into it. +/// +/// # Panics +/// +/// Panics if the converted to probability would lie +/// outside interval `[0.0, 1.0]`. Consult the `Into` (or `From`) +/// implementations for more details. +pub fn prob(from: impl Into) -> Probability { + from.into() +} + +impl Default for Probability { + /// The default probability is 0.5, or 50% chance. + fn default() -> Self { prob(0.5) } +} + +impl From for Probability { + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + fn from(prob: f64) -> Self { + Probability::new(prob) + } +} + +impl Probability { + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + pub fn new(prob: f64) -> Self { + assert!(prob >= 0.0 && prob <= 1.0); + Probability(prob) + } + + // Don't rely on these existing internally: + + /// Merges self together with some other argument producing a product + /// type expected by some impelementations of `A: Arbitrary` in + /// `A::Parameters`. This can be more ergonomic to work with and may + /// help type inference. + pub fn with(self, and: X) -> product_type![Self, X] { + product_pack![self, and] + } + + /// Merges self together with some other argument generated with a + /// default value producing a product type expected by some + /// impelementations of `A: Arbitrary` in `A::Parameters`. + /// This can be more ergonomic to work with and may help type inference. + pub fn lift(self) -> product_type![Self, X] { + self.with(Default::default()) + } +} + +#[cfg(feature = "frunk")] +use frunk_core::generic::Generic; + +#[cfg(feature = "frunk")] +impl Generic for Probability { + type Repr = f64; + + /// Converts the `Probability` into an `f64`. + fn into(self) -> Self::Repr { self.0 } + + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + fn from(r: Self::Repr) -> Self { r.into() } +} + +impl From for f64 { + fn from(p: Probability) -> Self { p.0 } +} + +/// A probability in the range `[0.0, 1.0]` with a default of `0.5`. +#[derive(Clone, Copy, PartialEq, Debug)] +pub struct Probability(f64); + +//============================================================================== +// Strategies for Option +//============================================================================== + +mapfn! { + [] fn WrapSome[](t: T) -> Option { + Some(t) + } +} + +#[must_use = "strategies do nothing unless used"] +struct NoneStrategy(PhantomData); +impl Clone for NoneStrategy { + fn clone(&self) -> Self { *self } +} +impl Copy for NoneStrategy { } +impl fmt::Debug for NoneStrategy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NoneStrategy") + } +} +impl Strategy for NoneStrategy { + type Tree = Self; + type Value = Option; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + Ok(*self) + } +} +impl ValueTree for NoneStrategy { + type Value = Option; + + fn current(&self) -> Option { None } + fn simplify(&mut self) -> bool { false } + fn complicate(&mut self) -> bool { false } +} + +opaque_strategy_wrapper! { + /// Strategy which generates `Option` values whose inner `Some` values are + /// generated by another strategy. + /// + /// Constructed by other functions in this module. + #[derive(Clone)] + pub struct OptionStrategy[][where T : Strategy] + (TupleUnion<(W>, + W>)>) + -> OptionValueTree; + /// `ValueTree` type corresponding to `OptionStrategy`. + #[derive(Clone, Debug)] + pub struct OptionValueTree[][where T : ValueTree] + (TupleUnionValueTree<(NoneStrategy, + Option>)>) + -> Option; +} + +// XXX Unclear why this is necessary; #[derive(Debug)] *should* generate +// exactly this, but for some reason it adds a `T::Value : Debug` constraint as +// well. +impl fmt::Debug for OptionStrategy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OptionStrategy({:?})", self.0) + } +} + +/// Return a strategy producing `Optional` values wrapping values from the +/// given delegate strategy. +/// +/// `Some` values shrink to `None`. +/// +/// `Some` and `None` are each chosen with 50% probability. +pub fn of(t: T) -> OptionStrategy { + weighted(Probability::default(), t) +} + +/// Return a strategy producing `Optional` values wrapping values from the +/// given delegate strategy. +/// +/// `Some` values shrink to `None`. +/// +/// `Some` is chosen with a probability given by `probability_of_some`, which +/// must be between 0.0 and 1.0, both exclusive. +pub fn weighted + (probability_of_some: impl Into, t: T) -> OptionStrategy +{ + let prob = probability_of_some.into().into(); + let (weight_some, weight_none) = float_to_weight(prob); + + OptionStrategy(TupleUnion::new(( + (weight_none, NoneStrategy(PhantomData)), + (weight_some, statics::Map::new(t, WrapSome)), + ))) +} + +#[cfg(test)] +mod test { + use super::*; + + fn count_some_of_1000(s: OptionStrategy>) -> u32 { + let mut runner = TestRunner::default(); + let mut count = 0; + for _ in 0..1000 { + count += s.new_tree(&mut runner).unwrap() + .current().is_some() as u32; + } + + count + } + + #[test] + fn probability_defaults_to_0p5() { + let count = count_some_of_1000(of(Just(42i32))); + assert!(count > 450 && count < 550); + } + + #[test] + fn probability_handled_correctly() { + let count = count_some_of_1000(weighted(0.9, Just(42i32))); + assert!(count > 800 && count < 950); + + let count = count_some_of_1000(weighted(0.1, Just(42i32))); + assert!(count > 50 && count < 150); + } + + #[test] + fn test_sanity() { + check_strategy_sanity(of(0i32..1000i32), None); + } +} diff --git a/proptest/src/prelude.rs b/proptest/src/prelude.rs new file mode 100644 index 000000000..7f3d9a2c0 --- /dev/null +++ b/proptest/src/prelude.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Re-exports the most commonly-needed APIs of proptest. +//! +//! This module is intended to be wildcard-imported, i.e., +//! `use proptest::prelude::*;`. Note that it re-exports the whole crate itself +//! under the name `prop`, so you don't need a separate `use proptest;` line. +//! +//! In addition to Proptest's own APIs, this also reexports a small portion of +//! the `rand` crate sufficient to easily use `prop_perturb` and other +//! functionality that exposes random number generators. Please note that this +//! is will always be a direct reexport; using these in preference to using the +//! `rand` crate directly will not provide insulation from the upcoming +//! revision to the `rand` crate. + +pub use strategy::{BoxedStrategy, Just, SBoxedStrategy, Strategy}; +pub use arbitrary::{Arbitrary, any, any_with}; +pub use test_runner::Config as ProptestConfig; +pub use test_runner::TestCaseError; + +pub use rand::{RngCore, Rng}; + +/// Re-exports the entire public API of proptest so that an import of `prelude` +/// allows simply writing, for example, `prop::num::i32::ANY` rather than +/// `proptest::num::i32::ANY` plus a separate `use proptest;`. +pub mod prop { + pub use test_runner; + pub use strategy; + pub use arbitrary; + pub use bool; + pub use num; + pub use bits; + pub use tuple; + pub use array; + pub use collection; + pub use char; + #[cfg(feature = "std")] + pub use string; + pub use option; + pub use result; + pub use sample; +} diff --git a/proptest/src/product_frunk.rs b/proptest/src/product_frunk.rs new file mode 100644 index 000000000..9f37f565f --- /dev/null +++ b/proptest/src/product_frunk.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines macros for product type creation, extraction, and the type signature +//! itself. This version uses `frunk_core`. This mechanism is used to be very +//! loosely coupled with `frunk_core` so that only `lib.rs` has to be changed +//! in the event that Rust gets tuple-varadic generics. + +macro_rules! product_type { + ($factor: ty) => { + Hlist![$factor] + }; + ($($factor: ty),*) => { + Hlist![$( $factor, )*] + }; + ($($factor: ty),*,) => { + Hlist![$( $factor, )*] + }; +} + +macro_rules! product_pack { + ($factor: expr) => { + hlist![$factor] + }; + ($($factor: expr),*) => { + hlist![$( $factor ),*] + }; + ($($factor: expr),*,) => { + hlist![$( $factor ),*] + }; +} + +macro_rules! product_unpack { + ($factor: pat) => { + hlist_pat![$factor] + }; + ($($factor: pat),*) => { + hlist_pat![$( $factor ),*] + }; + ($($factor: pat),*,) => { + hlist_pat![$( $factor ),*] + }; +} diff --git a/proptest/src/product_tuple.rs b/proptest/src/product_tuple.rs new file mode 100644 index 000000000..c684938dc --- /dev/null +++ b/proptest/src/product_tuple.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines macros for product type creation, extraction, and the type signature +//! itself. This version uses tuples. This mechanism is used to be very +//! loosely coupled with `frunk_core` so that only `lib.rs` has to be changed +//! in the event that Rust gets tuple-varadic generics. + +macro_rules! product_type { + ($factor: ty) => { + ($factor,) + }; + ($($factor: ty),*) => { + ( $( $factor, )* ) + }; + ($($factor: ty),*,) => { + ( $( $factor, )* ) + }; +} + +macro_rules! product_pack { + ($factor: expr) => { + ($factor,) + }; + ($($factor: expr),*) => { + ( $( $factor ),* ) + }; + ($($factor: expr),*,) => { + ( $( $factor ),* ) + }; +} + +macro_rules! product_unpack { + ($factor: pat) => { + ($factor,) + }; + ($($factor: pat),*) => { + ( $( $factor ),* ) + }; + ($($factor: pat),*,) => { + ( $( $factor ),* ) + }; +} diff --git a/proptest/src/regex-contrib/README.md b/proptest/src/regex-contrib/README.md new file mode 100644 index 000000000..f438d2047 --- /dev/null +++ b/proptest/src/regex-contrib/README.md @@ -0,0 +1,3 @@ +Files in this directory are copied verbatim from the +https://github.com/rust-lang/regex repository and are used for generating test +data. They do not become part of the proptest binary. diff --git a/proptest/src/regex-contrib/crates_regex.rs b/proptest/src/regex-contrib/crates_regex.rs new file mode 100644 index 000000000..1ccfe4710 --- /dev/null +++ b/proptest/src/regex-contrib/crates_regex.rs @@ -0,0 +1,3129 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// DO NOT EDIT. Automatically generated by 'scripts/scrape_crates_io.py' +// on 2018-06-20 09:56:32.820354. + + + +// autoshutdown-0.1.0: r"\s*(\d+)(\w)\s*" +consistent!(autoshutdown_0, r"\s*(\d+)(\w)\s*"); + +// epub-1.1.1: r"/" +consistent!(epub_0, r"/"); + +// rpi-info-0.2.0: "^Revision\t+: ([0-9a-fA-F]+)" +consistent!(rpi_info_0, "^Revision\t+: ([0-9a-fA-F]+)"); + +// rpi-info-0.2.0: "Serial\t+: ([0-9a-fA-F]+)" +consistent!(rpi_info_1, "Serial\t+: ([0-9a-fA-F]+)"); + +// pnet_macros-0.21.0: r"^u([0-9]+)(be|le|he)?$" +consistent!(pnet_macros_0, r"^u([0-9]+)(be|le|he)?$"); + +// iban_validate-1.0.3: r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$" +consistent!(iban_validate_0, r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$"); + +// markifier-0.1.0: r".*\[(?P.+)%.*\].*" +consistent!(markifier_0, r".*\[(?P.+)%.*\].*"); + +// mallumo-0.3.0: r"(#include) (\S*)(.*)" +consistent!(mallumo_0, r"(#include) (\S*)(.*)"); + +// mallumo-0.3.0: r"(ERROR: \d+:)(\d+)(: )(.+)" +consistent!(mallumo_1, r"(ERROR: \d+:)(\d+)(: )(.+)"); + +// mallumo-0.3.0: r"(\d+\()(\d+)(?:\) : )(.+)" +consistent!(mallumo_2, r"(\d+\()(\d+)(?:\) : )(.+)"); + +// magnet_more-0.0.1: r"(.+?)(\[.*?\])?" +consistent!(magnet_more_0, r"(.+?)(\[.*?\])?"); + +// magnet_app-0.0.1: r":(?P[a-zA-Z_]+)" +consistent!(magnet_app_0, r":(?P[a-zA-Z_]+)"); + +// yubibomb-0.2.0: r"^\d{6}(?:\s*,\s*\d{6})*$" +consistent!(yubibomb_0, r"^\d{6}(?:\s*,\s*\d{6})*$"); + +// multirust-rs-0.0.4: r"[\\/]([^\\/?]+)(\?.*)?$" +consistent!(multirust_rs_0, r"[\\/]([^\\/?]+)(\?.*)?$"); + +// hueclient-0.3.2: "\"[a-z]*\":null" +consistent!(hueclient_0, "\"[a-z]*\":null"); + +// hueclient-0.3.2: ",+" +consistent!(hueclient_1, ",+"); + +// hueclient-0.3.2: ",\\}" +consistent!(hueclient_2, ",\\}"); + +// hueclient-0.3.2: "\\{," +consistent!(hueclient_3, "\\{,"); + +// aerial-0.1.0: r"[a-zA-Z_\$][a-zA-Z_0-9]*" +consistent!(aerial_0, r"[a-zA-Z_\$][a-zA-Z_0-9]*"); + +// aerial-0.1.0: r"thi[sng]+" +consistent!(aerial_1, r"thi[sng]+"); + +// rvue-0.1.0: r"(.+)\s+\((.+?)\)" +consistent!(rvue_0, r"(.+)\s+\((.+?)\)"); + +// rvue-0.1.0: r"([\d\.]+)\s*out\s*of\s*([\d\.]+)" +consistent!(rvue_1, r"([\d\.]+)\s*out\s*of\s*([\d\.]+)"); + +// rvue-0.1.0: r"^([\d\.]+)\s*(?:\(\))?$" +consistent!(rvue_2, r"^([\d\.]+)\s*(?:\(\))?$"); + +// rvue-0.1.0: r"([\d\.]+)\s*Points\s*Possible" +consistent!(rvue_3, r"([\d\.]+)\s*Points\s*Possible"); + +// rvue-0.1.0: r"([\d\.]+)\s*/\s*([\d\.]+)" +consistent!(rvue_4, r"([\d\.]+)\s*/\s*([\d\.]+)"); + +// rvsim-0.1.0: r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]" +consistent!(rvsim_0, r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]"); + +// nereon-0.1.4: "(.*[^\\\\])\\{\\}(.*)" +consistent!(nereon_0, "(.*[^\\\\])\\{\\}(.*)"); + +// next_episode-0.3.0: r"((?i)^(.+).s(\d+)e(\d+).*)$" +consistent!(next_episode_0, r"((?i)^(.+).s(\d+)e(\d+).*)$"); + +// migrant_lib-0.19.2: r"[^a-z0-9-]+" +consistent!(migrant_lib_0, r"[^a-z0-9-]+"); + +// migrant_lib-0.19.2: r"[0-9]{14}_[a-z0-9-]+" +consistent!(migrant_lib_1, r"[0-9]{14}_[a-z0-9-]+"); + +// migrant_lib-0.19.2: r"([0-9]{14}_)?[a-z0-9-]+" +consistent!(migrant_lib_2, r"([0-9]{14}_)?[a-z0-9-]+"); + +// minipre-0.2.0: "$_" +consistent!(minipre_0, "$_"); + +// minifier-0.0.13: r">\s+<" +consistent!(minifier_0, r">\s+<"); + +// minifier-0.0.13: r"\s{2,}|[\r\n]" +consistent!(minifier_1, r"\s{2,}|[\r\n]"); + +// minifier-0.0.13: r"<(style|script)[\w|\s].*?>" +consistent!(minifier_2, r"<(style|script)[\w|\s].*?>"); + +// minifier-0.0.13: "" +consistent!(minifier_3, ""); + +// minifier-0.0.13: r"<\w.*?>" +consistent!(minifier_4, r"<\w.*?>"); + +// minifier-0.0.13: r" \s+|\s +" +consistent!(minifier_5, r" \s+|\s +"); + +// minifier-0.0.13: r"\w\s+\w" +consistent!(minifier_6, r"\w\s+\w"); + +// minifier-0.0.13: r"'\s+>" +consistent!(minifier_7, r"'\s+>"); + +// minifier-0.0.13: r"\d\s+>" +consistent!(minifier_8, r"\d\s+>"); + +// ggp-rs-0.1.2: r"(?P\([^)]+\))|(?P[a-zA-Z0-9_]+)" +consistent!(ggp_rs_0, r"(?P\([^)]+\))|(?P[a-zA-Z0-9_]+)"); + +// ggp-rs-0.1.2: r"\((.*)\)." +consistent!(ggp_rs_1, r"\((.*)\)."); + +// poe-superfilter-0.2.0: "[A-Za-z0-9_]" +consistent!(poe_superfilter_0, "[A-Za-z0-9_]"); + +// poke-a-mango-0.5.0: r"(\d+)x(\d+)" +consistent!(poke_a_mango_0, r"(\d+)x(\d+)"); + +// pop3-rs-0.1.0: r"(?P\d+) (?P\d+)" +consistent!(pop3_rs_0, r"(?P\d+) (?P\d+)"); + +// pop3-rs-0.1.0: r"(?P\d+) (?P[\x21-\x7E]{1,70})" +consistent!(pop3_rs_1, r"(?P\d+) (?P[\x21-\x7E]{1,70})"); + +// pop3-rs-0.1.0: r"(<.*>)\r\n$" +consistent!(pop3_rs_2, r"(<.*>)\r\n$"); + +// pop3-rs-0.1.0: r"^(?P\+OK|-ERR) (?P.*)" +consistent!(pop3_rs_3, r"^(?P\+OK|-ERR) (?P.*)"); + +// pop3-1.0.6: r"^\.\r\n$" +consistent!(pop3_0, r"^\.\r\n$"); + +// pop3-1.0.6: r"\+OK(.*)" +consistent!(pop3_1, r"\+OK(.*)"); + +// pop3-1.0.6: r"-ERR(.*)" +consistent!(pop3_2, r"-ERR(.*)"); + +// pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" +consistent!(pop3_3, r"\+OK (\d+) (\d+)\r\n"); + +// pop3-1.0.6: r"(\d+) ([\x21-\x7e]+)\r\n" +consistent!(pop3_4, r"(\d+) ([\x21-\x7e]+)\r\n"); + +// pop3-1.0.6: r"\+OK (\d+) ([\x21-\x7e]+)\r\n" +consistent!(pop3_5, r"\+OK (\d+) ([\x21-\x7e]+)\r\n"); + +// pop3-1.0.6: r"(\d+) (\d+)\r\n" +consistent!(pop3_6, r"(\d+) (\d+)\r\n"); + +// pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" +consistent!(pop3_7, r"\+OK (\d+) (\d+)\r\n"); + +// polk-1.1.3: "github:(\\w+)/?(\\w+)?" +consistent!(polk_0, "github:(\\w+)/?(\\w+)?"); + +// geochunk-0.1.5: "^[0-9]{5}" +consistent!(geochunk_0, "^[0-9]{5}"); + +// generic-dns-update-1.1.4: r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))" +consistent!(generic_dns_update_0, r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))"); + +// generic-dns-update-1.1.4: r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))" +consistent!(generic_dns_update_1, r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))"); + +// generic-dns-update-1.1.4: r"([0-9.]*)" +consistent!(generic_dns_update_2, r"([0-9.]*)"); + +// generic-dns-update-1.1.4: r"([0-9]+)" +consistent!(generic_dns_update_3, r"([0-9]+)"); + +// generic-dns-update-1.1.4: r"([0-9]+)" +consistent!(generic_dns_update_4, r"([0-9]+)"); + +// generic-dns-update-1.1.4: r"([0-1]*)" +consistent!(generic_dns_update_5, r"([0-1]*)"); + +// generate-nix-pkg-0.3.0: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(generate_nix_pkg_0, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// generate-nix-pkg-0.3.0: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(generate_nix_pkg_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// genact-0.6.0: r"arch/([a-z0-9_])+/" +consistent!(genact_0, r"arch/([a-z0-9_])+/"); + +// genact-0.6.0: r"arch/([a-z0-9_])+/" +consistent!(genact_1, r"arch/([a-z0-9_])+/"); + +// cron_rs-0.1.6: r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$" +consistent!(cron_rs_0, r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$"); + +// systemfd-0.3.0: r"^([a-zA-Z]+)::(.+)$" +consistent!(systemfd_0, r"^([a-zA-Z]+)::(.+)$"); + +// symbolic-debuginfo-5.0.2: "__?hidden#\\d+_" +consistent!(symbolic_debuginfo_0, "__?hidden#\\d+_"); + +// symbolic-minidump-5.0.2: r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$" +consistent!(symbolic_minidump_0, r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$"); + +// graphql-idl-parser-0.1.1: "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" +consistent!(graphql_idl_parser_0, "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); + +// graphql-idl-parser-0.1.1: "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" +consistent!(graphql_idl_parser_1, "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); + +// graphql-idl-parser-0.1.1: "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*" +consistent!(graphql_idl_parser_2, "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*"); + +// graphql-idl-parser-0.1.1: "^(?u:!)" +consistent!(graphql_idl_parser_3, "^(?u:!)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\()" +consistent!(graphql_idl_parser_4, "^(?u:\\()"); + +// graphql-idl-parser-0.1.1: "^(?u:\\))" +consistent!(graphql_idl_parser_5, "^(?u:\\))"); + +// graphql-idl-parser-0.1.1: "^(?u:,)" +consistent!(graphql_idl_parser_6, "^(?u:,)"); + +// graphql-idl-parser-0.1.1: "^(?u::)" +consistent!(graphql_idl_parser_7, "^(?u::)"); + +// graphql-idl-parser-0.1.1: "^(?u:@)" +consistent!(graphql_idl_parser_8, "^(?u:@)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\[)" +consistent!(graphql_idl_parser_9, "^(?u:\\[)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\])" +consistent!(graphql_idl_parser_10, "^(?u:\\])"); + +// graphql-idl-parser-0.1.1: "^(?u:enum)" +consistent!(graphql_idl_parser_11, "^(?u:enum)"); + +// graphql-idl-parser-0.1.1: "^(?u:implements)" +consistent!(graphql_idl_parser_12, "^(?u:implements)"); + +// graphql-idl-parser-0.1.1: "^(?u:input)" +consistent!(graphql_idl_parser_13, "^(?u:input)"); + +// graphql-idl-parser-0.1.1: "^(?u:interface)" +consistent!(graphql_idl_parser_14, "^(?u:interface)"); + +// graphql-idl-parser-0.1.1: "^(?u:scalar)" +consistent!(graphql_idl_parser_15, "^(?u:scalar)"); + +// graphql-idl-parser-0.1.1: "^(?u:type)" +consistent!(graphql_idl_parser_16, "^(?u:type)"); + +// graphql-idl-parser-0.1.1: "^(?u:union)" +consistent!(graphql_idl_parser_17, "^(?u:union)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\{)" +consistent!(graphql_idl_parser_18, "^(?u:\\{)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\})" +consistent!(graphql_idl_parser_19, "^(?u:\\})"); + +// grimoire-0.1.0: r"(?s)/\*(?P.*?)\*/" +consistent!(grimoire_0, r"(?s)/\*(?P.*?)\*/"); + +// phonenumber-0.2.0+8.9.0: r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?" +consistent!(phonenumber_0, r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?"); + +// phonenumber-0.2.0+8.9.0: r"[, \[\]]" +consistent!(phonenumber_1, r"[, \[\]]"); + +// phonenumber-0.2.0+8.9.0: r"[\\/] *x" +consistent!(phonenumber_2, r"[\\/] *x"); + +// phonenumber-0.2.0+8.9.0: r"[[\P{N}&&\P{L}]&&[^#]]+$" +consistent!(phonenumber_3, r"[[\P{N}&&\P{L}]&&[^#]]+$"); + +// phonenumber-0.2.0+8.9.0: r"(?:.*?[A-Za-z]){3}.*" +consistent!(phonenumber_4, r"(?:.*?[A-Za-z]){3}.*"); + +// phonenumber-0.2.0+8.9.0: r"(\D+)" +consistent!(phonenumber_5, r"(\D+)"); + +// phonenumber-0.2.0+8.9.0: r"(\$\d)" +consistent!(phonenumber_6, r"(\$\d)"); + +// phonenumber-0.2.0+8.9.0: r"\(?\$1\)?" +consistent!(phonenumber_7, r"\(?\$1\)?"); + +// phone_number-0.1.0: r"\D" +consistent!(phone_number_0, r"\D"); + +// phone_number-0.1.0: r"^0+" +consistent!(phone_number_1, r"^0+"); + +// phone_number-0.1.0: r"^89" +consistent!(phone_number_2, r"^89"); + +// phone_number-0.1.0: r"^8+" +consistent!(phone_number_3, r"^8+"); + +// phile-0.1.4: r"^ *(\^_*\^) *$" +consistent!(phile_0, r"^ *(\^_*\^) *$"); + +// phile-0.1.4: r"^[_\p{XID_Start}]$" +consistent!(phile_1, r"^[_\p{XID_Start}]$"); + +// phile-0.1.4: r"^\p{XID_Continue}$" +consistent!(phile_2, r"^\p{XID_Continue}$"); + +// uritemplate-0.1.2: "%25(?P[0-9a-fA-F][0-9a-fA-F])" +consistent!(uritemplate_0, "%25(?P[0-9a-fA-F][0-9a-fA-F])"); + +// urdf-rs-0.4.2: "^package://(\\w+)/" +consistent!(urdf_rs_0, "^package://(\\w+)/"); + +// url-match-0.1.7: r"(?P[?&.])" +consistent!(url_match_0, r"(?P[?&.])"); + +// url-match-0.1.7: r":(?P[a-zA-Z0-9_-]+)" +consistent!(url_match_1, r":(?P[a-zA-Z0-9_-]+)"); + +// tsm-sys-0.1.0: r"hello world" +consistent!(tsm_sys_0, r"hello world"); + +// deb-version-0.1.0: "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$" +consistent!(deb_version_0, "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$"); + +// debcargo-2.1.0: r"^(?i)(a|an|the)\s+" +consistent!(debcargo_0, r"^(?i)(a|an|the)\s+"); + +// debcargo-2.1.0: r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+" +consistent!(debcargo_1, r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+"); + +// feaders-0.2.0: r"^.*\.h$" +consistent!(feaders_0, r"^.*\.h$"); + +// feaders-0.2.0: r"^.*\.c$" +consistent!(feaders_1, r"^.*\.c$"); + +// feaders-0.2.0: r"^.*\.hpp$" +consistent!(feaders_2, r"^.*\.hpp$"); + +// feaders-0.2.0: r"^.*\.cc$" +consistent!(feaders_3, r"^.*\.cc$"); + +// feaders-0.2.0: r"^.*\.cpp$" +consistent!(feaders_4, r"^.*\.cpp$"); + +// hyperscan-0.1.6: r"CPtr\(\w+\)" +consistent!(hyperscan_0, r"CPtr\(\w+\)"); + +// hyperscan-0.1.6: r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$" +consistent!(hyperscan_1, r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$"); + +// hyperscan-0.1.6: r"RawDatabase\{db: \w+\}" +consistent!(hyperscan_2, r"RawDatabase\{db: \w+\}"); + +// hyperscan-0.1.6: r"RawSerializedDatabase\{p: \w+, len: \d+\}" +consistent!(hyperscan_3, r"RawSerializedDatabase\{p: \w+, len: \d+\}"); + +// ucd-parse-0.1.1: r"[0-9A-F]+" +consistent!(ucd_parse_0, r"[0-9A-F]+"); + +// afsort-0.2.0: r".*" +consistent!(afsort_0, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_1, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_2, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_3, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_4, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_5, r".*"); + +// afsort-0.2.0: r"^[a-z]+$" +consistent!(afsort_6, r"^[a-z]+$"); + +// afsort-0.2.0: r"^[a-z]+$" +consistent!(afsort_7, r"^[a-z]+$"); + +// tin-summer-1.21.4: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(tin_summer_0, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// tin-drummer-1.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$" +consistent!(tin_drummer_1, r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$"); + +// tin-drummer-1.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|\.js)$" +consistent!(tin_drummer_3, r".*?\.(stats|conf|h|out|cache.*|\.js)$"); + +// tin-drummer-1.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(tin_drummer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// tin-drummer-1.0.1: r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_5, r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(ibc)$" +consistent!(tin_drummer_6, r".*?\.(ibc)$"); + +// tin-drummer-1.0.1: r"\.stack-work|dist-newstyle" +consistent!(tin_drummer_7, r"\.stack-work|dist-newstyle"); + +// timmy-0.3.0: r"_NET_WM_PID\(CARDINAL\) = (\d+)" +consistent!(timmy_0, r"_NET_WM_PID\(CARDINAL\) = (\d+)"); + +// timmy-0.3.0: r"today|yesterday|now" +consistent!(timmy_1, r"today|yesterday|now"); + +// timmy-0.3.0: r"(?P\d{1,2})/(?P\d{1,2})(/(?P\d{4}|\d{2}))?" +consistent!(timmy_2, r"(?P\d{1,2})/(?P\d{1,2})(/(?P\d{4}|\d{2}))?"); + +// timmy-0.3.0: r"(?P\d+) (days?|ds?)(?P( ago)?)" +consistent!(timmy_3, r"(?P\d+) (days?|ds?)(?P( ago)?)"); + +// timmy-0.3.0: r"(?P


\d{2}):(?P\d{2})" +consistent!(timmy_4, r"(?P
\d{2}):(?P\d{2})"); + +// tinfo-0.5.0: r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?" +consistent!(tinfo_0, r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?"); + +// tinfo-0.5.0: r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]" +consistent!(tinfo_1, r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]"); + +// timespan-0.0.4: r"(?:\\\{start\\\}|\\\{end\\\})" +consistent!(timespan_0, r"(?:\\\{start\\\}|\\\{end\\\})"); + +// timespan-0.0.4: r"(.*)\s+-\s+(.*)" +consistent!(timespan_1, r"(.*)\s+-\s+(.*)"); + +// timespan-0.0.4: r"(.*)\s+(\w+)$" +consistent!(timespan_2, r"(.*)\s+(\w+)$"); + +// timespan-0.0.4: r"(.*)\s+(\w+)$" +consistent!(timespan_3, r"(.*)\s+(\w+)$"); + +// timespan-0.0.4: r"(.*)\s+-\s+(.*)" +consistent!(timespan_4, r"(.*)\s+-\s+(.*)"); + +// titlecase-0.10.0: r"[[:lower:]]" +consistent!(titlecase_0, r"[[:lower:]]"); + +// tight-0.1.3: r"^\d+ (day|week|month|year)s?$" +consistent!(tight_0, r"^\d+ (day|week|month|year)s?$"); + +// tight-0.1.3: r"^\d+ (day|week|month|year)s?$" +consistent!(tight_1, r"^\d+ (day|week|month|year)s?$"); + +// yaml-0.2.1: r"^[-+]?(0|[1-9][0-9_]*)$" +consistent!(yaml_0, r"^[-+]?(0|[1-9][0-9_]*)$"); + +// yaml-0.2.1: r"^([-+]?)0o?([0-7_]+)$" +consistent!(yaml_1, r"^([-+]?)0o?([0-7_]+)$"); + +// yaml-0.2.1: r"^([-+]?)0x([0-9a-fA-F_]+)$" +consistent!(yaml_2, r"^([-+]?)0x([0-9a-fA-F_]+)$"); + +// yaml-0.2.1: r"^([-+]?)0b([0-1_]+)$" +consistent!(yaml_3, r"^([-+]?)0b([0-1_]+)$"); + +// yaml-0.2.1: r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$" +consistent!(yaml_4, r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$"); + +// yaml-0.2.1: r"^[+]?(\.inf|\.Inf|\.INF)$" +consistent!(yaml_5, r"^[+]?(\.inf|\.Inf|\.INF)$"); + +// yaml-0.2.1: r"^-(\.inf|\.Inf|\.INF)$" +consistent!(yaml_6, r"^-(\.inf|\.Inf|\.INF)$"); + +// yaml-0.2.1: r"^(\.nan|\.NaN|\.NAN)$" +consistent!(yaml_7, r"^(\.nan|\.NaN|\.NAN)$"); + +// yaml-0.2.1: r"^(null|Null|NULL|~)$" +consistent!(yaml_8, r"^(null|Null|NULL|~)$"); + +// yaml-0.2.1: r"^(true|True|TRUE|yes|Yes|YES)$" +consistent!(yaml_9, r"^(true|True|TRUE|yes|Yes|YES)$"); + +// yaml-0.2.1: r"^(false|False|FALSE|no|No|NO)$" +consistent!(yaml_10, r"^(false|False|FALSE|no|No|NO)$"); + +// kefia-0.1.0: r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$" +consistent!(kefia_0, r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$"); + +// risp-0.7.0: "^(\\s+|;.*?(\n|$))+" +consistent!(risp_0, "^(\\s+|;.*?(\n|$))+"); + +// risp-0.7.0: "^\".*?\"" +consistent!(risp_1, "^\".*?\""); + +// risp-0.7.0: r"^[^\s\{\}()\[\]]+" +consistent!(risp_2, r"^[^\s\{\}()\[\]]+"); + +// risp-0.7.0: r"^-?\d+" +consistent!(risp_3, r"^-?\d+"); + +// ripgrep-0.8.1: "^([0-9]+)([KMG])?$" +consistent!(ripgrep_0, "^([0-9]+)([KMG])?$"); + +// riquid-0.0.1: r"^\w+" +consistent!(riquid_0, r"^\w+"); + +// riquid-0.0.1: r"^\d+" +consistent!(riquid_1, r"^\d+"); + +// recursive_disassembler-2.1.2: r"\A(0x)?([a-fA-F0-9]+)\z" +consistent!(recursive_disassembler_0, r"\A(0x)?([a-fA-F0-9]+)\z"); + +// remake-0.1.0: r"^[a-zA-Z_][a-zA-Z0-9_]*" +consistent!(remake_0, r"^[a-zA-Z_][a-zA-Z0-9_]*"); + +// regex-decode-0.1.0: r"'(?P[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_0, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_1, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_2, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_3, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_4, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_5, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)" +consistent!(regex_decode_6, r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_7, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_8, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_9, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_10, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_11, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_12, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_13, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-cache-0.2.0: "[0-9]{3}-[0-9]{3}-[0-9]{4}" +consistent!(regex_cache_0, "[0-9]{3}-[0-9]{3}-[0-9]{4}"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_1, r"^\d+$"); + +// regex-cache-0.2.0: r"^[a-z]+$" +consistent!(regex_cache_2, r"^[a-z]+$"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_3, r"^\d+$"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_4, r"^\d+$"); + +// regex_dfa-0.5.0: r"\d{4}-\d{2}-\d{2}" +consistent!(regex_dfa_0, r"\d{4}-\d{2}-\d{2}"); + +// reaper-2.0.0: r"^[0-9\p{L} _\\.]{3,16}$" +consistent!(reaper_0, r"^[0-9\p{L} _\\.]{3,16}$"); + +// retdec-0.1.0: r"^attachment; filename=(.+)$" +consistent!(retdec_0, r"^attachment; filename=(.+)$"); + +// renvsubst-0.1.2: r"(\\)(?P<head>\$[0-9A-Za-z_{])" +consistent!(renvsubst_0, r"(\\)(?P<head>\$[0-9A-Za-z_{])"); + +// renvsubst-0.1.2: r"\$([[:word:]]+)" +consistent!(renvsubst_1, r"\$([[:word:]]+)"); + +// renvsubst-0.1.2: r"\$\{([[:word:]]+)\}" +consistent!(renvsubst_2, r"\$\{([[:word:]]+)\}"); + +// rexpect-0.3.0: r"'[a-z]+'" +consistent!(rexpect_0, r"'[a-z]+'"); + +// rexpect-0.3.0: r"^\d{4}-\d{2}-\d{2}$" +consistent!(rexpect_1, r"^\d{4}-\d{2}-\d{2}$"); + +// rexpect-0.3.0: r"-\d{2}-" +consistent!(rexpect_2, r"-\d{2}-"); + +// luther-0.1.0: "^a(b|c)c*$" +consistent!(luther_0, "^a(b|c)c*$"); + +// little_boxes-1.6.0: r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]" +consistent!(little_boxes_0, r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]"); + +// libimagentrytag-0.8.0: "^[a-zA-Z]([a-zA-Z0-9_-]*)$" +consistent!(libimagentrytag_0, "^[a-zA-Z]([a-zA-Z0-9_-]*)$"); + +// libimaginteraction-0.8.0: r"^[Yy](\n?)$" +consistent!(libimaginteraction_0, r"^[Yy](\n?)$"); + +// libimaginteraction-0.8.0: r"^[Nn](\n?)$" +consistent!(libimaginteraction_1, r"^[Nn](\n?)$"); + +// libimagutil-0.8.0: "^(?P<KEY>([^=]*))=(.*)$" +consistent!(libimagutil_0, "^(?P<KEY>([^=]*))=(.*)$"); + +// libimagutil-0.8.0: "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$" +consistent!(libimagutil_1, "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$"); + +// linux_ip-0.1.0: r"\s+" +consistent!(linux_ip_0, r"\s+"); + +// linux_ip-0.1.0: r"\s*[\n\r]+\s*" +consistent!(linux_ip_1, r"\s*[\n\r]+\s*"); + +// linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" +consistent!(linux_ip_2, r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); + +// linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" +consistent!(linux_ip_3, r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); + +// linux_ip-0.1.0: r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$" +consistent!(linux_ip_4, r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$"); + +// linux_ip-0.1.0: r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$" +consistent!(linux_ip_5, r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$"); + +// linux_ip-0.1.0: r"\s*[\n\r]+\s*" +consistent!(linux_ip_6, r"\s*[\n\r]+\s*"); + +// linux_ip-0.1.0: r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$" +consistent!(linux_ip_7, r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$"); + +// linux_ip-0.1.0: r"\s*link/ether\s+([a-f0-9:]+)\s+.*" +consistent!(linux_ip_8, r"\s*link/ether\s+([a-f0-9:]+)\s+.*"); + +// linux_ip-0.1.0: r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*" +consistent!(linux_ip_9, r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*"); + +// linky-0.1.4: r"[^\w -]" +consistent!(linky_0, r"[^\w -]"); + +// linky-0.1.4: r"^(.*):(\d+): [^ ]* ([^ ]*)$" +consistent!(linky_1, r"^(.*):(\d+): [^ ]* ([^ ]*)$"); + +// limonite-0.2.1: r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$" +consistent!(limonite_0, r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$"); + +// process-queue-0.1.1: r"^[a-zA-Z]+$" +consistent!(process_queue_0, r"^[a-zA-Z]+$"); + +// pronghorn-0.1.2: r"^\{([a-zA-Z_]+)\}$" +consistent!(pronghorn_0, r"^\{([a-zA-Z_]+)\}$"); + +// protocol-ftp-client-0.1.1: "(?m:^(\\d{3}) (.+)\r$)" +consistent!(protocol_ftp_client_0, "(?m:^(\\d{3}) (.+)\r$)"); + +// protocol-ftp-client-0.1.1: "\"(.+)\"" +consistent!(protocol_ftp_client_1, "\"(.+)\""); + +// protocol-ftp-client-0.1.1: "(\\w+) [Tt]ype: (\\w+)" +consistent!(protocol_ftp_client_2, "(\\w+) [Tt]ype: (\\w+)"); + +// protocol-ftp-client-0.1.1: "(?m:^(\\d{3})-.+\r$)" +consistent!(protocol_ftp_client_3, "(?m:^(\\d{3})-.+\r$)"); + +// protocol-ftp-client-0.1.1: "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)" +consistent!(protocol_ftp_client_4, "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)"); + +// protocol-ftp-client-0.1.1: "(?m:^(.+)\r$)" +consistent!(protocol_ftp_client_5, "(?m:^(.+)\r$)"); + +// protocol-ftp-client-0.1.1: "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$" +consistent!(protocol_ftp_client_6, "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$"); + +// article-date-extractor-0.1.1: r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})" +consistent!(article_date_extractor_0, r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})"); + +// article-date-extractor-0.1.1: r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date" +consistent!(article_date_extractor_1, r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date"); + +// arthas_plugin-0.1.1: r"type\((.*)\)" +consistent!(arthas_plugin_0, r"type\((.*)\)"); + +// arthas_plugin-0.1.1: r"Vec<(.*)>" +consistent!(arthas_plugin_1, r"Vec<(.*)>"); + +// arthas_plugin-0.1.1: r"Option<(.*)>" +consistent!(arthas_plugin_2, r"Option<(.*)>"); + +// arthas_plugin-0.1.1: r"HashMap<[a-z0-9A-Z]+, *(.*)>" +consistent!(arthas_plugin_3, r"HashMap<[a-z0-9A-Z]+, *(.*)>"); + +// arthas_derive-0.1.0: "Vec *< *(.*) *>" +consistent!(arthas_derive_0, "Vec *< *(.*) *>"); + +// arthas_derive-0.1.0: r"Option *< *(.*) *>" +consistent!(arthas_derive_1, r"Option *< *(.*) *>"); + +// arthas_derive-0.1.0: r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>" +consistent!(arthas_derive_2, r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>"); + +// arpabet-0.2.0: r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$" +consistent!(arpabet_0, r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$"); + +// arpabet-0.2.0: r"^;;;\s+" +consistent!(arpabet_1, r"^;;;\s+"); + +// glossy_codegen-0.2.0: r"/\*.*?\*/|//.*" +consistent!(glossy_codegen_0, r"/\*.*?\*/|//.*"); + +// glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$" +consistent!(glossy_codegen_1, "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$"); + +// glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$" +consistent!(glossy_codegen_2, "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$"); + +// glossy_codegen-0.2.0: r"^\s*#\s*version\s+(\d+)" +consistent!(glossy_codegen_3, r"^\s*#\s*version\s+(\d+)"); + +// glossy_codegen-0.2.0: r"^\s*$" +consistent!(glossy_codegen_4, r"^\s*$"); + +// gluster-1.0.1: r"(?P<addr>via \S+)" +consistent!(gluster_0, r"(?P<addr>via \S+)"); + +// gluster-1.0.1: r"(?P<src>src \S+)" +consistent!(gluster_1, r"(?P<src>src \S+)"); + +// gl_helpers-0.1.7: r"(.*)\[\d+\]" +consistent!(gl_helpers_0, r"(.*)\[\d+\]"); + +// gl_helpers-0.1.7: r"(\d+).(\d+)" +consistent!(gl_helpers_1, r"(\d+).(\d+)"); + +// glr-parser-0.0.1: r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])" +consistent!(glr_parser_0, r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])"); + +// glr-parser-0.0.1: r"^\w+$" +consistent!(glr_parser_1, r"^\w+$"); + +// glr-parser-0.0.1: "'[^']+'" +consistent!(glr_parser_2, "'[^']+'"); + +// hoodlum-0.5.0: r"(?m)//.*" +consistent!(hoodlum_0, r"(?m)//.*"); + +// form-checker-0.2.2: r"^1\d{10}$" +consistent!(form_checker_0, r"^1\d{10}$"); + +// form-checker-0.2.2: r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$" +consistent!(form_checker_1, r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$"); + +// wikibase-0.2.0: r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)" +consistent!(wikibase_0, r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)"); + +// wifiscanner-0.3.6: r"Cell [0-9]{2,} - Address:" +consistent!(wifiscanner_0, r"Cell [0-9]{2,} - Address:"); + +// wifiscanner-0.3.6: r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}" +consistent!(wifiscanner_1, r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}"); + +// wifiscanner-0.3.6: r"Signal level=(\d+)/100" +consistent!(wifiscanner_2, r"Signal level=(\d+)/100"); + +// bbcode-1.0.2: r"(?s)\[b\](.*?)\[/b\]" +consistent!(bbcode_0, r"(?s)\[b\](.*?)\[/b\]"); + +// bbcode-1.0.2: r"(?s)\[i\](.*?)\[/i\]" +consistent!(bbcode_1, r"(?s)\[i\](.*?)\[/i\]"); + +// bbcode-1.0.2: r"(?s)\[u\](.*?)\[/u\]" +consistent!(bbcode_2, r"(?s)\[u\](.*?)\[/u\]"); + +// bbcode-1.0.2: r"(?s)\[s\](.*?)\[/s\]" +consistent!(bbcode_3, r"(?s)\[s\](.*?)\[/s\]"); + +// bbcode-1.0.2: r"(?s)\[size=(\d+)](.*?)\[/size\]" +consistent!(bbcode_4, r"(?s)\[size=(\d+)](.*?)\[/size\]"); + +// bbcode-1.0.2: r"(?s)\[color=(.+)](.*?)\[/color\]" +consistent!(bbcode_5, r"(?s)\[color=(.+)](.*?)\[/color\]"); + +// bbcode-1.0.2: r"(?s)\[center\](.*?)\[/center\]" +consistent!(bbcode_6, r"(?s)\[center\](.*?)\[/center\]"); + +// bbcode-1.0.2: r"(?s)\[left\](.*?)\[/left\]" +consistent!(bbcode_7, r"(?s)\[left\](.*?)\[/left\]"); + +// bbcode-1.0.2: r"(?s)\[right\](.*?)\[/right\]" +consistent!(bbcode_8, r"(?s)\[right\](.*?)\[/right\]"); + +// bbcode-1.0.2: r"(?s)\[table\](.*?)\[/table\]" +consistent!(bbcode_9, r"(?s)\[table\](.*?)\[/table\]"); + +// bbcode-1.0.2: r"(?s)\[td\](.*?)\[/td\]" +consistent!(bbcode_10, r"(?s)\[td\](.*?)\[/td\]"); + +// bbcode-1.0.2: r"(?s)\[tr\](.*?)\[/tr\]" +consistent!(bbcode_11, r"(?s)\[tr\](.*?)\[/tr\]"); + +// bbcode-1.0.2: r"(?s)\[th\](.*?)\[/th\]" +consistent!(bbcode_12, r"(?s)\[th\](.*?)\[/th\]"); + +// bbcode-1.0.2: r"(?s)\[url\](.*?)\[/url\]" +consistent!(bbcode_13, r"(?s)\[url\](.*?)\[/url\]"); + +// bbcode-1.0.2: r"(?s)\[url=(.+)\](.*?)\[/url\]" +consistent!(bbcode_14, r"(?s)\[url=(.+)\](.*?)\[/url\]"); + +// bbcode-1.0.2: r"(?s)\[quote\](.*?)\[/quote\]" +consistent!(bbcode_15, r"(?s)\[quote\](.*?)\[/quote\]"); + +// bbcode-1.0.2: r"(?s)\[quote=(.+)\](.*?)\[/quote\]" +consistent!(bbcode_16, r"(?s)\[quote=(.+)\](.*?)\[/quote\]"); + +// bbcode-1.0.2: r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_17, r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_18, r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[img(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_19, r"(?s)\[img(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[ol\](.*?)\[/ol\]" +consistent!(bbcode_20, r"(?s)\[ol\](.*?)\[/ol\]"); + +// bbcode-1.0.2: r"(?s)\[ul\](.*?)\[/ul\]" +consistent!(bbcode_21, r"(?s)\[ul\](.*?)\[/ul\]"); + +// bbcode-1.0.2: r"(?s)\[list\](.*?)\[/list\]" +consistent!(bbcode_22, r"(?s)\[list\](.*?)\[/list\]"); + +// bbcode-1.0.2: r"(?s)\[youtube\](.*?)\[/youtube\]" +consistent!(bbcode_23, r"(?s)\[youtube\](.*?)\[/youtube\]"); + +// bbcode-1.0.2: r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]" +consistent!(bbcode_24, r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]"); + +// bbcode-1.0.2: r"(?s)\[li\](.*?)\[/li\]" +consistent!(bbcode_25, r"(?s)\[li\](.*?)\[/li\]"); + +// block-utils-0.5.0: r"loop\d+" +consistent!(block_utils_0, r"loop\d+"); + +// block-utils-0.5.0: r"ram\d+" +consistent!(block_utils_1, r"ram\d+"); + +// block-utils-0.5.0: r"md\d+" +consistent!(block_utils_2, r"md\d+"); + +// kvvliveapi-0.1.0: r"^([1-9]) min$" +consistent!(kvvliveapi_0, r"^([1-9]) min$"); + +// rfc822_sanitizer-0.3.3: r"(\d{2}):(\d{2}):(\d{2})" +consistent!(rfc822_sanitizer_0, r"(\d{2}):(\d{2}):(\d{2})"); + +// rfc822_sanitizer-0.3.3: r"(\d{1,2}):(\d{1,2}):(\d{1,2})" +consistent!(rfc822_sanitizer_1, r"(\d{1,2}):(\d{1,2}):(\d{1,2})"); + +// faker-0.0.4: r"[2-9]" +consistent!(faker_0, r"[2-9]"); + +// faker-0.0.4: r"[1-9]" +consistent!(faker_1, r"[1-9]"); + +// faker-0.0.4: r"[0-9]" +consistent!(faker_2, r"[0-9]"); + +// faker-0.0.4: r"\d{10}" +consistent!(faker_3, r"\d{10}"); + +// faker-0.0.4: r"\d{1}" +consistent!(faker_4, r"\d{1}"); + +// faker-0.0.4: r"^\w+" +consistent!(faker_5, r"^\w+"); + +// faker-0.0.4: r"^\w+" +consistent!(faker_6, r"^\w+"); + +// faker-0.0.4: r"^(\w+\.? ?){2,3}$" +consistent!(faker_7, r"^(\w+\.? ?){2,3}$"); + +// faker-0.0.4: r"^[A-Z][a-z]+\.?$" +consistent!(faker_8, r"^[A-Z][a-z]+\.?$"); + +// faker-0.0.4: r"^[A-Z][A-Za-z]*\.?$" +consistent!(faker_9, r"^[A-Z][A-Za-z]*\.?$"); + +// faker-0.0.4: r"http://lorempixel.com/100/100/\w+" +consistent!(faker_10, r"http://lorempixel.com/100/100/\w+"); + +// faker-0.0.4: r"http://lorempixel.com/100/100/cats" +consistent!(faker_11, r"http://lorempixel.com/100/100/cats"); + +// fancy-regex-0.1.0: "(?i:ß)" +consistent!(fancy_regex_0, "(?i:ß)"); + +// fancy-regex-0.1.0: "(?i:\\x{0587})" +consistent!(fancy_regex_1, "(?i:\\x{0587})"); + +// fancy-regex-0.1.0: "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})" +consistent!(fancy_regex_2, "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})"); + +// fancy-prompt-0.1.5: r"/([^/])[^/]+/" +consistent!(fancy_prompt_0, r"/([^/])[^/]+/"); + +// fancy-prompt-0.1.5: r"^([^:]+):.*?(?::([^:]+))?$" +consistent!(fancy_prompt_1, r"^([^:]+):.*?(?::([^:]+))?$"); + +// fanta-0.2.0: r"^(/?__\w+__)/(.*)" +consistent!(fanta_0, r"^(/?__\w+__)/(.*)"); + +// fanta-cli-0.1.1: r"(.)([A-Z])" +consistent!(fanta_cli_0, r"(.)([A-Z])"); + +// fanta-cli-0.1.1: "\\{:[^\\s]+\\}" +consistent!(fanta_cli_1, "\\{:[^\\s]+\\}"); + +// amethyst_tools-0.7.1: "(?P<last>[^\r])\n" +consistent!(amethyst_tools_0, "(?P<last>[^\r])\n"); + +// amigo-0.3.1: r"^-?\d+(\.\d)?" +consistent!(amigo_0, r"^-?\d+(\.\d)?"); + +// amigo-0.3.1: r"^[a-zA-Z_]+[\w-]*[!?_]?" +consistent!(amigo_1, r"^[a-zA-Z_]+[\w-]*[!?_]?"); + +// amigo-0.3.1: r"^\(" +consistent!(amigo_2, r"^\("); + +// amigo-0.3.1: r"^\)" +consistent!(amigo_3, r"^\)"); + +// amigo-0.3.1: r"^\s+" +consistent!(amigo_4, r"^\s+"); + +// ethcore-logger-1.12.0: "\x1b\\[[^m]+m" +consistent!(ethcore_logger_0, "\x1b\\[[^m]+m"); + +// dash2html-1.0.1: r"__.*?__" +consistent!(dash2html_0, r"__.*?__"); + +// dash2html-1.0.1: r"(?i)@(?:time|clipboard|cursor|date)" +consistent!(dash2html_1, r"(?i)@(?:time|clipboard|cursor|date)"); + +// os_type-2.0.0: r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$" +consistent!(os_type_0, r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$"); + +// os_type-2.0.0: r"ProductName:\s([\w\s]+)\n" +consistent!(os_type_1, r"ProductName:\s([\w\s]+)\n"); + +// os_type-2.0.0: r"ProductVersion:\s(\w+\.\w+\.\w+)" +consistent!(os_type_2, r"ProductVersion:\s(\w+\.\w+\.\w+)"); + +// os_type-2.0.0: r"BuildVersion:\s(\w+)" +consistent!(os_type_3, r"BuildVersion:\s(\w+)"); + +// os_type-2.0.0: r"(\w+) Linux release" +consistent!(os_type_4, r"(\w+) Linux release"); + +// os_type-2.0.0: r"release\s([\w\.]+)" +consistent!(os_type_5, r"release\s([\w\.]+)"); + +// os_type-2.0.0: r"Distributor ID:\s(\w+)" +consistent!(os_type_6, r"Distributor ID:\s(\w+)"); + +// os_type-2.0.0: r"Release:\s([\w\.]+)" +consistent!(os_type_7, r"Release:\s([\w\.]+)"); + +// bindgen-0.37.0: r"typename type\-parameter\-\d+\-\d+::.+" +consistent!(bindgen_0, r"typename type\-parameter\-\d+\-\d+::.+"); + +// imap-0.8.1: "^+(.*)\r\n" +consistent!(imap_0, "^+(.*)\r\n"); + +// image-base64-0.1.0: r"^ffd8ffe0" +consistent!(image_base64_0, r"^ffd8ffe0"); + +// image-base64-0.1.0: r"^89504e47" +consistent!(image_base64_1, r"^89504e47"); + +// image-base64-0.1.0: r"^47494638" +consistent!(image_base64_2, r"^47494638"); + +// json-pointer-0.3.2: "^(/([^/~]|~[01])*)*$" +consistent!(json_pointer_0, "^(/([^/~]|~[01])*)*$"); + +// json-pointer-0.3.2: "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$" +consistent!(json_pointer_1, "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$"); + +// mysql_common-0.7.0: r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB" +consistent!(mysql_common_0, r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB"); + +// mysql_common-0.7.0: r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)" +consistent!(mysql_common_1, r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)"); + +// government_id-0.1.0: r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$" +consistent!(government_id_0, r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$"); + +// ohmers-0.1.1: r"UniqueIndexViolation: (\w+)" +consistent!(ohmers_0, r"UniqueIndexViolation: (\w+)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_0, r"(.*) you are (.*)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_1, r"(.*) you are (.*)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_2, r"(.*) you are (.*)"); + +// chema-0.0.5: "^\\s*\\*" +consistent!(chema_0, "^\\s*\\*"); + +// chema-0.0.5: "^\\s*@(\\w+)\\s+(.*)" +consistent!(chema_1, "^\\s*@(\\w+)\\s+(.*)"); + +// chord3-0.3.0: r"^\s*#" +consistent!(chord3_0, r"^\s*#"); + +// chord3-0.3.0: r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}" +consistent!(chord3_1, r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}"); + +// chord3-0.3.0: r"\{(eot|end_of_tab):?\s*" +consistent!(chord3_2, r"\{(eot|end_of_tab):?\s*"); + +// chord3-0.3.0: r"([^\[]*)(?:\[([^\]]*)\])?" +consistent!(chord3_3, r"([^\[]*)(?:\[([^\]]*)\])?"); + +// checkmail-0.1.1: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" +consistent!(checkmail_0, "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"); + +// cntk-0.2.1: r"\b\w\w+\b" +consistent!(cntk_0, r"\b\w\w+\b"); + +// cntk-0.2.1: r"\b\w\w+\b" +consistent!(cntk_1, r"\b\w\w+\b"); + +// cniguru-0.1.0: r"\(id: (\d+)\)" +consistent!(cniguru_0, r"\(id: (\d+)\)"); + +// upm_lib-0.3.0: r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$" +consistent!(upm_lib_0, r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$"); + +// avro-0.2.1: r"^\s*(\*+(\s+))?" +consistent!(avro_0, r"^\s*(\*+(\s+))?"); + +// avro-0.2.1: r"^\s*(\*+)?" +consistent!(avro_1, r"^\s*(\*+)?"); + +// nomi-0.0.2: "[0-9]+" +consistent!(nomi_0, "[0-9]+"); + +// nodes-0.1.0: "([0-9]+)@(?:nodes|n)?:([^@]+)?" +consistent!(nodes_0, "([0-9]+)@(?:nodes|n)?:([^@]+)?"); + +// not-stakkr-1.0.0: r"(?i)in (\d+) (second|minute|hour|day|week)s?" +consistent!(not_stakkr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); + +// notetxt-0.0.1: "^([A-Za-z0-9 -_:]+)\n-+\n" +consistent!(notetxt_0, "^([A-Za-z0-9 -_:]+)\n-+\n"); + +// nail-0.1.0-pre.0: r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$" +consistent!(nail_0, r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$"); + +// nail-0.1.0-pre.0: r"^-?[0-9]+$" +consistent!(nail_1, r"^-?[0-9]+$"); + +// askalono-0.2.0: r"[^\w\s\pP]+" +consistent!(askalono_0, r"[^\w\s\pP]+"); + +// askalono-0.2.0: r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+" +consistent!(askalono_1, r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+"); + +// askalono-0.2.0: r"\p{Pd}+" +consistent!(askalono_2, r"\p{Pd}+"); + +// askalono-0.2.0: r"\p{Ps}+" +consistent!(askalono_3, r"\p{Ps}+"); + +// askalono-0.2.0: r"\p{Pe}+" +consistent!(askalono_4, r"\p{Pe}+"); + +// askalono-0.2.0: r"\p{Pc}+" +consistent!(askalono_5, r"\p{Pc}+"); + +// askalono-0.2.0: r"[©Ⓒⓒ]" +consistent!(askalono_6, r"[©Ⓒⓒ]"); + +// askalono-0.2.0: r"[\r\n\v\f]" +consistent!(askalono_7, r"[\r\n\v\f]"); + +// askalono-0.2.0: r"\n{3,}" +consistent!(askalono_8, r"\n{3,}"); + +// askalono-0.2.0: r"[^\w\s]+" +consistent!(askalono_9, r"[^\w\s]+"); + +// askalono-0.2.0: r"\s+" +consistent!(askalono_10, r"\s+"); + +// assembunny_plus-0.0.3: r"[^0-9a-zA-Z_]" +consistent!(assembunny_plus_0, r"[^0-9a-zA-Z_]"); + +// assembunny_plus-0.0.3: r"[0-9]" +consistent!(assembunny_plus_1, r"[0-9]"); + +// salt-compressor-0.4.0: r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$" +consistent!(salt_compressor_0, r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$"); + +// sabisabi-0.4.1: r"</?[^>]+?>" +consistent!(sabisabi_0, r"</?[^>]+?>"); + +// sabisabi-0.4.1: r"\([^)]*\)" +consistent!(sabisabi_1, r"\([^)]*\)"); + +// sassers-0.13.5-h28: "@import \"([^\"]*)\";" +consistent!(sassers_0, "@import \"([^\"]*)\";"); + +// shadowsocks-0.6.2: r"[A-Za-z\d-]{1,63}$" +consistent!(shadowsocks_0, r"[A-Za-z\d-]{1,63}$"); + +// shkeleton-0.1.5: "[abc]+" +consistent!(shkeleton_0, "[abc]+"); + +// shellwords-0.1.0: r"([^A-Za-z0-9_\-.,:/@\n])" +consistent!(shellwords_0, r"([^A-Za-z0-9_\-.,:/@\n])"); + +// shellwords-0.1.0: r"\n" +consistent!(shellwords_1, r"\n"); + +// shush-0.1.5: "(?P<num>[0-9]+)(?P<units>[dhms])" +consistent!(shush_0, "(?P<num>[0-9]+)(?P<units>[dhms])"); + +// woothee-0.8.0: r"(?:Chrome|CrMo|CriOS)/([.0-9]+)" +consistent!(woothee_0, r"(?:Chrome|CrMo|CriOS)/([.0-9]+)"); + +// woothee-0.8.0: r"Vivaldi/([.0-9]+)" +consistent!(woothee_1, r"Vivaldi/([.0-9]+)"); + +// woothee-0.8.0: r"Firefox/([.0-9]+)" +consistent!(woothee_2, r"Firefox/([.0-9]+)"); + +// woothee-0.8.0: r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$" +consistent!(woothee_3, r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$"); + +// woothee-0.8.0: r"FxiOS/([.0-9]+)" +consistent!(woothee_4, r"FxiOS/([.0-9]+)"); + +// woothee-0.8.0: r"\(([^;)]+);FOMA;" +consistent!(woothee_5, r"\(([^;)]+);FOMA;"); + +// woothee-0.8.0: r"jig browser[^;]+; ([^);]+)" +consistent!(woothee_6, r"jig browser[^;]+; ([^);]+)"); + +// woothee-0.8.0: r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)" +consistent!(woothee_7, r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)"); + +// woothee-0.8.0: r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)" +consistent!(woothee_8, r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)"); + +// woothee-0.8.0: r"(?i)(?:feed|web) ?parser" +consistent!(woothee_9, r"(?i)(?:feed|web) ?parser"); + +// woothee-0.8.0: r"(?i)watch ?dog" +consistent!(woothee_10, r"(?i)watch ?dog"); + +// woothee-0.8.0: r"Edge/([.0-9]+)" +consistent!(woothee_11, r"Edge/([.0-9]+)"); + +// woothee-0.8.0: r"MSIE ([.0-9]+);" +consistent!(woothee_12, r"MSIE ([.0-9]+);"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_13, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"Opera[/ ]([.0-9]+)" +consistent!(woothee_14, r"Opera[/ ]([.0-9]+)"); + +// woothee-0.8.0: r"OPR/([.0-9]+)" +consistent!(woothee_15, r"OPR/([.0-9]+)"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_16, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)" +consistent!(woothee_17, r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)"); + +// woothee-0.8.0: r"Trident/([.0-9]+);" +consistent!(woothee_18, r"Trident/([.0-9]+);"); + +// woothee-0.8.0: r" rv:([.0-9]+)" +consistent!(woothee_19, r" rv:([.0-9]+)"); + +// woothee-0.8.0: r"IEMobile/([.0-9]+);" +consistent!(woothee_20, r"IEMobile/([.0-9]+);"); + +// woothee-0.8.0: r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)" +consistent!(woothee_21, r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)"); + +// woothee-0.8.0: r"Windows ([ .a-zA-Z0-9]+)[;\\)]" +consistent!(woothee_22, r"Windows ([ .a-zA-Z0-9]+)[;\\)]"); + +// woothee-0.8.0: r"^Phone(?: OS)? ([.0-9]+)" +consistent!(woothee_23, r"^Phone(?: OS)? ([.0-9]+)"); + +// woothee-0.8.0: r"iP(hone;|ad;|od) .*like Mac OS X" +consistent!(woothee_24, r"iP(hone;|ad;|od) .*like Mac OS X"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_25, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"rv:(\d+\.\d+\.\d+)" +consistent!(woothee_26, r"rv:(\d+\.\d+\.\d+)"); + +// woothee-0.8.0: r"FreeBSD ([^;\)]+);" +consistent!(woothee_27, r"FreeBSD ([^;\)]+);"); + +// woothee-0.8.0: r"CrOS ([^\)]+)\)" +consistent!(woothee_28, r"CrOS ([^\)]+)\)"); + +// woothee-0.8.0: r"Android[- ](\d+\.\d+(?:\.\d+)?)" +consistent!(woothee_29, r"Android[- ](\d+\.\d+(?:\.\d+)?)"); + +// woothee-0.8.0: r"PSP \(PlayStation Portable\); ([.0-9]+)\)" +consistent!(woothee_30, r"PSP \(PlayStation Portable\); ([.0-9]+)\)"); + +// woothee-0.8.0: r"PLAYSTATION 3;? ([.0-9]+)\)" +consistent!(woothee_31, r"PLAYSTATION 3;? ([.0-9]+)\)"); + +// woothee-0.8.0: r"PlayStation Vita ([.0-9]+)\)" +consistent!(woothee_32, r"PlayStation Vita ([.0-9]+)\)"); + +// woothee-0.8.0: r"PlayStation 4 ([.0-9]+)\)" +consistent!(woothee_33, r"PlayStation 4 ([.0-9]+)\)"); + +// woothee-0.8.0: r"BB10(?:.+)Version/([.0-9]+) " +consistent!(woothee_34, r"BB10(?:.+)Version/([.0-9]+) "); + +// woothee-0.8.0: r"BlackBerry(?:\d+)/([.0-9]+) " +consistent!(woothee_35, r"BlackBerry(?:\d+)/([.0-9]+) "); + +// woothee-0.8.0: r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X" +consistent!(woothee_36, r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X"); + +// woothee-0.8.0: r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)" +consistent!(woothee_37, r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)"); + +// woothee-0.8.0: r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)" +consistent!(woothee_38, r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)"); + +// woothee-0.8.0: r"[- ]HttpClient(/|$)" +consistent!(woothee_39, r"[- ]HttpClient(/|$)"); + +// woothee-0.8.0: r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)" +consistent!(woothee_40, r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)"); + +// woothee-0.8.0: r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)" +consistent!(woothee_41, r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)"); + +// woothee-0.8.0: r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)" +consistent!(woothee_42, r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)"); + +// woothee-0.8.0: r"Sleipnir/([.0-9]+)" +consistent!(woothee_43, r"Sleipnir/([.0-9]+)"); + +// word_replace-0.0.3: r"@@[a-z|A-Z|\d]+@@" +consistent!(word_replace_0, r"@@[a-z|A-Z|\d]+@@"); + +// wordcount-0.1.0: r"\w+" +consistent!(wordcount_0, r"\w+"); + +// just-0.3.12: "^([^=]+)=(.*)$" +consistent!(just_0, "^([^=]+)=(.*)$"); + +// emote-0.1.0: r":[a-zA-Z_]+?:" +consistent!(emote_0, r":[a-zA-Z_]+?:"); + +// emojicons-1.0.1: r":([a-zA-Z0-9_+-]+):" +consistent!(emojicons_0, r":([a-zA-Z0-9_+-]+):"); + +// git2_codecommit-0.1.2: r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com" +consistent!(git2_codecommit_0, r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com"); + +// git-workarea-3.1.2: r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$" +consistent!(git_workarea_0, r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$"); + +// git-shell-enforce-directory-1.0.0: r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$" +consistent!(git_shell_enforce_directory_0, r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$"); + +// git-journal-1.6.3: r"[ \n]:(.*?):" +consistent!(git_journal_0, r"[ \n]:(.*?):"); + +// git-find-0.3.2: r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$" +consistent!(git_find_0, r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$"); + +// gitlab-api-0.6.0: r"private_token=\w{20}" +consistent!(gitlab_api_0, r"private_token=\w{20}"); + +// td-client-0.7.0: "^(http://|https://)" +consistent!(td_client_0, "^(http://|https://)"); + +// karaconv-0.3.0: r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)" +consistent!(karaconv_0, r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)"); + +// katana-1.0.2: r"(?P<comp>et al\.)(?:\.)" +consistent!(katana_0, r"(?P<comp>et al\.)(?:\.)"); + +// katana-1.0.2: r"\.{3}" +consistent!(katana_1, r"\.{3}"); + +// katana-1.0.2: r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)" +consistent!(katana_2, r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)"); + +// katana-1.0.2: r"\s\.(?P<nums>[0-9]+)" +consistent!(katana_3, r"\s\.(?P<nums>[0-9]+)"); + +// katana-1.0.2: r"(?:[A-Za-z]\.){2,}" +consistent!(katana_4, r"(?:[A-Za-z]\.){2,}"); + +// katana-1.0.2: r"(?P<init>[A-Z])(?P<point>\.)" +consistent!(katana_5, r"(?P<init>[A-Z])(?P<point>\.)"); + +// katana-1.0.2: r"(?P<title>[A-Z][a-z]{1,3})(\.)" +consistent!(katana_6, r"(?P<title>[A-Z][a-z]{1,3})(\.)"); + +// katana-1.0.2: r"&==&(?P<p>[.!?])" +consistent!(katana_7, r"&==&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\^&(?P<p>[.!?])" +consistent!(katana_8, r"&\^&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\*\*&(?P<p>[.!?])" +consistent!(katana_9, r"&\*\*&(?P<p>[.!?])"); + +// katana-1.0.2: r"&=&(?P<p>[.!?])" +consistent!(katana_10, r"&=&(?P<p>[.!?])"); + +// katana-1.0.2: r"&##&(?P<p>[.!?])" +consistent!(katana_11, r"&##&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\$&(?P<p>[.!?])" +consistent!(katana_12, r"&\$&(?P<p>[.!?])"); + +// kailua_syntax-1.1.0: r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)" +consistent!(kailua_syntax_0, r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)"); + +// kailua_syntax-1.1.0: r"<(\d+)>" +consistent!(kailua_syntax_1, r"<(\d+)>"); + +// ftp-3.0.1: r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)" +consistent!(ftp_0, r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)"); + +// ftp-3.0.1: r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b" +consistent!(ftp_1, r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b"); + +// ftp-3.0.1: r"\s+(\d+)\s*$" +consistent!(ftp_2, r"\s+(\d+)\s*$"); + +// vat-0.1.0: r"<countryCode>(.*?)</countryCode>" +consistent!(vat_0, r"<countryCode>(.*?)</countryCode>"); + +// vat-0.1.0: r"<vatNumber>(.*?)</vatNumber>" +consistent!(vat_1, r"<vatNumber>(.*?)</vatNumber>"); + +// vat-0.1.0: r"<name>(.*?)</name>" +consistent!(vat_2, r"<name>(.*?)</name>"); + +// vat-0.1.0: r"<address>(?s)(.*?)(?-s)</address>" +consistent!(vat_3, r"<address>(?s)(.*?)(?-s)</address>"); + +// vat-0.1.0: r"<valid>(true|false)</valid>" +consistent!(vat_4, r"<valid>(true|false)</valid>"); + +// vat-0.1.0: r"^ATU\d{8}$" +consistent!(vat_5, r"^ATU\d{8}$"); + +// vat-0.1.0: r"^BE0?\d{9, 10}$" +consistent!(vat_6, r"^BE0?\d{9, 10}$"); + +// vat-0.1.0: r"^BG\d{9,10}$" +consistent!(vat_7, r"^BG\d{9,10}$"); + +// vat-0.1.0: r"^HR\d{11}$" +consistent!(vat_8, r"^HR\d{11}$"); + +// vat-0.1.0: r"^CY\d{8}[A-Z]$" +consistent!(vat_9, r"^CY\d{8}[A-Z]$"); + +// vat-0.1.0: r"^CZ\d{8,10}$" +consistent!(vat_10, r"^CZ\d{8,10}$"); + +// vat-0.1.0: r"^DK\d{8}$" +consistent!(vat_11, r"^DK\d{8}$"); + +// vat-0.1.0: r"^EE\d{9}$" +consistent!(vat_12, r"^EE\d{9}$"); + +// vat-0.1.0: r"^FI\d{8}$" +consistent!(vat_13, r"^FI\d{8}$"); + +// vat-0.1.0: r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$" +consistent!(vat_14, r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$"); + +// vat-0.1.0: r"^DE\d{9}$" +consistent!(vat_15, r"^DE\d{9}$"); + +// vat-0.1.0: r"^EL\d{9}$" +consistent!(vat_16, r"^EL\d{9}$"); + +// vat-0.1.0: r"^HU\d{8}$" +consistent!(vat_17, r"^HU\d{8}$"); + +// vat-0.1.0: r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$" +consistent!(vat_18, r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$"); + +// vat-0.1.0: r"^IT\d{11}$" +consistent!(vat_19, r"^IT\d{11}$"); + +// vat-0.1.0: r"^LV\d{11}$" +consistent!(vat_20, r"^LV\d{11}$"); + +// vat-0.1.0: r"^LT(\d{9}|\d{12})$" +consistent!(vat_21, r"^LT(\d{9}|\d{12})$"); + +// vat-0.1.0: r"^LU\d{8}$" +consistent!(vat_22, r"^LU\d{8}$"); + +// vat-0.1.0: r"^MT\d{8}$" +consistent!(vat_23, r"^MT\d{8}$"); + +// vat-0.1.0: r"^NL\d{9}B\d{2}$" +consistent!(vat_24, r"^NL\d{9}B\d{2}$"); + +// vat-0.1.0: r"^PL\d{10}$" +consistent!(vat_25, r"^PL\d{10}$"); + +// vat-0.1.0: r"^PT\d{9}$" +consistent!(vat_26, r"^PT\d{9}$"); + +// vat-0.1.0: r"^RO\d{2,10}$" +consistent!(vat_27, r"^RO\d{2,10}$"); + +// vat-0.1.0: r"^SK\d{10}$" +consistent!(vat_28, r"^SK\d{10}$"); + +// vat-0.1.0: r"^SI\d{8}$" +consistent!(vat_29, r"^SI\d{8}$"); + +// vat-0.1.0: r"^ES[A-Z0-9]\d{7}[A-Z0-9]$" +consistent!(vat_30, r"^ES[A-Z0-9]\d{7}[A-Z0-9]$"); + +// vat-0.1.0: r"^SE\d{10}01$" +consistent!(vat_31, r"^SE\d{10}01$"); + +// vat-0.1.0: r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$" +consistent!(vat_32, r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$"); + +// eve-0.1.1: r"\{\{(.*)\}\}" +consistent!(eve_0, r"\{\{(.*)\}\}"); + +// egc-0.1.2: "^mio" +consistent!(egc_0, "^mio"); + +// pew-0.2.3: "" +consistent!(pew_0, ""); + +// pew-0.2.3: "" +consistent!(pew_1, ""); + +// mob-0.4.3: "y" +consistent!(mob_0, "y"); + +// lit-0.2.8: "@([a-z]+)" +consistent!(lit_0, "@([a-z]+)"); + +// lit-0.2.8: "([A-Z-]+):(.*)" +consistent!(lit_1, "([A-Z-]+):(.*)"); + +// lit-0.2.8: "^[a-zA-Z_][a-zA-Z0-9_]*$" +consistent!(lit_2, "^[a-zA-Z_][a-zA-Z0-9_]*$"); + +// avm-1.0.1: r"\d+\.\d+\.\d+" +consistent!(avm_0, r"\d+\.\d+\.\d+"); + +// avm-1.0.1: r"\d+\.\d+\.\d+" +consistent!(avm_1, r"\d+\.\d+\.\d+"); + +// orm-0.2.0: r"^Vec<(.+)>$" +consistent!(orm_0, r"^Vec<(.+)>$"); + +// sgf-0.1.5: r"\\(\r\n|\n\r|\n|\r)" +consistent!(sgf_0, r"\\(\r\n|\n\r|\n|\r)"); + +// sgf-0.1.5: r"\\(.)" +consistent!(sgf_1, r"\\(.)"); + +// sgf-0.1.5: r"\r\n|\n\r|\n|\r" +consistent!(sgf_2, r"\r\n|\n\r|\n|\r"); + +// sgf-0.1.5: r"([\]\\:])" +consistent!(sgf_3, r"([\]\\:])"); + +// dok-0.2.0: "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$" +consistent!(dok_0, "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$"); + +// d20-0.1.0: r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)" +consistent!(d20_0, r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)"); + +// dvb-0.3.0: "E" +consistent!(dvb_0, "E"); + +// dvb-0.3.0: "^F" +consistent!(dvb_1, "^F"); + +// dvb-0.3.0: "^S" +consistent!(dvb_2, "^S"); + +// ger-0.2.0: r"Change-Id: (I[a-f0-9]{40})$" +consistent!(ger_0, r"Change-Id: (I[a-f0-9]{40})$"); + +// ger-0.2.0: r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$" +consistent!(ger_1, r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$"); + +// n5-0.2.1: r"(\d+)(\.(\d+))?(\.(\d+))?(.*)" +consistent!(n5_0, r"(\d+)(\.(\d+))?(\.(\d+))?(.*)"); + +// po-0.1.4: r"[A-Za-z0-9]" +consistent!(po_0, r"[A-Za-z0-9]"); + +// carnix-0.8.5: "path is (‘|')?([^’'\n]*)(’|')?" +consistent!(carnix_0, "path is (‘|')?([^’'\n]*)(’|')?"); + +// carnix-0.8.5: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?" +consistent!(carnix_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?"); + +// carnix-0.8.5: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(carnix_2, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// carnix-0.8.5: r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(carnix_3, r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// caseless-0.2.1: r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$" +consistent!(caseless_0, r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$"); + +// caseless-0.2.1: r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);" +consistent!(caseless_1, r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);"); + +// cabot-0.2.0: "\r?\n\r?\n" +consistent!(cabot_0, "\r?\n\r?\n"); + +// cabot-0.2.0: "\r?\n" +consistent!(cabot_1, "\r?\n"); + +// card-validate-2.2.1: r"^600" +consistent!(card_validate_0, r"^600"); + +// card-validate-2.2.1: r"^5019" +consistent!(card_validate_1, r"^5019"); + +// card-validate-2.2.1: r"^4" +consistent!(card_validate_2, r"^4"); + +// card-validate-2.2.1: r"^(5[1-5]|2[2-7])" +consistent!(card_validate_3, r"^(5[1-5]|2[2-7])"); + +// card-validate-2.2.1: r"^3[47]" +consistent!(card_validate_4, r"^3[47]"); + +// card-validate-2.2.1: r"^3[0689]" +consistent!(card_validate_5, r"^3[0689]"); + +// card-validate-2.2.1: r"^6([045]|22)" +consistent!(card_validate_6, r"^6([045]|22)"); + +// card-validate-2.2.1: r"^(62|88)" +consistent!(card_validate_7, r"^(62|88)"); + +// card-validate-2.2.1: r"^35" +consistent!(card_validate_8, r"^35"); + +// card-validate-2.2.1: r"^[0-9]+$" +consistent!(card_validate_9, r"^[0-9]+$"); + +// cargo-testify-0.3.0: r"\d{1,} passed.*filtered out" +consistent!(cargo_testify_0, r"\d{1,} passed.*filtered out"); + +// cargo-testify-0.3.0: r"error(:|\[).*" +consistent!(cargo_testify_1, r"error(:|\[).*"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_0, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_1, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_2, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_3, r"<(.*?)>"); + +// cargo-incremental-0.1.23: r"(?m)^incremental: re-using (\d+) out of (\d+) modules$" +consistent!(cargo_incremental_0, r"(?m)^incremental: re-using (\d+) out of (\d+) modules$"); + +// cargo-incremental-0.1.23: "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$" +consistent!(cargo_incremental_1, "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$"); + +// cargo-incremental-0.1.23: r"(?m)^test (.*) \.\.\. (\w+)" +consistent!(cargo_incremental_2, r"(?m)^test (.*) \.\.\. (\w+)"); + +// cargo-incremental-0.1.23: r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured" +consistent!(cargo_incremental_3, r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured"); + +// cargo-testjs-0.1.2: r"^[^-]+-[0-9a-f]+\.js$" +consistent!(cargo_testjs_0, r"^[^-]+-[0-9a-f]+\.js$"); + +// cargo-tarpaulin-0.6.2: r"\s*//" +consistent!(cargo_tarpaulin_0, r"\s*//"); + +// cargo-tarpaulin-0.6.2: r"/\*" +consistent!(cargo_tarpaulin_1, r"/\*"); + +// cargo-tarpaulin-0.6.2: r"\*/" +consistent!(cargo_tarpaulin_2, r"\*/"); + +// cargo-culture-kit-0.1.0: r"^fo" +consistent!(cargo_culture_kit_0, r"^fo"); + +// cargo-screeps-0.1.3: "\\s+" +consistent!(cargo_screeps_0, "\\s+"); + +// cargo-brew-0.1.4: r"`(\S+) v([0-9.]+)" +consistent!(cargo_brew_0, r"`(\S+) v([0-9.]+)"); + +// cargo-release-0.10.2: "^\\[.+\\]" +consistent!(cargo_release_0, "^\\[.+\\]"); + +// cargo-release-0.10.2: "^\\[\\[.+\\]\\]" +consistent!(cargo_release_1, "^\\[\\[.+\\]\\]"); + +// cargo-edit-0.3.0-beta.1: r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" +consistent!(cargo_edit_0, r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); + +// cargo-edit-0.3.0-beta.1: r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" +consistent!(cargo_edit_1, r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); + +// cargo-disassemble-0.1.1: ".*" +consistent!(cargo_disassemble_0, ".*"); + +// cargo-demangle-0.1.2: r"(?m)(?P<symbol>_ZN[0-9]+.*E)" +consistent!(cargo_demangle_0, r"(?m)(?P<symbol>_ZN[0-9]+.*E)"); + +// cargo-coverage-annotations-0.1.5: r"^\s*\}(?:\)*;?|\s*else\s*\{)$" +consistent!(cargo_coverage_annotations_0, r"^\s*\}(?:\)*;?|\s*else\s*\{)$"); + +// cargo-urlcrate-1.0.1: "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]" +consistent!(cargo_urlcrate_0, "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]"); + +// cargo-script-0.2.8: r"^\s*\*( |$)" +consistent!(cargo_script_0, r"^\s*\*( |$)"); + +// cargo-script-0.2.8: r"^(\s+)" +consistent!(cargo_script_1, r"^(\s+)"); + +// cargo-script-0.2.8: r"/\*|\*/" +consistent!(cargo_script_2, r"/\*|\*/"); + +// cargo-script-0.2.8: r"^\s*//!" +consistent!(cargo_script_3, r"^\s*//!"); + +// cargo-script-0.2.8: r"^#![^\[].*?(\r\n|\n)" +consistent!(cargo_script_4, r"^#![^\[].*?(\r\n|\n)"); + +// cargo-update-1.5.2: r"cargo-install-update\.exe-v.+" +consistent!(cargo_update_0, r"cargo-install-update\.exe-v.+"); + +// canteen-0.4.1: r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$" +consistent!(canteen_0, r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$"); + +// thruster-cli-0.1.3: r"(.)([A-Z])" +consistent!(thruster_cli_0, r"(.)([A-Z])"); + +// thieves-cant-0.1.0: "([Z]+)$" +consistent!(thieves_cant_0, "([Z]+)$"); + +// codeowners-0.1.3: r"^@\S+/\S+" +consistent!(codeowners_0, r"^@\S+/\S+"); + +// codeowners-0.1.3: r"^@\S+" +consistent!(codeowners_1, r"^@\S+"); + +// codeowners-0.1.3: r"^\S+@\S+" +consistent!(codeowners_2, r"^\S+@\S+"); + +// conserve-0.4.2: r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$" +consistent!(conserve_0, r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$"); + +// commodore-0.3.0: r"(?P<greeting>\S+?) (?P<name>\S+?)$" +consistent!(commodore_0, r"(?P<greeting>\S+?) (?P<name>\S+?)$"); + +// corollary-0.3.0: r"([ \t]*)```haskell([\s\S]*?)```" +consistent!(corollary_0, r"([ \t]*)```haskell([\s\S]*?)```"); + +// corollary-0.3.0: r"\b((?:a|b|t)\d*)\b" +consistent!(corollary_1, r"\b((?:a|b|t)\d*)\b"); + +// colorizex-0.1.3: "NB" +consistent!(colorizex_0, "NB"); + +// colorstring-0.0.1: r"(?i)\[[a-z0-9_-]+\]" +consistent!(colorstring_0, r"(?i)\[[a-z0-9_-]+\]"); + +// colorstring-0.0.1: r"^(?i)(\[[a-z0-9_-]+\])+" +consistent!(colorstring_1, r"^(?i)(\[[a-z0-9_-]+\])+"); + +// cosmogony-0.3.0: "name:(.+)" +consistent!(cosmogony_0, "name:(.+)"); + +// cobalt-bin-0.12.1: r"(?m:^ {0,3}\[[^\]]+\]:.+$)" +consistent!(cobalt_bin_0, r"(?m:^ {0,3}\[[^\]]+\]:.+$)"); + +// comrak-0.2.12: r"[^\p{L}\p{M}\p{N}\p{Pc} -]" +consistent!(comrak_0, r"[^\p{L}\p{M}\p{N}\p{Pc} -]"); + +// content-blocker-0.2.3: "" +consistent!(content_blocker_0, ""); + +// content-blocker-0.2.3: "(?i)hi" +consistent!(content_blocker_1, "(?i)hi"); + +// content-blocker-0.2.3: "http[s]?://domain.org" +consistent!(content_blocker_2, "http[s]?://domain.org"); + +// content-blocker-0.2.3: "(?i)http[s]?://domain.org" +consistent!(content_blocker_3, "(?i)http[s]?://domain.org"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_4, "http://domain.org"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_5, "http://domain.org"); + +// content-blocker-0.2.3: "ad.html" +consistent!(content_blocker_6, "ad.html"); + +// content-blocker-0.2.3: "ad.html" +consistent!(content_blocker_7, "ad.html"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_8, "http://domain.org"); + +// content-blocker-0.2.3: "http://domain.org/nocookies.sjs" +consistent!(content_blocker_9, "http://domain.org/nocookies.sjs"); + +// content-blocker-0.2.3: "http://domain.org/nocookies.sjs" +consistent!(content_blocker_10, "http://domain.org/nocookies.sjs"); + +// content-blocker-0.2.3: "http://domain.org/hideme.jpg" +consistent!(content_blocker_11, "http://domain.org/hideme.jpg"); + +// content-blocker-0.2.3: "http://domain.org/ok.html" +consistent!(content_blocker_12, "http://domain.org/ok.html"); + +// content-blocker-0.2.3: "http://domain.org/ok.html\\?except_this=1" +consistent!(content_blocker_13, "http://domain.org/ok.html\\?except_this=1"); + +// victoria-dom-0.1.2: "[A-Za-z0-9=]" +consistent!(victoria_dom_0, "[A-Za-z0-9=]"); + +// numbat-1.0.0: r"^nsq://" +consistent!(numbat_0, r"^nsq://"); + +// airkorea-0.1.2: r"[\s\t\r\n]" +consistent!(airkorea_0, r"[\s\t\r\n]"); + +// airkorea-0.1.2: r"([\{\[,])|([\}\]])" +consistent!(airkorea_1, r"([\{\[,])|([\}\]])"); + +// airkorea-0.1.2: r"[^.\d]+$" +consistent!(airkorea_2, r"[^.\d]+$"); + +// rofl-0.0.1: r"\b" +// consistent!(rofl_0, r"\b"); + +// rogcat-0.2.15: r"--------- beginning of.*" +consistent!(rogcat_0, r"--------- beginning of.*"); + +// rogcat-0.2.15: r"a|e|i|o|u" +consistent!(rogcat_1, r"a|e|i|o|u"); + +// rogcat-0.2.15: r"^(\d+)([kMG])$" +consistent!(rogcat_2, r"^(\d+)([kMG])$"); + +// media_filename-0.1.4: "\\.([A-Za-z0-9]{2,4})$" +consistent!(media_filename_0, "\\.([A-Za-z0-9]{2,4})$"); + +// media_filename-0.1.4: "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})" +consistent!(media_filename_1, "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})"); + +// media_filename-0.1.4: "(?:^\\[([^]]+)\\]|- ?([^-]+)$)" +consistent!(media_filename_2, "(?:^\\[([^]]+)\\]|- ?([^-]+)$)"); + +// media_filename-0.1.4: "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])" +consistent!(media_filename_3, "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])"); + +// media_filename-0.1.4: "[sS]([0-9]{1,2})" +consistent!(media_filename_4, "[sS]([0-9]{1,2})"); + +// media_filename-0.1.4: "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)" +consistent!(media_filename_5, "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)"); + +// media_filename-0.1.4: "((19[0-9]|20[01])[0-9])" +consistent!(media_filename_6, "((19[0-9]|20[01])[0-9])"); + +// media_filename-0.1.4: "((?i)xvid|x264|h\\.?264)" +consistent!(media_filename_7, "((?i)xvid|x264|h\\.?264)"); + +// media_filename-0.1.4: "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)" +consistent!(media_filename_8, "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)"); + +// media_filename-0.1.4: "\\[([0-9A-F]{8})\\]" +consistent!(media_filename_9, "\\[([0-9A-F]{8})\\]"); + +// termimage-0.3.2: r"(\d+)[xX](\d+)" +consistent!(termimage_0, r"(\d+)[xX](\d+)"); + +// teensy-0.1.0: r".*(\d{4}-\d{2}-\d{2}).*" +consistent!(teensy_0, r".*(\d{4}-\d{2}-\d{2}).*"); + +// telescreen-0.1.3: r"<@(.+)>" +consistent!(telescreen_0, r"<@(.+)>"); + +// tempus_fugit-0.4.4: r"^(\d+)" +consistent!(tempus_fugit_0, r"^(\d+)"); + +// fselect-0.4.1: "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" +consistent!(fselect_0, "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); + +// fselect-0.4.1: "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" +consistent!(fselect_1, "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); + +// fs_eventbridge-0.1.0: r"^([A-Z]+)(?:\s(.+))?\s*" +consistent!(fs_eventbridge_0, r"^([A-Z]+)(?:\s(.+))?\s*"); + +// joseki-0.0.1: r"(\w{1,2})\[(.+?)\]" +consistent!(joseki_0, r"(\w{1,2})\[(.+?)\]"); + +// tweetr-0.2.1: r"(?i)in (\d+) (second|minute|hour|day|week)s?" +consistent!(tweetr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); + +// bullet_core-0.1.1: "^(?u:[0-9])+" +consistent!(bullet_core_0, "^(?u:[0-9])+"); + +// bullet_core-0.1.1: "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+" +consistent!(bullet_core_1, "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+"); + +// bullet_core-0.1.1: "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-Ô¯Ô±-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-Û¦Û®-Û¯Ûº-Û¼Û¿-ۿܐ-ܐܒ-ܯݍ-Þ¥Þ±-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-à§¡à§°-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-à­¡à­±-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-á® á®®-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-á¾´á¾¶-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-á¿´á¿¶-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-â´§â´­-â´­â´°-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-ï©­ï©°-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ï¹´ï¹¶-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+" +consistent!(bullet_core_2, "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-Ô¯Ô±-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-Û¦Û®-Û¯Ûº-Û¼Û¿-ۿܐ-ܐܒ-ܯݍ-Þ¥Þ±-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-à§¡à§°-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-à­¡à­±-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-á® á®®-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-á¾´á¾¶-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-á¿´á¿¶-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-â´§â´­-â´­â´°-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-ï©­ï©°-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ï¹´ï¹¶-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+"); + +// bullet_core-0.1.1: "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-Ô¯Ô±-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-Û¦Û®-Û¯Ûº-Û¼Û¿-ۿܐ-ܐܒ-ܯݍ-Þ¥Þ±-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-à§¡à§°-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-à­¡à­±-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-á® á®®-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-á¾´á¾¶-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-á¿´á¿¶-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-â´§â´­-â´­â´°-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-ï©­ï©°-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ï¹´ï¹¶-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)" +consistent!(bullet_core_3, "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-Ô¯Ô±-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-Û¦Û®-Û¯Ûº-Û¼Û¿-ۿܐ-ܐܒ-ܯݍ-Þ¥Þ±-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-à§¡à§°-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-à­¡à­±-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-á® á®®-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-á¾´á¾¶-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-á¿´á¿¶-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-â´§â´­-â´­â´°-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-ï©­ï©°-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ï¹´ï¹¶-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)"); + +// bullet_core-0.1.1: "^(?u:\\()" +consistent!(bullet_core_4, "^(?u:\\()"); + +// bullet_core-0.1.1: "^(?u:\\))" +consistent!(bullet_core_5, "^(?u:\\))"); + +// bullet_core-0.1.1: "^(?u:\\*)" +consistent!(bullet_core_6, "^(?u:\\*)"); + +// bullet_core-0.1.1: "^(?u:\\+)" +consistent!(bullet_core_7, "^(?u:\\+)"); + +// bullet_core-0.1.1: "^(?u:,)" +consistent!(bullet_core_8, "^(?u:,)"); + +// bullet_core-0.1.1: "^(?u:\\-)" +consistent!(bullet_core_9, "^(?u:\\-)"); + +// bullet_core-0.1.1: "^(?u:/)" +consistent!(bullet_core_10, "^(?u:/)"); + +// bullet_core-0.1.1: "^(?u:\\[)" +consistent!(bullet_core_11, "^(?u:\\[)"); + +// bullet_core-0.1.1: "^(?u:\\])" +consistent!(bullet_core_12, "^(?u:\\])"); + +// bullet_core-0.1.1: "^(?u:\\^)" +consistent!(bullet_core_13, "^(?u:\\^)"); + +// bullet_core-0.1.1: "^(?u:·)" +consistent!(bullet_core_14, "^(?u:·)"); + +// actix-web-0.6.13: "//+" +consistent!(actix_web_0, "//+"); + +// actix-web-0.6.13: "//+" +consistent!(actix_web_1, "//+"); + +// althea_kernel_interface-0.1.0: r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)" +consistent!(althea_kernel_interface_0, r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)"); + +// althea_kernel_interface-0.1.0: r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)" +consistent!(althea_kernel_interface_1, r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)"); + +// alcibiades-0.3.0: r"\buci(?:\s|$)" +consistent!(alcibiades_0, r"\buci(?:\s|$)"); + +// ruma-identifiers-0.11.0: r"\A[a-z0-9._=-]+\z" +consistent!(ruma_identifiers_0, r"\A[a-z0-9._=-]+\z"); + +// rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$" +consistent!(rusqbin_0, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$"); + +// rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$" +consistent!(rusqbin_1, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$"); + +// rust-install-0.0.4: r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$" +consistent!(rust_install_0, r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$"); + +// rust_inbox-0.0.5: "^+(.*)\r\n" +consistent!(rust_inbox_0, "^+(.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* CAPABILITY (.*)\r\n" +consistent!(rust_inbox_1, r"^\* CAPABILITY (.*)\r\n"); + +// rust_inbox-0.0.5: r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)" +consistent!(rust_inbox_2, r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)"); + +// rust_inbox-0.0.5: r"^\* (\d+) EXISTS\r\n" +consistent!(rust_inbox_3, r"^\* (\d+) EXISTS\r\n"); + +// rust_inbox-0.0.5: r"^\* (\d+) RECENT\r\n" +consistent!(rust_inbox_4, r"^\* (\d+) RECENT\r\n"); + +// rust_inbox-0.0.5: r"^\* FLAGS (.+)\r\n" +consistent!(rust_inbox_5, r"^\* FLAGS (.+)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UNSEEN (\d+)\](.*)\r\n" +consistent!(rust_inbox_6, r"^\* OK \[UNSEEN (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n" +consistent!(rust_inbox_7, r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n" +consistent!(rust_inbox_8, r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n" +consistent!(rust_inbox_9, r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_0, r"^[a-z]+ (\d+)$"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_1, r"^[a-z]+ (\d+)$"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_2, r"^[a-z]+ (\d+)$"); + +// rustfmt-0.10.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-core-0.4.0: r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)" +consistent!(rustfmt_core_0, r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)"); + +// rustfmt-core-0.4.0: r"^## `([^`]+)`" +consistent!(rustfmt_core_1, r"^## `([^`]+)`"); + +// rustfmt-core-0.4.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_core_2, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-core-0.4.0: r"\s;" +consistent!(rustfmt_core_3, r"\s;"); + +// rust-enum-derive-0.4.0: r"^(0x)?([:digit:]+)$" +consistent!(rust_enum_derive_0, r"^(0x)?([:digit:]+)$"); + +// rust-enum-derive-0.4.0: r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$" +consistent!(rust_enum_derive_1, r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$"); + +// rust-enum-derive-0.4.0: r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*," +consistent!(rust_enum_derive_2, r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*,"); + +// rust-enum-derive-0.4.0: r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)" +consistent!(rust_enum_derive_3, r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)"); + +// rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" +consistent!(rustsourcebundler_0, r"^\s*pub mod (.+);$"); + +// rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" +consistent!(rustsourcebundler_1, r"^\s*pub mod (.+);$"); + +// rustfmt-nightly-0.8.2: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_nightly_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-nightly-0.8.2: r"\s;" +consistent!(rustfmt_nightly_1, r"\s;"); + +// rustache-0.1.0: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" +consistent!(rustache_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); + +// rustfilt-0.2.0: r"_ZN[\$\._[:alnum:]]*" +consistent!(rustfilt_0, r"_ZN[\$\._[:alnum:]]*"); + +// rustache-lists-0.1.2: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" +consistent!(rustache_lists_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); + +// rural-0.7.3: "(.+)=(.+)" +consistent!(rural_0, "(.+)=(.+)"); + +// rural-0.7.3: "(.*):(.+)" +consistent!(rural_1, "(.*):(.+)"); + +// rural-0.7.3: "(.+):=(.+)" +consistent!(rural_2, "(.+):=(.+)"); + +// rural-0.7.3: "(.*)==(.+)" +consistent!(rural_3, "(.*)==(.+)"); + +// rusoto_credential-0.11.0: r"^\[([^\]]+)\]$" +consistent!(rusoto_credential_0, r"^\[([^\]]+)\]$"); + +// rumblebars-0.3.0: "([:blank:]*)$" +consistent!(rumblebars_0, "([:blank:]*)$"); + +// rumblebars-0.3.0: "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" +consistent!(rumblebars_1, "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); + +// rumblebars-0.3.0: "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" +consistent!(rumblebars_2, "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); + +// rumblebars-0.3.0: "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$" +consistent!(rumblebars_3, "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$"); + +// rumblebars-0.3.0: "^([:blank:]*\r?\n)(.*)" +consistent!(rumblebars_4, "^([:blank:]*\r?\n)(.*)"); + +// diesel_cli-1.3.1: r"(?P<stamp>[\d-]*)_hello" +consistent!(diesel_cli_0, r"(?P<stamp>[\d-]*)_hello"); + +// dishub-0.1.1: r"(\d+)s" +consistent!(dishub_0, r"(\d+)s"); + +// spreadsheet_textconv-0.1.0: r"\n" +consistent!(spreadsheet_textconv_0, r"\n"); + +// spreadsheet_textconv-0.1.0: r"\r" +consistent!(spreadsheet_textconv_1, r"\r"); + +// spreadsheet_textconv-0.1.0: r"\t" +consistent!(spreadsheet_textconv_2, r"\t"); + +// split_aud-0.1.0: r"DELAY (-?\d+)ms" +consistent!(split_aud_0, r"DELAY (-?\d+)ms"); + +// split_aud-0.1.0: r"Trim\((\d+), ?(\d+)\)" +consistent!(split_aud_1, r"Trim\((\d+), ?(\d+)\)"); + +// spotrust-0.0.5: r"spotify:[a-z]+:[a-zA-Z0-9]+" +consistent!(spotrust_0, r"spotify:[a-z]+:[a-zA-Z0-9]+"); + +// spaceslugs-0.1.0: r"[^\x00-\x7F]" +consistent!(spaceslugs_0, r"[^\x00-\x7F]"); + +// spaceslugs-0.1.0: r"[']+" +consistent!(spaceslugs_1, r"[']+"); + +// spaceslugs-0.1.0: r"\W+" +consistent!(spaceslugs_2, r"\W+"); + +// spaceslugs-0.1.0: r"[ ]+" +consistent!(spaceslugs_3, r"[ ]+"); + +// space_email_api-0.1.1: "PHPSESSID=([0-9a-f]+)" +consistent!(space_email_api_0, "PHPSESSID=([0-9a-f]+)"); + +// lorikeet-0.7.0: "[^0-9.,]" +consistent!(lorikeet_0, "[^0-9.,]"); + +// claude-0.3.0: r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$" +consistent!(claude_0, r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$"); + +// clam-0.1.6: r"<%=\s*(.+?)\s*%>" +consistent!(clam_0, r"<%=\s*(.+?)\s*%>"); + +// classifier-0.0.3: r"(\s)" +consistent!(classifier_0, r"(\s)"); + +// click-0.3.2: r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)" +consistent!(click_0, r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)"); + +// click-0.3.2: r"-----BEGIN PRIVATE KEY-----" +consistent!(click_1, r"-----BEGIN PRIVATE KEY-----"); + +// ultrastar-txt-0.1.2: r"#([A-Z3a-z]*):(.*)" +consistent!(ultrastar_txt_0, r"#([A-Z3a-z]*):(.*)"); + +// ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s*$" +consistent!(ultrastar_txt_1, "^-\\s?(-?[0-9]+)\\s*$"); + +// ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)" +consistent!(ultrastar_txt_2, "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)"); + +// ultrastar-txt-0.1.2: "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)" +consistent!(ultrastar_txt_3, "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)"); + +// ultrastar-txt-0.1.2: "^P\\s?(-?[0-9]+)" +consistent!(ultrastar_txt_4, "^P\\s?(-?[0-9]+)"); + +// db-accelerate-2.0.0: r"^template\.add($|\..+$)" +consistent!(db_accelerate_0, r"^template\.add($|\..+$)"); + +// db-accelerate-2.0.0: r"^template\.sub($|\..+$)" +consistent!(db_accelerate_1, r"^template\.sub($|\..+$)"); + +// sterling-0.3.0: r"(\d+)([cegps])" +consistent!(sterling_0, r"(\d+)([cegps])"); + +// stache-0.2.0: r"[^\w]" +consistent!(stache_0, r"[^\w]"); + +// strukt-0.1.0: "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\"" +consistent!(strukt_0, "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\""); + +// steamid-ng-0.3.1: r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$" +consistent!(steamid_ng_0, r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$"); + +// steamid-ng-0.3.1: r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$" +consistent!(steamid_ng_1, r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$"); + +// strscan-0.1.1: r"^\w+" +consistent!(strscan_0, r"^\w+"); + +// strscan-0.1.1: r"^\s+" +consistent!(strscan_1, r"^\s+"); + +// strscan-0.1.1: r"^\w+" +consistent!(strscan_2, r"^\w+"); + +// strscan-0.1.1: r"^\s+" +consistent!(strscan_3, r"^\s+"); + +// strscan-0.1.1: r"^(\w+)\s+" +consistent!(strscan_4, r"^(\w+)\s+"); + +// tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" +consistent!(tk_carbon_0, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); + +// tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" +consistent!(tk_carbon_1, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); + +// evalrs-0.0.10: r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?" +consistent!(evalrs_0, r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?"); + +// evalrs-0.0.10: r"(?m)^# " +consistent!(evalrs_1, r"(?m)^# "); + +// evalrs-0.0.10: r"(?m)^\s*fn +main *\( *\)" +consistent!(evalrs_2, r"(?m)^\s*fn +main *\( *\)"); + +// evalrs-0.0.10: r"(extern\s+crate\s+[a-z0-9_]+\s*;)" +consistent!(evalrs_3, r"(extern\s+crate\s+[a-z0-9_]+\s*;)"); + +// gate_build-0.5.0: "(.*)_t([0-9]+)" +consistent!(gate_build_0, "(.*)_t([0-9]+)"); + +// rake-0.1.1: r"[^\P{P}-]|\s+-\s+" +consistent!(rake_0, r"[^\P{P}-]|\s+-\s+"); + +// rafy-0.2.1: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" +consistent!(rafy_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); + +// raven-0.2.1: r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$" +consistent!(raven_0, r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$"); + +// rargs-0.2.0: r"\{[[:space:]]*[^{}]*[[:space:]]*\}" +consistent!(rargs_0, r"\{[[:space:]]*[^{}]*[[:space:]]*\}"); + +// rargs-0.2.0: r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$" +consistent!(rargs_1, r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$"); + +// rargs-0.2.0: r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$" +consistent!(rargs_2, r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$"); + +// rargs-0.2.0: r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$" +consistent!(rargs_3, r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$"); + +// rargs-0.2.0: r"(.*?)[[:space:]]+|(.*?)$" +consistent!(rargs_4, r"(.*?)[[:space:]]+|(.*?)$"); + +// indradb-lib-0.15.0: r"[a-zA-Z0-9]{8}" +consistent!(indradb_lib_0, r"[a-zA-Z0-9]{8}"); + +// fungi-lang-0.1.50: r"::" +consistent!(fungi_lang_0, r"::"); + +// nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" +consistent!(nickel_0, "/hello/(?P<name>[a-zA-Z]+)"); + +// nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" +consistent!(nickel_1, "/hello/(?P<name>[a-zA-Z]+)"); + +// pact_verifier-0.4.0: r"\{(\w+)\}" +consistent!(pact_verifier_0, r"\{(\w+)\}"); + +// pact_matching-0.4.1: "application/.*json" +consistent!(pact_matching_0, "application/.*json"); + +// pact_matching-0.4.1: "application/json.*" +consistent!(pact_matching_1, "application/json.*"); + +// pact_matching-0.4.1: "application/.*xml" +consistent!(pact_matching_2, "application/.*xml"); + +// pangu-0.2.0: "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])" +consistent!(pangu_0, "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])"); + +// pangu-0.2.0: "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)" +consistent!(pangu_1, "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)"); + +// parser-haskell-0.2.0: r"\{-[\s\S]*?-\}" +consistent!(parser_haskell_0, r"\{-[\s\S]*?-\}"); + +// parser-haskell-0.2.0: r"(?m);+\s*$" +consistent!(parser_haskell_1, r"(?m);+\s*$"); + +// parser-haskell-0.2.0: r"(?m)^#(if|ifn?def|endif|else|include|elif).*" +consistent!(parser_haskell_2, r"(?m)^#(if|ifn?def|endif|else|include|elif).*"); + +// parser-haskell-0.2.0: r"'([^'\\]|\\[A-Z]{1,3}|\\.)'" +consistent!(parser_haskell_3, r"'([^'\\]|\\[A-Z]{1,3}|\\.)'"); + +// parser-haskell-0.2.0: r"forall\s+(.*?)\." +consistent!(parser_haskell_4, r"forall\s+(.*?)\."); + +// html2md-0.2.1: "\\s{2,}" +consistent!(html2md_0, "\\s{2,}"); + +// html2md-0.2.1: "\\n{2,}" +consistent!(html2md_1, "\\n{2,}"); + +// html2md-0.2.1: "(?m)(\\S) $" +consistent!(html2md_2, "(?m)(\\S) $"); + +// html2md-0.2.1: "(?m)^[-*] " +consistent!(html2md_3, "(?m)^[-*] "); + +// ovpnfile-0.1.2: r"#.*$" +consistent!(ovpnfile_0, r"#.*$"); + +// ovpnfile-0.1.2: r"^<(\S+)>" +consistent!(ovpnfile_1, r"^<(\S+)>"); + +// ovpnfile-0.1.2: r"^</(\S+)>" +consistent!(ovpnfile_2, r"^</(\S+)>"); + +// screenruster-saver-fractal-0.1.1: r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})" +consistent!(screenruster_saver_fractal_0, r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})"); + +// scarlet-0.2.2: r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)" +consistent!(scarlet_0, r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)"); + +// cpp_to_rust_generator-0.2.0: r"^([\w:]+)<(.+)>$" +consistent!(cpp_to_rust_generator_0, r"^([\w:]+)<(.+)>$"); + +// cpp_to_rust_generator-0.2.0: r"^type-parameter-(\d+)-(\d+)$" +consistent!(cpp_to_rust_generator_1, r"^type-parameter-(\d+)-(\d+)$"); + +// cpp_to_rust_generator-0.2.0: r"^([\w~]+)<[^<>]+>$" +consistent!(cpp_to_rust_generator_2, r"^([\w~]+)<[^<>]+>$"); + +// cpp_to_rust_generator-0.2.0: r"(signals|Q_SIGNALS)\s*:" +consistent!(cpp_to_rust_generator_3, r"(signals|Q_SIGNALS)\s*:"); + +// cpp_to_rust_generator-0.2.0: r"(slots|Q_SLOTS)\s*:" +consistent!(cpp_to_rust_generator_4, r"(slots|Q_SLOTS)\s*:"); + +// cpp_to_rust_generator-0.2.0: r"(public|protected|private)\s*:" +consistent!(cpp_to_rust_generator_5, r"(public|protected|private)\s*:"); + +// cpp_to_rust-0.5.3: r"^([\w:]+)<(.+)>$" +consistent!(cpp_to_rust_0, r"^([\w:]+)<(.+)>$"); + +// cpp_to_rust-0.5.3: r"^type-parameter-(\d+)-(\d+)$" +consistent!(cpp_to_rust_1, r"^type-parameter-(\d+)-(\d+)$"); + +// cpp_to_rust-0.5.3: r"^([\w~]+)<[^<>]+>$" +consistent!(cpp_to_rust_2, r"^([\w~]+)<[^<>]+>$"); + +// cpp_to_rust-0.5.3: r"(signals|Q_SIGNALS)\s*:" +consistent!(cpp_to_rust_3, r"(signals|Q_SIGNALS)\s*:"); + +// cpp_to_rust-0.5.3: r"(slots|Q_SLOTS)\s*:" +consistent!(cpp_to_rust_4, r"(slots|Q_SLOTS)\s*:"); + +// cpp_to_rust-0.5.3: r"(public|protected|private)\s*:" +consistent!(cpp_to_rust_5, r"(public|protected|private)\s*:"); + +// fritzbox_logs-0.2.0: "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)" +consistent!(fritzbox_logs_0, "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)"); + +// fractal-matrix-api-3.29.0: r"mxc://(?P<server>[^/]+)/(?P<media>.+)" +consistent!(fractal_matrix_api_0, r"mxc://(?P<server>[^/]+)/(?P<media>.+)"); + +// smtp2go-0.1.4: r"^api-[a-zA-Z0-9]{32}$" +consistent!(smtp2go_0, r"^api-[a-zA-Z0-9]{32}$"); + +// pusher-0.3.1: r"^[-a-zA-Z0-9_=@,.;]+$" +consistent!(pusher_0, r"^[-a-zA-Z0-9_=@,.;]+$"); + +// pusher-0.3.1: r"\A\d+\.\d+\z" +consistent!(pusher_1, r"\A\d+\.\d+\z"); + +// bakervm-0.9.0: r"^\.(.+?) +?(.+)$" +consistent!(bakervm_0, r"^\.(.+?) +?(.+)$"); + +// bakervm-0.9.0: r"^\.([^\s]+)$" +consistent!(bakervm_1, r"^\.([^\s]+)$"); + +// bakervm-0.9.0: r"^include! +([^\s]+)$" +consistent!(bakervm_2, r"^include! +([^\s]+)$"); + +// bakervm-0.9.0: r"^@(\d+)$" +consistent!(bakervm_3, r"^@(\d+)$"); + +// bakervm-0.9.0: r"^true|false$" +consistent!(bakervm_4, r"^true|false$"); + +// bakervm-0.9.0: r"^(-?\d+)?\.[0-9]+$" +consistent!(bakervm_5, r"^(-?\d+)?\.[0-9]+$"); + +// bakervm-0.9.0: r"^(-?\d+)?$" +consistent!(bakervm_6, r"^(-?\d+)?$"); + +// bakervm-0.9.0: r"^#([0-9abcdefABCDEF]{6})$" +consistent!(bakervm_7, r"^#([0-9abcdefABCDEF]{6})$"); + +// bakervm-0.9.0: r"^'(.)'$" +consistent!(bakervm_8, r"^'(.)'$"); + +// bakervm-0.9.0: r"^\$vi\((\d+)\)$" +consistent!(bakervm_9, r"^\$vi\((\d+)\)$"); + +// bakervm-0.9.0: r"^\$key\((\d+)\)$" +consistent!(bakervm_10, r"^\$key\((\d+)\)$"); + +// banana-0.0.2: "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)" +consistent!(banana_0, "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)"); + +// serial-key-2.0.0: r"[A-F0-9]{8}" +consistent!(serial_key_0, r"[A-F0-9]{8}"); + +// serde-hjson-0.8.1: "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_0, "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-hjson-0.8.1: "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_1, "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-hjson-0.8.1: "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_2, "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-odbc-0.1.0: r"/todos/(?P<id>\d+)" +consistent!(serde_odbc_0, r"/todos/(?P<id>\d+)"); + +// sentry-0.6.0: r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)" +consistent!(sentry_0, r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)"); + +// sentiment-0.1.1: r"[^a-zA-Z0 -]+" +consistent!(sentiment_0, r"[^a-zA-Z0 -]+"); + +// sentiment-0.1.1: r" {2,}" +consistent!(sentiment_1, r" {2,}"); + +// verilog-0.0.1: r"(?m)//.*" +consistent!(verilog_0, r"(?m)//.*"); + +// verex-0.2.2: "(?P<robot>C3PO)" +consistent!(verex_0, "(?P<robot>C3PO)"); + +// handlebars-0.32.4: ">|<|\"|&" +consistent!(handlebars_0, ">|<|\"|&"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789]{4}$" +consistent!(haikunator_0, r"^\w+-\w+-[0123456789]{4}$"); + +// haikunator-0.1.2: r"^\w+@\w+@[0123456789]{4}$" +consistent!(haikunator_1, r"^\w+@\w+@[0123456789]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789abcdef]{4}$" +consistent!(haikunator_2, r"^\w+-\w+-[0123456789abcdef]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$" +consistent!(haikunator_3, r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$"); + +// haikunator-0.1.2: r"^\w+-\w+$" +consistent!(haikunator_4, r"^\w+-\w+$"); + +// haikunator-0.1.2: r"^\w+-\w+-[foo]{4}$" +consistent!(haikunator_5, r"^\w+-\w+-[foo]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$" +consistent!(haikunator_6, r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$"); + +// bobbin-cli-0.8.3: r"(.*)" +consistent!(bobbin_cli_0, r"(.*)"); + +// bobbin-cli-0.8.3: r"rustc (.*)" +consistent!(bobbin_cli_1, r"rustc (.*)"); + +// bobbin-cli-0.8.3: r"cargo (.*)" +consistent!(bobbin_cli_2, r"cargo (.*)"); + +// bobbin-cli-0.8.3: r"xargo (.*)\n" +consistent!(bobbin_cli_3, r"xargo (.*)\n"); + +// bobbin-cli-0.8.3: r"Open On-Chip Debugger (.*)" +consistent!(bobbin_cli_4, r"Open On-Chip Debugger (.*)"); + +// bobbin-cli-0.8.3: r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)" +consistent!(bobbin_cli_5, r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)"); + +// bobbin-cli-0.8.3: r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n" +consistent!(bobbin_cli_6, r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n"); + +// bobbin-cli-0.8.3: r"(?m)SEGGER J-Link Commander (.*)\n" +consistent!(bobbin_cli_7, r"(?m)SEGGER J-Link Commander (.*)\n"); + +// bobbin-cli-0.8.3: r"(?m)Teensy Loader, Command Line, Version (.*)\n" +consistent!(bobbin_cli_8, r"(?m)Teensy Loader, Command Line, Version (.*)\n"); + +// bobbin-cli-0.8.3: r"dfu-util (.*)\n" +consistent!(bobbin_cli_9, r"dfu-util (.*)\n"); + +// borsholder-0.9.1: r"^/static/[\w.]+$" +consistent!(borsholder_0, r"^/static/[\w.]+$"); + +// borsholder-0.9.1: r"^/timeline/([0-9]+)$" +consistent!(borsholder_1, r"^/timeline/([0-9]+)$"); + +// fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" +consistent!(fblog_0, "\u{001B}\\[[\\d;]*[^\\d;]"); + +// fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" +consistent!(fblog_1, "\u{001B}\\[[\\d;]*[^\\d;]"); + +// toml-query-0.6.0: r"^\[\d+\]$" +consistent!(toml_query_0, r"^\[\d+\]$"); + +// todo-txt-1.1.0: r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)" +consistent!(todo_txt_0, r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)"); + +// findr-0.1.5: r"\band\b" +consistent!(findr_0, r"\band\b"); + +// findr-0.1.5: r"\bor\b" +consistent!(findr_1, r"\bor\b"); + +// findr-0.1.5: r"\bnot\b" +consistent!(findr_2, r"\bnot\b"); + +// file-sniffer-3.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(file_sniffer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*|dat|pc|info)$" +consistent!(file_sniffer_1, r".*?\.(stats|conf|h|cache.*|dat|pc|info)$"); + +// file-sniffer-3.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(file_sniffer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*)$" +consistent!(file_sniffer_3, r".*?\.(stats|conf|h|cache.*)$"); + +// file-sniffer-3.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(file_sniffer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// file_logger-0.1.0: "test" +consistent!(file_logger_0, "test"); + +// file_scanner-0.2.0: r"foo" +consistent!(file_scanner_0, r"foo"); + +// file_scanner-0.2.0: r"a+b" +consistent!(file_scanner_1, r"a+b"); + +// file_scanner-0.2.0: r"a[ab]*b" +consistent!(file_scanner_2, r"a[ab]*b"); + +// file_scanner-0.2.0: r"\s+" +consistent!(file_scanner_3, r"\s+"); + +// file_scanner-0.2.0: r"\s+" +consistent!(file_scanner_4, r"\s+"); + +// cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" +consistent!(cellsplit_0, r"^\s*([^\s]+) %cellsplit<\d+>$"); + +// cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" +consistent!(cellsplit_1, r"^\s*([^\s]+) %cellsplit<\d+>$"); + +// aterm-0.20.0: r"^[+\-]?[0-9]+" +consistent!(aterm_0, r"^[+\-]?[0-9]+"); + +// aterm-0.20.0: r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?" +consistent!(aterm_1, r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?"); + +// atarashii_imap-0.3.0: r"^[*] OK" +consistent!(atarashii_imap_0, r"^[*] OK"); + +// atarashii_imap-0.3.0: r"FLAGS\s\((.+)\)" +consistent!(atarashii_imap_1, r"FLAGS\s\((.+)\)"); + +// atarashii_imap-0.3.0: r"\[PERMANENTFLAGS\s\((.+)\)\]" +consistent!(atarashii_imap_2, r"\[PERMANENTFLAGS\s\((.+)\)\]"); + +// atarashii_imap-0.3.0: r"\[UIDVALIDITY\s(\d+)\]" +consistent!(atarashii_imap_3, r"\[UIDVALIDITY\s(\d+)\]"); + +// atarashii_imap-0.3.0: r"(\d+)\sEXISTS" +consistent!(atarashii_imap_4, r"(\d+)\sEXISTS"); + +// atarashii_imap-0.3.0: r"(\d+)\sRECENT" +consistent!(atarashii_imap_5, r"(\d+)\sRECENT"); + +// atarashii_imap-0.3.0: r"\[UNSEEN\s(\d+)\]" +consistent!(atarashii_imap_6, r"\[UNSEEN\s(\d+)\]"); + +// atarashii_imap-0.3.0: r"\[UIDNEXT\s(\d+)\]" +consistent!(atarashii_imap_7, r"\[UIDNEXT\s(\d+)\]"); + +// editorconfig-1.0.0: r"\\(\{|\})" +consistent!(editorconfig_0, r"\\(\{|\})"); + +// editorconfig-1.0.0: r"(^|[^\\])\\\|" +consistent!(editorconfig_1, r"(^|[^\\])\\\|"); + +// editorconfig-1.0.0: r"\[([^\]]*)$" +consistent!(editorconfig_2, r"\[([^\]]*)$"); + +// editorconfig-1.0.0: r"\[(.*/.*)\]" +consistent!(editorconfig_3, r"\[(.*/.*)\]"); + +// editorconfig-1.0.0: r"\{(-?\d+\\\.\\\.-?\d+)\}" +consistent!(editorconfig_4, r"\{(-?\d+\\\.\\\.-?\d+)\}"); + +// editorconfig-1.0.0: r"\{([^,]+)\}" +consistent!(editorconfig_5, r"\{([^,]+)\}"); + +// editorconfig-1.0.0: r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}" +consistent!(editorconfig_6, r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}"); + +// editorconfig-1.0.0: r"^/" +consistent!(editorconfig_7, r"^/"); + +// editorconfig-1.0.0: r"(^|[^\\])(\{|\})" +consistent!(editorconfig_8, r"(^|[^\\])(\{|\})"); + +// edmunge-1.0.0: "^#!.*\n" +consistent!(edmunge_0, "^#!.*\n"); + +// unicode_names2_macros-0.2.0: r"\\N\{(.*?)(?:\}|$)" +consistent!(unicode_names2_macros_0, r"\\N\{(.*?)(?:\}|$)"); + +// unidiff-0.2.1: r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" +consistent!(unidiff_0, r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); + +// unidiff-0.2.1: r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" +consistent!(unidiff_1, r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); + +// unidiff-0.2.1: r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)" +consistent!(unidiff_2, r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)"); + +// unidiff-0.2.1: r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)" +consistent!(unidiff_3, r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)"); + +// slippy-map-tiles-0.13.1: "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$" +consistent!(slippy_map_tiles_0, "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$"); + +// slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" +consistent!(slippy_map_tiles_1, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); + +// slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" +consistent!(slippy_map_tiles_2, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); + +// sonos-0.1.2: r"^https?://(.+?):1400/xml" +consistent!(sonos_0, r"^https?://(.+?):1400/xml"); + +// validator_derive-0.7.0: r"^[a-z]{2}$" +consistent!(validator_derive_0, r"^[a-z]{2}$"); + +// validator_derive-0.7.0: r"[a-z]{2}" +consistent!(validator_derive_1, r"[a-z]{2}"); + +// validator_derive-0.7.0: r"[a-z]{2}" +consistent!(validator_derive_2, r"[a-z]{2}"); + +// nginx-config-0.8.0: r"one of \d+ options" +consistent!(nginx_config_0, r"one of \d+ options"); + +// waltz-0.4.0: r"[\s,]" +consistent!(waltz_0, r"[\s,]"); + +// warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" +consistent!(warheadhateus_0, r"^aws_access_key_id = (.*)"); + +// warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" +consistent!(warheadhateus_1, r"^aws_secret_access_key = (.*)"); + +// warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" +consistent!(warheadhateus_2, r"^aws_access_key_id = (.*)"); + +// warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" +consistent!(warheadhateus_3, r"^aws_secret_access_key = (.*)"); + +// jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)" +consistent!(jieba_rs_0, r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)"); + +// jieba-rs-0.2.2: r"(\r\n|\s)" +consistent!(jieba_rs_1, r"(\r\n|\s)"); + +// jieba-rs-0.2.2: "([\u{4E00}-\u{9FD5}]+)" +consistent!(jieba_rs_2, "([\u{4E00}-\u{9FD5}]+)"); + +// jieba-rs-0.2.2: r"[^a-zA-Z0-9+#\n]" +consistent!(jieba_rs_3, r"[^a-zA-Z0-9+#\n]"); + +// jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}]+)" +consistent!(jieba_rs_4, r"([\u{4E00}-\u{9FD5}]+)"); + +// jieba-rs-0.2.2: r"([a-zA-Z0-9]+(?:.\d+)?%?)" +consistent!(jieba_rs_5, r"([a-zA-Z0-9]+(?:.\d+)?%?)"); + +// lalrpop-0.15.2: r"Span\([0-9 ,]*\)" +consistent!(lalrpop_0, r"Span\([0-9 ,]*\)"); + +// lalrpop-snap-0.15.2: r"Span\([0-9 ,]*\)" +consistent!(lalrpop_snap_0, r"Span\([0-9 ,]*\)"); + +// nlp-tokenize-0.1.0: r"[\S]+" +consistent!(nlp_tokenize_0, r"[\S]+"); + +// kbgpg-0.1.2: "[[:xdigit:]][70]" +consistent!(kbgpg_0, "[[:xdigit:]][70]"); + +// cdbd-0.1.1: r"^((?P<address>.*):)?(?P<port>\d+)$" +consistent!(cdbd_0, r"^((?P<address>.*):)?(?P<port>\d+)$"); + +// mbutiles-0.1.1: r"[\w\s=+-/]+\((\{(.|\n)*\})\);?" +consistent!(mbutiles_0, r"[\w\s=+-/]+\((\{(.|\n)*\})\);?"); + +// extrahop-0.2.5: r"^-\d+(?:ms|s|m|h|d|w|y)?$" +consistent!(extrahop_0, r"^-\d+(?:ms|s|m|h|d|w|y)?$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" +consistent!(pippin_0, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" +consistent!(pippin_1, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" +consistent!(pippin_2, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" +consistent!(pippin_3, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); + +// pippin-0.1.0: "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$" +consistent!(pippin_4, "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$"); + +// pippin-0.1.0: "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$" +consistent!(pippin_5, "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$"); + +// pinyin-0.3.0: r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]" +consistent!(pinyin_0, r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]"); + +// pinyin-0.3.0: r"([aeoiuvnm])([0-4])$" +consistent!(pinyin_1, r"([aeoiuvnm])([0-4])$"); + +// duration-parser-0.2.0: r"(?P<value>\d+)(?P<units>[a-z])" +consistent!(duration_parser_0, r"(?P<value>\d+)(?P<units>[a-z])"); + +// dutree-0.2.7: r"^\d+\D?$" +consistent!(dutree_0, r"^\d+\D?$"); + +// djangohashers-0.3.0: r"^[A-Za-z0-9]*$" +consistent!(djangohashers_0, r"^[A-Za-z0-9]*$"); + +// rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}$" +consistent!(rtag_0, r"^[A-Z][A-Z0-9]{2,}$"); + +// rtag-0.3.5: r"^http://www\.emusic\.com" +consistent!(rtag_1, r"^http://www\.emusic\.com"); + +// rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}" +consistent!(rtag_2, r"^[A-Z][A-Z0-9]{2,}"); + +// rtag-0.3.5: r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)" +consistent!(rtag_3, r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)"); + +// rtow-0.1.0: r"(\d+)[xX](\d+)" +consistent!(rtow_0, r"(\d+)[xX](\d+)"); + +// pleingres-sql-plugin-0.1.0: r"\$([a-zA-Z0-9_]+)" +consistent!(pleingres_sql_plugin_0, r"\$([a-zA-Z0-9_]+)"); + +// dono-2.0.0: "[\\n]+" +consistent!(dono_0, "[\\n]+"); + +// dono-2.0.0: "(?m)^\\n" +consistent!(dono_1, "(?m)^\\n"); + +// dono-2.0.0: "(?m)^\\n" +consistent!(dono_2, "(?m)^\\n"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.ed25519$" +consistent!(ssb_common_0, r"^[0-9A-Za-z\+/]{43}=\.ed25519$"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{86}==\.ed25519$" +consistent!(ssb_common_1, r"^[0-9A-Za-z\+/]{86}==\.ed25519$"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.sha256$" +consistent!(ssb_common_2, r"^[0-9A-Za-z\+/]{43}=\.sha256$"); + +// mozversion-0.1.3: r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$" +consistent!(mozversion_0, r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$"); + +// monger-0.5.6: r"^(\d+)\.(\d+)$" +consistent!(monger_0, r"^(\d+)\.(\d+)$"); + +// mongo_rub-0.0.2: r"^[rv]2\.6" +consistent!(mongo_rub_0, r"^[rv]2\.6"); + +// flow-0.3.5: "body value" +consistent!(flow_0, "body value"); + +// flow-0.3.5: "start marker" +consistent!(flow_1, "start marker"); + +// flow-0.3.5: "end marker" +consistent!(flow_2, "end marker"); + +// flow-0.3.5: "body value" +consistent!(flow_3, "body value"); + +// vobsub-0.2.3: "^([A-Za-z/ ]+): (.*)" +consistent!(vobsub_0, "^([A-Za-z/ ]+): (.*)"); + +// voidmap-1.1.2: r"#([^\s=]+)*" +consistent!(voidmap_0, r"#([^\s=]+)*"); + +// voidmap-1.1.2: r"#(\S+)*" +consistent!(voidmap_1, r"#(\S+)*"); + +// voidmap-1.1.2: r"#prio=(\d+)" +consistent!(voidmap_2, r"#prio=(\d+)"); + +// voidmap-1.1.2: r"\[(\S+)\]" +consistent!(voidmap_3, r"\[(\S+)\]"); + +// voidmap-1.1.2: r"#limit=(\d+)" +consistent!(voidmap_4, r"#limit=(\d+)"); + +// voidmap-1.1.2: r"#tagged=(\S+)" +consistent!(voidmap_5, r"#tagged=(\S+)"); + +// voidmap-1.1.2: r"#rev\b" +consistent!(voidmap_6, r"#rev\b"); + +// voidmap-1.1.2: r"#done\b" +consistent!(voidmap_7, r"#done\b"); + +// voidmap-1.1.2: r"#open\b" +consistent!(voidmap_8, r"#open\b"); + +// voidmap-1.1.2: r"#since=(\S+)" +consistent!(voidmap_9, r"#since=(\S+)"); + +// voidmap-1.1.2: r"#until=(\S+)" +consistent!(voidmap_10, r"#until=(\S+)"); + +// voidmap-1.1.2: r"#plot=(\S+)" +consistent!(voidmap_11, r"#plot=(\S+)"); + +// voidmap-1.1.2: r"#n=(\d+)" +consistent!(voidmap_12, r"#n=(\d+)"); + +// voidmap-1.1.2: r"(\S+)" +consistent!(voidmap_13, r"(\S+)"); + +// voidmap-1.1.2: r"(?P<y>\d+)y" +consistent!(voidmap_14, r"(?P<y>\d+)y"); + +// voidmap-1.1.2: r"(?P<m>\d+)m" +consistent!(voidmap_15, r"(?P<m>\d+)m"); + +// voidmap-1.1.2: r"(?P<w>\d+)w" +consistent!(voidmap_16, r"(?P<w>\d+)w"); + +// voidmap-1.1.2: r"(?P<d>\d+)d" +consistent!(voidmap_17, r"(?P<d>\d+)d"); + +// voidmap-1.1.2: r"(?P<h>\d+)h" +consistent!(voidmap_18, r"(?P<h>\d+)h"); + +// voidmap-1.1.2: r"C-(.)" +consistent!(voidmap_19, r"C-(.)"); + +// qt_generator-0.2.0: r"^\.\./qt[^/]+/" +consistent!(qt_generator_0, r"^\.\./qt[^/]+/"); + +// qt_generator-0.2.0: "(href|src)=\"([^\"]*)\"" +consistent!(qt_generator_1, "(href|src)=\"([^\"]*)\""); + +// kryptos-0.6.1: r"[01]{5}" +consistent!(kryptos_0, r"[01]{5}"); + +// cifar_10_loader-0.2.0: "data_batch_[1-5].bin" +consistent!(cifar_10_loader_0, "data_batch_[1-5].bin"); + +// cifar_10_loader-0.2.0: "test_batch.bin" +consistent!(cifar_10_loader_1, "test_batch.bin"); + +// circadian-0.6.0: r"^\d+.\d+s$" +consistent!(circadian_0, r"^\d+.\d+s$"); + +// circadian-0.6.0: r"^\d+:\d+$" +consistent!(circadian_1, r"^\d+:\d+$"); + +// circadian-0.6.0: r"^\d+:\d+m$" +consistent!(circadian_2, r"^\d+:\d+m$"); + +// cicada-0.8.1: r"!!" +consistent!(cicada_0, r"!!"); + +// cicada-0.8.1: r"^([^`]*)`([^`]+)`(.*)$" +consistent!(cicada_1, r"^([^`]*)`([^`]+)`(.*)$"); + +// cicada-0.8.1: r"\*+" +consistent!(cicada_2, r"\*+"); + +// cicada-0.8.1: r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)" +consistent!(cicada_3, r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)"); + +// cicada-0.8.1: r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$" +consistent!(cicada_4, r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$"); + +// vterm-sys-0.1.0: r"hi" +consistent!(vterm_sys_0, r"hi"); + +// skim-0.5.0: r".*?\t" +consistent!(skim_0, r".*?\t"); + +// skim-0.5.0: r".*?[\t ]" +consistent!(skim_1, r".*?[\t ]"); + +// skim-0.5.0: r"(\{-?[0-9.,q]*?})" +consistent!(skim_2, r"(\{-?[0-9.,q]*?})"); + +// skim-0.5.0: r"[ \t\n]+" +consistent!(skim_3, r"[ \t\n]+"); + +// skim-0.5.0: r"[ \t\n]+" +consistent!(skim_4, r"[ \t\n]+"); + +// skim-0.5.0: r"([^ |]+( +\| +[^ |]*)+)|( +)" +consistent!(skim_5, r"([^ |]+( +\| +[^ |]*)+)|( +)"); + +// skim-0.5.0: r" +\| +" +consistent!(skim_6, r" +\| +"); + +// skim-0.5.0: r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$" +consistent!(skim_7, r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$"); + +// skim-0.5.0: "," +consistent!(skim_8, ","); + +// skim-0.5.0: ".*?," +consistent!(skim_9, ".*?,"); + +// skim-0.5.0: ".*?," +consistent!(skim_10, ".*?,"); + +// skim-0.5.0: "," +consistent!(skim_11, ","); + +// skim-0.5.0: r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))" +consistent!(skim_12, r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))"); + +// egg-mode-text-1.14.7: r"[-_./]\z" +consistent!(egg_mode_text_0, r"[-_./]\z"); + +// java-properties-1.1.1: "^[ \t\r\n\x0c]*[#!]" +consistent!(java_properties_0, "^[ \t\r\n\x0c]*[#!]"); + +// java-properties-1.1.1: r"^[ \t\x0c]*[#!][^\r\n]*$" +consistent!(java_properties_1, r"^[ \t\x0c]*[#!][^\r\n]*$"); + +// java-properties-1.1.1: r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$" +consistent!(java_properties_2, r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$"); + +// ipaddress-0.1.2: r":.+\." +consistent!(ipaddress_0, r":.+\."); + +// ipaddress-0.1.2: r"\." +consistent!(ipaddress_1, r"\."); + +// ipaddress-0.1.2: r":" +consistent!(ipaddress_2, r":"); + +// iptables-0.2.2: r"v(\d+)\.(\d+)\.(\d+)" +consistent!(iptables_0, r"v(\d+)\.(\d+)\.(\d+)"); + +// rsure-0.8.1: r"^([^-]+)-(.*)\.dat\.gz$" +consistent!(rsure_0, r"^([^-]+)-(.*)\.dat\.gz$"); + +// rs-jsonpath-0.1.0: "^(.*?)(<=|<|==|>=|>)(.*?)$" +consistent!(rs_jsonpath_0, "^(.*?)(<=|<|==|>=|>)(.*?)$"); + +// oatie-0.3.0: r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))" +consistent!(oatie_0, r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))"); + +// weld-0.2.0: "#.*$" +consistent!(weld_0, "#.*$"); + +// weld-0.2.0: r"^[A-Za-z$_][A-Za-z0-9$_]*$" +consistent!(weld_1, r"^[A-Za-z$_][A-Za-z0-9$_]*$"); + +// weld-0.2.0: r"^[0-9]+[cC]$" +consistent!(weld_2, r"^[0-9]+[cC]$"); + +// weld-0.2.0: r"^0b[0-1]+[cC]$" +consistent!(weld_3, r"^0b[0-1]+[cC]$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+[cC]$" +consistent!(weld_4, r"^0x[0-9a-fA-F]+[cC]$"); + +// weld-0.2.0: r"^[0-9]+$" +consistent!(weld_5, r"^[0-9]+$"); + +// weld-0.2.0: r"^0b[0-1]+$" +consistent!(weld_6, r"^0b[0-1]+$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+$" +consistent!(weld_7, r"^0x[0-9a-fA-F]+$"); + +// weld-0.2.0: r"^[0-9]+[lL]$" +consistent!(weld_8, r"^[0-9]+[lL]$"); + +// weld-0.2.0: r"^0b[0-1]+[lL]$" +consistent!(weld_9, r"^0b[0-1]+[lL]$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+[lL]$" +consistent!(weld_10, r"^0x[0-9a-fA-F]+[lL]$"); + +// webgl_generator-0.1.0: "([(, ])enum\\b" +consistent!(webgl_generator_0, "([(, ])enum\\b"); + +// webgl_generator-0.1.0: "\\bAcquireResourcesCallback\\b" +consistent!(webgl_generator_1, "\\bAcquireResourcesCallback\\b"); + +// weave-0.2.0: r"^(\d+)(,(\d+))?([acd]).*$" +consistent!(weave_0, r"^(\d+)(,(\d+))?([acd]).*$"); + +// wemo-0.0.12: r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>" +consistent!(wemo_0, r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>"); + +// webscale-0.9.4: r"(http[s]?://[^\s]+)" +consistent!(webscale_0, r"(http[s]?://[^\s]+)"); + +// svgrep-1.1.0: r"^\d+.*$" +consistent!(svgrep_0, r"^\d+.*$"); + +// ignore-0.4.2: r"^[\pL\pN]+$" +consistent!(ignore_0, r"^[\pL\pN]+$"); + +// ommui_string_patterns-0.1.2: r"^([A-Za-z][0-9A-Za-z_]*)?$" +consistent!(ommui_string_patterns_0, r"^([A-Za-z][0-9A-Za-z_]*)?$"); + +// ommui_string_patterns-0.1.2: r"^(\S+(?:.*\S)?)?$" +consistent!(ommui_string_patterns_1, r"^(\S+(?:.*\S)?)?$"); + +// opcua-types-0.3.0: "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$" +consistent!(opcua_types_0, "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$"); + +// opcua-types-0.3.0: r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$" +consistent!(opcua_types_1, r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$"); + +// open_read_later-1.1.1: r"^(.+?)\s*:\s*(.+)$" +consistent!(open_read_later_0, r"^(.+?)\s*:\s*(.+)$"); + +// youtube-downloader-0.1.0: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" +consistent!(youtube_downloader_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); + +// yobot-0.1.1: "." +consistent!(yobot_0, "."); + +// yobot-0.1.1: r"." +consistent!(yobot_1, r"."); + +// yobot-0.1.1: r".+" +consistent!(yobot_2, r".+"); + +// yobot-0.1.1: r"." +consistent!(yobot_3, r"."); + +// ubiquity-0.1.5: r"foo" +consistent!(ubiquity_0, r"foo"); + +// ubiquity-0.1.5: r"/target/" +consistent!(ubiquity_1, r"/target/"); + +// ubiquity-0.1.5: r".DS_Store" +consistent!(ubiquity_2, r".DS_Store"); + +// qasm-1.0.0: r"//.*" +consistent!(qasm_0, r"//.*"); + +// drill-0.3.5: r"\{\{ *([a-z\._]+) *\}\}" +consistent!(drill_0, r"\{\{ *([a-z\._]+) *\}\}"); + +// queryst-2.0.0: r"^([^\]\[]+)" +consistent!(queryst_0, r"^([^\]\[]+)"); + +// queryst-2.0.0: r"(\[[^\]\[]*\])" +consistent!(queryst_1, r"(\[[^\]\[]*\])"); + +// qui-vive-0.1.0: r"^/(\w+)$" +consistent!(qui_vive_0, r"^/(\w+)$"); + +// qui-vive-0.1.0: r"^/key$" +consistent!(qui_vive_1, r"^/key$"); + +// qui-vive-0.1.0: r"^/key/(\w+)$" +consistent!(qui_vive_2, r"^/key/(\w+)$"); + +// qui-vive-0.1.0: r"^/url$" +consistent!(qui_vive_3, r"^/url$"); + +// qui-vive-0.1.0: r"^/url/(\w+)$" +consistent!(qui_vive_4, r"^/url/(\w+)$"); + +// qui-vive-0.1.0: r"^/inv$" +consistent!(qui_vive_5, r"^/inv$"); + +// qui-vive-0.1.0: r"^/inv/(\w+)$" +consistent!(qui_vive_6, r"^/inv/(\w+)$"); + +// subdiff-0.1.0: r"\b" +// consistent!(subdiff_0, r"\b"); + +// substudy-0.4.5: r"^(\d+)/(\d+)$" +consistent!(substudy_0, r"^(\d+)/(\d+)$"); + +// substudy-0.4.5: r"\s+" +consistent!(substudy_1, r"\s+"); + +// substudy-0.4.5: r"<[a-z/][^>]*>" +consistent!(substudy_2, r"<[a-z/][^>]*>"); + +// substudy-0.4.5: r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)" +consistent!(substudy_3, r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)"); + +// substudy-0.4.5: r"\s+" +consistent!(substudy_4, r"\s+"); + +// isbnid-0.1.3: r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$" +consistent!(isbnid_0, r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$"); + +// isbnid-0.1.3: r"[^0-9X]" +consistent!(isbnid_1, r"[^0-9X]"); + +// ispc-0.3.5: r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)" +consistent!(ispc_0, r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)"); + diff --git a/proptest/src/result.rs b/proptest/src/result.rs new file mode 100644 index 000000000..769bfa229 --- /dev/null +++ b/proptest/src/result.rs @@ -0,0 +1,262 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for combining delegate strategies into `std::Result`s. +//! +//! That is, the strategies here are for producing `Ok` _and_ `Err` cases. To +//! simply adapt a strategy producing `T` into `Result<T, something>` which is +//! always `Ok`, you can do something like `base_strategy.prop_map(Ok)` to +//! simply wrap the generated values. +//! +//! Note that there are two nearly identical APIs for doing this, termed "maybe +//! ok" and "maybe err". The difference between the two is in how they shrink; +//! "maybe ok" treats `Ok` as the special case and shrinks to `Err`; +//! conversely, "maybe err" treats `Err` as the special case and shrinks to +//! `Ok`. Which to use largely depends on the code being tested; if the code +//! typically handles errors by immediately bailing out and doing nothing else, +//! "maybe ok" is likely more suitable, as shrinking will cause the code to +//! take simpler paths. On the other hand, functions that need to make a +//! complicated or fragile "back out" process on error are better tested with +//! "maybe err" since the success case results in an easier to understand code +//! path. + +#![cfg_attr(feature="cargo-clippy", allow(expl_impl_clone_on_copy))] + +use core::fmt; +use core::marker::PhantomData; + +use strategy::*; +use test_runner::*; + +// Re-export the type for easier usage. +pub use option::{prob, Probability}; + +struct WrapOk<T, E>(PhantomData<T>, PhantomData<E>); +impl<T, E> Clone for WrapOk<T, E> { + fn clone(&self) -> Self { *self } +} +impl<T, E> Copy for WrapOk<T, E> { } +impl<T, E> fmt::Debug for WrapOk<T, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WrapOk") + } +} +impl<T : fmt::Debug, E : fmt::Debug> statics::MapFn<T> for WrapOk<T, E> { + type Output = Result<T, E>; + fn apply(&self, t: T) -> Result<T, E> { + Ok(t) + } +} +struct WrapErr<T, E>(PhantomData<T>, PhantomData<E>); +impl<T, E> Clone for WrapErr<T, E> { + fn clone(&self) -> Self { *self } +} +impl<T, E> Copy for WrapErr<T, E> { } +impl<T, E> fmt::Debug for WrapErr<T, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "WrapErr") + } +} +impl<T : fmt::Debug, E : fmt::Debug> statics::MapFn<E> for WrapErr<T, E> { + type Output = Result<T, E>; + fn apply(&self, e: E) -> Result<T, E> { + Err(e) + } +} + +type MapErr<T, E> = statics::Map<E, WrapErr< + <T as Strategy>::Value, <E as Strategy>::Value>>; +type MapOk <T, E> = statics::Map<T, WrapOk< + <T as Strategy>::Value, <E as Strategy>::Value>>; + +opaque_strategy_wrapper! { + /// Strategy which generates `Result`s using `Ok` and `Err` values from two + /// delegate strategies. + /// + /// Shrinks to `Err`. + #[derive(Clone)] + pub struct MaybeOk[<T, E>][where T : Strategy, E : Strategy] + (TupleUnion<(W<MapErr<T, E>>, W<MapOk<T, E>>)>) + -> MaybeOkValueTree<T::Tree, E::Tree>; + /// `ValueTree` type corresponding to `MaybeOk`. + #[derive(Clone, Debug)] + pub struct MaybeOkValueTree[<T, E>][where T : ValueTree, E : ValueTree] + (TupleUnionValueTree<(statics::Map<E, WrapErr<T::Value, E::Value>>, + Option<statics::Map<T, WrapOk<T::Value, E::Value>>>)>) + -> Result<T::Value, E::Value>; +} + +opaque_strategy_wrapper! { + /// Strategy which generates `Result`s using `Ok` and `Err` values from two + /// delegate strategies. + /// + /// Shrinks to `Ok`. + #[derive(Clone)] + pub struct MaybeErr[<T, E>][where T : Strategy, E : Strategy] + (TupleUnion<(W<MapOk<T, E>>, W<MapErr<T, E>>)>) + -> MaybeErrValueTree<T::Tree, E::Tree>; + /// `ValueTree` type corresponding to `MaybeErr`. + #[derive(Clone, Debug)] + pub struct MaybeErrValueTree[<T, E>][where T : ValueTree, E : ValueTree] + (TupleUnionValueTree<(statics::Map<T, WrapOk<T::Value, E::Value>>, + Option<statics::Map<E, WrapErr<T::Value, E::Value>>>)>) + -> Result<T::Value, E::Value>; +} + +// These need to exist for the same reason as the one on `OptionStrategy` +impl<T : Strategy + fmt::Debug, E : Strategy + fmt::Debug> fmt::Debug +for MaybeOk<T, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MaybeOk({:?})", self.0) + } +} +impl<T : Strategy + fmt::Debug, E : Strategy + fmt::Debug> fmt::Debug +for MaybeErr<T, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MaybeErr({:?})", self.0) + } +} + +/// Create a strategy for `Result`s where `Ok` values are taken from `t` and +/// `Err` values are taken from `e`. +/// +/// `Ok` and `Err` are chosen with equal probability. +/// +/// Generated values shrink to `Err`. +pub fn maybe_ok<T : Strategy, E : Strategy>(t: T, e: E) -> MaybeOk<T, E> { + maybe_ok_weighted(0.5, t, e) +} + +/// Create a strategy for `Result`s where `Ok` values are taken from `t` and +/// `Err` values are taken from `e`. +/// +/// `probability_of_ok` is the probability (between 0.0 and 1.0, exclusive) +/// that `Ok` is initially chosen. +/// +/// Generated values shrink to `Err`. +pub fn maybe_ok_weighted<T : Strategy, E : Strategy>( + probability_of_ok: impl Into<Probability>, t: T, e: E) -> MaybeOk<T, E> +{ + let prob = probability_of_ok.into().into(); + let (ok_weight, err_weight) = float_to_weight(prob); + + MaybeOk(TupleUnion::new(( + (err_weight, statics::Map::new(e, WrapErr(PhantomData, PhantomData))), + (ok_weight, statics::Map::new(t, WrapOk(PhantomData, PhantomData))), + ))) +} + +/// Create a strategy for `Result`s where `Ok` values are taken from `t` and +/// `Err` values are taken from `e`. +/// +/// `Ok` and `Err` are chosen with equal probability. +/// +/// Generated values shrink to `Ok`. +pub fn maybe_err<T : Strategy, E : Strategy>(t: T, e: E) -> MaybeErr<T, E> { + maybe_err_weighted(0.5, t, e) +} + +/// Create a strategy for `Result`s where `Ok` values are taken from `t` and +/// `Err` values are taken from `e`. +/// +/// `probability_of_ok` is the probability (between 0.0 and 1.0, exclusive) +/// that `Err` is initially chosen. +/// +/// Generated values shrink to `Ok`. +pub fn maybe_err_weighted<T : Strategy, E : Strategy>( + probability_of_err: impl Into<Probability>, t: T, e: E) -> MaybeErr<T, E> +{ + let prob = probability_of_err.into().into(); + let (err_weight, ok_weight) = float_to_weight(prob); + + MaybeErr(TupleUnion::new(( + (ok_weight, statics::Map::new(t, WrapOk(PhantomData, PhantomData))), + (err_weight, statics::Map::new(e, WrapErr(PhantomData, PhantomData))), + ))) +} + +#[cfg(test)] +mod test { + use super::*; + + fn count_ok_of_1000(s: impl Strategy<Value = Result<(), ()>>) -> u32 { + let mut runner = TestRunner::default(); + let mut count = 0; + for _ in 0..1000 { + count += s.new_tree(&mut runner).unwrap() + .current().is_ok() as u32; + } + + count + } + + #[test] + fn probability_defaults_to_0p5() { + let count = count_ok_of_1000(maybe_err(Just(()), Just(()))); + assert!(count > 400 && count < 600); + let count = count_ok_of_1000(maybe_ok(Just(()), Just(()))); + assert!(count > 400 && count < 600); + } + + #[test] + fn probability_handled_correctly() { + let count = count_ok_of_1000(maybe_err_weighted( + 0.1, Just(()), Just(()))); + assert!(count > 800 && count < 950); + + let count = count_ok_of_1000(maybe_err_weighted( + 0.9, Just(()), Just(()))); + assert!(count > 50 && count < 150); + + let count = count_ok_of_1000(maybe_ok_weighted( + 0.9, Just(()), Just(()))); + assert!(count > 800 && count < 950); + + let count = count_ok_of_1000(maybe_ok_weighted( + 0.1, Just(()), Just(()))); + assert!(count > 50 && count < 150); + } + + #[test] + fn shrink_to_correct_case() { + let mut runner = TestRunner::default(); + { + let input = maybe_err(Just(()), Just(())); + for _ in 0..64 { + let mut val = input.new_tree(&mut runner).unwrap(); + if val.current().is_ok() { + assert!(!val.simplify()); + assert!(val.current().is_ok()); + } else { + assert!(val.simplify()); + assert!(val.current().is_ok()); + } + } + } + { + let input = maybe_ok(Just(()), Just(())); + for _ in 0..64 { + let mut val = input.new_tree(&mut runner).unwrap(); + if val.current().is_err() { + assert!(!val.simplify()); + assert!(val.current().is_err()); + } else { + assert!(val.simplify()); + assert!(val.current().is_err()); + } + } + } + } + + #[test] + fn test_sanity() { + check_strategy_sanity(maybe_ok(0i32..100i32, 0i32..100i32), None); + check_strategy_sanity(maybe_err(0i32..100i32, 0i32..100i32), None); + } +} diff --git a/proptest/src/sample.rs b/proptest/src/sample.rs new file mode 100644 index 000000000..78f424cf0 --- /dev/null +++ b/proptest/src/sample.rs @@ -0,0 +1,551 @@ +//- +// Copyright 2017, 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating values by taking samples of collections. +//! +//! Note that the strategies in this module are not native combinators; that +//! is, the input collection is not itself a strategy, but is rather fixed when +//! the strategy is created. + +use core::fmt; +use core::mem; +use core::ops::Range; +use core::u64; +use std_facade::{Cow, Vec, Arc}; + +use rand::Rng; + +use bits::{self, BitSetValueTree, SampledBitSetStrategy, VarBitSet}; +use num; +use strategy::*; +use test_runner::*; + +/// Re-exported to make usage more ergonomic. +pub use collection::{SizeRange, size_range}; + +/// Sample subsequences whose size are within `size` from the given collection +/// `values`. +/// +/// A subsequence is a subset of the elements in a collection in the order they +/// occur in that collection. The elements are not chosen to be contiguous. +/// +/// This is roughly analogous to `rand::sample`, except that it guarantees that +/// the order is preserved. +/// +/// `values` may be a static slice or a `Vec`. +/// +/// ## Panics +/// +/// Panics if the maximum size implied by `size` is larger than the size of +/// `values`. +/// +/// Panics if `size` is a zero-length range. +pub fn subsequence<T : Clone + 'static> + (values: impl Into<Cow<'static, [T]>>, + size: impl Into<SizeRange>) -> Subsequence<T> +{ + let values = values.into(); + let len = values.len(); + let size = size.into(); + + size.assert_nonempty(); + assert!(size.end_incl() <= len, + "Maximum size of subsequence {} exceeds length of input {}", + size.end_incl(), len); + Subsequence { + values: Arc::new(values), + bit_strategy: bits::varsize::sampled(size, 0..len), + } +} + +/// Strategy to generate `Vec`s by sampling a subsequence from another +/// collection. +/// +/// This is created by the `subsequence` function in the same module. +#[derive(Debug, Clone)] +#[must_use = "strategies do nothing unless used"] +pub struct Subsequence<T : Clone + 'static> { + values: Arc<Cow<'static, [T]>>, + bit_strategy: SampledBitSetStrategy<VarBitSet>, +} + +impl<T : fmt::Debug + Clone + 'static> Strategy for Subsequence<T> { + type Tree = SubsequenceValueTree<T>; + type Value = Vec<T>; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + Ok(SubsequenceValueTree { + values: Arc::clone(&self.values), + inner: self.bit_strategy.new_tree(runner)?, + }) + } +} + +/// `ValueTree` type for `Subsequence`. +#[derive(Debug, Clone)] +pub struct SubsequenceValueTree<T : Clone + 'static> { + values: Arc<Cow<'static, [T]>>, + inner: BitSetValueTree<VarBitSet>, +} + +impl<T : fmt::Debug + Clone + 'static> ValueTree for SubsequenceValueTree<T> { + type Value = Vec<T>; + + fn current(&self) -> Self::Value { + let inner = self.inner.current(); + let ret = inner.iter().map(|ix| self.values[ix].clone()).collect(); + ret + } + + fn simplify(&mut self) -> bool { + self.inner.simplify() + } + + fn complicate(&mut self) -> bool { + self.inner.complicate() + } +} + + +#[derive(Debug, Clone)] +struct SelectMapFn<T : Clone + 'static>(Arc<Cow<'static, [T]>>); + +impl<T : fmt::Debug + Clone + 'static> statics::MapFn<usize> +for SelectMapFn<T> { + type Output = T; + + fn apply(&self, ix: usize) -> T { + self.0[ix].clone() + } +} + +opaque_strategy_wrapper! { + /// Strategy to produce one value from a fixed collection of options. + /// + /// Created by the `select()` in the same module. + #[derive(Clone, Debug)] + pub struct Select[<T>][where T : Clone + fmt::Debug + 'static]( + statics::Map<Range<usize>, SelectMapFn<T>>) + -> SelectValueTree<T>; + /// `ValueTree` corresponding to `Select`. + #[derive(Clone, Debug)] + pub struct SelectValueTree[<T>][where T : Clone + fmt::Debug + 'static]( + statics::Map<num::usize::BinarySearch, SelectMapFn<T>>) + -> T; +} + +/// Create a strategy which uniformly selects one value from `values`. +/// +/// `values` should be a `&'static [T]` or a `Vec<T>`, or potentially another +/// type that can be coerced to `Cow<'static,[T]>`. +/// +/// This is largely equivalent to making a `Union` of a bunch of `Just` +/// strategies, but is substantially more efficient and shrinks by binary +/// search. +/// +/// If `values` is also to be generated by a strategy, see +/// [`Index`](struct.Index.html) for a more efficient way to select values than +/// using `prop_flat_map()`. +pub fn select<T : Clone + fmt::Debug + 'static> + (values: impl Into<Cow<'static, [T]>>) -> Select<T> +{ + let cow = values.into(); + + Select(statics::Map::new( + 0..cow.len(), SelectMapFn(Arc::new(cow)))) +} + +/// A stand-in for an index into a slice or similar collection or conceptually +/// similar things. +/// +/// At the lowest level, `Index` is a mechanism for generating `usize` values +/// in the range [0..N), for some N whose value is not known until it is +/// needed. (Contrast with using `0..N` itself as a strategy, where you need to +/// know N when you define the strategy.) +/// +/// For any upper bound, the actual index produced by an `Index` is the same no +/// matter how many times it is used. Different upper bounds will produce +/// different but not independent values. +/// +/// Shrinking will cause the index to binary search through the underlying +/// collection(s) it is used to sample. +/// +/// Note that `Index` _cannot_ currently be used as a slice index (e.g., +/// `slice[index]`) due to the trait coherence rules. +/// +/// ## Example +/// +/// If the collection itself being indexed is itself generated by a strategy, +/// you can make separately define that strategy and a strategy generating one +/// or more `Index`es and then join the two after input generation, avoiding a +/// call to `prop_flat_map()`. +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn my_test( +/// names in prop::collection::vec("[a-z]+", 10..20), +/// indices in prop::collection::vec(any::<prop::sample::Index>(), 5..10) +/// ) { +/// // We now have Vec<String> of ten to twenty names, and a Vec<Index> +/// // of five to ten indices and can combine them however we like. +/// for index in &indices { +/// println!("Accessing item by index: {}", names[index.index(names.len())]); +/// println!("Accessing item by convenience method: {}", index.get(&names)); +/// } +/// // Test stuff... +/// } +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Index(usize); + +impl Index { + /// Return the real index that would be used to index a collection of size `size`. + /// + /// ## Panics + /// + /// Panics if `size == 0`. + pub fn index(&self, size: usize) -> usize { + assert!(size > 0, "Attempt to use `Index` with 0-size collection"); + + // No platforms currently have `usize` wider than 64 bits, so `u128` is + // sufficient to hold the result of a full multiply, letting us do a + // simple fixed-point multiply. + ((size as u128) * (self.0 as u128) >> (mem::size_of::<usize>() * 8)) as usize + } + + /// Return a reference to the element in `slice` that this `Index` refers to. + /// + /// A shortcut for `&slice[index.index(slice.len())]`. + pub fn get<'a, T>(&self, slice: &'a [T]) -> &'a T { + &slice[self.index(slice.len())] + } + + /// Return a mutable reference to the element in `slice` that this `Index` + /// refers to. + /// + /// A shortcut for `&mut slice[index.index(slice.len())]`. + pub fn get_mut<'a, T>(&self, slice: &'a mut [T]) -> &'a mut T { + let ix = self.index(slice.len()); + &mut slice[ix] + } +} + +mapfn! { + [] fn UsizeToIndex[](raw: usize) -> Index { + Index(raw) + } +} + +opaque_strategy_wrapper! { + /// Strategy to create `Index`es. + /// + /// Created via `any::<Index>()`. + #[derive(Clone, Debug)] + pub struct IndexStrategy[][]( + statics::Map<num::usize::Any, UsizeToIndex>) + -> IndexValueTree; + /// `ValueTree` corresponding to `IndexStrategy`. + #[derive(Clone, Debug)] + pub struct IndexValueTree[][]( + statics::Map<num::usize::BinarySearch,UsizeToIndex>) + -> Index; +} + +impl IndexStrategy { + pub(crate) fn new() -> Self { + IndexStrategy(statics::Map::new(num::usize::ANY, UsizeToIndex)) + } +} + +/// A value for picking random values out of iterators. +/// +/// This is, in a sense, a more flexible variant of +/// [`Index`](struct.Index.html) in that it can operate on arbitrary +/// `IntoIterator` values. +/// +/// Initially, the selection is roughly uniform, with a very slight bias +/// towards items earlier in the iterator. +/// +/// Shrinking causes the selection to move toward items earlier in the +/// iterator, ultimately settling on the very first, but this currently happens +/// in a very haphazard way that may fail to find the earliest failing input. +/// +/// ## Example +/// +/// Generate a non-indexable collection and a value to pick out of it. +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn my_test( +/// names in prop::collection::hash_set("[a-z]+", 10..20), +/// selector in any::<prop::sample::Selector>() +/// ) { +/// println!("Selected name: {}", selector.select(&names)); +/// // Test stuff... +/// } +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[derive(Clone, Debug)] +pub struct Selector { + rng: TestRng, + bias_increment: u64, +} + +/// Strategy to create `Selector`s. +/// +/// Created via `any::<Selector>()`. +#[derive(Debug)] +pub struct SelectorStrategy { + _nonexhaustive: (), +} + +/// `ValueTree` corresponding to `SelectorStrategy`. +#[derive(Debug)] +pub struct SelectorValueTree { + rng: TestRng, + reverse_bias_increment: num::u64::BinarySearch, +} + +impl SelectorStrategy { + pub(crate) fn new() -> Self { + SelectorStrategy { + _nonexhaustive: (), + } + } +} + +impl Strategy for SelectorStrategy { + type Tree = SelectorValueTree; + type Value = Selector; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + Ok(SelectorValueTree { + rng: runner.new_rng(), + reverse_bias_increment: num::u64::BinarySearch::new(u64::MAX), + }) + } +} + +impl ValueTree for SelectorValueTree { + type Value = Selector; + + fn current(&self) -> Selector { + Selector { + rng: self.rng.clone(), + bias_increment: u64::MAX - self.reverse_bias_increment.current(), + } + } + + fn simplify(&mut self) -> bool { + self.reverse_bias_increment.simplify() + } + + fn complicate(&mut self) -> bool { + self.reverse_bias_increment.complicate() + } +} + +impl Selector { + /// Pick a random element from iterable `it`. + /// + /// The selection is unaffected by the elements themselves, and is + /// dependent only on the actual length of `it`. + /// + /// `it` is always iterated completely. + /// + /// ## Panics + /// + /// Panics if `it` has no elements. + pub fn select<T : IntoIterator>(&self, it: T) -> T::Item { + self.try_select(it).expect("select from empty iterator") + } + + /// Pick a random element from iterable `it`. + /// + /// Returns `None` if `it` is empty. + /// + /// The selection is unaffected by the elements themselves, and is + /// dependent only on the actual length of `it`. + /// + /// `it` is always iterated completely. + pub fn try_select<T : IntoIterator>(&self, it: T) -> Option<T::Item> { + let mut bias = 0u64; + let mut min_score = 0; + let mut best = None; + let mut rng = self.rng.clone(); + + for item in it { + let score = bias.saturating_add(rng.gen()); + if best.is_none() || score < min_score { + best = Some(item); + min_score = score; + } + + bias = bias.saturating_add(self.bias_increment); + } + + best + } +} + +#[cfg(test)] +mod test { + use std_facade::BTreeSet; + + use super::*; + use arbitrary::any; + + #[test] + fn sample_slice() { + static VALUES: &[usize] = &[0, 1, 2, 3, 4, 5, 6, 7]; + let mut size_counts = [0; 8]; + let mut value_counts = [0; 8]; + + let mut runner = TestRunner::default(); + let input = subsequence(VALUES, 3..7); + + for _ in 0..2048 { + let value = input.new_tree(&mut runner).unwrap().current(); + // Generated the correct number of items + assert!(value.len() >= 3 && value.len() < 7); + // Chose distinct items + assert_eq!(value.len(), + value.iter().cloned().collect::<BTreeSet<_>>().len()); + // Values are in correct order + let mut sorted = value.clone(); + sorted.sort(); + assert_eq!(sorted, value); + + size_counts[value.len()] += 1; + + for value in value { + value_counts[value] += 1; + } + } + + for i in 3..7 { + assert!(size_counts[i] >= 256 && size_counts[i] < 1024, + "size {} was chosen {} times", i, size_counts[i]); + } + + for (ix, &v) in value_counts.iter().enumerate() { + assert!(v >= 1024 && v < 1500, + "Value {} was chosen {} times", ix, v); + } + } + + #[test] + fn sample_vec() { + // Just test that the types work out + let values = vec![0, 1, 2, 3, 4]; + + let mut runner = TestRunner::default(); + let input = subsequence(values, 1..3); + + let _ = input.new_tree(&mut runner).unwrap().current(); + } + + #[test] + fn test_select() { + let values = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut counts = [0; 8]; + + let mut runner = TestRunner::default(); + let input = select(values); + + for _ in 0..1024 { + counts[input.new_tree(&mut runner).unwrap().current()] += 1; + } + + for (ix, &count) in counts.iter().enumerate() { + assert!(count >= 64 && count < 256, + "Generated value {} {} times", ix, count); + } + } + + #[test] + fn test_sample_sanity() { + check_strategy_sanity(subsequence(vec![0, 1, 2, 3, 4], 1..3), None); + } + + #[test] + fn test_select_sanity() { + check_strategy_sanity(select(vec![0, 1, 2, 3, 4]), None); + } + + #[test] + fn subseq_empty_vec_works() { + let mut runner = TestRunner::default(); + let input = subsequence(Vec::<()>::new(), 0..1); + assert_eq!(Vec::<()>::new(), input.new_tree(&mut runner).unwrap().current()); + } + + #[test] + fn subseq_full_vec_works() { + let v = vec![1u32, 2u32, 3u32]; + let mut runner = TestRunner::default(); + let input = subsequence(v.clone(), 3); + assert_eq!(v, input.new_tree(&mut runner).unwrap().current()); + } + + #[test] + fn index_works() { + let mut runner = TestRunner::default(); + let input = any::<Index>(); + let col = vec!["foo", "bar", "baz"]; + let mut seen = BTreeSet::new(); + + for _ in 0..16 { + let mut tree = input.new_tree(&mut runner).unwrap(); + seen.insert(*tree.current().get(&col)); + + while tree.simplify() { } + + assert_eq!("foo", *tree.current().get(&col)); + } + + assert_eq!(col.into_iter().collect::<BTreeSet<_>>(), seen); + } + + #[test] + fn selector_works() { + let mut runner = TestRunner::default(); + let input = any::<Selector>(); + let col: BTreeSet<&str> = vec!["foo", "bar", "baz"].into_iter().collect(); + let mut seen = BTreeSet::new(); + + for _ in 0..16 { + let mut tree = input.new_tree(&mut runner).unwrap(); + seen.insert(*tree.current().select(&col)); + + while tree.simplify() { } + + assert_eq!("bar", *tree.current().select(&col)); + } + + assert_eq!(col, seen); + } +} diff --git a/proptest/src/std_facade.rs b/proptest/src/std_facade.rs new file mode 100644 index 000000000..c00d53f97 --- /dev/null +++ b/proptest/src/std_facade.rs @@ -0,0 +1,74 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module provides #[cfg(..)]ed type aliases over features. + +macro_rules! multiplex_alloc { + ($($alloc: path, $std: path),*) => { + $( + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub(crate) use $alloc; + #[cfg(feature = "std")] + pub(crate) use $std; + )* + }; +} + +macro_rules! multiplex_core { + ($($core: path, $std: path),*) => { + $( + #[cfg(not(feature = "std"))] + pub(crate) use $core; + #[cfg(feature = "std")] + pub(crate) use $std; + )* + }; +} + +multiplex_alloc! { + alloc::borrow::Cow, ::std::borrow::Cow, + alloc::borrow::ToOwned, ::std::borrow::ToOwned, + alloc::boxed::Box, ::std::boxed::Box, + alloc::string::String, ::std::string::String, + alloc::string, ::std::string, + alloc::sync::Arc, ::std::sync::Arc, + alloc::rc::Rc, ::std::rc::Rc, + alloc::vec::Vec, ::std::vec::Vec, + alloc::vec, ::std::vec, + alloc::collections::VecDeque, std::collections::VecDeque, + alloc::collections::vec_deque, std::collections::vec_deque, + alloc::collections::BinaryHeap, ::std::collections::BinaryHeap, + alloc::collections::binary_heap, ::std::collections::binary_heap, + alloc::collections::LinkedList, ::std::collections::LinkedList, + alloc::collections::linked_list, ::std::collections::linked_list, + alloc::collections::BTreeSet, ::std::collections::BTreeSet, + alloc::collections::BTreeMap, ::std::collections::BTreeMap, + alloc::collections::btree_map, ::std::collections::btree_map, + alloc::collections::btree_set, ::std::collections::btree_set +} + +#[cfg(feature = "std")] +multiplex_alloc! { + hashmap_core::HashMap, ::std::collections::HashMap, + hashmap_core::HashSet, ::std::collections::HashSet +} + +//#[cfg(not(feature = "std"))] +//pub(crate) use hashmap_core::map as hash_map; +#[cfg(feature = "std")] +pub(crate) use ::std::collections::hash_map; +//#[cfg(not(feature = "std"))] +//pub(crate) use hashmap_core::set as hash_set; +#[cfg(feature = "std")] +pub(crate) use ::std::collections::hash_set; + +multiplex_core! { + core::fmt, ::std::fmt, + core::cell::Cell, ::std::cell::Cell +} diff --git a/proptest/src/strategy/filter.rs b/proptest/src/strategy/filter.rs new file mode 100644 index 000000000..c6b2809c3 --- /dev/null +++ b/proptest/src/strategy/filter.rs @@ -0,0 +1,144 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::{fmt, Arc}; + +use strategy::traits::*; +use test_runner::*; + +/// `Strategy` and `ValueTree` filter adaptor. +/// +/// See `Strategy::prop_filter()`. +#[must_use = "strategies do nothing unless used"] +pub struct Filter<S, F> { + pub(super) source: S, + pub(super) whence: Reason, + pub(super) fun: Arc<F>, +} + +impl<S, F> Filter<S, F> { + pub (super) fn new(source: S, whence: Reason, fun: F) -> Self { + Self { source, whence, fun: Arc::new(fun) } + } +} + +impl<S : fmt::Debug, F> fmt::Debug for Filter<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Filter") + .field("source", &self.source) + .field("whence", &self.whence) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Clone, F> Clone for Filter<S, F> { + fn clone(&self) -> Self { + Filter { + source: self.source.clone(), + whence: "unused".into(), + fun: Arc::clone(&self.fun), + } + } +} + +impl<S : Strategy, + F : Fn (&S::Value) -> bool> +Strategy for Filter<S, F> { + type Tree = Filter<S::Tree, F>; + type Value = S::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + loop { + let val = self.source.new_tree(runner)?; + if !(self.fun)(&val.current()) { + runner.reject_local(self.whence.clone())?; + } else { + return Ok(Filter { + source: val, + whence: self.whence.clone(), + fun: Arc::clone(&self.fun), + }) + } + } + } +} + +impl<S : ValueTree, F : Fn (&S::Value) -> bool> +Filter<S, F> { + fn ensure_acceptable(&mut self) { + while !(self.fun)(&self.source.current()) { + if !self.source.complicate() { + panic!("Unable to complicate filtered strategy \ + back into acceptable value"); + } + } + } +} + +impl<S : ValueTree, F : Fn (&S::Value) -> bool> +ValueTree for Filter<S, F> { + type Value = S::Value; + + fn current(&self) -> S::Value { + self.source.current() + } + + fn simplify(&mut self) -> bool { + if self.source.simplify() { + self.ensure_acceptable(); + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.source.complicate() { + self.ensure_acceptable(); + true + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_filter() { + let input = (0..256).prop_filter("%3", |&v| 0 == v % 3); + + for _ in 0..256 { + let mut runner = TestRunner::default(); + let mut case = input.new_tree(&mut runner).unwrap(); + + assert!(0 == case.current() % 3); + + while case.simplify() { + assert!(0 == case.current() % 3); + } + assert!(0 == case.current() % 3); + } + } + + #[test] + fn test_filter_sanity() { + check_strategy_sanity( + (0..256).prop_filter("!%5", |&v| 0 != v % 5), + Some(CheckStrategySanityOptions { + // Due to internal rejection sampling, `simplify()` can + // converge back to what `complicate()` would do. + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } +} diff --git a/proptest/src/strategy/filter_map.rs b/proptest/src/strategy/filter_map.rs new file mode 100644 index 000000000..2bd7fe5c9 --- /dev/null +++ b/proptest/src/strategy/filter_map.rs @@ -0,0 +1,189 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::{fmt, Arc, Cell}; + +use strategy::traits::*; +use test_runner::*; + +/// `Strategy` and `ValueTree` filter_map adaptor. +/// +/// See `Strategy::prop_filter_map()`. +#[must_use = "strategies do nothing unless used"] +pub struct FilterMap<S, F> { + pub(super) source: S, + pub(super) whence: Reason, + pub(super) fun: Arc<F>, +} + +impl<S, F> FilterMap<S, F> { + pub (super) fn new(source: S, whence: Reason, fun: F) -> Self { + Self { source, whence, fun: Arc::new(fun) } + } +} + +impl<S: fmt::Debug, F> fmt::Debug for FilterMap<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FilterMap") + .field("source", &self.source) + .field("whence", &self.whence) + .field("fun", &"<function>") + .finish() + } +} + +impl<S: Clone, F> Clone for FilterMap<S, F> { + fn clone(&self) -> Self { + Self { + source: self.source.clone(), + whence: self.whence.clone(), + fun: Arc::clone(&self.fun), + } + } +} + +impl<S : Strategy, F : Fn (S::Value) -> Option<O>, O : fmt::Debug> Strategy +for FilterMap<S, F> { + type Tree = FilterMapValueTree<S::Tree, F, O>; + type Value = O; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + loop { + let val = self.source.new_tree(runner)?; + if let Some(current) = (self.fun)(val.current()) { + return Ok(FilterMapValueTree::new(val, &self.fun, current)) + } else { + runner.reject_local(self.whence.clone())?; + } + } + } +} + +/// `ValueTree` corresponding to `FilterMap`. +pub struct FilterMapValueTree<V, F, O> { + source: V, + current: Cell<Option<O>>, + fun: Arc<F>, +} + +impl<V : Clone + ValueTree, F : Fn (V::Value) -> Option<O>, O> Clone +for FilterMapValueTree<V, F, O> { + fn clone(&self) -> Self { + Self::new(self.source.clone(), &self.fun, self.fresh_current()) + } +} + +impl<V: fmt::Debug, F, O> fmt::Debug for FilterMapValueTree<V, F, O> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FilterMapValueTree") + .field("source", &self.source) + .field("current", &"<current>") + .field("fun", &"<function>") + .finish() + } +} + +impl<V : ValueTree, F : Fn (V::Value) -> Option<O>, O> +FilterMapValueTree<V, F, O> { + fn new(source: V, fun: &Arc<F>, current: O) -> Self { + Self { + source, + current: Cell::new(Some(current)), + fun: Arc::clone(fun), + } + } + + fn fresh_current(&self) -> O { + (self.fun)(self.source.current()) + .expect("internal logic error; this is a bug!") + } + + fn ensure_acceptable(&mut self) { + loop { + if let Some(current) = (self.fun)(self.source.current()) { + // Found an acceptable element! + self.current = Cell::new(Some(current)); + break; + } else if !self.source.complicate() { + panic!("Unable to complicate filtered strategy \ + back into acceptable value"); + } + } + } +} + +impl<V : ValueTree, F : Fn (V::Value) -> Option<O>, O : fmt::Debug> ValueTree +for FilterMapValueTree<V, F, O> { + type Value = O; + + fn current(&self) -> O { + // Optimization: we avoid the else branch in most success cases + // thereby avoiding to call the closure and the source tree. + if let Some(current) = self.current.replace(None) { + current + } else { + self.fresh_current() + } + } + + fn simplify(&mut self) -> bool { + if self.source.simplify() { + self.ensure_acceptable(); + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.source.complicate() { + self.ensure_acceptable(); + true + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_filter_map() { + let input = (0..256).prop_filter_map("%3 + 1", + |v| if 0 == v % 3 { Some(v + 1) } else { None }); + + for _ in 0..256 { + let mut runner = TestRunner::default(); + let mut case = input.new_tree(&mut runner).unwrap(); + + assert_eq!(0, (case.current() - 1) % 3); + + while case.simplify() { + assert_eq!(0, (case.current() - 1) % 3); + } + assert_eq!(0, (case.current() - 1) % 3); + } + } + + #[test] + fn test_filter_map_sanity() { + check_strategy_sanity( + (0..256).prop_filter_map("!%5 * 2", + |v| if 0 != v % 5 { Some(v * 2) } else { None }), + + Some(CheckStrategySanityOptions { + // Due to internal rejection sampling, `simplify()` can + // converge back to what `complicate()` would do. + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } +} diff --git a/proptest/src/strategy/flatten.rs b/proptest/src/strategy/flatten.rs new file mode 100644 index 000000000..8be780492 --- /dev/null +++ b/proptest/src/strategy/flatten.rs @@ -0,0 +1,326 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::mem; +use std_facade::{fmt, Arc}; + +use strategy::fuse::Fuse; +use strategy::traits::*; +use test_runner::*; + +/// Adaptor that flattens a `Strategy` which produces other `Strategy`s into a +/// `Strategy` that picks one of those strategies and then picks values from +/// it. +#[derive(Debug, Clone, Copy)] +#[must_use = "strategies do nothing unless used"] +pub struct Flatten<S> { + source: S, +} + +impl<S : Strategy> Flatten<S> { + /// Wrap `source` to flatten it. + pub fn new(source: S) -> Self { + Flatten { source } + } +} + +impl<S : Strategy> Strategy for Flatten<S> +where S::Value : Strategy { + type Tree = FlattenValueTree<S::Tree>; + type Value = <S::Value as Strategy>::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let meta = self.source.new_tree(runner)?; + FlattenValueTree::new(runner, meta) + } +} + +/// The `ValueTree` produced by `Flatten`. +pub struct FlattenValueTree<S : ValueTree> where S::Value : Strategy { + meta: Fuse<S>, + current: Fuse<<S::Value as Strategy>::Tree>, + // The final value to produce after successive calls to complicate() on the + // underlying objects return false. + final_complication: Option<Fuse<<S::Value as Strategy>::Tree>>, + // When `simplify()` or `complicate()` causes a new `Strategy` to be + // chosen, we need to find a new failing input for that case. To do this, + // we implement `complicate()` by regenerating values up to a number of + // times corresponding to the maximum number of test cases. A `simplify()` + // which does not cause a new strategy to be chosen always resets + // `complicate_regen_remaining` to 0. + // + // This does unfortunately depart from the direct interpretation of + // simplify/complicate as binary search, but is still easier to think about + // than other implementations of higher-order strategies. + runner: TestRunner, + complicate_regen_remaining: u32, +} + +impl<S : ValueTree> Clone for FlattenValueTree<S> +where S::Value : Strategy + Clone, + S : Clone, + <S::Value as Strategy>::Tree : Clone { + fn clone(&self) -> Self { + FlattenValueTree { + meta: self.meta.clone(), + current: self.current.clone(), + final_complication: self.final_complication.clone(), + runner: self.runner.clone(), + complicate_regen_remaining: self.complicate_regen_remaining, + } + } +} + +impl<S : ValueTree> fmt::Debug for FlattenValueTree<S> +where S::Value : Strategy, + S : fmt::Debug, <S::Value as Strategy>::Tree : fmt::Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FlattenValueTree") + .field("meta", &self.meta) + .field("current", &self.current) + .field("final_complication", &self.final_complication) + .field("complicate_regen_remaining", + &self.complicate_regen_remaining) + .finish() + } +} + +impl<S : ValueTree> FlattenValueTree<S> where S::Value : Strategy { + fn new(runner: &mut TestRunner, meta: S) -> Result<Self, Reason> { + let current = meta.current().new_tree(runner)?; + Ok(FlattenValueTree { + meta: Fuse::new(meta), + current: Fuse::new(current), + final_complication: None, + runner: runner.partial_clone(), + complicate_regen_remaining: 0 + }) + } +} + +impl<S : ValueTree> ValueTree for FlattenValueTree<S> +where S::Value : Strategy { + type Value = <S::Value as Strategy>::Value; + + fn current(&self) -> Self::Value { + self.current.current() + } + + fn simplify(&mut self) -> bool { + self.complicate_regen_remaining = 0; + + if self.current.simplify() { + // Now that we've simplified the derivative value, we can't + // re-complicate the meta value unless it gets simplified again. + // We also mustn't complicate back to whatever's in + // `final_complication` since the new state of `self.current` is + // the most complicated state. + self.meta.disallow_complicate(); + self.final_complication = None; + true + } else if !self.meta.simplify() { + false + } else if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { + // Shift current into final_complication and `v` into + // `current`. We also need to prevent that value from + // complicating beyond the current point in the future + // since we're going to return `true` from `simplify()` + // ourselves. + self.current.disallow_complicate(); + self.final_complication = Some(Fuse::new(v)); + mem::swap(self.final_complication.as_mut().unwrap(), + &mut self.current); + // Initially complicate by regenerating the chosen value. + self.complicate_regen_remaining = self.runner.config().cases; + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.complicate_regen_remaining > 0 { + if self.runner.flat_map_regen() { + self.complicate_regen_remaining -= 1; + + if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { + self.current = Fuse::new(v); + return true; + } + } else { + self.complicate_regen_remaining = 0; + } + } + + if self.current.complicate() { + return true; + } else if self.meta.complicate() { + if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { + self.complicate_regen_remaining = self.runner.config().cases; + self.current = Fuse::new(v); + return true; + } + } + + if let Some(v) = self.final_complication.take() { + self.current = v; + true + } else { + false + } + } +} + +/// Similar to `Flatten`, but does not shrink the input strategy. +/// +/// See `Strategy::prop_ind_flat_map()` fore more details. +#[derive(Clone, Copy, Debug)] +pub struct IndFlatten<S>(pub(super) S); + +impl<S : Strategy> Strategy for IndFlatten<S> +where S::Value : Strategy { + type Tree = <S::Value as Strategy>::Tree; + type Value = <S::Value as Strategy>::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let inner = self.0.new_tree(runner)?; + inner.current().new_tree(runner) + } +} + +/// Similar to `Map` plus `Flatten`, but does not shrink the input strategy and +/// passes the original input through. +/// +/// See `Strategy::prop_ind_flat_map2()` for more details. +pub struct IndFlattenMap<S, F> { + pub(super) source: S, + pub(super) fun: Arc<F>, +} + +impl<S : fmt::Debug, F> fmt::Debug for IndFlattenMap<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("IndFlattenMap") + .field("source", &self.source) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Clone, F> Clone for IndFlattenMap<S, F> { + fn clone(&self) -> Self { + IndFlattenMap { + source: self.source.clone(), + fun: Arc::clone(&self.fun), + } + } +} + +impl<S : Strategy, R : Strategy, + F : Fn(S::Value) -> R> +Strategy for IndFlattenMap<S, F> { + type Tree = ::tuple::TupleValueTree<(S::Tree, R::Tree)>; + type Value = (S::Value, R::Value); + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let left = self.source.new_tree(runner)?; + let right_source = (self.fun)(left.current()); + let right = right_source.new_tree(runner)?; + + Ok(::tuple::TupleValueTree::new((left, right))) + } +} + +#[cfg(test)] +mod test { + use strategy::just::Just; + use super::*; + + #[test] + fn test_flat_map() { + // Pick random integer A, then random integer B which is ±5 of A and + // assert that B <= A if A > 10000. Shrinking should always converge to + // A=10001, B=10002. + let input = (0..65536).prop_flat_map( + |a| (Just(a), (a-5..a+5))); + + let mut failures = 0; + for _ in 0..1000 { + let mut runner = TestRunner::default(); + let case = input.new_tree(&mut runner).unwrap(); + let result = runner.run_one(case, |(a, b)| { + if a <= 10000 || b <= a { + Ok(()) + } else { + Err(TestCaseError::fail("fail")) + } + }); + + match result { + Ok(_) => { }, + Err(TestError::Fail(_, v)) => { + failures += 1; + assert_eq!((10001, 10002), v); + }, + result => panic!("Unexpected result: {:?}", result), + } + } + + assert!(failures > 250); + } + + #[test] + fn test_flat_map_sanity() { + check_strategy_sanity( + (0..65536).prop_flat_map(|a| (Just(a), (a-5..a+5))), + None); + } + + #[test] + fn flat_map_respects_regen_limit() { + use std::sync::atomic::{AtomicBool, Ordering}; + + let input = (0..65536) + .prop_flat_map(|_| 0..65536) + .prop_flat_map(|_| 0..65536) + .prop_flat_map(|_| 0..65536) + .prop_flat_map(|_| 0..65536) + .prop_flat_map(|_| 0..65536); + + // Arteficially make the first case fail and all others pass, so that + // the regeneration logic futilely searches for another failing + // example and eventually gives up. Unfortunately, the test is sort of + // semi-decidable; if the limit *doesn't* work, the test just runs + // almost forever. + let pass = AtomicBool::new(false); + let mut runner = TestRunner::new(Config { + max_flat_map_regens: 1000, + .. Config::default() + }); + let case = input.new_tree(&mut runner).unwrap(); + let _ = runner.run_one(case, |_| { + // Only the first run fails, all others succeed + prop_assert!(pass.fetch_or(true, Ordering::SeqCst)); + Ok(()) + }); + } + + #[test] + fn test_ind_flat_map_sanity() { + check_strategy_sanity( + (0..65536).prop_ind_flat_map(|a| (Just(a), (a-5..a+5))), + None); + } + + #[test] + fn test_ind_flat_map2_sanity() { + check_strategy_sanity( + (0..65536).prop_ind_flat_map2(|a| a-5..a+5), + None); + } +} diff --git a/proptest/src/strategy/fuse.rs b/proptest/src/strategy/fuse.rs new file mode 100644 index 000000000..5ecb3536d --- /dev/null +++ b/proptest/src/strategy/fuse.rs @@ -0,0 +1,228 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use strategy::*; +use test_runner::*; + +/// Adaptor for `Strategy` and `ValueTree` which guards `simplify()` and +/// `complicate()` to avoid contract violations. +/// +/// This can be used as an intermediate when the caller would otherwise need +/// its own separate state tracking, or as a workaround for a broken +/// `ValueTree` implementation. +/// +/// This wrapper specifically has the following effects: +/// +/// - Calling `complicate()` before `simplify()` was ever called does nothing +/// and returns `false`. +/// +/// - Calling `simplify()` after it has returned `false` and no calls to +/// `complicate()` returned `true` does nothing and returns `false`. +/// +/// - Calling `complicate()` after it has returned `false` and no calls to +/// `simplify()` returned `true` does nothing and returns `false`. +/// +/// There is also limited functionality to alter the internal state to assist +/// in its usage as a state tracker. +/// +/// Wrapping a `Strategy` in `Fuse` simply causes its `ValueTree` to also be +/// wrapped in `Fuse`. +/// +/// While this is similar to `std::iter::Fuse`, it is not exposed as a method +/// on `Strategy` since the vast majority of proptest should never need this +/// functionality; it mainly concerns implementors of strategies. +#[derive(Debug, Clone, Copy)] +#[must_use = "strategies do nothing unless used"] +pub struct Fuse<T> { + inner: T, + may_simplify: bool, + may_complicate: bool, +} + +impl<T> Fuse<T> { + /// Wrap the given `T` in `Fuse`. + pub fn new(inner: T) -> Self { + Fuse { + inner, + may_simplify: true, + may_complicate: false, + } + } +} + +impl<T : Strategy> Strategy for Fuse<T> { + type Tree = Fuse<T::Tree>; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.inner.new_tree(runner).map(Fuse::new) + } +} + +impl<T : ValueTree> Fuse<T> { + /// Return whether a call to `simplify()` may be productive. + /// + /// Formally, this is true if one of the following holds: + /// + /// - `simplify()` has never been called. + /// - The most recent call to `simplify()` returned `true`. + /// - `complicate()` has been called more recently than `simplify()` and + /// the last call returned `true`. + pub fn may_simplify(&self) -> bool { + self.may_simplify + } + + /// Disallow any further calls to `simplify()` until a call to + /// `complicate()` returns `true`. + pub fn disallow_simplify(&mut self) { + self.may_simplify = false; + } + + /// Return whether a call to `complicate()` may be productive. + /// + /// Formally, this is true if one of the following holds: + /// + /// - The most recent call to `complicate()` returned `true`. + /// - `simplify()` has been called more recently than `complicate()` and + /// the last call returned `true`. + pub fn may_complicate(&self) -> bool { + self.may_complicate + } + + /// Disallow any further calls to `complicate()` until a call to + /// `simplify()` returns `true`. + pub fn disallow_complicate(&mut self) { + self.may_complicate = false; + } + + /// Prevent any further shrinking operations from occurring. + pub fn freeze(&mut self) { + self.disallow_simplify(); + self.disallow_complicate(); + } +} + +impl<T : ValueTree> ValueTree for Fuse<T> { + type Value = T::Value; + + fn current(&self) -> T::Value { + self.inner.current() + } + + fn simplify(&mut self) -> bool { + if self.may_simplify { + if self.inner.simplify() { + self.may_complicate = true; + true + } else { + self.may_simplify = false; + false + } + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.may_complicate { + if self.inner.complicate() { + self.may_simplify = true; + true + } else { + self.may_complicate = false; + false + } + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + struct StrictValueTree { + min: u32, + curr: u32, + max: u32, + ready: bool, + } + + impl StrictValueTree { + fn new(start: u32) -> Self { + StrictValueTree { + min: 0, + curr: start, + max: start, + ready: false, + } + } + } + + impl ValueTree for StrictValueTree { + type Value = u32; + + fn current(&self) -> u32 { + self.curr + } + + fn simplify(&mut self) -> bool { + assert!(self.min <= self.curr); + if self.curr > self.min { + self.max = self.curr; + self.curr -= 1; + self.ready = true; + true + } else { + self.min += 1; + false + } + } + + fn complicate(&mut self) -> bool { + assert!(self.max >= self.curr); + assert!(self.ready); + if self.curr < self.max { + self.curr += 1; + true + } else { + self.max -= 1; + false + } + } + } + + #[test] + fn test_sanity() { + check_strategy_sanity(Fuse::new(0i32..100i32), None); + } + + #[test] + fn guards_bad_transitions() { + let mut vt = Fuse::new(StrictValueTree::new(5)); + assert!(!vt.complicate()); + assert_eq!(5, vt.current()); + + assert!(vt.simplify()); // 0, 4, 5 + assert!(vt.simplify()); // 0, 3, 4 + assert!(vt.simplify()); // 0, 2, 3 + assert!(vt.simplify()); // 0, 1, 2 + assert!(vt.simplify()); // 0, 0, 1 + assert_eq!(0, vt.current()); + assert!(!vt.simplify()); // 1, 0, 1 + assert!(!vt.simplify()); // 1, 0, 1 + assert_eq!(0, vt.current()); + assert!(vt.complicate()); // 1, 1, 1 + assert_eq!(1, vt.current()); + assert!(!vt.complicate()); // 1, 1, 0 + assert!(!vt.complicate()); // 1, 1, 0 + assert_eq!(1, vt.current()); + } +} diff --git a/proptest/src/strategy/just.rs b/proptest/src/strategy/just.rs new file mode 100644 index 000000000..d769349d8 --- /dev/null +++ b/proptest/src/strategy/just.rs @@ -0,0 +1,130 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::fmt; + +use strategy::{Strategy, ValueTree, NewTree}; +use test_runner::TestRunner; + +macro_rules! noshrink { + () => { + fn simplify(&mut self) -> bool { false } + fn complicate(&mut self) -> bool { false } + }; +} + +//============================================================================== +// Just +//============================================================================== + +/// A `Strategy` which always produces a single value value and never +/// simplifies. +#[derive(Clone, Copy, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct Just<T : Clone + fmt::Debug>( + /// The value produced by this strategy. + pub T); + +impl<T : Clone + fmt::Debug> Strategy for Just<T> { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { + Ok(self.clone()) + } +} + +impl<T : Clone + fmt::Debug> ValueTree for Just<T> { + type Value = T; + noshrink!(); + fn current(&self) -> T { self.0.clone() } +} + +//============================================================================== +// LazyJust +//============================================================================== + +/// A `Strategy` which always produces a single value value and never +/// simplifies. If `T` is `Clone`, you should use `Just` instead. +/// +/// This is a generalization of `Just` and works by calling +/// the provided `Fn () -> T` in `.current()` every time. This is not a +/// very interesting strategy, but is required in cases where `T` is +/// not `Clone`. It is also used in `proptest_derive` where we can't +/// assume that your type is `Clone`. +/// +/// **It is important that the function used be pure.** +#[must_use = "strategies do nothing unless used"] +pub struct LazyJust<T, F: Fn () -> T> { + /// The function executed in `.current()`. + function: F +} + +/// Shorthand for `LazyJust<T, fn () -> T>`. +pub type LazyJustFn<V> = LazyJust<V, fn () -> V>; + +impl<T, F: Fn () -> T> LazyJust<T, F> { + /// Constructs a `LazyJust` strategy given the function/closure + /// that produces the value. + /// + /// **It is important that the function used be pure.** + pub fn new(function: F) -> Self { + Self { function } + } +} + +impl<T: fmt::Debug, F: Clone + Fn () -> T> Strategy for LazyJust<T, F> { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { + Ok(self.clone()) + } +} + +impl<T: fmt::Debug, F: Fn () -> T> ValueTree for LazyJust<T, F> { + type Value = T; + noshrink!(); + fn current(&self) -> Self::Value { (self.function)() } +} + +impl<T, F: Copy + Fn () -> T> Copy for LazyJust<T, F> {} + +impl<T, F: Clone + Fn () -> T> Clone for LazyJust<T, F> { + fn clone(&self) -> Self { + Self { function: self.function.clone() } + } +} + +impl<T, F: Fn () -> T> fmt::Debug for LazyJust<T, F> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("LazyJust") + .field("function", &"<function>") + .finish() + } +} + +//============================================================================== +// Any `fn () -> T` is a Strategy +//============================================================================== + +// TODO: try 'F: Fn () -> T' instead when we've got specialization. + +impl<T: fmt::Debug> Strategy for fn () -> T { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { Ok(*self) } +} + +impl<T: fmt::Debug> ValueTree for fn () -> T { + type Value = T; + noshrink!(); + fn current(&self) -> Self::Value { self() } +} diff --git a/proptest/src/strategy/map.rs b/proptest/src/strategy/map.rs new file mode 100644 index 000000000..121060262 --- /dev/null +++ b/proptest/src/strategy/map.rs @@ -0,0 +1,290 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::fmt; +use core::marker::PhantomData; +use std_facade::Arc; + +use strategy::traits::*; +use test_runner::*; + +//============================================================================== +// Map +//============================================================================== + +/// `Strategy` and `ValueTree` map adaptor. +/// +/// See `Strategy::prop_map()`. +#[must_use = "strategies do nothing unless used"] +pub struct Map<S, F> { + pub(super) source: S, + pub(super) fun: Arc<F>, +} + +impl<S : fmt::Debug, F> fmt::Debug for Map<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Map") + .field("source", &self.source) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Clone, F> Clone for Map<S, F> { + fn clone(&self) -> Self { + Map { + source: self.source.clone(), + fun: Arc::clone(&self.fun), + } + } +} + +impl<S : Strategy, O : fmt::Debug, + F : Fn (S::Value) -> O> +Strategy for Map<S, F> { + type Tree = Map<S::Tree, F>; + type Value = O; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.source.new_tree(runner).map( + |v| Map { source: v, fun: Arc::clone(&self.fun) }) + } +} + +impl<S : ValueTree, O : fmt::Debug, F : Fn (S::Value) -> O> +ValueTree for Map<S, F> { + type Value = O; + + fn current(&self) -> O { + (self.fun)(self.source.current()) + } + + fn simplify(&mut self) -> bool { + self.source.simplify() + } + + fn complicate(&mut self) -> bool { + self.source.complicate() + } +} + +//============================================================================== +// MapInto +//============================================================================== + +// NOTE: Since this is external stable API, +// we avoid relying on the Map in `statics`. + +/// `Strategy` and `ValueTree` map into adaptor. +/// +/// See `Strategy::prop_map_into()`. +#[must_use = "strategies do nothing unless used"] +pub struct MapInto<S, O> { + pub(super) source: S, + pub(super) output: PhantomData<O>, +} + +impl<S, O> MapInto<S, O> { + /// Construct a `MapInto` mapper from an `S` strategy into a strategy + /// producing `O`s. + pub(super) fn new(source: S) -> Self { + Self { source, output: PhantomData } + } +} + +impl<S : fmt::Debug, O> fmt::Debug for MapInto<S, O> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MapInto").field("source", &self.source).finish() + } +} + +impl<S : Clone, O> Clone for MapInto<S, O> { + fn clone(&self) -> Self { + Self::new(self.source.clone()) + } +} + +impl<S : Strategy, O : fmt::Debug> Strategy for MapInto<S, O> +where + S::Value : Into<O> +{ + type Tree = MapInto<S::Tree, O>; + type Value = O; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.source.new_tree(runner).map(MapInto::new) + } +} + +impl<S : ValueTree, O : fmt::Debug> ValueTree for MapInto<S, O> +where + S::Value: Into<O> +{ + type Value = O; + + fn current(&self) -> O { + self.source.current().into() + } + + fn simplify(&mut self) -> bool { + self.source.simplify() + } + + fn complicate(&mut self) -> bool { + self.source.complicate() + } +} + +//============================================================================== +// Perturb +//============================================================================== + +/// `Strategy` perturbation adaptor. +/// +/// See `Strategy::prop_perturb()`. +#[must_use = "strategies do nothing unless used"] +pub struct Perturb<S, F> { + pub(super) source: S, + pub(super) fun: Arc<F>, +} + +impl<S : fmt::Debug, F> fmt::Debug for Perturb<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Perturb") + .field("source", &self.source) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Clone, F> Clone for Perturb<S, F> { + fn clone(&self) -> Self { + Perturb { + source: self.source.clone(), + fun: Arc::clone(&self.fun), + } + } +} + +impl<S : Strategy, O : fmt::Debug, + F : Fn (S::Value, TestRng) -> O> +Strategy for Perturb<S, F> { + type Tree = PerturbValueTree<S::Tree, F>; + type Value = O; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let rng = runner.new_rng(); + + self.source.new_tree(runner).map(|source| + PerturbValueTree { source, rng, fun: Arc::clone(&self.fun) } + ) + } +} + +/// `ValueTree` perturbation adaptor. +/// +/// See `Strategy::prop_perturb()`. +pub struct PerturbValueTree<S, F> { + source: S, + fun: Arc<F>, + rng: TestRng, +} + +impl<S : fmt::Debug, F> fmt::Debug for PerturbValueTree<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("PerturbValueTree") + .field("source", &self.source) + .field("fun", &"<function>") + .field("rng", &self.rng) + .finish() + } +} + +impl<S : Clone, F> Clone for PerturbValueTree<S, F> { + fn clone(&self) -> Self { + PerturbValueTree { + source: self.source.clone(), + fun: Arc::clone(&self.fun), + rng: self.rng.clone(), + } + } +} + +impl<S : ValueTree, O : fmt::Debug, F : Fn (S::Value, TestRng) -> O> +ValueTree for PerturbValueTree<S, F> { + type Value = O; + + fn current(&self) -> O { + (self.fun)(self.source.current(), self.rng.clone()) + } + + fn simplify(&mut self) -> bool { + self.source.simplify() + } + + fn complicate(&mut self) -> bool { + self.source.complicate() + } +} + +//============================================================================== +// Tests +//============================================================================== + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use rand::RngCore; + + use strategy::just::Just; + use super::*; + + #[test] + fn test_map() { + TestRunner::default() + .run(&(0..10).prop_map(|v| v * 2), |v| { + assert!(0 == v % 2); + Ok(()) + }).unwrap(); + } + + #[test] + fn test_map_into() { + TestRunner::default() + .run(&(0..10u8).prop_map_into::<usize>(), |v| { + assert!(v < 10); + Ok(()) + }).unwrap(); + } + + #[test] + fn perturb_uses_same_rng_every_time() { + let mut runner = TestRunner::default(); + let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32()); + + for _ in 0..16 { + let value = input.new_tree(&mut runner).unwrap(); + assert_eq!(value.current(), value.current()); + } + } + + #[test] + fn perturb_uses_varying_random_seeds() { + let mut runner = TestRunner::default(); + let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32()); + + let mut seen = HashSet::new(); + for _ in 0..64 { + seen.insert(input.new_tree(&mut runner).unwrap().current()); + } + + assert_eq!(64, seen.len()); + } +} diff --git a/proptest/src/strategy/mod.rs b/proptest/src/strategy/mod.rs new file mode 100644 index 000000000..0d1865b63 --- /dev/null +++ b/proptest/src/strategy/mod.rs @@ -0,0 +1,34 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines the core traits used by Proptest. + +mod traits; +mod just; +mod map; +mod filter; +mod filter_map; +mod flatten; +mod unions; +mod recursive; +mod shuffle; +mod fuse; + +pub use self::traits::*; +pub use self::just::*; +pub use self::map::*; +pub use self::filter::*; +pub use self::filter_map::*; +pub use self::flatten::*; +pub use self::unions::*; +pub use self::recursive::*; +pub use self::shuffle::*; +pub use self::fuse::*; + +pub mod statics; diff --git a/proptest/src/strategy/recursive.rs b/proptest/src/strategy/recursive.rs new file mode 100644 index 000000000..bd9b459c8 --- /dev/null +++ b/proptest/src/strategy/recursive.rs @@ -0,0 +1,200 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::{fmt, Arc, Box, Vec}; + +use strategy::traits::*; +use strategy::unions::float_to_weight; +use test_runner::*; + +/// Return type from `Strategy::prop_recursive()`. +#[must_use = "strategies do nothing unless used"] +pub struct Recursive<T, F> { + base: BoxedStrategy<T>, + recurse: Arc<F>, + depth: u32, + desired_size: u32, + expected_branch_size: u32, +} + +impl<T: fmt::Debug, F> fmt::Debug for Recursive<T, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Recursive") + .field("base", &self.base) + .field("recurse", &"<function>") + .field("depth", &self.depth) + .field("desired_size", &self.desired_size) + .field("expected_branch_size", &self.expected_branch_size) + .finish() + } +} + +impl<T, F> Clone for Recursive<T, F> { + fn clone(&self) -> Self { + Recursive { + base: self.base.clone(), + recurse: Arc::clone(&self.recurse), + depth: self.depth, + desired_size: self.desired_size, + expected_branch_size: self.expected_branch_size, + } + } +} + +impl<T : fmt::Debug + 'static, + R : Strategy<Value = T> + 'static, + F : Fn (BoxedStrategy<T>) -> R> +Recursive<T, F> { + pub(super) fn new + (base: impl Strategy<Value = T> + 'static, + depth: u32, desired_size: u32, expected_branch_size: u32, + recurse: F) + -> Self + { + Self { + base: base.boxed(), + recurse: Arc::new(recurse), + depth, desired_size, expected_branch_size, + } + } +} + +impl<T : fmt::Debug + 'static, + R : Strategy<Value = T> + 'static, + F : Fn (BoxedStrategy<T>) -> R> +Strategy for Recursive<T, F> { + type Tree = Box<dyn ValueTree<Value = T>>; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + // Since the generator is stateless, we can't implement any "absolutely + // X many items" rule. We _can_, however, with extremely high + // probability, obtain a value near what we want by using decaying + // probabilities of branching as we go down the tree. + // + // We are given a target size S and a branch size K (branch size = + // expected number of items immediately below each branch). We select + // some probability P for each level. + // + // A single level l is thus expected to hold PlK branches. Each of + // those will have P(l+1)K child branches of their own, so there are + // PlP(l+1)K² second-level branches. The total branches in the tree is + // thus (Σ PlK^l) for l from 0 to infinity. Each level is expected to + // hold K items, so the total number of items is simply K times the + // number of branches, or (K Σ PlK^l). So we want to find a P sequence + // such that (lim (K Σ PlK^l) = S), or more simply, + // (lim Σ PlK^l = S/K). + // + // Let Q be a second probability sequence such that Pl = Ql/K^l. This + // changes the formulation to (lim Σ Ql = S/K). The series Σ0.5^(l+1) + // converges on 1.0, so we can let Ql = S/K * 0.5^(l+1), and so + // Pl = S/K^(l+1) * 0.5^(l+1) = S / (2K) ^ (l+1) + // + // We don't actually have infinite levels here since we _can_ easily + // cap to a fixed max depth, so this will be a minor underestimate. We + // also clamp all probabilities to 0.9 to ensure that we can't end up + // with levels which are always pure branches, which further + // underestimates size. + + let mut branch_probabilities = Vec::new(); + let mut k2 = u64::from(self.expected_branch_size) * 2; + for _ in 0..self.depth { + branch_probabilities.push(f64::from(self.desired_size) / k2 as f64); + k2 = k2.saturating_mul(u64::from(self.expected_branch_size) * 2); + } + + let mut strat = self.base.clone(); + while let Some(branch_probability) = branch_probabilities.pop() { + let recursed = (self.recurse)(strat.clone()); + let recursive_choice = recursed.boxed(); + let non_recursive_choice = strat; + // Clamp the maximum branch probability to 0.9 to ensure we can + // generate non-recursive cases reasonably often. + let branch_probability = branch_probability.min(0.9); + let (weight_branch, weight_leaf) = + float_to_weight(branch_probability); + let branch = prop_oneof![ + weight_leaf => non_recursive_choice, + weight_branch => recursive_choice, + ]; + strat = branch.boxed(); + } + + strat.new_tree(runner) + } +} + +#[cfg(test)] +mod test { + use std::cmp::max; + + use strategy::just::Just; + use super::*; + + #[derive(Clone, Debug, PartialEq)] + enum Tree { + Leaf, + Branch(Vec<Tree>), + } + + impl Tree { + fn stats(&self) -> (u32, u32) { + match *self { + Tree::Leaf => (0, 1), + Tree::Branch(ref children) => { + let mut depth = 0; + let mut count = 0; + for child in children { + let (d, c) = child.stats(); + depth = max(d, depth); + count += c; + } + + (depth + 1, count + 1) + } + } + } + } + + #[test] + fn test_recursive() { + let mut max_depth = 0; + let mut max_count = 0; + + let strat = Just(Tree::Leaf).prop_recursive(4, 64, 16, + |element| ::collection::vec(element, 8..16).prop_map(Tree::Branch)); + + let mut runner = TestRunner::default(); + for _ in 0..65536 { + let tree = strat.new_tree(&mut runner).unwrap().current(); + let (depth, count) = tree.stats(); + assert!(depth <= 4, "Got depth {}", depth); + assert!(count <= 128, "Got count {}", count); + max_depth = max(depth, max_depth); + max_count = max(count, max_count); + } + + assert!(max_depth >= 3, "Only got max depth {}", max_depth); + assert!(max_count > 48, "Only got max count {}", max_count); + } + + #[test] + fn simplifies_to_non_recursive() { + let strat = Just(Tree::Leaf).prop_recursive(4, 64, 16, + |element| ::collection::vec(element, 8..16).prop_map(Tree::Branch)); + + let mut runner = TestRunner::default(); + for _ in 0..256 { + let mut value = strat.new_tree(&mut runner).unwrap(); + while value.simplify() { } + + assert_eq!(Tree::Leaf, value.current()); + } + } +} diff --git a/proptest/src/strategy/shuffle.rs b/proptest/src/strategy/shuffle.rs new file mode 100644 index 000000000..ed1c8bf7f --- /dev/null +++ b/proptest/src/strategy/shuffle.rs @@ -0,0 +1,271 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::{Cell, VecDeque, Vec}; + +use rand::Rng; + +use num; +use strategy::traits::*; +use test_runner::*; + +/// `Strategy` shuffle adaptor. +/// +/// See `Strategy::prop_shuffle()`. +#[derive(Clone, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct Shuffle<S>(pub(super) S); + +/// A value which can be used with the `prop_shuffle` combinator. +/// +/// This is not a general-purpose trait. Its methods are prefixed with +/// `shuffle_` to avoid the compiler suggesting them or this trait as +/// corrections in errors. +pub trait Shuffleable { + /// Return the length of this collection. + fn shuffle_len(&self) -> usize; + /// Swap the elements at the given indices. + fn shuffle_swap(&mut self, a: usize, b: usize); +} + +macro_rules! shuffleable { + ($($t:tt)*) => { + impl<T> Shuffleable for $($t)* { + fn shuffle_len(&self) -> usize { + self.len() + } + + fn shuffle_swap(&mut self, a: usize, b: usize) { + self.swap(a, b); + } + } + } +} + +shuffleable!([T]); +shuffleable!(Vec<T>); +shuffleable!(VecDeque<T>); +// Zero- and 1-length arrays aren't usefully shuffleable, but are included to +// simplify external macros that may try to use them anyway. +shuffleable!([T;0]); +shuffleable!([T;1]); +shuffleable!([T;2]); +shuffleable!([T;3]); +shuffleable!([T;4]); +shuffleable!([T;5]); +shuffleable!([T;6]); +shuffleable!([T;7]); +shuffleable!([T;8]); +shuffleable!([T;9]); +shuffleable!([T;10]); +shuffleable!([T;11]); +shuffleable!([T;12]); +shuffleable!([T;13]); +shuffleable!([T;14]); +shuffleable!([T;15]); +shuffleable!([T;16]); +shuffleable!([T;17]); +shuffleable!([T;18]); +shuffleable!([T;19]); +shuffleable!([T;20]); +shuffleable!([T;21]); +shuffleable!([T;22]); +shuffleable!([T;23]); +shuffleable!([T;24]); +shuffleable!([T;25]); +shuffleable!([T;26]); +shuffleable!([T;27]); +shuffleable!([T;28]); +shuffleable!([T;29]); +shuffleable!([T;30]); +shuffleable!([T;31]); +shuffleable!([T;32]); + +impl<S : Strategy> Strategy for Shuffle<S> +where S::Value : Shuffleable { + type Tree = ShuffleValueTree<S::Tree>; + type Value = S::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let rng = runner.new_rng(); + + self.0.new_tree(runner).map(|inner| ShuffleValueTree { + inner, rng, + dist: Cell::new(None), + simplifying_inner: false, + }) + } +} + +/// `ValueTree` shuffling adaptor. +/// +/// See `Strategy::prop_shuffle()`. +#[derive(Clone, Debug)] +pub struct ShuffleValueTree<V> { + inner: V, + rng: TestRng, + /// The maximum amount to move any one element during shuffling. + /// + /// This is `Cell` since we can't determine the bounds of the value until + /// the first call to `current()`. (We technically _could_ by generating a + /// value in `new_tree` and checking its length, but that would be a 100% + /// slowdown.) + dist: Cell<Option<num::usize::BinarySearch>>, + /// Whether we've started simplifying `inner`. After this point, we can no + /// longer simplify or complicate `dist`. + simplifying_inner: bool, +} + + +impl<V : ValueTree> ShuffleValueTree<V> +where V::Value : Shuffleable { + fn init_dist(&self, dflt: usize) -> usize { + if self.dist.get().is_none() { + self.dist.set(Some(num::usize::BinarySearch::new(dflt))); + } + + self.dist.get().unwrap().current() + } + + fn force_init_dist(&self) { + if self.dist.get().is_none() { + self.init_dist(self.current().shuffle_len()); + } + } +} + +impl<V : ValueTree> ValueTree for ShuffleValueTree<V> +where V::Value : Shuffleable { + type Value = V::Value; + + fn current(&self) -> V::Value { + let mut value = self.inner.current(); + let len = value.shuffle_len(); + // The maximum distance to swap elements. This could be larger than + // `value` if `value` has reduced size during shrinking; that's OK, + // since we only use this to filter swaps. + let max_swap = self.init_dist(len); + + // If empty collection or all swaps will be filtered out, there's + // nothing to shuffle. + if 0 == len || 0 == max_swap { return value; } + + let mut rng = self.rng.clone(); + + for start_index in 0..len - 1 { + // Determine the other index to be swapped, then skip the swap if + // it is too far. This ordering is critical, as it ensures that we + // generate the same sequence of random numbers every time. + let end_index = rng.gen_range(start_index + 1, len); + if end_index - start_index <= max_swap { + value.shuffle_swap(start_index, end_index); + } + } + + value + } + + fn simplify(&mut self) -> bool { + if self.simplifying_inner { + self.inner.simplify() + } else { + // Ensure that we've initialised `dist` to *something* to give + // consistent non-panicking behaviour even if called in an + // unexpected sequence. + self.force_init_dist(); + if self.dist.get_mut().as_mut().unwrap().simplify() { + true + } else { + self.simplifying_inner = true; + self.inner.simplify() + } + } + } + + fn complicate(&mut self) -> bool { + if self.simplifying_inner { + self.inner.complicate() + } else { + self.force_init_dist(); + self.dist.get_mut().as_mut().unwrap().complicate() + } + } +} + +#[cfg(test)] +mod test { + use std::borrow::ToOwned; + use std::collections::HashSet; + use std::i32; + + use collection; + use strategy::just::Just; + use super::*; + + static VALUES: &'static [i32] = &[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + ]; + + #[test] + fn generates_different_permutations() { + let mut runner = TestRunner::default(); + let mut seen = HashSet::<Vec<i32>>::new(); + + let input = Just(VALUES.to_owned()).prop_shuffle(); + + for _ in 0..1024 { + let mut value = input.new_tree(&mut runner).unwrap().current(); + + assert!(seen.insert(value.clone()), + "Value {:?} generated more than once", value); + + value.sort(); + assert_eq!(VALUES, &value[..]); + } + } + + #[test] + fn simplify_reduces_shuffle_amount() { + let mut runner = TestRunner::default(); + + let input = Just(VALUES.to_owned()).prop_shuffle(); + for _ in 0..1024 { + let mut value = input.new_tree(&mut runner).unwrap(); + + let mut prev_dist = i32::MAX; + loop { + let v = value.current(); + // Compute the "shuffle distance" by summing the absolute + // distance of each element's displacement. + let mut dist = 0; + for (ix, &nominal) in v.iter().enumerate() { + dist += (nominal - ix as i32).abs(); + } + + assert!(dist <= prev_dist, + "dist = {}, prev_dist = {}", dist, prev_dist); + + prev_dist = dist; + if !value.simplify() { + break + } + } + + // When fully simplified, the result is in the original order. + assert_eq!(0, prev_dist); + } + } + + #[test] + fn simplify_complicate_contract_upheld() { + check_strategy_sanity( + collection::vec(0i32..1000, 5..10).prop_shuffle(), None); + } +} diff --git a/proptest/src/strategy/statics.rs b/proptest/src/strategy/statics.rs new file mode 100644 index 000000000..e4a90deae --- /dev/null +++ b/proptest/src/strategy/statics.rs @@ -0,0 +1,253 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Modified versions of the normal strategy combinators which take specialised +//! traits instead of normal functions. +//! +//! This entire module is strictly a workaround until +//! <https://github.com/rust-lang/rfcs/pull/1522> and +//! <https://github.com/rust-lang/rfcs/pull/2071> are available in stable. It +//! allows naming types built on the combinators without resorting to dynamic +//! dispatch or causing `Arc` to allocate space for a function pointer. +//! +//! External code is discouraged from using this module directly. It is +//! deliberately not exposed in a convenient way (i.e., via the `Strategy` +//! trait itself), but is nonetheless exposed since external trait implementors +//! may face the same issues. +//! +//! **This module is subject to removal at some point after the language +//! features linked above become stable.** + +use std_facade::fmt; + +use strategy::traits::*; +use test_runner::*; + +//============================================================================== +// Filter +//============================================================================== + +/// Essentially `Fn (&T) -> bool`. +pub trait FilterFn<T> { + /// Test whether `t` passes the filter. + fn apply(&self, t: &T) -> bool; +} + +/// Static version of `strategy::Filter`. +#[derive(Clone)] +#[must_use = "strategies do nothing unless used"] +pub struct Filter<S, F> { + source: S, + whence: Reason, + fun: F, +} + +impl<S, F> Filter<S, F> { + /// Adapt strategy `source` to reject values which do not pass `filter`, + /// using `whence` as the reported reason/location. + pub fn new(source: S, whence: Reason, filter: F) -> Self { + // NOTE: We don't use universal quantification R: Into<Reason> + // since the module is not conviniently exposed. + Filter { source, whence, fun: filter } + } +} + +impl<S : fmt::Debug, F> fmt::Debug for Filter<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Filter") + .field("source", &self.source) + .field("whence", &self.whence) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Strategy, + F : FilterFn<S::Value> + Clone> +Strategy for Filter<S, F> { + type Tree = Filter<S::Tree, F>; + type Value = S::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + loop { + let val = self.source.new_tree(runner)?; + if !self.fun.apply(&val.current()) { + runner.reject_local(self.whence.clone())?; + } else { + return Ok(Filter { + source: val, + whence: "unused".into(), + fun: self.fun.clone(), + }) + } + } + } +} + +impl<S : ValueTree, F : FilterFn<S::Value>> Filter<S, F> { + fn ensure_acceptable(&mut self) { + while !self.fun.apply(&self.source.current()) { + if !self.source.complicate() { + panic!("Unable to complicate filtered strategy \ + back into acceptable value"); + } + } + } +} + +impl<S : ValueTree, F : FilterFn<S::Value>> ValueTree for Filter<S, F> { + type Value = S::Value; + + fn current(&self) -> S::Value { + self.source.current() + } + + fn simplify(&mut self) -> bool { + if self.source.simplify() { + self.ensure_acceptable(); + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if self.source.complicate() { + self.ensure_acceptable(); + true + } else { + false + } + } +} + +//============================================================================== +// Map +//============================================================================== + +/// Essentially `Fn (T) -> Output`. +pub trait MapFn<T> { + #[allow(missing_docs)] + type Output : fmt::Debug; + + /// Map `T` to `Output`. + fn apply(&self, t: T) -> Self::Output; +} + +/// Static version of `strategy::Map`. +#[derive(Clone)] +#[must_use = "strategies do nothing unless used"] +pub struct Map<S, F> { + source: S, + fun: F, +} + +impl<S, F> Map<S, F> { + /// Adapt strategy `source` by applying `fun` to values it produces. + pub fn new(source: S, fun: F) -> Self { + Map { source, fun } + } +} + +impl<S : fmt::Debug, F> fmt::Debug for Map<S, F> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Map") + .field("source", &self.source) + .field("fun", &"<function>") + .finish() + } +} + +impl<S : Strategy, F : Clone + MapFn<S::Value>> Strategy for Map<S, F> { + type Tree = Map<S::Tree, F>; + type Value = F::Output; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.source.new_tree(runner).map( + |v| Map { source: v, fun: self.fun.clone() }) + } +} + +impl<S : ValueTree, F : MapFn<S::Value>> +ValueTree for Map<S, F> { + type Value = F::Output; + + fn current(&self) -> F::Output { + self.fun.apply(self.source.current()) + } + + fn simplify(&mut self) -> bool { + self.source.simplify() + } + + fn complicate(&mut self) -> bool { + self.source.complicate() + } +} + +impl<I, O: fmt::Debug> MapFn<I> for fn(I) -> O { + type Output = O; + fn apply(&self, x: I) -> Self::Output { self(x) } +} + +pub(crate) fn static_map<S: Strategy, O: fmt::Debug> + (strat: S, fun: fn(S::Value) -> O) + -> Map<S, fn(S::Value) -> O> { + Map::new(strat, fun) +} + +//============================================================================== +// Tests +//============================================================================== + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_static_filter() { + #[derive(Clone, Copy, Debug)] + struct MyFilter; + impl FilterFn<i32> for MyFilter { + fn apply(&self, &v: &i32) -> bool { 0 == v % 3 } + } + + let input = Filter::new(0..256, "%3".into(), MyFilter); + + for _ in 0..256 { + let mut runner = TestRunner::default(); + let mut case = input.new_tree(&mut runner).unwrap(); + + assert!(0 == case.current() % 3); + + while case.simplify() { + assert!(0 == case.current() % 3); + } + assert!(0 == case.current() % 3); + } + } + + #[test] + fn test_static_map() { + #[derive(Clone, Copy, Debug)] + struct MyMap; + impl MapFn<i32> for MyMap { + type Output = i32; + fn apply(&self, v: i32) -> i32 { v * 2 } + } + + let input = Map::new(0..10, MyMap); + + TestRunner::default() + .run(&input, |v| { + assert!(0 == v % 2); + Ok(()) + }).unwrap(); + } +} diff --git a/proptest/src/strategy/traits.rs b/proptest/src/strategy/traits.rs new file mode 100644 index 000000000..fd1c36262 --- /dev/null +++ b/proptest/src/strategy/traits.rs @@ -0,0 +1,924 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::cmp; +use std_facade::{fmt, Box, Rc, Arc}; + +use strategy::*; +use test_runner::*; + +//============================================================================== +// Traits +//============================================================================== + +/// A new [`ValueTree`] from a [`Strategy`] when [`Ok`] or otherwise [`Err`] +/// when a new value-tree can not be produced for some reason such as +/// in the case of filtering with a predicate which always returns false. +/// You should pass in your strategy as the type parameter. +/// +/// [`Strategy`]: trait.Strategy.html +/// [`ValueTree`]: trait.ValueTree.html +/// [`Ok`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Ok +/// [`Err`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Err +pub type NewTree<S> = Result<<S as Strategy>::Tree, Reason>; + +/// The value that functions under test use for a particular `Strategy`. +#[deprecated(since = "0.8.0", note="please use `S::Value` instead")] +pub type ValueFor<S> = <<S as Strategy>::Tree as ValueTree>::Value; + +/// A strategy for producing arbitrary values of a given type. +/// +/// `fmt::Debug` is a hard requirement for all strategies currently due to +/// `prop_flat_map()`. This constraint will be removed when specialisation +/// becomes stable. +pub trait Strategy : fmt::Debug { + /// The value tree generated by this `Strategy`. + type Tree : ValueTree<Value = Self::Value>; + + /// The type of value used by functions under test generated by this Strategy. + /// + /// This corresponds to the same type as the associated type `Value` + /// in `Self::Tree`. It is provided here to simplify usage particularly + /// in conjunction with `-> impl Strategy<Value = MyType>`. + type Value : fmt::Debug; + + /// Generate a new value tree from the given runner. + /// + /// This may fail if there are constraints on the generated value and the + /// generator is unable to produce anything that satisfies them. Any + /// failure is wrapped in `TestError::Abort`. + /// + /// This method is generally expected to be deterministic. That is, given a + /// `TestRunner` with its RNG in a particular state, this should produce an + /// identical `ValueTree` every time. Non-deterministic strategies do not + /// cause problems during normal operation, but they do break failure + /// persistence since it is implemented by simply saving the seed used to + /// generate the test case. + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self>; + + /// Returns a strategy which produces values transformed by the function + /// `fun`. + /// + /// There is no need (or possibility, for that matter) to define how the + /// output is to be shrunken. Shrinking continues to take place in terms of + /// the source value. + fn prop_map<O : fmt::Debug, + F : Fn (Self::Value) -> O> + (self, fun: F) -> Map<Self, F> + where Self : Sized { + Map { source: self, fun: Arc::new(fun) } + } + + /// Returns a strategy which produces values of type `O` by transforming + /// `Self` with `Into<O>`. + /// + /// You should always prefer this operation instead of `prop_map` when + /// you can as it is both clearer and also currently more efficient. + /// + /// There is no need (or possibility, for that matter) to define how the + /// output is to be shrunken. Shrinking continues to take place in terms of + /// the source value. + fn prop_map_into<O : fmt::Debug>(self) -> MapInto<Self, O> + where + Self : Sized, + Self::Value: Into<O> + { + MapInto::new(self) + } + + /// Returns a strategy which produces values transformed by the function + /// `fun`, which is additionally given a random number generator. + /// + /// This is exactly like `prop_map()` except for the addition of the second + /// argument to the function. This allows introducing chaotic variations to + /// generated values that are not easily expressed otherwise while allowing + /// shrinking to proceed reasonably. + /// + /// During shrinking, `fun` is always called with an identical random + /// number generator, so if it is a pure function it will always perform + /// the same perturbation. + /// + /// ## Example + /// + /// ``` + /// #[macro_use] extern crate proptest; + /// // The prelude also gets us the `Rng` trait. + /// use proptest::prelude::*; + /// + /// proptest! { + /// #[test] + /// fn test_something(a in (0i32..10).prop_perturb( + /// // Perturb the integer `a` (range 0..10) to a pair of that + /// // integer and another that's ± 10 of it. + /// // Note that this particular case would be better implemented as + /// // `(0i32..10, -10i32..10).prop_map(|(a, b)| (a, a + b))` + /// // but is shown here for simplicity. + /// |centre, rng| (centre, centre + rng.gen_range(-10, 10)))) + /// { + /// // Test stuff + /// } + /// } + /// # fn main() { } + /// ``` + fn prop_perturb<O : fmt::Debug, + F : Fn (Self::Value, TestRng) -> O> + (self, fun: F) -> Perturb<Self, F> + where Self : Sized { + Perturb { source: self, fun: Arc::new(fun) } + } + + /// Maps values produced by this strategy into new strategies and picks + /// values from those strategies. + /// + /// `fun` is used to transform the values produced by this strategy into + /// other strategies. Values are then chosen from the derived strategies. + /// Shrinking proceeds by shrinking individual values as well as shrinking + /// the input used to generate the internal strategies. + /// + /// ## Shrinking + /// + /// In the case of test failure, shrinking will not only shrink the output + /// from the combinator itself, but also the input, i.e., the strategy used + /// to generate the output itself. Doing this requires searching the new + /// derived strategy for a new failing input. The combinator will generate + /// up to `Config::cases` values for this search. + /// + /// As a result, nested `prop_flat_map`/`Flatten` combinators risk + /// exponential run time on this search for new failing values. To ensure + /// that test failures occur within a reasonable amount of time, all of + /// these combinators share a single "flat map regen" counter, and will + /// stop generating new values if it exceeds `Config::max_flat_map_regens`. + /// + /// ## Example + /// + /// Generate two integers, where the second is always less than the first, + /// without using filtering: + /// + /// ``` + /// #[macro_use] extern crate proptest; + /// + /// use proptest::prelude::*; + /// + /// proptest! { + /// # /* + /// #[test] + /// # */ + /// fn test_two( + /// // Pick integers in the 1..65536 range, and derive a strategy + /// // which emits a tuple of that integer and another one which is + /// // some value less than it. + /// (a, b) in (1..65536).prop_flat_map(|a| (Just(a), 0..a)) + /// ) { + /// prop_assert!(b < a); + /// } + /// } + /// # + /// # fn main() { test_two(); } + /// ``` + /// + /// ## Choosing the right flat-map + /// + /// `Strategy` has three "flat-map" combinators. They look very similar at + /// first, and can be used to produce superficially identical test results. + /// For example, the following three expressions all produce inputs which + /// are 2-tuples `(a,b)` where the `b` component is less than `a`. + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use proptest::prelude::*; + /// + /// let flat_map = (1..10).prop_flat_map(|a| (Just(a), 0..a)); + /// let ind_flat_map = (1..10).prop_ind_flat_map(|a| (Just(a), 0..a)); + /// let ind_flat_map2 = (1..10).prop_ind_flat_map2(|a| 0..a); + /// ``` + /// + /// The three do differ however in terms of how they shrink. + /// + /// For `flat_map`, both `a` and `b` will shrink, and the invariant that + /// `b < a` is maintained. This is a "dependent" or "higher-order" strategy + /// in that it remembers that the strategy for choosing `b` is dependent on + /// the value chosen for `a`. + /// + /// For `ind_flat_map`, the invariant `b < a` is maintained, but only + /// because `a` does not shrink. This is due to the fact that the + /// dependency between the strategies is not tracked; `a` is simply seen as + /// a constant. + /// + /// Finally, for `ind_flat_map2`, the invariant `b < a` is _not_ + /// maintained, because `a` can shrink independently of `b`, again because + /// the dependency between the two variables is not tracked, but in this + /// case the derivation of `a` is still exposed to the shrinking system. + /// + /// The use-cases for the independent flat-map variants is pretty narrow. + /// For the majority of cases where invariants need to be maintained and + /// you want all components to shrink, `prop_flat_map` is the way to go. + /// `prop_ind_flat_map` makes the most sense when the input to the map + /// function is not exposed in the output and shrinking across strategies + /// is not expected to be useful. `prop_ind_flat_map2` is useful for using + /// related values as starting points while not constraining them to that + /// relation. + fn prop_flat_map<S : Strategy, + F : Fn (Self::Value) -> S> + (self, fun: F) -> Flatten<Map<Self, F>> + where Self : Sized { + Flatten::new(Map { source: self, fun: Arc::new(fun) }) + } + + /// Maps values produced by this strategy into new strategies and picks + /// values from those strategies while considering the new strategies to be + /// independent. + /// + /// This is very similar to `prop_flat_map()`, but shrinking will *not* + /// attempt to shrink the input that produces the derived strategies. This + /// is appropriate for when the derived strategies already fully shrink in + /// the desired way. + /// + /// In most cases, you want `prop_flat_map()`. + /// + /// See `prop_flat_map()` for a more detailed explanation on how the + /// three flat-map combinators differ. + fn prop_ind_flat_map<S : Strategy, + F : Fn (Self::Value) -> S> + (self, fun: F) -> IndFlatten<Map<Self, F>> + where Self : Sized { + IndFlatten(Map { source: self, fun: Arc::new(fun) }) + } + + /// Similar to `prop_ind_flat_map()`, but produces 2-tuples with the input + /// generated from `self` in slot 0 and the derived strategy in slot 1. + /// + /// See `prop_flat_map()` for a more detailed explanation on how the + /// three flat-map combinators differ differ. + fn prop_ind_flat_map2<S : Strategy, + F : Fn (Self::Value) -> S> + (self, fun: F) -> IndFlattenMap<Self, F> + where Self : Sized { + IndFlattenMap { source: self, fun: Arc::new(fun) } + } + + /// Returns a strategy which only produces values accepted by `fun`. + /// + /// This results in a very naïve form of rejection sampling and should only + /// be used if (a) relatively few values will actually be rejected; (b) it + /// isn't easy to express what you want by using another strategy and/or + /// `map()`. + /// + /// There are a lot of downsides to this form of filtering. It slows + /// testing down, since values must be generated but then discarded. + /// Proptest only allows a limited number of rejects this way (across the + /// entire `TestRunner`). Rejection can interfere with shrinking; + /// particularly, complex filters may largely or entirely prevent shrinking + /// from substantially altering the original value. + /// + /// Local rejection sampling is still preferable to rejecting the entire + /// input to a test (via `TestCaseError::Reject`), however, and the default + /// number of local rejections allowed is much higher than the number of + /// whole-input rejections. + /// + /// `whence` is used to record where and why the rejection occurred. + fn prop_filter<R: Into<Reason>, F : Fn (&Self::Value) -> bool> + (self, whence: R, fun: F) -> Filter<Self, F> + where Self : Sized { + Filter::new(self, whence.into(), fun) + } + + /// Returns a strategy which only produces transformed values where `fun` + /// returns `Some(value)` and rejects those where `fun` returns `None`. + /// + /// Using this method is preferable to using `.prop_map(..).prop_filter(..)`. + /// + /// This results in a very naïve form of rejection sampling and should only + /// be used if (a) relatively few values will actually be rejected; (b) it + /// isn't easy to express what you want by using another strategy and/or + /// `map()`. + /// + /// There are a lot of downsides to this form of filtering. It slows + /// testing down, since values must be generated but then discarded. + /// Proptest only allows a limited number of rejects this way (across the + /// entire `TestRunner`). Rejection can interfere with shrinking; + /// particularly, complex filters may largely or entirely prevent shrinking + /// from substantially altering the original value. + /// + /// Local rejection sampling is still preferable to rejecting the entire + /// input to a test (via `TestCaseError::Reject`), however, and the default + /// number of local rejections allowed is much higher than the number of + /// whole-input rejections. + /// + /// `whence` is used to record where and why the rejection occurred. + fn prop_filter_map<F : Fn (Self::Value) -> Option<O>, + O : fmt::Debug> + (self, whence: impl Into<Reason>, fun: F) -> FilterMap<Self, F> + where Self : Sized { + FilterMap::new(self, whence.into(), fun) + } + + /// Returns a strategy which picks uniformly from `self` and `other`. + /// + /// When shrinking, if a value from `other` was originally chosen but that + /// value can be shrunken no further, it switches to a value from `self` + /// and starts shrinking that. + /// + /// Be aware that chaining `prop_union` calls will result in a very + /// right-skewed distribution. If this is not what you want, you can call + /// the `.or()` method on the `Union` to add more values to the same union, + /// or directly call `Union::new()`. + /// + /// Both `self` and `other` must be of the same type. To combine + /// heterogeneous strategies, call the `boxed()` method on both `self` and + /// `other` to erase the type differences before calling `prop_union()`. + fn prop_union(self, other: Self) -> Union<Self> + where Self : Sized { + Union::new(vec![self, other]) + } + + /// Generate a recursive structure with `self` items as leaves. + /// + /// `recurse` is applied to various strategies that produce the same type + /// as `self` with nesting depth _n_ to create a strategy that produces the + /// same type with nesting depth _n+1_. Generated structures will have a + /// depth between 0 and `depth` and will usually have up to `desired_size` + /// total elements, though they may have more. `expected_branch_size` gives + /// the expected maximum size for any collection which may contain + /// recursive elements and is used to control branch probability to achieve + /// the desired size. Passing a too small value can result in trees vastly + /// larger than desired. + /// + /// Note that `depth` only counts branches; i.e., `depth = 0` is a single + /// leaf, and `depth = 1` is a leaf or a branch containing only leaves. + /// + /// In practise, generated values usually have a lower depth than `depth` + /// (but `depth` is a hard limit) and almost always under + /// `expected_branch_size` (though it is not a hard limit) since the + /// underlying code underestimates probabilities. + /// + /// Shrinking shrinks both the inner values and attempts switching from + /// recursive to non-recursive cases. + /// + /// ## Example + /// + /// ```rust,norun + /// # #![allow(unused_variables)] + /// use std::collections::HashMap; + /// + /// #[macro_use] extern crate proptest; + /// use proptest::prelude::*; + /// + /// /// Define our own JSON AST type + /// #[derive(Debug, Clone)] + /// enum JsonNode { + /// Null, + /// Bool(bool), + /// Number(f64), + /// String(String), + /// Array(Vec<JsonNode>), + /// Map(HashMap<String, JsonNode>), + /// } + /// + /// # fn main() { + /// # + /// // Define a strategy for generating leaf nodes of the AST + /// let json_leaf = prop_oneof![ + /// Just(JsonNode::Null), + /// prop::bool::ANY.prop_map(JsonNode::Bool), + /// prop::num::f64::ANY.prop_map(JsonNode::Number), + /// ".*".prop_map(JsonNode::String), + /// ]; + /// + /// // Now define a strategy for a whole tree + /// let json_tree = json_leaf.prop_recursive( + /// 4, // No more than 4 branch levels deep + /// 64, // Target around 64 total elements + /// 16, // Each collection is up to 16 elements long + /// |element| prop_oneof![ + /// // NB `element` is an `Arc` and we'll need to reference it twice, + /// // so we clone it the first time. + /// prop::collection::vec(element.clone(), 0..16) + /// .prop_map(JsonNode::Array), + /// prop::collection::hash_map(".*", element, 0..16) + /// .prop_map(JsonNode::Map) + /// ]); + /// # } + /// ``` + fn prop_recursive<R : Strategy<Value = Self::Value> + 'static, + F : Fn (BoxedStrategy<Self::Value>) -> R> + (self, depth: u32, desired_size: u32, expected_branch_size: u32, + recurse: F) + -> Recursive<Self::Value, F> + where Self : Sized + 'static { + Recursive::new(self, depth, desired_size, expected_branch_size, recurse) + } + + /// Shuffle the contents of the values produced by this strategy. + /// + /// That is, this modifies a strategy producing a `Vec`, slice, etc, to + /// shuffle the contents of that `Vec`/slice/etc. + /// + /// Initially, the value is fully shuffled. During shrinking, the input + /// value will initially be unchanged while the result will gradually be + /// restored to its original order. Once de-shuffling either completes or + /// is cancelled by calls to `complicate()` pinning it to a particular + /// permutation, the inner value will be simplified. + /// + /// ## Example + /// + /// ``` + /// #[macro_use] extern crate proptest; + /// use proptest::prelude::*; + /// + /// static VALUES: &'static [u32] = &[0, 1, 2, 3, 4]; + /// + /// fn is_permutation(orig: &[u32], mut actual: Vec<u32>) -> bool { + /// actual.sort(); + /// orig == &actual[..] + /// } + /// + /// proptest! { + /// # /* + /// #[test] + /// # */ + /// fn test_is_permutation( + /// ref perm in Just(VALUES.to_owned()).prop_shuffle() + /// ) { + /// assert!(is_permutation(VALUES, perm.clone())); + /// } + /// } + /// # + /// # fn main() { test_is_permutation(); } + /// ``` + fn prop_shuffle(self) -> Shuffle<Self> + where + Self : Sized, + Self::Value : Shuffleable + { + Shuffle(self) + } + + /// Erases the type of this `Strategy` so it can be passed around as a + /// simple trait object. + /// + /// See also `sboxed()` if this `Strategy` is `Send` and `Sync` and you + /// want to preserve that information. + /// + /// Strategies of this type afford cheap shallow cloning via reference + /// counting by using an `Arc` internally. + fn boxed(self) -> BoxedStrategy<Self::Value> + where Self : Sized + 'static { + BoxedStrategy(Arc::new(BoxedStrategyWrapper(self))) + } + + /// Erases the type of this `Strategy` so it can be passed around as a + /// simple trait object. + /// + /// Unlike `boxed()`, this conversion retains the `Send` and `Sync` traits + /// on the output. + /// + /// Strategies of this type afford cheap shallow cloning via reference + /// counting by using an `Arc` internally. + fn sboxed(self) -> SBoxedStrategy<Self::Value> + where Self : Sized + Send + Sync + 'static { + SBoxedStrategy(Arc::new(BoxedStrategyWrapper(self))) + } + + /// Wraps this strategy to prevent values from being subject to shrinking. + /// + /// Suppressing shrinking is useful when testing things like linear + /// approximation functions. Ordinarily, proptest will tend to shrink the + /// input to the function until the result is just barely outside the + /// acceptable range whereas the original input may have produced a result + /// far outside of it. Since this makes it harder to see what the actual + /// problem is, making the input `NoShrink` allows learning about inputs + /// that produce more incorrect results. + fn no_shrink(self) -> NoShrink<Self> where Self : Sized { + NoShrink(self) + } +} + +/// A generated value and its associated shrinker. +/// +/// Conceptually, a `ValueTree` represents a spectrum between a "minimally +/// complex" value and a starting, randomly-chosen value. For values such as +/// numbers, this can be thought of as a simple binary search, and this is how +/// the `ValueTree` state machine is defined. +/// +/// The `ValueTree` state machine notionally has three fields: low, current, +/// and high. Initially, low is the "minimally complex" value for the type, and +/// high and current are both the initially chosen value. It can be queried for +/// its current state. When shrinking, the controlling code tries simplifying +/// the value one step. If the test failure still happens with the simplified +/// value, further simplification occurs. Otherwise, the code steps back up +/// towards the prior complexity. +/// +/// The main invariants here are that the "high" value always corresponds to a +/// failing test case, and that repeated calls to `complicate()` will return +/// `false` only once the "current" value has returned to what it was before +/// the last call to `simplify()`. +/// +/// While it would be possible for default do-nothing implementations of +/// `simplify()` and `complicate()` to be provided, this was not done +/// deliberately since the majority of strategies will want to define their own +/// shrinking anyway, and the minority that do not must call it out explicitly +/// by their own implementation. +pub trait ValueTree { + /// The type of the value produced by this `ValueTree`. + type Value : fmt::Debug; + + /// Returns the current value. + fn current(&self) -> Self::Value; + /// Attempts to simplify the current value. Notionally, this sets the + /// "high" value to the current value, and the current value to a "halfway + /// point" between high and low, rounding towards low. + /// + /// Returns whether any state changed as a result of this call. This does + /// not necessarily imply that the value of `current()` has changed, since + /// in the most general case, it is not possible for an implementation to + /// determine this. + /// + /// This call needs to correctly handle being called even immediately after + /// it had been called previously and returned `false`. + fn simplify(&mut self) -> bool; + /// Attempts to partially undo the last simplification. Notionally, this + /// sets the "low" value to one plus the current value, and the current + /// value to a "halfway point" between high and the new low, rounding + /// towards low. + /// + /// Returns whether any state changed as a result of this call. This does + /// not necessarily imply that the value of `current()` has changed, since + /// in the most general case, it is not possible for an implementation to + /// determine this. + /// + /// It is usually expected that, immediately after a call to `simplify()` + /// which returns true, this call will itself return true. However, this is + /// not always the case; in some strategies, particularly those that use + /// some form of rejection sampling, the act of trying to simplify may + /// change the state such that `simplify()` returns true, yet ultimately + /// left the resulting value unchanged, in which case there is nothing left + /// to complicate. + /// + /// This call does not need to gracefully handle being called before + /// `simplify()` was ever called, but does need to correctly handle being + /// called even immediately after it had been called previously and + /// returned `false`. + fn complicate(&mut self) -> bool; +} + +//============================================================================== +// NoShrink +//============================================================================== + +/// Wraps a `Strategy` or `ValueTree` to suppress shrinking of generated +/// values. +/// +/// See `Strategy::no_shrink()` for more details. +#[derive(Clone, Copy, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct NoShrink<T>(T); + +impl<T : Strategy> Strategy for NoShrink<T> { + type Tree = NoShrink<T::Tree>; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.0.new_tree(runner).map(NoShrink) + } +} + +impl<T : ValueTree> ValueTree for NoShrink<T> { + type Value = T::Value; + + fn current(&self) -> T::Value { + self.0.current() + } + + fn simplify(&mut self) -> bool { false } + fn complicate(&mut self) -> bool { false } +} + +//============================================================================== +// Trait objects +//============================================================================== + +macro_rules! proxy_strategy { + ($typ:ty $(, $lt:tt)*) => { + impl<$($lt,)* S : Strategy + ?Sized> Strategy for $typ { + type Tree = S::Tree; + type Value = S::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + (**self).new_tree(runner) + } + } + }; +} +proxy_strategy!(Box<S>); +proxy_strategy!(&'a S, 'a); +proxy_strategy!(&'a mut S, 'a); +proxy_strategy!(Rc<S>); +proxy_strategy!(Arc<S>); + +impl<T : ValueTree + ?Sized> ValueTree for Box<T> { + type Value = T::Value; + fn current(&self) -> Self::Value { (**self).current() } + fn simplify(&mut self) -> bool { (**self).simplify() } + fn complicate(&mut self) -> bool { (**self).complicate() } +} + +/// A boxed `ValueTree`. +type BoxedVT<T> = Box<dyn ValueTree<Value = T>>; + +/// A boxed `Strategy` trait object as produced by `Strategy::boxed()`. +/// +/// Strategies of this type afford cheap shallow cloning via reference +/// counting by using an `Arc` internally. +#[derive(Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct BoxedStrategy<T>( + Arc<dyn Strategy<Value = T, Tree = BoxedVT<T>>>); + +/// A boxed `Strategy` trait object which is also `Sync` and +/// `Send`, as produced by `Strategy::sboxed()`. +/// +/// Strategies of this type afford cheap shallow cloning via reference +/// counting by using an `Arc` internally. +#[derive(Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct SBoxedStrategy<T>( + Arc<dyn Strategy<Value = T, Tree = BoxedVT<T>> + Sync + Send>); + +impl<T> Clone for BoxedStrategy<T> { + fn clone(&self) -> Self { + BoxedStrategy(Arc::clone(&self.0)) + } +} + +impl<T> Clone for SBoxedStrategy<T> { + fn clone(&self) -> Self { + SBoxedStrategy(Arc::clone(&self.0)) + } +} + +impl<T: fmt::Debug> Strategy for BoxedStrategy<T> { + type Tree = BoxedVT<T>; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.0.new_tree(runner) + } + + // Optimization: Don't rebox the strategy. + + fn boxed(self) -> BoxedStrategy<Self::Value> + where Self : Sized + 'static { + self + } +} + +impl<T: fmt::Debug> Strategy for SBoxedStrategy<T> { + type Tree = BoxedVT<T>; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + self.0.new_tree(runner) + } + + // Optimization: Don't rebox the strategy. + + fn sboxed(self) -> SBoxedStrategy<Self::Value> + where Self : Sized + Send + Sync + 'static { + self + } + + fn boxed(self) -> BoxedStrategy<Self::Value> + where Self : Sized + 'static { + BoxedStrategy(self.0) + } +} + +#[derive(Debug)] +struct BoxedStrategyWrapper<T>(T); +impl<T : Strategy> Strategy for BoxedStrategyWrapper<T> +where T::Tree : 'static { + type Tree = Box<dyn ValueTree<Value = T::Value>>; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + Ok(Box::new(self.0.new_tree(runner)?)) + } +} + +//============================================================================== +// Sanity checking +//============================================================================== + +/// Options passed to `check_strategy_sanity()`. +#[derive(Clone, Copy, Debug)] +pub struct CheckStrategySanityOptions { + /// If true (the default), require that `complicate()` return `true` at + /// least once after any call to `simplify()` which itself returns once. + /// + /// This property is not required by contract, but many strategies are + /// designed in a way that this is expected to hold. + pub strict_complicate_after_simplify: bool, + + // Needs to be public for FRU syntax. + #[allow(missing_docs)] + #[doc(hidden)] + pub _non_exhaustive: (), +} + +impl Default for CheckStrategySanityOptions { + fn default() -> Self { + CheckStrategySanityOptions { + strict_complicate_after_simplify: true, + _non_exhaustive: (), + } + } +} + +/// Run some tests on the given `Strategy` to ensure that it upholds the +/// simplify/complicate contracts. +/// +/// This is used to internally test proptest, but is made generally available +/// for external implementations to use as well. +/// +/// `options` can be passed to configure the test; if `None`, the defaults are +/// used. Note that the defaults check for certain properties which are **not** +/// actually required by the `Strategy` and `ValueTree` contracts; if you think +/// your code is right but it fails the test, consider whether a non-default +/// configuration is necessary. +/// +/// This can work with fallible strategies, but limits how many times it will +/// retry failures. +pub fn check_strategy_sanity<S : Strategy>( + strategy: S, options: Option<CheckStrategySanityOptions>) +where S::Tree : Clone + fmt::Debug, S::Value : cmp::PartialEq { + // Like assert_eq!, but also pass if both values do not equal themselves. + // This allows the test to work correctly with things like NaN. + macro_rules! assert_same { + ($a:expr, $b:expr, $($stuff:tt)*) => { { + let a = $a; + let b = $b; + if a == a || b == b { + assert_eq!(a, b, $($stuff)*); + } + } } + } + + let options = options.unwrap_or_else(CheckStrategySanityOptions::default); + let mut runner = TestRunner::default(); + + for _ in 0..1024 { + let mut gen_tries = 0; + let mut state; + loop { + let err = match strategy.new_tree(&mut runner) { + Ok(s) => { state = s; break; }, + Err(e) => e, + }; + + gen_tries += 1; + if gen_tries > 100 { + panic!("Strategy passed to check_strategy_sanity failed \ + to generate a value over 100 times in a row; \ + last failure reason: {}", err); + } + } + + { + let mut state = state.clone(); + let mut count = 0; + while state.simplify() || state.complicate() { + count += 1; + if count > 65536 { + panic!("Failed to converge on any value. State:\n{:#?}", + state); + } + } + } + + let mut num_simplifies = 0; + let mut before_simplified; + loop { + before_simplified = state.clone(); + if !state.simplify() { + break; + } + + let mut complicated = state.clone(); + let before_complicated = state.clone(); + if options.strict_complicate_after_simplify { + assert!(complicated.complicate(), + "complicate() returned false immediately after \ + simplify() returned true. internal state after \ + {} calls to simplify():\n\ + {:#?}\n\ + simplified to:\n\ + {:#?}\n\ + complicated to:\n\ + {:#?}", num_simplifies, before_simplified, state, + complicated); + } + + let mut prev_complicated = complicated.clone(); + let mut num_complications = 0; + loop { + if !complicated.complicate() { + break; + } + prev_complicated = complicated.clone(); + num_complications += 1; + + if num_complications > 65_536 { + panic!("complicate() returned true over 65536 times in a \ + row; aborting due to possible infinite loop. \ + If this is not an infinite loop, it may be \ + necessary to reconsider how shrinking is \ + implemented or use a simpler test strategy. \ + Internal state:\n{:#?}", state); + } + } + + assert_same!(before_simplified.current(), complicated.current(), + "Calling simplify(), then complicate() until it \ + returned false, did not return to the value before \ + simplify. Expected:\n\ + {:#?}\n\ + Actual:\n\ + {:#?}\n\ + Internal state after {} calls to simplify():\n\ + {:#?}\n\ + Internal state after another call to simplify():\n\ + {:#?}\n\ + Internal state after {} subsequent calls to \ + complicate():\n\ + {:#?}", + before_simplified.current(), complicated.current(), + num_simplifies, before_simplified, before_complicated, + num_complications + 1, complicated); + + for iter in 1..16 { + assert_same!(prev_complicated.current(), complicated.current(), + "complicate() returned false but changed the output \ + value anyway.\n\ + Old value:\n\ + {:#?}\n\ + New value:\n\ + {:#?}\n\ + Old internal state:\n\ + {:#?}\n\ + New internal state after {} calls to complicate()\ + including the :\n\ + {:#?}", + prev_complicated.current(), + complicated.current(), + prev_complicated, iter, complicated); + + assert!(!complicated.complicate(), + "complicate() returned true after having returned \ + false;\n\ + Internal state before:\n{:#?}\n\ + Internal state after calling complicate() {} times:\n\ + {:#?}", prev_complicated, iter + 1, complicated); + } + + num_simplifies += 1; + if num_simplifies > 65_536 { + panic!("simplify() returned true over 65536 times in a row, \ + aborting due to possible infinite loop. If this is not \ + an infinite loop, it may be necessary to reconsider \ + how shrinking is implemented or use a simpler test \ + strategy. Internal state:\n{:#?}", state); + } + } + + for iter in 0..16 { + assert_same!(before_simplified.current(), state.current(), + "simplify() returned false but changed the output \ + value anyway.\n\ + Old value:\n\ + {:#?}\n\ + New value:\n\ + {:#?}\n\ + Previous internal state:\n\ + {:#?}\n\ + New internal state after calling simplify() {} times:\n\ + {:#?}", + before_simplified.current(), + state.current(), + before_simplified, iter, state); + + if state.simplify() { + panic!("simplify() returned true after having returned false. \ + Previous internal state:\n\ + {:#?}\n\ + New internal state after calling simplify() {} times:\n\ + {:#?}", before_simplified, iter + 1, state); + } + } + } +} diff --git a/proptest/src/strategy/unions.rs b/proptest/src/strategy/unions.rs new file mode 100644 index 000000000..40aa26617 --- /dev/null +++ b/proptest/src/strategy/unions.rs @@ -0,0 +1,511 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::cmp::{max, min}; +use core::u32; +use std_facade::Vec; + +#[cfg(not(feature="std"))] +use num_traits::float::FloatCore; + +use num::sample_uniform; +use strategy::traits::*; +use test_runner::*; + +/// A **relative** `weight` of a particular `Strategy` corresponding to `T` +/// coupled with `T` itself. The weight is currently given in `u32`. +pub type W<T> = (u32, T); + +/// A `Strategy` which picks from one of several delegate `Stragegy`s. +/// +/// See `Strategy::prop_union()`. +#[derive(Clone, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct Union<T : Strategy> { + options: Vec<W<T>>, +} + +impl<T : Strategy> Union<T> { + /// Create a strategy which selects uniformly from the given delegate + /// strategies. + /// + /// When shrinking, after maximal simplification of the chosen element, the + /// strategy will move to earlier options and continue simplification with + /// those. + /// + /// ## Panics + /// + /// Panics if `options` is empty. + pub fn new(options: impl IntoIterator<Item = T>) -> Self { + let options: Vec<W<T>> = options.into_iter() + .map(|v| (1, v)).collect(); + assert!(!options.is_empty()); + Self { options } + } + + pub(crate) fn try_new<E>(it: impl Iterator<Item = Result<T, E>>) + -> Result<Self, E> { + let options: Vec<W<T>> = it.map(|r| r.map(|v| (1, v))) + .collect::<Result<_, _>>()?; + + assert!(!options.is_empty()); + Ok(Self { options }) + } + + /// Create a strategy which selects from the given delegate strategies. + /// + /// Each strategy is assigned a non-zero weight which determines how + /// frequently that strategy is chosen. For example, a strategy with a + /// weight of 2 will be chosen twice as frequently as one with a weight of + /// 1\. + /// + /// ## Panics + /// + /// Panics if `options` is empty or any element has a weight of 0. + /// + /// Panics if the sum of the weights overflows a `u32`. + pub fn new_weighted(options: Vec<W<T>>) -> Self { + assert!(!options.is_empty()); + assert!(!options.iter().any(|&(w, _)| 0 == w), + "Union option has a weight of 0"); + assert!(options.iter().map(|&(w, _)| u64::from(w)).sum::<u64>() <= + u64::from(u32::MAX), "Union weights overflow u32"); + Self { options } + } + + /// Add `other` as an additional alternate strategy with weight 1. + pub fn or(mut self, other: T) -> Self { + self.options.push((1, other)); + self + } +} + +fn pick_weighted<I : Iterator<Item = u32>>(runner: &mut TestRunner, + weights1: I, weights2: I) -> usize { + let sum = weights1.map(u64::from).sum(); + let weighted_pick = sample_uniform(runner, 0..sum); + weights2.scan(0u64, |state, w| { + *state += u64::from(w); + Some(*state) + }).filter(|&v| v <= weighted_pick).count() +} + +impl<T : Strategy> Strategy for Union<T> { + type Tree = UnionValueTree<T::Tree>; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + fn extract_weight<V>(&(w, _): &W<V>) -> u32 { w } + + let pick = pick_weighted( + runner, + self.options.iter().map(extract_weight::<T>), + self.options.iter().map(extract_weight::<T>)); + + let mut options = Vec::with_capacity(pick); + for option in &self.options[0..pick+1] { + options.push(option.1.new_tree(runner)?); + } + + Ok(UnionValueTree { options, pick, min_pick: 0, prev_pick: None }) + } +} + +/// `ValueTree` corresponding to `Union`. +#[derive(Clone, Debug)] +pub struct UnionValueTree<T : ValueTree> { + options: Vec<T>, + pick: usize, + min_pick: usize, + prev_pick: Option<usize>, +} + +macro_rules! access_vec { + ([$($muta:tt)*] $dst:ident = $this:expr, $ix:expr, $body:block) => {{ + let $dst = &$($muta)* $this.options[$ix]; + $body + }} +} + +macro_rules! union_value_tree_body { + ($typ:ty, $access:ident) => { + type Value = $typ; + + fn current(&self) -> Self::Value { + $access!([] opt = self, self.pick, { + opt.current() + }) + } + + fn simplify(&mut self) -> bool { + if $access!([mut] opt = self, self.pick, { opt.simplify() }) { + self.prev_pick = None; + true + } else if self.pick > self.min_pick { + self.prev_pick = Some(self.pick); + self.pick -= 1; + true + } else { + false + } + } + + fn complicate(&mut self) -> bool { + if let Some(pick) = self.prev_pick { + self.pick = pick; + self.min_pick = pick; + self.prev_pick = None; + true + } else { + $access!([mut] opt = self, self.pick, { opt.complicate() }) + } + } + } +} + +impl<T : ValueTree> ValueTree for UnionValueTree<T> { + union_value_tree_body!(T::Value, access_vec); +} + +macro_rules! def_access_tuple { + ($b:tt $name:ident, $($n:tt)*) => { + macro_rules! $name { + ([$b($b muta:tt)*] $b dst:ident = $b this:expr, + $b ix:expr, $b body:block) => { + match $b ix { + 0 => { + let $b dst = &$b($b muta)* $b this.options.0; + $b body + }, + $( + $n => { + if let Some(ref $b($b muta)* $b dst) = + $b this.options.$n + { + $b body + } else { + panic!("TupleUnion tried to access \ + uninitialised slot {}", $n) + } + }, + )* + _ => panic!("TupleUnion tried to access out-of-range \ + slot {}", $b ix), + } + } + } + } +} + +def_access_tuple!($ access_tuple2, 1); +def_access_tuple!($ access_tuple3, 1 2); +def_access_tuple!($ access_tuple4, 1 2 3); +def_access_tuple!($ access_tuple5, 1 2 3 4); +def_access_tuple!($ access_tuple6, 1 2 3 4 5); +def_access_tuple!($ access_tuple7, 1 2 3 4 5 6); +def_access_tuple!($ access_tuple8, 1 2 3 4 5 6 7); +def_access_tuple!($ access_tuple9, 1 2 3 4 5 6 7 8); +def_access_tuple!($ access_tupleA, 1 2 3 4 5 6 7 8 9); + +/// Similar to `Union`, but internally uses a tuple to hold the strategies. +/// +/// This allows better performance than vanilla `Union` since one does not need +/// to resort to boxing and dynamic dispatch to handle heterogeneous +/// strategies. +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Copy, Debug)] +pub struct TupleUnion<T>(T); + +impl<T> TupleUnion<T> { + /// Wrap `tuple` in a `TupleUnion`. + /// + /// The struct definition allows any `T` for `tuple`, but to be useful, it + /// must be a 2- to 10-tuple of `(u32, impl Strategy)` pairs where all + /// strategies ultimately produce the same value. Each `u32` indicates the + /// relative weight of its corresponding strategy. + /// You may use `W<S>` as an alias for `(u32, S)`. + /// + /// Using this constructor directly is discouraged; prefer to use + /// `prop_oneof!` since it is generally clearer. + pub fn new(tuple: T) -> Self { + TupleUnion(tuple) + } +} + +macro_rules! tuple_union { + ($($gen:ident $ix:tt)*) => { + impl<A : Strategy, $($gen: Strategy<Value = A::Value>),*> + Strategy for TupleUnion<(W<A>, $(W<$gen>),*)> { + type Tree = TupleUnionValueTree< + (A::Tree, $(Option<$gen::Tree>),*)>; + type Value = A::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let weights = [((self.0).0).0, $(((self.0).$ix).0),*]; + let pick = pick_weighted(runner, weights.iter().cloned(), + weights.iter().cloned()); + + Ok(TupleUnionValueTree { + options: ( + ((self.0).0).1.new_tree(runner)?, + $(if $ix <= pick { + Some(((self.0).$ix).1.new_tree(runner)?) + } else { + None + }),*), + pick: pick, + min_pick: 0, + prev_pick: None, + }) + } + } + } +} + +tuple_union!(B 1); +tuple_union!(B 1 C 2); +tuple_union!(B 1 C 2 D 3); +tuple_union!(B 1 C 2 D 3 E 4); +tuple_union!(B 1 C 2 D 3 E 4 F 5); +tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6); +tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7); +tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7 I 8); +tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7 I 8 J 9); + +/// `ValueTree` type produced by `TupleUnion`. +#[derive(Clone, Copy, Debug)] +pub struct TupleUnionValueTree<T> { + options: T, + pick: usize, + min_pick: usize, + prev_pick: Option<usize>, +} + +macro_rules! value_tree_tuple { + ($access:ident, $($gen:ident)*) => { + impl<A : ValueTree, $($gen: ValueTree<Value = A::Value>),*> ValueTree + for TupleUnionValueTree<(A, $(Option<$gen>),*)> { + union_value_tree_body!(A::Value, $access); + } + } +} + +value_tree_tuple!(access_tuple2, B); +value_tree_tuple!(access_tuple3, B C); +value_tree_tuple!(access_tuple4, B C D); +value_tree_tuple!(access_tuple5, B C D E); +value_tree_tuple!(access_tuple6, B C D E F); +value_tree_tuple!(access_tuple7, B C D E F G); +value_tree_tuple!(access_tuple8, B C D E F G H); +value_tree_tuple!(access_tuple9, B C D E F G H I); +value_tree_tuple!(access_tupleA, B C D E F G H I J); + +const WEIGHT_BASE: u32 = 0x8000_0000; + +/// Convert a floating-point weight in the range (0.0,1.0) to a pair of weights +/// that can be used with `Union` and similar. +/// +/// The first return value is the weight corresponding to `f`; the second +/// return value is the weight corresponding to `1.0 - f`. +/// +/// This call does not make any guarantees as to what range of weights it may +/// produce, except that adding the two return values will never overflow a +/// `u32`. As such, it is generally not meaningful to combine any other weights +/// with the two returned. +/// +/// ## Panics +/// +/// Panics if `f` is not a real number between 0.0 and 1.0, both exclusive. +pub fn float_to_weight(f: f64) -> (u32, u32) { + assert!(f > 0.0 && f < 1.0, "Invalid probability: {}", f); + + // Clamp to 1..WEIGHT_BASE-1 so that we never produce a weight of 0. + let pos = max(1, min(WEIGHT_BASE - 1, + (f * f64::from(WEIGHT_BASE)).round() as u32)); + let neg = WEIGHT_BASE - pos; + + (pos, neg) +} + +#[cfg(test)] +mod test { + use strategy::just::Just; + use super::*; + + // FIXME(2018-06-01): figure out a way to run this test on no_std. + // The problem is that the default seed is fixed and does not produce + // enough passed tests. We need some universal source of non-determinism + // for the seed, which is unlikely. + #[cfg(feature = "std")] + #[test] + fn test_union() { + let input = (10u32..20u32).prop_union(30u32..40u32); + // Expect that 25% of cases pass (left input happens to be < 15, and + // left is chosen as initial value). Of the 75% that fail, 50% should + // converge to 15 and 50% to 30 (the latter because the left is beneath + // the passing threshold). + let mut passed = 0; + let mut converged_low = 0; + let mut converged_high = 0; + for _ in 0..256 { + let mut runner = TestRunner::default(); + let case = input.new_tree(&mut runner).unwrap(); + let result = runner.run_one(case, |v| { + prop_assert!(v < 15); + Ok(()) + }); + + match result { + Ok(true) => passed += 1, + Err(TestError::Fail(_, 15)) => converged_low += 1, + Err(TestError::Fail(_, 30)) => converged_high += 1, + e => panic!("Unexpected result: {:?}", e), + } + } + + assert!(passed >= 32 && passed <= 96, + "Bad passed count: {}", passed); + assert!(converged_low >= 32 && converged_low <= 160, + "Bad converged_low count: {}", converged_low); + assert!(converged_high >= 32 && converged_high <= 160, + "Bad converged_high count: {}", converged_high); + } + + #[test] + fn test_union_weighted() { + let input = Union::new_weighted(vec![ + (1, Just(0usize)), + (2, Just(1usize)), + (1, Just(2usize)), + ]); + + let mut counts = [0, 0, 0]; + let mut runner = TestRunner::default(); + for _ in 0..65536 { + counts[input.new_tree(&mut runner).unwrap().current()] += 1; + } + + println!("{:?}", counts); + assert!(counts[0] > 0); + assert!(counts[2] > 0); + assert!(counts[1] > counts[0] * 3/2); + assert!(counts[1] > counts[2] * 3/2); + } + + #[test] + fn test_union_sanity() { + check_strategy_sanity(Union::new_weighted(vec![ + (1, 0i32..100), + (2, 200i32..300), + (1, 400i32..500), + ]), None); + } + + // FIXME(2018-06-01): See note on `test_union`. + #[cfg(feature = "std")] + #[test] + fn test_tuple_union() { + let input = TupleUnion::new( + ((1, 10u32..20u32), + (1, 30u32..40u32))); + // Expect that 25% of cases pass (left input happens to be < 15, and + // left is chosen as initial value). Of the 75% that fail, 50% should + // converge to 15 and 50% to 30 (the latter because the left is beneath + // the passing threshold). + let mut passed = 0; + let mut converged_low = 0; + let mut converged_high = 0; + for _ in 0..256 { + let mut runner = TestRunner::default(); + let case = input.new_tree(&mut runner).unwrap(); + let result = runner.run_one(case, |v| { + prop_assert!(v < 15); + Ok(()) + }); + + match result { + Ok(true) => passed += 1, + Err(TestError::Fail(_, 15)) => converged_low += 1, + Err(TestError::Fail(_, 30)) => converged_high += 1, + e => panic!("Unexpected result: {:?}", e), + } + } + + assert!(passed >= 32 && passed <= 96, + "Bad passed count: {}", passed); + assert!(converged_low >= 32 && converged_low <= 160, + "Bad converged_low count: {}", converged_low); + assert!(converged_high >= 32 && converged_high <= 160, + "Bad converged_high count: {}", converged_high); + } + + #[test] + fn test_tuple_union_weighting() { + let input = TupleUnion::new(( + (1, Just(0usize)), + (2, Just(1usize)), + (1, Just(2usize)), + )); + + let mut counts = [0, 0, 0]; + let mut runner = TestRunner::default(); + for _ in 0..65536 { + counts[input.new_tree(&mut runner).unwrap().current()] += 1; + } + + println!("{:?}", counts); + assert!(counts[0] > 0); + assert!(counts[2] > 0); + assert!(counts[1] > counts[0] * 3/2); + assert!(counts[1] > counts[2] * 3/2); + } + + #[test] + fn test_tuple_union_all_sizes() { + let mut runner = TestRunner::default(); + let r = 1i32..10; + + macro_rules! test { + ($($part:expr),*) => {{ + let input = TupleUnion::new(( + $((1, $part.clone())),*, + (1, Just(0i32)) + )); + + let mut pass = false; + for _ in 0..1024 { + if 0 == input.new_tree(&mut runner).unwrap().current() { + pass = true; + break; + } + } + + assert!(pass); + }} + } + + test!(r); // 2 + test!(r, r); // 3 + test!(r, r, r); // 4 + test!(r, r, r, r); // 5 + test!(r, r, r, r, r); // 6 + test!(r, r, r, r, r, r); // 7 + test!(r, r, r, r, r, r, r); // 8 + test!(r, r, r, r, r, r, r, r); // 9 + test!(r, r, r, r, r, r, r, r, r); // 10 + } + + #[test] + fn test_tuple_union_sanity() { + check_strategy_sanity( + TupleUnion::new(((1, 0i32..100i32), (1, 200i32..1000i32), + (1, 2000i32..3000i32))), + None); + } +} diff --git a/proptest/src/string.rs b/proptest/src/string.rs new file mode 100644 index 000000000..4fa75d8c2 --- /dev/null +++ b/proptest/src/string.rs @@ -0,0 +1,459 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating strings and byte strings from regular +//! expressions. + +use core::mem; +use core::fmt; +use core::ops::RangeInclusive; +use core::u32; +use std_facade::{Cow, Box, String, Vec, ToOwned}; + +use regex_syntax::{Parser, Error as ParseError}; +use regex_syntax::hir::{ + self, Hir, HirKind::*, Literal::*, + RepetitionKind::{self, *}, RepetitionRange::* +}; + +use bool; +use char; +use collection::{vec, size_range, SizeRange}; +use strategy::*; +use test_runner::*; + +/// Wraps the regex that forms the `Strategy` for `String` so that a sensible +/// `Default` can be given. The default is a string of non-control characters. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct StringParam(&'static str); + +impl From<StringParam> for &'static str { + fn from(x: StringParam) -> Self { x.0 } +} + +impl From<&'static str> for StringParam { + fn from(x: &'static str) -> Self { StringParam(x) } +} + +impl Default for StringParam { + fn default() -> Self { + StringParam("\\PC*") + } +} + +// quick_error! uses bare trait objects, so we enclose its invocation here in a +// module so the lint can be disabled just for it. +#[allow(bare_trait_objects)] +mod error_container { + use super::*; + + quick_error! { + /// Errors which may occur when preparing a regular expression for use with + /// string generation. + #[derive(Debug)] + pub enum Error { + /// The string passed as the regex was not syntactically valid. + RegexSyntax(err: ParseError) { + from() + cause(err) + description(err.description()) + display("{}", err) + } + /// The regex was syntactically valid, but contains elements not + /// supported by proptest. + UnsupportedRegex(message: &'static str) { + description(message) + } + } + } +} + +pub use self::error_container::Error; + +opaque_strategy_wrapper! { + /// Strategy which generates values (i.e., `String` or `Vec<u8>`) matching + /// a regular expression. + /// + /// Created by various functions in this module. + #[derive(Debug)] + pub struct RegexGeneratorStrategy[<T>][where T : fmt::Debug] + (SBoxedStrategy<T>) -> RegexGeneratorValueTree<T>; + /// `ValueTree` corresponding to `RegexGeneratorStrategy`. + pub struct RegexGeneratorValueTree[<T>][where T : fmt::Debug] + (Box<dyn ValueTree<Value = T>>) -> T; +} + +impl Strategy for str { + type Tree = RegexGeneratorValueTree<String>; + type Value = String; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + string_regex(self).unwrap().new_tree(runner) + } +} + +type ParseResult<T> = Result<RegexGeneratorStrategy<T>, Error>; + +/// Creates a strategy which generates strings matching the given regular +/// expression. +/// +/// If you don't need error handling and aren't limited by setup time, it is +/// also possible to directly use a `&str` as a strategy with the same effect. +pub fn string_regex(regex: &str) -> ParseResult<String> { + string_regex_parsed(®ex_to_hir(regex)?) +} + +/// Like `string_regex()`, but allows providing a pre-parsed expression. +pub fn string_regex_parsed(expr: &Hir) -> ParseResult<String> { + bytes_regex_parsed(expr).map( + |v| v.prop_map(|bytes| String::from_utf8(bytes).expect( + "non-utf8 string")).sboxed()).map(RegexGeneratorStrategy) +} + +/// Creates a strategy which generates byte strings matching the given regular +/// expression. +pub fn bytes_regex(regex: &str) -> ParseResult<Vec<u8>> { + bytes_regex_parsed(®ex_to_hir(regex)?) +} + +/// Like `bytes_regex()`, but allows providing a pre-parsed expression. +pub fn bytes_regex_parsed(expr: &Hir) -> ParseResult<Vec<u8>> { + match expr.kind() { + Empty => Ok(Just(vec![]).sboxed()), + + Literal(lit) => Ok(Just(match lit { + Unicode(scalar) => to_bytes(*scalar), + Byte(byte) => vec![*byte], + }).sboxed()), + + Class(class) => Ok(match class { + hir::Class::Unicode(class) => + unicode_class_strategy(class).prop_map(to_bytes).sboxed(), + hir::Class::Bytes(class) => { + let subs = class.iter().map(|r| r.start() ..= r.end()); + Union::new(subs).prop_map(|b| vec![b]).sboxed() + } + }), + + Repetition(rep) => Ok( + vec(bytes_regex_parsed(&rep.hir)?, to_range(rep.kind.clone())?) + .prop_map(|parts| parts.into_iter().fold( + vec![], |mut acc, child| { acc.extend(child); acc })) + .sboxed() + ), + + Group(group) => bytes_regex_parsed(&group.hir).map(|v| v.0), + + Concat(subs) => { + let subs = ConcatIter { iter: subs.iter(), buf: vec![], next: None }; + let ext = |(mut lhs, rhs): (Vec<_>, _)| { + lhs.extend(rhs); + lhs + }; + Ok(subs.fold(Ok(None), |accum: Result<_, Error>, rhs| Ok(match accum? { + None => Some(rhs?.sboxed()), + Some(accum) => Some((accum, rhs?).prop_map(ext).sboxed()), + }))?.unwrap_or_else(|| Just(vec![]).sboxed())) + }, + + Alternation(subs) => + Ok(Union::try_new(subs.iter().map(bytes_regex_parsed))?.sboxed()), + + Anchor(_) => + unsupported("line/text anchors not supported for string generation"), + + WordBoundary(_) => + unsupported("word boundary tests not supported for string generation"), + }.map(RegexGeneratorStrategy) +} + +fn unicode_class_strategy(class: &hir::ClassUnicode) -> char::CharStrategy<'static> { + static NONL_RANGES: &[RangeInclusive<char>] = &[ + '\x00'..='\x09', + // Multiple instances of the latter range to partially make up + // for the bias of having such a tiny range in the control + // characters. + '\x0B'..=::core::char::MAX, + '\x0B'..=::core::char::MAX, + '\x0B'..=::core::char::MAX, + '\x0B'..=::core::char::MAX, + '\x0B'..=::core::char::MAX, + ]; + + let dotnnl = |x: &hir::ClassUnicodeRange, y: &hir::ClassUnicodeRange| + x.start() == '\0' && x.end() == '\x09' && + y.start() == '\x0B' && y.end() == '\u{10FFFF}'; + + char::ranges(match class.ranges() { + [x, y] if dotnnl(x, y) || dotnnl(y, x) => Cow::Borrowed(NONL_RANGES), + _ => Cow::Owned(class.iter().map(|r| r.start() ..= r.end()).collect()), + }) +} + +struct ConcatIter<'a, I> { + buf: Vec<u8>, + iter: I, + next: Option<&'a Hir>, +} + +fn flush_lit_buf<I>(it: &mut ConcatIter<'_, I>) -> Option<ParseResult<Vec<u8>>> { + Some(Ok(RegexGeneratorStrategy( + Just(mem::replace(&mut it.buf, vec![])).sboxed() + ))) +} + +impl<'a, I: Iterator<Item = &'a Hir>> Iterator for ConcatIter<'a, I> { + type Item = ParseResult<Vec<u8>>; + + fn next(&mut self) -> Option<Self::Item> { + // A left-over node, process it first: + if let Some(next) = self.next.take() { + return Some(bytes_regex_parsed(next)); + } + + // Accumulate a literal sequence as long as we can: + while let Some(next) = self.iter.next() { + match next.kind() { + // A literal. Accumulate: + Literal(Unicode(scalar)) => self.buf.extend(to_bytes(*scalar)), + Literal(Byte(byte)) => self.buf.push(*byte), + // Ecountered a non-literal. + _ => return if !self.buf.is_empty() { + // We've accumulated a literal from before, flush it out. + // Store this node so we deal with it the next call. + self.next = Some(next); + flush_lit_buf(self) + } else { + // We didn't; just yield this node. + Some(bytes_regex_parsed(next)) + }, + } + } + + // Flush out any accumulated literal from before. + if !self.buf.is_empty() { + flush_lit_buf(self) + } else { + self.next.take().map(bytes_regex_parsed) + } + } +} + +fn to_range(kind: RepetitionKind) -> Result<SizeRange, Error> { + Ok(match kind { + ZeroOrOne => size_range(0..=1), + ZeroOrMore => size_range(0..=32), + OneOrMore => size_range(1..=32), + Range(range) => match range { + Exactly(count) if u32::MAX == count => + return unsupported("Cannot have repetition of exactly u32::MAX"), + Exactly(count) => size_range(count as usize), + AtLeast(min) => { + let max = if min < u32::MAX as u32 / 2 { + min as usize * 2 + } else { + u32::MAX as usize + }; + size_range((min as usize)..max) + }, + Bounded(_, max) if u32::MAX == max => + return unsupported("Cannot have repetition max of u32::MAX"), + Bounded(min, max) => + size_range((min as usize)..(max as usize + 1)) + } + }) +} + +fn to_bytes(khar: char) -> Vec<u8> { + let mut buf = [0u8; 4]; + khar.encode_utf8(&mut buf).as_bytes().to_owned() +} + +fn regex_to_hir(pattern: &str) -> Result<Hir, Error> { + Ok(Parser::new().parse(pattern)?) +} + +fn unsupported<T>(error: &'static str) -> Result<T, Error> { + Err(Error::UnsupportedRegex(error)) +} + +#[cfg(test)] +mod test { + use std::collections::HashSet; + + use regex::Regex; + + use super::*; + + fn do_test(pattern: &str, min_distinct: usize, max_distinct: usize, + iterations: usize) { + let generated = generate_values_matching_regex(pattern, iterations); + assert!(generated.len() >= min_distinct, + "Expected to generate at least {} strings, but only \ + generated {}", min_distinct, generated.len()); + assert!(generated.len() <= max_distinct, + "Expected to generate at most {} strings, but \ + generated {}", max_distinct, generated.len()); + } + + fn generate_values_matching_regex(pattern: &str, iterations: usize) -> HashSet<String> { + let rx = Regex::new(pattern).unwrap(); + let mut generated = HashSet::new(); + + let strategy = string_regex(pattern).unwrap(); + let mut runner = TestRunner::default(); + for _ in 0..iterations { + let mut value = strategy.new_tree(&mut runner).unwrap(); + + loop { + let s = value.current(); + let ok = if let Some(matsch) = rx.find(&s) { + 0 == matsch.start() && s.len() == matsch.end() + } else { + false + }; + if !ok { + panic!("Generated string {:?} which does not match {:?}", + s, pattern); + } + + generated.insert(s); + + if !value.simplify() { break; } + } + } + generated + } + + #[test] + fn test_case_insensitive_produces_all_available_values() { + let mut expected: HashSet<String> = HashSet::new(); + expected.insert("a".into()); + expected.insert("b".into()); + expected.insert("A".into()); + expected.insert("B".into()); + assert_eq!(generate_values_matching_regex("(?i:a|B)", 64), expected); + } + + #[test] + fn test_literal() { + do_test("foo", 1, 1, 8); + } + + #[test] + fn test_casei_literal() { + do_test("(?i:fOo)", 8, 8, 64); + } + + #[test] + fn test_alternation() { + do_test("foo|bar|baz", 3, 3, 16); + } + + #[test] + fn test_repitition() { + do_test("a{0,8}", 9, 9, 64); + } + + #[test] + fn test_question() { + do_test("a?", 2, 2, 16); + } + + #[test] + fn test_star() { + do_test("a*", 33, 33, 256); + } + + #[test] + fn test_plus() { + do_test("a+", 32, 32, 256); + } + + #[test] + fn test_n_to_range() { + do_test("a{4,}", 4, 4, 64); + } + + #[test] + fn test_concatenation() { + do_test("(foo|bar)(xyzzy|plugh)", 4, 4, 32); + } + + #[test] + fn test_ascii_class() { + do_test("[[:digit:]]", 10, 10, 256); + } + + #[test] + fn test_unicode_class() { + do_test("\\p{Greek}", 24, 512, 256); + } + + #[test] + fn test_dot() { + do_test(".", 200, 65536, 256); + } + + #[test] + fn test_dot_s() { + do_test("(?s).", 200, 65536, 256); + } + + #[test] + fn test_backslash_d_plus() { + do_test("\\d+", 1, 65536, 256); + } + + fn assert_send_and_sync<T : Send + Sync>(_: T) { } + + #[test] + fn regex_strategy_is_send_and_sync() { + assert_send_and_sync(string_regex(".").unwrap()); + } + + macro_rules! consistent { + ($name:ident, $value:expr) => { + #[test] + fn $name() { + test_generates_matching_strings($value); + } + } + } + + fn test_generates_matching_strings(pattern: &str) { + use std::time; + + let mut runner = TestRunner::default(); + let start = time::Instant::now(); + + // If we don't support this regex, just move on quietly + if let Ok(strategy) = string_regex(pattern) { + let rx = Regex::new(pattern).unwrap(); + + for _ in 0..1000 { + let mut val = strategy.new_tree(&mut runner).unwrap(); + // No more than 1000 simplify steps to keep test time down + for _ in 0..1000 { + let s = val.current(); + assert!(rx.is_match(&s), + "Produced string {:?}, which does not match {:?}", + s, pattern); + + if !val.simplify() { break; } + } + + // Quietly stop testing if we've run for >10 s + if start.elapsed().as_secs() > 10 { break; } + } + } + } + + include!("regex-contrib/crates_regex.rs"); +} diff --git a/proptest/src/sugar.rs b/proptest/src/sugar.rs new file mode 100644 index 000000000..3ddb06a34 --- /dev/null +++ b/proptest/src/sugar.rs @@ -0,0 +1,1498 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::fmt; + +/// Easily define `proptest` tests. +/// +/// Within `proptest!`, define one or more functions without return type +/// normally, except instead of putting `: type` after each parameter, write +/// `in strategy`, where `strategy` is an expression evaluating to some +/// `Strategy`. +/// +/// Each function will be wrapped in a function which sets up a `TestRunner`, +/// and then invokes the function body with inputs generated according to the +/// strategies. +/// +/// ### Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b in ".*") { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { test_addition(); test_string_concat(); } +/// ``` +/// +/// You can also use the normal argument syntax `pattern: type` as in: +/// +/// ```rust +/// #[macro_use] extern crate proptest; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn addition_is_commutative(a: u8, b: u8) { +/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b: String) { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { addition_is_commutative(); test_string_concat(); } +/// ``` +/// +/// As you can see, you can mix `pattern: type` and `pattern in expr`. +/// Due to limitations in `macro_rules!`, `pattern: type` does not work in +/// all circumstances. In such a case, use `(pattern): type` instead. +/// +/// To override the default configuration, you can start the `proptest!` block +/// with `#![proptest_config(expr)]`, where `expr` is an expression that +/// evaluates to a `proptest::test_runner::Config` (or a reference to one). +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// proptest! { +/// #![proptest_config(ProptestConfig { +/// cases: 99, .. ProptestConfig::default() +/// })] +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +/// +/// ## Closure-Style Invocation +/// +/// As of proptest 0.8.1, an alternative, "closure-style" invocation is +/// supported. In this form, `proptest!` is a function-like macro taking a +/// closure-esque argument. This makes it possible to run multiple tests that +/// require some expensive setup process. Note that the "fork" and "timeout" +/// features are _not_ supported in closure style. +/// +/// To use a custom configuration, pass the `Config` object as a first +/// argument. +/// +/// ### Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// #[derive(Debug)] +/// struct BigStruct { /* Lots of fields ... */ } +/// +/// fn very_expensive_function() -> BigStruct { +/// // Lots of code... +/// BigStruct { /* fields */ } +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// // We create just one `BigStruct` +/// let big_struct = very_expensive_function(); +/// +/// // But now can run multiple tests without needing to build it every time. +/// // Note the extra parentheses around the arguments are currently +/// // required. +/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { +/// // Test stuff +/// }); +/// +/// // `move` closures are also supported +/// proptest!(move |(x in 0u32..42u32)| { +/// // Test other stuff +/// }); +/// +/// // You can pass a custom configuration as the first argument +/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { +/// // Test more stuff +/// }); +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[macro_export] +macro_rules! proptest { + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+) $body:block + )*) => { + $( + $(#[$meta])* + fn $test_name() { + let mut config = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); + } + )* + }; + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { + $( + $(#[$meta])* + fn $test_name() { + let mut config = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } + )* + }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+) $body:block + )*) => { proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($parm in $strategy),+) $body)* + } }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($arg)+) $body)* + } }; + + (|($($parm:pat in $strategy:expr),+)| $body:expr) => { + proptest!( + $crate::test_runner::Config::default(), + |($($parm in $strategy),+)| $body) + }; + + (move |($($parm:pat in $strategy:expr),+)| $body:expr) => { + proptest!( + $crate::test_runner::Config::default(), + move |($($parm in $strategy),+)| $body) + }; + + (|($($arg:tt)+)| $body:expr) => { + proptest!( + $crate::test_runner::Config::default(), + |($($arg)+)| $body) + }; + + (move |($($arg:tt)+)| $body:expr) => { + proptest!( + $crate::test_runner::Config::default(), + move |($($arg)+)| $body) + }; + + ($config:expr, |($($parm:pat in $strategy:expr),+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) + } }; + + ($config:expr, move |($($parm:pat in $strategy:expr),+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) + } }; + + ($config:expr, |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } }; + + ($config:expr, move |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); + } }; +} + +/// Rejects the test input if assumptions are not met. +/// +/// Used directly within a function defined with `proptest!` or in any function +/// returning `Result<_, TestCaseError>`. +/// +/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` +/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The +/// message includes the point of invocation and the format message. `format` +/// and `args` may be omitted to simply use the condition itself as the +/// message. +#[macro_export] +macro_rules! prop_assume { + ($expr:expr) => { + prop_assume!($expr, "{}", stringify!($expr)) + }; + + ($expr:expr, $fmt:tt $(, $fmt_arg:expr),*) => { + if !$expr { + return ::std::result::Result::Err( + $crate::test_runner::TestCaseError::reject( + format!(concat!("{}:{}:{}: ", $fmt), + file!(), line!(), column!() + $(, $fmt_arg)*))); + } + }; +} + +/// Produce a strategy which picks one of the listed choices. +/// +/// This is conceptually equivalent to calling `prop_union` on the first two +/// elements and then chaining `.or()` onto the rest after implicitly boxing +/// all of them. As with `Union`, values shrink across elements on the +/// assumption that earlier ones are "simpler", so they should be listed in +/// order of ascending complexity when possible. +/// +/// The macro invocation has two forms. The first is to simply list the +/// strategies separated by commas; this will cause value generation to pick +/// from the strategies uniformly. The other form is to provide a weight in the +/// form of a `u32` before each strategy, separated from the strategy with +/// `=>`. +/// +/// Note that the exact type returned by the macro varies depending on how many +/// inputs there are. In particular, if given exactly one option, it will +/// return it unmodified. It is not recommended to depend on the particular +/// type produced by this macro. +/// +/// ## Example +/// +/// ```rust,no_run +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Copy, Debug)] +/// enum MyEnum { +/// Big(u64), +/// Medium(u32), +/// Little(i16), +/// } +/// +/// # #[allow(unused_variables)] +/// # fn main() { +/// let my_enum_strategy = prop_oneof![ +/// prop::num::i16::ANY.prop_map(MyEnum::Little), +/// prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// +/// let my_weighted_strategy = prop_oneof![ +/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), +/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., +/// // around 50% of values will be `Medium`, and 25% for each of `Little` +/// // and `Big`. +/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// # } +/// ``` +#[macro_export] +macro_rules! prop_oneof { + ($($item:expr),+ $(,)*) => { + prop_oneof![ + $(1 => $item),* + ] + }; + + ($_weight0:expr => $item0:expr $(,)*) => { $item0 }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4), ($weight5, $item5))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4), ($weight5, $item5), + ($weight6, $item6))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4), ($weight5, $item5), + ($weight6, $item6), ($weight7, $item7))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4), ($weight5, $item5), + ($weight6, $item6), ($weight7, $item7), + ($weight8, $item8))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr, + $weight9:expr => $item9:expr $(,)*) => { + $crate::strategy::TupleUnion::new( + (($weight0, $item0), ($weight1, $item1), + ($weight2, $item2), ($weight3, $item3), + ($weight4, $item4), ($weight5, $item5), + ($weight6, $item6), ($weight7, $item7), + ($weight8, $item8), ($weight9, $item9))) + }; + + ($($weight:expr => $item:expr),+ $(,)*) => { + $crate::strategy::Union::new_weighted(vec![ + $(($weight, $crate::strategy::Strategy::boxed($item))),* + ]) + }; +} + +/// Convenience to define functions which produce new strategies. +/// +/// The macro has two general forms. In the first, you define a function with +/// two argument lists. The first argument list uses the usual syntax and +/// becomes exactly the argument list of the defined function. The second +/// argument list uses the `in strategy` syntax as with `proptest!`, and is +/// used to generate the other inputs for the function. The second argument +/// list has access to all arguments in the first. The return type indicates +/// the type of value being generated; the final return type of the function is +/// `impl Strategy<Value = $type>`. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// #[macro_use] extern crate proptest; +/// +/// #[derive(Clone, Debug)] +/// struct MyStruct { +/// integer: u32, +/// string: String, +/// } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string in ".*") +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// This form is simply sugar around making a tuple and then calling `prop_map` +/// on it. You can also use `arg: type` as in `proptest! { .. }`: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// # #[macro_use] extern crate proptest; +/// +/// # #[derive(Clone, Debug)] +/// # struct MyStruct { +/// # integer: u32, +/// # string: String, +/// # } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string: String) +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// The second form is mostly the same, except that it takes _three_ argument +/// lists. The third argument list can see all values in both prior, which +/// permits producing strategies based on other strategies. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// #[macro_use] extern crate proptest; +/// +/// prop_compose! { +/// fn nearby_numbers()(centre in -1000..1000) +/// (a in centre-10..centre+10, +/// b in centre-10..centre+10) +/// -> (i32, i32) { +/// (a, b) +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// However, the body of the function does _not_ have access to the second +/// argument list. If the body needs access to those values, they must be +/// passed through explicitly. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn vec_and_index +/// (max_length: usize) +/// (vec in prop::collection::vec(1..10, 1..max_length)) +/// (index in 0..vec.len(), vec in Just(vec)) +/// -> (Vec<i32>, usize) +/// { +/// (vec, index) +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// The second form is sugar around making a strategy tuple, calling +/// `prop_flat_map()`, then `prop_map()`. +/// +/// To give the function a visibility or unsafe modifier, put it in brackets +/// before the `fn` token. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// [pub(crate) unsafe] fn pointer()(v in prop::num::usize::ANY) +/// -> *const () { +/// v as *const () +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// ## Comparison with Hypothesis' `@composite` +/// +/// `prop_compose!` makes it easy to do a lot of things you can do with +/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), +/// but not everything. +/// +/// - You can't filter via this macro. For filtering, you need to make the +/// strategy the "normal" way and use `prop_filter()`. +/// +/// - More than two layers of strategies or arbitrary logic between the two +/// layers. If you need either of these, you can achieve them by calling +/// `prop_flat_map()` by hand. +#[macro_export] +macro_rules! prop_compose { + ($(#[$meta:meta])* + $([$($vis:tt)*])* fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)*) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $($($vis)*)* fn $name $params + -> impl $crate::strategy::Strategy<Value = $return_type> { + let strat = proptest_helper!(@_WRAP ($($strategy)*)); + $crate::strategy::Strategy::prop_map(strat, + |proptest_helper!(@_WRAPPAT ($($var),*))| $body) + } + }; + + ($(#[$meta:meta])* + $([$($vis:tt)*])* fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)*) + ($($var2:pat in $strategy2:expr),+ $(,)*) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $($($vis)*)* fn $name $params + -> impl $crate::strategy::Strategy<Value = $return_type> { + let strat = proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + |proptest_helper!(@_WRAPPAT ($($var),*))| + proptest_helper!(@_WRAP ($($strategy2)*))); + $crate::strategy::Strategy::prop_map(strat, + |proptest_helper!(@_WRAPPAT ($($var2),*))| $body) + } + }; + + ($(#[$meta:meta])* + $([$($vis:tt)*])* fn $name:ident $params:tt + ($($arg:tt)+) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $($($vis)*)* fn $name $params + -> impl $crate::strategy::Strategy<Value = $return_type> { + let strat = proptest_helper!(@_EXT _STRAT ($($arg)+)); + $crate::strategy::Strategy::prop_map(strat, + |proptest_helper!(@_EXT _PAT ($($arg)+))| $body) + } + }; + + ($(#[$meta:meta])* + $([$($vis:tt)*])* fn $name:ident $params:tt + ($($arg:tt)+ $(,)*) + ($($arg2:tt)+ $(,)*) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $($($vis)*)* fn $name $params + -> impl $crate::strategy::Strategy<Value = $return_type> { + let strat = proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + |proptest_helper!(@_EXT _PAT ($($arg)+))| + proptest_helper!(@_EXT _STRAT ($($arg2)*))); + $crate::strategy::Strategy::prop_map(strat, + |proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) + } + }; +} + +/// Similar to `assert!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// This can be used in any function that returns a `Result<_, TestCaseError>`, +/// including the top-level function inside `proptest!`. +/// +/// Both panicking via `assert!` and returning a test case failure have the +/// same effect as far as proptest is concerned; however, the Rust runtime +/// implicitly prints every panic to stderr by default (including a backtrace +/// if enabled), which can make test failures unnecessarily noisy. By using +/// `prop_assert!` instead, the only output on a failing test case is the final +/// panic including the minimal test case. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { +/// // Called with just a condition will print the condition on failure +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// // You can also provide a custom failure message +/// prop_assert!((a*a + b*b).sqrt() <= a + b, +/// "Triangle inequality didn't hold for ({}, {})", a, b); +/// // If calling another function that can return failure, don't forget +/// // the `?` to propagate the failure. +/// assert_from_other_function(a, b)?; +/// } +/// } +/// +/// // The macro can be used from another function provided it has a compatible +/// // return type. +/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// Ok(()) +/// } +/// # +/// # fn main() { triangle_inequality(); } +/// ``` +#[macro_export] +macro_rules! prop_assert { + ($cond:expr) => { + prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) + }; + + ($cond:expr, $($fmt:tt)*) => { + if !$cond { + let message = format!($($fmt)*); + let message = format!("{} at {}:{}", message, file!(), line!()); + return ::std::result::Result::Err( + $crate::test_runner::TestCaseError::fail(message)); + } + }; +} + +/// Similar to `assert_eq!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn concat_string_length(ref a in ".*", ref b in ".*") { +/// let cat = format!("{}{}", a, b); +/// // Use with default message +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// // Can also provide custom message (added after the normal +/// // assertion message) +/// prop_assert_eq!(a.len() + b.len(), cat.len(), +/// "a = {:?}, b = {:?}", a, b); +/// } +/// } +/// # +/// # fn main() { concat_string_length(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_eq { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + prop_assert!(left == right, "assertion failed: `(left == right)` \ + (left: `{:?}`, right: `{:?}`)", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + prop_assert!(left == right, concat!( + "assertion failed: `(left == right)` \ + (left: `{:?}`, right: `{:?}`): ", $fmt), + left, right $($args)*); + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! proptest_helper { + (@_WRAP ($a:tt)) => { $a }; + (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt + $a4:tt $a5:tt $a6:tt $a7:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAP ($a:tt $($rest:tt)*)) => { + ($a, proptest_helper!(@_WRAP ($($rest)*))) + }; + (@_WRAPPAT ($item:pat)) => { $item }; + (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + ($a0, $a1, $a2, $a3) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { + ($a, proptest_helper!(@_WRAPPAT ($($rest),*))) + }; + (@_WRAPSTR ($item:pat)) => { stringify!($item) }; + (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), + stringify!($a3), stringify!($a4)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8), stringify!($a9)) + }; + (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { + (stringify!($a), proptest_helper!(@_WRAPSTR ($($rest),*))) + }; + // build a property testing block that when executed, executes the full property test. + (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ + $config.source_file = Some(file!()); + let mut runner = $crate::test_runner::TestRunner::new($config); + let names = proptest_helper!(@_WRAPSTR ($($parm),*)); + match runner.run( + &$crate::strategy::Strategy::prop_map( + proptest_helper!(@_WRAP ($($strategy)*)), + |values| $crate::sugar::NamedArguments(names, values)), + $($mod)* |$crate::sugar::NamedArguments( + _, proptest_helper!(@_WRAPPAT ($($parm),*)))| + { + $body; + Ok(()) + }) + { + Ok(_) => (), + Err(e) => panic!("{}\n{}", e, runner), + } + }}; + // build a property testing block that when executed, executes the full property test. + (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ + $config.source_file = Some(file!()); + let mut runner = $crate::test_runner::TestRunner::new($config); + let names = proptest_helper!(@_EXT _STR ($($arg)*)); + match runner.run( + &$crate::strategy::Strategy::prop_map( + proptest_helper!(@_EXT _STRAT ($($arg)*)), + |values| $crate::sugar::NamedArguments(names, values)), + $($mod)* |$crate::sugar::NamedArguments( + _, proptest_helper!(@_EXT _PAT ($($arg)*)))| + { + $body; + Ok(()) + }) + { + Ok(_) => (), + Err(e) => panic!("{}\n{}", e, runner), + } + }}; + + // The logic below helps support `pat: type` in the proptest! macro. + + // These matchers define the actual logic: + (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; + (@_PAT [$s:ty] [$p:pat]) => { $p }; + (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; + (@_STRAT in [$s:expr] [$p:pat]) => { $s }; + (@_PAT in [$s:expr] [$p:pat]) => { $p }; + (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; + + // These matchers rewrite into the above extractors. + // We have to do this because `:` can't FOLLOW(pat). + // Note that this is not the full `pat` grammar... + // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. + (@_EXT $cmd:ident ($p:pat in $s:expr $(,)*)) => { + proptest_helper!(@$cmd in [$s] [$p]) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)*)) => { + // Users can wrap in parens as a last resort. + proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident (_ : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [_]) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [ref mut $p]) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [ref $p]) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [mut $p]) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)*)) => { + proptest_helper!(@$cmd [$s] [[$($p)*]]) + }; + + // Rewrite, Inductive case: + (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { + (proptest_helper!(@$cmd in [$s] [$p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [$p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [_]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [ref mut $p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [ref $p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [mut $p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [$p]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { + (proptest_helper!(@$cmd [$s] [[$($p)*]]), proptest_helper!(@_EXT $cmd ($($r)*))) + }; +} + +#[doc(hidden)] +#[derive(Clone, Copy)] +pub struct NamedArguments<N, V>( + #[doc(hidden)] pub N, #[doc(hidden)] pub V); + +impl<V : fmt::Debug> fmt::Debug for NamedArguments<&'static str, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} = ", self.0)?; + self.1.fmt(f) + } +} + +macro_rules! named_arguments_tuple { + ($($ix:tt $argn:ident $argv:ident)*) => { + impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug + for NamedArguments<($($argn,)*),&'a ($($argv,)*)> + where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, + $($argv : 'a),* + { + #[allow(unused_assignments)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut first = true; + $( + if !first { + write!(f, ", ")?; + } + first = false; + fmt::Debug::fmt( + &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; + )* + Ok(()) + } + } + + impl<$($argn : Copy),*, $($argv),*> fmt::Debug + for NamedArguments<($($argn,)*), ($($argv,)*)> + where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* + { + #[allow(unused_assignments)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut first = true; + $( + if !first { + write!(f, ", ")?; + } + first = false; + fmt::Debug::fmt( + &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; + )* + Ok(()) + } + } + } +} + +named_arguments_tuple!(0 AN AV); +named_arguments_tuple!(0 AN AV 1 BN BV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV + 5 FN FV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV + 5 FN FV 6 GN GV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV + 5 FN FV 6 GN GV 7 HN HV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV + 5 FN FV 6 GN GV 7 HN HV 8 IN IV); +named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV + 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); + +/// Similar to `assert_ne!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] extern crate proptest; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { +/// // Use with default message +/// prop_assert_ne!(a, a + b); +/// // Can also provide custom message added after the common message +/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_ne { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + prop_assert!(left != right, "assertion failed: `(left != right)` \ + (left: `{:?}`, right: `{:?}`)", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + prop_assert!(left != right, concat!( + "assertion failed: `(left != right)` \ + (left: `{:?}`, right: `{:?}`): ", $fmt), + left, right $($args)*); + }}; +} + +#[cfg(feature = "std")] +#[doc(hidden)] +pub fn force_no_fork(config: &mut ::test_runner::Config) { + if config.fork() { + eprintln!("proptest: Forking/timeout not supported in closure-style \ + invocations; ignoring"); + + #[cfg(feature = "fork")] { + config.fork = false; + } + #[cfg(feature = "timeout")] { + config.timeout = 0; + } + assert!(!config.fork()); + } +} + +#[cfg(not(feature = "std"))] +pub fn force_no_fork(_: &mut ::test_runner::Config) { } + +#[cfg(test)] +mod test { + use ::strategy::Just; + + prop_compose! { + /// These are docs! + #[allow(dead_code)] + fn two_ints(relative: i32)(a in 0..relative, b in relative..) + -> (i32, i32) { + (a, b) + } + } + + prop_compose! { + /// These are docs! + #[allow(dead_code)] + [pub] fn two_ints_pub(relative: i32)(a in 0..relative, b in relative..) + -> (i32, i32) { + (a, b) + } + } + + prop_compose! { + #[allow(dead_code)] + fn a_less_than_b()(b in 0..1000)(a in 0..b, b in Just(b)) + -> (i32, i32) { + (a, b) + } + } + + proptest! { + #[test] + fn test_something(a in 0u32..42u32, b in 1u32..10u32) { + prop_assume!(a != 41 || b != 9); + assert!(a + b < 50); + } + } + + #[allow(unused_variables)] + mod test_arg_counts { + use strategy::Just; + + proptest! { + #[test] + fn test_1_arg(a in Just(0)) { } + #[test] + fn test_2_arg(a in Just(0), b in Just(0)) { } + #[test] + fn test_3_arg(a in Just(0), b in Just(0), c in Just(0)) { } + #[test] + fn test_4_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0)) { } + #[test] + fn test_5_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0)) { } + #[test] + fn test_6_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0)) { } + #[test] + fn test_7_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0)) { } + #[test] + fn test_8_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0), h in Just(0)) { } + #[test] + fn test_9_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0), h in Just(0), i in Just(0)) { } + #[test] + fn test_a_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0), h in Just(0), i in Just(0), + j in Just(0)) { } + #[test] + fn test_b_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0), h in Just(0), i in Just(0), + j in Just(0), k in Just(0)) { } + #[test] + fn test_c_arg(a in Just(0), b in Just(0), c in Just(0), + d in Just(0), e in Just(0), f in Just(0), + g in Just(0), h in Just(0), i in Just(0), + j in Just(0), k in Just(0), l in Just(0)) { } + } + } + + #[test] + fn named_arguments_is_debug_for_needed_cases() { + use super::NamedArguments; + + println!("{:?}", NamedArguments("foo", &"bar")); + println!("{:?}", NamedArguments(("foo",), &(1,))); + println!("{:?}", NamedArguments(("foo","bar"), &(1,2))); + println!("{:?}", NamedArguments(("a","b","c"), &(1,2,3))); + println!("{:?}", NamedArguments(("a","b","c","d"), &(1,2,3,4))); + println!("{:?}", NamedArguments(("a","b","c","d","e"), + &(1,2,3,4,5))); + println!("{:?}", NamedArguments(("a","b","c","d","e","f"), + &(1,2,3,4,5,6))); + println!("{:?}", NamedArguments(("a","b","c","d","e","f","g"), + &(1,2,3,4,5,6,7))); + println!("{:?}", NamedArguments(("a","b","c","d","e","f","g","h"), + &(1,2,3,4,5,6,7,8))); + println!("{:?}", NamedArguments(("a","b","c","d","e","f","g","h","i"), + &(1,2,3,4,5,6,7,8,9))); + println!("{:?}", NamedArguments(("a","b","c","d","e","f","g","h","i","j"), + &(1,2,3,4,5,6,7,8,9,10))); + println!("{:?}", NamedArguments((("a","b"),"c","d"), &((1,2),3,4))); + } + + #[test] + fn oneof_all_counts() { + use ::strategy::{Strategy, TupleUnion, Union, Just as J}; + + fn expect_count(n: usize, s: impl Strategy<Value = i32>) { + use std::collections::HashSet; + use strategy::*; + use test_runner::*; + + let mut runner = TestRunner::default(); + let mut seen = HashSet::new(); + for _ in 0..1024 { + seen.insert(s.new_tree(&mut runner).unwrap().current()); + } + + assert_eq!(n, seen.len()); + } + + fn assert_static<T>(v: TupleUnion<T>) -> TupleUnion<T> { v } + fn assert_dynamic<T: Strategy>(v: Union<T>) -> Union<T> { v } + + expect_count(1, prop_oneof![J(0i32)]); + expect_count(2, assert_static(prop_oneof![ + J(0i32), + J(1i32), + ])); + expect_count(3, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + ])); + expect_count(4, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + ])); + expect_count(5, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + ])); + expect_count(6, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + ])); + expect_count(7, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + J(6i32), + ])); + expect_count(8, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + J(6i32), + J(7i32), + ])); + expect_count(9, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + J(6i32), + J(7i32), + J(8i32), + ])); + expect_count(10, assert_static(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + J(6i32), + J(7i32), + J(8i32), + J(9i32), + ])); + expect_count(11, assert_dynamic(prop_oneof![ + J(0i32), + J(1i32), + J(2i32), + J(3i32), + J(4i32), + J(5i32), + J(6i32), + J(7i32), + J(8i32), + J(9i32), + J(10i32), + ])); + } +} + +#[cfg(all(test, feature = "timeout"))] +mod test_timeout { + proptest! { + #![proptest_config(::test_runner::Config { + fork: true, + .. ::test_runner::Config::default() + })] + + // Ensure that the macro sets the test name properly. If it doesn't, + // this test will fail to run correctly. + #[test] + fn test_name_set_correctly_for_fork(_ in 0u32..1u32) { } + } +} + +#[cfg(test)] +mod another_test { + use sugar; + + // Ensure that we can access the `[pub]` composed function above. + #[allow(dead_code)] + fn can_access_pub_compose() { + let _ = sugar::test::two_ints_pub(42); + } +} + +#[cfg(test)] +mod ownership_tests { + #[cfg(feature = "std")] + proptest! { + #[test] + fn accept_ref_arg(ref s in "[0-9]") { + use std_facade::String; + fn assert_string(_s: &String) {} + assert_string(s); + } + + #[test] + fn accept_move_arg(s in "[0-9]") { + use std_facade::String; + fn assert_string(_s: String) {} + assert_string(s); + } + } + + #[derive(Debug)] + struct NotClone(); + const MK: fn() -> NotClone = NotClone; + + proptest! { + #[test] + fn accept_noclone_arg(nc in MK) { + let _nc2: NotClone = nc; + } + + #[test] + fn accept_noclone_ref_arg(ref nc in MK) { + let _nc2: &NotClone = nc; + } + } +} + +#[cfg(test)] +mod closure_tests { + #[test] + fn test_simple() { + let x = 420; + + proptest!(|(y: i32)| { + assert!(x != y); + }); + + proptest!(|(y in 0..100)| { + println!("{}", y); + assert!(x != y); + }); + } + + #[test] + fn test_move() { + let foo = Foo; + + proptest!(move |(x in 1..100, y in 0..100)| { + assert!(x + y > 0, "foo: {:?}", foo); + }); + + let foo = Foo; + proptest!(move |(x: (), y: ())| { + assert!(x == y, "foo: {:?}", foo); + }); + + #[derive(Debug)] + struct Foo; + } + + #[test] + #[should_panic] + #[allow(unreachable_code)] + fn fails_if_closure_panics() { + proptest!(|(_ in 0..1)| { + panic!() + }); + } + + #[test] + fn accepts_unblocked_syntax() { + proptest!(|(x in 0u32..10, y in 10u32..20)| assert!(x < y)); + } + + #[test] + fn accepts_custom_config() { + let conf = ::test_runner::Config::default(); + + proptest!(conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); + proptest!(&conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); + proptest!(conf, move |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); + proptest!(conf, |(_x: u32, _y: u32)| { }); + proptest!(conf, move |(_x: u32, _y: u32)| { }); + } +} + +#[cfg(test)] +mod any_tests { + proptest! { + #[test] + fn test_something + ( + a: bool, + b in 25u8.., + c in 25u8.., + _d: (), + mut _e: (), + ref _f: (), + ref mut _g: (), + [_, _]: [(); 2], + ) { + if a {} // Assert bool. + assert!(b as usize + c as usize >= 50); + } + } + + // Test that the macro accepts some of the inputs we expect it to: + #[test] + fn proptest_ext_test() { + struct Y(pub u8); + + let _ = proptest_helper!(@_EXT _STRAT( _ : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( x : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( ref x : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( mut x : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( ref mut x : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( [_, _] : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( (&mut &Y(ref x)) : u8 )); + let _ = proptest_helper!(@_EXT _STRAT( x in 1..2 )); + + let proptest_helper!(@_EXT _PAT( _ : u8 )) = 1; + let proptest_helper!(@_EXT _PAT( _x : u8 )) = 1; + let proptest_helper!(@_EXT _PAT( mut _x : u8 )) = 1; + let proptest_helper!(@_EXT _PAT( ref _x : u8 )) = 1; + let proptest_helper!(@_EXT _PAT( ref mut _x : u8 )) = 1; + let proptest_helper!(@_EXT _PAT( [_, _] : u8 )) = [1, 2]; + let proptest_helper!(@_EXT _PAT( (&mut &Y(ref _x)) : u8 )) = &mut &Y(1); + let proptest_helper!(@_EXT _PAT( _x in 1..2 )) = 1; + } +} diff --git a/proptest/src/test_runner/config.rs b/proptest/src/test_runner/config.rs new file mode 100644 index 000000000..436127441 --- /dev/null +++ b/proptest/src/test_runner/config.rs @@ -0,0 +1,407 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::Box; +use core::u32; + +#[cfg(feature = "std")] +use std::env; +#[cfg(feature = "std")] +use std::fmt; +#[cfg(feature = "std")] +use std::ffi::OsString; +#[cfg(feature = "std")] +use std::str::FromStr; + +use test_runner::FailurePersistence; +#[cfg(feature = "std")] +use test_runner::FileFailurePersistence; +use test_runner::result_cache::{noop_result_cache, ResultCache}; + +#[cfg(feature = "std")] +const CASES: &str = "PROPTEST_CASES"; +#[cfg(feature = "std")] +const MAX_LOCAL_REJECTS: &str = "PROPTEST_MAX_LOCAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_GLOBAL_REJECTS: &str = "PROPTEST_MAX_GLOBAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_FLAT_MAP_REGENS: &str = "PROPTEST_MAX_FLAT_MAP_REGENS"; +#[cfg(feature = "std")] +const MAX_SHRINK_TIME: &str = "PROPTEST_MAX_SHRINK_TIME"; +#[cfg(feature = "std")] +const MAX_SHRINK_ITERS: &str = "PROPTEST_MAX_SHRINK_ITERS"; +#[cfg(feature = "fork")] +const FORK: &str = "PROPTEST_FORK"; +#[cfg(feature = "timeout")] +const TIMEOUT: &str = "PROPTEST_TIMEOUT"; +#[cfg(feature = "std")] +const VERBOSE: &str = "PROPTEST_VERBOSE"; + +#[cfg(feature = "std")] +fn contextualize_config(mut result: Config) -> Config { + fn parse_or_warn<T : FromStr + fmt::Display>( + src: &OsString, dst: &mut T, typ: &str, var: &str + ) { + if let Some(src) = src.to_str() { + if let Ok(value) = src.parse() { + *dst = value; + } else { + eprintln!( + "proptest: The env-var {}={} can't be parsed as {}, \ + using default of {}.", var, src, typ, *dst); + } + } else { + eprintln!( + "proptest: The env-var {} is not valid, using \ + default of {}.", var, *dst); + } + } + + result.failure_persistence = Some(Box::new(FileFailurePersistence::default())); + for (var, value) in env::vars_os().filter_map( + |(k,v)| k.into_string().ok().map(|k| (k,v))) { + match var.as_str() { + CASES => parse_or_warn(&value, &mut result.cases, "u32", CASES), + MAX_LOCAL_REJECTS => parse_or_warn( + &value, &mut result.max_local_rejects, + "u32", MAX_LOCAL_REJECTS), + MAX_GLOBAL_REJECTS => parse_or_warn( + &value, &mut result.max_global_rejects, + "u32", MAX_GLOBAL_REJECTS), + MAX_FLAT_MAP_REGENS => parse_or_warn( + &value, &mut result.max_flat_map_regens, + "u32", MAX_FLAT_MAP_REGENS), + #[cfg(feature = "fork")] + FORK => parse_or_warn(&value, &mut result.fork, "bool", FORK), + #[cfg(feature = "timeout")] + TIMEOUT => parse_or_warn( + &value, &mut result.timeout, "timeout", TIMEOUT), + MAX_SHRINK_TIME => parse_or_warn( + &value, &mut result.max_shrink_time, "u32", MAX_SHRINK_TIME), + MAX_SHRINK_ITERS => parse_or_warn( + &value, &mut result.max_shrink_iters, "u32", MAX_SHRINK_ITERS), + VERBOSE => parse_or_warn( + &value, &mut result.verbose, "u32", VERBOSE), + + _ => if var.starts_with("PROPTEST_") { + eprintln!("proptest: Ignoring unknown env-var {}.", var); + }, + } + } + + result +} + +#[cfg(not(feature = "std"))] +fn contextualize_config(result: Config) -> Config { result } + +/// The default config, computed by combining environment variables and +/// defaults. +lazy_static! { + static ref DEFAULT_CONFIG: Config = { + let result = Config { + cases: 256, + max_local_rejects: 65_536, + max_global_rejects: 1024, + max_flat_map_regens: 1_000_000, + failure_persistence: None, + source_file: None, + test_name: None, + #[cfg(feature = "fork")] + fork: false, + #[cfg(feature = "timeout")] + timeout: 0, + #[cfg(feature = "std")] + max_shrink_time: 0, + max_shrink_iters: u32::MAX, + result_cache: noop_result_cache, + #[cfg(feature = "std")] + verbose: 0, + _non_exhaustive: (), + }; + + contextualize_config(result) + }; +} + +/// Configuration for how a proptest test should be run. +#[derive(Clone, Debug, PartialEq)] +pub struct Config { + /// The number of successful test cases that must execute for the test as a + /// whole to pass. + /// + /// This does not include implicitly-replayed persisted failing cases. + /// + /// The default is 256, which can be overridden by setting the + /// `PROPTEST_CASES` environment variable. + pub cases: u32, + + /// The maximum number of individual inputs that may be rejected before the + /// test as a whole aborts. + /// + /// The default is 65536, which can be overridden by setting the + /// `PROPTEST_MAX_LOCAL_REJECTS` environment variable. + pub max_local_rejects: u32, + + /// The maximum number of combined inputs that may be rejected before the + /// test as a whole aborts. + /// + /// The default is 1024, which can be overridden by setting the + /// `PROPTEST_MAX_GLOBAL_REJECTS` environment variable. + pub max_global_rejects: u32, + + /// The maximum number of times all `Flatten` combinators will attempt to + /// regenerate values. This puts a limit on the worst-case exponential + /// explosion that can happen with nested `Flatten`s. + /// + /// The default is 1_000_000, which can be overridden by setting the + /// `PROPTEST_MAX_FLAT_MAP_REGENS` environment variable. + pub max_flat_map_regens: u32, + + /// Indicates whether and how to persist failed test results. + /// + /// When compiling with "std" feature (i.e. the standard library is available), the default + /// is `Some(Box::new(FileFailurePersistence::SourceParallel("proptest-regressions")))`. + /// + /// Without the standard library, the default is `None`, and no persistence occurs. + /// + /// See the docs of [`FileFailurePersistence`](enum.FileFailurePersistence.html) + /// and [`MapFailurePersistence`](struct.MapFailurePersistence.html) for more information. + /// + /// The default cannot currently be overridden by an environment variable. + pub failure_persistence: Option<Box<dyn FailurePersistence>>, + + /// File location of the current test, relevant for persistence + /// and debugging. + /// + /// Note the use of `&str` rather than `Path` to be compatible with + /// `#![no_std]` use cases where `Path` is unavailable. + /// + /// See the docs of [`FileFailurePersistence`](enum.FileFailurePersistence.html) + /// for more information on how it may be used for persistence. + pub source_file: Option<&'static str>, + + /// The fully-qualified name of the test being run, as would be passed to + /// the test executable to run just that test. + /// + /// This must be set if `fork` is `true`. Otherwise, it is unused. It is + /// automatically set by `proptest!`. + /// + /// This must include the crate name at the beginning, as produced by + /// `module_path!()`. + pub test_name: Option<&'static str>, + + /// If true, tests are run in a subprocess. + /// + /// Forking allows proptest to work with tests which may fail by aborting + /// the process, causing a segmentation fault, etc, but can be a lot slower + /// in certain environments or when running a very large number of tests. + /// + /// For forking to work correctly, both the `Strategy` and the content of + /// the test case itself must be deterministic. + /// + /// This requires the "fork" feature, enabled by default. + /// + /// The default is `false`, which can be overridden by setting the + /// `PROPTEST_FORK` environment variable. + #[cfg(feature = "fork")] + pub fork: bool, + + /// If non-zero, tests are run in a subprocess and each generated case + /// fails if it takes longer than this number of milliseconds. + /// + /// This implicitly enables forking, even if the `fork` field is `false`. + /// + /// The type here is plain `u32` (rather than + /// `Option<std::time::Duration>`) for the sake of ergonomics. + /// + /// This requires the "timeout" feature, enabled by default. + /// + /// Setting a timeout to less than the time it takes the process to start + /// up and initialise the first test case will cause the whole test to be + /// aborted. + /// + /// The default is `0` (i.e., no timeout), which can be overridden by + /// setting the `PROPTEST_TIMEOUT` environment variable. + #[cfg(feature = "timeout")] + pub timeout: u32, + + /// If non-zero, give up the shrinking process after this many milliseconds + /// have elapsed since the start of the shrinking process. + /// + /// This will not cause currently running test cases to be interrupted. + /// + /// This configuration is only available when the `std` feature is enabled + /// (which it is by default). + /// + /// The default is `0` (i.e., no limit), which can be overridden by setting + /// the `PROPTEST_MAX_SHRINK_TIME` environment variable. + #[cfg(feature = "std")] + pub max_shrink_time: u32, + + /// Give up on shrinking if more than this number of iterations of the test + /// code are run. + /// + /// Setting this value to `0` disables shrinking altogether. + /// + /// The default is `std::u32::MAX`, which can be overridden by setting the + /// `PROPTEST_MAX_SHRINK_ITERS` environment variable. + pub max_shrink_iters: u32, + + /// A function to create new result caches. + /// + /// The default is to do no caching. The easiest way to enable caching is + /// to set this field to `basic_result_cache` (though that is currently + /// only available with the `std` feature). + /// + /// This is useful for strategies which have a tendency to produce + /// duplicate values, or for tests where shrinking can take a very long + /// time due to exploring the same output multiple times. + /// + /// When caching is enabled, generated values themselves are not stored, so + /// this does not pose a risk of memory exhaustion for large test inputs + /// unless using extraordinarily large test case counts. + /// + /// Caching incurs its own overhead, and may very well make your test run + /// more slowly. + pub result_cache: fn () -> Box<dyn ResultCache>, + + /// Set to non-zero values to cause proptest to emit human-targeted + /// messages to stderr as it runs. + /// + /// Greater values cause greater amounts of logs to be emitted. The exact + /// meaning of certain levels other than 0 is subject to change. + /// + /// - 0: No extra output. + /// - 1: Log test failure messages. + /// - 2: Trace low-level details. + /// + /// This is only available with the `std` feature (enabled by default) + /// since on nostd proptest has no way to produce output. + /// + /// The default is `0`, which can be overridden by setting the + /// `PROPTEST_VERBOSE` environment variable. + #[cfg(feature = "std")] + pub verbose: u32, + + // Needs to be public so FRU syntax can be used. + #[doc(hidden)] + pub _non_exhaustive: (), +} + +impl Config { + /// Constructs a `Config` only differing from the `default()` in the + /// number of test cases required to pass the test successfully. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// assert_eq!( + /// Config::with_cases(42), + /// Config { cases: 42, .. Config::default() } + /// ); + /// ``` + pub fn with_cases(cases: u32) -> Self { + Self { cases, .. Config::default() } + } + + /// Constructs a `Config` only differing from the `default()` in the + /// source_file of the present test. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// assert_eq!( + /// Config::with_source_file("computer/question"), + /// Config { source_file: Some("computer/question"), .. Config::default() } + /// ); + /// ``` + pub fn with_source_file(source_file: &'static str) -> Self { + Self { source_file: Some(source_file), .. Config::default() } + } + + /// Constructs a `Config` only differing from the provided Config instance, `self`, + /// in the source_file of the present test. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// let a = Config::with_source_file("computer/question"); + /// let b = a.clone_with_source_file("answer/42"); + /// assert_eq!( + /// a, + /// Config { source_file: Some("computer/question"), .. Config::default() } + /// ); + /// assert_eq!( + /// b, + /// Config { source_file: Some("answer/42"), .. Config::default() } + /// ); + /// ``` + pub fn clone_with_source_file(&self, source_file: &'static str) -> Self { + let mut result = self.clone(); + result.source_file = Some(source_file); + result + } + + /// Return whether this configuration implies forking. + /// + /// This method exists even if the "fork" feature is disabled, in which + /// case it simply returns false. + pub fn fork(&self) -> bool { + self._fork() || self.timeout() > 0 + } + + #[cfg(feature = "fork")] + fn _fork(&self) -> bool { + self.fork + } + + #[cfg(not(feature = "fork"))] + fn _fork(&self) -> bool { + false + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(feature = "timeout")] + pub fn timeout(&self) -> u32 { + self.timeout + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(not(feature = "timeout"))] + pub fn timeout(&self) -> u32 { + 0 + } + + // Used by macros to force the config to be owned without depending on + // certain traits being `use`d. + #[allow(missing_docs)] + #[doc(hidden)] + pub fn __sugar_to_owned(&self) -> Self { + self.clone() + } +} + +impl Default for Config { + fn default() -> Self { + DEFAULT_CONFIG.clone() + } +} diff --git a/proptest/src/test_runner/errors.rs b/proptest/src/test_runner/errors.rs new file mode 100644 index 000000000..72975d46c --- /dev/null +++ b/proptest/src/test_runner/errors.rs @@ -0,0 +1,109 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::fmt; + +#[cfg(feature = "std")] +use std::string::ToString; + +use test_runner::Reason; + +/// Errors which can be returned from test cases to indicate non-successful +/// completion. +/// +/// Note that in spite of the name, `TestCaseError` is currently *not* an +/// instance of `Error`, since otherwise `impl<E : Error> From<E>` could not be +/// provided. +/// +/// Any `Error` can be converted to a `TestCaseError`, which places +/// `Error::display()` into the `Fail` case. +#[derive(Debug, Clone)] +pub enum TestCaseError { + /// The input was not valid for the test case. This does not count as a + /// test failure (nor a success); rather, it simply signals to generate + /// a new input and try again. + Reject(Reason), + /// The code under test failed the test. + Fail(Reason), +} + +/// Convenience for the type returned by test cases. +pub type TestCaseResult = Result<(), TestCaseError>; + +impl TestCaseError { + /// Rejects the generated test input as invalid for this test case. This + /// does not count as a test failure (nor a success); rather, it simply + /// signals to generate a new input and try again. + /// + /// The string gives the location and context of the rejection, and + /// should be suitable for formatting like `Foo did X at {whence}`. + pub fn reject(reason: impl Into<Reason>) -> Self { + TestCaseError::Reject(reason.into()) + } + + /// The code under test failed the test. + /// + /// The string should indicate the location of the failure, but may + /// generally be any string. + pub fn fail(reason: impl Into<Reason>) -> Self { + TestCaseError::Fail(reason.into()) + } +} + +impl fmt::Display for TestCaseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TestCaseError::Reject(ref whence) => + write!(f, "Input rejected at {}", whence), + TestCaseError::Fail(ref why) => + write!(f, "Case failed: {}", why), + } + } +} + +#[cfg(feature = "std")] +impl<E : ::std::error::Error> From<E> for TestCaseError { + fn from(cause: E) -> Self { + TestCaseError::fail(cause.to_string()) + } +} + +/// A failure state from running test cases for a single test. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TestError<T> { + /// The test was aborted for the given reason, for example, due to too many + /// inputs having been rejected. + Abort(Reason), + /// A failing test case was found. The string indicates where and/or why + /// the test failed. The `T` is the minimal input found to reproduce the + /// failure. + Fail(Reason, T), +} + +impl<T : fmt::Debug> fmt::Display for TestError<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TestError::Abort(ref why) => + write!(f, "Test aborted: {}", why), + TestError::Fail(ref why, ref what) => + write!(f, "Test failed: {}; minimal failing input: {:?}", + why, what), + } + } +} + +#[cfg(feature = "std")] +impl<T : fmt::Debug> ::std::error::Error for TestError<T> { + fn description(&self) -> &str { + match *self { + TestError::Abort(..) => "Abort", + TestError::Fail(..) => "Fail", + } + } +} diff --git a/proptest/src/test_runner/failure_persistence/file.rs b/proptest/src/test_runner/failure_persistence/file.rs new file mode 100644 index 000000000..9a30142bb --- /dev/null +++ b/proptest/src/test_runner/failure_persistence/file.rs @@ -0,0 +1,554 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::any::Any; +use core::fmt::Debug; +use core::num::ParseIntError; +use std::borrow::{Cow, ToOwned}; +use std::boxed::Box; +use std::env; +use std::fs; +use std::io::{self, BufRead, Write}; +use std::path::{Path, PathBuf}; +use std::sync::RwLock; +use std::vec::Vec; +use std::string::{String, ToString}; + +use test_runner::{Seed, failure_persistence::FailurePersistence}; +use self::FileFailurePersistence::*; + +/// Describes how failing test cases are persisted. +/// +/// Note that file names in this enum are `&str` rather than `&Path` since +/// constant functions are not yet in Rust stable as of 2017-12-16. +/// +/// In all cases, if a derived path references a directory which does not yet +/// exist, proptest will attempt to create all necessary parent directories. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FileFailurePersistence { + /// Completely disables persistence of failing test cases. + /// + /// This is semantically equivalent to `Direct("/dev/null")` on Unix and + /// `Direct("NUL")` on Windows (though it is internally handled by simply + /// not doing any I/O). + Off, + /// The path given to `TestRunner::set_source_file()` is parsed. The path + /// is traversed up the directory tree until a directory containing a file + /// named `lib.rs` or `main.rs` is found. A sibling to that directory with + /// the name given by the string in this configuration is created, and a + /// file with the same name and path relative to the source directory, but + /// with the extension changed to `.txt`, is used. + /// + /// For example, given a source path of + /// `/home/jsmith/code/project/src/foo/bar.rs` and a configuration of + /// `SourceParallel("proptest-regressions")` (the default), assuming the + /// `src` directory has a `lib.rs` or `main.rs`, the resulting file would + /// be `/home/jsmith/code/project/proptest-regressions/foo/bar.txt`. + /// + /// If no `lib.rs` or `main.rs` can be found, a warning is printed and this + /// behaves like `WithSource`. + /// + /// If no source file has been configured, a warning is printed and this + /// behaves like `Off`. + SourceParallel(&'static str), + /// The path given to `TestRunner::set_source_file()` is parsed. The + /// extension of the path is changed to the string given in this + /// configuration, and that filename is used. + /// + /// For example, given a source path of + /// `/home/jsmith/code/project/src/foo/bar.rs` and a configuration of + /// `WithSource("regressions")`, the resulting path would be + /// `/home/jsmith/code/project/src/foo/bar.regressions`. + WithSource(&'static str), + /// The string given in this option is directly used as a file path without + /// any further processing. + Direct(&'static str), + #[doc(hidden)] + #[allow(missing_docs)] + _NonExhaustive, +} + +impl Default for FileFailurePersistence { + fn default() -> Self { + SourceParallel("proptest-regressions") + } +} + +impl FailurePersistence for FileFailurePersistence { + fn load_persisted_failures(&self, source_file: Option<&'static str>) + -> Vec<Seed> { + let p = self.resolve( + source_file.and_then(|s| absolutize_source_file(Path::new(s))) + .as_ref() + .map(|cow| &**cow)); + + let path: Option<&PathBuf> = p.as_ref(); + let result: io::Result<Vec<Seed>> = path.map_or_else( + || Ok(vec![]), + |path| { + // .ok() instead of .unwrap() so we don't propagate panics here + let _lock = PERSISTENCE_LOCK.read().ok(); + io::BufReader::new(fs::File::open(path)?) + .lines().enumerate() + .filter_map(|(lineno, line)| match line { + Err(err) => Some(Err(err)), + Ok(line) => parse_seed_line(line, path, lineno).map(Ok) + }).collect() + }, + ); + + unwrap_or!(result, err => { + if io::ErrorKind::NotFound != err.kind() { + eprintln!( + "proptest: failed to open {}: {}", + &path.map(|x| &**x) + .unwrap_or_else(|| Path::new("??")) + .display(), + err + ); + } + vec![] + }) + } + + fn save_persisted_failure( + &mut self, + source_file: Option<&'static str>, + seed: Seed, + shrunken_value: &dyn Debug, + ) { + let path = self.resolve(source_file.map(Path::new)); + if let Some(path) = path { + // .ok() instead of .unwrap() so we don't propagate panics here + let _lock = PERSISTENCE_LOCK.write().ok(); + let is_new = !path.is_file(); + + let mut to_write = Vec::<u8>::new(); + if is_new { + write_header(&mut to_write) + .expect("proptest: couldn't write header."); + } + + write_seed_line(&mut to_write, seed, shrunken_value) + .expect("proptest: couldn't write seed line."); + + if let Err(e) = write_seed_data_to_file(&path, &to_write) { + eprintln!("proptest: failed to append to {}: {}", path.display(), e); + } else if is_new { + eprintln!( + "proptest: Saving this and future failures in {}\n\ + proptest: If this test was run on a CI system, you may \ + wish to add the following line to your copy of the file.{}\n\ + {}", + path.display(), + if is_new { " (You may need to create it.)" } else { "" }, + format_basic_seed_line(seed)); + } + } + } + + fn box_clone(&self) -> Box<dyn FailurePersistence> { + Box::new(*self) + } + + fn eq(&self, other: &dyn FailurePersistence) -> bool { + other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self) + } + + fn as_any(&self) -> &dyn Any { self } +} + +/// Ensure that the source file to use for resolving the location of the persisted +/// failing cases file is absolute. +/// +/// The source location can only be used if it is absolute. If `source` is +/// not an absolute path, an attempt will be made to determine the absolute +/// path based on the current working directory and its parents. If no +/// absolute path can be determined, a warning will be printed and proptest +/// will continue as if this function had never been called. +/// +/// See [`FileFailurePersistence`](enum.FileFailurePersistence.html) for details on +/// how this value is used once it is made absolute. +/// +/// This is normally called automatically by the `proptest!` macro, which +/// passes `file!()`. +/// +fn absolutize_source_file<'a>(source: &'a Path) -> Option<Cow<'a, Path>> { + absolutize_source_file_with_cwd(env::current_dir, source) +} + +fn absolutize_source_file_with_cwd<'a>( + getcwd: impl FnOnce () -> io::Result<PathBuf>, + source: &'a Path, +) -> Option<Cow<'a, Path>> { + if source.is_absolute() { + // On Unix, `file!()` is absolute. In these cases, we can use + // that path directly. + Some(Cow::Borrowed(source)) + } else { + // On Windows, `file!()` is relative to the crate root, but the + // test is not generally run with the crate root as the working + // directory, so the path is not directly usable. However, the + // working directory is almost always a subdirectory of the crate + // root, so pop directories off until pushing the source onto the + // directory results in a path that refers to an existing file. + // Once we find such a path, we can use that. + // + // If we can't figure out an absolute path, print a warning and act + // as if no source had been given. + match getcwd() { + Ok(mut cwd) => loop { + let joined = cwd.join(source); + if joined.is_file() { + break Some(Cow::Owned(joined)); + } + + if !cwd.pop() { + eprintln!( + "proptest: Failed to find absolute path of \ + source file '{:?}'. Ensure the test is \ + being run from somewhere within the crate \ + directory hierarchy.", + source + ); + break None; + } + }, + + Err(e) => { + eprintln!( + "proptest: Failed to determine current \ + directory, so the relative source path \ + '{:?}' cannot be resolved: {}", + source, e + ); + None + } + } + } +} + +fn parse_seed_line(mut line: String, path: &Path, lineno: usize) + -> Option<Seed> { + // Remove anything after and including '#': + if let Some(comment_start) = line.find('#') { + line.truncate(comment_start); + } + + if line.len() > 0 { + // Split by whitespace and ignore empty lines: + let parts = line.trim().split(char::is_whitespace).collect::<Vec<_>>(); + let len = parts.len(); + // "xs" stands for "XorShift". + if parts[0] == "xs" && len == 5 { + // Parse using the chosen one: + if let Ok(seed) = parse_seed_old(&parts[1..]) { + return Some(seed); + } else { + eprintln!("proptest: {}:{}: unparsable line, ignoring", + path.display(), lineno + 1); + } + } else { + eprintln!("proptest: {}:{}: unknown case type `{}` \ + (corrupt file or newer proptest version?)", + &path.display(), lineno + 1, parts[0]); + } + } + + None +} + +fn parse_seed_old(parts: &[&str]) -> Result<Seed, ParseIntError> { + let mut ret = [0u32; 4]; + for (src, dst) in parts.iter().zip(ret.iter_mut()) { + *dst = src.parse()?; + } + + Ok(convert_to_new_format(ret)) +} + +fn convert_to_new_format(old_format: [u32; 4]) -> Seed { + use byteorder::{ByteOrder, LittleEndian}; + let mut new_format = [0; 16]; + // rand uses little endian for this conversion on all platforms + LittleEndian::write_u32_into(&old_format[..], &mut new_format); + new_format +} + +fn convert_from_new_format(new_format: Seed) -> [u32; 4] { + use byteorder::{ByteOrder, LittleEndian}; + let mut old_format = [0; 4]; + LittleEndian::read_u32_into(&new_format[..], &mut old_format); + old_format +} + +fn format_basic_seed_line(seed: Seed) -> String { + // Write line start: + let mut buf = "xs ".to_owned(); + + // Write out each part of seed: + for &s in &convert_from_new_format(seed) { + buf.push_str(&s.to_string()); + buf.push(' '); + } + + buf +} + +fn write_seed_line(buf: &mut Vec<u8>, seed: Seed, shrunken_value: &dyn Debug) + -> io::Result<()> +{ + // Write the seed itself + write!(buf, "{}", format_basic_seed_line(seed)); + + // Write out comment: + let debug_start = buf.len(); + write!(buf, "# shrinks to {:?}", shrunken_value)?; + + // Ensure there are no newlines in the debug output + for byte in &mut buf[debug_start..] { + if b'\n' == *byte || b'\r' == *byte { + *byte = b' '; + } + } + + buf.push(b'\n'); + + Ok(()) +} + +fn write_header(buf: &mut Vec<u8>) -> io::Result<()> { + writeln!(buf, +"\ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases." + ) +} + +fn write_seed_data_to_file(dst: &Path, data: &[u8]) -> io::Result<()> { + if let Some(parent) = dst.parent() { + fs::create_dir_all(parent)?; + } + + let mut options = fs::OpenOptions::new(); + options.append(true).create(true); + let mut out = options.open(dst)?; + out.write_all(data)?; + + Ok(()) +} + +impl FileFailurePersistence { + /// Given the nominal source path, determine the location of the failure + /// persistence file, if any. + pub(super) fn resolve(&self, source: Option<&Path>) -> Option<PathBuf> { + let source = source.and_then(absolutize_source_file); + + match *self { + Off => None, + + SourceParallel(sibling) => match source { + Some(source_path) => { + let mut dir = Cow::into_owned(source_path.clone()); + let mut found = false; + while dir.pop() { + if dir.join("lib.rs").is_file() || + dir.join("main.rs").is_file() + { + found = true; + break; + } + } + + if !found { + eprintln!( + "proptest: FileFailurePersistence::SourceParallel set, \ + but failed to find lib.rs or main.rs" + ); + WithSource(sibling).resolve(Some(&*source_path)) + } else { + let suffix = source_path + .strip_prefix(&dir) + .expect("parent of source is not a prefix of it?") + .to_owned(); + let mut result = dir; + // If we've somehow reached the root, or someone gave + // us a relative path that we've exhausted, just accept + // creating a subdirectory instead. + let _ = result.pop(); + result.push(sibling); + result.push(&suffix); + result.set_extension("txt"); + Some(result) + } + } + None => { + eprintln!( + "proptest: FileFailurePersistence::SourceParallel set, \ + but no source file known" + ); + None + } + }, + + WithSource(extension) => match source { + Some(source_path) => { + let mut result = Cow::into_owned(source_path); + result.set_extension(extension); + Some(result) + } + + None => { + eprintln!( + "proptest: FileFailurePersistence::WithSource set, \ + but no source file known" + ); + None + } + }, + + Direct(path) => Some(Path::new(path).to_owned()), + + _NonExhaustive => panic!("FailurePersistence set to _NonExhaustive"), + } + } +} + +lazy_static! { + /// Used to guard access to the persistence file(s) so that a single + /// process will not step on its own toes. + /// + /// We don't have much protecting us should two separate process try to + /// write to the same file at once (depending on how atomic append mode is + /// on the OS), but this should be extremely rare. + static ref PERSISTENCE_LOCK: RwLock<()> = RwLock::new(()); +} + +#[cfg(test)] +mod tests { + use super::*; + + struct TestPaths { + crate_root: &'static Path, + src_file: PathBuf, + subdir_file: PathBuf, + misplaced_file: PathBuf, + } + + lazy_static! { + static ref TEST_PATHS: TestPaths = { + let crate_root = Path::new(env!("CARGO_MANIFEST_DIR")); + let lib_root = crate_root.join("src"); + let src_subdir = lib_root.join("strategy"); + let src_file = lib_root.join("foo.rs"); + let subdir_file = src_subdir.join("foo.rs"); + let misplaced_file = crate_root.join("foo.rs"); + TestPaths { + crate_root, + src_file, + subdir_file, + misplaced_file, + } + }; + } + + #[test] + fn persistence_file_location_resolved_correctly() { + // If off, there is never a file + assert_eq!(None, Off.resolve(None)); + assert_eq!(None, Off.resolve(Some(&TEST_PATHS.subdir_file))); + + // For direct, we don't care about the source file, and instead always + // use whatever is in the config. + assert_eq!( + Some(Path::new("bar.txt").to_owned()), + Direct("bar.txt").resolve(None) + ); + assert_eq!( + Some(Path::new("bar.txt").to_owned()), + Direct("bar.txt").resolve(Some(&TEST_PATHS.subdir_file)) + ); + + // For WithSource, only the extension changes, but we get nothing if no + // source file was configured. + // Accounting for the way absolute paths work on Windows would be more + // complex, so for now don't test that case. + #[cfg(unix)] + fn absolute_path_case() { + assert_eq!( + Some(Path::new("/foo/bar.ext").to_owned()), + WithSource("ext").resolve(Some(Path::new("/foo/bar.rs"))) + ); + } + #[cfg(not(unix))] + fn absolute_path_case() {} + absolute_path_case(); + assert_eq!(None, WithSource("ext").resolve(None)); + + // For SourceParallel, we make a sibling directory tree and change the + // extensions to .txt ... + assert_eq!( + Some(TEST_PATHS.crate_root.join("sib").join("foo.txt")), + SourceParallel("sib").resolve(Some(&TEST_PATHS.src_file)) + ); + assert_eq!( + Some( + TEST_PATHS + .crate_root + .join("sib") + .join("strategy") + .join("foo.txt") + ), + SourceParallel("sib").resolve(Some(&TEST_PATHS.subdir_file)) + ); + // ... but if we can't find lib.rs / main.rs, give up and set the + // extension instead ... + assert_eq!( + Some(TEST_PATHS.crate_root.join("foo.sib")), + SourceParallel("sib").resolve(Some(&TEST_PATHS.misplaced_file)) + ); + // ... and if no source is configured, we do nothing + assert_eq!(None, SourceParallel("ext").resolve(None)); + } + + #[test] + fn relative_source_files_absolutified() { + const TEST_RUNNER_PATH: &[&str] = &["src", "test_runner", "mod.rs"]; + lazy_static! { + static ref TEST_RUNNER_RELATIVE: PathBuf = TEST_RUNNER_PATH.iter().collect(); + } + const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); + + let expected = ::std::iter::once(CARGO_DIR) + .chain(TEST_RUNNER_PATH.iter().map(|s| *s)) + .collect::<PathBuf>(); + + // Running from crate root + assert_eq!( + &*expected, + absolutize_source_file_with_cwd( + || Ok(Path::new(CARGO_DIR).to_owned()), + &TEST_RUNNER_RELATIVE + ).unwrap() + ); + + // Running from test subdirectory + assert_eq!( + &*expected, + absolutize_source_file_with_cwd( + || Ok(Path::new(CARGO_DIR).join("target")), + &TEST_RUNNER_RELATIVE + ).unwrap() + ); + } +} diff --git a/proptest/src/test_runner/failure_persistence/map.rs b/proptest/src/test_runner/failure_persistence/map.rs new file mode 100644 index 000000000..3410c97a5 --- /dev/null +++ b/proptest/src/test_runner/failure_persistence/map.rs @@ -0,0 +1,91 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::any::Any; +use std_facade::{fmt, Box, Vec, BTreeMap, BTreeSet}; + +use test_runner::failure_persistence::FailurePersistence; +use test_runner::Seed; + +/// Failure persistence option that loads and saves seeds in memory +/// on the heap. This may be useful when accumulating test failures +/// across multiple `TestRunner` instances for external reporting +/// or batched persistence. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct MapFailurePersistence { + /// Backing map, keyed by source_file. + pub map: BTreeMap<&'static str, BTreeSet<Seed>> +} + +impl FailurePersistence for MapFailurePersistence { + fn load_persisted_failures(&self, source_file: Option<&'static str>) + -> Vec<Seed> { + source_file + .and_then(|source| self.map.get(source)) + .map(|seeds| seeds.iter().cloned().collect::<Vec<_>>()) + .unwrap_or_default() + } + + fn save_persisted_failure( + &mut self, + source_file: Option<&'static str>, + seed: Seed, + _shrunken_value: &dyn fmt::Debug, + ) { + let s = match source_file { + Some(sf) => sf, + None => return + }; + let set = self.map.entry(s).or_insert_with(BTreeSet::new); + set.insert(seed); + } + + fn box_clone(&self) -> Box<dyn FailurePersistence> { + Box::new(self.clone()) + } + + fn eq(&self, other: &dyn FailurePersistence) -> bool { + other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self) + } + + fn as_any(&self) -> &dyn Any { self } +} + +#[cfg(test)] +mod tests { + use super::*; + use test_runner::failure_persistence::tests::*; + + #[test] + fn initial_map_is_empty() { + assert!(MapFailurePersistence::default() + .load_persisted_failures(HI_PATH).is_empty()) + } + + #[test] + fn seeds_recoverable() { + let mut p = MapFailurePersistence::default(); + p.save_persisted_failure(HI_PATH, INC_SEED, &""); + let restored = p.load_persisted_failures(HI_PATH); + assert_eq!(1, restored.len()); + assert_eq!(INC_SEED, *restored.first().unwrap()); + + assert!(p.load_persisted_failures(None).is_empty()); + assert!(p.load_persisted_failures(UNREL_PATH).is_empty()); + } + + #[test] + fn seeds_deduplicated() { + let mut p = MapFailurePersistence::default(); + p.save_persisted_failure(HI_PATH, INC_SEED, &""); + p.save_persisted_failure(HI_PATH, INC_SEED, &""); + let restored = p.load_persisted_failures(HI_PATH); + assert_eq!(1, restored.len()); + } +} diff --git a/proptest/src/test_runner/failure_persistence/mod.rs b/proptest/src/test_runner/failure_persistence/mod.rs new file mode 100644 index 000000000..7a39dfe30 --- /dev/null +++ b/proptest/src/test_runner/failure_persistence/mod.rs @@ -0,0 +1,71 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::any::Any; +use std_facade::{fmt, Box, Vec}; + +#[cfg(feature = "std")] +mod file; +mod map; +mod noop; + +#[cfg(feature = "std")] +pub use self::file::*; +pub use self::map::*; +pub use self::noop::*; + +use test_runner::Seed; + +/// Provides external persistence for historical test failures by storing seeds. +pub trait FailurePersistence: Send + Sync + fmt::Debug { + /// Supply seeds associated with the given `source_file` that may be used + /// by a `TestRunner`'s random number generator in order to consistently + /// recreate a previously-failing `Strategy`-provided value. + fn load_persisted_failures(&self, source_file: Option<&'static str>) + -> Vec<Seed>; + + /// Store a new failure-generating seed associated with the given `source_file`. + fn save_persisted_failure( + &mut self, + source_file: Option<&'static str>, + seed: Seed, + shrunken_value: &dyn fmt::Debug, + ); + + /// Delegate method for producing a trait object usable with `Clone` + fn box_clone(&self) -> Box<dyn FailurePersistence>; + + /// Equality testing delegate required due to constraints of trait objects. + fn eq(&self, other: &dyn FailurePersistence) -> bool; + + /// Assistant method for trait object comparison. + fn as_any(&self) -> &dyn Any; +} + +impl<'a, 'b> PartialEq<dyn FailurePersistence + 'b> +for dyn FailurePersistence + 'a { + fn eq(&self, other: &(dyn FailurePersistence + 'b)) -> bool { + FailurePersistence::eq(self, other) + } +} + +impl Clone for Box<dyn FailurePersistence> { + fn clone(&self) -> Box<dyn FailurePersistence> { + self.box_clone() + } +} + +#[cfg(test)] +mod tests { + pub const INC_SEED: [u8; 16] = + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + + pub const HI_PATH: Option<&str> = Some("hi"); + pub const UNREL_PATH: Option<&str> = Some("unrelated"); +} diff --git a/proptest/src/test_runner/failure_persistence/noop.rs b/proptest/src/test_runner/failure_persistence/noop.rs new file mode 100644 index 000000000..3819c1e8b --- /dev/null +++ b/proptest/src/test_runner/failure_persistence/noop.rs @@ -0,0 +1,64 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::any::Any; +use std_facade::{fmt, Box, Vec}; + +use test_runner::failure_persistence::FailurePersistence; +use test_runner::Seed; + +/// Failure persistence option that loads and saves nothing at all. +#[derive(Debug, Default, PartialEq)] +struct NoopFailurePersistence; + +impl FailurePersistence for NoopFailurePersistence { + fn load_persisted_failures(&self, _source_file: Option<&'static str>) -> Vec<Seed> { + Vec::new() + } + + fn save_persisted_failure(&mut self, + _source_file: Option<&'static str>, + _seed: Seed, + _shrunken_value: &dyn fmt::Debug, + ) { + } + + fn box_clone(&self) -> Box<dyn FailurePersistence> { + Box::new(NoopFailurePersistence) + } + + fn eq(&self, other: &dyn FailurePersistence) -> bool { + other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self) + } + + fn as_any(&self) -> &dyn Any { self } +} + +#[cfg(test)] +mod tests { + use super::*; + use test_runner::failure_persistence::tests::*; + + #[test] + fn default_load_is_empty() { + assert!(NoopFailurePersistence::default() + .load_persisted_failures(None).is_empty()); + assert!(NoopFailurePersistence::default() + .load_persisted_failures(HI_PATH).is_empty()); + } + + #[test] + fn seeds_not_recoverable() { + let mut p = NoopFailurePersistence::default(); + p.save_persisted_failure(HI_PATH, INC_SEED, &""); + assert!(p.load_persisted_failures(HI_PATH).is_empty()); + assert!(p.load_persisted_failures(None).is_empty()); + assert!(p.load_persisted_failures(UNREL_PATH).is_empty()); + } +} diff --git a/proptest/src/test_runner/mod.rs b/proptest/src/test_runner/mod.rs new file mode 100644 index 000000000..fb4e8ea45 --- /dev/null +++ b/proptest/src/test_runner/mod.rs @@ -0,0 +1,31 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! State and functions for running proptest tests. +//! +//! You do not normally need to access things in this module directly except +//! when implementing new low-level strategies. + +mod rng; +mod failure_persistence; +mod result_cache; +mod config; +mod reason; +mod errors; +#[cfg(feature = "fork")] +mod replay; +mod runner; + +pub use self::rng::*; +pub use self::failure_persistence::*; +pub use self::result_cache::*; +pub use self::config::*; +pub use self::reason::*; +pub use self::errors::*; +pub use self::runner::*; diff --git a/proptest/src/test_runner/reason.rs b/proptest/src/test_runner/reason.rs new file mode 100644 index 000000000..09395b67b --- /dev/null +++ b/proptest/src/test_runner/reason.rs @@ -0,0 +1,54 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::{fmt, Cow, String, Box}; + +/// The reason for why something, such as a generated value, was rejected. +/// +/// Currently this is merely a wrapper around a message, but more properties +/// may be added in the future. +/// +/// This is constructed via `.into()` on a `String`, `&'static str`, or +/// `Box<str>`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Reason(Cow<'static, str>); + +impl Reason { + /// Return the message for this `Reason`. + /// + /// The message is intended for human consumption, and is not guaranteed to + /// have any format in particular. + pub fn message(&self) -> &str { + &*self.0 + } +} + +impl From<&'static str> for Reason { + fn from(s: &'static str) -> Self { + Reason(s.into()) + } +} + +impl From<String> for Reason { + fn from(s: String) -> Self { + Reason(s.into()) + } +} + +impl From<Box<str>> for Reason { + fn from(s: Box<str>) -> Self { + Reason(String::from(s).into()) + } +} + +impl fmt::Display for Reason { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.message(), f) + } +} diff --git a/proptest/src/test_runner/replay.rs b/proptest/src/test_runner/replay.rs new file mode 100644 index 000000000..4dc8a3fa6 --- /dev/null +++ b/proptest/src/test_runner/replay.rs @@ -0,0 +1,188 @@ +//- +// Copyright 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +use std::fs; +use std::io::{self, BufRead, Read, Seek, Write}; +use std::path::Path; +use std::string::String; +use std::vec::Vec; + +use test_runner::{TestCaseError, TestCaseResult, Seed}; + +const SENTINEL: &'static str = "proptest-forkfile"; + +/// A "replay" of a `TestRunner` invocation. +/// +/// The replay mechanism is used to support forking. When a child process +/// exits, the parent can read the replay to reproduce the state the child had; +/// similarly, if a child crashes, a new one can be started and given a replay +/// which steps it one complication past the input that caused the crash. +/// +/// The replay system is tightly coupled to the `TestRunner` itself. It does +/// not carry enough information to be used in different builds of the same +/// application, or even two different runs of the test process since changes +/// to the persistence file will perturb the replay. +/// +/// `Replay` has a special string format for being stored in files. It starts +/// with a line just containing the text in `SENTINEL`, then 16 lines +/// containing the values of `seed`, then an unterminated line consisting of +/// `+`, `-`, and `!` characters to indicate test case passes/failures/rejects, +/// `.` to indicate termination of the test run, or ` ` as a dummy "I'm alive" +/// signal. This format makes it easy for the child process to blindly append +/// to the file without having to worry about the possibility of appends being +/// non-atomic. +#[derive(Clone, Debug)] +pub struct Replay { + /// The seed of the RNG used to start running the test cases. + pub seed: Seed, + /// A log of whether certain test cases passed or failed. The runner will + /// assume the same results occur without actually running the test cases. + pub steps: Vec<TestCaseResult>, +} + +impl Replay { + /// If `other` is longer than `self`, add the extra elements to `self`. + pub fn merge(&mut self, other: &Replay) { + if other.steps.len() > self.steps.len() { + let sl = self.steps.len(); + self.steps.extend_from_slice(&other.steps[sl..]); + } + } +} + +/// Result of loading a replay file. +#[derive(Clone, Debug)] +pub enum ReplayFileStatus { + /// The file is valid and represents a currently-in-progress test. + InProgress(Replay), + /// The file is valid, but indicates that all testing has completed. + Terminated(Replay), + /// The file is not parsable. + Corrupt, +} + +/// Open the file in the usual read+append+create mode. +pub fn open_file(path: impl AsRef<Path>) -> io::Result<fs::File> { + fs::OpenOptions::new() + .read(true) + .append(true) + .create(true) + .truncate(false) + .open(path) +} + +fn step_to_char(step: &TestCaseResult) -> char { + match *step { + Ok(_) => '+', + Err(TestCaseError::Reject(_)) => '!', + Err(TestCaseError::Fail(_)) => '-', + } +} + +/// Append the given step to the given output. +pub fn append(mut file: impl Write, step: &TestCaseResult) + -> io::Result<()> { + write!(file, "{}", step_to_char(step)) +} + +/// Append a no-op step to the given output. +pub fn ping(mut file: impl Write) -> io::Result<()> { + write!(file, " ") +} + +/// Append a termination mark to the given output. +pub fn terminate(mut file: impl Write) -> io::Result<()> { + write!(file, ".") +} + +impl Replay { + /// Write the full state of this `Replay` to the given output. + pub fn init_file(&self, mut file: impl Write) -> io::Result<()> { + writeln!(file, "{}", SENTINEL)?; + + for word in &self.seed { + writeln!(file, "{}", word)?; + } + + let mut step_data = Vec::<u8>::new(); + for step in &self.steps { + step_data.push(step_to_char(step) as u8); + } + + file.write_all(&step_data)?; + + Ok(()) + } + + /// Mark the replay as complete in the file. + pub fn complete(mut file: impl Write) -> io::Result<()> { + write!(file, ".") + } + + /// Parse a `Replay` out of the given file. + /// + /// The reader is implicitly seeked to the beginning before reading. + pub fn parse_from(mut file: impl Read + Seek) + -> io::Result<ReplayFileStatus> { + file.seek(io::SeekFrom::Start(0))?; + + let mut reader = io::BufReader::new(&mut file); + let mut line = String::new(); + + // Ensure it starts with the sentinel. We do this since we rely on a + // named temporary file which could be in a location where another + // actor could replace it with, eg, a symlink to a location they don't + // control but we do. By rejecting a read from a file missing the + // sentinel, and not doing any writes if we can't read the file, we + // won't risk overwriting another file since the prospective attacker + // would need to be able to change the file to start with the sentinel + // themselves. + // + // There are still some possible symlink attacks that can work by + // tricking us into reading, but those are non-destructive things like + // interfering with a FIFO or Unix socket. + reader.read_line(&mut line)?; + if SENTINEL != line.trim() { + return Ok(ReplayFileStatus::Corrupt); + } + + let mut seed: Seed = [0; 16]; + for word in &mut seed { + line.clear(); + reader.read_line(&mut line)?; + + match line.trim().parse::<u8>() { + Ok(w) => *word = w, + Err(_) => return Ok(ReplayFileStatus::Corrupt), + } + } + + line.clear(); + reader.read_line(&mut line)?; + + let mut steps = Vec::new(); + for ch in line.chars() { + match ch { + '+' => steps.push(Ok(())), + '-' => steps.push(Err(TestCaseError::fail( + "failed in other process"))), + '!' => steps.push(Err(TestCaseError::reject( + "rejected in other process"))), + '.' => return Ok(ReplayFileStatus::Terminated( + Replay { seed, steps })), + ' ' => (), + _ => return Ok(ReplayFileStatus::Corrupt), + } + } + + Ok(ReplayFileStatus::InProgress(Replay { seed, steps })) + } +} diff --git a/proptest/src/test_runner/result_cache.rs b/proptest/src/test_runner/result_cache.rs new file mode 100644 index 000000000..0f1c33762 --- /dev/null +++ b/proptest/src/test_runner/result_cache.rs @@ -0,0 +1,115 @@ +//- +// Copyright 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std_facade::Box; +use std_facade::fmt; +#[cfg(feature = "std")] use std::collections::HashMap; + +use test_runner::errors::TestCaseResult; + +/// A key used for the result cache. +/// +/// The capabilities of this structure are currently quite limited; all one can +/// do with safe code is get the `&dyn Debug` of the test input value. This may +/// improve in the future, particularly at such a time that specialisation +/// becomes stable. +#[derive(Debug)] +pub struct ResultCacheKey<'a> { + value: &'a dyn fmt::Debug, +} + +impl<'a> ResultCacheKey<'a> { + pub(crate) fn new(value: &'a dyn fmt::Debug) -> Self { + Self { value } + } + + /// Return the test input value as an `&dyn Debug`. + pub fn value_debug(&self) -> &dyn fmt::Debug { + self.value + } +} + +/// An object which can cache the outcomes of tests. +pub trait ResultCache { + /// Convert the given cache key into a `u64` representing that value. The + /// u64 is used as the key below. + /// + /// This is a separate step so that ownership of the key value can be + /// handed off to user code without needing to be able to clone it. + fn key(&self, key: &ResultCacheKey) -> u64; + /// Save `result` as the outcome associated with the test input in `key`. + /// + /// `result` is passed as a reference so that the decision to clone depends + /// on whether the cache actually plans on storing it. + fn put(&mut self, key: u64, result: &TestCaseResult); + /// If `put()` has been called with a semantically equivalent `key`, return + /// the saved result. Otherwise, return `None`. + fn get(&self, key: u64) -> Option<&TestCaseResult>; +} + +#[cfg(feature = "std")] +#[derive(Debug, Default, Clone)] +struct BasicResultCache { + entries: HashMap<u64, TestCaseResult>, +} + +#[cfg(feature = "std")] +impl ResultCache for BasicResultCache { + fn key(&self, val: &ResultCacheKey) -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::io::{self, Write}; + use std::hash::Hasher; + + struct HashWriter(DefaultHasher); + impl io::Write for HashWriter { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.0.write(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + let mut hash = HashWriter(DefaultHasher::default()); + write!(hash, "{:?}", val).expect("Debug format returned Err"); + hash.0.finish() + } + + fn put(&mut self, key: u64, result: &TestCaseResult) { + self.entries.insert(key, result.clone()); + } + + fn get(&self, key: u64) -> Option<&TestCaseResult> { + self.entries.get(&key) + } +} + +/// A basic result cache. +/// +/// Values are identified by their `Debug` string representation. +#[cfg(feature = "std")] +pub fn basic_result_cache() -> Box<dyn ResultCache> { + Box::new(BasicResultCache::default()) +} + +pub(crate) struct NoOpResultCache; +impl ResultCache for NoOpResultCache { + fn key(&self, _: &ResultCacheKey) -> u64 { 0 } + fn put(&mut self, _: u64, _: &TestCaseResult) { } + fn get(&self, _: u64) -> Option<&TestCaseResult> { None } +} + +/// A result cache that does nothing. +/// +/// This is the default value of `ProptestConfig.result_cache`. +pub fn noop_result_cache() -> Box<dyn ResultCache> { + Box::new(NoOpResultCache) +} diff --git a/proptest/src/test_runner/rng.rs b/proptest/src/test_runner/rng.rs new file mode 100644 index 000000000..1be53d72b --- /dev/null +++ b/proptest/src/test_runner/rng.rs @@ -0,0 +1,87 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rand::{Error, RngCore, Rng, SeedableRng}; +use rand::prng::XorShiftRng; + +/// Proptest's random number generator. +/// +/// Currently, this is just a wrapper around `XorShiftRng`. +#[derive(Clone, Debug)] +pub struct TestRng { rng: XorShiftRng } + +impl RngCore for TestRng { + fn next_u32(&mut self) -> u32 { self.rng.next_u32() } + fn next_u64(&mut self) -> u64 { self.rng.next_u64() } + fn fill_bytes(&mut self, dest: &mut [u8]) { self.rng.fill_bytes(dest) } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.rng.try_fill_bytes(dest) + } +} + +pub(crate) type Seed = [u8; 16]; + +impl TestRng { + /// Construct a default TestRng from entropy. + pub(crate) fn default_rng() -> Self { + #[cfg(feature = "std")] + { + use rand::FromEntropy; + Self { rng: XorShiftRng::from_entropy() } + } + #[cfg(not(feature = "std"))] + Self::from_seed([ + 0x19, 0x3a, 0x67, 0x54, // x + 0x69, 0xd4, 0xa7, 0xa8, // y + 0x05, 0x0e, 0x83, 0x97, // z + 0xbb, 0xa7, 0x3b, 0x11, // w + ]) + } + + /// Construct a TestRng by the perturbed randomized seed + /// from an existing TestRng. + pub(crate) fn gen_rng(&mut self) -> Self { + Self::from_seed(self.new_rng_seed()) + } + + /// Overwrite the given TestRng with the provided seed. + pub(crate) fn set_seed(&mut self, seed: Seed) { + *self = Self::from_seed(seed); + } + + /// Generate a new randomized seed, set it to this TestRng, + /// and return the seed. + pub(crate) fn gen_get_seed(&mut self) -> Seed { + let seed = self.new_rng_seed(); + self.set_seed(seed); + seed + } + + /// Randomize a perturbed randomized seed from the given TestRng. + pub(crate) fn new_rng_seed(&mut self) -> Seed { + let mut seed = self.rng.gen::<Seed>(); + + // Directly using XorShiftRng::from_seed() at this point would result + // in self.rng and the returned value being exactly the same. Perturb + // the seed with some arbitrary values to prevent this. + for word in seed.chunks_mut(4) { + word[3] ^= 0xde; + word[2] ^= 0xad; + word[1] ^= 0xbe; + word[0] ^= 0xef; + } + + seed + } + + /// Construct a TestRng from a given seed. + fn from_seed(seed: Seed) -> Self { + Self { rng: XorShiftRng::from_seed(seed) } + } +} diff --git a/proptest/src/test_runner/runner.rs b/proptest/src/test_runner/runner.rs new file mode 100644 index 000000000..e83ef633b --- /dev/null +++ b/proptest/src/test_runner/runner.rs @@ -0,0 +1,1197 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::{fmt, iter}; +#[cfg(feature = "std")] +use std::panic::{self, AssertUnwindSafe}; +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering::SeqCst; +use std_facade::{Box, Arc, Vec, BTreeMap, String}; + +#[cfg(feature = "fork")] +use std::fs; +#[cfg(feature = "fork")] +use std::env; +#[cfg(feature = "fork")] +use std::cell::{Cell, RefCell}; +#[cfg(feature = "fork")] +use rusty_fork; +#[cfg(feature = "fork")] +use tempfile; + +use test_runner::{TestRng, Seed}; +use test_runner::errors::*; +use test_runner::config::*; +use test_runner::reason::*; +use test_runner::result_cache::*; +#[cfg(feature = "fork")] +use test_runner::replay; +use strategy::*; + +#[cfg(feature = "fork")] +const ENV_FORK_FILE: &'static str = "_PROPTEST_FORKFILE"; + +const ALWAYS: u32 = 0; +const SHOW_FALURES: u32 = 1; +const TRACE: u32 = 2; + +#[cfg(feature = "std")] +macro_rules! verbose_message { + ($runner:expr, $level:expr, $fmt:tt $($arg:tt)*) => { { + #[allow(unused_comparisons)] + { + if $runner.config.verbose >= $level { + eprintln!(concat!("proptest: ", $fmt) $($arg)*); + } + }; + () + } } +} + +#[cfg(not(feature = "std"))] +macro_rules! verbose_message { + ($runner:expr, $level:expr, $fmt:tt $($arg:tt)*) => { + let _ = $level; + } +} + +type RejectionDetail = BTreeMap<Reason, u32>; + +/// State used when running a proptest test. +#[derive(Clone)] +pub struct TestRunner { + config: Config, + successes: u32, + local_rejects: u32, + global_rejects: u32, + rng: TestRng, + flat_map_regens: Arc<AtomicUsize>, + + local_reject_detail: RejectionDetail, + global_reject_detail: RejectionDetail, +} + +impl fmt::Debug for TestRunner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TestRunner") + .field("config", &self.config) + .field("successes", &self.successes) + .field("local_rejects", &self.local_rejects) + .field("global_rejects", &self.global_rejects) + .field("rng", &"<TestRng>") + .field("flat_map_regens", &self.flat_map_regens) + .field("local_reject_detail", &self.local_reject_detail) + .field("global_reject_detail", &self.global_reject_detail) + .finish() + } +} + +impl fmt::Display for TestRunner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\tsuccesses: {}\n\ + \tlocal rejects: {}\n", + self.successes, self.local_rejects)?; + for (whence, count) in &self.local_reject_detail { + writeln!(f, "\t\t{} times at {}", count, whence)?; + } + writeln!(f, "\tglobal rejects: {}", self.global_rejects)?; + for (whence, count) in &self.global_reject_detail { + writeln!(f, "\t\t{} times at {}", count, whence)?; + } + + Ok(()) + } +} + +/// Equivalent to: `TestRunner::new(Config::default())`. +impl Default for TestRunner { + fn default() -> Self { + Self::new(Config::default()) + } +} + +#[cfg(feature = "fork")] +#[derive(Debug)] +struct ForkOutput { + file: Option<fs::File>, +} + +#[cfg(feature = "fork")] +impl ForkOutput { + fn append(&mut self, result: &TestCaseResult) { + if let Some(ref mut file) = self.file { + replay::append(file, result) + .expect("Failed to append to replay file"); + } + } + + fn ping(&mut self) { + if let Some(ref mut file) = self.file { + replay::ping(file) + .expect("Failed to append to replay file"); + } + } + + fn terminate(&mut self) { + if let Some(ref mut file) = self.file { + replay::terminate(file) + .expect("Failed to append to replay file"); + } + } + + fn empty() -> Self { + ForkOutput { file: None } + } + + fn is_in_fork(&self) -> bool { + self.file.is_some() + } +} + +#[cfg(not(feature = "fork"))] +#[derive(Debug)] +struct ForkOutput; + +#[cfg(not(feature = "fork"))] +impl ForkOutput { + fn append(&mut self, _result: &TestCaseResult) { } + fn ping(&mut self) { } + fn terminate(&mut self) { } + fn empty() -> Self { ForkOutput } + fn is_in_fork(&self) -> bool { false } +} + +#[cfg(not(feature = "std"))] +fn call_test<V, F, R> + (_runner: &mut TestRunner, + case: V, test: &F, replay: &mut R, + result_cache: &mut dyn ResultCache, _: &mut ForkOutput) -> TestCaseResult +where + V: fmt::Debug, + F: Fn(V) -> TestCaseResult, + R: Iterator<Item = TestCaseResult>, +{ + if let Some(result) = replay.next() { + return result; + } + + let cache_key = result_cache.key(&ResultCacheKey::new(&case)); + if let Some(result) = result_cache.get(cache_key) { + return result.clone(); + } + + let result = test(case); + result_cache.put(cache_key, &result); + result +} + +#[cfg(feature = "std")] +fn call_test<V, F, R> + (runner: &mut TestRunner, + case: V, test: &F, replay: &mut R, + result_cache: &mut dyn ResultCache, fork_output: &mut ForkOutput) + -> TestCaseResult +where + V: fmt::Debug, + F: Fn(V) -> TestCaseResult, + R: Iterator<Item = TestCaseResult>, +{ + use std::time; + + let timeout = runner.config.timeout(); + + if let Some(result) = replay.next() { + return result; + } + + // Now that we're about to start a new test (as far as the replay system is + // concerned), ping the replay file so the parent process can determine + // that we made it this far. + fork_output.ping(); + + verbose_message!(runner, TRACE, "Next test input: {:?}", case); + + let cache_key = result_cache.key(&ResultCacheKey::new(&case)); + if let Some(result) = result_cache.get(cache_key) { + verbose_message!(runner, TRACE, "Test input hit cache, skipping execution"); + return result.clone(); + } + + let time_start = time::Instant::now(); + + let mut result = unwrap_or!( + panic::catch_unwind(AssertUnwindSafe(|| test(case))), + what => Err(TestCaseError::Fail( + what.downcast::<&'static str>().map(|s| (*s).into()) + .or_else(|what| what.downcast::<String>().map(|b| (*b).into())) + .or_else(|what| what.downcast::<Box<str>>().map(|b| (*b).into())) + .unwrap_or_else(|_| "<unknown panic value>".into())))); + + // If there is a timeout and we exceeded it, fail the test here so we get + // consistent behaviour. (The parent process cannot precisely time the test + // cases itself.) + if timeout > 0 && result.is_ok() { + let elapsed = time_start.elapsed(); + let elapsed_millis = elapsed.as_secs() as u32 * 1000 + + elapsed.subsec_nanos() / 1_000_000; + + if elapsed_millis > timeout { + result = Err(TestCaseError::fail( + format!("Timeout of {} ms exceeded: test took {} ms", + timeout, elapsed_millis))); + } + } + + result_cache.put(cache_key, &result); + fork_output.append(&result); + + match result { + Ok(()) => verbose_message!(runner, TRACE, "Test case passed"), + Err(TestCaseError::Reject(ref reason)) => verbose_message!( + runner, SHOW_FALURES, "Test case rejected: {}", reason), + Err(TestCaseError::Fail(ref reason)) => verbose_message!( + runner, SHOW_FALURES, "Test case failed: {}", reason), + } + + result +} + +type TestRunResult<S> = Result<(), TestError<<S as Strategy>::Value>>; + +impl TestRunner { + /// Create a fresh `TestRunner` with the given configuration. + pub fn new(config: Config) -> Self { + TestRunner { + config: config, + successes: 0, + local_rejects: 0, + global_rejects: 0, + rng: TestRng::default_rng(), + flat_map_regens: Arc::new(AtomicUsize::new(0)), + local_reject_detail: BTreeMap::new(), + global_reject_detail: BTreeMap::new(), + } + } + + /// Create a fresh `TestRunner` with the same config and global counters as + /// this one, but with local state reset and an independent `Rng` (but + /// deterministic). + pub(crate) fn partial_clone(&mut self) -> Self { + TestRunner { + config: self.config.clone(), + successes: 0, + local_rejects: 0, + global_rejects: 0, + rng: self.new_rng(), + flat_map_regens: Arc::clone(&self.flat_map_regens), + local_reject_detail: BTreeMap::new(), + global_reject_detail: BTreeMap::new(), + } + } + + /// Returns the RNG for this test run. + pub fn rng(&mut self) -> &mut TestRng { + &mut self.rng + } + + /// Create a new, independent but deterministic RNG from the RNG in this + /// runner. + pub fn new_rng(&mut self) -> TestRng { + self.rng.gen_rng() + } + + /// Returns the configuration of this runner. + pub fn config(&self) -> &Config { + &self.config + } + + /// Run test cases against `f`, choosing inputs via `strategy`. + /// + /// If any failure cases occur, try to find a minimal failure case and + /// report that. If invoking `f` panics, the panic is turned into a + /// `TestCaseError::Fail`. + /// + /// If failure persistence is enabled, all persisted failing cases are + /// tested first. If a later non-persisted case fails, its seed is + /// persisted before returning failure. + /// + /// Returns success or failure indicating why the test as a whole failed. + pub fn run<S : Strategy>(&mut self, strategy: &S, + test: impl Fn (S::Value) -> TestCaseResult) + -> TestRunResult<S> { + if self.config.fork() { + self.run_in_fork(strategy, test) + } else { + self.run_in_process(strategy, test) + } + } + + #[cfg(not(feature = "fork"))] + fn run_in_fork<S : Strategy> + (&mut self, _: &S, _: impl Fn (S::Value) -> TestCaseResult) -> TestRunResult<S> + { + unreachable!() + } + + #[cfg(feature = "fork")] + fn run_in_fork<S : Strategy>(&mut self, strategy: &S, + test: impl Fn (S::Value) -> TestCaseResult) + -> TestRunResult<S> + { + let mut test = Some(test); + + let test_name = rusty_fork::fork_test::fix_module_path( + self.config.test_name.expect( + "Must supply test_name when forking enabled")); + let forkfile: RefCell<Option<tempfile::NamedTempFile>> = + RefCell::new(None); + let init_forkfile_size = Cell::new(0u64); + let seed = self.rng.new_rng_seed(); + let mut replay = replay::Replay { seed, steps: vec![] }; + let mut child_count = 0; + let timeout = self.config.timeout(); + + fn forkfile_size(forkfile: &Option<tempfile::NamedTempFile>) + -> u64 { + forkfile.as_ref().map_or( + 0, |ff| ff.as_file().metadata().map(|md| md.len()).unwrap_or(0)) + } + + loop { + let (child_error, last_fork_file_len) = rusty_fork::fork( + test_name, + rusty_fork_id!(), + |cmd| { + let mut forkfile = forkfile.borrow_mut(); + if forkfile.is_none() { + *forkfile = + Some(tempfile::NamedTempFile::new().expect( + "Failed to create temporary file for fork")); + replay.init_file( + forkfile.as_mut().unwrap()).expect( + "Failed to initialise temporary file for fork"); + } + + init_forkfile_size.set(forkfile_size(&forkfile)); + + cmd.env(ENV_FORK_FILE, forkfile.as_ref().unwrap().path()); + }, + |child, _| await_child( + child, &mut forkfile.borrow_mut().as_mut().unwrap(), + timeout), + || match self.run_in_process(strategy, test.take().unwrap()) { + Ok(_) => (), + Err(e) => + panic!("Test failed normally in child process.\n{}\n{}", + e, self), + }) + .expect("Fork failed"); + + let parsed = replay::Replay::parse_from( + &mut forkfile.borrow_mut().as_mut().unwrap()) + .expect("Failed to re-read fork file"); + match parsed { + replay::ReplayFileStatus::InProgress(new_replay) => + replay = new_replay, + replay::ReplayFileStatus::Terminated(new_replay) => { + replay = new_replay; + break; + }, + replay::ReplayFileStatus::Corrupt => + panic!("Child process corrupted replay file"), + } + + let curr_forkfile_size = forkfile_size(&forkfile.borrow()); + + // If the child failed to append *anything* to the forkfile, it + // crashed or timed out before starting even one test case, so + // bail. + if curr_forkfile_size == init_forkfile_size.get() { + return Err(TestError::Abort( + "Child process crashed or timed out before the first test \ + started running; giving up.".into())); + } + + // The child only terminates early if it outright crashes or we + // kill it due to timeout, so add a synthetic failure to the + // output. But only do this if the length of the fork file is the + // same as when we last saw it, or if the child was not killed due + // to timeout. (This is because the child could have appended + // something to the file after we gave up waiting for it but before + // we were able to kill it). + if last_fork_file_len.map_or(true, |last_fork_file_len| { + last_fork_file_len == curr_forkfile_size + }) { + let error = Err(child_error.unwrap_or( + TestCaseError::fail("Child process was terminated abruptly \ + but with successful status"))); + replay::append(forkfile.borrow_mut().as_mut().unwrap(), &error) + .expect("Failed to append to replay file"); + replay.steps.push(error); + } + + // Bail if we've gone through too many processes in case the + // shrinking process itself is crashing. + child_count += 1; + if child_count >= 10000 { + return Err(TestError::Abort( + "Giving up after 10000 child processes crashed".into())); + } + } + + // Run through the steps in-process (without ever running the actual + // tests) to produce the shrunken value and update the persistence + // file. + self.rng.set_seed(replay.seed); + self.run_in_process_with_replay( + strategy, |_| panic!("Ran past the end of the replay"), + replay.steps.into_iter(), ForkOutput::empty()) + } + + fn run_in_process<S : Strategy> + (&mut self, strategy: &S, test: impl Fn (S::Value) -> TestCaseResult) + -> TestRunResult<S> + { + let (replay_steps, fork_output) = init_replay(&mut self.rng); + self.run_in_process_with_replay( + strategy, test, replay_steps.into_iter(), fork_output) + } + + fn run_in_process_with_replay<S : Strategy> + (&mut self, strategy: &S, + test: impl Fn (S::Value) -> TestCaseResult, + mut replay: impl Iterator<Item = TestCaseResult>, + mut fork_output: ForkOutput) + -> TestRunResult<S> + { + let old_rng = self.rng.clone(); + + let persisted_failure_seeds: Vec<Seed> = + self.config.failure_persistence + .as_ref() + .map(|f| f.load_persisted_failures(self.config.source_file)) + .unwrap_or_default(); + + let mut result_cache = self.new_cache(); + + for persisted_seed in persisted_failure_seeds { + self.rng.set_seed(persisted_seed); + self.gen_and_run_case(strategy, &test, &mut replay, + &mut *result_cache, &mut fork_output)?; + } + self.rng = old_rng; + + while self.successes < self.config.cases { + // Generate a new seed and make an RNG from that so that we know + // what seed to persist if this case fails. + let seed = self.rng.gen_get_seed(); + let result = self.gen_and_run_case( + strategy, &test, &mut replay, &mut *result_cache, &mut fork_output); + if let Err(TestError::Fail(_, ref value)) = result { + if let Some(ref mut failure_persistence) = self.config.failure_persistence { + let source_file = &self.config.source_file; + + // Don't update the persistence file if we're a child + // process. The parent relies on it remaining consistent + // and will take care of updating it itself. + if !fork_output.is_in_fork() { + failure_persistence.save_persisted_failure( + *source_file, seed, value); + } + } + } + + if let Err(e) = result { + fork_output.terminate(); + return Err(e.into()); + } + } + + fork_output.terminate(); + Ok(()) + } + + fn gen_and_run_case<S : Strategy> + (&mut self, strategy: &S, + f: &impl Fn (S::Value) -> TestCaseResult, + replay: &mut impl Iterator<Item = TestCaseResult>, + result_cache: &mut dyn ResultCache, + fork_output: &mut ForkOutput) + -> TestRunResult<S> + { + let case = + unwrap_or!(strategy.new_tree(self), msg => + return Err(TestError::Abort(msg))); + + if self.run_one_with_replay(case, f, replay, result_cache, fork_output)? { + self.successes += 1; + } + Ok(()) + } + + /// Run one specific test case against this runner. + /// + /// If the test fails, finds the minimal failing test case. If the test + /// does not fail, returns whether it succeeded or was filtered out. + /// + /// This does not honour the `fork` config, and will not be able to + /// terminate the run if it runs for longer than `timeout`. However, if the + /// test function returns but took longer than `timeout`, the test case + /// will fail. + pub fn run_one<V : ValueTree> + (&mut self, case: V, + test: impl Fn (V::Value) -> TestCaseResult) + -> Result<bool, TestError<V::Value>> + { + let mut result_cache = self.new_cache(); + self.run_one_with_replay( + case, test, + &mut iter::empty::<TestCaseResult>().fuse(), + &mut *result_cache, + &mut ForkOutput::empty()) + } + + fn run_one_with_replay<V : ValueTree> + (&mut self, mut case: V, + test: impl Fn (V::Value) -> TestCaseResult, + replay: &mut impl Iterator<Item = TestCaseResult>, + result_cache: &mut dyn ResultCache, + fork_output: &mut ForkOutput) + -> Result<bool, TestError<V::Value>> + { + let result = call_test( + self, case.current(), &test, + replay, result_cache, fork_output); + + match result { + Ok(_) => Ok(true), + Err(TestCaseError::Fail(why)) => { + let why = self.shrink(&mut case, test, replay, + result_cache, fork_output) + .unwrap_or(why); + Err(TestError::Fail(why, case.current())) + }, + Err(TestCaseError::Reject(whence)) => { + self.reject_global(whence)?; + Ok(false) + }, + } + } + + fn shrink<V : ValueTree> + (&mut self, case: &mut V, + test: impl Fn (V::Value) -> TestCaseResult, + replay: &mut impl Iterator<Item = TestCaseResult>, + result_cache: &mut dyn ResultCache, + fork_output: &mut ForkOutput) + -> Option<Reason> + { + #[cfg(feature = "std")] + use std::time; + + let mut last_failure = None; + let mut iterations = 0; + #[cfg(feature = "std")] + let start_time = time::Instant::now(); + + if case.simplify() { + loop { + #[cfg(feature = "std")] + let timed_out = if self.config.max_shrink_time > 0 { + let elapsed = start_time.elapsed(); + let elapsed_ms = elapsed.as_secs().saturating_mul(1000) + .saturating_add(elapsed.subsec_millis().into()); + if elapsed_ms > self.config.max_shrink_time as u64 { + Some(elapsed_ms) + } else { + None + } + } else { + None + }; + #[cfg(not(feature = "std"))] + let timed_out: Option<u64> = None; + + let bail = if iterations >= self.config.max_shrink_iters { + verbose_message!( + self, ALWAYS, + "Aborting shrinking after {} iterations", iterations); + true + } else if let Some(ms) = timed_out { + verbose_message!( + self, ALWAYS, + "Aborting shrinking after taking too long: {}", ms); + true + } else { + false + }; + + if bail { + // Move back to the most recent failing case + while case.complicate() { + fork_output.append(&Ok(())); + } + break; + } + + iterations += 1; + + let result = call_test( + self, + case.current(), &test, + replay, + result_cache, fork_output); + + match result { + // Rejections are effectively a pass here, + // since they indicate that any behaviour of + // the function under test is acceptable. + Ok(_) | Err(TestCaseError::Reject(..)) => { + if !case.complicate() { + break; + } + }, + Err(TestCaseError::Fail(why)) => { + last_failure = Some(why); + if !case.simplify() { + break; + } + }, + } + } + } + + last_failure + } + + /// Update the state to account for a local rejection from `whence`, and + /// return `Ok` if the caller should keep going or `Err` to abort. + pub fn reject_local(&mut self, whence: impl Into<Reason>) + -> Result<(), Reason> { + if self.local_rejects >= self.config.max_local_rejects { + Err("Too many local rejects".into()) + } else { + self.local_rejects += 1; + Self::insert_or_increment(&mut self.local_reject_detail, + whence.into()); + Ok(()) + } + } + + /// Update the state to account for a global rejection from `whence`, and + /// return `Ok` if the caller should keep going or `Err` to abort. + fn reject_global<T>(&mut self, whence: Reason) -> Result<(),TestError<T>> { + if self.global_rejects >= self.config.max_global_rejects { + Err(TestError::Abort("Too many global rejects".into())) + } else { + self.global_rejects += 1; + Self::insert_or_increment(&mut self.global_reject_detail, whence); + Ok(()) + } + } + + /// Insert 1 or increment the rejection detail at key for whence. + fn insert_or_increment(into: &mut RejectionDetail, whence: Reason) { + into.entry(whence).and_modify(|count| { *count += 1 }).or_insert(1); + } + + /// Increment the counter of flat map regenerations and return whether it + /// is still under the configured limit. + pub fn flat_map_regen(&self) -> bool { + self.flat_map_regens.fetch_add(1, SeqCst) < + self.config.max_flat_map_regens as usize + } + + fn new_cache(&self) -> Box<dyn ResultCache> { + (self.config.result_cache)() + } +} + +#[cfg(feature = "fork")] +fn init_replay(rng: &mut TestRng) -> (Vec<TestCaseResult>, ForkOutput) { + use test_runner::replay::{open_file, Replay, ReplayFileStatus::*}; + + if let Some(path) = env::var_os(ENV_FORK_FILE) { + let mut file = open_file(&path).expect("Failed to open replay file"); + let loaded = Replay::parse_from(&mut file) + .expect("Failed to read replay file"); + match loaded { + InProgress(replay) => { + rng.set_seed(replay.seed); + (replay.steps, ForkOutput { file: Some(file) }) + }, + + Terminated(_) => + panic!("Replay file for child process is terminated?"), + + Corrupt => + panic!("Replay file for child process is corrupt"), + } + } else { + (vec![], ForkOutput::empty()) + } +} + +#[cfg(not(feature = "fork"))] +fn init_replay(_rng: &mut TestRng) -> (iter::Empty<TestCaseResult>, ForkOutput) { + (iter::empty(), ForkOutput::empty()) +} + +#[cfg(feature = "fork")] +fn await_child_without_timeout(child: &mut rusty_fork::ChildWrapper) + -> (Option<TestCaseError>, Option<u64>) { + let status = child.wait().expect("Failed to wait for child process"); + + if status.success() { + (None, None) + } else { + (Some(TestCaseError::fail(format!( + "Child process exited with {}", status))), None) + } +} + +#[cfg(all(feature = "fork", not(feature = "timeout")))] +fn await_child(child: &mut rusty_fork::ChildWrapper, + _: &mut tempfile::NamedTempFile, + _timeout: u32) + -> (Option<TestCaseError>, Option<u64>) { + await_child_without_timeout(child) +} + +#[cfg(all(feature = "fork", feature = "timeout"))] +fn await_child(child: &mut rusty_fork::ChildWrapper, + forkfile: &mut tempfile::NamedTempFile, + timeout: u32) + -> (Option<TestCaseError>, Option<u64>) { + use std::time::Duration; + + if 0 == timeout { + return await_child_without_timeout(child); + } + + // The child can run for longer than the timeout since it may run + // multiple tests. Each time the timeout expires, we check whether the + // file has grown larger. If it has, we allow the child to keep running + // until the next timeout. + let mut last_forkfile_len = forkfile.as_file().metadata() + .map(|md| md.len()).unwrap_or(0); + + loop { + if let Some(status) = + child.wait_timeout(Duration::from_millis(timeout.into())) + .expect("Failed to wait for child process") + { + if status.success() { + return (None, None); + } else { + return (Some(TestCaseError::fail(format!( + "Child process exited with {}", status))), None); + } + } + + let current_len = forkfile.as_file().metadata() + .map(|md| md.len()).unwrap_or(0); + // If we've gone a full timeout period without the file growing, + // fail the test and kill the child. + if current_len <= last_forkfile_len { + return (Some(TestCaseError::fail(format!( + "Timed out waiting for child process"))), Some(current_len)); + } else { + last_forkfile_len = current_len; + } + } +} + +#[cfg(test)] +mod test { + use std::cell::Cell; + use std::fs; + + use super::*; + use test_runner::FileFailurePersistence; + use strategy::Strategy; + + #[test] + fn gives_up_after_too_many_rejections() { + let config = Config::default(); + let mut runner = TestRunner::new(config.clone()); + let runs = Cell::new(0); + let result = runner.run(&(0u32..), |_| { + runs.set(runs.get() + 1); + Err(TestCaseError::reject("reject")) + }); + match result { + Err(TestError::Abort(_)) => (), + e => panic!("Unexpected result: {:?}", e), + } + assert_eq!(config.max_global_rejects + 1, runs.get()); + } + + #[test] + fn test_pass() { + let mut runner = TestRunner::default(); + let result = runner.run(&(1u32..), |v| { assert!(v > 0); Ok(()) }); + assert_eq!(Ok(()), result); + } + + #[test] + fn test_fail_via_result() { + let mut runner = TestRunner::new(Config { + failure_persistence: None, + .. Config::default() + }); + let result = runner.run( + &(0u32..10u32), |v| { + if v < 5 { + Ok(()) + } else { + Err(TestCaseError::fail("not less than 5")) + } + }); + + assert_eq!(Err(TestError::Fail("not less than 5".into(), 5)), result); + } + + #[test] + fn test_fail_via_panic() { + let mut runner = TestRunner::new(Config { + failure_persistence: None, + .. Config::default() + }); + let result = runner.run(&(0u32..10u32), |v| { + assert!(v < 5, "not less than 5"); + Ok(()) + }); + assert_eq!(Err(TestError::Fail("not less than 5".into(), 5)), result); + } + + #[derive(Clone, Copy, PartialEq)] + struct PoorlyBehavedDebug(i32); + impl fmt::Debug for PoorlyBehavedDebug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\r\n{:?}\r\n", self.0) + } + } + + #[test] + fn failing_cases_persisted_and_reloaded() { + const FILE: &'static str = "persistence-test.txt"; + let _ = fs::remove_file(FILE); + + let max = 10_000_000i32; + let input = (0i32..max).prop_map(PoorlyBehavedDebug); + let config = Config { + failure_persistence: Some(Box::new( + FileFailurePersistence::Direct(FILE) + )), + .. Config::default() + }; + + // First test with cases that fail above half max, and then below half + // max, to ensure we can correctly parse both lines of the persistence + // file. + let first_sub_failure = { + TestRunner::new(config.clone()).run(&input, |v| { + if v.0 < max/2 { + Ok(()) + } else { + Err(TestCaseError::Fail("too big".into())) + } + }).expect_err("didn't fail?") + }; + let first_super_failure = { + TestRunner::new(config.clone()).run(&input, |v| { + if v.0 >= max/2 { + Ok(()) + } else { + Err(TestCaseError::Fail("too small".into())) + } + }).expect_err("didn't fail?") + }; + let second_sub_failure = { + TestRunner::new(config.clone()).run(&input, |v| { + if v.0 < max/2 { + Ok(()) + } else { + Err(TestCaseError::Fail("too big".into())) + } + }).expect_err("didn't fail?") + }; + let second_super_failure = { + TestRunner::new(config.clone()).run(&input, |v| { + if v.0 >= max/2 { + Ok(()) + } else { + Err(TestCaseError::Fail("too small".into())) + } + }).expect_err("didn't fail?") + }; + + assert_eq!(first_sub_failure, second_sub_failure); + assert_eq!(first_super_failure, second_super_failure); + } + + #[test] + fn new_rng_makes_separate_rng() { + use rand::Rng; + let mut runner = TestRunner::default(); + let from_1 = runner.new_rng().gen::<Seed>(); + let from_2 = runner.rng().gen::<Seed>(); + assert_ne!(from_1, from_2); + } + + #[cfg(feature = "fork")] + #[test] + fn run_successful_test_in_fork() { + let mut runner = TestRunner::new(Config { + fork: true, + test_name: Some(concat!( + module_path!(), "::run_successful_test_in_fork")), + .. Config::default() + }); + + assert!(runner.run(&(0u32..1000), |_| Ok(())).is_ok()); + } + + #[cfg(feature = "fork")] + #[test] + fn normal_failure_in_fork_results_in_correct_failure() { + let mut runner = TestRunner::new(Config { + fork: true, + test_name: Some(concat!( + module_path!(), "::normal_failure_in_fork_results_in_correct_failure")), + .. Config::default() + }); + + let failure = runner.run(&(0u32..1000), |v| { + prop_assert!(v < 500); + Ok(()) + }).err().unwrap(); + + match failure { + TestError::Fail(_, value) => assert_eq!(500, value), + failure => panic!("Unexpected failure: {:?}", failure), + } + } + + #[cfg(feature = "fork")] + #[test] + fn nonsuccessful_exit_finds_correct_failure() { + let mut runner = TestRunner::new(Config { + fork: true, + test_name: Some(concat!( + module_path!(), "::nonsuccessful_exit_finds_correct_failure")), + .. Config::default() + }); + + let failure = runner.run(&(0u32..1000), |v| { + if v >= 500 { + ::std::process::exit(1); + } + Ok(()) + }).err().unwrap(); + + match failure { + TestError::Fail(_, value) => assert_eq!(500, value), + failure => panic!("Unexpected failure: {:?}", failure), + } + } + + #[cfg(feature = "fork")] + #[test] + fn spurious_exit_finds_correct_failure() { + let mut runner = TestRunner::new(Config { + fork: true, + test_name: Some(concat!( + module_path!(), "::spurious_exit_finds_correct_failure")), + .. Config::default() + }); + + let failure = runner.run(&(0u32..1000), |v| { + if v >= 500 { + ::std::process::exit(0); + } + Ok(()) + }).err().unwrap(); + + match failure { + TestError::Fail(_, value) => assert_eq!(500, value), + failure => panic!("Unexpected failure: {:?}", failure), + } + } + + #[cfg(feature = "timeout")] + #[test] + fn long_sleep_timeout_finds_correct_failure() { + let mut runner = TestRunner::new(Config { + fork: true, + timeout: 500, + test_name: Some(concat!( + module_path!(), "::long_sleep_timeout_finds_correct_failure")), + .. Config::default() + }); + + let failure = runner.run(&(0u32..1000), |v| { + if v >= 500 { + ::std::thread::sleep(::std::time::Duration::from_millis(10_000)); + } + Ok(()) + }).err().unwrap(); + + match failure { + TestError::Fail(_, value) => assert_eq!(500, value), + failure => panic!("Unexpected failure: {:?}", failure), + } + } + + #[cfg(feature = "timeout")] + #[test] + fn mid_sleep_timeout_finds_correct_failure() { + let mut runner = TestRunner::new(Config { + fork: true, + timeout: 500, + test_name: Some(concat!( + module_path!(), "::mid_sleep_timeout_finds_correct_failure")), + .. Config::default() + }); + + let failure = runner.run(&(0u32..1000), |v| { + if v >= 500 { + // Sleep a little longer than the timeout. This means that + // sometimes the test case itself will return before the parent + // process has noticed the child is timing out, so it's up to + // the child to mark it as a failure. + ::std::thread::sleep(::std::time::Duration::from_millis(600)); + } else { + // Sleep a bit so that the parent and child timing don't stay + // in sync. + ::std::thread::sleep(::std::time::Duration::from_millis(100)) + } + Ok(()) + }).err().unwrap(); + + match failure { + TestError::Fail(_, value) => assert_eq!(500, value), + failure => panic!("Unexpected failure: {:?}", failure), + } + } + + #[cfg(feature = "std")] + #[test] + fn duplicate_tests_not_run_with_basic_result_cache() { + use std::cell::{Cell, RefCell}; + use std::collections::HashSet; + use std::rc::Rc; + + for _ in 0..256 { + let mut runner = TestRunner::new(Config { + failure_persistence: None, + result_cache: ::test_runner::result_cache::basic_result_cache, + .. Config::default() + }); + let pass = Rc::new(Cell::new(true)); + let seen = Rc::new(RefCell::new(HashSet::new())); + let result = runner.run( + &(0u32..65536u32).prop_map(|v| v % 10), + |val| { + if !seen.borrow_mut().insert(val) { + println!("Value {} seen more than once", val); + pass.set(false); + } + + prop_assert!(val <= 5); + Ok(()) + }); + + assert!(pass.get()); + if let Err(TestError::Fail(_, val)) = result { + assert_eq!(6, val); + } else { + panic!("Incorrect result: {:?}", result); + } + } + } +} + +#[cfg(all(feature = "fork", feature = "timeout", test))] +mod timeout_tests { + use core::u32; + use std::thread; + use std::time::Duration; + + use super::*; + + rusty_fork_test! { + #![rusty_fork(timeout_ms = 4_000)] + + #[test] + fn max_shrink_iters_works() { + test_shrink_bail(Config { + max_shrink_iters: 5, + .. Config::default() + }); + } + + #[test] + fn max_shrink_time_works() { + test_shrink_bail(Config { + max_shrink_time: 1000, + .. Config::default() + }); + } + + #[test] + fn max_shrink_iters_works_with_forking() { + test_shrink_bail(Config { + fork: true, + test_name: Some( + concat!(module_path!(), + "::max_shrink_iters_works_with_forking")), + max_shrink_time: 1000, + .. Config::default() + }); + } + + #[test] + fn detects_child_failure_to_start() { + let mut runner = TestRunner::new(Config { + timeout: 100, + test_name: Some( + concat!(module_path!(), + "::detects_child_failure_to_start")), + .. Config::default() + }); + let result = runner.run(&Just(()).prop_map(|()| { + thread::sleep(Duration::from_millis(200)) + }), Ok); + + if let Err(TestError::Abort(_)) = result { + // OK + } else { + panic!("Unexpected result: {:?}", result); + } + } + } + + fn test_shrink_bail(config: Config) { + let mut runner = TestRunner::new(config); + let result = runner.run(&::num::u64::ANY, |v| { + thread::sleep(Duration::from_millis(250)); + prop_assert!(v <= u32::MAX as u64); + Ok(()) + }); + + if let Err(TestError::Fail(_, value)) = result { + // Ensure the final value was in fact a failing case. + assert!(value > u32::MAX as u64); + } else { + panic!("Unexpected result: {:?}", result); + } + } +} diff --git a/proptest/src/tuple.rs b/proptest/src/tuple.rs new file mode 100644 index 000000000..a0506638b --- /dev/null +++ b/proptest/src/tuple.rs @@ -0,0 +1,148 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for combining strategies into tuples. +//! +//! There is no explicit "tuple strategy"; simply make a tuple containing the +//! strategy and that tuple is itself a strategy. + +use strategy::*; +use test_runner::*; + +/// Common `ValueTree` implementation for all tuple strategies. +#[derive(Clone, Copy, Debug)] +pub struct TupleValueTree<T> { + tree: T, + shrinker: u32, + prev_shrinker: Option<u32>, +} + +impl<T> TupleValueTree<T> { + /// Create a new `TupleValueTree` wrapping `inner`. + /// + /// It only makes sense for `inner` to be a tuple of an arity for which the + /// type implements `ValueTree`. + pub fn new(inner: T) -> Self { + TupleValueTree { + tree: inner, + shrinker: 0, + prev_shrinker: None, + } + } +} + +macro_rules! tuple { + ($($fld:tt : $typ:ident),*) => { + impl<$($typ : Strategy),*> Strategy for ($($typ,)*) { + type Tree = TupleValueTree<($($typ::Tree,)*)>; + type Value = ($($typ::Value,)*); + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let values = ($(self.$fld.new_tree(runner)?,)*); + Ok(TupleValueTree::new(values)) + } + } + + impl<$($typ : ValueTree),*> ValueTree + for TupleValueTree<($($typ,)*)> { + type Value = ($($typ::Value,)*); + + fn current(&self) -> Self::Value { + ($(self.tree.$fld.current(),)*) + } + + fn simplify(&mut self) -> bool { + $( + if $fld == self.shrinker { + if self.tree.$fld.simplify() { + self.prev_shrinker = Some(self.shrinker); + return true; + } else { + self.shrinker += 1; + } + } + )* + false + } + + fn complicate(&mut self) -> bool { + if let Some(shrinker) = self.prev_shrinker {$( + if $fld == shrinker { + if self.tree.$fld.complicate() { + self.shrinker = shrinker; + return true; + } else { + self.prev_shrinker = None; + return false; + } + } + )*} + false + } + } + } +} + +tuple!(0: A); +tuple!(0: A, 1: B); +tuple!(0: A, 1: B, 2: C); +tuple!(0: A, 1: B, 2: C, 3: D); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J); + +#[cfg(test)] +mod test { + use strategy::*; + + use super::*; + + #[test] + fn shrinks_fully_ltr() { + fn pass(a: (i32, i32)) -> bool { + a.0 * a.1 <= 9 + } + + let input = (0..32, 0..32); + let mut runner = TestRunner::default(); + + let mut cases_tested = 0; + for _ in 0..256 { + // Find a failing test case + let mut case = input.new_tree(&mut runner).unwrap(); + if pass(case.current()) { continue; } + + loop { + if pass(case.current()) { + if !case.complicate() { break; } + } else { + if !case.simplify() { break; } + } + } + + let last = case.current(); + assert!(!pass(last)); + // Maximally shrunken + assert!(pass((last.0 - 1, last.1))); + assert!(pass((last.0, last.1 - 1))); + + cases_tested += 1; + } + + assert!(cases_tested > 32, "Didn't find enough test cases"); + } + + #[test] + fn test_sanity() { + check_strategy_sanity((0i32..100, 0i32..1000, 0i32..10000), None); + } +} diff --git a/proptest/test-persistence-location/README.md b/proptest/test-persistence-location/README.md new file mode 100644 index 000000000..173213fc1 --- /dev/null +++ b/proptest/test-persistence-location/README.md @@ -0,0 +1,6 @@ +This directory contains two independent cargo worspaces, one which is a +traditional single-crate workspace and another which is a multi-crate workspace +(with only one crate, but what matters is the directory layout). + +These are used to test where the persistence files end up when all is said and +done. diff --git a/proptest/test-persistence-location/run-tests.bat b/proptest/test-persistence-location/run-tests.bat new file mode 100644 index 000000000..bb4f4891d --- /dev/null +++ b/proptest/test-persistence-location/run-tests.bat @@ -0,0 +1,23 @@ +cd single-crate +rd /s /q proptest-regressions +cargo test >cargo.txt +cargo clean >nul +if not exist proptest-regressions/submodule/code.txt goto fail + +cd ..\workspace +rd /s /q proptest-regressions +cargo test --all >cargo.txt +cargo clean >nul +if not exist member/proptest-regressions/submodule/code.txt goto fail +cd .. + +echo All persistence files written to correct location. +echo PASS +exit /b + +:fail +echo Persistence file not in expected location. FS: +dir /s +echo Cargo output: +type cargo.txt +exit /b 1 diff --git a/proptest/test-persistence-location/run-tests.sh b/proptest/test-persistence-location/run-tests.sh new file mode 100755 index 000000000..a642055a6 --- /dev/null +++ b/proptest/test-persistence-location/run-tests.sh @@ -0,0 +1,28 @@ +#! /bin/sh + +find . -name \*.txt -o -name proptest-regressions -depth -exec rm -rf {} \; || \ + exit $? + +( + cd single-crate + cargo test >cargo-out.txt 2>&1 # Ignore expected failure + cargo clean >/dev/null + if ! test -f proptest-regressions/submodule/code.txt; then + echo >&2 "Persistence file not written to the correct location. FS:" + find . >&2 + echo >&2 "Cargo output:" + cat >&2 cargo-out.txt + exit 1 + fi +) && ( + cd workspace + cargo test --all >cargo-out.txt 2>&1 # Ignore expected failure + cargo clean >/dev/null + if ! test -f member/proptest-regressions/submodule/code.txt; then + echo >&2 "Persistence file not written to the correct location. FS:" + find . >&2 + echo >&2 "Cargo output:" + cat >&2 cargo-out.txt + exit 1 + fi +) diff --git a/quick-error/.cargo-checksum.json b/quick-error/.cargo-checksum.json new file mode 100644 index 000000000..3b29ff3d5 --- /dev/null +++ b/quick-error/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"} \ No newline at end of file diff --git a/quick-error/Cargo.toml b/quick-error/Cargo.toml new file mode 100644 index 000000000..19bc2424a --- /dev/null +++ b/quick-error/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "quick-error" +version = "1.2.2" +authors = ["Paul Colomiets <paul@colomiets.name>", "Colin Kiegel <kiegel@gmx.de>"] +description = " A macro which makes error types pleasant to write.\n" +homepage = "http://github.com/tailhook/quick-error" +documentation = "http://docs.rs/quick-error" +keywords = ["macro", "error", "type", "enum"] +categories = ["rust-patterns"] +license = "MIT/Apache-2.0" +repository = "http://github.com/tailhook/quick-error" diff --git a/quick-error/LICENSE-APACHE b/quick-error/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/quick-error/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/quick-error/LICENSE-MIT b/quick-error/LICENSE-MIT new file mode 100644 index 000000000..14f715b80 --- /dev/null +++ b/quick-error/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 The quick-error Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/quick-error/README.rst b/quick-error/README.rst new file mode 100644 index 000000000..9b934a91b --- /dev/null +++ b/quick-error/README.rst @@ -0,0 +1,69 @@ +=========== +Quick Error +=========== + +:Status: production-ready +:Documentation: http://tailhook.github.io/quick-error/ + +A macro which makes error types pleasant to write. + +Features: + +* Define enum type with arbitrary parameters +* Concise notation of ``Display`` and ``Error`` traits +* Full control of ``Display`` and ``Error`` trait implementation +* Any number of ``From`` traits +* Support for all enum-variants ``Unit``, ``Tuple`` and ``Struct`` + +Here is the comprehensive example: + +.. code-block:: rust + + quick_error! { + #[derive(Debug)] + pub enum IoWrapper { + Io(err: io::Error) { + from() + description("io error") + display("I/O error: {}", err) + cause(err) + } + Other(descr: &'static str) { + description(descr) + display("Error {}", descr) + } + IoAt { place: &'static str, err: io::Error } { + cause(err) + display(me) -> ("{} {}: {}", me.description(), place, err) + description("io error at") + from(s: String) -> { + place: "some string", + err: io::Error::new(io::ErrorKind::Other, s) + } + } + Discard { + from(&'static str) + } + } + } + +======= +License +======= + +Licensed under either of + + * Apache License, Version 2.0, (./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license (./LICENSE-MIT or http://opensource.org/licenses/MIT) + +at your option. + +------------ +Contribution +------------ + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. + diff --git a/quick-error/bulk.yaml b/quick-error/bulk.yaml new file mode 100644 index 000000000..cdb9763b6 --- /dev/null +++ b/quick-error/bulk.yaml @@ -0,0 +1,8 @@ +minimum-bulk: v0.4.5 + +versions: + +- file: Cargo.toml + block-start: ^\[package\] + block-end: ^\[.*\] + regex: ^version\s*=\s*"(\S+)" diff --git a/quick-error/examples/context.rs b/quick-error/examples/context.rs new file mode 100644 index 000000000..334700a03 --- /dev/null +++ b/quick-error/examples/context.rs @@ -0,0 +1,48 @@ +#[macro_use(quick_error)] extern crate quick_error; + +use std::io::{self, stderr, Read, Write}; +use std::fs::File; +use std::env; +use std::num::ParseIntError; +use std::path::{Path, PathBuf}; + +use quick_error::ResultExt; + +quick_error! { + #[derive(Debug)] + pub enum Error { + NoFileName { + description("no file name specified") + } + Io(err: io::Error, path: PathBuf) { + display("could not read file {:?}: {}", path, err) + context(path: &'a Path, err: io::Error) + -> (err, path.to_path_buf()) + } + Parse(err: ParseIntError, path: PathBuf) { + display("could not parse file {:?}: {}", path, err) + context(path: &'a Path, err: ParseIntError) + -> (err, path.to_path_buf()) + } + } +} + +fn parse_file() -> Result<u64, Error> { + let fname = try!(env::args().skip(1).next().ok_or(Error::NoFileName)); + let fname = Path::new(&fname); + let mut file = try!(File::open(fname).context(fname)); + let mut buf = String::new(); + try!(file.read_to_string(&mut buf).context(fname)); + Ok(try!(buf.parse().context(fname))) +} + +fn main() { + match parse_file() { + Ok(val) => { + println!("Read: {}", val); + } + Err(e) => { + writeln!(&mut stderr(), "Error: {}", e).ok(); + } + } +} diff --git a/quick-error/src/lib.rs b/quick-error/src/lib.rs new file mode 100644 index 000000000..fd95fe139 --- /dev/null +++ b/quick-error/src/lib.rs @@ -0,0 +1,1309 @@ +#![warn(missing_docs)] +//! A macro which makes errors easy to write +//! +//! Minimum type is like this: +//! +//! ```rust +//! #[macro_use] extern crate quick_error; +//! # fn main() {} +//! +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Variant1 {} +//! } +//! } +//! ``` +//! Both ``pub`` and non-public types may be declared, and all meta attributes +//! (such as ``#[derive(Debug)]``) are forwarded as is. The `Debug` must be +//! implemented (but you may do that yourself if you like). The documentation +//! comments ``/// something`` (as well as other meta attrbiutes) on variants +//! are allowed. +//! +//! # Allowed Syntax +//! +//! You may add arbitrary parameters to any struct variant: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! /// IO Error +//! Io(err: std::io::Error) {} +//! /// Utf8 Error +//! Utf8(err: std::str::Utf8Error) {} +//! } +//! } +//! ``` +//! +//! Note unlike in normal Enum declarations you declare names of fields (which +//! are omitted from type). How they can be used is outlined below. +//! +//! Now you might have noticed trailing braces `{}`. They are used to define +//! implementations. By default: +//! +//! * `Error::description()` returns variant name as static string +//! * `Error::cause()` returns None (even if type wraps some value) +//! * `Display` outputs `description()` +//! * No `From` implementations are defined +//! +//! To define description simply add `description(value)` inside braces: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Io(err: std::io::Error) { +//! description(err.description()) +//! } +//! Utf8(err: std::str::Utf8Error) { +//! description("utf8 error") +//! } +//! } +//! } +//! ``` +//! +//! Normal rules for borrowing apply. So most of the time description either +//! returns constant string or forwards description from enclosed type. +//! +//! To change `cause` method to return some error, add `cause(value)`, for +//! example: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Io(err: std::io::Error) { +//! cause(err) +//! description(err.description()) +//! } +//! Utf8(err: std::str::Utf8Error) { +//! description("utf8 error") +//! } +//! Other(err: Box<std::error::Error>) { +//! cause(&**err) +//! description(err.description()) +//! } +//! } +//! } +//! ``` +//! Note you don't need to wrap value in `Some`, its implicit. In case you want +//! `None` returned just omit the `cause`. You can't return `None` +//! conditionally. +//! +//! To change how each clause is `Display`ed add `display(pattern,..args)`, +//! for example: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Io(err: std::io::Error) { +//! display("I/O error: {}", err) +//! } +//! Utf8(err: std::str::Utf8Error) { +//! display("Utf8 error, valid up to {}", err.valid_up_to()) +//! } +//! } +//! } +//! ``` +//! +//! If you need a reference to the error when `Display`ing, you can instead use +//! `display(x) -> (pattern, ..args)`, where `x` sets the name of the reference. +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! use std::error::Error; // put methods like `description()` of this trait into scope +//! +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Io(err: std::io::Error) { +//! display(x) -> ("{}: {}", x.description(), err) +//! } +//! Utf8(err: std::str::Utf8Error) { +//! display(self_) -> ("{}, valid up to {}", self_.description(), err.valid_up_to()) +//! } +//! } +//! } +//! ``` +//! +//! To convert to the type from any other, use one of the three forms of +//! `from` clause. +//! +//! For example, to convert simple wrapper use bare `from()`: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! Io(err: std::io::Error) { +//! from() +//! } +//! } +//! } +//! ``` +//! +//! This implements ``From<io::Error>``. +//! +//! To convert to singleton enumeration type (discarding the value), use +//! the `from(type)` form: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! FormatError { +//! from(std::fmt::Error) +//! } +//! } +//! } +//! ``` +//! +//! And the most powerful form is `from(var: type) -> (arguments...)`. It +//! might be used to convert to type with multiple arguments or for arbitrary +//! value conversions: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # fn main() {} +//! # +//! quick_error! { +//! #[derive(Debug)] +//! pub enum SomeError { +//! FailedOperation(s: &'static str, errno: i32) { +//! from(errno: i32) -> ("os error", errno) +//! from(e: std::io::Error) -> ("io error", e.raw_os_error().unwrap()) +//! } +//! /// Converts from both kinds of utf8 errors +//! Utf8(err: std::str::Utf8Error) { +//! from() +//! from(err: std::string::FromUtf8Error) -> (err.utf8_error()) +//! } +//! } +//! } +//! ``` +//! # Context +//! +//! Since quick-error 1.1 we also have a `context` declaration, which is +//! similar to (the longest form of) `from`, but allows adding some context to +//! the error. We need a longer example to demonstrate this: +//! +//! ```rust +//! # #[macro_use] extern crate quick_error; +//! # use std::io; +//! # use std::fs::File; +//! # use std::path::{Path, PathBuf}; +//! # +//! use quick_error::ResultExt; +//! +//! quick_error! { +//! #[derive(Debug)] +//! pub enum Error { +//! File(filename: PathBuf, err: io::Error) { +//! context(path: &'a Path, err: io::Error) +//! -> (path.to_path_buf(), err) +//! } +//! } +//! } +//! +//! fn openfile(path: &Path) -> Result<(), Error> { +//! try!(File::open(path).context(path)); +//! +//! // If we didn't have context, the line above would be written as; +//! // +//! // try!(File::open(path) +//! // .map_err(|err| Error::File(path.to_path_buf(), err))); +//! +//! Ok(()) +//! } +//! +//! # fn main() { +//! # openfile(Path::new("/etc/somefile")).ok(); +//! # } +//! ``` +//! +//! Each `context(a: A, b: B)` clause implements +//! `From<Context<A, B>> for Error`. Which means multiple `context` clauses +//! are a subject to the normal coherence rules. Unfortunately, we can't +//! provide full support of generics for the context, but you may either use a +//! lifetime `'a` for references or `AsRef<Type>` (the latter means `A: +//! AsRef<Type>`, and `Type` must be concrete). It's also occasionally useful +//! to use a tuple as a type of the first argument. +//! +//! You also need to `use quick_error::ResultExt` extension trait to get +//! working `.context()` method. +//! +//! More info on context in [this article](http://bit.ly/1PsuxDt). +//! +//! All forms of `from`, `display`, `description`, `cause`, and `context` +//! clauses can be combined and put in arbitrary order. Only `from` and +//! `context` can be used multiple times in single variant of enumeration. +//! Docstrings are also okay. Empty braces can be omitted as of quick_error +//! 0.1.3. +//! +//! # Private Enums +//! +//! Since quick-error 1.2.0 we have a way to make a private enum that is +//! wrapped by public structure: +//! +//! ```rust +//! #[macro_use] extern crate quick_error; +//! # fn main() {} +//! +//! quick_error! { +//! #[derive(Debug)] +//! pub enum PubError wraps ErrorEnum { +//! Variant1 {} +//! } +//! } +//! ``` +//! +//! This generates data structures like this +//! +//! ```rust +//! +//! pub struct PubError(ErrorEnum); +//! +//! enum ErrorEnum { +//! Variant1, +//! } +//! +//! ``` +//! +//! Which in turn allows you to export just `PubError` in your crate and keep +//! actual enumeration private to the crate. This is useful to keep backwards +//! compatibility for error types. Currently there is no shorcuts to define +//! error constructors for the inner type, but we consider adding some in +//! future versions. +//! +//! It's possible to declare internal enum as public too. +//! +//! + + +/// Main macro that does all the work +#[macro_export] +macro_rules! quick_error { + + ( $(#[$meta:meta])* + pub enum $name:ident { $($chunks:tt)* } + ) => { + quick_error!(SORT [pub enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + ( $(#[$meta:meta])* + enum $name:ident { $($chunks:tt)* } + ) => { + quick_error!(SORT [enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + + ( $(#[$meta:meta])* + pub enum $name:ident wraps $enum_name:ident { $($chunks:tt)* } + ) => { + quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*); + quick_error!(SORT [enum $enum_name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + + ( $(#[$meta:meta])* + pub enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* } + ) => { + quick_error!(WRAPPER $enum_name [ pub struct ] $name $(#[$meta])*); + quick_error!(SORT [pub enum $enum_name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + ( $(#[$meta:meta])* + enum $name:ident wraps $enum_name:ident { $($chunks:tt)* } + ) => { + quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*); + quick_error!(SORT [enum $enum_name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + + ( $(#[$meta:meta])* + enum $name:ident wraps pub $enum_name:ident { $($chunks:tt)* } + ) => { + quick_error!(WRAPPER $enum_name [ struct ] $name $(#[$meta])*); + quick_error!(SORT [pub enum $enum_name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + + + ( + WRAPPER $internal:ident [ $($strdef:tt)* ] $strname:ident + $(#[$meta:meta])* + ) => { + $(#[$meta])* + $($strdef)* $strname ( $internal ); + + impl ::std::fmt::Display for $strname { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result + { + ::std::fmt::Display::fmt(&self.0, f) + } + } + + impl From<$internal> for $strname { + fn from(err: $internal) -> Self { + $strname(err) + } + } + + impl ::std::error::Error for $strname { + fn description(&self) -> &str { + self.0.description() + } + fn cause(&self) -> Option<&::std::error::Error> { + self.0.cause() + } + } + }; + + // Queue is empty, can do the work + (SORT [enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + quick_error!(ENUM_DEFINITION [enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + quick_error!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + quick_error!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + (SORT [pub enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + quick_error!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + quick_error!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + quick_error!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + // Add meta to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add ident to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$(#[$bmeta])* => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on meta after ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* + $(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] + items [$($( #[$imeta:meta] )* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add tuple enum-variant + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*] + ); + }; + // Add struct enum-variant - e.g. { descr: &'static str } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*]); + }; + // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*]); + }; + // Add braces and flush always on braces + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ {$( $qfuncs:tt )*} $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ] + buf [ ] + queue [$( $tail )*]); + }; + // Flush buffer on double ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on end + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ ] + ) => { + quick_error!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ ] + queue [ ]); + }; + // Public enum (Queue Empty) + (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + #[allow(unknown_lints)] // no unused_doc_comments in older rust + #[allow(renamed_and_removed_lints)] + #[allow(unused_doc_comment)] + #[allow(unused_doc_comments)] + $(#[$meta])* + pub enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, + )* + } + }; + // Private enum (Queue Empty) + (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + #[allow(unknown_lints)] // no unused_doc_comments in older rust + #[allow(renamed_and_removed_lints)] + #[allow(unused_doc_comment)] + #[allow(unused_doc_comments)] + $(#[$meta])* + enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, + )* + } + }; + // Unit variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: UNIT [ ] $( $queue:tt )*] + ) => { + quick_error!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {} ] + queue [ $($queue)* ] + ); + }; + // Tuple variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*] + ) => { + quick_error!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ] + queue [ $($queue)* ] + ); + }; + // Struct variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*] + ) => { + quick_error!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ] + queue [ $($queue)* ] + ); + }; + (IMPLEMENTATIONS + $name:ident {$( + $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} + )*} + ) => { + #[allow(unused)] + #[allow(unknown_lints)] // no unused_doc_comments in older rust + #[allow(renamed_and_removed_lints)] + #[allow(unused_doc_comment)] + #[allow(unused_doc_comments)] + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result + { + match *self { + $( + $(#[$imeta])* + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + let display_fn = quick_error!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $funcs )*}); + + display_fn(self, fmt) + } + )* + } + } + } + #[allow(unused)] + #[allow(unknown_lints)] // no unused_doc_comments in older rust + #[allow(renamed_and_removed_lints)] + #[allow(unused_doc_comment)] + #[allow(unused_doc_comments)] + impl ::std::error::Error for $name { + fn description(&self) -> &str { + match *self { + $( + $(#[$imeta])* + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + quick_error!(FIND_DESCRIPTION_IMPL + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) + } + )* + } + } + fn cause(&self) -> Option<&::std::error::Error> { + match *self { + $( + $(#[$imeta])* + quick_error!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + quick_error!(FIND_CAUSE_IMPL + $item: $imode [$( $var ),*] + {$( $funcs )*}) + } + )* + } + } + } + $( + quick_error!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $funcs )*}); + )* + $( + quick_error!(FIND_CONTEXT_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $funcs )*}); + )* + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*} + ) => { + |quick_error!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { write!(f, $( $exprs )*) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { $t:tt $( $tail:tt )*} + ) => { + quick_error!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $tail )*}) + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { } + ) => { + |self_: &$name, f: &mut ::std::fmt::Formatter| { + write!(f, "{}", ::std::error::Error::description(self_)) + } + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { description($expr:expr) $( $tail:tt )*} + ) => { + $expr + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + quick_error!(FIND_DESCRIPTION_IMPL + $item: $imode $me $fmt [$( $var ),*] + {$( $tail )*}) + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { } + ) => { + stringify!($item) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { cause($expr:expr) $( $tail:tt )*} + ) => { + Some($expr) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + quick_error!(FIND_CAUSE_IMPL + $item: $imode [$( $var ),*] + { $($tail)* }) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { } + ) => { + None + }; + // ----------------------------- FROM IMPL -------------------------- + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { from() $( $tail:tt )*} + ) => { + $( + impl From<$typ> for $name { + fn from($var: $typ) -> $name { + $name::$item($var) + } + } + )* + quick_error!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*}); + }; + (FIND_FROM_IMPL $name:ident $item:ident: UNIT + [ ] + { from($ftyp:ty) $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from(_discarded_error: $ftyp) -> $name { + $name::$item + } + } + quick_error!(FIND_FROM_IMPL + $name $item: UNIT [ ] + {$( $tail )*}); + }; + (FIND_FROM_IMPL $name:ident $item:ident: TUPLE + [$( $var:ident: $typ:ty ),*] + { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from($fvar: $ftyp) -> $name { + $name::$item($( $texpr ),*) + } + } + quick_error!(FIND_FROM_IMPL + $name $item: TUPLE [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_FROM_IMPL $name:ident $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + { from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from($fvar: $ftyp) -> $name { + $name::$item { + $( $tvar: $texpr ),* + } + } + } + quick_error!(FIND_FROM_IMPL + $name $item: STRUCT [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { $t:tt $( $tail:tt )*} + ) => { + quick_error!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*} + ); + }; + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { } + ) => { + }; + // ----------------------------- CONTEXT IMPL -------------------------- + (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE + [$( $var:ident: $typ:ty ),*] + { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty) + -> ($( $texpr:expr ),*) $( $tail:tt )* } + ) => { + impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name { + fn from( + $crate::Context($cvar, $fvar): $crate::Context<T, $ftyp>) + -> $name + { + $name::$item($( $texpr ),*) + } + } + quick_error!(FIND_CONTEXT_IMPL + $name $item: TUPLE [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_CONTEXT_IMPL $name:ident $item:ident: TUPLE + [$( $var:ident: $typ:ty ),*] + { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty) + -> ($( $texpr:expr ),*) $( $tail:tt )* } + ) => { + impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name { + fn from( + $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>) + -> $name + { + $name::$item($( $texpr ),*) + } + } + quick_error!(FIND_CONTEXT_IMPL + $name $item: TUPLE [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + { context($cvar:ident: AsRef<$ctyp:ty>, $fvar:ident: $ftyp:ty) + -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* } + ) => { + impl<T: AsRef<$ctyp>> From<$crate::Context<T, $ftyp>> for $name { + fn from( + $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>) + -> $name + { + $name::$item { + $( $tvar: $texpr ),* + } + } + } + quick_error!(FIND_CONTEXT_IMPL + $name $item: STRUCT [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_CONTEXT_IMPL $name:ident $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + { context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty) + -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )* } + ) => { + impl<'a> From<$crate::Context<$ctyp, $ftyp>> for $name { + fn from( + $crate::Context($cvar, $fvar): $crate::Context<$ctyp, $ftyp>) + -> $name + { + $name::$item { + $( $tvar: $texpr ),* + } + } + } + quick_error!(FIND_CONTEXT_IMPL + $name $item: STRUCT [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { $t:tt $( $tail:tt )*} + ) => { + quick_error!(FIND_CONTEXT_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*} + ); + }; + (FIND_CONTEXT_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { } + ) => { + }; + // ----------------------------- ITEM IMPL -------------------------- + (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT + ) => { }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE + [$( $typ:ty ),*] + ) => { + ($( $typ ),*) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + ) => { + {$( $var:$typ ),*} + }; + (ITEM_PATTERN $name:ident $item:ident: UNIT [] + ) => { + $name::$item + }; + (ITEM_PATTERN $name:ident $item:ident: TUPLE + [$( ref $var:ident ),*] + ) => { + $name::$item ($( ref $var ),*) + }; + (ITEM_PATTERN $name:ident $item:ident: STRUCT + [$( ref $var:ident ),*] + ) => { + $name::$item {$( ref $var ),*} + }; + // This one should match all allowed sequences in "funcs" but not match + // anything else. + // This is to contrast FIND_* clauses which just find stuff they need and + // skip everything else completely + (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt cause($expr:expr) $($tail:tt)*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt from() $($tail:tt)*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*) + => { quick_error!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK TUPLE $($tail)*); }; + (ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*) + => { quick_error!(ERROR_CHECK STRUCT $($tail)*); }; + + (ERROR_CHECK TUPLE context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty) + -> ($( $e:expr ),*) $( $tail:tt )*) + => { quick_error!(ERROR_CHECK TUPLE $($tail)*); }; + (ERROR_CHECK STRUCT context($cvar:ident: $ctyp:ty, $fvar:ident: $ftyp:ty) + -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*) + => { quick_error!(ERROR_CHECK STRUCT $($tail)*); }; + + (ERROR_CHECK $imode:tt ) => {}; + // Utility functions + (IDENT $ident:ident) => { $ident } +} + + +/// Generic context type +/// +/// Used mostly as a transport for `ResultExt::context` method +#[derive(Debug)] +pub struct Context<X, E>(pub X, pub E); + +/// Result extension trait adding a `context` method +pub trait ResultExt<T, E> { + /// The method is use to add context information to current operation + /// + /// The context data is then used in error constructor to store additional + /// information within error. For example, you may add a filename as a + /// context for file operation. See crate documentation for the actual + /// example. + fn context<X>(self, x: X) -> Result<T, Context<X, E>>; +} + +impl<T, E> ResultExt<T, E> for Result<T, E> { + fn context<X>(self, x: X) -> Result<T, Context<X, E>> { + self.map_err(|e| Context(x, e)) + } +} + + + +#[cfg(test)] +mod test { + use std::num::{ParseFloatError, ParseIntError}; + use std::str::Utf8Error; + use std::string::FromUtf8Error; + use std::error::Error; + use std::path::{Path, PathBuf}; + + use super::ResultExt; + + quick_error! { + #[derive(Debug)] + pub enum Bare { + One + Two + } + } + + #[test] + fn bare_item_direct() { + assert_eq!(format!("{}", Bare::One), "One".to_string()); + assert_eq!(format!("{:?}", Bare::One), "One".to_string()); + assert_eq!(Bare::One.description(), "One".to_string()); + assert!(Bare::One.cause().is_none()); + } + #[test] + fn bare_item_trait() { + let err: &Error = &Bare::Two; + assert_eq!(format!("{}", err), "Two".to_string()); + assert_eq!(format!("{:?}", err), "Two".to_string()); + assert_eq!(err.description(), "Two".to_string()); + assert!(err.cause().is_none()); + } + + quick_error! { + #[derive(Debug)] + pub enum Wrapper wraps Wrapped { + One + Two(s: String) { + display("two: {}", s) + from() + } + } + } + + #[test] + fn wrapper() { + assert_eq!(format!("{}", Wrapper::from(Wrapped::One)), + "One".to_string()); + assert_eq!(format!("{}", + Wrapper::from(Wrapped::from(String::from("hello")))), + "two: hello".to_string()); + assert_eq!(format!("{:?}", Wrapper::from(Wrapped::One)), + "Wrapper(One)".to_string()); + assert_eq!(Wrapper::from(Wrapped::One).description(), + "One".to_string()); + } + + quick_error! { + #[derive(Debug, PartialEq)] + pub enum TupleWrapper { + /// ParseFloat Error + ParseFloatError(err: ParseFloatError) { + from() + description(err.description()) + display("parse float error: {err}", err=err) + cause(err) + } + Other(descr: &'static str) { + description(descr) + display("Error: {}", descr) + } + /// FromUtf8 Error + FromUtf8Error(err: Utf8Error, source: Vec<u8>) { + cause(err) + display(me) -> ("{desc} at index {pos}: {err}", desc=me.description(), pos=err.valid_up_to(), err=err) + description("utf8 error") + from(err: FromUtf8Error) -> (err.utf8_error().clone(), err.into_bytes()) + } + Discard { + from(&'static str) + } + Singleton { + display("Just a string") + } + } + } + + #[test] + fn tuple_wrapper_err() { + let cause = "one and a half times pi".parse::<f32>().unwrap_err(); + let err = TupleWrapper::ParseFloatError(cause.clone()); + assert_eq!(format!("{}", err), format!("parse float error: {}", cause)); + assert_eq!(format!("{:?}", err), format!("ParseFloatError({:?})", cause)); + assert_eq!(err.description(), cause.description()); + assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause)); + } + + #[test] + fn tuple_wrapper_trait_str() { + let desc = "hello"; + let err: &Error = &TupleWrapper::Other(desc); + assert_eq!(format!("{}", err), format!("Error: {}", desc)); + assert_eq!(format!("{:?}", err), format!("Other({:?})", desc)); + assert_eq!(err.description(), desc); + assert!(err.cause().is_none()); + } + + #[test] + fn tuple_wrapper_trait_two_fields() { + let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err: &Error = &TupleWrapper::FromUtf8Error(cause.clone(), invalid_utf8.clone()); + assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc=err.description(), pos=cause.valid_up_to(), cause=cause)); + assert_eq!(format!("{:?}", err), format!("FromUtf8Error({:?}, {:?})", cause, invalid_utf8)); + assert_eq!(err.description(), "utf8 error"); + assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause)); + } + + #[test] + fn tuple_wrapper_from() { + let cause = "one and a half times pi".parse::<f32>().unwrap_err(); + let err = TupleWrapper::ParseFloatError(cause.clone()); + let err_from: TupleWrapper = From::from(cause); + assert_eq!(err_from, err); + } + + #[test] + fn tuple_wrapper_custom_from() { + let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err(); + let err = TupleWrapper::FromUtf8Error(cause.utf8_error().clone(), invalid_utf8); + let err_from: TupleWrapper = From::from(cause); + assert_eq!(err_from, err); + } + + #[test] + fn tuple_wrapper_discard() { + let err: TupleWrapper = From::from("hello"); + assert_eq!(format!("{}", err), format!("Discard")); + assert_eq!(format!("{:?}", err), format!("Discard")); + assert_eq!(err.description(), "Discard"); + assert!(err.cause().is_none()); + } + + #[test] + fn tuple_wrapper_singleton() { + let err: TupleWrapper = TupleWrapper::Singleton; + assert_eq!(format!("{}", err), format!("Just a string")); + assert_eq!(format!("{:?}", err), format!("Singleton")); + assert_eq!(err.description(), "Singleton"); + assert!(err.cause().is_none()); + } + + quick_error! { + #[derive(Debug, PartialEq)] + pub enum StructWrapper { + // Utf8 Error + Utf8Error{ err: Utf8Error, hint: Option<&'static str> } { + cause(err) + display(me) -> ("{desc} at index {pos}: {err}", desc=me.description(), pos=err.valid_up_to(), err=err) + description("utf8 error") + from(err: Utf8Error) -> { err: err, hint: None } + } + // Utf8 Error + ExcessComma { descr: &'static str, } { + description(descr) + display("Error: {}", descr) + } + } + } + + #[test] + fn struct_wrapper_err() { + let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err: &Error = &StructWrapper::Utf8Error{ err: cause.clone(), hint: Some("nonsense") }; + assert_eq!(format!("{}", err), format!("{desc} at index {pos}: {cause}", desc=err.description(), pos=cause.valid_up_to(), cause=cause)); + assert_eq!(format!("{:?}", err), format!("Utf8Error {{ err: {:?}, hint: {:?} }}", cause, Some("nonsense"))); + assert_eq!(err.description(), "utf8 error"); + assert_eq!(format!("{:?}", err.cause().unwrap()), format!("{:?}", cause)); + } + + #[test] + fn struct_wrapper_struct_from() { + let invalid_utf8: Vec<u8> = vec![0, 159, 146, 150]; + let cause = String::from_utf8(invalid_utf8.clone()).unwrap_err().utf8_error(); + let err = StructWrapper::Utf8Error{ err: cause.clone(), hint: None }; + let err_from: StructWrapper = From::from(cause); + assert_eq!(err_from, err); + } + + #[test] + fn struct_wrapper_excess_comma() { + let descr = "hello"; + let err = StructWrapper::ExcessComma { descr: descr }; + assert_eq!(format!("{}", err), format!("Error: {}", descr)); + assert_eq!(format!("{:?}", err), format!("ExcessComma {{ descr: {:?} }}", descr)); + assert_eq!(err.description(), descr); + assert!(err.cause().is_none()); + } + + quick_error! { + #[derive(Debug)] + pub enum ContextErr { + Float(src: String, err: ParseFloatError) { + context(s: &'a str, e: ParseFloatError) -> (s.to_string(), e) + display("Float error {:?}: {}", src, err) + } + Int { src: String, err: ParseIntError } { + context(s: &'a str, e: ParseIntError) + -> {src: s.to_string(), err: e} + display("Int error {:?}: {}", src, err) + } + Utf8(path: PathBuf, err: Utf8Error) { + context(p: AsRef<Path>, e: Utf8Error) + -> (p.as_ref().to_path_buf(), e) + display("Path error at {:?}: {}", path, err) + } + Utf8Str(s: String, err: ::std::io::Error) { + context(s: AsRef<str>, e: ::std::io::Error) + -> (s.as_ref().to_string(), e) + display("Str error {:?}: {}", s, err) + } + } + } + + #[test] + fn parse_float_error() { + fn parse_float(s: &str) -> Result<f32, ContextErr> { + Ok(try!(s.parse().context(s))) + } + assert_eq!(format!("{}", parse_float("12ab").unwrap_err()), + r#"Float error "12ab": invalid float literal"#); + } + + #[test] + fn parse_int_error() { + fn parse_int(s: &str) -> Result<i32, ContextErr> { + Ok(try!(s.parse().context(s))) + } + assert_eq!(format!("{}", parse_int("12.5").unwrap_err()), + r#"Int error "12.5": invalid digit found in string"#); + } + + #[test] + fn debug_context() { + fn parse_int(s: &str) -> i32 { + s.parse().context(s).unwrap() + } + assert_eq!(parse_int("12"), 12); + assert_eq!(format!("{:?}", "x".parse::<i32>().context("x")), + r#"Err(Context("x", ParseIntError { kind: InvalidDigit }))"#); + } + + #[test] + fn path_context() { + fn parse_utf<P: AsRef<Path>>(s: &[u8], p: P) + -> Result<(), ContextErr> + { + try!(::std::str::from_utf8(s).context(p)); + Ok(()) + } + let etext = parse_utf(b"a\x80\x80", "/etc").unwrap_err().to_string(); + assert!(etext.starts_with( + "Path error at \"/etc\": invalid utf-8")); + let etext = parse_utf(b"\x80\x80", PathBuf::from("/tmp")).unwrap_err() + .to_string(); + assert!(etext.starts_with( + "Path error at \"/tmp\": invalid utf-8")); + } + + #[test] + fn conditional_compilation() { + quick_error! { + #[allow(dead_code)] + #[derive(Debug)] + pub enum Test { + #[cfg(feature = "foo")] + Variant + } + } + } +} diff --git a/quick-error/vagga.yaml b/quick-error/vagga.yaml new file mode 100644 index 000000000..71b9be44e --- /dev/null +++ b/quick-error/vagga.yaml @@ -0,0 +1,36 @@ +commands: + + cargo: !Command + description: Run any cargo command + container: ubuntu + run: [cargo] + + test: !Command + description: Run unit tests + container: ubuntu + run: [cargo, test] + + _bulk: !Command + description: Run `bulk` command (for version bookkeeping) + container: ubuntu + run: [bulk] + +containers: + + ubuntu: + setup: + - !Ubuntu xenial + - !Install [ca-certificates, build-essential, vim] + + - !TarInstall + url: "https://static.rust-lang.org/dist/rust-1.16.0-x86_64-unknown-linux-gnu.tar.gz" + script: "./install.sh --prefix=/usr \ + --components=rustc,rust-std-x86_64-unknown-linux-gnu,cargo" + - &bulk !Tar + url: "https://github.com/tailhook/bulk/releases/download/v0.4.9/bulk-v0.4.9.tar.gz" + sha256: 23471a9986274bb4b7098c03e2eb7e1204171869b72c45385fcee1c64db2d111 + path: / + + environ: + HOME: /work/target + USER: pc diff --git a/quote/.cargo-checksum.json b/quote/.cargo-checksum.json new file mode 100644 index 000000000..d29006069 --- /dev/null +++ b/quote/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"} \ No newline at end of file diff --git a/quote/Cargo.toml b/quote/Cargo.toml new file mode 100644 index 000000000..02a98955d --- /dev/null +++ b/quote/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "quote" +version = "0.6.12" +authors = ["David Tolnay <dtolnay@gmail.com>"] +include = ["Cargo.toml", "src/**/*.rs", "tests/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +description = "Quasi-quoting macro quote!(...)" +documentation = "https://docs.rs/quote/" +readme = "README.md" +keywords = ["syn"] +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT/Apache-2.0" +repository = "https://github.com/dtolnay/quote" +[dependencies.proc-macro2] +version = "0.4.21" +default-features = false + +[features] +default = ["proc-macro"] +proc-macro = ["proc-macro2/proc-macro"] +[badges.travis-ci] +repository = "dtolnay/quote" diff --git a/quote/LICENSE-APACHE b/quote/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/quote/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/quote/LICENSE-MIT b/quote/LICENSE-MIT new file mode 100644 index 000000000..40b8817a4 --- /dev/null +++ b/quote/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/quote/README.md b/quote/README.md new file mode 100644 index 000000000..759916ace --- /dev/null +++ b/quote/README.md @@ -0,0 +1,241 @@ +Rust Quasi-Quoting +================== + +[![Build Status](https://api.travis-ci.org/dtolnay/quote.svg?branch=master)](https://travis-ci.org/dtolnay/quote) +[![Latest Version](https://img.shields.io/crates/v/quote.svg)](https://crates.io/crates/quote) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/quote/) + +This crate provides the [`quote!`] macro for turning Rust syntax tree data +structures into tokens of source code. + +[`quote!`]: https://docs.rs/quote/0.6/quote/macro.quote.html + +Procedural macros in Rust receive a stream of tokens as input, execute arbitrary +Rust code to determine how to manipulate those tokens, and produce a stream of +tokens to hand back to the compiler to compile into the caller's crate. +Quasi-quoting is a solution to one piece of that -- producing tokens to return +to the compiler. + +The idea of quasi-quoting is that we write *code* that we treat as *data*. +Within the `quote!` macro, we can write what looks like code to our text editor +or IDE. We get all the benefits of the editor's brace matching, syntax +highlighting, indentation, and maybe autocompletion. But rather than compiling +that as code into the current crate, we can treat it as data, pass it around, +mutate it, and eventually hand it back to the compiler as tokens to compile into +the macro caller's crate. + +This crate is motivated by the procedural macro use case, but is a +general-purpose Rust quasi-quoting library and is not specific to procedural +macros. + +*Version requirement: Quote supports any compiler version back to Rust's very +first support for procedural macros in Rust 1.15.0.* + +[*Release notes*](https://github.com/dtolnay/quote/releases) + +```toml +[dependencies] +quote = "0.6" +``` + +## Syntax + +The quote crate provides a [`quote!`] macro within which you can write Rust code +that gets packaged into a [`TokenStream`] and can be treated as data. You should +think of `TokenStream` as representing a fragment of Rust source code. + +[`TokenStream`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.TokenStream.html + +Within the `quote!` macro, interpolation is done with `#var`. Any type +implementing the [`quote::ToTokens`] trait can be interpolated. This includes +most Rust primitive types as well as most of the syntax tree types from [`syn`]. + +[`quote::ToTokens`]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +[`syn`]: https://github.com/dtolnay/syn + +```rust +let tokens = quote! { + struct SerializeWith #generics #where_clause { + value: &'a #field_ty, + phantom: core::marker::PhantomData<#item_ty>, + } + + impl #generics serde::Serialize for SerializeWith #generics #where_clause { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + #path(self.value, serializer) + } + } + + SerializeWith { + value: #value, + phantom: core::marker::PhantomData::<#item_ty>, + } +}; +``` + +## Repetition + +Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This +iterates through the elements of any variable interpolated within the repetition +and inserts a copy of the repetition body for each one. The variables in an +interpolation may be anything that implements `IntoIterator`, including `Vec` or +a pre-existing iterator. + +- `#(#var)*` — no separators +- `#(#var),*` — the character before the asterisk is used as a separator +- `#( struct #var; )*` — the repetition can contain other things +- `#( #k => println!("{}", #v), )*` — even multiple interpolations + +Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter +does not produce a trailing comma. This matches the behavior of delimiters in +`macro_rules!`. + +## Returning tokens to the compiler + +The `quote!` macro evaluates to an expression of type +`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to +return the type `proc_macro::TokenStream`. + +The difference between the two types is that `proc_macro` types are entirely +specific to procedural macros and cannot ever exist in code outside of a +procedural macro, while `proc_macro2` types may exist anywhere including tests +and non-macro code like main.rs and build.rs. This is why even the procedural +macro ecosystem is largely built around `proc_macro2`, because that ensures the +libraries are unit testable and accessible in non-macro contexts. + +There is a [`From`]-conversion in both directions so returning the output of +`quote!` from a procedural macro usually looks like `tokens.into()` or +`proc_macro::TokenStream::from(tokens)`. + +[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html + +## Examples + +### Combining quoted fragments + +Usually you don't end up constructing an entire final `TokenStream` in one +piece. Different parts may come from different helper functions. The tokens +produced by `quote!` themselves implement `ToTokens` and so can be interpolated +into later `quote!` invocations to build up a final result. + +```rust +let type_definition = quote! {...}; +let methods = quote! {...}; + +let tokens = quote! { + #type_definition + #methods +}; +``` + +### Constructing identifiers + +Suppose we have an identifier `ident` which came from somewhere in a macro +input and we need to modify it in some way for the macro output. Let's consider +prepending the identifier with an underscore. + +Simply interpolating the identifier next to an underscore will not have the +behavior of concatenating them. The underscore and the identifier will continue +to be two separate tokens as if you had written `_ x`. + +```rust +// incorrect +quote! { + let mut _#ident = 0; +} +``` + +The solution is to perform token-level manipulations using the APIs provided by +Syn and proc-macro2. + +```rust +let concatenated = format!("_{}", ident); +let varname = syn::Ident::new(&concatenated, ident.span()); +quote! { + let mut #varname = 0; +} +``` + +### Making method calls + +Let's say our macro requires some type specified in the macro input to have a +constructor called `new`. We have the type in a variable called `field_type` of +type `syn::Type` and want to invoke the constructor. + +```rust +// incorrect +quote! { + let value = #field_type::new(); +} +``` + +This works only sometimes. If `field_type` is `String`, the expanded code +contains `String::new()` which is fine. But if `field_type` is something like +`Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid syntax. +Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` but for macros +often the following is more convenient. + +```rust +quote! { + let value = <#field_type>::new(); +} +``` + +This expands to `<Vec<i32>>::new()` which behaves correctly. + +A similar pattern is appropriate for trait methods. + +```rust +quote! { + let value = <#field_type as core::default::Default>::default(); +} +``` + +## Hygiene + +Any interpolated tokens preserve the `Span` information provided by their +`ToTokens` implementation. Tokens that originate within a `quote!` invocation +are spanned with [`Span::call_site()`]. + +[`Span::call_site()`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.call_site + +A different span can be provided explicitly through the [`quote_spanned!`] +macro. + +[`quote_spanned!`]: https://docs.rs/quote/0.6/quote/macro.quote_spanned.html + +### Limitations + +- A non-repeating variable may not be interpolated inside of a repeating block + ([#7]). +- The same variable may not be interpolated more than once inside of a repeating + block ([#8]). + +[#7]: https://github.com/dtolnay/quote/issues/7 +[#8]: https://github.com/dtolnay/quote/issues/8 + +### Recursion limit + +The `quote!` macro relies on deep recursion so some large invocations may fail +with "recursion limit reached" when you compile. If it fails, bump up the +recursion limit by adding `#![recursion_limit = "128"]` to your crate. An even +higher limit may be necessary for especially large invocations. You don't need +this unless the compiler tells you that you need it. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/quote/src/ext.rs b/quote/src/ext.rs new file mode 100644 index 000000000..7ebbe30a1 --- /dev/null +++ b/quote/src/ext.rs @@ -0,0 +1,112 @@ +use super::ToTokens; + +use std::iter; + +use proc_macro2::{TokenStream, TokenTree}; + +/// TokenStream extension trait with methods for appending tokens. +/// +/// This trait is sealed and cannot be implemented outside of the `quote` crate. +pub trait TokenStreamExt: private::Sealed { + /// For use by `ToTokens` implementations. + /// + /// Appends the token specified to this list of tokens. + fn append<U>(&mut self, token: U) + where + U: Into<TokenTree>; + + /// For use by `ToTokens` implementations. + /// + /// ```edition2018 + /// # use quote::{quote, TokenStreamExt, ToTokens}; + /// # use proc_macro2::TokenStream; + /// # + /// struct X; + /// + /// impl ToTokens for X { + /// fn to_tokens(&self, tokens: &mut TokenStream) { + /// tokens.append_all(&[true, false]); + /// } + /// } + /// + /// let tokens = quote!(#X); + /// assert_eq!(tokens.to_string(), "true false"); + /// ``` + fn append_all<T, I>(&mut self, iter: I) + where + T: ToTokens, + I: IntoIterator<Item = T>; + + /// For use by `ToTokens` implementations. + /// + /// Appends all of the items in the iterator `I`, separated by the tokens + /// `U`. + fn append_separated<T, I, U>(&mut self, iter: I, op: U) + where + T: ToTokens, + I: IntoIterator<Item = T>, + U: ToTokens; + + /// For use by `ToTokens` implementations. + /// + /// Appends all tokens in the iterator `I`, appending `U` after each + /// element, including after the last element of the iterator. + fn append_terminated<T, I, U>(&mut self, iter: I, term: U) + where + T: ToTokens, + I: IntoIterator<Item = T>, + U: ToTokens; +} + +impl TokenStreamExt for TokenStream { + fn append<U>(&mut self, token: U) + where + U: Into<TokenTree>, + { + self.extend(iter::once(token.into())); + } + + fn append_all<T, I>(&mut self, iter: I) + where + T: ToTokens, + I: IntoIterator<Item = T>, + { + for token in iter { + token.to_tokens(self); + } + } + + fn append_separated<T, I, U>(&mut self, iter: I, op: U) + where + T: ToTokens, + I: IntoIterator<Item = T>, + U: ToTokens, + { + for (i, token) in iter.into_iter().enumerate() { + if i > 0 { + op.to_tokens(self); + } + token.to_tokens(self); + } + } + + fn append_terminated<T, I, U>(&mut self, iter: I, term: U) + where + T: ToTokens, + I: IntoIterator<Item = T>, + U: ToTokens, + { + for token in iter { + token.to_tokens(self); + term.to_tokens(self); + } + } +} + +mod private { + use proc_macro2::TokenStream; + + pub trait Sealed {} + + impl Sealed for TokenStream {} +} diff --git a/quote/src/lib.rs b/quote/src/lib.rs new file mode 100644 index 000000000..a71d8af4c --- /dev/null +++ b/quote/src/lib.rs @@ -0,0 +1,861 @@ +//! This crate provides the [`quote!`] macro for turning Rust syntax tree data +//! structures into tokens of source code. +//! +//! [`quote!`]: macro.quote.html +//! +//! Procedural macros in Rust receive a stream of tokens as input, execute +//! arbitrary Rust code to determine how to manipulate those tokens, and produce +//! a stream of tokens to hand back to the compiler to compile into the caller's +//! crate. Quasi-quoting is a solution to one piece of that -- producing tokens +//! to return to the compiler. +//! +//! The idea of quasi-quoting is that we write *code* that we treat as *data*. +//! Within the `quote!` macro, we can write what looks like code to our text +//! editor or IDE. We get all the benefits of the editor's brace matching, +//! syntax highlighting, indentation, and maybe autocompletion. But rather than +//! compiling that as code into the current crate, we can treat it as data, pass +//! it around, mutate it, and eventually hand it back to the compiler as tokens +//! to compile into the macro caller's crate. +//! +//! This crate is motivated by the procedural macro use case, but is a +//! general-purpose Rust quasi-quoting library and is not specific to procedural +//! macros. +//! +//! *Version requirement: Quote supports any compiler version back to Rust's +//! very first support for procedural macros in Rust 1.15.0.* +//! +//! ```toml +//! [dependencies] +//! quote = "0.6" +//! ``` +//! +//! # Example +//! +//! The following quasi-quoted block of code is something you might find in [a] +//! procedural macro having to do with data structure serialization. The `#var` +//! syntax performs interpolation of runtime variables into the quoted tokens. +//! Check out the documentation of the [`quote!`] macro for more detail about +//! the syntax. See also the [`quote_spanned!`] macro which is important for +//! implementing hygienic procedural macros. +//! +//! [a]: https://serde.rs/ +//! [`quote_spanned!`]: macro.quote_spanned.html +//! +//! ```edition2018 +//! # use quote::quote; +//! # +//! # let generics = ""; +//! # let where_clause = ""; +//! # let field_ty = ""; +//! # let item_ty = ""; +//! # let path = ""; +//! # let value = ""; +//! # +//! let tokens = quote! { +//! struct SerializeWith #generics #where_clause { +//! value: &'a #field_ty, +//! phantom: core::marker::PhantomData<#item_ty>, +//! } +//! +//! impl #generics serde::Serialize for SerializeWith #generics #where_clause { +//! fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +//! where +//! S: serde::Serializer, +//! { +//! #path(self.value, serializer) +//! } +//! } +//! +//! SerializeWith { +//! value: #value, +//! phantom: core::marker::PhantomData::<#item_ty>, +//! } +//! }; +//! ``` +//! +//! # Recursion limit +//! +//! The `quote!` macro relies on deep recursion so some large invocations may +//! fail with "recursion limit reached" when you compile. If it fails, bump up +//! the recursion limit by adding `#![recursion_limit = "128"]` to your crate. +//! An even higher limit may be necessary for especially large invocations. + +// Quote types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/quote/0.6.12")] + +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" +))] +extern crate proc_macro; +extern crate proc_macro2; + +mod ext; +pub use ext::TokenStreamExt; + +mod to_tokens; +pub use to_tokens::ToTokens; + +// Not public API. +#[doc(hidden)] +#[path = "runtime.rs"] +pub mod __rt; + +/// The whole point. +/// +/// Performs variable interpolation against the input and produces it as +/// [`TokenStream`]. For returning tokens to the compiler in a procedural macro, use +/// `into()` to build a `TokenStream`. +/// +/// [`TokenStream`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.TokenStream.html +/// +/// # Interpolation +/// +/// Variable interpolation is done with `#var` (similar to `$var` in +/// `macro_rules!` macros). This grabs the `var` variable that is currently in +/// scope and inserts it in that location in the output tokens. Any type +/// implementing the [`ToTokens`] trait can be interpolated. This includes most +/// Rust primitive types as well as most of the syntax tree types from the [Syn] +/// crate. +/// +/// [`ToTokens`]: trait.ToTokens.html +/// [Syn]: https://github.com/dtolnay/syn +/// +/// Repetition is done using `#(...)*` or `#(...),*` again similar to +/// `macro_rules!`. This iterates through the elements of any variable +/// interpolated within the repetition and inserts a copy of the repetition body +/// for each one. The variables in an interpolation may be anything that +/// implements `IntoIterator`, including `Vec` or a pre-existing iterator. +/// +/// - `#(#var)*` — no separators +/// - `#(#var),*` — the character before the asterisk is used as a separator +/// - `#( struct #var; )*` — the repetition can contain other tokens +/// - `#( #k => println!("{}", #v), )*` — even multiple interpolations +/// +/// There are two limitations around interpolations in a repetition: +/// +/// - Every interpolation inside of a repetition must be a distinct variable. +/// That is, `#(#a #a)*` is not allowed. Work around this by collecting `a` +/// into a vector and taking references `a1 = &a` and `a2 = &a` which you use +/// inside the repetition: `#(#a1 #a2)*`. Where possible, use meaningful names +/// that indicate the distinct role of each copy. +/// +/// - Every interpolation inside of a repetition must be iterable. If we have +/// `vec` which is a vector and `ident` which is a single identifier, +/// `#(#ident #vec)*` is not allowed. Work around this by using +/// `std::iter::repeat(ident)` to produce an iterable that can be used from +/// within the repetition. +/// +/// # Hygiene +/// +/// Any interpolated tokens preserve the `Span` information provided by their +/// `ToTokens` implementation. Tokens that originate within the `quote!` +/// invocation are spanned with [`Span::call_site()`]. +/// +/// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.call_site +/// +/// A different span can be provided through the [`quote_spanned!`] macro. +/// +/// [`quote_spanned!`]: macro.quote_spanned.html +/// +/// # Return type +/// +/// The macro evaluates to an expression of type `proc_macro2::TokenStream`. +/// Meanwhile Rust procedural macros are expected to return the type +/// `proc_macro::TokenStream`. +/// +/// The difference between the two types is that `proc_macro` types are entirely +/// specific to procedural macros and cannot ever exist in code outside of a +/// procedural macro, while `proc_macro2` types may exist anywhere including +/// tests and non-macro code like main.rs and build.rs. This is why even the +/// procedural macro ecosystem is largely built around `proc_macro2`, because +/// that ensures the libraries are unit testable and accessible in non-macro +/// contexts. +/// +/// There is a [`From`]-conversion in both directions so returning the output of +/// `quote!` from a procedural macro usually looks like `tokens.into()` or +/// `proc_macro::TokenStream::from(tokens)`. +/// +/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +/// +/// # Examples +/// +/// ## Procedural macro +/// +/// The structure of a basic procedural macro is as follows. Refer to the [Syn] +/// crate for further useful guidance on using `quote!` as part of a procedural +/// macro. +/// +/// [Syn]: https://github.com/dtolnay/syn +/// +/// ```edition2018 +/// # #[cfg(any())] +/// extern crate proc_macro; +/// # use proc_macro2 as proc_macro; +/// +/// use proc_macro::TokenStream; +/// use quote::quote; +/// +/// # const IGNORE_TOKENS: &'static str = stringify! { +/// #[proc_macro_derive(HeapSize)] +/// # }; +/// pub fn derive_heap_size(input: TokenStream) -> TokenStream { +/// // Parse the input and figure out what implementation to generate... +/// # const IGNORE_TOKENS: &'static str = stringify! { +/// let name = /* ... */; +/// let expr = /* ... */; +/// # }; +/// # +/// # let name = 0; +/// # let expr = 0; +/// +/// let expanded = quote! { +/// // The generated impl. +/// impl heapsize::HeapSize for #name { +/// fn heap_size_of_children(&self) -> usize { +/// #expr +/// } +/// } +/// }; +/// +/// // Hand the output tokens back to the compiler. +/// TokenStream::from(expanded) +/// } +/// ``` +/// +/// ## Combining quoted fragments +/// +/// Usually you don't end up constructing an entire final `TokenStream` in one +/// piece. Different parts may come from different helper functions. The tokens +/// produced by `quote!` themselves implement `ToTokens` and so can be +/// interpolated into later `quote!` invocations to build up a final result. +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// let type_definition = quote! {...}; +/// let methods = quote! {...}; +/// +/// let tokens = quote! { +/// #type_definition +/// #methods +/// }; +/// ``` +/// +/// ## Constructing identifiers +/// +/// Suppose we have an identifier `ident` which came from somewhere in a macro +/// input and we need to modify it in some way for the macro output. Let's +/// consider prepending the identifier with an underscore. +/// +/// Simply interpolating the identifier next to an underscore will not have the +/// behavior of concatenating them. The underscore and the identifier will +/// continue to be two separate tokens as if you had written `_ x`. +/// +/// ```edition2018 +/// # use proc_macro2::{self as syn, Span}; +/// # use quote::quote; +/// # +/// # let ident = syn::Ident::new("i", Span::call_site()); +/// # +/// // incorrect +/// quote! { +/// let mut _#ident = 0; +/// } +/// # ; +/// ``` +/// +/// The solution is to perform token-level manipulations using the APIs provided +/// by Syn and proc-macro2. +/// +/// ```edition2018 +/// # use proc_macro2::{self as syn, Span}; +/// # use quote::quote; +/// # +/// # let ident = syn::Ident::new("i", Span::call_site()); +/// # +/// let concatenated = format!("_{}", ident); +/// let varname = syn::Ident::new(&concatenated, ident.span()); +/// quote! { +/// let mut #varname = 0; +/// } +/// # ; +/// ``` +/// +/// ## Making method calls +/// +/// Let's say our macro requires some type specified in the macro input to have +/// a constructor called `new`. We have the type in a variable called +/// `field_type` of type `syn::Type` and want to invoke the constructor. +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// # let field_type = quote!(...); +/// # +/// // incorrect +/// quote! { +/// let value = #field_type::new(); +/// } +/// # ; +/// ``` +/// +/// This works only sometimes. If `field_type` is `String`, the expanded code +/// contains `String::new()` which is fine. But if `field_type` is something +/// like `Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid +/// syntax. Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` +/// but for macros often the following is more convenient. +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// # let field_type = quote!(...); +/// # +/// quote! { +/// let value = <#field_type>::new(); +/// } +/// # ; +/// ``` +/// +/// This expands to `<Vec<i32>>::new()` which behaves correctly. +/// +/// A similar pattern is appropriate for trait methods. +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// # let field_type = quote!(...); +/// # +/// quote! { +/// let value = <#field_type as core::default::Default>::default(); +/// } +/// # ; +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! quote { + ($($tt:tt)*) => { + quote_spanned!($crate::__rt::Span::call_site()=> $($tt)*) + }; +} + +/// Same as `quote!`, but applies a given span to all tokens originating within +/// the macro invocation. +/// +/// # Syntax +/// +/// A span expression of type [`Span`], followed by `=>`, followed by the tokens +/// to quote. The span expression should be brief -- use a variable for anything +/// more than a few characters. There should be no space before the `=>` token. +/// +/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html +/// +/// ```edition2018 +/// # use proc_macro2::Span; +/// # use quote::quote_spanned; +/// # +/// # const IGNORE_TOKENS: &'static str = stringify! { +/// let span = /* ... */; +/// # }; +/// # let span = Span::call_site(); +/// # let init = 0; +/// +/// // On one line, use parentheses. +/// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init))); +/// +/// // On multiple lines, place the span at the top and use braces. +/// let tokens = quote_spanned! {span=> +/// Box::into_raw(Box::new(#init)) +/// }; +/// ``` +/// +/// The lack of space before the `=>` should look jarring to Rust programmers +/// and this is intentional. The formatting is designed to be visibly +/// off-balance and draw the eye a particular way, due to the span expression +/// being evaluated in the context of the procedural macro and the remaining +/// tokens being evaluated in the generated code. +/// +/// # Hygiene +/// +/// Any interpolated tokens preserve the `Span` information provided by their +/// `ToTokens` implementation. Tokens that originate within the `quote_spanned!` +/// invocation are spanned with the given span argument. +/// +/// # Example +/// +/// The following procedural macro code uses `quote_spanned!` to assert that a +/// particular Rust type implements the [`Sync`] trait so that references can be +/// safely shared between threads. +/// +/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +/// +/// ```edition2018 +/// # use quote::{quote_spanned, TokenStreamExt, ToTokens}; +/// # use proc_macro2::{Span, TokenStream}; +/// # +/// # struct Type; +/// # +/// # impl Type { +/// # fn span(&self) -> Span { +/// # Span::call_site() +/// # } +/// # } +/// # +/// # impl ToTokens for Type { +/// # fn to_tokens(&self, _tokens: &mut TokenStream) {} +/// # } +/// # +/// # let ty = Type; +/// # let call_site = Span::call_site(); +/// # +/// let ty_span = ty.span(); +/// let assert_sync = quote_spanned! {ty_span=> +/// struct _AssertSync where #ty: Sync; +/// }; +/// ``` +/// +/// If the assertion fails, the user will see an error like the following. The +/// input span of their type is hightlighted in the error. +/// +/// ```text +/// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied +/// --> src/main.rs:10:21 +/// | +/// 10 | static ref PTR: *const () = &(); +/// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely +/// ``` +/// +/// In this example it is important for the where-clause to be spanned with the +/// line/column information of the user's input type so that error messages are +/// placed appropriately by the compiler. But it is also incredibly important +/// that `Sync` resolves at the macro definition site and not the macro call +/// site. If we resolve `Sync` at the same span that the user's type is going to +/// be resolved, then they could bypass our check by defining their own trait +/// named `Sync` that is implemented for their type. +#[macro_export(local_inner_macros)] +macro_rules! quote_spanned { + ($span:expr=> $($tt:tt)*) => {{ + let mut _s = $crate::__rt::TokenStream::new(); + let _span = $span; + quote_each_token!(_s _span $($tt)*); + _s + }}; +} + +// Extract the names of all #metavariables and pass them to the $finish macro. +// +// in: pounded_var_names!(then () a #b c #( #d )* #e) +// out: then!(() b d e) +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! pounded_var_names { + ($finish:ident ($($found:ident)*) # ( $($inner:tt)* ) $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) # [ $($inner:tt)* ] $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) # { $($inner:tt)* } $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) # $first:ident $($rest:tt)*) => { + pounded_var_names!($finish ($($found)* $first) $($rest)*) + }; + + ($finish:ident ($($found:ident)*) ( $($inner:tt)* ) $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) [ $($inner:tt)* ] $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) { $($inner:tt)* } $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) + }; + + ($finish:ident ($($found:ident)*) $ignore:tt $($rest:tt)*) => { + pounded_var_names!($finish ($($found)*) $($rest)*) + }; + + ($finish:ident ($($found:ident)*)) => { + $finish!(() $($found)*) + }; +} + +// in: nested_tuples_pat!(() a b c d e) +// out: ((((a b) c) d) e) +// +// in: nested_tuples_pat!(() a) +// out: a +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! nested_tuples_pat { + (()) => { + &() + }; + + (() $first:ident $($rest:ident)*) => { + nested_tuples_pat!(($first) $($rest)*) + }; + + (($pat:pat) $first:ident $($rest:ident)*) => { + nested_tuples_pat!((($pat, $first)) $($rest)*) + }; + + (($done:pat)) => { + $done + }; +} + +// in: multi_zip_expr!(() a b c d e) +// out: a.into_iter().zip(b).zip(c).zip(d).zip(e) +// +// in: multi_zip_iter!(() a) +// out: a +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! multi_zip_expr { + (()) => { + &[] + }; + + (() $single:ident) => { + $single + }; + + (() $first:ident $($rest:ident)*) => { + multi_zip_expr!(($first.into_iter()) $($rest)*) + }; + + (($zips:expr) $first:ident $($rest:ident)*) => { + multi_zip_expr!(($zips.zip($first)) $($rest)*) + }; + + (($done:expr)) => { + $done + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! quote_each_token { + ($tokens:ident $span:ident) => {}; + + ($tokens:ident $span:ident # ! $($rest:tt)*) => { + quote_each_token!($tokens $span #); + quote_each_token!($tokens $span !); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident # ( $($inner:tt)* ) * $($rest:tt)*) => { + for pounded_var_names!(nested_tuples_pat () $($inner)*) + in pounded_var_names!(multi_zip_expr () $($inner)*) { + quote_each_token!($tokens $span $($inner)*); + } + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt * $($rest:tt)*) => { + for (_i, pounded_var_names!(nested_tuples_pat () $($inner)*)) + in pounded_var_names!(multi_zip_expr () $($inner)*).into_iter().enumerate() { + if _i > 0 { + quote_each_token!($tokens $span $sep); + } + quote_each_token!($tokens $span $($inner)*); + } + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident # [ $($inner:tt)* ] $($rest:tt)*) => { + quote_each_token!($tokens $span #); + $tokens.extend({ + let mut g = $crate::__rt::Group::new( + $crate::__rt::Delimiter::Bracket, + quote_spanned!($span=> $($inner)*), + ); + g.set_span($span); + Some($crate::__rt::TokenTree::from(g)) + }); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident # $first:ident $($rest:tt)*) => { + $crate::ToTokens::to_tokens(&$first, &mut $tokens); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ( $($first:tt)* ) $($rest:tt)*) => { + $tokens.extend({ + let mut g = $crate::__rt::Group::new( + $crate::__rt::Delimiter::Parenthesis, + quote_spanned!($span=> $($first)*), + ); + g.set_span($span); + Some($crate::__rt::TokenTree::from(g)) + }); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident [ $($first:tt)* ] $($rest:tt)*) => { + $tokens.extend({ + let mut g = $crate::__rt::Group::new( + $crate::__rt::Delimiter::Bracket, + quote_spanned!($span=> $($first)*), + ); + g.set_span($span); + Some($crate::__rt::TokenTree::from(g)) + }); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident { $($first:tt)* } $($rest:tt)*) => { + $tokens.extend({ + let mut g = $crate::__rt::Group::new( + $crate::__rt::Delimiter::Brace, + quote_spanned!($span=> $($first)*), + ); + g.set_span($span); + Some($crate::__rt::TokenTree::from(g)) + }); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident + $($rest:tt)*) => { + $crate::__rt::push_add(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident += $($rest:tt)*) => { + $crate::__rt::push_add_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident & $($rest:tt)*) => { + $crate::__rt::push_and(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident && $($rest:tt)*) => { + $crate::__rt::push_and_and(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident &= $($rest:tt)*) => { + $crate::__rt::push_and_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident @ $($rest:tt)*) => { + $crate::__rt::push_at(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ! $($rest:tt)*) => { + $crate::__rt::push_bang(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ^ $($rest:tt)*) => { + $crate::__rt::push_caret(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ^= $($rest:tt)*) => { + $crate::__rt::push_caret_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident : $($rest:tt)*) => { + $crate::__rt::push_colon(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident :: $($rest:tt)*) => { + $crate::__rt::push_colon2(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident , $($rest:tt)*) => { + $crate::__rt::push_comma(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident / $($rest:tt)*) => { + $crate::__rt::push_div(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident /= $($rest:tt)*) => { + $crate::__rt::push_div_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident . $($rest:tt)*) => { + $crate::__rt::push_dot(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident .. $($rest:tt)*) => { + $crate::__rt::push_dot2(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ... $($rest:tt)*) => { + $crate::__rt::push_dot3(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ..= $($rest:tt)*) => { + $crate::__rt::push_dot_dot_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident = $($rest:tt)*) => { + $crate::__rt::push_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident == $($rest:tt)*) => { + $crate::__rt::push_eq_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident >= $($rest:tt)*) => { + $crate::__rt::push_ge(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident > $($rest:tt)*) => { + $crate::__rt::push_gt(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident <= $($rest:tt)*) => { + $crate::__rt::push_le(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident < $($rest:tt)*) => { + $crate::__rt::push_lt(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident *= $($rest:tt)*) => { + $crate::__rt::push_mul_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident != $($rest:tt)*) => { + $crate::__rt::push_ne(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident | $($rest:tt)*) => { + $crate::__rt::push_or(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident |= $($rest:tt)*) => { + $crate::__rt::push_or_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident || $($rest:tt)*) => { + $crate::__rt::push_or_or(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident # $($rest:tt)*) => { + $crate::__rt::push_pound(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ? $($rest:tt)*) => { + $crate::__rt::push_question(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident -> $($rest:tt)*) => { + $crate::__rt::push_rarrow(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident <- $($rest:tt)*) => { + $crate::__rt::push_larrow(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident % $($rest:tt)*) => { + $crate::__rt::push_rem(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident %= $($rest:tt)*) => { + $crate::__rt::push_rem_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident => $($rest:tt)*) => { + $crate::__rt::push_fat_arrow(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident ; $($rest:tt)*) => { + $crate::__rt::push_semi(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident << $($rest:tt)*) => { + $crate::__rt::push_shl(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident <<= $($rest:tt)*) => { + $crate::__rt::push_shl_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident >> $($rest:tt)*) => { + $crate::__rt::push_shr(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident >>= $($rest:tt)*) => { + $crate::__rt::push_shr_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident * $($rest:tt)*) => { + $crate::__rt::push_star(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident - $($rest:tt)*) => { + $crate::__rt::push_sub(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident -= $($rest:tt)*) => { + $crate::__rt::push_sub_eq(&mut $tokens, $span); + quote_each_token!($tokens $span $($rest)*); + }; + + ($tokens:ident $span:ident $first:tt $($rest:tt)*) => { + $crate::__rt::parse(&mut $tokens, $span, quote_stringify!($first)); + quote_each_token!($tokens $span $($rest)*); + }; +} + +// Unhygienically invoke whatever `stringify` the caller has in scope i.e. not a +// local macro. The macros marked `local_inner_macros` above cannot invoke +// `stringify` directly. +#[macro_export] +#[doc(hidden)] +macro_rules! quote_stringify { + ($tt:tt) => { + stringify!($tt) + }; +} diff --git a/quote/src/runtime.rs b/quote/src/runtime.rs new file mode 100644 index 000000000..715a87707 --- /dev/null +++ b/quote/src/runtime.rs @@ -0,0 +1,119 @@ +use ext::TokenStreamExt; +pub use proc_macro2::*; + +fn is_ident_start(c: u8) -> bool { + (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' +} + +fn is_ident_continue(c: u8) -> bool { + (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' || (b'0' <= c && c <= b'9') +} + +fn is_ident(token: &str) -> bool { + if token.bytes().all(|digit| digit >= b'0' && digit <= b'9') { + return false; + } + + let mut bytes = token.bytes(); + let first = bytes.next().unwrap(); + if !is_ident_start(first) { + return false; + } + for ch in bytes { + if !is_ident_continue(ch) { + return false; + } + } + true +} + +pub fn parse(tokens: &mut TokenStream, span: Span, s: &str) { + if is_ident(s) { + // Fast path, since idents are the most common token. + tokens.append(Ident::new(s, span)); + } else { + let s: TokenStream = s.parse().expect("invalid token stream"); + tokens.extend(s.into_iter().map(|mut t| { + t.set_span(span); + t + })); + } +} + +macro_rules! push_punct { + ($name:ident $char1:tt) => { + pub fn $name(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; + ($name:ident $char1:tt $char2:tt) => { + pub fn $name(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char2, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; + ($name:ident $char1:tt $char2:tt $char3:tt) => { + pub fn $name(tokens: &mut TokenStream, span: Span) { + let mut punct = Punct::new($char1, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char2, Spacing::Joint); + punct.set_span(span); + tokens.append(punct); + let mut punct = Punct::new($char3, Spacing::Alone); + punct.set_span(span); + tokens.append(punct); + } + }; +} + +push_punct!(push_add '+'); +push_punct!(push_add_eq '+' '='); +push_punct!(push_and '&'); +push_punct!(push_and_and '&' '&'); +push_punct!(push_and_eq '&' '='); +push_punct!(push_at '@'); +push_punct!(push_bang '!'); +push_punct!(push_caret '^'); +push_punct!(push_caret_eq '^' '='); +push_punct!(push_colon ':'); +push_punct!(push_colon2 ':' ':'); +push_punct!(push_comma ','); +push_punct!(push_div '/'); +push_punct!(push_div_eq '/' '='); +push_punct!(push_dot '.'); +push_punct!(push_dot2 '.' '.'); +push_punct!(push_dot3 '.' '.' '.'); +push_punct!(push_dot_dot_eq '.' '.' '='); +push_punct!(push_eq '='); +push_punct!(push_eq_eq '=' '='); +push_punct!(push_ge '>' '='); +push_punct!(push_gt '>'); +push_punct!(push_le '<' '='); +push_punct!(push_lt '<'); +push_punct!(push_mul_eq '*' '='); +push_punct!(push_ne '!' '='); +push_punct!(push_or '|'); +push_punct!(push_or_eq '|' '='); +push_punct!(push_or_or '|' '|'); +push_punct!(push_pound '#'); +push_punct!(push_question '?'); +push_punct!(push_rarrow '-' '>'); +push_punct!(push_larrow '<' '-'); +push_punct!(push_rem '%'); +push_punct!(push_rem_eq '%' '='); +push_punct!(push_fat_arrow '=' '>'); +push_punct!(push_semi ';'); +push_punct!(push_shl '<' '<'); +push_punct!(push_shl_eq '<' '<' '='); +push_punct!(push_shr '>' '>'); +push_punct!(push_shr_eq '>' '>' '='); +push_punct!(push_star '*'); +push_punct!(push_sub '-'); +push_punct!(push_sub_eq '-' '='); diff --git a/quote/src/to_tokens.rs b/quote/src/to_tokens.rs new file mode 100644 index 000000000..9d221b27b --- /dev/null +++ b/quote/src/to_tokens.rs @@ -0,0 +1,205 @@ +use super::TokenStreamExt; + +use std::borrow::Cow; +use std::iter; +use std::rc::Rc; + +use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; + +/// Types that can be interpolated inside a [`quote!`] invocation. +/// +/// [`quote!`]: macro.quote.html +pub trait ToTokens { + /// Write `self` to the given `TokenStream`. + /// + /// The token append methods provided by the [`TokenStreamExt`] extension + /// trait may be useful for implementing `ToTokens`. + /// + /// [`TokenStreamExt`]: trait.TokenStreamExt.html + /// + /// # Example + /// + /// Example implementation for a struct representing Rust paths like + /// `std::cmp::PartialEq`: + /// + /// ```edition2018 + /// use proc_macro2::{TokenTree, Spacing, Span, Punct, TokenStream}; + /// use quote::{TokenStreamExt, ToTokens}; + /// + /// pub struct Path { + /// pub global: bool, + /// pub segments: Vec<PathSegment>, + /// } + /// + /// impl ToTokens for Path { + /// fn to_tokens(&self, tokens: &mut TokenStream) { + /// for (i, segment) in self.segments.iter().enumerate() { + /// if i > 0 || self.global { + /// // Double colon `::` + /// tokens.append(Punct::new(':', Spacing::Joint)); + /// tokens.append(Punct::new(':', Spacing::Alone)); + /// } + /// segment.to_tokens(tokens); + /// } + /// } + /// } + /// # + /// # pub struct PathSegment; + /// # + /// # impl ToTokens for PathSegment { + /// # fn to_tokens(&self, tokens: &mut TokenStream) { + /// # unimplemented!() + /// # } + /// # } + /// ``` + fn to_tokens(&self, tokens: &mut TokenStream); + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn into_token_stream(self) -> TokenStream + where + Self: Sized, + { + let mut tokens = TokenStream::new(); + self.to_tokens(&mut tokens); + tokens + } +} + +impl<'a, T: ?Sized + ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<'a, T: ?Sized + ToTokens> ToTokens for &'a mut T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ?Sized + ToTokens> ToTokens for Box<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ?Sized + ToTokens> ToTokens for Rc<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ToTokens> ToTokens for Option<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(ref t) = *self { + t.to_tokens(tokens); + } + } +} + +impl ToTokens for str { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::string(self)); + } +} + +impl ToTokens for String { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.as_str().to_tokens(tokens); + } +} + +macro_rules! primitive { + ($($t:ident => $name:ident)*) => ($( + impl ToTokens for $t { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::$name(*self)); + } + } + )*) +} + +primitive! { + i8 => i8_suffixed + i16 => i16_suffixed + i32 => i32_suffixed + i64 => i64_suffixed + isize => isize_suffixed + + u8 => u8_suffixed + u16 => u16_suffixed + u32 => u32_suffixed + u64 => u64_suffixed + usize => usize_suffixed + + f32 => f32_suffixed + f64 => f64_suffixed +} + +#[cfg(integer128)] +primitive! { + i128 => i128_suffixed + u128 => u128_suffixed +} + +impl ToTokens for char { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Literal::character(*self)); + } +} + +impl ToTokens for bool { + fn to_tokens(&self, tokens: &mut TokenStream) { + let word = if *self { "true" } else { "false" }; + tokens.append(Ident::new(word, Span::call_site())); + } +} + +impl ToTokens for Group { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Ident { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Punct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for Literal { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(self.clone()); + } +} + +impl ToTokens for TokenTree { + fn to_tokens(&self, dst: &mut TokenStream) { + dst.append(self.clone()); + } +} + +impl ToTokens for TokenStream { + fn to_tokens(&self, dst: &mut TokenStream) { + dst.extend(iter::once(self.clone())); + } + + fn into_token_stream(self) -> TokenStream { + self + } +} diff --git a/quote/tests/conditional/integer128.rs b/quote/tests/conditional/integer128.rs new file mode 100644 index 000000000..61e227446 --- /dev/null +++ b/quote/tests/conditional/integer128.rs @@ -0,0 +1,11 @@ +#[test] +fn test_integer128() { + let ii128 = -1i128; + let uu128 = 1u128; + + let tokens = quote! { + #ii128 #uu128 + }; + let expected = "-1i128 1u128"; + assert_eq!(expected, tokens.to_string()); +} diff --git a/quote/tests/test.rs b/quote/tests/test.rs new file mode 100644 index 000000000..f832da596 --- /dev/null +++ b/quote/tests/test.rs @@ -0,0 +1,295 @@ +#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))] + +use std::borrow::Cow; + +extern crate proc_macro2; +#[macro_use] +extern crate quote; + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::TokenStreamExt; + +mod conditional { + #[cfg(integer128)] + mod integer128; +} + +struct X; + +impl quote::ToTokens for X { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Ident::new("X", Span::call_site())); + } +} + +#[test] +fn test_quote_impl() { + let tokens = quote! { + impl<'a, T: ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens) + } + } + }; + + let expected = concat!( + "impl < 'a , T : ToTokens > ToTokens for & 'a T { ", + "fn to_tokens ( & self , tokens : & mut TokenStream ) { ", + "( * * self ) . to_tokens ( tokens ) ", + "} ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_substitution() { + let x = X; + let tokens = quote!(#x <#x> (#x) [#x] {#x}); + + let expected = "X < X > ( X ) [ X ] { X }"; + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_iter() { + let primes = &[X, X, X, X]; + + assert_eq!("X X X X", quote!(#(#primes)*).to_string()); + + assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string()); + + assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string()); +} + +#[test] +fn test_advanced() { + let generics = quote!( <'a, T> ); + + let where_clause = quote!( where T: Serialize ); + + let field_ty = quote!(String); + + let item_ty = quote!(Cow<'a, str>); + + let path = quote!(SomeTrait::serialize_with); + + let value = quote!(self.x); + + let tokens = quote! { + struct SerializeWith #generics #where_clause { + value: &'a #field_ty, + phantom: ::std::marker::PhantomData<#item_ty>, + } + + impl #generics ::serde::Serialize for SerializeWith #generics #where_clause { + fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer + { + #path(self.value, s) + } + } + + SerializeWith { + value: #value, + phantom: ::std::marker::PhantomData::<#item_ty>, + } + }; + + let expected = concat!( + "struct SerializeWith < 'a , T > where T : Serialize { ", + "value : & 'a String , ", + "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ", + "} ", + "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ", + "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ", + "where S : :: serde :: Serializer ", + "{ ", + "SomeTrait :: serialize_with ( self . value , s ) ", + "} ", + "} ", + "SerializeWith { ", + "value : self . x , ", + "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ", + "}" + ); + + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_integer() { + let ii8 = -1i8; + let ii16 = -1i16; + let ii32 = -1i32; + let ii64 = -1i64; + let iisize = -1isize; + let uu8 = 1u8; + let uu16 = 1u16; + let uu32 = 1u32; + let uu64 = 1u64; + let uusize = 1usize; + + let tokens = quote! { + #ii8 #ii16 #ii32 #ii64 #iisize + #uu8 #uu16 #uu32 #uu64 #uusize + }; + let expected = "-1i8 -1i16 -1i32 -1i64 -1isize 1u8 1u16 1u32 1u64 1usize"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_floating() { + let e32 = 2.345f32; + + let e64 = 2.345f64; + + let tokens = quote! { + #e32 + #e64 + }; + let expected = concat!("2.345f32 2.345f64"); + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_char() { + let zero = '\0'; + let pound = '#'; + let quote = '"'; + let apost = '\''; + let newline = '\n'; + let heart = '\u{2764}'; + + let tokens = quote! { + #zero #pound #quote #apost #newline #heart + }; + let expected = "'\\u{0}' '#' '\\\"' '\\'' '\\n' '\\u{2764}'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_str() { + let s = "\0 a 'b \" c"; + let tokens = quote!(#s); + let expected = "\"\\u{0} a \\'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_string() { + let s = "\0 a 'b \" c".to_string(); + let tokens = quote!(#s); + let expected = "\"\\u{0} a \\'b \\\" c\""; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_ident() { + let foo = Ident::new("Foo", Span::call_site()); + let bar = Ident::new(&format!("Bar{}", 7), Span::call_site()); + let tokens = quote!(struct #foo; enum #bar {}); + let expected = "struct Foo ; enum Bar7 { }"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_duplicate() { + let ch = 'x'; + + let tokens = quote!(#ch #ch); + + let expected = "'x' 'x'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_fancy_repetition() { + let foo = vec!["a", "b"]; + let bar = vec![true, false]; + + let tokens = quote! { + #(#foo: #bar),* + }; + + let expected = r#""a" : true , "b" : false"#; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_nested_fancy_repetition() { + let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']]; + + let tokens = quote! { + #( + #(#nested)* + ),* + }; + + let expected = "'a' 'b' 'c' , 'x' 'y' 'z'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_empty_repetition() { + let tokens = quote!(#(a b)* #(c d),*); + assert_eq!("", tokens.to_string()); +} + +#[test] +fn test_variable_name_conflict() { + // The implementation of `#(...),*` uses the variable `_i` but it should be + // fine, if a little confusing when debugging. + let _i = vec!['a', 'b']; + let tokens = quote! { #(#_i),* }; + let expected = "'a' , 'b'"; + assert_eq!(expected, tokens.to_string()); +} + +#[test] +fn test_empty_quote() { + let tokens = quote!(); + assert_eq!("", tokens.to_string()); +} + +#[test] +fn test_box_str() { + let b = "str".to_owned().into_boxed_str(); + let tokens = quote! { #b }; + assert_eq!("\"str\"", tokens.to_string()); +} + +#[test] +fn test_cow() { + let owned: Cow<Ident> = Cow::Owned(Ident::new("owned", Span::call_site())); + + let ident = Ident::new("borrowed", Span::call_site()); + let borrowed = Cow::Borrowed(&ident); + + let tokens = quote! { #owned #borrowed }; + assert_eq!("owned borrowed", tokens.to_string()); +} + +#[test] +fn test_closure() { + fn field_i(i: usize) -> Ident { + Ident::new(&format!("__field{}", i), Span::call_site()) + } + + let fields = (0usize..3) + .map(field_i as fn(_) -> _) + .map(|var| quote! { #var }); + + let tokens = quote! { #(#fields)* }; + assert_eq!("__field0 __field1 __field2", tokens.to_string()); +} + +#[test] +fn test_append_tokens() { + let mut a = quote!(a); + let b = quote!(b); + a.append_all(b); + assert_eq!("a b", a.to_string()); +} diff --git a/rand-0.5.6/.cargo-checksum.json b/rand-0.5.6/.cargo-checksum.json new file mode 100644 index 000000000..cc479c36a --- /dev/null +++ b/rand-0.5.6/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"} \ No newline at end of file diff --git a/rand-0.5.6/CHANGELOG.md b/rand-0.5.6/CHANGELOG.md new file mode 100644 index 000000000..4a09a5d46 --- /dev/null +++ b/rand-0.5.6/CHANGELOG.md @@ -0,0 +1,422 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md). + +You may also find the [Update Guide](UPDATING.md) useful. + + +## [0.5.6] - 2019-01-25 +### Platforms +- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng + + +## [0.5.5] - 2018-08-07 +### Documentation +- Fix links in documentation (#582) + + +## [0.5.4] - 2018-07-11 +### Platform support +- Make `OsRng` work via WASM/stdweb for WebWorkers + + +## [0.5.3] - 2018-06-26 +### Platform support +- OpenBSD, Bitrig: fix compilation (broken in 0.5.1) (#530) + + +## [0.5.2] - 2018-06-18 +### Platform support +- Hide `OsRng` and `JitterRng` on unsupported platforms (#512; fixes #503). + + +## [0.5.1] - 2018-06-08 + +### New distributions +- Added Cauchy distribution. (#474, #486) +- Added Pareto distribution. (#495) + +### Platform support and `OsRng` +- Remove blanket Unix implementation. (#484) +- Remove Wasm unimplemented stub. (#484) +- Dragonfly BSD: read from `/dev/random`. (#484) +- Bitrig: use `getentropy` like OpenBSD. (#484) +- Solaris: (untested) use `getrandom` if available, otherwise `/dev/random`. (#484) +- Emscripten, `stdweb`: split the read up in chunks. (#484) +- Emscripten, Haiku: don't do an extra blocking read from `/dev/random`. (#484) +- Linux, NetBSD, Solaris: read in blocking mode on first use in `fill_bytes`. (#484) +- Fuchsia, CloudABI: fix compilation (broken in Rand 0.5). (#484) + + +## [0.5.0] - 2018-05-21 + +### Crate features and organisation +- Minimum Rust version update: 1.22.0. (#239) +- Create a separate `rand_core` crate. (#288) +- Deprecate `rand_derive`. (#256) +- Add `prelude` (and module reorganisation). (#435) +- Add `log` feature. Logging is now available in `JitterRng`, `OsRng`, `EntropyRng` and `ReseedingRng`. (#246) +- Add `serde1` feature for some PRNGs. (#189) +- `stdweb` feature for `OsRng` support on WASM via stdweb. (#272, #336) + +### `Rng` trait +- Split `Rng` in `RngCore` and `Rng` extension trait. + `next_u32`, `next_u64` and `fill_bytes` are now part of `RngCore`. (#265) +- Add `Rng::sample`. (#256) +- Deprecate `Rng::gen_weighted_bool`. (#308) +- Add `Rng::gen_bool`. (#308) +- Remove `Rng::next_f32` and `Rng::next_f64`. (#273) +- Add optimized `Rng::fill` and `Rng::try_fill` methods. (#247) +- Deprecate `Rng::gen_iter`. (#286) +- Deprecate `Rng::gen_ascii_chars`. (#279) + +### `rand_core` crate +- `rand` now depends on new `rand_core` crate (#288) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +### Other traits and types +- Add `FromEntropy` trait. (#233, #375) +- Add `SmallRng` wrapper. (#296) +- Rewrite `ReseedingRng` to only work with `BlockRngCore` (substantial performance improvement). (#281) +- Deprecate `weak_rng`. Use `SmallRng` instead. (#296) +- Deprecate `AsciiGenerator`. (#279) + +### Random number generators +- Switch `StdRng` and `thread_rng` to HC-128. (#277) +- `StdRng` must now be created with `from_entropy` instead of `new` +- Change `thread_rng` reseeding threshold to 32 MiB. (#277) +- PRNGs no longer implement `Copy`. (#209) +- `Debug` implementations no longer show internals. (#209) +- Implement `Clone` for `ReseedingRng`, `JitterRng`, OsRng`. (#383, #384) +- Implement serialization for `XorShiftRng`, `IsaacRng` and `Isaac64Rng` under the `serde1` feature. (#189) +- Implement `BlockRngCore` for `ChaChaCore` and `Hc128Core`. (#281) +- All PRNGs are now portable across big- and little-endian architectures. (#209) +- `Isaac64Rng::next_u32` no longer throws away half the results. (#209) +- Add `IsaacRng::new_from_u64` and `Isaac64Rng::new_from_u64`. (#209) +- Add the HC-128 CSPRNG `Hc128Rng`. (#210) +- Change ChaCha20 to have 64-bit counter and 64-bit stream. (#349) +- Changes to `JitterRng` to get its size down from 2112 to 24 bytes. (#251) +- Various performance improvements to all PRNGs. + +### Platform support and `OsRng` +- Add support for CloudABI. (#224) +- Remove support for NaCl. (#225) +- WASM support for `OsRng` via stdweb, behind the `stdweb` feature. (#272, #336) +- Use `getrandom` on more platforms for Linux, and on Android. (#338) +- Use the `SecRandomCopyBytes` interface on macOS. (#322) +- On systems that do not have a syscall interface, only keep a single file descriptor open for `OsRng`. (#239) +- On Unix, first try a single read from `/dev/random`, then `/dev/urandom`. (#338) +- Better error handling and reporting in `OsRng` (using new error type). (#225) +- `OsRng` now uses non-blocking when available. (#225) +- Add `EntropyRng`, which provides `OsRng`, but has `JitterRng` as a fallback. (#235) + +### Distributions +- New `Distribution` trait. (#256) +- Add `Distribution::sample_iter` and `Rng::::sample_iter`. (#361) +- Deprecate `Rand`, `Sample` and `IndependentSample` traits. (#256) +- Add a `Standard` distribution (replaces most `Rand` implementations). (#256) +- Add `Binomial` and `Poisson` distributions. (#96) +- Add `Bernoulli` dsitribution. (#411) +- Add `Alphanumeric` distribution. (#279) +- Remove `Closed01` distribution, add `OpenClosed01`. (#274, #420) +- Rework `Range` type, making it possible to implement it for user types. (#274) +- Rename `Range` to `Uniform`. (#395) +- Add `Uniform::new_inclusive` for inclusive ranges. (#274) +- Use widening multiply method for much faster integer range reduction. (#274) +- `Standard` distribution for `char` uses `Uniform` internally. (#274) +- `Standard` distribution for `bool` uses sign test. (#274) +- Implement `Standard` distribution for `Wrapping<T>`. (#436) +- Implement `Uniform` distribution for `Duration`. (#427) + + +## [0.4.3] - 2018-08-16 +### Fixed +- Use correct syscall number for PowerPC (#589) + + +## [0.4.2] - 2018-01-06 +### Changed +- Use `winapi` on Windows +- Update for Fuchsia OS +- Remove dev-dependency on `log` + + +## [0.4.1] - 2017-12-17 +### Added +- `no_std` support + + +## [0.4.0-pre.0] - 2017-12-11 +### Added +- `JitterRng` added as a high-quality alternative entropy source using the + system timer +- new `seq` module with `sample_iter`, `sample_slice`, etc. +- WASM support via dummy implementations (fail at run-time) +- Additional benchmarks, covering generators and new seq code + +### Changed +- `thread_rng` uses `JitterRng` if seeding from system time fails + (slower but more secure than previous method) + +### Deprecated + - `sample` function deprecated (replaced by `sample_iter`) + + +## [0.3.20] - 2018-01-06 +### Changed +- Remove dev-dependency on `log` +- Update `fuchsia-zircon` dependency to 0.3.2 + + +## [0.3.19] - 2017-12-27 +### Changed +- Require `log <= 0.3.8` for dev builds +- Update `fuchsia-zircon` dependency to 0.3 +- Fix broken links in docs (to unblock compiler docs testing CI) + + +## [0.3.18] - 2017-11-06 +### Changed +- `thread_rng` is seeded from the system time if `OsRng` fails +- `weak_rng` now uses `thread_rng` internally + + +## [0.3.17] - 2017-10-07 +### Changed + - Fuchsia: Magenta was renamed Zircon + +## [0.3.16] - 2017-07-27 +### Added +- Implement Debug for mote non-public types +- implement `Rand` for (i|u)i128 +- Support for Fuchsia + +### Changed +- Add inline attribute to SampleRange::construct_range. + This improves the benchmark for sample in 11% and for shuffle in 16%. +- Use `RtlGenRandom` instead of `CryptGenRandom` + + +## [0.3.15] - 2016-11-26 +### Added +- Add `Rng` trait method `choose_mut` +- Redox support + +### Changed +- Use `arc4rand` for `OsRng` on FreeBSD. +- Use `arc4random(3)` for `OsRng` on OpenBSD. + +### Fixed +- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows + + +## [0.3.14] - 2016-02-13 +### Fixed +- Inline definitions from winapi/advapi32, wich decreases build times + + +## [0.3.13] - 2016-01-09 +### Fixed +- Compatible with Rust 1.7.0-nightly (needed some extra type annotations) + + +## [0.3.12] - 2015-11-09 +### Changed +- Replaced the methods in `next_f32` and `next_f64` with the technique described + Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more + uniform distribution. +- Depend on libc 0.2 + +### Fixed +- Fix iterator protocol issue in `rand::sample` + + +## [0.3.11] - 2015-08-31 +### Added +- Implement `Rand` for arrays with n <= 32 + + +## [0.3.10] - 2015-08-17 +### Added +- Support for NaCl platforms + +### Changed +- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng` + + +## [0.3.9] - 2015-06-18 +### Changed +- Use `winapi` for Windows API things + +### Fixed +- Fixed test on stable/nightly +- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu + + +## [0.3.8] - 2015-04-23 +### Changed +- `log` is a dev dependency + +### Fixed +- Fix race condition of atomics in `is_getrandom_available` + + +## [0.3.7] - 2015-04-03 +### Fixed +- Derive Copy/Clone changes + + +## [0.3.6] - 2015-04-02 +### Changed +- Move to stable Rust! + + +## [0.3.5] - 2015-04-01 +### Fixed +- Compatible with Rust master + + +## [0.3.4] - 2015-03-31 +### Added +- Implement Clone for `Weighted` + +### Fixed +- Compatible with Rust master + + +## [0.3.3] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.2] - 2015-03-26 + + +## [0.3.1] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.0] - 2015-03-25 +### Changed +- Update to use log version 0.3.x + + +## [0.2.1] - 2015-03-22 +### Fixed +- Compatible with Rust master +- Fixed iOS compilation + + +## [0.2.0] - 2015-03-06 +### Fixed +- Compatible with Rust master (move from `old_io` to `std::io`) + + +## [0.1.4] - 2015-03-04 +### Fixed +- Compatible with Rust master (use wrapping ops) + + +## [0.1.3] - 2015-02-20 +### Fixed +- Compatible with Rust master + +### Removed +- Removed Copy implementations from RNGs + + +## [0.1.2] - 2015-02-03 +### Added +- Imported functionality from `std::rand`, including: + - `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()` + - `ReaderRng`: A wrapper around any Reader to treat it as an RNG. +- Imported documentation from `std::rand` +- Imported tests from `std::rand` + + +## [0.1.1] - 2015-02-03 +### Added +- Migrate to a cargo-compatible directory structure. + +### Fixed +- Do not use entropy during `gen_weighted_bool(1)` + + +## [Rust 0.12.0] - 2014-10-09 +### Added +- Impl Rand for tuples of arity 11 and 12 +- Include ChaCha pseudorandom generator +- Add `next_f64` and `next_f32` to Rng +- Implement Clone for PRNGs + +### Changed +- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a + runtime is removed from Rust). + +### Fixed +- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by + informing the optimiser that indexing is never out-of-bounds. + +### Removed +- Removed the Deprecated `choose_option` + + +## [Rust 0.11.0] - 2014-07-02 +### Added +- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random` +- `Rng::gen_iter()` which will return an infinite stream of random values +- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters + +### Changed +- Now only depends on libcore! +- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()` +- Rename OSRng to OsRng +- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`, + but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice + structure now has a lifetime associated with it. +- The `sample` method on `Rng` has been moved to a top-level function in the + `rand` module due to its dependence on `Vec`. + +### Removed +- `Rng::gen_vec()` was removed. Previous behavior can be regained with + `rng.gen_iter().take(n).collect()` +- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with + `rng.gen_ascii_chars().take(n).collect()` +- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all + relied on being able to use an OSRng for seeding, but this is no longer + available in librand (where these types are defined). To retain the same + functionality, these types now implement the `Rand` trait so they can be + generated with a random seed from another random number generator. This allows + the stdlib to use an OSRng to create seeded instances of these RNGs. +- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be + pretty rare in the codebase, and it allows for librand to not depend on + liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not + supported. +- Remove a slew of old deprecated functions + + +## [Rust 0.10] - 2014-04-03 +### Changed +- replace `Rng.shuffle's` functionality with `.shuffle_mut` +- bubble up IO errors when creating an OSRng + +### Fixed +- Use `fill()` instead of `read()` +- Rewrite OsRng in Rust for windows + +## [0.10-pre] - 2014-03-02 +### Added +- Seperate `rand` out of the standard library diff --git a/rand-0.5.6/CONTRIBUTING.md b/rand-0.5.6/CONTRIBUTING.md new file mode 100644 index 000000000..37c1a9d56 --- /dev/null +++ b/rand-0.5.6/CONTRIBUTING.md @@ -0,0 +1,93 @@ +# Contributing to Rand + +Thank you for your interest in contributing to Rand! + +The following is a list of notes and tips for when you want to contribute to +Rand with a pull request. + +If you want to make major changes, it is usually best to open an issue to +discuss the idea first. + +Rand doesn't (yet) use rustfmt. It is best to follow the style of the +surrounding code, and try to keep an 80 character line limit. + + +## Documentation + +We especially welcome documentation PRs. + +As of Rust 1.25 there are differences in how stable and nightly render +documentation links. Make sure it works on stable, then nightly should be good +too. One Travis CI build checks for dead links using `cargo-deadlinks`. If you +want to run the check locally: +```sh +cargo install cargo-deadlinks +# It is recommended to remove left-over files from previous compilations +rm -rf /target/doc +cargo doc --no-deps +cargo deadlinks --dir target/doc +``` + +When making changes to code examples in the documentation, make sure they build +with: +```sh +cargo test --doc +``` + +A helpful command to rebuild documentation automatically on save (only works on +Linux): +``` +while inotifywait -r -e close_write src/ rand_core/; do cargo doc; done +``` + + +## Testing + +Rand already contains a number of unit tests, but could use more. Also the +existing ones could use clean-up. Any work on the tests is appreciated. + +Not every change or new bit of functionality requires tests, but if you can +think of a test that adds value, please add it. + +Depending on the code you change, test with one of: +```sh +cargo test +cargo test --package rand_core +# Test log, serde and 128-bit support +cargo test --features serde1,log,nightly +``` + +We want to be able to not only run the unit tests with `std` available, but also +without. Because `thread_rng()` and `FromEntropy` are not available without the +`std` feature, you may have to disable a new test with `#[cfg(feature="std")]`. +In other cases using `::test::rng` with a constant seed is a good option: +```rust +let mut rng = ::test::rng(528); // just pick some number +``` + +Only the unit tests should work in `no_std` mode, we don't want to complicate +the doc-tests. Run the tests with: +```sh +# Test no_std support +cargo test --lib --no-default-features +cargo test --package rand_core --no-default-features + +# Test no_std+alloc support; requires nightly +cargo test --lib --no-default-features --features alloc +``` + + +## Benchmarking + +A lot of code in Rand is performance-sensitive, most of it is expected to be +used in hot loops in some libraries/applications. If you change code in the +`rngs`, `prngs` or `distributions` modules, especially when you see an 'obvious +cleanup', make sure the benchmarks do not regress. It is nice to report the +benchmark results in the PR (or to report nothing's changed). + +```sh +# Benchmarks (requires nightly) +cargo bench +# Some benchmarks have a faster path with i128_support +cargo bench --features=nightly +``` diff --git a/rand-0.5.6/Cargo.toml b/rand-0.5.6/Cargo.toml new file mode 100644 index 000000000..32d6ef0ad --- /dev/null +++ b/rand-0.5.6/Cargo.toml @@ -0,0 +1,72 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand" +version = "0.5.6" +authors = ["The Rust Project Developers"] +description = "Random number generators and other randomness functionality.\n" +homepage = "https://crates.io/crates/rand" +documentation = "https://docs.rs/rand" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/rand" +[package.metadata.docs.rs] +all-features = true +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.rand_core] +version = "0.3" +default-features = false + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "1" +optional = true +[dev-dependencies.bincode] +version = "1.0" + +[features] +alloc = ["rand_core/alloc"] +default = ["std"] +i128_support = [] +nightly = ["i128_support"] +serde1 = ["serde", "serde_derive", "rand_core/serde1"] +std = ["rand_core/std", "alloc", "libc", "winapi", "cloudabi", "fuchsia-cprng"] +[target."cfg(target_os = \"cloudabi\")".dependencies.cloudabi] +version = "0.0.3" +optional = true +[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-cprng] +version = "0.1.0" +optional = true +[target."cfg(unix)".dependencies.libc] +version = "0.2" +optional = true +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["minwindef", "ntsecapi", "profileapi", "winnt"] +optional = true +[target.wasm32-unknown-unknown.dependencies.stdweb] +version = "0.4" +optional = true +[badges.appveyor] +repository = "alexcrichton/rand" + +[badges.travis-ci] +repository = "rust-lang-nursery/rand" diff --git a/rand-0.5.6/LICENSE-APACHE b/rand-0.5.6/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand-0.5.6/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand-0.5.6/LICENSE-MIT b/rand-0.5.6/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/rand-0.5.6/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand-0.5.6/README.md b/rand-0.5.6/README.md new file mode 100644 index 000000000..75950ed48 --- /dev/null +++ b/rand-0.5.6/README.md @@ -0,0 +1,143 @@ +# Rand + +[![Build Status](https://travis-ci.org/rust-lang-nursery/rand.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-lang-nursery/rand?svg=true)](https://ci.appveyor.com/project/alexcrichton/rand) +[![Latest version](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand) +[![Documentation](https://docs.rs/rand/badge.svg)](https://docs.rs/rand) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-yellow.svg)](https://github.com/rust-lang-nursery/rand#rust-version-requirements) + +A Rust library for random number generation. + +Rand provides utilities to generate random numbers, to convert them to useful +types and distributions, and some randomness-related algorithms. + +The core random number generation traits of Rand live in the [rand_core]( +https://crates.io/crates/rand_core) crate; this crate is most useful when +implementing RNGs. + +API reference: +[master branch](https://rust-lang-nursery.github.io/rand/rand/index.html), +[by release](https://docs.rs/rand/0.5). + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +rand = "0.5" +``` + +and this to your crate root: + +```rust +extern crate rand; + +use rand::prelude::*; + +fn main() { + // basic usage with random(): + let x: u8 = random(); + println!("{}", x); + + let y = random::<f64>(); + println!("{}", y); + + if random() { // generates a boolean + println!("Heads!"); + } + + // normal usage needs both an RNG and a function to generate the appropriate + // type, range, distribution, etc. + let mut rng = thread_rng(); + if rng.gen() { // random bool + let x: f64 = rng.gen(); // random number in range [0, 1) + println!("x is: {}", x); + let ch = rng.gen::<char>(); // Sometimes you need type annotation + println!("char is: {}", ch); + println!("Number from 0 to 9: {}", rng.gen_range(0, 10)); + } +} +``` + +## Functionality + +The Rand crate provides: + +- A convenient to use default RNG, `thread_rng`: an automatically seeded, + crypto-grade generator stored in thread-local memory. +- Pseudo-random number generators: `StdRng`, `SmallRng`, `prng` module. +- Functionality for seeding PRNGs: the `FromEntropy` trait, and as sources of + external randomness `EntropyRng`, `OsRng` and `JitterRng`. +- Most content from [`rand_core`](https://crates.io/crates/rand_core) + (re-exported): base random number generator traits and error-reporting types. +- 'Distributions' producing many different types of random values: + - A `Standard` distribution for integers, floats, and derived types including + tuples, arrays and `Option` + - Unbiased sampling from specified `Uniform` ranges. + - Sampling from exponential/normal/gamma distributions. + - Sampling from binomial/poisson distributions. + - `gen_bool` aka Bernoulli distribution. +- `seq`-uence related functionality: + - Sampling a subset of elements. + - Randomly shuffling a list. + + +## Versions + +Version 0.5 is the latest version and contains many breaking changes. +See [the Upgrade Guide](UPDATING.md) for guidance on updating from previous +versions. + +Version 0.4 was released in December 2017. It contains almost no breaking +changes since the 0.3 series. + +For more details, see the [changelog](CHANGELOG.md). + +### Rust version requirements + +The 0.5 release of Rand requires **Rustc version 1.22 or greater**. +Rand 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or +greater. Subsets of the Rand code may work with older Rust versions, but this +is not supported. + +Travis CI always has a build with a pinned version of Rustc matching the oldest +supported Rust release. The current policy is that this can be updated in any +Rand release if required, but the change must be noted in the changelog. + + +## Crate Features + +Rand is built with only the `std` feature enabled by default. The following +optional features are available: + +- `alloc` can be used instead of `std` to provide `Vec` and `Box`. +- `i128_support` enables support for generating `u128` and `i128` values. +- `log` enables some logging via the `log` crate. +- `nightly` enables all unstable features (`i128_support`). +- `serde1` enables serialization for some types, via Serde version 1. +- `stdweb` enables support for `OsRng` on `wasm-unknown-unknown` via `stdweb` + combined with `cargo-web`. + +`no_std` mode is activated by setting `default-features = false`; this removes +functionality depending on `std`: + +- `thread_rng()`, and `random()` are not available, as they require thread-local + storage and an entropy source. +- `OsRng` and `EntropyRng` are unavailable. +- `JitterRng` code is still present, but a nanosecond timer must be provided via + `JitterRng::new_with_timer` +- Since no external entropy is available, it is not possible to create + generators with fresh seeds using the `FromEntropy` trait (user must provide + a seed). +- Exponential, normal and gamma type distributions are unavailable since `exp` + and `log` functions are not provided in `core`. +- The `seq`-uence module is unavailable, as it requires `Vec`. + + +# License + +Rand is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details. diff --git a/rand-0.5.6/UPDATING.md b/rand-0.5.6/UPDATING.md new file mode 100644 index 000000000..09321b7b6 --- /dev/null +++ b/rand-0.5.6/UPDATING.md @@ -0,0 +1,260 @@ +# Update Guide + +This guide gives a few more details than the [changelog], in particular giving +guidance on how to use new features and migrate away from old ones. + +[changelog]: CHANGELOG.md + +## Rand 0.5 + +The 0.5 release has quite significant changes over the 0.4 release; as such, +it may be worth reading through the following coverage of breaking changes. +This release also contains many optimisations, which are not detailed below. + +### Crates + +We have a new crate: `rand_core`! This crate houses some important traits, +`RngCore`, `BlockRngCore`, `SeedableRng` and `CryptoRng`, the error types, as +well as two modules with helpers for implementations: `le` and `impls`. It is +recommended that implementations of generators use the `rand_core` crate while +other users use only the `rand` crate, which re-exports most parts of `rand_core`. + +The `rand_derive` crate has been deprecated due to very low usage and +deprecation of `Rand`. + +### Features + +Several new Cargo feature flags have been added: + +- `alloc`, used without `std`, allows use of `Box` and `Vec` +- `serde1` adds serialization support to some PRNGs +- `log` adds logging in a few places (primarily to `OsRng` and `JitterRng`) + +### `Rng` and friends (core traits) + +`Rng` trait has been split into two traits, a "back end" `RngCore` (implemented +by generators) and a "front end" `Rng` implementing all the convenient extension +methods. + +Implementations of generators must `impl RngCore` instead. Usage of `rand_core` +for implementations is encouraged; the `rand_core::{le, impls}` modules may +prove useful. + +Users of `Rng` *who don't need to implement it* won't need to make so many +changes; often users can forget about `RngCore` and only import `Rng`. Instead +of `RngCore::next_u32()` / `next_u64()` users should prefer `Rng::gen()`, and +instead of `RngCore::fill_bytes(dest)`, `Rng::fill(dest)` can be used. + +#### `Rng` / `RngCore` methods + +To allow error handling from fallible sources (e.g. `OsRng`), a new +`RngCore::try_fill_bytes` method has been added; for example `EntropyRng` uses +this mechanism to fall back to `JitterRng` if `OsRng` fails, and various +handlers produce better error messages. +As before, the other methods will panic on failure, but since these are usually +used with algorithmic generators which are usually infallible, this is +considered an appropriate compromise. + +A few methods from the old `Rng` have been removed or deprecated: + +- `next_f32` and `next_f64`; these are no longer implementable by generators; + use `gen` instead +- `gen_iter`; users may instead use standard iterators with closures: + `::std::iter::repeat(()).map(|()| rng.gen())` +- `gen_ascii_chars`; use `repeat` as above and `rng.sample(Alphanumeric)` +- `gen_weighted_bool(n)`; use `gen_bool(1.0 / n)` instead + +`Rng` has a few new methods: + +- `sample(distr)` is a shortcut for `distr.sample(rng)` for any `Distribution` +- `gen_bool(p)` generates a boolean with probability `p` of being true +- `fill` and `try_fill`, corresponding to `fill_bytes` and `try_fill_bytes` + respectively (i.e. the only difference is error handling); these can fill + and integer slice / array directly, and provide better performance + than `gen()` + +#### Constructing PRNGs + +##### New randomly-initialised PRNGs + +A new trait has been added: `FromEntropy`. This is automatically implemented for +any type supporting `SeedableRng`, and provides construction from fresh, strong +entropy: + +```rust +use rand::{ChaChaRng, FromEntropy}; + +let mut rng = ChaChaRng::from_entropy(); +``` + +##### Seeding PRNGs + +The `SeedableRng` trait has been modified to include the seed type via an +associated type (`SeedableRng::Seed`) instead of a template parameter +(`SeedableRng<Seed>`). Additionally, all PRNGs now seed from a byte-array +(`[u8; N]` for some fixed N). This allows generic handling of PRNG seeding +which was not previously possible. + +PRNGs are no longer constructed from other PRNGs via `Rand` support / `gen()`, +but through `SeedableRng::from_rng`, which allows error handling and is +intentionally explicit. + +`SeedableRng::reseed` has been removed since it has no utility over `from_seed` +and its performance advantage is questionable. + +Implementations of `SeedableRng` may need to change their `Seed` type to a +byte-array; this restriction has been made to ensure portable handling of +Endianness. Helper functions are available in `rand_core::le` to read `u32` and +`u64` values from byte arrays. + +#### Block-based PRNGs + +rand_core has a new helper trait, `BlockRngCore`, and implementation, +`BlockRng`. These are for use by generators which generate a block of random +data at a time instead of word-sized values. Using this trait and implementation +has two advantages: optimised `RngCore` methods are provided, and the PRNG can +be used with `ReseedingRng` with very low overhead. + +#### Cryptographic RNGs + +A new trait has been added: `CryptoRng`. This is purely a marker trait to +indicate which generators should be suitable for cryptography, e.g. +`fn foo<R: Rng + CryptoRng>(rng: &mut R)`. *Suitability for cryptographic +use cannot be guaranteed.* + +### Error handling + +A new `Error` type has been added, designed explicitly for no-std compatibility, +simplicity, and enough flexibility for our uses (carrying a `cause` when +possible): +```rust +pub struct Error { + pub kind: ErrorKind, + pub msg: &'static str, + // some fields omitted +} +``` +The associated `ErrorKind` allows broad classification of errors into permanent, +unexpected, transient and not-yet-ready kinds. + +The following use the new error type: + +- `RngCore::try_fill_bytes` +- `Rng::try_fill` +- `OsRng::new` +- `JitterRng::new` + +### External generators + +We have a new generator, `EntropyRng`, which wraps `OsRng` and `JitterRng` +(preferring to use the former, but falling back to the latter if necessary). +This allows easy construction with fallback via `SeedableRng::from_rng`, +e.g. `IsaacRng::from_rng(EntropyRng::new())?`. This is equivalent to using +`FromEntropy` except for error handling. + +It is recommended to use `EntropyRng` over `OsRng` to avoid errors on platforms +with broken system generator, but it should be noted that the `JitterRng` +fallback is very slow. + +### PRNGs + +*Pseudo-Random Number Generators* (i.e. deterministic algorithmic generators) +have had a few changes since 0.4, and are now housed in the `prng` module +(old names remain temporarily available for compatibility; eventually these +generators will likely be housed outside the `rand` crate). + +All PRNGs now do not implement `Copy` to prevent accidental copying of the +generator's state (and thus repetitions of generated values). Explicit cloning +via `Clone` is still available. All PRNGs now have a custom implementation of +`Debug` which does not print any internal state; this helps avoid accidentally +leaking cryptographic generator state in log files. External PRNG +implementations are advised to follow this pattern (see also doc on `RngCore`). + +`SmallRng` has been added as a wrapper, currently around `XorShiftRng` (but +likely another algorithm soon). This is for uses where small state and fast +initialisation are important but cryptographic strength is not required. +(Actual performance of generation varies by benchmark; dependending on usage +this may or may not be the fastest algorithm, but will always be fast.) + +#### `ReseedingRng` + +The `ReseedingRng` wrapper has been signficantly altered to reduce overhead. +Unfortunately the new `ReseedingRng` is not compatible with all RNGs, but only +those using `BlockRngCore`. + +#### ISAAC PRNGs + +The `IsaacRng` and `Isaac64Rng` PRNGs now have an additional construction +method: `new_from_u64(seed)`. 64 bits of state is insufficient for cryptography +but may be of use in simulations and games. This will likely be superceeded by +a method to construct any PRNG from any hashable object in the future. + +#### HC-128 + +This is a new cryptographic generator, selected as one of the "stream ciphers +suitable for widespread adoption" by eSTREAM. This is now the default +cryptographic generator, used by `StdRng` and `thread_rng()`. + +### Helper functions/traits + +The `Rand` trait has been deprecated. Instead, users are encouraged to use +`Standard` which is a real distribution and supports the same sampling as +`Rand`. `Rng::gen()` now uses `Standard` and should work exactly as before. +See the documentation of the `distributions` module on how to implement +`Distribution<T>` for `Standard` for user types `T` + +`weak_rng()` has been deprecated; use `SmallRng::from_entropy()` instead. + +### Distributions + +The `Sample` and `IndependentSample` traits have been replaced by a single +trait, `Distribution`. This is largely equivalent to `IndependentSample`, but +with `ind_sample` replaced by just `sample`. Support for mutable distributions +has been dropped; although it appears there may be a few genuine uses, these +are not used widely enough to justify the existance of two independent traits +or of having to provide mutable access to a distribution object. Both `Sample` +and `IndependentSample` are still available, but deprecated; they will be +removed in a future release. + +`Distribution::sample` (as well as several other functions) can now be called +directly on type-erased (unsized) RNGs. + +`RandSample` has been removed (see `Rand` deprecation and new `Standard` +distribution). + +The `Closed01` wrapper has been removed, but `OpenClosed01` has been added. + +#### Uniform distributions + +Two new distributions are available: + +- `Standard` produces uniformly-distributed samples for many different types, + and acts as a replacement for `Rand` +- `Alphanumeric` samples `char`s from the ranges `a-z A-Z 0-9` + +##### Ranges + +The `Range` distribution has been heavily adapted, and renamed to `Uniform`: + +- `Uniform::new(low, high)` remains (half open `[low, high)`) +- `Uniform::new_inclusive(low, high)` has been added, including `high` in the sample range +- `Uniform::sample_single(low, high, rng)` is a faster variant for single usage sampling from `[low, high)` + +`Uniform` can now be implemented for user-defined types; see the `uniform` module. + +#### Non-uniform distributions + +Two distributions have been added: + +- Poisson, modelling the number of events expected from a constant-rate + source within a fixed time interval (e.g. nuclear decay) +- Binomial, modelling the outcome of a fixed number of yes-no trials + +The sampling methods are based on those in "Numerical Recipes in C". + +##### Exponential and Normal distributions + +The main `Exp` and `Normal` distributions are unchanged, however the +"standard" versions, `Exp1` and `StandardNormal` are no longer wrapper types, +but full distributions. Instead of writing `let Exp1(x) = rng.gen();` you now +write `let x = rng.sample(Exp1);`. diff --git a/rand-0.5.6/appveyor.yml b/rand-0.5.6/appveyor.yml new file mode 100644 index 000000000..97d3ce6fd --- /dev/null +++ b/rand-0.5.6/appveyor.yml @@ -0,0 +1,39 @@ +environment: + + # At the time this was added AppVeyor was having troubles with checking + # revocation of SSL certificates of sites like static.rust-lang.org and what + # we think is crates.io. The libcurl HTTP client by default checks for + # revocation on Windows and according to a mailing list [1] this can be + # disabled. + # + # The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL + # revocation checking on Windows in libcurl. Note, though, that rustup, which + # we're using to download Rust here, also uses libcurl as the default backend. + # Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation + # checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to + # use the Hyper instead of libcurl backend. Both Hyper and libcurl use + # schannel on Windows but it appears that Hyper configures it slightly + # differently such that revocation checking isn't turned on by default. + # + # [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html + RUSTUP_USE_HYPER: 1 + CARGO_HTTP_CHECK_REVOKE: false + + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --all # cannot use --all and --features together + - cargo test --all --benches + - cargo test --features serde1,log,nightly + - cargo test --tests --no-default-features --features=alloc,serde1 + - cargo test --package rand_core --no-default-features --features=alloc,serde1 diff --git a/rand-0.5.6/benches/distributions.rs b/rand-0.5.6/benches/distributions.rs new file mode 100644 index 000000000..fd6b5ae03 --- /dev/null +++ b/rand-0.5.6/benches/distributions.rs @@ -0,0 +1,161 @@ +#![feature(test)] +#![cfg_attr(all(feature="i128_support", feature="nightly"), allow(stable_features))] // stable since 2018-03-27 +#![cfg_attr(all(feature="i128_support", feature="nightly"), feature(i128_type, i128))] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; + +use std::mem::size_of; +use test::Bencher; + +use rand::{Rng, FromEntropy, XorShiftRng}; +use rand::distributions::*; + +macro_rules! distr_int { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0 as $ty; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_float { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum += x; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0u32; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x as u32); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +// uniform +distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100)); +distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000)); +distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000)); +distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123)); +#[cfg(feature = "i128_support")] +distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789)); + +distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319)); +distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319)); + +// standard +distr_int!(distr_standard_i8, i8, Standard); +distr_int!(distr_standard_i16, i16, Standard); +distr_int!(distr_standard_i32, i32, Standard); +distr_int!(distr_standard_i64, i64, Standard); +#[cfg(feature = "i128_support")] +distr_int!(distr_standard_i128, i128, Standard); + +distr!(distr_standard_bool, bool, Standard); +distr!(distr_standard_alphanumeric, char, Alphanumeric); +distr!(distr_standard_codepoint, char, Standard); + +distr_float!(distr_standard_f32, f32, Standard); +distr_float!(distr_standard_f64, f64, Standard); +distr_float!(distr_open01_f32, f32, Open01); +distr_float!(distr_open01_f64, f64, Open01); +distr_float!(distr_openclosed01_f32, f32, OpenClosed01); +distr_float!(distr_openclosed01_f64, f64, OpenClosed01); + +// distributions +distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56)); +distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56)); +distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56)); +distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0)); +distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0)); +distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9)); +distr_int!(distr_binomial, u64, Binomial::new(20, 0.7)); +distr_int!(distr_poisson, u64, Poisson::new(4.0)); +distr!(distr_bernoulli, bool, Bernoulli::new(0.18)); + + +// construct and sample from a range +macro_rules! gen_range_int { + ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + + b.iter(|| { + let mut high = $high; + let mut accum: $ty = 0; + for _ in 0..::RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen_range($low, high)); + // force recalculation of range each time + high = high.wrapping_add(1) & std::$ty::MAX; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +gen_range_int!(gen_range_i8, i8, -20i8, 100); +gen_range_int!(gen_range_i16, i16, -500i16, 2000); +gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000); +gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123); +#[cfg(feature = "i128_support")] +gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789); + +#[bench] +fn dist_iter(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + let distr = Normal::new(-2.71828, 3.14159); + let mut iter = distr.sample_iter(&mut rng); + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + accum += iter.next().unwrap(); + } + accum + }); + b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N; +} diff --git a/rand-0.5.6/benches/generators.rs b/rand-0.5.6/benches/generators.rs new file mode 100644 index 000000000..402a87bae --- /dev/null +++ b/rand-0.5.6/benches/generators.rs @@ -0,0 +1,176 @@ +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; +const BYTES_LEN: usize = 1024; + +use std::mem::size_of; +use test::{black_box, Bencher}; + +use rand::prelude::*; +use rand::prng::{XorShiftRng, Hc128Rng, IsaacRng, Isaac64Rng, ChaChaRng}; +use rand::prng::hc128::Hc128Core; +use rand::rngs::adapter::ReseedingRng; +use rand::rngs::{OsRng, JitterRng, EntropyRng}; + +macro_rules! gen_bytes { + ($fnn:ident, $gen:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen; + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; + } + } +} + +gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy()); +gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy()); +gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy()); +gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy()); +gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy()); +gen_bytes!(gen_bytes_std, StdRng::from_entropy()); +gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); +gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); + +macro_rules! gen_uint { + ($fnn:ident, $ty:ty, $gen:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen; + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy()); +gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy()); +gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy()); +gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy()); +gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy()); +gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); +gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); +gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); + +gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy()); +gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy()); +gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy()); +gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy()); +gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy()); +gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); +gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); +gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); + +// Do not test JitterRng like the others by running it RAND_BENCH_N times per, +// measurement, because it is way too slow. Only run it once. +#[bench] +fn gen_u64_jitter(b: &mut Bencher) { + let mut rng = JitterRng::new().unwrap(); + b.iter(|| { + rng.gen::<u64>() + }); + b.bytes = size_of::<u64>() as u64; +} + +macro_rules! init_gen { + ($fnn:ident, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + b.iter(|| { + let r2 = $gen::from_rng(&mut rng).unwrap(); + r2 + }); + } + } +} + +init_gen!(init_xorshift, XorShiftRng); +init_gen!(init_hc128, Hc128Rng); +init_gen!(init_isaac, IsaacRng); +init_gen!(init_isaac64, Isaac64Rng); +init_gen!(init_chacha, ChaChaRng); + +#[bench] +fn init_jitter(b: &mut Bencher) { + b.iter(|| { + JitterRng::new().unwrap() + }); +} + + +const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get + // deterministic measurements + +#[bench] +fn reseeding_hc128_bytes(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; +} + +macro_rules! reseeding_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +reseeding_uint!(reseeding_hc128_u32, u32); +reseeding_uint!(reseeding_hc128_u64, u64); + + +macro_rules! threadrng_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +threadrng_uint!(thread_rng_u32, u32); +threadrng_uint!(thread_rng_u64, u64); diff --git a/rand-0.5.6/benches/misc.rs b/rand-0.5.6/benches/misc.rs new file mode 100644 index 000000000..a1822a53a --- /dev/null +++ b/rand-0.5.6/benches/misc.rs @@ -0,0 +1,194 @@ +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; + +use test::Bencher; + +use rand::prelude::*; +use rand::seq::*; + +#[bench] +fn misc_gen_bool_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(0.18); + } + accum + }) +} + +#[bench] +fn misc_gen_bool_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(p); + p += 0.0001; + } + accum + }) +} + +#[bench] +fn misc_bernoulli_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + let d = rand::distributions::Bernoulli::new(0.18); + b.iter(|| { + // Can be evaluated at compile time. + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.sample(d); + } + accum + }) +} + +#[bench] +fn misc_bernoulli_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + let d = rand::distributions::Bernoulli::new(p); + accum ^= rng.sample(d); + p += 0.0001; + } + accum + }) +} + +macro_rules! sample_binomial { + ($name:ident, $n:expr, $p:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let (n, p) = ($n, $p); + b.iter(|| { + let d = rand::distributions::Binomial::new(n, p); + rng.sample(d) + }) + } + } +} + +sample_binomial!(misc_binomial_1, 1, 0.9); +sample_binomial!(misc_binomial_10, 10, 0.9); +sample_binomial!(misc_binomial_100, 100, 0.99); +sample_binomial!(misc_binomial_1000, 1000, 0.01); +sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); + +#[bench] +fn misc_shuffle_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 100]; + b.iter(|| { + rng.shuffle(x); + x[0] + }) +} + +#[bench] +fn misc_sample_iter_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e) + }) +} + +#[bench] +fn misc_sample_slice_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + sample_slice(&mut rng, x, 10) + }) +} + +#[bench] +fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + sample_slice_ref(&mut rng, x, 10) + }) +} + +macro_rules! sample_indices { + ($name:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + b.iter(|| { + sample_indices(&mut rng, $length, $amount) + }) + } + } +} + +sample_indices!(misc_sample_indices_10_of_1k, 10, 1000); +sample_indices!(misc_sample_indices_50_of_1k, 50, 1000); +sample_indices!(misc_sample_indices_100_of_1k, 100, 1000); + +#[bench] +fn gen_1k_iter_repeat(b: &mut Bencher) { + use std::iter; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +#[allow(deprecated)] +fn gen_1k_gen_iter(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec<u64> = rng.gen_iter().take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_sample_iter(b: &mut Bencher) { + use rand::distributions::{Distribution, Standard}; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_gen_array(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + // max supported array length is 32! + let v: [[u64; 32]; 4] = rng.gen(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_fill(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut buf = [0u64; 128]; + b.iter(|| { + rng.fill(&mut buf[..]); + buf + }); + b.bytes = 1024; +} diff --git a/rand-0.5.6/examples/monte-carlo.rs b/rand-0.5.6/examples/monte-carlo.rs new file mode 100644 index 000000000..c18108a14 --- /dev/null +++ b/rand-0.5.6/examples/monte-carlo.rs @@ -0,0 +1,52 @@ +// Copyright 2013-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Monte Carlo estimation of π +//! +//! Imagine that we have a square with sides of length 2 and a unit circle +//! (radius = 1), both centered at the origin. The areas are: +//! +//! ```text +//! area of circle = πr² = π * r * r = π +//! area of square = 2² = 4 +//! ``` +//! +//! The circle is entirely within the square, so if we sample many points +//! randomly from the square, roughly π / 4 of them should be inside the circle. +//! +//! We can use the above fact to estimate the value of π: pick many points in +//! the square at random, calculate the fraction that fall within the circle, +//! and multiply this fraction by 4. + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::distributions::{Distribution, Uniform}; + +fn main() { + let range = Uniform::new(-1.0f64, 1.0); + let mut rng = rand::thread_rng(); + + let total = 1_000_000; + let mut in_circle = 0; + + for _ in 0..total { + let a = range.sample(&mut rng); + let b = range.sample(&mut rng); + if a*a + b*b <= 1.0 { + in_circle += 1; + } + } + + // prints something close to 3.14159... + println!("π is approximately {}", 4. * (in_circle as f64) / (total as f64)); +} diff --git a/rand-0.5.6/examples/monty-hall.rs b/rand-0.5.6/examples/monty-hall.rs new file mode 100644 index 000000000..3750f8fab --- /dev/null +++ b/rand-0.5.6/examples/monty-hall.rs @@ -0,0 +1,117 @@ +// Copyright 2013-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ## Monty Hall Problem +//! +//! This is a simulation of the [Monty Hall Problem][]: +//! +//! > Suppose you're on a game show, and you're given the choice of three doors: +//! > Behind one door is a car; behind the others, goats. You pick a door, say +//! > No. 1, and the host, who knows what's behind the doors, opens another +//! > door, say No. 3, which has a goat. He then says to you, "Do you want to +//! > pick door No. 2?" Is it to your advantage to switch your choice? +//! +//! The rather unintuitive answer is that you will have a 2/3 chance of winning +//! if you switch and a 1/3 chance of winning if you don't, so it's better to +//! switch. +//! +//! This program will simulate the game show and with large enough simulation +//! steps it will indeed confirm that it is better to switch. +//! +//! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::Rng; +use rand::distributions::{Distribution, Uniform}; + +struct SimulationResult { + win: bool, + switch: bool, +} + +// Run a single simulation of the Monty Hall problem. +fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R) + -> SimulationResult { + let car = random_door.sample(rng); + + // This is our initial choice + let mut choice = random_door.sample(rng); + + // The game host opens a door + let open = game_host_open(car, choice, rng); + + // Shall we switch? + let switch = rng.gen(); + if switch { + choice = switch_door(choice, open); + } + + SimulationResult { win: choice == car, switch } +} + +// Returns the door the game host opens given our choice and knowledge of +// where the car is. The game host will never open the door with the car. +fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 { + let choices = free_doors(&[car, choice]); + rand::seq::sample_slice(rng, &choices, 1)[0] +} + +// Returns the door we switch to, given our current choice and +// the open door. There will only be one valid door. +fn switch_door(choice: u32, open: u32) -> u32 { + free_doors(&[choice, open])[0] +} + +fn free_doors(blocked: &[u32]) -> Vec<u32> { + (0..3).filter(|x| !blocked.contains(x)).collect() +} + +fn main() { + // The estimation will be more accurate with more simulations + let num_simulations = 10000; + + let mut rng = rand::thread_rng(); + let random_door = Uniform::new(0u32, 3); + + let (mut switch_wins, mut switch_losses) = (0, 0); + let (mut keep_wins, mut keep_losses) = (0, 0); + + println!("Running {} simulations...", num_simulations); + for _ in 0..num_simulations { + let result = simulate(&random_door, &mut rng); + + match (result.win, result.switch) { + (true, true) => switch_wins += 1, + (true, false) => keep_wins += 1, + (false, true) => switch_losses += 1, + (false, false) => keep_losses += 1, + } + } + + let total_switches = switch_wins + switch_losses; + let total_keeps = keep_wins + keep_losses; + + println!("Switched door {} times with {} wins and {} losses", + total_switches, switch_wins, switch_losses); + + println!("Kept our choice {} times with {} wins and {} losses", + total_keeps, keep_wins, keep_losses); + + // With a large number of simulations, the values should converge to + // 0.667 and 0.333 respectively. + println!("Estimated chance to win if we switch: {}", + switch_wins as f32 / total_switches as f32); + println!("Estimated chance to win if we don't: {}", + keep_wins as f32 / total_keeps as f32); +} diff --git a/rand-0.5.6/src/distributions/bernoulli.rs b/rand-0.5.6/src/distributions/bernoulli.rs new file mode 100644 index 000000000..2361fac0c --- /dev/null +++ b/rand-0.5.6/src/distributions/bernoulli.rs @@ -0,0 +1,120 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! The Bernoulli distribution. + +use Rng; +use distributions::Distribution; + +/// The Bernoulli distribution. +/// +/// This is a special case of the Binomial distribution where `n = 1`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Bernoulli, Distribution}; +/// +/// let d = Bernoulli::new(0.3); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a Bernoulli distribution", v); +/// ``` +/// +/// # Precision +/// +/// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`), +/// so only probabilities that are multiples of 2<sup>-64</sup> can be +/// represented. +#[derive(Clone, Copy, Debug)] +pub struct Bernoulli { + /// Probability of success, relative to the maximal integer. + p_int: u64, +} + +impl Bernoulli { + /// Construct a new `Bernoulli` with the given probability of success `p`. + /// + /// # Panics + /// + /// If `p < 0` or `p > 1`. + /// + /// # Precision + /// + /// For `p = 1.0`, the resulting distribution will always generate true. + /// For `p = 0.0`, the resulting distribution will always generate false. + /// + /// This method is accurate for any input `p` in the range `[0, 1]` which is + /// a multiple of 2<sup>-64</sup>. (Note that not all multiples of + /// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.) + #[inline] + pub fn new(p: f64) -> Bernoulli { + assert!((p >= 0.0) & (p <= 1.0), "Bernoulli::new not called with 0 <= p <= 0"); + // Technically, this should be 2^64 or `u64::MAX + 1` because we compare + // using `<` when sampling. However, `u64::MAX` rounds to an `f64` + // larger than `u64::MAX` anyway. + const MAX_P_INT: f64 = ::core::u64::MAX as f64; + let p_int = if p < 1.0 { + (p * MAX_P_INT) as u64 + } else { + // Avoid overflow: `MAX_P_INT` cannot be represented as u64. + ::core::u64::MAX + }; + Bernoulli { p_int } + } +} + +impl Distribution<bool> for Bernoulli { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { + // Make sure to always return true for p = 1.0. + if self.p_int == ::core::u64::MAX { + return true; + } + let r: u64 = rng.gen(); + r < self.p_int + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Bernoulli; + + #[test] + fn test_trivial() { + let mut r = ::test::rng(1); + let always_false = Bernoulli::new(0.0); + let always_true = Bernoulli::new(1.0); + for _ in 0..5 { + assert_eq!(r.sample::<bool, _>(&always_false), false); + assert_eq!(r.sample::<bool, _>(&always_true), true); + assert_eq!(Distribution::<bool>::sample(&always_false, &mut r), false); + assert_eq!(Distribution::<bool>::sample(&always_true, &mut r), true); + } + } + + #[test] + fn test_average() { + const P: f64 = 0.3; + let d = Bernoulli::new(P); + const N: u32 = 10_000_000; + + let mut sum: u32 = 0; + let mut rng = ::test::rng(2); + for _ in 0..N { + if d.sample(&mut rng) { + sum += 1; + } + } + let avg = (sum as f64) / (N as f64); + + assert!((avg - P).abs() < 1e-3); + } +} diff --git a/rand-0.5.6/src/distributions/binomial.rs b/rand-0.5.6/src/distributions/binomial.rs new file mode 100644 index 000000000..5eb03e388 --- /dev/null +++ b/rand-0.5.6/src/distributions/binomial.rs @@ -0,0 +1,178 @@ +// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The binomial distribution. + +use Rng; +use distributions::{Distribution, Bernoulli, Cauchy}; +use distributions::log_gamma::log_gamma; + +/// The binomial distribution `Binomial(n, p)`. +/// +/// This distribution has density function: +/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Binomial, Distribution}; +/// +/// let bin = Binomial::new(20, 0.3); +/// let v = bin.sample(&mut rand::thread_rng()); +/// println!("{} is from a binomial distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Binomial { + /// Number of trials. + n: u64, + /// Probability of success. + p: f64, +} + +impl Binomial { + /// Construct a new `Binomial` with the given shape parameters `n` (number + /// of trials) and `p` (probability of success). + /// + /// Panics if `p < 0` or `p > 1`. + pub fn new(n: u64, p: f64) -> Binomial { + assert!(p >= 0.0, "Binomial::new called with p < 0"); + assert!(p <= 1.0, "Binomial::new called with p > 1"); + Binomial { n, p } + } +} + +impl Distribution<u64> for Binomial { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + // Handle these values directly. + if self.p == 0.0 { + return 0; + } else if self.p == 1.0 { + return self.n; + } + + // For low n, it is faster to sample directly. For both methods, + // performance is independent of p. On Intel Haswell CPU this method + // appears to be faster for approx n < 300. + if self.n < 300 { + let mut result = 0; + let d = Bernoulli::new(self.p); + for _ in 0 .. self.n { + result += rng.sample(d) as u32; + } + return result as u64; + } + + // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k + // switch p so that it is less than 0.5 - this allows for lower expected values + // we will just invert the result at the end + let p = if self.p <= 0.5 { + self.p + } else { + 1.0 - self.p + }; + + // prepare some cached values + let float_n = self.n as f64; + let ln_fact_n = log_gamma(float_n + 1.0); + let pc = 1.0 - p; + let log_p = p.ln(); + let log_pc = pc.ln(); + let expected = self.n as f64 * p; + let sq = (expected * (2.0 * pc)).sqrt(); + + let mut lresult; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + loop { + let mut comp_dev: f64; + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + lresult = expected + sq * comp_dev; + // repeat the drawing until we are in the range of possible values + if lresult >= 0.0 && lresult < float_n + 1.0 { + break; + } + } + + // the result should be discrete + lresult = lresult.floor(); + + let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) - + log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc; + // this is the binomial probability divided by the comparison probability + // we will generate a uniform random value and if it is larger than this, + // we interpret it as a value falling out of the distribution and repeat + let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev)); + + if comparison_coeff >= rng.gen() { + break; + } + } + + // invert the result for p < 0.5 + if p != self.p { + self.n - lresult as u64 + } else { + lresult as u64 + } + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Binomial; + + fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) { + let binomial = Binomial::new(n, p); + + let expected_mean = n as f64 * p; + let expected_variance = n as f64 * p * (1.0 - p); + + let mut results = [0.0; 1000]; + for i in results.iter_mut() { *i = binomial.sample(rng) as f64; } + + let mean = results.iter().sum::<f64>() / results.len() as f64; + assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0); + + let variance = + results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>() + / results.len() as f64; + assert!((variance - expected_variance).abs() < expected_variance / 10.0); + } + + #[test] + fn test_binomial() { + let mut rng = ::test::rng(351); + test_binomial_mean_and_variance(150, 0.1, &mut rng); + test_binomial_mean_and_variance(70, 0.6, &mut rng); + test_binomial_mean_and_variance(40, 0.5, &mut rng); + test_binomial_mean_and_variance(20, 0.7, &mut rng); + test_binomial_mean_and_variance(20, 0.5, &mut rng); + } + + #[test] + fn test_binomial_end_points() { + let mut rng = ::test::rng(352); + assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0); + assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20); + } + + #[test] + #[should_panic] + fn test_binomial_invalid_lambda_neg() { + Binomial::new(20, -10.0); + } +} diff --git a/rand-0.5.6/src/distributions/cauchy.rs b/rand-0.5.6/src/distributions/cauchy.rs new file mode 100644 index 000000000..5ac55bd8b --- /dev/null +++ b/rand-0.5.6/src/distributions/cauchy.rs @@ -0,0 +1,116 @@ +// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Cauchy distribution. + +use Rng; +use distributions::Distribution; +use std::f64::consts::PI; + +/// The Cauchy distribution `Cauchy(median, scale)`. +/// +/// This distribution has a density function: +/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))` +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Cauchy, Distribution}; +/// +/// let cau = Cauchy::new(2.0, 5.0); +/// let v = cau.sample(&mut rand::thread_rng()); +/// println!("{} is from a Cauchy(2, 5) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Cauchy { + median: f64, + scale: f64 +} + +impl Cauchy { + /// Construct a new `Cauchy` with the given shape parameters + /// `median` the peak location and `scale` the scale factor. + /// Panics if `scale <= 0`. + pub fn new(median: f64, scale: f64) -> Cauchy { + assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0"); + Cauchy { + median, + scale + } + } +} + +impl Distribution<f64> for Cauchy { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + // sample from [0, 1) + let x = rng.gen::<f64>(); + // get standard cauchy random number + // note that π/2 is not exactly representable, even if x=0.5 the result is finite + let comp_dev = (PI * x).tan(); + // shift and scale according to parameters + let result = self.median + self.scale * comp_dev; + result + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Cauchy; + + fn median(mut numbers: &mut [f64]) -> f64 { + sort(&mut numbers); + let mid = numbers.len() / 2; + numbers[mid] + } + + fn sort(numbers: &mut [f64]) { + numbers.sort_by(|a, b| a.partial_cmp(b).unwrap()); + } + + #[test] + fn test_cauchy_median() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut numbers: [f64; 1000] = [0.0; 1000]; + for i in 0..1000 { + numbers[i] = cauchy.sample(&mut rng); + } + let median = median(&mut numbers); + println!("Cauchy median: {}", median); + assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_cauchy_mean() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut sum = 0.0; + for _ in 0..1000 { + sum += cauchy.sample(&mut rng); + } + let mean = sum / 1000.0; + println!("Cauchy mean: {}", mean); + // for a Cauchy distribution the mean should not converge + assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_zero() { + Cauchy::new(0.0, 0.0); + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_neg() { + Cauchy::new(0.0, -10.0); + } +} diff --git a/rand-0.5.6/src/distributions/exponential.rs b/rand-0.5.6/src/distributions/exponential.rs new file mode 100644 index 000000000..e8dbdc9c9 --- /dev/null +++ b/rand-0.5.6/src/distributions/exponential.rs @@ -0,0 +1,122 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The exponential distribution. + +use {Rng}; +use distributions::{ziggurat, ziggurat_tables, Distribution}; + +/// Samples floating-point numbers according to the exponential distribution, +/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or +/// sampling with `-rng.gen::<f64>().ln()`, but faster. +/// +/// See `Exp` for the general exponential distribution. +/// +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact +/// description in the paper was adjusted to use tables for the exponential +/// distribution rather than normal. +/// +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Exp1; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Exp1); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp1; + +// This could be done via `-rng.gen::<f64>().ln()` but that is slower. +impl Distribution<f64> for Exp1 { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + #[inline] + fn pdf(x: f64) -> f64 { + (-x).exp() + } + #[inline] + fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln() + } + + ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, + pdf, zero_case) + } +} + +/// The exponential distribution `Exp(lambda)`. +/// +/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)` +/// for `x > 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Exp, Distribution}; +/// +/// let exp = Exp::new(2.0); +/// let v = exp.sample(&mut rand::thread_rng()); +/// println!("{} is from a Exp(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp { + /// `lambda` stored as `1/lambda`, since this is what we scale by. + lambda_inverse: f64 +} + +impl Exp { + /// Construct a new `Exp` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + #[inline] + pub fn new(lambda: f64) -> Exp { + assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0"); + Exp { lambda_inverse: 1.0 / lambda } + } +} + +impl Distribution<f64> for Exp { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let n: f64 = rng.sample(Exp1); + n * self.lambda_inverse + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Exp; + + #[test] + fn test_exp() { + let exp = Exp::new(10.0); + let mut rng = ::test::rng(221); + for _ in 0..1000 { + assert!(exp.sample(&mut rng) >= 0.0); + } + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_zero() { + Exp::new(0.0); + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_neg() { + Exp::new(-10.0); + } +} diff --git a/rand-0.5.6/src/distributions/float.rs b/rand-0.5.6/src/distributions/float.rs new file mode 100644 index 000000000..005812244 --- /dev/null +++ b/rand-0.5.6/src/distributions/float.rs @@ -0,0 +1,206 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Basic floating-point number distributions + +use core::mem; +use Rng; +use distributions::{Distribution, Standard}; + +/// A distribution to sample floating point numbers uniformly in the half-open +/// interval `(0, 1]`, i.e. including 1 but not 0. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`] +/// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::OpenClosed01; +/// +/// let val: f32 = thread_rng().sample(OpenClosed01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: struct.Standard.html +/// [`Open01`]: struct.Open01.html +/// [`Uniform`]: uniform/struct.Uniform.html +#[derive(Clone, Copy, Debug)] +pub struct OpenClosed01; + +/// A distribution to sample floating point numbers uniformly in the open +/// interval `(0, 1)`, i.e. not including either endpoint. +/// +/// All values that can be generated are of the form `n * ε + ε/2`. For `f32` +/// the 22 most significant random bits of an `u32` are used, for `f64` 52 from +/// an `u64`. The conversion uses a transmute-based method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`] +/// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::Open01; +/// +/// let val: f32 = thread_rng().sample(Open01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: struct.Standard.html +/// [`OpenClosed01`]: struct.OpenClosed01.html +/// [`Uniform`]: uniform/struct.Uniform.html +#[derive(Clone, Copy, Debug)] +pub struct Open01; + + +pub(crate) trait IntoFloat { + type F; + + /// Helper method to combine the fraction and a contant exponent into a + /// float. + /// + /// Only the least significant bits of `self` may be set, 23 for `f32` and + /// 52 for `f64`. + /// The resulting value will fall in a range that depends on the exponent. + /// As an example the range with exponent 0 will be + /// [2<sup>0</sup>..2<sup>1</sup>), which is [1..2). + fn into_float_with_exponent(self, exponent: i32) -> Self::F; +} + +macro_rules! float_impls { + ($ty:ty, $uty:ty, $fraction_bits:expr, $exponent_bias:expr) => { + impl IntoFloat for $uty { + type F = $ty; + #[inline(always)] + fn into_float_with_exponent(self, exponent: i32) -> $ty { + // The exponent is encoded using an offset-binary representation + let exponent_bits = + (($exponent_bias + exponent) as $uty) << $fraction_bits; + unsafe { mem::transmute(self | exponent_bits) } + } + } + + impl Distribution<$ty> for Standard { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; [0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$ty>() * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $uty << precision) as $ty); + + let value: $uty = rng.gen(); + scale * (value >> (float_size - precision)) as $ty + } + } + + impl Distribution<$ty> for OpenClosed01 { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; (0, 1] interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$ty>() * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $uty << precision) as $ty); + + let value: $uty = rng.gen(); + let value = value >> (float_size - precision); + // Add 1 to shift up; will not overflow because of right-shift: + scale * (value + 1) as $ty + } + } + + impl Distribution<$ty> for Open01 { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Transmute-based method; 23/52 random bits; (0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + const EPSILON: $ty = 1.0 / (1u64 << $fraction_bits) as $ty; + let float_size = mem::size_of::<$ty>() * 8; + + let value: $uty = rng.gen(); + let fraction = value >> (float_size - $fraction_bits); + fraction.into_float_with_exponent(0) - (1.0 - EPSILON / 2.0) + } + } + } +} +float_impls! { f32, u32, 23, 127 } +float_impls! { f64, u64, 52, 1023 } + + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Open01, OpenClosed01}; + use rngs::mock::StepRng; + + const EPSILON32: f32 = ::core::f32::EPSILON; + const EPSILON64: f64 = ::core::f64::EPSILON; + + #[test] + fn standard_fp_edge_cases() { + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.gen::<f32>(), 0.0); + assert_eq!(zeros.gen::<f64>(), 0.0); + + let mut one32 = StepRng::new(1 << 8, 0); + assert_eq!(one32.gen::<f32>(), EPSILON32 / 2.0); + + let mut one64 = StepRng::new(1 << 11, 0); + assert_eq!(one64.gen::<f64>(), EPSILON64 / 2.0); + + let mut max = StepRng::new(!0, 0); + assert_eq!(max.gen::<f32>(), 1.0 - EPSILON32 / 2.0); + assert_eq!(max.gen::<f64>(), 1.0 - EPSILON64 / 2.0); + } + + #[test] + fn openclosed01_edge_cases() { + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<f32, _>(OpenClosed01), 0.0 + EPSILON32 / 2.0); + assert_eq!(zeros.sample::<f64, _>(OpenClosed01), 0.0 + EPSILON64 / 2.0); + + let mut one32 = StepRng::new(1 << 8, 0); + assert_eq!(one32.sample::<f32, _>(OpenClosed01), EPSILON32); + + let mut one64 = StepRng::new(1 << 11, 0); + assert_eq!(one64.sample::<f64, _>(OpenClosed01), EPSILON64); + + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<f32, _>(OpenClosed01), 1.0); + assert_eq!(max.sample::<f64, _>(OpenClosed01), 1.0); + } + + #[test] + fn open01_edge_cases() { + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<f32, _>(Open01), 0.0 + EPSILON32 / 2.0); + assert_eq!(zeros.sample::<f64, _>(Open01), 0.0 + EPSILON64 / 2.0); + + let mut one32 = StepRng::new(1 << 9, 0); + assert_eq!(one32.sample::<f32, _>(Open01), EPSILON32 / 2.0 * 3.0); + + let mut one64 = StepRng::new(1 << 12, 0); + assert_eq!(one64.sample::<f64, _>(Open01), EPSILON64 / 2.0 * 3.0); + + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<f32, _>(Open01), 1.0 - EPSILON32 / 2.0); + assert_eq!(max.sample::<f64, _>(Open01), 1.0 - EPSILON64 / 2.0); + } +} diff --git a/rand-0.5.6/src/distributions/gamma.rs b/rand-0.5.6/src/distributions/gamma.rs new file mode 100644 index 000000000..f02cf3b21 --- /dev/null +++ b/rand-0.5.6/src/distributions/gamma.rs @@ -0,0 +1,360 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Gamma and derived distributions. + +use self::GammaRepr::*; +use self::ChiSquaredRepr::*; + +use Rng; +use distributions::normal::StandardNormal; +use distributions::{Distribution, Exp, Open01}; + +/// The Gamma distribution `Gamma(shape, scale)` distribution. +/// +/// The density function of this distribution is +/// +/// ```text +/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k) +/// ``` +/// +/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the +/// scale and both `k` and `θ` are strictly positive. +/// +/// The algorithm used is that described by Marsaglia & Tsang 2000[^1], +/// falling back to directly sampling from an Exponential for `shape +/// == 1`, and using the boosting technique described in that paper for +/// `shape < 1`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Gamma}; +/// +/// let gamma = Gamma::new(2.0, 5.0); +/// let v = gamma.sample(&mut rand::thread_rng()); +/// println!("{} is from a Gamma(2, 5) distribution", v); +/// ``` +/// +/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for +/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 +/// (September 2000), 363-372. +/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414) +#[derive(Clone, Copy, Debug)] +pub struct Gamma { + repr: GammaRepr, +} + +#[derive(Clone, Copy, Debug)] +enum GammaRepr { + Large(GammaLargeShape), + One(Exp), + Small(GammaSmallShape) +} + +// These two helpers could be made public, but saving the +// match-on-Gamma-enum branch from using them directly (e.g. if one +// knows that the shape is always > 1) doesn't appear to be much +// faster. + +/// Gamma distribution where the shape parameter is less than 1. +/// +/// Note, samples from this require a compulsory floating-point `pow` +/// call, which makes it significantly slower than sampling from a +/// gamma distribution where the shape parameter is greater than or +/// equal to 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaSmallShape { + inv_shape: f64, + large_shape: GammaLargeShape +} + +/// Gamma distribution where the shape parameter is larger than 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaLargeShape { + scale: f64, + c: f64, + d: f64 +} + +impl Gamma { + /// Construct an object representing the `Gamma(shape, scale)` + /// distribution. + /// + /// Panics if `shape <= 0` or `scale <= 0`. + #[inline] + pub fn new(shape: f64, scale: f64) -> Gamma { + assert!(shape > 0.0, "Gamma::new called with shape <= 0"); + assert!(scale > 0.0, "Gamma::new called with scale <= 0"); + + let repr = if shape == 1.0 { + One(Exp::new(1.0 / scale)) + } else if shape < 1.0 { + Small(GammaSmallShape::new_raw(shape, scale)) + } else { + Large(GammaLargeShape::new_raw(shape, scale)) + }; + Gamma { repr } + } +} + +impl GammaSmallShape { + fn new_raw(shape: f64, scale: f64) -> GammaSmallShape { + GammaSmallShape { + inv_shape: 1. / shape, + large_shape: GammaLargeShape::new_raw(shape + 1.0, scale) + } + } +} + +impl GammaLargeShape { + fn new_raw(shape: f64, scale: f64) -> GammaLargeShape { + let d = shape - 1. / 3.; + GammaLargeShape { + scale, + c: 1. / (9. * d).sqrt(), + d + } + } +} + +impl Distribution<f64> for Gamma { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + match self.repr { + Small(ref g) => g.sample(rng), + One(ref g) => g.sample(rng), + Large(ref g) => g.sample(rng), + } + } +} +impl Distribution<f64> for GammaSmallShape { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(Open01); + + self.large_shape.sample(rng) * u.powf(self.inv_shape) + } +} +impl Distribution<f64> for GammaLargeShape { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + loop { + let x = rng.sample(StandardNormal); + let v_cbrt = 1.0 + self.c * x; + if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0 + continue + } + + let v = v_cbrt * v_cbrt * v_cbrt; + let u: f64 = rng.sample(Open01); + + let x_sqr = x * x; + if u < 1.0 - 0.0331 * x_sqr * x_sqr || + u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) { + return self.d * v * self.scale + } + } + } +} + +/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of +/// freedom. +/// +/// For `k > 0` integral, this distribution is the sum of the squares +/// of `k` independent standard normal random variables. For other +/// `k`, this uses the equivalent characterisation +/// `χ²(k) = Gamma(k/2, 2)`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{ChiSquared, Distribution}; +/// +/// let chi = ChiSquared::new(11.0); +/// let v = chi.sample(&mut rand::thread_rng()); +/// println!("{} is from a χ²(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct ChiSquared { + repr: ChiSquaredRepr, +} + +#[derive(Clone, Copy, Debug)] +enum ChiSquaredRepr { + // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1, + // e.g. when alpha = 1/2 as it would be for this case, so special- + // casing and using the definition of N(0,1)^2 is faster. + DoFExactlyOne, + DoFAnythingElse(Gamma), +} + +impl ChiSquared { + /// Create a new chi-squared distribution with degrees-of-freedom + /// `k`. Panics if `k < 0`. + pub fn new(k: f64) -> ChiSquared { + let repr = if k == 1.0 { + DoFExactlyOne + } else { + assert!(k > 0.0, "ChiSquared::new called with `k` < 0"); + DoFAnythingElse(Gamma::new(0.5 * k, 2.0)) + }; + ChiSquared { repr } + } +} +impl Distribution<f64> for ChiSquared { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + match self.repr { + DoFExactlyOne => { + // k == 1 => N(0,1)^2 + let norm = rng.sample(StandardNormal); + norm * norm + } + DoFAnythingElse(ref g) => g.sample(rng) + } + } +} + +/// The Fisher F distribution `F(m, n)`. +/// +/// This distribution is equivalent to the ratio of two normalised +/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) / +/// (χ²(n)/n)`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{FisherF, Distribution}; +/// +/// let f = FisherF::new(2.0, 32.0); +/// let v = f.sample(&mut rand::thread_rng()); +/// println!("{} is from an F(2, 32) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct FisherF { + numer: ChiSquared, + denom: ChiSquared, + // denom_dof / numer_dof so that this can just be a straight + // multiplication, rather than a division. + dof_ratio: f64, +} + +impl FisherF { + /// Create a new `FisherF` distribution, with the given + /// parameter. Panics if either `m` or `n` are not positive. + pub fn new(m: f64, n: f64) -> FisherF { + assert!(m > 0.0, "FisherF::new called with `m < 0`"); + assert!(n > 0.0, "FisherF::new called with `n < 0`"); + + FisherF { + numer: ChiSquared::new(m), + denom: ChiSquared::new(n), + dof_ratio: n / m + } + } +} +impl Distribution<f64> for FisherF { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio + } +} + +/// The Student t distribution, `t(nu)`, where `nu` is the degrees of +/// freedom. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{StudentT, Distribution}; +/// +/// let t = StudentT::new(11.0); +/// let v = t.sample(&mut rand::thread_rng()); +/// println!("{} is from a t(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StudentT { + chi: ChiSquared, + dof: f64 +} + +impl StudentT { + /// Create a new Student t distribution with `n` degrees of + /// freedom. Panics if `n <= 0`. + pub fn new(n: f64) -> StudentT { + assert!(n > 0.0, "StudentT::new called with `n <= 0`"); + StudentT { + chi: ChiSquared::new(n), + dof: n + } + } +} +impl Distribution<f64> for StudentT { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let norm = rng.sample(StandardNormal); + norm * (self.dof / self.chi.sample(rng)).sqrt() + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::{ChiSquared, StudentT, FisherF}; + + #[test] + fn test_chi_squared_one() { + let chi = ChiSquared::new(1.0); + let mut rng = ::test::rng(201); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + fn test_chi_squared_small() { + let chi = ChiSquared::new(0.5); + let mut rng = ::test::rng(202); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + fn test_chi_squared_large() { + let chi = ChiSquared::new(30.0); + let mut rng = ::test::rng(203); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_chi_squared_invalid_dof() { + ChiSquared::new(-1.0); + } + + #[test] + fn test_f() { + let f = FisherF::new(2.0, 32.0); + let mut rng = ::test::rng(204); + for _ in 0..1000 { + f.sample(&mut rng); + } + } + + #[test] + fn test_t() { + let t = StudentT::new(11.0); + let mut rng = ::test::rng(205); + for _ in 0..1000 { + t.sample(&mut rng); + } + } +} diff --git a/rand-0.5.6/src/distributions/integer.rs b/rand-0.5.6/src/distributions/integer.rs new file mode 100644 index 000000000..a23ddd51a --- /dev/null +++ b/rand-0.5.6/src/distributions/integer.rs @@ -0,0 +1,113 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for integer types. + +use {Rng}; +use distributions::{Distribution, Standard}; + +impl Distribution<u8> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 { + rng.next_u32() as u8 + } +} + +impl Distribution<u16> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u16 { + rng.next_u32() as u16 + } +} + +impl Distribution<u32> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u32 { + rng.next_u32() + } +} + +impl Distribution<u64> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + rng.next_u64() + } +} + +#[cfg(feature = "i128_support")] +impl Distribution<u128> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 { + // Use LE; we explicitly generate one value before the next. + let x = rng.next_u64() as u128; + let y = rng.next_u64() as u128; + (y << 64) | x + } +} + +impl Distribution<usize> for Standard { + #[inline] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + rng.next_u32() as usize + } + + #[inline] + #[cfg(target_pointer_width = "64")] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + rng.next_u64() as usize + } +} + +macro_rules! impl_int_from_uint { + ($ty:ty, $uty:ty) => { + impl Distribution<$ty> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + rng.gen::<$uty>() as $ty + } + } + } +} + +impl_int_from_uint! { i8, u8 } +impl_int_from_uint! { i16, u16 } +impl_int_from_uint! { i32, u32 } +impl_int_from_uint! { i64, u64 } +#[cfg(feature = "i128_support")] impl_int_from_uint! { i128, u128 } +impl_int_from_uint! { isize, usize } + + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Standard}; + + #[test] + fn test_integers() { + let mut rng = ::test::rng(806); + + rng.sample::<isize, _>(Standard); + rng.sample::<i8, _>(Standard); + rng.sample::<i16, _>(Standard); + rng.sample::<i32, _>(Standard); + rng.sample::<i64, _>(Standard); + #[cfg(feature = "i128_support")] + rng.sample::<i128, _>(Standard); + + rng.sample::<usize, _>(Standard); + rng.sample::<u8, _>(Standard); + rng.sample::<u16, _>(Standard); + rng.sample::<u32, _>(Standard); + rng.sample::<u64, _>(Standard); + #[cfg(feature = "i128_support")] + rng.sample::<u128, _>(Standard); + } +} diff --git a/rand-0.5.6/src/distributions/log_gamma.rs b/rand-0.5.6/src/distributions/log_gamma.rs new file mode 100644 index 000000000..f1fa3831f --- /dev/null +++ b/rand-0.5.6/src/distributions/log_gamma.rs @@ -0,0 +1,51 @@ +// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Calculates ln(gamma(x)) (natural logarithm of the gamma +/// function) using the Lanczos approximation. +/// +/// The approximation expresses the gamma function as: +/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)` +/// `g` is an arbitrary constant; we use the approximation with `g=5`. +/// +/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides: +/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)` +/// +/// `Ag(z)` is an infinite series with coefficients that can be calculated +/// ahead of time - we use just the first 6 terms, which is good enough +/// for most purposes. +pub fn log_gamma(x: f64) -> f64 { + // precalculated 6 coefficients for the first 6 terms of the series + let coefficients: [f64; 6] = [ + 76.18009172947146, + -86.50532032941677, + 24.01409824083091, + -1.231739572450155, + 0.1208650973866179e-2, + -0.5395239384953e-5, + ]; + + // (x+0.5)*ln(x+g+0.5)-(x+g+0.5) + let tmp = x + 5.5; + let log = (x + 0.5) * tmp.ln() - tmp; + + // the first few terms of the series for Ag(x) + let mut a = 1.000000000190015; + let mut denom = x; + for coeff in &coefficients { + denom += 1.0; + a += coeff / denom; + } + + // get everything together + // a is Ag(x) + // 2.5066... is sqrt(2pi) + log + (2.5066282746310005 * a / x).ln() +} diff --git a/rand-0.5.6/src/distributions/mod.rs b/rand-0.5.6/src/distributions/mod.rs new file mode 100644 index 000000000..24dd3a368 --- /dev/null +++ b/rand-0.5.6/src/distributions/mod.rs @@ -0,0 +1,784 @@ +// Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generating random samples from probability distributions. +//! +//! This module is the home of the [`Distribution`] trait and several of its +//! implementations. It is the workhorse behind some of the convenient +//! functionality of the [`Rng`] trait, including [`gen`], [`gen_range`] and +//! of course [`sample`]. +//! +//! Abstractly, a [probability distribution] describes the probability of +//! occurance of each value in its sample space. +//! +//! More concretely, an implementation of `Distribution<T>` for type `X` is an +//! algorithm for choosing values from the sample space (a subset of `T`) +//! according to the distribution `X` represents, using an external source of +//! randomness (an RNG supplied to the `sample` function). +//! +//! A type `X` may implement `Distribution<T>` for multiple types `T`. +//! Any type implementing [`Distribution`] is stateless (i.e. immutable), +//! but it may have internal parameters set at construction time (for example, +//! [`Uniform`] allows specification of its sample space as a range within `T`). +//! +//! +//! # The `Standard` distribution +//! +//! The [`Standard`] distribution is important to mention. This is the +//! distribution used by [`Rng::gen()`] and represents the "default" way to +//! produce a random value for many different types, including most primitive +//! types, tuples, arrays, and a few derived types. See the documentation of +//! [`Standard`] for more details. +//! +//! Implementing `Distribution<T>` for [`Standard`] for user types `T` makes it +//! possible to generate type `T` with [`Rng::gen()`], and by extension also +//! with the [`random()`] function. +//! +//! +//! # Distribution to sample from a `Uniform` range +//! +//! The [`Uniform`] distribution is more flexible than [`Standard`], but also +//! more specialised: it supports fewer target types, but allows the sample +//! space to be specified as an arbitrary range within its target type `T`. +//! Both [`Standard`] and [`Uniform`] are in some sense uniform distributions. +//! +//! Values may be sampled from this distribution using [`Rng::gen_range`] or +//! by creating a distribution object with [`Uniform::new`], +//! [`Uniform::new_inclusive`] or `From<Range>`. When the range limits are not +//! known at compile time it is typically faster to reuse an existing +//! distribution object than to call [`Rng::gen_range`]. +//! +//! User types `T` may also implement `Distribution<T>` for [`Uniform`], +//! although this is less straightforward than for [`Standard`] (see the +//! documentation in the [`uniform` module]. Doing so enables generation of +//! values of type `T` with [`Rng::gen_range`]. +//! +//! +//! # Other distributions +//! +//! There are surprisingly many ways to uniformly generate random floats. A +//! range between 0 and 1 is standard, but the exact bounds (open vs closed) +//! and accuracy differ. In addition to the [`Standard`] distribution Rand offers +//! [`Open01`] and [`OpenClosed01`]. See [Floating point implementation] for +//! more details. +//! +//! [`Alphanumeric`] is a simple distribution to sample random letters and +//! numbers of the `char` type; in contrast [`Standard`] may sample any valid +//! `char`. +//! +//! +//! # Non-uniform probability distributions +//! +//! Rand currently provides the following probability distributions: +//! +//! - Related to real-valued quantities that grow linearly +//! (e.g. errors, offsets): +//! - [`Normal`] distribution, and [`StandardNormal`] as a primitive +//! - [`Cauchy`] distribution +//! - Related to Bernoulli trials (yes/no events, with a given probability): +//! - [`Binomial`] distribution +//! - [`Bernoulli`] distribution, similar to [`Rng::gen_bool`]. +//! - Related to positive real-valued quantities that grow exponentially +//! (e.g. prices, incomes, populations): +//! - [`LogNormal`] distribution +//! - Related to the occurrence of independent events at a given rate: +//! - [`Poisson`] distribution +//! - [`Exp`]onential distribution, and [`Exp1`] as a primitive +//! - Gamma and derived distributions: +//! - [`Gamma`] distribution +//! - [`ChiSquared`] distribution +//! - [`StudentT`] distribution +//! - [`FisherF`] distribution +//! +//! +//! # Examples +//! +//! Sampling from a distribution: +//! +//! ``` +//! use rand::{thread_rng, Rng}; +//! use rand::distributions::Exp; +//! +//! let exp = Exp::new(2.0); +//! let v = thread_rng().sample(exp); +//! println!("{} is from an Exp(2) distribution", v); +//! ``` +//! +//! Implementing the [`Standard`] distribution for a user type: +//! +//! ``` +//! # #![allow(dead_code)] +//! use rand::Rng; +//! use rand::distributions::{Distribution, Standard}; +//! +//! struct MyF32 { +//! x: f32, +//! } +//! +//! impl Distribution<MyF32> for Standard { +//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> MyF32 { +//! MyF32 { x: rng.gen() } +//! } +//! } +//! ``` +//! +//! +//! [probability distribution]: https://en.wikipedia.org/wiki/Probability_distribution +//! [`Distribution`]: trait.Distribution.html +//! [`gen_range`]: ../trait.Rng.html#method.gen_range +//! [`gen`]: ../trait.Rng.html#method.gen +//! [`sample`]: ../trait.Rng.html#method.sample +//! [`new_inclusive`]: struct.Uniform.html#method.new_inclusive +//! [`random()`]: ../fn.random.html +//! [`Rng::gen_bool`]: ../trait.Rng.html#method.gen_bool +//! [`Rng::gen_range`]: ../trait.Rng.html#method.gen_range +//! [`Rng::gen()`]: ../trait.Rng.html#method.gen +//! [`Rng`]: ../trait.Rng.html +//! [`uniform` module]: uniform/index.html +//! [Floating point implementation]: struct.Standard.html#floating-point-implementation +// distributions +//! [`Alphanumeric`]: struct.Alphanumeric.html +//! [`Bernoulli`]: struct.Bernoulli.html +//! [`Binomial`]: struct.Binomial.html +//! [`Cauchy`]: struct.Cauchy.html +//! [`ChiSquared`]: struct.ChiSquared.html +//! [`Exp`]: struct.Exp.html +//! [`Exp1`]: struct.Exp1.html +//! [`FisherF`]: struct.FisherF.html +//! [`Gamma`]: struct.Gamma.html +//! [`LogNormal`]: struct.LogNormal.html +//! [`Normal`]: struct.Normal.html +//! [`Open01`]: struct.Open01.html +//! [`OpenClosed01`]: struct.OpenClosed01.html +//! [`Pareto`]: struct.Pareto.html +//! [`Poisson`]: struct.Poisson.html +//! [`Standard`]: struct.Standard.html +//! [`StandardNormal`]: struct.StandardNormal.html +//! [`StudentT`]: struct.StudentT.html +//! [`Uniform`]: struct.Uniform.html +//! [`Uniform::new`]: struct.Uniform.html#method.new +//! [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive + +use Rng; + +#[doc(inline)] pub use self::other::Alphanumeric; +#[doc(inline)] pub use self::uniform::Uniform; +#[doc(inline)] pub use self::float::{OpenClosed01, Open01}; +#[deprecated(since="0.5.0", note="use Uniform instead")] +pub use self::uniform::Uniform as Range; +#[cfg(feature="std")] +#[doc(inline)] pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT}; +#[cfg(feature="std")] +#[doc(inline)] pub use self::normal::{Normal, LogNormal, StandardNormal}; +#[cfg(feature="std")] +#[doc(inline)] pub use self::exponential::{Exp, Exp1}; +#[cfg(feature="std")] +#[doc(inline)] pub use self::pareto::Pareto; +#[cfg(feature = "std")] +#[doc(inline)] pub use self::poisson::Poisson; +#[cfg(feature = "std")] +#[doc(inline)] pub use self::binomial::Binomial; +#[doc(inline)] pub use self::bernoulli::Bernoulli; +#[cfg(feature = "std")] +#[doc(inline)] pub use self::cauchy::Cauchy; + +pub mod uniform; +#[cfg(feature="std")] +#[doc(hidden)] pub mod gamma; +#[cfg(feature="std")] +#[doc(hidden)] pub mod normal; +#[cfg(feature="std")] +#[doc(hidden)] pub mod exponential; +#[cfg(feature="std")] +#[doc(hidden)] pub mod pareto; +#[cfg(feature = "std")] +#[doc(hidden)] pub mod poisson; +#[cfg(feature = "std")] +#[doc(hidden)] pub mod binomial; +#[doc(hidden)] pub mod bernoulli; +#[cfg(feature = "std")] +#[doc(hidden)] pub mod cauchy; + +mod float; +mod integer; +#[cfg(feature="std")] +mod log_gamma; +mod other; +#[cfg(feature="std")] +mod ziggurat_tables; +#[cfg(feature="std")] +use distributions::float::IntoFloat; + +/// Types that can be used to create a random instance of `Support`. +#[deprecated(since="0.5.0", note="use Distribution instead")] +pub trait Sample<Support> { + /// Generate a random value of `Support`, using `rng` as the + /// source of randomness. + fn sample<R: Rng>(&mut self, rng: &mut R) -> Support; +} + +/// `Sample`s that do not require keeping track of state. +/// +/// Since no state is recorded, each sample is (statistically) +/// independent of all others, assuming the `Rng` used has this +/// property. +#[allow(deprecated)] +#[deprecated(since="0.5.0", note="use Distribution instead")] +pub trait IndependentSample<Support>: Sample<Support> { + /// Generate a random value. + fn ind_sample<R: Rng>(&self, &mut R) -> Support; +} + +/// DEPRECATED: Use `distributions::uniform` instead. +#[deprecated(since="0.5.0", note="use uniform instead")] +pub mod range { + pub use distributions::uniform::Uniform as Range; + pub use distributions::uniform::SampleUniform as SampleRange; +} + +#[allow(deprecated)] +mod impls { + use Rng; + use distributions::{Distribution, Sample, IndependentSample, + WeightedChoice}; + #[cfg(feature="std")] + use distributions::exponential::Exp; + #[cfg(feature="std")] + use distributions::gamma::{Gamma, ChiSquared, FisherF, StudentT}; + #[cfg(feature="std")] + use distributions::normal::{Normal, LogNormal}; + use distributions::range::{Range, SampleRange}; + + impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> { + fn sample<R: Rng>(&mut self, rng: &mut R) -> T { + Distribution::sample(self, rng) + } + } + impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> T { + Distribution::sample(self, rng) + } + } + + impl<T: SampleRange> Sample<T> for Range<T> { + fn sample<R: Rng>(&mut self, rng: &mut R) -> T { + Distribution::sample(self, rng) + } + } + impl<T: SampleRange> IndependentSample<T> for Range<T> { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> T { + Distribution::sample(self, rng) + } + } + + #[cfg(feature="std")] + macro_rules! impl_f64 { + ($($name: ident), *) => { + $( + impl Sample<f64> for $name { + fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { + Distribution::sample(self, rng) + } + } + impl IndependentSample<f64> for $name { + fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 { + Distribution::sample(self, rng) + } + } + )* + } + } + #[cfg(feature="std")] + impl_f64!(Exp, Gamma, ChiSquared, FisherF, StudentT, Normal, LogNormal); +} + +/// Types (distributions) that can be used to create a random instance of `T`. +/// +/// It is possible to sample from a distribution through both the +/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and +/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which +/// produces an iterator that samples from the distribution. +/// +/// All implementations are expected to be immutable; this has the significant +/// advantage of not needing to consider thread safety, and for most +/// distributions efficient state-less sampling algorithms are available. +/// +/// [`Rng`]: ../trait.Rng.html +/// [`sample_iter`]: trait.Distribution.html#method.sample_iter +pub trait Distribution<T> { + /// Generate a random value of `T`, using `rng` as the source of randomness. + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T; + + /// Create an iterator that generates random values of `T`, using `rng` as + /// the source of randomness. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect(); + /// + /// // String: + /// let s: String = Alphanumeric.sample_iter(&mut rng).take(7).collect(); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = die_range.sample_iter(&mut rng); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T> + where Self: Sized, R: Rng + { + DistIter { + distr: self, + rng: rng, + phantom: ::core::marker::PhantomData, + } + } +} + +impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { + (*self).sample(rng) + } +} + + +/// An iterator that generates random values of `T` with distribution `D`, +/// using `R` as the source of randomness. +/// +/// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. +/// See its documentation for more. +/// +/// [`Distribution`]: trait.Distribution.html +/// [`sample_iter`]: trait.Distribution.html#method.sample_iter +#[derive(Debug)] +pub struct DistIter<'a, D: 'a, R: 'a, T> { + distr: &'a D, + rng: &'a mut R, + phantom: ::core::marker::PhantomData<T>, +} + +impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> + where D: Distribution<T>, R: Rng + 'a +{ + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option<T> { + Some(self.distr.sample(self.rng)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (usize::max_value(), None) + } +} + + +/// A generic random value distribution, implemented for many primitive types. +/// Usually generates values with a numerically uniform distribution, and with a +/// range appropriate to the type. +/// +/// ## Built-in Implementations +/// +/// Assuming the provided `Rng` is well-behaved, these implementations +/// generate values with the following ranges and distributions: +/// +/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed +/// over all values of the type. +/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all +/// code points in the range `0...0x10_FFFF`, except for the range +/// `0xD800...0xDFFF` (the surrogate code points). This includes +/// unassigned/reserved code points. +/// * `bool`: Generates `false` or `true`, each with probability 0.5. +/// * Floating point types (`f32` and `f64`): Uniformly distributed in the +/// half-open range `[0, 1)`. See notes below. +/// * Wrapping integers (`Wrapping<T>`), besides the type identical to their +/// normal integer variants. +/// +/// The following aggregate types also implement the distribution `Standard` as +/// long as their component types implement it: +/// +/// * Tuples and arrays: Each element of the tuple or array is generated +/// independently, using the `Standard` distribution recursively. +/// * `Option<T>` where `Standard` is implemented for `T`: Returns `None` with +/// probability 0.5; otherwise generates a random `x: T` and returns `Some(x)`. +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Standard; +/// +/// let val: f32 = SmallRng::from_entropy().sample(Standard); +/// println!("f32 from [0, 1): {}", val); +/// ``` +/// +/// # Floating point implementation +/// The floating point implementations for `Standard` generate a random value in +/// the half-open interval `[0, 1)`, i.e. including 0 but not 1. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`. +/// +/// See also: [`Open01`] which samples from `(0, 1)`, [`OpenClosed01`] which +/// samples from `(0, 1]` and `Rng::gen_range(0, 1)` which also samples from +/// `[0, 1)`. Note that `Open01` and `gen_range` (which uses [`Uniform`]) use +/// transmute-based methods which yield 1 bit less precision but may perform +/// faster on some architectures (on modern Intel CPUs all methods have +/// approximately equal performance). +/// +/// [`Open01`]: struct.Open01.html +/// [`OpenClosed01`]: struct.OpenClosed01.html +/// [`Uniform`]: uniform/struct.Uniform.html +#[derive(Clone, Copy, Debug)] +pub struct Standard; + +#[allow(deprecated)] +impl<T> ::Rand for T where Standard: Distribution<T> { + fn rand<R: Rng>(rng: &mut R) -> Self { + Standard.sample(rng) + } +} + + +/// A value with a particular weight for use with `WeightedChoice`. +#[derive(Copy, Clone, Debug)] +pub struct Weighted<T> { + /// The numerical weight of this item + pub weight: u32, + /// The actual item which is being weighted + pub item: T, +} + +/// A distribution that selects from a finite collection of weighted items. +/// +/// Each item has an associated weight that influences how likely it +/// is to be chosen: higher weight is more likely. +/// +/// The `Clone` restriction is a limitation of the `Distribution` trait. +/// Note that `&T` is (cheaply) `Clone` for all `T`, as is `u32`, so one can +/// store references or indices into another vector. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Weighted, WeightedChoice, Distribution}; +/// +/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, +/// Weighted { weight: 4, item: 'b' }, +/// Weighted { weight: 1, item: 'c' }); +/// let wc = WeightedChoice::new(&mut items); +/// let mut rng = rand::thread_rng(); +/// for _ in 0..16 { +/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. +/// println!("{}", wc.sample(&mut rng)); +/// } +/// ``` +#[derive(Debug)] +pub struct WeightedChoice<'a, T:'a> { + items: &'a mut [Weighted<T>], + weight_range: Uniform<u32>, +} + +impl<'a, T: Clone> WeightedChoice<'a, T> { + /// Create a new `WeightedChoice`. + /// + /// Panics if: + /// + /// - `items` is empty + /// - the total weight is 0 + /// - the total weight is larger than a `u32` can contain. + pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> { + // strictly speaking, this is subsumed by the total weight == 0 case + assert!(!items.is_empty(), "WeightedChoice::new called with no items"); + + let mut running_total: u32 = 0; + + // we convert the list from individual weights to cumulative + // weights so we can binary search. This *could* drop elements + // with weight == 0 as an optimisation. + for item in items.iter_mut() { + running_total = match running_total.checked_add(item.weight) { + Some(n) => n, + None => panic!("WeightedChoice::new called with a total weight \ + larger than a u32 can contain") + }; + + item.weight = running_total; + } + assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); + + WeightedChoice { + items, + // we're likely to be generating numbers in this range + // relatively often, so might as well cache it + weight_range: Uniform::new(0, running_total) + } + } +} + +impl<'a, T: Clone> Distribution<T> for WeightedChoice<'a, T> { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { + // we want to find the first element that has cumulative + // weight > sample_weight, which we do by binary since the + // cumulative weights of self.items are sorted. + + // choose a weight in [0, total_weight) + let sample_weight = self.weight_range.sample(rng); + + // short circuit when it's the first item + if sample_weight < self.items[0].weight { + return self.items[0].item.clone(); + } + + let mut idx = 0; + let mut modifier = self.items.len(); + + // now we know that every possibility has an element to the + // left, so we can just search for the last element that has + // cumulative weight <= sample_weight, then the next one will + // be "it". (Note that this greatest element will never be the + // last element of the vector, since sample_weight is chosen + // in [0, total_weight) and the cumulative weight of the last + // one is exactly the total weight.) + while modifier > 1 { + let i = idx + modifier / 2; + if self.items[i].weight <= sample_weight { + // we're small, so look to the right, but allow this + // exact element still. + idx = i; + // we need the `/ 2` to round up otherwise we'll drop + // the trailing elements when `modifier` is odd. + modifier += 1; + } else { + // otherwise we're too big, so go left. (i.e. do + // nothing) + } + modifier /= 2; + } + self.items[idx + 1].item.clone() + } +} + +/// Sample a random number using the Ziggurat method (specifically the +/// ZIGNOR variant from Doornik 2005). Most of the arguments are +/// directly from the paper: +/// +/// * `rng`: source of randomness +/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. +/// * `X`: the $x_i$ abscissae. +/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) +/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ +/// * `pdf`: the probability density function +/// * `zero_case`: manual sampling from the tail when we chose the +/// bottom box (i.e. i == 0) + +// the perf improvement (25-50%) is definitely worth the extra code +// size from force-inlining. +#[cfg(feature="std")] +#[inline(always)] +fn ziggurat<R: Rng + ?Sized, P, Z>( + rng: &mut R, + symmetric: bool, + x_tab: ziggurat_tables::ZigTable, + f_tab: ziggurat_tables::ZigTable, + mut pdf: P, + mut zero_case: Z) + -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { + loop { + // As an optimisation we re-implement the conversion to a f64. + // From the remaining 12 most significant bits we use 8 to construct `i`. + // This saves us generating a whole extra random number, while the added + // precision of using 64 bits for f64 does not buy us much. + let bits = rng.next_u64(); + let i = bits as usize & 0xff; + + let u = if symmetric { + // Convert to a value in the range [2,4) and substract to get [-1,1) + // We can't convert to an open range directly, that would require + // substracting `3.0 - EPSILON`, which is not representable. + // It is possible with an extra step, but an open range does not + // seem neccesary for the ziggurat algorithm anyway. + (bits >> 12).into_float_with_exponent(1) - 3.0 + } else { + // Convert to a value in the range [1,2) and substract to get (0,1) + (bits >> 12).into_float_with_exponent(0) + - (1.0 - ::core::f64::EPSILON / 2.0) + }; + let x = u * x_tab[i]; + + let test_x = if symmetric { x.abs() } else {x}; + + // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) + if test_x < x_tab[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) { + return x; + } + } +} + +#[cfg(test)] +mod tests { + use Rng; + use rngs::mock::StepRng; + use super::{WeightedChoice, Weighted, Distribution}; + + #[test] + fn test_weighted_choice() { + // this makes assumptions about the internal implementation of + // WeightedChoice. It may fail when the implementation in + // `distributions::uniform::UniformInt` changes. + + macro_rules! t { + ($items:expr, $expected:expr) => {{ + let mut items = $items; + let mut total_weight = 0; + for item in &items { total_weight += item.weight; } + + let wc = WeightedChoice::new(&mut items); + let expected = $expected; + + // Use extremely large steps between the random numbers, because + // we test with small ranges and `UniformInt` is designed to prefer + // the most significant bits. + let mut rng = StepRng::new(0, !0 / (total_weight as u64)); + + for &val in expected.iter() { + assert_eq!(wc.sample(&mut rng), val) + } + }} + } + + t!([Weighted { weight: 1, item: 10}], [10]); + + // skip some + t!([Weighted { weight: 0, item: 20}, + Weighted { weight: 2, item: 21}, + Weighted { weight: 0, item: 22}, + Weighted { weight: 1, item: 23}], + [21, 21, 23]); + + // different weights + t!([Weighted { weight: 4, item: 30}, + Weighted { weight: 3, item: 31}], + [30, 31, 30, 31, 30, 31, 30]); + + // check that we're binary searching + // correctly with some vectors of odd + // length. + t!([Weighted { weight: 1, item: 40}, + Weighted { weight: 1, item: 41}, + Weighted { weight: 1, item: 42}, + Weighted { weight: 1, item: 43}, + Weighted { weight: 1, item: 44}], + [40, 41, 42, 43, 44]); + t!([Weighted { weight: 1, item: 50}, + Weighted { weight: 1, item: 51}, + Weighted { weight: 1, item: 52}, + Weighted { weight: 1, item: 53}, + Weighted { weight: 1, item: 54}, + Weighted { weight: 1, item: 55}, + Weighted { weight: 1, item: 56}], + [50, 54, 51, 55, 52, 56, 53]); + } + + #[test] + fn test_weighted_clone_initialization() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let clone = initial.clone(); + assert_eq!(initial.weight, clone.weight); + assert_eq!(initial.item, clone.item); + } + + #[test] #[should_panic] + fn test_weighted_clone_change_weight() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.weight = 5; + assert_eq!(initial.weight, clone.weight); + } + + #[test] #[should_panic] + fn test_weighted_clone_change_item() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.item = 5; + assert_eq!(initial.item, clone.item); + + } + + #[test] #[should_panic] + fn test_weighted_choice_no_items() { + WeightedChoice::<isize>::new(&mut []); + } + #[test] #[should_panic] + fn test_weighted_choice_zero_weight() { + WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, + Weighted { weight: 0, item: 1}]); + } + #[test] #[should_panic] + fn test_weighted_choice_weight_overflows() { + let x = ::core::u32::MAX / 2; // x + x + 2 is the overflow + WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, + Weighted { weight: 1, item: 1 }, + Weighted { weight: x, item: 2 }, + Weighted { weight: 1, item: 3 }]); + } + + #[test] #[allow(deprecated)] + fn test_backwards_compat_sample() { + use distributions::{Sample, IndependentSample}; + + struct Constant<T> { val: T } + impl<T: Copy> Sample<T> for Constant<T> { + fn sample<R: Rng>(&mut self, _: &mut R) -> T { self.val } + } + impl<T: Copy> IndependentSample<T> for Constant<T> { + fn ind_sample<R: Rng>(&self, _: &mut R) -> T { self.val } + } + + let mut sampler = Constant{ val: 293 }; + assert_eq!(sampler.sample(&mut ::test::rng(233)), 293); + assert_eq!(sampler.ind_sample(&mut ::test::rng(234)), 293); + } + + #[cfg(feature="std")] + #[test] #[allow(deprecated)] + fn test_backwards_compat_exp() { + use distributions::{IndependentSample, Exp}; + let sampler = Exp::new(1.0); + sampler.ind_sample(&mut ::test::rng(235)); + } + + #[cfg(feature="std")] + #[test] + fn test_distributions_iter() { + use distributions::Normal; + let mut rng = ::test::rng(210); + let distr = Normal::new(10.0, 10.0); + let results: Vec<_> = distr.sample_iter(&mut rng).take(100).collect(); + println!("{:?}", results); + } +} diff --git a/rand-0.5.6/src/distributions/normal.rs b/rand-0.5.6/src/distributions/normal.rs new file mode 100644 index 000000000..f053fb6c7 --- /dev/null +++ b/rand-0.5.6/src/distributions/normal.rs @@ -0,0 +1,192 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The normal and derived distributions. + +use Rng; +use distributions::{ziggurat, ziggurat_tables, Distribution, Open01}; + +/// Samples floating-point numbers according to the normal distribution +/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to +/// `Normal::new(0.0, 1.0)` but faster. +/// +/// See `Normal` for the general normal distribution. +/// +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. +/// +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::StandardNormal; +/// +/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StandardNormal; + +impl Distribution<f64> for StandardNormal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + #[inline] + fn pdf(x: f64) -> f64 { + (-x*x/2.0).exp() + } + #[inline] + fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // do-while, so the condition should be true on the first + // run, they get overwritten anyway (0 < 1, so these are + // good). + let mut x = 1.0f64; + let mut y = 0.0f64; + + while -2.0 * y < x * x { + let x_: f64 = rng.sample(Open01); + let y_: f64 = rng.sample(Open01); + + x = x_.ln() / ziggurat_tables::ZIG_NORM_R; + y = y_.ln(); + } + + if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x } + } + + ziggurat(rng, true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, + pdf, zero_case) + } +} + +/// The normal distribution `N(mean, std_dev**2)`. +/// +/// This uses the ZIGNOR variant of the Ziggurat method, see `StandardNormal` +/// for more details. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Normal, Distribution}; +/// +/// // mean 2, standard deviation 3 +/// let normal = Normal::new(2.0, 3.0); +/// let v = normal.sample(&mut rand::thread_rng()); +/// println!("{} is from a N(2, 9) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Normal { + mean: f64, + std_dev: f64, +} + +impl Normal { + /// Construct a new `Normal` distribution with the given mean and + /// standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> Normal { + assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); + Normal { + mean, + std_dev + } + } +} +impl Distribution<f64> for Normal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let n = rng.sample(StandardNormal); + self.mean + self.std_dev * n + } +} + + +/// The log-normal distribution `ln N(mean, std_dev**2)`. +/// +/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)` +/// distributed. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{LogNormal, Distribution}; +/// +/// // mean 2, standard deviation 3 +/// let log_normal = LogNormal::new(2.0, 3.0); +/// let v = log_normal.sample(&mut rand::thread_rng()); +/// println!("{} is from an ln N(2, 9) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct LogNormal { + norm: Normal +} + +impl LogNormal { + /// Construct a new `LogNormal` distribution with the given mean + /// and standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> LogNormal { + assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0"); + LogNormal { norm: Normal::new(mean, std_dev) } + } +} +impl Distribution<f64> for LogNormal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + self.norm.sample(rng).exp() + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::{Normal, LogNormal}; + + #[test] + fn test_normal() { + let norm = Normal::new(10.0, 10.0); + let mut rng = ::test::rng(210); + for _ in 0..1000 { + norm.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_normal_invalid_sd() { + Normal::new(10.0, -1.0); + } + + + #[test] + fn test_log_normal() { + let lnorm = LogNormal::new(10.0, 10.0); + let mut rng = ::test::rng(211); + for _ in 0..1000 { + lnorm.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_log_normal_invalid_sd() { + LogNormal::new(10.0, -1.0); + } +} diff --git a/rand-0.5.6/src/distributions/other.rs b/rand-0.5.6/src/distributions/other.rs new file mode 100644 index 000000000..f23d2b85e --- /dev/null +++ b/rand-0.5.6/src/distributions/other.rs @@ -0,0 +1,215 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for other built-in types. + +use core::char; +use core::num::Wrapping; + +use {Rng}; +use distributions::{Distribution, Standard, Uniform}; + +// ----- Sampling distributions ----- + +/// Sample a `char`, uniformly distributed over ASCII letters and numbers: +/// a-z, A-Z and 0-9. +/// +/// # Example +/// +/// ``` +/// use std::iter; +/// use rand::{Rng, thread_rng}; +/// use rand::distributions::Alphanumeric; +/// +/// let mut rng = thread_rng(); +/// let chars: String = iter::repeat(()) +/// .map(|()| rng.sample(Alphanumeric)) +/// .take(7) +/// .collect(); +/// println!("Random chars: {}", chars); +/// ``` +#[derive(Debug)] +pub struct Alphanumeric; + + +// ----- Implementations of distributions ----- + +impl Distribution<char> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { + let range = Uniform::new(0u32, 0x11_0000); + loop { + match char::from_u32(range.sample(rng)) { + Some(c) => return c, + // About 0.2% of numbers in the range 0..0x110000 are invalid + // codepoints (surrogates). + None => {} + } + } + } +} + +impl Distribution<char> for Alphanumeric { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { + const RANGE: u32 = 26 + 26 + 10; + const GEN_ASCII_STR_CHARSET: &[u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + // We can pick from 62 characters. This is so close to a power of 2, 64, + // that we can do better than `Uniform`. Use a simple bitshift and + // rejection sampling. We do not use a bitmask, because for small RNGs + // the most significant bits are usually of higher quality. + loop { + let var = rng.next_u32() >> (32 - 6); + if var < RANGE { + return GEN_ASCII_STR_CHARSET[var as usize] as char + } + } + } +} + +impl Distribution<bool> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { + // We can compare against an arbitrary bit of an u32 to get a bool. + // Because the least significant bits of a lower quality RNG can have + // simple patterns, we compare against the most significant bit. This is + // easiest done using a sign test. + (rng.next_u32() as i32) < 0 + } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< $( $tyvar ),* > + Distribution<( $( $tyvar ),* , )> + for Standard + where $( Standard: Distribution<$tyvar> ),* + { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) { + ( + // use the $tyvar's to get the appropriate number of + // repeats (they're not actually needed) + $( + _rng.gen::<$tyvar>() + ),* + , + ) + } + } + } +} + +impl Distribution<()> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () } +} +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +macro_rules! array_impl { + // recursive, given at least one type parameter: + {$n:expr, $t:ident, $($ts:ident,)*} => { + array_impl!{($n - 1), $($ts,)*} + + impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { + [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*] + } + } + }; + // empty case: + {$n:expr,} => { + impl<T> Distribution<[T; $n]> for Standard { + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] } + } + }; +} + +array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,} + +impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> { + // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066 + if rng.gen::<bool>() { + Some(rng.gen()) + } else { + None + } + } +} + +impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> { + Wrapping(rng.gen()) + } +} + + +#[cfg(test)] +mod tests { + use {Rng, RngCore, Standard}; + use distributions::Alphanumeric; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String; + + #[test] + fn test_misc() { + let rng: &mut RngCore = &mut ::test::rng(820); + + rng.sample::<char, _>(Standard); + rng.sample::<bool, _>(Standard); + } + + #[cfg(feature="alloc")] + #[test] + fn test_chars() { + use core::iter; + let mut rng = ::test::rng(805); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let word: String = iter::repeat(()) + .map(|()| rng.gen::<char>()).take(1000).collect(); + assert!(word.len() != 0); + } + + #[test] + fn test_alphanumeric() { + let mut rng = ::test::rng(806); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let mut incorrect = false; + for _ in 0..100 { + let c = rng.sample(Alphanumeric); + incorrect |= !((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') ); + } + assert!(incorrect == false); + } +} diff --git a/rand-0.5.6/src/distributions/pareto.rs b/rand-0.5.6/src/distributions/pareto.rs new file mode 100644 index 000000000..ba628e061 --- /dev/null +++ b/rand-0.5.6/src/distributions/pareto.rs @@ -0,0 +1,76 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Pareto distribution. + +use Rng; +use distributions::{Distribution, OpenClosed01}; + +/// Samples floating-point numbers according to the Pareto distribution +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Pareto; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.)); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Pareto { + scale: f64, + inv_neg_shape: f64, +} + +impl Pareto { + /// Construct a new Pareto distribution with given `scale` and `shape`. + /// + /// In the literature, `scale` is commonly written as x<sub>m</sub> or k and + /// `shape` is often written as α. + /// + /// # Panics + /// + /// `scale` and `shape` have to be non-zero and positive. + pub fn new(scale: f64, shape: f64) -> Pareto { + assert!((scale > 0.) & (shape > 0.)); + Pareto { scale, inv_neg_shape: -1.0 / shape } + } +} + +impl Distribution<f64> for Pareto { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(OpenClosed01); + self.scale * u.powf(self.inv_neg_shape) + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::Pareto; + + #[test] + #[should_panic] + fn invalid() { + Pareto::new(0., 0.); + } + + #[test] + fn sample() { + let scale = 1.0; + let shape = 2.0; + let d = Pareto::new(scale, shape); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + let r = d.sample(&mut rng); + assert!(r >= scale); + } + } +} diff --git a/rand-0.5.6/src/distributions/poisson.rs b/rand-0.5.6/src/distributions/poisson.rs new file mode 100644 index 000000000..bdecb7715 --- /dev/null +++ b/rand-0.5.6/src/distributions/poisson.rs @@ -0,0 +1,158 @@ +// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Poisson distribution. + +use Rng; +use distributions::{Distribution, Cauchy}; +use distributions::log_gamma::log_gamma; + +/// The Poisson distribution `Poisson(lambda)`. +/// +/// This distribution has a density function: +/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Poisson, Distribution}; +/// +/// let poi = Poisson::new(2.0); +/// let v = poi.sample(&mut rand::thread_rng()); +/// println!("{} is from a Poisson(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Poisson { + lambda: f64, + // precalculated values + exp_lambda: f64, + log_lambda: f64, + sqrt_2lambda: f64, + magic_val: f64, +} + +impl Poisson { + /// Construct a new `Poisson` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + pub fn new(lambda: f64) -> Poisson { + assert!(lambda > 0.0, "Poisson::new called with lambda <= 0"); + let log_lambda = lambda.ln(); + Poisson { + lambda, + exp_lambda: (-lambda).exp(), + log_lambda, + sqrt_2lambda: (2.0 * lambda).sqrt(), + magic_val: lambda * log_lambda - log_gamma(1.0 + lambda), + } + } +} + +impl Distribution<u64> for Poisson { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + // using the algorithm from Numerical Recipes in C + + // for low expected values use the Knuth method + if self.lambda < 12.0 { + let mut result = 0; + let mut p = 1.0; + while p > self.exp_lambda { + p *= rng.gen::<f64>(); + result += 1; + } + result - 1 + } + // high expected values - rejection method + else { + let mut int_result: u64; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + + loop { + let mut result; + let mut comp_dev; + + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + result = self.sqrt_2lambda * comp_dev + self.lambda; + // repeat the drawing until we are in the range of possible values + if result >= 0.0 { + break; + } + } + // now the result is a random variable greater than 0 with Cauchy distribution + // the result should be an integer value + result = result.floor(); + int_result = result as u64; + + // this is the ratio of the Poisson distribution to the comparison distribution + // the magic value scales the distribution function to a range of approximately 0-1 + // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1 + // this doesn't change the resulting distribution, only increases the rate of failed drawings + let check = 0.9 * (1.0 + comp_dev * comp_dev) + * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp(); + + // check with uniform random value - if below the threshold, we are within the target distribution + if rng.gen::<f64>() <= check { + break; + } + } + int_result + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Poisson; + + #[test] + fn test_poisson_10() { + let poisson = Poisson::new(10.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_poisson_15() { + // Take the 'high expected values' path + let poisson = Poisson::new(15.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_zero() { + Poisson::new(0.0); + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_neg() { + Poisson::new(-10.0); + } +} diff --git a/rand-0.5.6/src/distributions/uniform.rs b/rand-0.5.6/src/distributions/uniform.rs new file mode 100644 index 000000000..8fda0319f --- /dev/null +++ b/rand-0.5.6/src/distributions/uniform.rs @@ -0,0 +1,856 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A distribution uniformly sampling numbers within a given range. +//! +//! [`Uniform`] is the standard distribution to sample uniformly from a range; +//! e.g. `Uniform::new_inclusive(1, 6)` can sample integers from 1 to 6, like a +//! standard die. [`Rng::gen_range`] supports any type supported by +//! [`Uniform`]. +//! +//! This distribution is provided with support for several primitive types +//! (all integer and floating-point types) as well as `std::time::Duration`, +//! and supports extension to user-defined types via a type-specific *back-end* +//! implementation. +//! +//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the +//! back-ends supporting sampling from primitive integer and floating-point +//! ranges as well as from `std::time::Duration`; these types do not normally +//! need to be used directly (unless implementing a derived back-end). +//! +//! # Example usage +//! +//! ``` +//! use rand::{Rng, thread_rng}; +//! use rand::distributions::Uniform; +//! +//! let mut rng = thread_rng(); +//! let side = Uniform::new(-10.0, 10.0); +//! +//! // sample between 1 and 10 points +//! for _ in 0..rng.gen_range(1, 11) { +//! // sample a point from the square with sides -10 - 10 in two dimensions +//! let (x, y) = (rng.sample(side), rng.sample(side)); +//! println!("Point: {}, {}", x, y); +//! } +//! ``` +//! +//! # Extending `Uniform` to support a custom type +//! +//! To extend [`Uniform`] to support your own types, write a back-end which +//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`] +//! helper trait to "register" your back-end. See the `MyF32` example below. +//! +//! At a minimum, the back-end needs to store any parameters needed for sampling +//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`. +//! Those methods should include an assert to check the range is valid (i.e. +//! `low < high`). The example below merely wraps another back-end. +//! +//! ``` +//! use rand::prelude::*; +//! use rand::distributions::uniform::{Uniform, SampleUniform, +//! UniformSampler, UniformFloat}; +//! +//! struct MyF32(f32); +//! +//! #[derive(Clone, Copy, Debug)] +//! struct UniformMyF32 { +//! inner: UniformFloat<f32>, +//! } +//! +//! impl UniformSampler for UniformMyF32 { +//! type X = MyF32; +//! fn new(low: Self::X, high: Self::X) -> Self { +//! UniformMyF32 { +//! inner: UniformFloat::<f32>::new(low.0, high.0), +//! } +//! } +//! fn new_inclusive(low: Self::X, high: Self::X) -> Self { +//! UniformSampler::new(low, high) +//! } +//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { +//! MyF32(self.inner.sample(rng)) +//! } +//! } +//! +//! impl SampleUniform for MyF32 { +//! type Sampler = UniformMyF32; +//! } +//! +//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32)); +//! let uniform = Uniform::new(low, high); +//! let x = uniform.sample(&mut thread_rng()); +//! ``` +//! +//! [`Uniform`]: struct.Uniform.html +//! [`Rng::gen_range`]: ../../trait.Rng.html#method.gen_range +//! [`SampleUniform`]: trait.SampleUniform.html +//! [`UniformSampler`]: trait.UniformSampler.html +//! [`UniformInt`]: struct.UniformInt.html +//! [`UniformFloat`]: struct.UniformFloat.html +//! [`UniformDuration`]: struct.UniformDuration.html + +#[cfg(feature = "std")] +use std::time::Duration; + +use Rng; +use distributions::Distribution; +use distributions::float::IntoFloat; + +/// Sample values uniformly between two bounds. +/// +/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform +/// distribution sampling from the given range; these functions may do extra +/// work up front to make sampling of multiple values faster. +/// +/// When sampling from a constant range, many calculations can happen at +/// compile-time and all methods should be fast; for floating-point ranges and +/// the full range of integer types this should have comparable performance to +/// the `Standard` distribution. +/// +/// Steps are taken to avoid bias which might be present in naive +/// implementations; for example `rng.gen::<u8>() % 170` samples from the range +/// `[0, 169]` but is twice as likely to select numbers less than 85 than other +/// values. Further, the implementations here give more weight to the high-bits +/// generated by the RNG than the low bits, since with some RNGs the low-bits +/// are of lower quality than the high bits. +/// +/// Implementations should attempt to sample in `[low, high)` for +/// `Uniform::new(low, high)`, i.e., excluding `high`, but this may be very +/// difficult. All the primitive integer types satisfy this property, and the +/// float types normally satisfy it, but rounding may mean `high` can occur. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Uniform}; +/// +/// fn main() { +/// let between = Uniform::from(10..10000); +/// let mut rng = rand::thread_rng(); +/// let mut sum = 0; +/// for _ in 0..1000 { +/// sum += between.sample(&mut rng); +/// } +/// println!("{}", sum); +/// } +/// ``` +/// +/// [`Uniform::new`]: struct.Uniform.html#method.new +/// [`Uniform::new_inclusive`]: struct.Uniform.html#method.new_inclusive +/// [`new`]: struct.Uniform.html#method.new +/// [`new_inclusive`]: struct.Uniform.html#method.new_inclusive +#[derive(Clone, Copy, Debug)] +pub struct Uniform<X: SampleUniform> { + inner: X::Sampler, +} + +impl<X: SampleUniform> Uniform<X> { + /// Create a new `Uniform` instance which samples uniformly from the half + /// open range `[low, high)` (excluding `high`). Panics if `low >= high`. + pub fn new(low: X, high: X) -> Uniform<X> { + Uniform { inner: X::Sampler::new(low, high) } + } + + /// Create a new `Uniform` instance which samples uniformly from the closed + /// range `[low, high]` (inclusive). Panics if `low > high`. + pub fn new_inclusive(low: X, high: X) -> Uniform<X> { + Uniform { inner: X::Sampler::new_inclusive(low, high) } + } +} + +impl<X: SampleUniform> Distribution<X> for Uniform<X> { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X { + self.inner.sample(rng) + } +} + +/// Helper trait for creating objects using the correct implementation of +/// [`UniformSampler`] for the sampling type. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// [`UniformSampler`]: trait.UniformSampler.html +/// [module documentation]: index.html +/// [`Uniform`]: struct.Uniform.html +pub trait SampleUniform: Sized { + /// The `UniformSampler` implementation supporting type `X`. + type Sampler: UniformSampler<X = Self>; +} + +/// Helper trait handling actual uniform sampling. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// Implementation of [`sample_single`] is optional, and is only useful when +/// the implementation can be faster than `Self::new(low, high).sample(rng)`. +/// +/// [module documentation]: index.html +/// [`Uniform`]: struct.Uniform.html +/// [`sample_single`]: trait.UniformSampler.html#method.sample_single +pub trait UniformSampler: Sized { + /// The type sampled by this implementation. + type X; + + /// Construct self, with inclusive lower bound and exclusive upper bound + /// `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new`, which asserts that `low < high` before calling this. + fn new(low: Self::X, high: Self::X) -> Self; + + /// Construct self, with inclusive bounds `[low, high]`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new_inclusive`, which asserts that `low <= high` before + /// calling this. + fn new_inclusive(low: Self::X, high: Self::X) -> Self; + + /// Sample a value. + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X; + + /// Sample a single value uniformly from a range with inclusive lower bound + /// and exclusive upper bound `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::sample_single`, which asserts that `low < high` before calling + /// this. + /// + /// Via this method, implementations can provide a method optimized for + /// sampling only a single value from the specified range. The default + /// implementation simply calls `UniformSampler::new` then `sample` on the + /// result. + fn sample_single<R: Rng + ?Sized>(low: Self::X, high: Self::X, rng: &mut R) + -> Self::X + { + let uniform: Self = UniformSampler::new(low, high); + uniform.sample(rng) + } +} + +impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> { + fn from(r: ::core::ops::Range<X>) -> Uniform<X> { + Uniform::new(r.start, r.end) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// What follows are all back-ends. + + +/// The back-end implementing [`UniformSampler`] for integer types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// For a closed range, the number of possible numbers we should generate is +/// `range = (high - low + 1)`. It is not possible to end up with a uniform +/// distribution if we map *all* the random integers that can be generated to +/// this range. We have to map integers from a `zone` that is a multiple of the +/// range. The rest of the integers, that cause a bias, are rejected. +/// +/// The problem with `range` is that to cover the full range of the type, it has +/// to store `unsigned_max + 1`, which can't be represented. But if the range +/// covers the full range of the type, no modulus is needed. A range of size 0 +/// can't exist, so we use that to represent this special case. Wrapping +/// arithmetic even makes representing `unsigned_max + 1` as 0 simple. +/// +/// We don't calculate `zone` directly, but first calculate the number of +/// integers to reject. To handle `unsigned_max + 1` not fitting in the type, +/// we use: +/// `ints_to_reject = (unsigned_max + 1) % range;` +/// `ints_to_reject = (unsigned_max - range + 1) % range;` +/// +/// The smallest integer PRNGs generate is `u32`. That is why for small integer +/// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization: don't pick the +/// largest zone that can fit in the small type, but pick the largest zone that +/// can fit in an `u32`. `ints_to_reject` is always less than half the size of +/// the small integer. This means the first bit of `zone` is always 1, and so +/// are all the other preceding bits of a larger integer. The easiest way to +/// grow the `zone` for the larger type is to simply sign extend it. +/// +/// An alternative to using a modulus is widening multiply: After a widening +/// multiply by `range`, the result is in the high word. Then comparing the low +/// word against `zone` makes sure our distribution is uniform. +/// +/// [`UniformSampler`]: trait.UniformSampler.html +/// [`Uniform`]: struct.Uniform.html +#[derive(Clone, Copy, Debug)] +pub struct UniformInt<X> { + low: X, + range: X, + zone: X, +} + +macro_rules! uniform_int_impl { + ($ty:ty, $signed:ty, $unsigned:ident, + $i_large:ident, $u_large:ident) => { + impl SampleUniform for $ty { + type Sampler = UniformInt<$ty>; + } + + impl UniformSampler for UniformInt<$ty> { + // We play free and fast with unsigned vs signed here + // (when $ty is signed), but that's fine, since the + // contract of this macro is for $ty and $unsigned to be + // "bit-equal", so casting between them is a no-op. + + type X = $ty; + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new(low: Self::X, high: Self::X) -> Self { + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformSampler::new_inclusive(low, high - 1) + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive(low: Self::X, high: Self::X) -> Self { + assert!(low <= high, + "Uniform::new_inclusive called with `low > high`"); + let unsigned_max = ::core::$unsigned::MAX; + + let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned; + let ints_to_reject = + if range > 0 { + (unsigned_max - range + 1) % range + } else { + 0 + }; + let zone = unsigned_max - ints_to_reject; + + UniformInt { + low: low, + // These are really $unsigned values, but store as $ty: + range: range as $ty, + zone: zone as $ty + } + } + + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + let range = self.range as $unsigned as $u_large; + if range > 0 { + // Grow `zone` to fit a type of at least 32 bits, by + // sign-extending it (the first bit is always 1, so are all + // the preceding bits of the larger type). + // For types that already have the right size, all the + // casting is a no-op. + let zone = self.zone as $signed as $i_large as $u_large; + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return self.low.wrapping_add(hi as $ty); + } + } + } else { + // Sample from the entire integer range. + rng.gen() + } + } + + fn sample_single<R: Rng + ?Sized>(low: Self::X, + high: Self::X, + rng: &mut R) -> Self::X + { + assert!(low < high, + "Uniform::sample_single called with low >= high"); + let range = high.wrapping_sub(low) as $unsigned as $u_large; + let zone = + if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned { + // Using a modulus is faster than the approximation for + // i8 and i16. I suppose we trade the cost of one + // modulus for near-perfect branch prediction. + let unsigned_max: $u_large = ::core::$u_large::MAX; + let ints_to_reject = (unsigned_max - range + 1) % range; + unsigned_max - ints_to_reject + } else { + // conservative but fast approximation + range << range.leading_zeros() + }; + + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return low.wrapping_add(hi as $ty); + } + } + } + } + } +} + +uniform_int_impl! { i8, i8, u8, i32, u32 } +uniform_int_impl! { i16, i16, u16, i32, u32 } +uniform_int_impl! { i32, i32, u32, i32, u32 } +uniform_int_impl! { i64, i64, u64, i64, u64 } +#[cfg(feature = "i128_support")] +uniform_int_impl! { i128, i128, u128, u128, u128 } +uniform_int_impl! { isize, isize, usize, isize, usize } +uniform_int_impl! { u8, i8, u8, i32, u32 } +uniform_int_impl! { u16, i16, u16, i32, u32 } +uniform_int_impl! { u32, i32, u32, i32, u32 } +uniform_int_impl! { u64, i64, u64, i64, u64 } +uniform_int_impl! { usize, isize, usize, isize, usize } +#[cfg(feature = "i128_support")] +uniform_int_impl! { u128, u128, u128, i128, u128 } + + +trait WideningMultiply<RHS = Self> { + type Output; + + fn wmul(self, x: RHS) -> Self::Output; +} + +macro_rules! wmul_impl { + ($ty:ty, $wide:ty, $shift:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + let tmp = (self as $wide) * (x as $wide); + ((tmp >> $shift) as $ty, tmp as $ty) + } + } + } +} +wmul_impl! { u8, u16, 8 } +wmul_impl! { u16, u32, 16 } +wmul_impl! { u32, u64, 32 } +#[cfg(feature = "i128_support")] +wmul_impl! { u64, u128, 64 } + +// This code is a translation of the __mulddi3 function in LLVM's +// compiler-rt. It is an optimised variant of the common method +// `(a + b) * (c + d) = ac + ad + bc + bd`. +// +// For some reason LLVM can optimise the C version very well, but +// keeps shuffeling registers in this Rust translation. +macro_rules! wmul_impl_large { + ($ty:ty, $half:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, b: $ty) -> Self::Output { + const LOWER_MASK: $ty = !0 >> $half; + let mut low = (self & LOWER_MASK).wrapping_mul(b & LOWER_MASK); + let mut t = low >> $half; + low &= LOWER_MASK; + t += (self >> $half).wrapping_mul(b & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + let mut high = t >> $half; + t = low >> $half; + low &= LOWER_MASK; + t += (b >> $half).wrapping_mul(self & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + high += t >> $half; + high += (self >> $half).wrapping_mul(b >> $half); + + (high, low) + } + } + } +} +#[cfg(not(feature = "i128_support"))] +wmul_impl_large! { u64, 32 } +#[cfg(feature = "i128_support")] +wmul_impl_large! { u128, 64 } + +macro_rules! wmul_impl_usize { + ($ty:ty) => { + impl WideningMultiply for usize { + type Output = (usize, usize); + + #[inline(always)] + fn wmul(self, x: usize) -> Self::Output { + let (high, low) = (self as $ty).wmul(x as $ty); + (high as usize, low as usize) + } + } + } +} +#[cfg(target_pointer_width = "32")] +wmul_impl_usize! { u32 } +#[cfg(target_pointer_width = "64")] +wmul_impl_usize! { u64 } + + + +/// The back-end implementing [`UniformSampler`] for floating-point types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the +/// `UniformFloat` implementation converts the output of an PRNG itself. This +/// way one or two steps can be optimized out. +/// +/// The floats are first converted to a value in the `[1, 2)` interval using a +/// transmute-based method, and then mapped to the expected range with a +/// multiply and addition. Values produced this way have what equals 22 bits of +/// random digits for an `f32`, and 52 for an `f64`. +/// +/// Currently there is no difference between [`new`] and [`new_inclusive`], +/// because the boundaries of a floats range are a bit of a fuzzy concept due to +/// rounding errors. +/// +/// [`UniformSampler`]: trait.UniformSampler.html +/// [`new`]: trait.UniformSampler.html#tymethod.new +/// [`new_inclusive`]: trait.UniformSampler.html#tymethod.new_inclusive +/// [`Uniform`]: struct.Uniform.html +/// [`Standard`]: ../struct.Standard.html +#[derive(Clone, Copy, Debug)] +pub struct UniformFloat<X> { + scale: X, + offset: X, +} + +macro_rules! uniform_float_impl { + ($ty:ty, $bits_to_discard:expr, $next_u:ident) => { + impl SampleUniform for $ty { + type Sampler = UniformFloat<$ty>; + } + + impl UniformSampler for UniformFloat<$ty> { + type X = $ty; + + fn new(low: Self::X, high: Self::X) -> Self { + assert!(low < high, "Uniform::new called with `low >= high`"); + let scale = high - low; + let offset = low - scale; + UniformFloat { + scale: scale, + offset: offset, + } + } + + fn new_inclusive(low: Self::X, high: Self::X) -> Self { + assert!(low <= high, + "Uniform::new_inclusive called with `low > high`"); + let scale = high - low; + let offset = low - scale; + UniformFloat { + scale: scale, + offset: offset, + } + } + + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + // Generate a value in the range [1, 2) + let value1_2 = (rng.$next_u() >> $bits_to_discard) + .into_float_with_exponent(0); + // We don't use `f64::mul_add`, because it is not available with + // `no_std`. Furthermore, it is slower for some targets (but + // faster for others). However, the order of multiplication and + // addition is important, because on some platforms (e.g. ARM) + // it will be optimized to a single (non-FMA) instruction. + value1_2 * self.scale + self.offset + } + + fn sample_single<R: Rng + ?Sized>(low: Self::X, + high: Self::X, + rng: &mut R) -> Self::X { + assert!(low < high, + "Uniform::sample_single called with low >= high"); + let scale = high - low; + let offset = low - scale; + // Generate a value in the range [1, 2) + let value1_2 = (rng.$next_u() >> $bits_to_discard) + .into_float_with_exponent(0); + // Doing multiply before addition allows some architectures to + // use a single instruction. + value1_2 * scale + offset + } + } + } +} + +uniform_float_impl! { f32, 32 - 23, next_u32 } +uniform_float_impl! { f64, 64 - 52, next_u64 } + + + +/// The back-end implementing [`UniformSampler`] for `Duration`. +/// +/// Unless you are implementing [`UniformSampler`] for your own types, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// [`UniformSampler`]: trait.UniformSampler.html +/// [`Uniform`]: struct.Uniform.html +#[cfg(feature = "std")] +#[derive(Clone, Copy, Debug)] +pub struct UniformDuration { + offset: Duration, + mode: UniformDurationMode, +} + +#[cfg(feature = "std")] +#[derive(Debug, Copy, Clone)] +enum UniformDurationMode { + Small { + nanos: Uniform<u64>, + }, + Large { + size: Duration, + secs: Uniform<u64>, + } +} + +#[cfg(feature = "std")] +impl SampleUniform for Duration { + type Sampler = UniformDuration; +} + +#[cfg(feature = "std")] +impl UniformSampler for UniformDuration { + type X = Duration; + + #[inline] + fn new(low: Duration, high: Duration) -> UniformDuration { + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformDuration::new_inclusive(low, high - Duration::new(0, 1)) + } + + #[inline] + fn new_inclusive(low: Duration, high: Duration) -> UniformDuration { + assert!(low <= high, "Uniform::new_inclusive called with `low > high`"); + let size = high - low; + let nanos = size + .as_secs() + .checked_mul(1_000_000_000) + .and_then(|n| n.checked_add(size.subsec_nanos() as u64)); + + let mode = match nanos { + Some(nanos) => { + UniformDurationMode::Small { + nanos: Uniform::new_inclusive(0, nanos), + } + } + None => { + UniformDurationMode::Large { + size: size, + secs: Uniform::new_inclusive(0, size.as_secs()), + } + } + }; + + UniformDuration { + mode, + offset: low, + } + } + + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration { + let d = match self.mode { + UniformDurationMode::Small { nanos } => { + let nanos = nanos.sample(rng); + Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32) + } + UniformDurationMode::Large { size, secs } => { + // constant folding means this is at least as fast as `gen_range` + let nano_range = Uniform::new(0, 1_000_000_000); + loop { + let d = Duration::new(secs.sample(rng), nano_range.sample(rng)); + if d <= size { + break d; + } + } + } + }; + + self.offset + d + } +} + +#[cfg(test)] +mod tests { + use Rng; + use distributions::uniform::{Uniform, UniformSampler, UniformFloat, SampleUniform}; + + #[should_panic] + #[test] + fn test_uniform_bad_limits_equal_int() { + Uniform::new(10, 10); + } + + #[should_panic] + #[test] + fn test_uniform_bad_limits_equal_float() { + Uniform::new(10., 10.); + } + + #[test] + fn test_uniform_good_limits_equal_int() { + let mut rng = ::test::rng(804); + let dist = Uniform::new_inclusive(10, 10); + for _ in 0..20 { + assert_eq!(rng.sample(dist), 10); + } + } + + #[test] + fn test_uniform_good_limits_equal_float() { + let mut rng = ::test::rng(805); + let dist = Uniform::new_inclusive(10., 10.); + for _ in 0..20 { + assert_eq!(rng.sample(dist), 10.); + } + } + + #[should_panic] + #[test] + fn test_uniform_bad_limits_flipped_int() { + Uniform::new(10, 5); + } + + #[should_panic] + #[test] + fn test_uniform_bad_limits_flipped_float() { + Uniform::new(10., 5.); + } + + #[test] + fn test_integers() { + let mut rng = ::test::rng(251); + macro_rules! t { + ($($ty:ident),*) => {{ + $( + let v: &[($ty, $ty)] = &[(0, 10), + (10, 127), + (::core::$ty::MIN, ::core::$ty::MAX)]; + for &(low, high) in v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!(low <= v && v < high); + } + + let my_uniform = Uniform::new_inclusive(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!(low <= v && v <= high); + } + + for _ in 0..1000 { + let v: $ty = rng.gen_range(low, high); + assert!(low <= v && v < high); + } + } + )* + }} + } + t!(i8, i16, i32, i64, isize, + u8, u16, u32, u64, usize); + #[cfg(feature = "i128_support")] + t!(i128, u128) + } + + #[test] + fn test_floats() { + let mut rng = ::test::rng(252); + macro_rules! t { + ($($ty:ty),*) => {{ + $( + let v: &[($ty, $ty)] = &[(0.0, 100.0), + (-1e35, -1e25), + (1e-35, 1e-25), + (-1e35, 1e35)]; + for &(low, high) in v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!(low <= v && v < high); + } + } + )* + }} + } + + t!(f32, f64) + } + + #[test] + #[cfg(feature = "std")] + fn test_durations() { + use std::time::Duration; + + let mut rng = ::test::rng(253); + + let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)), + (Duration::new(0, 100), Duration::new(1, 50)), + (Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))]; + for &(low, high) in v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v = rng.sample(my_uniform); + assert!(low <= v && v < high); + } + } + } + + #[test] + fn test_custom_uniform() { + #[derive(Clone, Copy, PartialEq, PartialOrd)] + struct MyF32 { + x: f32, + } + #[derive(Clone, Copy, Debug)] + struct UniformMyF32 { + inner: UniformFloat<f32>, + } + impl UniformSampler for UniformMyF32 { + type X = MyF32; + fn new(low: Self::X, high: Self::X) -> Self { + UniformMyF32 { + inner: UniformFloat::<f32>::new(low.x, high.x), + } + } + fn new_inclusive(low: Self::X, high: Self::X) -> Self { + UniformSampler::new(low, high) + } + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + MyF32 { x: self.inner.sample(rng) } + } + } + impl SampleUniform for MyF32 { + type Sampler = UniformMyF32; + } + + let (low, high) = (MyF32{ x: 17.0f32 }, MyF32{ x: 22.0f32 }); + let uniform = Uniform::new(low, high); + let mut rng = ::test::rng(804); + for _ in 0..100 { + let x: MyF32 = rng.sample(uniform); + assert!(low <= x && x < high); + } + } + + #[test] + fn test_uniform_from_std_range() { + let r = Uniform::from(2u32..7); + assert_eq!(r.inner.low, 2); + assert_eq!(r.inner.range, 5); + let r = Uniform::from(2.0f64..7.0); + assert_eq!(r.inner.offset, -3.0); + assert_eq!(r.inner.scale, 5.0); + } +} diff --git a/rand-0.5.6/src/distributions/ziggurat_tables.rs b/rand-0.5.6/src/distributions/ziggurat_tables.rs new file mode 100644 index 000000000..11a217276 --- /dev/null +++ b/rand-0.5.6/src/distributions/ziggurat_tables.rs @@ -0,0 +1,280 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64; 257]; +pub const ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64; 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64; 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub const ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64; 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64; 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; diff --git a/rand-0.5.6/src/lib.rs b/rand-0.5.6/src/lib.rs new file mode 100644 index 000000000..a1eb469a1 --- /dev/null +++ b/rand-0.5.6/src/lib.rs @@ -0,0 +1,1238 @@ +// Copyright 2013-2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for random number generation +//! +//! Rand provides utilities to generate random numbers, to convert them to +//! useful types and distributions, and some randomness-related algorithms. +//! +//! # Basic usage +//! +//! To get you started quickly, the easiest and highest-level way to get +//! a random value is to use [`random()`]. +//! +//! ``` +//! let x: u8 = rand::random(); +//! println!("{}", x); +//! +//! let y = rand::random::<f64>(); +//! println!("{}", y); +//! +//! if rand::random() { // generates a boolean +//! println!("Heads!"); +//! } +//! ``` +//! +//! This supports generating most common types but is not very flexible, thus +//! you probably want to learn a bit more about the Rand library. +//! +//! +//! # The two-step process to get a random value +//! +//! Generating random values is typically a two-step process: +//! +//! - get some *random data* (an integer or bit/byte sequence) from a random +//! number generator (RNG); +//! - use some function to transform that *data* into the type of value you want +//! (this function is an implementation of some *distribution* describing the +//! kind of value produced). +//! +//! Rand represents the first step with the [`RngCore`] trait and the second +//! step via a combination of the [`Rng`] extension trait and the +//! [`distributions` module]. +//! In practice you probably won't use [`RngCore`] directly unless you are +//! implementing a random number generator (RNG). +//! +//! There are many kinds of RNGs, with different trade-offs. You can read more +//! about them in the [`rngs` module] and even more in the [`prng` module], +//! however, often you can just use [`thread_rng()`]. This function +//! automatically initializes an RNG in thread-local memory, then returns a +//! reference to it. It is fast, good quality, and secure (unpredictable). +//! +//! To turn the output of the RNG into something usable, you usually want to use +//! the methods from the [`Rng`] trait. Some of the most useful methods are: +//! +//! - [`gen`] generates a random value appropriate for the type (just like +//! [`random()`]). For integers this is normally the full representable range +//! (e.g. from `0u32` to `std::u32::MAX`), for floats this is between 0 and 1, +//! and some other types are supported, including arrays and tuples. See the +//! [`Standard`] distribution which provides the implementations. +//! - [`gen_range`] samples from a specific range of values; this is like +//! [`gen`] but with specific upper and lower bounds. +//! - [`sample`] samples directly from some distribution. +//! +//! [`random()`] is defined using just the above: `thread_rng().gen()`. +//! +//! ## Distributions +//! +//! What are distributions, you ask? Specifying only the type and range of +//! values (known as the *sample space*) is not enough; samples must also have +//! a *probability distribution*, describing the relative probability of +//! sampling each value in that space. +//! +//! In many cases a *uniform* distribution is used, meaning roughly that each +//! value is equally likely (or for "continuous" types like floats, that each +//! equal-sized sub-range has the same probability of containing a sample). +//! [`gen`] and [`gen_range`] both use statistically uniform distributions. +//! +//! The [`distributions` module] provides implementations +//! of some other distributions, including Normal, Log-Normal and Exponential. +//! +//! It is worth noting that the functionality already mentioned is implemented +//! with distributions: [`gen`] samples values using the [`Standard`] +//! distribution, while [`gen_range`] uses [`Uniform`]. +//! +//! ## Importing (prelude) +//! +//! The most convenient way to import items from Rand is to use the [prelude]. +//! This includes the most important parts of Rand, but only those unlikely to +//! cause name conflicts. +//! +//! Note that Rand 0.5 has significantly changed the module organization and +//! contents relative to previous versions. Where possible old names have been +//! kept (but are hidden in the documentation), however these will be removed +//! in the future. We therefore recommend migrating to use the prelude or the +//! new module organization in your imports. +//! +//! +//! ## Examples +//! +//! ``` +//! use rand::prelude::*; +//! +//! // thread_rng is often the most convenient source of randomness: +//! let mut rng = thread_rng(); +//! +//! if rng.gen() { // random bool +//! let x: f64 = rng.gen(); // random number in range [0, 1) +//! println!("x is: {}", x); +//! let ch = rng.gen::<char>(); // using type annotation +//! println!("char is: {}", ch); +//! println!("Number from 0 to 9: {}", rng.gen_range(0, 10)); +//! } +//! ``` +//! +//! +//! # More functionality +//! +//! The [`Rng`] trait includes a few more methods not mentioned above: +//! +//! - [`Rng::sample_iter`] allows iterating over values from a chosen +//! distribution. +//! - [`Rng::gen_bool`] generates boolean "events" with a given probability. +//! - [`Rng::fill`] and [`Rng::try_fill`] are fast alternatives to fill a slice +//! of integers. +//! - [`Rng::shuffle`] randomly shuffles elements in a slice. +//! - [`Rng::choose`] picks one element at random from a slice. +//! +//! For more slice/sequence related functionality, look in the [`seq` module]. +//! +//! There is also [`distributions::WeightedChoice`], which can be used to pick +//! elements at random with some probability. But it does not work well at the +//! moment and is going through a redesign. +//! +//! +//! # Error handling +//! +//! Error handling in Rand is a compromise between simplicity and necessity. +//! Most RNGs and sampling functions will never produce errors, and making these +//! able to handle errors would add significant overhead (to code complexity +//! and ergonomics of usage at least, and potentially also performance, +//! depending on the approach). +//! However, external RNGs can fail, and being able to handle this is important. +//! +//! It has therefore been decided that *most* methods should not return a +//! `Result` type, with as exceptions [`Rng::try_fill`], +//! [`RngCore::try_fill_bytes`], and [`SeedableRng::from_rng`]. +//! +//! Note that it is the RNG that panics when it fails but is not used through a +//! method that can report errors. Currently Rand contains only three RNGs that +//! can return an error (and thus may panic), and documents this property: +//! [`OsRng`], [`EntropyRng`] and [`ReadRng`]. Other RNGs, like [`ThreadRng`] +//! and [`StdRng`], can be used with all methods without concern. +//! +//! One further problem is that if Rand is unable to get any external randomness +//! when initializing an RNG with [`EntropyRng`], it will panic in +//! [`FromEntropy::from_entropy`], and notably in [`thread_rng()`]. Except by +//! compromising security, this problem is as unsolvable as running out of +//! memory. +//! +//! +//! # Distinction between Rand and `rand_core` +//! +//! The [`rand_core`] crate provides the necessary traits and functionality for +//! implementing RNGs; this includes the [`RngCore`] and [`SeedableRng`] traits +//! and the [`Error`] type. +//! Crates implementing RNGs should depend on [`rand_core`]. +//! +//! Applications and libraries consuming random values are encouraged to use the +//! Rand crate, which re-exports the common parts of [`rand_core`]. +//! +//! +//! # More examples +//! +//! For some inspiration, see the examples: +//! +//! - [Monte Carlo estimation of π]( +//! https://github.com/rust-lang-nursery/rand/blob/master/examples/monte-carlo.rs) +//! - [Monty Hall Problem]( +//! https://github.com/rust-lang-nursery/rand/blob/master/examples/monty-hall.rs) +//! +//! +//! [`distributions` module]: distributions/index.html +//! [`distributions::WeightedChoice`]: distributions/struct.WeightedChoice.html +//! [`FromEntropy::from_entropy`]: trait.FromEntropy.html#tymethod.from_entropy +//! [`EntropyRng`]: rngs/struct.EntropyRng.html +//! [`Error`]: struct.Error.html +//! [`gen_range`]: trait.Rng.html#method.gen_range +//! [`gen`]: trait.Rng.html#method.gen +//! [`OsRng`]: rngs/struct.OsRng.html +//! [prelude]: prelude/index.html +//! [`rand_core`]: https://crates.io/crates/rand_core +//! [`random()`]: fn.random.html +//! [`ReadRng`]: rngs/adapter/struct.ReadRng.html +//! [`Rng::choose`]: trait.Rng.html#method.choose +//! [`Rng::fill`]: trait.Rng.html#method.fill +//! [`Rng::gen_bool`]: trait.Rng.html#method.gen_bool +//! [`Rng::gen`]: trait.Rng.html#method.gen +//! [`Rng::sample_iter`]: trait.Rng.html#method.sample_iter +//! [`Rng::shuffle`]: trait.Rng.html#method.shuffle +//! [`RngCore`]: trait.RngCore.html +//! [`RngCore::try_fill_bytes`]: trait.RngCore.html#method.try_fill_bytes +//! [`rngs` module]: rngs/index.html +//! [`prng` module]: prng/index.html +//! [`Rng`]: trait.Rng.html +//! [`Rng::try_fill`]: trait.Rng.html#method.try_fill +//! [`sample`]: trait.Rng.html#method.sample +//! [`SeedableRng`]: trait.SeedableRng.html +//! [`SeedableRng::from_rng`]: trait.SeedableRng.html#method.from_rng +//! [`seq` module]: seq/index.html +//! [`SmallRng`]: rngs/struct.SmallRng.html +//! [`StdRng`]: rngs/struct.StdRng.html +//! [`thread_rng()`]: fn.thread_rng.html +//! [`ThreadRng`]: rngs/struct.ThreadRng.html +//! [`Standard`]: distributions/struct.Standard.html +//! [`Uniform`]: distributions/struct.Uniform.html + + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/rand/0.5.6")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(feature="std"), no_std)] +#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] +#![cfg_attr(all(feature="i128_support", feature="nightly"), allow(stable_features))] // stable since 2018-03-27 +#![cfg_attr(all(feature="i128_support", feature="nightly"), feature(i128_type, i128))] +#![cfg_attr(feature = "stdweb", recursion_limit="128")] + +#[cfg(feature="std")] extern crate std as core; +#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; + +#[cfg(test)] #[cfg(feature="serde1")] extern crate bincode; +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +#[cfg(all(target_arch="wasm32", not(target_os="emscripten"), feature="stdweb"))] +#[macro_use] +extern crate stdweb; + +extern crate rand_core; + +#[cfg(feature = "log")] #[macro_use] extern crate log; +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () } + + +// Re-exports from rand_core +pub use rand_core::{RngCore, CryptoRng, SeedableRng}; +pub use rand_core::{ErrorKind, Error}; + +// Public exports +#[cfg(feature="std")] pub use rngs::thread::thread_rng; + +// Public modules +pub mod distributions; +pub mod prelude; +pub mod prng; +pub mod rngs; +#[cfg(feature = "alloc")] pub mod seq; + +//////////////////////////////////////////////////////////////////////////////// +// Compatibility re-exports. Documentation is hidden; will be removed eventually. + +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::adapter::read; +#[doc(hidden)] pub use rngs::adapter::ReseedingRng; + +#[allow(deprecated)] +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::EntropyRng; + +#[allow(deprecated)] +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +#[doc(hidden)] +pub use rngs::OsRng; + +#[doc(hidden)] pub use prng::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; +#[doc(hidden)] pub use rngs::StdRng; + + +#[allow(deprecated)] +#[doc(hidden)] +pub mod jitter { + pub use rngs::{JitterRng, TimerError}; +} +#[allow(deprecated)] +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +#[doc(hidden)] +pub mod os { + pub use rngs::OsRng; +} +#[allow(deprecated)] +#[doc(hidden)] +pub mod chacha { + //! The ChaCha random number generator. + pub use prng::ChaChaRng; +} +#[doc(hidden)] +pub mod isaac { + //! The ISAAC random number generator. + pub use prng::{IsaacRng, Isaac64Rng}; +} + +#[cfg(feature="std")] #[doc(hidden)] pub use rngs::ThreadRng; + +//////////////////////////////////////////////////////////////////////////////// + + +use core::{marker, mem, slice}; +use distributions::{Distribution, Standard}; +use distributions::uniform::{SampleUniform, UniformSampler}; + + +/// A type that can be randomly generated using an [`Rng`]. +/// +/// This is merely an adapter around the [`Standard`] distribution for +/// convenience and backwards-compatibility. +/// +/// [`Rng`]: trait.Rng.html +/// [`Standard`]: distributions/struct.Standard.html +#[deprecated(since="0.5.0", note="replaced by distributions::Standard")] +pub trait Rand : Sized { + /// Generates a random instance of this type using the specified source of + /// randomness. + fn rand<R: Rng>(rng: &mut R) -> Self; +} + +/// An automatically-implemented extension trait on [`RngCore`] providing high-level +/// generic methods for sampling values and other convenience methods. +/// +/// This is the primary trait to use when generating random values. +/// +/// # Generic usage +/// +/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some +/// things are worth noting here: +/// +/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no +/// difference whether we use `R: Rng` or `R: RngCore`. +/// - The `+ ?Sized` un-bounding allows functions to be called directly on +/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without +/// this it would be necessary to write `foo(&mut r)`. +/// +/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some +/// trade-offs. It allows the argument to be consumed directly without a `&mut` +/// (which is how `from_rng(thread_rng())` works); also it still works directly +/// on references (including type-erased references). Unfortunately within the +/// function `foo` it is not known whether `rng` is a reference type or not, +/// hence many uses of `rng` require an extra reference, either explicitly +/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the +/// optimiser can remove redundant references later. +/// +/// Example: +/// +/// ``` +/// # use rand::thread_rng; +/// use rand::Rng; +/// +/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 { +/// rng.gen() +/// } +/// +/// # let v = foo(&mut thread_rng()); +/// ``` +/// +/// [`RngCore`]: trait.RngCore.html +pub trait Rng: RngCore { + /// Return a random value supporting the [`Standard`] distribution. + /// + /// [`Standard`]: distributions/struct.Standard.html + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let x: u32 = rng.gen(); + /// println!("{}", x); + /// println!("{:?}", rng.gen::<(f64, bool)>()); + /// ``` + #[inline] + fn gen<T>(&mut self) -> T where Standard: Distribution<T> { + Standard.sample(self) + } + + /// Generate a random value in the range [`low`, `high`), i.e. inclusive of + /// `low` and exclusive of `high`. + /// + /// This function is optimised for the case that only a single sample is + /// made from the given range. See also the [`Uniform`] distribution + /// type which may be faster if sampling from the same range repeatedly. + /// + /// # Panics + /// + /// Panics if `low >= high`. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let n: u32 = rng.gen_range(0, 10); + /// println!("{}", n); + /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); + /// println!("{}", m); + /// ``` + /// + /// [`Uniform`]: distributions/uniform/struct.Uniform.html + fn gen_range<T: PartialOrd + SampleUniform>(&mut self, low: T, high: T) -> T { + T::Sampler::sample_single(low, high, self) + } + + /// Sample a new value, using the given distribution. + /// + /// ### Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::Uniform; + /// + /// let mut rng = thread_rng(); + /// let x = rng.sample(Uniform::new(10u32, 15)); + /// // Type annotation requires two types, the type and distribution; the + /// // distribution can be inferred. + /// let y = rng.sample::<u16, _>(Uniform::new(10, 15)); + /// ``` + fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T { + distr.sample(self) + } + + /// Create an iterator that generates values using the given distribution. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::{Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec<f32> = thread_rng().sample_iter(&Standard).take(16).collect(); + /// + /// // String: + /// let s: String = rng.sample_iter(&Alphanumeric).take(7).collect(); + /// + /// // Combined values + /// println!("{:?}", thread_rng().sample_iter(&Standard).take(5) + /// .collect::<Vec<(f64, bool)>>()); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = rng.sample_iter(&die_range); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, T, D: Distribution<T>>(&'a mut self, distr: &'a D) + -> distributions::DistIter<'a, D, Self, T> where Self: Sized + { + distr.sample_iter(self) + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`fill_bytes`] internally which may handle some RNG errors + /// implicitly (e.g. waiting if the OS generator is not ready), but panics + /// on other errors. See also [`try_fill`] which returns errors. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut arr = [0i8; 20]; + /// thread_rng().fill(&mut arr[..]); + /// ``` + /// + /// [`fill_bytes`]: trait.RngCore.html#method.fill_bytes + /// [`try_fill`]: trait.Rng.html#method.try_fill + /// [`AsByteSliceMut`]: trait.AsByteSliceMut.html + fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) { + self.fill_bytes(dest.as_byte_slice_mut()); + dest.to_le(); + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In + /// some cases errors may be resolvable; see [`ErrorKind`] and + /// documentation for the RNG in use. If you do not plan to handle these + /// errors you may prefer to use [`fill`]. + /// + /// # Example + /// + /// ``` + /// # use rand::Error; + /// use rand::{thread_rng, Rng}; + /// + /// # fn try_inner() -> Result<(), Error> { + /// let mut arr = [0u64; 4]; + /// thread_rng().try_fill(&mut arr[..])?; + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + /// + /// [`ErrorKind`]: enum.ErrorKind.html + /// [`try_fill_bytes`]: trait.RngCore.html#method.try_fill_bytes + /// [`fill`]: trait.Rng.html#method.fill + /// [`AsByteSliceMut`]: trait.AsByteSliceMut.html + fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> { + self.try_fill_bytes(dest.as_byte_slice_mut())?; + dest.to_le(); + Ok(()) + } + + /// Return a bool with a probability `p` of being true. + /// + /// This is a wrapper around [`distributions::Bernoulli`]. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_bool(1.0 / 3.0)); + /// ``` + /// + /// # Panics + /// + /// If `p` < 0 or `p` > 1. + /// + /// [`distributions::Bernoulli`]: distributions/bernoulli/struct.Bernoulli.html + #[inline] + fn gen_bool(&mut self, p: f64) -> bool { + let d = distributions::Bernoulli::new(p); + self.sample(d) + } + + /// Return a random element from `values`. + /// + /// Return `None` if `values` is empty. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let choices = [1, 2, 4, 8, 16, 32]; + /// let mut rng = thread_rng(); + /// println!("{:?}", rng.choose(&choices)); + /// assert_eq!(rng.choose(&choices[..0]), None); + /// ``` + fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { + if values.is_empty() { + None + } else { + Some(&values[self.gen_range(0, values.len())]) + } + } + + /// Return a mutable pointer to a random element from `values`. + /// + /// Return `None` if `values` is empty. + fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> { + if values.is_empty() { + None + } else { + let len = values.len(); + Some(&mut values[self.gen_range(0, len)]) + } + } + + /// Shuffle a mutable slice in place. + /// + /// This applies Durstenfeld's algorithm for the [Fisher–Yates shuffle]( + /// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) + /// which produces an unbiased permutation. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let mut y = [1, 2, 3]; + /// rng.shuffle(&mut y); + /// println!("{:?}", y); + /// rng.shuffle(&mut y); + /// println!("{:?}", y); + /// ``` + fn shuffle<T>(&mut self, values: &mut [T]) { + let mut i = values.len(); + while i >= 2 { + // invariant: elements with index >= i have been locked in place. + i -= 1; + // lock element i in place. + values.swap(i, self.gen_range(0, i + 1)); + } + } + + /// Return an iterator that will yield an infinite number of randomly + /// generated items. + /// + /// # Example + /// + /// ``` + /// # #![allow(deprecated)] + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let x = rng.gen_iter::<u32>().take(10).collect::<Vec<u32>>(); + /// println!("{:?}", x); + /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) + /// .collect::<Vec<(f64, bool)>>()); + /// ``` + #[allow(deprecated)] + #[deprecated(since="0.5.0", note="use Rng::sample_iter(&Standard) instead")] + fn gen_iter<T>(&mut self) -> Generator<T, &mut Self> where Standard: Distribution<T> { + Generator { rng: self, _marker: marker::PhantomData } + } + + /// Return a bool with a 1 in n chance of true + /// + /// # Example + /// + /// ``` + /// # #![allow(deprecated)] + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// assert_eq!(rng.gen_weighted_bool(0), true); + /// assert_eq!(rng.gen_weighted_bool(1), true); + /// // Just like `rng.gen::<bool>()` a 50-50% chance, but using a slower + /// // method with different results. + /// println!("{}", rng.gen_weighted_bool(2)); + /// // First meaningful use of `gen_weighted_bool`. + /// println!("{}", rng.gen_weighted_bool(3)); + /// ``` + #[deprecated(since="0.5.0", note="use gen_bool instead")] + fn gen_weighted_bool(&mut self, n: u32) -> bool { + // Short-circuit after `n <= 1` to avoid panic in `gen_range` + n <= 1 || self.gen_range(0, n) == 0 + } + + /// Return an iterator of random characters from the set A-Z,a-z,0-9. + /// + /// # Example + /// + /// ``` + /// # #![allow(deprecated)] + /// use rand::{thread_rng, Rng}; + /// + /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); + /// println!("{}", s); + /// ``` + #[allow(deprecated)] + #[deprecated(since="0.5.0", note="use sample_iter(&Alphanumeric) instead")] + fn gen_ascii_chars(&mut self) -> AsciiGenerator<&mut Self> { + AsciiGenerator { rng: self } + } +} + +impl<R: RngCore + ?Sized> Rng for R {} + +/// Trait for casting types to byte slices +/// +/// This is used by the [`fill`] and [`try_fill`] methods. +/// +/// [`fill`]: trait.Rng.html#method.fill +/// [`try_fill`]: trait.Rng.html#method.try_fill +pub trait AsByteSliceMut { + /// Return a mutable reference to self as a byte slice + fn as_byte_slice_mut(&mut self) -> &mut [u8]; + + /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms). + fn to_le(&mut self); +} + +impl AsByteSliceMut for [u8] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self + } + + fn to_le(&mut self) {} +} + +macro_rules! impl_as_byte_slice { + ($t:ty) => { + impl AsByteSliceMut for [$t] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + if self.len() == 0 { + unsafe { + // must not use null pointer + slice::from_raw_parts_mut(0x1 as *mut u8, 0) + } + } else { + unsafe { + slice::from_raw_parts_mut(&mut self[0] + as *mut $t + as *mut u8, + self.len() * mem::size_of::<$t>() + ) + } + } + } + + fn to_le(&mut self) { + for x in self { + *x = x.to_le(); + } + } + } + } +} + +impl_as_byte_slice!(u16); +impl_as_byte_slice!(u32); +impl_as_byte_slice!(u64); +#[cfg(feature="i128_support")] impl_as_byte_slice!(u128); +impl_as_byte_slice!(usize); +impl_as_byte_slice!(i8); +impl_as_byte_slice!(i16); +impl_as_byte_slice!(i32); +impl_as_byte_slice!(i64); +#[cfg(feature="i128_support")] impl_as_byte_slice!(i128); +impl_as_byte_slice!(isize); + +macro_rules! impl_as_byte_slice_arrays { + ($n:expr,) => {}; + ($n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!($n - 1, $($NN,)*); + + impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } + + fn to_le(&mut self) { + self[..].to_le() + } + } + }; + (!div $n:expr,) => {}; + (!div $n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*); + + impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } + + fn to_le(&mut self) { + self[..].to_le() + } + } + }; +} +impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,); +impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,); + +/// Iterator which will generate a stream of random items. +/// +/// This iterator is created via the [`gen_iter`] method on [`Rng`]. +/// +/// [`gen_iter`]: trait.Rng.html#method.gen_iter +/// [`Rng`]: trait.Rng.html +#[derive(Debug)] +#[allow(deprecated)] +#[deprecated(since="0.5.0", note="use Rng::sample_iter instead")] +pub struct Generator<T, R: RngCore> { + rng: R, + _marker: marker::PhantomData<fn() -> T>, +} + +#[allow(deprecated)] +impl<T, R: RngCore> Iterator for Generator<T, R> where Standard: Distribution<T> { + type Item = T; + + fn next(&mut self) -> Option<T> { + Some(self.rng.gen()) + } +} + +/// Iterator which will continuously generate random ascii characters. +/// +/// This iterator is created via the [`gen_ascii_chars`] method on [`Rng`]. +/// +/// [`gen_ascii_chars`]: trait.Rng.html#method.gen_ascii_chars +/// [`Rng`]: trait.Rng.html +#[derive(Debug)] +#[allow(deprecated)] +#[deprecated(since="0.5.0", note="use distributions::Alphanumeric instead")] +pub struct AsciiGenerator<R: RngCore> { + rng: R, +} + +#[allow(deprecated)] +impl<R: RngCore> Iterator for AsciiGenerator<R> { + type Item = char; + + fn next(&mut self) -> Option<char> { + const GEN_ASCII_STR_CHARSET: &[u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + Some(*self.rng.choose(GEN_ASCII_STR_CHARSET).unwrap() as char) + } +} + + +/// A convenience extension to [`SeedableRng`] allowing construction from fresh +/// entropy. This trait is automatically implemented for any PRNG implementing +/// [`SeedableRng`] and is not intended to be implemented by users. +/// +/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then +/// unwrapping the result. +/// +/// Since this is convenient and secure, it is the recommended way to create +/// PRNGs, though two alternatives may be considered: +/// +/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed +/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; +/// this will usually be faster and should also be secure, but requires +/// trusting one extra component. +/// +/// ## Example +/// +/// ``` +/// use rand::{Rng, FromEntropy}; +/// use rand::rngs::StdRng; +/// +/// let mut rng = StdRng::from_entropy(); +/// println!("Random die roll: {}", rng.gen_range(1, 7)); +/// ``` +/// +/// [`EntropyRng`]: rngs/struct.EntropyRng.html +/// [`SeedableRng`]: trait.SeedableRng.html +/// [`SeedableRng::from_seed`]: trait.SeedableRng.html#tymethod.from_seed +#[cfg(feature="std")] +pub trait FromEntropy: SeedableRng { + /// Creates a new instance, automatically seeded with fresh entropy. + /// + /// Normally this will use `OsRng`, but if that fails `JitterRng` will be + /// used instead. Both should be suitable for cryptography. It is possible + /// that both entropy sources will fail though unlikely; failures would + /// almost certainly be platform limitations or build issues, i.e. most + /// applications targetting PC/mobile platforms should not need to worry + /// about this failing. + /// + /// # Panics + /// + /// If all entropy sources fail this will panic. If you need to handle + /// errors, use the following code, equivalent aside from error handling: + /// + /// ``` + /// # use rand::Error; + /// use rand::prelude::*; + /// use rand::rngs::EntropyRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// // This uses StdRng, but is valid for any R: SeedableRng + /// let mut rng = StdRng::from_rng(EntropyRng::new())?; + /// + /// println!("random number: {}", rng.gen_range(1, 10)); + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + fn from_entropy() -> Self; +} + +#[cfg(feature="std")] +impl<R: SeedableRng> FromEntropy for R { + fn from_entropy() -> R { + R::from_rng(EntropyRng::new()).unwrap_or_else(|err| + panic!("FromEntropy::from_entropy() failed: {}", err)) + } +} + + +/// DEPRECATED: use [`SmallRng`] instead. +/// +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fastest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +/// +/// This will seed the generator with randomness from `thread_rng`. +/// +/// [`SmallRng`]: rngs/struct.SmallRng.html +#[deprecated(since="0.5.0", note="removed in favor of SmallRng")] +#[cfg(feature="std")] +pub fn weak_rng() -> XorShiftRng { + XorShiftRng::from_rng(thread_rng()).unwrap_or_else(|err| + panic!("weak_rng failed: {:?}", err)) +} + +/// Generates a random value using the thread-local random number generator. +/// +/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for +/// documentation of the entropy source and [`Standard`] for documentation of +/// distributions and type-specific generation. +/// +/// # Examples +/// +/// ``` +/// let x = rand::random::<u8>(); +/// println!("{}", x); +/// +/// let y = rand::random::<f64>(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +/// +/// If you're calling `random()` in a loop, caching the generator as in the +/// following example can increase performance. +/// +/// ``` +/// # #![allow(deprecated)] +/// use rand::Rng; +/// +/// let mut v = vec![1, 2, 3]; +/// +/// for x in v.iter_mut() { +/// *x = rand::random() +/// } +/// +/// // can be made faster by caching thread_rng +/// +/// let mut rng = rand::thread_rng(); +/// +/// for x in v.iter_mut() { +/// *x = rng.gen(); +/// } +/// ``` +/// +/// [`thread_rng`]: fn.thread_rng.html +/// [`Standard`]: distributions/struct.Standard.html +#[cfg(feature="std")] +#[inline] +pub fn random<T>() -> T where Standard: Distribution<T> { + thread_rng().gen() +} + +/// DEPRECATED: use `seq::sample_iter` instead. +/// +/// Randomly sample up to `amount` elements from a finite iterator. +/// The order of elements in the sample is not random. +/// +/// # Example +/// +/// ``` +/// # #![allow(deprecated)] +/// use rand::{thread_rng, sample}; +/// +/// let mut rng = thread_rng(); +/// let sample = sample(&mut rng, 1..100, 5); +/// println!("{:?}", sample); +/// ``` +#[cfg(feature="std")] +#[inline] +#[deprecated(since="0.4.0", note="renamed to seq::sample_iter")] +pub fn sample<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T> + where I: IntoIterator<Item=T>, + R: Rng, +{ + // the legacy sample didn't care whether amount was met + seq::sample_iter(rng, iterable, amount) + .unwrap_or_else(|e| e) +} + +#[cfg(test)] +mod test { + use rngs::mock::StepRng; + use super::*; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box; + + pub struct TestRng<R> { inner: R } + + impl<R: RngCore> RngCore for TestRng<R> { + fn next_u32(&mut self) -> u32 { + self.inner.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.inner.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.inner.fill_bytes(dest) + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.inner.try_fill_bytes(dest) + } + } + + pub fn rng(seed: u64) -> TestRng<StdRng> { + TestRng { inner: StdRng::seed_from_u64(seed) } + } + + #[test] + fn test_fill_bytes_default() { + let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0); + + // check every remainder mod 8, both in small and big vectors. + let lengths = [0, 1, 2, 3, 4, 5, 6, 7, + 80, 81, 82, 83, 84, 85, 86, 87]; + for &n in lengths.iter() { + let mut buffer = [0u8; 87]; + let v = &mut buffer[0..n]; + r.fill_bytes(v); + + // use this to get nicer error messages. + for (i, &byte) in v.iter().enumerate() { + if byte == 0 { + panic!("byte {} of {} is zero", i, n) + } + } + } + } + + #[test] + fn test_fill() { + let x = 9041086907909331047; // a random u64 + let mut rng = StepRng::new(x, 0); + + // Convert to byte sequence and back to u64; byte-swap twice if BE. + let mut array = [0u64; 2]; + rng.fill(&mut array[..]); + assert_eq!(array, [x, x]); + assert_eq!(rng.next_u64(), x); + + // Convert to bytes then u32 in LE order + let mut array = [0u32; 2]; + rng.fill(&mut array[..]); + assert_eq!(array, [x as u32, (x >> 32) as u32]); + assert_eq!(rng.next_u32(), x as u32); + } + + #[test] + fn test_fill_empty() { + let mut array = [0u32; 0]; + let mut rng = StepRng::new(0, 1); + rng.fill(&mut array); + rng.fill(&mut array[..]); + } + + #[test] + fn test_gen_range() { + let mut r = rng(101); + for _ in 0..1000 { + let a = r.gen_range(-3, 42); + assert!(a >= -3 && a < 42); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(-12, -11), -12); + } + + for _ in 0..1000 { + let a = r.gen_range(10, 42); + assert!(a >= 10 && a < 42); + assert_eq!(r.gen_range(0, 1), 0); + assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); + } + + } + + #[test] + #[should_panic] + fn test_gen_range_panic_int() { + let mut r = rng(102); + r.gen_range(5, -2); + } + + #[test] + #[should_panic] + fn test_gen_range_panic_usize() { + let mut r = rng(103); + r.gen_range(5, 2); + } + + #[test] + #[allow(deprecated)] + fn test_gen_weighted_bool() { + let mut r = rng(104); + assert_eq!(r.gen_weighted_bool(0), true); + assert_eq!(r.gen_weighted_bool(1), true); + } + + #[test] + fn test_gen_bool() { + let mut r = rng(105); + for _ in 0..5 { + assert_eq!(r.gen_bool(0.0), false); + assert_eq!(r.gen_bool(1.0), true); + } + } + + #[test] + fn test_choose() { + let mut r = rng(107); + assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1)); + + let v: &[isize] = &[]; + assert_eq!(r.choose(v), None); + } + + #[test] + fn test_shuffle() { + let mut r = rng(108); + let empty: &mut [isize] = &mut []; + r.shuffle(empty); + let mut one = [1]; + r.shuffle(&mut one); + let b: &[_] = &[1]; + assert_eq!(one, b); + + let mut two = [1, 2]; + r.shuffle(&mut two); + assert!(two == [1, 2] || two == [2, 1]); + + let mut x = [1, 1, 1]; + r.shuffle(&mut x); + let b: &[_] = &[1, 1, 1]; + assert_eq!(x, b); + } + + #[test] + fn test_rng_trait_object() { + use distributions::{Distribution, Standard}; + let mut rng = rng(109); + let mut r = &mut rng as &mut RngCore; + r.next_u32(); + r.gen::<i32>(); + let mut v = [1, 1, 1]; + r.shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); + } + + #[test] + #[cfg(feature="alloc")] + fn test_rng_boxed_trait() { + use distributions::{Distribution, Standard}; + let rng = rng(110); + let mut r = Box::new(rng) as Box<RngCore>; + r.next_u32(); + r.gen::<i32>(); + let mut v = [1, 1, 1]; + r.shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); + } + + #[test] + #[cfg(feature="std")] + fn test_random() { + // not sure how to test this aside from just getting some values + let _n : usize = random(); + let _f : f32 = random(); + let _o : Option<Option<i8>> = random(); + let _many : ((), + (usize, + isize, + Option<(u32, (bool,))>), + (u8, i8, u16, i16, u32, i32, u64, i64), + (f32, (f64, (f64,)))) = random(); + } +} diff --git a/rand-0.5.6/src/prelude.rs b/rand-0.5.6/src/prelude.rs new file mode 100644 index 000000000..358c23708 --- /dev/null +++ b/rand-0.5.6/src/prelude.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Convenience re-export of common members +//! +//! Like the standard library's prelude, this module simplifies importing of +//! common items. Unlike the standard prelude, the contents of this module must +//! be imported manually: +//! +//! ``` +//! use rand::prelude::*; +//! # let _ = StdRng::from_entropy(); +//! # let mut r = SmallRng::from_rng(thread_rng()).unwrap(); +//! # let _: f32 = r.gen(); +//! ``` + +#[doc(no_inline)] pub use distributions::Distribution; +#[doc(no_inline)] pub use rngs::{SmallRng, StdRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng; +#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng}; diff --git a/rand-0.5.6/src/prng/chacha.rs b/rand-0.5.6/src/prng/chacha.rs new file mode 100644 index 000000000..2817f8f87 --- /dev/null +++ b/rand-0.5.6/src/prng/chacha.rs @@ -0,0 +1,477 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://www.rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 8 words for the 256-bit key +const STATE_WORDS: usize = 16; + +/// A cryptographically secure random number generator that uses the ChaCha +/// algorithm. +/// +/// ChaCha is a stream cipher designed by Daniel J. Bernstein [^1], that we use +/// as an RNG. It is an improved variant of the Salsa20 cipher family, which was +/// selected as one of the "stream ciphers suitable for widespread adoption" by +/// eSTREAM [^2]. +/// +/// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe +/// against timing attacks, although that is mostly a concern for ciphers and +/// not for RNGs. Also it is very suitable for SIMD implementation. +/// Here we do not provide a SIMD implementation yet, except for what is +/// provided by auto-vectorisation. +/// +/// With the ChaCha algorithm it is possible to choose the number of rounds the +/// core algorithm should run. The number of rounds is a tradeoff between +/// performance and security, where 8 rounds is the minimum potentially +/// secure configuration, and 20 rounds is widely used as a conservative choice. +/// We use 20 rounds in this implementation, but hope to allow type-level +/// configuration in the future. +/// +/// We use a 64-bit counter and 64-bit stream identifier as in Benstein's +/// implementation [^1] except that we use a stream identifier in place of a +/// nonce. A 64-bit counter over 64-byte (16 word) blocks allows 1 ZiB of output +/// before cycling, and the stream identifier allows 2<sup>64</sup> unique +/// streams of output per seed. Both counter and stream are initialized to zero +/// but may be set via [`set_word_pos`] and [`set_stream`]. +/// +/// The word layout is: +/// +/// ```text +/// constant constant constant constant +/// seed seed seed seed +/// seed seed seed seed +/// counter counter nonce nonce +/// ``` +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( +/// https://cr.yp.to/chacha.html) +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [`set_word_pos`]: #method.set_word_pos +/// [`set_stream`]: #method.set_stream +/// [`BlockRng`]: ../../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../trait.RngCore.html +#[derive(Clone, Debug)] +pub struct ChaChaRng(BlockRng<ChaChaCore>); + +impl RngCore for ChaChaRng { + #[inline] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for ChaChaRng { + type Seed = <ChaChaCore as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + ChaChaRng(BlockRng::<ChaChaCore>::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + BlockRng::<ChaChaCore>::from_rng(rng).map(ChaChaRng) + } +} + +impl CryptoRng for ChaChaRng {} + +impl ChaChaRng { + /// Create an ChaCha random number generator using the default + /// fixed key of 8 zero words. + /// + /// # Examples + /// + /// ``` + /// # #![allow(deprecated)] + /// use rand::{RngCore, ChaChaRng}; + /// + /// let mut ra = ChaChaRng::new_unseeded(); + /// println!("{:?}", ra.next_u32()); + /// println!("{:?}", ra.next_u32()); + /// ``` + /// + /// Since this equivalent to a RNG with a fixed seed, repeated executions + /// of an unseeded RNG will produce the same result. This code sample will + /// consistently produce: + /// + /// - 2917185654 + /// - 2419978656 + #[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")] + pub fn new_unseeded() -> ChaChaRng { + ChaChaRng::from_seed([0; SEED_WORDS*4]) + } + + /// Get the offset from the start of the stream, in 32-bit words. + /// + /// Since the generated blocks are 16 words (2<sup>4</sup>) long and the + /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are + /// not supported, hence the result can simply be multiplied by 4 to get a + /// byte-offset. + /// + /// Note: this function is currently only available when the `i128_support` + /// feature is enabled. In the future this will be enabled by default. + #[cfg(feature = "i128_support")] + pub fn get_word_pos(&self) -> u128 { + let mut c = (self.0.core.state[13] as u64) << 32 + | (self.0.core.state[12] as u64); + let mut index = self.0.index(); + // c is the end of the last block generated, unless index is at end + if index >= STATE_WORDS { + index = 0; + } else { + c = c.wrapping_sub(1); + } + ((c as u128) << 4) | (index as u128) + } + + /// Set the offset from the start of the stream, in 32-bit words. + /// + /// As with `get_word_pos`, we use a 68-bit number. Since the generator + /// simply cycles at the end of its period (1 ZiB), we ignore the upper + /// 60 bits. + /// + /// Note: this function is currently only available when the `i128_support` + /// feature is enabled. In the future this will be enabled by default. + #[cfg(feature = "i128_support")] + pub fn set_word_pos(&mut self, word_offset: u128) { + let index = (word_offset as usize) & 0xF; + let counter = (word_offset >> 4) as u64; + self.0.core.state[12] = counter as u32; + self.0.core.state[13] = (counter >> 32) as u32; + if index != 0 { + self.0.generate_and_set(index); // also increments counter + } else { + self.0.reset(); + } + } + + /// Set the stream number. + /// + /// This is initialized to zero; 2<sup>64</sup> unique streams of output + /// are available per seed/key. + /// + /// Note that in order to reproduce ChaCha output with a specific 64-bit + /// nonce, one can convert that nonce to a `u64` in little-endian fashion + /// and pass to this function. In theory a 96-bit nonce can be used by + /// passing the last 64-bits to this function and using the first 32-bits as + /// the most significant half of the 64-bit counter (which may be set + /// indirectly via `set_word_pos`), but this is not directly supported. + pub fn set_stream(&mut self, stream: u64) { + let index = self.0.index(); + self.0.core.state[14] = stream as u32; + self.0.core.state[15] = (stream >> 32) as u32; + if index < STATE_WORDS { + // we need to regenerate a partial result buffer + { + // reverse of counter adjustment in generate() + if self.0.core.state[12] == 0 { + self.0.core.state[13] = self.0.core.state[13].wrapping_sub(1); + } + self.0.core.state[12] = self.0.core.state[12].wrapping_sub(1); + } + self.0.generate_and_set(index); + } + } +} + +/// The core of `ChaChaRng`, used with `BlockRng`. +#[derive(Clone)] +pub struct ChaChaCore { + state: [u32; STATE_WORDS], +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for ChaChaCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ChaChaCore {{}}") + } +} + +macro_rules! quarter_round{ + ($a: expr, $b: expr, $c: expr, $d: expr) => {{ + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left(16); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left(12); + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left( 8); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left( 7); + }} +} + +macro_rules! double_round{ + ($x: expr) => {{ + // Column round + quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]); + quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]); + quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]); + quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]); + // Diagonal round + quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]); + quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]); + quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]); + quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]); + }} +} + +impl BlockRngCore for ChaChaCore { + type Item = u32; + type Results = [u32; STATE_WORDS]; + + fn generate(&mut self, results: &mut Self::Results) { + // For some reason extracting this part into a separate function + // improves performance by 50%. + fn core(results: &mut [u32; STATE_WORDS], + state: &[u32; STATE_WORDS]) + { + let mut tmp = *state; + let rounds = 20; + for _ in 0..rounds / 2 { + double_round!(tmp); + } + for i in 0..STATE_WORDS { + results[i] = tmp[i].wrapping_add(state[i]); + } + } + + core(results, &self.state); + + // update 64-bit counter + self.state[12] = self.state[12].wrapping_add(1); + if self.state[12] != 0 { return; }; + self.state[13] = self.state[13].wrapping_add(1); + } +} + +impl SeedableRng for ChaChaCore { + type Seed = [u8; SEED_WORDS*4]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_le = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_le); + Self { + state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants + seed_le[0], seed_le[1], seed_le[2], seed_le[3], // seed + seed_le[4], seed_le[5], seed_le[6], seed_le[7], // seed + 0, 0, 0, 0], // counter + } + } +} + +impl CryptoRng for ChaChaCore {} + +impl From<ChaChaCore> for ChaChaRng { + fn from(core: ChaChaCore) -> Self { + ChaChaRng(BlockRng::new(core)) + } +} + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use super::ChaChaRng; + + #[test] + fn test_chacha_construction() { + let seed = [0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, + 2,0,0,0,0,0,0,0, + 3,0,0,0,0,0,0,0]; + let mut rng1 = ChaChaRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 137206642); + + let mut rng2 = ChaChaRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 1325750369); + } + + #[test] + fn test_chacha_true_values_a() { + // Test vectors 1 and 2 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, + 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b, + 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, + 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2]; + assert_eq!(results, expected); + + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, + 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32, + 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, + 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_values_b() { + // Test vector 3 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1]; + let mut rng = ChaChaRng::from_seed(seed); + + // Skip block 0 + for _ in 0..16 { rng.next_u32(); } + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, + 0xe8252083, 0x60818b01, 0xf38422b8, 0x5aaa49c9, + 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, + 0x4436274e, 0x2561b3c8, 0xebdd4aa6, 0xa0136c00]; + assert_eq!(results, expected); + } + + #[test] + #[cfg(feature = "i128_support")] + fn test_chacha_true_values_c() { + // Test vector 4 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0xff, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]; + let expected = [0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, + 0xa78dea8f, 0x5e269039, 0xa1bebbc1, 0xcaf09aae, + 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, + 0x546ca624, 0x1bec45d5, 0x87f47473, 0x96f0992e]; + let expected_end = 3 * 16; + let mut results = [0u32; 16]; + + // Test block 2 by skipping block 0 and 1 + let mut rng1 = ChaChaRng::from_seed(seed); + for _ in 0..32 { rng1.next_u32(); } + for i in results.iter_mut() { *i = rng1.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng1.get_word_pos(), expected_end); + + // Test block 2 by using `set_word_pos` + let mut rng2 = ChaChaRng::from_seed(seed); + rng2.set_word_pos(2 * 16); + for i in results.iter_mut() { *i = rng2.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng2.get_word_pos(), expected_end); + + // Test skipping behaviour with other types + let mut buf = [0u8; 32]; + rng2.fill_bytes(&mut buf[..]); + assert_eq!(rng2.get_word_pos(), expected_end + 8); + rng2.fill_bytes(&mut buf[0..25]); + assert_eq!(rng2.get_word_pos(), expected_end + 15); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 17); + rng2.next_u32(); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 20); + rng2.fill_bytes(&mut buf[0..1]); + assert_eq!(rng2.get_word_pos(), expected_end + 21); + } + + #[test] + fn test_chacha_multiple_blocks() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + + // Store the 17*i-th 32-bit word, + // i.e., the i-th word of the i-th 16-word block + let mut results = [0u32; 16]; + for i in results.iter_mut() { + *i = rng.next_u32(); + for _ in 0..16 { + rng.next_u32(); + } + } + let expected = [0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, + 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384, + 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, + 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_bytes() { + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [118, 184, 224, 173, 160, 241, 61, 144, + 64, 93, 106, 229, 83, 134, 189, 40, + 189, 210, 25, 184, 160, 141, 237, 26, + 168, 54, 239, 204, 139, 119, 13, 199]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_nonce() { + // Test vector 5 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + // Although we do not support setting a nonce, we try it here anyway so + // we can use this test vector. + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2 + rng.set_stream(2u64 << (24 + 32)); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, + 0x88228b1a, 0x96a4dfb3, 0x5b76ab72, 0xc727ee54, + 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, + 0x99c28f5f, 0x628314e8, 0x398a19fa, 0x6ded1b53]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_clone_streams() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + let mut clone = rng.clone(); + for _ in 0..16 { + assert_eq!(rng.next_u64(), clone.next_u64()); + } + + rng.set_stream(51); + for _ in 0..7 { + assert!(rng.next_u32() != clone.next_u32()); + } + clone.set_stream(51); // switch part way through block + for _ in 7..16 { + assert_eq!(rng.next_u32(), clone.next_u32()); + } + } +} diff --git a/rand-0.5.6/src/prng/hc128.rs b/rand-0.5.6/src/prng/hc128.rs new file mode 100644 index 000000000..5aa2d243a --- /dev/null +++ b/rand-0.5.6/src/prng/hc128.rs @@ -0,0 +1,464 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://www.rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The HC-128 random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv + +/// A cryptographically secure random number generator that uses the HC-128 +/// algorithm. +/// +/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an +/// RNG. It is selected as one of the "stream ciphers suitable for widespread +/// adoption" by eSTREAM[^2]. +/// +/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before +/// it, but those have never been proven cryptographically secure (or have even +/// been significantly compromised, as in the case of RC-4[^5]). +/// +/// Because HC-128 works with simple indexing into a large array and with a few +/// operations that parallelize well, it has very good performance. The size of +/// the array it needs, 4kb, can however be a disadvantage. +/// +/// This implementation is not based on the version of HC-128 submitted to the +/// eSTREAM contest, but on a later version by the author with a few small +/// improvements from December 15, 2009[^3]. +/// +/// HC-128 has no known weaknesses that are easier to exploit than doing a +/// brute-force search of 2<sup>128</sup>. A very comprehensive analysis of the +/// current state of known attacks / weaknesses of HC-128 is given in *Some +/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4]. +/// +/// The average cycle length is expected to be +/// 2<sup>1024*32+10-1</sup> = 2<sup>32777</sup>. +/// We support seeding with a 256-bit array, which matches the 128-bit key +/// concatenated with a 128-bit IV from the stream cipher. +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( +/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). +/// *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256]( +/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html) +/// +/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And +/// Implementation Of HC-128 Stream Cipher"]( +/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf). +/// +/// [^5]: Internet Engineering Task Force (February 2015), +/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465). +/// +/// [`BlockRng`]: ../../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../trait.RngCore.html +#[derive(Clone, Debug)] +pub struct Hc128Rng(BlockRng<Hc128Core>); + +impl RngCore for Hc128Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Hc128Rng { + type Seed = <Hc128Core as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Hc128Rng(BlockRng::<Hc128Core>::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + BlockRng::<Hc128Core>::from_rng(rng).map(Hc128Rng) + } +} + +impl CryptoRng for Hc128Rng {} + +/// The core of `Hc128Rng`, used with `BlockRng`. +#[derive(Clone)] +pub struct Hc128Core { + t: [u32; 1024], + counter1024: usize, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Hc128Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Hc128Core {{}}") + } +} + +impl BlockRngCore for Hc128Core { + type Item = u32; + type Results = [u32; 16]; + + fn generate(&mut self, results: &mut Self::Results) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 & 512 == 0 { + // P block + results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + results[0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 = self.counter1024.wrapping_add(16); + } +} + +impl Hc128Core { + // One step of HC-128, update P and generate 32 bits keystream + #[inline(always)] + fn step_p(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + // FIXME: it would be great if we the bounds checks here could be + // optimized out, and we would not need unsafe. + // This improves performance by about 7%. + unsafe { + let temp0 = p.get_unchecked(i511).rotate_right(23); + let temp1 = p.get_unchecked(i3).rotate_right(10); + let temp2 = p.get_unchecked(i10).rotate_right(8); + *p.get_unchecked_mut(i) = p.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h1 function in HC-128 + let a = *p.get_unchecked(i12) as u8; + let c = (p.get_unchecked(i12) >> 16) as u8; + q[a as usize].wrapping_add(q[256 + c as usize]) + }; + temp3 ^ p.get_unchecked(i) + } + } + + // One step of HC-128, update Q and generate 32 bits keystream + // Similar to `step_p`, but `p` and `q` are swapped, and the rotates are to + // the left instead of to the right. + #[inline(always)] + fn step_q(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + unsafe { + let temp0 = q.get_unchecked(i511).rotate_left(23); + let temp1 = q.get_unchecked(i3).rotate_left(10); + let temp2 = q.get_unchecked(i10).rotate_left(8); + *q.get_unchecked_mut(i) = q.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h2 function in HC-128 + let a = *q.get_unchecked(i12) as u8; + let c = (q.get_unchecked(i12) >> 16) as u8; + p[a as usize].wrapping_add(p[256 + c as usize]) + }; + temp3 ^ q.get_unchecked(i) + } + } + + fn sixteen_steps(&mut self) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 < 512 { + // P block + self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 += 16; + } + + // Initialize an HC-128 random number generator. The seed has to be + // 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by + // 128 bit `iv` when HC-128 where to be used as a stream cipher. + fn init(seed: [u32; SEED_WORDS]) -> Self { + #[inline] + fn f1(x: u32) -> u32 { + x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) + } + + #[inline] + fn f2(x: u32) -> u32 { + x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) + } + + let mut t = [0u32; 1024]; + + // Expand the key and iv into P and Q + let (key, iv) = seed.split_at(4); + t[..4].copy_from_slice(key); + t[4..8].copy_from_slice(key); + t[8..12].copy_from_slice(iv); + t[12..16].copy_from_slice(iv); + + // Generate the 256 intermediate values W[16] ... W[256+16-1], and + // copy the last 16 generated values to the start op P. + for i in 16..256+16 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(i as u32); + } + { + let (p1, p2) = t.split_at_mut(256); + p1[0..16].copy_from_slice(&p2[0..16]); + } + + // Generate both the P and Q tables + for i in 16..1024 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); + } + + let mut core = Self { t, counter1024: 0 }; + + // run the cipher 1024 steps + for _ in 0..64 { core.sixteen_steps() }; + core.counter1024 = 0; + core + } +} + +impl SeedableRng for Hc128Core { + type Seed = [u8; SEED_WORDS*4]; + + /// Create an HC-128 random number generator with a seed. The seed has to be + /// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv` + /// when HC-128 where to be used as a stream cipher. + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_u32); + Self::init(seed_u32) + } +} + +impl CryptoRng for Hc128Core {} + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use super::Hc128Rng; + + #[test] + // Test vector 1 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_a() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x73150082, 0x3bfd03a0, 0xfb2fd77f, 0xaa63af0e, + 0xde122fc6, 0xa7dc29b6, 0x62a68527, 0x8b75ec68, + 0x9036db1e, 0x81896005, 0x00ade078, 0x491fbf9a, + 0x1cdc3013, 0x6c3d6e24, 0x90f664b2, 0x9cd57102]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 2 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_b() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xc01893d5, 0xb7dbe958, 0x8f65ec98, 0x64176604, + 0x36fc6724, 0xc82c6eec, 0x1b1c38a7, 0xc9b42a95, + 0x323ef123, 0x0a6a908b, 0xce757b68, 0x9f14f7bb, + 0xe4cde011, 0xaeb5173f, 0x89608c94, 0xb5cf46ca]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 3 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_c() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x518251a4, 0x04b4930a, 0xb02af931, 0x0639f032, + 0xbcb4a47a, 0x5722480b, 0x2bf99f72, 0xcdc0e566, + 0x310f0c56, 0xd3cc83e8, 0x663db8ef, 0x62dfe07f, + 0x593e1790, 0xc5ceaa9c, 0xab03806f, 0xc9a6e5a0]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_u64() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u64; 8]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0x3bfd03a073150082, 0xaa63af0efb2fd77f, + 0xa7dc29b6de122fc6, 0x8b75ec6862a68527, + 0x818960059036db1e, 0x491fbf9a00ade078, + 0x6c3d6e241cdc3013, 0x9cd5710290f664b2]; + assert_eq!(results, expected); + + // The RNG operates in a P block of 512 results and next a Q block. + // After skipping 2*800 u32 results we end up somewhere in the Q block + // of the second round + for _ in 0..800 { rng.next_u64(); } + + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0xd8c4d6ca84d0fc10, 0xf16a5d91dc66e8e7, + 0xd800de5bc37a8653, 0x7bae1f88c0dfbb4c, + 0x3bfe1f374e6d4d14, 0x424b55676be3fa06, + 0xe3a1e8758cbff579, 0x417f7198c5652bcd]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_bytes() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + let expected = [0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06, + 0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57, + 0x72, 0x9f, 0xf9, 0x2b, 0x66, 0xe5, 0xc0, 0xcd, + 0x56, 0x0c, 0x0f, 0x31, 0xe8, 0x83, 0xcc, 0xd3, + 0xef, 0xb8, 0x3d, 0x66, 0x7f, 0xe0, 0xdf, 0x62, + 0x90, 0x17, 0x3e, 0x59, 0x9c, 0xaa, 0xce, 0xc5, + 0x6f, 0x80, 0x03, 0xab, 0xa0, 0xe5, 0xa6, 0xc9, + 0x60, 0x95, 0x84, 0x7a, 0xa5, 0x68, 0x5a, 0x84, + 0xea, 0xd5, 0xf3, 0xea, 0x73, 0xa9, 0xad, 0x01, + 0x79, 0x7d, 0xbe, 0x9f, 0xea, 0xe3, 0xf9, 0x74, + 0x0e, 0xda, 0x2f, 0xa0, 0xe4, 0x7b, 0x4b, 0x1b, + 0xdd, 0x17, 0x69, 0x4a, 0xfe, 0x9f, 0x56, 0x95, + 0xad, 0x83, 0x6b, 0x9d, 0x60, 0xa1, 0x99, 0x96, + 0x90, 0x00, 0x66, 0x7f, 0xfa, 0x7e, 0x65, 0xe9, + 0xac, 0x8b, 0x92, 0x34, 0x77, 0xb4, 0x23, 0xd0, + 0xb9, 0xab, 0xb1, 0x47, 0x7d, 0x4a, 0x13, 0x0a]; + + // Pick a somewhat large buffer so we can test filling with the + // remainder from `state.results`, directly filling the buffer, and + // filling the remainder of the buffer. + let mut buffer = [0u8; 16*4*2]; + // Consume a value so that we have a remainder. + assert!(rng.next_u64() == 0x04b4930a518251a4); + rng.fill_bytes(&mut buffer); + + // [u8; 128] doesn't implement PartialEq + assert_eq!(buffer.len(), expected.len()); + for (b, e) in buffer.iter().zip(expected.iter()) { + assert_eq!(b, e); + } + } + + #[test] + fn test_hc128_clone() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng1 = Hc128Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } +} diff --git a/rand-0.5.6/src/prng/isaac.rs b/rand-0.5.6/src/prng/isaac.rs new file mode 100644 index 000000000..99c80d6a0 --- /dev/null +++ b/rand-0.5.6/src/prng/isaac.rs @@ -0,0 +1,494 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; +use prng::isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w32 = w<u32>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses the ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1][^2]. +/// +/// ISAAC is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson, +/// named ISAAC+[^3]. But because the specification is not complete, because +/// there is no good implementation, and because the suggested bias may not +/// exist, it is not implemented here. +/// +/// ## Overview of the ISAAC algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = a ^ a << 13 if i = 0 mod 4 +/// a ^ a >> 6 if i = 1 mod 4 +/// a ^ a << 2 if i = 2 mod 4 +/// a ^ a >> 16 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = f(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>2 mod 256] +/// s[i] = y +/// b = x + s[y>>10 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// Numbers are generated in blocks of 256. This means the function above only +/// runs once every 256 times you ask for a next random number. In all other +/// circumstances the last element of the results array is returned. +/// +/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs. +/// 2 * 256 * 4 = 2 kb to hold the state and results. +/// +/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]( +/// http://burtleburtle.net/bob/rand/isaacafa.html) +/// +/// [^2]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]( +/// https://eprint.iacr.org/2006/438) +/// +/// [`Hc128Rng`]: ../hc128/struct.Hc128Rng.html +/// [`BlockRng`]: ../../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacRng(BlockRng<IsaacCore>); + +impl RngCore for IsaacRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for IsaacRng { + type Seed = <IsaacCore as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacRng(BlockRng::<IsaacCore>::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng)) + } +} + +impl IsaacRng { + /// Create an ISAAC random number generator using the default + /// fixed seed. + /// + /// DEPRECATED. `IsaacRng::new_from_u64(0)` will produce identical results. + #[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")] + pub fn new_unseeded() -> Self { + Self::seed_from_u64(0) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `IsaacRng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacCore { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w32; RAND_SIZE], + a: w32, + b: w32, + c: w32, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for IsaacCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "IsaacCore {{}}") + } +} + +impl BlockRngCore for IsaacCore { + type Item = u32; + type Results = IsaacArray<Self::Item>; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`IsaacRng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`IsaacRng`]: struct.IsaacRng.html + fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w32; RAND_SIZE], + results: &mut [u32; RAND_SIZE], + mix: w32, + a: &mut w32, + b: &mut w32, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 2); + mem[base + m] = y; + *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl IsaacCore { + /// Create a new ISAAC random number generator. + /// + /// The author Bob Jenkins describes how to best initialize ISAAC here: + /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324> + /// The answer is included here just in case: + /// + /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will + /// do fine, and they should have their expected strength (eg a 40-bit key + /// will take as much time to brute force as 40-bit keys usually will). You + /// could fill the remainder with 0, but set the last array element to the + /// length of the key provided (to distinguish keys that differ only by + /// different amounts of 0 padding). You do still need to call `randinit()` + /// to make sure the initial state isn't uniform-looking." + /// "After publishing ISAAC, I wanted to limit the key to half the size of + /// `r[]`, and repeat it twice. That would have made it hard to provide a + /// key that sets the whole internal state to anything convenient. But I'd + /// already published it." + /// + /// And his answer to the question "For my code, would repeating the key + /// over and over to fill 256 integers be a better solution than + /// zero-filling, or would they essentially be the same?": + /// "If the seed is under 32 bytes, they're essentially the same, otherwise + /// repeating the seed would be stronger. randinit() takes a chunk of 32 + /// bytes, mixes it, and combines that with the next 32 bytes, et cetera. + /// Then loops over all the elements the same way a second time." + #[inline] + fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, + e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) { + *a ^= *b << 11; *d += *a; *b += *c; + *b ^= *c >> 2; *e += *b; *c += *d; + *c ^= *d << 8; *f += *c; *d += *e; + *d ^= *e >> 16; *g += *d; *e += *f; + *e ^= *f << 10; *h += *e; *f += *g; + *f ^= *g >> 4; *a += *f; *g += *h; + *g ^= *h << 8; *b += *g; *h += *a; + *h ^= *a >> 9; *c += *h; *a += *b; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b9) + // and applying mix() 4 times. + let mut a = w(0x1367df5a); + let mut b = w(0x95d90059); + let mut c = w(0xc3163e4b); + let mut d = w(0x0f421ad8); + let mut e = w(0xd92a4a78); + let mut f = w(0xa51a3c49); + let mut g = w(0xc4efea1b); + let mut h = w(0x30609119); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } +} + +impl SeedableRng for IsaacCore { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 8]; + le::read_u32_into(&seed, &mut seed_u32); + // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed as u32); + key[1] = w((seed >> 32) as u32); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u32); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use super::IsaacRng; + + #[test] + fn test_isaac_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 2869442790); + + let mut rng2 = IsaacRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 3094074039); + } + + #[test] + fn test_isaac_true_values_32() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut results = [0u32; 10]; + for i in results.iter_mut() { *i = rng1.next_u32(); } + let expected = [ + 2558573138, 873787463, 263499565, 2103644246, 3595684709, + 4203127393, 264982119, 2765226902, 2737944514, 3900253796]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng2 = IsaacRng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u32(); } + + for i in results.iter_mut() { *i = rng2.next_u32(); } + let expected = [ + 3676831399, 3183332890, 2834741178, 3854698763, 2717568474, + 1576568959, 3507990155, 179069555, 141456972, 2478885421]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_values_64() { + // As above, using little-endian versions of above values + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u64; 5]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [ + 3752888579798383186, 9035083239252078381,18052294697452424037, + 11876559110374379111, 16751462502657800130]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_bytes() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac_true_values as bytes in LE order + let expected = [82, 186, 128, 152, 71, 240, 20, 52, + 45, 175, 180, 15, 86, 16, 99, 125, + 101, 203, 81, 214, 97, 162, 134, 250, + 103, 78, 203, 15, 150, 3, 210, 164]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = IsaacRng::seed_from_u64(0); + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 16] = [ + 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA, + 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD, + 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846, + 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_clone() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } + + #[test] + #[cfg(all(feature="serde1", feature="std"))] + fn test_isaac_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u32(), deserialized.next_u32()); + } + } +} diff --git a/rand-0.5.6/src/prng/isaac64.rs b/rand-0.5.6/src/prng/isaac64.rs new file mode 100644 index 000000000..fb3156df9 --- /dev/null +++ b/rand-0.5.6/src/prng/isaac64.rs @@ -0,0 +1,491 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC-64 random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng64}; +use prng::isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w64 = w<u64>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses ISAAC-64, the 64-bit variant of the +/// ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1]. +/// +/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers +/// instead of 32-bit, it uses twice as much memory to hold its state and +/// results. Also it uses different constants for shifts and indirect indexing, +/// optimized to give good results for 64bit arithmetic. +/// +/// ISAAC-64 is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// ## Overview of the ISAAC-64 algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4 +/// a ^ a >> 5 if i = 1 mod 4 +/// a ^ a << 12 if i = 2 mod 4 +/// a ^ a >> 33 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = mix(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>3 mod 256] +/// s[i] = y +/// b = x + s[y>>11 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods. +/// +/// See for more information the documentation of [`IsaacRng`]. +/// +/// [^1]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html +/// [`Hc128Rng`]: ../hc128/struct.Hc128Rng.html +/// [`BlockRng64`]: ../../../rand_core/block/struct.BlockRng64.html +/// [`RngCore`]: ../../trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Rng(BlockRng64<Isaac64Core>); + +impl RngCore for Isaac64Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Isaac64Rng { + type Seed = <Isaac64Core as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng)) + } +} + +impl Isaac64Rng { + /// Create a 64-bit ISAAC random number generator using the + /// default fixed seed. + /// + /// DEPRECATED. `Isaac64Rng::new_from_u64(0)` will produce identical results. + #[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")] + pub fn new_unseeded() -> Self { + Self::seed_from_u64(0) + } + + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `Isaac64Rng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Core { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w64; RAND_SIZE], + a: w64, + b: w64, + c: w64, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Isaac64Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Isaac64Core {{}}") + } +} + +impl BlockRngCore for Isaac64Core { + type Item = u64; + type Results = IsaacArray<Self::Item>; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`Isaac64Rng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`Isaac64Rng`]: struct.Isaac64Rng.html + fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w64; RAND_SIZE], + results: &mut [u64; RAND_SIZE], + mix: w64, + a: &mut w64, + b: &mut w64, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 3); + mem[base + m] = y; + *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl Isaac64Core { + /// Create a new ISAAC-64 random number generator. + fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, + e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) { + *a -= *e; *f ^= *h >> 9; *h += *a; + *b -= *f; *g ^= *a << 9; *a += *b; + *c -= *g; *h ^= *b >> 23; *b += *c; + *d -= *h; *a ^= *c << 15; *c += *d; + *e -= *a; *b ^= *d >> 14; *d += *e; + *f -= *b; *c ^= *e << 20; *e += *f; + *g -= *c; *d ^= *f >> 17; *f += *g; + *h -= *d; *e ^= *g << 14; *g += *h; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13) + // and applying mix() 4 times. + let mut a = w(0x647c4677a2884b7c); + let mut b = w(0xb9f8b322c73ac862); + let mut c = w(0x8c0ea5053d4712a0); + let mut d = w(0xb29b2e824a595524); + let mut e = w(0x82f053db8355e0ce); + let mut f = w(0x48fe4a0fa5a09315); + let mut g = w(0xae985bf2cbfc89ed); + let mut h = w(0x98f5704f6c44c0ab); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } + + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +impl SeedableRng for Isaac64Core { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 4]; + le::read_u64_into(&seed, &mut seed_u64); + // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u64); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use super::Isaac64Rng; + + #[test] + fn test_isaac64_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + assert_eq!(rng1.next_u64(), 14964555543728284049); + + let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 919595328260451758); + } + + #[test] + fn test_isaac64_true_values_64() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut results = [0u64; 10]; + for i in results.iter_mut() { *i = rng1.next_u64(); } + let expected = [ + 15071495833797886820, 7720185633435529318, + 10836773366498097981, 5414053799617603544, + 12890513357046278984, 17001051845652595546, + 9240803642279356310, 12558996012687158051, + 14673053937227185542, 1677046725350116783]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0, + 49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0]; + let mut rng2 = Isaac64Rng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u64(); } + + for i in results.iter_mut() { *i = rng2.next_u64(); } + let expected = [ + 18143823860592706164, 8491801882678285927, 2699425367717515619, + 17196852593171130876, 2606123525235546165, 15790932315217671084, + 596345674630742204, 9947027391921273664, 11788097613744130851, + 10391409374914919106]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_32() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u32; 12]; + for i in results.iter_mut() { *i = rng.next_u32(); } + // Subset of above values, as an LE u32 sequence + let expected = [ + 3477963620, 3509106075, + 687845478, 1797495790, + 227048253, 2523132918, + 4044335064, 1260557630, + 4079741768, 3001306521, + 69157722, 3958365844]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_mixed() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + // Test alternating between `next_u64` and `next_u32` works as expected. + // Values are the same as `test_isaac64_true_values` and + // `test_isaac64_true_values_32`. + assert_eq!(rng.next_u64(), 15071495833797886820); + assert_eq!(rng.next_u32(), 687845478); + assert_eq!(rng.next_u32(), 1797495790); + assert_eq!(rng.next_u64(), 10836773366498097981); + assert_eq!(rng.next_u32(), 4044335064); + // Skip one u32 + assert_eq!(rng.next_u64(), 12890513357046278984); + assert_eq!(rng.next_u32(), 69157722); + } + + #[test] + fn test_isaac64_true_bytes() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac64_true_values as bytes in LE order + let expected = [100, 131, 77, 207, 155, 181, 40, 209, + 102, 176, 255, 40, 238, 155, 35, 107, + 61, 123, 136, 13, 246, 243, 99, 150, + 216, 167, 15, 241, 62, 149, 34, 75]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = Isaac64Rng::seed_from_u64(0); + let mut results = [0u64; 16]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 16] = [ + 0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB, + 0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49, + 0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F, + 0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF, + 0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD, + 0xB9090F3D42D2D2EA]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_clone() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } + } + + #[test] + #[cfg(all(feature="serde1", feature="std"))] + fn test_isaac64_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } + } +} diff --git a/rand-0.5.6/src/prng/isaac_array.rs b/rand-0.5.6/src/prng/isaac_array.rs new file mode 100644 index 000000000..3ebf828c6 --- /dev/null +++ b/rand-0.5.6/src/prng/isaac_array.rs @@ -0,0 +1,137 @@ +// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ISAAC helper functions for 256-element arrays. + +// Terrible workaround because arrays with more than 32 elements do not +// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other +// traits for that matter. + +#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + +#[derive(Copy, Clone)] +#[allow(missing_debug_implementations)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacArray<T> { + #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))] + #[cfg_attr(feature="serde1", serde(bound( + serialize = "T: Serialize", + deserialize = "T: Deserialize<'de> + Copy + Default")))] + inner: [T; RAND_SIZE] +} + +impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> { + #[inline(always)] + fn as_ref(&self) -> &[T] { + &self.inner[..] + } +} + +impl<T> ::core::convert::AsMut<[T]> for IsaacArray<T> { + #[inline(always)] + fn as_mut(&mut self) -> &mut [T] { + &mut self.inner[..] + } +} + +impl<T> ::core::ops::Deref for IsaacArray<T> { + type Target = [T; RAND_SIZE]; + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<T> ::core::ops::DerefMut for IsaacArray<T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] { + &mut self.inner + } +} + +impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default { + fn default() -> IsaacArray<T> { + IsaacArray { inner: [T::default(); RAND_SIZE] } + } +} + + +#[cfg(feature="serde1")] +pub(super) mod isaac_array_serde { + const RAND_SIZE_LEN: usize = 8; + const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde::de::{Visitor,SeqAccess}; + use serde::de; + + use core::fmt; + + pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error> + where + T: Serialize, + S: Serializer + { + use serde::ser::SerializeTuple; + + let mut seq = ser.serialize_tuple(RAND_SIZE)?; + + for e in arr.iter() { + seq.serialize_element(&e)?; + } + + seq.end() + } + + #[inline] + pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error> + where + T: Deserialize<'de>+Default+Copy, + D: Deserializer<'de>, + { + use core::marker::PhantomData; + struct ArrayVisitor<T> { + _pd: PhantomData<T>, + }; + impl<'de,T> Visitor<'de> for ArrayVisitor<T> + where + T: Deserialize<'de>+Default+Copy + { + type Value = [T; RAND_SIZE]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Isaac state array") + } + + #[inline] + fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error> + where + A: SeqAccess<'de>, + { + let mut out = [Default::default();RAND_SIZE]; + + for i in 0..RAND_SIZE { + match seq.next_element()? { + Some(val) => out[i] = val, + None => return Err(de::Error::invalid_length(i, &self)), + }; + } + + Ok(out) + } + } + + de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData}) + } +} diff --git a/rand-0.5.6/src/prng/mod.rs b/rand-0.5.6/src/prng/mod.rs new file mode 100644 index 000000000..240b6828b --- /dev/null +++ b/rand-0.5.6/src/prng/mod.rs @@ -0,0 +1,330 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Pseudo-random number generators. +//! +//! Pseudo-random number generators are algorithms to produce apparently random +//! numbers deterministically, and usually fairly quickly. See the documentation +//! of the [`rngs` module] for some introduction to PRNGs. +//! +//! As mentioned there, PRNGs fall in two broad categories: +//! +//! - [basic PRNGs], primarily designed for simulations +//! - [CSPRNGs], primarily designed for cryptography +//! +//! In simple terms, the basic PRNGs are often predictable; CSPRNGs should not +//! be predictable *when used correctly*. +//! +//! Contents of this documentation: +//! +//! 1. [The generators](#the-generators) +//! 1. [Performance and size](#performance) +//! 1. [Quality and cycle length](#quality) +//! 1. [Security](#security) +//! 1. [Extra features](#extra-features) +//! 1. [Further reading](#further-reading) +//! +//! +//! # The generators +//! +//! ## Basic pseudo-random number generators (PRNGs) +//! +//! The goal of regular, non-cryptographic PRNGs is usually to find a good +//! balance between simplicity, quality, memory usage and performance. These +//! algorithms are very important to Monte Carlo simulations, and also suitable +//! for several other problems such as randomized algorithms and games (except +//! where there is a risk of players predicting the next output value from +//! previous values, in which case a CSPRNG should be used). +//! +//! Currently Rand provides only one PRNG, and not a very good one at that: +//! +//! | name | full name | performance | memory | quality | period | features | +//! |------|-----------|-------------|--------|---------|--------|----------| +//! | [`XorShiftRng`] | Xorshift 32/128 | ★★★☆☆ | 16 bytes | ★☆☆☆☆ | `u32` * 2<sup>128</sup> - 1 | — | +//! +// Quality stars [not rendered in documentation]: +// 5. reserved for crypto-level (e.g. ChaCha8, ISAAC) +// 4. good performance on TestU01 and PractRand, good theory +// (e.g. PCG, truncated Xorshift*) +// 3. good performance on TestU01 and PractRand, but "falling through the +// cracks" or insufficient theory (e.g. SFC, Xoshiro) +// 2. imperfect performance on tests or other limiting properties, but not +// terrible (e.g. Xoroshiro128+) +// 1. clear deficiencies in test results, cycle length, theory, or other +// properties (e.g. Xorshift) +// +// Performance stars [not rendered in documentation]: +// Meant to give an indication of relative performance. Roughly follows a log +// scale, based on the performance of `next_u64` on a current i5/i7: +// - 5. 8000 MB/s+ +// - 4. 4000 MB/s+ +// - 3. 2000 MB/s+ +// - 2. 1000 MB/s+ +// - 1. < 1000 MB/s +// +//! ## Cryptographically secure pseudo-random number generators (CSPRNGs) +//! +//! CSPRNGs have much higher requirements than basic PRNGs. The primary +//! consideration is security. Performance and simplicity are also important, +//! but in general CSPRNGs are more complex and slower than regular PRNGs. +//! Quality is no longer a concern, as it is a requirement for a +//! CSPRNG that the output is basically indistinguishable from true randomness +//! since any bias or correlation makes the output more predictable. +//! +//! There is a close relationship between CSPRNGs and cryptographic ciphers. +//! Any block cipher can be turned into a CSPRNG by encrypting a counter. Stream +//! ciphers are basically a CSPRNG and a combining operation, usually XOR. This +//! means that we can easily use any stream cipher as a CSPRNG. +//! +//! Rand currently provides two trustworthy CSPRNGs and two CSPRNG-like PRNGs: +//! +//! | name | full name | performance | initialization | memory | predictability | forward secrecy | +//! |------|-----------|--------------|--------------|----------|----------------|-------------------------| +//! | [`ChaChaRng`] | ChaCha20 | ★☆☆☆☆ | fast | 136 bytes | secure | no | +//! | [`Hc128Rng`] | HC-128 | ★★☆☆☆ | slow | 4176 bytes | secure | no | +//! | [`IsaacRng`] | ISAAC | ★★☆☆☆ | slow | 2072 bytes | unknown | unknown | +//! | [`Isaac64Rng`] | ISAAC-64 | ★★☆☆☆ | slow | 4136 bytes| unknown | unknown | +//! +//! It should be noted that the ISAAC generators are only included for +//! historical reasons, they have been with the Rust language since the very +//! beginning. They have good quality output and no attacks are known, but have +//! received little attention from cryptography experts. +//! +//! +//! # Performance +//! +//! First it has to be said most PRNGs are very fast, and will rarely be a +//! performance bottleneck. +//! +//! Performance of basic PRNGs is a bit of a subtle thing. It depends a lot on +//! the CPU architecture (32 vs. 64 bits), inlining, and also on the number of +//! available registers. This often causes the performance to be affected by +//! surrounding code due to inlining and other usage of registers. +//! +//! When choosing a PRNG for performance it is important to benchmark your own +//! application due to interactions between PRNGs and surrounding code and +//! dependence on the CPU architecture as well as the impact of the size of +//! data requested. Because of all this, we do not include performance numbers +//! here but merely a qualitative rating. +//! +//! CSPRNGs are a little different in that they typically generate a block of +//! output in a cache, and pull outputs from the cache. This allows them to have +//! good amortised performance, and reduces or completely removes the influence +//! of surrounding code on the CSPRNG performance. +//! +//! ### Worst-case performance +//! Because CSPRNGs usually produce a block of values into a cache, they have +//! poor worst case performance (in contrast to basic PRNGs, where the +//! performance is usually quite regular). +//! +//! ## State size +//! +//! Simple PRNGs often use very little memory, commonly only a few words, where +//! a *word* is usually either `u32` or `u64`. This is not true for all +//! non-cryptographic PRNGs however, for example the historically popular +//! Mersenne Twister MT19937 algorithm requires 2.5 kB of state. +//! +//! CSPRNGs typically require more memory; since the seed size is recommended +//! to be at least 192 bits and some more may be required for the algorithm, +//! 256 bits would be approximately the minimum secure size. In practice, +//! CSPRNGs tend to use quite a bit more, [`ChaChaRng`] is relatively small with +//! 136 bytes of state. +//! +//! ## Initialization time +//! +//! The time required to initialize new generators varies significantly. Many +//! simple PRNGs and even some cryptographic ones (including [`ChaChaRng`]) +//! only need to copy the seed value and some constants into their state, and +//! thus can be constructed very quickly. In contrast, CSPRNGs with large state +//! require an expensive key-expansion. +//! +//! # Quality +//! +//! Many basic PRNGs are not much more than a couple of bitwise and arithmetic +//! operations. Their simplicity gives good performance, but also means there +//! are small regularities hidden in the generated random number stream. +//! +//! How much do those hidden regularities matter? That is hard to say, and +//! depends on how the RNG gets used. If there happen to be correlations between +//! the random numbers and the algorithm they are used in, the results can be +//! wrong or misleading. +//! +//! A random number generator can be considered good if it gives the correct +//! results in as many applications as possible. The quality of PRNG +//! algorithms can be evaluated to some extend analytically, to determine the +//! cycle length and to rule out some correlations. Then there are empirical +//! test suites designed to test how well a PRNG performs on a wide range of +//! possible uses, the latest and most complete of which are [TestU01] and +//! [PractRand]. +//! +//! CSPRNGs tend to be more complex, and have an explicit requirement to be +//! unpredictable. This implies there must be no obvious correlations between +//! output values. +//! +//! ### Quality stars: +//! PRNGs with 3 stars or more should be good enough for any purpose. +//! 1 or 2 stars may be good enough for typical apps and games, but do not work +//! well with all algorithms. +//! +//! ## Period +//! +//! The *period* or *cycle length* of a PRNG is the number of values that can be +//! generated after which it starts repeating the same random number stream. +//! Many PRNGs have a fixed-size period, but for some only an expected average +//! cycle length can be given, where the exact length depends on the seed. +//! +//! On today's hardware, even a fast RNG with a cycle length of *only* +//! 2<sup>64</sup> can be used for centuries before cycling. Yet we recommend a +//! period of 2<sup>128</sup> or more, which most modern PRNGs satisfy. +//! Alternatively a PRNG with shorter period but support for multiple streams +//! may be chosen. There are two reasons for this, as follows. +//! +//! If we see the entire period of an RNG as one long random number stream, +//! every independently seeded RNG returns a slice of that stream. When multiple +//! RNG are seeded randomly, there is an increasingly large chance to end up +//! with a partially overlapping slice of the stream. +//! +//! If the period of the RNG is 2<sup>128</sup>, and an application consumes +//! 2<sup>48</sup> values, it then takes about 2<sup>32</sup> random +//! initializations to have a chance of 1 in a million to repeat part of an +//! already used stream. This seems good enough for common usage of +//! non-cryptographic generators, hence the recommendation of at least +//! 2<sup>128</sup>. As an estimate, the chance of any overlap in a period of +//! size `p` with `n` independent seeds and `u` values used per seed is +//! approximately `1 - e^(-u * n^2 / (2 * p))`. +//! +//! Further, it is not recommended to use the full period of an RNG. Many +//! PRNGs have a property called *k-dimensional equidistribution*, meaning that +//! for values of some size (potentially larger than the output size), all +//! possible values are produced the same number of times over the generator's +//! period. This is not a property of true randomness. This is known as the +//! generalized birthday problem, see the [PCG paper] for a good explanation. +//! This results in a noticable bias on output after generating more values +//! than the square root of the period (after 2<sup>64</sup> values for a +//! period of 2<sup>128</sup>). +//! +//! +//! # Security +//! +//! ## Predictability +//! +//! From the context of any PRNG, one can ask the question *given some previous +//! output from the PRNG, is it possible to predict the next output value?* +//! This is an important property in any situation where there might be an +//! adversary. +//! +//! Regular PRNGs tend to be predictable, although with varying difficulty. In +//! some cases prediction is trivial, for example plain Xorshift outputs part of +//! its state without mutation, and prediction is as simple as seeding a new +//! Xorshift generator from four `u32` outputs. Other generators, like +//! [PCG](http://www.pcg-random.org/predictability.html) and truncated Xorshift* +//! are harder to predict, but not outside the realm of common mathematics and a +//! desktop PC. +//! +//! The basic security that CSPRNGs must provide is the infeasibility to predict +//! output. This requirement is formalized as the [next-bit test]; this is +//! roughly stated as: given the first *k* bits of a random sequence, the +//! sequence satisfies the next-bit test if there is no algorithm able to +//! predict the next bit using reasonable computing power. +//! +//! A further security that *some* CSPRNGs provide is forward secrecy: +//! in the event that the CSPRNGs state is revealed at some point, it must be +//! infeasible to reconstruct previous states or output. Note that many CSPRNGs +//! *do not* have forward secrecy in their usual formulations. +//! +//! As an outsider it is hard to get a good idea about the security of an +//! algorithm. People in the field of cryptography spend a lot of effort +//! analyzing existing designs, and what was once considered good may now turn +//! out to be weaker. Generally it is best to use algorithms well-analyzed by +//! experts, such as those recommended by NIST or ECRYPT. +//! +//! ## State and seeding +//! +//! It is worth noting that a CSPRNG's security relies absolutely on being +//! seeded with a secure random key. Should the key be known or guessable, all +//! output of the CSPRNG is easy to guess. This implies that the seed should +//! come from a trusted source; usually either the OS or another CSPRNG. Our +//! seeding helper trait, [`FromEntropy`], and the source it uses +//! ([`EntropyRng`]), should be secure. Additionally, [`ThreadRng`] is a CSPRNG, +//! thus it is acceptable to seed from this (although for security applications +//! fresh/external entropy should be preferred). +//! +//! Further, it should be obvious that the internal state of a CSPRNG must be +//! kept secret. With that in mind, our implementations do not provide direct +//! access to most of their internal state, and `Debug` implementations do not +//! print any internal state. This does not fully protect CSPRNG state; code +//! within the same process may read this memory (and we allow cloning and +//! serialisation of CSPRNGs for convenience). Further, a running process may be +//! forked by the operating system, which may leave both processes with a copy +//! of the same generator. +//! +//! ## Not a crypto library +//! +//! It should be emphasised that this is not a cryptography library; although +//! Rand does take some measures to provide secure random numbers, it does not +//! necessarily take all recommended measures. Further, cryptographic processes +//! such as encryption and authentication are complex and must be implemented +//! very carefully to avoid flaws and resist known attacks. It is therefore +//! recommended to use specialized libraries where possible, for example +//! [openssl], [ring] and the [RustCrypto libraries]. +//! +//! +//! # Extra features +//! +//! Some PRNGs may provide extra features, like: +//! +//! - Support for multiple streams, which can help with parallel tasks. +//! - The ability to jump or seek around in the random number stream; +//! with large periood this can be used as an alternative to streams. +//! +//! +//! # Further reading +//! +//! There is quite a lot that can be said about PRNGs. The [PCG paper] is a +//! very approachable explaining more concepts. +//! +//! A good paper about RNG quality is +//! ["Good random number generators are (not so) easy to find"]( +//! http://random.mat.sbg.ac.at/results/peter/A19final.pdf) by P. Hellekalek. +//! +//! +//! [`rngs` module]: ../rngs/index.html +//! [basic PRNGs]: #basic-pseudo-random-number-generators-prngs +//! [CSPRNGs]: #cryptographically-secure-pseudo-random-number-generators-csprngs +//! [`XorShiftRng`]: struct.XorShiftRng.html +//! [`ChaChaRng`]: chacha/struct.ChaChaRng.html +//! [`Hc128Rng`]: hc128/struct.Hc128Rng.html +//! [`IsaacRng`]: isaac/struct.IsaacRng.html +//! [`Isaac64Rng`]: isaac64/struct.Isaac64Rng.html +//! [`ThreadRng`]: ../rngs/struct.ThreadRng.html +//! [`FromEntropy`]: ../trait.FromEntropy.html +//! [`EntropyRng`]: ../rngs/struct.EntropyRng.html +//! [TestU01]: http://simul.iro.umontreal.ca/testu01/tu01.html +//! [PractRand]: http://pracrand.sourceforge.net/ +//! [PCG paper]: http://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf +//! [openssl]: https://crates.io/crates/openssl +//! [ring]: https://crates.io/crates/ring +//! [RustCrypto libraries]: https://github.com/RustCrypto +//! [next-bit test]: https://en.wikipedia.org/wiki/Next-bit_test + + +pub mod chacha; +pub mod hc128; +pub mod isaac; +pub mod isaac64; +mod xorshift; + +mod isaac_array; + +pub use self::chacha::ChaChaRng; +pub use self::hc128::Hc128Rng; +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng; +pub use self::xorshift::XorShiftRng; diff --git a/rand-0.5.6/src/prng/xorshift.rs b/rand-0.5.6/src/prng/xorshift.rs new file mode 100644 index 000000000..90871f8bb --- /dev/null +++ b/rand-0.5.6/src/prng/xorshift.rs @@ -0,0 +1,225 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Xorshift generators + +use core::num::Wrapping as w; +use core::{fmt, slice}; +use rand_core::{RngCore, SeedableRng, Error, impls, le}; + +/// An Xorshift random number generator. +/// +/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `IsaacRng` or `OsRng`. +/// +/// [^1]: Marsaglia, George (July 2003). +/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). +/// *Journal of Statistical Software*. Vol. 8 (Issue 14). +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct XorShiftRng { + x: w<u32>, + y: w<u32>, + z: w<u32>, + w: w<u32>, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for XorShiftRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "XorShiftRng {{}}") + } +} + +impl XorShiftRng { + /// Creates a new XorShiftRng instance which is not seeded. + /// + /// The initial values of this RNG are constants, so all generators created + /// by this function will yield the same stream of random numbers. It is + /// highly recommended that this is created through `SeedableRng` instead of + /// this function + #[deprecated(since="0.5.0", note="use the FromEntropy or SeedableRng trait")] + pub fn new_unseeded() -> XorShiftRng { + XorShiftRng { + x: w(0x193a6754), + y: w(0xa8a7d469), + z: w(0x97830e05), + w: w(0x113ba7bb), + } + } +} + +impl RngCore for XorShiftRng { + #[inline] + fn next_u32(&mut self) -> u32 { + let x = self.x; + let t = x ^ (x << 11); + self.x = self.y; + self.y = self.z; + self.z = self.w; + let w_ = self.w; + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); + self.w.0 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_u32(self) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for XorShiftRng { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 4]; + le::read_u32_into(&seed, &mut seed_u32); + + // Xorshift cannot be seeded with 0 and we cannot return an Error, but + // also do not wish to panic (because a random seed can legitimately be + // 0); our only option is therefore to use a preset value. + if seed_u32.iter().all(|&x| x == 0) { + seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; + } + + XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + } + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + let mut seed_u32 = [0u32; 4]; + loop { + unsafe { + let ptr = seed_u32.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); + rng.try_fill_bytes(slice)?; + } + if !seed_u32.iter().all(|&x| x == 0) { break; } + } + + Ok(XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + }) + } +} + +#[cfg(test)] +mod tests { + use {RngCore, SeedableRng}; + use super::XorShiftRng; + + #[test] + fn test_xorshift_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = XorShiftRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 4325440999699518727); + + let _rng2 = XorShiftRng::from_rng(rng1).unwrap(); + // Note: we cannot test the state of _rng2 because from_rng does not + // fix Endianness. This is allowed in the trait specification. + } + + #[test] + fn test_xorshift_true_values() { + let seed = [16,15,14,13, 12,11,10,9, 8,7,6,5, 4,3,2,1]; + let mut rng = XorShiftRng::from_seed(seed); + + let mut results = [0u32; 9]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 9] = [ + 2081028795, 620940381, 269070770, 16943764, 854422573, 29242889, + 1550291885, 1227154591, 271695242]; + assert_eq!(results, expected); + + let mut results = [0u64; 9]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 9] = [ + 9247529084182843387, 8321512596129439293, 14104136531997710878, + 6848554330849612046, 343577296533772213, 17828467390962600268, + 9847333257685787782, 7717352744383350108, 1133407547287910111]; + assert_eq!(results, expected); + + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [102, 57, 212, 16, 233, 130, 49, 183, + 158, 187, 44, 203, 63, 149, 45, 17, + 117, 129, 131, 160, 70, 121, 158, 155, + 224, 209, 192, 53, 10, 62, 57, 72]; + assert_eq!(results, expected); + } + + #[test] + fn test_xorshift_zero_seed() { + // Xorshift does not work with an all zero seed. + // Assert it does not panic. + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = XorShiftRng::from_seed(seed); + let a = rng.next_u64(); + let b = rng.next_u64(); + assert!(a != 0); + assert!(b != a); + } + + #[test] + fn test_xorshift_clone() { + let seed = [1,2,3,4, 5,5,7,8, 8,7,6,5, 4,3,2,1]; + let mut rng1 = XorShiftRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } + } + + #[cfg(all(feature="serde1", feature="std"))] + #[test] + fn test_xorshift_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng = XorShiftRng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: XorShiftRng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + assert_eq!(rng.x, deserialized.x); + assert_eq!(rng.y, deserialized.y); + assert_eq!(rng.z, deserialized.z); + assert_eq!(rng.w, deserialized.w); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } + } +} diff --git a/rand-0.5.6/src/rngs/adapter/mod.rs b/rand-0.5.6/src/rngs/adapter/mod.rs new file mode 100644 index 000000000..9a3851ae7 --- /dev/null +++ b/rand-0.5.6/src/rngs/adapter/mod.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Wrappers / adapters forming RNGs + +#[cfg(feature="std")] #[doc(hidden)] pub mod read; +mod reseeding; + +#[cfg(feature="std")] pub use self::read::ReadRng; +pub use self::reseeding::ReseedingRng; diff --git a/rand-0.5.6/src/rngs/adapter/read.rs b/rand-0.5.6/src/rngs/adapter/read.rs new file mode 100644 index 000000000..de75f978c --- /dev/null +++ b/rand-0.5.6/src/rngs/adapter/read.rs @@ -0,0 +1,137 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around any Read to treat it as an RNG. + +use std::io::Read; + +use rand_core::{RngCore, Error, ErrorKind, impls}; + + +/// An RNG that reads random bytes straight from any type supporting +/// `std::io::Read`, for example files. +/// +/// This will work best with an infinite reader, but that is not required. +/// +/// This can be used with `/dev/urandom` on Unix but it is recommended to use +/// [`OsRng`] instead. +/// +/// # Panics +/// +/// `ReadRng` uses `std::io::read_exact`, which retries on interrupts. All other +/// errors from the underlying reader, including when it does not have enough +/// data, will only be reported through [`try_fill_bytes`]. The other +/// [`RngCore`] methods will panic in case of an error. +/// +/// # Example +/// +/// ``` +/// use rand::{read, Rng}; +/// +/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; +/// let mut rng = read::ReadRng::new(&data[..]); +/// println!("{:x}", rng.gen::<u32>()); +/// ``` +/// +/// [`OsRng`]: ../struct.OsRng.html +/// [`RngCore`]: ../../trait.RngCore.html +/// [`try_fill_bytes`]: ../../trait.RngCore.html#method.tymethod.try_fill_bytes +#[derive(Debug)] +pub struct ReadRng<R> { + reader: R +} + +impl<R: Read> ReadRng<R> { + /// Create a new `ReadRng` from a `Read`. + pub fn new(r: R) -> ReadRng<R> { + ReadRng { + reader: r + } + } +} + +impl<R: Read> RngCore for ReadRng<R> { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("reading random bytes from Read implementation failed; error: {}", err)); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + if dest.len() == 0 { return Ok(()); } + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + self.reader.read_exact(dest).map_err(|err| { + match err.kind() { + ::std::io::ErrorKind::UnexpectedEof => Error::with_cause( + ErrorKind::Unavailable, + "not enough bytes available, reached end of source", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error reading from Read source", err) + } + }) + } +} + +#[cfg(test)] +mod test { + use super::ReadRng; + use {RngCore, ErrorKind}; + + #[test] + fn test_reader_rng_u64() { + // transmute from the target to avoid endianness concerns. + let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u64(), 1_u64.to_be()); + assert_eq!(rng.next_u64(), 2_u64.to_be()); + assert_eq!(rng.next_u64(), 3_u64.to_be()); + } + + #[test] + fn test_reader_rng_u32() { + let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u32(), 1_u32.to_be()); + assert_eq!(rng.next_u32(), 2_u32.to_be()); + assert_eq!(rng.next_u32(), 3_u32.to_be()); + } + + #[test] + fn test_reader_rng_fill_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 8]; + + let mut rng = ReadRng::new(&v[..]); + rng.fill_bytes(&mut w); + + assert!(v == w); + } + + #[test] + fn test_reader_rng_insufficient_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 9]; + + let mut rng = ReadRng::new(&v[..]); + + assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable); + } +} diff --git a/rand-0.5.6/src/rngs/adapter/reseeding.rs b/rand-0.5.6/src/rngs/adapter/reseeding.rs new file mode 100644 index 000000000..7ec8de516 --- /dev/null +++ b/rand-0.5.6/src/rngs/adapter/reseeding.rs @@ -0,0 +1,260 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around another PRNG that reseeds it after it +//! generates a certain number of random bytes. + +use core::mem::size_of; + +use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind}; +use rand_core::block::{BlockRngCore, BlockRng}; + +/// A wrapper around any PRNG which reseeds the underlying PRNG after it has +/// generated a certain number of random bytes. +/// +/// When the RNG gets cloned, the clone is reseeded on first use. +/// +/// Reseeding is never strictly *necessary*. Cryptographic PRNGs don't have a +/// limited number of bytes they can output, or at least not a limit reachable +/// in any practical way. There is no such thing as 'running out of entropy'. +/// +/// Some small non-cryptographic PRNGs can have very small periods, for +/// example less than 2<sup>64</sup>. Would reseeding help to ensure that you do +/// not wrap around at the end of the period? A period of 2<sup>64</sup> still +/// takes several centuries of CPU-years on current hardware. Reseeding will +/// actually make things worse, because the reseeded PRNG will just continue +/// somewhere else *in the same period*, with a high chance of overlapping with +/// previously used parts of it. +/// +/// # When should you use `ReseedingRng`? +/// +/// - Reseeding can be seen as some form of 'security in depth'. Even if in the +/// future a cryptographic weakness is found in the CSPRNG being used, +/// occasionally reseeding should make exploiting it much more difficult or +/// even impossible. +/// - It can be used as a poor man's cryptography (not recommended, just use a +/// good CSPRNG). Previous implementations of `thread_rng` for example used +/// `ReseedingRng` with the ISAAC RNG. That algorithm, although apparently +/// strong and with no known attack, does not come with any proof of security +/// and does not meet the current standards for a cryptographically secure +/// PRNG. By reseeding it frequently (every 32 kiB) it seems safe to assume +/// there is no attack that can operate on the tiny window between reseeds. +/// +/// # Error handling +/// +/// Although extremely unlikely, reseeding the wrapped PRNG can fail. +/// `ReseedingRng` will never panic but try to handle the error intelligently +/// through some combination of retrying and delaying reseeding until later. +/// If handling the source error fails `ReseedingRng` will continue generating +/// data from the wrapped PRNG without reseeding. +#[derive(Debug)] +pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>) +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore; + +impl<R, Rsdr> ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingRng` with the given parameters. + /// + /// # Arguments + /// + /// * `rng`: the random number generator to use. + /// * `threshold`: the number of generated bytes after which to reseed the RNG. + /// * `reseeder`: the RNG to use for reseeding. + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder))) + } + + /// Reseed the internal PRNG. + pub fn reseed(&mut self) -> Result<(), Error> { + self.0.core.reseed() + } +} + +// TODO: this should be implemented for any type where the inner type +// implements RngCore, but we can't specify that because ReseedingCore is private +impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr> +where R: BlockRngCore<Item = u32> + SeedableRng, + <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingRng<R, Rsdr> { + // Recreating `BlockRng` seems easier than cloning it and resetting + // the index. + ReseedingRng(BlockRng::new(self.0.core.clone())) + } +} + +impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + +#[derive(Debug)] +struct ReseedingCore<R, Rsdr> { + inner: R, + reseeder: Rsdr, + threshold: i64, + bytes_until_reseed: i64, +} + +impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + type Item = <R as BlockRngCore>::Item; + type Results = <R as BlockRngCore>::Results; + + fn generate(&mut self, results: &mut Self::Results) { + if self.bytes_until_reseed <= 0 { + // We get better performance by not calling only `auto_reseed` here + // and continuing with the rest of the function, but by directly + // returning from a non-inlined function. + return self.reseed_and_generate(results); + } + let num_bytes = results.as_ref().len() * size_of::<Self::Item>(); + self.bytes_until_reseed -= num_bytes as i64; + self.inner.generate(results); + } +} + +impl<R, Rsdr> ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingCore` with the given parameters. + /// + /// # Arguments + /// + /// * `rng`: the random number generator to use. + /// * `threshold`: the number of generated bytes after which to reseed the RNG. + /// * `reseeder`: the RNG to use for reseeding. + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + assert!(threshold <= ::core::i64::MAX as u64); + ReseedingCore { + inner: rng, + reseeder, + threshold: threshold as i64, + bytes_until_reseed: threshold as i64, + } + } + + /// Reseed the internal PRNG. + fn reseed(&mut self) -> Result<(), Error> { + R::from_rng(&mut self.reseeder).map(|result| { + self.bytes_until_reseed = self.threshold; + self.inner = result + }) + } + + #[inline(never)] + fn reseed_and_generate(&mut self, + results: &mut <Self as BlockRngCore>::Results) + { + trace!("Reseeding RNG after {} generated bytes", + self.threshold - self.bytes_until_reseed); + let threshold = if let Err(e) = self.reseed() { + let delay = match e.kind { + ErrorKind::Transient => 0, + kind @ _ if kind.should_retry() => self.threshold >> 8, + _ => self.threshold, + }; + warn!("Reseeding RNG delayed reseeding by {} bytes due to \ + error from source: {}", delay, e); + delay + } else { + self.threshold + }; + + let num_bytes = results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>(); + self.bytes_until_reseed = threshold - num_bytes as i64; + self.inner.generate(results); + } +} + +impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingCore<R, Rsdr> { + ReseedingCore { + inner: self.inner.clone(), + reseeder: self.reseeder.clone(), + threshold: self.threshold, + bytes_until_reseed: 0, // reseed clone on first use + } + } +} + +impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + +#[cfg(test)] +mod test { + use {Rng, SeedableRng}; + use prng::chacha::ChaChaCore; + use rngs::mock::StepRng; + use super::ReseedingRng; + + #[test] + fn test_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut reseeding = ReseedingRng::new(rng, 32*4, zero); + + // Currently we only support for arrays up to length 32. + // TODO: cannot generate seq via Rng::gen because it uses different alg + let mut buf = [0u32; 32]; // Needs to be a multiple of the RNGs result + // size to test exactly. + reseeding.fill(&mut buf); + let seq = buf; + for _ in 0..10 { + reseeding.fill(&mut buf); + assert_eq!(buf, seq); + } + } + + #[test] + fn test_clone_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut rng1 = ReseedingRng::new(rng, 32*4, zero); + + let first: u32 = rng1.gen(); + for _ in 0..10 { let _ = rng1.gen::<u32>(); } + + let mut rng2 = rng1.clone(); + assert_eq!(first, rng2.gen::<u32>()); + } +} diff --git a/rand-0.5.6/src/rngs/entropy.rs b/rand-0.5.6/src/rngs/entropy.rs new file mode 100644 index 000000000..b8f4be799 --- /dev/null +++ b/rand-0.5.6/src/rngs/entropy.rs @@ -0,0 +1,296 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Entropy generator, or wrapper around external generators + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls}; +#[allow(unused)] +use rngs; + +/// An interface returning random data from external source(s), provided +/// specifically for securely seeding algorithmic generators (PRNGs). +/// +/// Where possible, `EntropyRng` retrieves random data from the operating +/// system's interface for random numbers ([`OsRng`]); if that fails it will +/// fall back to the [`JitterRng`] entropy collector. In the latter case it will +/// still try to use [`OsRng`] on the next usage. +/// +/// If no secure source of entropy is available `EntropyRng` will panic on use; +/// i.e. it should never output predictable data. +/// +/// This is either a little slow ([`OsRng`] requires a system call) or extremely +/// slow ([`JitterRng`] must use significant CPU time to generate sufficient +/// jitter); for better performance it is common to seed a local PRNG from +/// external entropy then primarily use the local PRNG ([`thread_rng`] is +/// provided as a convenient, local, automatically-seeded CSPRNG). +/// +/// # Panics +/// +/// On most systems, like Windows, Linux, macOS and *BSD on common hardware, it +/// is highly unlikely for both [`OsRng`] and [`JitterRng`] to fail. But on +/// combinations like webassembly without Emscripten or stdweb both sources are +/// unavailable. If both sources fail, only [`try_fill_bytes`] is able to +/// report the error, and only the one from `OsRng`. The other [`RngCore`] +/// methods will panic in case of an error. +/// +/// [`OsRng`]: struct.OsRng.html +/// [`JitterRng`]: jitter/struct.JitterRng.html +/// [`thread_rng`]: ../fn.thread_rng.html +/// [`RngCore`]: ../trait.RngCore.html +/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes +#[derive(Debug)] +pub struct EntropyRng { + source: Source, +} + +#[derive(Debug)] +enum Source { + Os(Os), + Custom(Custom), + Jitter(Jitter), + None, +} + +impl EntropyRng { + /// Create a new `EntropyRng`. + /// + /// This method will do no system calls or other initialization routines, + /// those are done on first use. This is done to make `new` infallible, + /// and `try_fill_bytes` the only place to report errors. + pub fn new() -> Self { + EntropyRng { source: Source::None } + } +} + +impl Default for EntropyRng { + fn default() -> Self { + EntropyRng::new() + } +} + +impl RngCore for EntropyRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("all entropy sources failed; first error: {}", err)) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mut reported_error = None; + + if let Source::Os(ref mut os_rng) = self.source { + match os_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: OsRng failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Os::is_supported() { + match Os::new_and_fill(dest) { + Ok(os_rng) => { + debug!("EntropyRng: using OsRng"); + self.source = Source::Os(os_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Custom(ref mut rng) = self.source { + match rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: custom entropy source failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Custom::is_supported() { + match Custom::new_and_fill(dest) { + Ok(custom) => { + debug!("EntropyRng: using custom entropy source"); + self.source = Source::Custom(custom); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Jitter(ref mut jitter_rng) = self.source { + match jitter_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: JitterRng failed: {}", err); + reported_error = Some(err); + }, + } + } else if Jitter::is_supported() { + match Jitter::new_and_fill(dest) { + Ok(jitter_rng) => { + debug!("EntropyRng: using JitterRng"); + self.source = Source::Jitter(jitter_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Some(err) = reported_error { + Err(Error::with_cause(ErrorKind::Unavailable, + "All entropy sources failed", + err)) + } else { + Err(Error::new(ErrorKind::Unavailable, + "No entropy sources available")) + } + } +} + +impl CryptoRng for EntropyRng {} + + + +trait EntropySource { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> + where Self: Sized; + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + fn is_supported() -> bool { true } +} + +#[allow(unused)] +#[derive(Clone, Debug)] +struct NoSource; + +#[allow(unused)] +impl EntropySource for NoSource { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + Err(Error::new(ErrorKind::Unavailable, "Source not supported")) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unreachable!() + } + + fn is_supported() -> bool { false } +} + + +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +#[derive(Clone, Debug)] +pub struct Os(rngs::OsRng); + +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +impl EntropySource for Os { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + let mut rng = rngs::OsRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Os(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(not(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +))))] +type Os = NoSource; + + +type Custom = NoSource; + + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Clone, Debug)] +pub struct Jitter(rngs::JitterRng); + +#[cfg(not(target_arch = "wasm32"))] +impl EntropySource for Jitter { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + let mut rng = rngs::JitterRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Jitter(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(target_arch = "wasm32")] +type Jitter = NoSource; + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_entropy() { + let mut rng = EntropyRng::new(); + let n = (rng.next_u32() ^ rng.next_u32()).count_ones(); + assert!(n >= 2); // p(failure) approx 1e-7 + } +} diff --git a/rand-0.5.6/src/rngs/jitter.rs b/rand-0.5.6/src/rngs/jitter.rs new file mode 100644 index 000000000..311682c4b --- /dev/null +++ b/rand-0.5.6/src/rngs/jitter.rs @@ -0,0 +1,887 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Based on jitterentropy-library, http://www.chronox.de/jent.html. +// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017. +// +// With permission from Stephan Mueller to relicense the Rust translation under +// the MIT license. + +//! Non-physical true random number generator based on timing jitter. + +// Note: the C implementation of `Jitterentropy` relies on being compiled +// without optimizations. This implementation goes through lengths to make the +// compiler not optimize out code which does influence timing jitter, but is +// technically dead code. + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls}; + +use core::{fmt, mem, ptr}; +#[cfg(all(feature="std", not(target_arch = "wasm32")))] +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +const MEMORY_BLOCKS: usize = 64; +const MEMORY_BLOCKSIZE: usize = 32; +const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE; + +/// A true random number generator based on jitter in the CPU execution time, +/// and jitter in memory access time. +/// +/// This is a true random number generator, as opposed to pseudo-random +/// generators. Random numbers generated by `JitterRng` can be seen as fresh +/// entropy. A consequence is that is orders of magnitude slower than [`OsRng`] +/// and PRNGs (about 10<sup>3</sup>..10<sup>6</sup> slower). +/// +/// There are very few situations where using this RNG is appropriate. Only very +/// few applications require true entropy. A normal PRNG can be statistically +/// indistinguishable, and a cryptographic PRNG should also be as impossible to +/// predict. +/// +/// Use of `JitterRng` is recommended for initializing cryptographic PRNGs when +/// [`OsRng`] is not available. +/// +/// `JitterRng` can be used without the standard library, but not conveniently, +/// you must provide a high-precision timer and carefully have to follow the +/// instructions of [`new_with_timer`]. +/// +/// This implementation is based on +/// [Jitterentropy](http://www.chronox.de/jent.html) version 2.1.0. +/// +/// Note: There is no accurate timer available on Wasm platforms, to help +/// prevent fingerprinting or timing side-channel attacks. Therefore +/// [`JitterRng::new()`] is not available on Wasm. +/// +/// # Quality testing +/// +/// [`JitterRng::new()`] has build-in, but limited, quality testing, however +/// before using `JitterRng` on untested hardware, or after changes that could +/// effect how the code is optimized (such as a new LLVM version), it is +/// recommend to run the much more stringent +/// [NIST SP 800-90B Entropy Estimation Suite]( +/// https://github.com/usnistgov/SP800-90B_EntropyAssessment). +/// +/// Use the following code using [`timer_stats`] to collect the data: +/// +/// ```no_run +/// use rand::jitter::JitterRng; +/// # +/// # use std::error::Error; +/// # use std::fs::File; +/// # use std::io::Write; +/// # +/// # fn try_main() -> Result<(), Box<Error>> { +/// let mut rng = JitterRng::new()?; +/// +/// // 1_000_000 results are required for the +/// // NIST SP 800-90B Entropy Estimation Suite +/// const ROUNDS: usize = 1_000_000; +/// let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS); +/// let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS); +/// +/// for _ in 0..ROUNDS { +/// deltas_variable.push(rng.timer_stats(true) as u8); +/// deltas_minimal.push(rng.timer_stats(false) as u8); +/// } +/// +/// // Write out after the statistics collection loop, to not disturb the +/// // test results. +/// File::create("jitter_rng_var.bin")?.write(&deltas_variable)?; +/// File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?; +/// # +/// # Ok(()) +/// # } +/// # +/// # fn main() { +/// # try_main().unwrap(); +/// # } +/// ``` +/// +/// This will produce two files: `jitter_rng_var.bin` and `jitter_rng_min.bin`. +/// Run the Entropy Estimation Suite in three configurations, as outlined below. +/// Every run has two steps. One step to produce an estimation, another to +/// validate the estimation. +/// +/// 1. Estimate the expected amount of entropy that is at least available with +/// each round of the entropy collector. This number should be greater than +/// the amount estimated with `64 / test_timer()`. +/// ```sh +/// python noniid_main.py -v jitter_rng_var.bin 8 +/// restart.py -v jitter_rng_var.bin 8 <min-entropy> +/// ``` +/// 2. Estimate the expected amount of entropy that is available in the last 4 +/// bits of the timer delta after running noice sources. Note that a value of +/// `3.70` is the minimum estimated entropy for true randomness. +/// ```sh +/// python noniid_main.py -v -u 4 jitter_rng_var.bin 4 +/// restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy> +/// ``` +/// 3. Estimate the expected amount of entropy that is available to the entropy +/// collector if both noice sources only run their minimal number of times. +/// This measures the absolute worst-case, and gives a lower bound for the +/// available entropy. +/// ```sh +/// python noniid_main.py -v -u 4 jitter_rng_min.bin 4 +/// restart.py -v -u 4 jitter_rng_min.bin 4 <min-entropy> +/// ``` +/// +/// [`OsRng`]: struct.OsRng.html +/// [`JitterRng::new()`]: struct.JitterRng.html#method.new +/// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer +/// [`timer_stats`]: struct.JitterRng.html#method.timer_stats +pub struct JitterRng { + data: u64, // Actual random number + // Number of rounds to run the entropy collector per 64 bits + rounds: u8, + // Timer used by `measure_jitter` + timer: fn() -> u64, + // Memory for the Memory Access noise source + mem_prev_index: u16, + // Make `next_u32` not waste 32 bits + data_half_used: bool, +} + +// Note: `JitterRng` maintains a small 64-bit entropy pool. With every +// `generate` 64 new bits should be integrated in the pool. If a round of +// `generate` were to collect less than the expected 64 bit, then the returned +// value, and the new state of the entropy pool, would be in some way related to +// the initial state. It is therefore better if the initial state of the entropy +// pool is different on each call to `generate`. This has a few implications: +// - `generate` should be called once before using `JitterRng` to produce the +// first usable value (this is done by default in `new`); +// - We do not zero the entropy pool after generating a result. The reference +// implementation also does not support zeroing, but recommends generating a +// new value without using it if you want to protect a previously generated +// 'secret' value from someone inspecting the memory; +// - Implementing `Clone` seems acceptable, as it would not cause the systematic +// bias a constant might cause. Only instead of one value that could be +// potentially related to the same initial state, there are now two. + +// Entropy collector state. +// These values are not necessary to preserve across runs. +struct EcState { + // Previous time stamp to determine the timer delta + prev_time: u64, + // Deltas used for the stuck test + last_delta: i32, + last_delta2: i32, + // Memory for the Memory Access noise source + mem: [u8; MEMORY_SIZE], +} + +impl EcState { + // Stuck test by checking the: + // - 1st derivation of the jitter measurement (time delta) + // - 2nd derivation of the jitter measurement (delta of time deltas) + // - 3rd derivation of the jitter measurement (delta of delta of time + // deltas) + // + // All values must always be non-zero. + // This test is a heuristic to see whether the last measurement holds + // entropy. + fn stuck(&mut self, current_delta: i32) -> bool { + let delta2 = self.last_delta - current_delta; + let delta3 = delta2 - self.last_delta2; + + self.last_delta = current_delta; + self.last_delta2 = delta2; + + current_delta == 0 || delta2 == 0 || delta3 == 0 + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for JitterRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "JitterRng {{}}") + } +} + +impl Clone for JitterRng { + fn clone(&self) -> JitterRng { + JitterRng { + data: self.data, + rounds: self.rounds, + timer: self.timer, + mem_prev_index: self.mem_prev_index, + // The 32 bits that may still be unused from the previous round are + // for the original to use, not for the clone. + data_half_used: false, + } + } +} + +/// An error that can occur when [`JitterRng::test_timer`] fails. +/// +/// [`JitterRng::test_timer`]: struct.JitterRng.html#method.test_timer +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TimerError { + /// No timer available. + NoTimer, + /// Timer too coarse to use as an entropy source. + CoarseTimer, + /// Timer is not monotonically increasing. + NotMonotonic, + /// Variations of deltas of time too small. + TinyVariantions, + /// Too many stuck results (indicating no added entropy). + TooManyStuck, + #[doc(hidden)] + __Nonexhaustive, +} + +impl TimerError { + fn description(&self) -> &'static str { + match *self { + TimerError::NoTimer => "no timer available", + TimerError::CoarseTimer => "coarse timer", + TimerError::NotMonotonic => "timer not monotonic", + TimerError::TinyVariantions => "time delta variations too small", + TimerError::TooManyStuck => "too many stuck results", + TimerError::__Nonexhaustive => unreachable!(), + } + } +} + +impl fmt::Display for TimerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +#[cfg(feature="std")] +impl ::std::error::Error for TimerError { + fn description(&self) -> &str { + self.description() + } +} + +impl From<TimerError> for Error { + fn from(err: TimerError) -> Error { + // Timer check is already quite permissive of failures so we don't + // expect false-positive failures, i.e. any error is irrecoverable. + Error::with_cause(ErrorKind::Unavailable, + "timer jitter failed basic quality tests", err) + } +} + +// Initialise to zero; must be positive +#[cfg(all(feature="std", not(target_arch = "wasm32")))] +static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT; + +impl JitterRng { + /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a + /// platform-specific function with higher accuracy if necessary and + /// available. + /// + /// During initialization CPU execution timing jitter is measured a few + /// hundred times. If this does not pass basic quality tests, an error is + /// returned. The test result is cached to make subsequent calls faster. + #[cfg(all(feature="std", not(target_arch = "wasm32")))] + pub fn new() -> Result<JitterRng, TimerError> { + let mut state = JitterRng::new_with_timer(platform::get_nstime); + let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8; + if rounds == 0 { + // No result yet: run test. + // This allows the timer test to run multiple times; we don't care. + rounds = state.test_timer()?; + JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed); + info!("JitterRng: using {} rounds per u64 output", rounds); + } + state.set_rounds(rounds); + + // Fill `data` with a non-zero value. + state.gen_entropy(); + Ok(state) + } + + /// Create a new `JitterRng`. + /// A custom timer can be supplied, making it possible to use `JitterRng` in + /// `no_std` environments. + /// + /// The timer must have nanosecond precision. + /// + /// This method is more low-level than `new()`. It is the responsibility of + /// the caller to run [`test_timer`] before using any numbers generated with + /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to + /// consume at least one `u64` before using the first result to initialize + /// the entropy collection pool. + /// + /// # Example + /// + /// ``` + /// # use rand::{Rng, Error}; + /// use rand::jitter::JitterRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// fn get_nstime() -> u64 { + /// use std::time::{SystemTime, UNIX_EPOCH}; + /// + /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + /// // The correct way to calculate the current time is + /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + /// // But this is faster, and the difference in terms of entropy is + /// // negligible (log2(10^9) == 29.9). + /// dur.as_secs() << 30 | dur.subsec_nanos() as u64 + /// } + /// + /// let mut rng = JitterRng::new_with_timer(get_nstime); + /// let rounds = rng.test_timer()?; + /// rng.set_rounds(rounds); // optional + /// let _ = rng.gen::<u64>(); + /// + /// // Ready for use + /// let v: u64 = rng.gen(); + /// # Ok(()) + /// # } + /// + /// # let _ = try_inner(); + /// ``` + /// + /// [`test_timer`]: struct.JitterRng.html#method.test_timer + /// [`set_rounds`]: struct.JitterRng.html#method.set_rounds + pub fn new_with_timer(timer: fn() -> u64) -> JitterRng { + JitterRng { + data: 0, + rounds: 64, + timer, + mem_prev_index: 0, + data_half_used: false, + } + } + + /// Configures how many rounds are used to generate each 64-bit value. + /// This must be greater than zero, and has a big impact on performance + /// and output quality. + /// + /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds + /// can be used. The `test_timer()` function returns the minimum number of + /// rounds required for full strength (platform dependent), so one may use + /// `rng.set_rounds(rng.test_timer()?);` or cache the value. + /// + /// [`new_with_timer`]: struct.JitterRng.html#method.new_with_timer + pub fn set_rounds(&mut self, rounds: u8) { + assert!(rounds > 0); + self.rounds = rounds; + } + + // Calculate a random loop count used for the next round of an entropy + // collection, based on bits from a fresh value from the timer. + // + // The timer is folded to produce a number that contains at most `n_bits` + // bits. + // + // Note: A constant should be added to the resulting random loop count to + // prevent loops that run 0 times. + #[inline(never)] + fn random_loop_cnt(&mut self, n_bits: u32) -> u32 { + let mut rounds = 0; + + let mut time = (self.timer)(); + // Mix with the current state of the random number balance the random + // loop counter a bit more. + time ^= self.data; + + // We fold the time value as much as possible to ensure that as many + // bits of the time stamp are included as possible. + let folds = (64 + n_bits - 1) / n_bits; + let mask = (1 << n_bits) - 1; + for _ in 0..folds { + rounds ^= time & mask; + time >>= n_bits; + } + + rounds as u32 + } + + // CPU jitter noise source + // Noise source based on the CPU execution time jitter + // + // This function injects the individual bits of the time value into the + // entropy pool using an LFSR. + // + // The code is deliberately inefficient with respect to the bit shifting. + // This function not only acts as folding operation, but this function's + // execution is used to measure the CPU execution time jitter. Any change to + // the loop in this function implies that careful retesting must be done. + #[inline(never)] + fn lfsr_time(&mut self, time: u64, var_rounds: bool) { + fn lfsr(mut data: u64, time: u64) -> u64{ + for i in 1..65 { + let mut tmp = time << (64 - i); + tmp >>= 64 - 1; + + // Fibonacci LSFR with polynomial of + // x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is + // primitive according to + // http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf + // (the shift values are the polynomial values minus one + // due to counting bits from 0 to 63). As the current + // position is always the LSB, the polynomial only needs + // to shift data in from the left without wrap. + data ^= tmp; + data ^= (data >> 63) & 1; + data ^= (data >> 60) & 1; + data ^= (data >> 55) & 1; + data ^= (data >> 30) & 1; + data ^= (data >> 27) & 1; + data ^= (data >> 22) & 1; + data = data.rotate_left(1); + } + data + } + + // Note: in the reference implementation only the last round effects + // `self.data`, all the other results are ignored. To make sure the + // other rounds are not optimised out, we first run all but the last + // round on a throw-away value instead of the real `self.data`. + let mut lfsr_loop_cnt = 0; + if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) }; + + let mut throw_away: u64 = 0; + for _ in 0..lfsr_loop_cnt { + throw_away = lfsr(throw_away, time); + } + black_box(throw_away); + + self.data = lfsr(self.data, time); + } + + // Memory Access noise source + // This is a noise source based on variations in memory access times + // + // This function performs memory accesses which will add to the timing + // variations due to an unknown amount of CPU wait states that need to be + // added when accessing memory. The memory size should be larger than the L1 + // caches as outlined in the documentation and the associated testing. + // + // The L1 cache has a very high bandwidth, albeit its access rate is usually + // slower than accessing CPU registers. Therefore, L1 accesses only add + // minimal variations as the CPU has hardly to wait. Starting with L2, + // significant variations are added because L2 typically does not belong to + // the CPU any more and therefore a wider range of CPU wait states is + // necessary for accesses. L3 and real memory accesses have even a wider + // range of wait states. However, to reliably access either L3 or memory, + // the `self.mem` memory must be quite large which is usually not desirable. + #[inline(never)] + fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) { + let mut acc_loop_cnt = 128; + if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) }; + + let mut index = self.mem_prev_index as usize; + for _ in 0..acc_loop_cnt { + // Addition of memblocksize - 1 to index with wrap around logic to + // ensure that every memory location is hit evenly. + // The modulus also allows the compiler to remove the indexing + // bounds check. + index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE; + + // memory access: just add 1 to one byte + // memory access implies read from and write to memory location + mem[index] = mem[index].wrapping_add(1); + } + self.mem_prev_index = index as u16; + } + + // This is the heart of the entropy generation: calculate time deltas and + // use the CPU jitter in the time deltas. The jitter is injected into the + // entropy pool. + // + // Ensure that `ec.prev_time` is primed before using the output of this + // function. This can be done by calling this function and not using its + // result. + fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> { + // Invoke one noise source before time measurement to add variations + self.memaccess(&mut ec.mem, true); + + // Get time stamp and calculate time delta to previous + // invocation to measure the timing variations + let time = (self.timer)(); + // Note: wrapping_sub combined with a cast to `i64` generates a correct + // delta, even in the unlikely case this is a timer that is not strictly + // monotonic. + let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32; + ec.prev_time = time; + + // Call the next noise source which also injects the data + self.lfsr_time(current_delta as u64, true); + + // Check whether we have a stuck measurement (i.e. does the last + // measurement holds entropy?). + if ec.stuck(current_delta) { return None }; + + // Rotate the data buffer by a prime number (any odd number would + // do) to ensure that every bit position of the input time stamp + // has an even chance of being merged with a bit position in the + // entropy pool. We do not use one here as the adjacent bits in + // successive time deltas may have some form of dependency. The + // chosen value of 7 implies that the low 7 bits of the next + // time delta value is concatenated with the current time delta. + self.data = self.data.rotate_left(7); + + Some(()) + } + + // Shuffle the pool a bit by mixing some value with a bijective function + // (XOR) into the pool. + // + // The function generates a mixer value that depends on the bits set and + // the location of the set bits in the random number generated by the + // entropy source. Therefore, based on the generated random number, this + // mixer value can have 2^64 different values. That mixer value is + // initialized with the first two SHA-1 constants. After obtaining the + // mixer value, it is XORed into the random number. + // + // The mixer value is not assumed to contain any entropy. But due to the + // XOR operation, it can also not destroy any entropy present in the + // entropy pool. + #[inline(never)] + fn stir_pool(&mut self) { + // This constant is derived from the first two 32 bit initialization + // vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 + // The order does not really matter as we do not rely on the specific + // numbers. We just pick the SHA-1 constants as they have a good mix of + // bit set and unset. + const CONSTANT: u64 = 0x67452301efcdab89; + + // The start value of the mixer variable is derived from the third + // and fourth 32 bit initialization vector of SHA-1 as defined in + // FIPS 180-4 section 5.3.1 + let mut mixer = 0x98badcfe10325476; + + // This is a constant time function to prevent leaking timing + // information about the random number. + // The normal code is: + // ``` + // for i in 0..64 { + // if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; } + // } + // ``` + // This is a bit fragile, as LLVM really wants to use branches here, and + // we rely on it to not recognise the opportunity. + for i in 0..64 { + let apply = (self.data >> i) & 1; + let mask = !apply.wrapping_sub(1); + mixer ^= CONSTANT & mask; + mixer = mixer.rotate_left(1); + } + + self.data ^= mixer; + } + + fn gen_entropy(&mut self) -> u64 { + trace!("JitterRng: collecting entropy"); + + // Prime `ec.prev_time`, and run the noice sources to make sure the + // first loop round collects the expected entropy. + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + let _ = self.measure_jitter(&mut ec); + + for _ in 0..self.rounds { + // If a stuck measurement is received, repeat measurement + // Note: we do not guard against an infinite loop, that would mean + // the timer suddenly became broken. + while self.measure_jitter(&mut ec).is_none() {} + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + self.stir_pool(); + self.data + } + + /// Basic quality tests on the timer, by measuring CPU timing jitter a few + /// hundred times. + /// + /// If succesful, this will return the estimated number of rounds necessary + /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause + /// of the failure will be returned. + /// + /// [`TimerError`]: enum.TimerError.html + pub fn test_timer(&mut self) -> Result<u8, TimerError> { + debug!("JitterRng: testing timer ..."); + // We could add a check for system capabilities such as `clock_getres` + // or check for `CONFIG_X86_TSC`, but it does not make much sense as the + // following sanity checks verify that we have a high-resolution timer. + + let mut delta_sum = 0; + let mut old_delta = 0; + + let mut time_backwards = 0; + let mut count_mod = 0; + let mut count_stuck = 0; + + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + + // TESTLOOPCOUNT needs some loops to identify edge systems. + // 100 is definitely too little. + const TESTLOOPCOUNT: u64 = 300; + const CLEARCACHE: u64 = 100; + + for i in 0..(CLEARCACHE + TESTLOOPCOUNT) { + // Measure time delta of core entropy collection logic + let time = (self.timer)(); + self.memaccess(&mut ec.mem, true); + self.lfsr_time(time, true); + let time2 = (self.timer)(); + + // Test whether timer works + if time == 0 || time2 == 0 { + return Err(TimerError::NoTimer); + } + let delta = time2.wrapping_sub(time) as i64 as i32; + + // Test whether timer is fine grained enough to provide delta even + // when called shortly after each other -- this implies that we also + // have a high resolution timer + if delta == 0 { + return Err(TimerError::CoarseTimer); + } + + // Up to here we did not modify any variable that will be + // evaluated later, but we already performed some work. Thus we + // already have had an impact on the caches, branch prediction, + // etc. with the goal to clear it to get the worst case + // measurements. + if i < CLEARCACHE { continue; } + + if ec.stuck(delta) { count_stuck += 1; } + + // Test whether we have an increasing timer. + if !(time2 > time) { time_backwards += 1; } + + // Count the number of times the counter increases in steps of 100ns + // or greater. + if (delta % 100) == 0 { count_mod += 1; } + + // Ensure that we have a varying delta timer which is necessary for + // the calculation of entropy -- perform this check only after the + // first loop is executed as we need to prime the old_delta value + delta_sum += (delta - old_delta).abs() as u64; + old_delta = delta; + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + // We allow the time to run backwards for up to three times. + // This can happen if the clock is being adjusted by NTP operations. + // If such an operation just happens to interfere with our test, it + // should not fail. The value of 3 should cover the NTP case being + // performed during our test run. + if time_backwards > 3 { + return Err(TimerError::NotMonotonic); + } + + // Test that the available amount of entropy per round does not get to + // low. We expect 1 bit of entropy per round as a reasonable minimum + // (although less is possible, it means the collector loop has to run + // much more often). + // `assert!(delta_average >= log2(1))` + // `assert!(delta_sum / TESTLOOPCOUNT >= 1)` + // `assert!(delta_sum >= TESTLOOPCOUNT)` + if delta_sum < TESTLOOPCOUNT { + return Err(TimerError::TinyVariantions); + } + + // Ensure that we have variations in the time stamp below 100 for at + // least 10% of all checks -- on some platforms, the counter increments + // in multiples of 100, but not always + if count_mod > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::CoarseTimer); + } + + // If we have more than 90% stuck results, then this Jitter RNG is + // likely to not work well. + if count_stuck > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::TooManyStuck); + } + + // Estimate the number of `measure_jitter` rounds necessary for 64 bits + // of entropy. + // + // We don't try very hard to come up with a good estimate of the + // available bits of entropy per round here for two reasons: + // 1. Simple estimates of the available bits (like Shannon entropy) are + // too optimistic. + // 2. Unless we want to waste a lot of time during intialization, there + // only a small number of samples are available. + // + // Therefore we use a very simple and conservative estimate: + // `let bits_of_entropy = log2(delta_average) / 2`. + // + // The number of rounds `measure_jitter` should run to collect 64 bits + // of entropy is `64 / bits_of_entropy`. + let delta_average = delta_sum / TESTLOOPCOUNT; + + if delta_average >= 16 { + let log2 = 64 - delta_average.leading_zeros(); + // Do something similar to roundup(64/(log2/2)): + Ok( ((64u32 * 2 + log2 - 1) / log2) as u8) + } else { + // For values < 16 the rounding error becomes too large, use a + // lookup table. + // Values 0 and 1 are invalid, and filtered out by the + // `delta_sum < TESTLOOPCOUNT` test above. + let log2_lookup = [0, 0, 128, 81, 64, 56, 50, 46, + 43, 41, 39, 38, 36, 35, 34, 33]; + Ok(log2_lookup[delta_average as usize]) + } + } + + /// Statistical test: return the timer delta of one normal run of the + /// `JitterRng` entropy collector. + /// + /// Setting `var_rounds` to `true` will execute the memory access and the + /// CPU jitter noice sources a variable amount of times (just like a real + /// `JitterRng` round). + /// + /// Setting `var_rounds` to `false` will execute the noice sources the + /// minimal number of times. This can be used to measure the minimum amount + /// of entropy one round of the entropy collector can collect in the worst + /// case. + /// + /// See [Quality testing](struct.JitterRng.html#quality-testing) on how to + /// use `timer_stats` to test the quality of `JitterRng`. + pub fn timer_stats(&mut self, var_rounds: bool) -> i64 { + let mut mem = [0; MEMORY_SIZE]; + + let time = (self.timer)(); + self.memaccess(&mut mem, var_rounds); + self.lfsr_time(time, var_rounds); + let time2 = (self.timer)(); + time2.wrapping_sub(time) as i64 + } +} + +#[cfg(feature="std")] +mod platform { + #[cfg(not(any(target_os = "macos", target_os = "ios", + target_os = "windows", + target_arch = "wasm32")))] + pub fn get_nstime() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + // The correct way to calculate the current time is + // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + // But this is faster, and the difference in terms of entropy is + // negligible (log2(10^9) == 29.9). + dur.as_secs() << 30 | dur.subsec_nanos() as u64 + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub fn get_nstime() -> u64 { + extern crate libc; + // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution. + // We use `mach_absolute_time` instead. This provides a CPU dependent + // unit, to get real nanoseconds the result should by multiplied by + // numer/denom from `mach_timebase_info`. + // But we are not interested in the exact nanoseconds, just entropy. So + // we use the raw result. + unsafe { libc::mach_absolute_time() } + } + + #[cfg(target_os = "windows")] + pub fn get_nstime() -> u64 { + extern crate winapi; + unsafe { + let mut t = super::mem::zeroed(); + winapi::um::profileapi::QueryPerformanceCounter(&mut t); + *t.QuadPart() as u64 + } + } +} + +// A function that is opaque to the optimizer to assist in avoiding dead-code +// elimination. Taken from `bencher`. +fn black_box<T>(dummy: T) -> T { + unsafe { + let ret = ptr::read_volatile(&dummy); + mem::forget(dummy); + ret + } +} + +impl RngCore for JitterRng { + fn next_u32(&mut self) -> u32 { + // We want to use both parts of the generated entropy + if self.data_half_used { + self.data_half_used = false; + (self.data >> 32) as u32 + } else { + self.data = self.next_u64(); + self.data_half_used = true; + self.data as u32 + } + } + + fn next_u64(&mut self) -> u64 { + self.data_half_used = false; + self.gen_entropy() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + // Fill using `next_u32`. This is faster for filling small slices (four + // bytes or less), while the overhead is negligible. + // + // This is done especially for wrappers that implement `next_u32` + // themselves via `fill_bytes`. + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl CryptoRng for JitterRng {} + +#[cfg(test)] +mod test_jitter_init { + use jitter::JitterRng; + + #[cfg(all(feature="std", not(target_arch = "wasm32")))] + #[test] + fn test_jitter_init() { + use RngCore; + // Because this is a debug build, measurements here are not representive + // of the final release build. + // Don't fail this test if initializing `JitterRng` fails because of a + // bad timer (the timer from the standard library may not have enough + // accuracy on all platforms). + match JitterRng::new() { + Ok(ref mut rng) => { + // false positives are possible, but extremely unlikely + assert!(rng.next_u32() | rng.next_u32() != 0); + }, + Err(_) => {}, + } + } + + #[test] + fn test_jitter_bad_timer() { + fn bad_timer() -> u64 { 0 } + let mut rng = JitterRng::new_with_timer(bad_timer); + assert!(rng.test_timer().is_err()); + } +} diff --git a/rand-0.5.6/src/rngs/mock.rs b/rand-0.5.6/src/rngs/mock.rs new file mode 100644 index 000000000..812e4bebf --- /dev/null +++ b/rand-0.5.6/src/rngs/mock.rs @@ -0,0 +1,61 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Mock random number generator + +use rand_core::{RngCore, Error, impls}; + +/// A simple implementation of `RngCore` for testing purposes. +/// +/// This generates an arithmetic sequence (i.e. adds a constant each step) +/// over a `u64` number, using wrapping arithmetic. If the increment is 0 +/// the generator yields a constant. +/// +/// ``` +/// use rand::Rng; +/// use rand::rngs::mock::StepRng; +/// +/// let mut my_rng = StepRng::new(2, 1); +/// let sample: [u64; 3] = my_rng.gen(); +/// assert_eq!(sample, [2, 3, 4]); +/// ``` +#[derive(Debug, Clone)] +pub struct StepRng { + v: u64, + a: u64, +} + +impl StepRng { + /// Create a `StepRng`, yielding an arithmetic sequence starting with + /// `initial` and incremented by `increment` each time. + pub fn new(initial: u64, increment: u64) -> Self { + StepRng { v: initial, a: increment } + } +} + +impl RngCore for StepRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + let result = self.v; + self.v = self.v.wrapping_add(self.a); + result + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/rand-0.5.6/src/rngs/mod.rs b/rand-0.5.6/src/rngs/mod.rs new file mode 100644 index 000000000..acc207d0d --- /dev/null +++ b/rand-0.5.6/src/rngs/mod.rs @@ -0,0 +1,218 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generators and adapters for common usage: +//! +//! - [`ThreadRng`], a fast, secure, auto-seeded thread-local generator +//! - [`StdRng`] and [`SmallRng`], algorithms to cover typical usage +//! - [`EntropyRng`], [`OsRng`] and [`JitterRng`] as entropy sources +//! - [`mock::StepRng`] as a simple counter for tests +//! - [`adapter::ReadRng`] to read from a file/stream +//! +//! # Background — Random number generators (RNGs) +//! +//! Computers are inherently deterministic, so to get *random* numbers one +//! either has to use a hardware generator or collect bits of *entropy* from +//! various sources (e.g. event timestamps, or jitter). This is a relatively +//! slow and complicated operation. +//! +//! Generally the operating system will collect some entropy, remove bias, and +//! use that to seed its own PRNG; [`OsRng`] provides an interface to this. +//! [`JitterRng`] is an entropy collector included with Rand that measures +//! jitter in the CPU execution time, and jitter in memory access time. +//! [`EntropyRng`] is a wrapper that uses the best entropy source that is +//! available. +//! +//! ## Pseudo-random number generators +//! +//! What is commonly used instead of "true" random number renerators, are +//! *pseudo-random number generators* (PRNGs), deterministic algorithms that +//! produce an infinite stream of pseudo-random numbers from a small random +//! seed. PRNGs are faster, and have better provable properties. The numbers +//! produced can be statistically of very high quality and can be impossible to +//! predict. (They can also have obvious correlations and be trivial to predict; +//! quality varies.) +//! +//! There are two different types of PRNGs: those developed for simulations +//! and statistics, and those developed for use in cryptography; the latter are +//! called Cryptographically Secure PRNGs (CSPRNG or CPRNG). Both types can +//! have good statistical quality but the latter also have to be impossible to +//! predict, even after seeing many previous output values. Rand provides a good +//! default algorithm from each class: +//! +//! - [`SmallRng`] is a PRNG chosen for low memory usage, high performance and +//! good statistical quality. +//! The current algorithm (plain Xorshift) unfortunately performs +//! poorly in statistical quality test suites (TestU01 and PractRand) and will +//! be replaced in the next major release. +//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security +//! (based on reviews, maturity and usage). The current algorithm is HC-128, +//! which is one of the recommendations by ECRYPT's eSTREAM project. +//! +//! The above PRNGs do not cover all use-cases; more algorithms can be found in +//! the [`prng` module], as well as in several other crates. For example, you +//! may wish a CSPRNG with significantly lower memory usage than [`StdRng`] +//! while being less concerned about performance, in which case [`ChaChaRng`] +//! is a good choice. +//! +//! One complexity is that the internal state of a PRNG must change with every +//! generated number. For APIs this generally means a mutable reference to the +//! state of the PRNG has to be passed around. +//! +//! A solution is [`ThreadRng`]. This is a thread-local implementation of +//! [`StdRng`] with automatic seeding on first use. It is the best choice if you +//! "just" want a convenient, secure, fast random number source. Use via the +//! [`thread_rng`] function, which gets a reference to the current thread's +//! local instance. +//! +//! ## Seeding +//! +//! As mentioned above, PRNGs require a random seed in order to produce random +//! output. This is especially important for CSPRNGs, which are still +//! deterministic algorithms, thus can only be secure if their seed value is +//! also secure. To seed a PRNG, use one of: +//! +//! - [`FromEntropy::from_entropy`]; this is the most convenient way to seed +//! with fresh, secure random data. +//! - [`SeedableRng::from_rng`]; this allows seeding from another PRNG or +//! from an entropy source such as [`EntropyRng`]. +//! - [`SeedableRng::from_seed`]; this is mostly useful if you wish to be able +//! to reproduce the output sequence by using a fixed seed. (Don't use +//! [`StdRng`] or [`SmallRng`] in this case since different algorithms may be +//! used by future versions of Rand; use an algorithm from the +//! [`prng` module].) +//! +//! ## Conclusion +//! +//! - [`thread_rng`] is what you often want to use. +//! - If you want more control, flexibility, or better performance, use +//! [`StdRng`], [`SmallRng`] or an algorithm from the [`prng` module]. +//! - Use [`FromEntropy::from_entropy`] to seed new PRNGs. +//! - If you need reproducibility, use [`SeedableRng::from_seed`] combined with +//! a named PRNG. +//! +//! More information and notes on cryptographic security can be found +//! in the [`prng` module]. +//! +//! ## Examples +//! +//! Examples of seeding PRNGs: +//! +//! ``` +//! use rand::prelude::*; +//! # use rand::Error; +//! +//! // StdRng seeded securely by the OS or local entropy collector: +//! let mut rng = StdRng::from_entropy(); +//! # let v: u32 = rng.gen(); +//! +//! // SmallRng seeded from thread_rng: +//! # fn try_inner() -> Result<(), Error> { +//! let mut rng = SmallRng::from_rng(thread_rng())?; +//! # let v: u32 = rng.gen(); +//! # Ok(()) +//! # } +//! # try_inner().unwrap(); +//! +//! // SmallRng seeded by a constant, for deterministic results: +//! let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; // byte array +//! let mut rng = SmallRng::from_seed(seed); +//! # let v: u32 = rng.gen(); +//! ``` +//! +//! +//! # Implementing custom RNGs +//! +//! If you want to implement custom RNG, see the [`rand_core`] crate. The RNG +//! will have to implement the [`RngCore`] trait, where the [`Rng`] trait is +//! build on top of. +//! +//! If the RNG needs seeding, also implement the [`SeedableRng`] trait. +//! +//! [`CryptoRng`] is a marker trait cryptographically secure PRNGs can +//! implement. +//! +//! +// This module: +//! [`ThreadRng`]: struct.ThreadRng.html +//! [`StdRng`]: struct.StdRng.html +//! [`SmallRng`]: struct.SmallRng.html +//! [`EntropyRng`]: struct.EntropyRng.html +//! [`OsRng`]: struct.OsRng.html +//! [`JitterRng`]: struct.JitterRng.html +// Other traits and functions: +//! [`rand_core`]: https://crates.io/crates/rand_core +//! [`prng` module]: ../prng/index.html +//! [`CryptoRng`]: ../trait.CryptoRng.html +//! [`FromEntropy`]: ../trait.FromEntropy.html +//! [`FromEntropy::from_entropy`]: ../trait.FromEntropy.html#tymethod.from_entropy +//! [`RngCore`]: ../trait.RngCore.html +//! [`Rng`]: ../trait.Rng.html +//! [`SeedableRng`]: ../trait.SeedableRng.html +//! [`SeedableRng::from_rng`]: ../trait.SeedableRng.html#tymethod.from_rng +//! [`SeedableRng::from_seed`]: ../trait.SeedableRng.html#tymethod.from_seed +//! [`thread_rng`]: ../fn.thread_rng.html +//! [`mock::StepRng`]: mock/struct.StepRng.html +//! [`adapter::ReadRng`]: adapter/struct.ReadRng.html +//! [`ChaChaRng`]: ../prng/chacha/struct.ChaChaRng.html + +pub mod adapter; + +#[cfg(feature="std")] mod entropy; +#[doc(hidden)] pub mod jitter; +pub mod mock; // Public so we don't export `StepRng` directly, making it a bit + // more clear it is intended for testing. +mod small; +mod std; +#[cfg(feature="std")] pub(crate) mod thread; + + +pub use self::jitter::{JitterRng, TimerError}; +#[cfg(feature="std")] pub use self::entropy::EntropyRng; + +pub use self::small::SmallRng; +pub use self::std::StdRng; +#[cfg(feature="std")] pub use self::thread::ThreadRng; + +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +mod os; + +#[cfg(all(feature="std", + any(target_os = "linux", target_os = "android", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten", + target_os = "solaris", + target_os = "cloudabi", + target_os = "macos", target_os = "ios", + target_os = "freebsd", + target_os = "openbsd", target_os = "bitrig", + target_os = "redox", + target_os = "fuchsia", + windows, + all(target_arch = "wasm32", feature = "stdweb") +)))] +pub use self::os::OsRng; diff --git a/rand-0.5.6/src/rngs/os.rs b/rand-0.5.6/src/rngs/os.rs new file mode 100644 index 000000000..ecc5f3216 --- /dev/null +++ b/rand-0.5.6/src/rngs/os.rs @@ -0,0 +1,1171 @@ +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Interface to the random number generator of the operating system. + +use std::fmt; +use rand_core::{CryptoRng, RngCore, Error, impls}; + +/// A random number generator that retrieves randomness straight from the +/// operating system. +/// +/// This is the preferred external source of entropy for most applications. +/// Commonly it is used to initialize a user-space RNG, which can then be used +/// to generate random values with much less overhead than `OsRng`. +/// +/// You may prefer to use [`EntropyRng`] instead of `OsRng`. It is unlikely, but +/// not entirely theoretical, for `OsRng` to fail. In such cases [`EntropyRng`] +/// falls back on a good alternative entropy source. +/// +/// `OsRng::new()` is guaranteed to be very cheap (after the first successful +/// call), and will never consume more than one file handle per process. +/// +/// # Platform sources +/// +/// | OS | interface +/// |------------------|--------------------------------------------------------- +/// | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once +/// | Windows | [`RtlGenRandom`][3] +/// | macOS, iOS | [`SecRandomCopyBytes`][4] +/// | FreeBSD | [`kern.arandom`][5] +/// | OpenBSD, Bitrig | [`getentropy`][6] +/// | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once +/// | Dragonfly BSD | [`/dev/random`][8] +/// | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] +/// | Fuchsia OS | [`cprng_draw`][11] +/// | Redox | [`rand:`][12] +/// | CloudABI | [`random_get`][13] +/// | Haiku | `/dev/random` (identical to `/dev/urandom`) +/// | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14]) +/// | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16]) +/// +/// Rand doesn't have a blanket implementation for all Unix-like operating +/// systems that reads from `/dev/urandom`. This ensures all supported operating +/// systems are using the recommended interface and respect maximum buffer +/// sizes. +/// +/// ## Support for WebAssembly and ams.js +/// +/// The three Emscripten targets `asmjs-unknown-emscripten`, +/// `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use +/// Emscripten's emulation of `/dev/random` on web browsers and Node.js. +/// Unfortunately it falls back to the insecure `Math.random()` if a browser +/// doesn't support [`Crypto.getRandomValues`][12]. +/// +/// The bare Wasm target `wasm32-unknown-unknown` tries to call the javascript +/// methods directly, using `stdweb` in combination with `cargo-web`. +/// `wasm-bindgen` is not yet supported. +/// +/// ## Early boot +/// +/// It is possible that early in the boot process the OS hasn't had enough time +/// yet to collect entropy to securely seed its RNG, especially on virtual +/// machines. +/// +/// Some operating systems always block the thread until the RNG is securely +/// seeded. This can take anywhere from a few seconds to more than a minute. +/// Others make a best effort to use a seed from before the shutdown and don't +/// document much. +/// +/// A few, Linux, NetBSD and Solaris, offer a choice between blocking, and +/// getting an error. With `try_fill_bytes` we choose to get the error +/// ([`ErrorKind::NotReady`]), while the other methods use a blocking interface. +/// +/// On Linux (when the `genrandom` system call is not available) and on NetBSD +/// reading from `/dev/urandom` never blocks, even when the OS hasn't collected +/// enough entropy yet. As a countermeasure we try to do a single read from +/// `/dev/random` until we know the OS RNG is initialized (and store this in a +/// global static). +/// +/// # Panics +/// +/// `OsRng` is extremely unlikely to fail if `OsRng::new()`, and one read from +/// it, where succesfull. But in case it does fail, only [`try_fill_bytes`] is +/// able to report the cause. Depending on the error the other [`RngCore`] +/// methods will retry several times, and panic in case the error remains. +/// +/// [`EntropyRng`]: struct.EntropyRng.html +/// [`RngCore`]: ../trait.RngCore.html +/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes +/// [`ErrorKind::NotReady`]: ../enum.ErrorKind.html#variant.NotReady +/// +/// [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html +/// [2]: http://man7.org/linux/man-pages/man4/urandom.4.html +/// [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +/// [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc +/// [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 +/// [6]: https://man.openbsd.org/getentropy.2 +/// [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current +/// [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 +/// [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html +/// [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html +/// [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md +/// [12]: https://github.com/redox-os/randd/blob/master/src/main.rs +/// [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826 +/// [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues +/// [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback +/// [16]: #support-for-webassembly-and-amsjs + + +#[derive(Clone)] +pub struct OsRng(imp::OsRng); + +impl fmt::Debug for OsRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> Result<OsRng, Error> { + imp::OsRng::new().map(OsRng) + } +} + +impl CryptoRng for OsRng {} + +impl RngCore for OsRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + use std::{time, thread}; + + // We cannot return Err(..), so we try to handle before panicking. + const MAX_RETRY_PERIOD: u32 = 10; // max 10s + const WAIT_DUR_MS: u32 = 100; // retry every 100ms + let wait_dur = time::Duration::from_millis(WAIT_DUR_MS as u64); + const RETRY_LIMIT: u32 = (MAX_RETRY_PERIOD * 1000) / WAIT_DUR_MS; + const TRANSIENT_RETRIES: u32 = 8; + let mut err_count = 0; + let mut error_logged = false; + + // Maybe block until the OS RNG is initialized + let mut read = 0; + if let Ok(n) = self.0.test_initialized(dest, true) { read = n }; + let dest = &mut dest[read..]; + + loop { + if let Err(e) = self.try_fill_bytes(dest) { + if err_count >= RETRY_LIMIT { + error!("OsRng failed too many times; last error: {}", e); + panic!("OsRng failed too many times; last error: {}", e); + } + + if e.kind.should_wait() { + if !error_logged { + warn!("OsRng failed; waiting up to {}s and retrying. Error: {}", + MAX_RETRY_PERIOD, e); + error_logged = true; + } + err_count += 1; + thread::sleep(wait_dur); + continue; + } else if e.kind.should_retry() { + if !error_logged { + warn!("OsRng failed; retrying up to {} times. Error: {}", + TRANSIENT_RETRIES, e); + error_logged = true; + } + err_count += (RETRY_LIMIT + TRANSIENT_RETRIES - 1) + / TRANSIENT_RETRIES; // round up + continue; + } else { + error!("OsRng failed: {}", e); + panic!("OsRng fatal error: {}", e); + } + } + + break; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + // Some systems do not support reading 0 random bytes. + // (And why waste a system call?) + if dest.len() == 0 { return Ok(()); } + + let read = self.0.test_initialized(dest, false)?; + let dest = &mut dest[read..]; + + let max = self.0.max_chunk_size(); + if dest.len() <= max { + trace!("OsRng: reading {} bytes via {}", + dest.len(), self.0.method_str()); + } else { + trace!("OsRng: reading {} bytes via {} in {} chunks of {} bytes", + dest.len(), self.0.method_str(), (dest.len() + max) / max, max); + } + for slice in dest.chunks_mut(max) { + self.0.fill_chunk(slice)?; + } + Ok(()) + } +} + +trait OsRngImpl where Self: Sized { + // Create a new `OsRng` platform interface. + fn new() -> Result<Self, Error>; + + // Fill a chunk with random bytes. + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + // Test whether the OS RNG is initialized. This method may not be possible + // to support cheaply (or at all) on all operating systems. + // + // If `blocking` is set, this will cause the OS the block execution until + // its RNG is initialized. + // + // Random values that are read while this are stored in `dest`, the amount + // of read bytes is returned. + fn test_initialized(&mut self, _dest: &mut [u8], _blocking: bool) + -> Result<usize, Error> { Ok(0) } + + // Maximum chunk size supported. + fn max_chunk_size(&self) -> usize { ::core::usize::MAX } + + // Name of the OS interface (used for logging). + fn method_str(&self) -> &'static str; +} + + + + +// Helper functions to read from a random device such as `/dev/urandom`. +// +// All instances use a single internal file handle, to prevent possible +// exhaustion of file descriptors. +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "netbsd", target_os = "dragonfly", + target_os = "solaris", target_os = "redox", + target_os = "haiku", target_os = "emscripten"))] +mod random_device { + use {Error, ErrorKind}; + use std::fs::File; + use std::io; + use std::io::Read; + use std::sync::{Once, Mutex, ONCE_INIT}; + + // TODO: remove outer Option when `Mutex::new(None)` is a constant expression + static mut READ_RNG_FILE: Option<Mutex<Option<File>>> = None; + static READ_RNG_ONCE: Once = ONCE_INIT; + + #[allow(unused)] + pub fn open<F>(path: &'static str, open_fn: F) -> Result<(), Error> + where F: Fn(&'static str) -> Result<File, io::Error> + { + READ_RNG_ONCE.call_once(|| { + unsafe { READ_RNG_FILE = Some(Mutex::new(None)) } + }); + + // We try opening the file outside the `call_once` fn because we cannot + // clone the error, thus we must retry on failure. + + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + if (*guard).is_none() { + info!("OsRng: opening random device {}", path); + let file = open_fn(path).map_err(map_err)?; + *guard = Some(file); + }; + Ok(()) + } + + pub fn read(dest: &mut [u8]) -> Result<(), Error> { + // We expect this function only to be used after `random_device::open` + // was succesful. Therefore we can assume that our memory was set with a + // valid object. + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + let file = (*guard).as_mut().unwrap(); + + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + file.read_exact(dest).map_err(|err| { + Error::with_cause(ErrorKind::Unavailable, + "error reading random device", err) + }) + + } + + pub fn map_err(err: io::Error) -> Error { + match err.kind() { + io::ErrorKind::Interrupted => + Error::new(ErrorKind::Transient, "interrupted"), + io::ErrorKind::WouldBlock => + Error::with_cause(ErrorKind::NotReady, + "OS RNG not yet seeded", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error while opening random device", err) + } + } +} + + +#[cfg(any(target_os = "linux", target_os = "android"))] +mod imp { + extern crate libc; + + use {Error, ErrorKind}; + use super::random_device; + use super::OsRngImpl; + + use std::io; + use std::io::Read; + use std::fs::{File, OpenOptions}; + use std::os::unix::fs::OpenOptionsExt; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; + use std::sync::{Once, ONCE_INIT}; + + #[derive(Clone, Debug)] + pub struct OsRng { + method: OsRngMethod, + initialized: bool, + } + + #[derive(Clone, Debug)] + enum OsRngMethod { + GetRandom, + RandomDevice, + } + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result<usize, Error> + { + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let result = match self.method { + OsRngMethod::GetRandom => { + getrandom_try_fill(dest, blocking)?; + Ok(dest.len()) + } + OsRngMethod::RandomDevice => { + info!("OsRng: testing random device /dev/random"); + let mut file = OpenOptions::new() + .read(true) + .custom_flags(if blocking { 0 } else { libc::O_NONBLOCK }) + .open("/dev/random") + .map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + Ok(1) + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + result + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/urandom", + } + } + } + + #[cfg(target_arch = "x86_64")] + const NR_GETRANDOM: libc::c_long = 318; + #[cfg(target_arch = "x86")] + const NR_GETRANDOM: libc::c_long = 355; + #[cfg(target_arch = "arm")] + const NR_GETRANDOM: libc::c_long = 384; + #[cfg(target_arch = "aarch64")] + const NR_GETRANDOM: libc::c_long = 278; + #[cfg(target_arch = "s390x")] + const NR_GETRANDOM: libc::c_long = 349; + #[cfg(target_arch = "powerpc")] + const NR_GETRANDOM: libc::c_long = 359; + #[cfg(target_arch = "mips")] // old ABI + const NR_GETRANDOM: libc::c_long = 4353; + #[cfg(target_arch = "mips64")] + const NR_GETRANDOM: libc::c_long = 5313; + #[cfg(not(any(target_arch = "x86_64", target_arch = "x86", + target_arch = "arm", target_arch = "aarch64", + target_arch = "s390x", target_arch = "powerpc", + target_arch = "mips", target_arch = "mips64")))] + const NR_GETRANDOM: libc::c_long = 0; + + fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { + extern "C" { + fn syscall(number: libc::c_long, ...) -> libc::c_long; + } + const GRND_NONBLOCK: libc::c_uint = 0x0001; + + if NR_GETRANDOM == 0 { return -1 }; + + unsafe { + syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), + if blocking { 0 } else { GRND_NONBLOCK }) + } + } + + fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let mut read = 0; + while read < dest.len() { + let result = getrandom(&mut dest[read..], blocking); + if result == -1 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::Interrupted { + continue; + } else if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else { + read += result as usize; + } + } + Ok(()) + } + + fn is_getrandom_available() -> bool { + static CHECKER: Once = ONCE_INIT; + static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; + + if NR_GETRANDOM == 0 { return false }; + + CHECKER.call_once(|| { + debug!("OsRng: testing getrandom"); + let mut buf: [u8; 0] = []; + let result = getrandom(&mut buf, false); + let available = if result == -1 { + let err = io::Error::last_os_error().raw_os_error(); + err != Some(libc::ENOSYS) + } else { + true + }; + AVAILABLE.store(available, Ordering::Relaxed); + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/urandom" }); + }); + + AVAILABLE.load(Ordering::Relaxed) + } +} + + +#[cfg(target_os = "netbsd")] +mod imp { + use Error; + use super::random_device; + use super::OsRngImpl; + + use std::fs::File; + use std::io::Read; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; + + #[derive(Clone, Debug)] + pub struct OsRng { initialized: bool } + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + // Read a single byte from `/dev/random` to determine if the OS RNG is + // already seeded. NetBSD always blocks if not yet ready. + fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool) + -> Result<usize, Error> + { + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + info!("OsRng: testing random device /dev/random"); + let mut file = + File::open("/dev/random").map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(1) + } + + fn method_str(&self) -> &'static str { "/dev/urandom" } + } +} + + +#[cfg(any(target_os = "dragonfly", + target_os = "haiku", + target_os = "emscripten"))] +mod imp { + use Error; + use super::random_device; + use super::OsRngImpl; + use std::fs::File; + + #[derive(Clone, Debug)] + pub struct OsRng(); + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("/dev/random", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + #[cfg(target_os = "emscripten")] + fn max_chunk_size(&self) -> usize { + // `Crypto.getRandomValues` documents `dest` should be at most 65536 + // bytes. `crypto.randomBytes` documents: "To minimize threadpool + // task length variation, partition large randomBytes requests when + // doing so as part of fulfilling a client request. + 65536 + } + + fn method_str(&self) -> &'static str { "/dev/random" } + } +} + + +// Read from `/dev/random`, with chunks of limited size (1040 bytes). +// `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. +// `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less +// secure. We choose to read from `/dev/random`. +// +// Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can +// compile on both Solaris and on OpenSolaris derivatives, that do not have the +// function, we do a direct syscall instead of calling a library function. +// +// We have no way to differentiate between Solaris, illumos, SmartOS, etc. +#[cfg(target_os = "solaris")] +mod imp { + extern crate libc; + + use {Error, ErrorKind}; + use super::random_device; + use super::OsRngImpl; + + use std::io; + use std::io::Read; + use std::fs::{File, OpenOptions}; + use std::os::unix::fs::OpenOptionsExt; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; + + #[derive(Clone, Debug)] + pub struct OsRng { + method: OsRngMethod, + initialized: bool, + } + + #[derive(Clone, Debug)] + enum OsRngMethod { + GetRandom, + RandomDevice, + } + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + let open = |p| OpenOptions::new() + .read(true) + .custom_flags(libc::O_NONBLOCK) + .open(p); + random_device::open("/dev/random", &open)?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result<usize, Error> + { + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let chunk_len = ::core::cmp::min(1024, dest.len()); + let dest = &mut dest[..chunk_len]; + + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, blocking)?, + OsRngMethod::RandomDevice => { + if blocking { + info!("OsRng: testing random device /dev/random"); + // We already have a non-blocking handle, but now need a + // blocking one. Not much choice except opening it twice + let mut file = File::open("/dev/random") + .map_err(random_device::map_err)?; + file.read(dest).map_err(random_device::map_err)?; + } else { + self.fill_chunk(dest)?; + } + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(chunk_len) + } + + fn max_chunk_size(&self) -> usize { + // The documentation says 1024 is the maximum for getrandom, but + // 1040 for /dev/random. + 1024 + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/random", + } + } + } + + fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { + extern "C" { + fn syscall(number: libc::c_long, ...) -> libc::c_long; + } + + const SYS_GETRANDOM: libc::c_long = 143; + const GRND_NONBLOCK: libc::c_uint = 0x0001; + const GRND_RANDOM: libc::c_uint = 0x0002; + + unsafe { + syscall(SYS_GETRANDOM, buf.as_mut_ptr(), buf.len(), + if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM) + } + } + + fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let result = getrandom(dest, blocking); + if result == -1 || result == 0 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else if result != dest.len() as i64 { + return Err(Error::new(ErrorKind::Unavailable, + "unexpected getrandom error")); + } + Ok(()) + } + + fn is_getrandom_available() -> bool { + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; + use std::sync::{Once, ONCE_INIT}; + + static CHECKER: Once = ONCE_INIT; + static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; + + CHECKER.call_once(|| { + debug!("OsRng: testing getrandom"); + let mut buf: [u8; 0] = []; + let result = getrandom(&mut buf, false); + let available = if result == -1 { + let err = io::Error::last_os_error().raw_os_error(); + err != Some(libc::ENOSYS) + } else { + true + }; + AVAILABLE.store(available, Ordering::Relaxed); + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); + }); + + AVAILABLE.load(Ordering::Relaxed) + } +} + + +#[cfg(target_os = "cloudabi")] +mod imp { + extern crate cloudabi; + + use std::io; + use {Error, ErrorKind}; + use super::OsRngImpl; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let errno = unsafe { cloudabi::random_get(dest) }; + if errno == cloudabi::errno::SUCCESS { + Ok(()) + } else { + // Cloudlibc provides its own `strerror` implementation so we + // can use `from_raw_os_error` here. + Err(Error::with_cause( + ErrorKind::Unavailable, + "random_get() system call failed", + io::Error::from_raw_os_error(errno as i32), + )) + } + } + + fn method_str(&self) -> &'static str { "cloudabi::random_get" } + } +} + + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod imp { + extern crate libc; + + use {Error, ErrorKind}; + use super::OsRngImpl; + + use std::io; + use self::libc::{c_int, size_t}; + + #[derive(Clone, Debug)] + pub struct OsRng; + + enum SecRandom {} + + #[allow(non_upper_case_globals)] + const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; + + #[link(name = "Security", kind = "framework")] + extern { + fn SecRandomCopyBytes(rnd: *const SecRandom, + count: size_t, bytes: *mut u8) -> c_int; + } + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, + dest.len() as size_t, + dest.as_mut_ptr()) + }; + if ret == -1 { + Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())) + } else { + Ok(()) + } + } + + fn method_str(&self) -> &'static str { "SecRandomCopyBytes" } + } +} + + +#[cfg(target_os = "freebsd")] +mod imp { + extern crate libc; + + use {Error, ErrorKind}; + use super::OsRngImpl; + + use std::ptr; + use std::io; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + let mut len = dest.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + dest.as_mut_ptr() as *mut _, &mut len, + ptr::null(), 0) + }; + if ret == -1 || len != dest.len() { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "kern.arandom sysctl failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "kern.arandom" } + } +} + + +#[cfg(any(target_os = "openbsd", target_os = "bitrig"))] +mod imp { + extern crate libc; + + use {Error, ErrorKind}; + use super::OsRngImpl; + + use std::io; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + libc::getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) + }; + if ret == -1 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "getentropy failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "getentropy" } + } +} + + +#[cfg(target_os = "redox")] +mod imp { + use Error; + use super::random_device; + use super::OsRngImpl; + use std::fs::File; + + #[derive(Clone, Debug)] + pub struct OsRng(); + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("rand:", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + fn method_str(&self) -> &'static str { "'rand:'" } + } +} + + +#[cfg(target_os = "fuchsia")] +mod imp { + extern crate fuchsia_cprng; + + use Error; + use super::OsRngImpl; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + fuchsia_cprng::cprng_draw(dest); + Ok(()) + } + + fn method_str(&self) -> &'static str { "cprng_draw" } + } +} + + +#[cfg(windows)] +mod imp { + extern crate winapi; + + use {Error, ErrorKind}; + use super::OsRngImpl; + + use std::io; + + use self::winapi::shared::minwindef::ULONG; + use self::winapi::um::ntsecapi::RtlGenRandom; + use self::winapi::um::winnt::PVOID; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) + }; + if ret == 0 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { <ULONG>::max_value() as usize } + + fn method_str(&self) -> &'static str { "RtlGenRandom" } + } +} + + +#[cfg(all(target_arch = "wasm32", + not(target_os = "emscripten"), + feature = "stdweb"))] +mod imp { + use std::mem; + use stdweb::unstable::TryInto; + use stdweb::web::error::Error as WebError; + use {Error, ErrorKind}; + use super::OsRngImpl; + + #[derive(Clone, Debug)] + enum OsRngMethod { + Browser, + Node + } + + #[derive(Clone, Debug)] + pub struct OsRng(OsRngMethod); + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + let result = js! { + try { + if ( + typeof self === "object" && + typeof self.crypto === "object" && + typeof self.crypto.getRandomValues === "function" + ) { + return { success: true, ty: 1 }; + } + + if (typeof require("crypto").randomBytes === "function") { + return { success: true, ty: 2 }; + } + + return { success: false, error: new Error("not supported") }; + } catch(err) { + return { success: false, error: err }; + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + let ty = js!{ return @{ result }.ty }; + + if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) } + else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) } + else { unreachable!() } + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err)) + } + } + + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + assert_eq!(mem::size_of::<usize>(), 4); + + let len = dest.len() as u32; + let ptr = dest.as_mut_ptr() as i32; + + let result = match self.0 { + OsRngMethod::Browser => js! { + try { + let array = new Uint8Array(@{ len }); + self.crypto.getRandomValues(array); + HEAPU8.set(array, @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + }, + OsRngMethod::Node => js! { + try { + let bytes = require("crypto").randomBytes(@{ len }); + HEAPU8.set(new Uint8Array(bytes), @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + Ok(()) + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err)) + } + } + + fn max_chunk_size(&self) -> usize { 65536 } + + fn method_str(&self) -> &'static str { + match self.0 { + OsRngMethod::Browser => "Crypto.getRandomValues", + OsRngMethod::Node => "crypto.randomBytes", + } + } + } +} + + +#[cfg(test)] +mod test { + use RngCore; + use OsRng; + + #[test] + fn test_os_rng() { + let mut r = OsRng::new().unwrap(); + + r.next_u32(); + r.next_u64(); + + let mut v1 = [0u8; 1000]; + r.fill_bytes(&mut v1); + + let mut v2 = [0u8; 1000]; + r.fill_bytes(&mut v2); + + let mut n_diff_bits = 0; + for i in 0..v1.len() { + n_diff_bits += (v1[i] ^ v2[i]).count_ones(); + } + + // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input. + assert!(n_diff_bits >= v1.len() as u32); + } + + #[test] + fn test_os_rng_empty() { + let mut r = OsRng::new().unwrap(); + + let mut empty = [0u8; 0]; + r.fill_bytes(&mut empty); + } + + #[test] + fn test_os_rng_huge() { + let mut r = OsRng::new().unwrap(); + + let mut huge = [0u8; 100_000]; + r.fill_bytes(&mut huge); + } + + #[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] + #[test] + fn test_os_rng_tasks() { + use std::sync::mpsc::channel; + use std::thread; + + let mut txs = vec!(); + for _ in 0..20 { + let (tx, rx) = channel(); + txs.push(tx); + + thread::spawn(move|| { + // wait until all the tasks are ready to go. + rx.recv().unwrap(); + + // deschedule to attempt to interleave things as much + // as possible (XXX: is this a good test?) + let mut r = OsRng::new().unwrap(); + thread::yield_now(); + let mut v = [0u8; 1000]; + + for _ in 0..100 { + r.next_u32(); + thread::yield_now(); + r.next_u64(); + thread::yield_now(); + r.fill_bytes(&mut v); + thread::yield_now(); + } + }); + } + + // start all the tasks + for tx in txs.iter() { + tx.send(()).unwrap(); + } + } +} diff --git a/rand-0.5.6/src/rngs/small.rs b/rand-0.5.6/src/rngs/small.rs new file mode 100644 index 000000000..effdbffcb --- /dev/null +++ b/rand-0.5.6/src/rngs/small.rs @@ -0,0 +1,101 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A small fast RNG + +use {RngCore, SeedableRng, Error}; +use prng::XorShiftRng; + +/// An RNG recommended when small state, cheap initialization and good +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be +/// efficient on the current platform, **without consideration for cryptography +/// or security**. The size of its state is much smaller than for [`StdRng`]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`XorShiftRng`]. +/// +/// The current algorithm used on all platforms is [Xorshift]. +/// +/// # Examples +/// +/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// +/// ``` +/// # use rand::Rng; +/// use rand::FromEntropy; +/// use rand::rngs::SmallRng; +/// +/// // Create small, cheap to initialize and fast RNG with a random seed. +/// // The randomness is supplied by the operating system. +/// let mut small_rng = SmallRng::from_entropy(); +/// # let v: u32 = small_rng.gen(); +/// ``` +/// +/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more +/// efficient: +/// +/// ``` +/// use std::iter; +/// use rand::{SeedableRng, thread_rng}; +/// use rand::rngs::SmallRng; +/// +/// // Create a big, expensive to initialize and slower, but unpredictable RNG. +/// // This is cached and done only once per thread. +/// let mut thread_rng = thread_rng(); +/// // Create small, cheap to initialize and fast RNGs with random seeds. +/// // One can generally assume this won't fail. +/// let rngs: Vec<SmallRng> = iter::repeat(()) +/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) +/// .take(10) +/// .collect(); +/// ``` +/// +/// [`FromEntropy`]: ../trait.FromEntropy.html +/// [`StdRng`]: struct.StdRng.html +/// [`thread_rng`]: ../fn.thread_rng.html +/// [Xorshift]: ../prng/struct.XorShiftRng.html +/// [`XorShiftRng`]: ../prng/struct.XorShiftRng.html +#[derive(Clone, Debug)] +pub struct SmallRng(XorShiftRng); + +impl RngCore for SmallRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for SmallRng { + type Seed = <XorShiftRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + SmallRng(XorShiftRng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + XorShiftRng::from_rng(rng).map(SmallRng) + } +} diff --git a/rand-0.5.6/src/rngs/std.rs b/rand-0.5.6/src/rngs/std.rs new file mode 100644 index 000000000..1451f7636 --- /dev/null +++ b/rand-0.5.6/src/rngs/std.rs @@ -0,0 +1,83 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The standard RNG + +use {RngCore, CryptoRng, Error, SeedableRng}; +use prng::Hc128Rng; + +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient +/// on the current platform, to be statistically strong and unpredictable +/// (meaning a cryptographically secure PRNG). +/// +/// The current algorithm used on all platforms is [HC-128]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`ChaChaRng`]. +/// +/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html +/// [`ChaChaRng`]: ../prng/chacha/struct.ChaChaRng.html +#[derive(Clone, Debug)] +pub struct StdRng(Hc128Rng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = <Hc128Rng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(Hc128Rng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + Hc128Rng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use rngs::StdRng; + + #[test] + fn test_stdrng_construction() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = StdRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 15759097995037006553); + + let mut rng2 = StdRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 6766915756997287454); + } +} diff --git a/rand-0.5.6/src/rngs/thread.rs b/rand-0.5.6/src/rngs/thread.rs new file mode 100644 index 000000000..863b79d31 --- /dev/null +++ b/rand-0.5.6/src/rngs/thread.rs @@ -0,0 +1,141 @@ +// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Thread-local random number generator + +use std::cell::UnsafeCell; +use std::rc::Rc; + +use {RngCore, CryptoRng, SeedableRng, Error}; +use rngs::adapter::ReseedingRng; +use rngs::EntropyRng; +use prng::hc128::Hc128Core; + +// Rationale for using `UnsafeCell` in `ThreadRng`: +// +// Previously we used a `RefCell`, with an overhead of ~15%. There will only +// ever be one mutable reference to the interior of the `UnsafeCell`, because +// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a +// single thread (which is the definition of `ThreadRng`), there will only ever +// be one of these methods active at a time. +// +// A possible scenario where there could be multiple mutable references is if +// `ThreadRng` is used inside `next_u32` and co. But the implementation is +// completely under our control. We just have to ensure none of them use +// `ThreadRng` internally, which is nonsensical anyway. We should also never run +// `ThreadRng` in destructors of its implementation, which is also nonsensical. +// +// The additional `Rc` is not strictly neccesary, and could be removed. For now +// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`. + + +// Number of generated bytes after which to reseed `TreadRng`. +// +// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB. +// We pick a treshold here that is large enough to not reduce the average +// performance too much, but also small enough to not make reseeding something +// that basically never happens. +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB + +/// The type returned by [`thread_rng`], essentially just a reference to the +/// PRNG in thread-local memory. +/// +/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`], +/// which is reseeded after generating 32 MiB of random data. A single instance +/// is cached per thread and the returned `ThreadRng` is a reference to this +/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use +/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`] +/// as required. +/// +/// Note that the reseeding is done as an extra precaution against entropy +/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an +/// attacker would have to either determine most of the RNG's seed or internal +/// state, or crack the algorithm used. +/// +/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current +/// algorithm used is [HC-128], which is an array-based PRNG that trades memory +/// usage for better performance. This makes it similar to ISAAC, the algorithm +/// used in `ThreadRng` before rand 0.5. +/// +/// Cloning this handle just produces a new reference to the same thread-local +/// generator. +/// +/// [`thread_rng`]: ../fn.thread_rng.html +/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html +/// [`StdRng`]: struct.StdRng.html +/// [`EntropyRng`]: struct.EntropyRng.html +/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html +#[derive(Clone, Debug)] +pub struct ThreadRng { + rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>, +} + +thread_local!( + static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = { + let mut entropy_source = EntropyRng::new(); + let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err| + panic!("could not initialize thread_rng: {}", err)); + let rng = ReseedingRng::new(r, + THREAD_RNG_RESEED_THRESHOLD, + entropy_source); + Rc::new(UnsafeCell::new(rng)) + } +); + +/// Retrieve the lazily-initialized thread-local random number +/// generator, seeded by the system. Intended to be used in method +/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g. +/// `let mut rng = thread_rng();`. +/// +/// For more information see [`ThreadRng`]. +/// +/// [`ThreadRng`]: rngs/struct.ThreadRng.html +pub fn thread_rng() -> ThreadRng { + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } +} + +impl RngCore for ThreadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + unsafe { (*self.rng.get()).next_u32() } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + unsafe { (*self.rng.get()).next_u64() } + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + unsafe { (*self.rng.get()).fill_bytes(dest) } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unsafe { (*self.rng.get()).try_fill_bytes(dest) } + } +} + +impl CryptoRng for ThreadRng {} + + +#[cfg(test)] +mod test { + #[test] + #[cfg(not(feature="stdweb"))] + fn test_thread_rng() { + use Rng; + let mut r = ::thread_rng(); + r.gen::<i32>(); + let mut v = [1, 1, 1]; + r.shuffle(&mut v); + let b: &[_] = &[1, 1, 1]; + assert_eq!(v, b); + assert_eq!(r.gen_range(0, 1), 0); + } +} diff --git a/rand-0.5.6/src/seq.rs b/rand-0.5.6/src/seq.rs new file mode 100644 index 000000000..8c7ed4786 --- /dev/null +++ b/rand-0.5.6/src/seq.rs @@ -0,0 +1,334 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Functions for randomly accessing and sampling sequences. + +use super::Rng; + +// This crate is only enabled when either std or alloc is available. +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::Vec; +// BTreeMap is not as fast in tests, but better than nothing. +#[cfg(feature="std")] use std::collections::HashMap; +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::collections::BTreeMap; + +/// Randomly sample `amount` elements from a finite iterator. +/// +/// The following can be returned: +/// +/// - `Ok`: `Vec` of `amount` non-repeating randomly sampled elements. The order is not random. +/// - `Err`: `Vec` of all the elements from `iterable` in sequential order. This happens when the +/// length of `iterable` was less than `amount`. This is considered an error since exactly +/// `amount` elements is typically expected. +/// +/// This implementation uses `O(len(iterable))` time and `O(amount)` memory. +/// +/// # Example +/// +/// ``` +/// use rand::{thread_rng, seq}; +/// +/// let mut rng = thread_rng(); +/// let sample = seq::sample_iter(&mut rng, 1..100, 5).unwrap(); +/// println!("{:?}", sample); +/// ``` +pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>> + where I: IntoIterator<Item=T>, + R: Rng + ?Sized, +{ + let mut iter = iterable.into_iter(); + let mut reservoir = Vec::with_capacity(amount); + reservoir.extend(iter.by_ref().take(amount)); + + // Continue unless the iterator was exhausted + // + // note: this prevents iterators that "restart" from causing problems. + // If the iterator stops once, then so do we. + if reservoir.len() == amount { + for (i, elem) in iter.enumerate() { + let k = rng.gen_range(0, i + 1 + amount); + if let Some(spot) = reservoir.get_mut(k) { + *spot = elem; + } + } + Ok(reservoir) + } else { + // Don't hang onto extra memory. There is a corner case where + // `amount` was much less than `len(iterable)`. + reservoir.shrink_to_fit(); + Err(reservoir) + } +} + +/// Randomly sample exactly `amount` values from `slice`. +/// +/// The values are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// # Example +/// +/// ``` +/// use rand::{thread_rng, seq}; +/// +/// let mut rng = thread_rng(); +/// let values = vec![5, 6, 1, 3, 4, 6, 7]; +/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3)); +/// ``` +pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T> + where R: Rng + ?Sized, + T: Clone +{ + let indices = sample_indices(rng, slice.len(), amount); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.iter().map(|i| slice[*i].clone())); + out +} + +/// Randomly sample exactly `amount` references from `slice`. +/// +/// The references are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// # Example +/// +/// ``` +/// use rand::{thread_rng, seq}; +/// +/// let mut rng = thread_rng(); +/// let values = vec![5, 6, 1, 3, 4, 6, 7]; +/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3)); +/// ``` +pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T> + where R: Rng + ?Sized +{ + let indices = sample_indices(rng, slice.len(), amount); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.iter().map(|i| &slice[*i])); + out +} + +/// Randomly sample exactly `amount` indices from `0..length`. +/// +/// The values are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// This method is used internally by the slice sampling methods, but it can sometimes be useful to +/// have the indices themselves so this is provided as an alternative. +/// +/// Panics if `amount > length` +pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize> + where R: Rng + ?Sized, +{ + if amount > length { + panic!("`amount` must be less than or equal to `slice.len()`"); + } + + // We are going to have to allocate at least `amount` for the output no matter what. However, + // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since + // it inserts an element for every loop. + // + // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory. + // In fact, benchmarks show the inplace version is faster for length up to about 20 times + // faster than amount. + // + // TODO: there is probably even more fine-tuning that can be done here since + // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice, + // and a trade off could probably be made between memory/cpu, since hashmap operations + // are slower than array index swapping. + if amount >= length / 20 { + sample_indices_inplace(rng, length, amount) + } else { + sample_indices_cache(rng, length, amount) + } +} + +/// Sample an amount of indices using an inplace partial fisher yates method. +/// +/// This allocates the entire `length` of indices and randomizes only the first `amount`. +/// It then truncates to `amount` and returns. +/// +/// This is better than using a `HashMap` "cache" when `amount >= length / 2` +/// since it does not require allocating an extra cache and is much faster. +fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize> + where R: Rng + ?Sized, +{ + debug_assert!(amount <= length); + let mut indices: Vec<usize> = Vec::with_capacity(length); + indices.extend(0..length); + for i in 0..amount { + let j: usize = rng.gen_range(i, length); + indices.swap(i, j); + } + indices.truncate(amount); + debug_assert_eq!(indices.len(), amount); + indices +} + + +/// This method performs a partial fisher-yates on a range of indices using a +/// `HashMap` as a cache to record potential collisions. +/// +/// The cache avoids allocating the entire `length` of values. This is especially useful when +/// `amount <<< length`, i.e. select 3 non-repeating from `1_000_000` +fn sample_indices_cache<R>( + rng: &mut R, + length: usize, + amount: usize, +) -> Vec<usize> + where R: Rng + ?Sized, +{ + debug_assert!(amount <= length); + #[cfg(feature="std")] let mut cache = HashMap::with_capacity(amount); + #[cfg(not(feature="std"))] let mut cache = BTreeMap::new(); + let mut out = Vec::with_capacity(amount); + for i in 0..amount { + let j: usize = rng.gen_range(i, length); + + // equiv: let tmp = slice[i]; + let tmp = match cache.get(&i) { + Some(e) => *e, + None => i, + }; + + // equiv: slice[i] = slice[j]; + let x = match cache.get(&j) { + Some(x) => *x, + None => j, + }; + + // equiv: slice[j] = tmp; + cache.insert(j, tmp); + + // note that in the inplace version, slice[i] is automatically "returned" value + out.push(x); + } + debug_assert_eq!(out.len(), amount); + out +} + +#[cfg(test)] +mod test { + use super::*; + use {XorShiftRng, Rng, SeedableRng}; + #[cfg(not(feature="std"))] + use alloc::vec::Vec; + + #[test] + fn test_sample_iter() { + let min_val = 1; + let max_val = 100; + + let mut r = ::test::rng(401); + let vals = (min_val..max_val).collect::<Vec<i32>>(); + let small_sample = sample_iter(&mut r, vals.iter(), 5).unwrap(); + let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5).unwrap_err(); + + assert_eq!(small_sample.len(), 5); + assert_eq!(large_sample.len(), vals.len()); + // no randomization happens when amount >= len + assert_eq!(large_sample, vals.iter().collect::<Vec<_>>()); + + assert!(small_sample.iter().all(|e| { + **e >= min_val && **e <= max_val + })); + } + #[test] + fn test_sample_slice_boundaries() { + let empty: &[u8] = &[]; + + let mut r = ::test::rng(402); + + // sample 0 items + assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]); + assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]); + + // sample 1 item + assert_eq!(&sample_slice(&mut r, &[42], 1)[..], [42]); + let v = sample_slice(&mut r, &[1, 42], 1)[0]; + assert!(v == 1 || v == 42); + + // sample "all" the items + let v = sample_slice(&mut r, &[42, 133], 2); + assert!(&v[..] == [42, 133] || v[..] == [133, 42]); + + assert_eq!(&sample_indices_inplace(&mut r, 0, 0)[..], [0usize; 0]); + assert_eq!(&sample_indices_inplace(&mut r, 1, 0)[..], [0usize; 0]); + assert_eq!(&sample_indices_inplace(&mut r, 1, 1)[..], [0]); + + assert_eq!(&sample_indices_cache(&mut r, 0, 0)[..], [0usize; 0]); + assert_eq!(&sample_indices_cache(&mut r, 1, 0)[..], [0usize; 0]); + assert_eq!(&sample_indices_cache(&mut r, 1, 1)[..], [0]); + + // Make sure lucky 777's aren't lucky + let slice = &[42, 777]; + let mut num_42 = 0; + let total = 1000; + for _ in 0..total { + let v = sample_slice(&mut r, slice, 1); + assert_eq!(v.len(), 1); + let v = v[0]; + assert!(v == 42 || v == 777); + if v == 42 { + num_42 += 1; + } + } + let ratio_42 = num_42 as f64 / 1000 as f64; + assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42); + } + + #[test] + fn test_sample_slice() { + let xor_rng = XorShiftRng::from_seed; + + let max_range = 100; + let mut r = ::test::rng(403); + + for length in 1usize..max_range { + let amount = r.gen_range(0, length); + let mut seed = [0u8; 16]; + r.fill(&mut seed); + + // assert that the two index methods give exactly the same result + let inplace = sample_indices_inplace( + &mut xor_rng(seed), length, amount); + let cache = sample_indices_cache( + &mut xor_rng(seed), length, amount); + assert_eq!(inplace, cache); + + // assert the basics work + let regular = sample_indices( + &mut xor_rng(seed), length, amount); + assert_eq!(regular.len(), amount); + assert!(regular.iter().all(|e| *e < length)); + assert_eq!(regular, inplace); + + // also test that sampling the slice works + let vec: Vec<usize> = (0..length).collect(); + { + let result = sample_slice(&mut xor_rng(seed), &vec, amount); + assert_eq!(result, regular); + } + + { + let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount); + let expected = regular.iter().map(|v| v).collect::<Vec<_>>(); + assert_eq!(result, expected); + } + } + } +} diff --git a/rand-0.5.6/tests/bool.rs b/rand-0.5.6/tests/bool.rs new file mode 100644 index 000000000..c4208a009 --- /dev/null +++ b/rand-0.5.6/tests/bool.rs @@ -0,0 +1,23 @@ +#![no_std] + +extern crate rand; + +use rand::SeedableRng; +use rand::rngs::SmallRng; +use rand::distributions::{Distribution, Bernoulli}; + +/// This test should make sure that we don't accidentally have undefined +/// behavior for large propabilties due to +/// https://github.com/rust-lang/rust/issues/10184. +/// Expressions like `1.0*(u64::MAX as f64) as u64` have to be avoided. +#[test] +fn large_probability() { + let p = 1. - ::core::f64::EPSILON / 2.; + assert!(p < 1.); + let d = Bernoulli::new(p); + let mut rng = SmallRng::from_seed( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); + for _ in 0..10 { + assert!(d.sample(&mut rng), "extremely unlikely to fail by accident"); + } +} diff --git a/rand-0.5.6/utils/ci/install.sh b/rand-0.5.6/utils/ci/install.sh new file mode 100644 index 000000000..8e636e181 --- /dev/null +++ b/rand-0.5.6/utils/ci/install.sh @@ -0,0 +1,49 @@ +# From https://github.com/japaric/trust + +set -ex + +main() { + local target= + if [ $TRAVIS_OS_NAME = linux ]; then + target=x86_64-unknown-linux-musl + sort=sort + else + target=x86_64-apple-darwin + sort=gsort # for `sort --sort-version`, from brew's coreutils. + fi + + # Builds for iOS are done on OSX, but require the specific target to be + # installed. + case $TARGET in + aarch64-apple-ios) + rustup target install aarch64-apple-ios + ;; + armv7-apple-ios) + rustup target install armv7-apple-ios + ;; + armv7s-apple-ios) + rustup target install armv7s-apple-ios + ;; + i386-apple-ios) + rustup target install i386-apple-ios + ;; + x86_64-apple-ios) + rustup target install x86_64-apple-ios + ;; + esac + + # This fetches latest stable release + local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ + | cut -d/ -f3 \ + | grep -E '^v[0.1.0-9.]+$' \ + | $sort --version-sort \ + | tail -n1) + curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- \ + --force \ + --git japaric/cross \ + --tag $tag \ + --target $target +} + +main diff --git a/rand-0.5.6/utils/ci/script.sh b/rand-0.5.6/utils/ci/script.sh new file mode 100644 index 000000000..21188f38d --- /dev/null +++ b/rand-0.5.6/utils/ci/script.sh @@ -0,0 +1,29 @@ +# Derived from https://github.com/japaric/trust + +set -ex + +main() { + if [ ! -z $DISABLE_TESTS ]; then # tests are disabled + cross build --no-default-features --target $TARGET --release + if [ -z $DISABLE_STD ]; then # std is enabled + cross build --features log,serde1 --target $TARGET + fi + return + fi + + if [ ! -z $NIGHTLY ]; then # have nightly Rust + cross test --tests --no-default-features --features alloc --target $TARGET + cross test --package rand_core --no-default-features --features alloc --target $TARGET + cross test --features serde1,log,nightly,alloc --target $TARGET + cross test --all --benches --target $TARGET + else # have stable Rust + cross test --tests --no-default-features --target $TARGET + cross test --package rand_core --no-default-features --target $TARGET + cross test --features serde1,log --target $TARGET + fi +} + +# we don't run the "test phase" when doing deploys +if [ -z $TRAVIS_TAG ]; then + main +fi diff --git a/rand-0.5.6/utils/ziggurat_tables.py b/rand-0.5.6/utils/ziggurat_tables.py new file mode 100755 index 000000000..9973b83f4 --- /dev/null +++ b/rand-0.5.6/utils/ziggurat_tables.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# +# Copyright 2013 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# https://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This creates the tables used for distributions implemented using the +# ziggurat algorithm in `rand::distributions;`. They are +# (basically) the tables as used in the ZIGNOR variant (Doornik 2005). +# They are changed rarely, so the generated file should be checked in +# to git. +# +# It creates 3 tables: X as in the paper, F which is f(x_i), and +# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached +# values which is not done in that paper (but is done in other +# variants). Note that the adZigR table is unnecessary because of +# algebra. +# +# It is designed to be compatible with Python 2 and 3. + +from math import exp, sqrt, log, floor +import random + +# The order should match the return value of `tables` +TABLE_NAMES = ['X', 'F'] + +# The actual length of the table is 1 more, to stop +# index-out-of-bounds errors. This should match the bitwise operation +# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and +# *_V constants below depend on this value. +TABLE_LEN = 256 + +# equivalent to `zigNorInit` in Doornik2005, but generalised to any +# distribution. r = dR, v = dV, f = probability density function, +# f_inv = inverse of f +def tables(r, v, f, f_inv): + # compute the x_i + xvec = [0]*(TABLE_LEN+1) + + xvec[0] = v / f(r) + xvec[1] = r + + for i in range(2, TABLE_LEN): + last = xvec[i-1] + xvec[i] = f_inv(v / last + f(last)) + + # cache the f's + fvec = [0]*(TABLE_LEN+1) + for i in range(TABLE_LEN+1): + fvec[i] = f(xvec[i]) + + return xvec, fvec + +# Distributions +# N(0, 1) +def norm_f(x): + return exp(-x*x/2.0) +def norm_f_inv(y): + return sqrt(-2.0*log(y)) + +NORM_R = 3.6541528853610088 +NORM_V = 0.00492867323399 + +NORM = tables(NORM_R, NORM_V, + norm_f, norm_f_inv) + +# Exp(1) +def exp_f(x): + return exp(-x) +def exp_f_inv(y): + return -log(y) + +EXP_R = 7.69711747013104972 +EXP_V = 0.0039496598225815571993 + +EXP = tables(EXP_R, EXP_V, + exp_f, exp_f_inv) + + +# Output the tables/constants/types + +def render_static(name, type, value): + # no space or + return 'pub static %s: %s =%s;\n' % (name, type, value) + +# static `name`: [`type`, .. `len(values)`] = +# [values[0], ..., values[3], +# values[4], ..., values[7], +# ... ]; +def render_table(name, values): + rows = [] + # 4 values on each row + for i in range(0, len(values), 4): + row = values[i:i+4] + rows.append(', '.join('%.18f' % f for f in row)) + + rendered = '\n [%s]' % ',\n '.join(rows) + return render_static(name, '[f64, .. %d]' % len(values), rendered) + + +with open('ziggurat_tables.rs', 'w') as f: + f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// https://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &\'static [f64, .. %d]; +''' % (TABLE_LEN + 1)) + for name, tables, r in [('NORM', NORM, NORM_R), + ('EXP', EXP, EXP_R)]: + f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r)) + for (tabname, table) in zip(TABLE_NAMES, tables): + f.write(render_table('ZIG_%s_%s' % (name, tabname), table)) diff --git a/rand/.cargo-checksum.json b/rand/.cargo-checksum.json new file mode 100644 index 000000000..31098a1b2 --- /dev/null +++ b/rand/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"} \ No newline at end of file diff --git a/rand/CHANGELOG.md b/rand/CHANGELOG.md new file mode 100644 index 000000000..955e872b0 --- /dev/null +++ b/rand/CHANGELOG.md @@ -0,0 +1,522 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md). + +You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful. + + +## [0.6.5] - 2019-01-28 +### Crates +- Update `rand_core` to 0.4 (#703) +- Move `JitterRng` to its own crate (#685) +- Add a warm-bindgen test crate (#696) + +### Platforms +- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng + +### Doc +- Use RFC 1946 for doc links (#691) +- Fix some doc links and notes (#711) + +## [0.6.4] - 2019-01-08 +### Fixes +- Move wasm-bindgen shims to correct crate (#686) +- Make `wasm32-unknown-unknown` compile but fail at run-time if missing bindingsg (#686) + +## [0.6.3] - 2019-01-04 +### Fixes +- Make the `std` feature require the optional `rand_os` dependency (#675) +- Re-export the optional WASM dependencies of `rand_os` from `rand` to avoid breakage (#674) + +## [0.6.2] - 2019-01-04 +### Additions +- Add `Default` for `ThreadRng` (#657) +- Move `rngs::OsRng` to `rand_os` sub-crate; clean up code; use as dependency (#643) ##BLOCKER## +- Add `rand_xoshiro` sub-crate, plus benchmarks (#642, #668) + +### Fixes +- Fix bias in `UniformInt::sample_single` (#662) +- Use `autocfg` instead of `rustc_version` for rustc version detection (#664) +- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) +- CI fixes (#660, #671) + +### Optimisations +- Optimise memory usage of `UnitCircle` and `UnitSphereSurface` distributions (no PR) + +## [0.6.1] - 2018-11-22 +- Support sampling `Duration` also for `no_std` (only since Rust 1.25) (#649) +- Disable default features of `libc` (#647) + +## [0.6.0] - 2018-11-14 + +### Project organisation +- Rand has moved from [rust-lang-nursery](https://github.com/rust-lang-nursery/rand) + to [rust-random](https://github.com/rust-random/rand)! (#578) +- Created [The Rust Random Book](https://rust-random.github.io/book/) + ([source](https://github.com/rust-random/book)) +- Update copyright and licence notices (#591, #611) +- Migrate policy documentation from the wiki (#544) + +### Platforms +- Add fork protection on Unix (#466) +- Added support for wasm-bindgen. (#541, #559, #562, #600) +- Enable `OsRng` for powerpc64, sparc and sparc64 (#609) +- Use `syscall` from `libc` on Linux instead of redefining it (#629) + +### RNGs +- Switch `SmallRng` to use PCG (#623) +- Implement `Pcg32` and `Pcg64Mcg` generators (#632) +- Move ISAAC RNGs to a dedicated crate (#551) +- Move Xorshift RNG to its own crate (#557) +- Move ChaCha and HC128 RNGs to dedicated crates (#607, #636) +- Remove usage of `Rc` from `ThreadRng` (#615) + +### Sampling and distributions +- Implement `Rng.gen_ratio()` and `Bernoulli::new_ratio()` (#491) +- Make `Uniform` strictly respect `f32` / `f64` high/low bounds (#477) +- Allow `gen_range` and `Uniform` to work on non-`Copy` types (#506) +- `Uniform` supports inclusive ranges: `Uniform::from(a..=b)`. This is + automatically enabled for Rust >= 1.27. (#566) +- Implement `TrustedLen` and `FusedIterator` for `DistIter` (#620) + +#### New distributions +- Add the `Dirichlet` distribution (#485) +- Added sampling from the unit sphere and circle. (#567) +- Implement the triangular distribution (#575) +- Implement the Weibull distribution (#576) +- Implement the Beta distribution (#574) + +#### Optimisations + +- Optimise `Bernoulli::new` (#500) +- Optimise `char` sampling (#519) +- Optimise sampling of `std::time::Duration` (#583) + +### Sequences +- Redesign the `seq` module (#483, #515) +- Add `WeightedIndex` and `choose_weighted` (#518, #547) +- Optimised and changed return type of the `sample_indices` function. (#479) +- Use `Iterator::size_hint()` to speed up `IteratorRandom::choose` (#593) + +### SIMD +- Support for generating SIMD types (#523, #542, #561, #630) + +### Other +- Revise CI scripts (#632, #635) +- Remove functionality already deprecated in 0.5 (#499) +- Support for `i128` and `u128` is automatically enabled for Rust >= 1.26. This + renders the `i128_support` feature obsolete. It still exists for backwards + compatibility but does not have any effect. This breaks programs using Rand + with `i128_support` on nightlies older than Rust 1.26. (#571) + + +## [0.5.5] - 2018-08-07 +### Documentation +- Fix links in documentation (#582) + + +## [0.5.4] - 2018-07-11 +### Platform support +- Make `OsRng` work via WASM/stdweb for WebWorkers + + +## [0.5.3] - 2018-06-26 +### Platform support +- OpenBSD, Bitrig: fix compilation (broken in 0.5.1) (#530) + + +## [0.5.2] - 2018-06-18 +### Platform support +- Hide `OsRng` and `JitterRng` on unsupported platforms (#512; fixes #503). + + +## [0.5.1] - 2018-06-08 + +### New distributions +- Added Cauchy distribution. (#474, #486) +- Added Pareto distribution. (#495) + +### Platform support and `OsRng` +- Remove blanket Unix implementation. (#484) +- Remove Wasm unimplemented stub. (#484) +- Dragonfly BSD: read from `/dev/random`. (#484) +- Bitrig: use `getentropy` like OpenBSD. (#484) +- Solaris: (untested) use `getrandom` if available, otherwise `/dev/random`. (#484) +- Emscripten, `stdweb`: split the read up in chunks. (#484) +- Emscripten, Haiku: don't do an extra blocking read from `/dev/random`. (#484) +- Linux, NetBSD, Solaris: read in blocking mode on first use in `fill_bytes`. (#484) +- Fuchsia, CloudABI: fix compilation (broken in Rand 0.5). (#484) + + +## [0.5.0] - 2018-05-21 + +### Crate features and organisation +- Minimum Rust version update: 1.22.0. (#239) +- Create a separate `rand_core` crate. (#288) +- Deprecate `rand_derive`. (#256) +- Add `prelude` (and module reorganisation). (#435) +- Add `log` feature. Logging is now available in `JitterRng`, `OsRng`, `EntropyRng` and `ReseedingRng`. (#246) +- Add `serde1` feature for some PRNGs. (#189) +- `stdweb` feature for `OsRng` support on WASM via stdweb. (#272, #336) + +### `Rng` trait +- Split `Rng` in `RngCore` and `Rng` extension trait. + `next_u32`, `next_u64` and `fill_bytes` are now part of `RngCore`. (#265) +- Add `Rng::sample`. (#256) +- Deprecate `Rng::gen_weighted_bool`. (#308) +- Add `Rng::gen_bool`. (#308) +- Remove `Rng::next_f32` and `Rng::next_f64`. (#273) +- Add optimized `Rng::fill` and `Rng::try_fill` methods. (#247) +- Deprecate `Rng::gen_iter`. (#286) +- Deprecate `Rng::gen_ascii_chars`. (#279) + +### `rand_core` crate +- `rand` now depends on new `rand_core` crate (#288) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +### Other traits and types +- Add `FromEntropy` trait. (#233, #375) +- Add `SmallRng` wrapper. (#296) +- Rewrite `ReseedingRng` to only work with `BlockRngCore` (substantial performance improvement). (#281) +- Deprecate `weak_rng`. Use `SmallRng` instead. (#296) +- Deprecate `AsciiGenerator`. (#279) + +### Random number generators +- Switch `StdRng` and `thread_rng` to HC-128. (#277) +- `StdRng` must now be created with `from_entropy` instead of `new` +- Change `thread_rng` reseeding threshold to 32 MiB. (#277) +- PRNGs no longer implement `Copy`. (#209) +- `Debug` implementations no longer show internals. (#209) +- Implement `Clone` for `ReseedingRng`, `JitterRng`, OsRng`. (#383, #384) +- Implement serialization for `XorShiftRng`, `IsaacRng` and `Isaac64Rng` under the `serde1` feature. (#189) +- Implement `BlockRngCore` for `ChaChaCore` and `Hc128Core`. (#281) +- All PRNGs are now portable across big- and little-endian architectures. (#209) +- `Isaac64Rng::next_u32` no longer throws away half the results. (#209) +- Add `IsaacRng::new_from_u64` and `Isaac64Rng::new_from_u64`. (#209) +- Add the HC-128 CSPRNG `Hc128Rng`. (#210) +- Change ChaCha20 to have 64-bit counter and 64-bit stream. (#349) +- Changes to `JitterRng` to get its size down from 2112 to 24 bytes. (#251) +- Various performance improvements to all PRNGs. + +### Platform support and `OsRng` +- Add support for CloudABI. (#224) +- Remove support for NaCl. (#225) +- WASM support for `OsRng` via stdweb, behind the `stdweb` feature. (#272, #336) +- Use `getrandom` on more platforms for Linux, and on Android. (#338) +- Use the `SecRandomCopyBytes` interface on macOS. (#322) +- On systems that do not have a syscall interface, only keep a single file descriptor open for `OsRng`. (#239) +- On Unix, first try a single read from `/dev/random`, then `/dev/urandom`. (#338) +- Better error handling and reporting in `OsRng` (using new error type). (#225) +- `OsRng` now uses non-blocking when available. (#225) +- Add `EntropyRng`, which provides `OsRng`, but has `JitterRng` as a fallback. (#235) + +### Distributions +- New `Distribution` trait. (#256) +- Add `Distribution::sample_iter` and `Rng::::sample_iter`. (#361) +- Deprecate `Rand`, `Sample` and `IndependentSample` traits. (#256) +- Add a `Standard` distribution (replaces most `Rand` implementations). (#256) +- Add `Binomial` and `Poisson` distributions. (#96) +- Add `Bernoulli` dsitribution. (#411) +- Add `Alphanumeric` distribution. (#279) +- Remove `Closed01` distribution, add `OpenClosed01`. (#274, #420) +- Rework `Range` type, making it possible to implement it for user types. (#274) +- Rename `Range` to `Uniform`. (#395) +- Add `Uniform::new_inclusive` for inclusive ranges. (#274) +- Use widening multiply method for much faster integer range reduction. (#274) +- `Standard` distribution for `char` uses `Uniform` internally. (#274) +- `Standard` distribution for `bool` uses sign test. (#274) +- Implement `Standard` distribution for `Wrapping<T>`. (#436) +- Implement `Uniform` distribution for `Duration`. (#427) + + +## [0.4.3] - 2018-08-16 +### Fixed +- Use correct syscall number for PowerPC (#589) + + +## [0.4.2] - 2018-01-06 +### Changed +- Use `winapi` on Windows +- Update for Fuchsia OS +- Remove dev-dependency on `log` + + +## [0.4.1] - 2017-12-17 +### Added +- `no_std` support + + +## [0.4.0-pre.0] - 2017-12-11 +### Added +- `JitterRng` added as a high-quality alternative entropy source using the + system timer +- new `seq` module with `sample_iter`, `sample_slice`, etc. +- WASM support via dummy implementations (fail at run-time) +- Additional benchmarks, covering generators and new seq code + +### Changed +- `thread_rng` uses `JitterRng` if seeding from system time fails + (slower but more secure than previous method) + +### Deprecated + - `sample` function deprecated (replaced by `sample_iter`) + + +## [0.3.20] - 2018-01-06 +### Changed +- Remove dev-dependency on `log` +- Update `fuchsia-zircon` dependency to 0.3.2 + + +## [0.3.19] - 2017-12-27 +### Changed +- Require `log <= 0.3.8` for dev builds +- Update `fuchsia-zircon` dependency to 0.3 +- Fix broken links in docs (to unblock compiler docs testing CI) + + +## [0.3.18] - 2017-11-06 +### Changed +- `thread_rng` is seeded from the system time if `OsRng` fails +- `weak_rng` now uses `thread_rng` internally + + +## [0.3.17] - 2017-10-07 +### Changed + - Fuchsia: Magenta was renamed Zircon + +## [0.3.16] - 2017-07-27 +### Added +- Implement Debug for mote non-public types +- implement `Rand` for (i|u)i128 +- Support for Fuchsia + +### Changed +- Add inline attribute to SampleRange::construct_range. + This improves the benchmark for sample in 11% and for shuffle in 16%. +- Use `RtlGenRandom` instead of `CryptGenRandom` + + +## [0.3.15] - 2016-11-26 +### Added +- Add `Rng` trait method `choose_mut` +- Redox support + +### Changed +- Use `arc4rand` for `OsRng` on FreeBSD. +- Use `arc4random(3)` for `OsRng` on OpenBSD. + +### Fixed +- Fix filling buffers 4 GiB or larger with `OsRng::fill_bytes` on Windows + + +## [0.3.14] - 2016-02-13 +### Fixed +- Inline definitions from winapi/advapi32, wich decreases build times + + +## [0.3.13] - 2016-01-09 +### Fixed +- Compatible with Rust 1.7.0-nightly (needed some extra type annotations) + + +## [0.3.12] - 2015-11-09 +### Changed +- Replaced the methods in `next_f32` and `next_f64` with the technique described + Saito & Matsumoto at MCQMC'08. The new method should exhibit a slightly more + uniform distribution. +- Depend on libc 0.2 + +### Fixed +- Fix iterator protocol issue in `rand::sample` + + +## [0.3.11] - 2015-08-31 +### Added +- Implement `Rand` for arrays with n <= 32 + + +## [0.3.10] - 2015-08-17 +### Added +- Support for NaCl platforms + +### Changed +- Allow `Rng` to be `?Sized`, impl for `&mut R` and `Box<R>` where `R: ?Sized + Rng` + + +## [0.3.9] - 2015-06-18 +### Changed +- Use `winapi` for Windows API things + +### Fixed +- Fixed test on stable/nightly +- Fix `getrandom` syscall number for aarch64-unknown-linux-gnu + + +## [0.3.8] - 2015-04-23 +### Changed +- `log` is a dev dependency + +### Fixed +- Fix race condition of atomics in `is_getrandom_available` + + +## [0.3.7] - 2015-04-03 +### Fixed +- Derive Copy/Clone changes + + +## [0.3.6] - 2015-04-02 +### Changed +- Move to stable Rust! + + +## [0.3.5] - 2015-04-01 +### Fixed +- Compatible with Rust master + + +## [0.3.4] - 2015-03-31 +### Added +- Implement Clone for `Weighted` + +### Fixed +- Compatible with Rust master + + +## [0.3.3] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.2] - 2015-03-26 + + +## [0.3.1] - 2015-03-26 +### Fixed +- Fix compile on Windows + + +## [0.3.0] - 2015-03-25 +### Changed +- Update to use log version 0.3.x + + +## [0.2.1] - 2015-03-22 +### Fixed +- Compatible with Rust master +- Fixed iOS compilation + + +## [0.2.0] - 2015-03-06 +### Fixed +- Compatible with Rust master (move from `old_io` to `std::io`) + + +## [0.1.4] - 2015-03-04 +### Fixed +- Compatible with Rust master (use wrapping ops) + + +## [0.1.3] - 2015-02-20 +### Fixed +- Compatible with Rust master + +### Removed +- Removed Copy implementations from RNGs + + +## [0.1.2] - 2015-02-03 +### Added +- Imported functionality from `std::rand`, including: + - `StdRng`, `SeedableRng`, `TreadRng`, `weak_rng()` + - `ReaderRng`: A wrapper around any Reader to treat it as an RNG. +- Imported documentation from `std::rand` +- Imported tests from `std::rand` + + +## [0.1.1] - 2015-02-03 +### Added +- Migrate to a cargo-compatible directory structure. + +### Fixed +- Do not use entropy during `gen_weighted_bool(1)` + + +## [Rust 0.12.0] - 2014-10-09 +### Added +- Impl Rand for tuples of arity 11 and 12 +- Include ChaCha pseudorandom generator +- Add `next_f64` and `next_f32` to Rng +- Implement Clone for PRNGs + +### Changed +- Rename `TaskRng` to `ThreadRng` and `task_rng` to `thread_rng` (since a + runtime is removed from Rust). + +### Fixed +- Improved performance of ISAAC and ISAAC64 by 30% and 12 % respectively, by + informing the optimiser that indexing is never out-of-bounds. + +### Removed +- Removed the Deprecated `choose_option` + + +## [Rust 0.11.0] - 2014-07-02 +### Added +- document when to use `OSRng` in cryptographic context, and explain why we use `/dev/urandom` instead of `/dev/random` +- `Rng::gen_iter()` which will return an infinite stream of random values +- `Rng::gen_ascii_chars()` which will return an infinite stream of random ascii characters + +### Changed +- Now only depends on libcore! +- Remove `Rng.choose()`, rename `Rng.choose_option()` to `.choose()` +- Rename OSRng to OsRng +- The WeightedChoice structure is no longer built with a `Vec<Weighted<T>>`, + but rather a `&mut [Weighted<T>]`. This means that the WeightedChoice + structure now has a lifetime associated with it. +- The `sample` method on `Rng` has been moved to a top-level function in the + `rand` module due to its dependence on `Vec`. + +### Removed +- `Rng::gen_vec()` was removed. Previous behavior can be regained with + `rng.gen_iter().take(n).collect()` +- `Rng::gen_ascii_str()` was removed. Previous behavior can be regained with + `rng.gen_ascii_chars().take(n).collect()` +- {IsaacRng, Isaac64Rng, XorShiftRng}::new() have all been removed. These all + relied on being able to use an OSRng for seeding, but this is no longer + available in librand (where these types are defined). To retain the same + functionality, these types now implement the `Rand` trait so they can be + generated with a random seed from another random number generator. This allows + the stdlib to use an OSRng to create seeded instances of these RNGs. +- Rand implementations for `Box<T>` and `@T` were removed. These seemed to be + pretty rare in the codebase, and it allows for librand to not depend on + liballoc. Additionally, other pointer types like Rc<T> and Arc<T> were not + supported. +- Remove a slew of old deprecated functions + + +## [Rust 0.10] - 2014-04-03 +### Changed +- replace `Rng.shuffle's` functionality with `.shuffle_mut` +- bubble up IO errors when creating an OSRng + +### Fixed +- Use `fill()` instead of `read()` +- Rewrite OsRng in Rust for windows + +## [0.10-pre] - 2014-03-02 +### Added +- Seperate `rand` out of the standard library diff --git a/rand/COPYRIGHT b/rand/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand/Cargo.toml b/rand/Cargo.toml new file mode 100644 index 000000000..fc0313afa --- /dev/null +++ b/rand/Cargo.toml @@ -0,0 +1,90 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand" +version = "0.6.5" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +build = "build.rs" +exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"] +description = "Random number generators and other randomness functionality.\n" +homepage = "https://crates.io/crates/rand" +documentation = "https://rust-random.github.io/rand" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[package.metadata.docs.rs] +all-features = true +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.packed_simd] +version = "0.3" +features = ["into_bits"] +optional = true + +[dependencies.rand_chacha] +version = "0.1" + +[dependencies.rand_core] +version = "0.4" + +[dependencies.rand_hc] +version = "0.1" + +[dependencies.rand_isaac] +version = "0.1" + +[dependencies.rand_jitter] +version = "0.1" + +[dependencies.rand_os] +version = "0.1" +optional = true + +[dependencies.rand_pcg] +version = "0.1" + +[dependencies.rand_xorshift] +version = "0.1" +[dev-dependencies.average] +version = "0.9.2" + +[dev-dependencies.rand_xoshiro] +version = "0.1" +[build-dependencies.autocfg] +version = "0.1" + +[features] +alloc = ["rand_core/alloc"] +default = ["std"] +i128_support = [] +nightly = ["simd_support"] +serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] +simd_support = ["packed_simd"] +std = ["rand_core/std", "alloc", "rand_os", "rand_jitter/std"] +stdweb = ["rand_os/stdweb"] +wasm-bindgen = ["rand_os/wasm-bindgen"] +[target."cfg(unix)".dependencies.libc] +version = "0.2" +default-features = false +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["minwindef", "ntsecapi", "profileapi", "winnt"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand/LICENSE-APACHE b/rand/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand/LICENSE-MIT b/rand/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand/README.md b/rand/README.md new file mode 100644 index 000000000..314a57fd6 --- /dev/null +++ b/rand/README.md @@ -0,0 +1,122 @@ +# Rand + +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand) +[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +A Rust library for random number generation. + +Rand provides utilities to generate random numbers, to convert them to useful +types and distributions, and some randomness-related algorithms. + +The core random number generation traits of Rand live in the [rand_core]( +https://crates.io/crates/rand_core) crate but are also exposed here; RNG +implementations should prefer to use `rand_core` while most other users should +depend on `rand`. + +Documentation: +- [The Rust Rand Book](https://rust-random.github.io/book) +- [API reference (master)](https://rust-random.github.io/rand) +- [API reference (docs.rs)](https://docs.rs/rand) + + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +rand = "0.6" +``` + +To get started using Rand, see [The Book](https://rust-random.github.io/book). + + +## Versions + +The Rand lib is not yet stable, however we are careful to limit breaking changes +and warn via deprecation wherever possible. Patch versions never introduce +breaking changes. The following minor versions are supported: + +- Version 0.6 was released in November 2018, redesigning the `seq` module, + moving most PRNGs to external crates, and many small changes. +- Version 0.5 was released in May 2018, as a major reorganisation + (introducing `RngCore` and `rand_core`, and deprecating `Rand` and the + previous distribution traits). +- Version 0.4 was released in December 2017, but contained almost no breaking + changes from the 0.3 series. + +A detailed [changelog](CHANGELOG.md) is available. + +When upgrading to the next minor series (especially 0.4 → 0.5), we recommend +reading the [Upgrade Guide](https://rust-random.github.io/book/update.html). + +### Rust version requirements + +Since version 0.5, Rand requires **Rustc version 1.22 or greater**. +Rand 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or +greater. Subsets of the Rand code may work with older Rust versions, but this +is not supported. + +Travis CI always has a build with a pinned version of Rustc matching the oldest +supported Rust release. The current policy is that this can be updated in any +Rand release if required, but the change must be noted in the changelog. + +To avoid bumping the required version unnecessarily, we use a `build.rs` script +to auto-detect the compiler version and enable certain features or change code +paths automatically. Since this makes it easy to unintentionally make use of +features requiring a more recent Rust version, we recommend testing with a +pinned version of Rustc if you require compatibility with a specific version. + +## Crate Features + +Rand is built with the `std` and `rand_os` features enabled by default: + +- `std` enables functionality dependent on the `std` lib and implies `alloc` + and `rand_os` +- `rand_os` enables the `rand_os` crate, `rngs::OsRng` and enables its usage; + the continued existance of this feature is not guaranteed so users are + encouraged to specify `std` instead + +The following optional features are available: + +- `alloc` can be used instead of `std` to provide `Vec` and `Box`. +- `log` enables some logging via the `log` crate. +- `nightly` enables all unstable features (`simd_support`). +- `serde1` enables serialization for some types, via Serde version 1. +- `simd_support` enables uniform sampling of SIMD types (integers and floats). +- `stdweb` enables support for `OsRng` on `wasm32-unknown-unknown` via `stdweb` + combined with `cargo-web`. +- `wasm-bindgen` enables support for `OsRng` on `wasm32-unknown-unknown` via + [`wasm-bindgen`] + +[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen + +`no_std` mode is activated by setting `default-features = false`; this removes +functionality depending on `std`: + +- `thread_rng()`, and `random()` are not available, as they require thread-local + storage and an entropy source. +- `OsRng` and `EntropyRng` are unavailable. +- `JitterRng` code is still present, but a nanosecond timer must be provided via + `JitterRng::new_with_timer` +- Since no external entropy is available, it is not possible to create + generators with fresh seeds using the `FromEntropy` trait (user must provide + a seed). +- Several non-linear distributions distributions are unavailable since `exp` + and `log` functions are not provided in `core`. +- Large parts of the `seq`-uence module are unavailable, unless the `alloc` + feature is used (several APIs and many implementations require `Vec`). + + +# License + +Rand is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand/benches/distributions.rs b/rand/benches/distributions.rs new file mode 100644 index 000000000..069a82856 --- /dev/null +++ b/rand/benches/distributions.rs @@ -0,0 +1,259 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; + +use std::mem::size_of; +use test::Bencher; +use std::time::Duration; + +use rand::{Rng, FromEntropy}; +use rand::rngs::SmallRng; +use rand::distributions::*; + +macro_rules! distr_int { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0 as $ty; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_float { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum += x; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_duration { + ($fnn:ident, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = Duration::new(0, 0); + for _ in 0..::RAND_BENCH_N { + let x: Duration = distr.sample(&mut rng); + accum = accum.checked_add(x).unwrap_or(Duration::new(u64::max_value(), 999_999_999)); + } + accum + }); + b.bytes = size_of::<Duration>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0u32; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x as u32); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +macro_rules! distr_arr { + ($fnn:ident, $ty:ty, $distr:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = $distr; + + b.iter(|| { + let mut accum = 0u32; + for _ in 0..::RAND_BENCH_N { + let x: $ty = distr.sample(&mut rng); + accum = accum.wrapping_add(x[0] as u32); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +// uniform +distr_int!(distr_uniform_i8, i8, Uniform::new(20i8, 100)); +distr_int!(distr_uniform_i16, i16, Uniform::new(-500i16, 2000)); +distr_int!(distr_uniform_i32, i32, Uniform::new(-200_000_000i32, 800_000_000)); +distr_int!(distr_uniform_i64, i64, Uniform::new(3i64, 123_456_789_123)); +distr_int!(distr_uniform_i128, i128, Uniform::new(-123_456_789_123i128, 123_456_789_123_456_789)); + +distr_float!(distr_uniform_f32, f32, Uniform::new(2.26f32, 2.319)); +distr_float!(distr_uniform_f64, f64, Uniform::new(2.26f64, 2.319)); + +const LARGE_SEC: u64 = u64::max_value() / 1000; + +distr_duration!(distr_uniform_duration_largest, + Uniform::new_inclusive(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999)) +); +distr_duration!(distr_uniform_duration_large, + Uniform::new(Duration::new(0, 0), Duration::new(LARGE_SEC, 1_000_000_000 / 2)) +); +distr_duration!(distr_uniform_duration_one, + Uniform::new(Duration::new(0, 0), Duration::new(1, 0)) +); +distr_duration!(distr_uniform_duration_variety, + Uniform::new(Duration::new(10000, 423423), Duration::new(200000, 6969954)) +); +distr_duration!(distr_uniform_duration_edge, + Uniform::new_inclusive(Duration::new(LARGE_SEC, 999_999_999), Duration::new(LARGE_SEC + 1, 1)) +); + + +// standard +distr_int!(distr_standard_i8, i8, Standard); +distr_int!(distr_standard_i16, i16, Standard); +distr_int!(distr_standard_i32, i32, Standard); +distr_int!(distr_standard_i64, i64, Standard); +distr_int!(distr_standard_i128, i128, Standard); + +distr!(distr_standard_bool, bool, Standard); +distr!(distr_standard_alphanumeric, char, Alphanumeric); +distr!(distr_standard_codepoint, char, Standard); + +distr_float!(distr_standard_f32, f32, Standard); +distr_float!(distr_standard_f64, f64, Standard); +distr_float!(distr_open01_f32, f32, Open01); +distr_float!(distr_open01_f64, f64, Open01); +distr_float!(distr_openclosed01_f32, f32, OpenClosed01); +distr_float!(distr_openclosed01_f64, f64, OpenClosed01); + +// distributions +distr_float!(distr_exp, f64, Exp::new(1.23 * 4.56)); +distr_float!(distr_normal, f64, Normal::new(-1.23, 4.56)); +distr_float!(distr_log_normal, f64, LogNormal::new(-1.23, 4.56)); +distr_float!(distr_gamma_large_shape, f64, Gamma::new(10., 1.0)); +distr_float!(distr_gamma_small_shape, f64, Gamma::new(0.1, 1.0)); +distr_float!(distr_cauchy, f64, Cauchy::new(4.2, 6.9)); +distr_int!(distr_binomial, u64, Binomial::new(20, 0.7)); +distr_int!(distr_poisson, u64, Poisson::new(4.0)); +distr!(distr_bernoulli, bool, Bernoulli::new(0.18)); +distr_arr!(distr_circle, [f64; 2], UnitCircle::new()); +distr_arr!(distr_sphere_surface, [f64; 3], UnitSphereSurface::new()); + +// Weighted +distr_int!(distr_weighted_i8, usize, WeightedIndex::new(&[1i8, 2, 3, 4, 12, 0, 2, 1]).unwrap()); +distr_int!(distr_weighted_u32, usize, WeightedIndex::new(&[1u32, 2, 3, 4, 12, 0, 2, 1]).unwrap()); +distr_int!(distr_weighted_f64, usize, WeightedIndex::new(&[1.0f64, 0.001, 1.0/3.0, 4.01, 0.0, 3.3, 22.0, 0.001]).unwrap()); +distr_int!(distr_weighted_large_set, usize, WeightedIndex::new((0..10000).rev().chain(1..10001)).unwrap()); + +// construct and sample from a range +macro_rules! gen_range_int { + ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + + b.iter(|| { + let mut high = $high; + let mut accum: $ty = 0; + for _ in 0..::RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen_range($low, high)); + // force recalculation of range each time + high = high.wrapping_add(1) & std::$ty::MAX; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +gen_range_int!(gen_range_i8, i8, -20i8, 100); +gen_range_int!(gen_range_i16, i16, -500i16, 2000); +gen_range_int!(gen_range_i32, i32, -200_000_000i32, 800_000_000); +gen_range_int!(gen_range_i64, i64, 3i64, 123_456_789_123); +gen_range_int!(gen_range_i128, i128, -12345678901234i128, 123_456_789_123_456_789); + +// construct and sample from a floating-point range +macro_rules! gen_range_float { + ($fnn:ident, $ty:ident, $low:expr, $high:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + + b.iter(|| { + let mut high = $high; + let mut low = $low; + let mut accum: $ty = 0.0; + for _ in 0..::RAND_BENCH_N { + accum += rng.gen_range(low, high); + // force recalculation of range each time + low += 0.9; + high += 1.1; + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * ::RAND_BENCH_N; + } + } +} + +gen_range_float!(gen_range_f32, f32, -20000.0f32, 100000.0); +gen_range_float!(gen_range_f64, f64, 123.456f64, 7890.12); + +#[bench] +fn dist_iter(b: &mut Bencher) { + let mut rng = SmallRng::from_entropy(); + let distr = Normal::new(-2.71828, 3.14159); + let mut iter = distr.sample_iter(&mut rng); + + b.iter(|| { + let mut accum = 0.0; + for _ in 0..::RAND_BENCH_N { + accum += iter.next().unwrap(); + } + accum + }); + b.bytes = size_of::<f64>() as u64 * ::RAND_BENCH_N; +} diff --git a/rand/benches/generators.rs b/rand/benches/generators.rs new file mode 100644 index 000000000..a6e3a4232 --- /dev/null +++ b/rand/benches/generators.rs @@ -0,0 +1,240 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; +extern crate rand; +extern crate rand_isaac; +extern crate rand_chacha; +extern crate rand_hc; +extern crate rand_pcg; +extern crate rand_xorshift; +extern crate rand_xoshiro; + +const RAND_BENCH_N: u64 = 1000; +const BYTES_LEN: usize = 1024; + +use std::mem::size_of; +use test::{black_box, Bencher}; + +use rand::prelude::*; +use rand::rngs::adapter::ReseedingRng; +use rand::rngs::{OsRng, JitterRng, EntropyRng}; +use rand_isaac::{IsaacRng, Isaac64Rng}; +use rand_chacha::ChaChaRng; +use rand_hc::{Hc128Rng, Hc128Core}; +use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64}; +use rand_xorshift::XorShiftRng; +use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar, + Xoshiro128Plus, Xoroshiro128StarStar, Xoroshiro128Plus, SplitMix64, + Xoroshiro64StarStar, Xoroshiro64Star}; + +macro_rules! gen_bytes { + ($fnn:ident, $gen:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen; + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; + } + } +} + +gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy()); +gen_bytes!(gen_bytes_xoshiro256starstar, Xoshiro256StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoshiro256plus, Xoshiro256Plus::from_entropy()); +gen_bytes!(gen_bytes_xoshiro128starstar, Xoshiro128StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoshiro128plus, Xoshiro128Plus::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro128starstar, Xoroshiro128StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro128plus, Xoroshiro128Plus::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro64starstar, Xoroshiro64StarStar::from_entropy()); +gen_bytes!(gen_bytes_xoroshiro64star, Xoroshiro64Star::from_entropy()); +gen_bytes!(gen_bytes_splitmix64, SplitMix64::from_entropy()); +gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy()); +gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy()); +gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy()); +gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy()); +gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy()); +gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy()); +gen_bytes!(gen_bytes_std, StdRng::from_entropy()); +gen_bytes!(gen_bytes_small, SmallRng::from_entropy()); +gen_bytes!(gen_bytes_os, OsRng::new().unwrap()); + +macro_rules! gen_uint { + ($fnn:ident, $ty:ty, $gen:expr) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = $gen; + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy()); +gen_uint!(gen_u32_xoshiro256starstar, u32, Xoshiro256StarStar::from_entropy()); +gen_uint!(gen_u32_xoshiro256plus, u32, Xoshiro256Plus::from_entropy()); +gen_uint!(gen_u32_xoshiro128starstar, u32, Xoshiro128StarStar::from_entropy()); +gen_uint!(gen_u32_xoshiro128plus, u32, Xoshiro128Plus::from_entropy()); +gen_uint!(gen_u32_xoroshiro128starstar, u32, Xoroshiro128StarStar::from_entropy()); +gen_uint!(gen_u32_xoroshiro128plus, u32, Xoroshiro128Plus::from_entropy()); +gen_uint!(gen_u32_xoroshiro64starstar, u32, Xoroshiro64StarStar::from_entropy()); +gen_uint!(gen_u32_xoroshiro64star, u32, Xoroshiro64Star::from_entropy()); +gen_uint!(gen_u32_splitmix64, u32, SplitMix64::from_entropy()); +gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy()); +gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy()); +gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy()); +gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy()); +gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy()); +gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy()); +gen_uint!(gen_u32_std, u32, StdRng::from_entropy()); +gen_uint!(gen_u32_small, u32, SmallRng::from_entropy()); +gen_uint!(gen_u32_os, u32, OsRng::new().unwrap()); + +gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy()); +gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy()); +gen_uint!(gen_u64_xoshiro256plus, u64, Xoshiro256Plus::from_entropy()); +gen_uint!(gen_u64_xoshiro128starstar, u64, Xoshiro128StarStar::from_entropy()); +gen_uint!(gen_u64_xoshiro128plus, u64, Xoshiro128Plus::from_entropy()); +gen_uint!(gen_u64_xoroshiro128starstar, u64, Xoroshiro128StarStar::from_entropy()); +gen_uint!(gen_u64_xoroshiro128plus, u64, Xoroshiro128Plus::from_entropy()); +gen_uint!(gen_u64_xoroshiro64starstar, u64, Xoroshiro64StarStar::from_entropy()); +gen_uint!(gen_u64_xoroshiro64star, u64, Xoroshiro64Star::from_entropy()); +gen_uint!(gen_u64_splitmix64, u64, SplitMix64::from_entropy()); +gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy()); +gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy()); +gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy()); +gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy()); +gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy()); +gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy()); +gen_uint!(gen_u64_std, u64, StdRng::from_entropy()); +gen_uint!(gen_u64_small, u64, SmallRng::from_entropy()); +gen_uint!(gen_u64_os, u64, OsRng::new().unwrap()); + +// Do not test JitterRng like the others by running it RAND_BENCH_N times per, +// measurement, because it is way too slow. Only run it once. +#[bench] +fn gen_u64_jitter(b: &mut Bencher) { + let mut rng = JitterRng::new().unwrap(); + b.iter(|| { + rng.gen::<u64>() + }); + b.bytes = size_of::<u64>() as u64; +} + +macro_rules! init_gen { + ($fnn:ident, $gen:ident) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = XorShiftRng::from_entropy(); + b.iter(|| { + let r2 = $gen::from_rng(&mut rng).unwrap(); + r2 + }); + } + } +} + +init_gen!(init_xorshift, XorShiftRng); +init_gen!(init_xoshiro256starstar, Xoshiro256StarStar); +init_gen!(init_xoshiro256plus, Xoshiro256Plus); +init_gen!(init_xoshiro128starstar, Xoshiro128StarStar); +init_gen!(init_xoshiro128plus, Xoshiro128Plus); +init_gen!(init_xoroshiro128starstar, Xoroshiro128StarStar); +init_gen!(init_xoroshiro128plus, Xoroshiro128Plus); +init_gen!(init_xoroshiro64starstar, Xoroshiro64StarStar); +init_gen!(init_xoroshiro64star, Xoroshiro64Star); +init_gen!(init_splitmix64, SplitMix64); +init_gen!(init_lcg64_xsh32, Lcg64Xsh32); +init_gen!(init_mcg128_xsh64, Mcg128Xsl64); +init_gen!(init_hc128, Hc128Rng); +init_gen!(init_isaac, IsaacRng); +init_gen!(init_isaac64, Isaac64Rng); +init_gen!(init_chacha, ChaChaRng); + +#[bench] +fn init_jitter(b: &mut Bencher) { + b.iter(|| { + JitterRng::new().unwrap() + }); +} + + +const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get + // deterministic measurements + +#[bench] +fn reseeding_hc128_bytes(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + let mut buf = [0u8; BYTES_LEN]; + b.iter(|| { + for _ in 0..RAND_BENCH_N { + rng.fill_bytes(&mut buf); + black_box(buf); + } + }); + b.bytes = BYTES_LEN as u64 * RAND_BENCH_N; +} + +macro_rules! reseeding_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = ReseedingRng::new(Hc128Core::from_entropy(), + RESEEDING_THRESHOLD, + EntropyRng::new()); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +reseeding_uint!(reseeding_hc128_u32, u32); +reseeding_uint!(reseeding_hc128_u64, u64); + + +macro_rules! threadrng_uint { + ($fnn:ident, $ty:ty) => { + #[bench] + fn $fnn(b: &mut Bencher) { + let mut rng = thread_rng(); + b.iter(|| { + let mut accum: $ty = 0; + for _ in 0..RAND_BENCH_N { + accum = accum.wrapping_add(rng.gen::<$ty>()); + } + accum + }); + b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N; + } + } +} + +threadrng_uint!(thread_rng_u32, u32); +threadrng_uint!(thread_rng_u64, u64); diff --git a/rand/benches/misc.rs b/rand/benches/misc.rs new file mode 100644 index 000000000..8fb3a832f --- /dev/null +++ b/rand/benches/misc.rs @@ -0,0 +1,160 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate test; +extern crate rand; + +const RAND_BENCH_N: u64 = 1000; + +use test::Bencher; + +use rand::prelude::*; + +#[bench] +fn misc_gen_bool_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(0.18); + } + accum + }) +} + +#[bench] +fn misc_gen_bool_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_bool(p); + p += 0.0001; + } + accum + }) +} + +#[bench] +fn misc_gen_ratio_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.gen_ratio(2, 3); + } + accum + }) +} + +#[bench] +fn misc_gen_ratio_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + for i in 2..(::RAND_BENCH_N as u32 + 2) { + accum ^= rng.gen_ratio(i, i + 1); + } + accum + }) +} + +#[bench] +fn misc_bernoulli_const(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let d = rand::distributions::Bernoulli::new(0.18); + let mut accum = true; + for _ in 0..::RAND_BENCH_N { + accum ^= rng.sample(d); + } + accum + }) +} + +#[bench] +fn misc_bernoulli_var(b: &mut Bencher) { + let mut rng = StdRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let mut accum = true; + let mut p = 0.18; + for _ in 0..::RAND_BENCH_N { + let d = rand::distributions::Bernoulli::new(p); + accum ^= rng.sample(d); + p += 0.0001; + } + accum + }) +} + +macro_rules! sample_binomial { + ($name:ident, $n:expr, $p:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let (n, p) = ($n, $p); + b.iter(|| { + let d = rand::distributions::Binomial::new(n, p); + rng.sample(d) + }) + } + } +} + +sample_binomial!(misc_binomial_1, 1, 0.9); +sample_binomial!(misc_binomial_10, 10, 0.9); +sample_binomial!(misc_binomial_100, 100, 0.99); +sample_binomial!(misc_binomial_1000, 1000, 0.01); +sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); + +#[bench] +fn gen_1k_iter_repeat(b: &mut Bencher) { + use std::iter; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_sample_iter(b: &mut Bencher) { + use rand::distributions::{Distribution, Standard}; + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_gen_array(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + b.iter(|| { + // max supported array length is 32! + let v: [[u64; 32]; 4] = rng.gen(); + v + }); + b.bytes = 1024; +} + +#[bench] +fn gen_1k_fill(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut buf = [0u64; 128]; + b.iter(|| { + rng.fill(&mut buf[..]); + buf + }); + b.bytes = 1024; +} diff --git a/rand/benches/seq.rs b/rand/benches/seq.rs new file mode 100644 index 000000000..0ca3398f2 --- /dev/null +++ b/rand/benches/seq.rs @@ -0,0 +1,174 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] +#![allow(non_snake_case)] + +extern crate test; +extern crate rand; + +use test::Bencher; + +use rand::prelude::*; +use rand::seq::*; +use std::mem::size_of; + +const RAND_BENCH_N: u64 = 1000; + +#[bench] +fn seq_shuffle_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 100]; + b.iter(|| { + x.shuffle(&mut rng); + x[0] + }) +} + +#[bench] +fn seq_slice_choose_1_of_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 1000]; + for i in 0..1000 { + x[i] = i; + } + b.iter(|| { + let mut s = 0; + for _ in 0..RAND_BENCH_N { + s += x.choose(&mut rng).unwrap(); + } + s + }); + b.bytes = size_of::<usize>() as u64 * ::RAND_BENCH_N; +} + +macro_rules! seq_slice_choose_multiple { + ($name:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[i32] = &[$amount; $length]; + let mut result = [0i32; $amount]; + b.iter(|| { + // Collect full result to prevent unwanted shortcuts getting + // first element (in case sample_indices returns an iterator). + for (slot, sample) in result.iter_mut().zip( + x.choose_multiple(&mut rng, $amount)) { + *slot = *sample; + } + result[$amount-1] + }) + } + } +} + +seq_slice_choose_multiple!(seq_slice_choose_multiple_1_of_1000, 1, 1000); +seq_slice_choose_multiple!(seq_slice_choose_multiple_950_of_1000, 950, 1000); +seq_slice_choose_multiple!(seq_slice_choose_multiple_10_of_100, 10, 100); +seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100); + +#[bench] +fn seq_iter_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &mut [usize] = &mut [1; 1000]; + for i in 0..1000 { + x[i] = i; + } + b.iter(|| { + let mut s = 0; + for _ in 0..RAND_BENCH_N { + s += x.iter().choose(&mut rng).unwrap(); + } + s + }); + b.bytes = size_of::<usize>() as u64 * ::RAND_BENCH_N; +} + +#[derive(Clone)] +struct UnhintedIterator<I: Iterator + Clone> { + iter: I, +} +impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} + +#[derive(Clone)] +struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> { + iter: I, + window_size: usize, +} +impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + (std::cmp::min(self.iter.len(), self.window_size), None) + } +} + +#[bench] +fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 1000]; + b.iter(|| { + UnhintedIterator { iter: x.iter() }.choose(&mut rng).unwrap() + }) +} + +#[bench] +fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 1000]; + b.iter(|| { + WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng) + }) +} + +#[bench] +fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + b.iter(|| { + x.iter().cloned().choose_multiple(&mut rng, 10) + }) +} + +#[bench] +fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + let x : &[usize] = &[1; 100]; + let mut buf = [0; 10]; + b.iter(|| { + x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf) + }) +} + +macro_rules! sample_indices { + ($name:ident, $fn:ident, $amount:expr, $length:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); + b.iter(|| { + index::$fn(&mut rng, $length, $amount) + }) + } + } +} + +sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000); +sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000); +sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000); +sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000); +sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000); +sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000); +sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000); +sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000); diff --git a/rand/build.rs b/rand/build.rs new file mode 100644 index 000000000..a554ad987 --- /dev/null +++ b/rand/build.rs @@ -0,0 +1,10 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let ac = autocfg::new(); + ac.emit_rustc_version(1, 25); + ac.emit_rustc_version(1, 26); + ac.emit_rustc_version(1, 27); +} diff --git a/rand/examples/monte-carlo.rs b/rand/examples/monte-carlo.rs new file mode 100644 index 000000000..916299686 --- /dev/null +++ b/rand/examples/monte-carlo.rs @@ -0,0 +1,51 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Monte Carlo estimation of π +//! +//! Imagine that we have a square with sides of length 2 and a unit circle +//! (radius = 1), both centered at the origin. The areas are: +//! +//! ```text +//! area of circle = πr² = π * r * r = π +//! area of square = 2² = 4 +//! ``` +//! +//! The circle is entirely within the square, so if we sample many points +//! randomly from the square, roughly π / 4 of them should be inside the circle. +//! +//! We can use the above fact to estimate the value of π: pick many points in +//! the square at random, calculate the fraction that fall within the circle, +//! and multiply this fraction by 4. + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::distributions::{Distribution, Uniform}; + +fn main() { + let range = Uniform::new(-1.0f64, 1.0); + let mut rng = rand::thread_rng(); + + let total = 1_000_000; + let mut in_circle = 0; + + for _ in 0..total { + let a = range.sample(&mut rng); + let b = range.sample(&mut rng); + if a*a + b*b <= 1.0 { + in_circle += 1; + } + } + + // prints something close to 3.14159... + println!("π is approximately {}", 4. * (in_circle as f64) / (total as f64)); +} diff --git a/rand/examples/monty-hall.rs b/rand/examples/monty-hall.rs new file mode 100644 index 000000000..0932c5efb --- /dev/null +++ b/rand/examples/monty-hall.rs @@ -0,0 +1,116 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ## Monty Hall Problem +//! +//! This is a simulation of the [Monty Hall Problem][]: +//! +//! > Suppose you're on a game show, and you're given the choice of three doors: +//! > Behind one door is a car; behind the others, goats. You pick a door, say +//! > No. 1, and the host, who knows what's behind the doors, opens another +//! > door, say No. 3, which has a goat. He then says to you, "Do you want to +//! > pick door No. 2?" Is it to your advantage to switch your choice? +//! +//! The rather unintuitive answer is that you will have a 2/3 chance of winning +//! if you switch and a 1/3 chance of winning if you don't, so it's better to +//! switch. +//! +//! This program will simulate the game show and with large enough simulation +//! steps it will indeed confirm that it is better to switch. +//! +//! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem + +#![cfg(feature="std")] + + +extern crate rand; + +use rand::Rng; +use rand::distributions::{Distribution, Uniform}; + +struct SimulationResult { + win: bool, + switch: bool, +} + +// Run a single simulation of the Monty Hall problem. +fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R) + -> SimulationResult { + let car = random_door.sample(rng); + + // This is our initial choice + let mut choice = random_door.sample(rng); + + // The game host opens a door + let open = game_host_open(car, choice, rng); + + // Shall we switch? + let switch = rng.gen(); + if switch { + choice = switch_door(choice, open); + } + + SimulationResult { win: choice == car, switch } +} + +// Returns the door the game host opens given our choice and knowledge of +// where the car is. The game host will never open the door with the car. +fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 { + use rand::seq::SliceRandom; + *free_doors(&[car, choice]).choose(rng).unwrap() +} + +// Returns the door we switch to, given our current choice and +// the open door. There will only be one valid door. +fn switch_door(choice: u32, open: u32) -> u32 { + free_doors(&[choice, open])[0] +} + +fn free_doors(blocked: &[u32]) -> Vec<u32> { + (0..3).filter(|x| !blocked.contains(x)).collect() +} + +fn main() { + // The estimation will be more accurate with more simulations + let num_simulations = 10000; + + let mut rng = rand::thread_rng(); + let random_door = Uniform::new(0u32, 3); + + let (mut switch_wins, mut switch_losses) = (0, 0); + let (mut keep_wins, mut keep_losses) = (0, 0); + + println!("Running {} simulations...", num_simulations); + for _ in 0..num_simulations { + let result = simulate(&random_door, &mut rng); + + match (result.win, result.switch) { + (true, true) => switch_wins += 1, + (true, false) => keep_wins += 1, + (false, true) => switch_losses += 1, + (false, false) => keep_losses += 1, + } + } + + let total_switches = switch_wins + switch_losses; + let total_keeps = keep_wins + keep_losses; + + println!("Switched door {} times with {} wins and {} losses", + total_switches, switch_wins, switch_losses); + + println!("Kept our choice {} times with {} wins and {} losses", + total_keeps, keep_wins, keep_losses); + + // With a large number of simulations, the values should converge to + // 0.667 and 0.333 respectively. + println!("Estimated chance to win if we switch: {}", + switch_wins as f32 / total_switches as f32); + println!("Estimated chance to win if we don't: {}", + keep_wins as f32 / total_keeps as f32); +} diff --git a/rand/src/deprecated.rs b/rand/src/deprecated.rs new file mode 100644 index 000000000..88eb09fce --- /dev/null +++ b/rand/src/deprecated.rs @@ -0,0 +1,544 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Deprecated re-exports (we can't add deprecation warnings otherwise) + +#![allow(deprecated)] + +use rngs; +use {RngCore, CryptoRng, SeedableRng, Error}; +use rand_core::block::BlockRngCore; +use rand_isaac; +use rand_chacha; +use rand_hc; + +#[cfg(feature="std")] +use std::io::Read; + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import from rand_isaac crate instead, or use the newer Hc128Rng")] +pub struct IsaacRng(rand_isaac::IsaacRng); + +impl RngCore for IsaacRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for IsaacRng { + type Seed = <rand_isaac::IsaacRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacRng(rand_isaac::IsaacRng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + rand_isaac::IsaacRng::from_rng(rng).map(IsaacRng) + } +} + +impl IsaacRng { + pub fn new_from_u64(seed: u64) -> Self { + IsaacRng(rand_isaac::IsaacRng::new_from_u64(seed)) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import from rand_isaac crate instead, or use newer Hc128Rng")] +pub struct Isaac64Rng(rand_isaac::Isaac64Rng); + +impl RngCore for Isaac64Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Isaac64Rng { + type Seed = <rand_isaac::Isaac64Rng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Isaac64Rng(rand_isaac::Isaac64Rng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + rand_isaac::Isaac64Rng::from_rng(rng).map(Isaac64Rng) + } +} + +impl Isaac64Rng { + pub fn new_from_u64(seed: u64) -> Self { + Isaac64Rng(rand_isaac::Isaac64Rng::new_from_u64(seed)) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_chacha crate instead")] +pub struct ChaChaRng(rand_chacha::ChaChaRng); + +impl RngCore for ChaChaRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for ChaChaRng { + type Seed = <rand_chacha::ChaChaRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + ChaChaRng(rand_chacha::ChaChaRng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + rand_chacha::ChaChaRng::from_rng(rng).map(ChaChaRng) + } +} + +impl ChaChaRng { + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn get_word_pos(&self) -> u128 { + self.0.get_word_pos() + } + + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn set_word_pos(&mut self, word_offset: u128) { + self.0.set_word_pos(word_offset) + } + + pub fn set_stream(&mut self, stream: u64) { + self.0.set_stream(stream) + } +} + +impl CryptoRng for ChaChaRng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_hc crate instead")] +pub struct Hc128Rng(rand_hc::Hc128Rng); + +impl RngCore for Hc128Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Hc128Rng { + type Seed = <rand_hc::Hc128Rng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Hc128Rng(rand_hc::Hc128Rng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + rand_hc::Hc128Rng::from_rng(rng).map(Hc128Rng) + } +} + +impl CryptoRng for Hc128Rng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import from rand_xorshift crate instead")] +pub struct XorShiftRng(::rand_xorshift::XorShiftRng); + +impl RngCore for XorShiftRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for XorShiftRng { + type Seed = <::rand_xorshift::XorShiftRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + XorShiftRng(::rand_xorshift::XorShiftRng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + ::rand_xorshift::XorShiftRng::from_rng(rng).map(XorShiftRng) + } +} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import with rand::prelude::* or rand::rngs::StdRng instead")] +pub struct StdRng(rngs::StdRng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = <rngs::StdRng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(rngs::StdRng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + rngs::StdRng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(feature="rand_os")] +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::OsRng instead")] +pub struct OsRng(rngs::OsRng); + +#[cfg(feature="rand_os")] +impl RngCore for OsRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="rand_os")] +impl OsRng { + pub fn new() -> Result<Self, Error> { + rngs::OsRng::new().map(OsRng) + } +} + +#[cfg(feature="rand_os")] +impl CryptoRng for OsRng {} + + +#[cfg(feature="std")] +#[derive(Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::EntropyRng instead")] +pub struct EntropyRng(rngs::EntropyRng); + +#[cfg(feature="std")] +impl RngCore for EntropyRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl EntropyRng { + pub fn new() -> Self { + EntropyRng(rngs::EntropyRng::new()) + } +} + +#[cfg(feature="std")] +impl Default for EntropyRng { + fn default() -> Self { + EntropyRng::new() + } +} + +#[cfg(feature="std")] +impl CryptoRng for EntropyRng {} + + +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::JitterRng instead")] +pub struct JitterRng(rngs::JitterRng); + +impl RngCore for JitterRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl JitterRng { + #[cfg(all(feature="std", not(target_arch = "wasm32")))] + pub fn new() -> Result<JitterRng, rngs::TimerError> { + rngs::JitterRng::new().map(JitterRng) + } + + pub fn new_with_timer(timer: fn() -> u64) -> JitterRng { + JitterRng(rngs::JitterRng::new_with_timer(timer)) + } + + pub fn set_rounds(&mut self, rounds: u8) { + self.0.set_rounds(rounds) + } + + pub fn test_timer(&mut self) -> Result<u8, rngs::TimerError> { + self.0.test_timer() + } + + #[cfg(feature="std")] + pub fn timer_stats(&mut self, var_rounds: bool) -> i64 { + self.0.timer_stats(var_rounds) + } +} + +impl CryptoRng for JitterRng {} + + +#[cfg(feature="std")] +#[derive(Clone, Debug)] +#[deprecated(since="0.6.0", + note="import with rand::prelude::* or rand::rngs::ThreadRng instead")] +pub struct ThreadRng(rngs::ThreadRng); + +#[cfg(feature="std")] +impl RngCore for ThreadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl CryptoRng for ThreadRng {} + + +#[cfg(feature="std")] +#[derive(Debug)] +#[deprecated(since="0.6.0", note="import with rand::rngs::adapter::ReadRng instead")] +pub struct ReadRng<R>(rngs::adapter::ReadRng<R>); + +#[cfg(feature="std")] +impl<R: Read> RngCore for ReadRng<R> { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl<R: Read> ReadRng<R> { + pub fn new(r: R) -> ReadRng<R> { + ReadRng(rngs::adapter::ReadRng::new(r)) + } +} + + +#[derive(Clone, Debug)] +pub struct ReseedingRng<R, Rsdr>(rngs::adapter::ReseedingRng<R, Rsdr>) +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore; + +impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr> +where R: BlockRngCore<Item = u32> + SeedableRng, + <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl<R, Rsdr> ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + ReseedingRng(rngs::adapter::ReseedingRng::new(rng, threshold, reseeder)) + } + + pub fn reseed(&mut self) -> Result<(), Error> { + self.0.reseed() + } +} + +impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} diff --git a/rand/src/distributions/bernoulli.rs b/rand/src/distributions/bernoulli.rs new file mode 100644 index 000000000..f49618c67 --- /dev/null +++ b/rand/src/distributions/bernoulli.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Bernoulli distribution. + +use Rng; +use distributions::Distribution; + +/// The Bernoulli distribution. +/// +/// This is a special case of the Binomial distribution where `n = 1`. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Bernoulli, Distribution}; +/// +/// let d = Bernoulli::new(0.3); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a Bernoulli distribution", v); +/// ``` +/// +/// # Precision +/// +/// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`), +/// so only probabilities that are multiples of 2<sup>-64</sup> can be +/// represented. +#[derive(Clone, Copy, Debug)] +pub struct Bernoulli { + /// Probability of success, relative to the maximal integer. + p_int: u64, +} + +// To sample from the Bernoulli distribution we use a method that compares a +// random `u64` value `v < (p * 2^64)`. +// +// If `p == 1.0`, the integer `v` to compare against can not represented as a +// `u64`. We manually set it to `u64::MAX` instead (2^64 - 1 instead of 2^64). +// Note that value of `p < 1.0` can never result in `u64::MAX`, because an +// `f64` only has 53 bits of precision, and the next largest value of `p` will +// result in `2^64 - 2048`. +// +// Also there is a 100% theoretical concern: if someone consistenly wants to +// generate `true` using the Bernoulli distribution (i.e. by using a probability +// of `1.0`), just using `u64::MAX` is not enough. On average it would return +// false once every 2^64 iterations. Some people apparently care about this +// case. +// +// That is why we special-case `u64::MAX` to always return `true`, without using +// the RNG, and pay the performance price for all uses that *are* reasonable. +// Luckily, if `new()` and `sample` are close, the compiler can optimize out the +// extra check. +const ALWAYS_TRUE: u64 = ::core::u64::MAX; + +// This is just `2.0.powi(64)`, but written this way because it is not available +// in `no_std` mode. +const SCALE: f64 = 2.0 * (1u64 << 63) as f64; + +impl Bernoulli { + /// Construct a new `Bernoulli` with the given probability of success `p`. + /// + /// # Panics + /// + /// If `p < 0` or `p > 1`. + /// + /// # Precision + /// + /// For `p = 1.0`, the resulting distribution will always generate true. + /// For `p = 0.0`, the resulting distribution will always generate false. + /// + /// This method is accurate for any input `p` in the range `[0, 1]` which is + /// a multiple of 2<sup>-64</sup>. (Note that not all multiples of + /// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.) + #[inline] + pub fn new(p: f64) -> Bernoulli { + if p < 0.0 || p >= 1.0 { + if p == 1.0 { return Bernoulli { p_int: ALWAYS_TRUE } } + panic!("Bernoulli::new not called with 0.0 <= p <= 1.0"); + } + Bernoulli { p_int: (p * SCALE) as u64 } + } + + /// Construct a new `Bernoulli` with the probability of success of + /// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return + /// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`. + /// + /// If `numerator == denominator` then the returned `Bernoulli` will always + /// return `true`. If `numerator == 0` it will always return `false`. + /// + /// # Panics + /// + /// If `denominator == 0` or `numerator > denominator`. + /// + #[inline] + pub fn from_ratio(numerator: u32, denominator: u32) -> Bernoulli { + assert!(numerator <= denominator); + if numerator == denominator { + return Bernoulli { p_int: ::core::u64::MAX } + } + let p_int = ((numerator as f64 / denominator as f64) * SCALE) as u64; + Bernoulli { p_int } + } +} + +impl Distribution<bool> for Bernoulli { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { + // Make sure to always return true for p = 1.0. + if self.p_int == ALWAYS_TRUE { return true; } + let v: u64 = rng.gen(); + v < self.p_int + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Bernoulli; + + #[test] + fn test_trivial() { + let mut r = ::test::rng(1); + let always_false = Bernoulli::new(0.0); + let always_true = Bernoulli::new(1.0); + for _ in 0..5 { + assert_eq!(r.sample::<bool, _>(&always_false), false); + assert_eq!(r.sample::<bool, _>(&always_true), true); + assert_eq!(Distribution::<bool>::sample(&always_false, &mut r), false); + assert_eq!(Distribution::<bool>::sample(&always_true, &mut r), true); + } + } + + #[test] + fn test_average() { + const P: f64 = 0.3; + const NUM: u32 = 3; + const DENOM: u32 = 10; + let d1 = Bernoulli::new(P); + let d2 = Bernoulli::from_ratio(NUM, DENOM); + const N: u32 = 100_000; + + let mut sum1: u32 = 0; + let mut sum2: u32 = 0; + let mut rng = ::test::rng(2); + for _ in 0..N { + if d1.sample(&mut rng) { + sum1 += 1; + } + if d2.sample(&mut rng) { + sum2 += 1; + } + } + let avg1 = (sum1 as f64) / (N as f64); + assert!((avg1 - P).abs() < 5e-3); + + let avg2 = (sum2 as f64) / (N as f64); + assert!((avg2 - (NUM as f64)/(DENOM as f64)).abs() < 5e-3); + } +} diff --git a/rand/src/distributions/binomial.rs b/rand/src/distributions/binomial.rs new file mode 100644 index 000000000..2df393e53 --- /dev/null +++ b/rand/src/distributions/binomial.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The binomial distribution. + +use Rng; +use distributions::{Distribution, Bernoulli, Cauchy}; +use distributions::utils::log_gamma; + +/// The binomial distribution `Binomial(n, p)`. +/// +/// This distribution has density function: +/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Binomial, Distribution}; +/// +/// let bin = Binomial::new(20, 0.3); +/// let v = bin.sample(&mut rand::thread_rng()); +/// println!("{} is from a binomial distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Binomial { + /// Number of trials. + n: u64, + /// Probability of success. + p: f64, +} + +impl Binomial { + /// Construct a new `Binomial` with the given shape parameters `n` (number + /// of trials) and `p` (probability of success). + /// + /// Panics if `p < 0` or `p > 1`. + pub fn new(n: u64, p: f64) -> Binomial { + assert!(p >= 0.0, "Binomial::new called with p < 0"); + assert!(p <= 1.0, "Binomial::new called with p > 1"); + Binomial { n, p } + } +} + +impl Distribution<u64> for Binomial { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + // Handle these values directly. + if self.p == 0.0 { + return 0; + } else if self.p == 1.0 { + return self.n; + } + + // For low n, it is faster to sample directly. For both methods, + // performance is independent of p. On Intel Haswell CPU this method + // appears to be faster for approx n < 300. + if self.n < 300 { + let mut result = 0; + let d = Bernoulli::new(self.p); + for _ in 0 .. self.n { + result += rng.sample(d) as u32; + } + return result as u64; + } + + // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k + // switch p so that it is less than 0.5 - this allows for lower expected values + // we will just invert the result at the end + let p = if self.p <= 0.5 { + self.p + } else { + 1.0 - self.p + }; + + // prepare some cached values + let float_n = self.n as f64; + let ln_fact_n = log_gamma(float_n + 1.0); + let pc = 1.0 - p; + let log_p = p.ln(); + let log_pc = pc.ln(); + let expected = self.n as f64 * p; + let sq = (expected * (2.0 * pc)).sqrt(); + + let mut lresult; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + loop { + let mut comp_dev: f64; + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + lresult = expected + sq * comp_dev; + // repeat the drawing until we are in the range of possible values + if lresult >= 0.0 && lresult < float_n + 1.0 { + break; + } + } + + // the result should be discrete + lresult = lresult.floor(); + + let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) - + log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc; + // this is the binomial probability divided by the comparison probability + // we will generate a uniform random value and if it is larger than this, + // we interpret it as a value falling out of the distribution and repeat + let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev)); + + if comparison_coeff >= rng.gen() { + break; + } + } + + // invert the result for p < 0.5 + if p != self.p { + self.n - lresult as u64 + } else { + lresult as u64 + } + } +} + +#[cfg(test)] +mod test { + use Rng; + use distributions::Distribution; + use super::Binomial; + + fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) { + let binomial = Binomial::new(n, p); + + let expected_mean = n as f64 * p; + let expected_variance = n as f64 * p * (1.0 - p); + + let mut results = [0.0; 1000]; + for i in results.iter_mut() { *i = binomial.sample(rng) as f64; } + + let mean = results.iter().sum::<f64>() / results.len() as f64; + assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0); + + let variance = + results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>() + / results.len() as f64; + assert!((variance - expected_variance).abs() < expected_variance / 10.0); + } + + #[test] + fn test_binomial() { + let mut rng = ::test::rng(351); + test_binomial_mean_and_variance(150, 0.1, &mut rng); + test_binomial_mean_and_variance(70, 0.6, &mut rng); + test_binomial_mean_and_variance(40, 0.5, &mut rng); + test_binomial_mean_and_variance(20, 0.7, &mut rng); + test_binomial_mean_and_variance(20, 0.5, &mut rng); + } + + #[test] + fn test_binomial_end_points() { + let mut rng = ::test::rng(352); + assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0); + assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20); + } + + #[test] + #[should_panic] + fn test_binomial_invalid_lambda_neg() { + Binomial::new(20, -10.0); + } +} diff --git a/rand/src/distributions/cauchy.rs b/rand/src/distributions/cauchy.rs new file mode 100644 index 000000000..feef015a3 --- /dev/null +++ b/rand/src/distributions/cauchy.rs @@ -0,0 +1,115 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Cauchy distribution. + +use Rng; +use distributions::Distribution; +use std::f64::consts::PI; + +/// The Cauchy distribution `Cauchy(median, scale)`. +/// +/// This distribution has a density function: +/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))` +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Cauchy, Distribution}; +/// +/// let cau = Cauchy::new(2.0, 5.0); +/// let v = cau.sample(&mut rand::thread_rng()); +/// println!("{} is from a Cauchy(2, 5) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Cauchy { + median: f64, + scale: f64 +} + +impl Cauchy { + /// Construct a new `Cauchy` with the given shape parameters + /// `median` the peak location and `scale` the scale factor. + /// Panics if `scale <= 0`. + pub fn new(median: f64, scale: f64) -> Cauchy { + assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0"); + Cauchy { + median, + scale + } + } +} + +impl Distribution<f64> for Cauchy { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + // sample from [0, 1) + let x = rng.gen::<f64>(); + // get standard cauchy random number + // note that π/2 is not exactly representable, even if x=0.5 the result is finite + let comp_dev = (PI * x).tan(); + // shift and scale according to parameters + let result = self.median + self.scale * comp_dev; + result + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Cauchy; + + fn median(mut numbers: &mut [f64]) -> f64 { + sort(&mut numbers); + let mid = numbers.len() / 2; + numbers[mid] + } + + fn sort(numbers: &mut [f64]) { + numbers.sort_by(|a, b| a.partial_cmp(b).unwrap()); + } + + #[test] + fn test_cauchy_median() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut numbers: [f64; 1000] = [0.0; 1000]; + for i in 0..1000 { + numbers[i] = cauchy.sample(&mut rng); + } + let median = median(&mut numbers); + println!("Cauchy median: {}", median); + assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_cauchy_mean() { + let cauchy = Cauchy::new(10.0, 5.0); + let mut rng = ::test::rng(123); + let mut sum = 0.0; + for _ in 0..1000 { + sum += cauchy.sample(&mut rng); + } + let mean = sum / 1000.0; + println!("Cauchy mean: {}", mean); + // for a Cauchy distribution the mean should not converge + assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_zero() { + Cauchy::new(0.0, 0.0); + } + + #[test] + #[should_panic] + fn test_cauchy_invalid_scale_neg() { + Cauchy::new(0.0, -10.0); + } +} diff --git a/rand/src/distributions/dirichlet.rs b/rand/src/distributions/dirichlet.rs new file mode 100644 index 000000000..19384b82d --- /dev/null +++ b/rand/src/distributions/dirichlet.rs @@ -0,0 +1,137 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The dirichlet distribution. + +use Rng; +use distributions::Distribution; +use distributions::gamma::Gamma; + +/// The dirichelet distribution `Dirichlet(alpha)`. +/// +/// The Dirichlet distribution is a family of continuous multivariate +/// probability distributions parameterized by a vector alpha of positive reals. +/// It is a multivariate generalization of the beta distribution. +/// +/// # Example +/// +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Dirichlet; +/// +/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]); +/// let samples = dirichlet.sample(&mut rand::thread_rng()); +/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples); +/// ``` + +#[derive(Clone, Debug)] +pub struct Dirichlet { + /// Concentration parameters (alpha) + alpha: Vec<f64>, +} + +impl Dirichlet { + /// Construct a new `Dirichlet` with the given alpha parameter `alpha`. + /// + /// # Panics + /// - if `alpha.len() < 2` + /// + #[inline] + pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet { + let a = alpha.into(); + assert!(a.len() > 1); + for i in 0..a.len() { + assert!(a[i] > 0.0); + } + + Dirichlet { alpha: a } + } + + /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`. + /// + /// # Panics + /// - if `alpha <= 0.0` + /// - if `size < 2` + /// + #[inline] + pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet { + assert!(alpha > 0.0); + assert!(size > 1); + Dirichlet { + alpha: vec![alpha; size], + } + } +} + +impl Distribution<Vec<f64>> for Dirichlet { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> { + let n = self.alpha.len(); + let mut samples = vec![0.0f64; n]; + let mut sum = 0.0f64; + + for i in 0..n { + let g = Gamma::new(self.alpha[i], 1.0); + samples[i] = g.sample(rng); + sum += samples[i]; + } + let invacc = 1.0 / sum; + for i in 0..n { + samples[i] *= invacc; + } + samples + } +} + +#[cfg(test)] +mod test { + use super::Dirichlet; + use distributions::Distribution; + + #[test] + fn test_dirichlet() { + let d = Dirichlet::new(vec![1.0, 2.0, 3.0]); + let mut rng = ::test::rng(221); + let samples = d.sample(&mut rng); + let _: Vec<f64> = samples + .into_iter() + .map(|x| { + assert!(x > 0.0); + x + }) + .collect(); + } + + #[test] + fn test_dirichlet_with_param() { + let alpha = 0.5f64; + let size = 2; + let d = Dirichlet::new_with_param(alpha, size); + let mut rng = ::test::rng(221); + let samples = d.sample(&mut rng); + let _: Vec<f64> = samples + .into_iter() + .map(|x| { + assert!(x > 0.0); + x + }) + .collect(); + } + + #[test] + #[should_panic] + fn test_dirichlet_invalid_length() { + Dirichlet::new_with_param(0.5f64, 1); + } + + #[test] + #[should_panic] + fn test_dirichlet_invalid_alpha() { + Dirichlet::new_with_param(0.0f64, 2); + } +} diff --git a/rand/src/distributions/exponential.rs b/rand/src/distributions/exponential.rs new file mode 100644 index 000000000..76752a60e --- /dev/null +++ b/rand/src/distributions/exponential.rs @@ -0,0 +1,124 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The exponential distribution. + +use {Rng}; +use distributions::{ziggurat_tables, Distribution}; +use distributions::utils::ziggurat; + +/// Samples floating-point numbers according to the exponential distribution, +/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or +/// sampling with `-rng.gen::<f64>().ln()`, but faster. +/// +/// See `Exp` for the general exponential distribution. +/// +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact +/// description in the paper was adjusted to use tables for the exponential +/// distribution rather than normal. +/// +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Exp1; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Exp1); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp1; + +// This could be done via `-rng.gen::<f64>().ln()` but that is slower. +impl Distribution<f64> for Exp1 { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + #[inline] + fn pdf(x: f64) -> f64 { + (-x).exp() + } + #[inline] + fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln() + } + + ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, + pdf, zero_case) + } +} + +/// The exponential distribution `Exp(lambda)`. +/// +/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)` +/// for `x > 0`. +/// +/// Note that [`Exp1`][crate::distributions::Exp1] is an optimised implementation for `lambda = 1`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Exp, Distribution}; +/// +/// let exp = Exp::new(2.0); +/// let v = exp.sample(&mut rand::thread_rng()); +/// println!("{} is from a Exp(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Exp { + /// `lambda` stored as `1/lambda`, since this is what we scale by. + lambda_inverse: f64 +} + +impl Exp { + /// Construct a new `Exp` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + #[inline] + pub fn new(lambda: f64) -> Exp { + assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0"); + Exp { lambda_inverse: 1.0 / lambda } + } +} + +impl Distribution<f64> for Exp { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let n: f64 = rng.sample(Exp1); + n * self.lambda_inverse + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Exp; + + #[test] + fn test_exp() { + let exp = Exp::new(10.0); + let mut rng = ::test::rng(221); + for _ in 0..1000 { + assert!(exp.sample(&mut rng) >= 0.0); + } + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_zero() { + Exp::new(0.0); + } + #[test] + #[should_panic] + fn test_exp_invalid_lambda_neg() { + Exp::new(-10.0); + } +} diff --git a/rand/src/distributions/float.rs b/rand/src/distributions/float.rs new file mode 100644 index 000000000..0dd5caa4a --- /dev/null +++ b/rand/src/distributions/float.rs @@ -0,0 +1,259 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Basic floating-point number distributions + +use core::mem; +use Rng; +use distributions::{Distribution, Standard}; +use distributions::utils::FloatSIMDUtils; +#[cfg(feature="simd_support")] +use packed_simd::*; + +/// A distribution to sample floating point numbers uniformly in the half-open +/// interval `(0, 1]`, i.e. including 1 but not 0. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`Open01`] +/// which samples from `(0, 1)` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::OpenClosed01; +/// +/// let val: f32 = thread_rng().sample(OpenClosed01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: crate::distributions::Standard +/// [`Open01`]: crate::distributions::Open01 +/// [`Uniform`]: crate::distributions::uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct OpenClosed01; + +/// A distribution to sample floating point numbers uniformly in the open +/// interval `(0, 1)`, i.e. not including either endpoint. +/// +/// All values that can be generated are of the form `n * ε + ε/2`. For `f32` +/// the 22 most significant random bits of an `u32` are used, for `f64` 52 from +/// an `u64`. The conversion uses a transmute-based method. +/// +/// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`] +/// which samples from `(0, 1]` and [`Uniform`] which samples from arbitrary +/// ranges. +/// +/// # Example +/// ``` +/// use rand::{thread_rng, Rng}; +/// use rand::distributions::Open01; +/// +/// let val: f32 = thread_rng().sample(Open01); +/// println!("f32 from (0, 1): {}", val); +/// ``` +/// +/// [`Standard`]: crate::distributions::Standard +/// [`OpenClosed01`]: crate::distributions::OpenClosed01 +/// [`Uniform`]: crate::distributions::uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct Open01; + + +pub(crate) trait IntoFloat { + type F; + + /// Helper method to combine the fraction and a contant exponent into a + /// float. + /// + /// Only the least significant bits of `self` may be set, 23 for `f32` and + /// 52 for `f64`. + /// The resulting value will fall in a range that depends on the exponent. + /// As an example the range with exponent 0 will be + /// [2<sup>0</sup>..2<sup>1</sup>), which is [1..2). + fn into_float_with_exponent(self, exponent: i32) -> Self::F; +} + +macro_rules! float_impls { + ($ty:ident, $uty:ident, $f_scalar:ident, $u_scalar:ty, + $fraction_bits:expr, $exponent_bias:expr) => { + impl IntoFloat for $uty { + type F = $ty; + #[inline(always)] + fn into_float_with_exponent(self, exponent: i32) -> $ty { + // The exponent is encoded using an offset-binary representation + let exponent_bits: $u_scalar = + (($exponent_bias + exponent) as $u_scalar) << $fraction_bits; + // TODO: use from_bits when min compiler > 1.25 (see #545) + // $ty::from_bits(self | exponent_bits) + unsafe{ mem::transmute(self | exponent_bits) } + } + } + + impl Distribution<$ty> for Standard { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; [0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); + + let value: $uty = rng.gen(); + let value = value >> (float_size - precision); + scale * $ty::cast_from_int(value) + } + } + + impl Distribution<$ty> for OpenClosed01 { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Multiply-based method; 24/53 random bits; (0, 1] interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + let precision = $fraction_bits + 1; + let scale = 1.0 / ((1 as $u_scalar << precision) as $f_scalar); + + let value: $uty = rng.gen(); + let value = value >> (float_size - precision); + // Add 1 to shift up; will not overflow because of right-shift: + scale * $ty::cast_from_int(value + 1) + } + } + + impl Distribution<$ty> for Open01 { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + // Transmute-based method; 23/52 random bits; (0, 1) interval. + // We use the most significant bits because for simple RNGs + // those are usually more random. + use core::$f_scalar::EPSILON; + let float_size = mem::size_of::<$f_scalar>() as u32 * 8; + + let value: $uty = rng.gen(); + let fraction = value >> (float_size - $fraction_bits); + fraction.into_float_with_exponent(0) - (1.0 - EPSILON / 2.0) + } + } + } +} + +float_impls! { f32, u32, f32, u32, 23, 127 } +float_impls! { f64, u64, f64, u64, 52, 1023 } + +#[cfg(feature="simd_support")] +float_impls! { f32x2, u32x2, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x4, u32x4, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x8, u32x8, f32, u32, 23, 127 } +#[cfg(feature="simd_support")] +float_impls! { f32x16, u32x16, f32, u32, 23, 127 } + +#[cfg(feature="simd_support")] +float_impls! { f64x2, u64x2, f64, u64, 52, 1023 } +#[cfg(feature="simd_support")] +float_impls! { f64x4, u64x4, f64, u64, 52, 1023 } +#[cfg(feature="simd_support")] +float_impls! { f64x8, u64x8, f64, u64, 52, 1023 } + + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Open01, OpenClosed01}; + use rngs::mock::StepRng; + #[cfg(feature="simd_support")] + use packed_simd::*; + + const EPSILON32: f32 = ::core::f32::EPSILON; + const EPSILON64: f64 = ::core::f64::EPSILON; + + macro_rules! test_f32 { + ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { + #[test] + fn $fnn() { + // Standard + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.gen::<$ty>(), $ZERO); + let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); + + // OpenClosed01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), + 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0); + assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); + + // Open01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 9 | 1 << (9 + 32), 0); + assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); + } + } + } + test_f32! { f32_edge_cases, f32, 0.0, EPSILON32 } + #[cfg(feature="simd_support")] + test_f32! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) } + #[cfg(feature="simd_support")] + test_f32! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) } + + macro_rules! test_f64 { + ($fnn:ident, $ty:ident, $ZERO:expr, $EPSILON:expr) => { + #[test] + fn $fnn() { + // Standard + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.gen::<$ty>(), $ZERO); + let mut one = StepRng::new(1 << 11, 0); + assert_eq!(one.gen::<$ty>(), $EPSILON / 2.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.gen::<$ty>(), 1.0 - $EPSILON / 2.0); + + // OpenClosed01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), + 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 11, 0); + assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(OpenClosed01), $ZERO + 1.0); + + // Open01 + let mut zeros = StepRng::new(0, 0); + assert_eq!(zeros.sample::<$ty, _>(Open01), 0.0 + $EPSILON / 2.0); + let mut one = StepRng::new(1 << 12, 0); + assert_eq!(one.sample::<$ty, _>(Open01), $EPSILON / 2.0 * 3.0); + let mut max = StepRng::new(!0, 0); + assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0); + } + } + } + test_f64! { f64_edge_cases, f64, 0.0, EPSILON64 } + #[cfg(feature="simd_support")] + test_f64! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) } + #[cfg(feature="simd_support")] + test_f64! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) } + #[cfg(feature="simd_support")] + test_f64! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) } +} diff --git a/rand/src/distributions/gamma.rs b/rand/src/distributions/gamma.rs new file mode 100644 index 000000000..43ac2bc15 --- /dev/null +++ b/rand/src/distributions/gamma.rs @@ -0,0 +1,413 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Gamma and derived distributions. + +use self::GammaRepr::*; +use self::ChiSquaredRepr::*; + +use Rng; +use distributions::normal::StandardNormal; +use distributions::{Distribution, Exp, Open01}; + +/// The Gamma distribution `Gamma(shape, scale)` distribution. +/// +/// The density function of this distribution is +/// +/// ```text +/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k) +/// ``` +/// +/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the +/// scale and both `k` and `θ` are strictly positive. +/// +/// The algorithm used is that described by Marsaglia & Tsang 2000[^1], +/// falling back to directly sampling from an Exponential for `shape +/// == 1`, and using the boosting technique described in that paper for +/// `shape < 1`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Gamma}; +/// +/// let gamma = Gamma::new(2.0, 5.0); +/// let v = gamma.sample(&mut rand::thread_rng()); +/// println!("{} is from a Gamma(2, 5) distribution", v); +/// ``` +/// +/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for +/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 +/// (September 2000), 363-372. +/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414) +#[derive(Clone, Copy, Debug)] +pub struct Gamma { + repr: GammaRepr, +} + +#[derive(Clone, Copy, Debug)] +enum GammaRepr { + Large(GammaLargeShape), + One(Exp), + Small(GammaSmallShape) +} + +// These two helpers could be made public, but saving the +// match-on-Gamma-enum branch from using them directly (e.g. if one +// knows that the shape is always > 1) doesn't appear to be much +// faster. + +/// Gamma distribution where the shape parameter is less than 1. +/// +/// Note, samples from this require a compulsory floating-point `pow` +/// call, which makes it significantly slower than sampling from a +/// gamma distribution where the shape parameter is greater than or +/// equal to 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaSmallShape { + inv_shape: f64, + large_shape: GammaLargeShape +} + +/// Gamma distribution where the shape parameter is larger than 1. +/// +/// See `Gamma` for sampling from a Gamma distribution with general +/// shape parameters. +#[derive(Clone, Copy, Debug)] +struct GammaLargeShape { + scale: f64, + c: f64, + d: f64 +} + +impl Gamma { + /// Construct an object representing the `Gamma(shape, scale)` + /// distribution. + /// + /// Panics if `shape <= 0` or `scale <= 0`. + #[inline] + pub fn new(shape: f64, scale: f64) -> Gamma { + assert!(shape > 0.0, "Gamma::new called with shape <= 0"); + assert!(scale > 0.0, "Gamma::new called with scale <= 0"); + + let repr = if shape == 1.0 { + One(Exp::new(1.0 / scale)) + } else if shape < 1.0 { + Small(GammaSmallShape::new_raw(shape, scale)) + } else { + Large(GammaLargeShape::new_raw(shape, scale)) + }; + Gamma { repr } + } +} + +impl GammaSmallShape { + fn new_raw(shape: f64, scale: f64) -> GammaSmallShape { + GammaSmallShape { + inv_shape: 1. / shape, + large_shape: GammaLargeShape::new_raw(shape + 1.0, scale) + } + } +} + +impl GammaLargeShape { + fn new_raw(shape: f64, scale: f64) -> GammaLargeShape { + let d = shape - 1. / 3.; + GammaLargeShape { + scale, + c: 1. / (9. * d).sqrt(), + d + } + } +} + +impl Distribution<f64> for Gamma { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + match self.repr { + Small(ref g) => g.sample(rng), + One(ref g) => g.sample(rng), + Large(ref g) => g.sample(rng), + } + } +} +impl Distribution<f64> for GammaSmallShape { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(Open01); + + self.large_shape.sample(rng) * u.powf(self.inv_shape) + } +} +impl Distribution<f64> for GammaLargeShape { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + loop { + let x = rng.sample(StandardNormal); + let v_cbrt = 1.0 + self.c * x; + if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0 + continue + } + + let v = v_cbrt * v_cbrt * v_cbrt; + let u: f64 = rng.sample(Open01); + + let x_sqr = x * x; + if u < 1.0 - 0.0331 * x_sqr * x_sqr || + u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) { + return self.d * v * self.scale + } + } + } +} + +/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of +/// freedom. +/// +/// For `k > 0` integral, this distribution is the sum of the squares +/// of `k` independent standard normal random variables. For other +/// `k`, this uses the equivalent characterisation +/// `χ²(k) = Gamma(k/2, 2)`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{ChiSquared, Distribution}; +/// +/// let chi = ChiSquared::new(11.0); +/// let v = chi.sample(&mut rand::thread_rng()); +/// println!("{} is from a χ²(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct ChiSquared { + repr: ChiSquaredRepr, +} + +#[derive(Clone, Copy, Debug)] +enum ChiSquaredRepr { + // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1, + // e.g. when alpha = 1/2 as it would be for this case, so special- + // casing and using the definition of N(0,1)^2 is faster. + DoFExactlyOne, + DoFAnythingElse(Gamma), +} + +impl ChiSquared { + /// Create a new chi-squared distribution with degrees-of-freedom + /// `k`. Panics if `k < 0`. + pub fn new(k: f64) -> ChiSquared { + let repr = if k == 1.0 { + DoFExactlyOne + } else { + assert!(k > 0.0, "ChiSquared::new called with `k` < 0"); + DoFAnythingElse(Gamma::new(0.5 * k, 2.0)) + }; + ChiSquared { repr } + } +} +impl Distribution<f64> for ChiSquared { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + match self.repr { + DoFExactlyOne => { + // k == 1 => N(0,1)^2 + let norm = rng.sample(StandardNormal); + norm * norm + } + DoFAnythingElse(ref g) => g.sample(rng) + } + } +} + +/// The Fisher F distribution `F(m, n)`. +/// +/// This distribution is equivalent to the ratio of two normalised +/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) / +/// (χ²(n)/n)`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{FisherF, Distribution}; +/// +/// let f = FisherF::new(2.0, 32.0); +/// let v = f.sample(&mut rand::thread_rng()); +/// println!("{} is from an F(2, 32) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct FisherF { + numer: ChiSquared, + denom: ChiSquared, + // denom_dof / numer_dof so that this can just be a straight + // multiplication, rather than a division. + dof_ratio: f64, +} + +impl FisherF { + /// Create a new `FisherF` distribution, with the given + /// parameter. Panics if either `m` or `n` are not positive. + pub fn new(m: f64, n: f64) -> FisherF { + assert!(m > 0.0, "FisherF::new called with `m < 0`"); + assert!(n > 0.0, "FisherF::new called with `n < 0`"); + + FisherF { + numer: ChiSquared::new(m), + denom: ChiSquared::new(n), + dof_ratio: n / m + } + } +} +impl Distribution<f64> for FisherF { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio + } +} + +/// The Student t distribution, `t(nu)`, where `nu` is the degrees of +/// freedom. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{StudentT, Distribution}; +/// +/// let t = StudentT::new(11.0); +/// let v = t.sample(&mut rand::thread_rng()); +/// println!("{} is from a t(11) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StudentT { + chi: ChiSquared, + dof: f64 +} + +impl StudentT { + /// Create a new Student t distribution with `n` degrees of + /// freedom. Panics if `n <= 0`. + pub fn new(n: f64) -> StudentT { + assert!(n > 0.0, "StudentT::new called with `n <= 0`"); + StudentT { + chi: ChiSquared::new(n), + dof: n + } + } +} +impl Distribution<f64> for StudentT { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let norm = rng.sample(StandardNormal); + norm * (self.dof / self.chi.sample(rng)).sqrt() + } +} + +/// The Beta distribution with shape parameters `alpha` and `beta`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Beta}; +/// +/// let beta = Beta::new(2.0, 5.0); +/// let v = beta.sample(&mut rand::thread_rng()); +/// println!("{} is from a Beta(2, 5) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Beta { + gamma_a: Gamma, + gamma_b: Gamma, +} + +impl Beta { + /// Construct an object representing the `Beta(alpha, beta)` + /// distribution. + /// + /// Panics if `shape <= 0` or `scale <= 0`. + pub fn new(alpha: f64, beta: f64) -> Beta { + assert!((alpha > 0.) & (beta > 0.)); + Beta { + gamma_a: Gamma::new(alpha, 1.), + gamma_b: Gamma::new(beta, 1.), + } + } +} + +impl Distribution<f64> for Beta { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let x = self.gamma_a.sample(rng); + let y = self.gamma_b.sample(rng); + x / (x + y) + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::{Beta, ChiSquared, StudentT, FisherF}; + + #[test] + fn test_chi_squared_one() { + let chi = ChiSquared::new(1.0); + let mut rng = ::test::rng(201); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + fn test_chi_squared_small() { + let chi = ChiSquared::new(0.5); + let mut rng = ::test::rng(202); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + fn test_chi_squared_large() { + let chi = ChiSquared::new(30.0); + let mut rng = ::test::rng(203); + for _ in 0..1000 { + chi.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_chi_squared_invalid_dof() { + ChiSquared::new(-1.0); + } + + #[test] + fn test_f() { + let f = FisherF::new(2.0, 32.0); + let mut rng = ::test::rng(204); + for _ in 0..1000 { + f.sample(&mut rng); + } + } + + #[test] + fn test_t() { + let t = StudentT::new(11.0); + let mut rng = ::test::rng(205); + for _ in 0..1000 { + t.sample(&mut rng); + } + } + + #[test] + fn test_beta() { + let beta = Beta::new(1.0, 2.0); + let mut rng = ::test::rng(201); + for _ in 0..1000 { + beta.sample(&mut rng); + } + } + + #[test] + #[should_panic] + fn test_beta_invalid_dof() { + Beta::new(0., 0.); + } +} diff --git a/rand/src/distributions/integer.rs b/rand/src/distributions/integer.rs new file mode 100644 index 000000000..7e408dbf1 --- /dev/null +++ b/rand/src/distributions/integer.rs @@ -0,0 +1,161 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for integer types. + +use {Rng}; +use distributions::{Distribution, Standard}; +#[cfg(feature="simd_support")] +use packed_simd::*; +#[cfg(all(target_arch = "x86", feature="nightly"))] +use core::arch::x86::*; +#[cfg(all(target_arch = "x86_64", feature="nightly"))] +use core::arch::x86_64::*; + +impl Distribution<u8> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 { + rng.next_u32() as u8 + } +} + +impl Distribution<u16> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u16 { + rng.next_u32() as u16 + } +} + +impl Distribution<u32> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u32 { + rng.next_u32() + } +} + +impl Distribution<u64> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + rng.next_u64() + } +} + +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +impl Distribution<u128> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u128 { + // Use LE; we explicitly generate one value before the next. + let x = rng.next_u64() as u128; + let y = rng.next_u64() as u128; + (y << 64) | x + } +} + +impl Distribution<usize> for Standard { + #[inline] + #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + rng.next_u32() as usize + } + + #[inline] + #[cfg(target_pointer_width = "64")] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + rng.next_u64() as usize + } +} + +macro_rules! impl_int_from_uint { + ($ty:ty, $uty:ty) => { + impl Distribution<$ty> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + rng.gen::<$uty>() as $ty + } + } + } +} + +impl_int_from_uint! { i8, u8 } +impl_int_from_uint! { i16, u16 } +impl_int_from_uint! { i32, u32 } +impl_int_from_uint! { i64, u64 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_int_from_uint! { i128, u128 } +impl_int_from_uint! { isize, usize } + +#[cfg(feature="simd_support")] +macro_rules! simd_impl { + ($(($intrinsic:ident, $vec:ty),)+) => {$( + impl Distribution<$intrinsic> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $intrinsic { + $intrinsic::from_bits(rng.gen::<$vec>()) + } + } + )+}; + + ($bits:expr,) => {}; + ($bits:expr, $ty:ty, $($ty_more:ty,)*) => { + simd_impl!($bits, $($ty_more,)*); + + impl Distribution<$ty> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $ty { + let mut vec: $ty = Default::default(); + unsafe { + let ptr = &mut vec; + let b_ptr = &mut *(ptr as *mut $ty as *mut [u8; $bits/8]); + rng.fill_bytes(b_ptr); + } + vec.to_le() + } + } + }; +} + +#[cfg(feature="simd_support")] +simd_impl!(16, u8x2, i8x2,); +#[cfg(feature="simd_support")] +simd_impl!(32, u8x4, i8x4, u16x2, i16x2,); +#[cfg(feature="simd_support")] +simd_impl!(64, u8x8, i8x8, u16x4, i16x4, u32x2, i32x2,); +#[cfg(feature="simd_support")] +simd_impl!(128, u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2,); +#[cfg(feature="simd_support")] +simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,); +#[cfg(feature="simd_support")] +simd_impl!(512, u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8,); +#[cfg(all(feature="simd_support", feature="nightly", any(target_arch="x86", target_arch="x86_64")))] +simd_impl!((__m64, u8x8), (__m128i, u8x16), (__m256i, u8x32),); + +#[cfg(test)] +mod tests { + use Rng; + use distributions::{Standard}; + + #[test] + fn test_integers() { + let mut rng = ::test::rng(806); + + rng.sample::<isize, _>(Standard); + rng.sample::<i8, _>(Standard); + rng.sample::<i16, _>(Standard); + rng.sample::<i32, _>(Standard); + rng.sample::<i64, _>(Standard); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + rng.sample::<i128, _>(Standard); + + rng.sample::<usize, _>(Standard); + rng.sample::<u8, _>(Standard); + rng.sample::<u16, _>(Standard); + rng.sample::<u32, _>(Standard); + rng.sample::<u64, _>(Standard); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + rng.sample::<u128, _>(Standard); + } +} diff --git a/rand/src/distributions/mod.rs b/rand/src/distributions/mod.rs new file mode 100644 index 000000000..6e2d6c7ba --- /dev/null +++ b/rand/src/distributions/mod.rs @@ -0,0 +1,608 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generating random samples from probability distributions. +//! +//! This module is the home of the [`Distribution`] trait and several of its +//! implementations. It is the workhorse behind some of the convenient +//! functionality of the [`Rng`] trait, including [`gen`], [`gen_range`] and +//! of course [`sample`]. +//! +//! Abstractly, a [probability distribution] describes the probability of +//! occurance of each value in its sample space. +//! +//! More concretely, an implementation of `Distribution<T>` for type `X` is an +//! algorithm for choosing values from the sample space (a subset of `T`) +//! according to the distribution `X` represents, using an external source of +//! randomness (an RNG supplied to the `sample` function). +//! +//! A type `X` may implement `Distribution<T>` for multiple types `T`. +//! Any type implementing [`Distribution`] is stateless (i.e. immutable), +//! but it may have internal parameters set at construction time (for example, +//! [`Uniform`] allows specification of its sample space as a range within `T`). +//! +//! +//! # The `Standard` distribution +//! +//! The [`Standard`] distribution is important to mention. This is the +//! distribution used by [`Rng::gen()`] and represents the "default" way to +//! produce a random value for many different types, including most primitive +//! types, tuples, arrays, and a few derived types. See the documentation of +//! [`Standard`] for more details. +//! +//! Implementing `Distribution<T>` for [`Standard`] for user types `T` makes it +//! possible to generate type `T` with [`Rng::gen()`], and by extension also +//! with the [`random()`] function. +//! +//! +//! # Distribution to sample from a `Uniform` range +//! +//! The [`Uniform`] distribution is more flexible than [`Standard`], but also +//! more specialised: it supports fewer target types, but allows the sample +//! space to be specified as an arbitrary range within its target type `T`. +//! Both [`Standard`] and [`Uniform`] are in some sense uniform distributions. +//! +//! Values may be sampled from this distribution using [`Rng::gen_range`] or +//! by creating a distribution object with [`Uniform::new`], +//! [`Uniform::new_inclusive`] or `From<Range>`. When the range limits are not +//! known at compile time it is typically faster to reuse an existing +//! distribution object than to call [`Rng::gen_range`]. +//! +//! User types `T` may also implement `Distribution<T>` for [`Uniform`], +//! although this is less straightforward than for [`Standard`] (see the +//! documentation in the [`uniform`] module. Doing so enables generation of +//! values of type `T` with [`Rng::gen_range`]. +//! +//! +//! # Other distributions +//! +//! There are surprisingly many ways to uniformly generate random floats. A +//! range between 0 and 1 is standard, but the exact bounds (open vs closed) +//! and accuracy differ. In addition to the [`Standard`] distribution Rand offers +//! [`Open01`] and [`OpenClosed01`]. See "Floating point implementation" section of +//! [`Standard`] documentation for more details. +//! +//! [`Alphanumeric`] is a simple distribution to sample random letters and +//! numbers of the `char` type; in contrast [`Standard`] may sample any valid +//! `char`. +//! +//! [`WeightedIndex`] can be used to do weighted sampling from a set of items, +//! such as from an array. +//! +//! # Non-uniform probability distributions +//! +//! Rand currently provides the following probability distributions: +//! +//! - Related to real-valued quantities that grow linearly +//! (e.g. errors, offsets): +//! - [`Normal`] distribution, and [`StandardNormal`] as a primitive +//! - [`Cauchy`] distribution +//! - Related to Bernoulli trials (yes/no events, with a given probability): +//! - [`Binomial`] distribution +//! - [`Bernoulli`] distribution, similar to [`Rng::gen_bool`]. +//! - Related to positive real-valued quantities that grow exponentially +//! (e.g. prices, incomes, populations): +//! - [`LogNormal`] distribution +//! - Related to the occurrence of independent events at a given rate: +//! - [`Pareto`] distribution +//! - [`Poisson`] distribution +//! - [`Exp`]onential distribution, and [`Exp1`] as a primitive +//! - [`Weibull`] distribution +//! - Gamma and derived distributions: +//! - [`Gamma`] distribution +//! - [`ChiSquared`] distribution +//! - [`StudentT`] distribution +//! - [`FisherF`] distribution +//! - Triangular distribution: +//! - [`Beta`] distribution +//! - [`Triangular`] distribution +//! - Multivariate probability distributions +//! - [`Dirichlet`] distribution +//! - [`UnitSphereSurface`] distribution +//! - [`UnitCircle`] distribution +//! +//! # Examples +//! +//! Sampling from a distribution: +//! +//! ``` +//! use rand::{thread_rng, Rng}; +//! use rand::distributions::Exp; +//! +//! let exp = Exp::new(2.0); +//! let v = thread_rng().sample(exp); +//! println!("{} is from an Exp(2) distribution", v); +//! ``` +//! +//! Implementing the [`Standard`] distribution for a user type: +//! +//! ``` +//! # #![allow(dead_code)] +//! use rand::Rng; +//! use rand::distributions::{Distribution, Standard}; +//! +//! struct MyF32 { +//! x: f32, +//! } +//! +//! impl Distribution<MyF32> for Standard { +//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> MyF32 { +//! MyF32 { x: rng.gen() } +//! } +//! } +//! ``` +//! +//! +//! [probability distribution]: https://en.wikipedia.org/wiki/Probability_distribution +//! [`gen_range`]: Rng::gen_range +//! [`gen`]: Rng::gen +//! [`sample`]: Rng::sample +//! [`new_inclusive`]: Uniform::new_inclusive +//! [`Alphanumeric`]: distributions::Alphanumeric +//! [`Bernoulli`]: distributions::Bernoulli +//! [`Beta`]: distributions::Beta +//! [`Binomial`]: distributions::Binomial +//! [`Cauchy`]: distributions::Cauchy +//! [`ChiSquared`]: distributions::ChiSquared +//! [`Dirichlet`]: distributions::Dirichlet +//! [`Exp`]: distributions::Exp +//! [`Exp1`]: distributions::Exp1 +//! [`FisherF`]: distributions::FisherF +//! [`Gamma`]: distributions::Gamma +//! [`LogNormal`]: distributions::LogNormal +//! [`Normal`]: distributions::Normal +//! [`Open01`]: distributions::Open01 +//! [`OpenClosed01`]: distributions::OpenClosed01 +//! [`Pareto`]: distributions::Pareto +//! [`Poisson`]: distributions::Poisson +//! [`Standard`]: distributions::Standard +//! [`StandardNormal`]: distributions::StandardNormal +//! [`StudentT`]: distributions::StudentT +//! [`Triangular`]: distributions::Triangular +//! [`Uniform`]: distributions::Uniform +//! [`Uniform::new`]: distributions::Uniform::new +//! [`Uniform::new_inclusive`]: distributions::Uniform::new_inclusive +//! [`UnitSphereSurface`]: distributions::UnitSphereSurface +//! [`UnitCircle`]: distributions::UnitCircle +//! [`Weibull`]: distributions::Weibull +//! [`WeightedIndex`]: distributions::WeightedIndex + +#[cfg(any(rustc_1_26, features="nightly"))] +use core::iter; +use Rng; + +pub use self::other::Alphanumeric; +#[doc(inline)] pub use self::uniform::Uniform; +pub use self::float::{OpenClosed01, Open01}; +pub use self::bernoulli::Bernoulli; +#[cfg(feature="alloc")] pub use self::weighted::{WeightedIndex, WeightedError}; +#[cfg(feature="std")] pub use self::unit_sphere::UnitSphereSurface; +#[cfg(feature="std")] pub use self::unit_circle::UnitCircle; +#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF, + StudentT, Beta}; +#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal, StandardNormal}; +#[cfg(feature="std")] pub use self::exponential::{Exp, Exp1}; +#[cfg(feature="std")] pub use self::pareto::Pareto; +#[cfg(feature="std")] pub use self::poisson::Poisson; +#[cfg(feature="std")] pub use self::binomial::Binomial; +#[cfg(feature="std")] pub use self::cauchy::Cauchy; +#[cfg(feature="std")] pub use self::dirichlet::Dirichlet; +#[cfg(feature="std")] pub use self::triangular::Triangular; +#[cfg(feature="std")] pub use self::weibull::Weibull; + +pub mod uniform; +mod bernoulli; +#[cfg(feature="alloc")] mod weighted; +#[cfg(feature="std")] mod unit_sphere; +#[cfg(feature="std")] mod unit_circle; +#[cfg(feature="std")] mod gamma; +#[cfg(feature="std")] mod normal; +#[cfg(feature="std")] mod exponential; +#[cfg(feature="std")] mod pareto; +#[cfg(feature="std")] mod poisson; +#[cfg(feature="std")] mod binomial; +#[cfg(feature="std")] mod cauchy; +#[cfg(feature="std")] mod dirichlet; +#[cfg(feature="std")] mod triangular; +#[cfg(feature="std")] mod weibull; + +mod float; +mod integer; +mod other; +mod utils; +#[cfg(feature="std")] mod ziggurat_tables; + +/// Types (distributions) that can be used to create a random instance of `T`. +/// +/// It is possible to sample from a distribution through both the +/// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and +/// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which +/// produces an iterator that samples from the distribution. +/// +/// All implementations are expected to be immutable; this has the significant +/// advantage of not needing to consider thread safety, and for most +/// distributions efficient state-less sampling algorithms are available. +/// +/// [`sample_iter`]: Distribution::method.sample_iter +pub trait Distribution<T> { + /// Generate a random value of `T`, using `rng` as the source of randomness. + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T; + + /// Create an iterator that generates random values of `T`, using `rng` as + /// the source of randomness. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect(); + /// + /// // String: + /// let s: String = Alphanumeric.sample_iter(&mut rng).take(7).collect(); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = die_range.sample_iter(&mut rng); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T> + where Self: Sized, R: Rng + { + DistIter { + distr: self, + rng: rng, + phantom: ::core::marker::PhantomData, + } + } +} + +impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { + (*self).sample(rng) + } +} + + +/// An iterator that generates random values of `T` with distribution `D`, +/// using `R` as the source of randomness. +/// +/// This `struct` is created by the [`sample_iter`] method on [`Distribution`]. +/// See its documentation for more. +/// +/// [`sample_iter`]: Distribution::sample_iter +#[derive(Debug)] +pub struct DistIter<'a, D: 'a, R: 'a, T> { + distr: &'a D, + rng: &'a mut R, + phantom: ::core::marker::PhantomData<T>, +} + +impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T> + where D: Distribution<T>, R: Rng + 'a +{ + type Item = T; + + #[inline(always)] + fn next(&mut self) -> Option<T> { + Some(self.distr.sample(self.rng)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (usize::max_value(), None) + } +} + +#[cfg(rustc_1_26)] +impl<'a, D, R, T> iter::FusedIterator for DistIter<'a, D, R, T> + where D: Distribution<T>, R: Rng + 'a {} + +#[cfg(features = "nightly")] +impl<'a, D, R, T> iter::TrustedLen for DistIter<'a, D, R, T> + where D: Distribution<T>, R: Rng + 'a {} + + +/// A generic random value distribution, implemented for many primitive types. +/// Usually generates values with a numerically uniform distribution, and with a +/// range appropriate to the type. +/// +/// ## Built-in Implementations +/// +/// Assuming the provided `Rng` is well-behaved, these implementations +/// generate values with the following ranges and distributions: +/// +/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed +/// over all values of the type. +/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all +/// code points in the range `0...0x10_FFFF`, except for the range +/// `0xD800...0xDFFF` (the surrogate code points). This includes +/// unassigned/reserved code points. +/// * `bool`: Generates `false` or `true`, each with probability 0.5. +/// * Floating point types (`f32` and `f64`): Uniformly distributed in the +/// half-open range `[0, 1)`. See notes below. +/// * Wrapping integers (`Wrapping<T>`), besides the type identical to their +/// normal integer variants. +/// +/// The following aggregate types also implement the distribution `Standard` as +/// long as their component types implement it: +/// +/// * Tuples and arrays: Each element of the tuple or array is generated +/// independently, using the `Standard` distribution recursively. +/// * `Option<T>` where `Standard` is implemented for `T`: Returns `None` with +/// probability 0.5; otherwise generates a random `x: T` and returns `Some(x)`. +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Standard; +/// +/// let val: f32 = SmallRng::from_entropy().sample(Standard); +/// println!("f32 from [0, 1): {}", val); +/// ``` +/// +/// # Floating point implementation +/// The floating point implementations for `Standard` generate a random value in +/// the half-open interval `[0, 1)`, i.e. including 0 but not 1. +/// +/// All values that can be generated are of the form `n * ε/2`. For `f32` +/// the 23 most significant random bits of a `u32` are used and for `f64` the +/// 53 most significant bits of a `u64` are used. The conversion uses the +/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`. +/// +/// See also: [`Open01`] which samples from `(0, 1)`, [`OpenClosed01`] which +/// samples from `(0, 1]` and `Rng::gen_range(0, 1)` which also samples from +/// `[0, 1)`. Note that `Open01` and `gen_range` (which uses [`Uniform`]) use +/// transmute-based methods which yield 1 bit less precision but may perform +/// faster on some architectures (on modern Intel CPUs all methods have +/// approximately equal performance). +/// +/// [`Uniform`]: uniform::Uniform +#[derive(Clone, Copy, Debug)] +pub struct Standard; + + +/// A value with a particular weight for use with `WeightedChoice`. +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] +#[derive(Copy, Clone, Debug)] +pub struct Weighted<T> { + /// The numerical weight of this item + pub weight: u32, + /// The actual item which is being weighted + pub item: T, +} + +/// A distribution that selects from a finite collection of weighted items. +/// +/// Deprecated: use [`WeightedIndex`] instead. +/// +/// [`WeightedIndex`]: WeightedIndex +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] +#[derive(Debug)] +pub struct WeightedChoice<'a, T:'a> { + items: &'a mut [Weighted<T>], + weight_range: Uniform<u32>, +} + +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] +impl<'a, T: Clone> WeightedChoice<'a, T> { + /// Create a new `WeightedChoice`. + /// + /// Panics if: + /// + /// - `items` is empty + /// - the total weight is 0 + /// - the total weight is larger than a `u32` can contain. + pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> { + // strictly speaking, this is subsumed by the total weight == 0 case + assert!(!items.is_empty(), "WeightedChoice::new called with no items"); + + let mut running_total: u32 = 0; + + // we convert the list from individual weights to cumulative + // weights so we can binary search. This *could* drop elements + // with weight == 0 as an optimisation. + for item in items.iter_mut() { + running_total = match running_total.checked_add(item.weight) { + Some(n) => n, + None => panic!("WeightedChoice::new called with a total weight \ + larger than a u32 can contain") + }; + + item.weight = running_total; + } + assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0"); + + WeightedChoice { + items, + // we're likely to be generating numbers in this range + // relatively often, so might as well cache it + weight_range: Uniform::new(0, running_total) + } + } +} + +#[deprecated(since="0.6.0", note="use WeightedIndex instead")] +#[allow(deprecated)] +impl<'a, T: Clone> Distribution<T> for WeightedChoice<'a, T> { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T { + // we want to find the first element that has cumulative + // weight > sample_weight, which we do by binary since the + // cumulative weights of self.items are sorted. + + // choose a weight in [0, total_weight) + let sample_weight = self.weight_range.sample(rng); + + // short circuit when it's the first item + if sample_weight < self.items[0].weight { + return self.items[0].item.clone(); + } + + let mut idx = 0; + let mut modifier = self.items.len(); + + // now we know that every possibility has an element to the + // left, so we can just search for the last element that has + // cumulative weight <= sample_weight, then the next one will + // be "it". (Note that this greatest element will never be the + // last element of the vector, since sample_weight is chosen + // in [0, total_weight) and the cumulative weight of the last + // one is exactly the total weight.) + while modifier > 1 { + let i = idx + modifier / 2; + if self.items[i].weight <= sample_weight { + // we're small, so look to the right, but allow this + // exact element still. + idx = i; + // we need the `/ 2` to round up otherwise we'll drop + // the trailing elements when `modifier` is odd. + modifier += 1; + } else { + // otherwise we're too big, so go left. (i.e. do + // nothing) + } + modifier /= 2; + } + self.items[idx + 1].item.clone() + } +} + +#[cfg(test)] +mod tests { + use rngs::mock::StepRng; + #[allow(deprecated)] + use super::{WeightedChoice, Weighted, Distribution}; + + #[test] + #[allow(deprecated)] + fn test_weighted_choice() { + // this makes assumptions about the internal implementation of + // WeightedChoice. It may fail when the implementation in + // `distributions::uniform::UniformInt` changes. + + macro_rules! t { + ($items:expr, $expected:expr) => {{ + let mut items = $items; + let mut total_weight = 0; + for item in &items { total_weight += item.weight; } + + let wc = WeightedChoice::new(&mut items); + let expected = $expected; + + // Use extremely large steps between the random numbers, because + // we test with small ranges and `UniformInt` is designed to prefer + // the most significant bits. + let mut rng = StepRng::new(0, !0 / (total_weight as u64)); + + for &val in expected.iter() { + assert_eq!(wc.sample(&mut rng), val) + } + }} + } + + t!([Weighted { weight: 1, item: 10}], [10]); + + // skip some + t!([Weighted { weight: 0, item: 20}, + Weighted { weight: 2, item: 21}, + Weighted { weight: 0, item: 22}, + Weighted { weight: 1, item: 23}], + [21, 21, 23]); + + // different weights + t!([Weighted { weight: 4, item: 30}, + Weighted { weight: 3, item: 31}], + [30, 31, 30, 31, 30, 31, 30]); + + // check that we're binary searching + // correctly with some vectors of odd + // length. + t!([Weighted { weight: 1, item: 40}, + Weighted { weight: 1, item: 41}, + Weighted { weight: 1, item: 42}, + Weighted { weight: 1, item: 43}, + Weighted { weight: 1, item: 44}], + [40, 41, 42, 43, 44]); + t!([Weighted { weight: 1, item: 50}, + Weighted { weight: 1, item: 51}, + Weighted { weight: 1, item: 52}, + Weighted { weight: 1, item: 53}, + Weighted { weight: 1, item: 54}, + Weighted { weight: 1, item: 55}, + Weighted { weight: 1, item: 56}], + [50, 54, 51, 55, 52, 56, 53]); + } + + #[test] + #[allow(deprecated)] + fn test_weighted_clone_initialization() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let clone = initial.clone(); + assert_eq!(initial.weight, clone.weight); + assert_eq!(initial.item, clone.item); + } + + #[test] #[should_panic] + #[allow(deprecated)] + fn test_weighted_clone_change_weight() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.weight = 5; + assert_eq!(initial.weight, clone.weight); + } + + #[test] #[should_panic] + #[allow(deprecated)] + fn test_weighted_clone_change_item() { + let initial : Weighted<u32> = Weighted {weight: 1, item: 1}; + let mut clone = initial.clone(); + clone.item = 5; + assert_eq!(initial.item, clone.item); + + } + + #[test] #[should_panic] + #[allow(deprecated)] + fn test_weighted_choice_no_items() { + WeightedChoice::<isize>::new(&mut []); + } + #[test] #[should_panic] + #[allow(deprecated)] + fn test_weighted_choice_zero_weight() { + WeightedChoice::new(&mut [Weighted { weight: 0, item: 0}, + Weighted { weight: 0, item: 1}]); + } + #[test] #[should_panic] + #[allow(deprecated)] + fn test_weighted_choice_weight_overflows() { + let x = ::core::u32::MAX / 2; // x + x + 2 is the overflow + WeightedChoice::new(&mut [Weighted { weight: x, item: 0 }, + Weighted { weight: 1, item: 1 }, + Weighted { weight: x, item: 2 }, + Weighted { weight: 1, item: 3 }]); + } + + #[cfg(feature="std")] + #[test] + fn test_distributions_iter() { + use distributions::Normal; + let mut rng = ::test::rng(210); + let distr = Normal::new(10.0, 10.0); + let results: Vec<_> = distr.sample_iter(&mut rng).take(100).collect(); + println!("{:?}", results); + } +} diff --git a/rand/src/distributions/normal.rs b/rand/src/distributions/normal.rs new file mode 100644 index 000000000..089865e0a --- /dev/null +++ b/rand/src/distributions/normal.rs @@ -0,0 +1,197 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The normal and derived distributions. + +use Rng; +use distributions::{ziggurat_tables, Distribution, Open01}; +use distributions::utils::ziggurat; + +/// Samples floating-point numbers according to the normal distribution +/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to +/// `Normal::new(0.0, 1.0)` but faster. +/// +/// See `Normal` for the general normal distribution. +/// +/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. +/// +/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to +/// Generate Normal Random Samples*]( +/// https://www.doornik.com/research/ziggurat.pdf). +/// Nuffield College, Oxford +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::StandardNormal; +/// +/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct StandardNormal; + +impl Distribution<f64> for StandardNormal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + #[inline] + fn pdf(x: f64) -> f64 { + (-x*x/2.0).exp() + } + #[inline] + fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // do-while, so the condition should be true on the first + // run, they get overwritten anyway (0 < 1, so these are + // good). + let mut x = 1.0f64; + let mut y = 0.0f64; + + while -2.0 * y < x * x { + let x_: f64 = rng.sample(Open01); + let y_: f64 = rng.sample(Open01); + + x = x_.ln() / ziggurat_tables::ZIG_NORM_R; + y = y_.ln(); + } + + if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x } + } + + ziggurat(rng, true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, + pdf, zero_case) + } +} + +/// The normal distribution `N(mean, std_dev**2)`. +/// +/// This uses the ZIGNOR variant of the Ziggurat method, see [`StandardNormal`] +/// for more details. +/// +/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and +/// standard deviation 1. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Normal, Distribution}; +/// +/// // mean 2, standard deviation 3 +/// let normal = Normal::new(2.0, 3.0); +/// let v = normal.sample(&mut rand::thread_rng()); +/// println!("{} is from a N(2, 9) distribution", v) +/// ``` +/// +/// [`StandardNormal`]: crate::distributions::StandardNormal +#[derive(Clone, Copy, Debug)] +pub struct Normal { + mean: f64, + std_dev: f64, +} + +impl Normal { + /// Construct a new `Normal` distribution with the given mean and + /// standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> Normal { + assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0"); + Normal { + mean, + std_dev + } + } +} +impl Distribution<f64> for Normal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let n = rng.sample(StandardNormal); + self.mean + self.std_dev * n + } +} + + +/// The log-normal distribution `ln N(mean, std_dev**2)`. +/// +/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)` +/// distributed. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{LogNormal, Distribution}; +/// +/// // mean 2, standard deviation 3 +/// let log_normal = LogNormal::new(2.0, 3.0); +/// let v = log_normal.sample(&mut rand::thread_rng()); +/// println!("{} is from an ln N(2, 9) distribution", v) +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct LogNormal { + norm: Normal +} + +impl LogNormal { + /// Construct a new `LogNormal` distribution with the given mean + /// and standard deviation. + /// + /// # Panics + /// + /// Panics if `std_dev < 0`. + #[inline] + pub fn new(mean: f64, std_dev: f64) -> LogNormal { + assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0"); + LogNormal { norm: Normal::new(mean, std_dev) } + } +} +impl Distribution<f64> for LogNormal { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + self.norm.sample(rng).exp() + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::{Normal, LogNormal}; + + #[test] + fn test_normal() { + let norm = Normal::new(10.0, 10.0); + let mut rng = ::test::rng(210); + for _ in 0..1000 { + norm.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_normal_invalid_sd() { + Normal::new(10.0, -1.0); + } + + + #[test] + fn test_log_normal() { + let lnorm = LogNormal::new(10.0, 10.0); + let mut rng = ::test::rng(211); + for _ in 0..1000 { + lnorm.sample(&mut rng); + } + } + #[test] + #[should_panic] + fn test_log_normal_invalid_sd() { + LogNormal::new(10.0, -1.0); + } +} diff --git a/rand/src/distributions/other.rs b/rand/src/distributions/other.rs new file mode 100644 index 000000000..2295f790d --- /dev/null +++ b/rand/src/distributions/other.rs @@ -0,0 +1,219 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The implementations of the `Standard` distribution for other built-in types. + +use core::char; +use core::num::Wrapping; + +use {Rng}; +use distributions::{Distribution, Standard, Uniform}; + +// ----- Sampling distributions ----- + +/// Sample a `char`, uniformly distributed over ASCII letters and numbers: +/// a-z, A-Z and 0-9. +/// +/// # Example +/// +/// ``` +/// use std::iter; +/// use rand::{Rng, thread_rng}; +/// use rand::distributions::Alphanumeric; +/// +/// let mut rng = thread_rng(); +/// let chars: String = iter::repeat(()) +/// .map(|()| rng.sample(Alphanumeric)) +/// .take(7) +/// .collect(); +/// println!("Random chars: {}", chars); +/// ``` +#[derive(Debug)] +pub struct Alphanumeric; + + +// ----- Implementations of distributions ----- + +impl Distribution<char> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { + // A valid `char` is either in the interval `[0, 0xD800)` or + // `(0xDFFF, 0x11_0000)`. All `char`s must therefore be in + // `[0, 0x11_0000)` but not in the "gap" `[0xD800, 0xDFFF]` which is + // reserved for surrogates. This is the size of that gap. + const GAP_SIZE: u32 = 0xDFFF - 0xD800 + 1; + + // Uniform::new(0, 0x11_0000 - GAP_SIZE) can also be used but it + // seemed slower. + let range = Uniform::new(GAP_SIZE, 0x11_0000); + + let mut n = range.sample(rng); + if n <= 0xDFFF { + n -= GAP_SIZE; + } + unsafe { char::from_u32_unchecked(n) } + } +} + +impl Distribution<char> for Alphanumeric { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char { + const RANGE: u32 = 26 + 26 + 10; + const GEN_ASCII_STR_CHARSET: &[u8] = + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ + abcdefghijklmnopqrstuvwxyz\ + 0123456789"; + // We can pick from 62 characters. This is so close to a power of 2, 64, + // that we can do better than `Uniform`. Use a simple bitshift and + // rejection sampling. We do not use a bitmask, because for small RNGs + // the most significant bits are usually of higher quality. + loop { + let var = rng.next_u32() >> (32 - 6); + if var < RANGE { + return GEN_ASCII_STR_CHARSET[var as usize] as char + } + } + } +} + +impl Distribution<bool> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool { + // We can compare against an arbitrary bit of an u32 to get a bool. + // Because the least significant bits of a lower quality RNG can have + // simple patterns, we compare against the most significant bit. This is + // easiest done using a sign test. + (rng.next_u32() as i32) < 0 + } +} + +macro_rules! tuple_impl { + // use variables to indicate the arity of the tuple + ($($tyvar:ident),* ) => { + // the trailing commas are for the 1 tuple + impl< $( $tyvar ),* > + Distribution<( $( $tyvar ),* , )> + for Standard + where $( Standard: Distribution<$tyvar> ),* + { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> ( $( $tyvar ),* , ) { + ( + // use the $tyvar's to get the appropriate number of + // repeats (they're not actually needed) + $( + _rng.gen::<$tyvar>() + ),* + , + ) + } + } + } +} + +impl Distribution<()> for Standard { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () } +} +tuple_impl!{A} +tuple_impl!{A, B} +tuple_impl!{A, B, C} +tuple_impl!{A, B, C, D} +tuple_impl!{A, B, C, D, E} +tuple_impl!{A, B, C, D, E, F} +tuple_impl!{A, B, C, D, E, F, G} +tuple_impl!{A, B, C, D, E, F, G, H} +tuple_impl!{A, B, C, D, E, F, G, H, I} +tuple_impl!{A, B, C, D, E, F, G, H, I, J} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K} +tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} + +macro_rules! array_impl { + // recursive, given at least one type parameter: + {$n:expr, $t:ident, $($ts:ident,)*} => { + array_impl!{($n - 1), $($ts,)*} + + impl<T> Distribution<[T; $n]> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { + [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*] + } + } + }; + // empty case: + {$n:expr,} => { + impl<T> Distribution<[T; $n]> for Standard { + fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; $n] { [] } + } + }; +} + +array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,} + +impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> { + // UFCS is needed here: https://github.com/rust-lang/rust/issues/24066 + if rng.gen::<bool>() { + Some(rng.gen()) + } else { + None + } + } +} + +impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> { + Wrapping(rng.gen()) + } +} + + +#[cfg(test)] +mod tests { + use {Rng, RngCore, Standard}; + use distributions::Alphanumeric; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String; + + #[test] + fn test_misc() { + let rng: &mut RngCore = &mut ::test::rng(820); + + rng.sample::<char, _>(Standard); + rng.sample::<bool, _>(Standard); + } + + #[cfg(feature="alloc")] + #[test] + fn test_chars() { + use core::iter; + let mut rng = ::test::rng(805); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let word: String = iter::repeat(()) + .map(|()| rng.gen::<char>()).take(1000).collect(); + assert!(word.len() != 0); + } + + #[test] + fn test_alphanumeric() { + let mut rng = ::test::rng(806); + + // Test by generating a relatively large number of chars, so we also + // take the rejection sampling path. + let mut incorrect = false; + for _ in 0..100 { + let c = rng.sample(Alphanumeric); + incorrect |= !((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') ); + } + assert!(incorrect == false); + } +} diff --git a/rand/src/distributions/pareto.rs b/rand/src/distributions/pareto.rs new file mode 100644 index 000000000..744a157fd --- /dev/null +++ b/rand/src/distributions/pareto.rs @@ -0,0 +1,74 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Pareto distribution. + +use Rng; +use distributions::{Distribution, OpenClosed01}; + +/// Samples floating-point numbers according to the Pareto distribution +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Pareto; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.)); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Pareto { + scale: f64, + inv_neg_shape: f64, +} + +impl Pareto { + /// Construct a new Pareto distribution with given `scale` and `shape`. + /// + /// In the literature, `scale` is commonly written as x<sub>m</sub> or k and + /// `shape` is often written as α. + /// + /// # Panics + /// + /// `scale` and `shape` have to be non-zero and positive. + pub fn new(scale: f64, shape: f64) -> Pareto { + assert!((scale > 0.) & (shape > 0.)); + Pareto { scale, inv_neg_shape: -1.0 / shape } + } +} + +impl Distribution<f64> for Pareto { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let u: f64 = rng.sample(OpenClosed01); + self.scale * u.powf(self.inv_neg_shape) + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::Pareto; + + #[test] + #[should_panic] + fn invalid() { + Pareto::new(0., 0.); + } + + #[test] + fn sample() { + let scale = 1.0; + let shape = 2.0; + let d = Pareto::new(scale, shape); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + let r = d.sample(&mut rng); + assert!(r >= scale); + } + } +} diff --git a/rand/src/distributions/poisson.rs b/rand/src/distributions/poisson.rs new file mode 100644 index 000000000..1244caada --- /dev/null +++ b/rand/src/distributions/poisson.rs @@ -0,0 +1,157 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2016-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Poisson distribution. + +use Rng; +use distributions::{Distribution, Cauchy}; +use distributions::utils::log_gamma; + +/// The Poisson distribution `Poisson(lambda)`. +/// +/// This distribution has a density function: +/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Poisson, Distribution}; +/// +/// let poi = Poisson::new(2.0); +/// let v = poi.sample(&mut rand::thread_rng()); +/// println!("{} is from a Poisson(2) distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Poisson { + lambda: f64, + // precalculated values + exp_lambda: f64, + log_lambda: f64, + sqrt_2lambda: f64, + magic_val: f64, +} + +impl Poisson { + /// Construct a new `Poisson` with the given shape parameter + /// `lambda`. Panics if `lambda <= 0`. + pub fn new(lambda: f64) -> Poisson { + assert!(lambda > 0.0, "Poisson::new called with lambda <= 0"); + let log_lambda = lambda.ln(); + Poisson { + lambda, + exp_lambda: (-lambda).exp(), + log_lambda, + sqrt_2lambda: (2.0 * lambda).sqrt(), + magic_val: lambda * log_lambda - log_gamma(1.0 + lambda), + } + } +} + +impl Distribution<u64> for Poisson { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 { + // using the algorithm from Numerical Recipes in C + + // for low expected values use the Knuth method + if self.lambda < 12.0 { + let mut result = 0; + let mut p = 1.0; + while p > self.exp_lambda { + p *= rng.gen::<f64>(); + result += 1; + } + result - 1 + } + // high expected values - rejection method + else { + let mut int_result: u64; + + // we use the Cauchy distribution as the comparison distribution + // f(x) ~ 1/(1+x^2) + let cauchy = Cauchy::new(0.0, 1.0); + + loop { + let mut result; + let mut comp_dev; + + loop { + // draw from the Cauchy distribution + comp_dev = rng.sample(cauchy); + // shift the peak of the comparison ditribution + result = self.sqrt_2lambda * comp_dev + self.lambda; + // repeat the drawing until we are in the range of possible values + if result >= 0.0 { + break; + } + } + // now the result is a random variable greater than 0 with Cauchy distribution + // the result should be an integer value + result = result.floor(); + int_result = result as u64; + + // this is the ratio of the Poisson distribution to the comparison distribution + // the magic value scales the distribution function to a range of approximately 0-1 + // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1 + // this doesn't change the resulting distribution, only increases the rate of failed drawings + let check = 0.9 * (1.0 + comp_dev * comp_dev) + * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp(); + + // check with uniform random value - if below the threshold, we are within the target distribution + if rng.gen::<f64>() <= check { + break; + } + } + int_result + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Poisson; + + #[test] + fn test_poisson_10() { + let poisson = Poisson::new(10.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + fn test_poisson_15() { + // Take the 'high expected values' path + let poisson = Poisson::new(15.0); + let mut rng = ::test::rng(123); + let mut sum = 0; + for _ in 0..1000 { + sum += poisson.sample(&mut rng); + } + let avg = (sum as f64) / 1000.0; + println!("Poisson average: {}", avg); + assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_zero() { + Poisson::new(0.0); + } + + #[test] + #[should_panic] + fn test_poisson_invalid_lambda_neg() { + Poisson::new(-10.0); + } +} diff --git a/rand/src/distributions/triangular.rs b/rand/src/distributions/triangular.rs new file mode 100644 index 000000000..a6eef5c26 --- /dev/null +++ b/rand/src/distributions/triangular.rs @@ -0,0 +1,86 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! The triangular distribution. + +use Rng; +use distributions::{Distribution, Standard}; + +/// The triangular distribution. +/// +/// # Example +/// +/// ```rust +/// use rand::distributions::{Triangular, Distribution}; +/// +/// let d = Triangular::new(0., 5., 2.5); +/// let v = d.sample(&mut rand::thread_rng()); +/// println!("{} is from a triangular distribution", v); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Triangular { + min: f64, + max: f64, + mode: f64, +} + +impl Triangular { + /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode + /// `mode`. + /// + /// # Panics + /// + /// If `max < mode`, `mode < max` or `max == min`. + /// + #[inline] + pub fn new(min: f64, max: f64, mode: f64) -> Triangular { + assert!(max >= mode); + assert!(mode >= min); + assert!(max != min); + Triangular { min, max, mode } + } +} + +impl Distribution<f64> for Triangular { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let f: f64 = rng.sample(Standard); + let diff_mode_min = self.mode - self.min; + let diff_max_min = self.max - self.min; + if f * diff_max_min < diff_mode_min { + self.min + (f * diff_max_min * diff_mode_min).sqrt() + } else { + self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt() + } + } +} + +#[cfg(test)] +mod test { + use distributions::Distribution; + use super::Triangular; + + #[test] + fn test_new() { + for &(min, max, mode) in &[ + (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3), + (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17), + ] { + println!("{} {} {}", min, max, mode); + let _ = Triangular::new(min, max, mode); + } + } + + #[test] + fn test_sample() { + let norm = Triangular::new(0., 1., 0.5); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + norm.sample(&mut rng); + } + } +} diff --git a/rand/src/distributions/uniform.rs b/rand/src/distributions/uniform.rs new file mode 100644 index 000000000..19b49345b --- /dev/null +++ b/rand/src/distributions/uniform.rs @@ -0,0 +1,1283 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A distribution uniformly sampling numbers within a given range. +//! +//! [`Uniform`] is the standard distribution to sample uniformly from a range; +//! e.g. `Uniform::new_inclusive(1, 6)` can sample integers from 1 to 6, like a +//! standard die. [`Rng::gen_range`] supports any type supported by +//! [`Uniform`]. +//! +//! This distribution is provided with support for several primitive types +//! (all integer and floating-point types) as well as [`std::time::Duration`], +//! and supports extension to user-defined types via a type-specific *back-end* +//! implementation. +//! +//! The types [`UniformInt`], [`UniformFloat`] and [`UniformDuration`] are the +//! back-ends supporting sampling from primitive integer and floating-point +//! ranges as well as from [`std::time::Duration`]; these types do not normally +//! need to be used directly (unless implementing a derived back-end). +//! +//! # Example usage +//! +//! ``` +//! use rand::{Rng, thread_rng}; +//! use rand::distributions::Uniform; +//! +//! let mut rng = thread_rng(); +//! let side = Uniform::new(-10.0, 10.0); +//! +//! // sample between 1 and 10 points +//! for _ in 0..rng.gen_range(1, 11) { +//! // sample a point from the square with sides -10 - 10 in two dimensions +//! let (x, y) = (rng.sample(side), rng.sample(side)); +//! println!("Point: {}, {}", x, y); +//! } +//! ``` +//! +//! # Extending `Uniform` to support a custom type +//! +//! To extend [`Uniform`] to support your own types, write a back-end which +//! implements the [`UniformSampler`] trait, then implement the [`SampleUniform`] +//! helper trait to "register" your back-end. See the `MyF32` example below. +//! +//! At a minimum, the back-end needs to store any parameters needed for sampling +//! (e.g. the target range) and implement `new`, `new_inclusive` and `sample`. +//! Those methods should include an assert to check the range is valid (i.e. +//! `low < high`). The example below merely wraps another back-end. +//! +//! The `new`, `new_inclusive` and `sample_single` functions use arguments of +//! type SampleBorrow<X> in order to support passing in values by reference or +//! by value. In the implementation of these functions, you can choose to +//! simply use the reference returned by [`SampleBorrow::borrow`], or you can choose +//! to copy or clone the value, whatever is appropriate for your type. +//! +//! ``` +//! use rand::prelude::*; +//! use rand::distributions::uniform::{Uniform, SampleUniform, +//! UniformSampler, UniformFloat, SampleBorrow}; +//! +//! struct MyF32(f32); +//! +//! #[derive(Clone, Copy, Debug)] +//! struct UniformMyF32 { +//! inner: UniformFloat<f32>, +//! } +//! +//! impl UniformSampler for UniformMyF32 { +//! type X = MyF32; +//! fn new<B1, B2>(low: B1, high: B2) -> Self +//! where B1: SampleBorrow<Self::X> + Sized, +//! B2: SampleBorrow<Self::X> + Sized +//! { +//! UniformMyF32 { +//! inner: UniformFloat::<f32>::new(low.borrow().0, high.borrow().0), +//! } +//! } +//! fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self +//! where B1: SampleBorrow<Self::X> + Sized, +//! B2: SampleBorrow<Self::X> + Sized +//! { +//! UniformSampler::new(low, high) +//! } +//! fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { +//! MyF32(self.inner.sample(rng)) +//! } +//! } +//! +//! impl SampleUniform for MyF32 { +//! type Sampler = UniformMyF32; +//! } +//! +//! let (low, high) = (MyF32(17.0f32), MyF32(22.0f32)); +//! let uniform = Uniform::new(low, high); +//! let x = uniform.sample(&mut thread_rng()); +//! ``` +//! +//! [`SampleUniform`]: crate::distributions::uniform::SampleUniform +//! [`UniformSampler`]: crate::distributions::uniform::UniformSampler +//! [`UniformInt`]: crate::distributions::uniform::UniformInt +//! [`UniformFloat`]: crate::distributions::uniform::UniformFloat +//! [`UniformDuration`]: crate::distributions::uniform::UniformDuration +//! [`SampleBorrow::borrow`]: crate::distributions::uniform::SampleBorrow::borrow + +#[cfg(feature = "std")] +use std::time::Duration; +#[cfg(all(not(feature = "std"), rustc_1_25))] +use core::time::Duration; + +use Rng; +use distributions::Distribution; +use distributions::float::IntoFloat; +use distributions::utils::{WideningMultiply, FloatSIMDUtils, FloatAsSIMD, BoolAsSIMD}; + +#[cfg(not(feature = "std"))] +#[allow(unused_imports)] // rustc doesn't detect that this is actually used +use distributions::utils::Float; + + +#[cfg(feature="simd_support")] +use packed_simd::*; + +/// Sample values uniformly between two bounds. +/// +/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform +/// distribution sampling from the given range; these functions may do extra +/// work up front to make sampling of multiple values faster. +/// +/// When sampling from a constant range, many calculations can happen at +/// compile-time and all methods should be fast; for floating-point ranges and +/// the full range of integer types this should have comparable performance to +/// the `Standard` distribution. +/// +/// Steps are taken to avoid bias which might be present in naive +/// implementations; for example `rng.gen::<u8>() % 170` samples from the range +/// `[0, 169]` but is twice as likely to select numbers less than 85 than other +/// values. Further, the implementations here give more weight to the high-bits +/// generated by the RNG than the low bits, since with some RNGs the low-bits +/// are of lower quality than the high bits. +/// +/// Implementations must sample in `[low, high)` range for +/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must +/// be taken to ensure that rounding never results values `< low` or `>= high`. +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{Distribution, Uniform}; +/// +/// fn main() { +/// let between = Uniform::from(10..10000); +/// let mut rng = rand::thread_rng(); +/// let mut sum = 0; +/// for _ in 0..1000 { +/// sum += between.sample(&mut rng); +/// } +/// println!("{}", sum); +/// } +/// ``` +/// +/// [`new`]: Uniform::new +/// [`new_inclusive`]: Uniform::new_inclusive +#[derive(Clone, Copy, Debug)] +pub struct Uniform<X: SampleUniform> { + inner: X::Sampler, +} + +impl<X: SampleUniform> Uniform<X> { + /// Create a new `Uniform` instance which samples uniformly from the half + /// open range `[low, high)` (excluding `high`). Panics if `low >= high`. + pub fn new<B1, B2>(low: B1, high: B2) -> Uniform<X> + where B1: SampleBorrow<X> + Sized, + B2: SampleBorrow<X> + Sized + { + Uniform { inner: X::Sampler::new(low, high) } + } + + /// Create a new `Uniform` instance which samples uniformly from the closed + /// range `[low, high]` (inclusive). Panics if `low > high`. + pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Uniform<X> + where B1: SampleBorrow<X> + Sized, + B2: SampleBorrow<X> + Sized + { + Uniform { inner: X::Sampler::new_inclusive(low, high) } + } +} + +impl<X: SampleUniform> Distribution<X> for Uniform<X> { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> X { + self.inner.sample(rng) + } +} + +/// Helper trait for creating objects using the correct implementation of +/// [`UniformSampler`] for the sampling type. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// [module documentation]: crate::distributions::uniform +pub trait SampleUniform: Sized { + /// The `UniformSampler` implementation supporting type `X`. + type Sampler: UniformSampler<X = Self>; +} + +/// Helper trait handling actual uniform sampling. +/// +/// See the [module documentation] on how to implement [`Uniform`] range +/// sampling for a custom type. +/// +/// Implementation of [`sample_single`] is optional, and is only useful when +/// the implementation can be faster than `Self::new(low, high).sample(rng)`. +/// +/// [module documentation]: crate::distributions::uniform +/// [`sample_single`]: UniformSampler::sample_single +pub trait UniformSampler: Sized { + /// The type sampled by this implementation. + type X; + + /// Construct self, with inclusive lower bound and exclusive upper bound + /// `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new`, which asserts that `low < high` before calling this. + fn new<B1, B2>(low: B1, high: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized; + + /// Construct self, with inclusive bounds `[low, high]`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::new_inclusive`, which asserts that `low <= high` before + /// calling this. + fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized; + + /// Sample a value. + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X; + + /// Sample a single value uniformly from a range with inclusive lower bound + /// and exclusive upper bound `[low, high)`. + /// + /// Usually users should not call this directly but instead use + /// `Uniform::sample_single`, which asserts that `low < high` before calling + /// this. + /// + /// Via this method, implementations can provide a method optimized for + /// sampling only a single value from the specified range. The default + /// implementation simply calls `UniformSampler::new` then `sample` on the + /// result. + fn sample_single<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let uniform: Self = UniformSampler::new(low, high); + uniform.sample(rng) + } +} + +impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> { + fn from(r: ::core::ops::Range<X>) -> Uniform<X> { + Uniform::new(r.start, r.end) + } +} + +#[cfg(rustc_1_27)] +impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> { + fn from(r: ::core::ops::RangeInclusive<X>) -> Uniform<X> { + Uniform::new_inclusive(r.start(), r.end()) + } +} + +/// Helper trait similar to [`Borrow`] but implemented +/// only for SampleUniform and references to SampleUniform in +/// order to resolve ambiguity issues. +/// +/// [`Borrow`]: std::borrow::Borrow +pub trait SampleBorrow<Borrowed> { + /// Immutably borrows from an owned value. See [`Borrow::borrow`] + /// + /// [`Borrow::borrow`]: std::borrow::Borrow::borrow + fn borrow(&self) -> &Borrowed; +} +impl<Borrowed> SampleBorrow<Borrowed> for Borrowed where Borrowed: SampleUniform { + #[inline(always)] + fn borrow(&self) -> &Borrowed { self } +} +impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: SampleUniform { + #[inline(always)] + fn borrow(&self) -> &Borrowed { *self } +} + +//////////////////////////////////////////////////////////////////////////////// + +// What follows are all back-ends. + + +/// The back-end implementing [`UniformSampler`] for integer types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// For a closed range, the number of possible numbers we should generate is +/// `range = (high - low + 1)`. It is not possible to end up with a uniform +/// distribution if we map *all* the random integers that can be generated to +/// this range. We have to map integers from a `zone` that is a multiple of the +/// range. The rest of the integers, that cause a bias, are rejected. +/// +/// The problem with `range` is that to cover the full range of the type, it has +/// to store `unsigned_max + 1`, which can't be represented. But if the range +/// covers the full range of the type, no modulus is needed. A range of size 0 +/// can't exist, so we use that to represent this special case. Wrapping +/// arithmetic even makes representing `unsigned_max + 1` as 0 simple. +/// +/// We don't calculate `zone` directly, but first calculate the number of +/// integers to reject. To handle `unsigned_max + 1` not fitting in the type, +/// we use: +/// `ints_to_reject = (unsigned_max + 1) % range;` +/// `ints_to_reject = (unsigned_max - range + 1) % range;` +/// +/// The smallest integer PRNGs generate is `u32`. That is why for small integer +/// sizes (`i8`/`u8` and `i16`/`u16`) there is an optimization: don't pick the +/// largest zone that can fit in the small type, but pick the largest zone that +/// can fit in an `u32`. `ints_to_reject` is always less than half the size of +/// the small integer. This means the first bit of `zone` is always 1, and so +/// are all the other preceding bits of a larger integer. The easiest way to +/// grow the `zone` for the larger type is to simply sign extend it. +/// +/// An alternative to using a modulus is widening multiply: After a widening +/// multiply by `range`, the result is in the high word. Then comparing the low +/// word against `zone` makes sure our distribution is uniform. +#[derive(Clone, Copy, Debug)] +pub struct UniformInt<X> { + low: X, + range: X, + zone: X, +} + +macro_rules! uniform_int_impl { + ($ty:ty, $signed:ty, $unsigned:ident, + $i_large:ident, $u_large:ident) => { + impl SampleUniform for $ty { + type Sampler = UniformInt<$ty>; + } + + impl UniformSampler for UniformInt<$ty> { + // We play free and fast with unsigned vs signed here + // (when $ty is signed), but that's fine, since the + // contract of this macro is for $ty and $unsigned to be + // "bit-equal", so casting between them is a no-op. + + type X = $ty; + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformSampler::new_inclusive(low, high - 1) + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low <= high, + "Uniform::new_inclusive called with `low > high`"); + let unsigned_max = ::core::$unsigned::MAX; + + let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned; + let ints_to_reject = + if range > 0 { + (unsigned_max - range + 1) % range + } else { + 0 + }; + let zone = unsigned_max - ints_to_reject; + + UniformInt { + low: low, + // These are really $unsigned values, but store as $ty: + range: range as $ty, + zone: zone as $ty + } + } + + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + let range = self.range as $unsigned as $u_large; + if range > 0 { + // Grow `zone` to fit a type of at least 32 bits, by + // sign-extending it (the first bit is always 1, so are all + // the preceding bits of the larger type). + // For types that already have the right size, all the + // casting is a no-op. + let zone = self.zone as $signed as $i_large as $u_large; + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return self.low.wrapping_add(hi as $ty); + } + } + } else { + // Sample from the entire integer range. + rng.gen() + } + } + + fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, + "Uniform::sample_single called with low >= high"); + let range = high.wrapping_sub(low) as $unsigned as $u_large; + let zone = + if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned { + // Using a modulus is faster than the approximation for + // i8 and i16. I suppose we trade the cost of one + // modulus for near-perfect branch prediction. + let unsigned_max: $u_large = ::core::$u_large::MAX; + let ints_to_reject = (unsigned_max - range + 1) % range; + unsigned_max - ints_to_reject + } else { + // conservative but fast approximation. `- 1` is necessary to allow the + // same comparison without bias. + (range << range.leading_zeros()).wrapping_sub(1) + }; + + loop { + let v: $u_large = rng.gen(); + let (hi, lo) = v.wmul(range); + if lo <= zone { + return low.wrapping_add(hi as $ty); + } + } + } + } + } +} + +uniform_int_impl! { i8, i8, u8, i32, u32 } +uniform_int_impl! { i16, i16, u16, i32, u32 } +uniform_int_impl! { i32, i32, u32, i32, u32 } +uniform_int_impl! { i64, i64, u64, i64, u64 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +uniform_int_impl! { i128, i128, u128, u128, u128 } +uniform_int_impl! { isize, isize, usize, isize, usize } +uniform_int_impl! { u8, i8, u8, i32, u32 } +uniform_int_impl! { u16, i16, u16, i32, u32 } +uniform_int_impl! { u32, i32, u32, i32, u32 } +uniform_int_impl! { u64, i64, u64, i64, u64 } +uniform_int_impl! { usize, isize, usize, isize, usize } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +uniform_int_impl! { u128, u128, u128, i128, u128 } + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +macro_rules! uniform_simd_int_impl { + ($ty:ident, $unsigned:ident, $u_scalar:ident) => { + // The "pick the largest zone that can fit in an `u32`" optimization + // is less useful here. Multiple lanes complicate things, we don't + // know the PRNG's minimal output size, and casting to a larger vector + // is generally a bad idea for SIMD performance. The user can still + // implement it manually. + + // TODO: look into `Uniform::<u32x4>::new(0u32, 100)` functionality + // perhaps `impl SampleUniform for $u_scalar`? + impl SampleUniform for $ty { + type Sampler = UniformInt<$ty>; + } + + impl UniformSampler for UniformInt<$ty> { + type X = $ty; + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.lt(high).all(), "Uniform::new called with `low >= high`"); + UniformSampler::new_inclusive(low, high - 1) + } + + #[inline] // if the range is constant, this helps LLVM to do the + // calculations at compile-time. + fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.le(high).all(), + "Uniform::new_inclusive called with `low > high`"); + let unsigned_max = ::core::$u_scalar::MAX; + + // NOTE: these may need to be replaced with explicitly + // wrapping operations if `packed_simd` changes + let range: $unsigned = ((high - low) + 1).cast(); + // `% 0` will panic at runtime. + let not_full_range = range.gt($unsigned::splat(0)); + // replacing 0 with `unsigned_max` allows a faster `select` + // with bitwise OR + let modulo = not_full_range.select(range, $unsigned::splat(unsigned_max)); + // wrapping addition + let ints_to_reject = (unsigned_max - range + 1) % modulo; + // When `range` is 0, `lo` of `v.wmul(range)` will always be + // zero which means only one sample is needed. + let zone = unsigned_max - ints_to_reject; + + UniformInt { + low: low, + // These are really $unsigned values, but store as $ty: + range: range.cast(), + zone: zone.cast(), + } + } + + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + let range: $unsigned = self.range.cast(); + let zone: $unsigned = self.zone.cast(); + + // This might seem very slow, generating a whole new + // SIMD vector for every sample rejection. For most uses + // though, the chance of rejection is small and provides good + // general performance. With multiple lanes, that chance is + // multiplied. To mitigate this, we replace only the lanes of + // the vector which fail, iteratively reducing the chance of + // rejection. The replacement method does however add a little + // overhead. Benchmarking or calculating probabilities might + // reveal contexts where this replacement method is slower. + let mut v: $unsigned = rng.gen(); + loop { + let (hi, lo) = v.wmul(range); + let mask = lo.le(zone); + if mask.all() { + let hi: $ty = hi.cast(); + // wrapping addition + let result = self.low + hi; + // `select` here compiles to a blend operation + // When `range.eq(0).none()` the compare and blend + // operations are avoided. + let v: $ty = v.cast(); + return range.gt($unsigned::splat(0)).select(result, v); + } + // Replace only the failing lanes + v = mask.select(v, rng.gen()); + } + } + } + }; + + // bulk implementation + ($(($unsigned:ident, $signed:ident),)+ $u_scalar:ident) => { + $( + uniform_simd_int_impl!($unsigned, $unsigned, $u_scalar); + uniform_simd_int_impl!($signed, $unsigned, $u_scalar); + )+ + }; +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u64x2, i64x2), + (u64x4, i64x4), + (u64x8, i64x8), + u64 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u32x2, i32x2), + (u32x4, i32x4), + (u32x8, i32x8), + (u32x16, i32x16), + u32 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u16x2, i16x2), + (u16x4, i16x4), + (u16x8, i16x8), + (u16x16, i16x16), + (u16x32, i16x32), + u16 +} + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +uniform_simd_int_impl! { + (u8x2, i8x2), + (u8x4, i8x4), + (u8x8, i8x8), + (u8x16, i8x16), + (u8x32, i8x32), + (u8x64, i8x64), + u8 +} + + +/// The back-end implementing [`UniformSampler`] for floating-point types. +/// +/// Unless you are implementing [`UniformSampler`] for your own type, this type +/// should not be used directly, use [`Uniform`] instead. +/// +/// # Implementation notes +/// +/// Instead of generating a float in the `[0, 1)` range using [`Standard`], the +/// `UniformFloat` implementation converts the output of an PRNG itself. This +/// way one or two steps can be optimized out. +/// +/// The floats are first converted to a value in the `[1, 2)` interval using a +/// transmute-based method, and then mapped to the expected range with a +/// multiply and addition. Values produced this way have what equals 22 bits of +/// random digits for an `f32`, and 52 for an `f64`. +/// +/// [`new`]: UniformSampler::new +/// [`new_inclusive`]: UniformSampler::new_inclusive +/// [`Standard`]: crate::distributions::Standard +#[derive(Clone, Copy, Debug)] +pub struct UniformFloat<X> { + low: X, + scale: X, +} + +macro_rules! uniform_float_impl { + ($ty:ty, $uty:ident, $f_scalar:ident, $u_scalar:ident, $bits_to_discard:expr) => { + impl SampleUniform for $ty { + type Sampler = UniformFloat<$ty>; + } + + impl UniformSampler for UniformFloat<$ty> { + type X = $ty; + + fn new<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_lt(high), + "Uniform::new called with `low >= high`"); + assert!(low.all_finite() && high.all_finite(), + "Uniform::new called with non-finite boundaries"); + let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard) + .into_float_with_exponent(0) - 1.0); + + let mut scale = high - low; + + loop { + let mask = (scale * max_rand + low).ge_mask(high); + if mask.none() { + break; + } + scale = scale.decrease_masked(mask); + } + + debug_assert!(<$ty>::splat(0.0).all_le(scale)); + + UniformFloat { low, scale } + } + + fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_le(high), + "Uniform::new_inclusive called with `low > high`"); + assert!(low.all_finite() && high.all_finite(), + "Uniform::new_inclusive called with non-finite boundaries"); + let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard) + .into_float_with_exponent(0) - 1.0); + + let mut scale = (high - low) / max_rand; + + loop { + let mask = (scale * max_rand + low).gt_mask(high); + if mask.none() { + break; + } + scale = scale.decrease_masked(mask); + } + + debug_assert!(<$ty>::splat(0.0).all_le(scale)); + + UniformFloat { low, scale } + } + + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + // Generate a value in the range [1, 2) + let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard) + .into_float_with_exponent(0); + + // Get a value in the range [0, 1) in order to avoid + // overflowing into infinity when multiplying with scale + let value0_1 = value1_2 - 1.0; + + // We don't use `f64::mul_add`, because it is not available with + // `no_std`. Furthermore, it is slower for some targets (but + // faster for others). However, the order of multiplication and + // addition is important, because on some platforms (e.g. ARM) + // it will be optimized to a single (non-FMA) instruction. + value0_1 * self.scale + self.low + } + + #[inline] + fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) + -> Self::X + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low.all_lt(high), + "Uniform::sample_single called with low >= high"); + let mut scale = high - low; + + loop { + // Generate a value in the range [1, 2) + let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard) + .into_float_with_exponent(0); + + // Get a value in the range [0, 1) in order to avoid + // overflowing into infinity when multiplying with scale + let value0_1 = value1_2 - 1.0; + + // Doing multiply before addition allows some architectures + // to use a single instruction. + let res = value0_1 * scale + low; + + debug_assert!(low.all_le(res) || !scale.all_finite()); + if res.all_lt(high) { + return res; + } + + // This handles a number of edge cases. + // * `low` or `high` is NaN. In this case `scale` and + // `res` are going to end up as NaN. + // * `low` is negative infinity and `high` is finite. + // `scale` is going to be infinite and `res` will be + // NaN. + // * `high` is positive infinity and `low` is finite. + // `scale` is going to be infinite and `res` will + // be infinite or NaN (if value0_1 is 0). + // * `low` is negative infinity and `high` is positive + // infinity. `scale` will be infinite and `res` will + // be NaN. + // * `low` and `high` are finite, but `high - low` + // overflows to infinite. `scale` will be infinite + // and `res` will be infinite or NaN (if value0_1 is 0). + // So if `high` or `low` are non-finite, we are guaranteed + // to fail the `res < high` check above and end up here. + // + // While we technically should check for non-finite `low` + // and `high` before entering the loop, by doing the checks + // here instead, we allow the common case to avoid these + // checks. But we are still guaranteed that if `low` or + // `high` are non-finite we'll end up here and can do the + // appropriate checks. + // + // Likewise `high - low` overflowing to infinity is also + // rare, so handle it here after the common case. + let mask = !scale.finite_mask(); + if mask.any() { + assert!(low.all_finite() && high.all_finite(), + "Uniform::sample_single called with non-finite boundaries"); + scale = scale.decrease_masked(mask); + } + } + } + } + } +} + +uniform_float_impl! { f32, u32, f32, u32, 32 - 23 } +uniform_float_impl! { f64, u64, f64, u64, 64 - 52 } + +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x2, u32x2, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x4, u32x4, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x8, u32x8, f32, u32, 32 - 23 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f32x16, u32x16, f32, u32, 32 - 23 } + +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x2, u64x2, f64, u64, 64 - 52 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x4, u64x4, f64, u64, 64 - 52 } +#[cfg(feature="simd_support")] +uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 } + + + +/// The back-end implementing [`UniformSampler`] for `Duration`. +/// +/// Unless you are implementing [`UniformSampler`] for your own types, this type +/// should not be used directly, use [`Uniform`] instead. +#[cfg(any(feature = "std", rustc_1_25))] +#[derive(Clone, Copy, Debug)] +pub struct UniformDuration { + mode: UniformDurationMode, + offset: u32, +} + +#[cfg(any(feature = "std", rustc_1_25))] +#[derive(Debug, Copy, Clone)] +enum UniformDurationMode { + Small { + secs: u64, + nanos: Uniform<u32>, + }, + Medium { + nanos: Uniform<u64>, + }, + Large { + max_secs: u64, + max_nanos: u32, + secs: Uniform<u64>, + } +} + +#[cfg(any(feature = "std", rustc_1_25))] +impl SampleUniform for Duration { + type Sampler = UniformDuration; +} + +#[cfg(any(feature = "std", rustc_1_25))] +impl UniformSampler for UniformDuration { + type X = Duration; + + #[inline] + fn new<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low < high, "Uniform::new called with `low >= high`"); + UniformDuration::new_inclusive(low, high - Duration::new(0, 1)) + } + + #[inline] + fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + let low = *low_b.borrow(); + let high = *high_b.borrow(); + assert!(low <= high, "Uniform::new_inclusive called with `low > high`"); + + let low_s = low.as_secs(); + let low_n = low.subsec_nanos(); + let mut high_s = high.as_secs(); + let mut high_n = high.subsec_nanos(); + + if high_n < low_n { + high_s = high_s - 1; + high_n = high_n + 1_000_000_000; + } + + let mode = if low_s == high_s { + UniformDurationMode::Small { + secs: low_s, + nanos: Uniform::new_inclusive(low_n, high_n), + } + } else { + let max = high_s + .checked_mul(1_000_000_000) + .and_then(|n| n.checked_add(high_n as u64)); + + if let Some(higher_bound) = max { + let lower_bound = low_s * 1_000_000_000 + low_n as u64; + UniformDurationMode::Medium { + nanos: Uniform::new_inclusive(lower_bound, higher_bound), + } + } else { + // An offset is applied to simplify generation of nanoseconds + let max_nanos = high_n - low_n; + UniformDurationMode::Large { + max_secs: high_s, + max_nanos, + secs: Uniform::new_inclusive(low_s, high_s), + } + } + }; + UniformDuration { + mode, + offset: low_n, + } + } + + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration { + match self.mode { + UniformDurationMode::Small { secs, nanos } => { + let n = nanos.sample(rng); + Duration::new(secs, n) + } + UniformDurationMode::Medium { nanos } => { + let nanos = nanos.sample(rng); + Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32) + } + UniformDurationMode::Large { max_secs, max_nanos, secs } => { + // constant folding means this is at least as fast as `gen_range` + let nano_range = Uniform::new(0, 1_000_000_000); + loop { + let s = secs.sample(rng); + let n = nano_range.sample(rng); + if !(s == max_secs && n > max_nanos) { + let sum = n + self.offset; + break Duration::new(s, sum); + } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use Rng; + use rngs::mock::StepRng; + use distributions::uniform::Uniform; + use distributions::utils::FloatAsSIMD; + #[cfg(feature="simd_support")] use packed_simd::*; + + #[should_panic] + #[test] + fn test_uniform_bad_limits_equal_int() { + Uniform::new(10, 10); + } + + #[test] + fn test_uniform_good_limits_equal_int() { + let mut rng = ::test::rng(804); + let dist = Uniform::new_inclusive(10, 10); + for _ in 0..20 { + assert_eq!(rng.sample(dist), 10); + } + } + + #[should_panic] + #[test] + fn test_uniform_bad_limits_flipped_int() { + Uniform::new(10, 5); + } + + #[test] + fn test_integers() { + use core::{i8, i16, i32, i64, isize}; + use core::{u8, u16, u32, u64, usize}; + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + use core::{i128, u128}; + + let mut rng = ::test::rng(251); + macro_rules! t { + ($ty:ident, $v:expr, $le:expr, $lt:expr) => {{ + for &(low, high) in $v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $lt(v, high)); + } + + let my_uniform = Uniform::new_inclusive(low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $le(v, high)); + } + + let my_uniform = Uniform::new(&low, high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $lt(v, high)); + } + + let my_uniform = Uniform::new_inclusive(&low, &high); + for _ in 0..1000 { + let v: $ty = rng.sample(my_uniform); + assert!($le(low, v) && $le(v, high)); + } + + for _ in 0..1000 { + let v: $ty = rng.gen_range(low, high); + assert!($le(low, v) && $lt(v, high)); + } + } + }}; + + // scalar bulk + ($($ty:ident),*) => {{ + $(t!( + $ty, + [(0, 10), (10, 127), ($ty::MIN, $ty::MAX)], + |x, y| x <= y, + |x, y| x < y + );)* + }}; + + // simd bulk + ($($ty:ident),* => $scalar:ident) => {{ + $(t!( + $ty, + [ + ($ty::splat(0), $ty::splat(10)), + ($ty::splat(10), $ty::splat(127)), + ($ty::splat($scalar::MIN), $ty::splat($scalar::MAX)), + ], + |x: $ty, y| x.le(y).all(), + |x: $ty, y| x.lt(y).all() + );)* + }}; + } + t!(i8, i16, i32, i64, isize, + u8, u16, u32, u64, usize); + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + t!(i128, u128); + + #[cfg(all(feature = "simd_support", feature = "nightly"))] + { + t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8); + t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8); + t!(u16x2, u16x4, u16x8, u16x16, u16x32 => u16); + t!(i16x2, i16x4, i16x8, i16x16, i16x32 => i16); + t!(u32x2, u32x4, u32x8, u32x16 => u32); + t!(i32x2, i32x4, i32x8, i32x16 => i32); + t!(u64x2, u64x4, u64x8 => u64); + t!(i64x2, i64x4, i64x8 => i64); + } + } + + #[test] + fn test_floats() { + let mut rng = ::test::rng(252); + let mut zero_rng = StepRng::new(0, 0); + let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0); + macro_rules! t { + ($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{ + let v: &[($f_scalar, $f_scalar)]= + &[(0.0, 100.0), + (-1e35, -1e25), + (1e-35, 1e-25), + (-1e35, 1e35), + (<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)), + (-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)), + (-<$f_scalar>::from_bits(5), 0.0), + (-<$f_scalar>::from_bits(7), -0.0), + (10.0, ::core::$f_scalar::MAX), + (-100.0, ::core::$f_scalar::MAX), + (-::core::$f_scalar::MAX / 5.0, ::core::$f_scalar::MAX), + (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX / 5.0), + (-::core::$f_scalar::MAX * 0.8, ::core::$f_scalar::MAX * 0.7), + (-::core::$f_scalar::MAX, ::core::$f_scalar::MAX), + ]; + for &(low_scalar, high_scalar) in v.iter() { + for lane in 0..<$ty>::lanes() { + let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar); + let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar); + let my_uniform = Uniform::new(low, high); + let my_incl_uniform = Uniform::new_inclusive(low, high); + for _ in 0..100 { + let v = rng.sample(my_uniform).extract(lane); + assert!(low_scalar <= v && v < high_scalar); + let v = rng.sample(my_incl_uniform).extract(lane); + assert!(low_scalar <= v && v <= high_scalar); + let v = rng.gen_range(low, high).extract(lane); + assert!(low_scalar <= v && v < high_scalar); + } + + assert_eq!(rng.sample(Uniform::new_inclusive(low, low)).extract(lane), low_scalar); + + assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar); + assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar); + assert_eq!(zero_rng.gen_range(low, high).extract(lane), low_scalar); + assert!(max_rng.sample(my_uniform).extract(lane) < high_scalar); + assert!(max_rng.sample(my_incl_uniform).extract(lane) <= high_scalar); + + // Don't run this test for really tiny differences between high and low + // since for those rounding might result in selecting high for a very + // long time. + if (high_scalar - low_scalar) > 0.0001 { + let mut lowering_max_rng = + StepRng::new(0xffff_ffff_ffff_ffff, + (-1i64 << $bits_shifted) as u64); + assert!(lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar); + } + } + } + + assert_eq!(rng.sample(Uniform::new_inclusive(::core::$f_scalar::MAX, + ::core::$f_scalar::MAX)), + ::core::$f_scalar::MAX); + assert_eq!(rng.sample(Uniform::new_inclusive(-::core::$f_scalar::MAX, + -::core::$f_scalar::MAX)), + -::core::$f_scalar::MAX); + }} + } + + t!(f32, f32, 32 - 23); + t!(f64, f64, 64 - 52); + #[cfg(feature="simd_support")] + { + t!(f32x2, f32, 32 - 23); + t!(f32x4, f32, 32 - 23); + t!(f32x8, f32, 32 - 23); + t!(f32x16, f32, 32 - 23); + t!(f64x2, f64, 64 - 52); + t!(f64x4, f64, 64 - 52); + t!(f64x8, f64, 64 - 52); + } + } + + #[test] + #[cfg(all(feature="std", + not(target_arch = "wasm32"), + not(target_arch = "asmjs")))] + fn test_float_assertions() { + use std::panic::catch_unwind; + use super::SampleUniform; + fn range<T: SampleUniform>(low: T, high: T) { + let mut rng = ::test::rng(253); + rng.gen_range(low, high); + } + + macro_rules! t { + ($ty:ident, $f_scalar:ident) => {{ + let v: &[($f_scalar, $f_scalar)] = + &[(::std::$f_scalar::NAN, 0.0), + (1.0, ::std::$f_scalar::NAN), + (::std::$f_scalar::NAN, ::std::$f_scalar::NAN), + (1.0, 0.5), + (::std::$f_scalar::MAX, -::std::$f_scalar::MAX), + (::std::$f_scalar::INFINITY, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NEG_INFINITY), + (::std::$f_scalar::NEG_INFINITY, 5.0), + (5.0, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NAN, ::std::$f_scalar::INFINITY), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NAN), + (::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::INFINITY), + ]; + for &(low_scalar, high_scalar) in v.iter() { + for lane in 0..<$ty>::lanes() { + let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar); + let high = <$ty>::splat(1.0 as $f_scalar).replace(lane, high_scalar); + assert!(catch_unwind(|| range(low, high)).is_err()); + assert!(catch_unwind(|| Uniform::new(low, high)).is_err()); + assert!(catch_unwind(|| Uniform::new_inclusive(low, high)).is_err()); + assert!(catch_unwind(|| range(low, low)).is_err()); + assert!(catch_unwind(|| Uniform::new(low, low)).is_err()); + } + } + }} + } + + t!(f32, f32); + t!(f64, f64); + #[cfg(feature="simd_support")] + { + t!(f32x2, f32); + t!(f32x4, f32); + t!(f32x8, f32); + t!(f32x16, f32); + t!(f64x2, f64); + t!(f64x4, f64); + t!(f64x8, f64); + } + } + + + #[test] + #[cfg(any(feature = "std", rustc_1_25))] + fn test_durations() { + #[cfg(feature = "std")] + use std::time::Duration; + #[cfg(all(not(feature = "std"), rustc_1_25))] + use core::time::Duration; + + let mut rng = ::test::rng(253); + + let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)), + (Duration::new(0, 100), Duration::new(1, 50)), + (Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))]; + for &(low, high) in v.iter() { + let my_uniform = Uniform::new(low, high); + for _ in 0..1000 { + let v = rng.sample(my_uniform); + assert!(low <= v && v < high); + } + } + } + + #[test] + fn test_custom_uniform() { + use distributions::uniform::{UniformSampler, UniformFloat, SampleUniform, SampleBorrow}; + #[derive(Clone, Copy, PartialEq, PartialOrd)] + struct MyF32 { + x: f32, + } + #[derive(Clone, Copy, Debug)] + struct UniformMyF32 { + inner: UniformFloat<f32>, + } + impl UniformSampler for UniformMyF32 { + type X = MyF32; + fn new<B1, B2>(low: B1, high: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + UniformMyF32 { + inner: UniformFloat::<f32>::new(low.borrow().x, high.borrow().x), + } + } + fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self + where B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized + { + UniformSampler::new(low, high) + } + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X { + MyF32 { x: self.inner.sample(rng) } + } + } + impl SampleUniform for MyF32 { + type Sampler = UniformMyF32; + } + + let (low, high) = (MyF32{ x: 17.0f32 }, MyF32{ x: 22.0f32 }); + let uniform = Uniform::new(low, high); + let mut rng = ::test::rng(804); + for _ in 0..100 { + let x: MyF32 = rng.sample(uniform); + assert!(low <= x && x < high); + } + } + + #[test] + fn test_uniform_from_std_range() { + let r = Uniform::from(2u32..7); + assert_eq!(r.inner.low, 2); + assert_eq!(r.inner.range, 5); + let r = Uniform::from(2.0f64..7.0); + assert_eq!(r.inner.low, 2.0); + assert_eq!(r.inner.scale, 5.0); + } + + #[cfg(rustc_1_27)] + #[test] + fn test_uniform_from_std_range_inclusive() { + let r = Uniform::from(2u32..=6); + assert_eq!(r.inner.low, 2); + assert_eq!(r.inner.range, 5); + let r = Uniform::from(2.0f64..=7.0); + assert_eq!(r.inner.low, 2.0); + assert!(r.inner.scale > 5.0); + assert!(r.inner.scale < 5.0 + 1e-14); + } +} diff --git a/rand/src/distributions/unit_circle.rs b/rand/src/distributions/unit_circle.rs new file mode 100644 index 000000000..01ab76a38 --- /dev/null +++ b/rand/src/distributions/unit_circle.rs @@ -0,0 +1,101 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::{Distribution, Uniform}; + +/// Samples uniformly from the edge of the unit circle in two dimensions. +/// +/// Implemented via a method by von Neumann[^1]. +/// +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{UnitCircle, Distribution}; +/// +/// let circle = UnitCircle::new(); +/// let v = circle.sample(&mut rand::thread_rng()); +/// println!("{:?} is from the unit circle.", v) +/// ``` +/// +/// [^1]: von Neumann, J. (1951) [*Various Techniques Used in Connection with +/// Random Digits.*](https://mcnp.lanl.gov/pdf_files/nbs_vonneumann.pdf) +/// NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing +/// Office, pp. 36-38. +#[derive(Clone, Copy, Debug)] +pub struct UnitCircle; + +impl UnitCircle { + /// Construct a new `UnitCircle` distribution. + #[inline] + pub fn new() -> UnitCircle { + UnitCircle + } +} + +impl Distribution<[f64; 2]> for UnitCircle { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] { + let uniform = Uniform::new(-1., 1.); + let mut x1; + let mut x2; + let mut sum; + loop { + x1 = uniform.sample(rng); + x2 = uniform.sample(rng); + sum = x1*x1 + x2*x2; + if sum < 1. { + break; + } + } + let diff = x1*x1 - x2*x2; + [diff / sum, 2.*x1*x2 / sum] + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::UnitCircle; + + /// Assert that two numbers are almost equal to each other. + /// + /// On panic, this macro will print the values of the expressions with their + /// debug representations. + macro_rules! assert_almost_eq { + ($a:expr, $b:expr, $prec:expr) => ( + let diff = ($a - $b).abs(); + if diff > $prec { + panic!(format!( + "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ + (left: `{}`, right: `{}`)", + diff, $prec, $a, $b)); + } + ); + } + + #[test] + fn norm() { + let mut rng = ::test::rng(1); + let dist = UnitCircle::new(); + for _ in 0..1000 { + let x = dist.sample(&mut rng); + assert_almost_eq!(x[0]*x[0] + x[1]*x[1], 1., 1e-15); + } + } + + #[test] + fn value_stability() { + let mut rng = ::test::rng(2); + let dist = UnitCircle::new(); + assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]); + assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]); + assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]); + } +} diff --git a/rand/src/distributions/unit_sphere.rs b/rand/src/distributions/unit_sphere.rs new file mode 100644 index 000000000..37de88b6a --- /dev/null +++ b/rand/src/distributions/unit_sphere.rs @@ -0,0 +1,99 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::{Distribution, Uniform}; + +/// Samples uniformly from the surface of the unit sphere in three dimensions. +/// +/// Implemented via a method by Marsaglia[^1]. +/// +/// +/// # Example +/// +/// ``` +/// use rand::distributions::{UnitSphereSurface, Distribution}; +/// +/// let sphere = UnitSphereSurface::new(); +/// let v = sphere.sample(&mut rand::thread_rng()); +/// println!("{:?} is from the unit sphere surface.", v) +/// ``` +/// +/// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a +/// Sphere.*](https://doi.org/10.1214/aoms/1177692644) +/// Ann. Math. Statist. 43, no. 2, 645--646. +#[derive(Clone, Copy, Debug)] +pub struct UnitSphereSurface; + +impl UnitSphereSurface { + /// Construct a new `UnitSphereSurface` distribution. + #[inline] + pub fn new() -> UnitSphereSurface { + UnitSphereSurface + } +} + +impl Distribution<[f64; 3]> for UnitSphereSurface { + #[inline] + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] { + let uniform = Uniform::new(-1., 1.); + loop { + let (x1, x2) = (uniform.sample(rng), uniform.sample(rng)); + let sum = x1*x1 + x2*x2; + if sum >= 1. { + continue; + } + let factor = 2. * (1.0_f64 - sum).sqrt(); + return [x1 * factor, x2 * factor, 1. - 2.*sum]; + } + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::UnitSphereSurface; + + /// Assert that two numbers are almost equal to each other. + /// + /// On panic, this macro will print the values of the expressions with their + /// debug representations. + macro_rules! assert_almost_eq { + ($a:expr, $b:expr, $prec:expr) => ( + let diff = ($a - $b).abs(); + if diff > $prec { + panic!(format!( + "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ + (left: `{}`, right: `{}`)", + diff, $prec, $a, $b)); + } + ); + } + + #[test] + fn norm() { + let mut rng = ::test::rng(1); + let dist = UnitSphereSurface::new(); + for _ in 0..1000 { + let x = dist.sample(&mut rng); + assert_almost_eq!(x[0]*x[0] + x[1]*x[1] + x[2]*x[2], 1., 1e-15); + } + } + + #[test] + fn value_stability() { + let mut rng = ::test::rng(2); + let dist = UnitSphereSurface::new(); + assert_eq!(dist.sample(&mut rng), + [-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]); + assert_eq!(dist.sample(&mut rng), + [0.47604534507233487, -0.797200864987207, -0.3712837328763685]); + assert_eq!(dist.sample(&mut rng), + [0.9795722330927367, 0.18692349236651176, 0.07414747571708524]); + } +} diff --git a/rand/src/distributions/utils.rs b/rand/src/distributions/utils.rs new file mode 100644 index 000000000..d4d364263 --- /dev/null +++ b/rand/src/distributions/utils.rs @@ -0,0 +1,504 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Math helper functions + +#[cfg(feature="simd_support")] +use packed_simd::*; +#[cfg(feature="std")] +use distributions::ziggurat_tables; +#[cfg(feature="std")] +use Rng; + + +pub trait WideningMultiply<RHS = Self> { + type Output; + + fn wmul(self, x: RHS) -> Self::Output; +} + +macro_rules! wmul_impl { + ($ty:ty, $wide:ty, $shift:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + let tmp = (self as $wide) * (x as $wide); + ((tmp >> $shift) as $ty, tmp as $ty) + } + } + }; + + // simd bulk implementation + ($(($ty:ident, $wide:ident),)+, $shift:expr) => { + $( + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + // For supported vectors, this should compile to a couple + // supported multiply & swizzle instructions (no actual + // casting). + // TODO: optimize + let y: $wide = self.cast(); + let x: $wide = x.cast(); + let tmp = y * x; + let hi: $ty = (tmp >> $shift).cast(); + let lo: $ty = tmp.cast(); + (hi, lo) + } + } + )+ + }; +} +wmul_impl! { u8, u16, 8 } +wmul_impl! { u16, u32, 16 } +wmul_impl! { u32, u64, 32 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +wmul_impl! { u64, u128, 64 } + +// This code is a translation of the __mulddi3 function in LLVM's +// compiler-rt. It is an optimised variant of the common method +// `(a + b) * (c + d) = ac + ad + bc + bd`. +// +// For some reason LLVM can optimise the C version very well, but +// keeps shuffling registers in this Rust translation. +macro_rules! wmul_impl_large { + ($ty:ty, $half:expr) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, b: $ty) -> Self::Output { + const LOWER_MASK: $ty = !0 >> $half; + let mut low = (self & LOWER_MASK).wrapping_mul(b & LOWER_MASK); + let mut t = low >> $half; + low &= LOWER_MASK; + t += (self >> $half).wrapping_mul(b & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + let mut high = t >> $half; + t = low >> $half; + low &= LOWER_MASK; + t += (b >> $half).wrapping_mul(self & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + high += t >> $half; + high += (self >> $half).wrapping_mul(b >> $half); + + (high, low) + } + } + }; + + // simd bulk implementation + (($($ty:ty,)+) $scalar:ty, $half:expr) => { + $( + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, b: $ty) -> Self::Output { + // needs wrapping multiplication + const LOWER_MASK: $scalar = !0 >> $half; + let mut low = (self & LOWER_MASK) * (b & LOWER_MASK); + let mut t = low >> $half; + low &= LOWER_MASK; + t += (self >> $half) * (b & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + let mut high = t >> $half; + t = low >> $half; + low &= LOWER_MASK; + t += (b >> $half) * (self & LOWER_MASK); + low += (t & LOWER_MASK) << $half; + high += t >> $half; + high += (self >> $half) * (b >> $half); + + (high, low) + } + } + )+ + }; +} +#[cfg(not(all(rustc_1_26, not(target_os = "emscripten"))))] +wmul_impl_large! { u64, 32 } +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] +wmul_impl_large! { u128, 64 } + +macro_rules! wmul_impl_usize { + ($ty:ty) => { + impl WideningMultiply for usize { + type Output = (usize, usize); + + #[inline(always)] + fn wmul(self, x: usize) -> Self::Output { + let (high, low) = (self as $ty).wmul(x as $ty); + (high as usize, low as usize) + } + } + } +} +#[cfg(target_pointer_width = "32")] +wmul_impl_usize! { u32 } +#[cfg(target_pointer_width = "64")] +wmul_impl_usize! { u64 } + +#[cfg(all(feature = "simd_support", feature = "nightly"))] +mod simd_wmul { + #[cfg(target_arch = "x86")] + use core::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::*; + use super::*; + + wmul_impl! { + (u8x2, u16x2), + (u8x4, u16x4), + (u8x8, u16x8), + (u8x16, u16x16), + (u8x32, u16x32),, + 8 + } + + wmul_impl! { (u16x2, u32x2),, 16 } + #[cfg(not(target_feature = "sse2"))] + wmul_impl! { (u16x4, u32x4),, 16 } + #[cfg(not(target_feature = "sse4.2"))] + wmul_impl! { (u16x8, u32x8),, 16 } + #[cfg(not(target_feature = "avx2"))] + wmul_impl! { (u16x16, u32x16),, 16 } + + // 16-bit lane widths allow use of the x86 `mulhi` instructions, which + // means `wmul` can be implemented with only two instructions. + #[allow(unused_macros)] + macro_rules! wmul_impl_16 { + ($ty:ident, $intrinsic:ident, $mulhi:ident, $mullo:ident) => { + impl WideningMultiply for $ty { + type Output = ($ty, $ty); + + #[inline(always)] + fn wmul(self, x: $ty) -> Self::Output { + let b = $intrinsic::from_bits(x); + let a = $intrinsic::from_bits(self); + let hi = $ty::from_bits(unsafe { $mulhi(a, b) }); + let lo = $ty::from_bits(unsafe { $mullo(a, b) }); + (hi, lo) + } + } + }; + } + + #[cfg(target_feature = "sse2")] + wmul_impl_16! { u16x4, __m64, _mm_mulhi_pu16, _mm_mullo_pi16 } + #[cfg(target_feature = "sse4.2")] + wmul_impl_16! { u16x8, __m128i, _mm_mulhi_epu16, _mm_mullo_epi16 } + #[cfg(target_feature = "avx2")] + wmul_impl_16! { u16x16, __m256i, _mm256_mulhi_epu16, _mm256_mullo_epi16 } + // FIXME: there are no `__m512i` types in stdsimd yet, so `wmul::<u16x32>` + // cannot use the same implementation. + + wmul_impl! { + (u32x2, u64x2), + (u32x4, u64x4), + (u32x8, u64x8),, + 32 + } + + // TODO: optimize, this seems to seriously slow things down + wmul_impl_large! { (u8x64,) u8, 4 } + wmul_impl_large! { (u16x32,) u16, 8 } + wmul_impl_large! { (u32x16,) u32, 16 } + wmul_impl_large! { (u64x2, u64x4, u64x8,) u64, 32 } +} +#[cfg(all(feature = "simd_support", feature = "nightly"))] +pub use self::simd_wmul::*; + + +/// Helper trait when dealing with scalar and SIMD floating point types. +pub(crate) trait FloatSIMDUtils { + // `PartialOrd` for vectors compares lexicographically. We want to compare all + // the individual SIMD lanes instead, and get the combined result over all + // lanes. This is possible using something like `a.lt(b).all()`, but we + // implement it as a trait so we can write the same code for `f32` and `f64`. + // Only the comparison functions we need are implemented. + fn all_lt(self, other: Self) -> bool; + fn all_le(self, other: Self) -> bool; + fn all_finite(self) -> bool; + + type Mask; + fn finite_mask(self) -> Self::Mask; + fn gt_mask(self, other: Self) -> Self::Mask; + fn ge_mask(self, other: Self) -> Self::Mask; + + // Decrease all lanes where the mask is `true` to the next lower value + // representable by the floating-point type. At least one of the lanes + // must be set. + fn decrease_masked(self, mask: Self::Mask) -> Self; + + // Convert from int value. Conversion is done while retaining the numerical + // value, not by retaining the binary representation. + type UInt; + fn cast_from_int(i: Self::UInt) -> Self; +} + +/// Implement functions available in std builds but missing from core primitives +#[cfg(not(std))] +pub(crate) trait Float : Sized { + type Bits; + + fn is_nan(self) -> bool; + fn is_infinite(self) -> bool; + fn is_finite(self) -> bool; + fn to_bits(self) -> Self::Bits; + fn from_bits(v: Self::Bits) -> Self; +} + +/// Implement functions on f32/f64 to give them APIs similar to SIMD types +pub(crate) trait FloatAsSIMD : Sized { + #[inline(always)] + fn lanes() -> usize { 1 } + #[inline(always)] + fn splat(scalar: Self) -> Self { scalar } + #[inline(always)] + fn extract(self, index: usize) -> Self { debug_assert_eq!(index, 0); self } + #[inline(always)] + fn replace(self, index: usize, new_value: Self) -> Self { debug_assert_eq!(index, 0); new_value } +} + +pub(crate) trait BoolAsSIMD : Sized { + fn any(self) -> bool; + fn all(self) -> bool; + fn none(self) -> bool; +} + +impl BoolAsSIMD for bool { + #[inline(always)] + fn any(self) -> bool { self } + #[inline(always)] + fn all(self) -> bool { self } + #[inline(always)] + fn none(self) -> bool { !self } +} + +macro_rules! scalar_float_impl { + ($ty:ident, $uty:ident) => { + #[cfg(not(std))] + impl Float for $ty { + type Bits = $uty; + + #[inline] + fn is_nan(self) -> bool { + self != self + } + + #[inline] + fn is_infinite(self) -> bool { + self == ::core::$ty::INFINITY || self == ::core::$ty::NEG_INFINITY + } + + #[inline] + fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } + + #[inline] + fn to_bits(self) -> Self::Bits { + unsafe { ::core::mem::transmute(self) } + } + + #[inline] + fn from_bits(v: Self::Bits) -> Self { + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { ::core::mem::transmute(v) } + } + } + + impl FloatSIMDUtils for $ty { + type Mask = bool; + #[inline(always)] + fn all_lt(self, other: Self) -> bool { self < other } + #[inline(always)] + fn all_le(self, other: Self) -> bool { self <= other } + #[inline(always)] + fn all_finite(self) -> bool { self.is_finite() } + #[inline(always)] + fn finite_mask(self) -> Self::Mask { self.is_finite() } + #[inline(always)] + fn gt_mask(self, other: Self) -> Self::Mask { self > other } + #[inline(always)] + fn ge_mask(self, other: Self) -> Self::Mask { self >= other } + #[inline(always)] + fn decrease_masked(self, mask: Self::Mask) -> Self { + debug_assert!(mask, "At least one lane must be set"); + <$ty>::from_bits(self.to_bits() - 1) + } + type UInt = $uty; + fn cast_from_int(i: Self::UInt) -> Self { i as $ty } + } + + impl FloatAsSIMD for $ty {} + } +} + +scalar_float_impl!(f32, u32); +scalar_float_impl!(f64, u64); + + +#[cfg(feature="simd_support")] +macro_rules! simd_impl { + ($ty:ident, $f_scalar:ident, $mty:ident, $uty:ident) => { + impl FloatSIMDUtils for $ty { + type Mask = $mty; + #[inline(always)] + fn all_lt(self, other: Self) -> bool { self.lt(other).all() } + #[inline(always)] + fn all_le(self, other: Self) -> bool { self.le(other).all() } + #[inline(always)] + fn all_finite(self) -> bool { self.finite_mask().all() } + #[inline(always)] + fn finite_mask(self) -> Self::Mask { + // This can possibly be done faster by checking bit patterns + let neg_inf = $ty::splat(::core::$f_scalar::NEG_INFINITY); + let pos_inf = $ty::splat(::core::$f_scalar::INFINITY); + self.gt(neg_inf) & self.lt(pos_inf) + } + #[inline(always)] + fn gt_mask(self, other: Self) -> Self::Mask { self.gt(other) } + #[inline(always)] + fn ge_mask(self, other: Self) -> Self::Mask { self.ge(other) } + #[inline(always)] + fn decrease_masked(self, mask: Self::Mask) -> Self { + // Casting a mask into ints will produce all bits set for + // true, and 0 for false. Adding that to the binary + // representation of a float means subtracting one from + // the binary representation, resulting in the next lower + // value representable by $ty. This works even when the + // current value is infinity. + debug_assert!(mask.any(), "At least one lane must be set"); + <$ty>::from_bits(<$uty>::from_bits(self) + <$uty>::from_bits(mask)) + } + type UInt = $uty; + fn cast_from_int(i: Self::UInt) -> Self { i.cast() } + } + } +} + +#[cfg(feature="simd_support")] simd_impl! { f32x2, f32, m32x2, u32x2 } +#[cfg(feature="simd_support")] simd_impl! { f32x4, f32, m32x4, u32x4 } +#[cfg(feature="simd_support")] simd_impl! { f32x8, f32, m32x8, u32x8 } +#[cfg(feature="simd_support")] simd_impl! { f32x16, f32, m32x16, u32x16 } +#[cfg(feature="simd_support")] simd_impl! { f64x2, f64, m64x2, u64x2 } +#[cfg(feature="simd_support")] simd_impl! { f64x4, f64, m64x4, u64x4 } +#[cfg(feature="simd_support")] simd_impl! { f64x8, f64, m64x8, u64x8 } + +/// Calculates ln(gamma(x)) (natural logarithm of the gamma +/// function) using the Lanczos approximation. +/// +/// The approximation expresses the gamma function as: +/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)` +/// `g` is an arbitrary constant; we use the approximation with `g=5`. +/// +/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides: +/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)` +/// +/// `Ag(z)` is an infinite series with coefficients that can be calculated +/// ahead of time - we use just the first 6 terms, which is good enough +/// for most purposes. +#[cfg(feature="std")] +pub fn log_gamma(x: f64) -> f64 { + // precalculated 6 coefficients for the first 6 terms of the series + let coefficients: [f64; 6] = [ + 76.18009172947146, + -86.50532032941677, + 24.01409824083091, + -1.231739572450155, + 0.1208650973866179e-2, + -0.5395239384953e-5, + ]; + + // (x+0.5)*ln(x+g+0.5)-(x+g+0.5) + let tmp = x + 5.5; + let log = (x + 0.5) * tmp.ln() - tmp; + + // the first few terms of the series for Ag(x) + let mut a = 1.000000000190015; + let mut denom = x; + for coeff in &coefficients { + denom += 1.0; + a += coeff / denom; + } + + // get everything together + // a is Ag(x) + // 2.5066... is sqrt(2pi) + log + (2.5066282746310005 * a / x).ln() +} + +/// Sample a random number using the Ziggurat method (specifically the +/// ZIGNOR variant from Doornik 2005). Most of the arguments are +/// directly from the paper: +/// +/// * `rng`: source of randomness +/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0. +/// * `X`: the $x_i$ abscissae. +/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$) +/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$ +/// * `pdf`: the probability density function +/// * `zero_case`: manual sampling from the tail when we chose the +/// bottom box (i.e. i == 0) + +// the perf improvement (25-50%) is definitely worth the extra code +// size from force-inlining. +#[cfg(feature="std")] +#[inline(always)] +pub fn ziggurat<R: Rng + ?Sized, P, Z>( + rng: &mut R, + symmetric: bool, + x_tab: ziggurat_tables::ZigTable, + f_tab: ziggurat_tables::ZigTable, + mut pdf: P, + mut zero_case: Z) + -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 { + use distributions::float::IntoFloat; + loop { + // As an optimisation we re-implement the conversion to a f64. + // From the remaining 12 most significant bits we use 8 to construct `i`. + // This saves us generating a whole extra random number, while the added + // precision of using 64 bits for f64 does not buy us much. + let bits = rng.next_u64(); + let i = bits as usize & 0xff; + + let u = if symmetric { + // Convert to a value in the range [2,4) and substract to get [-1,1) + // We can't convert to an open range directly, that would require + // substracting `3.0 - EPSILON`, which is not representable. + // It is possible with an extra step, but an open range does not + // seem neccesary for the ziggurat algorithm anyway. + (bits >> 12).into_float_with_exponent(1) - 3.0 + } else { + // Convert to a value in the range [1,2) and substract to get (0,1) + (bits >> 12).into_float_with_exponent(0) + - (1.0 - ::core::f64::EPSILON / 2.0) + }; + let x = u * x_tab[i]; + + let test_x = if symmetric { x.abs() } else {x}; + + // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) + if test_x < x_tab[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) { + return x; + } + } +} diff --git a/rand/src/distributions/weibull.rs b/rand/src/distributions/weibull.rs new file mode 100644 index 000000000..5fbe10ae9 --- /dev/null +++ b/rand/src/distributions/weibull.rs @@ -0,0 +1,71 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Weibull distribution. + +use Rng; +use distributions::{Distribution, OpenClosed01}; + +/// Samples floating-point numbers according to the Weibull distribution +/// +/// # Example +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::Weibull; +/// +/// let val: f64 = SmallRng::from_entropy().sample(Weibull::new(1., 10.)); +/// println!("{}", val); +/// ``` +#[derive(Clone, Copy, Debug)] +pub struct Weibull { + inv_shape: f64, + scale: f64, +} + +impl Weibull { + /// Construct a new `Weibull` distribution with given `scale` and `shape`. + /// + /// # Panics + /// + /// `scale` and `shape` have to be non-zero and positive. + pub fn new(scale: f64, shape: f64) -> Weibull { + assert!((scale > 0.) & (shape > 0.)); + Weibull { inv_shape: 1./shape, scale } + } +} + +impl Distribution<f64> for Weibull { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 { + let x: f64 = rng.sample(OpenClosed01); + self.scale * (-x.ln()).powf(self.inv_shape) + } +} + +#[cfg(test)] +mod tests { + use distributions::Distribution; + use super::Weibull; + + #[test] + #[should_panic] + fn invalid() { + Weibull::new(0., 0.); + } + + #[test] + fn sample() { + let scale = 1.0; + let shape = 2.0; + let d = Weibull::new(scale, shape); + let mut rng = ::test::rng(1); + for _ in 0..1000 { + let r = d.sample(&mut rng); + assert!(r >= 0.); + } + } +} diff --git a/rand/src/distributions/weighted.rs b/rand/src/distributions/weighted.rs new file mode 100644 index 000000000..d7499596e --- /dev/null +++ b/rand/src/distributions/weighted.rs @@ -0,0 +1,230 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Rng; +use distributions::Distribution; +use distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow}; +use ::core::cmp::PartialOrd; +use core::fmt; + +// Note that this whole module is only imported if feature="alloc" is enabled. +#[cfg(not(feature="std"))] use alloc::vec::Vec; + +/// A distribution using weighted sampling to pick a discretely selected +/// item. +/// +/// Sampling a `WeightedIndex` distribution returns the index of a randomly +/// selected element from the iterator used when the `WeightedIndex` was +/// created. The chance of a given element being picked is proportional to the +/// value of the element. The weights can use any type `X` for which an +/// implementation of [`Uniform<X>`] exists. +/// +/// # Performance +/// +/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its +/// size is the sum of the size of those objects, possibly plus some alignment. +/// +/// Creating a `WeightedIndex<X>` will allocate enough space to hold `N - 1` +/// weights of type `X`, where `N` is the number of weights. However, since +/// `Vec` doesn't guarantee a particular growth strategy, additional memory +/// might be allocated but not used. Since the `WeightedIndex` object also +/// contains, this might cause additional allocations, though for primitive +/// types, ['Uniform<X>`] doesn't allocate any memory. +/// +/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where +/// `N` is the number of weights. +/// +/// Sampling from `WeightedIndex` will result in a single call to +/// `Uniform<X>::sample` (method of the [`Distribution`] trait), which typically +/// will request a single value from the underlying [`RngCore`], though the +/// exact number depends on the implementaiton of `Uniform<X>::sample`. +/// +/// # Example +/// +/// ``` +/// use rand::prelude::*; +/// use rand::distributions::WeightedIndex; +/// +/// let choices = ['a', 'b', 'c']; +/// let weights = [2, 1, 1]; +/// let dist = WeightedIndex::new(&weights).unwrap(); +/// let mut rng = thread_rng(); +/// for _ in 0..100 { +/// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c' +/// println!("{}", choices[dist.sample(&mut rng)]); +/// } +/// +/// let items = [('a', 0), ('b', 3), ('c', 7)]; +/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1)).unwrap(); +/// for _ in 0..100 { +/// // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c' +/// println!("{}", items[dist2.sample(&mut rng)].0); +/// } +/// ``` +/// +/// [`Uniform<X>`]: crate::distributions::uniform::Uniform +/// [`RngCore`]: rand_core::RngCore +#[derive(Debug, Clone)] +pub struct WeightedIndex<X: SampleUniform + PartialOrd> { + cumulative_weights: Vec<X>, + weight_distribution: X::Sampler, +} + +impl<X: SampleUniform + PartialOrd> WeightedIndex<X> { + /// Creates a new a `WeightedIndex` [`Distribution`] using the values + /// in `weights`. The weights can use any type `X` for which an + /// implementation of [`Uniform<X>`] exists. + /// + /// Returns an error if the iterator is empty, if any weight is `< 0`, or + /// if its total value is 0. + /// + /// [`Uniform<X>`]: crate::distributions::uniform::Uniform + pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError> + where I: IntoIterator, + I::Item: SampleBorrow<X>, + X: for<'a> ::core::ops::AddAssign<&'a X> + + Clone + + Default { + let mut iter = weights.into_iter(); + let mut total_weight: X = iter.next() + .ok_or(WeightedError::NoItem)? + .borrow() + .clone(); + + let zero = <X as Default>::default(); + if total_weight < zero { + return Err(WeightedError::NegativeWeight); + } + + let mut weights = Vec::<X>::with_capacity(iter.size_hint().0); + for w in iter { + if *w.borrow() < zero { + return Err(WeightedError::NegativeWeight); + } + weights.push(total_weight.clone()); + total_weight += w.borrow(); + } + + if total_weight == zero { + return Err(WeightedError::AllWeightsZero); + } + let distr = X::Sampler::new(zero, total_weight); + + Ok(WeightedIndex { cumulative_weights: weights, weight_distribution: distr }) + } +} + +impl<X> Distribution<usize> for WeightedIndex<X> where + X: SampleUniform + PartialOrd { + fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize { + use ::core::cmp::Ordering; + let chosen_weight = self.weight_distribution.sample(rng); + // Find the first item which has a weight *higher* than the chosen weight. + self.cumulative_weights.binary_search_by( + |w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_weightedindex() { + let mut r = ::test::rng(700); + const N_REPS: u32 = 5000; + let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]; + let total_weight = weights.iter().sum::<u32>() as f32; + + let verify = |result: [i32; 14]| { + for (i, count) in result.iter().enumerate() { + let exp = (weights[i] * N_REPS) as f32 / total_weight; + let mut err = (*count as f32 - exp).abs(); + if err != 0.0 { + err /= exp; + } + assert!(err <= 0.25); + } + }; + + // WeightedIndex from vec + let mut chosen = [0i32; 14]; + let distr = WeightedIndex::new(weights.to_vec()).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + // WeightedIndex from slice + chosen = [0i32; 14]; + let distr = WeightedIndex::new(&weights[..]).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + // WeightedIndex from iterator + chosen = [0i32; 14]; + let distr = WeightedIndex::new(weights.iter()).unwrap(); + for _ in 0..N_REPS { + chosen[distr.sample(&mut r)] += 1; + } + verify(chosen); + + for _ in 0..5 { + assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1); + assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0); + assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4); + } + + assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem); + assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero); + assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::NegativeWeight); + assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::NegativeWeight); + assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::NegativeWeight); + } +} + +/// Error type returned from `WeightedIndex::new`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WeightedError { + /// The provided iterator contained no items. + NoItem, + + /// A weight lower than zero was used. + NegativeWeight, + + /// All items in the provided iterator had a weight of zero. + AllWeightsZero, +} + +impl WeightedError { + fn msg(&self) -> &str { + match *self { + WeightedError::NoItem => "No items found", + WeightedError::NegativeWeight => "Item has negative weight", + WeightedError::AllWeightsZero => "All items had weight zero", + } + } +} + +#[cfg(feature="std")] +impl ::std::error::Error for WeightedError { + fn description(&self) -> &str { + self.msg() + } + fn cause(&self) -> Option<&::std::error::Error> { + None + } +} + +impl fmt::Display for WeightedError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg()) + } +} diff --git a/rand/src/distributions/ziggurat_tables.rs b/rand/src/distributions/ziggurat_tables.rs new file mode 100644 index 000000000..ca1ce3041 --- /dev/null +++ b/rand/src/distributions/ziggurat_tables.rs @@ -0,0 +1,279 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64; 257]; +pub const ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64; 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64; 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub const ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64; 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64; 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; diff --git a/rand/src/lib.rs b/rand/src/lib.rs new file mode 100644 index 000000000..9c0482f32 --- /dev/null +++ b/rand/src/lib.rs @@ -0,0 +1,830 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2017 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for random number generation +//! +//! Rand provides utilities to generate random numbers, to convert them to +//! useful types and distributions, and some randomness-related algorithms. +//! +//! # Quick Start +//! +//! To get you started quickly, the easiest and highest-level way to get +//! a random value is to use [`random()`]; alternatively you can use +//! [`thread_rng()`]. The [`Rng`] trait provides a useful API on all RNGs, while +//! the [`distributions`] and [`seq`] modules provide further +//! functionality on top of RNGs. +//! +//! ``` +//! use rand::prelude::*; +//! +//! if rand::random() { // generates a boolean +//! // Try printing a random unicode code point (probably a bad idea)! +//! println!("char: {}", rand::random::<char>()); +//! } +//! +//! let mut rng = rand::thread_rng(); +//! let y: f64 = rng.gen(); // generates a float between 0 and 1 +//! +//! let mut nums: Vec<i32> = (1..100).collect(); +//! nums.shuffle(&mut rng); +//! ``` +//! +//! # The Book +//! +//! For the user guide and futher documentation, please read +//! [The Rust Rand Book](https://rust-random.github.io/book). + + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(feature="std"), no_std)] +#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] +#![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))] + +#[cfg(feature = "std")] extern crate core; +#[cfg(all(feature = "alloc", not(feature="std")))] #[macro_use] extern crate alloc; + +#[cfg(feature="simd_support")] extern crate packed_simd; + +extern crate rand_jitter; +#[cfg(feature = "rand_os")] +extern crate rand_os; + +extern crate rand_core; +extern crate rand_isaac; // only for deprecations +extern crate rand_chacha; // only for deprecations +extern crate rand_hc; +extern crate rand_pcg; +extern crate rand_xorshift; + +#[cfg(feature = "log")] #[macro_use] extern crate log; +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () } + + +// Re-exports from rand_core +pub use rand_core::{RngCore, CryptoRng, SeedableRng}; +pub use rand_core::{ErrorKind, Error}; + +// Public exports +#[cfg(feature="std")] pub use rngs::thread::thread_rng; + +// Public modules +pub mod distributions; +pub mod prelude; +#[deprecated(since="0.6.0")] +pub mod prng; +pub mod rngs; +pub mod seq; + +//////////////////////////////////////////////////////////////////////////////// +// Compatibility re-exports. Documentation is hidden; will be removed eventually. + +#[doc(hidden)] mod deprecated; + +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::ReseedingRng; + +#[allow(deprecated)] +#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::EntropyRng; + +#[allow(deprecated)] +#[cfg(feature="rand_os")] +#[doc(hidden)] +pub use deprecated::OsRng; + +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::{ChaChaRng, IsaacRng, Isaac64Rng, XorShiftRng}; +#[allow(deprecated)] +#[doc(hidden)] pub use deprecated::StdRng; + + +#[allow(deprecated)] +#[doc(hidden)] +pub mod jitter { + pub use deprecated::JitterRng; + pub use rngs::TimerError; +} +#[allow(deprecated)] +#[cfg(feature="rand_os")] +#[doc(hidden)] +pub mod os { + pub use deprecated::OsRng; +} +#[allow(deprecated)] +#[doc(hidden)] +pub mod chacha { + pub use deprecated::ChaChaRng; +} +#[allow(deprecated)] +#[doc(hidden)] +pub mod isaac { + pub use deprecated::{IsaacRng, Isaac64Rng}; +} +#[allow(deprecated)] +#[cfg(feature="std")] +#[doc(hidden)] +pub mod read { + pub use deprecated::ReadRng; +} + +#[allow(deprecated)] +#[cfg(feature="std")] #[doc(hidden)] pub use deprecated::ThreadRng; + +//////////////////////////////////////////////////////////////////////////////// + + +use core::{mem, slice}; +use distributions::{Distribution, Standard}; +use distributions::uniform::{SampleUniform, UniformSampler, SampleBorrow}; + +/// An automatically-implemented extension trait on [`RngCore`] providing high-level +/// generic methods for sampling values and other convenience methods. +/// +/// This is the primary trait to use when generating random values. +/// +/// # Generic usage +/// +/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some +/// things are worth noting here: +/// +/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no +/// difference whether we use `R: Rng` or `R: RngCore`. +/// - The `+ ?Sized` un-bounding allows functions to be called directly on +/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without +/// this it would be necessary to write `foo(&mut r)`. +/// +/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some +/// trade-offs. It allows the argument to be consumed directly without a `&mut` +/// (which is how `from_rng(thread_rng())` works); also it still works directly +/// on references (including type-erased references). Unfortunately within the +/// function `foo` it is not known whether `rng` is a reference type or not, +/// hence many uses of `rng` require an extra reference, either explicitly +/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the +/// optimiser can remove redundant references later. +/// +/// Example: +/// +/// ``` +/// # use rand::thread_rng; +/// use rand::Rng; +/// +/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 { +/// rng.gen() +/// } +/// +/// # let v = foo(&mut thread_rng()); +/// ``` +pub trait Rng: RngCore { + /// Return a random value supporting the [`Standard`] distribution. + /// + /// [`Standard`]: distributions::Standard + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let x: u32 = rng.gen(); + /// println!("{}", x); + /// println!("{:?}", rng.gen::<(f64, bool)>()); + /// ``` + #[inline] + fn gen<T>(&mut self) -> T where Standard: Distribution<T> { + Standard.sample(self) + } + + /// Generate a random value in the range [`low`, `high`), i.e. inclusive of + /// `low` and exclusive of `high`. + /// + /// This function is optimised for the case that only a single sample is + /// made from the given range. See also the [`Uniform`] distribution + /// type which may be faster if sampling from the same range repeatedly. + /// + /// # Panics + /// + /// Panics if `low >= high`. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// let n: u32 = rng.gen_range(0, 10); + /// println!("{}", n); + /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); + /// println!("{}", m); + /// ``` + /// + /// [`Uniform`]: distributions::uniform::Uniform + fn gen_range<T: SampleUniform, B1, B2>(&mut self, low: B1, high: B2) -> T + where B1: SampleBorrow<T> + Sized, + B2: SampleBorrow<T> + Sized { + T::Sampler::sample_single(low, high, self) + } + + /// Sample a new value, using the given distribution. + /// + /// ### Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::Uniform; + /// + /// let mut rng = thread_rng(); + /// let x = rng.sample(Uniform::new(10u32, 15)); + /// // Type annotation requires two types, the type and distribution; the + /// // distribution can be inferred. + /// let y = rng.sample::<u16, _>(Uniform::new(10, 15)); + /// ``` + fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T { + distr.sample(self) + } + + /// Create an iterator that generates values using the given distribution. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// use rand::distributions::{Alphanumeric, Uniform, Standard}; + /// + /// let mut rng = thread_rng(); + /// + /// // Vec of 16 x f32: + /// let v: Vec<f32> = thread_rng().sample_iter(&Standard).take(16).collect(); + /// + /// // String: + /// let s: String = rng.sample_iter(&Alphanumeric).take(7).collect(); + /// + /// // Combined values + /// println!("{:?}", thread_rng().sample_iter(&Standard).take(5) + /// .collect::<Vec<(f64, bool)>>()); + /// + /// // Dice-rolling: + /// let die_range = Uniform::new_inclusive(1, 6); + /// let mut roll_die = rng.sample_iter(&die_range); + /// while roll_die.next().unwrap() != 6 { + /// println!("Not a 6; rolling again!"); + /// } + /// ``` + fn sample_iter<'a, T, D: Distribution<T>>(&'a mut self, distr: &'a D) + -> distributions::DistIter<'a, D, Self, T> where Self: Sized + { + distr.sample_iter(self) + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`fill_bytes`] internally which may handle some RNG errors + /// implicitly (e.g. waiting if the OS generator is not ready), but panics + /// on other errors. See also [`try_fill`] which returns errors. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut arr = [0i8; 20]; + /// thread_rng().fill(&mut arr[..]); + /// ``` + /// + /// [`fill_bytes`]: RngCore::fill_bytes + /// [`try_fill`]: Rng::try_fill + fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) { + self.fill_bytes(dest.as_byte_slice_mut()); + dest.to_le(); + } + + /// Fill `dest` entirely with random bytes (uniform value distribution), + /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices + /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.). + /// + /// On big-endian platforms this performs byte-swapping to ensure + /// portability of results from reproducible generators. + /// + /// This uses [`try_fill_bytes`] internally and forwards all RNG errors. In + /// some cases errors may be resolvable; see [`ErrorKind`] and + /// documentation for the RNG in use. If you do not plan to handle these + /// errors you may prefer to use [`fill`]. + /// + /// # Example + /// + /// ``` + /// # use rand::Error; + /// use rand::{thread_rng, Rng}; + /// + /// # fn try_inner() -> Result<(), Error> { + /// let mut arr = [0u64; 4]; + /// thread_rng().try_fill(&mut arr[..])?; + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + /// + /// [`try_fill_bytes`]: RngCore::try_fill_bytes + /// [`fill`]: Rng::fill + fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> { + self.try_fill_bytes(dest.as_byte_slice_mut())?; + dest.to_le(); + Ok(()) + } + + /// Return a bool with a probability `p` of being true. + /// + /// See also the [`Bernoulli`] distribution, which may be faster if + /// sampling from the same probability repeatedly. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_bool(1.0 / 3.0)); + /// ``` + /// + /// # Panics + /// + /// If `p < 0` or `p > 1`. + /// + /// [`Bernoulli`]: distributions::bernoulli::Bernoulli + #[inline] + fn gen_bool(&mut self, p: f64) -> bool { + let d = distributions::Bernoulli::new(p); + self.sample(d) + } + + /// Return a bool with a probability of `numerator/denominator` of being + /// true. I.e. `gen_ratio(2, 3)` has chance of 2 in 3, or about 67%, of + /// returning true. If `numerator == denominator`, then the returned value + /// is guaranteed to be `true`. If `numerator == 0`, then the returned + /// value is guaranteed to be `false`. + /// + /// See also the [`Bernoulli`] distribution, which may be faster if + /// sampling from the same `numerator` and `denominator` repeatedly. + /// + /// # Panics + /// + /// If `denominator == 0` or `numerator > denominator`. + /// + /// # Example + /// + /// ``` + /// use rand::{thread_rng, Rng}; + /// + /// let mut rng = thread_rng(); + /// println!("{}", rng.gen_ratio(2, 3)); + /// ``` + /// + /// [`Bernoulli`]: distributions::bernoulli::Bernoulli + #[inline] + fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool { + let d = distributions::Bernoulli::from_ratio(numerator, denominator); + self.sample(d) + } + + /// Return a random element from `values`. + /// + /// Deprecated: use [`seq::SliceRandom::choose`] instead. + #[deprecated(since="0.6.0", note="use SliceRandom::choose instead")] + fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { + use seq::SliceRandom; + values.choose(self) + } + + /// Return a mutable pointer to a random element from `values`. + /// + /// Deprecated: use [`seq::SliceRandom::choose_mut`] instead. + #[deprecated(since="0.6.0", note="use SliceRandom::choose_mut instead")] + fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> { + use seq::SliceRandom; + values.choose_mut(self) + } + + /// Shuffle a mutable slice in place. + /// + /// Deprecated: use [`seq::SliceRandom::shuffle`] instead. + #[deprecated(since="0.6.0", note="use SliceRandom::shuffle instead")] + fn shuffle<T>(&mut self, values: &mut [T]) { + use seq::SliceRandom; + values.shuffle(self) + } +} + +impl<R: RngCore + ?Sized> Rng for R {} + +/// Trait for casting types to byte slices +/// +/// This is used by the [`Rng::fill`] and [`Rng::try_fill`] methods. +pub trait AsByteSliceMut { + /// Return a mutable reference to self as a byte slice + fn as_byte_slice_mut(&mut self) -> &mut [u8]; + + /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms). + fn to_le(&mut self); +} + +impl AsByteSliceMut for [u8] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self + } + + fn to_le(&mut self) {} +} + +macro_rules! impl_as_byte_slice { + ($t:ty) => { + impl AsByteSliceMut for [$t] { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + if self.len() == 0 { + unsafe { + // must not use null pointer + slice::from_raw_parts_mut(0x1 as *mut u8, 0) + } + } else { + unsafe { + slice::from_raw_parts_mut(&mut self[0] + as *mut $t + as *mut u8, + self.len() * mem::size_of::<$t>() + ) + } + } + } + + fn to_le(&mut self) { + for x in self { + *x = x.to_le(); + } + } + } + } +} + +impl_as_byte_slice!(u16); +impl_as_byte_slice!(u32); +impl_as_byte_slice!(u64); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(u128); +impl_as_byte_slice!(usize); +impl_as_byte_slice!(i8); +impl_as_byte_slice!(i16); +impl_as_byte_slice!(i32); +impl_as_byte_slice!(i64); +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] impl_as_byte_slice!(i128); +impl_as_byte_slice!(isize); + +macro_rules! impl_as_byte_slice_arrays { + ($n:expr,) => {}; + ($n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!($n - 1, $($NN,)*); + + impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } + + fn to_le(&mut self) { + self[..].to_le() + } + } + }; + (!div $n:expr,) => {}; + (!div $n:expr, $N:ident, $($NN:ident,)*) => { + impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*); + + impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut { + fn as_byte_slice_mut(&mut self) -> &mut [u8] { + self[..].as_byte_slice_mut() + } + + fn to_le(&mut self) { + self[..].to_le() + } + } + }; +} +impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,); +impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,); + + +/// A convenience extension to [`SeedableRng`] allowing construction from fresh +/// entropy. This trait is automatically implemented for any PRNG implementing +/// [`SeedableRng`] and is not intended to be implemented by users. +/// +/// This is equivalent to using `SeedableRng::from_rng(EntropyRng::new())` then +/// unwrapping the result. +/// +/// Since this is convenient and secure, it is the recommended way to create +/// PRNGs, though two alternatives may be considered: +/// +/// * Deterministic creation using [`SeedableRng::from_seed`] with a fixed seed +/// * Seeding from `thread_rng`: `SeedableRng::from_rng(thread_rng())?`; +/// this will usually be faster and should also be secure, but requires +/// trusting one extra component. +/// +/// ## Example +/// +/// ``` +/// use rand::{Rng, FromEntropy}; +/// use rand::rngs::StdRng; +/// +/// let mut rng = StdRng::from_entropy(); +/// println!("Random die roll: {}", rng.gen_range(1, 7)); +/// ``` +/// +/// [`EntropyRng`]: rngs::EntropyRng +#[cfg(feature="std")] +pub trait FromEntropy: SeedableRng { + /// Creates a new instance, automatically seeded with fresh entropy. + /// + /// Normally this will use `OsRng`, but if that fails `JitterRng` will be + /// used instead. Both should be suitable for cryptography. It is possible + /// that both entropy sources will fail though unlikely; failures would + /// almost certainly be platform limitations or build issues, i.e. most + /// applications targetting PC/mobile platforms should not need to worry + /// about this failing. + /// + /// # Panics + /// + /// If all entropy sources fail this will panic. If you need to handle + /// errors, use the following code, equivalent aside from error handling: + /// + /// ``` + /// # use rand::Error; + /// use rand::prelude::*; + /// use rand::rngs::EntropyRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// // This uses StdRng, but is valid for any R: SeedableRng + /// let mut rng = StdRng::from_rng(EntropyRng::new())?; + /// + /// println!("random number: {}", rng.gen_range(1, 10)); + /// # Ok(()) + /// # } + /// + /// # try_inner().unwrap() + /// ``` + fn from_entropy() -> Self; +} + +#[cfg(feature="std")] +impl<R: SeedableRng> FromEntropy for R { + fn from_entropy() -> R { + R::from_rng(rngs::EntropyRng::new()).unwrap_or_else(|err| + panic!("FromEntropy::from_entropy() failed: {}", err)) + } +} + + +/// Generates a random value using the thread-local random number generator. +/// +/// This is simply a shortcut for `thread_rng().gen()`. See [`thread_rng`] for +/// documentation of the entropy source and [`Standard`] for documentation of +/// distributions and type-specific generation. +/// +/// # Examples +/// +/// ``` +/// let x = rand::random::<u8>(); +/// println!("{}", x); +/// +/// let y = rand::random::<f64>(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +/// +/// If you're calling `random()` in a loop, caching the generator as in the +/// following example can increase performance. +/// +/// ``` +/// use rand::Rng; +/// +/// let mut v = vec![1, 2, 3]; +/// +/// for x in v.iter_mut() { +/// *x = rand::random() +/// } +/// +/// // can be made faster by caching thread_rng +/// +/// let mut rng = rand::thread_rng(); +/// +/// for x in v.iter_mut() { +/// *x = rng.gen(); +/// } +/// ``` +/// +/// [`Standard`]: distributions::Standard +#[cfg(feature="std")] +#[inline] +pub fn random<T>() -> T where Standard: Distribution<T> { + thread_rng().gen() +} + +#[cfg(test)] +mod test { + use rngs::mock::StepRng; + use rngs::StdRng; + use super::*; + #[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box; + + pub struct TestRng<R> { inner: R } + + impl<R: RngCore> RngCore for TestRng<R> { + fn next_u32(&mut self) -> u32 { + self.inner.next_u32() + } + fn next_u64(&mut self) -> u64 { + self.inner.next_u64() + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.inner.fill_bytes(dest) + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.inner.try_fill_bytes(dest) + } + } + + pub fn rng(seed: u64) -> TestRng<StdRng> { + TestRng { inner: StdRng::seed_from_u64(seed) } + } + + #[test] + fn test_fill_bytes_default() { + let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0); + + // check every remainder mod 8, both in small and big vectors. + let lengths = [0, 1, 2, 3, 4, 5, 6, 7, + 80, 81, 82, 83, 84, 85, 86, 87]; + for &n in lengths.iter() { + let mut buffer = [0u8; 87]; + let v = &mut buffer[0..n]; + r.fill_bytes(v); + + // use this to get nicer error messages. + for (i, &byte) in v.iter().enumerate() { + if byte == 0 { + panic!("byte {} of {} is zero", i, n) + } + } + } + } + + #[test] + fn test_fill() { + let x = 9041086907909331047; // a random u64 + let mut rng = StepRng::new(x, 0); + + // Convert to byte sequence and back to u64; byte-swap twice if BE. + let mut array = [0u64; 2]; + rng.fill(&mut array[..]); + assert_eq!(array, [x, x]); + assert_eq!(rng.next_u64(), x); + + // Convert to bytes then u32 in LE order + let mut array = [0u32; 2]; + rng.fill(&mut array[..]); + assert_eq!(array, [x as u32, (x >> 32) as u32]); + assert_eq!(rng.next_u32(), x as u32); + } + + #[test] + fn test_fill_empty() { + let mut array = [0u32; 0]; + let mut rng = StepRng::new(0, 1); + rng.fill(&mut array); + rng.fill(&mut array[..]); + } + + #[test] + fn test_gen_range() { + let mut r = rng(101); + for _ in 0..1000 { + let a = r.gen_range(-4711, 17); + assert!(a >= -4711 && a < 17); + let a = r.gen_range(-3i8, 42); + assert!(a >= -3i8 && a < 42i8); + let a = r.gen_range(&10u16, 99); + assert!(a >= 10u16 && a < 99u16); + let a = r.gen_range(-100i32, &2000); + assert!(a >= -100i32 && a < 2000i32); + let a = r.gen_range(&12u32, &24u32); + assert!(a >= 12u32 && a < 24u32); + + assert_eq!(r.gen_range(0u32, 1), 0u32); + assert_eq!(r.gen_range(-12i64, -11), -12i64); + assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); + } + } + + #[test] + #[should_panic] + fn test_gen_range_panic_int() { + let mut r = rng(102); + r.gen_range(5, -2); + } + + #[test] + #[should_panic] + fn test_gen_range_panic_usize() { + let mut r = rng(103); + r.gen_range(5, 2); + } + + #[test] + fn test_gen_bool() { + let mut r = rng(105); + for _ in 0..5 { + assert_eq!(r.gen_bool(0.0), false); + assert_eq!(r.gen_bool(1.0), true); + } + } + + #[test] + fn test_rng_trait_object() { + use distributions::{Distribution, Standard}; + let mut rng = rng(109); + let mut r = &mut rng as &mut RngCore; + r.next_u32(); + r.gen::<i32>(); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); + } + + #[test] + #[cfg(feature="alloc")] + fn test_rng_boxed_trait() { + use distributions::{Distribution, Standard}; + let rng = rng(110); + let mut r = Box::new(rng) as Box<RngCore>; + r.next_u32(); + r.gen::<i32>(); + assert_eq!(r.gen_range(0, 1), 0); + let _c: u8 = Standard.sample(&mut r); + } + + #[test] + #[cfg(feature="std")] + fn test_random() { + // not sure how to test this aside from just getting some values + let _n : usize = random(); + let _f : f32 = random(); + let _o : Option<Option<i8>> = random(); + let _many : ((), + (usize, + isize, + Option<(u32, (bool,))>), + (u8, i8, u16, i16, u32, i32, u64, i64), + (f32, (f64, (f64,)))) = random(); + } + + #[test] + fn test_gen_ratio_average() { + const NUM: u32 = 3; + const DENOM: u32 = 10; + const N: u32 = 100_000; + + let mut sum: u32 = 0; + let mut rng = rng(111); + for _ in 0..N { + if rng.gen_ratio(NUM, DENOM) { + sum += 1; + } + } + // Have Binomial(N, NUM/DENOM) distribution + let expected = (NUM * N) / DENOM; // exact integer + assert!(((sum - expected) as i32).abs() < 500); + } +} diff --git a/rand/src/prelude.rs b/rand/src/prelude.rs new file mode 100644 index 000000000..5d8a0e9b2 --- /dev/null +++ b/rand/src/prelude.rs @@ -0,0 +1,27 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Convenience re-export of common members +//! +//! Like the standard library's prelude, this module simplifies importing of +//! common items. Unlike the standard prelude, the contents of this module must +//! be imported manually: +//! +//! ``` +//! use rand::prelude::*; +//! # let _ = StdRng::from_entropy(); +//! # let mut r = SmallRng::from_rng(thread_rng()).unwrap(); +//! # let _: f32 = r.gen(); +//! ``` + +#[doc(no_inline)] pub use distributions::Distribution; +#[doc(no_inline)] pub use rngs::{SmallRng, StdRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng; +#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng}; +#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng}; +#[doc(no_inline)] pub use seq::{SliceRandom, IteratorRandom}; diff --git a/rand/src/prng/mod.rs b/rand/src/prng/mod.rs new file mode 100644 index 000000000..3c0d27b2e --- /dev/null +++ b/rand/src/prng/mod.rs @@ -0,0 +1,37 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Pseudo-random number generators. +//! +//! This module is deprecated: +//! +//! - documentation has moved to +//! [The Book](https://rust-random.github.io/book/guide-rngs.html), +//! - PRNGs have moved to other `rand_*` crates. + +// Deprecations (to be removed in 0.7) +#[doc(hidden)] #[allow(deprecated)] +pub use deprecated::XorShiftRng; +#[doc(hidden)] pub mod isaac { + // Note: we miss `IsaacCore` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::IsaacRng; +} +#[doc(hidden)] pub mod isaac64 { + #[allow(deprecated)] pub use deprecated::Isaac64Rng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::{IsaacRng, Isaac64Rng}; +#[doc(hidden)] pub mod chacha { + // Note: we miss `ChaChaCore` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::ChaChaRng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::ChaChaRng; +#[doc(hidden)] pub mod hc128 { + // Note: we miss `Hc128Core` here but probably unimportant. + #[allow(deprecated)] pub use deprecated::Hc128Rng; +} +#[doc(hidden)] #[allow(deprecated)] pub use deprecated::Hc128Rng; diff --git a/rand/src/rngs/adapter/mod.rs b/rand/src/rngs/adapter/mod.rs new file mode 100644 index 000000000..60b832e9a --- /dev/null +++ b/rand/src/rngs/adapter/mod.rs @@ -0,0 +1,15 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Wrappers / adapters forming RNGs + +#[cfg(feature="std")] #[doc(hidden)] pub mod read; +mod reseeding; + +#[cfg(feature="std")] pub use self::read::ReadRng; +pub use self::reseeding::ReseedingRng; diff --git a/rand/src/rngs/adapter/read.rs b/rand/src/rngs/adapter/read.rs new file mode 100644 index 000000000..9b9c18b3e --- /dev/null +++ b/rand/src/rngs/adapter/read.rs @@ -0,0 +1,136 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around any Read to treat it as an RNG. + +use std::io::Read; + +use rand_core::{RngCore, Error, ErrorKind, impls}; + + +/// An RNG that reads random bytes straight from any type supporting +/// [`std::io::Read`], for example files. +/// +/// This will work best with an infinite reader, but that is not required. +/// +/// This can be used with `/dev/urandom` on Unix but it is recommended to use +/// [`OsRng`] instead. +/// +/// # Panics +/// +/// `ReadRng` uses [`std::io::Read::read_exact`], which retries on interrupts. +/// All other errors from the underlying reader, including when it does not +/// have enough data, will only be reported through [`try_fill_bytes`]. +/// The other [`RngCore`] methods will panic in case of an error. +/// +/// # Example +/// +/// ``` +/// use rand::Rng; +/// use rand::rngs::adapter::ReadRng; +/// +/// let data = vec![1, 2, 3, 4, 5, 6, 7, 8]; +/// let mut rng = ReadRng::new(&data[..]); +/// println!("{:x}", rng.gen::<u32>()); +/// ``` +/// +/// [`OsRng`]: rand_os::OsRng +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Debug)] +pub struct ReadRng<R> { + reader: R +} + +impl<R: Read> ReadRng<R> { + /// Create a new `ReadRng` from a `Read`. + pub fn new(r: R) -> ReadRng<R> { + ReadRng { + reader: r + } + } +} + +impl<R: Read> RngCore for ReadRng<R> { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("reading random bytes from Read implementation failed; error: {}", err)); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + if dest.len() == 0 { return Ok(()); } + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + self.reader.read_exact(dest).map_err(|err| { + match err.kind() { + ::std::io::ErrorKind::UnexpectedEof => Error::with_cause( + ErrorKind::Unavailable, + "not enough bytes available, reached end of source", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error reading from Read source", err) + } + }) + } +} + +#[cfg(test)] +mod test { + use super::ReadRng; + use {RngCore, ErrorKind}; + + #[test] + fn test_reader_rng_u64() { + // transmute from the target to avoid endianness concerns. + let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u64(), 1_u64.to_be()); + assert_eq!(rng.next_u64(), 2_u64.to_be()); + assert_eq!(rng.next_u64(), 3_u64.to_be()); + } + + #[test] + fn test_reader_rng_u32() { + let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; + let mut rng = ReadRng::new(&v[..]); + + assert_eq!(rng.next_u32(), 1_u32.to_be()); + assert_eq!(rng.next_u32(), 2_u32.to_be()); + assert_eq!(rng.next_u32(), 3_u32.to_be()); + } + + #[test] + fn test_reader_rng_fill_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 8]; + + let mut rng = ReadRng::new(&v[..]); + rng.fill_bytes(&mut w); + + assert!(v == w); + } + + #[test] + fn test_reader_rng_insufficient_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8; 9]; + + let mut rng = ReadRng::new(&v[..]); + + assert!(rng.try_fill_bytes(&mut w).err().unwrap().kind == ErrorKind::Unavailable); + } +} diff --git a/rand/src/rngs/adapter/reseeding.rs b/rand/src/rngs/adapter/reseeding.rs new file mode 100644 index 000000000..ed2aab4cf --- /dev/null +++ b/rand/src/rngs/adapter/reseeding.rs @@ -0,0 +1,370 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A wrapper around another PRNG that reseeds it after it +//! generates a certain number of random bytes. + +use core::mem::size_of; + +use rand_core::{RngCore, CryptoRng, SeedableRng, Error, ErrorKind}; +use rand_core::block::{BlockRngCore, BlockRng}; + +/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the +/// ability to reseed it. +/// +/// `ReseedingRng` reseeds the underlying PRNG in the following cases: +/// +/// - On a manual call to [`reseed()`]. +/// - After `clone()`, the clone will be reseeded on first use. +/// - After a process is forked, the RNG in the child process is reseeded within +/// the next few generated values, depending on the block size of the +/// underlying PRNG. For [`ChaChaCore`] and [`Hc128Core`] this is a maximum of +/// 15 `u32` values before reseeding. +/// - After the PRNG has generated a configurable number of random bytes. +/// +/// # When should reseeding after a fixed number of generated bytes be used? +/// +/// Reseeding after a fixed number of generated bytes is never strictly +/// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they +/// can output, or at least not a limit reachable in any practical way. There is +/// no such thing as 'running out of entropy'. +/// +/// Occasionally reseeding can be seen as some form of 'security in depth'. Even +/// if in the future a cryptographic weakness is found in the CSPRNG being used, +/// or a flaw in the implementation, occasionally reseeding should make +/// exploiting it much more difficult or even impossible. +/// +/// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding +/// after a fixed number of generated bytes. +/// +/// # Error handling +/// +/// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will +/// never panic but try to handle the error intelligently through some +/// combination of retrying and delaying reseeding until later. +/// If handling the source error fails `ReseedingRng` will continue generating +/// data from the wrapped PRNG without reseeding. +/// +/// Manually calling [`reseed()`] will not have this retry or delay logic, but +/// reports the error. +/// +/// # Example +/// +/// ``` +/// # extern crate rand; +/// # extern crate rand_chacha; +/// # fn main() { +/// use rand::prelude::*; +/// use rand_chacha::ChaChaCore; // Internal part of ChaChaRng that +/// // implements BlockRngCore +/// use rand::rngs::OsRng; +/// use rand::rngs::adapter::ReseedingRng; +/// +/// let prng = ChaChaCore::from_entropy(); +// FIXME: it is better to use EntropyRng as reseeder, but that doesn't implement +// clone yet. +/// let reseeder = OsRng::new().unwrap(); +/// let mut reseeding_rng = ReseedingRng::new(prng, 0, reseeder); +/// +/// println!("{}", reseeding_rng.gen::<u64>()); +/// +/// let mut cloned_rng = reseeding_rng.clone(); +/// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>()); +/// # } +/// ``` +/// +/// [`ChaChaCore`]: rand_chacha::ChaChaCore +/// [`Hc128Core`]: rand_hc::Hc128Core +/// [`BlockRngCore`]: rand_core::block::BlockRngCore +/// [`ReseedingRng::new`]: ReseedingRng::new +/// [`reseed()`]: ReseedingRng::reseed +#[derive(Debug)] +pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>) +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore; + +impl<R, Rsdr> ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG + /// to use as reseeder. + /// + /// `threshold` sets the number of generated bytes after which to reseed the + /// PRNG. Set it to zero to never reseed based on the number of generated + /// values. + pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder))) + } + + /// Reseed the internal PRNG. + pub fn reseed(&mut self) -> Result<(), Error> { + self.0.core.reseed() + } +} + +// TODO: this should be implemented for any type where the inner type +// implements RngCore, but we can't specify that because ReseedingCore is private +impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr> +where R: BlockRngCore<Item = u32> + SeedableRng, + <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingRng<R, Rsdr> { + // Recreating `BlockRng` seems easier than cloning it and resetting + // the index. + ReseedingRng(BlockRng::new(self.0.core.clone())) + } +} + +impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + +#[derive(Debug)] +struct ReseedingCore<R, Rsdr> { + inner: R, + reseeder: Rsdr, + threshold: i64, + bytes_until_reseed: i64, + fork_counter: usize, +} + +impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + type Item = <R as BlockRngCore>::Item; + type Results = <R as BlockRngCore>::Results; + + fn generate(&mut self, results: &mut Self::Results) { + let global_fork_counter = fork::get_fork_counter(); + if self.bytes_until_reseed <= 0 || + self.is_forked(global_fork_counter) { + // We get better performance by not calling only `reseed` here + // and continuing with the rest of the function, but by directly + // returning from a non-inlined function. + return self.reseed_and_generate(results, global_fork_counter); + } + let num_bytes = results.as_ref().len() * size_of::<Self::Item>(); + self.bytes_until_reseed -= num_bytes as i64; + self.inner.generate(results); + } +} + +impl<R, Rsdr> ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng, + Rsdr: RngCore +{ + /// Create a new `ReseedingCore`. + fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { + use ::core::i64::MAX; + fork::register_fork_handler(); + + // Because generating more values than `i64::MAX` takes centuries on + // current hardware, we just clamp to that value. + // Also we set a threshold of 0, which indicates no limit, to that + // value. + let threshold = + if threshold == 0 { MAX } + else if threshold <= MAX as u64 { threshold as i64 } + else { MAX }; + + ReseedingCore { + inner: rng, + reseeder, + threshold: threshold as i64, + bytes_until_reseed: threshold as i64, + fork_counter: 0, + } + } + + /// Reseed the internal PRNG. + fn reseed(&mut self) -> Result<(), Error> { + R::from_rng(&mut self.reseeder).map(|result| { + self.bytes_until_reseed = self.threshold; + self.inner = result + }) + } + + fn is_forked(&self, global_fork_counter: usize) -> bool { + // In theory, on 32-bit platforms, it is possible for + // `global_fork_counter` to wrap around after ~4e9 forks. + // + // This check will detect a fork in the normal case where + // `fork_counter < global_fork_counter`, and also when the difference + // between both is greater than `isize::MAX` (wrapped around). + // + // It will still fail to detect a fork if there have been more than + // `isize::MAX` forks, without any reseed in between. Seems unlikely + // enough. + (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0 + } + + #[inline(never)] + fn reseed_and_generate(&mut self, + results: &mut <Self as BlockRngCore>::Results, + global_fork_counter: usize) + { + if self.is_forked(global_fork_counter) { + info!("Fork detected, reseeding RNG"); + } else { + trace!("Reseeding RNG (periodic reseed)"); + } + + let num_bytes = + results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>(); + + let threshold = if let Err(e) = self.reseed() { + let delay = match e.kind { + ErrorKind::Transient => num_bytes as i64, + kind @ _ if kind.should_retry() => self.threshold >> 8, + _ => self.threshold, + }; + warn!("Reseeding RNG delayed reseeding by {} bytes due to \ + error from source: {}", delay, e); + delay + } else { + self.fork_counter = global_fork_counter; + self.threshold + }; + + self.bytes_until_reseed = threshold - num_bytes as i64; + self.inner.generate(results); + } +} + +impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng + Clone, + Rsdr: RngCore + Clone +{ + fn clone(&self) -> ReseedingCore<R, Rsdr> { + ReseedingCore { + inner: self.inner.clone(), + reseeder: self.reseeder.clone(), + threshold: self.threshold, + bytes_until_reseed: 0, // reseed clone on first use + fork_counter: self.fork_counter, + } + } +} + +impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr> +where R: BlockRngCore + SeedableRng + CryptoRng, + Rsdr: RngCore + CryptoRng {} + + +#[cfg(all(feature="std", unix, not(target_os="emscripten")))] +mod fork { + extern crate libc; + + use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; + + // Fork protection + // + // We implement fork protection on Unix using `pthread_atfork`. + // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`. + // Every `ReseedingRng` stores the last known value of the static in + // `fork_counter`. If the cached `fork_counter` is less than + // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG. + // + // If reseeding fails, we don't deal with this by setting a delay, but just + // don't update `fork_counter`, so a reseed is attempted as soon as + // possible. + + static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + + pub fn get_fork_counter() -> usize { + RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) + } + + static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT; + + extern fn fork_handler() { + // Note: fetch_add is defined to wrap on overflow + // (which is what we want). + RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed); + } + + pub fn register_fork_handler() { + if FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) == false { + unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) }; + FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed); + } + } +} + +#[cfg(not(all(feature="std", unix, not(target_os="emscripten"))))] +mod fork { + pub fn get_fork_counter() -> usize { 0 } + pub fn register_fork_handler() {} +} + + +#[cfg(test)] +mod test { + use {Rng, SeedableRng}; + use rand_chacha::ChaChaCore; + use rngs::mock::StepRng; + use super::ReseedingRng; + + #[test] + fn test_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut reseeding = ReseedingRng::new(rng, 32*4, zero); + + // Currently we only support for arrays up to length 32. + // TODO: cannot generate seq via Rng::gen because it uses different alg + let mut buf = [0u32; 32]; // Needs to be a multiple of the RNGs result + // size to test exactly. + reseeding.fill(&mut buf); + let seq = buf; + for _ in 0..10 { + reseeding.fill(&mut buf); + assert_eq!(buf, seq); + } + } + + #[test] + fn test_clone_reseeding() { + let mut zero = StepRng::new(0, 0); + let rng = ChaChaCore::from_rng(&mut zero).unwrap(); + let mut rng1 = ReseedingRng::new(rng, 32*4, zero); + + let first: u32 = rng1.gen(); + for _ in 0..10 { let _ = rng1.gen::<u32>(); } + + let mut rng2 = rng1.clone(); + assert_eq!(first, rng2.gen::<u32>()); + } +} diff --git a/rand/src/rngs/entropy.rs b/rand/src/rngs/entropy.rs new file mode 100644 index 000000000..9a2affdff --- /dev/null +++ b/rand/src/rngs/entropy.rs @@ -0,0 +1,248 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Entropy generator, or wrapper around external generators + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind, impls}; +#[allow(unused)] +use rngs; + +/// An interface returning random data from external source(s), provided +/// specifically for securely seeding algorithmic generators (PRNGs). +/// +/// Where possible, `EntropyRng` retrieves random data from the operating +/// system's interface for random numbers ([`OsRng`]); if that fails it will +/// fall back to the [`JitterRng`] entropy collector. In the latter case it will +/// still try to use [`OsRng`] on the next usage. +/// +/// If no secure source of entropy is available `EntropyRng` will panic on use; +/// i.e. it should never output predictable data. +/// +/// This is either a little slow ([`OsRng`] requires a system call) or extremely +/// slow ([`JitterRng`] must use significant CPU time to generate sufficient +/// jitter); for better performance it is common to seed a local PRNG from +/// external entropy then primarily use the local PRNG ([`thread_rng`] is +/// provided as a convenient, local, automatically-seeded CSPRNG). +/// +/// # Panics +/// +/// On most systems, like Windows, Linux, macOS and *BSD on common hardware, it +/// is highly unlikely for both [`OsRng`] and [`JitterRng`] to fail. But on +/// combinations like webassembly without Emscripten or stdweb both sources are +/// unavailable. If both sources fail, only [`try_fill_bytes`] is able to +/// report the error, and only the one from `OsRng`. The other [`RngCore`] +/// methods will panic in case of an error. +/// +/// [`OsRng`]: rand_os::OsRng +/// [`thread_rng`]: crate::thread_rng +/// [`JitterRng`]: crate::rngs::JitterRng +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Debug)] +pub struct EntropyRng { + source: Source, +} + +#[derive(Debug)] +enum Source { + Os(Os), + Custom(Custom), + Jitter(Jitter), + None, +} + +impl EntropyRng { + /// Create a new `EntropyRng`. + /// + /// This method will do no system calls or other initialization routines, + /// those are done on first use. This is done to make `new` infallible, + /// and `try_fill_bytes` the only place to report errors. + pub fn new() -> Self { + EntropyRng { source: Source::None } + } +} + +impl Default for EntropyRng { + fn default() -> Self { + EntropyRng::new() + } +} + +impl RngCore for EntropyRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest).unwrap_or_else(|err| + panic!("all entropy sources failed; first error: {}", err)) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mut reported_error = None; + + if let Source::Os(ref mut os_rng) = self.source { + match os_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: OsRng failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Os::is_supported() { + match Os::new_and_fill(dest) { + Ok(os_rng) => { + debug!("EntropyRng: using OsRng"); + self.source = Source::Os(os_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Custom(ref mut rng) = self.source { + match rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: custom entropy source failed \ + [trying other entropy sources]: {}", err); + reported_error = Some(err); + }, + } + } else if Custom::is_supported() { + match Custom::new_and_fill(dest) { + Ok(custom) => { + debug!("EntropyRng: using custom entropy source"); + self.source = Source::Custom(custom); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Source::Jitter(ref mut jitter_rng) = self.source { + match jitter_rng.fill(dest) { + Ok(()) => return Ok(()), + Err(err) => { + warn!("EntropyRng: JitterRng failed: {}", err); + reported_error = Some(err); + }, + } + } else if Jitter::is_supported() { + match Jitter::new_and_fill(dest) { + Ok(jitter_rng) => { + debug!("EntropyRng: using JitterRng"); + self.source = Source::Jitter(jitter_rng); + return Ok(()); + }, + Err(err) => { reported_error = reported_error.or(Some(err)) }, + } + } + + if let Some(err) = reported_error { + Err(Error::with_cause(ErrorKind::Unavailable, + "All entropy sources failed", + err)) + } else { + Err(Error::new(ErrorKind::Unavailable, + "No entropy sources available")) + } + } +} + +impl CryptoRng for EntropyRng {} + + + +trait EntropySource { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> + where Self: Sized; + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + fn is_supported() -> bool { true } +} + +#[allow(unused)] +#[derive(Clone, Debug)] +struct NoSource; + +#[allow(unused)] +impl EntropySource for NoSource { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + Err(Error::new(ErrorKind::Unavailable, "Source not supported")) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unreachable!() + } + + fn is_supported() -> bool { false } +} + + +#[cfg(feature="rand_os")] +#[derive(Clone, Debug)] +pub struct Os(rngs::OsRng); + +#[cfg(feature="rand_os")] +impl EntropySource for Os { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + let mut rng = rngs::OsRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Os(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(not(feature="std"))] +type Os = NoSource; + + +type Custom = NoSource; + + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Clone, Debug)] +pub struct Jitter(rngs::JitterRng); + +#[cfg(not(target_arch = "wasm32"))] +impl EntropySource for Jitter { + fn new_and_fill(dest: &mut [u8]) -> Result<Self, Error> { + let mut rng = rngs::JitterRng::new()?; + rng.try_fill_bytes(dest)?; + Ok(Jitter(rng)) + } + + fn fill(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +#[cfg(target_arch = "wasm32")] +type Jitter = NoSource; + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_entropy() { + let mut rng = EntropyRng::new(); + let n = (rng.next_u32() ^ rng.next_u32()).count_ones(); + assert!(n >= 2); // p(failure) approx 1e-7 + } +} diff --git a/rand/src/rngs/mock.rs b/rand/src/rngs/mock.rs new file mode 100644 index 000000000..3c9a994eb --- /dev/null +++ b/rand/src/rngs/mock.rs @@ -0,0 +1,59 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Mock random number generator + +use rand_core::{RngCore, Error, impls}; + +/// A simple implementation of `RngCore` for testing purposes. +/// +/// This generates an arithmetic sequence (i.e. adds a constant each step) +/// over a `u64` number, using wrapping arithmetic. If the increment is 0 +/// the generator yields a constant. +/// +/// ``` +/// use rand::Rng; +/// use rand::rngs::mock::StepRng; +/// +/// let mut my_rng = StepRng::new(2, 1); +/// let sample: [u64; 3] = my_rng.gen(); +/// assert_eq!(sample, [2, 3, 4]); +/// ``` +#[derive(Debug, Clone)] +pub struct StepRng { + v: u64, + a: u64, +} + +impl StepRng { + /// Create a `StepRng`, yielding an arithmetic sequence starting with + /// `initial` and incremented by `increment` each time. + pub fn new(initial: u64, increment: u64) -> Self { + StepRng { v: initial, a: increment } + } +} + +impl RngCore for StepRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + let result = self.v; + self.v = self.v.wrapping_add(self.a); + result + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/rand/src/rngs/mod.rs b/rand/src/rngs/mod.rs new file mode 100644 index 000000000..b3f05a072 --- /dev/null +++ b/rand/src/rngs/mod.rs @@ -0,0 +1,167 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generators and adapters for common usage: +//! +//! - [`ThreadRng`], a fast, secure, auto-seeded thread-local generator +//! - [`StdRng`] and [`SmallRng`], algorithms to cover typical usage +//! - [`EntropyRng`], [`OsRng`] and [`JitterRng`] as entropy sources +//! - [`mock::StepRng`] as a simple counter for tests +//! - [`adapter::ReadRng`] to read from a file/stream +//! - [`adapter::ReseedingRng`] to reseed a PRNG on clone / process fork etc. +//! +//! # Background — Random number generators (RNGs) +//! +//! Computers are inherently deterministic, so to get *random* numbers one +//! either has to use a hardware generator or collect bits of *entropy* from +//! various sources (e.g. event timestamps, or jitter). This is a relatively +//! slow and complicated operation. +//! +//! Generally the operating system will collect some entropy, remove bias, and +//! use that to seed its own PRNG; [`OsRng`] provides an interface to this. +//! [`JitterRng`] is an entropy collector included with Rand that measures +//! jitter in the CPU execution time, and jitter in memory access time. +//! [`EntropyRng`] is a wrapper that uses the best entropy source that is +//! available. +//! +//! ## Pseudo-random number generators +//! +//! What is commonly used instead of "true" random number renerators, are +//! *pseudo-random number generators* (PRNGs), deterministic algorithms that +//! produce an infinite stream of pseudo-random numbers from a small random +//! seed. PRNGs are faster, and have better provable properties. The numbers +//! produced can be statistically of very high quality and can be impossible to +//! predict. (They can also have obvious correlations and be trivial to predict; +//! quality varies.) +//! +//! There are two different types of PRNGs: those developed for simulations +//! and statistics, and those developed for use in cryptography; the latter are +//! called Cryptographically Secure PRNGs (CSPRNG or CPRNG). Both types can +//! have good statistical quality but the latter also have to be impossible to +//! predict, even after seeing many previous output values. Rand provides a good +//! default algorithm from each class: +//! +//! - [`SmallRng`] is a PRNG chosen for low memory usage, high performance and +//! good statistical quality. +//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security +//! (based on reviews, maturity and usage). The current algorithm is HC-128, +//! which is one of the recommendations by ECRYPT's eSTREAM project. +//! +//! The above PRNGs do not cover all use-cases; more algorithms can be found in +//! the [`prng`][crate::prng] module, as well as in several other crates. For example, you +//! may wish a CSPRNG with significantly lower memory usage than [`StdRng`] +//! while being less concerned about performance, in which case [`ChaChaRng`] +//! is a good choice. +//! +//! One complexity is that the internal state of a PRNG must change with every +//! generated number. For APIs this generally means a mutable reference to the +//! state of the PRNG has to be passed around. +//! +//! A solution is [`ThreadRng`]. This is a thread-local implementation of +//! [`StdRng`] with automatic seeding on first use. It is the best choice if you +//! "just" want a convenient, secure, fast random number source. Use via the +//! [`thread_rng`] function, which gets a reference to the current thread's +//! local instance. +//! +//! ## Seeding +//! +//! As mentioned above, PRNGs require a random seed in order to produce random +//! output. This is especially important for CSPRNGs, which are still +//! deterministic algorithms, thus can only be secure if their seed value is +//! also secure. To seed a PRNG, use one of: +//! +//! - [`FromEntropy::from_entropy`]; this is the most convenient way to seed +//! with fresh, secure random data. +//! - [`SeedableRng::from_rng`]; this allows seeding from another PRNG or +//! from an entropy source such as [`EntropyRng`]. +//! - [`SeedableRng::from_seed`]; this is mostly useful if you wish to be able +//! to reproduce the output sequence by using a fixed seed. (Don't use +//! [`StdRng`] or [`SmallRng`] in this case since different algorithms may be +//! used by future versions of Rand; use an algorithm from the +//! [`prng`] module.) +//! +//! ## Conclusion +//! +//! - [`thread_rng`] is what you often want to use. +//! - If you want more control, flexibility, or better performance, use +//! [`StdRng`], [`SmallRng`] or an algorithm from the [`prng`] module. +//! - Use [`FromEntropy::from_entropy`] to seed new PRNGs. +//! - If you need reproducibility, use [`SeedableRng::from_seed`] combined with +//! a named PRNG. +//! +//! More information and notes on cryptographic security can be found +//! in the [`prng`] module. +//! +//! ## Examples +//! +//! Examples of seeding PRNGs: +//! +//! ``` +//! use rand::prelude::*; +//! # use rand::Error; +//! +//! // StdRng seeded securely by the OS or local entropy collector: +//! let mut rng = StdRng::from_entropy(); +//! # let v: u32 = rng.gen(); +//! +//! // SmallRng seeded from thread_rng: +//! # fn try_inner() -> Result<(), Error> { +//! let mut rng = SmallRng::from_rng(thread_rng())?; +//! # let v: u32 = rng.gen(); +//! # Ok(()) +//! # } +//! # try_inner().unwrap(); +//! +//! // SmallRng seeded by a constant, for deterministic results: +//! let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; // byte array +//! let mut rng = SmallRng::from_seed(seed); +//! # let v: u32 = rng.gen(); +//! ``` +//! +//! +//! # Implementing custom RNGs +//! +//! If you want to implement custom RNG, see the [`rand_core`] crate. The RNG +//! will have to implement the [`RngCore`] trait, where the [`Rng`] trait is +//! build on top of. +//! +//! If the RNG needs seeding, also implement the [`SeedableRng`] trait. +//! +//! [`CryptoRng`] is a marker trait cryptographically secure PRNGs can +//! implement. +//! +//! [`OsRng`]: rand_os::OsRng +//! [`SmallRng`]: rngs::SmallRng +//! [`StdRng`]: rngs::StdRng +//! [`ThreadRng`]: rngs::ThreadRng +//! [`EntropyRng`]: rngs::EntropyRng +//! [`JitterRng`]: rngs::JitterRng +//! [`mock::StepRng`]: rngs::mock::StepRng +//! [`adapter::ReadRng`]: rngs::adapter::ReadRng +//! [`adapter::ReseedingRng`]: rngs::adapter::ReseedingRng +//! [`ChaChaRng`]: rand_chacha::ChaChaRng + +pub mod adapter; + +#[cfg(feature="std")] mod entropy; +pub mod mock; // Public so we don't export `StepRng` directly, making it a bit + // more clear it is intended for testing. +mod small; +mod std; +#[cfg(feature="std")] pub(crate) mod thread; + + +pub use rand_jitter::{JitterRng, TimerError}; +#[cfg(feature="std")] pub use self::entropy::EntropyRng; + +pub use self::small::SmallRng; +pub use self::std::StdRng; +#[cfg(feature="std")] pub use self::thread::ThreadRng; + +#[cfg(feature="rand_os")] +pub use rand_os::OsRng; diff --git a/rand/src/rngs/small.rs b/rand/src/rngs/small.rs new file mode 100644 index 000000000..9874d2469 --- /dev/null +++ b/rand/src/rngs/small.rs @@ -0,0 +1,106 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A small fast RNG + +use {RngCore, SeedableRng, Error}; + +#[cfg(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64"))] +type Rng = ::rand_pcg::Pcg64Mcg; +#[cfg(not(all(all(rustc_1_26, not(target_os = "emscripten")), target_pointer_width = "64")))] +type Rng = ::rand_pcg::Pcg32; + +/// An RNG recommended when small state, cheap initialization and good +/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be +/// efficient on the current platform, **without consideration for cryptography +/// or security**. The size of its state is much smaller than for [`StdRng`]. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG. +/// Refer to [The Book](https://rust-random.github.io/book/guide-rngs.html). +/// +/// +/// The current algorithm is [`Pcg64Mcg`][rand_pcg::Pcg64Mcg] on 64-bit platforms with Rust version +/// 1.26 and later, or [`Pcg32`][rand_pcg::Pcg32] otherwise. Both are found in +/// the [rand_pcg] crate. +/// +/// # Examples +/// +/// Initializing `SmallRng` with a random seed can be done using [`FromEntropy`]: +/// +/// ``` +/// # use rand::Rng; +/// use rand::FromEntropy; +/// use rand::rngs::SmallRng; +/// +/// // Create small, cheap to initialize and fast RNG with a random seed. +/// // The randomness is supplied by the operating system. +/// let mut small_rng = SmallRng::from_entropy(); +/// # let v: u32 = small_rng.gen(); +/// ``` +/// +/// When initializing a lot of `SmallRng`'s, using [`thread_rng`] can be more +/// efficient: +/// +/// ``` +/// use std::iter; +/// use rand::{SeedableRng, thread_rng}; +/// use rand::rngs::SmallRng; +/// +/// // Create a big, expensive to initialize and slower, but unpredictable RNG. +/// // This is cached and done only once per thread. +/// let mut thread_rng = thread_rng(); +/// // Create small, cheap to initialize and fast RNGs with random seeds. +/// // One can generally assume this won't fail. +/// let rngs: Vec<SmallRng> = iter::repeat(()) +/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap()) +/// .take(10) +/// .collect(); +/// ``` +/// +/// [`FromEntropy`]: crate::FromEntropy +/// [`StdRng`]: crate::rngs::StdRng +/// [`thread_rng`]: crate::thread_rng +/// [rand_pcg]: https://crates.io/crates/rand_pcg +#[derive(Clone, Debug)] +pub struct SmallRng(Rng); + +impl RngCore for SmallRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for SmallRng { + type Seed = <Rng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + SmallRng(Rng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + Rng::from_rng(rng).map(SmallRng) + } +} diff --git a/rand/src/rngs/std.rs b/rand/src/rngs/std.rs new file mode 100644 index 000000000..e67a76da8 --- /dev/null +++ b/rand/src/rngs/std.rs @@ -0,0 +1,85 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The standard RNG + +use {RngCore, CryptoRng, Error, SeedableRng}; +use rand_hc::Hc128Rng; + +/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient +/// on the current platform, to be statistically strong and unpredictable +/// (meaning a cryptographically secure PRNG). +/// +/// The current algorithm used on all platforms is [HC-128], found in the +/// [rand_hc] crate. +/// +/// Reproducibility of output from this generator is however not required, thus +/// future library versions may use a different internal generator with +/// different output. Further, this generator may not be portable and can +/// produce different output depending on the architecture. If you require +/// reproducible output, use a named RNG, for example [`ChaChaRng`] from the +/// [rand_chacha] crate. +/// +/// [HC-128]: rand_hc::Hc128Rng +/// [`ChaChaRng`]: rand_chacha::ChaChaRng +/// [rand_hc]: https://crates.io/crates/rand_hc +/// [rand_chacha]: https://crates.io/crates/rand_chacha +#[derive(Clone, Debug)] +pub struct StdRng(Hc128Rng); + +impl RngCore for StdRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for StdRng { + type Seed = <Hc128Rng as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + StdRng(Hc128Rng::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + Hc128Rng::from_rng(rng).map(StdRng) + } +} + +impl CryptoRng for StdRng {} + + +#[cfg(test)] +mod test { + use {RngCore, SeedableRng}; + use rngs::StdRng; + + #[test] + fn test_stdrng_construction() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = StdRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 15759097995037006553); + + let mut rng2 = StdRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 6766915756997287454); + } +} diff --git a/rand/src/rngs/thread.rs b/rand/src/rngs/thread.rs new file mode 100644 index 000000000..f1aa787dc --- /dev/null +++ b/rand/src/rngs/thread.rs @@ -0,0 +1,137 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Thread-local random number generator + +use std::cell::UnsafeCell; + +use {RngCore, CryptoRng, SeedableRng, Error}; +use rngs::adapter::ReseedingRng; +use rngs::EntropyRng; +use rand_hc::Hc128Core; + +// Rationale for using `UnsafeCell` in `ThreadRng`: +// +// Previously we used a `RefCell`, with an overhead of ~15%. There will only +// ever be one mutable reference to the interior of the `UnsafeCell`, because +// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a +// single thread (which is the definition of `ThreadRng`), there will only ever +// be one of these methods active at a time. +// +// A possible scenario where there could be multiple mutable references is if +// `ThreadRng` is used inside `next_u32` and co. But the implementation is +// completely under our control. We just have to ensure none of them use +// `ThreadRng` internally, which is nonsensical anyway. We should also never run +// `ThreadRng` in destructors of its implementation, which is also nonsensical. +// +// The additional `Rc` is not strictly neccesary, and could be removed. For now +// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`. + + +// Number of generated bytes after which to reseed `TreadRng`. +// +// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB. +// We pick a treshold here that is large enough to not reduce the average +// performance too much, but also small enough to not make reseeding something +// that basically never happens. +const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB + +/// The type returned by [`thread_rng`], essentially just a reference to the +/// PRNG in thread-local memory. +/// +/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`], +/// which is reseeded after generating 32 MiB of random data. A single instance +/// is cached per thread and the returned `ThreadRng` is a reference to this +/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use +/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`] +/// as required. +/// +/// Note that the reseeding is done as an extra precaution against entropy +/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an +/// attacker would have to either determine most of the RNG's seed or internal +/// state, or crack the algorithm used. +/// +/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current +/// algorithm used is [HC-128], which is an array-based PRNG that trades memory +/// usage for better performance. This makes it similar to ISAAC, the algorithm +/// used in `ThreadRng` before rand 0.5. +/// +/// Cloning this handle just produces a new reference to the same thread-local +/// generator. +/// +/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng +/// [`StdRng`]: crate::rngs::StdRng +/// [HC-128]: rand_hc::Hc128Rng +#[derive(Clone, Debug)] +pub struct ThreadRng { + // use of raw pointer implies type is neither Send nor Sync + rng: *mut ReseedingRng<Hc128Core, EntropyRng>, +} + +thread_local!( + static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>> = { + let mut entropy_source = EntropyRng::new(); + let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err| + panic!("could not initialize thread_rng: {}", err)); + let rng = ReseedingRng::new(r, + THREAD_RNG_RESEED_THRESHOLD, + entropy_source); + UnsafeCell::new(rng) + } +); + +/// Retrieve the lazily-initialized thread-local random number generator, +/// seeded by the system. Intended to be used in method chaining style, +/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g. +/// `let mut rng = thread_rng();`. Invoked by the `Default` trait, making +/// `ThreadRng::default()` equivelent. +/// +/// For more information see [`ThreadRng`]. +pub fn thread_rng() -> ThreadRng { + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.get()) } +} + +impl Default for ThreadRng { + fn default() -> ThreadRng { + ::prelude::thread_rng() + } +} + +impl RngCore for ThreadRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + unsafe { (*self.rng).next_u32() } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + unsafe { (*self.rng).next_u64() } + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + unsafe { (*self.rng).fill_bytes(dest) } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + unsafe { (*self.rng).try_fill_bytes(dest) } + } +} + +impl CryptoRng for ThreadRng {} + + +#[cfg(test)] +mod test { + #[test] + fn test_thread_rng() { + use Rng; + let mut r = ::thread_rng(); + r.gen::<i32>(); + assert_eq!(r.gen_range(0, 1), 0); + } +} diff --git a/rand/src/seq/index.rs b/rand/src/seq/index.rs new file mode 100644 index 000000000..a70c7367f --- /dev/null +++ b/rand/src/seq/index.rs @@ -0,0 +1,378 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Index sampling + +#[cfg(feature="alloc")] use core::slice; + +#[cfg(feature="std")] use std::vec; +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::{self, Vec}; +// BTreeMap is not as fast in tests, but better than nothing. +#[cfg(feature="std")] use std::collections::{HashSet}; +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::collections::BTreeSet; + +#[cfg(feature="alloc")] use distributions::{Distribution, Uniform}; +use Rng; + +/// A vector of indices. +/// +/// Multiple internal representations are possible. +#[derive(Clone, Debug)] +pub enum IndexVec { + #[doc(hidden)] U32(Vec<u32>), + #[doc(hidden)] USize(Vec<usize>), +} + +impl IndexVec { + /// Returns the number of indices + pub fn len(&self) -> usize { + match self { + &IndexVec::U32(ref v) => v.len(), + &IndexVec::USize(ref v) => v.len(), + } + } + + /// Return the value at the given `index`. + /// + /// (Note: we cannot implement [`std::ops::Index`] because of lifetime + /// restrictions.) + pub fn index(&self, index: usize) -> usize { + match self { + &IndexVec::U32(ref v) => v[index] as usize, + &IndexVec::USize(ref v) => v[index], + } + } + + /// Return result as a `Vec<usize>`. Conversion may or may not be trivial. + pub fn into_vec(self) -> Vec<usize> { + match self { + IndexVec::U32(v) => v.into_iter().map(|i| i as usize).collect(), + IndexVec::USize(v) => v, + } + } + + /// Iterate over the indices as a sequence of `usize` values + pub fn iter<'a>(&'a self) -> IndexVecIter<'a> { + match self { + &IndexVec::U32(ref v) => IndexVecIter::U32(v.iter()), + &IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()), + } + } + + /// Convert into an iterator over the indices as a sequence of `usize` values + pub fn into_iter(self) -> IndexVecIntoIter { + match self { + IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()), + IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()), + } + } +} + +impl PartialEq for IndexVec { + fn eq(&self, other: &IndexVec) -> bool { + use self::IndexVec::*; + match (self, other) { + (&U32(ref v1), &U32(ref v2)) => v1 == v2, + (&USize(ref v1), &USize(ref v2)) => v1 == v2, + (&U32(ref v1), &USize(ref v2)) => (v1.len() == v2.len()) + && (v1.iter().zip(v2.iter()).all(|(x, y)| *x as usize == *y)), + (&USize(ref v1), &U32(ref v2)) => (v1.len() == v2.len()) + && (v1.iter().zip(v2.iter()).all(|(x, y)| *x == *y as usize)), + } + } +} + +impl From<Vec<u32>> for IndexVec { + fn from(v: Vec<u32>) -> Self { + IndexVec::U32(v) + } +} + +impl From<Vec<usize>> for IndexVec { + fn from(v: Vec<usize>) -> Self { + IndexVec::USize(v) + } +} + +/// Return type of `IndexVec::iter`. +#[derive(Debug)] +pub enum IndexVecIter<'a> { + #[doc(hidden)] U32(slice::Iter<'a, u32>), + #[doc(hidden)] USize(slice::Iter<'a, usize>), +} + +impl<'a> Iterator for IndexVecIter<'a> { + type Item = usize; + fn next(&mut self) -> Option<usize> { + use self::IndexVecIter::*; + match self { + &mut U32(ref mut iter) => iter.next().map(|i| *i as usize), + &mut USize(ref mut iter) => iter.next().cloned(), + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + match self { + &IndexVecIter::U32(ref v) => v.size_hint(), + &IndexVecIter::USize(ref v) => v.size_hint(), + } + } +} + +impl<'a> ExactSizeIterator for IndexVecIter<'a> {} + +/// Return type of `IndexVec::into_iter`. +#[derive(Clone, Debug)] +pub enum IndexVecIntoIter { + #[doc(hidden)] U32(vec::IntoIter<u32>), + #[doc(hidden)] USize(vec::IntoIter<usize>), +} + +impl Iterator for IndexVecIntoIter { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + use self::IndexVecIntoIter::*; + match self { + &mut U32(ref mut v) => v.next().map(|i| i as usize), + &mut USize(ref mut v) => v.next(), + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + use self::IndexVecIntoIter::*; + match self { + &U32(ref v) => v.size_hint(), + &USize(ref v) => v.size_hint(), + } + } +} + +impl ExactSizeIterator for IndexVecIntoIter {} + + +/// Randomly sample exactly `amount` distinct indices from `0..length`, and +/// return them in random order (fully shuffled). +/// +/// This method is used internally by the slice sampling methods, but it can +/// sometimes be useful to have the indices themselves so this is provided as +/// an alternative. +/// +/// The implementation used is not specified; we automatically select the +/// fastest available algorithm for the `length` and `amount` parameters +/// (based on detailed profiling on an Intel Haswell CPU). Roughly speaking, +/// complexity is `O(amount)`, except that when `amount` is small, performance +/// is closer to `O(amount^2)`, and when `length` is close to `amount` then +/// `O(length)`. +/// +/// Note that performance is significantly better over `u32` indices than over +/// `u64` indices. Because of this we hide the underlying type behind an +/// abstraction, `IndexVec`. +/// +/// If an allocation-free `no_std` function is required, it is suggested +/// to adapt the internal `sample_floyd` implementation. +/// +/// Panics if `amount > length`. +pub fn sample<R>(rng: &mut R, length: usize, amount: usize) -> IndexVec + where R: Rng + ?Sized, +{ + if amount > length { + panic!("`amount` of samples must be less than or equal to `length`"); + } + if length > (::core::u32::MAX as usize) { + // We never want to use inplace here, but could use floyd's alg + // Lazy version: always use the cache alg. + return sample_rejection(rng, length, amount); + } + let amount = amount as u32; + let length = length as u32; + + // Choice of algorithm here depends on both length and amount. See: + // https://github.com/rust-random/rand/pull/479 + // We do some calculations with f32. Accuracy is not very important. + + if amount < 163 { + const C: [[f32; 2]; 2] = [[1.6, 8.0/45.0], [10.0, 70.0/9.0]]; + let j = if length < 500_000 { 0 } else { 1 }; + let amount_fp = amount as f32; + let m4 = C[0][j] * amount_fp; + // Short-cut: when amount < 12, floyd's is always faster + if amount > 11 && (length as f32) < (C[1][j] + m4) * amount_fp { + sample_inplace(rng, length, amount) + } else { + sample_floyd(rng, length, amount) + } + } else { + const C: [f32; 2] = [270.0, 330.0/9.0]; + let j = if length < 500_000 { 0 } else { 1 }; + if (length as f32) < C[j] * (amount as f32) { + sample_inplace(rng, length, amount) + } else { + // note: could have a specific u32 impl, but I'm lazy and + // generics don't have usable conversions + sample_rejection(rng, length as usize, amount as usize) + } + } +} + +/// Randomly sample exactly `amount` indices from `0..length`, using Floyd's +/// combination algorithm. +/// +/// The output values are fully shuffled. (Overhead is under 50%.) +/// +/// This implementation uses `O(amount)` memory and `O(amount^2)` time. +fn sample_floyd<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec + where R: Rng + ?Sized, +{ + // For small amount we use Floyd's fully-shuffled variant. For larger + // amounts this is slow due to Vec::insert performance, so we shuffle + // afterwards. Benchmarks show little overhead from extra logic. + let floyd_shuffle = amount < 50; + + debug_assert!(amount <= length); + let mut indices = Vec::with_capacity(amount as usize); + for j in length - amount .. length { + let t = rng.gen_range(0, j + 1); + if floyd_shuffle { + if let Some(pos) = indices.iter().position(|&x| x == t) { + indices.insert(pos, j); + continue; + } + } else { + if indices.contains(&t) { + indices.push(j); + continue; + } + } + indices.push(t); + } + if !floyd_shuffle { + // Reimplement SliceRandom::shuffle with smaller indices + for i in (1..amount).rev() { + // invariant: elements with index > i have been locked in place. + indices.swap(i as usize, rng.gen_range(0, i + 1) as usize); + } + } + IndexVec::from(indices) +} + +/// Randomly sample exactly `amount` indices from `0..length`, using an inplace +/// partial Fisher-Yates method. +/// Sample an amount of indices using an inplace partial fisher yates method. +/// +/// This allocates the entire `length` of indices and randomizes only the first `amount`. +/// It then truncates to `amount` and returns. +/// +/// This method is not appropriate for large `length` and potentially uses a lot +/// of memory; because of this we only implement for `u32` index (which improves +/// performance in all cases). +/// +/// Set-up is `O(length)` time and memory and shuffling is `O(amount)` time. +fn sample_inplace<R>(rng: &mut R, length: u32, amount: u32) -> IndexVec + where R: Rng + ?Sized, +{ + debug_assert!(amount <= length); + let mut indices: Vec<u32> = Vec::with_capacity(length as usize); + indices.extend(0..length); + for i in 0..amount { + let j: u32 = rng.gen_range(i, length); + indices.swap(i as usize, j as usize); + } + indices.truncate(amount as usize); + debug_assert_eq!(indices.len(), amount as usize); + IndexVec::from(indices) +} + +/// Randomly sample exactly `amount` indices from `0..length`, using rejection +/// sampling. +/// +/// Since `amount <<< length` there is a low chance of a random sample in +/// `0..length` being a duplicate. We test for duplicates and resample where +/// necessary. The algorithm is `O(amount)` time and memory. +fn sample_rejection<R>(rng: &mut R, length: usize, amount: usize) -> IndexVec + where R: Rng + ?Sized, +{ + debug_assert!(amount < length); + #[cfg(feature="std")] let mut cache = HashSet::with_capacity(amount); + #[cfg(not(feature="std"))] let mut cache = BTreeSet::new(); + let distr = Uniform::new(0, length); + let mut indices = Vec::with_capacity(amount); + for _ in 0..amount { + let mut pos = distr.sample(rng); + while !cache.insert(pos) { + pos = distr.sample(rng); + } + indices.push(pos); + } + + debug_assert_eq!(indices.len(), amount); + IndexVec::from(indices) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_sample_boundaries() { + let mut r = ::test::rng(404); + + assert_eq!(sample_inplace(&mut r, 0, 0).len(), 0); + assert_eq!(sample_inplace(&mut r, 1, 0).len(), 0); + assert_eq!(sample_inplace(&mut r, 1, 1).into_vec(), vec![0]); + + assert_eq!(sample_rejection(&mut r, 1, 0).len(), 0); + + assert_eq!(sample_floyd(&mut r, 0, 0).len(), 0); + assert_eq!(sample_floyd(&mut r, 1, 0).len(), 0); + assert_eq!(sample_floyd(&mut r, 1, 1).into_vec(), vec![0]); + + // These algorithms should be fast with big numbers. Test average. + let sum: usize = sample_rejection(&mut r, 1 << 25, 10) + .into_iter().sum(); + assert!(1 << 25 < sum && sum < (1 << 25) * 25); + + let sum: usize = sample_floyd(&mut r, 1 << 25, 10) + .into_iter().sum(); + assert!(1 << 25 < sum && sum < (1 << 25) * 25); + } + + #[test] + fn test_sample_alg() { + let seed_rng = ::test::rng; + + // We can't test which algorithm is used directly, but Floyd's alg + // should produce different results from the others. (Also, `inplace` + // and `cached` currently use different sizes thus produce different results.) + + // A small length and relatively large amount should use inplace + let (length, amount): (usize, usize) = (100, 50); + let v1 = sample(&mut seed_rng(420), length, amount); + let v2 = sample_inplace(&mut seed_rng(420), length as u32, amount as u32); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + + // Test Floyd's alg does produce different results + let v3 = sample_floyd(&mut seed_rng(420), length as u32, amount as u32); + assert!(v1 != v3); + + // A large length and small amount should use Floyd + let (length, amount): (usize, usize) = (1<<20, 50); + let v1 = sample(&mut seed_rng(421), length, amount); + let v2 = sample_floyd(&mut seed_rng(421), length as u32, amount as u32); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + + // A large length and larger amount should use cache + let (length, amount): (usize, usize) = (1<<20, 600); + let v1 = sample(&mut seed_rng(422), length, amount); + let v2 = sample_rejection(&mut seed_rng(422), length, amount); + assert!(v1.iter().all(|e| e < length)); + assert_eq!(v1, v2); + } +} diff --git a/rand/src/seq/mod.rs b/rand/src/seq/mod.rs new file mode 100644 index 000000000..d0f83084a --- /dev/null +++ b/rand/src/seq/mod.rs @@ -0,0 +1,829 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Functions for randomly accessing and sampling sequences. +//! +//! TODO: module doc + + +#[cfg(feature="alloc")] pub mod index; + +#[cfg(feature="alloc")] use core::ops::Index; + +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::vec::Vec; + +use Rng; +#[cfg(feature="alloc")] use distributions::WeightedError; +#[cfg(feature="alloc")] use distributions::uniform::{SampleUniform, SampleBorrow}; + +/// Extension trait on slices, providing random mutation and sampling methods. +/// +/// An implementation is provided for slices. This may also be implementable for +/// other types. +pub trait SliceRandom { + /// The element type. + type Item; + + /// Returns a reference to one random element of the slice, or `None` if the + /// slice is empty. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::seq::SliceRandom; + /// + /// let choices = [1, 2, 4, 8, 16, 32]; + /// let mut rng = thread_rng(); + /// println!("{:?}", choices.choose(&mut rng)); + /// assert_eq!(choices[..0].choose(&mut rng), None); + /// ``` + fn choose<R>(&self, rng: &mut R) -> Option<&Self::Item> + where R: Rng + ?Sized; + + /// Returns a mutable reference to one random element of the slice, or + /// `None` if the slice is empty. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + fn choose_mut<R>(&mut self, rng: &mut R) -> Option<&mut Self::Item> + where R: Rng + ?Sized; + + /// Produces an iterator that chooses `amount` elements from the slice at + /// random without repeating any, and returns them in random order. + /// + /// In case this API is not sufficiently flexible, use `index::sample` then + /// apply the indices to the slice. + /// + /// Complexity is expected to be the same as `index::sample`. + /// + /// # Example + /// ``` + /// use rand::seq::SliceRandom; + /// + /// let mut rng = &mut rand::thread_rng(); + /// let sample = "Hello, audience!".as_bytes(); + /// + /// // collect the results into a vector: + /// let v: Vec<u8> = sample.choose_multiple(&mut rng, 3).cloned().collect(); + /// + /// // store in a buffer: + /// let mut buf = [0u8; 5]; + /// for (b, slot) in sample.choose_multiple(&mut rng, buf.len()).zip(buf.iter_mut()) { + /// *slot = *b; + /// } + /// ``` + #[cfg(feature = "alloc")] + fn choose_multiple<R>(&self, rng: &mut R, amount: usize) -> SliceChooseIter<Self, Self::Item> + where R: Rng + ?Sized; + + /// Similar to [`choose`], where the likelihood of each outcome may be + /// specified. The specified function `weight` maps items `x` to a relative + /// likelihood `weight(x)`. The probability of each item being selected is + /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`. + /// + /// # Example + /// + /// ``` + /// use rand::prelude::*; + /// + /// let choices = [('a', 2), ('b', 1), ('c', 1)]; + /// let mut rng = thread_rng(); + /// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c' + /// println!("{:?}", choices.choose_weighted(&mut rng, |item| item.1).unwrap().0); + /// ``` + /// [`choose`]: SliceRandom::choose + #[cfg(feature = "alloc")] + fn choose_weighted<R, F, B, X>(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow<X>, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd<X> + + Clone + + Default; + + /// Similar to [`choose_mut`], where the likelihood of each outcome may be + /// specified. The specified function `weight` maps items `x` to a relative + /// likelihood `weight(x)`. The probability of each item being selected is + /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`. + /// + /// See also [`choose_weighted`]. + /// + /// [`choose_mut`]: SliceRandom::choose_mut + /// [`choose_weighted`]: SliceRandom::choose_weighted + #[cfg(feature = "alloc")] + fn choose_weighted_mut<R, F, B, X>(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow<X>, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd<X> + + Clone + + Default; + + /// Shuffle a mutable slice in place. + /// + /// Depending on the implementation, complexity is expected to be `O(1)`. + /// + /// # Example + /// + /// ``` + /// use rand::thread_rng; + /// use rand::seq::SliceRandom; + /// + /// let mut rng = thread_rng(); + /// let mut y = [1, 2, 3, 4, 5]; + /// println!("Unshuffled: {:?}", y); + /// y.shuffle(&mut rng); + /// println!("Shuffled: {:?}", y); + /// ``` + fn shuffle<R>(&mut self, rng: &mut R) where R: Rng + ?Sized; + + /// Shuffle a slice in place, but exit early. + /// + /// Returns two mutable slices from the source slice. The first contains + /// `amount` elements randomly permuted. The second has the remaining + /// elements that are not fully shuffled. + /// + /// This is an efficient method to select `amount` elements at random from + /// the slice, provided the slice may be mutated. + /// + /// If you only need to choose elements randomly and `amount > self.len()/2` + /// then you may improve performance by taking + /// `amount = values.len() - amount` and using only the second slice. + /// + /// If `amount` is greater than the number of elements in the slice, this + /// will perform a full shuffle. + /// + /// Complexity is expected to be `O(m)` where `m = amount`. + fn partial_shuffle<R>(&mut self, rng: &mut R, amount: usize) + -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized; +} + +/// Extension trait on iterators, providing random sampling methods. +pub trait IteratorRandom: Iterator + Sized { + /// Choose one element at random from the iterator. If you have a slice, + /// it's significantly faster to call the [`choose`] or [`choose_mut`] + /// functions using the slice instead. + /// + /// Returns `None` if and only if the iterator is empty. + /// + /// Complexity is `O(n)`, where `n` is the length of the iterator. + /// This likely consumes multiple random numbers, but the exact number + /// is unspecified. + /// + /// [`choose`]: SliceRandom::method.choose + /// [`choose_mut`]: SliceRandom::choose_mut + fn choose<R>(mut self, rng: &mut R) -> Option<Self::Item> + where R: Rng + ?Sized + { + let (mut lower, mut upper) = self.size_hint(); + let mut consumed = 0; + let mut result = None; + + if upper == Some(lower) { + return if lower == 0 { None } else { self.nth(rng.gen_range(0, lower)) }; + } + + // Continue until the iterator is exhausted + loop { + if lower > 1 { + let ix = rng.gen_range(0, lower + consumed); + let skip; + if ix < lower { + result = self.nth(ix); + skip = lower - (ix + 1); + } else { + skip = lower; + } + if upper == Some(lower) { + return result; + } + consumed += lower; + if skip > 0 { + self.nth(skip - 1); + } + } else { + let elem = self.next(); + if elem.is_none() { + return result; + } + consumed += 1; + let denom = consumed as f64; // accurate to 2^53 elements + if rng.gen_bool(1.0 / denom) { + result = elem; + } + } + + let hint = self.size_hint(); + lower = hint.0; + upper = hint.1; + } + } + + /// Collects `amount` values at random from the iterator into a supplied + /// buffer. + /// + /// Although the elements are selected randomly, the order of elements in + /// the buffer is neither stable nor fully random. If random ordering is + /// desired, shuffle the result. + /// + /// Returns the number of elements added to the buffer. This equals `amount` + /// unless the iterator contains insufficient elements, in which case this + /// equals the number of elements available. + /// + /// Complexity is `O(n)` where `n` is the length of the iterator. + fn choose_multiple_fill<R>(mut self, rng: &mut R, buf: &mut [Self::Item]) + -> usize where R: Rng + ?Sized + { + let amount = buf.len(); + let mut len = 0; + while len < amount { + if let Some(elem) = self.next() { + buf[len] = elem; + len += 1; + } else { + // Iterator exhausted; stop early + return len; + } + } + + // Continue, since the iterator was not exhausted + for (i, elem) in self.enumerate() { + let k = rng.gen_range(0, i + 1 + amount); + if let Some(slot) = buf.get_mut(k) { + *slot = elem; + } + } + len + } + + /// Collects `amount` values at random from the iterator into a vector. + /// + /// This is equivalent to `choose_multiple_fill` except for the result type. + /// + /// Although the elements are selected randomly, the order of elements in + /// the buffer is neither stable nor fully random. If random ordering is + /// desired, shuffle the result. + /// + /// The length of the returned vector equals `amount` unless the iterator + /// contains insufficient elements, in which case it equals the number of + /// elements available. + /// + /// Complexity is `O(n)` where `n` is the length of the iterator. + #[cfg(feature = "alloc")] + fn choose_multiple<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item> + where R: Rng + ?Sized + { + let mut reservoir = Vec::with_capacity(amount); + reservoir.extend(self.by_ref().take(amount)); + + // Continue unless the iterator was exhausted + // + // note: this prevents iterators that "restart" from causing problems. + // If the iterator stops once, then so do we. + if reservoir.len() == amount { + for (i, elem) in self.enumerate() { + let k = rng.gen_range(0, i + 1 + amount); + if let Some(slot) = reservoir.get_mut(k) { + *slot = elem; + } + } + } else { + // Don't hang onto extra memory. There is a corner case where + // `amount` was much less than `self.len()`. + reservoir.shrink_to_fit(); + } + reservoir + } +} + + +impl<T> SliceRandom for [T] { + type Item = T; + + fn choose<R>(&self, rng: &mut R) -> Option<&Self::Item> + where R: Rng + ?Sized + { + if self.is_empty() { + None + } else { + Some(&self[rng.gen_range(0, self.len())]) + } + } + + fn choose_mut<R>(&mut self, rng: &mut R) -> Option<&mut Self::Item> + where R: Rng + ?Sized + { + if self.is_empty() { + None + } else { + let len = self.len(); + Some(&mut self[rng.gen_range(0, len)]) + } + } + + #[cfg(feature = "alloc")] + fn choose_multiple<R>(&self, rng: &mut R, amount: usize) + -> SliceChooseIter<Self, Self::Item> + where R: Rng + ?Sized + { + let amount = ::core::cmp::min(amount, self.len()); + SliceChooseIter { + slice: self, + _phantom: Default::default(), + indices: index::sample(rng, self.len(), amount).into_iter(), + } + } + + #[cfg(feature = "alloc")] + fn choose_weighted<R, F, B, X>(&self, rng: &mut R, weight: F) -> Result<&Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow<X>, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd<X> + + Clone + + Default { + use distributions::{Distribution, WeightedIndex}; + let distr = WeightedIndex::new(self.iter().map(weight))?; + Ok(&self[distr.sample(rng)]) + } + + #[cfg(feature = "alloc")] + fn choose_weighted_mut<R, F, B, X>(&mut self, rng: &mut R, weight: F) -> Result<&mut Self::Item, WeightedError> + where R: Rng + ?Sized, + F: Fn(&Self::Item) -> B, + B: SampleBorrow<X>, + X: SampleUniform + + for<'a> ::core::ops::AddAssign<&'a X> + + ::core::cmp::PartialOrd<X> + + Clone + + Default { + use distributions::{Distribution, WeightedIndex}; + let distr = WeightedIndex::new(self.iter().map(weight))?; + Ok(&mut self[distr.sample(rng)]) + } + + fn shuffle<R>(&mut self, rng: &mut R) where R: Rng + ?Sized + { + for i in (1..self.len()).rev() { + // invariant: elements with index > i have been locked in place. + self.swap(i, rng.gen_range(0, i + 1)); + } + } + + fn partial_shuffle<R>(&mut self, rng: &mut R, amount: usize) + -> (&mut [Self::Item], &mut [Self::Item]) where R: Rng + ?Sized + { + // This applies Durstenfeld's algorithm for the + // [Fisher–Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm) + // for an unbiased permutation, but exits early after choosing `amount` + // elements. + + let len = self.len(); + let end = if amount >= len { 0 } else { len - amount }; + + for i in (end..len).rev() { + // invariant: elements with index > i have been locked in place. + self.swap(i, rng.gen_range(0, i + 1)); + } + let r = self.split_at_mut(end); + (r.1, r.0) + } +} + +impl<I> IteratorRandom for I where I: Iterator + Sized {} + + +/// Iterator over multiple choices, as returned by [`SliceRandom::choose_multiple] +#[cfg(feature = "alloc")] +#[derive(Debug)] +pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> { + slice: &'a S, + _phantom: ::core::marker::PhantomData<T>, + indices: index::IndexVecIntoIter, +} + +#[cfg(feature = "alloc")] +impl<'a, S: Index<usize, Output = T> + ?Sized + 'a, T: 'a> Iterator for SliceChooseIter<'a, S, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + // TODO: investigate using SliceIndex::get_unchecked when stable + self.indices.next().map(|i| &self.slice[i as usize]) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.indices.len(), Some(self.indices.len())) + } +} + +#[cfg(feature = "alloc")] +impl<'a, S: Index<usize, Output = T> + ?Sized + 'a, T: 'a> ExactSizeIterator + for SliceChooseIter<'a, S, T> +{ + fn len(&self) -> usize { + self.indices.len() + } +} + + +/// Randomly sample `amount` elements from a finite iterator. +/// +/// Deprecated: use [`IteratorRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use IteratorRandom::choose_multiple instead")] +pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Result<Vec<T>, Vec<T>> + where I: IntoIterator<Item=T>, + R: Rng + ?Sized, +{ + use seq::IteratorRandom; + let iter = iterable.into_iter(); + let result = iter.choose_multiple(rng, amount); + if result.len() == amount { + Ok(result) + } else { + Err(result) + } +} + +/// Randomly sample exactly `amount` values from `slice`. +/// +/// The values are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// Deprecated: use [`SliceRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")] +pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T> + where R: Rng + ?Sized, + T: Clone +{ + let indices = index::sample(rng, slice.len(), amount).into_iter(); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.map(|i| slice[i].clone())); + out +} + +/// Randomly sample exactly `amount` references from `slice`. +/// +/// The references are non-repeating and in random order. +/// +/// This implementation uses `O(amount)` time and memory. +/// +/// Panics if `amount > slice.len()` +/// +/// Deprecated: use [`SliceRandom::choose_multiple`] instead. +#[cfg(feature = "alloc")] +#[deprecated(since="0.6.0", note="use SliceRandom::choose_multiple instead")] +pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T> + where R: Rng + ?Sized +{ + let indices = index::sample(rng, slice.len(), amount).into_iter(); + + let mut out = Vec::with_capacity(amount); + out.extend(indices.map(|i| &slice[i])); + out +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(feature = "alloc")] use {Rng, SeedableRng}; + #[cfg(feature = "alloc")] use rngs::SmallRng; + #[cfg(all(feature="alloc", not(feature="std")))] + use alloc::vec::Vec; + + #[test] + fn test_slice_choose() { + let mut r = ::test::rng(107); + let chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n']; + let mut chosen = [0i32; 14]; + for _ in 0..1000 { + let picked = *chars.choose(&mut r).unwrap(); + chosen[(picked as usize) - ('a' as usize)] += 1; + } + for count in chosen.iter() { + let err = *count - (1000 / (chars.len() as i32)); + assert!(-20 <= err && err <= 20); + } + + chosen.iter_mut().for_each(|x| *x = 0); + for _ in 0..1000 { + *chosen.choose_mut(&mut r).unwrap() += 1; + } + for count in chosen.iter() { + let err = *count - (1000 / (chosen.len() as i32)); + assert!(-20 <= err && err <= 20); + } + + let mut v: [isize; 0] = []; + assert_eq!(v.choose(&mut r), None); + assert_eq!(v.choose_mut(&mut r), None); + } + + #[derive(Clone)] + struct UnhintedIterator<I: Iterator + Clone> { + iter: I, + } + impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } + } + + #[derive(Clone)] + struct ChunkHintedIterator<I: ExactSizeIterator + Iterator + Clone> { + iter: I, + chunk_remaining: usize, + chunk_size: usize, + hint_total_size: bool, + } + impl<I: ExactSizeIterator + Iterator + Clone> Iterator for ChunkHintedIterator<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + if self.chunk_remaining == 0 { + self.chunk_remaining = ::core::cmp::min(self.chunk_size, + self.iter.len()); + } + self.chunk_remaining = self.chunk_remaining.saturating_sub(1); + + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + (self.chunk_remaining, + if self.hint_total_size { Some(self.iter.len()) } else { None }) + } + } + + #[derive(Clone)] + struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> { + iter: I, + window_size: usize, + hint_total_size: bool, + } + impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> { + type Item = I::Item; + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + (::core::cmp::min(self.iter.len(), self.window_size), + if self.hint_total_size { Some(self.iter.len()) } else { None }) + } + } + + #[test] + fn test_iterator_choose() { + let r = &mut ::test::rng(109); + fn test_iter<R: Rng + ?Sized, Iter: Iterator<Item=usize> + Clone>(r: &mut R, iter: Iter) { + let mut chosen = [0i32; 9]; + for _ in 0..1000 { + let picked = iter.clone().choose(r).unwrap(); + chosen[picked] += 1; + } + for count in chosen.iter() { + // Samples should follow Binomial(1000, 1/9) + // Octave: binopdf(x, 1000, 1/9) gives the prob of *count == x + // Note: have seen 153, which is unlikely but not impossible. + assert!(72 < *count && *count < 154, "count not close to 1000/9: {}", count); + } + } + + test_iter(r, 0..9); + test_iter(r, [0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned()); + #[cfg(feature = "alloc")] + test_iter(r, (0..9).collect::<Vec<_>>().into_iter()); + test_iter(r, UnhintedIterator { iter: 0..9 }); + test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: false }); + test_iter(r, ChunkHintedIterator { iter: 0..9, chunk_size: 4, chunk_remaining: 4, hint_total_size: true }); + test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: false }); + test_iter(r, WindowHintedIterator { iter: 0..9, window_size: 2, hint_total_size: true }); + + assert_eq!((0..0).choose(r), None); + assert_eq!(UnhintedIterator{ iter: 0..0 }.choose(r), None); + } + + #[test] + fn test_shuffle() { + let mut r = ::test::rng(108); + let empty: &mut [isize] = &mut []; + empty.shuffle(&mut r); + let mut one = [1]; + one.shuffle(&mut r); + let b: &[_] = &[1]; + assert_eq!(one, b); + + let mut two = [1, 2]; + two.shuffle(&mut r); + assert!(two == [1, 2] || two == [2, 1]); + + fn move_last(slice: &mut [usize], pos: usize) { + // use slice[pos..].rotate_left(1); once we can use that + let last_val = slice[pos]; + for i in pos..slice.len() - 1 { + slice[i] = slice[i + 1]; + } + *slice.last_mut().unwrap() = last_val; + } + let mut counts = [0i32; 24]; + for _ in 0..10000 { + let mut arr: [usize; 4] = [0, 1, 2, 3]; + arr.shuffle(&mut r); + let mut permutation = 0usize; + let mut pos_value = counts.len(); + for i in 0..4 { + pos_value /= 4 - i; + let pos = arr.iter().position(|&x| x == i).unwrap(); + assert!(pos < (4 - i)); + permutation += pos * pos_value; + move_last(&mut arr, pos); + assert_eq!(arr[3], i); + } + for i in 0..4 { + assert_eq!(arr[i], i); + } + counts[permutation] += 1; + } + for count in counts.iter() { + let err = *count - 10000i32 / 24; + assert!(-50 <= err && err <= 50); + } + } + + #[test] + fn test_partial_shuffle() { + let mut r = ::test::rng(118); + + let mut empty: [u32; 0] = []; + let res = empty.partial_shuffle(&mut r, 10); + assert_eq!((res.0.len(), res.1.len()), (0, 0)); + + let mut v = [1, 2, 3, 4, 5]; + let res = v.partial_shuffle(&mut r, 2); + assert_eq!((res.0.len(), res.1.len()), (2, 3)); + assert!(res.0[0] != res.0[1]); + // First elements are only modified if selected, so at least one isn't modified: + assert!(res.1[0] == 1 || res.1[1] == 2 || res.1[2] == 3); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_sample_iter() { + let min_val = 1; + let max_val = 100; + + let mut r = ::test::rng(401); + let vals = (min_val..max_val).collect::<Vec<i32>>(); + let small_sample = vals.iter().choose_multiple(&mut r, 5); + let large_sample = vals.iter().choose_multiple(&mut r, vals.len() + 5); + + assert_eq!(small_sample.len(), 5); + assert_eq!(large_sample.len(), vals.len()); + // no randomization happens when amount >= len + assert_eq!(large_sample, vals.iter().collect::<Vec<_>>()); + + assert!(small_sample.iter().all(|e| { + **e >= min_val && **e <= max_val + })); + } + + #[test] + #[cfg(feature = "alloc")] + #[allow(deprecated)] + fn test_sample_slice_boundaries() { + let empty: &[u8] = &[]; + + let mut r = ::test::rng(402); + + // sample 0 items + assert_eq!(&sample_slice(&mut r, empty, 0)[..], [0u8; 0]); + assert_eq!(&sample_slice(&mut r, &[42, 2, 42], 0)[..], [0u8; 0]); + + // sample 1 item + assert_eq!(&sample_slice(&mut r, &[42], 1)[..], [42]); + let v = sample_slice(&mut r, &[1, 42], 1)[0]; + assert!(v == 1 || v == 42); + + // sample "all" the items + let v = sample_slice(&mut r, &[42, 133], 2); + assert!(&v[..] == [42, 133] || v[..] == [133, 42]); + + // Make sure lucky 777's aren't lucky + let slice = &[42, 777]; + let mut num_42 = 0; + let total = 1000; + for _ in 0..total { + let v = sample_slice(&mut r, slice, 1); + assert_eq!(v.len(), 1); + let v = v[0]; + assert!(v == 42 || v == 777); + if v == 42 { + num_42 += 1; + } + } + let ratio_42 = num_42 as f64 / 1000 as f64; + assert!(0.4 <= ratio_42 || ratio_42 <= 0.6, "{}", ratio_42); + } + + #[test] + #[cfg(feature = "alloc")] + #[allow(deprecated)] + fn test_sample_slice() { + let seeded_rng = SmallRng::from_seed; + + let mut r = ::test::rng(403); + + for n in 1..20 { + let length = 5*n - 4; // 1, 6, ... + let amount = r.gen_range(0, length); + let mut seed = [0u8; 16]; + r.fill(&mut seed); + + // assert the basics work + let regular = index::sample(&mut seeded_rng(seed), length, amount); + assert_eq!(regular.len(), amount); + assert!(regular.iter().all(|e| e < length)); + + // also test that sampling the slice works + let vec: Vec<u32> = (0..(length as u32)).collect(); + let result = sample_slice(&mut seeded_rng(seed), &vec, amount); + assert_eq!(result, regular.iter().map(|i| i as u32).collect::<Vec<_>>()); + + let result = sample_slice_ref(&mut seeded_rng(seed), &vec, amount); + assert!(result.iter().zip(regular.iter()).all(|(i,j)| **i == j as u32)); + } + } + + #[test] + #[cfg(feature = "alloc")] + fn test_weighted() { + let mut r = ::test::rng(406); + const N_REPS: u32 = 3000; + let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]; + let total_weight = weights.iter().sum::<u32>() as f32; + + let verify = |result: [i32; 14]| { + for (i, count) in result.iter().enumerate() { + let exp = (weights[i] * N_REPS) as f32 / total_weight; + let mut err = (*count as f32 - exp).abs(); + if err != 0.0 { + err /= exp; + } + assert!(err <= 0.25); + } + }; + + // choose_weighted + fn get_weight<T>(item: &(u32, T)) -> u32 { + item.0 + } + let mut chosen = [0i32; 14]; + let mut items = [(0u32, 0usize); 14]; // (weight, index) + for (i, item) in items.iter_mut().enumerate() { + *item = (weights[i], i); + } + for _ in 0..N_REPS { + let item = items.choose_weighted(&mut r, get_weight).unwrap(); + chosen[item.1] += 1; + } + verify(chosen); + + // choose_weighted_mut + let mut items = [(0u32, 0i32); 14]; // (weight, count) + for (i, item) in items.iter_mut().enumerate() { + *item = (weights[i], 0); + } + for _ in 0..N_REPS { + items.choose_weighted_mut(&mut r, get_weight).unwrap().1 += 1; + } + for (ch, item) in chosen.iter_mut().zip(items.iter()) { + *ch = item.1; + } + verify(chosen); + + // Check error cases + let empty_slice = &mut [10][0..0]; + assert_eq!(empty_slice.choose_weighted(&mut r, |_| 1), Err(WeightedError::NoItem)); + assert_eq!(empty_slice.choose_weighted_mut(&mut r, |_| 1), Err(WeightedError::NoItem)); + assert_eq!(['x'].choose_weighted_mut(&mut r, |_| 0), Err(WeightedError::AllWeightsZero)); + assert_eq!([0, -1].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight)); + assert_eq!([-1, 0].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::NegativeWeight)); + } +} diff --git a/rand/tests/uniformity.rs b/rand/tests/uniformity.rs new file mode 100644 index 000000000..b8f74a62e --- /dev/null +++ b/rand/tests/uniformity.rs @@ -0,0 +1,67 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(feature = "std")] + +#[macro_use] +extern crate average; +extern crate rand; + +use std as core; +use rand::FromEntropy; +use rand::distributions::Distribution; +use average::Histogram; + +const N_BINS: usize = 100; +const N_SAMPLES: u32 = 1_000_000; +const TOL: f64 = 1e-3; +define_histogram!(hist, 100); +use hist::Histogram as Histogram100; + +#[test] +fn unit_sphere() { + const N_DIM: usize = 3; + let h = Histogram100::with_const_width(-1., 1.); + let mut histograms = [h.clone(), h.clone(), h]; + let dist = rand::distributions::UnitSphereSurface::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + for _ in 0..N_SAMPLES { + let v = dist.sample(&mut rng); + for i in 0..N_DIM { + histograms[i].add(v[i]).map_err( + |e| { println!("v: {}", v[i]); e } + ).unwrap(); + } + } + for h in &histograms { + let sum: u64 = h.bins().iter().sum(); + println!("{:?}", h); + for &b in h.bins() { + let p = (b as f64) / (sum as f64); + assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); + } + } +} + +#[test] +fn unit_circle() { + use ::std::f64::consts::PI; + let mut h = Histogram100::with_const_width(-PI, PI); + let dist = rand::distributions::UnitCircle::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + for _ in 0..N_SAMPLES { + let v = dist.sample(&mut rng); + h.add(v[0].atan2(v[1])).unwrap(); + } + let sum: u64 = h.bins().iter().sum(); + println!("{:?}", h); + for &b in h.bins() { + let p = (b as f64) / (sum as f64); + assert!((p - 1.0 / (N_BINS as f64)).abs() < TOL, "{}", p); + } +} diff --git a/rand_chacha/.cargo-checksum.json b/rand_chacha/.cargo-checksum.json new file mode 100644 index 000000000..acdaeb679 --- /dev/null +++ b/rand_chacha/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"} \ No newline at end of file diff --git a/rand_chacha/CHANGELOG.md b/rand_chacha/CHANGELOG.md new file mode 100644 index 000000000..a1979f601 --- /dev/null +++ b/rand_chacha/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2019-01-04 +- Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation) +- Update readme and doc links + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/rand_chacha/COPYRIGHT b/rand_chacha/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_chacha/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_chacha/Cargo.toml b/rand_chacha/Cargo.toml new file mode 100644 index 000000000..e6d552302 --- /dev/null +++ b/rand_chacha/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_chacha" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +build = "build.rs" +description = "ChaCha random number generator\n" +homepage = "https://crates.io/crates/rand_chacha" +documentation = "https://rust-random.github.io/rand/rand_chacha" +readme = "README.md" +keywords = ["random", "rng", "chacha"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false +[build-dependencies.autocfg] +version = "0.1" +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_chacha/LICENSE-APACHE b/rand_chacha/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_chacha/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_chacha/LICENSE-MIT b/rand_chacha/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_chacha/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_chacha/README.md b/rand_chacha/README.md new file mode 100644 index 000000000..5a1dbac8a --- /dev/null +++ b/rand_chacha/README.md @@ -0,0 +1,45 @@ +# rand_chacha + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_chacha.svg)](https://crates.io/crates/rand_chacha) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_chacha) +[![API](https://docs.rs/rand_chacha/badge.svg)](https://docs.rs/rand_chacha) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +A cryptographically secure random number generator that uses the ChaCha +algorithm. + +ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use +as an RNG. It is an improved variant of the Salsa20 cipher family, which was +selected as one of the "stream ciphers suitable for widespread adoption" by +eSTREAM[^2]. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_chacha) +- [API documentation (docs.rs)](https://docs.rs/rand_chacha) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( + https://cr.yp.to/chacha.html) + +[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( + http://www.ecrypt.eu.org/stream/) + + +## Crate Features + +`rand_chacha` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + + +# License + +`rand_chacha` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_chacha/build.rs b/rand_chacha/build.rs new file mode 100644 index 000000000..06e12a47b --- /dev/null +++ b/rand_chacha/build.rs @@ -0,0 +1,7 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let ac = autocfg::new(); + ac.emit_rustc_version(1, 26); +} diff --git a/rand_chacha/src/chacha.rs b/rand_chacha/src/chacha.rs new file mode 100644 index 000000000..86f191e49 --- /dev/null +++ b/rand_chacha/src/chacha.rs @@ -0,0 +1,449 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2014 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 8 words for the 256-bit key +const STATE_WORDS: usize = 16; + +/// A cryptographically secure random number generator that uses the ChaCha +/// algorithm. +/// +/// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use +/// as an RNG. It is an improved variant of the Salsa20 cipher family, which was +/// selected as one of the "stream ciphers suitable for widespread adoption" by +/// eSTREAM[^2]. +/// +/// ChaCha uses add-rotate-xor (ARX) operations as its basis. These are safe +/// against timing attacks, although that is mostly a concern for ciphers and +/// not for RNGs. Also it is very suitable for SIMD implementation. +/// Here we do not provide a SIMD implementation yet, except for what is +/// provided by auto-vectorisation. +/// +/// With the ChaCha algorithm it is possible to choose the number of rounds the +/// core algorithm should run. The number of rounds is a tradeoff between +/// performance and security, where 8 rounds is the minimum potentially +/// secure configuration, and 20 rounds is widely used as a conservative choice. +/// We use 20 rounds in this implementation, but hope to allow type-level +/// configuration in the future. +/// +/// We use a 64-bit counter and 64-bit stream identifier as in Bernstein's +/// implementation[^1] except that we use a stream identifier in place of a +/// nonce. A 64-bit counter over 64-byte (16 word) blocks allows 1 ZiB of output +/// before cycling, and the stream identifier allows 2<sup>64</sup> unique +/// streams of output per seed. Both counter and stream are initialized to zero +/// but may be set via [`set_word_pos`] and [`set_stream`]. +/// +/// The word layout is: +/// +/// ```text +/// constant constant constant constant +/// seed seed seed seed +/// seed seed seed seed +/// counter counter stream_id stream_id +/// ``` +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*]( +/// https://cr.yp.to/chacha.html) +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [`set_word_pos`]: #method.set_word_pos +/// [`set_stream`]: #method.set_stream +/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +pub struct ChaChaRng(BlockRng<ChaChaCore>); + +impl RngCore for ChaChaRng { + #[inline] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for ChaChaRng { + type Seed = <ChaChaCore as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + ChaChaRng(BlockRng::<ChaChaCore>::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + BlockRng::<ChaChaCore>::from_rng(rng).map(ChaChaRng) + } +} + +impl CryptoRng for ChaChaRng {} + +impl ChaChaRng { + /// Get the offset from the start of the stream, in 32-bit words. + /// + /// Since the generated blocks are 16 words (2<sup>4</sup>) long and the + /// counter is 64-bits, the offset is a 68-bit number. Sub-word offsets are + /// not supported, hence the result can simply be multiplied by 4 to get a + /// byte-offset. + /// + /// Note: this function is currently only available with Rust 1.26 or later. + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn get_word_pos(&self) -> u128 { + let mut c = (self.0.core.state[13] as u64) << 32 + | (self.0.core.state[12] as u64); + let mut index = self.0.index(); + // c is the end of the last block generated, unless index is at end + if index >= STATE_WORDS { + index = 0; + } else { + c = c.wrapping_sub(1); + } + ((c as u128) << 4) | (index as u128) + } + + /// Set the offset from the start of the stream, in 32-bit words. + /// + /// As with `get_word_pos`, we use a 68-bit number. Since the generator + /// simply cycles at the end of its period (1 ZiB), we ignore the upper + /// 60 bits. + /// + /// Note: this function is currently only available with Rust 1.26 or later. + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + pub fn set_word_pos(&mut self, word_offset: u128) { + let index = (word_offset as usize) & 0xF; + let counter = (word_offset >> 4) as u64; + self.0.core.state[12] = counter as u32; + self.0.core.state[13] = (counter >> 32) as u32; + if index != 0 { + self.0.generate_and_set(index); // also increments counter + } else { + self.0.reset(); + } + } + + /// Set the stream number. + /// + /// This is initialized to zero; 2<sup>64</sup> unique streams of output + /// are available per seed/key. + /// + /// Note that in order to reproduce ChaCha output with a specific 64-bit + /// nonce, one can convert that nonce to a `u64` in little-endian fashion + /// and pass to this function. In theory a 96-bit nonce can be used by + /// passing the last 64-bits to this function and using the first 32-bits as + /// the most significant half of the 64-bit counter (which may be set + /// indirectly via `set_word_pos`), but this is not directly supported. + pub fn set_stream(&mut self, stream: u64) { + let index = self.0.index(); + self.0.core.state[14] = stream as u32; + self.0.core.state[15] = (stream >> 32) as u32; + if index < STATE_WORDS { + // we need to regenerate a partial result buffer + { + // reverse of counter adjustment in generate() + if self.0.core.state[12] == 0 { + self.0.core.state[13] = self.0.core.state[13].wrapping_sub(1); + } + self.0.core.state[12] = self.0.core.state[12].wrapping_sub(1); + } + self.0.generate_and_set(index); + } + } +} + +/// The core of `ChaChaRng`, used with `BlockRng`. +#[derive(Clone)] +pub struct ChaChaCore { + state: [u32; STATE_WORDS], +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for ChaChaCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ChaChaCore {{}}") + } +} + +macro_rules! quarter_round{ + ($a: expr, $b: expr, $c: expr, $d: expr) => {{ + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left(16); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left(12); + $a = $a.wrapping_add($b); $d ^= $a; $d = $d.rotate_left( 8); + $c = $c.wrapping_add($d); $b ^= $c; $b = $b.rotate_left( 7); + }} +} + +macro_rules! double_round{ + ($x: expr) => {{ + // Column round + quarter_round!($x[ 0], $x[ 4], $x[ 8], $x[12]); + quarter_round!($x[ 1], $x[ 5], $x[ 9], $x[13]); + quarter_round!($x[ 2], $x[ 6], $x[10], $x[14]); + quarter_round!($x[ 3], $x[ 7], $x[11], $x[15]); + // Diagonal round + quarter_round!($x[ 0], $x[ 5], $x[10], $x[15]); + quarter_round!($x[ 1], $x[ 6], $x[11], $x[12]); + quarter_round!($x[ 2], $x[ 7], $x[ 8], $x[13]); + quarter_round!($x[ 3], $x[ 4], $x[ 9], $x[14]); + }} +} + +impl BlockRngCore for ChaChaCore { + type Item = u32; + type Results = [u32; STATE_WORDS]; + + fn generate(&mut self, results: &mut Self::Results) { + // For some reason extracting this part into a separate function + // improves performance by 50%. + fn core(results: &mut [u32; STATE_WORDS], + state: &[u32; STATE_WORDS]) + { + let mut tmp = *state; + let rounds = 20; + for _ in 0..rounds / 2 { + double_round!(tmp); + } + for i in 0..STATE_WORDS { + results[i] = tmp[i].wrapping_add(state[i]); + } + } + + core(results, &self.state); + + // update 64-bit counter + self.state[12] = self.state[12].wrapping_add(1); + if self.state[12] != 0 { return; }; + self.state[13] = self.state[13].wrapping_add(1); + } +} + +impl SeedableRng for ChaChaCore { + type Seed = [u8; SEED_WORDS*4]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_le = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_le); + Self { + state: [0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, // constants + seed_le[0], seed_le[1], seed_le[2], seed_le[3], // seed + seed_le[4], seed_le[5], seed_le[6], seed_le[7], // seed + 0, 0, 0, 0], // counter + } + } +} + +impl CryptoRng for ChaChaCore {} + +impl From<ChaChaCore> for ChaChaRng { + fn from(core: ChaChaCore) -> Self { + ChaChaRng(BlockRng::new(core)) + } +} + +#[cfg(test)] +mod test { + use ::rand_core::{RngCore, SeedableRng}; + use super::ChaChaRng; + + #[test] + fn test_chacha_construction() { + let seed = [0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, + 2,0,0,0,0,0,0,0, + 3,0,0,0,0,0,0,0]; + let mut rng1 = ChaChaRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 137206642); + + let mut rng2 = ChaChaRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 1325750369); + } + + #[test] + fn test_chacha_true_values_a() { + // Test vectors 1 and 2 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, + 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b, + 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, + 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2]; + assert_eq!(results, expected); + + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, + 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32, + 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, + 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_values_b() { + // Test vector 3 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1]; + let mut rng = ChaChaRng::from_seed(seed); + + // Skip block 0 + for _ in 0..16 { rng.next_u32(); } + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, + 0xe8252083, 0x60818b01, 0xf38422b8, 0x5aaa49c9, + 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, + 0x4436274e, 0x2561b3c8, 0xebdd4aa6, 0xa0136c00]; + assert_eq!(results, expected); + } + + #[test] + #[cfg(all(rustc_1_26, not(target_os = "emscripten")))] + fn test_chacha_true_values_c() { + // Test vector 4 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + let seed = [0, 0xff, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]; + let expected = [0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, + 0xa78dea8f, 0x5e269039, 0xa1bebbc1, 0xcaf09aae, + 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, + 0x546ca624, 0x1bec45d5, 0x87f47473, 0x96f0992e]; + let expected_end = 3 * 16; + let mut results = [0u32; 16]; + + // Test block 2 by skipping block 0 and 1 + let mut rng1 = ChaChaRng::from_seed(seed); + for _ in 0..32 { rng1.next_u32(); } + for i in results.iter_mut() { *i = rng1.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng1.get_word_pos(), expected_end); + + // Test block 2 by using `set_word_pos` + let mut rng2 = ChaChaRng::from_seed(seed); + rng2.set_word_pos(2 * 16); + for i in results.iter_mut() { *i = rng2.next_u32(); } + assert_eq!(results, expected); + assert_eq!(rng2.get_word_pos(), expected_end); + + // Test skipping behaviour with other types + let mut buf = [0u8; 32]; + rng2.fill_bytes(&mut buf[..]); + assert_eq!(rng2.get_word_pos(), expected_end + 8); + rng2.fill_bytes(&mut buf[0..25]); + assert_eq!(rng2.get_word_pos(), expected_end + 15); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 17); + rng2.next_u32(); + rng2.next_u64(); + assert_eq!(rng2.get_word_pos(), expected_end + 20); + rng2.fill_bytes(&mut buf[0..1]); + assert_eq!(rng2.get_word_pos(), expected_end + 21); + } + + #[test] + fn test_chacha_multiple_blocks() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + + // Store the 17*i-th 32-bit word, + // i.e., the i-th word of the i-th 16-word block + let mut results = [0u32; 16]; + for i in results.iter_mut() { + *i = rng.next_u32(); + for _ in 0..16 { + rng.next_u32(); + } + } + let expected = [0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, + 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384, + 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, + 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_true_bytes() { + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [118, 184, 224, 173, 160, 241, 61, 144, + 64, 93, 106, 229, 83, 134, 189, 40, + 189, 210, 25, 184, 160, 141, 237, 26, + 168, 54, 239, 204, 139, 119, 13, 199]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_nonce() { + // Test vector 5 from + // https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + // Although we do not support setting a nonce, we try it here anyway so + // we can use this test vector. + let seed = [0u8; 32]; + let mut rng = ChaChaRng::from_seed(seed); + // 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2 + rng.set_stream(2u64 << (24 + 32)); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, + 0x88228b1a, 0x96a4dfb3, 0x5b76ab72, 0xc727ee54, + 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, + 0x99c28f5f, 0x628314e8, 0x398a19fa, 0x6ded1b53]; + assert_eq!(results, expected); + } + + #[test] + fn test_chacha_clone_streams() { + let seed = [0,0,0,0, 1,0,0,0, 2,0,0,0, 3,0,0,0, 4,0,0,0, 5,0,0,0, 6,0,0,0, 7,0,0,0]; + let mut rng = ChaChaRng::from_seed(seed); + let mut clone = rng.clone(); + for _ in 0..16 { + assert_eq!(rng.next_u64(), clone.next_u64()); + } + + rng.set_stream(51); + for _ in 0..7 { + assert!(rng.next_u32() != clone.next_u32()); + } + clone.set_stream(51); // switch part way through block + for _ in 7..16 { + assert_eq!(rng.next_u32(), clone.next_u32()); + } + } +} diff --git a/rand_chacha/src/lib.rs b/rand_chacha/src/lib.rs new file mode 100644 index 000000000..8cff03ac0 --- /dev/null +++ b/rand_chacha/src/lib.rs @@ -0,0 +1,25 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ChaCha random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core; + +mod chacha; + +pub use chacha::{ChaChaRng, ChaChaCore}; diff --git a/rand_core-0.3.1/.cargo-checksum.json b/rand_core-0.3.1/.cargo-checksum.json new file mode 100644 index 000000000..2197bf569 --- /dev/null +++ b/rand_core-0.3.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"} \ No newline at end of file diff --git a/rand_core-0.3.1/CHANGELOG.md b/rand_core-0.3.1/CHANGELOG.md new file mode 100644 index 000000000..e3755364d --- /dev/null +++ b/rand_core-0.3.1/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.3.1] - 2019-01-25 +- Compatibility shim around version 0.4 + +## [0.3.0] - 2018-09-24 +- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537) + +## [0.2.1] - 2018-06-08 +- References to a `CryptoRng` now also implement `CryptoRng`. (#470) + +## [0.2.0] - 2018-05-21 +- Enable the `std` feature by default. (#409) +- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public +- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) +- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) +- Implement `std::io::Read` for RngCore. (#434) + +## [0.1.0] - 2018-04-17 +(Split out of the Rand crate, changes here are relative to rand 0.4.2) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +## [0.0.1] - 2017-09-14 (yanked) +Experimental version as part of the rand crate refactor. diff --git a/rand_core-0.3.1/COPYRIGHT b/rand_core-0.3.1/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_core-0.3.1/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_core-0.3.1/Cargo.toml b/rand_core-0.3.1/Cargo.toml new file mode 100644 index 000000000..439b7d174 --- /dev/null +++ b/rand_core-0.3.1/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_core" +version = "0.3.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Core random number generator traits and tools for implementation.\n" +homepage = "https://crates.io/crates/rand_core" +documentation = "https://rust-random.github.io/rand/rand_core" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.4" + +[features] +alloc = ["rand_core/alloc"] +default = ["std"] +serde1 = ["rand_core/serde1"] +std = ["rand_core/std"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_core-0.3.1/LICENSE-APACHE b/rand_core-0.3.1/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_core-0.3.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_core-0.3.1/LICENSE-MIT b/rand_core-0.3.1/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_core-0.3.1/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_core-0.3.1/README.md b/rand_core-0.3.1/README.md new file mode 100644 index 000000000..dee650482 --- /dev/null +++ b/rand_core-0.3.1/README.md @@ -0,0 +1,65 @@ +# rand_core + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) +[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Core traits and error types of the [rand] library, plus tools for implementing +RNGs. + +This crate is intended for use when implementing the core trait, `RngCore`; it +defines the core traits to be implemented as well as several small functions to +aid in their implementation and types required for error handling. + +The main [rand] crate re-exports most items defined in this crate, along with +tools to convert the integer samples generated by `RngCore` to many different +applications (including sampling from restricted ranges, conversion to floating +point, list permutations and secure initialisation of RNGs). Most users should +prefer to use the main [rand] crate. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_core) +- [API documentation (docs.rs)](https://docs.rs/rand_core) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Functionality + +The `rand_core` crate provides: + +- base random number generator traits +- error-reporting types +- functionality to aid implementation of RNGs + +The traits and error types are also available via `rand`. + +## Crate Features + +`rand_core` supports `no_std` and `alloc`-only configurations, as well as full +`std` functionality. The differences between `no_std` and full `std` are small, +comprising `RngCore` support for `Box<R>` types where `R: RngCore`, as well as +extensions to the `Error` type's functionality. + +Due to [rust-lang/cargo#1596](https://github.com/rust-lang/cargo/issues/1596), +`rand_core` is built without `std` support by default. Since features are +unioned across the whole dependency tree, any crate using `rand` with its +default features will also enable `std` support in `rand_core`. + +The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG +implementations that use the `BlockRng` or `BlockRng64` wrappers. + + +# License + +`rand_core` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_core-0.3.1/src/block.rs b/rand_core-0.3.1/src/block.rs new file mode 100644 index 000000000..3045b9482 --- /dev/null +++ b/rand_core-0.3.1/src/block.rs @@ -0,0 +1,499 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `BlockRngCore` trait and implementation helpers +//! +//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! which generate a block of data in a cache instead of returning generated +//! values directly. +//! +//! Usage of this trait is optional, but provides two advantages: +//! implementations only need to concern themselves with generation of the +//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where +//! the optimal implementations are not trivial), and this allows +//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic +//! reseeding with very low overhead. +//! +//! # Example +//! +//! ```norun +//! use rand_core::block::{BlockRngCore, BlockRng}; +//! +//! struct MyRngCore; +//! +//! impl BlockRngCore for MyRngCore { +//! type Results = [u32; 16]; +//! +//! fn generate(&mut self, results: &mut Self::Results) { +//! unimplemented!() +//! } +//! } +//! +//! impl SeedableRng for MyRngCore { +//! type Seed = unimplemented!(); +//! fn from_seed(seed: Self::Seed) -> Self { +//! unimplemented!() +//! } +//! } +//! +//! // optionally, also implement CryptoRng for MyRngCore +//! +//! // Final RNG. +//! type MyRng = BlockRng<u32, MyRngCore>; +//! ``` +//! +//! [`BlockRngCore`]: crate::block::BlockRngCore +//! [`fill_bytes`]: RngCore::fill_bytes + +use core::convert::AsRef; +use core::fmt; +use {RngCore, CryptoRng, SeedableRng, Error}; +use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; + +/// A trait for RNGs which do not generate random numbers individually, but in +/// blocks (typically `[u32; N]`). This technique is commonly used by +/// cryptographic RNGs to improve performance. +/// +/// See the [module][crate::block] documentation for details. +pub trait BlockRngCore { + /// Results element type, e.g. `u32`. + type Item; + + /// Results type. This is the 'block' an RNG implementing `BlockRngCore` + /// generates, which will usually be an array like `[u32; 16]`. + type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + + /// Generate a new block of results. + fn generate(&mut self, results: &mut Self::Results); +} + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// The `core` field may be accessed directly but the results buffer may not. +/// PRNG implementations can simply use a type alias +/// (`pub type MyRng = BlockRng<MyRngCore>;`) but might prefer to use a +/// wrapper type (`pub struct MyRng(BlockRng<MyRngCore>);`); the latter must +/// re-implement `RngCore` but hides the implementation details and allows +/// extra functionality to be defined on the RNG +/// (e.g. `impl MyRng { fn set_stream(...){...} }`). +/// +/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods +/// reading values from the results buffer, as well as +/// calling [`BlockRngCore::generate`] directly on the output array when +/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods +/// also handle the bookkeeping of when to generate a new batch of values. +/// +/// No whole generated `u32` values are thown away and all values are consumed +/// in-order. [`next_u32`] simply takes the next available `u32` value. +/// [`next_u64`] is implemented by combining two `u32` values, least +/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole +/// number of `u32` values, converting each `u32` to a byte slice in +/// little-endian order. If the requested byte length is not a multiple of 4, +/// some bytes will be discarded. +/// +/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is +/// no direct support for other buffer types. +/// +/// For easy initialization `BlockRng` also implements [`SeedableRng`]. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng<R: BlockRngCore + ?Sized> { + results: R::Results, + index: usize, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() + } +} + +impl<R: BlockRngCore> BlockRng<R> { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng<R>{ + let results_empty = R::Results::default(); + BlockRng { + core, + index: results_empty.as_ref().len(), + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + } +} + +impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R> +where <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + let read_u64 = |results: &[u32], index| { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } + } else { + let x = u64::from(results[index]); + let y = u64::from(results[index + 1]); + (y << 32) | x + } + }; + + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + read_u64(self.results.as_ref(), index) + } else if index >= len { + self.generate_and_set(2); + read_u64(self.results.as_ref(), 0) + } else { + let x = u64::from(self.results.as_ref()[len-1]); + self.generate_and_set(1); + let y = u64::from(self.results.as_ref()[0]); + (y << 32) | x + } + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 4); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u32: &mut R::Results = unsafe { + &mut *(dest[filled..].as_mut_ptr() as + *mut <R as BlockRngCore>::Results) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u32, _) = + fill_via_u32_chunks(self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + Ok(Self::new(R::from_rng(rng)?)) + } +} + + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// This is similar to [`BlockRng`], but specialized for algorithms that operate +/// on `u64` values. +/// +/// No whole generated `u64` values are thrown away and all values are consumed +/// in-order. [`next_u64`] simply takes the next available `u64` value. +/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving +/// the other half in the buffer. If the next function called is [`next_u32`] +/// then the other half is then consumed, however both [`next_u64`] and +/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. +/// +/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` +/// values. If the requested length is not a multiple of 8, some bytes will be +/// discarded. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng64<R: BlockRngCore + ?Sized> { + results: R::Results, + index: usize, + half_used: bool, // true if only half of the previous result is used + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng64") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() + } +} + +impl<R: BlockRngCore> BlockRng64<R> { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng64<R>{ + let results_empty = R::Results::default(); + BlockRng64 { + core, + index: results_empty.as_ref().len(), + half_used: false, + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + self.half_used = false; + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + self.half_used = false; + } +} + +impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R> +where <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + let mut index = self.index * 2 - self.half_used as usize; + if index >= self.results.as_ref().len() * 2 { + self.core.generate(&mut self.results); + self.index = 0; + // `self.half_used` is by definition `false` + self.half_used = false; + index = 0; + } + + self.half_used = !self.half_used; + self.index += self.half_used as usize; + + // Index as if this is a u32 slice. + unsafe { + let results = + &*(self.results.as_ref() as *const [u64] as *const [u32]); + if cfg!(target_endian = "little") { + *results.get_unchecked(index) + } else { + *results.get_unchecked(index ^ 1) + } + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + self.half_used = false; + value + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + self.half_used = false; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u64; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 8); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u64: &mut R::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u64); + filled += self.results.as_ref().len() * 8; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u64, _) = + fill_via_u64_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u64; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + self.half_used = false; + while read_len < dest.len() { + if self.index as usize >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], + &mut dest[read_len..]); + + self.index += consumed_u64; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + Ok(Self::new(R::from_rng(rng)?)) + } +} + +impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {} diff --git a/rand_core-0.3.1/src/error.rs b/rand_core-0.3.1/src/error.rs new file mode 100644 index 000000000..5a8459ea8 --- /dev/null +++ b/rand_core-0.3.1/src/error.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error types + +use core::fmt; + +#[cfg(feature="std")] +use std::error::Error as stdError; +#[cfg(feature="std")] +use std::io; + +/// Error kind which can be matched over. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ErrorKind { + /// Feature is not available; not recoverable. + /// + /// This is the most permanent failure type and implies the error cannot be + /// resolved simply by retrying (e.g. the feature may not exist in this + /// build of the application or on the current platform). + Unavailable, + /// General failure; there may be a chance of recovery on retry. + /// + /// This is the catch-all kind for errors from known and unknown sources + /// which do not have a more specific kind / handling method. + /// + /// It is suggested to retry a couple of times or retry later when + /// handling; some error sources may be able to resolve themselves, + /// although this is not likely. + Unexpected, + /// A transient failure which likely can be resolved or worked around. + /// + /// This error kind exists for a few specific cases where it is known that + /// the error likely can be resolved internally, but is reported anyway. + Transient, + /// Not ready yet: recommended to try again a little later. + /// + /// This error kind implies the generator needs more time or needs some + /// other part of the application to do something else first before it is + /// ready for use; for example this may be used by external generators + /// which require time for initialization. + NotReady, + #[doc(hidden)] + __Nonexhaustive, +} + +impl ErrorKind { + /// True if this kind of error may resolve itself on retry. + /// + /// See also `should_wait()`. + pub fn should_retry(self) -> bool { + self != ErrorKind::Unavailable + } + + /// True if we should retry but wait before retrying + /// + /// This implies `should_retry()` is true. + pub fn should_wait(self) -> bool { + self == ErrorKind::NotReady + } + + /// A description of this error kind + pub fn description(self) -> &'static str { + match self { + ErrorKind::Unavailable => "permanently unavailable", + ErrorKind::Unexpected => "unexpected failure", + ErrorKind::Transient => "transient failure", + ErrorKind::NotReady => "not ready yet", + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + + +/// Error type of random number generators +/// +/// This is a relatively simple error type, designed for compatibility with and +/// without the Rust `std` library. It embeds a "kind" code, a message (static +/// string only), and an optional chained cause (`std` only). The `kind` and +/// `msg` fields can be accessed directly; cause can be accessed via +/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be +/// done via `Error::new` or `Error::with_cause`. +#[derive(Debug)] +pub struct Error { + /// The error kind + pub kind: ErrorKind, + /// The error message + pub msg: &'static str, + #[cfg(feature="std")] + cause: Option<Box<stdError + Send + Sync>>, +} + +impl Error { + /// Create a new instance, with specified kind and a message. + pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + #[cfg(feature="std")] { + Error { kind, msg, cause: None } + } + #[cfg(not(feature="std"))] { + Error { kind, msg } + } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// Note: `stdError` is an alias for `std::error::Error`. + /// + /// If not targetting `std` (i.e. `no_std`), this function is replaced by + /// another with the same prototype, except that there are no bounds on the + /// type `E` (because both `Box` and `stdError` are unavailable), and the + /// `cause` is ignored. + #[cfg(feature="std")] + pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self + where E: Into<Box<stdError + Send + Sync>> + { + Error { kind, msg, cause: Some(cause.into()) } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// In `no_std` mode the *cause* is ignored. + #[cfg(not(feature="std"))] + pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { + Error { kind, msg } + } + + /// Take the cause, if any. This allows the embedded cause to be extracted. + /// This uses `Option::take`, leaving `self` with no cause. + #[cfg(feature="std")] + pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> { + self.cause.take() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(feature="std")] { + if let Some(ref cause) = self.cause { + return write!(f, "{} ({}); cause: {}", + self.msg, self.kind.description(), cause); + } + } + write!(f, "{} ({})", self.msg, self.kind.description()) + } +} + +#[cfg(feature="std")] +impl stdError for Error { + fn description(&self) -> &str { + self.msg + } + + fn cause(&self) -> Option<&stdError> { + self.cause.as_ref().map(|e| e.as_ref() as &stdError) + } +} + +#[cfg(feature="std")] +impl From<Error> for io::Error { + fn from(error: Error) -> Self { + use std::io::ErrorKind::*; + match error.kind { + ErrorKind::Unavailable => io::Error::new(NotFound, error), + ErrorKind::Unexpected | + ErrorKind::Transient => io::Error::new(Other, error), + ErrorKind::NotReady => io::Error::new(WouldBlock, error), + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/rand_core-0.3.1/src/impls.rs b/rand_core-0.3.1/src/impls.rs new file mode 100644 index 000000000..57bdd070d --- /dev/null +++ b/rand_core-0.3.1/src/impls.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions for implementing `RngCore` functions. +//! +//! For cross-platform reproducibility, these functions all use Little Endian: +//! least-significant part first. For example, `next_u64_via_u32` takes `u32` +//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32` +//! from `next_u64` in little-endian order, one should use `next_u64() as u32`. +//! +//! Byte-swapping (like the std `to_le` functions) is only needed to convert +//! to/from byte sequences, and since its purpose is reproducibility, +//! non-reproducible sources (e.g. `OsRng`) need not bother with it. + +use core::intrinsics::transmute; +use core::ptr::copy_nonoverlapping; +use core::slice; +use core::cmp::min; +use core::mem::size_of; +use RngCore; + + +/// Implement `next_u64` via `next_u32`, little-endian order. +pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 { + // Use LE; we explicitly generate one value before the next. + let x = u64::from(rng.next_u32()); + let y = u64::from(rng.next_u32()); + (y << 32) | x +} + +/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. +/// +/// The fastest way to fill a slice is usually to work as long as possible with +/// integers. That is why this method mostly uses `next_u64`, and only when +/// there are 4 or less bytes remaining at the end of the slice it uses +/// `next_u32` once. +pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) { + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 4 { + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } else if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(rng.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } +} + +macro_rules! impl_uint_from_fill { + ($rng:expr, $ty:ty, $N:expr) => ({ + debug_assert!($N == size_of::<$ty>()); + + let mut int: $ty = 0; + unsafe { + let ptr = &mut int as *mut $ty as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, $N); + $rng.fill_bytes(slice); + } + int + }); +} + +macro_rules! fill_via_chunks { + ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({ + let chunk_size_u8 = min($src.len() * $size, $dst.len()); + let chunk_size = (chunk_size_u8 + $size - 1) / $size; + if cfg!(target_endian="little") { + unsafe { + copy_nonoverlapping( + $src.as_ptr() as *const u8, + $dst.as_mut_ptr(), + chunk_size_u8); + } + } else { + for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + let tmp = n.to_le(); + let src_ptr = &tmp as *const $ty as *const u8; + unsafe { + copy_nonoverlapping(src_ptr, + chunk.as_mut_ptr(), + chunk.len()); + } + } + } + + (chunk_size, chunk_size_u8) + }); +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u32, filled_u8)`. +/// +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u32` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 4` rounded up. +/// +/// # Example +/// (from `IsaacRng`) +/// +/// ```ignore +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// let mut read_len = 0; +/// while read_len < dest.len() { +/// if self.index >= self.rsl.len() { +/// self.isaac(); +/// } +/// +/// let (consumed_u32, filled_u8) = +/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..], +/// &mut dest[read_len..]); +/// +/// self.index += consumed_u32; +/// read_len += filled_u8; +/// } +/// } +/// ``` +pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u32, 4) +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u64, filled_u8)`. +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u64` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 8` rounded up. +/// +/// See `fill_via_u32_chunks` for an example. +pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u64, 8) +} + +/// Implement `next_u32` via `fill_bytes`, little-endian order. +pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 { + impl_uint_from_fill!(rng, u32, 4) +} + +/// Implement `next_u64` via `fill_bytes`, little-endian order. +pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 { + impl_uint_from_fill!(rng, u64, 8) +} + +// TODO: implement tests for the above diff --git a/rand_core-0.3.1/src/le.rs b/rand_core-0.3.1/src/le.rs new file mode 100644 index 000000000..266651f10 --- /dev/null +++ b/rand_core-0.3.1/src/le.rs @@ -0,0 +1,68 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Little-Endian utilities +//! +//! Little-Endian order has been chosen for internal usage; this makes some +//! useful functions available. + +use core::ptr; + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + ptr::copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} + +/// Reads unsigned 32 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); +} + +/// Reads unsigned 64 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); +} + +#[test] +fn test_read() { + let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + let mut buf = [0u32; 4]; + read_u32_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x04030201); + assert_eq!(buf[3], 0x100F0E0D); + + let mut buf = [0u32; 3]; + read_u32_into(&bytes[1..13], &mut buf); // unaligned + assert_eq!(buf[0], 0x05040302); + assert_eq!(buf[2], 0x0D0C0B0A); + + let mut buf = [0u64; 2]; + read_u64_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x0807060504030201); + assert_eq!(buf[1], 0x100F0E0D0C0B0A09); + + let mut buf = [0u64; 1]; + read_u64_into(&bytes[7..15], &mut buf); // unaligned + assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); +} diff --git a/rand_core-0.3.1/src/lib.rs b/rand_core-0.3.1/src/lib.rs new file mode 100644 index 000000000..892314225 --- /dev/null +++ b/rand_core-0.3.1/src/lib.rs @@ -0,0 +1,46 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generation traits +//! +//! This version of `rand_core` is a compatibility shim around version 0.3. +//! +//! This crate is mainly of interest to crates publishing implementations of +//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead +//! which re-exports the main traits and error types. +//! +//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number +//! generators and external random-number sources. +//! +//! [`SeedableRng`] is an extension trait for construction from fixed seeds and +//! other random number generators. +//! +//! [`Error`] is provided for error-handling. It is safe to use in `no_std` +//! environments. +//! +//! The [`impls`] and [`le`] sub-modules include a few small functions to assist +//! implementation of [`RngCore`]. +//! +//! [`rand`]: https://docs.rs/rand + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core as core4; + +pub use core4::{ErrorKind, Error}; +pub use core4::{block, impls, le}; +pub use core4::{RngCore, CryptoRng, SeedableRng}; diff --git a/rand_core/.cargo-checksum.json b/rand_core/.cargo-checksum.json new file mode 100644 index 000000000..80057591f --- /dev/null +++ b/rand_core/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"} \ No newline at end of file diff --git a/rand_core/CHANGELOG.md b/rand_core/CHANGELOG.md new file mode 100644 index 000000000..7f2d7978f --- /dev/null +++ b/rand_core/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.4.0] - 2019-01-24 +- Disable the `std` feature by default (#702) + +## [0.3.0] - 2018-09-24 +- Add `SeedableRng::seed_from_u64` for convenient seeding. (#537) + +## [0.2.1] - 2018-06-08 +- References to a `CryptoRng` now also implement `CryptoRng`. (#470) + +## [0.2.0] - 2018-05-21 +- Enable the `std` feature by default. (#409) +- Remove `BlockRng{64}::inner` and `BlockRng::inner_mut`; instead making `core` public +- Add `BlockRng{64}::index` and `BlockRng{64}::generate_and_set`. (#374, #419) +- Change `BlockRngCore::Results` bound to also require `AsMut<[Self::Item]>`. (#419) +- Implement `std::io::Read` for RngCore. (#434) + +## [0.1.0] - 2018-04-17 +(Split out of the Rand crate, changes here are relative to rand 0.4.2) +- `RngCore` and `SeedableRng` are now part of `rand_core`. (#288) +- Add modules to help implementing RNGs `impl` and `le`. (#209, #228) +- Add `Error` and `ErrorKind`. (#225) +- Add `CryptoRng` marker trait. (#273) +- Add `BlockRngCore` trait. (#281) +- Add `BlockRng` and `BlockRng64` wrappers to help implementations. (#281, #325) +- Revise the `SeedableRng` trait. (#233) +- Remove default implementations for `RngCore::next_u64` and `RngCore::fill_bytes`. (#288) +- Add `RngCore::try_fill_bytes`. (#225) + +## [0.0.1] - 2017-09-14 (yanked) +Experimental version as part of the rand crate refactor. diff --git a/rand_core/COPYRIGHT b/rand_core/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_core/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_core/Cargo.toml b/rand_core/Cargo.toml new file mode 100644 index 000000000..aee2ec0b6 --- /dev/null +++ b/rand_core/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_core" +version = "0.4.0" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Core random number generator traits and tools for implementation.\n" +homepage = "https://crates.io/crates/rand_core" +documentation = "https://rust-random.github.io/rand/rand_core" +readme = "README.md" +keywords = ["random", "rng"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true + +[features] +alloc = [] +serde1 = ["serde", "serde_derive"] +std = ["alloc"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_core/LICENSE-APACHE b/rand_core/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_core/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_core/LICENSE-MIT b/rand_core/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_core/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_core/README.md b/rand_core/README.md new file mode 100644 index 000000000..ef076b99d --- /dev/null +++ b/rand_core/README.md @@ -0,0 +1,66 @@ +# rand_core + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_core.svg)](https://crates.io/crates/rand_core) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_core) +[![API](https://docs.rs/rand_core/badge.svg)](https://docs.rs/rand_core) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Core traits and error types of the [rand] library, plus tools for implementing +RNGs. + +This crate is intended for use when implementing the core trait, `RngCore`; it +defines the core traits to be implemented as well as several small functions to +aid in their implementation and types required for error handling. + +The main [rand] crate re-exports most items defined in this crate, along with +tools to convert the integer samples generated by `RngCore` to many different +applications (including sampling from restricted ranges, conversion to floating +point, list permutations and secure initialisation of RNGs). Most users should +prefer to use the main [rand] crate. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_core) +- [API documentation (docs.rs)](https://docs.rs/rand_core) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Functionality + +The `rand_core` crate provides: + +- base random number generator traits +- error-reporting types +- functionality to aid implementation of RNGs + +The traits and error types are also available via `rand`. + +## Crate Features + +`rand_core` supports `no_std` and `alloc`-only configurations, as well as full +`std` functionality. The differences between `no_std` and full `std` are small, +comprising `RngCore` support for `Box<R>` types where `R: RngCore`, +`std::io::Read` support for types supporting `RngCore`, and +extensions to the `Error` type's functionality. + +The `std` feature is *not enabled by default*. This is primarily to avoid build +problems where one crate implicitly requires `rand_core` with `std` support and +another crate requires `rand` *without* `std` support. However, the `rand` crate +continues to enable `std` support by default, both for itself and `rand_core`. + +The `serde1` feature can be used to derive `Serialize` and `Deserialize` for RNG +implementations that use the `BlockRng` or `BlockRng64` wrappers. + + +# License + +`rand_core` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_core/src/block.rs b/rand_core/src/block.rs new file mode 100644 index 000000000..3045b9482 --- /dev/null +++ b/rand_core/src/block.rs @@ -0,0 +1,499 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `BlockRngCore` trait and implementation helpers +//! +//! The [`BlockRngCore`] trait exists to assist in the implementation of RNGs +//! which generate a block of data in a cache instead of returning generated +//! values directly. +//! +//! Usage of this trait is optional, but provides two advantages: +//! implementations only need to concern themselves with generation of the +//! block, not the various [`RngCore`] methods (especially [`fill_bytes`], where +//! the optimal implementations are not trivial), and this allows +//! `ReseedingRng` (see [`rand`](https://docs.rs/rand) crate) perform periodic +//! reseeding with very low overhead. +//! +//! # Example +//! +//! ```norun +//! use rand_core::block::{BlockRngCore, BlockRng}; +//! +//! struct MyRngCore; +//! +//! impl BlockRngCore for MyRngCore { +//! type Results = [u32; 16]; +//! +//! fn generate(&mut self, results: &mut Self::Results) { +//! unimplemented!() +//! } +//! } +//! +//! impl SeedableRng for MyRngCore { +//! type Seed = unimplemented!(); +//! fn from_seed(seed: Self::Seed) -> Self { +//! unimplemented!() +//! } +//! } +//! +//! // optionally, also implement CryptoRng for MyRngCore +//! +//! // Final RNG. +//! type MyRng = BlockRng<u32, MyRngCore>; +//! ``` +//! +//! [`BlockRngCore`]: crate::block::BlockRngCore +//! [`fill_bytes`]: RngCore::fill_bytes + +use core::convert::AsRef; +use core::fmt; +use {RngCore, CryptoRng, SeedableRng, Error}; +use impls::{fill_via_u32_chunks, fill_via_u64_chunks}; + +/// A trait for RNGs which do not generate random numbers individually, but in +/// blocks (typically `[u32; N]`). This technique is commonly used by +/// cryptographic RNGs to improve performance. +/// +/// See the [module][crate::block] documentation for details. +pub trait BlockRngCore { + /// Results element type, e.g. `u32`. + type Item; + + /// Results type. This is the 'block' an RNG implementing `BlockRngCore` + /// generates, which will usually be an array like `[u32; 16]`. + type Results: AsRef<[Self::Item]> + AsMut<[Self::Item]> + Default; + + /// Generate a new block of results. + fn generate(&mut self, results: &mut Self::Results); +} + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u32` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// The `core` field may be accessed directly but the results buffer may not. +/// PRNG implementations can simply use a type alias +/// (`pub type MyRng = BlockRng<MyRngCore>;`) but might prefer to use a +/// wrapper type (`pub struct MyRng(BlockRng<MyRngCore>);`); the latter must +/// re-implement `RngCore` but hides the implementation details and allows +/// extra functionality to be defined on the RNG +/// (e.g. `impl MyRng { fn set_stream(...){...} }`). +/// +/// `BlockRng` has heavily optimized implementations of the [`RngCore`] methods +/// reading values from the results buffer, as well as +/// calling [`BlockRngCore::generate`] directly on the output array when +/// [`fill_bytes`] / [`try_fill_bytes`] is called on a large array. These methods +/// also handle the bookkeeping of when to generate a new batch of values. +/// +/// No whole generated `u32` values are thown away and all values are consumed +/// in-order. [`next_u32`] simply takes the next available `u32` value. +/// [`next_u64`] is implemented by combining two `u32` values, least +/// significant first. [`fill_bytes`] and [`try_fill_bytes`] consume a whole +/// number of `u32` values, converting each `u32` to a byte slice in +/// little-endian order. If the requested byte length is not a multiple of 4, +/// some bytes will be discarded. +/// +/// See also [`BlockRng64`] which uses `u64` array buffers. Currently there is +/// no direct support for other buffer types. +/// +/// For easy initialization `BlockRng` also implements [`SeedableRng`]. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng<R: BlockRngCore + ?Sized> { + results: R::Results, + index: usize, + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng<R> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .finish() + } +} + +impl<R: BlockRngCore> BlockRng<R> { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng<R>{ + let results_empty = R::Results::default(); + BlockRng { + core, + index: results_empty.as_ref().len(), + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + } +} + +impl<R: BlockRngCore<Item=u32>> RngCore for BlockRng<R> +where <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + value + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + let read_u64 = |results: &[u32], index| { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // requires little-endian CPU supporting unaligned reads: + unsafe { *(&results[index] as *const u32 as *const u64) } + } else { + let x = u64::from(results[index]); + let y = u64::from(results[index + 1]); + (y << 32) | x + } + }; + + let len = self.results.as_ref().len(); + + let index = self.index; + if index < len-1 { + self.index += 2; + // Read an u64 from the current index + read_u64(self.results.as_ref(), index) + } else if index >= len { + self.generate_and_set(2); + read_u64(self.results.as_ref(), 0) + } else { + let x = u64::from(self.results.as_ref()[len-1]); + self.generate_and_set(1); + let y = u64::from(self.results.as_ref()[0]); + (y << 32) | x + } + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u32; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 4); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u32: &mut R::Results = unsafe { + &mut *(dest[filled..].as_mut_ptr() as + *mut <R as BlockRngCore>::Results) + }; + self.core.generate(dest_u32); + filled += self.results.as_ref().len() * 4; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u32, _) = + fill_via_u32_chunks(self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u32; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + while read_len < dest.len() { + if self.index >= self.results.as_ref().len() { + self.generate_and_set(0); + } + let (consumed_u32, filled_u8) = + fill_via_u32_chunks(&self.results.as_ref()[self.index..], + &mut dest[read_len..]); + + self.index += consumed_u32; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + Ok(Self::new(R::from_rng(rng)?)) + } +} + + + +/// A wrapper type implementing [`RngCore`] for some type implementing +/// [`BlockRngCore`] with `u64` array buffer; i.e. this can be used to implement +/// a full RNG from just a `generate` function. +/// +/// This is similar to [`BlockRng`], but specialized for algorithms that operate +/// on `u64` values. +/// +/// No whole generated `u64` values are thrown away and all values are consumed +/// in-order. [`next_u64`] simply takes the next available `u64` value. +/// [`next_u32`] is however a bit special: half of a `u64` is consumed, leaving +/// the other half in the buffer. If the next function called is [`next_u32`] +/// then the other half is then consumed, however both [`next_u64`] and +/// [`fill_bytes`] discard the rest of any half-consumed `u64`s when called. +/// +/// [`fill_bytes`] and [`try_fill_bytes`] consume a whole number of `u64` +/// values. If the requested length is not a multiple of 8, some bytes will be +/// discarded. +/// +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct BlockRng64<R: BlockRngCore + ?Sized> { + results: R::Results, + index: usize, + half_used: bool, // true if only half of the previous result is used + /// The *core* part of the RNG, implementing the `generate` function. + pub core: R, +} + +// Custom Debug implementation that does not expose the contents of `results`. +impl<R: BlockRngCore + fmt::Debug> fmt::Debug for BlockRng64<R> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("BlockRng64") + .field("core", &self.core) + .field("result_len", &self.results.as_ref().len()) + .field("index", &self.index) + .field("half_used", &self.half_used) + .finish() + } +} + +impl<R: BlockRngCore> BlockRng64<R> { + /// Create a new `BlockRng` from an existing RNG implementing + /// `BlockRngCore`. Results will be generated on first use. + pub fn new(core: R) -> BlockRng64<R>{ + let results_empty = R::Results::default(); + BlockRng64 { + core, + index: results_empty.as_ref().len(), + half_used: false, + results: results_empty, + } + } + + /// Get the index into the result buffer. + /// + /// If this is equal to or larger than the size of the result buffer then + /// the buffer is "empty" and `generate()` must be called to produce new + /// results. + pub fn index(&self) -> usize { + self.index + } + + /// Reset the number of available results. + /// This will force a new set of results to be generated on next use. + pub fn reset(&mut self) { + self.index = self.results.as_ref().len(); + self.half_used = false; + } + + /// Generate a new set of results immediately, setting the index to the + /// given value. + pub fn generate_and_set(&mut self, index: usize) { + assert!(index < self.results.as_ref().len()); + self.core.generate(&mut self.results); + self.index = index; + self.half_used = false; + } +} + +impl<R: BlockRngCore<Item=u64>> RngCore for BlockRng64<R> +where <R as BlockRngCore>::Results: AsRef<[u64]> + AsMut<[u64]> +{ + #[inline(always)] + fn next_u32(&mut self) -> u32 { + let mut index = self.index * 2 - self.half_used as usize; + if index >= self.results.as_ref().len() * 2 { + self.core.generate(&mut self.results); + self.index = 0; + // `self.half_used` is by definition `false` + self.half_used = false; + index = 0; + } + + self.half_used = !self.half_used; + self.index += self.half_used as usize; + + // Index as if this is a u32 slice. + unsafe { + let results = + &*(self.results.as_ref() as *const [u64] as *const [u32]); + if cfg!(target_endian = "little") { + *results.get_unchecked(index) + } else { + *results.get_unchecked(index ^ 1) + } + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if self.index >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let value = self.results.as_ref()[self.index]; + self.index += 1; + self.half_used = false; + value + } + + // As an optimization we try to write directly into the output buffer. + // This is only enabled for little-endian platforms where unaligned writes + // are known to be safe and fast. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut filled = 0; + self.half_used = false; + + // Continue filling from the current set of results + if self.index < self.results.as_ref().len() { + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index..], + dest); + + self.index += consumed_u64; + filled += filled_u8; + } + + let len_remainder = + (dest.len() - filled) % (self.results.as_ref().len() * 8); + let end_direct = dest.len() - len_remainder; + + while filled < end_direct { + let dest_u64: &mut R::Results = unsafe { + ::core::mem::transmute(dest[filled..].as_mut_ptr()) + }; + self.core.generate(dest_u64); + filled += self.results.as_ref().len() * 8; + self.index = self.results.as_ref().len(); + } + + if len_remainder > 0 { + self.core.generate(&mut self.results); + let (consumed_u64, _) = + fill_via_u64_chunks(&mut self.results.as_ref(), + &mut dest[filled..]); + + self.index = consumed_u64; + } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut read_len = 0; + self.half_used = false; + while read_len < dest.len() { + if self.index as usize >= self.results.as_ref().len() { + self.core.generate(&mut self.results); + self.index = 0; + } + + let (consumed_u64, filled_u8) = + fill_via_u64_chunks(&self.results.as_ref()[self.index as usize..], + &mut dest[read_len..]); + + self.index += consumed_u64; + read_len += filled_u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> { + type Seed = R::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Self::new(R::from_seed(seed)) + } + + fn seed_from_u64(seed: u64) -> Self { + Self::new(R::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + Ok(Self::new(R::from_rng(rng)?)) + } +} + +impl<R: BlockRngCore + CryptoRng> CryptoRng for BlockRng<R> {} diff --git a/rand_core/src/error.rs b/rand_core/src/error.rs new file mode 100644 index 000000000..5a8459ea8 --- /dev/null +++ b/rand_core/src/error.rs @@ -0,0 +1,177 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error types + +use core::fmt; + +#[cfg(feature="std")] +use std::error::Error as stdError; +#[cfg(feature="std")] +use std::io; + +/// Error kind which can be matched over. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum ErrorKind { + /// Feature is not available; not recoverable. + /// + /// This is the most permanent failure type and implies the error cannot be + /// resolved simply by retrying (e.g. the feature may not exist in this + /// build of the application or on the current platform). + Unavailable, + /// General failure; there may be a chance of recovery on retry. + /// + /// This is the catch-all kind for errors from known and unknown sources + /// which do not have a more specific kind / handling method. + /// + /// It is suggested to retry a couple of times or retry later when + /// handling; some error sources may be able to resolve themselves, + /// although this is not likely. + Unexpected, + /// A transient failure which likely can be resolved or worked around. + /// + /// This error kind exists for a few specific cases where it is known that + /// the error likely can be resolved internally, but is reported anyway. + Transient, + /// Not ready yet: recommended to try again a little later. + /// + /// This error kind implies the generator needs more time or needs some + /// other part of the application to do something else first before it is + /// ready for use; for example this may be used by external generators + /// which require time for initialization. + NotReady, + #[doc(hidden)] + __Nonexhaustive, +} + +impl ErrorKind { + /// True if this kind of error may resolve itself on retry. + /// + /// See also `should_wait()`. + pub fn should_retry(self) -> bool { + self != ErrorKind::Unavailable + } + + /// True if we should retry but wait before retrying + /// + /// This implies `should_retry()` is true. + pub fn should_wait(self) -> bool { + self == ErrorKind::NotReady + } + + /// A description of this error kind + pub fn description(self) -> &'static str { + match self { + ErrorKind::Unavailable => "permanently unavailable", + ErrorKind::Unexpected => "unexpected failure", + ErrorKind::Transient => "transient failure", + ErrorKind::NotReady => "not ready yet", + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} + + +/// Error type of random number generators +/// +/// This is a relatively simple error type, designed for compatibility with and +/// without the Rust `std` library. It embeds a "kind" code, a message (static +/// string only), and an optional chained cause (`std` only). The `kind` and +/// `msg` fields can be accessed directly; cause can be accessed via +/// `std::error::Error::cause` or `Error::take_cause`. Construction can only be +/// done via `Error::new` or `Error::with_cause`. +#[derive(Debug)] +pub struct Error { + /// The error kind + pub kind: ErrorKind, + /// The error message + pub msg: &'static str, + #[cfg(feature="std")] + cause: Option<Box<stdError + Send + Sync>>, +} + +impl Error { + /// Create a new instance, with specified kind and a message. + pub fn new(kind: ErrorKind, msg: &'static str) -> Self { + #[cfg(feature="std")] { + Error { kind, msg, cause: None } + } + #[cfg(not(feature="std"))] { + Error { kind, msg } + } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// Note: `stdError` is an alias for `std::error::Error`. + /// + /// If not targetting `std` (i.e. `no_std`), this function is replaced by + /// another with the same prototype, except that there are no bounds on the + /// type `E` (because both `Box` and `stdError` are unavailable), and the + /// `cause` is ignored. + #[cfg(feature="std")] + pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, cause: E) -> Self + where E: Into<Box<stdError + Send + Sync>> + { + Error { kind, msg, cause: Some(cause.into()) } + } + + /// Create a new instance, with specified kind, message, and a + /// chained cause. + /// + /// In `no_std` mode the *cause* is ignored. + #[cfg(not(feature="std"))] + pub fn with_cause<E>(kind: ErrorKind, msg: &'static str, _cause: E) -> Self { + Error { kind, msg } + } + + /// Take the cause, if any. This allows the embedded cause to be extracted. + /// This uses `Option::take`, leaving `self` with no cause. + #[cfg(feature="std")] + pub fn take_cause(&mut self) -> Option<Box<stdError + Send + Sync>> { + self.cause.take() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(feature="std")] { + if let Some(ref cause) = self.cause { + return write!(f, "{} ({}); cause: {}", + self.msg, self.kind.description(), cause); + } + } + write!(f, "{} ({})", self.msg, self.kind.description()) + } +} + +#[cfg(feature="std")] +impl stdError for Error { + fn description(&self) -> &str { + self.msg + } + + fn cause(&self) -> Option<&stdError> { + self.cause.as_ref().map(|e| e.as_ref() as &stdError) + } +} + +#[cfg(feature="std")] +impl From<Error> for io::Error { + fn from(error: Error) -> Self { + use std::io::ErrorKind::*; + match error.kind { + ErrorKind::Unavailable => io::Error::new(NotFound, error), + ErrorKind::Unexpected | + ErrorKind::Transient => io::Error::new(Other, error), + ErrorKind::NotReady => io::Error::new(WouldBlock, error), + ErrorKind::__Nonexhaustive => unreachable!(), + } + } +} diff --git a/rand_core/src/impls.rs b/rand_core/src/impls.rs new file mode 100644 index 000000000..57bdd070d --- /dev/null +++ b/rand_core/src/impls.rs @@ -0,0 +1,165 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions for implementing `RngCore` functions. +//! +//! For cross-platform reproducibility, these functions all use Little Endian: +//! least-significant part first. For example, `next_u64_via_u32` takes `u32` +//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32` +//! from `next_u64` in little-endian order, one should use `next_u64() as u32`. +//! +//! Byte-swapping (like the std `to_le` functions) is only needed to convert +//! to/from byte sequences, and since its purpose is reproducibility, +//! non-reproducible sources (e.g. `OsRng`) need not bother with it. + +use core::intrinsics::transmute; +use core::ptr::copy_nonoverlapping; +use core::slice; +use core::cmp::min; +use core::mem::size_of; +use RngCore; + + +/// Implement `next_u64` via `next_u32`, little-endian order. +pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 { + // Use LE; we explicitly generate one value before the next. + let x = u64::from(rng.next_u32()); + let y = u64::from(rng.next_u32()); + (y << 32) | x +} + +/// Implement `fill_bytes` via `next_u64` and `next_u32`, little-endian order. +/// +/// The fastest way to fill a slice is usually to work as long as possible with +/// integers. That is why this method mostly uses `next_u64`, and only when +/// there are 4 or less bytes remaining at the end of the slice it uses +/// `next_u32` once. +pub fn fill_bytes_via_next<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) { + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 4 { + let chunk: [u8; 8] = unsafe { + transmute(rng.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } else if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(rng.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } +} + +macro_rules! impl_uint_from_fill { + ($rng:expr, $ty:ty, $N:expr) => ({ + debug_assert!($N == size_of::<$ty>()); + + let mut int: $ty = 0; + unsafe { + let ptr = &mut int as *mut $ty as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, $N); + $rng.fill_bytes(slice); + } + int + }); +} + +macro_rules! fill_via_chunks { + ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({ + let chunk_size_u8 = min($src.len() * $size, $dst.len()); + let chunk_size = (chunk_size_u8 + $size - 1) / $size; + if cfg!(target_endian="little") { + unsafe { + copy_nonoverlapping( + $src.as_ptr() as *const u8, + $dst.as_mut_ptr(), + chunk_size_u8); + } + } else { + for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) { + let tmp = n.to_le(); + let src_ptr = &tmp as *const $ty as *const u8; + unsafe { + copy_nonoverlapping(src_ptr, + chunk.as_mut_ptr(), + chunk.len()); + } + } + } + + (chunk_size, chunk_size_u8) + }); +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u32, filled_u8)`. +/// +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u32` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 4` rounded up. +/// +/// # Example +/// (from `IsaacRng`) +/// +/// ```ignore +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// let mut read_len = 0; +/// while read_len < dest.len() { +/// if self.index >= self.rsl.len() { +/// self.isaac(); +/// } +/// +/// let (consumed_u32, filled_u8) = +/// impls::fill_via_u32_chunks(&mut self.rsl[self.index..], +/// &mut dest[read_len..]); +/// +/// self.index += consumed_u32; +/// read_len += filled_u8; +/// } +/// } +/// ``` +pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u32, 4) +} + +/// Implement `fill_bytes` by reading chunks from the output buffer of a block +/// based RNG. +/// +/// The return values are `(consumed_u64, filled_u8)`. +/// `filled_u8` is the number of filled bytes in `dest`, which may be less than +/// the length of `dest`. +/// `consumed_u64` is the number of words consumed from `src`, which is the same +/// as `filled_u8 / 8` rounded up. +/// +/// See `fill_via_u32_chunks` for an example. +pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) { + fill_via_chunks!(src, dest, u64, 8) +} + +/// Implement `next_u32` via `fill_bytes`, little-endian order. +pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 { + impl_uint_from_fill!(rng, u32, 4) +} + +/// Implement `next_u64` via `fill_bytes`, little-endian order. +pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 { + impl_uint_from_fill!(rng, u64, 8) +} + +// TODO: implement tests for the above diff --git a/rand_core/src/le.rs b/rand_core/src/le.rs new file mode 100644 index 000000000..266651f10 --- /dev/null +++ b/rand_core/src/le.rs @@ -0,0 +1,68 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Little-Endian utilities +//! +//! Little-Endian order has been chosen for internal usage; this makes some +//! useful functions available. + +use core::ptr; + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + ptr::copy_nonoverlapping( + $src.as_ptr(), + $dst.as_mut_ptr() as *mut u8, + $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} + +/// Reads unsigned 32 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u32_into(src: &[u8], dst: &mut [u32]) { + read_slice!(src, dst, 4, to_le); +} + +/// Reads unsigned 64 bit integers from `src` into `dst`. +/// Borrowed from the `byteorder` crate. +#[inline] +pub fn read_u64_into(src: &[u8], dst: &mut [u64]) { + read_slice!(src, dst, 8, to_le); +} + +#[test] +fn test_read() { + let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + let mut buf = [0u32; 4]; + read_u32_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x04030201); + assert_eq!(buf[3], 0x100F0E0D); + + let mut buf = [0u32; 3]; + read_u32_into(&bytes[1..13], &mut buf); // unaligned + assert_eq!(buf[0], 0x05040302); + assert_eq!(buf[2], 0x0D0C0B0A); + + let mut buf = [0u64; 2]; + read_u64_into(&bytes, &mut buf); + assert_eq!(buf[0], 0x0807060504030201); + assert_eq!(buf[1], 0x100F0E0D0C0B0A09); + + let mut buf = [0u64; 1]; + read_u64_into(&bytes[7..15], &mut buf); // unaligned + assert_eq!(buf[0], 0x0F0E0D0C0B0A0908); +} diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs new file mode 100644 index 000000000..4b0e6e48b --- /dev/null +++ b/rand_core/src/lib.rs @@ -0,0 +1,477 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Random number generation traits +//! +//! This crate is mainly of interest to crates publishing implementations of +//! [`RngCore`]. Other users are encouraged to use the [`rand`] crate instead +//! which re-exports the main traits and error types. +//! +//! [`RngCore`] is the core trait implemented by algorithmic pseudo-random number +//! generators and external random-number sources. +//! +//! [`SeedableRng`] is an extension trait for construction from fixed seeds and +//! other random number generators. +//! +//! [`Error`] is provided for error-handling. It is safe to use in `no_std` +//! environments. +//! +//! The [`impls`] and [`le`] sub-modules include a few small functions to assist +//! implementation of [`RngCore`]. +//! +//! [`rand`]: https://docs.rs/rand + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(feature="std"), no_std)] +#![cfg_attr(all(feature="alloc", not(feature="std")), feature(alloc))] + +#[cfg(feature="std")] extern crate core; +#[cfg(all(feature = "alloc", not(feature="std")))] extern crate alloc; +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + + +use core::default::Default; +use core::convert::AsMut; +use core::ptr::copy_nonoverlapping; + +#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box; + +pub use error::{ErrorKind, Error}; + + +mod error; +pub mod block; +pub mod impls; +pub mod le; + + +/// The core of a random number generator. +/// +/// This trait encapsulates the low-level functionality common to all +/// generators, and is the "back end", to be implemented by generators. +/// End users should normally use the `Rng` trait from the [`rand`] crate, +/// which is automatically implemented for every type implementing `RngCore`. +/// +/// Three different methods for generating random data are provided since the +/// optimal implementation of each is dependent on the type of generator. There +/// is no required relationship between the output of each; e.g. many +/// implementations of [`fill_bytes`] consume a whole number of `u32` or `u64` +/// values and drop any remaining unused bytes. +/// +/// The [`try_fill_bytes`] method is a variant of [`fill_bytes`] allowing error +/// handling; it is not deemed sufficiently useful to add equivalents for +/// [`next_u32`] or [`next_u64`] since the latter methods are almost always used +/// with algorithmic generators (PRNGs), which are normally infallible. +/// +/// Algorithmic generators implementing [`SeedableRng`] should normally have +/// *portable, reproducible* output, i.e. fix Endianness when converting values +/// to avoid platform differences, and avoid making any changes which affect +/// output (except by communicating that the release has breaking changes). +/// +/// Typically implementators will implement only one of the methods available +/// in this trait directly, then use the helper functions from the +/// [`impls`] module to implement the other methods. +/// +/// It is recommended that implementations also implement: +/// +/// - `Debug` with a custom implementation which *does not* print any internal +/// state (at least, [`CryptoRng`]s should not risk leaking state through +/// `Debug`). +/// - `Serialize` and `Deserialize` (from Serde), preferably making Serde +/// support optional at the crate level in PRNG libs. +/// - `Clone`, if possible. +/// - *never* implement `Copy` (accidental copies may cause repeated values). +/// - *do not* implement `Default` for pseudorandom generators, but instead +/// implement [`SeedableRng`], to guide users towards proper seeding. +/// External / hardware RNGs can choose to implement `Default`. +/// - `Eq` and `PartialEq` could be implemented, but are probably not useful. +/// +/// # Example +/// +/// A simple example, obviously not generating very *random* output: +/// +/// ``` +/// #![allow(dead_code)] +/// use rand_core::{RngCore, Error, impls}; +/// +/// struct CountingRng(u64); +/// +/// impl RngCore for CountingRng { +/// fn next_u32(&mut self) -> u32 { +/// self.next_u64() as u32 +/// } +/// +/// fn next_u64(&mut self) -> u64 { +/// self.0 += 1; +/// self.0 +/// } +/// +/// fn fill_bytes(&mut self, dest: &mut [u8]) { +/// impls::fill_bytes_via_next(self, dest) +/// } +/// +/// fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { +/// Ok(self.fill_bytes(dest)) +/// } +/// } +/// ``` +/// +/// [`rand`]: https://docs.rs/rand +/// [`try_fill_bytes`]: RngCore::try_fill_bytes +/// [`fill_bytes`]: RngCore::fill_bytes +/// [`next_u32`]: RngCore::next_u32 +/// [`next_u64`]: RngCore::next_u64 +pub trait RngCore { + /// Return the next random `u32`. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// using `self.next_u64() as u32` or via + /// [`fill_bytes`][impls::next_u32_via_fill]. + fn next_u32(&mut self) -> u32; + + /// Return the next random `u64`. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// via [`next_u32`][impls::next_u64_via_u32] or via + /// [`fill_bytes`][impls::next_u64_via_fill]. + fn next_u64(&mut self) -> u64; + + /// Fill `dest` with random data. + /// + /// RNGs must implement at least one method from this trait directly. In + /// the case this method is not implemented directly, it can be implemented + /// via [`next_u*`][impls::fill_bytes_via_next] or + /// via [`try_fill_bytes`][RngCore::try_fill_bytes]; if this generator can + /// fail the implementation must choose how best to handle errors here + /// (e.g. panic with a descriptive message or log a warning and retry a few + /// times). + /// + /// This method should guarantee that `dest` is entirely filled + /// with new data, and may panic if this is impossible + /// (e.g. reading past the end of a file that is being used as the + /// source of randomness). + fn fill_bytes(&mut self, dest: &mut [u8]); + + /// Fill `dest` entirely with random data. + /// + /// This is the only method which allows an RNG to report errors while + /// generating random data thus making this the primary method implemented + /// by external (true) RNGs (e.g. `OsRng`) which can fail. It may be used + /// directly to generate keys and to seed (infallible) PRNGs. + /// + /// Other than error handling, this method is identical to [`fill_bytes`]; + /// thus this may be implemented using `Ok(self.fill_bytes(dest))` or + /// `fill_bytes` may be implemented with + /// `self.try_fill_bytes(dest).unwrap()` or more specific error handling. + /// + /// [`fill_bytes`]: RngCore::fill_bytes + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>; +} + +/// A marker trait used to indicate that an [`RngCore`] or [`BlockRngCore`] +/// implementation is supposed to be cryptographically secure. +/// +/// *Cryptographically secure generators*, also known as *CSPRNGs*, should +/// satisfy an additional properties over other generators: given the first +/// *k* bits of an algorithm's output +/// sequence, it should not be possible using polynomial-time algorithms to +/// predict the next bit with probability significantly greater than 50%. +/// +/// Some generators may satisfy an additional property, however this is not +/// required by this trait: if the CSPRNG's state is revealed, it should not be +/// computationally-feasible to reconstruct output prior to this. Some other +/// generators allow backwards-computation and are consided *reversible*. +/// +/// Note that this trait is provided for guidance only and cannot guarantee +/// suitability for cryptographic applications. In general it should only be +/// implemented for well-reviewed code implementing well-regarded algorithms. +/// +/// Note also that use of a `CryptoRng` does not protect against other +/// weaknesses such as seeding from a weak entropy source or leaking state. +/// +/// [`BlockRngCore`]: block::BlockRngCore +pub trait CryptoRng {} + +/// A random number generator that can be explicitly seeded. +/// +/// This trait encapsulates the low-level functionality common to all +/// pseudo-random number generators (PRNGs, or algorithmic generators). +/// +/// The `FromEntropy` trait from the [`rand`] crate is automatically +/// implemented for every type implementing `SeedableRng`, providing +/// a convenient `from_entropy()` constructor. +/// +/// [`rand`]: https://docs.rs/rand +pub trait SeedableRng: Sized { + /// Seed type, which is restricted to types mutably-dereferencable as `u8` + /// arrays (we recommend `[u8; N]` for some `N`). + /// + /// It is recommended to seed PRNGs with a seed of at least circa 100 bits, + /// which means an array of `[u8; 12]` or greater to avoid picking RNGs with + /// partially overlapping periods. + /// + /// For cryptographic RNG's a seed of 256 bits is recommended, `[u8; 32]`. + /// + /// + /// # Implementing `SeedableRng` for RNGs with large seeds + /// + /// Note that the required traits `core::default::Default` and + /// `core::convert::AsMut<u8>` are not implemented for large arrays + /// `[u8; N]` with `N` > 32. To be able to implement the traits required by + /// `SeedableRng` for RNGs with such large seeds, the newtype pattern can be + /// used: + /// + /// ``` + /// use rand_core::SeedableRng; + /// + /// const N: usize = 64; + /// pub struct MyRngSeed(pub [u8; N]); + /// pub struct MyRng(MyRngSeed); + /// + /// impl Default for MyRngSeed { + /// fn default() -> MyRngSeed { + /// MyRngSeed([0; N]) + /// } + /// } + /// + /// impl AsMut<[u8]> for MyRngSeed { + /// fn as_mut(&mut self) -> &mut [u8] { + /// &mut self.0 + /// } + /// } + /// + /// impl SeedableRng for MyRng { + /// type Seed = MyRngSeed; + /// + /// fn from_seed(seed: MyRngSeed) -> MyRng { + /// MyRng(seed) + /// } + /// } + /// ``` + type Seed: Sized + Default + AsMut<[u8]>; + + /// Create a new PRNG using the given seed. + /// + /// PRNG implementations are allowed to assume that bits in the seed are + /// well distributed. That means usually that the number of one and zero + /// bits are about equal, and values like 0, 1 and (size - 1) are unlikely. + /// + /// PRNG implementations are recommended to be reproducible. A PRNG seeded + /// using this function with a fixed seed should produce the same sequence + /// of output in the future and on different architectures (with for example + /// different endianness). + /// + /// It is however not required that this function yield the same state as a + /// reference implementation of the PRNG given equivalent seed; if necessary + /// another constructor replicating behaviour from a reference + /// implementation can be added. + /// + /// PRNG implementations should make sure `from_seed` never panics. In the + /// case that some special values (like an all zero seed) are not viable + /// seeds it is preferable to map these to alternative constant value(s), + /// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad + /// seed"). This is assuming only a small number of values must be rejected. + fn from_seed(seed: Self::Seed) -> Self; + + /// Create a new PRNG using a `u64` seed. + /// + /// This is a convenience-wrapper around `from_seed` to allow construction + /// of any `SeedableRng` from a simple `u64` value. It is designed such that + /// low Hamming Weight numbers like 0 and 1 can be used and should still + /// result in good, independent seeds to the PRNG which is returned. + /// + /// This **is not suitable for cryptography**, as should be clear given that + /// the input size is only 64 bits. + /// + /// Implementations for PRNGs *may* provide their own implementations of + /// this function, but the default implementation should be good enough for + /// all purposes. *Changing* the implementation of this function should be + /// considered a value-breaking change. + fn seed_from_u64(mut state: u64) -> Self { + // We use PCG32 to generate a u32 sequence, and copy to the seed + const MUL: u64 = 6364136223846793005; + const INC: u64 = 11634580027462260723; + + let mut seed = Self::Seed::default(); + for chunk in seed.as_mut().chunks_mut(4) { + // We advance the state first (to get away from the input value, + // in case it has low Hamming Weight). + state = state.wrapping_mul(MUL).wrapping_add(INC); + + // Use PCG output function with to_le to generate x: + let xorshifted = (((state >> 18) ^ state) >> 27) as u32; + let rot = (state >> 59) as u32; + let x = xorshifted.rotate_right(rot).to_le(); + + unsafe { + let p = &x as *const u32 as *const u8; + copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len()); + } + } + + Self::from_seed(seed) + } + + /// Create a new PRNG seeded from another `Rng`. + /// + /// This is the recommended way to initialize PRNGs with fresh entropy. The + /// `FromEntropy` trait from the [`rand`] crate provides a convenient + /// `from_entropy` method based on `from_rng`. + /// + /// Usage of this method is not recommended when reproducibility is required + /// since implementing PRNGs are not required to fix Endianness and are + /// allowed to modify implementations in new releases. + /// + /// It is important to use a good source of randomness to initialize the + /// PRNG. Cryptographic PRNG may be rendered insecure when seeded from a + /// non-cryptographic PRNG or with insufficient entropy. + /// Many non-cryptographic PRNGs will show statistical bias in their first + /// results if their seed numbers are small or if there is a simple pattern + /// between them. + /// + /// Prefer to seed from a strong external entropy source like `OsRng` from + /// the [`rand_os`] crate or from a cryptographic PRNG; if creating a new + /// generator for cryptographic uses you *must* seed from a strong source. + /// + /// Seeding a small PRNG from another small PRNG is possible, but + /// something to be careful with. An extreme example of how this can go + /// wrong is seeding an Xorshift RNG from another Xorshift RNG, which + /// will effectively clone the generator. In general seeding from a + /// generator which is hard to predict is probably okay. + /// + /// PRNG implementations are allowed to assume that a good RNG is provided + /// for seeding, and that it is cryptographically secure when appropriate. + /// + /// [`rand`]: https://docs.rs/rand + /// [`rand_os`]: https://docs.rs/rand_os + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + let mut seed = Self::Seed::default(); + rng.try_fill_bytes(seed.as_mut())?; + Ok(Self::from_seed(seed)) + } +} + +// Implement `RngCore` for references to an `RngCore`. +// Force inlining all functions, so that it is up to the `RngCore` +// implementation and the optimizer to decide on inlining. +impl<'a, R: RngCore + ?Sized> RngCore for &'a mut R { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + (**self).try_fill_bytes(dest) + } +} + +// Implement `RngCore` for boxed references to an `RngCore`. +// Force inlining all functions, so that it is up to the `RngCore` +// implementation and the optimizer to decide on inlining. +#[cfg(feature="alloc")] +impl<R: RngCore + ?Sized> RngCore for Box<R> { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + (**self).next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + (**self).next_u64() + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + (**self).fill_bytes(dest) + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + (**self).try_fill_bytes(dest) + } +} + +#[cfg(feature="std")] +impl std::io::Read for RngCore { + fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> { + self.try_fill_bytes(buf)?; + Ok(buf.len()) + } +} + +// Implement `CryptoRng` for references to an `CryptoRng`. +impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {} + +// Implement `CryptoRng` for boxed references to an `CryptoRng`. +#[cfg(feature="alloc")] +impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_seed_from_u64() { + struct SeedableNum(u64); + impl SeedableRng for SeedableNum { + type Seed = [u8; 8]; + fn from_seed(seed: Self::Seed) -> Self { + let mut x = [0u64; 1]; + le::read_u64_into(&seed, &mut x); + SeedableNum(x[0]) + } + } + + const N: usize = 8; + const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64]; + let mut results = [0u64; N]; + for (i, seed) in SEEDS.iter().enumerate() { + let SeedableNum(x) = SeedableNum::seed_from_u64(*seed); + results[i] = x; + } + + for (i1, r1) in results.iter().enumerate() { + let weight = r1.count_ones(); + // This is the binomial distribution B(64, 0.5), so chance of + // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for + // weight > 44. + assert!(weight >= 20 && weight <= 44); + + for (i2, r2) in results.iter().enumerate() { + if i1 == i2 { continue; } + let diff_weight = (r1 ^ r2).count_ones(); + assert!(diff_weight >= 20); + } + } + + // value-breakage test: + assert_eq!(results[0], 5029875928683246316); + } +} diff --git a/rand_hc/.cargo-checksum.json b/rand_hc/.cargo-checksum.json new file mode 100644 index 000000000..ca2bf5ea3 --- /dev/null +++ b/rand_hc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"} \ No newline at end of file diff --git a/rand_hc/CHANGELOG.md b/rand_hc/CHANGELOG.md new file mode 100644 index 000000000..d0c4a2fcb --- /dev/null +++ b/rand_hc/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/rand_hc/COPYRIGHT b/rand_hc/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_hc/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_hc/Cargo.toml b/rand_hc/Cargo.toml new file mode 100644 index 000000000..e08027473 --- /dev/null +++ b/rand_hc/Cargo.toml @@ -0,0 +1,32 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_hc" +version = "0.1.0" +authors = ["The Rand Project Developers"] +description = "HC128 random number generator\n" +homepage = "https://crates.io/crates/rand_hc" +documentation = "https://docs.rs/rand_hc" +readme = "README.md" +keywords = ["random", "rng", "hc128"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_hc/LICENSE-APACHE b/rand_hc/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_hc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_hc/LICENSE-MIT b/rand_hc/LICENSE-MIT new file mode 100644 index 000000000..cf656074c --- /dev/null +++ b/rand_hc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright 2018 Developers of the Rand project + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_hc/README.md b/rand_hc/README.md new file mode 100644 index 000000000..9c1f5e122 --- /dev/null +++ b/rand_hc/README.md @@ -0,0 +1,44 @@ +# rand_hc + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_hc.svg)](https://crates.io/crates/rand_hc) +[![Documentation](https://docs.rs/rand_hc/badge.svg)](https://docs.rs/rand_hc) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-yellow.svg)](https://github.com/rust-random/rand#rust-version-requirements) +[![License](https://img.shields.io/crates/l/rand_hc.svg)](https://github.com/rust-random/rand/tree/master/rand_hc#license) + +A cryptographically secure random number generator that uses the HC-128 +algorithm. + +HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an +RNG. It is selected as one of the "stream ciphers suitable for widespread +adoption" by eSTREAM[^2]. + +Documentation: +[master branch](https://rust-random.github.io/rand/rand_hc/index.html), +[by release](https://docs.rs/rand_hc) + +[Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( + http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). + *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. + +[^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( + http://www.ecrypt.eu.org/stream/) + + +## Crate Features + +`rand_hc` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + + +# License + +`rand_hc` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_hc/src/hc128.rs b/rand_hc/src/hc128.rs new file mode 100644 index 000000000..d1dadcc90 --- /dev/null +++ b/rand_hc/src/hc128.rs @@ -0,0 +1,462 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The HC-128 random number generator. + +use core::fmt; +use rand_core::{CryptoRng, RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; + +const SEED_WORDS: usize = 8; // 128 bit key followed by 128 bit iv + +/// A cryptographically secure random number generator that uses the HC-128 +/// algorithm. +/// +/// HC-128 is a stream cipher designed by Hongjun Wu[^1], that we use as an +/// RNG. It is selected as one of the "stream ciphers suitable for widespread +/// adoption" by eSTREAM[^2]. +/// +/// HC-128 is an array based RNG. In this it is similar to RC-4 and ISAAC before +/// it, but those have never been proven cryptographically secure (or have even +/// been significantly compromised, as in the case of RC-4[^5]). +/// +/// Because HC-128 works with simple indexing into a large array and with a few +/// operations that parallelize well, it has very good performance. The size of +/// the array it needs, 4kb, can however be a disadvantage. +/// +/// This implementation is not based on the version of HC-128 submitted to the +/// eSTREAM contest, but on a later version by the author with a few small +/// improvements from December 15, 2009[^3]. +/// +/// HC-128 has no known weaknesses that are easier to exploit than doing a +/// brute-force search of 2<sup>128</sup>. A very comprehensive analysis of the +/// current state of known attacks / weaknesses of HC-128 is given in *Some +/// Results On Analysis And Implementation Of HC-128 Stream Cipher*[^4]. +/// +/// The average cycle length is expected to be +/// 2<sup>1024*32+10-1</sup> = 2<sup>32777</sup>. +/// We support seeding with a 256-bit array, which matches the 128-bit key +/// concatenated with a 128-bit IV from the stream cipher. +/// +/// This implementation uses an output buffer of sixteen `u32` words, and uses +/// [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Hongjun Wu (2008). ["The Stream Cipher HC-128"]( +/// http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf). +/// *The eSTREAM Finalists*, LNCS 4986, pp. 39–47, Springer-Verlag. +/// +/// [^2]: [eSTREAM: the ECRYPT Stream Cipher Project]( +/// http://www.ecrypt.eu.org/stream/) +/// +/// [^3]: Hongjun Wu, [Stream Ciphers HC-128 and HC-256]( +/// https://www.ntu.edu.sg/home/wuhj/research/hc/index.html) +/// +/// [^4]: Shashwat Raizada (January 2015),["Some Results On Analysis And +/// Implementation Of HC-128 Stream Cipher"]( +/// http://library.isical.ac.in:8080/jspui/bitstream/123456789/6636/1/TH431.pdf). +/// +/// [^5]: Internet Engineering Task Force (February 2015), +/// ["Prohibiting RC4 Cipher Suites"](https://tools.ietf.org/html/rfc7465). +/// +/// [`BlockRng`]: ../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +pub struct Hc128Rng(BlockRng<Hc128Core>); + +impl RngCore for Hc128Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Hc128Rng { + type Seed = <Hc128Core as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Hc128Rng(BlockRng::<Hc128Core>::from_seed(seed)) + } + + fn from_rng<R: RngCore>(rng: R) -> Result<Self, Error> { + BlockRng::<Hc128Core>::from_rng(rng).map(Hc128Rng) + } +} + +impl CryptoRng for Hc128Rng {} + +/// The core of `Hc128Rng`, used with `BlockRng`. +#[derive(Clone)] +pub struct Hc128Core { + t: [u32; 1024], + counter1024: usize, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Hc128Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Hc128Core {{}}") + } +} + +impl BlockRngCore for Hc128Core { + type Item = u32; + type Results = [u32; 16]; + + fn generate(&mut self, results: &mut Self::Results) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 & 512 == 0 { + // P block + results[0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + results[0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + results[1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + results[2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + results[3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + results[4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + results[5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + results[6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + results[7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + results[8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + results[9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + results[10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + results[11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + results[12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + results[13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + results[14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + results[15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 = self.counter1024.wrapping_add(16); + } +} + +impl Hc128Core { + // One step of HC-128, update P and generate 32 bits keystream + #[inline(always)] + fn step_p(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + // FIXME: it would be great if we the bounds checks here could be + // optimized out, and we would not need unsafe. + // This improves performance by about 7%. + unsafe { + let temp0 = p.get_unchecked(i511).rotate_right(23); + let temp1 = p.get_unchecked(i3).rotate_right(10); + let temp2 = p.get_unchecked(i10).rotate_right(8); + *p.get_unchecked_mut(i) = p.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h1 function in HC-128 + let a = *p.get_unchecked(i12) as u8; + let c = (p.get_unchecked(i12) >> 16) as u8; + q[a as usize].wrapping_add(q[256 + c as usize]) + }; + temp3 ^ p.get_unchecked(i) + } + } + + // One step of HC-128, update Q and generate 32 bits keystream + // Similar to `step_p`, but `p` and `q` are swapped, and the rotates are to + // the left instead of to the right. + #[inline(always)] + fn step_q(&mut self, i: usize, i511: usize, i3: usize, i10: usize, i12: usize) + -> u32 + { + let (p, q) = self.t.split_at_mut(512); + unsafe { + let temp0 = q.get_unchecked(i511).rotate_left(23); + let temp1 = q.get_unchecked(i3).rotate_left(10); + let temp2 = q.get_unchecked(i10).rotate_left(8); + *q.get_unchecked_mut(i) = q.get_unchecked(i) + .wrapping_add(temp2) + .wrapping_add(temp0 ^ temp1); + let temp3 = { + // The h2 function in HC-128 + let a = *q.get_unchecked(i12) as u8; + let c = (q.get_unchecked(i12) >> 16) as u8; + p[a as usize].wrapping_add(p[256 + c as usize]) + }; + temp3 ^ q.get_unchecked(i) + } + } + + fn sixteen_steps(&mut self) { + assert!(self.counter1024 % 16 == 0); + + let cc = self.counter1024 % 512; + let dd = (cc + 16) % 512; + let ee = cc.wrapping_sub(16) % 512; + + if self.counter1024 < 512 { + // P block + self.t[cc+0] = self.step_p(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+1] = self.step_p(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+2] = self.step_p(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+3] = self.step_p(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+4] = self.step_p(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+5] = self.step_p(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+6] = self.step_p(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+7] = self.step_p(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+8] = self.step_p(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+9] = self.step_p(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+10] = self.step_p(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+11] = self.step_p(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+12] = self.step_p(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+13] = self.step_p(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+14] = self.step_p(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+15] = self.step_p(cc+15, dd+0, cc+12, cc+5, cc+3); + } else { + // Q block + self.t[cc+512+0] = self.step_q(cc+0, cc+1, ee+13, ee+6, ee+4); + self.t[cc+512+1] = self.step_q(cc+1, cc+2, ee+14, ee+7, ee+5); + self.t[cc+512+2] = self.step_q(cc+2, cc+3, ee+15, ee+8, ee+6); + self.t[cc+512+3] = self.step_q(cc+3, cc+4, cc+0, ee+9, ee+7); + self.t[cc+512+4] = self.step_q(cc+4, cc+5, cc+1, ee+10, ee+8); + self.t[cc+512+5] = self.step_q(cc+5, cc+6, cc+2, ee+11, ee+9); + self.t[cc+512+6] = self.step_q(cc+6, cc+7, cc+3, ee+12, ee+10); + self.t[cc+512+7] = self.step_q(cc+7, cc+8, cc+4, ee+13, ee+11); + self.t[cc+512+8] = self.step_q(cc+8, cc+9, cc+5, ee+14, ee+12); + self.t[cc+512+9] = self.step_q(cc+9, cc+10, cc+6, ee+15, ee+13); + self.t[cc+512+10] = self.step_q(cc+10, cc+11, cc+7, cc+0, ee+14); + self.t[cc+512+11] = self.step_q(cc+11, cc+12, cc+8, cc+1, ee+15); + self.t[cc+512+12] = self.step_q(cc+12, cc+13, cc+9, cc+2, cc+0); + self.t[cc+512+13] = self.step_q(cc+13, cc+14, cc+10, cc+3, cc+1); + self.t[cc+512+14] = self.step_q(cc+14, cc+15, cc+11, cc+4, cc+2); + self.t[cc+512+15] = self.step_q(cc+15, dd+0, cc+12, cc+5, cc+3); + } + self.counter1024 += 16; + } + + // Initialize an HC-128 random number generator. The seed has to be + // 256 bits in length (`[u32; 8]`), matching the 128 bit `key` followed by + // 128 bit `iv` when HC-128 where to be used as a stream cipher. + fn init(seed: [u32; SEED_WORDS]) -> Self { + #[inline] + fn f1(x: u32) -> u32 { + x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3) + } + + #[inline] + fn f2(x: u32) -> u32 { + x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10) + } + + let mut t = [0u32; 1024]; + + // Expand the key and iv into P and Q + let (key, iv) = seed.split_at(4); + t[..4].copy_from_slice(key); + t[4..8].copy_from_slice(key); + t[8..12].copy_from_slice(iv); + t[12..16].copy_from_slice(iv); + + // Generate the 256 intermediate values W[16] ... W[256+16-1], and + // copy the last 16 generated values to the start op P. + for i in 16..256+16 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(i as u32); + } + { + let (p1, p2) = t.split_at_mut(256); + p1[0..16].copy_from_slice(&p2[0..16]); + } + + // Generate both the P and Q tables + for i in 16..1024 { + t[i] = f2(t[i-2]).wrapping_add(t[i-7]).wrapping_add(f1(t[i-15])) + .wrapping_add(t[i-16]).wrapping_add(256 + i as u32); + } + + let mut core = Self { t, counter1024: 0 }; + + // run the cipher 1024 steps + for _ in 0..64 { core.sixteen_steps() }; + core.counter1024 = 0; + core + } +} + +impl SeedableRng for Hc128Core { + type Seed = [u8; SEED_WORDS*4]; + + /// Create an HC-128 random number generator with a seed. The seed has to be + /// 256 bits in length, matching the 128 bit `key` followed by 128 bit `iv` + /// when HC-128 where to be used as a stream cipher. + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; SEED_WORDS]; + le::read_u32_into(&seed, &mut seed_u32); + Self::init(seed_u32) + } +} + +impl CryptoRng for Hc128Core {} + +#[cfg(test)] +mod test { + use ::rand_core::{RngCore, SeedableRng}; + use super::Hc128Rng; + + #[test] + // Test vector 1 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_a() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x73150082, 0x3bfd03a0, 0xfb2fd77f, 0xaa63af0e, + 0xde122fc6, 0xa7dc29b6, 0x62a68527, 0x8b75ec68, + 0x9036db1e, 0x81896005, 0x00ade078, 0x491fbf9a, + 0x1cdc3013, 0x6c3d6e24, 0x90f664b2, 0x9cd57102]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 2 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_b() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0xc01893d5, 0xb7dbe958, 0x8f65ec98, 0x64176604, + 0x36fc6724, 0xc82c6eec, 0x1b1c38a7, 0xc9b42a95, + 0x323ef123, 0x0a6a908b, 0xce757b68, 0x9f14f7bb, + 0xe4cde011, 0xaeb5173f, 0x89608c94, 0xb5cf46ca]; + assert_eq!(results, expected); + } + + #[test] + // Test vector 3 from the paper "The Stream Cipher HC-128" + fn test_hc128_true_values_c() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected = [0x518251a4, 0x04b4930a, 0xb02af931, 0x0639f032, + 0xbcb4a47a, 0x5722480b, 0x2bf99f72, 0xcdc0e566, + 0x310f0c56, 0xd3cc83e8, 0x663db8ef, 0x62dfe07f, + 0x593e1790, 0xc5ceaa9c, 0xab03806f, 0xc9a6e5a0]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_u64() { + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + + let mut results = [0u64; 8]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0x3bfd03a073150082, 0xaa63af0efb2fd77f, + 0xa7dc29b6de122fc6, 0x8b75ec6862a68527, + 0x818960059036db1e, 0x491fbf9a00ade078, + 0x6c3d6e241cdc3013, 0x9cd5710290f664b2]; + assert_eq!(results, expected); + + // The RNG operates in a P block of 512 results and next a Q block. + // After skipping 2*800 u32 results we end up somewhere in the Q block + // of the second round + for _ in 0..800 { rng.next_u64(); } + + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [0xd8c4d6ca84d0fc10, 0xf16a5d91dc66e8e7, + 0xd800de5bc37a8653, 0x7bae1f88c0dfbb4c, + 0x3bfe1f374e6d4d14, 0x424b55676be3fa06, + 0xe3a1e8758cbff579, 0x417f7198c5652bcd]; + assert_eq!(results, expected); + } + + #[test] + fn test_hc128_true_values_bytes() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng = Hc128Rng::from_seed(seed); + let expected = [0x31, 0xf9, 0x2a, 0xb0, 0x32, 0xf0, 0x39, 0x06, + 0x7a, 0xa4, 0xb4, 0xbc, 0x0b, 0x48, 0x22, 0x57, + 0x72, 0x9f, 0xf9, 0x2b, 0x66, 0xe5, 0xc0, 0xcd, + 0x56, 0x0c, 0x0f, 0x31, 0xe8, 0x83, 0xcc, 0xd3, + 0xef, 0xb8, 0x3d, 0x66, 0x7f, 0xe0, 0xdf, 0x62, + 0x90, 0x17, 0x3e, 0x59, 0x9c, 0xaa, 0xce, 0xc5, + 0x6f, 0x80, 0x03, 0xab, 0xa0, 0xe5, 0xa6, 0xc9, + 0x60, 0x95, 0x84, 0x7a, 0xa5, 0x68, 0x5a, 0x84, + 0xea, 0xd5, 0xf3, 0xea, 0x73, 0xa9, 0xad, 0x01, + 0x79, 0x7d, 0xbe, 0x9f, 0xea, 0xe3, 0xf9, 0x74, + 0x0e, 0xda, 0x2f, 0xa0, 0xe4, 0x7b, 0x4b, 0x1b, + 0xdd, 0x17, 0x69, 0x4a, 0xfe, 0x9f, 0x56, 0x95, + 0xad, 0x83, 0x6b, 0x9d, 0x60, 0xa1, 0x99, 0x96, + 0x90, 0x00, 0x66, 0x7f, 0xfa, 0x7e, 0x65, 0xe9, + 0xac, 0x8b, 0x92, 0x34, 0x77, 0xb4, 0x23, 0xd0, + 0xb9, 0xab, 0xb1, 0x47, 0x7d, 0x4a, 0x13, 0x0a]; + + // Pick a somewhat large buffer so we can test filling with the + // remainder from `state.results`, directly filling the buffer, and + // filling the remainder of the buffer. + let mut buffer = [0u8; 16*4*2]; + // Consume a value so that we have a remainder. + assert!(rng.next_u64() == 0x04b4930a518251a4); + rng.fill_bytes(&mut buffer); + + // [u8; 128] doesn't implement PartialEq + assert_eq!(buffer.len(), expected.len()); + for (b, e) in buffer.iter().zip(expected.iter()) { + assert_eq!(b, e); + } + } + + #[test] + fn test_hc128_clone() { + let seed = [0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // key + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; // iv + let mut rng1 = Hc128Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } +} diff --git a/rand_hc/src/lib.rs b/rand_hc/src/lib.rs new file mode 100644 index 000000000..15ca34ebe --- /dev/null +++ b/rand_hc/src/lib.rs @@ -0,0 +1,25 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The HC128 random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/rand_hc/0.1.0")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![no_std] + +extern crate rand_core; + +mod hc128; + +pub use hc128::{Hc128Rng, Hc128Core}; diff --git a/rand_isaac/.cargo-checksum.json b/rand_isaac/.cargo-checksum.json new file mode 100644 index 000000000..4e89f82e6 --- /dev/null +++ b/rand_isaac/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"} \ No newline at end of file diff --git a/rand_isaac/CHANGELOG.md b/rand_isaac/CHANGELOG.md new file mode 100644 index 000000000..fb1ab3f3c --- /dev/null +++ b/rand_isaac/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2018-11-26 +- Fix `rand_core` version requirement +- Fix doc links + +## [0.1.0] - 2018-10-17 +- Pulled out of the Rand crate diff --git a/rand_isaac/COPYRIGHT b/rand_isaac/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_isaac/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_isaac/Cargo.toml b/rand_isaac/Cargo.toml new file mode 100644 index 000000000..79a541dec --- /dev/null +++ b/rand_isaac/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_isaac" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "ISAAC random number generator\n" +homepage = "https://crates.io/crates/rand_isaac" +documentation = "https://rust-random.github.io/rand/rand_isaac" +readme = "README.md" +keywords = ["random", "rng", "isaac"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.3" +default-features = false + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1" + +[features] +serde1 = ["serde", "serde_derive", "rand_core/serde1"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_isaac/LICENSE-APACHE b/rand_isaac/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_isaac/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_isaac/LICENSE-MIT b/rand_isaac/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_isaac/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_isaac/README.md b/rand_isaac/README.md new file mode 100644 index 000000000..02d123033 --- /dev/null +++ b/rand_isaac/README.md @@ -0,0 +1,47 @@ +# rand_isaac + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_isaac.svg)](https://crates.io/crates/rand_isaac) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_isaac) +[![API](https://docs.rs/rand_isaac/badge.svg)](https://docs.rs/rand_isaac) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements the ISAAC and ISAAC-64 random number generators. + +ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +the principal bitwise operations employed. It is the most advanced of a +series of array based random number generator designed by Robert Jenkins +in 1996[^1][^2]. + +ISAAC is notably fast and produces excellent quality random numbers for +non-cryptographic applications. + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_isaac) +- [API documentation (docs.rs)](https://docs.rs/rand_isaac) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand +[^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*](http://burtleburtle.net/bob/rand/isaacafa.html) +[^2]: Bob Jenkins, [*ISAAC and RC4*](http://burtleburtle.net/bob/rand/isaac.html) + + +## Crate Features + +`rand_isaac` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + + +# License + +`rand_isaac` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_isaac/src/isaac.rs b/rand_isaac/src/isaac.rs new file mode 100644 index 000000000..2bfdd9435 --- /dev/null +++ b/rand_isaac/src/isaac.rs @@ -0,0 +1,484 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w32 = w<u32>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses the ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1][^2]. +/// +/// ISAAC is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// In 2006 an improvement to ISAAC was suggested by Jean-Philippe Aumasson, +/// named ISAAC+[^3]. But because the specification is not complete, because +/// there is no good implementation, and because the suggested bias may not +/// exist, it is not implemented here. +/// +/// ## Overview of the ISAAC algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = a ^ a << 13 if i = 0 mod 4 +/// a ^ a >> 6 if i = 1 mod 4 +/// a ^ a << 2 if i = 2 mod 4 +/// a ^ a >> 16 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = f(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>2 mod 256] +/// s[i] = y +/// b = x + s[y>>10 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// Numbers are generated in blocks of 256. This means the function above only +/// runs once every 256 times you ask for a next random number. In all other +/// circumstances the last element of the results array is returned. +/// +/// ISAAC therefore needs a lot of memory, relative to other non-crypto RNGs. +/// 2 * 256 * 4 = 2 kb to hold the state and results. +/// +/// This implementation uses [`BlockRng`] to implement the [`RngCore`] methods. +/// +/// ## References +/// [^1]: Bob Jenkins, [*ISAAC: A fast cryptographic random number generator*]( +/// http://burtleburtle.net/bob/rand/isaacafa.html) +/// +/// [^2]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [^3]: Jean-Philippe Aumasson, [*On the pseudo-random generator ISAAC*]( +/// https://eprint.iacr.org/2006/438) +/// +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng`]: ../../rand_core/block/struct.BlockRng.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacRng(BlockRng<IsaacCore>); + +impl RngCore for IsaacRng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for IsaacRng { + type Seed = <IsaacCore as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + IsaacRng(BlockRng::<IsaacCore>::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng)) + } +} + +impl IsaacRng { + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `IsaacRng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacCore { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w32; RAND_SIZE], + a: w32, + b: w32, + c: w32, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for IsaacCore { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "IsaacCore {{}}") + } +} + +impl BlockRngCore for IsaacCore { + type Item = u32; + type Results = IsaacArray<Self::Item>; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`IsaacRng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`IsaacRng`]: struct.IsaacRng.html + fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w32; RAND_SIZE], v: w32, amount: usize) -> w32 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w32; RAND_SIZE], + results: &mut [u32; RAND_SIZE], + mix: w32, + a: &mut w32, + b: &mut w32, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 2); + mem[base + m] = y; + *b = x + ind(&mem, y, 2 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, a ^ (a << 13), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 6 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 2 ), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 16), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl IsaacCore { + /// Create a new ISAAC random number generator. + /// + /// The author Bob Jenkins describes how to best initialize ISAAC here: + /// <https://rt.cpan.org/Public/Bug/Display.html?id=64324> + /// The answer is included here just in case: + /// + /// "No, you don't need a full 8192 bits of seed data. Normal key sizes will + /// do fine, and they should have their expected strength (eg a 40-bit key + /// will take as much time to brute force as 40-bit keys usually will). You + /// could fill the remainder with 0, but set the last array element to the + /// length of the key provided (to distinguish keys that differ only by + /// different amounts of 0 padding). You do still need to call `randinit()` + /// to make sure the initial state isn't uniform-looking." + /// "After publishing ISAAC, I wanted to limit the key to half the size of + /// `r[]`, and repeat it twice. That would have made it hard to provide a + /// key that sets the whole internal state to anything convenient. But I'd + /// already published it." + /// + /// And his answer to the question "For my code, would repeating the key + /// over and over to fill 256 integers be a better solution than + /// zero-filling, or would they essentially be the same?": + /// "If the seed is under 32 bytes, they're essentially the same, otherwise + /// repeating the seed would be stronger. randinit() takes a chunk of 32 + /// bytes, mixes it, and combines that with the next 32 bytes, et cetera. + /// Then loops over all the elements the same way a second time." + #[inline] + fn init(mut mem: [w32; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w32, b: &mut w32, c: &mut w32, d: &mut w32, + e: &mut w32, f: &mut w32, g: &mut w32, h: &mut w32) { + *a ^= *b << 11; *d += *a; *b += *c; + *b ^= *c >> 2; *e += *b; *c += *d; + *c ^= *d << 8; *f += *c; *d += *e; + *d ^= *e >> 16; *g += *d; *e += *f; + *e ^= *f << 10; *h += *e; *f += *g; + *f ^= *g >> 4; *a += *f; *g += *h; + *g ^= *h << 8; *b += *g; *h += *a; + *h ^= *a >> 9; *c += *h; *a += *b; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b9) + // and applying mix() 4 times. + let mut a = w(0x1367df5a); + let mut b = w(0x95d90059); + let mut c = w(0xc3163e4b); + let mut d = w(0x0f421ad8); + let mut e = w(0xd92a4a78); + let mut f = w(0xa51a3c49); + let mut g = w(0xc4efea1b); + let mut h = w(0x30609119); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } +} + +impl SeedableRng for IsaacCore { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 8]; + le::read_u32_into(&seed, &mut seed_u32); + // Convert the seed to `Wrapping<u32>` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u32.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed as u32); + key[1] = w((seed >> 32) as u32); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u32); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 4); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use rand_core::{RngCore, SeedableRng}; + use super::IsaacRng; + + #[test] + fn test_isaac_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + assert_eq!(rng1.next_u32(), 2869442790); + + let mut rng2 = IsaacRng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u32(), 3094074039); + } + + #[test] + fn test_isaac_true_values_32() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut results = [0u32; 10]; + for i in results.iter_mut() { *i = rng1.next_u32(); } + let expected = [ + 2558573138, 873787463, 263499565, 2103644246, 3595684709, + 4203127393, 264982119, 2765226902, 2737944514, 3900253796]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 50,9,1,0, 49,212,0,0, 148,38,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng2 = IsaacRng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u32(); } + + for i in results.iter_mut() { *i = rng2.next_u32(); } + let expected = [ + 3676831399, 3183332890, 2834741178, 3854698763, 2717568474, + 1576568959, 3507990155, 179069555, 141456972, 2478885421]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_values_64() { + // As above, using little-endian versions of above values + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u64; 5]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected = [ + 3752888579798383186, 9035083239252078381,18052294697452424037, + 11876559110374379111, 16751462502657800130]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_true_bytes() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac_true_values as bytes in LE order + let expected = [82, 186, 128, 152, 71, 240, 20, 52, + 45, 175, 180, 15, 86, 16, 99, 125, + 101, 203, 81, 214, 97, 162, 134, 250, + 103, 78, 203, 15, 150, 3, 210, 164]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = IsaacRng::seed_from_u64(0); + let mut results = [0u32; 16]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 16] = [ + 0x71D71FD2, 0xB54ADAE7, 0xD4788559, 0xC36129FA, + 0x21DC1EA9, 0x3CB879CA, 0xD83B237F, 0xFA3CE5BD, + 0x8D048509, 0xD82E9489, 0xDB452848, 0xCA20E846, + 0x500F972E, 0x0EEFF940, 0x00D6B993, 0xBC12C17F]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac_clone() { + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = IsaacRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u32(), rng2.next_u32()); + } + } + + #[test] + #[cfg(feature="serde1")] + fn test_isaac_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = IsaacRng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: IsaacRng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u32(), deserialized.next_u32()); + } + } +} diff --git a/rand_isaac/src/isaac64.rs b/rand_isaac/src/isaac64.rs new file mode 100644 index 000000000..2712762ab --- /dev/null +++ b/rand_isaac/src/isaac64.rs @@ -0,0 +1,481 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC-64 random number generator. + +use core::{fmt, slice}; +use core::num::Wrapping as w; +use rand_core::{RngCore, SeedableRng, Error, le}; +use rand_core::block::{BlockRngCore, BlockRng64}; +use isaac_array::IsaacArray; + +#[allow(non_camel_case_types)] +type w64 = w<u64>; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + +/// A random number generator that uses ISAAC-64, the 64-bit variant of the +/// ISAAC algorithm. +/// +/// ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are +/// the principal bitwise operations employed. It is the most advanced of a +/// series of array based random number generator designed by Robert Jenkins +/// in 1996[^1]. +/// +/// ISAAC-64 is mostly similar to ISAAC. Because it operates on 64-bit integers +/// instead of 32-bit, it uses twice as much memory to hold its state and +/// results. Also it uses different constants for shifts and indirect indexing, +/// optimized to give good results for 64bit arithmetic. +/// +/// ISAAC-64 is notably fast and produces excellent quality random numbers for +/// non-cryptographic applications. +/// +/// In spite of being designed with cryptographic security in mind, ISAAC hasn't +/// been stringently cryptanalyzed and thus cryptographers do not not +/// consensually trust it to be secure. When looking for a secure RNG, prefer +/// [`Hc128Rng`] instead, which, like ISAAC, is an array-based RNG and one of +/// the stream-ciphers selected the by eSTREAM contest. +/// +/// ## Overview of the ISAAC-64 algorithm: +/// (in pseudo-code) +/// +/// ```text +/// Input: a, b, c, s[256] // state +/// Output: r[256] // results +/// +/// mix(a,i) = !(a ^ a << 21) if i = 0 mod 4 +/// a ^ a >> 5 if i = 1 mod 4 +/// a ^ a << 12 if i = 2 mod 4 +/// a ^ a >> 33 if i = 3 mod 4 +/// +/// c = c + 1 +/// b = b + c +/// +/// for i in 0..256 { +/// x = s_[i] +/// a = mix(a,i) + s[i+128 mod 256] +/// y = a + b + s[x>>3 mod 256] +/// s[i] = y +/// b = x + s[y>>11 mod 256] +/// r[i] = b +/// } +/// ``` +/// +/// This implementation uses [`BlockRng64`] to implement the [`RngCore`] methods. +/// +/// See for more information the documentation of [`IsaacRng`]. +/// +/// [^1]: Bob Jenkins, [*ISAAC and RC4*]( +/// http://burtleburtle.net/bob/rand/isaac.html) +/// +/// [`IsaacRng`]: ../isaac/struct.IsaacRng.html +/// [`Hc128Rng`]: ../../rand_hc/struct.Hc128Rng.html +/// [`BlockRng64`]: ../../rand_core/block/struct.BlockRng64.html +/// [`RngCore`]: ../../rand_core/trait.RngCore.html +#[derive(Clone, Debug)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Rng(BlockRng64<Isaac64Core>); + +impl RngCore for Isaac64Rng { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.0.fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.0.try_fill_bytes(dest) + } +} + +impl SeedableRng for Isaac64Rng { + type Seed = <Isaac64Core as SeedableRng>::Seed; + + fn from_seed(seed: Self::Seed) -> Self { + Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed)) + } + + /// Create an ISAAC random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + fn seed_from_u64(seed: u64) -> Self { + Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed)) + } + + fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> { + BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng)) + } +} + +impl Isaac64Rng { + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +/// The core of `Isaac64Rng`, used with `BlockRng`. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct Isaac64Core { + #[cfg_attr(feature="serde1",serde(with="super::isaac_array::isaac_array_serde"))] + mem: [w64; RAND_SIZE], + a: w64, + b: w64, + c: w64, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Isaac64Core { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Isaac64Core {{}}") + } +} + +impl BlockRngCore for Isaac64Core { + type Item = u64; + type Results = IsaacArray<Self::Item>; + + /// Refills the output buffer, `results`. See also the pseudocode desciption + /// of the algorithm in the [`Isaac64Rng`] documentation. + /// + /// Optimisations used (similar to the reference implementation): + /// + /// - The loop is unrolled 4 times, once for every constant of mix(). + /// - The contents of the main loop are moved to a function `rngstep`, to + /// reduce code duplication. + /// - We use local variables for a and b, which helps with optimisations. + /// - We split the main loop in two, one that operates over 0..128 and one + /// over 128..256. This way we can optimise out the addition and modulus + /// from `s[i+128 mod 256]`. + /// - We maintain one index `i` and add `m` or `m2` as base (m2 for the + /// `s[i+128 mod 256]`), relying on the optimizer to turn it into pointer + /// arithmetic. + /// - We fill `results` backwards. The reference implementation reads values + /// from `results` in reverse. We read them in the normal direction, to + /// make `fill_bytes` a memcopy. To maintain compatibility we fill in + /// reverse. + /// + /// [`Isaac64Rng`]: struct.Isaac64Rng.html + fn generate(&mut self, results: &mut IsaacArray<Self::Item>) { + self.c += w(1); + // abbreviations + let mut a = self.a; + let mut b = self.b + self.c; + const MIDPOINT: usize = RAND_SIZE / 2; + + #[inline] + fn ind(mem:&[w64; RAND_SIZE], v: w64, amount: usize) -> w64 { + let index = (v >> amount).0 as usize % RAND_SIZE; + mem[index] + } + + #[inline] + fn rngstep(mem: &mut [w64; RAND_SIZE], + results: &mut [u64; RAND_SIZE], + mix: w64, + a: &mut w64, + b: &mut w64, + base: usize, + m: usize, + m2: usize) { + let x = mem[base + m]; + *a = mix + mem[base + m2]; + let y = *a + *b + ind(&mem, x, 3); + mem[base + m] = y; + *b = x + ind(&mem, y, 3 + RAND_SIZE_LEN); + results[RAND_SIZE - 1 - base - m] = (*b).0; + } + + let mut m = 0; + let mut m2 = MIDPOINT; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + m = MIDPOINT; + m2 = 0; + for i in (0..MIDPOINT/4).map(|i| i * 4) { + rngstep(&mut self.mem, results, !(a ^ (a << 21)), &mut a, &mut b, i + 0, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 5 ), &mut a, &mut b, i + 1, m, m2); + rngstep(&mut self.mem, results, a ^ (a << 12), &mut a, &mut b, i + 2, m, m2); + rngstep(&mut self.mem, results, a ^ (a >> 33), &mut a, &mut b, i + 3, m, m2); + } + + self.a = a; + self.b = b; + } +} + +impl Isaac64Core { + /// Create a new ISAAC-64 random number generator. + fn init(mut mem: [w64; RAND_SIZE], rounds: u32) -> Self { + fn mix(a: &mut w64, b: &mut w64, c: &mut w64, d: &mut w64, + e: &mut w64, f: &mut w64, g: &mut w64, h: &mut w64) { + *a -= *e; *f ^= *h >> 9; *h += *a; + *b -= *f; *g ^= *a << 9; *a += *b; + *c -= *g; *h ^= *b >> 23; *b += *c; + *d -= *h; *a ^= *c << 15; *c += *d; + *e -= *a; *b ^= *d >> 14; *d += *e; + *f -= *b; *c ^= *e << 20; *e += *f; + *g -= *c; *d ^= *f >> 17; *f += *g; + *h -= *d; *e ^= *g << 14; *g += *h; + } + + // These numbers are the result of initializing a...h with the + // fractional part of the golden ratio in binary (0x9e3779b97f4a7c13) + // and applying mix() 4 times. + let mut a = w(0x647c4677a2884b7c); + let mut b = w(0xb9f8b322c73ac862); + let mut c = w(0x8c0ea5053d4712a0); + let mut d = w(0xb29b2e824a595524); + let mut e = w(0x82f053db8355e0ce); + let mut f = w(0x48fe4a0fa5a09315); + let mut g = w(0xae985bf2cbfc89ed); + let mut h = w(0x98f5704f6c44c0ab); + + // Normally this should do two passes, to make all of the seed effect + // all of `mem` + for _ in 0..rounds { + for i in (0..RAND_SIZE/8).map(|i| i * 8) { + a += mem[i ]; b += mem[i+1]; + c += mem[i+2]; d += mem[i+3]; + e += mem[i+4]; f += mem[i+5]; + g += mem[i+6]; h += mem[i+7]; + mix(&mut a, &mut b, &mut c, &mut d, + &mut e, &mut f, &mut g, &mut h); + mem[i ] = a; mem[i+1] = b; + mem[i+2] = c; mem[i+3] = d; + mem[i+4] = e; mem[i+5] = f; + mem[i+6] = g; mem[i+7] = h; + } + } + + Self { mem, a: w(0), b: w(0), c: w(0) } + } + + /// Create an ISAAC-64 random number generator using an `u64` as seed. + /// If `seed == 0` this will produce the same stream of random numbers as + /// the reference implementation when used unseeded. + #[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")] + pub fn new_from_u64(seed: u64) -> Self { + Self::seed_from_u64(seed) + } +} + +impl SeedableRng for Isaac64Core { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 4]; + le::read_u64_into(&seed, &mut seed_u64); + // Convert the seed to `Wrapping<u64>` and zero-extend to `RAND_SIZE`. + let mut seed_extended = [w(0); RAND_SIZE]; + for (x, y) in seed_extended.iter_mut().zip(seed_u64.iter()) { + *x = w(*y); + } + Self::init(seed_extended, 2) + } + + fn seed_from_u64(seed: u64) -> Self { + let mut key = [w(0); RAND_SIZE]; + key[0] = w(seed); + // Initialize with only one pass. + // A second pass does not improve the quality here, because all of the + // seed was already available in the first round. + // Not doing the second pass has the small advantage that if + // `seed == 0` this method produces exactly the same state as the + // reference implementation when used unseeded. + Self::init(key, 1) + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + // Custom `from_rng` implementation that fills a seed with the same size + // as the entire state. + let mut seed = [w(0u64); RAND_SIZE]; + unsafe { + let ptr = seed.as_mut_ptr() as *mut u8; + let slice = slice::from_raw_parts_mut(ptr, RAND_SIZE * 8); + rng.try_fill_bytes(slice)?; + } + for i in seed.iter_mut() { + *i = w(i.0.to_le()); + } + + Ok(Self::init(seed, 2)) + } +} + +#[cfg(test)] +mod test { + use rand_core::{RngCore, SeedableRng}; + use super::Isaac64Rng; + + #[test] + fn test_isaac64_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + assert_eq!(rng1.next_u64(), 14964555543728284049); + + let mut rng2 = Isaac64Rng::from_rng(rng1).unwrap(); + assert_eq!(rng2.next_u64(), 919595328260451758); + } + + #[test] + fn test_isaac64_true_values_64() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut results = [0u64; 10]; + for i in results.iter_mut() { *i = rng1.next_u64(); } + let expected = [ + 15071495833797886820, 7720185633435529318, + 10836773366498097981, 5414053799617603544, + 12890513357046278984, 17001051845652595546, + 9240803642279356310, 12558996012687158051, + 14673053937227185542, 1677046725350116783]; + assert_eq!(results, expected); + + let seed = [57,48,0,0, 0,0,0,0, 50,9,1,0, 0,0,0,0, + 49,212,0,0, 0,0,0,0, 148,38,0,0, 0,0,0,0]; + let mut rng2 = Isaac64Rng::from_seed(seed); + // skip forward to the 10000th number + for _ in 0..10000 { rng2.next_u64(); } + + for i in results.iter_mut() { *i = rng2.next_u64(); } + let expected = [ + 18143823860592706164, 8491801882678285927, 2699425367717515619, + 17196852593171130876, 2606123525235546165, 15790932315217671084, + 596345674630742204, 9947027391921273664, 11788097613744130851, + 10391409374914919106]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_32() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u32; 12]; + for i in results.iter_mut() { *i = rng.next_u32(); } + // Subset of above values, as an LE u32 sequence + let expected = [ + 3477963620, 3509106075, + 687845478, 1797495790, + 227048253, 2523132918, + 4044335064, 1260557630, + 4079741768, 3001306521, + 69157722, 3958365844]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_true_values_mixed() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + // Test alternating between `next_u64` and `next_u32` works as expected. + // Values are the same as `test_isaac64_true_values` and + // `test_isaac64_true_values_32`. + assert_eq!(rng.next_u64(), 15071495833797886820); + assert_eq!(rng.next_u32(), 687845478); + assert_eq!(rng.next_u32(), 1797495790); + assert_eq!(rng.next_u64(), 10836773366498097981); + assert_eq!(rng.next_u32(), 4044335064); + // Skip one u32 + assert_eq!(rng.next_u64(), 12890513357046278984); + assert_eq!(rng.next_u32(), 69157722); + } + + #[test] + fn test_isaac64_true_bytes() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + // Same as first values in test_isaac64_true_values as bytes in LE order + let expected = [100, 131, 77, 207, 155, 181, 40, 209, + 102, 176, 255, 40, 238, 155, 35, 107, + 61, 123, 136, 13, 246, 243, 99, 150, + 216, 167, 15, 241, 62, 149, 34, 75]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_new_uninitialized() { + // Compare the results from initializing `IsaacRng` with + // `seed_from_u64(0)`, to make sure it is the same as the reference + // implementation when used uninitialized. + // Note: We only test the first 16 integers, not the full 256 of the + // first block. + let mut rng = Isaac64Rng::seed_from_u64(0); + let mut results = [0u64; 16]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 16] = [ + 0xF67DFBA498E4937C, 0x84A5066A9204F380, 0xFEE34BD5F5514DBB, + 0x4D1664739B8F80D6, 0x8607459AB52A14AA, 0x0E78BC5A98529E49, + 0xFE5332822AD13777, 0x556C27525E33D01A, 0x08643CA615F3149F, + 0xD0771FAF3CB04714, 0x30E86F68A37B008D, 0x3074EBC0488A3ADF, + 0x270645EA7A2790BC, 0x5601A0A8D3763C6A, 0x2F83071F53F325DD, + 0xB9090F3D42D2D2EA]; + assert_eq!(results, expected); + } + + #[test] + fn test_isaac64_clone() { + let seed = [1,0,0,0, 0,0,0,0, 23,0,0,0, 0,0,0,0, + 200,1,0,0, 0,0,0,0, 210,30,0,0, 0,0,0,0]; + let mut rng1 = Isaac64Rng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } + } + + #[test] + #[cfg(feature="serde1")] + fn test_isaac64_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0, + 57,48,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = Isaac64Rng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Isaac64Rng = bincode::deserialize_from(&mut read).expect("Could not deserialize"); + + for _ in 0..300 { // more than the 256 buffered results + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } + } +} diff --git a/rand_isaac/src/isaac_array.rs b/rand_isaac/src/isaac_array.rs new file mode 100644 index 000000000..0fa614707 --- /dev/null +++ b/rand_isaac/src/isaac_array.rs @@ -0,0 +1,136 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017-2018 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! ISAAC helper functions for 256-element arrays. + +// Terrible workaround because arrays with more than 32 elements do not +// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other +// traits for that matter. + +#[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; + +const RAND_SIZE_LEN: usize = 8; +const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + +#[derive(Copy, Clone)] +#[allow(missing_debug_implementations)] +#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))] +pub struct IsaacArray<T> { + #[cfg_attr(feature="serde1",serde(with="isaac_array_serde"))] + #[cfg_attr(feature="serde1", serde(bound( + serialize = "T: Serialize", + deserialize = "T: Deserialize<'de> + Copy + Default")))] + inner: [T; RAND_SIZE] +} + +impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> { + #[inline(always)] + fn as_ref(&self) -> &[T] { + &self.inner[..] + } +} + +impl<T> ::core::convert::AsMut<[T]> for IsaacArray<T> { + #[inline(always)] + fn as_mut(&mut self) -> &mut [T] { + &mut self.inner[..] + } +} + +impl<T> ::core::ops::Deref for IsaacArray<T> { + type Target = [T; RAND_SIZE]; + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<T> ::core::ops::DerefMut for IsaacArray<T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] { + &mut self.inner + } +} + +impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default { + fn default() -> IsaacArray<T> { + IsaacArray { inner: [T::default(); RAND_SIZE] } + } +} + + +#[cfg(feature="serde1")] +pub(super) mod isaac_array_serde { + const RAND_SIZE_LEN: usize = 8; + const RAND_SIZE: usize = 1 << RAND_SIZE_LEN; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde::de::{Visitor,SeqAccess}; + use serde::de; + + use core::fmt; + + pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error> + where + T: Serialize, + S: Serializer + { + use serde::ser::SerializeTuple; + + let mut seq = ser.serialize_tuple(RAND_SIZE)?; + + for e in arr.iter() { + seq.serialize_element(&e)?; + } + + seq.end() + } + + #[inline] + pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error> + where + T: Deserialize<'de>+Default+Copy, + D: Deserializer<'de>, + { + use core::marker::PhantomData; + struct ArrayVisitor<T> { + _pd: PhantomData<T>, + }; + impl<'de,T> Visitor<'de> for ArrayVisitor<T> + where + T: Deserialize<'de>+Default+Copy + { + type Value = [T; RAND_SIZE]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Isaac state array") + } + + #[inline] + fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error> + where + A: SeqAccess<'de>, + { + let mut out = [Default::default();RAND_SIZE]; + + for i in 0..RAND_SIZE { + match seq.next_element()? { + Some(val) => out[i] = val, + None => return Err(de::Error::invalid_length(i, &self)), + }; + } + + Ok(out) + } + } + + de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData}) + } +} diff --git a/rand_isaac/src/lib.rs b/rand_isaac/src/lib.rs new file mode 100644 index 000000000..ec82d8e7b --- /dev/null +++ b/rand_isaac/src/lib.rs @@ -0,0 +1,36 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The ISAAC and ISAAC-64 random number generators. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(not(all(feature="serde1", test)), no_std)] + +extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +// To test serialization we need bincode and the standard library +#[cfg(all(feature="serde1", test))] extern crate bincode; +#[cfg(all(feature="serde1", test))] extern crate std as core; + +pub mod isaac; +pub mod isaac64; + +mod isaac_array; + +pub use self::isaac::IsaacRng; +pub use self::isaac64::Isaac64Rng; diff --git a/rand_jitter/.cargo-checksum.json b/rand_jitter/.cargo-checksum.json new file mode 100644 index 000000000..93d00bd1f --- /dev/null +++ b/rand_jitter/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"} \ No newline at end of file diff --git a/rand_jitter/CHANGELOG.md b/rand_jitter/CHANGELOG.md new file mode 100644 index 000000000..bbb21dcbf --- /dev/null +++ b/rand_jitter/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.4] - 2019-05-02 +- Change error conversion code to partially fix #738 + +## [0.1.3] - 2019-02-05 +- Use libc in `no_std` mode to fix #723 + +## [0.1.2] - 2019-01-31 +- Fix for older rustc compilers on Windows (#722) + +## [0.1.1] - 2019-01-29 +- Fix for older rustc compilers on Mac OSX / iOS (#720) +- Misc. doc fixes + +## [0.1.0] - 2019-01-24 +Initial release. diff --git a/rand_jitter/COPYRIGHT b/rand_jitter/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_jitter/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_jitter/Cargo.toml b/rand_jitter/Cargo.toml new file mode 100644 index 000000000..387b8073f --- /dev/null +++ b/rand_jitter/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_jitter" +version = "0.1.4" +authors = ["The Rand Project Developers"] +description = "Random number generator based on timing jitter" +documentation = "https://docs.rs/rand_jitter" +readme = "README.md" +keywords = ["random", "rng", "os"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.rand_core] +version = "0.4" + +[features] +std = ["rand_core/std"] +[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.libc] +version = "0.2" +default_features = false +[target."cfg(target_os = \"windows\")".dependencies.winapi] +version = "0.3" +features = ["profileapi"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_jitter/LICENSE-APACHE b/rand_jitter/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_jitter/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_jitter/LICENSE-MIT b/rand_jitter/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_jitter/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_jitter/README.md b/rand_jitter/README.md new file mode 100644 index 000000000..8e0805fae --- /dev/null +++ b/rand_jitter/README.md @@ -0,0 +1,104 @@ +# rand_jitter +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_jitter.svg)](https://crates.io/crates/rand_jitter) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_jitter) +[![API](https://docs.rs/rand_jitter/badge.svg)](https://docs.rs/rand_jitter) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Non-physical true random number generator based on timing jitter. + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +This crate aims to support all of Rust's `std` platforms with a system-provided +entropy source. Unlike other Rand crates, this crate does not support `no_std` +(handling this gracefully is a current discussion topic). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_jitter) +- [API documentation (docs.rs)](https://docs.rs/rand_jitter) +- [Changelog](CHANGELOG.md) + +## Features + +This crate has optional `std` support which is *disabled by default*; +this feature is required to provide the `JitterRng::new` function; +without `std` support a timer must be supplied via `JitterRng::new_with_timer`. + +## Quality testing + +`JitterRng::new()` has build-in, but limited, quality testing, however +before using `JitterRng` on untested hardware, or after changes that could +effect how the code is optimized (such as a new LLVM version), it is +recommend to run the much more stringent +[NIST SP 800-90B Entropy Estimation Suite](https://github.com/usnistgov/SP800-90B_EntropyAssessment). + +Use the following code using `timer_stats` to collect the data: + +```rust +use rand_jitter::JitterRng; + +use std::error::Error; +use std::fs::File; +use std::io::Write; + +fn main() -> Result<(), Box<Error>> { + let mut rng = JitterRng::new()?; + + // 1_000_000 results are required for the + // NIST SP 800-90B Entropy Estimation Suite + const ROUNDS: usize = 1_000_000; + let mut deltas_variable: Vec<u8> = Vec::with_capacity(ROUNDS); + let mut deltas_minimal: Vec<u8> = Vec::with_capacity(ROUNDS); + + for _ in 0..ROUNDS { + deltas_variable.push(rng.timer_stats(true) as u8); + deltas_minimal.push(rng.timer_stats(false) as u8); + } + + // Write out after the statistics collection loop, to not disturb the + // test results. + File::create("jitter_rng_var.bin")?.write(&deltas_variable)?; + File::create("jitter_rng_min.bin")?.write(&deltas_minimal)?; + Ok(()) +} +``` + +This will produce two files: `jitter_rng_var.bin` and `jitter_rng_min.bin`. +Run the Entropy Estimation Suite in three configurations, as outlined below. +Every run has two steps. One step to produce an estimation, another to +validate the estimation. + +1. Estimate the expected amount of entropy that is at least available with + each round of the entropy collector. This number should be greater than + the amount estimated with `64 / test_timer()`. + ```sh + python noniid_main.py -v jitter_rng_var.bin 8 + restart.py -v jitter_rng_var.bin 8 <min-entropy> + ``` +2. Estimate the expected amount of entropy that is available in the last 4 + bits of the timer delta after running noice sources. Note that a value of + `3.70` is the minimum estimated entropy for true randomness. + ```sh + python noniid_main.py -v -u 4 jitter_rng_var.bin 4 + restart.py -v -u 4 jitter_rng_var.bin 4 <min-entropy> + ``` +3. Estimate the expected amount of entropy that is available to the entropy + collector if both noise sources only run their minimal number of times. + This measures the absolute worst-case, and gives a lower bound for the + available entropy. + ```sh + python noniid_main.py -v -u 4 jitter_rng_min.bin 4 + restart.py -v -u 4 jitter_rng_min.bin 4 <min-entropy> + ``` + +## License + +`rand_jitter` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_jitter/benches/mod.rs b/rand_jitter/benches/mod.rs new file mode 100644 index 000000000..23b34472b --- /dev/null +++ b/rand_jitter/benches/mod.rs @@ -0,0 +1,18 @@ +#![feature(test)] +extern crate test; +extern crate rand_jitter; + +use test::Bencher; +use rand_jitter::rand_core::RngCore; + +#[bench] +fn bench_add_two(b: &mut Bencher) { + let mut rng = rand_jitter::JitterRng::new().unwrap(); + let mut buf = [0u8; 1024]; + b.iter(|| { + rng.fill_bytes(&mut buf[..]); + test::black_box(&buf); + }); + b.bytes = buf.len() as u64; +} + diff --git a/rand_jitter/src/dummy_log.rs b/rand_jitter/src/dummy_log.rs new file mode 100644 index 000000000..ccfe4baef --- /dev/null +++ b/rand_jitter/src/dummy_log.rs @@ -0,0 +1,10 @@ +#[allow(unused)] +macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! error { ($($x:tt)*) => () } diff --git a/rand_jitter/src/error.rs b/rand_jitter/src/error.rs new file mode 100644 index 000000000..a3483e84d --- /dev/null +++ b/rand_jitter/src/error.rs @@ -0,0 +1,70 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rand_core::{Error, ErrorKind}; +use core::fmt; + +/// An error that can occur when [`JitterRng::test_timer`] fails. +/// +/// [`JitterRng::test_timer`]: crate::JitterRng::test_timer +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TimerError { + /// No timer available. + NoTimer, + /// Timer too coarse to use as an entropy source. + CoarseTimer, + /// Timer is not monotonically increasing. + NotMonotonic, + /// Variations of deltas of time too small. + TinyVariantions, + /// Too many stuck results (indicating no added entropy). + TooManyStuck, + #[doc(hidden)] + __Nonexhaustive, +} + +impl TimerError { + fn description(&self) -> &'static str { + match *self { + TimerError::NoTimer => "no timer available", + TimerError::CoarseTimer => "coarse timer", + TimerError::NotMonotonic => "timer not monotonic", + TimerError::TinyVariantions => "time delta variations too small", + TimerError::TooManyStuck => "too many stuck results", + TimerError::__Nonexhaustive => unreachable!(), + } + } +} + +impl fmt::Display for TimerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +#[cfg(feature = "std")] +impl ::std::error::Error for TimerError { + fn description(&self) -> &str { + self.description() + } +} + +impl From<TimerError> for Error { + fn from(err: TimerError) -> Error { + // Timer check is already quite permissive of failures so we don't + // expect false-positive failures, i.e. any error is irrecoverable. + #[cfg(feature = "std")] { + Error::with_cause(ErrorKind::Unavailable, "timer jitter failed basic quality tests", err) + } + #[cfg(not(feature = "std"))] { + Error::new(ErrorKind::Unavailable, "timer jitter failed basic quality tests") + } + } +} + diff --git a/rand_jitter/src/lib.rs b/rand_jitter/src/lib.rs new file mode 100644 index 000000000..338a6b966 --- /dev/null +++ b/rand_jitter/src/lib.rs @@ -0,0 +1,718 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Based on jitterentropy-library, http://www.chronox.de/jent.html. +// Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017. +// +// With permission from Stephan Mueller to relicense the Rust translation under +// the MIT license. + +//! Non-physical true random number generator based on timing jitter. +//! +//! This is a true random number generator, as opposed to pseudo-random +//! generators. Random numbers generated by `JitterRng` can be seen as fresh +//! entropy. A consequence is that it is orders of magnitude slower than `OsRng` +//! and PRNGs (about 10<sup>3</sup>..10<sup>6</sup> slower). +//! +//! There are very few situations where using this RNG is appropriate. Only very +//! few applications require true entropy. A normal PRNG can be statistically +//! indistinguishable, and a cryptographic PRNG should also be as impossible to +//! predict. +//! +//! Use of `JitterRng` is recommended for initializing cryptographic PRNGs when +//! `OsRng` is not available. +//! +//! `JitterRng` can be used without the standard library, but not conveniently, +//! you must provide a high-precision timer and carefully have to follow the +//! instructions of [`JitterRng::new_with_timer`]. +//! +//! This implementation is based on [Jitterentropy] version 2.1.0. +//! +//! Note: There is no accurate timer available on WASM platforms, to help +//! prevent fingerprinting or timing side-channel attacks. Therefore +//! [`JitterRng::new()`] is not available on WASM. It is also unavailable +//! with disabled `std` feature. +//! +//! [Jitterentropy]: http://www.chronox.de/jent.html + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +// Note: the C implementation of `Jitterentropy` relies on being compiled +// without optimizations. This implementation goes through lengths to make the +// compiler not optimize out code which does influence timing jitter, but is +// technically dead code. +#![no_std] +pub extern crate rand_core; +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "log")] +#[macro_use] extern crate log; +#[cfg(any(target_os = "macos", target_os = "ios"))] +extern crate libc; +#[cfg(target_os = "windows")] +extern crate winapi; + + +#[cfg(not(feature = "log"))] +#[macro_use] mod dummy_log; +#[cfg(feature = "std")] +mod platform; +mod error; + +use rand_core::{RngCore, CryptoRng, Error, impls}; +pub use error::TimerError; + +use core::{fmt, mem, ptr}; +#[cfg(feature = "std")] +use std::sync::atomic::{AtomicUsize, Ordering}; +#[cfg(feature = "std")] +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_USIZE_INIT; + +const MEMORY_BLOCKS: usize = 64; +const MEMORY_BLOCKSIZE: usize = 32; +const MEMORY_SIZE: usize = MEMORY_BLOCKS * MEMORY_BLOCKSIZE; + +/// A true random number generator based on jitter in the CPU execution time, +/// and jitter in memory access time. +pub struct JitterRng { + data: u64, // Actual random number + // Number of rounds to run the entropy collector per 64 bits + rounds: u8, + // Timer used by `measure_jitter` + timer: fn() -> u64, + // Memory for the Memory Access noise source + mem_prev_index: u16, + // Make `next_u32` not waste 32 bits + data_half_used: bool, +} + +// Note: `JitterRng` maintains a small 64-bit entropy pool. With every +// `generate` 64 new bits should be integrated in the pool. If a round of +// `generate` were to collect less than the expected 64 bit, then the returned +// value, and the new state of the entropy pool, would be in some way related to +// the initial state. It is therefore better if the initial state of the entropy +// pool is different on each call to `generate`. This has a few implications: +// - `generate` should be called once before using `JitterRng` to produce the +// first usable value (this is done by default in `new`); +// - We do not zero the entropy pool after generating a result. The reference +// implementation also does not support zeroing, but recommends generating a +// new value without using it if you want to protect a previously generated +// 'secret' value from someone inspecting the memory; +// - Implementing `Clone` seems acceptable, as it would not cause the systematic +// bias a constant might cause. Only instead of one value that could be +// potentially related to the same initial state, there are now two. + +// Entropy collector state. +// These values are not necessary to preserve across runs. +struct EcState { + // Previous time stamp to determine the timer delta + prev_time: u64, + // Deltas used for the stuck test + last_delta: i32, + last_delta2: i32, + // Memory for the Memory Access noise source + mem: [u8; MEMORY_SIZE], +} + +impl EcState { + // Stuck test by checking the: + // - 1st derivation of the jitter measurement (time delta) + // - 2nd derivation of the jitter measurement (delta of time deltas) + // - 3rd derivation of the jitter measurement (delta of delta of time + // deltas) + // + // All values must always be non-zero. + // This test is a heuristic to see whether the last measurement holds + // entropy. + fn stuck(&mut self, current_delta: i32) -> bool { + let delta2 = self.last_delta - current_delta; + let delta3 = delta2 - self.last_delta2; + + self.last_delta = current_delta; + self.last_delta2 = delta2; + + current_delta == 0 || delta2 == 0 || delta3 == 0 + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for JitterRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "JitterRng {{}}") + } +} + +impl Clone for JitterRng { + fn clone(&self) -> JitterRng { + JitterRng { + data: self.data, + rounds: self.rounds, + timer: self.timer, + mem_prev_index: self.mem_prev_index, + // The 32 bits that may still be unused from the previous round are + // for the original to use, not for the clone. + data_half_used: false, + } + } +} + +// Initialise to zero; must be positive +#[cfg(all(feature = "std", not(target_arch = "wasm32")))] +#[allow(deprecated)] +static JITTER_ROUNDS: AtomicUsize = ATOMIC_USIZE_INIT; + +impl JitterRng { + /// Create a new `JitterRng`. Makes use of `std::time` for a timer, or a + /// platform-specific function with higher accuracy if necessary and + /// available. + /// + /// During initialization CPU execution timing jitter is measured a few + /// hundred times. If this does not pass basic quality tests, an error is + /// returned. The test result is cached to make subsequent calls faster. + #[cfg(all(feature = "std", not(target_arch = "wasm32")))] + pub fn new() -> Result<JitterRng, TimerError> { + if cfg!(target_arch = "wasm32") { + return Err(TimerError::NoTimer); + } + let mut state = JitterRng::new_with_timer(platform::get_nstime); + let mut rounds = JITTER_ROUNDS.load(Ordering::Relaxed) as u8; + if rounds == 0 { + // No result yet: run test. + // This allows the timer test to run multiple times; we don't care. + rounds = state.test_timer()?; + JITTER_ROUNDS.store(rounds as usize, Ordering::Relaxed); + info!("JitterRng: using {} rounds per u64 output", rounds); + } + state.set_rounds(rounds); + + // Fill `data` with a non-zero value. + state.gen_entropy(); + Ok(state) + } + + /// Create a new `JitterRng`. + /// A custom timer can be supplied, making it possible to use `JitterRng` in + /// `no_std` environments. + /// + /// The timer must have nanosecond precision. + /// + /// This method is more low-level than `new()`. It is the responsibility of + /// the caller to run [`test_timer`] before using any numbers generated with + /// `JitterRng`, and optionally call [`set_rounds`]. Also it is important to + /// consume at least one `u64` before using the first result to initialize + /// the entropy collection pool. + /// + /// # Example + /// + /// ``` + /// # use rand_jitter::rand_core::{RngCore, Error}; + /// use rand_jitter::JitterRng; + /// + /// # fn try_inner() -> Result<(), Error> { + /// fn get_nstime() -> u64 { + /// use std::time::{SystemTime, UNIX_EPOCH}; + /// + /// let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + /// // The correct way to calculate the current time is + /// // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + /// // But this is faster, and the difference in terms of entropy is + /// // negligible (log2(10^9) == 29.9). + /// dur.as_secs() << 30 | dur.subsec_nanos() as u64 + /// } + /// + /// let mut rng = JitterRng::new_with_timer(get_nstime); + /// let rounds = rng.test_timer()?; + /// rng.set_rounds(rounds); // optional + /// let _ = rng.next_u64(); + /// + /// // Ready for use + /// let v: u64 = rng.next_u64(); + /// # Ok(()) + /// # } + /// + /// # let _ = try_inner(); + /// ``` + /// + /// [`test_timer`]: JitterRng::test_timer + /// [`set_rounds`]: JitterRng::set_rounds + pub fn new_with_timer(timer: fn() -> u64) -> JitterRng { + JitterRng { + data: 0, + rounds: 64, + timer, + mem_prev_index: 0, + data_half_used: false, + } + } + + /// Configures how many rounds are used to generate each 64-bit value. + /// This must be greater than zero, and has a big impact on performance + /// and output quality. + /// + /// [`new_with_timer`] conservatively uses 64 rounds, but often less rounds + /// can be used. The `test_timer()` function returns the minimum number of + /// rounds required for full strength (platform dependent), so one may use + /// `rng.set_rounds(rng.test_timer()?);` or cache the value. + /// + /// [`new_with_timer`]: JitterRng::new_with_timer + pub fn set_rounds(&mut self, rounds: u8) { + assert!(rounds > 0); + self.rounds = rounds; + } + + // Calculate a random loop count used for the next round of an entropy + // collection, based on bits from a fresh value from the timer. + // + // The timer is folded to produce a number that contains at most `n_bits` + // bits. + // + // Note: A constant should be added to the resulting random loop count to + // prevent loops that run 0 times. + #[inline(never)] + fn random_loop_cnt(&mut self, n_bits: u32) -> u32 { + let mut rounds = 0; + + let mut time = (self.timer)(); + // Mix with the current state of the random number balance the random + // loop counter a bit more. + time ^= self.data; + + // We fold the time value as much as possible to ensure that as many + // bits of the time stamp are included as possible. + let folds = (64 + n_bits - 1) / n_bits; + let mask = (1 << n_bits) - 1; + for _ in 0..folds { + rounds ^= time & mask; + time >>= n_bits; + } + + rounds as u32 + } + + // CPU jitter noise source + // Noise source based on the CPU execution time jitter + // + // This function injects the individual bits of the time value into the + // entropy pool using an LFSR. + // + // The code is deliberately inefficient with respect to the bit shifting. + // This function not only acts as folding operation, but this function's + // execution is used to measure the CPU execution time jitter. Any change to + // the loop in this function implies that careful retesting must be done. + #[inline(never)] + fn lfsr_time(&mut self, time: u64, var_rounds: bool) { + fn lfsr(mut data: u64, time: u64) -> u64{ + for i in 1..65 { + let mut tmp = time << (64 - i); + tmp >>= 64 - 1; + + // Fibonacci LSFR with polynomial of + // x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is + // primitive according to + // http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf + // (the shift values are the polynomial values minus one + // due to counting bits from 0 to 63). As the current + // position is always the LSB, the polynomial only needs + // to shift data in from the left without wrap. + data ^= tmp; + data ^= (data >> 63) & 1; + data ^= (data >> 60) & 1; + data ^= (data >> 55) & 1; + data ^= (data >> 30) & 1; + data ^= (data >> 27) & 1; + data ^= (data >> 22) & 1; + data = data.rotate_left(1); + } + data + } + + // Note: in the reference implementation only the last round effects + // `self.data`, all the other results are ignored. To make sure the + // other rounds are not optimised out, we first run all but the last + // round on a throw-away value instead of the real `self.data`. + let mut lfsr_loop_cnt = 0; + if var_rounds { lfsr_loop_cnt = self.random_loop_cnt(4) }; + + let mut throw_away: u64 = 0; + for _ in 0..lfsr_loop_cnt { + throw_away = lfsr(throw_away, time); + } + black_box(throw_away); + + self.data = lfsr(self.data, time); + } + + // Memory Access noise source + // This is a noise source based on variations in memory access times + // + // This function performs memory accesses which will add to the timing + // variations due to an unknown amount of CPU wait states that need to be + // added when accessing memory. The memory size should be larger than the L1 + // caches as outlined in the documentation and the associated testing. + // + // The L1 cache has a very high bandwidth, albeit its access rate is usually + // slower than accessing CPU registers. Therefore, L1 accesses only add + // minimal variations as the CPU has hardly to wait. Starting with L2, + // significant variations are added because L2 typically does not belong to + // the CPU any more and therefore a wider range of CPU wait states is + // necessary for accesses. L3 and real memory accesses have even a wider + // range of wait states. However, to reliably access either L3 or memory, + // the `self.mem` memory must be quite large which is usually not desirable. + #[inline(never)] + fn memaccess(&mut self, mem: &mut [u8; MEMORY_SIZE], var_rounds: bool) { + let mut acc_loop_cnt = 128; + if var_rounds { acc_loop_cnt += self.random_loop_cnt(4) }; + + let mut index = self.mem_prev_index as usize; + for _ in 0..acc_loop_cnt { + // Addition of memblocksize - 1 to index with wrap around logic to + // ensure that every memory location is hit evenly. + // The modulus also allows the compiler to remove the indexing + // bounds check. + index = (index + MEMORY_BLOCKSIZE - 1) % MEMORY_SIZE; + + // memory access: just add 1 to one byte + // memory access implies read from and write to memory location + mem[index] = mem[index].wrapping_add(1); + } + self.mem_prev_index = index as u16; + } + + // This is the heart of the entropy generation: calculate time deltas and + // use the CPU jitter in the time deltas. The jitter is injected into the + // entropy pool. + // + // Ensure that `ec.prev_time` is primed before using the output of this + // function. This can be done by calling this function and not using its + // result. + fn measure_jitter(&mut self, ec: &mut EcState) -> Option<()> { + // Invoke one noise source before time measurement to add variations + self.memaccess(&mut ec.mem, true); + + // Get time stamp and calculate time delta to previous + // invocation to measure the timing variations + let time = (self.timer)(); + // Note: wrapping_sub combined with a cast to `i64` generates a correct + // delta, even in the unlikely case this is a timer that is not strictly + // monotonic. + let current_delta = time.wrapping_sub(ec.prev_time) as i64 as i32; + ec.prev_time = time; + + // Call the next noise source which also injects the data + self.lfsr_time(current_delta as u64, true); + + // Check whether we have a stuck measurement (i.e. does the last + // measurement holds entropy?). + if ec.stuck(current_delta) { return None }; + + // Rotate the data buffer by a prime number (any odd number would + // do) to ensure that every bit position of the input time stamp + // has an even chance of being merged with a bit position in the + // entropy pool. We do not use one here as the adjacent bits in + // successive time deltas may have some form of dependency. The + // chosen value of 7 implies that the low 7 bits of the next + // time delta value is concatenated with the current time delta. + self.data = self.data.rotate_left(7); + + Some(()) + } + + // Shuffle the pool a bit by mixing some value with a bijective function + // (XOR) into the pool. + // + // The function generates a mixer value that depends on the bits set and + // the location of the set bits in the random number generated by the + // entropy source. Therefore, based on the generated random number, this + // mixer value can have 2^64 different values. That mixer value is + // initialized with the first two SHA-1 constants. After obtaining the + // mixer value, it is XORed into the random number. + // + // The mixer value is not assumed to contain any entropy. But due to the + // XOR operation, it can also not destroy any entropy present in the + // entropy pool. + #[inline(never)] + fn stir_pool(&mut self) { + // This constant is derived from the first two 32 bit initialization + // vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 + // The order does not really matter as we do not rely on the specific + // numbers. We just pick the SHA-1 constants as they have a good mix of + // bit set and unset. + const CONSTANT: u64 = 0x67452301efcdab89; + + // The start value of the mixer variable is derived from the third + // and fourth 32 bit initialization vector of SHA-1 as defined in + // FIPS 180-4 section 5.3.1 + let mut mixer = 0x98badcfe10325476; + + // This is a constant time function to prevent leaking timing + // information about the random number. + // The normal code is: + // ``` + // for i in 0..64 { + // if ((self.data >> i) & 1) == 1 { mixer ^= CONSTANT; } + // } + // ``` + // This is a bit fragile, as LLVM really wants to use branches here, and + // we rely on it to not recognise the opportunity. + for i in 0..64 { + let apply = (self.data >> i) & 1; + let mask = !apply.wrapping_sub(1); + mixer ^= CONSTANT & mask; + mixer = mixer.rotate_left(1); + } + + self.data ^= mixer; + } + + fn gen_entropy(&mut self) -> u64 { + trace!("JitterRng: collecting entropy"); + + // Prime `ec.prev_time`, and run the noice sources to make sure the + // first loop round collects the expected entropy. + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + let _ = self.measure_jitter(&mut ec); + + for _ in 0..self.rounds { + // If a stuck measurement is received, repeat measurement + // Note: we do not guard against an infinite loop, that would mean + // the timer suddenly became broken. + while self.measure_jitter(&mut ec).is_none() {} + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + self.stir_pool(); + self.data + } + + /// Basic quality tests on the timer, by measuring CPU timing jitter a few + /// hundred times. + /// + /// If successful, this will return the estimated number of rounds necessary + /// to collect 64 bits of entropy. Otherwise a [`TimerError`] with the cause + /// of the failure will be returned. + pub fn test_timer(&mut self) -> Result<u8, TimerError> { + debug!("JitterRng: testing timer ..."); + // We could add a check for system capabilities such as `clock_getres` + // or check for `CONFIG_X86_TSC`, but it does not make much sense as the + // following sanity checks verify that we have a high-resolution timer. + + let mut delta_sum = 0; + let mut old_delta = 0; + + let mut time_backwards = 0; + let mut count_mod = 0; + let mut count_stuck = 0; + + let mut ec = EcState { + prev_time: (self.timer)(), + last_delta: 0, + last_delta2: 0, + mem: [0; MEMORY_SIZE], + }; + + // TESTLOOPCOUNT needs some loops to identify edge systems. + // 100 is definitely too little. + const TESTLOOPCOUNT: u64 = 300; + const CLEARCACHE: u64 = 100; + + for i in 0..(CLEARCACHE + TESTLOOPCOUNT) { + // Measure time delta of core entropy collection logic + let time = (self.timer)(); + self.memaccess(&mut ec.mem, true); + self.lfsr_time(time, true); + let time2 = (self.timer)(); + + // Test whether timer works + if time == 0 || time2 == 0 { + return Err(TimerError::NoTimer); + } + let delta = time2.wrapping_sub(time) as i64 as i32; + + // Test whether timer is fine grained enough to provide delta even + // when called shortly after each other -- this implies that we also + // have a high resolution timer + if delta == 0 { + return Err(TimerError::CoarseTimer); + } + + // Up to here we did not modify any variable that will be + // evaluated later, but we already performed some work. Thus we + // already have had an impact on the caches, branch prediction, + // etc. with the goal to clear it to get the worst case + // measurements. + if i < CLEARCACHE { continue; } + + if ec.stuck(delta) { count_stuck += 1; } + + // Test whether we have an increasing timer. + if !(time2 > time) { time_backwards += 1; } + + // Count the number of times the counter increases in steps of 100ns + // or greater. + if (delta % 100) == 0 { count_mod += 1; } + + // Ensure that we have a varying delta timer which is necessary for + // the calculation of entropy -- perform this check only after the + // first loop is executed as we need to prime the old_delta value + delta_sum += (delta - old_delta).abs() as u64; + old_delta = delta; + } + + // Do a single read from `self.mem` to make sure the Memory Access noise + // source is not optimised out. + black_box(ec.mem[0]); + + // We allow the time to run backwards for up to three times. + // This can happen if the clock is being adjusted by NTP operations. + // If such an operation just happens to interfere with our test, it + // should not fail. The value of 3 should cover the NTP case being + // performed during our test run. + if time_backwards > 3 { + return Err(TimerError::NotMonotonic); + } + + // Test that the available amount of entropy per round does not get to + // low. We expect 1 bit of entropy per round as a reasonable minimum + // (although less is possible, it means the collector loop has to run + // much more often). + // `assert!(delta_average >= log2(1))` + // `assert!(delta_sum / TESTLOOPCOUNT >= 1)` + // `assert!(delta_sum >= TESTLOOPCOUNT)` + if delta_sum < TESTLOOPCOUNT { + return Err(TimerError::TinyVariantions); + } + + // Ensure that we have variations in the time stamp below 100 for at + // least 10% of all checks -- on some platforms, the counter increments + // in multiples of 100, but not always + if count_mod > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::CoarseTimer); + } + + // If we have more than 90% stuck results, then this Jitter RNG is + // likely to not work well. + if count_stuck > (TESTLOOPCOUNT * 9 / 10) { + return Err(TimerError::TooManyStuck); + } + + // Estimate the number of `measure_jitter` rounds necessary for 64 bits + // of entropy. + // + // We don't try very hard to come up with a good estimate of the + // available bits of entropy per round here for two reasons: + // 1. Simple estimates of the available bits (like Shannon entropy) are + // too optimistic. + // 2. Unless we want to waste a lot of time during intialization, there + // only a small number of samples are available. + // + // Therefore we use a very simple and conservative estimate: + // `let bits_of_entropy = log2(delta_average) / 2`. + // + // The number of rounds `measure_jitter` should run to collect 64 bits + // of entropy is `64 / bits_of_entropy`. + let delta_average = delta_sum / TESTLOOPCOUNT; + + if delta_average >= 16 { + let log2 = 64 - delta_average.leading_zeros(); + // Do something similar to roundup(64/(log2/2)): + Ok( ((64u32 * 2 + log2 - 1) / log2) as u8) + } else { + // For values < 16 the rounding error becomes too large, use a + // lookup table. + // Values 0 and 1 are invalid, and filtered out by the + // `delta_sum < TESTLOOPCOUNT` test above. + let log2_lookup = [0, 0, 128, 81, 64, 56, 50, 46, + 43, 41, 39, 38, 36, 35, 34, 33]; + Ok(log2_lookup[delta_average as usize]) + } + } + + /// Statistical test: return the timer delta of one normal run of the + /// `JitterRng` entropy collector. + /// + /// Setting `var_rounds` to `true` will execute the memory access and the + /// CPU jitter noice sources a variable amount of times (just like a real + /// `JitterRng` round). + /// + /// Setting `var_rounds` to `false` will execute the noice sources the + /// minimal number of times. This can be used to measure the minimum amount + /// of entropy one round of the entropy collector can collect in the worst + /// case. + /// + /// See this crate's README on how to use `timer_stats` to test the quality + /// of `JitterRng`. + pub fn timer_stats(&mut self, var_rounds: bool) -> i64 { + let mut mem = [0; MEMORY_SIZE]; + + let time = (self.timer)(); + self.memaccess(&mut mem, var_rounds); + self.lfsr_time(time, var_rounds); + let time2 = (self.timer)(); + time2.wrapping_sub(time) as i64 + } +} + +// A function that is opaque to the optimizer to assist in avoiding dead-code +// elimination. Taken from `bencher`. +fn black_box<T>(dummy: T) -> T { + unsafe { + let ret = ptr::read_volatile(&dummy); + mem::forget(dummy); + ret + } +} + +impl RngCore for JitterRng { + fn next_u32(&mut self) -> u32 { + // We want to use both parts of the generated entropy + if self.data_half_used { + self.data_half_used = false; + (self.data >> 32) as u32 + } else { + self.data = self.next_u64(); + self.data_half_used = true; + self.data as u32 + } + } + + fn next_u64(&mut self) -> u64 { + self.data_half_used = false; + self.gen_entropy() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + // Fill using `next_u32`. This is faster for filling small slices (four + // bytes or less), while the overhead is negligible. + // + // This is done especially for wrappers that implement `next_u32` + // themselves via `fill_bytes`. + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl CryptoRng for JitterRng {} + diff --git a/rand_jitter/src/platform.rs b/rand_jitter/src/platform.rs new file mode 100644 index 000000000..8e3d0fb22 --- /dev/null +++ b/rand_jitter/src/platform.rs @@ -0,0 +1,44 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))] +pub fn get_nstime() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + + let dur = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + // The correct way to calculate the current time is + // `dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64` + // But this is faster, and the difference in terms of entropy is + // negligible (log2(10^9) == 29.9). + dur.as_secs() << 30 | dur.subsec_nanos() as u64 +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn get_nstime() -> u64 { + use libc; + + // On Mac OS and iOS std::time::SystemTime only has 1000ns resolution. + // We use `mach_absolute_time` instead. This provides a CPU dependent + // unit, to get real nanoseconds the result should by multiplied by + // numer/denom from `mach_timebase_info`. + // But we are not interested in the exact nanoseconds, just entropy. So + // we use the raw result. + unsafe { libc::mach_absolute_time() } +} + +#[cfg(target_os = "windows")] +pub fn get_nstime() -> u64 { + use winapi; + + unsafe { + let mut t = super::mem::zeroed(); + winapi::um::profileapi::QueryPerformanceCounter(&mut t); + *t.QuadPart() as u64 + } +} diff --git a/rand_jitter/tests/mod.rs b/rand_jitter/tests/mod.rs new file mode 100644 index 000000000..6820c2080 --- /dev/null +++ b/rand_jitter/tests/mod.rs @@ -0,0 +1,31 @@ +extern crate rand_jitter; +extern crate rand_core; + +use rand_jitter::JitterRng; +#[cfg(feature = "std")] +use rand_core::RngCore; + +#[cfg(feature = "std")] +#[test] +fn test_jitter_init() { + // Because this is a debug build, measurements here are not representive + // of the final release build. + // Don't fail this test if initializing `JitterRng` fails because of a + // bad timer (the timer from the standard library may not have enough + // accuracy on all platforms). + match JitterRng::new() { + Ok(ref mut rng) => { + // false positives are possible, but extremely unlikely + assert!(rng.next_u32() | rng.next_u32() != 0); + }, + Err(_) => {}, + } +} + +#[test] +fn test_jitter_bad_timer() { + fn bad_timer() -> u64 { 0 } + let mut rng = JitterRng::new_with_timer(bad_timer); + assert!(rng.test_timer().is_err()); +} + diff --git a/rand_os/.cargo-checksum.json b/rand_os/.cargo-checksum.json new file mode 100644 index 000000000..3fb6532f3 --- /dev/null +++ b/rand_os/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"} \ No newline at end of file diff --git a/rand_os/CHANGELOG.md b/rand_os/CHANGELOG.md new file mode 100644 index 000000000..1ce36fc6c --- /dev/null +++ b/rand_os/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## [0.1.3] - 2019-03-05 +### Changes +- Fix support for Illumos (#730) +- Fix deprecation warnings from atomic init (#739) + +## [0.1.2] - 2019-01-28 +### Changes +- Fuchsia: Replaced fuchsia-zircon with fuchsia-cprng + +## [0.1.1] - 2019-01-08 +### Additions +- Add support for x86_64-fortanix-unknown-sgx target (#670) + +## [0.1.0] - 2019-01-04 +Initial release. diff --git a/rand_os/COPYRIGHT b/rand_os/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_os/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_os/Cargo.toml b/rand_os/Cargo.toml new file mode 100644 index 000000000..d0f1dfe7a --- /dev/null +++ b/rand_os/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_os" +version = "0.1.3" +authors = ["The Rand Project Developers"] +description = "OS backed Random Number Generator" +homepage = "https://crates.io/crates/rand_os" +documentation = "https://docs.rs/rand_os" +readme = "README.md" +keywords = ["random", "rng", "os"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.log] +version = "0.4" +optional = true + +[dependencies.rand_core] +version = "0.4" +features = ["std"] +[target."cfg(target_env = \"sgx\")".dependencies.rdrand] +version = "0.4.0" +[target."cfg(target_os = \"cloudabi\")".dependencies.cloudabi] +version = "0.0.3" +[target."cfg(target_os = \"fuchsia\")".dependencies.fuchsia-cprng] +version = "0.1.0" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["minwindef", "ntsecapi", "winnt"] +[target.wasm32-unknown-unknown.dependencies.stdweb] +version = "0.4" +optional = true + +[target.wasm32-unknown-unknown.dependencies.wasm-bindgen] +version = "0.2.12" +optional = true +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_os/LICENSE-APACHE b/rand_os/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_os/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_os/LICENSE-MIT b/rand_os/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_os/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_os/README.md b/rand_os/README.md new file mode 100644 index 000000000..4f48b63de --- /dev/null +++ b/rand_os/README.md @@ -0,0 +1,33 @@ +# rand_os + +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_os.svg)](https://crates.io/crates/rand_os) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_os) +[![API](https://docs.rs/rand_os/badge.svg)](https://docs.rs/rand_os) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +A random number generator that retrieves randomness straight from the +operating system. + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +This crate aims to support all of Rust's `std` platforms with a system-provided +entropy source. Unlike other Rand crates, this crate does not support `no_std` +(handling this gracefully is a current discussion topic). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_os) +- [API documentation (docs.rs)](https://docs.rs/rand_os) +- [Changelog](CHANGELOG.md) + +## License + +`rand_os` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_os/src/cloudabi.rs b/rand_os/src/cloudabi.rs new file mode 100644 index 000000000..8b96a2bc9 --- /dev/null +++ b/rand_os/src/cloudabi.rs @@ -0,0 +1,39 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for CloudABI + +extern crate cloudabi; + +use std::io; +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let errno = unsafe { cloudabi::random_get(dest) }; + if errno == cloudabi::errno::SUCCESS { + Ok(()) + } else { + // Cloudlibc provides its own `strerror` implementation so we + // can use `from_raw_os_error` here. + Err(Error::with_cause( + ErrorKind::Unavailable, + "random_get() system call failed", + io::Error::from_raw_os_error(errno as i32), + )) + } + } + + fn method_str(&self) -> &'static str { "cloudabi::random_get" } +} diff --git a/rand_os/src/dragonfly_haiku_emscripten.rs b/rand_os/src/dragonfly_haiku_emscripten.rs new file mode 100644 index 000000000..6132d7ac3 --- /dev/null +++ b/rand_os/src/dragonfly_haiku_emscripten.rs @@ -0,0 +1,39 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for DragonFly / Haiku / Emscripten + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; +use std::fs::File; + +#[derive(Clone, Debug)] +pub struct OsRng(); + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("/dev/random", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + #[cfg(target_os = "emscripten")] + fn max_chunk_size(&self) -> usize { + // `Crypto.getRandomValues` documents `dest` should be at most 65536 + // bytes. `crypto.randomBytes` documents: "To minimize threadpool + // task length variation, partition large randomBytes requests when + // doing so as part of fulfilling a client request. + 65536 + } + + fn method_str(&self) -> &'static str { "/dev/random" } +} diff --git a/rand_os/src/dummy_log.rs b/rand_os/src/dummy_log.rs new file mode 100644 index 000000000..ccfe4baef --- /dev/null +++ b/rand_os/src/dummy_log.rs @@ -0,0 +1,10 @@ +#[allow(unused)] +macro_rules! trace { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! debug { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! info { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! warn { ($($x:tt)*) => () } +#[allow(unused)] +macro_rules! error { ($($x:tt)*) => () } diff --git a/rand_os/src/freebsd.rs b/rand_os/src/freebsd.rs new file mode 100644 index 000000000..6b8e6728a --- /dev/null +++ b/rand_os/src/freebsd.rs @@ -0,0 +1,45 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for FreeBSD + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::ptr; +use std::io; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let mib = [libc::CTL_KERN, libc::KERN_ARND]; + let mut len = dest.len(); + let ret = unsafe { + libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint, + dest.as_mut_ptr() as *mut _, &mut len, + ptr::null(), 0) + }; + if ret == -1 || len != dest.len() { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "kern.arandom sysctl failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "kern.arandom" } +} diff --git a/rand_os/src/fuchsia.rs b/rand_os/src/fuchsia.rs new file mode 100644 index 000000000..ada367761 --- /dev/null +++ b/rand_os/src/fuchsia.rs @@ -0,0 +1,28 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Fuchsia Zircon + +extern crate fuchsia_cprng; + +use rand_core::Error; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + fuchsia_cprng::cprng_draw(dest); + Ok(()) + } + + fn method_str(&self) -> &'static str { "cprng_draw" } +} diff --git a/rand_os/src/lib.rs b/rand_os/src/lib.rs new file mode 100644 index 000000000..1b9cb2548 --- /dev/null +++ b/rand_os/src/lib.rs @@ -0,0 +1,440 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2013-2015 The Rust Project Developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Interface to the random number generator of the operating system. +//! +//! [`OsRng`] is the preferred external source of entropy for most applications. +//! Commonly it is used to initialize a user-space RNG, which can then be used +//! to generate random values with much less overhead than `OsRng`. +//! +//! You may prefer to use [`EntropyRng`] instead of `OsRng`. It is unlikely, but +//! not entirely theoretical, for `OsRng` to fail. In such cases [`EntropyRng`] +//! falls back on a good alternative entropy source. +//! +//! [`OsRng::new()`] is guaranteed to be very cheap (after the first successful +//! call), and will never consume more than one file handle per process. +//! +//! # Usage example +//! ``` +//! use rand_os::OsRng; +//! use rand_os::rand_core::RngCore; +//! +//! let mut os_rng = OsRng::new().unwrap(); +//! let mut key = [0u8; 16]; +//! os_rng.fill_bytes(&mut key); +//! let random_u64 = os_rng.next_u64(); +//! ``` +//! +//! # Platform sources +//! +//! | OS | interface +//! |------------------|--------------------------------------------------------- +//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once +//! | Windows | [`RtlGenRandom`][3] +//! | macOS, iOS | [`SecRandomCopyBytes`][4] +//! | FreeBSD | [`kern.arandom`][5] +//! | OpenBSD, Bitrig | [`getentropy`][6] +//! | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once +//! | Dragonfly BSD | [`/dev/random`][8] +//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10] +//! | Fuchsia OS | [`cprng_draw`][11] +//! | Redox | [`rand:`][12] +//! | CloudABI | [`random_get`][13] +//! | Haiku | `/dev/random` (identical to `/dev/urandom`) +//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14]) +//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16]) +//! +//! Rand doesn't have a blanket implementation for all Unix-like operating +//! systems that reads from `/dev/urandom`. This ensures all supported operating +//! systems are using the recommended interface and respect maximum buffer +//! sizes. +//! +//! ## Support for WebAssembly and ams.js +//! +//! The three Emscripten targets `asmjs-unknown-emscripten`, +//! `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use +//! Emscripten's emulation of `/dev/random` on web browsers and Node.js. +//! +//! The bare WASM target `wasm32-unknown-unknown` tries to call the javascript +//! methods directly, using either `stdweb` or `wasm-bindgen` depending on what +//! features are activated for this crate. Note that if both features are +//! enabled `wasm-bindgen` will be used. +//! +//! ## Early boot +//! +//! It is possible that early in the boot process the OS hasn't had enough time +//! yet to collect entropy to securely seed its RNG, especially on virtual +//! machines. +//! +//! Some operating systems always block the thread until the RNG is securely +//! seeded. This can take anywhere from a few seconds to more than a minute. +//! Others make a best effort to use a seed from before the shutdown and don't +//! document much. +//! +//! A few, Linux, NetBSD and Solaris, offer a choice between blocking, and +//! getting an error. With `try_fill_bytes` we choose to get the error +//! ([`ErrorKind::NotReady`]), while the other methods use a blocking interface. +//! +//! On Linux (when the `genrandom` system call is not available) and on NetBSD +//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected +//! enough entropy yet. As a countermeasure we try to do a single read from +//! `/dev/random` until we know the OS RNG is initialized (and store this in a +//! global static). +//! +//! # Panics and error handling +//! +//! We cannot guarantee that `OsRng` will fail, but if it does, it will likely +//! be either when `OsRng::new()` is first called or when data is first read. +//! If you wish to catch errors early, then test reading of at least one byte +//! from `OsRng` via [`try_fill_bytes`]. If this succeeds, it is extremely +//! unlikely that any further errors will occur. +//! +//! Only [`try_fill_bytes`] is able to report the cause of an error; the other +//! [`RngCore`] methods may (depending on the error kind) retry several times, +//! but must eventually panic if the error persists. +//! +//! [`EntropyRng`]: ../rand/rngs/struct.EntropyRng.html +//! [`try_fill_bytes`]: RngCore::try_fill_bytes +//! [`ErrorKind::NotReady`]: rand_core::ErrorKind +//! +//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html +//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html +//! [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx +//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc +//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4 +//! [6]: https://man.openbsd.org/getentropy.2 +//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current +//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 +//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html +//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html +//! [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md +//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs +//! [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826 +//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues +//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback +//! [16]: #support-for-webassembly-and-amsjs +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +#![cfg_attr(feature = "stdweb", recursion_limit="128")] + +pub extern crate rand_core; +#[cfg(feature = "log")] +#[macro_use] extern crate log; + +// We have to do it here because we load macros +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + feature = "wasm-bindgen"))] +extern crate wasm_bindgen; +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb"))] +#[macro_use] extern crate stdweb; + +#[cfg(target_env = "sgx")] +extern crate rdrand; + +#[cfg(not(feature = "log"))] +#[macro_use] +mod dummy_log; + +use std::fmt; +use rand_core::{CryptoRng, RngCore, Error, impls}; + +/// A random number generator that retrieves randomness straight from the +/// operating system. +#[derive(Clone)] +pub struct OsRng(imp::OsRng); + +impl fmt::Debug for OsRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> Result<OsRng, Error> { + imp::OsRng::new().map(OsRng) + } +} + +impl CryptoRng for OsRng {} + +impl RngCore for OsRng { + fn next_u32(&mut self) -> u32 { + impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + use std::{time, thread}; + + // We cannot return Err(..), so we try to handle before panicking. + const MAX_RETRY_PERIOD: u32 = 10; // max 10s + const WAIT_DUR_MS: u32 = 100; // retry every 100ms + let wait_dur = time::Duration::from_millis(WAIT_DUR_MS as u64); + const RETRY_LIMIT: u32 = (MAX_RETRY_PERIOD * 1000) / WAIT_DUR_MS; + const TRANSIENT_RETRIES: u32 = 8; + let mut err_count = 0; + let mut error_logged = false; + + // Maybe block until the OS RNG is initialized + let mut read = 0; + if let Ok(n) = self.0.test_initialized(dest, true) { read = n }; + let dest = &mut dest[read..]; + + loop { + if let Err(e) = self.try_fill_bytes(dest) { + if err_count >= RETRY_LIMIT { + error!("OsRng failed too many times; last error: {}", e); + panic!("OsRng failed too many times; last error: {}", e); + } + + if e.kind.should_wait() { + if !error_logged { + warn!("OsRng failed; waiting up to {}s and retrying. Error: {}", + MAX_RETRY_PERIOD, e); + error_logged = true; + } + err_count += 1; + thread::sleep(wait_dur); + continue; + } else if e.kind.should_retry() { + if !error_logged { + warn!("OsRng failed; retrying up to {} times. Error: {}", + TRANSIENT_RETRIES, e); + error_logged = true; + } + err_count += (RETRY_LIMIT + TRANSIENT_RETRIES - 1) + / TRANSIENT_RETRIES; // round up + continue; + } else { + error!("OsRng failed: {}", e); + panic!("OsRng fatal error: {}", e); + } + } + + break; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + // Some systems do not support reading 0 random bytes. + // (And why waste a system call?) + if dest.len() == 0 { return Ok(()); } + + let read = self.0.test_initialized(dest, false)?; + let dest = &mut dest[read..]; + + let max = self.0.max_chunk_size(); + if dest.len() <= max { + trace!("OsRng: reading {} bytes via {}", + dest.len(), self.0.method_str()); + } else { + trace!("OsRng: reading {} bytes via {} in {} chunks of {} bytes", + dest.len(), self.0.method_str(), (dest.len() + max) / max, max); + } + for slice in dest.chunks_mut(max) { + self.0.fill_chunk(slice)?; + } + Ok(()) + } +} + +trait OsRngImpl where Self: Sized { + // Create a new `OsRng` platform interface. + fn new() -> Result<Self, Error>; + + // Fill a chunk with random bytes. + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error>; + + // Test whether the OS RNG is initialized. This method may not be possible + // to support cheaply (or at all) on all operating systems. + // + // If `blocking` is set, this will cause the OS the block execution until + // its RNG is initialized. + // + // Random values that are read while this are stored in `dest`, the amount + // of read bytes is returned. + fn test_initialized(&mut self, _dest: &mut [u8], _blocking: bool) + -> Result<usize, Error> { Ok(0) } + + // Maximum chunk size supported. + fn max_chunk_size(&self) -> usize { ::std::usize::MAX } + + // Name of the OS interface (used for logging). + fn method_str(&self) -> &'static str; +} + +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "netbsd", target_os = "dragonfly", + target_os = "solaris", target_os = "redox", + target_os = "haiku", target_os = "emscripten", + target_os = "illumos"))] +mod random_device; + +macro_rules! mod_use { + ($cond:meta, $module:ident) => { + #[$cond] + mod $module; + #[$cond] + use $module as imp; + } +} + +mod_use!(cfg(target_os = "android"), linux_android); +mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig); +mod_use!(cfg(target_os = "cloudabi"), cloudabi); +mod_use!(cfg(target_os = "dragonfly"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "emscripten"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "freebsd"), freebsd); +mod_use!(cfg(target_os = "fuchsia"), fuchsia); +mod_use!(cfg(target_os = "haiku"), dragonfly_haiku_emscripten); +mod_use!(cfg(target_os = "ios"), macos); +mod_use!(cfg(target_os = "linux"), linux_android); +mod_use!(cfg(target_os = "macos"), macos); +mod_use!(cfg(target_os = "netbsd"), netbsd); +mod_use!(cfg(target_os = "openbsd"), openbsd_bitrig); +mod_use!(cfg(target_os = "redox"), redox); +mod_use!(cfg(any(target_os = "solaris", target_os = "illumos")), solarish); +mod_use!(cfg(windows), windows); +mod_use!(cfg(target_env = "sgx"), sgx); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + feature = "wasm-bindgen" + )), + wasm32_bindgen +); + +mod_use!( + cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + feature = "stdweb", + )), + wasm32_stdweb +); + +/// Per #678 we use run-time failure where WASM bindings are missing +#[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "wasm-bindgen"), + not(feature = "stdweb"), +))] +mod imp { + use rand_core::{Error, ErrorKind}; + use super::OsRngImpl; + + #[derive(Clone, Debug)] + pub struct OsRng; + + impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + Err(Error::new(ErrorKind::Unavailable, + "OsRng: support for wasm32 requires emscripten, stdweb or wasm-bindgen")) + } + + fn fill_chunk(&mut self, _dest: &mut [u8]) -> Result<(), Error> { + unimplemented!() + } + + fn method_str(&self) -> &'static str { unimplemented!() } + } +} + +#[cfg(not(any( + target_os = "android", + target_os = "bitrig", + target_os = "cloudabi", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "redox", + target_os = "solaris", + target_os = "illumos", + windows, + target_arch = "wasm32", + target_env = "sgx" +)))] +compile_error!("OS RNG support is not available for this platform"); + +// Due to rustwasm/wasm-bindgen#201 this can't be defined in the inner os +// modules, so hack around it for now and place it at the root. +#[cfg(all(feature = "wasm-bindgen", target_arch = "wasm32"))] +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub mod __wbg_shims { + + // `extern { type Foo; }` isn't supported on 1.22 syntactically, so use a + // macro to work around that. + macro_rules! rust_122_compat { + ($($t:tt)*) => ($($t)*) + } + + rust_122_compat! { + extern crate wasm_bindgen; + + pub use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + extern "C" { + pub type Function; + #[wasm_bindgen(constructor)] + pub fn new(s: &str) -> Function; + #[wasm_bindgen(method)] + pub fn call(this: &Function, self_: &JsValue) -> JsValue; + + pub type This; + #[wasm_bindgen(method, getter, structural, js_name = self)] + pub fn self_(me: &This) -> JsValue; + #[wasm_bindgen(method, getter, structural)] + pub fn crypto(me: &This) -> JsValue; + + #[derive(Clone, Debug)] + pub type BrowserCrypto; + + // TODO: these `structural` annotations here ideally wouldn't be here to + // avoid a JS shim, but for now with feature detection they're + // unavoidable. + #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)] + pub fn get_random_values_fn(me: &BrowserCrypto) -> JsValue; + #[wasm_bindgen(method, js_name = getRandomValues, structural)] + pub fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]); + + #[wasm_bindgen(js_name = require)] + pub fn node_require(s: &str) -> NodeCrypto; + + #[derive(Clone, Debug)] + pub type NodeCrypto; + + #[wasm_bindgen(method, js_name = randomFillSync, structural)] + pub fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]); + } + } +} diff --git a/rand_os/src/linux_android.rs b/rand_os/src/linux_android.rs new file mode 100644 index 000000000..255c22002 --- /dev/null +++ b/rand_os/src/linux_android.rs @@ -0,0 +1,186 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Linux / Android + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::random_device; +use super::OsRngImpl; + +use std::io; +use std::io::Read; +use std::fs::{File, OpenOptions}; +use std::os::unix::fs::OpenOptionsExt; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; +use std::sync::{Once, ONCE_INIT}; + +#[derive(Clone, Debug)] +pub struct OsRng { + method: OsRngMethod, + initialized: bool, +} + +#[derive(Clone, Debug)] +enum OsRngMethod { + GetRandom, + RandomDevice, +} + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result<usize, Error> + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let result = match self.method { + OsRngMethod::GetRandom => { + getrandom_try_fill(dest, blocking)?; + Ok(dest.len()) + } + OsRngMethod::RandomDevice => { + info!("OsRng: testing random device /dev/random"); + let mut file = OpenOptions::new() + .read(true) + .custom_flags(if blocking { 0 } else { libc::O_NONBLOCK }) + .open("/dev/random") + .map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + Ok(1) + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + result + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/urandom", + } + } +} + +#[cfg(target_arch = "x86_64")] +const NR_GETRANDOM: libc::c_long = 318; +#[cfg(target_arch = "x86")] +const NR_GETRANDOM: libc::c_long = 355; +#[cfg(target_arch = "arm")] +const NR_GETRANDOM: libc::c_long = 384; +#[cfg(target_arch = "aarch64")] +const NR_GETRANDOM: libc::c_long = 278; + #[cfg(target_arch = "s390x")] +const NR_GETRANDOM: libc::c_long = 349; +#[cfg(target_arch = "powerpc")] +const NR_GETRANDOM: libc::c_long = 359; +#[cfg(target_arch = "powerpc64")] +const NR_GETRANDOM: libc::c_long = 359; +#[cfg(target_arch = "mips")] // old ABI +const NR_GETRANDOM: libc::c_long = 4353; +#[cfg(target_arch = "mips64")] +const NR_GETRANDOM: libc::c_long = 5313; +#[cfg(target_arch = "sparc")] +const NR_GETRANDOM: libc::c_long = 347; +#[cfg(target_arch = "sparc64")] +const NR_GETRANDOM: libc::c_long = 347; +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", + target_arch = "arm", target_arch = "aarch64", + target_arch = "s390x", target_arch = "powerpc", + target_arch = "powerpc64", target_arch = "mips", + target_arch = "mips64", target_arch = "sparc", + target_arch = "sparc64")))] +const NR_GETRANDOM: libc::c_long = 0; + +fn getrandom(buf: &mut [u8], blocking: bool) -> libc::c_long { + const GRND_NONBLOCK: libc::c_uint = 0x0001; + + if NR_GETRANDOM == 0 { return -1 }; + + unsafe { + libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), + if blocking { 0 } else { GRND_NONBLOCK }) + } +} + +fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let mut read = 0; + while read < dest.len() { + let result = getrandom(&mut dest[read..], blocking); + if result == -1 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::Interrupted { + continue; + } else if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else { + read += result as usize; + } + } + Ok(()) +} + +fn is_getrandom_available() -> bool { + static CHECKER: Once = ONCE_INIT; + #[allow(deprecated)] + static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT; + + if NR_GETRANDOM == 0 { return false }; + + CHECKER.call_once(|| { + debug!("OsRng: testing getrandom"); + let mut buf: [u8; 0] = []; + let result = getrandom(&mut buf, false); + let available = if result == -1 { + let err = io::Error::last_os_error().raw_os_error(); + err != Some(libc::ENOSYS) + } else { + true + }; + AVAILABLE.store(available, Ordering::Relaxed); + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/urandom" }); + }); + + AVAILABLE.load(Ordering::Relaxed) +} diff --git a/rand_os/src/macos.rs b/rand_os/src/macos.rs new file mode 100644 index 000000000..6c67251c0 --- /dev/null +++ b/rand_os/src/macos.rs @@ -0,0 +1,53 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for MacOS / iOS + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; +use self::libc::{c_int, size_t}; + +#[derive(Clone, Debug)] +pub struct OsRng; + +enum SecRandom {} + +#[allow(non_upper_case_globals)] +const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; + +#[link(name = "Security", kind = "framework")] +extern { + fn SecRandomCopyBytes(rnd: *const SecRandom, + count: size_t, bytes: *mut u8) -> c_int; +} + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, + dest.len() as size_t, + dest.as_mut_ptr()) + }; + if ret == -1 { + Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())) + } else { + Ok(()) + } + } + + fn method_str(&self) -> &'static str { "SecRandomCopyBytes" } +} diff --git a/rand_os/src/netbsd.rs b/rand_os/src/netbsd.rs new file mode 100644 index 000000000..34517bfeb --- /dev/null +++ b/rand_os/src/netbsd.rs @@ -0,0 +1,57 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for NetBSD + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; + +use std::fs::File; +use std::io::Read; +use std::sync::atomic::{AtomicBool, Ordering}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; + +#[derive(Clone, Debug)] +pub struct OsRng { initialized: bool } + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("/dev/urandom", &|p| File::open(p))?; + Ok(OsRng { initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + // Read a single byte from `/dev/random` to determine if the OS RNG is + // already seeded. NetBSD always blocks if not yet ready. + fn test_initialized(&mut self, dest: &mut [u8], _blocking: bool) + -> Result<usize, Error> + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + info!("OsRng: testing random device /dev/random"); + let mut file = + File::open("/dev/random").map_err(random_device::map_err)?; + file.read(&mut dest[..1]).map_err(random_device::map_err)?; + + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(1) + } + + fn method_str(&self) -> &'static str { "/dev/urandom" } +} diff --git a/rand_os/src/openbsd_bitrig.rs b/rand_os/src/openbsd_bitrig.rs new file mode 100644 index 000000000..c9b35a6c5 --- /dev/null +++ b/rand_os/src/openbsd_bitrig.rs @@ -0,0 +1,40 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for OpenBSD / Bitrig + +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + libc::getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) + }; + if ret == -1 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "getentropy failed", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { 256 } + + fn method_str(&self) -> &'static str { "getentropy" } +} diff --git a/rand_os/src/random_device.rs b/rand_os/src/random_device.rs new file mode 100644 index 000000000..5da91940f --- /dev/null +++ b/rand_os/src/random_device.rs @@ -0,0 +1,70 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Helper functions to read from a random device such as `/dev/urandom`. +//! +//! All instances use a single internal file handle, to prevent possible +//! exhaustion of file descriptors. +use rand_core::{Error, ErrorKind}; +use std::fs::File; +use std::io; +use std::io::Read; +use std::sync::{Once, Mutex, ONCE_INIT}; + +// TODO: remove outer Option when `Mutex::new(None)` is a constant expression +static mut READ_RNG_FILE: Option<Mutex<Option<File>>> = None; +static READ_RNG_ONCE: Once = ONCE_INIT; + +#[allow(unused)] +pub fn open<F>(path: &'static str, open_fn: F) -> Result<(), Error> + where F: Fn(&'static str) -> Result<File, io::Error> +{ + READ_RNG_ONCE.call_once(|| { + unsafe { READ_RNG_FILE = Some(Mutex::new(None)) } + }); + + // We try opening the file outside the `call_once` fn because we cannot + // clone the error, thus we must retry on failure. + + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + if (*guard).is_none() { + info!("OsRng: opening random device {}", path); + let file = open_fn(path).map_err(map_err)?; + *guard = Some(file); + }; + Ok(()) +} + +pub fn read(dest: &mut [u8]) -> Result<(), Error> { + // We expect this function only to be used after `random_device::open` + // was succesful. Therefore we can assume that our memory was set with a + // valid object. + let mutex = unsafe { READ_RNG_FILE.as_ref().unwrap() }; + let mut guard = mutex.lock().unwrap(); + let file = (*guard).as_mut().unwrap(); + + // Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`. + file.read_exact(dest).map_err(|err| { + Error::with_cause(ErrorKind::Unavailable, + "error reading random device", err) + }) + +} + +pub fn map_err(err: io::Error) -> Error { + match err.kind() { + io::ErrorKind::Interrupted => + Error::new(ErrorKind::Transient, "interrupted"), + io::ErrorKind::WouldBlock => + Error::with_cause(ErrorKind::NotReady, + "OS RNG not yet seeded", err), + _ => Error::with_cause(ErrorKind::Unavailable, + "error while opening random device", err) + } +} diff --git a/rand_os/src/redox.rs b/rand_os/src/redox.rs new file mode 100644 index 000000000..36fae2666 --- /dev/null +++ b/rand_os/src/redox.rs @@ -0,0 +1,30 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Redox + +use rand_core::Error; +use super::random_device; +use super::OsRngImpl; +use std::fs::File; + +#[derive(Clone, Debug)] +pub struct OsRng(); + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + random_device::open("rand:", &|p| File::open(p))?; + Ok(OsRng()) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + random_device::read(dest) + } + + fn method_str(&self) -> &'static str { "'rand:'" } +} diff --git a/rand_os/src/sgx.rs b/rand_os/src/sgx.rs new file mode 100644 index 000000000..43ae0ef79 --- /dev/null +++ b/rand_os/src/sgx.rs @@ -0,0 +1,38 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::OsRngImpl; +use Error; +use rdrand::RdRand; +use rand_core::RngCore; +use std::fmt::{Debug, Formatter, Result as FmtResult}; + +#[derive(Clone)] +pub struct OsRng{ + gen: RdRand +} + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + let rng = RdRand::new()?; + Ok(OsRng{ gen: rng }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.gen.try_fill_bytes(dest) + } + + fn method_str(&self) -> &'static str { "RDRAND" } +} + +impl Debug for OsRng { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.debug_struct("OsRng") + .finish() + } +} diff --git a/rand_os/src/solarish.rs b/rand_os/src/solarish.rs new file mode 100644 index 000000000..471768adc --- /dev/null +++ b/rand_os/src/solarish.rs @@ -0,0 +1,195 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for the Solaris family +//! +//! Read from `/dev/random`, with chunks of limited size (1040 bytes). +//! `/dev/random` uses the Hash_DRBG with SHA512 algorithm from NIST SP 800-90A. +//! `/dev/urandom` uses the FIPS 186-2 algorithm, which is considered less +//! secure. We choose to read from `/dev/random`. +//! +//! Since Solaris 11.3 the `getrandom` syscall is available. To make sure we can +//! compile on both Solaris and on OpenSolaris derivatives, that do not have the +//! function, we do a direct syscall instead of calling a library function. +//! +//! We have no way to differentiate between Solaris, illumos, SmartOS, etc. +extern crate libc; + +use rand_core::{Error, ErrorKind}; +use super::random_device; +use super::OsRngImpl; + +use std::io; +use std::io::Read; +use std::fs::{File, OpenOptions}; +use std::os::unix::fs::OpenOptionsExt; +use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize}; +#[allow(deprecated)] // Required for compatibility with Rust < 1.24. +use std::sync::atomic::ATOMIC_BOOL_INIT; +use std::cmp; +use std::mem; + +#[derive(Clone, Debug)] +pub struct OsRng { + method: OsRngMethod, + initialized: bool, +} + +#[derive(Clone, Debug)] +enum OsRngMethod { + GetRandom, + RandomDevice, +} + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + if is_getrandom_available() { + return Ok(OsRng { method: OsRngMethod::GetRandom, + initialized: false }); + } + let open = |p| OpenOptions::new() + .read(true) + .custom_flags(libc::O_NONBLOCK) + .open(p); + random_device::open("/dev/random", &open)?; + Ok(OsRng { method: OsRngMethod::RandomDevice, initialized: false }) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, false), + OsRngMethod::RandomDevice => random_device::read(dest), + } + } + + fn test_initialized(&mut self, dest: &mut [u8], blocking: bool) + -> Result<usize, Error> + { + #[allow(deprecated)] + static OS_RNG_INITIALIZED: AtomicBool = ATOMIC_BOOL_INIT; + if !self.initialized { + self.initialized = OS_RNG_INITIALIZED.load(Ordering::Relaxed); + } + if self.initialized { return Ok(0); } + + let chunk_len = cmp::min(1024, dest.len()); + let dest = &mut dest[..chunk_len]; + + match self.method { + OsRngMethod::GetRandom => getrandom_try_fill(dest, blocking)?, + OsRngMethod::RandomDevice => { + if blocking { + info!("OsRng: testing random device /dev/random"); + // We already have a non-blocking handle, but now need a + // blocking one. Not much choice except opening it twice + let mut file = File::open("/dev/random") + .map_err(random_device::map_err)?; + file.read(dest).map_err(random_device::map_err)?; + } else { + self.fill_chunk(dest)?; + } + } + }; + OS_RNG_INITIALIZED.store(true, Ordering::Relaxed); + self.initialized = true; + Ok(chunk_len) + } + + fn max_chunk_size(&self) -> usize { + // This is the largest size that's guaranteed to not block across + // all the Solarish platforms, though some may allow for larger + // sizes. + 256 + } + + fn method_str(&self) -> &'static str { + match self.method { + OsRngMethod::GetRandom => "getrandom", + OsRngMethod::RandomDevice => "/dev/random", + } + } +} + +#[cfg(target_os = "illumos")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::ssize_t; +#[cfg(target_os = "solaris")] +type GetRandomFn = unsafe extern fn(*mut u8, libc::size_t, libc::c_uint) + -> libc::c_int; + +// Use dlsym to determine if getrandom(2) is present in libc. On Solarish +// systems, the syscall interface is not stable and can change between +// updates. Even worse, issuing unsupported syscalls will cause the system +// to generate a SIGSYS signal (usually terminating the program). +// Instead the stable APIs are exposed via libc. Cache the result of the +// lookup for future calls. This is loosely modeled after the +// libstd::sys::unix::weak macro which unfortunately is not exported. +fn fetch() -> Option<GetRandomFn> { + static FPTR: AtomicUsize = AtomicUsize::new(1); + + if FPTR.load(Ordering::SeqCst) == 1 { + let name = "getrandom\0"; + let addr = unsafe { + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize + }; + FPTR.store(addr, Ordering::SeqCst); + } + + let ptr = FPTR.load(Ordering::SeqCst); + unsafe { + mem::transmute::<usize, Option<GetRandomFn>>(ptr) + } +} + +fn getrandom(buf: &mut [u8], blocking: bool) -> libc::ssize_t { + const GRND_NONBLOCK: libc::c_uint = 0x0001; + const GRND_RANDOM: libc::c_uint = 0x0002; + + if let Some(rand) = fetch() { + let flag = if blocking { 0 } else { GRND_NONBLOCK } | GRND_RANDOM; + unsafe { + rand(buf.as_mut_ptr(), buf.len(), flag) as libc::ssize_t + } + } else { + -1 + } +} + +fn getrandom_try_fill(dest: &mut [u8], blocking: bool) -> Result<(), Error> { + let result = getrandom(dest, blocking); + if result == -1 || result == 0 { + let err = io::Error::last_os_error(); + let kind = err.kind(); + if kind == io::ErrorKind::WouldBlock { + return Err(Error::with_cause( + ErrorKind::NotReady, + "getrandom not ready", + err, + )); + } else { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "unexpected getrandom error", + err, + )); + } + } else if result != dest.len() as libc::ssize_t { + return Err(Error::new(ErrorKind::Unavailable, + "unexpected getrandom error")); + } + Ok(()) +} + +fn is_getrandom_available() -> bool { + let available = match fetch() { + Some(_) => true, + None => false, + }; + info!("OsRng: using {}", if available { "getrandom" } else { "/dev/random" }); + available +} diff --git a/rand_os/src/wasm32_bindgen.rs b/rand_os/src/wasm32_bindgen.rs new file mode 100644 index 000000000..5ab2d8417 --- /dev/null +++ b/rand_os/src/wasm32_bindgen.rs @@ -0,0 +1,92 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for WASM via wasm-bindgen + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; +use super::__wbg_shims::*; + +use wasm_bindgen::prelude::*; + + +#[derive(Clone, Debug)] +pub enum OsRng { + Node(NodeCrypto), + Browser(BrowserCrypto), +} + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + // First up we need to detect if we're running in node.js or a + // browser. To do this we get ahold of the `this` object (in a bit + // of a roundabout fashion). + // + // Once we have `this` we look at its `self` property, which is + // only defined on the web (either a main window or web worker). + let this = Function::new("return this").call(&JsValue::undefined()); + assert!(this != JsValue::undefined()); + let this = This::from(this); + let is_browser = this.self_() != JsValue::undefined(); + + if !is_browser { + return Ok(OsRng::Node(node_require("crypto"))) + } + + // If `self` is defined then we're in a browser somehow (main window + // or web worker). Here we want to try to use + // `crypto.getRandomValues`, but if `crypto` isn't defined we assume + // we're in an older web browser and the OS RNG isn't available. + let crypto = this.crypto(); + if crypto.is_undefined() { + let msg = "self.crypto is undefined"; + return Err(Error::new(ErrorKind::Unavailable, msg)) + } + + // Test if `crypto.getRandomValues` is undefined as well + let crypto: BrowserCrypto = crypto.into(); + if crypto.get_random_values_fn().is_undefined() { + let msg = "crypto.getRandomValues is undefined"; + return Err(Error::new(ErrorKind::Unavailable, msg)) + } + + // Ok! `self.crypto.getRandomValues` is a defined value, so let's + // assume we can do browser crypto. + Ok(OsRng::Browser(crypto)) + } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + match *self { + OsRng::Node(ref n) => n.random_fill_sync(dest), + OsRng::Browser(ref n) => n.get_random_values(dest), + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { + match *self { + OsRng::Node(_) => usize::max_value(), + OsRng::Browser(_) => { + // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues + // + // where it says: + // + // > A QuotaExceededError DOMException is thrown if the + // > requested length is greater than 65536 bytes. + 65536 + } + } + } + + fn method_str(&self) -> &'static str { + match *self { + OsRng::Node(_) => "crypto.randomFillSync", + OsRng::Browser(_) => "crypto.getRandomValues", + } + } +} diff --git a/rand_os/src/wasm32_stdweb.rs b/rand_os/src/wasm32_stdweb.rs new file mode 100644 index 000000000..3be0ce6a6 --- /dev/null +++ b/rand_os/src/wasm32_stdweb.rs @@ -0,0 +1,107 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for WASM via stdweb + +use std::mem; +use stdweb::unstable::TryInto; +use stdweb::web::error::Error as WebError; +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +#[derive(Clone, Debug)] +enum OsRngMethod { + Browser, + Node +} + +#[derive(Clone, Debug)] +pub struct OsRng(OsRngMethod); + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { + let result = js! { + try { + if ( + typeof self === "object" && + typeof self.crypto === "object" && + typeof self.crypto.getRandomValues === "function" + ) { + return { success: true, ty: 1 }; + } + + if (typeof require("crypto").randomBytes === "function") { + return { success: true, ty: 2 }; + } + + return { success: false, error: new Error("not supported") }; + } catch(err) { + return { success: false, error: err }; + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + let ty = js!{ return @{ result }.ty }; + + if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) } + else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) } + else { unreachable!() } + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err)) + } + } + + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + assert_eq!(mem::size_of::<usize>(), 4); + + let len = dest.len() as u32; + let ptr = dest.as_mut_ptr() as i32; + + let result = match self.0 { + OsRngMethod::Browser => js! { + try { + let array = new Uint8Array(@{ len }); + self.crypto.getRandomValues(array); + HEAPU8.set(array, @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + }, + OsRngMethod::Node => js! { + try { + let bytes = require("crypto").randomBytes(@{ len }); + HEAPU8.set(new Uint8Array(bytes), @{ ptr }); + + return { success: true }; + } catch(err) { + return { success: false, error: err }; + } + } + }; + + if js!{ return @{ result.as_ref() }.success } == true { + Ok(()) + } else { + let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); + Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err)) + } + } + + fn max_chunk_size(&self) -> usize { 65536 } + + fn method_str(&self) -> &'static str { + match self.0 { + OsRngMethod::Browser => "Crypto.getRandomValues", + OsRngMethod::Node => "crypto.randomBytes", + } + } +} diff --git a/rand_os/src/windows.rs b/rand_os/src/windows.rs new file mode 100644 index 000000000..6b06c7abf --- /dev/null +++ b/rand_os/src/windows.rs @@ -0,0 +1,44 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation for Windows + +extern crate winapi; + +use rand_core::{Error, ErrorKind}; +use super::OsRngImpl; + +use std::io; + +use self::winapi::shared::minwindef::ULONG; +use self::winapi::um::ntsecapi::RtlGenRandom; +use self::winapi::um::winnt::PVOID; + +#[derive(Clone, Debug)] +pub struct OsRng; + +impl OsRngImpl for OsRng { + fn new() -> Result<OsRng, Error> { Ok(OsRng) } + + fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { + let ret = unsafe { + RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) + }; + if ret == 0 { + return Err(Error::with_cause( + ErrorKind::Unavailable, + "couldn't generate random bytes", + io::Error::last_os_error())); + } + Ok(()) + } + + fn max_chunk_size(&self) -> usize { <ULONG>::max_value() as usize } + + fn method_str(&self) -> &'static str { "RtlGenRandom" } +} diff --git a/rand_os/tests/mod.rs b/rand_os/tests/mod.rs new file mode 100644 index 000000000..2130e169b --- /dev/null +++ b/rand_os/tests/mod.rs @@ -0,0 +1,80 @@ +extern crate rand_os; + +use rand_os::rand_core::RngCore; +use rand_os::OsRng; + +#[test] +fn test_os_rng() { + let mut r = OsRng::new().unwrap(); + + r.next_u32(); + r.next_u64(); + + let mut v1 = [0u8; 1000]; + r.fill_bytes(&mut v1); + + let mut v2 = [0u8; 1000]; + r.fill_bytes(&mut v2); + + let mut n_diff_bits = 0; + for i in 0..v1.len() { + n_diff_bits += (v1[i] ^ v2[i]).count_ones(); + } + + // Check at least 1 bit per byte differs. p(failure) < 1e-1000 with random input. + assert!(n_diff_bits >= v1.len() as u32); +} + +#[test] +fn test_os_rng_empty() { + let mut r = OsRng::new().unwrap(); + + let mut empty = [0u8; 0]; + r.fill_bytes(&mut empty); +} + +#[test] +fn test_os_rng_huge() { + let mut r = OsRng::new().unwrap(); + + let mut huge = [0u8; 100_000]; + r.fill_bytes(&mut huge); +} + +#[cfg(not(any(target_arch = "wasm32", target_arch = "asmjs")))] +#[test] +fn test_os_rng_tasks() { + use std::sync::mpsc::channel; + use std::thread; + + let mut txs = vec!(); + for _ in 0..20 { + let (tx, rx) = channel(); + txs.push(tx); + + thread::spawn(move|| { + // wait until all the tasks are ready to go. + rx.recv().unwrap(); + + // deschedule to attempt to interleave things as much + // as possible (XXX: is this a good test?) + let mut r = OsRng::new().unwrap(); + thread::yield_now(); + let mut v = [0u8; 1000]; + + for _ in 0..100 { + r.next_u32(); + thread::yield_now(); + r.next_u64(); + thread::yield_now(); + r.fill_bytes(&mut v); + thread::yield_now(); + } + }); + } + + // start all the tasks + for tx in txs.iter() { + tx.send(()).unwrap(); + } +} diff --git a/rand_pcg/.cargo-checksum.json b/rand_pcg/.cargo-checksum.json new file mode 100644 index 000000000..d3d9cb9df --- /dev/null +++ b/rand_pcg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"} \ No newline at end of file diff --git a/rand_pcg/CHANGELOG.md b/rand_pcg/CHANGELOG.md new file mode 100644 index 000000000..695722480 --- /dev/null +++ b/rand_pcg/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.2] - 2019-02-23 +- require `bincode` 1.1.2 for i128 auto-detection +- make `bincode` a dev-dependency again #663 +- clean up tests and Serde support + +## [0.1.1] - 2018-10-04 +- make `bincode` an explicit dependency when using Serde + +## [0.1.0] - 2018-10-04 +Initial release, including: + +- `Lcg64Xsh32` aka `Pcg32` +- `Mcg128Xsl64` aka `Pcg64Mcg` diff --git a/rand_pcg/COPYRIGHT b/rand_pcg/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_pcg/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_pcg/Cargo.toml b/rand_pcg/Cargo.toml new file mode 100644 index 000000000..346f2f7bc --- /dev/null +++ b/rand_pcg/Cargo.toml @@ -0,0 +1,47 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_pcg" +version = "0.1.2" +authors = ["The Rand Project Developers"] +build = "build.rs" +description = "Selected PCG random number generators\n" +homepage = "https://crates.io/crates/rand_pcg" +documentation = "https://rust-random.github.io/rand/rand_pcg" +readme = "README.md" +keywords = ["random", "rng", "pcg"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = "0.4" + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1.1.2" +[build-dependencies.autocfg] +version = "0.1" + +[features] +serde1 = ["serde", "serde_derive"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_pcg/LICENSE-APACHE b/rand_pcg/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_pcg/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_pcg/LICENSE-MIT b/rand_pcg/LICENSE-MIT new file mode 100644 index 000000000..d46f058e9 --- /dev/null +++ b/rand_pcg/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors +Copyright 2018 Developers of the Rand project + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_pcg/README.md b/rand_pcg/README.md new file mode 100644 index 000000000..ae583a1a4 --- /dev/null +++ b/rand_pcg/README.md @@ -0,0 +1,43 @@ +# rand_pcg + +[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_pcg.svg)](https://crates.io/crates/rand_pcg) +[[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_pcg) +[![API](https://docs.rs/rand_pcg/badge.svg)](https://docs.rs/rand_pcg) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements a selection of PCG random number generators. + +> PCG is a family of simple fast space-efficient statistically good algorithms +> for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014]. + +The PCG algorithms are not suitable for cryptographic uses, but perform well +in statistical tests, use little memory and are fairly fast. +See the [pcg-random website](http://www.pcg-random.org/). + +This crate depends on [rand_core](https://crates.io/crates/rand_core) and is +part of the [Rand project](https://github.com/rust-random/rand). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_pcg) +- [API documentation (docs.rs)](https://docs.rs/rand_pcg) +- [Changelog](CHANGELOG.md) + + +## Crate Features + +`rand_pcg` is `no_std` compatible by default. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + +## License + +`rand_pcg` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_pcg/build.rs b/rand_pcg/build.rs new file mode 100644 index 000000000..06e12a47b --- /dev/null +++ b/rand_pcg/build.rs @@ -0,0 +1,7 @@ +extern crate autocfg; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + let ac = autocfg::new(); + ac.emit_rustc_version(1, 26); +} diff --git a/rand_pcg/src/lib.rs b/rand_pcg/src/lib.rs new file mode 100644 index 000000000..9648e85d2 --- /dev/null +++ b/rand_pcg/src/lib.rs @@ -0,0 +1,48 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The PCG random number generators. +//! +//! This is a native Rust implementation of a small selection of PCG generators. +//! The primary goal of this crate is simple, minimal, well-tested code; in +//! other words it is explicitly not a goal to re-implement all of PCG. +//! +//! This crate provides: +//! +//! - `Pcg32` aka `Lcg64Xsh32`, officially known as `pcg32`, a general +//! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs +//! (for 32-bit output). +//! - `Pcg64Mcg` aka `Mcg128Xsl64`, officially known as `mcg_xsl_rr_128_64`, +//! a general purpose RNG using 128-bit multiplications. This has poor +//! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for +//! both 32-bit and 64-bit output. (Note: this RNG is only available using +//! Rust 1.26 or later.) +//! +//! Both of these use 16 bytes of state and 128-bit seeds, and are considered +//! value-stable (i.e. any change affecting the output given a fixed seed would +//! be considered a breaking change to the crate). + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#![no_std] + +pub extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +mod pcg64; +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] mod pcg128; + +pub use self::pcg64::{Pcg32, Lcg64Xsh32}; +#[cfg(all(rustc_1_26, not(target_os = "emscripten")))] pub use self::pcg128::{Pcg64Mcg, Mcg128Xsl64}; diff --git a/rand_pcg/src/pcg128.rs b/rand_pcg/src/pcg128.rs new file mode 100644 index 000000000..9aff50607 --- /dev/null +++ b/rand_pcg/src/pcg128.rs @@ -0,0 +1,122 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 Paul Dicker. +// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! PCG random number generators + +// This is the default multiplier used by PCG for 64-bit state. +const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; + +use core::fmt; +use core::mem::transmute; +use rand_core::{RngCore, SeedableRng, Error, le}; + +/// A PCG random number generator (XSL 128/64 (MCG) variant). +/// +/// Permuted Congruential Generator with 128-bit state, internal Multiplicative +/// Congruential Generator, and 64-bit output via "xorshift low (bits), +/// random rotation" output function. +/// +/// This is a 128-bit MCG with the PCG-XSL-RR output function. +/// Note that compared to the standard `pcg64` (128-bit LCG with PCG-XSL-RR +/// output function), this RNG is faster, also has a long cycle, and still has +/// good performance on statistical tests. +/// +/// Note: this RNG is only available using Rust 1.26 or later. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct Mcg128Xsl64 { + state: u128, +} + +/// A friendly name for `Mcg128Xsl64`. +pub type Pcg64Mcg = Mcg128Xsl64; + +impl Mcg128Xsl64 { + /// Construct an instance compatible with PCG seed. + /// + /// Note that PCG specifies a default value for the parameter: + /// + /// - `state = 0xcafef00dd15ea5e5` + pub fn new(state: u128) -> Self { + // Force low bit to 1, as in C version (C++ uses `state | 3` instead). + Mcg128Xsl64 { state: state | 1 } + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Mcg128Xsl64 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Mcg128Xsl64 {{}}") + } +} + +/// We use a single 126-bit seed to initialise the state and select a stream. +/// Two `seed` bits (lowest order of last byte) are ignored. +impl SeedableRng for Mcg128Xsl64 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + // Read as if a little-endian u128 value: + let mut seed_u64 = [0u64; 2]; + le::read_u64_into(&seed, &mut seed_u64); + let state = (seed_u64[0] as u128) | + (seed_u64[1] as u128) << 64; + Mcg128Xsl64::new(state) + } +} + +impl RngCore for Mcg128Xsl64 { + #[inline] + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + // prepare the LCG for the next round + let state = self.state.wrapping_mul(MULTIPLIER); + self.state = state; + + // Output function XSL RR ("xorshift low (bits), random rotation") + // Constants are for 128-bit state, 64-bit output + const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2 + const ROTATE: u32 = 122; // 128 - 6 + + let rot = (state >> ROTATE) as u32; + let xsl = ((state >> XSHIFT) as u64) ^ (state as u64); + xsl.rotate_right(rot) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + // specialisation of impls::fill_bytes_via_next; approx 3x faster + let mut left = dest; + while left.len() >= 8 { + let (l, r) = {left}.split_at_mut(8); + left = r; + let chunk: [u8; 8] = unsafe { + transmute(self.next_u64().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 0 { + let chunk: [u8; 8] = unsafe { + transmute(self.next_u64().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/rand_pcg/src/pcg64.rs b/rand_pcg/src/pcg64.rs new file mode 100644 index 000000000..9177ec248 --- /dev/null +++ b/rand_pcg/src/pcg64.rs @@ -0,0 +1,141 @@ +// Copyright 2018 Developers of the Rand project. +// Copyright 2017 Paul Dicker. +// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! PCG random number generators + +use core::fmt; +use core::mem::transmute; +use rand_core::{RngCore, SeedableRng, Error, le, impls}; + +// This is the default multiplier used by PCG for 64-bit state. +const MULTIPLIER: u64 = 6364136223846793005; + +/// A PCG random number generator (XSH RR 64/32 (LCG) variant). +/// +/// Permuted Congruential Generator with 64-bit state, internal Linear +/// Congruential Generator, and 32-bit output via "xorshift high (bits), +/// random rotation" output function. +/// +/// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR +/// output function. This combination is the standard `pcg32`. +/// +/// Despite the name, this implementation uses 16 bytes (128 bit) space +/// comprising 64 bits of state and 64 bits stream selector. These are both set +/// by `SeedableRng`, using a 128-bit seed. +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct Lcg64Xsh32 { + state: u64, + increment: u64, +} + +/// `Lcg64Xsh32` is also officially known as `pcg32`. +pub type Pcg32 = Lcg64Xsh32; + +impl Lcg64Xsh32 { + /// Construct an instance compatible with PCG seed and stream. + /// + /// Note that PCG specifies default values for both parameters: + /// + /// - `state = 0xcafef00dd15ea5e5` + /// - `stream = 721347520444481703` + pub fn new(state: u64, stream: u64) -> Self { + // The increment must be odd, hence we discard one bit: + let increment = (stream << 1) | 1; + Lcg64Xsh32::from_state_incr(state, increment) + } + + #[inline] + fn from_state_incr(state: u64, increment: u64) -> Self { + let mut pcg = Lcg64Xsh32 { state, increment }; + // Move away from inital value: + pcg.state = pcg.state.wrapping_add(pcg.increment); + pcg.step(); + pcg + } + + #[inline] + fn step(&mut self) { + // prepare the LCG for the next round + self.state = self.state + .wrapping_mul(MULTIPLIER) + .wrapping_add(self.increment); + } +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for Lcg64Xsh32 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Lcg64Xsh32 {{}}") + } +} + +/// We use a single 127-bit seed to initialise the state and select a stream. +/// One `seed` bit (lowest bit of `seed[8]`) is ignored. +impl SeedableRng for Lcg64Xsh32 { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u64 = [0u64; 2]; + le::read_u64_into(&seed, &mut seed_u64); + + // The increment must be odd, hence we discard one bit: + Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1) + } +} + +impl RngCore for Lcg64Xsh32 { + #[inline] + fn next_u32(&mut self) -> u32 { + let state = self.state; + self.step(); + + // Output function XSH RR: xorshift high (bits), followed by a random rotate + // Constants are for 64-bit state, 32-bit output + const ROTATE: u32 = 59; // 64 - 5 + const XSHIFT: u32 = 18; // (5 + 32) / 2 + const SPARE: u32 = 27; // 64 - 32 - 5 + + let rot = (state >> ROTATE) as u32; + let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32; + xsh.rotate_right(rot) + } + + #[inline] + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_u32(self) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + // specialisation of impls::fill_bytes_via_next; approx 40% faster + let mut left = dest; + while left.len() >= 4 { + let (l, r) = {left}.split_at_mut(4); + left = r; + let chunk: [u8; 4] = unsafe { + transmute(self.next_u32().to_le()) + }; + l.copy_from_slice(&chunk); + } + let n = left.len(); + if n > 0 { + let chunk: [u8; 4] = unsafe { + transmute(self.next_u32().to_le()) + }; + left.copy_from_slice(&chunk[..n]); + } + } + + #[inline] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} diff --git a/rand_pcg/tests/lcg64xsh32.rs b/rand_pcg/tests/lcg64xsh32.rs new file mode 100644 index 000000000..775b12c99 --- /dev/null +++ b/rand_pcg/tests/lcg64xsh32.rs @@ -0,0 +1,58 @@ +extern crate rand_pcg; +extern crate rand_core; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_pcg::{Lcg64Xsh32, Pcg32}; + +#[test] +fn test_lcg64xsh32_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = Lcg64Xsh32::from_seed(seed); + assert_eq!(rng1.next_u64(), 1204678643940597513); + + let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap(); + assert_eq!(rng2.next_u64(), 12384929573776311845); + + let mut rng3 = Lcg64Xsh32::seed_from_u64(0); + assert_eq!(rng3.next_u64(), 18195738587432868099); + + // This is the same as Lcg64Xsh32, so we only have a single test: + let mut rng4 = Pcg32::seed_from_u64(0); + assert_eq!(rng4.next_u64(), 18195738587432868099); +} + +#[test] +fn test_lcg64xsh32_true_values() { + // Numbers copied from official test suite. + let mut rng = Lcg64Xsh32::new(42, 54); + + let mut results = [0u32; 6]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 6] = [0xa15c02b7, 0x7b47f409, 0xba1d3330, + 0x83d2f293, 0xbfa4784b, 0xcbed606e]; + assert_eq!(results, expected); +} + +#[cfg(feature="serde1")] +#[test] +fn test_lcg64xsh32_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let mut rng = Lcg64Xsh32::seed_from_u64(0); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Lcg64Xsh32 = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/rand_pcg/tests/mcg128xsl64.rs b/rand_pcg/tests/mcg128xsl64.rs new file mode 100644 index 000000000..3279536fc --- /dev/null +++ b/rand_pcg/tests/mcg128xsl64.rs @@ -0,0 +1,59 @@ +#![cfg(rustc_1_26)] +extern crate rand_pcg; +extern crate rand_core; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_pcg::{Mcg128Xsl64, Pcg64Mcg}; + +#[test] +fn test_mcg128xsl64_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = Mcg128Xsl64::from_seed(seed); + assert_eq!(rng1.next_u64(), 7071994460355047496); + + let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1).unwrap(); + assert_eq!(rng2.next_u64(), 12300796107712034932); + + let mut rng3 = Mcg128Xsl64::seed_from_u64(0); + assert_eq!(rng3.next_u64(), 6198063878555692194); + + // This is the same as Mcg128Xsl64, so we only have a single test: + let mut rng4 = Pcg64Mcg::seed_from_u64(0); + assert_eq!(rng4.next_u64(), 6198063878555692194); +} + +#[test] +fn test_mcg128xsl64_true_values() { + // Numbers copied from official test suite (C version). + let mut rng = Mcg128Xsl64::new(42); + + let mut results = [0u64; 6]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 6] = [0x63b4a3a813ce700a, 0x382954200617ab24, + 0xa7fd85ae3fe950ce, 0xd715286aa2887737, 0x60c92fee2e59f32c, 0x84c4e96beff30017]; + assert_eq!(results, expected); +} + +#[cfg(feature="serde1")] +#[test] +fn test_mcg128xsl64_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let mut rng = Mcg128Xsl64::seed_from_u64(0); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: Mcg128Xsl64 = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/rand_xorshift/.cargo-checksum.json b/rand_xorshift/.cargo-checksum.json new file mode 100644 index 000000000..64d9a3ab7 --- /dev/null +++ b/rand_xorshift/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"} \ No newline at end of file diff --git a/rand_xorshift/CHANGELOG.md b/rand_xorshift/CHANGELOG.md new file mode 100644 index 000000000..539af4131 --- /dev/null +++ b/rand_xorshift/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.1] - 2019-01-04 +- Reorganise code and tests; tweak doc + +## [0.1.0] - 2018-07-16 +- Pulled out of the Rand crate diff --git a/rand_xorshift/COPYRIGHT b/rand_xorshift/COPYRIGHT new file mode 100644 index 000000000..468d907ca --- /dev/null +++ b/rand_xorshift/COPYRIGHT @@ -0,0 +1,12 @@ +Copyrights in the Rand project are retained by their contributors. No +copyright assignment is required to contribute to the Rand project. + +For full authorship information, see the version control history. + +Except as otherwise noted (below and/or in individual files), Rand is +licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or +<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +<LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. + +The Rand project includes code from the Rust project +published under these same licenses. diff --git a/rand_xorshift/Cargo.toml b/rand_xorshift/Cargo.toml new file mode 100644 index 000000000..26aa48129 --- /dev/null +++ b/rand_xorshift/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rand_xorshift" +version = "0.1.1" +authors = ["The Rand Project Developers", "The Rust Project Developers"] +description = "Xorshift random number generator\n" +homepage = "https://crates.io/crates/rand_xorshift" +documentation = "https://rust-random.github.io/rand/rand_xorshift" +readme = "README.md" +keywords = ["random", "rng", "xorshift"] +categories = ["algorithms", "no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-random/rand" +[dependencies.rand_core] +version = ">=0.2, <0.4" +default-features = false + +[dependencies.serde] +version = "1" +optional = true + +[dependencies.serde_derive] +version = "^1.0.38" +optional = true +[dev-dependencies.bincode] +version = "1" + +[features] +serde1 = ["serde", "serde_derive"] +[badges.appveyor] +repository = "rust-random/rand" + +[badges.travis-ci] +repository = "rust-random/rand" diff --git a/rand_xorshift/LICENSE-APACHE b/rand_xorshift/LICENSE-APACHE new file mode 100644 index 000000000..17d74680f --- /dev/null +++ b/rand_xorshift/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rand_xorshift/LICENSE-MIT b/rand_xorshift/LICENSE-MIT new file mode 100644 index 000000000..d93b5baf3 --- /dev/null +++ b/rand_xorshift/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright 2018 Developers of the Rand project +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rand_xorshift/README.md b/rand_xorshift/README.md new file mode 100644 index 000000000..573ee1231 --- /dev/null +++ b/rand_xorshift/README.md @@ -0,0 +1,45 @@ +# rand_xorshift + +[![Build Status](https://travis-ci.org/rust-random/rand.svg)](https://travis-ci.org/rust-random/rand) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand) +[![Latest version](https://img.shields.io/crates/v/rand_xorshift.svg)](https://crates.io/crates/rand_xorshift) +[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/) +[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand_xorshift) +[![API](https://docs.rs/rand_xorshift/badge.svg)](https://docs.rs/rand_xorshift) +[![Minimum rustc version](https://img.shields.io/badge/rustc-1.22+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements) + +Implements the Xorshift random number generator. + +The Xorshift[^1] algorithm is not suitable for cryptographic purposes +but is very fast. If you do not know for sure that it fits your +requirements, use a more secure one such as `StdRng` or `OsRng`. + +[^1]: Marsaglia, George (July 2003). + ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). + *Journal of Statistical Software*. Vol. 8 (Issue 14). + +Links: + +- [API documentation (master)](https://rust-random.github.io/rand/rand_xorshift) +- [API documentation (docs.rs)](https://docs.rs/rand_xorshift) +- [Changelog](CHANGELOG.md) + +[rand]: https://crates.io/crates/rand + + +## Crate Features + +`rand_xorshift` is `no_std` compatible. It does not require any functionality +outside of the `core` lib, thus there are no features to configure. + +The `serde1` feature includes implementations of `Serialize` and `Deserialize` +for the included RNGs. + + +## License + +`rand_xorshift` is distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and +[COPYRIGHT](COPYRIGHT) for details. diff --git a/rand_xorshift/src/lib.rs b/rand_xorshift/src/lib.rs new file mode 100644 index 000000000..aad74e49f --- /dev/null +++ b/rand_xorshift/src/lib.rs @@ -0,0 +1,123 @@ +// Copyright 2018 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The xorshift random number generator. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://rust-random.github.io/rand/")] + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#![no_std] + +extern crate rand_core; + +#[cfg(feature="serde1")] extern crate serde; +#[cfg(feature="serde1")] #[macro_use] extern crate serde_derive; + +use core::num::Wrapping as w; +use core::{fmt, slice}; +use rand_core::{RngCore, SeedableRng, Error, impls, le}; + +/// An Xorshift random number generator. +/// +/// The Xorshift[^1] algorithm is not suitable for cryptographic purposes +/// but is very fast. If you do not know for sure that it fits your +/// requirements, use a more secure one such as `StdRng` or `OsRng`. +/// +/// [^1]: Marsaglia, George (July 2003). +/// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). +/// *Journal of Statistical Software*. Vol. 8 (Issue 14). +#[derive(Clone)] +#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] +pub struct XorShiftRng { + x: w<u32>, + y: w<u32>, + z: w<u32>, + w: w<u32>, +} + +// Custom Debug implementation that does not expose the internal state +impl fmt::Debug for XorShiftRng { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "XorShiftRng {{}}") + } +} + +impl RngCore for XorShiftRng { + #[inline] + fn next_u32(&mut self) -> u32 { + let x = self.x; + let t = x ^ (x << 11); + self.x = self.y; + self.y = self.z; + self.z = self.w; + let w_ = self.w; + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); + self.w.0 + } + + #[inline] + fn next_u64(&mut self) -> u64 { + impls::next_u64_via_u32(self) + } + + #[inline] + fn fill_bytes(&mut self, dest: &mut [u8]) { + impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for XorShiftRng { + type Seed = [u8; 16]; + + fn from_seed(seed: Self::Seed) -> Self { + let mut seed_u32 = [0u32; 4]; + le::read_u32_into(&seed, &mut seed_u32); + + // Xorshift cannot be seeded with 0 and we cannot return an Error, but + // also do not wish to panic (because a random seed can legitimately be + // 0); our only option is therefore to use a preset value. + if seed_u32.iter().all(|&x| x == 0) { + seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; + } + + XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + } + } + + fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { + let mut seed_u32 = [0u32; 4]; + loop { + unsafe { + let ptr = seed_u32.as_mut_ptr() as *mut u8; + + let slice = slice::from_raw_parts_mut(ptr, 4 * 4); + rng.try_fill_bytes(slice)?; + } + if !seed_u32.iter().all(|&x| x == 0) { break; } + } + + Ok(XorShiftRng { + x: w(seed_u32[0]), + y: w(seed_u32[1]), + z: w(seed_u32[2]), + w: w(seed_u32[3]), + }) + } +} diff --git a/rand_xorshift/tests/mod.rs b/rand_xorshift/tests/mod.rs new file mode 100644 index 000000000..8374b6410 --- /dev/null +++ b/rand_xorshift/tests/mod.rs @@ -0,0 +1,92 @@ +extern crate rand_core; +extern crate rand_xorshift; +#[cfg(all(feature="serde1", test))] extern crate bincode; + +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; + +#[test] +fn test_xorshift_construction() { + // Test that various construction techniques produce a working RNG. + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng1 = XorShiftRng::from_seed(seed); + assert_eq!(rng1.next_u64(), 4325440999699518727); + + let _rng2 = XorShiftRng::from_rng(rng1).unwrap(); + // Note: we cannot test the state of _rng2 because from_rng does not + // fix Endianness. This is allowed in the trait specification. +} + +#[test] +fn test_xorshift_true_values() { + let seed = [16,15,14,13, 12,11,10,9, 8,7,6,5, 4,3,2,1]; + let mut rng = XorShiftRng::from_seed(seed); + + let mut results = [0u32; 9]; + for i in results.iter_mut() { *i = rng.next_u32(); } + let expected: [u32; 9] = [ + 2081028795, 620940381, 269070770, 16943764, 854422573, 29242889, + 1550291885, 1227154591, 271695242]; + assert_eq!(results, expected); + + let mut results = [0u64; 9]; + for i in results.iter_mut() { *i = rng.next_u64(); } + let expected: [u64; 9] = [ + 9247529084182843387, 8321512596129439293, 14104136531997710878, + 6848554330849612046, 343577296533772213, 17828467390962600268, + 9847333257685787782, 7717352744383350108, 1133407547287910111]; + assert_eq!(results, expected); + + let mut results = [0u8; 32]; + rng.fill_bytes(&mut results); + let expected = [102, 57, 212, 16, 233, 130, 49, 183, + 158, 187, 44, 203, 63, 149, 45, 17, + 117, 129, 131, 160, 70, 121, 158, 155, + 224, 209, 192, 53, 10, 62, 57, 72]; + assert_eq!(results, expected); +} + +#[test] +fn test_xorshift_zero_seed() { + // Xorshift does not work with an all zero seed. + // Assert it does not panic. + let seed = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; + let mut rng = XorShiftRng::from_seed(seed); + let a = rng.next_u64(); + let b = rng.next_u64(); + assert!(a != 0); + assert!(b != a); +} + +#[test] +fn test_xorshift_clone() { + let seed = [1,2,3,4, 5,5,7,8, 8,7,6,5, 4,3,2,1]; + let mut rng1 = XorShiftRng::from_seed(seed); + let mut rng2 = rng1.clone(); + for _ in 0..16 { + assert_eq!(rng1.next_u64(), rng2.next_u64()); + } +} + +#[cfg(feature="serde1")] +#[test] +fn test_xorshift_serde() { + use bincode; + use std::io::{BufWriter, BufReader}; + + let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16]; + let mut rng = XorShiftRng::from_seed(seed); + + let buf: Vec<u8> = Vec::new(); + let mut buf = BufWriter::new(buf); + bincode::serialize_into(&mut buf, &rng).expect("Could not serialize"); + + let buf = buf.into_inner().unwrap(); + let mut read = BufReader::new(&buf[..]); + let mut deserialized: XorShiftRng = bincode::deserialize_from(&mut read) + .expect("Could not deserialize"); + + for _ in 0..16 { + assert_eq!(rng.next_u64(), deserialized.next_u64()); + } +} diff --git a/rdrand/.cargo-checksum.json b/rdrand/.cargo-checksum.json new file mode 100644 index 000000000..8e05e40f0 --- /dev/null +++ b/rdrand/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"} \ No newline at end of file diff --git a/rdrand/Cargo.toml b/rdrand/Cargo.toml new file mode 100644 index 000000000..6b3c80a87 --- /dev/null +++ b/rdrand/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rdrand" +version = "0.4.0" +authors = ["Simonas Kazlauskas <rdrand@kazlauskas.me>"] +description = "An implementation of random number generator based on rdrand and rdseed instructions" +documentation = "https://docs.rs/rdrand/0.4.0/" +keywords = ["rand", "rdrand", "rdseed", "random"] +license = "ISC" +repository = "https://github.com/nagisa/rust_rdrand/" +[dependencies.rand_core] +version = "0.3" +default-features = false + +[features] +default = ["std"] +std = [] diff --git a/rdrand/LICENSE b/rdrand/LICENSE new file mode 100644 index 000000000..4d6f40d43 --- /dev/null +++ b/rdrand/LICENSE @@ -0,0 +1,12 @@ +Copyright © 2014, Simonas Kazlauskas + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without +fee is hereby granted, provided that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/rdrand/README.mkd b/rdrand/README.mkd new file mode 100644 index 000000000..55ab48b8e --- /dev/null +++ b/rdrand/README.mkd @@ -0,0 +1,8 @@ +An implementation of random number generators based on `rdrand` and `rdseed` instructions. + +The random number generators provided by this crate are fairly slow (the latency for these +instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s +nor Intel’s designs are public and therefore are not verifiable for lack of backdoors. + +Unless you know what you are doing, use the random number generators provided by the `rand` +crate (such as `EntropyRng`) instead. diff --git a/rdrand/appveyor.yml b/rdrand/appveyor.yml new file mode 100644 index 000000000..2e915cf4f --- /dev/null +++ b/rdrand/appveyor.yml @@ -0,0 +1,27 @@ +environment: + matrix: + - TARGET: 1.30.0-x86_64-pc-windows-msvc + - TARGET: 1.30.0-i686-pc-windows-msvc + - TARGET: 1.30.0-x86_64-pc-windows-gnu + - TARGET: 1.30.0-i686-pc-windows-gnu + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust.exe" + - ps: .\rust.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - rustc -vV + - cargo -vV +build: off + +test_script: +- cargo test +- cargo test --no-default-features + +for: +- matrix: + only: + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + test_script: + - cargo bench diff --git a/rdrand/benches/rdrand.rs b/rdrand/benches/rdrand.rs new file mode 100644 index 000000000..7e70c233e --- /dev/null +++ b/rdrand/benches/rdrand.rs @@ -0,0 +1,49 @@ +#![feature(test)] +extern crate rand_core; +extern crate rdrand; +extern crate test; + +use rand_core::RngCore; +use test::Bencher; + +#[bench] +fn bench_u16(b : &mut Bencher) { + if let Ok(gen) = rdrand::RdRand::new() { + b.bytes = 2; + b.iter(|| { + gen.try_next_u16().unwrap() + }); + } +} + +#[bench] +fn bench_u32(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + b.bytes = 4; + b.iter(|| { + gen.next_u32() + }); + } +} + +#[bench] +fn bench_u64(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + b.bytes = 8; + b.iter(|| { + gen.next_u64() + }); + } +} + +#[bench] +fn bench_fill(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdRand::new() { + let mut buffer = [0; 128]; + b.bytes = 128; + b.iter(|| { + gen.fill_bytes(&mut buffer); + buffer + }); + } +} diff --git a/rdrand/benches/rdseed.rs b/rdrand/benches/rdseed.rs new file mode 100644 index 000000000..6bf8cebf9 --- /dev/null +++ b/rdrand/benches/rdseed.rs @@ -0,0 +1,49 @@ +#![feature(test)] +extern crate rand_core; +extern crate rdrand; +extern crate test; + +use rand_core::RngCore; +use test::Bencher; + +#[bench] +fn bench_rdseed_u16(b : &mut Bencher) { + if let Ok(gen) = rdrand::RdSeed::new() { + b.bytes = 2; + b.iter(|| { + gen.try_next_u16().unwrap() + }); + } +} + +#[bench] +fn bench_rdseed_u32(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + b.bytes = 4; + b.iter(|| { + gen.next_u32() + }); + } +} + +#[bench] +fn bench_rdseed_u64(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + b.bytes = 8; + b.iter(|| { + gen.next_u64() + }); + } +} + +#[bench] +fn bench_fill(b : &mut Bencher) { + if let Ok(mut gen) = rdrand::RdSeed::new() { + let mut buffer = [0; 128]; + b.bytes = 128; + b.iter(|| { + gen.fill_bytes(&mut buffer); + buffer + }); + } +} diff --git a/rdrand/benches/std.rs b/rdrand/benches/std.rs new file mode 100644 index 000000000..3fa8fadd9 --- /dev/null +++ b/rdrand/benches/std.rs @@ -0,0 +1,31 @@ +// #![feature(test)] +// extern crate rand; +// extern crate test; +// +// use test::Bencher; +// use test::black_box; +// use rand::Rng; +// use rand::StdRng; +// use rand::OsRng; +// +// // OsRng is supposed to be the default for crypto uses. +// #[bench] +// fn bench_osrng_u64(b : &mut Bencher) { +// if let Ok(mut gen) = OsRng::new() { +// b.bytes = 8; +// b.iter(|| { +// black_box(gen.next_u64()); +// }); +// } +// } +// +// // StdRng is the default for everything else. +// #[bench] +// fn bench_stdrng_u64(b : &mut Bencher) { +// if let Ok(mut gen) = StdRng::new() { +// b.bytes = 8; +// b.iter(|| { +// gen.next_u64(); +// }); +// } +// } diff --git a/rdrand/src/changelog.rs b/rdrand/src/changelog.rs new file mode 100644 index 000000000..503f73810 --- /dev/null +++ b/rdrand/src/changelog.rs @@ -0,0 +1,25 @@ +//! Project changelog + +/// ## Breaking changes +/// +/// Crate gained an enabled-by-default `std` feature. If you relied on rdrand being `core`-able +/// change your dependency to appear as such: +/// +/// ```toml +/// rdrand = { version = "0.4", default-features = false } +/// ``` +/// +/// This is done so that an advantage of the common feature detection functionality could be +/// employed by users that are not constrained by `core`. This functionality is faster, caches the +/// results and is shared between all users of the functionality. +/// +/// For `core` usage the feature detection has also been improved and will not be done if e.g. +/// crate is built with `rdrand` instructions enabled globally. +pub mod r0_4_0 {} + +/// Crate now works on stable! +/// +/// ## Breaking changes +/// +/// * Updated to `rand_core = ^0.3`. +pub mod r0_3_0 {} diff --git a/rdrand/src/lib.rs b/rdrand/src/lib.rs new file mode 100644 index 000000000..423ae2139 --- /dev/null +++ b/rdrand/src/lib.rs @@ -0,0 +1,472 @@ +// Copyright © 2014, Simonas Kazlauskas <rdrand@kazlauskas.me> +// +// Permission to use, copy, modify, and/or distribute this software for any purpose with or without +// fee is hereby granted, provided that the above copyright notice and this permission notice +// appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +// SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +// OF THIS SOFTWARE. +//! An implementation of random number generators based on `rdrand` and `rdseed` instructions. +//! +//! The random number generators provided by this crate are fairly slow (the latency for these +//! instructions is pretty high), but provide high quality random bits. Caveat is: neither AMD’s +//! nor Intel’s designs are public and therefore are not verifiable for lack of backdoors. +//! +//! Unless you know what you are doing, use the random number generators provided by the `rand` +//! crate (such as `OsRng`) instead. +//! +//! Here are a measurements for select processor architectures. Check [Agner’s instruction tables] +//! for up-to-date listings. +//! +//! <table> +//! <tr> +//! <th>Architecture</th> +//! <th colspan="3">Latency (cycles)</th> +//! <th>Maximum throughput (per core)</th> +//! </tr> +//! <tr> +//! <td></td> +//! <td>u16</td> +//! <td>u32</td> +//! <td>u64</td> +//! <td></td> +//! </tr> +//! <tr> +//! <td>AMD Ryzen</td> +//! <td>~1200</td> +//! <td>~1200</td> +//! <td>~2500</td> +//! <td>~12MB/s @ 3.7GHz</td> +//! </tr> +//! <tr> +//! <td>Intel Skylake</td> +//! <td>460</td> +//! <td>460</td> +//! <td>460</td> +//! <td>~72MB/s @ 4.2GHz</td> +//! </tr> +//! <tr> +//! <td>Intel Haswell</td> +//! <td>320</td> +//! <td>320</td> +//! <td>320</td> +//! <td>~110MB/s @ 4.4GHz</td> +//! </tr> +//! </table> +//! +//! [Agner’s instruction tables]: http://agner.org/optimize/ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate rand_core; + +#[cfg(feature = "std")] +extern crate core; + +pub mod changelog; + +use rand_core::{RngCore, CryptoRng, Error, ErrorKind}; +use core::slice; + +const RETRY_LIMIT: u8 = 127; + +#[cold] +#[inline(never)] +pub(crate) fn busy_loop_fail() -> ! { + panic!("hardware generator failure"); +} + +/// A cryptographically secure statistically uniform, non-periodic and non-deterministic random bit +/// generator. +/// +/// Note that this generator may be implemented using a deterministic algorithm that is reseeded +/// routinely from a non-deterministic entropy source to achieve the desirable properties. +/// +/// This generator is a viable replacement to any generator, however, since nobody has audited +/// Intel or AMD hardware yet, the usual disclaimers as to their suitability apply. +/// +/// It is potentially faster than `OsRng`, but is only supported on more recent Intel (Ivy Bridge +/// and later) and AMD (Ryzen and later) processors. +#[derive(Clone, Copy)] +pub struct RdRand(()); + +/// A cryptographically secure non-deterministic random bit generator. +/// +/// This generator produces high-entropy output and is suited to seed other pseudo-random +/// generators. +/// +/// This instruction currently is only available in Intel Broadwell (and later) and AMD Ryzen +/// processors. +/// +/// This generator is not intended for general random number generation purposes and should be used +/// to seed other generators implementing [rand_core::SeedableRng]. +#[derive(Clone, Copy)] +pub struct RdSeed(()); + +impl CryptoRng for RdRand {} +impl CryptoRng for RdSeed {} + +mod arch { + #[cfg(target_arch = "x86_64")] + pub use core::arch::x86_64::*; + #[cfg(target_arch = "x86")] + pub use core::arch::x86::*; + + #[cfg(target_arch = "x86")] + pub(crate) unsafe fn _rdrand64_step(dest: &mut u64) -> i32 { + let mut ret1: u32 = ::core::mem::uninitialized(); + let mut ret2: u32 = ::core::mem::uninitialized(); + if _rdrand32_step(&mut ret1) != 0 && _rdrand32_step(&mut ret2) != 0 { + *dest = (ret1 as u64) << 32 | (ret2 as u64); + 1 + } else { + 0 + } + } + + #[cfg(target_arch = "x86")] + pub(crate) unsafe fn _rdseed64_step(dest: &mut u64) -> i32 { + let mut ret1: u32 = ::core::mem::uninitialized(); + let mut ret2: u32 = ::core::mem::uninitialized(); + if _rdseed32_step(&mut ret1) != 0 && _rdseed32_step(&mut ret2) != 0 { + *dest = (ret1 as u64) << 32 | (ret2 as u64); + 1 + } else { + 0 + } + } +} + +#[cfg(not(feature = "std"))] +macro_rules! is_x86_feature_detected { + ("rdrand") => {{ + if cfg!(target_feature="rdrand") { + true + } else if cfg!(target_env = "sgx") { + false + } else { + const FLAG : u32 = 1 << 30; + unsafe { ::arch::__cpuid(1).ecx & FLAG == FLAG } + } + }}; + ("rdseed") => {{ + if cfg!(target_feature = "rdseed") { + true + } else if cfg!(target_env = "sgx") { + false + } else { + const FLAG : u32 = 1 << 18; + unsafe { ::arch::__cpuid(7).ebx & FLAG == FLAG } + } + }}; +} + +macro_rules! loop_rand { + ($el: ty, $step: path) => { { + let mut idx = 0; + loop { + let mut el: $el = ::core::mem::uninitialized(); + if $step(&mut el) != 0 { + break Some(el); + } else if idx == RETRY_LIMIT { + break None; + } + idx += 1; + } + } } +} + +macro_rules! impl_rand { + ($gen:ident, $feat:tt, $step16: path, $step32:path, $step64:path, + maxstep = $maxstep:path, maxty = $maxty: ty) => { + impl $gen { + /// Create a new instance of the random number generator. + /// + /// This constructor checks whether the CPU the program is running on supports the + /// instruction necessary for this generator to operate. If the instruction is not + /// supported, an error is returned. + pub fn new() -> Result<Self, Error> { + if is_x86_feature_detected!($feat) { + Ok($gen(())) + } else { + Err(Error::new(rand_core::ErrorKind::Unavailable, + "the instruction is not supported")) + } + } + + /// Generate a single random `u16` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + pub fn try_next_u16(&self) -> Option<u16> { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option<u16> { + loop_rand!(u16, $step16) + } + unsafe { imp() } + } + + /// Generate a single random `u32` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + pub fn try_next_u32(&self) -> Option<u32> { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option<u32> { + loop_rand!(u32, $step32) + } + unsafe { imp() } + } + + /// Generate a single random `u64` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return `None`. + /// + /// In case `None` is returned, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + /// + /// Note, that on 32-bit targets, there’s no underlying instruction to generate a + /// 64-bit number, so it is emulated with the 32-bit version of the instruction. + #[inline(always)] + pub fn try_next_u64(&self) -> Option<u64> { + #[target_feature(enable = $feat)] + unsafe fn imp() + -> Option<u64> { + loop_rand!(u64, $step64) + } + unsafe { imp() } + } + } + + impl RngCore for $gen { + /// Generate a single random `u32` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// # Panic + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will `panic`. + /// + /// In case `panic` occurs, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if let Some(result) = self.try_next_u32() { + result + } else { + busy_loop_fail() + } + } + + /// Generate a single random `u64` value. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// Note, that on 32-bit targets, there’s no underlying instruction to generate a + /// 64-bit number, so it is emulated with the 32-bit version of the instruction. + /// + /// # Panic + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will `panic`. + /// + /// In case `panic` occurs, the caller should assume that an non-recoverable + /// hardware failure has occured and use another random number genrator instead. + #[inline(always)] + fn next_u64(&mut self) -> u64 { + if let Some(result) = self.try_next_u64() { + result + } else { + busy_loop_fail() + } + } + + /// Fill a buffer `dest` with random data. + /// + /// See `try_fill_bytes` for a more extensive documentation. + /// + /// # Panic + /// + /// This method will panic any time `try_fill_bytes` would return an error. + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + if let Err(_) = self.try_fill_bytes(dest) { + busy_loop_fail() + } + } + + /// Fill a buffer `dest` with random data. + /// + /// This method will use the most appropriate variant of the instruction available on + /// the machine to achieve the greatest single-core throughput, however it has a + /// slightly higher setup cost than the plain `next_u32` or `next_u64` methods. + /// + /// The underlying instruction may fail for variety reasons (such as actual hardware + /// failure or exhausted entropy), however the exact reason for the failure is not + /// usually exposed. + /// + /// This method will retry calling the instruction a few times, however if all the + /// attempts fail, it will return an error. + /// + /// If an error is returned, the caller should assume that an non-recoverable hardware + /// failure has occured and use another random number genrator instead. + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) + -> Result<(), Error> { + #[target_feature(enable = $feat)] + unsafe fn imp(dest: &mut [u8]) + -> Result<(), Error> + { + unsafe fn imp_less_fast(mut dest: &mut [u8], word: &mut $maxty, + buffer: &mut &[u8]) + -> Result<(), Error> + { + while !dest.is_empty() { + if buffer.is_empty() { + if let Some(w) = loop_rand!($maxty, $maxstep) { + *word = w; + *buffer = slice::from_raw_parts( + word as *const _ as *const u8, + ::core::mem::size_of::<$maxty>() + ); + } else { + return Err(Error::new(ErrorKind::Unexpected, + "hardware generator failure")); + } + } + + let len = dest.len().min(buffer.len()); + let (copy_src, leftover) = buffer.split_at(len); + let (copy_dest, dest_leftover) = { dest }.split_at_mut(len); + *buffer = leftover; + dest = dest_leftover; + ::core::ptr::copy_nonoverlapping( + copy_src.as_ptr(), copy_dest.as_mut_ptr(), len + ); + } + Ok(()) + } + + let destlen = dest.len(); + if destlen > ::core::mem::size_of::<$maxty>() { + let (left, mid, right) = dest.align_to_mut(); + let mut word = 0; + let mut buffer: &[u8] = &[]; + + for el in mid { + if let Some(val) = loop_rand!($maxty, $maxstep) { + *el = val; + } else { + return Err(Error::new(ErrorKind::Unexpected, + "hardware generator failure")); + } + } + + imp_less_fast(left, &mut word, &mut buffer)?; + imp_less_fast(right, &mut word, &mut buffer) + } else { + let mut word = 0; + let mut buffer: &[u8] = &[]; + imp_less_fast(dest, &mut word, &mut buffer) + } + } + unsafe { imp(dest) } + } + } + } +} + +#[cfg(target_arch = "x86_64")] +impl_rand!(RdRand, "rdrand", + ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step, + maxstep = ::arch::_rdrand64_step, maxty = u64); +#[cfg(target_arch = "x86_64")] +impl_rand!(RdSeed, "rdseed", + ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step, + maxstep = ::arch::_rdseed64_step, maxty = u64); +#[cfg(target_arch = "x86")] +impl_rand!(RdRand, "rdrand", + ::arch::_rdrand16_step, ::arch::_rdrand32_step, ::arch::_rdrand64_step, + maxstep = ::arch::_rdrand32_step, maxty = u32); +#[cfg(target_arch = "x86")] +impl_rand!(RdSeed, "rdseed", + ::arch::_rdseed16_step, ::arch::_rdseed32_step, ::arch::_rdseed64_step, + maxstep = ::arch::_rdseed32_step, maxty = u32); + +#[test] +fn rdrand_works() { + let _ = RdRand::new().map(|mut r| { + r.next_u32(); + r.next_u64(); + }); +} + +#[test] +fn fill_fills_all_bytes() { + let _ = RdRand::new().map(|mut r| { + let mut peach; + let mut banana; + let mut start = 0; + let mut end = 128; + 'outer: while start < end { + banana = [0; 128]; + for _ in 0..512 { + peach = [0; 128]; + r.fill_bytes(&mut peach[start..end]); + for (b, p) in banana.iter_mut().zip(peach.iter()) { + *b = *b | *p; + } + if (&banana[start..end]).iter().all(|x| *x != 0) { + assert!(banana[..start].iter().all(|x| *x == 0), "all other values must be 0"); + assert!(banana[end..].iter().all(|x| *x == 0), "all other values must be 0"); + if start < 17 { + start += 1; + } else { + end -= 3; + } + continue 'outer; + } + } + panic!("wow, we broke it? {} {} {:?}", start, end, &banana[..]) + } + }); +} + +#[test] +fn rdseed_works() { + let _ = RdSeed::new().map(|mut r| { + r.next_u32(); + r.next_u64(); + }); +} diff --git a/redox_syscall/.cargo-checksum.json b/redox_syscall/.cargo-checksum.json new file mode 100644 index 000000000..952508229 --- /dev/null +++ b/redox_syscall/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"} \ No newline at end of file diff --git a/redox_syscall/Cargo.toml b/redox_syscall/Cargo.toml new file mode 100644 index 000000000..d7bd8cc6c --- /dev/null +++ b/redox_syscall/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "redox_syscall" +version = "0.1.54" +authors = ["Jeremy Soller <jackpot51@gmail.com>"] +description = "A Rust library to access raw Redox system calls" +documentation = "https://docs.rs/redox_syscall" +license = "MIT" +repository = "https://gitlab.redox-os.org/redox-os/syscall" + +[lib] +name = "syscall" diff --git a/redox_syscall/LICENSE b/redox_syscall/LICENSE new file mode 100644 index 000000000..1292bb7fb --- /dev/null +++ b/redox_syscall/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2017 Redox OS Developers + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/redox_syscall/README.md b/redox_syscall/README.md new file mode 100644 index 000000000..244c90861 --- /dev/null +++ b/redox_syscall/README.md @@ -0,0 +1,6 @@ +# syscall +[Redox OS](https://gitlab.redox-os.org/redox-os/redox)'s syscall API + +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) +[![crates.io](http://meritbadge.herokuapp.com/redox_syscall)](https://crates.io/crates/redox_syscall) +[![docs.rs](https://docs.rs/redox_syscall/badge.svg)](https://docs.rs/redox_syscall) diff --git a/redox_syscall/src/arch/aarch64.rs b/redox_syscall/src/arch/aarch64.rs new file mode 100644 index 000000000..662f428d0 --- /dev/null +++ b/redox_syscall/src/arch/aarch64.rs @@ -0,0 +1,77 @@ +use super::error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a) + : "x0", "x8" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b) + : "x0", "x8" + : "volatile"); + + Error::demux(a) +} + +// Clobbers all registers - special for clone +pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b) + : "memory", + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", + "x16", "x17","x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b), "{x1}"(c) + : "x0", "x1", "x8" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d) + : "x0", "x1", "x2", "x8" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e) + : "x0", "x1", "x2", "x3", "x8" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result<usize> { + asm!("svc 0" + : "={x0}"(a) + : "{x8}"(a), "{x0}"(b), "{x1}"(c), "{x2}"(d), "{x3}"(e), "{x4}"(f) + : "x0", "x1", "x2", "x3", "x4", "x8" + : "volatile"); + + Error::demux(a) +} diff --git a/redox_syscall/src/arch/arm.rs b/redox_syscall/src/arch/arm.rs new file mode 100644 index 000000000..e640f7ed3 --- /dev/null +++ b/redox_syscall/src/arch/arm.rs @@ -0,0 +1,73 @@ +use super::error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a) + : "memory" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b) + : "memory" + : "volatile"); + + Error::demux(a) +} + +// Clobbers all registers - special for clone +pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b) + : "memory", "r0", "r1", "r2", "r3", "r4" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b), "{r1}"(c) + : "memory" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d) + : "memory" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e) + : "memory" + : "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result<usize> { + asm!("swi $$0" + : "={r0}"(a) + : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f) + : "memory" + : "volatile"); + + Error::demux(a) +} diff --git a/redox_syscall/src/arch/x86.rs b/redox_syscall/src/arch/x86.rs new file mode 100644 index 000000000..0cd6409bb --- /dev/null +++ b/redox_syscall/src/arch/x86.rs @@ -0,0 +1,73 @@ +use super::error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +// Clobbers all registers - special for clone +pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b) + : "memory", "ebx", "ecx", "edx", "esi", "edi" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result<usize> { + asm!("int 0x80" + : "={eax}"(a) + : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f) + : "memory" + : "intel", "volatile"); + + Error::demux(a) +} diff --git a/redox_syscall/src/arch/x86_64.rs b/redox_syscall/src/arch/x86_64.rs new file mode 100644 index 000000000..76c3da130 --- /dev/null +++ b/redox_syscall/src/arch/x86_64.rs @@ -0,0 +1,74 @@ +use super::error::{Error, Result}; + +pub unsafe fn syscall0(mut a: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +// Clobbers all registers - special for clone +pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b) + : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", + "r9", "r10", "r11", "r12", "r13", "r14", "r15" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b), "{rsi}"(c) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d), "{r10}"(e) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} + +pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) + -> Result<usize> { + asm!("syscall" + : "={rax}"(a) + : "{rax}"(a), "{rdi}"(b), "{rsi}"(c), "{rdx}"(d), "{r10}"(e), "{r8}"(f) + : "rcx", "r11", "memory" + : "intel", "volatile"); + + Error::demux(a) +} diff --git a/redox_syscall/src/call.rs b/redox_syscall/src/call.rs new file mode 100644 index 000000000..aff381a9b --- /dev/null +++ b/redox_syscall/src/call.rs @@ -0,0 +1,389 @@ +use super::arch::*; +use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec}; +use super::error::Result; +use super::number::*; + +use core::{mem, ptr}; + +// Signal restorer +extern "C" fn restorer() -> ! { + sigreturn().unwrap(); + unreachable!(); +} + +/// Set the end of the process's heap +/// +/// When `addr` is `0`, this function will return the current break. +/// +/// When `addr` is nonzero, this function will attempt to set the end of the process's +/// heap to `addr` and return the new program break. The new program break should be +/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page +/// boundary. +/// +/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available +pub unsafe fn brk(addr: usize) -> Result<usize> { + syscall1(SYS_BRK, addr) +} + +/// Change the process's working directory +/// +/// This function will attempt to set the process's working directory to `path`, which can be +/// either a relative, scheme relative, or absolute path. +/// +/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned. +/// +/// # Errors +/// +/// * `EACCES` - permission is denied for one of the components of `path`, or `path` +/// * `EFAULT` - `path` does not point to the process's addressible memory +/// * `EIO` - an I/O error occurred +/// * `ENOENT` - `path` does not exit +/// * `ENOTDIR` - `path` is not a directory +pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> { + unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> { + unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) } +} + +/// Produce a fork of the current process, or a new process thread +pub unsafe fn clone(flags: usize) -> Result<usize> { + syscall1_clobber(SYS_CLONE, flags) +} + +/// Close a file +pub fn close(fd: usize) -> Result<usize> { + unsafe { syscall1(SYS_CLOSE, fd) } +} + +/// Get the current system time +pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> { + unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } +} + +/// Copy and transform a file descriptor +pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> { + unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + +/// Exit the current process +pub fn exit(status: usize) -> Result<usize> { + unsafe { syscall1(SYS_EXIT, status) } +} + +/// Change file permissions +pub fn fchmod(fd: usize, mode: u16) -> Result<usize> { + unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } + +} + +/// Change file ownership +pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> { + unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } + +} + +/// Change file descriptor flags +pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> { + unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } +} + +/// Replace the current process with a new executable +pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> { + unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), vars.as_ptr() as usize, vars.len()) } +} + +/// Map a file into memory +pub unsafe fn fmap(fd: usize, map: &Map) -> Result<usize> { + syscall3(SYS_FMAP, fd, map as *const Map as usize, mem::size_of::<Map>()) +} + +/// Unmap a memory-mapped file +pub unsafe fn funmap(addr: usize) -> Result<usize> { + syscall1(SYS_FUNMAP, addr) +} + +/// Retrieve the canonical path of a file +pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> { + unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Rename a file +pub fn frename<T: AsRef<[u8]>>(fd: usize, path: T) -> Result<usize> { + unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Get metadata about a file +pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> { + unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) } +} + +/// Get metadata about a filesystem +pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> { + unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) } +} + +/// Sync a file descriptor to its underlying medium +pub fn fsync(fd: usize) -> Result<usize> { + unsafe { syscall1(SYS_FSYNC, fd) } +} + +/// Truncate or extend a file to a specified length +pub fn ftruncate(fd: usize, len: usize) -> Result<usize> { + unsafe { syscall2(SYS_FTRUNCATE, fd, len) } +} + +// Change modify and/or access times +pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> { + unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize, times.len() * mem::size_of::<TimeSpec>()) } +} + +/// Fast userspace mutex +pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32) + -> Result<usize> { + syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize) +} + +/// Get the current working directory +pub fn getcwd(buf: &mut [u8]) -> Result<usize> { + unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Get the effective group ID +pub fn getegid() -> Result<usize> { + unsafe { syscall0(SYS_GETEGID) } +} + +/// Get the effective namespace +pub fn getens() -> Result<usize> { + unsafe { syscall0(SYS_GETENS) } +} + +/// Get the effective user ID +pub fn geteuid() -> Result<usize> { + unsafe { syscall0(SYS_GETEUID) } +} + +/// Get the current group ID +pub fn getgid() -> Result<usize> { + unsafe { syscall0(SYS_GETGID) } +} + +/// Get the current namespace +pub fn getns() -> Result<usize> { + unsafe { syscall0(SYS_GETNS) } +} + +/// Get the current process ID +pub fn getpid() -> Result<usize> { + unsafe { syscall0(SYS_GETPID) } +} + +/// Get the process group ID +pub fn getpgid(pid: usize) -> Result<usize> { + unsafe { syscall1(SYS_GETPGID, pid) } +} + +/// Get the parent process ID +pub fn getppid() -> Result<usize> { + unsafe { syscall0(SYS_GETPPID) } +} + +/// Get the current user ID +pub fn getuid() -> Result<usize> { + unsafe { syscall0(SYS_GETUID) } +} + +/// Set the I/O privilege level +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EINVAL` - `level > 3` +pub unsafe fn iopl(level: usize) -> Result<usize> { + syscall1(SYS_IOPL, level) +} + +/// Send a signal `sig` to the process identified by `pid` +pub fn kill(pid: usize, sig: usize) -> Result<usize> { + unsafe { syscall2(SYS_KILL, pid, sig) } +} + +/// Create a link to a file +pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> { + syscall2(SYS_LINK, old as usize, new as usize) +} + +/// Seek to `offset` bytes in a file descriptor +pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> { + unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } +} + +/// Make a new scheme namespace +pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> { + unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } +} + +/// Change mapping flags +pub unsafe fn mprotect(addr: usize, size: usize, flags: usize) -> Result<usize> { + syscall3(SYS_MPROTECT, addr, size, flags) +} + +/// Sleep for the time specified in `req` +pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> { + unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize, + rem as *mut TimeSpec as usize) } +} + +/// Open a file +pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> { + unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) } +} + +/// Allocate pages, linearly in physical memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `ENOMEM` - the system has run out of available memory +pub unsafe fn physalloc(size: usize) -> Result<usize> { + syscall1(SYS_PHYSALLOC, size) +} + +/// Free physically allocated pages +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> { + syscall2(SYS_PHYSFREE, physical_address, size) +} + +/// Map physical memory to virtual memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { + syscall3(SYS_PHYSMAP, physical_address, size, flags) +} + +/// Unmap previously mapped physical memory +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +/// * `EFAULT` - `virtual_address` has not been mapped +pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> { + syscall1(SYS_PHYSUNMAP, virtual_address) +} + +/// Create a pair of file descriptors referencing the read and write ends of a pipe +pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> { + unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) } +} + +/// Read from a file descriptor into a buffer +pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> { + unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } +} + +/// Remove a directory +pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> { + unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Set the process group ID +pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> { + unsafe { syscall2(SYS_SETPGID, pid, pgid) } +} + +/// Set the current process group IDs +pub fn setregid(rgid: usize, egid: usize) -> Result<usize> { + unsafe { syscall2(SYS_SETREGID, rgid, egid) } +} + +/// Make a new scheme namespace +pub fn setrens(rns: usize, ens: usize) -> Result<usize> { + unsafe { syscall2(SYS_SETRENS, rns, ens) } +} + +/// Set the current process user IDs +pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> { + unsafe { syscall2(SYS_SETREUID, ruid, euid) } +} + +/// Set up a signal handler +pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>) -> Result<usize> { + unsafe { syscall4(SYS_SIGACTION, sig, + act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize, + restorer as usize) } +} + +/// Get and/or set signal masks +pub fn sigprocmask(how: usize, set: Option<&[u64; 2]>, oldset: Option<&mut [u64; 2]>) -> Result<usize> { + unsafe { syscall3(SYS_SIGPROCMASK, how, + set.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize, + oldset.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize) } +} + +// Return from signal handler +pub fn sigreturn() -> Result<usize> { + unsafe { syscall0(SYS_SIGRETURN) } +} + +/// Set the file mode creation mask +pub fn umask(mask: usize) -> Result<usize> { + unsafe { syscall1(SYS_UMASK, mask) } +} + +/// Remove a file +pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> { + unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) } +} + +/// Convert a virtual address to a physical one +/// +/// # Errors +/// +/// * `EPERM` - `uid != 0` +pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> { + syscall1(SYS_VIRTTOPHYS, virtual_address) +} + +/// Check if a child process has exited or received a signal +pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> { + unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) } +} + +/// Write a buffer to a file descriptor +/// +/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning +/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which +/// were written. +/// +/// # Errors +/// +/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block +/// * `EBADF` - the file descriptor is not valid or is not open for writing +/// * `EFAULT` - `buf` does not point to the process's addressible memory +/// * `EIO` - an I/O error occurred +/// * `ENOSPC` - the device containing the file descriptor has no room for data +/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed +pub fn write(fd: usize, buf: &[u8]) -> Result<usize> { + unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } +} + +/// Yield the process's time slice to the kernel +/// +/// This function will return Ok(0) on success +pub fn sched_yield() -> Result<usize> { + unsafe { syscall0(SYS_YIELD) } +} diff --git a/redox_syscall/src/data.rs b/redox_syscall/src/data.rs new file mode 100644 index 000000000..89e3b9efa --- /dev/null +++ b/redox_syscall/src/data.rs @@ -0,0 +1,219 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, slice}; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Event { + pub id: usize, + pub flags: usize, + pub data: usize +} + +impl Deref for Event { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::<Event>()) as &[u8] + } + } +} + +impl DerefMut for Event { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::<Event>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct ITimerSpec { + pub it_interval: TimeSpec, + pub it_value: TimeSpec, +} + +impl Deref for ITimerSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const ITimerSpec as *const u8, + mem::size_of::<ITimerSpec>()) as &[u8] + } + } +} + +impl DerefMut for ITimerSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut ITimerSpec as *mut u8, + mem::size_of::<ITimerSpec>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Map { + pub offset: usize, + pub size: usize, + pub flags: usize, +} + +impl Deref for Map { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::<Map>()) as &[u8] + } + } +} + +impl DerefMut for Map { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::<Map>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Packet { + pub id: u64, + pub pid: usize, + pub uid: u32, + pub gid: u32, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + +impl Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::<Packet>()) as &[u8] + } + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::<Packet>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct SigAction { + pub sa_handler: extern "C" fn(usize), + pub sa_mask: [u64; 2], + pub sa_flags: usize, +} + +impl Default for SigAction { + fn default() -> Self { + Self { + sa_handler: unsafe { mem::transmute(0usize) }, + sa_mask: [0; 2], + sa_flags: 0, + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct Stat { + pub st_dev: u64, + pub st_ino: u64, + pub st_mode: u16, + pub st_nlink: u32, + pub st_uid: u32, + pub st_gid: u32, + pub st_size: u64, + pub st_blksize: u32, + pub st_blocks: u64, + pub st_mtime: u64, + pub st_mtime_nsec: u32, + pub st_atime: u64, + pub st_atime_nsec: u32, + pub st_ctime: u64, + pub st_ctime_nsec: u32, +} + +impl Deref for Stat { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Stat as *const u8, + mem::size_of::<Stat>()) as &[u8] + } + } +} + +impl DerefMut for Stat { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Stat as *mut u8, + mem::size_of::<Stat>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct StatVfs { + pub f_bsize: u32, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, +} + +impl Deref for StatVfs { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const StatVfs as *const u8, + mem::size_of::<StatVfs>()) as &[u8] + } + } +} + +impl DerefMut for StatVfs { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8, + mem::size_of::<StatVfs>()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} + +impl Deref for TimeSpec { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const TimeSpec as *const u8, + mem::size_of::<TimeSpec>()) as &[u8] + } + } +} + +impl DerefMut for TimeSpec { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8, + mem::size_of::<TimeSpec>()) as &mut [u8] + } + } +} diff --git a/redox_syscall/src/error.rs b/redox_syscall/src/error.rs new file mode 100644 index 000000000..fde4796a4 --- /dev/null +++ b/redox_syscall/src/error.rs @@ -0,0 +1,311 @@ +use core::{fmt, result}; + +#[derive(Eq, PartialEq)] +pub struct Error { + pub errno: i32, +} + +pub type Result<T> = result::Result<T, Error>; + +impl Error { + pub fn new(errno: i32) -> Error { + Error { errno: errno } + } + + pub fn mux(result: Result<usize>) -> usize { + match result { + Ok(value) => value, + Err(error) => -error.errno as usize, + } + } + + pub fn demux(value: usize) -> Result<usize> { + let errno = -(value as i32); + if errno >= 1 && errno < STR_ERROR.len() as i32 { + Err(Error::new(errno)) + } else { + Ok(value) + } + } + + pub fn text(&self) -> &'static str { + STR_ERROR.get(self.errno as usize).map(|&x| x).unwrap_or("Unknown Error") + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + f.write_str(self.text()) + } +} + +pub const EPERM: i32 = 1; /* Operation not permitted */ +pub const ENOENT: i32 = 2; /* No such file or directory */ +pub const ESRCH: i32 = 3; /* No such process */ +pub const EINTR: i32 = 4; /* Interrupted system call */ +pub const EIO: i32 = 5; /* I/O error */ +pub const ENXIO: i32 = 6; /* No such device or address */ +pub const E2BIG: i32 = 7; /* Argument list too long */ +pub const ENOEXEC: i32 = 8; /* Exec format error */ +pub const EBADF: i32 = 9; /* Bad file number */ +pub const ECHILD: i32 = 10; /* No child processes */ +pub const EAGAIN: i32 = 11; /* Try again */ +pub const ENOMEM: i32 = 12; /* Out of memory */ +pub const EACCES: i32 = 13; /* Permission denied */ +pub const EFAULT: i32 = 14; /* Bad address */ +pub const ENOTBLK: i32 = 15; /* Block device required */ +pub const EBUSY: i32 = 16; /* Device or resource busy */ +pub const EEXIST: i32 = 17; /* File exists */ +pub const EXDEV: i32 = 18; /* Cross-device link */ +pub const ENODEV: i32 = 19; /* No such device */ +pub const ENOTDIR: i32 = 20; /* Not a directory */ +pub const EISDIR: i32 = 21; /* Is a directory */ +pub const EINVAL: i32 = 22; /* Invalid argument */ +pub const ENFILE: i32 = 23; /* File table overflow */ +pub const EMFILE: i32 = 24; /* Too many open files */ +pub const ENOTTY: i32 = 25; /* Not a typewriter */ +pub const ETXTBSY: i32 = 26; /* Text file busy */ +pub const EFBIG: i32 = 27; /* File too large */ +pub const ENOSPC: i32 = 28; /* No space left on device */ +pub const ESPIPE: i32 = 29; /* Illegal seek */ +pub const EROFS: i32 = 30; /* Read-only file system */ +pub const EMLINK: i32 = 31; /* Too many links */ +pub const EPIPE: i32 = 32; /* Broken pipe */ +pub const EDOM: i32 = 33; /* Math argument out of domain of func */ +pub const ERANGE: i32 = 34; /* Math result not representable */ +pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: i32 = 36; /* File name too long */ +pub const ENOLCK: i32 = 37; /* No record locks available */ +pub const ENOSYS: i32 = 38; /* Function not implemented */ +pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ +pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ +pub const ENOMSG: i32 = 42; /* No message of desired type */ +pub const EIDRM: i32 = 43; /* Identifier removed */ +pub const ECHRNG: i32 = 44; /* Channel number out of range */ +pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ +pub const EL3HLT: i32 = 46; /* Level 3 halted */ +pub const EL3RST: i32 = 47; /* Level 3 reset */ +pub const ELNRNG: i32 = 48; /* Link number out of range */ +pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ +pub const ENOCSI: i32 = 50; /* No CSI structure available */ +pub const EL2HLT: i32 = 51; /* Level 2 halted */ +pub const EBADE: i32 = 52; /* Invalid exchange */ +pub const EBADR: i32 = 53; /* Invalid request descriptor */ +pub const EXFULL: i32 = 54; /* Exchange full */ +pub const ENOANO: i32 = 55; /* No anode */ +pub const EBADRQC: i32 = 56; /* Invalid request code */ +pub const EBADSLT: i32 = 57; /* Invalid slot */ +pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ +pub const EBFONT: i32 = 59; /* Bad font file format */ +pub const ENOSTR: i32 = 60; /* Device not a stream */ +pub const ENODATA: i32 = 61; /* No data available */ +pub const ETIME: i32 = 62; /* Timer expired */ +pub const ENOSR: i32 = 63; /* Out of streams resources */ +pub const ENONET: i32 = 64; /* Machine is not on the network */ +pub const ENOPKG: i32 = 65; /* Package not installed */ +pub const EREMOTE: i32 = 66; /* Object is remote */ +pub const ENOLINK: i32 = 67; /* Link has been severed */ +pub const EADV: i32 = 68; /* Advertise error */ +pub const ESRMNT: i32 = 69; /* Srmount error */ +pub const ECOMM: i32 = 70; /* Communication error on send */ +pub const EPROTO: i32 = 71; /* Protocol error */ +pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ +pub const EDOTDOT: i32 = 73; /* RFS specific error */ +pub const EBADMSG: i32 = 74; /* Not a data message */ +pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ +pub const EBADFD: i32 = 77; /* File descriptor in bad state */ +pub const EREMCHG: i32 = 78; /* Remote address changed */ +pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ +pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ +pub const EUSERS: i32 = 87; /* Too many users */ +pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ +pub const EMSGSIZE: i32 = 90; /* Message too long */ +pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: i32 = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ +pub const ENETDOWN: i32 = 100; /* Network is down */ +pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ +pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ +pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ +pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ +pub const ENOBUFS: i32 = 105; /* No buffer space available */ +pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ +pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ +pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ +pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ +pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ +pub const ECONNREFUSED: i32 = 111; /* Connection refused */ +pub const EHOSTDOWN: i32 = 112; /* Host is down */ +pub const EHOSTUNREACH: i32 = 113; /* No route to host */ +pub const EALREADY: i32 = 114; /* Operation already in progress */ +pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ +pub const ESTALE: i32 = 116; /* Stale NFS file handle */ +pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ +pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ +pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ +pub const EISNAM: i32 = 120; /* Is a named type file */ +pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ +pub const EDQUOT: i32 = 122; /* Quota exceeded */ +pub const ENOMEDIUM: i32 = 123; /* No medium found */ +pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ +pub const ECANCELED: i32 = 125; /* Operation Canceled */ +pub const ENOKEY: i32 = 126; /* Required key not available */ +pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ +pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ +pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ +pub const EOWNERDEAD: i32 = 130; /* Owner died */ +pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ + +pub static STR_ERROR: [&'static str; 132] = ["Success", + "Operation not permitted", + "No such file or directory", + "No such process", + "Interrupted system call", + "I/O error", + "No such device or address", + "Argument list too long", + "Exec format error", + "Bad file number", + "No child processes", + "Try again", + "Out of memory", + "Permission denied", + "Bad address", + "Block device required", + "Device or resource busy", + "File exists", + "Cross-device link", + "No such device", + "Not a directory", + "Is a directory", + "Invalid argument", + "File table overflow", + "Too many open files", + "Not a typewriter", + "Text file busy", + "File too large", + "No space left on device", + "Illegal seek", + "Read-only file system", + "Too many links", + "Broken pipe", + "Math argument out of domain of func", + "Math result not representable", + "Resource deadlock would occur", + "File name too long", + "No record locks available", + "Function not implemented", + "Directory not empty", + "Too many symbolic links encountered", + "Operation would block", + "No message of desired type", + "Identifier removed", + "Channel number out of range", + "Level 2 not synchronized", + "Level 3 halted", + "Level 3 reset", + "Link number out of range", + "Protocol driver not attached", + "No CSI structure available", + "Level 2 halted", + "Invalid exchange", + "Invalid request descriptor", + "Exchange full", + "No anode", + "Invalid request code", + "Invalid slot", + "Resource deadlock would occur", + "Bad font file format", + "Device not a stream", + "No data available", + "Timer expired", + "Out of streams resources", + "Machine is not on the network", + "Package not installed", + "Object is remote", + "Link has been severed", + "Advertise error", + "Srmount error", + "Communication error on send", + "Protocol error", + "Multihop attempted", + "RFS specific error", + "Not a data message", + "Value too large for defined data type", + "Name not unique on network", + "File descriptor in bad state", + "Remote address changed", + "Can not access a needed shared library", + "Accessing a corrupted shared library", + ".lib section in a.out corrupted", + "Attempting to link in too many shared libraries", + "Cannot exec a shared library directly", + "Illegal byte sequence", + "Interrupted system call should be restarted", + "Streams pipe error", + "Too many users", + "Socket operation on non-socket", + "Destination address required", + "Message too long", + "Protocol wrong type for socket", + "Protocol not available", + "Protocol not supported", + "Socket type not supported", + "Operation not supported on transport endpoint", + "Protocol family not supported", + "Address family not supported by protocol", + "Address already in use", + "Cannot assign requested address", + "Network is down", + "Network is unreachable", + "Network dropped connection because of reset", + "Software caused connection abort", + "Connection reset by peer", + "No buffer space available", + "Transport endpoint is already connected", + "Transport endpoint is not connected", + "Cannot send after transport endpoint shutdown", + "Too many references: cannot splice", + "Connection timed out", + "Connection refused", + "Host is down", + "No route to host", + "Operation already in progress", + "Operation now in progress", + "Stale NFS file handle", + "Structure needs cleaning", + "Not a XENIX named type file", + "No XENIX semaphores available", + "Is a named type file", + "Remote I/O error", + "Quota exceeded", + "No medium found", + "Wrong medium type", + "Operation Canceled", + "Required key not available", + "Key has expired", + "Key has been revoked", + "Key was rejected by service", + "Owner died", + "State not recoverable"]; diff --git a/redox_syscall/src/flag.rs b/redox_syscall/src/flag.rs new file mode 100644 index 000000000..6a03793b8 --- /dev/null +++ b/redox_syscall/src/flag.rs @@ -0,0 +1,162 @@ +pub const CLONE_VM: usize = 0x100; +pub const CLONE_FS: usize = 0x200; +pub const CLONE_FILES: usize = 0x400; +pub const CLONE_SIGHAND: usize = 0x800; +pub const CLONE_VFORK: usize = 0x4000; +pub const CLONE_THREAD: usize = 0x10000; +pub const CLONE_STACK: usize = 0x1000_0000; + +pub const CLOCK_REALTIME: usize = 1; +pub const CLOCK_MONOTONIC: usize = 4; + +pub const EVENT_NONE: usize = 0; +pub const EVENT_READ: usize = 1; +pub const EVENT_WRITE: usize = 2; + +pub const F_DUPFD: usize = 0; +pub const F_GETFD: usize = 1; +pub const F_SETFD: usize = 2; +pub const F_GETFL: usize = 3; +pub const F_SETFL: usize = 4; + +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; +pub const FUTEX_REQUEUE: usize = 2; + +pub const MAP_SHARED: usize = 0x0001; +pub const MAP_PRIVATE: usize = 0x0002; + +pub const MODE_TYPE: u16 = 0xF000; +pub const MODE_DIR: u16 = 0x4000; +pub const MODE_FILE: u16 = 0x8000; +pub const MODE_SYMLINK: u16 = 0xA000; +pub const MODE_FIFO: u16 = 0x1000; +pub const MODE_CHR: u16 = 0x2000; + +pub const MODE_PERM: u16 = 0x0FFF; +pub const MODE_SETUID: u16 = 0o4000; +pub const MODE_SETGID: u16 = 0o2000; + +pub const O_RDONLY: usize = 0x0001_0000; +pub const O_WRONLY: usize = 0x0002_0000; +pub const O_RDWR: usize = 0x0003_0000; +pub const O_NONBLOCK: usize = 0x0004_0000; +pub const O_APPEND: usize = 0x0008_0000; +pub const O_SHLOCK: usize = 0x0010_0000; +pub const O_EXLOCK: usize = 0x0020_0000; +pub const O_ASYNC: usize = 0x0040_0000; +pub const O_FSYNC: usize = 0x0080_0000; +pub const O_CLOEXEC: usize = 0x0100_0000; +pub const O_CREAT: usize = 0x0200_0000; +pub const O_TRUNC: usize = 0x0400_0000; +pub const O_EXCL: usize = 0x0800_0000; +pub const O_DIRECTORY: usize = 0x1000_0000; +pub const O_STAT: usize = 0x2000_0000; +pub const O_SYMLINK: usize = 0x4000_0000; +pub const O_NOFOLLOW: usize = 0x8000_0000; +pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; + +pub const PHYSMAP_WRITE: usize = 0x0000_0001; +pub const PHYSMAP_WRITE_COMBINE: usize = 0x0000_0002; +pub const PHYSMAP_NO_CACHE: usize = 0x0000_0004; + +pub const PROT_NONE: usize = 0x0000_0000; +pub const PROT_EXEC: usize = 0x0001_0000; +pub const PROT_WRITE: usize = 0x0002_0000; +pub const PROT_READ: usize = 0x0004_0000; + +pub const SEEK_SET: usize = 0; +pub const SEEK_CUR: usize = 1; +pub const SEEK_END: usize = 2; + +pub const SIGHUP: usize = 1; +pub const SIGINT: usize = 2; +pub const SIGQUIT: usize = 3; +pub const SIGILL: usize = 4; +pub const SIGTRAP: usize = 5; +pub const SIGABRT: usize = 6; +pub const SIGBUS: usize = 7; +pub const SIGFPE: usize = 8; +pub const SIGKILL: usize = 9; +pub const SIGUSR1: usize = 10; +pub const SIGSEGV: usize = 11; +pub const SIGUSR2: usize = 12; +pub const SIGPIPE: usize = 13; +pub const SIGALRM: usize = 14; +pub const SIGTERM: usize = 15; +pub const SIGSTKFLT: usize= 16; +pub const SIGCHLD: usize = 17; +pub const SIGCONT: usize = 18; +pub const SIGSTOP: usize = 19; +pub const SIGTSTP: usize = 20; +pub const SIGTTIN: usize = 21; +pub const SIGTTOU: usize = 22; +pub const SIGURG: usize = 23; +pub const SIGXCPU: usize = 24; +pub const SIGXFSZ: usize = 25; +pub const SIGVTALRM: usize= 26; +pub const SIGPROF: usize = 27; +pub const SIGWINCH: usize = 28; +pub const SIGIO: usize = 29; +pub const SIGPWR: usize = 30; +pub const SIGSYS: usize = 31; + +pub const SIG_DFL: usize = 0; +pub const SIG_IGN: usize = 1; + +pub const SIG_BLOCK: usize = 0; +pub const SIG_UNBLOCK: usize = 1; +pub const SIG_SETMASK: usize = 2; + +pub const SA_NOCLDSTOP: usize = 0x00000001; +pub const SA_NOCLDWAIT: usize = 0x00000002; +pub const SA_SIGINFO: usize = 0x00000004; +pub const SA_RESTORER: usize = 0x04000000; +pub const SA_ONSTACK: usize = 0x08000000; +pub const SA_RESTART: usize = 0x10000000; +pub const SA_NODEFER: usize = 0x40000000; +pub const SA_RESETHAND: usize = 0x80000000; + +pub const WNOHANG: usize = 0x01; +pub const WUNTRACED: usize = 0x02; +pub const WCONTINUED: usize = 0x08; + +/// True if status indicates the child is stopped. +pub fn wifstopped(status: usize) -> bool { + (status & 0xff) == 0x7f +} + +/// If wifstopped(status), the signal that stopped the child. +pub fn wstopsig(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates the child continued after a stop. +pub fn wifcontinued(status: usize) -> bool { + status == 0xffff +} + +/// True if STATUS indicates termination by a signal. +pub fn wifsignaled(status: usize) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +/// If wifsignaled(status), the terminating signal. +pub fn wtermsig(status: usize) -> usize { + status & 0x7f +} + +/// True if status indicates normal termination. +pub fn wifexited(status: usize) -> bool { + wtermsig(status) == 0 +} + +/// If wifexited(status), the exit status. +pub fn wexitstatus(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates a core dump was created. +pub fn wcoredump(status: usize) -> bool { + (status & 0x80) != 0 +} diff --git a/redox_syscall/src/io/dma.rs b/redox_syscall/src/io/dma.rs new file mode 100644 index 000000000..d5334b843 --- /dev/null +++ b/redox_syscall/src/io/dma.rs @@ -0,0 +1,76 @@ +use core::{mem, ptr}; +use core::ops::{Deref, DerefMut}; + +use Result; + +struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + fn new(size: usize) -> Result<PhysBox> { + let address = unsafe { ::physalloc(size)? }; + Ok(PhysBox { + address: address, + size: size + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { ::physfree(self.address, self.size) }; + } +} + +pub struct Dma<T> { + phys: PhysBox, + virt: *mut T +} + +impl<T> Dma<T> { + pub fn new(value: T) -> Result<Dma<T>> { + let phys = PhysBox::new(mem::size_of::<T>())?; + let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T; + unsafe { ptr::write(virt, value); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn zeroed() -> Result<Dma<T>> { + let phys = PhysBox::new(mem::size_of::<T>())?; + let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T; + unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn physical(&self) -> usize { + self.phys.address + } +} + +impl<T> Deref for Dma<T> { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl<T> DerefMut for Dma<T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl<T> Drop for Dma<T> { + fn drop(&mut self) { + unsafe { drop(ptr::read(self.virt)); } + let _ = unsafe { ::physunmap(self.virt as usize) }; + } +} diff --git a/redox_syscall/src/io/io.rs b/redox_syscall/src/io/io.rs new file mode 100644 index 000000000..fb866b581 --- /dev/null +++ b/redox_syscall/src/io/io.rs @@ -0,0 +1,67 @@ +use core::cmp::PartialEq; +use core::ops::{BitAnd, BitOr, Not}; + +pub trait Io { + type Value: Copy + PartialEq + BitAnd<Output = Self::Value> + BitOr<Output = Self::Value> + Not<Output = Self::Value>; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +pub struct ReadOnly<I: Io> { + inner: I +} + +impl<I: Io> ReadOnly<I> { + pub const fn new(inner: I) -> ReadOnly<I> { + ReadOnly { + inner: inner + } + } + + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +pub struct WriteOnly<I: Io> { + inner: I +} + +impl<I: Io> WriteOnly<I> { + pub const fn new(inner: I) -> WriteOnly<I> { + WriteOnly { + inner: inner + } + } + + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} diff --git a/redox_syscall/src/io/mmio.rs b/redox_syscall/src/io/mmio.rs new file mode 100644 index 000000000..b8e7727d3 --- /dev/null +++ b/redox_syscall/src/io/mmio.rs @@ -0,0 +1,31 @@ +use core::ptr::{read_volatile, write_volatile}; +use core::mem::uninitialized; +use core::ops::{BitAnd, BitOr, Not}; + +use super::io::Io; + +#[repr(packed)] +pub struct Mmio<T> { + value: T, +} + +impl<T> Mmio<T> { + /// Create a new Mmio without initializing + pub fn new() -> Self { + Mmio { + value: unsafe { uninitialized() } + } + } +} + +impl<T> Io for Mmio<T> where T: Copy + PartialEq + BitAnd<Output = T> + BitOr<Output = T> + Not<Output = T> { + type Value = T; + + fn read(&self) -> T { + unsafe { read_volatile(&self.value) } + } + + fn write(&mut self, value: T) { + unsafe { write_volatile(&mut self.value, value) }; + } +} diff --git a/redox_syscall/src/io/mod.rs b/redox_syscall/src/io/mod.rs new file mode 100644 index 000000000..a35456e30 --- /dev/null +++ b/redox_syscall/src/io/mod.rs @@ -0,0 +1,11 @@ +//! I/O functions + +pub use self::dma::*; +pub use self::io::*; +pub use self::mmio::*; +pub use self::pio::*; + +mod dma; +mod io; +mod mmio; +mod pio; diff --git a/redox_syscall/src/io/pio.rs b/redox_syscall/src/io/pio.rs new file mode 100644 index 000000000..91ae310b6 --- /dev/null +++ b/redox_syscall/src/io/pio.rs @@ -0,0 +1,89 @@ +use core::marker::PhantomData; + +use super::io::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio<T> { + port: u16, + value: PhantomData<T>, +} + +impl<T> Pio<T> { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio::<T> { + port: port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio<u8> { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio<u16> { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio<u32> { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} diff --git a/redox_syscall/src/lib.rs b/redox_syscall/src/lib.rs new file mode 100644 index 000000000..8851fbb79 --- /dev/null +++ b/redox_syscall/src/lib.rs @@ -0,0 +1,49 @@ +#![feature(asm)] +#![feature(const_fn)] +#![no_std] + +pub use self::arch::*; +pub use self::call::*; +pub use self::data::*; +pub use self::error::*; +pub use self::flag::*; +pub use self::io::*; +pub use self::number::*; +pub use self::scheme::*; + +#[cfg(target_arch = "arm")] +#[path="arch/arm.rs"] +mod arch; + +#[cfg(target_arch = "aarch64")] +#[path="arch/aarch64.rs"] +mod arch; + +#[cfg(target_arch = "x86")] +#[path="arch/x86.rs"] +mod arch; + +#[cfg(target_arch = "x86_64")] +#[path="arch/x86_64.rs"] +mod arch; + +/// Function definitions +pub mod call; + +/// Complex structures that are used for some system calls +pub mod data; + +/// All errors that can be generated by a system call +pub mod error; + +/// Flags used as an argument to many system calls +pub mod flag; + +/// Functions for low level hardware control +pub mod io; + +/// Call numbers used by each system call +pub mod number; + +/// A trait useful for scheme handlers +pub mod scheme; diff --git a/redox_syscall/src/number.rs b/redox_syscall/src/number.rs new file mode 100644 index 000000000..ec9acfaac --- /dev/null +++ b/redox_syscall/src/number.rs @@ -0,0 +1,76 @@ +pub const SYS_CLASS: usize = 0xF000_0000; +pub const SYS_CLASS_PATH: usize=0x1000_0000; +pub const SYS_CLASS_FILE: usize=0x2000_0000; + +pub const SYS_ARG: usize = 0x0F00_0000; +pub const SYS_ARG_SLICE: usize =0x0100_0000; +pub const SYS_ARG_MSLICE: usize=0x0200_0000; +pub const SYS_ARG_PATH: usize = 0x0300_0000; + +pub const SYS_RET: usize = 0x00F0_0000; +pub const SYS_RET_FILE: usize = 0x0010_0000; + +pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9; +pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5; +pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15; +pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84; +pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; + +pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; +pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; +pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; +pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; +pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; +pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; +pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; +pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; +pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; +pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11; +pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; +pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91; +pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; +pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; +pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; +pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100; +pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; +pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93; +pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; + +pub const SYS_BRK: usize = 45; +pub const SYS_CHDIR: usize = 12; +pub const SYS_CLOCK_GETTIME: usize = 265; +pub const SYS_CLONE: usize = 120; +pub const SYS_EXIT: usize = 1; +pub const SYS_FUTEX: usize = 240; +pub const SYS_GETCWD: usize = 183; +pub const SYS_GETEGID: usize = 202; +pub const SYS_GETENS: usize = 951; +pub const SYS_GETEUID: usize = 201; +pub const SYS_GETGID: usize = 200; +pub const SYS_GETNS: usize = 950; +pub const SYS_GETPID: usize = 20; +pub const SYS_GETPGID: usize = 132; +pub const SYS_GETPPID: usize = 64; +pub const SYS_GETUID: usize = 199; +pub const SYS_IOPL: usize = 110; +pub const SYS_KILL: usize = 37; +pub const SYS_MPROTECT: usize = 125; +pub const SYS_MKNS: usize = 984; +pub const SYS_NANOSLEEP: usize =162; +pub const SYS_PHYSALLOC: usize =945; +pub const SYS_PHYSFREE: usize = 946; +pub const SYS_PHYSMAP: usize = 947; +pub const SYS_PHYSUNMAP: usize =948; +pub const SYS_VIRTTOPHYS: usize=949; +pub const SYS_PIPE2: usize = 331; +pub const SYS_SETPGID: usize = 57; +pub const SYS_SETREGID: usize = 204; +pub const SYS_SETRENS: usize = 952; +pub const SYS_SETREUID: usize = 203; +pub const SYS_SIGACTION: usize =67; +pub const SYS_SIGPROCMASK:usize=126; +pub const SYS_SIGRETURN: usize =119; +pub const SYS_UMASK: usize = 60; +pub const SYS_WAITPID: usize = 7; +pub const SYS_YIELD: usize = 158; diff --git a/redox_syscall/src/scheme/generate.sh b/redox_syscall/src/scheme/generate.sh new file mode 100755 index 000000000..e5d11ae30 --- /dev/null +++ b/redox_syscall/src/scheme/generate.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e + +echo "Generating SchemeMut from Scheme" +sed 's/trait Scheme/trait SchemeMut/' scheme.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_mut.rs + +echo "Generating SchemeBlock from Scheme" +sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \ +| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option<usize>/' \ +| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \ +| sed 's/Result<usize>/Result<Option<usize>>/g' \ +> scheme_block.rs + +echo "Generating SchemeBlockMut from SchemeBlock" +sed 's/trait SchemeBlock/trait SchemeBlockMut/' scheme_block.rs \ +| sed 's/\&self/\&mut self/g' \ +> scheme_block_mut.rs diff --git a/redox_syscall/src/scheme/mod.rs b/redox_syscall/src/scheme/mod.rs new file mode 100644 index 000000000..66f8fc76d --- /dev/null +++ b/redox_syscall/src/scheme/mod.rs @@ -0,0 +1,9 @@ +pub use self::scheme::Scheme; +pub use self::scheme_mut::SchemeMut; +pub use self::scheme_block::SchemeBlock; +pub use self::scheme_block_mut::SchemeBlockMut; + +mod scheme; +mod scheme_mut; +mod scheme_block; +mod scheme_block_mut; diff --git a/redox_syscall/src/scheme/scheme.rs b/redox_syscall/src/scheme/scheme.rs new file mode 100644 index 000000000..c047e9683 --- /dev/null +++ b/redox_syscall/src/scheme/scheme.rs @@ -0,0 +1,167 @@ +use core::{mem, slice}; + +use data::*; +use error::*; +use number::*; + +pub trait Scheme { + fn handle(&self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid), + SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), + SYS_FMAP => if packet.d >= mem::size_of::<Map>() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP => self.funmap(packet.b), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), + SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::<StatVfs>() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::<TimeSpec>() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::<TimeSpec>()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } +} diff --git a/redox_syscall/src/scheme/scheme_block.rs b/redox_syscall/src/scheme/scheme_block.rs new file mode 100644 index 000000000..0407dde61 --- /dev/null +++ b/redox_syscall/src/scheme/scheme_block.rs @@ -0,0 +1,167 @@ +use core::{mem, slice}; + +use data::*; +use error::*; +use number::*; + +pub trait SchemeBlock { + fn handle(&self, packet: &Packet) -> Option<usize> { + let res = match packet.a { + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid), + SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), + SYS_FMAP => if packet.d >= mem::size_of::<Map>() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP => self.funmap(packet.b), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), + SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::<StatVfs>() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::<TimeSpec>() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::<TimeSpec>()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize, buf: &[u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&self, id: usize, mode: u16) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap(&self, id: usize, map: &Map) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn funmap(&self, address: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } +} diff --git a/redox_syscall/src/scheme/scheme_block_mut.rs b/redox_syscall/src/scheme/scheme_block_mut.rs new file mode 100644 index 000000000..411035f42 --- /dev/null +++ b/redox_syscall/src/scheme/scheme_block_mut.rs @@ -0,0 +1,167 @@ +use core::{mem, slice}; + +use data::*; +use error::*; +use number::*; + +pub trait SchemeBlockMut { + fn handle(&mut self, packet: &Packet) -> Option<usize> { + let res = match packet.a { + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid), + SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), + SYS_FMAP => if packet.d >= mem::size_of::<Map>() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP => self.funmap(packet.b), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), + SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::<StatVfs>() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::<TimeSpec>() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::<TimeSpec>()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + res.transpose().map(Error::mux) + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result<Option<usize>> { + Err(Error::new(EBADF)) + } +} diff --git a/redox_syscall/src/scheme/scheme_mut.rs b/redox_syscall/src/scheme/scheme_mut.rs new file mode 100644 index 000000000..abd2e88e5 --- /dev/null +++ b/redox_syscall/src/scheme/scheme_mut.rs @@ -0,0 +1,167 @@ +use core::{mem, slice}; + +use data::*; +use error::*; +use number::*; + +pub trait SchemeMut { + fn handle(&mut self, packet: &mut Packet) { + let res = match packet.a { + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid), + SYS_CHMOD => self.chmod(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + + SYS_DUP => self.dup(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), + SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), + SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), + SYS_FMAP => if packet.d >= mem::size_of::<Map>() { + self.fmap(packet.b, unsafe { &*(packet.c as *const Map) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FUNMAP => self.funmap(packet.b), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FRENAME => self.frename(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, packet.uid, packet.gid), + SYS_FSTAT => if packet.d >= mem::size_of::<Stat>() { + self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSTATVFS => if packet.d >= mem::size_of::<StatVfs>() { + self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_FUTIMENS => if packet.d >= mem::size_of::<TimeSpec>() { + self.futimens(packet.b, unsafe { slice::from_raw_parts(packet.c as *const TimeSpec, packet.d / mem::size_of::<TimeSpec>()) }) + } else { + Err(Error::new(EFAULT)) + }, + SYS_CLOSE => self.close(packet.b), + _ => Err(Error::new(ENOSYS)) + }; + + packet.a = Error::mux(res); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn chmod(&mut self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&mut self, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchmod(&mut self, id: usize, mode: u16) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fevent(&mut self, id: usize, flags: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn funmap(&mut self, address: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn frename(&mut self, id: usize, path: &[u8], uid: u32, gid: u32) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&mut self, id: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&mut self, id: usize, len: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result<usize> { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&mut self, id: usize) -> Result<usize> { + Err(Error::new(EBADF)) + } +} diff --git a/redox_termios/.cargo-checksum.json b/redox_termios/.cargo-checksum.json new file mode 100644 index 000000000..125ed39f9 --- /dev/null +++ b/redox_termios/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"} \ No newline at end of file diff --git a/redox_termios/Cargo.toml b/redox_termios/Cargo.toml new file mode 100644 index 000000000..a89b0e89c --- /dev/null +++ b/redox_termios/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "redox_termios" +version = "0.1.1" +authors = ["Jeremy Soller <jackpot51@gmail.com>"] +description = "A Rust library to access Redox termios functions" +documentation = "https://docs.rs/redox_termios" +license = "MIT" +repository = "https://github.com/redox-os/termios" + +[lib] +name = "redox_termios" +path = "src/lib.rs" +[dependencies.redox_syscall] +version = "0.1" diff --git a/redox_termios/LICENSE b/redox_termios/LICENSE new file mode 100644 index 000000000..5deeece4f --- /dev/null +++ b/redox_termios/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Redox OS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/redox_termios/README.md b/redox_termios/README.md new file mode 100644 index 000000000..24156cb95 --- /dev/null +++ b/redox_termios/README.md @@ -0,0 +1,2 @@ +# termios +Redox Rust termios library diff --git a/redox_termios/src/lib.rs b/redox_termios/src/lib.rs new file mode 100644 index 000000000..b1c904502 --- /dev/null +++ b/redox_termios/src/lib.rs @@ -0,0 +1,218 @@ +#![allow(non_camel_case_types)] +#![no_std] + +extern crate syscall; + +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +pub type tcflag_t = u32; +pub type cc_t = u8; + +/* c_cc { */ +pub const VEOF: usize = 0; +pub const VEOL: usize = 1; +pub const VEOL2: usize = 2; +pub const VERASE: usize = 3; +pub const VWERASE: usize = 4; +pub const VKILL: usize = 5; +pub const VREPRINT: usize = 6; +pub const VSWTC: usize = 7; +pub const VINTR: usize = 8; +pub const VQUIT: usize = 9; +pub const VSUSP: usize = 10; +pub const VSTART: usize = 12; +pub const VSTOP: usize = 13; +pub const VLNEXT: usize = 14; +pub const VDISCARD: usize = 15; +pub const VMIN: usize = 16; +pub const VTIME: usize = 17; +pub const NCCS: usize = 32; +/* } c_cc */ + +/* c_iflag { */ +pub const IGNBRK: tcflag_t = 0o000001; +pub const BRKINT: tcflag_t = 0o000002; +pub const IGNPAR: tcflag_t = 0o000004; +pub const PARMRK: tcflag_t = 0o000010; +pub const INPCK: tcflag_t = 0o000020; +pub const ISTRIP: tcflag_t = 0o000040; +pub const INLCR: tcflag_t = 0o000100; +pub const IGNCR: tcflag_t = 0o000200; +pub const ICRNL: tcflag_t = 0o000400; +pub const IXON: tcflag_t = 0o001000; +pub const IXOFF: tcflag_t = 0o002000; +/* } c_iflag */ + +/* c_oflag { */ +pub const OPOST: tcflag_t = 0o000001; +pub const ONLCR: tcflag_t = 0o000002; +pub const OLCUC: tcflag_t = 0o000004; + +pub const OCRNL: tcflag_t = 0o000010; +pub const ONOCR: tcflag_t = 0o000020; +pub const ONLRET: tcflag_t = 0o000040; + +pub const OFILL: tcflag_t = 0o0000100; +pub const OFDEL: tcflag_t = 0o0000200; +/* } c_oflag */ + +/* c_cflag { */ +pub const B0: tcflag_t = 0o000000; +pub const B50: tcflag_t = 0o000001; +pub const B75: tcflag_t = 0o000002; +pub const B110: tcflag_t = 0o000003; +pub const B134: tcflag_t = 0o000004; +pub const B150: tcflag_t = 0o000005; +pub const B200: tcflag_t = 0o000006; +pub const B300: tcflag_t = 0o000007; +pub const B600: tcflag_t = 0o000010; +pub const B1200: tcflag_t = 0o000011; +pub const B1800: tcflag_t = 0o000012; +pub const B2400: tcflag_t = 0o000013; +pub const B4800: tcflag_t = 0o000014; +pub const B9600: tcflag_t = 0o000015; +pub const B19200: tcflag_t = 0o000016; +pub const B38400: tcflag_t = 0o000017; +pub const B57600: tcflag_t = 0o0020; +pub const B115200: tcflag_t = 0o0021; +pub const B230400: tcflag_t = 0o0022; +pub const B460800: tcflag_t = 0o0023; +pub const B500000: tcflag_t = 0o0024; +pub const B576000: tcflag_t = 0o0025; +pub const B921600: tcflag_t = 0o0026; +pub const B1000000: tcflag_t = 0o0027; +pub const B1152000: tcflag_t = 0o0030; +pub const B1500000: tcflag_t = 0o0031; +pub const B2000000: tcflag_t = 0o0032; +pub const B2500000: tcflag_t = 0o0033; +pub const B3000000: tcflag_t = 0o0034; +pub const B3500000: tcflag_t = 0o0035; +pub const B4000000: tcflag_t = 0o0036; + +pub const __MAX_BAUD: tcflag_t = B4000000; + +pub const CSIZE: tcflag_t = 0o0001400; +pub const CS5: tcflag_t = 0o0000000; +pub const CS6: tcflag_t = 0o0000400; +pub const CS7: tcflag_t = 0o0001000; +pub const CS8: tcflag_t = 0o0001400; + +pub const CSTOPB: tcflag_t = 0o0002000; +pub const CREAD: tcflag_t = 0o0004000; +pub const PARENB: tcflag_t = 0o0010000; +pub const PARODD: tcflag_t = 0o0020000; +pub const HUPCL: tcflag_t = 0o0040000; + +pub const CLOCAL: tcflag_t = 0o0100000; +/* } c_clfag */ + +/* c_lflag { */ +pub const ISIG: tcflag_t = 0x00000080; +pub const ICANON: tcflag_t = 0x00000100; +pub const ECHO: tcflag_t = 0x00000008; +pub const ECHOE: tcflag_t = 0x00000002; +pub const ECHOK: tcflag_t = 0x00000004; +pub const ECHONL: tcflag_t = 0x00000010; +pub const NOFLSH: tcflag_t = 0x80000000; +pub const TOSTOP: tcflag_t = 0x00400000; +pub const IEXTEN: tcflag_t = 0x00000400; +/* } c_lflag */ + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct Termios { + pub c_iflag: tcflag_t, + pub c_oflag: tcflag_t, + pub c_cflag: tcflag_t, + pub c_lflag: tcflag_t, + pub c_cc: [cc_t; 32] +} + +impl Default for Termios { + fn default() -> Termios { + let mut termios = Termios { + c_iflag: ICRNL | IXON, + c_oflag: OPOST | ONLCR, + c_cflag: B38400 | CS8 | CREAD | HUPCL, + c_lflag: ISIG | ICANON | ECHO | ECHOE | ECHOK | IEXTEN, + c_cc: [0; 32] + }; + + { + let mut cc = |i: usize, b: cc_t| { + termios.c_cc[i] = b; + }; + + cc(VEOF, 0o004); // CTRL-D + cc(VEOL, 0o000); // NUL + cc(VEOL2, 0o000); // NUL + cc(VERASE, 0o177); // DEL + cc(VWERASE, 0o027); // CTRL-W + cc(VKILL, 0o025); // CTRL-U + cc(VREPRINT, 0o022);// CTRL-R + cc(VINTR, 0o003); // CTRL-C + cc(VQUIT, 0o034); // CTRL-\ + cc(VSUSP, 0o032); // CTRL-Z + cc(VSTART, 0o021); // CTRL-Q + cc(VSTOP, 0o023); // CTRL-S + cc(VLNEXT, 0o026); // CTRL-V + cc(VDISCARD, 0o017);// CTRL-U + cc(VMIN, 1); + cc(VTIME, 0); + } + + termios + } +} + +impl Termios { + pub fn make_raw(&mut self) { + self.c_iflag &= !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + self.c_oflag &= !OPOST; + self.c_cflag &= !(CSIZE | PARENB); + self.c_cflag |= CS8; + self.c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + } +} + +impl Deref for Termios { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Termios as *const u8, mem::size_of::<Termios>()) as &[u8] + } + } +} + +impl DerefMut for Termios { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Termios as *mut u8, mem::size_of::<Termios>()) as &mut [u8] + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[repr(C)] +pub struct Winsize { + pub ws_row: u16, + pub ws_col: u16 +} + +impl Deref for Winsize { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Winsize as *const u8, mem::size_of::<Winsize>()) as &[u8] + } + } +} + +impl DerefMut for Winsize { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Winsize as *mut u8, mem::size_of::<Winsize>()) as &mut [u8] + } + } +} diff --git a/regex-syntax/.cargo-checksum.json b/regex-syntax/.cargo-checksum.json new file mode 100644 index 000000000..30f4d81b1 --- /dev/null +++ b/regex-syntax/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"} \ No newline at end of file diff --git a/regex-syntax/Cargo.toml b/regex-syntax/Cargo.toml new file mode 100644 index 000000000..95c9776be --- /dev/null +++ b/regex-syntax/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "regex-syntax" +version = "0.6.6" +authors = ["The Rust Project Developers"] +description = "A regular expression parser." +homepage = "https://github.com/rust-lang/regex" +documentation = "https://docs.rs/regex-syntax" +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/regex" +[dependencies.ucd-util] +version = "0.1.0" diff --git a/regex-syntax/LICENSE-APACHE b/regex-syntax/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/regex-syntax/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/regex-syntax/LICENSE-MIT b/regex-syntax/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/regex-syntax/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/regex-syntax/benches/bench.rs b/regex-syntax/benches/bench.rs new file mode 100644 index 000000000..60aea9e98 --- /dev/null +++ b/regex-syntax/benches/bench.rs @@ -0,0 +1,73 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(test)] + +extern crate regex_syntax; +extern crate test; + +use regex_syntax::Parser; +use test::Bencher; + +#[bench] +fn parse_simple1(b: &mut Bencher) { + b.iter(|| { + let re = r"^bc(d|e)*$"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_simple2(b: &mut Bencher) { + b.iter(|| { + let re = r"'[a-zA-Z_][a-zA-Z0-9_]*(')\b"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_small1(b: &mut Bencher) { + b.iter(|| { + let re = r"\p{L}|\p{N}|\s|.|\d"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium1(b: &mut Bencher) { + b.iter(|| { + let re = r"\pL\p{Greek}\p{Hiragana}\p{Alphabetic}\p{Hebrew}\p{Arabic}"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium2(b: &mut Bencher) { + b.iter(|| { + let re = r"\s\S\w\W\d\D"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_medium3(b: &mut Bencher) { + b.iter(|| { + let re = r"\p{age:3.2}\p{hira}\p{scx:hira}\p{alphabetic}\p{sc:Greek}\pL"; + Parser::new().parse(re).unwrap() + }); +} + +#[bench] +fn parse_huge(b: &mut Bencher) { + b.iter(|| { + let re = r"\p{L}{100}"; + Parser::new().parse(re).unwrap() + }); +} diff --git a/regex-syntax/src/ast/mod.rs b/regex-syntax/src/ast/mod.rs new file mode 100644 index 000000000..884fcfa35 --- /dev/null +++ b/regex-syntax/src/ast/mod.rs @@ -0,0 +1,1515 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Defines an abstract syntax for regular expressions. +*/ + +use std::cmp::Ordering; +use std::error; +use std::fmt; + +pub use ast::visitor::{Visitor, visit}; + +pub mod parse; +pub mod print; +mod visitor; + +/// An error that occurred while parsing a regular expression into an abstract +/// syntax tree. +/// +/// Note that note all ASTs represents a valid regular expression. For example, +/// an AST is constructed without error for `\p{Quux}`, but `Quux` is not a +/// valid Unicode property name. That particular error is reported when +/// translating an AST to the high-level intermediate representation (`HIR`). +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Error { + /// The kind of error. + kind: ErrorKind, + /// The original pattern that the parser generated the error from. Every + /// span in an error is a valid range into this string. + pattern: String, + /// The span of this error. + span: Span, +} + +impl Error { + /// Return the type of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } + + /// The original pattern string in which this error occurred. + /// + /// Every span reported by this error is reported in terms of this string. + pub fn pattern(&self) -> &str { + &self.pattern + } + + /// Return the span at which this error occurred. + pub fn span(&self) -> &Span { + &self.span + } + + /// Return an auxiliary span. This span exists only for some errors that + /// benefit from being able to point to two locations in the original + /// regular expression. For example, "duplicate" errors will have the + /// main error position set to the duplicate occurrence while its + /// auxiliary span will be set to the initial occurrence. + pub fn auxiliary_span(&self) -> Option<&Span> { + use self::ErrorKind::*; + match self.kind { + FlagDuplicate { ref original } => Some(original), + FlagRepeatedNegation { ref original, .. } => Some(original), + GroupNameDuplicate { ref original, .. } => Some(original), + _ => None, + } + } +} + +/// The type of an error that occurred while building an AST. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ErrorKind { + /// The capturing group limit was exceeded. + /// + /// Note that this represents a limit on the total number of capturing + /// groups in a regex and not necessarily the number of nested capturing + /// groups. That is, the nest limit can be low and it is still possible for + /// this error to occur. + CaptureLimitExceeded, + /// An invalid escape sequence was found in a character class set. + ClassEscapeInvalid, + /// An invalid character class range was found. An invalid range is any + /// range where the start is greater than the end. + ClassRangeInvalid, + /// An invalid range boundary was found in a character class. Range + /// boundaries must be a single literal codepoint, but this error indicates + /// that something else was found, such as a nested class. + ClassRangeLiteral, + /// An opening `[` was found with no corresponding closing `]`. + ClassUnclosed, + /// An empty decimal number was given where one was expected. + DecimalEmpty, + /// An invalid decimal number was given where one was expected. + DecimalInvalid, + /// A bracketed hex literal was empty. + EscapeHexEmpty, + /// A bracketed hex literal did not correspond to a Unicode scalar value. + EscapeHexInvalid, + /// An invalid hexadecimal digit was found. + EscapeHexInvalidDigit, + /// EOF was found before an escape sequence was completed. + EscapeUnexpectedEof, + /// An unrecognized escape sequence. + EscapeUnrecognized, + /// A dangling negation was used when setting flags, e.g., `i-`. + FlagDanglingNegation, + /// A flag was used twice, e.g., `i-i`. + FlagDuplicate { + /// The position of the original flag. The error position + /// points to the duplicate flag. + original: Span, + }, + /// The negation operator was used twice, e.g., `-i-s`. + FlagRepeatedNegation { + /// The position of the original negation operator. The error position + /// points to the duplicate negation operator. + original: Span, + }, + /// Expected a flag but got EOF, e.g., `(?`. + FlagUnexpectedEof, + /// Unrecognized flag, e.g., `a`. + FlagUnrecognized, + /// A duplicate capture name was found. + GroupNameDuplicate { + /// The position of the initial occurrence of the capture name. The + /// error position itself points to the duplicate occurrence. + original: Span, + }, + /// A capture group name is empty, e.g., `(?P<>abc)`. + GroupNameEmpty, + /// An invalid character was seen for a capture group name. This includes + /// errors where the first character is a digit (even though subsequent + /// characters are allowed to be digits). + GroupNameInvalid, + /// A closing `>` could not be found for a capture group name. + GroupNameUnexpectedEof, + /// An unclosed group, e.g., `(ab`. + /// + /// The span of this error corresponds to the unclosed parenthesis. + GroupUnclosed, + /// An unopened group, e.g., `ab)`. + GroupUnopened, + /// The nest limit was exceeded. The limit stored here is the limit + /// configured in the parser. + NestLimitExceeded(u32), + /// The range provided in a counted repetition operator is invalid. The + /// range is invalid if the start is greater than the end. + RepetitionCountInvalid, + /// An opening `{` was found with no corresponding closing `}`. + RepetitionCountUnclosed, + /// A repetition operator was applied to a missing sub-expression. This + /// occurs, for example, in the regex consisting of just a `*` or even + /// `(?i)*`. It is, however, possible to create a repetition operating on + /// an empty sub-expression. For example, `()*` is still considered valid. + RepetitionMissing, + /// When octal support is disabled, this error is produced when an octal + /// escape is used. The octal escape is assumed to be an invocation of + /// a backreference, which is the common case. + UnsupportedBackreference, + /// When syntax similar to PCRE's look-around is used, this error is + /// returned. Some example syntaxes that are rejected include, but are + /// not necessarily limited to, `(?=re)`, `(?!re)`, `(?<=re)` and + /// `(?<!re)`. Note that all of these syntaxes are otherwise invalid; this + /// error is used to improve the user experience. + UnsupportedLookAround, + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +impl error::Error for Error { + fn description(&self) -> &str { + use self::ErrorKind::*; + match self.kind { + CaptureLimitExceeded => "capture group limit exceeded", + ClassEscapeInvalid => "invalid escape sequence in character class", + ClassRangeInvalid => "invalid character class range", + ClassRangeLiteral => "invalid range boundary, must be a literal", + ClassUnclosed => "unclosed character class", + DecimalEmpty => "empty decimal literal", + DecimalInvalid => "invalid decimal literal", + EscapeHexEmpty => "empty hexadecimal literal", + EscapeHexInvalid => "invalid hexadecimal literal", + EscapeHexInvalidDigit => "invalid hexadecimal digit", + EscapeUnexpectedEof => "unexpected eof (escape sequence)", + EscapeUnrecognized => "unrecognized escape sequence", + FlagDanglingNegation => "dangling flag negation operator", + FlagDuplicate{..} => "duplicate flag", + FlagRepeatedNegation{..} => "repeated negation", + FlagUnexpectedEof => "unexpected eof (flag)", + FlagUnrecognized => "unrecognized flag", + GroupNameDuplicate{..} => "duplicate capture group name", + GroupNameEmpty => "empty capture group name", + GroupNameInvalid => "invalid capture group name", + GroupNameUnexpectedEof => "unclosed capture group name", + GroupUnclosed => "unclosed group", + GroupUnopened => "unopened group", + NestLimitExceeded(_) => "nest limit exceeded", + RepetitionCountInvalid => "invalid repetition count range", + RepetitionCountUnclosed => "unclosed counted repetition", + RepetitionMissing => "repetition operator missing expression", + UnsupportedBackreference => "backreferences are not supported", + UnsupportedLookAround => "look-around is not supported", + _ => unreachable!(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::error::Formatter::from(self).fmt(f) + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ErrorKind::*; + match *self { + CaptureLimitExceeded => { + write!(f, "exceeded the maximum number of \ + capturing groups ({})", ::std::u32::MAX) + } + ClassEscapeInvalid => { + write!(f, "invalid escape sequence found in character class") + } + ClassRangeInvalid => { + write!(f, "invalid character class range, \ + the start must be <= the end") + } + ClassRangeLiteral => { + write!(f, "invalid range boundary, must be a literal") + } + ClassUnclosed => { + write!(f, "unclosed character class") + } + DecimalEmpty => { + write!(f, "decimal literal empty") + } + DecimalInvalid => { + write!(f, "decimal literal invalid") + } + EscapeHexEmpty => { + write!(f, "hexadecimal literal empty") + } + EscapeHexInvalid => { + write!(f, "hexadecimal literal is not a Unicode scalar value") + } + EscapeHexInvalidDigit => { + write!(f, "invalid hexadecimal digit") + } + EscapeUnexpectedEof => { + write!(f, "incomplete escape sequence, \ + reached end of pattern prematurely") + } + EscapeUnrecognized => { + write!(f, "unrecognized escape sequence") + } + FlagDanglingNegation => { + write!(f, "dangling flag negation operator") + } + FlagDuplicate{..} => { + write!(f, "duplicate flag") + } + FlagRepeatedNegation{..} => { + write!(f, "flag negation operator repeated") + } + FlagUnexpectedEof => { + write!(f, "expected flag but got end of regex") + } + FlagUnrecognized => { + write!(f, "unrecognized flag") + } + GroupNameDuplicate{..} => { + write!(f, "duplicate capture group name") + } + GroupNameEmpty => { + write!(f, "empty capture group name") + } + GroupNameInvalid => { + write!(f, "invalid capture group character") + } + GroupNameUnexpectedEof => { + write!(f, "unclosed capture group name") + } + GroupUnclosed => { + write!(f, "unclosed group") + } + GroupUnopened => { + write!(f, "unopened group") + } + NestLimitExceeded(limit) => { + write!(f, "exceed the maximum number of \ + nested parentheses/brackets ({})", limit) + } + RepetitionCountInvalid => { + write!(f, "invalid repetition count range, \ + the start must be <= the end") + } + RepetitionCountUnclosed => { + write!(f, "unclosed counted repetition") + } + RepetitionMissing => { + write!(f, "repetition operator missing expression") + } + UnsupportedBackreference => { + write!(f, "backreferences are not supported") + } + UnsupportedLookAround => { + write!(f, "look-around, including look-ahead and look-behind, \ + is not supported") + } + _ => unreachable!(), + } + } +} + +/// Span represents the position information of a single AST item. +/// +/// All span positions are absolute byte offsets that can be used on the +/// original regular expression that was parsed. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Span { + /// The start byte offset. + pub start: Position, + /// The end byte offset. + pub end: Position, +} + +impl fmt::Debug for Span { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Span({:?}, {:?})", self.start, self.end) + } +} + +impl Ord for Span { + fn cmp(&self, other: &Span) -> Ordering { + (&self.start, &self.end).cmp(&(&other.start, &other.end)) + } +} + +impl PartialOrd for Span { + fn partial_cmp(&self, other: &Span) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +/// A single position in a regular expression. +/// +/// A position encodes one half of a span, and include the byte offset, line +/// number and column number. +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Position { + /// The absolute offset of this position, starting at `0` from the + /// beginning of the regular expression pattern string. + pub offset: usize, + /// The line number, starting at `1`. + pub line: usize, + /// The approximate column number, starting at `1`. + pub column: usize, +} + +impl fmt::Debug for Position { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Position(o: {:?}, l: {:?}, c: {:?})", + self.offset, self.line, self.column) + } +} + +impl Ord for Position { + fn cmp(&self, other: &Position) -> Ordering { + self.offset.cmp(&other.offset) + } +} + +impl PartialOrd for Position { + fn partial_cmp(&self, other: &Position) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Span { + /// Create a new span with the given positions. + pub fn new(start: Position, end: Position) -> Span { + Span { start: start, end: end } + } + + /// Create a new span using the given position as the start and end. + pub fn splat(pos: Position) -> Span { + Span::new(pos, pos) + } + + /// Create a new span by replacing the starting the position with the one + /// given. + pub fn with_start(self, pos: Position) -> Span { + Span { start: pos, ..self } + } + + /// Create a new span by replacing the ending the position with the one + /// given. + pub fn with_end(self, pos: Position) -> Span { + Span { end: pos, ..self } + } + + /// Returns true if and only if this span occurs on a single line. + pub fn is_one_line(&self) -> bool { + self.start.line == self.end.line + } + + /// Returns true if and only if this span is empty. That is, it points to + /// a single position in the concrete syntax of a regular expression. + pub fn is_empty(&self) -> bool { + self.start.offset == self.end.offset + } +} + +impl Position { + /// Create a new position with the given information. + /// + /// `offset` is the absolute offset of the position, starting at `0` from + /// the beginning of the regular expression pattern string. + /// + /// `line` is the line number, starting at `1`. + /// + /// `column` is the approximate column number, starting at `1`. + pub fn new(offset: usize, line: usize, column: usize) -> Position { + Position { offset: offset, line: line, column: column } + } +} + +/// An abstract syntax tree for a singular expression along with comments +/// found. +/// +/// Comments are not stored in the tree itself to avoid complexity. Each +/// comment contains a span of precisely where it occurred in the original +/// regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct WithComments { + /// The actual ast. + pub ast: Ast, + /// All comments found in the original regular expression. + pub comments: Vec<Comment>, +} + +/// A comment from a regular expression with an associated span. +/// +/// A regular expression can only contain comments when the `x` flag is +/// enabled. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Comment { + /// The span of this comment, including the beginning `#` and ending `\n`. + pub span: Span, + /// The comment text, starting with the first character following the `#` + /// and ending with the last character preceding the `\n`. + pub comment: String, +} + +/// An abstract syntax tree for a single regular expression. +/// +/// An `Ast`'s `fmt::Display` implementation uses constant stack space and heap +/// space proportional to the size of the `Ast`. +/// +/// This type defines its own destructor that uses constant stack space and +/// heap space proportional to the size of the `Ast`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Ast { + /// An empty regex that matches everything. + Empty(Span), + /// A set of flags, e.g., `(?is)`. + Flags(SetFlags), + /// A single character literal, which includes escape sequences. + Literal(Literal), + /// The "any character" class. + Dot(Span), + /// A single zero-width assertion. + Assertion(Assertion), + /// A single character class. This includes all forms of character classes + /// except for `.`. e.g., `\d`, `\pN`, `[a-z]` and `[[:alpha:]]`. + Class(Class), + /// A repetition operator applied to an arbitrary regular expression. + Repetition(Repetition), + /// A grouped regular expression. + Group(Group), + /// An alternation of regular expressions. + Alternation(Alternation), + /// A concatenation of regular expressions. + Concat(Concat), +} + +impl Ast { + /// Return the span of this abstract syntax tree. + pub fn span(&self) -> &Span { + match *self { + Ast::Empty(ref span) => span, + Ast::Flags(ref x) => &x.span, + Ast::Literal(ref x) => &x.span, + Ast::Dot(ref span) => span, + Ast::Assertion(ref x) => &x.span, + Ast::Class(ref x) => x.span(), + Ast::Repetition(ref x) => &x.span, + Ast::Group(ref x) => &x.span, + Ast::Alternation(ref x) => &x.span, + Ast::Concat(ref x) => &x.span, + } + } + + /// Return true if and only if this Ast is empty. + pub fn is_empty(&self) -> bool { + match *self { + Ast::Empty(_) => true, + _ => false, + } + } + + /// Returns true if and only if this AST has any (including possibly empty) + /// subexpressions. + fn has_subexprs(&self) -> bool { + match *self { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) => false, + Ast::Class(_) + | Ast::Repetition(_) + | Ast::Group(_) + | Ast::Alternation(_) + | Ast::Concat(_) => true, + } + } +} + +/// Print a display representation of this Ast. +/// +/// This does not preserve any of the original whitespace formatting that may +/// have originally been present in the concrete syntax from which this Ast +/// was generated. +/// +/// This implementation uses constant stack space and heap space proportional +/// to the size of the `Ast`. +impl fmt::Display for Ast { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use ast::print::Printer; + Printer::new().print(self, f) + } +} + +/// An alternation of regular expressions. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Alternation { + /// The span of this alternation. + pub span: Span, + /// The alternate regular expressions. + pub asts: Vec<Ast>, +} + +impl Alternation { + /// Return this alternation as an AST. + /// + /// If this alternation contains zero ASTs, then Ast::Empty is + /// returned. If this alternation contains exactly 1 AST, then the + /// corresponding AST is returned. Otherwise, Ast::Alternation is returned. + pub fn into_ast(mut self) -> Ast { + match self.asts.len() { + 0 => Ast::Empty(self.span), + 1 => self.asts.pop().unwrap(), + _ => Ast::Alternation(self), + } + } +} + +/// A concatenation of regular expressions. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Concat { + /// The span of this concatenation. + pub span: Span, + /// The concatenation regular expressions. + pub asts: Vec<Ast>, +} + +impl Concat { + /// Return this concatenation as an AST. + /// + /// If this concatenation contains zero ASTs, then Ast::Empty is + /// returned. If this concatenation contains exactly 1 AST, then the + /// corresponding AST is returned. Otherwise, Ast::Concat is returned. + pub fn into_ast(mut self) -> Ast { + match self.asts.len() { + 0 => Ast::Empty(self.span), + 1 => self.asts.pop().unwrap(), + _ => Ast::Concat(self), + } + } +} + +/// A single literal expression. +/// +/// A literal corresponds to a single Unicode scalar value. Literals may be +/// represented in their literal form, e.g., `a` or in their escaped form, +/// e.g., `\x61`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Literal { + /// The span of this literal. + pub span: Span, + /// The kind of this literal. + pub kind: LiteralKind, + /// The Unicode scalar value corresponding to this literal. + pub c: char, +} + +impl Literal { + /// If this literal was written as a `\x` hex escape, then this returns + /// the corresponding byte value. Otherwise, this returns `None`. + pub fn byte(&self) -> Option<u8> { + let short_hex = LiteralKind::HexFixed(HexLiteralKind::X); + if self.c as u32 <= 255 && self.kind == short_hex { + Some(self.c as u8) + } else { + None + } + } +} + +/// The kind of a single literal expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LiteralKind { + /// The literal is written verbatim, e.g., `a` or `☃`. + Verbatim, + /// The literal is written as an escape because it is punctuation, e.g., + /// `\*` or `\[`. + Punctuation, + /// The literal is written as an octal escape, e.g., `\141`. + Octal, + /// The literal is written as a hex code with a fixed number of digits + /// depending on the type of the escape, e.g., `\x61` or or `\u0061` or + /// `\U00000061`. + HexFixed(HexLiteralKind), + /// The literal is written as a hex code with a bracketed number of + /// digits. The only restriction is that the bracketed hex code must refer + /// to a valid Unicode scalar value. + HexBrace(HexLiteralKind), + /// The literal is written as a specially recognized escape, e.g., `\f` + /// or `\n`. + Special(SpecialLiteralKind), +} + +/// The type of a special literal. +/// +/// A special literal is a special escape sequence recognized by the regex +/// parser, e.g., `\f` or `\n`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum SpecialLiteralKind { + /// Bell, spelled `\a` (`\x07`). + Bell, + /// Form feed, spelled `\f` (`\x0C`). + FormFeed, + /// Tab, spelled `\t` (`\x09`). + Tab, + /// Line feed, spelled `\n` (`\x0A`). + LineFeed, + /// Carriage return, spelled `\r` (`\x0D`). + CarriageReturn, + /// Vertical tab, spelled `\v` (`\x0B`). + VerticalTab, + /// Space, spelled `\ ` (`\x20`). Note that this can only appear when + /// parsing in verbose mode. + Space, +} + +/// The type of a Unicode hex literal. +/// +/// Note that all variants behave the same when used with brackets. They only +/// differ when used without brackets in the number of hex digits that must +/// follow. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum HexLiteralKind { + /// A `\x` prefix. When used without brackets, this form is limited to + /// two digits. + X, + /// A `\u` prefix. When used without brackets, this form is limited to + /// four digits. + UnicodeShort, + /// A `\U` prefix. When used without brackets, this form is limited to + /// eight digits. + UnicodeLong, +} + +impl HexLiteralKind { + /// The number of digits that must be used with this literal form when + /// used without brackets. When used with brackets, there is no + /// restriction on the number of digits. + pub fn digits(&self) -> u32 { + match *self { + HexLiteralKind::X => 2, + HexLiteralKind::UnicodeShort => 4, + HexLiteralKind::UnicodeLong => 8, + } + } +} + +/// A single character class expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Class { + /// A Unicode character class, e.g., `\pL` or `\p{Greek}`. + Unicode(ClassUnicode), + /// A perl character class, e.g., `\d` or `\W`. + Perl(ClassPerl), + /// A bracketed character class set, which may contain zero or more + /// character ranges and/or zero or more nested classes. e.g., + /// `[a-zA-Z\pL]`. + Bracketed(ClassBracketed), +} + +impl Class { + /// Return the span of this character class. + pub fn span(&self) -> &Span { + match *self { + Class::Perl(ref x) => &x.span, + Class::Unicode(ref x) => &x.span, + Class::Bracketed(ref x) => &x.span, + } + } +} + +/// A Perl character class. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassPerl { + /// The span of this class. + pub span: Span, + /// The kind of Perl class. + pub kind: ClassPerlKind, + /// Whether the class is negated or not. e.g., `\d` is not negated but + /// `\D` is. + pub negated: bool, +} + +/// The available Perl character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassPerlKind { + /// Decimal numbers. + Digit, + /// Whitespace. + Space, + /// Word characters. + Word, +} + +/// An ASCII character class. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassAscii { + /// The span of this class. + pub span: Span, + /// The kind of ASCII class. + pub kind: ClassAsciiKind, + /// Whether the class is negated or not. e.g., `[[:alpha:]]` is not negated + /// but `[[:^alpha:]]` is. + pub negated: bool, +} + +/// The available ASCII character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassAsciiKind { + /// `[0-9A-Za-z]` + Alnum, + /// `[A-Za-z]` + Alpha, + /// `[\x00-\x7F]` + Ascii, + /// `[ \t]` + Blank, + /// `[\x00-\x1F\x7F]` + Cntrl, + /// `[0-9]` + Digit, + /// `[!-~]` + Graph, + /// `[a-z]` + Lower, + /// `[ -~]` + Print, + /// `[!-/:-@\[-`{-~]` + Punct, + /// `[\t\n\v\f\r ]` + Space, + /// `[A-Z]` + Upper, + /// `[0-9A-Za-z_]` + Word, + /// `[0-9A-Fa-f]` + Xdigit, +} + +impl ClassAsciiKind { + /// Return the corresponding ClassAsciiKind variant for the given name. + /// + /// The name given should correspond to the lowercase version of the + /// variant name. e.g., `cntrl` is the name for `ClassAsciiKind::Cntrl`. + /// + /// If no variant with the corresponding name exists, then `None` is + /// returned. + pub fn from_name(name: &str) -> Option<ClassAsciiKind> { + use self::ClassAsciiKind::*; + match name { + "alnum" => Some(Alnum), + "alpha" => Some(Alpha), + "ascii" => Some(Ascii), + "blank" => Some(Blank), + "cntrl" => Some(Cntrl), + "digit" => Some(Digit), + "graph" => Some(Graph), + "lower" => Some(Lower), + "print" => Some(Print), + "punct" => Some(Punct), + "space" => Some(Space), + "upper" => Some(Upper), + "word" => Some(Word), + "xdigit" => Some(Xdigit), + _ => None, + } + } +} + +/// A Unicode character class. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassUnicode { + /// The span of this class. + pub span: Span, + /// Whether this class is negated or not. + /// + /// Note: be careful when using this attribute. This specifically refers + /// to whether the class is written as `\p` or `\P`, where the latter + /// is `negated = true`. However, it also possible to write something like + /// `\P{scx!=Katakana}` which is actually equivalent to + /// `\p{scx=Katakana}` and is therefore not actually negated even though + /// `negated = true` here. To test whether this class is truly negated + /// or not, use the `is_negated` method. + pub negated: bool, + /// The kind of Unicode class. + pub kind: ClassUnicodeKind, +} + +impl ClassUnicode { + /// Returns true if this class has been negated. + /// + /// Note that this takes the Unicode op into account, if it's present. + /// e.g., `is_negated` for `\P{scx!=Katakana}` will return `false`. + pub fn is_negated(&self) -> bool { + match self.kind { + ClassUnicodeKind::NamedValue { + op: ClassUnicodeOpKind::NotEqual, .. + } => !self.negated, + _ => self.negated, + } + } +} + +/// The available forms of Unicode character classes. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassUnicodeKind { + /// A one letter abbreviated class, e.g., `\pN`. + OneLetter(char), + /// A binary property, general category or script. The string may be + /// empty. + Named(String), + /// A property name and an associated value. + NamedValue { + /// The type of Unicode op used to associate `name` with `value`. + op: ClassUnicodeOpKind, + /// The property name (which may be empty). + name: String, + /// The property value (which may be empty). + value: String, + }, +} + +/// The type of op used in a Unicode character class. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassUnicodeOpKind { + /// A property set to a specific value, e.g., `\p{scx=Katakana}`. + Equal, + /// A property set to a specific value using a colon, e.g., + /// `\p{scx:Katakana}`. + Colon, + /// A property that isn't a particular value, e.g., `\p{scx!=Katakana}`. + NotEqual, +} + +impl ClassUnicodeOpKind { + /// Whether the op is an equality op or not. + pub fn is_equal(&self) -> bool { + match *self { + ClassUnicodeOpKind::Equal|ClassUnicodeOpKind::Colon => true, + _ => false, + } + } +} + +/// A bracketed character class, e.g., `[a-z0-9]`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassBracketed { + /// The span of this class. + pub span: Span, + /// Whether this class is negated or not. e.g., `[a]` is not negated but + /// `[^a]` is. + pub negated: bool, + /// The type of this set. A set is either a normal union of things, e.g., + /// `[abc]` or a result of applying set operations, e.g., `[\pL--c]`. + pub kind: ClassSet, +} + +/// A character class set. +/// +/// This type corresponds to the internal structure of a bracketed character +/// class. That is, every bracketed character is one of two types: a union of +/// items (literals, ranges, other bracketed classes) or a tree of binary set +/// operations. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassSet { + /// An item, which can be a single literal, range, nested character class + /// or a union of items. + Item(ClassSetItem), + /// A single binary operation (i.e., &&, -- or ~~). + BinaryOp(ClassSetBinaryOp), +} + +impl ClassSet { + /// Build a set from a union. + pub fn union(ast: ClassSetUnion) -> ClassSet { + ClassSet::Item(ClassSetItem::Union(ast)) + } + + /// Return the span of this character class set. + pub fn span(&self) -> &Span { + match *self { + ClassSet::Item(ref x) => x.span(), + ClassSet::BinaryOp(ref x) => &x.span, + } + } + + /// Return true if and only if this class set is empty. + fn is_empty(&self) -> bool { + match *self { + ClassSet::Item(ClassSetItem::Empty(_)) => true, + _ => false, + } + } +} + +/// A single component of a character class set. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ClassSetItem { + /// An empty item. + /// + /// Note that a bracketed character class cannot contain a single empty + /// item. Empty items can appear when using one of the binary operators. + /// For example, `[&&]` is the intersection of two empty classes. + Empty(Span), + /// A single literal. + Literal(Literal), + /// A range between two literals. + Range(ClassSetRange), + /// An ASCII character class, e.g., `[:alnum:]` or `[:punct:]`. + Ascii(ClassAscii), + /// A Unicode character class, e.g., `\pL` or `\p{Greek}`. + Unicode(ClassUnicode), + /// A perl character class, e.g., `\d` or `\W`. + Perl(ClassPerl), + /// A bracketed character class set, which may contain zero or more + /// character ranges and/or zero or more nested classes. e.g., + /// `[a-zA-Z\pL]`. + Bracketed(Box<ClassBracketed>), + /// A union of items. + Union(ClassSetUnion), +} + +impl ClassSetItem { + /// Return the span of this character class set item. + pub fn span(&self) -> &Span { + match *self { + ClassSetItem::Empty(ref span) => span, + ClassSetItem::Literal(ref x) => &x.span, + ClassSetItem::Range(ref x) => &x.span, + ClassSetItem::Ascii(ref x) => &x.span, + ClassSetItem::Perl(ref x) => &x.span, + ClassSetItem::Unicode(ref x) => &x.span, + ClassSetItem::Bracketed(ref x) => &x.span, + ClassSetItem::Union(ref x) => &x.span, + } + } +} + +/// A single character class range in a set. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassSetRange { + /// The span of this range. + pub span: Span, + /// The start of this range. + pub start: Literal, + /// The end of this range. + pub end: Literal, +} + +impl ClassSetRange { + /// Returns true if and only if this character class range is valid. + /// + /// The only case where a range is invalid is if its start is greater than + /// its end. + pub fn is_valid(&self) -> bool { + self.start.c <= self.end.c + } +} + +/// A union of items inside a character class set. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassSetUnion { + /// The span of the items in this operation. e.g., the `a-z0-9` in + /// `[^a-z0-9]` + pub span: Span, + /// The sequence of items that make up this union. + pub items: Vec<ClassSetItem>, +} + +impl ClassSetUnion { + /// Push a new item in this union. + /// + /// The ending position of this union's span is updated to the ending + /// position of the span of the item given. If the union is empty, then + /// the starting position of this union is set to the starting position + /// of this item. + /// + /// In other words, if you only use this method to add items to a union + /// and you set the spans on each item correctly, then you should never + /// need to adjust the span of the union directly. + pub fn push(&mut self, item: ClassSetItem) { + if self.items.is_empty() { + self.span.start = item.span().start; + } + self.span.end = item.span().end; + self.items.push(item); + } + + /// Return this union as a character class set item. + /// + /// If this union contains zero items, then an empty union is + /// returned. If this concatenation contains exactly 1 item, then the + /// corresponding item is returned. Otherwise, ClassSetItem::Union is + /// returned. + pub fn into_item(mut self) -> ClassSetItem { + match self.items.len() { + 0 => ClassSetItem::Empty(self.span), + 1 => self.items.pop().unwrap(), + _ => ClassSetItem::Union(self), + } + } +} + +/// A Unicode character class set operation. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassSetBinaryOp { + /// The span of this operation. e.g., the `a-z--[h-p]` in `[a-z--h-p]`. + pub span: Span, + /// The type of this set operation. + pub kind: ClassSetBinaryOpKind, + /// The left hand side of the operation. + pub lhs: Box<ClassSet>, + /// The right hand side of the operation. + pub rhs: Box<ClassSet>, +} + +/// The type of a Unicode character class set operation. +/// +/// Note that this doesn't explicitly represent union since there is no +/// explicit union operator. Concatenation inside a character class corresponds +/// to the union operation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ClassSetBinaryOpKind { + /// The intersection of two sets, e.g., `\pN&&[a-z]`. + Intersection, + /// The difference of two sets, e.g., `\pN--[0-9]`. + Difference, + /// The symmetric difference of two sets. The symmetric difference is the + /// set of elements belonging to one but not both sets. + /// e.g., `[\pL~~[:ascii:]]`. + SymmetricDifference, +} + +/// A single zero-width assertion. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Assertion { + /// The span of this assertion. + pub span: Span, + /// The assertion kind, e.g., `\b` or `^`. + pub kind: AssertionKind, +} + +/// An assertion kind. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum AssertionKind { + /// `^` + StartLine, + /// `$` + EndLine, + /// `\A` + StartText, + /// `\z` + EndText, + /// `\b` + WordBoundary, + /// `\B` + NotWordBoundary, +} + +/// A repetition operation applied to a regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Repetition { + /// The span of this operation. + pub span: Span, + /// The actual operation. + pub op: RepetitionOp, + /// Whether this operation was applied greedily or not. + pub greedy: bool, + /// The regular expression under repetition. + pub ast: Box<Ast>, +} + +/// The repetition operator itself. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RepetitionOp { + /// The span of this operator. This includes things like `+`, `*?` and + /// `{m,n}`. + pub span: Span, + /// The type of operation. + pub kind: RepetitionKind, +} + +/// The kind of a repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RepetitionKind { + /// `?` + ZeroOrOne, + /// `*` + ZeroOrMore, + /// `+` + OneOrMore, + /// `{m,n}` + Range(RepetitionRange), +} + +/// A range repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RepetitionRange { + /// `{m}` + Exactly(u32), + /// `{m,}` + AtLeast(u32), + /// `{m,n}` + Bounded(u32, u32), +} + +impl RepetitionRange { + /// Returns true if and only if this repetition range is valid. + /// + /// The only case where a repetition range is invalid is if it is bounded + /// and its start is greater than its end. + pub fn is_valid(&self) -> bool { + match *self { + RepetitionRange::Bounded(s, e) if s > e => false, + _ => true, + } + } +} + +/// A grouped regular expression. +/// +/// This includes both capturing and non-capturing groups. This does **not** +/// include flag-only groups like `(?is)`, but does contain any group that +/// contains a sub-expression, e.g., `(a)`, `(?P<name>a)`, `(?:a)` and +/// `(?is:a)`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Group { + /// The span of this group. + pub span: Span, + /// The kind of this group. + pub kind: GroupKind, + /// The regular expression in this group. + pub ast: Box<Ast>, +} + +impl Group { + /// If this group is non-capturing, then this returns the (possibly empty) + /// set of flags. Otherwise, `None` is returned. + pub fn flags(&self) -> Option<&Flags> { + match self.kind { + GroupKind::NonCapturing(ref flags) => Some(flags), + _ => None, + } + } + + /// Returns true if and only if this group is capturing. + pub fn is_capturing(&self) -> bool { + match self.kind { + GroupKind::CaptureIndex(_) | GroupKind::CaptureName(_) => true, + GroupKind::NonCapturing(_) => false, + } + } + + /// Returns the capture index of this group, if this is a capturing group. + /// + /// This returns a capture index precisely when `is_capturing` is `true`. + pub fn capture_index(&self) -> Option<u32> { + match self.kind { + GroupKind::CaptureIndex(i) => Some(i), + GroupKind::CaptureName(ref x) => Some(x.index), + GroupKind::NonCapturing(_) => None, + } + } +} + +/// The kind of a group. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum GroupKind { + /// `(a)` + CaptureIndex(u32), + /// `(?P<name>a)` + CaptureName(CaptureName), + /// `(?:a)` and `(?i:a)` + NonCapturing(Flags), +} + +/// A capture name. +/// +/// This corresponds to the name itself between the angle brackets in, e.g., +/// `(?P<foo>expr)`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CaptureName { + /// The span of this capture name. + pub span: Span, + /// The capture name. + pub name: String, + /// The capture index. + pub index: u32, +} + +/// A group of flags that is not applied to a particular regular expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SetFlags { + /// The span of these flags, including the grouping parentheses. + pub span: Span, + /// The actual sequence of flags. + pub flags: Flags, +} + +/// A group of flags. +/// +/// This corresponds only to the sequence of flags themselves, e.g., `is-u`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Flags { + /// The span of this group of flags. + pub span: Span, + /// A sequence of flag items. Each item is either a flag or a negation + /// operator. + pub items: Vec<FlagsItem>, +} + +impl Flags { + /// Add the given item to this sequence of flags. + /// + /// If the item was added successfully, then `None` is returned. If the + /// given item is a duplicate, then `Some(i)` is returned, where + /// `items[i].kind == item.kind`. + pub fn add_item(&mut self, item: FlagsItem) -> Option<usize> { + for (i, x) in self.items.iter().enumerate() { + if x.kind == item.kind { + return Some(i); + } + } + self.items.push(item); + None + } + + /// Returns the state of the given flag in this set. + /// + /// If the given flag is in the set but is negated, then `Some(false)` is + /// returned. + /// + /// If the given flag is in the set and is not negated, then `Some(true)` + /// is returned. + /// + /// Otherwise, `None` is returned. + pub fn flag_state(&self, flag: Flag) -> Option<bool> { + let mut negated = false; + for x in &self.items { + match x.kind { + FlagsItemKind::Negation => { + negated = true; + } + FlagsItemKind::Flag(ref xflag) if xflag == &flag => { + return Some(!negated); + } + _ => {} + } + } + None + } +} + +/// A single item in a group of flags. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FlagsItem { + /// The span of this item. + pub span: Span, + /// The kind of this item. + pub kind: FlagsItemKind, +} + +/// The kind of an item in a group of flags. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum FlagsItemKind { + /// A negation operator applied to all subsequent flags in the enclosing + /// group. + Negation, + /// A single flag in a group. + Flag(Flag), +} + +impl FlagsItemKind { + /// Returns true if and only if this item is a negation operator. + pub fn is_negation(&self) -> bool { + match *self { + FlagsItemKind::Negation => true, + _ => false, + } + } +} + +/// A single flag. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Flag { + /// `i` + CaseInsensitive, + /// `m` + MultiLine, + /// `s` + DotMatchesNewLine, + /// `U` + SwapGreed, + /// `u` + Unicode, + /// `x` + IgnoreWhitespace, +} + +/// A custom `Drop` impl is used for `Ast` such that it uses constant stack +/// space but heap space proportional to the depth of the `Ast`. +impl Drop for Ast { + fn drop(&mut self) { + use std::mem; + + match *self { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + // Classes are recursive, so they get their own Drop impl. + | Ast::Class(_) => return, + Ast::Repetition(ref x) if !x.ast.has_subexprs() => return, + Ast::Group(ref x) if !x.ast.has_subexprs() => return, + Ast::Alternation(ref x) if x.asts.is_empty() => return, + Ast::Concat(ref x) if x.asts.is_empty() => return, + _ => {} + } + + let empty_span = || Span::splat(Position::new(0, 0, 0)); + let empty_ast = || Ast::Empty(empty_span()); + let mut stack = vec![mem::replace(self, empty_ast())]; + while let Some(mut ast) = stack.pop() { + match ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + // Classes are recursive, so they get their own Drop impl. + | Ast::Class(_) => {} + Ast::Repetition(ref mut x) => { + stack.push(mem::replace(&mut x.ast, empty_ast())); + } + Ast::Group(ref mut x) => { + stack.push(mem::replace(&mut x.ast, empty_ast())); + } + Ast::Alternation(ref mut x) => { + stack.extend(x.asts.drain(..)); + } + Ast::Concat(ref mut x) => { + stack.extend(x.asts.drain(..)); + } + } + } + } +} + +/// A custom `Drop` impl is used for `ClassSet` such that it uses constant +/// stack space but heap space proportional to the depth of the `ClassSet`. +impl Drop for ClassSet { + fn drop(&mut self) { + use std::mem; + + match *self { + ClassSet::Item(ref item) => { + match *item { + ClassSetItem::Empty(_) + | ClassSetItem::Literal(_) + | ClassSetItem::Range(_) + | ClassSetItem::Ascii(_) + | ClassSetItem::Unicode(_) + | ClassSetItem::Perl(_) => return, + ClassSetItem::Bracketed(ref x) => { + if x.kind.is_empty() { + return; + } + } + ClassSetItem::Union(ref x) => { + if x.items.is_empty() { + return; + } + } + } + } + ClassSet::BinaryOp(ref op) => { + if op.lhs.is_empty() && op.rhs.is_empty() { + return; + } + } + } + + let empty_span = || Span::splat(Position::new(0, 0, 0)); + let empty_set = || ClassSet::Item(ClassSetItem::Empty(empty_span())); + let mut stack = vec![mem::replace(self, empty_set())]; + while let Some(mut set) = stack.pop() { + match set { + ClassSet::Item(ref mut item) => { + match *item { + ClassSetItem::Empty(_) + | ClassSetItem::Literal(_) + | ClassSetItem::Range(_) + | ClassSetItem::Ascii(_) + | ClassSetItem::Unicode(_) + | ClassSetItem::Perl(_) => {} + ClassSetItem::Bracketed(ref mut x) => { + stack.push(mem::replace(&mut x.kind, empty_set())); + } + ClassSetItem::Union(ref mut x) => { + stack.extend( + x.items.drain(..).map(ClassSet::Item)); + } + } + } + ClassSet::BinaryOp(ref mut op) => { + stack.push(mem::replace(&mut op.lhs, empty_set())); + stack.push(mem::replace(&mut op.rhs, empty_set())); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // We use a thread with an explicit stack size to test that our destructor + // for Ast can handle arbitrarily sized expressions in constant stack + // space. In case we run on a platform without threads (WASM?), we limit + // this test to Windows/Unix. + #[test] + #[cfg(any(unix, windows))] + fn no_stack_overflow_on_drop() { + use std::thread; + + let run = || { + let span = || Span::splat(Position::new(0, 0, 0)); + let mut ast = Ast::Empty(span()); + for i in 0..200 { + ast = Ast::Group(Group { + span: span(), + kind: GroupKind::CaptureIndex(i), + ast: Box::new(ast), + }); + } + assert!(!ast.is_empty()); + }; + + // We run our test on a thread with a small stack size so we can + // force the issue more easily. + thread::Builder::new() + .stack_size(1<<10) + .spawn(run) + .unwrap() + .join() + .unwrap(); + } +} diff --git a/regex-syntax/src/ast/parse.rs b/regex-syntax/src/ast/parse.rs new file mode 100644 index 000000000..9e9900c96 --- /dev/null +++ b/regex-syntax/src/ast/parse.rs @@ -0,0 +1,5384 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +This module provides a regular expression parser. +*/ + +use std::borrow::Borrow; +use std::cell::{Cell, RefCell}; +use std::mem; +use std::result; + +use ast::{self, Ast, Position, Span}; +use either::Either; + +use is_meta_character; + +type Result<T> = result::Result<T, ast::Error>; + +/// A primitive is an expression with no sub-expressions. This includes +/// literals, assertions and non-set character classes. This representation +/// is used as intermediate state in the parser. +/// +/// This does not include ASCII character classes, since they can only appear +/// within a set character class. +#[derive(Clone, Debug, Eq, PartialEq)] +enum Primitive { + Literal(ast::Literal), + Assertion(ast::Assertion), + Dot(Span), + Perl(ast::ClassPerl), + Unicode(ast::ClassUnicode), +} + +impl Primitive { + /// Return the span of this primitive. + fn span(&self) -> &Span { + match *self { + Primitive::Literal(ref x) => &x.span, + Primitive::Assertion(ref x) => &x.span, + Primitive::Dot(ref span) => span, + Primitive::Perl(ref x) => &x.span, + Primitive::Unicode(ref x) => &x.span, + } + } + + /// Convert this primitive into a proper AST. + fn into_ast(self) -> Ast { + match self { + Primitive::Literal(lit) => Ast::Literal(lit), + Primitive::Assertion(assert) => Ast::Assertion(assert), + Primitive::Dot(span) => Ast::Dot(span), + Primitive::Perl(cls) => Ast::Class(ast::Class::Perl(cls)), + Primitive::Unicode(cls) => Ast::Class(ast::Class::Unicode(cls)), + } + } + + /// Convert this primitive into an item in a character class. + /// + /// If this primitive is not a legal item (i.e., an assertion or a dot), + /// then return an error. + fn into_class_set_item<P: Borrow<Parser>>( + self, + p: &ParserI<P>, + ) -> Result<ast::ClassSetItem> { + use ast::ClassSetItem; + use self::Primitive::*; + + match self { + Literal(lit) => Ok(ClassSetItem::Literal(lit)), + Perl(cls) => Ok(ClassSetItem::Perl(cls)), + Unicode(cls) => Ok(ClassSetItem::Unicode(cls)), + x => Err(p.error(*x.span(), ast::ErrorKind::ClassEscapeInvalid)), + } + } + + /// Convert this primitive into a literal in a character class. In + /// particular, literals are the only valid items that can appear in + /// ranges. + /// + /// If this primitive is not a legal item (i.e., a class, assertion or a + /// dot), then return an error. + fn into_class_literal<P: Borrow<Parser>>( + self, + p: &ParserI<P>, + ) -> Result<ast::Literal> { + use self::Primitive::*; + + match self { + Literal(lit) => Ok(lit), + x => Err(p.error(*x.span(), ast::ErrorKind::ClassRangeLiteral)), + } + } +} + +/// Returns true if the given character is a hexadecimal digit. +fn is_hex(c: char) -> bool { + ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F') +} + +/// Returns true if the given character is a valid in a capture group name. +/// +/// If `first` is true, then `c` is treated as the first character in the +/// group name (which is not allowed to be a digit). +fn is_capture_char(c: char, first: bool) -> bool { + c == '_' || (!first && c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +/// A builder for a regular expression parser. +/// +/// This builder permits modifying configuration options for the parser. +#[derive(Clone, Debug)] +pub struct ParserBuilder { + ignore_whitespace: bool, + nest_limit: u32, + octal: bool, +} + +impl Default for ParserBuilder { + fn default() -> ParserBuilder { + ParserBuilder::new() + } +} + +impl ParserBuilder { + /// Create a new parser builder with a default configuration. + pub fn new() -> ParserBuilder { + ParserBuilder { + ignore_whitespace: false, + nest_limit: 250, + octal: false, + } + } + + /// Build a parser from this configuration with the given pattern. + pub fn build(&self) -> Parser { + Parser { + pos: Cell::new(Position { offset: 0, line: 1, column: 1 }), + capture_index: Cell::new(0), + nest_limit: self.nest_limit, + octal: self.octal, + initial_ignore_whitespace: self.ignore_whitespace, + ignore_whitespace: Cell::new(self.ignore_whitespace), + comments: RefCell::new(vec![]), + stack_group: RefCell::new(vec![]), + stack_class: RefCell::new(vec![]), + capture_names: RefCell::new(vec![]), + scratch: RefCell::new(String::new()), + } + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire Ast is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// lenth of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut ParserBuilder { + self.nest_limit = limit; + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut ParserBuilder { + self.octal = yes; + self + } + + /// Enable verbose mode in the regular expression. + /// + /// When enabled, verbose mode permits insigificant whitespace in many + /// places in the regular expression, as well as comments. Comments are + /// started using `#` and continue until the end of the line. + /// + /// By default, this is disabled. It may be selectively enabled in the + /// regular expression by using the `x` flag regardless of this setting. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut ParserBuilder { + self.ignore_whitespace = yes; + self + } +} + +/// A regular expression parser. +/// +/// This parses a string representation of a regular expression into an +/// abstract syntax tree. The size of the tree is proportional to the length +/// of the regular expression pattern. +/// +/// A `Parser` can be configured in more detail via a +/// [`ParserBuilder`](struct.ParserBuilder.html). +#[derive(Clone, Debug)] +pub struct Parser { + /// The current position of the parser. + pos: Cell<Position>, + /// The current capture index. + capture_index: Cell<u32>, + /// The maximum number of open parens/brackets allowed. If the parser + /// exceeds this number, then an error is returned. + nest_limit: u32, + /// Whether to support octal syntax or not. When `false`, the parser will + /// return an error helpfully pointing out that backreferences are not + /// supported. + octal: bool, + /// The initial setting for `ignore_whitespace` as provided by + /// Th`ParserBuilder`. is is used when reseting the parser's state. + initial_ignore_whitespace: bool, + /// Whether whitespace should be ignored. When enabled, comments are + /// also permitted. + ignore_whitespace: Cell<bool>, + /// A list of comments, in order of appearance. + comments: RefCell<Vec<ast::Comment>>, + /// A stack of grouped sub-expressions, including alternations. + stack_group: RefCell<Vec<GroupState>>, + /// A stack of nested character classes. This is only non-empty when + /// parsing a class. + stack_class: RefCell<Vec<ClassState>>, + /// A sorted sequence of capture names. This is used to detect duplicate + /// capture names and report an error if one is detected. + capture_names: RefCell<Vec<ast::CaptureName>>, + /// A scratch buffer used in various places. Mostly this is used to + /// accumulate relevant characters from parts of a pattern. + scratch: RefCell<String>, +} + +/// ParserI is the internal parser implementation. +/// +/// We use this separate type so that we can carry the provided pattern string +/// along with us. In particular, a `Parser` internal state is not tied to any +/// one pattern, but `ParserI` is. +/// +/// This type also lets us use `ParserI<&Parser>` in production code while +/// retaining the convenience of `ParserI<Parser>` for tests, which sometimes +/// work against the internal interface of the parser. +#[derive(Clone, Debug)] +struct ParserI<'s, P> { + /// The parser state/configuration. + parser: P, + /// The full regular expression provided by the user. + pattern: &'s str, +} + +/// GroupState represents a single stack frame while parsing nested groups +/// and alternations. Each frame records the state up to an opening parenthesis +/// or a alternating bracket `|`. +#[derive(Clone, Debug)] +enum GroupState { + /// This state is pushed whenever an opening group is found. + Group { + /// The concatenation immediately preceding the opening group. + concat: ast::Concat, + /// The group that has been opened. Its sub-AST is always empty. + group: ast::Group, + /// Whether this group has the `x` flag enabled or not. + ignore_whitespace: bool, + }, + /// This state is pushed whenever a new alternation branch is found. If + /// an alternation branch is found and this state is at the top of the + /// stack, then this state should be modified to include the new + /// alternation. + Alternation(ast::Alternation), +} + +/// ClassState represents a single stack frame while parsing character classes. +/// Each frame records the state up to an intersection, difference, symmetric +/// difference or nested class. +/// +/// Note that a parser's character class stack is only non-empty when parsing +/// a character class. In all other cases, it is empty. +#[derive(Clone, Debug)] +enum ClassState { + /// This state is pushed whenever an opening bracket is found. + Open { + /// The union of class items immediately preceding this class. + union: ast::ClassSetUnion, + /// The class that has been opened. Typically this just corresponds + /// to the `[`, but it can also include `[^` since `^` indicates + /// negation of the class. + set: ast::ClassBracketed, + }, + /// This state is pushed when a operator is seen. When popped, the stored + /// set becomes the left hand side of the operator. + Op { + /// The type of the operation, i.e., &&, -- or ~~. + kind: ast::ClassSetBinaryOpKind, + /// The left-hand side of the operator. + lhs: ast::ClassSet, + }, +} + +impl Parser { + /// Create a new parser with a default configuration. + /// + /// The parser can be run with either the `parse` or `parse_with_comments` + /// methods. The parse methods return an abstract syntax tree. + /// + /// To set configuration options on the parser, use + /// [`ParserBuilder`](struct.ParserBuilder.html). + pub fn new() -> Parser { + ParserBuilder::new().build() + } + + /// Parse the regular expression into an abstract syntax tree. + pub fn parse(&mut self, pattern: &str) -> Result<Ast> { + ParserI::new(self, pattern).parse() + } + + /// Parse the regular expression and return an abstract syntax tree with + /// all of the comments found in the pattern. + pub fn parse_with_comments( + &mut self, + pattern: &str, + ) -> Result<ast::WithComments> { + ParserI::new(self, pattern).parse_with_comments() + } + + /// Reset the internal state of a parser. + /// + /// This is called at the beginning of every parse. This prevents the + /// parser from running with inconsistent state (say, if a previous + /// invocation returned an error and the parser is reused). + fn reset(&self) { + // These settings should be in line with the construction + // in `ParserBuilder::build`. + self.pos.set(Position { offset: 0, line: 1, column: 1}); + self.ignore_whitespace.set(self.initial_ignore_whitespace); + self.comments.borrow_mut().clear(); + self.stack_group.borrow_mut().clear(); + self.stack_class.borrow_mut().clear(); + } +} + +impl<'s, P: Borrow<Parser>> ParserI<'s, P> { + /// Build an internal parser from a parser configuration and a pattern. + fn new(parser: P, pattern: &'s str) -> ParserI<'s, P> { + ParserI { parser: parser, pattern: pattern } + } + + /// Return a reference to the parser state. + fn parser(&self) -> &Parser { + self.parser.borrow() + } + + /// Return a reference to the pattern being parsed. + fn pattern(&self) -> &str { + self.pattern.borrow() + } + + /// Create a new error with the given span and error type. + fn error(&self, span: Span, kind: ast::ErrorKind) -> ast::Error { + ast::Error { + kind: kind, + pattern: self.pattern().to_string(), + span: span, + } + } + + /// Return the current offset of the parser. + /// + /// The offset starts at `0` from the beginning of the regular expression + /// pattern string. + fn offset(&self) -> usize { + self.parser().pos.get().offset + } + + /// Return the current line number of the parser. + /// + /// The line number starts at `1`. + fn line(&self) -> usize { + self.parser().pos.get().line + } + + /// Return the current column of the parser. + /// + /// The column number starts at `1` and is reset whenever a `\n` is seen. + fn column(&self) -> usize { + self.parser().pos.get().column + } + + /// Return the next capturing index. Each subsequent call increments the + /// internal index. + /// + /// The span given should correspond to the location of the opening + /// parenthesis. + /// + /// If the capture limit is exceeded, then an error is returned. + fn next_capture_index(&self, span: Span) -> Result<u32> { + let current = self.parser().capture_index.get(); + let i = current.checked_add(1).ok_or_else(|| { + self.error(span, ast::ErrorKind::CaptureLimitExceeded) + })?; + self.parser().capture_index.set(i); + Ok(i) + } + + /// Adds the given capture name to this parser. If this capture name has + /// already been used, then an error is returned. + fn add_capture_name(&self, cap: &ast::CaptureName) -> Result<()> { + let mut names = self.parser().capture_names.borrow_mut(); + match names.binary_search_by_key( + &cap.name.as_str(), + |c| c.name.as_str(), + ) { + Err(i) => { + names.insert(i, cap.clone()); + Ok(()) + } + Ok(i) => { + Err(self.error(cap.span, ast::ErrorKind::GroupNameDuplicate { + original: names[i].span, + })) + } + } + } + + /// Return whether the parser should ignore whitespace or not. + fn ignore_whitespace(&self) -> bool { + self.parser().ignore_whitespace.get() + } + + /// Return the character at the current position of the parser. + /// + /// This panics if the current position does not point to a valid char. + fn char(&self) -> char { + self.char_at(self.offset()) + } + + /// Return the character at the given position. + /// + /// This panics if the given position does not point to a valid char. + fn char_at(&self, i: usize) -> char { + self.pattern()[i..].chars().next() + .unwrap_or_else(|| { + panic!("expected char at offset {}", i) + }) + } + + /// Bump the parser to the next Unicode scalar value. + /// + /// If the end of the input has been reached, then `false` is returned. + fn bump(&self) -> bool { + if self.is_eof() { + return false; + } + let Position { mut offset, mut line, mut column } = self.pos(); + if self.char() == '\n' { + line = line.checked_add(1).unwrap(); + column = 1; + } else { + column = column.checked_add(1).unwrap(); + } + offset += self.char().len_utf8(); + self.parser().pos.set(Position { + offset: offset, + line: line, + column: column, + }); + self.pattern()[self.offset()..].chars().next().is_some() + } + + /// If the substring starting at the current position of the parser has + /// the given prefix, then bump the parser to the character immediately + /// following the prefix and return true. Otherwise, don't bump the parser + /// and return false. + fn bump_if(&self, prefix: &str) -> bool { + if self.pattern()[self.offset()..].starts_with(prefix) { + for _ in 0..prefix.chars().count() { + self.bump(); + } + true + } else { + false + } + } + + /// Returns true if and only if the parser is positioned at a look-around + /// prefix. The conditions under which this returns true must always + /// correspond to a regular expression that would otherwise be consider + /// invalid. + /// + /// This should only be called immediately after parsing the opening of + /// a group or a set of flags. + fn is_lookaround_prefix(&self) -> bool { + self.bump_if("?=") + || self.bump_if("?!") + || self.bump_if("?<=") + || self.bump_if("?<!") + } + + /// Bump the parser, and if the `x` flag is enabled, bump through any + /// subsequent spaces. Return true if and only if the parser is not at + /// EOF. + fn bump_and_bump_space(&self) -> bool { + if !self.bump() { + return false; + } + self.bump_space(); + !self.is_eof() + } + + /// If the `x` flag is enabled (i.e., whitespace insensitivity with + /// comments), then this will advance the parser through all whitespace + /// and comments to the next non-whitespace non-comment byte. + /// + /// If the `x` flag is disabled, then this is a no-op. + /// + /// This should be used selectively throughout the parser where + /// arbitrary whitespace is permitted when the `x` flag is enabled. For + /// example, `{ 5 , 6}` is equivalent to `{5,6}`. + fn bump_space(&self) { + if !self.ignore_whitespace() { + return; + } + while !self.is_eof() { + if self.char().is_whitespace() { + self.bump(); + } else if self.char() == '#' { + let start = self.pos(); + let mut comment_text = String::new(); + self.bump(); + while !self.is_eof() { + let c = self.char(); + self.bump(); + if c == '\n' { + break; + } + comment_text.push(c); + } + let comment = ast::Comment { + span: Span::new(start, self.pos()), + comment: comment_text, + }; + self.parser().comments.borrow_mut().push(comment); + } else { + break; + } + } + } + + /// Peek at the next character in the input without advancing the parser. + /// + /// If the input has been exhausted, then this returns `None`. + fn peek(&self) -> Option<char> { + if self.is_eof() { + return None; + } + self.pattern()[self.offset() + self.char().len_utf8()..].chars().next() + } + + /// Like peek, but will ignore spaces when the parser is in whitespace + /// insensitive mode. + fn peek_space(&self) -> Option<char> { + if !self.ignore_whitespace() { + return self.peek(); + } + if self.is_eof() { + return None; + } + let mut start = self.offset() + self.char().len_utf8(); + let mut in_comment = false; + for (i, c) in self.pattern()[start..].char_indices() { + if c.is_whitespace() { + continue; + } else if !in_comment && c == '#' { + in_comment = true; + } else if in_comment && c == '\n' { + in_comment = false; + } else { + start += i; + break; + } + } + self.pattern()[start..].chars().next() + } + + /// Returns true if the next call to `bump` would return false. + fn is_eof(&self) -> bool { + self.offset() == self.pattern().len() + } + + /// Return the current position of the parser, which includes the offset, + /// line and column. + fn pos(&self) -> Position { + self.parser().pos.get() + } + + /// Create a span at the current position of the parser. Both the start + /// and end of the span are set. + fn span(&self) -> Span { + Span::splat(self.pos()) + } + + /// Create a span that covers the current character. + fn span_char(&self) -> Span { + let mut next = Position { + offset: self.offset().checked_add(self.char().len_utf8()).unwrap(), + line: self.line(), + column: self.column().checked_add(1).unwrap(), + }; + if self.char() == '\n' { + next.line += 1; + next.column = 1; + } + Span::new(self.pos(), next) + } + + /// Parse and push a single alternation on to the parser's internal stack. + /// If the top of the stack already has an alternation, then add to that + /// instead of pushing a new one. + /// + /// The concatenation given corresponds to a single alternation branch. + /// The concatenation returned starts the next branch and is empty. + /// + /// This assumes the parser is currently positioned at `|` and will advance + /// the parser to the character following `|`. + fn push_alternate(&self, mut concat: ast::Concat) -> Result<ast::Concat> { + assert_eq!(self.char(), '|'); + concat.span.end = self.pos(); + self.push_or_add_alternation(concat); + self.bump(); + Ok(ast::Concat { + span: self.span(), + asts: vec![], + }) + } + + /// Pushes or adds the given branch of an alternation to the parser's + /// internal stack of state. + fn push_or_add_alternation(&self, concat: ast::Concat) { + use self::GroupState::*; + + let mut stack = self.parser().stack_group.borrow_mut(); + if let Some(&mut Alternation(ref mut alts)) = stack.last_mut() { + alts.asts.push(concat.into_ast()); + return; + } + stack.push(Alternation(ast::Alternation { + span: Span::new(concat.span.start, self.pos()), + asts: vec![concat.into_ast()], + })); + } + + /// Parse and push a group AST (and its parent concatenation) on to the + /// parser's internal stack. Return a fresh concatenation corresponding + /// to the group's sub-AST. + /// + /// If a set of flags was found (with no group), then the concatenation + /// is returned with that set of flags added. + /// + /// This assumes that the parser is currently positioned on the opening + /// parenthesis. It advances the parser to the character at the start + /// of the sub-expression (or adjoining expression). + /// + /// If there was a problem parsing the start of the group, then an error + /// is returned. + fn push_group(&self, mut concat: ast::Concat) -> Result<ast::Concat> { + assert_eq!(self.char(), '('); + match self.parse_group()? { + Either::Left(set) => { + let ignore = set.flags.flag_state(ast::Flag::IgnoreWhitespace); + if let Some(v) = ignore { + self.parser().ignore_whitespace.set(v); + } + + concat.asts.push(Ast::Flags(set)); + Ok(concat) + } + Either::Right(group) => { + let old_ignore_whitespace = self.ignore_whitespace(); + let new_ignore_whitespace = group + .flags() + .and_then(|f| f.flag_state(ast::Flag::IgnoreWhitespace)) + .unwrap_or(old_ignore_whitespace); + self.parser().stack_group.borrow_mut().push(GroupState::Group { + concat: concat, + group: group, + ignore_whitespace: old_ignore_whitespace, + }); + self.parser().ignore_whitespace.set(new_ignore_whitespace); + Ok(ast::Concat { + span: self.span(), + asts: vec![], + }) + } + } + } + + /// Pop a group AST from the parser's internal stack and set the group's + /// AST to the given concatenation. Return the concatenation containing + /// the group. + /// + /// This assumes that the parser is currently positioned on the closing + /// parenthesis and advances the parser to the character following the `)`. + /// + /// If no such group could be popped, then an unopened group error is + /// returned. + fn pop_group(&self, mut group_concat: ast::Concat) -> Result<ast::Concat> { + use self::GroupState::*; + + assert_eq!(self.char(), ')'); + let mut stack = self.parser().stack_group.borrow_mut(); + let (mut prior_concat, mut group, ignore_whitespace, alt) = + match stack.pop() { + Some(Group { concat, group, ignore_whitespace }) => { + (concat, group, ignore_whitespace, None) + } + Some(Alternation(alt)) => { + match stack.pop() { + Some(Group { concat, group, ignore_whitespace }) => { + (concat, group, ignore_whitespace, Some(alt)) + } + None | Some(Alternation(_)) => { + return Err(self.error( + self.span_char(), + ast::ErrorKind::GroupUnopened, + )); + } + } + } + None => { + return Err(self.error( + self.span_char(), + ast::ErrorKind::GroupUnopened, + )); + } + }; + self.parser().ignore_whitespace.set(ignore_whitespace); + group_concat.span.end = self.pos(); + self.bump(); + group.span.end = self.pos(); + match alt { + Some(mut alt) => { + alt.span.end = group_concat.span.end; + alt.asts.push(group_concat.into_ast()); + group.ast = Box::new(alt.into_ast()); + } + None => { + group.ast = Box::new(group_concat.into_ast()); + } + } + prior_concat.asts.push(Ast::Group(group)); + Ok(prior_concat) + } + + /// Pop the last state from the parser's internal stack, if it exists, and + /// add the given concatenation to it. There either must be no state or a + /// single alternation item on the stack. Any other scenario produces an + /// error. + /// + /// This assumes that the parser has advanced to the end. + fn pop_group_end(&self, mut concat: ast::Concat) -> Result<Ast> { + concat.span.end = self.pos(); + let mut stack = self.parser().stack_group.borrow_mut(); + let ast = match stack.pop() { + None => Ok(concat.into_ast()), + Some(GroupState::Alternation(mut alt)) => { + alt.span.end = self.pos(); + alt.asts.push(concat.into_ast()); + Ok(Ast::Alternation(alt)) + } + Some(GroupState::Group { group, .. }) => { + return Err(self.error( + group.span, + ast::ErrorKind::GroupUnclosed, + )); + } + }; + // If we try to pop again, there should be nothing. + match stack.pop() { + None => ast, + Some(GroupState::Alternation(_)) => { + // This unreachable is unfortunate. This case can't happen + // because the only way we can be here is if there were two + // `GroupState::Alternation`s adjacent in the parser's stack, + // which we guarantee to never happen because we never push a + // `GroupState::Alternation` if one is already at the top of + // the stack. + unreachable!() + } + Some(GroupState::Group { group, .. }) => { + Err(self.error(group.span, ast::ErrorKind::GroupUnclosed)) + } + } + } + + /// Parse the opening of a character class and push the current class + /// parsing context onto the parser's stack. This assumes that the parser + /// is positioned at an opening `[`. The given union should correspond to + /// the union of set items built up before seeing the `[`. + /// + /// If there was a problem parsing the opening of the class, then an error + /// is returned. Otherwise, a new union of set items for the class is + /// returned (which may be populated with either a `]` or a `-`). + fn push_class_open( + &self, + parent_union: ast::ClassSetUnion, + ) -> Result<ast::ClassSetUnion> { + assert_eq!(self.char(), '['); + + let (nested_set, nested_union) = self.parse_set_class_open()?; + self.parser().stack_class.borrow_mut().push(ClassState::Open { + union: parent_union, + set: nested_set, + }); + Ok(nested_union) + } + + /// Parse the end of a character class set and pop the character class + /// parser stack. The union given corresponds to the last union built + /// before seeing the closing `]`. The union returned corresponds to the + /// parent character class set with the nested class added to it. + /// + /// This assumes that the parser is positioned at a `]` and will advance + /// the parser to the byte immediately following the `]`. + /// + /// If the stack is empty after popping, then this returns the final + /// "top-level" character class AST (where a "top-level" character class + /// is one that is not nested inside any other character class). + /// + /// If there is no corresponding opening bracket on the parser's stack, + /// then an error is returned. + fn pop_class( + &self, + nested_union: ast::ClassSetUnion, + ) -> Result<Either<ast::ClassSetUnion, ast::Class>> { + assert_eq!(self.char(), ']'); + + let item = ast::ClassSet::Item(nested_union.into_item()); + let prevset = self.pop_class_op(item); + let mut stack = self.parser().stack_class.borrow_mut(); + match stack.pop() { + None => { + // We can never observe an empty stack: + // + // 1) We are guaranteed to start with a non-empty stack since + // the character class parser is only initiated when it sees + // a `[`. + // 2) If we ever observe an empty stack while popping after + // seeing a `]`, then we signal the character class parser + // to terminate. + panic!("unexpected empty character class stack") + }, + Some(ClassState::Op { .. }) => { + // This panic is unfortunate, but this case is impossible + // since we already popped the Op state if one exists above. + // Namely, every push to the class parser stack is guarded by + // whether an existing Op is already on the top of the stack. + // If it is, the existing Op is modified. That is, the stack + // can never have consecutive Op states. + panic!("unexpected ClassState::Op") + } + Some(ClassState::Open { mut union, mut set }) => { + self.bump(); + set.span.end = self.pos(); + set.kind = prevset; + if stack.is_empty() { + Ok(Either::Right(ast::Class::Bracketed(set))) + } else { + union.push(ast::ClassSetItem::Bracketed(Box::new(set))); + Ok(Either::Left(union)) + } + } + } + } + + /// Return an "unclosed class" error whose span points to the most + /// recently opened class. + /// + /// This should only be called while parsing a character class. + fn unclosed_class_error(&self) -> ast::Error { + for state in self.parser().stack_class.borrow().iter().rev() { + match *state { + ClassState::Open { ref set, .. } => { + return self.error(set.span, ast::ErrorKind::ClassUnclosed); + } + _ => {} + } + } + // We are guaranteed to have a non-empty stack with at least + // one open bracket, so we should never get here. + panic!("no open character class found") + } + + /// Push the current set of class items on to the class parser's stack as + /// the left hand side of the given operator. + /// + /// A fresh set union is returned, which should be used to build the right + /// hand side of this operator. + fn push_class_op( + &self, + next_kind: ast::ClassSetBinaryOpKind, + next_union: ast::ClassSetUnion, + ) -> ast::ClassSetUnion { + + let item = ast::ClassSet::Item(next_union.into_item()); + let new_lhs = self.pop_class_op(item); + self.parser().stack_class.borrow_mut().push(ClassState::Op { + kind: next_kind, + lhs: new_lhs, + }); + ast::ClassSetUnion { span: self.span(), items: vec![] } + } + + /// Pop a character class set from the character class parser stack. If the + /// top of the stack is just an item (not an operation), then return the + /// given set unchanged. If the top of the stack is an operation, then the + /// given set will be used as the rhs of the operation on the top of the + /// stack. In that case, the binary operation is returned as a set. + fn pop_class_op(&self, rhs: ast::ClassSet) -> ast::ClassSet { + let mut stack = self.parser().stack_class.borrow_mut(); + let (kind, lhs) = match stack.pop() { + Some(ClassState::Op { kind, lhs }) => (kind, lhs), + Some(state @ ClassState::Open { .. }) => { + stack.push(state); + return rhs; + } + None => unreachable!(), + }; + let span = Span::new(lhs.span().start, rhs.span().end); + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span: span, + kind: kind, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } +} + +impl<'s, P: Borrow<Parser>> ParserI<'s, P> { + /// Parse the regular expression into an abstract syntax tree. + fn parse(&self) -> Result<Ast> { + self.parse_with_comments().map(|astc| astc.ast) + } + + /// Parse the regular expression and return an abstract syntax tree with + /// all of the comments found in the pattern. + fn parse_with_comments(&self) -> Result<ast::WithComments> { + assert_eq!(self.offset(), 0, "parser can only be used once"); + self.parser().reset(); + let mut concat = ast::Concat { + span: self.span(), + asts: vec![], + }; + loop { + self.bump_space(); + if self.is_eof() { + break; + } + match self.char() { + '(' => concat = self.push_group(concat)?, + ')' => concat = self.pop_group(concat)?, + '|' => concat = self.push_alternate(concat)?, + '[' => { + let class = self.parse_set_class()?; + concat.asts.push(Ast::Class(class)); + } + '?' => { + concat = self.parse_uncounted_repetition( + concat, ast::RepetitionKind::ZeroOrOne)?; + } + '*' => { + concat = self.parse_uncounted_repetition( + concat, ast::RepetitionKind::ZeroOrMore)?; + } + '+' => { + concat = self.parse_uncounted_repetition( + concat, ast::RepetitionKind::OneOrMore)?; + } + '{' => { + concat = self.parse_counted_repetition(concat)?; + } + _ => concat.asts.push(self.parse_primitive()?.into_ast()), + } + } + let ast = self.pop_group_end(concat)?; + NestLimiter::new(self).check(&ast)?; + Ok(ast::WithComments { + ast: ast, + comments: mem::replace( + &mut *self.parser().comments.borrow_mut(), + vec![], + ), + }) + } + + /// Parses an uncounted repetition operation. An uncounted repetition + /// operator includes ?, * and +, but does not include the {m,n} syntax. + /// The given `kind` should correspond to the operator observed by the + /// caller. + /// + /// This assumes that the paser is currently positioned at the repetition + /// operator and advances the parser to the first character after the + /// operator. (Note that the operator may include a single additional `?`, + /// which makes the operator ungreedy.) + /// + /// The caller should include the concatenation that is being built. The + /// concatenation returned includes the repetition operator applied to the + /// last expression in the given concatenation. + fn parse_uncounted_repetition( + &self, + mut concat: ast::Concat, + kind: ast::RepetitionKind, + ) -> Result<ast::Concat> { + assert!( + self.char() == '?' || self.char() == '*' || self.char() == '+'); + let op_start = self.pos(); + let ast = match concat.asts.pop() { + Some(ast) => ast, + None => return Err(self.error( + self.span(), + ast::ErrorKind::RepetitionMissing, + )), + }; + match ast { + Ast::Empty(_) | Ast::Flags(_) => return Err(self.error( + self.span(), + ast::ErrorKind::RepetitionMissing, + )), + _ => {} + } + let mut greedy = true; + if self.bump() && self.char() == '?' { + greedy = false; + self.bump(); + } + concat.asts.push(Ast::Repetition(ast::Repetition { + span: ast.span().with_end(self.pos()), + op: ast::RepetitionOp { + span: Span::new(op_start, self.pos()), + kind: kind, + }, + greedy: greedy, + ast: Box::new(ast), + })); + Ok(concat) + } + + /// Parses a counted repetition operation. A counted repetition operator + /// corresponds to the {m,n} syntax, and does not include the ?, * or + + /// operators. + /// + /// This assumes that the paser is currently positioned at the opening `{` + /// and advances the parser to the first character after the operator. + /// (Note that the operator may include a single additional `?`, which + /// makes the operator ungreedy.) + /// + /// The caller should include the concatenation that is being built. The + /// concatenation returned includes the repetition operator applied to the + /// last expression in the given concatenation. + fn parse_counted_repetition( + &self, + mut concat: ast::Concat, + ) -> Result<ast::Concat> { + assert!(self.char() == '{'); + let start = self.pos(); + let ast = match concat.asts.pop() { + Some(ast) => ast, + None => return Err(self.error( + self.span(), + ast::ErrorKind::RepetitionMissing, + )), + }; + match ast { + Ast::Empty(_) | Ast::Flags(_) => return Err(self.error( + self.span(), + ast::ErrorKind::RepetitionMissing, + )), + _ => {} + } + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + let count_start = self.parse_decimal()?; + let mut range = ast::RepetitionRange::Exactly(count_start); + if self.is_eof() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + if self.char() == ',' { + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + if self.char() != '}' { + let count_end = self.parse_decimal()?; + range = ast::RepetitionRange::Bounded(count_start, count_end); + } else { + range = ast::RepetitionRange::AtLeast(count_start); + } + } + if self.is_eof() || self.char() != '}' { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::RepetitionCountUnclosed, + )); + } + + let mut greedy = true; + if self.bump_and_bump_space() && self.char() == '?' { + greedy = false; + self.bump(); + } + + let op_span = Span::new(start, self.pos()); + if !range.is_valid() { + return Err(self.error( + op_span, + ast::ErrorKind::RepetitionCountInvalid, + )); + } + concat.asts.push(Ast::Repetition(ast::Repetition { + span: ast.span().with_end(self.pos()), + op: ast::RepetitionOp { + span: op_span, + kind: ast::RepetitionKind::Range(range), + }, + greedy: greedy, + ast: Box::new(ast), + })); + Ok(concat) + } + + /// Parse a group (which contains a sub-expression) or a set of flags. + /// + /// If a group was found, then it is returned with an empty AST. If a set + /// of flags is found, then that set is returned. + /// + /// The parser should be positioned at the opening parenthesis. + /// + /// This advances the parser to the character before the start of the + /// sub-expression (in the case of a group) or to the closing parenthesis + /// immediately following the set of flags. + /// + /// # Errors + /// + /// If flags are given and incorrectly specified, then a corresponding + /// error is returned. + /// + /// If a capture name is given and it is incorrectly specified, then a + /// corresponding error is returned. + fn parse_group(&self) -> Result<Either<ast::SetFlags, ast::Group>> { + assert_eq!(self.char(), '('); + let open_span = self.span_char(); + self.bump(); + self.bump_space(); + if self.is_lookaround_prefix() { + return Err(self.error( + Span::new(open_span.start, self.span().end), + ast::ErrorKind::UnsupportedLookAround, + )); + } + let inner_span = self.span(); + if self.bump_if("?P<") { + let capture_index = self.next_capture_index(open_span)?; + let cap = self.parse_capture_name(capture_index)?; + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::CaptureName(cap), + ast: Box::new(Ast::Empty(self.span())), + })) + } else if self.bump_if("?") { + if self.is_eof() { + return Err(self.error( + open_span, + ast::ErrorKind::GroupUnclosed, + )); + } + let flags = self.parse_flags()?; + let char_end = self.char(); + self.bump(); + if char_end == ')' { + // We don't allow empty flags, e.g., `(?)`. We instead + // interpret it as a repetition operator missing its argument. + if flags.items.is_empty() { + return Err(self.error( + inner_span, + ast::ErrorKind::RepetitionMissing, + )); + } + Ok(Either::Left(ast::SetFlags { + span: Span { end: self.pos(), ..open_span }, + flags: flags, + })) + } else { + assert_eq!(char_end, ':'); + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::NonCapturing(flags), + ast: Box::new(Ast::Empty(self.span())), + })) + } + } else { + let capture_index = self.next_capture_index(open_span)?; + Ok(Either::Right(ast::Group { + span: open_span, + kind: ast::GroupKind::CaptureIndex(capture_index), + ast: Box::new(Ast::Empty(self.span())), + })) + } + } + + /// Parses a capture group name. Assumes that the parser is positioned at + /// the first character in the name following the opening `<` (and may + /// possibly be EOF). This advances the parser to the first character + /// following the closing `>`. + /// + /// The caller must provide the capture index of the group for this name. + fn parse_capture_name( + &self, + capture_index: u32, + ) -> Result<ast::CaptureName> { + if self.is_eof() { + return Err(self.error( + self.span(), + ast::ErrorKind::GroupNameUnexpectedEof, + )); + } + let start = self.pos(); + loop { + if self.char() == '>' { + break; + } + if !is_capture_char(self.char(), self.pos() == start) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::GroupNameInvalid, + )); + } + if !self.bump() { + break; + } + } + let end = self.pos(); + if self.is_eof() { + return Err(self.error( + self.span(), + ast::ErrorKind::GroupNameUnexpectedEof, + )); + } + assert_eq!(self.char(), '>'); + self.bump(); + let name = &self.pattern()[start.offset..end.offset]; + if name.is_empty() { + return Err(self.error( + Span::new(start, start), + ast::ErrorKind::GroupNameEmpty, + )); + } + let capname = ast::CaptureName { + span: Span::new(start, end), + name: name.to_string(), + index: capture_index, + }; + self.add_capture_name(&capname)?; + Ok(capname) + } + + /// Parse a sequence of flags starting at the current character. + /// + /// This advances the parser to the character immediately following the + /// flags, which is guaranteed to be either `:` or `)`. + /// + /// # Errors + /// + /// If any flags are duplicated, then an error is returned. + /// + /// If the negation operator is used more than once, then an error is + /// returned. + /// + /// If no flags could be found or if the negation operation is not followed + /// by any flags, then an error is returned. + fn parse_flags(&self) -> Result<ast::Flags> { + let mut flags = ast::Flags { + span: self.span(), + items: vec![], + }; + let mut last_was_negation = None; + while self.char() != ':' && self.char() != ')' { + if self.char() == '-' { + last_was_negation = Some(self.span_char()); + let item = ast::FlagsItem { + span: self.span_char(), + kind: ast::FlagsItemKind::Negation, + }; + if let Some(i) = flags.add_item(item) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::FlagRepeatedNegation { + original: flags.items[i].span, + }, + )); + } + } else { + last_was_negation = None; + let item = ast::FlagsItem { + span: self.span_char(), + kind: ast::FlagsItemKind::Flag(self.parse_flag()?), + }; + if let Some(i) = flags.add_item(item) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::FlagDuplicate { + original: flags.items[i].span, + }, + )); + } + } + if !self.bump() { + return Err(self.error( + self.span(), + ast::ErrorKind::FlagUnexpectedEof, + )); + } + } + if let Some(span) = last_was_negation { + return Err(self.error(span, ast::ErrorKind::FlagDanglingNegation)); + } + flags.span.end = self.pos(); + Ok(flags) + } + + /// Parse the current character as a flag. Do not advance the parser. + /// + /// # Errors + /// + /// If the flag is not recognized, then an error is returned. + fn parse_flag(&self) -> Result<ast::Flag> { + match self.char() { + 'i' => Ok(ast::Flag::CaseInsensitive), + 'm' => Ok(ast::Flag::MultiLine), + 's' => Ok(ast::Flag::DotMatchesNewLine), + 'U' => Ok(ast::Flag::SwapGreed), + 'u' => Ok(ast::Flag::Unicode), + 'x' => Ok(ast::Flag::IgnoreWhitespace), + _ => Err(self.error( + self.span_char(), + ast::ErrorKind::FlagUnrecognized, + )), + } + } + + /// Parse a primitive AST. e.g., A literal, non-set character class or + /// assertion. + /// + /// This assumes that the parser expects a primitive at the current + /// location. i.e., All other non-primitive cases have been handled. + /// For example, if the parser's position is at `|`, then `|` will be + /// treated as a literal (e.g., inside a character class). + /// + /// This advances the parser to the first character immediately following + /// the primitive. + fn parse_primitive(&self) -> Result<Primitive> { + match self.char() { + '\\' => self.parse_escape(), + '.' => { + let ast = Primitive::Dot(self.span_char()); + self.bump(); + Ok(ast) + } + '^' => { + let ast = Primitive::Assertion(ast::Assertion { + span: self.span_char(), + kind: ast::AssertionKind::StartLine, + }); + self.bump(); + Ok(ast) + } + '$' => { + let ast = Primitive::Assertion(ast::Assertion { + span: self.span_char(), + kind: ast::AssertionKind::EndLine, + }); + self.bump(); + Ok(ast) + } + c => { + let ast = Primitive::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: c, + }); + self.bump(); + Ok(ast) + } + } + } + + /// Parse an escape sequence as a primitive AST. + /// + /// This assumes the parser is positioned at the start of the escape + /// sequence, i.e., `\`. It advances the parser to the first position + /// immediately following the escape sequence. + fn parse_escape(&self) -> Result<Primitive> { + assert_eq!(self.char(), '\\'); + let start = self.pos(); + if !self.bump() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + let c = self.char(); + // Put some of the more complicated routines into helpers. + match c { + '0'...'7' => { + if !self.parser().octal { + return Err(self.error( + Span::new(start, self.span_char().end), + ast::ErrorKind::UnsupportedBackreference, + )); + } + let mut lit = self.parse_octal(); + lit.span.start = start; + return Ok(Primitive::Literal(lit)); + } + '8'...'9' if !self.parser().octal => { + return Err(self.error( + Span::new(start, self.span_char().end), + ast::ErrorKind::UnsupportedBackreference, + )); + } + 'x' | 'u' | 'U' => { + let mut lit = self.parse_hex()?; + lit.span.start = start; + return Ok(Primitive::Literal(lit)); + } + 'p' | 'P' => { + let mut cls = self.parse_unicode_class()?; + cls.span.start = start; + return Ok(Primitive::Unicode(cls)); + } + 'd' | 's' | 'w' | 'D' | 'S' | 'W' => { + let mut cls = self.parse_perl_class(); + cls.span.start = start; + return Ok(Primitive::Perl(cls)); + } + _ => {} + } + + // Handle all of the one letter sequences inline. + self.bump(); + let span = Span::new(start, self.pos()); + if is_meta_character(c) { + return Ok(Primitive::Literal(ast::Literal { + span: span, + kind: ast::LiteralKind::Punctuation, + c: c, + })); + } + let special = |kind, c| Ok(Primitive::Literal(ast::Literal { + span: span, + kind: ast::LiteralKind::Special(kind), + c: c, + })); + match c { + 'a' => special(ast::SpecialLiteralKind::Bell, '\x07'), + 'f' => special(ast::SpecialLiteralKind::FormFeed, '\x0C'), + 't' => special(ast::SpecialLiteralKind::Tab, '\t'), + 'n' => special(ast::SpecialLiteralKind::LineFeed, '\n'), + 'r' => special(ast::SpecialLiteralKind::CarriageReturn, '\r'), + 'v' => special(ast::SpecialLiteralKind::VerticalTab, '\x0B'), + ' ' if self.ignore_whitespace() => { + special(ast::SpecialLiteralKind::Space, ' ') + } + 'A' => Ok(Primitive::Assertion(ast::Assertion { + span: span, + kind: ast::AssertionKind::StartText, + })), + 'z' => Ok(Primitive::Assertion(ast::Assertion { + span: span, + kind: ast::AssertionKind::EndText, + })), + 'b' => Ok(Primitive::Assertion(ast::Assertion { + span: span, + kind: ast::AssertionKind::WordBoundary, + })), + 'B' => Ok(Primitive::Assertion(ast::Assertion { + span: span, + kind: ast::AssertionKind::NotWordBoundary, + })), + _ => Err(self.error(span, ast::ErrorKind::EscapeUnrecognized)), + } + } + + /// Parse an octal representation of a Unicode codepoint up to 3 digits + /// long. This expects the parser to be positioned at the first octal + /// digit and advances the parser to the first character immediately + /// following the octal number. This also assumes that parsing octal + /// escapes is enabled. + /// + /// Assuming the preconditions are met, this routine can never fail. + fn parse_octal(&self) -> ast::Literal { + use std::char; + use std::u32; + + assert!(self.parser().octal); + assert!('0' <= self.char() && self.char() <= '7'); + let start = self.pos(); + // Parse up to two more digits. + while + self.bump() && + '0' <= self.char() && self.char() <= '7' && + self.pos().offset - start.offset <= 2 + {} + let end = self.pos(); + let octal = &self.pattern()[start.offset..end.offset]; + // Parsing the octal should never fail since the above guarantees a + // valid number. + let codepoint = + u32::from_str_radix(octal, 8).expect("valid octal number"); + // The max value for 3 digit octal is 0777 = 511 and [0, 511] has no + // invalid Unicode scalar values. + let c = char::from_u32(codepoint).expect("Unicode scalar value"); + ast::Literal { + span: Span::new(start, end), + kind: ast::LiteralKind::Octal, + c: c, + } + } + + /// Parse a hex representation of a Unicode codepoint. This handles both + /// hex notations, i.e., `\xFF` and `\x{FFFF}`. This expects the parser to + /// be positioned at the `x`, `u` or `U` prefix. The parser is advanced to + /// the first character immediately following the hexadecimal literal. + fn parse_hex(&self) -> Result<ast::Literal> { + assert!(self.char() == 'x' + || self.char() == 'u' + || self.char() == 'U'); + + let hex_kind = match self.char() { + 'x' => ast::HexLiteralKind::X, + 'u' => ast::HexLiteralKind::UnicodeShort, + _ => ast::HexLiteralKind::UnicodeLong, + }; + if !self.bump_and_bump_space() { + return Err(self.error( + self.span(), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + if self.char() == '{' { + self.parse_hex_brace(hex_kind) + } else { + self.parse_hex_digits(hex_kind) + } + } + + /// Parse an N-digit hex representation of a Unicode codepoint. This + /// expects the parser to be positioned at the first digit and will advance + /// the parser to the first character immediately following the escape + /// sequence. + /// + /// The number of digits given must be 2 (for `\xNN`), 4 (for `\uNNNN`) + /// or 8 (for `\UNNNNNNNN`). + fn parse_hex_digits( + &self, + kind: ast::HexLiteralKind, + ) -> Result<ast::Literal> { + use std::char; + use std::u32; + + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let start = self.pos(); + for i in 0..kind.digits() { + if i > 0 && !self.bump_and_bump_space() { + return Err(self.error( + self.span(), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + if !is_hex(self.char()) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::EscapeHexInvalidDigit, + )); + } + scratch.push(self.char()); + } + // The final bump just moves the parser past the literal, which may + // be EOF. + self.bump_and_bump_space(); + let end = self.pos(); + let hex = scratch.as_str(); + match u32::from_str_radix(hex, 16).ok().and_then(char::from_u32) { + None => Err(self.error( + Span::new(start, end), + ast::ErrorKind::EscapeHexInvalid, + )), + Some(c) => Ok(ast::Literal { + span: Span::new(start, end), + kind: ast::LiteralKind::HexFixed(kind), + c: c, + }), + } + } + + /// Parse a hex representation of any Unicode scalar value. This expects + /// the parser to be positioned at the opening brace `{` and will advance + /// the parser to the first character following the closing brace `}`. + fn parse_hex_brace( + &self, + kind: ast::HexLiteralKind, + ) -> Result<ast::Literal> { + use std::char; + use std::u32; + + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let brace_pos = self.pos(); + let start = self.span_char().end; + while self.bump_and_bump_space() && self.char() != '}' { + if !is_hex(self.char()) { + return Err(self.error( + self.span_char(), + ast::ErrorKind::EscapeHexInvalidDigit, + )); + } + scratch.push(self.char()); + } + if self.is_eof() { + return Err(self.error( + Span::new(brace_pos, self.pos()), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + let end = self.pos(); + let hex = scratch.as_str(); + assert_eq!(self.char(), '}'); + self.bump_and_bump_space(); + + if hex.is_empty() { + return Err(self.error( + Span::new(brace_pos, self.pos()), + ast::ErrorKind::EscapeHexEmpty, + )); + } + match u32::from_str_radix(hex, 16).ok().and_then(char::from_u32) { + None => Err(self.error( + Span::new(start, end), + ast::ErrorKind::EscapeHexInvalid, + )), + Some(c) => Ok(ast::Literal { + span: Span::new(start, self.pos()), + kind: ast::LiteralKind::HexBrace(kind), + c: c, + }), + } + } + + /// Parse a decimal number into a u32 while trimming leading and trailing + /// whitespace. + /// + /// This expects the parser to be positioned at the first position where + /// a decimal digit could occur. This will advance the parser to the byte + /// immediately following the last contiguous decimal digit. + /// + /// If no decimal digit could be found or if there was a problem parsing + /// the complete set of digits into a u32, then an error is returned. + fn parse_decimal(&self) -> Result<u32> { + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + while !self.is_eof() && self.char().is_whitespace() { + self.bump(); + } + let start = self.pos(); + while !self.is_eof() && '0' <= self.char() && self.char() <= '9' { + scratch.push(self.char()); + self.bump_and_bump_space(); + } + let span = Span::new(start, self.pos()); + while !self.is_eof() && self.char().is_whitespace() { + self.bump_and_bump_space(); + } + let digits = scratch.as_str(); + if digits.is_empty() { + return Err(self.error(span, ast::ErrorKind::DecimalEmpty)); + } + match u32::from_str_radix(digits, 10).ok() { + Some(n) => Ok(n), + None => Err(self.error(span, ast::ErrorKind::DecimalInvalid)), + } + } + + /// Parse a standard character class consisting primarily of characters or + /// character ranges, but can also contain nested character classes of + /// any type (sans `.`). + /// + /// This assumes the parser is positioned at the opening `[`. If parsing + /// is successful, then the parser is advanced to the position immediately + /// following the closing `]`. + fn parse_set_class(&self) -> Result<ast::Class> { + assert_eq!(self.char(), '['); + + let mut union = ast::ClassSetUnion { + span: self.span(), + items: vec![], + }; + loop { + self.bump_space(); + if self.is_eof() { + return Err(self.unclosed_class_error()); + } + match self.char() { + '[' => { + // If we've already parsed the opening bracket, then + // attempt to treat this as the beginning of an ASCII + // class. If ASCII class parsing fails, then the parser + // backs up to `[`. + if !self.parser().stack_class.borrow().is_empty() { + if let Some(cls) = self.maybe_parse_ascii_class() { + union.push(ast::ClassSetItem::Ascii(cls)); + continue; + } + } + union = self.push_class_open(union)?; + } + ']' => { + match self.pop_class(union)? { + Either::Left(nested_union) => { union = nested_union; } + Either::Right(class) => return Ok(class), + } + } + '&' if self.peek() == Some('&') => { + assert!(self.bump_if("&&")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::Intersection, union); + } + '-' if self.peek() == Some('-') => { + assert!(self.bump_if("--")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::Difference, union); + } + '~' if self.peek() == Some('~') => { + assert!(self.bump_if("~~")); + union = self.push_class_op( + ast::ClassSetBinaryOpKind::SymmetricDifference, union); + } + _ => { + union.push(self.parse_set_class_range()?); + } + } + } + } + + /// Parse a single primitive item in a character class set. The item to + /// be parsed can either be one of a simple literal character, a range + /// between two simple literal characters or a "primitive" character + /// class like \w or \p{Greek}. + /// + /// If an invalid escape is found, or if a character class is found where + /// a simple literal is expected (e.g., in a range), then an error is + /// returned. + fn parse_set_class_range(&self) -> Result<ast::ClassSetItem> { + let prim1 = self.parse_set_class_item()?; + self.bump_space(); + if self.is_eof() { + return Err(self.unclosed_class_error()); + } + // If the next char isn't a `-`, then we don't have a range. + // There are two exceptions. If the char after a `-` is a `]`, then + // `-` is interpreted as a literal `-`. Alternatively, if the char + // after a `-` is a `-`, then `--` corresponds to a "difference" + // operation. + if self.char() != '-' + || self.peek_space() == Some(']') + || self.peek_space() == Some('-') + { + return prim1.into_class_set_item(self); + } + // OK, now we're parsing a range, so bump past the `-` and parse the + // second half of the range. + if !self.bump_and_bump_space() { + return Err(self.unclosed_class_error()); + } + let prim2 = self.parse_set_class_item()?; + let range = ast::ClassSetRange { + span: Span::new(prim1.span().start, prim2.span().end), + start: prim1.into_class_literal(self)?, + end: prim2.into_class_literal(self)?, + }; + if !range.is_valid() { + return Err(self.error( + range.span, + ast::ErrorKind::ClassRangeInvalid, + )); + } + Ok(ast::ClassSetItem::Range(range)) + } + + /// Parse a single item in a character class as a primitive, where the + /// primitive either consists of a verbatim literal or a single escape + /// sequence. + /// + /// This assumes the parser is positioned at the beginning of a primitive, + /// and advances the parser to the first position after the primitive if + /// successful. + /// + /// Note that it is the caller's responsibility to report an error if an + /// illegal primitive was parsed. + fn parse_set_class_item(&self) -> Result<Primitive> { + if self.char() == '\\' { + self.parse_escape() + } else { + let x = Primitive::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: self.char(), + }); + self.bump(); + Ok(x) + } + } + + /// Parses the opening of a character class set. This includes the opening + /// bracket along with `^` if present to indicate negation. This also + /// starts parsing the opening set of unioned items if applicable, since + /// there are special rules applied to certain characters in the opening + /// of a character class. For example, `[^]]` is the class of all + /// characters not equal to `]`. (`]` would need to be escaped in any other + /// position.) Similarly for `-`. + /// + /// In all cases, the op inside the returned `ast::ClassBracketed` is an + /// empty union. This empty union should be replaced with the actual item + /// when it is popped from the parser's stack. + /// + /// This assumes the parser is positioned at the opening `[` and advances + /// the parser to the first non-special byte of the character class. + /// + /// An error is returned if EOF is found. + fn parse_set_class_open( + &self, + ) -> Result<(ast::ClassBracketed, ast::ClassSetUnion)> { + assert_eq!(self.char(), '['); + let start = self.pos(); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + + let negated = + if self.char() != '^' { + false + } else { + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + true + }; + // Accept any number of `-` as literal `-`. + let mut union = ast::ClassSetUnion { + span: self.span(), + items: vec![], + }; + while self.char() == '-' { + union.push(ast::ClassSetItem::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: '-', + })); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + } + // If `]` is the *first* char in a set, then interpret it as a literal + // `]`. That is, an empty class is impossible to write. + if union.items.is_empty() && self.char() == ']' { + union.push(ast::ClassSetItem::Literal(ast::Literal { + span: self.span_char(), + kind: ast::LiteralKind::Verbatim, + c: ']', + })); + if !self.bump_and_bump_space() { + return Err(self.error( + Span::new(start, self.pos()), + ast::ErrorKind::ClassUnclosed, + )); + } + } + let set = ast::ClassBracketed { + span: Span::new(start, self.pos()), + negated: negated, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: Span::new(union.span.start, union.span.start), + items: vec![], + }), + }; + Ok((set, union)) + } + + /// Attempt to parse an ASCII character class, e.g., `[:alnum:]`. + /// + /// This assumes the parser is positioned at the opening `[`. + /// + /// If no valid ASCII character class could be found, then this does not + /// advance the parser and `None` is returned. Otherwise, the parser is + /// advanced to the first byte following the closing `]` and the + /// corresponding ASCII class is returned. + fn maybe_parse_ascii_class(&self) -> Option<ast::ClassAscii> { + // ASCII character classes are interesting from a parsing perspective + // because parsing cannot fail with any interesting error. For example, + // in order to use an ASCII character class, it must be enclosed in + // double brackets, e.g., `[[:alnum:]]`. Alternatively, you might think + // of it as "ASCII character characters have the syntax `[:NAME:]` + // which can only appear within character brackets." This means that + // things like `[[:lower:]A]` are legal constructs. + // + // However, if one types an incorrect ASCII character class, e.g., + // `[[:loower:]]`, then we treat that as a normal nested character + // class containing the characters `:elorw`. One might argue that we + // should return an error instead since the repeated colons give away + // the intent to write an ASCII class. But what if the user typed + // `[[:lower]]` instead? How can we tell that was intended to be an + // ASCII class and not just a normal nested class? + // + // Reasonable people can probably disagree over this, but for better + // or worse, we implement semantics that never fails at the expense + // of better failure modes. + assert_eq!(self.char(), '['); + // If parsing fails, then we back up the parser to this starting point. + let start = self.pos(); + let mut negated = false; + if !self.bump() || self.char() != ':' { + self.parser().pos.set(start); + return None; + } + if !self.bump() { + self.parser().pos.set(start); + return None; + } + if self.char() == '^' { + negated = true; + if !self.bump() { + self.parser().pos.set(start); + return None; + } + } + let name_start = self.offset(); + while self.char() != ':' && self.bump() {} + if self.is_eof() { + self.parser().pos.set(start); + return None; + } + let name = &self.pattern()[name_start..self.offset()]; + if !self.bump_if(":]") { + self.parser().pos.set(start); + return None; + } + let kind = match ast::ClassAsciiKind::from_name(name) { + Some(kind) => kind, + None => { + self.parser().pos.set(start); + return None; + } + }; + Some(ast::ClassAscii { + span: Span::new(start, self.pos()), + kind: kind, + negated: negated, + }) + } + + /// Parse a Unicode class in either the single character notation, `\pN` + /// or the multi-character bracketed notation, `\p{Greek}`. This assumes + /// the parser is positioned at the `p` (or `P` for negation) and will + /// advance the parser to the character immediately following the class. + /// + /// Note that this does not check whether the class name is valid or not. + fn parse_unicode_class(&self) -> Result<ast::ClassUnicode> { + assert!(self.char() == 'p' || self.char() == 'P'); + + let mut scratch = self.parser().scratch.borrow_mut(); + scratch.clear(); + + let negated = self.char() == 'P'; + if !self.bump_and_bump_space() { + return Err(self.error( + self.span(), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + let (start, kind) = + if self.char() == '{' { + let start = self.span_char().end; + while self.bump_and_bump_space() && self.char() != '}' { + scratch.push(self.char()); + } + if self.is_eof() { + return Err(self.error( + self.span(), + ast::ErrorKind::EscapeUnexpectedEof, + )); + } + assert_eq!(self.char(), '}'); + self.bump(); + + let name = scratch.as_str(); + if let Some(i) = name.find("!=") { + (start, ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: name[..i].to_string(), + value: name[i+2..].to_string(), + }) + } else if let Some(i) = name.find(':') { + (start, ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: name[..i].to_string(), + value: name[i+1..].to_string(), + }) + } else if let Some(i) = name.find('=') { + (start, ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: name[..i].to_string(), + value: name[i+1..].to_string(), + }) + } else { + (start, ast::ClassUnicodeKind::Named(name.to_string())) + } + } else { + let start = self.pos(); + let c = self.char(); + self.bump_and_bump_space(); + let kind = ast::ClassUnicodeKind::OneLetter(c); + (start, kind) + }; + Ok(ast::ClassUnicode { + span: Span::new(start, self.pos()), + negated: negated, + kind: kind, + }) + } + + /// Parse a Perl character class, e.g., `\d` or `\W`. This assumes the + /// parser is currently at a valid character class name and will be + /// advanced to the character immediately following the class. + fn parse_perl_class(&self) -> ast::ClassPerl { + let c = self.char(); + let span = self.span_char(); + self.bump(); + let (negated, kind) = match c { + 'd' => (false, ast::ClassPerlKind::Digit), + 'D' => (true, ast::ClassPerlKind::Digit), + 's' => (false, ast::ClassPerlKind::Space), + 'S' => (true, ast::ClassPerlKind::Space), + 'w' => (false, ast::ClassPerlKind::Word), + 'W' => (true, ast::ClassPerlKind::Word), + c => panic!("expected valid Perl class but got '{}'", c), + }; + ast::ClassPerl { span: span, kind: kind, negated: negated } + } +} + +/// A type that traverses a fully parsed Ast and checks whether its depth +/// exceeds the specified nesting limit. If it does, then an error is returned. +#[derive(Debug)] +struct NestLimiter<'p, 's: 'p, P: 'p + 's> { + /// The parser that is checking the nest limit. + p: &'p ParserI<'s, P>, + /// The current depth while walking an Ast. + depth: u32, +} + +impl<'p, 's, P: Borrow<Parser>> NestLimiter<'p, 's, P> { + fn new(p: &'p ParserI<'s, P>) -> NestLimiter<'p, 's, P> { + NestLimiter { p: p, depth: 0 } + } + + fn check(self, ast: &Ast) -> Result<()> { + ast::visit(ast, self) + } + + fn increment_depth(&mut self, span: &Span) -> Result<()> { + let new = self.depth.checked_add(1).ok_or_else(|| self.p.error( + span.clone(), + ast::ErrorKind::NestLimitExceeded(::std::u32::MAX), + ))?; + let limit = self.p.parser().nest_limit; + if new > limit { + return Err(self.p.error( + span.clone(), + ast::ErrorKind::NestLimitExceeded(limit), + )); + } + self.depth = new; + Ok(()) + } + + fn decrement_depth(&mut self) { + // Assuming the correctness of the visitor, this should never drop + // below 0. + self.depth = self.depth.checked_sub(1).unwrap(); + } +} + +impl<'p, 's, P: Borrow<Parser>> ast::Visitor for NestLimiter<'p, 's, P> { + type Output = (); + type Err = ast::Error; + + fn finish(self) -> Result<()> { + Ok(()) + } + + fn visit_pre(&mut self, ast: &Ast) -> Result<()> { + let span = match *ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + | Ast::Class(ast::Class::Unicode(_)) + | Ast::Class(ast::Class::Perl(_)) => { + // These are all base cases, so we don't increment depth. + return Ok(()); + } + Ast::Class(ast::Class::Bracketed(ref x)) => &x.span, + Ast::Repetition(ref x) => &x.span, + Ast::Group(ref x) => &x.span, + Ast::Alternation(ref x) => &x.span, + Ast::Concat(ref x) => &x.span, + }; + self.increment_depth(span) + } + + fn visit_post(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Empty(_) + | Ast::Flags(_) + | Ast::Literal(_) + | Ast::Dot(_) + | Ast::Assertion(_) + | Ast::Class(ast::Class::Unicode(_)) + | Ast::Class(ast::Class::Perl(_)) => { + // These are all base cases, so we don't decrement depth. + Ok(()) + } + Ast::Class(ast::Class::Bracketed(_)) + | Ast::Repetition(_) + | Ast::Group(_) + | Ast::Alternation(_) + | Ast::Concat(_) => { + self.decrement_depth(); + Ok(()) + } + } + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + let span = match *ast { + ast::ClassSetItem::Empty(_) + | ast::ClassSetItem::Literal(_) + | ast::ClassSetItem::Range(_) + | ast::ClassSetItem::Ascii(_) + | ast::ClassSetItem::Unicode(_) + | ast::ClassSetItem::Perl(_) => { + // These are all base cases, so we don't increment depth. + return Ok(()); + } + ast::ClassSetItem::Bracketed(ref x) => &x.span, + ast::ClassSetItem::Union(ref x) => &x.span, + }; + self.increment_depth(span) + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Empty(_) + | ast::ClassSetItem::Literal(_) + | ast::ClassSetItem::Range(_) + | ast::ClassSetItem::Ascii(_) + | ast::ClassSetItem::Unicode(_) + | ast::ClassSetItem::Perl(_) => { + // These are all base cases, so we don't decrement depth. + Ok(()) + } + ast::ClassSetItem::Bracketed(_) + | ast::ClassSetItem::Union(_) => { + self.decrement_depth(); + Ok(()) + } + } + } + + fn visit_class_set_binary_op_pre( + &mut self, + ast: &ast::ClassSetBinaryOp, + ) -> Result<()> { + self.increment_depth(&ast.span) + } + + fn visit_class_set_binary_op_post( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<()> { + self.decrement_depth(); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::ops::Range; + + use ast::{self, Ast, Position, Span}; + use super::{Parser, ParserI, ParserBuilder, Primitive}; + + // Our own assert_eq, which has slightly better formatting (but honestly + // still kind of crappy). + macro_rules! assert_eq { + ($left:expr, $right:expr) => ({ + match (&$left, &$right) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + panic!("assertion failed: `(left == right)`\n\n\ + left: `{:?}`\nright: `{:?}`\n\n", + left_val, right_val) + } + } + } + }); + } + + // We create these errors to compare with real ast::Errors in the tests. + // We define equality between TestError and ast::Error to disregard the + // pattern string in ast::Error, which is annoying to provide in tests. + #[derive(Clone, Debug)] + struct TestError { + span: Span, + kind: ast::ErrorKind, + } + + impl PartialEq<ast::Error> for TestError { + fn eq(&self, other: &ast::Error) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + impl PartialEq<TestError> for ast::Error { + fn eq(&self, other: &TestError) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + fn s(str: &str) -> String { + str.to_string() + } + + fn parser(pattern: &str) -> ParserI<Parser> { + ParserI::new(Parser::new(), pattern) + } + + fn parser_octal(pattern: &str) -> ParserI<Parser> { + let parser = ParserBuilder::new().octal(true).build(); + ParserI::new(parser, pattern) + } + + fn parser_nest_limit(pattern: &str, nest_limit: u32) -> ParserI<Parser> { + let p = ParserBuilder::new().nest_limit(nest_limit).build(); + ParserI::new(p, pattern) + } + + fn parser_ignore_whitespace(pattern: &str) -> ParserI<Parser> { + let p = ParserBuilder::new().ignore_whitespace(true).build(); + ParserI::new(p, pattern) + } + + /// Short alias for creating a new span. + fn nspan(start: Position, end: Position) -> Span { + Span::new(start, end) + } + + /// Short alias for creating a new position. + fn npos(offset: usize, line: usize, column: usize) -> Position { + Position::new(offset, line, column) + } + + /// Create a new span from the given offset range. This assumes a single + /// line and sets the columns based on the offsets. i.e., This only works + /// out of the box for ASCII, which is fine for most tests. + fn span(range: Range<usize>) -> Span { + let start = Position::new(range.start, 1, range.start + 1); + let end = Position::new(range.end, 1, range.end + 1); + Span::new(start, end) + } + + /// Create a new span for the corresponding byte range in the given string. + fn span_range(subject: &str, range: Range<usize>) -> Span { + let start = Position { + offset: range.start, + line: 1 + subject[..range.start].matches('\n').count(), + column: 1 + subject[..range.start] + .chars() + .rev() + .position(|c| c == '\n') + .unwrap_or(subject[..range.start].chars().count()), + }; + let end = Position { + offset: range.end, + line: 1 + subject[..range.end].matches('\n').count(), + column: 1 + subject[..range.end] + .chars() + .rev() + .position(|c| c == '\n') + .unwrap_or(subject[..range.end].chars().count()), + }; + Span::new(start, end) + } + + /// Create a verbatim literal starting at the given position. + fn lit(c: char, start: usize) -> Ast { + lit_with(c, span(start..start + c.len_utf8())) + } + + /// Create a punctuation literal starting at the given position. + fn punct_lit(c: char, span: Span) -> Ast { + Ast::Literal(ast::Literal { + span: span, + kind: ast::LiteralKind::Punctuation, + c: c, + }) + } + + /// Create a verbatim literal with the given span. + fn lit_with(c: char, span: Span) -> Ast { + Ast::Literal(ast::Literal { + span: span, + kind: ast::LiteralKind::Verbatim, + c: c, + }) + } + + /// Create a concatenation with the given range. + fn concat(range: Range<usize>, asts: Vec<Ast>) -> Ast { + concat_with(span(range), asts) + } + + /// Create a concatenation with the given span. + fn concat_with(span: Span, asts: Vec<Ast>) -> Ast { + Ast::Concat(ast::Concat { span: span, asts: asts }) + } + + /// Create an alternation with the given span. + fn alt(range: Range<usize>, asts: Vec<Ast>) -> Ast { + Ast::Alternation(ast::Alternation { span: span(range), asts: asts }) + } + + /// Create a capturing group with the given span. + fn group(range: Range<usize>, index: u32, ast: Ast) -> Ast { + Ast::Group(ast::Group { + span: span(range), + kind: ast::GroupKind::CaptureIndex(index), + ast: Box::new(ast), + }) + } + + /// Create an ast::SetFlags. + /// + /// The given pattern should be the full pattern string. The range given + /// should correspond to the byte offsets where the flag set occurs. + /// + /// If negated is true, then the set is interpreted as beginning with a + /// negation. + fn flag_set( + pat: &str, + range: Range<usize>, + flag: ast::Flag, + negated: bool, + ) -> Ast { + let mut items = vec![ + ast::FlagsItem { + span: span_range(pat, (range.end - 2)..(range.end - 1)), + kind: ast::FlagsItemKind::Flag(flag), + }, + ]; + if negated { + items.insert(0, ast::FlagsItem { + span: span_range(pat, (range.start + 2)..(range.end - 2)), + kind: ast::FlagsItemKind::Negation, + }); + } + Ast::Flags(ast::SetFlags { + span: span_range(pat, range.clone()), + flags: ast::Flags { + span: span_range(pat, (range.start + 2)..(range.end - 1)), + items: items, + }, + }) + } + + #[test] + fn parse_nest_limit() { + // A nest limit of 0 still allows some types of regexes. + assert_eq!( + parser_nest_limit("", 0).parse(), + Ok(Ast::Empty(span(0..0)))); + assert_eq!( + parser_nest_limit("a", 0).parse(), + Ok(lit('a', 0))); + + // Test repetition operations, which require one level of nesting. + assert_eq!( + parser_nest_limit("a+", 0).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(0), + }); + assert_eq!( + parser_nest_limit("a+", 1).parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser_nest_limit("(a)+", 1).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(1), + }); + assert_eq!( + parser_nest_limit("a+*", 1).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(1), + }); + assert_eq!( + parser_nest_limit("a+*", 2).parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrMore, + }, + greedy: true, + ast: Box::new(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + })), + }))); + + // Test concatenations. A concatenation requires one level of nesting. + assert_eq!( + parser_nest_limit("ab", 0).parse().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::NestLimitExceeded(0), + }); + assert_eq!( + parser_nest_limit("ab", 1).parse(), + Ok(concat(0..2, vec![lit('a', 0), lit('b', 1)]))); + assert_eq!( + parser_nest_limit("abc", 1).parse(), + Ok(concat(0..3, vec![lit('a', 0), lit('b', 1), lit('c', 2)]))); + + // Test alternations. An alternation requires one level of nesting. + assert_eq!( + parser_nest_limit("a|b", 0).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(0), + }); + assert_eq!( + parser_nest_limit("a|b", 1).parse(), + Ok(alt(0..3, vec![lit('a', 0), lit('b', 2)]))); + assert_eq!( + parser_nest_limit("a|b|c", 1).parse(), + Ok(alt(0..5, vec![lit('a', 0), lit('b', 2), lit('c', 4)]))); + + // Test character classes. Classes form their own mini-recursive + // syntax! + assert_eq!( + parser_nest_limit("[a]", 0).parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::NestLimitExceeded(0), + }); + assert_eq!( + parser_nest_limit("[a]", 1).parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: ast::ClassSet::Item( + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: 'a', + }) + ), + })))); + assert_eq!( + parser_nest_limit("[ab]", 1).parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::NestLimitExceeded(1), + }); + assert_eq!( + parser_nest_limit("[ab[cd]]", 2).parse().unwrap_err(), + TestError { + span: span(3..7), + kind: ast::ErrorKind::NestLimitExceeded(2), + }); + assert_eq!( + parser_nest_limit("[ab[cd]]", 3).parse().unwrap_err(), + TestError { + span: span(4..6), + kind: ast::ErrorKind::NestLimitExceeded(3), + }); + assert_eq!( + parser_nest_limit("[a--b]", 1).parse().unwrap_err(), + TestError { + span: span(1..5), + kind: ast::ErrorKind::NestLimitExceeded(1), + }); + assert_eq!( + parser_nest_limit("[a--bc]", 2).parse().unwrap_err(), + TestError { + span: span(4..6), + kind: ast::ErrorKind::NestLimitExceeded(2), + }); + } + + #[test] + fn parse_comments() { + let pat = "(?x) +# This is comment 1. +foo # This is comment 2. + # This is comment 3. +bar +# This is comment 4."; + let astc = parser(pat).parse_with_comments().unwrap(); + assert_eq!( + astc.ast, + concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('f', span_range(pat, 26..27)), + lit_with('o', span_range(pat, 27..28)), + lit_with('o', span_range(pat, 28..29)), + lit_with('b', span_range(pat, 74..75)), + lit_with('a', span_range(pat, 75..76)), + lit_with('r', span_range(pat, 76..77)), + ])); + assert_eq!(astc.comments, vec![ + ast::Comment { + span: span_range(pat, 5..26), + comment: s(" This is comment 1."), + }, + ast::Comment { + span: span_range(pat, 30..51), + comment: s(" This is comment 2."), + }, + ast::Comment { + span: span_range(pat, 53..74), + comment: s(" This is comment 3."), + }, + ast::Comment { + span: span_range(pat, 78..98), + comment: s(" This is comment 4."), + }, + ]); + } + + #[test] + fn parse_holistic() { + assert_eq!( + parser("]").parse(), + Ok(lit(']', 0))); + assert_eq!( + parser(r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~").parse(), + Ok(concat(0..36, vec![ + punct_lit('\\', span(0..2)), + punct_lit('.', span(2..4)), + punct_lit('+', span(4..6)), + punct_lit('*', span(6..8)), + punct_lit('?', span(8..10)), + punct_lit('(', span(10..12)), + punct_lit(')', span(12..14)), + punct_lit('|', span(14..16)), + punct_lit('[', span(16..18)), + punct_lit(']', span(18..20)), + punct_lit('{', span(20..22)), + punct_lit('}', span(22..24)), + punct_lit('^', span(24..26)), + punct_lit('$', span(26..28)), + punct_lit('#', span(28..30)), + punct_lit('&', span(30..32)), + punct_lit('-', span(32..34)), + punct_lit('~', span(34..36)), + ]))); + } + + #[test] + fn parse_ignore_whitespace() { + // Test that basic whitespace insensitivity works. + let pat = "(?x)a b"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(nspan(npos(0, 1, 1), npos(7, 1, 8)), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('b', nspan(npos(6, 1, 7), npos(7, 1, 8))), + ]))); + + // Test that we can toggle whitespace insensitivity. + let pat = "(?x)a b(?-x)a b"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(nspan(npos(0, 1, 1), npos(15, 1, 16)), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('b', nspan(npos(6, 1, 7), npos(7, 1, 8))), + flag_set(pat, 7..12, ast::Flag::IgnoreWhitespace, true), + lit_with('a', nspan(npos(12, 1, 13), npos(13, 1, 14))), + lit_with(' ', nspan(npos(13, 1, 14), npos(14, 1, 15))), + lit_with('b', nspan(npos(14, 1, 15), npos(15, 1, 16))), + ]))); + + // Test that nesting whitespace insensitive flags works. + let pat = "a (?x:a )a "; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..11), vec![ + lit_with('a', span_range(pat, 0..1)), + lit_with(' ', span_range(pat, 1..2)), + Ast::Group(ast::Group { + span: span_range(pat, 2..9), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span_range(pat, 4..5), + items: vec![ + ast::FlagsItem { + span: span_range(pat, 4..5), + kind: ast::FlagsItemKind::Flag( + ast::Flag::IgnoreWhitespace), + }, + ], + }), + ast: Box::new(lit_with('a', span_range(pat, 6..7))), + }), + lit_with('a', span_range(pat, 9..10)), + lit_with(' ', span_range(pat, 10..11)), + ]))); + + // Test that whitespace after an opening paren is insignificant. + let pat = "(?x)( ?P<foo> a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::CaptureName(ast::CaptureName { + span: span_range(pat, 9..12), + name: s("foo"), + index: 1, + }), + ast: Box::new(lit_with('a', span_range(pat, 14..15))), + }), + ]))); + let pat = "(?x)( a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::CaptureIndex(1), + ast: Box::new(lit_with('a', span_range(pat, 7..8))), + }), + ]))); + let pat = "(?x)( ?: a )"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Group(ast::Group { + span: span_range(pat, 4..pat.len()), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span_range(pat, 8..8), + items: vec![], + }), + ast: Box::new(lit_with('a', span_range(pat, 11..12))), + }), + ]))); + let pat = r"(?x)\x { 53 }"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Literal(ast::Literal { + span: span(4..13), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: 'S', + }), + ]))); + + // Test that whitespace after an escape is OK. + let pat = r"(?x)\ "; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + flag_set(pat, 0..4, ast::Flag::IgnoreWhitespace, false), + Ast::Literal(ast::Literal { + span: span_range(pat, 4..6), + kind: ast::LiteralKind::Special( + ast::SpecialLiteralKind::Space), + c: ' ', + }), + ]))); + // ... but only when `x` mode is enabled. + let pat = r"\ "; + assert_eq!( + parser(pat).parse().unwrap_err(), + TestError { + span: span_range(pat, 0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + }); + } + + #[test] + fn parse_newlines() { + let pat = ".\n."; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..3), vec![ + Ast::Dot(span_range(pat, 0..1)), + lit_with('\n', span_range(pat, 1..2)), + Ast::Dot(span_range(pat, 2..3)), + ]))); + + let pat = "foobar\nbaz\nquux\n"; + assert_eq!( + parser(pat).parse(), + Ok(concat_with(span_range(pat, 0..pat.len()), vec![ + lit_with('f', nspan(npos(0, 1, 1), npos(1, 1, 2))), + lit_with('o', nspan(npos(1, 1, 2), npos(2, 1, 3))), + lit_with('o', nspan(npos(2, 1, 3), npos(3, 1, 4))), + lit_with('b', nspan(npos(3, 1, 4), npos(4, 1, 5))), + lit_with('a', nspan(npos(4, 1, 5), npos(5, 1, 6))), + lit_with('r', nspan(npos(5, 1, 6), npos(6, 1, 7))), + lit_with('\n', nspan(npos(6, 1, 7), npos(7, 2, 1))), + lit_with('b', nspan(npos(7, 2, 1), npos(8, 2, 2))), + lit_with('a', nspan(npos(8, 2, 2), npos(9, 2, 3))), + lit_with('z', nspan(npos(9, 2, 3), npos(10, 2, 4))), + lit_with('\n', nspan(npos(10, 2, 4), npos(11, 3, 1))), + lit_with('q', nspan(npos(11, 3, 1), npos(12, 3, 2))), + lit_with('u', nspan(npos(12, 3, 2), npos(13, 3, 3))), + lit_with('u', nspan(npos(13, 3, 3), npos(14, 3, 4))), + lit_with('x', nspan(npos(14, 3, 4), npos(15, 3, 5))), + lit_with('\n', nspan(npos(15, 3, 5), npos(16, 4, 1))), + ]))); + } + + #[test] + fn parse_uncounted_repetition() { + assert_eq!( + parser(r"a*").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a+").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::OneOrMore, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + + assert_eq!( + parser(r"a?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a??").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(1..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: false, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a?b").parse(), + Ok(concat(0..3, vec![ + Ast::Repetition(ast::Repetition { + span: span(0..2), + op: ast::RepetitionOp { + span: span(1..2), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }), + lit('b', 2), + ]))); + assert_eq!( + parser(r"a??b").parse(), + Ok(concat(0..4, vec![ + Ast::Repetition(ast::Repetition { + span: span(0..3), + op: ast::RepetitionOp { + span: span(1..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: false, + ast: Box::new(lit('a', 0)), + }), + lit('b', 3), + ]))); + assert_eq!( + parser(r"ab?").parse(), + Ok(concat(0..3, vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + ]))); + assert_eq!( + parser(r"(ab)?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(4..5), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(group(0..4, 1, concat(1..3, vec![ + lit('a', 1), + lit('b', 2), + ]))), + }))); + assert_eq!( + parser(r"|a?").parse(), + Ok(alt(0..3, vec![ + Ast::Empty(span(0..0)), + Ast::Repetition(ast::Repetition { + span: span(1..3), + op: ast::RepetitionOp { + span: span(2..3), + kind: ast::RepetitionKind::ZeroOrOne, + }, + greedy: true, + ast: Box::new(lit('a', 1)), + }), + ]))); + + assert_eq!( + parser(r"*").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"(?i)*").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"(*)").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"(?:?)").parse().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"+").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"?").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"(?)").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"|*").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"|+").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"|?").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + } + + #[test] + fn parse_counted_repetition() { + assert_eq!( + parser(r"a{5}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..4), + op: ast::RepetitionOp { + span: span(1..4), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5)), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a{5,}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(1..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::AtLeast(5)), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a{5,9}").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..6), + op: ast::RepetitionOp { + span: span(1..6), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9)), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a{5}?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..5), + op: ast::RepetitionOp { + span: span(1..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5)), + }, + greedy: false, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"ab{5}").parse(), + Ok(concat(0..5, vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..5), + op: ast::RepetitionOp { + span: span(2..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5)), + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + ]))); + assert_eq!( + parser(r"ab{5}c").parse(), + Ok(concat(0..6, vec![ + lit('a', 0), + Ast::Repetition(ast::Repetition { + span: span(1..5), + op: ast::RepetitionOp { + span: span(2..5), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5)), + }, + greedy: true, + ast: Box::new(lit('b', 1)), + }), + lit('c', 5), + ]))); + + assert_eq!( + parser(r"a{ 5 }").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..6), + op: ast::RepetitionOp { + span: span(1..6), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Exactly(5)), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser(r"a{ 5 , 9 }").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..10), + op: ast::RepetitionOp { + span: span(1..10), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9)), + }, + greedy: true, + ast: Box::new(lit('a', 0)), + }))); + assert_eq!( + parser_ignore_whitespace(r"a{5,9} ?").parse(), + Ok(Ast::Repetition(ast::Repetition { + span: span(0..8), + op: ast::RepetitionOp { + span: span(1..8), + kind: ast::RepetitionKind::Range( + ast::RepetitionRange::Bounded(5, 9)), + }, + greedy: false, + ast: Box::new(lit('a', 0)), + }))); + + assert_eq!( + parser(r"(?i){0}").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"(?m){1,1}").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"a{").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::RepetitionCountUnclosed, + }); + assert_eq!( + parser(r"a{}").parse().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::DecimalEmpty, + }); + assert_eq!( + parser(r"a{a").parse().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::DecimalEmpty, + }); + assert_eq!( + parser(r"a{9999999999}").parse().unwrap_err(), + TestError { + span: span(2..12), + kind: ast::ErrorKind::DecimalInvalid, + }); + assert_eq!( + parser(r"a{9").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::RepetitionCountUnclosed, + }); + assert_eq!( + parser(r"a{9,a").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::DecimalEmpty, + }); + assert_eq!( + parser(r"a{9,9999999999}").parse().unwrap_err(), + TestError { + span: span(4..14), + kind: ast::ErrorKind::DecimalInvalid, + }); + assert_eq!( + parser(r"a{9,").parse().unwrap_err(), + TestError { + span: span(1..4), + kind: ast::ErrorKind::RepetitionCountUnclosed, + }); + assert_eq!( + parser(r"a{9,11").parse().unwrap_err(), + TestError { + span: span(1..6), + kind: ast::ErrorKind::RepetitionCountUnclosed, + }); + assert_eq!( + parser(r"a{2,1}").parse().unwrap_err(), + TestError { + span: span(1..6), + kind: ast::ErrorKind::RepetitionCountInvalid, + }); + assert_eq!( + parser(r"{5}").parse().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::RepetitionMissing, + }); + assert_eq!( + parser(r"|{5}").parse().unwrap_err(), + TestError { + span: span(1..1), + kind: ast::ErrorKind::RepetitionMissing, + }); + } + + #[test] + fn parse_alternate() { + assert_eq!( + parser(r"a|b").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..3), + asts: vec![lit('a', 0), lit('b', 2)], + }))); + assert_eq!( + parser(r"(a|b)").parse(), + Ok(group(0..5, 1, Ast::Alternation(ast::Alternation { + span: span(1..4), + asts: vec![lit('a', 1), lit('b', 3)], + })))); + + assert_eq!( + parser(r"a|b|c").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..5), + asts: vec![lit('a', 0), lit('b', 2), lit('c', 4)], + }))); + assert_eq!( + parser(r"ax|by|cz").parse(), + Ok(Ast::Alternation(ast::Alternation { + span: span(0..8), + asts: vec![ + concat(0..2, vec![lit('a', 0), lit('x', 1)]), + concat(3..5, vec![lit('b', 3), lit('y', 4)]), + concat(6..8, vec![lit('c', 6), lit('z', 7)]), + ], + }))); + assert_eq!( + parser(r"(ax|by|cz)").parse(), + Ok(group(0..10, 1, Ast::Alternation(ast::Alternation { + span: span(1..9), + asts: vec![ + concat(1..3, vec![lit('a', 1), lit('x', 2)]), + concat(4..6, vec![lit('b', 4), lit('y', 5)]), + concat(7..9, vec![lit('c', 7), lit('z', 8)]), + ], + })))); + assert_eq!( + parser(r"(ax|(by|(cz)))").parse(), + Ok(group(0..14, 1, alt(1..13, vec![ + concat(1..3, vec![lit('a', 1), lit('x', 2)]), + group(4..13, 2, alt(5..12, vec![ + concat(5..7, vec![lit('b', 5), lit('y', 6)]), + group(8..12, 3, concat(9..11, vec![ + lit('c', 9), + lit('z', 10), + ])), + ])), + ])))); + + assert_eq!( + parser(r"|").parse(), Ok(alt(0..1, vec![ + Ast::Empty(span(0..0)), Ast::Empty(span(1..1)), + ]))); + assert_eq!( + parser(r"||").parse(), Ok(alt(0..2, vec![ + Ast::Empty(span(0..0)), + Ast::Empty(span(1..1)), + Ast::Empty(span(2..2)), + ]))); + assert_eq!( + parser(r"a|").parse(), Ok(alt(0..2, vec![ + lit('a', 0), Ast::Empty(span(2..2)), + ]))); + assert_eq!( + parser(r"|a").parse(), Ok(alt(0..2, vec![ + Ast::Empty(span(0..0)), lit('a', 1), + ]))); + + assert_eq!( + parser(r"(|)").parse(), Ok(group(0..3, 1, alt(1..2, vec![ + Ast::Empty(span(1..1)), Ast::Empty(span(2..2)), + ])))); + assert_eq!( + parser(r"(a|)").parse(), Ok(group(0..4, 1, alt(1..3, vec![ + lit('a', 1), Ast::Empty(span(3..3)), + ])))); + assert_eq!( + parser(r"(|a)").parse(), Ok(group(0..4, 1, alt(1..3, vec![ + Ast::Empty(span(1..1)), lit('a', 2), + ])))); + + assert_eq!( + parser(r"a|b)").parse().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::GroupUnopened, + }); + assert_eq!( + parser(r"(a|b").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + }); + } + + #[test] + fn parse_unsupported_lookaround() { + assert_eq!( + parser(r"(?=a)").parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::UnsupportedLookAround, + }); + assert_eq!( + parser(r"(?!a)").parse().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::UnsupportedLookAround, + }); + assert_eq!( + parser(r"(?<=a)").parse().unwrap_err(), + TestError { + span: span(0..4), + kind: ast::ErrorKind::UnsupportedLookAround, + }); + assert_eq!( + parser(r"(?<!a)").parse().unwrap_err(), + TestError { + span: span(0..4), + kind: ast::ErrorKind::UnsupportedLookAround, + }); + } + + #[test] + fn parse_group() { + assert_eq!(parser("(?i)").parse(), Ok(Ast::Flags(ast::SetFlags { + span: span(0..4), + flags: ast::Flags { + span: span(2..3), + items: vec![ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }], + }, + }))); + assert_eq!(parser("(?iU)").parse(), Ok(Ast::Flags(ast::SetFlags { + span: span(0..5), + flags: ast::Flags { + span: span(2..4), + items: vec![ + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }, + }))); + assert_eq!(parser("(?i-U)").parse(), Ok(Ast::Flags(ast::SetFlags { + span: span(0..6), + flags: ast::Flags { + span: span(2..5), + items: vec![ + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(4..5), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }, + }))); + + assert_eq!(parser("()").parse(), Ok(Ast::Group(ast::Group { + span: span(0..2), + kind: ast::GroupKind::CaptureIndex(1), + ast: Box::new(Ast::Empty(span(1..1))), + }))); + assert_eq!(parser("(a)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..3), + kind: ast::GroupKind::CaptureIndex(1), + ast: Box::new(lit('a', 1)), + }))); + assert_eq!(parser("(())").parse(), Ok(Ast::Group(ast::Group { + span: span(0..4), + kind: ast::GroupKind::CaptureIndex(1), + ast: Box::new(Ast::Group(ast::Group { + span: span(1..3), + kind: ast::GroupKind::CaptureIndex(2), + ast: Box::new(Ast::Empty(span(2..2))), + })), + }))); + + assert_eq!(parser("(?:a)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..5), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span(2..2), + items: vec![], + }), + ast: Box::new(lit('a', 3)), + }))); + + assert_eq!(parser("(?i:a)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..6), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span(2..3), + items: vec![ + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive), + }, + ], + }), + ast: Box::new(lit('a', 4)), + }))); + assert_eq!(parser("(?i-U:a)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..8), + kind: ast::GroupKind::NonCapturing(ast::Flags { + span: span(2..5), + items: vec![ + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(4..5), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + }), + ast: Box::new(lit('a', 6)), + }))); + + assert_eq!( + parser("(").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + }); + assert_eq!( + parser("(?").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + }); + assert_eq!( + parser("(?P").parse().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::FlagUnrecognized, + }); + assert_eq!( + parser("(?P<").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::GroupNameUnexpectedEof, + }); + assert_eq!( + parser("(a").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + }); + assert_eq!( + parser("(()").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnclosed, + }); + assert_eq!( + parser(")").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::GroupUnopened, + }); + assert_eq!( + parser("a)").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::GroupUnopened, + }); + } + + #[test] + fn parse_capture_name() { + assert_eq!(parser("(?P<a>z)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..8), + kind: ast::GroupKind::CaptureName(ast::CaptureName { + span: span(4..5), + name: s("a"), + index: 1, + }), + ast: Box::new(lit('z', 6)), + }))); + assert_eq!(parser("(?P<abc>z)").parse(), Ok(Ast::Group(ast::Group { + span: span(0..10), + kind: ast::GroupKind::CaptureName(ast::CaptureName { + span: span(4..7), + name: s("abc"), + index: 1, + }), + ast: Box::new(lit('z', 8)), + }))); + + assert_eq!( + parser("(?P<").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::GroupNameUnexpectedEof, + }); + assert_eq!( + parser("(?P<>z)").parse().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::GroupNameEmpty, + }); + assert_eq!( + parser("(?P<a").parse().unwrap_err(), + TestError { + span: span(5..5), + kind: ast::ErrorKind::GroupNameUnexpectedEof, + }); + assert_eq!( + parser("(?P<ab").parse().unwrap_err(), + TestError { + span: span(6..6), + kind: ast::ErrorKind::GroupNameUnexpectedEof, + }); + assert_eq!( + parser("(?P<0a").parse().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::GroupNameInvalid, + }); + assert_eq!( + parser("(?P<~").parse().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::GroupNameInvalid, + }); + assert_eq!( + parser("(?P<abc~").parse().unwrap_err(), + TestError { + span: span(7..8), + kind: ast::ErrorKind::GroupNameInvalid, + }); + assert_eq!( + parser("(?P<a>y)(?P<a>z)").parse().unwrap_err(), + TestError { + span: span(12..13), + kind: ast::ErrorKind::GroupNameDuplicate { + original: span(4..5), + }, + }); + } + + #[test] + fn parse_flags() { + assert_eq!(parser("i:").parse_flags(), Ok(ast::Flags { + span: span(0..1), + items: vec![ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }], + })); + assert_eq!(parser("i)").parse_flags(), Ok(ast::Flags { + span: span(0..1), + items: vec![ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }], + })); + + assert_eq!(parser("isU:").parse_flags(), Ok(ast::Flags { + span: span(0..3), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine), + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + })); + + assert_eq!(parser("-isU:").parse_flags(), Ok(ast::Flags { + span: span(0..4), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + })); + assert_eq!(parser("i-sU:").parse_flags(), Ok(ast::Flags { + span: span(0..4), + items: vec![ + ast::FlagsItem { + span: span(0..1), + kind: ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive), + }, + ast::FlagsItem { + span: span(1..2), + kind: ast::FlagsItemKind::Negation, + }, + ast::FlagsItem { + span: span(2..3), + kind: ast::FlagsItemKind::Flag( + ast::Flag::DotMatchesNewLine), + }, + ast::FlagsItem { + span: span(3..4), + kind: ast::FlagsItemKind::Flag(ast::Flag::SwapGreed), + }, + ], + })); + + assert_eq!( + parser("isU").parse_flags().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::FlagUnexpectedEof, + }); + assert_eq!( + parser("isUa:").parse_flags().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::FlagUnrecognized, + }); + assert_eq!( + parser("isUi:").parse_flags().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::FlagDuplicate { + original: span(0..1), + }, + }); + assert_eq!( + parser("i-sU-i:").parse_flags().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::FlagRepeatedNegation { + original: span(1..2), + }, + }); + assert_eq!( + parser("-)").parse_flags().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::FlagDanglingNegation, + }); + assert_eq!( + parser("i-)").parse_flags().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::FlagDanglingNegation, + }); + assert_eq!( + parser("iU-)").parse_flags().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::FlagDanglingNegation, + }); + } + + #[test] + fn parse_flag() { + assert_eq!(parser("i").parse_flag(), Ok(ast::Flag::CaseInsensitive)); + assert_eq!(parser("m").parse_flag(), Ok(ast::Flag::MultiLine)); + assert_eq!(parser("s").parse_flag(), Ok(ast::Flag::DotMatchesNewLine)); + assert_eq!(parser("U").parse_flag(), Ok(ast::Flag::SwapGreed)); + assert_eq!(parser("u").parse_flag(), Ok(ast::Flag::Unicode)); + assert_eq!(parser("x").parse_flag(), Ok(ast::Flag::IgnoreWhitespace)); + + assert_eq!( + parser("a").parse_flag().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::FlagUnrecognized, + }); + assert_eq!( + parser("☃").parse_flag().unwrap_err(), + TestError { + span: span_range("☃", 0..3), + kind: ast::ErrorKind::FlagUnrecognized, + }); + } + + #[test] + fn parse_primitive_non_escape() { + assert_eq!( + parser(r".").parse_primitive(), + Ok(Primitive::Dot(span(0..1)))); + assert_eq!( + parser(r"^").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..1), + kind: ast::AssertionKind::StartLine, + }))); + assert_eq!( + parser(r"$").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..1), + kind: ast::AssertionKind::EndLine, + }))); + + assert_eq!( + parser(r"a").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..1), + kind: ast::LiteralKind::Verbatim, + c: 'a', + }))); + assert_eq!( + parser(r"|").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..1), + kind: ast::LiteralKind::Verbatim, + c: '|', + }))); + assert_eq!( + parser(r"☃").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span_range("☃", 0..3), + kind: ast::LiteralKind::Verbatim, + c: '☃', + }))); + } + + #[test] + fn parse_escape() { + assert_eq!( + parser(r"\|").parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..2), + kind: ast::LiteralKind::Punctuation, + c: '|', + }))); + let specials = &[ + (r"\a", '\x07', ast::SpecialLiteralKind::Bell), + (r"\f", '\x0C', ast::SpecialLiteralKind::FormFeed), + (r"\t", '\t', ast::SpecialLiteralKind::Tab), + (r"\n", '\n', ast::SpecialLiteralKind::LineFeed), + (r"\r", '\r', ast::SpecialLiteralKind::CarriageReturn), + (r"\v", '\x0B', ast::SpecialLiteralKind::VerticalTab), + ]; + for &(pat, c, ref kind) in specials { + assert_eq!( + parser(pat).parse_primitive(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..2), + kind: ast::LiteralKind::Special(kind.clone()), + c: c, + }))); + } + assert_eq!( + parser(r"\A").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::StartText, + }))); + assert_eq!( + parser(r"\z").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::EndText, + }))); + assert_eq!( + parser(r"\b").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::WordBoundary, + }))); + assert_eq!( + parser(r"\B").parse_primitive(), + Ok(Primitive::Assertion(ast::Assertion { + span: span(0..2), + kind: ast::AssertionKind::NotWordBoundary, + }))); + + assert_eq!( + parser(r"\").parse_escape().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\y").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + }); + } + + #[test] + fn parse_unsupported_backreference() { + assert_eq!( + parser(r"\0").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::UnsupportedBackreference, + }); + assert_eq!( + parser(r"\9").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::UnsupportedBackreference, + }); + } + + #[test] + fn parse_octal() { + for i in 0..511 { + let pat = format!(r"\{:o}", i); + assert_eq!( + parser_octal(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::Octal, + c: ::std::char::from_u32(i).unwrap(), + }))); + } + assert_eq!( + parser_octal(r"\778").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..3), + kind: ast::LiteralKind::Octal, + c: '?', + }))); + assert_eq!( + parser_octal(r"\7777").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..4), + kind: ast::LiteralKind::Octal, + c: '\u{01FF}', + }))); + assert_eq!( + parser_octal(r"\778").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..4), + asts: vec![ + Ast::Literal(ast::Literal { + span: span(0..3), + kind: ast::LiteralKind::Octal, + c: '?', + }), + Ast::Literal(ast::Literal { + span: span(3..4), + kind: ast::LiteralKind::Verbatim, + c: '8', + }), + ], + }))); + assert_eq!( + parser_octal(r"\7777").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..5), + asts: vec![ + Ast::Literal(ast::Literal { + span: span(0..4), + kind: ast::LiteralKind::Octal, + c: '\u{01FF}', + }), + Ast::Literal(ast::Literal { + span: span(4..5), + kind: ast::LiteralKind::Verbatim, + c: '7', + }), + ], + }))); + + assert_eq!( + parser_octal(r"\8").parse_escape().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::EscapeUnrecognized, + }); + } + + #[test] + fn parse_hex_two() { + for i in 0..256 { + let pat = format!(r"\x{:02x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed(ast::HexLiteralKind::X), + c: ::std::char::from_u32(i).unwrap(), + }))); + } + + assert_eq!( + parser(r"\xF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\xG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\xFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + } + + #[test] + fn parse_hex_four() { + for i in 0..65536 { + let c = match ::std::char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let pat = format!(r"\u{:04x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed( + ast::HexLiteralKind::UnicodeShort), + c: c, + }))); + } + + assert_eq!( + parser(r"\uF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\uG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\uFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\uFFG").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\uFFFG").parse_escape().unwrap_err(), + TestError { + span: span(5..6), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\uD800").parse_escape().unwrap_err(), + TestError { + span: span(2..6), + kind: ast::ErrorKind::EscapeHexInvalid, + }); + } + + #[test] + fn parse_hex_eight() { + for i in 0..65536 { + let c = match ::std::char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let pat = format!(r"\U{:08x}", i); + assert_eq!( + parser(&pat).parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..pat.len()), + kind: ast::LiteralKind::HexFixed( + ast::HexLiteralKind::UnicodeLong), + c: c, + }))); + } + + assert_eq!( + parser(r"\UF").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\UG").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFG").parse_escape().unwrap_err(), + TestError { + span: span(3..4), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFG").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFFG").parse_escape().unwrap_err(), + TestError { + span: span(5..6), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(6..7), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(7..8), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(8..9), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\UFFFFFFFG").parse_escape().unwrap_err(), + TestError { + span: span(9..10), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + } + + #[test] + fn parse_hex_brace() { + assert_eq!( + parser(r"\u{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace( + ast::HexLiteralKind::UnicodeShort), + c: '⛄', + }))); + assert_eq!( + parser(r"\U{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace( + ast::HexLiteralKind::UnicodeLong), + c: '⛄', + }))); + assert_eq!( + parser(r"\x{26c4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '⛄', + }))); + assert_eq!( + parser(r"\x{26C4}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..8), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '⛄', + }))); + assert_eq!( + parser(r"\x{10fFfF}").parse_escape(), + Ok(Primitive::Literal(ast::Literal { + span: span(0..10), + kind: ast::LiteralKind::HexBrace(ast::HexLiteralKind::X), + c: '\u{10FFFF}', + }))); + + assert_eq!( + parser(r"\x").parse_escape().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\x{").parse_escape().unwrap_err(), + TestError { + span: span(2..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\x{FF").parse_escape().unwrap_err(), + TestError { + span: span(2..5), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\x{}").parse_escape().unwrap_err(), + TestError { + span: span(2..4), + kind: ast::ErrorKind::EscapeHexEmpty, + }); + assert_eq!( + parser(r"\x{FGF}").parse_escape().unwrap_err(), + TestError { + span: span(4..5), + kind: ast::ErrorKind::EscapeHexInvalidDigit, + }); + assert_eq!( + parser(r"\x{FFFFFF}").parse_escape().unwrap_err(), + TestError { + span: span(3..9), + kind: ast::ErrorKind::EscapeHexInvalid, + }); + assert_eq!( + parser(r"\x{D800}").parse_escape().unwrap_err(), + TestError { + span: span(3..7), + kind: ast::ErrorKind::EscapeHexInvalid, + }); + assert_eq!( + parser(r"\x{FFFFFFFFF}").parse_escape().unwrap_err(), + TestError { + span: span(3..12), + kind: ast::ErrorKind::EscapeHexInvalid, + }); + } + + #[test] + fn parse_decimal() { + assert_eq!(parser("123").parse_decimal(), Ok(123)); + assert_eq!(parser("0").parse_decimal(), Ok(0)); + assert_eq!(parser("01").parse_decimal(), Ok(1)); + + assert_eq!( + parser("-1").parse_decimal().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::DecimalEmpty, + }); + assert_eq!( + parser("").parse_decimal().unwrap_err(), + TestError { + span: span(0..0), + kind: ast::ErrorKind::DecimalEmpty, + }); + assert_eq!( + parser("9999999999").parse_decimal().unwrap_err(), + TestError { + span: span(0..10), + kind: ast::ErrorKind::DecimalInvalid, + }); + } + + #[test] + fn parse_set_class() { + fn union(span: Span, items: Vec<ast::ClassSetItem>) -> ast::ClassSet { + ast::ClassSet::union(ast::ClassSetUnion { + span: span, + items: items, + }) + } + + fn intersection( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span: span, + kind: ast::ClassSetBinaryOpKind::Intersection, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn difference( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span: span, + kind: ast::ClassSetBinaryOpKind::Difference, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn symdifference( + span: Span, + lhs: ast::ClassSet, + rhs: ast::ClassSet, + ) -> ast::ClassSet { + ast::ClassSet::BinaryOp(ast::ClassSetBinaryOp { + span: span, + kind: ast::ClassSetBinaryOpKind::SymmetricDifference, + lhs: Box::new(lhs), + rhs: Box::new(rhs), + }) + } + + fn itemset(item: ast::ClassSetItem) -> ast::ClassSet { + ast::ClassSet::Item(item) + } + + fn item_ascii(cls: ast::ClassAscii) -> ast::ClassSetItem { + ast::ClassSetItem::Ascii(cls) + } + + fn item_unicode(cls: ast::ClassUnicode) -> ast::ClassSetItem { + ast::ClassSetItem::Unicode(cls) + } + + fn item_perl(cls: ast::ClassPerl) -> ast::ClassSetItem { + ast::ClassSetItem::Perl(cls) + } + + fn item_bracket(cls: ast::ClassBracketed) -> ast::ClassSetItem { + ast::ClassSetItem::Bracketed(Box::new(cls)) + } + + fn lit(span: Span, c: char) -> ast::ClassSetItem { + ast::ClassSetItem::Literal(ast::Literal { + span: span, + kind: ast::LiteralKind::Verbatim, + c: c, + }) + } + + fn empty(span: Span) -> ast::ClassSetItem { + ast::ClassSetItem::Empty(span) + } + + fn range(span: Span, start: char, end: char) -> ast::ClassSetItem { + let pos1 = Position { + offset: span.start.offset + start.len_utf8(), + column: span.start.column + 1, + ..span.start + }; + let pos2 = Position { + offset: span.end.offset - end.len_utf8(), + column: span.end.column - 1, + ..span.end + }; + ast::ClassSetItem::Range(ast::ClassSetRange { + span: span, + start: ast::Literal { + span: Span { end: pos1, ..span }, + kind: ast::LiteralKind::Verbatim, + c: start, + }, + end: ast::Literal { + span: Span { start: pos2, ..span }, + kind: ast::LiteralKind::Verbatim, + c: end, + }, + }) + } + + fn alnum(span: Span, negated: bool) -> ast::ClassAscii { + ast::ClassAscii { + span: span, + kind: ast::ClassAsciiKind::Alnum, + negated: negated, + } + } + + fn lower(span: Span, negated: bool) -> ast::ClassAscii { + ast::ClassAscii { + span: span, + kind: ast::ClassAsciiKind::Lower, + negated: negated, + } + } + + assert_eq!( + parser("[[:alnum:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..11), + negated: false, + kind: itemset(item_ascii(alnum(span(1..10), false))), + })))); + assert_eq!( + parser("[[[:alnum:]]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..13), + negated: false, + kind: itemset(item_bracket(ast::ClassBracketed { + span: span(1..12), + negated: false, + kind: itemset(item_ascii(alnum(span(2..11), false))), + })), + })))); + assert_eq!( + parser("[[:alnum:]&&[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: intersection( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + })))); + assert_eq!( + parser("[[:alnum:]--[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: difference( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + })))); + assert_eq!( + parser("[[:alnum:]~~[:lower:]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..22), + negated: false, + kind: symdifference( + span(1..21), + itemset(item_ascii(alnum(span(1..10), false))), + itemset(item_ascii(lower(span(12..21), false))), + ), + })))); + + assert_eq!( + parser("[a]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: itemset(lit(span(1..2), 'a')), + })))); + assert_eq!( + parser(r"[a\]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: union(span(1..4), vec![ + lit(span(1..2), 'a'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Punctuation, + c: ']', + }), + ]), + })))); + assert_eq!( + parser(r"[a\-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: union(span(1..5), vec![ + lit(span(1..2), 'a'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Punctuation, + c: '-', + }), + lit(span(4..5), 'z'), + ]), + })))); + assert_eq!( + parser("[ab]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union(span(1..3), vec![ + lit(span(1..2), 'a'), + lit(span(2..3), 'b'), + ]), + })))); + assert_eq!( + parser("[a-]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union(span(1..3), vec![ + lit(span(1..2), 'a'), + lit(span(2..3), '-'), + ]), + })))); + assert_eq!( + parser("[-a]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: union(span(1..3), vec![ + lit(span(1..2), '-'), + lit(span(2..3), 'a'), + ]), + })))); + assert_eq!( + parser(r"[\pL]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: itemset(item_unicode(ast::ClassUnicode { + span: span(1..4), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('L'), + })), + })))); + assert_eq!( + parser(r"[\w]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: itemset(item_perl(ast::ClassPerl { + span: span(1..3), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + })))); + assert_eq!( + parser(r"[a\wz]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: union(span(1..5), vec![ + lit(span(1..2), 'a'), + item_perl(ast::ClassPerl { + span: span(2..4), + kind: ast::ClassPerlKind::Word, + negated: false, + }), + lit(span(4..5), 'z'), + ]), + })))); + + assert_eq!( + parser("[a-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: itemset(range(span(1..4), 'a', 'z')), + })))); + assert_eq!( + parser("[a-cx-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..8), + negated: false, + kind: union(span(1..7), vec![ + range(span(1..4), 'a', 'c'), + range(span(4..7), 'x', 'z'), + ]), + })))); + assert_eq!( + parser(r"[\w&&a-cx-z]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..12), + negated: false, + kind: intersection( + span(1..11), + itemset(item_perl(ast::ClassPerl { + span: span(1..3), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + union(span(5..11), vec![ + range(span(5..8), 'a', 'c'), + range(span(8..11), 'x', 'z'), + ]), + ), + })))); + assert_eq!( + parser(r"[a-cx-z&&\w]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..12), + negated: false, + kind: intersection( + span(1..11), + union(span(1..7), vec![ + range(span(1..4), 'a', 'c'), + range(span(4..7), 'x', 'z'), + ]), + itemset(item_perl(ast::ClassPerl { + span: span(9..11), + kind: ast::ClassPerlKind::Word, + negated: false, + })), + ), + })))); + assert_eq!( + parser(r"[a--b--c]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..9), + negated: false, + kind: difference( + span(1..8), + difference( + span(1..5), + itemset(lit(span(1..2), 'a')), + itemset(lit(span(4..5), 'b')), + ), + itemset(lit(span(7..8), 'c')), + ), + })))); + assert_eq!( + parser(r"[a~~b~~c]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..9), + negated: false, + kind: symdifference( + span(1..8), + symdifference( + span(1..5), + itemset(lit(span(1..2), 'a')), + itemset(lit(span(4..5), 'b')), + ), + itemset(lit(span(7..8), 'c')), + ), + })))); + assert_eq!( + parser(r"[\^&&^]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..7), + negated: false, + kind: intersection( + span(1..6), + itemset(ast::ClassSetItem::Literal(ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Punctuation, + c: '^', + })), + itemset(lit(span(5..6), '^')), + ), + })))); + assert_eq!( + parser(r"[\&&&&]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..7), + negated: false, + kind: intersection( + span(1..6), + itemset(ast::ClassSetItem::Literal(ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Punctuation, + c: '&', + })), + itemset(lit(span(5..6), '&')), + ), + })))); + assert_eq!( + parser(r"[&&&&]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..6), + negated: false, + kind: intersection( + span(1..5), + intersection( + span(1..3), + itemset(empty(span(1..1))), + itemset(empty(span(3..3))), + ), + itemset(empty(span(5..5))), + ), + })))); + + let pat = "[☃-⛄]"; + assert_eq!( + parser(pat).parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span_range(pat, 0..9), + negated: false, + kind: itemset(ast::ClassSetItem::Range(ast::ClassSetRange { + span: span_range(pat, 1..8), + start: ast::Literal { + span: span_range(pat, 1..4), + kind: ast::LiteralKind::Verbatim, + c: '☃', + }, + end: ast::Literal { + span: span_range(pat, 5..8), + kind: ast::LiteralKind::Verbatim, + c: '⛄', + }, + })), + })))); + + assert_eq!( + parser(r"[]]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: itemset(lit(span(1..2), ']')), + })))); + assert_eq!( + parser(r"[]\[]").parse(), + Ok(Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..5), + negated: false, + kind: union(span(1..4), vec![ + lit(span(1..2), ']'), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..4), + kind: ast::LiteralKind::Punctuation, + c: '[', + }), + ]), + })))); + assert_eq!( + parser(r"[\[]]").parse(), + Ok(concat(0..5, vec![ + Ast::Class(ast::Class::Bracketed(ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: itemset(ast::ClassSetItem::Literal(ast::Literal { + span: span(1..3), + kind: ast::LiteralKind::Punctuation, + c: '[', + })), + })), + Ast::Literal(ast::Literal { + span: span(4..5), + kind: ast::LiteralKind::Verbatim, + c: ']', + }), + ]))); + + assert_eq!( + parser("[").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[[").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[[-]").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[[[:alnum:]").parse().unwrap_err(), + TestError { + span: span(1..2), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser(r"[\b]").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::ClassEscapeInvalid, + }); + assert_eq!( + parser(r"[\w-a]").parse().unwrap_err(), + TestError { + span: span(1..3), + kind: ast::ErrorKind::ClassRangeLiteral, + }); + assert_eq!( + parser(r"[a-\w]").parse().unwrap_err(), + TestError { + span: span(3..5), + kind: ast::ErrorKind::ClassRangeLiteral, + }); + assert_eq!( + parser(r"[z-a]").parse().unwrap_err(), + TestError { + span: span(1..4), + kind: ast::ErrorKind::ClassRangeInvalid, + }); + + assert_eq!( + parser_ignore_whitespace("[a ").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser_ignore_whitespace("[a- ").parse().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + }); + } + + #[test] + fn parse_set_class_open() { + assert_eq!( + parser("[a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..1), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[^a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ ^ a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..4), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(4..4), + items: vec![], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[-a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ - a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[^-a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[--a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: ']', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser_ignore_whitespace("[ ] a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..4), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: ']', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[^]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..3), + negated: true, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(2..2), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(2..3), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: ']', + }), + ], + }; + Ok((set, union)) + }); + assert_eq!( + parser("[-]a]").parse_set_class_open(), { + let set = ast::ClassBracketed { + span: span(0..2), + negated: false, + kind: ast::ClassSet::union(ast::ClassSetUnion { + span: span(1..1), + items: vec![], + }), + }; + let union = ast::ClassSetUnion { + span: span(1..2), + items: vec![ + ast::ClassSetItem::Literal(ast::Literal { + span: span(1..2), + kind: ast::LiteralKind::Verbatim, + c: '-', + }), + ], + }; + Ok((set, union)) + }); + + assert_eq!( + parser("[").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..1), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser_ignore_whitespace("[ ") + .parse_set_class_open() + .unwrap_err(), + TestError { + span: span(0..5), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[^").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[]").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[-").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..2), + kind: ast::ErrorKind::ClassUnclosed, + }); + assert_eq!( + parser("[--").parse_set_class_open().unwrap_err(), + TestError { + span: span(0..3), + kind: ast::ErrorKind::ClassUnclosed, + }); + } + + #[test] + fn maybe_parse_ascii_class() { + assert_eq!( + parser(r"[:alnum:]").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..9), + kind: ast::ClassAsciiKind::Alnum, + negated: false, + })); + assert_eq!( + parser(r"[:alnum:]A").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..9), + kind: ast::ClassAsciiKind::Alnum, + negated: false, + })); + assert_eq!( + parser(r"[:^alnum:]").maybe_parse_ascii_class(), + Some(ast::ClassAscii { + span: span(0..10), + kind: ast::ClassAsciiKind::Alnum, + negated: true, + })); + + let p = parser(r"[:"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:^"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[^:alnum:]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnnum:]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnum]"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + + let p = parser(r"[:alnum:"); + assert_eq!(p.maybe_parse_ascii_class(), None); + assert_eq!(p.offset(), 0); + } + + #[test] + fn parse_unicode_class() { + assert_eq!( + parser(r"\pN").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('N'), + }))); + assert_eq!( + parser(r"\PN").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: true, + kind: ast::ClassUnicodeKind::OneLetter('N'), + }))); + assert_eq!( + parser(r"\p{N}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("N")), + }))); + assert_eq!( + parser(r"\P{N}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: true, + kind: ast::ClassUnicodeKind::Named(s("N")), + }))); + assert_eq!( + parser(r"\p{Greek}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..9), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("Greek")), + }))); + + assert_eq!( + parser(r"\p{scx:Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..16), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: s("scx"), + value: s("Katakana"), + }, + }))); + assert_eq!( + parser(r"\p{scx=Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..16), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: s("scx"), + value: s("Katakana"), + }, + }))); + assert_eq!( + parser(r"\p{scx!=Katakana}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..17), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: s("scx"), + value: s("Katakana"), + }, + }))); + + assert_eq!( + parser(r"\p{:}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Colon, + name: s(""), + value: s(""), + }, + }))); + assert_eq!( + parser(r"\p{=}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..5), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::Equal, + name: s(""), + value: s(""), + }, + }))); + assert_eq!( + parser(r"\p{!=}").parse_escape(), + Ok(Primitive::Unicode(ast::ClassUnicode { + span: span(0..6), + negated: false, + kind: ast::ClassUnicodeKind::NamedValue { + op: ast::ClassUnicodeOpKind::NotEqual, + name: s(""), + value: s(""), + }, + }))); + + assert_eq!( + parser(r"\p").parse_escape().unwrap_err(), + TestError { + span: span(2..2), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\p{").parse_escape().unwrap_err(), + TestError { + span: span(3..3), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\p{N").parse_escape().unwrap_err(), + TestError { + span: span(4..4), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + assert_eq!( + parser(r"\p{Greek").parse_escape().unwrap_err(), + TestError { + span: span(8..8), + kind: ast::ErrorKind::EscapeUnexpectedEof, + }); + + assert_eq!( + parser(r"\pNz").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..4), + asts: vec![ + Ast::Class(ast::Class::Unicode(ast::ClassUnicode { + span: span(0..3), + negated: false, + kind: ast::ClassUnicodeKind::OneLetter('N'), + })), + Ast::Literal(ast::Literal { + span: span(3..4), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + }))); + assert_eq!( + parser(r"\p{Greek}z").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..10), + asts: vec![ + Ast::Class(ast::Class::Unicode(ast::ClassUnicode { + span: span(0..9), + negated: false, + kind: ast::ClassUnicodeKind::Named(s("Greek")), + })), + Ast::Literal(ast::Literal { + span: span(9..10), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + }))); + } + + #[test] + fn parse_perl_class() { + assert_eq!( + parser(r"\d").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + }))); + assert_eq!( + parser(r"\D").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: true, + }))); + assert_eq!( + parser(r"\s").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Space, + negated: false, + }))); + assert_eq!( + parser(r"\S").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Space, + negated: true, + }))); + assert_eq!( + parser(r"\w").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Word, + negated: false, + }))); + assert_eq!( + parser(r"\W").parse_escape(), + Ok(Primitive::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Word, + negated: true, + }))); + + assert_eq!( + parser(r"\d").parse(), + Ok(Ast::Class(ast::Class::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + })))); + assert_eq!( + parser(r"\dz").parse(), + Ok(Ast::Concat(ast::Concat { + span: span(0..3), + asts: vec![ + Ast::Class(ast::Class::Perl(ast::ClassPerl { + span: span(0..2), + kind: ast::ClassPerlKind::Digit, + negated: false, + })), + Ast::Literal(ast::Literal { + span: span(2..3), + kind: ast::LiteralKind::Verbatim, + c: 'z', + }), + ], + }))); + } + + // This tests a bug fix where the nest limit checker wasn't decrementing + // its depth during post-traversal, which causes long regexes to trip + // the default limit too aggressively. + #[test] + fn regression_454_nest_too_big() { + let pattern = r#" + 2(?: + [45]\d{3}| + 7(?: + 1[0-267]| + 2[0-289]| + 3[0-29]| + 4[01]| + 5[1-3]| + 6[013]| + 7[0178]| + 91 + )| + 8(?: + 0[125]| + [139][1-6]| + 2[0157-9]| + 41| + 6[1-35]| + 7[1-5]| + 8[1-8]| + 90 + )| + 9(?: + 0[0-2]| + 1[0-4]| + 2[568]| + 3[3-6]| + 5[5-7]| + 6[0167]| + 7[15]| + 8[0146-9] + ) + )\d{4} + "#; + assert!(parser_nest_limit(pattern, 50).parse().is_ok()); + } + + // This tests that we treat a trailing `-` in a character class as a + // literal `-` even when whitespace mode is enabled and there is whitespace + // after the trailing `-`. + #[test] + fn regression_455_trailing_dash_ignore_whitespace() { + assert!(parser("(?x)[ / - ]").parse().is_ok()); + assert!(parser("(?x)[ a - ]").parse().is_ok()); + assert!(parser("(?x)[ + a + - ] + ").parse().is_ok()); + assert!(parser("(?x)[ + a # wat + - ] + ").parse().is_ok()); + + assert!(parser("(?x)[ / -").parse().is_err()); + assert!(parser("(?x)[ / - ").parse().is_err()); + assert!(parser("(?x)[ + / - + ").parse().is_err()); + assert!(parser("(?x)[ + / - # wat + ").parse().is_err()); + } +} diff --git a/regex-syntax/src/ast/print.rs b/regex-syntax/src/ast/print.rs new file mode 100644 index 000000000..4441b4d58 --- /dev/null +++ b/regex-syntax/src/ast/print.rs @@ -0,0 +1,586 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +This module provides a regular expression printer for `Ast`. +*/ + +use std::fmt; + +use ast::{self, Ast}; +use ast::visitor::{self, Visitor}; + +/// A builder for constructing a printer. +/// +/// Note that since a printer doesn't have any configuration knobs, this type +/// remains unexported. +#[derive(Clone, Debug)] +struct PrinterBuilder { + _priv: (), +} + +impl Default for PrinterBuilder { + fn default() -> PrinterBuilder { + PrinterBuilder::new() + } +} + +impl PrinterBuilder { + fn new() -> PrinterBuilder { + PrinterBuilder { + _priv: (), + } + } + + fn build(&self) -> Printer { + Printer { + _priv: (), + } + } +} + +/// A printer for a regular expression abstract syntax tree. +/// +/// A printer converts an abstract syntax tree (AST) to a regular expression +/// pattern string. This particular printer uses constant stack space and heap +/// space proportional to the size of the AST. +/// +/// This printer will not necessarily preserve the original formatting of the +/// regular expression pattern string. For example, all whitespace and comments +/// are ignored. +#[derive(Debug)] +pub struct Printer { + _priv: (), +} + +impl Printer { + /// Create a new printer. + pub fn new() -> Printer { + PrinterBuilder::new().build() + } + + /// Print the given `Ast` to the given writer. The writer must implement + /// `fmt::Write`. Typical implementations of `fmt::Write` that can be used + /// here are a `fmt::Formatter` (which is available in `fmt::Display` + /// implementations) or a `&mut String`. + pub fn print<W: fmt::Write>(&mut self, ast: &Ast, wtr: W) -> fmt::Result { + visitor::visit(ast, Writer { printer: self, wtr: wtr }) + } +} + +#[derive(Debug)] +struct Writer<'p, W> { + printer: &'p mut Printer, + wtr: W, +} + +impl<'p, W: fmt::Write> Visitor for Writer<'p, W> { + type Output = (); + type Err = fmt::Error; + + fn finish(self) -> fmt::Result { + Ok(()) + } + + fn visit_pre(&mut self, ast: &Ast) -> fmt::Result { + match *ast { + Ast::Group(ref x) => self.fmt_group_pre(x), + Ast::Class(ast::Class::Bracketed(ref x)) => { + self.fmt_class_bracketed_pre(x) + } + _ => Ok(()) + } + } + + fn visit_post(&mut self, ast: &Ast) -> fmt::Result { + use ast::Class; + + match *ast { + Ast::Empty(_) => Ok(()), + Ast::Flags(ref x) => self.fmt_set_flags(x), + Ast::Literal(ref x) => self.fmt_literal(x), + Ast::Dot(_) => self.wtr.write_str("."), + Ast::Assertion(ref x) => self.fmt_assertion(x), + Ast::Class(Class::Perl(ref x)) => self.fmt_class_perl(x), + Ast::Class(Class::Unicode(ref x)) => self.fmt_class_unicode(x), + Ast::Class(Class::Bracketed(ref x)) => { + self.fmt_class_bracketed_post(x) + } + Ast::Repetition(ref x) => self.fmt_repetition(x), + Ast::Group(ref x) => self.fmt_group_post(x), + Ast::Alternation(_) => Ok(()), + Ast::Concat(_) => Ok(()), + } + } + + fn visit_alternation_in(&mut self) -> fmt::Result { + self.wtr.write_str("|") + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + match *ast { + ast::ClassSetItem::Bracketed(ref x) => { + self.fmt_class_bracketed_pre(x) + } + _ => Ok(()), + } + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + use ast::ClassSetItem::*; + + match *ast { + Empty(_) => Ok(()), + Literal(ref x) => self.fmt_literal(x), + Range(ref x) => { + self.fmt_literal(&x.start)?; + self.wtr.write_str("-")?; + self.fmt_literal(&x.end)?; + Ok(()) + } + Ascii(ref x) => self.fmt_class_ascii(x), + Unicode(ref x) => self.fmt_class_unicode(x), + Perl(ref x) => self.fmt_class_perl(x), + Bracketed(ref x) => self.fmt_class_bracketed_post(x), + Union(_) => Ok(()), + } + } + + fn visit_class_set_binary_op_in( + &mut self, + ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + self.fmt_class_set_binary_op_kind(&ast.kind) + } +} + +impl<'p, W: fmt::Write> Writer<'p, W> { + fn fmt_group_pre(&mut self, ast: &ast::Group) -> fmt::Result { + use ast::GroupKind::*; + match ast.kind { + CaptureIndex(_) => self.wtr.write_str("("), + CaptureName(ref x) => { + self.wtr.write_str("(?P<")?; + self.wtr.write_str(&x.name)?; + self.wtr.write_str(">")?; + Ok(()) + } + NonCapturing(ref flags) => { + self.wtr.write_str("(?")?; + self.fmt_flags(flags)?; + self.wtr.write_str(":")?; + Ok(()) + } + } + } + + fn fmt_group_post(&mut self, _ast: &ast::Group) -> fmt::Result { + self.wtr.write_str(")") + } + + fn fmt_repetition(&mut self, ast: &ast::Repetition) -> fmt::Result { + use ast::RepetitionKind::*; + match ast.op.kind { + ZeroOrOne if ast.greedy => self.wtr.write_str("?"), + ZeroOrOne => self.wtr.write_str("??"), + ZeroOrMore if ast.greedy => self.wtr.write_str("*"), + ZeroOrMore => self.wtr.write_str("*?"), + OneOrMore if ast.greedy => self.wtr.write_str("+"), + OneOrMore => self.wtr.write_str("+?"), + Range(ref x) => { + self.fmt_repetition_range(x)?; + if !ast.greedy { + self.wtr.write_str("?")?; + } + Ok(()) + } + } + } + + fn fmt_repetition_range( + &mut self, + ast: &ast::RepetitionRange, + ) -> fmt::Result { + use ast::RepetitionRange::*; + match *ast { + Exactly(x) => write!(self.wtr, "{{{}}}", x), + AtLeast(x) => write!(self.wtr, "{{{},}}", x), + Bounded(x, y) => write!(self.wtr, "{{{},{}}}", x, y), + } + } + + fn fmt_literal(&mut self, ast: &ast::Literal) -> fmt::Result { + use ast::LiteralKind::*; + + match ast.kind { + Verbatim => self.wtr.write_char(ast.c), + Punctuation => write!(self.wtr, r"\{}", ast.c), + Octal => write!(self.wtr, r"\{:o}", ast.c as u32), + HexFixed(ast::HexLiteralKind::X) => { + write!(self.wtr, r"\x{:02X}", ast.c as u32) + } + HexFixed(ast::HexLiteralKind::UnicodeShort) => { + write!(self.wtr, r"\u{:04X}", ast.c as u32) + } + HexFixed(ast::HexLiteralKind::UnicodeLong) => { + write!(self.wtr, r"\U{:08X}", ast.c as u32) + } + HexBrace(ast::HexLiteralKind::X) => { + write!(self.wtr, r"\x{{{:X}}}", ast.c as u32) + } + HexBrace(ast::HexLiteralKind::UnicodeShort) => { + write!(self.wtr, r"\u{{{:X}}}", ast.c as u32) + } + HexBrace(ast::HexLiteralKind::UnicodeLong) => { + write!(self.wtr, r"\U{{{:X}}}", ast.c as u32) + } + Special(ast::SpecialLiteralKind::Bell) => { + self.wtr.write_str(r"\a") + } + Special(ast::SpecialLiteralKind::FormFeed) => { + self.wtr.write_str(r"\f") + } + Special(ast::SpecialLiteralKind::Tab) => { + self.wtr.write_str(r"\t") + } + Special(ast::SpecialLiteralKind::LineFeed) => { + self.wtr.write_str(r"\n") + } + Special(ast::SpecialLiteralKind::CarriageReturn) => { + self.wtr.write_str(r"\r") + } + Special(ast::SpecialLiteralKind::VerticalTab) => { + self.wtr.write_str(r"\v") + } + Special(ast::SpecialLiteralKind::Space) => { + self.wtr.write_str(r"\ ") + } + } + } + + fn fmt_assertion(&mut self, ast: &ast::Assertion) -> fmt::Result { + use ast::AssertionKind::*; + match ast.kind { + StartLine => self.wtr.write_str("^"), + EndLine => self.wtr.write_str("$"), + StartText => self.wtr.write_str(r"\A"), + EndText => self.wtr.write_str(r"\z"), + WordBoundary => self.wtr.write_str(r"\b"), + NotWordBoundary => self.wtr.write_str(r"\B"), + } + } + + fn fmt_set_flags(&mut self, ast: &ast::SetFlags) -> fmt::Result { + self.wtr.write_str("(?")?; + self.fmt_flags(&ast.flags)?; + self.wtr.write_str(")")?; + Ok(()) + } + + fn fmt_flags(&mut self, ast: &ast::Flags) -> fmt::Result { + use ast::{Flag, FlagsItemKind}; + + for item in &ast.items { + match item.kind { + FlagsItemKind::Negation => self.wtr.write_str("-"), + FlagsItemKind::Flag(ref flag) => { + match *flag { + Flag::CaseInsensitive => self.wtr.write_str("i"), + Flag::MultiLine => self.wtr.write_str("m"), + Flag::DotMatchesNewLine => self.wtr.write_str("s"), + Flag::SwapGreed => self.wtr.write_str("U"), + Flag::Unicode => self.wtr.write_str("u"), + Flag::IgnoreWhitespace => self.wtr.write_str("x"), + } + } + }?; + } + Ok(()) + } + + fn fmt_class_bracketed_pre( + &mut self, + ast: &ast::ClassBracketed, + ) -> fmt::Result { + if ast.negated { + self.wtr.write_str("[^") + } else { + self.wtr.write_str("[") + } + } + + fn fmt_class_bracketed_post( + &mut self, + _ast: &ast::ClassBracketed, + ) -> fmt::Result { + self.wtr.write_str("]") + } + + fn fmt_class_set_binary_op_kind( + &mut self, + ast: &ast::ClassSetBinaryOpKind, + ) -> fmt::Result { + use ast::ClassSetBinaryOpKind::*; + match *ast { + Intersection => self.wtr.write_str("&&"), + Difference => self.wtr.write_str("--"), + SymmetricDifference => self.wtr.write_str("~~"), + } + } + + fn fmt_class_perl(&mut self, ast: &ast::ClassPerl) -> fmt::Result { + use ast::ClassPerlKind::*; + match ast.kind { + Digit if ast.negated => self.wtr.write_str(r"\D"), + Digit => self.wtr.write_str(r"\d"), + Space if ast.negated => self.wtr.write_str(r"\S"), + Space => self.wtr.write_str(r"\s"), + Word if ast.negated => self.wtr.write_str(r"\W"), + Word => self.wtr.write_str(r"\w"), + } + } + + fn fmt_class_ascii(&mut self, ast: &ast::ClassAscii) -> fmt::Result { + use ast::ClassAsciiKind::*; + match ast.kind { + Alnum if ast.negated => self.wtr.write_str("[:^alnum:]"), + Alnum => self.wtr.write_str("[:alnum:]"), + Alpha if ast.negated => self.wtr.write_str("[:^alpha:]"), + Alpha => self.wtr.write_str("[:alpha:]"), + Ascii if ast.negated => self.wtr.write_str("[:^ascii:]"), + Ascii => self.wtr.write_str("[:ascii:]"), + Blank if ast.negated => self.wtr.write_str("[:^blank:]"), + Blank => self.wtr.write_str("[:blank:]"), + Cntrl if ast.negated => self.wtr.write_str("[:^cntrl:]"), + Cntrl => self.wtr.write_str("[:cntrl:]"), + Digit if ast.negated => self.wtr.write_str("[:^digit:]"), + Digit => self.wtr.write_str("[:digit:]"), + Graph if ast.negated => self.wtr.write_str("[:^graph:]"), + Graph => self.wtr.write_str("[:graph:]"), + Lower if ast.negated => self.wtr.write_str("[:^lower:]"), + Lower => self.wtr.write_str("[:lower:]"), + Print if ast.negated => self.wtr.write_str("[:^print:]"), + Print => self.wtr.write_str("[:print:]"), + Punct if ast.negated => self.wtr.write_str("[:^punct:]"), + Punct => self.wtr.write_str("[:punct:]"), + Space if ast.negated => self.wtr.write_str("[:^space:]"), + Space => self.wtr.write_str("[:space:]"), + Upper if ast.negated => self.wtr.write_str("[:^upper:]"), + Upper => self.wtr.write_str("[:upper:]"), + Word if ast.negated => self.wtr.write_str("[:^word:]"), + Word => self.wtr.write_str("[:word:]"), + Xdigit if ast.negated => self.wtr.write_str("[:^xdigit:]"), + Xdigit => self.wtr.write_str("[:xdigit:]"), + } + } + + fn fmt_class_unicode(&mut self, ast: &ast::ClassUnicode) -> fmt::Result { + use ast::ClassUnicodeKind::*; + use ast::ClassUnicodeOpKind::*; + + if ast.negated { + self.wtr.write_str(r"\P")?; + } else { + self.wtr.write_str(r"\p")?; + } + match ast.kind { + OneLetter(c) => self.wtr.write_char(c), + Named(ref x) => write!(self.wtr, "{{{}}}", x), + NamedValue { op: Equal, ref name, ref value } => { + write!(self.wtr, "{{{}={}}}", name, value) + } + NamedValue { op: Colon, ref name, ref value } => { + write!(self.wtr, "{{{}:{}}}", name, value) + } + NamedValue { op: NotEqual, ref name, ref value } => { + write!(self.wtr, "{{{}!={}}}", name, value) + } + } + } +} + +#[cfg(test)] +mod tests { + use ast::parse::ParserBuilder; + use super::Printer; + + fn roundtrip(given: &str) { + roundtrip_with(|b| b, given); + } + + fn roundtrip_with<F>(mut f: F, given: &str) + where F: FnMut(&mut ParserBuilder) -> &mut ParserBuilder + { + let mut builder = ParserBuilder::new(); + f(&mut builder); + let ast = builder.build().parse(given).unwrap(); + + let mut printer = Printer::new(); + let mut dst = String::new(); + printer.print(&ast, &mut dst).unwrap(); + assert_eq!(given, dst); + } + + #[test] + fn print_literal() { + roundtrip("a"); + roundtrip(r"\["); + roundtrip_with(|b| b.octal(true), r"\141"); + roundtrip(r"\x61"); + roundtrip(r"\x7F"); + roundtrip(r"\u0061"); + roundtrip(r"\U00000061"); + roundtrip(r"\x{61}"); + roundtrip(r"\x{7F}"); + roundtrip(r"\u{61}"); + roundtrip(r"\U{61}"); + + roundtrip(r"\a"); + roundtrip(r"\f"); + roundtrip(r"\t"); + roundtrip(r"\n"); + roundtrip(r"\r"); + roundtrip(r"\v"); + roundtrip(r"(?x)\ "); + } + + #[test] + fn print_dot() { + roundtrip("."); + } + + #[test] + fn print_concat() { + roundtrip("ab"); + roundtrip("abcde"); + roundtrip("a(bcd)ef"); + } + + #[test] + fn print_alternation() { + roundtrip("a|b"); + roundtrip("a|b|c|d|e"); + roundtrip("|a|b|c|d|e"); + roundtrip("|a|b|c|d|e|"); + roundtrip("a(b|c|d)|e|f"); + } + + #[test] + fn print_assertion() { + roundtrip(r"^"); + roundtrip(r"$"); + roundtrip(r"\A"); + roundtrip(r"\z"); + roundtrip(r"\b"); + roundtrip(r"\B"); + } + + #[test] + fn print_repetition() { + roundtrip("a?"); + roundtrip("a??"); + roundtrip("a*"); + roundtrip("a*?"); + roundtrip("a+"); + roundtrip("a+?"); + roundtrip("a{5}"); + roundtrip("a{5}?"); + roundtrip("a{5,}"); + roundtrip("a{5,}?"); + roundtrip("a{5,10}"); + roundtrip("a{5,10}?"); + } + + #[test] + fn print_flags() { + roundtrip("(?i)"); + roundtrip("(?-i)"); + roundtrip("(?s-i)"); + roundtrip("(?-si)"); + roundtrip("(?siUmux)"); + } + + #[test] + fn print_group() { + roundtrip("(?i:a)"); + roundtrip("(?P<foo>a)"); + roundtrip("(a)"); + } + + #[test] + fn print_class() { + roundtrip(r"[abc]"); + roundtrip(r"[a-z]"); + roundtrip(r"[^a-z]"); + roundtrip(r"[a-z0-9]"); + roundtrip(r"[-a-z0-9]"); + roundtrip(r"[-a-z0-9]"); + roundtrip(r"[a-z0-9---]"); + roundtrip(r"[a-z&&m-n]"); + roundtrip(r"[[a-z&&m-n]]"); + roundtrip(r"[a-z--m-n]"); + roundtrip(r"[a-z~~m-n]"); + roundtrip(r"[a-z[0-9]]"); + roundtrip(r"[a-z[^0-9]]"); + + roundtrip(r"\d"); + roundtrip(r"\D"); + roundtrip(r"\s"); + roundtrip(r"\S"); + roundtrip(r"\w"); + roundtrip(r"\W"); + + roundtrip(r"[[:alnum:]]"); + roundtrip(r"[[:^alnum:]]"); + roundtrip(r"[[:alpha:]]"); + roundtrip(r"[[:^alpha:]]"); + roundtrip(r"[[:ascii:]]"); + roundtrip(r"[[:^ascii:]]"); + roundtrip(r"[[:blank:]]"); + roundtrip(r"[[:^blank:]]"); + roundtrip(r"[[:cntrl:]]"); + roundtrip(r"[[:^cntrl:]]"); + roundtrip(r"[[:digit:]]"); + roundtrip(r"[[:^digit:]]"); + roundtrip(r"[[:graph:]]"); + roundtrip(r"[[:^graph:]]"); + roundtrip(r"[[:lower:]]"); + roundtrip(r"[[:^lower:]]"); + roundtrip(r"[[:print:]]"); + roundtrip(r"[[:^print:]]"); + roundtrip(r"[[:punct:]]"); + roundtrip(r"[[:^punct:]]"); + roundtrip(r"[[:space:]]"); + roundtrip(r"[[:^space:]]"); + roundtrip(r"[[:upper:]]"); + roundtrip(r"[[:^upper:]]"); + roundtrip(r"[[:word:]]"); + roundtrip(r"[[:^word:]]"); + roundtrip(r"[[:xdigit:]]"); + roundtrip(r"[[:^xdigit:]]"); + + roundtrip(r"\pL"); + roundtrip(r"\PL"); + roundtrip(r"\p{L}"); + roundtrip(r"\P{L}"); + roundtrip(r"\p{X=Y}"); + roundtrip(r"\P{X=Y}"); + roundtrip(r"\p{X:Y}"); + roundtrip(r"\P{X:Y}"); + roundtrip(r"\p{X!=Y}"); + roundtrip(r"\P{X!=Y}"); + } +} diff --git a/regex-syntax/src/ast/visitor.rs b/regex-syntax/src/ast/visitor.rs new file mode 100644 index 000000000..9b93a1ae1 --- /dev/null +++ b/regex-syntax/src/ast/visitor.rs @@ -0,0 +1,557 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +use ast::{self, Ast}; + +/// A trait for visiting an abstract syntax tree (AST) in depth first order. +/// +/// The principle aim of this trait is to enable callers to perform case +/// analysis on an abstract syntax tree without necessarily using recursion. +/// In particular, this permits callers to do case analysis with constant stack +/// usage, which can be important since the size of an abstract syntax tree +/// may be proportional to end user input. +/// +/// Typical usage of this trait involves providing an implementation and then +/// running it using the [`visit`](fn.visit.html) function. +/// +/// Note that the abstract syntax tree for a regular expression is quite +/// complex. Unless you specifically need it, you might be able to use the +/// much simpler +/// [high-level intermediate representation](../hir/struct.Hir.html) +/// and its +/// [corresponding `Visitor` trait](../hir/trait.Visitor.html) +/// instead. +pub trait Visitor { + /// The result of visiting an AST. + type Output; + /// An error that visiting an AST might return. + type Err; + + /// All implementors of `Visitor` must provide a `finish` method, which + /// yields the result of visiting the AST or an error. + fn finish(self) -> Result<Self::Output, Self::Err>; + + /// This method is called before beginning traversal of the AST. + fn start(&mut self) {} + + /// This method is called on an `Ast` before descending into child `Ast` + /// nodes. + fn visit_pre(&mut self, _ast: &Ast) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on an `Ast` after descending all of its child + /// `Ast` nodes. + fn visit_post(&mut self, _ast: &Ast) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of an + /// [`Alternation`](struct.Alternation.html). + fn visit_alternation_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetItem`](enum.ClassSetItem.html) + /// before descending into child nodes. + fn visit_class_set_item_pre( + &mut self, + _ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetItem`](enum.ClassSetItem.html) + /// after descending into child nodes. + fn visit_class_set_item_post( + &mut self, + _ast: &ast::ClassSetItem, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetBinaryOp`](struct.ClassSetBinaryOp.html) + /// before descending into child nodes. + fn visit_class_set_binary_op_pre( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on every + /// [`ClassSetBinaryOp`](struct.ClassSetBinaryOp.html) + /// after descending into child nodes. + fn visit_class_set_binary_op_post( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between the left hand and right hand child nodes + /// of a [`ClassSetBinaryOp`](struct.ClassSetBinaryOp.html). + fn visit_class_set_binary_op_in( + &mut self, + _ast: &ast::ClassSetBinaryOp, + ) -> Result<(), Self::Err> { + Ok(()) + } +} + +/// Executes an implementation of `Visitor` in constant stack space. +/// +/// This function will visit every node in the given `Ast` while calling the +/// appropriate methods provided by the +/// [`Visitor`](trait.Visitor.html) trait. +/// +/// The primary use case for this method is when one wants to perform case +/// analysis over an `Ast` without using a stack size proportional to the depth +/// of the `Ast`. Namely, this method will instead use constant stack size, but +/// will use heap space proportional to the size of the `Ast`. This may be +/// desirable in cases where the size of `Ast` is proportional to end user +/// input. +/// +/// If the visitor returns an error at any point, then visiting is stopped and +/// the error is returned. +pub fn visit<V: Visitor>(ast: &Ast, visitor: V) -> Result<V::Output, V::Err> { + HeapVisitor::new().visit(ast, visitor) +} + +/// HeapVisitor visits every item in an `Ast` recursively using constant stack +/// size and a heap size proportional to the size of the `Ast`. +struct HeapVisitor<'a> { + /// A stack of `Ast` nodes. This is roughly analogous to the call stack + /// used in a typical recursive visitor. + stack: Vec<(&'a Ast, Frame<'a>)>, + /// Similar to the `Ast` stack above, but is used only for character + /// classes. In particular, character classes embed their own mini + /// recursive syntax. + stack_class: Vec<(ClassInduct<'a>, ClassFrame<'a>)>, +} + +/// Represents a single stack frame while performing structural induction over +/// an `Ast`. +enum Frame<'a> { + /// A stack frame allocated just before descending into a repetition + /// operator's child node. + Repetition(&'a ast::Repetition), + /// A stack frame allocated just before descending into a group's child + /// node. + Group(&'a ast::Group), + /// The stack frame used while visiting every child node of a concatenation + /// of expressions. + Concat { + /// The child node we are currently visiting. + head: &'a Ast, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Ast], + }, + /// The stack frame used while visiting every child node of an alternation + /// of expressions. + Alternation { + /// The child node we are currently visiting. + head: &'a Ast, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Ast], + }, +} + +/// Represents a single stack frame while performing structural induction over +/// a character class. +enum ClassFrame<'a> { + /// The stack frame used while visiting every child node of a union of + /// character class items. + Union { + /// The child node we are currently visiting. + head: &'a ast::ClassSetItem, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [ast::ClassSetItem], + }, + /// The stack frame used while a binary class operation. + Binary { + op: &'a ast::ClassSetBinaryOp, + }, + /// A stack frame allocated just before descending into a binary operator's + /// left hand child node. + BinaryLHS { + op: &'a ast::ClassSetBinaryOp, + lhs: &'a ast::ClassSet, + rhs: &'a ast::ClassSet, + }, + /// A stack frame allocated just before descending into a binary operator's + /// right hand child node. + BinaryRHS { + op: &'a ast::ClassSetBinaryOp, + rhs: &'a ast::ClassSet, + }, +} + +/// A representation of the inductive step when performing structural induction +/// over a character class. +/// +/// Note that there is no analogous explicit type for the inductive step for +/// `Ast` nodes because the inductive step is just an `Ast`. For character +/// classes, the inductive step can produce one of two possible child nodes: +/// an item or a binary operation. (An item cannot be a binary operation +/// because that would imply binary operations can be unioned in the concrete +/// syntax, which is not possible.) +enum ClassInduct<'a> { + Item(&'a ast::ClassSetItem), + BinaryOp(&'a ast::ClassSetBinaryOp), +} + +impl<'a> HeapVisitor<'a> { + fn new() -> HeapVisitor<'a> { + HeapVisitor { stack: vec![], stack_class: vec![] } + } + + fn visit<V: Visitor>( + &mut self, + mut ast: &'a Ast, + mut visitor: V, + ) -> Result<V::Output, V::Err> { + self.stack.clear(); + self.stack_class.clear(); + + visitor.start(); + loop { + visitor.visit_pre(ast)?; + if let Some(x) = self.induct(ast, &mut visitor)? { + let child = x.child(); + self.stack.push((ast, x)); + ast = child; + continue; + } + // No induction means we have a base case, so we can post visit + // it now. + visitor.visit_post(ast)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_ast, frame) = match self.stack.pop() { + None => return visitor.finish(), + Some((post_ast, frame)) => (post_ast, frame), + }; + // If this is a concat/alternate, then we might have additional + // inductive steps to process. + if let Some(x) = self.pop(frame) { + if let Frame::Alternation {..} = x { + visitor.visit_alternation_in()?; + } + ast = x.child(); + self.stack.push((post_ast, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this AST, so we can post visit it now. + visitor.visit_post(post_ast)?; + } + } + } + + /// Build a stack frame for the given AST if one is needed (which occurs if + /// and only if there are child nodes in the AST). Otherwise, return None. + /// + /// If this visits a class, then the underlying visitor implementation may + /// return an error which will be passed on here. + fn induct<V: Visitor>( + &mut self, + ast: &'a Ast, + visitor: &mut V, + ) -> Result<Option<Frame<'a>>, V::Err> { + Ok(match *ast { + Ast::Class(ast::Class::Bracketed(ref x)) => { + self.visit_class(x, visitor)?; + None + } + Ast::Repetition(ref x) => Some(Frame::Repetition(x)), + Ast::Group(ref x) => Some(Frame::Group(x)), + Ast::Concat(ref x) if x.asts.is_empty() => None, + Ast::Concat(ref x) => { + Some(Frame::Concat { + head: &x.asts[0], + tail: &x.asts[1..], + }) + } + Ast::Alternation(ref x) if x.asts.is_empty() => None, + Ast::Alternation(ref x) => { + Some(Frame::Alternation { + head: &x.asts[0], + tail: &x.asts[1..], + }) + } + _ => None, + }) + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop(&self, induct: Frame<'a>) -> Option<Frame<'a>> { + match induct { + Frame::Repetition(_) => None, + Frame::Group(_) => None, + Frame::Concat { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Concat { + head: &tail[0], + tail: &tail[1..], + }) + } + } + Frame::Alternation { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Alternation { + head: &tail[0], + tail: &tail[1..], + }) + } + } + } + } + + fn visit_class<V: Visitor>( + &mut self, + ast: &'a ast::ClassBracketed, + visitor: &mut V, + ) -> Result<(), V::Err> { + let mut ast = ClassInduct::from_bracketed(ast); + loop { + self.visit_class_pre(&ast, visitor)?; + if let Some(x) = self.induct_class(&ast) { + let child = x.child(); + self.stack_class.push((ast, x)); + ast = child; + continue; + } + self.visit_class_post(&ast, visitor)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_ast, frame) = match self.stack_class.pop() { + None => return Ok(()), + Some((post_ast, frame)) => (post_ast, frame), + }; + // If this is a union or a binary op, then we might have + // additional inductive steps to process. + if let Some(x) = self.pop_class(frame) { + if let ClassFrame::BinaryRHS { ref op, .. } = x { + visitor.visit_class_set_binary_op_in(op)?; + } + ast = x.child(); + self.stack_class.push((post_ast, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this class node, so we can post visit it now. + self.visit_class_post(&post_ast, visitor)?; + } + } + } + + /// Call the appropriate `Visitor` methods given an inductive step. + fn visit_class_pre<V: Visitor>( + &self, + ast: &ClassInduct<'a>, + visitor: &mut V, + ) -> Result<(), V::Err> { + match *ast { + ClassInduct::Item(item) => { + visitor.visit_class_set_item_pre(item)?; + } + ClassInduct::BinaryOp(op) => { + visitor.visit_class_set_binary_op_pre(op)?; + } + } + Ok(()) + } + + /// Call the appropriate `Visitor` methods given an inductive step. + fn visit_class_post<V: Visitor>( + &self, + ast: &ClassInduct<'a>, + visitor: &mut V, + ) -> Result<(), V::Err> { + match *ast { + ClassInduct::Item(item) => { + visitor.visit_class_set_item_post(item)?; + } + ClassInduct::BinaryOp(op) => { + visitor.visit_class_set_binary_op_post(op)?; + } + } + Ok(()) + } + + /// Build a stack frame for the given class node if one is needed (which + /// occurs if and only if there are child nodes). Otherwise, return None. + fn induct_class( + &self, + ast: &ClassInduct<'a>, + ) -> Option<ClassFrame<'a>> { + match *ast { + ClassInduct::Item(&ast::ClassSetItem::Bracketed(ref x)) => { + match x.kind { + ast::ClassSet::Item(ref item) => { + Some(ClassFrame::Union { + head: item, + tail: &[], + }) + } + ast::ClassSet::BinaryOp(ref op) => { + Some(ClassFrame::Binary { op: op }) + } + } + } + ClassInduct::Item(&ast::ClassSetItem::Union(ref x)) => { + if x.items.is_empty() { + None + } else { + Some(ClassFrame::Union { + head: &x.items[0], + tail: &x.items[1..], + }) + } + } + ClassInduct::BinaryOp(op) => { + Some(ClassFrame::BinaryLHS { + op: op, + lhs: &op.lhs, + rhs: &op.rhs, + }) + } + _ => None, + } + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop_class(&self, induct: ClassFrame<'a>) -> Option<ClassFrame<'a>> { + match induct { + ClassFrame::Union { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(ClassFrame::Union { + head: &tail[0], + tail: &tail[1..], + }) + } + } + ClassFrame::Binary {..} => None, + ClassFrame::BinaryLHS { op, rhs, .. } => { + Some(ClassFrame::BinaryRHS { + op: op, + rhs: rhs, + }) + } + ClassFrame::BinaryRHS {..} => None, + } + } +} + +impl<'a> Frame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child AST node to visit. + fn child(&self) -> &'a Ast { + match *self { + Frame::Repetition(rep) => &rep.ast, + Frame::Group(group) => &group.ast, + Frame::Concat { head, .. } => head, + Frame::Alternation { head, .. } => head, + } + } +} + +impl<'a> ClassFrame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child class node to visit. + fn child(&self) -> ClassInduct<'a> { + match *self { + ClassFrame::Union { head, .. } => ClassInduct::Item(head), + ClassFrame::Binary { op, .. } => ClassInduct::BinaryOp(op), + ClassFrame::BinaryLHS { ref lhs, .. } => { + ClassInduct::from_set(lhs) + } + ClassFrame::BinaryRHS { ref rhs, .. } => { + ClassInduct::from_set(rhs) + } + } + } +} + +impl<'a> ClassInduct<'a> { + fn from_bracketed(ast: &'a ast::ClassBracketed) -> ClassInduct<'a> { + ClassInduct::from_set(&ast.kind) + } + + fn from_set(ast: &'a ast::ClassSet) -> ClassInduct<'a> { + match *ast { + ast::ClassSet::Item(ref item) => ClassInduct::Item(item), + ast::ClassSet::BinaryOp(ref op) => ClassInduct::BinaryOp(op), + } + } +} + +impl<'a> fmt::Debug for ClassFrame<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let x = match *self { + ClassFrame::Union{..} => "Union", + ClassFrame::Binary{..} => "Binary", + ClassFrame::BinaryLHS{..} => "BinaryLHS", + ClassFrame::BinaryRHS{..} => "BinaryRHS", + }; + write!(f, "{}", x) + } +} + +impl<'a> fmt::Debug for ClassInduct<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let x = match *self { + ClassInduct::Item(it) => { + match *it { + ast::ClassSetItem::Empty(_) => "Item(Empty)", + ast::ClassSetItem::Literal(_) => "Item(Literal)", + ast::ClassSetItem::Range(_) => "Item(Range)", + ast::ClassSetItem::Ascii(_) => "Item(Ascii)", + ast::ClassSetItem::Perl(_) => "Item(Perl)", + ast::ClassSetItem::Unicode(_) => "Item(Unicode)", + ast::ClassSetItem::Bracketed(_) => "Item(Bracketed)", + ast::ClassSetItem::Union(_) => "Item(Union)", + } + } + ClassInduct::BinaryOp(it) => { + match it.kind { + ast::ClassSetBinaryOpKind::Intersection => { + "BinaryOp(Intersection)" + } + ast::ClassSetBinaryOpKind::Difference => { + "BinaryOp(Difference)" + } + ast::ClassSetBinaryOpKind::SymmetricDifference => { + "BinaryOp(SymmetricDifference)" + } + } + } + }; + write!(f, "{}", x) + } +} diff --git a/regex-syntax/src/either.rs b/regex-syntax/src/either.rs new file mode 100644 index 000000000..7ae41e4ce --- /dev/null +++ b/regex-syntax/src/either.rs @@ -0,0 +1,8 @@ +/// A simple binary sum type. +/// +/// This is occasionally useful in an ad hoc fashion. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Either<Left, Right> { + Left(Left), + Right(Right), +} diff --git a/regex-syntax/src/error.rs b/regex-syntax/src/error.rs new file mode 100644 index 000000000..1f5b8f817 --- /dev/null +++ b/regex-syntax/src/error.rs @@ -0,0 +1,297 @@ +use std::cmp; +use std::error; +use std::fmt; +use std::result; + +use ast; +use hir; + +/// A type alias for dealing with errors returned by this crate. +pub type Result<T> = result::Result<T, Error>; + +/// This error type encompasses any error that can be returned by this crate. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Error { + /// An error that occurred while translating concrete syntax into abstract + /// syntax (AST). + Parse(ast::Error), + /// An error that occurred while translating abstract syntax into a high + /// level intermediate representation (HIR). + Translate(hir::Error), + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +impl From<ast::Error> for Error { + fn from(err: ast::Error) -> Error { + Error::Parse(err) + } +} + +impl From<hir::Error> for Error { + fn from(err: hir::Error) -> Error { + Error::Translate(err) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Parse(ref x) => x.description(), + Error::Translate(ref x) => x.description(), + _ => unreachable!(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Parse(ref x) => x.fmt(f), + Error::Translate(ref x) => x.fmt(f), + _ => unreachable!(), + } + } +} + +/// A helper type for formatting nice error messages. +/// +/// This type is responsible for reporting regex parse errors in a nice human +/// readable format. Most of its complexity is from interspersing notational +/// markers pointing out the position where an error occurred. +#[derive(Debug)] +pub struct Formatter<'e, E: 'e> { + /// The original regex pattern in which the error occurred. + pattern: &'e str, + /// The error kind. It must impl fmt::Display. + err: &'e E, + /// The primary span of the error. + span: &'e ast::Span, + /// An auxiliary and optional span, in case the error needs to point to + /// two locations (e.g., when reporting a duplicate capture group name). + aux_span: Option<&'e ast::Span>, +} + +impl<'e> From<&'e ast::Error> for Formatter<'e, ast::ErrorKind> { + fn from(err: &'e ast::Error) -> Self { + Formatter { + pattern: err.pattern(), + err: err.kind(), + span: err.span(), + aux_span: err.auxiliary_span(), + } + } +} + +impl<'e> From<&'e hir::Error> for Formatter<'e, hir::ErrorKind> { + fn from(err: &'e hir::Error) -> Self { + Formatter { + pattern: err.pattern(), + err: err.kind(), + span: err.span(), + aux_span: None, + } + } +} + +impl<'e, E: fmt::Display> fmt::Display for Formatter<'e, E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let spans = Spans::from_formatter(self); + if self.pattern.contains('\n') { + let divider = repeat_char('~', 79); + + writeln!(f, "regex parse error:")?; + writeln!(f, "{}", divider)?; + let notated = spans.notate(); + write!(f, "{}", notated)?; + writeln!(f, "{}", divider)?; + // If we have error spans that cover multiple lines, then we just + // note the line numbers. + if !spans.multi_line.is_empty() { + let mut notes = vec![]; + for span in &spans.multi_line { + notes.push(format!( + "on line {} (column {}) through line {} (column {})", + span.start.line, span.start.column, + span.end.line, span.end.column - 1)); + } + writeln!(f, "{}", notes.join("\n"))?; + } + write!(f, "error: {}", self.err)?; + } else { + writeln!(f, "regex parse error:")?; + let notated = Spans::from_formatter(self).notate(); + write!(f, "{}", notated)?; + write!(f, "error: {}", self.err)?; + } + Ok(()) + } +} + +/// This type represents an arbitrary number of error spans in a way that makes +/// it convenient to notate the regex pattern. ("Notate" means "point out +/// exactly where the error occurred in the regex pattern.") +/// +/// Technically, we can only ever have two spans given our current error +/// structure. However, after toiling with a specific algorithm for handling +/// two spans, it became obvious that an algorithm to handle an arbitrary +/// number of spans was actually much simpler. +struct Spans<'p> { + /// The original regex pattern string. + pattern: &'p str, + /// The total width that should be used for line numbers. The width is + /// used for left padding the line numbers for alignment. + /// + /// A value of `0` means line numbers should not be displayed. That is, + /// the pattern is itself only one line. + line_number_width: usize, + /// All error spans that occur on a single line. This sequence always has + /// length equivalent to the number of lines in `pattern`, where the index + /// of the sequence represents a line number, starting at `0`. The spans + /// in each line are sorted in ascending order. + by_line: Vec<Vec<ast::Span>>, + /// All error spans that occur over one or more lines. That is, the start + /// and end position of the span have different line numbers. The spans are + /// sorted in ascending order. + multi_line: Vec<ast::Span>, +} + +impl<'p> Spans<'p> { + /// Build a sequence of spans from a formatter. + fn from_formatter<'e, E: fmt::Display>( + fmter: &'p Formatter<'e, E>, + ) -> Spans<'p> { + let mut line_count = fmter.pattern.lines().count(); + // If the pattern ends with a `\n` literal, then our line count is + // off by one, since a span can occur immediately after the last `\n`, + // which is consider to be an additional line. + if fmter.pattern.ends_with('\n') { + line_count += 1; + } + let line_number_width = + if line_count <= 1 { + 0 + } else { + line_count.to_string().len() + }; + let mut spans = Spans { + pattern: &fmter.pattern, + line_number_width: line_number_width, + by_line: vec![vec![]; line_count], + multi_line: vec![], + }; + spans.add(fmter.span.clone()); + if let Some(span) = fmter.aux_span { + spans.add(span.clone()); + } + spans + } + + /// Add the given span to this sequence, putting it in the right place. + fn add(&mut self, span: ast::Span) { + // This is grossly inefficient since we sort after each add, but right + // now, we only ever add two spans at most. + if span.is_one_line() { + let i = span.start.line - 1; // because lines are 1-indexed + self.by_line[i].push(span); + self.by_line[i].sort(); + } else { + self.multi_line.push(span); + self.multi_line.sort(); + } + } + + /// Notate the pattern string with carents (`^`) pointing at each span + /// location. This only applies to spans that occur within a single line. + fn notate(&self) -> String { + let mut notated = String::new(); + for (i, line) in self.pattern.lines().enumerate() { + if self.line_number_width > 0 { + notated.push_str(&self.left_pad_line_number(i + 1)); + notated.push_str(": "); + } else { + notated.push_str(" "); + } + notated.push_str(line); + notated.push('\n'); + if let Some(notes) = self.notate_line(i) { + notated.push_str(¬es); + notated.push('\n'); + } + } + notated + } + + /// Return notes for the line indexed at `i` (zero-based). If there are no + /// spans for the given line, then `None` is returned. Otherwise, an + /// appropriately space padded string with correctly positioned `^` is + /// returned, accounting for line numbers. + fn notate_line(&self, i: usize) -> Option<String> { + let spans = &self.by_line[i]; + if spans.is_empty() { + return None; + } + let mut notes = String::new(); + for _ in 0..self.line_number_padding() { + notes.push(' '); + } + let mut pos = 0; + for span in spans { + for _ in pos..(span.start.column - 1) { + notes.push(' '); + pos += 1; + } + let note_len = span.end.column.saturating_sub(span.start.column); + for _ in 0..cmp::max(1, note_len) { + notes.push('^'); + pos += 1; + } + } + Some(notes) + } + + /// Left pad the given line number with spaces such that it is aligned with + /// other line numbers. + fn left_pad_line_number(&self, n: usize) -> String { + let n = n.to_string(); + let pad = self.line_number_width.checked_sub(n.len()).unwrap(); + let mut result = repeat_char(' ', pad); + result.push_str(&n); + result + } + + /// Return the line number padding beginning at the start of each line of + /// the pattern. + /// + /// If the pattern is only one line, then this returns a fixed padding + /// for visual indentation. + fn line_number_padding(&self) -> usize { + if self.line_number_width == 0 { + 4 + } else { + 2 + self.line_number_width + } + } +} + +fn repeat_char(c: char, count: usize) -> String { + ::std::iter::repeat(c).take(count).collect() +} + +#[cfg(test)] +mod tests { + use ast::parse::Parser; + + // See: https://github.com/rust-lang/regex/issues/464 + #[test] + fn regression_464() { + let err = Parser::new().parse("a{\n").unwrap_err(); + // This test checks that the error formatter doesn't panic. + assert!(!err.to_string().is_empty()); + } +} diff --git a/regex-syntax/src/hir/interval.rs b/regex-syntax/src/hir/interval.rs new file mode 100644 index 000000000..6b63caa94 --- /dev/null +++ b/regex-syntax/src/hir/interval.rs @@ -0,0 +1,490 @@ +use std::char; +use std::cmp; +use std::fmt::Debug; +use std::slice; +use std::u8; + +// This module contains an *internal* implementation of interval sets. +// +// The primary invariant that interval sets guards is canonical ordering. That +// is, every interval set contains an ordered sequence of intervals where +// no two intervals are overlapping or adjacent. While this invariant is +// occasionally broken within the implementation, it should be impossible for +// callers to observe it. +// +// Since case folding (as implemented below) breaks that invariant, we roll +// that into this API even though it is a little out of place in an otherwise +// generic interval set. +// +// Some of the implementation complexity here is a result of me wanting to +// preserve the sequential representation without using additional memory. +// In many cases, we do use linear extra memory, but it is at most 2x and it +// is amortized. If we relaxed the memory requirements, this implementation +// could become much simpler. The extra memory is honestly probably OK, but +// character classes (especially of the Unicode variety) can become quite +// large, and it would be nice to keep regex compilation snappy even in debug +// builds. (In the past, I have been careless with this area of code and it has +// caused slow regex compilations in debug mode, so this isn't entirely +// unwarranted.) +// +// Tests on this are relegated to the public API of HIR in src/hir.rs. + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IntervalSet<I> { + ranges: Vec<I>, +} + +impl<I: Interval> IntervalSet<I> { + /// Create a new set from a sequence of intervals. Each interval is + /// specified as a pair of bounds, where both bounds are inclusive. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. + pub fn new<T: IntoIterator<Item=I>>(intervals: T) -> IntervalSet<I> { + let mut set = IntervalSet { ranges: intervals.into_iter().collect() }; + set.canonicalize(); + set + } + + /// Add a new interval to this set. + pub fn push(&mut self, interval: I) { + // TODO: This could be faster. e.g., Push the interval such that + // it preserves canonicalization. + self.ranges.push(interval); + self.canonicalize(); + } + + /// Return an iterator over all intervals in this set. + /// + /// The iterator yields intervals in ascending order. + pub fn iter(&self) -> IntervalSetIter<I> { + IntervalSetIter(self.ranges.iter()) + } + + /// Return an immutable slice of intervals in this set. + /// + /// The sequence returned is in canonical ordering. + pub fn intervals(&self) -> &[I] { + &self.ranges + } + + /// Expand this interval set such that it contains all case folded + /// characters. For example, if this class consists of the range `a-z`, + /// then applying case folding will result in the class containing both the + /// ranges `a-z` and `A-Z`. + pub fn case_fold_simple(&mut self) { + let len = self.ranges.len(); + for i in 0..len { + let range = self.ranges[i]; + range.case_fold_simple(&mut self.ranges); + } + self.canonicalize(); + } + + /// Union this set with the given set, in place. + pub fn union(&mut self, other: &IntervalSet<I>) { + // This could almost certainly be done more efficiently. + self.ranges.extend(&other.ranges); + self.canonicalize(); + } + + /// Intersect this set with the given set, in place. + pub fn intersect(&mut self, other: &IntervalSet<I>) { + if self.ranges.is_empty() { + return; + } + if other.ranges.is_empty() { + self.ranges.clear(); + return; + } + + // There should be a way to do this in-place with constant memory, + // but I couldn't figure out a simple way to do it. So just append + // the intersection to the end of this range, and then drain it before + // we're done. + let drain_end = self.ranges.len(); + + let mut ita = (0..drain_end).into_iter(); + let mut itb = (0..other.ranges.len()).into_iter(); + let mut a = ita.next().unwrap(); + let mut b = itb.next().unwrap(); + loop { + if let Some(ab) = self.ranges[a].intersect(&other.ranges[b]) { + self.ranges.push(ab); + } + let (it, aorb) = + if self.ranges[a].upper() < other.ranges[b].upper() { + (&mut ita, &mut a) + } else { + (&mut itb, &mut b) + }; + match it.next() { + Some(v) => *aorb = v, + None => break, + } + } + self.ranges.drain(..drain_end); + } + + /// Subtract the given set from this set, in place. + pub fn difference(&mut self, other: &IntervalSet<I>) { + if self.ranges.is_empty() || other.ranges.is_empty() { + return; + } + + // This algorithm is (to me) surprisingly complex. A search of the + // interwebs indicate that this is a potentially interesting problem. + // Folks seem to suggest interval or segment trees, but I'd like to + // avoid the overhead (both runtime and conceptual) of that. + // + // The following is basically my Shitty First Draft. Therefore, in + // order to grok it, you probably need to read each line carefully. + // Simplifications are most welcome! + // + // Remember, we can assume the canonical format invariant here, which + // says that all ranges are sorted, not overlapping and not adjacent in + // each class. + let drain_end = self.ranges.len(); + let (mut a, mut b) = (0, 0); + 'LOOP: + while a < drain_end && b < other.ranges.len() { + // Basically, the easy cases are when neither range overlaps with + // each other. If the `b` range is less than our current `a` + // range, then we can skip it and move on. + if other.ranges[b].upper() < self.ranges[a].lower() { + b += 1; + continue; + } + // ... similarly for the `a` range. If it's less than the smallest + // `b` range, then we can add it as-is. + if self.ranges[a].upper() < other.ranges[b].lower() { + let range = self.ranges[a]; + self.ranges.push(range); + a += 1; + continue; + } + // Otherwise, we have overlapping ranges. + assert!(!self.ranges[a].is_intersection_empty(&other.ranges[b])); + + // This part is tricky and was non-obvious to me without looking + // at explicit examples (see the tests). The trickiness stems from + // two things: 1) subtracting a range from another range could + // yield two ranges and 2) after subtracting a range, it's possible + // that future ranges can have an impact. The loop below advances + // the `b` ranges until they can't possible impact the current + // range. + // + // For example, if our `a` range is `a-t` and our next three `b` + // ranges are `a-c`, `g-i`, `r-t` and `x-z`, then we need to apply + // subtraction three times before moving on to the next `a` range. + let mut range = self.ranges[a]; + while b < other.ranges.len() + && !range.is_intersection_empty(&other.ranges[b]) + { + let old_range = range; + range = match range.difference(&other.ranges[b]) { + (None, None) => { + // We lost the entire range, so move on to the next + // without adding this one. + a += 1; + continue 'LOOP; + } + (Some(range1), None) | (None, Some(range1)) => range1, + (Some(range1), Some(range2)) => { + self.ranges.push(range1); + range2 + } + }; + // It's possible that the `b` range has more to contribute + // here. In particular, if it is greater than the original + // range, then it might impact the next `a` range *and* it + // has impacted the current `a` range as much as possible, + // so we can quit. We don't bump `b` so that the next `a` + // range can apply it. + if other.ranges[b].upper() > old_range.upper() { + break; + } + // Otherwise, the next `b` range might apply to the current + // `a` range. + b += 1; + } + self.ranges.push(range); + a += 1; + } + while a < drain_end { + let range = self.ranges[a]; + self.ranges.push(range); + a += 1; + } + self.ranges.drain(..drain_end); + } + + /// Compute the symmetric difference of the two sets, in place. + /// + /// This computes the symmetric difference of two interval sets. This + /// removes all elements in this set that are also in the given set, + /// but also adds all elements from the given set that aren't in this + /// set. That is, the set will contain all elements in either set, + /// but will not contain any elements that are in both sets. + pub fn symmetric_difference(&mut self, other: &IntervalSet<I>) { + // TODO(burntsushi): Fix this so that it amortizes allocation. + let mut intersection = self.clone(); + intersection.intersect(other); + self.union(other); + self.difference(&intersection); + } + + /// Negate this interval set. + /// + /// For all `x` where `x` is any element, if `x` was in this set, then it + /// will not be in this set after negation. + pub fn negate(&mut self) { + if self.ranges.is_empty() { + let (min, max) = (I::Bound::min_value(), I::Bound::max_value()); + self.ranges.push(I::create(min, max)); + return; + } + + // There should be a way to do this in-place with constant memory, + // but I couldn't figure out a simple way to do it. So just append + // the negation to the end of this range, and then drain it before + // we're done. + let drain_end = self.ranges.len(); + + // We do checked arithmetic below because of the canonical ordering + // invariant. + if self.ranges[0].lower() > I::Bound::min_value() { + let upper = self.ranges[0].lower().decrement(); + self.ranges.push(I::create(I::Bound::min_value(), upper)); + } + for i in 1..drain_end { + let lower = self.ranges[i - 1].upper().increment(); + let upper = self.ranges[i].lower().decrement(); + self.ranges.push(I::create(lower, upper)); + } + if self.ranges[drain_end - 1].upper() < I::Bound::max_value() { + let lower = self.ranges[drain_end - 1].upper().increment(); + self.ranges.push(I::create(lower, I::Bound::max_value())); + } + self.ranges.drain(..drain_end); + } + + /// Converts this set into a canonical ordering. + fn canonicalize(&mut self) { + if self.is_canonical() { + return; + } + self.ranges.sort(); + assert!(!self.ranges.is_empty()); + + // Is there a way to do this in-place with constant memory? I couldn't + // figure out a way to do it. So just append the canonicalization to + // the end of this range, and then drain it before we're done. + let drain_end = self.ranges.len(); + for oldi in 0..drain_end { + // If we've added at least one new range, then check if we can + // merge this range in the previously added range. + if self.ranges.len() > drain_end { + let (last, rest) = self.ranges.split_last_mut().unwrap(); + if let Some(union) = last.union(&rest[oldi]) { + *last = union; + continue; + } + } + let range = self.ranges[oldi]; + self.ranges.push(range); + } + self.ranges.drain(..drain_end); + } + + /// Returns true if and only if this class is in a canonical ordering. + fn is_canonical(&self) -> bool { + for pair in self.ranges.windows(2) { + if pair[0] >= pair[1] { + return false; + } + if pair[0].is_contiguous(&pair[1]) { + return false; + } + } + true + } +} + +/// An iterator over intervals. +#[derive(Debug)] +pub struct IntervalSetIter<'a, I: 'a>(slice::Iter<'a, I>); + +impl<'a, I> Iterator for IntervalSetIter<'a, I> { + type Item = &'a I; + + fn next(&mut self) -> Option<&'a I> { + self.0.next() + } +} + +pub trait Interval: + Clone + Copy + Debug + Default + Eq + PartialEq + PartialOrd + Ord +{ + type Bound: Bound; + + fn lower(&self) -> Self::Bound; + fn upper(&self) -> Self::Bound; + fn set_lower(&mut self, bound: Self::Bound); + fn set_upper(&mut self, bound: Self::Bound); + fn case_fold_simple(&self, intervals: &mut Vec<Self>); + + /// Create a new interval. + fn create(lower: Self::Bound, upper: Self::Bound) -> Self { + let mut int = Self::default(); + if lower <= upper { + int.set_lower(lower); + int.set_upper(upper); + } else { + int.set_lower(upper); + int.set_upper(lower); + } + int + } + + /// Union the given overlapping range into this range. + /// + /// If the two ranges aren't contiguous, then this returns `None`. + fn union(&self, other: &Self) -> Option<Self> { + if !self.is_contiguous(other) { + return None; + } + let lower = cmp::min(self.lower(), other.lower()); + let upper = cmp::max(self.upper(), other.upper()); + Some(Self::create(lower, upper)) + } + + /// Intersect this range with the given range and return the result. + /// + /// If the intersection is empty, then this returns `None`. + fn intersect(&self, other: &Self) -> Option<Self> { + let lower = cmp::max(self.lower(), other.lower()); + let upper = cmp::min(self.upper(), other.upper()); + if lower <= upper { + Some(Self::create(lower, upper)) + } else { + None + } + } + + /// Subtract the given range from this range and return the resulting + /// ranges. + /// + /// If subtraction would result in an empty range, then no ranges are + /// returned. + fn difference(&self, other: &Self) -> (Option<Self>, Option<Self>) { + if self.is_subset(other) { + return (None, None); + } + if self.is_intersection_empty(other) { + return (Some(self.clone()), None); + } + let add_lower = other.lower() > self.lower(); + let add_upper = other.upper() < self.upper(); + // We know this because !self.is_subset(other) and the ranges have + // a non-empty intersection. + assert!(add_lower || add_upper); + let mut ret = (None, None); + if add_lower { + let upper = other.lower().decrement(); + ret.0 = Some(Self::create(self.lower(), upper)); + } + if add_upper { + let lower = other.upper().increment(); + let range = Self::create(lower, self.upper()); + if ret.0.is_none() { + ret.0 = Some(range); + } else { + ret.1 = Some(range); + } + } + ret + } + + /// Compute the symmetric difference the given range from this range. This + /// returns the union of the two ranges minus its intersection. + fn symmetric_difference( + &self, + other: &Self, + ) -> (Option<Self>, Option<Self>) { + let union = match self.union(other) { + None => return (Some(self.clone()), Some(other.clone())), + Some(union) => union, + }; + let intersection = match self.intersect(other) { + None => return (Some(self.clone()), Some(other.clone())), + Some(intersection) => intersection, + }; + union.difference(&intersection) + } + + /// Returns true if and only if the two ranges are contiguous. Two ranges + /// are contiguous if and only if the ranges are either overlapping or + /// adjacent. + fn is_contiguous(&self, other: &Self) -> bool { + let lower1 = self.lower().as_u32(); + let upper1 = self.upper().as_u32(); + let lower2 = other.lower().as_u32(); + let upper2 = other.upper().as_u32(); + cmp::max(lower1, lower2) <= cmp::min(upper1, upper2).saturating_add(1) + } + + /// Returns true if and only if the intersection of this range and the + /// other range is empty. + fn is_intersection_empty(&self, other: &Self) -> bool { + let (lower1, upper1) = (self.lower(), self.upper()); + let (lower2, upper2) = (other.lower(), other.upper()); + cmp::max(lower1, lower2) > cmp::min(upper1, upper2) + } + + /// Returns true if and only if this range is a subset of the other range. + fn is_subset(&self, other: &Self) -> bool { + let (lower1, upper1) = (self.lower(), self.upper()); + let (lower2, upper2) = (other.lower(), other.upper()); + (lower2 <= lower1 && lower1 <= upper2) + && (lower2 <= upper1 && upper1 <= upper2) + } +} + +pub trait Bound: Copy + Clone + Debug + Eq + PartialEq + PartialOrd + Ord { + fn min_value() -> Self; + fn max_value() -> Self; + fn as_u32(self) -> u32; + fn increment(self) -> Self; + fn decrement(self) -> Self; +} + +impl Bound for u8 { + fn min_value() -> Self { u8::MIN } + fn max_value() -> Self { u8::MAX } + fn as_u32(self) -> u32 { self as u32 } + fn increment(self) -> Self { self.checked_add(1).unwrap() } + fn decrement(self) -> Self { self.checked_sub(1).unwrap() } +} + +impl Bound for char { + fn min_value() -> Self { '\x00' } + fn max_value() -> Self { '\u{10FFFF}' } + fn as_u32(self) -> u32 { self as u32 } + + fn increment(self) -> Self { + match self { + '\u{D7FF}' => '\u{E000}', + c => char::from_u32((c as u32).checked_add(1).unwrap()).unwrap(), + } + } + + fn decrement(self) -> Self { + match self { + '\u{E000}' => '\u{D7FF}', + c => char::from_u32((c as u32).checked_sub(1).unwrap()).unwrap(), + } + } +} + +// Tests for interval sets are written in src/hir.rs against the public API. diff --git a/regex-syntax/src/hir/literal/mod.rs b/regex-syntax/src/hir/literal/mod.rs new file mode 100644 index 000000000..b7d9c1db2 --- /dev/null +++ b/regex-syntax/src/hir/literal/mod.rs @@ -0,0 +1,1551 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Provides routines for extracting literal prefixes and suffixes from an `Hir`. +*/ + +use std::cmp; +use std::fmt; +use std::iter; +use std::mem; +use std::ops; + +use hir::{self, Hir, HirKind}; + +/// A set of literal byte strings extracted from a regular expression. +/// +/// Every member of the set is a `Literal`, which is represented by a +/// `Vec<u8>`. (Notably, it may contain invalid UTF-8.) Every member is +/// said to be either *complete* or *cut*. A complete literal means that +/// it extends until the beginning (or end) of the regular expression. In +/// some circumstances, this can be used to indicate a match in the regular +/// expression. +/// +/// A key aspect of literal extraction is knowing when to stop. It is not +/// feasible to blindly extract all literals from a regular expression, even if +/// there are finitely many. For example, the regular expression `[0-9]{10}` +/// has `10^10` distinct literals. For this reason, literal extraction is +/// bounded to some low number by default using heuristics, but the limits can +/// be tweaked. +/// +/// **WARNING**: Literal extraction uses stack space proportional to the size +/// of the `Hir` expression. At some point, this drawback will be eliminated. +/// To protect yourself, set a reasonable +/// [`nest_limit` on your `Parser`](../../struct.ParserBuilder.html#method.nest_limit). +/// This is done for you by default. +#[derive(Clone, Eq, PartialEq)] +pub struct Literals { + lits: Vec<Literal>, + limit_size: usize, + limit_class: usize, +} + +/// A single member of a set of literals extracted from a regular expression. +/// +/// This type has `Deref` and `DerefMut` impls to `Vec<u8>` so that all slice +/// and `Vec` operations are available. +#[derive(Clone, Eq, Ord)] +pub struct Literal { + v: Vec<u8>, + cut: bool, +} + +impl Literals { + /// Returns a new empty set of literals using default limits. + pub fn empty() -> Literals { + Literals { + lits: vec![], + limit_size: 250, + limit_class: 10, + } + } + + /// Returns a set of literal prefixes extracted from the given `Hir`. + pub fn prefixes(expr: &Hir) -> Literals { + let mut lits = Literals::empty(); + lits.union_prefixes(expr); + lits + } + + /// Returns a set of literal suffixes extracted from the given `Hir`. + pub fn suffixes(expr: &Hir) -> Literals { + let mut lits = Literals::empty(); + lits.union_suffixes(expr); + lits + } + + /// Get the approximate size limit (in bytes) of this set. + pub fn limit_size(&self) -> usize { + self.limit_size + } + + /// Set the approximate size limit (in bytes) of this set. + /// + /// If extracting a literal would put the set over this limit, then + /// extraction stops. + /// + /// The new limits will only apply to additions to this set. Existing + /// members remain unchanged, even if the set exceeds the new limit. + pub fn set_limit_size(&mut self, size: usize) -> &mut Literals { + self.limit_size = size; + self + } + + /// Get the character class size limit for this set. + pub fn limit_class(&self) -> usize { + self.limit_class + } + + /// Limits the size of character(or byte) classes considered. + /// + /// A value of `0` prevents all character classes from being considered. + /// + /// This limit also applies to case insensitive literals, since each + /// character in the case insensitive literal is converted to a class, and + /// then case folded. + /// + /// The new limits will only apply to additions to this set. Existing + /// members remain unchanged, even if the set exceeds the new limit. + pub fn set_limit_class(&mut self, size: usize) -> &mut Literals { + self.limit_class = size; + self + } + + /// Returns the set of literals as a slice. Its order is unspecified. + pub fn literals(&self) -> &[Literal] { + &self.lits + } + + /// Returns the length of the smallest literal. + /// + /// Returns None is there are no literals in the set. + pub fn min_len(&self) -> Option<usize> { + let mut min = None; + for lit in &self.lits { + match min { + None => min = Some(lit.len()), + Some(m) if lit.len() < m => min = Some(lit.len()), + _ => {} + } + } + min + } + + /// Returns true if all members in this set are complete. + pub fn all_complete(&self) -> bool { + !self.lits.is_empty() && self.lits.iter().all(|l| !l.is_cut()) + } + + /// Returns true if any member in this set is complete. + pub fn any_complete(&self) -> bool { + self.lits.iter().any(|lit| !lit.is_cut()) + } + + /// Returns true if this set contains an empty literal. + pub fn contains_empty(&self) -> bool { + self.lits.iter().any(|lit| lit.is_empty()) + } + + /// Returns true if this set is empty or if all of its members is empty. + pub fn is_empty(&self) -> bool { + self.lits.is_empty() || self.lits.iter().all(|lit| lit.is_empty()) + } + + /// Returns a new empty set of literals using this set's limits. + pub fn to_empty(&self) -> Literals { + let mut lits = Literals::empty(); + lits.set_limit_size(self.limit_size) + .set_limit_class(self.limit_class); + lits + } + + /// Returns the longest common prefix of all members in this set. + pub fn longest_common_prefix(&self) -> &[u8] { + if self.is_empty() { + return &[]; + } + let lit0 = &*self.lits[0]; + let mut len = lit0.len(); + for lit in &self.lits[1..] { + len = cmp::min( + len, + lit.iter() + .zip(lit0) + .take_while(|&(a, b)| a == b) + .count()); + } + &self.lits[0][..len] + } + + /// Returns the longest common suffix of all members in this set. + pub fn longest_common_suffix(&self) -> &[u8] { + if self.is_empty() { + return &[]; + } + let lit0 = &*self.lits[0]; + let mut len = lit0.len(); + for lit in &self.lits[1..] { + len = cmp::min( + len, + lit.iter() + .rev() + .zip(lit0.iter().rev()) + .take_while(|&(a, b)| a == b) + .count()); + } + &self.lits[0][self.lits[0].len() - len..] + } + + /// Returns a new set of literals with the given number of bytes trimmed + /// from the suffix of each literal. + /// + /// If any literal would be cut out completely by trimming, then None is + /// returned. + /// + /// Any duplicates that are created as a result of this transformation are + /// removed. + pub fn trim_suffix(&self, num_bytes: usize) -> Option<Literals> { + if self.min_len().map(|len| len <= num_bytes).unwrap_or(true) { + return None; + } + let mut new = self.to_empty(); + for mut lit in self.lits.iter().cloned() { + let new_len = lit.len() - num_bytes; + lit.truncate(new_len); + lit.cut(); + new.lits.push(lit); + } + new.lits.sort(); + new.lits.dedup(); + Some(new) + } + + /// Returns a new set of prefixes of this set of literals that are + /// guaranteed to be unambiguous. + /// + /// Any substring match with a member of the set is returned is guaranteed + /// to never overlap with a substring match of another member of the set + /// at the same starting position. + /// + /// Given any two members of the returned set, neither is a substring of + /// the other. + pub fn unambiguous_prefixes(&self) -> Literals { + if self.lits.is_empty() { + return self.to_empty(); + } + let mut old: Vec<Literal> = self.lits.iter().cloned().collect(); + let mut new = self.to_empty(); + 'OUTER: + while let Some(mut candidate) = old.pop() { + if candidate.is_empty() { + continue; + } + if new.lits.is_empty() { + new.lits.push(candidate); + continue; + } + for lit2 in &mut new.lits { + if lit2.is_empty() { + continue; + } + if &candidate == lit2 { + // If the literal is already in the set, then we can + // just drop it. But make sure that cut literals are + // infectious! + candidate.cut = candidate.cut || lit2.cut; + lit2.cut = candidate.cut; + continue 'OUTER; + } + if candidate.len() < lit2.len() { + if let Some(i) = position(&candidate, &lit2) { + candidate.cut(); + let mut lit3 = lit2.clone(); + lit3.truncate(i); + lit3.cut(); + old.push(lit3); + lit2.clear(); + } + } else { + if let Some(i) = position(&lit2, &candidate) { + lit2.cut(); + let mut new_candidate = candidate.clone(); + new_candidate.truncate(i); + new_candidate.cut(); + old.push(new_candidate); + candidate.clear(); + } + } + // Oops, the candidate is already represented in the set. + if candidate.is_empty() { + continue 'OUTER; + } + } + new.lits.push(candidate); + } + new.lits.retain(|lit| !lit.is_empty()); + new.lits.sort(); + new.lits.dedup(); + new + } + + /// Returns a new set of suffixes of this set of literals that are + /// guaranteed to be unambiguous. + /// + /// Any substring match with a member of the set is returned is guaranteed + /// to never overlap with a substring match of another member of the set + /// at the same ending position. + /// + /// Given any two members of the returned set, neither is a substring of + /// the other. + pub fn unambiguous_suffixes(&self) -> Literals { + // This is a touch wasteful... + let mut lits = self.clone(); + lits.reverse(); + let mut unamb = lits.unambiguous_prefixes(); + unamb.reverse(); + unamb + } + + /// Unions the prefixes from the given expression to this set. + /// + /// If prefixes could not be added (for example, this set would exceed its + /// size limits or the set of prefixes from `expr` includes the empty + /// string), then false is returned. + /// + /// Note that prefix literals extracted from `expr` are said to be complete + /// if and only if the literal extends from the beginning of `expr` to the + /// end of `expr`. + pub fn union_prefixes(&mut self, expr: &Hir) -> bool { + let mut lits = self.to_empty(); + prefixes(expr, &mut lits); + !lits.is_empty() && !lits.contains_empty() && self.union(lits) + } + + /// Unions the suffixes from the given expression to this set. + /// + /// If suffixes could not be added (for example, this set would exceed its + /// size limits or the set of suffixes from `expr` includes the empty + /// string), then false is returned. + /// + /// Note that prefix literals extracted from `expr` are said to be complete + /// if and only if the literal extends from the end of `expr` to the + /// beginning of `expr`. + pub fn union_suffixes(&mut self, expr: &Hir) -> bool { + let mut lits = self.to_empty(); + suffixes(expr, &mut lits); + lits.reverse(); + !lits.is_empty() && !lits.contains_empty() && self.union(lits) + } + + /// Unions this set with another set. + /// + /// If the union would cause the set to exceed its limits, then the union + /// is skipped and it returns false. Otherwise, if the union succeeds, it + /// returns true. + pub fn union(&mut self, lits: Literals) -> bool { + if self.num_bytes() + lits.num_bytes() > self.limit_size { + return false; + } + if lits.is_empty() { + self.lits.push(Literal::empty()); + } else { + self.lits.extend(lits.lits); + } + true + } + + /// Extends this set with another set. + /// + /// The set of literals is extended via a cross product. + /// + /// If a cross product would cause this set to exceed its limits, then the + /// cross product is skipped and it returns false. Otherwise, if the cross + /// product succeeds, it returns true. + pub fn cross_product(&mut self, lits: &Literals) -> bool { + if lits.is_empty() { + return true; + } + // Check that we make sure we stay in our limits. + let mut size_after; + if self.is_empty() || !self.any_complete() { + size_after = self.num_bytes(); + for lits_lit in lits.literals() { + size_after += lits_lit.len(); + } + } else { + size_after = self.lits.iter().fold(0, |accum, lit| { + accum + if lit.is_cut() { lit.len() } else { 0 } + }); + for lits_lit in lits.literals() { + for self_lit in self.literals() { + if !self_lit.is_cut() { + size_after += self_lit.len() + lits_lit.len(); + } + } + } + } + if size_after > self.limit_size { + return false; + } + + let mut base = self.remove_complete(); + if base.is_empty() { + base = vec![Literal::empty()]; + } + for lits_lit in lits.literals() { + for mut self_lit in base.clone() { + self_lit.extend(&**lits_lit); + self_lit.cut = lits_lit.cut; + self.lits.push(self_lit); + } + } + true + } + + /// Extends each literal in this set with the bytes given. + /// + /// If the set is empty, then the given literal is added to the set. + /// + /// If adding any number of bytes to all members of this set causes a limit + /// to be exceeded, then no bytes are added and false is returned. If a + /// prefix of `bytes` can be fit into this set, then it is used and all + /// resulting literals are cut. + pub fn cross_add(&mut self, bytes: &[u8]) -> bool { + // N.B. This could be implemented by simply calling cross_product with + // a literal set containing just `bytes`, but we can be smarter about + // taking shorter prefixes of `bytes` if they'll fit. + if bytes.is_empty() { + return true; + } + if self.lits.is_empty() { + let i = cmp::min(self.limit_size, bytes.len()); + self.lits.push(Literal::new(bytes[..i].to_owned())); + self.lits[0].cut = i < bytes.len(); + return !self.lits[0].is_cut(); + } + let size = self.num_bytes(); + if size + self.lits.len() >= self.limit_size { + return false; + } + let mut i = 1; + while size + (i * self.lits.len()) <= self.limit_size + && i < bytes.len() { + i += 1; + } + for lit in &mut self.lits { + if !lit.is_cut() { + lit.extend(&bytes[..i]); + if i < bytes.len() { + lit.cut(); + } + } + } + true + } + + /// Adds the given literal to this set. + /// + /// Returns false if adding this literal would cause the class to be too + /// big. + pub fn add(&mut self, lit: Literal) -> bool { + if self.num_bytes() + lit.len() > self.limit_size { + return false; + } + self.lits.push(lit); + true + } + + /// Extends each literal in this set with the character class given. + /// + /// Returns false if the character class was too big to add. + pub fn add_char_class(&mut self, cls: &hir::ClassUnicode) -> bool { + self._add_char_class(cls, false) + } + + /// Extends each literal in this set with the character class given, + /// writing the bytes of each character in reverse. + /// + /// Returns false if the character class was too big to add. + fn add_char_class_reverse(&mut self, cls: &hir::ClassUnicode) -> bool { + self._add_char_class(cls, true) + } + + fn _add_char_class( + &mut self, + cls: &hir::ClassUnicode, + reverse: bool, + ) -> bool { + use std::char; + + if self.class_exceeds_limits(cls_char_count(cls)) { + return false; + } + let mut base = self.remove_complete(); + if base.is_empty() { + base = vec![Literal::empty()]; + } + for r in cls.iter() { + let (s, e) = (r.start as u32, r.end as u32 + 1); + for c in (s..e).filter_map(char::from_u32) { + for mut lit in base.clone() { + let mut bytes = c.to_string().into_bytes(); + if reverse { + bytes.reverse(); + } + lit.extend(&bytes); + self.lits.push(lit); + } + } + } + true + } + + /// Extends each literal in this set with the byte class given. + /// + /// Returns false if the byte class was too big to add. + pub fn add_byte_class(&mut self, cls: &hir::ClassBytes) -> bool { + if self.class_exceeds_limits(cls_byte_count(cls)) { + return false; + } + let mut base = self.remove_complete(); + if base.is_empty() { + base = vec![Literal::empty()]; + } + for r in cls.iter() { + let (s, e) = (r.start as u32, r.end as u32 + 1); + for b in (s..e).map(|b| b as u8) { + for mut lit in base.clone() { + lit.push(b); + self.lits.push(lit); + } + } + } + true + } + + /// Cuts every member of this set. When a member is cut, it can never + /// be extended. + pub fn cut(&mut self) { + for lit in &mut self.lits { + lit.cut(); + } + } + + /// Reverses all members in place. + pub fn reverse(&mut self) { + for lit in &mut self.lits { + lit.reverse(); + } + } + + /// Clears this set of all members. + pub fn clear(&mut self) { + self.lits.clear(); + } + + /// Pops all complete literals out of this set. + fn remove_complete(&mut self) -> Vec<Literal> { + let mut base = vec![]; + for lit in mem::replace(&mut self.lits, vec![]) { + if lit.is_cut() { + self.lits.push(lit); + } else { + base.push(lit); + } + } + base + } + + /// Returns the total number of bytes in this set. + fn num_bytes(&self) -> usize { + self.lits.iter().fold(0, |accum, lit| accum + lit.len()) + } + + /// Returns true if a character class with the given size would cause this + /// set to exceed its limits. + /// + /// The size given should correspond to the number of items in the class. + fn class_exceeds_limits(&self, size: usize) -> bool { + if size > self.limit_class { + return true; + } + // This is an approximation since codepoints in a char class can encode + // to 1-4 bytes. + let new_byte_count = + if self.lits.is_empty() { + size + } else { + self.lits + .iter() + .fold(0, |accum, lit| { + accum + if lit.is_cut() { + // If the literal is cut, then we'll never add + // anything to it, so don't count it. + 0 + } else { + (lit.len() + 1) * size + } + }) + }; + new_byte_count > self.limit_size + } +} + +fn prefixes(expr: &Hir, lits: &mut Literals) { + match *expr.kind() { + HirKind::Literal(hir::Literal::Unicode(c)) => { + let mut buf = [0; 4]; + lits.cross_add(c.encode_utf8(&mut buf).as_bytes()); + } + HirKind::Literal(hir::Literal::Byte(b)) => { + lits.cross_add(&[b]); + } + HirKind::Class(hir::Class::Unicode(ref cls)) => { + if !lits.add_char_class(cls) { + lits.cut(); + } + } + HirKind::Class(hir::Class::Bytes(ref cls)) => { + if !lits.add_byte_class(cls) { + lits.cut(); + } + } + HirKind::Group(hir::Group { ref hir, .. }) => { + prefixes(&**hir, lits); + } + HirKind::Repetition(ref x) => { + match x.kind { + hir::RepetitionKind::ZeroOrOne => { + repeat_zero_or_one_literals(&x.hir, lits, prefixes); + } + hir::RepetitionKind::ZeroOrMore => { + repeat_zero_or_more_literals(&x.hir, lits, prefixes); + } + hir::RepetitionKind::OneOrMore => { + repeat_one_or_more_literals(&x.hir, lits, prefixes); + } + hir::RepetitionKind::Range(ref rng) => { + let (min, max) = match *rng { + hir::RepetitionRange::Exactly(m) => { + (m, Some(m)) + } + hir::RepetitionRange::AtLeast(m) => { + (m, None) + } + hir::RepetitionRange::Bounded(m, n) => { + (m, Some(n)) + } + }; + repeat_range_literals( + &x.hir, min, max, x.greedy, lits, prefixes) + } + } + } + HirKind::Concat(ref es) if es.is_empty() => {} + HirKind::Concat(ref es) if es.len() == 1 => prefixes(&es[0], lits), + HirKind::Concat(ref es) => { + for e in es { + if let HirKind::Anchor(hir::Anchor::StartText) = *e.kind() { + if !lits.is_empty() { + lits.cut(); + break; + } + lits.add(Literal::empty()); + continue; + } + let mut lits2 = lits.to_empty(); + prefixes(e, &mut lits2); + if !lits.cross_product(&lits2) || !lits2.any_complete() { + // If this expression couldn't yield any literal that + // could be extended, then we need to quit. Since we're + // short-circuiting, we also need to freeze every member. + lits.cut(); + break; + } + } + } + HirKind::Alternation(ref es) => { + alternate_literals(es, lits, prefixes); + } + _ => lits.cut(), + } +} + +fn suffixes(expr: &Hir, lits: &mut Literals) { + match *expr.kind() { + HirKind::Literal(hir::Literal::Unicode(c)) => { + let mut buf = [0u8; 4]; + let i = c.encode_utf8(&mut buf).len(); + let mut buf = &mut buf[..i]; + buf.reverse(); + lits.cross_add(buf); + } + HirKind::Literal(hir::Literal::Byte(b)) => { + lits.cross_add(&[b]); + } + HirKind::Class(hir::Class::Unicode(ref cls)) => { + if !lits.add_char_class_reverse(cls) { + lits.cut(); + } + } + HirKind::Class(hir::Class::Bytes(ref cls)) => { + if !lits.add_byte_class(cls) { + lits.cut(); + } + } + HirKind::Group(hir::Group { ref hir, .. }) => { + suffixes(&**hir, lits); + } + HirKind::Repetition(ref x) => { + match x.kind { + hir::RepetitionKind::ZeroOrOne => { + repeat_zero_or_one_literals(&x.hir, lits, suffixes); + } + hir::RepetitionKind::ZeroOrMore => { + repeat_zero_or_more_literals(&x.hir, lits, suffixes); + } + hir::RepetitionKind::OneOrMore => { + repeat_one_or_more_literals(&x.hir, lits, suffixes); + } + hir::RepetitionKind::Range(ref rng) => { + let (min, max) = match *rng { + hir::RepetitionRange::Exactly(m) => { + (m, Some(m)) + } + hir::RepetitionRange::AtLeast(m) => { + (m, None) + } + hir::RepetitionRange::Bounded(m, n) => { + (m, Some(n)) + } + }; + repeat_range_literals( + &x.hir, min, max, x.greedy, lits, suffixes) + } + } + } + HirKind::Concat(ref es) if es.is_empty() => {} + HirKind::Concat(ref es) if es.len() == 1 => suffixes(&es[0], lits), + HirKind::Concat(ref es) => { + for e in es.iter().rev() { + if let HirKind::Anchor(hir::Anchor::EndText) = *e.kind() { + if !lits.is_empty() { + lits.cut(); + break; + } + lits.add(Literal::empty()); + continue; + } + let mut lits2 = lits.to_empty(); + suffixes(e, &mut lits2); + if !lits.cross_product(&lits2) || !lits2.any_complete() { + // If this expression couldn't yield any literal that + // could be extended, then we need to quit. Since we're + // short-circuiting, we also need to freeze every member. + lits.cut(); + break; + } + } + } + HirKind::Alternation(ref es) => { + alternate_literals(es, lits, suffixes); + } + _ => lits.cut(), + } +} + +fn repeat_zero_or_one_literals<F: FnMut(&Hir, &mut Literals)>( + e: &Hir, + lits: &mut Literals, + mut f: F, +) { + let (mut lits2, mut lits3) = (lits.clone(), lits.to_empty()); + lits3.set_limit_size(lits.limit_size() / 2); + f(e, &mut lits3); + + if lits3.is_empty() || !lits2.cross_product(&lits3) { + lits.cut(); + return; + } + lits2.add(Literal::empty()); + if !lits.union(lits2) { + lits.cut(); + } +} + +fn repeat_zero_or_more_literals<F: FnMut(&Hir, &mut Literals)>( + e: &Hir, + lits: &mut Literals, + mut f: F, +) { + let (mut lits2, mut lits3) = (lits.clone(), lits.to_empty()); + lits3.set_limit_size(lits.limit_size() / 2); + f(e, &mut lits3); + + if lits3.is_empty() || !lits2.cross_product(&lits3) { + lits.cut(); + return; + } + lits2.cut(); + lits2.add(Literal::empty()); + if !lits.union(lits2) { + lits.cut(); + } +} + +fn repeat_one_or_more_literals<F: FnMut(&Hir, &mut Literals)>( + e: &Hir, + lits: &mut Literals, + mut f: F, +) { + f(e, lits); + lits.cut(); +} + +fn repeat_range_literals<F: FnMut(&Hir, &mut Literals)>( + e: &Hir, + min: u32, + max: Option<u32>, + greedy: bool, + lits: &mut Literals, + mut f: F, +) { + if min == 0 { + // This is a bit conservative. If `max` is set, then we could + // treat this as a finite set of alternations. For now, we + // just treat it as `e*`. + f(&Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::ZeroOrMore, + greedy: greedy, + hir: Box::new(e.clone()), + }), lits); + } else { + if min > 0 { + let n = cmp::min(lits.limit_size, min as usize); + let es = iter::repeat(e.clone()).take(n).collect(); + f(&Hir::concat(es), lits); + if n < min as usize || lits.contains_empty() { + lits.cut(); + } + } + if max.map_or(true, |max| min < max) { + lits.cut(); + } + } +} + +fn alternate_literals<F: FnMut(&Hir, &mut Literals)>( + es: &[Hir], + lits: &mut Literals, + mut f: F, +) { + let mut lits2 = lits.to_empty(); + for e in es { + let mut lits3 = lits.to_empty(); + lits3.set_limit_size(lits.limit_size() / 5); + f(e, &mut lits3); + if lits3.is_empty() || !lits2.union(lits3) { + // If we couldn't find suffixes for *any* of the + // alternates, then the entire alternation has to be thrown + // away and any existing members must be frozen. Similarly, + // if the union couldn't complete, stop and freeze. + lits.cut(); + return; + } + } + if !lits.cross_product(&lits2) { + lits.cut(); + } +} + +impl fmt::Debug for Literals { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Literals") + .field("lits", &self.lits) + .field("limit_size", &self.limit_size) + .field("limit_class", &self.limit_class) + .finish() + } +} + +impl Literal { + /// Returns a new complete literal with the bytes given. + pub fn new(bytes: Vec<u8>) -> Literal { + Literal { v: bytes, cut: false } + } + + /// Returns a new complete empty literal. + pub fn empty() -> Literal { + Literal { v: vec![], cut: false } + } + + /// Returns true if this literal was "cut." + pub fn is_cut(&self) -> bool { + self.cut + } + + /// Cuts this literal. + pub fn cut(&mut self) { + self.cut = true; + } +} + +impl PartialEq for Literal { + fn eq(&self, other: &Literal) -> bool { + self.v == other.v + } +} + +impl PartialOrd for Literal { + fn partial_cmp(&self, other: &Literal) -> Option<cmp::Ordering> { + self.v.partial_cmp(&other.v) + } +} + +impl fmt::Debug for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_cut() { + write!(f, "Cut({})", escape_unicode(&self.v)) + } else { + write!(f, "Complete({})", escape_unicode(&self.v)) + } + } +} + +impl AsRef<[u8]> for Literal { + fn as_ref(&self) -> &[u8] { &self.v } +} + +impl ops::Deref for Literal { + type Target = Vec<u8>; + fn deref(&self) -> &Vec<u8> { &self.v } +} + +impl ops::DerefMut for Literal { + fn deref_mut(&mut self) -> &mut Vec<u8> { &mut self.v } +} + +fn position(needle: &[u8], mut haystack: &[u8]) -> Option<usize> { + let mut i = 0; + while haystack.len() >= needle.len() { + if needle == &haystack[..needle.len()] { + return Some(i); + } + i += 1; + haystack = &haystack[1..]; + } + None +} + +fn escape_unicode(bytes: &[u8]) -> String { + let show = match ::std::str::from_utf8(bytes) { + Ok(v) => v.to_string(), + Err(_) => escape_bytes(bytes), + }; + let mut space_escaped = String::new(); + for c in show.chars() { + if c.is_whitespace() { + let escaped = if c as u32 <= 0x7F { + escape_byte(c as u8) + } else { + if c as u32 <= 0xFFFF { + format!(r"\u{{{:04x}}}", c as u32) + } else { + format!(r"\U{{{:08x}}}", c as u32) + } + }; + space_escaped.push_str(&escaped); + } else { + space_escaped.push(c); + } + } + space_escaped +} + +fn escape_bytes(bytes: &[u8]) -> String { + let mut s = String::new(); + for &b in bytes { + s.push_str(&escape_byte(b)); + } + s +} + +fn escape_byte(byte: u8) -> String { + use std::ascii::escape_default; + + let escaped: Vec<u8> = escape_default(byte).collect(); + String::from_utf8_lossy(&escaped).into_owned() +} + +fn cls_char_count(cls: &hir::ClassUnicode) -> usize { + cls.iter() + .map(|&r| 1 + (r.end as u32) - (r.start as u32)) + .sum::<u32>() as usize +} + +fn cls_byte_count(cls: &hir::ClassBytes) -> usize { + cls.iter() + .map(|&r| 1 + (r.end as u32) - (r.start as u32)) + .sum::<u32>() as usize +} + +#[cfg(test)] +mod tests { + use std::fmt; + + use ParserBuilder; + use hir::Hir; + use super::{Literals, Literal, escape_bytes}; + + // To make test failures easier to read. + #[derive(Debug, Eq, PartialEq)] + struct Bytes(Vec<ULiteral>); + #[derive(Debug, Eq, PartialEq)] + struct Unicode(Vec<ULiteral>); + + fn escape_lits(blits: &[Literal]) -> Vec<ULiteral> { + let mut ulits = vec![]; + for blit in blits { + ulits.push(ULiteral { + v: escape_bytes(&blit), + cut: blit.is_cut(), + }); + } + ulits + } + + fn create_lits<I: IntoIterator<Item=Literal>>(it: I) -> Literals { + Literals { + lits: it.into_iter().collect(), + limit_size: 0, + limit_class: 0, + } + } + + // Needs to be pub for 1.3? + #[derive(Clone, Eq, PartialEq)] + pub struct ULiteral { + v: String, + cut: bool, + } + + impl ULiteral { + fn is_cut(&self) -> bool { self.cut } + } + + impl fmt::Debug for ULiteral { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_cut() { + write!(f, "Cut({})", self.v) + } else { + write!(f, "Complete({})", self.v) + } + } + } + + impl PartialEq<Literal> for ULiteral { + fn eq(&self, other: &Literal) -> bool { + self.v.as_bytes() == &*other.v && self.is_cut() == other.is_cut() + } + } + + impl PartialEq<ULiteral> for Literal { + fn eq(&self, other: &ULiteral) -> bool { + &*self.v == other.v.as_bytes() && self.is_cut() == other.is_cut() + } + } + + #[allow(non_snake_case)] + fn C(s: &'static str) -> ULiteral { + ULiteral { v: s.to_owned(), cut: true } + } + #[allow(non_snake_case)] + fn M(s: &'static str) -> ULiteral { + ULiteral { v: s.to_owned(), cut: false } + } + + fn prefixes(lits: &mut Literals, expr: &Hir) { + lits.union_prefixes(expr); + } + + fn suffixes(lits: &mut Literals, expr: &Hir) { + lits.union_suffixes(expr); + } + + macro_rules! assert_lit_eq { + ($which:ident, $got_lits:expr, $($expected_lit:expr),*) => {{ + let expected: Vec<ULiteral> = vec![$($expected_lit),*]; + let lits = $got_lits; + assert_eq!( + $which(expected.clone()), + $which(escape_lits(lits.literals()))); + assert_eq!( + !expected.is_empty() && expected.iter().all(|l| !l.is_cut()), + lits.all_complete()); + assert_eq!( + expected.iter().any(|l| !l.is_cut()), + lits.any_complete()); + }}; + } + + macro_rules! test_lit { + ($name:ident, $which:ident, $re:expr) => { + test_lit!($name, $which, $re,); + }; + ($name:ident, $which:ident, $re:expr, $($lit:expr),*) => { + #[test] + fn $name() { + let expr = ParserBuilder::new() + .build() + .parse($re) + .unwrap(); + let lits = Literals::$which(&expr); + assert_lit_eq!(Unicode, lits, $($lit),*); + + let expr = ParserBuilder::new() + .allow_invalid_utf8(true) + .unicode(false) + .build() + .parse($re) + .unwrap(); + let lits = Literals::$which(&expr); + assert_lit_eq!(Bytes, lits, $($lit),*); + } + }; + } + + // ************************************************************************ + // Tests for prefix literal extraction. + // ************************************************************************ + + // Elementary tests. + test_lit!(pfx_one_lit1, prefixes, "a", M("a")); + test_lit!(pfx_one_lit2, prefixes, "abc", M("abc")); + test_lit!(pfx_one_lit3, prefixes, "(?u)☃", M("\\xe2\\x98\\x83")); + test_lit!(pfx_one_lit4, prefixes, "(?ui)☃", M("\\xe2\\x98\\x83")); + test_lit!(pfx_class1, prefixes, "[1-4]", + M("1"), M("2"), M("3"), M("4")); + test_lit!(pfx_class2, prefixes, "(?u)[☃Ⅰ]", + M("\\xe2\\x85\\xa0"), M("\\xe2\\x98\\x83")); + test_lit!(pfx_class3, prefixes, "(?ui)[☃Ⅰ]", + M("\\xe2\\x85\\xa0"), M("\\xe2\\x85\\xb0"), + M("\\xe2\\x98\\x83")); + test_lit!(pfx_one_lit_casei1, prefixes, "(?i)a", + M("A"), M("a")); + test_lit!(pfx_one_lit_casei2, prefixes, "(?i)abc", + M("ABC"), M("aBC"), M("AbC"), M("abC"), + M("ABc"), M("aBc"), M("Abc"), M("abc")); + test_lit!(pfx_group1, prefixes, "(a)", M("a")); + test_lit!(pfx_rep_zero_or_one1, prefixes, "a?"); + test_lit!(pfx_rep_zero_or_one2, prefixes, "(?:abc)?"); + test_lit!(pfx_rep_zero_or_more1, prefixes, "a*"); + test_lit!(pfx_rep_zero_or_more2, prefixes, "(?:abc)*"); + test_lit!(pfx_rep_one_or_more1, prefixes, "a+", C("a")); + test_lit!(pfx_rep_one_or_more2, prefixes, "(?:abc)+", C("abc")); + test_lit!(pfx_rep_nested_one_or_more, prefixes, "(?:a+)+", C("a")); + test_lit!(pfx_rep_range1, prefixes, "a{0}"); + test_lit!(pfx_rep_range2, prefixes, "a{0,}"); + test_lit!(pfx_rep_range3, prefixes, "a{0,1}"); + test_lit!(pfx_rep_range4, prefixes, "a{1}", M("a")); + test_lit!(pfx_rep_range5, prefixes, "a{2}", M("aa")); + test_lit!(pfx_rep_range6, prefixes, "a{1,2}", C("a")); + test_lit!(pfx_rep_range7, prefixes, "a{2,3}", C("aa")); + + // Test regexes with concatenations. + test_lit!(pfx_cat1, prefixes, "(?:a)(?:b)", M("ab")); + test_lit!(pfx_cat2, prefixes, "[ab]z", M("az"), M("bz")); + test_lit!(pfx_cat3, prefixes, "(?i)[ab]z", + M("AZ"), M("BZ"), M("aZ"), M("bZ"), + M("Az"), M("Bz"), M("az"), M("bz")); + test_lit!(pfx_cat4, prefixes, "[ab][yz]", + M("ay"), M("by"), M("az"), M("bz")); + test_lit!(pfx_cat5, prefixes, "a*b", C("a"), M("b")); + test_lit!(pfx_cat6, prefixes, "a*b*c", C("a"), C("b"), M("c")); + test_lit!(pfx_cat7, prefixes, "a*b*c+", C("a"), C("b"), C("c")); + test_lit!(pfx_cat8, prefixes, "a*b+c", C("a"), C("b")); + test_lit!(pfx_cat9, prefixes, "a*b+c*", C("a"), C("b")); + test_lit!(pfx_cat10, prefixes, "ab*", C("ab"), M("a")); + test_lit!(pfx_cat11, prefixes, "ab*c", C("ab"), M("ac")); + test_lit!(pfx_cat12, prefixes, "ab+", C("ab")); + test_lit!(pfx_cat13, prefixes, "ab+c", C("ab")); + test_lit!(pfx_cat14, prefixes, "a^", C("a")); + test_lit!(pfx_cat15, prefixes, "$a"); + test_lit!(pfx_cat16, prefixes, r"ab*c", C("ab"), M("ac")); + test_lit!(pfx_cat17, prefixes, r"ab+c", C("ab")); + test_lit!(pfx_cat18, prefixes, r"z*azb", C("z"), M("azb")); + test_lit!(pfx_cat19, prefixes, "a.z", C("a")); + + // Test regexes with alternations. + test_lit!(pfx_alt1, prefixes, "a|b", M("a"), M("b")); + test_lit!(pfx_alt2, prefixes, "[1-3]|b", M("1"), M("2"), M("3"), M("b")); + test_lit!(pfx_alt3, prefixes, "y(?:a|b)z", M("yaz"), M("ybz")); + test_lit!(pfx_alt4, prefixes, "a|b*"); + test_lit!(pfx_alt5, prefixes, "a|b+", M("a"), C("b")); + test_lit!(pfx_alt6, prefixes, "a|(?:b|c*)"); + test_lit!(pfx_alt7, prefixes, "(a|b)*c|(a|ab)*c", + C("a"), C("b"), M("c"), C("a"), C("ab"), M("c")); + test_lit!(pfx_alt8, prefixes, "a*b|c", C("a"), M("b"), M("c")); + + // Test regexes with empty assertions. + test_lit!(pfx_empty1, prefixes, "^a", M("a")); + test_lit!(pfx_empty2, prefixes, "a${2}", C("a")); + test_lit!(pfx_empty3, prefixes, "^abc", M("abc")); + test_lit!(pfx_empty4, prefixes, "(?:^abc)|(?:^z)", M("abc"), M("z")); + + // Make sure some curious regexes have no prefixes. + test_lit!(pfx_nothing1, prefixes, "."); + test_lit!(pfx_nothing2, prefixes, "(?s)."); + test_lit!(pfx_nothing3, prefixes, "^"); + test_lit!(pfx_nothing4, prefixes, "$"); + test_lit!(pfx_nothing6, prefixes, "(?m)$"); + test_lit!(pfx_nothing7, prefixes, r"\b"); + test_lit!(pfx_nothing8, prefixes, r"\B"); + + // Test a few regexes that defeat any prefix literal detection. + test_lit!(pfx_defeated1, prefixes, ".a"); + test_lit!(pfx_defeated2, prefixes, "(?s).a"); + test_lit!(pfx_defeated3, prefixes, "a*b*c*"); + test_lit!(pfx_defeated4, prefixes, "a|."); + test_lit!(pfx_defeated5, prefixes, ".|a"); + test_lit!(pfx_defeated6, prefixes, "a|^"); + test_lit!(pfx_defeated7, prefixes, ".(?:a(?:b)(?:c))"); + test_lit!(pfx_defeated8, prefixes, "$a"); + test_lit!(pfx_defeated9, prefixes, "(?m)$a"); + test_lit!(pfx_defeated10, prefixes, r"\ba"); + test_lit!(pfx_defeated11, prefixes, r"\Ba"); + test_lit!(pfx_defeated12, prefixes, "^*a"); + test_lit!(pfx_defeated13, prefixes, "^+a"); + + test_lit!( + pfx_crazy1, + prefixes, + r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", + C("Mo\\'am"), C("Mu\\'am"), C("Moam"), C("Muam")); + + // ************************************************************************ + // Tests for quiting prefix literal search. + // ************************************************************************ + + macro_rules! test_exhausted { + ($name:ident, $which:ident, $re:expr) => { + test_exhausted!($name, $which, $re,); + }; + ($name:ident, $which:ident, $re:expr, $($lit:expr),*) => { + #[test] + fn $name() { + let expr = ParserBuilder::new() + .build() + .parse($re) + .unwrap(); + let mut lits = Literals::empty(); + lits.set_limit_size(20).set_limit_class(10); + $which(&mut lits, &expr); + assert_lit_eq!(Unicode, lits, $($lit),*); + + let expr = ParserBuilder::new() + .allow_invalid_utf8(true) + .unicode(false) + .build() + .parse($re) + .unwrap(); + let mut lits = Literals::empty(); + lits.set_limit_size(20).set_limit_class(10); + $which(&mut lits, &expr); + assert_lit_eq!(Bytes, lits, $($lit),*); + } + }; + } + + // These test use a much lower limit than the default so that we can + // write test cases of reasonable size. + test_exhausted!(pfx_exhausted1, prefixes, "[a-z]"); + test_exhausted!(pfx_exhausted2, prefixes, "[a-z]*A"); + test_exhausted!(pfx_exhausted3, prefixes, "A[a-z]Z", C("A")); + test_exhausted!(pfx_exhausted4, prefixes, "(?i)foobar", + C("FO"), C("fO"), C("Fo"), C("fo")); + test_exhausted!(pfx_exhausted5, prefixes, "(?:ab){100}", + C("abababababababababab")); + test_exhausted!(pfx_exhausted6, prefixes, "(?:(?:ab){100})*cd", + C("ababababab"), M("cd")); + test_exhausted!(pfx_exhausted7, prefixes, "z(?:(?:ab){100})*cd", + C("zababababab"), M("zcd")); + test_exhausted!(pfx_exhausted8, prefixes, "aaaaaaaaaaaaaaaaaaaaz", + C("aaaaaaaaaaaaaaaaaaaa")); + + // ************************************************************************ + // Tests for suffix literal extraction. + // ************************************************************************ + + // Elementary tests. + test_lit!(sfx_one_lit1, suffixes, "a", M("a")); + test_lit!(sfx_one_lit2, suffixes, "abc", M("abc")); + test_lit!(sfx_one_lit3, suffixes, "(?u)☃", M("\\xe2\\x98\\x83")); + test_lit!(sfx_one_lit4, suffixes, "(?ui)☃", M("\\xe2\\x98\\x83")); + test_lit!(sfx_class1, suffixes, "[1-4]", + M("1"), M("2"), M("3"), M("4")); + test_lit!(sfx_class2, suffixes, "(?u)[☃Ⅰ]", + M("\\xe2\\x85\\xa0"), M("\\xe2\\x98\\x83")); + test_lit!(sfx_class3, suffixes, "(?ui)[☃Ⅰ]", + M("\\xe2\\x85\\xa0"), M("\\xe2\\x85\\xb0"), + M("\\xe2\\x98\\x83")); + test_lit!(sfx_one_lit_casei1, suffixes, "(?i)a", + M("A"), M("a")); + test_lit!(sfx_one_lit_casei2, suffixes, "(?i)abc", + M("ABC"), M("ABc"), M("AbC"), M("Abc"), + M("aBC"), M("aBc"), M("abC"), M("abc")); + test_lit!(sfx_group1, suffixes, "(a)", M("a")); + test_lit!(sfx_rep_zero_or_one1, suffixes, "a?"); + test_lit!(sfx_rep_zero_or_one2, suffixes, "(?:abc)?"); + test_lit!(sfx_rep_zero_or_more1, suffixes, "a*"); + test_lit!(sfx_rep_zero_or_more2, suffixes, "(?:abc)*"); + test_lit!(sfx_rep_one_or_more1, suffixes, "a+", C("a")); + test_lit!(sfx_rep_one_or_more2, suffixes, "(?:abc)+", C("abc")); + test_lit!(sfx_rep_nested_one_or_more, suffixes, "(?:a+)+", C("a")); + test_lit!(sfx_rep_range1, suffixes, "a{0}"); + test_lit!(sfx_rep_range2, suffixes, "a{0,}"); + test_lit!(sfx_rep_range3, suffixes, "a{0,1}"); + test_lit!(sfx_rep_range4, suffixes, "a{1}", M("a")); + test_lit!(sfx_rep_range5, suffixes, "a{2}", M("aa")); + test_lit!(sfx_rep_range6, suffixes, "a{1,2}", C("a")); + test_lit!(sfx_rep_range7, suffixes, "a{2,3}", C("aa")); + + // Test regexes with concatenations. + test_lit!(sfx_cat1, suffixes, "(?:a)(?:b)", M("ab")); + test_lit!(sfx_cat2, suffixes, "[ab]z", M("az"), M("bz")); + test_lit!(sfx_cat3, suffixes, "(?i)[ab]z", + M("AZ"), M("Az"), M("BZ"), M("Bz"), + M("aZ"), M("az"), M("bZ"), M("bz")); + test_lit!(sfx_cat4, suffixes, "[ab][yz]", + M("ay"), M("az"), M("by"), M("bz")); + test_lit!(sfx_cat5, suffixes, "a*b", C("ab"), M("b")); + test_lit!(sfx_cat6, suffixes, "a*b*c", C("bc"), C("ac"), M("c")); + test_lit!(sfx_cat7, suffixes, "a*b*c+", C("c")); + test_lit!(sfx_cat8, suffixes, "a*b+c", C("bc")); + test_lit!(sfx_cat9, suffixes, "a*b+c*", C("c"), C("b")); + test_lit!(sfx_cat10, suffixes, "ab*", C("b"), M("a")); + test_lit!(sfx_cat11, suffixes, "ab*c", C("bc"), M("ac")); + test_lit!(sfx_cat12, suffixes, "ab+", C("b")); + test_lit!(sfx_cat13, suffixes, "ab+c", C("bc")); + test_lit!(sfx_cat14, suffixes, "a^"); + test_lit!(sfx_cat15, suffixes, "$a", C("a")); + test_lit!(sfx_cat16, suffixes, r"ab*c", C("bc"), M("ac")); + test_lit!(sfx_cat17, suffixes, r"ab+c", C("bc")); + test_lit!(sfx_cat18, suffixes, r"z*azb", C("zazb"), M("azb")); + test_lit!(sfx_cat19, suffixes, "a.z", C("z")); + + // Test regexes with alternations. + test_lit!(sfx_alt1, suffixes, "a|b", M("a"), M("b")); + test_lit!(sfx_alt2, suffixes, "[1-3]|b", M("1"), M("2"), M("3"), M("b")); + test_lit!(sfx_alt3, suffixes, "y(?:a|b)z", M("yaz"), M("ybz")); + test_lit!(sfx_alt4, suffixes, "a|b*"); + test_lit!(sfx_alt5, suffixes, "a|b+", M("a"), C("b")); + test_lit!(sfx_alt6, suffixes, "a|(?:b|c*)"); + test_lit!(sfx_alt7, suffixes, "(a|b)*c|(a|ab)*c", + C("ac"), C("bc"), M("c"), C("ac"), C("abc"), M("c")); + test_lit!(sfx_alt8, suffixes, "a*b|c", C("ab"), M("b"), M("c")); + + // Test regexes with empty assertions. + test_lit!(sfx_empty1, suffixes, "a$", M("a")); + test_lit!(sfx_empty2, suffixes, "${2}a", C("a")); + + // Make sure some curious regexes have no suffixes. + test_lit!(sfx_nothing1, suffixes, "."); + test_lit!(sfx_nothing2, suffixes, "(?s)."); + test_lit!(sfx_nothing3, suffixes, "^"); + test_lit!(sfx_nothing4, suffixes, "$"); + test_lit!(sfx_nothing6, suffixes, "(?m)$"); + test_lit!(sfx_nothing7, suffixes, r"\b"); + test_lit!(sfx_nothing8, suffixes, r"\B"); + + // Test a few regexes that defeat any suffix literal detection. + test_lit!(sfx_defeated1, suffixes, "a."); + test_lit!(sfx_defeated2, suffixes, "(?s)a."); + test_lit!(sfx_defeated3, suffixes, "a*b*c*"); + test_lit!(sfx_defeated4, suffixes, "a|."); + test_lit!(sfx_defeated5, suffixes, ".|a"); + test_lit!(sfx_defeated6, suffixes, "a|^"); + test_lit!(sfx_defeated7, suffixes, "(?:a(?:b)(?:c))."); + test_lit!(sfx_defeated8, suffixes, "a^"); + test_lit!(sfx_defeated9, suffixes, "(?m)a$"); + test_lit!(sfx_defeated10, suffixes, r"a\b"); + test_lit!(sfx_defeated11, suffixes, r"a\B"); + test_lit!(sfx_defeated12, suffixes, "a^*"); + test_lit!(sfx_defeated13, suffixes, "a^+"); + + // These test use a much lower limit than the default so that we can + // write test cases of reasonable size. + test_exhausted!(sfx_exhausted1, suffixes, "[a-z]"); + test_exhausted!(sfx_exhausted2, suffixes, "A[a-z]*"); + test_exhausted!(sfx_exhausted3, suffixes, "A[a-z]Z", C("Z")); + test_exhausted!(sfx_exhausted4, suffixes, "(?i)foobar", + C("AR"), C("Ar"), C("aR"), C("ar")); + test_exhausted!(sfx_exhausted5, suffixes, "(?:ab){100}", + C("abababababababababab")); + test_exhausted!(sfx_exhausted6, suffixes, "cd(?:(?:ab){100})*", + C("ababababab"), M("cd")); + test_exhausted!(sfx_exhausted7, suffixes, "cd(?:(?:ab){100})*z", + C("abababababz"), M("cdz")); + test_exhausted!(sfx_exhausted8, suffixes, "zaaaaaaaaaaaaaaaaaaaa", + C("aaaaaaaaaaaaaaaaaaaa")); + + // ************************************************************************ + // Tests for generating unambiguous literal sets. + // ************************************************************************ + + macro_rules! test_unamb { + ($name:ident, $given:expr, $expected:expr) => { + #[test] + fn $name() { + let given: Vec<Literal> = + $given + .into_iter() + .map(|ul| { + let cut = ul.is_cut(); + Literal { v: ul.v.into_bytes(), cut: cut } + }) + .collect(); + let lits = create_lits(given); + let got = lits.unambiguous_prefixes(); + assert_eq!($expected, escape_lits(got.literals())); + } + }; + } + + test_unamb!(unambiguous1, vec![M("z"), M("azb")], vec![C("a"), C("z")]); + test_unamb!(unambiguous2, + vec![M("zaaaaaa"), M("aa")], vec![C("aa"), C("z")]); + test_unamb!(unambiguous3, + vec![M("Sherlock"), M("Watson")], + vec![M("Sherlock"), M("Watson")]); + test_unamb!(unambiguous4, vec![M("abc"), M("bc")], vec![C("a"), C("bc")]); + test_unamb!(unambiguous5, vec![M("bc"), M("abc")], vec![C("a"), C("bc")]); + test_unamb!(unambiguous6, vec![M("a"), M("aa")], vec![C("a")]); + test_unamb!(unambiguous7, vec![M("aa"), M("a")], vec![C("a")]); + test_unamb!(unambiguous8, vec![M("ab"), M("a")], vec![C("a")]); + test_unamb!(unambiguous9, + vec![M("ac"), M("bc"), M("c"), M("ac"), M("abc"), M("c")], + vec![C("a"), C("b"), C("c")]); + test_unamb!(unambiguous10, + vec![M("Mo'"), M("Mu'"), M("Mo"), M("Mu")], + vec![C("Mo"), C("Mu")]); + test_unamb!(unambiguous11, + vec![M("zazb"), M("azb")], vec![C("a"), C("z")]); + test_unamb!(unambiguous12, vec![M("foo"), C("foo")], vec![C("foo")]); + test_unamb!(unambiguous13, + vec![M("ABCX"), M("CDAX"), M("BCX")], + vec![C("A"), C("BCX"), C("CD")]); + test_unamb!(unambiguous14, + vec![M("IMGX"), M("MVIX"), M("MGX"), M("DSX")], + vec![M("DSX"), C("I"), C("MGX"), C("MV")]); + test_unamb!(unambiguous15, + vec![M("IMG_"), M("MG_"), M("CIMG")], + vec![C("C"), C("I"), C("MG_")]); + + + // ************************************************************************ + // Tests for suffix trimming. + // ************************************************************************ + macro_rules! test_trim { + ($name:ident, $trim:expr, $given:expr, $expected:expr) => { + #[test] + fn $name() { + let given: Vec<Literal> = + $given + .into_iter() + .map(|ul| { + let cut = ul.is_cut(); + Literal { v: ul.v.into_bytes(), cut: cut } + }) + .collect(); + let lits = create_lits(given); + let got = lits.trim_suffix($trim).unwrap(); + assert_eq!($expected, escape_lits(got.literals())); + } + } + } + + test_trim!(trim1, 1, vec![M("ab"), M("yz")], vec![C("a"), C("y")]); + test_trim!(trim2, 1, vec![M("abc"), M("abd")], vec![C("ab")]); + test_trim!(trim3, 2, vec![M("abc"), M("abd")], vec![C("a")]); + test_trim!(trim4, 2, vec![M("abc"), M("ghij")], vec![C("a"), C("gh")]); + + // ************************************************************************ + // Tests for longest common prefix. + // ************************************************************************ + + macro_rules! test_lcp { + ($name:ident, $given:expr, $expected:expr) => { + #[test] + fn $name() { + let given: Vec<Literal> = + $given + .into_iter() + .map(|s: &str| Literal { + v: s.to_owned().into_bytes(), + cut: false, + }) + .collect(); + let lits = create_lits(given); + let got = lits.longest_common_prefix(); + assert_eq!($expected, escape_bytes(got)); + } + }; + } + + test_lcp!(lcp1, vec!["a"], "a"); + test_lcp!(lcp2, vec![], ""); + test_lcp!(lcp3, vec!["a", "b"], ""); + test_lcp!(lcp4, vec!["ab", "ab"], "ab"); + test_lcp!(lcp5, vec!["ab", "a"], "a"); + test_lcp!(lcp6, vec!["a", "ab"], "a"); + test_lcp!(lcp7, vec!["ab", "b"], ""); + test_lcp!(lcp8, vec!["b", "ab"], ""); + test_lcp!(lcp9, vec!["foobar", "foobaz"], "fooba"); + test_lcp!(lcp10, vec!["foobar", "foobaz", "a"], ""); + test_lcp!(lcp11, vec!["a", "foobar", "foobaz"], ""); + test_lcp!(lcp12, vec!["foo", "flub", "flab", "floo"], "f"); + + // ************************************************************************ + // Tests for longest common suffix. + // ************************************************************************ + + macro_rules! test_lcs { + ($name:ident, $given:expr, $expected:expr) => { + #[test] + fn $name() { + let given: Vec<Literal> = + $given + .into_iter() + .map(|s: &str| Literal { + v: s.to_owned().into_bytes(), + cut: false, + }) + .collect(); + let lits = create_lits(given); + let got = lits.longest_common_suffix(); + assert_eq!($expected, escape_bytes(got)); + } + }; + } + + test_lcs!(lcs1, vec!["a"], "a"); + test_lcs!(lcs2, vec![], ""); + test_lcs!(lcs3, vec!["a", "b"], ""); + test_lcs!(lcs4, vec!["ab", "ab"], "ab"); + test_lcs!(lcs5, vec!["ab", "a"], ""); + test_lcs!(lcs6, vec!["a", "ab"], ""); + test_lcs!(lcs7, vec!["ab", "b"], "b"); + test_lcs!(lcs8, vec!["b", "ab"], "b"); + test_lcs!(lcs9, vec!["barfoo", "bazfoo"], "foo"); + test_lcs!(lcs10, vec!["barfoo", "bazfoo", "a"], ""); + test_lcs!(lcs11, vec!["a", "barfoo", "bazfoo"], ""); + test_lcs!(lcs12, vec!["flub", "bub", "boob", "dub"], "b"); +} diff --git a/regex-syntax/src/hir/mod.rs b/regex-syntax/src/hir/mod.rs new file mode 100644 index 000000000..40b4fea34 --- /dev/null +++ b/regex-syntax/src/hir/mod.rs @@ -0,0 +1,2192 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Defines a high-level intermediate representation for regular expressions. +*/ +use std::char; +use std::cmp; +use std::error; +use std::fmt; +use std::u8; + +use ast::Span; +use hir::interval::{Interval, IntervalSet, IntervalSetIter}; +use unicode; + +pub use hir::visitor::{Visitor, visit}; + +mod interval; +pub mod literal; +pub mod print; +pub mod translate; +mod visitor; + +/// An error that can occur while translating an `Ast` to a `Hir`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Error { + /// The kind of error. + kind: ErrorKind, + /// The original pattern that the translator's Ast was parsed from. Every + /// span in an error is a valid range into this string. + pattern: String, + /// The span of this error, derived from the Ast given to the translator. + span: Span, +} + +impl Error { + /// Return the type of this error. + pub fn kind(&self) -> &ErrorKind { + &self.kind + } + + /// The original pattern string in which this error occurred. + /// + /// Every span reported by this error is reported in terms of this string. + pub fn pattern(&self) -> &str { + &self.pattern + } + + /// Return the span at which this error occurred. + pub fn span(&self) -> &Span { + &self.span + } +} + +/// The type of an error that occurred while building an `Hir`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ErrorKind { + /// This error occurs when a Unicode feature is used when Unicode + /// support is disabled. For example `(?-u:\pL)` would trigger this error. + UnicodeNotAllowed, + /// This error occurs when translating a pattern that could match a byte + /// sequence that isn't UTF-8 and `allow_invalid_utf8` was disabled. + InvalidUtf8, + /// This occurs when an unrecognized Unicode property name could not + /// be found. + UnicodePropertyNotFound, + /// This occurs when an unrecognized Unicode property value could not + /// be found. + UnicodePropertyValueNotFound, + /// This occurs when the translator attempts to construct a character class + /// that is empty. + /// + /// Note that this restriction in the translator may be removed in the + /// future. + EmptyClassNotAllowed, + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +impl ErrorKind { + fn description(&self) -> &str { + use self::ErrorKind::*; + match *self { + UnicodeNotAllowed => "Unicode not allowed here", + InvalidUtf8 => "pattern can match invalid UTF-8", + UnicodePropertyNotFound => "Unicode property not found", + UnicodePropertyValueNotFound => "Unicode property value not found", + EmptyClassNotAllowed => "empty character classes are not allowed", + _ => unreachable!(), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + self.kind.description() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::error::Formatter::from(self).fmt(f) + } +} + +impl fmt::Display for ErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.description()) + } +} + +/// A high-level intermediate representation (HIR) for a regular expression. +/// +/// The HIR of a regular expression represents an intermediate step between its +/// abstract syntax (a structured description of the concrete syntax) and +/// compiled byte codes. The purpose of HIR is to make regular expressions +/// easier to analyze. In particular, the AST is much more complex than the +/// HIR. For example, while an AST supports arbitrarily nested character +/// classes, the HIR will flatten all nested classes into a single set. The HIR +/// will also "compile away" every flag present in the concrete syntax. For +/// example, users of HIR expressions never need to worry about case folding; +/// it is handled automatically by the translator (e.g., by translating `(?i)A` +/// to `[aA]`). +/// +/// If the HIR was produced by a translator that disallows invalid UTF-8, then +/// the HIR is guaranteed to match UTF-8 exclusively. +/// +/// This type defines its own destructor that uses constant stack space and +/// heap space proportional to the size of the HIR. +/// +/// The specific type of an HIR expression can be accessed via its `kind` +/// or `into_kind` methods. This extra level of indirection exists for two +/// reasons: +/// +/// 1. Construction of an HIR expression *must* use the constructor methods +/// on this `Hir` type instead of building the `HirKind` values directly. +/// This permits construction to enforce invariants like "concatenations +/// always consist of two or more sub-expressions." +/// 2. Every HIR expression contains attributes that are defined inductively, +/// and can be computed cheaply during the construction process. For +/// example, one such attribute is whether the expression must match at the +/// beginning of the text. +/// +/// Also, an `Hir`'s `fmt::Display` implementation prints an HIR as a regular +/// expression pattern string, and uses constant stack space and heap space +/// proportional to the size of the `Hir`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Hir { + /// The underlying HIR kind. + kind: HirKind, + /// Analysis info about this HIR, computed during construction. + info: HirInfo, +} + +/// The kind of an arbitrary `Hir` expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum HirKind { + /// The empty regular expression, which matches everything, including the + /// empty string. + Empty, + /// A single literal character that matches exactly this character. + Literal(Literal), + /// A single character class that matches any of the characters in the + /// class. A class can either consist of Unicode scalar values as + /// characters, or it can use bytes. + Class(Class), + /// An anchor assertion. An anchor assertion match always has zero length. + Anchor(Anchor), + /// A word boundary assertion, which may or may not be Unicode aware. A + /// word boundary assertion match always has zero length. + WordBoundary(WordBoundary), + /// A repetition operation applied to a child expression. + Repetition(Repetition), + /// A possibly capturing group, which contains a child expression. + Group(Group), + /// A concatenation of expressions. A concatenation always has at least two + /// child expressions. + /// + /// A concatenation matches only if each of its child expression matches + /// one after the other. + Concat(Vec<Hir>), + /// An alternation of expressions. An alternation always has at least two + /// child expressions. + /// + /// An alternation matches only if at least one of its child expression + /// matches. If multiple expressions match, then the leftmost is preferred. + Alternation(Vec<Hir>), +} + +impl Hir { + /// Returns a reference to the underlying HIR kind. + pub fn kind(&self) -> &HirKind { + &self.kind + } + + /// Consumes ownership of this HIR expression and returns its underlying + /// `HirKind`. + pub fn into_kind(mut self) -> HirKind { + use std::mem; + mem::replace(&mut self.kind, HirKind::Empty) + } + + /// Returns an empty HIR expression. + /// + /// An empty HIR expression always matches, including the empty string. + pub fn empty() -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(true); + info.set_all_assertions(true); + info.set_anchored_start(false); + info.set_anchored_end(false); + info.set_line_anchored_start(false); + info.set_line_anchored_end(false); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(true); + info.set_literal(true); + info.set_alternation_literal(true); + Hir { + kind: HirKind::Empty, + info: info, + } + } + + /// Creates a literal HIR expression. + /// + /// If the given literal has a `Byte` variant with an ASCII byte, then this + /// method panics. This enforces the invariant that `Byte` variants are + /// only used to express matching of invalid UTF-8. + pub fn literal(lit: Literal) -> Hir { + if let Literal::Byte(b) = lit { + assert!(b > 0x7F); + } + + let mut info = HirInfo::new(); + info.set_always_utf8(lit.is_unicode()); + info.set_all_assertions(false); + info.set_anchored_start(false); + info.set_anchored_end(false); + info.set_line_anchored_start(false); + info.set_line_anchored_end(false); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(false); + info.set_literal(true); + info.set_alternation_literal(true); + Hir { + kind: HirKind::Literal(lit), + info: info, + } + } + + /// Creates a class HIR expression. + pub fn class(class: Class) -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(class.is_always_utf8()); + info.set_all_assertions(false); + info.set_anchored_start(false); + info.set_anchored_end(false); + info.set_line_anchored_start(false); + info.set_line_anchored_end(false); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(false); + info.set_literal(false); + info.set_alternation_literal(false); + Hir { + kind: HirKind::Class(class), + info: info, + } + } + + /// Creates an anchor assertion HIR expression. + pub fn anchor(anchor: Anchor) -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(true); + info.set_all_assertions(true); + info.set_anchored_start(false); + info.set_anchored_end(false); + info.set_line_anchored_start(false); + info.set_line_anchored_end(false); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(true); + info.set_literal(false); + info.set_alternation_literal(false); + if let Anchor::StartText = anchor { + info.set_anchored_start(true); + info.set_line_anchored_start(true); + info.set_any_anchored_start(true); + } + if let Anchor::EndText = anchor { + info.set_anchored_end(true); + info.set_line_anchored_end(true); + info.set_any_anchored_end(true); + } + if let Anchor::StartLine = anchor { + info.set_line_anchored_start(true); + } + if let Anchor::EndLine = anchor { + info.set_line_anchored_end(true); + } + Hir { + kind: HirKind::Anchor(anchor), + info: info, + } + } + + /// Creates a word boundary assertion HIR expression. + pub fn word_boundary(word_boundary: WordBoundary) -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(true); + info.set_all_assertions(true); + info.set_anchored_start(false); + info.set_anchored_end(false); + info.set_line_anchored_start(false); + info.set_line_anchored_end(false); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_literal(false); + info.set_alternation_literal(false); + // A negated word boundary matches the empty string, but a normal + // word boundary does not! + info.set_match_empty(word_boundary.is_negated()); + // Negated ASCII word boundaries can match invalid UTF-8. + if let WordBoundary::AsciiNegate = word_boundary { + info.set_always_utf8(false); + } + Hir { + kind: HirKind::WordBoundary(word_boundary), + info: info, + } + } + + /// Creates a repetition HIR expression. + pub fn repetition(rep: Repetition) -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(rep.hir.is_always_utf8()); + info.set_all_assertions(rep.hir.is_all_assertions()); + // If this operator can match the empty string, then it can never + // be anchored. + info.set_anchored_start( + !rep.is_match_empty() && rep.hir.is_anchored_start() + ); + info.set_anchored_end( + !rep.is_match_empty() && rep.hir.is_anchored_end() + ); + info.set_line_anchored_start( + !rep.is_match_empty() && rep.hir.is_anchored_start() + ); + info.set_line_anchored_end( + !rep.is_match_empty() && rep.hir.is_anchored_end() + ); + info.set_any_anchored_start(rep.hir.is_any_anchored_start()); + info.set_any_anchored_end(rep.hir.is_any_anchored_end()); + info.set_match_empty(rep.is_match_empty() || rep.hir.is_match_empty()); + info.set_literal(false); + info.set_alternation_literal(false); + Hir { + kind: HirKind::Repetition(rep), + info: info, + } + } + + /// Creates a group HIR expression. + pub fn group(group: Group) -> Hir { + let mut info = HirInfo::new(); + info.set_always_utf8(group.hir.is_always_utf8()); + info.set_all_assertions(group.hir.is_all_assertions()); + info.set_anchored_start(group.hir.is_anchored_start()); + info.set_anchored_end(group.hir.is_anchored_end()); + info.set_line_anchored_start(group.hir.is_line_anchored_start()); + info.set_line_anchored_end(group.hir.is_line_anchored_end()); + info.set_any_anchored_start(group.hir.is_any_anchored_start()); + info.set_any_anchored_end(group.hir.is_any_anchored_end()); + info.set_match_empty(group.hir.is_match_empty()); + info.set_literal(false); + info.set_alternation_literal(false); + Hir { + kind: HirKind::Group(group), + info: info, + } + } + + /// Returns the concatenation of the given expressions. + /// + /// This flattens the concatenation as appropriate. + pub fn concat(mut exprs: Vec<Hir>) -> Hir { + match exprs.len() { + 0 => Hir::empty(), + 1 => { exprs.pop().unwrap() } + _ => { + let mut info = HirInfo::new(); + info.set_always_utf8(true); + info.set_all_assertions(true); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(true); + info.set_literal(true); + info.set_alternation_literal(true); + + // Some attributes require analyzing all sub-expressions. + for e in &exprs { + let x = info.is_always_utf8() && e.is_always_utf8(); + info.set_always_utf8(x); + + let x = info.is_all_assertions() && e.is_all_assertions(); + info.set_all_assertions(x); + + let x = + info.is_any_anchored_start() + || e.is_any_anchored_start(); + info.set_any_anchored_start(x); + + let x = + info.is_any_anchored_end() + || e.is_any_anchored_end(); + info.set_any_anchored_end(x); + + let x = info.is_match_empty() && e.is_match_empty(); + info.set_match_empty(x); + + let x = info.is_literal() && e.is_literal(); + info.set_literal(x); + + let x = + info.is_alternation_literal() + && e.is_alternation_literal(); + info.set_alternation_literal(x); + } + // Anchored attributes require something slightly more + // sophisticated. Normally, WLOG, to determine whether an + // expression is anchored to the start, we'd only need to check + // the first expression of a concatenation. However, + // expressions like `$\b^` are still anchored to the start, + // but the first expression in the concatenation *isn't* + // anchored to the start. So the "first" expression to look at + // is actually one that is either not an assertion or is + // specifically the StartText assertion. + info.set_anchored_start( + exprs.iter() + .take_while(|e| { + e.is_anchored_start() || e.is_all_assertions() + }) + .any(|e| { + e.is_anchored_start() + })); + // Similarly for the end anchor, but in reverse. + info.set_anchored_end( + exprs.iter() + .rev() + .take_while(|e| { + e.is_anchored_end() || e.is_all_assertions() + }) + .any(|e| { + e.is_anchored_end() + })); + // Repeat the process for line anchors. + info.set_line_anchored_start( + exprs.iter() + .take_while(|e| { + e.is_line_anchored_start() || e.is_all_assertions() + }) + .any(|e| { + e.is_line_anchored_start() + })); + info.set_line_anchored_end( + exprs.iter() + .rev() + .take_while(|e| { + e.is_line_anchored_end() || e.is_all_assertions() + }) + .any(|e| { + e.is_line_anchored_end() + })); + Hir { + kind: HirKind::Concat(exprs), + info: info, + } + } + } + } + + /// Returns the alternation of the given expressions. + /// + /// This flattens the alternation as appropriate. + pub fn alternation(mut exprs: Vec<Hir>) -> Hir { + match exprs.len() { + 0 => Hir::empty(), + 1 => exprs.pop().unwrap(), + _ => { + let mut info = HirInfo::new(); + info.set_always_utf8(true); + info.set_all_assertions(true); + info.set_anchored_start(true); + info.set_anchored_end(true); + info.set_line_anchored_start(true); + info.set_line_anchored_end(true); + info.set_any_anchored_start(false); + info.set_any_anchored_end(false); + info.set_match_empty(false); + info.set_literal(false); + info.set_alternation_literal(true); + + // Some attributes require analyzing all sub-expressions. + for e in &exprs { + let x = info.is_always_utf8() && e.is_always_utf8(); + info.set_always_utf8(x); + + let x = info.is_all_assertions() && e.is_all_assertions(); + info.set_all_assertions(x); + + let x = info.is_anchored_start() && e.is_anchored_start(); + info.set_anchored_start(x); + + let x = info.is_anchored_end() && e.is_anchored_end(); + info.set_anchored_end(x); + + let x = info.is_line_anchored_start() + && e.is_line_anchored_start(); + info.set_line_anchored_start(x); + + let x = info.is_line_anchored_end() + && e.is_line_anchored_end(); + info.set_line_anchored_end(x); + + let x = + info.is_any_anchored_start() + || e.is_any_anchored_start(); + info.set_any_anchored_start(x); + + let x = + info.is_any_anchored_end() + || e.is_any_anchored_end(); + info.set_any_anchored_end(x); + + let x = info.is_match_empty() || e.is_match_empty(); + info.set_match_empty(x); + + let x = + info.is_alternation_literal() + && e.is_literal(); + info.set_alternation_literal(x); + } + Hir { + kind: HirKind::Alternation(exprs), + info: info, + } + } + } + } + + /// Build an HIR expression for `.`. + /// + /// A `.` expression matches any character except for `\n`. To build an + /// expression that matches any character, including `\n`, use the `any` + /// method. + /// + /// If `bytes` is `true`, then this assumes characters are limited to a + /// single byte. + pub fn dot(bytes: bool) -> Hir { + if bytes { + let mut cls = ClassBytes::empty(); + cls.push(ClassBytesRange::new(b'\0', b'\x09')); + cls.push(ClassBytesRange::new(b'\x0B', b'\xFF')); + Hir::class(Class::Bytes(cls)) + } else { + let mut cls = ClassUnicode::empty(); + cls.push(ClassUnicodeRange::new('\0', '\x09')); + cls.push(ClassUnicodeRange::new('\x0B', '\u{10FFFF}')); + Hir::class(Class::Unicode(cls)) + } + } + + /// Build an HIR expression for `(?s).`. + /// + /// A `(?s).` expression matches any character, including `\n`. To build an + /// expression that matches any character except for `\n`, then use the + /// `dot` method. + /// + /// If `bytes` is `true`, then this assumes characters are limited to a + /// single byte. + pub fn any(bytes: bool) -> Hir { + if bytes { + let mut cls = ClassBytes::empty(); + cls.push(ClassBytesRange::new(b'\0', b'\xFF')); + Hir::class(Class::Bytes(cls)) + } else { + let mut cls = ClassUnicode::empty(); + cls.push(ClassUnicodeRange::new('\0', '\u{10FFFF}')); + Hir::class(Class::Unicode(cls)) + } + } + + /// Return true if and only if this HIR will always match valid UTF-8. + /// + /// When this returns false, then it is possible for this HIR expression + /// to match invalid UTF-8. + pub fn is_always_utf8(&self) -> bool { + self.info.is_always_utf8() + } + + /// Returns true if and only if this entire HIR expression is made up of + /// zero-width assertions. + /// + /// This includes expressions like `^$\b\A\z` and even `((\b)+())*^`, but + /// not `^a`. + pub fn is_all_assertions(&self) -> bool { + self.info.is_all_assertions() + } + + /// Return true if and only if this HIR is required to match from the + /// beginning of text. This includes expressions like `^foo`, `^(foo|bar)`, + /// `^foo|^bar` but not `^foo|bar`. + pub fn is_anchored_start(&self) -> bool { + self.info.is_anchored_start() + } + + /// Return true if and only if this HIR is required to match at the end + /// of text. This includes expressions like `foo$`, `(foo|bar)$`, + /// `foo$|bar$` but not `foo$|bar`. + pub fn is_anchored_end(&self) -> bool { + self.info.is_anchored_end() + } + + /// Return true if and only if this HIR is required to match from the + /// beginning of text or the beginning of a line. This includes expressions + /// like `^foo`, `(?m)^foo`, `^(foo|bar)`, `^(foo|bar)`, `(?m)^foo|^bar` + /// but not `^foo|bar` or `(?m)^foo|bar`. + /// + /// Note that if `is_anchored_start` is `true`, then + /// `is_line_anchored_start` will also be `true`. The reverse implication + /// is not true. For example, `(?m)^foo` is line anchored, but not + /// `is_anchored_start`. + pub fn is_line_anchored_start(&self) -> bool { + self.info.is_line_anchored_start() + } + + /// Return true if and only if this HIR is required to match at the + /// end of text or the end of a line. This includes expressions like + /// `foo$`, `(?m)foo$`, `(foo|bar)$`, `(?m)(foo|bar)$`, `foo$|bar$`, + /// `(?m)(foo|bar)$`, but not `foo$|bar` or `(?m)foo$|bar`. + /// + /// Note that if `is_anchored_end` is `true`, then + /// `is_line_anchored_end` will also be `true`. The reverse implication + /// is not true. For example, `(?m)foo$` is line anchored, but not + /// `is_anchored_end`. + pub fn is_line_anchored_end(&self) -> bool { + self.info.is_line_anchored_end() + } + + /// Return true if and only if this HIR contains any sub-expression that + /// is required to match at the beginning of text. Specifically, this + /// returns true if the `^` symbol (when multiline mode is disabled) or the + /// `\A` escape appear anywhere in the regex. + pub fn is_any_anchored_start(&self) -> bool { + self.info.is_any_anchored_start() + } + + /// Return true if and only if this HIR contains any sub-expression that is + /// required to match at the end of text. Specifically, this returns true + /// if the `$` symbol (when multiline mode is disabled) or the `\z` escape + /// appear anywhere in the regex. + pub fn is_any_anchored_end(&self) -> bool { + self.info.is_any_anchored_end() + } + + /// Return true if and only if the empty string is part of the language + /// matched by this regular expression. + /// + /// This includes `a*`, `a?b*`, `a{0}`, `()`, `()+`, `^$`, `a|b?`, `\B`, + /// but not `a`, `a+` or `\b`. + pub fn is_match_empty(&self) -> bool { + self.info.is_match_empty() + } + + /// Return true if and only if this HIR is a simple literal. This is only + /// true when this HIR expression is either itself a `Literal` or a + /// concatenation of only `Literal`s. + /// + /// For example, `f` and `foo` are literals, but `f+`, `(foo)`, `foo()` + /// are not (even though that contain sub-expressions that are literals). + pub fn is_literal(&self) -> bool { + self.info.is_literal() + } + + /// Return true if and only if this HIR is either a simple literal or an + /// alternation of simple literals. This is only + /// true when this HIR expression is either itself a `Literal` or a + /// concatenation of only `Literal`s or an alternation of only `Literal`s. + /// + /// For example, `f`, `foo`, `a|b|c`, and `foo|bar|baz` are alternaiton + /// literals, but `f+`, `(foo)`, `foo()` + /// are not (even though that contain sub-expressions that are literals). + pub fn is_alternation_literal(&self) -> bool { + self.info.is_alternation_literal() + } +} + +impl HirKind { + /// Return true if and only if this HIR is the empty regular expression. + /// + /// Note that this is not defined inductively. That is, it only tests if + /// this kind is the `Empty` variant. To get the inductive definition, + /// use the `is_match_empty` method on [`Hir`](struct.Hir.html). + pub fn is_empty(&self) -> bool { + match *self { + HirKind::Empty => true, + _ => false, + } + } + + /// Returns true if and only if this kind has any (including possibly + /// empty) subexpressions. + pub fn has_subexprs(&self) -> bool { + match *self { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Anchor(_) + | HirKind::WordBoundary(_) => false, + HirKind::Group(_) + | HirKind::Repetition(_) + | HirKind::Concat(_) + | HirKind::Alternation(_) => true, + } + } +} + +/// Print a display representation of this Hir. +/// +/// The result of this is a valid regular expression pattern string. +/// +/// This implementation uses constant stack space and heap space proportional +/// to the size of the `Hir`. +impl fmt::Display for Hir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use hir::print::Printer; + Printer::new().print(self, f) + } +} + +/// The high-level intermediate representation of a literal. +/// +/// A literal corresponds to a single character, where a character is either +/// defined by a Unicode scalar value or an arbitrary byte. Unicode characters +/// are preferred whenever possible. In particular, a `Byte` variant is only +/// ever produced when it could match invalid UTF-8. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Literal { + /// A single character represented by a Unicode scalar value. + Unicode(char), + /// A single character represented by an arbitrary byte. + Byte(u8), +} + +impl Literal { + /// Returns true if and only if this literal corresponds to a Unicode + /// scalar value. + pub fn is_unicode(&self) -> bool { + match *self { + Literal::Unicode(_) => true, + Literal::Byte(b) if b <= 0x7F => true, + Literal::Byte(_) => false, + } + } +} + +/// The high-level intermediate representation of a character class. +/// +/// A character class corresponds to a set of characters. A character is either +/// defined by a Unicode scalar value or a byte. Unicode characters are used +/// by default, while bytes are used when Unicode mode (via the `u` flag) is +/// disabled. +/// +/// A character class, regardless of its character type, is represented by a +/// sequence of non-overlapping non-adjacent ranges of characters. +/// +/// Note that unlike [`Literal`](enum.Literal.html), a `Bytes` variant may +/// be produced even when it exclusively matches valid UTF-8. This is because +/// a `Bytes` variant represents an intention by the author of the regular +/// expression to disable Unicode mode, which in turn impacts the semantics of +/// case insensitive matching. For example, `(?i)k` and `(?i-u)k` will not +/// match the same set of strings. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Class { + /// A set of characters represented by Unicode scalar values. + Unicode(ClassUnicode), + /// A set of characters represented by arbitrary bytes (one byte per + /// character). + Bytes(ClassBytes), +} + +impl Class { + /// Apply Unicode simple case folding to this character class, in place. + /// The character class will be expanded to include all simple case folded + /// character variants. + /// + /// If this is a byte oriented character class, then this will be limited + /// to the ASCII ranges `A-Z` and `a-z`. + pub fn case_fold_simple(&mut self) { + match *self { + Class::Unicode(ref mut x) => x.case_fold_simple(), + Class::Bytes(ref mut x) => x.case_fold_simple(), + } + } + + /// Negate this character class in place. + /// + /// After completion, this character class will contain precisely the + /// characters that weren't previously in the class. + pub fn negate(&mut self) { + match *self { + Class::Unicode(ref mut x) => x.negate(), + Class::Bytes(ref mut x) => x.negate(), + } + } + + /// Returns true if and only if this character class will only ever match + /// valid UTF-8. + /// + /// A character class can match invalid UTF-8 only when the following + /// conditions are met: + /// + /// 1. The translator was configured to permit generating an expression + /// that can match invalid UTF-8. (By default, this is disabled.) + /// 2. Unicode mode (via the `u` flag) was disabled either in the concrete + /// syntax or in the parser builder. By default, Unicode mode is + /// enabled. + pub fn is_always_utf8(&self) -> bool { + match *self { + Class::Unicode(_) => true, + Class::Bytes(ref x) => x.is_all_ascii(), + } + } +} + +/// A set of characters represented by Unicode scalar values. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassUnicode { + set: IntervalSet<ClassUnicodeRange>, +} + +impl ClassUnicode { + /// Create a new class from a sequence of ranges. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. + pub fn new<I>(ranges: I) -> ClassUnicode + where I: IntoIterator<Item=ClassUnicodeRange> + { + ClassUnicode { set: IntervalSet::new(ranges) } + } + + /// Create a new class with no ranges. + pub fn empty() -> ClassUnicode { + ClassUnicode::new(vec![]) + } + + /// Add a new range to this set. + pub fn push(&mut self, range: ClassUnicodeRange) { + self.set.push(range); + } + + /// Return an iterator over all ranges in this class. + /// + /// The iterator yields ranges in ascending order. + pub fn iter(&self) -> ClassUnicodeIter { + ClassUnicodeIter(self.set.iter()) + } + + /// Return the underlying ranges as a slice. + pub fn ranges(&self) -> &[ClassUnicodeRange] { + self.set.intervals() + } + + /// Expand this character class such that it contains all case folded + /// characters, according to Unicode's "simple" mapping. For example, if + /// this class consists of the range `a-z`, then applying case folding will + /// result in the class containing both the ranges `a-z` and `A-Z`. + pub fn case_fold_simple(&mut self) { + self.set.case_fold_simple(); + } + + /// Negate this character class. + /// + /// For all `c` where `c` is a Unicode scalar value, if `c` was in this + /// set, then it will not be in this set after negation. + pub fn negate(&mut self) { + self.set.negate(); + } + + /// Union this character class with the given character class, in place. + pub fn union(&mut self, other: &ClassUnicode) { + self.set.union(&other.set); + } + + /// Intersect this character class with the given character class, in + /// place. + pub fn intersect(&mut self, other: &ClassUnicode) { + self.set.intersect(&other.set); + } + + /// Subtract the given character class from this character class, in place. + pub fn difference(&mut self, other: &ClassUnicode) { + self.set.difference(&other.set); + } + + /// Compute the symmetric difference of the given character classes, in + /// place. + /// + /// This computes the symmetric difference of two character classes. This + /// removes all elements in this class that are also in the given class, + /// but all adds all elements from the given class that aren't in this + /// class. That is, the class will contain all elements in either class, + /// but will not contain any elements that are in both classes. + pub fn symmetric_difference(&mut self, other: &ClassUnicode) { + self.set.symmetric_difference(&other.set); + } +} + +/// An iterator over all ranges in a Unicode character class. +/// +/// The lifetime `'a` refers to the lifetime of the underlying class. +#[derive(Debug)] +pub struct ClassUnicodeIter<'a>(IntervalSetIter<'a, ClassUnicodeRange>); + +impl<'a> Iterator for ClassUnicodeIter<'a> { + type Item = &'a ClassUnicodeRange; + + fn next(&mut self) -> Option<&'a ClassUnicodeRange> { + self.0.next() + } +} + +/// A single range of characters represented by Unicode scalar values. +/// +/// The range is closed. That is, the start and end of the range are included +/// in the range. +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct ClassUnicodeRange { + start: char, + end: char, +} + +impl fmt::Debug for ClassUnicodeRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let start = + if !self.start.is_whitespace() && !self.start.is_control() { + self.start.to_string() + } else { + format!("0x{:X}", self.start as u32) + }; + let end = + if !self.end.is_whitespace() && !self.end.is_control() { + self.end.to_string() + } else { + format!("0x{:X}", self.end as u32) + }; + f.debug_struct("ClassUnicodeRange") + .field("start", &start) + .field("end", &end) + .finish() + } +} + +impl Interval for ClassUnicodeRange { + type Bound = char; + + #[inline] fn lower(&self) -> char { self.start } + #[inline] fn upper(&self) -> char { self.end } + #[inline] fn set_lower(&mut self, bound: char) { self.start = bound; } + #[inline] fn set_upper(&mut self, bound: char) { self.end = bound; } + + /// Apply simple case folding to this Unicode scalar value range. + /// + /// Additional ranges are appended to the given vector. Canonical ordering + /// is *not* maintained in the given vector. + fn case_fold_simple(&self, ranges: &mut Vec<ClassUnicodeRange>) { + if !unicode::contains_simple_case_mapping(self.start, self.end) { + return; + } + let start = self.start as u32; + let end = (self.end as u32).saturating_add(1); + let mut next_simple_cp = None; + for cp in (start..end).filter_map(char::from_u32) { + if next_simple_cp.map_or(false, |next| cp < next) { + continue; + } + let it = match unicode::simple_fold(cp) { + Ok(it) => it, + Err(next) => { + next_simple_cp = next; + continue; + } + }; + for cp_folded in it { + ranges.push(ClassUnicodeRange::new(cp_folded, cp_folded)); + } + } + } +} + +impl ClassUnicodeRange { + /// Create a new Unicode scalar value range for a character class. + /// + /// The returned range is always in a canonical form. That is, the range + /// returned always satisfies the invariant that `start <= end`. + pub fn new(start: char, end: char) -> ClassUnicodeRange { + ClassUnicodeRange::create(start, end) + } + + /// Return the start of this range. + /// + /// The start of a range is always less than or equal to the end of the + /// range. + pub fn start(&self) -> char { + self.start + } + + /// Return the end of this range. + /// + /// The end of a range is always greater than or equal to the start of the + /// range. + pub fn end(&self) -> char { + self.end + } +} + +/// A set of characters represented by arbitrary bytes (where one byte +/// corresponds to one character). +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ClassBytes { + set: IntervalSet<ClassBytesRange>, +} + +impl ClassBytes { + /// Create a new class from a sequence of ranges. + /// + /// The given ranges do not need to be in any specific order, and ranges + /// may overlap. + pub fn new<I>(ranges: I) -> ClassBytes + where I: IntoIterator<Item=ClassBytesRange> + { + ClassBytes { set: IntervalSet::new(ranges) } + } + + /// Create a new class with no ranges. + pub fn empty() -> ClassBytes { + ClassBytes::new(vec![]) + } + + /// Add a new range to this set. + pub fn push(&mut self, range: ClassBytesRange) { + self.set.push(range); + } + + /// Return an iterator over all ranges in this class. + /// + /// The iterator yields ranges in ascending order. + pub fn iter(&self) -> ClassBytesIter { + ClassBytesIter(self.set.iter()) + } + + /// Return the underlying ranges as a slice. + pub fn ranges(&self) -> &[ClassBytesRange] { + self.set.intervals() + } + + /// Expand this character class such that it contains all case folded + /// characters. For example, if this class consists of the range `a-z`, + /// then applying case folding will result in the class containing both the + /// ranges `a-z` and `A-Z`. + /// + /// Note that this only applies ASCII case folding, which is limited to the + /// characters `a-z` and `A-Z`. + pub fn case_fold_simple(&mut self) { + self.set.case_fold_simple(); + } + + /// Negate this byte class. + /// + /// For all `b` where `b` is a any byte, if `b` was in this set, then it + /// will not be in this set after negation. + pub fn negate(&mut self) { + self.set.negate(); + } + + /// Union this byte class with the given byte class, in place. + pub fn union(&mut self, other: &ClassBytes) { + self.set.union(&other.set); + } + + /// Intersect this byte class with the given byte class, in place. + pub fn intersect(&mut self, other: &ClassBytes) { + self.set.intersect(&other.set); + } + + /// Subtract the given byte class from this byte class, in place. + pub fn difference(&mut self, other: &ClassBytes) { + self.set.difference(&other.set); + } + + /// Compute the symmetric difference of the given byte classes, in place. + /// + /// This computes the symmetric difference of two byte classes. This + /// removes all elements in this class that are also in the given class, + /// but all adds all elements from the given class that aren't in this + /// class. That is, the class will contain all elements in either class, + /// but will not contain any elements that are in both classes. + pub fn symmetric_difference(&mut self, other: &ClassBytes) { + self.set.symmetric_difference(&other.set); + } + + /// Returns true if and only if this character class will either match + /// nothing or only ASCII bytes. Stated differently, this returns false + /// if and only if this class contains a non-ASCII byte. + pub fn is_all_ascii(&self) -> bool { + self.set.intervals().last().map_or(true, |r| r.end <= 0x7F) + } +} + +/// An iterator over all ranges in a byte character class. +/// +/// The lifetime `'a` refers to the lifetime of the underlying class. +#[derive(Debug)] +pub struct ClassBytesIter<'a>(IntervalSetIter<'a, ClassBytesRange>); + +impl<'a> Iterator for ClassBytesIter<'a> { + type Item = &'a ClassBytesRange; + + fn next(&mut self) -> Option<&'a ClassBytesRange> { + self.0.next() + } +} + +/// A single range of characters represented by arbitrary bytes. +/// +/// The range is closed. That is, the start and end of the range are included +/// in the range. +#[derive(Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord)] +pub struct ClassBytesRange { + start: u8, + end: u8, +} + +impl Interval for ClassBytesRange { + type Bound = u8; + + #[inline] fn lower(&self) -> u8 { self.start } + #[inline] fn upper(&self) -> u8 { self.end } + #[inline] fn set_lower(&mut self, bound: u8) { self.start = bound; } + #[inline] fn set_upper(&mut self, bound: u8) { self.end = bound; } + + /// Apply simple case folding to this byte range. Only ASCII case mappings + /// (for a-z) are applied. + /// + /// Additional ranges are appended to the given vector. Canonical ordering + /// is *not* maintained in the given vector. + fn case_fold_simple(&self, ranges: &mut Vec<ClassBytesRange>) { + if !ClassBytesRange::new(b'a', b'z').is_intersection_empty(self) { + let lower = cmp::max(self.start, b'a'); + let upper = cmp::min(self.end, b'z'); + ranges.push(ClassBytesRange::new(lower - 32, upper - 32)); + } + if !ClassBytesRange::new(b'A', b'Z').is_intersection_empty(self) { + let lower = cmp::max(self.start, b'A'); + let upper = cmp::min(self.end, b'Z'); + ranges.push(ClassBytesRange::new(lower + 32, upper + 32)); + } + } +} + +impl ClassBytesRange { + /// Create a new byte range for a character class. + /// + /// The returned range is always in a canonical form. That is, the range + /// returned always satisfies the invariant that `start <= end`. + pub fn new(start: u8, end: u8) -> ClassBytesRange { + ClassBytesRange::create(start, end) + } + + /// Return the start of this range. + /// + /// The start of a range is always less than or equal to the end of the + /// range. + pub fn start(&self) -> u8 { + self.start + } + + /// Return the end of this range. + /// + /// The end of a range is always greater than or equal to the start of the + /// range. + pub fn end(&self) -> u8 { + self.end + } +} + +impl fmt::Debug for ClassBytesRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut debug = f.debug_struct("ClassBytesRange"); + if self.start <= 0x7F { + debug.field("start", &(self.start as char)); + } else { + debug.field("start", &self.start); + } + if self.end <= 0x7F { + debug.field("end", &(self.end as char)); + } else { + debug.field("end", &self.end); + } + debug.finish() + } +} + +/// The high-level intermediate representation for an anchor assertion. +/// +/// A matching anchor assertion is always zero-length. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Anchor { + /// Match the beginning of a line or the beginning of text. Specifically, + /// this matches at the starting position of the input, or at the position + /// immediately following a `\n` character. + StartLine, + /// Match the end of a line or the end of text. Specifically, + /// this matches at the end position of the input, or at the position + /// immediately preceding a `\n` character. + EndLine, + /// Match the beginning of text. Specifically, this matches at the starting + /// position of the input. + StartText, + /// Match the end of text. Specifically, this matches at the ending + /// position of the input. + EndText, +} + +/// The high-level intermediate representation for a word-boundary assertion. +/// +/// A matching word boundary assertion is always zero-length. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum WordBoundary { + /// Match a Unicode-aware word boundary. That is, this matches a position + /// where the left adjacent character and right adjacent character + /// correspond to a word and non-word or a non-word and word character. + Unicode, + /// Match a Unicode-aware negation of a word boundary. + UnicodeNegate, + /// Match an ASCII-only word boundary. That is, this matches a position + /// where the left adjacent character and right adjacent character + /// correspond to a word and non-word or a non-word and word character. + Ascii, + /// Match an ASCII-only negation of a word boundary. + AsciiNegate, +} + +impl WordBoundary { + /// Returns true if and only if this word boundary assertion is negated. + pub fn is_negated(&self) -> bool { + match *self { + WordBoundary::Unicode | WordBoundary::Ascii => false, + WordBoundary::UnicodeNegate | WordBoundary::AsciiNegate => true, + } + } +} + +/// The high-level intermediate representation for a group. +/// +/// This represents one of three possible group types: +/// +/// 1. A non-capturing group (e.g., `(?:expr)`). +/// 2. A capturing group (e.g., `(expr)`). +/// 3. A named capturing group (e.g., `(?P<name>expr)`). +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Group { + /// The kind of this group. If it is a capturing group, then the kind + /// contains the capture group index (and the name, if it is a named + /// group). + pub kind: GroupKind, + /// The expression inside the capturing group, which may be empty. + pub hir: Box<Hir>, +} + +/// The kind of group. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum GroupKind { + /// A normal unnamed capturing group. + /// + /// The value is the capture index of the group. + CaptureIndex(u32), + /// A named capturing group. + CaptureName { + /// The name of the group. + name: String, + /// The capture index of the group. + index: u32, + }, + /// A non-capturing group. + NonCapturing, +} + +/// The high-level intermediate representation of a repetition operator. +/// +/// A repetition operator permits the repetition of an arbitrary +/// sub-expression. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Repetition { + /// The kind of this repetition operator. + pub kind: RepetitionKind, + /// Whether this repetition operator is greedy or not. A greedy operator + /// will match as much as it can. A non-greedy operator will match as + /// little as it can. + /// + /// Typically, operators are greedy by default and are only non-greedy when + /// a `?` suffix is used, e.g., `(expr)*` is greedy while `(expr)*?` is + /// not. However, this can be inverted via the `U` "ungreedy" flag. + pub greedy: bool, + /// The expression being repeated. + pub hir: Box<Hir>, +} + +impl Repetition { + /// Returns true if and only if this repetition operator makes it possible + /// to match the empty string. + /// + /// Note that this is not defined inductively. For example, while `a*` + /// will report `true`, `()+` will not, even though `()` matches the empty + /// string and one or more occurrences of something that matches the empty + /// string will always match the empty string. In order to get the + /// inductive definition, see the corresponding method on + /// [`Hir`](struct.Hir.html). + pub fn is_match_empty(&self) -> bool { + match self.kind { + RepetitionKind::ZeroOrOne => true, + RepetitionKind::ZeroOrMore => true, + RepetitionKind::OneOrMore => false, + RepetitionKind::Range(RepetitionRange::Exactly(m)) => m == 0, + RepetitionKind::Range(RepetitionRange::AtLeast(m)) => m == 0, + RepetitionKind::Range(RepetitionRange::Bounded(m, _)) => m == 0, + } + } +} + +/// The kind of a repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RepetitionKind { + /// Matches a sub-expression zero or one times. + ZeroOrOne, + /// Matches a sub-expression zero or more times. + ZeroOrMore, + /// Matches a sub-expression one or more times. + OneOrMore, + /// Matches a sub-expression within a bounded range of times. + Range(RepetitionRange), +} + +/// The kind of a counted repetition operator. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RepetitionRange { + /// Matches a sub-expression exactly this many times. + Exactly(u32), + /// Matches a sub-expression at least this many times. + AtLeast(u32), + /// Matches a sub-expression at least `m` times and at most `n` times. + Bounded(u32, u32), +} + +/// A custom `Drop` impl is used for `HirKind` such that it uses constant stack +/// space but heap space proportional to the depth of the total `Hir`. +impl Drop for Hir { + fn drop(&mut self) { + use std::mem; + + match *self.kind() { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Anchor(_) + | HirKind::WordBoundary(_) => return, + HirKind::Group(ref x) if !x.hir.kind.has_subexprs() => return, + HirKind::Repetition(ref x) if !x.hir.kind.has_subexprs() => return, + HirKind::Concat(ref x) if x.is_empty() => return, + HirKind::Alternation(ref x) if x.is_empty() => return, + _ => {} + } + + let mut stack = vec![mem::replace(self, Hir::empty())]; + while let Some(mut expr) = stack.pop() { + match expr.kind { + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Anchor(_) + | HirKind::WordBoundary(_) => {} + HirKind::Group(ref mut x) => { + stack.push(mem::replace(&mut x.hir, Hir::empty())); + } + HirKind::Repetition(ref mut x) => { + stack.push(mem::replace(&mut x.hir, Hir::empty())); + } + HirKind::Concat(ref mut x) => { + stack.extend(x.drain(..)); + } + HirKind::Alternation(ref mut x) => { + stack.extend(x.drain(..)); + } + } + } + } +} + +/// A type that documents various attributes of an HIR expression. +/// +/// These attributes are typically defined inductively on the HIR. +#[derive(Clone, Debug, Eq, PartialEq)] +struct HirInfo { + /// Represent yes/no questions by a bitfield to conserve space, since + /// this is included in every HIR expression. + /// + /// If more attributes need to be added, it is OK to increase the size of + /// this as appropriate. + bools: u16, +} + +// A simple macro for defining bitfield accessors/mutators. +macro_rules! define_bool { + ($bit:expr, $is_fn_name:ident, $set_fn_name:ident) => { + fn $is_fn_name(&self) -> bool { + self.bools & (0b1 << $bit) > 0 + } + + fn $set_fn_name(&mut self, yes: bool) { + if yes { + self.bools |= 1 << $bit; + } else { + self.bools &= !(1 << $bit); + } + } + } +} + +impl HirInfo { + fn new() -> HirInfo { + HirInfo { + bools: 0, + } + } + + define_bool!(0, is_always_utf8, set_always_utf8); + define_bool!(1, is_all_assertions, set_all_assertions); + define_bool!(2, is_anchored_start, set_anchored_start); + define_bool!(3, is_anchored_end, set_anchored_end); + define_bool!(4, is_line_anchored_start, set_line_anchored_start); + define_bool!(5, is_line_anchored_end, set_line_anchored_end); + define_bool!(6, is_any_anchored_start, set_any_anchored_start); + define_bool!(7, is_any_anchored_end, set_any_anchored_end); + define_bool!(8, is_match_empty, set_match_empty); + define_bool!(9, is_literal, set_literal); + define_bool!(10, is_alternation_literal, set_alternation_literal); +} + +#[cfg(test)] +mod tests { + use super::*; + + fn uclass(ranges: &[(char, char)]) -> ClassUnicode { + let ranges: Vec<ClassUnicodeRange> = ranges + .iter() + .map(|&(s, e)| ClassUnicodeRange::new(s, e)) + .collect(); + ClassUnicode::new(ranges) + } + + fn bclass(ranges: &[(u8, u8)]) -> ClassBytes { + let ranges: Vec<ClassBytesRange> = ranges + .iter() + .map(|&(s, e)| ClassBytesRange::new(s, e)) + .collect(); + ClassBytes::new(ranges) + } + + fn uranges(cls: &ClassUnicode) -> Vec<(char, char)> { + cls.iter().map(|x| (x.start(), x.end())).collect() + } + + fn ucasefold(cls: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls.clone(); + cls_.case_fold_simple(); + cls_ + } + + fn uunion(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.union(cls2); + cls_ + } + + fn uintersect(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.intersect(cls2); + cls_ + } + + fn udifference(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.difference(cls2); + cls_ + } + + fn usymdifference(cls1: &ClassUnicode, cls2: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls1.clone(); + cls_.symmetric_difference(cls2); + cls_ + } + + fn unegate(cls: &ClassUnicode) -> ClassUnicode { + let mut cls_ = cls.clone(); + cls_.negate(); + cls_ + } + + fn branges(cls: &ClassBytes) -> Vec<(u8, u8)> { + cls.iter().map(|x| (x.start(), x.end())).collect() + } + + fn bcasefold(cls: &ClassBytes) -> ClassBytes { + let mut cls_ = cls.clone(); + cls_.case_fold_simple(); + cls_ + } + + fn bunion(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.union(cls2); + cls_ + } + + fn bintersect(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.intersect(cls2); + cls_ + } + + fn bdifference(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.difference(cls2); + cls_ + } + + fn bsymdifference(cls1: &ClassBytes, cls2: &ClassBytes) -> ClassBytes { + let mut cls_ = cls1.clone(); + cls_.symmetric_difference(cls2); + cls_ + } + + fn bnegate(cls: &ClassBytes) -> ClassBytes { + let mut cls_ = cls.clone(); + cls_.negate(); + cls_ + } + + #[test] + fn class_range_canonical_unicode() { + let range = ClassUnicodeRange::new('\u{00FF}', '\0'); + assert_eq!('\0', range.start()); + assert_eq!('\u{00FF}', range.end()); + } + + #[test] + fn class_range_canonical_bytes() { + let range = ClassBytesRange::new(b'\xFF', b'\0'); + assert_eq!(b'\0', range.start()); + assert_eq!(b'\xFF', range.end()); + } + + #[test] + fn class_canonicalize_unicode() { + let cls = uclass(&[('a', 'c'), ('x', 'z')]); + let expected = vec![('a', 'c'), ('x', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('a', 'c')]); + let expected = vec![('a', 'c'), ('x', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('w', 'y')]); + let expected = vec![('w', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[ + ('c', 'f'), ('a', 'g'), ('d', 'j'), ('a', 'c'), + ('m', 'p'), ('l', 's'), + ]); + let expected = vec![('a', 'j'), ('l', 's')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('x', 'z'), ('u', 'w')]); + let expected = vec![('u', 'z')]; + assert_eq!(expected, uranges(&cls)); + + let cls = uclass(&[('\x00', '\u{10FFFF}'), ('\x00', '\u{10FFFF}')]); + let expected = vec![('\x00', '\u{10FFFF}')]; + assert_eq!(expected, uranges(&cls)); + + + let cls = uclass(&[('a', 'a'), ('b', 'b')]); + let expected = vec![('a', 'b')]; + assert_eq!(expected, uranges(&cls)); + } + + #[test] + fn class_canonicalize_bytes() { + let cls = bclass(&[(b'a', b'c'), (b'x', b'z')]); + let expected = vec![(b'a', b'c'), (b'x', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'a', b'c')]); + let expected = vec![(b'a', b'c'), (b'x', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'w', b'y')]); + let expected = vec![(b'w', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[ + (b'c', b'f'), (b'a', b'g'), (b'd', b'j'), (b'a', b'c'), + (b'm', b'p'), (b'l', b's'), + ]); + let expected = vec![(b'a', b'j'), (b'l', b's')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'x', b'z'), (b'u', b'w')]); + let expected = vec![(b'u', b'z')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFF'), (b'\x00', b'\xFF')]); + let expected = vec![(b'\x00', b'\xFF')]; + assert_eq!(expected, branges(&cls)); + + let cls = bclass(&[(b'a', b'a'), (b'b', b'b')]); + let expected = vec![(b'a', b'b')]; + assert_eq!(expected, branges(&cls)); + } + + #[test] + fn class_case_fold_unicode() { + let cls = uclass(&[ + ('C', 'F'), ('A', 'G'), ('D', 'J'), ('A', 'C'), + ('M', 'P'), ('L', 'S'), ('c', 'f'), + ]); + let expected = uclass(&[ + ('A', 'J'), ('L', 'S'), + ('a', 'j'), ('l', 's'), + ('\u{17F}', '\u{17F}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'Z')]); + let expected = uclass(&[ + ('A', 'Z'), ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('a', 'z')]); + let expected = uclass(&[ + ('A', 'Z'), ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'A'), ('_', '_')]); + let expected = uclass(&[('A', 'A'), ('_', '_'), ('a', 'a')]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('A', 'A'), ('=', '=')]); + let expected = uclass(&[('=', '='), ('A', 'A'), ('a', 'a')]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('\x00', '\x10')]); + assert_eq!(cls, ucasefold(&cls)); + + let cls = uclass(&[('k', 'k')]); + let expected = uclass(&[ + ('K', 'K'), ('k', 'k'), ('\u{212A}', '\u{212A}'), + ]); + assert_eq!(expected, ucasefold(&cls)); + + let cls = uclass(&[('@', '@')]); + assert_eq!(cls, ucasefold(&cls)); + } + + #[test] + fn class_case_fold_bytes() { + let cls = bclass(&[ + (b'C', b'F'), (b'A', b'G'), (b'D', b'J'), (b'A', b'C'), + (b'M', b'P'), (b'L', b'S'), (b'c', b'f'), + ]); + let expected = bclass(&[ + (b'A', b'J'), (b'L', b'S'), + (b'a', b'j'), (b'l', b's'), + ]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'Z')]); + let expected = bclass(&[(b'A', b'Z'), (b'a', b'z')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'a', b'z')]); + let expected = bclass(&[(b'A', b'Z'), (b'a', b'z')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'A'), (b'_', b'_')]); + let expected = bclass(&[(b'A', b'A'), (b'_', b'_'), (b'a', b'a')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'A', b'A'), (b'=', b'=')]); + let expected = bclass(&[(b'=', b'='), (b'A', b'A'), (b'a', b'a')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'\x00', b'\x10')]); + assert_eq!(cls, bcasefold(&cls)); + + let cls = bclass(&[(b'k', b'k')]); + let expected = bclass(&[(b'K', b'K'), (b'k', b'k')]); + assert_eq!(expected, bcasefold(&cls)); + + let cls = bclass(&[(b'@', b'@')]); + assert_eq!(cls, bcasefold(&cls)); + } + + #[test] + fn class_negate_unicode() { + let cls = uclass(&[('a', 'a')]); + let expected = uclass(&[('\x00', '\x60'), ('\x62', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', 'a'), ('b', 'b')]); + let expected = uclass(&[('\x00', '\x60'), ('\x63', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', 'c'), ('x', 'z')]); + let expected = uclass(&[ + ('\x00', '\x60'), ('\x64', '\x77'), ('\x7B', '\u{10FFFF}'), + ]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', 'a')]); + let expected = uclass(&[('\x62', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('a', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\x60')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{10FFFF}')]); + let expected = uclass(&[]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[]); + let expected = uclass(&[('\x00', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[ + ('\x00', '\u{10FFFD}'), ('\u{10FFFF}', '\u{10FFFF}'), + ]); + let expected = uclass(&[('\u{10FFFE}', '\u{10FFFE}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{D7FF}')]); + let expected = uclass(&[('\u{E000}', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\x00', '\u{D7FE}')]); + let expected = uclass(&[('\u{D7FF}', '\u{10FFFF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\u{E000}', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\u{D7FF}')]); + assert_eq!(expected, unegate(&cls)); + + let cls = uclass(&[('\u{E001}', '\u{10FFFF}')]); + let expected = uclass(&[('\x00', '\u{E000}')]); + assert_eq!(expected, unegate(&cls)); + } + + #[test] + fn class_negate_bytes() { + let cls = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'\x00', b'\x60'), (b'\x62', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'a'), (b'b', b'b')]); + let expected = bclass(&[(b'\x00', b'\x60'), (b'\x63', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'c'), (b'x', b'z')]); + let expected = bclass(&[ + (b'\x00', b'\x60'), (b'\x64', b'\x77'), (b'\x7B', b'\xFF'), + ]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'a')]); + let expected = bclass(&[(b'\x62', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'a', b'\xFF')]); + let expected = bclass(&[(b'\x00', b'\x60')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFF')]); + let expected = bclass(&[]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[]); + let expected = bclass(&[(b'\x00', b'\xFF')]); + assert_eq!(expected, bnegate(&cls)); + + let cls = bclass(&[(b'\x00', b'\xFD'), (b'\xFF', b'\xFF')]); + let expected = bclass(&[(b'\xFE', b'\xFE')]); + assert_eq!(expected, bnegate(&cls)); + } + + #[test] + fn class_union_unicode() { + let cls1 = uclass(&[('a', 'g'), ('m', 't'), ('A', 'C')]); + let cls2 = uclass(&[('a', 'z')]); + let expected = uclass(&[('a', 'z'), ('A', 'C')]); + assert_eq!(expected, uunion(&cls1, &cls2)); + } + + #[test] + fn class_union_bytes() { + let cls1 = bclass(&[(b'a', b'g'), (b'm', b't'), (b'A', b'C')]); + let cls2 = bclass(&[(b'a', b'z')]); + let expected = bclass(&[(b'a', b'z'), (b'A', b'C')]); + assert_eq!(expected, bunion(&cls1, &cls2)); + } + + #[test] + fn class_intersect_unicode() { + let cls1 = uclass(&[]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('b', 'b')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'c')]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('a', 'c')]); + let expected = uclass(&[('a', 'b')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('b', 'c')]); + let expected = uclass(&[('b', 'b')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b')]); + let cls2 = uclass(&[('c', 'd')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('b', 'c')]); + let cls2 = uclass(&[('a', 'd')]); + let expected = uclass(&[('b', 'c')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('a', 'h')]); + let expected = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let expected = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('g', 'h')]); + let cls2 = uclass(&[('d', 'e'), ('k', 'l')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('d', 'e'), ('g', 'h')]); + let cls2 = uclass(&[('h', 'h')]); + let expected = uclass(&[('h', 'h')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('e', 'f'), ('i', 'j')]); + let cls2 = uclass(&[('c', 'd'), ('g', 'h'), ('k', 'l')]); + let expected = uclass(&[]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'b'), ('c', 'd'), ('e', 'f')]); + let cls2 = uclass(&[('b', 'c'), ('d', 'e'), ('f', 'g')]); + let expected = uclass(&[('b', 'f')]); + assert_eq!(expected, uintersect(&cls1, &cls2)); + } + + #[test] + fn class_intersect_bytes() { + let cls1 = bclass(&[]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'b', b'b')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'c')]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'a', b'c')]); + let expected = bclass(&[(b'a', b'b')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'b', b'c')]); + let expected = bclass(&[(b'b', b'b')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b')]); + let cls2 = bclass(&[(b'c', b'd')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'b', b'c')]); + let cls2 = bclass(&[(b'a', b'd')]); + let expected = bclass(&[(b'b', b'c')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'a', b'h')]); + let expected = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let expected = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'g', b'h')]); + let cls2 = bclass(&[(b'd', b'e'), (b'k', b'l')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'd', b'e'), (b'g', b'h')]); + let cls2 = bclass(&[(b'h', b'h')]); + let expected = bclass(&[(b'h', b'h')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'e', b'f'), (b'i', b'j')]); + let cls2 = bclass(&[(b'c', b'd'), (b'g', b'h'), (b'k', b'l')]); + let expected = bclass(&[]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'b'), (b'c', b'd'), (b'e', b'f')]); + let cls2 = bclass(&[(b'b', b'c'), (b'd', b'e'), (b'f', b'g')]); + let expected = bclass(&[(b'b', b'f')]); + assert_eq!(expected, bintersect(&cls1, &cls2)); + } + + #[test] + fn class_difference_unicode() { + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'a')]); + let cls2 = uclass(&[]); + let expected = uclass(&[('a', 'a')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('a', 'a')]); + let expected = uclass(&[('b', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('z', 'z')]); + let expected = uclass(&[('a', 'y')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('m', 'm')]); + let expected = uclass(&[('a', 'l'), ('n', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('a', 'z')]); + let expected = uclass(&[]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('d', 'v')]); + let expected = uclass(&[('a', 'c')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('b', 'g'), ('s', 'u')]); + let expected = uclass(&[('a', 'a'), ('h', 'i'), ('r', 'r')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'c'), ('g', 'i'), ('r', 't')]); + let cls2 = uclass(&[('b', 'd'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('a', 'a'), ('h', 'i'), ('r', 'r')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('x', 'z')]); + let cls2 = uclass(&[('a', 'c'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('x', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + + let cls1 = uclass(&[('a', 'z')]); + let cls2 = uclass(&[('a', 'c'), ('e', 'g'), ('s', 'u')]); + let expected = uclass(&[('d', 'd'), ('h', 'r'), ('v', 'z')]); + assert_eq!(expected, udifference(&cls1, &cls2)); + } + + #[test] + fn class_difference_bytes() { + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'a')]); + let cls2 = bclass(&[]); + let expected = bclass(&[(b'a', b'a')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'a', b'a')]); + let expected = bclass(&[(b'b', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'z', b'z')]); + let expected = bclass(&[(b'a', b'y')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'm', b'm')]); + let expected = bclass(&[(b'a', b'l'), (b'n', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'a', b'z')]); + let expected = bclass(&[]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'd', b'v')]); + let expected = bclass(&[(b'a', b'c')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'b', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'a', b'a'), (b'h', b'i'), (b'r', b'r')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'c'), (b'g', b'i'), (b'r', b't')]); + let cls2 = bclass(&[(b'b', b'd'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'a', b'a'), (b'h', b'i'), (b'r', b'r')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'x', b'z')]); + let cls2 = bclass(&[(b'a', b'c'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'x', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + + let cls1 = bclass(&[(b'a', b'z')]); + let cls2 = bclass(&[(b'a', b'c'), (b'e', b'g'), (b's', b'u')]); + let expected = bclass(&[(b'd', b'd'), (b'h', b'r'), (b'v', b'z')]); + assert_eq!(expected, bdifference(&cls1, &cls2)); + } + + #[test] + fn class_symmetric_difference_unicode() { + let cls1 = uclass(&[('a', 'm')]); + let cls2 = uclass(&[('g', 't')]); + let expected = uclass(&[('a', 'f'), ('n', 't')]); + assert_eq!(expected, usymdifference(&cls1, &cls2)); + } + + #[test] + fn class_symmetric_difference_bytes() { + let cls1 = bclass(&[(b'a', b'm')]); + let cls2 = bclass(&[(b'g', b't')]); + let expected = bclass(&[(b'a', b'f'), (b'n', b't')]); + assert_eq!(expected, bsymdifference(&cls1, &cls2)); + } + + #[test] + #[should_panic] + fn hir_byte_literal_non_ascii() { + Hir::literal(Literal::Byte(b'a')); + } + + // We use a thread with an explicit stack size to test that our destructor + // for Hir can handle arbitrarily sized expressions in constant stack + // space. In case we run on a platform without threads (WASM?), we limit + // this test to Windows/Unix. + #[test] + #[cfg(any(unix, windows))] + fn no_stack_overflow_on_drop() { + use std::thread; + + let run = || { + let mut expr = Hir::empty(); + for _ in 0..100 { + expr = Hir::group(Group { + kind: GroupKind::NonCapturing, + hir: Box::new(expr), + }); + expr = Hir::repetition(Repetition { + kind: RepetitionKind::ZeroOrOne, + greedy: true, + hir: Box::new(expr), + }); + + expr = Hir { + kind: HirKind::Concat(vec![expr]), + info: HirInfo::new(), + }; + expr = Hir { + kind: HirKind::Alternation(vec![expr]), + info: HirInfo::new(), + }; + } + assert!(!expr.kind.is_empty()); + }; + + // We run our test on a thread with a small stack size so we can + // force the issue more easily. + thread::Builder::new() + .stack_size(1<<10) + .spawn(run) + .unwrap() + .join() + .unwrap(); + } +} diff --git a/regex-syntax/src/hir/print.rs b/regex-syntax/src/hir/print.rs new file mode 100644 index 000000000..e312d8852 --- /dev/null +++ b/regex-syntax/src/hir/print.rs @@ -0,0 +1,375 @@ +/*! +This module provides a regular expression printer for `Hir`. +*/ + +use std::fmt; + +use hir::{self, Hir, HirKind}; +use hir::visitor::{self, Visitor}; +use is_meta_character; + +/// A builder for constructing a printer. +/// +/// Note that since a printer doesn't have any configuration knobs, this type +/// remains unexported. +#[derive(Clone, Debug)] +struct PrinterBuilder { + _priv: (), +} + +impl Default for PrinterBuilder { + fn default() -> PrinterBuilder { + PrinterBuilder::new() + } +} + +impl PrinterBuilder { + fn new() -> PrinterBuilder { + PrinterBuilder { + _priv: (), + } + } + + fn build(&self) -> Printer { + Printer { + _priv: (), + } + } +} + +/// A printer for a regular expression's high-level intermediate +/// representation. +/// +/// A printer converts a high-level intermediate representation (HIR) to a +/// regular expression pattern string. This particular printer uses constant +/// stack space and heap space proportional to the size of the HIR. +/// +/// Since this printer is only using the HIR, the pattern it prints will likely +/// not resemble the original pattern at all. For example, a pattern like +/// `\pL` will have its entire class written out. +/// +/// The purpose of this printer is to provide a means to mutate an HIR and then +/// build a regular expression from the result of that mutation. (A regex +/// library could provide a constructor from this HIR explicitly, but that +/// creates an unnecessary public coupling between the regex library and this +/// specific HIR representation.) +#[derive(Debug)] +pub struct Printer { + _priv: (), +} + +impl Printer { + /// Create a new printer. + pub fn new() -> Printer { + PrinterBuilder::new().build() + } + + /// Print the given `Ast` to the given writer. The writer must implement + /// `fmt::Write`. Typical implementations of `fmt::Write` that can be used + /// here are a `fmt::Formatter` (which is available in `fmt::Display` + /// implementations) or a `&mut String`. + pub fn print<W: fmt::Write>(&mut self, hir: &Hir, wtr: W) -> fmt::Result { + visitor::visit(hir, Writer { printer: self, wtr: wtr }) + } +} + +#[derive(Debug)] +struct Writer<'p, W> { + printer: &'p mut Printer, + wtr: W, +} + +impl<'p, W: fmt::Write> Visitor for Writer<'p, W> { + type Output = (); + type Err = fmt::Error; + + fn finish(self) -> fmt::Result { + Ok(()) + } + + fn visit_pre(&mut self, hir: &Hir) -> fmt::Result { + match *hir.kind() { + HirKind::Empty + | HirKind::Repetition(_) + | HirKind::Concat(_) + | HirKind::Alternation(_) => {} + HirKind::Literal(hir::Literal::Unicode(c)) => { + self.write_literal_char(c)?; + } + HirKind::Literal(hir::Literal::Byte(b)) => { + self.write_literal_byte(b)?; + } + HirKind::Class(hir::Class::Unicode(ref cls)) => { + self.wtr.write_str("[")?; + for range in cls.iter() { + if range.start() == range.end() { + self.write_literal_char(range.start())?; + } else { + self.write_literal_char(range.start())?; + self.wtr.write_str("-")?; + self.write_literal_char(range.end())?; + } + } + self.wtr.write_str("]")?; + } + HirKind::Class(hir::Class::Bytes(ref cls)) => { + self.wtr.write_str("(?-u:[")?; + for range in cls.iter() { + if range.start() == range.end() { + self.write_literal_class_byte(range.start())?; + } else { + self.write_literal_class_byte(range.start())?; + self.wtr.write_str("-")?; + self.write_literal_class_byte(range.end())?; + } + } + self.wtr.write_str("])")?; + } + HirKind::Anchor(hir::Anchor::StartLine) => { + self.wtr.write_str("(?m:^)")?; + } + HirKind::Anchor(hir::Anchor::EndLine) => { + self.wtr.write_str("(?m:$)")?; + } + HirKind::Anchor(hir::Anchor::StartText) => { + self.wtr.write_str(r"\A")?; + } + HirKind::Anchor(hir::Anchor::EndText) => { + self.wtr.write_str(r"\z")?; + } + HirKind::WordBoundary(hir::WordBoundary::Unicode) => { + self.wtr.write_str(r"\b")?; + } + HirKind::WordBoundary(hir::WordBoundary::UnicodeNegate) => { + self.wtr.write_str(r"\B")?; + } + HirKind::WordBoundary(hir::WordBoundary::Ascii) => { + self.wtr.write_str(r"(?-u:\b)")?; + } + HirKind::WordBoundary(hir::WordBoundary::AsciiNegate) => { + self.wtr.write_str(r"(?-u:\B)")?; + } + HirKind::Group(ref x) => { + match x.kind { + hir::GroupKind::CaptureIndex(_) => { + self.wtr.write_str("(")?; + } + hir::GroupKind::CaptureName { ref name, .. } => { + write!(self.wtr, "(?P<{}>", name)?; + } + hir::GroupKind::NonCapturing => { + self.wtr.write_str("(?:")?; + } + } + } + } + Ok(()) + } + + fn visit_post(&mut self, hir: &Hir) -> fmt::Result { + match *hir.kind() { + // Handled during visit_pre + HirKind::Empty + | HirKind::Literal(_) + | HirKind::Class(_) + | HirKind::Anchor(_) + | HirKind::WordBoundary(_) + | HirKind::Concat(_) + | HirKind::Alternation(_) => {} + HirKind::Repetition(ref x) => { + match x.kind { + hir::RepetitionKind::ZeroOrOne => { + self.wtr.write_str("?")?; + } + hir::RepetitionKind::ZeroOrMore => { + self.wtr.write_str("*")?; + } + hir::RepetitionKind::OneOrMore => { + self.wtr.write_str("+")?; + } + hir::RepetitionKind::Range(ref x) => { + match *x { + hir::RepetitionRange::Exactly(m) => { + write!(self.wtr, "{{{}}}", m)?; + } + hir::RepetitionRange::AtLeast(m) => { + write!(self.wtr, "{{{},}}", m)?; + } + hir::RepetitionRange::Bounded(m, n) => { + write!(self.wtr, "{{{},{}}}", m, n)?; + } + } + } + } + if !x.greedy { + self.wtr.write_str("?")?; + } + } + HirKind::Group(_) => { + self.wtr.write_str(")")?; + } + } + Ok(()) + } + + fn visit_alternation_in(&mut self) -> fmt::Result { + self.wtr.write_str("|") + } +} + +impl<'p, W: fmt::Write> Writer<'p, W> { + fn write_literal_char(&mut self, c: char) -> fmt::Result { + if is_meta_character(c) { + self.wtr.write_str("\\")?; + } + self.wtr.write_char(c) + } + + fn write_literal_byte(&mut self, b: u8) -> fmt::Result { + let c = b as char; + if c <= 0x7F as char && !c.is_control() && !c.is_whitespace() { + self.write_literal_char(c) + } else { + write!(self.wtr, "(?-u:\\x{:02X})", b) + } + } + + fn write_literal_class_byte(&mut self, b: u8) -> fmt::Result { + let c = b as char; + if c <= 0x7F as char && !c.is_control() && !c.is_whitespace() { + self.write_literal_char(c) + } else { + write!(self.wtr, "\\x{:02X}", b) + } + } +} + +#[cfg(test)] +mod tests { + use ParserBuilder; + use super::Printer; + + fn roundtrip(given: &str, expected: &str) { + roundtrip_with(|b| b, given, expected); + } + + fn roundtrip_bytes(given: &str, expected: &str) { + roundtrip_with(|b| b.allow_invalid_utf8(true), given, expected); + } + + fn roundtrip_with<F>(mut f: F, given: &str, expected: &str) + where F: FnMut(&mut ParserBuilder) -> &mut ParserBuilder + { + let mut builder = ParserBuilder::new(); + f(&mut builder); + let hir = builder.build().parse(given).unwrap(); + + let mut printer = Printer::new(); + let mut dst = String::new(); + printer.print(&hir, &mut dst).unwrap(); + + // Check that the result is actually valid. + builder.build().parse(&dst).unwrap(); + + assert_eq!(expected, dst); + } + + #[test] + fn print_literal() { + roundtrip("a", "a"); + roundtrip(r"\xff", "\u{FF}"); + roundtrip_bytes(r"\xff", "\u{FF}"); + roundtrip_bytes(r"(?-u)\xff", r"(?-u:\xFF)"); + roundtrip("☃", "☃"); + } + + #[test] + fn print_class() { + roundtrip(r"[a]", r"[a]"); + roundtrip(r"[a-z]", r"[a-z]"); + roundtrip(r"[a-z--b-c--x-y]", r"[ad-wz]"); + roundtrip(r"[^\x01-\u{10FFFF}]", "[\u{0}]"); + roundtrip(r"[-]", r"[\-]"); + roundtrip(r"[☃-⛄]", r"[☃-⛄]"); + + roundtrip(r"(?-u)[a]", r"(?-u:[a])"); + roundtrip(r"(?-u)[a-z]", r"(?-u:[a-z])"); + roundtrip_bytes(r"(?-u)[a-\xFF]", r"(?-u:[a-\xFF])"); + + // The following test that the printer escapes meta characters + // in character classes. + roundtrip(r"[\[]", r"[\[]"); + roundtrip(r"[Z-_]", r"[Z-_]"); + roundtrip(r"[Z-_--Z]", r"[\[-_]"); + + // The following test that the printer escapes meta characters + // in byte oriented character classes. + roundtrip_bytes(r"(?-u)[\[]", r"(?-u:[\[])"); + roundtrip_bytes(r"(?-u)[Z-_]", r"(?-u:[Z-_])"); + roundtrip_bytes(r"(?-u)[Z-_--Z]", r"(?-u:[\[-_])"); + } + + #[test] + fn print_anchor() { + roundtrip(r"^", r"\A"); + roundtrip(r"$", r"\z"); + roundtrip(r"(?m)^", r"(?m:^)"); + roundtrip(r"(?m)$", r"(?m:$)"); + } + + #[test] + fn print_word_boundary() { + roundtrip(r"\b", r"\b"); + roundtrip(r"\B", r"\B"); + roundtrip(r"(?-u)\b", r"(?-u:\b)"); + roundtrip_bytes(r"(?-u)\B", r"(?-u:\B)"); + } + + #[test] + fn print_repetition() { + roundtrip("a?", "a?"); + roundtrip("a??", "a??"); + roundtrip("(?U)a?", "a??"); + + roundtrip("a*", "a*"); + roundtrip("a*?", "a*?"); + roundtrip("(?U)a*", "a*?"); + + roundtrip("a+", "a+"); + roundtrip("a+?", "a+?"); + roundtrip("(?U)a+", "a+?"); + + roundtrip("a{1}", "a{1}"); + roundtrip("a{1,}", "a{1,}"); + roundtrip("a{1,5}", "a{1,5}"); + roundtrip("a{1}?", "a{1}?"); + roundtrip("a{1,}?", "a{1,}?"); + roundtrip("a{1,5}?", "a{1,5}?"); + roundtrip("(?U)a{1}", "a{1}?"); + roundtrip("(?U)a{1,}", "a{1,}?"); + roundtrip("(?U)a{1,5}", "a{1,5}?"); + } + + #[test] + fn print_group() { + roundtrip("()", "()"); + roundtrip("(?P<foo>)", "(?P<foo>)"); + roundtrip("(?:)", "(?:)"); + + roundtrip("(a)", "(a)"); + roundtrip("(?P<foo>a)", "(?P<foo>a)"); + roundtrip("(?:a)", "(?:a)"); + + roundtrip("((((a))))", "((((a))))"); + } + + #[test] + fn print_alternation() { + roundtrip("|", "|"); + roundtrip("||", "||"); + + roundtrip("a|b", "a|b"); + roundtrip("a|b|c", "a|b|c"); + roundtrip("foo|bar|quux", "foo|bar|quux"); + } +} diff --git a/regex-syntax/src/hir/translate.rs b/regex-syntax/src/hir/translate.rs new file mode 100644 index 000000000..c2afd98f7 --- /dev/null +++ b/regex-syntax/src/hir/translate.rs @@ -0,0 +1,2646 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Defines a translator that converts an `Ast` to an `Hir`. +*/ + +use std::cell::{Cell, RefCell}; +use std::result; + +use ast::{self, Ast, Span, Visitor}; +use hir::{self, Error, ErrorKind, Hir}; +use unicode::{self, ClassQuery}; + +type Result<T> = result::Result<T, Error>; + +/// A builder for constructing an AST->HIR translator. +#[derive(Clone, Debug)] +pub struct TranslatorBuilder { + allow_invalid_utf8: bool, + flags: Flags, +} + +impl Default for TranslatorBuilder { + fn default() -> TranslatorBuilder { + TranslatorBuilder::new() + } +} + +impl TranslatorBuilder { + /// Create a new translator builder with a default c onfiguration. + pub fn new() -> TranslatorBuilder { + TranslatorBuilder { + allow_invalid_utf8: false, + flags: Flags::default(), + } + } + + /// Build a translator using the current configuration. + pub fn build(&self) -> Translator { + Translator { + stack: RefCell::new(vec![]), + flags: Cell::new(self.flags), + allow_invalid_utf8: self.allow_invalid_utf8, + } + } + + /// When enabled, translation will permit the construction of a regular + /// expression that may match invalid UTF-8. + /// + /// When disabled (the default), the translator is guaranteed to produce + /// an expression that will only ever match valid UTF-8 (otherwise, the + /// translator will return an error). + /// + /// Perhaps surprisingly, when invalid UTF-8 isn't allowed, a negated ASCII + /// word boundary (uttered as `(?-u:\B)` in the concrete syntax) will cause + /// the parser to return an error. Namely, a negated ASCII word boundary + /// can result in matching positions that aren't valid UTF-8 boundaries. + pub fn allow_invalid_utf8( + &mut self, + yes: bool, + ) -> &mut TranslatorBuilder { + self.allow_invalid_utf8 = yes; + self + } + + /// Enable or disable the case insensitive flag (`i`) by default. + pub fn case_insensitive(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.case_insensitive = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the multi-line matching flag (`m`) by default. + pub fn multi_line(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.multi_line = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the "dot matches any character" flag (`s`) by + /// default. + pub fn dot_matches_new_line( + &mut self, + yes: bool, + ) -> &mut TranslatorBuilder { + self.flags.dot_matches_new_line = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the "swap greed" flag (`U`) by default. + pub fn swap_greed(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.swap_greed = if yes { Some(true) } else { None }; + self + } + + /// Enable or disable the Unicode flag (`u`) by default. + pub fn unicode(&mut self, yes: bool) -> &mut TranslatorBuilder { + self.flags.unicode = if yes { None } else { Some(false) }; + self + } +} + +/// A translator maps abstract syntax to a high level intermediate +/// representation. +/// +/// A translator may be benefit from reuse. That is, a translator can translate +/// many abstract syntax trees. +/// +/// A `Translator` can be configured in more detail via a +/// [`TranslatorBuilder`](struct.TranslatorBuilder.html). +#[derive(Clone, Debug)] +pub struct Translator { + /// Our call stack, but on the heap. + stack: RefCell<Vec<HirFrame>>, + /// The current flag settings. + flags: Cell<Flags>, + /// Whether we're allowed to produce HIR that can match arbitrary bytes. + allow_invalid_utf8: bool, +} + +impl Translator { + /// Create a new translator using the default configuration. + pub fn new() -> Translator { + TranslatorBuilder::new().build() + } + + /// Translate the given abstract syntax tree (AST) into a high level + /// intermediate representation (HIR). + /// + /// If there was a problem doing the translation, then an HIR-specific + /// error is returned. + /// + /// The original pattern string used to produce the `Ast` *must* also be + /// provided. The translator does not use the pattern string during any + /// correct translation, but is used for error reporting. + pub fn translate(&mut self, pattern: &str, ast: &Ast) -> Result<Hir> { + ast::visit(ast, TranslatorI::new(self, pattern)) + } +} + +/// An HirFrame is a single stack frame, represented explicitly, which is +/// created for each item in the Ast that we traverse. +/// +/// Note that technically, this type doesn't represent our entire stack +/// frame. In particular, the Ast visitor represents any state associated with +/// traversing the Ast itself. +#[derive(Clone, Debug)] +enum HirFrame { + /// An arbitrary HIR expression. These get pushed whenever we hit a base + /// case in the Ast. They get popped after an inductive (i.e., recursive) + /// step is complete. + Expr(Hir), + /// A Unicode character class. This frame is mutated as we descend into + /// the Ast of a character class (which is itself its own mini recursive + /// structure). + ClassUnicode(hir::ClassUnicode), + /// A byte-oriented character class. This frame is mutated as we descend + /// into the Ast of a character class (which is itself its own mini + /// recursive structure). + /// + /// Byte character classes are created when Unicode mode (`u`) is disabled. + /// If `allow_invalid_utf8` is disabled (the default), then a byte + /// character is only permitted to match ASCII text. + ClassBytes(hir::ClassBytes), + /// This is pushed on to the stack upon first seeing any kind of group, + /// indicated by parentheses (including non-capturing groups). It is popped + /// upon leaving a group. + Group { + /// The old active flags, if any, when this group was opened. + /// + /// If this group sets flags, then the new active flags are set to the + /// result of merging the old flags with the flags introduced by this + /// group. + /// + /// When this group is popped, the active flags should be restored to + /// the flags set here. + /// + /// The "active" flags correspond to whatever flags are set in the + /// Translator. + old_flags: Option<Flags>, + }, + /// This is pushed whenever a concatenation is observed. After visiting + /// every sub-expression in the concatenation, the translator's stack is + /// popped until it sees a Concat frame. + Concat, + /// This is pushed whenever an alternation is observed. After visiting + /// every sub-expression in the alternation, the translator's stack is + /// popped until it sees an Alternation frame. + Alternation, +} + +impl HirFrame { + /// Assert that the current stack frame is an Hir expression and return it. + fn unwrap_expr(self) -> Hir { + match self { + HirFrame::Expr(expr) => expr, + _ => panic!("tried to unwrap expr from HirFrame, got: {:?}", self) + } + } + + /// Assert that the current stack frame is a Unicode class expression and + /// return it. + fn unwrap_class_unicode(self) -> hir::ClassUnicode { + match self { + HirFrame::ClassUnicode(cls) => cls, + _ => panic!("tried to unwrap Unicode class \ + from HirFrame, got: {:?}", self) + } + } + + /// Assert that the current stack frame is a byte class expression and + /// return it. + fn unwrap_class_bytes(self) -> hir::ClassBytes { + match self { + HirFrame::ClassBytes(cls) => cls, + _ => panic!("tried to unwrap byte class \ + from HirFrame, got: {:?}", self) + } + } + + /// Assert that the current stack frame is a group indicator and return + /// its corresponding flags (the flags that were active at the time the + /// group was entered) if they exist. + fn unwrap_group(self) -> Option<Flags> { + match self { + HirFrame::Group { old_flags } => old_flags, + _ => panic!("tried to unwrap group from HirFrame, got: {:?}", self) + } + } +} + +impl<'t, 'p> Visitor for TranslatorI<'t, 'p> { + type Output = Hir; + type Err = Error; + + fn finish(self) -> Result<Hir> { + // ... otherwise, we should have exactly one HIR on the stack. + assert_eq!(self.trans().stack.borrow().len(), 1); + Ok(self.pop().unwrap().unwrap_expr()) + } + + fn visit_pre(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Class(ast::Class::Bracketed(_)) => { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + } + Ast::Group(ref x) => { + let old_flags = x.flags().map(|ast| self.set_flags(ast)); + self.push(HirFrame::Group { + old_flags: old_flags, + }); + } + Ast::Concat(ref x) if x.asts.is_empty() => {} + Ast::Concat(_) => { + self.push(HirFrame::Concat); + } + Ast::Alternation(ref x) if x.asts.is_empty() => {} + Ast::Alternation(_) => { + self.push(HirFrame::Alternation); + } + _ => {} + } + Ok(()) + } + + fn visit_post(&mut self, ast: &Ast) -> Result<()> { + match *ast { + Ast::Empty(_) => { + self.push(HirFrame::Expr(Hir::empty())); + } + Ast::Flags(ref x) => { + self.set_flags(&x.flags); + // Flags in the AST are generally considered directives and + // not actual sub-expressions. However, they can be used in + // the concrete syntax like `((?i))`, and we need some kind of + // indication of an expression there, and Empty is the correct + // choice. + // + // There can also be things like `(?i)+`, but we rule those out + // in the parser. In the future, we might allow them for + // consistency sake. + self.push(HirFrame::Expr(Hir::empty())); + } + Ast::Literal(ref x) => { + self.push(HirFrame::Expr(self.hir_literal(x)?)); + } + Ast::Dot(span) => { + self.push(HirFrame::Expr(self.hir_dot(span)?)); + } + Ast::Assertion(ref x) => { + self.push(HirFrame::Expr(self.hir_assertion(x)?)); + } + Ast::Class(ast::Class::Perl(ref x)) => { + if self.flags().unicode() { + let cls = self.hir_perl_unicode_class(x); + let hcls = hir::Class::Unicode(cls); + self.push(HirFrame::Expr(Hir::class(hcls))); + } else { + let cls = self.hir_perl_byte_class(x); + let hcls = hir::Class::Bytes(cls); + self.push(HirFrame::Expr(Hir::class(hcls))); + } + } + Ast::Class(ast::Class::Unicode(ref x)) => { + let cls = hir::Class::Unicode(self.hir_unicode_class(x)?); + self.push(HirFrame::Expr(Hir::class(cls))); + } + Ast::Class(ast::Class::Bracketed(ref ast)) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + self.unicode_fold_and_negate(ast.negated, &mut cls); + if cls.iter().next().is_none() { + return Err(self.error( + ast.span, ErrorKind::EmptyClassNotAllowed)); + } + let expr = Hir::class(hir::Class::Unicode(cls)); + self.push(HirFrame::Expr(expr)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + self.bytes_fold_and_negate( + &ast.span, ast.negated, &mut cls)?; + if cls.iter().next().is_none() { + return Err(self.error( + ast.span, ErrorKind::EmptyClassNotAllowed)); + } + + let expr = Hir::class(hir::Class::Bytes(cls)); + self.push(HirFrame::Expr(expr)); + } + } + Ast::Repetition(ref x) => { + let expr = self.pop().unwrap().unwrap_expr(); + self.push(HirFrame::Expr(self.hir_repetition(x, expr))); + } + Ast::Group(ref x) => { + let expr = self.pop().unwrap().unwrap_expr(); + if let Some(flags) = self.pop().unwrap().unwrap_group() { + self.trans().flags.set(flags); + } + self.push(HirFrame::Expr(self.hir_group(x, expr))); + } + Ast::Concat(_) => { + let mut exprs = vec![]; + while let Some(HirFrame::Expr(expr)) = self.pop() { + if !expr.kind().is_empty() { + exprs.push(expr); + } + } + exprs.reverse(); + self.push(HirFrame::Expr(Hir::concat(exprs))); + } + Ast::Alternation(_) => { + let mut exprs = vec![]; + while let Some(HirFrame::Expr(expr)) = self.pop() { + exprs.push(expr); + } + exprs.reverse(); + self.push(HirFrame::Expr(Hir::alternation(exprs))); + } + } + Ok(()) + } + + fn visit_class_set_item_pre( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Bracketed(_) => { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + } + // We needn't handle the Union case here since the visitor will + // do it for us. + _ => {} + } + Ok(()) + } + + fn visit_class_set_item_post( + &mut self, + ast: &ast::ClassSetItem, + ) -> Result<()> { + match *ast { + ast::ClassSetItem::Empty(_) => {} + ast::ClassSetItem::Literal(ref x) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.push(hir::ClassUnicodeRange::new(x.c, x.c)); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + let byte = self.class_literal_byte(x)?; + cls.push(hir::ClassBytesRange::new(byte, byte)); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Range(ref x) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.push(hir::ClassUnicodeRange::new(x.start.c, x.end.c)); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + let start = self.class_literal_byte(&x.start)?; + let end = self.class_literal_byte(&x.end)?; + cls.push(hir::ClassBytesRange::new(start, end)); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Ascii(ref x) => { + if self.flags().unicode() { + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + for &(s, e) in ascii_class(&x.kind) { + cls.push(hir::ClassUnicodeRange::new(s, e)); + } + self.unicode_fold_and_negate(x.negated, &mut cls); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + for &(s, e) in ascii_class(&x.kind) { + cls.push(hir::ClassBytesRange::new(s as u8, e as u8)); + } + self.bytes_fold_and_negate( + &x.span, x.negated, &mut cls)?; + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Unicode(ref x) => { + let xcls = self.hir_unicode_class(x)?; + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.union(&xcls); + self.push(HirFrame::ClassUnicode(cls)); + } + ast::ClassSetItem::Perl(ref x) => { + if self.flags().unicode() { + let xcls = self.hir_perl_unicode_class(x); + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + cls.union(&xcls); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let xcls = self.hir_perl_byte_class(x); + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + cls.union(&xcls); + self.push(HirFrame::ClassBytes(cls)); + } + } + ast::ClassSetItem::Bracketed(ref ast) => { + if self.flags().unicode() { + let mut cls1 = self.pop().unwrap().unwrap_class_unicode(); + self.unicode_fold_and_negate(ast.negated, &mut cls1); + + let mut cls2 = self.pop().unwrap().unwrap_class_unicode(); + cls2.union(&cls1); + self.push(HirFrame::ClassUnicode(cls2)); + } else { + let mut cls1 = self.pop().unwrap().unwrap_class_bytes(); + self.bytes_fold_and_negate( + &ast.span, ast.negated, &mut cls1)?; + + let mut cls2 = self.pop().unwrap().unwrap_class_bytes(); + cls2.union(&cls1); + self.push(HirFrame::ClassBytes(cls2)); + } + } + // This is handled automatically by the visitor. + ast::ClassSetItem::Union(_) => {} + } + Ok(()) + } + + fn visit_class_set_binary_op_pre( + &mut self, + _op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } + + fn visit_class_set_binary_op_in( + &mut self, + _op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + if self.flags().unicode() { + let cls = hir::ClassUnicode::empty(); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let cls = hir::ClassBytes::empty(); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } + + fn visit_class_set_binary_op_post( + &mut self, + op: &ast::ClassSetBinaryOp, + ) -> Result<()> { + use ast::ClassSetBinaryOpKind::*; + + if self.flags().unicode() { + let mut rhs = self.pop().unwrap().unwrap_class_unicode(); + let mut lhs = self.pop().unwrap().unwrap_class_unicode(); + let mut cls = self.pop().unwrap().unwrap_class_unicode(); + if self.flags().case_insensitive() { + rhs.case_fold_simple(); + lhs.case_fold_simple(); + } + match op.kind { + Intersection => lhs.intersect(&rhs), + Difference => lhs.difference(&rhs), + SymmetricDifference => lhs.symmetric_difference(&rhs), + } + cls.union(&lhs); + self.push(HirFrame::ClassUnicode(cls)); + } else { + let mut rhs = self.pop().unwrap().unwrap_class_bytes(); + let mut lhs = self.pop().unwrap().unwrap_class_bytes(); + let mut cls = self.pop().unwrap().unwrap_class_bytes(); + if self.flags().case_insensitive() { + rhs.case_fold_simple(); + lhs.case_fold_simple(); + } + match op.kind { + Intersection => lhs.intersect(&rhs), + Difference => lhs.difference(&rhs), + SymmetricDifference => lhs.symmetric_difference(&rhs), + } + cls.union(&lhs); + self.push(HirFrame::ClassBytes(cls)); + } + Ok(()) + } +} + +/// The internal implementation of a translator. +/// +/// This type is responsible for carrying around the original pattern string, +/// which is not tied to the internal state of a translator. +/// +/// A TranslatorI exists for the time it takes to translate a single Ast. +#[derive(Clone, Debug)] +struct TranslatorI<'t, 'p> { + trans: &'t Translator, + pattern: &'p str, +} + +impl<'t, 'p> TranslatorI<'t, 'p> { + /// Build a new internal translator. + fn new(trans: &'t Translator, pattern: &'p str) -> TranslatorI<'t, 'p> { + TranslatorI { trans: trans, pattern: pattern } + } + + /// Return a reference to the underlying translator. + fn trans(&self) -> &Translator { + &self.trans + } + + /// Push the given frame on to the call stack. + fn push(&self, frame: HirFrame) { + self.trans().stack.borrow_mut().push(frame); + } + + /// Pop the top of the call stack. If the call stack is empty, return None. + fn pop(&self) -> Option<HirFrame> { + self.trans().stack.borrow_mut().pop() + } + + /// Create a new error with the given span and error type. + fn error(&self, span: Span, kind: ErrorKind) -> Error { + Error { kind: kind, pattern: self.pattern.to_string(), span: span } + } + + /// Return a copy of the active flags. + fn flags(&self) -> Flags { + self.trans().flags.get() + } + + /// Set the flags of this translator from the flags set in the given AST. + /// Then, return the old flags. + fn set_flags(&self, ast_flags: &ast::Flags) -> Flags { + let old_flags = self.flags(); + let mut new_flags = Flags::from_ast(ast_flags); + new_flags.merge(&old_flags); + self.trans().flags.set(new_flags); + old_flags + } + + fn hir_literal(&self, lit: &ast::Literal) -> Result<Hir> { + let ch = match self.literal_to_char(lit)? { + byte @ hir::Literal::Byte(_) => return Ok(Hir::literal(byte)), + hir::Literal::Unicode(ch) => ch, + }; + if self.flags().case_insensitive() { + self.hir_from_char_case_insensitive(lit.span, ch) + } else { + self.hir_from_char(lit.span, ch) + } + } + + /// Convert an Ast literal to its scalar representation. + /// + /// When Unicode mode is enabled, then this always succeeds and returns a + /// `char` (Unicode scalar value). + /// + /// When Unicode mode is disabled, then a raw byte is returned. If that + /// byte is not ASCII and invalid UTF-8 is not allowed, then this returns + /// an error. + fn literal_to_char(&self, lit: &ast::Literal) -> Result<hir::Literal> { + if self.flags().unicode() { + return Ok(hir::Literal::Unicode(lit.c)); + } + let byte = match lit.byte() { + None => return Ok(hir::Literal::Unicode(lit.c)), + Some(byte) => byte, + }; + if byte <= 0x7F { + return Ok(hir::Literal::Unicode(byte as char)); + } + if !self.trans().allow_invalid_utf8 { + return Err(self.error(lit.span, ErrorKind::InvalidUtf8)); + } + Ok(hir::Literal::Byte(byte)) + } + + fn hir_from_char(&self, span: Span, c: char) -> Result<Hir> { + if !self.flags().unicode() && c.len_utf8() > 1 { + return Err(self.error(span, ErrorKind::UnicodeNotAllowed)); + } + Ok(Hir::literal(hir::Literal::Unicode(c))) + } + + fn hir_from_char_case_insensitive( + &self, + span: Span, + c: char, + ) -> Result<Hir> { + // If case folding won't do anything, then don't bother trying. + if !unicode::contains_simple_case_mapping(c, c) { + return self.hir_from_char(span, c); + } + if self.flags().unicode() { + let mut cls = hir::ClassUnicode::new(vec![ + hir::ClassUnicodeRange::new(c, c), + ]); + cls.case_fold_simple(); + Ok(Hir::class(hir::Class::Unicode(cls))) + } else { + if c.len_utf8() > 1 { + return Err(self.error(span, ErrorKind::UnicodeNotAllowed)); + } + let mut cls = hir::ClassBytes::new(vec![ + hir::ClassBytesRange::new(c as u8, c as u8), + ]); + cls.case_fold_simple(); + Ok(Hir::class(hir::Class::Bytes(cls))) + } + } + + fn hir_dot(&self, span: Span) -> Result<Hir> { + let unicode = self.flags().unicode(); + if !unicode && !self.trans().allow_invalid_utf8 { + return Err(self.error(span, ErrorKind::InvalidUtf8)); + } + Ok(if self.flags().dot_matches_new_line() { + Hir::any(!unicode) + } else { + Hir::dot(!unicode) + }) + } + + fn hir_assertion(&self, asst: &ast::Assertion) -> Result<Hir> { + let unicode = self.flags().unicode(); + let multi_line = self.flags().multi_line(); + Ok(match asst.kind { + ast::AssertionKind::StartLine => { + Hir::anchor(if multi_line { + hir::Anchor::StartLine + } else { + hir::Anchor::StartText + }) + } + ast::AssertionKind::EndLine => { + Hir::anchor(if multi_line { + hir::Anchor::EndLine + } else { + hir::Anchor::EndText + }) + } + ast::AssertionKind::StartText => { + Hir::anchor(hir::Anchor::StartText) + } + ast::AssertionKind::EndText => { + Hir::anchor(hir::Anchor::EndText) + } + ast::AssertionKind::WordBoundary => { + Hir::word_boundary(if unicode { + hir::WordBoundary::Unicode + } else { + hir::WordBoundary::Ascii + }) + } + ast::AssertionKind::NotWordBoundary => { + Hir::word_boundary(if unicode { + hir::WordBoundary::UnicodeNegate + } else { + // It is possible for negated ASCII word boundaries to + // match at invalid UTF-8 boundaries, even when searching + // valid UTF-8. + if !self.trans().allow_invalid_utf8 { + return Err(self.error( + asst.span, ErrorKind::InvalidUtf8)); + } + hir::WordBoundary::AsciiNegate + }) + } + }) + } + + fn hir_group(&self, group: &ast::Group, expr: Hir) -> Hir { + let kind = match group.kind { + ast::GroupKind::CaptureIndex(idx) => { + hir::GroupKind::CaptureIndex(idx) + } + ast::GroupKind::CaptureName(ref capname) => { + hir::GroupKind::CaptureName { + name: capname.name.clone(), + index: capname.index, + } + } + ast::GroupKind::NonCapturing(_) => hir::GroupKind::NonCapturing, + }; + Hir::group(hir::Group { + kind: kind, + hir: Box::new(expr), + }) + } + + fn hir_repetition(&self, rep: &ast::Repetition, expr: Hir) -> Hir { + let kind = match rep.op.kind { + ast::RepetitionKind::ZeroOrOne => hir::RepetitionKind::ZeroOrOne, + ast::RepetitionKind::ZeroOrMore => hir::RepetitionKind::ZeroOrMore, + ast::RepetitionKind::OneOrMore => hir::RepetitionKind::OneOrMore, + ast::RepetitionKind::Range(ast::RepetitionRange::Exactly(m)) => { + hir::RepetitionKind::Range(hir::RepetitionRange::Exactly(m)) + } + ast::RepetitionKind::Range(ast::RepetitionRange::AtLeast(m)) => { + hir::RepetitionKind::Range(hir::RepetitionRange::AtLeast(m)) + } + ast::RepetitionKind::Range(ast::RepetitionRange::Bounded(m,n)) => { + hir::RepetitionKind::Range(hir::RepetitionRange::Bounded(m, n)) + } + }; + let greedy = + if self.flags().swap_greed() { + !rep.greedy + } else { + rep.greedy + }; + Hir::repetition(hir::Repetition { + kind: kind, + greedy: greedy, + hir: Box::new(expr), + }) + } + + fn hir_unicode_class( + &self, + ast_class: &ast::ClassUnicode, + ) -> Result<hir::ClassUnicode> { + use ast::ClassUnicodeKind::*; + + if !self.flags().unicode() { + return Err(self.error( + ast_class.span, + ErrorKind::UnicodeNotAllowed, + )); + } + let query = match ast_class.kind { + OneLetter(name) => ClassQuery::OneLetter(name), + Named(ref name) => ClassQuery::Binary(name), + NamedValue { ref name, ref value, .. } => { + ClassQuery::ByValue { + property_name: name, + property_value: value, + } + } + }; + match unicode::class(query) { + Ok(mut class) => { + self.unicode_fold_and_negate(ast_class.negated, &mut class); + Ok(class) + } + Err(unicode::Error::PropertyNotFound) => { + Err(self.error( + ast_class.span, + ErrorKind::UnicodePropertyNotFound, + )) + } + Err(unicode::Error::PropertyValueNotFound) => { + Err(self.error( + ast_class.span, + ErrorKind::UnicodePropertyValueNotFound, + )) + } + } + } + + fn hir_perl_unicode_class( + &self, + ast_class: &ast::ClassPerl, + ) -> hir::ClassUnicode { + use ast::ClassPerlKind::*; + use unicode_tables::perl_word::PERL_WORD; + + assert!(self.flags().unicode()); + let mut class = match ast_class.kind { + Digit => { + let query = ClassQuery::Binary("Decimal_Number"); + unicode::class(query).unwrap() + } + Space => { + let query = ClassQuery::Binary("Whitespace"); + unicode::class(query).unwrap() + } + Word => unicode::hir_class(PERL_WORD), + }; + // We needn't apply case folding here because the Perl Unicode classes + // are already closed under Unicode simple case folding. + if ast_class.negated { + class.negate(); + } + class + } + + fn hir_perl_byte_class( + &self, + ast_class: &ast::ClassPerl, + ) -> hir::ClassBytes { + use ast::ClassPerlKind::*; + + assert!(!self.flags().unicode()); + let mut class = match ast_class.kind { + Digit => hir_ascii_class_bytes(&ast::ClassAsciiKind::Digit), + Space => hir_ascii_class_bytes(&ast::ClassAsciiKind::Space), + Word => hir_ascii_class_bytes(&ast::ClassAsciiKind::Word), + }; + // We needn't apply case folding here because the Perl ASCII classes + // are already closed (under ASCII case folding). + if ast_class.negated { + class.negate(); + } + class + } + + fn unicode_fold_and_negate( + &self, + negated: bool, + class: &mut hir::ClassUnicode, + ) { + // Note that we must apply case folding before negation! + // Consider `(?i)[^x]`. If we applied negation field, then + // the result would be the character class that matched any + // Unicode scalar value. + if self.flags().case_insensitive() { + class.case_fold_simple(); + } + if negated { + class.negate(); + } + } + + fn bytes_fold_and_negate( + &self, + span: &Span, + negated: bool, + class: &mut hir::ClassBytes, + ) -> Result<()> { + // Note that we must apply case folding before negation! + // Consider `(?i)[^x]`. If we applied negation field, then + // the result would be the character class that matched any + // Unicode scalar value. + if self.flags().case_insensitive() { + class.case_fold_simple(); + } + if negated { + class.negate(); + } + if !self.trans().allow_invalid_utf8 && !class.is_all_ascii() { + return Err(self.error(span.clone(), ErrorKind::InvalidUtf8)); + } + Ok(()) + } + + /// Return a scalar byte value suitable for use as a literal in a byte + /// character class. + fn class_literal_byte(&self, ast: &ast::Literal) -> Result<u8> { + match self.literal_to_char(ast)? { + hir::Literal::Byte(byte) => Ok(byte), + hir::Literal::Unicode(ch) => { + if ch <= 0x7F as char { + Ok(ch as u8) + } else { + // We can't feasibly support Unicode in + // byte oriented classes. Byte classes don't + // do Unicode case folding. + Err(self.error(ast.span, ErrorKind::UnicodeNotAllowed)) + } + } + } + } +} + +/// A translator's representation of a regular expression's flags at any given +/// moment in time. +/// +/// Each flag can be in one of three states: absent, present but disabled or +/// present but enabled. +#[derive(Clone, Copy, Debug, Default)] +struct Flags { + case_insensitive: Option<bool>, + multi_line: Option<bool>, + dot_matches_new_line: Option<bool>, + swap_greed: Option<bool>, + unicode: Option<bool>, + // Note that `ignore_whitespace` is omitted here because it is handled + // entirely in the parser. +} + +impl Flags { + fn from_ast(ast: &ast::Flags) -> Flags { + let mut flags = Flags::default(); + let mut enable = true; + for item in &ast.items { + match item.kind { + ast::FlagsItemKind::Negation => { + enable = false; + } + ast::FlagsItemKind::Flag(ast::Flag::CaseInsensitive) => { + flags.case_insensitive = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::MultiLine) => { + flags.multi_line = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::DotMatchesNewLine) => { + flags.dot_matches_new_line = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::SwapGreed) => { + flags.swap_greed = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::Unicode) => { + flags.unicode = Some(enable); + } + ast::FlagsItemKind::Flag(ast::Flag::IgnoreWhitespace) => {} + } + } + flags + } + + fn merge(&mut self, previous: &Flags) { + if self.case_insensitive.is_none() { + self.case_insensitive = previous.case_insensitive; + } + if self.multi_line.is_none() { + self.multi_line = previous.multi_line; + } + if self.dot_matches_new_line.is_none() { + self.dot_matches_new_line = previous.dot_matches_new_line; + } + if self.swap_greed.is_none() { + self.swap_greed = previous.swap_greed; + } + if self.unicode.is_none() { + self.unicode = previous.unicode; + } + } + + fn case_insensitive(&self) -> bool { + self.case_insensitive.unwrap_or(false) + } + + fn multi_line(&self) -> bool { + self.multi_line.unwrap_or(false) + } + + fn dot_matches_new_line(&self) -> bool { + self.dot_matches_new_line.unwrap_or(false) + } + + fn swap_greed(&self) -> bool { + self.swap_greed.unwrap_or(false) + } + + fn unicode(&self) -> bool { + self.unicode.unwrap_or(true) + } +} + +fn hir_ascii_class_bytes(kind: &ast::ClassAsciiKind) -> hir::ClassBytes { + let ranges: Vec<_> = ascii_class(kind).iter().cloned().map(|(s, e)| { + hir::ClassBytesRange::new(s as u8, e as u8) + }).collect(); + hir::ClassBytes::new(ranges) +} + +fn ascii_class(kind: &ast::ClassAsciiKind) -> &'static [(char, char)] { + use ast::ClassAsciiKind::*; + + // The contortions below with `const` appear necessary for older versions + // of Rust. + type T = &'static [(char, char)]; + match *kind { + Alnum => { + const X: T = &[('0', '9'), ('A', 'Z'), ('a', 'z')]; + X + } + Alpha => { + const X: T = &[('A', 'Z'), ('a', 'z')]; + X + } + Ascii => { + const X: T = &[('\x00', '\x7F')]; + X + } + Blank => { + const X: T = &[('\t', '\t'), (' ', ' ')]; + X + } + Cntrl => { + const X: T = &[('\x00', '\x1F'), ('\x7F', '\x7F')]; + X + } + Digit => { + const X: T = &[('0', '9')]; + X + } + Graph => { + const X: T = &[('!', '~')]; + X + } + Lower => { + const X: T = &[('a', 'z')]; + X + } + Print => { + const X: T = &[(' ', '~')]; + X + } + Punct => { + const X: T = &[('!', '/'), (':', '@'), ('[', '`'), ('{', '~')]; + X + } + Space => { + const X: T = &[ + ('\t', '\t'), ('\n', '\n'), ('\x0B', '\x0B'), ('\x0C', '\x0C'), + ('\r', '\r'), (' ', ' '), + ]; + X + } + Upper => { + const X: T = &[('A', 'Z')]; + X + } + Word => { + const X: T = &[('0', '9'), ('A', 'Z'), ('_', '_'), ('a', 'z')]; + X + } + Xdigit => { + const X: T = &[('0', '9'), ('A', 'F'), ('a', 'f')]; + X + } + } +} + +#[cfg(test)] +mod tests { + use ast::{self, Ast, Position, Span}; + use ast::parse::ParserBuilder; + use hir::{self, Hir, HirKind}; + use unicode::{self, ClassQuery}; + + use super::{TranslatorBuilder, ascii_class}; + + // We create these errors to compare with real hir::Errors in the tests. + // We define equality between TestError and hir::Error to disregard the + // pattern string in hir::Error, which is annoying to provide in tests. + #[derive(Clone, Debug)] + struct TestError { + span: Span, + kind: hir::ErrorKind, + } + + impl PartialEq<hir::Error> for TestError { + fn eq(&self, other: &hir::Error) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + impl PartialEq<TestError> for hir::Error { + fn eq(&self, other: &TestError) -> bool { + self.span == other.span && self.kind == other.kind + } + } + + fn parse(pattern: &str) -> Ast { + ParserBuilder::new().octal(true).build().parse(pattern).unwrap() + } + + fn t(pattern: &str) -> Hir { + TranslatorBuilder::new() + .allow_invalid_utf8(false) + .build() + .translate(pattern, &parse(pattern)) + .unwrap() + } + + fn t_err(pattern: &str) -> hir::Error { + TranslatorBuilder::new() + .allow_invalid_utf8(false) + .build() + .translate(pattern, &parse(pattern)) + .unwrap_err() + } + + fn t_bytes(pattern: &str) -> Hir { + TranslatorBuilder::new() + .allow_invalid_utf8(true) + .build() + .translate(pattern, &parse(pattern)) + .unwrap() + } + + fn hir_lit(s: &str) -> Hir { + match s.len() { + 0 => Hir::empty(), + _ => { + let lits = s + .chars() + .map(hir::Literal::Unicode) + .map(Hir::literal) + .collect(); + Hir::concat(lits) + } + } + } + + fn hir_blit(s: &[u8]) -> Hir { + match s.len() { + 0 => Hir::empty(), + 1 => Hir::literal(hir::Literal::Byte(s[0])), + _ => { + let lits = s + .iter() + .cloned() + .map(hir::Literal::Byte) + .map(Hir::literal) + .collect(); + Hir::concat(lits) + } + } + } + + fn hir_group(i: u32, expr: Hir) -> Hir { + Hir::group(hir::Group { + kind: hir::GroupKind::CaptureIndex(i), + hir: Box::new(expr), + }) + } + + fn hir_group_name(i: u32, name: &str, expr: Hir) -> Hir { + Hir::group(hir::Group { + kind: hir::GroupKind::CaptureName { + name: name.to_string(), + index: i, + }, + hir: Box::new(expr), + }) + } + + fn hir_group_nocap(expr: Hir) -> Hir { + Hir::group(hir::Group { + kind: hir::GroupKind::NonCapturing, + hir: Box::new(expr), + }) + } + + fn hir_quest(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::ZeroOrOne, + greedy: greedy, + hir: Box::new(expr), + }) + } + + fn hir_star(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::ZeroOrMore, + greedy: greedy, + hir: Box::new(expr), + }) + } + + fn hir_plus(greedy: bool, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::OneOrMore, + greedy: greedy, + hir: Box::new(expr), + }) + } + + fn hir_range(greedy: bool, range: hir::RepetitionRange, expr: Hir) -> Hir { + Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::Range(range), + greedy: greedy, + hir: Box::new(expr), + }) + } + + fn hir_alt(alts: Vec<Hir>) -> Hir { + Hir::alternation(alts) + } + + fn hir_cat(exprs: Vec<Hir>) -> Hir { + Hir::concat(exprs) + } + + fn hir_uclass_query(query: ClassQuery) -> Hir { + Hir::class(hir::Class::Unicode(unicode::class(query).unwrap())) + } + + fn hir_uclass_perl_word() -> Hir { + use unicode_tables::perl_word::PERL_WORD; + Hir::class(hir::Class::Unicode(unicode::hir_class(PERL_WORD))) + } + + fn hir_uclass(ranges: &[(char, char)]) -> Hir { + let ranges: Vec<hir::ClassUnicodeRange> = ranges + .iter() + .map(|&(s, e)| hir::ClassUnicodeRange::new(s, e)) + .collect(); + Hir::class(hir::Class::Unicode(hir::ClassUnicode::new(ranges))) + } + + fn hir_bclass(ranges: &[(u8, u8)]) -> Hir { + let ranges: Vec<hir::ClassBytesRange> = ranges + .iter() + .map(|&(s, e)| hir::ClassBytesRange::new(s, e)) + .collect(); + Hir::class(hir::Class::Bytes(hir::ClassBytes::new(ranges))) + } + + fn hir_bclass_from_char(ranges: &[(char, char)]) -> Hir { + let ranges: Vec<hir::ClassBytesRange> = ranges + .iter() + .map(|&(s, e)| { + assert!(s as u32 <= 0x7F); + assert!(e as u32 <= 0x7F); + hir::ClassBytesRange::new(s as u8, e as u8) + }) + .collect(); + Hir::class(hir::Class::Bytes(hir::ClassBytes::new(ranges))) + } + + fn hir_case_fold(expr: Hir) -> Hir { + match expr.into_kind() { + HirKind::Class(mut cls) => { + cls.case_fold_simple(); + Hir::class(cls) + } + _ => panic!("cannot case fold non-class Hir expr"), + } + } + + fn hir_negate(expr: Hir) -> Hir { + match expr.into_kind() { + HirKind::Class(mut cls) => { + cls.negate(); + Hir::class(cls) + } + _ => panic!("cannot negate non-class Hir expr"), + } + } + + fn hir_union(expr1: Hir, expr2: Hir) -> Hir { + use hir::Class::{Bytes, Unicode}; + + match (expr1.into_kind(), expr2.into_kind()) { + ( + HirKind::Class(Unicode(mut c1)), + HirKind::Class(Unicode(c2)), + ) => { + c1.union(&c2); + Hir::class(hir::Class::Unicode(c1)) + } + ( + HirKind::Class(Bytes(mut c1)), + HirKind::Class(Bytes(c2)), + ) => { + c1.union(&c2); + Hir::class(hir::Class::Bytes(c1)) + } + _ => panic!("cannot union non-class Hir exprs"), + } + } + + fn hir_difference(expr1: Hir, expr2: Hir) -> Hir { + use hir::Class::{Bytes, Unicode}; + + match (expr1.into_kind(), expr2.into_kind()) { + ( + HirKind::Class(Unicode(mut c1)), + HirKind::Class(Unicode(c2)), + ) => { + c1.difference(&c2); + Hir::class(hir::Class::Unicode(c1)) + } + ( + HirKind::Class(Bytes(mut c1)), + HirKind::Class(Bytes(c2)), + ) => { + c1.difference(&c2); + Hir::class(hir::Class::Bytes(c1)) + } + _ => panic!("cannot difference non-class Hir exprs"), + } + } + + fn hir_anchor(anchor: hir::Anchor) -> Hir { + Hir::anchor(anchor) + } + + fn hir_word(wb: hir::WordBoundary) -> Hir { + Hir::word_boundary(wb) + } + + #[test] + fn empty() { + assert_eq!(t(""), Hir::empty()); + assert_eq!(t("(?i)"), Hir::empty()); + assert_eq!(t("()"), hir_group(1, Hir::empty())); + assert_eq!(t("(?:)"), hir_group_nocap(Hir::empty())); + assert_eq!(t("(?P<wat>)"), hir_group_name(1, "wat", Hir::empty())); + assert_eq!(t("|"), hir_alt(vec![Hir::empty(), Hir::empty()])); + assert_eq!(t("()|()"), hir_alt(vec![ + hir_group(1, Hir::empty()), + hir_group(2, Hir::empty()), + ])); + assert_eq!(t("(|b)"), hir_group(1, hir_alt(vec![ + Hir::empty(), + hir_lit("b"), + ]))); + assert_eq!(t("(a|)"), hir_group(1, hir_alt(vec![ + hir_lit("a"), + Hir::empty(), + ]))); + assert_eq!(t("(a||c)"), hir_group(1, hir_alt(vec![ + hir_lit("a"), + Hir::empty(), + hir_lit("c"), + ]))); + assert_eq!(t("(||)"), hir_group(1, hir_alt(vec![ + Hir::empty(), + Hir::empty(), + Hir::empty(), + ]))); + } + + #[test] + fn literal() { + assert_eq!(t("a"), hir_lit("a")); + assert_eq!(t("(?-u)a"), hir_lit("a")); + assert_eq!(t("☃"), hir_lit("☃")); + assert_eq!(t("abcd"), hir_lit("abcd")); + + assert_eq!(t_bytes("(?-u)a"), hir_lit("a")); + assert_eq!(t_bytes("(?-u)\x61"), hir_lit("a")); + assert_eq!(t_bytes(r"(?-u)\x61"), hir_lit("a")); + assert_eq!(t_bytes(r"(?-u)\xFF"), hir_blit(b"\xFF")); + + assert_eq!(t_err("(?-u)☃"), TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new(Position::new(5, 1, 6), Position::new(8, 1, 7)), + }); + assert_eq!(t_err(r"(?-u)\xFF"), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(5, 1, 6), Position::new(9, 1, 10)), + }); + } + + #[test] + fn literal_case_insensitive() { + assert_eq!(t("(?i)a"), hir_uclass(&[ + ('A', 'A'), ('a', 'a'), + ])); + assert_eq!(t("(?i:a)"), hir_group_nocap(hir_uclass(&[ + ('A', 'A'), ('a', 'a')], + ))); + assert_eq!(t("a(?i)a(?-i)a"), hir_cat(vec![ + hir_lit("a"), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_lit("a"), + ])); + assert_eq!(t("(?i)ab@c"), hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_uclass(&[('B', 'B'), ('b', 'b')]), + hir_lit("@"), + hir_uclass(&[('C', 'C'), ('c', 'c')]), + ])); + assert_eq!(t("(?i)β"), hir_uclass(&[ + ('Β', 'Β'), ('β', 'β'), ('ϐ', 'ϐ'), + ])); + + assert_eq!(t("(?i-u)a"), hir_bclass(&[ + (b'A', b'A'), (b'a', b'a'), + ])); + assert_eq!(t("(?-u)a(?i)a(?-i)a"), hir_cat(vec![ + hir_lit("a"), + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_lit("a"), + ])); + assert_eq!(t("(?i-u)ab@c"), hir_cat(vec![ + hir_bclass(&[(b'A', b'A'), (b'a', b'a')]), + hir_bclass(&[(b'B', b'B'), (b'b', b'b')]), + hir_lit("@"), + hir_bclass(&[(b'C', b'C'), (b'c', b'c')]), + ])); + + assert_eq!(t_bytes("(?i-u)a"), hir_bclass(&[ + (b'A', b'A'), (b'a', b'a'), + ])); + assert_eq!(t_bytes("(?i-u)\x61"), hir_bclass(&[ + (b'A', b'A'), (b'a', b'a'), + ])); + assert_eq!(t_bytes(r"(?i-u)\x61"), hir_bclass(&[ + (b'A', b'A'), (b'a', b'a'), + ])); + assert_eq!(t_bytes(r"(?i-u)\xFF"), hir_blit(b"\xFF")); + + assert_eq!(t_err("(?i-u)β"), TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new( + Position::new(6, 1, 7), + Position::new(8, 1, 8), + ), + }); + } + + #[test] + fn dot() { + assert_eq!(t("."), hir_uclass(&[ + ('\0', '\t'), + ('\x0B', '\u{10FFFF}'), + ])); + assert_eq!(t("(?s)."), hir_uclass(&[ + ('\0', '\u{10FFFF}'), + ])); + assert_eq!(t_bytes("(?-u)."), hir_bclass(&[ + (b'\0', b'\t'), + (b'\x0B', b'\xFF'), + ])); + assert_eq!(t_bytes("(?s-u)."), hir_bclass(&[ + (b'\0', b'\xFF'), + ])); + + // If invalid UTF-8 isn't allowed, then non-Unicode `.` isn't allowed. + assert_eq!(t_err("(?-u)."), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(5, 1, 6), Position::new(6, 1, 7)), + }); + assert_eq!(t_err("(?s-u)."), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(6, 1, 7), Position::new(7, 1, 8)), + }); + } + + #[test] + fn assertions() { + assert_eq!(t("^"), hir_anchor(hir::Anchor::StartText)); + assert_eq!(t("$"), hir_anchor(hir::Anchor::EndText)); + assert_eq!(t(r"\A"), hir_anchor(hir::Anchor::StartText)); + assert_eq!(t(r"\z"), hir_anchor(hir::Anchor::EndText)); + assert_eq!(t("(?m)^"), hir_anchor(hir::Anchor::StartLine)); + assert_eq!(t("(?m)$"), hir_anchor(hir::Anchor::EndLine)); + assert_eq!(t(r"(?m)\A"), hir_anchor(hir::Anchor::StartText)); + assert_eq!(t(r"(?m)\z"), hir_anchor(hir::Anchor::EndText)); + + assert_eq!(t(r"\b"), hir_word(hir::WordBoundary::Unicode)); + assert_eq!(t(r"\B"), hir_word(hir::WordBoundary::UnicodeNegate)); + assert_eq!(t(r"(?-u)\b"), hir_word(hir::WordBoundary::Ascii)); + assert_eq!( + t_bytes(r"(?-u)\B"), + hir_word(hir::WordBoundary::AsciiNegate)); + + assert_eq!(t_err(r"(?-u)\B"), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(5, 1, 6), Position::new(7, 1, 8)), + }); + } + + #[test] + fn group() { + assert_eq!(t("(a)"), hir_group(1, hir_lit("a"))); + assert_eq!(t("(a)(b)"), hir_cat(vec![ + hir_group(1, hir_lit("a")), + hir_group(2, hir_lit("b")), + ])); + assert_eq!(t("(a)|(b)"), hir_alt(vec![ + hir_group(1, hir_lit("a")), + hir_group(2, hir_lit("b")), + ])); + assert_eq!(t("(?P<foo>)"), hir_group_name(1, "foo", Hir::empty())); + assert_eq!(t("(?P<foo>a)"), hir_group_name(1, "foo", hir_lit("a"))); + assert_eq!(t("(?P<foo>a)(?P<bar>b)"), hir_cat(vec![ + hir_group_name(1, "foo", hir_lit("a")), + hir_group_name(2, "bar", hir_lit("b")), + ])); + assert_eq!(t("(?:)"), hir_group_nocap(Hir::empty())); + assert_eq!(t("(?:a)"), hir_group_nocap(hir_lit("a"))); + assert_eq!(t("(?:a)(b)"), hir_cat(vec![ + hir_group_nocap(hir_lit("a")), + hir_group(1, hir_lit("b")), + ])); + assert_eq!(t("(a)(?:b)(c)"), hir_cat(vec![ + hir_group(1, hir_lit("a")), + hir_group_nocap(hir_lit("b")), + hir_group(2, hir_lit("c")), + ])); + assert_eq!(t("(a)(?P<foo>b)(c)"), hir_cat(vec![ + hir_group(1, hir_lit("a")), + hir_group_name(2, "foo", hir_lit("b")), + hir_group(3, hir_lit("c")), + ])); + assert_eq!(t("()"), hir_group(1, Hir::empty())); + assert_eq!(t("((?i))"), hir_group(1, Hir::empty())); + assert_eq!(t("((?x))"), hir_group(1, Hir::empty())); + assert_eq!(t("(((?x)))"), hir_group(1, hir_group(2, Hir::empty()))); + } + + #[test] + fn flags() { + assert_eq!(t("(?i:a)a"), hir_cat(vec![ + hir_group_nocap(hir_uclass(&[('A', 'A'), ('a', 'a')])), + hir_lit("a"), + ])); + assert_eq!(t("(?i-u:a)β"), hir_cat(vec![ + hir_group_nocap(hir_bclass(&[(b'A', b'A'), (b'a', b'a')])), + hir_lit("β"), + ])); + assert_eq!(t("(?i)(?-i:a)a"), hir_cat(vec![ + hir_group_nocap(hir_lit("a")), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + ])); + assert_eq!(t("(?im)a^"), hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_anchor(hir::Anchor::StartLine), + ])); + assert_eq!(t("(?im)a^(?i-m)a^"), hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_anchor(hir::Anchor::StartLine), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_anchor(hir::Anchor::StartText), + ])); + assert_eq!(t("(?U)a*a*?(?-U)a*a*?"), hir_cat(vec![ + hir_star(false, hir_lit("a")), + hir_star(true, hir_lit("a")), + hir_star(true, hir_lit("a")), + hir_star(false, hir_lit("a")), + ])); + assert_eq!(t("(?:a(?i)a)a"), hir_cat(vec![ + hir_group_nocap(hir_cat(vec![ + hir_lit("a"), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + ])), + hir_lit("a"), + ])); + assert_eq!(t("(?i)(?:a(?-i)a)a"), hir_cat(vec![ + hir_group_nocap(hir_cat(vec![ + hir_uclass(&[('A', 'A'), ('a', 'a')]), + hir_lit("a"), + ])), + hir_uclass(&[('A', 'A'), ('a', 'a')]), + ])); + } + + #[test] + fn escape() { + assert_eq!( + t(r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#"), + hir_lit(r"\.+*?()|[]{}^$#")); + } + + #[test] + fn repetition() { + assert_eq!(t("a?"), hir_quest(true, hir_lit("a"))); + assert_eq!(t("a*"), hir_star(true, hir_lit("a"))); + assert_eq!(t("a+"), hir_plus(true, hir_lit("a"))); + assert_eq!(t("a??"), hir_quest(false, hir_lit("a"))); + assert_eq!(t("a*?"), hir_star(false, hir_lit("a"))); + assert_eq!(t("a+?"), hir_plus(false, hir_lit("a"))); + + assert_eq!( + t("a{1}"), + hir_range( + true, + hir::RepetitionRange::Exactly(1), + hir_lit("a"), + )); + assert_eq!( + t("a{1,}"), + hir_range( + true, + hir::RepetitionRange::AtLeast(1), + hir_lit("a"), + )); + assert_eq!( + t("a{1,2}"), + hir_range( + true, + hir::RepetitionRange::Bounded(1, 2), + hir_lit("a"), + )); + assert_eq!( + t("a{1}?"), + hir_range( + false, + hir::RepetitionRange::Exactly(1), + hir_lit("a"), + )); + assert_eq!( + t("a{1,}?"), + hir_range( + false, + hir::RepetitionRange::AtLeast(1), + hir_lit("a"), + )); + assert_eq!( + t("a{1,2}?"), + hir_range( + false, + hir::RepetitionRange::Bounded(1, 2), + hir_lit("a"), + )); + + assert_eq!(t("ab?"), hir_cat(vec![ + hir_lit("a"), + hir_quest(true, hir_lit("b")), + ])); + assert_eq!(t("(ab)?"), hir_quest(true, hir_group(1, hir_cat(vec![ + hir_lit("a"), + hir_lit("b"), + ])))); + assert_eq!(t("a|b?"), hir_alt(vec![ + hir_lit("a"), + hir_quest(true, hir_lit("b")), + ])); + } + + #[test] + fn cat_alt() { + assert_eq!(t("(ab)"), hir_group(1, hir_cat(vec![ + hir_lit("a"), + hir_lit("b"), + ]))); + assert_eq!(t("a|b"), hir_alt(vec![ + hir_lit("a"), + hir_lit("b"), + ])); + assert_eq!(t("a|b|c"), hir_alt(vec![ + hir_lit("a"), + hir_lit("b"), + hir_lit("c"), + ])); + assert_eq!(t("ab|bc|cd"), hir_alt(vec![ + hir_lit("ab"), + hir_lit("bc"), + hir_lit("cd"), + ])); + assert_eq!(t("(a|b)"), hir_group(1, hir_alt(vec![ + hir_lit("a"), + hir_lit("b"), + ]))); + assert_eq!(t("(a|b|c)"), hir_group(1, hir_alt(vec![ + hir_lit("a"), + hir_lit("b"), + hir_lit("c"), + ]))); + assert_eq!(t("(ab|bc|cd)"), hir_group(1, hir_alt(vec![ + hir_lit("ab"), + hir_lit("bc"), + hir_lit("cd"), + ]))); + assert_eq!(t("(ab|(bc|(cd)))"), hir_group(1, hir_alt(vec![ + hir_lit("ab"), + hir_group(2, hir_alt(vec![ + hir_lit("bc"), + hir_group(3, hir_lit("cd")), + ])), + ]))); + } + + #[test] + fn class_ascii() { + assert_eq!( + t("[[:alnum:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Alnum))); + assert_eq!( + t("[[:alpha:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Alpha))); + assert_eq!( + t("[[:ascii:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Ascii))); + assert_eq!( + t("[[:blank:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Blank))); + assert_eq!( + t("[[:cntrl:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Cntrl))); + assert_eq!( + t("[[:digit:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Digit))); + assert_eq!( + t("[[:graph:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Graph))); + assert_eq!( + t("[[:lower:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Lower))); + assert_eq!( + t("[[:print:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Print))); + assert_eq!( + t("[[:punct:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Punct))); + assert_eq!( + t("[[:space:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Space))); + assert_eq!( + t("[[:upper:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Upper))); + assert_eq!( + t("[[:word:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Word))); + assert_eq!( + t("[[:xdigit:]]"), + hir_uclass(ascii_class(&ast::ClassAsciiKind::Xdigit))); + + assert_eq!( + t("[[:^lower:]]"), + hir_negate(hir_uclass(ascii_class(&ast::ClassAsciiKind::Lower)))); + assert_eq!( + t("(?i)[[:lower:]]"), + hir_uclass(&[ + ('A', 'Z'), ('a', 'z'), + ('\u{17F}', '\u{17F}'), + ('\u{212A}', '\u{212A}'), + ])); + + assert_eq!( + t("(?-u)[[:lower:]]"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Lower))); + assert_eq!( + t("(?i-u)[[:lower:]]"), + hir_case_fold(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Lower)))); + + assert_eq!(t_err("(?-u)[[:^lower:]]"), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(6, 1, 7), Position::new(16, 1, 17)), + }); + assert_eq!(t_err("(?i-u)[[:^lower:]]"), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(7, 1, 8), Position::new(17, 1, 18)), + }); + } + + #[test] + fn class_perl() { + // Unicode + assert_eq!( + t(r"\d"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"\s"), + hir_uclass_query(ClassQuery::Binary("space"))); + assert_eq!( + t(r"\w"), + hir_uclass_perl_word()); + assert_eq!( + t(r"(?i)\d"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"(?i)\s"), + hir_uclass_query(ClassQuery::Binary("space"))); + assert_eq!( + t(r"(?i)\w"), + hir_uclass_perl_word()); + + // Unicode, negated + assert_eq!( + t(r"\D"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit")))); + assert_eq!( + t(r"\S"), + hir_negate(hir_uclass_query(ClassQuery::Binary("space")))); + assert_eq!( + t(r"\W"), + hir_negate(hir_uclass_perl_word())); + assert_eq!( + t(r"(?i)\D"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit")))); + assert_eq!( + t(r"(?i)\S"), + hir_negate(hir_uclass_query(ClassQuery::Binary("space")))); + assert_eq!( + t(r"(?i)\W"), + hir_negate(hir_uclass_perl_word())); + + // ASCII only + assert_eq!( + t(r"(?-u)\d"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Digit))); + assert_eq!( + t(r"(?-u)\s"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Space))); + assert_eq!( + t(r"(?-u)\w"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Word))); + assert_eq!( + t(r"(?i-u)\d"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Digit))); + assert_eq!( + t(r"(?i-u)\s"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Space))); + assert_eq!( + t(r"(?i-u)\w"), + hir_bclass_from_char(ascii_class(&ast::ClassAsciiKind::Word))); + + // ASCII only, negated + assert_eq!( + t(r"(?-u)\D"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Digit)))); + assert_eq!( + t(r"(?-u)\S"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Space)))); + assert_eq!( + t(r"(?-u)\W"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Word)))); + assert_eq!( + t(r"(?i-u)\D"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Digit)))); + assert_eq!( + t(r"(?i-u)\S"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Space)))); + assert_eq!( + t(r"(?i-u)\W"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Word)))); + } + + #[test] + fn class_unicode() { + assert_eq!( + t(r"\pZ"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\pz"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{Separator}"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{se PaRa ToR}"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{gc:Separator}"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{gc=Separator}"), + hir_uclass_query(ClassQuery::Binary("Z"))); + assert_eq!( + t(r"\p{Other}"), + hir_uclass_query(ClassQuery::Binary("Other"))); + assert_eq!( + t(r"\pC"), + hir_uclass_query(ClassQuery::Binary("Other"))); + + assert_eq!( + t(r"\PZ"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z")))); + assert_eq!( + t(r"\P{separator}"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z")))); + assert_eq!( + t(r"\P{gc!=separator}"), + hir_negate(hir_uclass_query(ClassQuery::Binary("Z")))); + + assert_eq!( + t(r"\p{Greek}"), + hir_uclass_query(ClassQuery::Binary("Greek"))); + assert_eq!( + t(r"(?i)\p{Greek}"), + hir_case_fold(hir_uclass_query(ClassQuery::Binary("Greek")))); + assert_eq!( + t(r"(?i)\P{Greek}"), + hir_negate(hir_case_fold(hir_uclass_query( + ClassQuery::Binary("Greek"))))); + + assert_eq!( + t(r"\p{any}"), + hir_uclass_query(ClassQuery::Binary("Any"))); + assert_eq!( + t(r"\p{assigned}"), + hir_uclass_query(ClassQuery::Binary("Assigned"))); + assert_eq!( + t(r"\p{ascii}"), + hir_uclass_query(ClassQuery::Binary("ASCII"))); + assert_eq!( + t(r"\p{gc:any}"), + hir_uclass_query(ClassQuery::Binary("Any"))); + assert_eq!( + t(r"\p{gc:assigned}"), + hir_uclass_query(ClassQuery::Binary("Assigned"))); + assert_eq!( + t(r"\p{gc:ascii}"), + hir_uclass_query(ClassQuery::Binary("ASCII"))); + + assert_eq!(t_err(r"(?-u)\pZ"), TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new(Position::new(5, 1, 6), Position::new(8, 1, 9)), + }); + assert_eq!(t_err(r"(?-u)\p{Separator}"), TestError { + kind: hir::ErrorKind::UnicodeNotAllowed, + span: Span::new(Position::new(5, 1, 6), Position::new(18, 1, 19)), + }); + assert_eq!(t_err(r"\pE"), TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(3, 1, 4)), + }); + assert_eq!(t_err(r"\p{Foo}"), TestError { + kind: hir::ErrorKind::UnicodePropertyNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(7, 1, 8)), + }); + assert_eq!(t_err(r"\p{gc:Foo}"), TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(10, 1, 11)), + }); + assert_eq!(t_err(r"\p{sc:Foo}"), TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(10, 1, 11)), + }); + assert_eq!(t_err(r"\p{scx:Foo}"), TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(11, 1, 12)), + }); + assert_eq!(t_err(r"\p{age:Foo}"), TestError { + kind: hir::ErrorKind::UnicodePropertyValueNotFound, + span: Span::new(Position::new(0, 1, 1), Position::new(11, 1, 12)), + }); + } + + #[test] + fn class_bracketed() { + assert_eq!(t("[a]"), hir_uclass(&[('a', 'a')])); + assert_eq!(t("[^[a]]"), hir_negate(hir_uclass(&[('a', 'a')]))); + assert_eq!(t("[a-z]"), hir_uclass(&[('a', 'z')])); + assert_eq!(t("[a-fd-h]"), hir_uclass(&[('a', 'h')])); + assert_eq!(t("[a-fg-m]"), hir_uclass(&[('a', 'm')])); + assert_eq!(t(r"[\x00]"), hir_uclass(&[('\0', '\0')])); + assert_eq!(t(r"[\n]"), hir_uclass(&[('\n', '\n')])); + assert_eq!(t("[\n]"), hir_uclass(&[('\n', '\n')])); + assert_eq!( + t(r"[\d]"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"[\pZ]"), + hir_uclass_query(ClassQuery::Binary("separator"))); + assert_eq!( + t(r"[\p{separator}]"), + hir_uclass_query(ClassQuery::Binary("separator"))); + assert_eq!( + t(r"[^\D]"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"[^\PZ]"), + hir_uclass_query(ClassQuery::Binary("separator"))); + assert_eq!( + t(r"[^\P{separator}]"), + hir_uclass_query(ClassQuery::Binary("separator"))); + assert_eq!( + t(r"(?i)[^\D]"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"(?i)[^\P{greek}]"), + hir_case_fold(hir_uclass_query(ClassQuery::Binary("greek")))); + + assert_eq!(t("(?-u)[a]"), hir_bclass(&[(b'a', b'a')])); + assert_eq!(t(r"(?-u)[\x00]"), hir_bclass(&[(b'\0', b'\0')])); + assert_eq!(t_bytes(r"(?-u)[\xFF]"), hir_bclass(&[(b'\xFF', b'\xFF')])); + + assert_eq!(t("(?i)[a]"), hir_uclass(&[('A', 'A'), ('a', 'a')])); + assert_eq!(t("(?i)[k]"), hir_uclass(&[ + ('K', 'K'), ('k', 'k'), ('\u{212A}', '\u{212A}'), + ])); + assert_eq!(t("(?i)[β]"), hir_uclass(&[ + ('Β', 'Β'), ('β', 'β'), ('ϐ', 'ϐ'), + ])); + assert_eq!(t("(?i-u)[k]"), hir_bclass(&[ + (b'K', b'K'), (b'k', b'k'), + ])); + + assert_eq!(t("[^a]"), hir_negate(hir_uclass(&[('a', 'a')]))); + assert_eq!(t(r"[^\x00]"), hir_negate(hir_uclass(&[('\0', '\0')]))); + assert_eq!( + t_bytes("(?-u)[^a]"), + hir_negate(hir_bclass(&[(b'a', b'a')]))); + assert_eq!( + t(r"[^\d]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit")))); + assert_eq!( + t(r"[^\pZ]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("separator")))); + assert_eq!( + t(r"[^\p{separator}]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("separator")))); + assert_eq!( + t(r"(?i)[^\p{greek}]"), + hir_negate(hir_case_fold(hir_uclass_query( + ClassQuery::Binary("greek"))))); + assert_eq!( + t(r"(?i)[\P{greek}]"), + hir_negate(hir_case_fold(hir_uclass_query( + ClassQuery::Binary("greek"))))); + + // Test some weird cases. + assert_eq!(t(r"[\[]"), hir_uclass(&[('[', '[')])); + + assert_eq!(t(r"[&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&\&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\x00-&]"), hir_uclass(&[('\0', '&')])); + assert_eq!(t(r"[&-\xFF]"), hir_uclass(&[('&', '\u{FF}')])); + + assert_eq!(t(r"[~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\~\~]"), hir_uclass(&[('~', '~')])); + assert_eq!(t(r"[\x00-~]"), hir_uclass(&[('\0', '~')])); + assert_eq!(t(r"[~-\xFF]"), hir_uclass(&[('~', '\u{FF}')])); + + assert_eq!(t(r"[-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\-\-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\x00-\-]"), hir_uclass(&[('\0', '-')])); + assert_eq!(t(r"[\--\xFF]"), hir_uclass(&[('-', '\u{FF}')])); + + assert_eq!(t_err("(?-u)[^a]"), TestError { + kind: hir::ErrorKind::InvalidUtf8, + span: Span::new(Position::new(5, 1, 6), Position::new(9, 1, 10)), + }); + assert_eq!(t_err(r"[^\s\S]"), TestError { + kind: hir::ErrorKind::EmptyClassNotAllowed, + span: Span::new(Position::new(0, 1, 1), Position::new(7, 1, 8)), + }); + assert_eq!(t_err(r"(?-u)[^\s\S]"), TestError { + kind: hir::ErrorKind::EmptyClassNotAllowed, + span: Span::new(Position::new(5, 1, 6), Position::new(12, 1, 13)), + }); + } + + #[test] + fn class_bracketed_union() { + assert_eq!( + t("[a-zA-Z]"), + hir_uclass(&[('A', 'Z'), ('a', 'z')])); + assert_eq!( + t(r"[a\pZb]"), + hir_union( + hir_uclass(&[('a', 'b')]), + hir_uclass_query(ClassQuery::Binary("separator")))); + assert_eq!( + t(r"[\pZ\p{Greek}]"), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")))); + assert_eq!( + t(r"[\p{age:3.0}\pZ\p{Greek}]"), + hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator"))))); + assert_eq!( + t(r"[[[\p{age:3.0}\pZ]\p{Greek}][\p{Cyrillic}]]"), + hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("cyrillic")), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")))))); + + assert_eq!( + t(r"(?i)[\p{age:3.0}\pZ\p{Greek}]"), + hir_case_fold(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")))))); + assert_eq!( + t(r"[^\p{age:3.0}\pZ\p{Greek}]"), + hir_negate(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator")))))); + assert_eq!( + t(r"(?i)[^\p{age:3.0}\pZ\p{Greek}]"), + hir_negate(hir_case_fold(hir_union( + hir_uclass_query(ClassQuery::ByValue { + property_name: "age", + property_value: "3.0", + }), + hir_union( + hir_uclass_query(ClassQuery::Binary("greek")), + hir_uclass_query(ClassQuery::Binary("separator"))))))); + } + + #[test] + fn class_bracketed_nested() { + assert_eq!( + t(r"[a[^c]]"), + hir_negate(hir_uclass(&[('c', 'c')]))); + assert_eq!( + t(r"[a-b[^c]]"), + hir_negate(hir_uclass(&[('c', 'c')]))); + assert_eq!( + t(r"[a-c[^c]]"), + hir_negate(hir_uclass(&[]))); + + assert_eq!( + t(r"[^a[^c]]"), + hir_uclass(&[('c', 'c')])); + assert_eq!( + t(r"[^a-b[^c]]"), + hir_uclass(&[('c', 'c')])); + + assert_eq!( + t(r"(?i)[a[^c]]"), + hir_negate(hir_case_fold(hir_uclass(&[('c', 'c')])))); + assert_eq!( + t(r"(?i)[a-b[^c]]"), + hir_negate(hir_case_fold(hir_uclass(&[('c', 'c')])))); + + assert_eq!( + t(r"(?i)[^a[^c]]"), + hir_uclass(&[('C', 'C'), ('c', 'c')])); + assert_eq!( + t(r"(?i)[^a-b[^c]]"), + hir_uclass(&[('C', 'C'), ('c', 'c')])); + + assert_eq!(t_err(r"[^a-c[^c]]"), TestError { + kind: hir::ErrorKind::EmptyClassNotAllowed, + span: Span::new(Position::new(0, 1, 1), Position::new(10, 1, 11)), + }); + assert_eq!(t_err(r"(?i)[^a-c[^c]]"), TestError { + kind: hir::ErrorKind::EmptyClassNotAllowed, + span: Span::new(Position::new(4, 1, 5), Position::new(14, 1, 15)), + }); + } + + #[test] + fn class_bracketed_intersect() { + assert_eq!(t("[abc&&b-c]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[abc&&[b-c]]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[[abc]&&[b-c]]"), hir_uclass(&[('b', 'c')])); + assert_eq!(t("[a-z&&b-y&&c-x]"), hir_uclass(&[('c', 'x')])); + assert_eq!(t("[c-da-b&&a-d]"), hir_uclass(&[('a', 'd')])); + assert_eq!(t("[a-d&&c-da-b]"), hir_uclass(&[('a', 'd')])); + assert_eq!(t(r"[a-z&&a-c]"), hir_uclass(&[('a', 'c')])); + assert_eq!(t(r"[[a-z&&a-c]]"), hir_uclass(&[('a', 'c')])); + assert_eq!(t(r"[^[a-z&&a-c]]"), hir_negate(hir_uclass(&[('a', 'c')]))); + + assert_eq!(t("(?-u)[abc&&b-c]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[abc&&[b-c]]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[[abc]&&[b-c]]"), hir_bclass(&[(b'b', b'c')])); + assert_eq!(t("(?-u)[a-z&&b-y&&c-x]"), hir_bclass(&[(b'c', b'x')])); + assert_eq!(t("(?-u)[c-da-b&&a-d]"), hir_bclass(&[(b'a', b'd')])); + assert_eq!(t("(?-u)[a-d&&c-da-b]"), hir_bclass(&[(b'a', b'd')])); + + assert_eq!( + t("(?i)[abc&&b-c]"), + hir_case_fold(hir_uclass(&[('b', 'c')]))); + assert_eq!( + t("(?i)[abc&&[b-c]]"), + hir_case_fold(hir_uclass(&[('b', 'c')]))); + assert_eq!( + t("(?i)[[abc]&&[b-c]]"), + hir_case_fold(hir_uclass(&[('b', 'c')]))); + assert_eq!( + t("(?i)[a-z&&b-y&&c-x]"), + hir_case_fold(hir_uclass(&[('c', 'x')]))); + assert_eq!( + t("(?i)[c-da-b&&a-d]"), + hir_case_fold(hir_uclass(&[('a', 'd')]))); + assert_eq!( + t("(?i)[a-d&&c-da-b]"), + hir_case_fold(hir_uclass(&[('a', 'd')]))); + + assert_eq!( + t("(?i-u)[abc&&b-c]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')]))); + assert_eq!( + t("(?i-u)[abc&&[b-c]]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')]))); + assert_eq!( + t("(?i-u)[[abc]&&[b-c]]"), + hir_case_fold(hir_bclass(&[(b'b', b'c')]))); + assert_eq!( + t("(?i-u)[a-z&&b-y&&c-x]"), + hir_case_fold(hir_bclass(&[(b'c', b'x')]))); + assert_eq!( + t("(?i-u)[c-da-b&&a-d]"), + hir_case_fold(hir_bclass(&[(b'a', b'd')]))); + assert_eq!( + t("(?i-u)[a-d&&c-da-b]"), + hir_case_fold(hir_bclass(&[(b'a', b'd')]))); + + // In `[a^]`, `^` does not need to be escaped, so it makes sense that + // `^` is also allowed to be unescaped after `&&`. + assert_eq!(t(r"[\^&&^]"), hir_uclass(&[('^', '^')])); + // `]` needs to be escaped after `&&` since it's not at start of class. + assert_eq!(t(r"[]&&\]]"), hir_uclass(&[(']', ']')])); + assert_eq!(t(r"[-&&-]"), hir_uclass(&[('-', '-')])); + assert_eq!(t(r"[\&&&&]"), hir_uclass(&[('&', '&')])); + assert_eq!(t(r"[\&&&\&]"), hir_uclass(&[('&', '&')])); + // Test precedence. + assert_eq!( + t(r"[a-w&&[^c-g]z]"), + hir_uclass(&[('a', 'b'), ('h', 'w')])); + } + + #[test] + fn class_bracketed_intersect_negate() { + assert_eq!( + t(r"[^\w&&\d]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit")))); + assert_eq!( + t(r"[^[a-z&&a-c]]"), + hir_negate(hir_uclass(&[('a', 'c')]))); + assert_eq!( + t(r"[^[\w&&\d]]"), + hir_negate(hir_uclass_query(ClassQuery::Binary("digit")))); + assert_eq!( + t(r"[^[^\w&&\d]]"), + hir_uclass_query(ClassQuery::Binary("digit"))); + assert_eq!( + t(r"[[[^\w]&&[^\d]]]"), + hir_negate(hir_uclass_perl_word())); + + assert_eq!( + t_bytes(r"(?-u)[^\w&&\d]"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Digit)))); + assert_eq!( + t_bytes(r"(?-u)[^[a-z&&a-c]]"), + hir_negate(hir_bclass(&[(b'a', b'c')]))); + assert_eq!( + t_bytes(r"(?-u)[^[\w&&\d]]"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Digit)))); + assert_eq!( + t_bytes(r"(?-u)[^[^\w&&\d]]"), + hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Digit))); + assert_eq!( + t_bytes(r"(?-u)[[[^\w]&&[^\d]]]"), + hir_negate(hir_bclass_from_char(ascii_class( + &ast::ClassAsciiKind::Word)))); + } + + #[test] + fn class_bracketed_difference() { + assert_eq!( + t(r"[\pL--[:ascii:]]"), + hir_difference( + hir_uclass_query(ClassQuery::Binary("letter")), + hir_uclass(&[('\0', '\x7F')]))); + + assert_eq!( + t(r"(?-u)[[:alpha:]--[:lower:]]"), + hir_bclass(&[(b'A', b'Z')])); + } + + #[test] + fn class_bracketed_symmetric_difference() { + assert_eq!( + t(r"[\p{sc:Greek}~~\p{scx:Greek}]"), + hir_uclass(&[ + ('\u{0342}', '\u{0342}'), + ('\u{0345}', '\u{0345}'), + ('\u{1DC0}', '\u{1DC1}'), + ])); + assert_eq!( + t(r"[a-g~~c-j]"), + hir_uclass(&[('a', 'b'), ('h', 'j')])); + + assert_eq!( + t(r"(?-u)[a-g~~c-j]"), + hir_bclass(&[(b'a', b'b'), (b'h', b'j')])); + } + + #[test] + fn ignore_whitespace() { + assert_eq!(t(r"(?x)\12 3"), hir_lit("\n3")); + assert_eq!(t(r"(?x)\x { 53 }"), hir_lit("S")); + assert_eq!(t(r"(?x)\x # comment +{ # comment + 53 # comment +} #comment"), hir_lit("S")); + + assert_eq!(t(r"(?x)\x 53"), hir_lit("S")); + assert_eq!(t(r"(?x)\x # comment + 53 # comment"), hir_lit("S")); + assert_eq!(t(r"(?x)\x5 3"), hir_lit("S")); + + assert_eq!(t(r"(?x)\p # comment +{ # comment + Separator # comment +} # comment"), hir_uclass_query(ClassQuery::Binary("separator"))); + + assert_eq!(t(r"(?x)a # comment +{ # comment + 5 # comment + , # comment + 10 # comment +} # comment"), + hir_range( + true, hir::RepetitionRange::Bounded(5, 10), hir_lit("a"))); + + assert_eq!(t(r"(?x)a\ # hi there"), hir_lit("a ")); + } + + #[test] + fn analysis_is_always_utf8() { + // Positive examples. + assert!(t_bytes(r"a").is_always_utf8()); + assert!(t_bytes(r"ab").is_always_utf8()); + assert!(t_bytes(r"(?-u)a").is_always_utf8()); + assert!(t_bytes(r"(?-u)ab").is_always_utf8()); + assert!(t_bytes(r"\xFF").is_always_utf8()); + assert!(t_bytes(r"\xFF\xFF").is_always_utf8()); + assert!(t_bytes(r"[^a]").is_always_utf8()); + assert!(t_bytes(r"[^a][^a]").is_always_utf8()); + assert!(t_bytes(r"\b").is_always_utf8()); + assert!(t_bytes(r"\B").is_always_utf8()); + assert!(t_bytes(r"(?-u)\b").is_always_utf8()); + + // Negative examples. + assert!(!t_bytes(r"(?-u)\xFF").is_always_utf8()); + assert!(!t_bytes(r"(?-u)\xFF\xFF").is_always_utf8()); + assert!(!t_bytes(r"(?-u)[^a]").is_always_utf8()); + assert!(!t_bytes(r"(?-u)[^a][^a]").is_always_utf8()); + assert!(!t_bytes(r"(?-u)\B").is_always_utf8()); + } + + #[test] + fn analysis_is_all_assertions() { + // Positive examples. + assert!(t(r"\b").is_all_assertions()); + assert!(t(r"\B").is_all_assertions()); + assert!(t(r"^").is_all_assertions()); + assert!(t(r"$").is_all_assertions()); + assert!(t(r"\A").is_all_assertions()); + assert!(t(r"\z").is_all_assertions()); + assert!(t(r"$^\z\A\b\B").is_all_assertions()); + assert!(t(r"$|^|\z|\A|\b|\B").is_all_assertions()); + assert!(t(r"^$|$^").is_all_assertions()); + assert!(t(r"((\b)+())*^").is_all_assertions()); + + // Negative examples. + assert!(!t(r"^a").is_all_assertions()); + } + + #[test] + fn analysis_is_anchored() { + // Positive examples. + assert!(t(r"^").is_anchored_start()); + assert!(t(r"$").is_anchored_end()); + assert!(t(r"^").is_line_anchored_start()); + assert!(t(r"$").is_line_anchored_end()); + + assert!(t(r"^^").is_anchored_start()); + assert!(t(r"$$").is_anchored_end()); + assert!(t(r"^^").is_line_anchored_start()); + assert!(t(r"$$").is_line_anchored_end()); + + assert!(t(r"^$").is_anchored_start()); + assert!(t(r"^$").is_anchored_end()); + assert!(t(r"^$").is_line_anchored_start()); + assert!(t(r"^$").is_line_anchored_end()); + + assert!(t(r"^foo").is_anchored_start()); + assert!(t(r"foo$").is_anchored_end()); + assert!(t(r"^foo").is_line_anchored_start()); + assert!(t(r"foo$").is_line_anchored_end()); + + assert!(t(r"^foo|^bar").is_anchored_start()); + assert!(t(r"foo$|bar$").is_anchored_end()); + assert!(t(r"^foo|^bar").is_line_anchored_start()); + assert!(t(r"foo$|bar$").is_line_anchored_end()); + + assert!(t(r"^(foo|bar)").is_anchored_start()); + assert!(t(r"(foo|bar)$").is_anchored_end()); + assert!(t(r"^(foo|bar)").is_line_anchored_start()); + assert!(t(r"(foo|bar)$").is_line_anchored_end()); + + assert!(t(r"^+").is_anchored_start()); + assert!(t(r"$+").is_anchored_end()); + assert!(t(r"^+").is_line_anchored_start()); + assert!(t(r"$+").is_line_anchored_end()); + assert!(t(r"^++").is_anchored_start()); + assert!(t(r"$++").is_anchored_end()); + assert!(t(r"^++").is_line_anchored_start()); + assert!(t(r"$++").is_line_anchored_end()); + assert!(t(r"(^)+").is_anchored_start()); + assert!(t(r"($)+").is_anchored_end()); + assert!(t(r"(^)+").is_line_anchored_start()); + assert!(t(r"($)+").is_line_anchored_end()); + + assert!(t(r"$^").is_anchored_start()); + assert!(t(r"$^").is_anchored_start()); + assert!(t(r"$^").is_line_anchored_end()); + assert!(t(r"$^").is_line_anchored_end()); + assert!(t(r"$^|^$").is_anchored_start()); + assert!(t(r"$^|^$").is_anchored_end()); + assert!(t(r"$^|^$").is_line_anchored_start()); + assert!(t(r"$^|^$").is_line_anchored_end()); + + assert!(t(r"\b^").is_anchored_start()); + assert!(t(r"$\b").is_anchored_end()); + assert!(t(r"\b^").is_line_anchored_start()); + assert!(t(r"$\b").is_line_anchored_end()); + assert!(t(r"^(?m:^)").is_anchored_start()); + assert!(t(r"(?m:$)$").is_anchored_end()); + assert!(t(r"^(?m:^)").is_line_anchored_start()); + assert!(t(r"(?m:$)$").is_line_anchored_end()); + assert!(t(r"(?m:^)^").is_anchored_start()); + assert!(t(r"$(?m:$)").is_anchored_end()); + assert!(t(r"(?m:^)^").is_line_anchored_start()); + assert!(t(r"$(?m:$)").is_line_anchored_end()); + + // Negative examples. + assert!(!t(r"(?m)^").is_anchored_start()); + assert!(!t(r"(?m)$").is_anchored_end()); + assert!(!t(r"(?m:^$)|$^").is_anchored_start()); + assert!(!t(r"(?m:^$)|$^").is_anchored_end()); + assert!(!t(r"$^|(?m:^$)").is_anchored_start()); + assert!(!t(r"$^|(?m:^$)").is_anchored_end()); + + assert!(!t(r"a^").is_anchored_start()); + assert!(!t(r"$a").is_anchored_start()); + assert!(!t(r"a^").is_line_anchored_start()); + assert!(!t(r"$a").is_line_anchored_start()); + + assert!(!t(r"a^").is_anchored_end()); + assert!(!t(r"$a").is_anchored_end()); + assert!(!t(r"a^").is_line_anchored_end()); + assert!(!t(r"$a").is_line_anchored_end()); + + assert!(!t(r"^foo|bar").is_anchored_start()); + assert!(!t(r"foo|bar$").is_anchored_end()); + assert!(!t(r"^foo|bar").is_line_anchored_start()); + assert!(!t(r"foo|bar$").is_line_anchored_end()); + + assert!(!t(r"^*").is_anchored_start()); + assert!(!t(r"$*").is_anchored_end()); + assert!(!t(r"^*").is_line_anchored_start()); + assert!(!t(r"$*").is_line_anchored_end()); + assert!(!t(r"^*+").is_anchored_start()); + assert!(!t(r"$*+").is_anchored_end()); + assert!(!t(r"^*+").is_line_anchored_start()); + assert!(!t(r"$*+").is_line_anchored_end()); + assert!(!t(r"^+*").is_anchored_start()); + assert!(!t(r"$+*").is_anchored_end()); + assert!(!t(r"^+*").is_line_anchored_start()); + assert!(!t(r"$+*").is_line_anchored_end()); + assert!(!t(r"(^)*").is_anchored_start()); + assert!(!t(r"($)*").is_anchored_end()); + assert!(!t(r"(^)*").is_line_anchored_start()); + assert!(!t(r"($)*").is_line_anchored_end()); + } + + #[test] + fn analysis_is_line_anchored() { + assert!(t(r"(?m)^(foo|bar)").is_line_anchored_start()); + assert!(t(r"(?m)(foo|bar)$").is_line_anchored_end()); + + assert!(t(r"(?m)^foo|^bar").is_line_anchored_start()); + assert!(t(r"(?m)foo$|bar$").is_line_anchored_end()); + + assert!(t(r"(?m)^").is_line_anchored_start()); + assert!(t(r"(?m)$").is_line_anchored_end()); + + assert!(t(r"(?m:^$)|$^").is_line_anchored_start()); + assert!(t(r"(?m:^$)|$^").is_line_anchored_end()); + + assert!(t(r"$^|(?m:^$)").is_line_anchored_start()); + assert!(t(r"$^|(?m:^$)").is_line_anchored_end()); + } + + #[test] + fn analysis_is_any_anchored() { + // Positive examples. + assert!(t(r"^").is_any_anchored_start()); + assert!(t(r"$").is_any_anchored_end()); + assert!(t(r"\A").is_any_anchored_start()); + assert!(t(r"\z").is_any_anchored_end()); + + // Negative examples. + assert!(!t(r"(?m)^").is_any_anchored_start()); + assert!(!t(r"(?m)$").is_any_anchored_end()); + assert!(!t(r"$").is_any_anchored_start()); + assert!(!t(r"^").is_any_anchored_end()); + } + + #[test] + fn analysis_is_match_empty() { + // Positive examples. + assert!(t(r"").is_match_empty()); + assert!(t(r"()").is_match_empty()); + assert!(t(r"()*").is_match_empty()); + assert!(t(r"()+").is_match_empty()); + assert!(t(r"()?").is_match_empty()); + assert!(t(r"a*").is_match_empty()); + assert!(t(r"a?").is_match_empty()); + assert!(t(r"a{0}").is_match_empty()); + assert!(t(r"a{0,}").is_match_empty()); + assert!(t(r"a{0,1}").is_match_empty()); + assert!(t(r"a{0,10}").is_match_empty()); + assert!(t(r"\pL*").is_match_empty()); + assert!(t(r"a*|b").is_match_empty()); + assert!(t(r"b|a*").is_match_empty()); + assert!(t(r"a*a?(abcd)*").is_match_empty()); + assert!(t(r"^").is_match_empty()); + assert!(t(r"$").is_match_empty()); + assert!(t(r"(?m)^").is_match_empty()); + assert!(t(r"(?m)$").is_match_empty()); + assert!(t(r"\A").is_match_empty()); + assert!(t(r"\z").is_match_empty()); + assert!(t(r"\B").is_match_empty()); + assert!(t_bytes(r"(?-u)\B").is_match_empty()); + + // Negative examples. + assert!(!t(r"a+").is_match_empty()); + assert!(!t(r"a{1}").is_match_empty()); + assert!(!t(r"a{1,}").is_match_empty()); + assert!(!t(r"a{1,2}").is_match_empty()); + assert!(!t(r"a{1,10}").is_match_empty()); + assert!(!t(r"b|a").is_match_empty()); + assert!(!t(r"a*a+(abcd)*").is_match_empty()); + assert!(!t(r"\b").is_match_empty()); + assert!(!t(r"(?-u)\b").is_match_empty()); + } + + #[test] + fn analysis_is_literal() { + // Positive examples. + assert!(t(r"").is_literal()); + assert!(t(r"a").is_literal()); + assert!(t(r"ab").is_literal()); + assert!(t(r"abc").is_literal()); + assert!(t(r"(?m)abc").is_literal()); + + // Negative examples. + assert!(!t(r"^").is_literal()); + assert!(!t(r"a|b").is_literal()); + assert!(!t(r"(a)").is_literal()); + assert!(!t(r"a+").is_literal()); + assert!(!t(r"foo(a)").is_literal()); + assert!(!t(r"(a)foo").is_literal()); + assert!(!t(r"[a]").is_literal()); + } + + #[test] + fn analysis_is_alternation_literal() { + // Positive examples. + assert!(t(r"").is_alternation_literal()); + assert!(t(r"a").is_alternation_literal()); + assert!(t(r"ab").is_alternation_literal()); + assert!(t(r"abc").is_alternation_literal()); + assert!(t(r"(?m)abc").is_alternation_literal()); + assert!(t(r"a|b").is_alternation_literal()); + assert!(t(r"a|b|c").is_alternation_literal()); + assert!(t(r"foo|bar").is_alternation_literal()); + assert!(t(r"foo|bar|baz").is_alternation_literal()); + + // Negative examples. + assert!(!t(r"^").is_alternation_literal()); + assert!(!t(r"(a)").is_alternation_literal()); + assert!(!t(r"a+").is_alternation_literal()); + assert!(!t(r"foo(a)").is_alternation_literal()); + assert!(!t(r"(a)foo").is_alternation_literal()); + assert!(!t(r"[a]").is_alternation_literal()); + assert!(!t(r"[a]|b").is_alternation_literal()); + assert!(!t(r"a|[b]").is_alternation_literal()); + assert!(!t(r"(a)|b").is_alternation_literal()); + assert!(!t(r"a|(b)").is_alternation_literal()); + } +} diff --git a/regex-syntax/src/hir/visitor.rs b/regex-syntax/src/hir/visitor.rs new file mode 100644 index 000000000..58be7ad07 --- /dev/null +++ b/regex-syntax/src/hir/visitor.rs @@ -0,0 +1,222 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::{self, Hir, HirKind}; + +/// A trait for visiting the high-level IR (HIR) in depth first order. +/// +/// The principle aim of this trait is to enable callers to perform case +/// analysis on a high-level intermediate representation of a regular +/// expression without necessarily using recursion. In particular, this permits +/// callers to do case analysis with constant stack usage, which can be +/// important since the size of an HIR may be proportional to end user input. +/// +/// Typical usage of this trait involves providing an implementation and then +/// running it using the [`visit`](fn.visit.html) function. +pub trait Visitor { + /// The result of visiting an HIR. + type Output; + /// An error that visiting an HIR might return. + type Err; + + /// All implementors of `Visitor` must provide a `finish` method, which + /// yields the result of visiting the HIR or an error. + fn finish(self) -> Result<Self::Output, Self::Err>; + + /// This method is called before beginning traversal of the HIR. + fn start(&mut self) {} + + /// This method is called on an `Hir` before descending into child `Hir` + /// nodes. + fn visit_pre(&mut self, _hir: &Hir) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called on an `Hir` after descending all of its child + /// `Hir` nodes. + fn visit_post(&mut self, _hir: &Hir) -> Result<(), Self::Err> { + Ok(()) + } + + /// This method is called between child nodes of an alternation. + fn visit_alternation_in(&mut self) -> Result<(), Self::Err> { + Ok(()) + } +} + +/// Executes an implementation of `Visitor` in constant stack space. +/// +/// This function will visit every node in the given `Hir` while calling +/// appropriate methods provided by the +/// [`Visitor`](trait.Visitor.html) trait. +/// +/// The primary use case for this method is when one wants to perform case +/// analysis over an `Hir` without using a stack size proportional to the depth +/// of the `Hir`. Namely, this method will instead use constant stack space, +/// but will use heap space proportional to the size of the `Hir`. This may be +/// desirable in cases where the size of `Hir` is proportional to end user +/// input. +/// +/// If the visitor returns an error at any point, then visiting is stopped and +/// the error is returned. +pub fn visit<V: Visitor>(hir: &Hir, visitor: V) -> Result<V::Output, V::Err> { + HeapVisitor::new().visit(hir, visitor) +} + +/// HeapVisitor visits every item in an `Hir` recursively using constant stack +/// size and a heap size proportional to the size of the `Hir`. +struct HeapVisitor<'a> { + /// A stack of `Hir` nodes. This is roughly analogous to the call stack + /// used in a typical recursive visitor. + stack: Vec<(&'a Hir, Frame<'a>)>, +} + +/// Represents a single stack frame while performing structural induction over +/// an `Hir`. +enum Frame<'a> { + /// A stack frame allocated just before descending into a repetition + /// operator's child node. + Repetition(&'a hir::Repetition), + /// A stack frame allocated just before descending into a group's child + /// node. + Group(&'a hir::Group), + /// The stack frame used while visiting every child node of a concatenation + /// of expressions. + Concat { + /// The child node we are currently visiting. + head: &'a Hir, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Hir], + }, + /// The stack frame used while visiting every child node of an alternation + /// of expressions. + Alternation { + /// The child node we are currently visiting. + head: &'a Hir, + /// The remaining child nodes to visit (which may be empty). + tail: &'a [Hir], + }, +} + +impl<'a> HeapVisitor<'a> { + fn new() -> HeapVisitor<'a> { + HeapVisitor { stack: vec![] } + } + + fn visit<V: Visitor>( + &mut self, + mut hir: &'a Hir, + mut visitor: V, + ) -> Result<V::Output, V::Err> { + self.stack.clear(); + + visitor.start(); + loop { + visitor.visit_pre(hir)?; + if let Some(x) = self.induct(hir) { + let child = x.child(); + self.stack.push((hir, x)); + hir = child; + continue; + } + // No induction means we have a base case, so we can post visit + // it now. + visitor.visit_post(hir)?; + + // At this point, we now try to pop our call stack until it is + // either empty or we hit another inductive case. + loop { + let (post_hir, frame) = match self.stack.pop() { + None => return visitor.finish(), + Some((post_hir, frame)) => (post_hir, frame), + }; + // If this is a concat/alternate, then we might have additional + // inductive steps to process. + if let Some(x) = self.pop(frame) { + if let Frame::Alternation {..} = x { + visitor.visit_alternation_in()?; + } + hir = x.child(); + self.stack.push((post_hir, x)); + break; + } + // Otherwise, we've finished visiting all the child nodes for + // this HIR, so we can post visit it now. + visitor.visit_post(post_hir)?; + } + } + } + + /// Build a stack frame for the given HIR if one is needed (which occurs if + /// and only if there are child nodes in the HIR). Otherwise, return None. + fn induct(&mut self, hir: &'a Hir) -> Option<Frame<'a>> { + match *hir.kind() { + HirKind::Repetition(ref x) => Some(Frame::Repetition(x)), + HirKind::Group(ref x) => Some(Frame::Group(x)), + HirKind::Concat(ref x) if x.is_empty() => None, + HirKind::Concat(ref x) => { + Some(Frame::Concat { + head: &x[0], + tail: &x[1..], + }) + } + HirKind::Alternation(ref x) if x.is_empty() => None, + HirKind::Alternation(ref x) => { + Some(Frame::Alternation { + head: &x[0], + tail: &x[1..], + }) + } + _ => None, + } + } + + /// Pops the given frame. If the frame has an additional inductive step, + /// then return it, otherwise return `None`. + fn pop(&self, induct: Frame<'a>) -> Option<Frame<'a>> { + match induct { + Frame::Repetition(_) => None, + Frame::Group(_) => None, + Frame::Concat { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Concat { + head: &tail[0], + tail: &tail[1..], + }) + } + } + Frame::Alternation { tail, .. } => { + if tail.is_empty() { + None + } else { + Some(Frame::Alternation { + head: &tail[0], + tail: &tail[1..], + }) + } + } + } + } +} + +impl<'a> Frame<'a> { + /// Perform the next inductive step on this frame and return the next + /// child HIR node to visit. + fn child(&self) -> &'a Hir { + match *self { + Frame::Repetition(rep) => &rep.hir, + Frame::Group(group) => &group.hir, + Frame::Concat { head, .. } => head, + Frame::Alternation { head, .. } => head, + } + } +} diff --git a/regex-syntax/src/lib.rs b/regex-syntax/src/lib.rs new file mode 100644 index 000000000..f47ad9ce4 --- /dev/null +++ b/regex-syntax/src/lib.rs @@ -0,0 +1,228 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +This crate provides a robust regular expression parser. + +This crate defines two primary types: + +* [`Ast`](ast/enum.Ast.html) is the abstract syntax of a regular expression. + An abstract syntax corresponds to a *structured representation* of the + concrete syntax of a regular expression, where the concrete syntax is the + pattern string itself (e.g., `foo(bar)+`). Given some abstract syntax, it + can be converted back to the original concrete syntax (modulo some details, + like whitespace). To a first approximation, the abstract syntax is complex + and difficult to analyze. +* [`Hir`](hir/struct.Hir.html) is the high-level intermediate representation + ("HIR" or "high-level IR" for short) of regular expression. It corresponds to + an intermediate state of a regular expression that sits between the abstract + syntax and the low level compiled opcodes that are eventually responsible for + executing a regular expression search. Given some high-level IR, it is not + possible to produce the original concrete syntax (although it is possible to + produce an equivalent conrete syntax, but it will likely scarcely resemble + the original pattern). To a first approximation, the high-level IR is simple + and easy to analyze. + +These two types come with conversion routines: + +* An [`ast::parse::Parser`](ast/parse/struct.Parser.html) converts concrete + syntax (a `&str`) to an [`Ast`](ast/enum.Ast.html). +* A [`hir::translate::Translator`](hir/translate/struct.Translator.html) + converts an [`Ast`](ast/enum.Ast.html) to a [`Hir`](hir/struct.Hir.html). + +As a convenience, the above two conversion routines are combined into one via +the top-level [`Parser`](struct.Parser.html) type. This `Parser` will first +convert your pattern to an `Ast` and then convert the `Ast` to an `Hir`. + + +# Example + +This example shows how to parse a pattern string into its HIR: + +``` +use regex_syntax::Parser; +use regex_syntax::hir::{self, Hir}; + +let hir = Parser::new().parse("a|b").unwrap(); +assert_eq!(hir, Hir::alternation(vec![ + Hir::literal(hir::Literal::Unicode('a')), + Hir::literal(hir::Literal::Unicode('b')), +])); +``` + + +# Concrete syntax supported + +The concrete syntax is documented as part of the public API of the +[`regex` crate](https://docs.rs/regex/%2A/regex/#syntax). + + +# Input safety + +A key feature of this library is that it is safe to use with end user facing +input. This plays a significant role in the internal implementation. In +particular: + +1. Parsers provide a `nest_limit` option that permits callers to control how + deeply nested a regular expression is allowed to be. This makes it possible + to do case analysis over an `Ast` or an `Hir` using recursion without + worrying about stack overflow. +2. Since relying on a particular stack size is brittle, this crate goes to + great lengths to ensure that all interactions with both the `Ast` and the + `Hir` do not use recursion. Namely, they use constant stack space and heap + space proportional to the size of the original pattern string (in bytes). + This includes the type's corresponding destructors. (One exception to this + is literal extraction, but this will eventually get fixed.) + + +# Error reporting + +The `Display` implementations on all `Error` types exposed in this library +provide nice human readable errors that are suitable for showing to end users +in a monospace font. + + +# Literal extraction + +This crate provides limited support for +[literal extraction from `Hir` values](hir/literal/struct.Literals.html). +Be warned that literal extraction currently uses recursion, and therefore, +stack size proportional to the size of the `Hir`. + +The purpose of literal extraction is to speed up searches. That is, if you +know a regular expression must match a prefix or suffix literal, then it is +often quicker to search for instances of that literal, and then confirm or deny +the match using the full regular expression engine. These optimizations are +done automatically in the `regex` crate. +*/ + +#![deny(missing_docs)] + +extern crate ucd_util; + +pub use error::{Error, Result}; +pub use parser::{Parser, ParserBuilder}; + +pub mod ast; +mod either; +mod error; +pub mod hir; +mod parser; +mod unicode; +mod unicode_tables; + +/// Escapes all regular expression meta characters in `text`. +/// +/// The string returned may be safely used as a literal in a regular +/// expression. +pub fn escape(text: &str) -> String { + let mut quoted = String::with_capacity(text.len()); + escape_into(text, &mut quoted); + quoted +} + +/// Escapes all meta characters in `text` and writes the result into `buf`. +/// +/// This will append escape characters into the given buffer. The characters +/// that are appended are safe to use as a literal in a regular expression. +pub fn escape_into(text: &str, buf: &mut String) { + for c in text.chars() { + if is_meta_character(c) { + buf.push('\\'); + } + buf.push(c); + } +} + +/// Returns true if the give character has significance in a regex. +/// +/// These are the only characters that are allowed to be escaped, with one +/// exception: an ASCII space character may be escaped when extended mode (with +/// the `x` flag) is enabld. In particular, `is_meta_character(' ')` returns +/// `false`. +/// +/// Note that the set of characters for which this function returns `true` or +/// `false` is fixed and won't change in a semver compatible release. +pub fn is_meta_character(c: char) -> bool { + match c { + '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | + '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~' => true, + _ => false, + } +} + +/// Returns true if and only if the given character is a Unicode word +/// character. +/// +/// A Unicode word character is defined by +/// [UTS#18 Annex C](http://unicode.org/reports/tr18/#Compatibility_Properties). +/// In particular, a character +/// is considered a word character if it is in either of the `Alphabetic` or +/// `Join_Control` properties, or is in one of the `Decimal_Number`, `Mark` +/// or `Connector_Punctuation` general categories. +pub fn is_word_character(c: char) -> bool { + use std::cmp::Ordering; + use unicode_tables::perl_word::PERL_WORD; + + if c <= 0x7F as char && is_word_byte(c as u8) { + return true; + } + PERL_WORD + .binary_search_by(|&(start, end)| { + if start <= c && c <= end { + Ordering::Equal + } else if start > c { + Ordering::Greater + } else { + Ordering::Less + } + }).is_ok() +} + +/// Returns true if and only if the given character is an ASCII word character. +/// +/// An ASCII word character is defined by the following character class: +/// `[_0-9a-zA-Z]'. +pub fn is_word_byte(c: u8) -> bool { + match c { + b'_' | b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z' => true, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn escape_meta() { + assert_eq!( + escape(r"\.+*?()|[]{}^$#&-~"), + r"\\\.\+\*\?\(\)\|\[\]\{\}\^\$\#\&\-\~".to_string()); + } + + #[test] + fn word() { + assert!(is_word_byte(b'a')); + assert!(!is_word_byte(b'-')); + + assert!(is_word_character('a'), "ASCII"); + assert!(is_word_character('à'), "Latin-1"); + assert!(is_word_character('β'), "Greek"); + assert!(is_word_character('\u{11011}'), "Brahmi (Unicode 6.0)"); + assert!(is_word_character('\u{11611}'), "Modi (Unicode 7.0)"); + assert!(is_word_character('\u{11711}'), "Ahom (Unicode 8.0)"); + assert!(is_word_character('\u{17828}'), "Tangut (Unicode 9.0)"); + assert!(is_word_character('\u{1B1B1}'), "Nushu (Unicode 10.0)"); + assert!(is_word_character('\u{16E40}'), "Medefaidrin (Unicode 11.0)"); + assert!(!is_word_character('-')); + assert!(!is_word_character('☃')); + } +} diff --git a/regex-syntax/src/parser.rs b/regex-syntax/src/parser.rs new file mode 100644 index 000000000..9788ad557 --- /dev/null +++ b/regex-syntax/src/parser.rs @@ -0,0 +1,206 @@ +use ast; +use hir; + +use Result; + +/// A builder for a regular expression parser. +/// +/// This builder permits modifying configuration options for the parser. +/// +/// This type combines the builder options for both the +/// [AST `ParserBuilder`](ast/parse/struct.ParserBuilder.html) +/// and the +/// [HIR `TranslatorBuilder`](hir/translate/struct.TranslatorBuilder.html). +#[derive(Clone, Debug, Default)] +pub struct ParserBuilder { + ast: ast::parse::ParserBuilder, + hir: hir::translate::TranslatorBuilder, +} + +impl ParserBuilder { + /// Create a new parser builder with a default configuration. + pub fn new() -> ParserBuilder { + ParserBuilder::default() + } + + /// Build a parser from this configuration with the given pattern. + pub fn build(&self) -> Parser { + Parser { + ast: self.ast.build(), + hir: self.hir.build(), + } + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire Ast is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// lenth of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut ParserBuilder { + self.ast.nest_limit(limit); + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut ParserBuilder { + self.ast.octal(yes); + self + } + + /// When enabled, the parser will permit the construction of a regular + /// expression that may match invalid UTF-8. + /// + /// When disabled (the default), the parser is guaranteed to produce + /// an expression that will only ever match valid UTF-8 (otherwise, the + /// parser will return an error). + /// + /// Perhaps surprisingly, when invalid UTF-8 isn't allowed, a negated ASCII + /// word boundary (uttered as `(?-u:\B)` in the concrete syntax) will cause + /// the parser to return an error. Namely, a negated ASCII word boundary + /// can result in matching positions that aren't valid UTF-8 boundaries. + pub fn allow_invalid_utf8(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.allow_invalid_utf8(yes); + self + } + + /// Enable verbose mode in the regular expression. + /// + /// When enabled, verbose mode permits insigificant whitespace in many + /// places in the regular expression, as well as comments. Comments are + /// started using `#` and continue until the end of the line. + /// + /// By default, this is disabled. It may be selectively enabled in the + /// regular expression by using the `x` flag regardless of this setting. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut ParserBuilder { + self.ast.ignore_whitespace(yes); + self + } + + /// Enable or disable the case insensitive flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `i` flag. + pub fn case_insensitive(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.case_insensitive(yes); + self + } + + /// Enable or disable the multi-line matching flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `m` flag. + pub fn multi_line(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.multi_line(yes); + self + } + + /// Enable or disable the "dot matches any character" flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `s` flag. + pub fn dot_matches_new_line( + &mut self, + yes: bool, + ) -> &mut ParserBuilder { + self.hir.dot_matches_new_line(yes); + self + } + + /// Enable or disable the "swap greed" flag by default. + /// + /// By default this is disabled. It may alternatively be selectively + /// enabled in the regular expression itself via the `U` flag. + pub fn swap_greed(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.swap_greed(yes); + self + } + + /// Enable or disable the Unicode flag (`u`) by default. + /// + /// By default this is **enabled**. It may alternatively be selectively + /// disabled in the regular expression itself via the `u` flag. + /// + /// Note that unless `allow_invalid_utf8` is enabled (it's disabled by + /// default), a regular expression will fail to parse if Unicode mode is + /// disabled and a sub-expression could possibly match invalid UTF-8. + pub fn unicode(&mut self, yes: bool) -> &mut ParserBuilder { + self.hir.unicode(yes); + self + } +} + +/// A convenience parser for regular expressions. +/// +/// This parser takes as input a regular expression pattern string (the +/// "concrete syntax") and returns a high-level intermediate representation +/// (the HIR) suitable for most types of analysis. In particular, this parser +/// hides the intermediate state of producing an AST (the "abstract syntax"). +/// The AST is itself far more complex than the HIR, so this parser serves as a +/// convenience for never having to deal with it at all. +/// +/// If callers have more fine grained use cases that need an AST, then please +/// see the [`ast::parse`](ast/parse/index.html) module. +/// +/// A `Parser` can be configured in more detail via a +/// [`ParserBuilder`](struct.ParserBuilder.html). +#[derive(Clone, Debug)] +pub struct Parser { + ast: ast::parse::Parser, + hir: hir::translate::Translator, +} + +impl Parser { + /// Create a new parser with a default configuration. + /// + /// The parser can be run with `parse` method. The parse method returns + /// a high level intermediate representation of the given regular + /// expression. + /// + /// To set configuration options on the parser, use + /// [`ParserBuilder`](struct.ParserBuilder.html). + pub fn new() -> Parser { + ParserBuilder::new().build() + } + + /// Parse the regular expression into a high level intermediate + /// representation. + pub fn parse(&mut self, pattern: &str) -> Result<hir::Hir> { + let ast = self.ast.parse(pattern)?; + let hir = self.hir.translate(pattern, &ast)?; + Ok(hir) + } +} diff --git a/regex-syntax/src/unicode.rs b/regex-syntax/src/unicode.rs new file mode 100644 index 000000000..cdc59fcf4 --- /dev/null +++ b/regex-syntax/src/unicode.rs @@ -0,0 +1,455 @@ +use std::cmp::Ordering; +use std::result; + +use ucd_util::{self, PropertyValues}; + +use hir; +use unicode_tables::age; +use unicode_tables::case_folding_simple::CASE_FOLDING_SIMPLE; +use unicode_tables::general_category; +use unicode_tables::grapheme_cluster_break; +use unicode_tables::property_bool; +use unicode_tables::property_names::PROPERTY_NAMES; +use unicode_tables::property_values::PROPERTY_VALUES; +use unicode_tables::script; +use unicode_tables::script_extension; +use unicode_tables::sentence_break; +use unicode_tables::word_break; + +type Result<T> = result::Result<T, Error>; + +/// An error that occurs when dealing with Unicode. +/// +/// We don't impl the Error trait here because these always get converted +/// into other public errors. (This error type isn't exported.) +#[derive(Debug)] +pub enum Error { + PropertyNotFound, + PropertyValueNotFound, +} + +/// An iterator over a codepoint's simple case equivalence class. +#[derive(Debug)] +pub struct SimpleFoldIter(::std::slice::Iter<'static, char>); + +impl Iterator for SimpleFoldIter { + type Item = char; + + fn next(&mut self) -> Option<char> { + self.0.next().map(|c| *c) + } +} + +/// Return an iterator over the equivalence class of simple case mappings +/// for the given codepoint. The equivalence class does not include the +/// given codepoint. +/// +/// If the equivalence class is empty, then this returns the next scalar +/// value that has a non-empty equivalence class, if it exists. If no such +/// scalar value exists, then `None` is returned. The point of this behavior +/// is to permit callers to avoid calling `simple_fold` more than they need +/// to, since there is some cost to fetching the equivalence class. +pub fn simple_fold(c: char) -> result::Result<SimpleFoldIter, Option<char>> { + CASE_FOLDING_SIMPLE + .binary_search_by_key(&c, |&(c1, _)| c1) + .map(|i| SimpleFoldIter(CASE_FOLDING_SIMPLE[i].1.iter())) + .map_err(|i| { + if i >= CASE_FOLDING_SIMPLE.len() { + None + } else { + Some(CASE_FOLDING_SIMPLE[i].0) + } + }) +} + +/// Returns true if and only if the given (inclusive) range contains at least +/// one Unicode scalar value that has a non-empty non-trivial simple case +/// mapping. +/// +/// This function panics if `end < start`. +pub fn contains_simple_case_mapping(start: char, end: char) -> bool { + assert!(start <= end); + CASE_FOLDING_SIMPLE + .binary_search_by(|&(c, _)| { + if start <= c && c <= end { + Ordering::Equal + } else if c > end { + Ordering::Greater + } else { + Ordering::Less + } + }).is_ok() +} + +/// A query for finding a character class defined by Unicode. This supports +/// either use of a property name directly, or lookup by property value. The +/// former generally refers to Binary properties (see UTS#44, Table 8), but +/// as a special exception (see UTS#18, Section 1.2) both general categories +/// (an enumeration) and scripts (a catalog) are supported as if each of their +/// possible values were a binary property. +/// +/// In all circumstances, property names and values are normalized and +/// canonicalized. That is, `GC == gc == GeneralCategory == general_category`. +/// +/// The lifetime `'a` refers to the shorter of the lifetimes of property name +/// and property value. +#[derive(Debug)] +pub enum ClassQuery<'a> { + /// Return a class corresponding to a Unicode binary property, named by + /// a single letter. + OneLetter(char), + /// Return a class corresponding to a Unicode binary property. + /// + /// Note that, by special exception (see UTS#18, Section 1.2), both + /// general category values and script values are permitted here as if + /// they were a binary property. + Binary(&'a str), + /// Return a class corresponding to all codepoints whose property + /// (identified by `property_name`) corresponds to the given value + /// (identified by `property_value`). + ByValue { + /// A property name. + property_name: &'a str, + /// A property value. + property_value: &'a str, + }, +} + +impl<'a> ClassQuery<'a> { + fn canonicalize(&self) -> Result<CanonicalClassQuery> { + match *self { + ClassQuery::OneLetter(c) => self.canonical_binary(&c.to_string()), + ClassQuery::Binary(name) => self.canonical_binary(name), + ClassQuery::ByValue { property_name, property_value } => { + let property_name = normalize(property_name); + let property_value = normalize(property_value); + + let canon_name = match canonical_prop(&property_name) { + None => return Err(Error::PropertyNotFound), + Some(canon_name) => canon_name, + }; + Ok(match canon_name { + "General_Category" => { + let canon = match canonical_gencat(&property_value) { + None => return Err(Error::PropertyValueNotFound), + Some(canon) => canon, + }; + CanonicalClassQuery::GeneralCategory(canon) + } + "Script" => { + let canon = match canonical_script(&property_value) { + None => return Err(Error::PropertyValueNotFound), + Some(canon) => canon, + }; + CanonicalClassQuery::Script(canon) + } + _ => { + let vals = match property_values(canon_name) { + None => return Err(Error::PropertyValueNotFound), + Some(vals) => vals, + }; + let canon_val = match canonical_value( + vals, + &property_value, + ) { + None => return Err(Error::PropertyValueNotFound), + Some(canon_val) => canon_val, + }; + CanonicalClassQuery::ByValue { + property_name: canon_name, + property_value: canon_val, + } + } + }) + } + } + } + + fn canonical_binary(&self, name: &str) -> Result<CanonicalClassQuery> { + let norm = normalize(name); + + if let Some(canon) = canonical_prop(&norm) { + return Ok(CanonicalClassQuery::Binary(canon)); + } + if let Some(canon) = canonical_gencat(&norm) { + return Ok(CanonicalClassQuery::GeneralCategory(canon)); + } + if let Some(canon) = canonical_script(&norm) { + return Ok(CanonicalClassQuery::Script(canon)); + } + Err(Error::PropertyNotFound) + } +} + +/// Like ClassQuery, but its parameters have been canonicalized. This also +/// differentiates binary properties from flattened general categories and +/// scripts. +#[derive(Debug, Eq, PartialEq)] +enum CanonicalClassQuery { + /// The canonical binary property name. + Binary(&'static str), + /// The canonical general category name. + GeneralCategory(&'static str), + /// The canonical script name. + Script(&'static str), + /// An arbitrary association between property and value, both of which + /// have been canonicalized. + /// + /// Note that by construction, the property name of ByValue will never + /// be General_Category or Script. Those two cases are subsumed by the + /// eponymous variants. + ByValue { + /// The canonical property name. + property_name: &'static str, + /// The canonical property value. + property_value: &'static str, + }, +} + +/// Looks up a Unicode class given a query. If one doesn't exist, then +/// `None` is returned. +pub fn class<'a>(query: ClassQuery<'a>) -> Result<hir::ClassUnicode> { + use self::CanonicalClassQuery::*; + + match query.canonicalize()? { + Binary(name) => { + property_set(property_bool::BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyNotFound) + } + GeneralCategory("Any") => { + Ok(hir_class(&[('\0', '\u{10FFFF}')])) + } + GeneralCategory("Assigned") => { + let mut cls = + property_set(general_category::BY_NAME, "Unassigned") + .map(hir_class) + .ok_or(Error::PropertyNotFound)?; + cls.negate(); + Ok(cls) + } + GeneralCategory("ASCII") => { + Ok(hir_class(&[('\0', '\x7F')])) + } + GeneralCategory(name) => { + property_set(general_category::BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + Script(name) => { + property_set(script::BY_NAME, name) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + ByValue { property_name: "Age", property_value } => { + let mut class = hir::ClassUnicode::empty(); + for set in ages(property_value)? { + class.union(&hir_class(set)); + } + Ok(class) + } + ByValue { property_name: "Script_Extensions", property_value } => { + property_set(script_extension::BY_NAME, property_value) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + ByValue { property_name: "Grapheme_Cluster_Break", property_value } => { + property_set(grapheme_cluster_break::BY_NAME, property_value) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + ByValue { property_name: "Sentence_Break", property_value } => { + property_set(sentence_break::BY_NAME, property_value) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + ByValue { property_name: "Word_Break", property_value } => { + property_set(word_break::BY_NAME, property_value) + .map(hir_class) + .ok_or(Error::PropertyValueNotFound) + } + _ => { + // What else should we support? + Err(Error::PropertyNotFound) + } + } +} + +/// Build a Unicode HIR class from a sequence of Unicode scalar value ranges. +pub fn hir_class(ranges: &[(char, char)]) -> hir::ClassUnicode { + let hir_ranges: Vec<hir::ClassUnicodeRange> = ranges + .iter() + .map(|&(s, e)| hir::ClassUnicodeRange::new(s, e)) + .collect(); + hir::ClassUnicode::new(hir_ranges) +} + +fn canonical_prop(normalized_name: &str) -> Option<&'static str> { + ucd_util::canonical_property_name(PROPERTY_NAMES, normalized_name) +} + +fn canonical_gencat(normalized_value: &str) -> Option<&'static str> { + match normalized_value { + "any" => Some("Any"), + "assigned" => Some("Assigned"), + "ascii" => Some("ASCII"), + _ => { + let gencats = property_values("General_Category").unwrap(); + canonical_value(gencats, normalized_value) + } + } +} + +fn canonical_script(normalized_value: &str) -> Option<&'static str> { + let scripts = property_values("Script").unwrap(); + canonical_value(scripts, normalized_value) +} + +fn canonical_value( + vals: PropertyValues, + normalized_value: &str, +) -> Option<&'static str> { + ucd_util::canonical_property_value(vals, normalized_value) +} + +fn normalize(x: &str) -> String { + let mut x = x.to_string(); + ucd_util::symbolic_name_normalize(&mut x); + x +} + +fn property_values( + canonical_property_name: &'static str, +) -> Option<PropertyValues> +{ + ucd_util::property_values(PROPERTY_VALUES, canonical_property_name) +} + +fn property_set( + name_map: &'static [(&'static str, &'static [(char, char)])], + canonical: &'static str, +) -> Option<&'static [(char, char)]> { + name_map + .binary_search_by_key(&canonical, |x| x.0) + .ok() + .map(|i| name_map[i].1) +} + +/// An iterator over Unicode Age sets. Each item corresponds to a set of +/// codepoints that were added in a particular revision of Unicode. The +/// iterator yields items in chronological order. +#[derive(Debug)] +struct AgeIter { + ages: &'static [(&'static str, &'static [(char, char)])], +} + +fn ages(canonical_age: &str) -> Result<AgeIter> { + const AGES: &'static [(&'static str, &'static [(char, char)])] = &[ + ("V1_1", age::V1_1), + ("V2_0", age::V2_0), + ("V2_1", age::V2_1), + ("V3_0", age::V3_0), + ("V3_1", age::V3_1), + ("V3_2", age::V3_2), + ("V4_0", age::V4_0), + ("V4_1", age::V4_1), + ("V5_0", age::V5_0), + ("V5_1", age::V5_1), + ("V5_2", age::V5_2), + ("V6_0", age::V6_0), + ("V6_1", age::V6_1), + ("V6_2", age::V6_2), + ("V6_3", age::V6_3), + ("V7_0", age::V7_0), + ("V8_0", age::V8_0), + ("V9_0", age::V9_0), + ("V10_0", age::V10_0), + ("V11_0", age::V11_0), + ]; + assert_eq!(AGES.len(), age::BY_NAME.len(), "ages are out of sync"); + + let pos = AGES.iter().position(|&(age, _)| canonical_age == age); + match pos { + None => Err(Error::PropertyValueNotFound), + Some(i) => Ok(AgeIter { ages: &AGES[..i+1] }), + } +} + +impl Iterator for AgeIter { + type Item = &'static [(char, char)]; + + fn next(&mut self) -> Option<&'static [(char, char)]> { + if self.ages.is_empty() { + None + } else { + let set = self.ages[0]; + self.ages = &self.ages[1..]; + Some(set.1) + } + } +} + +#[cfg(test)] +mod tests { + use super::{contains_simple_case_mapping, simple_fold}; + + #[test] + fn simple_fold_k() { + let xs: Vec<char> = simple_fold('k').unwrap().collect(); + assert_eq!(xs, vec!['K', 'K']); + + let xs: Vec<char> = simple_fold('K').unwrap().collect(); + assert_eq!(xs, vec!['k', 'K']); + + let xs: Vec<char> = simple_fold('K').unwrap().collect(); + assert_eq!(xs, vec!['K', 'k']); + } + + #[test] + fn simple_fold_a() { + let xs: Vec<char> = simple_fold('a').unwrap().collect(); + assert_eq!(xs, vec!['A']); + + let xs: Vec<char> = simple_fold('A').unwrap().collect(); + assert_eq!(xs, vec!['a']); + } + + #[test] + fn simple_fold_empty() { + assert_eq!(Some('A'), simple_fold('?').unwrap_err()); + assert_eq!(Some('A'), simple_fold('@').unwrap_err()); + assert_eq!(Some('a'), simple_fold('[').unwrap_err()); + assert_eq!(Some('Ⰰ'), simple_fold('☃').unwrap_err()); + } + + #[test] + fn simple_fold_max() { + assert_eq!(None, simple_fold('\u{10FFFE}').unwrap_err()); + assert_eq!(None, simple_fold('\u{10FFFF}').unwrap_err()); + } + + #[test] + fn range_contains() { + assert!(contains_simple_case_mapping('A', 'A')); + assert!(contains_simple_case_mapping('Z', 'Z')); + assert!(contains_simple_case_mapping('A', 'Z')); + assert!(contains_simple_case_mapping('@', 'A')); + assert!(contains_simple_case_mapping('Z', '[')); + assert!(contains_simple_case_mapping('☃', 'Ⰰ')); + + assert!(!contains_simple_case_mapping('[', '[')); + assert!(!contains_simple_case_mapping('[', '`')); + + assert!(!contains_simple_case_mapping('☃', '☃')); + } + + #[test] + fn regression_466() { + use super::{CanonicalClassQuery, ClassQuery}; + + let q = ClassQuery::OneLetter('C'); + assert_eq!( + q.canonicalize().unwrap(), + CanonicalClassQuery::GeneralCategory("Other")); + } +} diff --git a/regex-syntax/src/unicode_tables/LICENSE-UNICODE b/regex-syntax/src/unicode_tables/LICENSE-UNICODE new file mode 100644 index 000000000..b82826bdb --- /dev/null +++ b/regex-syntax/src/unicode_tables/LICENSE-UNICODE @@ -0,0 +1,57 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +Unicode Data Files do not include PDF online code charts under the +directory http://www.unicode.org/Public/. + +Software includes any source code published in the Unicode Standard +or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2018 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. diff --git a/regex-syntax/src/unicode_tables/age.rs b/regex-syntax/src/unicode_tables/age.rs new file mode 100644 index 000000000..8e2cd0a9f --- /dev/null +++ b/regex-syntax/src/unicode_tables/age.rs @@ -0,0 +1,455 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate age tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("V10_0", V10_0), ("V11_0", V11_0), ("V1_1", V1_1), ("V2_0", V2_0), + ("V2_1", V2_1), ("V3_0", V3_0), ("V3_1", V3_1), ("V3_2", V3_2), + ("V4_0", V4_0), ("V4_1", V4_1), ("V5_0", V5_0), ("V5_1", V5_1), + ("V5_2", V5_2), ("V6_0", V6_0), ("V6_1", V6_1), ("V6_2", V6_2), + ("V6_3", V6_3), ("V7_0", V7_0), ("V8_0", V8_0), ("V9_0", V9_0), +]; + +pub const V10_0: &'static [(char, char)] = &[ + ('à¡ ', 'ࡪ'), ('à§¼', 'à§½'), ('ૺ', 'à«¿'), ('ഀ', 'ഀ'), + ('à´»', 'à´¼'), ('á³·', 'á³·'), ('á·¶', 'á·¹'), ('₿', '₿'), + ('⏿', '⏿'), ('⯒', '⯒'), ('⹅', '⹉'), ('ㄮ', 'ㄮ'), + ('鿖', '鿪'), ('𐌭', '𐌯'), ('𑨀', '𑩇'), ('𑩐', '𑪃'), + ('𑪆', '𑪜'), ('𑪞', '𑪢'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), + ('𑴋', '𑴶'), ('𑴺', '𑴺'), ('𑴼', '𑴽'), ('𑴿', '𑵇'), + ('𑵐', '𑵙'), ('𖿡', '𖿡'), ('𛀂', '𛄞'), ('𛅰', '𛋻'), + ('🉠', '🉥'), ('🛓', '🛔'), ('🛷', '🛸'), ('🤀', '🤋'), + ('🤟', '🤟'), ('🤨', '🤯'), ('🤱', '🤲'), ('🥌', '🥌'), + ('🥟', '🥫'), ('🦒', '🦗'), ('🧐', '🧦'), ('𬺰', '𮯠'), +]; + +pub const V11_0: &'static [(char, char)] = &[ + ('\u{560}', '\u{560}'), ('\u{588}', '\u{588}'), ('\u{5ef}', '\u{5ef}'), + ('\u{7fd}', '\u{7ff}'), ('\u{8d3}', '\u{8d3}'), ('\u{9fe}', '\u{9fe}'), + ('\u{a76}', '\u{a76}'), ('\u{c04}', '\u{c04}'), ('\u{c84}', '\u{c84}'), + ('\u{1878}', '\u{1878}'), ('\u{1c90}', '\u{1cba}'), + ('\u{1cbd}', '\u{1cbf}'), ('\u{2bba}', '\u{2bbc}'), + ('\u{2bd3}', '\u{2beb}'), ('\u{2bf0}', '\u{2bfe}'), + ('\u{2e4a}', '\u{2e4e}'), ('\u{312f}', '\u{312f}'), + ('\u{9feb}', '\u{9fef}'), ('\u{a7af}', '\u{a7af}'), + ('\u{a7b8}', '\u{a7b9}'), ('\u{a8fe}', '\u{a8ff}'), + ('\u{10a34}', '\u{10a35}'), ('\u{10a48}', '\u{10a48}'), + ('\u{10d00}', '\u{10d27}'), ('\u{10d30}', '\u{10d39}'), + ('\u{10f00}', '\u{10f27}'), ('\u{10f30}', '\u{10f59}'), + ('\u{110cd}', '\u{110cd}'), ('\u{11144}', '\u{11146}'), + ('\u{1133b}', '\u{1133b}'), ('\u{1145e}', '\u{1145e}'), + ('\u{1171a}', '\u{1171a}'), ('\u{11800}', '\u{1183b}'), + ('\u{11a9d}', '\u{11a9d}'), ('\u{11d60}', '\u{11d65}'), + ('\u{11d67}', '\u{11d68}'), ('\u{11d6a}', '\u{11d8e}'), + ('\u{11d90}', '\u{11d91}'), ('\u{11d93}', '\u{11d98}'), + ('\u{11da0}', '\u{11da9}'), ('\u{11ee0}', '\u{11ef8}'), + ('\u{16e40}', '\u{16e9a}'), ('\u{187ed}', '\u{187f1}'), + ('\u{1d2e0}', '\u{1d2f3}'), ('\u{1d372}', '\u{1d378}'), + ('\u{1ec71}', '\u{1ecb4}'), ('\u{1f12f}', '\u{1f12f}'), + ('\u{1f6f9}', '\u{1f6f9}'), ('\u{1f7d5}', '\u{1f7d8}'), + ('\u{1f94d}', '\u{1f94f}'), ('\u{1f96c}', '\u{1f970}'), + ('\u{1f973}', '\u{1f976}'), ('\u{1f97a}', '\u{1f97a}'), + ('\u{1f97c}', '\u{1f97f}'), ('\u{1f998}', '\u{1f9a2}'), + ('\u{1f9b0}', '\u{1f9b9}'), ('\u{1f9c1}', '\u{1f9c2}'), + ('\u{1f9e7}', '\u{1f9ff}'), ('\u{1fa60}', '\u{1fa6d}'), +]; + +pub const V1_1: &'static [(char, char)] = &[ + ('\u{0}', 'ǵ'), ('Ǻ', 'ȗ'), ('ɐ', 'ʨ'), ('ʰ', '˞'), ('Ë ', 'Ë©'), + ('̀', 'ͅ'), ('Í ', 'Í¡'), ('Í´', '͵'), ('ͺ', 'ͺ'), (';', ';'), + ('΄', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'ώ'), ('ϐ', 'ϖ'), + ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), ('Ï ', 'Ï '), ('Ï¢', 'ϳ'), + ('Ё', 'Ќ'), ('Ў', 'я'), ('ё', 'ќ'), ('ў', '҆'), ('Ґ', 'ӄ'), + ('Ӈ', 'ӈ'), ('Ӌ', 'ӌ'), ('Ӑ', 'Ó«'), ('Ó®', 'Óµ'), ('Ó¸', 'Ó¹'), + ('Ô±', 'Ֆ'), ('ՙ', '՟'), ('Õ¡', 'և'), ('։', '։'), ('Ö°', 'Ö¹'), + ('Ö»', '׃'), ('א', 'ת'), ('×°', '×´'), ('،', '،'), ('؛', '؛'), + ('؟', '؟'), ('Ø¡', 'غ'), ('ـ', 'ْ'), ('Ù ', 'Ù­'), ('Ù°', 'Ú·'), + ('Úº', 'Ú¾'), ('ۀ', 'ێ'), ('ې', 'Û­'), ('Û°', 'Û¹'), ('ँ', 'ः'), + ('अ', 'ह'), ('़', '्'), ('ॐ', '॔'), ('क़', '॰'), + ('ঁ', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), ('ও', 'ন'), + ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), ('়', '়'), + ('া', 'ৄ'), ('ে', 'ৈ'), ('ো', '্'), ('ৗ', 'ৗ'), + ('ড়', 'ঢ়'), ('য়', 'à§£'), ('০', '৺'), ('ਂ', 'ਂ'), + ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('਼', '਼'), + ('ਾ', 'ੂ'), ('ੇ', 'ੈ'), ('ੋ', '੍'), ('ਖ਼', 'ੜ'), + ('ਫ਼', 'ਫ਼'), ('੦', 'à©´'), ('ઁ', 'ઃ'), ('અ', 'ઋ'), + ('ઍ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('઼', 'ૅ'), ('ે', 'ૉ'), + ('ો', '્'), ('ૐ', 'ૐ'), ('à« ', 'à« '), ('૦', '૯'), + ('ଁ', 'ଃ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), + ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଶ', 'ହ'), ('଼', 'ୃ'), + ('େ', 'ୈ'), ('ୋ', '୍'), ('ୖ', 'ୗ'), ('ଡ଼', 'ଢ଼'), + ('ୟ', 'à­¡'), ('à­¦', 'à­°'), ('ஂ', 'ஃ'), ('அ', 'ஊ'), + ('எ', 'ஐ'), ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), + ('ஞ', 'ட'), ('ண', 'த'), ('ந', 'ப'), ('à®®', 'வ'), + ('à®·', 'ஹ'), ('ா', 'ூ'), ('ெ', 'ை'), ('ொ', '்'), + ('ௗ', 'ௗ'), ('௧', '௲'), ('ఁ', 'ః'), ('అ', 'ఌ'), + ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°³'), ('à°µ', 'à°¹'), + ('à°¾', 'ౄ'), ('ె', 'ై'), ('ొ', '్'), ('ౕ', 'ౖ'), + ('à± ', 'ౡ'), ('౦', '౯'), ('ಂ', 'ಃ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('ಾ', 'ೄ'), ('ೆ', 'ೈ'), ('ೊ', '್'), ('ೕ', 'ೖ'), + ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), ('೦', '೯'), ('ം', 'ഃ'), + ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´¨'), ('à´ª', 'à´¹'), + ('à´¾', 'ൃ'), ('െ', 'ൈ'), ('ൊ', '്'), ('ൗ', 'ൗ'), + ('ൠ', 'ൡ'), ('൦', '൯'), ('ก', 'ฺ'), ('฿', '๛'), + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ູ'), + ('ົ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('່', 'ໍ'), + ('໐', '໙'), ('ໜ', 'ໝ'), ('Ⴀ', 'Ⴥ'), ('ა', 'ჶ'), + ('჻', '჻'), ('ᄀ', 'ᅙ'), ('ᅟ', 'ᆢ'), ('ᆨ', 'ᇹ'), + ('Ḁ', 'ẚ'), ('Ạ', 'ỹ'), ('ἀ', 'ἕ'), ('Ἐ', 'Ἕ'), + ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), + ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), + ('á¾¶', 'ῄ'), ('ῆ', 'ΐ'), ('ῖ', 'Ί'), ('῝', '`'), + ('ῲ', 'á¿´'), ('á¿¶', '῾'), ('\u{2000}', '\u{202e}'), ('‰', '⁆'), + ('\u{206a}', '⁰'), ('⁴', '₎'), ('₠', '₪'), ('⃐', '⃡'), + ('℀', 'ℸ'), ('⅓', 'ↂ'), ('←', '⇪'), ('∀', '⋱'), + ('⌀', '⌀'), ('⌂', '⍺'), ('␀', '␤'), ('⑀', '⑊'), + ('①', '⓪'), ('─', '▕'), ('■', '◯'), ('☀', '☓'), + ('☚', '♯'), ('✁', '✄'), ('✆', '✉'), ('✌', '✧'), + ('✩', '❋'), ('❍', '❍'), ('❏', '❒'), ('❖', '❖'), + ('❘', '❞'), ('❡', '❧'), ('❶', '➔'), ('➘', '➯'), + ('➱', '➾'), ('\u{3000}', '〷'), ('〿', '〿'), ('ぁ', 'ゔ'), + ('゙', 'ゞ'), ('ァ', 'ヾ'), ('ㄅ', 'ㄬ'), ('ㄱ', 'ㆎ'), + ('㆐', '㆟'), ('㈀', '㈜'), ('㈠', '㉃'), ('㉠', '㉻'), + ('㉿', '㊰'), ('㋀', '㋋'), ('㋐', '㋾'), ('㌀', '㍶'), + ('㍻', '㏝'), ('㏠', '㏾'), ('一', 'é¾¥'), ('\u{e000}', '鶴'), + ('ff', 'st'), ('ﬓ', 'ﬗ'), ('ﬞ', 'זּ'), ('טּ', 'לּ'), + ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), + ('ﯓ', 'ï´¿'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), + ('︠', '︣'), ('︰', '﹄'), ('﹉', '﹒'), ('﹔', '﹦'), + ('﹨', '﹫'), ('ï¹°', 'ï¹²'), ('ï¹´', 'ï¹´'), ('ï¹¶', 'ﻼ'), + ('\u{feff}', '\u{feff}'), ('!', '~'), ('。', 'ï¾¾'), ('ᅡ', 'ᅦ'), + ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('ï¿ ', '₩'), + ('│', 'ï¿®'), ('�', '\u{ffff}'), +]; + +pub const V2_0: &'static [(char, char)] = &[ + ('֑', 'Ö¡'), ('Ö£', 'Ö¯'), ('ׄ', 'ׄ'), ('ༀ', 'ཇ'), ('ཉ', 'ཀྵ'), + ('ཱ', 'ྋ'), ('ྐ', 'ྕ'), ('ྗ', 'ྗ'), ('ྙ', 'ྭ'), + ('ྱ', 'ྷ'), ('ྐྵ', 'ྐྵ'), ('ẛ', 'ẛ'), ('₫', '₫'), + ('가', '힣'), ('\u{1fffe}', '\u{1ffff}'), ('\u{2fffe}', '\u{2ffff}'), + ('\u{3fffe}', '\u{3ffff}'), ('\u{4fffe}', '\u{4ffff}'), + ('\u{5fffe}', '\u{5ffff}'), ('\u{6fffe}', '\u{6ffff}'), + ('\u{7fffe}', '\u{7ffff}'), ('\u{8fffe}', '\u{8ffff}'), + ('\u{9fffe}', '\u{9ffff}'), ('\u{afffe}', '\u{affff}'), + ('\u{bfffe}', '\u{bffff}'), ('\u{cfffe}', '\u{cffff}'), + ('\u{dfffe}', '\u{dffff}'), ('\u{efffe}', '\u{10ffff}'), +]; + +pub const V2_1: &'static [(char, char)] = &[ + ('€', '€'), ('', ''), +]; + +pub const V3_0: &'static [(char, char)] = &[ + ('Ƕ', 'ǹ'), ('Ș', 'ȟ'), ('È¢', 'ȳ'), ('Ê©', 'Ê­'), ('˟', '˟'), + ('˪', 'Ë®'), ('͆', '͎'), ('Í¢', 'Í¢'), ('ϗ', 'ϗ'), ('ϛ', 'ϛ'), + ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), ('Ï¡', 'Ï¡'), ('Ѐ', 'Ѐ'), ('Ѝ', 'Ѝ'), + ('ѐ', 'ѐ'), ('ѝ', 'ѝ'), ('҈', '҉'), ('Ҍ', 'ҏ'), ('Ó¬', 'Ó­'), + ('֊', '֊'), ('ٓ', 'ٕ'), ('Ú¸', 'Ú¹'), ('Ú¿', 'Ú¿'), ('ۏ', 'ۏ'), + ('Ûº', 'Û¾'), ('܀', '܍'), ('\u{70f}', 'ܬ'), ('ܰ', '݊'), ('ހ', 'Þ°'), + ('ං', 'ඃ'), ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), + ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('්', '්'), ('ා', 'ු'), + ('ූ', 'ූ'), ('ෘ', 'ෟ'), ('à·²', 'à·´'), ('ཪ', 'ཪ'), + ('ྖ', 'ྖ'), ('ྮ', 'ྰ'), ('ྸ', 'ྸ'), ('ྺ', 'ྼ'), + ('྾', '࿌'), ('࿏', '࿏'), ('က', 'အ'), ('ဣ', 'ဧ'), + ('ဩ', 'ဪ'), ('ာ', 'ဲ'), ('ံ', '္'), ('၀', 'ၙ'), + ('ሀ', 'ሆ'), ('ለ', 'ቆ'), ('ቈ', 'ቈ'), ('ቊ', 'ቍ'), + ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኆ'), + ('ኈ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኮ'), ('ኰ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዎ'), ('ዐ', 'ዖ'), ('ዘ', 'ዮ'), ('ደ', 'ጎ'), + ('ጐ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ጞ'), ('ጠ', 'ፆ'), + ('ፈ', 'ፚ'), ('፡', '፼'), ('Ꭰ', 'Ᏼ'), ('ᐁ', 'ᙶ'), + ('\u{1680}', '᚜'), ('ᚠ', 'ᛰ'), ('ក', 'ៜ'), ('០', '៩'), + ('᠀', '\u{180e}'), ('᠐', '᠙'), ('á  ', 'á¡·'), ('ᢀ', 'ᢩ'), + ('\u{202f}', '\u{202f}'), ('⁈', '⁍'), ('₭', '₯'), ('⃢', '⃣'), + ('ℹ', '℺'), ('Ↄ', 'Ↄ'), ('⇫', '⇳'), ('⌁', '⌁'), + ('⍻', '⍻'), ('⍽', '⎚'), ('␥', '␦'), ('◰', '◷'), + ('☙', '☙'), ('♰', '♱'), ('⠀', '⣿'), ('⺀', '⺙'), + ('⺛', '⻳'), ('⼀', '⿕'), ('â¿°', 'â¿»'), ('〸', '〺'), + ('〾', '〾'), ('ㆠ', 'ㆷ'), ('㐀', 'ä¶µ'), ('ꀀ', 'ꒌ'), + ('꒐', '꒡'), ('꒤', '꒳'), ('꒵', '꓀'), ('꓂', '꓄'), + ('꓆', '꓆'), ('יִ', 'יִ'), ('\u{fff9}', '\u{fffb}'), +]; + +pub const V3_1: &'static [(char, char)] = &[ + ('Ï´', 'ϵ'), ('\u{fdd0}', '\u{fdef}'), ('𐌀', '𐌞'), ('𐌠', '𐌣'), + ('𐌰', '𐍊'), ('𐐀', '𐐥'), ('𐐨', '𐑍'), ('𝀀', '𝃵'), + ('𝄀', '𝄦'), ('𝄪', '𝇝'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓀'), ('𝓂', '𝓃'), + ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕒', '𝚣'), ('𝚨', '𝟉'), ('𝟎', '𝟿'), + ('𠀀', '𪛖'), ('丽', '𪘀'), ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const V3_2: &'static [(char, char)] = &[ + ('È ', 'È '), ('͏', '͏'), ('Í£', 'ͯ'), ('Ϙ', 'ϙ'), ('϶', '϶'), + ('Ҋ', 'ҋ'), ('Ӆ', 'ӆ'), ('Ӊ', 'ӊ'), ('Ӎ', 'ӎ'), ('Ԁ', 'ԏ'), + ('Ù®', 'Ù¯'), ('Þ±', 'Þ±'), ('ჷ', 'ჸ'), ('ᜀ', 'ᜌ'), ('ᜎ', '᜔'), + ('ᜠ', '᜶'), ('ᝀ', 'ᝓ'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), + ('ᝲ', 'ᝳ'), ('⁇', '⁇'), ('⁎', '⁒'), ('⁗', '⁗'), + ('\u{205f}', '\u{2063}'), ('ⁱ', 'ⁱ'), ('₰', '₱'), ('⃤', '⃪'), + ('ℽ', '⅋'), ('⇴', '⇿'), ('⋲', '⋿'), ('⍼', '⍼'), + ('⎛', '⏎'), ('⓫', '⓾'), ('▖', '▟'), ('◸', '◿'), + ('☖', '☗'), ('♲', '♽'), ('⚀', '⚉'), ('❨', '❵'), + ('⟐', '⟫'), ('⟰', '⟿'), ('⤀', 'â«¿'), ('〻', '〽'), + ('ゕ', 'ゖ'), ('ゟ', '゠'), ('ヿ', 'ヿ'), ('ㇰ', 'ㇿ'), + ('㉑', '㉟'), ('㊱', '㊿'), ('꒢', '꒣'), ('꒴', '꒴'), + ('꓁', '꓁'), ('꓅', '꓅'), ('侮', '頻'), ('ï·¼', 'ï·¼'), + ('︀', '️'), ('﹅', '﹆'), ('ï¹³', 'ï¹³'), ('⦅', 'ï½ '), +]; + +pub const V4_0: &'static [(char, char)] = &[ + ('È¡', 'È¡'), ('È´', 'ȶ'), ('Ê®', 'ʯ'), ('˯', 'Ë¿'), ('͐', '͗'), + ('͝', '͟'), ('Ï·', 'Ï»'), ('\u{600}', '\u{603}'), ('؍', 'ؕ'), + ('ٖ', '٘'), ('Û®', 'Û¯'), ('Û¿', 'Û¿'), ('Ü­', 'ܯ'), ('ݍ', 'ݏ'), + ('ऄ', 'ऄ'), ('ঽ', 'ঽ'), ('ਁ', 'ਁ'), ('ਃ', 'ਃ'), + ('ઌ', 'ઌ'), ('à«¡', 'à«£'), ('૱', '૱'), ('ଵ', 'ଵ'), + ('à­±', 'à­±'), ('௳', '௺'), ('಼', 'ಽ'), ('៝', '៝'), + ('៰', '៹'), ('ᤀ', 'ᤜ'), ('ᤠ', 'ᤫ'), ('ᤰ', '᤻'), + ('᥀', '᥀'), ('᥄', 'ᥭ'), ('ᥰ', 'ᥴ'), ('á§ ', 'á§¿'), + ('ᴀ', 'ᵫ'), ('⁓', '⁔'), ('℻', '℻'), ('⏏', '⏐'), + ('⓿', '⓿'), ('☔', '☕'), ('⚊', '⚑'), ('⚠', '⚡'), + ('⬀', '⬍'), ('㈝', '㈞'), ('㉐', '㉐'), ('㉼', '㉽'), + ('㋌', '㋏'), ('㍷', '㍺'), ('㏞', '㏟'), ('㏿', '㏿'), + ('䷀', 'ä·¿'), ('ï·½', 'ï·½'), ('﹇', '﹈'), ('𐀀', '𐀋'), + ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), ('𐀿', '𐁍'), + ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐄀', '𐄂'), ('𐄇', '𐄳'), + ('𐄷', '𐄿'), ('𐎀', '𐎝'), ('𐎟', '𐎟'), ('𐐦', '𐐧'), + ('𐑎', '𐒝'), ('𐒠', '𐒩'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), + ('𐠊', '𐠵'), ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐠿'), + ('𝌀', '𝍖'), ('𝓁', '𝓁'), ('󠄀', '󠇯'), +]; + +pub const V4_1: &'static [(char, char)] = &[ + ('È·', 'Ɂ'), ('͘', '͜'), ('ϼ', 'Ï¿'), ('Ó¶', 'Ó·'), ('Ö¢', 'Ö¢'), + ('ׅ', 'ׇ'), ('؋', '؋'), ('؞', '؞'), ('ٙ', 'ٞ'), ('ݐ', 'Ý­'), + ('ॽ', 'ॽ'), ('ৎ', 'ৎ'), ('à®¶', 'à®¶'), ('௦', '௦'), + ('࿐', '࿑'), ('ჹ', 'ჺ'), ('ჼ', 'ჼ'), ('ሇ', 'ሇ'), + ('ቇ', 'ቇ'), ('ኇ', 'ኇ'), ('ኯ', 'ኯ'), ('ዏ', 'ዏ'), + ('ዯ', 'ዯ'), ('ጏ', 'ጏ'), ('ጟ', 'ጟ'), ('ፇ', 'ፇ'), + ('፟', '፠'), ('ᎀ', '᎙'), ('ᦀ', 'ᦩ'), ('ᦰ', 'ᧉ'), + ('᧐', '᧙'), ('᧞', '᧟'), ('ᨀ', 'ᨛ'), ('᨞', '᨟'), + ('ᵬ', '᷃'), ('⁕', '⁖'), ('⁘', '⁞'), ('ₐ', 'ₔ'), + ('₲', '₵'), ('⃫', '⃫'), ('ℼ', 'ℼ'), ('⅌', '⅌'), + ('⏑', '⏛'), ('☘', '☘'), ('♾', '♿'), ('⚒', '⚜'), + ('⚢', '⚱'), ('⟀', '⟆'), ('⬎', '⬓'), ('Ⰰ', 'â°®'), + ('â°°', 'ⱞ'), ('Ⲁ', '⳪'), ('â³¹', 'â´¥'), ('â´°', 'âµ¥'), + ('ⵯ', 'ⵯ'), ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), + ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), + ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('⸀', '⸗'), ('⸜', '⸝'), + ('㇀', '㇏'), ('㉾', '㉾'), ('龦', 'é¾»'), ('꜀', '꜖'), + ('ꠀ', 'ê «'), ('ï©°', '龎'), ('︐', '︙'), ('𐅀', '𐆊'), + ('𐎠', '𐏃'), ('𐏈', '𐏕'), ('𐨀', '𐨃'), ('𐨅', '𐨆'), + ('𐨌', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '𐨳'), ('𐨸', '𐨺'), + ('𐨿', '𐩇'), ('𐩐', '𐩘'), ('𝈀', '𝉅'), ('𝚤', '𝚥'), +]; + +pub const V5_0: &'static [(char, char)] = &[ + ('ɂ', 'ɏ'), ('Í»', 'ͽ'), ('ӏ', 'ӏ'), ('Óº', 'Ó¿'), ('Ԑ', 'ԓ'), + ('Öº', 'Öº'), ('߀', 'ߺ'), ('ॻ', 'ॼ'), ('ॾ', 'ॿ'), ('à³¢', 'à³£'), + ('à³±', 'à³²'), ('ᬀ', 'ᭋ'), ('᭐', 'á­¼'), ('᷄', '᷊'), + ('á·¾', 'á·¿'), ('⃬', '⃯'), ('⅍', 'ⅎ'), ('ↄ', 'ↄ'), + ('⏜', '⏧'), ('⚲', '⚲'), ('⟇', '⟊'), ('⬔', '⬚'), + ('⬠', '⬣'), ('â± ', 'ⱬ'), ('â±´', 'â±·'), ('ꜗ', 'ꜚ'), + ('꜠', '꜡'), ('ꡀ', 'ê¡·'), ('𐤀', '𐤙'), ('𐤟', '𐤟'), + ('𒀀', '𒍮'), ('𒐀', '𒑢'), ('𒑰', '𒑳'), ('𝍠', '𝍱'), + ('𝟊', '𝟋'), +]; + +pub const V5_1: &'static [(char, char)] = &[ + ('Ͱ', 'ͳ'), ('Ͷ', 'Í·'), ('Ϗ', 'Ϗ'), ('҇', '҇'), ('Ԕ', 'Ô£'), + ('؆', '؊'), ('ؖ', 'ؚ'), ('Ø»', 'Ø¿'), ('Ý®', 'Ý¿'), ('ॱ', 'ॲ'), + ('ੑ', 'ੑ'), ('ੵ', 'ੵ'), ('ୄ', 'ୄ'), ('à­¢', 'à­£'), + ('ௐ', 'ௐ'), ('à°½', 'à°½'), ('ౘ', 'ౙ'), ('à±¢', 'à±£'), + ('౸', '౿'), ('à´½', 'à´½'), ('ൄ', 'ൄ'), ('ൢ', 'ൣ'), + ('൰', '൵'), ('൹', 'ൿ'), ('ཫ', 'ཬ'), ('࿎', '࿎'), + ('࿒', '࿔'), ('ဢ', 'ဢ'), ('ဨ', 'ဨ'), ('ါ', 'ါ'), + ('ဳ', 'ဵ'), ('်', 'ဿ'), ('ၚ', '႙'), ('႞', '႟'), + ('ᢪ', 'ᢪ'), ('ᮀ', '᮪'), ('á®®', '᮹'), ('ᰀ', 'á°·'), + ('á°»', '᱉'), ('ᱍ', '᱿'), ('᷋', 'á·¦'), ('ẜ', 'ẟ'), + ('Ỻ', 'ỿ'), ('\u{2064}', '\u{2064}'), ('⃰', '⃰'), ('⅏', '⅏'), + ('ↅ', 'ↈ'), ('⚝', '⚝'), ('⚳', '⚼'), ('⛀', '⛃'), + ('⟌', '⟌'), ('⟬', '⟯'), ('⬛', '⬟'), ('⬤', '⭌'), + ('⭐', '⭔'), ('â±­', 'Ɐ'), ('â±±', 'â±³'), ('ⱸ', 'â±½'), + ('â· ', 'â·¿'), ('⸘', '⸛'), ('⸞', '⸰'), ('ㄭ', 'ㄭ'), + ('㇐', '㇣'), ('é¾¼', '鿃'), ('ꔀ', 'ꘫ'), ('Ꙁ', 'ꙟ'), + ('Ꙣ', '꙳'), ('꙼', 'ꚗ'), ('ꜛ', 'ꜟ'), ('Ꜣ', 'ꞌ'), + ('ꟻ', 'ꟿ'), ('ꢀ', '꣄'), ('꣎', '꣙'), ('꤀', '꥓'), + ('꥟', '꥟'), ('ꨀ', 'ꨶ'), ('ꩀ', 'ꩍ'), ('꩐', '꩙'), + ('꩜', '꩟'), ('︤', '︦'), ('𐆐', '𐆛'), ('𐇐', '𐇽'), + ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐤠', '𐤹'), ('𐤿', '𐤿'), + ('𝄩', '𝄩'), ('🀀', '🀫'), ('🀰', '🂓'), +]; + +pub const V5_2: &'static [(char, char)] = &[ + ('Ô¤', 'Ô¥'), ('ࠀ', 'à ­'), ('à °', 'à ¾'), ('ऀ', 'ऀ'), + ('ॎ', 'ॎ'), ('ॕ', 'ॕ'), ('ॹ', 'ॺ'), ('à§»', 'à§»'), + ('࿕', '࿘'), ('ႚ', 'ႝ'), ('ᅚ', 'ᅞ'), ('ᆣ', 'ᆧ'), + ('ᇺ', 'ᇿ'), ('᐀', '᐀'), ('ᙷ', 'ᙿ'), ('ᢰ', 'ᣵ'), + ('ᦪ', 'ᦫ'), ('᧚', '᧚'), ('ᨠ', 'ᩞ'), ('á© ', '᩼'), + ('á©¿', '᪉'), ('᪐', '᪙'), ('᪠', '᪭'), ('᳐', 'á³²'), + ('á·½', 'á·½'), ('₶', '₸'), ('⅐', '⅒'), ('↉', '↉'), + ('⏨', '⏨'), ('⚞', '⚟'), ('⚽', '⚿'), ('⛄', '⛍'), + ('⛏', '⛡'), ('⛣', '⛣'), ('⛨', '⛿'), ('❗', '❗'), + ('⭕', '⭙'), ('â±°', 'â±°'), ('â±¾', 'Ɀ'), ('Ⳬ', 'â³±'), + ('⸱', '⸱'), ('㉄', '㉏'), ('鿄', '鿋'), ('ꓐ', '꓿'), + ('ꚠ', '꛷'), ('ê °', 'ê ¹'), ('꣠', 'ꣻ'), ('ꥠ', 'ꥼ'), + ('ꦀ', '꧍'), ('ꧏ', '꧙'), ('꧞', '꧟'), ('ê© ', 'ê©»'), + ('ꪀ', 'ꫂ'), ('ꫛ', '꫟'), ('ꯀ', '꯭'), ('꯰', '꯹'), + ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('ï©«', 'ï©­'), ('𐡀', '𐡕'), + ('𐡗', '𐡟'), ('𐤚', '𐤛'), ('𐩠', '𐩿'), ('𐬀', '𐬵'), + ('𐬹', '𐭕'), ('𐭘', '𐭲'), ('𐭸', '𐭿'), ('𐰀', '𐱈'), + ('𐹠', '𐹾'), ('𑂀', '𑃁'), ('𓀀', '𓐮'), ('🄀', '🄊'), + ('🄐', '🄮'), ('🄱', '🄱'), ('🄽', '🄽'), ('🄿', '🄿'), + ('🅂', '🅂'), ('🅆', '🅆'), ('🅊', '🅎'), ('🅗', '🅗'), + ('🅟', '🅟'), ('🅹', '🅹'), ('🅻', '🅼'), ('🅿', '🅿'), + ('🆊', '🆍'), ('🆐', '🆐'), ('🈀', '🈀'), ('🈐', '🈱'), + ('🉀', '🉈'), ('𪜀', '𫜴'), +]; + +pub const V6_0: &'static [(char, char)] = &[ + ('Ô¦', 'Ô§'), ('Ø ', 'Ø '), ('ٟ', 'ٟ'), ('ࡀ', '࡛'), ('࡞', '࡞'), + ('ऺ', 'ऻ'), ('ॏ', 'ॏ'), ('ॖ', 'ॗ'), ('ॳ', 'ॷ'), + ('à­²', 'à­·'), ('à´©', 'à´©'), ('à´º', 'à´º'), ('ൎ', 'ൎ'), + ('ྌ', 'ྏ'), ('࿙', '࿚'), ('፝', '፞'), ('ᯀ', '᯳'), + ('᯼', '᯿'), ('á·¼', 'á·¼'), ('ₕ', 'ₜ'), ('₹', '₹'), + ('⏩', '⏳'), ('⛎', '⛎'), ('⛢', '⛢'), ('⛤', '⛧'), + ('✅', '✅'), ('✊', '✋'), ('✨', '✨'), ('❌', '❌'), + ('❎', '❎'), ('❓', '❕'), ('❟', '❠'), ('➕', '➗'), + ('➰', '➰'), ('➿', '➿'), ('⟎', '⟏'), ('âµ°', 'âµ°'), + ('⵿', '⵿'), ('ㆸ', 'ㆺ'), ('Ꙡ', 'ꙡ'), ('Ɥ', 'ꞎ'), + ('Ꞑ', 'ꞑ'), ('Ꞡ', 'ꞩ'), ('ꟺ', 'ꟺ'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), + ('﮲', '﯁'), ('𑀀', '𑁍'), ('𑁒', '𑁯'), ('𖠀', '𖨸'), + ('𛀀', '𛀁'), ('🂠', '🂮'), ('🂱', '🂾'), ('🃁', '🃏'), + ('🃑', '🃟'), ('🄰', '🄰'), ('🄲', '🄼'), ('🄾', '🄾'), + ('🅀', '🅁'), ('🅃', '🅅'), ('🅇', '🅉'), ('🅏', '🅖'), + ('🅘', '🅞'), ('🅠', '🅩'), ('🅰', '🅸'), ('🅺', '🅺'), + ('🅽', '🅾'), ('🆀', '🆉'), ('🆎', '🆏'), ('🆑', '🆚'), + ('🇦', '🇿'), ('🈁', '🈂'), ('🈲', '🈺'), ('🉐', '🉑'), + ('🌀', '🌠'), ('🌰', '🌵'), ('🌷', '🍼'), ('🎀', '🎓'), + ('🎠', '🏄'), ('🏆', '🏊'), ('🏠', '🏰'), ('🐀', '🐾'), + ('👀', '👀'), ('👂', '📷'), ('📹', '📼'), ('🔀', '🔽'), + ('🕐', '🕧'), ('🗻', '🗿'), ('😁', '😐'), ('😒', '😔'), + ('😖', '😖'), ('😘', '😘'), ('😚', '😚'), ('😜', '😞'), + ('😠', '😥'), ('😨', '😫'), ('😭', '😭'), ('😰', '😳'), + ('😵', '🙀'), ('🙅', '🙏'), ('🚀', '🛅'), ('🜀', '🝳'), + ('𫝀', '𫠝'), +]; + +pub const V6_1: &'static [(char, char)] = &[ + ('֏', '֏'), ('\u{604}', '\u{604}'), ('ࢠ', 'ࢠ'), ('ࢢ', 'ࢬ'), + ('ࣤ', 'ࣾ'), ('à«°', 'à«°'), ('ໞ', 'ໟ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ჽ', 'ჿ'), ('᮫', 'á®­'), ('ᮺ', 'ᮿ'), + ('᳀', '᳇'), ('á³³', 'á³¶'), ('⟋', '⟋'), ('⟍', '⟍'), + ('â³²', 'â³³'), ('â´§', 'â´§'), ('â´­', 'â´­'), ('ⵦ', 'âµ§'), + ('⸲', '⸻'), ('鿌', '鿌'), ('ꙴ', 'ꙻ'), ('ꚟ', 'ꚟ'), + ('Ꞓ', 'ꞓ'), ('Ɦ', 'Ɦ'), ('ꟸ', 'ꟹ'), ('ê« ', 'ê«¶'), + ('郞', '隷'), ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𑃐', '𑃨'), + ('𑃰', '𑃹'), ('𑄀', '𑄴'), ('𑄶', '𑅃'), ('𑆀', '𑇈'), + ('𑇐', '𑇙'), ('𑚀', '𑚷'), ('𑛀', '𑛉'), ('𖼀', '𖽄'), + ('𖽐', '𖽾'), ('𖾏', '𖾟'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𞻰', '𞻱'), + ('🅪', '🅫'), ('🕀', '🕃'), ('😀', '😀'), ('😑', '😑'), + ('😕', '😕'), ('😗', '😗'), ('😙', '😙'), ('😛', '😛'), + ('😟', '😟'), ('😦', '😧'), ('😬', '😬'), ('😮', '😯'), + ('😴', '😴'), +]; + +pub const V6_2: &'static [(char, char)] = &[ + ('₺', '₺'), +]; + +pub const V6_3: &'static [(char, char)] = &[ + ('\u{61c}', '\u{61c}'), ('\u{2066}', '\u{2069}'), +]; + +pub const V7_0: &'static [(char, char)] = &[ + ('Í¿', 'Í¿'), ('Ô¨', 'Ô¯'), ('֍', '֎'), ('\u{605}', '\u{605}'), + ('ࢡ', 'ࢡ'), ('ࢭ', 'ࢲ'), ('ࣿ', 'ࣿ'), ('ॸ', 'ॸ'), + ('ঀ', 'ঀ'), ('ఀ', 'ఀ'), ('à°´', 'à°´'), ('ಁ', 'ಁ'), + ('ഁ', 'ഁ'), ('à·¦', 'à·¯'), ('ᛱ', 'ᛸ'), ('ᤝ', 'ᤞ'), + ('᪰', '᪾'), ('᳸', 'á³¹'), ('á·§', 'á·µ'), ('₻', '₽'), + ('⏴', '⏺'), ('✀', '✀'), ('⭍', '⭏'), ('⭚', 'â­³'), + ('â­¶', '⮕'), ('⮘', '⮹'), ('⮽', '⯈'), ('⯊', '⯑'), + ('⸼', '⹂'), ('Ꚙ', 'ꚝ'), ('ꞔ', 'ꞟ'), ('Ɜ', 'Ɬ'), + ('Ʞ', 'Ʇ'), ('ꟷ', 'ꟷ'), ('ê§ ', 'ê§¾'), ('ꩼ', 'ê©¿'), + ('ꬰ', 'ꭟ'), ('ê­¤', 'ê­¥'), ('︧', '︭'), ('𐆋', '𐆌'), + ('𐆠', '𐆠'), ('𐋠', '𐋻'), ('𐌟', '𐌟'), ('𐍐', '𐍺'), + ('𐔀', '𐔧'), ('𐔰', '𐕣'), ('𐕯', '𐕯'), ('𐘀', '𐜶'), + ('𐝀', '𐝕'), ('𐝠', '𐝧'), ('𐡠', '𐢞'), ('𐢧', '𐢯'), + ('𐪀', '𐪟'), ('𐫀', '𐫦'), ('𐫫', '𐫶'), ('𐮀', '𐮑'), + ('𐮙', '𐮜'), ('𐮩', '𐮯'), ('𑁿', '𑁿'), ('𑅐', '𑅶'), + ('𑇍', '𑇍'), ('𑇚', '𑇚'), ('𑇡', '𑇴'), ('𑈀', '𑈑'), + ('𑈓', '𑈽'), ('𑊰', '𑋪'), ('𑋰', '𑋹'), ('𑌁', '𑌃'), + ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), ('𑌪', '𑌰'), + ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('𑌼', '𑍄'), ('𑍇', '𑍈'), + ('𑍋', '𑍍'), ('𑍗', '𑍗'), ('𑍝', '𑍣'), ('𑍦', '𑍬'), + ('𑍰', '𑍴'), ('𑒀', '𑓇'), ('𑓐', '𑓙'), ('𑖀', '𑖵'), + ('𑖸', '𑗉'), ('𑘀', '𑙄'), ('𑙐', '𑙙'), ('𑢠', '𑣲'), + ('𑣿', '𑣿'), ('𑫀', '𑫸'), ('𒍯', '𒎘'), ('𒑣', '𒑮'), + ('𒑴', '𒑴'), ('𖩀', '𖩞'), ('𖩠', '𖩩'), ('𖩮', '𖩯'), + ('𖫐', '𖫭'), ('𖫰', '𖫵'), ('𖬀', '𖭅'), ('𖭐', '𖭙'), + ('𖭛', '𖭡'), ('𖭣', '𖭷'), ('𖭽', '𖮏'), ('𛰀', '𛱪'), + ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𛲜', '\u{1bca3}'), + ('𞠀', '𞣄'), ('𞣇', '𞣖'), ('🂿', '🂿'), ('🃠', '🃵'), + ('🄋', '🄌'), ('🌡', '🌬'), ('🌶', '🌶'), ('🍽', '🍽'), + ('🎔', '🎟'), ('🏅', '🏅'), ('🏋', '🏎'), ('🏔', '🏟'), + ('🏱', '🏷'), ('🐿', '🐿'), ('👁', '👁'), ('📸', '📸'), + ('📽', '📾'), ('🔾', '🔿'), ('🕄', '🕊'), ('🕨', '🕹'), + ('🕻', '🖣'), ('🖥', '🗺'), ('🙁', '🙂'), ('🙐', '🙿'), + ('🛆', '🛏'), ('🛠', '🛬'), ('🛰', '🛳'), ('🞀', '🟔'), + ('🠀', '🠋'), ('🠐', '🡇'), ('🡐', '🡙'), ('🡠', '🢇'), + ('🢐', '🢭'), +]; + +pub const V8_0: &'static [(char, char)] = &[ + ('ࢳ', 'ࢴ'), ('ࣣ', 'ࣣ'), ('ૹ', 'ૹ'), ('ౚ', 'ౚ'), + ('ൟ', 'ൟ'), ('Ᏽ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('₾', '₾'), + ('↊', '↋'), ('⯬', '⯯'), ('鿍', '鿕'), ('ꚞ', 'ꚞ'), + ('ꞏ', 'ꞏ'), ('Ʝ', 'ꞷ'), ('꣼', 'ꣽ'), ('ê­ ', 'ê­£'), + ('ê­°', 'ꮿ'), ('︮', '︯'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), + ('𐣻', '𐣿'), ('𐦼', '𐦽'), ('𐧀', '𐧏'), ('𐧒', '𐧿'), + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐳺', '𐳿'), ('𑇉', '𑇌'), + ('𑇛', '𑇟'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), + ('𑊏', '𑊝'), ('𑊟', '𑊩'), ('𑌀', '𑌀'), ('𑍐', '𑍐'), + ('𑗊', '𑗝'), ('𑜀', '𑜙'), ('𑜝', '𑜫'), ('𑜰', '𑜿'), + ('𒎙', '𒎙'), ('𒒀', '𒕃'), ('𔐀', '𔙆'), ('𝇞', '𝇨'), + ('𝠀', '𝪋'), ('𝪛', '𝪟'), ('𝪡', '𝪯'), ('🌭', '🌯'), + ('🍾', '🍿'), ('🏏', '🏓'), ('🏸', '🏿'), ('📿', '📿'), + ('🕋', '🕏'), ('🙃', '🙄'), ('🛐', '🛐'), ('🤐', '🤘'), + ('🦀', '🦄'), ('🧀', '🧀'), ('ð«  ', '𬺡'), +]; + +pub const V9_0: &'static [(char, char)] = &[ + ('ࢶ', 'ࢽ'), ('ࣔ', '\u{8e2}'), ('ಀ', 'ಀ'), ('൏', '൏'), + ('ൔ', 'ൖ'), ('൘', '൞'), ('൶', '൸'), ('ᲀ', 'ᲈ'), + ('á·»', 'á·»'), ('⏻', '⏾'), ('⹃', '⹄'), ('Ɪ', 'Ɪ'), + ('ꣅ', 'ꣅ'), ('𐆍', '𐆎'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), + ('𑈾', '𑈾'), ('𑐀', '𑑙'), ('𑑛', '𑑛'), ('𑑝', '𑑝'), + ('𑙠', '𑙬'), ('𑰀', '𑰈'), ('𑰊', '𑰶'), ('𑰸', '𑱅'), + ('𑱐', '𑱬'), ('𑱰', '𑲏'), ('𑲒', '𑲧'), ('𑲩', '𑲶'), + ('𖿠', '𖿠'), ('𗀀', '𘟬'), ('𘠀', '𘫲'), ('𞀀', '𞀆'), + ('𞀈', '𞀘'), ('𞀛', '𞀡'), ('𞀣', '𞀤'), ('𞀦', '𞀪'), + ('𞤀', '𞥊'), ('𞥐', '𞥙'), ('𞥞', '𞥟'), ('🆛', '🆬'), + ('🈻', '🈻'), ('🕺', '🕺'), ('🖤', '🖤'), ('🛑', '🛒'), + ('🛴', '🛶'), ('🤙', '🤞'), ('🤠', '🤧'), ('🤰', '🤰'), + ('🤳', '🤾'), ('🥀', '🥋'), ('🥐', '🥞'), ('🦅', '🦑'), +]; diff --git a/regex-syntax/src/unicode_tables/case_folding_simple.rs b/regex-syntax/src/unicode_tables/case_folding_simple.rs new file mode 100644 index 000000000..bf2f61ec8 --- /dev/null +++ b/regex-syntax/src/unicode_tables/case_folding_simple.rs @@ -0,0 +1,725 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate case-folding-simple tmp/ucd-11.0.0/ --chars --all-pairs +// +// ucd-generate is available on crates.io. + +pub const CASE_FOLDING_SIMPLE: &'static [(char, &'static [char])] = &[ + ('A', &['a']), ('B', &['b']), ('C', &['c']), ('D', &['d']), ('E', &['e']), + ('F', &['f']), ('G', &['g']), ('H', &['h']), ('I', &['i']), ('J', &['j']), + ('K', &['k', 'K', ]), ('L', &['l']), ('M', &['m']), ('N', &['n']), ('O', &[ + 'o']), ('P', &['p']), ('Q', &['q']), ('R', &['r']), ('S', &['s', 'Å¿', ]), + ('T', &['t']), ('U', &['u']), ('V', &['v']), ('W', &['w']), ('X', &['x']), + ('Y', &['y']), ('Z', &['z']), ('a', &['A']), ('b', &['B']), ('c', &['C']), + ('d', &['D']), ('e', &['E']), ('f', &['F']), ('g', &['G']), ('h', &['H']), + ('i', &['I']), ('j', &['J']), ('k', &['K', 'K', ]), ('l', &['L']), ('m', &[ + 'M']), ('n', &['N']), ('o', &['O']), ('p', &['P']), ('q', &['Q']), ('r', &[ + 'R']), ('s', &['S', 'Å¿', ]), ('t', &['T']), ('u', &['U']), ('v', &['V']), + ('w', &['W']), ('x', &['X']), ('y', &['Y']), ('z', &['Z']), ('µ', &['Μ', + 'μ', ]), ('À', &['à']), ('Á', &['á']), ('Â', &['â']), ('Ã', &['ã' + ]), ('Ä', &['ä']), ('Å', &['Ã¥', 'Å', ]), ('Æ', &['æ']), ('Ç', &['ç' + ]), ('È', &['è']), ('É', &['é']), ('Ê', &['ê']), ('Ë', &['ë']), + ('Ì', &['ì']), ('Í', &['í']), ('Î', &['î']), ('Ï', &['ï']), ('Ð', &[ + 'ð']), ('Ñ', &['ñ']), ('Ò', &['ò']), ('Ó', &['ó']), ('Ô', &['ô']), + ('Õ', &['õ']), ('Ö', &['ö']), ('Ø', &['ø']), ('Ù', &['ù']), ('Ú', &[ + 'ú']), ('Û', &['û']), ('Ü', &['ü']), ('Ý', &['ý']), ('Þ', &['þ']), + ('ß', &['ẞ']), ('à', &['À']), ('á', &['Á']), ('â', &['Â']), + ('ã', &['Ã']), ('ä', &['Ä']), ('Ã¥', &['Å', 'Å', ]), ('æ', &['Æ']), + ('ç', &['Ç']), ('è', &['È']), ('é', &['É']), ('ê', &['Ê']), ('ë', &[ + 'Ë']), ('ì', &['Ì']), ('í', &['Í']), ('î', &['Î']), ('ï', &['Ï']), + ('ð', &['Ð']), ('ñ', &['Ñ']), ('ò', &['Ò']), ('ó', &['Ó']), ('ô', &[ + 'Ô']), ('õ', &['Õ']), ('ö', &['Ö']), ('ø', &['Ø']), ('ù', &['Ù']), + ('ú', &['Ú']), ('û', &['Û']), ('ü', &['Ü']), ('ý', &['Ý']), ('þ', &[ + 'Þ']), ('ÿ', &['Ÿ']), ('Ā', &['ā']), ('ā', &['Ā']), ('Ă', &['ă']), + ('ă', &['Ă']), ('Ą', &['ą']), ('ą', &['Ą']), ('Ć', &['ć']), ('ć', &[ + 'Ć']), ('Ĉ', &['ĉ']), ('ĉ', &['Ĉ']), ('Ċ', &['ċ']), ('ċ', &['Ċ']), + ('Č', &['č']), ('č', &['Č']), ('Ď', &['ď']), ('ď', &['Ď']), ('Đ', &[ + 'đ']), ('đ', &['Đ']), ('Ē', &['ē']), ('ē', &['Ē']), ('Ĕ', &['ĕ']), + ('ĕ', &['Ĕ']), ('Ė', &['ė']), ('ė', &['Ė']), ('Ę', &['ę']), ('ę', &[ + 'Ę']), ('Ě', &['ě']), ('ě', &['Ě']), ('Ĝ', &['ĝ']), ('ĝ', &['Ĝ']), + ('Ğ', &['ğ']), ('ğ', &['Ğ']), ('Ä ', &['Ä¡']), ('Ä¡', &['Ä ']), ('Ä¢', &[ + 'Ä£']), ('Ä£', &['Ä¢']), ('Ĥ', &['Ä¥']), ('Ä¥', &['Ĥ']), ('Ħ', &['ħ']), + ('ħ', &['Ħ']), ('Ĩ', &['Ä©']), ('Ä©', &['Ĩ']), ('Ī', &['Ä«']), ('Ä«', &[ + 'Ī']), ('Ĭ', &['Ä­']), ('Ä­', &['Ĭ']), ('Ä®', &['į']), ('į', &['Ä®']), + ('IJ', &['ij']), ('ij', &['IJ']), ('Ä´', &['ĵ']), ('ĵ', &['Ä´']), ('Ķ', &[ + 'Ä·']), ('Ä·', &['Ķ']), ('Ĺ', &['ĺ']), ('ĺ', &['Ĺ']), ('Ä»', &['ļ']), + ('ļ', &['Ä»']), ('Ľ', &['ľ']), ('ľ', &['Ľ']), ('Ä¿', &['ŀ']), ('ŀ', &[ + 'Ä¿']), ('Ł', &['ł']), ('ł', &['Ł']), ('Ń', &['ń']), ('ń', &['Ń']), + ('Ņ', &['ņ']), ('ņ', &['Ņ']), ('Ň', &['ň']), ('ň', &['Ň']), ('Ŋ', &[ + 'ŋ']), ('ŋ', &['Ŋ']), ('Ō', &['ō']), ('ō', &['Ō']), ('Ŏ', &['ŏ']), + ('ŏ', &['Ŏ']), ('Ő', &['ő']), ('ő', &['Ő']), ('Œ', &['œ']), ('œ', &[ + 'Œ']), ('Ŕ', &['ŕ']), ('ŕ', &['Ŕ']), ('Ŗ', &['ŗ']), ('ŗ', &['Ŗ']), + ('Ř', &['ř']), ('ř', &['Ř']), ('Ś', &['ś']), ('ś', &['Ś']), ('Ŝ', &[ + 'ŝ']), ('ŝ', &['Ŝ']), ('Ş', &['ş']), ('ş', &['Ş']), ('Å ', &['Å¡']), + ('Å¡', &['Å ']), ('Å¢', &['Å£']), ('Å£', &['Å¢']), ('Ť', &['Å¥']), ('Å¥', &[ + 'Ť']), ('Ŧ', &['ŧ']), ('ŧ', &['Ŧ']), ('Ũ', &['Å©']), ('Å©', &['Ũ']), + ('Ū', &['Å«']), ('Å«', &['Ū']), ('Ŭ', &['Å­']), ('Å­', &['Ŭ']), ('Å®', &[ + 'ů']), ('ů', &['Å®']), ('Ű', &['ű']), ('ű', &['Ű']), ('Ų', &['ų']), + ('ų', &['Ų']), ('Å´', &['ŵ']), ('ŵ', &['Å´']), ('Ŷ', &['Å·']), ('Å·', &[ + 'Ŷ']), ('Ÿ', &['ÿ']), ('Ź', &['ź']), ('ź', &['Ź']), ('Å»', &['ż']), + ('ż', &['Å»']), ('Ž', &['ž']), ('ž', &['Ž']), ('Å¿', &['S', 's', ]), + ('ƀ', &['Ƀ']), ('Ɓ', &['ɓ']), ('Ƃ', &['ƃ']), ('ƃ', &['Ƃ']), ('Ƅ', &[ + 'ƅ']), ('ƅ', &['Ƅ']), ('Ɔ', &['ɔ']), ('Ƈ', &['ƈ']), ('ƈ', &['Ƈ']), + ('Ɖ', &['ɖ']), ('Ɗ', &['ɗ']), ('Ƌ', &['ƌ']), ('ƌ', &['Ƌ']), ('Ǝ', &[ + 'ǝ']), ('Ə', &['ə']), ('Ɛ', &['ɛ']), ('Ƒ', &['ƒ']), ('ƒ', &['Ƒ']), + ('Ɠ', &['É ']), ('Ɣ', &['É£']), ('ƕ', &['Ƕ']), ('Ɩ', &['É©']), ('Ɨ', &[ + 'ɨ']), ('Ƙ', &['ƙ']), ('ƙ', &['Ƙ']), ('ƚ', &['Ƚ']), ('Ɯ', &['ɯ']), + ('Ɲ', &['ɲ']), ('ƞ', &['È ']), ('Ɵ', &['ɵ']), ('Æ ', &['Æ¡']), ('Æ¡', &[ + 'Æ ']), ('Æ¢', &['Æ£']), ('Æ£', &['Æ¢']), ('Ƥ', &['Æ¥']), ('Æ¥', &['Ƥ']), + ('Ʀ', &['ʀ']), ('Ƨ', &['ƨ']), ('ƨ', &['Ƨ']), ('Æ©', &['ʃ']), ('Ƭ', &[ + 'Æ­']), ('Æ­', &['Ƭ']), ('Æ®', &['ʈ']), ('Ư', &['ư']), ('ư', &['Ư']), + ('Ʊ', &['ʊ']), ('Ʋ', &['ʋ']), ('Ƴ', &['Æ´']), ('Æ´', &['Ƴ']), ('Ƶ', &[ + 'ƶ']), ('ƶ', &['Ƶ']), ('Æ·', &['ʒ']), ('Ƹ', &['ƹ']), ('ƹ', &['Ƹ']), + ('Ƽ', &['ƽ']), ('ƽ', &['Ƽ']), ('Æ¿', &['Ç·']), ('DŽ', &['Dž', 'dž', ]), + ('Dž', &['DŽ', 'dž', ]), ('dž', &['DŽ', 'Dž', ]), ('LJ', &['Lj', 'lj', ]), + ('Lj', &['LJ', 'lj', ]), ('lj', &['LJ', 'Lj', ]), ('NJ', &['Nj', 'nj', ]), + ('Nj', &['NJ', 'nj', ]), ('nj', &['NJ', 'Nj', ]), ('Ǎ', &['ǎ']), ('ǎ', &[ + 'Ǎ']), ('Ǐ', &['ǐ']), ('ǐ', &['Ǐ']), ('Ǒ', &['ǒ']), ('ǒ', &['Ǒ']), + ('Ǔ', &['ǔ']), ('ǔ', &['Ǔ']), ('Ǖ', &['ǖ']), ('ǖ', &['Ǖ']), ('Ǘ', &[ + 'ǘ']), ('ǘ', &['Ǘ']), ('Ǚ', &['ǚ']), ('ǚ', &['Ǚ']), ('Ǜ', &['ǜ']), + ('ǜ', &['Ǜ']), ('ǝ', &['Ǝ']), ('Ǟ', &['ǟ']), ('ǟ', &['Ǟ']), ('Ç ', &[ + 'Ç¡']), ('Ç¡', &['Ç ']), ('Ç¢', &['Ç£']), ('Ç£', &['Ç¢']), ('Ǥ', &['Ç¥']), + ('Ç¥', &['Ǥ']), ('Ǧ', &['ǧ']), ('ǧ', &['Ǧ']), ('Ǩ', &['Ç©']), ('Ç©', &[ + 'Ǩ']), ('Ǫ', &['Ç«']), ('Ç«', &['Ǫ']), ('Ǭ', &['Ç­']), ('Ç­', &['Ǭ']), + ('Ç®', &['ǯ']), ('ǯ', &['Ç®']), ('DZ', &['Dz', 'dz', ]), ('Dz', &['DZ', + 'dz', ]), ('dz', &['DZ', 'Dz', ]), ('Ç´', &['ǵ']), ('ǵ', &['Ç´']), + ('Ƕ', &['ƕ']), ('Ç·', &['Æ¿']), ('Ǹ', &['ǹ']), ('ǹ', &['Ǹ']), ('Ǻ', &[ + 'Ç»']), ('Ç»', &['Ǻ']), ('Ǽ', &['ǽ']), ('ǽ', &['Ǽ']), ('Ǿ', &['Ç¿']), + ('Ç¿', &['Ǿ']), ('Ȁ', &['ȁ']), ('ȁ', &['Ȁ']), ('Ȃ', &['ȃ']), ('ȃ', &[ + 'Ȃ']), ('Ȅ', &['ȅ']), ('ȅ', &['Ȅ']), ('Ȇ', &['ȇ']), ('ȇ', &['Ȇ']), + ('Ȉ', &['ȉ']), ('ȉ', &['Ȉ']), ('Ȋ', &['ȋ']), ('ȋ', &['Ȋ']), ('Ȍ', &[ + 'ȍ']), ('ȍ', &['Ȍ']), ('Ȏ', &['ȏ']), ('ȏ', &['Ȏ']), ('Ȑ', &['ȑ']), + ('ȑ', &['Ȑ']), ('Ȓ', &['ȓ']), ('ȓ', &['Ȓ']), ('Ȕ', &['ȕ']), ('ȕ', &[ + 'Ȕ']), ('Ȗ', &['ȗ']), ('ȗ', &['Ȗ']), ('Ș', &['ș']), ('ș', &['Ș']), + ('Ț', &['ț']), ('ț', &['Ț']), ('Ȝ', &['ȝ']), ('ȝ', &['Ȝ']), ('Ȟ', &[ + 'ȟ']), ('ȟ', &['Ȟ']), ('È ', &['ƞ']), ('È¢', &['È£']), ('È£', &['È¢']), + ('Ȥ', &['È¥']), ('È¥', &['Ȥ']), ('Ȧ', &['ȧ']), ('ȧ', &['Ȧ']), ('Ȩ', &[ + 'È©']), ('È©', &['Ȩ']), ('Ȫ', &['È«']), ('È«', &['Ȫ']), ('Ȭ', &['È­']), + ('È­', &['Ȭ']), ('È®', &['ȯ']), ('ȯ', &['È®']), ('Ȱ', &['ȱ']), ('ȱ', &[ + 'Ȱ']), ('Ȳ', &['ȳ']), ('ȳ', &['Ȳ']), ('Ⱥ', &['â±¥']), ('È»', &['ȼ']), + ('ȼ', &['È»']), ('Ƚ', &['ƚ']), ('Ⱦ', &['ⱦ']), ('È¿', &['â±¾']), + ('ɀ', &['Ɀ']), ('Ɂ', &['ɂ']), ('ɂ', &['Ɂ']), ('Ƀ', &['ƀ']), + ('Ʉ', &['ʉ']), ('Ʌ', &['ʌ']), ('Ɇ', &['ɇ']), ('ɇ', &['Ɇ']), ('Ɉ', &[ + 'ɉ']), ('ɉ', &['Ɉ']), ('Ɋ', &['ɋ']), ('ɋ', &['Ɋ']), ('Ɍ', &['ɍ']), + ('ɍ', &['Ɍ']), ('Ɏ', &['ɏ']), ('ɏ', &['Ɏ']), ('ɐ', &['Ɐ']), + ('ɑ', &['â±­']), ('ɒ', &['â±°']), ('ɓ', &['Ɓ']), ('ɔ', &['Ɔ']), + ('ɖ', &['Ɖ']), ('ɗ', &['Ɗ']), ('ə', &['Ə']), ('ɛ', &['Ɛ']), ('ɜ', &[ + 'Ɜ']), ('É ', &['Ɠ']), ('É¡', &['Ɡ']), ('É£', &['Ɣ']), ('É¥', &['Ɥ' + ]), ('ɦ', &['Ɦ']), ('ɨ', &['Ɨ']), ('É©', &['Ɩ']), ('ɪ', &['Ɪ']), + ('É«', &['â±¢']), ('ɬ', &['Ɬ']), ('ɯ', &['Ɯ']), ('ɱ', &['â±®']), + ('ɲ', &['Ɲ']), ('ɵ', &['Ɵ']), ('ɽ', &['Ɽ']), ('ʀ', &['Ʀ']), + ('ʃ', &['Æ©']), ('ʇ', &['Ʇ']), ('ʈ', &['Æ®']), ('ʉ', &['Ʉ']), + ('ʊ', &['Ʊ']), ('ʋ', &['Ʋ']), ('ʌ', &['Ʌ']), ('ʒ', &['Æ·']), ('ʝ', &[ + 'Ʝ']), ('ʞ', &['Ʞ']), ('ͅ', &['Ι', 'ι', 'á¾¾', ]), ('Ͱ', &['ͱ']), + ('ͱ', &['Ͱ']), ('Ͳ', &['ͳ']), ('ͳ', &['Ͳ']), ('Ͷ', &['Í·']), ('Í·', &[ + 'Ͷ']), ('Í»', &['Ͻ']), ('ͼ', &['Ͼ']), ('ͽ', &['Ï¿']), ('Í¿', &['ϳ']), + ('Ά', &['ά']), ('Έ', &['έ']), ('Ή', &['ή']), ('Ί', &['ί']), ('Ό', &[ + 'ό']), ('Ύ', &['ύ']), ('Ώ', &['ώ']), ('Α', &['α']), ('Β', &['β', + 'ϐ', ]), ('Γ', &['γ']), ('Δ', &['δ']), ('Ε', &['ε', 'ϵ', ]), + ('Ζ', &['ζ']), ('Η', &['η']), ('Θ', &['θ', 'ϑ', 'Ï´', ]), ('Ι', &[ + 'ͅ', 'ι', 'á¾¾', ]), ('Κ', &['κ', 'ϰ', ]), ('Λ', &['λ']), ('Μ', &[ + 'µ', 'μ', ]), ('Ν', &['ν']), ('Ξ', &['ξ']), ('Ο', &['ο']), ('Π', &[ + 'π', 'ϖ', ]), ('Ρ', &['ρ', 'ϱ', ]), ('Σ', &['ς', 'σ', ]), ('Τ', &[ + 'τ']), ('Î¥', &['υ']), ('Φ', &['φ', 'ϕ', ]), ('Χ', &['χ']), ('Ψ', &[ + 'ψ']), ('Ω', &['ω', 'Ω', ]), ('Ϊ', &['ϊ']), ('Ϋ', &['ϋ']), ('ά', &[ + 'Ά']), ('έ', &['Έ']), ('ή', &['Ή']), ('ί', &['Ί']), ('α', &['Α']), + ('β', &['Β', 'ϐ', ]), ('γ', &['Γ']), ('δ', &['Δ']), ('ε', &['Ε', + 'ϵ', ]), ('ζ', &['Ζ']), ('η', &['Η']), ('θ', &['Θ', 'ϑ', 'Ï´', ]), + ('ι', &['ͅ', 'Ι', 'á¾¾', ]), ('κ', &['Κ', 'ϰ', ]), ('λ', &['Λ']), + ('μ', &['µ', 'Μ', ]), ('ν', &['Ν']), ('ξ', &['Ξ']), ('ο', &['Ο']), + ('π', &['Π', 'ϖ', ]), ('ρ', &['Ρ', 'ϱ', ]), ('ς', &['Σ', 'σ', ]), + ('σ', &['Σ', 'ς', ]), ('τ', &['Τ']), ('υ', &['Î¥']), ('φ', &['Φ', + 'ϕ', ]), ('χ', &['Χ']), ('ψ', &['Ψ']), ('ω', &['Ω', 'Ω', ]), + ('ϊ', &['Ϊ']), ('ϋ', &['Ϋ']), ('ό', &['Ό']), ('ύ', &['Ύ']), ('ώ', &[ + 'Ώ']), ('Ϗ', &['ϗ']), ('ϐ', &['Β', 'β', ]), ('ϑ', &['Θ', 'θ', 'Ï´', + ]), ('ϕ', &['Φ', 'φ', ]), ('ϖ', &['Π', 'π', ]), ('ϗ', &['Ϗ']), + ('Ϙ', &['ϙ']), ('ϙ', &['Ϙ']), ('Ϛ', &['ϛ']), ('ϛ', &['Ϛ']), ('Ϝ', &[ + 'ϝ']), ('ϝ', &['Ϝ']), ('Ϟ', &['ϟ']), ('ϟ', &['Ϟ']), ('Ï ', &['Ï¡']), + ('Ï¡', &['Ï ']), ('Ï¢', &['Ï£']), ('Ï£', &['Ï¢']), ('Ϥ', &['Ï¥']), ('Ï¥', &[ + 'Ϥ']), ('Ϧ', &['ϧ']), ('ϧ', &['Ϧ']), ('Ϩ', &['Ï©']), ('Ï©', &['Ϩ']), + ('Ϫ', &['Ï«']), ('Ï«', &['Ϫ']), ('Ϭ', &['Ï­']), ('Ï­', &['Ϭ']), ('Ï®', &[ + 'ϯ']), ('ϯ', &['Ï®']), ('ϰ', &['Κ', 'κ', ]), ('ϱ', &['Ρ', 'ρ', ]), + ('ϲ', &['Ϲ']), ('ϳ', &['Í¿']), ('Ï´', &['Θ', 'θ', 'ϑ', ]), ('ϵ', &[ + 'Ε', 'ε', ]), ('Ï·', &['ϸ']), ('ϸ', &['Ï·']), ('Ϲ', &['ϲ']), ('Ϻ', &[ + 'Ï»']), ('Ï»', &['Ϻ']), ('Ͻ', &['Í»']), ('Ͼ', &['ͼ']), ('Ï¿', &['ͽ']), + ('Ѐ', &['ѐ']), ('Ё', &['ё']), ('Ђ', &['ђ']), ('Ѓ', &['ѓ']), ('Є', &[ + 'є']), ('Ѕ', &['ѕ']), ('І', &['і']), ('Ї', &['ї']), ('Ј', &['ј']), + ('Љ', &['љ']), ('Њ', &['њ']), ('Ћ', &['ћ']), ('Ќ', &['ќ']), ('Ѝ', &[ + 'ѝ']), ('Ў', &['ў']), ('Џ', &['џ']), ('А', &['а']), ('Б', &['б']), + ('В', &['в', 'ᲀ', ]), ('Г', &['г']), ('Д', &['д', 'ᲁ', ]), + ('Е', &['е']), ('Ж', &['ж']), ('З', &['з']), ('И', &['и']), ('Й', &[ + 'й']), ('К', &['к']), ('Л', &['л']), ('М', &['м']), ('Н', &['н']), + ('О', &['о', 'ᲂ', ]), ('П', &['п']), ('Р', &['р']), ('С', &['с', + 'ᲃ', ]), ('Т', &['т', 'ᲄ', 'ᲅ', ]), ('У', &['у']), ('Ф', &['ф' + ]), ('Ð¥', &['х']), ('Ц', &['ц']), ('Ч', &['ч']), ('Ш', &['ш']), + ('Щ', &['щ']), ('Ъ', &['ъ', 'ᲆ', ]), ('Ы', &['ы']), ('Ь', &['ь']), + ('Э', &['э']), ('Ю', &['ю']), ('Я', &['я']), ('а', &['А']), ('б', &[ + 'Б']), ('в', &['В', 'ᲀ', ]), ('г', &['Г']), ('д', &['Д', 'ᲁ', ]), + ('е', &['Е']), ('ж', &['Ж']), ('з', &['З']), ('и', &['И']), ('й', &[ + 'Й']), ('к', &['К']), ('л', &['Л']), ('м', &['М']), ('н', &['Н']), + ('о', &['О', 'ᲂ', ]), ('п', &['П']), ('р', &['Р']), ('с', &['С', + 'ᲃ', ]), ('т', &['Т', 'ᲄ', 'ᲅ', ]), ('у', &['У']), ('ф', &['Ф' + ]), ('х', &['Ð¥']), ('ц', &['Ц']), ('ч', &['Ч']), ('ш', &['Ш']), + ('щ', &['Щ']), ('ъ', &['Ъ', 'ᲆ', ]), ('ы', &['Ы']), ('ь', &['Ь']), + ('э', &['Э']), ('ю', &['Ю']), ('я', &['Я']), ('ѐ', &['Ѐ']), ('ё', &[ + 'Ё']), ('ђ', &['Ђ']), ('ѓ', &['Ѓ']), ('є', &['Є']), ('ѕ', &['Ѕ']), + ('і', &['І']), ('ї', &['Ї']), ('ј', &['Ј']), ('љ', &['Љ']), ('њ', &[ + 'Њ']), ('ћ', &['Ћ']), ('ќ', &['Ќ']), ('ѝ', &['Ѝ']), ('ў', &['Ў']), + ('џ', &['Џ']), ('Ñ ', &['Ñ¡']), ('Ñ¡', &['Ñ ']), ('Ñ¢', &['Ñ£', 'ᲇ', ]), + ('Ñ£', &['Ñ¢', 'ᲇ', ]), ('Ѥ', &['Ñ¥']), ('Ñ¥', &['Ѥ']), ('Ѧ', &['ѧ']), + ('ѧ', &['Ѧ']), ('Ѩ', &['Ñ©']), ('Ñ©', &['Ѩ']), ('Ѫ', &['Ñ«']), ('Ñ«', &[ + 'Ѫ']), ('Ѭ', &['Ñ­']), ('Ñ­', &['Ѭ']), ('Ñ®', &['ѯ']), ('ѯ', &['Ñ®']), + ('Ѱ', &['ѱ']), ('ѱ', &['Ѱ']), ('Ѳ', &['ѳ']), ('ѳ', &['Ѳ']), ('Ñ´', &[ + 'ѵ']), ('ѵ', &['Ñ´']), ('Ѷ', &['Ñ·']), ('Ñ·', &['Ѷ']), ('Ѹ', &['ѹ']), + ('ѹ', &['Ѹ']), ('Ѻ', &['Ñ»']), ('Ñ»', &['Ѻ']), ('Ѽ', &['ѽ']), ('ѽ', &[ + 'Ѽ']), ('Ѿ', &['Ñ¿']), ('Ñ¿', &['Ѿ']), ('Ҁ', &['ҁ']), ('ҁ', &['Ҁ']), + ('Ҋ', &['ҋ']), ('ҋ', &['Ҋ']), ('Ҍ', &['ҍ']), ('ҍ', &['Ҍ']), ('Ҏ', &[ + 'ҏ']), ('ҏ', &['Ҏ']), ('Ґ', &['ґ']), ('ґ', &['Ґ']), ('Ғ', &['ғ']), + ('ғ', &['Ғ']), ('Ҕ', &['ҕ']), ('ҕ', &['Ҕ']), ('Җ', &['җ']), ('җ', &[ + 'Җ']), ('Ҙ', &['ҙ']), ('ҙ', &['Ҙ']), ('Қ', &['қ']), ('қ', &['Қ']), + ('Ҝ', &['ҝ']), ('ҝ', &['Ҝ']), ('Ҟ', &['ҟ']), ('ҟ', &['Ҟ']), ('Ò ', &[ + 'Ò¡']), ('Ò¡', &['Ò ']), ('Ò¢', &['Ò£']), ('Ò£', &['Ò¢']), ('Ò¤', &['Ò¥']), + ('Ò¥', &['Ò¤']), ('Ò¦', &['Ò§']), ('Ò§', &['Ò¦']), ('Ò¨', &['Ò©']), ('Ò©', &[ + 'Ò¨']), ('Òª', &['Ò«']), ('Ò«', &['Òª']), ('Ò¬', &['Ò­']), ('Ò­', &['Ò¬']), + ('Ò®', &['Ò¯']), ('Ò¯', &['Ò®']), ('Ò°', &['Ò±']), ('Ò±', &['Ò°']), ('Ò²', &[ + 'Ò³']), ('Ò³', &['Ò²']), ('Ò´', &['Òµ']), ('Òµ', &['Ò´']), ('Ò¶', &['Ò·']), + ('Ò·', &['Ò¶']), ('Ò¸', &['Ò¹']), ('Ò¹', &['Ò¸']), ('Òº', &['Ò»']), ('Ò»', &[ + 'Òº']), ('Ò¼', &['Ò½']), ('Ò½', &['Ò¼']), ('Ò¾', &['Ò¿']), ('Ò¿', &['Ò¾']), + ('Ӏ', &['ӏ']), ('Ӂ', &['ӂ']), ('ӂ', &['Ӂ']), ('Ӄ', &['ӄ']), ('ӄ', &[ + 'Ӄ']), ('Ӆ', &['ӆ']), ('ӆ', &['Ӆ']), ('Ӈ', &['ӈ']), ('ӈ', &['Ӈ']), + ('Ӊ', &['ӊ']), ('ӊ', &['Ӊ']), ('Ӌ', &['ӌ']), ('ӌ', &['Ӌ']), ('Ӎ', &[ + 'ӎ']), ('ӎ', &['Ӎ']), ('ӏ', &['Ӏ']), ('Ӑ', &['ӑ']), ('ӑ', &['Ӑ']), + ('Ӓ', &['ӓ']), ('ӓ', &['Ӓ']), ('Ӕ', &['ӕ']), ('ӕ', &['Ӕ']), ('Ӗ', &[ + 'ӗ']), ('ӗ', &['Ӗ']), ('Ә', &['ә']), ('ә', &['Ә']), ('Ӛ', &['ӛ']), + ('ӛ', &['Ӛ']), ('Ӝ', &['ӝ']), ('ӝ', &['Ӝ']), ('Ӟ', &['ӟ']), ('ӟ', &[ + 'Ӟ']), ('Ó ', &['Ó¡']), ('Ó¡', &['Ó ']), ('Ó¢', &['Ó£']), ('Ó£', &['Ó¢']), + ('Ó¤', &['Ó¥']), ('Ó¥', &['Ó¤']), ('Ó¦', &['Ó§']), ('Ó§', &['Ó¦']), ('Ó¨', &[ + 'Ó©']), ('Ó©', &['Ó¨']), ('Óª', &['Ó«']), ('Ó«', &['Óª']), ('Ó¬', &['Ó­']), + ('Ó­', &['Ó¬']), ('Ó®', &['Ó¯']), ('Ó¯', &['Ó®']), ('Ó°', &['Ó±']), ('Ó±', &[ + 'Ó°']), ('Ó²', &['Ó³']), ('Ó³', &['Ó²']), ('Ó´', &['Óµ']), ('Óµ', &['Ó´']), + ('Ó¶', &['Ó·']), ('Ó·', &['Ó¶']), ('Ó¸', &['Ó¹']), ('Ó¹', &['Ó¸']), ('Óº', &[ + 'Ó»']), ('Ó»', &['Óº']), ('Ó¼', &['Ó½']), ('Ó½', &['Ó¼']), ('Ó¾', &['Ó¿']), + ('Ó¿', &['Ó¾']), ('Ԁ', &['ԁ']), ('ԁ', &['Ԁ']), ('Ԃ', &['ԃ']), ('ԃ', &[ + 'Ԃ']), ('Ԅ', &['ԅ']), ('ԅ', &['Ԅ']), ('Ԇ', &['ԇ']), ('ԇ', &['Ԇ']), + ('Ԉ', &['ԉ']), ('ԉ', &['Ԉ']), ('Ԋ', &['ԋ']), ('ԋ', &['Ԋ']), ('Ԍ', &[ + 'ԍ']), ('ԍ', &['Ԍ']), ('Ԏ', &['ԏ']), ('ԏ', &['Ԏ']), ('Ԑ', &['ԑ']), + ('ԑ', &['Ԑ']), ('Ԓ', &['ԓ']), ('ԓ', &['Ԓ']), ('Ԕ', &['ԕ']), ('ԕ', &[ + 'Ԕ']), ('Ԗ', &['ԗ']), ('ԗ', &['Ԗ']), ('Ԙ', &['ԙ']), ('ԙ', &['Ԙ']), + ('Ԛ', &['ԛ']), ('ԛ', &['Ԛ']), ('Ԝ', &['ԝ']), ('ԝ', &['Ԝ']), ('Ԟ', &[ + 'ԟ']), ('ԟ', &['Ԟ']), ('Ô ', &['Ô¡']), ('Ô¡', &['Ô ']), ('Ô¢', &['Ô£']), + ('Ô£', &['Ô¢']), ('Ô¤', &['Ô¥']), ('Ô¥', &['Ô¤']), ('Ô¦', &['Ô§']), ('Ô§', &[ + 'Ô¦']), ('Ô¨', &['Ô©']), ('Ô©', &['Ô¨']), ('Ôª', &['Ô«']), ('Ô«', &['Ôª']), + ('Ô¬', &['Ô­']), ('Ô­', &['Ô¬']), ('Ô®', &['Ô¯']), ('Ô¯', &['Ô®']), ('Ô±', &[ + 'Õ¡']), ('Ô²', &['Õ¢']), ('Ô³', &['Õ£']), ('Ô´', &['Õ¤']), ('Ôµ', &['Õ¥']), + ('Ô¶', &['Õ¦']), ('Ô·', &['Õ§']), ('Ô¸', &['Õ¨']), ('Ô¹', &['Õ©']), ('Ôº', &[ + 'Õª']), ('Ô»', &['Õ«']), ('Ô¼', &['Õ¬']), ('Ô½', &['Õ­']), ('Ô¾', &['Õ®']), + ('Ô¿', &['Õ¯']), ('Հ', &['Õ°']), ('Ձ', &['Õ±']), ('Ղ', &['Õ²']), ('Ճ', &[ + 'Õ³']), ('Մ', &['Õ´']), ('Յ', &['Õµ']), ('Ն', &['Õ¶']), ('Շ', &['Õ·']), + ('Ո', &['Õ¸']), ('Չ', &['Õ¹']), ('Պ', &['Õº']), ('Ջ', &['Õ»']), ('Ռ', &[ + 'Õ¼']), ('Ս', &['Õ½']), ('Վ', &['Õ¾']), ('Տ', &['Õ¿']), ('Ր', &['ր']), + ('Ց', &['ց']), ('Ւ', &['ւ']), ('Փ', &['փ']), ('Ք', &['ք']), ('Օ', &[ + 'օ']), ('Ֆ', &['ֆ']), ('Õ¡', &['Ô±']), ('Õ¢', &['Ô²']), ('Õ£', &['Ô³']), + ('Õ¤', &['Ô´']), ('Õ¥', &['Ôµ']), ('Õ¦', &['Ô¶']), ('Õ§', &['Ô·']), ('Õ¨', &[ + 'Ô¸']), ('Õ©', &['Ô¹']), ('Õª', &['Ôº']), ('Õ«', &['Ô»']), ('Õ¬', &['Ô¼']), + ('Õ­', &['Ô½']), ('Õ®', &['Ô¾']), ('Õ¯', &['Ô¿']), ('Õ°', &['Հ']), ('Õ±', &[ + 'Ձ']), ('Õ²', &['Ղ']), ('Õ³', &['Ճ']), ('Õ´', &['Մ']), ('Õµ', &['Յ']), + ('Õ¶', &['Ն']), ('Õ·', &['Շ']), ('Õ¸', &['Ո']), ('Õ¹', &['Չ']), ('Õº', &[ + 'Պ']), ('Õ»', &['Ջ']), ('Õ¼', &['Ռ']), ('Õ½', &['Ս']), ('Õ¾', &['Վ']), + ('Õ¿', &['Տ']), ('ր', &['Ր']), ('ց', &['Ց']), ('ւ', &['Ւ']), ('փ', &[ + 'Փ']), ('ք', &['Ք']), ('օ', &['Օ']), ('ֆ', &['Ֆ']), ('Ⴀ', &['ⴀ' + ]), ('Ⴁ', &['ⴁ']), ('Ⴂ', &['ⴂ']), ('Ⴃ', &['ⴃ']), ('Ⴄ', &['ⴄ' + ]), ('Ⴅ', &['ⴅ']), ('Ⴆ', &['ⴆ']), ('Ⴇ', &['ⴇ']), ('Ⴈ', &['ⴈ' + ]), ('Ⴉ', &['ⴉ']), ('Ⴊ', &['ⴊ']), ('Ⴋ', &['ⴋ']), ('Ⴌ', &['ⴌ' + ]), ('Ⴍ', &['ⴍ']), ('Ⴎ', &['ⴎ']), ('Ⴏ', &['ⴏ']), ('Ⴐ', &['ⴐ' + ]), ('Ⴑ', &['ⴑ']), ('Ⴒ', &['ⴒ']), ('Ⴓ', &['ⴓ']), ('Ⴔ', &['ⴔ' + ]), ('Ⴕ', &['ⴕ']), ('Ⴖ', &['ⴖ']), ('Ⴗ', &['ⴗ']), ('Ⴘ', &['ⴘ' + ]), ('Ⴙ', &['ⴙ']), ('Ⴚ', &['ⴚ']), ('Ⴛ', &['ⴛ']), ('Ⴜ', &['ⴜ' + ]), ('Ⴝ', &['ⴝ']), ('Ⴞ', &['ⴞ']), ('Ⴟ', &['ⴟ']), ('Ⴠ', &['â´ ' + ]), ('Ⴡ', &['â´¡']), ('Ⴢ', &['â´¢']), ('Ⴣ', &['â´£']), ('Ⴤ', &['â´¤' + ]), ('Ⴥ', &['â´¥']), ('Ⴧ', &['â´§']), ('Ⴭ', &['â´­']), ('ა', &[ + '\u{1c90}']), ('ბ', &['\u{1c91}']), ('გ', &['\u{1c92}']), ('დ', &[ + '\u{1c93}']), ('ე', &['\u{1c94}']), ('ვ', &['\u{1c95}']), ('ზ', &[ + '\u{1c96}']), ('თ', &['\u{1c97}']), ('ი', &['\u{1c98}']), ('კ', &[ + '\u{1c99}']), ('ლ', &['\u{1c9a}']), ('მ', &['\u{1c9b}']), ('ნ', &[ + '\u{1c9c}']), ('ო', &['\u{1c9d}']), ('პ', &['\u{1c9e}']), ('ჟ', &[ + '\u{1c9f}']), ('რ', &['\u{1ca0}']), ('ს', &['\u{1ca1}']), ('ტ', &[ + '\u{1ca2}']), ('უ', &['\u{1ca3}']), ('ფ', &['\u{1ca4}']), ('ქ', &[ + '\u{1ca5}']), ('ღ', &['\u{1ca6}']), ('ყ', &['\u{1ca7}']), ('შ', &[ + '\u{1ca8}']), ('ჩ', &['\u{1ca9}']), ('ც', &['\u{1caa}']), ('ძ', &[ + '\u{1cab}']), ('წ', &['\u{1cac}']), ('ჭ', &['\u{1cad}']), ('ხ', &[ + '\u{1cae}']), ('ჯ', &['\u{1caf}']), ('ჰ', &['\u{1cb0}']), ('ჱ', &[ + '\u{1cb1}']), ('ჲ', &['\u{1cb2}']), ('ჳ', &['\u{1cb3}']), ('ჴ', &[ + '\u{1cb4}']), ('ჵ', &['\u{1cb5}']), ('ჶ', &['\u{1cb6}']), ('ჷ', &[ + '\u{1cb7}']), ('ჸ', &['\u{1cb8}']), ('ჹ', &['\u{1cb9}']), ('ჺ', &[ + '\u{1cba}']), ('ჽ', &['\u{1cbd}']), ('ჾ', &['\u{1cbe}']), ('ჿ', &[ + '\u{1cbf}']), ('Ꭰ', &['ê­°']), ('Ꭱ', &['ê­±']), ('Ꭲ', &['ê­²']), + ('Ꭳ', &['ê­³']), ('Ꭴ', &['ê­´']), ('Ꭵ', &['ê­µ']), ('Ꭶ', &['ê­¶']), + ('Ꭷ', &['ê­·']), ('Ꭸ', &['ê­¸']), ('Ꭹ', &['ê­¹']), ('Ꭺ', &['ê­º']), + ('Ꭻ', &['ê­»']), ('Ꭼ', &['ê­¼']), ('Ꭽ', &['ê­½']), ('Ꭾ', &['ê­¾']), + ('Ꭿ', &['ê­¿']), ('Ꮀ', &['ꮀ']), ('Ꮁ', &['ꮁ']), ('Ꮂ', &['ꮂ']), + ('Ꮃ', &['ꮃ']), ('Ꮄ', &['ꮄ']), ('Ꮅ', &['ꮅ']), ('Ꮆ', &['ꮆ']), + ('Ꮇ', &['ꮇ']), ('Ꮈ', &['ꮈ']), ('Ꮉ', &['ꮉ']), ('Ꮊ', &['ꮊ']), + ('Ꮋ', &['ꮋ']), ('Ꮌ', &['ꮌ']), ('Ꮍ', &['ꮍ']), ('Ꮎ', &['ꮎ']), + ('Ꮏ', &['ꮏ']), ('Ꮐ', &['ꮐ']), ('Ꮑ', &['ꮑ']), ('Ꮒ', &['ꮒ']), + ('Ꮓ', &['ꮓ']), ('Ꮔ', &['ꮔ']), ('Ꮕ', &['ꮕ']), ('Ꮖ', &['ꮖ']), + ('Ꮗ', &['ꮗ']), ('Ꮘ', &['ꮘ']), ('Ꮙ', &['ꮙ']), ('Ꮚ', &['ꮚ']), + ('Ꮛ', &['ꮛ']), ('Ꮜ', &['ꮜ']), ('Ꮝ', &['ꮝ']), ('Ꮞ', &['ꮞ']), + ('Ꮟ', &['ꮟ']), ('Ꮠ', &['ê® ']), ('Ꮡ', &['ꮡ']), ('Ꮢ', &['ꮢ']), + ('Ꮣ', &['ꮣ']), ('Ꮤ', &['ꮤ']), ('Ꮥ', &['ꮥ']), ('Ꮦ', &['ꮦ']), + ('Ꮧ', &['ê®§']), ('Ꮨ', &['ꮨ']), ('Ꮩ', &['ꮩ']), ('Ꮪ', &['ꮪ']), + ('Ꮫ', &['ꮫ']), ('Ꮬ', &['ꮬ']), ('Ꮭ', &['ê®­']), ('Ꮮ', &['ê®®']), + ('Ꮯ', &['ꮯ']), ('Ꮰ', &['ê®°']), ('Ꮱ', &['ê®±']), ('Ꮲ', &['ꮲ']), + ('Ꮳ', &['ꮳ']), ('Ꮴ', &['ê®´']), ('Ꮵ', &['ꮵ']), ('Ꮶ', &['ê®¶']), + ('Ꮷ', &['ê®·']), ('Ꮸ', &['ꮸ']), ('Ꮹ', &['ꮹ']), ('Ꮺ', &['ꮺ']), + ('Ꮻ', &['ê®»']), ('Ꮼ', &['ꮼ']), ('Ꮽ', &['ꮽ']), ('Ꮾ', &['ꮾ']), + ('Ꮿ', &['ꮿ']), ('Ᏸ', &['ᏸ']), ('Ᏹ', &['ᏹ']), ('Ᏺ', &['ᏺ']), + ('Ᏻ', &['ᏻ']), ('Ᏼ', &['ᏼ']), ('Ᏽ', &['ᏽ']), ('ᏸ', &['Ᏸ']), + ('ᏹ', &['Ᏹ']), ('ᏺ', &['Ᏺ']), ('ᏻ', &['Ᏻ']), ('ᏼ', &['Ᏼ']), + ('ᏽ', &['Ᏽ']), ('ᲀ', &['В', 'в', ]), ('ᲁ', &['Д', 'д', ]), + ('ᲂ', &['О', 'о', ]), ('ᲃ', &['С', 'с', ]), ('ᲄ', &['Т', 'т', + 'ᲅ', ]), ('ᲅ', &['Т', 'т', 'ᲄ', ]), ('ᲆ', &['Ъ', 'ъ', ]), + ('ᲇ', &['Ñ¢', 'Ñ£', ]), ('ᲈ', &['Ꙋ', 'ꙋ', ]), ('\u{1c90}', &['ა' + ]), ('\u{1c91}', &['ბ']), ('\u{1c92}', &['გ']), ('\u{1c93}', &['დ']), + ('\u{1c94}', &['ე']), ('\u{1c95}', &['ვ']), ('\u{1c96}', &['ზ']), + ('\u{1c97}', &['თ']), ('\u{1c98}', &['ი']), ('\u{1c99}', &['კ']), + ('\u{1c9a}', &['ლ']), ('\u{1c9b}', &['მ']), ('\u{1c9c}', &['ნ']), + ('\u{1c9d}', &['ო']), ('\u{1c9e}', &['პ']), ('\u{1c9f}', &['ჟ']), + ('\u{1ca0}', &['რ']), ('\u{1ca1}', &['ს']), ('\u{1ca2}', &['ტ']), + ('\u{1ca3}', &['უ']), ('\u{1ca4}', &['ფ']), ('\u{1ca5}', &['ქ']), + ('\u{1ca6}', &['ღ']), ('\u{1ca7}', &['ყ']), ('\u{1ca8}', &['შ']), + ('\u{1ca9}', &['ჩ']), ('\u{1caa}', &['ც']), ('\u{1cab}', &['ძ']), + ('\u{1cac}', &['წ']), ('\u{1cad}', &['ჭ']), ('\u{1cae}', &['ხ']), + ('\u{1caf}', &['ჯ']), ('\u{1cb0}', &['ჰ']), ('\u{1cb1}', &['ჱ']), + ('\u{1cb2}', &['ჲ']), ('\u{1cb3}', &['ჳ']), ('\u{1cb4}', &['ჴ']), + ('\u{1cb5}', &['ჵ']), ('\u{1cb6}', &['ჶ']), ('\u{1cb7}', &['ჷ']), + ('\u{1cb8}', &['ჸ']), ('\u{1cb9}', &['ჹ']), ('\u{1cba}', &['ჺ']), + ('\u{1cbd}', &['ჽ']), ('\u{1cbe}', &['ჾ']), ('\u{1cbf}', &['ჿ']), + ('áµ¹', &['Ᵹ']), ('áµ½', &['â±£']), ('Ḁ', &['ḁ']), ('ḁ', &['Ḁ']), + ('Ḃ', &['ḃ']), ('ḃ', &['Ḃ']), ('Ḅ', &['ḅ']), ('ḅ', &['Ḅ']), + ('Ḇ', &['ḇ']), ('ḇ', &['Ḇ']), ('Ḉ', &['ḉ']), ('ḉ', &['Ḉ']), + ('Ḋ', &['ḋ']), ('ḋ', &['Ḋ']), ('Ḍ', &['ḍ']), ('ḍ', &['Ḍ']), + ('Ḏ', &['ḏ']), ('ḏ', &['Ḏ']), ('Ḑ', &['ḑ']), ('ḑ', &['Ḑ']), + ('Ḓ', &['ḓ']), ('ḓ', &['Ḓ']), ('Ḕ', &['ḕ']), ('ḕ', &['Ḕ']), + ('Ḗ', &['ḗ']), ('ḗ', &['Ḗ']), ('Ḙ', &['ḙ']), ('ḙ', &['Ḙ']), + ('Ḛ', &['ḛ']), ('ḛ', &['Ḛ']), ('Ḝ', &['ḝ']), ('ḝ', &['Ḝ']), + ('Ḟ', &['ḟ']), ('ḟ', &['Ḟ']), ('Ḡ', &['ḡ']), ('ḡ', &['Ḡ']), + ('Ḣ', &['ḣ']), ('ḣ', &['Ḣ']), ('Ḥ', &['ḥ']), ('ḥ', &['Ḥ']), + ('Ḧ', &['ḧ']), ('ḧ', &['Ḧ']), ('Ḩ', &['ḩ']), ('ḩ', &['Ḩ']), + ('Ḫ', &['ḫ']), ('ḫ', &['Ḫ']), ('Ḭ', &['ḭ']), ('ḭ', &['Ḭ']), + ('Ḯ', &['ḯ']), ('ḯ', &['Ḯ']), ('Ḱ', &['ḱ']), ('ḱ', &['Ḱ']), + ('Ḳ', &['ḳ']), ('ḳ', &['Ḳ']), ('Ḵ', &['ḵ']), ('ḵ', &['Ḵ']), + ('Ḷ', &['ḷ']), ('ḷ', &['Ḷ']), ('Ḹ', &['ḹ']), ('ḹ', &['Ḹ']), + ('Ḻ', &['ḻ']), ('ḻ', &['Ḻ']), ('Ḽ', &['ḽ']), ('ḽ', &['Ḽ']), + ('Ḿ', &['ḿ']), ('ḿ', &['Ḿ']), ('Ṁ', &['ṁ']), ('ṁ', &['Ṁ']), + ('Ṃ', &['ṃ']), ('ṃ', &['Ṃ']), ('Ṅ', &['ṅ']), ('ṅ', &['Ṅ']), + ('Ṇ', &['ṇ']), ('ṇ', &['Ṇ']), ('Ṉ', &['ṉ']), ('ṉ', &['Ṉ']), + ('Ṋ', &['ṋ']), ('ṋ', &['Ṋ']), ('Ṍ', &['ṍ']), ('ṍ', &['Ṍ']), + ('Ṏ', &['ṏ']), ('ṏ', &['Ṏ']), ('Ṑ', &['ṑ']), ('ṑ', &['Ṑ']), + ('Ṓ', &['ṓ']), ('ṓ', &['Ṓ']), ('Ṕ', &['ṕ']), ('ṕ', &['Ṕ']), + ('Ṗ', &['ṗ']), ('ṗ', &['Ṗ']), ('Ṙ', &['ṙ']), ('ṙ', &['Ṙ']), + ('Ṛ', &['ṛ']), ('ṛ', &['Ṛ']), ('Ṝ', &['ṝ']), ('ṝ', &['Ṝ']), + ('Ṟ', &['ṟ']), ('ṟ', &['Ṟ']), ('á¹ ', &['ṡ', 'ẛ', ]), ('ṡ', &[ + 'á¹ ', 'ẛ', ]), ('á¹¢', &['á¹£']), ('á¹£', &['á¹¢']), ('Ṥ', &['á¹¥']), + ('á¹¥', &['Ṥ']), ('Ṧ', &['á¹§']), ('á¹§', &['Ṧ']), ('Ṩ', &['ṩ']), + ('ṩ', &['Ṩ']), ('Ṫ', &['ṫ']), ('ṫ', &['Ṫ']), ('Ṭ', &['á¹­']), + ('á¹­', &['Ṭ']), ('á¹®', &['ṯ']), ('ṯ', &['á¹®']), ('á¹°', &['á¹±']), + ('á¹±', &['á¹°']), ('á¹²', &['á¹³']), ('á¹³', &['á¹²']), ('á¹´', &['á¹µ']), + ('á¹µ', &['á¹´']), ('á¹¶', &['á¹·']), ('á¹·', &['á¹¶']), ('Ṹ', &['á¹¹']), + ('á¹¹', &['Ṹ']), ('Ṻ', &['á¹»']), ('á¹»', &['Ṻ']), ('á¹¼', &['á¹½']), + ('á¹½', &['á¹¼']), ('á¹¾', &['ṿ']), ('ṿ', &['á¹¾']), ('Ẁ', &['ẁ']), + ('ẁ', &['Ẁ']), ('Ẃ', &['ẃ']), ('ẃ', &['Ẃ']), ('Ẅ', &['ẅ']), + ('ẅ', &['Ẅ']), ('Ẇ', &['ẇ']), ('ẇ', &['Ẇ']), ('Ẉ', &['ẉ']), + ('ẉ', &['Ẉ']), ('Ẋ', &['ẋ']), ('ẋ', &['Ẋ']), ('Ẍ', &['ẍ']), + ('ẍ', &['Ẍ']), ('Ẏ', &['ẏ']), ('ẏ', &['Ẏ']), ('Ẑ', &['ẑ']), + ('ẑ', &['Ẑ']), ('Ẓ', &['ẓ']), ('ẓ', &['Ẓ']), ('Ẕ', &['ẕ']), + ('ẕ', &['Ẕ']), ('ẛ', &['á¹ ', 'ṡ', ]), ('ẞ', &['ß']), ('Ạ', &[ + 'ạ']), ('ạ', &['Ạ']), ('Ả', &['ả']), ('ả', &['Ả']), ('Ấ', &[ + 'ấ']), ('ấ', &['Ấ']), ('Ầ', &['ầ']), ('ầ', &['Ầ']), ('Ẩ', &[ + 'ẩ']), ('ẩ', &['Ẩ']), ('Ẫ', &['ẫ']), ('ẫ', &['Ẫ']), ('Ậ', &[ + 'ậ']), ('ậ', &['Ậ']), ('Ắ', &['ắ']), ('ắ', &['Ắ']), ('Ằ', &[ + 'ằ']), ('ằ', &['Ằ']), ('Ẳ', &['ẳ']), ('ẳ', &['Ẳ']), ('Ẵ', &[ + 'ẵ']), ('ẵ', &['Ẵ']), ('Ặ', &['ặ']), ('ặ', &['Ặ']), ('Ẹ', &[ + 'ẹ']), ('ẹ', &['Ẹ']), ('Ẻ', &['ẻ']), ('ẻ', &['Ẻ']), ('Ẽ', &[ + 'ẽ']), ('ẽ', &['Ẽ']), ('Ế', &['ế']), ('ế', &['Ế']), ('Ề', &[ + 'ề']), ('ề', &['Ề']), ('Ể', &['ể']), ('ể', &['Ể']), ('Ễ', &[ + 'ễ']), ('ễ', &['Ễ']), ('Ệ', &['ệ']), ('ệ', &['Ệ']), ('Ỉ', &[ + 'ỉ']), ('ỉ', &['Ỉ']), ('Ị', &['ị']), ('ị', &['Ị']), ('Ọ', &[ + 'ọ']), ('ọ', &['Ọ']), ('Ỏ', &['ỏ']), ('ỏ', &['Ỏ']), ('Ố', &[ + 'ố']), ('ố', &['Ố']), ('Ồ', &['ồ']), ('ồ', &['Ồ']), ('Ổ', &[ + 'ổ']), ('ổ', &['Ổ']), ('Ỗ', &['ỗ']), ('ỗ', &['Ỗ']), ('Ộ', &[ + 'ộ']), ('ộ', &['Ộ']), ('Ớ', &['ớ']), ('ớ', &['Ớ']), ('Ờ', &[ + 'ờ']), ('ờ', &['Ờ']), ('Ở', &['ở']), ('ở', &['Ở']), ('á» ', &[ + 'ỡ']), ('ỡ', &['á» ']), ('Ợ', &['ợ']), ('ợ', &['Ợ']), ('Ụ', &[ + 'ụ']), ('ụ', &['Ụ']), ('Ủ', &['á»§']), ('á»§', &['Ủ']), ('Ứ', &[ + 'ứ']), ('ứ', &['Ứ']), ('Ừ', &['ừ']), ('ừ', &['Ừ']), ('Ử', &[ + 'á»­']), ('á»­', &['Ử']), ('á»®', &['ữ']), ('ữ', &['á»®']), ('á»°', &[ + 'á»±']), ('á»±', &['á»°']), ('Ỳ', &['ỳ']), ('ỳ', &['Ỳ']), ('á»´', &[ + 'ỵ']), ('ỵ', &['á»´']), ('á»¶', &['á»·']), ('á»·', &['á»¶']), ('Ỹ', &[ + 'ỹ']), ('ỹ', &['Ỹ']), ('Ỻ', &['á»»']), ('á»»', &['Ỻ']), ('Ỽ', &[ + 'ỽ']), ('ỽ', &['Ỽ']), ('Ỿ', &['ỿ']), ('ỿ', &['Ỿ']), ('ἀ', &[ + 'Ἀ']), ('ἁ', &['Ἁ']), ('ἂ', &['Ἂ']), ('ἃ', &['Ἃ']), ('ἄ', &[ + 'Ἄ']), ('ἅ', &['Ἅ']), ('ἆ', &['Ἆ']), ('ἇ', &['Ἇ']), ('Ἀ', &[ + 'ἀ']), ('Ἁ', &['ἁ']), ('Ἂ', &['ἂ']), ('Ἃ', &['ἃ']), ('Ἄ', &[ + 'ἄ']), ('Ἅ', &['ἅ']), ('Ἆ', &['ἆ']), ('Ἇ', &['ἇ']), ('ἐ', &[ + 'Ἐ']), ('ἑ', &['Ἑ']), ('ἒ', &['Ἒ']), ('ἓ', &['Ἓ']), ('ἔ', &[ + 'Ἔ']), ('ἕ', &['Ἕ']), ('Ἐ', &['ἐ']), ('Ἑ', &['ἑ']), ('Ἒ', &[ + 'ἒ']), ('Ἓ', &['ἓ']), ('Ἔ', &['ἔ']), ('Ἕ', &['ἕ']), ('á¼ ', &[ + 'Ἠ']), ('ἡ', &['Ἡ']), ('á¼¢', &['Ἢ']), ('á¼£', &['Ἣ']), ('ἤ', &[ + 'Ἤ']), ('á¼¥', &['á¼­']), ('ἦ', &['á¼®']), ('á¼§', &['Ἧ']), ('Ἠ', &[ + 'á¼ ']), ('Ἡ', &['ἡ']), ('Ἢ', &['á¼¢']), ('Ἣ', &['á¼£']), ('Ἤ', &[ + 'ἤ']), ('á¼­', &['á¼¥']), ('á¼®', &['ἦ']), ('Ἧ', &['á¼§']), ('á¼°', &[ + 'Ἰ']), ('á¼±', &['á¼¹']), ('á¼²', &['Ἲ']), ('á¼³', &['á¼»']), ('á¼´', &[ + 'á¼¼']), ('á¼µ', &['á¼½']), ('á¼¶', &['á¼¾']), ('á¼·', &['Ἷ']), ('Ἰ', &[ + 'á¼°']), ('á¼¹', &['á¼±']), ('Ἲ', &['á¼²']), ('á¼»', &['á¼³']), ('á¼¼', &[ + 'á¼´']), ('á¼½', &['á¼µ']), ('á¼¾', &['á¼¶']), ('Ἷ', &['á¼·']), ('ὀ', &[ + 'Ὀ']), ('ὁ', &['Ὁ']), ('ὂ', &['Ὂ']), ('ὃ', &['Ὃ']), ('ὄ', &[ + 'Ὄ']), ('ὅ', &['Ὅ']), ('Ὀ', &['ὀ']), ('Ὁ', &['ὁ']), ('Ὂ', &[ + 'ὂ']), ('Ὃ', &['ὃ']), ('Ὄ', &['ὄ']), ('Ὅ', &['ὅ']), ('ὑ', &[ + 'Ὑ']), ('ὓ', &['Ὓ']), ('ὕ', &['Ὕ']), ('ὗ', &['Ὗ']), ('Ὑ', &[ + 'ὑ']), ('Ὓ', &['ὓ']), ('Ὕ', &['ὕ']), ('Ὗ', &['ὗ']), ('á½ ', &[ + 'Ὠ']), ('ὡ', &['Ὡ']), ('á½¢', &['Ὢ']), ('á½£', &['Ὣ']), ('ὤ', &[ + 'Ὤ']), ('á½¥', &['á½­']), ('ὦ', &['á½®']), ('á½§', &['Ὧ']), ('Ὠ', &[ + 'á½ ']), ('Ὡ', &['ὡ']), ('Ὢ', &['á½¢']), ('Ὣ', &['á½£']), ('Ὤ', &[ + 'ὤ']), ('á½­', &['á½¥']), ('á½®', &['ὦ']), ('Ὧ', &['á½§']), ('á½°', &[ + 'Ὰ']), ('á½±', &['á¾»']), ('á½²', &['Ὲ']), ('á½³', &['Έ']), ('á½´', &[ + 'Ὴ']), ('á½µ', &['Ή']), ('á½¶', &['Ὶ']), ('á½·', &['Ί']), ('ὸ', &[ + 'Ὸ']), ('á½¹', &['Ό']), ('ὺ', &['Ὺ']), ('á½»', &['á¿«']), ('á½¼', &[ + 'Ὼ']), ('á½½', &['á¿»']), ('ᾀ', &['ᾈ']), ('ᾁ', &['ᾉ']), ('ᾂ', &[ + 'ᾊ']), ('ᾃ', &['ᾋ']), ('ᾄ', &['ᾌ']), ('ᾅ', &['ᾍ']), ('ᾆ', &[ + 'ᾎ']), ('ᾇ', &['ᾏ']), ('ᾈ', &['ᾀ']), ('ᾉ', &['ᾁ']), ('ᾊ', &[ + 'ᾂ']), ('ᾋ', &['ᾃ']), ('ᾌ', &['ᾄ']), ('ᾍ', &['ᾅ']), ('ᾎ', &[ + 'ᾆ']), ('ᾏ', &['ᾇ']), ('ᾐ', &['ᾘ']), ('ᾑ', &['ᾙ']), ('ᾒ', &[ + 'ᾚ']), ('ᾓ', &['ᾛ']), ('ᾔ', &['ᾜ']), ('ᾕ', &['ᾝ']), ('ᾖ', &[ + 'ᾞ']), ('ᾗ', &['ᾟ']), ('ᾘ', &['ᾐ']), ('ᾙ', &['ᾑ']), ('ᾚ', &[ + 'ᾒ']), ('ᾛ', &['ᾓ']), ('ᾜ', &['ᾔ']), ('ᾝ', &['ᾕ']), ('ᾞ', &[ + 'ᾖ']), ('ᾟ', &['ᾗ']), ('á¾ ', &['ᾨ']), ('ᾡ', &['ᾩ']), ('á¾¢', &[ + 'ᾪ']), ('á¾£', &['ᾫ']), ('ᾤ', &['ᾬ']), ('á¾¥', &['á¾­']), ('ᾦ', &[ + 'á¾®']), ('á¾§', &['ᾯ']), ('ᾨ', &['á¾ ']), ('ᾩ', &['ᾡ']), ('ᾪ', &[ + 'á¾¢']), ('ᾫ', &['á¾£']), ('ᾬ', &['ᾤ']), ('á¾­', &['á¾¥']), ('á¾®', &[ + 'ᾦ']), ('ᾯ', &['á¾§']), ('á¾°', &['Ᾰ']), ('á¾±', &['á¾¹']), ('á¾³', &[ + 'á¾¼']), ('Ᾰ', &['á¾°']), ('á¾¹', &['á¾±']), ('Ὰ', &['á½°']), ('á¾»', &[ + 'á½±']), ('á¾¼', &['á¾³']), ('á¾¾', &['ͅ', 'Ι', 'ι', ]), ('ῃ', &['ῌ' + ]), ('Ὲ', &['á½²']), ('Έ', &['á½³']), ('Ὴ', &['á½´']), ('Ή', &['á½µ' + ]), ('ῌ', &['ῃ']), ('ῐ', &['Ῐ']), ('ῑ', &['Ῑ']), ('Ῐ', &['ῐ' + ]), ('Ῑ', &['ῑ']), ('Ὶ', &['á½¶']), ('Ί', &['á½·']), ('á¿ ', &['Ῠ' + ]), ('á¿¡', &['á¿©']), ('á¿¥', &['Ῥ']), ('Ῠ', &['á¿ ']), ('á¿©', &['á¿¡' + ]), ('Ὺ', &['ὺ']), ('á¿«', &['á½»']), ('Ῥ', &['á¿¥']), ('ῳ', &['ῼ' + ]), ('Ὸ', &['ὸ']), ('Ό', &['á½¹']), ('Ὼ', &['á½¼']), ('á¿»', &['á½½' + ]), ('ῼ', &['ῳ']), ('Ω', &['Ω', 'ω', ]), ('K', &['K', 'k', ]), + ('Å', &['Å', 'Ã¥', ]), ('Ⅎ', &['ⅎ']), ('ⅎ', &['Ⅎ']), ('Ⅰ', &[ + 'ⅰ']), ('Ⅱ', &['ⅱ']), ('Ⅲ', &['ⅲ']), ('Ⅳ', &['ⅳ']), ('Ⅴ', &[ + 'ⅴ']), ('Ⅵ', &['ⅵ']), ('Ⅶ', &['ⅶ']), ('Ⅷ', &['ⅷ']), ('Ⅸ', &[ + 'ⅸ']), ('Ⅹ', &['ⅹ']), ('Ⅺ', &['ⅺ']), ('Ⅻ', &['ⅻ']), ('Ⅼ', &[ + 'ⅼ']), ('Ⅽ', &['ⅽ']), ('Ⅾ', &['ⅾ']), ('Ⅿ', &['ⅿ']), ('ⅰ', &[ + 'Ⅰ']), ('ⅱ', &['Ⅱ']), ('ⅲ', &['Ⅲ']), ('ⅳ', &['Ⅳ']), ('ⅴ', &[ + 'Ⅴ']), ('ⅵ', &['Ⅵ']), ('ⅶ', &['Ⅶ']), ('ⅷ', &['Ⅷ']), ('ⅸ', &[ + 'Ⅸ']), ('ⅹ', &['Ⅹ']), ('ⅺ', &['Ⅺ']), ('ⅻ', &['Ⅻ']), ('ⅼ', &[ + 'Ⅼ']), ('ⅽ', &['Ⅽ']), ('ⅾ', &['Ⅾ']), ('ⅿ', &['Ⅿ']), ('Ↄ', &[ + 'ↄ']), ('ↄ', &['Ↄ']), ('Ⓐ', &['ⓐ']), ('Ⓑ', &['ⓑ']), ('Ⓒ', &[ + 'ⓒ']), ('Ⓓ', &['ⓓ']), ('Ⓔ', &['ⓔ']), ('Ⓕ', &['ⓕ']), ('Ⓖ', &[ + 'ⓖ']), ('Ⓗ', &['ⓗ']), ('Ⓘ', &['ⓘ']), ('Ⓙ', &['ⓙ']), ('Ⓚ', &[ + 'ⓚ']), ('Ⓛ', &['ⓛ']), ('Ⓜ', &['ⓜ']), ('Ⓝ', &['ⓝ']), ('Ⓞ', &[ + 'ⓞ']), ('Ⓟ', &['ⓟ']), ('Ⓠ', &['ⓠ']), ('Ⓡ', &['ⓡ']), ('Ⓢ', &[ + 'ⓢ']), ('Ⓣ', &['ⓣ']), ('Ⓤ', &['ⓤ']), ('Ⓥ', &['ⓥ']), ('Ⓦ', &[ + 'ⓦ']), ('Ⓧ', &['ⓧ']), ('Ⓨ', &['ⓨ']), ('Ⓩ', &['ⓩ']), ('ⓐ', &[ + 'Ⓐ']), ('ⓑ', &['Ⓑ']), ('ⓒ', &['Ⓒ']), ('ⓓ', &['Ⓓ']), ('ⓔ', &[ + 'Ⓔ']), ('ⓕ', &['Ⓕ']), ('ⓖ', &['Ⓖ']), ('ⓗ', &['Ⓗ']), ('ⓘ', &[ + 'Ⓘ']), ('ⓙ', &['Ⓙ']), ('ⓚ', &['Ⓚ']), ('ⓛ', &['Ⓛ']), ('ⓜ', &[ + 'Ⓜ']), ('ⓝ', &['Ⓝ']), ('ⓞ', &['Ⓞ']), ('ⓟ', &['Ⓟ']), ('ⓠ', &[ + 'Ⓠ']), ('ⓡ', &['Ⓡ']), ('ⓢ', &['Ⓢ']), ('ⓣ', &['Ⓣ']), ('ⓤ', &[ + 'Ⓤ']), ('ⓥ', &['Ⓥ']), ('ⓦ', &['Ⓦ']), ('ⓧ', &['Ⓧ']), ('ⓨ', &[ + 'Ⓨ']), ('ⓩ', &['Ⓩ']), ('Ⰰ', &['â°°']), ('Ⰱ', &['â°±']), ('Ⰲ', &[ + 'â°²']), ('Ⰳ', &['â°³']), ('Ⰴ', &['â°´']), ('Ⰵ', &['â°µ']), ('Ⰶ', &[ + 'â°¶']), ('Ⰷ', &['â°·']), ('Ⰸ', &['â°¸']), ('Ⰹ', &['â°¹']), ('Ⰺ', &[ + 'â°º']), ('Ⰻ', &['â°»']), ('Ⰼ', &['â°¼']), ('Ⰽ', &['â°½']), ('Ⰾ', &[ + 'â°¾']), ('Ⰿ', &['â°¿']), ('Ⱀ', &['ⱀ']), ('Ⱁ', &['ⱁ']), ('Ⱂ', &[ + 'ⱂ']), ('Ⱃ', &['ⱃ']), ('Ⱄ', &['ⱄ']), ('Ⱅ', &['ⱅ']), ('Ⱆ', &[ + 'ⱆ']), ('Ⱇ', &['ⱇ']), ('Ⱈ', &['ⱈ']), ('Ⱉ', &['ⱉ']), ('Ⱊ', &[ + 'ⱊ']), ('Ⱋ', &['ⱋ']), ('Ⱌ', &['ⱌ']), ('Ⱍ', &['ⱍ']), ('Ⱎ', &[ + 'ⱎ']), ('Ⱏ', &['ⱏ']), ('â° ', &['ⱐ']), ('â°¡', &['ⱑ']), ('â°¢', &[ + 'ⱒ']), ('â°£', &['ⱓ']), ('â°¤', &['ⱔ']), ('â°¥', &['ⱕ']), ('â°¦', &[ + 'ⱖ']), ('â°§', &['ⱗ']), ('â°¨', &['ⱘ']), ('â°©', &['ⱙ']), ('â°ª', &[ + 'ⱚ']), ('â°«', &['ⱛ']), ('â°¬', &['ⱜ']), ('â°­', &['ⱝ']), ('â°®', &[ + 'ⱞ']), ('â°°', &['Ⰰ']), ('â°±', &['Ⰱ']), ('â°²', &['Ⰲ']), ('â°³', &[ + 'Ⰳ']), ('â°´', &['Ⰴ']), ('â°µ', &['Ⰵ']), ('â°¶', &['Ⰶ']), ('â°·', &[ + 'Ⰷ']), ('â°¸', &['Ⰸ']), ('â°¹', &['Ⰹ']), ('â°º', &['Ⰺ']), ('â°»', &[ + 'Ⰻ']), ('â°¼', &['Ⰼ']), ('â°½', &['Ⰽ']), ('â°¾', &['Ⰾ']), ('â°¿', &[ + 'Ⰿ']), ('ⱀ', &['Ⱀ']), ('ⱁ', &['Ⱁ']), ('ⱂ', &['Ⱂ']), ('ⱃ', &[ + 'Ⱃ']), ('ⱄ', &['Ⱄ']), ('ⱅ', &['Ⱅ']), ('ⱆ', &['Ⱆ']), ('ⱇ', &[ + 'Ⱇ']), ('ⱈ', &['Ⱈ']), ('ⱉ', &['Ⱉ']), ('ⱊ', &['Ⱊ']), ('ⱋ', &[ + 'Ⱋ']), ('ⱌ', &['Ⱌ']), ('ⱍ', &['Ⱍ']), ('ⱎ', &['Ⱎ']), ('ⱏ', &[ + 'Ⱏ']), ('ⱐ', &['â° ']), ('ⱑ', &['â°¡']), ('ⱒ', &['â°¢']), ('ⱓ', &[ + 'â°£']), ('ⱔ', &['â°¤']), ('ⱕ', &['â°¥']), ('ⱖ', &['â°¦']), ('ⱗ', &[ + 'â°§']), ('ⱘ', &['â°¨']), ('ⱙ', &['â°©']), ('ⱚ', &['â°ª']), ('ⱛ', &[ + 'â°«']), ('ⱜ', &['â°¬']), ('ⱝ', &['â°­']), ('ⱞ', &['â°®']), ('â± ', &[ + 'ⱡ']), ('ⱡ', &['â± ']), ('â±¢', &['É«']), ('â±£', &['áµ½']), ('Ɽ', &[ + 'ɽ']), ('â±¥', &['Ⱥ']), ('ⱦ', &['Ⱦ']), ('â±§', &['ⱨ']), ('ⱨ', &[ + 'â±§']), ('Ⱪ', &['ⱪ']), ('ⱪ', &['Ⱪ']), ('Ⱬ', &['ⱬ']), ('ⱬ', &[ + 'Ⱬ']), ('â±­', &['ɑ']), ('â±®', &['ɱ']), ('Ɐ', &['ɐ']), ('â±°', &['ɒ' + ]), ('â±²', &['â±³']), ('â±³', &['â±²']), ('â±µ', &['â±¶']), ('â±¶', &['â±µ' + ]), ('â±¾', &['È¿']), ('Ɀ', &['ɀ']), ('Ⲁ', &['ⲁ']), ('ⲁ', &['Ⲁ' + ]), ('Ⲃ', &['ⲃ']), ('ⲃ', &['Ⲃ']), ('Ⲅ', &['ⲅ']), ('ⲅ', &['Ⲅ' + ]), ('Ⲇ', &['ⲇ']), ('ⲇ', &['Ⲇ']), ('Ⲉ', &['ⲉ']), ('ⲉ', &['Ⲉ' + ]), ('Ⲋ', &['ⲋ']), ('ⲋ', &['Ⲋ']), ('Ⲍ', &['ⲍ']), ('ⲍ', &['Ⲍ' + ]), ('Ⲏ', &['ⲏ']), ('ⲏ', &['Ⲏ']), ('Ⲑ', &['ⲑ']), ('ⲑ', &['Ⲑ' + ]), ('Ⲓ', &['ⲓ']), ('ⲓ', &['Ⲓ']), ('Ⲕ', &['ⲕ']), ('ⲕ', &['Ⲕ' + ]), ('Ⲗ', &['ⲗ']), ('ⲗ', &['Ⲗ']), ('Ⲙ', &['ⲙ']), ('ⲙ', &['Ⲙ' + ]), ('Ⲛ', &['ⲛ']), ('ⲛ', &['Ⲛ']), ('Ⲝ', &['ⲝ']), ('ⲝ', &['Ⲝ' + ]), ('Ⲟ', &['ⲟ']), ('ⲟ', &['Ⲟ']), ('â² ', &['ⲡ']), ('ⲡ', &['â² ' + ]), ('â²¢', &['â²£']), ('â²£', &['â²¢']), ('Ⲥ', &['â²¥']), ('â²¥', &['Ⲥ' + ]), ('Ⲧ', &['â²§']), ('â²§', &['Ⲧ']), ('Ⲩ', &['ⲩ']), ('ⲩ', &['Ⲩ' + ]), ('Ⲫ', &['ⲫ']), ('ⲫ', &['Ⲫ']), ('Ⲭ', &['â²­']), ('â²­', &['Ⲭ' + ]), ('â²®', &['ⲯ']), ('ⲯ', &['â²®']), ('â²°', &['â²±']), ('â²±', &['â²°' + ]), ('â²²', &['â²³']), ('â²³', &['â²²']), ('â²´', &['â²µ']), ('â²µ', &['â²´' + ]), ('â²¶', &['â²·']), ('â²·', &['â²¶']), ('Ⲹ', &['â²¹']), ('â²¹', &['Ⲹ' + ]), ('Ⲻ', &['â²»']), ('â²»', &['Ⲻ']), ('â²¼', &['â²½']), ('â²½', &['â²¼' + ]), ('â²¾', &['ⲿ']), ('ⲿ', &['â²¾']), ('Ⳁ', &['ⳁ']), ('ⳁ', &['Ⳁ' + ]), ('Ⳃ', &['ⳃ']), ('ⳃ', &['Ⳃ']), ('Ⳅ', &['ⳅ']), ('ⳅ', &['Ⳅ' + ]), ('Ⳇ', &['ⳇ']), ('ⳇ', &['Ⳇ']), ('Ⳉ', &['ⳉ']), ('ⳉ', &['Ⳉ' + ]), ('Ⳋ', &['ⳋ']), ('ⳋ', &['Ⳋ']), ('Ⳍ', &['ⳍ']), ('ⳍ', &['Ⳍ' + ]), ('Ⳏ', &['ⳏ']), ('ⳏ', &['Ⳏ']), ('Ⳑ', &['ⳑ']), ('ⳑ', &['Ⳑ' + ]), ('Ⳓ', &['ⳓ']), ('ⳓ', &['Ⳓ']), ('Ⳕ', &['ⳕ']), ('ⳕ', &['Ⳕ' + ]), ('Ⳗ', &['ⳗ']), ('ⳗ', &['Ⳗ']), ('Ⳙ', &['ⳙ']), ('ⳙ', &['Ⳙ' + ]), ('Ⳛ', &['ⳛ']), ('ⳛ', &['Ⳛ']), ('Ⳝ', &['ⳝ']), ('ⳝ', &['Ⳝ' + ]), ('Ⳟ', &['ⳟ']), ('ⳟ', &['Ⳟ']), ('â³ ', &['ⳡ']), ('ⳡ', &['â³ ' + ]), ('â³¢', &['â³£']), ('â³£', &['â³¢']), ('Ⳬ', &['ⳬ']), ('ⳬ', &['Ⳬ' + ]), ('â³­', &['â³®']), ('â³®', &['â³­']), ('â³²', &['â³³']), ('â³³', &['â³²' + ]), ('ⴀ', &['Ⴀ']), ('ⴁ', &['Ⴁ']), ('ⴂ', &['Ⴂ']), ('ⴃ', &['Ⴃ' + ]), ('ⴄ', &['Ⴄ']), ('ⴅ', &['Ⴅ']), ('ⴆ', &['Ⴆ']), ('ⴇ', &['Ⴇ' + ]), ('ⴈ', &['Ⴈ']), ('ⴉ', &['Ⴉ']), ('ⴊ', &['Ⴊ']), ('ⴋ', &['Ⴋ' + ]), ('ⴌ', &['Ⴌ']), ('ⴍ', &['Ⴍ']), ('ⴎ', &['Ⴎ']), ('ⴏ', &['Ⴏ' + ]), ('ⴐ', &['Ⴐ']), ('ⴑ', &['Ⴑ']), ('ⴒ', &['Ⴒ']), ('ⴓ', &['Ⴓ' + ]), ('ⴔ', &['Ⴔ']), ('ⴕ', &['Ⴕ']), ('ⴖ', &['Ⴖ']), ('ⴗ', &['Ⴗ' + ]), ('ⴘ', &['Ⴘ']), ('ⴙ', &['Ⴙ']), ('ⴚ', &['Ⴚ']), ('ⴛ', &['Ⴛ' + ]), ('ⴜ', &['Ⴜ']), ('ⴝ', &['Ⴝ']), ('ⴞ', &['Ⴞ']), ('ⴟ', &['Ⴟ' + ]), ('â´ ', &['Ⴠ']), ('â´¡', &['Ⴡ']), ('â´¢', &['Ⴢ']), ('â´£', &['Ⴣ' + ]), ('â´¤', &['Ⴤ']), ('â´¥', &['Ⴥ']), ('â´§', &['Ⴧ']), ('â´­', &['Ⴭ' + ]), ('Ꙁ', &['ꙁ']), ('ꙁ', &['Ꙁ']), ('Ꙃ', &['ꙃ']), ('ꙃ', &['Ꙃ' + ]), ('Ꙅ', &['ꙅ']), ('ꙅ', &['Ꙅ']), ('Ꙇ', &['ꙇ']), ('ꙇ', &['Ꙇ' + ]), ('Ꙉ', &['ꙉ']), ('ꙉ', &['Ꙉ']), ('Ꙋ', &['ᲈ', 'ꙋ', ]), + ('ꙋ', &['ᲈ', 'Ꙋ', ]), ('Ꙍ', &['ꙍ']), ('ꙍ', &['Ꙍ']), ('Ꙏ', &[ + 'ꙏ']), ('ꙏ', &['Ꙏ']), ('Ꙑ', &['ꙑ']), ('ꙑ', &['Ꙑ']), ('Ꙓ', &[ + 'ꙓ']), ('ꙓ', &['Ꙓ']), ('Ꙕ', &['ꙕ']), ('ꙕ', &['Ꙕ']), ('Ꙗ', &[ + 'ꙗ']), ('ꙗ', &['Ꙗ']), ('Ꙙ', &['ꙙ']), ('ꙙ', &['Ꙙ']), ('Ꙛ', &[ + 'ꙛ']), ('ꙛ', &['Ꙛ']), ('Ꙝ', &['ꙝ']), ('ꙝ', &['Ꙝ']), ('Ꙟ', &[ + 'ꙟ']), ('ꙟ', &['Ꙟ']), ('Ꙡ', &['ꙡ']), ('ꙡ', &['Ꙡ']), ('Ꙣ', &[ + 'ꙣ']), ('ꙣ', &['Ꙣ']), ('Ꙥ', &['ꙥ']), ('ꙥ', &['Ꙥ']), ('Ꙧ', &[ + 'ꙧ']), ('ꙧ', &['Ꙧ']), ('Ꙩ', &['ꙩ']), ('ꙩ', &['Ꙩ']), ('Ꙫ', &[ + 'ꙫ']), ('ꙫ', &['Ꙫ']), ('Ꙭ', &['ꙭ']), ('ꙭ', &['Ꙭ']), ('Ꚁ', &[ + 'ꚁ']), ('ꚁ', &['Ꚁ']), ('Ꚃ', &['ꚃ']), ('ꚃ', &['Ꚃ']), ('Ꚅ', &[ + 'ꚅ']), ('ꚅ', &['Ꚅ']), ('Ꚇ', &['ꚇ']), ('ꚇ', &['Ꚇ']), ('Ꚉ', &[ + 'ꚉ']), ('ꚉ', &['Ꚉ']), ('Ꚋ', &['ꚋ']), ('ꚋ', &['Ꚋ']), ('Ꚍ', &[ + 'ꚍ']), ('ꚍ', &['Ꚍ']), ('Ꚏ', &['ꚏ']), ('ꚏ', &['Ꚏ']), ('Ꚑ', &[ + 'ꚑ']), ('ꚑ', &['Ꚑ']), ('Ꚓ', &['ꚓ']), ('ꚓ', &['Ꚓ']), ('Ꚕ', &[ + 'ꚕ']), ('ꚕ', &['Ꚕ']), ('Ꚗ', &['ꚗ']), ('ꚗ', &['Ꚗ']), ('Ꚙ', &[ + 'ꚙ']), ('ꚙ', &['Ꚙ']), ('Ꚛ', &['ꚛ']), ('ꚛ', &['Ꚛ']), ('Ꜣ', &[ + 'ꜣ']), ('ꜣ', &['Ꜣ']), ('Ꜥ', &['ꜥ']), ('ꜥ', &['Ꜥ']), ('Ꜧ', &[ + 'ꜧ']), ('ꜧ', &['Ꜧ']), ('Ꜩ', &['ꜩ']), ('ꜩ', &['Ꜩ']), ('Ꜫ', &[ + 'ꜫ']), ('ꜫ', &['Ꜫ']), ('Ꜭ', &['ꜭ']), ('ꜭ', &['Ꜭ']), ('Ꜯ', &[ + 'ꜯ']), ('ꜯ', &['Ꜯ']), ('Ꜳ', &['ꜳ']), ('ꜳ', &['Ꜳ']), ('Ꜵ', &[ + 'ꜵ']), ('ꜵ', &['Ꜵ']), ('Ꜷ', &['ꜷ']), ('ꜷ', &['Ꜷ']), ('Ꜹ', &[ + 'ꜹ']), ('ꜹ', &['Ꜹ']), ('Ꜻ', &['ꜻ']), ('ꜻ', &['Ꜻ']), ('Ꜽ', &[ + 'ꜽ']), ('ꜽ', &['Ꜽ']), ('Ꜿ', &['ꜿ']), ('ꜿ', &['Ꜿ']), ('Ꝁ', &[ + 'ꝁ']), ('ꝁ', &['Ꝁ']), ('Ꝃ', &['ꝃ']), ('ꝃ', &['Ꝃ']), ('Ꝅ', &[ + 'ꝅ']), ('ꝅ', &['Ꝅ']), ('Ꝇ', &['ꝇ']), ('ꝇ', &['Ꝇ']), ('Ꝉ', &[ + 'ꝉ']), ('ꝉ', &['Ꝉ']), ('Ꝋ', &['ꝋ']), ('ꝋ', &['Ꝋ']), ('Ꝍ', &[ + 'ꝍ']), ('ꝍ', &['Ꝍ']), ('Ꝏ', &['ꝏ']), ('ꝏ', &['Ꝏ']), ('Ꝑ', &[ + 'ꝑ']), ('ꝑ', &['Ꝑ']), ('Ꝓ', &['ꝓ']), ('ꝓ', &['Ꝓ']), ('Ꝕ', &[ + 'ꝕ']), ('ꝕ', &['Ꝕ']), ('Ꝗ', &['ꝗ']), ('ꝗ', &['Ꝗ']), ('Ꝙ', &[ + 'ꝙ']), ('ꝙ', &['Ꝙ']), ('Ꝛ', &['ꝛ']), ('ꝛ', &['Ꝛ']), ('Ꝝ', &[ + 'ꝝ']), ('ꝝ', &['Ꝝ']), ('Ꝟ', &['ꝟ']), ('ꝟ', &['Ꝟ']), ('Ꝡ', &[ + 'ꝡ']), ('ꝡ', &['Ꝡ']), ('Ꝣ', &['ꝣ']), ('ꝣ', &['Ꝣ']), ('Ꝥ', &[ + 'ꝥ']), ('ꝥ', &['Ꝥ']), ('Ꝧ', &['ꝧ']), ('ꝧ', &['Ꝧ']), ('Ꝩ', &[ + 'ꝩ']), ('ꝩ', &['Ꝩ']), ('Ꝫ', &['ꝫ']), ('ꝫ', &['Ꝫ']), ('Ꝭ', &[ + 'ꝭ']), ('ꝭ', &['Ꝭ']), ('Ꝯ', &['ꝯ']), ('ꝯ', &['Ꝯ']), ('Ꝺ', &[ + 'ꝺ']), ('ꝺ', &['Ꝺ']), ('Ꝼ', &['ꝼ']), ('ꝼ', &['Ꝼ']), ('Ᵹ', &[ + 'áµ¹']), ('Ꝿ', &['ꝿ']), ('ꝿ', &['Ꝿ']), ('Ꞁ', &['ꞁ']), ('ꞁ', &[ + 'Ꞁ']), ('Ꞃ', &['ꞃ']), ('ꞃ', &['Ꞃ']), ('Ꞅ', &['ꞅ']), ('ꞅ', &[ + 'Ꞅ']), ('Ꞇ', &['ꞇ']), ('ꞇ', &['Ꞇ']), ('Ꞌ', &['ꞌ']), ('ꞌ', &[ + 'Ꞌ']), ('Ɥ', &['É¥']), ('Ꞑ', &['ꞑ']), ('ꞑ', &['Ꞑ']), ('Ꞓ', &[ + 'ꞓ']), ('ꞓ', &['Ꞓ']), ('Ꞗ', &['ꞗ']), ('ꞗ', &['Ꞗ']), ('Ꞙ', &[ + 'ꞙ']), ('ꞙ', &['Ꞙ']), ('Ꞛ', &['ꞛ']), ('ꞛ', &['Ꞛ']), ('Ꞝ', &[ + 'ꞝ']), ('ꞝ', &['Ꞝ']), ('Ꞟ', &['ꞟ']), ('ꞟ', &['Ꞟ']), ('Ꞡ', &[ + 'ꞡ']), ('ꞡ', &['Ꞡ']), ('Ꞣ', &['ꞣ']), ('ꞣ', &['Ꞣ']), ('Ꞥ', &[ + 'ꞥ']), ('ꞥ', &['Ꞥ']), ('Ꞧ', &['ꞧ']), ('ꞧ', &['Ꞧ']), ('Ꞩ', &[ + 'ꞩ']), ('ꞩ', &['Ꞩ']), ('Ɦ', &['ɦ']), ('Ɜ', &['ɜ']), ('Ɡ', &[ + 'É¡']), ('Ɬ', &['ɬ']), ('Ɪ', &['ɪ']), ('Ʞ', &['ʞ']), ('Ʇ', &['ʇ' + ]), ('Ʝ', &['ʝ']), ('Ꭓ', &['ꭓ']), ('Ꞵ', &['ꞵ']), ('ꞵ', &['Ꞵ' + ]), ('Ꞷ', &['ꞷ']), ('ꞷ', &['Ꞷ']), ('\u{a7b8}', &['\u{a7b9}']), + ('\u{a7b9}', &['\u{a7b8}']), ('ꭓ', &['Ꭓ']), ('ê­°', &['Ꭰ']), ('ê­±', &[ + 'Ꭱ']), ('ê­²', &['Ꭲ']), ('ê­³', &['Ꭳ']), ('ê­´', &['Ꭴ']), ('ê­µ', &[ + 'Ꭵ']), ('ê­¶', &['Ꭶ']), ('ê­·', &['Ꭷ']), ('ê­¸', &['Ꭸ']), ('ê­¹', &[ + 'Ꭹ']), ('ê­º', &['Ꭺ']), ('ê­»', &['Ꭻ']), ('ê­¼', &['Ꭼ']), ('ê­½', &[ + 'Ꭽ']), ('ê­¾', &['Ꭾ']), ('ê­¿', &['Ꭿ']), ('ꮀ', &['Ꮀ']), ('ꮁ', &[ + 'Ꮁ']), ('ꮂ', &['Ꮂ']), ('ꮃ', &['Ꮃ']), ('ꮄ', &['Ꮄ']), ('ꮅ', &[ + 'Ꮅ']), ('ꮆ', &['Ꮆ']), ('ꮇ', &['Ꮇ']), ('ꮈ', &['Ꮈ']), ('ꮉ', &[ + 'Ꮉ']), ('ꮊ', &['Ꮊ']), ('ꮋ', &['Ꮋ']), ('ꮌ', &['Ꮌ']), ('ꮍ', &[ + 'Ꮍ']), ('ꮎ', &['Ꮎ']), ('ꮏ', &['Ꮏ']), ('ꮐ', &['Ꮐ']), ('ꮑ', &[ + 'Ꮑ']), ('ꮒ', &['Ꮒ']), ('ꮓ', &['Ꮓ']), ('ꮔ', &['Ꮔ']), ('ꮕ', &[ + 'Ꮕ']), ('ꮖ', &['Ꮖ']), ('ꮗ', &['Ꮗ']), ('ꮘ', &['Ꮘ']), ('ꮙ', &[ + 'Ꮙ']), ('ꮚ', &['Ꮚ']), ('ꮛ', &['Ꮛ']), ('ꮜ', &['Ꮜ']), ('ꮝ', &[ + 'Ꮝ']), ('ꮞ', &['Ꮞ']), ('ꮟ', &['Ꮟ']), ('ê® ', &['Ꮠ']), ('ꮡ', &[ + 'Ꮡ']), ('ꮢ', &['Ꮢ']), ('ꮣ', &['Ꮣ']), ('ꮤ', &['Ꮤ']), ('ꮥ', &[ + 'Ꮥ']), ('ꮦ', &['Ꮦ']), ('ê®§', &['Ꮧ']), ('ꮨ', &['Ꮨ']), ('ꮩ', &[ + 'Ꮩ']), ('ꮪ', &['Ꮪ']), ('ꮫ', &['Ꮫ']), ('ꮬ', &['Ꮬ']), ('ê®­', &[ + 'Ꮭ']), ('ê®®', &['Ꮮ']), ('ꮯ', &['Ꮯ']), ('ê®°', &['Ꮰ']), ('ê®±', &[ + 'Ꮱ']), ('ꮲ', &['Ꮲ']), ('ꮳ', &['Ꮳ']), ('ê®´', &['Ꮴ']), ('ꮵ', &[ + 'Ꮵ']), ('ê®¶', &['Ꮶ']), ('ê®·', &['Ꮷ']), ('ꮸ', &['Ꮸ']), ('ꮹ', &[ + 'Ꮹ']), ('ꮺ', &['Ꮺ']), ('ê®»', &['Ꮻ']), ('ꮼ', &['Ꮼ']), ('ꮽ', &[ + 'Ꮽ']), ('ꮾ', &['Ꮾ']), ('ꮿ', &['Ꮿ']), ('A', &['a']), ('ï¼¢', &[ + 'b']), ('ï¼£', &['c']), ('D', &['d']), ('ï¼¥', &['e']), ('F', &[ + 'f']), ('ï¼§', &['g']), ('H', &['h']), ('I', &['i']), ('J', &[ + 'j']), ('K', &['k']), ('L', &['l']), ('ï¼­', &['m']), ('ï¼®', &[ + 'n']), ('O', &['o']), ('ï¼°', &['p']), ('ï¼±', &['q']), ('ï¼²', &[ + 'r']), ('ï¼³', &['s']), ('ï¼´', &['t']), ('ï¼µ', &['u']), ('ï¼¶', &[ + 'v']), ('ï¼·', &['w']), ('X', &['x']), ('ï¼¹', &['y']), ('Z', &[ + 'z']), ('a', &['A']), ('b', &['ï¼¢']), ('c', &['ï¼£']), ('d', &[ + 'D']), ('e', &['ï¼¥']), ('f', &['F']), ('g', &['ï¼§']), ('h', &[ + 'H']), ('i', &['I']), ('j', &['J']), ('k', &['K']), ('l', &[ + 'L']), ('m', &['ï¼­']), ('n', &['ï¼®']), ('o', &['O']), ('p', &[ + 'ï¼°']), ('q', &['ï¼±']), ('r', &['ï¼²']), ('s', &['ï¼³']), ('t', &[ + 'ï¼´']), ('u', &['ï¼µ']), ('v', &['ï¼¶']), ('w', &['ï¼·']), ('x', &[ + 'X']), ('y', &['ï¼¹']), ('z', &['Z']), ('𐐀', &['𐐨']), + ('𐐁', &['𐐩']), ('𐐂', &['𐐪']), ('𐐃', &['𐐫']), ('𐐄', &[ + '𐐬']), ('𐐅', &['𐐭']), ('𐐆', &['𐐮']), ('𐐇', &['𐐯']), + ('𐐈', &['𐐰']), ('𐐉', &['𐐱']), ('𐐊', &['𐐲']), ('𐐋', &[ + '𐐳']), ('𐐌', &['𐐴']), ('𐐍', &['𐐵']), ('𐐎', &['𐐶']), + ('𐐏', &['𐐷']), ('𐐐', &['𐐸']), ('𐐑', &['𐐹']), ('𐐒', &[ + '𐐺']), ('𐐓', &['𐐻']), ('𐐔', &['𐐼']), ('𐐕', &['𐐽']), + ('𐐖', &['𐐾']), ('𐐗', &['𐐿']), ('𐐘', &['𐑀']), ('𐐙', &[ + '𐑁']), ('𐐚', &['𐑂']), ('𐐛', &['𐑃']), ('𐐜', &['𐑄']), + ('𐐝', &['𐑅']), ('𐐞', &['𐑆']), ('𐐟', &['𐑇']), ('𐐠', &[ + '𐑈']), ('𐐡', &['𐑉']), ('𐐢', &['𐑊']), ('𐐣', &['𐑋']), + ('𐐤', &['𐑌']), ('𐐥', &['𐑍']), ('𐐦', &['𐑎']), ('𐐧', &[ + '𐑏']), ('𐐨', &['𐐀']), ('𐐩', &['𐐁']), ('𐐪', &['𐐂']), + ('𐐫', &['𐐃']), ('𐐬', &['𐐄']), ('𐐭', &['𐐅']), ('𐐮', &[ + '𐐆']), ('𐐯', &['𐐇']), ('𐐰', &['𐐈']), ('𐐱', &['𐐉']), + ('𐐲', &['𐐊']), ('𐐳', &['𐐋']), ('𐐴', &['𐐌']), ('𐐵', &[ + '𐐍']), ('𐐶', &['𐐎']), ('𐐷', &['𐐏']), ('𐐸', &['𐐐']), + ('𐐹', &['𐐑']), ('𐐺', &['𐐒']), ('𐐻', &['𐐓']), ('𐐼', &[ + '𐐔']), ('𐐽', &['𐐕']), ('𐐾', &['𐐖']), ('𐐿', &['𐐗']), + ('𐑀', &['𐐘']), ('𐑁', &['𐐙']), ('𐑂', &['𐐚']), ('𐑃', &[ + '𐐛']), ('𐑄', &['𐐜']), ('𐑅', &['𐐝']), ('𐑆', &['𐐞']), + ('𐑇', &['𐐟']), ('𐑈', &['𐐠']), ('𐑉', &['𐐡']), ('𐑊', &[ + '𐐢']), ('𐑋', &['𐐣']), ('𐑌', &['𐐤']), ('𐑍', &['𐐥']), + ('𐑎', &['𐐦']), ('𐑏', &['𐐧']), ('𐒰', &['𐓘']), ('𐒱', &[ + '𐓙']), ('𐒲', &['𐓚']), ('𐒳', &['𐓛']), ('𐒴', &['𐓜']), + ('𐒵', &['𐓝']), ('𐒶', &['𐓞']), ('𐒷', &['𐓟']), ('𐒸', &[ + '𐓠']), ('𐒹', &['𐓡']), ('𐒺', &['𐓢']), ('𐒻', &['𐓣']), + ('𐒼', &['𐓤']), ('𐒽', &['𐓥']), ('𐒾', &['𐓦']), ('𐒿', &[ + '𐓧']), ('𐓀', &['𐓨']), ('𐓁', &['𐓩']), ('𐓂', &['𐓪']), + ('𐓃', &['𐓫']), ('𐓄', &['𐓬']), ('𐓅', &['𐓭']), ('𐓆', &[ + '𐓮']), ('𐓇', &['𐓯']), ('𐓈', &['𐓰']), ('𐓉', &['𐓱']), + ('𐓊', &['𐓲']), ('𐓋', &['𐓳']), ('𐓌', &['𐓴']), ('𐓍', &[ + '𐓵']), ('𐓎', &['𐓶']), ('𐓏', &['𐓷']), ('𐓐', &['𐓸']), + ('𐓑', &['𐓹']), ('𐓒', &['𐓺']), ('𐓓', &['𐓻']), ('𐓘', &[ + '𐒰']), ('𐓙', &['𐒱']), ('𐓚', &['𐒲']), ('𐓛', &['𐒳']), + ('𐓜', &['𐒴']), ('𐓝', &['𐒵']), ('𐓞', &['𐒶']), ('𐓟', &[ + '𐒷']), ('𐓠', &['𐒸']), ('𐓡', &['𐒹']), ('𐓢', &['𐒺']), + ('𐓣', &['𐒻']), ('𐓤', &['𐒼']), ('𐓥', &['𐒽']), ('𐓦', &[ + '𐒾']), ('𐓧', &['𐒿']), ('𐓨', &['𐓀']), ('𐓩', &['𐓁']), + ('𐓪', &['𐓂']), ('𐓫', &['𐓃']), ('𐓬', &['𐓄']), ('𐓭', &[ + '𐓅']), ('𐓮', &['𐓆']), ('𐓯', &['𐓇']), ('𐓰', &['𐓈']), + ('𐓱', &['𐓉']), ('𐓲', &['𐓊']), ('𐓳', &['𐓋']), ('𐓴', &[ + '𐓌']), ('𐓵', &['𐓍']), ('𐓶', &['𐓎']), ('𐓷', &['𐓏']), + ('𐓸', &['𐓐']), ('𐓹', &['𐓑']), ('𐓺', &['𐓒']), ('𐓻', &[ + '𐓓']), ('𐲀', &['𐳀']), ('𐲁', &['𐳁']), ('𐲂', &['𐳂']), + ('𐲃', &['𐳃']), ('𐲄', &['𐳄']), ('𐲅', &['𐳅']), ('𐲆', &[ + '𐳆']), ('𐲇', &['𐳇']), ('𐲈', &['𐳈']), ('𐲉', &['𐳉']), + ('𐲊', &['𐳊']), ('𐲋', &['𐳋']), ('𐲌', &['𐳌']), ('𐲍', &[ + '𐳍']), ('𐲎', &['𐳎']), ('𐲏', &['𐳏']), ('𐲐', &['𐳐']), + ('𐲑', &['𐳑']), ('𐲒', &['𐳒']), ('𐲓', &['𐳓']), ('𐲔', &[ + '𐳔']), ('𐲕', &['𐳕']), ('𐲖', &['𐳖']), ('𐲗', &['𐳗']), + ('𐲘', &['𐳘']), ('𐲙', &['𐳙']), ('𐲚', &['𐳚']), ('𐲛', &[ + '𐳛']), ('𐲜', &['𐳜']), ('𐲝', &['𐳝']), ('𐲞', &['𐳞']), + ('𐲟', &['𐳟']), ('𐲠', &['𐳠']), ('𐲡', &['𐳡']), ('𐲢', &[ + '𐳢']), ('𐲣', &['𐳣']), ('𐲤', &['𐳤']), ('𐲥', &['𐳥']), + ('𐲦', &['𐳦']), ('𐲧', &['𐳧']), ('𐲨', &['𐳨']), ('𐲩', &[ + '𐳩']), ('𐲪', &['𐳪']), ('𐲫', &['𐳫']), ('𐲬', &['𐳬']), + ('𐲭', &['𐳭']), ('𐲮', &['𐳮']), ('𐲯', &['𐳯']), ('𐲰', &[ + '𐳰']), ('𐲱', &['𐳱']), ('𐲲', &['𐳲']), ('𐳀', &['𐲀']), + ('𐳁', &['𐲁']), ('𐳂', &['𐲂']), ('𐳃', &['𐲃']), ('𐳄', &[ + '𐲄']), ('𐳅', &['𐲅']), ('𐳆', &['𐲆']), ('𐳇', &['𐲇']), + ('𐳈', &['𐲈']), ('𐳉', &['𐲉']), ('𐳊', &['𐲊']), ('𐳋', &[ + '𐲋']), ('𐳌', &['𐲌']), ('𐳍', &['𐲍']), ('𐳎', &['𐲎']), + ('𐳏', &['𐲏']), ('𐳐', &['𐲐']), ('𐳑', &['𐲑']), ('𐳒', &[ + '𐲒']), ('𐳓', &['𐲓']), ('𐳔', &['𐲔']), ('𐳕', &['𐲕']), + ('𐳖', &['𐲖']), ('𐳗', &['𐲗']), ('𐳘', &['𐲘']), ('𐳙', &[ + '𐲙']), ('𐳚', &['𐲚']), ('𐳛', &['𐲛']), ('𐳜', &['𐲜']), + ('𐳝', &['𐲝']), ('𐳞', &['𐲞']), ('𐳟', &['𐲟']), ('𐳠', &[ + '𐲠']), ('𐳡', &['𐲡']), ('𐳢', &['𐲢']), ('𐳣', &['𐲣']), + ('𐳤', &['𐲤']), ('𐳥', &['𐲥']), ('𐳦', &['𐲦']), ('𐳧', &[ + '𐲧']), ('𐳨', &['𐲨']), ('𐳩', &['𐲩']), ('𐳪', &['𐲪']), + ('𐳫', &['𐲫']), ('𐳬', &['𐲬']), ('𐳭', &['𐲭']), ('𐳮', &[ + '𐲮']), ('𐳯', &['𐲯']), ('𐳰', &['𐲰']), ('𐳱', &['𐲱']), + ('𐳲', &['𐲲']), ('𑢠', &['𑣀']), ('𑢡', &['𑣁']), ('𑢢', &[ + '𑣂']), ('𑢣', &['𑣃']), ('𑢤', &['𑣄']), ('𑢥', &['𑣅']), + ('𑢦', &['𑣆']), ('𑢧', &['𑣇']), ('𑢨', &['𑣈']), ('𑢩', &[ + '𑣉']), ('𑢪', &['𑣊']), ('𑢫', &['𑣋']), ('𑢬', &['𑣌']), + ('𑢭', &['𑣍']), ('𑢮', &['𑣎']), ('𑢯', &['𑣏']), ('𑢰', &[ + '𑣐']), ('𑢱', &['𑣑']), ('𑢲', &['𑣒']), ('𑢳', &['𑣓']), + ('𑢴', &['𑣔']), ('𑢵', &['𑣕']), ('𑢶', &['𑣖']), ('𑢷', &[ + '𑣗']), ('𑢸', &['𑣘']), ('𑢹', &['𑣙']), ('𑢺', &['𑣚']), + ('𑢻', &['𑣛']), ('𑢼', &['𑣜']), ('𑢽', &['𑣝']), ('𑢾', &[ + '𑣞']), ('𑢿', &['𑣟']), ('𑣀', &['𑢠']), ('𑣁', &['𑢡']), + ('𑣂', &['𑢢']), ('𑣃', &['𑢣']), ('𑣄', &['𑢤']), ('𑣅', &[ + '𑢥']), ('𑣆', &['𑢦']), ('𑣇', &['𑢧']), ('𑣈', &['𑢨']), + ('𑣉', &['𑢩']), ('𑣊', &['𑢪']), ('𑣋', &['𑢫']), ('𑣌', &[ + '𑢬']), ('𑣍', &['𑢭']), ('𑣎', &['𑢮']), ('𑣏', &['𑢯']), + ('𑣐', &['𑢰']), ('𑣑', &['𑢱']), ('𑣒', &['𑢲']), ('𑣓', &[ + '𑢳']), ('𑣔', &['𑢴']), ('𑣕', &['𑢵']), ('𑣖', &['𑢶']), + ('𑣗', &['𑢷']), ('𑣘', &['𑢸']), ('𑣙', &['𑢹']), ('𑣚', &[ + '𑢺']), ('𑣛', &['𑢻']), ('𑣜', &['𑢼']), ('𑣝', &['𑢽']), + ('𑣞', &['𑢾']), ('𑣟', &['𑢿']), ('\u{16e40}', &['\u{16e60}']), + ('\u{16e41}', &['\u{16e61}']), ('\u{16e42}', &['\u{16e62}']), + ('\u{16e43}', &['\u{16e63}']), ('\u{16e44}', &['\u{16e64}']), + ('\u{16e45}', &['\u{16e65}']), ('\u{16e46}', &['\u{16e66}']), + ('\u{16e47}', &['\u{16e67}']), ('\u{16e48}', &['\u{16e68}']), + ('\u{16e49}', &['\u{16e69}']), ('\u{16e4a}', &['\u{16e6a}']), + ('\u{16e4b}', &['\u{16e6b}']), ('\u{16e4c}', &['\u{16e6c}']), + ('\u{16e4d}', &['\u{16e6d}']), ('\u{16e4e}', &['\u{16e6e}']), + ('\u{16e4f}', &['\u{16e6f}']), ('\u{16e50}', &['\u{16e70}']), + ('\u{16e51}', &['\u{16e71}']), ('\u{16e52}', &['\u{16e72}']), + ('\u{16e53}', &['\u{16e73}']), ('\u{16e54}', &['\u{16e74}']), + ('\u{16e55}', &['\u{16e75}']), ('\u{16e56}', &['\u{16e76}']), + ('\u{16e57}', &['\u{16e77}']), ('\u{16e58}', &['\u{16e78}']), + ('\u{16e59}', &['\u{16e79}']), ('\u{16e5a}', &['\u{16e7a}']), + ('\u{16e5b}', &['\u{16e7b}']), ('\u{16e5c}', &['\u{16e7c}']), + ('\u{16e5d}', &['\u{16e7d}']), ('\u{16e5e}', &['\u{16e7e}']), + ('\u{16e5f}', &['\u{16e7f}']), ('\u{16e60}', &['\u{16e40}']), + ('\u{16e61}', &['\u{16e41}']), ('\u{16e62}', &['\u{16e42}']), + ('\u{16e63}', &['\u{16e43}']), ('\u{16e64}', &['\u{16e44}']), + ('\u{16e65}', &['\u{16e45}']), ('\u{16e66}', &['\u{16e46}']), + ('\u{16e67}', &['\u{16e47}']), ('\u{16e68}', &['\u{16e48}']), + ('\u{16e69}', &['\u{16e49}']), ('\u{16e6a}', &['\u{16e4a}']), + ('\u{16e6b}', &['\u{16e4b}']), ('\u{16e6c}', &['\u{16e4c}']), + ('\u{16e6d}', &['\u{16e4d}']), ('\u{16e6e}', &['\u{16e4e}']), + ('\u{16e6f}', &['\u{16e4f}']), ('\u{16e70}', &['\u{16e50}']), + ('\u{16e71}', &['\u{16e51}']), ('\u{16e72}', &['\u{16e52}']), + ('\u{16e73}', &['\u{16e53}']), ('\u{16e74}', &['\u{16e54}']), + ('\u{16e75}', &['\u{16e55}']), ('\u{16e76}', &['\u{16e56}']), + ('\u{16e77}', &['\u{16e57}']), ('\u{16e78}', &['\u{16e58}']), + ('\u{16e79}', &['\u{16e59}']), ('\u{16e7a}', &['\u{16e5a}']), + ('\u{16e7b}', &['\u{16e5b}']), ('\u{16e7c}', &['\u{16e5c}']), + ('\u{16e7d}', &['\u{16e5d}']), ('\u{16e7e}', &['\u{16e5e}']), + ('\u{16e7f}', &['\u{16e5f}']), ('𞤀', &['𞤢']), ('𞤁', &['𞤣']), + ('𞤂', &['𞤤']), ('𞤃', &['𞤥']), ('𞤄', &['𞤦']), ('𞤅', &[ + '𞤧']), ('𞤆', &['𞤨']), ('𞤇', &['𞤩']), ('𞤈', &['𞤪']), + ('𞤉', &['𞤫']), ('𞤊', &['𞤬']), ('𞤋', &['𞤭']), ('𞤌', &[ + '𞤮']), ('𞤍', &['𞤯']), ('𞤎', &['𞤰']), ('𞤏', &['𞤱']), + ('𞤐', &['𞤲']), ('𞤑', &['𞤳']), ('𞤒', &['𞤴']), ('𞤓', &[ + '𞤵']), ('𞤔', &['𞤶']), ('𞤕', &['𞤷']), ('𞤖', &['𞤸']), + ('𞤗', &['𞤹']), ('𞤘', &['𞤺']), ('𞤙', &['𞤻']), ('𞤚', &[ + '𞤼']), ('𞤛', &['𞤽']), ('𞤜', &['𞤾']), ('𞤝', &['𞤿']), + ('𞤞', &['𞥀']), ('𞤟', &['𞥁']), ('𞤠', &['𞥂']), ('𞤡', &[ + '𞥃']), ('𞤢', &['𞤀']), ('𞤣', &['𞤁']), ('𞤤', &['𞤂']), + ('𞤥', &['𞤃']), ('𞤦', &['𞤄']), ('𞤧', &['𞤅']), ('𞤨', &[ + '𞤆']), ('𞤩', &['𞤇']), ('𞤪', &['𞤈']), ('𞤫', &['𞤉']), + ('𞤬', &['𞤊']), ('𞤭', &['𞤋']), ('𞤮', &['𞤌']), ('𞤯', &[ + '𞤍']), ('𞤰', &['𞤎']), ('𞤱', &['𞤏']), ('𞤲', &['𞤐']), + ('𞤳', &['𞤑']), ('𞤴', &['𞤒']), ('𞤵', &['𞤓']), ('𞤶', &[ + '𞤔']), ('𞤷', &['𞤕']), ('𞤸', &['𞤖']), ('𞤹', &['𞤗']), + ('𞤺', &['𞤘']), ('𞤻', &['𞤙']), ('𞤼', &['𞤚']), ('𞤽', &[ + '𞤛']), ('𞤾', &['𞤜']), ('𞤿', &['𞤝']), ('𞥀', &['𞤞']), + ('𞥁', &['𞤟']), ('𞥂', &['𞤠']), ('𞥃', &['𞤡']), +]; diff --git a/regex-syntax/src/unicode_tables/general_category.rs b/regex-syntax/src/unicode_tables/general_category.rs new file mode 100644 index 000000000..9a7be2880 --- /dev/null +++ b/regex-syntax/src/unicode_tables/general_category.rs @@ -0,0 +1,1907 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate general-category tmp/ucd-11.0.0/ --chars --exclude surrogate +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Cased_Letter", CASED_LETTER), ("Close_Punctuation", CLOSE_PUNCTUATION), + ("Connector_Punctuation", CONNECTOR_PUNCTUATION), ("Control", CONTROL), + ("Currency_Symbol", CURRENCY_SYMBOL), + ("Dash_Punctuation", DASH_PUNCTUATION), ("Decimal_Number", DECIMAL_NUMBER), + ("Enclosing_Mark", ENCLOSING_MARK), + ("Final_Punctuation", FINAL_PUNCTUATION), ("Format", FORMAT), + ("Initial_Punctuation", INITIAL_PUNCTUATION), ("Letter", LETTER), + ("Letter_Number", LETTER_NUMBER), ("Line_Separator", LINE_SEPARATOR), + ("Lowercase_Letter", LOWERCASE_LETTER), ("Mark", MARK), + ("Math_Symbol", MATH_SYMBOL), ("Modifier_Letter", MODIFIER_LETTER), + ("Modifier_Symbol", MODIFIER_SYMBOL), ("Nonspacing_Mark", NONSPACING_MARK), + ("Number", NUMBER), ("Open_Punctuation", OPEN_PUNCTUATION), + ("Other", OTHER), ("Other_Letter", OTHER_LETTER), + ("Other_Number", OTHER_NUMBER), ("Other_Punctuation", OTHER_PUNCTUATION), + ("Other_Symbol", OTHER_SYMBOL), + ("Paragraph_Separator", PARAGRAPH_SEPARATOR), ("Private_Use", PRIVATE_USE), + ("Punctuation", PUNCTUATION), ("Separator", SEPARATOR), + ("Space_Separator", SPACE_SEPARATOR), ("Spacing_Mark", SPACING_MARK), + ("Symbol", SYMBOL), ("Titlecase_Letter", TITLECASE_LETTER), + ("Unassigned", UNASSIGNED), ("Uppercase_Letter", UPPERCASE_LETTER), +]; + +pub const CASED_LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('µ', 'µ'), ('À', 'Ö'), ('Ø', 'ö'), + ('ø', 'ƺ'), ('Ƽ', 'Æ¿'), ('DŽ', 'ʓ'), ('ʕ', 'ʯ'), ('Ͱ', 'ͳ'), + ('Ͷ', 'Í·'), ('Í»', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('Ҋ', 'Ô¯'), + ('Ô±', 'Ֆ'), ('\u{560}', '\u{588}'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('Ꭰ', 'Ᏽ'), + ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), ('\u{1c90}', '\u{1cba}'), + ('\u{1cbd}', '\u{1cbf}'), ('ᴀ', 'á´«'), ('ᵫ', 'áµ·'), ('áµ¹', 'ᶚ'), + ('Ḁ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), + ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), + ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), + ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), + ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('ℂ', 'ℂ'), + ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), + ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), + ('ℯ', 'ℴ'), ('ℹ', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ↄ', 'ↄ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'â±»'), ('â±¾', 'ⳤ'), ('Ⳬ', 'â³®'), ('â³²', 'â³³'), + ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), ('Ꙁ', 'ꙭ'), + ('Ꚁ', 'ꚛ'), ('Ꜣ', 'ꝯ'), ('ꝱ', 'ꞇ'), ('Ꞌ', 'ꞎ'), + ('Ꞑ', '\u{a7b9}'), ('ꟺ', 'ꟺ'), ('ꬰ', 'ꭚ'), ('ê­ ', 'ê­¥'), + ('ê­°', 'ꮿ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('A', 'Z'), + ('a', 'z'), ('𐐀', '𐑏'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𑢠', '𑣟'), + ('\u{16e40}', '\u{16e7f}'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), ('𝛜', '𝛺'), + ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), ('𝝐', '𝝮'), + ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), ('𝟄', '𝟋'), + ('𞤀', '𞥃'), +]; + +pub const CLOSE_PUNCTUATION: &'static [(char, char)] = &[ + (')', ')'), (']', ']'), ('}', '}'), ('༻', '༻'), ('༽', '༽'), + ('᚜', '᚜'), ('⁆', '⁆'), ('⁾', '⁾'), ('₎', '₎'), + ('⌉', '⌉'), ('⌋', '⌋'), ('〉', '〉'), ('❩', '❩'), + ('❫', '❫'), ('❭', '❭'), ('❯', '❯'), ('❱', '❱'), + ('❳', '❳'), ('❵', '❵'), ('⟆', '⟆'), ('⟧', '⟧'), + ('⟩', '⟩'), ('⟫', '⟫'), ('⟭', '⟭'), ('⟯', '⟯'), + ('⦄', '⦄'), ('⦆', '⦆'), ('⦈', '⦈'), ('⦊', '⦊'), + ('⦌', '⦌'), ('⦎', '⦎'), ('⦐', '⦐'), ('⦒', '⦒'), + ('⦔', '⦔'), ('⦖', '⦖'), ('⦘', '⦘'), ('⧙', '⧙'), + ('⧛', '⧛'), ('â§½', 'â§½'), ('⸣', '⸣'), ('⸥', '⸥'), + ('⸧', '⸧'), ('⸩', '⸩'), ('〉', '〉'), ('》', '》'), + ('」', '」'), ('』', '』'), ('】', '】'), ('〕', '〕'), + ('〗', '〗'), ('〙', '〙'), ('〛', '〛'), ('〞', '〟'), + ('ï´¾', 'ï´¾'), ('︘', '︘'), ('︶', '︶'), ('︸', '︸'), + ('︺', '︺'), ('︼', '︼'), ('︾', '︾'), ('﹀', '﹀'), + ('﹂', '﹂'), ('﹄', '﹄'), ('﹈', '﹈'), ('﹚', '﹚'), + ('﹜', '﹜'), ('﹞', '﹞'), (')', ')'), ('ï¼½', 'ï¼½'), + ('}', '}'), ('ï½ ', 'ï½ '), ('ï½£', 'ï½£'), +]; + +pub const CONNECTOR_PUNCTUATION: &'static [(char, char)] = &[ + ('_', '_'), ('‿', '⁀'), ('⁔', '⁔'), ('︳', '︴'), ('﹍', '﹏'), + ('_', '_'), +]; + +pub const CONTROL: &'static [(char, char)] = &[ + ('\u{0}', '\u{1f}'), ('\u{7f}', '\u{9f}'), +]; + +pub const CURRENCY_SYMBOL: &'static [(char, char)] = &[ + ('$', '$'), ('¢', 'Â¥'), ('֏', '֏'), ('؋', '؋'), + ('\u{7fe}', '\u{7ff}'), ('à§²', 'à§³'), ('à§»', 'à§»'), ('૱', '૱'), + ('௹', '௹'), ('฿', '฿'), ('៛', '៛'), ('₠', '₿'), + ('ê ¸', 'ê ¸'), ('ï·¼', 'ï·¼'), ('﹩', '﹩'), ('$', '$'), + ('ï¿ ', 'ï¿¡'), ('ï¿¥', '₩'), ('\u{1ecb0}', '\u{1ecb0}'), +]; + +pub const DASH_PUNCTUATION: &'static [(char, char)] = &[ + ('-', '-'), ('֊', '֊'), ('Ö¾', 'Ö¾'), ('᐀', '᐀'), ('᠆', '᠆'), + ('‐', '―'), ('⸗', '⸗'), ('⸚', '⸚'), ('⸺', '⸻'), + ('⹀', '⹀'), ('〜', '〜'), ('〰', '〰'), ('゠', '゠'), + ('︱', '︲'), ('﹘', '﹘'), ('ï¹£', 'ï¹£'), ('-', '-'), +]; + +pub const DECIMAL_NUMBER: &'static [(char, char)] = &[ + ('0', '9'), ('Ù ', 'Ù©'), ('Û°', 'Û¹'), ('߀', '߉'), ('०', '९'), + ('০', '৯'), ('੦', '੯'), ('૦', '૯'), ('à­¦', 'à­¯'), + ('௦', '௯'), ('౦', '౯'), ('೦', '೯'), ('൦', '൯'), + ('à·¦', 'à·¯'), ('๐', '๙'), ('໐', '໙'), ('༠', '༩'), + ('၀', '၉'), ('႐', '႙'), ('០', '៩'), ('᠐', '᠙'), + ('᥆', '᥏'), ('᧐', '᧙'), ('᪀', '᪉'), ('᪐', '᪙'), + ('᭐', '᭙'), ('á®°', '᮹'), ('᱀', '᱉'), ('᱐', '᱙'), + ('꘠', '꘩'), ('꣐', '꣙'), ('꤀', '꤉'), ('꧐', '꧙'), + ('ê§°', 'ê§¹'), ('꩐', '꩙'), ('꯰', '꯹'), ('0', '9'), + ('𐒠', '𐒩'), ('\u{10d30}', '\u{10d39}'), ('𑁦', '𑁯'), + ('𑃰', '𑃹'), ('𑄶', '𑄿'), ('𑇐', '𑇙'), ('𑋰', '𑋹'), + ('𑑐', '𑑙'), ('𑓐', '𑓙'), ('𑙐', '𑙙'), ('𑛀', '𑛉'), + ('𑜰', '𑜹'), ('𑣠', '𑣩'), ('𑱐', '𑱙'), ('𑵐', '𑵙'), + ('\u{11da0}', '\u{11da9}'), ('𖩠', '𖩩'), ('𖭐', '𖭙'), + ('𝟎', '𝟿'), ('𞥐', '𞥙'), +]; + +pub const ENCLOSING_MARK: &'static [(char, char)] = &[ + ('҈', '҉'), ('᪾', '᪾'), ('⃝', '⃠'), ('⃢', '⃤'), + ('꙰', '꙲'), +]; + +pub const FINAL_PUNCTUATION: &'static [(char, char)] = &[ + ('»', '»'), ('’', '’'), ('”', '”'), ('›', '›'), + ('⸃', '⸃'), ('⸅', '⸅'), ('⸊', '⸊'), ('⸍', '⸍'), + ('⸝', '⸝'), ('⸡', '⸡'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), ('\u{600}', '\u{605}'), ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), ('\u{70f}', '\u{70f}'), ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), ('\u{200b}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), ('\u{feff}', '\u{feff}'), + ('\u{fff9}', '\u{fffb}'), ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const INITIAL_PUNCTUATION: &'static [(char, char)] = &[ + ('«', '«'), ('‘', '‘'), ('‛', '“'), ('‟', '‟'), + ('‹', '‹'), ('⸂', '⸂'), ('⸄', '⸄'), ('⸉', '⸉'), + ('⸌', '⸌'), ('⸜', '⸜'), ('⸠', '⸠'), +]; + +pub const LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('Ͱ', 'Í´'), ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), + ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), + ('\u{560}', '\u{588}'), ('א', 'ת'), ('\u{5ef}', 'ײ'), ('Ø ', 'ي'), + ('Ù®', 'Ù¯'), ('Ù±', 'ۓ'), ('ە', 'ە'), ('Û¥', 'Û¦'), ('Û®', 'Û¯'), + ('Ûº', 'Û¼'), ('Û¿', 'Û¿'), ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), + ('Þ±', 'Þ±'), ('ߊ', 'ߪ'), ('ß´', 'ßµ'), ('ߺ', 'ߺ'), ('ࠀ', 'ࠕ'), + ('ࠚ', 'ࠚ'), ('à ¤', 'à ¤'), ('à ¨', 'à ¨'), ('ࡀ', 'ࡘ'), + ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), + ('ऽ', 'ऽ'), ('ॐ', 'ॐ'), ('क़', 'ॡ'), ('ॱ', 'ঀ'), + ('অ', 'ঌ'), ('এ', 'ঐ'), ('ও', 'ন'), ('প', 'র'), + ('ল', 'ল'), ('শ', 'হ'), ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), + ('ড়', 'ঢ়'), ('য়', 'à§¡'), ('à§°', 'à§±'), ('à§¼', 'à§¼'), + ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), + ('ਫ਼', 'ਫ਼'), ('ੲ', 'à©´'), ('અ', 'ઍ'), ('એ', 'ઑ'), + ('ઓ', 'ન'), ('પ', 'ર'), ('લ', 'ળ'), ('વ', 'હ'), + ('ઽ', 'ઽ'), ('ૐ', 'ૐ'), ('à« ', 'à«¡'), ('ૹ', 'ૹ'), + ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), + ('ଲ', 'ଳ'), ('ଵ', 'ହ'), ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), + ('ୟ', 'à­¡'), ('à­±', 'à­±'), ('ஃ', 'ஃ'), ('அ', 'ஊ'), + ('எ', 'ஐ'), ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), + ('ஞ', 'ட'), ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), + ('ௐ', 'ௐ'), ('అ', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), + ('à°ª', 'à°¹'), ('à°½', 'à°½'), ('ౘ', 'ౚ'), ('à± ', 'ౡ'), + ('ಀ', 'ಀ'), ('ಅ', 'ಌ'), ('ಎ', 'ಐ'), ('ಒ', 'ನ'), + ('ಪ', 'ಳ'), ('ವ', 'ಹ'), ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), + ('à³ ', 'ೡ'), ('à³±', 'à³²'), ('അ', 'ഌ'), ('എ', 'ഐ'), + ('ഒ', 'à´º'), ('à´½', 'à´½'), ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), + ('ൟ', 'ൡ'), ('ൺ', 'ൿ'), ('අ', 'ඖ'), ('ක', 'à¶±'), + ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('ก', 'ะ'), + ('า', 'ำ'), ('เ', 'ๆ'), ('ກ', 'ຂ'), ('ຄ', 'ຄ'), + ('ງ', 'ຈ'), ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), ('ດ', 'ທ'), + ('ນ', 'ຟ'), ('ມ', 'ຣ'), ('ລ', 'ລ'), ('ວ', 'ວ'), + ('ສ', 'ຫ'), ('ອ', 'ະ'), ('າ', 'ຳ'), ('ຽ', 'ຽ'), + ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), + ('ཀ', 'ཇ'), ('ཉ', 'ཬ'), ('ྈ', 'ྌ'), ('က', 'ဪ'), + ('ဿ', 'ဿ'), ('ၐ', 'ၕ'), ('ၚ', 'ၝ'), ('ၡ', 'ၡ'), + ('ၥ', 'ၦ'), ('ၮ', 'ၰ'), ('ၵ', 'ႁ'), ('ႎ', 'ႎ'), + ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), + ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), + ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), + ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), + ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛱ', 'ᛸ'), + ('ᜀ', 'ᜌ'), ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), ('ᝀ', 'ᝑ'), + ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), ('á  ', '\u{1878}'), ('ᢀ', 'ᢄ'), ('ᢇ', 'ᢨ'), + ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), ('ᤀ', 'ᤞ'), ('ᥐ', 'ᥭ'), + ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('ᨀ', 'ᨖ'), + ('ᨠ', 'ᩔ'), ('ᪧ', 'ᪧ'), ('ᬅ', 'ᬳ'), ('ᭅ', 'ᭋ'), + ('ᮃ', 'á® '), ('á®®', 'ᮯ'), ('ᮺ', 'ᯥ'), ('ᰀ', 'á°£'), + ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), ('ᲀ', 'ᲈ'), ('\u{1c90}', '\u{1cba}'), + ('\u{1cbd}', '\u{1cbf}'), ('ᳩ', 'ᳬ'), ('á³®', 'á³±'), ('á³µ', 'á³¶'), + ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), + ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), + ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), + ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), + ('ℯ', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), ('ⅎ', 'ⅎ'), + ('Ↄ', 'ↄ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('â± ', 'ⳤ'), + ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), + ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), ('ⶀ', 'ⶖ'), + ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), + ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), + ('ⸯ', 'ⸯ'), ('々', '〆'), ('〱', '〵'), ('〻', '〼'), + ('ぁ', 'ゖ'), ('ゝ', 'ゟ'), ('ァ', 'ヺ'), ('ー', 'ヿ'), + ('ㄅ', '\u{312f}'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), ('ㇰ', 'ㇿ'), + ('㐀', 'ä¶µ'), ('一', '\u{9fef}'), ('ꀀ', 'ꒌ'), ('ꓐ', 'ꓽ'), + ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), ('Ꙁ', 'ꙮ'), + ('ꙿ', 'ꚝ'), ('ꚠ', 'ꛥ'), ('ꜗ', 'ꜟ'), ('Ꜣ', 'ꞈ'), + ('Ꞌ', '\u{a7b9}'), ('ꟷ', 'ꠁ'), ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), + ('ꠌ', 'ê ¢'), ('ꡀ', 'ꡳ'), ('ꢂ', 'ꢳ'), ('ꣲ', 'ꣷ'), + ('ꣻ', 'ꣻ'), ('ꣽ', '\u{a8fe}'), ('ꤊ', 'ꤥ'), ('ꤰ', 'ꥆ'), + ('ꥠ', 'ꥼ'), ('ꦄ', 'ꦲ'), ('ꧏ', 'ꧏ'), ('ê§ ', 'ꧤ'), + ('ꧦ', 'ꧯ'), ('ꧺ', 'ê§¾'), ('ꨀ', 'ꨨ'), ('ꩀ', 'ꩂ'), + ('ꩄ', 'ꩋ'), ('ê© ', 'ê©¶'), ('ꩺ', 'ꩺ'), ('ꩾ', 'ꪯ'), + ('ꪱ', 'ꪱ'), ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪽ'), ('ꫀ', 'ꫀ'), + ('ꫂ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫪ'), ('ꫲ', 'ê«´'), + ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), ('ê­°', 'ꯢ'), + ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), + ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('יִ', 'יִ'), + ('ײַ', 'ﬨ'), ('שׁ', 'זּ'), ('טּ', 'לּ'), ('מּ', 'מּ'), + ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), + ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), ('ï¹°', 'ï¹´'), + ('ï¹¶', 'ﻼ'), ('A', 'Z'), ('a', 'z'), ('ヲ', 'ï¾¾'), + ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), + ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), + ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐊀', '𐊜'), + ('𐊠', '𐋐'), ('𐌀', '𐌟'), ('𐌭', '𐍀'), ('𐍂', '𐍉'), + ('𐍐', '𐍵'), ('𐎀', '𐎝'), ('𐎠', '𐏃'), ('𐏈', '𐏏'), + ('𐐀', '𐒝'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '𐨀'), ('𐨐', '𐨓'), + ('𐨕', '𐨗'), ('𐨙', '\u{10a35}'), ('𐩠', '𐩼'), ('𐪀', '𐪜'), + ('𐫀', '𐫇'), ('𐫉', '𐫤'), ('𐬀', '𐬵'), ('𐭀', '𐭕'), + ('𐭠', '𐭲'), ('𐮀', '𐮑'), ('𐰀', '𐱈'), ('𐲀', '𐲲'), + ('𐳀', '𐳲'), ('\u{10d00}', '\u{10d23}'), ('\u{10f00}', '\u{10f1c}'), + ('\u{10f27}', '\u{10f27}'), ('\u{10f30}', '\u{10f45}'), ('𑀃', '𑀷'), + ('𑂃', '𑂯'), ('𑃐', '𑃨'), ('𑄃', '𑄦'), + ('\u{11144}', '\u{11144}'), ('𑅐', '𑅲'), ('𑅶', '𑅶'), + ('𑆃', '𑆲'), ('𑇁', '𑇄'), ('𑇚', '𑇚'), ('𑇜', '𑇜'), + ('𑈀', '𑈑'), ('𑈓', '𑈫'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), + ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), ('𑊰', '𑋞'), + ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), ('𑌪', '𑌰'), + ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('𑌽', '𑌽'), ('𑍐', '𑍐'), + ('𑍝', '𑍡'), ('𑐀', '𑐴'), ('𑑇', '𑑊'), ('𑒀', '𑒯'), + ('𑓄', '𑓅'), ('𑓇', '𑓇'), ('𑖀', '𑖮'), ('𑗘', '𑗛'), + ('𑘀', '𑘯'), ('𑙄', '𑙄'), ('𑚀', '𑚪'), ('𑜀', '\u{1171a}'), + ('\u{11800}', '\u{1182b}'), ('𑢠', '𑣟'), ('𑣿', '𑣿'), + ('𑨀', '𑨀'), ('𑨋', '𑨲'), ('𑨺', '𑨺'), ('𑩐', '𑩐'), + ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('\u{11a9d}', '\u{11a9d}'), + ('𑫀', '𑫸'), ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), + ('𑱲', '𑲏'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), + ('𑵆', '𑵆'), ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d89}'), ('\u{11d98}', '\u{11d98}'), + ('\u{11ee0}', '\u{11ef2}'), ('𒀀', '𒎙'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭀', '𖭃'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('\u{16e40}', '\u{16e7f}'), ('𖼀', '𖽄'), + ('𖽐', '𖽐'), ('𖾓', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '\u{187f1}'), + ('𘠀', '𘫲'), ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), + ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𝐀', '𝑔'), + ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), + ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), + ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), + ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), + ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), + ('𝟄', '𝟋'), ('𞠀', '𞣄'), ('𞤀', '𞥃'), ('𞸀', '𞸃'), + ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), + ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), + ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), + ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), + ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), + ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), + ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), + ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), + ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const LETTER_NUMBER: &'static [(char, char)] = &[ + ('ᛮ', 'ᛰ'), ('Ⅰ', 'ↂ'), ('ↅ', 'ↈ'), ('〇', '〇'), + ('〡', '〩'), ('〸', '〺'), ('ꛦ', 'ꛯ'), ('𐅀', '𐅴'), + ('𐍁', '𐍁'), ('𐍊', '𐍊'), ('𐏑', '𐏕'), ('𒐀', '𒑮'), +]; + +pub const LINE_SEPARATOR: &'static [(char, char)] = &[ + ('\u{2028}', '\u{2028}'), +]; + +pub const LOWERCASE_LETTER: &'static [(char, char)] = &[ + ('a', 'z'), ('µ', 'µ'), ('ß', 'ö'), ('ø', 'ÿ'), ('ā', 'ā'), + ('ă', 'ă'), ('ą', 'ą'), ('ć', 'ć'), ('ĉ', 'ĉ'), ('ċ', 'ċ'), + ('č', 'č'), ('ď', 'ď'), ('đ', 'đ'), ('ē', 'ē'), ('ĕ', 'ĕ'), + ('ė', 'ė'), ('ę', 'ę'), ('ě', 'ě'), ('ĝ', 'ĝ'), ('ğ', 'ğ'), + ('Ä¡', 'Ä¡'), ('Ä£', 'Ä£'), ('Ä¥', 'Ä¥'), ('ħ', 'ħ'), ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), ('Ä­', 'Ä­'), ('į', 'į'), ('ı', 'ı'), ('ij', 'ij'), + ('ĵ', 'ĵ'), ('Ä·', 'ĸ'), ('ĺ', 'ĺ'), ('ļ', 'ļ'), ('ľ', 'ľ'), + ('ŀ', 'ŀ'), ('ł', 'ł'), ('ń', 'ń'), ('ņ', 'ņ'), ('ň', 'ʼn'), + ('ŋ', 'ŋ'), ('ō', 'ō'), ('ŏ', 'ŏ'), ('ő', 'ő'), ('œ', 'œ'), + ('ŕ', 'ŕ'), ('ŗ', 'ŗ'), ('ř', 'ř'), ('ś', 'ś'), ('ŝ', 'ŝ'), + ('ş', 'ş'), ('Å¡', 'Å¡'), ('Å£', 'Å£'), ('Å¥', 'Å¥'), ('ŧ', 'ŧ'), + ('Å©', 'Å©'), ('Å«', 'Å«'), ('Å­', 'Å­'), ('ů', 'ů'), ('ű', 'ű'), + ('ų', 'ų'), ('ŵ', 'ŵ'), ('Å·', 'Å·'), ('ź', 'ź'), ('ż', 'ż'), + ('ž', 'ƀ'), ('ƃ', 'ƃ'), ('ƅ', 'ƅ'), ('ƈ', 'ƈ'), ('ƌ', 'ƍ'), + ('ƒ', 'ƒ'), ('ƕ', 'ƕ'), ('ƙ', 'ƛ'), ('ƞ', 'ƞ'), ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), ('Æ¥', 'Æ¥'), ('ƨ', 'ƨ'), ('ƪ', 'Æ«'), ('Æ­', 'Æ­'), + ('ư', 'ư'), ('Æ´', 'Æ´'), ('ƶ', 'ƶ'), ('ƹ', 'ƺ'), ('ƽ', 'Æ¿'), + ('dž', 'dž'), ('lj', 'lj'), ('nj', 'nj'), ('ǎ', 'ǎ'), ('ǐ', 'ǐ'), + ('ǒ', 'ǒ'), ('ǔ', 'ǔ'), ('ǖ', 'ǖ'), ('ǘ', 'ǘ'), ('ǚ', 'ǚ'), + ('ǜ', 'ǝ'), ('ǟ', 'ǟ'), ('Ç¡', 'Ç¡'), ('Ç£', 'Ç£'), ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), ('Ç©', 'Ç©'), ('Ç«', 'Ç«'), ('Ç­', 'Ç­'), ('ǯ', 'ǰ'), + ('dz', 'dz'), ('ǵ', 'ǵ'), ('ǹ', 'ǹ'), ('Ç»', 'Ç»'), ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), ('ȁ', 'ȁ'), ('ȃ', 'ȃ'), ('ȅ', 'ȅ'), ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), ('ȋ', 'ȋ'), ('ȍ', 'ȍ'), ('ȏ', 'ȏ'), ('ȑ', 'ȑ'), + ('ȓ', 'ȓ'), ('ȕ', 'ȕ'), ('ȗ', 'ȗ'), ('ș', 'ș'), ('ț', 'ț'), + ('ȝ', 'ȝ'), ('ȟ', 'ȟ'), ('È¡', 'È¡'), ('È£', 'È£'), ('È¥', 'È¥'), + ('ȧ', 'ȧ'), ('È©', 'È©'), ('È«', 'È«'), ('È­', 'È­'), ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), ('ȳ', 'ȹ'), ('ȼ', 'ȼ'), ('È¿', 'ɀ'), ('ɂ', 'ɂ'), + ('ɇ', 'ɇ'), ('ɉ', 'ɉ'), ('ɋ', 'ɋ'), ('ɍ', 'ɍ'), ('ɏ', 'ʓ'), + ('ʕ', 'ʯ'), ('ͱ', 'ͱ'), ('ͳ', 'ͳ'), ('Í·', 'Í·'), ('Í»', 'ͽ'), + ('ΐ', 'ΐ'), ('ά', 'ώ'), ('ϐ', 'ϑ'), ('ϕ', 'ϗ'), ('ϙ', 'ϙ'), + ('ϛ', 'ϛ'), ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), ('Ï¡', 'Ï¡'), ('Ï£', 'Ï£'), + ('Ï¥', 'Ï¥'), ('ϧ', 'ϧ'), ('Ï©', 'Ï©'), ('Ï«', 'Ï«'), ('Ï­', 'Ï­'), + ('ϯ', 'ϳ'), ('ϵ', 'ϵ'), ('ϸ', 'ϸ'), ('Ï»', 'ϼ'), ('а', 'џ'), + ('Ñ¡', 'Ñ¡'), ('Ñ£', 'Ñ£'), ('Ñ¥', 'Ñ¥'), ('ѧ', 'ѧ'), ('Ñ©', 'Ñ©'), + ('Ñ«', 'Ñ«'), ('Ñ­', 'Ñ­'), ('ѯ', 'ѯ'), ('ѱ', 'ѱ'), ('ѳ', 'ѳ'), + ('ѵ', 'ѵ'), ('Ñ·', 'Ñ·'), ('ѹ', 'ѹ'), ('Ñ»', 'Ñ»'), ('ѽ', 'ѽ'), + ('Ñ¿', 'Ñ¿'), ('ҁ', 'ҁ'), ('ҋ', 'ҋ'), ('ҍ', 'ҍ'), ('ҏ', 'ҏ'), + ('ґ', 'ґ'), ('ғ', 'ғ'), ('ҕ', 'ҕ'), ('җ', 'җ'), ('ҙ', 'ҙ'), + ('қ', 'қ'), ('ҝ', 'ҝ'), ('ҟ', 'ҟ'), ('Ò¡', 'Ò¡'), ('Ò£', 'Ò£'), + ('Ò¥', 'Ò¥'), ('Ò§', 'Ò§'), ('Ò©', 'Ò©'), ('Ò«', 'Ò«'), ('Ò­', 'Ò­'), + ('Ò¯', 'Ò¯'), ('Ò±', 'Ò±'), ('Ò³', 'Ò³'), ('Òµ', 'Òµ'), ('Ò·', 'Ò·'), + ('Ò¹', 'Ò¹'), ('Ò»', 'Ò»'), ('Ò½', 'Ò½'), ('Ò¿', 'Ò¿'), ('ӂ', 'ӂ'), + ('ӄ', 'ӄ'), ('ӆ', 'ӆ'), ('ӈ', 'ӈ'), ('ӊ', 'ӊ'), ('ӌ', 'ӌ'), + ('ӎ', 'ӏ'), ('ӑ', 'ӑ'), ('ӓ', 'ӓ'), ('ӕ', 'ӕ'), ('ӗ', 'ӗ'), + ('ә', 'ә'), ('ӛ', 'ӛ'), ('ӝ', 'ӝ'), ('ӟ', 'ӟ'), ('Ó¡', 'Ó¡'), + ('Ó£', 'Ó£'), ('Ó¥', 'Ó¥'), ('Ó§', 'Ó§'), ('Ó©', 'Ó©'), ('Ó«', 'Ó«'), + ('Ó­', 'Ó­'), ('Ó¯', 'Ó¯'), ('Ó±', 'Ó±'), ('Ó³', 'Ó³'), ('Óµ', 'Óµ'), + ('Ó·', 'Ó·'), ('Ó¹', 'Ó¹'), ('Ó»', 'Ó»'), ('Ó½', 'Ó½'), ('Ó¿', 'Ó¿'), + ('ԁ', 'ԁ'), ('ԃ', 'ԃ'), ('ԅ', 'ԅ'), ('ԇ', 'ԇ'), ('ԉ', 'ԉ'), + ('ԋ', 'ԋ'), ('ԍ', 'ԍ'), ('ԏ', 'ԏ'), ('ԑ', 'ԑ'), ('ԓ', 'ԓ'), + ('ԕ', 'ԕ'), ('ԗ', 'ԗ'), ('ԙ', 'ԙ'), ('ԛ', 'ԛ'), ('ԝ', 'ԝ'), + ('ԟ', 'ԟ'), ('Ô¡', 'Ô¡'), ('Ô£', 'Ô£'), ('Ô¥', 'Ô¥'), ('Ô§', 'Ô§'), + ('Ô©', 'Ô©'), ('Ô«', 'Ô«'), ('Ô­', 'Ô­'), ('Ô¯', 'Ô¯'), + ('\u{560}', '\u{588}'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('ᏸ', 'ᏽ'), + ('ᲀ', 'ᲈ'), ('ᴀ', 'á´«'), ('ᵫ', 'áµ·'), ('áµ¹', 'ᶚ'), + ('ḁ', 'ḁ'), ('ḃ', 'ḃ'), ('ḅ', 'ḅ'), ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), ('ḋ', 'ḋ'), ('ḍ', 'ḍ'), ('ḏ', 'ḏ'), + ('ḑ', 'ḑ'), ('ḓ', 'ḓ'), ('ḕ', 'ḕ'), ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), ('ḛ', 'ḛ'), ('ḝ', 'ḝ'), ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), ('ḣ', 'ḣ'), ('ḥ', 'ḥ'), ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), ('ḫ', 'ḫ'), ('ḭ', 'ḭ'), ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), ('ḳ', 'ḳ'), ('ḵ', 'ḵ'), ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), ('ḻ', 'ḻ'), ('ḽ', 'ḽ'), ('ḿ', 'ḿ'), + ('ṁ', 'ṁ'), ('ṃ', 'ṃ'), ('ṅ', 'ṅ'), ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), ('ṋ', 'ṋ'), ('ṍ', 'ṍ'), ('ṏ', 'ṏ'), + ('ṑ', 'ṑ'), ('ṓ', 'ṓ'), ('ṕ', 'ṕ'), ('ṗ', 'ṗ'), + ('ṙ', 'ṙ'), ('ṛ', 'ṛ'), ('ṝ', 'ṝ'), ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), ('á¹£', 'á¹£'), ('á¹¥', 'á¹¥'), ('á¹§', 'á¹§'), + ('ṩ', 'ṩ'), ('ṫ', 'ṫ'), ('á¹­', 'á¹­'), ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), ('á¹³', 'á¹³'), ('á¹µ', 'á¹µ'), ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), ('á¹»', 'á¹»'), ('á¹½', 'á¹½'), ('ṿ', 'ṿ'), + ('ẁ', 'ẁ'), ('ẃ', 'ẃ'), ('ẅ', 'ẅ'), ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), ('ẋ', 'ẋ'), ('ẍ', 'ẍ'), ('ẏ', 'ẏ'), + ('ẑ', 'ẑ'), ('ẓ', 'ẓ'), ('ẕ', 'ẝ'), ('ẟ', 'ẟ'), + ('ạ', 'ạ'), ('ả', 'ả'), ('ấ', 'ấ'), ('ầ', 'ầ'), + ('ẩ', 'ẩ'), ('ẫ', 'ẫ'), ('ậ', 'ậ'), ('ắ', 'ắ'), + ('ằ', 'ằ'), ('ẳ', 'ẳ'), ('ẵ', 'ẵ'), ('ặ', 'ặ'), + ('ẹ', 'ẹ'), ('ẻ', 'ẻ'), ('ẽ', 'ẽ'), ('ế', 'ế'), + ('ề', 'ề'), ('ể', 'ể'), ('ễ', 'ễ'), ('ệ', 'ệ'), + ('ỉ', 'ỉ'), ('ị', 'ị'), ('ọ', 'ọ'), ('ỏ', 'ỏ'), + ('ố', 'ố'), ('ồ', 'ồ'), ('ổ', 'ổ'), ('ỗ', 'ỗ'), + ('ộ', 'ộ'), ('ớ', 'ớ'), ('ờ', 'ờ'), ('ở', 'ở'), + ('ỡ', 'ỡ'), ('ợ', 'ợ'), ('ụ', 'ụ'), ('á»§', 'á»§'), + ('ứ', 'ứ'), ('ừ', 'ừ'), ('á»­', 'á»­'), ('ữ', 'ữ'), + ('á»±', 'á»±'), ('ỳ', 'ỳ'), ('ỵ', 'ỵ'), ('á»·', 'á»·'), + ('ỹ', 'ỹ'), ('á»»', 'á»»'), ('ỽ', 'ỽ'), ('ỿ', 'ἇ'), + ('ἐ', 'ἕ'), ('á¼ ', 'á¼§'), ('á¼°', 'á¼·'), ('ὀ', 'ὅ'), + ('ὐ', 'ὗ'), ('á½ ', 'á½§'), ('á½°', 'á½½'), ('ᾀ', 'ᾇ'), + ('ᾐ', 'ᾗ'), ('á¾ ', 'á¾§'), ('á¾°', 'á¾´'), ('á¾¶', 'á¾·'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῇ'), ('ῐ', 'ΐ'), + ('ῖ', 'ῗ'), ('á¿ ', 'á¿§'), ('ῲ', 'á¿´'), ('á¿¶', 'á¿·'), + ('ℊ', 'ℊ'), ('ℎ', 'ℏ'), ('ℓ', 'ℓ'), ('ℯ', 'ℯ'), + ('ℴ', 'ℴ'), ('ℹ', 'ℹ'), ('ℼ', 'ℽ'), ('ⅆ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('ↄ', 'ↄ'), ('â°°', 'ⱞ'), ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), ('ⱨ', 'ⱨ'), ('ⱪ', 'ⱪ'), ('ⱬ', 'ⱬ'), + ('â±±', 'â±±'), ('â±³', 'â±´'), ('â±¶', 'â±»'), ('ⲁ', 'ⲁ'), + ('ⲃ', 'ⲃ'), ('ⲅ', 'ⲅ'), ('ⲇ', 'ⲇ'), ('ⲉ', 'ⲉ'), + ('ⲋ', 'ⲋ'), ('ⲍ', 'ⲍ'), ('ⲏ', 'ⲏ'), ('ⲑ', 'ⲑ'), + ('ⲓ', 'ⲓ'), ('ⲕ', 'ⲕ'), ('ⲗ', 'ⲗ'), ('ⲙ', 'ⲙ'), + ('ⲛ', 'ⲛ'), ('ⲝ', 'ⲝ'), ('ⲟ', 'ⲟ'), ('ⲡ', 'ⲡ'), + ('â²£', 'â²£'), ('â²¥', 'â²¥'), ('â²§', 'â²§'), ('ⲩ', 'ⲩ'), + ('ⲫ', 'ⲫ'), ('â²­', 'â²­'), ('ⲯ', 'ⲯ'), ('â²±', 'â²±'), + ('â²³', 'â²³'), ('â²µ', 'â²µ'), ('â²·', 'â²·'), ('â²¹', 'â²¹'), + ('â²»', 'â²»'), ('â²½', 'â²½'), ('ⲿ', 'ⲿ'), ('ⳁ', 'ⳁ'), + ('ⳃ', 'ⳃ'), ('ⳅ', 'ⳅ'), ('ⳇ', 'ⳇ'), ('ⳉ', 'ⳉ'), + ('ⳋ', 'ⳋ'), ('ⳍ', 'ⳍ'), ('ⳏ', 'ⳏ'), ('ⳑ', 'ⳑ'), + ('ⳓ', 'ⳓ'), ('ⳕ', 'ⳕ'), ('ⳗ', 'ⳗ'), ('ⳙ', 'ⳙ'), + ('ⳛ', 'ⳛ'), ('ⳝ', 'ⳝ'), ('ⳟ', 'ⳟ'), ('ⳡ', 'ⳡ'), + ('â³£', 'ⳤ'), ('ⳬ', 'ⳬ'), ('â³®', 'â³®'), ('â³³', 'â³³'), + ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), ('ꙁ', 'ꙁ'), + ('ꙃ', 'ꙃ'), ('ꙅ', 'ꙅ'), ('ꙇ', 'ꙇ'), ('ꙉ', 'ꙉ'), + ('ꙋ', 'ꙋ'), ('ꙍ', 'ꙍ'), ('ꙏ', 'ꙏ'), ('ꙑ', 'ꙑ'), + ('ꙓ', 'ꙓ'), ('ꙕ', 'ꙕ'), ('ꙗ', 'ꙗ'), ('ꙙ', 'ꙙ'), + ('ꙛ', 'ꙛ'), ('ꙝ', 'ꙝ'), ('ꙟ', 'ꙟ'), ('ꙡ', 'ꙡ'), + ('ꙣ', 'ꙣ'), ('ꙥ', 'ꙥ'), ('ꙧ', 'ꙧ'), ('ꙩ', 'ꙩ'), + ('ꙫ', 'ꙫ'), ('ꙭ', 'ꙭ'), ('ꚁ', 'ꚁ'), ('ꚃ', 'ꚃ'), + ('ꚅ', 'ꚅ'), ('ꚇ', 'ꚇ'), ('ꚉ', 'ꚉ'), ('ꚋ', 'ꚋ'), + ('ꚍ', 'ꚍ'), ('ꚏ', 'ꚏ'), ('ꚑ', 'ꚑ'), ('ꚓ', 'ꚓ'), + ('ꚕ', 'ꚕ'), ('ꚗ', 'ꚗ'), ('ꚙ', 'ꚙ'), ('ꚛ', 'ꚛ'), + ('ꜣ', 'ꜣ'), ('ꜥ', 'ꜥ'), ('ꜧ', 'ꜧ'), ('ꜩ', 'ꜩ'), + ('ꜫ', 'ꜫ'), ('ꜭ', 'ꜭ'), ('ꜯ', 'ꜱ'), ('ꜳ', 'ꜳ'), + ('ꜵ', 'ꜵ'), ('ꜷ', 'ꜷ'), ('ꜹ', 'ꜹ'), ('ꜻ', 'ꜻ'), + ('ꜽ', 'ꜽ'), ('ꜿ', 'ꜿ'), ('ꝁ', 'ꝁ'), ('ꝃ', 'ꝃ'), + ('ꝅ', 'ꝅ'), ('ꝇ', 'ꝇ'), ('ꝉ', 'ꝉ'), ('ꝋ', 'ꝋ'), + ('ꝍ', 'ꝍ'), ('ꝏ', 'ꝏ'), ('ꝑ', 'ꝑ'), ('ꝓ', 'ꝓ'), + ('ꝕ', 'ꝕ'), ('ꝗ', 'ꝗ'), ('ꝙ', 'ꝙ'), ('ꝛ', 'ꝛ'), + ('ꝝ', 'ꝝ'), ('ꝟ', 'ꝟ'), ('ꝡ', 'ꝡ'), ('ꝣ', 'ꝣ'), + ('ꝥ', 'ꝥ'), ('ꝧ', 'ꝧ'), ('ꝩ', 'ꝩ'), ('ꝫ', 'ꝫ'), + ('ꝭ', 'ꝭ'), ('ꝯ', 'ꝯ'), ('ꝱ', 'ꝸ'), ('ꝺ', 'ꝺ'), + ('ꝼ', 'ꝼ'), ('ꝿ', 'ꝿ'), ('ꞁ', 'ꞁ'), ('ꞃ', 'ꞃ'), + ('ꞅ', 'ꞅ'), ('ꞇ', 'ꞇ'), ('ꞌ', 'ꞌ'), ('ꞎ', 'ꞎ'), + ('ꞑ', 'ꞑ'), ('ꞓ', 'ꞕ'), ('ꞗ', 'ꞗ'), ('ꞙ', 'ꞙ'), + ('ꞛ', 'ꞛ'), ('ꞝ', 'ꞝ'), ('ꞟ', 'ꞟ'), ('ꞡ', 'ꞡ'), + ('ꞣ', 'ꞣ'), ('ꞥ', 'ꞥ'), ('ꞧ', 'ꞧ'), ('ꞩ', 'ꞩ'), + ('\u{a7af}', '\u{a7af}'), ('ꞵ', 'ꞵ'), ('ꞷ', 'ꞷ'), + ('\u{a7b9}', '\u{a7b9}'), ('ꟺ', 'ꟺ'), ('ꬰ', 'ꭚ'), ('ê­ ', 'ê­¥'), + ('ê­°', 'ꮿ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('a', 'z'), + ('𐐨', '𐑏'), ('𐓘', '𐓻'), ('𐳀', '𐳲'), ('𑣀', '𑣟'), + ('\u{16e60}', '\u{16e7f}'), ('𝐚', '𝐳'), ('𝑎', '𝑔'), + ('𝑖', '𝑧'), ('𝒂', '𝒛'), ('𝒶', '𝒹'), ('𝒻', '𝒻'), + ('𝒽', '𝓃'), ('𝓅', '𝓏'), ('𝓪', '𝔃'), ('𝔞', '𝔷'), + ('𝕒', '𝕫'), ('𝖆', '𝖟'), ('𝖺', '𝗓'), ('𝗮', '𝘇'), + ('𝘢', '𝘻'), ('𝙖', '𝙯'), ('𝚊', '𝚥'), ('𝛂', '𝛚'), + ('𝛜', '𝛡'), ('𝛼', '𝜔'), ('𝜖', '𝜛'), ('𝜶', '𝝎'), + ('𝝐', '𝝕'), ('𝝰', '𝞈'), ('𝞊', '𝞏'), ('𝞪', '𝟂'), + ('𝟄', '𝟉'), ('𝟋', '𝟋'), ('𞤢', '𞥃'), +]; + +pub const MARK: &'static [(char, char)] = &[ + ('̀', 'ͯ'), ('҃', '҉'), ('֑', 'Ö½'), ('Ö¿', 'Ö¿'), ('ׁ', 'ׂ'), + ('ׄ', 'ׅ'), ('ׇ', 'ׇ'), ('ؐ', 'ؚ'), ('ً', 'ٟ'), ('Ù°', 'Ù°'), + ('ۖ', 'ۜ'), ('۟', 'Û¤'), ('Û§', 'Û¨'), ('Ûª', 'Û­'), ('ܑ', 'ܑ'), + ('ܰ', '݊'), ('Þ¦', 'Þ°'), ('ß«', 'ß³'), ('\u{7fd}', '\u{7fd}'), + ('ࠖ', '࠙'), ('ࠛ', 'à £'), ('à ¥', 'à §'), ('à ©', 'à ­'), + ('࡙', '࡛'), ('\u{8d3}', '࣡'), ('ࣣ', 'ः'), ('ऺ', '़'), + ('ा', 'ॏ'), ('॑', 'ॗ'), ('ॢ', 'ॣ'), ('ঁ', 'ঃ'), + ('়', '়'), ('া', 'ৄ'), ('ে', 'ৈ'), ('ো', '্'), + ('ৗ', 'ৗ'), ('à§¢', 'à§£'), ('\u{9fe}', '\u{9fe}'), ('ਁ', 'ਃ'), + ('਼', '਼'), ('ਾ', 'ੂ'), ('ੇ', 'ੈ'), ('ੋ', '੍'), + ('ੑ', 'ੑ'), ('à©°', 'ੱ'), ('ੵ', 'ੵ'), ('ઁ', 'ઃ'), + ('઼', '઼'), ('ા', 'ૅ'), ('ે', 'ૉ'), ('ો', '્'), + ('à«¢', 'à«£'), ('ૺ', 'à«¿'), ('ଁ', 'ଃ'), ('଼', '଼'), + ('ା', 'ୄ'), ('େ', 'ୈ'), ('ୋ', '୍'), ('ୖ', 'ୗ'), + ('à­¢', 'à­£'), ('ஂ', 'ஂ'), ('ா', 'ூ'), ('ெ', 'ை'), + ('ொ', '்'), ('ௗ', 'ௗ'), ('ఀ', '\u{c04}'), ('à°¾', 'ౄ'), + ('ె', 'ై'), ('ొ', '్'), ('ౕ', 'ౖ'), ('à±¢', 'à±£'), + ('ಁ', 'ಃ'), ('಼', '಼'), ('ಾ', 'ೄ'), ('ೆ', 'ೈ'), + ('ೊ', '್'), ('ೕ', 'ೖ'), ('à³¢', 'à³£'), ('ഀ', 'ഃ'), + ('à´»', 'à´¼'), ('à´¾', 'ൄ'), ('െ', 'ൈ'), ('ൊ', '്'), + ('ൗ', 'ൗ'), ('ൢ', 'ൣ'), ('ං', 'ඃ'), ('්', '්'), + ('ා', 'ු'), ('ූ', 'ූ'), ('ෘ', 'ෟ'), ('à·²', 'à·³'), + ('ั', 'ั'), ('ิ', 'ฺ'), ('็', '๎'), ('ັ', 'ັ'), + ('ິ', 'ູ'), ('ົ', 'ຼ'), ('່', 'ໍ'), ('༘', '༙'), + ('༵', '༵'), ('༷', '༷'), ('༹', '༹'), ('༾', '༿'), + ('ཱ', '྄'), ('྆', '྇'), ('ྍ', 'ྗ'), ('ྙ', 'ྼ'), + ('࿆', '࿆'), ('ါ', 'ှ'), ('ၖ', 'ၙ'), ('ၞ', 'ၠ'), + ('ၢ', 'ၤ'), ('ၧ', 'ၭ'), ('ၱ', 'ၴ'), ('ႂ', 'ႍ'), + ('ႏ', 'ႏ'), ('ႚ', 'ႝ'), ('፝', '፟'), ('ᜒ', '᜔'), + ('ᜲ', '᜴'), ('ᝒ', 'ᝓ'), ('ᝲ', 'ᝳ'), ('឴', '៓'), + ('៝', '៝'), ('᠋', '᠍'), ('ᢅ', 'ᢆ'), ('ᢩ', 'ᢩ'), + ('ᤠ', 'ᤫ'), ('ᤰ', '᤻'), ('ᨗ', 'ᨛ'), ('ᩕ', 'ᩞ'), + ('á© ', '᩼'), ('á©¿', 'á©¿'), ('᪰', '᪾'), ('ᬀ', 'ᬄ'), + ('᬴', '᭄'), ('á­«', 'á­³'), ('ᮀ', 'ᮂ'), ('ᮡ', 'á®­'), + ('᯦', '᯳'), ('á°¤', 'á°·'), ('᳐', '᳒'), ('᳔', '᳨'), + ('á³­', 'á³­'), ('á³²', 'á³´'), ('á³·', 'á³¹'), ('᷀', 'á·¹'), + ('á·»', 'á·¿'), ('⃐', '⃰'), ('⳯', 'â³±'), ('⵿', '⵿'), + ('â· ', 'â·¿'), ('〪', '〯'), ('゙', '゚'), ('꙯', '꙲'), + ('ꙴ', '꙽'), ('ꚞ', 'ꚟ'), ('꛰', '꛱'), ('ꠂ', 'ꠂ'), + ('꠆', '꠆'), ('ꠋ', 'ꠋ'), ('ê £', 'ê §'), ('ꢀ', 'ꢁ'), + ('ꢴ', 'ꣅ'), ('꣠', '꣱'), ('\u{a8ff}', '\u{a8ff}'), ('ꤦ', '꤭'), + ('ꥇ', '꥓'), ('ꦀ', 'ꦃ'), ('꦳', '꧀'), ('ê§¥', 'ê§¥'), + ('ꨩ', 'ꨶ'), ('ꩃ', 'ꩃ'), ('ꩌ', 'ꩍ'), ('ê©»', 'ꩽ'), + ('ꪰ', 'ꪰ'), ('ꪲ', 'ꪴ'), ('ꪷ', 'ꪸ'), ('ꪾ', '꪿'), + ('꫁', '꫁'), ('ê««', 'ꫯ'), ('ꫵ', 'ê«¶'), ('ꯣ', 'ꯪ'), + ('꯬', '꯭'), ('ﬞ', 'ﬞ'), ('︀', '️'), ('︠', '︯'), + ('𐇽', '𐇽'), ('𐋠', '𐋠'), ('𐍶', '𐍺'), ('𐨁', '𐨃'), + ('𐨅', '𐨆'), ('𐨌', '𐨏'), ('𐨸', '𐨺'), ('𐨿', '𐨿'), + ('𐫥', '𐫦'), ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), + ('𑀀', '𑀂'), ('𑀸', '𑁆'), ('𑁿', '𑂂'), ('𑂰', '𑂺'), + ('𑄀', '𑄂'), ('𑄧', '𑄴'), ('\u{11145}', '\u{11146}'), + ('𑅳', '𑅳'), ('𑆀', '𑆂'), ('𑆳', '𑇀'), ('𑇉', '𑇌'), + ('𑈬', '𑈷'), ('𑈾', '𑈾'), ('𑋟', '𑋪'), ('𑌀', '𑌃'), + ('\u{1133b}', '𑌼'), ('𑌾', '𑍄'), ('𑍇', '𑍈'), ('𑍋', '𑍍'), + ('𑍗', '𑍗'), ('𑍢', '𑍣'), ('𑍦', '𑍬'), ('𑍰', '𑍴'), + ('𑐵', '𑑆'), ('\u{1145e}', '\u{1145e}'), ('𑒰', '𑓃'), + ('𑖯', '𑖵'), ('𑖸', '𑗀'), ('𑗜', '𑗝'), ('𑘰', '𑙀'), + ('𑚫', '𑚷'), ('𑜝', '𑜫'), ('\u{1182c}', '\u{1183a}'), + ('𑨁', '𑨊'), ('𑨳', '𑨹'), ('𑨻', '𑨾'), ('𑩇', '𑩇'), + ('𑩑', '𑩛'), ('𑪊', '𑪙'), ('𑰯', '𑰶'), ('𑰸', '𑰿'), + ('𑲒', '𑲧'), ('𑲩', '𑲶'), ('𑴱', '𑴶'), ('𑴺', '𑴺'), + ('𑴼', '𑴽'), ('𑴿', '𑵅'), ('𑵇', '𑵇'), + ('\u{11d8a}', '\u{11d8e}'), ('\u{11d90}', '\u{11d91}'), + ('\u{11d93}', '\u{11d97}'), ('\u{11ef3}', '\u{11ef6}'), ('𖫰', '𖫴'), + ('𖬰', '𖬶'), ('𖽑', '𖽾'), ('𖾏', '𖾒'), ('𛲝', '𛲞'), + ('𝅥', '𝅩'), ('𝅭', '𝅲'), ('𝅻', '𝆂'), ('𝆅', '𝆋'), + ('𝆪', '𝆭'), ('𝉂', '𝉄'), ('𝨀', '𝨶'), ('𝨻', '𝩬'), + ('𝩵', '𝩵'), ('𝪄', '𝪄'), ('𝪛', '𝪟'), ('𝪡', '𝪯'), + ('𞀀', '𞀆'), ('𞀈', '𞀘'), ('𞀛', '𞀡'), ('𞀣', '𞀤'), + ('𞀦', '𞀪'), ('𞣐', '𞣖'), ('𞥄', '𞥊'), ('󠄀', '󠇯'), +]; + +pub const MATH_SYMBOL: &'static [(char, char)] = &[ + ('+', '+'), ('<', '>'), ('|', '|'), ('~', '~'), ('¬', '¬'), ('±', '±'), + ('×', '×'), ('÷', '÷'), ('϶', '϶'), ('؆', '؈'), ('⁄', '⁄'), + ('⁒', '⁒'), ('⁺', '⁼'), ('₊', '₌'), ('℘', '℘'), + ('⅀', '⅄'), ('⅋', '⅋'), ('←', '↔'), ('↚', '↛'), + ('↠', '↠'), ('↣', '↣'), ('↦', '↦'), ('↮', '↮'), + ('⇎', '⇏'), ('⇒', '⇒'), ('⇔', '⇔'), ('⇴', '⋿'), + ('⌠', '⌡'), ('⍼', '⍼'), ('⎛', '⎳'), ('⏜', '⏡'), + ('▷', '▷'), ('◁', '◁'), ('◸', '◿'), ('♯', '♯'), + ('⟀', '⟄'), ('⟇', '⟥'), ('⟰', '⟿'), ('⤀', '⦂'), + ('⦙', '⧗'), ('⧜', 'â§»'), ('â§¾', 'â«¿'), ('⬰', '⭄'), + ('⭇', '⭌'), ('﬩', '﬩'), ('ï¹¢', 'ï¹¢'), ('﹤', '﹦'), + ('+', '+'), ('<', '>'), ('|', '|'), ('~', '~'), + ('ï¿¢', 'ï¿¢'), ('ï¿©', '↓'), ('𝛁', '𝛁'), ('𝛛', '𝛛'), + ('𝛻', '𝛻'), ('𝜕', '𝜕'), ('𝜵', '𝜵'), ('𝝏', '𝝏'), + ('𝝯', '𝝯'), ('𝞉', '𝞉'), ('𝞩', '𝞩'), ('𝟃', '𝟃'), + ('𞻰', '𞻱'), +]; + +pub const MODIFIER_LETTER: &'static [(char, char)] = &[ + ('ʰ', 'ˁ'), ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), + ('Í´', 'Í´'), ('ͺ', 'ͺ'), ('ՙ', 'ՙ'), ('ـ', 'ـ'), ('Û¥', 'Û¦'), + ('ß´', 'ßµ'), ('ߺ', 'ߺ'), ('ࠚ', 'ࠚ'), ('à ¤', 'à ¤'), ('à ¨', 'à ¨'), + ('ॱ', 'ॱ'), ('ๆ', 'ๆ'), ('ໆ', 'ໆ'), ('ჼ', 'ჼ'), + ('ៗ', 'ៗ'), ('ᡃ', 'ᡃ'), ('ᪧ', 'ᪧ'), ('ᱸ', 'á±½'), + ('á´¬', 'ᵪ'), ('ᵸ', 'ᵸ'), ('ᶛ', 'á¶¿'), ('ⁱ', 'ⁱ'), + ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('â±¼', 'â±½'), ('ⵯ', 'ⵯ'), + ('ⸯ', 'ⸯ'), ('々', '々'), ('〱', '〵'), ('〻', '〻'), + ('ゝ', 'ゞ'), ('ー', 'ヾ'), ('ꀕ', 'ꀕ'), ('ꓸ', 'ꓽ'), + ('ꘌ', 'ꘌ'), ('ꙿ', 'ꙿ'), ('ꚜ', 'ꚝ'), ('ꜗ', 'ꜟ'), + ('ꝰ', 'ꝰ'), ('ꞈ', 'ꞈ'), ('ꟸ', 'ꟹ'), ('ꧏ', 'ꧏ'), + ('ꧦ', 'ꧦ'), ('ê©°', 'ê©°'), ('ꫝ', 'ꫝ'), ('ꫳ', 'ê«´'), + ('ꭜ', 'ꭟ'), ('ï½°', 'ï½°'), ('゙', '゚'), ('𖭀', '𖭃'), + ('𖾓', '𖾟'), ('𖿠', '𖿡'), +]; + +pub const MODIFIER_SYMBOL: &'static [(char, char)] = &[ + ('^', '^'), ('`', '`'), ('¨', '¨'), ('¯', '¯'), ('´', '´'), + ('¸', '¸'), ('˂', '˅'), ('˒', '˟'), ('Ë¥', 'Ë«'), ('Ë­', 'Ë­'), + ('˯', 'Ë¿'), ('͵', '͵'), ('΄', '΅'), ('á¾½', 'á¾½'), ('᾿', '῁'), + ('῍', '῏'), ('῝', '῟'), ('á¿­', '`'), ('´', '῾'), + ('゛', '゜'), ('꜀', '꜖'), ('꜠', '꜡'), ('꞉', '꞊'), + ('꭛', '꭛'), ('﮲', '﯁'), ('ï¼¾', 'ï¼¾'), ('`', '`'), + ('ï¿£', 'ï¿£'), ('🏻', '🏿'), +]; + +pub const NONSPACING_MARK: &'static [(char, char)] = &[ + ('̀', 'ͯ'), ('҃', '҇'), ('֑', 'Ö½'), ('Ö¿', 'Ö¿'), ('ׁ', 'ׂ'), + ('ׄ', 'ׅ'), ('ׇ', 'ׇ'), ('ؐ', 'ؚ'), ('ً', 'ٟ'), ('Ù°', 'Ù°'), + ('ۖ', 'ۜ'), ('۟', 'Û¤'), ('Û§', 'Û¨'), ('Ûª', 'Û­'), ('ܑ', 'ܑ'), + ('ܰ', '݊'), ('Þ¦', 'Þ°'), ('ß«', 'ß³'), ('\u{7fd}', '\u{7fd}'), + ('ࠖ', '࠙'), ('ࠛ', 'à £'), ('à ¥', 'à §'), ('à ©', 'à ­'), + ('࡙', '࡛'), ('\u{8d3}', '࣡'), ('ࣣ', 'ं'), ('ऺ', 'ऺ'), + ('़', '़'), ('ु', 'ै'), ('्', '्'), ('॑', 'ॗ'), + ('ॢ', 'ॣ'), ('ঁ', 'ঁ'), ('়', '়'), ('ু', 'ৄ'), + ('্', '্'), ('à§¢', 'à§£'), ('\u{9fe}', '\u{9fe}'), ('ਁ', 'ਂ'), + ('਼', '਼'), ('ੁ', 'ੂ'), ('ੇ', 'ੈ'), ('ੋ', '੍'), + ('ੑ', 'ੑ'), ('à©°', 'ੱ'), ('ੵ', 'ੵ'), ('ઁ', 'ં'), + ('઼', '઼'), ('ુ', 'ૅ'), ('ે', 'ૈ'), ('્', '્'), + ('à«¢', 'à«£'), ('ૺ', 'à«¿'), ('ଁ', 'ଁ'), ('଼', '଼'), + ('ି', 'ି'), ('ୁ', 'ୄ'), ('୍', '୍'), ('ୖ', 'ୖ'), + ('à­¢', 'à­£'), ('ஂ', 'ஂ'), ('ீ', 'ீ'), ('்', '்'), + ('ఀ', 'ఀ'), ('\u{c04}', '\u{c04}'), ('à°¾', 'ీ'), ('ె', 'ై'), + ('ొ', '్'), ('ౕ', 'ౖ'), ('à±¢', 'à±£'), ('ಁ', 'ಁ'), + ('಼', '಼'), ('ಿ', 'ಿ'), ('ೆ', 'ೆ'), ('ೌ', '್'), + ('à³¢', 'à³£'), ('ഀ', 'ഁ'), ('à´»', 'à´¼'), ('ു', 'ൄ'), + ('്', '്'), ('ൢ', 'ൣ'), ('්', '්'), ('ි', 'ු'), + ('ූ', 'ූ'), ('ั', 'ั'), ('ิ', 'ฺ'), ('็', '๎'), + ('ັ', 'ັ'), ('ິ', 'ູ'), ('ົ', 'ຼ'), ('່', 'ໍ'), + ('༘', '༙'), ('༵', '༵'), ('༷', '༷'), ('༹', '༹'), + ('ཱ', 'ཾ'), ('ྀ', '྄'), ('྆', '྇'), ('ྍ', 'ྗ'), + ('ྙ', 'ྼ'), ('࿆', '࿆'), ('ိ', 'ူ'), ('ဲ', '့'), + ('္', '်'), ('ွ', 'ှ'), ('ၘ', 'ၙ'), ('ၞ', 'ၠ'), + ('ၱ', 'ၴ'), ('ႂ', 'ႂ'), ('ႅ', 'ႆ'), ('ႍ', 'ႍ'), + ('ႝ', 'ႝ'), ('፝', '፟'), ('ᜒ', '᜔'), ('ᜲ', '᜴'), + ('ᝒ', 'ᝓ'), ('ᝲ', 'ᝳ'), ('឴', '឵'), ('ិ', 'ួ'), + ('ំ', 'ំ'), ('៉', '៓'), ('៝', '៝'), ('᠋', '᠍'), + ('ᢅ', 'ᢆ'), ('ᢩ', 'ᢩ'), ('ᤠ', 'ᤢ'), ('ᤧ', 'ᤨ'), + ('ᤲ', 'ᤲ'), ('᤹', '᤻'), ('ᨗ', 'ᨘ'), ('ᨛ', 'ᨛ'), + ('ᩖ', 'ᩖ'), ('ᩘ', 'ᩞ'), ('á© ', 'á© '), ('á©¢', 'á©¢'), + ('á©¥', 'ᩬ'), ('ᩳ', '᩼'), ('á©¿', 'á©¿'), ('᪰', '᪽'), + ('ᬀ', 'ᬃ'), ('᬴', '᬴'), ('ᬶ', 'ᬺ'), ('ᬼ', 'ᬼ'), + ('ᭂ', 'ᭂ'), ('á­«', 'á­³'), ('ᮀ', 'ᮁ'), ('ᮢ', 'ᮥ'), + ('ᮨ', 'ᮩ'), ('᮫', 'á®­'), ('᯦', '᯦'), ('ᯨ', 'ᯩ'), + ('ᯭ', 'ᯭ'), ('ᯯ', 'ᯱ'), ('á°¬', 'á°³'), ('á°¶', 'á°·'), + ('᳐', '᳒'), ('᳔', 'á³ '), ('á³¢', '᳨'), ('á³­', 'á³­'), + ('á³´', 'á³´'), ('᳸', 'á³¹'), ('᷀', 'á·¹'), ('á·»', 'á·¿'), + ('⃐', '⃜'), ('⃡', '⃡'), ('⃥', '⃰'), ('⳯', 'â³±'), + ('⵿', '⵿'), ('â· ', 'â·¿'), ('〪', '〭'), ('゙', '゚'), + ('꙯', '꙯'), ('ꙴ', '꙽'), ('ꚞ', 'ꚟ'), ('꛰', '꛱'), + ('ꠂ', 'ꠂ'), ('꠆', '꠆'), ('ꠋ', 'ꠋ'), ('ê ¥', 'ê ¦'), + ('꣄', 'ꣅ'), ('꣠', '꣱'), ('\u{a8ff}', '\u{a8ff}'), ('ꤦ', '꤭'), + ('ꥇ', 'ꥑ'), ('ꦀ', 'ꦂ'), ('꦳', '꦳'), ('ꦶ', 'ꦹ'), + ('ꦼ', 'ꦼ'), ('ê§¥', 'ê§¥'), ('ꨩ', 'ꨮ'), ('ꨱ', 'ꨲ'), + ('ꨵ', 'ꨶ'), ('ꩃ', 'ꩃ'), ('ꩌ', 'ꩌ'), ('ꩼ', 'ꩼ'), + ('ꪰ', 'ꪰ'), ('ꪲ', 'ꪴ'), ('ꪷ', 'ꪸ'), ('ꪾ', '꪿'), + ('꫁', '꫁'), ('ꫬ', 'ê«­'), ('ê«¶', 'ê«¶'), ('ꯥ', 'ꯥ'), + ('ꯨ', 'ꯨ'), ('꯭', '꯭'), ('ﬞ', 'ﬞ'), ('︀', '️'), + ('︠', '︯'), ('𐇽', '𐇽'), ('𐋠', '𐋠'), ('𐍶', '𐍺'), + ('𐨁', '𐨃'), ('𐨅', '𐨆'), ('𐨌', '𐨏'), ('𐨸', '𐨺'), + ('𐨿', '𐨿'), ('𐫥', '𐫦'), ('\u{10d24}', '\u{10d27}'), + ('\u{10f46}', '\u{10f50}'), ('𑀁', '𑀁'), ('𑀸', '𑁆'), + ('𑁿', '𑂁'), ('𑂳', '𑂶'), ('𑂹', '𑂺'), ('𑄀', '𑄂'), + ('𑄧', '𑄫'), ('𑄭', '𑄴'), ('𑅳', '𑅳'), ('𑆀', '𑆁'), + ('𑆶', '𑆾'), ('𑇉', '𑇌'), ('𑈯', '𑈱'), ('𑈴', '𑈴'), + ('𑈶', '𑈷'), ('𑈾', '𑈾'), ('𑋟', '𑋟'), ('𑋣', '𑋪'), + ('𑌀', '𑌁'), ('\u{1133b}', '𑌼'), ('𑍀', '𑍀'), ('𑍦', '𑍬'), + ('𑍰', '𑍴'), ('𑐸', '𑐿'), ('𑑂', '𑑄'), ('𑑆', '𑑆'), + ('\u{1145e}', '\u{1145e}'), ('𑒳', '𑒸'), ('𑒺', '𑒺'), + ('𑒿', '𑓀'), ('𑓂', '𑓃'), ('𑖲', '𑖵'), ('𑖼', '𑖽'), + ('𑖿', '𑗀'), ('𑗜', '𑗝'), ('𑘳', '𑘺'), ('𑘽', '𑘽'), + ('𑘿', '𑙀'), ('𑚫', '𑚫'), ('𑚭', '𑚭'), ('𑚰', '𑚵'), + ('𑚷', '𑚷'), ('𑜝', '𑜟'), ('𑜢', '𑜥'), ('𑜧', '𑜫'), + ('\u{1182f}', '\u{11837}'), ('\u{11839}', '\u{1183a}'), ('𑨁', '𑨊'), + ('𑨳', '𑨸'), ('𑨻', '𑨾'), ('𑩇', '𑩇'), ('𑩑', '𑩖'), + ('𑩙', '𑩛'), ('𑪊', '𑪖'), ('𑪘', '𑪙'), ('𑰰', '𑰶'), + ('𑰸', '𑰽'), ('𑰿', '𑰿'), ('𑲒', '𑲧'), ('𑲪', '𑲰'), + ('𑲲', '𑲳'), ('𑲵', '𑲶'), ('𑴱', '𑴶'), ('𑴺', '𑴺'), + ('𑴼', '𑴽'), ('𑴿', '𑵅'), ('𑵇', '𑵇'), + ('\u{11d90}', '\u{11d91}'), ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), ('\u{11ef3}', '\u{11ef4}'), ('𖫰', '𖫴'), + ('𖬰', '𖬶'), ('𖾏', '𖾒'), ('𛲝', '𛲞'), ('𝅧', '𝅩'), + ('𝅻', '𝆂'), ('𝆅', '𝆋'), ('𝆪', '𝆭'), ('𝉂', '𝉄'), + ('𝨀', '𝨶'), ('𝨻', '𝩬'), ('𝩵', '𝩵'), ('𝪄', '𝪄'), + ('𝪛', '𝪟'), ('𝪡', '𝪯'), ('𞀀', '𞀆'), ('𞀈', '𞀘'), + ('𞀛', '𞀡'), ('𞀣', '𞀤'), ('𞀦', '𞀪'), ('𞣐', '𞣖'), + ('𞥄', '𞥊'), ('󠄀', '󠇯'), +]; + +pub const NUMBER: &'static [(char, char)] = &[ + ('0', '9'), ('²', '³'), ('¹', '¹'), ('¼', '¾'), ('Ù ', 'Ù©'), + ('Û°', 'Û¹'), ('߀', '߉'), ('०', '९'), ('০', '৯'), ('à§´', 'à§¹'), + ('੦', '੯'), ('૦', '૯'), ('à­¦', 'à­¯'), ('à­²', 'à­·'), + ('௦', '௲'), ('౦', '౯'), ('౸', 'à±¾'), ('೦', '೯'), + ('൘', '൞'), ('൦', '൸'), ('à·¦', 'à·¯'), ('๐', '๙'), + ('໐', '໙'), ('༠', '༳'), ('၀', '၉'), ('႐', '႙'), + ('፩', '፼'), ('ᛮ', 'ᛰ'), ('០', '៩'), ('៰', '៹'), + ('᠐', '᠙'), ('᥆', '᥏'), ('᧐', '᧚'), ('᪀', '᪉'), + ('᪐', '᪙'), ('᭐', '᭙'), ('á®°', '᮹'), ('᱀', '᱉'), + ('᱐', '᱙'), ('⁰', '⁰'), ('⁴', '⁹'), ('₀', '₉'), + ('⅐', 'ↂ'), ('ↅ', '↉'), ('①', '⒛'), ('⓪', '⓿'), + ('❶', '➓'), ('â³½', 'â³½'), ('〇', '〇'), ('〡', '〩'), + ('〸', '〺'), ('㆒', '㆕'), ('㈠', '㈩'), ('㉈', '㉏'), + ('㉑', '㉟'), ('㊀', '㊉'), ('㊱', '㊿'), ('꘠', '꘩'), + ('ꛦ', 'ꛯ'), ('ê °', 'ê µ'), ('꣐', '꣙'), ('꤀', '꤉'), + ('꧐', '꧙'), ('ê§°', 'ê§¹'), ('꩐', '꩙'), ('꯰', '꯹'), + ('0', '9'), ('𐄇', '𐄳'), ('𐅀', '𐅸'), ('𐆊', '𐆋'), + ('𐋡', '𐋻'), ('𐌠', '𐌣'), ('𐍁', '𐍁'), ('𐍊', '𐍊'), + ('𐏑', '𐏕'), ('𐒠', '𐒩'), ('𐡘', '𐡟'), ('𐡹', '𐡿'), + ('𐢧', '𐢯'), ('𐣻', '𐣿'), ('𐤖', '𐤛'), ('𐦼', '𐦽'), + ('𐧀', '𐧏'), ('𐧒', '𐧿'), ('𐩀', '\u{10a48}'), ('𐩽', '𐩾'), + ('𐪝', '𐪟'), ('𐫫', '𐫯'), ('𐭘', '𐭟'), ('𐭸', '𐭿'), + ('𐮩', '𐮯'), ('𐳺', '𐳿'), ('\u{10d30}', '\u{10d39}'), + ('𐹠', '𐹾'), ('\u{10f1d}', '\u{10f26}'), ('\u{10f51}', '\u{10f54}'), + ('𑁒', '𑁯'), ('𑃰', '𑃹'), ('𑄶', '𑄿'), ('𑇐', '𑇙'), + ('𑇡', '𑇴'), ('𑋰', '𑋹'), ('𑑐', '𑑙'), ('𑓐', '𑓙'), + ('𑙐', '𑙙'), ('𑛀', '𑛉'), ('𑜰', '𑜻'), ('𑣠', '𑣲'), + ('𑱐', '𑱬'), ('𑵐', '𑵙'), ('\u{11da0}', '\u{11da9}'), + ('𒐀', '𒑮'), ('𖩠', '𖩩'), ('𖭐', '𖭙'), ('𖭛', '𖭡'), + ('\u{16e80}', '\u{16e96}'), ('\u{1d2e0}', '\u{1d2f3}'), + ('𝍠', '\u{1d378}'), ('𝟎', '𝟿'), ('𞣇', '𞣏'), ('𞥐', '𞥙'), + ('\u{1ec71}', '\u{1ecab}'), ('\u{1ecad}', '\u{1ecaf}'), + ('\u{1ecb1}', '\u{1ecb4}'), ('🄀', '🄌'), +]; + +pub const OPEN_PUNCTUATION: &'static [(char, char)] = &[ + ('(', '('), ('[', '['), ('{', '{'), ('༺', '༺'), ('༼', '༼'), + ('᚛', '᚛'), ('‚', '‚'), ('„', '„'), ('⁅', '⁅'), + ('⁽', '⁽'), ('₍', '₍'), ('⌈', '⌈'), ('⌊', '⌊'), + ('〈', '〈'), ('❨', '❨'), ('❪', '❪'), ('❬', '❬'), + ('❮', '❮'), ('❰', '❰'), ('❲', '❲'), ('❴', '❴'), + ('⟅', '⟅'), ('⟦', '⟦'), ('⟨', '⟨'), ('⟪', '⟪'), + ('⟬', '⟬'), ('⟮', '⟮'), ('⦃', '⦃'), ('⦅', '⦅'), + ('⦇', '⦇'), ('⦉', '⦉'), ('⦋', '⦋'), ('⦍', '⦍'), + ('⦏', '⦏'), ('⦑', '⦑'), ('⦓', '⦓'), ('⦕', '⦕'), + ('⦗', '⦗'), ('⧘', '⧘'), ('⧚', '⧚'), ('â§¼', 'â§¼'), + ('⸢', '⸢'), ('⸤', '⸤'), ('⸦', '⸦'), ('⸨', '⸨'), + ('⹂', '⹂'), ('〈', '〈'), ('《', '《'), ('「', '「'), + ('『', '『'), ('【', '【'), ('〔', '〔'), ('〖', '〖'), + ('〘', '〘'), ('〚', '〚'), ('〝', '〝'), ('ï´¿', 'ï´¿'), + ('︗', '︗'), ('︵', '︵'), ('︷', '︷'), ('︹', '︹'), + ('︻', '︻'), ('︽', '︽'), ('︿', '︿'), ('﹁', '﹁'), + ('﹃', '﹃'), ('﹇', '﹇'), ('﹙', '﹙'), ('﹛', '﹛'), + ('﹝', '﹝'), ('(', '('), ('ï¼»', 'ï¼»'), ('{', '{'), + ('⦅', '⦅'), ('ï½¢', 'ï½¢'), +]; + +pub const OTHER: &'static [(char, char)] = &[ + ('\u{0}', '\u{1f}'), ('\u{7f}', '\u{9f}'), ('\u{ad}', '\u{ad}'), + ('\u{378}', '\u{379}'), ('\u{380}', '\u{383}'), ('\u{38b}', '\u{38b}'), + ('\u{38d}', '\u{38d}'), ('\u{3a2}', '\u{3a2}'), ('\u{530}', '\u{530}'), + ('\u{557}', '\u{558}'), ('\u{58b}', '\u{58c}'), ('\u{590}', '\u{590}'), + ('\u{5c8}', '\u{5cf}'), ('\u{5eb}', '\u{5ee}'), ('\u{5f5}', '\u{605}'), + ('\u{61c}', '\u{61d}'), ('\u{6dd}', '\u{6dd}'), ('\u{70e}', '\u{70f}'), + ('\u{74b}', '\u{74c}'), ('\u{7b2}', '\u{7bf}'), ('\u{7fb}', '\u{7fc}'), + ('\u{82e}', '\u{82f}'), ('\u{83f}', '\u{83f}'), ('\u{85c}', '\u{85d}'), + ('\u{85f}', '\u{85f}'), ('\u{86b}', '\u{89f}'), ('\u{8b5}', '\u{8b5}'), + ('\u{8be}', '\u{8d2}'), ('\u{8e2}', '\u{8e2}'), ('\u{984}', '\u{984}'), + ('\u{98d}', '\u{98e}'), ('\u{991}', '\u{992}'), ('\u{9a9}', '\u{9a9}'), + ('\u{9b1}', '\u{9b1}'), ('\u{9b3}', '\u{9b5}'), ('\u{9ba}', '\u{9bb}'), + ('\u{9c5}', '\u{9c6}'), ('\u{9c9}', '\u{9ca}'), ('\u{9cf}', '\u{9d6}'), + ('\u{9d8}', '\u{9db}'), ('\u{9de}', '\u{9de}'), ('\u{9e4}', '\u{9e5}'), + ('\u{9ff}', '\u{a00}'), ('\u{a04}', '\u{a04}'), ('\u{a0b}', '\u{a0e}'), + ('\u{a11}', '\u{a12}'), ('\u{a29}', '\u{a29}'), ('\u{a31}', '\u{a31}'), + ('\u{a34}', '\u{a34}'), ('\u{a37}', '\u{a37}'), ('\u{a3a}', '\u{a3b}'), + ('\u{a3d}', '\u{a3d}'), ('\u{a43}', '\u{a46}'), ('\u{a49}', '\u{a4a}'), + ('\u{a4e}', '\u{a50}'), ('\u{a52}', '\u{a58}'), ('\u{a5d}', '\u{a5d}'), + ('\u{a5f}', '\u{a65}'), ('\u{a77}', '\u{a80}'), ('\u{a84}', '\u{a84}'), + ('\u{a8e}', '\u{a8e}'), ('\u{a92}', '\u{a92}'), ('\u{aa9}', '\u{aa9}'), + ('\u{ab1}', '\u{ab1}'), ('\u{ab4}', '\u{ab4}'), ('\u{aba}', '\u{abb}'), + ('\u{ac6}', '\u{ac6}'), ('\u{aca}', '\u{aca}'), ('\u{ace}', '\u{acf}'), + ('\u{ad1}', '\u{adf}'), ('\u{ae4}', '\u{ae5}'), ('\u{af2}', '\u{af8}'), + ('\u{b00}', '\u{b00}'), ('\u{b04}', '\u{b04}'), ('\u{b0d}', '\u{b0e}'), + ('\u{b11}', '\u{b12}'), ('\u{b29}', '\u{b29}'), ('\u{b31}', '\u{b31}'), + ('\u{b34}', '\u{b34}'), ('\u{b3a}', '\u{b3b}'), ('\u{b45}', '\u{b46}'), + ('\u{b49}', '\u{b4a}'), ('\u{b4e}', '\u{b55}'), ('\u{b58}', '\u{b5b}'), + ('\u{b5e}', '\u{b5e}'), ('\u{b64}', '\u{b65}'), ('\u{b78}', '\u{b81}'), + ('\u{b84}', '\u{b84}'), ('\u{b8b}', '\u{b8d}'), ('\u{b91}', '\u{b91}'), + ('\u{b96}', '\u{b98}'), ('\u{b9b}', '\u{b9b}'), ('\u{b9d}', '\u{b9d}'), + ('\u{ba0}', '\u{ba2}'), ('\u{ba5}', '\u{ba7}'), ('\u{bab}', '\u{bad}'), + ('\u{bba}', '\u{bbd}'), ('\u{bc3}', '\u{bc5}'), ('\u{bc9}', '\u{bc9}'), + ('\u{bce}', '\u{bcf}'), ('\u{bd1}', '\u{bd6}'), ('\u{bd8}', '\u{be5}'), + ('\u{bfb}', '\u{bff}'), ('\u{c0d}', '\u{c0d}'), ('\u{c11}', '\u{c11}'), + ('\u{c29}', '\u{c29}'), ('\u{c3a}', '\u{c3c}'), ('\u{c45}', '\u{c45}'), + ('\u{c49}', '\u{c49}'), ('\u{c4e}', '\u{c54}'), ('\u{c57}', '\u{c57}'), + ('\u{c5b}', '\u{c5f}'), ('\u{c64}', '\u{c65}'), ('\u{c70}', '\u{c77}'), + ('\u{c8d}', '\u{c8d}'), ('\u{c91}', '\u{c91}'), ('\u{ca9}', '\u{ca9}'), + ('\u{cb4}', '\u{cb4}'), ('\u{cba}', '\u{cbb}'), ('\u{cc5}', '\u{cc5}'), + ('\u{cc9}', '\u{cc9}'), ('\u{cce}', '\u{cd4}'), ('\u{cd7}', '\u{cdd}'), + ('\u{cdf}', '\u{cdf}'), ('\u{ce4}', '\u{ce5}'), ('\u{cf0}', '\u{cf0}'), + ('\u{cf3}', '\u{cff}'), ('\u{d04}', '\u{d04}'), ('\u{d0d}', '\u{d0d}'), + ('\u{d11}', '\u{d11}'), ('\u{d45}', '\u{d45}'), ('\u{d49}', '\u{d49}'), + ('\u{d50}', '\u{d53}'), ('\u{d64}', '\u{d65}'), ('\u{d80}', '\u{d81}'), + ('\u{d84}', '\u{d84}'), ('\u{d97}', '\u{d99}'), ('\u{db2}', '\u{db2}'), + ('\u{dbc}', '\u{dbc}'), ('\u{dbe}', '\u{dbf}'), ('\u{dc7}', '\u{dc9}'), + ('\u{dcb}', '\u{dce}'), ('\u{dd5}', '\u{dd5}'), ('\u{dd7}', '\u{dd7}'), + ('\u{de0}', '\u{de5}'), ('\u{df0}', '\u{df1}'), ('\u{df5}', '\u{e00}'), + ('\u{e3b}', '\u{e3e}'), ('\u{e5c}', '\u{e80}'), ('\u{e83}', '\u{e83}'), + ('\u{e85}', '\u{e86}'), ('\u{e89}', '\u{e89}'), ('\u{e8b}', '\u{e8c}'), + ('\u{e8e}', '\u{e93}'), ('\u{e98}', '\u{e98}'), ('\u{ea0}', '\u{ea0}'), + ('\u{ea4}', '\u{ea4}'), ('\u{ea6}', '\u{ea6}'), ('\u{ea8}', '\u{ea9}'), + ('\u{eac}', '\u{eac}'), ('\u{eba}', '\u{eba}'), ('\u{ebe}', '\u{ebf}'), + ('\u{ec5}', '\u{ec5}'), ('\u{ec7}', '\u{ec7}'), ('\u{ece}', '\u{ecf}'), + ('\u{eda}', '\u{edb}'), ('\u{ee0}', '\u{eff}'), ('\u{f48}', '\u{f48}'), + ('\u{f6d}', '\u{f70}'), ('\u{f98}', '\u{f98}'), ('\u{fbd}', '\u{fbd}'), + ('\u{fcd}', '\u{fcd}'), ('\u{fdb}', '\u{fff}'), ('\u{10c6}', '\u{10c6}'), + ('\u{10c8}', '\u{10cc}'), ('\u{10ce}', '\u{10cf}'), + ('\u{1249}', '\u{1249}'), ('\u{124e}', '\u{124f}'), + ('\u{1257}', '\u{1257}'), ('\u{1259}', '\u{1259}'), + ('\u{125e}', '\u{125f}'), ('\u{1289}', '\u{1289}'), + ('\u{128e}', '\u{128f}'), ('\u{12b1}', '\u{12b1}'), + ('\u{12b6}', '\u{12b7}'), ('\u{12bf}', '\u{12bf}'), + ('\u{12c1}', '\u{12c1}'), ('\u{12c6}', '\u{12c7}'), + ('\u{12d7}', '\u{12d7}'), ('\u{1311}', '\u{1311}'), + ('\u{1316}', '\u{1317}'), ('\u{135b}', '\u{135c}'), + ('\u{137d}', '\u{137f}'), ('\u{139a}', '\u{139f}'), + ('\u{13f6}', '\u{13f7}'), ('\u{13fe}', '\u{13ff}'), + ('\u{169d}', '\u{169f}'), ('\u{16f9}', '\u{16ff}'), + ('\u{170d}', '\u{170d}'), ('\u{1715}', '\u{171f}'), + ('\u{1737}', '\u{173f}'), ('\u{1754}', '\u{175f}'), + ('\u{176d}', '\u{176d}'), ('\u{1771}', '\u{1771}'), + ('\u{1774}', '\u{177f}'), ('\u{17de}', '\u{17df}'), + ('\u{17ea}', '\u{17ef}'), ('\u{17fa}', '\u{17ff}'), + ('\u{180e}', '\u{180f}'), ('\u{181a}', '\u{181f}'), + ('\u{1879}', '\u{187f}'), ('\u{18ab}', '\u{18af}'), + ('\u{18f6}', '\u{18ff}'), ('\u{191f}', '\u{191f}'), + ('\u{192c}', '\u{192f}'), ('\u{193c}', '\u{193f}'), + ('\u{1941}', '\u{1943}'), ('\u{196e}', '\u{196f}'), + ('\u{1975}', '\u{197f}'), ('\u{19ac}', '\u{19af}'), + ('\u{19ca}', '\u{19cf}'), ('\u{19db}', '\u{19dd}'), + ('\u{1a1c}', '\u{1a1d}'), ('\u{1a5f}', '\u{1a5f}'), + ('\u{1a7d}', '\u{1a7e}'), ('\u{1a8a}', '\u{1a8f}'), + ('\u{1a9a}', '\u{1a9f}'), ('\u{1aae}', '\u{1aaf}'), + ('\u{1abf}', '\u{1aff}'), ('\u{1b4c}', '\u{1b4f}'), + ('\u{1b7d}', '\u{1b7f}'), ('\u{1bf4}', '\u{1bfb}'), + ('\u{1c38}', '\u{1c3a}'), ('\u{1c4a}', '\u{1c4c}'), + ('\u{1c89}', '\u{1c8f}'), ('\u{1cbb}', '\u{1cbc}'), + ('\u{1cc8}', '\u{1ccf}'), ('\u{1cfa}', '\u{1cff}'), + ('\u{1dfa}', '\u{1dfa}'), ('\u{1f16}', '\u{1f17}'), + ('\u{1f1e}', '\u{1f1f}'), ('\u{1f46}', '\u{1f47}'), + ('\u{1f4e}', '\u{1f4f}'), ('\u{1f58}', '\u{1f58}'), + ('\u{1f5a}', '\u{1f5a}'), ('\u{1f5c}', '\u{1f5c}'), + ('\u{1f5e}', '\u{1f5e}'), ('\u{1f7e}', '\u{1f7f}'), + ('\u{1fb5}', '\u{1fb5}'), ('\u{1fc5}', '\u{1fc5}'), + ('\u{1fd4}', '\u{1fd5}'), ('\u{1fdc}', '\u{1fdc}'), + ('\u{1ff0}', '\u{1ff1}'), ('\u{1ff5}', '\u{1ff5}'), + ('\u{1fff}', '\u{1fff}'), ('\u{200b}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{206f}'), + ('\u{2072}', '\u{2073}'), ('\u{208f}', '\u{208f}'), + ('\u{209d}', '\u{209f}'), ('\u{20c0}', '\u{20cf}'), + ('\u{20f1}', '\u{20ff}'), ('\u{218c}', '\u{218f}'), + ('\u{2427}', '\u{243f}'), ('\u{244b}', '\u{245f}'), + ('\u{2b74}', '\u{2b75}'), ('\u{2b96}', '\u{2b97}'), + ('\u{2bc9}', '\u{2bc9}'), ('\u{2bff}', '\u{2bff}'), + ('\u{2c2f}', '\u{2c2f}'), ('\u{2c5f}', '\u{2c5f}'), + ('\u{2cf4}', '\u{2cf8}'), ('\u{2d26}', '\u{2d26}'), + ('\u{2d28}', '\u{2d2c}'), ('\u{2d2e}', '\u{2d2f}'), + ('\u{2d68}', '\u{2d6e}'), ('\u{2d71}', '\u{2d7e}'), + ('\u{2d97}', '\u{2d9f}'), ('\u{2da7}', '\u{2da7}'), + ('\u{2daf}', '\u{2daf}'), ('\u{2db7}', '\u{2db7}'), + ('\u{2dbf}', '\u{2dbf}'), ('\u{2dc7}', '\u{2dc7}'), + ('\u{2dcf}', '\u{2dcf}'), ('\u{2dd7}', '\u{2dd7}'), + ('\u{2ddf}', '\u{2ddf}'), ('\u{2e4f}', '\u{2e7f}'), + ('\u{2e9a}', '\u{2e9a}'), ('\u{2ef4}', '\u{2eff}'), + ('\u{2fd6}', '\u{2fef}'), ('\u{2ffc}', '\u{2fff}'), + ('\u{3040}', '\u{3040}'), ('\u{3097}', '\u{3098}'), + ('\u{3100}', '\u{3104}'), ('\u{3130}', '\u{3130}'), + ('\u{318f}', '\u{318f}'), ('\u{31bb}', '\u{31bf}'), + ('\u{31e4}', '\u{31ef}'), ('\u{321f}', '\u{321f}'), + ('\u{32ff}', '\u{32ff}'), ('\u{4db6}', '\u{4dbf}'), + ('\u{9ff0}', '\u{9fff}'), ('\u{a48d}', '\u{a48f}'), + ('\u{a4c7}', '\u{a4cf}'), ('\u{a62c}', '\u{a63f}'), + ('\u{a6f8}', '\u{a6ff}'), ('\u{a7ba}', '\u{a7f6}'), + ('\u{a82c}', '\u{a82f}'), ('\u{a83a}', '\u{a83f}'), + ('\u{a878}', '\u{a87f}'), ('\u{a8c6}', '\u{a8cd}'), + ('\u{a8da}', '\u{a8df}'), ('\u{a954}', '\u{a95e}'), + ('\u{a97d}', '\u{a97f}'), ('\u{a9ce}', '\u{a9ce}'), + ('\u{a9da}', '\u{a9dd}'), ('\u{a9ff}', '\u{a9ff}'), + ('\u{aa37}', '\u{aa3f}'), ('\u{aa4e}', '\u{aa4f}'), + ('\u{aa5a}', '\u{aa5b}'), ('\u{aac3}', '\u{aada}'), + ('\u{aaf7}', '\u{ab00}'), ('\u{ab07}', '\u{ab08}'), + ('\u{ab0f}', '\u{ab10}'), ('\u{ab17}', '\u{ab1f}'), + ('\u{ab27}', '\u{ab27}'), ('\u{ab2f}', '\u{ab2f}'), + ('\u{ab66}', '\u{ab6f}'), ('\u{abee}', '\u{abef}'), + ('\u{abfa}', '\u{abff}'), ('\u{d7a4}', '\u{d7af}'), + ('\u{d7c7}', '\u{d7ca}'), ('\u{d7fc}', '\u{f8ff}'), + ('\u{fa6e}', '\u{fa6f}'), ('\u{fada}', '\u{faff}'), + ('\u{fb07}', '\u{fb12}'), ('\u{fb18}', '\u{fb1c}'), + ('\u{fb37}', '\u{fb37}'), ('\u{fb3d}', '\u{fb3d}'), + ('\u{fb3f}', '\u{fb3f}'), ('\u{fb42}', '\u{fb42}'), + ('\u{fb45}', '\u{fb45}'), ('\u{fbc2}', '\u{fbd2}'), + ('\u{fd40}', '\u{fd4f}'), ('\u{fd90}', '\u{fd91}'), + ('\u{fdc8}', '\u{fdef}'), ('\u{fdfe}', '\u{fdff}'), + ('\u{fe1a}', '\u{fe1f}'), ('\u{fe53}', '\u{fe53}'), + ('\u{fe67}', '\u{fe67}'), ('\u{fe6c}', '\u{fe6f}'), + ('\u{fe75}', '\u{fe75}'), ('\u{fefd}', '\u{ff00}'), + ('\u{ffbf}', '\u{ffc1}'), ('\u{ffc8}', '\u{ffc9}'), + ('\u{ffd0}', '\u{ffd1}'), ('\u{ffd8}', '\u{ffd9}'), + ('\u{ffdd}', '\u{ffdf}'), ('\u{ffe7}', '\u{ffe7}'), + ('\u{ffef}', '\u{fffb}'), ('\u{fffe}', '\u{ffff}'), + ('\u{1000c}', '\u{1000c}'), ('\u{10027}', '\u{10027}'), + ('\u{1003b}', '\u{1003b}'), ('\u{1003e}', '\u{1003e}'), + ('\u{1004e}', '\u{1004f}'), ('\u{1005e}', '\u{1007f}'), + ('\u{100fb}', '\u{100ff}'), ('\u{10103}', '\u{10106}'), + ('\u{10134}', '\u{10136}'), ('\u{1018f}', '\u{1018f}'), + ('\u{1019c}', '\u{1019f}'), ('\u{101a1}', '\u{101cf}'), + ('\u{101fe}', '\u{1027f}'), ('\u{1029d}', '\u{1029f}'), + ('\u{102d1}', '\u{102df}'), ('\u{102fc}', '\u{102ff}'), + ('\u{10324}', '\u{1032c}'), ('\u{1034b}', '\u{1034f}'), + ('\u{1037b}', '\u{1037f}'), ('\u{1039e}', '\u{1039e}'), + ('\u{103c4}', '\u{103c7}'), ('\u{103d6}', '\u{103ff}'), + ('\u{1049e}', '\u{1049f}'), ('\u{104aa}', '\u{104af}'), + ('\u{104d4}', '\u{104d7}'), ('\u{104fc}', '\u{104ff}'), + ('\u{10528}', '\u{1052f}'), ('\u{10564}', '\u{1056e}'), + ('\u{10570}', '\u{105ff}'), ('\u{10737}', '\u{1073f}'), + ('\u{10756}', '\u{1075f}'), ('\u{10768}', '\u{107ff}'), + ('\u{10806}', '\u{10807}'), ('\u{10809}', '\u{10809}'), + ('\u{10836}', '\u{10836}'), ('\u{10839}', '\u{1083b}'), + ('\u{1083d}', '\u{1083e}'), ('\u{10856}', '\u{10856}'), + ('\u{1089f}', '\u{108a6}'), ('\u{108b0}', '\u{108df}'), + ('\u{108f3}', '\u{108f3}'), ('\u{108f6}', '\u{108fa}'), + ('\u{1091c}', '\u{1091e}'), ('\u{1093a}', '\u{1093e}'), + ('\u{10940}', '\u{1097f}'), ('\u{109b8}', '\u{109bb}'), + ('\u{109d0}', '\u{109d1}'), ('\u{10a04}', '\u{10a04}'), + ('\u{10a07}', '\u{10a0b}'), ('\u{10a14}', '\u{10a14}'), + ('\u{10a18}', '\u{10a18}'), ('\u{10a36}', '\u{10a37}'), + ('\u{10a3b}', '\u{10a3e}'), ('\u{10a49}', '\u{10a4f}'), + ('\u{10a59}', '\u{10a5f}'), ('\u{10aa0}', '\u{10abf}'), + ('\u{10ae7}', '\u{10aea}'), ('\u{10af7}', '\u{10aff}'), + ('\u{10b36}', '\u{10b38}'), ('\u{10b56}', '\u{10b57}'), + ('\u{10b73}', '\u{10b77}'), ('\u{10b92}', '\u{10b98}'), + ('\u{10b9d}', '\u{10ba8}'), ('\u{10bb0}', '\u{10bff}'), + ('\u{10c49}', '\u{10c7f}'), ('\u{10cb3}', '\u{10cbf}'), + ('\u{10cf3}', '\u{10cf9}'), ('\u{10d28}', '\u{10d2f}'), + ('\u{10d3a}', '\u{10e5f}'), ('\u{10e7f}', '\u{10eff}'), + ('\u{10f28}', '\u{10f2f}'), ('\u{10f5a}', '\u{10fff}'), + ('\u{1104e}', '\u{11051}'), ('\u{11070}', '\u{1107e}'), + ('\u{110bd}', '\u{110bd}'), ('\u{110c2}', '\u{110cf}'), + ('\u{110e9}', '\u{110ef}'), ('\u{110fa}', '\u{110ff}'), + ('\u{11135}', '\u{11135}'), ('\u{11147}', '\u{1114f}'), + ('\u{11177}', '\u{1117f}'), ('\u{111ce}', '\u{111cf}'), + ('\u{111e0}', '\u{111e0}'), ('\u{111f5}', '\u{111ff}'), + ('\u{11212}', '\u{11212}'), ('\u{1123f}', '\u{1127f}'), + ('\u{11287}', '\u{11287}'), ('\u{11289}', '\u{11289}'), + ('\u{1128e}', '\u{1128e}'), ('\u{1129e}', '\u{1129e}'), + ('\u{112aa}', '\u{112af}'), ('\u{112eb}', '\u{112ef}'), + ('\u{112fa}', '\u{112ff}'), ('\u{11304}', '\u{11304}'), + ('\u{1130d}', '\u{1130e}'), ('\u{11311}', '\u{11312}'), + ('\u{11329}', '\u{11329}'), ('\u{11331}', '\u{11331}'), + ('\u{11334}', '\u{11334}'), ('\u{1133a}', '\u{1133a}'), + ('\u{11345}', '\u{11346}'), ('\u{11349}', '\u{1134a}'), + ('\u{1134e}', '\u{1134f}'), ('\u{11351}', '\u{11356}'), + ('\u{11358}', '\u{1135c}'), ('\u{11364}', '\u{11365}'), + ('\u{1136d}', '\u{1136f}'), ('\u{11375}', '\u{113ff}'), + ('\u{1145a}', '\u{1145a}'), ('\u{1145c}', '\u{1145c}'), + ('\u{1145f}', '\u{1147f}'), ('\u{114c8}', '\u{114cf}'), + ('\u{114da}', '\u{1157f}'), ('\u{115b6}', '\u{115b7}'), + ('\u{115de}', '\u{115ff}'), ('\u{11645}', '\u{1164f}'), + ('\u{1165a}', '\u{1165f}'), ('\u{1166d}', '\u{1167f}'), + ('\u{116b8}', '\u{116bf}'), ('\u{116ca}', '\u{116ff}'), + ('\u{1171b}', '\u{1171c}'), ('\u{1172c}', '\u{1172f}'), + ('\u{11740}', '\u{117ff}'), ('\u{1183c}', '\u{1189f}'), + ('\u{118f3}', '\u{118fe}'), ('\u{11900}', '\u{119ff}'), + ('\u{11a48}', '\u{11a4f}'), ('\u{11a84}', '\u{11a85}'), + ('\u{11aa3}', '\u{11abf}'), ('\u{11af9}', '\u{11bff}'), + ('\u{11c09}', '\u{11c09}'), ('\u{11c37}', '\u{11c37}'), + ('\u{11c46}', '\u{11c4f}'), ('\u{11c6d}', '\u{11c6f}'), + ('\u{11c90}', '\u{11c91}'), ('\u{11ca8}', '\u{11ca8}'), + ('\u{11cb7}', '\u{11cff}'), ('\u{11d07}', '\u{11d07}'), + ('\u{11d0a}', '\u{11d0a}'), ('\u{11d37}', '\u{11d39}'), + ('\u{11d3b}', '\u{11d3b}'), ('\u{11d3e}', '\u{11d3e}'), + ('\u{11d48}', '\u{11d4f}'), ('\u{11d5a}', '\u{11d5f}'), + ('\u{11d66}', '\u{11d66}'), ('\u{11d69}', '\u{11d69}'), + ('\u{11d8f}', '\u{11d8f}'), ('\u{11d92}', '\u{11d92}'), + ('\u{11d99}', '\u{11d9f}'), ('\u{11daa}', '\u{11edf}'), + ('\u{11ef9}', '\u{11fff}'), ('\u{1239a}', '\u{123ff}'), + ('\u{1246f}', '\u{1246f}'), ('\u{12475}', '\u{1247f}'), + ('\u{12544}', '\u{12fff}'), ('\u{1342f}', '\u{143ff}'), + ('\u{14647}', '\u{167ff}'), ('\u{16a39}', '\u{16a3f}'), + ('\u{16a5f}', '\u{16a5f}'), ('\u{16a6a}', '\u{16a6d}'), + ('\u{16a70}', '\u{16acf}'), ('\u{16aee}', '\u{16aef}'), + ('\u{16af6}', '\u{16aff}'), ('\u{16b46}', '\u{16b4f}'), + ('\u{16b5a}', '\u{16b5a}'), ('\u{16b62}', '\u{16b62}'), + ('\u{16b78}', '\u{16b7c}'), ('\u{16b90}', '\u{16e3f}'), + ('\u{16e9b}', '\u{16eff}'), ('\u{16f45}', '\u{16f4f}'), + ('\u{16f7f}', '\u{16f8e}'), ('\u{16fa0}', '\u{16fdf}'), + ('\u{16fe2}', '\u{16fff}'), ('\u{187f2}', '\u{187ff}'), + ('\u{18af3}', '\u{1afff}'), ('\u{1b11f}', '\u{1b16f}'), + ('\u{1b2fc}', '\u{1bbff}'), ('\u{1bc6b}', '\u{1bc6f}'), + ('\u{1bc7d}', '\u{1bc7f}'), ('\u{1bc89}', '\u{1bc8f}'), + ('\u{1bc9a}', '\u{1bc9b}'), ('\u{1bca0}', '\u{1cfff}'), + ('\u{1d0f6}', '\u{1d0ff}'), ('\u{1d127}', '\u{1d128}'), + ('\u{1d173}', '\u{1d17a}'), ('\u{1d1e9}', '\u{1d1ff}'), + ('\u{1d246}', '\u{1d2df}'), ('\u{1d2f4}', '\u{1d2ff}'), + ('\u{1d357}', '\u{1d35f}'), ('\u{1d379}', '\u{1d3ff}'), + ('\u{1d455}', '\u{1d455}'), ('\u{1d49d}', '\u{1d49d}'), + ('\u{1d4a0}', '\u{1d4a1}'), ('\u{1d4a3}', '\u{1d4a4}'), + ('\u{1d4a7}', '\u{1d4a8}'), ('\u{1d4ad}', '\u{1d4ad}'), + ('\u{1d4ba}', '\u{1d4ba}'), ('\u{1d4bc}', '\u{1d4bc}'), + ('\u{1d4c4}', '\u{1d4c4}'), ('\u{1d506}', '\u{1d506}'), + ('\u{1d50b}', '\u{1d50c}'), ('\u{1d515}', '\u{1d515}'), + ('\u{1d51d}', '\u{1d51d}'), ('\u{1d53a}', '\u{1d53a}'), + ('\u{1d53f}', '\u{1d53f}'), ('\u{1d545}', '\u{1d545}'), + ('\u{1d547}', '\u{1d549}'), ('\u{1d551}', '\u{1d551}'), + ('\u{1d6a6}', '\u{1d6a7}'), ('\u{1d7cc}', '\u{1d7cd}'), + ('\u{1da8c}', '\u{1da9a}'), ('\u{1daa0}', '\u{1daa0}'), + ('\u{1dab0}', '\u{1dfff}'), ('\u{1e007}', '\u{1e007}'), + ('\u{1e019}', '\u{1e01a}'), ('\u{1e022}', '\u{1e022}'), + ('\u{1e025}', '\u{1e025}'), ('\u{1e02b}', '\u{1e7ff}'), + ('\u{1e8c5}', '\u{1e8c6}'), ('\u{1e8d7}', '\u{1e8ff}'), + ('\u{1e94b}', '\u{1e94f}'), ('\u{1e95a}', '\u{1e95d}'), + ('\u{1e960}', '\u{1ec70}'), ('\u{1ecb5}', '\u{1edff}'), + ('\u{1ee04}', '\u{1ee04}'), ('\u{1ee20}', '\u{1ee20}'), + ('\u{1ee23}', '\u{1ee23}'), ('\u{1ee25}', '\u{1ee26}'), + ('\u{1ee28}', '\u{1ee28}'), ('\u{1ee33}', '\u{1ee33}'), + ('\u{1ee38}', '\u{1ee38}'), ('\u{1ee3a}', '\u{1ee3a}'), + ('\u{1ee3c}', '\u{1ee41}'), ('\u{1ee43}', '\u{1ee46}'), + ('\u{1ee48}', '\u{1ee48}'), ('\u{1ee4a}', '\u{1ee4a}'), + ('\u{1ee4c}', '\u{1ee4c}'), ('\u{1ee50}', '\u{1ee50}'), + ('\u{1ee53}', '\u{1ee53}'), ('\u{1ee55}', '\u{1ee56}'), + ('\u{1ee58}', '\u{1ee58}'), ('\u{1ee5a}', '\u{1ee5a}'), + ('\u{1ee5c}', '\u{1ee5c}'), ('\u{1ee5e}', '\u{1ee5e}'), + ('\u{1ee60}', '\u{1ee60}'), ('\u{1ee63}', '\u{1ee63}'), + ('\u{1ee65}', '\u{1ee66}'), ('\u{1ee6b}', '\u{1ee6b}'), + ('\u{1ee73}', '\u{1ee73}'), ('\u{1ee78}', '\u{1ee78}'), + ('\u{1ee7d}', '\u{1ee7d}'), ('\u{1ee7f}', '\u{1ee7f}'), + ('\u{1ee8a}', '\u{1ee8a}'), ('\u{1ee9c}', '\u{1eea0}'), + ('\u{1eea4}', '\u{1eea4}'), ('\u{1eeaa}', '\u{1eeaa}'), + ('\u{1eebc}', '\u{1eeef}'), ('\u{1eef2}', '\u{1efff}'), + ('\u{1f02c}', '\u{1f02f}'), ('\u{1f094}', '\u{1f09f}'), + ('\u{1f0af}', '\u{1f0b0}'), ('\u{1f0c0}', '\u{1f0c0}'), + ('\u{1f0d0}', '\u{1f0d0}'), ('\u{1f0f6}', '\u{1f0ff}'), + ('\u{1f10d}', '\u{1f10f}'), ('\u{1f16c}', '\u{1f16f}'), + ('\u{1f1ad}', '\u{1f1e5}'), ('\u{1f203}', '\u{1f20f}'), + ('\u{1f23c}', '\u{1f23f}'), ('\u{1f249}', '\u{1f24f}'), + ('\u{1f252}', '\u{1f25f}'), ('\u{1f266}', '\u{1f2ff}'), + ('\u{1f6d5}', '\u{1f6df}'), ('\u{1f6ed}', '\u{1f6ef}'), + ('\u{1f6fa}', '\u{1f6ff}'), ('\u{1f774}', '\u{1f77f}'), + ('\u{1f7d9}', '\u{1f7ff}'), ('\u{1f80c}', '\u{1f80f}'), + ('\u{1f848}', '\u{1f84f}'), ('\u{1f85a}', '\u{1f85f}'), + ('\u{1f888}', '\u{1f88f}'), ('\u{1f8ae}', '\u{1f8ff}'), + ('\u{1f90c}', '\u{1f90f}'), ('\u{1f93f}', '\u{1f93f}'), + ('\u{1f971}', '\u{1f972}'), ('\u{1f977}', '\u{1f979}'), + ('\u{1f97b}', '\u{1f97b}'), ('\u{1f9a3}', '\u{1f9af}'), + ('\u{1f9ba}', '\u{1f9bf}'), ('\u{1f9c3}', '\u{1f9cf}'), + ('\u{1fa00}', '\u{1fa5f}'), ('\u{1fa6e}', '\u{1ffff}'), + ('\u{2a6d7}', '\u{2a6ff}'), ('\u{2b735}', '\u{2b73f}'), + ('\u{2b81e}', '\u{2b81f}'), ('\u{2cea2}', '\u{2ceaf}'), + ('\u{2ebe1}', '\u{2f7ff}'), ('\u{2fa1e}', '\u{e00ff}'), + ('\u{e01f0}', '\u{10ffff}'), +]; + +pub const OTHER_LETTER: &'static [(char, char)] = &[ + ('ª', 'ª'), ('º', 'º'), ('Æ»', 'Æ»'), ('ǀ', 'ǃ'), ('ʔ', 'ʔ'), + ('א', 'ת'), ('\u{5ef}', 'ײ'), ('Ø ', 'Ø¿'), ('ف', 'ي'), ('Ù®', 'Ù¯'), + ('Ù±', 'ۓ'), ('ە', 'ە'), ('Û®', 'Û¯'), ('Ûº', 'Û¼'), ('Û¿', 'Û¿'), + ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), ('ߊ', 'ߪ'), + ('ࠀ', 'ࠕ'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), ('ऽ', 'ऽ'), ('ॐ', 'ॐ'), + ('क़', 'ॡ'), ('ॲ', 'ঀ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), ('ড়', 'ঢ়'), ('য়', 'à§¡'), + ('à§°', 'à§±'), ('à§¼', 'à§¼'), ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), + ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('ੲ', 'à©´'), + ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('ઽ', 'ઽ'), ('ૐ', 'ૐ'), + ('à« ', 'à«¡'), ('ૹ', 'ૹ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), + ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), ('à­±', 'à­±'), + ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), ('ஒ', 'க'), + ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), ('ண', 'த'), + ('ந', 'ப'), ('à®®', 'ஹ'), ('ௐ', 'ௐ'), ('అ', 'ఌ'), + ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'à°½'), + ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('ಀ', 'ಀ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), ('à³±', 'à³²'), + ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), ('à´½', 'à´½'), + ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), ('ൟ', 'ൡ'), ('ൺ', 'ൿ'), + ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), + ('ව', 'ෆ'), ('ก', 'ะ'), ('า', 'ำ'), ('เ', 'ๅ'), + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ະ'), + ('າ', 'ຳ'), ('ຽ', 'ຽ'), ('ເ', 'ໄ'), ('ໜ', 'ໟ'), + ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), ('ཉ', 'ཬ'), ('ྈ', 'ྌ'), + ('က', 'ဪ'), ('ဿ', 'ဿ'), ('ၐ', 'ၕ'), ('ၚ', 'ၝ'), + ('ၡ', 'ၡ'), ('ၥ', 'ၦ'), ('ၮ', 'ၰ'), ('ၵ', 'ႁ'), + ('ႎ', 'ႎ'), ('ᄀ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), + ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), + ('ነ', 'ኰ'), ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), + ('ዂ', 'ዅ'), ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), + ('ጘ', 'ፚ'), ('ᎀ', 'ᎏ'), ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), + ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛱ', 'ᛸ'), ('ᜀ', 'ᜌ'), + ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), + ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), ('ៜ', 'ៜ'), ('á  ', 'ᡂ'), + ('ᡄ', '\u{1878}'), ('ᢀ', 'ᢄ'), ('ᢇ', 'ᢨ'), ('ᢪ', 'ᢪ'), + ('ᢰ', 'ᣵ'), ('ᤀ', 'ᤞ'), ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), + ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('ᨀ', 'ᨖ'), ('ᨠ', 'ᩔ'), + ('ᬅ', 'ᬳ'), ('ᭅ', 'ᭋ'), ('ᮃ', 'á® '), ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), ('ᰀ', 'á°£'), ('ᱍ', 'ᱏ'), ('ᱚ', 'á±·'), + ('ᳩ', 'ᳬ'), ('á³®', 'á³±'), ('á³µ', 'á³¶'), ('ℵ', 'ℸ'), + ('â´°', 'âµ§'), ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), + ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), + ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('〆', '〆'), ('〼', '〼'), + ('ぁ', 'ゖ'), ('ゟ', 'ゟ'), ('ァ', 'ヺ'), ('ヿ', 'ヿ'), + ('ㄅ', '\u{312f}'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), ('ㇰ', 'ㇿ'), + ('㐀', 'ä¶µ'), ('一', '\u{9fef}'), ('ꀀ', 'ꀔ'), ('ꀖ', 'ꒌ'), + ('ꓐ', 'ꓷ'), ('ꔀ', 'ꘋ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), + ('ꙮ', 'ꙮ'), ('ꚠ', 'ꛥ'), ('ꞏ', 'ꞏ'), ('ꟷ', 'ꟷ'), + ('ꟻ', 'ꠁ'), ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), ('ꠌ', 'ê ¢'), + ('ꡀ', 'ꡳ'), ('ꢂ', 'ꢳ'), ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), + ('ꣽ', '\u{a8fe}'), ('ꤊ', 'ꤥ'), ('ꤰ', 'ꥆ'), ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), ('ê§ ', 'ꧤ'), ('ê§§', 'ꧯ'), ('ꧺ', 'ê§¾'), + ('ꨀ', 'ꨨ'), ('ꩀ', 'ꩂ'), ('ꩄ', 'ꩋ'), ('ê© ', 'ꩯ'), + ('ꩱ', 'ê©¶'), ('ꩺ', 'ꩺ'), ('ꩾ', 'ꪯ'), ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪽ'), ('ꫀ', 'ꫀ'), ('ꫂ', 'ꫂ'), + ('ꫛ', 'ꫜ'), ('ê« ', 'ꫪ'), ('ꫲ', 'ꫲ'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), + ('ꯀ', 'ꯢ'), ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), ('ï©°', '龎'), ('יִ', 'יִ'), ('ײַ', 'ﬨ'), + ('שׁ', 'זּ'), ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), + ('ףּ', 'פּ'), ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), + ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), + ('ヲ', 'ッ'), ('ï½±', 'ン'), ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), + ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), + ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), ('𐀿', '𐁍'), + ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), + ('𐌀', '𐌟'), ('𐌭', '𐍀'), ('𐍂', '𐍉'), ('𐍐', '𐍵'), + ('𐎀', '𐎝'), ('𐎠', '𐏃'), ('𐏈', '𐏏'), ('𐑐', '𐒝'), + ('𐔀', '𐔧'), ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), + ('𐝠', '𐝧'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), + ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), + ('𐢀', '𐢞'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), + ('𐤠', '𐤹'), ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '𐨀'), + ('𐨐', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '\u{10a35}'), ('𐩠', '𐩼'), + ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '𐫤'), ('𐬀', '𐬵'), + ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), ('𐰀', '𐱈'), + ('\u{10d00}', '\u{10d23}'), ('\u{10f00}', '\u{10f1c}'), + ('\u{10f27}', '\u{10f27}'), ('\u{10f30}', '\u{10f45}'), ('𑀃', '𑀷'), + ('𑂃', '𑂯'), ('𑃐', '𑃨'), ('𑄃', '𑄦'), + ('\u{11144}', '\u{11144}'), ('𑅐', '𑅲'), ('𑅶', '𑅶'), + ('𑆃', '𑆲'), ('𑇁', '𑇄'), ('𑇚', '𑇚'), ('𑇜', '𑇜'), + ('𑈀', '𑈑'), ('𑈓', '𑈫'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), + ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), ('𑊰', '𑋞'), + ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), ('𑌪', '𑌰'), + ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('𑌽', '𑌽'), ('𑍐', '𑍐'), + ('𑍝', '𑍡'), ('𑐀', '𑐴'), ('𑑇', '𑑊'), ('𑒀', '𑒯'), + ('𑓄', '𑓅'), ('𑓇', '𑓇'), ('𑖀', '𑖮'), ('𑗘', '𑗛'), + ('𑘀', '𑘯'), ('𑙄', '𑙄'), ('𑚀', '𑚪'), ('𑜀', '\u{1171a}'), + ('\u{11800}', '\u{1182b}'), ('𑣿', '𑣿'), ('𑨀', '𑨀'), + ('𑨋', '𑨲'), ('𑨺', '𑨺'), ('𑩐', '𑩐'), ('𑩜', '𑪃'), + ('𑪆', '𑪉'), ('\u{11a9d}', '\u{11a9d}'), ('𑫀', '𑫸'), + ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), ('𑱲', '𑲏'), + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), ('𑵆', '𑵆'), + ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d89}'), ('\u{11d98}', '\u{11d98}'), + ('\u{11ee0}', '\u{11ef2}'), ('𒀀', '𒎙'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭣', '𖭷'), ('𖭽', '𖮏'), + ('𖼀', '𖽄'), ('𖽐', '𖽐'), ('𗀀', '\u{187f1}'), ('𘠀', '𘫲'), + ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), + ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𞠀', '𞣄'), ('𞸀', '𞸃'), + ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), + ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), + ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), + ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), + ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), + ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), + ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), + ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), + ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const OTHER_NUMBER: &'static [(char, char)] = &[ + ('²', '³'), ('¹', '¹'), ('¼', '¾'), ('à§´', 'à§¹'), ('à­²', 'à­·'), + ('௰', '௲'), ('౸', 'à±¾'), ('൘', '൞'), ('൰', '൸'), + ('༪', '༳'), ('፩', '፼'), ('៰', '៹'), ('᧚', '᧚'), + ('⁰', '⁰'), ('⁴', '⁹'), ('₀', '₉'), ('⅐', '⅟'), + ('↉', '↉'), ('①', '⒛'), ('⓪', '⓿'), ('❶', '➓'), + ('â³½', 'â³½'), ('㆒', '㆕'), ('㈠', '㈩'), ('㉈', '㉏'), + ('㉑', '㉟'), ('㊀', '㊉'), ('㊱', '㊿'), ('ê °', 'ê µ'), + ('𐄇', '𐄳'), ('𐅵', '𐅸'), ('𐆊', '𐆋'), ('𐋡', '𐋻'), + ('𐌠', '𐌣'), ('𐡘', '𐡟'), ('𐡹', '𐡿'), ('𐢧', '𐢯'), + ('𐣻', '𐣿'), ('𐤖', '𐤛'), ('𐦼', '𐦽'), ('𐧀', '𐧏'), + ('𐧒', '𐧿'), ('𐩀', '\u{10a48}'), ('𐩽', '𐩾'), ('𐪝', '𐪟'), + ('𐫫', '𐫯'), ('𐭘', '𐭟'), ('𐭸', '𐭿'), ('𐮩', '𐮯'), + ('𐳺', '𐳿'), ('𐹠', '𐹾'), ('\u{10f1d}', '\u{10f26}'), + ('\u{10f51}', '\u{10f54}'), ('𑁒', '𑁥'), ('𑇡', '𑇴'), + ('𑜺', '𑜻'), ('𑣪', '𑣲'), ('𑱚', '𑱬'), ('𖭛', '𖭡'), + ('\u{16e80}', '\u{16e96}'), ('\u{1d2e0}', '\u{1d2f3}'), + ('𝍠', '\u{1d378}'), ('𞣇', '𞣏'), ('\u{1ec71}', '\u{1ecab}'), + ('\u{1ecad}', '\u{1ecaf}'), ('\u{1ecb1}', '\u{1ecb4}'), ('🄀', '🄌'), +]; + +pub const OTHER_PUNCTUATION: &'static [(char, char)] = &[ + ('!', '#'), ('%', '\''), ('*', '*'), (',', ','), ('.', '/'), (':', ';'), + ('?', '@'), ('\\', '\\'), ('¡', '¡'), ('§', '§'), ('¶', '·'), + ('¿', '¿'), (';', ';'), ('·', '·'), ('՚', '՟'), ('։', '։'), + ('׀', '׀'), ('׃', '׃'), ('׆', '׆'), ('׳', '×´'), ('؉', '؊'), + ('،', '؍'), ('؛', '؛'), ('؞', '؟'), ('Ùª', 'Ù­'), ('۔', '۔'), + ('܀', '܍'), ('ß·', 'ß¹'), ('à °', 'à ¾'), ('࡞', '࡞'), ('।', '॥'), + ('॰', '॰'), ('à§½', 'à§½'), ('\u{a76}', '\u{a76}'), ('à«°', 'à«°'), + ('\u{c84}', '\u{c84}'), ('à·´', 'à·´'), ('๏', '๏'), ('๚', '๛'), + ('༄', '༒'), ('༔', '༔'), ('྅', '྅'), ('࿐', '࿔'), + ('࿙', '࿚'), ('၊', '၏'), ('჻', '჻'), ('፠', '፨'), + ('᙭', '᙮'), ('᛫', '᛭'), ('᜵', '᜶'), ('។', '៖'), + ('៘', '៚'), ('᠀', '᠅'), ('᠇', '᠊'), ('᥄', '᥅'), + ('᨞', '᨟'), ('᪠', '᪦'), ('᪨', '᪭'), ('᭚', 'á­ '), + ('᯼', '᯿'), ('á°»', 'á°¿'), ('á±¾', '᱿'), ('᳀', '᳇'), + ('᳓', '᳓'), ('‖', '‗'), ('†', '‧'), ('‰', '‸'), + ('※', '‾'), ('⁁', '⁃'), ('⁇', '⁑'), ('⁓', '⁓'), + ('⁕', '⁞'), ('â³¹', 'â³¼'), ('â³¾', '⳿'), ('âµ°', 'âµ°'), + ('⸀', '⸁'), ('⸆', '⸈'), ('⸋', '⸋'), ('⸎', '⸖'), + ('⸘', '⸙'), ('⸛', '⸛'), ('⸞', '⸟'), ('⸪', '⸮'), + ('⸰', '⸹'), ('⸼', '⸿'), ('⹁', '⹁'), ('⹃', '\u{2e4e}'), + ('、', '〃'), ('〽', '〽'), ('・', '・'), ('꓾', '꓿'), + ('꘍', '꘏'), ('꙳', '꙳'), ('꙾', '꙾'), ('꛲', '꛷'), + ('ê¡´', 'ê¡·'), ('꣎', '꣏'), ('꣸', '꣺'), ('꣼', '꣼'), + ('꤮', '꤯'), ('꥟', '꥟'), ('꧁', '꧍'), ('꧞', '꧟'), + ('꩜', '꩟'), ('꫞', '꫟'), ('ê«°', '꫱'), ('꯫', '꯫'), + ('︐', '︖'), ('︙', '︙'), ('︰', '︰'), ('﹅', '﹆'), + ('﹉', '﹌'), ('﹐', '﹒'), ('﹔', '﹗'), ('﹟', '﹡'), + ('﹨', '﹨'), ('﹪', '﹫'), ('!', '#'), ('%', '''), + ('*', '*'), (',', ','), ('.', '/'), (':', ';'), + ('?', 'ï¼ '), ('ï¼¼', 'ï¼¼'), ('。', '。'), ('、', 'ï½¥'), + ('𐄀', '𐄂'), ('𐎟', '𐎟'), ('𐏐', '𐏐'), ('𐕯', '𐕯'), + ('𐡗', '𐡗'), ('𐤟', '𐤟'), ('𐤿', '𐤿'), ('𐩐', '𐩘'), + ('𐩿', '𐩿'), ('𐫰', '𐫶'), ('𐬹', '𐬿'), ('𐮙', '𐮜'), + ('\u{10f55}', '\u{10f59}'), ('𑁇', '𑁍'), ('𑂻', '𑂼'), + ('𑂾', '𑃁'), ('𑅀', '𑅃'), ('𑅴', '𑅵'), ('𑇅', '𑇈'), + ('𑇍', '𑇍'), ('𑇛', '𑇛'), ('𑇝', '𑇟'), ('𑈸', '𑈽'), + ('𑊩', '𑊩'), ('𑑋', '𑑏'), ('𑑛', '𑑛'), ('𑑝', '𑑝'), + ('𑓆', '𑓆'), ('𑗁', '𑗗'), ('𑙁', '𑙃'), ('𑙠', '𑙬'), + ('𑜼', '𑜾'), ('\u{1183b}', '\u{1183b}'), ('𑨿', '𑩆'), + ('𑪚', '𑪜'), ('𑪞', '𑪢'), ('𑱁', '𑱅'), ('𑱰', '𑱱'), + ('\u{11ef7}', '\u{11ef8}'), ('𒑰', '𒑴'), ('𖩮', '𖩯'), + ('𖫵', '𖫵'), ('𖬷', '𖬻'), ('𖭄', '𖭄'), + ('\u{16e97}', '\u{16e9a}'), ('𛲟', '𛲟'), ('𝪇', '𝪋'), + ('𞥞', '𞥟'), +]; + +pub const OTHER_SYMBOL: &'static [(char, char)] = &[ + ('¦', '¦'), ('©', '©'), ('®', '®'), ('°', '°'), ('҂', '҂'), + ('֍', '֎'), ('؎', '؏'), ('۞', '۞'), ('Û©', 'Û©'), ('Û½', 'Û¾'), + ('ß¶', 'ß¶'), ('৺', '৺'), ('à­°', 'à­°'), ('௳', '௸'), + ('௺', '௺'), ('౿', '౿'), ('൏', '൏'), ('൹', '൹'), + ('༁', '༃'), ('༓', '༓'), ('༕', '༗'), ('༚', '༟'), + ('༴', '༴'), ('༶', '༶'), ('༸', '༸'), ('྾', '࿅'), + ('࿇', '࿌'), ('࿎', '࿏'), ('࿕', '࿘'), ('႞', '႟'), + ('᎐', '᎙'), ('᥀', '᥀'), ('᧞', 'á§¿'), ('á­¡', 'á­ª'), + ('á­´', 'á­¼'), ('℀', '℁'), ('℃', '℆'), ('℈', '℉'), + ('℔', '℔'), ('№', '℗'), ('℞', '℣'), ('℥', '℥'), + ('℧', '℧'), ('℩', '℩'), ('℮', '℮'), ('℺', '℻'), + ('⅊', '⅊'), ('⅌', '⅍'), ('⅏', '⅏'), ('↊', '↋'), + ('↕', '↙'), ('↜', '↟'), ('↡', '↢'), ('↤', '↥'), + ('↧', '↭'), ('↯', '⇍'), ('⇐', '⇑'), ('⇓', '⇓'), + ('⇕', '⇳'), ('⌀', '⌇'), ('⌌', '⌟'), ('⌢', '⌨'), + ('⌫', '⍻'), ('⍽', '⎚'), ('⎴', '⏛'), ('⏢', '␦'), + ('⑀', '⑊'), ('⒜', 'ⓩ'), ('─', '▶'), ('▸', '◀'), + ('◂', '◷'), ('☀', '♮'), ('♰', '❧'), ('➔', '➿'), + ('⠀', '⣿'), ('⬀', '⬯'), ('⭅', '⭆'), ('⭍', 'â­³'), + ('â­¶', '⮕'), ('⮘', '⯈'), ('⯊', '\u{2bfe}'), ('â³¥', '⳪'), + ('⺀', '⺙'), ('⺛', '⻳'), ('⼀', '⿕'), ('â¿°', 'â¿»'), + ('〄', '〄'), ('〒', '〓'), ('〠', '〠'), ('〶', '〷'), + ('〾', '〿'), ('㆐', '㆑'), ('㆖', '㆟'), ('㇀', '㇣'), + ('㈀', '㈞'), ('㈪', '㉇'), ('㉐', '㉐'), ('㉠', '㉿'), + ('㊊', '㊰'), ('㋀', '㋾'), ('㌀', '㏿'), ('䷀', 'ä·¿'), + ('꒐', '꓆'), ('ê ¨', 'ê «'), ('ê ¶', 'ê ·'), ('ê ¹', 'ê ¹'), + ('ê©·', '꩹'), ('ï·½', 'ï·½'), ('¦', '¦'), ('│', '│'), + ('ï¿­', 'ï¿®'), ('', '�'), ('𐄷', '𐄿'), ('𐅹', '𐆉'), + ('𐆌', '𐆎'), ('𐆐', '𐆛'), ('𐆠', '𐆠'), ('𐇐', '𐇼'), + ('𐡷', '𐡸'), ('𐫈', '𐫈'), ('𑜿', '𑜿'), ('𖬼', '𖬿'), + ('𖭅', '𖭅'), ('𛲜', '𛲜'), ('𝀀', '𝃵'), ('𝄀', '𝄦'), + ('𝄩', '𝅘𝅥𝅲'), ('𝅪', '𝅬'), ('𝆃', '𝆄'), ('𝆌', '𝆩'), + ('𝆮', '𝇨'), ('𝈀', '𝉁'), ('𝉅', '𝉅'), ('𝌀', '𝍖'), + ('𝠀', '𝧿'), ('𝨷', '𝨺'), ('𝩭', '𝩴'), ('𝩶', '𝪃'), + ('𝪅', '𝪆'), ('\u{1ecac}', '\u{1ecac}'), ('🀀', '🀫'), + ('🀰', '🂓'), ('🂠', '🂮'), ('🂱', '🂿'), ('🃁', '🃏'), + ('🃑', '🃵'), ('🄐', '🅫'), ('🅰', '🆬'), ('🇦', '🈂'), + ('🈐', '🈻'), ('🉀', '🉈'), ('🉐', '🉑'), ('🉠', '🉥'), + ('🌀', '🏺'), ('🐀', '🛔'), ('🛠', '🛬'), ('🛰', '\u{1f6f9}'), + ('🜀', '🝳'), ('🞀', '\u{1f7d8}'), ('🠀', '🠋'), ('🠐', '🡇'), + ('🡐', '🡙'), ('🡠', '🢇'), ('🢐', '🢭'), ('🤀', '🤋'), + ('🤐', '🤾'), ('🥀', '\u{1f970}'), ('\u{1f973}', '\u{1f976}'), + ('\u{1f97a}', '\u{1f97a}'), ('\u{1f97c}', '\u{1f9a2}'), + ('\u{1f9b0}', '\u{1f9b9}'), ('🧀', '\u{1f9c2}'), ('🧐', '\u{1f9ff}'), + ('\u{1fa60}', '\u{1fa6d}'), +]; + +pub const PARAGRAPH_SEPARATOR: &'static [(char, char)] = &[ + ('\u{2029}', '\u{2029}'), +]; + +pub const PRIVATE_USE: &'static [(char, char)] = &[ + ('\u{e000}', '\u{f8ff}'), ('\u{f0000}', '\u{ffffd}'), + ('\u{100000}', '\u{10fffd}'), +]; + +pub const PUNCTUATION: &'static [(char, char)] = &[ + ('!', '#'), ('%', '*'), (',', '/'), (':', ';'), ('?', '@'), ('[', ']'), + ('_', '_'), ('{', '{'), ('}', '}'), ('¡', '¡'), ('§', '§'), + ('«', '«'), ('¶', '·'), ('»', '»'), ('¿', '¿'), (';', ';'), + ('·', '·'), ('՚', '՟'), ('։', '֊'), ('Ö¾', 'Ö¾'), ('׀', '׀'), + ('׃', '׃'), ('׆', '׆'), ('׳', '×´'), ('؉', '؊'), ('،', '؍'), + ('؛', '؛'), ('؞', '؟'), ('Ùª', 'Ù­'), ('۔', '۔'), ('܀', '܍'), + ('ß·', 'ß¹'), ('à °', 'à ¾'), ('࡞', '࡞'), ('।', '॥'), + ('॰', '॰'), ('à§½', 'à§½'), ('\u{a76}', '\u{a76}'), ('à«°', 'à«°'), + ('\u{c84}', '\u{c84}'), ('à·´', 'à·´'), ('๏', '๏'), ('๚', '๛'), + ('༄', '༒'), ('༔', '༔'), ('༺', '༽'), ('྅', '྅'), + ('࿐', '࿔'), ('࿙', '࿚'), ('၊', '၏'), ('჻', '჻'), + ('፠', '፨'), ('᐀', '᐀'), ('᙭', '᙮'), ('᚛', '᚜'), + ('᛫', '᛭'), ('᜵', '᜶'), ('។', '៖'), ('៘', '៚'), + ('᠀', '᠊'), ('᥄', '᥅'), ('᨞', '᨟'), ('᪠', '᪦'), + ('᪨', '᪭'), ('᭚', 'á­ '), ('᯼', '᯿'), ('á°»', 'á°¿'), + ('á±¾', '᱿'), ('᳀', '᳇'), ('᳓', '᳓'), ('‐', '‧'), + ('‰', '⁃'), ('⁅', '⁑'), ('⁓', '⁞'), ('⁽', '⁾'), + ('₍', '₎'), ('⌈', '⌋'), ('〈', '〉'), ('❨', '❵'), + ('⟅', '⟆'), ('⟦', '⟯'), ('⦃', '⦘'), ('⧘', '⧛'), + ('â§¼', 'â§½'), ('â³¹', 'â³¼'), ('â³¾', '⳿'), ('âµ°', 'âµ°'), + ('⸀', '⸮'), ('⸰', '\u{2e4e}'), ('、', '〃'), ('〈', '】'), + ('〔', '〟'), ('〰', '〰'), ('〽', '〽'), ('゠', '゠'), + ('・', '・'), ('꓾', '꓿'), ('꘍', '꘏'), ('꙳', '꙳'), + ('꙾', '꙾'), ('꛲', '꛷'), ('ê¡´', 'ê¡·'), ('꣎', '꣏'), + ('꣸', '꣺'), ('꣼', '꣼'), ('꤮', '꤯'), ('꥟', '꥟'), + ('꧁', '꧍'), ('꧞', '꧟'), ('꩜', '꩟'), ('꫞', '꫟'), + ('ê«°', '꫱'), ('꯫', '꯫'), ('ï´¾', 'ï´¿'), ('︐', '︙'), + ('︰', '﹒'), ('﹔', '﹡'), ('ï¹£', 'ï¹£'), ('﹨', '﹨'), + ('﹪', '﹫'), ('!', '#'), ('%', '*'), (',', '/'), + (':', ';'), ('?', 'ï¼ '), ('ï¼»', 'ï¼½'), ('_', '_'), + ('{', '{'), ('}', '}'), ('⦅', 'ï½¥'), ('𐄀', '𐄂'), + ('𐎟', '𐎟'), ('𐏐', '𐏐'), ('𐕯', '𐕯'), ('𐡗', '𐡗'), + ('𐤟', '𐤟'), ('𐤿', '𐤿'), ('𐩐', '𐩘'), ('𐩿', '𐩿'), + ('𐫰', '𐫶'), ('𐬹', '𐬿'), ('𐮙', '𐮜'), + ('\u{10f55}', '\u{10f59}'), ('𑁇', '𑁍'), ('𑂻', '𑂼'), + ('𑂾', '𑃁'), ('𑅀', '𑅃'), ('𑅴', '𑅵'), ('𑇅', '𑇈'), + ('𑇍', '𑇍'), ('𑇛', '𑇛'), ('𑇝', '𑇟'), ('𑈸', '𑈽'), + ('𑊩', '𑊩'), ('𑑋', '𑑏'), ('𑑛', '𑑛'), ('𑑝', '𑑝'), + ('𑓆', '𑓆'), ('𑗁', '𑗗'), ('𑙁', '𑙃'), ('𑙠', '𑙬'), + ('𑜼', '𑜾'), ('\u{1183b}', '\u{1183b}'), ('𑨿', '𑩆'), + ('𑪚', '𑪜'), ('𑪞', '𑪢'), ('𑱁', '𑱅'), ('𑱰', '𑱱'), + ('\u{11ef7}', '\u{11ef8}'), ('𒑰', '𒑴'), ('𖩮', '𖩯'), + ('𖫵', '𖫵'), ('𖬷', '𖬻'), ('𖭄', '𖭄'), + ('\u{16e97}', '\u{16e9a}'), ('𛲟', '𛲟'), ('𝪇', '𝪋'), + ('𞥞', '𞥟'), +]; + +pub const SEPARATOR: &'static [(char, char)] = &[ + (' ', ' '), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), ('\u{2028}', '\u{2029}'), + ('\u{202f}', '\u{202f}'), ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const SPACE_SEPARATOR: &'static [(char, char)] = &[ + (' ', ' '), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), + ('\u{2000}', '\u{200a}'), ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'), +]; + +pub const SPACING_MARK: &'static [(char, char)] = &[ + ('ः', 'ः'), ('ऻ', 'ऻ'), ('ा', 'ी'), ('ॉ', 'ौ'), + ('ॎ', 'ॏ'), ('ং', 'ঃ'), ('া', 'ী'), ('ে', 'ৈ'), + ('ো', 'ৌ'), ('ৗ', 'ৗ'), ('ਃ', 'ਃ'), ('ਾ', 'ੀ'), + ('ઃ', 'ઃ'), ('ા', 'ી'), ('ૉ', 'ૉ'), ('ો', 'ૌ'), + ('ଂ', 'ଃ'), ('ା', 'ା'), ('ୀ', 'ୀ'), ('େ', 'ୈ'), + ('ୋ', 'ୌ'), ('ୗ', 'ୗ'), ('ா', 'ி'), ('ு', 'ூ'), + ('ெ', 'ை'), ('ொ', 'ௌ'), ('ௗ', 'ௗ'), ('ఁ', 'ః'), + ('ు', 'ౄ'), ('ಂ', 'ಃ'), ('ಾ', 'ಾ'), ('ೀ', 'ೄ'), + ('ೇ', 'ೈ'), ('ೊ', 'ೋ'), ('ೕ', 'ೖ'), ('ം', 'ഃ'), + ('à´¾', 'ീ'), ('െ', 'ൈ'), ('ൊ', 'ൌ'), ('ൗ', 'ൗ'), + ('ං', 'ඃ'), ('ා', 'ෑ'), ('ෘ', 'ෟ'), ('à·²', 'à·³'), + ('༾', '༿'), ('ཿ', 'ཿ'), ('ါ', 'ာ'), ('ေ', 'ေ'), + ('း', 'း'), ('ျ', 'ြ'), ('ၖ', 'ၗ'), ('ၢ', 'ၤ'), + ('ၧ', 'ၭ'), ('ႃ', 'ႄ'), ('ႇ', 'ႌ'), ('ႏ', 'ႏ'), + ('ႚ', 'ႜ'), ('ា', 'ា'), ('ើ', 'ៅ'), ('ះ', 'ៈ'), + ('ᤣ', 'ᤦ'), ('ᤩ', 'ᤫ'), ('ᤰ', 'ᤱ'), ('ᤳ', 'ᤸ'), + ('ᨙ', 'ᨚ'), ('ᩕ', 'ᩕ'), ('ᩗ', 'ᩗ'), ('á©¡', 'á©¡'), + ('á©£', 'ᩤ'), ('á©­', 'ᩲ'), ('ᬄ', 'ᬄ'), ('ᬵ', 'ᬵ'), + ('ᬻ', 'ᬻ'), ('ᬽ', 'ᭁ'), ('ᭃ', '᭄'), ('ᮂ', 'ᮂ'), + ('ᮡ', 'ᮡ'), ('ᮦ', 'á®§'), ('᮪', '᮪'), ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), ('ᯮ', 'ᯮ'), ('᯲', '᯳'), ('á°¤', 'á°«'), + ('á°´', 'á°µ'), ('᳡', '᳡'), ('á³²', 'á³³'), ('á³·', 'á³·'), + ('〮', '〯'), ('ê £', 'ê ¤'), ('ê §', 'ê §'), ('ꢀ', 'ꢁ'), + ('ꢴ', 'ꣃ'), ('ꥒ', '꥓'), ('ꦃ', 'ꦃ'), ('ꦴ', 'ꦵ'), + ('ꦺ', 'ꦻ'), ('ꦽ', '꧀'), ('ꨯ', 'ꨰ'), ('ꨳ', 'ꨴ'), + ('ꩍ', 'ꩍ'), ('ê©»', 'ê©»'), ('ꩽ', 'ꩽ'), ('ê««', 'ê««'), + ('ê«®', 'ꫯ'), ('ꫵ', 'ꫵ'), ('ꯣ', 'ꯤ'), ('ꯦ', 'ꯧ'), + ('ꯩ', 'ꯪ'), ('꯬', '꯬'), ('𑀀', '𑀀'), ('𑀂', '𑀂'), + ('𑂂', '𑂂'), ('𑂰', '𑂲'), ('𑂷', '𑂸'), ('𑄬', '𑄬'), + ('\u{11145}', '\u{11146}'), ('𑆂', '𑆂'), ('𑆳', '𑆵'), + ('𑆿', '𑇀'), ('𑈬', '𑈮'), ('𑈲', '𑈳'), ('𑈵', '𑈵'), + ('𑋠', '𑋢'), ('𑌂', '𑌃'), ('𑌾', '𑌿'), ('𑍁', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍗', '𑍗'), ('𑍢', '𑍣'), + ('𑐵', '𑐷'), ('𑑀', '𑑁'), ('𑑅', '𑑅'), ('𑒰', '𑒲'), + ('𑒹', '𑒹'), ('𑒻', '𑒾'), ('𑓁', '𑓁'), ('𑖯', '𑖱'), + ('𑖸', '𑖻'), ('𑖾', '𑖾'), ('𑘰', '𑘲'), ('𑘻', '𑘼'), + ('𑘾', '𑘾'), ('𑚬', '𑚬'), ('𑚮', '𑚯'), ('𑚶', '𑚶'), + ('𑜠', '𑜡'), ('𑜦', '𑜦'), ('\u{1182c}', '\u{1182e}'), + ('\u{11838}', '\u{11838}'), ('𑨹', '𑨹'), ('𑩗', '𑩘'), + ('𑪗', '𑪗'), ('𑰯', '𑰯'), ('𑰾', '𑰾'), ('𑲩', '𑲩'), + ('𑲱', '𑲱'), ('𑲴', '𑲴'), ('\u{11d8a}', '\u{11d8e}'), + ('\u{11d93}', '\u{11d94}'), ('\u{11d96}', '\u{11d96}'), + ('\u{11ef5}', '\u{11ef6}'), ('𖽑', '𖽾'), ('𝅥', '𝅦'), + ('𝅭', '𝅲'), +]; + +pub const SYMBOL: &'static [(char, char)] = &[ + ('$', '$'), ('+', '+'), ('<', '>'), ('^', '^'), ('`', '`'), ('|', '|'), + ('~', '~'), ('¢', '¦'), ('¨', '©'), ('¬', '¬'), ('®', '±'), + ('´', '´'), ('¸', '¸'), ('×', '×'), ('÷', '÷'), ('˂', '˅'), + ('˒', '˟'), ('Ë¥', 'Ë«'), ('Ë­', 'Ë­'), ('˯', 'Ë¿'), ('͵', '͵'), + ('΄', '΅'), ('϶', '϶'), ('҂', '҂'), ('֍', '֏'), ('؆', '؈'), + ('؋', '؋'), ('؎', '؏'), ('۞', '۞'), ('Û©', 'Û©'), ('Û½', 'Û¾'), + ('ß¶', 'ß¶'), ('\u{7fe}', '\u{7ff}'), ('à§²', 'à§³'), ('৺', 'à§»'), + ('૱', '૱'), ('à­°', 'à­°'), ('௳', '௺'), ('౿', '౿'), + ('൏', '൏'), ('൹', '൹'), ('฿', '฿'), ('༁', '༃'), + ('༓', '༓'), ('༕', '༗'), ('༚', '༟'), ('༴', '༴'), + ('༶', '༶'), ('༸', '༸'), ('྾', '࿅'), ('࿇', '࿌'), + ('࿎', '࿏'), ('࿕', '࿘'), ('႞', '႟'), ('᎐', '᎙'), + ('៛', '៛'), ('᥀', '᥀'), ('᧞', 'á§¿'), ('á­¡', 'á­ª'), + ('á­´', 'á­¼'), ('á¾½', 'á¾½'), ('᾿', '῁'), ('῍', '῏'), + ('῝', '῟'), ('á¿­', '`'), ('´', '῾'), ('⁄', '⁄'), + ('⁒', '⁒'), ('⁺', '⁼'), ('₊', '₌'), ('₠', '₿'), + ('℀', '℁'), ('℃', '℆'), ('℈', '℉'), ('℔', '℔'), + ('№', '℘'), ('℞', '℣'), ('℥', '℥'), ('℧', '℧'), + ('℩', '℩'), ('℮', '℮'), ('℺', '℻'), ('⅀', '⅄'), + ('⅊', '⅍'), ('⅏', '⅏'), ('↊', '↋'), ('←', '⌇'), + ('⌌', '⌨'), ('⌫', '␦'), ('⑀', '⑊'), ('⒜', 'ⓩ'), + ('─', '❧'), ('➔', '⟄'), ('⟇', '⟥'), ('⟰', '⦂'), + ('⦙', '⧗'), ('⧜', 'â§»'), ('â§¾', 'â­³'), ('â­¶', '⮕'), + ('⮘', '⯈'), ('⯊', '\u{2bfe}'), ('â³¥', '⳪'), ('⺀', '⺙'), + ('⺛', '⻳'), ('⼀', '⿕'), ('â¿°', 'â¿»'), ('〄', '〄'), + ('〒', '〓'), ('〠', '〠'), ('〶', '〷'), ('〾', '〿'), + ('゛', '゜'), ('㆐', '㆑'), ('㆖', '㆟'), ('㇀', '㇣'), + ('㈀', '㈞'), ('㈪', '㉇'), ('㉐', '㉐'), ('㉠', '㉿'), + ('㊊', '㊰'), ('㋀', '㋾'), ('㌀', '㏿'), ('䷀', 'ä·¿'), + ('꒐', '꓆'), ('꜀', '꜖'), ('꜠', '꜡'), ('꞉', '꞊'), + ('ê ¨', 'ê «'), ('ê ¶', 'ê ¹'), ('ê©·', '꩹'), ('꭛', '꭛'), + ('﬩', '﬩'), ('﮲', '﯁'), ('ï·¼', 'ï·½'), ('ï¹¢', 'ï¹¢'), + ('﹤', '﹦'), ('﹩', '﹩'), ('$', '$'), ('+', '+'), + ('<', '>'), ('ï¼¾', 'ï¼¾'), ('`', '`'), ('|', '|'), + ('~', '~'), ('ï¿ ', '₩'), ('│', 'ï¿®'), ('', '�'), + ('𐄷', '𐄿'), ('𐅹', '𐆉'), ('𐆌', '𐆎'), ('𐆐', '𐆛'), + ('𐆠', '𐆠'), ('𐇐', '𐇼'), ('𐡷', '𐡸'), ('𐫈', '𐫈'), + ('𑜿', '𑜿'), ('𖬼', '𖬿'), ('𖭅', '𖭅'), ('𛲜', '𛲜'), + ('𝀀', '𝃵'), ('𝄀', '𝄦'), ('𝄩', '𝅘𝅥𝅲'), ('𝅪', '𝅬'), + ('𝆃', '𝆄'), ('𝆌', '𝆩'), ('𝆮', '𝇨'), ('𝈀', '𝉁'), + ('𝉅', '𝉅'), ('𝌀', '𝍖'), ('𝛁', '𝛁'), ('𝛛', '𝛛'), + ('𝛻', '𝛻'), ('𝜕', '𝜕'), ('𝜵', '𝜵'), ('𝝏', '𝝏'), + ('𝝯', '𝝯'), ('𝞉', '𝞉'), ('𝞩', '𝞩'), ('𝟃', '𝟃'), + ('𝠀', '𝧿'), ('𝨷', '𝨺'), ('𝩭', '𝩴'), ('𝩶', '𝪃'), + ('𝪅', '𝪆'), ('\u{1ecac}', '\u{1ecac}'), ('\u{1ecb0}', '\u{1ecb0}'), + ('𞻰', '𞻱'), ('🀀', '🀫'), ('🀰', '🂓'), ('🂠', '🂮'), + ('🂱', '🂿'), ('🃁', '🃏'), ('🃑', '🃵'), ('🄐', '🅫'), + ('🅰', '🆬'), ('🇦', '🈂'), ('🈐', '🈻'), ('🉀', '🉈'), + ('🉐', '🉑'), ('🉠', '🉥'), ('🌀', '🛔'), ('🛠', '🛬'), + ('🛰', '\u{1f6f9}'), ('🜀', '🝳'), ('🞀', '\u{1f7d8}'), + ('🠀', '🠋'), ('🠐', '🡇'), ('🡐', '🡙'), ('🡠', '🢇'), + ('🢐', '🢭'), ('🤀', '🤋'), ('🤐', '🤾'), ('🥀', '\u{1f970}'), + ('\u{1f973}', '\u{1f976}'), ('\u{1f97a}', '\u{1f97a}'), + ('\u{1f97c}', '\u{1f9a2}'), ('\u{1f9b0}', '\u{1f9b9}'), + ('🧀', '\u{1f9c2}'), ('🧐', '\u{1f9ff}'), ('\u{1fa60}', '\u{1fa6d}'), +]; + +pub const TITLECASE_LETTER: &'static [(char, char)] = &[ + ('Dž', 'Dž'), ('Lj', 'Lj'), ('Nj', 'Nj'), ('Dz', 'Dz'), ('ᾈ', 'ᾏ'), + ('ᾘ', 'ᾟ'), ('ᾨ', 'ᾯ'), ('á¾¼', 'á¾¼'), ('ῌ', 'ῌ'), + ('ῼ', 'ῼ'), +]; + +pub const UNASSIGNED: &'static [(char, char)] = &[ + ('\u{378}', '\u{379}'), ('\u{380}', '\u{383}'), ('\u{38b}', '\u{38b}'), + ('\u{38d}', '\u{38d}'), ('\u{3a2}', '\u{3a2}'), ('\u{530}', '\u{530}'), + ('\u{557}', '\u{558}'), ('\u{58b}', '\u{58c}'), ('\u{590}', '\u{590}'), + ('\u{5c8}', '\u{5cf}'), ('\u{5eb}', '\u{5ee}'), ('\u{5f5}', '\u{5ff}'), + ('\u{61d}', '\u{61d}'), ('\u{70e}', '\u{70e}'), ('\u{74b}', '\u{74c}'), + ('\u{7b2}', '\u{7bf}'), ('\u{7fb}', '\u{7fc}'), ('\u{82e}', '\u{82f}'), + ('\u{83f}', '\u{83f}'), ('\u{85c}', '\u{85d}'), ('\u{85f}', '\u{85f}'), + ('\u{86b}', '\u{89f}'), ('\u{8b5}', '\u{8b5}'), ('\u{8be}', '\u{8d2}'), + ('\u{984}', '\u{984}'), ('\u{98d}', '\u{98e}'), ('\u{991}', '\u{992}'), + ('\u{9a9}', '\u{9a9}'), ('\u{9b1}', '\u{9b1}'), ('\u{9b3}', '\u{9b5}'), + ('\u{9ba}', '\u{9bb}'), ('\u{9c5}', '\u{9c6}'), ('\u{9c9}', '\u{9ca}'), + ('\u{9cf}', '\u{9d6}'), ('\u{9d8}', '\u{9db}'), ('\u{9de}', '\u{9de}'), + ('\u{9e4}', '\u{9e5}'), ('\u{9ff}', '\u{a00}'), ('\u{a04}', '\u{a04}'), + ('\u{a0b}', '\u{a0e}'), ('\u{a11}', '\u{a12}'), ('\u{a29}', '\u{a29}'), + ('\u{a31}', '\u{a31}'), ('\u{a34}', '\u{a34}'), ('\u{a37}', '\u{a37}'), + ('\u{a3a}', '\u{a3b}'), ('\u{a3d}', '\u{a3d}'), ('\u{a43}', '\u{a46}'), + ('\u{a49}', '\u{a4a}'), ('\u{a4e}', '\u{a50}'), ('\u{a52}', '\u{a58}'), + ('\u{a5d}', '\u{a5d}'), ('\u{a5f}', '\u{a65}'), ('\u{a77}', '\u{a80}'), + ('\u{a84}', '\u{a84}'), ('\u{a8e}', '\u{a8e}'), ('\u{a92}', '\u{a92}'), + ('\u{aa9}', '\u{aa9}'), ('\u{ab1}', '\u{ab1}'), ('\u{ab4}', '\u{ab4}'), + ('\u{aba}', '\u{abb}'), ('\u{ac6}', '\u{ac6}'), ('\u{aca}', '\u{aca}'), + ('\u{ace}', '\u{acf}'), ('\u{ad1}', '\u{adf}'), ('\u{ae4}', '\u{ae5}'), + ('\u{af2}', '\u{af8}'), ('\u{b00}', '\u{b00}'), ('\u{b04}', '\u{b04}'), + ('\u{b0d}', '\u{b0e}'), ('\u{b11}', '\u{b12}'), ('\u{b29}', '\u{b29}'), + ('\u{b31}', '\u{b31}'), ('\u{b34}', '\u{b34}'), ('\u{b3a}', '\u{b3b}'), + ('\u{b45}', '\u{b46}'), ('\u{b49}', '\u{b4a}'), ('\u{b4e}', '\u{b55}'), + ('\u{b58}', '\u{b5b}'), ('\u{b5e}', '\u{b5e}'), ('\u{b64}', '\u{b65}'), + ('\u{b78}', '\u{b81}'), ('\u{b84}', '\u{b84}'), ('\u{b8b}', '\u{b8d}'), + ('\u{b91}', '\u{b91}'), ('\u{b96}', '\u{b98}'), ('\u{b9b}', '\u{b9b}'), + ('\u{b9d}', '\u{b9d}'), ('\u{ba0}', '\u{ba2}'), ('\u{ba5}', '\u{ba7}'), + ('\u{bab}', '\u{bad}'), ('\u{bba}', '\u{bbd}'), ('\u{bc3}', '\u{bc5}'), + ('\u{bc9}', '\u{bc9}'), ('\u{bce}', '\u{bcf}'), ('\u{bd1}', '\u{bd6}'), + ('\u{bd8}', '\u{be5}'), ('\u{bfb}', '\u{bff}'), ('\u{c0d}', '\u{c0d}'), + ('\u{c11}', '\u{c11}'), ('\u{c29}', '\u{c29}'), ('\u{c3a}', '\u{c3c}'), + ('\u{c45}', '\u{c45}'), ('\u{c49}', '\u{c49}'), ('\u{c4e}', '\u{c54}'), + ('\u{c57}', '\u{c57}'), ('\u{c5b}', '\u{c5f}'), ('\u{c64}', '\u{c65}'), + ('\u{c70}', '\u{c77}'), ('\u{c8d}', '\u{c8d}'), ('\u{c91}', '\u{c91}'), + ('\u{ca9}', '\u{ca9}'), ('\u{cb4}', '\u{cb4}'), ('\u{cba}', '\u{cbb}'), + ('\u{cc5}', '\u{cc5}'), ('\u{cc9}', '\u{cc9}'), ('\u{cce}', '\u{cd4}'), + ('\u{cd7}', '\u{cdd}'), ('\u{cdf}', '\u{cdf}'), ('\u{ce4}', '\u{ce5}'), + ('\u{cf0}', '\u{cf0}'), ('\u{cf3}', '\u{cff}'), ('\u{d04}', '\u{d04}'), + ('\u{d0d}', '\u{d0d}'), ('\u{d11}', '\u{d11}'), ('\u{d45}', '\u{d45}'), + ('\u{d49}', '\u{d49}'), ('\u{d50}', '\u{d53}'), ('\u{d64}', '\u{d65}'), + ('\u{d80}', '\u{d81}'), ('\u{d84}', '\u{d84}'), ('\u{d97}', '\u{d99}'), + ('\u{db2}', '\u{db2}'), ('\u{dbc}', '\u{dbc}'), ('\u{dbe}', '\u{dbf}'), + ('\u{dc7}', '\u{dc9}'), ('\u{dcb}', '\u{dce}'), ('\u{dd5}', '\u{dd5}'), + ('\u{dd7}', '\u{dd7}'), ('\u{de0}', '\u{de5}'), ('\u{df0}', '\u{df1}'), + ('\u{df5}', '\u{e00}'), ('\u{e3b}', '\u{e3e}'), ('\u{e5c}', '\u{e80}'), + ('\u{e83}', '\u{e83}'), ('\u{e85}', '\u{e86}'), ('\u{e89}', '\u{e89}'), + ('\u{e8b}', '\u{e8c}'), ('\u{e8e}', '\u{e93}'), ('\u{e98}', '\u{e98}'), + ('\u{ea0}', '\u{ea0}'), ('\u{ea4}', '\u{ea4}'), ('\u{ea6}', '\u{ea6}'), + ('\u{ea8}', '\u{ea9}'), ('\u{eac}', '\u{eac}'), ('\u{eba}', '\u{eba}'), + ('\u{ebe}', '\u{ebf}'), ('\u{ec5}', '\u{ec5}'), ('\u{ec7}', '\u{ec7}'), + ('\u{ece}', '\u{ecf}'), ('\u{eda}', '\u{edb}'), ('\u{ee0}', '\u{eff}'), + ('\u{f48}', '\u{f48}'), ('\u{f6d}', '\u{f70}'), ('\u{f98}', '\u{f98}'), + ('\u{fbd}', '\u{fbd}'), ('\u{fcd}', '\u{fcd}'), ('\u{fdb}', '\u{fff}'), + ('\u{10c6}', '\u{10c6}'), ('\u{10c8}', '\u{10cc}'), + ('\u{10ce}', '\u{10cf}'), ('\u{1249}', '\u{1249}'), + ('\u{124e}', '\u{124f}'), ('\u{1257}', '\u{1257}'), + ('\u{1259}', '\u{1259}'), ('\u{125e}', '\u{125f}'), + ('\u{1289}', '\u{1289}'), ('\u{128e}', '\u{128f}'), + ('\u{12b1}', '\u{12b1}'), ('\u{12b6}', '\u{12b7}'), + ('\u{12bf}', '\u{12bf}'), ('\u{12c1}', '\u{12c1}'), + ('\u{12c6}', '\u{12c7}'), ('\u{12d7}', '\u{12d7}'), + ('\u{1311}', '\u{1311}'), ('\u{1316}', '\u{1317}'), + ('\u{135b}', '\u{135c}'), ('\u{137d}', '\u{137f}'), + ('\u{139a}', '\u{139f}'), ('\u{13f6}', '\u{13f7}'), + ('\u{13fe}', '\u{13ff}'), ('\u{169d}', '\u{169f}'), + ('\u{16f9}', '\u{16ff}'), ('\u{170d}', '\u{170d}'), + ('\u{1715}', '\u{171f}'), ('\u{1737}', '\u{173f}'), + ('\u{1754}', '\u{175f}'), ('\u{176d}', '\u{176d}'), + ('\u{1771}', '\u{1771}'), ('\u{1774}', '\u{177f}'), + ('\u{17de}', '\u{17df}'), ('\u{17ea}', '\u{17ef}'), + ('\u{17fa}', '\u{17ff}'), ('\u{180f}', '\u{180f}'), + ('\u{181a}', '\u{181f}'), ('\u{1879}', '\u{187f}'), + ('\u{18ab}', '\u{18af}'), ('\u{18f6}', '\u{18ff}'), + ('\u{191f}', '\u{191f}'), ('\u{192c}', '\u{192f}'), + ('\u{193c}', '\u{193f}'), ('\u{1941}', '\u{1943}'), + ('\u{196e}', '\u{196f}'), ('\u{1975}', '\u{197f}'), + ('\u{19ac}', '\u{19af}'), ('\u{19ca}', '\u{19cf}'), + ('\u{19db}', '\u{19dd}'), ('\u{1a1c}', '\u{1a1d}'), + ('\u{1a5f}', '\u{1a5f}'), ('\u{1a7d}', '\u{1a7e}'), + ('\u{1a8a}', '\u{1a8f}'), ('\u{1a9a}', '\u{1a9f}'), + ('\u{1aae}', '\u{1aaf}'), ('\u{1abf}', '\u{1aff}'), + ('\u{1b4c}', '\u{1b4f}'), ('\u{1b7d}', '\u{1b7f}'), + ('\u{1bf4}', '\u{1bfb}'), ('\u{1c38}', '\u{1c3a}'), + ('\u{1c4a}', '\u{1c4c}'), ('\u{1c89}', '\u{1c8f}'), + ('\u{1cbb}', '\u{1cbc}'), ('\u{1cc8}', '\u{1ccf}'), + ('\u{1cfa}', '\u{1cff}'), ('\u{1dfa}', '\u{1dfa}'), + ('\u{1f16}', '\u{1f17}'), ('\u{1f1e}', '\u{1f1f}'), + ('\u{1f46}', '\u{1f47}'), ('\u{1f4e}', '\u{1f4f}'), + ('\u{1f58}', '\u{1f58}'), ('\u{1f5a}', '\u{1f5a}'), + ('\u{1f5c}', '\u{1f5c}'), ('\u{1f5e}', '\u{1f5e}'), + ('\u{1f7e}', '\u{1f7f}'), ('\u{1fb5}', '\u{1fb5}'), + ('\u{1fc5}', '\u{1fc5}'), ('\u{1fd4}', '\u{1fd5}'), + ('\u{1fdc}', '\u{1fdc}'), ('\u{1ff0}', '\u{1ff1}'), + ('\u{1ff5}', '\u{1ff5}'), ('\u{1fff}', '\u{1fff}'), + ('\u{2065}', '\u{2065}'), ('\u{2072}', '\u{2073}'), + ('\u{208f}', '\u{208f}'), ('\u{209d}', '\u{209f}'), + ('\u{20c0}', '\u{20cf}'), ('\u{20f1}', '\u{20ff}'), + ('\u{218c}', '\u{218f}'), ('\u{2427}', '\u{243f}'), + ('\u{244b}', '\u{245f}'), ('\u{2b74}', '\u{2b75}'), + ('\u{2b96}', '\u{2b97}'), ('\u{2bc9}', '\u{2bc9}'), + ('\u{2bff}', '\u{2bff}'), ('\u{2c2f}', '\u{2c2f}'), + ('\u{2c5f}', '\u{2c5f}'), ('\u{2cf4}', '\u{2cf8}'), + ('\u{2d26}', '\u{2d26}'), ('\u{2d28}', '\u{2d2c}'), + ('\u{2d2e}', '\u{2d2f}'), ('\u{2d68}', '\u{2d6e}'), + ('\u{2d71}', '\u{2d7e}'), ('\u{2d97}', '\u{2d9f}'), + ('\u{2da7}', '\u{2da7}'), ('\u{2daf}', '\u{2daf}'), + ('\u{2db7}', '\u{2db7}'), ('\u{2dbf}', '\u{2dbf}'), + ('\u{2dc7}', '\u{2dc7}'), ('\u{2dcf}', '\u{2dcf}'), + ('\u{2dd7}', '\u{2dd7}'), ('\u{2ddf}', '\u{2ddf}'), + ('\u{2e4f}', '\u{2e7f}'), ('\u{2e9a}', '\u{2e9a}'), + ('\u{2ef4}', '\u{2eff}'), ('\u{2fd6}', '\u{2fef}'), + ('\u{2ffc}', '\u{2fff}'), ('\u{3040}', '\u{3040}'), + ('\u{3097}', '\u{3098}'), ('\u{3100}', '\u{3104}'), + ('\u{3130}', '\u{3130}'), ('\u{318f}', '\u{318f}'), + ('\u{31bb}', '\u{31bf}'), ('\u{31e4}', '\u{31ef}'), + ('\u{321f}', '\u{321f}'), ('\u{32ff}', '\u{32ff}'), + ('\u{4db6}', '\u{4dbf}'), ('\u{9ff0}', '\u{9fff}'), + ('\u{a48d}', '\u{a48f}'), ('\u{a4c7}', '\u{a4cf}'), + ('\u{a62c}', '\u{a63f}'), ('\u{a6f8}', '\u{a6ff}'), + ('\u{a7ba}', '\u{a7f6}'), ('\u{a82c}', '\u{a82f}'), + ('\u{a83a}', '\u{a83f}'), ('\u{a878}', '\u{a87f}'), + ('\u{a8c6}', '\u{a8cd}'), ('\u{a8da}', '\u{a8df}'), + ('\u{a954}', '\u{a95e}'), ('\u{a97d}', '\u{a97f}'), + ('\u{a9ce}', '\u{a9ce}'), ('\u{a9da}', '\u{a9dd}'), + ('\u{a9ff}', '\u{a9ff}'), ('\u{aa37}', '\u{aa3f}'), + ('\u{aa4e}', '\u{aa4f}'), ('\u{aa5a}', '\u{aa5b}'), + ('\u{aac3}', '\u{aada}'), ('\u{aaf7}', '\u{ab00}'), + ('\u{ab07}', '\u{ab08}'), ('\u{ab0f}', '\u{ab10}'), + ('\u{ab17}', '\u{ab1f}'), ('\u{ab27}', '\u{ab27}'), + ('\u{ab2f}', '\u{ab2f}'), ('\u{ab66}', '\u{ab6f}'), + ('\u{abee}', '\u{abef}'), ('\u{abfa}', '\u{abff}'), + ('\u{d7a4}', '\u{d7af}'), ('\u{d7c7}', '\u{d7ca}'), + ('\u{d7fc}', '\u{d7ff}'), ('\u{fa6e}', '\u{fa6f}'), + ('\u{fada}', '\u{faff}'), ('\u{fb07}', '\u{fb12}'), + ('\u{fb18}', '\u{fb1c}'), ('\u{fb37}', '\u{fb37}'), + ('\u{fb3d}', '\u{fb3d}'), ('\u{fb3f}', '\u{fb3f}'), + ('\u{fb42}', '\u{fb42}'), ('\u{fb45}', '\u{fb45}'), + ('\u{fbc2}', '\u{fbd2}'), ('\u{fd40}', '\u{fd4f}'), + ('\u{fd90}', '\u{fd91}'), ('\u{fdc8}', '\u{fdef}'), + ('\u{fdfe}', '\u{fdff}'), ('\u{fe1a}', '\u{fe1f}'), + ('\u{fe53}', '\u{fe53}'), ('\u{fe67}', '\u{fe67}'), + ('\u{fe6c}', '\u{fe6f}'), ('\u{fe75}', '\u{fe75}'), + ('\u{fefd}', '\u{fefe}'), ('\u{ff00}', '\u{ff00}'), + ('\u{ffbf}', '\u{ffc1}'), ('\u{ffc8}', '\u{ffc9}'), + ('\u{ffd0}', '\u{ffd1}'), ('\u{ffd8}', '\u{ffd9}'), + ('\u{ffdd}', '\u{ffdf}'), ('\u{ffe7}', '\u{ffe7}'), + ('\u{ffef}', '\u{fff8}'), ('\u{fffe}', '\u{ffff}'), + ('\u{1000c}', '\u{1000c}'), ('\u{10027}', '\u{10027}'), + ('\u{1003b}', '\u{1003b}'), ('\u{1003e}', '\u{1003e}'), + ('\u{1004e}', '\u{1004f}'), ('\u{1005e}', '\u{1007f}'), + ('\u{100fb}', '\u{100ff}'), ('\u{10103}', '\u{10106}'), + ('\u{10134}', '\u{10136}'), ('\u{1018f}', '\u{1018f}'), + ('\u{1019c}', '\u{1019f}'), ('\u{101a1}', '\u{101cf}'), + ('\u{101fe}', '\u{1027f}'), ('\u{1029d}', '\u{1029f}'), + ('\u{102d1}', '\u{102df}'), ('\u{102fc}', '\u{102ff}'), + ('\u{10324}', '\u{1032c}'), ('\u{1034b}', '\u{1034f}'), + ('\u{1037b}', '\u{1037f}'), ('\u{1039e}', '\u{1039e}'), + ('\u{103c4}', '\u{103c7}'), ('\u{103d6}', '\u{103ff}'), + ('\u{1049e}', '\u{1049f}'), ('\u{104aa}', '\u{104af}'), + ('\u{104d4}', '\u{104d7}'), ('\u{104fc}', '\u{104ff}'), + ('\u{10528}', '\u{1052f}'), ('\u{10564}', '\u{1056e}'), + ('\u{10570}', '\u{105ff}'), ('\u{10737}', '\u{1073f}'), + ('\u{10756}', '\u{1075f}'), ('\u{10768}', '\u{107ff}'), + ('\u{10806}', '\u{10807}'), ('\u{10809}', '\u{10809}'), + ('\u{10836}', '\u{10836}'), ('\u{10839}', '\u{1083b}'), + ('\u{1083d}', '\u{1083e}'), ('\u{10856}', '\u{10856}'), + ('\u{1089f}', '\u{108a6}'), ('\u{108b0}', '\u{108df}'), + ('\u{108f3}', '\u{108f3}'), ('\u{108f6}', '\u{108fa}'), + ('\u{1091c}', '\u{1091e}'), ('\u{1093a}', '\u{1093e}'), + ('\u{10940}', '\u{1097f}'), ('\u{109b8}', '\u{109bb}'), + ('\u{109d0}', '\u{109d1}'), ('\u{10a04}', '\u{10a04}'), + ('\u{10a07}', '\u{10a0b}'), ('\u{10a14}', '\u{10a14}'), + ('\u{10a18}', '\u{10a18}'), ('\u{10a36}', '\u{10a37}'), + ('\u{10a3b}', '\u{10a3e}'), ('\u{10a49}', '\u{10a4f}'), + ('\u{10a59}', '\u{10a5f}'), ('\u{10aa0}', '\u{10abf}'), + ('\u{10ae7}', '\u{10aea}'), ('\u{10af7}', '\u{10aff}'), + ('\u{10b36}', '\u{10b38}'), ('\u{10b56}', '\u{10b57}'), + ('\u{10b73}', '\u{10b77}'), ('\u{10b92}', '\u{10b98}'), + ('\u{10b9d}', '\u{10ba8}'), ('\u{10bb0}', '\u{10bff}'), + ('\u{10c49}', '\u{10c7f}'), ('\u{10cb3}', '\u{10cbf}'), + ('\u{10cf3}', '\u{10cf9}'), ('\u{10d28}', '\u{10d2f}'), + ('\u{10d3a}', '\u{10e5f}'), ('\u{10e7f}', '\u{10eff}'), + ('\u{10f28}', '\u{10f2f}'), ('\u{10f5a}', '\u{10fff}'), + ('\u{1104e}', '\u{11051}'), ('\u{11070}', '\u{1107e}'), + ('\u{110c2}', '\u{110cc}'), ('\u{110ce}', '\u{110cf}'), + ('\u{110e9}', '\u{110ef}'), ('\u{110fa}', '\u{110ff}'), + ('\u{11135}', '\u{11135}'), ('\u{11147}', '\u{1114f}'), + ('\u{11177}', '\u{1117f}'), ('\u{111ce}', '\u{111cf}'), + ('\u{111e0}', '\u{111e0}'), ('\u{111f5}', '\u{111ff}'), + ('\u{11212}', '\u{11212}'), ('\u{1123f}', '\u{1127f}'), + ('\u{11287}', '\u{11287}'), ('\u{11289}', '\u{11289}'), + ('\u{1128e}', '\u{1128e}'), ('\u{1129e}', '\u{1129e}'), + ('\u{112aa}', '\u{112af}'), ('\u{112eb}', '\u{112ef}'), + ('\u{112fa}', '\u{112ff}'), ('\u{11304}', '\u{11304}'), + ('\u{1130d}', '\u{1130e}'), ('\u{11311}', '\u{11312}'), + ('\u{11329}', '\u{11329}'), ('\u{11331}', '\u{11331}'), + ('\u{11334}', '\u{11334}'), ('\u{1133a}', '\u{1133a}'), + ('\u{11345}', '\u{11346}'), ('\u{11349}', '\u{1134a}'), + ('\u{1134e}', '\u{1134f}'), ('\u{11351}', '\u{11356}'), + ('\u{11358}', '\u{1135c}'), ('\u{11364}', '\u{11365}'), + ('\u{1136d}', '\u{1136f}'), ('\u{11375}', '\u{113ff}'), + ('\u{1145a}', '\u{1145a}'), ('\u{1145c}', '\u{1145c}'), + ('\u{1145f}', '\u{1147f}'), ('\u{114c8}', '\u{114cf}'), + ('\u{114da}', '\u{1157f}'), ('\u{115b6}', '\u{115b7}'), + ('\u{115de}', '\u{115ff}'), ('\u{11645}', '\u{1164f}'), + ('\u{1165a}', '\u{1165f}'), ('\u{1166d}', '\u{1167f}'), + ('\u{116b8}', '\u{116bf}'), ('\u{116ca}', '\u{116ff}'), + ('\u{1171b}', '\u{1171c}'), ('\u{1172c}', '\u{1172f}'), + ('\u{11740}', '\u{117ff}'), ('\u{1183c}', '\u{1189f}'), + ('\u{118f3}', '\u{118fe}'), ('\u{11900}', '\u{119ff}'), + ('\u{11a48}', '\u{11a4f}'), ('\u{11a84}', '\u{11a85}'), + ('\u{11aa3}', '\u{11abf}'), ('\u{11af9}', '\u{11bff}'), + ('\u{11c09}', '\u{11c09}'), ('\u{11c37}', '\u{11c37}'), + ('\u{11c46}', '\u{11c4f}'), ('\u{11c6d}', '\u{11c6f}'), + ('\u{11c90}', '\u{11c91}'), ('\u{11ca8}', '\u{11ca8}'), + ('\u{11cb7}', '\u{11cff}'), ('\u{11d07}', '\u{11d07}'), + ('\u{11d0a}', '\u{11d0a}'), ('\u{11d37}', '\u{11d39}'), + ('\u{11d3b}', '\u{11d3b}'), ('\u{11d3e}', '\u{11d3e}'), + ('\u{11d48}', '\u{11d4f}'), ('\u{11d5a}', '\u{11d5f}'), + ('\u{11d66}', '\u{11d66}'), ('\u{11d69}', '\u{11d69}'), + ('\u{11d8f}', '\u{11d8f}'), ('\u{11d92}', '\u{11d92}'), + ('\u{11d99}', '\u{11d9f}'), ('\u{11daa}', '\u{11edf}'), + ('\u{11ef9}', '\u{11fff}'), ('\u{1239a}', '\u{123ff}'), + ('\u{1246f}', '\u{1246f}'), ('\u{12475}', '\u{1247f}'), + ('\u{12544}', '\u{12fff}'), ('\u{1342f}', '\u{143ff}'), + ('\u{14647}', '\u{167ff}'), ('\u{16a39}', '\u{16a3f}'), + ('\u{16a5f}', '\u{16a5f}'), ('\u{16a6a}', '\u{16a6d}'), + ('\u{16a70}', '\u{16acf}'), ('\u{16aee}', '\u{16aef}'), + ('\u{16af6}', '\u{16aff}'), ('\u{16b46}', '\u{16b4f}'), + ('\u{16b5a}', '\u{16b5a}'), ('\u{16b62}', '\u{16b62}'), + ('\u{16b78}', '\u{16b7c}'), ('\u{16b90}', '\u{16e3f}'), + ('\u{16e9b}', '\u{16eff}'), ('\u{16f45}', '\u{16f4f}'), + ('\u{16f7f}', '\u{16f8e}'), ('\u{16fa0}', '\u{16fdf}'), + ('\u{16fe2}', '\u{16fff}'), ('\u{187f2}', '\u{187ff}'), + ('\u{18af3}', '\u{1afff}'), ('\u{1b11f}', '\u{1b16f}'), + ('\u{1b2fc}', '\u{1bbff}'), ('\u{1bc6b}', '\u{1bc6f}'), + ('\u{1bc7d}', '\u{1bc7f}'), ('\u{1bc89}', '\u{1bc8f}'), + ('\u{1bc9a}', '\u{1bc9b}'), ('\u{1bca4}', '\u{1cfff}'), + ('\u{1d0f6}', '\u{1d0ff}'), ('\u{1d127}', '\u{1d128}'), + ('\u{1d1e9}', '\u{1d1ff}'), ('\u{1d246}', '\u{1d2df}'), + ('\u{1d2f4}', '\u{1d2ff}'), ('\u{1d357}', '\u{1d35f}'), + ('\u{1d379}', '\u{1d3ff}'), ('\u{1d455}', '\u{1d455}'), + ('\u{1d49d}', '\u{1d49d}'), ('\u{1d4a0}', '\u{1d4a1}'), + ('\u{1d4a3}', '\u{1d4a4}'), ('\u{1d4a7}', '\u{1d4a8}'), + ('\u{1d4ad}', '\u{1d4ad}'), ('\u{1d4ba}', '\u{1d4ba}'), + ('\u{1d4bc}', '\u{1d4bc}'), ('\u{1d4c4}', '\u{1d4c4}'), + ('\u{1d506}', '\u{1d506}'), ('\u{1d50b}', '\u{1d50c}'), + ('\u{1d515}', '\u{1d515}'), ('\u{1d51d}', '\u{1d51d}'), + ('\u{1d53a}', '\u{1d53a}'), ('\u{1d53f}', '\u{1d53f}'), + ('\u{1d545}', '\u{1d545}'), ('\u{1d547}', '\u{1d549}'), + ('\u{1d551}', '\u{1d551}'), ('\u{1d6a6}', '\u{1d6a7}'), + ('\u{1d7cc}', '\u{1d7cd}'), ('\u{1da8c}', '\u{1da9a}'), + ('\u{1daa0}', '\u{1daa0}'), ('\u{1dab0}', '\u{1dfff}'), + ('\u{1e007}', '\u{1e007}'), ('\u{1e019}', '\u{1e01a}'), + ('\u{1e022}', '\u{1e022}'), ('\u{1e025}', '\u{1e025}'), + ('\u{1e02b}', '\u{1e7ff}'), ('\u{1e8c5}', '\u{1e8c6}'), + ('\u{1e8d7}', '\u{1e8ff}'), ('\u{1e94b}', '\u{1e94f}'), + ('\u{1e95a}', '\u{1e95d}'), ('\u{1e960}', '\u{1ec70}'), + ('\u{1ecb5}', '\u{1edff}'), ('\u{1ee04}', '\u{1ee04}'), + ('\u{1ee20}', '\u{1ee20}'), ('\u{1ee23}', '\u{1ee23}'), + ('\u{1ee25}', '\u{1ee26}'), ('\u{1ee28}', '\u{1ee28}'), + ('\u{1ee33}', '\u{1ee33}'), ('\u{1ee38}', '\u{1ee38}'), + ('\u{1ee3a}', '\u{1ee3a}'), ('\u{1ee3c}', '\u{1ee41}'), + ('\u{1ee43}', '\u{1ee46}'), ('\u{1ee48}', '\u{1ee48}'), + ('\u{1ee4a}', '\u{1ee4a}'), ('\u{1ee4c}', '\u{1ee4c}'), + ('\u{1ee50}', '\u{1ee50}'), ('\u{1ee53}', '\u{1ee53}'), + ('\u{1ee55}', '\u{1ee56}'), ('\u{1ee58}', '\u{1ee58}'), + ('\u{1ee5a}', '\u{1ee5a}'), ('\u{1ee5c}', '\u{1ee5c}'), + ('\u{1ee5e}', '\u{1ee5e}'), ('\u{1ee60}', '\u{1ee60}'), + ('\u{1ee63}', '\u{1ee63}'), ('\u{1ee65}', '\u{1ee66}'), + ('\u{1ee6b}', '\u{1ee6b}'), ('\u{1ee73}', '\u{1ee73}'), + ('\u{1ee78}', '\u{1ee78}'), ('\u{1ee7d}', '\u{1ee7d}'), + ('\u{1ee7f}', '\u{1ee7f}'), ('\u{1ee8a}', '\u{1ee8a}'), + ('\u{1ee9c}', '\u{1eea0}'), ('\u{1eea4}', '\u{1eea4}'), + ('\u{1eeaa}', '\u{1eeaa}'), ('\u{1eebc}', '\u{1eeef}'), + ('\u{1eef2}', '\u{1efff}'), ('\u{1f02c}', '\u{1f02f}'), + ('\u{1f094}', '\u{1f09f}'), ('\u{1f0af}', '\u{1f0b0}'), + ('\u{1f0c0}', '\u{1f0c0}'), ('\u{1f0d0}', '\u{1f0d0}'), + ('\u{1f0f6}', '\u{1f0ff}'), ('\u{1f10d}', '\u{1f10f}'), + ('\u{1f16c}', '\u{1f16f}'), ('\u{1f1ad}', '\u{1f1e5}'), + ('\u{1f203}', '\u{1f20f}'), ('\u{1f23c}', '\u{1f23f}'), + ('\u{1f249}', '\u{1f24f}'), ('\u{1f252}', '\u{1f25f}'), + ('\u{1f266}', '\u{1f2ff}'), ('\u{1f6d5}', '\u{1f6df}'), + ('\u{1f6ed}', '\u{1f6ef}'), ('\u{1f6fa}', '\u{1f6ff}'), + ('\u{1f774}', '\u{1f77f}'), ('\u{1f7d9}', '\u{1f7ff}'), + ('\u{1f80c}', '\u{1f80f}'), ('\u{1f848}', '\u{1f84f}'), + ('\u{1f85a}', '\u{1f85f}'), ('\u{1f888}', '\u{1f88f}'), + ('\u{1f8ae}', '\u{1f8ff}'), ('\u{1f90c}', '\u{1f90f}'), + ('\u{1f93f}', '\u{1f93f}'), ('\u{1f971}', '\u{1f972}'), + ('\u{1f977}', '\u{1f979}'), ('\u{1f97b}', '\u{1f97b}'), + ('\u{1f9a3}', '\u{1f9af}'), ('\u{1f9ba}', '\u{1f9bf}'), + ('\u{1f9c3}', '\u{1f9cf}'), ('\u{1fa00}', '\u{1fa5f}'), + ('\u{1fa6e}', '\u{1ffff}'), ('\u{2a6d7}', '\u{2a6ff}'), + ('\u{2b735}', '\u{2b73f}'), ('\u{2b81e}', '\u{2b81f}'), + ('\u{2cea2}', '\u{2ceaf}'), ('\u{2ebe1}', '\u{2f7ff}'), + ('\u{2fa1e}', '\u{e0000}'), ('\u{e0002}', '\u{e001f}'), + ('\u{e0080}', '\u{e00ff}'), ('\u{e01f0}', '\u{effff}'), + ('\u{ffffe}', '\u{fffff}'), ('\u{10fffe}', '\u{10ffff}'), +]; + +pub const UPPERCASE_LETTER: &'static [(char, char)] = &[ + ('A', 'Z'), ('À', 'Ö'), ('Ø', 'Þ'), ('Ā', 'Ā'), ('Ă', 'Ă'), + ('Ą', 'Ą'), ('Ć', 'Ć'), ('Ĉ', 'Ĉ'), ('Ċ', 'Ċ'), ('Č', 'Č'), + ('Ď', 'Ď'), ('Đ', 'Đ'), ('Ē', 'Ē'), ('Ĕ', 'Ĕ'), ('Ė', 'Ė'), + ('Ę', 'Ę'), ('Ě', 'Ě'), ('Ĝ', 'Ĝ'), ('Ğ', 'Ğ'), ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), ('Ĥ', 'Ĥ'), ('Ħ', 'Ħ'), ('Ĩ', 'Ĩ'), ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), ('Ä®', 'Ä®'), ('İ', 'İ'), ('IJ', 'IJ'), ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), ('Ĺ', 'Ĺ'), ('Ä»', 'Ä»'), ('Ľ', 'Ľ'), ('Ä¿', 'Ä¿'), + ('Ł', 'Ł'), ('Ń', 'Ń'), ('Ņ', 'Ņ'), ('Ň', 'Ň'), ('Ŋ', 'Ŋ'), + ('Ō', 'Ō'), ('Ŏ', 'Ŏ'), ('Ő', 'Ő'), ('Œ', 'Œ'), ('Ŕ', 'Ŕ'), + ('Ŗ', 'Ŗ'), ('Ř', 'Ř'), ('Ś', 'Ś'), ('Ŝ', 'Ŝ'), ('Ş', 'Ş'), + ('Å ', 'Å '), ('Å¢', 'Å¢'), ('Ť', 'Ť'), ('Ŧ', 'Ŧ'), ('Ũ', 'Ũ'), + ('Ū', 'Ū'), ('Ŭ', 'Ŭ'), ('Å®', 'Å®'), ('Ű', 'Ű'), ('Ų', 'Ų'), + ('Å´', 'Å´'), ('Ŷ', 'Ŷ'), ('Ÿ', 'Ź'), ('Å»', 'Å»'), ('Ž', 'Ž'), + ('Ɓ', 'Ƃ'), ('Ƅ', 'Ƅ'), ('Ɔ', 'Ƈ'), ('Ɖ', 'Ƌ'), ('Ǝ', 'Ƒ'), + ('Ɠ', 'Ɣ'), ('Ɩ', 'Ƙ'), ('Ɯ', 'Ɲ'), ('Ɵ', 'Æ '), ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), ('Ʀ', 'Ƨ'), ('Æ©', 'Æ©'), ('Ƭ', 'Ƭ'), ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), ('Ƶ', 'Ƶ'), ('Æ·', 'Ƹ'), ('Ƽ', 'Ƽ'), ('DŽ', 'DŽ'), + ('LJ', 'LJ'), ('NJ', 'NJ'), ('Ǎ', 'Ǎ'), ('Ǐ', 'Ǐ'), ('Ǒ', 'Ǒ'), + ('Ǔ', 'Ǔ'), ('Ǖ', 'Ǖ'), ('Ǘ', 'Ǘ'), ('Ǚ', 'Ǚ'), ('Ǜ', 'Ǜ'), + ('Ǟ', 'Ǟ'), ('Ç ', 'Ç '), ('Ç¢', 'Ç¢'), ('Ǥ', 'Ǥ'), ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), ('Ǫ', 'Ǫ'), ('Ǭ', 'Ǭ'), ('Ç®', 'Ç®'), ('DZ', 'DZ'), + ('Ç´', 'Ç´'), ('Ƕ', 'Ǹ'), ('Ǻ', 'Ǻ'), ('Ǽ', 'Ǽ'), ('Ǿ', 'Ǿ'), + ('Ȁ', 'Ȁ'), ('Ȃ', 'Ȃ'), ('Ȅ', 'Ȅ'), ('Ȇ', 'Ȇ'), ('Ȉ', 'Ȉ'), + ('Ȋ', 'Ȋ'), ('Ȍ', 'Ȍ'), ('Ȏ', 'Ȏ'), ('Ȑ', 'Ȑ'), ('Ȓ', 'Ȓ'), + ('Ȕ', 'Ȕ'), ('Ȗ', 'Ȗ'), ('Ș', 'Ș'), ('Ț', 'Ț'), ('Ȝ', 'Ȝ'), + ('Ȟ', 'Ȟ'), ('È ', 'È '), ('È¢', 'È¢'), ('Ȥ', 'Ȥ'), ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), ('Ȫ', 'Ȫ'), ('Ȭ', 'Ȭ'), ('È®', 'È®'), ('Ȱ', 'Ȱ'), + ('Ȳ', 'Ȳ'), ('Ⱥ', 'È»'), ('Ƚ', 'Ⱦ'), ('Ɂ', 'Ɂ'), ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), ('Ɋ', 'Ɋ'), ('Ɍ', 'Ɍ'), ('Ɏ', 'Ɏ'), ('Ͱ', 'Ͱ'), + ('Ͳ', 'Ͳ'), ('Ͷ', 'Ͷ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ώ'), ('Α', 'Ρ'), ('Σ', 'Ϋ'), ('Ϗ', 'Ϗ'), + ('ϒ', 'ϔ'), ('Ϙ', 'Ϙ'), ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), + ('Ï ', 'Ï '), ('Ï¢', 'Ï¢'), ('Ϥ', 'Ϥ'), ('Ϧ', 'Ϧ'), ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), ('Ϭ', 'Ϭ'), ('Ï®', 'Ï®'), ('Ï´', 'Ï´'), ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), ('Ͻ', 'Я'), ('Ñ ', 'Ñ '), ('Ñ¢', 'Ñ¢'), ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), ('Ѩ', 'Ѩ'), ('Ѫ', 'Ѫ'), ('Ѭ', 'Ѭ'), ('Ñ®', 'Ñ®'), + ('Ѱ', 'Ѱ'), ('Ѳ', 'Ѳ'), ('Ñ´', 'Ñ´'), ('Ѷ', 'Ѷ'), ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), ('Ѽ', 'Ѽ'), ('Ѿ', 'Ѿ'), ('Ҁ', 'Ҁ'), ('Ҋ', 'Ҋ'), + ('Ҍ', 'Ҍ'), ('Ҏ', 'Ҏ'), ('Ґ', 'Ґ'), ('Ғ', 'Ғ'), ('Ҕ', 'Ҕ'), + ('Җ', 'Җ'), ('Ҙ', 'Ҙ'), ('Қ', 'Қ'), ('Ҝ', 'Ҝ'), ('Ҟ', 'Ҟ'), + ('Ò ', 'Ò '), ('Ò¢', 'Ò¢'), ('Ò¤', 'Ò¤'), ('Ò¦', 'Ò¦'), ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), ('Ò¬', 'Ò¬'), ('Ò®', 'Ò®'), ('Ò°', 'Ò°'), ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), ('Ò¶', 'Ò¶'), ('Ò¸', 'Ò¸'), ('Òº', 'Òº'), ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), ('Ӏ', 'Ӂ'), ('Ӄ', 'Ӄ'), ('Ӆ', 'Ӆ'), ('Ӈ', 'Ӈ'), + ('Ӊ', 'Ӊ'), ('Ӌ', 'Ӌ'), ('Ӎ', 'Ӎ'), ('Ӑ', 'Ӑ'), ('Ӓ', 'Ӓ'), + ('Ӕ', 'Ӕ'), ('Ӗ', 'Ӗ'), ('Ә', 'Ә'), ('Ӛ', 'Ӛ'), ('Ӝ', 'Ӝ'), + ('Ӟ', 'Ӟ'), ('Ó ', 'Ó '), ('Ó¢', 'Ó¢'), ('Ó¤', 'Ó¤'), ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), ('Óª', 'Óª'), ('Ó¬', 'Ó¬'), ('Ó®', 'Ó®'), ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), ('Ó´', 'Ó´'), ('Ó¶', 'Ó¶'), ('Ó¸', 'Ó¸'), ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), ('Ó¾', 'Ó¾'), ('Ԁ', 'Ԁ'), ('Ԃ', 'Ԃ'), ('Ԅ', 'Ԅ'), + ('Ԇ', 'Ԇ'), ('Ԉ', 'Ԉ'), ('Ԋ', 'Ԋ'), ('Ԍ', 'Ԍ'), ('Ԏ', 'Ԏ'), + ('Ԑ', 'Ԑ'), ('Ԓ', 'Ԓ'), ('Ԕ', 'Ԕ'), ('Ԗ', 'Ԗ'), ('Ԙ', 'Ԙ'), + ('Ԛ', 'Ԛ'), ('Ԝ', 'Ԝ'), ('Ԟ', 'Ԟ'), ('Ô ', 'Ô '), ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), ('Ô¦', 'Ô¦'), ('Ô¨', 'Ô¨'), ('Ôª', 'Ôª'), ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), ('Ô±', 'Ֆ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('Ꭰ', 'Ᏽ'), ('\u{1c90}', '\u{1cba}'), ('\u{1cbd}', '\u{1cbf}'), + ('Ḁ', 'Ḁ'), ('Ḃ', 'Ḃ'), ('Ḅ', 'Ḅ'), ('Ḇ', 'Ḇ'), + ('Ḉ', 'Ḉ'), ('Ḋ', 'Ḋ'), ('Ḍ', 'Ḍ'), ('Ḏ', 'Ḏ'), + ('Ḑ', 'Ḑ'), ('Ḓ', 'Ḓ'), ('Ḕ', 'Ḕ'), ('Ḗ', 'Ḗ'), + ('Ḙ', 'Ḙ'), ('Ḛ', 'Ḛ'), ('Ḝ', 'Ḝ'), ('Ḟ', 'Ḟ'), + ('Ḡ', 'Ḡ'), ('Ḣ', 'Ḣ'), ('Ḥ', 'Ḥ'), ('Ḧ', 'Ḧ'), + ('Ḩ', 'Ḩ'), ('Ḫ', 'Ḫ'), ('Ḭ', 'Ḭ'), ('Ḯ', 'Ḯ'), + ('Ḱ', 'Ḱ'), ('Ḳ', 'Ḳ'), ('Ḵ', 'Ḵ'), ('Ḷ', 'Ḷ'), + ('Ḹ', 'Ḹ'), ('Ḻ', 'Ḻ'), ('Ḽ', 'Ḽ'), ('Ḿ', 'Ḿ'), + ('Ṁ', 'Ṁ'), ('Ṃ', 'Ṃ'), ('Ṅ', 'Ṅ'), ('Ṇ', 'Ṇ'), + ('Ṉ', 'Ṉ'), ('Ṋ', 'Ṋ'), ('Ṍ', 'Ṍ'), ('Ṏ', 'Ṏ'), + ('Ṑ', 'Ṑ'), ('Ṓ', 'Ṓ'), ('Ṕ', 'Ṕ'), ('Ṗ', 'Ṗ'), + ('Ṙ', 'Ṙ'), ('Ṛ', 'Ṛ'), ('Ṝ', 'Ṝ'), ('Ṟ', 'Ṟ'), + ('á¹ ', 'á¹ '), ('á¹¢', 'á¹¢'), ('Ṥ', 'Ṥ'), ('Ṧ', 'Ṧ'), + ('Ṩ', 'Ṩ'), ('Ṫ', 'Ṫ'), ('Ṭ', 'Ṭ'), ('á¹®', 'á¹®'), + ('á¹°', 'á¹°'), ('á¹²', 'á¹²'), ('á¹´', 'á¹´'), ('á¹¶', 'á¹¶'), + ('Ṹ', 'Ṹ'), ('Ṻ', 'Ṻ'), ('á¹¼', 'á¹¼'), ('á¹¾', 'á¹¾'), + ('Ẁ', 'Ẁ'), ('Ẃ', 'Ẃ'), ('Ẅ', 'Ẅ'), ('Ẇ', 'Ẇ'), + ('Ẉ', 'Ẉ'), ('Ẋ', 'Ẋ'), ('Ẍ', 'Ẍ'), ('Ẏ', 'Ẏ'), + ('Ẑ', 'Ẑ'), ('Ẓ', 'Ẓ'), ('Ẕ', 'Ẕ'), ('ẞ', 'ẞ'), + ('Ạ', 'Ạ'), ('Ả', 'Ả'), ('Ấ', 'Ấ'), ('Ầ', 'Ầ'), + ('Ẩ', 'Ẩ'), ('Ẫ', 'Ẫ'), ('Ậ', 'Ậ'), ('Ắ', 'Ắ'), + ('Ằ', 'Ằ'), ('Ẳ', 'Ẳ'), ('Ẵ', 'Ẵ'), ('Ặ', 'Ặ'), + ('Ẹ', 'Ẹ'), ('Ẻ', 'Ẻ'), ('Ẽ', 'Ẽ'), ('Ế', 'Ế'), + ('Ề', 'Ề'), ('Ể', 'Ể'), ('Ễ', 'Ễ'), ('Ệ', 'Ệ'), + ('Ỉ', 'Ỉ'), ('Ị', 'Ị'), ('Ọ', 'Ọ'), ('Ỏ', 'Ỏ'), + ('Ố', 'Ố'), ('Ồ', 'Ồ'), ('Ổ', 'Ổ'), ('Ỗ', 'Ỗ'), + ('Ộ', 'Ộ'), ('Ớ', 'Ớ'), ('Ờ', 'Ờ'), ('Ở', 'Ở'), + ('á» ', 'á» '), ('Ợ', 'Ợ'), ('Ụ', 'Ụ'), ('Ủ', 'Ủ'), + ('Ứ', 'Ứ'), ('Ừ', 'Ừ'), ('Ử', 'Ử'), ('á»®', 'á»®'), + ('á»°', 'á»°'), ('Ỳ', 'Ỳ'), ('á»´', 'á»´'), ('á»¶', 'á»¶'), + ('Ỹ', 'Ỹ'), ('Ỻ', 'Ỻ'), ('Ỽ', 'Ỽ'), ('Ỿ', 'Ỿ'), + ('Ἀ', 'Ἇ'), ('Ἐ', 'Ἕ'), ('Ἠ', 'Ἧ'), ('Ἰ', 'Ἷ'), + ('Ὀ', 'Ὅ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), + ('Ὗ', 'Ὗ'), ('Ὠ', 'Ὧ'), ('Ᾰ', 'á¾»'), ('Ὲ', 'Ή'), + ('Ῐ', 'Ί'), ('Ῠ', 'Ῥ'), ('Ὸ', 'á¿»'), ('ℂ', 'ℂ'), + ('ℇ', 'ℇ'), ('ℋ', 'ℍ'), ('ℐ', 'ℒ'), ('ℕ', 'ℕ'), + ('ℙ', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), + ('K', 'ℭ'), ('ℰ', 'ℳ'), ('ℾ', 'ℿ'), ('ⅅ', 'ⅅ'), + ('Ↄ', 'Ↄ'), ('Ⰰ', 'â°®'), ('â± ', 'â± '), ('â±¢', 'Ɽ'), + ('â±§', 'â±§'), ('Ⱪ', 'Ⱪ'), ('Ⱬ', 'Ⱬ'), ('â±­', 'â±°'), + ('â±²', 'â±²'), ('â±µ', 'â±µ'), ('â±¾', 'Ⲁ'), ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), ('Ⲇ', 'Ⲇ'), ('Ⲉ', 'Ⲉ'), ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), ('Ⲏ', 'Ⲏ'), ('Ⲑ', 'Ⲑ'), ('Ⲓ', 'Ⲓ'), + ('Ⲕ', 'Ⲕ'), ('Ⲗ', 'Ⲗ'), ('Ⲙ', 'Ⲙ'), ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), ('Ⲟ', 'Ⲟ'), ('â² ', 'â² '), ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), ('Ⲧ', 'Ⲧ'), ('Ⲩ', 'Ⲩ'), ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), ('â²®', 'â²®'), ('â²°', 'â²°'), ('â²²', 'â²²'), + ('â²´', 'â²´'), ('â²¶', 'â²¶'), ('Ⲹ', 'Ⲹ'), ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), ('â²¾', 'â²¾'), ('Ⳁ', 'Ⳁ'), ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), ('Ⳇ', 'Ⳇ'), ('Ⳉ', 'Ⳉ'), ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), ('Ⳏ', 'Ⳏ'), ('Ⳑ', 'Ⳑ'), ('Ⳓ', 'Ⳓ'), + ('Ⳕ', 'Ⳕ'), ('Ⳗ', 'Ⳗ'), ('Ⳙ', 'Ⳙ'), ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), ('Ⳟ', 'Ⳟ'), ('â³ ', 'â³ '), ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), ('â³­', 'â³­'), ('â³²', 'â³²'), ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), ('Ꙅ', 'Ꙅ'), ('Ꙇ', 'Ꙇ'), ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), ('Ꙍ', 'Ꙍ'), ('Ꙏ', 'Ꙏ'), ('Ꙑ', 'Ꙑ'), + ('Ꙓ', 'Ꙓ'), ('Ꙕ', 'Ꙕ'), ('Ꙗ', 'Ꙗ'), ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), ('Ꙝ', 'Ꙝ'), ('Ꙟ', 'Ꙟ'), ('Ꙡ', 'Ꙡ'), + ('Ꙣ', 'Ꙣ'), ('Ꙥ', 'Ꙥ'), ('Ꙧ', 'Ꙧ'), ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), ('Ꙭ', 'Ꙭ'), ('Ꚁ', 'Ꚁ'), ('Ꚃ', 'Ꚃ'), + ('Ꚅ', 'Ꚅ'), ('Ꚇ', 'Ꚇ'), ('Ꚉ', 'Ꚉ'), ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), ('Ꚏ', 'Ꚏ'), ('Ꚑ', 'Ꚑ'), ('Ꚓ', 'Ꚓ'), + ('Ꚕ', 'Ꚕ'), ('Ꚗ', 'Ꚗ'), ('Ꚙ', 'Ꚙ'), ('Ꚛ', 'Ꚛ'), + ('Ꜣ', 'Ꜣ'), ('Ꜥ', 'Ꜥ'), ('Ꜧ', 'Ꜧ'), ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), ('Ꜭ', 'Ꜭ'), ('Ꜯ', 'Ꜯ'), ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), ('Ꜷ', 'Ꜷ'), ('Ꜹ', 'Ꜹ'), ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), ('Ꜿ', 'Ꜿ'), ('Ꝁ', 'Ꝁ'), ('Ꝃ', 'Ꝃ'), + ('Ꝅ', 'Ꝅ'), ('Ꝇ', 'Ꝇ'), ('Ꝉ', 'Ꝉ'), ('Ꝋ', 'Ꝋ'), + ('Ꝍ', 'Ꝍ'), ('Ꝏ', 'Ꝏ'), ('Ꝑ', 'Ꝑ'), ('Ꝓ', 'Ꝓ'), + ('Ꝕ', 'Ꝕ'), ('Ꝗ', 'Ꝗ'), ('Ꝙ', 'Ꝙ'), ('Ꝛ', 'Ꝛ'), + ('Ꝝ', 'Ꝝ'), ('Ꝟ', 'Ꝟ'), ('Ꝡ', 'Ꝡ'), ('Ꝣ', 'Ꝣ'), + ('Ꝥ', 'Ꝥ'), ('Ꝧ', 'Ꝧ'), ('Ꝩ', 'Ꝩ'), ('Ꝫ', 'Ꝫ'), + ('Ꝭ', 'Ꝭ'), ('Ꝯ', 'Ꝯ'), ('Ꝺ', 'Ꝺ'), ('Ꝼ', 'Ꝼ'), + ('Ᵹ', 'Ꝿ'), ('Ꞁ', 'Ꞁ'), ('Ꞃ', 'Ꞃ'), ('Ꞅ', 'Ꞅ'), + ('Ꞇ', 'Ꞇ'), ('Ꞌ', 'Ꞌ'), ('Ɥ', 'Ɥ'), ('Ꞑ', 'Ꞑ'), + ('Ꞓ', 'Ꞓ'), ('Ꞗ', 'Ꞗ'), ('Ꞙ', 'Ꞙ'), ('Ꞛ', 'Ꞛ'), + ('Ꞝ', 'Ꞝ'), ('Ꞟ', 'Ꞟ'), ('Ꞡ', 'Ꞡ'), ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), ('Ꞧ', 'Ꞧ'), ('Ꞩ', 'Ꞩ'), ('Ɦ', 'Ɪ'), + ('Ʞ', 'Ꞵ'), ('Ꞷ', 'Ꞷ'), ('\u{a7b8}', '\u{a7b8}'), ('A', 'Z'), + ('𐐀', '𐐧'), ('𐒰', '𐓓'), ('𐲀', '𐲲'), ('𑢠', '𑢿'), + ('\u{16e40}', '\u{16e5f}'), ('𝐀', '𝐙'), ('𝐴', '𝑍'), + ('𝑨', '𝒁'), ('𝒜', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), + ('𝒥', '𝒦'), ('𝒩', '𝒬'), ('𝒮', '𝒵'), ('𝓐', '𝓩'), + ('𝔄', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔸', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕬', '𝖅'), ('𝖠', '𝖹'), ('𝗔', '𝗭'), + ('𝘈', '𝘡'), ('𝘼', '𝙕'), ('𝙰', '𝚉'), ('𝚨', '𝛀'), + ('𝛢', '𝛺'), ('𝜜', '𝜴'), ('𝝖', '𝝮'), ('𝞐', '𝞨'), + ('𝟊', '𝟊'), ('𞤀', '𞤡'), +]; diff --git a/regex-syntax/src/unicode_tables/grapheme_cluster_break.rs b/regex-syntax/src/unicode_tables/grapheme_cluster_break.rs new file mode 100644 index 000000000..e139de45c --- /dev/null +++ b/regex-syntax/src/unicode_tables/grapheme_cluster_break.rs @@ -0,0 +1,455 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate grapheme-cluster-break /home/andrew/tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("CR", CR), ("Control", CONTROL), ("Extend", EXTEND), ("L", L), ("LF", LF), + ("LV", LV), ("LVT", LVT), ("Prepend", PREPEND), + ("Regional_Indicator", REGIONAL_INDICATOR), ("SpacingMark", SPACINGMARK), + ("T", T), ("V", V), ("ZWJ", ZWJ), +]; + +pub const CR: &'static [(char, char)] = &[ + ('\r', '\r'), +]; + +pub const CONTROL: &'static [(char, char)] = &[ + ('\u{0}', '\t'), ('\u{b}', '\u{c}'), ('\u{e}', '\u{1f}'), + ('\u{7f}', '\u{9f}'), ('\u{ad}', '\u{ad}'), ('\u{61c}', '\u{61c}'), + ('\u{180e}', '\u{180e}'), ('\u{200b}', '\u{200b}'), + ('\u{200e}', '\u{200f}'), ('\u{2028}', '\u{202e}'), + ('\u{2060}', '\u{206f}'), ('\u{feff}', '\u{feff}'), + ('\u{fff0}', '\u{fffb}'), ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), ('\u{e0000}', '\u{e001f}'), + ('\u{e0080}', '\u{e00ff}'), ('\u{e01f0}', '\u{e0fff}'), +]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), ('\u{483}', '\u{489}'), ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dc}'), ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), + ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', '\u{902}'), ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), ('\u{941}', '\u{948}'), ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), ('\u{9be}', '\u{9be}'), ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), ('\u{9d7}', '\u{9d7}'), ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), ('\u{a01}', '\u{a02}'), ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), ('\u{b01}', '\u{b01}'), ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b3f}'), ('\u{b41}', '\u{b44}'), ('\u{b4d}', '\u{b4d}'), + ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'), + ('\u{bbe}', '\u{bbe}'), ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c00}'), ('\u{c04}', '\u{c04}'), + ('\u{c3e}', '\u{c40}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), ('\u{cbf}', '\u{cbf}'), ('\u{cc2}', '\u{cc2}'), + ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), ('\u{d00}', '\u{d01}'), ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d3e}'), ('\u{d41}', '\u{d44}'), ('\u{d4d}', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), ('\u{d62}', '\u{d63}'), ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dcf}'), ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), + ('\u{ddf}', '\u{ddf}'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), ('\u{f80}', '\u{f84}'), ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), ('\u{1732}', '\u{1734}'), + ('\u{1752}', '\u{1753}'), ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180d}'), + ('\u{1885}', '\u{1886}'), ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), ('\u{1ab0}', '\u{1abe}'), + ('\u{1b00}', '\u{1b03}'), ('\u{1b34}', '\u{1b34}'), + ('\u{1b36}', '\u{1b3a}'), ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), ('\u{1c36}', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1df9}'), ('\u{1dfb}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), ('\u{a9bc}', '\u{a9bc}'), + ('\u{a9e5}', '\u{a9e5}'), ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', '\u{aa4c}'), + ('\u{aa7c}', '\u{aa7c}'), ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'), + ('\u{aaec}', '\u{aaed}'), ('\u{aaf6}', '\u{aaf6}'), + ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), + ('\u{11001}', '\u{11001}'), ('\u{11038}', '\u{11046}'), + ('\u{1107f}', '\u{11081}'), ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), ('\u{111c9}', '\u{111cc}'), + ('\u{1122f}', '\u{11231}'), ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), + ('\u{112df}', '\u{112df}'), ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', '\u{1133e}'), ('\u{11340}', '\u{11340}'), + ('\u{11357}', '\u{11357}'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), ('\u{114b0}', '\u{114b0}'), + ('\u{114b3}', '\u{114b8}'), ('\u{114ba}', '\u{114ba}'), + ('\u{114bd}', '\u{114bd}'), ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), ('\u{115af}', '\u{115af}'), + ('\u{115b2}', '\u{115b5}'), ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), ('\u{11839}', '\u{1183a}'), + ('\u{11a01}', '\u{11a0a}'), ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), ('\u{11ef3}', '\u{11ef4}'), + ('\u{16af0}', '\u{16af4}'), ('\u{16b30}', '\u{16b36}'), + ('\u{16f8f}', '\u{16f92}'), ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d165}'), ('\u{1d167}', '\u{1d169}'), + ('\u{1d16e}', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e944}', '\u{1e94a}'), ('🏻', '🏿'), + ('\u{e0020}', '\u{e007f}'), ('\u{e0100}', '\u{e01ef}'), +]; + +pub const L: &'static [(char, char)] = &[ + ('ᄀ', 'ᅟ'), ('ꥠ', 'ꥼ'), +]; + +pub const LF: &'static [(char, char)] = &[ + ('\n', '\n'), +]; + +pub const LV: &'static [(char, char)] = &[ + ('가', '가'), ('개', '개'), ('ê°¸', 'ê°¸'), ('걔', '걔'), + ('ê±°', 'ê±°'), ('게', '게'), ('겨', '겨'), ('계', '계'), + ('ê³ ', 'ê³ '), ('ê³¼', 'ê³¼'), ('괘', '괘'), ('ê´´', 'ê´´'), + ('교', '교'), ('구', '구'), ('궈', '궈'), ('궤', '궤'), + ('귀', '귀'), ('규', '규'), ('ê·¸', 'ê·¸'), ('긔', '긔'), + ('기', '기'), ('까', '까'), ('깨', '깨'), ('꺄', '꺄'), + ('꺠', '꺠'), ('꺼', '꺼'), ('께', '께'), ('ê»´', 'ê»´'), + ('꼐', '꼐'), ('꼬', '꼬'), ('꽈', '꽈'), ('꽤', '꽤'), + ('꾀', '꾀'), ('꾜', '꾜'), ('꾸', '꾸'), ('꿔', '꿔'), + ('ê¿°', 'ê¿°'), ('뀌', '뀌'), ('뀨', '뀨'), ('끄', '끄'), + ('끠', '끠'), ('끼', '끼'), ('나', '나'), ('내', '내'), + ('냐', '냐'), ('냬', '냬'), ('너', '너'), ('네', '네'), + ('녀', '녀'), ('녜', '녜'), ('노', '노'), ('놔', '놔'), + ('놰', '놰'), ('뇌', '뇌'), ('뇨', '뇨'), ('누', '누'), + ('눠', '눠'), ('눼', '눼'), ('뉘', '뉘'), ('뉴', '뉴'), + ('느', '느'), ('늬', '늬'), ('니', '니'), ('다', '다'), + ('대', '대'), ('댜', '댜'), ('댸', '댸'), ('더', '더'), + ('데', '데'), ('뎌', '뎌'), ('뎨', '뎨'), ('도', '도'), + ('돠', '돠'), ('돼', '돼'), ('되', '되'), ('됴', '됴'), + ('두', '두'), ('둬', '둬'), ('뒈', '뒈'), ('뒤', '뒤'), + ('듀', '듀'), ('드', '드'), ('듸', '듸'), ('디', '디'), + ('따', '따'), ('때', '때'), ('땨', '땨'), ('떄', '떄'), + ('떠', '떠'), ('떼', '떼'), ('뗘', '뗘'), ('뗴', '뗴'), + ('또', '또'), ('똬', '똬'), ('뙈', '뙈'), ('뙤', '뙤'), + ('뚀', '뚀'), ('뚜', '뚜'), ('뚸', '뚸'), ('뛔', '뛔'), + ('뛰', '뛰'), ('뜌', '뜌'), ('뜨', '뜨'), ('띄', '띄'), + ('띠', '띠'), ('라', '라'), ('래', '래'), ('랴', '랴'), + ('럐', '럐'), ('러', '러'), ('레', '레'), ('ë ¤', 'ë ¤'), + ('례', '례'), ('로', '로'), ('롸', '롸'), ('뢔', '뢔'), + ('뢰', '뢰'), ('료', '료'), ('루', '루'), ('뤄', '뤄'), + ('뤠', '뤠'), ('뤼', '뤼'), ('류', '류'), ('르', '르'), + ('릐', '릐'), ('리', '리'), ('마', '마'), ('매', '매'), + ('먀', '먀'), ('먜', '먜'), ('머', '머'), ('메', '메'), + ('ë©°', 'ë©°'), ('몌', '몌'), ('모', '모'), ('뫄', '뫄'), + ('ë« ', 'ë« '), ('뫼', '뫼'), ('묘', '묘'), ('무', '무'), + ('뭐', '뭐'), ('ë­¬', 'ë­¬'), ('뮈', '뮈'), ('뮤', '뮤'), + ('므', '므'), ('믜', '믜'), ('미', '미'), ('바', '바'), + ('ë°°', 'ë°°'), ('뱌', '뱌'), ('뱨', '뱨'), ('버', '버'), + ('ë² ', 'ë² '), ('ë²¼', 'ë²¼'), ('볘', '볘'), ('ë³´', 'ë³´'), + ('봐', '봐'), ('ë´¬', 'ë´¬'), ('뵈', '뵈'), ('뵤', '뵤'), + ('부', '부'), ('붜', '붜'), ('붸', '붸'), ('뷔', '뷔'), + ('ë·°', 'ë·°'), ('브', '브'), ('븨', '븨'), ('비', '비'), + ('ë¹ ', 'ë¹ '), ('ë¹¼', 'ë¹¼'), ('뺘', '뺘'), ('뺴', '뺴'), + ('뻐', '뻐'), ('뻬', '뻬'), ('뼈', '뼈'), ('뼤', '뼤'), + ('뽀', '뽀'), ('뽜', '뽜'), ('뽸', '뽸'), ('뾔', '뾔'), + ('ë¾°', 'ë¾°'), ('뿌', '뿌'), ('뿨', '뿨'), ('쀄', '쀄'), + ('쀠', '쀠'), ('쀼', '쀼'), ('쁘', '쁘'), ('쁴', '쁴'), + ('삐', '삐'), ('사', '사'), ('새', '새'), ('샤', '샤'), + ('섀', '섀'), ('서', '서'), ('세', '세'), ('셔', '셔'), + ('셰', '셰'), ('소', '소'), ('솨', '솨'), ('쇄', '쇄'), + ('쇠', '쇠'), ('쇼', '쇼'), ('수', '수'), ('숴', '숴'), + ('쉐', '쉐'), ('쉬', '쉬'), ('슈', '슈'), ('스', '스'), + ('싀', '싀'), ('시', '시'), ('싸', '싸'), ('쌔', '쌔'), + ('쌰', '쌰'), ('썌', '썌'), ('써', '써'), ('쎄', '쎄'), + ('쎠', '쎠'), ('쎼', '쎼'), ('쏘', '쏘'), ('쏴', '쏴'), + ('쐐', '쐐'), ('쐬', '쐬'), ('쑈', '쑈'), ('쑤', '쑤'), + ('쒀', '쒀'), ('쒜', '쒜'), ('쒸', '쒸'), ('쓔', '쓔'), + ('쓰', '쓰'), ('씌', '씌'), ('씨', '씨'), ('아', '아'), + ('애', '애'), ('야', '야'), ('얘', '얘'), ('어', '어'), + ('에', '에'), ('여', '여'), ('예', '예'), ('오', '오'), + ('와', '와'), ('왜', '왜'), ('외', '외'), ('요', '요'), + ('우', '우'), ('워', '워'), ('웨', '웨'), ('위', '위'), + ('유', '유'), ('으', '으'), ('의', '의'), ('이', '이'), + ('자', '자'), ('재', '재'), ('쟈', '쟈'), ('쟤', '쟤'), + ('저', '저'), ('제', '제'), ('ì ¸', 'ì ¸'), ('졔', '졔'), + ('ì¡°', 'ì¡°'), ('좌', '좌'), ('좨', '좨'), ('죄', '죄'), + ('죠', '죠'), ('주', '주'), ('줘', '줘'), ('줴', '줴'), + ('쥐', '쥐'), ('쥬', '쥬'), ('즈', '즈'), ('즤', '즤'), + ('지', '지'), ('짜', '짜'), ('째', '째'), ('쨔', '쨔'), + ('쨰', '쨰'), ('쩌', '쩌'), ('쩨', '쩨'), ('쪄', '쪄'), + ('쪠', '쪠'), ('쪼', '쪼'), ('쫘', '쫘'), ('ì«´', 'ì«´'), + ('쬐', '쬐'), ('쬬', '쬬'), ('쭈', '쭈'), ('ì­¤', 'ì­¤'), + ('쮀', '쮀'), ('쮜', '쮜'), ('쮸', '쮸'), ('쯔', '쯔'), + ('쯰', '쯰'), ('찌', '찌'), ('ì°¨', 'ì°¨'), ('채', '채'), + ('ì± ', 'ì± '), ('ì±¼', 'ì±¼'), ('처', '처'), ('ì²´', 'ì²´'), + ('쳐', '쳐'), ('쳬', '쳬'), ('초', '초'), ('ì´¤', 'ì´¤'), + ('쵀', '쵀'), ('최', '최'), ('쵸', '쵸'), ('추', '추'), + ('ì¶°', 'ì¶°'), ('췌', '췌'), ('ì·¨', 'ì·¨'), ('츄', '츄'), + ('츠', '츠'), ('츼', '츼'), ('치', '치'), ('ì¹´', 'ì¹´'), + ('캐', '캐'), ('캬', '캬'), ('컈', '컈'), ('커', '커'), + ('케', '케'), ('켜', '켜'), ('켸', '켸'), ('코', '코'), + ('ì½°', 'ì½°'), ('쾌', '쾌'), ('쾨', '쾨'), ('쿄', '쿄'), + ('ì¿ ', 'ì¿ '), ('쿼', '쿼'), ('퀘', '퀘'), ('퀴', '퀴'), + ('큐', '큐'), ('크', '크'), ('킈', '킈'), ('키', '키'), + ('타', '타'), ('태', '태'), ('탸', '탸'), ('턔', '턔'), + ('터', '터'), ('테', '테'), ('텨', '텨'), ('톄', '톄'), + ('토', '토'), ('톼', '톼'), ('퇘', '퇘'), ('퇴', '퇴'), + ('툐', '툐'), ('투', '투'), ('퉈', '퉈'), ('퉤', '퉤'), + ('튀', '튀'), ('튜', '튜'), ('트', '트'), ('틔', '틔'), + ('티', '티'), ('파', '파'), ('패', '패'), ('퍄', '퍄'), + ('퍠', '퍠'), ('퍼', '퍼'), ('페', '페'), ('펴', '펴'), + ('폐', '폐'), ('포', '포'), ('퐈', '퐈'), ('퐤', '퐤'), + ('푀', '푀'), ('표', '표'), ('푸', '푸'), ('풔', '풔'), + ('풰', '풰'), ('퓌', '퓌'), ('퓨', '퓨'), ('프', '프'), + ('픠', '픠'), ('피', '피'), ('하', '하'), ('해', '해'), + ('햐', '햐'), ('햬', '햬'), ('허', '허'), ('헤', '헤'), + ('혀', '혀'), ('혜', '혜'), ('호', '호'), ('화', '화'), + ('홰', '홰'), ('회', '회'), ('효', '효'), ('후', '후'), + ('훠', '훠'), ('훼', '훼'), ('휘', '휘'), ('휴', '휴'), + ('흐', '흐'), ('희', '희'), ('히', '히'), +]; + +pub const LVT: &'static [(char, char)] = &[ + ('각', '갛'), ('객', 'ê°·'), ('ê°¹', '걓'), ('걕', '걯'), + ('ê±±', '겋'), ('겍', 'ê²§'), ('격', '곃'), ('곅', '곟'), + ('곡', 'ê³»'), ('ê³½', '괗'), ('괙', 'ê´³'), ('ê´µ', '굏'), + ('굑', '굫'), ('êµ­', '궇'), ('궉', 'ê¶£'), ('ê¶¥', 'ê¶¿'), + ('귁', '귛'), ('귝', 'ê··'), ('ê·¹', '긓'), ('긕', '긯'), + ('긱', '깋'), ('깍', 'ê¹§'), ('깩', '꺃'), ('꺅', '꺟'), + ('꺡', '꺻'), ('꺽', '껗'), ('껙', '껳'), ('껵', '꼏'), + ('꼑', '꼫'), ('ê¼­', '꽇'), ('꽉', 'ê½£'), ('ê½¥', '꽿'), + ('꾁', '꾛'), ('꾝', 'ê¾·'), ('ê¾¹', '꿓'), ('꿕', '꿯'), + ('꿱', '뀋'), ('뀍', '뀧'), ('뀩', '끃'), ('끅', '끟'), + ('끡', '끻'), ('끽', '낗'), ('낙', '낳'), ('낵', '냏'), + ('냑', '냫'), ('냭', '넇'), ('넉', '넣'), ('넥', '넿'), + ('녁', '녛'), ('녝', '녷'), ('녹', '놓'), ('놕', '놯'), + ('놱', '뇋'), ('뇍', '뇧'), ('뇩', '눃'), ('눅', '눟'), + ('눡', '눻'), ('눽', '뉗'), ('뉙', '뉳'), ('뉵', '늏'), + ('늑', '늫'), ('늭', '닇'), ('닉', '닣'), ('닥', '닿'), + ('댁', '댛'), ('댝', '댷'), ('댹', '덓'), ('덕', '덯'), + ('덱', '뎋'), ('뎍', '뎧'), ('뎩', '돃'), ('독', '돟'), + ('돡', '돻'), ('돽', '됗'), ('됙', '됳'), ('됵', '둏'), + ('둑', '둫'), ('둭', '뒇'), ('뒉', '뒣'), ('뒥', '뒿'), + ('듁', '듛'), ('득', '듷'), ('듹', '딓'), ('딕', '딯'), + ('딱', '땋'), ('땍', '땧'), ('땩', '떃'), ('떅', '떟'), + ('떡', '떻'), ('떽', '뗗'), ('뗙', '뗳'), ('뗵', '똏'), + ('똑', '똫'), ('똭', '뙇'), ('뙉', '뙣'), ('뙥', '뙿'), + ('뚁', '뚛'), ('뚝', '뚷'), ('뚹', '뛓'), ('뛕', '뛯'), + ('뛱', '뜋'), ('뜍', '뜧'), ('뜩', '띃'), ('띅', '띟'), + ('띡', '띻'), ('락', '랗'), ('랙', '랳'), ('략', '럏'), + ('럑', '럫'), ('럭', '렇'), ('렉', 'ë £'), ('ë ¥', 'ë ¿'), + ('롁', '롛'), ('록', 'ë¡·'), ('롹', '뢓'), ('뢕', '뢯'), + ('뢱', '룋'), ('룍', '룧'), ('룩', '뤃'), ('뤅', '뤟'), + ('뤡', '뤻'), ('뤽', '륗'), ('륙', '륳'), ('륵', '릏'), + ('릑', '릫'), ('릭', '맇'), ('막', 'ë§£'), ('ë§¥', 'ë§¿'), + ('먁', '먛'), ('먝', '먷'), ('먹', '멓'), ('멕', '멯'), + ('멱', '몋'), ('몍', '몧'), ('목', '뫃'), ('뫅', '뫟'), + ('ë«¡', 'ë«»'), ('뫽', '묗'), ('묙', '묳'), ('묵', '뭏'), + ('뭑', 'ë­«'), ('ë­­', '뮇'), ('뮉', '뮣'), ('뮥', '뮿'), + ('믁', '믛'), ('믝', '믷'), ('믹', '밓'), ('박', 'ë°¯'), + ('ë°±', '뱋'), ('뱍', 'ë±§'), ('뱩', '벃'), ('벅', '벟'), + ('벡', 'ë²»'), ('ë²½', '볗'), ('볙', 'ë³³'), ('ë³µ', '봏'), + ('봑', 'ë´«'), ('ë´­', '뵇'), ('뵉', 'ëµ£'), ('ëµ¥', '뵿'), + ('북', '붛'), ('붝', 'ë¶·'), ('ë¶¹', '뷓'), ('뷕', 'ë·¯'), + ('ë·±', '븋'), ('븍', '븧'), ('븩', '빃'), ('빅', '빟'), + ('빡', 'ë¹»'), ('ë¹½', '뺗'), ('뺙', '뺳'), ('뺵', '뻏'), + ('뻑', '뻫'), ('ë»­', '뼇'), ('뼉', 'ë¼£'), ('ë¼¥', '뼿'), + ('뽁', '뽛'), ('뽝', 'ë½·'), ('ë½¹', '뾓'), ('뾕', '뾯'), + ('ë¾±', '뿋'), ('뿍', 'ë¿§'), ('ë¿©', '쀃'), ('쀅', '쀟'), + ('쀡', '쀻'), ('쀽', '쁗'), ('쁙', '쁳'), ('쁵', '삏'), + ('삑', '삫'), ('삭', '샇'), ('색', '샣'), ('샥', '샿'), + ('섁', '섛'), ('석', '섷'), ('섹', '셓'), ('셕', '셯'), + ('셱', '솋'), ('속', '솧'), ('솩', '쇃'), ('쇅', '쇟'), + ('쇡', '쇻'), ('쇽', '숗'), ('숙', '숳'), ('숵', '쉏'), + ('쉑', '쉫'), ('쉭', '슇'), ('슉', '슣'), ('슥', '슿'), + ('싁', '싛'), ('식', '싷'), ('싹', '쌓'), ('쌕', '쌯'), + ('쌱', '썋'), ('썍', '썧'), ('썩', '쎃'), ('쎅', '쎟'), + ('쎡', '쎻'), ('쎽', '쏗'), ('쏙', '쏳'), ('쏵', '쐏'), + ('쐑', '쐫'), ('쐭', '쑇'), ('쑉', '쑣'), ('쑥', '쑿'), + ('쒁', '쒛'), ('쒝', '쒷'), ('쒹', '쓓'), ('쓕', '쓯'), + ('쓱', '씋'), ('씍', '씧'), ('씩', '앃'), ('악', '앟'), + ('액', '앻'), ('약', '얗'), ('얙', '얳'), ('억', '엏'), + ('엑', '엫'), ('역', '옇'), ('옉', '옣'), ('옥', '옿'), + ('왁', '왛'), ('왝', '왷'), ('왹', '욓'), ('욕', '욯'), + ('욱', '웋'), ('웍', '웧'), ('웩', '윃'), ('윅', '윟'), + ('육', '윻'), ('윽', '읗'), ('읙', '읳'), ('익', '잏'), + ('작', '잫'), ('잭', '쟇'), ('쟉', '쟣'), ('쟥', '쟿'), + ('적', '젛'), ('젝', 'ì ·'), ('ì ¹', '졓'), ('졕', '졯'), + ('족', '좋'), ('좍', '좧'), ('좩', '죃'), ('죅', '죟'), + ('죡', '죻'), ('죽', '줗'), ('줙', '줳'), ('줵', '쥏'), + ('쥑', '쥫'), ('쥭', '즇'), ('즉', '즣'), ('즥', '즿'), + ('직', '짛'), ('짝', 'ì§·'), ('ì§¹', '쨓'), ('쨕', '쨯'), + ('쨱', '쩋'), ('쩍', 'ì©§'), ('ì©©', '쪃'), ('쪅', '쪟'), + ('쪡', '쪻'), ('쪽', '쫗'), ('쫙', '쫳'), ('쫵', '쬏'), + ('쬑', '쬫'), ('쬭', '쭇'), ('쭉', 'ì­£'), ('ì­¥', 'ì­¿'), + ('쮁', '쮛'), ('쮝', 'ì®·'), ('쮹', '쯓'), ('쯕', '쯯'), + ('쯱', '찋'), ('찍', 'ì°§'), ('ì°©', '챃'), ('책', '챟'), + ('챡', 'ì±»'), ('ì±½', '첗'), ('척', 'ì²³'), ('ì²µ', '쳏'), + ('쳑', '쳫'), ('ì³­', '촇'), ('촉', 'ì´£'), ('ì´¥', 'ì´¿'), + ('쵁', '쵛'), ('쵝', 'ìµ·'), ('ìµ¹', '춓'), ('축', '춯'), + ('ì¶±', '췋'), ('췍', 'ì·§'), ('ì·©', '츃'), ('츅', '츟'), + ('측', '츻'), ('츽', '칗'), ('칙', 'ì¹³'), ('ì¹µ', '캏'), + ('캑', '캫'), ('캭', '컇'), ('컉', '컣'), ('컥', '컿'), + ('켁', '켛'), ('켝', 'ì¼·'), ('ì¼¹', '콓'), ('콕', '콯'), + ('ì½±', '쾋'), ('쾍', 'ì¾§'), ('쾩', '쿃'), ('쿅', '쿟'), + ('ì¿¡', 'ì¿»'), ('쿽', '퀗'), ('퀙', '퀳'), ('퀵', '큏'), + ('큑', '큫'), ('큭', '킇'), ('킉', '킣'), ('킥', '킿'), + ('탁', '탛'), ('택', '탷'), ('탹', '턓'), ('턕', '턯'), + ('턱', '텋'), ('텍', '텧'), ('텩', '톃'), ('톅', '톟'), + ('톡', '톻'), ('톽', '퇗'), ('퇙', '퇳'), ('퇵', '툏'), + ('툑', '툫'), ('툭', '퉇'), ('퉉', '퉣'), ('퉥', '퉿'), + ('튁', '튛'), ('튝', '튷'), ('특', '틓'), ('틕', '틯'), + ('틱', '팋'), ('팍', '팧'), ('팩', '퍃'), ('퍅', '퍟'), + ('퍡', '퍻'), ('퍽', '펗'), ('펙', '펳'), ('펵', '폏'), + ('폑', '폫'), ('폭', '퐇'), ('퐉', '퐣'), ('퐥', '퐿'), + ('푁', '푛'), ('푝', '푷'), ('푹', '풓'), ('풕', '풯'), + ('풱', '퓋'), ('퓍', '퓧'), ('퓩', '픃'), ('픅', '픟'), + ('픡', '픻'), ('픽', '핗'), ('학', '핳'), ('핵', '햏'), + ('햑', '햫'), ('햭', '헇'), ('헉', '헣'), ('헥', '헿'), + ('혁', '혛'), ('혝', '혷'), ('혹', '홓'), ('확', '홯'), + ('홱', '횋'), ('획', '횧'), ('횩', '훃'), ('훅', '훟'), + ('훡', '훻'), ('훽', '휗'), ('휙', '휳'), ('휵', '흏'), + ('흑', '흫'), ('흭', '힇'), ('힉', '힣'), +]; + +pub const PREPEND: &'static [(char, char)] = &[ + ('\u{600}', '\u{605}'), ('\u{6dd}', '\u{6dd}'), ('\u{70f}', '\u{70f}'), + ('\u{8e2}', '\u{8e2}'), ('ൎ', 'ൎ'), ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), ('𑇂', '𑇃'), ('𑨺', '𑨺'), + ('𑪆', '𑪉'), ('𑵆', '𑵆'), +]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[ + ('🇦', '🇿'), +]; + +pub const SPACINGMARK: &'static [(char, char)] = &[ + ('ः', 'ः'), ('ऻ', 'ऻ'), ('ा', 'ी'), ('ॉ', 'ौ'), + ('ॎ', 'ॏ'), ('ং', 'ঃ'), ('ি', 'ী'), ('ে', 'ৈ'), + ('ো', 'ৌ'), ('ਃ', 'ਃ'), ('ਾ', 'ੀ'), ('ઃ', 'ઃ'), + ('ા', 'ી'), ('ૉ', 'ૉ'), ('ો', 'ૌ'), ('ଂ', 'ଃ'), + ('ୀ', 'ୀ'), ('େ', 'ୈ'), ('ୋ', 'ୌ'), ('ி', 'ி'), + ('ு', 'ூ'), ('ெ', 'ை'), ('ொ', 'ௌ'), ('ఁ', 'ః'), + ('ు', 'ౄ'), ('ಂ', 'ಃ'), ('ಾ', 'ಾ'), ('ೀ', 'ು'), + ('ೃ', 'ೄ'), ('ೇ', 'ೈ'), ('ೊ', 'ೋ'), ('ം', 'ഃ'), + ('à´¿', 'ീ'), ('െ', 'ൈ'), ('ൊ', 'ൌ'), ('ං', 'ඃ'), + ('ැ', 'ෑ'), ('ෘ', 'ෞ'), ('à·²', 'à·³'), ('ำ', 'ำ'), + ('ຳ', 'ຳ'), ('༾', '༿'), ('ཿ', 'ཿ'), ('ေ', 'ေ'), + ('ျ', 'ြ'), ('ၖ', 'ၗ'), ('ႄ', 'ႄ'), ('ា', 'ា'), + ('ើ', 'ៅ'), ('ះ', 'ៈ'), ('ᤣ', 'ᤦ'), ('ᤩ', 'ᤫ'), + ('ᤰ', 'ᤱ'), ('ᤳ', 'ᤸ'), ('ᨙ', 'ᨚ'), ('ᩕ', 'ᩕ'), + ('ᩗ', 'ᩗ'), ('á©­', 'ᩲ'), ('ᬄ', 'ᬄ'), ('ᬵ', 'ᬵ'), + ('ᬻ', 'ᬻ'), ('ᬽ', 'ᭁ'), ('ᭃ', '᭄'), ('ᮂ', 'ᮂ'), + ('ᮡ', 'ᮡ'), ('ᮦ', 'á®§'), ('᮪', '᮪'), ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), ('ᯮ', 'ᯮ'), ('᯲', '᯳'), ('á°¤', 'á°«'), + ('á°´', 'á°µ'), ('᳡', '᳡'), ('á³²', 'á³³'), ('á³·', 'á³·'), + ('ê £', 'ê ¤'), ('ê §', 'ê §'), ('ꢀ', 'ꢁ'), ('ꢴ', 'ꣃ'), + ('ꥒ', '꥓'), ('ꦃ', 'ꦃ'), ('ꦴ', 'ꦵ'), ('ꦺ', 'ꦻ'), + ('ꦽ', '꧀'), ('ꨯ', 'ꨰ'), ('ꨳ', 'ꨴ'), ('ꩍ', 'ꩍ'), + ('ê««', 'ê««'), ('ê«®', 'ꫯ'), ('ꫵ', 'ꫵ'), ('ꯣ', 'ꯤ'), + ('ꯦ', 'ꯧ'), ('ꯩ', 'ꯪ'), ('꯬', '꯬'), ('𑀀', '𑀀'), + ('𑀂', '𑀂'), ('𑂂', '𑂂'), ('𑂰', '𑂲'), ('𑂷', '𑂸'), + ('𑄬', '𑄬'), ('𑅅', '𑅆'), ('𑆂', '𑆂'), ('𑆳', '𑆵'), + ('𑆿', '𑇀'), ('𑈬', '𑈮'), ('𑈲', '𑈳'), ('𑈵', '𑈵'), + ('𑋠', '𑋢'), ('𑌂', '𑌃'), ('𑌿', '𑌿'), ('𑍁', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍢', '𑍣'), ('𑐵', '𑐷'), + ('𑑀', '𑑁'), ('𑑅', '𑑅'), ('𑒱', '𑒲'), ('𑒹', '𑒹'), + ('𑒻', '𑒼'), ('𑒾', '𑒾'), ('𑓁', '𑓁'), ('𑖰', '𑖱'), + ('𑖸', '𑖻'), ('𑖾', '𑖾'), ('𑘰', '𑘲'), ('𑘻', '𑘼'), + ('𑘾', '𑘾'), ('𑚬', '𑚬'), ('𑚮', '𑚯'), ('𑚶', '𑚶'), + ('𑜠', '𑜡'), ('𑜦', '𑜦'), ('𑠬', '𑠮'), ('𑠸', '𑠸'), + ('𑨹', '𑨹'), ('𑩗', '𑩘'), ('𑪗', '𑪗'), ('𑰯', '𑰯'), + ('𑰾', '𑰾'), ('𑲩', '𑲩'), ('𑲱', '𑲱'), ('𑲴', '𑲴'), + ('𑶊', '𑶎'), ('𑶓', '𑶔'), ('𑶖', '𑶖'), ('𑻵', '𑻶'), + ('𖽑', '𖽾'), ('𝅦', '𝅦'), ('𝅭', '𝅭'), +]; + +pub const T: &'static [(char, char)] = &[ + ('ᆨ', 'ᇿ'), ('ퟋ', 'ퟻ'), +]; + +pub const V: &'static [(char, char)] = &[ + ('ᅠ', 'ᆧ'), ('ힰ', 'ퟆ'), +]; + +pub const ZWJ: &'static [(char, char)] = &[ + ('\u{200d}', '\u{200d}'), +]; diff --git a/regex-syntax/src/unicode_tables/mod.rs b/regex-syntax/src/unicode_tables/mod.rs new file mode 100644 index 000000000..aa18d5b86 --- /dev/null +++ b/regex-syntax/src/unicode_tables/mod.rs @@ -0,0 +1,12 @@ +pub mod age; +pub mod case_folding_simple; +pub mod general_category; +pub mod grapheme_cluster_break; +pub mod perl_word; +pub mod property_bool; +pub mod property_names; +pub mod property_values; +pub mod script_extension; +pub mod script; +pub mod sentence_break; +pub mod word_break; diff --git a/regex-syntax/src/unicode_tables/perl_word.rs b/regex-syntax/src/unicode_tables/perl_word.rs new file mode 100644 index 000000000..336a71702 --- /dev/null +++ b/regex-syntax/src/unicode_tables/perl_word.rs @@ -0,0 +1,188 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate perl-word tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const PERL_WORD: &'static [(char, char)] = &[ + ('0', '9'), ('A', 'Z'), ('_', '_'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), + ('º', 'º'), ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), ('ˆ', 'ˑ'), + ('Ë ', 'ˤ'), ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('̀', 'Í´'), ('Ͷ', 'Í·'), + ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('҃', 'Ô¯'), ('Ô±', 'Ֆ'), + ('ՙ', 'ՙ'), ('\u{560}', '\u{588}'), ('֑', 'Ö½'), ('Ö¿', 'Ö¿'), + ('ׁ', 'ׂ'), ('ׄ', 'ׅ'), ('ׇ', 'ׇ'), ('א', 'ת'), ('\u{5ef}', 'ײ'), + ('ؐ', 'ؚ'), ('Ø ', 'Ù©'), ('Ù®', 'ۓ'), ('ە', 'ۜ'), ('۟', 'Û¨'), + ('Ûª', 'Û¼'), ('Û¿', 'Û¿'), ('ܐ', '݊'), ('ݍ', 'Þ±'), ('߀', 'ßµ'), + ('ߺ', 'ߺ'), ('\u{7fd}', '\u{7fd}'), ('ࠀ', 'à ­'), ('ࡀ', '࡛'), + ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('\u{8d3}', '࣡'), + ('ࣣ', 'ॣ'), ('०', '९'), ('ॱ', 'ঃ'), ('অ', 'ঌ'), + ('এ', 'ঐ'), ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), + ('শ', 'হ'), ('়', 'ৄ'), ('ে', 'ৈ'), ('ো', 'ৎ'), + ('ৗ', 'ৗ'), ('ড়', 'ঢ়'), ('য়', 'à§£'), ('০', 'à§±'), + ('à§¼', 'à§¼'), ('\u{9fe}', '\u{9fe}'), ('ਁ', 'ਃ'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('਼', '਼'), ('ਾ', 'ੂ'), + ('ੇ', 'ੈ'), ('ੋ', '੍'), ('ੑ', 'ੑ'), ('ਖ਼', 'ੜ'), + ('ਫ਼', 'ਫ਼'), ('੦', 'ੵ'), ('ઁ', 'ઃ'), ('અ', 'ઍ'), + ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), ('લ', 'ળ'), + ('વ', 'હ'), ('઼', 'ૅ'), ('ે', 'ૉ'), ('ો', '્'), + ('ૐ', 'ૐ'), ('à« ', 'à«£'), ('૦', '૯'), ('ૹ', 'à«¿'), + ('ଁ', 'ଃ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), + ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), ('଼', 'ୄ'), + ('େ', 'ୈ'), ('ୋ', '୍'), ('ୖ', 'ୗ'), ('ଡ଼', 'ଢ଼'), + ('ୟ', 'à­£'), ('à­¦', 'à­¯'), ('à­±', 'à­±'), ('ஂ', 'ஃ'), + ('அ', 'ஊ'), ('எ', 'ஐ'), ('ஒ', 'க'), ('ங', 'ச'), + ('ஜ', 'ஜ'), ('ஞ', 'ட'), ('ண', 'த'), ('ந', 'ப'), + ('à®®', 'ஹ'), ('ா', 'ூ'), ('ெ', 'ை'), ('ொ', '்'), + ('ௐ', 'ௐ'), ('ௗ', 'ௗ'), ('௦', '௯'), ('ఀ', 'ఌ'), + ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'ౄ'), + ('ె', 'ై'), ('ొ', '్'), ('ౕ', 'ౖ'), ('ౘ', 'ౚ'), + ('à± ', 'à±£'), ('౦', '౯'), ('ಀ', 'ಃ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('಼', 'ೄ'), ('ೆ', 'ೈ'), ('ೊ', '್'), ('ೕ', 'ೖ'), + ('ೞ', 'ೞ'), ('à³ ', 'à³£'), ('೦', '೯'), ('à³±', 'à³²'), + ('ഀ', 'ഃ'), ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'ൄ'), + ('െ', 'ൈ'), ('ൊ', 'ൎ'), ('ൔ', 'ൗ'), ('ൟ', 'ൣ'), + ('൦', '൯'), ('ൺ', 'ൿ'), ('ං', 'ඃ'), ('අ', 'ඖ'), + ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), ('ව', 'ෆ'), + ('්', '්'), ('ා', 'ු'), ('ූ', 'ූ'), ('ෘ', 'ෟ'), + ('à·¦', 'à·¯'), ('à·²', 'à·³'), ('ก', 'ฺ'), ('เ', '๎'), + ('๐', '๙'), ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), + ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), + ('ມ', 'ຣ'), ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), + ('ອ', 'ູ'), ('ົ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), + ('່', 'ໍ'), ('໐', '໙'), ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), + ('༘', '༙'), ('༠', '༩'), ('༵', '༵'), ('༷', '༷'), + ('༹', '༹'), ('༾', 'ཇ'), ('ཉ', 'ཬ'), ('ཱ', '྄'), + ('྆', 'ྗ'), ('ྙ', 'ྼ'), ('࿆', '࿆'), ('က', '၉'), + ('ၐ', 'ႝ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('ა', 'ჺ'), ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), + ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), + ('ነ', 'ኰ'), ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), + ('ዂ', 'ዅ'), ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), + ('ጘ', 'ፚ'), ('፝', '፟'), ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), + ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), + ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), ('ᜎ', '᜔'), + ('ᜠ', '᜴'), ('ᝀ', 'ᝓ'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), + ('ᝲ', 'ᝳ'), ('ក', '៓'), ('ៗ', 'ៗ'), ('ៜ', '៝'), + ('០', '៩'), ('᠋', '᠍'), ('᠐', '᠙'), ('á  ', '\u{1878}'), + ('ᢀ', 'ᢪ'), ('ᢰ', 'ᣵ'), ('ᤀ', 'ᤞ'), ('ᤠ', 'ᤫ'), + ('ᤰ', '᤻'), ('᥆', 'ᥭ'), ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), ('᧐', '᧙'), ('ᨀ', 'ᨛ'), ('ᨠ', 'ᩞ'), + ('á© ', '᩼'), ('á©¿', '᪉'), ('᪐', '᪙'), ('ᪧ', 'ᪧ'), + ('᪰', '᪾'), ('ᬀ', 'ᭋ'), ('᭐', '᭙'), ('á­«', 'á­³'), + ('ᮀ', '᯳'), ('ᰀ', 'á°·'), ('᱀', '᱉'), ('ᱍ', 'á±½'), + ('ᲀ', 'ᲈ'), ('\u{1c90}', '\u{1cba}'), ('\u{1cbd}', '\u{1cbf}'), + ('᳐', '᳒'), ('᳔', 'á³¹'), ('ᴀ', 'á·¹'), ('á·»', 'ἕ'), + ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), + ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), + ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('\u{200c}', '\u{200d}'), ('‿', '⁀'), + ('⁔', '⁔'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), + ('⃐', '⃰'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), + ('ℨ', 'ℨ'), ('K', 'ℭ'), ('ℯ', 'ℹ'), ('ℼ', 'ℿ'), + ('ⅅ', 'ⅉ'), ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('Ⓐ', 'ⓩ'), + ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('â± ', 'ⳤ'), ('Ⳬ', 'â³³'), + ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), ('â´°', 'âµ§'), + ('ⵯ', 'ⵯ'), ('⵿', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), + ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), + ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('â· ', 'â·¿'), ('ⸯ', 'ⸯ'), + ('々', '〇'), ('〡', '〯'), ('〱', '〵'), ('〸', '〼'), + ('ぁ', 'ゖ'), ('゙', '゚'), ('ゝ', 'ゟ'), ('ァ', 'ヺ'), + ('ー', 'ヿ'), ('ㄅ', '\u{312f}'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), + ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '\u{9fef}'), ('ꀀ', 'ꒌ'), + ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘫ'), ('Ꙁ', '꙲'), + ('ꙴ', '꙽'), ('ꙿ', '꛱'), ('ꜗ', 'ꜟ'), ('Ꜣ', 'ꞈ'), + ('Ꞌ', '\u{a7b9}'), ('ꟷ', 'ê §'), ('ꡀ', 'ꡳ'), ('ꢀ', 'ꣅ'), + ('꣐', '꣙'), ('꣠', 'ꣷ'), ('ꣻ', 'ꣻ'), ('ꣽ', '꤭'), + ('ꤰ', '꥓'), ('ꥠ', 'ꥼ'), ('ꦀ', '꧀'), ('ꧏ', '꧙'), + ('ê§ ', 'ê§¾'), ('ꨀ', 'ꨶ'), ('ꩀ', 'ꩍ'), ('꩐', '꩙'), + ('ê© ', 'ê©¶'), ('ꩺ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫯ'), + ('ꫲ', 'ê«¶'), ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), + ('ê­°', 'ꯪ'), ('꯬', '꯭'), ('꯰', '꯹'), ('가', '힣'), + ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), ('ï©°', '龎'), + ('ff', 'st'), ('ﬓ', 'ﬗ'), ('יִ', 'ﬨ'), ('שׁ', 'זּ'), + ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), + ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), + ('ï·°', 'ï·»'), ('︀', '️'), ('︠', '︯'), ('︳', '︴'), + ('﹍', '﹏'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), ('0', '9'), + ('A', 'Z'), ('_', '_'), ('a', 'z'), ('ヲ', 'ï¾¾'), + ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), + ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), + ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐅀', '𐅴'), + ('𐇽', '𐇽'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐋠', '𐋠'), + ('𐌀', '𐌟'), ('𐌭', '𐍊'), ('𐍐', '𐍺'), ('𐎀', '𐎝'), + ('𐎠', '𐏃'), ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐐀', '𐒝'), + ('𐒠', '𐒩'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '𐨃'), ('𐨅', '𐨆'), + ('𐨌', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '\u{10a35}'), ('𐨸', '𐨺'), + ('𐨿', '𐨿'), ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), + ('𐫉', '𐫦'), ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), + ('𐮀', '𐮑'), ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), + ('\u{10d00}', '\u{10d27}'), ('\u{10d30}', '\u{10d39}'), + ('\u{10f00}', '\u{10f1c}'), ('\u{10f27}', '\u{10f27}'), + ('\u{10f30}', '\u{10f50}'), ('𑀀', '𑁆'), ('𑁦', '𑁯'), + ('𑁿', '𑂺'), ('𑃐', '𑃨'), ('𑃰', '𑃹'), ('𑄀', '𑄴'), + ('𑄶', '𑄿'), ('\u{11144}', '\u{11146}'), ('𑅐', '𑅳'), + ('𑅶', '𑅶'), ('𑆀', '𑇄'), ('𑇉', '𑇌'), ('𑇐', '𑇚'), + ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '𑈷'), ('𑈾', '𑈾'), + ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), + ('𑊟', '𑊨'), ('𑊰', '𑋪'), ('𑋰', '𑋹'), ('𑌀', '𑌃'), + ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), ('𑌪', '𑌰'), + ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('\u{1133b}', '𑍄'), ('𑍇', '𑍈'), + ('𑍋', '𑍍'), ('𑍐', '𑍐'), ('𑍗', '𑍗'), ('𑍝', '𑍣'), + ('𑍦', '𑍬'), ('𑍰', '𑍴'), ('𑐀', '𑑊'), ('𑑐', '𑑙'), + ('\u{1145e}', '\u{1145e}'), ('𑒀', '𑓅'), ('𑓇', '𑓇'), + ('𑓐', '𑓙'), ('𑖀', '𑖵'), ('𑖸', '𑗀'), ('𑗘', '𑗝'), + ('𑘀', '𑙀'), ('𑙄', '𑙄'), ('𑙐', '𑙙'), ('𑚀', '𑚷'), + ('𑛀', '𑛉'), ('𑜀', '\u{1171a}'), ('𑜝', '𑜫'), ('𑜰', '𑜹'), + ('\u{11800}', '\u{1183a}'), ('𑢠', '𑣩'), ('𑣿', '𑣿'), + ('𑨀', '𑨾'), ('𑩇', '𑩇'), ('𑩐', '𑪃'), ('𑪆', '𑪙'), + ('\u{11a9d}', '\u{11a9d}'), ('𑫀', '𑫸'), ('𑰀', '𑰈'), + ('𑰊', '𑰶'), ('𑰸', '𑱀'), ('𑱐', '𑱙'), ('𑱲', '𑲏'), + ('𑲒', '𑲧'), ('𑲩', '𑲶'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), + ('𑴋', '𑴶'), ('𑴺', '𑴺'), ('𑴼', '𑴽'), ('𑴿', '𑵇'), + ('𑵐', '𑵙'), ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d8e}'), ('\u{11d90}', '\u{11d91}'), + ('\u{11d93}', '\u{11d98}'), ('\u{11da0}', '\u{11da9}'), + ('\u{11ee0}', '\u{11ef6}'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), + ('𒒀', '𒕃'), ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), + ('𖩀', '𖩞'), ('𖩠', '𖩩'), ('𖫐', '𖫭'), ('𖫰', '𖫴'), + ('𖬀', '𖬶'), ('𖭀', '𖭃'), ('𖭐', '𖭙'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('\u{16e40}', '\u{16e7f}'), ('𖼀', '𖽄'), + ('𖽐', '𖽾'), ('𖾏', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '\u{187f1}'), + ('𘠀', '𘫲'), ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), + ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𛲝', '𛲞'), + ('𝅥', '𝅩'), ('𝅭', '𝅲'), ('𝅻', '𝆂'), ('𝆅', '𝆋'), + ('𝆪', '𝆭'), ('𝉂', '𝉄'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), ('𝛜', '𝛺'), + ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), ('𝝐', '𝝮'), + ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), ('𝟄', '𝟋'), + ('𝟎', '𝟿'), ('𝨀', '𝨶'), ('𝨻', '𝩬'), ('𝩵', '𝩵'), + ('𝪄', '𝪄'), ('𝪛', '𝪟'), ('𝪡', '𝪯'), ('𞀀', '𞀆'), + ('𞀈', '𞀘'), ('𞀛', '𞀡'), ('𞀣', '𞀤'), ('𞀦', '𞀪'), + ('𞠀', '𞣄'), ('𞣐', '𞣖'), ('𞤀', '𞥊'), ('𞥐', '𞥙'), + ('𞸀', '𞸃'), ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), + ('𞸧', '𞸧'), ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), + ('𞸻', '𞸻'), ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), + ('𞹋', '𞹋'), ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), + ('𞹗', '𞹗'), ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), + ('𞹟', '𞹟'), ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), + ('𞹬', '𞹲'), ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), + ('𞺀', '𞺉'), ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), + ('𞺫', '𞺻'), ('🄰', '🅉'), ('🅐', '🅩'), ('🅰', '🆉'), + ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), ('丽', '𪘀'), ('󠄀', '󠇯'), +]; diff --git a/regex-syntax/src/unicode_tables/property_bool.rs b/regex-syntax/src/unicode_tables/property_bool.rs new file mode 100644 index 000000000..e34bb7383 --- /dev/null +++ b/regex-syntax/src/unicode_tables/property_bool.rs @@ -0,0 +1,2960 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-bool /home/andrew/tmp/ucd-11.0.0 --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ASCII_Hex_Digit", ASCII_HEX_DIGIT), ("Alphabetic", ALPHABETIC), + ("Bidi_Control", BIDI_CONTROL), ("Case_Ignorable", CASE_IGNORABLE), + ("Cased", CASED), ("Changes_When_Casefolded", CHANGES_WHEN_CASEFOLDED), + ("Changes_When_Casemapped", CHANGES_WHEN_CASEMAPPED), + ("Changes_When_Lowercased", CHANGES_WHEN_LOWERCASED), + ("Changes_When_Titlecased", CHANGES_WHEN_TITLECASED), + ("Changes_When_Uppercased", CHANGES_WHEN_UPPERCASED), ("Dash", DASH), + ("Default_Ignorable_Code_Point", DEFAULT_IGNORABLE_CODE_POINT), + ("Deprecated", DEPRECATED), ("Diacritic", DIACRITIC), ("Emoji", EMOJI), + ("Emoji_Component", EMOJI_COMPONENT), ("Emoji_Modifier", EMOJI_MODIFIER), + ("Emoji_Modifier_Base", EMOJI_MODIFIER_BASE), + ("Emoji_Presentation", EMOJI_PRESENTATION), + ("Extended_Pictographic", EXTENDED_PICTOGRAPHIC), ("Extender", EXTENDER), + ("Grapheme_Base", GRAPHEME_BASE), ("Grapheme_Extend", GRAPHEME_EXTEND), + ("Grapheme_Link", GRAPHEME_LINK), ("Hex_Digit", HEX_DIGIT), + ("Hyphen", HYPHEN), ("IDS_Binary_Operator", IDS_BINARY_OPERATOR), + ("IDS_Trinary_Operator", IDS_TRINARY_OPERATOR), + ("ID_Continue", ID_CONTINUE), ("ID_Start", ID_START), + ("Ideographic", IDEOGRAPHIC), ("Join_Control", JOIN_CONTROL), + ("Logical_Order_Exception", LOGICAL_ORDER_EXCEPTION), + ("Lowercase", LOWERCASE), ("Math", MATH), + ("Noncharacter_Code_Point", NONCHARACTER_CODE_POINT), + ("Other_Alphabetic", OTHER_ALPHABETIC), + ("Other_Default_Ignorable_Code_Point", OTHER_DEFAULT_IGNORABLE_CODE_POINT), + ("Other_Grapheme_Extend", OTHER_GRAPHEME_EXTEND), + ("Other_ID_Continue", OTHER_ID_CONTINUE), + ("Other_ID_Start", OTHER_ID_START), ("Other_Lowercase", OTHER_LOWERCASE), + ("Other_Math", OTHER_MATH), ("Other_Uppercase", OTHER_UPPERCASE), + ("Pattern_Syntax", PATTERN_SYNTAX), + ("Pattern_White_Space", PATTERN_WHITE_SPACE), + ("Prepended_Concatenation_Mark", PREPENDED_CONCATENATION_MARK), + ("Quotation_Mark", QUOTATION_MARK), ("Radical", RADICAL), + ("Regional_Indicator", REGIONAL_INDICATOR), + ("Sentence_Terminal", SENTENCE_TERMINAL), ("Soft_Dotted", SOFT_DOTTED), + ("Terminal_Punctuation", TERMINAL_PUNCTUATION), + ("Unified_Ideograph", UNIFIED_IDEOGRAPH), ("Uppercase", UPPERCASE), + ("Variation_Selector", VARIATION_SELECTOR), ("White_Space", WHITE_SPACE), + ("XID_Continue", XID_CONTINUE), ("XID_Start", XID_START), +]; + +pub const ASCII_HEX_DIGIT: &'static [(char, char)] = &[ + ('0', '9'), ('A', 'F'), ('a', 'f'), +]; + +pub const ALPHABETIC: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('\u{345}', '\u{345}'), ('Ͱ', 'Í´'), + ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('Ҋ', 'Ô¯'), + ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), ('Õ ', 'ֈ'), ('\u{5b0}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('א', 'ת'), ('ׯ', 'ײ'), ('\u{610}', '\u{61a}'), + ('Ø ', '\u{657}'), ('\u{659}', '\u{65f}'), ('Ù®', 'ۓ'), ('ە', '\u{6dc}'), + ('\u{6e1}', '\u{6e8}'), ('\u{6ed}', 'Û¯'), ('Ûº', 'Û¼'), ('Û¿', 'Û¿'), + ('ܐ', '\u{73f}'), ('ݍ', 'Þ±'), ('ߊ', 'ߪ'), ('ß´', 'ßµ'), ('ߺ', 'ߺ'), + ('ࠀ', '\u{817}'), ('ࠚ', '\u{82c}'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), + ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('\u{8d4}', '\u{8df}'), + ('\u{8e3}', '\u{8e9}'), ('\u{8f0}', 'ऻ'), ('ऽ', 'ौ'), ('ॎ', 'ॐ'), + ('\u{955}', '\u{963}'), ('ॱ', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('ঽ', '\u{9c4}'), ('ে', 'ৈ'), ('ো', 'ৌ'), ('ৎ', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), ('ড়', 'ঢ়'), ('য়', '\u{9e3}'), ('à§°', 'à§±'), + ('à§¼', 'à§¼'), ('\u{a01}', 'ਃ'), ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), + ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), ('ਾ', '\u{a42}'), ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4c}'), ('\u{a51}', '\u{a51}'), ('ਖ਼', 'ੜ'), + ('ਫ਼', 'ਫ਼'), ('\u{a70}', '\u{a75}'), ('\u{a81}', 'ઃ'), ('અ', 'ઍ'), + ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), ('લ', 'ળ'), + ('વ', 'હ'), ('ઽ', '\u{ac5}'), ('\u{ac7}', 'ૉ'), ('ો', 'ૌ'), + ('ૐ', 'ૐ'), ('à« ', '\u{ae3}'), ('ૹ', '\u{afc}'), ('\u{b01}', 'ଃ'), + ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), + ('ଲ', 'ଳ'), ('ଵ', 'ହ'), ('ଽ', '\u{b44}'), ('େ', 'ୈ'), + ('ୋ', 'ୌ'), ('\u{b56}', '\u{b57}'), ('ଡ଼', 'ଢ଼'), ('ୟ', '\u{b63}'), + ('à­±', 'à­±'), ('\u{b82}', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), ('ொ', 'ௌ'), ('ௐ', 'ௐ'), ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', 'ః'), ('అ', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), + ('à°ª', 'à°¹'), ('à°½', 'ౄ'), ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4c}'), ('\u{c55}', '\u{c56}'), ('ౘ', 'ౚ'), + ('à± ', '\u{c63}'), ('ಀ', 'ಃ'), ('ಅ', 'ಌ'), ('ಎ', 'ಐ'), + ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), ('ಽ', 'ೄ'), + ('\u{cc6}', 'ೈ'), ('ೊ', '\u{ccc}'), ('\u{cd5}', '\u{cd6}'), + ('ೞ', 'ೞ'), ('à³ ', '\u{ce3}'), ('à³±', 'à³²'), ('\u{d00}', 'ഃ'), + ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), ('à´½', '\u{d44}'), + ('െ', 'ൈ'), ('ൊ', 'ൌ'), ('ൎ', 'ൎ'), ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), ('ൺ', 'ൿ'), ('ං', 'ඃ'), ('අ', 'ඖ'), + ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), ('ව', 'ෆ'), + ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), + ('à·²', 'à·³'), ('ก', '\u{e3a}'), ('เ', 'ๆ'), ('\u{e4d}', '\u{e4d}'), + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', '\u{eb9}'), + ('\u{ebb}', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('\u{ecd}', '\u{ecd}'), + ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), ('ཉ', 'ཬ'), + ('\u{f71}', '\u{f81}'), ('ྈ', '\u{f97}'), ('\u{f99}', '\u{fbc}'), + ('က', '\u{1036}'), ('း', 'း'), ('ျ', 'ဿ'), ('ၐ', 'ၢ'), + ('ၥ', 'ၨ'), ('ၮ', '\u{1086}'), ('ႎ', 'ႎ'), ('ႜ', '\u{109d}'), + ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), + ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), + ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), + ('\u{135f}', '\u{135f}'), ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), + ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), + ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), ('ᜎ', '\u{1713}'), ('ᜠ', '\u{1733}'), + ('ᝀ', '\u{1753}'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), + ('\u{1772}', '\u{1773}'), ('ក', 'ឳ'), ('ា', 'ៈ'), ('ៗ', 'ៗ'), + ('ៜ', 'ៜ'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('\u{1920}', 'ᤫ'), ('ᤰ', 'ᤸ'), ('ᥐ', 'ᥭ'), + ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('ᨀ', '\u{1a1b}'), + ('ᨠ', '\u{1a5e}'), ('á©¡', '\u{1a74}'), ('ᪧ', 'ᪧ'), + ('\u{1b00}', 'ᬳ'), ('ᬵ', 'ᭃ'), ('ᭅ', 'ᭋ'), + ('\u{1b80}', '\u{1ba9}'), ('\u{1bac}', 'ᮯ'), ('ᮺ', 'ᯥ'), + ('ᯧ', '\u{1bf1}'), ('ᰀ', 'á°µ'), ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), + ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), ('á³µ', 'á³¶'), ('ᴀ', 'á¶¿'), ('\u{1de7}', '\u{1df4}'), + ('Ḁ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), + ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), + ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), + ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), + ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('ⁱ', 'ⁱ'), + ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), + ('ℊ', 'ℓ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), ('ℤ', 'ℤ'), + ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), ('ℯ', 'ℹ'), + ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), + ('Ⓐ', 'ⓩ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('â± ', 'ⳤ'), + ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), + ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), ('ⶀ', 'ⶖ'), + ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), + ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), + ('\u{2de0}', '\u{2dff}'), ('ⸯ', 'ⸯ'), ('々', '〇'), ('〡', '〩'), + ('〱', '〵'), ('〸', '〼'), ('ぁ', 'ゖ'), ('ゝ', 'ゟ'), + ('ァ', 'ヺ'), ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆺ'), ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '鿯'), + ('ꀀ', 'ꒌ'), ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), + ('ꘪ', 'ꘫ'), ('Ꙁ', 'ꙮ'), ('\u{a674}', '\u{a67b}'), ('ꙿ', 'ꛯ'), + ('ꜗ', 'ꜟ'), ('Ꜣ', 'ꞈ'), ('Ꞌ', 'ꞹ'), ('ꟷ', 'ꠁ'), + ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), ('ꠌ', 'ê §'), ('ꡀ', 'ꡳ'), + ('ꢀ', 'ꣃ'), ('\u{a8c5}', '\u{a8c5}'), ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), ('ꤊ', '\u{a92a}'), ('ꤰ', 'ꥒ'), ('ꥠ', 'ꥼ'), + ('\u{a980}', 'ꦲ'), ('ꦴ', 'ꦿ'), ('ꧏ', 'ꧏ'), ('ê§ ', 'ꧤ'), + ('ꧦ', 'ꧯ'), ('ꧺ', 'ê§¾'), ('ꨀ', '\u{aa36}'), ('ꩀ', 'ꩍ'), + ('ê© ', 'ê©¶'), ('ꩺ', 'ꩺ'), ('ꩾ', '\u{aabe}'), ('ꫀ', 'ꫀ'), + ('ꫂ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫯ'), ('ꫲ', 'ꫵ'), + ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), ('ê­°', 'ꯪ'), + ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), + ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('יִ', 'ﬨ'), + ('שׁ', 'זּ'), ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), + ('ףּ', 'פּ'), ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), + ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), + ('A', 'Z'), ('a', 'z'), ('ヲ', 'ï¾¾'), ('ᅡ', 'ᅦ'), + ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), + ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), ('𐀿', '𐁍'), + ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐅀', '𐅴'), ('𐊀', '𐊜'), + ('𐊠', '𐋐'), ('𐌀', '𐌟'), ('𐌭', '𐍊'), ('𐍐', '\u{1037a}'), + ('𐎀', '𐎝'), ('𐎠', '𐏃'), ('𐏈', '𐏏'), ('𐏑', '𐏕'), + ('𐐀', '𐒝'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '𐨓'), ('𐨕', '𐨗'), + ('𐨙', '𐨵'), ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), + ('𐫉', '𐫤'), ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), + ('𐮀', '𐮑'), ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), + ('𐴀', '\u{10d27}'), ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '𐽅'), + ('𑀀', '\u{11045}'), ('𑂂', '𑂸'), ('𑃐', '𑃨'), + ('\u{11100}', '\u{11132}'), ('𑅄', '𑅆'), ('𑅐', '𑅲'), + ('𑅶', '𑅶'), ('\u{11180}', '𑆿'), ('𑇁', '𑇄'), ('𑇚', '𑇚'), + ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '\u{11234}'), + ('\u{11237}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), ('𑊀', '𑊆'), + ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), + ('𑊰', '\u{112e8}'), ('\u{11300}', '𑌃'), ('𑌅', '𑌌'), + ('𑌏', '𑌐'), ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), + ('𑌵', '𑌹'), ('𑌽', '𑍄'), ('𑍇', '𑍈'), ('𑍋', '𑍌'), + ('𑍐', '𑍐'), ('\u{11357}', '\u{11357}'), ('𑍝', '𑍣'), + ('𑐀', '𑑁'), ('\u{11443}', '𑑅'), ('𑑇', '𑑊'), ('𑒀', '𑓁'), + ('𑓄', '𑓅'), ('𑓇', '𑓇'), ('𑖀', '\u{115b5}'), ('𑖸', '𑖾'), + ('𑗘', '\u{115dd}'), ('𑘀', '𑘾'), ('\u{11640}', '\u{11640}'), + ('𑙄', '𑙄'), ('𑚀', '\u{116b5}'), ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172a}'), ('𑠀', '𑠸'), ('𑢠', '𑣟'), + ('𑣿', '𑣿'), ('𑨀', '𑨲'), ('\u{11a35}', '\u{11a3e}'), + ('𑩐', '𑪃'), ('𑪆', '𑪗'), ('𑪝', '𑪝'), ('𑫀', '𑫸'), + ('𑰀', '𑰈'), ('𑰊', '\u{11c36}'), ('\u{11c38}', '𑰾'), + ('𑱀', '𑱀'), ('𑱲', '𑲏'), ('\u{11c92}', '\u{11ca7}'), + ('𑲩', '\u{11cb6}'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), + ('𑴋', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d41}'), + ('\u{11d43}', '\u{11d43}'), ('𑵆', '\u{11d47}'), ('𑵠', '𑵥'), + ('𑵧', '𑵨'), ('𑵪', '𑶎'), ('\u{11d90}', '\u{11d91}'), + ('𑶓', '𑶖'), ('𑶘', '𑶘'), ('𑻠', '𑻶'), ('𒀀', '𒎙'), + ('𒐀', '𒑮'), ('𒒀', '𒕃'), ('𓀀', '𓐮'), ('𔐀', '𔙆'), + ('𖠀', '𖨸'), ('𖩀', '𖩞'), ('𖫐', '𖫭'), ('𖬀', '\u{16b36}'), + ('𖭀', '𖭃'), ('𖭣', '𖭷'), ('𖭽', '𖮏'), ('𖹀', '𖹿'), + ('𖼀', '𖽄'), ('𖽐', '𖽾'), ('𖾓', '𖾟'), ('𖿠', '𖿡'), + ('𗀀', '𘟱'), ('𘠀', '𘫲'), ('𛀀', '𛄞'), ('𛅰', '𛋻'), + ('𛰀', '𛱪'), ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), + ('\u{1bc9e}', '\u{1bc9e}'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), ('𝛜', '𝛺'), + ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), ('𝝐', '𝝮'), + ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), ('𝟄', '𝟋'), + ('\u{1e000}', '\u{1e006}'), ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), ('𞠀', '𞣄'), ('𞤀', '𞥃'), + ('\u{1e947}', '\u{1e947}'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('🄰', '🅉'), + ('🅐', '🅩'), ('🅰', '🆉'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), + ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const BIDI_CONTROL: &'static [(char, char)] = &[ + ('\u{61c}', '\u{61c}'), ('\u{200e}', '\u{200f}'), ('\u{202a}', '\u{202e}'), + ('\u{2066}', '\u{2069}'), +]; + +pub const CASE_IGNORABLE: &'static [(char, char)] = &[ + ('\'', '\''), ('.', '.'), (':', ':'), ('^', '^'), ('`', '`'), ('¨', '¨'), + ('\u{ad}', '\u{ad}'), ('¯', '¯'), ('´', '´'), ('·', '¸'), + ('ʰ', '\u{36f}'), ('Í´', '͵'), ('ͺ', 'ͺ'), ('΄', '΅'), ('·', '·'), + ('\u{483}', '\u{489}'), ('ՙ', 'ՙ'), ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('×´', '×´'), ('\u{600}', '\u{605}'), + ('\u{610}', '\u{61a}'), ('\u{61c}', '\u{61c}'), ('ـ', 'ـ'), + ('\u{64b}', '\u{65f}'), ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dd}'), + ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{70f}', '\u{70f}'), + ('\u{711}', '\u{711}'), ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), + ('\u{7eb}', 'ßµ'), ('ߺ', 'ߺ'), ('\u{7fd}', '\u{7fd}'), + ('\u{816}', '\u{82d}'), ('\u{859}', '\u{85b}'), ('\u{8d3}', '\u{902}'), + ('\u{93a}', '\u{93a}'), ('\u{93c}', '\u{93c}'), ('\u{941}', '\u{948}'), + ('\u{94d}', '\u{94d}'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), + ('ॱ', 'ॱ'), ('\u{981}', '\u{981}'), ('\u{9bc}', '\u{9bc}'), + ('\u{9c1}', '\u{9c4}'), ('\u{9cd}', '\u{9cd}'), ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), ('\u{a01}', '\u{a02}'), ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), ('\u{b01}', '\u{b01}'), ('\u{b3c}', '\u{b3c}'), + ('\u{b3f}', '\u{b3f}'), ('\u{b41}', '\u{b44}'), ('\u{b4d}', '\u{b4d}'), + ('\u{b56}', '\u{b56}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'), + ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), ('\u{c00}', '\u{c00}'), + ('\u{c04}', '\u{c04}'), ('\u{c3e}', '\u{c40}'), ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), + ('\u{c81}', '\u{c81}'), ('\u{cbc}', '\u{cbc}'), ('\u{cbf}', '\u{cbf}'), + ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', '\u{d01}'), ('\u{d3b}', '\u{d3c}'), ('\u{d41}', '\u{d44}'), + ('\u{d4d}', '\u{d4d}'), ('\u{d62}', '\u{d63}'), ('\u{dca}', '\u{dca}'), + ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('\u{e31}', '\u{e31}'), + ('\u{e34}', '\u{e3a}'), ('ๆ', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), + ('\u{eb4}', '\u{eb9}'), ('\u{ebb}', '\u{ebc}'), ('ໆ', 'ໆ'), + ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f71}', '\u{f7e}'), + ('\u{f80}', '\u{f84}'), ('\u{f86}', '\u{f87}'), ('\u{f8d}', '\u{f97}'), + ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), ('\u{102d}', '\u{1030}'), + ('\u{1032}', '\u{1037}'), ('\u{1039}', '\u{103a}'), + ('\u{103d}', '\u{103e}'), ('\u{1058}', '\u{1059}'), + ('\u{105e}', '\u{1060}'), ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{1082}'), ('\u{1085}', '\u{1086}'), + ('\u{108d}', '\u{108d}'), ('\u{109d}', '\u{109d}'), ('ჼ', 'ჼ'), + ('\u{135d}', '\u{135f}'), ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1734}'), ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), ('\u{17b4}', '\u{17b5}'), + ('\u{17b7}', '\u{17bd}'), ('\u{17c6}', '\u{17c6}'), + ('\u{17c9}', '\u{17d3}'), ('ៗ', 'ៗ'), ('\u{17dd}', '\u{17dd}'), + ('\u{180b}', '\u{180e}'), ('ᡃ', 'ᡃ'), ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), ('\u{1920}', '\u{1922}'), + ('\u{1927}', '\u{1928}'), ('\u{1932}', '\u{1932}'), + ('\u{1939}', '\u{193b}'), ('\u{1a17}', '\u{1a18}'), + ('\u{1a1b}', '\u{1a1b}'), ('\u{1a56}', '\u{1a56}'), + ('\u{1a58}', '\u{1a5e}'), ('\u{1a60}', '\u{1a60}'), + ('\u{1a62}', '\u{1a62}'), ('\u{1a65}', '\u{1a6c}'), + ('\u{1a73}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1abe}'), ('\u{1b00}', '\u{1b03}'), + ('\u{1b34}', '\u{1b34}'), ('\u{1b36}', '\u{1b3a}'), + ('\u{1b3c}', '\u{1b3c}'), ('\u{1b42}', '\u{1b42}'), + ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1b81}'), + ('\u{1ba2}', '\u{1ba5}'), ('\u{1ba8}', '\u{1ba9}'), + ('\u{1bab}', '\u{1bad}'), ('\u{1be6}', '\u{1be6}'), + ('\u{1be8}', '\u{1be9}'), ('\u{1bed}', '\u{1bed}'), + ('\u{1bef}', '\u{1bf1}'), ('\u{1c2c}', '\u{1c33}'), + ('\u{1c36}', '\u{1c37}'), ('ᱸ', 'á±½'), ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce0}'), ('\u{1ce2}', '\u{1ce8}'), + ('\u{1ced}', '\u{1ced}'), ('\u{1cf4}', '\u{1cf4}'), + ('\u{1cf8}', '\u{1cf9}'), ('á´¬', 'ᵪ'), ('ᵸ', 'ᵸ'), + ('ᶛ', '\u{1df9}'), ('\u{1dfb}', '\u{1dff}'), ('á¾½', 'á¾½'), + ('᾿', '῁'), ('῍', '῏'), ('῝', '῟'), ('á¿­', '`'), + ('´', '῾'), ('\u{200b}', '\u{200f}'), ('‘', '’'), ('․', '․'), + ('‧', '‧'), ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), + ('\u{20d0}', '\u{20f0}'), ('â±¼', 'â±½'), ('\u{2cef}', '\u{2cf1}'), + ('ⵯ', 'ⵯ'), ('\u{2d7f}', '\u{2d7f}'), ('\u{2de0}', '\u{2dff}'), + ('ⸯ', 'ⸯ'), ('々', '々'), ('\u{302a}', '\u{302d}'), ('〱', '〵'), + ('〻', '〻'), ('\u{3099}', 'ゞ'), ('ー', 'ヾ'), ('ꀕ', 'ꀕ'), + ('ꓸ', 'ꓽ'), ('ꘌ', 'ꘌ'), ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), ('ꙿ', 'ꙿ'), ('ꚜ', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), ('꜀', '꜡'), ('ꝰ', 'ꝰ'), ('ꞈ', '꞊'), + ('ꟸ', 'ꟹ'), ('\u{a802}', '\u{a802}'), ('\u{a806}', '\u{a806}'), + ('\u{a80b}', '\u{a80b}'), ('\u{a825}', '\u{a826}'), + ('\u{a8c4}', '\u{a8c5}'), ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), ('\u{a926}', '\u{a92d}'), + ('\u{a947}', '\u{a951}'), ('\u{a980}', '\u{a982}'), + ('\u{a9b3}', '\u{a9b3}'), ('\u{a9b6}', '\u{a9b9}'), + ('\u{a9bc}', '\u{a9bc}'), ('ꧏ', 'ꧏ'), ('\u{a9e5}', 'ꧦ'), + ('\u{aa29}', '\u{aa2e}'), ('\u{aa31}', '\u{aa32}'), + ('\u{aa35}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), + ('\u{aa4c}', '\u{aa4c}'), ('ê©°', 'ê©°'), ('\u{aa7c}', '\u{aa7c}'), + ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), ('ꫝ', 'ꫝ'), ('\u{aaec}', '\u{aaed}'), + ('ꫳ', 'ê«´'), ('\u{aaf6}', '\u{aaf6}'), ('꭛', 'ꭟ'), + ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), ('﮲', '﯁'), + ('\u{fe00}', '\u{fe0f}'), ('︓', '︓'), ('\u{fe20}', '\u{fe2f}'), + ('﹒', '﹒'), ('﹕', '﹕'), ('\u{feff}', '\u{feff}'), (''', '''), + ('.', '.'), (':', ':'), ('ï¼¾', 'ï¼¾'), ('`', '`'), + ('ï½°', 'ï½°'), ('\u{ff9e}', '\u{ff9f}'), ('ï¿£', 'ï¿£'), + ('\u{fff9}', '\u{fffb}'), ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), + ('\u{11001}', '\u{11001}'), ('\u{11038}', '\u{11046}'), + ('\u{1107f}', '\u{11081}'), ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), ('\u{111c9}', '\u{111cc}'), + ('\u{1122f}', '\u{11231}'), ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), + ('\u{112df}', '\u{112df}'), ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), ('\u{1133b}', '\u{1133c}'), + ('\u{11340}', '\u{11340}'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), ('\u{114b3}', '\u{114b8}'), + ('\u{114ba}', '\u{114ba}'), ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), ('\u{115b2}', '\u{115b5}'), + ('\u{115bc}', '\u{115bd}'), ('\u{115bf}', '\u{115c0}'), + ('\u{115dc}', '\u{115dd}'), ('\u{11633}', '\u{1163a}'), + ('\u{1163d}', '\u{1163d}'), ('\u{1163f}', '\u{11640}'), + ('\u{116ab}', '\u{116ab}'), ('\u{116ad}', '\u{116ad}'), + ('\u{116b0}', '\u{116b5}'), ('\u{116b7}', '\u{116b7}'), + ('\u{1171d}', '\u{1171f}'), ('\u{11722}', '\u{11725}'), + ('\u{11727}', '\u{1172b}'), ('\u{1182f}', '\u{11837}'), + ('\u{11839}', '\u{1183a}'), ('\u{11a01}', '\u{11a0a}'), + ('\u{11a33}', '\u{11a38}'), ('\u{11a3b}', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), ('\u{11a51}', '\u{11a56}'), + ('\u{11a59}', '\u{11a5b}'), ('\u{11a8a}', '\u{11a96}'), + ('\u{11a98}', '\u{11a99}'), ('\u{11c30}', '\u{11c36}'), + ('\u{11c38}', '\u{11c3d}'), ('\u{11c3f}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), ('\u{11caa}', '\u{11cb0}'), + ('\u{11cb2}', '\u{11cb3}'), ('\u{11cb5}', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), ('\u{11d90}', '\u{11d91}'), + ('\u{11d95}', '\u{11d95}'), ('\u{11d97}', '\u{11d97}'), + ('\u{11ef3}', '\u{11ef4}'), ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), ('𖭀', '𖭃'), ('\u{16f8f}', '𖾟'), + ('𖿠', '𖿡'), ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d167}', '\u{1d169}'), ('\u{1d173}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e944}', '\u{1e94a}'), ('🏻', '🏿'), + ('\u{e0001}', '\u{e0001}'), ('\u{e0020}', '\u{e007f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const CASED: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ƺ'), ('Ƽ', 'Æ¿'), ('DŽ', 'ʓ'), + ('ʕ', 'ʸ'), ('ˀ', 'ˁ'), ('Ë ', 'ˤ'), ('\u{345}', '\u{345}'), + ('Ͱ', 'ͳ'), ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), + ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), + ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('Õ ', 'ֈ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('Ꭰ', 'Ᏽ'), + ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), + ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), + ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), + ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), + ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), + ('ℯ', 'ℴ'), ('ℹ', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ⅰ', 'ⅿ'), ('Ↄ', 'ↄ'), ('Ⓐ', 'ⓩ'), + ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('â± ', 'ⳤ'), ('Ⳬ', 'â³®'), + ('â³²', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), + ('Ꙁ', 'ꙭ'), ('Ꚁ', 'ꚝ'), ('Ꜣ', 'ꞇ'), ('Ꞌ', 'ꞎ'), + ('Ꞑ', 'ꞹ'), ('ꟸ', 'ꟺ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), + ('ê­°', 'ꮿ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('A', 'Z'), + ('a', 'z'), ('𐐀', '𐑏'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𑢠', '𑣟'), ('𖹀', '𖹿'), + ('𝐀', '𝑔'), ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), + ('𝒥', '𝒦'), ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), + ('𝒽', '𝓃'), ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), + ('𝔖', '𝔜'), ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), + ('𝕆', '𝕆'), ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), + ('𝛂', '𝛚'), ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), + ('𝜶', '𝝎'), ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), + ('𝞪', '𝟂'), ('𝟄', '𝟋'), ('𞤀', '𞥃'), ('🄰', '🅉'), + ('🅐', '🅩'), ('🅰', '🆉'), +]; + +pub const CHANGES_WHEN_CASEFOLDED: &'static [(char, char)] = &[ + ('A', 'Z'), ('µ', 'µ'), ('À', 'Ö'), ('Ø', 'ß'), ('Ā', 'Ā'), + ('Ă', 'Ă'), ('Ą', 'Ą'), ('Ć', 'Ć'), ('Ĉ', 'Ĉ'), ('Ċ', 'Ċ'), + ('Č', 'Č'), ('Ď', 'Ď'), ('Đ', 'Đ'), ('Ē', 'Ē'), ('Ĕ', 'Ĕ'), + ('Ė', 'Ė'), ('Ę', 'Ę'), ('Ě', 'Ě'), ('Ĝ', 'Ĝ'), ('Ğ', 'Ğ'), + ('Ä ', 'Ä '), ('Ä¢', 'Ä¢'), ('Ĥ', 'Ĥ'), ('Ħ', 'Ħ'), ('Ĩ', 'Ĩ'), + ('Ī', 'Ī'), ('Ĭ', 'Ĭ'), ('Ä®', 'Ä®'), ('İ', 'İ'), ('IJ', 'IJ'), + ('Ä´', 'Ä´'), ('Ķ', 'Ķ'), ('Ĺ', 'Ĺ'), ('Ä»', 'Ä»'), ('Ľ', 'Ľ'), + ('Ä¿', 'Ä¿'), ('Ł', 'Ł'), ('Ń', 'Ń'), ('Ņ', 'Ņ'), ('Ň', 'Ň'), + ('ʼn', 'Ŋ'), ('Ō', 'Ō'), ('Ŏ', 'Ŏ'), ('Ő', 'Ő'), ('Œ', 'Œ'), + ('Ŕ', 'Ŕ'), ('Ŗ', 'Ŗ'), ('Ř', 'Ř'), ('Ś', 'Ś'), ('Ŝ', 'Ŝ'), + ('Ş', 'Ş'), ('Å ', 'Å '), ('Å¢', 'Å¢'), ('Ť', 'Ť'), ('Ŧ', 'Ŧ'), + ('Ũ', 'Ũ'), ('Ū', 'Ū'), ('Ŭ', 'Ŭ'), ('Å®', 'Å®'), ('Ű', 'Ű'), + ('Ų', 'Ų'), ('Å´', 'Å´'), ('Ŷ', 'Ŷ'), ('Ÿ', 'Ź'), ('Å»', 'Å»'), + ('Ž', 'Ž'), ('Å¿', 'Å¿'), ('Ɓ', 'Ƃ'), ('Ƅ', 'Ƅ'), ('Ɔ', 'Ƈ'), + ('Ɖ', 'Ƌ'), ('Ǝ', 'Ƒ'), ('Ɠ', 'Ɣ'), ('Ɩ', 'Ƙ'), ('Ɯ', 'Ɲ'), + ('Ɵ', 'Æ '), ('Æ¢', 'Æ¢'), ('Ƥ', 'Ƥ'), ('Ʀ', 'Ƨ'), ('Æ©', 'Æ©'), + ('Ƭ', 'Ƭ'), ('Æ®', 'Ư'), ('Ʊ', 'Ƴ'), ('Ƶ', 'Ƶ'), ('Æ·', 'Ƹ'), + ('Ƽ', 'Ƽ'), ('DŽ', 'Dž'), ('LJ', 'Lj'), ('NJ', 'Nj'), ('Ǎ', 'Ǎ'), + ('Ǐ', 'Ǐ'), ('Ǒ', 'Ǒ'), ('Ǔ', 'Ǔ'), ('Ǖ', 'Ǖ'), ('Ǘ', 'Ǘ'), + ('Ǚ', 'Ǚ'), ('Ǜ', 'Ǜ'), ('Ǟ', 'Ǟ'), ('Ç ', 'Ç '), ('Ç¢', 'Ç¢'), + ('Ǥ', 'Ǥ'), ('Ǧ', 'Ǧ'), ('Ǩ', 'Ǩ'), ('Ǫ', 'Ǫ'), ('Ǭ', 'Ǭ'), + ('Ç®', 'Ç®'), ('DZ', 'Dz'), ('Ç´', 'Ç´'), ('Ƕ', 'Ǹ'), ('Ǻ', 'Ǻ'), + ('Ǽ', 'Ǽ'), ('Ǿ', 'Ǿ'), ('Ȁ', 'Ȁ'), ('Ȃ', 'Ȃ'), ('Ȅ', 'Ȅ'), + ('Ȇ', 'Ȇ'), ('Ȉ', 'Ȉ'), ('Ȋ', 'Ȋ'), ('Ȍ', 'Ȍ'), ('Ȏ', 'Ȏ'), + ('Ȑ', 'Ȑ'), ('Ȓ', 'Ȓ'), ('Ȕ', 'Ȕ'), ('Ȗ', 'Ȗ'), ('Ș', 'Ș'), + ('Ț', 'Ț'), ('Ȝ', 'Ȝ'), ('Ȟ', 'Ȟ'), ('È ', 'È '), ('È¢', 'È¢'), + ('Ȥ', 'Ȥ'), ('Ȧ', 'Ȧ'), ('Ȩ', 'Ȩ'), ('Ȫ', 'Ȫ'), ('Ȭ', 'Ȭ'), + ('È®', 'È®'), ('Ȱ', 'Ȱ'), ('Ȳ', 'Ȳ'), ('Ⱥ', 'È»'), ('Ƚ', 'Ⱦ'), + ('Ɂ', 'Ɂ'), ('Ƀ', 'Ɇ'), ('Ɉ', 'Ɉ'), ('Ɋ', 'Ɋ'), ('Ɍ', 'Ɍ'), + ('Ɏ', 'Ɏ'), ('\u{345}', '\u{345}'), ('Ͱ', 'Ͱ'), ('Ͳ', 'Ͳ'), + ('Ͷ', 'Ͷ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ώ'), ('Α', 'Ρ'), ('Σ', 'Ϋ'), ('ς', 'ς'), ('Ϗ', 'ϑ'), + ('ϕ', 'ϖ'), ('Ϙ', 'Ϙ'), ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), + ('Ï ', 'Ï '), ('Ï¢', 'Ï¢'), ('Ϥ', 'Ϥ'), ('Ϧ', 'Ϧ'), ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), ('Ϭ', 'Ϭ'), ('Ï®', 'Ï®'), ('ϰ', 'ϱ'), ('Ï´', 'ϵ'), + ('Ï·', 'Ï·'), ('Ϲ', 'Ϻ'), ('Ͻ', 'Я'), ('Ñ ', 'Ñ '), ('Ñ¢', 'Ñ¢'), + ('Ѥ', 'Ѥ'), ('Ѧ', 'Ѧ'), ('Ѩ', 'Ѩ'), ('Ѫ', 'Ѫ'), ('Ѭ', 'Ѭ'), + ('Ñ®', 'Ñ®'), ('Ѱ', 'Ѱ'), ('Ѳ', 'Ѳ'), ('Ñ´', 'Ñ´'), ('Ѷ', 'Ѷ'), + ('Ѹ', 'Ѹ'), ('Ѻ', 'Ѻ'), ('Ѽ', 'Ѽ'), ('Ѿ', 'Ѿ'), ('Ҁ', 'Ҁ'), + ('Ҋ', 'Ҋ'), ('Ҍ', 'Ҍ'), ('Ҏ', 'Ҏ'), ('Ґ', 'Ґ'), ('Ғ', 'Ғ'), + ('Ҕ', 'Ҕ'), ('Җ', 'Җ'), ('Ҙ', 'Ҙ'), ('Қ', 'Қ'), ('Ҝ', 'Ҝ'), + ('Ҟ', 'Ҟ'), ('Ò ', 'Ò '), ('Ò¢', 'Ò¢'), ('Ò¤', 'Ò¤'), ('Ò¦', 'Ò¦'), + ('Ò¨', 'Ò¨'), ('Òª', 'Òª'), ('Ò¬', 'Ò¬'), ('Ò®', 'Ò®'), ('Ò°', 'Ò°'), + ('Ò²', 'Ò²'), ('Ò´', 'Ò´'), ('Ò¶', 'Ò¶'), ('Ò¸', 'Ò¸'), ('Òº', 'Òº'), + ('Ò¼', 'Ò¼'), ('Ò¾', 'Ò¾'), ('Ӏ', 'Ӂ'), ('Ӄ', 'Ӄ'), ('Ӆ', 'Ӆ'), + ('Ӈ', 'Ӈ'), ('Ӊ', 'Ӊ'), ('Ӌ', 'Ӌ'), ('Ӎ', 'Ӎ'), ('Ӑ', 'Ӑ'), + ('Ӓ', 'Ӓ'), ('Ӕ', 'Ӕ'), ('Ӗ', 'Ӗ'), ('Ә', 'Ә'), ('Ӛ', 'Ӛ'), + ('Ӝ', 'Ӝ'), ('Ӟ', 'Ӟ'), ('Ó ', 'Ó '), ('Ó¢', 'Ó¢'), ('Ó¤', 'Ó¤'), + ('Ó¦', 'Ó¦'), ('Ó¨', 'Ó¨'), ('Óª', 'Óª'), ('Ó¬', 'Ó¬'), ('Ó®', 'Ó®'), + ('Ó°', 'Ó°'), ('Ó²', 'Ó²'), ('Ó´', 'Ó´'), ('Ó¶', 'Ó¶'), ('Ó¸', 'Ó¸'), + ('Óº', 'Óº'), ('Ó¼', 'Ó¼'), ('Ó¾', 'Ó¾'), ('Ԁ', 'Ԁ'), ('Ԃ', 'Ԃ'), + ('Ԅ', 'Ԅ'), ('Ԇ', 'Ԇ'), ('Ԉ', 'Ԉ'), ('Ԋ', 'Ԋ'), ('Ԍ', 'Ԍ'), + ('Ԏ', 'Ԏ'), ('Ԑ', 'Ԑ'), ('Ԓ', 'Ԓ'), ('Ԕ', 'Ԕ'), ('Ԗ', 'Ԗ'), + ('Ԙ', 'Ԙ'), ('Ԛ', 'Ԛ'), ('Ԝ', 'Ԝ'), ('Ԟ', 'Ԟ'), ('Ô ', 'Ô '), + ('Ô¢', 'Ô¢'), ('Ô¤', 'Ô¤'), ('Ô¦', 'Ô¦'), ('Ô¨', 'Ô¨'), ('Ôª', 'Ôª'), + ('Ô¬', 'Ô¬'), ('Ô®', 'Ô®'), ('Ô±', 'Ֆ'), ('և', 'և'), ('Ⴀ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), + ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('Ḁ', 'Ḁ'), ('Ḃ', 'Ḃ'), + ('Ḅ', 'Ḅ'), ('Ḇ', 'Ḇ'), ('Ḉ', 'Ḉ'), ('Ḋ', 'Ḋ'), + ('Ḍ', 'Ḍ'), ('Ḏ', 'Ḏ'), ('Ḑ', 'Ḑ'), ('Ḓ', 'Ḓ'), + ('Ḕ', 'Ḕ'), ('Ḗ', 'Ḗ'), ('Ḙ', 'Ḙ'), ('Ḛ', 'Ḛ'), + ('Ḝ', 'Ḝ'), ('Ḟ', 'Ḟ'), ('Ḡ', 'Ḡ'), ('Ḣ', 'Ḣ'), + ('Ḥ', 'Ḥ'), ('Ḧ', 'Ḧ'), ('Ḩ', 'Ḩ'), ('Ḫ', 'Ḫ'), + ('Ḭ', 'Ḭ'), ('Ḯ', 'Ḯ'), ('Ḱ', 'Ḱ'), ('Ḳ', 'Ḳ'), + ('Ḵ', 'Ḵ'), ('Ḷ', 'Ḷ'), ('Ḹ', 'Ḹ'), ('Ḻ', 'Ḻ'), + ('Ḽ', 'Ḽ'), ('Ḿ', 'Ḿ'), ('Ṁ', 'Ṁ'), ('Ṃ', 'Ṃ'), + ('Ṅ', 'Ṅ'), ('Ṇ', 'Ṇ'), ('Ṉ', 'Ṉ'), ('Ṋ', 'Ṋ'), + ('Ṍ', 'Ṍ'), ('Ṏ', 'Ṏ'), ('Ṑ', 'Ṑ'), ('Ṓ', 'Ṓ'), + ('Ṕ', 'Ṕ'), ('Ṗ', 'Ṗ'), ('Ṙ', 'Ṙ'), ('Ṛ', 'Ṛ'), + ('Ṝ', 'Ṝ'), ('Ṟ', 'Ṟ'), ('á¹ ', 'á¹ '), ('á¹¢', 'á¹¢'), + ('Ṥ', 'Ṥ'), ('Ṧ', 'Ṧ'), ('Ṩ', 'Ṩ'), ('Ṫ', 'Ṫ'), + ('Ṭ', 'Ṭ'), ('á¹®', 'á¹®'), ('á¹°', 'á¹°'), ('á¹²', 'á¹²'), + ('á¹´', 'á¹´'), ('á¹¶', 'á¹¶'), ('Ṹ', 'Ṹ'), ('Ṻ', 'Ṻ'), + ('á¹¼', 'á¹¼'), ('á¹¾', 'á¹¾'), ('Ẁ', 'Ẁ'), ('Ẃ', 'Ẃ'), + ('Ẅ', 'Ẅ'), ('Ẇ', 'Ẇ'), ('Ẉ', 'Ẉ'), ('Ẋ', 'Ẋ'), + ('Ẍ', 'Ẍ'), ('Ẏ', 'Ẏ'), ('Ẑ', 'Ẑ'), ('Ẓ', 'Ẓ'), + ('Ẕ', 'Ẕ'), ('ẚ', 'ẛ'), ('ẞ', 'ẞ'), ('Ạ', 'Ạ'), + ('Ả', 'Ả'), ('Ấ', 'Ấ'), ('Ầ', 'Ầ'), ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), ('Ậ', 'Ậ'), ('Ắ', 'Ắ'), ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), ('Ẵ', 'Ẵ'), ('Ặ', 'Ặ'), ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), ('Ẽ', 'Ẽ'), ('Ế', 'Ế'), ('Ề', 'Ề'), + ('Ể', 'Ể'), ('Ễ', 'Ễ'), ('Ệ', 'Ệ'), ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), ('Ọ', 'Ọ'), ('Ỏ', 'Ỏ'), ('Ố', 'Ố'), + ('Ồ', 'Ồ'), ('Ổ', 'Ổ'), ('Ỗ', 'Ỗ'), ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), ('Ờ', 'Ờ'), ('Ở', 'Ở'), ('á» ', 'á» '), + ('Ợ', 'Ợ'), ('Ụ', 'Ụ'), ('Ủ', 'Ủ'), ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), ('Ử', 'Ử'), ('á»®', 'á»®'), ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), ('á»´', 'á»´'), ('á»¶', 'á»¶'), ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), ('Ỽ', 'Ỽ'), ('Ỿ', 'Ỿ'), ('Ἀ', 'Ἇ'), + ('Ἐ', 'Ἕ'), ('Ἠ', 'Ἧ'), ('Ἰ', 'Ἷ'), ('Ὀ', 'Ὅ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), ('ᾀ', 'ᾯ'), ('á¾²', 'á¾´'), ('á¾·', 'á¾¼'), + ('ῂ', 'ῄ'), ('ῇ', 'ῌ'), ('Ῐ', 'Ί'), ('Ῠ', 'Ῥ'), + ('ῲ', 'á¿´'), ('á¿·', 'ῼ'), ('Ω', 'Ω'), ('K', 'Å'), + ('Ⅎ', 'Ⅎ'), ('Ⅰ', 'Ⅿ'), ('Ↄ', 'Ↄ'), ('Ⓐ', 'Ⓩ'), + ('Ⰰ', 'â°®'), ('â± ', 'â± '), ('â±¢', 'Ɽ'), ('â±§', 'â±§'), + ('Ⱪ', 'Ⱪ'), ('Ⱬ', 'Ⱬ'), ('â±­', 'â±°'), ('â±²', 'â±²'), + ('â±µ', 'â±µ'), ('â±¾', 'Ⲁ'), ('Ⲃ', 'Ⲃ'), ('Ⲅ', 'Ⲅ'), + ('Ⲇ', 'Ⲇ'), ('Ⲉ', 'Ⲉ'), ('Ⲋ', 'Ⲋ'), ('Ⲍ', 'Ⲍ'), + ('Ⲏ', 'Ⲏ'), ('Ⲑ', 'Ⲑ'), ('Ⲓ', 'Ⲓ'), ('Ⲕ', 'Ⲕ'), + ('Ⲗ', 'Ⲗ'), ('Ⲙ', 'Ⲙ'), ('Ⲛ', 'Ⲛ'), ('Ⲝ', 'Ⲝ'), + ('Ⲟ', 'Ⲟ'), ('â² ', 'â² '), ('â²¢', 'â²¢'), ('Ⲥ', 'Ⲥ'), + ('Ⲧ', 'Ⲧ'), ('Ⲩ', 'Ⲩ'), ('Ⲫ', 'Ⲫ'), ('Ⲭ', 'Ⲭ'), + ('â²®', 'â²®'), ('â²°', 'â²°'), ('â²²', 'â²²'), ('â²´', 'â²´'), + ('â²¶', 'â²¶'), ('Ⲹ', 'Ⲹ'), ('Ⲻ', 'Ⲻ'), ('â²¼', 'â²¼'), + ('â²¾', 'â²¾'), ('Ⳁ', 'Ⳁ'), ('Ⳃ', 'Ⳃ'), ('Ⳅ', 'Ⳅ'), + ('Ⳇ', 'Ⳇ'), ('Ⳉ', 'Ⳉ'), ('Ⳋ', 'Ⳋ'), ('Ⳍ', 'Ⳍ'), + ('Ⳏ', 'Ⳏ'), ('Ⳑ', 'Ⳑ'), ('Ⳓ', 'Ⳓ'), ('Ⳕ', 'Ⳕ'), + ('Ⳗ', 'Ⳗ'), ('Ⳙ', 'Ⳙ'), ('Ⳛ', 'Ⳛ'), ('Ⳝ', 'Ⳝ'), + ('Ⳟ', 'Ⳟ'), ('â³ ', 'â³ '), ('â³¢', 'â³¢'), ('Ⳬ', 'Ⳬ'), + ('â³­', 'â³­'), ('â³²', 'â³²'), ('Ꙁ', 'Ꙁ'), ('Ꙃ', 'Ꙃ'), + ('Ꙅ', 'Ꙅ'), ('Ꙇ', 'Ꙇ'), ('Ꙉ', 'Ꙉ'), ('Ꙋ', 'Ꙋ'), + ('Ꙍ', 'Ꙍ'), ('Ꙏ', 'Ꙏ'), ('Ꙑ', 'Ꙑ'), ('Ꙓ', 'Ꙓ'), + ('Ꙕ', 'Ꙕ'), ('Ꙗ', 'Ꙗ'), ('Ꙙ', 'Ꙙ'), ('Ꙛ', 'Ꙛ'), + ('Ꙝ', 'Ꙝ'), ('Ꙟ', 'Ꙟ'), ('Ꙡ', 'Ꙡ'), ('Ꙣ', 'Ꙣ'), + ('Ꙥ', 'Ꙥ'), ('Ꙧ', 'Ꙧ'), ('Ꙩ', 'Ꙩ'), ('Ꙫ', 'Ꙫ'), + ('Ꙭ', 'Ꙭ'), ('Ꚁ', 'Ꚁ'), ('Ꚃ', 'Ꚃ'), ('Ꚅ', 'Ꚅ'), + ('Ꚇ', 'Ꚇ'), ('Ꚉ', 'Ꚉ'), ('Ꚋ', 'Ꚋ'), ('Ꚍ', 'Ꚍ'), + ('Ꚏ', 'Ꚏ'), ('Ꚑ', 'Ꚑ'), ('Ꚓ', 'Ꚓ'), ('Ꚕ', 'Ꚕ'), + ('Ꚗ', 'Ꚗ'), ('Ꚙ', 'Ꚙ'), ('Ꚛ', 'Ꚛ'), ('Ꜣ', 'Ꜣ'), + ('Ꜥ', 'Ꜥ'), ('Ꜧ', 'Ꜧ'), ('Ꜩ', 'Ꜩ'), ('Ꜫ', 'Ꜫ'), + ('Ꜭ', 'Ꜭ'), ('Ꜯ', 'Ꜯ'), ('Ꜳ', 'Ꜳ'), ('Ꜵ', 'Ꜵ'), + ('Ꜷ', 'Ꜷ'), ('Ꜹ', 'Ꜹ'), ('Ꜻ', 'Ꜻ'), ('Ꜽ', 'Ꜽ'), + ('Ꜿ', 'Ꜿ'), ('Ꝁ', 'Ꝁ'), ('Ꝃ', 'Ꝃ'), ('Ꝅ', 'Ꝅ'), + ('Ꝇ', 'Ꝇ'), ('Ꝉ', 'Ꝉ'), ('Ꝋ', 'Ꝋ'), ('Ꝍ', 'Ꝍ'), + ('Ꝏ', 'Ꝏ'), ('Ꝑ', 'Ꝑ'), ('Ꝓ', 'Ꝓ'), ('Ꝕ', 'Ꝕ'), + ('Ꝗ', 'Ꝗ'), ('Ꝙ', 'Ꝙ'), ('Ꝛ', 'Ꝛ'), ('Ꝝ', 'Ꝝ'), + ('Ꝟ', 'Ꝟ'), ('Ꝡ', 'Ꝡ'), ('Ꝣ', 'Ꝣ'), ('Ꝥ', 'Ꝥ'), + ('Ꝧ', 'Ꝧ'), ('Ꝩ', 'Ꝩ'), ('Ꝫ', 'Ꝫ'), ('Ꝭ', 'Ꝭ'), + ('Ꝯ', 'Ꝯ'), ('Ꝺ', 'Ꝺ'), ('Ꝼ', 'Ꝼ'), ('Ᵹ', 'Ꝿ'), + ('Ꞁ', 'Ꞁ'), ('Ꞃ', 'Ꞃ'), ('Ꞅ', 'Ꞅ'), ('Ꞇ', 'Ꞇ'), + ('Ꞌ', 'Ꞌ'), ('Ɥ', 'Ɥ'), ('Ꞑ', 'Ꞑ'), ('Ꞓ', 'Ꞓ'), + ('Ꞗ', 'Ꞗ'), ('Ꞙ', 'Ꞙ'), ('Ꞛ', 'Ꞛ'), ('Ꞝ', 'Ꞝ'), + ('Ꞟ', 'Ꞟ'), ('Ꞡ', 'Ꞡ'), ('Ꞣ', 'Ꞣ'), ('Ꞥ', 'Ꞥ'), + ('Ꞧ', 'Ꞧ'), ('Ꞩ', 'Ꞩ'), ('Ɦ', 'Ɪ'), ('Ʞ', 'Ꞵ'), + ('Ꞷ', 'Ꞷ'), ('Ꞹ', 'Ꞹ'), ('ê­°', 'ꮿ'), ('ff', 'st'), + ('ﬓ', 'ﬗ'), ('A', 'Z'), ('𐐀', '𐐧'), ('𐒰', '𐓓'), + ('𐲀', '𐲲'), ('𑢠', '𑢿'), ('𖹀', '𖹟'), ('𞤀', '𞤡'), +]; + +pub const CHANGES_WHEN_CASEMAPPED: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('µ', 'µ'), ('À', 'Ö'), ('Ø', 'ö'), + ('ø', 'Ä·'), ('Ĺ', 'ƌ'), ('Ǝ', 'ƚ'), ('Ɯ', 'Æ©'), ('Ƭ', 'ƹ'), + ('Ƽ', 'ƽ'), ('Æ¿', 'Æ¿'), ('DŽ', 'È '), ('È¢', 'ȳ'), ('Ⱥ', 'ɔ'), + ('ɖ', 'ɗ'), ('ə', 'ə'), ('ɛ', 'ɜ'), ('É ', 'É¡'), ('É£', 'É£'), + ('É¥', 'ɦ'), ('ɨ', 'ɬ'), ('ɯ', 'ɯ'), ('ɱ', 'ɲ'), ('ɵ', 'ɵ'), + ('ɽ', 'ɽ'), ('ʀ', 'ʀ'), ('ʃ', 'ʃ'), ('ʇ', 'ʌ'), ('ʒ', 'ʒ'), + ('ʝ', 'ʞ'), ('\u{345}', '\u{345}'), ('Ͱ', 'ͳ'), ('Ͷ', 'Í·'), + ('Í»', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ρ'), ('Σ', 'ϑ'), ('ϕ', 'ϵ'), ('Ï·', 'Ï»'), ('Ͻ', 'ҁ'), + ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('Õ¡', 'և'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('Ꭰ', 'Ᏽ'), + ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), + ('áµ¹', 'áµ¹'), ('áµ½', 'áµ½'), ('Ḁ', 'ẛ'), ('ẞ', 'ẞ'), + ('Ạ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), + ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), + ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), + ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), + ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('Ω', 'Ω'), + ('K', 'Å'), ('Ⅎ', 'Ⅎ'), ('ⅎ', 'ⅎ'), ('Ⅰ', 'ⅿ'), + ('Ↄ', 'ↄ'), ('Ⓐ', 'ⓩ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'â±°'), ('â±²', 'â±³'), ('â±µ', 'â±¶'), ('â±¾', 'â³£'), + ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), + ('â´­', 'â´­'), ('Ꙁ', 'ꙭ'), ('Ꚁ', 'ꚛ'), ('Ꜣ', 'ꜯ'), + ('Ꜳ', 'ꝯ'), ('Ꝺ', 'ꞇ'), ('Ꞌ', 'Ɥ'), ('Ꞑ', 'ꞓ'), + ('Ꞗ', 'Ɪ'), ('Ʞ', 'ꞹ'), ('ꭓ', 'ꭓ'), ('ê­°', 'ꮿ'), + ('ff', 'st'), ('ﬓ', 'ﬗ'), ('A', 'Z'), ('a', 'z'), + ('𐐀', '𐑏'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐲀', '𐲲'), + ('𐳀', '𐳲'), ('𑢠', '𑣟'), ('𖹀', '𖹿'), ('𞤀', '𞥃'), +]; + +pub const CHANGES_WHEN_LOWERCASED: &'static [(char, char)] = &[ + ('A', 'Z'), ('À', 'Ö'), ('Ø', 'Þ'), ('Ā', 'Ā'), ('Ă', 'Ă'), + ('Ą', 'Ą'), ('Ć', 'Ć'), ('Ĉ', 'Ĉ'), ('Ċ', 'Ċ'), ('Č', 'Č'), + ('Ď', 'Ď'), ('Đ', 'Đ'), ('Ē', 'Ē'), ('Ĕ', 'Ĕ'), ('Ė', 'Ė'), + ('Ę', 'Ę'), ('Ě', 'Ě'), ('Ĝ', 'Ĝ'), ('Ğ', 'Ğ'), ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), ('Ĥ', 'Ĥ'), ('Ħ', 'Ħ'), ('Ĩ', 'Ĩ'), ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), ('Ä®', 'Ä®'), ('İ', 'İ'), ('IJ', 'IJ'), ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), ('Ĺ', 'Ĺ'), ('Ä»', 'Ä»'), ('Ľ', 'Ľ'), ('Ä¿', 'Ä¿'), + ('Ł', 'Ł'), ('Ń', 'Ń'), ('Ņ', 'Ņ'), ('Ň', 'Ň'), ('Ŋ', 'Ŋ'), + ('Ō', 'Ō'), ('Ŏ', 'Ŏ'), ('Ő', 'Ő'), ('Œ', 'Œ'), ('Ŕ', 'Ŕ'), + ('Ŗ', 'Ŗ'), ('Ř', 'Ř'), ('Ś', 'Ś'), ('Ŝ', 'Ŝ'), ('Ş', 'Ş'), + ('Å ', 'Å '), ('Å¢', 'Å¢'), ('Ť', 'Ť'), ('Ŧ', 'Ŧ'), ('Ũ', 'Ũ'), + ('Ū', 'Ū'), ('Ŭ', 'Ŭ'), ('Å®', 'Å®'), ('Ű', 'Ű'), ('Ų', 'Ų'), + ('Å´', 'Å´'), ('Ŷ', 'Ŷ'), ('Ÿ', 'Ź'), ('Å»', 'Å»'), ('Ž', 'Ž'), + ('Ɓ', 'Ƃ'), ('Ƅ', 'Ƅ'), ('Ɔ', 'Ƈ'), ('Ɖ', 'Ƌ'), ('Ǝ', 'Ƒ'), + ('Ɠ', 'Ɣ'), ('Ɩ', 'Ƙ'), ('Ɯ', 'Ɲ'), ('Ɵ', 'Æ '), ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), ('Ʀ', 'Ƨ'), ('Æ©', 'Æ©'), ('Ƭ', 'Ƭ'), ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), ('Ƶ', 'Ƶ'), ('Æ·', 'Ƹ'), ('Ƽ', 'Ƽ'), ('DŽ', 'Dž'), + ('LJ', 'Lj'), ('NJ', 'Nj'), ('Ǎ', 'Ǎ'), ('Ǐ', 'Ǐ'), ('Ǒ', 'Ǒ'), + ('Ǔ', 'Ǔ'), ('Ǖ', 'Ǖ'), ('Ǘ', 'Ǘ'), ('Ǚ', 'Ǚ'), ('Ǜ', 'Ǜ'), + ('Ǟ', 'Ǟ'), ('Ç ', 'Ç '), ('Ç¢', 'Ç¢'), ('Ǥ', 'Ǥ'), ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), ('Ǫ', 'Ǫ'), ('Ǭ', 'Ǭ'), ('Ç®', 'Ç®'), ('DZ', 'Dz'), + ('Ç´', 'Ç´'), ('Ƕ', 'Ǹ'), ('Ǻ', 'Ǻ'), ('Ǽ', 'Ǽ'), ('Ǿ', 'Ǿ'), + ('Ȁ', 'Ȁ'), ('Ȃ', 'Ȃ'), ('Ȅ', 'Ȅ'), ('Ȇ', 'Ȇ'), ('Ȉ', 'Ȉ'), + ('Ȋ', 'Ȋ'), ('Ȍ', 'Ȍ'), ('Ȏ', 'Ȏ'), ('Ȑ', 'Ȑ'), ('Ȓ', 'Ȓ'), + ('Ȕ', 'Ȕ'), ('Ȗ', 'Ȗ'), ('Ș', 'Ș'), ('Ț', 'Ț'), ('Ȝ', 'Ȝ'), + ('Ȟ', 'Ȟ'), ('È ', 'È '), ('È¢', 'È¢'), ('Ȥ', 'Ȥ'), ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), ('Ȫ', 'Ȫ'), ('Ȭ', 'Ȭ'), ('È®', 'È®'), ('Ȱ', 'Ȱ'), + ('Ȳ', 'Ȳ'), ('Ⱥ', 'È»'), ('Ƚ', 'Ⱦ'), ('Ɂ', 'Ɂ'), ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), ('Ɋ', 'Ɋ'), ('Ɍ', 'Ɍ'), ('Ɏ', 'Ɏ'), ('Ͱ', 'Ͱ'), + ('Ͳ', 'Ͳ'), ('Ͷ', 'Ͷ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ώ'), ('Α', 'Ρ'), ('Σ', 'Ϋ'), ('Ϗ', 'Ϗ'), + ('Ϙ', 'Ϙ'), ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), ('Ï ', 'Ï '), + ('Ï¢', 'Ï¢'), ('Ϥ', 'Ϥ'), ('Ϧ', 'Ϧ'), ('Ϩ', 'Ϩ'), ('Ϫ', 'Ϫ'), + ('Ϭ', 'Ϭ'), ('Ï®', 'Ï®'), ('Ï´', 'Ï´'), ('Ï·', 'Ï·'), ('Ϲ', 'Ϻ'), + ('Ͻ', 'Я'), ('Ñ ', 'Ñ '), ('Ñ¢', 'Ñ¢'), ('Ѥ', 'Ѥ'), ('Ѧ', 'Ѧ'), + ('Ѩ', 'Ѩ'), ('Ѫ', 'Ѫ'), ('Ѭ', 'Ѭ'), ('Ñ®', 'Ñ®'), ('Ѱ', 'Ѱ'), + ('Ѳ', 'Ѳ'), ('Ñ´', 'Ñ´'), ('Ѷ', 'Ѷ'), ('Ѹ', 'Ѹ'), ('Ѻ', 'Ѻ'), + ('Ѽ', 'Ѽ'), ('Ѿ', 'Ѿ'), ('Ҁ', 'Ҁ'), ('Ҋ', 'Ҋ'), ('Ҍ', 'Ҍ'), + ('Ҏ', 'Ҏ'), ('Ґ', 'Ґ'), ('Ғ', 'Ғ'), ('Ҕ', 'Ҕ'), ('Җ', 'Җ'), + ('Ҙ', 'Ҙ'), ('Қ', 'Қ'), ('Ҝ', 'Ҝ'), ('Ҟ', 'Ҟ'), ('Ò ', 'Ò '), + ('Ò¢', 'Ò¢'), ('Ò¤', 'Ò¤'), ('Ò¦', 'Ò¦'), ('Ò¨', 'Ò¨'), ('Òª', 'Òª'), + ('Ò¬', 'Ò¬'), ('Ò®', 'Ò®'), ('Ò°', 'Ò°'), ('Ò²', 'Ò²'), ('Ò´', 'Ò´'), + ('Ò¶', 'Ò¶'), ('Ò¸', 'Ò¸'), ('Òº', 'Òº'), ('Ò¼', 'Ò¼'), ('Ò¾', 'Ò¾'), + ('Ӏ', 'Ӂ'), ('Ӄ', 'Ӄ'), ('Ӆ', 'Ӆ'), ('Ӈ', 'Ӈ'), ('Ӊ', 'Ӊ'), + ('Ӌ', 'Ӌ'), ('Ӎ', 'Ӎ'), ('Ӑ', 'Ӑ'), ('Ӓ', 'Ӓ'), ('Ӕ', 'Ӕ'), + ('Ӗ', 'Ӗ'), ('Ә', 'Ә'), ('Ӛ', 'Ӛ'), ('Ӝ', 'Ӝ'), ('Ӟ', 'Ӟ'), + ('Ó ', 'Ó '), ('Ó¢', 'Ó¢'), ('Ó¤', 'Ó¤'), ('Ó¦', 'Ó¦'), ('Ó¨', 'Ó¨'), + ('Óª', 'Óª'), ('Ó¬', 'Ó¬'), ('Ó®', 'Ó®'), ('Ó°', 'Ó°'), ('Ó²', 'Ó²'), + ('Ó´', 'Ó´'), ('Ó¶', 'Ó¶'), ('Ó¸', 'Ó¸'), ('Óº', 'Óº'), ('Ó¼', 'Ó¼'), + ('Ó¾', 'Ó¾'), ('Ԁ', 'Ԁ'), ('Ԃ', 'Ԃ'), ('Ԅ', 'Ԅ'), ('Ԇ', 'Ԇ'), + ('Ԉ', 'Ԉ'), ('Ԋ', 'Ԋ'), ('Ԍ', 'Ԍ'), ('Ԏ', 'Ԏ'), ('Ԑ', 'Ԑ'), + ('Ԓ', 'Ԓ'), ('Ԕ', 'Ԕ'), ('Ԗ', 'Ԗ'), ('Ԙ', 'Ԙ'), ('Ԛ', 'Ԛ'), + ('Ԝ', 'Ԝ'), ('Ԟ', 'Ԟ'), ('Ô ', 'Ô '), ('Ô¢', 'Ô¢'), ('Ô¤', 'Ô¤'), + ('Ô¦', 'Ô¦'), ('Ô¨', 'Ô¨'), ('Ôª', 'Ôª'), ('Ô¬', 'Ô¬'), ('Ô®', 'Ô®'), + ('Ô±', 'Ֆ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('Ꭰ', 'Ᏽ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), ('Ḅ', 'Ḅ'), ('Ḇ', 'Ḇ'), ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), ('Ḍ', 'Ḍ'), ('Ḏ', 'Ḏ'), ('Ḑ', 'Ḑ'), + ('Ḓ', 'Ḓ'), ('Ḕ', 'Ḕ'), ('Ḗ', 'Ḗ'), ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), ('Ḝ', 'Ḝ'), ('Ḟ', 'Ḟ'), ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), ('Ḥ', 'Ḥ'), ('Ḧ', 'Ḧ'), ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), ('Ḭ', 'Ḭ'), ('Ḯ', 'Ḯ'), ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), ('Ḵ', 'Ḵ'), ('Ḷ', 'Ḷ'), ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), ('Ḽ', 'Ḽ'), ('Ḿ', 'Ḿ'), ('Ṁ', 'Ṁ'), + ('Ṃ', 'Ṃ'), ('Ṅ', 'Ṅ'), ('Ṇ', 'Ṇ'), ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), ('Ṍ', 'Ṍ'), ('Ṏ', 'Ṏ'), ('Ṑ', 'Ṑ'), + ('Ṓ', 'Ṓ'), ('Ṕ', 'Ṕ'), ('Ṗ', 'Ṗ'), ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), ('Ṝ', 'Ṝ'), ('Ṟ', 'Ṟ'), ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), ('Ṥ', 'Ṥ'), ('Ṧ', 'Ṧ'), ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), ('Ṭ', 'Ṭ'), ('á¹®', 'á¹®'), ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), ('á¹´', 'á¹´'), ('á¹¶', 'á¹¶'), ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), ('á¹¼', 'á¹¼'), ('á¹¾', 'á¹¾'), ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), ('Ẅ', 'Ẅ'), ('Ẇ', 'Ẇ'), ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), ('Ẍ', 'Ẍ'), ('Ẏ', 'Ẏ'), ('Ẑ', 'Ẑ'), + ('Ẓ', 'Ẓ'), ('Ẕ', 'Ẕ'), ('ẞ', 'ẞ'), ('Ạ', 'Ạ'), + ('Ả', 'Ả'), ('Ấ', 'Ấ'), ('Ầ', 'Ầ'), ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), ('Ậ', 'Ậ'), ('Ắ', 'Ắ'), ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), ('Ẵ', 'Ẵ'), ('Ặ', 'Ặ'), ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), ('Ẽ', 'Ẽ'), ('Ế', 'Ế'), ('Ề', 'Ề'), + ('Ể', 'Ể'), ('Ễ', 'Ễ'), ('Ệ', 'Ệ'), ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), ('Ọ', 'Ọ'), ('Ỏ', 'Ỏ'), ('Ố', 'Ố'), + ('Ồ', 'Ồ'), ('Ổ', 'Ổ'), ('Ỗ', 'Ỗ'), ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), ('Ờ', 'Ờ'), ('Ở', 'Ở'), ('á» ', 'á» '), + ('Ợ', 'Ợ'), ('Ụ', 'Ụ'), ('Ủ', 'Ủ'), ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), ('Ử', 'Ử'), ('á»®', 'á»®'), ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), ('á»´', 'á»´'), ('á»¶', 'á»¶'), ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), ('Ỽ', 'Ỽ'), ('Ỿ', 'Ỿ'), ('Ἀ', 'Ἇ'), + ('Ἐ', 'Ἕ'), ('Ἠ', 'Ἧ'), ('Ἰ', 'Ἷ'), ('Ὀ', 'Ὅ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), ('ᾈ', 'ᾏ'), ('ᾘ', 'ᾟ'), ('ᾨ', 'ᾯ'), + ('Ᾰ', 'á¾¼'), ('Ὲ', 'ῌ'), ('Ῐ', 'Ί'), ('Ῠ', 'Ῥ'), + ('Ὸ', 'ῼ'), ('Ω', 'Ω'), ('K', 'Å'), ('Ⅎ', 'Ⅎ'), + ('Ⅰ', 'Ⅿ'), ('Ↄ', 'Ↄ'), ('Ⓐ', 'Ⓩ'), ('Ⰰ', 'â°®'), + ('â± ', 'â± '), ('â±¢', 'Ɽ'), ('â±§', 'â±§'), ('Ⱪ', 'Ⱪ'), + ('Ⱬ', 'Ⱬ'), ('â±­', 'â±°'), ('â±²', 'â±²'), ('â±µ', 'â±µ'), + ('â±¾', 'Ⲁ'), ('Ⲃ', 'Ⲃ'), ('Ⲅ', 'Ⲅ'), ('Ⲇ', 'Ⲇ'), + ('Ⲉ', 'Ⲉ'), ('Ⲋ', 'Ⲋ'), ('Ⲍ', 'Ⲍ'), ('Ⲏ', 'Ⲏ'), + ('Ⲑ', 'Ⲑ'), ('Ⲓ', 'Ⲓ'), ('Ⲕ', 'Ⲕ'), ('Ⲗ', 'Ⲗ'), + ('Ⲙ', 'Ⲙ'), ('Ⲛ', 'Ⲛ'), ('Ⲝ', 'Ⲝ'), ('Ⲟ', 'Ⲟ'), + ('â² ', 'â² '), ('â²¢', 'â²¢'), ('Ⲥ', 'Ⲥ'), ('Ⲧ', 'Ⲧ'), + ('Ⲩ', 'Ⲩ'), ('Ⲫ', 'Ⲫ'), ('Ⲭ', 'Ⲭ'), ('â²®', 'â²®'), + ('â²°', 'â²°'), ('â²²', 'â²²'), ('â²´', 'â²´'), ('â²¶', 'â²¶'), + ('Ⲹ', 'Ⲹ'), ('Ⲻ', 'Ⲻ'), ('â²¼', 'â²¼'), ('â²¾', 'â²¾'), + ('Ⳁ', 'Ⳁ'), ('Ⳃ', 'Ⳃ'), ('Ⳅ', 'Ⳅ'), ('Ⳇ', 'Ⳇ'), + ('Ⳉ', 'Ⳉ'), ('Ⳋ', 'Ⳋ'), ('Ⳍ', 'Ⳍ'), ('Ⳏ', 'Ⳏ'), + ('Ⳑ', 'Ⳑ'), ('Ⳓ', 'Ⳓ'), ('Ⳕ', 'Ⳕ'), ('Ⳗ', 'Ⳗ'), + ('Ⳙ', 'Ⳙ'), ('Ⳛ', 'Ⳛ'), ('Ⳝ', 'Ⳝ'), ('Ⳟ', 'Ⳟ'), + ('â³ ', 'â³ '), ('â³¢', 'â³¢'), ('Ⳬ', 'Ⳬ'), ('â³­', 'â³­'), + ('â³²', 'â³²'), ('Ꙁ', 'Ꙁ'), ('Ꙃ', 'Ꙃ'), ('Ꙅ', 'Ꙅ'), + ('Ꙇ', 'Ꙇ'), ('Ꙉ', 'Ꙉ'), ('Ꙋ', 'Ꙋ'), ('Ꙍ', 'Ꙍ'), + ('Ꙏ', 'Ꙏ'), ('Ꙑ', 'Ꙑ'), ('Ꙓ', 'Ꙓ'), ('Ꙕ', 'Ꙕ'), + ('Ꙗ', 'Ꙗ'), ('Ꙙ', 'Ꙙ'), ('Ꙛ', 'Ꙛ'), ('Ꙝ', 'Ꙝ'), + ('Ꙟ', 'Ꙟ'), ('Ꙡ', 'Ꙡ'), ('Ꙣ', 'Ꙣ'), ('Ꙥ', 'Ꙥ'), + ('Ꙧ', 'Ꙧ'), ('Ꙩ', 'Ꙩ'), ('Ꙫ', 'Ꙫ'), ('Ꙭ', 'Ꙭ'), + ('Ꚁ', 'Ꚁ'), ('Ꚃ', 'Ꚃ'), ('Ꚅ', 'Ꚅ'), ('Ꚇ', 'Ꚇ'), + ('Ꚉ', 'Ꚉ'), ('Ꚋ', 'Ꚋ'), ('Ꚍ', 'Ꚍ'), ('Ꚏ', 'Ꚏ'), + ('Ꚑ', 'Ꚑ'), ('Ꚓ', 'Ꚓ'), ('Ꚕ', 'Ꚕ'), ('Ꚗ', 'Ꚗ'), + ('Ꚙ', 'Ꚙ'), ('Ꚛ', 'Ꚛ'), ('Ꜣ', 'Ꜣ'), ('Ꜥ', 'Ꜥ'), + ('Ꜧ', 'Ꜧ'), ('Ꜩ', 'Ꜩ'), ('Ꜫ', 'Ꜫ'), ('Ꜭ', 'Ꜭ'), + ('Ꜯ', 'Ꜯ'), ('Ꜳ', 'Ꜳ'), ('Ꜵ', 'Ꜵ'), ('Ꜷ', 'Ꜷ'), + ('Ꜹ', 'Ꜹ'), ('Ꜻ', 'Ꜻ'), ('Ꜽ', 'Ꜽ'), ('Ꜿ', 'Ꜿ'), + ('Ꝁ', 'Ꝁ'), ('Ꝃ', 'Ꝃ'), ('Ꝅ', 'Ꝅ'), ('Ꝇ', 'Ꝇ'), + ('Ꝉ', 'Ꝉ'), ('Ꝋ', 'Ꝋ'), ('Ꝍ', 'Ꝍ'), ('Ꝏ', 'Ꝏ'), + ('Ꝑ', 'Ꝑ'), ('Ꝓ', 'Ꝓ'), ('Ꝕ', 'Ꝕ'), ('Ꝗ', 'Ꝗ'), + ('Ꝙ', 'Ꝙ'), ('Ꝛ', 'Ꝛ'), ('Ꝝ', 'Ꝝ'), ('Ꝟ', 'Ꝟ'), + ('Ꝡ', 'Ꝡ'), ('Ꝣ', 'Ꝣ'), ('Ꝥ', 'Ꝥ'), ('Ꝧ', 'Ꝧ'), + ('Ꝩ', 'Ꝩ'), ('Ꝫ', 'Ꝫ'), ('Ꝭ', 'Ꝭ'), ('Ꝯ', 'Ꝯ'), + ('Ꝺ', 'Ꝺ'), ('Ꝼ', 'Ꝼ'), ('Ᵹ', 'Ꝿ'), ('Ꞁ', 'Ꞁ'), + ('Ꞃ', 'Ꞃ'), ('Ꞅ', 'Ꞅ'), ('Ꞇ', 'Ꞇ'), ('Ꞌ', 'Ꞌ'), + ('Ɥ', 'Ɥ'), ('Ꞑ', 'Ꞑ'), ('Ꞓ', 'Ꞓ'), ('Ꞗ', 'Ꞗ'), + ('Ꞙ', 'Ꞙ'), ('Ꞛ', 'Ꞛ'), ('Ꞝ', 'Ꞝ'), ('Ꞟ', 'Ꞟ'), + ('Ꞡ', 'Ꞡ'), ('Ꞣ', 'Ꞣ'), ('Ꞥ', 'Ꞥ'), ('Ꞧ', 'Ꞧ'), + ('Ꞩ', 'Ꞩ'), ('Ɦ', 'Ɪ'), ('Ʞ', 'Ꞵ'), ('Ꞷ', 'Ꞷ'), + ('Ꞹ', 'Ꞹ'), ('A', 'Z'), ('𐐀', '𐐧'), ('𐒰', '𐓓'), + ('𐲀', '𐲲'), ('𑢠', '𑢿'), ('𖹀', '𖹟'), ('𞤀', '𞤡'), +]; + +pub const CHANGES_WHEN_TITLECASED: &'static [(char, char)] = &[ + ('a', 'z'), ('µ', 'µ'), ('ß', 'ö'), ('ø', 'ÿ'), ('ā', 'ā'), + ('ă', 'ă'), ('ą', 'ą'), ('ć', 'ć'), ('ĉ', 'ĉ'), ('ċ', 'ċ'), + ('č', 'č'), ('ď', 'ď'), ('đ', 'đ'), ('ē', 'ē'), ('ĕ', 'ĕ'), + ('ė', 'ė'), ('ę', 'ę'), ('ě', 'ě'), ('ĝ', 'ĝ'), ('ğ', 'ğ'), + ('Ä¡', 'Ä¡'), ('Ä£', 'Ä£'), ('Ä¥', 'Ä¥'), ('ħ', 'ħ'), ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), ('Ä­', 'Ä­'), ('į', 'į'), ('ı', 'ı'), ('ij', 'ij'), + ('ĵ', 'ĵ'), ('Ä·', 'Ä·'), ('ĺ', 'ĺ'), ('ļ', 'ļ'), ('ľ', 'ľ'), + ('ŀ', 'ŀ'), ('ł', 'ł'), ('ń', 'ń'), ('ņ', 'ņ'), ('ň', 'ʼn'), + ('ŋ', 'ŋ'), ('ō', 'ō'), ('ŏ', 'ŏ'), ('ő', 'ő'), ('œ', 'œ'), + ('ŕ', 'ŕ'), ('ŗ', 'ŗ'), ('ř', 'ř'), ('ś', 'ś'), ('ŝ', 'ŝ'), + ('ş', 'ş'), ('Å¡', 'Å¡'), ('Å£', 'Å£'), ('Å¥', 'Å¥'), ('ŧ', 'ŧ'), + ('Å©', 'Å©'), ('Å«', 'Å«'), ('Å­', 'Å­'), ('ů', 'ů'), ('ű', 'ű'), + ('ų', 'ų'), ('ŵ', 'ŵ'), ('Å·', 'Å·'), ('ź', 'ź'), ('ż', 'ż'), + ('ž', 'ƀ'), ('ƃ', 'ƃ'), ('ƅ', 'ƅ'), ('ƈ', 'ƈ'), ('ƌ', 'ƌ'), + ('ƒ', 'ƒ'), ('ƕ', 'ƕ'), ('ƙ', 'ƚ'), ('ƞ', 'ƞ'), ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), ('Æ¥', 'Æ¥'), ('ƨ', 'ƨ'), ('Æ­', 'Æ­'), ('ư', 'ư'), + ('Æ´', 'Æ´'), ('ƶ', 'ƶ'), ('ƹ', 'ƹ'), ('ƽ', 'ƽ'), ('Æ¿', 'Æ¿'), + ('DŽ', 'DŽ'), ('dž', 'LJ'), ('lj', 'NJ'), ('nj', 'nj'), ('ǎ', 'ǎ'), + ('ǐ', 'ǐ'), ('ǒ', 'ǒ'), ('ǔ', 'ǔ'), ('ǖ', 'ǖ'), ('ǘ', 'ǘ'), + ('ǚ', 'ǚ'), ('ǜ', 'ǝ'), ('ǟ', 'ǟ'), ('Ç¡', 'Ç¡'), ('Ç£', 'Ç£'), + ('Ç¥', 'Ç¥'), ('ǧ', 'ǧ'), ('Ç©', 'Ç©'), ('Ç«', 'Ç«'), ('Ç­', 'Ç­'), + ('ǯ', 'DZ'), ('dz', 'dz'), ('ǵ', 'ǵ'), ('ǹ', 'ǹ'), ('Ç»', 'Ç»'), + ('ǽ', 'ǽ'), ('Ç¿', 'Ç¿'), ('ȁ', 'ȁ'), ('ȃ', 'ȃ'), ('ȅ', 'ȅ'), + ('ȇ', 'ȇ'), ('ȉ', 'ȉ'), ('ȋ', 'ȋ'), ('ȍ', 'ȍ'), ('ȏ', 'ȏ'), + ('ȑ', 'ȑ'), ('ȓ', 'ȓ'), ('ȕ', 'ȕ'), ('ȗ', 'ȗ'), ('ș', 'ș'), + ('ț', 'ț'), ('ȝ', 'ȝ'), ('ȟ', 'ȟ'), ('È£', 'È£'), ('È¥', 'È¥'), + ('ȧ', 'ȧ'), ('È©', 'È©'), ('È«', 'È«'), ('È­', 'È­'), ('ȯ', 'ȯ'), + ('ȱ', 'ȱ'), ('ȳ', 'ȳ'), ('ȼ', 'ȼ'), ('È¿', 'ɀ'), ('ɂ', 'ɂ'), + ('ɇ', 'ɇ'), ('ɉ', 'ɉ'), ('ɋ', 'ɋ'), ('ɍ', 'ɍ'), ('ɏ', 'ɔ'), + ('ɖ', 'ɗ'), ('ə', 'ə'), ('ɛ', 'ɜ'), ('É ', 'É¡'), ('É£', 'É£'), + ('É¥', 'ɦ'), ('ɨ', 'ɬ'), ('ɯ', 'ɯ'), ('ɱ', 'ɲ'), ('ɵ', 'ɵ'), + ('ɽ', 'ɽ'), ('ʀ', 'ʀ'), ('ʃ', 'ʃ'), ('ʇ', 'ʌ'), ('ʒ', 'ʒ'), + ('ʝ', 'ʞ'), ('\u{345}', '\u{345}'), ('ͱ', 'ͱ'), ('ͳ', 'ͳ'), + ('Í·', 'Í·'), ('Í»', 'ͽ'), ('ΐ', 'ΐ'), ('ά', 'ώ'), ('ϐ', 'ϑ'), + ('ϕ', 'ϗ'), ('ϙ', 'ϙ'), ('ϛ', 'ϛ'), ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), + ('Ï¡', 'Ï¡'), ('Ï£', 'Ï£'), ('Ï¥', 'Ï¥'), ('ϧ', 'ϧ'), ('Ï©', 'Ï©'), + ('Ï«', 'Ï«'), ('Ï­', 'Ï­'), ('ϯ', 'ϳ'), ('ϵ', 'ϵ'), ('ϸ', 'ϸ'), + ('Ï»', 'Ï»'), ('а', 'џ'), ('Ñ¡', 'Ñ¡'), ('Ñ£', 'Ñ£'), ('Ñ¥', 'Ñ¥'), + ('ѧ', 'ѧ'), ('Ñ©', 'Ñ©'), ('Ñ«', 'Ñ«'), ('Ñ­', 'Ñ­'), ('ѯ', 'ѯ'), + ('ѱ', 'ѱ'), ('ѳ', 'ѳ'), ('ѵ', 'ѵ'), ('Ñ·', 'Ñ·'), ('ѹ', 'ѹ'), + ('Ñ»', 'Ñ»'), ('ѽ', 'ѽ'), ('Ñ¿', 'Ñ¿'), ('ҁ', 'ҁ'), ('ҋ', 'ҋ'), + ('ҍ', 'ҍ'), ('ҏ', 'ҏ'), ('ґ', 'ґ'), ('ғ', 'ғ'), ('ҕ', 'ҕ'), + ('җ', 'җ'), ('ҙ', 'ҙ'), ('қ', 'қ'), ('ҝ', 'ҝ'), ('ҟ', 'ҟ'), + ('Ò¡', 'Ò¡'), ('Ò£', 'Ò£'), ('Ò¥', 'Ò¥'), ('Ò§', 'Ò§'), ('Ò©', 'Ò©'), + ('Ò«', 'Ò«'), ('Ò­', 'Ò­'), ('Ò¯', 'Ò¯'), ('Ò±', 'Ò±'), ('Ò³', 'Ò³'), + ('Òµ', 'Òµ'), ('Ò·', 'Ò·'), ('Ò¹', 'Ò¹'), ('Ò»', 'Ò»'), ('Ò½', 'Ò½'), + ('Ò¿', 'Ò¿'), ('ӂ', 'ӂ'), ('ӄ', 'ӄ'), ('ӆ', 'ӆ'), ('ӈ', 'ӈ'), + ('ӊ', 'ӊ'), ('ӌ', 'ӌ'), ('ӎ', 'ӏ'), ('ӑ', 'ӑ'), ('ӓ', 'ӓ'), + ('ӕ', 'ӕ'), ('ӗ', 'ӗ'), ('ә', 'ә'), ('ӛ', 'ӛ'), ('ӝ', 'ӝ'), + ('ӟ', 'ӟ'), ('Ó¡', 'Ó¡'), ('Ó£', 'Ó£'), ('Ó¥', 'Ó¥'), ('Ó§', 'Ó§'), + ('Ó©', 'Ó©'), ('Ó«', 'Ó«'), ('Ó­', 'Ó­'), ('Ó¯', 'Ó¯'), ('Ó±', 'Ó±'), + ('Ó³', 'Ó³'), ('Óµ', 'Óµ'), ('Ó·', 'Ó·'), ('Ó¹', 'Ó¹'), ('Ó»', 'Ó»'), + ('Ó½', 'Ó½'), ('Ó¿', 'Ó¿'), ('ԁ', 'ԁ'), ('ԃ', 'ԃ'), ('ԅ', 'ԅ'), + ('ԇ', 'ԇ'), ('ԉ', 'ԉ'), ('ԋ', 'ԋ'), ('ԍ', 'ԍ'), ('ԏ', 'ԏ'), + ('ԑ', 'ԑ'), ('ԓ', 'ԓ'), ('ԕ', 'ԕ'), ('ԗ', 'ԗ'), ('ԙ', 'ԙ'), + ('ԛ', 'ԛ'), ('ԝ', 'ԝ'), ('ԟ', 'ԟ'), ('Ô¡', 'Ô¡'), ('Ô£', 'Ô£'), + ('Ô¥', 'Ô¥'), ('Ô§', 'Ô§'), ('Ô©', 'Ô©'), ('Ô«', 'Ô«'), ('Ô­', 'Ô­'), + ('Ô¯', 'Ô¯'), ('Õ¡', 'և'), ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), ('áµ¹', 'áµ¹'), + ('áµ½', 'áµ½'), ('ḁ', 'ḁ'), ('ḃ', 'ḃ'), ('ḅ', 'ḅ'), + ('ḇ', 'ḇ'), ('ḉ', 'ḉ'), ('ḋ', 'ḋ'), ('ḍ', 'ḍ'), + ('ḏ', 'ḏ'), ('ḑ', 'ḑ'), ('ḓ', 'ḓ'), ('ḕ', 'ḕ'), + ('ḗ', 'ḗ'), ('ḙ', 'ḙ'), ('ḛ', 'ḛ'), ('ḝ', 'ḝ'), + ('ḟ', 'ḟ'), ('ḡ', 'ḡ'), ('ḣ', 'ḣ'), ('ḥ', 'ḥ'), + ('ḧ', 'ḧ'), ('ḩ', 'ḩ'), ('ḫ', 'ḫ'), ('ḭ', 'ḭ'), + ('ḯ', 'ḯ'), ('ḱ', 'ḱ'), ('ḳ', 'ḳ'), ('ḵ', 'ḵ'), + ('ḷ', 'ḷ'), ('ḹ', 'ḹ'), ('ḻ', 'ḻ'), ('ḽ', 'ḽ'), + ('ḿ', 'ḿ'), ('ṁ', 'ṁ'), ('ṃ', 'ṃ'), ('ṅ', 'ṅ'), + ('ṇ', 'ṇ'), ('ṉ', 'ṉ'), ('ṋ', 'ṋ'), ('ṍ', 'ṍ'), + ('ṏ', 'ṏ'), ('ṑ', 'ṑ'), ('ṓ', 'ṓ'), ('ṕ', 'ṕ'), + ('ṗ', 'ṗ'), ('ṙ', 'ṙ'), ('ṛ', 'ṛ'), ('ṝ', 'ṝ'), + ('ṟ', 'ṟ'), ('ṡ', 'ṡ'), ('á¹£', 'á¹£'), ('á¹¥', 'á¹¥'), + ('á¹§', 'á¹§'), ('ṩ', 'ṩ'), ('ṫ', 'ṫ'), ('á¹­', 'á¹­'), + ('ṯ', 'ṯ'), ('á¹±', 'á¹±'), ('á¹³', 'á¹³'), ('á¹µ', 'á¹µ'), + ('á¹·', 'á¹·'), ('á¹¹', 'á¹¹'), ('á¹»', 'á¹»'), ('á¹½', 'á¹½'), + ('ṿ', 'ṿ'), ('ẁ', 'ẁ'), ('ẃ', 'ẃ'), ('ẅ', 'ẅ'), + ('ẇ', 'ẇ'), ('ẉ', 'ẉ'), ('ẋ', 'ẋ'), ('ẍ', 'ẍ'), + ('ẏ', 'ẏ'), ('ẑ', 'ẑ'), ('ẓ', 'ẓ'), ('ẕ', 'ẛ'), + ('ạ', 'ạ'), ('ả', 'ả'), ('ấ', 'ấ'), ('ầ', 'ầ'), + ('ẩ', 'ẩ'), ('ẫ', 'ẫ'), ('ậ', 'ậ'), ('ắ', 'ắ'), + ('ằ', 'ằ'), ('ẳ', 'ẳ'), ('ẵ', 'ẵ'), ('ặ', 'ặ'), + ('ẹ', 'ẹ'), ('ẻ', 'ẻ'), ('ẽ', 'ẽ'), ('ế', 'ế'), + ('ề', 'ề'), ('ể', 'ể'), ('ễ', 'ễ'), ('ệ', 'ệ'), + ('ỉ', 'ỉ'), ('ị', 'ị'), ('ọ', 'ọ'), ('ỏ', 'ỏ'), + ('ố', 'ố'), ('ồ', 'ồ'), ('ổ', 'ổ'), ('ỗ', 'ỗ'), + ('ộ', 'ộ'), ('ớ', 'ớ'), ('ờ', 'ờ'), ('ở', 'ở'), + ('ỡ', 'ỡ'), ('ợ', 'ợ'), ('ụ', 'ụ'), ('á»§', 'á»§'), + ('ứ', 'ứ'), ('ừ', 'ừ'), ('á»­', 'á»­'), ('ữ', 'ữ'), + ('á»±', 'á»±'), ('ỳ', 'ỳ'), ('ỵ', 'ỵ'), ('á»·', 'á»·'), + ('ỹ', 'ỹ'), ('á»»', 'á»»'), ('ỽ', 'ỽ'), ('ỿ', 'ἇ'), + ('ἐ', 'ἕ'), ('á¼ ', 'á¼§'), ('á¼°', 'á¼·'), ('ὀ', 'ὅ'), + ('ὐ', 'ὗ'), ('á½ ', 'á½§'), ('á½°', 'á½½'), ('ᾀ', 'ᾇ'), + ('ᾐ', 'ᾗ'), ('á¾ ', 'á¾§'), ('á¾°', 'á¾´'), ('á¾¶', 'á¾·'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῇ'), ('ῐ', 'ΐ'), + ('ῖ', 'ῗ'), ('á¿ ', 'á¿§'), ('ῲ', 'á¿´'), ('á¿¶', 'á¿·'), + ('ⅎ', 'ⅎ'), ('ⅰ', 'ⅿ'), ('ↄ', 'ↄ'), ('ⓐ', 'ⓩ'), + ('â°°', 'ⱞ'), ('ⱡ', 'ⱡ'), ('â±¥', 'ⱦ'), ('ⱨ', 'ⱨ'), + ('ⱪ', 'ⱪ'), ('ⱬ', 'ⱬ'), ('â±³', 'â±³'), ('â±¶', 'â±¶'), + ('ⲁ', 'ⲁ'), ('ⲃ', 'ⲃ'), ('ⲅ', 'ⲅ'), ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), ('ⲋ', 'ⲋ'), ('ⲍ', 'ⲍ'), ('ⲏ', 'ⲏ'), + ('ⲑ', 'ⲑ'), ('ⲓ', 'ⲓ'), ('ⲕ', 'ⲕ'), ('ⲗ', 'ⲗ'), + ('ⲙ', 'ⲙ'), ('ⲛ', 'ⲛ'), ('ⲝ', 'ⲝ'), ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), ('â²£', 'â²£'), ('â²¥', 'â²¥'), ('â²§', 'â²§'), + ('ⲩ', 'ⲩ'), ('ⲫ', 'ⲫ'), ('â²­', 'â²­'), ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), ('â²³', 'â²³'), ('â²µ', 'â²µ'), ('â²·', 'â²·'), + ('â²¹', 'â²¹'), ('â²»', 'â²»'), ('â²½', 'â²½'), ('ⲿ', 'ⲿ'), + ('ⳁ', 'ⳁ'), ('ⳃ', 'ⳃ'), ('ⳅ', 'ⳅ'), ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), ('ⳋ', 'ⳋ'), ('ⳍ', 'ⳍ'), ('ⳏ', 'ⳏ'), + ('ⳑ', 'ⳑ'), ('ⳓ', 'ⳓ'), ('ⳕ', 'ⳕ'), ('ⳗ', 'ⳗ'), + ('ⳙ', 'ⳙ'), ('ⳛ', 'ⳛ'), ('ⳝ', 'ⳝ'), ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), ('â³£', 'â³£'), ('ⳬ', 'ⳬ'), ('â³®', 'â³®'), + ('â³³', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), + ('ꙁ', 'ꙁ'), ('ꙃ', 'ꙃ'), ('ꙅ', 'ꙅ'), ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), ('ꙋ', 'ꙋ'), ('ꙍ', 'ꙍ'), ('ꙏ', 'ꙏ'), + ('ꙑ', 'ꙑ'), ('ꙓ', 'ꙓ'), ('ꙕ', 'ꙕ'), ('ꙗ', 'ꙗ'), + ('ꙙ', 'ꙙ'), ('ꙛ', 'ꙛ'), ('ꙝ', 'ꙝ'), ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), ('ꙣ', 'ꙣ'), ('ꙥ', 'ꙥ'), ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), ('ꙫ', 'ꙫ'), ('ꙭ', 'ꙭ'), ('ꚁ', 'ꚁ'), + ('ꚃ', 'ꚃ'), ('ꚅ', 'ꚅ'), ('ꚇ', 'ꚇ'), ('ꚉ', 'ꚉ'), + ('ꚋ', 'ꚋ'), ('ꚍ', 'ꚍ'), ('ꚏ', 'ꚏ'), ('ꚑ', 'ꚑ'), + ('ꚓ', 'ꚓ'), ('ꚕ', 'ꚕ'), ('ꚗ', 'ꚗ'), ('ꚙ', 'ꚙ'), + ('ꚛ', 'ꚛ'), ('ꜣ', 'ꜣ'), ('ꜥ', 'ꜥ'), ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), ('ꜫ', 'ꜫ'), ('ꜭ', 'ꜭ'), ('ꜯ', 'ꜯ'), + ('ꜳ', 'ꜳ'), ('ꜵ', 'ꜵ'), ('ꜷ', 'ꜷ'), ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), ('ꜽ', 'ꜽ'), ('ꜿ', 'ꜿ'), ('ꝁ', 'ꝁ'), + ('ꝃ', 'ꝃ'), ('ꝅ', 'ꝅ'), ('ꝇ', 'ꝇ'), ('ꝉ', 'ꝉ'), + ('ꝋ', 'ꝋ'), ('ꝍ', 'ꝍ'), ('ꝏ', 'ꝏ'), ('ꝑ', 'ꝑ'), + ('ꝓ', 'ꝓ'), ('ꝕ', 'ꝕ'), ('ꝗ', 'ꝗ'), ('ꝙ', 'ꝙ'), + ('ꝛ', 'ꝛ'), ('ꝝ', 'ꝝ'), ('ꝟ', 'ꝟ'), ('ꝡ', 'ꝡ'), + ('ꝣ', 'ꝣ'), ('ꝥ', 'ꝥ'), ('ꝧ', 'ꝧ'), ('ꝩ', 'ꝩ'), + ('ꝫ', 'ꝫ'), ('ꝭ', 'ꝭ'), ('ꝯ', 'ꝯ'), ('ꝺ', 'ꝺ'), + ('ꝼ', 'ꝼ'), ('ꝿ', 'ꝿ'), ('ꞁ', 'ꞁ'), ('ꞃ', 'ꞃ'), + ('ꞅ', 'ꞅ'), ('ꞇ', 'ꞇ'), ('ꞌ', 'ꞌ'), ('ꞑ', 'ꞑ'), + ('ꞓ', 'ꞓ'), ('ꞗ', 'ꞗ'), ('ꞙ', 'ꞙ'), ('ꞛ', 'ꞛ'), + ('ꞝ', 'ꞝ'), ('ꞟ', 'ꞟ'), ('ꞡ', 'ꞡ'), ('ꞣ', 'ꞣ'), + ('ꞥ', 'ꞥ'), ('ꞧ', 'ꞧ'), ('ꞩ', 'ꞩ'), ('ꞵ', 'ꞵ'), + ('ꞷ', 'ꞷ'), ('ꞹ', 'ꞹ'), ('ꭓ', 'ꭓ'), ('ê­°', 'ꮿ'), + ('ff', 'st'), ('ﬓ', 'ﬗ'), ('a', 'z'), ('𐐨', '𐑏'), + ('𐓘', '𐓻'), ('𐳀', '𐳲'), ('𑣀', '𑣟'), ('𖹠', '𖹿'), + ('𞤢', '𞥃'), +]; + +pub const CHANGES_WHEN_UPPERCASED: &'static [(char, char)] = &[ + ('a', 'z'), ('µ', 'µ'), ('ß', 'ö'), ('ø', 'ÿ'), ('ā', 'ā'), + ('ă', 'ă'), ('ą', 'ą'), ('ć', 'ć'), ('ĉ', 'ĉ'), ('ċ', 'ċ'), + ('č', 'č'), ('ď', 'ď'), ('đ', 'đ'), ('ē', 'ē'), ('ĕ', 'ĕ'), + ('ė', 'ė'), ('ę', 'ę'), ('ě', 'ě'), ('ĝ', 'ĝ'), ('ğ', 'ğ'), + ('Ä¡', 'Ä¡'), ('Ä£', 'Ä£'), ('Ä¥', 'Ä¥'), ('ħ', 'ħ'), ('Ä©', 'Ä©'), + ('Ä«', 'Ä«'), ('Ä­', 'Ä­'), ('į', 'į'), ('ı', 'ı'), ('ij', 'ij'), + ('ĵ', 'ĵ'), ('Ä·', 'Ä·'), ('ĺ', 'ĺ'), ('ļ', 'ļ'), ('ľ', 'ľ'), + ('ŀ', 'ŀ'), ('ł', 'ł'), ('ń', 'ń'), ('ņ', 'ņ'), ('ň', 'ʼn'), + ('ŋ', 'ŋ'), ('ō', 'ō'), ('ŏ', 'ŏ'), ('ő', 'ő'), ('œ', 'œ'), + ('ŕ', 'ŕ'), ('ŗ', 'ŗ'), ('ř', 'ř'), ('ś', 'ś'), ('ŝ', 'ŝ'), + ('ş', 'ş'), ('Å¡', 'Å¡'), ('Å£', 'Å£'), ('Å¥', 'Å¥'), ('ŧ', 'ŧ'), + ('Å©', 'Å©'), ('Å«', 'Å«'), ('Å­', 'Å­'), ('ů', 'ů'), ('ű', 'ű'), + ('ų', 'ų'), ('ŵ', 'ŵ'), ('Å·', 'Å·'), ('ź', 'ź'), ('ż', 'ż'), + ('ž', 'ƀ'), ('ƃ', 'ƃ'), ('ƅ', 'ƅ'), ('ƈ', 'ƈ'), ('ƌ', 'ƌ'), + ('ƒ', 'ƒ'), ('ƕ', 'ƕ'), ('ƙ', 'ƚ'), ('ƞ', 'ƞ'), ('Æ¡', 'Æ¡'), + ('Æ£', 'Æ£'), ('Æ¥', 'Æ¥'), ('ƨ', 'ƨ'), ('Æ­', 'Æ­'), ('ư', 'ư'), + ('Æ´', 'Æ´'), ('ƶ', 'ƶ'), ('ƹ', 'ƹ'), ('ƽ', 'ƽ'), ('Æ¿', 'Æ¿'), + ('Dž', 'dž'), ('Lj', 'lj'), ('Nj', 'nj'), ('ǎ', 'ǎ'), ('ǐ', 'ǐ'), + ('ǒ', 'ǒ'), ('ǔ', 'ǔ'), ('ǖ', 'ǖ'), ('ǘ', 'ǘ'), ('ǚ', 'ǚ'), + ('ǜ', 'ǝ'), ('ǟ', 'ǟ'), ('Ç¡', 'Ç¡'), ('Ç£', 'Ç£'), ('Ç¥', 'Ç¥'), + ('ǧ', 'ǧ'), ('Ç©', 'Ç©'), ('Ç«', 'Ç«'), ('Ç­', 'Ç­'), ('ǯ', 'ǰ'), + ('Dz', 'dz'), ('ǵ', 'ǵ'), ('ǹ', 'ǹ'), ('Ç»', 'Ç»'), ('ǽ', 'ǽ'), + ('Ç¿', 'Ç¿'), ('ȁ', 'ȁ'), ('ȃ', 'ȃ'), ('ȅ', 'ȅ'), ('ȇ', 'ȇ'), + ('ȉ', 'ȉ'), ('ȋ', 'ȋ'), ('ȍ', 'ȍ'), ('ȏ', 'ȏ'), ('ȑ', 'ȑ'), + ('ȓ', 'ȓ'), ('ȕ', 'ȕ'), ('ȗ', 'ȗ'), ('ș', 'ș'), ('ț', 'ț'), + ('ȝ', 'ȝ'), ('ȟ', 'ȟ'), ('È£', 'È£'), ('È¥', 'È¥'), ('ȧ', 'ȧ'), + ('È©', 'È©'), ('È«', 'È«'), ('È­', 'È­'), ('ȯ', 'ȯ'), ('ȱ', 'ȱ'), + ('ȳ', 'ȳ'), ('ȼ', 'ȼ'), ('È¿', 'ɀ'), ('ɂ', 'ɂ'), ('ɇ', 'ɇ'), + ('ɉ', 'ɉ'), ('ɋ', 'ɋ'), ('ɍ', 'ɍ'), ('ɏ', 'ɔ'), ('ɖ', 'ɗ'), + ('ə', 'ə'), ('ɛ', 'ɜ'), ('É ', 'É¡'), ('É£', 'É£'), ('É¥', 'ɦ'), + ('ɨ', 'ɬ'), ('ɯ', 'ɯ'), ('ɱ', 'ɲ'), ('ɵ', 'ɵ'), ('ɽ', 'ɽ'), + ('ʀ', 'ʀ'), ('ʃ', 'ʃ'), ('ʇ', 'ʌ'), ('ʒ', 'ʒ'), ('ʝ', 'ʞ'), + ('\u{345}', '\u{345}'), ('ͱ', 'ͱ'), ('ͳ', 'ͳ'), ('Í·', 'Í·'), + ('Í»', 'ͽ'), ('ΐ', 'ΐ'), ('ά', 'ώ'), ('ϐ', 'ϑ'), ('ϕ', 'ϗ'), + ('ϙ', 'ϙ'), ('ϛ', 'ϛ'), ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), ('Ï¥', 'Ï¥'), ('ϧ', 'ϧ'), ('Ï©', 'Ï©'), ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), ('ϯ', 'ϳ'), ('ϵ', 'ϵ'), ('ϸ', 'ϸ'), ('Ï»', 'Ï»'), + ('а', 'џ'), ('Ñ¡', 'Ñ¡'), ('Ñ£', 'Ñ£'), ('Ñ¥', 'Ñ¥'), ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), ('Ñ«', 'Ñ«'), ('Ñ­', 'Ñ­'), ('ѯ', 'ѯ'), ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), ('ѵ', 'ѵ'), ('Ñ·', 'Ñ·'), ('ѹ', 'ѹ'), ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), ('Ñ¿', 'Ñ¿'), ('ҁ', 'ҁ'), ('ҋ', 'ҋ'), ('ҍ', 'ҍ'), + ('ҏ', 'ҏ'), ('ґ', 'ґ'), ('ғ', 'ғ'), ('ҕ', 'ҕ'), ('җ', 'җ'), + ('ҙ', 'ҙ'), ('қ', 'қ'), ('ҝ', 'ҝ'), ('ҟ', 'ҟ'), ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), ('Ò¥', 'Ò¥'), ('Ò§', 'Ò§'), ('Ò©', 'Ò©'), ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), ('Ò¯', 'Ò¯'), ('Ò±', 'Ò±'), ('Ò³', 'Ò³'), ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), ('Ò¹', 'Ò¹'), ('Ò»', 'Ò»'), ('Ò½', 'Ò½'), ('Ò¿', 'Ò¿'), + ('ӂ', 'ӂ'), ('ӄ', 'ӄ'), ('ӆ', 'ӆ'), ('ӈ', 'ӈ'), ('ӊ', 'ӊ'), + ('ӌ', 'ӌ'), ('ӎ', 'ӏ'), ('ӑ', 'ӑ'), ('ӓ', 'ӓ'), ('ӕ', 'ӕ'), + ('ӗ', 'ӗ'), ('ә', 'ә'), ('ӛ', 'ӛ'), ('ӝ', 'ӝ'), ('ӟ', 'ӟ'), + ('Ó¡', 'Ó¡'), ('Ó£', 'Ó£'), ('Ó¥', 'Ó¥'), ('Ó§', 'Ó§'), ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), ('Ó­', 'Ó­'), ('Ó¯', 'Ó¯'), ('Ó±', 'Ó±'), ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), ('Ó·', 'Ó·'), ('Ó¹', 'Ó¹'), ('Ó»', 'Ó»'), ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), ('ԁ', 'ԁ'), ('ԃ', 'ԃ'), ('ԅ', 'ԅ'), ('ԇ', 'ԇ'), + ('ԉ', 'ԉ'), ('ԋ', 'ԋ'), ('ԍ', 'ԍ'), ('ԏ', 'ԏ'), ('ԑ', 'ԑ'), + ('ԓ', 'ԓ'), ('ԕ', 'ԕ'), ('ԗ', 'ԗ'), ('ԙ', 'ԙ'), ('ԛ', 'ԛ'), + ('ԝ', 'ԝ'), ('ԟ', 'ԟ'), ('Ô¡', 'Ô¡'), ('Ô£', 'Ô£'), ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), ('Ô©', 'Ô©'), ('Ô«', 'Ô«'), ('Ô­', 'Ô­'), ('Ô¯', 'Ô¯'), + ('Õ¡', 'և'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('ᏸ', 'ᏽ'), + ('ᲀ', 'ᲈ'), ('áµ¹', 'áµ¹'), ('áµ½', 'áµ½'), ('ḁ', 'ḁ'), + ('ḃ', 'ḃ'), ('ḅ', 'ḅ'), ('ḇ', 'ḇ'), ('ḉ', 'ḉ'), + ('ḋ', 'ḋ'), ('ḍ', 'ḍ'), ('ḏ', 'ḏ'), ('ḑ', 'ḑ'), + ('ḓ', 'ḓ'), ('ḕ', 'ḕ'), ('ḗ', 'ḗ'), ('ḙ', 'ḙ'), + ('ḛ', 'ḛ'), ('ḝ', 'ḝ'), ('ḟ', 'ḟ'), ('ḡ', 'ḡ'), + ('ḣ', 'ḣ'), ('ḥ', 'ḥ'), ('ḧ', 'ḧ'), ('ḩ', 'ḩ'), + ('ḫ', 'ḫ'), ('ḭ', 'ḭ'), ('ḯ', 'ḯ'), ('ḱ', 'ḱ'), + ('ḳ', 'ḳ'), ('ḵ', 'ḵ'), ('ḷ', 'ḷ'), ('ḹ', 'ḹ'), + ('ḻ', 'ḻ'), ('ḽ', 'ḽ'), ('ḿ', 'ḿ'), ('ṁ', 'ṁ'), + ('ṃ', 'ṃ'), ('ṅ', 'ṅ'), ('ṇ', 'ṇ'), ('ṉ', 'ṉ'), + ('ṋ', 'ṋ'), ('ṍ', 'ṍ'), ('ṏ', 'ṏ'), ('ṑ', 'ṑ'), + ('ṓ', 'ṓ'), ('ṕ', 'ṕ'), ('ṗ', 'ṗ'), ('ṙ', 'ṙ'), + ('ṛ', 'ṛ'), ('ṝ', 'ṝ'), ('ṟ', 'ṟ'), ('ṡ', 'ṡ'), + ('á¹£', 'á¹£'), ('á¹¥', 'á¹¥'), ('á¹§', 'á¹§'), ('ṩ', 'ṩ'), + ('ṫ', 'ṫ'), ('á¹­', 'á¹­'), ('ṯ', 'ṯ'), ('á¹±', 'á¹±'), + ('á¹³', 'á¹³'), ('á¹µ', 'á¹µ'), ('á¹·', 'á¹·'), ('á¹¹', 'á¹¹'), + ('á¹»', 'á¹»'), ('á¹½', 'á¹½'), ('ṿ', 'ṿ'), ('ẁ', 'ẁ'), + ('ẃ', 'ẃ'), ('ẅ', 'ẅ'), ('ẇ', 'ẇ'), ('ẉ', 'ẉ'), + ('ẋ', 'ẋ'), ('ẍ', 'ẍ'), ('ẏ', 'ẏ'), ('ẑ', 'ẑ'), + ('ẓ', 'ẓ'), ('ẕ', 'ẛ'), ('ạ', 'ạ'), ('ả', 'ả'), + ('ấ', 'ấ'), ('ầ', 'ầ'), ('ẩ', 'ẩ'), ('ẫ', 'ẫ'), + ('ậ', 'ậ'), ('ắ', 'ắ'), ('ằ', 'ằ'), ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), ('ặ', 'ặ'), ('ẹ', 'ẹ'), ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), ('ế', 'ế'), ('ề', 'ề'), ('ể', 'ể'), + ('ễ', 'ễ'), ('ệ', 'ệ'), ('ỉ', 'ỉ'), ('ị', 'ị'), + ('ọ', 'ọ'), ('ỏ', 'ỏ'), ('ố', 'ố'), ('ồ', 'ồ'), + ('ổ', 'ổ'), ('ỗ', 'ỗ'), ('ộ', 'ộ'), ('ớ', 'ớ'), + ('ờ', 'ờ'), ('ở', 'ở'), ('ỡ', 'ỡ'), ('ợ', 'ợ'), + ('ụ', 'ụ'), ('á»§', 'á»§'), ('ứ', 'ứ'), ('ừ', 'ừ'), + ('á»­', 'á»­'), ('ữ', 'ữ'), ('á»±', 'á»±'), ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), ('á»·', 'á»·'), ('ỹ', 'ỹ'), ('á»»', 'á»»'), + ('ỽ', 'ỽ'), ('ỿ', 'ἇ'), ('ἐ', 'ἕ'), ('á¼ ', 'á¼§'), + ('á¼°', 'á¼·'), ('ὀ', 'ὅ'), ('ὐ', 'ὗ'), ('á½ ', 'á½§'), + ('á½°', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾·'), ('á¾¼', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῇ'), ('ῌ', 'ῌ'), + ('ῐ', 'ΐ'), ('ῖ', 'ῗ'), ('á¿ ', 'á¿§'), ('ῲ', 'á¿´'), + ('á¿¶', 'á¿·'), ('ῼ', 'ῼ'), ('ⅎ', 'ⅎ'), ('ⅰ', 'ⅿ'), + ('ↄ', 'ↄ'), ('ⓐ', 'ⓩ'), ('â°°', 'ⱞ'), ('ⱡ', 'ⱡ'), + ('â±¥', 'ⱦ'), ('ⱨ', 'ⱨ'), ('ⱪ', 'ⱪ'), ('ⱬ', 'ⱬ'), + ('â±³', 'â±³'), ('â±¶', 'â±¶'), ('ⲁ', 'ⲁ'), ('ⲃ', 'ⲃ'), + ('ⲅ', 'ⲅ'), ('ⲇ', 'ⲇ'), ('ⲉ', 'ⲉ'), ('ⲋ', 'ⲋ'), + ('ⲍ', 'ⲍ'), ('ⲏ', 'ⲏ'), ('ⲑ', 'ⲑ'), ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), ('ⲗ', 'ⲗ'), ('ⲙ', 'ⲙ'), ('ⲛ', 'ⲛ'), + ('ⲝ', 'ⲝ'), ('ⲟ', 'ⲟ'), ('ⲡ', 'ⲡ'), ('â²£', 'â²£'), + ('â²¥', 'â²¥'), ('â²§', 'â²§'), ('ⲩ', 'ⲩ'), ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), ('ⲯ', 'ⲯ'), ('â²±', 'â²±'), ('â²³', 'â²³'), + ('â²µ', 'â²µ'), ('â²·', 'â²·'), ('â²¹', 'â²¹'), ('â²»', 'â²»'), + ('â²½', 'â²½'), ('ⲿ', 'ⲿ'), ('ⳁ', 'ⳁ'), ('ⳃ', 'ⳃ'), + ('ⳅ', 'ⳅ'), ('ⳇ', 'ⳇ'), ('ⳉ', 'ⳉ'), ('ⳋ', 'ⳋ'), + ('ⳍ', 'ⳍ'), ('ⳏ', 'ⳏ'), ('ⳑ', 'ⳑ'), ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), ('ⳗ', 'ⳗ'), ('ⳙ', 'ⳙ'), ('ⳛ', 'ⳛ'), + ('ⳝ', 'ⳝ'), ('ⳟ', 'ⳟ'), ('ⳡ', 'ⳡ'), ('â³£', 'â³£'), + ('ⳬ', 'ⳬ'), ('â³®', 'â³®'), ('â³³', 'â³³'), ('ⴀ', 'â´¥'), + ('â´§', 'â´§'), ('â´­', 'â´­'), ('ꙁ', 'ꙁ'), ('ꙃ', 'ꙃ'), + ('ꙅ', 'ꙅ'), ('ꙇ', 'ꙇ'), ('ꙉ', 'ꙉ'), ('ꙋ', 'ꙋ'), + ('ꙍ', 'ꙍ'), ('ꙏ', 'ꙏ'), ('ꙑ', 'ꙑ'), ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), ('ꙗ', 'ꙗ'), ('ꙙ', 'ꙙ'), ('ꙛ', 'ꙛ'), + ('ꙝ', 'ꙝ'), ('ꙟ', 'ꙟ'), ('ꙡ', 'ꙡ'), ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), ('ꙧ', 'ꙧ'), ('ꙩ', 'ꙩ'), ('ꙫ', 'ꙫ'), + ('ꙭ', 'ꙭ'), ('ꚁ', 'ꚁ'), ('ꚃ', 'ꚃ'), ('ꚅ', 'ꚅ'), + ('ꚇ', 'ꚇ'), ('ꚉ', 'ꚉ'), ('ꚋ', 'ꚋ'), ('ꚍ', 'ꚍ'), + ('ꚏ', 'ꚏ'), ('ꚑ', 'ꚑ'), ('ꚓ', 'ꚓ'), ('ꚕ', 'ꚕ'), + ('ꚗ', 'ꚗ'), ('ꚙ', 'ꚙ'), ('ꚛ', 'ꚛ'), ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), ('ꜧ', 'ꜧ'), ('ꜩ', 'ꜩ'), ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), ('ꜯ', 'ꜯ'), ('ꜳ', 'ꜳ'), ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), ('ꜹ', 'ꜹ'), ('ꜻ', 'ꜻ'), ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), ('ꝁ', 'ꝁ'), ('ꝃ', 'ꝃ'), ('ꝅ', 'ꝅ'), + ('ꝇ', 'ꝇ'), ('ꝉ', 'ꝉ'), ('ꝋ', 'ꝋ'), ('ꝍ', 'ꝍ'), + ('ꝏ', 'ꝏ'), ('ꝑ', 'ꝑ'), ('ꝓ', 'ꝓ'), ('ꝕ', 'ꝕ'), + ('ꝗ', 'ꝗ'), ('ꝙ', 'ꝙ'), ('ꝛ', 'ꝛ'), ('ꝝ', 'ꝝ'), + ('ꝟ', 'ꝟ'), ('ꝡ', 'ꝡ'), ('ꝣ', 'ꝣ'), ('ꝥ', 'ꝥ'), + ('ꝧ', 'ꝧ'), ('ꝩ', 'ꝩ'), ('ꝫ', 'ꝫ'), ('ꝭ', 'ꝭ'), + ('ꝯ', 'ꝯ'), ('ꝺ', 'ꝺ'), ('ꝼ', 'ꝼ'), ('ꝿ', 'ꝿ'), + ('ꞁ', 'ꞁ'), ('ꞃ', 'ꞃ'), ('ꞅ', 'ꞅ'), ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), ('ꞑ', 'ꞑ'), ('ꞓ', 'ꞓ'), ('ꞗ', 'ꞗ'), + ('ꞙ', 'ꞙ'), ('ꞛ', 'ꞛ'), ('ꞝ', 'ꞝ'), ('ꞟ', 'ꞟ'), + ('ꞡ', 'ꞡ'), ('ꞣ', 'ꞣ'), ('ꞥ', 'ꞥ'), ('ꞧ', 'ꞧ'), + ('ꞩ', 'ꞩ'), ('ꞵ', 'ꞵ'), ('ꞷ', 'ꞷ'), ('ꞹ', 'ꞹ'), + ('ꭓ', 'ꭓ'), ('ê­°', 'ꮿ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), + ('a', 'z'), ('𐐨', '𐑏'), ('𐓘', '𐓻'), ('𐳀', '𐳲'), + ('𑣀', '𑣟'), ('𖹠', '𖹿'), ('𞤢', '𞥃'), +]; + +pub const DASH: &'static [(char, char)] = &[ + ('-', '-'), ('֊', '֊'), ('Ö¾', 'Ö¾'), ('᐀', '᐀'), ('᠆', '᠆'), + ('‐', '―'), ('⁓', '⁓'), ('⁻', '⁻'), ('₋', '₋'), + ('−', '−'), ('⸗', '⸗'), ('⸚', '⸚'), ('⸺', '⸻'), + ('⹀', '⹀'), ('〜', '〜'), ('〰', '〰'), ('゠', '゠'), + ('︱', '︲'), ('﹘', '﹘'), ('ï¹£', 'ï¹£'), ('-', '-'), +]; + +pub const DEFAULT_IGNORABLE_CODE_POINT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), ('\u{34f}', '\u{34f}'), ('\u{61c}', '\u{61c}'), + ('ᅟ', 'ᅠ'), ('\u{17b4}', '\u{17b5}'), ('\u{180b}', '\u{180e}'), + ('\u{200b}', '\u{200f}'), ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{206f}'), ('ㅤ', 'ㅤ'), ('\u{fe00}', '\u{fe0f}'), + ('\u{feff}', '\u{feff}'), ('ï¾ ', 'ï¾ '), ('\u{fff0}', '\u{fff8}'), + ('\u{1bca0}', '\u{1bca3}'), ('\u{1d173}', '\u{1d17a}'), + ('\u{e0000}', '\u{e0fff}'), +]; + +pub const DEPRECATED: &'static [(char, char)] = &[ + ('ʼn', 'ʼn'), ('Ù³', 'Ù³'), ('\u{f77}', '\u{f77}'), ('\u{f79}', '\u{f79}'), + ('ឣ', 'ឤ'), ('\u{206a}', '\u{206f}'), ('〈', '〉'), + ('\u{e0001}', '\u{e0001}'), +]; + +pub const DIACRITIC: &'static [(char, char)] = &[ + ('^', '^'), ('`', '`'), ('¨', '¨'), ('¯', '¯'), ('´', '´'), + ('·', '¸'), ('ʰ', '\u{34e}'), ('\u{350}', '\u{357}'), + ('\u{35d}', '\u{362}'), ('Í´', '͵'), ('ͺ', 'ͺ'), ('΄', '΅'), + ('\u{483}', '\u{487}'), ('ՙ', 'ՙ'), ('\u{591}', '\u{5a1}'), + ('\u{5a3}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c4}'), ('\u{64b}', '\u{652}'), ('\u{657}', '\u{658}'), + ('\u{6df}', '\u{6e0}'), ('Û¥', 'Û¦'), ('\u{6ea}', '\u{6ec}'), + ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', 'ßµ'), + ('\u{818}', '\u{819}'), ('\u{8e3}', '\u{8fe}'), ('\u{93c}', '\u{93c}'), + ('\u{94d}', '\u{94d}'), ('\u{951}', '\u{954}'), ('ॱ', 'ॱ'), + ('\u{9bc}', '\u{9bc}'), ('\u{9cd}', '\u{9cd}'), ('\u{a3c}', '\u{a3c}'), + ('\u{a4d}', '\u{a4d}'), ('\u{abc}', '\u{abc}'), ('\u{acd}', '\u{acd}'), + ('\u{afd}', '\u{aff}'), ('\u{b3c}', '\u{b3c}'), ('\u{b4d}', '\u{b4d}'), + ('\u{bcd}', '\u{bcd}'), ('\u{c4d}', '\u{c4d}'), ('\u{cbc}', '\u{cbc}'), + ('\u{ccd}', '\u{ccd}'), ('\u{d3b}', '\u{d3c}'), ('\u{d4d}', '\u{d4d}'), + ('\u{dca}', '\u{dca}'), ('\u{e47}', '\u{e4c}'), ('\u{e4e}', '\u{e4e}'), + ('\u{ec8}', '\u{ecc}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', '\u{f35}'), + ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), ('༾', '༿'), + ('\u{f82}', '\u{f84}'), ('\u{f86}', '\u{f87}'), ('\u{fc6}', '\u{fc6}'), + ('\u{1037}', '\u{1037}'), ('\u{1039}', '\u{103a}'), ('ႇ', '\u{108d}'), + ('ႏ', 'ႏ'), ('ႚ', 'ႛ'), ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), ('\u{1939}', '\u{193b}'), + ('\u{1a75}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1abd}'), ('\u{1b34}', '\u{1b34}'), ('᭄', '᭄'), + ('\u{1b6b}', '\u{1b73}'), ('᮪', '\u{1bab}'), ('\u{1c36}', '\u{1c37}'), + ('ᱸ', 'á±½'), ('\u{1cd0}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), ('á³·', '\u{1cf9}'), ('á´¬', 'ᵪ'), + ('\u{1dc4}', '\u{1dcf}'), ('\u{1df5}', '\u{1df9}'), + ('\u{1dfd}', '\u{1dff}'), ('á¾½', 'á¾½'), ('᾿', '῁'), ('῍', '῏'), + ('῝', '῟'), ('á¿­', '`'), ('´', '῾'), ('\u{2cef}', '\u{2cf1}'), + ('ⸯ', 'ⸯ'), ('\u{302a}', '\u{302f}'), ('\u{3099}', '゜'), + ('ー', 'ー'), ('\u{a66f}', '\u{a66f}'), ('\u{a67c}', '\u{a67d}'), + ('ꙿ', 'ꙿ'), ('ꚜ', 'ꚝ'), ('\u{a6f0}', '\u{a6f1}'), ('ꜗ', '꜡'), + ('ꞈ', 'ꞈ'), ('ꟸ', 'ꟹ'), ('\u{a8c4}', '\u{a8c4}'), + ('\u{a8e0}', '\u{a8f1}'), ('\u{a92b}', '꤮'), ('꥓', '꥓'), + ('\u{a9b3}', '\u{a9b3}'), ('꧀', '꧀'), ('\u{a9e5}', '\u{a9e5}'), + ('ê©»', 'ꩽ'), ('\u{aabf}', 'ꫂ'), ('\u{aaf6}', '\u{aaf6}'), + ('꭛', 'ꭟ'), ('꯬', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe20}', '\u{fe2f}'), ('ï¼¾', 'ï¼¾'), ('`', '`'), ('ï½°', 'ï½°'), + ('\u{ff9e}', '\u{ff9f}'), ('ï¿£', 'ï¿£'), ('\u{102e0}', '\u{102e0}'), + ('\u{10ae5}', '\u{10ae6}'), ('𐴢', '\u{10d27}'), + ('\u{10f46}', '\u{10f50}'), ('\u{110b9}', '\u{110ba}'), + ('\u{11133}', '\u{11134}'), ('\u{11173}', '\u{11173}'), ('𑇀', '𑇀'), + ('\u{111ca}', '\u{111cc}'), ('𑈵', '\u{11236}'), + ('\u{112e9}', '\u{112ea}'), ('\u{1133c}', '\u{1133c}'), ('𑍍', '𑍍'), + ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}'), + ('\u{11442}', '\u{11442}'), ('\u{11446}', '\u{11446}'), + ('\u{114c2}', '\u{114c3}'), ('\u{115bf}', '\u{115c0}'), + ('\u{1163f}', '\u{1163f}'), ('𑚶', '\u{116b7}'), + ('\u{1172b}', '\u{1172b}'), ('\u{11839}', '\u{1183a}'), + ('\u{11a34}', '\u{11a34}'), ('\u{11a47}', '\u{11a47}'), + ('\u{11a99}', '\u{11a99}'), ('\u{11c3f}', '\u{11c3f}'), + ('\u{11d42}', '\u{11d42}'), ('\u{11d44}', '\u{11d45}'), + ('\u{11d97}', '\u{11d97}'), ('\u{16af0}', '\u{16af4}'), + ('\u{16f8f}', '𖾟'), ('\u{1d167}', '\u{1d169}'), ('𝅭', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1e8d0}', '\u{1e8d6}'), + ('\u{1e944}', '\u{1e946}'), ('\u{1e948}', '\u{1e94a}'), +]; + +pub const EMOJI: &'static [(char, char)] = &[ + ('#', '#'), ('*', '*'), ('0', '9'), ('©', '©'), ('®', '®'), + ('‼', '‼'), ('⁉', '⁉'), ('™', '™'), ('ℹ', 'ℹ'), + ('↔', '↙'), ('↩', '↪'), ('⌚', '⌛'), ('⌨', '⌨'), + ('⏏', '⏏'), ('⏩', '⏳'), ('⏸', '⏺'), ('Ⓜ', 'Ⓜ'), + ('▪', '▫'), ('▶', '▶'), ('◀', '◀'), ('◻', '◾'), + ('☀', '☄'), ('☎', '☎'), ('☑', '☑'), ('☔', '☕'), + ('☘', '☘'), ('☝', '☝'), ('☠', '☠'), ('☢', '☣'), + ('☦', '☦'), ('☪', '☪'), ('☮', '☯'), ('☸', '☺'), + ('♀', '♀'), ('♂', '♂'), ('♈', '♓'), ('♟', '♠'), + ('♣', '♣'), ('♥', '♦'), ('♨', '♨'), ('♻', '♻'), + ('♾', '♿'), ('⚒', '⚗'), ('⚙', '⚙'), ('⚛', '⚜'), + ('⚠', '⚡'), ('⚪', '⚫'), ('⚰', '⚱'), ('⚽', '⚾'), + ('⛄', '⛅'), ('⛈', '⛈'), ('⛎', '⛏'), ('⛑', '⛑'), + ('⛓', '⛔'), ('⛩', '⛪'), ('⛰', '⛵'), ('⛷', '⛺'), + ('⛽', '⛽'), ('✂', '✂'), ('✅', '✅'), ('✈', '✍'), + ('✏', '✏'), ('✒', '✒'), ('✔', '✔'), ('✖', '✖'), + ('✝', '✝'), ('✡', '✡'), ('✨', '✨'), ('✳', '✴'), + ('❄', '❄'), ('❇', '❇'), ('❌', '❌'), ('❎', '❎'), + ('❓', '❕'), ('❗', '❗'), ('❣', '❤'), ('➕', '➗'), + ('➡', '➡'), ('➰', '➰'), ('➿', '➿'), ('⤴', '⤵'), + ('⬅', '⬇'), ('⬛', '⬜'), ('⭐', '⭐'), ('⭕', '⭕'), + ('〰', '〰'), ('〽', '〽'), ('㊗', '㊗'), ('㊙', '㊙'), + ('🀄', '🀄'), ('🃏', '🃏'), ('🅰', '🅱'), ('🅾', '🅿'), + ('🆎', '🆎'), ('🆑', '🆚'), ('🇦', '🇿'), ('🈁', '🈂'), + ('🈚', '🈚'), ('🈯', '🈯'), ('🈲', '🈺'), ('🉐', '🉑'), + ('🌀', '🌡'), ('🌤', '🎓'), ('🎖', '🎗'), ('🎙', '🎛'), + ('🎞', '🏰'), ('🏳', '🏵'), ('🏷', '📽'), ('📿', '🔽'), + ('🕉', '🕎'), ('🕐', '🕧'), ('🕯', '🕰'), ('🕳', '🕺'), + ('🖇', '🖇'), ('🖊', '🖍'), ('🖐', '🖐'), ('🖕', '🖖'), + ('🖤', '🖥'), ('🖨', '🖨'), ('🖱', '🖲'), ('🖼', '🖼'), + ('🗂', '🗄'), ('🗑', '🗓'), ('🗜', '🗞'), ('🗡', '🗡'), + ('🗣', '🗣'), ('🗨', '🗨'), ('🗯', '🗯'), ('🗳', '🗳'), + ('🗺', '🙏'), ('🚀', '🛅'), ('🛋', '🛒'), ('🛠', '🛥'), + ('🛩', '🛩'), ('🛫', '🛬'), ('🛰', '🛰'), ('🛳', '🛹'), + ('🤐', '🤺'), ('🤼', '🤾'), ('🥀', '🥅'), ('🥇', '🥰'), + ('🥳', '🥶'), ('🥺', '🥺'), ('🥼', '🦢'), ('🦰', '🦹'), + ('🧀', '🧂'), ('🧐', '🧿'), +]; + +pub const EMOJI_COMPONENT: &'static [(char, char)] = &[ + ('#', '#'), ('*', '*'), ('0', '9'), ('\u{200d}', '\u{200d}'), + ('\u{20e3}', '\u{20e3}'), ('\u{fe0f}', '\u{fe0f}'), ('🇦', '🇿'), + ('🏻', '🏿'), ('🦰', '🦳'), ('\u{e0020}', '\u{e007f}'), +]; + +pub const EMOJI_MODIFIER: &'static [(char, char)] = &[ + ('🏻', '🏿'), +]; + +pub const EMOJI_MODIFIER_BASE: &'static [(char, char)] = &[ + ('☝', '☝'), ('⛹', '⛹'), ('✊', '✍'), ('🎅', '🎅'), + ('🏂', '🏄'), ('🏇', '🏇'), ('🏊', '🏌'), ('👂', '👃'), + ('👆', '👐'), ('👦', '👩'), ('👮', '👮'), ('👰', '👸'), + ('👼', '👼'), ('💁', '💃'), ('💅', '💇'), ('💪', '💪'), + ('🕴', '🕵'), ('🕺', '🕺'), ('🖐', '🖐'), ('🖕', '🖖'), + ('🙅', '🙇'), ('🙋', '🙏'), ('🚣', '🚣'), ('🚴', '🚶'), + ('🛀', '🛀'), ('🛌', '🛌'), ('🤘', '🤜'), ('🤞', '🤟'), + ('🤦', '🤦'), ('🤰', '🤹'), ('🤽', '🤾'), ('🦵', '🦶'), + ('🦸', '🦹'), ('🧑', '🧝'), +]; + +pub const EMOJI_PRESENTATION: &'static [(char, char)] = &[ + ('⌚', '⌛'), ('⏩', '⏬'), ('⏰', '⏰'), ('⏳', '⏳'), + ('◽', '◾'), ('☔', '☕'), ('♈', '♓'), ('♿', '♿'), + ('⚓', '⚓'), ('⚡', '⚡'), ('⚪', '⚫'), ('⚽', '⚾'), + ('⛄', '⛅'), ('⛎', '⛎'), ('⛔', '⛔'), ('⛪', '⛪'), + ('⛲', '⛳'), ('⛵', '⛵'), ('⛺', '⛺'), ('⛽', '⛽'), + ('✅', '✅'), ('✊', '✋'), ('✨', '✨'), ('❌', '❌'), + ('❎', '❎'), ('❓', '❕'), ('❗', '❗'), ('➕', '➗'), + ('➰', '➰'), ('➿', '➿'), ('⬛', '⬜'), ('⭐', '⭐'), + ('⭕', '⭕'), ('🀄', '🀄'), ('🃏', '🃏'), ('🆎', '🆎'), + ('🆑', '🆚'), ('🇦', '🇿'), ('🈁', '🈁'), ('🈚', '🈚'), + ('🈯', '🈯'), ('🈲', '🈶'), ('🈸', '🈺'), ('🉐', '🉑'), + ('🌀', '🌠'), ('🌭', '🌵'), ('🌷', '🍼'), ('🍾', '🎓'), + ('🎠', '🏊'), ('🏏', '🏓'), ('🏠', '🏰'), ('🏴', '🏴'), + ('🏸', '🐾'), ('👀', '👀'), ('👂', '📼'), ('📿', '🔽'), + ('🕋', '🕎'), ('🕐', '🕧'), ('🕺', '🕺'), ('🖕', '🖖'), + ('🖤', '🖤'), ('🗻', '🙏'), ('🚀', '🛅'), ('🛌', '🛌'), + ('🛐', '🛒'), ('🛫', '🛬'), ('🛴', '🛹'), ('🤐', '🤺'), + ('🤼', '🤾'), ('🥀', '🥅'), ('🥇', '🥰'), ('🥳', '🥶'), + ('🥺', '🥺'), ('🥼', '🦢'), ('🦰', '🦹'), ('🧀', '🧂'), + ('🧐', '🧿'), +]; + +pub const EXTENDED_PICTOGRAPHIC: &'static [(char, char)] = &[ + ('©', '©'), ('®', '®'), ('‼', '‼'), ('⁉', '⁉'), ('™', '™'), + ('ℹ', 'ℹ'), ('↔', '↙'), ('↩', '↪'), ('⌚', '⌛'), + ('⌨', '⌨'), ('⎈', '⎈'), ('⏏', '⏏'), ('⏩', '⏳'), + ('⏸', '⏺'), ('Ⓜ', 'Ⓜ'), ('▪', '▫'), ('▶', '▶'), + ('◀', '◀'), ('◻', '◾'), ('☀', '★'), ('☇', '☒'), + ('☔', '⚅'), ('⚐', '✅'), ('✈', '✒'), ('✔', '✔'), + ('✖', '✖'), ('✝', '✝'), ('✡', '✡'), ('✨', '✨'), + ('✳', '✴'), ('❄', '❄'), ('❇', '❇'), ('❌', '❌'), + ('❎', '❎'), ('❓', '❕'), ('❗', '❗'), ('❣', '❧'), + ('➕', '➗'), ('➡', '➡'), ('➰', '➰'), ('➿', '➿'), + ('⤴', '⤵'), ('⬅', '⬇'), ('⬛', '⬜'), ('⭐', '⭐'), + ('⭕', '⭕'), ('〰', '〰'), ('〽', '〽'), ('㊗', '㊗'), + ('㊙', '㊙'), ('🀀', '\u{1f0ff}'), ('\u{1f10d}', '\u{1f10f}'), + ('🄯', '🄯'), ('\u{1f16c}', '🅱'), ('🅾', '🅿'), ('🆎', '🆎'), + ('🆑', '🆚'), ('\u{1f1ad}', '\u{1f1e5}'), ('🈁', '\u{1f20f}'), + ('🈚', '🈚'), ('🈯', '🈯'), ('🈲', '🈺'), + ('\u{1f23c}', '\u{1f23f}'), ('\u{1f249}', '🏺'), ('🐀', '🔽'), + ('🕆', '🙏'), ('🚀', '\u{1f6ff}'), ('\u{1f774}', '\u{1f77f}'), + ('🟕', '\u{1f7ff}'), ('\u{1f80c}', '\u{1f80f}'), + ('\u{1f848}', '\u{1f84f}'), ('\u{1f85a}', '\u{1f85f}'), + ('\u{1f888}', '\u{1f88f}'), ('\u{1f8ae}', '\u{1f8ff}'), + ('\u{1f90c}', '🤺'), ('🤼', '🥅'), ('🥇', '\u{1fffd}'), +]; + +pub const EXTENDER: &'static [(char, char)] = &[ + ('·', '·'), ('ː', 'ˑ'), ('ـ', 'ـ'), ('ߺ', 'ߺ'), ('ๆ', 'ๆ'), + ('ໆ', 'ໆ'), ('᠊', '᠊'), ('ᡃ', 'ᡃ'), ('ᪧ', 'ᪧ'), + ('\u{1c36}', '\u{1c36}'), ('á±»', 'á±»'), ('々', '々'), ('〱', '〵'), + ('ゝ', 'ゞ'), ('ー', 'ヾ'), ('ꀕ', 'ꀕ'), ('ꘌ', 'ꘌ'), + ('ꧏ', 'ꧏ'), ('ꧦ', 'ꧦ'), ('ê©°', 'ê©°'), ('ꫝ', 'ꫝ'), + ('ꫳ', 'ê«´'), ('ï½°', 'ï½°'), ('𑍝', '𑍝'), ('𑗆', '𑗈'), + ('\u{11a98}', '\u{11a98}'), ('𖭂', '𖭃'), ('𖿠', '𖿡'), + ('\u{1e944}', '\u{1e946}'), +]; + +pub const GRAPHEME_BASE: &'static [(char, char)] = &[ + (' ', '~'), ('\u{a0}', '¬'), ('®', 'Ë¿'), ('Ͱ', 'Í·'), ('ͺ', 'Í¿'), + ('΄', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', '҂'), ('Ҋ', 'Ô¯'), + ('Ô±', 'Ֆ'), ('ՙ', '֊'), ('֍', '֏'), ('Ö¾', 'Ö¾'), ('׀', '׀'), + ('׃', '׃'), ('׆', '׆'), ('א', 'ת'), ('ׯ', '×´'), ('؆', '؏'), + ('؛', '؛'), ('؞', 'ي'), ('Ù ', 'Ù¯'), ('Ù±', 'ە'), ('۞', '۞'), + ('Û¥', 'Û¦'), ('Û©', 'Û©'), ('Û®', '܍'), ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), + ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), ('߀', 'ߪ'), ('ß´', 'ߺ'), ('ß¾', 'ࠕ'), + ('ࠚ', 'ࠚ'), ('à ¤', 'à ¤'), ('à ¨', 'à ¨'), ('à °', 'à ¾'), + ('ࡀ', 'ࡘ'), ('࡞', '࡞'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('ः', 'ह'), ('ऻ', 'ऻ'), ('ऽ', 'ी'), + ('ॉ', 'ौ'), ('ॎ', 'ॐ'), ('क़', 'ॡ'), ('।', 'ঀ'), + ('ং', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), ('ও', 'ন'), + ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), ('ঽ', 'ঽ'), + ('ি', 'ী'), ('ে', 'ৈ'), ('ো', 'ৌ'), ('ৎ', 'ৎ'), + ('ড়', 'ঢ়'), ('য়', 'à§¡'), ('০', 'à§½'), ('ਃ', 'ਃ'), + ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), + ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('ਾ', 'ੀ'), + ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('੦', '੯'), ('ੲ', 'à©´'), + ('à©¶', 'à©¶'), ('ઃ', 'ઃ'), ('અ', 'ઍ'), ('એ', 'ઑ'), + ('ઓ', 'ન'), ('પ', 'ર'), ('લ', 'ળ'), ('વ', 'હ'), + ('ઽ', 'ી'), ('ૉ', 'ૉ'), ('ો', 'ૌ'), ('ૐ', 'ૐ'), + ('à« ', 'à«¡'), ('૦', '૱'), ('ૹ', 'ૹ'), ('ଂ', 'ଃ'), + ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), + ('ଲ', 'ଳ'), ('ଵ', 'ହ'), ('ଽ', 'ଽ'), ('ୀ', 'ୀ'), + ('େ', 'ୈ'), ('ୋ', 'ୌ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), + ('à­¦', 'à­·'), ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('ி', 'ி'), + ('ு', 'ூ'), ('ெ', 'ை'), ('ொ', 'ௌ'), ('ௐ', 'ௐ'), + ('௦', '௺'), ('ఁ', 'ః'), ('అ', 'ఌ'), ('ఎ', 'ఐ'), + ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'à°½'), ('ు', 'ౄ'), + ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('౦', '౯'), ('౸', 'ಀ'), + ('ಂ', 'ಌ'), ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), ('ಽ', 'ಾ'), ('ೀ', 'ು'), ('ೃ', 'ೄ'), + ('ೇ', 'ೈ'), ('ೊ', 'ೋ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), + ('೦', '೯'), ('à³±', 'à³²'), ('ം', 'ഃ'), ('അ', 'ഌ'), + ('എ', 'ഐ'), ('ഒ', 'à´º'), ('à´½', 'à´½'), ('à´¿', 'ീ'), + ('െ', 'ൈ'), ('ൊ', 'ൌ'), ('ൎ', '൏'), ('ൔ', 'ൖ'), + ('൘', 'ൡ'), ('൦', 'ൿ'), ('ං', 'ඃ'), ('අ', 'ඖ'), + ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), ('ව', 'ෆ'), + ('ැ', 'ෑ'), ('ෘ', 'ෞ'), ('à·¦', 'à·¯'), ('à·²', 'à·´'), + ('ก', 'ะ'), ('า', 'ำ'), ('฿', 'ๆ'), ('๏', '๛'), + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ະ'), + ('າ', 'ຳ'), ('ຽ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), + ('໐', '໙'), ('ໜ', 'ໟ'), ('ༀ', '༗'), ('༚', '༴'), + ('༶', '༶'), ('༸', '༸'), ('༺', 'ཇ'), ('ཉ', 'ཬ'), + ('ཿ', 'ཿ'), ('྅', '྅'), ('ྈ', 'ྌ'), ('྾', '࿅'), + ('࿇', '࿌'), ('࿎', '࿚'), ('က', 'ာ'), ('ေ', 'ေ'), + ('း', 'း'), ('ျ', 'ြ'), ('ဿ', 'ၗ'), ('ၚ', 'ၝ'), + ('ၡ', 'ၰ'), ('ၵ', 'ႁ'), ('ႃ', 'ႄ'), ('ႇ', 'ႌ'), + ('ႎ', 'ႜ'), ('႞', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('ა', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), + ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), + ('፠', '፼'), ('ᎀ', '᎙'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), + ('᐀', '᚜'), ('ᚠ', 'ᛸ'), ('ᜀ', 'ᜌ'), ('ᜎ', 'ᜑ'), + ('ᜠ', 'ᜱ'), ('᜵', '᜶'), ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), + ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), ('ា', 'ា'), ('ើ', 'ៅ'), + ('ះ', 'ៈ'), ('។', 'ៜ'), ('០', '៩'), ('៰', '៹'), + ('᠀', '᠊'), ('᠐', '᠙'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), ('ᤀ', 'ᤞ'), + ('ᤣ', 'ᤦ'), ('ᤩ', 'ᤫ'), ('ᤰ', 'ᤱ'), ('ᤳ', 'ᤸ'), + ('᥀', '᥀'), ('᥄', 'ᥭ'), ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), ('᧐', '᧚'), ('᧞', 'ᨖ'), ('ᨙ', 'ᨚ'), + ('᨞', 'ᩕ'), ('ᩗ', 'ᩗ'), ('á©¡', 'á©¡'), ('á©£', 'ᩤ'), + ('á©­', 'ᩲ'), ('᪀', '᪉'), ('᪐', '᪙'), ('᪠', '᪭'), + ('ᬄ', 'ᬳ'), ('ᬵ', 'ᬵ'), ('ᬻ', 'ᬻ'), ('ᬽ', 'ᭁ'), + ('ᭃ', 'ᭋ'), ('᭐', 'á­ª'), ('á­´', 'á­¼'), ('ᮂ', 'ᮡ'), + ('ᮦ', 'á®§'), ('᮪', '᮪'), ('á®®', 'ᯥ'), ('ᯧ', 'ᯧ'), + ('ᯪ', 'ᯬ'), ('ᯮ', 'ᯮ'), ('᯲', '᯳'), ('᯼', 'á°«'), + ('á°´', 'á°µ'), ('á°»', '᱉'), ('ᱍ', 'ᲈ'), ('Ა', 'Ჺ'), + ('á²½', '᳇'), ('᳓', '᳓'), ('᳡', '᳡'), ('ᳩ', 'ᳬ'), + ('á³®', 'á³³'), ('á³µ', 'á³·'), ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), + ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), + ('ᾀ', 'á¾´'), ('á¾¶', 'ῄ'), ('ῆ', 'ΐ'), ('ῖ', 'Ί'), + ('῝', '`'), ('ῲ', 'á¿´'), ('á¿¶', '῾'), ('\u{2000}', '\u{200a}'), + ('‐', '‧'), ('\u{202f}', '\u{205f}'), ('⁰', 'ⁱ'), ('⁴', '₎'), + ('ₐ', 'ₜ'), ('₠', '₿'), ('℀', '↋'), ('←', '␦'), + ('⑀', '⑊'), ('①', 'â­³'), ('â­¶', '⮕'), ('⮘', '⯈'), + ('⯊', '⯾'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('â± ', 'â³®'), + ('â³²', 'â³³'), ('â³¹', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), + ('â´°', 'âµ§'), ('ⵯ', 'âµ°'), ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), + ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), + ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('⸀', '⹎'), + ('⺀', '⺙'), ('⺛', '⻳'), ('⼀', '⿕'), ('â¿°', 'â¿»'), + ('\u{3000}', '〩'), ('〰', '〿'), ('ぁ', 'ゖ'), ('゛', 'ヿ'), + ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), ('㆐', 'ㆺ'), ('㇀', '㇣'), + ('ㇰ', '㈞'), ('㈠', '㋾'), ('㌀', 'ä¶µ'), ('䷀', '鿯'), + ('ꀀ', 'ꒌ'), ('꒐', '꓆'), ('ꓐ', 'ꘫ'), ('Ꙁ', 'ꙮ'), + ('꙳', '꙳'), ('꙾', 'ꚝ'), ('ꚠ', 'ꛯ'), ('꛲', '꛷'), + ('꜀', 'ꞹ'), ('ꟷ', 'ꠁ'), ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), + ('ꠌ', 'ê ¤'), ('ê §', 'ê «'), ('ê °', 'ê ¹'), ('ꡀ', 'ê¡·'), + ('ꢀ', 'ꣃ'), ('꣎', '꣙'), ('ꣲ', 'ꣾ'), ('꤀', 'ꤥ'), + ('꤮', 'ꥆ'), ('ꥒ', '꥓'), ('꥟', 'ꥼ'), ('ꦃ', 'ꦲ'), + ('ꦴ', 'ꦵ'), ('ꦺ', 'ꦻ'), ('ꦽ', '꧍'), ('ꧏ', '꧙'), + ('꧞', 'ꧤ'), ('ꧦ', 'ê§¾'), ('ꨀ', 'ꨨ'), ('ꨯ', 'ꨰ'), + ('ꨳ', 'ꨴ'), ('ꩀ', 'ꩂ'), ('ꩄ', 'ꩋ'), ('ꩍ', 'ꩍ'), + ('꩐', '꩙'), ('꩜', 'ê©»'), ('ꩽ', 'ꪯ'), ('ꪱ', 'ꪱ'), + ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪽ'), ('ꫀ', 'ꫀ'), ('ꫂ', 'ꫂ'), + ('ꫛ', 'ê««'), ('ê«®', 'ꫵ'), ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), ('ꬰ', 'ê­¥'), + ('ê­°', 'ꯤ'), ('ꯦ', 'ꯧ'), ('ꯩ', '꯬'), ('꯰', '꯹'), + ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), + ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('יִ', 'יִ'), + ('ײַ', 'זּ'), ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), + ('ףּ', 'פּ'), ('צּ', '﯁'), ('ﯓ', 'ï´¿'), ('ﵐ', 'ﶏ'), + ('ﶒ', 'ﷇ'), ('ï·°', 'ï·½'), ('︐', '︙'), ('︰', '﹒'), + ('﹔', '﹦'), ('﹨', '﹫'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), + ('!', 'ン'), ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), + ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('ï¿ ', '₩'), ('│', 'ï¿®'), + ('', '�'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), + ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), + ('𐄀', '𐄂'), ('𐄇', '𐄳'), ('𐄷', '𐆎'), ('𐆐', '𐆛'), + ('𐆠', '𐆠'), ('𐇐', '𐇼'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), + ('𐋡', '𐋻'), ('𐌀', '𐌣'), ('𐌭', '𐍊'), ('𐍐', '𐍵'), + ('𐎀', '𐎝'), ('𐎟', '𐏃'), ('𐏈', '𐏕'), ('𐐀', '𐒝'), + ('𐒠', '𐒩'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐕯', '𐕯'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), + ('𐝠', '𐝧'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), + ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡗', '𐢞'), + ('𐢧', '𐢯'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐣻', '𐤛'), + ('𐤟', '𐤹'), ('𐤿', '𐤿'), ('𐦀', '𐦷'), ('𐦼', '𐧏'), + ('𐧒', '𐨀'), ('𐨐', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '𐨵'), + ('𐩀', '𐩈'), ('𐩐', '𐩘'), ('𐩠', '𐪟'), ('𐫀', '𐫤'), + ('𐫫', '𐫶'), ('𐬀', '𐬵'), ('𐬹', '𐭕'), ('𐭘', '𐭲'), + ('𐭸', '𐮑'), ('𐮙', '𐮜'), ('𐮩', '𐮯'), ('𐰀', '𐱈'), + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐳺', '𐴣'), ('𐴰', '𐴹'), + ('𐹠', '𐹾'), ('𐼀', '𐼧'), ('𐼰', '𐽅'), ('𐽑', '𐽙'), + ('𑀀', '𑀀'), ('𑀂', '𑀷'), ('𑁇', '𑁍'), ('𑁒', '𑁯'), + ('𑂂', '𑂲'), ('𑂷', '𑂸'), ('𑂻', '𑂼'), ('𑂾', '𑃁'), + ('𑃐', '𑃨'), ('𑃰', '𑃹'), ('𑄃', '𑄦'), ('𑄬', '𑄬'), + ('𑄶', '𑅆'), ('𑅐', '𑅲'), ('𑅴', '𑅶'), ('𑆂', '𑆵'), + ('𑆿', '𑇈'), ('𑇍', '𑇍'), ('𑇐', '𑇟'), ('𑇡', '𑇴'), + ('𑈀', '𑈑'), ('𑈓', '𑈮'), ('𑈲', '𑈳'), ('𑈵', '𑈵'), + ('𑈸', '𑈽'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), + ('𑊏', '𑊝'), ('𑊟', '𑊩'), ('𑊰', '𑋞'), ('𑋠', '𑋢'), + ('𑋰', '𑋹'), ('𑌂', '𑌃'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('𑌽', '𑌽'), ('𑌿', '𑌿'), ('𑍁', '𑍄'), ('𑍇', '𑍈'), + ('𑍋', '𑍍'), ('𑍐', '𑍐'), ('𑍝', '𑍣'), ('𑐀', '𑐷'), + ('𑑀', '𑑁'), ('𑑅', '𑑅'), ('𑑇', '𑑙'), ('𑑛', '𑑛'), + ('𑑝', '𑑝'), ('𑒀', '𑒯'), ('𑒱', '𑒲'), ('𑒹', '𑒹'), + ('𑒻', '𑒼'), ('𑒾', '𑒾'), ('𑓁', '𑓁'), ('𑓄', '𑓇'), + ('𑓐', '𑓙'), ('𑖀', '𑖮'), ('𑖰', '𑖱'), ('𑖸', '𑖻'), + ('𑖾', '𑖾'), ('𑗁', '𑗛'), ('𑘀', '𑘲'), ('𑘻', '𑘼'), + ('𑘾', '𑘾'), ('𑙁', '𑙄'), ('𑙐', '𑙙'), ('𑙠', '𑙬'), + ('𑚀', '𑚪'), ('𑚬', '𑚬'), ('𑚮', '𑚯'), ('𑚶', '𑚶'), + ('𑛀', '𑛉'), ('𑜀', '𑜚'), ('𑜠', '𑜡'), ('𑜦', '𑜦'), + ('𑜰', '𑜿'), ('𑠀', '𑠮'), ('𑠸', '𑠸'), ('𑠻', '𑠻'), + ('𑢠', '𑣲'), ('𑣿', '𑣿'), ('𑨀', '𑨀'), ('𑨋', '𑨲'), + ('𑨹', '𑨺'), ('𑨿', '𑩆'), ('𑩐', '𑩐'), ('𑩗', '𑩘'), + ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('𑪗', '𑪗'), ('𑪚', '𑪢'), + ('𑫀', '𑫸'), ('𑰀', '𑰈'), ('𑰊', '𑰯'), ('𑰾', '𑰾'), + ('𑱀', '𑱅'), ('𑱐', '𑱬'), ('𑱰', '𑲏'), ('𑲩', '𑲩'), + ('𑲱', '𑲱'), ('𑲴', '𑲴'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), + ('𑴋', '𑴰'), ('𑵆', '𑵆'), ('𑵐', '𑵙'), ('𑵠', '𑵥'), + ('𑵧', '𑵨'), ('𑵪', '𑶎'), ('𑶓', '𑶔'), ('𑶖', '𑶖'), + ('𑶘', '𑶘'), ('𑶠', '𑶩'), ('𑻠', '𑻲'), ('𑻵', '𑻸'), + ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒑰', '𒑴'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖩠', '𖩩'), ('𖩮', '𖩯'), ('𖫐', '𖫭'), ('𖫵', '𖫵'), + ('𖬀', '𖬯'), ('𖬷', '𖭅'), ('𖭐', '𖭙'), ('𖭛', '𖭡'), + ('𖭣', '𖭷'), ('𖭽', '𖮏'), ('𖹀', '𖺚'), ('𖼀', '𖽄'), + ('𖽐', '𖽾'), ('𖾓', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '𘟱'), + ('𘠀', '𘫲'), ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), + ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𛲜', '𛲜'), + ('𛲟', '𛲟'), ('𝀀', '𝃵'), ('𝄀', '𝄦'), ('𝄩', '𝅘𝅥𝅲'), + ('𝅦', '𝅦'), ('𝅪', '𝅭'), ('𝆃', '𝆄'), ('𝆌', '𝆩'), + ('𝆮', '𝇨'), ('𝈀', '𝉁'), ('𝉅', '𝉅'), ('𝋠', '𝋳'), + ('𝌀', '𝍖'), ('𝍠', '𝍸'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝟋'), ('𝟎', '𝧿'), ('𝨷', '𝨺'), + ('𝩭', '𝩴'), ('𝩶', '𝪃'), ('𝪅', '𝪋'), ('𞠀', '𞣄'), + ('𞣇', '𞣏'), ('𞤀', '𞥃'), ('𞥐', '𞥙'), ('𞥞', '𞥟'), + ('𞱱', '𞲴'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), ('𞸡', '𞸢'), + ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), ('𞸴', '𞸷'), + ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), ('𞹇', '𞹇'), + ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), ('𞹑', '𞹒'), + ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), ('𞹛', '𞹛'), + ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), ('𞹤', '𞹤'), + ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), ('𞹹', '𞹼'), + ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), ('𞺡', '𞺣'), + ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𞻰', '𞻱'), ('🀀', '🀫'), + ('🀰', '🂓'), ('🂠', '🂮'), ('🂱', '🂿'), ('🃁', '🃏'), + ('🃑', '🃵'), ('🄀', '🄌'), ('🄐', '🅫'), ('🅰', '🆬'), + ('🇦', '🈂'), ('🈐', '🈻'), ('🉀', '🉈'), ('🉐', '🉑'), + ('🉠', '🉥'), ('🌀', '🛔'), ('🛠', '🛬'), ('🛰', '🛹'), + ('🜀', '🝳'), ('🞀', '🟘'), ('🠀', '🠋'), ('🠐', '🡇'), + ('🡐', '🡙'), ('🡠', '🢇'), ('🢐', '🢭'), ('🤀', '🤋'), + ('🤐', '🤾'), ('🥀', '🥰'), ('🥳', '🥶'), ('🥺', '🥺'), + ('🥼', '🦢'), ('🦰', '🦹'), ('🧀', '🧂'), ('🧐', '🧿'), + ('🩠', '🩭'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), + ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const GRAPHEME_EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), ('\u{483}', '\u{489}'), ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dc}'), ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), + ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', '\u{902}'), ('\u{93a}', '\u{93a}'), + ('\u{93c}', '\u{93c}'), ('\u{941}', '\u{948}'), ('\u{94d}', '\u{94d}'), + ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), ('\u{981}', '\u{981}'), + ('\u{9bc}', '\u{9bc}'), ('\u{9be}', '\u{9be}'), ('\u{9c1}', '\u{9c4}'), + ('\u{9cd}', '\u{9cd}'), ('\u{9d7}', '\u{9d7}'), ('\u{9e2}', '\u{9e3}'), + ('\u{9fe}', '\u{9fe}'), ('\u{a01}', '\u{a02}'), ('\u{a3c}', '\u{a3c}'), + ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), + ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'), + ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', '\u{ac5}'), + ('\u{ac7}', '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), + ('\u{afa}', '\u{aff}'), ('\u{b01}', '\u{b01}'), ('\u{b3c}', '\u{b3c}'), + ('\u{b3e}', '\u{b3f}'), ('\u{b41}', '\u{b44}'), ('\u{b4d}', '\u{b4d}'), + ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'), + ('\u{bbe}', '\u{bbe}'), ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), + ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c00}'), ('\u{c04}', '\u{c04}'), + ('\u{c3e}', '\u{c40}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), ('\u{c81}', '\u{c81}'), + ('\u{cbc}', '\u{cbc}'), ('\u{cbf}', '\u{cbf}'), ('\u{cc2}', '\u{cc2}'), + ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), + ('\u{ce2}', '\u{ce3}'), ('\u{d00}', '\u{d01}'), ('\u{d3b}', '\u{d3c}'), + ('\u{d3e}', '\u{d3e}'), ('\u{d41}', '\u{d44}'), ('\u{d4d}', '\u{d4d}'), + ('\u{d57}', '\u{d57}'), ('\u{d62}', '\u{d63}'), ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dcf}'), ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), + ('\u{ddf}', '\u{ddf}'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('\u{f71}', '\u{f7e}'), ('\u{f80}', '\u{f84}'), ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('\u{102d}', '\u{1030}'), ('\u{1032}', '\u{1037}'), + ('\u{1039}', '\u{103a}'), ('\u{103d}', '\u{103e}'), + ('\u{1058}', '\u{1059}'), ('\u{105e}', '\u{1060}'), + ('\u{1071}', '\u{1074}'), ('\u{1082}', '\u{1082}'), + ('\u{1085}', '\u{1086}'), ('\u{108d}', '\u{108d}'), + ('\u{109d}', '\u{109d}'), ('\u{135d}', '\u{135f}'), + ('\u{1712}', '\u{1714}'), ('\u{1732}', '\u{1734}'), + ('\u{1752}', '\u{1753}'), ('\u{1772}', '\u{1773}'), + ('\u{17b4}', '\u{17b5}'), ('\u{17b7}', '\u{17bd}'), + ('\u{17c6}', '\u{17c6}'), ('\u{17c9}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180d}'), + ('\u{1885}', '\u{1886}'), ('\u{18a9}', '\u{18a9}'), + ('\u{1920}', '\u{1922}'), ('\u{1927}', '\u{1928}'), + ('\u{1932}', '\u{1932}'), ('\u{1939}', '\u{193b}'), + ('\u{1a17}', '\u{1a18}'), ('\u{1a1b}', '\u{1a1b}'), + ('\u{1a56}', '\u{1a56}'), ('\u{1a58}', '\u{1a5e}'), + ('\u{1a60}', '\u{1a60}'), ('\u{1a62}', '\u{1a62}'), + ('\u{1a65}', '\u{1a6c}'), ('\u{1a73}', '\u{1a7c}'), + ('\u{1a7f}', '\u{1a7f}'), ('\u{1ab0}', '\u{1abe}'), + ('\u{1b00}', '\u{1b03}'), ('\u{1b34}', '\u{1b34}'), + ('\u{1b36}', '\u{1b3a}'), ('\u{1b3c}', '\u{1b3c}'), + ('\u{1b42}', '\u{1b42}'), ('\u{1b6b}', '\u{1b73}'), + ('\u{1b80}', '\u{1b81}'), ('\u{1ba2}', '\u{1ba5}'), + ('\u{1ba8}', '\u{1ba9}'), ('\u{1bab}', '\u{1bad}'), + ('\u{1be6}', '\u{1be6}'), ('\u{1be8}', '\u{1be9}'), + ('\u{1bed}', '\u{1bed}'), ('\u{1bef}', '\u{1bf1}'), + ('\u{1c2c}', '\u{1c33}'), ('\u{1c36}', '\u{1c37}'), + ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1ce0}'), + ('\u{1ce2}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), + ('\u{1cf4}', '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), + ('\u{1dc0}', '\u{1df9}'), ('\u{1dfb}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), + ('\u{a825}', '\u{a826}'), ('\u{a8c4}', '\u{a8c5}'), + ('\u{a8e0}', '\u{a8f1}'), ('\u{a8ff}', '\u{a8ff}'), + ('\u{a926}', '\u{a92d}'), ('\u{a947}', '\u{a951}'), + ('\u{a980}', '\u{a982}'), ('\u{a9b3}', '\u{a9b3}'), + ('\u{a9b6}', '\u{a9b9}'), ('\u{a9bc}', '\u{a9bc}'), + ('\u{a9e5}', '\u{a9e5}'), ('\u{aa29}', '\u{aa2e}'), + ('\u{aa31}', '\u{aa32}'), ('\u{aa35}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', '\u{aa4c}'), + ('\u{aa7c}', '\u{aa7c}'), ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'), + ('\u{aaec}', '\u{aaed}'), ('\u{aaf6}', '\u{aaf6}'), + ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'), + ('\u{abed}', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), + ('\u{11001}', '\u{11001}'), ('\u{11038}', '\u{11046}'), + ('\u{1107f}', '\u{11081}'), ('\u{110b3}', '\u{110b6}'), + ('\u{110b9}', '\u{110ba}'), ('\u{11100}', '\u{11102}'), + ('\u{11127}', '\u{1112b}'), ('\u{1112d}', '\u{11134}'), + ('\u{11173}', '\u{11173}'), ('\u{11180}', '\u{11181}'), + ('\u{111b6}', '\u{111be}'), ('\u{111c9}', '\u{111cc}'), + ('\u{1122f}', '\u{11231}'), ('\u{11234}', '\u{11234}'), + ('\u{11236}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), + ('\u{112df}', '\u{112df}'), ('\u{112e3}', '\u{112ea}'), + ('\u{11300}', '\u{11301}'), ('\u{1133b}', '\u{1133c}'), + ('\u{1133e}', '\u{1133e}'), ('\u{11340}', '\u{11340}'), + ('\u{11357}', '\u{11357}'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('\u{11438}', '\u{1143f}'), + ('\u{11442}', '\u{11444}'), ('\u{11446}', '\u{11446}'), + ('\u{1145e}', '\u{1145e}'), ('\u{114b0}', '\u{114b0}'), + ('\u{114b3}', '\u{114b8}'), ('\u{114ba}', '\u{114ba}'), + ('\u{114bd}', '\u{114bd}'), ('\u{114bf}', '\u{114c0}'), + ('\u{114c2}', '\u{114c3}'), ('\u{115af}', '\u{115af}'), + ('\u{115b2}', '\u{115b5}'), ('\u{115bc}', '\u{115bd}'), + ('\u{115bf}', '\u{115c0}'), ('\u{115dc}', '\u{115dd}'), + ('\u{11633}', '\u{1163a}'), ('\u{1163d}', '\u{1163d}'), + ('\u{1163f}', '\u{11640}'), ('\u{116ab}', '\u{116ab}'), + ('\u{116ad}', '\u{116ad}'), ('\u{116b0}', '\u{116b5}'), + ('\u{116b7}', '\u{116b7}'), ('\u{1171d}', '\u{1171f}'), + ('\u{11722}', '\u{11725}'), ('\u{11727}', '\u{1172b}'), + ('\u{1182f}', '\u{11837}'), ('\u{11839}', '\u{1183a}'), + ('\u{11a01}', '\u{11a0a}'), ('\u{11a33}', '\u{11a38}'), + ('\u{11a3b}', '\u{11a3e}'), ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a56}'), ('\u{11a59}', '\u{11a5b}'), + ('\u{11a8a}', '\u{11a96}'), ('\u{11a98}', '\u{11a99}'), + ('\u{11c30}', '\u{11c36}'), ('\u{11c38}', '\u{11c3d}'), + ('\u{11c3f}', '\u{11c3f}'), ('\u{11c92}', '\u{11ca7}'), + ('\u{11caa}', '\u{11cb0}'), ('\u{11cb2}', '\u{11cb3}'), + ('\u{11cb5}', '\u{11cb6}'), ('\u{11d31}', '\u{11d36}'), + ('\u{11d3a}', '\u{11d3a}'), ('\u{11d3c}', '\u{11d3d}'), + ('\u{11d3f}', '\u{11d45}'), ('\u{11d47}', '\u{11d47}'), + ('\u{11d90}', '\u{11d91}'), ('\u{11d95}', '\u{11d95}'), + ('\u{11d97}', '\u{11d97}'), ('\u{11ef3}', '\u{11ef4}'), + ('\u{16af0}', '\u{16af4}'), ('\u{16b30}', '\u{16b36}'), + ('\u{16f8f}', '\u{16f92}'), ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d165}'), ('\u{1d167}', '\u{1d169}'), + ('\u{1d16e}', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e944}', '\u{1e94a}'), + ('\u{e0020}', '\u{e007f}'), ('\u{e0100}', '\u{e01ef}'), +]; + +pub const GRAPHEME_LINK: &'static [(char, char)] = &[ + ('\u{94d}', '\u{94d}'), ('\u{9cd}', '\u{9cd}'), ('\u{a4d}', '\u{a4d}'), + ('\u{acd}', '\u{acd}'), ('\u{b4d}', '\u{b4d}'), ('\u{bcd}', '\u{bcd}'), + ('\u{c4d}', '\u{c4d}'), ('\u{ccd}', '\u{ccd}'), ('\u{d3b}', '\u{d3c}'), + ('\u{d4d}', '\u{d4d}'), ('\u{dca}', '\u{dca}'), ('\u{e3a}', '\u{e3a}'), + ('\u{f84}', '\u{f84}'), ('\u{1039}', '\u{103a}'), ('\u{1714}', '\u{1714}'), + ('\u{1734}', '\u{1734}'), ('\u{17d2}', '\u{17d2}'), + ('\u{1a60}', '\u{1a60}'), ('᭄', '᭄'), ('᮪', '\u{1bab}'), + ('᯲', '᯳'), ('\u{2d7f}', '\u{2d7f}'), ('\u{a806}', '\u{a806}'), + ('\u{a8c4}', '\u{a8c4}'), ('꥓', '꥓'), ('꧀', '꧀'), + ('\u{aaf6}', '\u{aaf6}'), ('\u{abed}', '\u{abed}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{11046}', '\u{11046}'), + ('\u{1107f}', '\u{1107f}'), ('\u{110b9}', '\u{110b9}'), + ('\u{11133}', '\u{11134}'), ('𑇀', '𑇀'), ('𑈵', '𑈵'), + ('\u{112ea}', '\u{112ea}'), ('𑍍', '𑍍'), ('\u{11442}', '\u{11442}'), + ('\u{114c2}', '\u{114c2}'), ('\u{115bf}', '\u{115bf}'), + ('\u{1163f}', '\u{1163f}'), ('𑚶', '𑚶'), ('\u{1172b}', '\u{1172b}'), + ('\u{11839}', '\u{11839}'), ('\u{11a34}', '\u{11a34}'), + ('\u{11a47}', '\u{11a47}'), ('\u{11a99}', '\u{11a99}'), + ('\u{11c3f}', '\u{11c3f}'), ('\u{11d44}', '\u{11d45}'), + ('\u{11d97}', '\u{11d97}'), +]; + +pub const HEX_DIGIT: &'static [(char, char)] = &[ + ('0', '9'), ('A', 'F'), ('a', 'f'), ('0', '9'), ('A', 'F'), + ('a', 'f'), +]; + +pub const HYPHEN: &'static [(char, char)] = &[ + ('-', '-'), ('\u{ad}', '\u{ad}'), ('֊', '֊'), ('᠆', '᠆'), + ('‐', '‑'), ('⸗', '⸗'), ('・', '・'), ('ï¹£', 'ï¹£'), + ('-', '-'), ('ï½¥', 'ï½¥'), +]; + +pub const IDS_BINARY_OPERATOR: &'static [(char, char)] = &[ + ('â¿°', '⿱'), ('â¿´', 'â¿»'), +]; + +pub const IDS_TRINARY_OPERATOR: &'static [(char, char)] = &[ + ('⿲', '⿳'), +]; + +pub const ID_CONTINUE: &'static [(char, char)] = &[ + ('0', '9'), ('A', 'Z'), ('_', '_'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), + ('·', '·'), ('º', 'º'), ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), + ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('\u{300}', 'Í´'), + ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('\u{483}', '\u{487}'), + ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), ('Õ ', 'ֈ'), + ('\u{591}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('א', 'ת'), ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), ('Ø ', 'Ù©'), ('Ù®', 'ۓ'), ('ە', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), ('\u{6ea}', 'Û¼'), ('Û¿', 'Û¿'), ('ܐ', '\u{74a}'), + ('ݍ', 'Þ±'), ('߀', 'ßµ'), ('ߺ', 'ߺ'), ('\u{7fd}', '\u{7fd}'), + ('ࠀ', '\u{82d}'), ('ࡀ', '\u{85b}'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', '\u{963}'), + ('०', '९'), ('ॱ', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), ('ে', 'ৈ'), ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), ('ড়', 'ঢ়'), ('য়', '\u{9e3}'), ('০', 'à§±'), + ('à§¼', 'à§¼'), ('\u{9fe}', '\u{9fe}'), ('\u{a01}', 'ਃ'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('\u{a3c}', '\u{a3c}'), ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), + ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('੦', '\u{a75}'), ('\u{a81}', 'ઃ'), + ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('\u{abc}', '\u{ac5}'), ('\u{ac7}', 'ૉ'), + ('ો', '\u{acd}'), ('ૐ', 'ૐ'), ('à« ', '\u{ae3}'), ('૦', '૯'), + ('ૹ', '\u{aff}'), ('\u{b01}', 'ଃ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), + ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), ('େ', 'ୈ'), ('ୋ', '\u{b4d}'), + ('\u{b56}', '\u{b57}'), ('ଡ଼', 'ଢ଼'), ('ୟ', '\u{b63}'), ('à­¦', 'à­¯'), + ('à­±', 'à­±'), ('\u{b82}', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), ('ொ', '\u{bcd}'), ('ௐ', 'ௐ'), ('\u{bd7}', '\u{bd7}'), + ('௦', '௯'), ('\u{c00}', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), + ('à°ª', 'à°¹'), ('à°½', 'ౄ'), ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('ౘ', 'ౚ'), + ('à± ', '\u{c63}'), ('౦', '౯'), ('ಀ', 'ಃ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), ('\u{cc6}', 'ೈ'), ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), ('ೞ', 'ೞ'), ('à³ ', '\u{ce3}'), ('೦', '೯'), + ('à³±', 'à³²'), ('\u{d00}', 'ഃ'), ('അ', 'ഌ'), ('എ', 'ഐ'), + ('ഒ', '\u{d44}'), ('െ', 'ൈ'), ('ൊ', 'ൎ'), ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), ('൦', '൯'), ('ൺ', 'ൿ'), ('ං', 'ඃ'), + ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), + ('ව', 'ෆ'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), ('à·¦', 'à·¯'), ('à·²', 'à·³'), + ('ก', '\u{e3a}'), ('เ', '\u{e4e}'), ('๐', '๙'), ('ກ', 'ຂ'), + ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), + ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), ('ລ', 'ລ'), + ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', '\u{eb9}'), ('\u{ebb}', 'ຽ'), + ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('\u{ec8}', '\u{ecd}'), ('໐', '໙'), + ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('\u{f18}', '\u{f19}'), ('༠', '༩'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('༾', 'ཇ'), ('ཉ', 'ཬ'), ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('က', '၉'), ('ၐ', '\u{109d}'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), + ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኈ'), + ('ኊ', 'ኍ'), ('ነ', 'ኰ'), ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), + ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), ('ወ', 'ዖ'), ('ዘ', 'ጐ'), + ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), ('\u{135d}', '\u{135f}'), ('፩', '፱'), + ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), + ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), + ('ᜀ', 'ᜌ'), ('ᜎ', '\u{1714}'), ('ᜠ', '\u{1734}'), + ('ᝀ', '\u{1753}'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), + ('\u{1772}', '\u{1773}'), ('ក', '\u{17d3}'), ('ៗ', 'ៗ'), + ('ៜ', '\u{17dd}'), ('០', '៩'), ('\u{180b}', '\u{180d}'), + ('᠐', '᠙'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('\u{1920}', 'ᤫ'), ('ᤰ', '\u{193b}'), ('᥆', 'ᥭ'), + ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('᧐', '᧚'), + ('ᨀ', '\u{1a1b}'), ('ᨠ', '\u{1a5e}'), ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), ('᪐', '᪙'), ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', 'ᭋ'), ('᭐', '᭙'), + ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '᯳'), ('ᰀ', '\u{1c37}'), + ('᱀', '᱉'), ('ᱍ', 'á±½'), ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), + ('á²½', 'Ჿ'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cf9}'), + ('ᴀ', '\u{1df9}'), ('\u{1dfb}', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), + ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), + ('‿', '⁀'), ('⁔', '⁔'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), + ('ₐ', 'ₜ'), ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('℘', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), + ('ℨ', 'ℨ'), ('K', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'ⳤ'), ('Ⳬ', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), + ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), ('\u{2d7f}', 'ⶖ'), + ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), + ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), + ('\u{2de0}', '\u{2dff}'), ('々', '〇'), ('〡', '\u{302f}'), + ('〱', '〵'), ('〸', '〼'), ('ぁ', 'ゖ'), ('\u{3099}', 'ゟ'), + ('ァ', 'ヺ'), ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), + ('ㆠ', 'ㆺ'), ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '鿯'), + ('ꀀ', 'ꒌ'), ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘫ'), + ('Ꙁ', '\u{a66f}'), ('\u{a674}', '\u{a67d}'), ('ꙿ', '\u{a6f1}'), + ('ꜗ', 'ꜟ'), ('Ꜣ', 'ꞈ'), ('Ꞌ', 'ꞹ'), ('ꟷ', 'ê §'), + ('ꡀ', 'ꡳ'), ('ꢀ', '\u{a8c5}'), ('꣐', '꣙'), ('\u{a8e0}', 'ꣷ'), + ('ꣻ', 'ꣻ'), ('ꣽ', '\u{a92d}'), ('ꤰ', '꥓'), ('ꥠ', 'ꥼ'), + ('\u{a980}', '꧀'), ('ꧏ', '꧙'), ('ê§ ', 'ê§¾'), ('ꨀ', '\u{aa36}'), + ('ꩀ', 'ꩍ'), ('꩐', '꩙'), ('ê© ', 'ê©¶'), ('ꩺ', 'ꫂ'), + ('ꫛ', 'ꫝ'), ('ê« ', 'ꫯ'), ('ꫲ', '\u{aaf6}'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), + ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), ('ê­°', 'ꯪ'), ('꯬', '\u{abed}'), + ('꯰', '꯹'), ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), + ('יִ', 'ﬨ'), ('שׁ', 'זּ'), ('טּ', 'לּ'), ('מּ', 'מּ'), + ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), + ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), ('\u{fe00}', '\u{fe0f}'), + ('\u{fe20}', '\u{fe2f}'), ('︳', '︴'), ('﹍', '﹏'), ('ï¹°', 'ï¹´'), + ('ï¹¶', 'ﻼ'), ('0', '9'), ('A', 'Z'), ('_', '_'), + ('a', 'z'), ('ヲ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), + ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), + ('𐀨', '𐀺'), ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), + ('𐂀', '𐃺'), ('𐅀', '𐅴'), ('\u{101fd}', '\u{101fd}'), + ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('\u{102e0}', '\u{102e0}'), + ('𐌀', '𐌟'), ('𐌭', '𐍊'), ('𐍐', '\u{1037a}'), ('𐎀', '𐎝'), + ('𐎠', '𐏃'), ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐐀', '𐒝'), + ('𐒠', '𐒩'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '𐨓'), ('𐨕', '𐨗'), + ('𐨙', '𐨵'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), + ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '\u{10ae6}'), + ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), + ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐴀', '\u{10d27}'), + ('𐴰', '𐴹'), ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '\u{10f50}'), + ('𑀀', '\u{11046}'), ('𑁦', '𑁯'), ('\u{1107f}', '\u{110ba}'), + ('𑃐', '𑃨'), ('𑃰', '𑃹'), ('\u{11100}', '\u{11134}'), + ('𑄶', '𑄿'), ('𑅄', '𑅆'), ('𑅐', '\u{11173}'), ('𑅶', '𑅶'), + ('\u{11180}', '𑇄'), ('\u{111c9}', '\u{111cc}'), ('𑇐', '𑇚'), + ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), + ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), ('𑊰', '\u{112ea}'), + ('𑋰', '𑋹'), ('\u{11300}', '𑌃'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('\u{1133b}', '𑍄'), ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍐', '𑍐'), + ('\u{11357}', '\u{11357}'), ('𑍝', '𑍣'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('𑐀', '𑑊'), ('𑑐', '𑑙'), + ('\u{1145e}', '\u{1145e}'), ('𑒀', '𑓅'), ('𑓇', '𑓇'), + ('𑓐', '𑓙'), ('𑖀', '\u{115b5}'), ('𑖸', '\u{115c0}'), + ('𑗘', '\u{115dd}'), ('𑘀', '\u{11640}'), ('𑙄', '𑙄'), + ('𑙐', '𑙙'), ('𑚀', '\u{116b7}'), ('𑛀', '𑛉'), ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172b}'), ('𑜰', '𑜹'), ('𑠀', '\u{1183a}'), + ('𑢠', '𑣩'), ('𑣿', '𑣿'), ('𑨀', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), ('𑩐', '𑪃'), ('𑪆', '\u{11a99}'), + ('𑪝', '𑪝'), ('𑫀', '𑫸'), ('𑰀', '𑰈'), ('𑰊', '\u{11c36}'), + ('\u{11c38}', '𑱀'), ('𑱐', '𑱙'), ('𑱲', '𑲏'), + ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}'), ('𑴀', '𑴆'), + ('𑴈', '𑴉'), ('𑴋', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d47}'), ('𑵐', '𑵙'), + ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), ('𑶓', '𑶘'), ('𑶠', '𑶩'), + ('𑻠', '𑻶'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖩠', '𖩩'), ('𖫐', '𖫭'), ('\u{16af0}', '\u{16af4}'), + ('𖬀', '\u{16b36}'), ('𖭀', '𖭃'), ('𖭐', '𖭙'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('𖹀', '𖹿'), ('𖼀', '𖽄'), ('𖽐', '𖽾'), + ('\u{16f8f}', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '𘟱'), ('𘠀', '𘫲'), + ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), + ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d169}'), ('𝅭', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), ('𝐀', '𝑔'), + ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), + ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), + ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), + ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), + ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), + ('𝟄', '𝟋'), ('𝟎', '𝟿'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), ('𞠀', '𞣄'), + ('\u{1e8d0}', '\u{1e8d6}'), ('𞤀', '\u{1e94a}'), ('𞥐', '𞥙'), + ('𞸀', '𞸃'), ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), + ('𞸧', '𞸧'), ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), + ('𞸻', '𞸻'), ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), + ('𞹋', '𞹋'), ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), + ('𞹗', '𞹗'), ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), + ('𞹟', '𞹟'), ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), + ('𞹬', '𞹲'), ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), + ('𞺀', '𞺉'), ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), + ('𞺫', '𞺻'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), + ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const ID_START: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('Ͱ', 'Í´'), ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), + ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), + ('Õ ', 'ֈ'), ('א', 'ת'), ('ׯ', 'ײ'), ('Ø ', 'ي'), ('Ù®', 'Ù¯'), + ('Ù±', 'ۓ'), ('ە', 'ە'), ('Û¥', 'Û¦'), ('Û®', 'Û¯'), ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), ('ß´', 'ßµ'), ('ߺ', 'ߺ'), ('ࠀ', 'ࠕ'), ('ࠚ', 'ࠚ'), + ('à ¤', 'à ¤'), ('à ¨', 'à ¨'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), + ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), ('ऽ', 'ऽ'), + ('ॐ', 'ॐ'), ('क़', 'ॡ'), ('ॱ', 'ঀ'), ('অ', 'ঌ'), + ('এ', 'ঐ'), ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), + ('শ', 'হ'), ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), ('ড়', 'ঢ়'), + ('য়', 'à§¡'), ('à§°', 'à§±'), ('à§¼', 'à§¼'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), + ('ੲ', 'à©´'), ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), + ('પ', 'ર'), ('લ', 'ળ'), ('વ', 'હ'), ('ઽ', 'ઽ'), + ('ૐ', 'ૐ'), ('à« ', 'à«¡'), ('ૹ', 'ૹ'), ('ଅ', 'ଌ'), + ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), + ('à­±', 'à­±'), ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('ௐ', 'ௐ'), + ('అ', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), + ('à°½', 'à°½'), ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), + ('à³±', 'à³²'), ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), + ('à´½', 'à´½'), ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), + ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('ก', 'ะ'), ('า', 'ำ'), + ('เ', 'ๆ'), ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), + ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), + ('ມ', 'ຣ'), ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), + ('ອ', 'ະ'), ('າ', 'ຳ'), ('ຽ', 'ຽ'), ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), ('ྈ', 'ྌ'), ('က', 'ဪ'), ('ဿ', 'ဿ'), + ('ၐ', 'ၕ'), ('ၚ', 'ၝ'), ('ၡ', 'ၡ'), ('ၥ', 'ၦ'), + ('ၮ', 'ၰ'), ('ၵ', 'ႁ'), ('ႎ', 'ႎ'), ('Ⴀ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჼ', 'ቈ'), + ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), + ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), ('ወ', 'ዖ'), + ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), ('ᎀ', 'ᎏ'), + ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), + ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), + ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), + ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), ('ៗ', 'ៗ'), ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), ('ᢀ', 'ᢨ'), ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), ('ᨀ', 'ᨖ'), ('ᨠ', 'ᩔ'), ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), ('ᭅ', 'ᭋ'), ('ᮃ', 'á® '), ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), ('ᰀ', 'á°£'), ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), + ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('ᳩ', 'ᳬ'), + ('á³®', 'á³±'), ('á³µ', 'á³¶'), ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), + ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), + ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), + ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), + ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('℘', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), + ('ℨ', 'ℨ'), ('K', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'ⳤ'), ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), + ('â´§', 'â´§'), ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), + ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), + ('ⷘ', 'ⷞ'), ('々', '〇'), ('〡', '〩'), ('〱', '〵'), + ('〸', '〼'), ('ぁ', 'ゖ'), ('゛', 'ゟ'), ('ァ', 'ヺ'), + ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), + ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '鿯'), ('ꀀ', 'ꒌ'), + ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ꙮ'), ('ꙿ', 'ꚝ'), ('ꚠ', 'ꛯ'), ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), ('Ꞌ', 'ꞹ'), ('ꟷ', 'ꠁ'), ('ꠃ', 'ꠅ'), + ('ꠇ', 'ꠊ'), ('ꠌ', 'ê ¢'), ('ꡀ', 'ꡳ'), ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), ('ꣽ', 'ꣾ'), ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), ('ꥠ', 'ꥼ'), ('ꦄ', 'ꦲ'), ('ꧏ', 'ꧏ'), + ('ê§ ', 'ꧤ'), ('ꧦ', 'ꧯ'), ('ꧺ', 'ê§¾'), ('ꨀ', 'ꨨ'), + ('ꩀ', 'ꩂ'), ('ꩄ', 'ꩋ'), ('ê© ', 'ê©¶'), ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), ('ꪱ', 'ꪱ'), ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪽ'), + ('ꫀ', 'ꫀ'), ('ꫂ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), + ('ê­°', 'ꯢ'), ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), + ('יִ', 'יִ'), ('ײַ', 'ﬨ'), ('שׁ', 'זּ'), ('טּ', 'לּ'), + ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), + ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), ('A', 'Z'), ('a', 'z'), + ('ヲ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), + ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), + ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), + ('𐅀', '𐅴'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐌀', '𐌟'), + ('𐌭', '𐍊'), ('𐍐', '𐍵'), ('𐎀', '𐎝'), ('𐎠', '𐏃'), + ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐐀', '𐒝'), ('𐒰', '𐓓'), + ('𐓘', '𐓻'), ('𐔀', '𐔧'), ('𐔰', '𐕣'), ('𐘀', '𐜶'), + ('𐝀', '𐝕'), ('𐝠', '𐝧'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), + ('𐠊', '𐠵'), ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐡕'), + ('𐡠', '𐡶'), ('𐢀', '𐢞'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), + ('𐤀', '𐤕'), ('𐤠', '𐤹'), ('𐦀', '𐦷'), ('𐦾', '𐦿'), + ('𐨀', '𐨀'), ('𐨐', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '𐨵'), + ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '𐫤'), + ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), + ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐴀', '𐴣'), + ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '𐽅'), ('𑀃', '𑀷'), + ('𑂃', '𑂯'), ('𑃐', '𑃨'), ('𑄃', '𑄦'), ('𑅄', '𑅄'), + ('𑅐', '𑅲'), ('𑅶', '𑅶'), ('𑆃', '𑆲'), ('𑇁', '𑇄'), + ('𑇚', '𑇚'), ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '𑈫'), + ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), + ('𑊟', '𑊨'), ('𑊰', '𑋞'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('𑌽', '𑌽'), ('𑍐', '𑍐'), ('𑍝', '𑍡'), ('𑐀', '𑐴'), + ('𑑇', '𑑊'), ('𑒀', '𑒯'), ('𑓄', '𑓅'), ('𑓇', '𑓇'), + ('𑖀', '𑖮'), ('𑗘', '𑗛'), ('𑘀', '𑘯'), ('𑙄', '𑙄'), + ('𑚀', '𑚪'), ('𑜀', '𑜚'), ('𑠀', '𑠫'), ('𑢠', '𑣟'), + ('𑣿', '𑣿'), ('𑨀', '𑨀'), ('𑨋', '𑨲'), ('𑨺', '𑨺'), + ('𑩐', '𑩐'), ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('𑪝', '𑪝'), + ('𑫀', '𑫸'), ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), + ('𑱲', '𑲏'), ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), + ('𑵆', '𑵆'), ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶉'), + ('𑶘', '𑶘'), ('𑻠', '𑻲'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), + ('𒒀', '𒕃'), ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), + ('𖩀', '𖩞'), ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭀', '𖭃'), + ('𖭣', '𖭷'), ('𖭽', '𖮏'), ('𖹀', '𖹿'), ('𖼀', '𖽄'), + ('𖽐', '𖽐'), ('𖾓', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '𘟱'), + ('𘠀', '𘫲'), ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), + ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𝐀', '𝑔'), + ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), + ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), + ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), + ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), + ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), + ('𝟄', '𝟋'), ('𞠀', '𞣄'), ('𞤀', '𞥃'), ('𞸀', '𞸃'), + ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), + ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), + ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), + ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), + ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), + ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), + ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), + ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), + ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), + ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const IDEOGRAPHIC: &'static [(char, char)] = &[ + ('〆', '〇'), ('〡', '〩'), ('〸', '〺'), ('㐀', 'ä¶µ'), + ('一', '鿯'), ('豈', 'ï©­'), ('ï©°', '龎'), ('𗀀', '𘟱'), + ('𘠀', '𘫲'), ('𛅰', '𛋻'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), + ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const JOIN_CONTROL: &'static [(char, char)] = &[ + ('\u{200c}', '\u{200d}'), +]; + +pub const LOGICAL_ORDER_EXCEPTION: &'static [(char, char)] = &[ + ('เ', 'ไ'), ('ເ', 'ໄ'), ('ᦵ', 'ᦷ'), ('ᦺ', 'ᦺ'), + ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪹ'), ('ꪻ', 'ꪼ'), +]; + +pub const LOWERCASE: &'static [(char, char)] = &[ + ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), ('ß', 'ö'), + ('ø', 'ÿ'), ('ā', 'ā'), ('ă', 'ă'), ('ą', 'ą'), ('ć', 'ć'), + ('ĉ', 'ĉ'), ('ċ', 'ċ'), ('č', 'č'), ('ď', 'ď'), ('đ', 'đ'), + ('ē', 'ē'), ('ĕ', 'ĕ'), ('ė', 'ė'), ('ę', 'ę'), ('ě', 'ě'), + ('ĝ', 'ĝ'), ('ğ', 'ğ'), ('Ä¡', 'Ä¡'), ('Ä£', 'Ä£'), ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), ('Ä©', 'Ä©'), ('Ä«', 'Ä«'), ('Ä­', 'Ä­'), ('į', 'į'), + ('ı', 'ı'), ('ij', 'ij'), ('ĵ', 'ĵ'), ('Ä·', 'ĸ'), ('ĺ', 'ĺ'), + ('ļ', 'ļ'), ('ľ', 'ľ'), ('ŀ', 'ŀ'), ('ł', 'ł'), ('ń', 'ń'), + ('ņ', 'ņ'), ('ň', 'ʼn'), ('ŋ', 'ŋ'), ('ō', 'ō'), ('ŏ', 'ŏ'), + ('ő', 'ő'), ('œ', 'œ'), ('ŕ', 'ŕ'), ('ŗ', 'ŗ'), ('ř', 'ř'), + ('ś', 'ś'), ('ŝ', 'ŝ'), ('ş', 'ş'), ('Å¡', 'Å¡'), ('Å£', 'Å£'), + ('Å¥', 'Å¥'), ('ŧ', 'ŧ'), ('Å©', 'Å©'), ('Å«', 'Å«'), ('Å­', 'Å­'), + ('ů', 'ů'), ('ű', 'ű'), ('ų', 'ų'), ('ŵ', 'ŵ'), ('Å·', 'Å·'), + ('ź', 'ź'), ('ż', 'ż'), ('ž', 'ƀ'), ('ƃ', 'ƃ'), ('ƅ', 'ƅ'), + ('ƈ', 'ƈ'), ('ƌ', 'ƍ'), ('ƒ', 'ƒ'), ('ƕ', 'ƕ'), ('ƙ', 'ƛ'), + ('ƞ', 'ƞ'), ('Æ¡', 'Æ¡'), ('Æ£', 'Æ£'), ('Æ¥', 'Æ¥'), ('ƨ', 'ƨ'), + ('ƪ', 'Æ«'), ('Æ­', 'Æ­'), ('ư', 'ư'), ('Æ´', 'Æ´'), ('ƶ', 'ƶ'), + ('ƹ', 'ƺ'), ('ƽ', 'Æ¿'), ('dž', 'dž'), ('lj', 'lj'), ('nj', 'nj'), + ('ǎ', 'ǎ'), ('ǐ', 'ǐ'), ('ǒ', 'ǒ'), ('ǔ', 'ǔ'), ('ǖ', 'ǖ'), + ('ǘ', 'ǘ'), ('ǚ', 'ǚ'), ('ǜ', 'ǝ'), ('ǟ', 'ǟ'), ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), ('Ç¥', 'Ç¥'), ('ǧ', 'ǧ'), ('Ç©', 'Ç©'), ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), ('ǯ', 'ǰ'), ('dz', 'dz'), ('ǵ', 'ǵ'), ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), ('ǽ', 'ǽ'), ('Ç¿', 'Ç¿'), ('ȁ', 'ȁ'), ('ȃ', 'ȃ'), + ('ȅ', 'ȅ'), ('ȇ', 'ȇ'), ('ȉ', 'ȉ'), ('ȋ', 'ȋ'), ('ȍ', 'ȍ'), + ('ȏ', 'ȏ'), ('ȑ', 'ȑ'), ('ȓ', 'ȓ'), ('ȕ', 'ȕ'), ('ȗ', 'ȗ'), + ('ș', 'ș'), ('ț', 'ț'), ('ȝ', 'ȝ'), ('ȟ', 'ȟ'), ('È¡', 'È¡'), + ('È£', 'È£'), ('È¥', 'È¥'), ('ȧ', 'ȧ'), ('È©', 'È©'), ('È«', 'È«'), + ('È­', 'È­'), ('ȯ', 'ȯ'), ('ȱ', 'ȱ'), ('ȳ', 'ȹ'), ('ȼ', 'ȼ'), + ('È¿', 'ɀ'), ('ɂ', 'ɂ'), ('ɇ', 'ɇ'), ('ɉ', 'ɉ'), ('ɋ', 'ɋ'), + ('ɍ', 'ɍ'), ('ɏ', 'ʓ'), ('ʕ', 'ʸ'), ('ˀ', 'ˁ'), ('Ë ', 'ˤ'), + ('\u{345}', '\u{345}'), ('ͱ', 'ͱ'), ('ͳ', 'ͳ'), ('Í·', 'Í·'), + ('ͺ', 'ͽ'), ('ΐ', 'ΐ'), ('ά', 'ώ'), ('ϐ', 'ϑ'), ('ϕ', 'ϗ'), + ('ϙ', 'ϙ'), ('ϛ', 'ϛ'), ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), ('Ï¡', 'Ï¡'), + ('Ï£', 'Ï£'), ('Ï¥', 'Ï¥'), ('ϧ', 'ϧ'), ('Ï©', 'Ï©'), ('Ï«', 'Ï«'), + ('Ï­', 'Ï­'), ('ϯ', 'ϳ'), ('ϵ', 'ϵ'), ('ϸ', 'ϸ'), ('Ï»', 'ϼ'), + ('а', 'џ'), ('Ñ¡', 'Ñ¡'), ('Ñ£', 'Ñ£'), ('Ñ¥', 'Ñ¥'), ('ѧ', 'ѧ'), + ('Ñ©', 'Ñ©'), ('Ñ«', 'Ñ«'), ('Ñ­', 'Ñ­'), ('ѯ', 'ѯ'), ('ѱ', 'ѱ'), + ('ѳ', 'ѳ'), ('ѵ', 'ѵ'), ('Ñ·', 'Ñ·'), ('ѹ', 'ѹ'), ('Ñ»', 'Ñ»'), + ('ѽ', 'ѽ'), ('Ñ¿', 'Ñ¿'), ('ҁ', 'ҁ'), ('ҋ', 'ҋ'), ('ҍ', 'ҍ'), + ('ҏ', 'ҏ'), ('ґ', 'ґ'), ('ғ', 'ғ'), ('ҕ', 'ҕ'), ('җ', 'җ'), + ('ҙ', 'ҙ'), ('қ', 'қ'), ('ҝ', 'ҝ'), ('ҟ', 'ҟ'), ('Ò¡', 'Ò¡'), + ('Ò£', 'Ò£'), ('Ò¥', 'Ò¥'), ('Ò§', 'Ò§'), ('Ò©', 'Ò©'), ('Ò«', 'Ò«'), + ('Ò­', 'Ò­'), ('Ò¯', 'Ò¯'), ('Ò±', 'Ò±'), ('Ò³', 'Ò³'), ('Òµ', 'Òµ'), + ('Ò·', 'Ò·'), ('Ò¹', 'Ò¹'), ('Ò»', 'Ò»'), ('Ò½', 'Ò½'), ('Ò¿', 'Ò¿'), + ('ӂ', 'ӂ'), ('ӄ', 'ӄ'), ('ӆ', 'ӆ'), ('ӈ', 'ӈ'), ('ӊ', 'ӊ'), + ('ӌ', 'ӌ'), ('ӎ', 'ӏ'), ('ӑ', 'ӑ'), ('ӓ', 'ӓ'), ('ӕ', 'ӕ'), + ('ӗ', 'ӗ'), ('ә', 'ә'), ('ӛ', 'ӛ'), ('ӝ', 'ӝ'), ('ӟ', 'ӟ'), + ('Ó¡', 'Ó¡'), ('Ó£', 'Ó£'), ('Ó¥', 'Ó¥'), ('Ó§', 'Ó§'), ('Ó©', 'Ó©'), + ('Ó«', 'Ó«'), ('Ó­', 'Ó­'), ('Ó¯', 'Ó¯'), ('Ó±', 'Ó±'), ('Ó³', 'Ó³'), + ('Óµ', 'Óµ'), ('Ó·', 'Ó·'), ('Ó¹', 'Ó¹'), ('Ó»', 'Ó»'), ('Ó½', 'Ó½'), + ('Ó¿', 'Ó¿'), ('ԁ', 'ԁ'), ('ԃ', 'ԃ'), ('ԅ', 'ԅ'), ('ԇ', 'ԇ'), + ('ԉ', 'ԉ'), ('ԋ', 'ԋ'), ('ԍ', 'ԍ'), ('ԏ', 'ԏ'), ('ԑ', 'ԑ'), + ('ԓ', 'ԓ'), ('ԕ', 'ԕ'), ('ԗ', 'ԗ'), ('ԙ', 'ԙ'), ('ԛ', 'ԛ'), + ('ԝ', 'ԝ'), ('ԟ', 'ԟ'), ('Ô¡', 'Ô¡'), ('Ô£', 'Ô£'), ('Ô¥', 'Ô¥'), + ('Ô§', 'Ô§'), ('Ô©', 'Ô©'), ('Ô«', 'Ô«'), ('Ô­', 'Ô­'), ('Ô¯', 'Ô¯'), + ('Õ ', 'ֈ'), ('ა', 'ჺ'), ('ჽ', 'ჿ'), ('ᏸ', 'ᏽ'), + ('ᲀ', 'ᲈ'), ('ᴀ', 'á¶¿'), ('ḁ', 'ḁ'), ('ḃ', 'ḃ'), + ('ḅ', 'ḅ'), ('ḇ', 'ḇ'), ('ḉ', 'ḉ'), ('ḋ', 'ḋ'), + ('ḍ', 'ḍ'), ('ḏ', 'ḏ'), ('ḑ', 'ḑ'), ('ḓ', 'ḓ'), + ('ḕ', 'ḕ'), ('ḗ', 'ḗ'), ('ḙ', 'ḙ'), ('ḛ', 'ḛ'), + ('ḝ', 'ḝ'), ('ḟ', 'ḟ'), ('ḡ', 'ḡ'), ('ḣ', 'ḣ'), + ('ḥ', 'ḥ'), ('ḧ', 'ḧ'), ('ḩ', 'ḩ'), ('ḫ', 'ḫ'), + ('ḭ', 'ḭ'), ('ḯ', 'ḯ'), ('ḱ', 'ḱ'), ('ḳ', 'ḳ'), + ('ḵ', 'ḵ'), ('ḷ', 'ḷ'), ('ḹ', 'ḹ'), ('ḻ', 'ḻ'), + ('ḽ', 'ḽ'), ('ḿ', 'ḿ'), ('ṁ', 'ṁ'), ('ṃ', 'ṃ'), + ('ṅ', 'ṅ'), ('ṇ', 'ṇ'), ('ṉ', 'ṉ'), ('ṋ', 'ṋ'), + ('ṍ', 'ṍ'), ('ṏ', 'ṏ'), ('ṑ', 'ṑ'), ('ṓ', 'ṓ'), + ('ṕ', 'ṕ'), ('ṗ', 'ṗ'), ('ṙ', 'ṙ'), ('ṛ', 'ṛ'), + ('ṝ', 'ṝ'), ('ṟ', 'ṟ'), ('ṡ', 'ṡ'), ('á¹£', 'á¹£'), + ('á¹¥', 'á¹¥'), ('á¹§', 'á¹§'), ('ṩ', 'ṩ'), ('ṫ', 'ṫ'), + ('á¹­', 'á¹­'), ('ṯ', 'ṯ'), ('á¹±', 'á¹±'), ('á¹³', 'á¹³'), + ('á¹µ', 'á¹µ'), ('á¹·', 'á¹·'), ('á¹¹', 'á¹¹'), ('á¹»', 'á¹»'), + ('á¹½', 'á¹½'), ('ṿ', 'ṿ'), ('ẁ', 'ẁ'), ('ẃ', 'ẃ'), + ('ẅ', 'ẅ'), ('ẇ', 'ẇ'), ('ẉ', 'ẉ'), ('ẋ', 'ẋ'), + ('ẍ', 'ẍ'), ('ẏ', 'ẏ'), ('ẑ', 'ẑ'), ('ẓ', 'ẓ'), + ('ẕ', 'ẝ'), ('ẟ', 'ẟ'), ('ạ', 'ạ'), ('ả', 'ả'), + ('ấ', 'ấ'), ('ầ', 'ầ'), ('ẩ', 'ẩ'), ('ẫ', 'ẫ'), + ('ậ', 'ậ'), ('ắ', 'ắ'), ('ằ', 'ằ'), ('ẳ', 'ẳ'), + ('ẵ', 'ẵ'), ('ặ', 'ặ'), ('ẹ', 'ẹ'), ('ẻ', 'ẻ'), + ('ẽ', 'ẽ'), ('ế', 'ế'), ('ề', 'ề'), ('ể', 'ể'), + ('ễ', 'ễ'), ('ệ', 'ệ'), ('ỉ', 'ỉ'), ('ị', 'ị'), + ('ọ', 'ọ'), ('ỏ', 'ỏ'), ('ố', 'ố'), ('ồ', 'ồ'), + ('ổ', 'ổ'), ('ỗ', 'ỗ'), ('ộ', 'ộ'), ('ớ', 'ớ'), + ('ờ', 'ờ'), ('ở', 'ở'), ('ỡ', 'ỡ'), ('ợ', 'ợ'), + ('ụ', 'ụ'), ('á»§', 'á»§'), ('ứ', 'ứ'), ('ừ', 'ừ'), + ('á»­', 'á»­'), ('ữ', 'ữ'), ('á»±', 'á»±'), ('ỳ', 'ỳ'), + ('ỵ', 'ỵ'), ('á»·', 'á»·'), ('ỹ', 'ỹ'), ('á»»', 'á»»'), + ('ỽ', 'ỽ'), ('ỿ', 'ἇ'), ('ἐ', 'ἕ'), ('á¼ ', 'á¼§'), + ('á¼°', 'á¼·'), ('ὀ', 'ὅ'), ('ὐ', 'ὗ'), ('á½ ', 'á½§'), + ('á½°', 'á½½'), ('ᾀ', 'ᾇ'), ('ᾐ', 'ᾗ'), ('á¾ ', 'á¾§'), + ('á¾°', 'á¾´'), ('á¾¶', 'á¾·'), ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), + ('ῆ', 'ῇ'), ('ῐ', 'ΐ'), ('ῖ', 'ῗ'), ('á¿ ', 'á¿§'), + ('ῲ', 'á¿´'), ('á¿¶', 'á¿·'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), + ('ₐ', 'ₜ'), ('ℊ', 'ℊ'), ('ℎ', 'ℏ'), ('ℓ', 'ℓ'), + ('ℯ', 'ℯ'), ('ℴ', 'ℴ'), ('ℹ', 'ℹ'), ('ℼ', 'ℽ'), + ('ⅆ', 'ⅉ'), ('ⅎ', 'ⅎ'), ('ⅰ', 'ⅿ'), ('ↄ', 'ↄ'), + ('ⓐ', 'ⓩ'), ('â°°', 'ⱞ'), ('ⱡ', 'ⱡ'), ('â±¥', 'ⱦ'), + ('ⱨ', 'ⱨ'), ('ⱪ', 'ⱪ'), ('ⱬ', 'ⱬ'), ('â±±', 'â±±'), + ('â±³', 'â±´'), ('â±¶', 'â±½'), ('ⲁ', 'ⲁ'), ('ⲃ', 'ⲃ'), + ('ⲅ', 'ⲅ'), ('ⲇ', 'ⲇ'), ('ⲉ', 'ⲉ'), ('ⲋ', 'ⲋ'), + ('ⲍ', 'ⲍ'), ('ⲏ', 'ⲏ'), ('ⲑ', 'ⲑ'), ('ⲓ', 'ⲓ'), + ('ⲕ', 'ⲕ'), ('ⲗ', 'ⲗ'), ('ⲙ', 'ⲙ'), ('ⲛ', 'ⲛ'), + ('ⲝ', 'ⲝ'), ('ⲟ', 'ⲟ'), ('ⲡ', 'ⲡ'), ('â²£', 'â²£'), + ('â²¥', 'â²¥'), ('â²§', 'â²§'), ('ⲩ', 'ⲩ'), ('ⲫ', 'ⲫ'), + ('â²­', 'â²­'), ('ⲯ', 'ⲯ'), ('â²±', 'â²±'), ('â²³', 'â²³'), + ('â²µ', 'â²µ'), ('â²·', 'â²·'), ('â²¹', 'â²¹'), ('â²»', 'â²»'), + ('â²½', 'â²½'), ('ⲿ', 'ⲿ'), ('ⳁ', 'ⳁ'), ('ⳃ', 'ⳃ'), + ('ⳅ', 'ⳅ'), ('ⳇ', 'ⳇ'), ('ⳉ', 'ⳉ'), ('ⳋ', 'ⳋ'), + ('ⳍ', 'ⳍ'), ('ⳏ', 'ⳏ'), ('ⳑ', 'ⳑ'), ('ⳓ', 'ⳓ'), + ('ⳕ', 'ⳕ'), ('ⳗ', 'ⳗ'), ('ⳙ', 'ⳙ'), ('ⳛ', 'ⳛ'), + ('ⳝ', 'ⳝ'), ('ⳟ', 'ⳟ'), ('ⳡ', 'ⳡ'), ('â³£', 'ⳤ'), + ('ⳬ', 'ⳬ'), ('â³®', 'â³®'), ('â³³', 'â³³'), ('ⴀ', 'â´¥'), + ('â´§', 'â´§'), ('â´­', 'â´­'), ('ꙁ', 'ꙁ'), ('ꙃ', 'ꙃ'), + ('ꙅ', 'ꙅ'), ('ꙇ', 'ꙇ'), ('ꙉ', 'ꙉ'), ('ꙋ', 'ꙋ'), + ('ꙍ', 'ꙍ'), ('ꙏ', 'ꙏ'), ('ꙑ', 'ꙑ'), ('ꙓ', 'ꙓ'), + ('ꙕ', 'ꙕ'), ('ꙗ', 'ꙗ'), ('ꙙ', 'ꙙ'), ('ꙛ', 'ꙛ'), + ('ꙝ', 'ꙝ'), ('ꙟ', 'ꙟ'), ('ꙡ', 'ꙡ'), ('ꙣ', 'ꙣ'), + ('ꙥ', 'ꙥ'), ('ꙧ', 'ꙧ'), ('ꙩ', 'ꙩ'), ('ꙫ', 'ꙫ'), + ('ꙭ', 'ꙭ'), ('ꚁ', 'ꚁ'), ('ꚃ', 'ꚃ'), ('ꚅ', 'ꚅ'), + ('ꚇ', 'ꚇ'), ('ꚉ', 'ꚉ'), ('ꚋ', 'ꚋ'), ('ꚍ', 'ꚍ'), + ('ꚏ', 'ꚏ'), ('ꚑ', 'ꚑ'), ('ꚓ', 'ꚓ'), ('ꚕ', 'ꚕ'), + ('ꚗ', 'ꚗ'), ('ꚙ', 'ꚙ'), ('ꚛ', 'ꚝ'), ('ꜣ', 'ꜣ'), + ('ꜥ', 'ꜥ'), ('ꜧ', 'ꜧ'), ('ꜩ', 'ꜩ'), ('ꜫ', 'ꜫ'), + ('ꜭ', 'ꜭ'), ('ꜯ', 'ꜱ'), ('ꜳ', 'ꜳ'), ('ꜵ', 'ꜵ'), + ('ꜷ', 'ꜷ'), ('ꜹ', 'ꜹ'), ('ꜻ', 'ꜻ'), ('ꜽ', 'ꜽ'), + ('ꜿ', 'ꜿ'), ('ꝁ', 'ꝁ'), ('ꝃ', 'ꝃ'), ('ꝅ', 'ꝅ'), + ('ꝇ', 'ꝇ'), ('ꝉ', 'ꝉ'), ('ꝋ', 'ꝋ'), ('ꝍ', 'ꝍ'), + ('ꝏ', 'ꝏ'), ('ꝑ', 'ꝑ'), ('ꝓ', 'ꝓ'), ('ꝕ', 'ꝕ'), + ('ꝗ', 'ꝗ'), ('ꝙ', 'ꝙ'), ('ꝛ', 'ꝛ'), ('ꝝ', 'ꝝ'), + ('ꝟ', 'ꝟ'), ('ꝡ', 'ꝡ'), ('ꝣ', 'ꝣ'), ('ꝥ', 'ꝥ'), + ('ꝧ', 'ꝧ'), ('ꝩ', 'ꝩ'), ('ꝫ', 'ꝫ'), ('ꝭ', 'ꝭ'), + ('ꝯ', 'ꝸ'), ('ꝺ', 'ꝺ'), ('ꝼ', 'ꝼ'), ('ꝿ', 'ꝿ'), + ('ꞁ', 'ꞁ'), ('ꞃ', 'ꞃ'), ('ꞅ', 'ꞅ'), ('ꞇ', 'ꞇ'), + ('ꞌ', 'ꞌ'), ('ꞎ', 'ꞎ'), ('ꞑ', 'ꞑ'), ('ꞓ', 'ꞕ'), + ('ꞗ', 'ꞗ'), ('ꞙ', 'ꞙ'), ('ꞛ', 'ꞛ'), ('ꞝ', 'ꞝ'), + ('ꞟ', 'ꞟ'), ('ꞡ', 'ꞡ'), ('ꞣ', 'ꞣ'), ('ꞥ', 'ꞥ'), + ('ꞧ', 'ꞧ'), ('ꞩ', 'ꞩ'), ('ꞯ', 'ꞯ'), ('ꞵ', 'ꞵ'), + ('ꞷ', 'ꞷ'), ('ꞹ', 'ꞹ'), ('ꟸ', 'ꟺ'), ('ꬰ', 'ꭚ'), + ('ꭜ', 'ê­¥'), ('ê­°', 'ꮿ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), + ('a', 'z'), ('𐐨', '𐑏'), ('𐓘', '𐓻'), ('𐳀', '𐳲'), + ('𑣀', '𑣟'), ('𖹠', '𖹿'), ('𝐚', '𝐳'), ('𝑎', '𝑔'), + ('𝑖', '𝑧'), ('𝒂', '𝒛'), ('𝒶', '𝒹'), ('𝒻', '𝒻'), + ('𝒽', '𝓃'), ('𝓅', '𝓏'), ('𝓪', '𝔃'), ('𝔞', '𝔷'), + ('𝕒', '𝕫'), ('𝖆', '𝖟'), ('𝖺', '𝗓'), ('𝗮', '𝘇'), + ('𝘢', '𝘻'), ('𝙖', '𝙯'), ('𝚊', '𝚥'), ('𝛂', '𝛚'), + ('𝛜', '𝛡'), ('𝛼', '𝜔'), ('𝜖', '𝜛'), ('𝜶', '𝝎'), + ('𝝐', '𝝕'), ('𝝰', '𝞈'), ('𝞊', '𝞏'), ('𝞪', '𝟂'), + ('𝟄', '𝟉'), ('𝟋', '𝟋'), ('𞤢', '𞥃'), +]; + +pub const MATH: &'static [(char, char)] = &[ + ('+', '+'), ('<', '>'), ('^', '^'), ('|', '|'), ('~', '~'), ('¬', '¬'), + ('±', '±'), ('×', '×'), ('÷', '÷'), ('ϐ', 'ϒ'), ('ϕ', 'ϕ'), + ('ϰ', 'ϱ'), ('Ï´', '϶'), ('؆', '؈'), ('‖', '‖'), ('′', '‴'), + ('⁀', '⁀'), ('⁄', '⁄'), ('⁒', '⁒'), ('\u{2061}', '\u{2064}'), + ('⁺', '⁾'), ('₊', '₎'), ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), ('\u{20e5}', '\u{20e6}'), + ('\u{20eb}', '\u{20ef}'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('℘', 'ℝ'), ('ℤ', 'ℤ'), ('ℨ', '℩'), + ('ℬ', 'ℭ'), ('ℯ', 'ℱ'), ('ℳ', 'ℸ'), ('ℼ', 'ⅉ'), + ('⅋', '⅋'), ('←', '↧'), ('↩', '↮'), ('↰', '↱'), + ('↶', '↷'), ('↼', '⇛'), ('⇝', '⇝'), ('⇤', '⇥'), + ('⇴', '⋿'), ('⌈', '⌋'), ('⌠', '⌡'), ('⍼', '⍼'), + ('⎛', '⎵'), ('⎷', '⎷'), ('⏐', '⏐'), ('⏜', '⏢'), + ('■', '□'), ('▮', '▷'), ('▼', '◁'), ('◆', '◇'), + ('◊', '○'), ('●', '◓'), ('◢', '◢'), ('◤', '◤'), + ('◧', '◬'), ('◸', '◿'), ('★', '☆'), ('♀', '♀'), + ('♂', '♂'), ('♠', '♣'), ('♭', '♯'), ('⟀', '⟿'), + ('⤀', 'â«¿'), ('⬰', '⭄'), ('⭇', '⭌'), ('﬩', '﬩'), + ('﹡', '﹦'), ('﹨', '﹨'), ('+', '+'), ('<', '>'), + ('ï¼¼', 'ï¼¼'), ('ï¼¾', 'ï¼¾'), ('|', '|'), ('~', '~'), + ('ï¿¢', 'ï¿¢'), ('ï¿©', '↓'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝟋'), ('𝟎', '𝟿'), ('𞸀', '𞸃'), + ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), + ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), + ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), + ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), + ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), + ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), + ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), + ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), + ('𞻰', '𞻱'), +]; + +pub const NONCHARACTER_CODE_POINT: &'static [(char, char)] = &[ + ('\u{fdd0}', '\u{fdef}'), ('\u{fffe}', '\u{ffff}'), + ('\u{1fffe}', '\u{1ffff}'), ('\u{2fffe}', '\u{2ffff}'), + ('\u{3fffe}', '\u{3ffff}'), ('\u{4fffe}', '\u{4ffff}'), + ('\u{5fffe}', '\u{5ffff}'), ('\u{6fffe}', '\u{6ffff}'), + ('\u{7fffe}', '\u{7ffff}'), ('\u{8fffe}', '\u{8ffff}'), + ('\u{9fffe}', '\u{9ffff}'), ('\u{afffe}', '\u{affff}'), + ('\u{bfffe}', '\u{bffff}'), ('\u{cfffe}', '\u{cffff}'), + ('\u{dfffe}', '\u{dffff}'), ('\u{efffe}', '\u{effff}'), + ('\u{ffffe}', '\u{fffff}'), ('\u{10fffe}', '\u{10ffff}'), +]; + +pub const OTHER_ALPHABETIC: &'static [(char, char)] = &[ + ('\u{345}', '\u{345}'), ('\u{5b0}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), + ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), + ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{657}'), ('\u{659}', '\u{65f}'), + ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dc}'), ('\u{6e1}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), ('\u{6ed}', '\u{6ed}'), ('\u{711}', '\u{711}'), + ('\u{730}', '\u{73f}'), ('\u{7a6}', '\u{7b0}'), ('\u{816}', '\u{817}'), + ('\u{81b}', '\u{823}'), ('\u{825}', '\u{827}'), ('\u{829}', '\u{82c}'), + ('\u{8d4}', '\u{8df}'), ('\u{8e3}', '\u{8e9}'), ('\u{8f0}', 'ः'), + ('\u{93a}', 'ऻ'), ('ा', 'ौ'), ('ॎ', 'ॏ'), ('\u{955}', '\u{957}'), + ('\u{962}', '\u{963}'), ('\u{981}', 'ঃ'), ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), ('ো', 'ৌ'), ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), ('\u{a01}', 'ਃ'), ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4c}'), ('\u{a51}', '\u{a51}'), + ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'), ('\u{a81}', 'ઃ'), + ('ા', '\u{ac5}'), ('\u{ac7}', 'ૉ'), ('ો', 'ૌ'), + ('\u{ae2}', '\u{ae3}'), ('\u{afa}', '\u{afc}'), ('\u{b01}', 'ଃ'), + ('\u{b3e}', '\u{b44}'), ('େ', 'ୈ'), ('ୋ', 'ୌ'), + ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'), + ('\u{bbe}', 'ூ'), ('ெ', 'ை'), ('ொ', 'ௌ'), ('\u{bd7}', '\u{bd7}'), + ('\u{c00}', 'ః'), ('\u{c3e}', 'ౄ'), ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4c}'), ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), + ('\u{c81}', 'ಃ'), ('ಾ', 'ೄ'), ('\u{cc6}', 'ೈ'), ('ೊ', '\u{ccc}'), + ('\u{cd5}', '\u{cd6}'), ('\u{ce2}', '\u{ce3}'), ('\u{d00}', 'ഃ'), + ('\u{d3e}', '\u{d44}'), ('െ', 'ൈ'), ('ൊ', 'ൌ'), + ('\u{d57}', '\u{d57}'), ('\u{d62}', '\u{d63}'), ('ං', 'ඃ'), + ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), + ('à·²', 'à·³'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), + ('\u{e4d}', '\u{e4d}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), ('\u{ecd}', '\u{ecd}'), ('\u{f71}', '\u{f81}'), + ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('ါ', '\u{1036}'), + ('း', 'း'), ('ျ', '\u{103e}'), ('ၖ', '\u{1059}'), + ('\u{105e}', '\u{1060}'), ('ၢ', 'ၢ'), ('ၧ', 'ၨ'), + ('\u{1071}', '\u{1074}'), ('\u{1082}', '\u{1086}'), ('ႜ', '\u{109d}'), + ('\u{135f}', '\u{135f}'), ('\u{1712}', '\u{1713}'), + ('\u{1732}', '\u{1733}'), ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), ('ា', 'ៈ'), ('\u{1885}', '\u{1886}'), + ('\u{18a9}', '\u{18a9}'), ('\u{1920}', 'ᤫ'), ('ᤰ', 'ᤸ'), + ('\u{1a17}', '\u{1a1b}'), ('ᩕ', '\u{1a5e}'), ('á©¡', '\u{1a74}'), + ('\u{1b00}', 'ᬄ'), ('ᬵ', 'ᭃ'), ('\u{1b80}', 'ᮂ'), + ('ᮡ', '\u{1ba9}'), ('\u{1bac}', '\u{1bad}'), ('ᯧ', '\u{1bf1}'), + ('á°¤', 'á°µ'), ('á³²', 'á³³'), ('\u{1de7}', '\u{1df4}'), ('Ⓐ', 'ⓩ'), + ('\u{2de0}', '\u{2dff}'), ('\u{a674}', '\u{a67b}'), + ('\u{a69e}', '\u{a69f}'), ('ê £', 'ê §'), ('ꢀ', 'ꢁ'), ('ꢴ', 'ꣃ'), + ('\u{a8c5}', '\u{a8c5}'), ('\u{a926}', '\u{a92a}'), ('\u{a947}', 'ꥒ'), + ('\u{a980}', 'ꦃ'), ('ꦴ', 'ꦿ'), ('\u{aa29}', '\u{aa36}'), + ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', 'ꩍ'), ('\u{aab0}', '\u{aab0}'), + ('\u{aab2}', '\u{aab4}'), ('\u{aab7}', '\u{aab8}'), + ('\u{aabe}', '\u{aabe}'), ('ê««', 'ꫯ'), ('ꫵ', 'ꫵ'), ('ꯣ', 'ꯪ'), + ('\u{fb1e}', '\u{fb1e}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10d24}', '\u{10d27}'), ('𑀀', '𑀂'), + ('\u{11038}', '\u{11045}'), ('𑂂', '𑂂'), ('𑂰', '𑂸'), + ('\u{11100}', '\u{11102}'), ('\u{11127}', '\u{11132}'), ('𑅅', '𑅆'), + ('\u{11180}', '𑆂'), ('𑆳', '𑆿'), ('𑈬', '\u{11234}'), + ('\u{11237}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), + ('\u{112df}', '\u{112e8}'), ('\u{11300}', '𑌃'), ('\u{1133e}', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍌'), ('\u{11357}', '\u{11357}'), + ('𑍢', '𑍣'), ('𑐵', '𑑁'), ('\u{11443}', '𑑅'), + ('\u{114b0}', '𑓁'), ('\u{115af}', '\u{115b5}'), ('𑖸', '𑖾'), + ('\u{115dc}', '\u{115dd}'), ('𑘰', '𑘾'), ('\u{11640}', '\u{11640}'), + ('\u{116ab}', '\u{116b5}'), ('\u{1171d}', '\u{1172a}'), ('𑠬', '𑠸'), + ('\u{11a01}', '\u{11a0a}'), ('\u{11a35}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), ('\u{11a51}', '\u{11a5b}'), + ('\u{11a8a}', '𑪗'), ('𑰯', '\u{11c36}'), ('\u{11c38}', '𑰾'), + ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d41}'), + ('\u{11d43}', '\u{11d43}'), ('\u{11d47}', '\u{11d47}'), ('𑶊', '𑶎'), + ('\u{11d90}', '\u{11d91}'), ('𑶓', '𑶖'), ('\u{11ef3}', '𑻶'), + ('\u{16b30}', '\u{16b36}'), ('𖽑', '𖽾'), ('\u{1bc9e}', '\u{1bc9e}'), + ('\u{1e000}', '\u{1e006}'), ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), ('\u{1e023}', '\u{1e024}'), + ('\u{1e026}', '\u{1e02a}'), ('\u{1e947}', '\u{1e947}'), ('🄰', '🅉'), + ('🅐', '🅩'), ('🅰', '🆉'), +]; + +pub const OTHER_DEFAULT_IGNORABLE_CODE_POINT: &'static [(char, char)] = &[ + ('\u{34f}', '\u{34f}'), ('ᅟ', 'ᅠ'), ('\u{17b4}', '\u{17b5}'), + ('\u{2065}', '\u{2065}'), ('ㅤ', 'ㅤ'), ('ï¾ ', 'ï¾ '), + ('\u{fff0}', '\u{fff8}'), ('\u{e0000}', '\u{e0000}'), + ('\u{e0002}', '\u{e001f}'), ('\u{e0080}', '\u{e00ff}'), + ('\u{e01f0}', '\u{e0fff}'), +]; + +pub const OTHER_GRAPHEME_EXTEND: &'static [(char, char)] = &[ + ('\u{9be}', '\u{9be}'), ('\u{9d7}', '\u{9d7}'), ('\u{b3e}', '\u{b3e}'), + ('\u{b57}', '\u{b57}'), ('\u{bbe}', '\u{bbe}'), ('\u{bd7}', '\u{bd7}'), + ('\u{cc2}', '\u{cc2}'), ('\u{cd5}', '\u{cd6}'), ('\u{d3e}', '\u{d3e}'), + ('\u{d57}', '\u{d57}'), ('\u{dcf}', '\u{dcf}'), ('\u{ddf}', '\u{ddf}'), + ('\u{200c}', '\u{200c}'), ('\u{302e}', '\u{302f}'), + ('\u{ff9e}', '\u{ff9f}'), ('\u{1133e}', '\u{1133e}'), + ('\u{11357}', '\u{11357}'), ('\u{114b0}', '\u{114b0}'), + ('\u{114bd}', '\u{114bd}'), ('\u{115af}', '\u{115af}'), + ('\u{1d165}', '\u{1d165}'), ('\u{1d16e}', '\u{1d172}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const OTHER_ID_CONTINUE: &'static [(char, char)] = &[ + ('·', '·'), ('·', '·'), ('፩', '፱'), ('᧚', '᧚'), +]; + +pub const OTHER_ID_START: &'static [(char, char)] = &[ + ('\u{1885}', '\u{1886}'), ('℘', '℘'), ('℮', '℮'), ('゛', '゜'), +]; + +pub const OTHER_LOWERCASE: &'static [(char, char)] = &[ + ('ª', 'ª'), ('º', 'º'), ('ʰ', 'ʸ'), ('ˀ', 'ˁ'), ('Ë ', 'ˤ'), + ('\u{345}', '\u{345}'), ('ͺ', 'ͺ'), ('á´¬', 'ᵪ'), ('ᵸ', 'ᵸ'), + ('ᶛ', 'á¶¿'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), + ('ⅰ', 'ⅿ'), ('ⓐ', 'ⓩ'), ('â±¼', 'â±½'), ('ꚜ', 'ꚝ'), + ('ꝰ', 'ꝰ'), ('ꟸ', 'ꟹ'), ('ꭜ', 'ꭟ'), +]; + +pub const OTHER_MATH: &'static [(char, char)] = &[ + ('^', '^'), ('ϐ', 'ϒ'), ('ϕ', 'ϕ'), ('ϰ', 'ϱ'), ('Ï´', 'ϵ'), + ('‖', '‖'), ('′', '‴'), ('⁀', '⁀'), ('\u{2061}', '\u{2064}'), + ('⁽', '⁾'), ('₍', '₎'), ('\u{20d0}', '\u{20dc}'), + ('\u{20e1}', '\u{20e1}'), ('\u{20e5}', '\u{20e6}'), + ('\u{20eb}', '\u{20ef}'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), ('ℤ', 'ℤ'), ('ℨ', '℩'), + ('ℬ', 'ℭ'), ('ℯ', 'ℱ'), ('ℳ', 'ℸ'), ('ℼ', 'ℿ'), + ('ⅅ', 'ⅉ'), ('↕', '↙'), ('↜', '↟'), ('↡', '↢'), + ('↤', '↥'), ('↧', '↧'), ('↩', '↭'), ('↰', '↱'), + ('↶', '↷'), ('↼', '⇍'), ('⇐', '⇑'), ('⇓', '⇓'), + ('⇕', '⇛'), ('⇝', '⇝'), ('⇤', '⇥'), ('⌈', '⌋'), + ('⎴', '⎵'), ('⎷', '⎷'), ('⏐', '⏐'), ('⏢', '⏢'), + ('■', '□'), ('▮', '▶'), ('▼', '◀'), ('◆', '◇'), + ('◊', '○'), ('●', '◓'), ('◢', '◢'), ('◤', '◤'), + ('◧', '◬'), ('★', '☆'), ('♀', '♀'), ('♂', '♂'), + ('♠', '♣'), ('♭', '♮'), ('⟅', '⟆'), ('⟦', '⟯'), + ('⦃', '⦘'), ('⧘', '⧛'), ('â§¼', 'â§½'), ('﹡', '﹡'), + ('ï¹£', 'ï¹£'), ('﹨', '﹨'), ('ï¼¼', 'ï¼¼'), ('ï¼¾', 'ï¼¾'), + ('𝐀', '𝑔'), ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), + ('𝒥', '𝒦'), ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), + ('𝒽', '𝓃'), ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), + ('𝔖', '𝔜'), ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), + ('𝕆', '𝕆'), ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), + ('𝛂', '𝛚'), ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), + ('𝜶', '𝝎'), ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), + ('𝞪', '𝟂'), ('𝟄', '𝟋'), ('𝟎', '𝟿'), ('𞸀', '𞸃'), + ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), + ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), + ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), + ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), + ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), + ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), + ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), + ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), +]; + +pub const OTHER_UPPERCASE: &'static [(char, char)] = &[ + ('Ⅰ', 'Ⅿ'), ('Ⓐ', 'Ⓩ'), ('🄰', '🅉'), ('🅐', '🅩'), + ('🅰', '🆉'), +]; + +pub const PATTERN_SYNTAX: &'static [(char, char)] = &[ + ('!', '/'), (':', '@'), ('[', '^'), ('`', '`'), ('{', '~'), ('¡', '§'), + ('©', '©'), ('«', '¬'), ('®', '®'), ('°', '±'), ('¶', '¶'), + ('»', '»'), ('¿', '¿'), ('×', '×'), ('÷', '÷'), ('‐', '‧'), + ('‰', '‾'), ('⁁', '⁓'), ('⁕', '⁞'), ('←', '\u{245f}'), + ('─', '❵'), ('➔', '\u{2bff}'), ('⸀', '\u{2e7f}'), ('、', '〃'), + ('〈', '〠'), ('〰', '〰'), ('ï´¾', 'ï´¿'), ('﹅', '﹆'), +]; + +pub const PATTERN_WHITE_SPACE: &'static [(char, char)] = &[ + ('\t', '\r'), (' ', ' '), ('\u{85}', '\u{85}'), ('\u{200e}', '\u{200f}'), + ('\u{2028}', '\u{2029}'), +]; + +pub const PREPENDED_CONCATENATION_MARK: &'static [(char, char)] = &[ + ('\u{600}', '\u{605}'), ('\u{6dd}', '\u{6dd}'), ('\u{70f}', '\u{70f}'), + ('\u{8e2}', '\u{8e2}'), ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), +]; + +pub const QUOTATION_MARK: &'static [(char, char)] = &[ + ('\"', '\"'), ('\'', '\''), ('«', '«'), ('»', '»'), ('‘', '‟'), + ('‹', '›'), ('⹂', '⹂'), ('「', '』'), ('〝', '〟'), + ('﹁', '﹄'), ('"', '"'), (''', '''), ('ï½¢', 'ï½£'), +]; + +pub const RADICAL: &'static [(char, char)] = &[ + ('⺀', '⺙'), ('⺛', '⻳'), ('⼀', '⿕'), +]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[ + ('🇦', '🇿'), +]; + +pub const SENTENCE_TERMINAL: &'static [(char, char)] = &[ + ('!', '!'), ('.', '.'), ('?', '?'), ('։', '։'), ('؞', '؟'), + ('۔', '۔'), ('܀', '܂'), ('ß¹', 'ß¹'), ('à ·', 'à ·'), ('à ¹', 'à ¹'), + ('à ½', 'à ¾'), ('।', '॥'), ('၊', '။'), ('።', '።'), + ('፧', '፨'), ('᙮', '᙮'), ('᜵', '᜶'), ('᠃', '᠃'), + ('᠉', '᠉'), ('᥄', '᥅'), ('᪨', '᪫'), ('᭚', '᭛'), + ('᭞', '᭟'), ('á°»', 'á°¼'), ('á±¾', '᱿'), ('‼', '‽'), + ('⁇', '⁉'), ('⸮', '⸮'), ('⸼', '⸼'), ('。', '。'), + ('꓿', '꓿'), ('꘎', '꘏'), ('꛳', '꛳'), ('꛷', '꛷'), + ('ê¡¶', 'ê¡·'), ('꣎', '꣏'), ('꤯', '꤯'), ('꧈', '꧉'), + ('꩝', '꩟'), ('ê«°', '꫱'), ('꯫', '꯫'), ('﹒', '﹒'), + ('﹖', '﹗'), ('!', '!'), ('.', '.'), ('?', '?'), + ('。', '。'), ('𐩖', '𐩗'), ('𐽕', '𐽙'), ('𑁇', '𑁈'), + ('𑂾', '𑃁'), ('𑅁', '𑅃'), ('𑇅', '𑇆'), ('𑇍', '𑇍'), + ('𑇞', '𑇟'), ('𑈸', '𑈹'), ('𑈻', '𑈼'), ('𑊩', '𑊩'), + ('𑑋', '𑑌'), ('𑗂', '𑗃'), ('𑗉', '𑗗'), ('𑙁', '𑙂'), + ('𑜼', '𑜾'), ('𑩂', '𑩃'), ('𑪛', '𑪜'), ('𑱁', '𑱂'), + ('𑻷', '𑻸'), ('𖩮', '𖩯'), ('𖫵', '𖫵'), ('𖬷', '𖬸'), + ('𖭄', '𖭄'), ('𖺘', '𖺘'), ('𛲟', '𛲟'), ('𝪈', '𝪈'), +]; + +pub const SOFT_DOTTED: &'static [(char, char)] = &[ + ('i', 'j'), ('į', 'į'), ('ɉ', 'ɉ'), ('ɨ', 'ɨ'), ('ʝ', 'ʝ'), + ('ʲ', 'ʲ'), ('ϳ', 'ϳ'), ('і', 'і'), ('ј', 'ј'), ('áµ¢', 'áµ¢'), + ('ᶖ', 'ᶖ'), ('ᶤ', 'ᶤ'), ('ᶨ', 'ᶨ'), ('ḭ', 'ḭ'), + ('ị', 'ị'), ('ⁱ', 'ⁱ'), ('ⅈ', 'ⅉ'), ('â±¼', 'â±¼'), + ('𝐢', '𝐣'), ('𝑖', '𝑗'), ('𝒊', '𝒋'), ('𝒾', '𝒿'), + ('𝓲', '𝓳'), ('𝔦', '𝔧'), ('𝕚', '𝕛'), ('𝖎', '𝖏'), + ('𝗂', '𝗃'), ('𝗶', '𝗷'), ('𝘪', '𝘫'), ('𝙞', '𝙟'), + ('𝚒', '𝚓'), +]; + +pub const TERMINAL_PUNCTUATION: &'static [(char, char)] = &[ + ('!', '!'), (',', ','), ('.', '.'), (':', ';'), ('?', '?'), (';', ';'), + ('·', '·'), ('։', '։'), ('׃', '׃'), ('،', '،'), ('؛', '؛'), + ('؞', '؟'), ('۔', '۔'), ('܀', '܊'), ('܌', '܌'), ('߸', 'ß¹'), + ('à °', 'à ¾'), ('࡞', '࡞'), ('।', '॥'), ('๚', '๛'), + ('༈', '༈'), ('།', '༒'), ('၊', '။'), ('፡', '፨'), + ('᙭', '᙮'), ('᛫', '᛭'), ('᜵', '᜶'), ('។', '៖'), + ('៚', '៚'), ('᠂', '᠅'), ('᠈', '᠉'), ('᥄', '᥅'), + ('᪨', '᪫'), ('᭚', '᭛'), ('᭝', '᭟'), ('á°»', 'á°¿'), + ('á±¾', '᱿'), ('‼', '‽'), ('⁇', '⁉'), ('⸮', '⸮'), + ('⸼', '⸼'), ('⹁', '⹁'), ('⹌', '⹌'), ('⹎', '⹎'), + ('、', '。'), ('꓾', '꓿'), ('꘍', '꘏'), ('꛳', '꛷'), + ('ê¡¶', 'ê¡·'), ('꣎', '꣏'), ('꤯', '꤯'), ('꧇', '꧉'), + ('꩝', '꩟'), ('꫟', '꫟'), ('ê«°', '꫱'), ('꯫', '꯫'), + ('﹐', '﹒'), ('﹔', '﹗'), ('!', '!'), (',', ','), + ('.', '.'), (':', ';'), ('?', '?'), ('。', '。'), + ('、', '、'), ('𐎟', '𐎟'), ('𐏐', '𐏐'), ('𐡗', '𐡗'), + ('𐤟', '𐤟'), ('𐩖', '𐩗'), ('𐫰', '𐫵'), ('𐬺', '𐬿'), + ('𐮙', '𐮜'), ('𐽕', '𐽙'), ('𑁇', '𑁍'), ('𑂾', '𑃁'), + ('𑅁', '𑅃'), ('𑇅', '𑇆'), ('𑇍', '𑇍'), ('𑇞', '𑇟'), + ('𑈸', '𑈼'), ('𑊩', '𑊩'), ('𑑋', '𑑍'), ('𑑛', '𑑛'), + ('𑗂', '𑗅'), ('𑗉', '𑗗'), ('𑙁', '𑙂'), ('𑜼', '𑜾'), + ('𑩂', '𑩃'), ('𑪛', '𑪜'), ('𑪡', '𑪢'), ('𑱁', '𑱃'), + ('𑱱', '𑱱'), ('𑻷', '𑻸'), ('𒑰', '𒑴'), ('𖩮', '𖩯'), + ('𖫵', '𖫵'), ('𖬷', '𖬹'), ('𖭄', '𖭄'), ('𖺗', '𖺘'), + ('𛲟', '𛲟'), ('𝪇', '𝪊'), +]; + +pub const UNIFIED_IDEOGRAPH: &'static [(char, char)] = &[ + ('㐀', 'ä¶µ'), ('一', '鿯'), ('﨎', '﨏'), ('﨑', '﨑'), + ('﨓', '﨔'), ('﨟', '﨟'), ('﨡', '﨡'), ('﨣', '﨤'), + ('﨧', '﨩'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), + ('ð«  ', '𬺡'), ('𬺰', '𮯠'), +]; + +pub const UPPERCASE: &'static [(char, char)] = &[ + ('A', 'Z'), ('À', 'Ö'), ('Ø', 'Þ'), ('Ā', 'Ā'), ('Ă', 'Ă'), + ('Ą', 'Ą'), ('Ć', 'Ć'), ('Ĉ', 'Ĉ'), ('Ċ', 'Ċ'), ('Č', 'Č'), + ('Ď', 'Ď'), ('Đ', 'Đ'), ('Ē', 'Ē'), ('Ĕ', 'Ĕ'), ('Ė', 'Ė'), + ('Ę', 'Ę'), ('Ě', 'Ě'), ('Ĝ', 'Ĝ'), ('Ğ', 'Ğ'), ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), ('Ĥ', 'Ĥ'), ('Ħ', 'Ħ'), ('Ĩ', 'Ĩ'), ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), ('Ä®', 'Ä®'), ('İ', 'İ'), ('IJ', 'IJ'), ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), ('Ĺ', 'Ĺ'), ('Ä»', 'Ä»'), ('Ľ', 'Ľ'), ('Ä¿', 'Ä¿'), + ('Ł', 'Ł'), ('Ń', 'Ń'), ('Ņ', 'Ņ'), ('Ň', 'Ň'), ('Ŋ', 'Ŋ'), + ('Ō', 'Ō'), ('Ŏ', 'Ŏ'), ('Ő', 'Ő'), ('Œ', 'Œ'), ('Ŕ', 'Ŕ'), + ('Ŗ', 'Ŗ'), ('Ř', 'Ř'), ('Ś', 'Ś'), ('Ŝ', 'Ŝ'), ('Ş', 'Ş'), + ('Å ', 'Å '), ('Å¢', 'Å¢'), ('Ť', 'Ť'), ('Ŧ', 'Ŧ'), ('Ũ', 'Ũ'), + ('Ū', 'Ū'), ('Ŭ', 'Ŭ'), ('Å®', 'Å®'), ('Ű', 'Ű'), ('Ų', 'Ų'), + ('Å´', 'Å´'), ('Ŷ', 'Ŷ'), ('Ÿ', 'Ź'), ('Å»', 'Å»'), ('Ž', 'Ž'), + ('Ɓ', 'Ƃ'), ('Ƅ', 'Ƅ'), ('Ɔ', 'Ƈ'), ('Ɖ', 'Ƌ'), ('Ǝ', 'Ƒ'), + ('Ɠ', 'Ɣ'), ('Ɩ', 'Ƙ'), ('Ɯ', 'Ɲ'), ('Ɵ', 'Æ '), ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), ('Ʀ', 'Ƨ'), ('Æ©', 'Æ©'), ('Ƭ', 'Ƭ'), ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), ('Ƶ', 'Ƶ'), ('Æ·', 'Ƹ'), ('Ƽ', 'Ƽ'), ('DŽ', 'DŽ'), + ('LJ', 'LJ'), ('NJ', 'NJ'), ('Ǎ', 'Ǎ'), ('Ǐ', 'Ǐ'), ('Ǒ', 'Ǒ'), + ('Ǔ', 'Ǔ'), ('Ǖ', 'Ǖ'), ('Ǘ', 'Ǘ'), ('Ǚ', 'Ǚ'), ('Ǜ', 'Ǜ'), + ('Ǟ', 'Ǟ'), ('Ç ', 'Ç '), ('Ç¢', 'Ç¢'), ('Ǥ', 'Ǥ'), ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), ('Ǫ', 'Ǫ'), ('Ǭ', 'Ǭ'), ('Ç®', 'Ç®'), ('DZ', 'DZ'), + ('Ç´', 'Ç´'), ('Ƕ', 'Ǹ'), ('Ǻ', 'Ǻ'), ('Ǽ', 'Ǽ'), ('Ǿ', 'Ǿ'), + ('Ȁ', 'Ȁ'), ('Ȃ', 'Ȃ'), ('Ȅ', 'Ȅ'), ('Ȇ', 'Ȇ'), ('Ȉ', 'Ȉ'), + ('Ȋ', 'Ȋ'), ('Ȍ', 'Ȍ'), ('Ȏ', 'Ȏ'), ('Ȑ', 'Ȑ'), ('Ȓ', 'Ȓ'), + ('Ȕ', 'Ȕ'), ('Ȗ', 'Ȗ'), ('Ș', 'Ș'), ('Ț', 'Ț'), ('Ȝ', 'Ȝ'), + ('Ȟ', 'Ȟ'), ('È ', 'È '), ('È¢', 'È¢'), ('Ȥ', 'Ȥ'), ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), ('Ȫ', 'Ȫ'), ('Ȭ', 'Ȭ'), ('È®', 'È®'), ('Ȱ', 'Ȱ'), + ('Ȳ', 'Ȳ'), ('Ⱥ', 'È»'), ('Ƚ', 'Ⱦ'), ('Ɂ', 'Ɂ'), ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), ('Ɋ', 'Ɋ'), ('Ɍ', 'Ɍ'), ('Ɏ', 'Ɏ'), ('Ͱ', 'Ͱ'), + ('Ͳ', 'Ͳ'), ('Ͷ', 'Ͷ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ώ'), ('Α', 'Ρ'), ('Σ', 'Ϋ'), ('Ϗ', 'Ϗ'), + ('ϒ', 'ϔ'), ('Ϙ', 'Ϙ'), ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), + ('Ï ', 'Ï '), ('Ï¢', 'Ï¢'), ('Ϥ', 'Ϥ'), ('Ϧ', 'Ϧ'), ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), ('Ϭ', 'Ϭ'), ('Ï®', 'Ï®'), ('Ï´', 'Ï´'), ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), ('Ͻ', 'Я'), ('Ñ ', 'Ñ '), ('Ñ¢', 'Ñ¢'), ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), ('Ѩ', 'Ѩ'), ('Ѫ', 'Ѫ'), ('Ѭ', 'Ѭ'), ('Ñ®', 'Ñ®'), + ('Ѱ', 'Ѱ'), ('Ѳ', 'Ѳ'), ('Ñ´', 'Ñ´'), ('Ѷ', 'Ѷ'), ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), ('Ѽ', 'Ѽ'), ('Ѿ', 'Ѿ'), ('Ҁ', 'Ҁ'), ('Ҋ', 'Ҋ'), + ('Ҍ', 'Ҍ'), ('Ҏ', 'Ҏ'), ('Ґ', 'Ґ'), ('Ғ', 'Ғ'), ('Ҕ', 'Ҕ'), + ('Җ', 'Җ'), ('Ҙ', 'Ҙ'), ('Қ', 'Қ'), ('Ҝ', 'Ҝ'), ('Ҟ', 'Ҟ'), + ('Ò ', 'Ò '), ('Ò¢', 'Ò¢'), ('Ò¤', 'Ò¤'), ('Ò¦', 'Ò¦'), ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), ('Ò¬', 'Ò¬'), ('Ò®', 'Ò®'), ('Ò°', 'Ò°'), ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), ('Ò¶', 'Ò¶'), ('Ò¸', 'Ò¸'), ('Òº', 'Òº'), ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), ('Ӏ', 'Ӂ'), ('Ӄ', 'Ӄ'), ('Ӆ', 'Ӆ'), ('Ӈ', 'Ӈ'), + ('Ӊ', 'Ӊ'), ('Ӌ', 'Ӌ'), ('Ӎ', 'Ӎ'), ('Ӑ', 'Ӑ'), ('Ӓ', 'Ӓ'), + ('Ӕ', 'Ӕ'), ('Ӗ', 'Ӗ'), ('Ә', 'Ә'), ('Ӛ', 'Ӛ'), ('Ӝ', 'Ӝ'), + ('Ӟ', 'Ӟ'), ('Ó ', 'Ó '), ('Ó¢', 'Ó¢'), ('Ó¤', 'Ó¤'), ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), ('Óª', 'Óª'), ('Ó¬', 'Ó¬'), ('Ó®', 'Ó®'), ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), ('Ó´', 'Ó´'), ('Ó¶', 'Ó¶'), ('Ó¸', 'Ó¸'), ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), ('Ó¾', 'Ó¾'), ('Ԁ', 'Ԁ'), ('Ԃ', 'Ԃ'), ('Ԅ', 'Ԅ'), + ('Ԇ', 'Ԇ'), ('Ԉ', 'Ԉ'), ('Ԋ', 'Ԋ'), ('Ԍ', 'Ԍ'), ('Ԏ', 'Ԏ'), + ('Ԑ', 'Ԑ'), ('Ԓ', 'Ԓ'), ('Ԕ', 'Ԕ'), ('Ԗ', 'Ԗ'), ('Ԙ', 'Ԙ'), + ('Ԛ', 'Ԛ'), ('Ԝ', 'Ԝ'), ('Ԟ', 'Ԟ'), ('Ô ', 'Ô '), ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), ('Ô¦', 'Ô¦'), ('Ô¨', 'Ô¨'), ('Ôª', 'Ôª'), ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), ('Ô±', 'Ֆ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('Ꭰ', 'Ᏽ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), ('Ḅ', 'Ḅ'), ('Ḇ', 'Ḇ'), ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), ('Ḍ', 'Ḍ'), ('Ḏ', 'Ḏ'), ('Ḑ', 'Ḑ'), + ('Ḓ', 'Ḓ'), ('Ḕ', 'Ḕ'), ('Ḗ', 'Ḗ'), ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), ('Ḝ', 'Ḝ'), ('Ḟ', 'Ḟ'), ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), ('Ḥ', 'Ḥ'), ('Ḧ', 'Ḧ'), ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), ('Ḭ', 'Ḭ'), ('Ḯ', 'Ḯ'), ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), ('Ḵ', 'Ḵ'), ('Ḷ', 'Ḷ'), ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), ('Ḽ', 'Ḽ'), ('Ḿ', 'Ḿ'), ('Ṁ', 'Ṁ'), + ('Ṃ', 'Ṃ'), ('Ṅ', 'Ṅ'), ('Ṇ', 'Ṇ'), ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), ('Ṍ', 'Ṍ'), ('Ṏ', 'Ṏ'), ('Ṑ', 'Ṑ'), + ('Ṓ', 'Ṓ'), ('Ṕ', 'Ṕ'), ('Ṗ', 'Ṗ'), ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), ('Ṝ', 'Ṝ'), ('Ṟ', 'Ṟ'), ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), ('Ṥ', 'Ṥ'), ('Ṧ', 'Ṧ'), ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), ('Ṭ', 'Ṭ'), ('á¹®', 'á¹®'), ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), ('á¹´', 'á¹´'), ('á¹¶', 'á¹¶'), ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), ('á¹¼', 'á¹¼'), ('á¹¾', 'á¹¾'), ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), ('Ẅ', 'Ẅ'), ('Ẇ', 'Ẇ'), ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), ('Ẍ', 'Ẍ'), ('Ẏ', 'Ẏ'), ('Ẑ', 'Ẑ'), + ('Ẓ', 'Ẓ'), ('Ẕ', 'Ẕ'), ('ẞ', 'ẞ'), ('Ạ', 'Ạ'), + ('Ả', 'Ả'), ('Ấ', 'Ấ'), ('Ầ', 'Ầ'), ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), ('Ậ', 'Ậ'), ('Ắ', 'Ắ'), ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), ('Ẵ', 'Ẵ'), ('Ặ', 'Ặ'), ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), ('Ẽ', 'Ẽ'), ('Ế', 'Ế'), ('Ề', 'Ề'), + ('Ể', 'Ể'), ('Ễ', 'Ễ'), ('Ệ', 'Ệ'), ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), ('Ọ', 'Ọ'), ('Ỏ', 'Ỏ'), ('Ố', 'Ố'), + ('Ồ', 'Ồ'), ('Ổ', 'Ổ'), ('Ỗ', 'Ỗ'), ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), ('Ờ', 'Ờ'), ('Ở', 'Ở'), ('á» ', 'á» '), + ('Ợ', 'Ợ'), ('Ụ', 'Ụ'), ('Ủ', 'Ủ'), ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), ('Ử', 'Ử'), ('á»®', 'á»®'), ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), ('á»´', 'á»´'), ('á»¶', 'á»¶'), ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), ('Ỽ', 'Ỽ'), ('Ỿ', 'Ỿ'), ('Ἀ', 'Ἇ'), + ('Ἐ', 'Ἕ'), ('Ἠ', 'Ἧ'), ('Ἰ', 'Ἷ'), ('Ὀ', 'Ὅ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), ('Ᾰ', 'á¾»'), ('Ὲ', 'Ή'), ('Ῐ', 'Ί'), + ('Ῠ', 'Ῥ'), ('Ὸ', 'á¿»'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), + ('ℋ', 'ℍ'), ('ℐ', 'ℒ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), + ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), + ('ℰ', 'ℳ'), ('ℾ', 'ℿ'), ('ⅅ', 'ⅅ'), ('Ⅰ', 'Ⅿ'), + ('Ↄ', 'Ↄ'), ('Ⓐ', 'Ⓩ'), ('Ⰰ', 'â°®'), ('â± ', 'â± '), + ('â±¢', 'Ɽ'), ('â±§', 'â±§'), ('Ⱪ', 'Ⱪ'), ('Ⱬ', 'Ⱬ'), + ('â±­', 'â±°'), ('â±²', 'â±²'), ('â±µ', 'â±µ'), ('â±¾', 'Ⲁ'), + ('Ⲃ', 'Ⲃ'), ('Ⲅ', 'Ⲅ'), ('Ⲇ', 'Ⲇ'), ('Ⲉ', 'Ⲉ'), + ('Ⲋ', 'Ⲋ'), ('Ⲍ', 'Ⲍ'), ('Ⲏ', 'Ⲏ'), ('Ⲑ', 'Ⲑ'), + ('Ⲓ', 'Ⲓ'), ('Ⲕ', 'Ⲕ'), ('Ⲗ', 'Ⲗ'), ('Ⲙ', 'Ⲙ'), + ('Ⲛ', 'Ⲛ'), ('Ⲝ', 'Ⲝ'), ('Ⲟ', 'Ⲟ'), ('â² ', 'â² '), + ('â²¢', 'â²¢'), ('Ⲥ', 'Ⲥ'), ('Ⲧ', 'Ⲧ'), ('Ⲩ', 'Ⲩ'), + ('Ⲫ', 'Ⲫ'), ('Ⲭ', 'Ⲭ'), ('â²®', 'â²®'), ('â²°', 'â²°'), + ('â²²', 'â²²'), ('â²´', 'â²´'), ('â²¶', 'â²¶'), ('Ⲹ', 'Ⲹ'), + ('Ⲻ', 'Ⲻ'), ('â²¼', 'â²¼'), ('â²¾', 'â²¾'), ('Ⳁ', 'Ⳁ'), + ('Ⳃ', 'Ⳃ'), ('Ⳅ', 'Ⳅ'), ('Ⳇ', 'Ⳇ'), ('Ⳉ', 'Ⳉ'), + ('Ⳋ', 'Ⳋ'), ('Ⳍ', 'Ⳍ'), ('Ⳏ', 'Ⳏ'), ('Ⳑ', 'Ⳑ'), + ('Ⳓ', 'Ⳓ'), ('Ⳕ', 'Ⳕ'), ('Ⳗ', 'Ⳗ'), ('Ⳙ', 'Ⳙ'), + ('Ⳛ', 'Ⳛ'), ('Ⳝ', 'Ⳝ'), ('Ⳟ', 'Ⳟ'), ('â³ ', 'â³ '), + ('â³¢', 'â³¢'), ('Ⳬ', 'Ⳬ'), ('â³­', 'â³­'), ('â³²', 'â³²'), + ('Ꙁ', 'Ꙁ'), ('Ꙃ', 'Ꙃ'), ('Ꙅ', 'Ꙅ'), ('Ꙇ', 'Ꙇ'), + ('Ꙉ', 'Ꙉ'), ('Ꙋ', 'Ꙋ'), ('Ꙍ', 'Ꙍ'), ('Ꙏ', 'Ꙏ'), + ('Ꙑ', 'Ꙑ'), ('Ꙓ', 'Ꙓ'), ('Ꙕ', 'Ꙕ'), ('Ꙗ', 'Ꙗ'), + ('Ꙙ', 'Ꙙ'), ('Ꙛ', 'Ꙛ'), ('Ꙝ', 'Ꙝ'), ('Ꙟ', 'Ꙟ'), + ('Ꙡ', 'Ꙡ'), ('Ꙣ', 'Ꙣ'), ('Ꙥ', 'Ꙥ'), ('Ꙧ', 'Ꙧ'), + ('Ꙩ', 'Ꙩ'), ('Ꙫ', 'Ꙫ'), ('Ꙭ', 'Ꙭ'), ('Ꚁ', 'Ꚁ'), + ('Ꚃ', 'Ꚃ'), ('Ꚅ', 'Ꚅ'), ('Ꚇ', 'Ꚇ'), ('Ꚉ', 'Ꚉ'), + ('Ꚋ', 'Ꚋ'), ('Ꚍ', 'Ꚍ'), ('Ꚏ', 'Ꚏ'), ('Ꚑ', 'Ꚑ'), + ('Ꚓ', 'Ꚓ'), ('Ꚕ', 'Ꚕ'), ('Ꚗ', 'Ꚗ'), ('Ꚙ', 'Ꚙ'), + ('Ꚛ', 'Ꚛ'), ('Ꜣ', 'Ꜣ'), ('Ꜥ', 'Ꜥ'), ('Ꜧ', 'Ꜧ'), + ('Ꜩ', 'Ꜩ'), ('Ꜫ', 'Ꜫ'), ('Ꜭ', 'Ꜭ'), ('Ꜯ', 'Ꜯ'), + ('Ꜳ', 'Ꜳ'), ('Ꜵ', 'Ꜵ'), ('Ꜷ', 'Ꜷ'), ('Ꜹ', 'Ꜹ'), + ('Ꜻ', 'Ꜻ'), ('Ꜽ', 'Ꜽ'), ('Ꜿ', 'Ꜿ'), ('Ꝁ', 'Ꝁ'), + ('Ꝃ', 'Ꝃ'), ('Ꝅ', 'Ꝅ'), ('Ꝇ', 'Ꝇ'), ('Ꝉ', 'Ꝉ'), + ('Ꝋ', 'Ꝋ'), ('Ꝍ', 'Ꝍ'), ('Ꝏ', 'Ꝏ'), ('Ꝑ', 'Ꝑ'), + ('Ꝓ', 'Ꝓ'), ('Ꝕ', 'Ꝕ'), ('Ꝗ', 'Ꝗ'), ('Ꝙ', 'Ꝙ'), + ('Ꝛ', 'Ꝛ'), ('Ꝝ', 'Ꝝ'), ('Ꝟ', 'Ꝟ'), ('Ꝡ', 'Ꝡ'), + ('Ꝣ', 'Ꝣ'), ('Ꝥ', 'Ꝥ'), ('Ꝧ', 'Ꝧ'), ('Ꝩ', 'Ꝩ'), + ('Ꝫ', 'Ꝫ'), ('Ꝭ', 'Ꝭ'), ('Ꝯ', 'Ꝯ'), ('Ꝺ', 'Ꝺ'), + ('Ꝼ', 'Ꝼ'), ('Ᵹ', 'Ꝿ'), ('Ꞁ', 'Ꞁ'), ('Ꞃ', 'Ꞃ'), + ('Ꞅ', 'Ꞅ'), ('Ꞇ', 'Ꞇ'), ('Ꞌ', 'Ꞌ'), ('Ɥ', 'Ɥ'), + ('Ꞑ', 'Ꞑ'), ('Ꞓ', 'Ꞓ'), ('Ꞗ', 'Ꞗ'), ('Ꞙ', 'Ꞙ'), + ('Ꞛ', 'Ꞛ'), ('Ꞝ', 'Ꞝ'), ('Ꞟ', 'Ꞟ'), ('Ꞡ', 'Ꞡ'), + ('Ꞣ', 'Ꞣ'), ('Ꞥ', 'Ꞥ'), ('Ꞧ', 'Ꞧ'), ('Ꞩ', 'Ꞩ'), + ('Ɦ', 'Ɪ'), ('Ʞ', 'Ꞵ'), ('Ꞷ', 'Ꞷ'), ('Ꞹ', 'Ꞹ'), + ('A', 'Z'), ('𐐀', '𐐧'), ('𐒰', '𐓓'), ('𐲀', '𐲲'), + ('𑢠', '𑢿'), ('𖹀', '𖹟'), ('𝐀', '𝐙'), ('𝐴', '𝑍'), + ('𝑨', '𝒁'), ('𝒜', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), + ('𝒥', '𝒦'), ('𝒩', '𝒬'), ('𝒮', '𝒵'), ('𝓐', '𝓩'), + ('𝔄', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔸', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕬', '𝖅'), ('𝖠', '𝖹'), ('𝗔', '𝗭'), + ('𝘈', '𝘡'), ('𝘼', '𝙕'), ('𝙰', '𝚉'), ('𝚨', '𝛀'), + ('𝛢', '𝛺'), ('𝜜', '𝜴'), ('𝝖', '𝝮'), ('𝞐', '𝞨'), + ('𝟊', '𝟊'), ('𞤀', '𞤡'), ('🄰', '🅉'), ('🅐', '🅩'), + ('🅰', '🆉'), +]; + +pub const VARIATION_SELECTOR: &'static [(char, char)] = &[ + ('\u{180b}', '\u{180d}'), ('\u{fe00}', '\u{fe0f}'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const WHITE_SPACE: &'static [(char, char)] = &[ + ('\t', '\r'), (' ', ' '), ('\u{85}', '\u{85}'), ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), + ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'), + ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}'), +]; + +pub const XID_CONTINUE: &'static [(char, char)] = &[ + ('0', '9'), ('A', 'Z'), ('_', '_'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), + ('·', '·'), ('º', 'º'), ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), + ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('\u{300}', 'Í´'), + ('Ͷ', 'Í·'), ('Í»', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('\u{483}', '\u{487}'), + ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), ('Õ ', 'ֈ'), + ('\u{591}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), + ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('א', 'ת'), ('ׯ', 'ײ'), + ('\u{610}', '\u{61a}'), ('Ø ', 'Ù©'), ('Ù®', 'ۓ'), ('ە', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), ('\u{6ea}', 'Û¼'), ('Û¿', 'Û¿'), ('ܐ', '\u{74a}'), + ('ݍ', 'Þ±'), ('߀', 'ßµ'), ('ߺ', 'ߺ'), ('\u{7fd}', '\u{7fd}'), + ('ࠀ', '\u{82d}'), ('ࡀ', '\u{85b}'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', '\u{963}'), + ('०', '९'), ('ॱ', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('\u{9bc}', '\u{9c4}'), ('ে', 'ৈ'), ('ো', 'ৎ'), + ('\u{9d7}', '\u{9d7}'), ('ড়', 'ঢ়'), ('য়', '\u{9e3}'), ('০', 'à§±'), + ('à§¼', 'à§¼'), ('\u{9fe}', '\u{9fe}'), ('\u{a01}', 'ਃ'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('\u{a3c}', '\u{a3c}'), ('ਾ', '\u{a42}'), + ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), + ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('੦', '\u{a75}'), ('\u{a81}', 'ઃ'), + ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('\u{abc}', '\u{ac5}'), ('\u{ac7}', 'ૉ'), + ('ો', '\u{acd}'), ('ૐ', 'ૐ'), ('à« ', '\u{ae3}'), ('૦', '૯'), + ('ૹ', '\u{aff}'), ('\u{b01}', 'ଃ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), + ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), + ('\u{b3c}', '\u{b44}'), ('େ', 'ୈ'), ('ୋ', '\u{b4d}'), + ('\u{b56}', '\u{b57}'), ('ଡ଼', 'ଢ଼'), ('ୟ', '\u{b63}'), ('à­¦', 'à­¯'), + ('à­±', 'à­±'), ('\u{b82}', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('\u{bbe}', 'ூ'), + ('ெ', 'ை'), ('ொ', '\u{bcd}'), ('ௐ', 'ௐ'), ('\u{bd7}', '\u{bd7}'), + ('௦', '௯'), ('\u{c00}', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), + ('à°ª', 'à°¹'), ('à°½', 'ౄ'), ('\u{c46}', '\u{c48}'), + ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('ౘ', 'ౚ'), + ('à± ', '\u{c63}'), ('౦', '౯'), ('ಀ', 'ಃ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('\u{cbc}', 'ೄ'), ('\u{cc6}', 'ೈ'), ('ೊ', '\u{ccd}'), + ('\u{cd5}', '\u{cd6}'), ('ೞ', 'ೞ'), ('à³ ', '\u{ce3}'), ('೦', '೯'), + ('à³±', 'à³²'), ('\u{d00}', 'ഃ'), ('അ', 'ഌ'), ('എ', 'ഐ'), + ('ഒ', '\u{d44}'), ('െ', 'ൈ'), ('ൊ', 'ൎ'), ('ൔ', '\u{d57}'), + ('ൟ', '\u{d63}'), ('൦', '൯'), ('ൺ', 'ൿ'), ('ං', 'ඃ'), + ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), + ('ව', 'ෆ'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', '\u{dd4}'), + ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), ('à·¦', 'à·¯'), ('à·²', 'à·³'), + ('ก', '\u{e3a}'), ('เ', '\u{e4e}'), ('๐', '๙'), ('ກ', 'ຂ'), + ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), + ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), ('ລ', 'ລ'), + ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', '\u{eb9}'), ('\u{ebb}', 'ຽ'), + ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('\u{ec8}', '\u{ecd}'), ('໐', '໙'), + ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('\u{f18}', '\u{f19}'), ('༠', '༩'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('༾', 'ཇ'), ('ཉ', 'ཬ'), ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('က', '၉'), ('ၐ', '\u{109d}'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), + ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), + ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኈ'), + ('ኊ', 'ኍ'), ('ነ', 'ኰ'), ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), + ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), ('ወ', 'ዖ'), ('ዘ', 'ጐ'), + ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), ('\u{135d}', '\u{135f}'), ('፩', '፱'), + ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), + ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), + ('ᜀ', 'ᜌ'), ('ᜎ', '\u{1714}'), ('ᜠ', '\u{1734}'), + ('ᝀ', '\u{1753}'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), + ('\u{1772}', '\u{1773}'), ('ក', '\u{17d3}'), ('ៗ', 'ៗ'), + ('ៜ', '\u{17dd}'), ('០', '៩'), ('\u{180b}', '\u{180d}'), + ('᠐', '᠙'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('\u{1920}', 'ᤫ'), ('ᤰ', '\u{193b}'), ('᥆', 'ᥭ'), + ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('᧐', '᧚'), + ('ᨀ', '\u{1a1b}'), ('ᨠ', '\u{1a5e}'), ('\u{1a60}', '\u{1a7c}'), + ('\u{1a7f}', '᪉'), ('᪐', '᪙'), ('ᪧ', 'ᪧ'), + ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', 'ᭋ'), ('᭐', '᭙'), + ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '᯳'), ('ᰀ', '\u{1c37}'), + ('᱀', '᱉'), ('ᱍ', 'á±½'), ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), + ('á²½', 'Ჿ'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cf9}'), + ('ᴀ', '\u{1df9}'), ('\u{1dfb}', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), + ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), + ('‿', '⁀'), ('⁔', '⁔'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), + ('ₐ', 'ₜ'), ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', '\u{20e1}'), + ('\u{20e5}', '\u{20f0}'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('℘', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), + ('ℨ', 'ℨ'), ('K', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'ⳤ'), ('Ⳬ', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), + ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), ('\u{2d7f}', 'ⶖ'), + ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), + ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), + ('\u{2de0}', '\u{2dff}'), ('々', '〇'), ('〡', '\u{302f}'), + ('〱', '〵'), ('〸', '〼'), ('ぁ', 'ゖ'), ('\u{3099}', '\u{309a}'), + ('ゝ', 'ゟ'), ('ァ', 'ヺ'), ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), + ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), + ('一', '鿯'), ('ꀀ', 'ꒌ'), ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), + ('ꘐ', 'ꘫ'), ('Ꙁ', '\u{a66f}'), ('\u{a674}', '\u{a67d}'), + ('ꙿ', '\u{a6f1}'), ('ꜗ', 'ꜟ'), ('Ꜣ', 'ꞈ'), ('Ꞌ', 'ꞹ'), + ('ꟷ', 'ê §'), ('ꡀ', 'ꡳ'), ('ꢀ', '\u{a8c5}'), ('꣐', '꣙'), + ('\u{a8e0}', 'ꣷ'), ('ꣻ', 'ꣻ'), ('ꣽ', '\u{a92d}'), ('ꤰ', '꥓'), + ('ꥠ', 'ꥼ'), ('\u{a980}', '꧀'), ('ꧏ', '꧙'), ('ê§ ', 'ê§¾'), + ('ꨀ', '\u{aa36}'), ('ꩀ', 'ꩍ'), ('꩐', '꩙'), ('ê© ', 'ê©¶'), + ('ꩺ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫯ'), ('ꫲ', '\u{aaf6}'), + ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), + ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), ('ê­°', 'ꯪ'), + ('꯬', '\u{abed}'), ('꯰', '꯹'), ('가', '힣'), ('ힰ', 'ퟆ'), + ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), ('ï©°', '龎'), ('ff', 'st'), + ('ﬓ', 'ﬗ'), ('יִ', 'ﬨ'), ('שׁ', 'זּ'), ('טּ', 'לּ'), + ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), + ('ﯓ', 'ﱝ'), ('ﱤ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), + ('ï·°', 'ï·¹'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), + ('︳', '︴'), ('﹍', '﹏'), ('ï¹±', 'ï¹±'), ('ï¹³', 'ï¹³'), + ('ï¹·', 'ï¹·'), ('ï¹¹', 'ï¹¹'), ('ï¹»', 'ï¹»'), ('ï¹½', 'ï¹½'), + ('ﹿ', 'ﻼ'), ('0', '9'), ('A', 'Z'), ('_', '_'), + ('a', 'z'), ('ヲ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), + ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), + ('𐀨', '𐀺'), ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), + ('𐂀', '𐃺'), ('𐅀', '𐅴'), ('\u{101fd}', '\u{101fd}'), + ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('\u{102e0}', '\u{102e0}'), + ('𐌀', '𐌟'), ('𐌭', '𐍊'), ('𐍐', '\u{1037a}'), ('𐎀', '𐎝'), + ('𐎠', '𐏃'), ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐐀', '𐒝'), + ('𐒠', '𐒩'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '𐨓'), ('𐨕', '𐨗'), + ('𐨙', '𐨵'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), + ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '\u{10ae6}'), + ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), + ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐴀', '\u{10d27}'), + ('𐴰', '𐴹'), ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '\u{10f50}'), + ('𑀀', '\u{11046}'), ('𑁦', '𑁯'), ('\u{1107f}', '\u{110ba}'), + ('𑃐', '𑃨'), ('𑃰', '𑃹'), ('\u{11100}', '\u{11134}'), + ('𑄶', '𑄿'), ('𑅄', '𑅆'), ('𑅐', '\u{11173}'), ('𑅶', '𑅶'), + ('\u{11180}', '𑇄'), ('\u{111c9}', '\u{111cc}'), ('𑇐', '𑇚'), + ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), + ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), ('𑊰', '\u{112ea}'), + ('𑋰', '𑋹'), ('\u{11300}', '𑌃'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('\u{1133b}', '𑍄'), ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍐', '𑍐'), + ('\u{11357}', '\u{11357}'), ('𑍝', '𑍣'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('𑐀', '𑑊'), ('𑑐', '𑑙'), + ('\u{1145e}', '\u{1145e}'), ('𑒀', '𑓅'), ('𑓇', '𑓇'), + ('𑓐', '𑓙'), ('𑖀', '\u{115b5}'), ('𑖸', '\u{115c0}'), + ('𑗘', '\u{115dd}'), ('𑘀', '\u{11640}'), ('𑙄', '𑙄'), + ('𑙐', '𑙙'), ('𑚀', '\u{116b7}'), ('𑛀', '𑛉'), ('𑜀', '𑜚'), + ('\u{1171d}', '\u{1172b}'), ('𑜰', '𑜹'), ('𑠀', '\u{1183a}'), + ('𑢠', '𑣩'), ('𑣿', '𑣿'), ('𑨀', '\u{11a3e}'), + ('\u{11a47}', '\u{11a47}'), ('𑩐', '𑪃'), ('𑪆', '\u{11a99}'), + ('𑪝', '𑪝'), ('𑫀', '𑫸'), ('𑰀', '𑰈'), ('𑰊', '\u{11c36}'), + ('\u{11c38}', '𑱀'), ('𑱐', '𑱙'), ('𑱲', '𑲏'), + ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}'), ('𑴀', '𑴆'), + ('𑴈', '𑴉'), ('𑴋', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d47}'), ('𑵐', '𑵙'), + ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶎'), + ('\u{11d90}', '\u{11d91}'), ('𑶓', '𑶘'), ('𑶠', '𑶩'), + ('𑻠', '𑻶'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖩠', '𖩩'), ('𖫐', '𖫭'), ('\u{16af0}', '\u{16af4}'), + ('𖬀', '\u{16b36}'), ('𖭀', '𖭃'), ('𖭐', '𖭙'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('𖹀', '𖹿'), ('𖼀', '𖽄'), ('𖽐', '𖽾'), + ('\u{16f8f}', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '𘟱'), ('𘠀', '𘫲'), + ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), + ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d169}'), ('𝅭', '\u{1d172}'), + ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), + ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), ('𝐀', '𝑔'), + ('𝑖', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), + ('𝒩', '𝒬'), ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), + ('𝓅', '𝔅'), ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), + ('𝔞', '𝔹'), ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), + ('𝕊', '𝕐'), ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), + ('𝛜', '𝛺'), ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), + ('𝝐', '𝝮'), ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), + ('𝟄', '𝟋'), ('𝟎', '𝟿'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), ('𞠀', '𞣄'), + ('\u{1e8d0}', '\u{1e8d6}'), ('𞤀', '\u{1e94a}'), ('𞥐', '𞥙'), + ('𞸀', '𞸃'), ('𞸅', '𞸟'), ('𞸡', '𞸢'), ('𞸤', '𞸤'), + ('𞸧', '𞸧'), ('𞸩', '𞸲'), ('𞸴', '𞸷'), ('𞸹', '𞸹'), + ('𞸻', '𞸻'), ('𞹂', '𞹂'), ('𞹇', '𞹇'), ('𞹉', '𞹉'), + ('𞹋', '𞹋'), ('𞹍', '𞹏'), ('𞹑', '𞹒'), ('𞹔', '𞹔'), + ('𞹗', '𞹗'), ('𞹙', '𞹙'), ('𞹛', '𞹛'), ('𞹝', '𞹝'), + ('𞹟', '𞹟'), ('𞹡', '𞹢'), ('𞹤', '𞹤'), ('𞹧', '𞹪'), + ('𞹬', '𞹲'), ('𞹴', '𞹷'), ('𞹹', '𞹼'), ('𞹾', '𞹾'), + ('𞺀', '𞺉'), ('𞺋', '𞺛'), ('𞺡', '𞺣'), ('𞺥', '𞺩'), + ('𞺫', '𞺻'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), ('𫝀', '𫠝'), + ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), + ('\u{e0100}', '\u{e01ef}'), +]; + +pub const XID_START: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', 'ˁ'), ('ˆ', 'ˑ'), ('Ë ', 'ˤ'), + ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('Ͱ', 'Í´'), ('Ͷ', 'Í·'), ('Í»', 'ͽ'), + ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), + ('Σ', 'ϵ'), ('Ï·', 'ҁ'), ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), + ('Õ ', 'ֈ'), ('א', 'ת'), ('ׯ', 'ײ'), ('Ø ', 'ي'), ('Ù®', 'Ù¯'), + ('Ù±', 'ۓ'), ('ە', 'ە'), ('Û¥', 'Û¦'), ('Û®', 'Û¯'), ('Ûº', 'Û¼'), + ('Û¿', 'Û¿'), ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), + ('ߊ', 'ߪ'), ('ß´', 'ßµ'), ('ߺ', 'ߺ'), ('ࠀ', 'ࠕ'), ('ࠚ', 'ࠚ'), + ('à ¤', 'à ¤'), ('à ¨', 'à ¨'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), + ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), ('ऽ', 'ऽ'), + ('ॐ', 'ॐ'), ('क़', 'ॡ'), ('ॱ', 'ঀ'), ('অ', 'ঌ'), + ('এ', 'ঐ'), ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), + ('শ', 'হ'), ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), ('ড়', 'ঢ়'), + ('য়', 'à§¡'), ('à§°', 'à§±'), ('à§¼', 'à§¼'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), + ('ੲ', 'à©´'), ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), + ('પ', 'ર'), ('લ', 'ળ'), ('વ', 'હ'), ('ઽ', 'ઽ'), + ('ૐ', 'ૐ'), ('à« ', 'à«¡'), ('ૹ', 'ૹ'), ('ଅ', 'ଌ'), + ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), + ('à­±', 'à­±'), ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), + ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), + ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), ('ௐ', 'ௐ'), + ('అ', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), + ('à°½', 'à°½'), ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('ಀ', 'ಀ'), + ('ಅ', 'ಌ'), ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), + ('à³±', 'à³²'), ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), + ('à´½', 'à´½'), ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), ('ൟ', 'ൡ'), + ('ൺ', 'ൿ'), ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), + ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('ก', 'ะ'), ('า', 'า'), + ('เ', 'ๆ'), ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), + ('ຊ', 'ຊ'), ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), + ('ມ', 'ຣ'), ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), + ('ອ', 'ະ'), ('າ', 'າ'), ('ຽ', 'ຽ'), ('ເ', 'ໄ'), + ('ໆ', 'ໆ'), ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), + ('ཉ', 'ཬ'), ('ྈ', 'ྌ'), ('က', 'ဪ'), ('ဿ', 'ဿ'), + ('ၐ', 'ၕ'), ('ၚ', 'ၝ'), ('ၡ', 'ၡ'), ('ၥ', 'ၦ'), + ('ၮ', 'ၰ'), ('ၵ', 'ႁ'), ('ႎ', 'ႎ'), ('Ⴀ', 'Ⴥ'), + ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), ('ჼ', 'ቈ'), + ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), + ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), ('ወ', 'ዖ'), + ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), ('ᎀ', 'ᎏ'), + ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), + ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), + ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), + ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), ('ៗ', 'ៗ'), ('ៜ', 'ៜ'), + ('á  ', 'ᡸ'), ('ᢀ', 'ᢨ'), ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), + ('ᦰ', 'ᧉ'), ('ᨀ', 'ᨖ'), ('ᨠ', 'ᩔ'), ('ᪧ', 'ᪧ'), + ('ᬅ', 'ᬳ'), ('ᭅ', 'ᭋ'), ('ᮃ', 'á® '), ('á®®', 'ᮯ'), + ('ᮺ', 'ᯥ'), ('ᰀ', 'á°£'), ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), + ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('ᳩ', 'ᳬ'), + ('á³®', 'á³±'), ('á³µ', 'á³¶'), ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), + ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), + ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), + ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), + ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), + ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), + ('ℕ', 'ℕ'), ('℘', 'ℝ'), ('ℤ', 'ℤ'), ('Ω', 'Ω'), + ('ℨ', 'ℨ'), ('K', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), + ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'ⳤ'), ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), + ('â´§', 'â´§'), ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), + ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), + ('ⷘ', 'ⷞ'), ('々', '〇'), ('〡', '〩'), ('〱', '〵'), + ('〸', '〼'), ('ぁ', 'ゖ'), ('ゝ', 'ゟ'), ('ァ', 'ヺ'), + ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), + ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '鿯'), ('ꀀ', 'ꒌ'), + ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ꙮ'), ('ꙿ', 'ꚝ'), ('ꚠ', 'ꛯ'), ('ꜗ', 'ꜟ'), + ('Ꜣ', 'ꞈ'), ('Ꞌ', 'ꞹ'), ('ꟷ', 'ꠁ'), ('ꠃ', 'ꠅ'), + ('ꠇ', 'ꠊ'), ('ꠌ', 'ê ¢'), ('ꡀ', 'ꡳ'), ('ꢂ', 'ꢳ'), + ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), ('ꣽ', 'ꣾ'), ('ꤊ', 'ꤥ'), + ('ꤰ', 'ꥆ'), ('ꥠ', 'ꥼ'), ('ꦄ', 'ꦲ'), ('ꧏ', 'ꧏ'), + ('ê§ ', 'ꧤ'), ('ꧦ', 'ꧯ'), ('ꧺ', 'ê§¾'), ('ꨀ', 'ꨨ'), + ('ꩀ', 'ꩂ'), ('ꩄ', 'ꩋ'), ('ê© ', 'ê©¶'), ('ꩺ', 'ꩺ'), + ('ꩾ', 'ꪯ'), ('ꪱ', 'ꪱ'), ('ꪵ', 'ꪶ'), ('ꪹ', 'ꪽ'), + ('ꫀ', 'ꫀ'), ('ꫂ', 'ꫂ'), ('ꫛ', 'ꫝ'), ('ê« ', 'ꫪ'), + ('ꫲ', 'ê«´'), ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), + ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), + ('ê­°', 'ꯢ'), ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), + ('豈', 'ï©­'), ('ï©°', '龎'), ('ff', 'st'), ('ﬓ', 'ﬗ'), + ('יִ', 'יִ'), ('ײַ', 'ﬨ'), ('שׁ', 'זּ'), ('טּ', 'לּ'), + ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), ('צּ', 'ï®±'), + ('ﯓ', 'ﱝ'), ('ﱤ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), + ('ï·°', 'ï·¹'), ('ï¹±', 'ï¹±'), ('ï¹³', 'ï¹³'), ('ï¹·', 'ï¹·'), + ('ï¹¹', 'ï¹¹'), ('ï¹»', 'ï¹»'), ('ï¹½', 'ï¹½'), ('ﹿ', 'ﻼ'), + ('A', 'Z'), ('a', 'z'), ('ヲ', 'ン'), ('ï¾ ', 'ï¾¾'), + ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), + ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), + ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐅀', '𐅴'), + ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐌀', '𐌟'), ('𐌭', '𐍊'), + ('𐍐', '𐍵'), ('𐎀', '𐎝'), ('𐎠', '𐏃'), ('𐏈', '𐏏'), + ('𐏑', '𐏕'), ('𐐀', '𐒝'), ('𐒰', '𐓓'), ('𐓘', '𐓻'), + ('𐔀', '𐔧'), ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), + ('𐝠', '𐝧'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), + ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), + ('𐢀', '𐢞'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), + ('𐤠', '𐤹'), ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '𐨀'), + ('𐨐', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '𐨵'), ('𐩠', '𐩼'), + ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '𐫤'), ('𐬀', '𐬵'), + ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), ('𐰀', '𐱈'), + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐴀', '𐴣'), ('𐼀', '𐼜'), + ('𐼧', '𐼧'), ('𐼰', '𐽅'), ('𑀃', '𑀷'), ('𑂃', '𑂯'), + ('𑃐', '𑃨'), ('𑄃', '𑄦'), ('𑅄', '𑅄'), ('𑅐', '𑅲'), + ('𑅶', '𑅶'), ('𑆃', '𑆲'), ('𑇁', '𑇄'), ('𑇚', '𑇚'), + ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '𑈫'), ('𑊀', '𑊆'), + ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), ('𑊟', '𑊨'), + ('𑊰', '𑋞'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), + ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('𑌽', '𑌽'), + ('𑍐', '𑍐'), ('𑍝', '𑍡'), ('𑐀', '𑐴'), ('𑑇', '𑑊'), + ('𑒀', '𑒯'), ('𑓄', '𑓅'), ('𑓇', '𑓇'), ('𑖀', '𑖮'), + ('𑗘', '𑗛'), ('𑘀', '𑘯'), ('𑙄', '𑙄'), ('𑚀', '𑚪'), + ('𑜀', '𑜚'), ('𑠀', '𑠫'), ('𑢠', '𑣟'), ('𑣿', '𑣿'), + ('𑨀', '𑨀'), ('𑨋', '𑨲'), ('𑨺', '𑨺'), ('𑩐', '𑩐'), + ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('𑪝', '𑪝'), ('𑫀', '𑫸'), + ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), ('𑱲', '𑲏'), + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), ('𑵆', '𑵆'), + ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶉'), ('𑶘', '𑶘'), + ('𑻠', '𑻲'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭀', '𖭃'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('𖹀', '𖹿'), ('𖼀', '𖽄'), ('𖽐', '𖽐'), + ('𖾓', '𖾟'), ('𖿠', '𖿡'), ('𗀀', '𘟱'), ('𘠀', '𘫲'), + ('𛀀', '𛄞'), ('𛅰', '𛋻'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), + ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), ('𝛜', '𝛺'), + ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), ('𝝐', '𝝮'), + ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), ('𝟄', '𝟋'), + ('𞠀', '𞣄'), ('𞤀', '𞥃'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𠀀', '𪛖'), + ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), + ('丽', '𪘀'), +]; diff --git a/regex-syntax/src/unicode_tables/property_names.rs b/regex-syntax/src/unicode_tables/property_names.rs new file mode 100644 index 000000000..7a2bffb00 --- /dev/null +++ b/regex-syntax/src/unicode_tables/property_names.rs @@ -0,0 +1,151 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-names /home/andrew/tmp/ucd-11.0.0/ +// +// ucd-generate is available on crates.io. + +pub const PROPERTY_NAMES: &'static [(&'static str, &'static str)] = &[ + ("age", "Age"), ("ahex", "ASCII_Hex_Digit"), ("alpha", "Alphabetic"), + ("alphabetic", "Alphabetic"), ("asciihexdigit", "ASCII_Hex_Digit"), + ("bc", "Bidi_Class"), ("bidic", "Bidi_Control"), + ("bidiclass", "Bidi_Class"), ("bidicontrol", "Bidi_Control"), + ("bidim", "Bidi_Mirrored"), ("bidimirrored", "Bidi_Mirrored"), + ("bidimirroringglyph", "Bidi_Mirroring_Glyph"), + ("bidipairedbracket", "Bidi_Paired_Bracket"), + ("bidipairedbrackettype", "Bidi_Paired_Bracket_Type"), ("blk", "Block"), + ("block", "Block"), ("bmg", "Bidi_Mirroring_Glyph"), + ("bpb", "Bidi_Paired_Bracket"), ("bpt", "Bidi_Paired_Bracket_Type"), + ("canonicalcombiningclass", "Canonical_Combining_Class"), + ("cased", "Cased"), ("casefolding", "Case_Folding"), + ("caseignorable", "Case_Ignorable"), ("ccc", "Canonical_Combining_Class"), + ("ce", "Composition_Exclusion"), ("cf", "Case_Folding"), + ("changeswhencasefolded", "Changes_When_Casefolded"), + ("changeswhencasemapped", "Changes_When_Casemapped"), + ("changeswhenlowercased", "Changes_When_Lowercased"), + ("changeswhennfkccasefolded", "Changes_When_NFKC_Casefolded"), + ("changeswhentitlecased", "Changes_When_Titlecased"), + ("changeswhenuppercased", "Changes_When_Uppercased"), + ("ci", "Case_Ignorable"), ("cjkaccountingnumeric", "kAccountingNumeric"), + ("cjkcompatibilityvariant", "kCompatibilityVariant"), + ("cjkiicore", "kIICore"), ("cjkirggsource", "kIRG_GSource"), + ("cjkirghsource", "kIRG_HSource"), ("cjkirgjsource", "kIRG_JSource"), + ("cjkirgkpsource", "kIRG_KPSource"), ("cjkirgksource", "kIRG_KSource"), + ("cjkirgmsource", "kIRG_MSource"), ("cjkirgtsource", "kIRG_TSource"), + ("cjkirgusource", "kIRG_USource"), ("cjkirgvsource", "kIRG_VSource"), + ("cjkothernumeric", "kOtherNumeric"), + ("cjkprimarynumeric", "kPrimaryNumeric"), ("cjkrsunicode", "kRSUnicode"), + ("compex", "Full_Composition_Exclusion"), + ("compositionexclusion", "Composition_Exclusion"), + ("cwcf", "Changes_When_Casefolded"), ("cwcm", "Changes_When_Casemapped"), + ("cwkcf", "Changes_When_NFKC_Casefolded"), + ("cwl", "Changes_When_Lowercased"), ("cwt", "Changes_When_Titlecased"), + ("cwu", "Changes_When_Uppercased"), ("dash", "Dash"), + ("decompositionmapping", "Decomposition_Mapping"), + ("decompositiontype", "Decomposition_Type"), + ("defaultignorablecodepoint", "Default_Ignorable_Code_Point"), + ("dep", "Deprecated"), ("deprecated", "Deprecated"), + ("di", "Default_Ignorable_Code_Point"), ("dia", "Diacritic"), + ("diacritic", "Diacritic"), ("dm", "Decomposition_Mapping"), + ("dt", "Decomposition_Type"), ("ea", "East_Asian_Width"), + ("eastasianwidth", "East_Asian_Width"), ("emoji", "Emoji"), + ("emojicomponent", "Emoji_Component"), ("emojimodifier", "Emoji_Modifier"), + ("emojimodifierbase", "Emoji_Modifier_Base"), + ("emojipresentation", "Emoji_Presentation"), + ("equideo", "Equivalent_Unified_Ideograph"), + ("equivalentunifiedideograph", "Equivalent_Unified_Ideograph"), + ("expandsonnfc", "Expands_On_NFC"), ("expandsonnfd", "Expands_On_NFD"), + ("expandsonnfkc", "Expands_On_NFKC"), ("expandsonnfkd", "Expands_On_NFKD"), + ("ext", "Extender"), ("extendedpictographic", "Extended_Pictographic"), + ("extender", "Extender"), ("fcnfkc", "FC_NFKC_Closure"), + ("fcnfkcclosure", "FC_NFKC_Closure"), + ("fullcompositionexclusion", "Full_Composition_Exclusion"), + ("gc", "General_Category"), ("gcb", "Grapheme_Cluster_Break"), + ("generalcategory", "General_Category"), ("graphemebase", "Grapheme_Base"), + ("graphemeclusterbreak", "Grapheme_Cluster_Break"), + ("graphemeextend", "Grapheme_Extend"), ("graphemelink", "Grapheme_Link"), + ("grbase", "Grapheme_Base"), ("grext", "Grapheme_Extend"), + ("grlink", "Grapheme_Link"), ("hangulsyllabletype", "Hangul_Syllable_Type"), + ("hex", "Hex_Digit"), ("hexdigit", "Hex_Digit"), + ("hst", "Hangul_Syllable_Type"), ("hyphen", "Hyphen"), + ("idc", "ID_Continue"), ("idcontinue", "ID_Continue"), + ("ideo", "Ideographic"), ("ideographic", "Ideographic"), + ("ids", "ID_Start"), ("idsb", "IDS_Binary_Operator"), + ("idsbinaryoperator", "IDS_Binary_Operator"), + ("idst", "IDS_Trinary_Operator"), ("idstart", "ID_Start"), + ("idstrinaryoperator", "IDS_Trinary_Operator"), + ("indicpositionalcategory", "Indic_Positional_Category"), + ("indicsyllabiccategory", "Indic_Syllabic_Category"), + ("inpc", "Indic_Positional_Category"), ("insc", "Indic_Syllabic_Category"), + ("isc", "ISO_Comment"), ("jamoshortname", "Jamo_Short_Name"), + ("jg", "Joining_Group"), ("joinc", "Join_Control"), + ("joincontrol", "Join_Control"), ("joininggroup", "Joining_Group"), + ("joiningtype", "Joining_Type"), ("jsn", "Jamo_Short_Name"), + ("jt", "Joining_Type"), ("kaccountingnumeric", "kAccountingNumeric"), + ("kcompatibilityvariant", "kCompatibilityVariant"), ("kiicore", "kIICore"), + ("kirggsource", "kIRG_GSource"), ("kirghsource", "kIRG_HSource"), + ("kirgjsource", "kIRG_JSource"), ("kirgkpsource", "kIRG_KPSource"), + ("kirgksource", "kIRG_KSource"), ("kirgmsource", "kIRG_MSource"), + ("kirgtsource", "kIRG_TSource"), ("kirgusource", "kIRG_USource"), + ("kirgvsource", "kIRG_VSource"), ("kothernumeric", "kOtherNumeric"), + ("kprimarynumeric", "kPrimaryNumeric"), ("krsunicode", "kRSUnicode"), + ("lb", "Line_Break"), ("lc", "Lowercase_Mapping"), + ("linebreak", "Line_Break"), ("loe", "Logical_Order_Exception"), + ("logicalorderexception", "Logical_Order_Exception"), + ("lower", "Lowercase"), ("lowercase", "Lowercase"), + ("lowercasemapping", "Lowercase_Mapping"), ("math", "Math"), ("na", "Name"), + ("na1", "Unicode_1_Name"), ("name", "Name"), ("namealias", "Name_Alias"), + ("nchar", "Noncharacter_Code_Point"), ("nfcqc", "NFC_Quick_Check"), + ("nfcquickcheck", "NFC_Quick_Check"), ("nfdqc", "NFD_Quick_Check"), + ("nfdquickcheck", "NFD_Quick_Check"), ("nfkccasefold", "NFKC_Casefold"), + ("nfkccf", "NFKC_Casefold"), ("nfkcqc", "NFKC_Quick_Check"), + ("nfkcquickcheck", "NFKC_Quick_Check"), ("nfkdqc", "NFKD_Quick_Check"), + ("nfkdquickcheck", "NFKD_Quick_Check"), + ("noncharactercodepoint", "Noncharacter_Code_Point"), + ("nt", "Numeric_Type"), ("numerictype", "Numeric_Type"), + ("numericvalue", "Numeric_Value"), ("nv", "Numeric_Value"), + ("oalpha", "Other_Alphabetic"), ("ocomment", "ISO_Comment"), + ("odi", "Other_Default_Ignorable_Code_Point"), + ("ogrext", "Other_Grapheme_Extend"), ("oidc", "Other_ID_Continue"), + ("oids", "Other_ID_Start"), ("olower", "Other_Lowercase"), + ("omath", "Other_Math"), ("otheralphabetic", "Other_Alphabetic"), + ("otherdefaultignorablecodepoint", "Other_Default_Ignorable_Code_Point"), + ("othergraphemeextend", "Other_Grapheme_Extend"), + ("otheridcontinue", "Other_ID_Continue"), + ("otheridstart", "Other_ID_Start"), ("otherlowercase", "Other_Lowercase"), + ("othermath", "Other_Math"), ("otheruppercase", "Other_Uppercase"), + ("oupper", "Other_Uppercase"), ("patsyn", "Pattern_Syntax"), + ("patternsyntax", "Pattern_Syntax"), + ("patternwhitespace", "Pattern_White_Space"), + ("patws", "Pattern_White_Space"), ("pcm", "Prepended_Concatenation_Mark"), + ("prependedconcatenationmark", "Prepended_Concatenation_Mark"), + ("qmark", "Quotation_Mark"), ("quotationmark", "Quotation_Mark"), + ("radical", "Radical"), ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), ("sb", "Sentence_Break"), ("sc", "Script"), + ("scf", "Simple_Case_Folding"), ("script", "Script"), + ("scriptextensions", "Script_Extensions"), ("scx", "Script_Extensions"), + ("sd", "Soft_Dotted"), ("sentencebreak", "Sentence_Break"), + ("sentenceterminal", "Sentence_Terminal"), ("sfc", "Simple_Case_Folding"), + ("simplecasefolding", "Simple_Case_Folding"), + ("simplelowercasemapping", "Simple_Lowercase_Mapping"), + ("simpletitlecasemapping", "Simple_Titlecase_Mapping"), + ("simpleuppercasemapping", "Simple_Uppercase_Mapping"), + ("slc", "Simple_Lowercase_Mapping"), ("softdotted", "Soft_Dotted"), + ("space", "White_Space"), ("stc", "Simple_Titlecase_Mapping"), + ("sterm", "Sentence_Terminal"), ("suc", "Simple_Uppercase_Mapping"), + ("tc", "Titlecase_Mapping"), ("term", "Terminal_Punctuation"), + ("terminalpunctuation", "Terminal_Punctuation"), + ("titlecasemapping", "Titlecase_Mapping"), ("uc", "Uppercase_Mapping"), + ("uideo", "Unified_Ideograph"), ("unicode1name", "Unicode_1_Name"), + ("unicoderadicalstroke", "kRSUnicode"), + ("unifiedideograph", "Unified_Ideograph"), ("upper", "Uppercase"), + ("uppercase", "Uppercase"), ("uppercasemapping", "Uppercase_Mapping"), + ("urs", "kRSUnicode"), ("variationselector", "Variation_Selector"), + ("verticalorientation", "Vertical_Orientation"), + ("vo", "Vertical_Orientation"), ("vs", "Variation_Selector"), + ("wb", "Word_Break"), ("whitespace", "White_Space"), + ("wordbreak", "Word_Break"), ("wspace", "White_Space"), + ("xidc", "XID_Continue"), ("xidcontinue", "XID_Continue"), + ("xids", "XID_Start"), ("xidstart", "XID_Start"), + ("xonfc", "Expands_On_NFC"), ("xonfd", "Expands_On_NFD"), + ("xonfkc", "Expands_On_NFKC"), ("xonfkd", "Expands_On_NFKD"), +]; diff --git a/regex-syntax/src/unicode_tables/property_values.rs b/regex-syntax/src/unicode_tables/property_values.rs new file mode 100644 index 000000000..e2b0e9648 --- /dev/null +++ b/regex-syntax/src/unicode_tables/property_values.rs @@ -0,0 +1,326 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-values /home/andrew/tmp/ucd-11.0.0/ --include gc,script,scx,age,gcb,wb,sb +// +// ucd-generate is available on crates.io. + +pub const PROPERTY_VALUES: &'static [(&'static str, &'static [(&'static str, &'static str)])] = &[ + ("Age", &[("1.1", "V1_1"), ("10.0", "V10_0"), ("11.0", "V11_0"), + ("2.0", "V2_0"), ("2.1", "V2_1"), ("3.0", "V3_0"), ("3.1", "V3_1"), + ("3.2", "V3_2"), ("4.0", "V4_0"), ("4.1", "V4_1"), ("5.0", "V5_0"), + ("5.1", "V5_1"), ("5.2", "V5_2"), ("6.0", "V6_0"), ("6.1", "V6_1"), + ("6.2", "V6_2"), ("6.3", "V6_3"), ("7.0", "V7_0"), ("8.0", "V8_0"), + ("9.0", "V9_0"), ("na", "Unassigned"), ("unassigned", "Unassigned"), + ("v100", "V10_0"), ("v11", "V1_1"), ("v110", "V11_0"), ("v20", "V2_0"), + ("v21", "V2_1"), ("v30", "V3_0"), ("v31", "V3_1"), ("v32", "V3_2"), + ("v40", "V4_0"), ("v41", "V4_1"), ("v50", "V5_0"), ("v51", "V5_1"), + ("v52", "V5_2"), ("v60", "V6_0"), ("v61", "V6_1"), ("v62", "V6_2"), + ("v63", "V6_3"), ("v70", "V7_0"), ("v80", "V8_0"), ("v90", "V9_0"), ]), + + ("General_Category", &[("c", "Other"), ("casedletter", "Cased_Letter"), + ("cc", "Control"), ("cf", "Format"), + ("closepunctuation", "Close_Punctuation"), ("cn", "Unassigned"), + ("cntrl", "Control"), ("co", "Private_Use"), ("combiningmark", "Mark"), + ("connectorpunctuation", "Connector_Punctuation"), ("control", "Control"), + ("cs", "Surrogate"), ("currencysymbol", "Currency_Symbol"), + ("dashpunctuation", "Dash_Punctuation"), + ("decimalnumber", "Decimal_Number"), ("digit", "Decimal_Number"), + ("enclosingmark", "Enclosing_Mark"), + ("finalpunctuation", "Final_Punctuation"), ("format", "Format"), + ("initialpunctuation", "Initial_Punctuation"), ("l", "Letter"), + ("lc", "Cased_Letter"), ("letter", "Letter"), + ("letternumber", "Letter_Number"), ("lineseparator", "Line_Separator"), + ("ll", "Lowercase_Letter"), ("lm", "Modifier_Letter"), + ("lo", "Other_Letter"), ("lowercaseletter", "Lowercase_Letter"), + ("lt", "Titlecase_Letter"), ("lu", "Uppercase_Letter"), ("m", "Mark"), + ("mark", "Mark"), ("mathsymbol", "Math_Symbol"), ("mc", "Spacing_Mark"), + ("me", "Enclosing_Mark"), ("mn", "Nonspacing_Mark"), + ("modifierletter", "Modifier_Letter"), + ("modifiersymbol", "Modifier_Symbol"), ("n", "Number"), + ("nd", "Decimal_Number"), ("nl", "Letter_Number"), ("no", "Other_Number"), + ("nonspacingmark", "Nonspacing_Mark"), ("number", "Number"), + ("openpunctuation", "Open_Punctuation"), ("other", "Other"), + ("otherletter", "Other_Letter"), ("othernumber", "Other_Number"), + ("otherpunctuation", "Other_Punctuation"), ("othersymbol", "Other_Symbol"), + ("p", "Punctuation"), ("paragraphseparator", "Paragraph_Separator"), + ("pc", "Connector_Punctuation"), ("pd", "Dash_Punctuation"), + ("pe", "Close_Punctuation"), ("pf", "Final_Punctuation"), + ("pi", "Initial_Punctuation"), ("po", "Other_Punctuation"), + ("privateuse", "Private_Use"), ("ps", "Open_Punctuation"), + ("punct", "Punctuation"), ("punctuation", "Punctuation"), ("s", "Symbol"), + ("sc", "Currency_Symbol"), ("separator", "Separator"), + ("sk", "Modifier_Symbol"), ("sm", "Math_Symbol"), ("so", "Other_Symbol"), + ("spaceseparator", "Space_Separator"), ("spacingmark", "Spacing_Mark"), + ("surrogate", "Surrogate"), ("symbol", "Symbol"), + ("titlecaseletter", "Titlecase_Letter"), ("unassigned", "Unassigned"), + ("uppercaseletter", "Uppercase_Letter"), ("z", "Separator"), + ("zl", "Line_Separator"), ("zp", "Paragraph_Separator"), + ("zs", "Space_Separator"), ]), + + ("Grapheme_Cluster_Break", &[("cn", "Control"), ("control", "Control"), + ("cr", "CR"), ("eb", "E_Base"), ("ebase", "E_Base"), + ("ebasegaz", "E_Base_GAZ"), ("ebg", "E_Base_GAZ"), ("em", "E_Modifier"), + ("emodifier", "E_Modifier"), ("ex", "Extend"), ("extend", "Extend"), + ("gaz", "Glue_After_Zwj"), ("glueafterzwj", "Glue_After_Zwj"), ("l", "L"), + ("lf", "LF"), ("lv", "LV"), ("lvt", "LVT"), ("other", "Other"), + ("pp", "Prepend"), ("prepend", "Prepend"), + ("regionalindicator", "Regional_Indicator"), ("ri", "Regional_Indicator"), + ("sm", "SpacingMark"), ("spacingmark", "SpacingMark"), ("t", "T"), + ("v", "V"), ("xx", "Other"), ("zwj", "ZWJ"), ]), + + ("Script", &[("adlam", "Adlam"), ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), ("arab", "Arabic"), + ("arabic", "Arabic"), ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), ("armn", "Armenian"), ("avestan", "Avestan"), + ("avst", "Avestan"), ("bali", "Balinese"), ("balinese", "Balinese"), + ("bamu", "Bamum"), ("bamum", "Bamum"), ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), ("batak", "Batak"), ("batk", "Batak"), + ("beng", "Bengali"), ("bengali", "Bengali"), ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), ("bopo", "Bopomofo"), ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), ("brahmi", "Brahmi"), ("brai", "Braille"), + ("braille", "Braille"), ("bugi", "Buginese"), ("buginese", "Buginese"), + ("buhd", "Buhid"), ("buhid", "Buhid"), ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), ("cari", "Carian"), ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), ("chakma", "Chakma"), + ("cham", "Cham"), ("cher", "Cherokee"), ("cherokee", "Cherokee"), + ("common", "Common"), ("copt", "Coptic"), ("coptic", "Coptic"), + ("cprt", "Cypriot"), ("cuneiform", "Cuneiform"), ("cypriot", "Cypriot"), + ("cyrillic", "Cyrillic"), ("cyrl", "Cyrillic"), ("deseret", "Deseret"), + ("deva", "Devanagari"), ("devanagari", "Devanagari"), ("dogr", "Dogra"), + ("dogra", "Dogra"), ("dsrt", "Deseret"), ("dupl", "Duployan"), + ("duployan", "Duployan"), ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), ("elba", "Elbasan"), + ("elbasan", "Elbasan"), ("ethi", "Ethiopic"), ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), ("georgian", "Georgian"), ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), ("goth", "Gothic"), ("gothic", "Gothic"), + ("gran", "Grantha"), ("grantha", "Grantha"), ("greek", "Greek"), + ("grek", "Greek"), ("gujarati", "Gujarati"), ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), ("han", "Han"), ("hang", "Hangul"), + ("hangul", "Hangul"), ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), ("hatr", "Hatran"), ("hatran", "Hatran"), + ("hebr", "Hebrew"), ("hebrew", "Hebrew"), ("hira", "Hiragana"), + ("hiragana", "Hiragana"), ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), ("ital", "Old_Italic"), + ("java", "Javanese"), ("javanese", "Javanese"), ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), ("kana", "Katakana"), ("kannada", "Kannada"), + ("katakana", "Katakana"), ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kayahli", "Kayah_Li"), ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), ("khmer", "Khmer"), ("khmr", "Khmer"), + ("khoj", "Khojki"), ("khojki", "Khojki"), ("khudawadi", "Khudawadi"), + ("knda", "Kannada"), ("kthi", "Kaithi"), ("lana", "Tai_Tham"), + ("lao", "Lao"), ("laoo", "Lao"), ("latin", "Latin"), ("latn", "Latin"), + ("lepc", "Lepcha"), ("lepcha", "Lepcha"), ("limb", "Limbu"), + ("limbu", "Limbu"), ("lina", "Linear_A"), ("linb", "Linear_B"), + ("lineara", "Linear_A"), ("linearb", "Linear_B"), ("lisu", "Lisu"), + ("lyci", "Lycian"), ("lycian", "Lycian"), ("lydi", "Lydian"), + ("lydian", "Lydian"), ("mahajani", "Mahajani"), ("mahj", "Mahajani"), + ("maka", "Makasar"), ("makasar", "Makasar"), ("malayalam", "Malayalam"), + ("mand", "Mandaic"), ("mandaic", "Mandaic"), ("mani", "Manichaean"), + ("manichaean", "Manichaean"), ("marc", "Marchen"), ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), ("miao", "Miao"), + ("mlym", "Malayalam"), ("modi", "Modi"), ("mong", "Mongolian"), + ("mongolian", "Mongolian"), ("mro", "Mro"), ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), ("mult", "Multani"), ("multani", "Multani"), + ("myanmar", "Myanmar"), ("mymr", "Myanmar"), ("nabataean", "Nabataean"), + ("narb", "Old_North_Arabian"), ("nbat", "Nabataean"), ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), ("nko", "Nko"), ("nkoo", "Nko"), + ("nshu", "Nushu"), ("nushu", "Nushu"), ("ogam", "Ogham"), + ("ogham", "Ogham"), ("olchiki", "Ol_Chiki"), ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), ("oldturkic", "Old_Turkic"), + ("oriya", "Oriya"), ("orkh", "Old_Turkic"), ("orya", "Oriya"), + ("osage", "Osage"), ("osge", "Osage"), ("osma", "Osmanya"), + ("osmanya", "Osmanya"), ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), ("palmyrene", "Palmyrene"), ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), ("perm", "Old_Permic"), ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), ("qaai", "Inherited"), ("rejang", "Rejang"), + ("rjng", "Rejang"), ("rohg", "Hanifi_Rohingya"), ("runic", "Runic"), + ("runr", "Runic"), ("samaritan", "Samaritan"), ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), ("sgnw", "SignWriting"), + ("sharada", "Sharada"), ("shavian", "Shavian"), ("shaw", "Shavian"), + ("shrd", "Sharada"), ("sidd", "Siddham"), ("siddham", "Siddham"), + ("signwriting", "SignWriting"), ("sind", "Khudawadi"), ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), ("sogd", "Sogdian"), ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), ("sund", "Sundanese"), ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), ("syriac", "Syriac"), ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), ("tagbanwa", "Tagbanwa"), ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), ("taiviet", "Tai_Viet"), ("takr", "Takri"), + ("takri", "Takri"), ("tale", "Tai_Le"), ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), ("taml", "Tamil"), ("tang", "Tangut"), + ("tangut", "Tangut"), ("tavt", "Tai_Viet"), ("telu", "Telugu"), + ("telugu", "Telugu"), ("tfng", "Tifinagh"), ("tglg", "Tagalog"), + ("thaa", "Thaana"), ("thaana", "Thaana"), ("thai", "Thai"), + ("tibetan", "Tibetan"), ("tibt", "Tibetan"), ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), ("tirhuta", "Tirhuta"), ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), ("unknown", "Unknown"), ("vai", "Vai"), + ("vaii", "Vai"), ("wara", "Warang_Citi"), ("warangciti", "Warang_Citi"), + ("xpeo", "Old_Persian"), ("xsux", "Cuneiform"), ("yi", "Yi"), + ("yiii", "Yi"), ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), ("zinh", "Inherited"), ("zyyy", "Common"), + ("zzzz", "Unknown"), ]), + + ("Script_Extensions", &[("adlam", "Adlam"), ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), ("arab", "Arabic"), + ("arabic", "Arabic"), ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), ("armn", "Armenian"), ("avestan", "Avestan"), + ("avst", "Avestan"), ("bali", "Balinese"), ("balinese", "Balinese"), + ("bamu", "Bamum"), ("bamum", "Bamum"), ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), ("batak", "Batak"), ("batk", "Batak"), + ("beng", "Bengali"), ("bengali", "Bengali"), ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), ("bopo", "Bopomofo"), ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), ("brahmi", "Brahmi"), ("brai", "Braille"), + ("braille", "Braille"), ("bugi", "Buginese"), ("buginese", "Buginese"), + ("buhd", "Buhid"), ("buhid", "Buhid"), ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), ("cari", "Carian"), ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), ("chakma", "Chakma"), + ("cham", "Cham"), ("cher", "Cherokee"), ("cherokee", "Cherokee"), + ("common", "Common"), ("copt", "Coptic"), ("coptic", "Coptic"), + ("cprt", "Cypriot"), ("cuneiform", "Cuneiform"), ("cypriot", "Cypriot"), + ("cyrillic", "Cyrillic"), ("cyrl", "Cyrillic"), ("deseret", "Deseret"), + ("deva", "Devanagari"), ("devanagari", "Devanagari"), ("dogr", "Dogra"), + ("dogra", "Dogra"), ("dsrt", "Deseret"), ("dupl", "Duployan"), + ("duployan", "Duployan"), ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), ("elba", "Elbasan"), + ("elbasan", "Elbasan"), ("ethi", "Ethiopic"), ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), ("georgian", "Georgian"), ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), ("goth", "Gothic"), ("gothic", "Gothic"), + ("gran", "Grantha"), ("grantha", "Grantha"), ("greek", "Greek"), + ("grek", "Greek"), ("gujarati", "Gujarati"), ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), ("han", "Han"), ("hang", "Hangul"), + ("hangul", "Hangul"), ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), ("hatr", "Hatran"), ("hatran", "Hatran"), + ("hebr", "Hebrew"), ("hebrew", "Hebrew"), ("hira", "Hiragana"), + ("hiragana", "Hiragana"), ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), ("ital", "Old_Italic"), + ("java", "Javanese"), ("javanese", "Javanese"), ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), ("kana", "Katakana"), ("kannada", "Kannada"), + ("katakana", "Katakana"), ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kayahli", "Kayah_Li"), ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), ("khmer", "Khmer"), ("khmr", "Khmer"), + ("khoj", "Khojki"), ("khojki", "Khojki"), ("khudawadi", "Khudawadi"), + ("knda", "Kannada"), ("kthi", "Kaithi"), ("lana", "Tai_Tham"), + ("lao", "Lao"), ("laoo", "Lao"), ("latin", "Latin"), ("latn", "Latin"), + ("lepc", "Lepcha"), ("lepcha", "Lepcha"), ("limb", "Limbu"), + ("limbu", "Limbu"), ("lina", "Linear_A"), ("linb", "Linear_B"), + ("lineara", "Linear_A"), ("linearb", "Linear_B"), ("lisu", "Lisu"), + ("lyci", "Lycian"), ("lycian", "Lycian"), ("lydi", "Lydian"), + ("lydian", "Lydian"), ("mahajani", "Mahajani"), ("mahj", "Mahajani"), + ("maka", "Makasar"), ("makasar", "Makasar"), ("malayalam", "Malayalam"), + ("mand", "Mandaic"), ("mandaic", "Mandaic"), ("mani", "Manichaean"), + ("manichaean", "Manichaean"), ("marc", "Marchen"), ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), ("miao", "Miao"), + ("mlym", "Malayalam"), ("modi", "Modi"), ("mong", "Mongolian"), + ("mongolian", "Mongolian"), ("mro", "Mro"), ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), ("mult", "Multani"), ("multani", "Multani"), + ("myanmar", "Myanmar"), ("mymr", "Myanmar"), ("nabataean", "Nabataean"), + ("narb", "Old_North_Arabian"), ("nbat", "Nabataean"), ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), ("nko", "Nko"), ("nkoo", "Nko"), + ("nshu", "Nushu"), ("nushu", "Nushu"), ("ogam", "Ogham"), + ("ogham", "Ogham"), ("olchiki", "Ol_Chiki"), ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), ("oldturkic", "Old_Turkic"), + ("oriya", "Oriya"), ("orkh", "Old_Turkic"), ("orya", "Oriya"), + ("osage", "Osage"), ("osge", "Osage"), ("osma", "Osmanya"), + ("osmanya", "Osmanya"), ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), ("palmyrene", "Palmyrene"), ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), ("perm", "Old_Permic"), ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), ("qaai", "Inherited"), ("rejang", "Rejang"), + ("rjng", "Rejang"), ("rohg", "Hanifi_Rohingya"), ("runic", "Runic"), + ("runr", "Runic"), ("samaritan", "Samaritan"), ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), ("sgnw", "SignWriting"), + ("sharada", "Sharada"), ("shavian", "Shavian"), ("shaw", "Shavian"), + ("shrd", "Sharada"), ("sidd", "Siddham"), ("siddham", "Siddham"), + ("signwriting", "SignWriting"), ("sind", "Khudawadi"), ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), ("sogd", "Sogdian"), ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), ("sund", "Sundanese"), ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), ("syriac", "Syriac"), ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), ("tagbanwa", "Tagbanwa"), ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), ("taiviet", "Tai_Viet"), ("takr", "Takri"), + ("takri", "Takri"), ("tale", "Tai_Le"), ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), ("taml", "Tamil"), ("tang", "Tangut"), + ("tangut", "Tangut"), ("tavt", "Tai_Viet"), ("telu", "Telugu"), + ("telugu", "Telugu"), ("tfng", "Tifinagh"), ("tglg", "Tagalog"), + ("thaa", "Thaana"), ("thaana", "Thaana"), ("thai", "Thai"), + ("tibetan", "Tibetan"), ("tibt", "Tibetan"), ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), ("tirhuta", "Tirhuta"), ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), ("unknown", "Unknown"), ("vai", "Vai"), + ("vaii", "Vai"), ("wara", "Warang_Citi"), ("warangciti", "Warang_Citi"), + ("xpeo", "Old_Persian"), ("xsux", "Cuneiform"), ("yi", "Yi"), + ("yiii", "Yi"), ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), ("zinh", "Inherited"), ("zyyy", "Common"), + ("zzzz", "Unknown"), ]), + + ("Sentence_Break", &[("at", "ATerm"), ("aterm", "ATerm"), ("cl", "Close"), + ("close", "Close"), ("cr", "CR"), ("ex", "Extend"), ("extend", "Extend"), + ("fo", "Format"), ("format", "Format"), ("le", "OLetter"), ("lf", "LF"), + ("lo", "Lower"), ("lower", "Lower"), ("nu", "Numeric"), + ("numeric", "Numeric"), ("oletter", "OLetter"), ("other", "Other"), + ("sc", "SContinue"), ("scontinue", "SContinue"), ("se", "Sep"), + ("sep", "Sep"), ("sp", "Sp"), ("st", "STerm"), ("sterm", "STerm"), + ("up", "Upper"), ("upper", "Upper"), ("xx", "Other"), ]), + + ("Word_Break", &[("aletter", "ALetter"), ("cr", "CR"), + ("doublequote", "Double_Quote"), ("dq", "Double_Quote"), ("eb", "E_Base"), + ("ebase", "E_Base"), ("ebasegaz", "E_Base_GAZ"), ("ebg", "E_Base_GAZ"), + ("em", "E_Modifier"), ("emodifier", "E_Modifier"), ("ex", "ExtendNumLet"), + ("extend", "Extend"), ("extendnumlet", "ExtendNumLet"), ("fo", "Format"), + ("format", "Format"), ("gaz", "Glue_After_Zwj"), + ("glueafterzwj", "Glue_After_Zwj"), ("hebrewletter", "Hebrew_Letter"), + ("hl", "Hebrew_Letter"), ("ka", "Katakana"), ("katakana", "Katakana"), + ("le", "ALetter"), ("lf", "LF"), ("mb", "MidNumLet"), + ("midletter", "MidLetter"), ("midnum", "MidNum"), + ("midnumlet", "MidNumLet"), ("ml", "MidLetter"), ("mn", "MidNum"), + ("newline", "Newline"), ("nl", "Newline"), ("nu", "Numeric"), + ("numeric", "Numeric"), ("other", "Other"), + ("regionalindicator", "Regional_Indicator"), ("ri", "Regional_Indicator"), + ("singlequote", "Single_Quote"), ("sq", "Single_Quote"), + ("wsegspace", "WSegSpace"), ("xx", "Other"), ("zwj", "ZWJ"), ]), +]; diff --git a/regex-syntax/src/unicode_tables/script.rs b/regex-syntax/src/unicode_tables/script.rs new file mode 100644 index 000000000..b9b65b5dd --- /dev/null +++ b/regex-syntax/src/unicode_tables/script.rs @@ -0,0 +1,801 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate script tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Adlam", ADLAM), ("Ahom", AHOM), + ("Anatolian_Hieroglyphs", ANATOLIAN_HIEROGLYPHS), ("Arabic", ARABIC), + ("Armenian", ARMENIAN), ("Avestan", AVESTAN), ("Balinese", BALINESE), + ("Bamum", BAMUM), ("Bassa_Vah", BASSA_VAH), ("Batak", BATAK), + ("Bengali", BENGALI), ("Bhaiksuki", BHAIKSUKI), ("Bopomofo", BOPOMOFO), + ("Brahmi", BRAHMI), ("Braille", BRAILLE), ("Buginese", BUGINESE), + ("Buhid", BUHID), ("Canadian_Aboriginal", CANADIAN_ABORIGINAL), + ("Carian", CARIAN), ("Caucasian_Albanian", CAUCASIAN_ALBANIAN), + ("Chakma", CHAKMA), ("Cham", CHAM), ("Cherokee", CHEROKEE), + ("Common", COMMON), ("Coptic", COPTIC), ("Cuneiform", CUNEIFORM), + ("Cypriot", CYPRIOT), ("Cyrillic", CYRILLIC), ("Deseret", DESERET), + ("Devanagari", DEVANAGARI), ("Dogra", DOGRA), ("Duployan", DUPLOYAN), + ("Egyptian_Hieroglyphs", EGYPTIAN_HIEROGLYPHS), ("Elbasan", ELBASAN), + ("Ethiopic", ETHIOPIC), ("Georgian", GEORGIAN), ("Glagolitic", GLAGOLITIC), + ("Gothic", GOTHIC), ("Grantha", GRANTHA), ("Greek", GREEK), + ("Gujarati", GUJARATI), ("Gunjala_Gondi", GUNJALA_GONDI), + ("Gurmukhi", GURMUKHI), ("Han", HAN), ("Hangul", HANGUL), + ("Hanifi_Rohingya", HANIFI_ROHINGYA), ("Hanunoo", HANUNOO), + ("Hatran", HATRAN), ("Hebrew", HEBREW), ("Hiragana", HIRAGANA), + ("Imperial_Aramaic", IMPERIAL_ARAMAIC), ("Inherited", INHERITED), + ("Inscriptional_Pahlavi", INSCRIPTIONAL_PAHLAVI), + ("Inscriptional_Parthian", INSCRIPTIONAL_PARTHIAN), ("Javanese", JAVANESE), + ("Kaithi", KAITHI), ("Kannada", KANNADA), ("Katakana", KATAKANA), + ("Kayah_Li", KAYAH_LI), ("Kharoshthi", KHAROSHTHI), ("Khmer", KHMER), + ("Khojki", KHOJKI), ("Khudawadi", KHUDAWADI), ("Lao", LAO), + ("Latin", LATIN), ("Lepcha", LEPCHA), ("Limbu", LIMBU), + ("Linear_A", LINEAR_A), ("Linear_B", LINEAR_B), ("Lisu", LISU), + ("Lycian", LYCIAN), ("Lydian", LYDIAN), ("Mahajani", MAHAJANI), + ("Makasar", MAKASAR), ("Malayalam", MALAYALAM), ("Mandaic", MANDAIC), + ("Manichaean", MANICHAEAN), ("Marchen", MARCHEN), + ("Masaram_Gondi", MASARAM_GONDI), ("Medefaidrin", MEDEFAIDRIN), + ("Meetei_Mayek", MEETEI_MAYEK), ("Mende_Kikakui", MENDE_KIKAKUI), + ("Meroitic_Cursive", MEROITIC_CURSIVE), + ("Meroitic_Hieroglyphs", MEROITIC_HIEROGLYPHS), ("Miao", MIAO), + ("Modi", MODI), ("Mongolian", MONGOLIAN), ("Mro", MRO), + ("Multani", MULTANI), ("Myanmar", MYANMAR), ("Nabataean", NABATAEAN), + ("New_Tai_Lue", NEW_TAI_LUE), ("Newa", NEWA), ("Nko", NKO), + ("Nushu", NUSHU), ("Ogham", OGHAM), ("Ol_Chiki", OL_CHIKI), + ("Old_Hungarian", OLD_HUNGARIAN), ("Old_Italic", OLD_ITALIC), + ("Old_North_Arabian", OLD_NORTH_ARABIAN), ("Old_Permic", OLD_PERMIC), + ("Old_Persian", OLD_PERSIAN), ("Old_Sogdian", OLD_SOGDIAN), + ("Old_South_Arabian", OLD_SOUTH_ARABIAN), ("Old_Turkic", OLD_TURKIC), + ("Oriya", ORIYA), ("Osage", OSAGE), ("Osmanya", OSMANYA), + ("Pahawh_Hmong", PAHAWH_HMONG), ("Palmyrene", PALMYRENE), + ("Pau_Cin_Hau", PAU_CIN_HAU), ("Phags_Pa", PHAGS_PA), + ("Phoenician", PHOENICIAN), ("Psalter_Pahlavi", PSALTER_PAHLAVI), + ("Rejang", REJANG), ("Runic", RUNIC), ("Samaritan", SAMARITAN), + ("Saurashtra", SAURASHTRA), ("Sharada", SHARADA), ("Shavian", SHAVIAN), + ("Siddham", SIDDHAM), ("SignWriting", SIGNWRITING), ("Sinhala", SINHALA), + ("Sogdian", SOGDIAN), ("Sora_Sompeng", SORA_SOMPENG), ("Soyombo", SOYOMBO), + ("Sundanese", SUNDANESE), ("Syloti_Nagri", SYLOTI_NAGRI), + ("Syriac", SYRIAC), ("Tagalog", TAGALOG), ("Tagbanwa", TAGBANWA), + ("Tai_Le", TAI_LE), ("Tai_Tham", TAI_THAM), ("Tai_Viet", TAI_VIET), + ("Takri", TAKRI), ("Tamil", TAMIL), ("Tangut", TANGUT), ("Telugu", TELUGU), + ("Thaana", THAANA), ("Thai", THAI), ("Tibetan", TIBETAN), + ("Tifinagh", TIFINAGH), ("Tirhuta", TIRHUTA), ("Ugaritic", UGARITIC), + ("Vai", VAI), ("Warang_Citi", WARANG_CITI), ("Yi", YI), + ("Zanabazar_Square", ZANABAZAR_SQUARE), +]; + +pub const ADLAM: &'static [(char, char)] = &[ + ('𞤀', '𞥊'), ('𞥐', '𞥙'), ('𞥞', '𞥟'), +]; + +pub const AHOM: &'static [(char, char)] = &[ + ('𑜀', '\u{1171a}'), ('𑜝', '𑜫'), ('𑜰', '𑜿'), +]; + +pub const ANATOLIAN_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𔐀', '𔙆'), +]; + +pub const ARABIC: &'static [(char, char)] = &[ + ('\u{600}', '\u{604}'), ('؆', '؋'), ('؍', 'ؚ'), ('\u{61c}', '\u{61c}'), + ('؞', '؞'), ('Ø ', 'Ø¿'), ('ف', 'ي'), ('ٖ', 'Ù¯'), ('Ù±', 'ۜ'), + ('۞', 'Û¿'), ('ݐ', 'Ý¿'), ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), + ('\u{8d3}', '࣡'), ('ࣣ', 'ࣿ'), ('ﭐ', '﯁'), ('ﯓ', 'ï´½'), + ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·½'), ('ï¹°', 'ï¹´'), + ('ï¹¶', 'ﻼ'), ('𐹠', '𐹾'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𞻰', '𞻱'), +]; + +pub const ARMENIAN: &'static [(char, char)] = &[ + ('Ô±', 'Ֆ'), ('ՙ', '\u{588}'), ('֊', '֊'), ('֍', '֏'), ('ﬓ', 'ﬗ'), +]; + +pub const AVESTAN: &'static [(char, char)] = &[ + ('𐬀', '𐬵'), ('𐬹', '𐬿'), +]; + +pub const BALINESE: &'static [(char, char)] = &[ + ('ᬀ', 'ᭋ'), ('᭐', 'á­¼'), +]; + +pub const BAMUM: &'static [(char, char)] = &[ + ('ꚠ', '꛷'), ('𖠀', '𖨸'), +]; + +pub const BASSA_VAH: &'static [(char, char)] = &[ + ('𖫐', '𖫭'), ('𖫰', '𖫵'), +]; + +pub const BATAK: &'static [(char, char)] = &[ + ('ᯀ', '᯳'), ('᯼', '᯿'), +]; + +pub const BENGALI: &'static [(char, char)] = &[ + ('ঀ', 'ঃ'), ('অ', 'ঌ'), ('এ', 'ঐ'), ('ও', 'ন'), + ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), ('়', 'ৄ'), + ('ে', 'ৈ'), ('ো', 'ৎ'), ('ৗ', 'ৗ'), ('ড়', 'ঢ়'), + ('য়', 'à§£'), ('০', '\u{9fe}'), +]; + +pub const BHAIKSUKI: &'static [(char, char)] = &[ + ('𑰀', '𑰈'), ('𑰊', '𑰶'), ('𑰸', '𑱅'), ('𑱐', '𑱬'), +]; + +pub const BOPOMOFO: &'static [(char, char)] = &[ + ('˪', 'Ë«'), ('ㄅ', '\u{312f}'), ('ㆠ', 'ㆺ'), +]; + +pub const BRAHMI: &'static [(char, char)] = &[ + ('𑀀', '𑁍'), ('𑁒', '𑁯'), ('𑁿', '𑁿'), +]; + +pub const BRAILLE: &'static [(char, char)] = &[ + ('⠀', '⣿'), +]; + +pub const BUGINESE: &'static [(char, char)] = &[ + ('ᨀ', 'ᨛ'), ('᨞', '᨟'), +]; + +pub const BUHID: &'static [(char, char)] = &[ + ('ᝀ', 'ᝓ'), +]; + +pub const CANADIAN_ABORIGINAL: &'static [(char, char)] = &[ + ('᐀', 'ᙿ'), ('ᢰ', 'ᣵ'), +]; + +pub const CARIAN: &'static [(char, char)] = &[ + ('𐊠', '𐋐'), +]; + +pub const CAUCASIAN_ALBANIAN: &'static [(char, char)] = &[ + ('𐔰', '𐕣'), ('𐕯', '𐕯'), +]; + +pub const CHAKMA: &'static [(char, char)] = &[ + ('𑄀', '𑄴'), ('𑄶', '\u{11146}'), +]; + +pub const CHAM: &'static [(char, char)] = &[ + ('ꨀ', 'ꨶ'), ('ꩀ', 'ꩍ'), ('꩐', '꩙'), ('꩜', '꩟'), +]; + +pub const CHEROKEE: &'static [(char, char)] = &[ + ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ê­°', 'ꮿ'), +]; + +pub const COMMON: &'static [(char, char)] = &[ + ('\u{0}', '@'), ('[', '`'), ('{', '©'), ('«', '¹'), ('»', '¿'), + ('×', '×'), ('÷', '÷'), ('ʹ', '˟'), ('Ë¥', 'Ë©'), ('ˬ', 'Ë¿'), + ('Í´', 'Í´'), (';', ';'), ('΅', '΅'), ('·', '·'), ('։', '։'), + ('\u{605}', '\u{605}'), ('،', '،'), ('؛', '؛'), ('؟', '؟'), + ('ـ', 'ـ'), ('\u{6dd}', '\u{6dd}'), ('\u{8e2}', '\u{8e2}'), + ('।', '॥'), ('฿', '฿'), ('࿕', '࿘'), ('჻', '჻'), + ('᛫', '᛭'), ('᜵', '᜶'), ('᠂', '᠃'), ('᠅', '᠅'), + ('᳓', '᳓'), ('᳡', '᳡'), ('ᳩ', 'ᳬ'), ('á³®', 'á³³'), + ('á³µ', 'á³·'), ('\u{2000}', '\u{200b}'), ('\u{200e}', '\u{2064}'), + ('\u{2066}', '⁰'), ('⁴', '⁾'), ('₀', '₎'), ('₠', '₿'), + ('℀', '℥'), ('℧', '℩'), ('ℬ', 'ℱ'), ('ℳ', '⅍'), + ('⅏', '⅟'), ('↉', '↋'), ('←', '␦'), ('⑀', '⑊'), + ('①', '⟿'), ('⤀', 'â­³'), ('â­¶', '⮕'), ('⮘', '⯈'), + ('⯊', '\u{2bfe}'), ('⸀', '\u{2e4e}'), ('â¿°', 'â¿»'), + ('\u{3000}', '〄'), ('〆', '〆'), ('〈', '〠'), ('〰', '〷'), + ('〼', '〿'), ('゛', '゜'), ('゠', '゠'), ('・', 'ー'), + ('㆐', '㆟'), ('㇀', '㇣'), ('㈠', '㉟'), ('㉿', '㋏'), + ('㍘', '㏿'), ('䷀', 'ä·¿'), ('꜀', '꜡'), ('ꞈ', '꞊'), + ('ê °', 'ê ¹'), ('꤮', '꤮'), ('ꧏ', 'ꧏ'), ('꭛', '꭛'), + ('ï´¾', 'ï´¿'), ('︐', '︙'), ('︰', '﹒'), ('﹔', '﹦'), + ('﹨', '﹫'), ('\u{feff}', '\u{feff}'), ('!', 'ï¼ '), ('ï¼»', '`'), + ('{', 'ï½¥'), ('ï½°', 'ï½°'), ('゙', '゚'), ('ï¿ ', '₩'), + ('│', 'ï¿®'), ('\u{fff9}', '�'), ('𐄀', '𐄂'), ('𐄇', '𐄳'), + ('𐄷', '𐄿'), ('𐆐', '𐆛'), ('𐇐', '𐇼'), ('𐋡', '𐋻'), + ('\u{1bca0}', '\u{1bca3}'), ('𝀀', '𝃵'), ('𝄀', '𝄦'), + ('𝄩', '𝅦'), ('𝅪', '\u{1d17a}'), ('𝆃', '𝆄'), ('𝆌', '𝆩'), + ('𝆮', '𝇨'), ('\u{1d2e0}', '\u{1d2f3}'), ('𝌀', '𝍖'), + ('𝍠', '\u{1d378}'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), ('𝒞', '𝒟'), + ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), ('𝒮', '𝒹'), + ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), ('𝔇', '𝔊'), + ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), ('𝔻', '𝔾'), + ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), ('𝕒', '𝚥'), + ('𝚨', '𝟋'), ('𝟎', '𝟿'), ('\u{1ec71}', '\u{1ecb4}'), + ('🀀', '🀫'), ('🀰', '🂓'), ('🂠', '🂮'), ('🂱', '🂿'), + ('🃁', '🃏'), ('🃑', '🃵'), ('🄀', '🄌'), ('🄐', '🅫'), + ('🅰', '🆬'), ('🇦', '🇿'), ('🈁', '🈂'), ('🈐', '🈻'), + ('🉀', '🉈'), ('🉐', '🉑'), ('🉠', '🉥'), ('🌀', '🛔'), + ('🛠', '🛬'), ('🛰', '\u{1f6f9}'), ('🜀', '🝳'), + ('🞀', '\u{1f7d8}'), ('🠀', '🠋'), ('🠐', '🡇'), ('🡐', '🡙'), + ('🡠', '🢇'), ('🢐', '🢭'), ('🤀', '🤋'), ('🤐', '🤾'), + ('🥀', '\u{1f970}'), ('\u{1f973}', '\u{1f976}'), + ('\u{1f97a}', '\u{1f97a}'), ('\u{1f97c}', '\u{1f9a2}'), + ('\u{1f9b0}', '\u{1f9b9}'), ('🧀', '\u{1f9c2}'), ('🧐', '\u{1f9ff}'), + ('\u{1fa60}', '\u{1fa6d}'), ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const COPTIC: &'static [(char, char)] = &[ + ('Ï¢', 'ϯ'), ('Ⲁ', 'â³³'), ('â³¹', '⳿'), +]; + +pub const CUNEIFORM: &'static [(char, char)] = &[ + ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒑰', '𒑴'), ('𒒀', '𒕃'), +]; + +pub const CYPRIOT: &'static [(char, char)] = &[ + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐠿'), +]; + +pub const CYRILLIC: &'static [(char, char)] = &[ + ('Ѐ', '҄'), ('҇', 'Ô¯'), ('ᲀ', 'ᲈ'), ('á´«', 'á´«'), ('ᵸ', 'ᵸ'), + ('â· ', 'â·¿'), ('Ꙁ', 'ꚟ'), ('︮', '︯'), +]; + +pub const DESERET: &'static [(char, char)] = &[ + ('𐐀', '𐑏'), +]; + +pub const DEVANAGARI: &'static [(char, char)] = &[ + ('ऀ', 'ॐ'), ('॓', 'ॣ'), ('०', 'ॿ'), ('꣠', '\u{a8ff}'), +]; + +pub const DOGRA: &'static [(char, char)] = &[ + ('\u{11800}', '\u{1183b}'), +]; + +pub const DUPLOYAN: &'static [(char, char)] = &[ + ('𛰀', '𛱪'), ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), + ('𛲜', '𛲟'), +]; + +pub const EGYPTIAN_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𓀀', '𓐮'), +]; + +pub const ELBASAN: &'static [(char, char)] = &[ + ('𐔀', '𐔧'), +]; + +pub const ETHIOPIC: &'static [(char, char)] = &[ + ('ሀ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), + ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), + ('፝', '፼'), ('ᎀ', '᎙'), ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), + ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), + ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), +]; + +pub const GEORGIAN: &'static [(char, char)] = &[ + ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), ('ა', 'ჺ'), + ('ჼ', 'ჿ'), ('\u{1c90}', '\u{1cba}'), ('\u{1cbd}', '\u{1cbf}'), + ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), +]; + +pub const GLAGOLITIC: &'static [(char, char)] = &[ + ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('𞀀', '𞀆'), ('𞀈', '𞀘'), + ('𞀛', '𞀡'), ('𞀣', '𞀤'), ('𞀦', '𞀪'), +]; + +pub const GOTHIC: &'static [(char, char)] = &[ + ('𐌰', '𐍊'), +]; + +pub const GRANTHA: &'static [(char, char)] = &[ + ('𑌀', '𑌃'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), + ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('𑌼', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍐', '𑍐'), ('𑍗', '𑍗'), + ('𑍝', '𑍣'), ('𑍦', '𑍬'), ('𑍰', '𑍴'), +]; + +pub const GREEK: &'static [(char, char)] = &[ + ('Ͱ', 'ͳ'), ('͵', 'Í·'), ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('΄', '΄'), + ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'Ï¡'), + ('ϰ', 'Ï¿'), ('á´¦', 'á´ª'), ('ᵝ', 'ᵡ'), ('ᵦ', 'ᵪ'), + ('á¶¿', 'á¶¿'), ('ἀ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'ῄ'), + ('ῆ', 'ΐ'), ('ῖ', 'Ί'), ('῝', '`'), ('ῲ', 'á¿´'), + ('á¿¶', '῾'), ('Ω', 'Ω'), ('ê­¥', 'ê­¥'), ('𐅀', '𐆎'), + ('𐆠', '𐆠'), ('𝈀', '𝉅'), +]; + +pub const GUJARATI: &'static [(char, char)] = &[ + ('ઁ', 'ઃ'), ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), + ('પ', 'ર'), ('લ', 'ળ'), ('વ', 'હ'), ('઼', 'ૅ'), + ('ે', 'ૉ'), ('ો', '્'), ('ૐ', 'ૐ'), ('à« ', 'à«£'), + ('૦', '૱'), ('ૹ', 'à«¿'), +]; + +pub const GUNJALA_GONDI: &'static [(char, char)] = &[ + ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d8e}'), ('\u{11d90}', '\u{11d91}'), + ('\u{11d93}', '\u{11d98}'), ('\u{11da0}', '\u{11da9}'), +]; + +pub const GURMUKHI: &'static [(char, char)] = &[ + ('ਁ', 'ਃ'), ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), + ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), + ('਼', '਼'), ('ਾ', 'ੂ'), ('ੇ', 'ੈ'), ('ੋ', '੍'), + ('ੑ', 'ੑ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('੦', '\u{a76}'), +]; + +pub const HAN: &'static [(char, char)] = &[ + ('⺀', '⺙'), ('⺛', '⻳'), ('⼀', '⿕'), ('々', '々'), + ('〇', '〇'), ('〡', '〩'), ('〸', '〻'), ('㐀', 'ä¶µ'), + ('一', '\u{9fef}'), ('豈', 'ï©­'), ('ï©°', '龎'), ('𠀀', '𪛖'), + ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), + ('丽', '𪘀'), +]; + +pub const HANGUL: &'static [(char, char)] = &[ + ('ᄀ', 'ᇿ'), ('〮', '〯'), ('ㄱ', 'ㆎ'), ('㈀', '㈞'), + ('㉠', '㉾'), ('ꥠ', 'ꥼ'), ('가', '힣'), ('ힰ', 'ퟆ'), + ('ퟋ', 'ퟻ'), ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), + ('ᅭ', 'ᅲ'), ('ᅳ', 'ᅵ'), +]; + +pub const HANIFI_ROHINGYA: &'static [(char, char)] = &[ + ('\u{10d00}', '\u{10d27}'), ('\u{10d30}', '\u{10d39}'), +]; + +pub const HANUNOO: &'static [(char, char)] = &[ + ('ᜠ', '᜴'), +]; + +pub const HATRAN: &'static [(char, char)] = &[ + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐣻', '𐣿'), +]; + +pub const HEBREW: &'static [(char, char)] = &[ + ('֑', 'ׇ'), ('א', 'ת'), ('\u{5ef}', '×´'), ('יִ', 'זּ'), + ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), + ('צּ', 'ﭏ'), +]; + +pub const HIRAGANA: &'static [(char, char)] = &[ + ('ぁ', 'ゖ'), ('ゝ', 'ゟ'), ('𛀁', '𛄞'), ('🈀', '🈀'), +]; + +pub const IMPERIAL_ARAMAIC: &'static [(char, char)] = &[ + ('𐡀', '𐡕'), ('𐡗', '𐡟'), +]; + +pub const INHERITED: &'static [(char, char)] = &[ + ('̀', 'ͯ'), ('҅', '҆'), ('ً', 'ٕ'), ('Ù°', 'Ù°'), ('॑', '॒'), + ('᪰', '᪾'), ('᳐', '᳒'), ('᳔', 'á³ '), ('á³¢', '᳨'), + ('á³­', 'á³­'), ('á³´', 'á³´'), ('᳸', 'á³¹'), ('᷀', 'á·¹'), + ('á·»', 'á·¿'), ('\u{200c}', '\u{200d}'), ('⃐', '⃰'), ('〪', '〭'), + ('゙', '゚'), ('︀', '️'), ('︠', '︭'), ('𐇽', '𐇽'), + ('𐋠', '𐋠'), ('\u{1133b}', '\u{1133b}'), ('𝅧', '𝅩'), + ('𝅻', '𝆂'), ('𝆅', '𝆋'), ('𝆪', '𝆭'), ('󠄀', '󠇯'), +]; + +pub const INSCRIPTIONAL_PAHLAVI: &'static [(char, char)] = &[ + ('𐭠', '𐭲'), ('𐭸', '𐭿'), +]; + +pub const INSCRIPTIONAL_PARTHIAN: &'static [(char, char)] = &[ + ('𐭀', '𐭕'), ('𐭘', '𐭟'), +]; + +pub const JAVANESE: &'static [(char, char)] = &[ + ('ꦀ', '꧍'), ('꧐', '꧙'), ('꧞', '꧟'), +]; + +pub const KAITHI: &'static [(char, char)] = &[ + ('𑂀', '𑃁'), ('\u{110cd}', '\u{110cd}'), +]; + +pub const KANNADA: &'static [(char, char)] = &[ + ('ಀ', 'ಌ'), ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), + ('ವ', 'ಹ'), ('಼', 'ೄ'), ('ೆ', 'ೈ'), ('ೊ', '್'), + ('ೕ', 'ೖ'), ('ೞ', 'ೞ'), ('à³ ', 'à³£'), ('೦', '೯'), + ('à³±', 'à³²'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('ァ', 'ヺ'), ('ヽ', 'ヿ'), ('ㇰ', 'ㇿ'), ('㋐', '㋾'), + ('㌀', '㍗'), ('ヲ', 'ッ'), ('ï½±', 'ン'), ('𛀀', '𛀀'), +]; + +pub const KAYAH_LI: &'static [(char, char)] = &[ + ('꤀', '꤭'), ('꤯', '꤯'), +]; + +pub const KHAROSHTHI: &'static [(char, char)] = &[ + ('𐨀', '𐨃'), ('𐨅', '𐨆'), ('𐨌', '𐨓'), ('𐨕', '𐨗'), + ('𐨙', '\u{10a35}'), ('𐨸', '𐨺'), ('𐨿', '\u{10a48}'), + ('𐩐', '𐩘'), +]; + +pub const KHMER: &'static [(char, char)] = &[ + ('ក', '៝'), ('០', '៩'), ('៰', '៹'), ('á§ ', 'á§¿'), +]; + +pub const KHOJKI: &'static [(char, char)] = &[ + ('𑈀', '𑈑'), ('𑈓', '𑈾'), +]; + +pub const KHUDAWADI: &'static [(char, char)] = &[ + ('𑊰', '𑋪'), ('𑋰', '𑋹'), +]; + +pub const LAO: &'static [(char, char)] = &[ + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ູ'), + ('ົ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('່', 'ໍ'), + ('໐', '໙'), ('ໜ', 'ໟ'), +]; + +pub const LATIN: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('º', 'º'), ('À', 'Ö'), + ('Ø', 'ö'), ('ø', 'ʸ'), ('Ë ', 'ˤ'), ('ᴀ', 'á´¥'), ('á´¬', 'ᵜ'), + ('áµ¢', 'áµ¥'), ('ᵫ', 'áµ·'), ('áµ¹', 'á¶¾'), ('Ḁ', 'ỿ'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('K', 'Å'), + ('Ⅎ', 'Ⅎ'), ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), ('â± ', 'Ɀ'), + ('Ꜣ', 'ꞇ'), ('Ꞌ', '\u{a7b9}'), ('ꟷ', 'ꟿ'), ('ꬰ', 'ꭚ'), + ('ꭜ', 'ê­¤'), ('ff', 'st'), ('A', 'Z'), ('a', 'z'), +]; + +pub const LEPCHA: &'static [(char, char)] = &[ + ('ᰀ', 'á°·'), ('á°»', '᱉'), ('ᱍ', 'ᱏ'), +]; + +pub const LIMBU: &'static [(char, char)] = &[ + ('ᤀ', 'ᤞ'), ('ᤠ', 'ᤫ'), ('ᤰ', '᤻'), ('᥀', '᥀'), + ('᥄', '᥏'), +]; + +pub const LINEAR_A: &'static [(char, char)] = &[ + ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), +]; + +pub const LINEAR_B: &'static [(char, char)] = &[ + ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), + ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), +]; + +pub const LISU: &'static [(char, char)] = &[ + ('ꓐ', '꓿'), +]; + +pub const LYCIAN: &'static [(char, char)] = &[ + ('𐊀', '𐊜'), +]; + +pub const LYDIAN: &'static [(char, char)] = &[ + ('𐤠', '𐤹'), ('𐤿', '𐤿'), +]; + +pub const MAHAJANI: &'static [(char, char)] = &[ + ('𑅐', '𑅶'), +]; + +pub const MAKASAR: &'static [(char, char)] = &[ + ('\u{11ee0}', '\u{11ef8}'), +]; + +pub const MALAYALAM: &'static [(char, char)] = &[ + ('ഀ', 'ഃ'), ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'ൄ'), + ('െ', 'ൈ'), ('ൊ', '൏'), ('ൔ', 'ൣ'), ('൦', 'ൿ'), +]; + +pub const MANDAIC: &'static [(char, char)] = &[ + ('ࡀ', '࡛'), ('࡞', '࡞'), +]; + +pub const MANICHAEAN: &'static [(char, char)] = &[ + ('𐫀', '𐫦'), ('𐫫', '𐫶'), +]; + +pub const MARCHEN: &'static [(char, char)] = &[ + ('𑱰', '𑲏'), ('𑲒', '𑲧'), ('𑲩', '𑲶'), +]; + +pub const MASARAM_GONDI: &'static [(char, char)] = &[ + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴶'), ('𑴺', '𑴺'), + ('𑴼', '𑴽'), ('𑴿', '𑵇'), ('𑵐', '𑵙'), +]; + +pub const MEDEFAIDRIN: &'static [(char, char)] = &[ + ('\u{16e40}', '\u{16e9a}'), +]; + +pub const MEETEI_MAYEK: &'static [(char, char)] = &[ + ('ê« ', 'ê«¶'), ('ꯀ', '꯭'), ('꯰', '꯹'), +]; + +pub const MENDE_KIKAKUI: &'static [(char, char)] = &[ + ('𞠀', '𞣄'), ('𞣇', '𞣖'), +]; + +pub const MEROITIC_CURSIVE: &'static [(char, char)] = &[ + ('𐦠', '𐦷'), ('𐦼', '𐧏'), ('𐧒', '𐧿'), +]; + +pub const MEROITIC_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𐦀', '𐦟'), +]; + +pub const MIAO: &'static [(char, char)] = &[ + ('𖼀', '𖽄'), ('𖽐', '𖽾'), ('𖾏', '𖾟'), +]; + +pub const MODI: &'static [(char, char)] = &[ + ('𑘀', '𑙄'), ('𑙐', '𑙙'), +]; + +pub const MONGOLIAN: &'static [(char, char)] = &[ + ('᠀', '᠁'), ('᠄', '᠄'), ('᠆', '\u{180e}'), ('᠐', '᠙'), + ('á  ', '\u{1878}'), ('ᢀ', 'ᢪ'), ('𑙠', '𑙬'), +]; + +pub const MRO: &'static [(char, char)] = &[ + ('𖩀', '𖩞'), ('𖩠', '𖩩'), ('𖩮', '𖩯'), +]; + +pub const MULTANI: &'static [(char, char)] = &[ + ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), + ('𑊟', '𑊩'), +]; + +pub const MYANMAR: &'static [(char, char)] = &[ + ('က', '႟'), ('ê§ ', 'ê§¾'), ('ê© ', 'ê©¿'), +]; + +pub const NABATAEAN: &'static [(char, char)] = &[ + ('𐢀', '𐢞'), ('𐢧', '𐢯'), +]; + +pub const NEW_TAI_LUE: &'static [(char, char)] = &[ + ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('᧐', '᧚'), ('᧞', '᧟'), +]; + +pub const NEWA: &'static [(char, char)] = &[ + ('𑐀', '𑑙'), ('𑑛', '𑑛'), ('𑑝', '\u{1145e}'), +]; + +pub const NKO: &'static [(char, char)] = &[ + ('߀', 'ߺ'), ('\u{7fd}', '\u{7ff}'), +]; + +pub const NUSHU: &'static [(char, char)] = &[ + ('𖿡', '𖿡'), ('𛅰', '𛋻'), +]; + +pub const OGHAM: &'static [(char, char)] = &[ + ('\u{1680}', '᚜'), +]; + +pub const OL_CHIKI: &'static [(char, char)] = &[ + ('᱐', '᱿'), +]; + +pub const OLD_HUNGARIAN: &'static [(char, char)] = &[ + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐳺', '𐳿'), +]; + +pub const OLD_ITALIC: &'static [(char, char)] = &[ + ('𐌀', '𐌣'), ('𐌭', '𐌯'), +]; + +pub const OLD_NORTH_ARABIAN: &'static [(char, char)] = &[ + ('𐪀', '𐪟'), +]; + +pub const OLD_PERMIC: &'static [(char, char)] = &[ + ('𐍐', '𐍺'), +]; + +pub const OLD_PERSIAN: &'static [(char, char)] = &[ + ('𐎠', '𐏃'), ('𐏈', '𐏕'), +]; + +pub const OLD_SOGDIAN: &'static [(char, char)] = &[ + ('\u{10f00}', '\u{10f27}'), +]; + +pub const OLD_SOUTH_ARABIAN: &'static [(char, char)] = &[ + ('𐩠', '𐩿'), +]; + +pub const OLD_TURKIC: &'static [(char, char)] = &[ + ('𐰀', '𐱈'), +]; + +pub const ORIYA: &'static [(char, char)] = &[ + ('ଁ', 'ଃ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), ('ଓ', 'ନ'), + ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), ('଼', 'ୄ'), + ('େ', 'ୈ'), ('ୋ', '୍'), ('ୖ', 'ୗ'), ('ଡ଼', 'ଢ଼'), + ('ୟ', 'à­£'), ('à­¦', 'à­·'), +]; + +pub const OSAGE: &'static [(char, char)] = &[ + ('𐒰', '𐓓'), ('𐓘', '𐓻'), +]; + +pub const OSMANYA: &'static [(char, char)] = &[ + ('𐒀', '𐒝'), ('𐒠', '𐒩'), +]; + +pub const PAHAWH_HMONG: &'static [(char, char)] = &[ + ('𖬀', '𖭅'), ('𖭐', '𖭙'), ('𖭛', '𖭡'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), +]; + +pub const PALMYRENE: &'static [(char, char)] = &[ + ('𐡠', '𐡿'), +]; + +pub const PAU_CIN_HAU: &'static [(char, char)] = &[ + ('𑫀', '𑫸'), +]; + +pub const PHAGS_PA: &'static [(char, char)] = &[ + ('ꡀ', 'ê¡·'), +]; + +pub const PHOENICIAN: &'static [(char, char)] = &[ + ('𐤀', '𐤛'), ('𐤟', '𐤟'), +]; + +pub const PSALTER_PAHLAVI: &'static [(char, char)] = &[ + ('𐮀', '𐮑'), ('𐮙', '𐮜'), ('𐮩', '𐮯'), +]; + +pub const REJANG: &'static [(char, char)] = &[ + ('ꤰ', '꥓'), ('꥟', '꥟'), +]; + +pub const RUNIC: &'static [(char, char)] = &[ + ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), +]; + +pub const SAMARITAN: &'static [(char, char)] = &[ + ('ࠀ', 'à ­'), ('à °', 'à ¾'), +]; + +pub const SAURASHTRA: &'static [(char, char)] = &[ + ('ꢀ', 'ꣅ'), ('꣎', '꣙'), +]; + +pub const SHARADA: &'static [(char, char)] = &[ + ('𑆀', '𑇍'), ('𑇐', '𑇟'), +]; + +pub const SHAVIAN: &'static [(char, char)] = &[ + ('𐑐', '𐑿'), +]; + +pub const SIDDHAM: &'static [(char, char)] = &[ + ('𑖀', '𑖵'), ('𑖸', '𑗝'), +]; + +pub const SIGNWRITING: &'static [(char, char)] = &[ + ('𝠀', '𝪋'), ('𝪛', '𝪟'), ('𝪡', '𝪯'), +]; + +pub const SINHALA: &'static [(char, char)] = &[ + ('ං', 'ඃ'), ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), + ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('්', '්'), ('ා', 'ු'), + ('ූ', 'ූ'), ('ෘ', 'ෟ'), ('à·¦', 'à·¯'), ('à·²', 'à·´'), + ('𑇡', '𑇴'), +]; + +pub const SOGDIAN: &'static [(char, char)] = &[ + ('\u{10f30}', '\u{10f59}'), +]; + +pub const SORA_SOMPENG: &'static [(char, char)] = &[ + ('𑃐', '𑃨'), ('𑃰', '𑃹'), +]; + +pub const SOYOMBO: &'static [(char, char)] = &[ + ('𑩐', '𑪃'), ('𑪆', '𑪢'), +]; + +pub const SUNDANESE: &'static [(char, char)] = &[ + ('ᮀ', 'ᮿ'), ('᳀', '᳇'), +]; + +pub const SYLOTI_NAGRI: &'static [(char, char)] = &[ + ('ꠀ', 'ê «'), +]; + +pub const SYRIAC: &'static [(char, char)] = &[ + ('܀', '܍'), ('\u{70f}', '݊'), ('ݍ', 'ݏ'), ('à¡ ', 'ࡪ'), +]; + +pub const TAGALOG: &'static [(char, char)] = &[ + ('ᜀ', 'ᜌ'), ('ᜎ', '᜔'), +]; + +pub const TAGBANWA: &'static [(char, char)] = &[ + ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), ('ᝲ', 'ᝳ'), +]; + +pub const TAI_LE: &'static [(char, char)] = &[ + ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), +]; + +pub const TAI_THAM: &'static [(char, char)] = &[ + ('ᨠ', 'ᩞ'), ('á© ', '᩼'), ('á©¿', '᪉'), ('᪐', '᪙'), + ('᪠', '᪭'), +]; + +pub const TAI_VIET: &'static [(char, char)] = &[ + ('ꪀ', 'ꫂ'), ('ꫛ', '꫟'), +]; + +pub const TAKRI: &'static [(char, char)] = &[ + ('𑚀', '𑚷'), ('𑛀', '𑛉'), +]; + +pub const TAMIL: &'static [(char, char)] = &[ + ('ஂ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), ('ஒ', 'க'), + ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), ('ண', 'த'), + ('ந', 'ப'), ('à®®', 'ஹ'), ('ா', 'ூ'), ('ெ', 'ை'), + ('ொ', '்'), ('ௐ', 'ௐ'), ('ௗ', 'ௗ'), ('௦', '௺'), +]; + +pub const TANGUT: &'static [(char, char)] = &[ + ('𖿠', '𖿠'), ('𗀀', '\u{187f1}'), ('𘠀', '𘫲'), +]; + +pub const TELUGU: &'static [(char, char)] = &[ + ('ఀ', 'ఌ'), ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), + ('à°½', 'ౄ'), ('ె', 'ై'), ('ొ', '్'), ('ౕ', 'ౖ'), + ('ౘ', 'ౚ'), ('à± ', 'à±£'), ('౦', '౯'), ('౸', '౿'), +]; + +pub const THAANA: &'static [(char, char)] = &[ + ('ހ', 'Þ±'), +]; + +pub const THAI: &'static [(char, char)] = &[ + ('ก', 'ฺ'), ('เ', '๛'), +]; + +pub const TIBETAN: &'static [(char, char)] = &[ + ('ༀ', 'ཇ'), ('ཉ', 'ཬ'), ('ཱ', 'ྗ'), ('ྙ', 'ྼ'), + ('྾', '࿌'), ('࿎', '࿔'), ('࿙', '࿚'), +]; + +pub const TIFINAGH: &'static [(char, char)] = &[ + ('â´°', 'âµ§'), ('ⵯ', 'âµ°'), ('⵿', '⵿'), +]; + +pub const TIRHUTA: &'static [(char, char)] = &[ + ('𑒀', '𑓇'), ('𑓐', '𑓙'), +]; + +pub const UGARITIC: &'static [(char, char)] = &[ + ('𐎀', '𐎝'), ('𐎟', '𐎟'), +]; + +pub const VAI: &'static [(char, char)] = &[ + ('ꔀ', 'ꘫ'), +]; + +pub const WARANG_CITI: &'static [(char, char)] = &[ + ('𑢠', '𑣲'), ('𑣿', '𑣿'), +]; + +pub const YI: &'static [(char, char)] = &[ + ('ꀀ', 'ꒌ'), ('꒐', '꓆'), +]; + +pub const ZANABAZAR_SQUARE: &'static [(char, char)] = &[ + ('𑨀', '𑩇'), +]; diff --git a/regex-syntax/src/unicode_tables/script_extension.rs b/regex-syntax/src/unicode_tables/script_extension.rs new file mode 100644 index 000000000..13f19dc16 --- /dev/null +++ b/regex-syntax/src/unicode_tables/script_extension.rs @@ -0,0 +1,829 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate script-extension tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("Adlam", ADLAM), ("Ahom", AHOM), + ("Anatolian_Hieroglyphs", ANATOLIAN_HIEROGLYPHS), ("Arabic", ARABIC), + ("Armenian", ARMENIAN), ("Avestan", AVESTAN), ("Balinese", BALINESE), + ("Bamum", BAMUM), ("Bassa_Vah", BASSA_VAH), ("Batak", BATAK), + ("Bengali", BENGALI), ("Bhaiksuki", BHAIKSUKI), ("Bopomofo", BOPOMOFO), + ("Brahmi", BRAHMI), ("Braille", BRAILLE), ("Buginese", BUGINESE), + ("Buhid", BUHID), ("Canadian_Aboriginal", CANADIAN_ABORIGINAL), + ("Carian", CARIAN), ("Caucasian_Albanian", CAUCASIAN_ALBANIAN), + ("Chakma", CHAKMA), ("Cham", CHAM), ("Cherokee", CHEROKEE), + ("Common", COMMON), ("Coptic", COPTIC), ("Cuneiform", CUNEIFORM), + ("Cypriot", CYPRIOT), ("Cyrillic", CYRILLIC), ("Deseret", DESERET), + ("Devanagari", DEVANAGARI), ("Dogra", DOGRA), ("Duployan", DUPLOYAN), + ("Egyptian_Hieroglyphs", EGYPTIAN_HIEROGLYPHS), ("Elbasan", ELBASAN), + ("Ethiopic", ETHIOPIC), ("Georgian", GEORGIAN), ("Glagolitic", GLAGOLITIC), + ("Gothic", GOTHIC), ("Grantha", GRANTHA), ("Greek", GREEK), + ("Gujarati", GUJARATI), ("Gunjala_Gondi", GUNJALA_GONDI), + ("Gurmukhi", GURMUKHI), ("Han", HAN), ("Hangul", HANGUL), + ("Hanifi_Rohingya", HANIFI_ROHINGYA), ("Hanunoo", HANUNOO), + ("Hatran", HATRAN), ("Hebrew", HEBREW), ("Hiragana", HIRAGANA), + ("Imperial_Aramaic", IMPERIAL_ARAMAIC), ("Inherited", INHERITED), + ("Inscriptional_Pahlavi", INSCRIPTIONAL_PAHLAVI), + ("Inscriptional_Parthian", INSCRIPTIONAL_PARTHIAN), ("Javanese", JAVANESE), + ("Kaithi", KAITHI), ("Kannada", KANNADA), ("Katakana", KATAKANA), + ("Kayah_Li", KAYAH_LI), ("Kharoshthi", KHAROSHTHI), ("Khmer", KHMER), + ("Khojki", KHOJKI), ("Khudawadi", KHUDAWADI), ("Lao", LAO), + ("Latin", LATIN), ("Lepcha", LEPCHA), ("Limbu", LIMBU), + ("Linear_A", LINEAR_A), ("Linear_B", LINEAR_B), ("Lisu", LISU), + ("Lycian", LYCIAN), ("Lydian", LYDIAN), ("Mahajani", MAHAJANI), + ("Makasar", MAKASAR), ("Malayalam", MALAYALAM), ("Mandaic", MANDAIC), + ("Manichaean", MANICHAEAN), ("Marchen", MARCHEN), + ("Masaram_Gondi", MASARAM_GONDI), ("Medefaidrin", MEDEFAIDRIN), + ("Meetei_Mayek", MEETEI_MAYEK), ("Mende_Kikakui", MENDE_KIKAKUI), + ("Meroitic_Cursive", MEROITIC_CURSIVE), + ("Meroitic_Hieroglyphs", MEROITIC_HIEROGLYPHS), ("Miao", MIAO), + ("Modi", MODI), ("Mongolian", MONGOLIAN), ("Mro", MRO), + ("Multani", MULTANI), ("Myanmar", MYANMAR), ("Nabataean", NABATAEAN), + ("New_Tai_Lue", NEW_TAI_LUE), ("Newa", NEWA), ("Nko", NKO), + ("Nushu", NUSHU), ("Ogham", OGHAM), ("Ol_Chiki", OL_CHIKI), + ("Old_Hungarian", OLD_HUNGARIAN), ("Old_Italic", OLD_ITALIC), + ("Old_North_Arabian", OLD_NORTH_ARABIAN), ("Old_Permic", OLD_PERMIC), + ("Old_Persian", OLD_PERSIAN), ("Old_Sogdian", OLD_SOGDIAN), + ("Old_South_Arabian", OLD_SOUTH_ARABIAN), ("Old_Turkic", OLD_TURKIC), + ("Oriya", ORIYA), ("Osage", OSAGE), ("Osmanya", OSMANYA), + ("Pahawh_Hmong", PAHAWH_HMONG), ("Palmyrene", PALMYRENE), + ("Pau_Cin_Hau", PAU_CIN_HAU), ("Phags_Pa", PHAGS_PA), + ("Phoenician", PHOENICIAN), ("Psalter_Pahlavi", PSALTER_PAHLAVI), + ("Rejang", REJANG), ("Runic", RUNIC), ("Samaritan", SAMARITAN), + ("Saurashtra", SAURASHTRA), ("Sharada", SHARADA), ("Shavian", SHAVIAN), + ("Siddham", SIDDHAM), ("SignWriting", SIGNWRITING), ("Sinhala", SINHALA), + ("Sogdian", SOGDIAN), ("Sora_Sompeng", SORA_SOMPENG), ("Soyombo", SOYOMBO), + ("Sundanese", SUNDANESE), ("Syloti_Nagri", SYLOTI_NAGRI), + ("Syriac", SYRIAC), ("Tagalog", TAGALOG), ("Tagbanwa", TAGBANWA), + ("Tai_Le", TAI_LE), ("Tai_Tham", TAI_THAM), ("Tai_Viet", TAI_VIET), + ("Takri", TAKRI), ("Tamil", TAMIL), ("Tangut", TANGUT), ("Telugu", TELUGU), + ("Thaana", THAANA), ("Thai", THAI), ("Tibetan", TIBETAN), + ("Tifinagh", TIFINAGH), ("Tirhuta", TIRHUTA), ("Ugaritic", UGARITIC), + ("Vai", VAI), ("Warang_Citi", WARANG_CITI), ("Yi", YI), + ("Zanabazar_Square", ZANABAZAR_SQUARE), +]; + +pub const ADLAM: &'static [(char, char)] = &[ + ('ـ', 'ـ'), ('𞤀', '𞥊'), ('𞥐', '𞥙'), ('𞥞', '𞥟'), +]; + +pub const AHOM: &'static [(char, char)] = &[ + ('𑜀', '\u{1171a}'), ('𑜝', '𑜫'), ('𑜰', '𑜿'), +]; + +pub const ANATOLIAN_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𔐀', '𔙆'), +]; + +pub const ARABIC: &'static [(char, char)] = &[ + ('\u{600}', '\u{604}'), ('؆', '\u{61c}'), ('؞', 'ۜ'), ('۞', 'Û¿'), + ('ݐ', 'Ý¿'), ('ࢠ', 'ࢴ'), ('ࢶ', 'ࢽ'), ('\u{8d3}', '࣡'), + ('ࣣ', 'ࣿ'), ('ﭐ', '﯁'), ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), + ('ﶒ', 'ﷇ'), ('ï·°', 'ï·½'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), + ('𐋠', '𐋻'), ('𐹠', '𐹾'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𞻰', '𞻱'), +]; + +pub const ARMENIAN: &'static [(char, char)] = &[ + ('Ô±', 'Ֆ'), ('ՙ', '֊'), ('֍', '֏'), ('ﬓ', 'ﬗ'), +]; + +pub const AVESTAN: &'static [(char, char)] = &[ + ('𐬀', '𐬵'), ('𐬹', '𐬿'), +]; + +pub const BALINESE: &'static [(char, char)] = &[ + ('ᬀ', 'ᭋ'), ('᭐', 'á­¼'), +]; + +pub const BAMUM: &'static [(char, char)] = &[ + ('ꚠ', '꛷'), ('𖠀', '𖨸'), +]; + +pub const BASSA_VAH: &'static [(char, char)] = &[ + ('𖫐', '𖫭'), ('𖫰', '𖫵'), +]; + +pub const BATAK: &'static [(char, char)] = &[ + ('ᯀ', '᯳'), ('᯼', '᯿'), +]; + +pub const BENGALI: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ঀ', 'ঃ'), ('অ', 'ঌ'), + ('এ', 'ঐ'), ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), + ('শ', 'হ'), ('়', 'ৄ'), ('ে', 'ৈ'), ('ো', 'ৎ'), + ('ৗ', 'ৗ'), ('ড়', 'ঢ়'), ('য়', 'à§£'), ('০', '\u{9fe}'), + ('᳐', '᳐'), ('᳒', '᳒'), ('᳕', '᳖'), ('᳘', '᳘'), + ('᳡', '᳡'), ('ᳪ', 'ᳪ'), ('á³­', 'á³­'), ('á³µ', 'á³·'), + ('꣱', '꣱'), +]; + +pub const BHAIKSUKI: &'static [(char, char)] = &[ + ('𑰀', '𑰈'), ('𑰊', '𑰶'), ('𑰸', '𑱅'), ('𑱐', '𑱬'), +]; + +pub const BOPOMOFO: &'static [(char, char)] = &[ + ('˪', 'Ë«'), ('、', '〃'), ('〈', '】'), ('〓', '〟'), + ('〪', '〭'), ('〰', '〰'), ('〷', '〷'), ('・', '・'), + ('ㄅ', '\u{312f}'), ('ㆠ', 'ㆺ'), ('﹅', '﹆'), ('。', 'ï½¥'), +]; + +pub const BRAHMI: &'static [(char, char)] = &[ + ('𑀀', '𑁍'), ('𑁒', '𑁯'), ('𑁿', '𑁿'), +]; + +pub const BRAILLE: &'static [(char, char)] = &[ + ('⠀', '⣿'), +]; + +pub const BUGINESE: &'static [(char, char)] = &[ + ('ᨀ', 'ᨛ'), ('᨞', '᨟'), ('ꧏ', 'ꧏ'), +]; + +pub const BUHID: &'static [(char, char)] = &[ + ('᜵', '᜶'), ('ᝀ', 'ᝓ'), +]; + +pub const CANADIAN_ABORIGINAL: &'static [(char, char)] = &[ + ('᐀', 'ᙿ'), ('ᢰ', 'ᣵ'), +]; + +pub const CARIAN: &'static [(char, char)] = &[ + ('𐊠', '𐋐'), +]; + +pub const CAUCASIAN_ALBANIAN: &'static [(char, char)] = &[ + ('𐔰', '𐕣'), ('𐕯', '𐕯'), +]; + +pub const CHAKMA: &'static [(char, char)] = &[ + ('০', '৯'), ('၀', '၉'), ('𑄀', '𑄴'), ('𑄶', '\u{11146}'), +]; + +pub const CHAM: &'static [(char, char)] = &[ + ('ꨀ', 'ꨶ'), ('ꩀ', 'ꩍ'), ('꩐', '꩙'), ('꩜', '꩟'), +]; + +pub const CHEROKEE: &'static [(char, char)] = &[ + ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), ('ê­°', 'ꮿ'), +]; + +pub const COMMON: &'static [(char, char)] = &[ + ('\u{0}', '@'), ('[', '`'), ('{', '©'), ('«', '¹'), ('»', '¿'), + ('×', '×'), ('÷', '÷'), ('ʹ', '˟'), ('Ë¥', 'Ë©'), ('ˬ', 'Ë¿'), + ('Í´', 'Í´'), (';', ';'), ('΅', '΅'), ('·', '·'), + ('\u{605}', '\u{605}'), ('\u{6dd}', '\u{6dd}'), ('\u{8e2}', '\u{8e2}'), + ('฿', '฿'), ('࿕', '࿘'), ('᛫', '᛭'), ('\u{2000}', '\u{200b}'), + ('\u{200e}', '\u{2064}'), ('\u{2066}', '⁰'), ('⁴', '⁾'), + ('₀', '₎'), ('₠', '₿'), ('℀', '℥'), ('℧', '℩'), + ('ℬ', 'ℱ'), ('ℳ', '⅍'), ('⅏', '⅟'), ('↉', '↋'), + ('←', '␦'), ('⑀', '⑊'), ('①', '⟿'), ('⤀', 'â­³'), + ('â­¶', '⮕'), ('⮘', '⯈'), ('⯊', '\u{2bfe}'), ('⸀', '⹂'), + ('⹄', '\u{2e4e}'), ('â¿°', 'â¿»'), ('\u{3000}', '\u{3000}'), + ('〄', '〄'), ('〒', '〒'), ('〠', '〠'), ('〶', '〶'), + ('㉈', '㉟'), ('㉿', '㉿'), ('㊱', '㊿'), ('㋌', '㋏'), + ('㍱', '㍺'), ('㎀', '㏟'), ('㏿', '㏿'), ('䷀', 'ä·¿'), + ('꜀', '꜡'), ('ꞈ', '꞊'), ('꭛', '꭛'), ('ï´¾', 'ï´¿'), + ('︐', '︙'), ('︰', '﹄'), ('﹇', '﹒'), ('﹔', '﹦'), + ('﹨', '﹫'), ('\u{feff}', '\u{feff}'), ('!', 'ï¼ '), ('ï¼»', '`'), + ('{', 'ï½ '), ('ï¿ ', '₩'), ('│', 'ï¿®'), ('\u{fff9}', '�'), + ('𐆐', '𐆛'), ('𐇐', '𐇼'), ('𝀀', '𝃵'), ('𝄀', '𝄦'), + ('𝄩', '𝅦'), ('𝅪', '\u{1d17a}'), ('𝆃', '𝆄'), ('𝆌', '𝆩'), + ('𝆮', '𝇨'), ('\u{1d2e0}', '\u{1d2f3}'), ('𝌀', '𝍖'), + ('\u{1d372}', '\u{1d378}'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝟋'), ('𝟎', '𝟿'), + ('\u{1ec71}', '\u{1ecb4}'), ('🀀', '🀫'), ('🀰', '🂓'), + ('🂠', '🂮'), ('🂱', '🂿'), ('🃁', '🃏'), ('🃑', '🃵'), + ('🄀', '🄌'), ('🄐', '🅫'), ('🅰', '🆬'), ('🇦', '🇿'), + ('🈁', '🈂'), ('🈐', '🈻'), ('🉀', '🉈'), ('🉠', '🉥'), + ('🌀', '🛔'), ('🛠', '🛬'), ('🛰', '\u{1f6f9}'), ('🜀', '🝳'), + ('🞀', '\u{1f7d8}'), ('🠀', '🠋'), ('🠐', '🡇'), ('🡐', '🡙'), + ('🡠', '🢇'), ('🢐', '🢭'), ('🤀', '🤋'), ('🤐', '🤾'), + ('🥀', '\u{1f970}'), ('\u{1f973}', '\u{1f976}'), + ('\u{1f97a}', '\u{1f97a}'), ('\u{1f97c}', '\u{1f9a2}'), + ('\u{1f9b0}', '\u{1f9b9}'), ('🧀', '\u{1f9c2}'), ('🧐', '\u{1f9ff}'), + ('\u{1fa60}', '\u{1fa6d}'), ('\u{e0001}', '\u{e0001}'), + ('\u{e0020}', '\u{e007f}'), +]; + +pub const COPTIC: &'static [(char, char)] = &[ + ('Ï¢', 'ϯ'), ('Ⲁ', 'â³³'), ('â³¹', '⳿'), ('𐋠', '𐋻'), +]; + +pub const CUNEIFORM: &'static [(char, char)] = &[ + ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒑰', '𒑴'), ('𒒀', '𒕃'), +]; + +pub const CYPRIOT: &'static [(char, char)] = &[ + ('𐄀', '𐄂'), ('𐄇', '𐄳'), ('𐄷', '𐄿'), ('𐠀', '𐠅'), + ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), ('𐠼', '𐠼'), + ('𐠿', '𐠿'), +]; + +pub const CYRILLIC: &'static [(char, char)] = &[ + ('Ѐ', 'Ô¯'), ('ᲀ', 'ᲈ'), ('á´«', 'á´«'), ('ᵸ', 'ᵸ'), + ('â· ', 'â·¿'), ('⹃', '⹃'), ('Ꙁ', 'ꚟ'), ('︮', '︯'), +]; + +pub const DESERET: &'static [(char, char)] = &[ + ('𐐀', '𐑏'), +]; + +pub const DEVANAGARI: &'static [(char, char)] = &[ + ('ऀ', 'ॿ'), ('᳐', 'á³¶'), ('᳸', 'á³¹'), ('⃰', '⃰'), + ('ê °', 'ê ¹'), ('꣠', '\u{a8ff}'), +]; + +pub const DOGRA: &'static [(char, char)] = &[ + ('।', '९'), ('ê °', 'ê ¹'), ('\u{11800}', '\u{1183b}'), +]; + +pub const DUPLOYAN: &'static [(char, char)] = &[ + ('𛰀', '𛱪'), ('𛱰', '𛱼'), ('𛲀', '𛲈'), ('𛲐', '𛲙'), + ('𛲜', '\u{1bca3}'), +]; + +pub const EGYPTIAN_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𓀀', '𓐮'), +]; + +pub const ELBASAN: &'static [(char, char)] = &[ + ('𐔀', '𐔧'), +]; + +pub const ETHIOPIC: &'static [(char, char)] = &[ + ('ሀ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), + ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), + ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), + ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), + ('፝', '፼'), ('ᎀ', '᎙'), ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), + ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), + ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), +]; + +pub const GEORGIAN: &'static [(char, char)] = &[ + ('։', '։'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('ა', 'ჿ'), ('\u{1c90}', '\u{1cba}'), ('\u{1cbd}', '\u{1cbf}'), + ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), +]; + +pub const GLAGOLITIC: &'static [(char, char)] = &[ + ('҄', '҄'), ('҇', '҇'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), ('⹃', '⹃'), + ('꙯', '꙯'), ('𞀀', '𞀆'), ('𞀈', '𞀘'), ('𞀛', '𞀡'), + ('𞀣', '𞀤'), ('𞀦', '𞀪'), +]; + +pub const GOTHIC: &'static [(char, char)] = &[ + ('𐌰', '𐍊'), +]; + +pub const GRANTHA: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('௦', '௳'), ('᳐', '᳐'), + ('᳒', '᳓'), ('á³²', 'á³´'), ('᳸', 'á³¹'), ('⃰', '⃰'), + ('𑌀', '𑌃'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), ('𑌓', '𑌨'), + ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), ('\u{1133b}', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('𑍐', '𑍐'), ('𑍗', '𑍗'), + ('𑍝', '𑍣'), ('𑍦', '𑍬'), ('𑍰', '𑍴'), +]; + +pub const GREEK: &'static [(char, char)] = &[ + ('͂', '͂'), ('ͅ', 'ͅ'), ('Ͱ', 'ͳ'), ('͵', 'Í·'), ('ͺ', 'ͽ'), + ('Í¿', 'Í¿'), ('΄', '΄'), ('Ά', 'Ά'), ('Έ', 'Ί'), ('Ό', 'Ό'), + ('Ύ', 'Ρ'), ('Σ', 'Ï¡'), ('ϰ', 'Ï¿'), ('á´¦', 'á´ª'), ('ᵝ', 'ᵡ'), + ('ᵦ', 'ᵪ'), ('á¶¿', '᷁'), ('ἀ', 'ἕ'), ('Ἐ', 'Ἕ'), + ('á¼ ', 'ὅ'), ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), + ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), + ('á¾¶', 'ῄ'), ('ῆ', 'ΐ'), ('ῖ', 'Ί'), ('῝', '`'), + ('ῲ', 'á¿´'), ('á¿¶', '῾'), ('Ω', 'Ω'), ('ê­¥', 'ê­¥'), + ('𐅀', '𐆎'), ('𐆠', '𐆠'), ('𝈀', '𝉅'), +]; + +pub const GUJARATI: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ઁ', 'ઃ'), ('અ', 'ઍ'), + ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), ('લ', 'ળ'), + ('વ', 'હ'), ('઼', 'ૅ'), ('ે', 'ૉ'), ('ો', '્'), + ('ૐ', 'ૐ'), ('à« ', 'à«£'), ('૦', '૱'), ('ૹ', 'à«¿'), + ('ê °', 'ê ¹'), +]; + +pub const GUNJALA_GONDI: &'static [(char, char)] = &[ + ('।', '॥'), ('\u{11d60}', '\u{11d65}'), ('\u{11d67}', '\u{11d68}'), + ('\u{11d6a}', '\u{11d8e}'), ('\u{11d90}', '\u{11d91}'), + ('\u{11d93}', '\u{11d98}'), ('\u{11da0}', '\u{11da9}'), +]; + +pub const GURMUKHI: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ਁ', 'ਃ'), ('ਅ', 'ਊ'), + ('ਏ', 'ਐ'), ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), + ('ਵ', 'ਸ਼'), ('ਸ', 'ਹ'), ('਼', '਼'), ('ਾ', 'ੂ'), + ('ੇ', 'ੈ'), ('ੋ', '੍'), ('ੑ', 'ੑ'), ('ਖ਼', 'ੜ'), + ('ਫ਼', 'ਫ਼'), ('੦', '\u{a76}'), ('ê °', 'ê ¹'), +]; + +pub const HAN: &'static [(char, char)] = &[ + ('⺀', '⺙'), ('⺛', '⻳'), ('⼀', '⿕'), ('、', '〃'), + ('々', '】'), ('〓', '〟'), ('〡', '〭'), ('〰', '〰'), + ('〷', '〿'), ('・', '・'), ('㆐', '㆟'), ('㇀', '㇣'), + ('㈠', '㉇'), ('㊀', '㊰'), ('㋀', '㋋'), ('㍘', '㍰'), + ('㍻', '㍿'), ('㏠', '㏾'), ('㐀', 'ä¶µ'), ('一', '\u{9fef}'), + ('豈', 'ï©­'), ('ï©°', '龎'), ('﹅', '﹆'), ('。', 'ï½¥'), + ('𝍠', '𝍱'), ('🉐', '🉑'), ('𠀀', '𪛖'), ('𪜀', '𫜴'), + ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), ('丽', '𪘀'), +]; + +pub const HANGUL: &'static [(char, char)] = &[ + ('ᄀ', 'ᇿ'), ('、', '〃'), ('〈', '】'), ('〓', '〟'), + ('〮', '〰'), ('〷', '〷'), ('・', '・'), ('ㄱ', 'ㆎ'), + ('㈀', '㈞'), ('㉠', '㉾'), ('ꥠ', 'ꥼ'), ('가', '힣'), + ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('﹅', '﹆'), ('。', 'ï½¥'), + ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), + ('ᅳ', 'ᅵ'), +]; + +pub const HANIFI_ROHINGYA: &'static [(char, char)] = &[ + ('،', '،'), ('؛', '؛'), ('؟', '؟'), ('ـ', 'ـ'), ('۔', '۔'), + ('\u{10d00}', '\u{10d27}'), ('\u{10d30}', '\u{10d39}'), +]; + +pub const HANUNOO: &'static [(char, char)] = &[ + ('ᜠ', '᜶'), +]; + +pub const HATRAN: &'static [(char, char)] = &[ + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐣻', '𐣿'), +]; + +pub const HEBREW: &'static [(char, char)] = &[ + ('֑', 'ׇ'), ('א', 'ת'), ('\u{5ef}', '×´'), ('יִ', 'זּ'), + ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), + ('צּ', 'ﭏ'), +]; + +pub const HIRAGANA: &'static [(char, char)] = &[ + ('、', '〃'), ('〈', '】'), ('〓', '〟'), ('〰', '〵'), + ('〷', '〷'), ('〼', '〽'), ('ぁ', 'ゖ'), ('゙', '゠'), + ('・', 'ー'), ('﹅', '﹆'), ('。', 'ï½¥'), ('ï½°', 'ï½°'), + ('゙', '゚'), ('𛀁', '𛄞'), ('🈀', '🈀'), +]; + +pub const IMPERIAL_ARAMAIC: &'static [(char, char)] = &[ + ('𐡀', '𐡕'), ('𐡗', '𐡟'), +]; + +pub const INHERITED: &'static [(char, char)] = &[ + ('̀', '́'), ('̓', '̈́'), ('͆', 'Í¢'), ('᪰', '᪾'), ('᷂', 'á·¹'), + ('á·»', 'á·¿'), ('\u{200c}', '\u{200d}'), ('⃐', '⃯'), ('︀', '️'), + ('︠', '︭'), ('𐇽', '𐇽'), ('𝅧', '𝅩'), ('𝅻', '𝆂'), + ('𝆅', '𝆋'), ('𝆪', '𝆭'), ('󠄀', '󠇯'), +]; + +pub const INSCRIPTIONAL_PAHLAVI: &'static [(char, char)] = &[ + ('𐭠', '𐭲'), ('𐭸', '𐭿'), +]; + +pub const INSCRIPTIONAL_PARTHIAN: &'static [(char, char)] = &[ + ('𐭀', '𐭕'), ('𐭘', '𐭟'), +]; + +pub const JAVANESE: &'static [(char, char)] = &[ + ('ꦀ', '꧍'), ('ꧏ', '꧙'), ('꧞', '꧟'), +]; + +pub const KAITHI: &'static [(char, char)] = &[ + ('०', '९'), ('ê °', 'ê ¹'), ('𑂀', '𑃁'), + ('\u{110cd}', '\u{110cd}'), +]; + +pub const KANNADA: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ಀ', 'ಌ'), ('ಎ', 'ಐ'), + ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), ('಼', 'ೄ'), + ('ೆ', 'ೈ'), ('ೊ', '್'), ('ೕ', 'ೖ'), ('ೞ', 'ೞ'), + ('à³ ', 'à³£'), ('೦', '೯'), ('à³±', 'à³²'), ('᳐', '᳐'), + ('᳒', '᳒'), ('᳚', '᳚'), ('á³´', 'á³´'), ('ê °', 'ê µ'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('、', '〃'), ('〈', '】'), ('〓', '〟'), ('〰', '〵'), + ('〷', '〷'), ('〼', '〽'), ('゙', '゜'), ('゠', 'ヿ'), + ('ㇰ', 'ㇿ'), ('㋐', '㋾'), ('㌀', '㍗'), ('﹅', '﹆'), + ('。', '゚'), ('𛀀', '𛀀'), +]; + +pub const KAYAH_LI: &'static [(char, char)] = &[ + ('꤀', '꤯'), +]; + +pub const KHAROSHTHI: &'static [(char, char)] = &[ + ('𐨀', '𐨃'), ('𐨅', '𐨆'), ('𐨌', '𐨓'), ('𐨕', '𐨗'), + ('𐨙', '\u{10a35}'), ('𐨸', '𐨺'), ('𐨿', '\u{10a48}'), + ('𐩐', '𐩘'), +]; + +pub const KHMER: &'static [(char, char)] = &[ + ('ក', '៝'), ('០', '៩'), ('៰', '៹'), ('á§ ', 'á§¿'), +]; + +pub const KHOJKI: &'static [(char, char)] = &[ + ('૦', '૯'), ('ê °', 'ê ¹'), ('𑈀', '𑈑'), ('𑈓', '𑈾'), +]; + +pub const KHUDAWADI: &'static [(char, char)] = &[ + ('।', '॥'), ('ê °', 'ê ¹'), ('𑊰', '𑋪'), ('𑋰', '𑋹'), +]; + +pub const LAO: &'static [(char, char)] = &[ + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ູ'), + ('ົ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), ('່', 'ໍ'), + ('໐', '໙'), ('ໜ', 'ໟ'), +]; + +pub const LATIN: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('º', 'º'), ('À', 'Ö'), + ('Ø', 'ö'), ('ø', 'ʸ'), ('Ë ', 'ˤ'), ('Í£', 'ͯ'), ('҅', '҆'), + ('॑', '॒'), ('჻', '჻'), ('ᴀ', 'á´¥'), ('á´¬', 'ᵜ'), + ('áµ¢', 'áµ¥'), ('ᵫ', 'áµ·'), ('áµ¹', 'á¶¾'), ('Ḁ', 'ỿ'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('⃰', '⃰'), + ('K', 'Å'), ('Ⅎ', 'Ⅎ'), ('ⅎ', 'ⅎ'), ('Ⅰ', 'ↈ'), + ('â± ', 'Ɀ'), ('Ꜣ', 'ꞇ'), ('Ꞌ', '\u{a7b9}'), ('ꟷ', 'ꟿ'), + ('꤮', '꤮'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¤'), ('ff', 'st'), + ('A', 'Z'), ('a', 'z'), +]; + +pub const LEPCHA: &'static [(char, char)] = &[ + ('ᰀ', 'á°·'), ('á°»', '᱉'), ('ᱍ', 'ᱏ'), +]; + +pub const LIMBU: &'static [(char, char)] = &[ + ('॥', '॥'), ('ᤀ', 'ᤞ'), ('ᤠ', 'ᤫ'), ('ᤰ', '᤻'), + ('᥀', '᥀'), ('᥄', '᥏'), +]; + +pub const LINEAR_A: &'static [(char, char)] = &[ + ('𐄇', '𐄳'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), +]; + +pub const LINEAR_B: &'static [(char, char)] = &[ + ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), ('𐀼', '𐀽'), + ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), ('𐄀', '𐄂'), + ('𐄇', '𐄳'), ('𐄷', '𐄿'), +]; + +pub const LISU: &'static [(char, char)] = &[ + ('ꓐ', '꓿'), +]; + +pub const LYCIAN: &'static [(char, char)] = &[ + ('𐊀', '𐊜'), +]; + +pub const LYDIAN: &'static [(char, char)] = &[ + ('𐤠', '𐤹'), ('𐤿', '𐤿'), +]; + +pub const MAHAJANI: &'static [(char, char)] = &[ + ('।', '९'), ('ê °', 'ê ¹'), ('𑅐', '𑅶'), +]; + +pub const MAKASAR: &'static [(char, char)] = &[ + ('\u{11ee0}', '\u{11ef8}'), +]; + +pub const MALAYALAM: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ഀ', 'ഃ'), ('അ', 'ഌ'), + ('എ', 'ഐ'), ('ഒ', 'ൄ'), ('െ', 'ൈ'), ('ൊ', '൏'), + ('ൔ', 'ൣ'), ('൦', 'ൿ'), ('᳚', '᳚'), ('ê °', 'ê ²'), +]; + +pub const MANDAIC: &'static [(char, char)] = &[ + ('ـ', 'ـ'), ('ࡀ', '࡛'), ('࡞', '࡞'), +]; + +pub const MANICHAEAN: &'static [(char, char)] = &[ + ('ـ', 'ـ'), ('𐫀', '𐫦'), ('𐫫', '𐫶'), +]; + +pub const MARCHEN: &'static [(char, char)] = &[ + ('𑱰', '𑲏'), ('𑲒', '𑲧'), ('𑲩', '𑲶'), +]; + +pub const MASARAM_GONDI: &'static [(char, char)] = &[ + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴶'), ('𑴺', '𑴺'), + ('𑴼', '𑴽'), ('𑴿', '𑵇'), ('𑵐', '𑵙'), +]; + +pub const MEDEFAIDRIN: &'static [(char, char)] = &[ + ('\u{16e40}', '\u{16e9a}'), +]; + +pub const MEETEI_MAYEK: &'static [(char, char)] = &[ + ('ê« ', 'ê«¶'), ('ꯀ', '꯭'), ('꯰', '꯹'), +]; + +pub const MENDE_KIKAKUI: &'static [(char, char)] = &[ + ('𞠀', '𞣄'), ('𞣇', '𞣖'), +]; + +pub const MEROITIC_CURSIVE: &'static [(char, char)] = &[ + ('𐦠', '𐦷'), ('𐦼', '𐧏'), ('𐧒', '𐧿'), +]; + +pub const MEROITIC_HIEROGLYPHS: &'static [(char, char)] = &[ + ('𐦀', '𐦟'), +]; + +pub const MIAO: &'static [(char, char)] = &[ + ('𖼀', '𖽄'), ('𖽐', '𖽾'), ('𖾏', '𖾟'), +]; + +pub const MODI: &'static [(char, char)] = &[ + ('ê °', 'ê ¹'), ('𑘀', '𑙄'), ('𑙐', '𑙙'), +]; + +pub const MONGOLIAN: &'static [(char, char)] = &[ + ('᠀', '\u{180e}'), ('᠐', '᠙'), ('á  ', '\u{1878}'), ('ᢀ', 'ᢪ'), + ('𑙠', '𑙬'), +]; + +pub const MRO: &'static [(char, char)] = &[ + ('𖩀', '𖩞'), ('𖩠', '𖩩'), ('𖩮', '𖩯'), +]; + +pub const MULTANI: &'static [(char, char)] = &[ + ('੦', '੯'), ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), + ('𑊏', '𑊝'), ('𑊟', '𑊩'), +]; + +pub const MYANMAR: &'static [(char, char)] = &[ + ('က', '႟'), ('꤮', '꤮'), ('ê§ ', 'ê§¾'), ('ê© ', 'ê©¿'), +]; + +pub const NABATAEAN: &'static [(char, char)] = &[ + ('𐢀', '𐢞'), ('𐢧', '𐢯'), +]; + +pub const NEW_TAI_LUE: &'static [(char, char)] = &[ + ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), ('᧐', '᧚'), ('᧞', '᧟'), +]; + +pub const NEWA: &'static [(char, char)] = &[ + ('𑐀', '𑑙'), ('𑑛', '𑑛'), ('𑑝', '\u{1145e}'), +]; + +pub const NKO: &'static [(char, char)] = &[ + ('߀', 'ߺ'), ('\u{7fd}', '\u{7ff}'), +]; + +pub const NUSHU: &'static [(char, char)] = &[ + ('𖿡', '𖿡'), ('𛅰', '𛋻'), +]; + +pub const OGHAM: &'static [(char, char)] = &[ + ('\u{1680}', '᚜'), +]; + +pub const OL_CHIKI: &'static [(char, char)] = &[ + ('᱐', '᱿'), +]; + +pub const OLD_HUNGARIAN: &'static [(char, char)] = &[ + ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐳺', '𐳿'), +]; + +pub const OLD_ITALIC: &'static [(char, char)] = &[ + ('𐌀', '𐌣'), ('𐌭', '𐌯'), +]; + +pub const OLD_NORTH_ARABIAN: &'static [(char, char)] = &[ + ('𐪀', '𐪟'), +]; + +pub const OLD_PERMIC: &'static [(char, char)] = &[ + ('҃', '҃'), ('𐍐', '𐍺'), +]; + +pub const OLD_PERSIAN: &'static [(char, char)] = &[ + ('𐎠', '𐏃'), ('𐏈', '𐏕'), +]; + +pub const OLD_SOGDIAN: &'static [(char, char)] = &[ + ('\u{10f00}', '\u{10f27}'), +]; + +pub const OLD_SOUTH_ARABIAN: &'static [(char, char)] = &[ + ('𐩠', '𐩿'), +]; + +pub const OLD_TURKIC: &'static [(char, char)] = &[ + ('𐰀', '𐱈'), +]; + +pub const ORIYA: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ଁ', 'ଃ'), ('ଅ', 'ଌ'), + ('ଏ', 'ଐ'), ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), + ('ଵ', 'ହ'), ('଼', 'ୄ'), ('େ', 'ୈ'), ('ୋ', '୍'), + ('ୖ', 'ୗ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­£'), ('à­¦', 'à­·'), + ('᳚', '᳚'), +]; + +pub const OSAGE: &'static [(char, char)] = &[ + ('𐒰', '𐓓'), ('𐓘', '𐓻'), +]; + +pub const OSMANYA: &'static [(char, char)] = &[ + ('𐒀', '𐒝'), ('𐒠', '𐒩'), +]; + +pub const PAHAWH_HMONG: &'static [(char, char)] = &[ + ('𖬀', '𖭅'), ('𖭐', '𖭙'), ('𖭛', '𖭡'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), +]; + +pub const PALMYRENE: &'static [(char, char)] = &[ + ('𐡠', '𐡿'), +]; + +pub const PAU_CIN_HAU: &'static [(char, char)] = &[ + ('𑫀', '𑫸'), +]; + +pub const PHAGS_PA: &'static [(char, char)] = &[ + ('᠂', '᠃'), ('᠅', '᠅'), ('ꡀ', 'ê¡·'), +]; + +pub const PHOENICIAN: &'static [(char, char)] = &[ + ('𐤀', '𐤛'), ('𐤟', '𐤟'), +]; + +pub const PSALTER_PAHLAVI: &'static [(char, char)] = &[ + ('ـ', 'ـ'), ('𐮀', '𐮑'), ('𐮙', '𐮜'), ('𐮩', '𐮯'), +]; + +pub const REJANG: &'static [(char, char)] = &[ + ('ꤰ', '꥓'), ('꥟', '꥟'), +]; + +pub const RUNIC: &'static [(char, char)] = &[ + ('ᚠ', 'ᛪ'), ('ᛮ', 'ᛸ'), +]; + +pub const SAMARITAN: &'static [(char, char)] = &[ + ('ࠀ', 'à ­'), ('à °', 'à ¾'), +]; + +pub const SAURASHTRA: &'static [(char, char)] = &[ + ('ꢀ', 'ꣅ'), ('꣎', '꣙'), +]; + +pub const SHARADA: &'static [(char, char)] = &[ + ('॑', '॑'), ('᳗', '᳗'), ('᳙', '᳙'), ('᳜', '᳝'), + ('á³ ', 'á³ '), ('𑆀', '𑇍'), ('𑇐', '𑇟'), +]; + +pub const SHAVIAN: &'static [(char, char)] = &[ + ('𐑐', '𐑿'), +]; + +pub const SIDDHAM: &'static [(char, char)] = &[ + ('𑖀', '𑖵'), ('𑖸', '𑗝'), +]; + +pub const SIGNWRITING: &'static [(char, char)] = &[ + ('𝠀', '𝪋'), ('𝪛', '𝪟'), ('𝪡', '𝪯'), +]; + +pub const SINHALA: &'static [(char, char)] = &[ + ('।', '॥'), ('ං', 'ඃ'), ('අ', 'ඖ'), ('ක', 'à¶±'), + ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), ('ව', 'ෆ'), ('්', '්'), + ('ා', 'ු'), ('ූ', 'ූ'), ('ෘ', 'ෟ'), ('à·¦', 'à·¯'), + ('à·²', 'à·´'), ('𑇡', '𑇴'), +]; + +pub const SOGDIAN: &'static [(char, char)] = &[ + ('ـ', 'ـ'), ('\u{10f30}', '\u{10f59}'), +]; + +pub const SORA_SOMPENG: &'static [(char, char)] = &[ + ('𑃐', '𑃨'), ('𑃰', '𑃹'), +]; + +pub const SOYOMBO: &'static [(char, char)] = &[ + ('𑩐', '𑪃'), ('𑪆', '𑪢'), +]; + +pub const SUNDANESE: &'static [(char, char)] = &[ + ('ᮀ', 'ᮿ'), ('᳀', '᳇'), +]; + +pub const SYLOTI_NAGRI: &'static [(char, char)] = &[ + ('।', '॥'), ('০', '৯'), ('ꠀ', 'ê «'), +]; + +pub const SYRIAC: &'static [(char, char)] = &[ + ('،', '،'), ('؛', '\u{61c}'), ('؟', '؟'), ('ـ', 'ـ'), ('ً', 'ٕ'), + ('Ù°', 'Ù°'), ('܀', '܍'), ('\u{70f}', '݊'), ('ݍ', 'ݏ'), ('à¡ ', 'ࡪ'), +]; + +pub const TAGALOG: &'static [(char, char)] = &[ + ('ᜀ', 'ᜌ'), ('ᜎ', '᜔'), ('᜵', '᜶'), +]; + +pub const TAGBANWA: &'static [(char, char)] = &[ + ('᜵', '᜶'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), ('ᝲ', 'ᝳ'), +]; + +pub const TAI_LE: &'static [(char, char)] = &[ + ('၀', '၉'), ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), +]; + +pub const TAI_THAM: &'static [(char, char)] = &[ + ('ᨠ', 'ᩞ'), ('á© ', '᩼'), ('á©¿', '᪉'), ('᪐', '᪙'), + ('᪠', '᪭'), +]; + +pub const TAI_VIET: &'static [(char, char)] = &[ + ('ꪀ', 'ꫂ'), ('ꫛ', '꫟'), +]; + +pub const TAKRI: &'static [(char, char)] = &[ + ('।', '॥'), ('ê °', 'ê ¹'), ('𑚀', '𑚷'), ('𑛀', '𑛉'), +]; + +pub const TAMIL: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ஂ', 'ஃ'), ('அ', 'ஊ'), + ('எ', 'ஐ'), ('ஒ', 'க'), ('ங', 'ச'), ('ஜ', 'ஜ'), + ('ஞ', 'ட'), ('ண', 'த'), ('ந', 'ப'), ('à®®', 'ஹ'), + ('ா', 'ூ'), ('ெ', 'ை'), ('ொ', '்'), ('ௐ', 'ௐ'), + ('ௗ', 'ௗ'), ('௦', '௺'), ('᳚', '᳚'), ('ꣳ', 'ꣳ'), + ('𑌁', '𑌁'), ('𑌃', '𑌃'), ('\u{1133b}', '𑌼'), +]; + +pub const TANGUT: &'static [(char, char)] = &[ + ('𖿠', '𖿠'), ('𗀀', '\u{187f1}'), ('𘠀', '𘫲'), +]; + +pub const TELUGU: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ఀ', 'ఌ'), ('ఎ', 'ఐ'), + ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'ౄ'), ('ె', 'ై'), + ('ొ', '్'), ('ౕ', 'ౖ'), ('ౘ', 'ౚ'), ('à± ', 'à±£'), + ('౦', '౯'), ('౸', '౿'), ('᳚', '᳚'), +]; + +pub const THAANA: &'static [(char, char)] = &[ + ('،', '،'), ('؛', '\u{61c}'), ('؟', '؟'), ('Ù ', 'Ù©'), ('ހ', 'Þ±'), + ('ï·²', 'ï·²'), ('ï·½', 'ï·½'), +]; + +pub const THAI: &'static [(char, char)] = &[ + ('ก', 'ฺ'), ('เ', '๛'), +]; + +pub const TIBETAN: &'static [(char, char)] = &[ + ('ༀ', 'ཇ'), ('ཉ', 'ཬ'), ('ཱ', 'ྗ'), ('ྙ', 'ྼ'), + ('྾', '࿌'), ('࿎', '࿔'), ('࿙', '࿚'), +]; + +pub const TIFINAGH: &'static [(char, char)] = &[ + ('â´°', 'âµ§'), ('ⵯ', 'âµ°'), ('⵿', '⵿'), +]; + +pub const TIRHUTA: &'static [(char, char)] = &[ + ('॑', '॒'), ('।', '॥'), ('ê °', 'ê ¹'), ('𑒀', '𑓇'), + ('𑓐', '𑓙'), +]; + +pub const UGARITIC: &'static [(char, char)] = &[ + ('𐎀', '𐎝'), ('𐎟', '𐎟'), +]; + +pub const VAI: &'static [(char, char)] = &[ + ('ꔀ', 'ꘫ'), +]; + +pub const WARANG_CITI: &'static [(char, char)] = &[ + ('𑢠', '𑣲'), ('𑣿', '𑣿'), +]; + +pub const YI: &'static [(char, char)] = &[ + ('、', '。'), ('〈', '】'), ('〔', '〛'), ('・', '・'), + ('ꀀ', 'ꒌ'), ('꒐', '꓆'), ('。', 'ï½¥'), +]; + +pub const ZANABAZAR_SQUARE: &'static [(char, char)] = &[ + ('𑨀', '𑩇'), +]; diff --git a/regex-syntax/src/unicode_tables/sentence_break.rs b/regex-syntax/src/unicode_tables/sentence_break.rs new file mode 100644 index 000000000..caf8dd33d --- /dev/null +++ b/regex-syntax/src/unicode_tables/sentence_break.rs @@ -0,0 +1,642 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate sentence-break /home/andrew/tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ATerm", ATERM), ("CR", CR), ("Close", CLOSE), ("Extend", EXTEND), + ("Format", FORMAT), ("LF", LF), ("Lower", LOWER), ("Numeric", NUMERIC), + ("OLetter", OLETTER), ("SContinue", SCONTINUE), ("STerm", STERM), + ("Sep", SEP), ("Sp", SP), ("Upper", UPPER), +]; + +pub const ATERM: &'static [(char, char)] = &[ + ('.', '.'), ('․', '․'), ('﹒', '﹒'), ('.', '.'), +]; + +pub const CR: &'static [(char, char)] = &[ + ('\r', '\r'), +]; + +pub const CLOSE: &'static [(char, char)] = &[ + ('\"', '\"'), ('\'', ')'), ('[', '['), (']', ']'), ('{', '{'), ('}', '}'), + ('«', '«'), ('»', '»'), ('༺', '༽'), ('᚛', '᚜'), ('‘', '‟'), + ('‹', '›'), ('⁅', '⁆'), ('⁽', '⁾'), ('₍', '₎'), + ('⌈', '⌋'), ('〈', '〉'), ('❛', '❠'), ('❨', '❵'), + ('⟅', '⟆'), ('⟦', '⟯'), ('⦃', '⦘'), ('⧘', '⧛'), + ('â§¼', 'â§½'), ('⸀', '⸍'), ('⸜', '⸝'), ('⸠', '⸩'), + ('⹂', '⹂'), ('〈', '】'), ('〔', '〛'), ('〝', '〟'), + ('ï´¾', 'ï´¿'), ('︗', '︘'), ('︵', '﹄'), ('﹇', '﹈'), + ('﹙', '﹞'), ('(', ')'), ('ï¼»', 'ï¼»'), ('ï¼½', 'ï¼½'), + ('{', '{'), ('}', '}'), ('⦅', 'ï½ '), ('ï½¢', 'ï½£'), + ('🙶', '🙸'), +]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), ('\u{483}', '\u{489}'), ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dc}'), ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), + ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', 'ः'), ('\u{93a}', '\u{93c}'), + ('ा', 'ॏ'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), ('\u{9bc}', '\u{9bc}'), ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), ('ো', '\u{9cd}'), ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), ('\u{9fe}', '\u{9fe}'), ('\u{a01}', 'ਃ'), + ('\u{a3c}', '\u{a3c}'), ('ਾ', '\u{a42}'), ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), ('\u{a81}', 'ઃ'), ('\u{abc}', '\u{abc}'), + ('ા', '\u{ac5}'), ('\u{ac7}', 'ૉ'), ('ો', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), ('\u{afa}', '\u{aff}'), ('\u{b01}', 'ଃ'), + ('\u{b3c}', '\u{b3c}'), ('\u{b3e}', '\u{b44}'), ('େ', 'ୈ'), + ('ୋ', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), ('\u{bbe}', 'ூ'), ('ெ', 'ை'), + ('ொ', '\u{bcd}'), ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c04}'), + ('\u{c3e}', 'ౄ'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), ('\u{c81}', 'ಃ'), + ('\u{cbc}', '\u{cbc}'), ('ಾ', 'ೄ'), ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', 'ഃ'), ('\u{d3b}', '\u{d3c}'), ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), ('ൊ', '\u{d4d}'), ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), ('ං', 'ඃ'), ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), + ('à·²', 'à·³'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('༾', '༿'), ('\u{f71}', '\u{f84}'), ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('ါ', '\u{103e}'), ('ၖ', '\u{1059}'), ('\u{105e}', '\u{1060}'), + ('ၢ', 'ၤ'), ('ၧ', 'ၭ'), ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), ('ႏ', 'ႏ'), ('ႚ', '\u{109d}'), + ('\u{135d}', '\u{135f}'), ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1734}'), ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), ('\u{17b4}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180d}'), + ('\u{1885}', '\u{1886}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), ('\u{1a17}', '\u{1a1b}'), ('ᩕ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1abe}'), ('\u{1b00}', 'ᬄ'), ('\u{1b34}', '᭄'), + ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', 'ᮂ'), ('ᮡ', '\u{1bad}'), + ('\u{1be6}', '᯳'), ('á°¤', '\u{1c37}'), ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), ('á³²', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), ('\u{1dc0}', '\u{1df9}'), ('\u{1dfb}', '\u{1dff}'), + ('\u{200c}', '\u{200d}'), ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), ('ê £', 'ê §'), + ('ꢀ', 'ꢁ'), ('ꢴ', '\u{a8c5}'), ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), ('\u{a926}', '\u{a92d}'), ('\u{a947}', '꥓'), + ('\u{a980}', 'ꦃ'), ('\u{a9b3}', '꧀'), ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', 'ꩍ'), + ('ê©»', 'ꩽ'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), ('ê««', 'ꫯ'), ('ꫵ', '\u{aaf6}'), + ('ꯣ', 'ꯪ'), ('꯬', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), ('𑀀', '𑀂'), + ('\u{11038}', '\u{11046}'), ('\u{1107f}', '𑂂'), ('𑂰', '\u{110ba}'), + ('\u{11100}', '\u{11102}'), ('\u{11127}', '\u{11134}'), ('𑅅', '𑅆'), + ('\u{11173}', '\u{11173}'), ('\u{11180}', '𑆂'), ('𑆳', '𑇀'), + ('\u{111c9}', '\u{111cc}'), ('𑈬', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), ('\u{112df}', '\u{112ea}'), + ('\u{11300}', '𑌃'), ('\u{1133b}', '\u{1133c}'), ('\u{1133e}', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('\u{11357}', '\u{11357}'), + ('𑍢', '𑍣'), ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}'), + ('𑐵', '\u{11446}'), ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114c3}'), ('\u{115af}', '\u{115b5}'), + ('𑖸', '\u{115c0}'), ('\u{115dc}', '\u{115dd}'), ('𑘰', '\u{11640}'), + ('\u{116ab}', '\u{116b7}'), ('\u{1171d}', '\u{1172b}'), + ('𑠬', '\u{1183a}'), ('\u{11a01}', '\u{11a0a}'), ('\u{11a33}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a5b}'), ('\u{11a8a}', '\u{11a99}'), + ('𑰯', '\u{11c36}'), ('\u{11c38}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), ('𑶊', '𑶎'), ('\u{11d90}', '\u{11d91}'), + ('𑶓', '\u{11d97}'), ('\u{11ef3}', '𑻶'), ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), ('𖽑', '𖽾'), ('\u{16f8f}', '\u{16f92}'), + ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1d165}', '\u{1d169}'), + ('𝅭', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e944}', '\u{1e94a}'), + ('\u{e0020}', '\u{e007f}'), ('\u{e0100}', '\u{e01ef}'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), ('\u{600}', '\u{605}'), ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), ('\u{70f}', '\u{70f}'), ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), ('\u{200b}', '\u{200b}'), + ('\u{200e}', '\u{200f}'), ('\u{202a}', '\u{202e}'), + ('\u{2060}', '\u{2064}'), ('\u{2066}', '\u{206f}'), + ('\u{feff}', '\u{feff}'), ('\u{fff9}', '\u{fffb}'), + ('\u{110bd}', '\u{110bd}'), ('\u{110cd}', '\u{110cd}'), + ('\u{1bca0}', '\u{1bca3}'), ('\u{1d173}', '\u{1d17a}'), + ('\u{e0001}', '\u{e0001}'), +]; + +pub const LF: &'static [(char, char)] = &[ + ('\n', '\n'), +]; + +pub const LOWER: &'static [(char, char)] = &[ + ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), ('ß', 'ö'), + ('ø', 'ÿ'), ('ā', 'ā'), ('ă', 'ă'), ('ą', 'ą'), ('ć', 'ć'), + ('ĉ', 'ĉ'), ('ċ', 'ċ'), ('č', 'č'), ('ď', 'ď'), ('đ', 'đ'), + ('ē', 'ē'), ('ĕ', 'ĕ'), ('ė', 'ė'), ('ę', 'ę'), ('ě', 'ě'), + ('ĝ', 'ĝ'), ('ğ', 'ğ'), ('Ä¡', 'Ä¡'), ('Ä£', 'Ä£'), ('Ä¥', 'Ä¥'), + ('ħ', 'ħ'), ('Ä©', 'Ä©'), ('Ä«', 'Ä«'), ('Ä­', 'Ä­'), ('į', 'į'), + ('ı', 'ı'), ('ij', 'ij'), ('ĵ', 'ĵ'), ('Ä·', 'ĸ'), ('ĺ', 'ĺ'), + ('ļ', 'ļ'), ('ľ', 'ľ'), ('ŀ', 'ŀ'), ('ł', 'ł'), ('ń', 'ń'), + ('ņ', 'ņ'), ('ň', 'ʼn'), ('ŋ', 'ŋ'), ('ō', 'ō'), ('ŏ', 'ŏ'), + ('ő', 'ő'), ('œ', 'œ'), ('ŕ', 'ŕ'), ('ŗ', 'ŗ'), ('ř', 'ř'), + ('ś', 'ś'), ('ŝ', 'ŝ'), ('ş', 'ş'), ('Å¡', 'Å¡'), ('Å£', 'Å£'), + ('Å¥', 'Å¥'), ('ŧ', 'ŧ'), ('Å©', 'Å©'), ('Å«', 'Å«'), ('Å­', 'Å­'), + ('ů', 'ů'), ('ű', 'ű'), ('ų', 'ų'), ('ŵ', 'ŵ'), ('Å·', 'Å·'), + ('ź', 'ź'), ('ż', 'ż'), ('ž', 'ƀ'), ('ƃ', 'ƃ'), ('ƅ', 'ƅ'), + ('ƈ', 'ƈ'), ('ƌ', 'ƍ'), ('ƒ', 'ƒ'), ('ƕ', 'ƕ'), ('ƙ', 'ƛ'), + ('ƞ', 'ƞ'), ('Æ¡', 'Æ¡'), ('Æ£', 'Æ£'), ('Æ¥', 'Æ¥'), ('ƨ', 'ƨ'), + ('ƪ', 'Æ«'), ('Æ­', 'Æ­'), ('ư', 'ư'), ('Æ´', 'Æ´'), ('ƶ', 'ƶ'), + ('ƹ', 'ƺ'), ('ƽ', 'Æ¿'), ('dž', 'dž'), ('lj', 'lj'), ('nj', 'nj'), + ('ǎ', 'ǎ'), ('ǐ', 'ǐ'), ('ǒ', 'ǒ'), ('ǔ', 'ǔ'), ('ǖ', 'ǖ'), + ('ǘ', 'ǘ'), ('ǚ', 'ǚ'), ('ǜ', 'ǝ'), ('ǟ', 'ǟ'), ('Ç¡', 'Ç¡'), + ('Ç£', 'Ç£'), ('Ç¥', 'Ç¥'), ('ǧ', 'ǧ'), ('Ç©', 'Ç©'), ('Ç«', 'Ç«'), + ('Ç­', 'Ç­'), ('ǯ', 'ǰ'), ('dz', 'dz'), ('ǵ', 'ǵ'), ('ǹ', 'ǹ'), + ('Ç»', 'Ç»'), ('ǽ', 'ǽ'), ('Ç¿', 'Ç¿'), ('ȁ', 'ȁ'), ('ȃ', 'ȃ'), + ('ȅ', 'ȅ'), ('ȇ', 'ȇ'), ('ȉ', 'ȉ'), ('ȋ', 'ȋ'), ('ȍ', 'ȍ'), + ('ȏ', 'ȏ'), ('ȑ', 'ȑ'), ('ȓ', 'ȓ'), ('ȕ', 'ȕ'), ('ȗ', 'ȗ'), + ('ș', 'ș'), ('ț', 'ț'), ('ȝ', 'ȝ'), ('ȟ', 'ȟ'), ('È¡', 'È¡'), + ('È£', 'È£'), ('È¥', 'È¥'), ('ȧ', 'ȧ'), ('È©', 'È©'), ('È«', 'È«'), + ('È­', 'È­'), ('ȯ', 'ȯ'), ('ȱ', 'ȱ'), ('ȳ', 'ȹ'), ('ȼ', 'ȼ'), + ('È¿', 'ɀ'), ('ɂ', 'ɂ'), ('ɇ', 'ɇ'), ('ɉ', 'ɉ'), ('ɋ', 'ɋ'), + ('ɍ', 'ɍ'), ('ɏ', 'ʓ'), ('ʕ', 'ʸ'), ('ˀ', 'ˁ'), ('Ë ', 'ˤ'), + ('ͱ', 'ͱ'), ('ͳ', 'ͳ'), ('Í·', 'Í·'), ('ͺ', 'ͽ'), ('ΐ', 'ΐ'), + ('ά', 'ώ'), ('ϐ', 'ϑ'), ('ϕ', 'ϗ'), ('ϙ', 'ϙ'), ('ϛ', 'ϛ'), + ('ϝ', 'ϝ'), ('ϟ', 'ϟ'), ('Ï¡', 'Ï¡'), ('Ï£', 'Ï£'), ('Ï¥', 'Ï¥'), + ('ϧ', 'ϧ'), ('Ï©', 'Ï©'), ('Ï«', 'Ï«'), ('Ï­', 'Ï­'), ('ϯ', 'ϳ'), + ('ϵ', 'ϵ'), ('ϸ', 'ϸ'), ('Ï»', 'ϼ'), ('а', 'џ'), ('Ñ¡', 'Ñ¡'), + ('Ñ£', 'Ñ£'), ('Ñ¥', 'Ñ¥'), ('ѧ', 'ѧ'), ('Ñ©', 'Ñ©'), ('Ñ«', 'Ñ«'), + ('Ñ­', 'Ñ­'), ('ѯ', 'ѯ'), ('ѱ', 'ѱ'), ('ѳ', 'ѳ'), ('ѵ', 'ѵ'), + ('Ñ·', 'Ñ·'), ('ѹ', 'ѹ'), ('Ñ»', 'Ñ»'), ('ѽ', 'ѽ'), ('Ñ¿', 'Ñ¿'), + ('ҁ', 'ҁ'), ('ҋ', 'ҋ'), ('ҍ', 'ҍ'), ('ҏ', 'ҏ'), ('ґ', 'ґ'), + ('ғ', 'ғ'), ('ҕ', 'ҕ'), ('җ', 'җ'), ('ҙ', 'ҙ'), ('қ', 'қ'), + ('ҝ', 'ҝ'), ('ҟ', 'ҟ'), ('Ò¡', 'Ò¡'), ('Ò£', 'Ò£'), ('Ò¥', 'Ò¥'), + ('Ò§', 'Ò§'), ('Ò©', 'Ò©'), ('Ò«', 'Ò«'), ('Ò­', 'Ò­'), ('Ò¯', 'Ò¯'), + ('Ò±', 'Ò±'), ('Ò³', 'Ò³'), ('Òµ', 'Òµ'), ('Ò·', 'Ò·'), ('Ò¹', 'Ò¹'), + ('Ò»', 'Ò»'), ('Ò½', 'Ò½'), ('Ò¿', 'Ò¿'), ('ӂ', 'ӂ'), ('ӄ', 'ӄ'), + ('ӆ', 'ӆ'), ('ӈ', 'ӈ'), ('ӊ', 'ӊ'), ('ӌ', 'ӌ'), ('ӎ', 'ӏ'), + ('ӑ', 'ӑ'), ('ӓ', 'ӓ'), ('ӕ', 'ӕ'), ('ӗ', 'ӗ'), ('ә', 'ә'), + ('ӛ', 'ӛ'), ('ӝ', 'ӝ'), ('ӟ', 'ӟ'), ('Ó¡', 'Ó¡'), ('Ó£', 'Ó£'), + ('Ó¥', 'Ó¥'), ('Ó§', 'Ó§'), ('Ó©', 'Ó©'), ('Ó«', 'Ó«'), ('Ó­', 'Ó­'), + ('Ó¯', 'Ó¯'), ('Ó±', 'Ó±'), ('Ó³', 'Ó³'), ('Óµ', 'Óµ'), ('Ó·', 'Ó·'), + ('Ó¹', 'Ó¹'), ('Ó»', 'Ó»'), ('Ó½', 'Ó½'), ('Ó¿', 'Ó¿'), ('ԁ', 'ԁ'), + ('ԃ', 'ԃ'), ('ԅ', 'ԅ'), ('ԇ', 'ԇ'), ('ԉ', 'ԉ'), ('ԋ', 'ԋ'), + ('ԍ', 'ԍ'), ('ԏ', 'ԏ'), ('ԑ', 'ԑ'), ('ԓ', 'ԓ'), ('ԕ', 'ԕ'), + ('ԗ', 'ԗ'), ('ԙ', 'ԙ'), ('ԛ', 'ԛ'), ('ԝ', 'ԝ'), ('ԟ', 'ԟ'), + ('Ô¡', 'Ô¡'), ('Ô£', 'Ô£'), ('Ô¥', 'Ô¥'), ('Ô§', 'Ô§'), ('Ô©', 'Ô©'), + ('Ô«', 'Ô«'), ('Ô­', 'Ô­'), ('Ô¯', 'Ô¯'), ('Õ ', 'ֈ'), ('ა', 'ჺ'), + ('ჽ', 'ჿ'), ('ᏸ', 'ᏽ'), ('ᲀ', 'ᲈ'), ('ᴀ', 'á¶¿'), + ('ḁ', 'ḁ'), ('ḃ', 'ḃ'), ('ḅ', 'ḅ'), ('ḇ', 'ḇ'), + ('ḉ', 'ḉ'), ('ḋ', 'ḋ'), ('ḍ', 'ḍ'), ('ḏ', 'ḏ'), + ('ḑ', 'ḑ'), ('ḓ', 'ḓ'), ('ḕ', 'ḕ'), ('ḗ', 'ḗ'), + ('ḙ', 'ḙ'), ('ḛ', 'ḛ'), ('ḝ', 'ḝ'), ('ḟ', 'ḟ'), + ('ḡ', 'ḡ'), ('ḣ', 'ḣ'), ('ḥ', 'ḥ'), ('ḧ', 'ḧ'), + ('ḩ', 'ḩ'), ('ḫ', 'ḫ'), ('ḭ', 'ḭ'), ('ḯ', 'ḯ'), + ('ḱ', 'ḱ'), ('ḳ', 'ḳ'), ('ḵ', 'ḵ'), ('ḷ', 'ḷ'), + ('ḹ', 'ḹ'), ('ḻ', 'ḻ'), ('ḽ', 'ḽ'), ('ḿ', 'ḿ'), + ('ṁ', 'ṁ'), ('ṃ', 'ṃ'), ('ṅ', 'ṅ'), ('ṇ', 'ṇ'), + ('ṉ', 'ṉ'), ('ṋ', 'ṋ'), ('ṍ', 'ṍ'), ('ṏ', 'ṏ'), + ('ṑ', 'ṑ'), ('ṓ', 'ṓ'), ('ṕ', 'ṕ'), ('ṗ', 'ṗ'), + ('ṙ', 'ṙ'), ('ṛ', 'ṛ'), ('ṝ', 'ṝ'), ('ṟ', 'ṟ'), + ('ṡ', 'ṡ'), ('á¹£', 'á¹£'), ('á¹¥', 'á¹¥'), ('á¹§', 'á¹§'), + ('ṩ', 'ṩ'), ('ṫ', 'ṫ'), ('á¹­', 'á¹­'), ('ṯ', 'ṯ'), + ('á¹±', 'á¹±'), ('á¹³', 'á¹³'), ('á¹µ', 'á¹µ'), ('á¹·', 'á¹·'), + ('á¹¹', 'á¹¹'), ('á¹»', 'á¹»'), ('á¹½', 'á¹½'), ('ṿ', 'ṿ'), + ('ẁ', 'ẁ'), ('ẃ', 'ẃ'), ('ẅ', 'ẅ'), ('ẇ', 'ẇ'), + ('ẉ', 'ẉ'), ('ẋ', 'ẋ'), ('ẍ', 'ẍ'), ('ẏ', 'ẏ'), + ('ẑ', 'ẑ'), ('ẓ', 'ẓ'), ('ẕ', 'ẝ'), ('ẟ', 'ẟ'), + ('ạ', 'ạ'), ('ả', 'ả'), ('ấ', 'ấ'), ('ầ', 'ầ'), + ('ẩ', 'ẩ'), ('ẫ', 'ẫ'), ('ậ', 'ậ'), ('ắ', 'ắ'), + ('ằ', 'ằ'), ('ẳ', 'ẳ'), ('ẵ', 'ẵ'), ('ặ', 'ặ'), + ('ẹ', 'ẹ'), ('ẻ', 'ẻ'), ('ẽ', 'ẽ'), ('ế', 'ế'), + ('ề', 'ề'), ('ể', 'ể'), ('ễ', 'ễ'), ('ệ', 'ệ'), + ('ỉ', 'ỉ'), ('ị', 'ị'), ('ọ', 'ọ'), ('ỏ', 'ỏ'), + ('ố', 'ố'), ('ồ', 'ồ'), ('ổ', 'ổ'), ('ỗ', 'ỗ'), + ('ộ', 'ộ'), ('ớ', 'ớ'), ('ờ', 'ờ'), ('ở', 'ở'), + ('ỡ', 'ỡ'), ('ợ', 'ợ'), ('ụ', 'ụ'), ('á»§', 'á»§'), + ('ứ', 'ứ'), ('ừ', 'ừ'), ('á»­', 'á»­'), ('ữ', 'ữ'), + ('á»±', 'á»±'), ('ỳ', 'ỳ'), ('ỵ', 'ỵ'), ('á»·', 'á»·'), + ('ỹ', 'ỹ'), ('á»»', 'á»»'), ('ỽ', 'ỽ'), ('ỿ', 'ἇ'), + ('ἐ', 'ἕ'), ('á¼ ', 'á¼§'), ('á¼°', 'á¼·'), ('ὀ', 'ὅ'), + ('ὐ', 'ὗ'), ('á½ ', 'á½§'), ('á½°', 'á½½'), ('ᾀ', 'ᾇ'), + ('ᾐ', 'ᾗ'), ('á¾ ', 'á¾§'), ('á¾°', 'á¾´'), ('á¾¶', 'á¾·'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῇ'), ('ῐ', 'ΐ'), + ('ῖ', 'ῗ'), ('á¿ ', 'á¿§'), ('ῲ', 'á¿´'), ('á¿¶', 'á¿·'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('ℊ', 'ℊ'), + ('ℎ', 'ℏ'), ('ℓ', 'ℓ'), ('ℯ', 'ℯ'), ('ℴ', 'ℴ'), + ('ℹ', 'ℹ'), ('ℼ', 'ℽ'), ('ⅆ', 'ⅉ'), ('ⅎ', 'ⅎ'), + ('ⅰ', 'ⅿ'), ('ↄ', 'ↄ'), ('ⓐ', 'ⓩ'), ('â°°', 'ⱞ'), + ('ⱡ', 'ⱡ'), ('â±¥', 'ⱦ'), ('ⱨ', 'ⱨ'), ('ⱪ', 'ⱪ'), + ('ⱬ', 'ⱬ'), ('â±±', 'â±±'), ('â±³', 'â±´'), ('â±¶', 'â±½'), + ('ⲁ', 'ⲁ'), ('ⲃ', 'ⲃ'), ('ⲅ', 'ⲅ'), ('ⲇ', 'ⲇ'), + ('ⲉ', 'ⲉ'), ('ⲋ', 'ⲋ'), ('ⲍ', 'ⲍ'), ('ⲏ', 'ⲏ'), + ('ⲑ', 'ⲑ'), ('ⲓ', 'ⲓ'), ('ⲕ', 'ⲕ'), ('ⲗ', 'ⲗ'), + ('ⲙ', 'ⲙ'), ('ⲛ', 'ⲛ'), ('ⲝ', 'ⲝ'), ('ⲟ', 'ⲟ'), + ('ⲡ', 'ⲡ'), ('â²£', 'â²£'), ('â²¥', 'â²¥'), ('â²§', 'â²§'), + ('ⲩ', 'ⲩ'), ('ⲫ', 'ⲫ'), ('â²­', 'â²­'), ('ⲯ', 'ⲯ'), + ('â²±', 'â²±'), ('â²³', 'â²³'), ('â²µ', 'â²µ'), ('â²·', 'â²·'), + ('â²¹', 'â²¹'), ('â²»', 'â²»'), ('â²½', 'â²½'), ('ⲿ', 'ⲿ'), + ('ⳁ', 'ⳁ'), ('ⳃ', 'ⳃ'), ('ⳅ', 'ⳅ'), ('ⳇ', 'ⳇ'), + ('ⳉ', 'ⳉ'), ('ⳋ', 'ⳋ'), ('ⳍ', 'ⳍ'), ('ⳏ', 'ⳏ'), + ('ⳑ', 'ⳑ'), ('ⳓ', 'ⳓ'), ('ⳕ', 'ⳕ'), ('ⳗ', 'ⳗ'), + ('ⳙ', 'ⳙ'), ('ⳛ', 'ⳛ'), ('ⳝ', 'ⳝ'), ('ⳟ', 'ⳟ'), + ('ⳡ', 'ⳡ'), ('â³£', 'ⳤ'), ('ⳬ', 'ⳬ'), ('â³®', 'â³®'), + ('â³³', 'â³³'), ('ⴀ', 'â´¥'), ('â´§', 'â´§'), ('â´­', 'â´­'), + ('ꙁ', 'ꙁ'), ('ꙃ', 'ꙃ'), ('ꙅ', 'ꙅ'), ('ꙇ', 'ꙇ'), + ('ꙉ', 'ꙉ'), ('ꙋ', 'ꙋ'), ('ꙍ', 'ꙍ'), ('ꙏ', 'ꙏ'), + ('ꙑ', 'ꙑ'), ('ꙓ', 'ꙓ'), ('ꙕ', 'ꙕ'), ('ꙗ', 'ꙗ'), + ('ꙙ', 'ꙙ'), ('ꙛ', 'ꙛ'), ('ꙝ', 'ꙝ'), ('ꙟ', 'ꙟ'), + ('ꙡ', 'ꙡ'), ('ꙣ', 'ꙣ'), ('ꙥ', 'ꙥ'), ('ꙧ', 'ꙧ'), + ('ꙩ', 'ꙩ'), ('ꙫ', 'ꙫ'), ('ꙭ', 'ꙭ'), ('ꚁ', 'ꚁ'), + ('ꚃ', 'ꚃ'), ('ꚅ', 'ꚅ'), ('ꚇ', 'ꚇ'), ('ꚉ', 'ꚉ'), + ('ꚋ', 'ꚋ'), ('ꚍ', 'ꚍ'), ('ꚏ', 'ꚏ'), ('ꚑ', 'ꚑ'), + ('ꚓ', 'ꚓ'), ('ꚕ', 'ꚕ'), ('ꚗ', 'ꚗ'), ('ꚙ', 'ꚙ'), + ('ꚛ', 'ꚝ'), ('ꜣ', 'ꜣ'), ('ꜥ', 'ꜥ'), ('ꜧ', 'ꜧ'), + ('ꜩ', 'ꜩ'), ('ꜫ', 'ꜫ'), ('ꜭ', 'ꜭ'), ('ꜯ', 'ꜱ'), + ('ꜳ', 'ꜳ'), ('ꜵ', 'ꜵ'), ('ꜷ', 'ꜷ'), ('ꜹ', 'ꜹ'), + ('ꜻ', 'ꜻ'), ('ꜽ', 'ꜽ'), ('ꜿ', 'ꜿ'), ('ꝁ', 'ꝁ'), + ('ꝃ', 'ꝃ'), ('ꝅ', 'ꝅ'), ('ꝇ', 'ꝇ'), ('ꝉ', 'ꝉ'), + ('ꝋ', 'ꝋ'), ('ꝍ', 'ꝍ'), ('ꝏ', 'ꝏ'), ('ꝑ', 'ꝑ'), + ('ꝓ', 'ꝓ'), ('ꝕ', 'ꝕ'), ('ꝗ', 'ꝗ'), ('ꝙ', 'ꝙ'), + ('ꝛ', 'ꝛ'), ('ꝝ', 'ꝝ'), ('ꝟ', 'ꝟ'), ('ꝡ', 'ꝡ'), + ('ꝣ', 'ꝣ'), ('ꝥ', 'ꝥ'), ('ꝧ', 'ꝧ'), ('ꝩ', 'ꝩ'), + ('ꝫ', 'ꝫ'), ('ꝭ', 'ꝭ'), ('ꝯ', 'ꝸ'), ('ꝺ', 'ꝺ'), + ('ꝼ', 'ꝼ'), ('ꝿ', 'ꝿ'), ('ꞁ', 'ꞁ'), ('ꞃ', 'ꞃ'), + ('ꞅ', 'ꞅ'), ('ꞇ', 'ꞇ'), ('ꞌ', 'ꞌ'), ('ꞎ', 'ꞎ'), + ('ꞑ', 'ꞑ'), ('ꞓ', 'ꞕ'), ('ꞗ', 'ꞗ'), ('ꞙ', 'ꞙ'), + ('ꞛ', 'ꞛ'), ('ꞝ', 'ꞝ'), ('ꞟ', 'ꞟ'), ('ꞡ', 'ꞡ'), + ('ꞣ', 'ꞣ'), ('ꞥ', 'ꞥ'), ('ꞧ', 'ꞧ'), ('ꞩ', 'ꞩ'), + ('ꞯ', 'ꞯ'), ('ꞵ', 'ꞵ'), ('ꞷ', 'ꞷ'), ('ꞹ', 'ꞹ'), + ('ꟸ', 'ꟺ'), ('ꬰ', 'ꭚ'), ('ꭜ', 'ê­¥'), ('ê­°', 'ꮿ'), + ('ff', 'st'), ('ﬓ', 'ﬗ'), ('a', 'z'), ('𐐨', '𐑏'), + ('𐓘', '𐓻'), ('𐳀', '𐳲'), ('𑣀', '𑣟'), ('𖹠', '𖹿'), + ('𝐚', '𝐳'), ('𝑎', '𝑔'), ('𝑖', '𝑧'), ('𝒂', '𝒛'), + ('𝒶', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝓏'), + ('𝓪', '𝔃'), ('𝔞', '𝔷'), ('𝕒', '𝕫'), ('𝖆', '𝖟'), + ('𝖺', '𝗓'), ('𝗮', '𝘇'), ('𝘢', '𝘻'), ('𝙖', '𝙯'), + ('𝚊', '𝚥'), ('𝛂', '𝛚'), ('𝛜', '𝛡'), ('𝛼', '𝜔'), + ('𝜖', '𝜛'), ('𝜶', '𝝎'), ('𝝐', '𝝕'), ('𝝰', '𝞈'), + ('𝞊', '𝞏'), ('𝞪', '𝟂'), ('𝟄', '𝟉'), ('𝟋', '𝟋'), + ('𞤢', '𞥃'), +]; + +pub const NUMERIC: &'static [(char, char)] = &[ + ('0', '9'), ('Ù ', 'Ù©'), ('Ù«', 'Ù¬'), ('Û°', 'Û¹'), ('߀', '߉'), + ('०', '९'), ('০', '৯'), ('੦', '੯'), ('૦', '૯'), + ('à­¦', 'à­¯'), ('௦', '௯'), ('౦', '౯'), ('೦', '೯'), + ('൦', '൯'), ('à·¦', 'à·¯'), ('๐', '๙'), ('໐', '໙'), + ('༠', '༩'), ('၀', '၉'), ('႐', '႙'), ('០', '៩'), + ('᠐', '᠙'), ('᥆', '᥏'), ('᧐', '᧙'), ('᪀', '᪉'), + ('᪐', '᪙'), ('᭐', '᭙'), ('á®°', '᮹'), ('᱀', '᱉'), + ('᱐', '᱙'), ('꘠', '꘩'), ('꣐', '꣙'), ('꤀', '꤉'), + ('꧐', '꧙'), ('ê§°', 'ê§¹'), ('꩐', '꩙'), ('꯰', '꯹'), + ('𐒠', '𐒩'), ('𐴰', '𐴹'), ('𑁦', '𑁯'), ('𑃰', '𑃹'), + ('𑄶', '𑄿'), ('𑇐', '𑇙'), ('𑋰', '𑋹'), ('𑑐', '𑑙'), + ('𑓐', '𑓙'), ('𑙐', '𑙙'), ('𑛀', '𑛉'), ('𑜰', '𑜹'), + ('𑣠', '𑣩'), ('𑱐', '𑱙'), ('𑵐', '𑵙'), ('𑶠', '𑶩'), + ('𖩠', '𖩩'), ('𖭐', '𖭙'), ('𝟎', '𝟿'), ('𞥐', '𞥙'), +]; + +pub const OLETTER: &'static [(char, char)] = &[ + ('Æ»', 'Æ»'), ('ǀ', 'ǃ'), ('ʔ', 'ʔ'), ('ʹ', 'Ê¿'), ('ˆ', 'ˑ'), + ('ˬ', 'ˬ'), ('Ë®', 'Ë®'), ('Í´', 'Í´'), ('ՙ', 'ՙ'), ('א', 'ת'), + ('ׯ', '׳'), ('Ø ', 'ي'), ('Ù®', 'Ù¯'), ('Ù±', 'ۓ'), ('ە', 'ە'), + ('Û¥', 'Û¦'), ('Û®', 'Û¯'), ('Ûº', 'Û¼'), ('Û¿', 'Û¿'), ('ܐ', 'ܐ'), + ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), ('ߊ', 'ߪ'), ('ß´', 'ßµ'), + ('ߺ', 'ߺ'), ('ࠀ', 'ࠕ'), ('ࠚ', 'ࠚ'), ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), ('ऽ', 'ऽ'), ('ॐ', 'ॐ'), + ('क़', 'ॡ'), ('ॱ', 'ঀ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), ('ড়', 'ঢ়'), ('য়', 'à§¡'), + ('à§°', 'à§±'), ('à§¼', 'à§¼'), ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), + ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('ੲ', 'à©´'), + ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('ઽ', 'ઽ'), ('ૐ', 'ૐ'), + ('à« ', 'à«¡'), ('ૹ', 'ૹ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), + ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), ('à­±', 'à­±'), + ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), ('ஒ', 'க'), + ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), ('ண', 'த'), + ('ந', 'ப'), ('à®®', 'ஹ'), ('ௐ', 'ௐ'), ('అ', 'ఌ'), + ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'à°½'), + ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('ಀ', 'ಀ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), ('à³±', 'à³²'), + ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), ('à´½', 'à´½'), + ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), ('ൟ', 'ൡ'), ('ൺ', 'ൿ'), + ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), + ('ව', 'ෆ'), ('ก', 'ะ'), ('า', 'ำ'), ('เ', 'ๆ'), + ('ກ', 'ຂ'), ('ຄ', 'ຄ'), ('ງ', 'ຈ'), ('ຊ', 'ຊ'), + ('ຍ', 'ຍ'), ('ດ', 'ທ'), ('ນ', 'ຟ'), ('ມ', 'ຣ'), + ('ລ', 'ລ'), ('ວ', 'ວ'), ('ສ', 'ຫ'), ('ອ', 'ະ'), + ('າ', 'ຳ'), ('ຽ', 'ຽ'), ('ເ', 'ໄ'), ('ໆ', 'ໆ'), + ('ໜ', 'ໟ'), ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), ('က', 'ဪ'), ('ဿ', 'ဿ'), ('ၐ', 'ၕ'), + ('ၚ', 'ၝ'), ('ၡ', 'ၡ'), ('ၥ', 'ၦ'), ('ၮ', 'ၰ'), + ('ၵ', 'ႁ'), ('ႎ', 'ႎ'), ('ჼ', 'ჼ'), ('ᄀ', 'ቈ'), + ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), + ('በ', 'ኈ'), ('ኊ', 'ኍ'), ('ነ', 'ኰ'), ('ኲ', 'ኵ'), + ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), ('ዂ', 'ዅ'), ('ወ', 'ዖ'), + ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), ('ጘ', 'ፚ'), ('ᎀ', 'ᎏ'), + ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), + ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), + ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), ('ក', 'ឳ'), + ('ៗ', 'ៗ'), ('ៜ', 'ៜ'), ('á  ', 'ᡸ'), ('ᢀ', 'ᢄ'), + ('ᢇ', 'ᢨ'), ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), ('ᤀ', 'ᤞ'), + ('ᥐ', 'ᥭ'), ('ᥰ', 'ᥴ'), ('ᦀ', 'ᦫ'), ('ᦰ', 'ᧉ'), + ('ᨀ', 'ᨖ'), ('ᨠ', 'ᩔ'), ('ᪧ', 'ᪧ'), ('ᬅ', 'ᬳ'), + ('ᭅ', 'ᭋ'), ('ᮃ', 'á® '), ('á®®', 'ᮯ'), ('ᮺ', 'ᯥ'), + ('ᰀ', 'á°£'), ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), ('ᳩ', 'ᳬ'), + ('á³®', 'á³±'), ('á³µ', 'á³¶'), ('ℵ', 'ℸ'), ('ↀ', 'ↂ'), + ('ↅ', 'ↈ'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), ('ⶀ', 'ⶖ'), + ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), ('ⶸ', 'â¶¾'), + ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), ('ⷘ', 'ⷞ'), + ('ⸯ', 'ⸯ'), ('々', '〇'), ('〡', '〩'), ('〱', '〵'), + ('〸', '〼'), ('ぁ', 'ゖ'), ('ゝ', 'ゟ'), ('ァ', 'ヺ'), + ('ー', 'ヿ'), ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), + ('ㇰ', 'ㇿ'), ('㐀', 'ä¶µ'), ('一', '鿯'), ('ꀀ', 'ꒌ'), + ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), + ('ꙮ', 'ꙮ'), ('ꙿ', 'ꙿ'), ('ꚠ', 'ꛯ'), ('ꜗ', 'ꜟ'), + ('ꞈ', 'ꞈ'), ('ꞏ', 'ꞏ'), ('ꟷ', 'ꟷ'), ('ꟻ', 'ꠁ'), + ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), ('ꠌ', 'ê ¢'), ('ꡀ', 'ꡳ'), + ('ꢂ', 'ꢳ'), ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), ('ꣽ', 'ꣾ'), + ('ꤊ', 'ꤥ'), ('ꤰ', 'ꥆ'), ('ꥠ', 'ꥼ'), ('ꦄ', 'ꦲ'), + ('ꧏ', 'ꧏ'), ('ê§ ', 'ꧤ'), ('ꧦ', 'ꧯ'), ('ꧺ', 'ê§¾'), + ('ꨀ', 'ꨨ'), ('ꩀ', 'ꩂ'), ('ꩄ', 'ꩋ'), ('ê© ', 'ê©¶'), + ('ꩺ', 'ꩺ'), ('ꩾ', 'ꪯ'), ('ꪱ', 'ꪱ'), ('ꪵ', 'ꪶ'), + ('ꪹ', 'ꪽ'), ('ꫀ', 'ꫀ'), ('ꫂ', 'ꫂ'), ('ꫛ', 'ꫝ'), + ('ê« ', 'ꫪ'), ('ꫲ', 'ê«´'), ('ꬁ', 'ꬆ'), ('ꬉ', 'ꬎ'), + ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), ('ꯀ', 'ꯢ'), + ('가', '힣'), ('ힰ', 'ퟆ'), ('ퟋ', 'ퟻ'), ('豈', 'ï©­'), + ('ï©°', '龎'), ('יִ', 'יִ'), ('ײַ', 'ﬨ'), ('שׁ', 'זּ'), + ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), + ('צּ', 'ï®±'), ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), + ('ï·°', 'ï·»'), ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), ('ヲ', 'ン'), + ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), + ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), + ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), + ('𐅀', '𐅴'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐌀', '𐌟'), + ('𐌭', '𐍊'), ('𐍐', '𐍵'), ('𐎀', '𐎝'), ('𐎠', '𐏃'), + ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐑐', '𐒝'), ('𐔀', '𐔧'), + ('𐔰', '𐕣'), ('𐘀', '𐜶'), ('𐝀', '𐝕'), ('𐝠', '𐝧'), + ('𐠀', '𐠅'), ('𐠈', '𐠈'), ('𐠊', '𐠵'), ('𐠷', '𐠸'), + ('𐠼', '𐠼'), ('𐠿', '𐡕'), ('𐡠', '𐡶'), ('𐢀', '𐢞'), + ('𐣠', '𐣲'), ('𐣴', '𐣵'), ('𐤀', '𐤕'), ('𐤠', '𐤹'), + ('𐦀', '𐦷'), ('𐦾', '𐦿'), ('𐨀', '𐨀'), ('𐨐', '𐨓'), + ('𐨕', '𐨗'), ('𐨙', '𐨵'), ('𐩠', '𐩼'), ('𐪀', '𐪜'), + ('𐫀', '𐫇'), ('𐫉', '𐫤'), ('𐬀', '𐬵'), ('𐭀', '𐭕'), + ('𐭠', '𐭲'), ('𐮀', '𐮑'), ('𐰀', '𐱈'), ('𐴀', '𐴣'), + ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '𐽅'), ('𑀃', '𑀷'), + ('𑂃', '𑂯'), ('𑃐', '𑃨'), ('𑄃', '𑄦'), ('𑅄', '𑅄'), + ('𑅐', '𑅲'), ('𑅶', '𑅶'), ('𑆃', '𑆲'), ('𑇁', '𑇄'), + ('𑇚', '𑇚'), ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '𑈫'), + ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), + ('𑊟', '𑊨'), ('𑊰', '𑋞'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('𑌽', '𑌽'), ('𑍐', '𑍐'), ('𑍝', '𑍡'), ('𑐀', '𑐴'), + ('𑑇', '𑑊'), ('𑒀', '𑒯'), ('𑓄', '𑓅'), ('𑓇', '𑓇'), + ('𑖀', '𑖮'), ('𑗘', '𑗛'), ('𑘀', '𑘯'), ('𑙄', '𑙄'), + ('𑚀', '𑚪'), ('𑜀', '𑜚'), ('𑠀', '𑠫'), ('𑣿', '𑣿'), + ('𑨀', '𑨀'), ('𑨋', '𑨲'), ('𑨺', '𑨺'), ('𑩐', '𑩐'), + ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('𑪝', '𑪝'), ('𑫀', '𑫸'), + ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), ('𑱲', '𑲏'), + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), ('𑵆', '𑵆'), + ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶉'), ('𑶘', '𑶘'), + ('𑻠', '𑻲'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭀', '𖭃'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('𖼀', '𖽄'), ('𖽐', '𖽐'), ('𖾓', '𖾟'), + ('𖿠', '𖿡'), ('𗀀', '𘟱'), ('𘠀', '𘫲'), ('𛀀', '𛄞'), + ('𛅰', '𛋻'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), ('𛲀', '𛲈'), + ('𛲐', '𛲙'), ('𞠀', '𞣄'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('𠀀', '𪛖'), + ('𪜀', '𫜴'), ('𫝀', '𫠝'), ('ð«  ', '𬺡'), ('𬺰', '𮯠'), + ('丽', '𪘀'), +]; + +pub const SCONTINUE: &'static [(char, char)] = &[ + (',', '-'), (':', ':'), ('՝', '՝'), ('،', '؍'), ('߸', '߸'), + ('᠂', '᠂'), ('᠈', '᠈'), ('–', '—'), ('、', '、'), + ('︐', '︑'), ('︓', '︓'), ('︱', '︲'), ('﹐', '﹑'), + ('﹕', '﹕'), ('﹘', '﹘'), ('ï¹£', 'ï¹£'), (',', '-'), + (':', ':'), ('、', '、'), +]; + +pub const STERM: &'static [(char, char)] = &[ + ('!', '!'), ('?', '?'), ('։', '։'), ('؞', '؟'), ('۔', '۔'), + ('܀', '܂'), ('ß¹', 'ß¹'), ('à ·', 'à ·'), ('à ¹', 'à ¹'), ('à ½', 'à ¾'), + ('।', '॥'), ('၊', '။'), ('።', '።'), ('፧', '፨'), + ('᙮', '᙮'), ('᜵', '᜶'), ('᠃', '᠃'), ('᠉', '᠉'), + ('᥄', '᥅'), ('᪨', '᪫'), ('᭚', '᭛'), ('᭞', '᭟'), + ('á°»', 'á°¼'), ('á±¾', '᱿'), ('‼', '‽'), ('⁇', '⁉'), + ('⸮', '⸮'), ('⸼', '⸼'), ('。', '。'), ('꓿', '꓿'), + ('꘎', '꘏'), ('꛳', '꛳'), ('꛷', '꛷'), ('ê¡¶', 'ê¡·'), + ('꣎', '꣏'), ('꤯', '꤯'), ('꧈', '꧉'), ('꩝', '꩟'), + ('ê«°', '꫱'), ('꯫', '꯫'), ('﹖', '﹗'), ('!', '!'), + ('?', '?'), ('。', '。'), ('𐩖', '𐩗'), ('𐽕', '𐽙'), + ('𑁇', '𑁈'), ('𑂾', '𑃁'), ('𑅁', '𑅃'), ('𑇅', '𑇆'), + ('𑇍', '𑇍'), ('𑇞', '𑇟'), ('𑈸', '𑈹'), ('𑈻', '𑈼'), + ('𑊩', '𑊩'), ('𑑋', '𑑌'), ('𑗂', '𑗃'), ('𑗉', '𑗗'), + ('𑙁', '𑙂'), ('𑜼', '𑜾'), ('𑩂', '𑩃'), ('𑪛', '𑪜'), + ('𑱁', '𑱂'), ('𑻷', '𑻸'), ('𖩮', '𖩯'), ('𖫵', '𖫵'), + ('𖬷', '𖬸'), ('𖭄', '𖭄'), ('𖺘', '𖺘'), ('𛲟', '𛲟'), + ('𝪈', '𝪈'), +]; + +pub const SEP: &'static [(char, char)] = &[ + ('\u{85}', '\u{85}'), ('\u{2028}', '\u{2029}'), +]; + +pub const SP: &'static [(char, char)] = &[ + ('\t', '\t'), ('\u{b}', '\u{c}'), (' ', ' '), ('\u{a0}', '\u{a0}'), + ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), + ('\u{202f}', '\u{202f}'), ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const UPPER: &'static [(char, char)] = &[ + ('A', 'Z'), ('À', 'Ö'), ('Ø', 'Þ'), ('Ā', 'Ā'), ('Ă', 'Ă'), + ('Ą', 'Ą'), ('Ć', 'Ć'), ('Ĉ', 'Ĉ'), ('Ċ', 'Ċ'), ('Č', 'Č'), + ('Ď', 'Ď'), ('Đ', 'Đ'), ('Ē', 'Ē'), ('Ĕ', 'Ĕ'), ('Ė', 'Ė'), + ('Ę', 'Ę'), ('Ě', 'Ě'), ('Ĝ', 'Ĝ'), ('Ğ', 'Ğ'), ('Ä ', 'Ä '), + ('Ä¢', 'Ä¢'), ('Ĥ', 'Ĥ'), ('Ħ', 'Ħ'), ('Ĩ', 'Ĩ'), ('Ī', 'Ī'), + ('Ĭ', 'Ĭ'), ('Ä®', 'Ä®'), ('İ', 'İ'), ('IJ', 'IJ'), ('Ä´', 'Ä´'), + ('Ķ', 'Ķ'), ('Ĺ', 'Ĺ'), ('Ä»', 'Ä»'), ('Ľ', 'Ľ'), ('Ä¿', 'Ä¿'), + ('Ł', 'Ł'), ('Ń', 'Ń'), ('Ņ', 'Ņ'), ('Ň', 'Ň'), ('Ŋ', 'Ŋ'), + ('Ō', 'Ō'), ('Ŏ', 'Ŏ'), ('Ő', 'Ő'), ('Œ', 'Œ'), ('Ŕ', 'Ŕ'), + ('Ŗ', 'Ŗ'), ('Ř', 'Ř'), ('Ś', 'Ś'), ('Ŝ', 'Ŝ'), ('Ş', 'Ş'), + ('Å ', 'Å '), ('Å¢', 'Å¢'), ('Ť', 'Ť'), ('Ŧ', 'Ŧ'), ('Ũ', 'Ũ'), + ('Ū', 'Ū'), ('Ŭ', 'Ŭ'), ('Å®', 'Å®'), ('Ű', 'Ű'), ('Ų', 'Ų'), + ('Å´', 'Å´'), ('Ŷ', 'Ŷ'), ('Ÿ', 'Ź'), ('Å»', 'Å»'), ('Ž', 'Ž'), + ('Ɓ', 'Ƃ'), ('Ƅ', 'Ƅ'), ('Ɔ', 'Ƈ'), ('Ɖ', 'Ƌ'), ('Ǝ', 'Ƒ'), + ('Ɠ', 'Ɣ'), ('Ɩ', 'Ƙ'), ('Ɯ', 'Ɲ'), ('Ɵ', 'Æ '), ('Æ¢', 'Æ¢'), + ('Ƥ', 'Ƥ'), ('Ʀ', 'Ƨ'), ('Æ©', 'Æ©'), ('Ƭ', 'Ƭ'), ('Æ®', 'Ư'), + ('Ʊ', 'Ƴ'), ('Ƶ', 'Ƶ'), ('Æ·', 'Ƹ'), ('Ƽ', 'Ƽ'), ('DŽ', 'Dž'), + ('LJ', 'Lj'), ('NJ', 'Nj'), ('Ǎ', 'Ǎ'), ('Ǐ', 'Ǐ'), ('Ǒ', 'Ǒ'), + ('Ǔ', 'Ǔ'), ('Ǖ', 'Ǖ'), ('Ǘ', 'Ǘ'), ('Ǚ', 'Ǚ'), ('Ǜ', 'Ǜ'), + ('Ǟ', 'Ǟ'), ('Ç ', 'Ç '), ('Ç¢', 'Ç¢'), ('Ǥ', 'Ǥ'), ('Ǧ', 'Ǧ'), + ('Ǩ', 'Ǩ'), ('Ǫ', 'Ǫ'), ('Ǭ', 'Ǭ'), ('Ç®', 'Ç®'), ('DZ', 'Dz'), + ('Ç´', 'Ç´'), ('Ƕ', 'Ǹ'), ('Ǻ', 'Ǻ'), ('Ǽ', 'Ǽ'), ('Ǿ', 'Ǿ'), + ('Ȁ', 'Ȁ'), ('Ȃ', 'Ȃ'), ('Ȅ', 'Ȅ'), ('Ȇ', 'Ȇ'), ('Ȉ', 'Ȉ'), + ('Ȋ', 'Ȋ'), ('Ȍ', 'Ȍ'), ('Ȏ', 'Ȏ'), ('Ȑ', 'Ȑ'), ('Ȓ', 'Ȓ'), + ('Ȕ', 'Ȕ'), ('Ȗ', 'Ȗ'), ('Ș', 'Ș'), ('Ț', 'Ț'), ('Ȝ', 'Ȝ'), + ('Ȟ', 'Ȟ'), ('È ', 'È '), ('È¢', 'È¢'), ('Ȥ', 'Ȥ'), ('Ȧ', 'Ȧ'), + ('Ȩ', 'Ȩ'), ('Ȫ', 'Ȫ'), ('Ȭ', 'Ȭ'), ('È®', 'È®'), ('Ȱ', 'Ȱ'), + ('Ȳ', 'Ȳ'), ('Ⱥ', 'È»'), ('Ƚ', 'Ⱦ'), ('Ɂ', 'Ɂ'), ('Ƀ', 'Ɇ'), + ('Ɉ', 'Ɉ'), ('Ɋ', 'Ɋ'), ('Ɍ', 'Ɍ'), ('Ɏ', 'Ɏ'), ('Ͱ', 'Ͱ'), + ('Ͳ', 'Ͳ'), ('Ͷ', 'Ͷ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), ('Έ', 'Ί'), + ('Ό', 'Ό'), ('Ύ', 'Ώ'), ('Α', 'Ρ'), ('Σ', 'Ϋ'), ('Ϗ', 'Ϗ'), + ('ϒ', 'ϔ'), ('Ϙ', 'Ϙ'), ('Ϛ', 'Ϛ'), ('Ϝ', 'Ϝ'), ('Ϟ', 'Ϟ'), + ('Ï ', 'Ï '), ('Ï¢', 'Ï¢'), ('Ϥ', 'Ϥ'), ('Ϧ', 'Ϧ'), ('Ϩ', 'Ϩ'), + ('Ϫ', 'Ϫ'), ('Ϭ', 'Ϭ'), ('Ï®', 'Ï®'), ('Ï´', 'Ï´'), ('Ï·', 'Ï·'), + ('Ϲ', 'Ϻ'), ('Ͻ', 'Я'), ('Ñ ', 'Ñ '), ('Ñ¢', 'Ñ¢'), ('Ѥ', 'Ѥ'), + ('Ѧ', 'Ѧ'), ('Ѩ', 'Ѩ'), ('Ѫ', 'Ѫ'), ('Ѭ', 'Ѭ'), ('Ñ®', 'Ñ®'), + ('Ѱ', 'Ѱ'), ('Ѳ', 'Ѳ'), ('Ñ´', 'Ñ´'), ('Ѷ', 'Ѷ'), ('Ѹ', 'Ѹ'), + ('Ѻ', 'Ѻ'), ('Ѽ', 'Ѽ'), ('Ѿ', 'Ѿ'), ('Ҁ', 'Ҁ'), ('Ҋ', 'Ҋ'), + ('Ҍ', 'Ҍ'), ('Ҏ', 'Ҏ'), ('Ґ', 'Ґ'), ('Ғ', 'Ғ'), ('Ҕ', 'Ҕ'), + ('Җ', 'Җ'), ('Ҙ', 'Ҙ'), ('Қ', 'Қ'), ('Ҝ', 'Ҝ'), ('Ҟ', 'Ҟ'), + ('Ò ', 'Ò '), ('Ò¢', 'Ò¢'), ('Ò¤', 'Ò¤'), ('Ò¦', 'Ò¦'), ('Ò¨', 'Ò¨'), + ('Òª', 'Òª'), ('Ò¬', 'Ò¬'), ('Ò®', 'Ò®'), ('Ò°', 'Ò°'), ('Ò²', 'Ò²'), + ('Ò´', 'Ò´'), ('Ò¶', 'Ò¶'), ('Ò¸', 'Ò¸'), ('Òº', 'Òº'), ('Ò¼', 'Ò¼'), + ('Ò¾', 'Ò¾'), ('Ӏ', 'Ӂ'), ('Ӄ', 'Ӄ'), ('Ӆ', 'Ӆ'), ('Ӈ', 'Ӈ'), + ('Ӊ', 'Ӊ'), ('Ӌ', 'Ӌ'), ('Ӎ', 'Ӎ'), ('Ӑ', 'Ӑ'), ('Ӓ', 'Ӓ'), + ('Ӕ', 'Ӕ'), ('Ӗ', 'Ӗ'), ('Ә', 'Ә'), ('Ӛ', 'Ӛ'), ('Ӝ', 'Ӝ'), + ('Ӟ', 'Ӟ'), ('Ó ', 'Ó '), ('Ó¢', 'Ó¢'), ('Ó¤', 'Ó¤'), ('Ó¦', 'Ó¦'), + ('Ó¨', 'Ó¨'), ('Óª', 'Óª'), ('Ó¬', 'Ó¬'), ('Ó®', 'Ó®'), ('Ó°', 'Ó°'), + ('Ó²', 'Ó²'), ('Ó´', 'Ó´'), ('Ó¶', 'Ó¶'), ('Ó¸', 'Ó¸'), ('Óº', 'Óº'), + ('Ó¼', 'Ó¼'), ('Ó¾', 'Ó¾'), ('Ԁ', 'Ԁ'), ('Ԃ', 'Ԃ'), ('Ԅ', 'Ԅ'), + ('Ԇ', 'Ԇ'), ('Ԉ', 'Ԉ'), ('Ԋ', 'Ԋ'), ('Ԍ', 'Ԍ'), ('Ԏ', 'Ԏ'), + ('Ԑ', 'Ԑ'), ('Ԓ', 'Ԓ'), ('Ԕ', 'Ԕ'), ('Ԗ', 'Ԗ'), ('Ԙ', 'Ԙ'), + ('Ԛ', 'Ԛ'), ('Ԝ', 'Ԝ'), ('Ԟ', 'Ԟ'), ('Ô ', 'Ô '), ('Ô¢', 'Ô¢'), + ('Ô¤', 'Ô¤'), ('Ô¦', 'Ô¦'), ('Ô¨', 'Ô¨'), ('Ôª', 'Ôª'), ('Ô¬', 'Ô¬'), + ('Ô®', 'Ô®'), ('Ô±', 'Ֆ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('Ꭰ', 'Ᏽ'), ('Ა', 'Ჺ'), ('á²½', 'Ჿ'), ('Ḁ', 'Ḁ'), + ('Ḃ', 'Ḃ'), ('Ḅ', 'Ḅ'), ('Ḇ', 'Ḇ'), ('Ḉ', 'Ḉ'), + ('Ḋ', 'Ḋ'), ('Ḍ', 'Ḍ'), ('Ḏ', 'Ḏ'), ('Ḑ', 'Ḑ'), + ('Ḓ', 'Ḓ'), ('Ḕ', 'Ḕ'), ('Ḗ', 'Ḗ'), ('Ḙ', 'Ḙ'), + ('Ḛ', 'Ḛ'), ('Ḝ', 'Ḝ'), ('Ḟ', 'Ḟ'), ('Ḡ', 'Ḡ'), + ('Ḣ', 'Ḣ'), ('Ḥ', 'Ḥ'), ('Ḧ', 'Ḧ'), ('Ḩ', 'Ḩ'), + ('Ḫ', 'Ḫ'), ('Ḭ', 'Ḭ'), ('Ḯ', 'Ḯ'), ('Ḱ', 'Ḱ'), + ('Ḳ', 'Ḳ'), ('Ḵ', 'Ḵ'), ('Ḷ', 'Ḷ'), ('Ḹ', 'Ḹ'), + ('Ḻ', 'Ḻ'), ('Ḽ', 'Ḽ'), ('Ḿ', 'Ḿ'), ('Ṁ', 'Ṁ'), + ('Ṃ', 'Ṃ'), ('Ṅ', 'Ṅ'), ('Ṇ', 'Ṇ'), ('Ṉ', 'Ṉ'), + ('Ṋ', 'Ṋ'), ('Ṍ', 'Ṍ'), ('Ṏ', 'Ṏ'), ('Ṑ', 'Ṑ'), + ('Ṓ', 'Ṓ'), ('Ṕ', 'Ṕ'), ('Ṗ', 'Ṗ'), ('Ṙ', 'Ṙ'), + ('Ṛ', 'Ṛ'), ('Ṝ', 'Ṝ'), ('Ṟ', 'Ṟ'), ('á¹ ', 'á¹ '), + ('á¹¢', 'á¹¢'), ('Ṥ', 'Ṥ'), ('Ṧ', 'Ṧ'), ('Ṩ', 'Ṩ'), + ('Ṫ', 'Ṫ'), ('Ṭ', 'Ṭ'), ('á¹®', 'á¹®'), ('á¹°', 'á¹°'), + ('á¹²', 'á¹²'), ('á¹´', 'á¹´'), ('á¹¶', 'á¹¶'), ('Ṹ', 'Ṹ'), + ('Ṻ', 'Ṻ'), ('á¹¼', 'á¹¼'), ('á¹¾', 'á¹¾'), ('Ẁ', 'Ẁ'), + ('Ẃ', 'Ẃ'), ('Ẅ', 'Ẅ'), ('Ẇ', 'Ẇ'), ('Ẉ', 'Ẉ'), + ('Ẋ', 'Ẋ'), ('Ẍ', 'Ẍ'), ('Ẏ', 'Ẏ'), ('Ẑ', 'Ẑ'), + ('Ẓ', 'Ẓ'), ('Ẕ', 'Ẕ'), ('ẞ', 'ẞ'), ('Ạ', 'Ạ'), + ('Ả', 'Ả'), ('Ấ', 'Ấ'), ('Ầ', 'Ầ'), ('Ẩ', 'Ẩ'), + ('Ẫ', 'Ẫ'), ('Ậ', 'Ậ'), ('Ắ', 'Ắ'), ('Ằ', 'Ằ'), + ('Ẳ', 'Ẳ'), ('Ẵ', 'Ẵ'), ('Ặ', 'Ặ'), ('Ẹ', 'Ẹ'), + ('Ẻ', 'Ẻ'), ('Ẽ', 'Ẽ'), ('Ế', 'Ế'), ('Ề', 'Ề'), + ('Ể', 'Ể'), ('Ễ', 'Ễ'), ('Ệ', 'Ệ'), ('Ỉ', 'Ỉ'), + ('Ị', 'Ị'), ('Ọ', 'Ọ'), ('Ỏ', 'Ỏ'), ('Ố', 'Ố'), + ('Ồ', 'Ồ'), ('Ổ', 'Ổ'), ('Ỗ', 'Ỗ'), ('Ộ', 'Ộ'), + ('Ớ', 'Ớ'), ('Ờ', 'Ờ'), ('Ở', 'Ở'), ('á» ', 'á» '), + ('Ợ', 'Ợ'), ('Ụ', 'Ụ'), ('Ủ', 'Ủ'), ('Ứ', 'Ứ'), + ('Ừ', 'Ừ'), ('Ử', 'Ử'), ('á»®', 'á»®'), ('á»°', 'á»°'), + ('Ỳ', 'Ỳ'), ('á»´', 'á»´'), ('á»¶', 'á»¶'), ('Ỹ', 'Ỹ'), + ('Ỻ', 'Ỻ'), ('Ỽ', 'Ỽ'), ('Ỿ', 'Ỿ'), ('Ἀ', 'Ἇ'), + ('Ἐ', 'Ἕ'), ('Ἠ', 'Ἧ'), ('Ἰ', 'Ἷ'), ('Ὀ', 'Ὅ'), + ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), ('Ὕ', 'Ὕ'), ('Ὗ', 'Ὗ'), + ('Ὠ', 'Ὧ'), ('ᾈ', 'ᾏ'), ('ᾘ', 'ᾟ'), ('ᾨ', 'ᾯ'), + ('Ᾰ', 'á¾¼'), ('Ὲ', 'ῌ'), ('Ῐ', 'Ί'), ('Ῠ', 'Ῥ'), + ('Ὸ', 'ῼ'), ('ℂ', 'ℂ'), ('ℇ', 'ℇ'), ('ℋ', 'ℍ'), + ('ℐ', 'ℒ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), ('ℤ', 'ℤ'), + ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), ('ℰ', 'ℳ'), + ('ℾ', 'ℿ'), ('ⅅ', 'ⅅ'), ('Ⅰ', 'Ⅿ'), ('Ↄ', 'Ↄ'), + ('Ⓐ', 'Ⓩ'), ('Ⰰ', 'â°®'), ('â± ', 'â± '), ('â±¢', 'Ɽ'), + ('â±§', 'â±§'), ('Ⱪ', 'Ⱪ'), ('Ⱬ', 'Ⱬ'), ('â±­', 'â±°'), + ('â±²', 'â±²'), ('â±µ', 'â±µ'), ('â±¾', 'Ⲁ'), ('Ⲃ', 'Ⲃ'), + ('Ⲅ', 'Ⲅ'), ('Ⲇ', 'Ⲇ'), ('Ⲉ', 'Ⲉ'), ('Ⲋ', 'Ⲋ'), + ('Ⲍ', 'Ⲍ'), ('Ⲏ', 'Ⲏ'), ('Ⲑ', 'Ⲑ'), ('Ⲓ', 'Ⲓ'), + ('Ⲕ', 'Ⲕ'), ('Ⲗ', 'Ⲗ'), ('Ⲙ', 'Ⲙ'), ('Ⲛ', 'Ⲛ'), + ('Ⲝ', 'Ⲝ'), ('Ⲟ', 'Ⲟ'), ('â² ', 'â² '), ('â²¢', 'â²¢'), + ('Ⲥ', 'Ⲥ'), ('Ⲧ', 'Ⲧ'), ('Ⲩ', 'Ⲩ'), ('Ⲫ', 'Ⲫ'), + ('Ⲭ', 'Ⲭ'), ('â²®', 'â²®'), ('â²°', 'â²°'), ('â²²', 'â²²'), + ('â²´', 'â²´'), ('â²¶', 'â²¶'), ('Ⲹ', 'Ⲹ'), ('Ⲻ', 'Ⲻ'), + ('â²¼', 'â²¼'), ('â²¾', 'â²¾'), ('Ⳁ', 'Ⳁ'), ('Ⳃ', 'Ⳃ'), + ('Ⳅ', 'Ⳅ'), ('Ⳇ', 'Ⳇ'), ('Ⳉ', 'Ⳉ'), ('Ⳋ', 'Ⳋ'), + ('Ⳍ', 'Ⳍ'), ('Ⳏ', 'Ⳏ'), ('Ⳑ', 'Ⳑ'), ('Ⳓ', 'Ⳓ'), + ('Ⳕ', 'Ⳕ'), ('Ⳗ', 'Ⳗ'), ('Ⳙ', 'Ⳙ'), ('Ⳛ', 'Ⳛ'), + ('Ⳝ', 'Ⳝ'), ('Ⳟ', 'Ⳟ'), ('â³ ', 'â³ '), ('â³¢', 'â³¢'), + ('Ⳬ', 'Ⳬ'), ('â³­', 'â³­'), ('â³²', 'â³²'), ('Ꙁ', 'Ꙁ'), + ('Ꙃ', 'Ꙃ'), ('Ꙅ', 'Ꙅ'), ('Ꙇ', 'Ꙇ'), ('Ꙉ', 'Ꙉ'), + ('Ꙋ', 'Ꙋ'), ('Ꙍ', 'Ꙍ'), ('Ꙏ', 'Ꙏ'), ('Ꙑ', 'Ꙑ'), + ('Ꙓ', 'Ꙓ'), ('Ꙕ', 'Ꙕ'), ('Ꙗ', 'Ꙗ'), ('Ꙙ', 'Ꙙ'), + ('Ꙛ', 'Ꙛ'), ('Ꙝ', 'Ꙝ'), ('Ꙟ', 'Ꙟ'), ('Ꙡ', 'Ꙡ'), + ('Ꙣ', 'Ꙣ'), ('Ꙥ', 'Ꙥ'), ('Ꙧ', 'Ꙧ'), ('Ꙩ', 'Ꙩ'), + ('Ꙫ', 'Ꙫ'), ('Ꙭ', 'Ꙭ'), ('Ꚁ', 'Ꚁ'), ('Ꚃ', 'Ꚃ'), + ('Ꚅ', 'Ꚅ'), ('Ꚇ', 'Ꚇ'), ('Ꚉ', 'Ꚉ'), ('Ꚋ', 'Ꚋ'), + ('Ꚍ', 'Ꚍ'), ('Ꚏ', 'Ꚏ'), ('Ꚑ', 'Ꚑ'), ('Ꚓ', 'Ꚓ'), + ('Ꚕ', 'Ꚕ'), ('Ꚗ', 'Ꚗ'), ('Ꚙ', 'Ꚙ'), ('Ꚛ', 'Ꚛ'), + ('Ꜣ', 'Ꜣ'), ('Ꜥ', 'Ꜥ'), ('Ꜧ', 'Ꜧ'), ('Ꜩ', 'Ꜩ'), + ('Ꜫ', 'Ꜫ'), ('Ꜭ', 'Ꜭ'), ('Ꜯ', 'Ꜯ'), ('Ꜳ', 'Ꜳ'), + ('Ꜵ', 'Ꜵ'), ('Ꜷ', 'Ꜷ'), ('Ꜹ', 'Ꜹ'), ('Ꜻ', 'Ꜻ'), + ('Ꜽ', 'Ꜽ'), ('Ꜿ', 'Ꜿ'), ('Ꝁ', 'Ꝁ'), ('Ꝃ', 'Ꝃ'), + ('Ꝅ', 'Ꝅ'), ('Ꝇ', 'Ꝇ'), ('Ꝉ', 'Ꝉ'), ('Ꝋ', 'Ꝋ'), + ('Ꝍ', 'Ꝍ'), ('Ꝏ', 'Ꝏ'), ('Ꝑ', 'Ꝑ'), ('Ꝓ', 'Ꝓ'), + ('Ꝕ', 'Ꝕ'), ('Ꝗ', 'Ꝗ'), ('Ꝙ', 'Ꝙ'), ('Ꝛ', 'Ꝛ'), + ('Ꝝ', 'Ꝝ'), ('Ꝟ', 'Ꝟ'), ('Ꝡ', 'Ꝡ'), ('Ꝣ', 'Ꝣ'), + ('Ꝥ', 'Ꝥ'), ('Ꝧ', 'Ꝧ'), ('Ꝩ', 'Ꝩ'), ('Ꝫ', 'Ꝫ'), + ('Ꝭ', 'Ꝭ'), ('Ꝯ', 'Ꝯ'), ('Ꝺ', 'Ꝺ'), ('Ꝼ', 'Ꝼ'), + ('Ᵹ', 'Ꝿ'), ('Ꞁ', 'Ꞁ'), ('Ꞃ', 'Ꞃ'), ('Ꞅ', 'Ꞅ'), + ('Ꞇ', 'Ꞇ'), ('Ꞌ', 'Ꞌ'), ('Ɥ', 'Ɥ'), ('Ꞑ', 'Ꞑ'), + ('Ꞓ', 'Ꞓ'), ('Ꞗ', 'Ꞗ'), ('Ꞙ', 'Ꞙ'), ('Ꞛ', 'Ꞛ'), + ('Ꞝ', 'Ꞝ'), ('Ꞟ', 'Ꞟ'), ('Ꞡ', 'Ꞡ'), ('Ꞣ', 'Ꞣ'), + ('Ꞥ', 'Ꞥ'), ('Ꞧ', 'Ꞧ'), ('Ꞩ', 'Ꞩ'), ('Ɦ', 'Ɪ'), + ('Ʞ', 'Ꞵ'), ('Ꞷ', 'Ꞷ'), ('Ꞹ', 'Ꞹ'), ('A', 'Z'), + ('𐐀', '𐐧'), ('𐒰', '𐓓'), ('𐲀', '𐲲'), ('𑢠', '𑢿'), + ('𖹀', '𖹟'), ('𝐀', '𝐙'), ('𝐴', '𝑍'), ('𝑨', '𝒁'), + ('𝒜', '𝒜'), ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), + ('𝒩', '𝒬'), ('𝒮', '𝒵'), ('𝓐', '𝓩'), ('𝔄', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔸', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕬', '𝖅'), ('𝖠', '𝖹'), ('𝗔', '𝗭'), ('𝘈', '𝘡'), + ('𝘼', '𝙕'), ('𝙰', '𝚉'), ('𝚨', '𝛀'), ('𝛢', '𝛺'), + ('𝜜', '𝜴'), ('𝝖', '𝝮'), ('𝞐', '𝞨'), ('𝟊', '𝟊'), + ('𞤀', '𞤡'), ('🄰', '🅉'), ('🅐', '🅩'), ('🅰', '🆉'), +]; diff --git a/regex-syntax/src/unicode_tables/word_break.rs b/regex-syntax/src/unicode_tables/word_break.rs new file mode 100644 index 000000000..82dff8285 --- /dev/null +++ b/regex-syntax/src/unicode_tables/word_break.rs @@ -0,0 +1,351 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate word-break /home/andrew/tmp/ucd-11.0.0/ --chars +// +// ucd-generate is available on crates.io. + +pub const BY_NAME: &'static [(&'static str, &'static [(char, char)])] = &[ + ("ALetter", ALETTER), ("CR", CR), ("Double_Quote", DOUBLE_QUOTE), + ("Extend", EXTEND), ("ExtendNumLet", EXTENDNUMLET), ("Format", FORMAT), + ("Hebrew_Letter", HEBREW_LETTER), ("Katakana", KATAKANA), ("LF", LF), + ("MidLetter", MIDLETTER), ("MidNum", MIDNUM), ("MidNumLet", MIDNUMLET), + ("Newline", NEWLINE), ("Numeric", NUMERIC), + ("Regional_Indicator", REGIONAL_INDICATOR), ("Single_Quote", SINGLE_QUOTE), + ("WSegSpace", WSEGSPACE), ("ZWJ", ZWJ), +]; + +pub const ALETTER: &'static [(char, char)] = &[ + ('A', 'Z'), ('a', 'z'), ('ª', 'ª'), ('µ', 'µ'), ('º', 'º'), + ('À', 'Ö'), ('Ø', 'ö'), ('ø', '˗'), ('˞', 'ˤ'), ('ˬ', 'Ë¿'), + ('Ͱ', 'Í´'), ('Ͷ', 'Í·'), ('ͺ', 'ͽ'), ('Í¿', 'Í¿'), ('Ά', 'Ά'), + ('Έ', 'Ί'), ('Ό', 'Ό'), ('Ύ', 'Ρ'), ('Σ', 'ϵ'), ('Ï·', 'ҁ'), + ('Ҋ', 'Ô¯'), ('Ô±', 'Ֆ'), ('ՙ', 'ՙ'), ('՛', '՜'), ('՞', '՞'), + ('Õ ', 'ֈ'), ('׳', '׳'), ('Ø ', 'ي'), ('Ù®', 'Ù¯'), ('Ù±', 'ۓ'), + ('ە', 'ە'), ('Û¥', 'Û¦'), ('Û®', 'Û¯'), ('Ûº', 'Û¼'), ('Û¿', 'Û¿'), + ('ܐ', 'ܐ'), ('ܒ', 'ܯ'), ('ݍ', 'Þ¥'), ('Þ±', 'Þ±'), ('ߊ', 'ߪ'), + ('ß´', 'ßµ'), ('ߺ', 'ߺ'), ('ࠀ', 'ࠕ'), ('ࠚ', 'ࠚ'), ('à ¤', 'à ¤'), + ('à ¨', 'à ¨'), ('ࡀ', 'ࡘ'), ('à¡ ', 'ࡪ'), ('ࢠ', 'ࢴ'), + ('ࢶ', 'ࢽ'), ('ऄ', 'ह'), ('ऽ', 'ऽ'), ('ॐ', 'ॐ'), + ('क़', 'ॡ'), ('ॱ', 'ঀ'), ('অ', 'ঌ'), ('এ', 'ঐ'), + ('ও', 'ন'), ('প', 'র'), ('ল', 'ল'), ('শ', 'হ'), + ('ঽ', 'ঽ'), ('ৎ', 'ৎ'), ('ড়', 'ঢ়'), ('য়', 'à§¡'), + ('à§°', 'à§±'), ('à§¼', 'à§¼'), ('ਅ', 'ਊ'), ('ਏ', 'ਐ'), + ('ਓ', 'ਨ'), ('ਪ', 'ਰ'), ('ਲ', 'ਲ਼'), ('ਵ', 'ਸ਼'), + ('ਸ', 'ਹ'), ('ਖ਼', 'ੜ'), ('ਫ਼', 'ਫ਼'), ('ੲ', 'à©´'), + ('અ', 'ઍ'), ('એ', 'ઑ'), ('ઓ', 'ન'), ('પ', 'ર'), + ('લ', 'ળ'), ('વ', 'હ'), ('ઽ', 'ઽ'), ('ૐ', 'ૐ'), + ('à« ', 'à«¡'), ('ૹ', 'ૹ'), ('ଅ', 'ଌ'), ('ଏ', 'ଐ'), + ('ଓ', 'ନ'), ('ପ', 'ର'), ('ଲ', 'ଳ'), ('ଵ', 'ହ'), + ('ଽ', 'ଽ'), ('ଡ଼', 'ଢ଼'), ('ୟ', 'à­¡'), ('à­±', 'à­±'), + ('ஃ', 'ஃ'), ('அ', 'ஊ'), ('எ', 'ஐ'), ('ஒ', 'க'), + ('ங', 'ச'), ('ஜ', 'ஜ'), ('ஞ', 'ட'), ('ண', 'த'), + ('ந', 'ப'), ('à®®', 'ஹ'), ('ௐ', 'ௐ'), ('అ', 'ఌ'), + ('ఎ', 'ఐ'), ('ఒ', 'à°¨'), ('à°ª', 'à°¹'), ('à°½', 'à°½'), + ('ౘ', 'ౚ'), ('à± ', 'ౡ'), ('ಀ', 'ಀ'), ('ಅ', 'ಌ'), + ('ಎ', 'ಐ'), ('ಒ', 'ನ'), ('ಪ', 'ಳ'), ('ವ', 'ಹ'), + ('ಽ', 'ಽ'), ('ೞ', 'ೞ'), ('à³ ', 'ೡ'), ('à³±', 'à³²'), + ('അ', 'ഌ'), ('എ', 'ഐ'), ('ഒ', 'à´º'), ('à´½', 'à´½'), + ('ൎ', 'ൎ'), ('ൔ', 'ൖ'), ('ൟ', 'ൡ'), ('ൺ', 'ൿ'), + ('අ', 'ඖ'), ('ක', 'à¶±'), ('à¶³', 'à¶»'), ('à¶½', 'à¶½'), + ('ව', 'ෆ'), ('ༀ', 'ༀ'), ('ཀ', 'ཇ'), ('ཉ', 'ཬ'), + ('ྈ', 'ྌ'), ('Ⴀ', 'Ⴥ'), ('Ⴧ', 'Ⴧ'), ('Ⴭ', 'Ⴭ'), + ('ა', 'ჺ'), ('ჼ', 'ቈ'), ('ቊ', 'ቍ'), ('ቐ', 'ቖ'), + ('ቘ', 'ቘ'), ('ቚ', 'ቝ'), ('በ', 'ኈ'), ('ኊ', 'ኍ'), + ('ነ', 'ኰ'), ('ኲ', 'ኵ'), ('ኸ', 'ኾ'), ('ዀ', 'ዀ'), + ('ዂ', 'ዅ'), ('ወ', 'ዖ'), ('ዘ', 'ጐ'), ('ጒ', 'ጕ'), + ('ጘ', 'ፚ'), ('ᎀ', 'ᎏ'), ('Ꭰ', 'Ᏽ'), ('ᏸ', 'ᏽ'), + ('ᐁ', 'ᙬ'), ('ᙯ', 'ᙿ'), ('ᚁ', 'ᚚ'), ('ᚠ', 'ᛪ'), + ('ᛮ', 'ᛸ'), ('ᜀ', 'ᜌ'), ('ᜎ', 'ᜑ'), ('ᜠ', 'ᜱ'), + ('ᝀ', 'ᝑ'), ('ᝠ', 'ᝬ'), ('ᝮ', 'ᝰ'), ('á  ', 'ᡸ'), + ('ᢀ', 'ᢄ'), ('ᢇ', 'ᢨ'), ('ᢪ', 'ᢪ'), ('ᢰ', 'ᣵ'), + ('ᤀ', 'ᤞ'), ('ᨀ', 'ᨖ'), ('ᬅ', 'ᬳ'), ('ᭅ', 'ᭋ'), + ('ᮃ', 'á® '), ('á®®', 'ᮯ'), ('ᮺ', 'ᯥ'), ('ᰀ', 'á°£'), + ('ᱍ', 'ᱏ'), ('ᱚ', 'á±½'), ('ᲀ', 'ᲈ'), ('Ა', 'Ჺ'), + ('á²½', 'Ჿ'), ('ᳩ', 'ᳬ'), ('á³®', 'á³±'), ('á³µ', 'á³¶'), + ('ᴀ', 'á¶¿'), ('Ḁ', 'ἕ'), ('Ἐ', 'Ἕ'), ('á¼ ', 'ὅ'), + ('Ὀ', 'Ὅ'), ('ὐ', 'ὗ'), ('Ὑ', 'Ὑ'), ('Ὓ', 'Ὓ'), + ('Ὕ', 'Ὕ'), ('Ὗ', 'á½½'), ('ᾀ', 'á¾´'), ('á¾¶', 'á¾¼'), + ('á¾¾', 'á¾¾'), ('ῂ', 'ῄ'), ('ῆ', 'ῌ'), ('ῐ', 'ΐ'), + ('ῖ', 'Ί'), ('á¿ ', 'Ῥ'), ('ῲ', 'á¿´'), ('á¿¶', 'ῼ'), + ('ⁱ', 'ⁱ'), ('ⁿ', 'ⁿ'), ('ₐ', 'ₜ'), ('ℂ', 'ℂ'), + ('ℇ', 'ℇ'), ('ℊ', 'ℓ'), ('ℕ', 'ℕ'), ('ℙ', 'ℝ'), + ('ℤ', 'ℤ'), ('Ω', 'Ω'), ('ℨ', 'ℨ'), ('K', 'ℭ'), + ('ℯ', 'ℹ'), ('ℼ', 'ℿ'), ('ⅅ', 'ⅉ'), ('ⅎ', 'ⅎ'), + ('Ⅰ', 'ↈ'), ('Ⓐ', 'ⓩ'), ('Ⰰ', 'â°®'), ('â°°', 'ⱞ'), + ('â± ', 'ⳤ'), ('Ⳬ', 'â³®'), ('â³²', 'â³³'), ('ⴀ', 'â´¥'), + ('â´§', 'â´§'), ('â´­', 'â´­'), ('â´°', 'âµ§'), ('ⵯ', 'ⵯ'), + ('ⶀ', 'ⶖ'), ('â¶ ', 'ⶦ'), ('ⶨ', 'â¶®'), ('â¶°', 'â¶¶'), + ('ⶸ', 'â¶¾'), ('ⷀ', 'ⷆ'), ('ⷈ', 'ⷎ'), ('ⷐ', 'ⷖ'), + ('ⷘ', 'ⷞ'), ('ⸯ', 'ⸯ'), ('々', '々'), ('〻', '〼'), + ('ㄅ', 'ㄯ'), ('ㄱ', 'ㆎ'), ('ㆠ', 'ㆺ'), ('ꀀ', 'ꒌ'), + ('ꓐ', 'ꓽ'), ('ꔀ', 'ꘌ'), ('ꘐ', 'ꘟ'), ('ꘪ', 'ꘫ'), + ('Ꙁ', 'ꙮ'), ('ꙿ', 'ꚝ'), ('ꚠ', 'ꛯ'), ('ꜗ', 'ꞹ'), + ('ꟷ', 'ꠁ'), ('ꠃ', 'ꠅ'), ('ꠇ', 'ꠊ'), ('ꠌ', 'ê ¢'), + ('ꡀ', 'ꡳ'), ('ꢂ', 'ꢳ'), ('ꣲ', 'ꣷ'), ('ꣻ', 'ꣻ'), + ('ꣽ', 'ꣾ'), ('ꤊ', 'ꤥ'), ('ꤰ', 'ꥆ'), ('ꥠ', 'ꥼ'), + ('ꦄ', 'ꦲ'), ('ꧏ', 'ꧏ'), ('ꨀ', 'ꨨ'), ('ꩀ', 'ꩂ'), + ('ꩄ', 'ꩋ'), ('ê« ', 'ꫪ'), ('ꫲ', 'ê«´'), ('ꬁ', 'ꬆ'), + ('ꬉ', 'ꬎ'), ('ꬑ', 'ꬖ'), ('ꬠ', 'ꬦ'), ('ꬨ', 'ꬮ'), + ('ꬰ', 'ê­¥'), ('ê­°', 'ꯢ'), ('가', '힣'), ('ힰ', 'ퟆ'), + ('ퟋ', 'ퟻ'), ('ff', 'st'), ('ﬓ', 'ﬗ'), ('ﭐ', 'ï®±'), + ('ﯓ', 'ï´½'), ('ﵐ', 'ﶏ'), ('ﶒ', 'ﷇ'), ('ï·°', 'ï·»'), + ('ï¹°', 'ï¹´'), ('ï¹¶', 'ﻼ'), ('A', 'Z'), ('a', 'z'), + ('ï¾ ', 'ï¾¾'), ('ᅡ', 'ᅦ'), ('ᅧ', 'ᅬ'), ('ᅭ', 'ᅲ'), + ('ᅳ', 'ᅵ'), ('𐀀', '𐀋'), ('𐀍', '𐀦'), ('𐀨', '𐀺'), + ('𐀼', '𐀽'), ('𐀿', '𐁍'), ('𐁐', '𐁝'), ('𐂀', '𐃺'), + ('𐅀', '𐅴'), ('𐊀', '𐊜'), ('𐊠', '𐋐'), ('𐌀', '𐌟'), + ('𐌭', '𐍊'), ('𐍐', '𐍵'), ('𐎀', '𐎝'), ('𐎠', '𐏃'), + ('𐏈', '𐏏'), ('𐏑', '𐏕'), ('𐐀', '𐒝'), ('𐒰', '𐓓'), + ('𐓘', '𐓻'), ('𐔀', '𐔧'), ('𐔰', '𐕣'), ('𐘀', '𐜶'), + ('𐝀', '𐝕'), ('𐝠', '𐝧'), ('𐠀', '𐠅'), ('𐠈', '𐠈'), + ('𐠊', '𐠵'), ('𐠷', '𐠸'), ('𐠼', '𐠼'), ('𐠿', '𐡕'), + ('𐡠', '𐡶'), ('𐢀', '𐢞'), ('𐣠', '𐣲'), ('𐣴', '𐣵'), + ('𐤀', '𐤕'), ('𐤠', '𐤹'), ('𐦀', '𐦷'), ('𐦾', '𐦿'), + ('𐨀', '𐨀'), ('𐨐', '𐨓'), ('𐨕', '𐨗'), ('𐨙', '𐨵'), + ('𐩠', '𐩼'), ('𐪀', '𐪜'), ('𐫀', '𐫇'), ('𐫉', '𐫤'), + ('𐬀', '𐬵'), ('𐭀', '𐭕'), ('𐭠', '𐭲'), ('𐮀', '𐮑'), + ('𐰀', '𐱈'), ('𐲀', '𐲲'), ('𐳀', '𐳲'), ('𐴀', '𐴣'), + ('𐼀', '𐼜'), ('𐼧', '𐼧'), ('𐼰', '𐽅'), ('𑀃', '𑀷'), + ('𑂃', '𑂯'), ('𑃐', '𑃨'), ('𑄃', '𑄦'), ('𑅄', '𑅄'), + ('𑅐', '𑅲'), ('𑅶', '𑅶'), ('𑆃', '𑆲'), ('𑇁', '𑇄'), + ('𑇚', '𑇚'), ('𑇜', '𑇜'), ('𑈀', '𑈑'), ('𑈓', '𑈫'), + ('𑊀', '𑊆'), ('𑊈', '𑊈'), ('𑊊', '𑊍'), ('𑊏', '𑊝'), + ('𑊟', '𑊨'), ('𑊰', '𑋞'), ('𑌅', '𑌌'), ('𑌏', '𑌐'), + ('𑌓', '𑌨'), ('𑌪', '𑌰'), ('𑌲', '𑌳'), ('𑌵', '𑌹'), + ('𑌽', '𑌽'), ('𑍐', '𑍐'), ('𑍝', '𑍡'), ('𑐀', '𑐴'), + ('𑑇', '𑑊'), ('𑒀', '𑒯'), ('𑓄', '𑓅'), ('𑓇', '𑓇'), + ('𑖀', '𑖮'), ('𑗘', '𑗛'), ('𑘀', '𑘯'), ('𑙄', '𑙄'), + ('𑚀', '𑚪'), ('𑠀', '𑠫'), ('𑢠', '𑣟'), ('𑣿', '𑣿'), + ('𑨀', '𑨀'), ('𑨋', '𑨲'), ('𑨺', '𑨺'), ('𑩐', '𑩐'), + ('𑩜', '𑪃'), ('𑪆', '𑪉'), ('𑪝', '𑪝'), ('𑫀', '𑫸'), + ('𑰀', '𑰈'), ('𑰊', '𑰮'), ('𑱀', '𑱀'), ('𑱲', '𑲏'), + ('𑴀', '𑴆'), ('𑴈', '𑴉'), ('𑴋', '𑴰'), ('𑵆', '𑵆'), + ('𑵠', '𑵥'), ('𑵧', '𑵨'), ('𑵪', '𑶉'), ('𑶘', '𑶘'), + ('𑻠', '𑻲'), ('𒀀', '𒎙'), ('𒐀', '𒑮'), ('𒒀', '𒕃'), + ('𓀀', '𓐮'), ('𔐀', '𔙆'), ('𖠀', '𖨸'), ('𖩀', '𖩞'), + ('𖫐', '𖫭'), ('𖬀', '𖬯'), ('𖭀', '𖭃'), ('𖭣', '𖭷'), + ('𖭽', '𖮏'), ('𖹀', '𖹿'), ('𖼀', '𖽄'), ('𖽐', '𖽐'), + ('𖾓', '𖾟'), ('𖿠', '𖿡'), ('𛰀', '𛱪'), ('𛱰', '𛱼'), + ('𛲀', '𛲈'), ('𛲐', '𛲙'), ('𝐀', '𝑔'), ('𝑖', '𝒜'), + ('𝒞', '𝒟'), ('𝒢', '𝒢'), ('𝒥', '𝒦'), ('𝒩', '𝒬'), + ('𝒮', '𝒹'), ('𝒻', '𝒻'), ('𝒽', '𝓃'), ('𝓅', '𝔅'), + ('𝔇', '𝔊'), ('𝔍', '𝔔'), ('𝔖', '𝔜'), ('𝔞', '𝔹'), + ('𝔻', '𝔾'), ('𝕀', '𝕄'), ('𝕆', '𝕆'), ('𝕊', '𝕐'), + ('𝕒', '𝚥'), ('𝚨', '𝛀'), ('𝛂', '𝛚'), ('𝛜', '𝛺'), + ('𝛼', '𝜔'), ('𝜖', '𝜴'), ('𝜶', '𝝎'), ('𝝐', '𝝮'), + ('𝝰', '𝞈'), ('𝞊', '𝞨'), ('𝞪', '𝟂'), ('𝟄', '𝟋'), + ('𞠀', '𞣄'), ('𞤀', '𞥃'), ('𞸀', '𞸃'), ('𞸅', '𞸟'), + ('𞸡', '𞸢'), ('𞸤', '𞸤'), ('𞸧', '𞸧'), ('𞸩', '𞸲'), + ('𞸴', '𞸷'), ('𞸹', '𞸹'), ('𞸻', '𞸻'), ('𞹂', '𞹂'), + ('𞹇', '𞹇'), ('𞹉', '𞹉'), ('𞹋', '𞹋'), ('𞹍', '𞹏'), + ('𞹑', '𞹒'), ('𞹔', '𞹔'), ('𞹗', '𞹗'), ('𞹙', '𞹙'), + ('𞹛', '𞹛'), ('𞹝', '𞹝'), ('𞹟', '𞹟'), ('𞹡', '𞹢'), + ('𞹤', '𞹤'), ('𞹧', '𞹪'), ('𞹬', '𞹲'), ('𞹴', '𞹷'), + ('𞹹', '𞹼'), ('𞹾', '𞹾'), ('𞺀', '𞺉'), ('𞺋', '𞺛'), + ('𞺡', '𞺣'), ('𞺥', '𞺩'), ('𞺫', '𞺻'), ('🄰', '🅉'), + ('🅐', '🅩'), ('🅰', '🆉'), +]; + +pub const CR: &'static [(char, char)] = &[ + ('\r', '\r'), +]; + +pub const DOUBLE_QUOTE: &'static [(char, char)] = &[ + ('\"', '\"'), +]; + +pub const EXTEND: &'static [(char, char)] = &[ + ('\u{300}', '\u{36f}'), ('\u{483}', '\u{489}'), ('\u{591}', '\u{5bd}'), + ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), + ('\u{670}', '\u{670}'), ('\u{6d6}', '\u{6dc}'), ('\u{6df}', '\u{6e4}'), + ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{711}', '\u{711}'), + ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', '\u{7f3}'), + ('\u{7fd}', '\u{7fd}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), + ('\u{825}', '\u{827}'), ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), + ('\u{8d3}', '\u{8e1}'), ('\u{8e3}', 'ः'), ('\u{93a}', '\u{93c}'), + ('ा', 'ॏ'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), + ('\u{981}', 'ঃ'), ('\u{9bc}', '\u{9bc}'), ('\u{9be}', '\u{9c4}'), + ('ে', 'ৈ'), ('ো', '\u{9cd}'), ('\u{9d7}', '\u{9d7}'), + ('\u{9e2}', '\u{9e3}'), ('\u{9fe}', '\u{9fe}'), ('\u{a01}', 'ਃ'), + ('\u{a3c}', '\u{a3c}'), ('ਾ', '\u{a42}'), ('\u{a47}', '\u{a48}'), + ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), + ('\u{a75}', '\u{a75}'), ('\u{a81}', 'ઃ'), ('\u{abc}', '\u{abc}'), + ('ા', '\u{ac5}'), ('\u{ac7}', 'ૉ'), ('ો', '\u{acd}'), + ('\u{ae2}', '\u{ae3}'), ('\u{afa}', '\u{aff}'), ('\u{b01}', 'ଃ'), + ('\u{b3c}', '\u{b3c}'), ('\u{b3e}', '\u{b44}'), ('େ', 'ୈ'), + ('ୋ', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), + ('\u{b82}', '\u{b82}'), ('\u{bbe}', 'ூ'), ('ெ', 'ை'), + ('ொ', '\u{bcd}'), ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c04}'), + ('\u{c3e}', 'ౄ'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), + ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), ('\u{c81}', 'ಃ'), + ('\u{cbc}', '\u{cbc}'), ('ಾ', 'ೄ'), ('\u{cc6}', 'ೈ'), + ('ೊ', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{ce2}', '\u{ce3}'), + ('\u{d00}', 'ഃ'), ('\u{d3b}', '\u{d3c}'), ('\u{d3e}', '\u{d44}'), + ('െ', 'ൈ'), ('ൊ', '\u{d4d}'), ('\u{d57}', '\u{d57}'), + ('\u{d62}', '\u{d63}'), ('ං', 'ඃ'), ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('ෘ', '\u{ddf}'), + ('à·²', 'à·³'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), + ('\u{e47}', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), + ('\u{ebb}', '\u{ebc}'), ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), + ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), + ('༾', '༿'), ('\u{f71}', '\u{f84}'), ('\u{f86}', '\u{f87}'), + ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), + ('ါ', '\u{103e}'), ('ၖ', '\u{1059}'), ('\u{105e}', '\u{1060}'), + ('ၢ', 'ၤ'), ('ၧ', 'ၭ'), ('\u{1071}', '\u{1074}'), + ('\u{1082}', '\u{108d}'), ('ႏ', 'ႏ'), ('ႚ', '\u{109d}'), + ('\u{135d}', '\u{135f}'), ('\u{1712}', '\u{1714}'), + ('\u{1732}', '\u{1734}'), ('\u{1752}', '\u{1753}'), + ('\u{1772}', '\u{1773}'), ('\u{17b4}', '\u{17d3}'), + ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180d}'), + ('\u{1885}', '\u{1886}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', 'ᤫ'), + ('ᤰ', '\u{193b}'), ('\u{1a17}', '\u{1a1b}'), ('ᩕ', '\u{1a5e}'), + ('\u{1a60}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), + ('\u{1ab0}', '\u{1abe}'), ('\u{1b00}', 'ᬄ'), ('\u{1b34}', '᭄'), + ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', 'ᮂ'), ('ᮡ', '\u{1bad}'), + ('\u{1be6}', '᯳'), ('á°¤', '\u{1c37}'), ('\u{1cd0}', '\u{1cd2}'), + ('\u{1cd4}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), ('á³²', '\u{1cf4}'), + ('á³·', '\u{1cf9}'), ('\u{1dc0}', '\u{1df9}'), ('\u{1dfb}', '\u{1dff}'), + ('\u{200c}', '\u{200c}'), ('\u{20d0}', '\u{20f0}'), + ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), + ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302f}'), + ('\u{3099}', '\u{309a}'), ('\u{a66f}', '\u{a672}'), + ('\u{a674}', '\u{a67d}'), ('\u{a69e}', '\u{a69f}'), + ('\u{a6f0}', '\u{a6f1}'), ('\u{a802}', '\u{a802}'), + ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), ('ê £', 'ê §'), + ('ꢀ', 'ꢁ'), ('ꢴ', '\u{a8c5}'), ('\u{a8e0}', '\u{a8f1}'), + ('\u{a8ff}', '\u{a8ff}'), ('\u{a926}', '\u{a92d}'), ('\u{a947}', '꥓'), + ('\u{a980}', 'ꦃ'), ('\u{a9b3}', '꧀'), ('\u{a9e5}', '\u{a9e5}'), + ('\u{aa29}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', 'ꩍ'), + ('ê©»', 'ꩽ'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', '\u{aab4}'), + ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), + ('\u{aac1}', '\u{aac1}'), ('ê««', 'ꫯ'), ('ꫵ', '\u{aaf6}'), + ('ꯣ', 'ꯪ'), ('꯬', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), + ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), + ('\u{ff9e}', '\u{ff9f}'), ('\u{101fd}', '\u{101fd}'), + ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), + ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), + ('\u{10a0c}', '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), + ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), + ('\u{10d24}', '\u{10d27}'), ('\u{10f46}', '\u{10f50}'), ('𑀀', '𑀂'), + ('\u{11038}', '\u{11046}'), ('\u{1107f}', '𑂂'), ('𑂰', '\u{110ba}'), + ('\u{11100}', '\u{11102}'), ('\u{11127}', '\u{11134}'), ('𑅅', '𑅆'), + ('\u{11173}', '\u{11173}'), ('\u{11180}', '𑆂'), ('𑆳', '𑇀'), + ('\u{111c9}', '\u{111cc}'), ('𑈬', '\u{11237}'), + ('\u{1123e}', '\u{1123e}'), ('\u{112df}', '\u{112ea}'), + ('\u{11300}', '𑌃'), ('\u{1133b}', '\u{1133c}'), ('\u{1133e}', '𑍄'), + ('𑍇', '𑍈'), ('𑍋', '𑍍'), ('\u{11357}', '\u{11357}'), + ('𑍢', '𑍣'), ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}'), + ('𑐵', '\u{11446}'), ('\u{1145e}', '\u{1145e}'), + ('\u{114b0}', '\u{114c3}'), ('\u{115af}', '\u{115b5}'), + ('𑖸', '\u{115c0}'), ('\u{115dc}', '\u{115dd}'), ('𑘰', '\u{11640}'), + ('\u{116ab}', '\u{116b7}'), ('\u{1171d}', '\u{1172b}'), + ('𑠬', '\u{1183a}'), ('\u{11a01}', '\u{11a0a}'), ('\u{11a33}', '𑨹'), + ('\u{11a3b}', '\u{11a3e}'), ('\u{11a47}', '\u{11a47}'), + ('\u{11a51}', '\u{11a5b}'), ('\u{11a8a}', '\u{11a99}'), + ('𑰯', '\u{11c36}'), ('\u{11c38}', '\u{11c3f}'), + ('\u{11c92}', '\u{11ca7}'), ('𑲩', '\u{11cb6}'), + ('\u{11d31}', '\u{11d36}'), ('\u{11d3a}', '\u{11d3a}'), + ('\u{11d3c}', '\u{11d3d}'), ('\u{11d3f}', '\u{11d45}'), + ('\u{11d47}', '\u{11d47}'), ('𑶊', '𑶎'), ('\u{11d90}', '\u{11d91}'), + ('𑶓', '\u{11d97}'), ('\u{11ef3}', '𑻶'), ('\u{16af0}', '\u{16af4}'), + ('\u{16b30}', '\u{16b36}'), ('𖽑', '𖽾'), ('\u{16f8f}', '\u{16f92}'), + ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1d165}', '\u{1d169}'), + ('𝅭', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), + ('\u{1d242}', '\u{1d244}'), ('\u{1da00}', '\u{1da36}'), + ('\u{1da3b}', '\u{1da6c}'), ('\u{1da75}', '\u{1da75}'), + ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), + ('\u{1e008}', '\u{1e018}'), ('\u{1e01b}', '\u{1e021}'), + ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e944}', '\u{1e94a}'), ('🏻', '🏿'), + ('\u{e0020}', '\u{e007f}'), ('\u{e0100}', '\u{e01ef}'), +]; + +pub const EXTENDNUMLET: &'static [(char, char)] = &[ + ('_', '_'), ('\u{202f}', '\u{202f}'), ('‿', '⁀'), ('⁔', '⁔'), + ('︳', '︴'), ('﹍', '﹏'), ('_', '_'), +]; + +pub const FORMAT: &'static [(char, char)] = &[ + ('\u{ad}', '\u{ad}'), ('\u{600}', '\u{605}'), ('\u{61c}', '\u{61c}'), + ('\u{6dd}', '\u{6dd}'), ('\u{70f}', '\u{70f}'), ('\u{8e2}', '\u{8e2}'), + ('\u{180e}', '\u{180e}'), ('\u{200e}', '\u{200f}'), + ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), + ('\u{2066}', '\u{206f}'), ('\u{feff}', '\u{feff}'), + ('\u{fff9}', '\u{fffb}'), ('\u{110bd}', '\u{110bd}'), + ('\u{110cd}', '\u{110cd}'), ('\u{1bca0}', '\u{1bca3}'), + ('\u{1d173}', '\u{1d17a}'), ('\u{e0001}', '\u{e0001}'), +]; + +pub const HEBREW_LETTER: &'static [(char, char)] = &[ + ('א', 'ת'), ('ׯ', 'ײ'), ('יִ', 'יִ'), ('ײַ', 'ﬨ'), ('שׁ', 'זּ'), + ('טּ', 'לּ'), ('מּ', 'מּ'), ('נּ', 'סּ'), ('ףּ', 'פּ'), + ('צּ', 'ﭏ'), +]; + +pub const KATAKANA: &'static [(char, char)] = &[ + ('〱', '〵'), ('゛', '゜'), ('゠', 'ヺ'), ('ー', 'ヿ'), + ('ㇰ', 'ㇿ'), ('㋐', '㋾'), ('㌀', '㍗'), ('ヲ', 'ン'), + ('𛀀', '𛀀'), +]; + +pub const LF: &'static [(char, char)] = &[ + ('\n', '\n'), +]; + +pub const MIDLETTER: &'static [(char, char)] = &[ + (':', ':'), ('·', '·'), ('·', '·'), ('×´', '×´'), ('‧', '‧'), + ('︓', '︓'), ('﹕', '﹕'), (':', ':'), +]; + +pub const MIDNUM: &'static [(char, char)] = &[ + (',', ','), (';', ';'), (';', ';'), ('։', '։'), ('،', '؍'), + ('Ù¬', 'Ù¬'), ('߸', '߸'), ('⁄', '⁄'), ('︐', '︐'), ('︔', '︔'), + ('﹐', '﹐'), ('﹔', '﹔'), (',', ','), (';', ';'), +]; + +pub const MIDNUMLET: &'static [(char, char)] = &[ + ('.', '.'), ('‘', '’'), ('․', '․'), ('﹒', '﹒'), (''', '''), + ('.', '.'), +]; + +pub const NEWLINE: &'static [(char, char)] = &[ + ('\u{b}', '\u{c}'), ('\u{85}', '\u{85}'), ('\u{2028}', '\u{2029}'), +]; + +pub const NUMERIC: &'static [(char, char)] = &[ + ('0', '9'), ('Ù ', 'Ù©'), ('Ù«', 'Ù«'), ('Û°', 'Û¹'), ('߀', '߉'), + ('०', '९'), ('০', '৯'), ('੦', '੯'), ('૦', '૯'), + ('à­¦', 'à­¯'), ('௦', '௯'), ('౦', '౯'), ('೦', '೯'), + ('൦', '൯'), ('à·¦', 'à·¯'), ('๐', '๙'), ('໐', '໙'), + ('༠', '༩'), ('၀', '၉'), ('႐', '႙'), ('០', '៩'), + ('᠐', '᠙'), ('᥆', '᥏'), ('᧐', '᧙'), ('᪀', '᪉'), + ('᪐', '᪙'), ('᭐', '᭙'), ('á®°', '᮹'), ('᱀', '᱉'), + ('᱐', '᱙'), ('꘠', '꘩'), ('꣐', '꣙'), ('꤀', '꤉'), + ('꧐', '꧙'), ('ê§°', 'ê§¹'), ('꩐', '꩙'), ('꯰', '꯹'), + ('𐒠', '𐒩'), ('𐴰', '𐴹'), ('𑁦', '𑁯'), ('𑃰', '𑃹'), + ('𑄶', '𑄿'), ('𑇐', '𑇙'), ('𑋰', '𑋹'), ('𑑐', '𑑙'), + ('𑓐', '𑓙'), ('𑙐', '𑙙'), ('𑛀', '𑛉'), ('𑜰', '𑜹'), + ('𑣠', '𑣩'), ('𑱐', '𑱙'), ('𑵐', '𑵙'), ('𑶠', '𑶩'), + ('𖩠', '𖩩'), ('𖭐', '𖭙'), ('𝟎', '𝟿'), ('𞥐', '𞥙'), +]; + +pub const REGIONAL_INDICATOR: &'static [(char, char)] = &[ + ('🇦', '🇿'), +]; + +pub const SINGLE_QUOTE: &'static [(char, char)] = &[ + ('\'', '\''), +]; + +pub const WSEGSPACE: &'static [(char, char)] = &[ + (' ', ' '), ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{2006}'), + ('\u{2008}', '\u{200a}'), ('\u{205f}', '\u{205f}'), + ('\u{3000}', '\u{3000}'), +]; + +pub const ZWJ: &'static [(char, char)] = &[ + ('\u{200d}', '\u{200d}'), +]; diff --git a/regex/.cargo-checksum.json b/regex/.cargo-checksum.json new file mode 100644 index 000000000..13a8edab3 --- /dev/null +++ b/regex/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"} \ No newline at end of file diff --git a/regex/CHANGELOG.md b/regex/CHANGELOG.md new file mode 100644 index 000000000..2c0d370a7 --- /dev/null +++ b/regex/CHANGELOG.md @@ -0,0 +1,668 @@ +1.1.6 (2019-04-16) +================== +This release fixes a regression introduced by a bug fix (for +[BUG #557](https://github.com/rust-lang/regex/issues/557)) which could cause +the regex engine to enter an infinite loop. This bug was originally +[reported against ripgrep](https://github.com/BurntSushi/ripgrep/issues/1247). + + +1.1.5 (2019-04-01) +================== +This release fixes a bug in regex's dependency specification where it requires +a newer version of regex-syntax, but this wasn't communicated correctly in the +Cargo.toml. This would have been caught by a minimal version check, but this +check was disabled because the `rand` crate itself advertises incorrect +dependency specifications. + +Bug fixes: + +* [BUG #570](https://github.com/rust-lang/regex/pull/570): + Fix regex-syntax minimal version. + + +1.1.4 (2019-03-31) +================== +This release fixes a backwards compatibility regression where Regex was no +longer UnwindSafe. This was caused by the upgrade to aho-corasick 0.7, whose +AhoCorasick type was itself not UnwindSafe. This has been fixed in aho-corasick +0.7.4, which we now require. + +Bug fixes: + +* [BUG #568](https://github.com/rust-lang/regex/pull/568): + Fix an API regression where Regex was no longer UnwindSafe. + + +1.1.3 (2019-03-30) +================== +This releases fixes a few bugs and adds a performance improvement when a regex +is a simple alternation of literals. + +Performance improvements: + +* [OPT #566](https://github.com/rust-lang/regex/pull/566): + Upgrades `aho-corasick` to 0.7 and uses it for `foo|bar|...|quux` regexes. + +Bug fixes: + +* [BUG #527](https://github.com/rust-lang/regex/issues/527): + Fix a bug where the parser would panic on patterns like `((?x))`. +* [BUG #555](https://github.com/rust-lang/regex/issues/555): + Fix a bug where the parser would panic on patterns like `(?m){1,1}`. +* [BUG #557](https://github.com/rust-lang/regex/issues/557): + Fix a bug where captures could lead to an incorrect match. + + +1.1.2 (2019-02-27) +================== +This release fixes a bug found in the fix introduced in 1.1.1. + +Bug fixes: + +* [BUG edf45e6f](https://github.com/rust-lang/regex/commit/edf45e6f): + Fix bug introduced in reverse suffix literal matcher in the 1.1.1 release. + + +1.1.1 (2019-02-27) +================== +This is a small release with one fix for a bug caused by literal optimizations. + +Bug fixes: + +* [BUG 661bf53d](https://github.com/rust-lang/regex/commit/661bf53d): + Fixes a bug in the reverse suffix literal optimization. This was originally + reported + [against ripgrep](https://github.com/BurntSushi/ripgrep/issues/1203). + + +1.1.0 (2018-11-30) +================== +This is a small release with a couple small enhancements. This release also +increases the minimal supported Rust version (MSRV) to 1.24.1 (from 1.20.0). In +accordance with this crate's MSRV policy, this release bumps the minor version +number. + +Performance improvements: + +* [OPT #511](https://github.com/rust-lang/regex/pull/511), + [OPT #540](https://github.com/rust-lang/regex/pull/540): + Improve lazy DFA construction for large regex sets. + +New features: + +* [FEATURE #538](https://github.com/rust-lang/regex/pull/538): + Add Emoji and "break" Unicode properties. See [UNICODE.md](UNICODE.md). + +Bug fixes: + +* [BUG #530](https://github.com/rust-lang/regex/pull/530): + Add Unicode license (for data tables). +* Various typo/doc fixups. + + +1.0.6 (2018-11-06) +================== +This is a small release. + +Performance improvements: + +* [OPT #513](https://github.com/rust-lang/regex/pull/513): + Improve performance of compiling large Unicode classes by 8-10%. + +Bug fixes: + +* [BUG #533](https://github.com/rust-lang/regex/issues/533): + Fix definition of `[[:blank:]]` class that regressed in `regex-syntax 0.5`. + + +1.0.5 (2018-09-06) +================== +This is a small release with an API enhancement. + +New features: + +* [FEATURE #509](https://github.com/rust-lang/regex/pull/509): + Generalize impls of the `Replacer` trait. + + +1.0.4 (2018-08-25) +================== +This is a small release that bumps the quickcheck dependency. + + +1.0.3 (2018-08-24) +================== +This is a small bug fix release. + +Bug fixes: + +* [BUG #504](https://github.com/rust-lang/regex/pull/504): + Fix for Cargo's "minimal version" support. +* [BUG 1e39165f](https://github.com/rust-lang/regex/commit/1e39165f): + Fix doc examples for byte regexes. + + +1.0.2 (2018-07-18) +================== +This release exposes some new lower level APIs on `Regex` that permit +amortizing allocation and controlling the location at which a search is +performed in a more granular way. Most users of the regex crate will not +need or want to use these APIs. + +New features: + +* [FEATURE #493](https://github.com/rust-lang/regex/pull/493): + Add a few lower level APIs for amortizing allocation and more fine grained + searching. + +Bug fixes: + +* [BUG 3981d2ad](https://github.com/rust-lang/regex/commit/3981d2ad): + Correct outdated documentation on `RegexBuilder::dot_matches_new_line`. +* [BUG 7ebe4ae0](https://github.com/rust-lang/regex/commit/7ebe4ae0): + Correct outdated documentation on `Parser::allow_invalid_utf8` in the + `regex-syntax` crate. +* [BUG 24c7770b](https://github.com/rust-lang/regex/commit/24c7770b): + Fix a bug in the HIR printer where it wouldn't correctly escape meta + characters in character classes. + + +1.0.1 (2018-06-19) +================== +This release upgrades regex's Unicode tables to Unicode 11, and enables SIMD +optimizations automatically on Rust stable (1.27 or newer). + +New features: + +* [FEATURE #486](https://github.com/rust-lang/regex/pull/486): + Implement `size_hint` on `RegexSet` match iterators. +* [FEATURE #488](https://github.com/rust-lang/regex/pull/488): + Update Unicode tables for Unicode 11. +* [FEATURE #490](https://github.com/rust-lang/regex/pull/490): + SIMD optimizations are now enabled automatically in Rust stable, for versions + 1.27 and up. No compilation flags or features need to be set. CPU support + SIMD is detected automatically at runtime. + +Bug fixes: + +* [BUG #482](https://github.com/rust-lang/regex/pull/482): + Present a better compilation error when the `use_std` feature isn't used. + + +1.0.0 (2018-05-01) +================== +This release marks the 1.0 release of regex. + +While this release includes some breaking changes, most users of older versions +of the regex library should be able to migrate to 1.0 by simply bumping the +version number. The important changes are as follows: + +* We adopt Rust 1.20 as the new minimum supported version of Rust for regex. + We also tentativley adopt a policy that permits bumping the minimum supported + version of Rust in minor version releases of regex, but no patch releases. + That is, with respect to semver, we do not strictly consider bumping the + minimum version of Rust to be a breaking change, but adopt a conservative + stance as a compromise. +* Octal syntax in regular expressions has been disabled by default. This + permits better error messages that inform users that backreferences aren't + available. Octal syntax can be re-enabled via the corresponding option on + `RegexBuilder`. +* `(?-u:\B)` is no longer allowed in Unicode regexes since it can match at + invalid UTF-8 code unit boundaries. `(?-u:\b)` is still allowed in Unicode + regexes. +* The `From<regex_syntax::Error>` impl has been removed. This formally removes + the public dependency on `regex-syntax`. +* A new feature, `use_std`, has been added and enabled by default. Disabling + the feature will result in a compilation error. In the future, this may + permit us to support `no_std` environments (w/ `alloc`) in a backwards + compatible way. + +For more information and discussion, please see +[1.0 release tracking issue](https://github.com/rust-lang/regex/issues/457). + + +0.2.11 (2018-05-01) +=================== +This release primarily contains bug fixes. Some of them resolve bugs where +the parser could panic. + +New features: + +* [FEATURE #459](https://github.com/rust-lang/regex/pull/459): + Include C++'s standard regex library and Boost's regex library in the + benchmark harness. We now include D/libphobos, C++/std, C++/boost, Oniguruma, + PCRE1, PCRE2, RE2 and Tcl in the harness. + +Bug fixes: + +* [BUG #445](https://github.com/rust-lang/regex/issues/445): + Clarify order of indices returned by RegexSet match iterator. +* [BUG #461](https://github.com/rust-lang/regex/issues/461): + Improve error messages for invalid regexes like `[\d-a]`. +* [BUG #464](https://github.com/rust-lang/regex/issues/464): + Fix a bug in the error message pretty printer that could cause a panic when + a regex contained a literal `\n` character. +* [BUG #465](https://github.com/rust-lang/regex/issues/465): + Fix a panic in the parser that was caused by applying a repetition operator + to `(?flags)`. +* [BUG #466](https://github.com/rust-lang/regex/issues/466): + Fix a bug where `\pC` was not recognized as an alias for `\p{Other}`. +* [BUG #470](https://github.com/rust-lang/regex/pull/470): + Fix a bug where literal searches did more work than necessary for anchored + regexes. + + +0.2.10 (2018-03-16) +=================== +This release primarily updates the regex crate to changes made in `std::arch` +on nightly Rust. + +New features: + +* [FEATURE #458](https://github.com/rust-lang/regex/pull/458): + The `Hir` type in `regex-syntax` now has a printer. + + +0.2.9 (2018-03-12) +================== +This release introduces a new nightly only feature, `unstable`, which enables +SIMD optimizations for certain types of regexes. No additional compile time +options are necessary, and the regex crate will automatically choose the +best CPU features at run time. As a result, the `simd` (nightly only) crate +dependency has been dropped. + +New features: + +* [FEATURE #456](https://github.com/rust-lang/regex/pull/456): + The regex crate now includes AVX2 optimizations in addition to the extant + SSSE3 optimization. + +Bug fixes: + +* [BUG #455](https://github.com/rust-lang/regex/pull/455): + Fix a bug where `(?x)[ / - ]` failed to parse. + + +0.2.8 (2018-03-12) +================== +Bug gixes: + +* [BUG #454](https://github.com/rust-lang/regex/pull/454): + Fix a bug in the nest limit checker being too aggressive. + + +0.2.7 (2018-03-07) +================== +This release includes a ground-up rewrite of the regex-syntax crate, which has +been in development for over a year. + +New features: + +* Error messages for invalid regexes have been greatly improved. You get these + automatically; you don't need to do anything. In addition to better + formatting, error messages will now explicitly call out the use of look + around. When regex 1.0 is released, this will happen for backreferences as + well. +* Full support for intersection, difference and symmetric difference of + character classes. These can be used via the `&&`, `--` and `~~` binary + operators within classes. +* A Unicode Level 1 conformat implementation of `\p{..}` character classes. + Things like `\p{scx:Hira}`, `\p{age:3.2}` or `\p{Changes_When_Casefolded}` + now work. All property name and value aliases are supported, and properties + are selected via loose matching. e.g., `\p{Greek}` is the same as + `\p{G r E e K}`. +* A new `UNICODE.md` document has been added to this repository that + exhaustively documents support for UTS#18. +* Empty sub-expressions are now permitted in most places. That is, `()+` is + now a valid regex. +* Almost everything in regex-syntax now uses constant stack space, even when + performing anaylsis that requires structural induction. This reduces the risk + of a user provided regular expression causing a stack overflow. +* [FEATURE #174](https://github.com/rust-lang/regex/issues/174): + The `Ast` type in `regex-syntax` now contains span information. +* [FEATURE #424](https://github.com/rust-lang/regex/issues/424): + Support `\u`, `\u{...}`, `\U` and `\U{...}` syntax for specifying code points + in a regular expression. +* [FEATURE #449](https://github.com/rust-lang/regex/pull/449): + Add a `Replace::by_ref` adapter for use of a replacer without consuming it. + +Bug fixes: + +* [BUG #446](https://github.com/rust-lang/regex/issues/446): + We re-enable the Boyer-Moore literal matcher. + + +0.2.6 (2018-02-08) +================== +Bug fixes: + +* [BUG #446](https://github.com/rust-lang/regex/issues/446): + Fixes a bug in the new Boyer-Moore searcher that results in a match failure. + We fix this bug by temporarily disabling Boyer-Moore. + + +0.2.5 (2017-12-30) +================== +Bug fixes: + +* [BUG #437](https://github.com/rust-lang/regex/issues/437): + Fixes a bug in the new Boyer-Moore searcher that results in a panic. + + +0.2.4 (2017-12-30) +================== +New features: + +* [FEATURE #348](https://github.com/rust-lang/regex/pull/348): + Improve performance for capture searches on anchored regex. + (Contributed by @ethanpailes. Nice work!) +* [FEATURE #419](https://github.com/rust-lang/regex/pull/419): + Expand literal searching to include Tuned Boyer-Moore in some cases. + (Contributed by @ethanpailes. Nice work!) + +Bug fixes: + +* [BUG](https://github.com/rust-lang/regex/pull/436): + The regex compiler plugin has been removed. +* [BUG](https://github.com/rust-lang/regex/pull/436): + `simd` has been bumped to `0.2.1`, which fixes a Rust nightly build error. +* [BUG](https://github.com/rust-lang/regex/pull/436): + Bring the benchmark harness up to date. + + +0.2.3 (2017-11-30) +================== +New features: + +* [FEATURE #374](https://github.com/rust-lang/regex/pull/374): + Add `impl From<Match> for &str`. +* [FEATURE #380](https://github.com/rust-lang/regex/pull/380): + Derive `Clone` and `PartialEq` on `Error`. +* [FEATURE #400](https://github.com/rust-lang/regex/pull/400): + Update to Unicode 10. + +Bug fixes: + +* [BUG #375](https://github.com/rust-lang/regex/issues/375): + Fix a bug that prevented the bounded backtracker from terminating. +* [BUG #393](https://github.com/rust-lang/regex/issues/393), + [BUG #394](https://github.com/rust-lang/regex/issues/394): + Fix bug with `replace` methods for empty matches. + + +0.2.2 (2017-05-21) +================== +New features: + +* [FEATURE #341](https://github.com/rust-lang/regex/issues/341): + Support nested character classes and intersection operation. + For example, `[\p{Greek}&&\pL]` matches greek letters and + `[[0-9]&&[^4]]` matches every decimal digit except `4`. + (Much thanks to @robinst, who contributed this awesome feature.) + +Bug fixes: + +* [BUG #321](https://github.com/rust-lang/regex/issues/321): + Fix bug in literal extraction and UTF-8 decoding. +* [BUG #326](https://github.com/rust-lang/regex/issues/326): + Add documentation tip about the `(?x)` flag. +* [BUG #333](https://github.com/rust-lang/regex/issues/333): + Show additional replacement example using curly braces. +* [BUG #334](https://github.com/rust-lang/regex/issues/334): + Fix bug when resolving captures after a match. +* [BUG #338](https://github.com/rust-lang/regex/issues/338): + Add example that uses `Captures::get` to API documentation. +* [BUG #353](https://github.com/rust-lang/regex/issues/353): + Fix RegexSet bug that caused match failure in some cases. +* [BUG #354](https://github.com/rust-lang/regex/pull/354): + Fix panic in parser when `(?x)` is used. +* [BUG #358](https://github.com/rust-lang/regex/issues/358): + Fix literal optimization bug with RegexSet. +* [BUG #359](https://github.com/rust-lang/regex/issues/359): + Fix example code in README. +* [BUG #365](https://github.com/rust-lang/regex/pull/365): + Fix bug in `rure_captures_len` in the C binding. +* [BUG #367](https://github.com/rust-lang/regex/issues/367): + Fix byte class bug that caused a panic. + + +0.2.1 +===== +One major bug with `replace_all` has been fixed along with a couple of other +touchups. + +* [BUG #312](https://github.com/rust-lang/regex/issues/312): + Fix documentation for `NoExpand` to reference correct lifetime parameter. +* [BUG #314](https://github.com/rust-lang/regex/issues/314): + Fix a bug with `replace_all` when replacing a match with the empty string. +* [BUG #316](https://github.com/rust-lang/regex/issues/316): + Note a missing breaking change from the `0.2.0` CHANGELOG entry. + (`RegexBuilder::compile` was renamed to `RegexBuilder::build`.) +* [BUG #324](https://github.com/rust-lang/regex/issues/324): + Compiling `regex` should only require one version of `memchr` crate. + + +0.2.0 +===== +This is a new major release of the regex crate, and is an implementation of the +[regex 1.0 RFC](https://github.com/rust-lang/rfcs/blob/master/text/1620-regex-1.0.md). +We are releasing a `0.2` first, and if there are no major problems, we will +release a `1.0` shortly. For `0.2`, the minimum *supported* Rust version is +1.12. + +There are a number of **breaking changes** in `0.2`. They are split into two +types. The first type correspond to breaking changes in regular expression +syntax. The second type correspond to breaking changes in the API. + +Breaking changes for regex syntax: + +* POSIX character classes now require double bracketing. Previously, the regex + `[:upper:]` would parse as the `upper` POSIX character class. Now it parses + as the character class containing the characters `:upper:`. The fix to this + change is to use `[[:upper:]]` instead. Note that variants like + `[[:upper:][:blank:]]` continue to work. +* The character `[` must always be escaped inside a character class. +* The characters `&`, `-` and `~` must be escaped if any one of them are + repeated consecutively. For example, `[&]`, `[\&]`, `[\&\&]`, `[&-&]` are all + equivalent while `[&&]` is illegal. (The motivation for this and the prior + change is to provide a backwards compatible path for adding character class + set notation.) +* A `bytes::Regex` now has Unicode mode enabled by default (like the main + `Regex` type). This means regexes compiled with `bytes::Regex::new` that + don't have the Unicode flag set should add `(?-u)` to recover the original + behavior. + +Breaking changes for the regex API: + +* `find` and `find_iter` now **return `Match` values instead of + `(usize, usize)`.** `Match` values have `start` and `end` methods, which + return the match offsets. `Match` values also have an `as_str` method, + which returns the text of the match itself. +* The `Captures` type now only provides a single iterator over all capturing + matches, which should replace uses of `iter` and `iter_pos`. Uses of + `iter_named` should use the `capture_names` method on `Regex`. +* The `at` method on the `Captures` type has been renamed to `get`, and it + now returns a `Match`. Similarly, the `name` method on `Captures` now returns + a `Match`. +* The `replace` methods now return `Cow` values. The `Cow::Borrowed` variant + is returned when no replacements are made. +* The `Replacer` trait has been completely overhauled. This should only + impact clients that implement this trait explicitly. Standard uses of + the `replace` methods should continue to work unchanged. If you implement + the `Replacer` trait, please consult the new documentation. +* The `quote` free function has been renamed to `escape`. +* The `Regex::with_size_limit` method has been removed. It is replaced by + `RegexBuilder::size_limit`. +* The `RegexBuilder` type has switched from owned `self` method receivers to + `&mut self` method receivers. Most uses will continue to work unchanged, but + some code may require naming an intermediate variable to hold the builder. +* The `compile` method on `RegexBuilder` has been renamed to `build`. +* The free `is_match` function has been removed. It is replaced by compiling + a `Regex` and calling its `is_match` method. +* The `PartialEq` and `Eq` impls on `Regex` have been dropped. If you relied + on these impls, the fix is to define a wrapper type around `Regex`, impl + `Deref` on it and provide the necessary impls. +* The `is_empty` method on `Captures` has been removed. This always returns + `false`, so its use is superfluous. +* The `Syntax` variant of the `Error` type now contains a string instead of + a `regex_syntax::Error`. If you were examining syntax errors more closely, + you'll need to explicitly use the `regex_syntax` crate to re-parse the regex. +* The `InvalidSet` variant of the `Error` type has been removed since it is + no longer used. +* Most of the iterator types have been renamed to match conventions. If you + were using these iterator types explicitly, please consult the documentation + for its new name. For example, `RegexSplits` has been renamed to `Split`. + +A number of bugs have been fixed: + +* [BUG #151](https://github.com/rust-lang/regex/issues/151): + The `Replacer` trait has been changed to permit the caller to control + allocation. +* [BUG #165](https://github.com/rust-lang/regex/issues/165): + Remove the free `is_match` function. +* [BUG #166](https://github.com/rust-lang/regex/issues/166): + Expose more knobs (available in `0.1`) and remove `with_size_limit`. +* [BUG #168](https://github.com/rust-lang/regex/issues/168): + Iterators produced by `Captures` now have the correct lifetime parameters. +* [BUG #175](https://github.com/rust-lang/regex/issues/175): + Fix a corner case in the parsing of POSIX character classes. +* [BUG #178](https://github.com/rust-lang/regex/issues/178): + Drop the `PartialEq` and `Eq` impls on `Regex`. +* [BUG #179](https://github.com/rust-lang/regex/issues/179): + Remove `is_empty` from `Captures` since it always returns false. +* [BUG #276](https://github.com/rust-lang/regex/issues/276): + Position of named capture can now be retrieved from a `Captures`. +* [BUG #296](https://github.com/rust-lang/regex/issues/296): + Remove winapi/kernel32-sys dependency on UNIX. +* [BUG #307](https://github.com/rust-lang/regex/issues/307): + Fix error on emscripten. + + +0.1.80 +====== +* [PR #292](https://github.com/rust-lang/regex/pull/292): + Fixes bug #291, which was introduced by PR #290. + +0.1.79 +====== +* Require regex-syntax 0.3.8. + +0.1.78 +====== +* [PR #290](https://github.com/rust-lang/regex/pull/290): + Fixes bug #289, which caused some regexes with a certain combination + of literals to match incorrectly. + +0.1.77 +====== +* [PR #281](https://github.com/rust-lang/regex/pull/281): + Fixes bug #280 by disabling all literal optimizations when a pattern + is partially anchored. + +0.1.76 +====== +* Tweak criteria for using the Teddy literal matcher. + +0.1.75 +====== +* [PR #275](https://github.com/rust-lang/regex/pull/275): + Improves match verification performance in the Teddy SIMD searcher. +* [PR #278](https://github.com/rust-lang/regex/pull/278): + Replaces slow substring loop in the Teddy SIMD searcher with Aho-Corasick. +* Implemented DoubleEndedIterator on regex set match iterators. + +0.1.74 +====== +* Release regex-syntax 0.3.5 with a minor bug fix. +* Fix bug #272. +* Fix bug #277. +* [PR #270](https://github.com/rust-lang/regex/pull/270): + Fixes bugs #264, #268 and an unreported where the DFA cache size could be + drastically under estimated in some cases (leading to high unexpected memory + usage). + +0.1.73 +====== +* Release `regex-syntax 0.3.4`. +* Bump `regex-syntax` dependency version for `regex` to `0.3.4`. + +0.1.72 +====== +* [PR #262](https://github.com/rust-lang/regex/pull/262): + Fixes a number of small bugs caught by fuzz testing (AFL). + +0.1.71 +====== +* [PR #236](https://github.com/rust-lang/regex/pull/236): + Fix a bug in how suffix literals were extracted, which could lead + to invalid match behavior in some cases. + +0.1.70 +====== +* [PR #231](https://github.com/rust-lang/regex/pull/231): + Add SIMD accelerated multiple pattern search. +* [PR #228](https://github.com/rust-lang/regex/pull/228): + Reintroduce the reverse suffix literal optimization. +* [PR #226](https://github.com/rust-lang/regex/pull/226): + Implements NFA state compression in the lazy DFA. +* [PR #223](https://github.com/rust-lang/regex/pull/223): + A fully anchored RegexSet can now short-circuit. + +0.1.69 +====== +* [PR #216](https://github.com/rust-lang/regex/pull/216): + Tweak the threshold for running backtracking. +* [PR #217](https://github.com/rust-lang/regex/pull/217): + Add upper limit (from the DFA) to capture search (for the NFA). +* [PR #218](https://github.com/rust-lang/regex/pull/218): + Add rure, a C API. + +0.1.68 +====== +* [PR #210](https://github.com/rust-lang/regex/pull/210): + Fixed a performance bug in `bytes::Regex::replace` where `extend` was used + instead of `extend_from_slice`. +* [PR #211](https://github.com/rust-lang/regex/pull/211): + Fixed a bug in the handling of word boundaries in the DFA. +* [PR #213](https://github.com/rust-lang/pull/213): + Added RE2 and Tcl to the benchmark harness. Also added a CLI utility from + running regexes using any of the following regex engines: PCRE1, PCRE2, + Oniguruma, RE2, Tcl and of course Rust's own regexes. + +0.1.67 +====== +* [PR #201](https://github.com/rust-lang/regex/pull/201): + Fix undefined behavior in the `regex!` compiler plugin macro. +* [PR #205](https://github.com/rust-lang/regex/pull/205): + More improvements to DFA performance. Competitive with RE2. See PR for + benchmarks. +* [PR #209](https://github.com/rust-lang/regex/pull/209): + Release 0.1.66 was semver incompatible since it required a newer version + of Rust than previous releases. This PR fixes that. (And `0.1.66` was + yanked.) + +0.1.66 +====== +* Speculative support for Unicode word boundaries was added to the DFA. This + should remove the last common case that disqualified use of the DFA. +* An optimization that scanned for suffix literals and then matched the regular + expression in reverse was removed because it had worst case quadratic time + complexity. It was replaced with a more limited optimization where, given any + regex of the form `re$`, it will be matched in reverse from the end of the + haystack. +* [PR #202](https://github.com/rust-lang/regex/pull/202): + The inner loop of the DFA was heavily optimized to improve cache locality + and reduce the overall number of instructions run on each iteration. This + represents the first use of `unsafe` in `regex` (to elide bounds checks). +* [PR #200](https://github.com/rust-lang/regex/pull/200): + Use of the `mempool` crate (which used thread local storage) was replaced + with a faster version of a similar API in @Amanieu's `thread_local` crate. + It should reduce contention when using a regex from multiple threads + simultaneously. +* PCRE2 JIT benchmarks were added. A benchmark comparison can be found + [here](https://gist.github.com/anonymous/14683c01993e91689f7206a18675901b). + (Includes a comparison with PCRE1's JIT and Oniguruma.) +* A bug where word boundaries weren't being matched correctly in the DFA was + fixed. This only affected use of `bytes::Regex`. +* [#160](https://github.com/rust-lang/regex/issues/160): + `Captures` now has a `Debug` impl. diff --git a/regex/Cargo.toml b/regex/Cargo.toml new file mode 100644 index 000000000..1dd95e7d3 --- /dev/null +++ b/regex/Cargo.toml @@ -0,0 +1,106 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "regex" +version = "1.1.6" +authors = ["The Rust Project Developers"] +exclude = ["/.travis.yml", "/appveyor.yml", "/ci/*", "/scripts/*"] +autotests = false +description = "An implementation of regular expressions for Rust. This implementation uses\nfinite automata and guarantees linear time matching on all inputs.\n" +homepage = "https://github.com/rust-lang/regex" +documentation = "https://docs.rs/regex" +readme = "README.md" +categories = ["text-processing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/regex" +[profile.test] +debug = true + +[profile.bench] +debug = true + +[profile.release] +debug = true + +[lib] +bench = false + +[[test]] +name = "default" +path = "tests/test_default.rs" + +[[test]] +name = "default-bytes" +path = "tests/test_default_bytes.rs" + +[[test]] +name = "nfa" +path = "tests/test_nfa.rs" + +[[test]] +name = "nfa-utf8bytes" +path = "tests/test_nfa_utf8bytes.rs" + +[[test]] +name = "nfa-bytes" +path = "tests/test_nfa_bytes.rs" + +[[test]] +name = "backtrack" +path = "tests/test_backtrack.rs" + +[[test]] +name = "backtrack-utf8bytes" +path = "tests/test_backtrack_utf8bytes.rs" + +[[test]] +name = "backtrack-bytes" +path = "tests/test_backtrack_bytes.rs" + +[[test]] +name = "crates-regex" +path = "tests/test_crates_regex.rs" +[dependencies.aho-corasick] +version = "0.7.3" + +[dependencies.memchr] +version = "2.0.2" + +[dependencies.regex-syntax] +version = "0.6.6" + +[dependencies.thread_local] +version = "0.3.6" + +[dependencies.utf8-ranges] +version = "1.0.1" +[dev-dependencies.lazy_static] +version = "1" + +[dev-dependencies.quickcheck] +version = "0.7" +default-features = false + +[dev-dependencies.rand] +version = "0.6.5" + +[features] +default = ["use_std"] +pattern = [] +unstable = ["pattern"] +use_std = [] +[badges.appveyor] +repository = "rust-lang-libs/regex" + +[badges.travis-ci] +repository = "rust-lang/regex" diff --git a/regex/HACKING.md b/regex/HACKING.md new file mode 100644 index 000000000..160bbc328 --- /dev/null +++ b/regex/HACKING.md @@ -0,0 +1,341 @@ +Your friendly guide to hacking and navigating the regex library. + +This guide assumes familiarity with Rust and Cargo, and at least a perusal of +the user facing documentation for this crate. + +If you're looking for background on the implementation in this library, then +you can do no better than Russ Cox's article series on implementing regular +expressions using finite automata: https://swtch.com/~rsc/regexp/ + + +## Architecture overview + +As you probably already know, this library executes regular expressions using +finite automata. In particular, a design goal is to make searching linear +with respect to both the regular expression and the text being searched. +Meeting that design goal on its own is not so hard and can be done with an +implementation of the Pike VM (similar to Thompson's construction, but supports +capturing groups), as described in: https://swtch.com/~rsc/regexp/regexp2.html +--- This library contains such an implementation in src/pikevm.rs. + +Making it fast is harder. One of the key problems with the Pike VM is that it +can be in more than one state at any point in time, and must shuffle capture +positions between them. The Pike VM also spends a lot of time following the +same epsilon transitions over and over again. We can employ one trick to +speed up the Pike VM: extract one or more literal prefixes from the regular +expression and execute specialized code to quickly find matches of those +prefixes in the search text. The Pike VM can then be avoided for most the +search, and instead only executed when a prefix is found. The code to find +prefixes is in the regex-syntax crate (in this repository). The code to search +for literals is in src/literals.rs. When more than one literal prefix is found, +we fall back to an Aho-Corasick DFA using the aho-corasick crate. For one +literal, we use a variant of the Boyer-Moore algorithm. Both Aho-Corasick and +Boyer-Moore use `memchr` when appropriate. The Boyer-Moore variant in this +library also uses elementary frequency analysis to choose the right byte to run +`memchr` with. + +Of course, detecting prefix literals can only take us so far. Not all regular +expressions have literal prefixes. To remedy this, we try another approach +to executing the Pike VM: backtracking, whose implementation can be found in +src/backtrack.rs. One reason why backtracking can be faster is that it avoids +excessive shuffling of capture groups. Of course, backtracking is susceptible +to exponential runtimes, so we keep track of every state we've visited to make +sure we never visit it again. This guarantees linear time execution, but we +pay for it with the memory required to track visited states. Because of the +memory requirement, we only use this engine on small search strings *and* small +regular expressions. + +Lastly, the real workhorse of this library is the "lazy" DFA in src/dfa.rs. +It is distinct from the Pike VM in that the DFA is explicitly represented in +memory and is only ever in one state at a time. It is said to be "lazy" because +the DFA is computed as text is searched, where each byte in the search text +results in at most one new DFA state. It is made fast by caching states. DFAs +are susceptible to exponential state blow up (where the worst case is computing +a new state for every input byte, regardless of what's in the state cache). To +avoid using a lot of memory, the lazy DFA uses a bounded cache. Once the cache +is full, it is wiped and state computation starts over again. If the cache is +wiped too frequently, then the DFA gives up and searching falls back to one of +the aforementioned algorithms. + +All of the above matching engines expose precisely the same matching semantics. +This is indeed tested. (See the section below about testing.) + +The following sub-sections describe the rest of the library and how each of the +matching engines are actually used. + +### Parsing + +Regular expressions are parsed using the regex-syntax crate, which is +maintained in this repository. The regex-syntax crate defines an abstract +syntax and provides very detailed error messages when a parse error is +encountered. Parsing is done in a separate crate so that others may benefit +from its existence, and because it is relatively divorced from the rest of the +regex library. + +The regex-syntax crate also provides sophisticated support for extracting +prefix and suffix literals from regular expressions. + +### Compilation + +The compiler is in src/compile.rs. The input to the compiler is some abstract +syntax for a regular expression and the output is a sequence of opcodes that +matching engines use to execute a search. (One can think of matching engines as +mini virtual machines.) The sequence of opcodes is a particular encoding of a +non-deterministic finite automaton. In particular, the opcodes explicitly rely +on epsilon transitions. + +Consider a simple regular expression like `a|b`. Its compiled form looks like +this: + + 000 Save(0) + 001 Split(2, 3) + 002 'a' (goto: 4) + 003 'b' + 004 Save(1) + 005 Match + +The first column is the instruction pointer and the second column is the +instruction. Save instructions indicate that the current position in the input +should be stored in a captured location. Split instructions represent a binary +branch in the program (i.e., epsilon transitions). The instructions `'a'` and +`'b'` indicate that the literal bytes `'a'` or `'b'` should match. + +In older versions of this library, the compilation looked like this: + + 000 Save(0) + 001 Split(2, 3) + 002 'a' + 003 Jump(5) + 004 'b' + 005 Save(1) + 006 Match + +In particular, empty instructions that merely served to move execution from one +point in the program to another were removed. Instead, every instruction has a +`goto` pointer embedded into it. This resulted in a small performance boost for +the Pike VM, because it was one fewer epsilon transition that it had to follow. + +There exist more instructions and they are defined and documented in +src/prog.rs. + +Compilation has several knobs and a few unfortunately complicated invariants. +Namely, the output of compilation can be one of two types of programs: a +program that executes on Unicode scalar values or a program that executes +on raw bytes. In the former case, the matching engine is responsible for +performing UTF-8 decoding and executing instructions using Unicode codepoints. +In the latter case, the program handles UTF-8 decoding implicitly, so that the +matching engine can execute on raw bytes. All matching engines can execute +either Unicode or byte based programs except for the lazy DFA, which requires +byte based programs. In general, both representations were kept because (1) the +lazy DFA requires byte based programs so that states can be encoded in a memory +efficient manner and (2) the Pike VM benefits greatly from inlining Unicode +character classes into fewer instructions as it results in fewer epsilon +transitions. + +N.B. UTF-8 decoding is built into the compiled program by making use of the +utf8-ranges crate. The compiler in this library factors out common suffixes to +reduce the size of huge character classes (e.g., `\pL`). + +A regrettable consequence of this split in instruction sets is we generally +need to compile two programs; one for NFA execution and one for the lazy DFA. + +In fact, it is worse than that: the lazy DFA is not capable of finding the +starting location of a match in a single scan, and must instead execute a +backwards search after finding the end location. To execute a backwards search, +we must have compiled the regular expression *in reverse*. + +This means that every compilation of a regular expression generally results in +three distinct programs. It would be possible to lazily compile the Unicode +program, since it is never needed if (1) the regular expression uses no word +boundary assertions and (2) the caller never asks for sub-capture locations. + +### Execution + +At the time of writing, there are four matching engines in this library: + +1. The Pike VM (supports captures). +2. Bounded backtracking (supports captures). +3. Literal substring or multi-substring search. +4. Lazy DFA (no support for Unicode word boundary assertions). + +Only the first two matching engines are capable of executing every regular +expression program. They also happen to be the slowest, which means we need +some logic that (1) knows various facts about the regular expression and (2) +knows what the caller wants. Using this information, we can determine which +engine (or engines) to use. + +The logic for choosing which engine to execute is in src/exec.rs and is +documented on the Exec type. Exec values contain regular expression Programs +(defined in src/prog.rs), which contain all the necessary tidbits for actually +executing a regular expression on search text. + +For the most part, the execution logic is straight-forward and follows the +limitations of each engine described above pretty faithfully. The hairiest +part of src/exec.rs by far is the execution of the lazy DFA, since it requires +a forwards and backwards search, and then falls back to either the Pike VM or +backtracking if the caller requested capture locations. + +The Exec type also contains mutable scratch space for each type of matching +engine. This scratch space is used during search (for example, for the lazy +DFA, it contains compiled states that are reused on subsequent searches). + +### Programs + +A regular expression program is essentially a sequence of opcodes produced by +the compiler plus various facts about the regular expression (such as whether +it is anchored, its capture names, etc.). + +### The regex! macro + +The `regex!` macro no longer exists. It was developed in a bygone era as a +compiler plugin during the infancy of the regex crate. Back then, then only +matching engine in the crate was the Pike VM. The `regex!` macro was, itself, +also a Pike VM. The only advantages it offered over the dynamic Pike VM that +was built at runtime were the following: + + 1. Syntax checking was done at compile time. Your Rust program wouldn't + compile if your regex didn't compile. + 2. Reduction of overhead that was proportional to the size of the regex. + For the most part, this overhead consisted of heap allocation, which + was nearly eliminated in the compiler plugin. + +The main takeaway here is that the compiler plugin was a marginally faster +version of a slow regex engine. As the regex crate evolved, it grew other regex +engines (DFA, bounded backtracker) and sophisticated literal optimizations. +The regex macro didn't keep pace, and it therefore became (dramatically) slower +than the dynamic engines. The only reason left to use it was for the compile +time guarantee that your regex is correct. Fortunately, Clippy (the Rust lint +tool) has a lint that checks your regular expression validity, which mostly +replaces that use case. + +Additionally, the regex compiler plugin stopped receiving maintenance. Nobody +complained. At that point, it seemed prudent to just remove it. + +Will a compiler plugin be brought back? The future is murky, but there is +definitely an opportunity there to build something that is faster than the +dynamic engines in some cases. But it will be challenging! As of now, there +are no plans to work on this. + + +## Testing + +A key aspect of any mature regex library is its test suite. A subset of the +tests in this library come from Glenn Fowler's AT&T test suite (its online +presence seems gone at the time of writing). The source of the test suite is +located in src/testdata. The scripts/regex-match-tests.py takes the test suite +in src/testdata and generates tests/matches.rs. + +There are also many other manually crafted tests and regression tests in +tests/tests.rs. Some of these tests were taken from RE2. + +The biggest source of complexity in the tests is related to answering this +question: how can we reuse the tests to check all of our matching engines? One +approach would have been to encode every test into some kind of format (like +the AT&T test suite) and code generate tests for each matching engine. The +approach we use in this library is to create a Cargo.toml entry point for each +matching engine we want to test. The entry points are: + +* `tests/test_default.rs` - tests `Regex::new` +* `tests/test_default_bytes.rs` - tests `bytes::Regex::new` +* `tests/test_nfa.rs` - tests `Regex::new`, forced to use the NFA + algorithm on every regex. +* `tests/test_nfa_bytes.rs` - tests `Regex::new`, forced to use the NFA + algorithm on every regex and use *arbitrary* byte based programs. +* `tests/test_nfa_utf8bytes.rs` - tests `Regex::new`, forced to use the NFA + algorithm on every regex and use *UTF-8* byte based programs. +* `tests/test_backtrack.rs` - tests `Regex::new`, forced to use + backtracking on every regex. +* `tests/test_backtrack_bytes.rs` - tests `Regex::new`, forced to use + backtracking on every regex and use *arbitrary* byte based programs. +* `tests/test_backtrack_utf8bytes.rs` - tests `Regex::new`, forced to use + backtracking on every regex and use *UTF-8* byte based programs. +* `tests/test_crates_regex.rs` - tests to make sure that all of the + backends behave in the same way against a number of quickcheck + generated random inputs. These tests need to be enabled through + the `RUST_REGEX_RANDOM_TEST` environment variable (see + below). + +The lazy DFA and pure literal engines are absent from this list because +they cannot be used on every regular expression. Instead, we rely on +`tests/test_dynamic.rs` to test the lazy DFA and literal engines when possible. + +Since the tests are repeated several times, and because `cargo test` runs all +entry points, it can take a while to compile everything. To reduce compile +times slightly, try using `cargo test --test default`, which will only use the +`tests/test_default.rs` entry point. + +The random testing takes quite a while, so it is not enabled by default. +In order to run the random testing you can set the +`RUST_REGEX_RANDOM_TEST` environment variable to anything before +invoking `cargo test`. Note that this variable is inspected at compile +time, so if the tests don't seem to be running, you may need to run +`cargo clean`. + +## Benchmarking + +The benchmarking in this crate is made up of many micro-benchmarks. Currently, +there are two primary sets of benchmarks: the benchmarks that were adopted +at this library's inception (in `bench/src/misc.rs`) and a newer set of +benchmarks meant to test various optimizations. Specifically, the latter set +contain some analysis and are in `bench/src/sherlock.rs`. Also, the latter +set are all executed on the same lengthy input whereas the former benchmarks +are executed on strings of varying length. + +There is also a smattering of benchmarks for parsing and compilation. + +Benchmarks are in a separate crate so that its dependencies can be managed +separately from the main regex crate. + +Benchmarking follows a similarly wonky setup as tests. There are multiple entry +points: + +* `bench_rust.rs` - benchmarks `Regex::new` +* `bench_rust_bytes.rs` benchmarks `bytes::Regex::new` +* `bench_pcre.rs` - benchmarks PCRE +* `bench_onig.rs` - benchmarks Oniguruma + +The PCRE and Oniguruma benchmarks exist as a comparison point to a mature +regular expression library. In general, this regex library compares favorably +(there are even a few benchmarks that PCRE simply runs too slowly on or +outright can't execute at all). I would love to add other regular expression +library benchmarks (especially RE2). + +If you're hacking on one of the matching engines and just want to see +benchmarks, then all you need to run is: + + $ ./bench/run rust + +If you want to compare your results with older benchmarks, then try: + + $ ./bench/run rust | tee old + $ ... make it faster + $ ./bench/run rust | tee new + $ cargo benchcmp old new --improvements + +The `cargo-benchcmp` utility is available here: +https://github.com/BurntSushi/cargo-benchcmp + +The `./bench/run` utility can run benchmarks for PCRE and Oniguruma too. See +`./bench/bench --help`. + +## Dev Docs + +When digging your teeth into the codebase for the first time, the +crate documentation can be a great resource. By default `rustdoc` +will strip out all documentation of private crate members in an +effort to help consumers of the crate focus on the *interface* +without having to concern themselves with the *implementation*. +Normally this is a great thing, but if you want to start hacking +on regex internals it is not what you want. Many of the private members +of this crate are well documented with rustdoc style comments, and +it would be a shame to miss out on the opportunity that presents. +You can generate the private docs with: + +``` +$ rustdoc --crate-name docs src/lib.rs -o target/doc -L target/debug/deps --no-defaults --passes collapse-docs --passes unindent-comments +``` + +Then just point your browser at `target/doc/regex/index.html`. + +See https://github.com/rust-lang/rust/issues/15347 for more info +about generating developer docs for internal use. diff --git a/regex/LICENSE-APACHE b/regex/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/regex/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/regex/LICENSE-MIT b/regex/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/regex/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/regex/PERFORMANCE.md b/regex/PERFORMANCE.md new file mode 100644 index 000000000..b4aeb89c1 --- /dev/null +++ b/regex/PERFORMANCE.md @@ -0,0 +1,279 @@ +Your friendly guide to understanding the performance characteristics of this +crate. + +This guide assumes some familiarity with the public API of this crate, which +can be found here: https://docs.rs/regex + +## Theory vs. Practice + +One of the design goals of this crate is to provide worst case linear time +behavior with respect to the text searched using finite state automata. This +means that, *in theory*, the performance of this crate is much better than most +regex implementations, which typically use backtracking which has worst case +exponential time. + +For example, try opening a Python interpreter and typing this: + + >>> import re + >>> re.search('(a*)*c', 'a' * 30).span() + +I'll wait. + +At some point, you'll figure out that it won't terminate any time soon. ^C it. + +The promise of this crate is that *this pathological behavior can't happen*. + +With that said, just because we have protected ourselves against worst case +exponential behavior doesn't mean we are immune from large constant factors +or places where the current regex engine isn't quite optimal. This guide will +detail those cases and provide guidance on how to avoid them, among other +bits of general advice. + +## Thou Shalt Not Compile Regular Expressions In A Loop + +**Advice**: Use `lazy_static` to amortize the cost of `Regex` compilation. + +Don't do it unless you really don't mind paying for it. Compiling a regular +expression in this crate is quite expensive. It is conceivable that it may get +faster some day, but I wouldn't hold out hope for, say, an order of magnitude +improvement. In particular, compilation can take any where from a few dozen +microseconds to a few dozen milliseconds. Yes, milliseconds. Unicode character +classes, in particular, have the largest impact on compilation performance. At +the time of writing, for example, `\pL{100}` takes around 44ms to compile. This +is because `\pL` corresponds to every letter in Unicode and compilation must +turn it into a proper automaton that decodes a subset of UTF-8 which +corresponds to those letters. Compilation also spends some cycles shrinking the +size of the automaton. + +This means that in order to realize efficient regex matching, one must +*amortize the cost of compilation*. Trivially, if a call to `is_match` is +inside a loop, then make sure your call to `Regex::new` is *outside* that loop. + +In many programming languages, regular expressions can be conveniently defined +and compiled in a global scope, and code can reach out and use them as if +they were global static variables. In Rust, there is really no concept of +life-before-main, and therefore, one cannot utter this: + + static MY_REGEX: Regex = Regex::new("...").unwrap(); + +Unfortunately, this would seem to imply that one must pass `Regex` objects +around to everywhere they are used, which can be especially painful depending +on how your program is structured. Thankfully, the +[`lazy_static`](https://crates.io/crates/lazy_static) +crate provides an answer that works well: + + #[macro_use] extern crate lazy_static; + extern crate regex; + + use regex::Regex; + + fn some_helper_function(text: &str) -> bool { + lazy_static! { + static ref MY_REGEX: Regex = Regex::new("...").unwrap(); + } + MY_REGEX.is_match(text) + } + +In other words, the `lazy_static!` macro enables us to define a `Regex` *as if* +it were a global static value. What is actually happening under the covers is +that the code inside the macro (i.e., `Regex::new(...)`) is run on *first use* +of `MY_REGEX` via a `Deref` impl. The implementation is admittedly magical, but +it's self contained and everything works exactly as you expect. In particular, +`MY_REGEX` can be used from multiple threads without wrapping it in an `Arc` or +a `Mutex`. On that note... + +## Using a regex from multiple threads + +**Advice**: The performance impact from using a `Regex` from multiple threads +is likely negligible. If necessary, clone the `Regex` so that each thread gets +its own copy. Cloning a regex does not incur any additional memory overhead +than what would be used by using a `Regex` from multiple threads +simultaneously. *Its only cost is ergonomics.* + +It is supported and encouraged to define your regexes using `lazy_static!` as +if they were global static values, and then use them to search text from +multiple threads simultaneously. + +One might imagine that this is possible because a `Regex` represents a +*compiled* program, so that any allocation or mutation is already done, and is +therefore read-only. Unfortunately, this is not true. Each type of search +strategy in this crate requires some kind of mutable scratch space to use +*during search*. For example, when executing a DFA, its states are computed +lazily and reused on subsequent searches. Those states go into that mutable +scratch space. + +The mutable scratch space is an implementation detail, and in general, its +mutation should not be observable from users of this crate. Therefore, it uses +interior mutability. This implies that `Regex` can either only be used from one +thread, or it must do some sort of synchronization. Either choice is +reasonable, but this crate chooses the latter, in particular because it is +ergonomic and makes use with `lazy_static!` straight forward. + +Synchronization implies *some* amount of overhead. When a `Regex` is used from +a single thread, this overhead is negligible. When a `Regex` is used from +multiple threads simultaneously, it is possible for the overhead of +synchronization from contention to impact performance. The specific cases where +contention may happen is if you are calling any of these methods repeatedly +from multiple threads simultaneously: + +* shortest_match +* is_match +* find +* captures + +In particular, every invocation of one of these methods must synchronize with +other threads to retrieve its mutable scratch space before searching can start. +If, however, you are using one of these methods: + +* find_iter +* captures_iter + +Then you may not suffer from contention since the cost of synchronization is +amortized on *construction of the iterator*. That is, the mutable scratch space +is obtained when the iterator is created and retained throughout its lifetime. + +## Only ask for what you need + +**Advice**: Prefer in this order: `is_match`, `find`, `captures`. + +There are three primary search methods on a `Regex`: + +* is_match +* find +* captures + +In general, these are ordered from fastest to slowest. + +`is_match` is fastest because it doesn't actually need to find the start or the +end of the leftmost-first match. It can quit immediately after it knows there +is a match. For example, given the regex `a+` and the haystack, `aaaaa`, the +search will quit after examing the first byte. + +In constrast, `find` must return both the start and end location of the +leftmost-first match. It can use the DFA matcher for this, but must run it +forwards once to find the end of the match *and then run it backwards* to find +the start of the match. The two scans and the cost of finding the real end of +the leftmost-first match make this more expensive than `is_match`. + +`captures` is the most expensive of them all because it must do what `find` +does, and then run either the bounded backtracker or the Pike VM to fill in the +capture group locations. Both of these are simulations of an NFA, which must +spend a lot of time shuffling states around. The DFA limits the performance hit +somewhat by restricting the amount of text that must be searched via an NFA +simulation. + +One other method not mentioned is `shortest_match`. This method has precisely +the same performance characteristics as `is_match`, except it will return the +end location of when it discovered a match. For example, given the regex `a+` +and the haystack `aaaaa`, `shortest_match` may return `1` as opposed to `5`, +the latter of which being the correct end location of the leftmost-first match. + +## Literals in your regex may make it faster + +**Advice**: Literals can reduce the work that the regex engine needs to do. Use +them if you can, especially as prefixes. + +In particular, if your regex starts with a prefix literal, the prefix is +quickly searched before entering the (much slower) regex engine. For example, +given the regex `foo\w+`, the literal `foo` will be searched for using +Boyer-Moore. If there's no match, then no regex engine is ever used. Only when +there's a match is the regex engine invoked at the location of the match, which +effectively permits the regex engine to skip large portions of a haystack. +If a regex is comprised entirely of literals (possibly more than one), then +it's possible that the regex engine can be avoided entirely even when there's a +match. + +When one literal is found, Boyer-Moore is used. When multiple literals are +found, then an optimized version of Aho-Corasick is used. + +This optimization is in particular extended quite a bit in this crate. Here are +a few examples of regexes that get literal prefixes detected: + +* `(foo|bar)` detects `foo` and `bar` +* `(a|b)c` detects `ac` and `bc` +* `[ab]foo[yz]` detects `afooy`, `afooz`, `bfooy` and `bfooz` +* `a?b` detects `a` and `b` +* `a*b` detects `a` and `b` +* `(ab){3,6}` detects `ababab` + +Literals in anchored regexes can also be used for detecting non-matches very +quickly. For example, `^foo\w+` and `\w+foo$` may be able to detect a non-match +just by examing the first (or last) three bytes of the haystack. + +## Unicode word boundaries may prevent the DFA from being used + +**Advice**: In most cases, `\b` should work well. If not, use `(?-u:\b)` +instead of `\b` if you care about consistent performance more than correctness. + +It's a sad state of the current implementation. At the moment, the DFA will try +to interpret Unicode word boundaries as if they were ASCII word boundaries. +If the DFA comes across any non-ASCII byte, it will quit and fall back to an +alternative matching engine that can handle Unicode word boundaries correctly. +The alternate matching engine is generally quite a bit slower (perhaps by an +order of magnitude). If necessary, this can be ameliorated in two ways. + +The first way is to add some number of literal prefixes to your regular +expression. Even though the DFA may not be used, specialized routines will +still kick in to find prefix literals quickly, which limits how much work the +NFA simulation will need to do. + +The second way is to give up on Unicode and use an ASCII word boundary instead. +One can use an ASCII word boundary by disabling Unicode support. That is, +instead of using `\b`, use `(?-u:\b)`. Namely, given the regex `\b.+\b`, it +can be transformed into a regex that uses the DFA with `(?-u:\b).+(?-u:\b)`. It +is important to limit the scope of disabling the `u` flag, since it might lead +to a syntax error if the regex could match arbitrary bytes. For example, if one +wrote `(?-u)\b.+\b`, then a syntax error would be returned because `.` matches +any *byte* when the Unicode flag is disabled. + +The second way isn't appreciably different than just using a Unicode word +boundary in the first place, since the DFA will speculatively interpret it as +an ASCII word boundary anyway. The key difference is that if an ASCII word +boundary is used explicitly, then the DFA won't quit in the presence of +non-ASCII UTF-8 bytes. This results in giving up correctness in exchange for +more consistent performance. + +N.B. When using `bytes::Regex`, Unicode support is disabled by default, so one +can simply write `\b` to get an ASCII word boundary. + +## Excessive counting can lead to exponential state blow up in the DFA + +**Advice**: Don't write regexes that cause DFA state blow up if you care about +match performance. + +Wait, didn't I say that this crate guards against exponential worst cases? +Well, it turns out that the process of converting an NFA to a DFA can lead to +an exponential blow up in the number of states. This crate specifically guards +against exponential blow up by doing two things: + +1. The DFA is computed lazily. That is, a state in the DFA only exists in + memory if it is visited. In particular, the lazy DFA guarantees that *at + most* one state is created for every byte of input. This, on its own, + guarantees linear time complexity. +2. Of course, creating a new state for *every* byte of input means that search + will go incredibly slow because of very large constant factors. On top of + that, creating a state for every byte in a large haystack could result in + exorbitant memory usage. To ameliorate this, the DFA bounds the number of + states it can store. Once it reaches its limit, it flushes its cache. This + prevents reuse of states that it already computed. If the cache is flushed + too frequently, then the DFA will give up and execution will fall back to + one of the NFA simulations. + +In effect, this crate will detect exponential state blow up and fall back to +a search routine with fixed memory requirements. This does, however, mean that +searching will be much slower than one might expect. Regexes that rely on +counting in particular are strong aggravators of this behavior. For example, +matching `[01]*1[01]{20}$` against a random sequence of `0`s and `1`s. + +In the future, it may be possible to increase the bound that the DFA uses, +which would allow the caller to choose how much memory they're willing to +spend. + +## Resist the temptation to "optimize" regexes + +**Advice**: This ain't a backtracking engine. + +An entire book was written on how to optimize Perl-style regular expressions. +Most of those techniques are not applicable for this library. For example, +there is no problem with using non-greedy matching or having lots of +alternations in your regex. diff --git a/regex/README.md b/regex/README.md new file mode 100644 index 000000000..f28123459 --- /dev/null +++ b/regex/README.md @@ -0,0 +1,231 @@ +regex +===== +A Rust library for parsing, compiling, and executing regular expressions. Its +syntax is similar to Perl-style regular expressions, but lacks a few features +like look around and backreferences. In exchange, all searches execute in +linear time with respect to the size of the regular expression and search text. +Much of the syntax and implementation is inspired +by [RE2](https://github.com/google/re2). + +[![Build Status](https://travis-ci.com/rust-lang/regex.svg?branch=master)](https://travis-ci.com/rust-lang/regex) +[![Build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/regex?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/regex) +[![Coverage Status](https://coveralls.io/repos/github/rust-lang/regex/badge.svg?branch=master)](https://coveralls.io/github/rust-lang/regex?branch=master) +[![](https://meritbadge.herokuapp.com/regex)](https://crates.io/crates/regex) +[![Rust](https://img.shields.io/badge/rust-1.24.1%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/regex) + +### Documentation + +[Module documentation with examples](https://docs.rs/regex). +The module documentation also includes a comprehensive description of the +syntax supported. + +Documentation with examples for the various matching functions and iterators +can be found on the +[`Regex` type](https://docs.rs/regex/*/regex/struct.Regex.html). + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +regex = "1" +``` + +and this to your crate root (if you're using Rust 2015): + +```rust +extern crate regex; +``` + +Here's a simple example that matches a date in YYYY-MM-DD format and prints the +year, month and day: + +```rust +use regex::Regex; + +fn main() { + let re = Regex::new(r"(?x) +(?P<year>\d{4}) # the year +- +(?P<month>\d{2}) # the month +- +(?P<day>\d{2}) # the day +").unwrap(); + let caps = re.captures("2010-03-14").unwrap(); + + assert_eq!("2010", &caps["year"]); + assert_eq!("03", &caps["month"]); + assert_eq!("14", &caps["day"]); +} +``` + +If you have lots of dates in text that you'd like to iterate over, then it's +easy to adapt the above example with an iterator: + +```rust +use regex::Regex; + +const TO_SEARCH: &'static str = " +On 2010-03-14, foo happened. On 2014-10-14, bar happened. +"; + +fn main() { + let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap(); + + for caps in re.captures_iter(TO_SEARCH) { + // Note that all of the unwraps are actually OK for this regex + // because the only way for the regex to match is if all of the + // capture groups match. This is not true in general though! + println!("year: {}, month: {}, day: {}", + caps.get(1).unwrap().as_str(), + caps.get(2).unwrap().as_str(), + caps.get(3).unwrap().as_str()); + } +} +``` + +This example outputs: + +``` +year: 2010, month: 03, day: 14 +year: 2014, month: 10, day: 14 +``` + +### Usage: Avoid compiling the same regex in a loop + +It is an anti-pattern to compile the same regular expression in a loop since +compilation is typically expensive. (It takes anywhere from a few microseconds +to a few **milliseconds** depending on the size of the regex.) Not only is +compilation itself expensive, but this also prevents optimizations that reuse +allocations internally to the matching engines. + +In Rust, it can sometimes be a pain to pass regular expressions around if +they're used from inside a helper function. Instead, we recommend using the +[`lazy_static`](https://crates.io/crates/lazy_static) crate to ensure that +regular expressions are compiled exactly once. + +For example: + +```rust +use regex::Regex; + +fn some_helper_function(text: &str) -> bool { + lazy_static! { + static ref RE: Regex = Regex::new("...").unwrap(); + } + RE.is_match(text) +} +``` + +Specifically, in this example, the regex will be compiled when it is used for +the first time. On subsequent uses, it will reuse the previous compilation. + +### Usage: match regular expressions on `&[u8]` + +The main API of this crate (`regex::Regex`) requires the caller to pass a +`&str` for searching. In Rust, an `&str` is required to be valid UTF-8, which +means the main API can't be used for searching arbitrary bytes. + +To match on arbitrary bytes, use the `regex::bytes::Regex` API. The API +is identical to the main API, except that it takes an `&[u8]` to search +on instead of an `&str`. By default, `.` will match any *byte* using +`regex::bytes::Regex`, while `.` will match any *UTF-8 encoded Unicode scalar +value* using the main API. + +This example shows how to find all null-terminated strings in a slice of bytes: + +```rust +use regex::bytes::Regex; + +let re = Regex::new(r"(?P<cstr>[^\x00]+)\x00").unwrap(); +let text = b"foo\x00bar\x00baz\x00"; + +// Extract all of the strings without the null terminator from each match. +// The unwrap is OK here since a match requires the `cstr` capture to match. +let cstrs: Vec<&[u8]> = + re.captures_iter(text) + .map(|c| c.name("cstr").unwrap().as_bytes()) + .collect(); +assert_eq!(vec![&b"foo"[..], &b"bar"[..], &b"baz"[..]], cstrs); +``` + +Notice here that the `[^\x00]+` will match any *byte* except for `NUL`. When +using the main API, `[^\x00]+` would instead match any valid UTF-8 sequence +except for `NUL`. + +### Usage: match multiple regular expressions simultaneously + +This demonstrates how to use a `RegexSet` to match multiple (possibly +overlapping) regular expressions in a single scan of the search text: + +```rust +use regex::RegexSet; + +let set = RegexSet::new(&[ + r"\w+", + r"\d+", + r"\pL+", + r"foo", + r"bar", + r"barfoo", + r"foobar", +]).unwrap(); + +// Iterate over and collect all of the matches. +let matches: Vec<_> = set.matches("foobar").into_iter().collect(); +assert_eq!(matches, vec![0, 2, 3, 4, 6]); + +// You can also test whether a particular regex matched: +let matches = set.matches("foobar"); +assert!(!matches.matched(5)); +assert!(matches.matched(6)); +``` + +### Usage: enable SIMD optimizations + +SIMD optimizations are enabled automatically on Rust stable 1.27 and newer. +For nightly versions of Rust, this requires a recent version with the SIMD +features stabilized. + + +### Usage: a regular expression parser + +This repository contains a crate that provides a well tested regular expression +parser, abstract syntax and a high-level intermediate representation for +convenient analysis. It provides no facilities for compilation or execution. +This may be useful if you're implementing your own regex engine or otherwise +need to do analysis on the syntax of a regular expression. It is otherwise not +recommended for general use. + +[Documentation `regex-syntax`.](https://docs.rs/regex-syntax) + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.24.1`. + +The current **tentative** policy is that the minimum Rust version required +to use this crate can be increased in minor version updates. For example, if +regex 1.0 requires Rust 1.20.0, then regex 1.0.z for all values of `z` will +also require Rust 1.20.0 or newer. However, regex 1.y for `y > 0` may require a +newer minimum version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + +### License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +The data in `regex-syntax/src/unicode_tables/` is licensed under the Unicode +License Agreement +([LICENSE-UNICODE](http://www.unicode.org/copyright.html#License)). diff --git a/regex/UNICODE.md b/regex/UNICODE.md new file mode 100644 index 000000000..18fa9b103 --- /dev/null +++ b/regex/UNICODE.md @@ -0,0 +1,259 @@ +# Unicode conformance + +This document describes the regex crate's conformance to Unicode's +[UTS#18](http://unicode.org/reports/tr18/) +report, which lays out 3 levels of support: Basic, Extended and Tailored. + +Full support for Level 1 ("Basic Unicode Support") is provided with two +exceptions: + +1. Line boundaries are not Unicode aware. Namely, only the `\n` + (`END OF LINE`) character is recognized as a line boundary. +2. The compatibility properties specified by + [RL1.2a](http://unicode.org/reports/tr18/#RL1.2a) + are ASCII-only definitions. + +Little to no support is provided for either Level 2 or Level 3. For the most +part, this is because the features are either complex/hard to implement, or at +the very least, very difficult to implement without sacrificing performance. +For example, tackling canonical equivalence such that matching worked as one +would expect regardless of normalization form would be a significant +undertaking. This is at least partially a result of the fact that this regex +engine is based on finite automata, which admits less flexibility normally +associated with backtracking implementations. + + +## RL1.1 Hex Notation + +[UTS#18 RL1.1](https://unicode.org/reports/tr18/#Hex_notation) + +Hex Notation refers to the ability to specify a Unicode code point in a regular +expression via its hexadecimal code point representation. This is useful in +environments that have poor Unicode font rendering or if you need to express a +code point that is not normally displayable. All forms of hexadecimal notation +are supported + + \x7F hex character code (exactly two digits) + \x{10FFFF} any hex character code corresponding to a Unicode code point + \u007F hex character code (exactly four digits) + \u{7F} any hex character code corresponding to a Unicode code point + \U0000007F hex character code (exactly eight digits) + \U{7F} any hex character code corresponding to a Unicode code point + +Briefly, the `\x{...}`, `\u{...}` and `\U{...}` are all exactly equivalent ways +of expressing hexadecimal code points. Any number of digits can be written +within the brackets. In contrast, `\xNN`, `\uNNNN`, `\UNNNNNNNN` are all +fixed-width variants of the same idea. + +Note that when Unicode mode is disabled, any non-ASCII Unicode codepoint is +banned. Additionally, the `\xNN` syntax represents arbitrary bytes when Unicode +mode is disabled. That is, the regex `\xFF` matches the Unicode codepoint +U+00FF (encoded as `\xC3\xBF` in UTF-8) while the regex `(?-u)\xFF` matches +the literal byte `\xFF`. + + +## RL1.2 Properties + +[UTS#18 RL1.2](https://unicode.org/reports/tr18/#Categories) + +Full support for Unicode property syntax is provided. Unicode properties +provide a convenient way to construct character classes of groups of code +points specified by Unicode. The regex crate does not provide exhaustive +support, but covers a useful subset. In particular: + +* [General categories](http://unicode.org/reports/tr18/#General_Category_Property) +* [Scripts and Script Extensions](http://unicode.org/reports/tr18/#Script_Property) +* [Age](http://unicode.org/reports/tr18/#Age) +* A smattering of boolean properties, including all of those specified by + [RL1.2](http://unicode.org/reports/tr18/#RL1.2) explicitly. + +In all cases, property name and value abbreviations are supported, and all +names/values are matched loosely without regard for case, whitespace or +underscores. Property name aliases can be found in Unicode's +[`PropertyAliases.txt`](http://www.unicode.org/Public/UCD/latest/ucd/PropertyAliases.txt) +file, while property value aliases can be found in Unicode's +[`PropertyValueAliases.txt`](http://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt) +file. + +The syntax supported is also consistent with the UTS#18 recommendation: + +* `\p{Greek}` selects the `Greek` script. Equivalent expressions follow: + `\p{sc:Greek}`, `\p{Script:Greek}`, `\p{Sc=Greek}`, `\p{script=Greek}`, + `\P{sc!=Greek}`. Similarly for `General_Category` (or `gc` for short) and + `Script_Extensions` (or `scx` for short). +* `\p{age:3.2}` selects all code points in Unicode 3.2. +* `\p{Alphabetic}` selects the "alphabetic" property and can be abbreviated + via `\p{alpha}` (for example). +* Single letter variants for properties with single letter abbreviations. + For example, `\p{Letter}` can be equivalently written as `\pL`. + +The following is a list of all properties supported by the regex crate (starred +properties correspond to properties required by RL1.2): + +* `General_Category` \* (including `Any`, `ASCII` and `Assigned`) +* `Script` \* +* `Script_Extensions` \* +* `Age` +* `ASCII_Hex_Digit` +* `Alphabetic` \* +* `Bidi_Control` +* `Case_Ignorable` +* `Cased` +* `Changes_When_Casefolded` +* `Changes_When_Casemapped` +* `Changes_When_Lowercased` +* `Changes_When_Titlecased` +* `Changes_When_Uppercased` +* `Dash` +* `Default_Ignorable_Code_Point` \* +* `Deprecated` +* `Diacritic` +* `Emoji` +* `Emoji_Presentation` +* `Emoji_Modifier` +* `Emoji_Modifier_Base` +* `Emoji_Component` +* `Extended_Pictographic` +* `Extender` +* `Grapheme_Base` +* `Grapheme_Cluster_Break` +* `Grapheme_Extend` +* `Hex_Digit` +* `IDS_Binary_Operator` +* `IDS_Trinary_Operator` +* `ID_Continue` +* `ID_Start` +* `Join_Control` +* `Logical_Order_Exception` +* `Lowercase` \* +* `Math` +* `Noncharacter_Code_Point` \* +* `Pattern_Syntax` +* `Pattern_White_Space` +* `Prepended_Concatenation_Mark` +* `Quotation_Mark` +* `Radical` +* `Regional_Indicator` +* `Sentence_Break` +* `Sentence_Terminal` +* `Soft_Dotted` +* `Terminal_Punctuation` +* `Unified_Ideograph` +* `Uppercase` \* +* `Variation_Selector` +* `White_Space` \* +* `Word_Break` +* `XID_Continue` +* `XID_Start` + + +## RL1.2a Compatibility Properties + +[UTS#18 RL1.2a](http://unicode.org/reports/tr18/#RL1.2a) + +The regex crate only provides ASCII definitions of the +[compatibility properties documented in UTS#18 Annex C](http://unicode.org/reports/tr18/#Compatibility_Properties) +(sans the `\X` class, for matching grapheme clusters, which isn't provided +at all). This is because it seems to be consistent with most other regular +expression engines, and in particular, because these are often referred to as +"ASCII" or "POSIX" character classes. + +Note that the `\w`, `\s` and `\d` character classes **are** Unicode aware. +Their traditional ASCII definition can be used by disabling Unicode. That is, +`[[:word:]]` and `(?-u)\w` are equivalent. + + +## RL1.3 Subtraction and Intersection + +[UTS#18 RL1.3](http://unicode.org/reports/tr18/#Subtraction_and_Intersection) + +The regex crate provides full support for nested character classes, along with +union, intersection (`&&`), difference (`--`) and symmetric difference (`~~`) +operations on arbitrary character classes. + +For example, to match all non-ASCII letters, you could use either +`[\p{Letter}--\p{Ascii}]` (difference) or `[\p{Letter}&&[^\p{Ascii}]]` +(intersecting the negation). + + +## RL1.4 Simple Word Boundaries + +[UTS#18 RL1.4](http://unicode.org/reports/tr18/#Simple_Word_Boundaries) + +The regex crate provides basic Unicode aware word boundary assertions. A word +boundary assertion can be written as `\b`, or `\B` as its negation. A word +boundary negation corresponds to a zero-width match, where its adjacent +characters correspond to word and non-word, or non-word and word characters. + +Conformance in this case chooses to define word character in the same way that +the `\w` character class is defined: a code point that is a member of one of +the following classes: + +* `\p{Alphabetic}` +* `\p{Join_Control}` +* `\p{gc:Mark}` +* `\p{gc:Decimal_Number}` +* `\p{gc:Connector_Punctuation}` + +In particular, this differs slightly from the +[prescription given in RL1.4](http://unicode.org/reports/tr18/#Simple_Word_Boundaries) +but is permissible according to +[UTS#18 Annex C](http://unicode.org/reports/tr18/#Compatibility_Properties). +Namely, it is convenient and simpler to have `\w` and `\b` be in sync with +one another. + +Finally, Unicode word boundaries can be disabled, which will cause ASCII word +boundaries to be used instead. That is, `\b` is a Unicode word boundary while +`(?-u)\b` is an ASCII-only word boundary. This can occasionally be beneficial +if performance is important, since the implementation of Unicode word +boundaries is currently sub-optimal on non-ASCII text. + + +## RL1.5 Simple Loose Matches + +[UTS#18 RL1.5](http://unicode.org/reports/tr18/#Simple_Loose_Matches) + +The regex crate provides full support for case insensitive matching in +accordance with RL1.5. That is, it uses the "simple" case folding mapping. The +"simple" mapping was chosen because of a key convenient property: every +"simple" mapping is a mapping from exactly one code point to exactly one other +code point. This makes case insensitive matching of character classes, for +example, straight-forward to implement. + +When case insensitive mode is enabled (e.g., `(?i)[a]` is equivalent to `a|A`), +then all characters classes are case folded as well. + + +## RL1.6 Line Boundaries + +[UTS#18 RL1.6](http://unicode.org/reports/tr18/#Line_Boundaries) + +The regex crate only provides support for recognizing the `\n` (`END OF LINE`) +character as a line boundary. This choice was made mostly for implementation +convenience, and to avoid performance cliffs that Unicode word boundaries are +subject to. + +Ideally, it would be nice to at least support `\r\n` as a line boundary as +well, and in theory, this could be done efficiently. + + +## RL1.7 Code Points + +[UTS#18 RL1.7](http://unicode.org/reports/tr18/#Supplementary_Characters) + +The regex crate provides full support for Unicode code point matching. Namely, +the fundamental atom of any match is always a single code point. + +Given Rust's strong ties to UTF-8, the following guarantees are also provided: + +* All matches are reported on valid UTF-8 code unit boundaries. That is, any + match range returned by the public regex API is guaranteed to successfully + slice the string that was searched. +* By consequence of the above, it is impossible to match surrogode code points. + No support for UTF-16 is provided, so this is never necessary. + +Note that when Unicode mode is disabled, the fundamental atom of matching is +no longer a code point but a single byte. When Unicode mode is disabled, many +Unicode features are disabled as well. For example, `(?-u)\pL` is not a valid +regex but `\pL(?-u)\xFF` (matches any Unicode `Letter` followed by the literal +byte `\xFF`) is, for example. diff --git a/regex/build.rs b/regex/build.rs new file mode 100644 index 000000000..f45e3c7fc --- /dev/null +++ b/regex/build.rs @@ -0,0 +1,89 @@ +use std::env; +use std::ffi::OsString; +use std::process::Command; + +fn main() { + let version = match Version::read() { + Ok(version) => version, + Err(err) => { + eprintln!("failed to parse `rustc --version`: {}", err); + return; + } + }; + enable_simd_optimizations(version); +} + +fn enable_simd_optimizations(version: Version) { + // We don't activate SIMD optimizations these if we've explicitly disabled + // them. Disabling auto optimizations is intended for use in tests, so that + // we can reliably test fallback implementations. + if env::var_os("CARGO_CFG_REGEX_DISABLE_AUTO_OPTIMIZATIONS").is_some() { + return; + } + if version < (Version { major: 1, minor: 27, patch: 0 }) { + return; + } + + println!("cargo:rustc-cfg=regex_runtime_teddy_ssse3"); + println!("cargo:rustc-cfg=regex_runtime_teddy_avx2"); +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +struct Version { + major: u32, + minor: u32, + patch: u32, +} + +impl Version { + fn read() -> Result<Version, String> { + let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc")); + let output = Command::new(&rustc) + .arg("--version") + .output() + .unwrap() + .stdout; + Version::parse(&String::from_utf8(output).unwrap()) + } + + fn parse(mut s: &str) -> Result<Version, String> { + if !s.starts_with("rustc ") { + return Err(format!("unrecognized version string: {}", s)); + } + s = &s["rustc ".len()..]; + + let parts: Vec<&str> = s.split(".").collect(); + if parts.len() < 3 { + return Err(format!("not enough version parts: {:?}", parts)); + } + + let mut num = String::new(); + for c in parts[0].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let major = num.parse::<u32>().map_err(|e| e.to_string())?; + + num.clear(); + for c in parts[1].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let minor = num.parse::<u32>().map_err(|e| e.to_string())?; + + num.clear(); + for c in parts[2].chars() { + if !c.is_digit(10) { + break; + } + num.push(c); + } + let patch = num.parse::<u32>().map_err(|e| e.to_string())?; + + Ok(Version { major, minor, patch }) + } +} diff --git a/regex/examples/regexdna-input.txt b/regex/examples/regexdna-input.txt new file mode 100644 index 000000000..fb2326339 --- /dev/null +++ b/regex/examples/regexdna-input.txt @@ -0,0 +1,1671 @@ +>ONE Homo sapiens alu +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG +GAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATC +GCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGC +GGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGG +TCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAA +AAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAG +GAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACT +CCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCC +TGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAG +ACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGC +GTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGA +ACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGA +CAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCA +CTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCA +ACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCG +CCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG +AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTC +CGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCG +AGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACC +CCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAG +CTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAG +CCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGG +CCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATC +ACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAA +AAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGC +TGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCC +ACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGG +CTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGG +AGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATT +AGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAA +TCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGC +CTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAA +TCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAG +CCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGT +GGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCG +GGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAG +CGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG +GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATG +GTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGT +AATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTT +GCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCT +CAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCG +GGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTC +TCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACT +CGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAG +ATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGG +CGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTG +AGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATA +CAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGG +CAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGC +ACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCAC +GCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTC +GAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCG +GGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCT +TGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGG +CGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCA +GCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGG +CCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGC +GCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGG +CGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGA +CTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGG +CCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAA +ACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCC +CAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGT +GAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAA +AGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGG +ATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTAC +TAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGA +GGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGC +GCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGG +TGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC +AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAA +ATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGA +GAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC +AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTG +TAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGAC +CAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGT +GGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC +CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACA +GAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACT +TTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAAC +ATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCC +TGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAG +GTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCG +TCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAG +GCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCC +GTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCT +ACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCC +GAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCC +GGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCAC +CTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAA +ATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTG +AGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCAC +TGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCT +CACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAG +TTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAG +CCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATC +GCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCT +GGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATC +CCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCC +TGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGG +CGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG +AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCG +AGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGG +AGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGT +GAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAA +TCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGC +AGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCA +AAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGG +CGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTC +TACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCG +GGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGAT +CGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCG +CGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAG +GTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACA +AAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCA +GGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCAC +TCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGC +CTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA +GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGG +CGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTG +AACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCG +ACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGC +ACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCC +AACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGC +GCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCG +GAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACT +CCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCC +GAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAAC +CCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA +GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGA +GCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAG +GCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGAT +CACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTA +AAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGG +CTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGC +CACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTG +GCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAG +GAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAAT +TAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGA +ATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAG +CCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTA +ATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCA +GCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGG +TGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCC +GGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGA +GCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTT +GGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACAT +GGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTG +TAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGT +TGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTC +TCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGC +GGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGT +CTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTAC +TCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGA +GATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGG +GCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCT +GAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT +ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAG +GCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG +CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCA +CGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTT +CGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCC +GGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGC +TTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGG +GCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCC +AGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTG +GCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCG +CGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAG +GCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAG +ACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAG +GCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGA +AACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATC +CCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAG +TGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAA +AAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCG +GATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTA +CTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGG +AGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCG +CGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCG +GTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGT +CAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAA +AATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGG +AGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTC +CAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCT +GTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA +CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG +TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAA +CCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGAC +AGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCAC +TTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAA +CATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGC +CTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGA +GGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCC +GTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGA +GGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCC +CGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGC +TACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGC +CGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGC +CGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCA +CCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA +AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCT +GAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCA +CTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGC +TCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGA +GTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTA +GCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAAT +CGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCC +TGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAAT +CCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGC +CTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTG +GCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGG +GAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGC +GAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG +GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGG +TGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTA +ATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTG +CAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTC +AAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGG +GCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCT +CTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTC +GGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGA +TCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGC +GCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGA +GGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATAC +AAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGC +AGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCA +CTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACG +CCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCG +AGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGG +GCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTT +GAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGC +GACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAG +CACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGC +CAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCG +CGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGC +GGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGAC +TCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGC +CGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAA +CCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCC +AGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTG +AGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA +GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA +TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT +AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG +GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG +CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT +GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA +GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA +TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG +AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA +GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT +AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC +AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG +GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC +CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG +AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT +TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA +TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT +GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG +TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT +CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG +CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG +TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA +CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG +AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG +GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC +TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA +TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA +GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT +GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC +ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT +TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC +CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG +CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG +GGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCC +CAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCT +GGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGC +GCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGA +GGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGA +GACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGA +GGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTG +AAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT +CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCA +GTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAA +AAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGC +GGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCT +ACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGG +GAGGCTGAGGCAGGAGAATC +>TWO IUB ambiguity codes +cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg +tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa +NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt +cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga +gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa +HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca +tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt +tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt +acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct +tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt +gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa +accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt +RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt +tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag +cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg +ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat +actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg +YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa +KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata +aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa +aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg +gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc +tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK +tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt +ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg +ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa +BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt +aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc +tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc +cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac +aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga +tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga +aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD +gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg +ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV +taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa +ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat +gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg +gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa +tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt +tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt +taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca +cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag +aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt +cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt +ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW +attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag +ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa +attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc +tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta +aagacYRcaggattHaYgtKtaatgcVcaataMYacccatatcacgWDBtgaatcBaata +cKcttRaRtgatgaBDacggtaattaaYtataStgVHDtDctgactcaaatKtacaatgc +gYatBtRaDatHaactgtttatatDttttaaaKVccYcaaccNcBcgHaaVcattHctcg +attaaatBtatgcaaaaatYMctSactHatacgaWacattacMBgHttcgaatVaaaaca +BatatVtctgaaaaWtctRacgBMaatSgRgtgtcgactatcRtattaScctaStagKga +DcWgtYtDDWKRgRtHatRtggtcgaHgggcgtattaMgtcagccaBggWVcWctVaaat +tcgNaatcKWagcNaHtgaaaSaaagctcYctttRVtaaaatNtataaccKtaRgtttaM +tgtKaBtRtNaggaSattHatatWactcagtgtactaKctatttgRYYatKatgtccgtR +tttttatttaatatVgKtttgtatgtNtataRatWYNgtRtHggtaaKaYtKSDcatcKg +taaYatcSRctaVtSMWtVtRWHatttagataDtVggacagVcgKWagBgatBtaaagNc +aRtagcataBggactaacacRctKgttaatcctHgDgttKHHagttgttaatgHBtatHc +DaagtVaBaRccctVgtgDtacRHSctaagagcggWYaBtSaKtHBtaaactYacgNKBa +VYgtaacttagtVttcttaatgtBtatMtMtttaattaatBWccatRtttcatagVgMMt +agctStKctaMactacDNYgKYHgaWcgaHgagattacVgtttgtRaSttaWaVgataat +gtgtYtaStattattMtNgWtgttKaccaatagNYttattcgtatHcWtctaaaNVYKKt +tWtggcDtcgaagtNcagatacgcattaagaccWctgcagcttggNSgaNcHggatgtVt +catNtRaaBNcHVagagaaBtaaSggDaatWaatRccaVgggStctDaacataKttKatt +tggacYtattcSatcttagcaatgaVBMcttDattctYaaRgatgcattttNgVHtKcYR +aatRKctgtaaacRatVSagctgtWacBtKVatctgttttKcgtctaaDcaagtatcSat +aWVgcKKataWaYttcccSaatgaaaacccWgcRctWatNcWtBRttYaattataaNgac +acaatagtttVNtataNaYtaatRaVWKtBatKagtaatataDaNaaaaataMtaagaaS +tccBcaatNgaataWtHaNactgtcDtRcYaaVaaaaaDgtttRatctatgHtgttKtga +aNSgatactttcgagWaaatctKaaDaRttgtggKKagcDgataaattgSaacWaVtaNM +acKtcaDaaatttctRaaVcagNacaScRBatatctRatcctaNatWgRtcDcSaWSgtt +RtKaRtMtKaatgttBHcYaaBtgatSgaSWaScMgatNtctcctatttctYtatMatMt +RRtSaattaMtagaaaaStcgVgRttSVaScagtgDtttatcatcatacRcatatDctta +tcatVRtttataaHtattcYtcaaaatactttgVctagtaaYttagatagtSYacKaaac +gaaKtaaatagataatSatatgaaatSgKtaatVtttatcctgKHaatHattagaaccgt +YaaHactRcggSBNgtgctaaBagBttgtRttaaattYtVRaaaattgtaatVatttctc +ttcatgBcVgtgKgaHaaatattYatagWacNctgaaMcgaattStagWaSgtaaKagtt +ttaagaDgatKcctgtaHtcatggKttVDatcaaggtYcgccagNgtgcVttttagagat +gctaccacggggtNttttaSHaNtatNcctcatSaaVgtactgBHtagcaYggYVKNgta +KBcRttgaWatgaatVtagtcgattYgatgtaatttacDacSctgctaaaStttaWMagD +aaatcaVYctccgggcgaVtaaWtStaKMgDtttcaaMtVgBaatccagNaaatcYRMBg +gttWtaaScKttMWtYataRaDBMaDataatHBcacDaaKDactaMgagttDattaHatH +taYatDtattDcRNStgaatattSDttggtattaaNSYacttcDMgYgBatWtaMagact +VWttctttgYMaYaacRgHWaattgRtaagcattctMKVStatactacHVtatgatcBtV +NataaBttYtSttacKgggWgYDtgaVtYgatDaacattYgatggtRDaVDttNactaSa +MtgNttaacaaSaBStcDctaccacagacgcaHatMataWKYtaYattMcaMtgSttDag +cHacgatcaHttYaKHggagttccgatYcaatgatRaVRcaagatcagtatggScctata +ttaNtagcgacgtgKaaWaactSgagtMYtcttccaKtStaacggMtaagNttattatcg +tctaRcactctctDtaacWYtgaYaSaagaWtNtatttRacatgNaatgttattgWDDcN +aHcctgaaHacSgaataaRaataMHttatMtgaSDSKatatHHaNtacagtccaYatWtc +actaactatKDacSaStcggataHgYatagKtaatKagStaNgtatactatggRHacttg +tattatgtDVagDVaRctacMYattDgtttYgtctatggtKaRSttRccRtaaccttaga +gRatagSaaMaacgcaNtatgaaatcaRaagataatagatactcHaaYKBctccaagaRa +BaStNagataggcgaatgaMtagaatgtcaKttaaatgtaWcaBttaatRcggtgNcaca +aKtttScRtWtgcatagtttWYaagBttDKgcctttatMggNttattBtctagVtacata +aaYttacacaaRttcYtWttgHcaYYtaMgBaBatctNgcDtNttacgacDcgataaSat +YaSttWtcctatKaatgcagHaVaacgctgcatDtgttaSataaaaYSNttatagtaNYt +aDaaaNtggggacttaBggcHgcgtNtaaMcctggtVtaKcgNacNtatVaSWctWtgaW +cggNaBagctctgaYataMgaagatBSttctatacttgtgtKtaattttRagtDtacata +tatatgatNHVgBMtKtaKaNttDHaagatactHaccHtcatttaaagttVaMcNgHata +tKtaNtgYMccttatcaaNagctggacStttcNtggcaVtattactHaSttatgNMVatt +MMDtMactattattgWMSgtHBttStStgatatRaDaagattttctatMtaaaaaggtac +taaVttaSacNaatactgMttgacHaHRttgMacaaaatagttaatatWKRgacDgaRta +tatttattatcYttaWtgtBRtWatgHaaattHataagtVaDtWaVaWtgStcgtMSgaS +RgMKtaaataVacataatgtaSaatttagtcgaaHtaKaatgcacatcggRaggSKctDc +agtcSttcccStYtccRtctctYtcaaKcgagtaMttttcRaYDttgttatctaatcata +NctctgctatcaMatactataggDaHaaSttMtaDtcNatataattctMcStaaBYtaNa +gatgtaatHagagSttgWHVcttatKaYgDctcttggtgttMcRaVgSgggtagacaata +aDtaattSaDaNaHaBctattgNtaccaaRgaVtKNtaaYggHtaKKgHcatctWtctDt +ttctttggSDtNtaStagttataaacaattgcaBaBWggHgcaaaBtYgctaatgaaatW +cDcttHtcMtWWattBHatcatcaaatctKMagtDNatttWaBtHaaaNgMttaaStagt +tctctaatDtcRVaYttgttMtRtgtcaSaaYVgSWDRtaatagctcagDgcWWaaaBaa +RaBctgVgggNgDWStNaNBKcBctaaKtttDcttBaaggBttgaccatgaaaNgttttt +tttatctatgttataccaaDRaaSagtaVtDtcaWatBtacattaWacttaSgtattggD +gKaaatScaattacgWcagKHaaccaYcRcaRttaDttRtttHgaHVggcttBaRgtccc +tDatKaVtKtcRgYtaKttacgtatBtStaagcaattaagaRgBagSaattccSWYttta +ttVaataNctgHgttaaNBgcVYgtRtcccagWNaaaacaDNaBcaaaaRVtcWMgBagM +tttattacgDacttBtactatcattggaaatVccggttRttcatagttVYcatYaSHaHc +ttaaagcNWaHataaaRWtctVtRYtagHtaaaYMataHYtNBctNtKaatattStgaMc +BtRgctaKtgcScSttDgYatcVtggaaKtaagatWccHccgKYctaNNctacaWctttt +gcRtgtVcgaKttcMRHgctaHtVaataaDtatgKDcttatBtDttggNtacttttMtga +acRattaaNagaactcaaaBBVtcDtcgaStaDctgaaaSgttMaDtcgttcaccaaaag +gWtcKcgSMtcDtatgtttStaaBtatagDcatYatWtaaaBacaKgcaDatgRggaaYc +taRtccagattDaWtttggacBaVcHtHtaacDacYgtaatataMagaatgHMatcttat +acgtatttttatattacHactgttataMgStYaattYaccaattgagtcaaattaYtgta +tcatgMcaDcgggtcttDtKgcatgWRtataatatRacacNRBttcHtBgcRttgtgcgt +catacMtttBctatctBaatcattMttMYgattaaVYatgDaatVagtattDacaacDMa +tcMtHcccataagatgBggaccattVWtRtSacatgctcaaggggYtttDtaaNgNtaaB +atggaatgtctRtaBgBtcNYatatNRtagaacMgagSaSDDSaDcctRagtVWSHtVSR +ggaacaBVaccgtttaStagaacaMtactccagtttVctaaRaaHttNcttagcaattta +ttaatRtaaaatctaacDaBttggSagagctacHtaaRWgattcaaBtctRtSHaNtgta +cattVcaHaNaagtataccacaWtaRtaaVKgMYaWgttaKggKMtKcgWatcaDatYtK +SttgtacgaccNctSaattcDcatcttcaaaDKttacHtggttHggRRaRcaWacaMtBW +VHSHgaaMcKattgtaRWttScNattBBatYtaNRgcggaagacHSaattRtttcYgacc +BRccMacccKgatgaacttcgDgHcaaaaaRtatatDtatYVtttttHgSHaSaatagct +NYtaHYaVYttattNtttgaaaYtaKttWtctaNtgagaaaNctNDctaaHgttagDcRt +tatagccBaacgcaRBtRctRtggtaMYYttWtgataatcgaataattattataVaaaaa +ttacNRVYcaaMacNatRttcKatMctgaagactaattataaYgcKcaSYaatMNctcaa +cgtgatttttBacNtgatDccaattattKWWcattttatatatgatBcDtaaaagttgaa +VtaHtaHHtBtataRBgtgDtaataMttRtDgDcttattNtggtctatctaaBcatctaR +atgNacWtaatgaagtcMNaacNgHttatactaWgcNtaStaRgttaaHacccgaYStac +aaaatWggaYaWgaattattcMaactcBKaaaRVNcaNRDcYcgaBctKaacaaaaaSgc +tccYBBHYaVagaatagaaaacagYtctVccaMtcgtttVatcaatttDRtgWctagtac +RttMctgtDctttcKtWttttataaatgVttgBKtgtKWDaWagMtaaagaaattDVtag +gttacatcatttatgtcgMHaVcttaBtVRtcgtaYgBRHatttHgaBcKaYWaatcNSc +tagtaaaaatttacaatcactSWacgtaatgKttWattagttttNaggtctcaagtcact +attcttctaagKggaataMgtttcataagataaaaatagattatDgcBVHWgaBKttDgc +atRHaagcaYcRaattattatgtMatatattgHDtcaDtcaaaHctStattaatHaccga +cNattgatatattttgtgtDtRatagSacaMtcRtcattcccgacacSattgttKaWatt +NHcaacttccgtttSRtgtctgDcgctcaaMagVtBctBMcMcWtgtaacgactctcttR +ggRKSttgYtYatDccagttDgaKccacgVatWcataVaaagaataMgtgataaKYaaat +cHDaacgataYctRtcYatcgcaMgtNttaBttttgatttaRtStgcaacaaaataccVg +aaDgtVgDcStctatatttattaaaaRKDatagaaagaKaaYYcaYSgKStctccSttac +agtcNactttDVttagaaagMHttRaNcSaRaMgBttattggtttaRMggatggcKDgWR +tNaataataWKKacttcKWaaagNaBttaBatMHtccattaacttccccYtcBcYRtaga +ttaagctaaYBDttaNtgaaaccHcaRMtKtaaHMcNBttaNaNcVcgVttWNtDaBatg +ataaVtcWKcttRggWatcattgaRagHgaattNtatttctctattaattaatgaDaaMa +tacgttgggcHaYVaaNaDDttHtcaaHtcVVDgBVagcMacgtgttaaBRNtatRtcag +taagaggtttaagacaVaaggttaWatctccgtVtaDtcDatttccVatgtacNtttccg +tHttatKgScBatgtVgHtYcWagcaKtaMYaaHgtaattaSaHcgcagtWNaatNccNN +YcacgVaagaRacttctcattcccRtgtgtaattagcSttaaStWaMtctNNcSMacatt +ataaactaDgtatWgtagtttaagaaaattgtagtNagtcaataaatttgatMMYactaa +tatcggBWDtVcYttcDHtVttatacYaRgaMaacaStaatcRttttVtagaDtcacWat +ttWtgaaaagaaagNRacDtttStVatBaDNtaactatatcBSMcccaSttccggaMatg +attaaWatKMaBaBatttgataNctgttKtVaagtcagScgaaaDggaWgtgttttKtWt +atttHaatgtagttcactaaKMagttSYBtKtaYgaactcagagRtatagtVtatcaaaW +YagcgNtaDagtacNSaaYDgatBgtcgataacYDtaaactacagWDcYKaagtttatta +gcatcgagttKcatDaattgattatDtcagRtWSKtcgNtMaaaaacaMttKcaWcaaSV +MaaaccagMVtaMaDtMaHaBgaacataBBVtaatVYaNSWcSgNtDNaaKacacBttta +tKtgtttcaaHaMctcagtaacgtcgYtactDcgcctaNgagagcYgatattttaaattt +ccattttacatttDaaRctattttWctttacgtDatYtttcagacgcaaVttagtaaKaa +aRtgVtccataBggacttatttgtttaWNtgttVWtaWNVDaattgtatttBaagcBtaa +BttaaVatcHcaVgacattccNggtcgacKttaaaRtagRtctWagaYggtgMtataatM +tgaaRttattttgWcttNtDRRgMDKacagaaaaggaaaRStcccagtYccVattaNaaK +StNWtgacaVtagaagcttSaaDtcacaacgDYacWDYtgtttKatcVtgcMaDaSKStV +cgtagaaWaKaagtttcHaHgMgMtctataagBtKaaaKKcactggagRRttaagaBaaN +atVVcgRcKSttDaactagtSttSattgttgaaRYatggttVttaataaHttccaagDtg +atNWtaagHtgcYtaactRgcaatgMgtgtRaatRaNaacHKtagactactggaatttcg +ccataacgMctRgatgttaccctaHgtgWaYcactcacYaattcttaBtgacttaaacct +gYgaWatgBttcttVttcgttWttMcNYgtaaaatctYgMgaaattacNgaHgaacDVVM +tttggtHtctaaRgtacagacgHtVtaBMNBgattagcttaRcttacaHcRctgttcaaD +BggttKaacatgKtttYataVaNattccgMcgcgtagtRaVVaattaKaatggttRgaMc +agtatcWBttNtHagctaatctagaaNaaacaYBctatcgcVctBtgcaaagDgttVtga +HtactSNYtaaNccatgtgDacgaVtDcgKaRtacDcttgctaagggcagMDagggtBWR +tttSgccttttttaacgtcHctaVtVDtagatcaNMaVtcVacatHctDWNaataRgcgt +aVHaggtaaaaSgtttMtattDgBtctgatSgtRagagYtctSaKWaataMgattRKtaa +catttYcgtaacacattRWtBtcggtaaatMtaaacBatttctKagtcDtttgcBtKYYB +aKttctVttgttaDtgattttcttccacttgSaaacggaaaNDaattcYNNaWcgaaYat +tttMgcBtcatRtgtaaagatgaWtgaccaYBHgaatagataVVtHtttVgYBtMctaMt +cctgaDcYttgtccaaaRNtacagcMctKaaaggatttacatgtttaaWSaYaKttBtag +DacactagctMtttNaKtctttcNcSattNacttggaacaatDagtattRtgSHaataat +gccVgacccgatactatccctgtRctttgagaSgatcatatcgDcagWaaHSgctYYWta +tHttggttctttatVattatcgactaagtgtagcatVgtgHMtttgtttcgttaKattcM +atttgtttWcaaStNatgtHcaaaDtaagBaKBtRgaBgDtSagtatMtaacYaatYtVc +KatgtgcaacVaaaatactKcRgtaYtgtNgBBNcKtcttaccttKgaRaYcaNKtactt +tgagSBtgtRagaNgcaaaNcacagtVtttHWatgttaNatBgtttaatNgVtctgaata +tcaRtattcttttttttRaaKcRStctcggDgKagattaMaaaKtcaHacttaataataK +taRgDtKVBttttcgtKaggHHcatgttagHggttNctcgtatKKagVagRaaaggaaBt +NatttVKcRttaHctaHtcaaatgtaggHccaBataNaNaggttgcWaatctgatYcaaa +HaatWtaVgaaBttagtaagaKKtaaaKtRHatMaDBtBctagcatWtatttgWttVaaa +ScMNattRactttgtYtttaaaagtaagtMtaMaSttMBtatgaBtttaKtgaatgagYg +tNNacMtcNRacMMHcttWtgtRtctttaacaacattattcYaMagBaacYttMatcttK +cRMtgMNccattaRttNatHaHNaSaaHMacacaVaatacaKaSttHatattMtVatWga +ttttttaYctttKttHgScWaacgHtttcaVaaMgaacagNatcgttaacaaaaagtaca +HBNaattgttKtcttVttaaBtctgctacgBgcWtttcaggacacatMgacatcccagcg +gMgaVKaBattgacttaatgacacacaaaaaatRKaaBctacgtRaDcgtagcVBaacDS +BHaaaaSacatatacagacRNatcttNaaVtaaaataHattagtaaaaSWccgtatWatg +gDttaactattgcccatcttHaSgYataBttBaactattBtcHtgatcaataSttaBtat +KSHYttWggtcYtttBttaataccRgVatStaHaKagaatNtagRMNgtcttYaaSaact +cagDSgagaaYtMttDtMRVgWKWtgMaKtKaDttttgactatacataatcNtatNaHat +tVagacgYgatatatttttgtStWaaatctWaMgagaRttRatacgStgattcttaagaD +taWccaaatRcagcagaaNKagtaaDggcgccBtYtagSBMtactaaataMataBSacRM +gDgattMMgtcHtcaYDtRaDaacggttDaggcMtttatgttaNctaattaVacgaaMMt +aatDccSgtattgaRtWWaccaccgagtactMcgVNgctDctaMScatagcgtcaactat +acRacgHRttgctatttaatgaattataYKttgtaagWgtYttgcHgMtaMattWaWVta +RgcttgYgttBHtYataSccStBtgtagMgtDtggcVaaSBaatagDttgBgtctttctc +attttaNagtHKtaMWcYactVcgcgtatMVtttRacVagDaatcttgctBBcRDgcaac +KttgatSKtYtagBMagaRtcgBattHcBWcaactgatttaatttWDccatttatcgagS +KaWttataHactaHMttaatHtggaHtHagaatgtKtaaRactgtttMatacgatcaagD +gatKaDctataMggtHDtggHacctttRtatcttYattttgacttgaaSaataaatYcgB +aaaaccgNatVBttMacHaKaataagtatKgtcaagactcttaHttcggaattgttDtct +aaccHttttWaaatgaaatataaaWattccYDtKtaaaacggtgaggWVtctattagtga +ctattaagtMgtttaagcatttgSgaaatatccHaaggMaaaattttcWtatKctagDtY +tMcctagagHcactttactatacaaacattaacttaHatcVMYattYgVgtMttaaRtga +aataaDatcaHgtHHatKcDYaatcttMtNcgatYatgSaMaNtcttKcWataScKggta +tcttacgcttWaaagNatgMgHtctttNtaacVtgttcMaaRatccggggactcMtttaY +MtcWRgNctgNccKatcttgYDcMgattNYaRagatHaaHgKctcataRDttacatBatc +cattgDWttatttaWgtcggagaaaaatacaatacSNtgggtttccttacSMaagBatta +caMaNcactMttatgaRBacYcYtcaaaWtagctSaacttWgDMHgaggatgBVgcHaDt +ggaactttggtcNatNgtaKaBcccaNtaagttBaacagtatacDYttcctNgWgcgSMc +acatStctHatgRcNcgtacacaatRttMggaNKKggataaaSaYcMVcMgtaMaHtgat +tYMatYcggtcttcctHtcDccgtgRatcattgcgccgatatMaaYaataaYSggatagc +gcBtNtaaaScaKgttBgagVagttaKagagtatVaactaSacWactSaKatWccaKaaa +atBKgaaKtDMattttgtaaatcRctMatcaaMagMttDgVatggMaaWgttcgaWatga +aatttgRtYtattaWHKcRgctacatKttctaccaaHttRatctaYattaaWatVNccat +NgagtcKttKataStRaatatattcctRWatDctVagttYDgSBaatYgttttgtVaatt +taatagcagMatRaacttBctattgtMagagattaaactaMatVtHtaaatctRgaaaaa +aaatttWacaacaYccYDSaattMatgaccKtaBKWBattgtcaagcHKaagttMMtaat +ttcKcMagNaaKagattggMagaggtaatttYacatcWaaDgatMgKHacMacgcVaaca +DtaDatatYggttBcgtatgWgaSatttgtagaHYRVacaRtctHaaRtatgaactaata +tctSSBgggaaHMWtcaagatKgagtDaSatagttgattVRatNtctMtcSaagaSHaat +aNataataRaaRgattctttaataaagWaRHcYgcatgtWRcttgaaggaMcaataBRaa +ccagStaaacNtttcaatataYtaatatgHaDgcStcWttaacctaRgtYaRtataKtgM +ttttatgactaaaatttacYatcccRWtttHRtattaaatgtttatatttgttYaatMca +RcSVaaDatcgtaYMcatgtagacatgaaattgRtcaaYaaYtRBatKacttataccaNa +aattVaBtctggacaagKaaYaaatatWtMtatcYaaVNtcgHaactBaagKcHgtctac +aatWtaDtSgtaHcataHtactgataNctRgttMtDcDttatHtcgtacatcccaggStt +aBgtcacacWtccNMcNatMVaVgtccDYStatMaccDatggYaRKaaagataRatttHK +tSaaatDgataaacttaHgttgVBtcttVttHgDacgaKatgtatatNYataactctSat +atatattgcHRRYttStggaactHgttttYtttaWtatMcttttctatctDtagVHYgMR +BgtHttcctaatYRttKtaagatggaVRataKDctaMtKBNtMtHNtWtttYcVtattMc +gRaacMcctNSctcatttaaagDcaHtYccSgatgcaatYaaaaDcttcgtaWtaattct +cgttttScttggtaatctttYgtctaactKataHacctMctcttacHtKataacacagcN +RatgKatttttSaaatRYcgDttaMRcgaaattactMtgcgtaagcgttatBtttttaat +taagtNacatHgttcRgacKcBBtVgatKttcgaBaatactDRgtRtgaNacWtcacYtt +aaKcgttctHaKttaNaMgWgWaggtctRgaKgWttSttBtDcNtgtttacaaatYcDRt +gVtgcctattcNtctaaaDMNttttNtggctgagaVctDaacVtWccaagtaacacaNct +gaScattccDHcVBatcgatgtMtaatBgHaatDctMYgagaatgYWKcctaatNaStHa +aaKccgHgcgtYaaYtattgtStgtgcaaRtattaKatattagaWVtcaMtBagttatta +gNaWHcVgcaattttDcMtgtaRHVYtHtctgtaaaaHVtMKacatcgNaatttMatatg +ttgttactagWYtaRacgataKagYNKcattataNaRtgaacKaYgcaaYYacaNccHat +MatDcNgtHttRaWttagaaDcaaaaaatagggtKDtStaDaRtaVtHWKNtgtattVct +SVgRgataDaRaWataBgaagaaKtaataaYgDcaStaNgtaDaaggtattHaRaWMYaY +aWtggttHYgagVtgtgcttttcaaDKcagVcgttagacNaaWtagtaataDttctggtt +VcatcataaagtgKaaaNaMtaBBaattaatWaattgctHaVKaSgDaaVKaHtatatat +HatcatSBagNgHtatcHYMHgttDgtaHtBttWatcgtttaRaattgStKgSKNWKatc +agDtctcagatttctRtYtBatBgHHtKaWtgYBgacVVWaKtacKcDttKMaKaVcggt +gttataagaataaHaatattagtataatMHgttYgaRttagtaRtcaaVatacggtcMcg +agtaaRttacWgactKRYataaaagSattYaWgagatYagKagatgSaagKgttaatMgg +tataatgttWYttatgagaaacctNVataatHcccKtDctcctaatactggctHggaSag +gRtKHaWaattcgSatMatttagaggcYtctaMcgctcataSatatgRagacNaaDagga +VBagaYttKtacNaKgtSYtagttggaWcatcWttaatctatgaVtcgtgtMtatcaYcg +tRccaaYgDctgcMgtgtWgacWtgataacacgcgctBtgttaKtYDtatDcatcagKaV +MctaatcttgVcaaRgcRMtDcgattaHttcaNatgaatMtactacVgtRgatggaWttt +actaaKatgagSaaKggtaNtactVaYtaaKRagaacccacaMtaaMtKtatBcttgtaa +WBtMctaataaVcDaaYtcRHBtcgttNtaaHatttBNgRStVDattBatVtaagttaYa +tVattaagaBcacggtSgtVtatttaRattgatgtaHDKgcaatattKtggcctatgaWD +KRYcggattgRctatNgatacaatMNttctgtcRBYRaaaHctNYattcHtaWcaattct +BtMKtVgYataatMgYtcagcttMDataVtggRtKtgaatgccNcRttcaMtRgattaac +attRcagcctHtWMtgtDRagaKaBtgDttYaaaaKatKgatctVaaYaacWcgcatagB +VtaNtRtYRaggBaaBtgKgttacataagagcatgtRattccacttaccatRaaatgWgD +aMHaYVgVtaSctatcgKaatatattaDgacccYagtgtaYNaaatKcagtBRgagtcca +tgKgaaaccBgaagBtgSttWtacgatWHaYatcgatttRaaNRgcaNaKVacaNtDgat +tgHVaatcDaagcgtatgcNttaDataatcSataaKcaataaHWataBtttatBtcaKtK +tatagttaDgSaYctacaRatNtaWctSaatatttYaKaKtaccWtatcRagacttaYtt +VcKgSDcgagaagatccHtaattctSttatggtKYgtMaHagVaBRatttctgtRgtcta +tgggtaHKgtHacHtSYacgtacacHatacKaaBaVaccaDtatcSaataaHaagagaat +ScagactataaRttagcaaVcaHataKgDacatWccccaagcaBgagWatctaYttgaaa +tctVNcYtttWagHcgcgcDcVaaatgttKcHtNtcaatagtgtNRaactttttcaatgg +WgBcgDtgVgtttctacMtaaataaaRggaaacWaHttaRtNtgctaaRRtVBctYtVta +tDcattDtgaccYatagatYRKatNYKttNgcctagtaWtgaactaMVaacctgaStttc +tgaKVtaaVaRKDttVtVctaDNtataaaDtccccaagtWtcgatcactDgYaBcatcct +MtVtacDaaBtYtMaKNatNtcaNacgDatYcatcgcaRatWBgaacWttKttagYtaat +tcggttgSWttttDWctttacYtatatWtcatDtMgtBttgRtVDggttaacYtacgtac +atgaattgaaWcttMStaDgtatattgaDtcRBcattSgaaVBRgagccaaKtttcDgcg +aSMtatgWattaKttWtgDBMaggBBttBaatWttRtgcNtHcgttttHtKtcWtagHSt +aacagttgatatBtaWSaWggtaataaMttaKacDaatactcBttcaatatHttcBaaSa +aatYggtaRtatNtHcaatcaHtagVtgtattataNggaMtcttHtNagctaaaggtaga +YctMattNaMVNtcKtactBKcaHHcBttaSagaKacataYgctaKaYgttYcgacWVtt +WtSagcaacatcccHaccKtcttaacgaKttcacKtNtacHtatatRtaaatacactaBt +ttgaHaRttggttWtatYagcatYDatcggagagcWBataagRtacctataRKgtBgatg +aDatataSttagBaHtaatNtaDWcWtgtaattacagKttcNtMagtattaNgtctcgtc +ctcttBaHaKcKccgtRcaaYagSattaagtKataDatatatagtcDtaacaWHcaKttD +gaaRcgtgYttgtcatatNtatttttatggccHtgDtYHtWgttatYaacaattcaWtat +NgctcaaaSttRgctaatcaaatNatcgtttaBtNNVtgttataagcaaagattBacgtD +atttNatttaaaDcBgtaSKgacgtagataatttcHMVNttgttBtDtgtaWKaaRMcKM +tHtaVtagataWctccNNaSWtVaHatctcMgggDgtNHtDaDttatatVWttgttattt +aacctttcacaaggaSaDcggttttttatatVtctgVtaacaStDVaKactaMtttaSNa +gtgaaattaNacttSKctattcctctaSagKcaVttaagNaVcttaVaaRNaHaaHttat +gtHttgtgatMccaggtaDcgaccgtWgtWMtttaHcRtattgScctatttKtaaccaag +tYagaHgtWcHaatgccKNRtttagtMYSgaDatctgtgaWDtccMNcgHgcaaacNDaa +aRaStDWtcaaaaHKtaNBctagBtgtattaactaattttVctagaatggcWSatMaccc +ttHttaSgSgtgMRcatRVKtatctgaaaccDNatYgaaVHNgatMgHRtacttaaaRta +tStRtDtatDttYatattHggaBcttHgcgattgaKcKtttcRataMtcgaVttWacatN +catacctRataDDatVaWNcggttgaHtgtMacVtttaBHtgagVttMaataattatgtt +cttagtttgtgcDtSatttgBtcaacHattaaBagVWcgcaSYttMgcttacYKtVtatc +aYaKctgBatgcgggcYcaaaaacgNtctagKBtattatctttKtaVttatagtaYtRag +NtaYataaVtgaatatcHgcaaRataHtacacatgtaNtgtcgYatWMatttgaactacR +ctaWtWtatacaatctBatatgYtaagtatgtgtatSttactVatcttYtaBcKgRaSgg +RaaaaatgcagtaaaWgtaRgcgataatcBaataccgtatttttccatcNHtatWYgatH +SaaaDHttgctgtccHtggggcctaataatttttctatattYWtcattBtgBRcVttaVM +RSgctaatMagtYtttaaaaatBRtcBttcaaVtaacagctccSaaSttKNtHtKYcagc +agaaaccccRtttttaaDcDtaStatccaagcgctHtatcttaDRYgatDHtWcaaaBcW +gKWHttHataagHacgMNKttMKHccaYcatMVaacgttaKgYcaVaaBtacgcaacttt +MctaaHaatgtBatgagaSatgtatgSRgHgWaVWgataaatatttccKagVgataattW +aHNcYggaaatgctHtKtaDtctaaagtMaatVDVactWtSaaWaaMtaHtaSKtcBRaN +cttStggtBttacNagcatagRgtKtgcgaacaacBcgKaatgataagatgaaaattgta +ctgcgggtccHHWHaaNacaBttNKtKtcaaBatatgctaHNgtKcDWgtttatNgVDHg +accaacWctKaaggHttgaRgYaatHcaBacaatgagcaaattactgtaVaaYaDtagat +tgagNKggtggtgKtWKaatacagDRtatRaMRtgattDggtcaaYRtatttNtagaDtc +acaaSDctDtataatcgtactaHttatacaatYaacaaHttHatHtgcgatRRttNgcat +SVtacWWgaaggagtatVMaVaaattScDDKNcaYBYaDatHgtctatBagcaacaagaa +tgagaaRcataaKNaRtBDatcaaacgcattttttaaBtcSgtacaRggatgtMNaattg +gatatWtgagtattaaaVctgcaYMtatgatttttYgaHtgtcttaagWBttHttgtctt +attDtcgtatWtataataSgctaHagcDVcNtaatcaagtaBDaWaDgtttagYctaNcc +DtaKtaHcttaataacccaRKtacaVaatNgcWRaMgaattatgaBaaagattVYaHMDc +aDHtcRcgYtcttaaaWaaaVKgatacRtttRRKYgaatacaWVacVcRtatMacaBtac +tggMataaattttHggNagSctacHgtBagcgtcgtgattNtttgatSaaggMttctttc +ttNtYNagBtaaacaaatttMgaccttacataattgYtcgacBtVMctgStgMDtagtaR +ctHtatgttcatatVRNWataDKatWcgaaaaagttaaaagcacgHNacgtaatctttMR +tgacttttDacctataaacgaaatatgattagaactccSYtaBctttaataacWgaaaYa +tagatgWttcatKtNgatttttcaagHtaYgaaRaDaagtaggagcttatVtagtctttc +attaaaatcgKtattaRttacagVaDatgcatVgattgggtctttHVtagKaaRBtaHta +aggccccaaaaKatggtttaMWgtBtaaacttcactttKHtcgatctccctaYaBacMgt +cttBaBaNgcgaaacaatctagtHccHtKttcRtRVttccVctttcatacYagMVtMcag +aMaaacaataBctgYtaatRaaagattaaccatVRatHtaRagcgcaBcgDttStttttc +VtttaDtKgcaaWaaaaatSccMcVatgtKgtaKgcgatatgtagtSaaaDttatacaaa +catYaRRcVRHctKtcgacKttaaVctaDaatgttMggRcWaacttttHaDaKaDaBctg +taggcgtttaHBccatccattcNHtDaYtaataMttacggctNVaacDattgatatttta +cVttSaattacaaRtataNDgacVtgaacataVRttttaDtcaaacataYDBtttaatBa +DtttYDaDaMccMttNBttatatgagaaMgaNtattHccNataattcaHagtgaaggDga +tgtatatatgYatgaStcataaBStWacgtcccataRMaaDattggttaaattcMKtctM +acaBSactcggaatDDgatDgcWctaacaccgggaVcacWKVacggtaNatatacctMta +tgatagtgcaKagggVaDtgtaacttggagtcKatatcgMcttRaMagcattaBRaStct +YSggaHYtacaactMBaagDcaBDRaaacMYacaHaattagcattaaaHgcgctaaggSc +cKtgaaKtNaBtatDDcKBSaVtgatVYaagVtctSgMctacgttaacWaaattctSgtD +actaaStaaattgcagBBRVctaatatacctNttMcRggctttMttagacRaHcaBaacV +KgaataHttttMgYgattcYaNRgttMgcVaaacaVVcDHaatttgKtMYgtatBtVVct +WgVtatHtacaaHttcacgatagcagtaaNattBatatatttcVgaDagcggttMaagtc +ScHagaaatgcYNggcgtttttMtStggtRatctacttaaatVVtBacttHNttttaRca +aatcacagHgagagtMgatcSWaNRacagDtatactaaDKaSRtgattctccatSaaRtt +aaYctacacNtaRtaactggatgaccYtacactttaattaattgattYgttcagDtNKtt +agDttaaaaaaaBtttaaNaYWKMBaaaacVcBMtatWtgBatatgaacVtattMtYatM +NYDKNcKgDttDaVtaaaatgggatttctgtaaatWtctcWgtVVagtcgRgacttcccc +taDcacagcRcagagtgtWSatgtacatgttaaSttgtaaHcgatgggMagtgaacttat +RtttaVcaccaWaMgtactaatSSaHtcMgaaYtatcgaaggYgggcgtgaNDtgttMNg +aNDMtaattcgVttttaacatgVatgtWVMatatcaKgaaattcaBcctccWcttgaaWH +tWgHtcgNWgaRgctcBgSgaattgcaaHtgattgtgNagtDttHHgBttaaWcaaWagc +aSaHHtaaaVctRaaMagtaDaatHtDMtcVaWMtagSagcttHSattaacaaagtRacM +tRtctgttagcMtcaBatVKtKtKacgagaSNatSactgtatatcBctgagVtYactgta +aattaaaggcYgDHgtaacatSRDatMMccHatKgttaacgactKtgKagtcttcaaHRV +tccttKgtSataatttacaactggatDNgaacttcaRtVaagDcaWatcBctctHYatHa +DaaatttagYatSatccaWtttagaaatVaacBatHcatcgtacaatatcgcNYRcaata +YaRaYtgattVttgaatgaVaactcRcaNStgtgtattMtgaggtNttBaDRcgaaaagc +tNgBcWaWgtSaDcVtgVaatMKBtttcgtttctaaHctaaagYactgMtatBDtcStga +ccgtSDattYaataHctgggaYYttcggttaWaatctggtRagWMaDagtaacBccacta +cgHWMKaatgatWatcctgHcaBaSctVtcMtgtDttacctaVgatYcWaDRaaaaRtag +atcgaMagtggaRaWctctgMgcWttaagKBRtaaDaaWtctgtaagYMttactaHtaat +cttcataacggcacBtSgcgttNHtgtHccatgttttaaagtatcgaKtMttVcataYBB +aKtaMVaVgtattNDSataHcagtWMtaggtaSaaKgttgBtVtttgttatcatKcgHac +acRtctHatNVagSBgatgHtgaRaSgttRcctaacaaattDNttgacctaaYtBgaaaa +tagttattactcttttgatgtNNtVtgtatMgtcttRttcatttgatgacacttcHSaaa +ccaWWDtWagtaRDDVNacVaRatgttBccttaatHtgtaaacStcVNtcacaSRttcYa +gacagaMMttttgMcNttBcgWBtactgVtaRttctccaaYHBtaaagaBattaYacgat +ttacatctgtaaMKaRYtttttactaaVatWgctBtttDVttctggcDaHaggDaagtcg +aWcaagtagtWttHtgKtVataStccaMcWcaagataagatcactctHatgtcYgaKcat +cagatactaagNSStHcctRRNtattgtccttagttagMVgtatagactaactctVcaat +MctgtttgtgttgccttatWgtaBVtttctggMcaaKgDWtcgtaaYStgSactatttHg +atctgKagtagBtVacRaagRtMctatgggcaaaKaaaatacttcHctaRtgtDcttDat +taggaaatttcYHaRaaBttaatggcacKtgctHVcaDcaaaVDaaaVcgMttgtNagcg +taDWgtcgttaatDgKgagcSatatcSHtagtagttggtgtHaWtaHKtatagctgtVga +ttaBVaatgaataagtaatVatSttaHctttKtttgtagttaccttaatcgtagtcctgB +cgactatttVcMacHaaaggaatgDatggKtaHtgStatattaaSagctWcctccRtata +BaDYcgttgcNaagaggatRaaaYtaWgNtSMcaatttactaacatttaaWttHtatBat +tgtcgacaatNgattgcNgtMaaaKaBDattHacttggtRtttaYaacgVactBtaBaKt +gBttatgVttgtVttcaatcWcNctDBaaBgaDHacBttattNtgtDtatttVSaaacag +gatgcRatSgtaSaNtgBatagttcHBgcBBaaattaHgtDattatDaKaatBaaYaaMa +ataaataKtttYtagtBgMatNcatgtttgaNagtgttgtgKaNaSagtttgaSMaYBca +aaacDStagttVacaaaaactaaWttBaagtctgtgcgtMgtaattctcctacctcaNtt +taaccaaaaVtBcacataacaccccBcWMtatVtggaatgaWtcaaWaaaaaaaaWtDta +atatRcctDWtcctaccMtVVatKttaWaaKaaatataaagScHBagaggBaSMtaWaVt +atattactSaaaKNaactatNatccttgaYctattcaaaVgatttYHcRagattttaSat +aggttattcVtaaagaKgtattattKtRttNcggcRgtgtgtWYtaacHgKatKgatYta +cYagDtWcHBDctctgRaYKaYagcactKcacSaRtBttttBHKcMtNtcBatttatttt +tgSatVgaaagaWtcDtagDatatgMacaacRgatatatgtttgtKtNRaatatNatgYc +aHtgHataacKtgagtagtaacYttaNccaaatHcacaacaVDtagtaYtccagcattNt +acKtBtactaaagaBatVtKaaHBctgStgtBgtatgaSNtgDataaccctgtagcaBgt +gatcttaDataStgaMaccaSBBgWagtacKcgattgaDgNNaaaacacagtSatBacKD +gcgtataBKcatacactaSaatYtYcDaactHttcatRtttaatcaattataRtttgtaa +gMcgNttcatcBtYBagtNWNMtSHcattcRctttttRWgaKacKttgggagBcgttcgc +MaWHtaatactgtctctatttataVgtttaBScttttaBMaNaatMacactYtBMggtHa +cMagtaRtctgcatttaHtcaaaatttgagKtgNtactBacaHtcgtatttctMaSRagc +agttaatgtNtaaattgagagWcKtaNttagVtacgatttgaatttcgRtgtWcVatcgt +taaDVctgtttBWgaccagaaagtcSgtVtatagaBccttttcctaaattgHtatcggRa +ttttcaaggcYSKaagWaWtRactaaaacccBatMtttBaatYtaagaactSttcgaaSc +aatagtattgaccaagtgttttctaacatgtttNVaatcaaagagaaaNattaaRtttta +VaaaccgcaggNMtatattVctcaagaggaacgBgtttaacaagttcKcYaatatactaa +ccBaaaSggttcNtattctagttRtBacgScVctcaatttaatYtaaaaaaatgSaatga +tagaMBRatgRcMcgttgaWHtcaVYgaatYtaatctttYttatRaWtctgBtDcgatNa +tcKaBaDgatgtaNatWKctccgatattaacattNaaacDatgBgttctgtDtaaaMggt +gaBaSHataacgccSctaBtttaRBtcNHcDatcDcctagagtcRtaBgWttDRVHagat +tYatgtatcWtaHtttYcattWtaaagtctNgtStggRNcgcggagSSaaagaaaatYcH +DtcgctttaatgYcKBVSgtattRaYBaDaaatBgtatgaHtaaRaRgcaSWNtagatHa +acttNctBtcaccatctMcatattccaSatttgcgaDagDgtatYtaaaVDtaagtttWV +aagtagYatRttaagDcNgacKBcScagHtattatcDaDactaaaaaYgHttBcgaDttg +gataaaKSRcBMaBcgaBSttcWtgNBatRaccgattcatttataacggHVtaattcaca +agagVttaaRaatVVRKcgWtVgacctgDgYaaHaWtctttcacMagggatVgactagMa +aataKaaNWagKatagNaaWtaaaatttgaattttatttgctaaVgaHatBatcaaBWcB +gttcMatcgBaaNgttcgSNaggSaRtttgHtRtattaNttcDcatSaVttttcgaaaaa +ttgHatctaRaggSaNatMDaaatDcacgattttagaHgHaWtYgattaatHNSttatMS +gggNtcKtYatRggtttgtMWVtttaYtagcagBagHaYagttatatggtBacYcattaR +SataBatMtttaaatctHcaaaSaaaagttNSaaWcWRccRtKaagtBWtcaaattSttM +tattggaaaccttaacgttBtWatttatatWcDaatagattcctScacctaagggRaaYt +aNaatgVtBcttaaBaacaMVaaattatStYgRcctgtactatcMcVKatttcgSgatRH +MaaaHtagtaaHtVgcaaataatatcgKKtgccaatBNgaaWcVttgagttaKatagttc +aggKDatDtattgaKaVcaKtaataDataataHSaHcattagttaatRVYcNaHtaRcaa +ggtNHcgtcaaccaBaaagYtHWaaaRcKgaYaaDttgcWYtataRgaatatgtYtgcKt +aNttWacatYHctRaDtYtattcBttttatcSataYaYgttWaRagcacHMgtttHtYtt +YaatcggtatStttcgtRSattaaDaKMaatatactaNBaWgctacacYtgaYVgtgHta +aaRaaRgHtagtWattataaaSDaaWtgMattatcgaaaagtaYRSaWtSgNtBgagcRY +aMDtactaacttaWgtatctagacaagNtattHggataatYttYatcataDcgHgttBtt +ctttVttgccgaaWtaaaacgKgtatctaaaaaNtccDtaDatBMaMggaatNKtatBaa +atVtccRaHtaSacataHattgtttKVYattcataVaattWtcgtgMttcttKtgtctaa +cVtatctatatBRataactcgKatStatattcatHHRttKtccaacgtgggtgRgtgaMt +attattggctatcgtgacMtRcBDtcttgtactaatRHttttaagatcgVMDStattatY +BtttDttgtBtNttgRcMtYtgBacHaWaBaatDKctaagtgaaactaatgRaaKgatcc +aagNaaaatattaggWNtaagtatacttttKcgtcggSYtcttgRctataYcttatataa +agtatattaatttataVaacacaDHatctatttttKYVatHRactttaBHccaWagtact +BtcacgaVgcgttRtttttttSVgtSagtBaaattctgaHgactcttgMcattttagVta +agaattHctHtcaDaaNtaacRggWatagttcgtSttgaDatcNgNagctagDgatcNtt +KgttgtaDtctttRaaYStRatDtgMggactSttaDtagSaVtBDttgtDgccatcacaM +attaaaMtNacaVcgSWcVaaDatcaHaatgaattaMtatccVtctBtaattgtWattat +BRcWcaatgNNtactWYtDaKttaaatcactcagtRaaRgatggtKgcgccaaHgaggat +StattYcaNMtcaBttacttatgagDaNtaMgaaWtgtttcttctaHtMNgttatctaWW +atMtBtaaatagDVatgtBYtatcggcttaagacMRtaHScgatatYgRDtcattatSDa +HggaaataNgaWSRRaaaBaatagBattaDctttgHWNttacaataaaaaaatacggttt +gHgVtaHtWMttNtBtctagtMcgKMgHgYtataHaNagWtcaacYattaataYRgtaWK +gaBctataaccgatttaHaNBRaRaMtccggtNgacMtctcatttgcaattcWgMactta +caaDaaNtactWatVtttagccttMaatcagVaagtctVaaDaBtattaattaYtNaYtg +gattaKtaKctYaMtattYgatattataatKtVgDcttatatNBtcgttgtStttttMag +aggttaHYSttcKgtcKtDNtataagttataagSgttatDtRttattgttttSNggRtca +aKMNatgaatattgtBWtaMacctgggYgaSgaagYataagattacgagaatBtggtRcV +HtgYggaDgaYaKagWagctatagacgaaHgtWaNgacttHRatVaWacKYtgRVNgVcS +gRWctacatcKSactctgWYtBggtataagcttNRttVtgRcaWaaatDMatYattaact +ttcgaagRatSctgccttgcRKaccHtttSNVagtagHagBagttagaccaRtataBcca +taatSHatRtcHagacBWatagcaMtacaRtgtgaaBatctKRtScttccaNaatcNgta +atatWtcaMgactctBtWtaaNactHaaaaRctcgcatggctMcaaNtcagaaaaacaca +gtggggWttRttagtaagaVctVMtcgaatcttcMaaaHcaHBttcgattatgtcaDagc +YRtBtYcgacMgtDcagcgaNgttaataatagcagKYYtcgtaBtYctMaRtaRtDagaa +aacacatgYaBttgattattcgaaNttBctSataaMataWRgaHtttccgtDgaYtatgg +tDgHKgMtatttVtMtVagttaRatMattRagataaccctKctMtSttgaHagtcStcta +tttccSagatgttccacgaggYNttHRacgattcDatatDcataaaatBBttatcgaHtN +HaaatatDNaggctgaNcaaggagttBttMgRagVatBcRtaWgatgBtSgaKtcgHttt +gaatcaaDaHttcSBgHcagtVaaSttDcagccgttNBtgttHagYtattctttRWaaVt +SttcatatKaaRaaaNacaVtVctMtSDtDtRHRcgtaatgctcttaaatSacacaatcg +HattcaWcttaaaatHaaatcNctWttaNMcMtaKctVtcctaagYgatgatcYaaaRac +tctaRDaYagtaacgtDgaggaaatctcaaacatcaScttcKttNtaccatNtaNataca +tttHaaDHgcaDatMWaaBttcRggctMaagctVYcacgatcaDttatYtaatcKatWat +caatVYtNagatttgattgaYttttYgacttVtcKaRagaaaHVgDtaMatKYagagttN +atWttaccNtYtcDWgSatgaRgtMatgKtcgacaagWtacttaagtcgKtgatccttNc +ttatagMatHVggtagcgHctatagccctYttggtaattKNaacgaaYatatVctaataM +aaaYtgVtcKaYtaataacagaatHcacVagatYWHttagaaSMaatWtYtgtaaagNaa +acaVgaWtcacNWgataNttcaSagctMDaRttgNactaccgataMaaatgtttattDtc +aagacgctDHYYatggttcaagccNctccttcMctttagacBtaaWtaWVHggaaaaNat +ttaDtDtgctaaHHtMtatNtMtagtcatttgcaaaRatacagRHtatDNtgtDgaatVg +tVNtcaaatYBMaaaagcaKgtgatgatMgWWMaHttttMgMagatDtataaattaacca +actMtacataaattgRataatacgBtKtaataattRgtatDagDtcRDacctatRcagag +cSHatNtcaScNtttggacNtaaggaccgtgKNttgttNcttgaaRgYgRtNtcagttBc +ttttcHtKtgcttYaaNgYagtaaatgaatggWaMattBHtatctatSgtcYtgcHtaat +tHgaaMtHcagaaSatggtatgccaHBtYtcNattWtgtNgctttaggtttgtWatNtgH +tgcDttactttttttgcNtactKtWRaVcttcatagtgSNKaNccgaataaBttataata +YtSagctttaaatSttggctaaKSaatRccgWHgagDttaaatcatgagMtcgagtVtaD +ggaBtatttgDacataaacgtagYRagBWtgDStKDgatgaagttcattatttaKWcata +aatWRgatataRgttRacaaNKttNtKagaaYaStaactScattattaacgatttaaatg +DtaattagatHgaYataaactatggggatVHtgccgtNgatNYcaStRtagaccacWcaM +tatRagHgVactYtWHtcttcatgatWgagaKggagtatgaWtDtVtNaNtcgYYgtaaa +ctttaDtBactagtaDctatagtaatatttatatataacgHaaaRagKattSagttYtSt +>THREE Homo sapiens frequency +agagagacgatgaaaattaatcgtcaatacgctggcgaacactgagggggacccaatgct +cttctcggtctaaaaaggaatgtgtcagaaattggtcagttcaaaagtagaccggatctt +tgcggagaacaattcacggaacgtagcgttgggaaatatcctttctaccacacatcggat +tttcgccctctcccattatttattgtgttctcacatagaattattgtttagacatccctc +gttgtatggagagttgcccgagcgtaaaggcataatccatataccgccgggtgagtgacc +tgaaattgtttttagttgggatttcgctatggattagcttacacgaagagattctaatgg +tactataggataattataatgctgcgtggcgcagtacaccgttacaaacgtcgttcgcat +atgtggctaacacggtgaaaatacctacatcgtatttgcaatttcggtcgtttcatagag +cgcattgaattactcaaaaattatatatgttgattatttgattagactgcgtggaaagaa +ggggtactcaagccatttgtaaaagctgcatctcgcttaagtttgagagcttacattagt +ctatttcagtcttctaggaaatgtctgtgtgagtggttgtcgtccataggtcactggcat +atgcgattcatgacatgctaaactaagaaagtagattactattaccggcatgcctaatgc +gattgcactgctatgaaggtgcggacgtcgcgcccatgtagccctgataataccaatact +tacatttggtcagcaattctgacattatacctagcacccataaatttactcagacttgag +gacaggctcttggagtcgatcttctgtttgtatgcatgtgatcatatagatgaataagcg +atgcgactagttagggcatagtatagatctgtgtatacagttcagctgaacgtccgcgag +tggaagtacagctgagatctatcctaaaatgcaaccatatcgttcacacatgatatgaac +ccagggggaaacattgagttcagttaaattggcagcgaatcccccaagaagaaggcggag +tgacgttgaacgggcttatggtttttcagtacttcctccgtataagttgagcgaaatgta +aacagaataatcgttgtgttaacaacattaaaatcgcggaatatgatgagaatacacagt +gtgagcatttcacttgtaaaatatctttggtagaacttactttgctttaaatatgttaaa +ccgatctaataatctacaaaacggtagattttgcctagcacattgcgtccttctctattc +agatagaggcaatactcagaaggttttatccaaagcactgtgttgactaacctaagtttt +agtctaataatcatgattgattataggtgccgtggactacatgactcgtccacaaataat +acttagcagatcagcaattggccaagcacccgacttttatttaatggttgtgcaatagtc +cagattcgtattcgggactctttcaaataatagtttcctggcatctaagtaagaaaagct +cataaggaagcgatattatgacacgctcttccgccgctgttttgaaacttgagtattgct +cgtccgaaattgagggtcacttcaaaatttactgagaagacgaagatcgactaaagttaa +aatgctagtccacagttggtcaagttgaattcatccacgagttatatagctattttaatt +tatagtcgagtgtacaaaaaacatccacaataagatttatcttagaataacaacccccgt +atcatcgaaatcctccgttatggcctgactcctcgagcttatagcatttgtgctggcgct +cttgccaggaacttgctcgcgaggtggtgacgagtgagatgatcagtttcattatgatga +tacgattttatcgcgactagttaatcatcatagcaagtaaaatttgaattatgtcattat +catgctccattaacaggttatttaattgatactgacgaaattttttcacaatgggttttc +tagaatttaatatcagtaattgaagccttcataggggtcctactagtatcctacacgacg +caggtccgcagtatcctggagggacgtgttactgattaaaagggtcaaaggaatgaaggc +tcacaatgttacctgcttcaccatagtgagccgatgagttttacattagtactaaatccc +aaatcatactttacgatgaggcttgctagcgctaaagagaatacatacaccaccacatag +aattgttagcgatgatatcaaatagactcctggaagtgtcagggggaaactgttcaatat +ttcgtccacaggactgaccaggcatggaaaagactgacgttggaaactataccatctcac +gcccgacgcttcactaattgatgatccaaaaaatatagcccggattcctgattagcaaag +ggttcacagagaaagatattatcgacgtatatcccaaaaaacagacgtaatgtgcatctt +cgaatcgggatgaatacttgtatcataaaaatgtgacctctagtatacaggttaatgtta +gtgatacacaatactcgtgggccatgggttctcaaataaaatgtaatattgcgtcgatca +ctcacccacgtatttggtctaattatgttttatttagtgacaatccaatagataaccggt +cctattaagggctatatttttagcgaccacgcgtttaaacaaaggattgtatgtagatgg +taccagtttaattgccagtgggcaatcctaagcaaaatgagattctatcctaaagtttgg +gcttgatataagatttcggatgtatgggttttataatcgttggagagctcaatcatgagc +taatacatggatttcgctacctcaccgagagaccttgcatgaagaattctaaccaaaagt +ttaataggccggattggattgagttaattaagaccttgttcagtcatagtaaaaaccctt +aaattttaccgattgacaaagtgagcagtcgcaataccctatgcgaaacgcctcgatagt +gactaggtatacaaggtttttgagttcctttgaaatagttaactaatttaaaattaatta +acgacatggaaatcacagaacctaatgctttgtaggagttatttatgctgtttactgcct +ctacaaccctaataaagcagtcctaagaatgaaacgcatcttttagttcagaaagtggta +tccagggtggtcaatttaataaattcaacatcgggtctcaggatattcggtcatataatt +tattaagggctcttcgagtcttactctgagtgaaattggaaacagtcatccttttcgttg +tgaggcatcttacaccgctatcgatatacaatgcattccaccgcggtgtcccgtacacaa +ggaaacttgttaccttggggatataagaaaactcacacgtctcattattaaactgagtac +aatttttgcacgagaaagtaatgcaatacaatatgatgaaagccagctaatgaaaaggga +tggaacgcacctcggatctgttgcactggattaaaatccgattatttttaaaaatattca +gtgctagagcatatcaggtctacttttttatctggtatgtaaagcccacggagcgatagt +gagatccttacgactcaacgaaaagttataacataactcccgttagccaaagcccaatcc +cgattactgccctaccctaacgtctgccatctaaatatcgaacttgttatgatcaatgtg +actacctcccaccctttccccttcatttgttccactggggataagctagcgttttcagaa +tcaatgcaataagaatagccaattgtctcacttcatcagagctcttggcaattccaggcg +ctacgtggttctggaatatattcatttttcaaatagtaatacgtttagtgttgctattgt +ctacacgtttggatattacgttatgtgagcggacatcaatagttgtctaactctttagta +agccagagatagcactcttagcgaatggataccatcttccataagtttagttaatagtcc +gaaacaactgcttcgagcatatttgaacctccttgtaggcaaatagcctcttcaaagcaa +tcttactaatagatagagtttgttttaagggactactagaaatgggacaatcttaatagt +atgacctaaactgacatttaaagatatatccaggtggcaagcataaagatcattgcgcca +cctccaccgtgggattacttatcagtcgatatcctatatgctaagtttgcgacggcagaa +tacaaactaagctgagttgatgctaaccttacctatgataccccattggaccggttaaca +gccctacttattccaaataaaagaacttttatgctgtagaagctattatagtgatgcctg +gtaacttcagtatattaaaatgacacacatacgccatatagagctcctggaactttgaat +aatgagcgaacttcgaagttgaagagcaagaaaccatatgtcacggttgcctaaagcccg +gtaaccagacatgtgctatcattgatcattatcgaggttttcataaccttgacccattat +cggctgtgcgcggacaagtacttaaatcactagtttcttcacctgcttatcggtaagaaa +taaggttggcaaagaatcgcataagacggacgtagagccgcagcgttgtgcgagtccagg +tgcatgcgcagcaataggattttaaattttgttccatttttaatttagccgtaaggatgt +ccgtaaatgattgaaaattggattcaatctttgggcctatgctactggaacctgatcgac +aaaatttcaaacatacgttaactccgaaagaccgtatttttgcggctagaatagtcagtc +gcttggagccatataccttaccacttaaacgacgtgctcctgtagttgaaatataaacag +aacacaaagactaccgatcatatcaactgaagatctttgtaactttgaggcgaagcaccc +tcttcgagacaactaagagtaaagtaccgggcgccgcaaggagtcgattgggaccctaaa +tcttgacgaattgctaagaggctcagagctaccactgtaatttctctagagcccataata +aatgaacgatacatccgtaggtagcacctaagggattataatggaagccaaatgcagtta +ataatattatatactggcgtacacgattcgacggatctctcacatagtgattcacgaccc +ccccctttgattgacacagcgtcagcattttgcaagaacgatcttctgcatagggtgcgc +caccgtaaggatgacgtcgaagctacaactgggtataatttaccatgcttccctgatgct +gagtgcaatacactaagaatgagtttttaccccatatcaccagtatttgttctgttattg +cgaagaaatggctatgctgagttggcgactaaagtcacccatcctttttattaggtaacc +ccctcccttaaactaactgatttgctggagctgccctgcatacatatactttatcattta +tggacgtccgtgacgcttattatccaccatagtcgatatgctacacggattcattaatgg +atcgtaggagtttaagttatatttactaagatcggtctcggctactatcccgccttaccc +ggcgctatttacggccatttttaatatattgacggtaattattcctatggtttcgaccgc +acgtccttggacaagaaagaatggcaaaaaaaatgtaaaagaaaaaaaatattgagtccc +taccatcatataaaaaatatgtgatgagtaacttgacgaaatgttagtggttattaaaga +ctatctattacaccttttgttttctgtcgtagtatattaaagtctagaagccttacagga +aaatcagggttatacagccgatactccgcagcatgaatcatcgaggaggtgtcctaccat +cgcgccttgtaatcttgtctgtgtatactgtatttagaccttttatacaaagtaaatatc +tcggctttatgtgattgggaggggcctactcaaacatgatgacttgacctaataatcact +gtgcgggcgtcttatgactagctattccttgaaatccaccaccaaatggttaatatgtaa +aaactttgacgatgaaacaaggtgaatgtgtagttactttgtgtaattagctgcgtcgag +cattgcttgtaaaaccgtcaatcgcacacgttacttccataaaatttctacgaatacacc +cttcttaaaaaaaacgtaggaattcacgagtttaacaaacgataactgtataaagtggaa +gtccgaagaaagcagatgcccgaactactcgaagatgtttcgttttcttaaccatagggg +cttcttaatggcccactacgcacattttgttcaagcccgagagggacatccccattacgg +gagtattactaaaactgttccgtaatacgttcagcaagggatgaaaaaggccactgctca +agttattgacgtgggagtattacatcggaagcctgaatcccacactatgatggtctgtac +aggcctagggactgcgtctagacggtattaccggcttctaatcatacgatcgtgagtctt +aacgggaagtaaggctcacacctaccccaaaccatttatctatgtaagtataaaattgtg +cgtaagtgttcaaagtggacaataaagacgtggcaaaaacccccgcacataagccgcttt +agatttcacaaataccaatgcggttaaaaacatccttgagtcgtacatacaccatactcg +cgttaaacggatataacagaagataataaatccggatgtggagtcggtgtaactatagaa +agccaagtgaaataatgcttaccagtcatttagctatacggctttcatttcatgtcaaga +gggtggagtttgacctgtacagttgatatatcaccgatacttagaactcacctaaagcta +aaattgctcgcagcgtgtaatccgcatattacaaacaatagatgggattcattatacata +agacacgatgatctgctttttcaggttgcgagatgttgcctatcgtcaatcgagtcctgc +cttacaccacttaaacaaaagtattgacagggaacctattttcgaggtattatatagtcc +agcttgaatatcaatttgacagttaacctagtgaaaatcagtaagaggaaatacgccaca +ttctccagtgaaattctacgggttatcgtctagtccaactatcaattataactcacgaga +tataagtaaattctcgtacttggcctgatttttattatactttggatccttagtaaacag +gaagggagaaaccttcaacgaaaaacactggattttgttttactctcaaagctcttatat +gacggaaataccctgtcaagtcttaactttattactagactaatgaaatgggcttggggt +ggccagaatcatagtacaatttagcggatacactattcggactttcctatcggctgtctg +gttggataagtatggggactaataggctagacatacctatacttaaactatacaggcgtc +atctatctctgcaactttggagttccctgatgttctcccgccctttgggttcacatcttc +tataccgacacccctaataacgattagtttgtgggttagagtaaattaatacggttaata +ttaatgtatcgttgaaaagctggtgtcgccaataaggtaaccggctaggcagagtatatg +tcacgaagtataactaccctaatgataagctgtaggaataaaattaatgctgtctctaag +cgaagagatatttccgactctgttttaatgacgaatctcattacttctgacttgcaaatg +ttcaatatggcacggtttcacggcacctttgtgacgcatataatgaacttagaagattat +aacgacggaactttatatgataatccgttacgattaaagaatctgttaaatatcataatg +gcattcagttctagaccgtgcatcatggtaaacttactttctctgcatggcgacatacat +ttcgctattcaaattcgcgtgtggttacacccactcgcacctttggaatattaagagaag +atgatcagaaaatccattcgctcaatttttctgacgtacgtctaatttatcctaggagac +aaatcgttttatgtctctcacatttttgaagaaaggttcgagagacaatactcaggtcct +gaactgctagaagatactcggtggagcgtggcaacaatgaaaaactcgtgacataaatga +atgatacttttccaagttcagttaagtgaatatgtttaacatacccggcttttcgatctt +aagctgacgctggacgtgcgagtaatgtcagtctcttacatacactagtgactccaagtt +tcgtcaaaaacgccccctcccttctcgagcccactcacgctatgtattgacgcgaacttg +ttcgggatcagacttttcaggagttcggtcgcgtgtccctatgtgctaatatataagtta +gatcgcattagatgctaatctgaatacttatagacgaccttcaacgagaacgggtaccac +cttgaggctagagttaggtgtgaaacgacaggtagggacatataaaatttgagtgcggct +ttagttaagggtttaattacctactcaaacatcacgctcgcgcccttcgtacgtaatcga +ccatctagaggctaaggggactgtactaggtagtgattaatgatatcctagacgcacgtg +ccttagatcttcagactctgatggtccgcgatcaccgtaattgtagtcctccaactcgat +cactttgttggcgtcaaagaaattacgatatctaaatacttataatacaataaccaagga +tgagaatgactcatcgcgttggagttatattgcttgaagttctatggaatgaaagcacgt +tatctgccgtcccaatatctccagtgagctaattcattggacggtccactttgatcaatc +cccgaggagatgttcggacactttagtctgtaacacttagcgttgagaccacgaacaatt +gattactcagtcttgaaggtgttttccaaagttcattttaaataagactacgataggcct +ttcctattgatataaactacccggctctgttgttcgtgtgagtcgtacttctctgtgttt +ttctgattatagcaagattcgattcttagtgtaaacagcgatttttatttgacccgtcaa +tgagaagcgcataggatctaagcaaaattatcaagttgtgccacaaggtaagatctttcc +agttattgcaggtaggatgtatcccacgttgatagtatgaggtctgacgtcaactgtcta +ggagagttgaccgcgtgcgggtacaccggatttgcatcgatgttgagaacgcagaactcc +cactgtcgtggcggcgttcctgatatttagcaagaggcgttgataaagccctcatcatct +agatctcgacctcatctgccctcttgctccatcattttctacacagactactttcctatc +tacgttagtataattgctttctatcttagtatcatttagagcttctccgtcaacaggttc +gtgctattaaagttagtacgaaagggacaacttgtagcaacgcatttaatcggttttcga +ctacttcgcacaaaatcagataaagaagtttgtcattctattagacattgaattgcgcaa +ttgacttgtaccacttatgatcgaacactgaatcaagactgtgattaactaaaatagaca +agccactatatcaactaataaaaacgcccctggtggtcgaacatagttgactacaggata +attaattggactggagccattacattctctacaatcgtatcacttcccaagtagacaact +ttgaccttgtagtttcatgtacaaaaaaatgctttcgcaggagcacattggtagttcaat +agtttcatgggaacctcttgagccgtcttctgtgggtgtgttcggatagtaggtactgat +aaagtcgtgtcgctttcgatgagagggaattcaccggaaaacaccttggttaacaggata +gtctatgtaaacttcgagacatgtttaagagttaccagcttaatccacggtgctctacta +gtatcatcagctgtcttgcctcgcctagaaatatgcattctatcgttatcctatcaacgg +ttgccgtactgagcagccttattgtggaagagtaatatataaatgtagtcttgtctttac +gaagcagacgtaagtaataatgacttggaataccaaaactaaacatagtggattatcata +ctcaagaactctccagataaataacagtttttacgatacgtcaccaatgagcttaaagat +taggatcctcaaaactgatacaaacgctaattcatttgttattggatccagtatcagtta +aactgaatggagtgaagattgtagaatgttgttctggcctcgcatggggtctaggtgata +tacaatttctcatacttacacggtagtggaaatctgattctagcttcgtagctgactata +ctcaaggaaccactgctcaaggtaggagactagttccgaccctacagtcaaagtggccga +agcttaaactatagactagttgttaaatgctgatttcaagatatcatctatatacagttt +ggacaattatgtgtgcgaaactaaaattcatgctattcagatggatttcacttatgcctt +agaaacagatattgcccgagctcaatcaacagttttagccggaaacaatcgaagcatagg +gacaatgtatcttttcctaaattgccatgtgcagatttctgagtgtcacgaagcgcataa +tagaatcttgtgttgcctcaactcgttgaaaagtttaaaacaatcgcagcagtctttttg +gggtctactgtgtgtttgcaaaataactgaaagaaacgcttgaacaactctgaagtagct +cgagtactcattaaagtgtaacacattagtgaatatcggccaatgaaccaaacgcttccc +ggtacgctatctctctcatcgggaggcgatgtgcaggttatctacgaaagcatcccttta +cgttgagagtgtcgatgcatgaacctcattgtaacaatagcccagcaaattctcatacgt +gcctcagggtccgggcgtactcctccatggaagggcgcgcatctagtgttataccaactc +gctttttaactactatgctgtagttctacaggcatagtggccagtattttctaacttctc +tggatagatgctctcactcctcatccatcacggcttcagtttacgtcttacttgcttgtt +cagcaacggatggaggcattaagtatcttcactgttccctaaaattgctgttcaatatca +aagtaaggacgatacagggaaagctcaagcacactcattgaatactgccccagttgcaac +ctcacttaatctgacaaaaataatgactactctaagtgttgcggaagcagtctcttccac +gagcttgtctgtatcacttcgtataggcatgtaactcgatagacacgaacaccgagtgag +aaactatattcttgcttccgtgtgtgtgacaccaggtaattgatgcggatataagctgga +gatcactcacgcccacacaaggcgctgctacctctttattccaatgtgtaagaatttgct +aacttcatttctagaccgcagctttgcggtcataatttcacggtacggacccttgggtta +gagacttgataacacacttcgcagtttccaccgcgcacatgttttagtggcttctaacat +agaatttttgttgtgacataaagagtgcgtgggagacttgcccgaccgttaagccataat +caattgaaagccccgtgagtcacatctaattggttgtactgcgcatttagctatccttta +gctgactcgaagagattcgattcctaatataggttaattagatggctgccgcgcgaagta +aaacgtgaaaaacgtagtgcgcagatctgcataactcgcgcttaattacttatgagtagt +tccaagttcgctacgttatgagagagattggaattaagcaaatatgttttatggtgattt +tgggatgagaaggactgctaagtacggctactaaacaaatttctaaaaccgccatctacc +ttatcttggagacatttaagttgtatatgtcactagtctagcttttgtctgtgggacgcg +ttctcggaatgagggaaatgcaagagccgattcatcaaatgcttatctaagaaagtagtg +gactattacaccaagcacgaatgccagggaactgctttcttgctcaggacctcgcgacaa +ggtaccccgcataagtcctagaattacatttggtcagcaatgctgacatttgaccgtgaa +aacataattttaatcagaaggcagctcacccgcttgctctagatcttatctttgtatgaa +tgtcagaatttactgcaatatccgttccgaatagtgagggcttagtatagttctctgtat +acaggtcacatcaaactccccctgtcctagtacagctctgagctttaattaattgcatac +atttccttcaatcatcagatgaaaacaccgcgaatcatgctcttctcgtatagggcaaga +gaagcaacaaacaactagcccgactcacgttcatccgccgtatccttgttcagttcttac +tccgtattaggtcagcgaaatctaatcagaataatcggtcgcgtatcaaaattaaaatcc +cgcttgaggttgacaattaaaacgctgagcagttatcggctattagatagtggggtgaaa +gtaattggctggaattatgttaaaacgtgatattaagctaaaatacgctacttgttgccg +acctaattcagtcattcgatattcagttagagccaagaataacaagcttgtataaattga +acggggtgcactaaacgatgtgttactctaatattcagcttggagtatacctgaaggcga +attcatgtatcggccaataataagacgttgaagatcacaatttggactagcaaaagaagg +tgatttatgcgtggggattgagtccactgtacgagtacggtctctggaaaattataggtt +cagggaatataaggaagtaaagataattaccaagagatttttggtatcgctatgacccag +aggtgttctaacgtctgttttgatccgcagaatttctgcctcaatgcatatttgacggac +ttgaactagagcctctaaagttaaatggcgacgcaactgttcctaaacttcaattattac +tactctttttttcctagggtattgtagaggccagtggacaaaataaatcaaatttaagat +gtttcggacattaacatcccccgtagcatagaaatcatcagttatccaatctctcatcga +gcttttacaatttctgctggcgctatggacagcatatgccgcgagacctccgcaagactc +acttgatcactgtaagtatcttcattagaggttagagcctatagttaagctgctgaccta +gtaaaattggtattttctaattttattgctcaagttaaaggttagtgaagggataatgac +gttatttttgaacaatgggttgtattcaattttatatcacgaatggaacccttcattccc +ggcataatactagacgacacgaacaagctccgatctatcagccaggcacgtgttaaggtt +taattccggcaaaccaatgaagcatcaaaaggtgacctgatgcaacttagggtcacgatg +agtttttcaggactacttattacctattaataagttaacatgagccttcataccccgtaa +gacaatacatactccaccaattagaattctgagccatcttatctttttgtatcatcgaag +ggtatggccgaataggttaattagttactcctaacgtctctacaggcatgcatttgacgc +accttcgaaaatagtcaatctctcgccacacgcgtctagtatgcagcatcaaaaatatag +tccacggtttccggattaccaaacgcggcaaagagaaacattgtatcgacggagataact +taatacagaaggaaggggcatcttcgaatacggatgaataattctatctgtttattctga +catcttgttttcaggttaatcttacgcattcaaatgacgcctgccccatgcgtgcgcaat +tattttctaatattgacgagagcaatctcactccttttgggtctatttatgttttattga +ggcacaagcctatacagaacaggtactattaaggccgtgagtgtgagactcaaaccgtgg +aaacaaaggatgggttgttcttggtacaagttttagtgcatgtgggcaatccttaccaaa +atcagatgctatccttaactttgggctgcatttaagatggcggttggaggcctgtgagaa +tcctgcgtgtcatctttaatgaccgaattcatccatgtagattcagatcacacactcatt +ccttgatgttgtctaaacaaaagttgttgtggacgcattggagggagttaagtaacaact +tgggatcgcatacttataaaaattatatgttaaactttcacaaacgctgaagtccaaagt +aactagcccaaacgcctcgagagtcactaggtattaatggtgtttgagttcctgtgaaat +agtgttcgaaggtaaaatttatgtaccaaatcgaaagaacacttaataaggcttgcttgc +acggaggtatgatgtttactgactctacaaccctaattttccagtacgtacattcattcc +aataggttagttctcaaagtgctatacaggctcctcaattgatgatatgcttcagccgct +ctatggatattagctcattttatttaggaagcccgcttagaggcttactatgagggaaat +gccaaaatgtcatacttttcggtgtgtcccatatgacaccgctttacatagaatttgaat +taaaacgcgctctcccgttcactaccatacttggtaccgtgcgcatattacatatagata +taggatcattttttaaagctgtactaggtttgatcgacaatcttatgctatactatatga +tgtaaccctcataatcaataccgatcgtacgatcctagcataggtggcaagcgattttat +gccgattattgtgttaaatagtctgtgagtgtgattatcagggctacgttggtagagggg +ttgtatagacctcgcacacattgtgacatacttaacaatatacgaaaactgatataataa +atccccttacccaaacaccaatcccgttgaatcaactaccataacgtctcccatataaat +tgcctacttgtttgcataaatctgaatacataacaccattgcaccttcttgtgttccaat +cccgttaagattgccttgtcagatgatatgcaagaacaatagcatttgctagcaattatt +aacagctcttcgaattgcctccacataacgcgggagggtatattttaatttggcaaatac +taagtactgttggcgtcatatgctattaacggttggatattaagttatgtcagccgtaag +caagagtgggcgaaatattttgttacccagtgagagcactcttagagtttggatacaata +ggccatatgttgacttaagaggacgtaactacgccgtacaccattgttcaaccgacttct +tggcaaatagaatcgtattagcaatcttaagaatagagacacgttcgtgttagggtatac +tacaaatccgaaaatcttaagaggatcacctaaactgaaatttatacatatttcaacgtg +gatagatttaacataattcagccacctccaacctgggagtaattttcagtagatttacta +gatgattagtggcccaacgcacttgactatataagatctggggatcctaacctgacctat +gagacaaaattggaaacgttaacagcccttatgtgtacaaagaaaagtaagttgttgctg +ttcaacagatgatagtcatgacgcgtaacttcactatagtaaattgaaacaaatacgcaa +tttagacagaatggtacggtcatgaatgacagtaattcgaagtgctagaccaacttaaaa +taggtaaacgtgcccgaaaccccccttaacagaaagctgctatcatggtgcagtatcgac +gtgttcagaaacttgtaacttttgagcaggtccgagcacatggaagtatatcacgtgttt +ctgaaccggcttatccctaagatatatccgtcgcaaactttcgatttagtcccacgtaga +gcccaagcgttgtgcgactccacgtgcatgcccagaaatacgagtttaaatttggttaca +tggttaattttgaccgaagcatcgcactttatgattgataattggattcaatatgtcgcc +ctatgcgaatgcaacatgatccacaatttggctataagacgtttaatccgtatcacactt +tgtttgcggctagtatagtaacgcccgtgcaccaagagtcagtaacaattataagtactc +cgcaggtacttcaaatataaaaactaatcaaacacgacccatatgatcatctgaagatat +ttggaactttctcgacaaccaccctcgtactcaatacttacactaatcgacaggcacacg +caacgtgtacagtcgcaccatattgagtcaagatttgcttagtggcgatgagcgtacacg +cttatttctctagtcacaattagttatctacgagacatcacgagggagcaaataagcgat +gttatggctacacataggcacgtatgaatatgatataagccagttaaacagtcgaaccat +cgagcaaattctcatgcaccaacccacacgttgaggcacaaagagtaagctgtttgaatg +taacttcttctgctgagcgggccccaacgtaaggatcaactagaagagaaaactcggtat +tagtttaaatgcgtcacggagcatgagtgcatttcactaagaatgtctgtgtaaccaata +taacatctatttgttatctgattgcctacttatggctttgcggtcgtggcgactaatgtc +tccaatccttttgaggtcggtaccaactccctttaaattacgctgtgcaggctcatgcac +tgcatacatatacggtagcaggtagggacctcacgcacccttattataatcaatagtagt +tatcagtcaacgaggcaggaatgctgaggtcgaggtgttggtatattttctatgtgccgt +ctaggcgactatcacgcattaccaggcgagatttaagccaattttgaatatagtcaacgt +aatttttactatgggttccaccgaaacgccttgcacaactaagaatcccataaaatatcg +atatcaaataaaagattgtgtcaataccttcatatatattttttcggttgactaacgtga +actaaggttaggggttttgtatgtctatataggaaacagtttcttttctgtcctacttta +gtaaagtcttcaagccttactccaaaatcacggtgattaagccgttactcagcagcatga +ttctgcctgctcgggtcctaaaatccagccttgtaagagtcgctgtgtattagctaggga +gacctttgttaaaaaggatatatcgcggcgggatgtgagtgcgtggcgcatactcaatct +tcagctcgtgtcattataatatctctcccccacgcttttcactagatatgccgtgtaagc +aaacaccttatgcttaatttcgaaaatattggtacttgaaaaaagctgtaggggtactta +atgtctggtaggagatcaggagagaattgagtgtaaaaccgtaaagccctcacctgactt +catgtaaatggcttagaagactccatgatttaataaatactacgaaggaaagactggatc +taaagataactctagtaaggccaactcccttcaatgctgttgccagttataatccaagag +ctgtccttttctgaaccatagcggcttctgaagcgaactagaagcaaagttggttctagc +cagacagccacataccctgtacgggtgtattactaaaactggtccggtattagttcacca +agggaggaattaggcaaaggatctaggtatgcaagtcggagtattacatccctaccctga +atccatcaataggttcctctgtactggccttcgcaatgagtattcaaggttgtacagccg +tataataataagatagtgactatgaacgggaagtaacccgctcaccttccccaaaacatt +gttatatctaagtattaaagtctgccgtagtgttaatactcgaaaataaacaactggcaa +attacaccgcacttaagccgcttttgatttatatttttccaatgcgcttttaaaaataat +tcagtcctacatactaattaagacccttaaacggagatatcacaagttaagttttaacca +tctcgactaggtggaactatagatacccaactcaatttatcattacctgtaatgttccta +gaaggattgcatttcatgtcaagacggtggagtttcacagcgaaacttcagtgtgaacag +attctgagaaatcacctaaacctattagtcagagcacccggttagaaccagttgtcaaaa +aatagagcggttgcatgagacagaagtaacgatgagatccgttgtaacgttgagacatct +ggcctatcgtcaatacagtcctcccttaaaaatatttttaaatactaggcaaacccaaca +taggttagtcctatgtgatacgccacatggtatatcattttgtaacgttacctagggata +atcaggaagtggaattacgcaaaagtagacagtgaaatgcttagggttatagtctagtcc +aaagataaaggataaagcacgtcagagaactatattagccgaatgggaatcattgttagg +agactgtggatcatgtctaaaaagcaacgcagaaacagtcatcgaaaaaatctcgttttt +gtttgaatctaaaagagctttgatgaccgatagtacctgtatactagttactgtattacg +tgtctaatgatttcggattggggtccccagaatcagacgtcattgtagacgattcaagtt +taccaatttaatttcccagctctccttggagaactatcgccaataattgcagtcactttc +cttttctgaaacgataaagccgtcagagttctctgcaacgttggacttacctgaggttct +aacccactttcggttctaatagtagttaacgacacaacgaataacctttactgtggggct +ttcacgatattttttcgcttattattaatggttacgtcataagctggtgtccaaattaag +gttaccggcttcgcagagtagttgtatccaagtataacttccctaatcataagatcgagg +tagaaaattaatgctgtctctaaccgaacagatatgtcccactatgtggtatggacgttg +ctaattacttctgaagggaaattggtcattatggatacgtgtctaccatcaggtcggacg +cagatatggttctgtcttcagttgatccaccgttctttataggataataactgacgatta +aagattatggtaaatagattaagccaattctcttcttgtcagtgaagcatccttaactga +cttgctctgcagcccctcatacatttagctattcaaagtaccggctcgtttcaaactctc +ccacctttggaagaggttgtcaacttgataagtatatcatttacagcattttttcggacg +tacctctaatgtttcattgcagaaaattagttttttctatcgcacattttgcaagtaacg +ttagagacacaattatctgcgaatgaactgctagatctgacgaccgggagcctcgcaaat +atcaaaaaagactgacatatatcaaggagtcgttgacaagtgctggtaagtcaattggtt +tatctgtcccggcgtttcgatcttaagctgaccatgcacggcagagtaatgtcactctcg +ttcttacaagtctgtctccaagggtcggcaaaaaagacccctccattctcgagcccactc +acgatatgtagggacgacaacttgtgcggcttatgaattgtctggactgcgggcgagggt +ccatatctccgaagttagaagggacatacctttagatgataagatcaattcttattgacg +aaattcatccacaacggggaacaacttcaccctagacttacgtctgaaaagacacctagc +gtcttataaaaggtcagtgccccgtttcgtaaggctggaattacctacgcaaacttaaac +ctcgcgcccttccttacgtatcgacaagatagaggctatcgcgaatgtactacggaggca +tgaatcatatactagaaccaagtgcctgtgatattaacaagatgatccgacgcgagcacc +gtaattctaggcataaaactccagcaatttgggggccgaaaacaaatgacgttagctaat +taattatatgacatgatcaaaggaggtcaatcacgcatcgagttcgacgtatattcattg +aacttcgtgcgtttgaaagaaacttttatgaaggcaaaattgatcctgtctcctatttca +tgcgtacctcctagttgataattccccgagcagtggttaggacacttttgtcggtatcaa +gttccggtctcaaaacgtaaaattctgtaatctgtatggatggtctgtgaattagttaat +ttttatgaagtcgtcgagacgcagttcctattgatttattctaaacggagatgtgcttcg +tgggactcggaagtagatctgtgtttatgattattgctactttagatgctgactgttaac +tccgtgttgtttttcaaccgtatatcacaaccgaattggatagaacctatagtttcaagt +tctgccacaaggtatcatatttacagttagtgctggttgcttctttcaaacgtggtgagt +ttgtgctatcacgtcaacggtagagctcagtggaccgagtgcgcgttcaaccctgttcca +gagagggtgtgatagcacatataccacgctcgtcgaggcgttcatgatagtttgcaagag +ccggtgttaaacacatattattattgttatccaactaatcggacctatgcataaagcatt +gtctaaacagaataattgcctatatacggtagttttagtgatttatatcttagtatcagt +tagagcttcgaactcttcaggttcctcatatttaacgttcttcgaaagcgaaaacttcta +caaacgaatgtaagcggttttccaagtagtacctataaatcacagaaagatctgtctcag +tatagttgaaatggtattcagctagtgacgtgtaccaattatcatagttcactcaagcaa +gacgctcattaacgaatatagacaagacactatatcatataataaaaaagaacatggtgc +tcgaacatagttgaattcaccatattgaaggggaatgctgacatgtaattcgctactaga +cgatcaattccctacttgtcaaagttgaactggtacgttcttggaattaaatatgattgc +gctggaccaaattgcgacttcttgagtttcagggcaaacgattgagccggaggatgtccg +tctcttacctttcttgcttatgataaacgacggtccctgtacatcactgggaattctcag +caaaaataattgggtaaatcgagactcgatgtattcggccacaaaggtgttagacgttaa +agattattcaacggggcgataataggatcataaccggtatgcaagcgcattgaaagagcc +atgagatccttatccgataaacgctgcacggtatgtgcagccttattgtcgatcacgaat +ttataaatgtagtctgggctgtaagttgaagacctaagttataatgaagtgcaataccaa +atcgattcatagtggattatcagactcaagatatctcctgataaattacagttgttaaga +tacggataaaatgagatttaagattagcagcctctaatctgtttcaatcccgttggaatg +tggtatgcgatcaaggttaagttaaaatcaagcctgtcttcagtcttgattcttgttctg +ccatcgcatgcggtctacgtgagttaatatgtagcttacgttctagcttgtgctaatctg +agtatagattcgtagaggaatattatcaagcttccacgcctcaacgtacgtgtattggtc +acacaagacactaaaagtggaagtagcgtaaactatagtctagttgttaaatgctcagtt +cttgttatattcgatatactcttggctaatttatgtctgagtatataaaattaatgatat +taacttgcatttcacggatcccttagaaaaagattttgaccgagcgcattataaacggtt +acaccgaatcaatagaagcatacccaatagctttctttgaatttattgcctgcgcaactt +ggctgactctctagatccgaataattctatatggtcgtgacgaaactagttcattactgt +ttaaaatgccaacatgtcttttgggccgataatggctctttgcaaaattactcaatgata +cgattgatcaaagcggtagttgctagtggtagcatgtaagtctatcaaatgtctgattat +ccgaaaatcttccaaaagagtccacgtaccatatctatctcatagcgacgcgaggggaac +cttatctaactatcattccatttaccgggtgactctcgatgcaggatccgattgggataa +attgcccagaaatggctcattcctgactaagggtaaggccgttctcagcaagggaacccc +gcgaatctaggcttataccatctagattgttaactacttgcctgtagttctacagccata +ctggacagttgtttctaaatgatcgggattcatgctagcactcctctgaatgcaccgcgt +aagtttaactattacgtccgtgggcagataaggatggaggctgtatgtatcttaactgtt +acctaatatggctggtaattatcaaagtaaggaccttaatgccatagcgctagcaatcgc +tttgtatactgaccatgtgccaacctctcttaatctgtaaaatataatgtcttagctaac +tgtggacgatcatgtctctgcctagagcttcgctgtatcaattcctatagccagcgtact +agtgacacaacaacaccgtgtgagaaaagatattagtccttacgtctgtctctctacagc +ttattgatgaggattgaacatggacatatagctccccctcaaaagcagatgctacctctt +tattccattctcgaacatttgccgaacttaatttcgacaaacctgaggtcacgtcttaat +ttatcggtaacgtcacgtccctttgagactggataaatatattaccaggggccaacgagc +aattgttggaggcgcttctataatacaaggtgtcttgtcaaagaaagacggcgtgcgtct +cgtgcaactcacttaaccaatattaatgtgaaacccccctctctcacatcttatgcggtg +tactgccctggtacatttcctgtacaggactccaacagtgtagattcctaagatagctgt +tggagttgcctcacgccagatcgaaaaactgaataaactagtgagctgagctgcagaaat +accgcttaattacttatgactagttcaaagggacctacgtgatgtcagacattgcaagga +agaaattaggtttgtgcgtcattttggctggactagcactccttacttcccctactattc +aaatgtcgtaaacagcatgagacaggatcgtgctgacatttaaggtctattgggaacgag +gctacctttggtcgcgcgctcgcgttctccgaatgaccgaaatgcatgagcacagtatgc +aattgcttatagatctaaggtctggtcgttgaaaccaagcacgtaggcctgggaaatcag +ttcttcctcagcaactacacaaaagcgtccaagcattagtacttgtagtaaatgtccgaa +cctatgcgctcatttgaaagtcaaaaaatatttttaagcagtaggcacctaacccgattc +ctctacttagtagctttctttgattctcagaattgactgcaatatcactgcacaattctg +tgccattactagacttctctgtattaacgtctcatcttactaacactcgcctaggacaca +tctgagagtgaagtatttcaatacatttactgaaatcttcagttctaaaatccccgaata +aggctcttatcggtttggccaacacaagaaaaaaacttcttgcaccactcaccttcatac +gcaggagcctggggaacttagtaataactatttcggcagacaaagcttataacaagttgc +cggcgcgtataatatttaaaagaccccttgagctgctcaattaaaacgctcacctggtat +aggctattagatagtgccgtcttagtaaggggcgggaattatcggataaactgatatttt +gataaaataaccgacttgttcacgacataagtcactaaggagattttatctttctccaaa +gtatatcttccttggataatttcaaagcgctgcaatttaagttctgttactagtttatgc +tgctgggaggtgaccggaaggcgtagtaatctagaggcaaattataagaagttcatcata +tcattttcgactacaaaaacaaggtgttgtatgccggcgcattgtgtaaactggacgagt +accctagatggaaaattatacgttaagccaagatttcgatgtaatgataattacctacac +atttttgctatccataggaacaagagctgttctataggctcgtggcatacgaacatttgc +tgccgctatgaatattggaagctcttcaactacagactctattcttaattgccgtcgaaa +atgggccgaatcggctattattaatactcggtttttccgaggggattgttgtcgacagtc +gtaattattattaatattgatgttggtgaggtcatttaaatacaaccttgcagacaatga +ataagggatccaatctctcatactccttttacaattgctcatgcccctatgcaaacctta +tgccgccacacctccgcaactctctcttctgaactgtaagtagcttcattactggtttga +gactatactgaagctgatgacattctaaaatggctattttcgaatgtgattcataatgtt +tatcgtttgggatggcagaatcacgttatttttgatatagcccgggtattctattgtata +gaacgtatgctacaagtcattccccgaagaagactagaagtaaacaacatgcgaccatcg +ttaagccacgcaaggctgtagctttatttcccgataacctatcttccataaatagcggac +agcaggatactgacgctcaacatcagtggttatggtctaatttttaacttttaataaggt +aacttcagcaggcatacacagtaactctttaatttataatcaaattagaagtctgacact +tcttatatttttctatcatccaacgcgatcgcccattagcttattgtgttactaataacg +tatctaaaccaatccttttcaagctactgcctatattgtcaatatatacaaacaacagga +tagtaggctgcttaaaaaatattgtcaaccgtgtacgctttacaatacccggaaatcaca +aactttgtagacaacgagtgaaatttatacactacgaagggccagcgtacaagacccatg +aattaggcgatatgtttattctgacatattggtttatccttaatctgtcgctgtaaaatg +aagccgcccccatccctgcgaattttttttcgaagattcacgactgaaatataaatacgt +ttggctatatttatgttggagggaggcaatagcctttactgttaaccgaagatttagcca +gtgagtgtgacactaaaacactggaataaatgcaggcgttcttctgggtaaaaggtttag +tcaatctcgcctataagttcatatagctctggatataattatctggcccatgcatttatc +atggcgcttggtgccctgtgtgaagccggcctctcatattgaaggtccgaagtattccat +gtacattaagatcactctctcattcatgcatcttggcttaacaaatctggttgtccaagc +tttccaggcacgtatggtacaaattcggatcgaatacttataaaaatgatatgttaaact +gtctaaaacgctcatctacaaagtaaagtgcactaaccaatagagtctcaagaccgtgta +atgctggtgcactgaatgtgtaatacggttagaagggattagttatgttacaaatccatt +gaaaacttaagaagcattgcgtgctcggagggtgcatcttttatcaagagactaacatta +ttttcaacgacgtacatgctttacaatagggtacttatcaaacgccgagaaacgcgccta +tagtgatgttatgattatgacccgatatccattggaccgaattttatgtaggttcccagc +gtactcgcgtaatatctcggtattgccataatgtaatacttgtcggtctctcccagatga +aaaagcgttacagagtatttcaatgaaaaacagcgcgcaacgtcaatacctttaggggta +acggccgctgatttcatatagatatacgataagttggtatagctctactaggtggcatcc +acaatcgttgcatttactatagctggttacaatcataatctataccgttccttacatact +accatagcgggatagcgtttttttgccgttgattgggtttaagaggatgtcagtctcatt +atatccgattcggtgggagagccgttgttttcaaatcgcacactttgtgacataatgtac +aagataacaaaactgatataagatataaactgtcaatatcaccttgacacttgaatcaaa +gtaaattaactcgcaaatataatttgactaattgggtgcagatttctcaattaataaaaa +aatggcaccggatgggcttacaagccccttatcattcacttgtatcatgatttccaagaa +caatagaatttgctagcaagtatgaacagagattcgaattgcatccacagtacgccggag +cgtttattttaatgtggatatgacgatgtactgttggcggcatttgctagtaaccggtcc +ttatttacgtagcgcacacgtaagcatgtctgggagaaatatggtggtacaatctcagag +aaagattacagtttggtttaaataggacttatcgggtcggaagtggaacttaataagcag +tacacaattgggcaacagacgtcttgcctattacaataggattacaatgcgttagatttc +agacacgttcgtgtttggctattcgtcaattccctaaatagttagacgatcaactattat +caaagtgattctttgttcatcctccattcatgtaacagatggcacactacgcataacgcc +gaggaattttaacgagatttaagagagcagttcgggcacaacccacttgactttataaca +gctcggcagcataaacggtaatatgtgacaaatttccaaacgttataagaacgtatgtgt +acttagaaaactaagtggttcatgttcaacagatgtgacgcagcaagcctaacttatcta +ttggttttgctataaaagaacaaagttacacagaatcctaagggcttgtttcacacttat +gcctagtgcttcaccatcttaaaatagcgaaaccggcacgaatcaaaccttaaaacaatg +cgcagatattggtgatggtgactccgggtatgataatggtaactgttgaccagcgcccac +ctcatcgaagtatagaaagtggttaggataaggatgagaccgaacttatttccggccata +actttagattttctacctagtacacaacatcagggcggacacgaaaccgccatcacatca +tataccaggtttaatttgcttaatgggggaagtgtcaacgaaccttcgaactttagcagg +catatggccattatatatggccccagagcagaatgctacagcagacaaaatttggattta +tgtagtttaatacctatcaaacttggtgtgaccatacttgtctaacgacagtgcacaaag +tgtaagttacaattattactactcagcagcttctgcaatgataaaatcttatcatacacg +tcacatatgataatatctacttagggggaacgggctccacaacctacatagtactcaata +cttacactattcgacaggcacaccaaacctgtacagtcccaaaagattgagtcaactttg +cagtactgcagatcacagtaatagcttagttagcgagtcaaaattagttttctacgagac +tgcacgaccgtgcaaatttccgatgtgttggctacaaatagcaacgtatgaatttgtttg +aagccacgtaaactgtacaaccttagagataagtctcaggctactaaaaacacgttgtgg +cactaacaggatcatggttgattcttacttattcggctgaccggcccaataagtaacctt +caactagaacagaataatcgggagtagtttaattcagtcaaggtgcaggtctcattgtaa +ctaacaagctctgtgtaaccaagttaaaatcgttttcttagcggattccctacttatgga +tttgagctcgtccacaatattcgatacaagaagtttgtggtccgtaacaacgaaatttta +attacgctgtgcagcctcatccaaggaattaatagaaggttgatggtaggctccgaacgc +tccatgattataatcaagtggactgtgcagtaaacgaggaaggtatcctgacgtcgtggt +gttcgtttttgttatttgtgccctatacgagtagataaaccatgaacagcacagtgtgaa +cccatggttgattttaggctaccttatttttaatttccgttacacagaaacgaattccac +aactaacatgccattaatttttcgatatcttataaaagatggtcgaaattcattcattta +ttttttttcggttctcgaaagtcaactaagctgtcgcgttttgtttctctttagaggtaa +aagtggctttgatctcctacgtttggatactagtcaaccattactccatttgatccgtga +gtatcacctgtctaacatccagcattatgactcctcggcgaagaaaagacacacttctta +gagtcgatgtgtattagctagggacacagttgtttaatacgatagtgagcccagggaggg +cagtgcgtcccccagtagatttattcagctagtgtaagtataagatatctcacccacgag +gttcaagtgatatgcagtcttagaataatacttatcctgaatttcgatattatgggtact +tcaataatccgctagcgctactttatgtctcgttggacagcaggacacatggcagtctta +aacactaaagacatcacctgaatgaatgtaatgggattacaagaatcaatgaggtattat +atacgacgtaggaaactctggatatatacagtaatctagttacgccatcgcacttcattc +ctctggaaacttagaagacatcagctgtacgtggaggaaccagacccccgtatgtagcca +aatagaaccaaagttgcttatacaaacacacccaatgacaatggaccgctggagttcgta +aactcggaacgtagtactgcacaaacccagcatttagcaataggagctacgtatgcaact +cccacgtggtaataccttcaagctatcaatatataggtgcctagctaatcgcattcgcaa +gcagtattcaagcttgtaaaccagtataataattacagaggctctatgaaacccaacttt +ccagctaaaagtcccaattaaatggttatttcgtacttttaaagtcgcccgttctgttat +tacgcgaattgattctactccaaaattaaacacaaattatcaaccgtttcatttatattt +gtcaatgcagctgtttaaaataaggctctactaaattataattaagacacttattaccag +atttctctagttaagtttgaaccagctcgactaccgcgaaagatacattcccttctctat +ttttcagttcatctatgggtcagagaagcattgaatttattctattcaccctcgtcgttc +acagcgaatcgtcagtgtgatcagtgtatgagaaatatcctaaaccgtttagtcagacca +cacgcttagaacaagtggtctaaaaagactgccctggaaggagtaagaagtatacagctg +atccggtgtatccttcagtcatctgccctatactaattacacgacgcaaggaaaaatagg +tttattttctaggcaaacccttcataggtgactccgatgtgttacgaatcatgcttgaga +atgtgctatcgttaccgacggataataacgatctccaatgaaccaaatgtagaatgtcta +ttgattacccttttactattcgacttagagataggagatagaacctcagtgtactttttt +agccgaatgggaatctttgggaggtgaatggccataaggtcgtaaatccaaccctcttaa +agtcttccatattatatcgttgttcgtggaatcgataacagatttgttgacccatagtaa +atgtatactagtttatgttgtaagtgtagattgttttccgattgccgtccaaactttatg +tcgtaattgtagaccagtaaagttgaccaaggtaagtgcccagcgatcctgcgagatcga +tcgccaatttttccagtcactgtaagtgtaggtttagataaagccgtatgagttatatca +taagggcctcggaaagcagcttcgaaccaaagttcccttataatagtagtttaactataa +aagtatatactggtctgtcgccctttcacgatttgttttaccggtttatgaagcgttacg +tcattagagcggctccaatttaaggttaacggcttccatgtgtagttgtatacaaggata +acttaaagtatctgttcagcgagctagttaagttatcctcgatagaacacaactcagagg +tcccaagatcgggtttgcaacttgctaatttattctcaaggcaaattgggaattatcgat +acctgtataccataaggtcgctcgatgtgatgcttatgtcttctggtgatcctaccttag +ttagtgctgattaacggaacattaatgtttatcgttttgagatttagccaattctctgat +tctaactcaagatgccttatctgacgtgctatgcagcccctaagtattttacattgtaat +aggacacgctcctttaaaactcgccaaaaggtcgttgtggttctctactggttaactata +taatttacagctttgttgagctagttcctctttggtttaagtcctcaatattagttggtt +cgagcgataagttggctagttaccttagtcactatattagatccgaatgttatgcttcat +ctgaagaccgccaccctccaaaatttcttttaagactcacttattgcaaggtgtaggtga +attcggctcgtttctcaagtggtgtatctgtacacgagtttccatattttcatcaacagc +caccgcacacttatgtcactctaggtattaaaagtcgctctacaaggggacgcaattaag +aaacagacatgctagtcaaaaataaacatagcgaggcaccactaattcggccgcttatca +atgggatgctctgcgcgagacgcgccagagctcagtagttagttcggacatacatttact +tcagatgatcaattagttttctacaaatgcttactctaccccgaaaaaagtcaccagact +cttacgtctctttagtatccttccgtcttatataaggtcagtcccccgtttcggtaccct +ggaatttactaagaataatgaaacagcccccaaggacgtacgtttacaaatgatagacca +gatcgcctagcttattccgacgcatgttgcatagaattgaaccaacggaatgtgagagta +actagatgagccgaccacagcacccgtttgcgtcgcagaatacgcctgatagttcggcca +cgaaatcatatgtcctttgagtattaagtatttgtaatgatcaatcgagctcaagcaagc +ttacacttcctcggatattcagggaacttagtgcctttgaaagatacgttgatcaacgaa +aaattgataatggctcatatggaatgcctacctcatagtgctgaattaacacagcactgc +ggacctaacttttcgaggtttcaagttcacgtctcaaaacctaataggctggaatatgta +gggatcctcggtgaatttgtgattgggtttgttgtagtactgaccaagtgaatattcttt +ttttctaaaagcagatctgctgccgggcactacgaaggagatctctgtgtatcattattg +cttcttgacatgatgactcttaaatcactgtgggtgtgcaaaacgatagcacaacccaat +tcgatagtacatattgttgatacttcgcactaaaccgttcatatttaaaggttgtgctcc +ttccttcgttaaatactggtgacttggtcctatctactattagctagacctctggggaac +cacgcccccgtaaaacctgtgcaagagagggggtcatacatcttagacatcgcgcctcca +ccagggaagcattgggtgattgaccaggtgtgtaacaaatatgattattcttatactaat +attagcaaagatgcataatgatttgtattaaatgtataattgaattgataagggtctttt +agtcagtgatagagtagtataaggtagacattagaactcttaaccggacgcagatttttc +ggtcttagtaagccaattagtcgacaaaacaaggtaagagcggttactagtagtacctat +aatgcactgaatcttcggtcgaagtatagttctaatgctatgcagattgtgacggcgaca +aatgttcagacttatatcatgaaacaagctcttgtaagtattgacaaatgaaaagattga +atatttttaaatacaaaatgcgcctacttattaggggaattaaccagattgaaggccaat +cctcacatgtaatgagataatagacgataaatgaaattcttgtaatagttgaactgctac +gtgatgggtattatatatgattgagatcctccaattgccgacgtcttgtcttgatgccca +aaagattgtcaacgaggagctccctcgcgtacctgtcgtccgtatcataaacgacgcgac +atgtacagcactccgaagtataagcaataataatgcgggtaatccagactagatcttttc +ggactcaatgcggtttcacggtaaacatgattaataccggagagtagtcgagcttatcag +cgatgcaagcgaattcattgtgccaggagatacgttgcagataaaaccggcaacgtatgt +caacaagttttggcgatctcgttgtttgtattcgacgaggcgcgggaacttcaagaacta +tcgtatattcaagtccattaccttttagtttcagactggtggagctgactaaagttatat +catcattttgtacactggtttagttaacgataatttcagatttaacatgaccagacgata +atcgctgtatatccagttggaatgtggtttgccagaaaggttaacttataatcaagcctc +tcttcagtcttgattcgtcgtatcccatccattgcgctatacctcagtgtatttggagct +gtagttataccgtgtgctaagatcagtagacatgacgagagcaatattatctaccttaca +agcatcaacggacgtctagtcggaacaaaagactctaaaactcgaacttcaggttaatat +actatagttctgtattcagcagttattcttatattcgatattatcttgcctattggatgt +ctgactttagtatattaatcatagtatctgccatgtaaaggtgccagtactaaatctgtt +tcacagtgcgaattataaacggttacaaccattaaagacaacaagaccctatagctttat +ttgaattttgtcaatgcgcaacttggagctcgcgatacatcccaattagtctatagggtc +gggacgattctacggcatttctggttataatgacaacatggattgtggcccgagaatcgc +tctttcattaattaagcaatcattacagtcttataagcgctacttccgagtggtagcagg +taactcgatataaggtcgcatgagccgaatagcttaaaaaacaggccaccgaacattgat +agagaataccgaccacagcgcaacctttgattactttcattaaattgtacggctcactcg +acatcaagcttaagattgcgataatgtgaactcaaatggatcagtactgaagaaccgtaa +cccacttcgcagaaagcgtacccagagaagatacgctgttacaatatacagggtgaaatt +attgcctgttcttcgtaaccatttcgccaaacttggttagaaatgatagccattcatgat +agaaataagctgaatgataccagtatctttaactatgtagtcagggggaagataacgatg +gtccatgtatgtttctgatatgtgacagtattggccgcgtaatttgctaacgaagctact +taatgcctttgagcttcatatagatttctttaatcaaaatcggcaaaaagatagtatgag +ctataatatatgctagtagagaactctggaccatcatctatatgaatactgattcgagcg +tgcaattactttagcctgcgtactactgactctacaaaacactctgagataagtttgtag +tcagtaagtcgctctctataaaccttttggatgaccattgtacagccacttatagatccc +aataaatagcacaggagacagagtttttcaatgctcgatcatttgccgatagtattttcg +tctaacctcagggcacctattatttgatacctaacctaacggccctttcacaatggagaa +atatatgacatcgggacaaacacaaatggtgggtggccaggagatatgacatggtggcgt +ctctaagaaacacggactccctctaggcaaactcacgtaaccaattttaatgtcaaacaa +aacgctcgaaaagattttgccgtgtaatgacctggtacattgactggtcaggaatacatc +actgtagttgccgtagtgtcctgttggtgttccatcaagacacatcgtataacgcaattt +acgacggacatcagatcaagttatacagattatttaagtatcacgtgtgcattgggacat +aagggatctcacacatgccttggaacatttttgctttgtgccgctttttcgctgcactac +caatccttacttaccagtatattcaaaggtcgttaacagaatgagaaaggttagggctct +aagttatcgtcgattgggatagacgagacatttgcgagcgccctccacggatacgaatct +cccatatcaatgtgaactggatgctatgcagtttagttcttacgtctcctagtggtaaaa +atcaaagtagcactcgcatagcagttattcagaacctaatacacaaaaccgtcaaacatt +ttctaattctaggtatgggccgatcataggagctaaggtgaaactcataaatgttttgtt +agatctagcatcctaaaaagatgcatatactgagtagctggcgtgcattctctcaattgt +atcctttttaactgaactagtcggtcccatttcgtgactgagatctattaaccgataaga +ttaataacactcgcattcgtatcagctcagagtgaagtttttcaataatttgactgatat +attaacttctaaaataaccctttaagcctcggatccgtttcccaatcacatcaaaaattc +ttattccaactatctacggattaacaacgtgcatggggatcgtagtaagaacttgttccg +atcactttgagtatatcaagttgacggcccggttattattgaatagaaacattcacctgc +taaattaaataccgcacatcggatacccgatttcagagggccgtcttactaagggcaggc +tttgttcggtttaactgagatgttcattattttacagtatgcttcaactaatatgtaacg +aaggacagtggatctgtctccatagtagatcttcagtcgtgaatttcataccgctcctat +ttaagttcgcgttcgagttgttgatcatggcacgtgaaagcaacccctagtattctagac +gaaaattttttctagttcatctgataatttgccaattcaaaaacaaccgctggtttcccg +gcgcattctctaaaatggaagtcgaacctagagccattatttgtcggtaacccatgagtt +ccttcttttcagaagttaatacactgtggtcctatacagaggaaaaacagcggttatata +cgatcgtggcataacaacattggatcaagatagcaatttggctacctattctaattctca +ctagattcggtattccactacaatatcggcagattaggattggatgaataatcggtgttt +aagtccggttgcgtctccaatctcctaatttttattaatattgatcttggtgacctattg +taaataaaaacttcaagactttgaataacggtgaaaagatagaagactcatttgaaaatg +gatcatccacagatccaaacattagcaagacactaatccccaactagctattctgatcgc +gatcgtgctgcagtactcctgtcacaatagtctgttcatgatctaattctttttgggctt +tgttcgatggtgattcagaatctttatccggtcgcttccctgtagctactttgtggggat +attgcccggggattatagggttgagatcgtttcctaaaagtatttaaaccaagtagactt +caactaaactacatcagaacatcgtgaagacaccatacgcggtacctttatttaccgata +acatttcttcaagaaataccggtaagcagcataatgaccctaaacagctcggggtatcgt +cgtagttttaaattttatttaggttactgctcaaggaataaaaactaactatttaattta +taataatattacaaggctcacactgattagatttgtctataagacttcgcgatcccccat +taccggattgtcttaagaataaactagataaaccatgcattttctagataaggcctttag +tctaattagatacaaaaaacacgatagttgcatccttaatttattgtgtcaaacctggaa +ccttttaattacccgcaaatcactttatgtcgagactacctctgaaatttattatctacc +taccgcatgaggacttgaaccatcttgtaggagttatgtttattagctaagattcgttta +tcctgtagcggtccatgtatattcaacaagcaaaaagcactcagaattgtttttagttga +gtcaagactgatatataaataagtttccctagttttttcgtggtgggacgatattgaatt +gaatcttaaccgaagagtttcccactctgtcgcacaataatacacgccaatatttccagc +cctgcttatgccttaatcggttactcaatctcccattgaagttcattttgatctgcatag +aagtttcgggcccagccttttttctgccaccttcctccaagctctgtagacgcactctaa +gattgatgctcacatgtattaattctacattaacataaatatataagtcatgcatcttcg +agtaaaatatctggttctccaacatgtcctggcacgtatcgttataatgcccatacatgt +agtattaaaatgattgggttaactggatattaagatcatcgaaattgtaaagtcaaatta +acaatactgtctcaagaccgtgtattcctcgtgctcggaagggctattacgcttacttcc +gttttggtatcttaatatgactttcaaaaattaagttgcagtgagtcctacctgcgtgca +tcggttagcaagagtataaaagttgtttaaacgaactacttgctttacaataccggtcgt +atatatcgccgtgaatccagaagattgtcttctttggattatcaaccgagatcctgtgga +ccgatgttttgggaccttcacagaggactccaggtagagctcgcttttgcattaatctaa +gaattgtacctctctaaaagatctaaaacagtgaatgtgtatttcatggaaaaacacaga +gaaacgtaaattactttaggccgaaaggcacatgagttattatacatatacgagatggtg +gtatacatcgaattcggggcatacactatagttgcattgtatttagctgctttaaataat +atgatattaccttccttacataagacattaccggcataccctggttttcaacttgtgggg +ctttttgacgatcgcactctcatttgatccgagtagggcggtgacccctgcttttcaaat +acaaaaatttcgctatgaaggtaatagattacttttcgctgttatgatagaaacggtaaa +tttaaaattgaaacttctagaaaagtaaagtaacgagaaatgattttgtgaataatgcgg +tcatgattgcgcaagtaagaaaaaaaggcaaaaggatgcgcggaatagaaacttatcagt +cacgggtatcttgatttcattcttcttgtcaattgccgacataggatgaaatcagattcc +aatgcaatacacagtaacccccacccttgattgtaatgtcgatttgaagttgtacgcgtc +gacgaagtggatagtatacgggccttttgtacggtgcgatcaactatgaatctcggcgag +ttagatggtcgtacaatctcacacatagaggtcacttgcctgtaatgacgaattttcggc +taggtactcgaactttattagaagtaaaaatgtgggcaaaagaaggattccattttacaa +gacgattacaatgagttacatgtctctcaacgtagtctttccctagtagtctttgaacta +tttaggtactccagaaaattttagcaaagggtttctgtgtgaatccgccattcatgttta +tgatggaacaataagaataacgccctcgtatgttatcgacagtgaagtcagcagttcggc +caaaaacatattcaatttagtacagatccccagaagttaagctaagtgctctaaaatggc +ctaaacggttatcaaagtaggtctaattactatactaacgggtgcatcgtaataactgct +gtcgatgcaacactatatgatagtgtcgttttgctatatatgtacaatgtgacaaagaag +ccttagcgattcttgcaaacttaggacttcggattctcaatcttaaatgtccgaaaacgc +aaagattcaaaaatttaatctatgagcagatatgcctgatggtgactacgcgtatgttaa +ggctaaatgttgacaaccgcacacataatcgaactattgatagtcgggagcataaccagg +tgaacgtactttgttcacgacatttattgacatgttctaaatacgtctcaaaatcacggc +gcactagaaaacgcaatcaaatcattgtcctggtttaagggccgtaatgccggtagtgtc +aaacttcatgagaactttagctggcttttggccagtatttagggaccaagagcactagcc +ttaagctgaatattttgccatttatctactgttataactttaaaacttggtggcaccaga +cttgtcgatacacacgcatcaatctgtaacgtaaaaggtttactaagaacaagcgtagga +attgagtttatattatatttaaactaaaagatgatattagcttctgagggcgatagggct +ccaaatcataaagaggaatatattattacacgattagaaacccacaacatacctcgaatc +gcccaaaagtttgacgaaacttggcagtactccacatctcagtaatacagttgggagagt +ctcaaatgttgttttattactcaatgaaccaccctcataatttcactgctgttccattaa +atttgcaaacgatcatttgctttgaagaaacgtaaaatcgacaaaattacagataagtag +atgcataataaaaaaaactgctcgctataacacgatcatcgtgcattcttacttaggagc +atcacccgcacaataacgtaccttaaactacaacactattagaccgagtactgtaattca +cgaaagctcaagctcgcattgtaaagaacttgctctctcgtaaaatgtgataatagtttg +cggagaggattcaattattttccattgcacctactccactagattcgataaaagaaggtg +gtcctcccttaaaaagaaatgttaagtaacatcggaaccataagcaaagcatgtaagtga +accgtcatccttccctaagaaacataaaggtttttaataatgtcgactgtgaactataac +tgcatcctttcctgacctactccggttccttgttgttatttctgaacgagaccagtagat +aaacaatgtaaaccacagtgggtaccaatggtgcatgtgacgctaccgttgttttaagtg +cccgtacaaacataagaagtcataatcttacttgaaattaattttgccttttattttttt +tcaggctcgaaattaatgatttgttttttttgaccttctagttacgctaatatgcggtcg +cctgtggtttctattgagtcctataacgggatgggatctaatacgtttggttactagtaa +acaaggtataaatttgataccggagtatcaactgtataacatcaagctttatgactcata +cgcgaagtaatgacacaaggctttcaggagatcgcgagtacagagccactaaggggtgta +ttacgatagtgacaccaccgagcgcactcactccccaagtagatttatgatcctacgcta +agtattagatatataaccaaagaggttctagtcagtgcaactcttagaataataattagc +cggttttgcctttttaggcctaatgcaatattcagctagcccttatgtatctcgcgttcc +acagcaccactcatggcacgcgtttaaactaatcaaatataatctatgaatgttatgcca +gtacttgaataaatcaggttttttataagtccttgcatactctcgttatatactgttaga +gtcttaccccatagaaattctttcatctgcaaacttagaagaattctcagctacggggag +cataaagtccccaggatgttgacaaatacaacaaatgtggcttatacaaacactccatat +gaaaatcgaaccctcgtggtagttttagccgaaccttgtacggataaatccctccatttt +ccaatagcagatacctatcctactacctcgtggtattaaattaaagcttgaaatatagag +ctgcatagcttatccaattcccaagcacgagtctaccgtcgtaaccacgatttgatttac +agacgctagagcaaacccatctttaaacatataagtaaaaattaaagggtgagtgcgtac +gtgtttactagcaacttcgcttattaagacaattgtttataagccataattaaaaacata +tgttcaacaggttcattgatatttgtaattgcacaggtttttaataaggatctacgtaag +tataatgaacaaactttttaccagagttatattctgtactttgaaaatgctcctctaccg +ccttagagactttcaattagattttttgcagttaatctatgcgtaagtgaaccatgcaag +ggatgcgattcaaccgcctcgtgctaaccctatcgtctgtctcataactgtaggtctaat +ataattttcagttttcgaacacataaccctttgaaaatctgctatttaatgtctcacctg +catgcactatcttctatactgctcagaacggctatacgtcactatgctccaagtgacgat +ttaaacgaagcaaggaataataggtttattttagtgcaaaacaattaagtgcggactacg +tgctctttacaataagccttgtgattgggctataggttaagtcccatattaacgatctcc +aatgtacaaaatcgacaatcgctttgcattacccggttactagtcgaattacagatagct +gttagatactcactctaattttggacaacaatcccaatcttggggtcgtctatcgcctga +agctcgtaaatccttccatcttaaacgattacatattatagacttgttcggggtagagat +atcacagttgtgcaaacattgtaaatcgatactagtttatgttggtagtctagttgcttt +taccattccccgaaaaacttgatctactatttcgacaacagtaaacttgaactaggtaag +tgaaaacagagaatgcctcatagtgccactatttgtccactatatgtaagtgtagcttta +cataatccactatgactgagatcattacggcctaggaaagcagcgtagaaaaaaagggcc +cggatattacgactgtaactataaaactagttactggtagcgcgccatgtatagatttgt +tttaccggttgtggttgcgttaacgaatttcagccgcgaaaattgatccgttaaccagtc +catctcgacttctataaaacgataaagtaaagttgatgttcagcctccttcttatggttg +catcgagagtacactactcagtgggaaatagatcggggttcctacttcagattgtattat +ctaggcaattgccgattgtgccatacctggataaaataagctacctacatgtgatgctta +tctattatcgtcatactaccttagggtgtcctgttgaacgctacattaatctttagccgt +ttgagatgttccaatggataggagtctaacgcatgatgaagtttaggaaggcagagcatc +ccactaagtatgtgacagtgtatttcgaaacgagacgttataaatagaaaaaaggtcctt +ctggttctattctgctgaactattgaatggaaagattggttgacctacgtactatttgct +tgaagtcatcaatttgacggggtgagagacatatggtgcatactttacggactctatatt +ttagatcagaagcttagcagtcttctctacaccccctcacgacataattgcttttaagaa +tctatgtttgattcctctacgggaattcggatccgttcgcatgtgcggtttatctaaacc +aggggacatatgttcagctaaagcatacgaacactttgctaactagacgtatgtatagta +gctataaatcccgacgatatttacaaaaagaaatgagactcaaatatatacatagcgacc +ctacacttattcgcaccctgatctaggcgatcctagcacccacacccgaaagtgagcact +agtgtcttccgtattaaatttactgcagttgagattttagttgtctactaaggattactc +taacccgtaataaggatcaagactcggtactagctttactatcattccctatgtgttttc +ctaactcacaagggtacgtaccagcctatgtaattacaataatgataaagacacaaagga +agtaactttacaaatgagtctccagttacactagcttagtccctcccatcttgctttgaa +gtctaaatacgcaatctctgaggatatacagcagaagaacactcataacgttggagtcca +agaattagactcatagggcccccaacatttaatatgtactgtgagtttgaaggtgttcta +ttgttaattcctgctcttgatacatgacacgtactccgtgtttaaggcttcggactgact +ttctttcataagttgagcaacgaaaatttcagaatcgataagttggattcactaactaat +acggctgattgaaaactccactccggacctatatggtcgacctttatacgtaaccgatat +aaaacttataggctggtatatcgagccttcctagcgcaatttcggatggggtttcttcta +ctactcaacaacggaatagtctttgtttagtaaaccagagctcaggacgcccaatacgta +ggagagcgctgtggagcatgtgtcattatggactggagcactcttaaatcactctgcgtg +tgctaaacgatagatcataacatgtcctgagtaaattttcttgatacgtcgcaatatacc +gttattagttaaacgttctcatccgtcatgcgtgaaatacggctgtcgtgctcagatata +ctattagcgactcatctcgcctaacacgcacacgtataaactcggaatgactgccgctct +tacatattagaaatacagactacaccacggaagcattgggtcattctcaaccgctgtata +aaagatgattagtcttataataagattaccaaagaggcagaatcatgggtagtaaatcta +ttattcaagtgattaccgtcgtgtaggcagggagtgaggacgagatggtactcaggacaa +atattaaccggacgaagtggtttacgtcgtactttcactattagtagtaaatacaaggta +acaccggggaatagtactaaatataatgatatctatcttcgggagaacgagtcgtctatt +gctttgaacattctcaaggcgtaaaatgtgctgacttatagcatgatacaaccgattgtt +acttttgtctattcaaaagattgaatagttttttatacaaaagccgcatacttatgacgg +ctagtatacagtttcatcccctagcatcaatgctatggacagtattgaacttataggaaa +ttcttctaatagggcaaatccgtcgtgatgcctattttttttcagtcacatcctcaaatg +gcactagtattgtcgggatcccattaacaggctcaaccacgagctcacgcgaggacatgt +agtccgtatctttaacgaagcgacagcgacagaactcccatggataaccaattataaggc +ccgtaatcctctagacatcgtttaccaataaatccgctttctccgtaatcatgttgaata +ccccagagtagtccagatgataaccgatgaaacacaagtctttctcaatgcacttacggt +gaacttattaccgccaacgtagctcatcaaggttgcgacatctagttgtgtgtttgcgac +gagcccagcgaacttcatcaactttcgtatattcaacgccttgtaattttactttaagac +gcctggtgatgtagattcttagataatcagtttgttatcggctgtactttaccataattt +cacaggtttcaggtcaagaagattatagctgtatatacagttccatgctcggtgcacaga +aacgtgatcggataataatcaatcgcttatgtcgtctttaggcgtatccaatacatgccc +cgataccgcagtgtatttcgacatgtaggtataccgtcgcatttgagctcgagtcaggac +gtcagctagattagattccttaatagaatataccgacctctagtccgaactaaactatag +ataacgccaacttcaggttaattgtctagtcgtctgtttgcagatgggattcttagatga +gtgagtatcggccatattggttcgagcactttagtttttgatgcataggatatgcaatgt +atagctgaaagtactttatctgtttcaaactcacattgattaaaccggtaaacctttaaa +gactacaagaaaatattcagtgagggcaattttgtcaatcacaatcttccagctagagat +acttcacaatttgtcttgaggctacgcaacattagacggattttcgcgttttattgaaat +aatcgaggggcccaagagtatccatagttcattttgtaagatttctttacaggcttatta +cagcttcttcagactcctacatgcttacgagttatatgctagcatgtgaacaatagatta +atatacaggaaaacgtacattgagagagatgaccctacacagcgcaaccgttgagtactt +tcattaaagggtaacgctctcgagacagcatccttaagatggccttattgtcaaatcatt +tgcagaagtacgcaagatccctaaccaacgtagaagaatccctacaaacacatgagacgc +ggtgaaaatagacagggtgttagtattcaatcttcggagtatcaatttcgccaatcttgg +tgagaaagcataccctttcttcagagaaagaagatcaatcataacactatctttaacgag +gtacgcacgcgcatcattacctgcctccatggatctttaggatagcggaaagtattggca +gcgtattgtgatttcgttcctactttatcaatttcacattcatatacatgtcttttatca +aaatcgccaataagataggatgagctatattagatgctagtagagttcgcgccaacatca +tcgataggaatactcaggacagcgtgataggacttttcaatccctaatactctctataat +tataactctctcttaagtttggaggcagtaacgcgctctatataatcagtttgctgcacc +attcttcagcctctgatacatacaaataaattccacagcagtaagagggtttaattgaga +catcttgggaacttaggattttactctaacatcaccgaaacgattattggataccgtacc +taaacgaactttctcaaggcagtaatataggacatccgcaataacacaaatgctgcctcc +ccaggagttatgtcttcctggaggctatatcttacacccactcactataggcaaactaaa +gtttaaatgttgattgtctaaaaaaaagatagataagagttggccggcgtagcacatgcg +aaagtgaatcgtaagctataattctctggacttgaagttctgtcctgttcctctgcaaga +aacaaacttcctttaaagctatttacgacgcacatctcagcaagttataaacatgttgga +agtttctagtcggaattcccaaagaacggatctatctaatgcattcctacatttttcctg +tctgccgatggtgccatcctattcaaagaatttcttaaaagtagattaaatgggactttt +aacaatgagtaaccttacgcctctaagggttcctcgagtgccatacaccagtcaggtccg +agccacatacacggagaacattctaacatagcattctcaactcgatcatttgcaggttac +ttctttcctatcctagtgctaaaaatcatacttgcaatcccatagcacggattaagaacc +taagaaacaattcagtaaaacatgttcgaattcttggtatgggaacatcattgcagctat +ggtctaacgcattaatgtttgggtacatcttccatcatataaacaggaagagtctgacga +cagggagtgcttgcgatcatgtctatcattgtgaaatcaaattgtagctcacatgtcgtc +tatgagagcgtgtatccgataagatttagaaaaatagaagtcgtataagatctcactgaa +cttttgaatgaatgtgaagcatatatgatctgctttaataaaactttatccataggatac +gtttccaaatcaattcaataattattagtcaaaatagataaggatgaacaacctgaaggc +cgatcggacgtagaaagtggtcccatcactttgagttgatattgttgaaccacacgttat +tatggttttcaaacagtctcaggatattgtatatacagataatccgataccagttgtctg +acgcccctcttacgtaccccaccctttgtgacgtttaaagcagttgttcagtattttaaa +ctaggcggcaactaatttggaaagaagcacagtggatatgtctaaattcttgttattcag +gcctgaatttaatacaccgcatagttaacttcgcggtagagttgttcatcatgcctcctc +taagctaccacttctatgatacaccaatagttgttctacggaatctgataattggccaag +tcataaacttccgctgcgttcaacccccttgctcgaatatccaactcgaaaagacagcct +tttggtgtccggaacaaatcagttacttcttttctgatgttaattctctgtggtcagata +cagaccaaaaactccgcggatttaccatcctccaagaacaaatttgcatcaacatagcat +tttggctacatattctaagtctcaatagtttaggttttcaactacattatcccaacatta +ggattggaggaataatagctgggtaagtccccttgcgtctacaatcgactattttttatg +aatatgcttctgccgcacctatggttattaaaaaagtcatgactttgaagaaccctgaaa +agatagatgaatcaggtgtaatggcagcagccaaagagcatataattagcaacactctaa +gaacattatagatatgatgatagcgatcgtcatgatgttatccggtcacaatagtagctt +catcagctaattcgttttgccagtggtgacttgcgctggaagaatcgttatacggtccct +tccctcttgatacggtgggggcttattcaaccgcgtggattgggttgtcatacttgcatt +aaacgatgtaaaccatctagtagtcaactatactaaatcacaaaatagtgatcaatacat +acccgcttcatggttttaaccatttaattgattaaagatattccgctaagaaccattatc +tacctaaactgatcgccgtatcctagtagtttgaaatttgatgtaccgtaatgatcaacg +aagtaaaacgttatattgtatgtagaataataggtcttggagctaaatgatgtgattggt +agtgaagacttacccttacaactttaccggtttctcggaagaatatactagagaatcaat +gcatgggctacataagcactttagtctaatgagataaaaaatacacgagtcttccatcat +gaattttttgtcgaaaaactcgaacctggtaatttaaaccatatatctttatgtcgtcaa +taactctcatatgttttatataacttcccaatcacgacttgtaactgcttgttcgactga +gctgtttgagctatgaggccgggatccggttgagctacatctatttgctacaagaaaaat +gaaagcacatttgttgggagttctggctacactcatagagaaataagtggcccgagtggg +tgcggcctgcctccatattcaagtgtatcttaaaccaagtggttccaacgctcgcgctaa +agaattaaagcctttatttcctccacggagtagcccgtaatccggttcgaaagagaccat +tgaagttaattttcatatccagtgaagtttaggcacaagcatgtgttctgccacatgcct +caaagcgctcttcaaccaagatatgattcatcctaacttcgatgaatgcgtctgtaacat +aaatatagaaggaatgattcggcgagttaattttcgccttctccaacatggcatccctac +gttcgttataaggaccatacatgtaggttttaaaggtttgcggttaatcgatatttacat +catagaaattctatagtcaaatttacaagactctagatactcactcgttgcagccggcta +ggaagcgctttgtaccttacttcccttttcgttgcgtaatatgaatttcatatagtaagt +tcaaggcactcatacctccgtgaagagggtagatagactattaaagttgtttaatagtac +gtattgatggaaatgacccgtaggagatttaccactcaatccacaagattcgctgctgtg +cattatcaaaacagtgcatgtcgaaacatgggttgggtccttcaaacacgaatccaggta +gagatacctttgcaattttt diff --git a/regex/examples/regexdna-output.txt b/regex/examples/regexdna-output.txt new file mode 100644 index 000000000..d36baa5be --- /dev/null +++ b/regex/examples/regexdna-output.txt @@ -0,0 +1,13 @@ +agggtaaa|tttaccct 0 +[cgt]gggtaaa|tttaccc[acg] 3 +a[act]ggtaaa|tttacc[agt]t 9 +ag[act]gtaaa|tttac[agt]ct 8 +agg[act]taaa|ttta[agt]cct 10 +aggg[acg]aaa|ttt[cgt]ccct 3 +agggt[cgt]aa|tt[acg]accct 4 +agggta[cgt]a|t[acg]taccct 3 +agggtaa[cgt]|[acg]ttaccct 5 + +101745 +100000 +133640 diff --git a/regex/examples/shootout-regex-dna-bytes.rs b/regex/examples/shootout-regex-dna-bytes.rs new file mode 100644 index 000000000..4010324db --- /dev/null +++ b/regex/examples/shootout-regex-dna-bytes.rs @@ -0,0 +1,66 @@ +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// +// contributed by the Rust Project Developers +// contributed by TeXitoi +// contributed by BurntSushi + +extern crate regex; + +use std::io::{self, Read}; +use std::sync::Arc; +use std::thread; + +macro_rules! regex { ($re:expr) => { ::regex::bytes::Regex::new($re).unwrap() } } + +fn main() { + let mut seq = Vec::with_capacity(51 * (1 << 20)); + io::stdin().read_to_end(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, &b""[..]).into_owned(); + let clen = seq.len(); + let seq_arc = Arc::new(seq.clone()); + + let variants = vec![ + regex!("agggtaaa|tttaccct"), + regex!("[cgt]gggtaaa|tttaccc[acg]"), + regex!("a[act]ggtaaa|tttacc[agt]t"), + regex!("ag[act]gtaaa|tttac[agt]ct"), + regex!("agg[act]taaa|ttta[agt]cct"), + regex!("aggg[acg]aaa|ttt[cgt]ccct"), + regex!("agggt[cgt]aa|tt[acg]accct"), + regex!("agggta[cgt]a|t[acg]taccct"), + regex!("agggtaa[cgt]|[acg]ttaccct"), + ]; + let mut counts = vec![]; + for variant in variants { + let seq = seq_arc.clone(); + let restr = variant.to_string(); + let future = thread::spawn(move || variant.find_iter(&seq).count()); + counts.push((restr, future)); + } + + let substs = vec![ + (regex!("B"), &b"(c|g|t)"[..]), + (regex!("D"), &b"(a|g|t)"[..]), + (regex!("H"), &b"(a|c|t)"[..]), + (regex!("K"), &b"(g|t)"[..]), + (regex!("M"), &b"(a|c)"[..]), + (regex!("N"), &b"(a|c|g|t)"[..]), + (regex!("R"), &b"(a|g)"[..]), + (regex!("S"), &b"(c|g)"[..]), + (regex!("V"), &b"(a|c|g)"[..]), + (regex!("W"), &b"(a|t)"[..]), + (regex!("Y"), &b"(c|t)"[..]), + ]; + let mut seq = seq; + for (re, replacement) in substs { + seq = re.replace_all(&seq, replacement).into_owned(); + } + + for (variant, count) in counts { + println!("{} {}", variant, count.join().unwrap()); + } + println!("\n{}\n{}\n{}", ilen, clen, seq.len()); +} diff --git a/regex/examples/shootout-regex-dna-cheat.rs b/regex/examples/shootout-regex-dna-cheat.rs new file mode 100644 index 000000000..a421d2085 --- /dev/null +++ b/regex/examples/shootout-regex-dna-cheat.rs @@ -0,0 +1,88 @@ +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// +// contributed by the Rust Project Developers +// contributed by TeXitoi +// contributed by BurntSushi + +// This technically solves the problem posed in the `regex-dna` benchmark, but +// it cheats by combining all of the replacements into a single regex and +// replacing them with a single linear scan. i.e., it re-implements +// `replace_all`. As a result, this is around 25% faster. ---AG + +extern crate regex; + +use std::io::{self, Read}; +use std::sync::Arc; +use std::thread; + +macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } } + +fn main() { + let mut seq = String::with_capacity(50 * (1 << 20)); + io::stdin().read_to_string(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, "").into_owned(); + let clen = seq.len(); + let seq_arc = Arc::new(seq.clone()); + + let variants = vec![ + regex!("agggtaaa|tttaccct"), + regex!("[cgt]gggtaaa|tttaccc[acg]"), + regex!("a[act]ggtaaa|tttacc[agt]t"), + regex!("ag[act]gtaaa|tttac[agt]ct"), + regex!("agg[act]taaa|ttta[agt]cct"), + regex!("aggg[acg]aaa|ttt[cgt]ccct"), + regex!("agggt[cgt]aa|tt[acg]accct"), + regex!("agggta[cgt]a|t[acg]taccct"), + regex!("agggtaa[cgt]|[acg]ttaccct"), + ]; + let mut counts = vec![]; + for variant in variants { + let seq = seq_arc.clone(); + let restr = variant.to_string(); + let future = thread::spawn(move || variant.find_iter(&seq).count()); + counts.push((restr, future)); + } + + let substs = vec![ + (b'B', "(c|g|t)"), + (b'D', "(a|g|t)"), + (b'H', "(a|c|t)"), + (b'K', "(g|t)"), + (b'M', "(a|c)"), + (b'N', "(a|c|g|t)"), + (b'R', "(a|g)"), + (b'S', "(c|g)"), + (b'V', "(a|c|g)"), + (b'W', "(a|t)"), + (b'Y', "(c|t)"), + ]; // combined into one regex in `replace_all` + let seq = replace_all(&seq, substs); + + for (variant, count) in counts { + println!("{} {}", variant, count.join().unwrap()); + } + println!("\n{}\n{}\n{}", ilen, clen, seq.len()); +} + +fn replace_all(text: &str, substs: Vec<(u8, &str)>) -> String { + let mut replacements = vec![""; 256]; + let mut alternates = vec![]; + for (re, replacement) in substs { + replacements[re as usize] = replacement; + alternates.push((re as char).to_string()); + } + + let re = regex!(&alternates.join("|")); + let mut new = String::with_capacity(text.len()); + let mut last_match = 0; + for m in re.find_iter(text) { + new.push_str(&text[last_match..m.start()]); + new.push_str(replacements[text.as_bytes()[m.start()] as usize]); + last_match = m.end(); + } + new.push_str(&text[last_match..]); + new +} diff --git a/regex/examples/shootout-regex-dna-replace.rs b/regex/examples/shootout-regex-dna-replace.rs new file mode 100644 index 000000000..857d8bfcd --- /dev/null +++ b/regex/examples/shootout-regex-dna-replace.rs @@ -0,0 +1,19 @@ +extern crate regex; + +use std::io::{self, Read}; + +macro_rules! regex { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re).build().unwrap().into_regex() + }} +} + +fn main() { + let mut seq = String::with_capacity(50 * (1 << 20)); + io::stdin().read_to_string(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, "").into_owned(); + println!("original: {}, replaced: {}", ilen, seq.len()); +} diff --git a/regex/examples/shootout-regex-dna-single-cheat.rs b/regex/examples/shootout-regex-dna-single-cheat.rs new file mode 100644 index 000000000..64d210499 --- /dev/null +++ b/regex/examples/shootout-regex-dna-single-cheat.rs @@ -0,0 +1,73 @@ +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// +// contributed by the Rust Project Developers +// contributed by TeXitoi +// contributed by BurntSushi + +extern crate regex; + +use std::io::{self, Read}; + +macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } } + +fn main() { + let mut seq = String::with_capacity(50 * (1 << 20)); + io::stdin().read_to_string(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, "").into_owned(); + let clen = seq.len(); + + let variants = vec![ + regex!("agggtaaa|tttaccct"), + regex!("[cgt]gggtaaa|tttaccc[acg]"), + regex!("a[act]ggtaaa|tttacc[agt]t"), + regex!("ag[act]gtaaa|tttac[agt]ct"), + regex!("agg[act]taaa|ttta[agt]cct"), + regex!("aggg[acg]aaa|ttt[cgt]ccct"), + regex!("agggt[cgt]aa|tt[acg]accct"), + regex!("agggta[cgt]a|t[acg]taccct"), + regex!("agggtaa[cgt]|[acg]ttaccct"), + ]; + for re in variants { + println!("{} {}", re.to_string(), re.find_iter(&seq).count()); + } + + let substs = vec![ + (b'B', "(c|g|t)"), + (b'D', "(a|g|t)"), + (b'H', "(a|c|t)"), + (b'K', "(g|t)"), + (b'M', "(a|c)"), + (b'N', "(a|c|g|t)"), + (b'R', "(a|g)"), + (b'S', "(c|g)"), + (b'V', "(a|c|g)"), + (b'W', "(a|t)"), + (b'Y', "(c|t)"), + ]; // combined into one regex in `replace_all` + let seq = replace_all(&seq, substs); + + println!("\n{}\n{}\n{}", ilen, clen, seq.len()); +} + +fn replace_all(text: &str, substs: Vec<(u8, &str)>) -> String { + let mut replacements = vec![""; 256]; + let mut alternates = vec![]; + for (re, replacement) in substs { + replacements[re as usize] = replacement; + alternates.push((re as char).to_string()); + } + + let re = regex!(&alternates.join("|")); + let mut new = String::with_capacity(text.len()); + let mut last_match = 0; + for m in re.find_iter(text) { + new.push_str(&text[last_match..m.start()]); + new.push_str(replacements[text.as_bytes()[m.start()] as usize]); + last_match = m.end(); + } + new.push_str(&text[last_match..]); + new +} diff --git a/regex/examples/shootout-regex-dna-single.rs b/regex/examples/shootout-regex-dna-single.rs new file mode 100644 index 000000000..ed48b8b01 --- /dev/null +++ b/regex/examples/shootout-regex-dna-single.rs @@ -0,0 +1,55 @@ +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// +// contributed by the Rust Project Developers +// contributed by TeXitoi +// contributed by BurntSushi + +extern crate regex; + +use std::io::{self, Read}; + +macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } } + +fn main() { + let mut seq = String::with_capacity(50 * (1 << 20)); + io::stdin().read_to_string(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, "").into_owned(); + let clen = seq.len(); + + let variants = vec![ + regex!("agggtaaa|tttaccct"), + regex!("[cgt]gggtaaa|tttaccc[acg]"), + regex!("a[act]ggtaaa|tttacc[agt]t"), + regex!("ag[act]gtaaa|tttac[agt]ct"), + regex!("agg[act]taaa|ttta[agt]cct"), + regex!("aggg[acg]aaa|ttt[cgt]ccct"), + regex!("agggt[cgt]aa|tt[acg]accct"), + regex!("agggta[cgt]a|t[acg]taccct"), + regex!("agggtaa[cgt]|[acg]ttaccct"), + ]; + for re in variants { + println!("{} {}", re.to_string(), re.find_iter(&seq).count()); + } + + let substs = vec![ + (regex!("B"), "(c|g|t)"), + (regex!("D"), "(a|g|t)"), + (regex!("H"), "(a|c|t)"), + (regex!("K"), "(g|t)"), + (regex!("M"), "(a|c)"), + (regex!("N"), "(a|c|g|t)"), + (regex!("R"), "(a|g)"), + (regex!("S"), "(c|g)"), + (regex!("V"), "(a|c|g)"), + (regex!("W"), "(a|t)"), + (regex!("Y"), "(c|t)"), + ]; + let mut seq = seq; + for (re, replacement) in substs { + seq = re.replace_all(&seq, replacement).into_owned(); + } + println!("\n{}\n{}\n{}", ilen, clen, seq.len()); +} diff --git a/regex/examples/shootout-regex-dna.rs b/regex/examples/shootout-regex-dna.rs new file mode 100644 index 000000000..2171bb3ea --- /dev/null +++ b/regex/examples/shootout-regex-dna.rs @@ -0,0 +1,66 @@ +// The Computer Language Benchmarks Game +// http://benchmarksgame.alioth.debian.org/ +// +// contributed by the Rust Project Developers +// contributed by TeXitoi +// contributed by BurntSushi + +extern crate regex; + +use std::io::{self, Read}; +use std::sync::Arc; +use std::thread; + +macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } } + +fn main() { + let mut seq = String::with_capacity(51 * (1 << 20)); + io::stdin().read_to_string(&mut seq).unwrap(); + let ilen = seq.len(); + + seq = regex!(">[^\n]*\n|\n").replace_all(&seq, "").into_owned(); + let clen = seq.len(); + let seq_arc = Arc::new(seq.clone()); + + let variants = vec![ + regex!("agggtaaa|tttaccct"), + regex!("[cgt]gggtaaa|tttaccc[acg]"), + regex!("a[act]ggtaaa|tttacc[agt]t"), + regex!("ag[act]gtaaa|tttac[agt]ct"), + regex!("agg[act]taaa|ttta[agt]cct"), + regex!("aggg[acg]aaa|ttt[cgt]ccct"), + regex!("agggt[cgt]aa|tt[acg]accct"), + regex!("agggta[cgt]a|t[acg]taccct"), + regex!("agggtaa[cgt]|[acg]ttaccct"), + ]; + let mut counts = vec![]; + for variant in variants { + let seq = seq_arc.clone(); + let restr = variant.to_string(); + let future = thread::spawn(move || variant.find_iter(&seq).count()); + counts.push((restr, future)); + } + + let substs = vec![ + (regex!("B"), "(c|g|t)"), + (regex!("D"), "(a|g|t)"), + (regex!("H"), "(a|c|t)"), + (regex!("K"), "(g|t)"), + (regex!("M"), "(a|c)"), + (regex!("N"), "(a|c|g|t)"), + (regex!("R"), "(a|g)"), + (regex!("S"), "(c|g)"), + (regex!("V"), "(a|c|g)"), + (regex!("W"), "(a|t)"), + (regex!("Y"), "(c|t)"), + ]; + let mut seq = seq; + for (re, replacement) in substs { + seq = re.replace_all(&seq, replacement).into_owned(); + } + + for (variant, count) in counts { + println!("{} {}", variant, count.join().unwrap()); + } + println!("\n{}\n{}\n{}", ilen, clen, seq.len()); +} diff --git a/regex/rustfmt.toml b/regex/rustfmt.toml new file mode 100644 index 000000000..c7ad93baf --- /dev/null +++ b/regex/rustfmt.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/regex/src/backtrack.rs b/regex/src/backtrack.rs new file mode 100644 index 000000000..13cdbb62b --- /dev/null +++ b/regex/src/backtrack.rs @@ -0,0 +1,303 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is the backtracking matching engine. It has the same exact capability +// as the full NFA simulation, except it is artificially restricted to small +// regexes on small inputs because of its memory requirements. +// +// In particular, this is a *bounded* backtracking engine. It retains worst +// case linear time by keeping track of the states that it has visited (using a +// bitmap). Namely, once a state is visited, it is never visited again. Since a +// state is keyed by `(instruction index, input index)`, we have that its time +// complexity is `O(mn)` (i.e., linear in the size of the search text). +// +// The backtracking engine can beat out the NFA simulation on small +// regexes/inputs because it doesn't have to keep track of multiple copies of +// the capture groups. In benchmarks, the backtracking engine is roughly twice +// as fast as the full NFA simulation. Note though that its performance doesn't +// scale, even if you're willing to live with the memory requirements. Namely, +// the bitset has to be zeroed on each execution, which becomes quite expensive +// on large bitsets. + +use exec::ProgramCache; +use input::{Input, InputAt}; +use prog::{Program, InstPtr}; +use re_trait::Slot; + +type Bits = u32; + +const BIT_SIZE: usize = 32; +const MAX_SIZE_BYTES: usize = 256 * (1 << 10); // 256 KB + +/// Returns true iff the given regex and input should be executed by this +/// engine with reasonable memory usage. +pub fn should_exec(num_insts: usize, text_len: usize) -> bool { + // Total memory usage in bytes is determined by: + // + // ((len(insts) * (len(input) + 1) + bits - 1) / bits) * (size_of(u32)) + // + // The actual limit picked is pretty much a heuristic. + // See: https://github.com/rust-lang/regex/issues/215 + let size = ((num_insts * (text_len + 1) + BIT_SIZE - 1) / BIT_SIZE) * 4; + size <= MAX_SIZE_BYTES +} + +/// A backtracking matching engine. +#[derive(Debug)] +pub struct Bounded<'a, 'm, 'r, 's, I> { + prog: &'r Program, + input: I, + matches: &'m mut [bool], + slots: &'s mut [Slot], + m: &'a mut Cache, +} + +/// Shared cached state between multiple invocations of a backtracking engine +/// in the same thread. +#[derive(Clone, Debug)] +pub struct Cache { + jobs: Vec<Job>, + visited: Vec<Bits>, +} + +impl Cache { + /// Create new empty cache for the backtracking engine. + pub fn new(_prog: &Program) -> Self { + Cache { jobs: vec![], visited: vec![] } + } +} + +/// A job is an explicit unit of stack space in the backtracking engine. +/// +/// The "normal" representation is a single state transition, which corresponds +/// to an NFA state and a character in the input. However, the backtracking +/// engine must keep track of old capture group values. We use the explicit +/// stack to do it. +#[derive(Clone, Copy, Debug)] +enum Job { + Inst { ip: InstPtr, at: InputAt }, + SaveRestore { slot: usize, old_pos: Option<usize> }, +} + +impl<'a, 'm, 'r, 's, I: Input> Bounded<'a, 'm, 'r, 's, I> { + /// Execute the backtracking matching engine. + /// + /// If there's a match, `exec` returns `true` and populates the given + /// captures accordingly. + pub fn exec( + prog: &'r Program, + cache: &ProgramCache, + matches: &'m mut [bool], + slots: &'s mut [Slot], + input: I, + start: usize, + end: usize, + ) -> bool { + let mut cache = cache.borrow_mut(); + let cache = &mut cache.backtrack; + let start = input.at(start); + let mut b = Bounded { + prog: prog, + input: input, + matches: matches, + slots: slots, + m: cache, + }; + b.exec_(start, end) + } + + /// Clears the cache such that the backtracking engine can be executed + /// on some input of fixed length. + fn clear(&mut self) { + // Reset the job memory so that we start fresh. + self.m.jobs.clear(); + + // Now we need to clear the bit state set. + // We do this by figuring out how much space we need to keep track + // of the states we've visited. + // Then we reset all existing allocated space to 0. + // Finally, we request more space if we need it. + // + // This is all a little circuitous, but doing this unsafely + // doesn't seem to have a measurable impact on performance. + // (Probably because backtracking is limited to such small + // inputs/regexes in the first place.) + let visited_len = + (self.prog.len() * (self.input.len() + 1) + BIT_SIZE - 1) + / + BIT_SIZE; + self.m.visited.truncate(visited_len); + for v in &mut self.m.visited { + *v = 0; + } + if visited_len > self.m.visited.len() { + let len = self.m.visited.len(); + self.m.visited.reserve_exact(visited_len - len); + for _ in 0..(visited_len - len) { + self.m.visited.push(0); + } + } + } + + /// Start backtracking at the given position in the input, but also look + /// for literal prefixes. + fn exec_(&mut self, mut at: InputAt, end: usize) -> bool { + self.clear(); + // If this is an anchored regex at the beginning of the input, then + // we're either already done or we only need to try backtracking once. + if self.prog.is_anchored_start { + return if !at.is_start() { + false + } else { + self.backtrack(at) + }; + } + let mut matched = false; + loop { + if !self.prog.prefixes.is_empty() { + at = match self.input.prefix_at(&self.prog.prefixes, at) { + None => break, + Some(at) => at, + }; + } + matched = self.backtrack(at) || matched; + if matched && self.prog.matches.len() == 1 { + return true; + } + if at.pos() == end || at.is_end() { + break; + } + at = self.input.at(at.next_pos()); + } + matched + } + + /// The main backtracking loop starting at the given input position. + fn backtrack(&mut self, start: InputAt) -> bool { + // N.B. We use an explicit stack to avoid recursion. + // To avoid excessive pushing and popping, most transitions are handled + // in the `step` helper function, which only pushes to the stack when + // there's a capture or a branch. + let mut matched = false; + self.m.jobs.push(Job::Inst { ip: 0, at: start }); + while let Some(job) = self.m.jobs.pop() { + match job { + Job::Inst { ip, at } => { + if self.step(ip, at) { + // Only quit if we're matching one regex. + // If we're matching a regex set, then mush on and + // try to find other matches (if we want them). + if self.prog.matches.len() == 1 { + return true; + } + matched = true; + } + } + Job::SaveRestore { slot, old_pos } => { + if slot < self.slots.len() { + self.slots[slot] = old_pos; + } + } + } + } + matched + } + + fn step(&mut self, mut ip: InstPtr, mut at: InputAt) -> bool { + use prog::Inst::*; + loop { + // This loop is an optimization to avoid constantly pushing/popping + // from the stack. Namely, if we're pushing a job only to run it + // next, avoid the push and just mutate `ip` (and possibly `at`) + // in place. + if self.has_visited(ip, at) { + return false; + } + match self.prog[ip] { + Match(slot) => { + if slot < self.matches.len() { + self.matches[slot] = true; + } + return true; + } + Save(ref inst) => { + if let Some(&old_pos) = self.slots.get(inst.slot) { + // If this path doesn't work out, then we save the old + // capture index (if one exists) in an alternate + // job. If the next path fails, then the alternate + // job is popped and the old capture index is restored. + self.m.jobs.push(Job::SaveRestore { + slot: inst.slot, + old_pos: old_pos, + }); + self.slots[inst.slot] = Some(at.pos()); + } + ip = inst.goto; + } + Split(ref inst) => { + self.m.jobs.push(Job::Inst { ip: inst.goto2, at: at }); + ip = inst.goto1; + } + EmptyLook(ref inst) => { + if self.input.is_empty_match(at, inst) { + ip = inst.goto; + } else { + return false; + } + } + Char(ref inst) => { + if inst.c == at.char() { + ip = inst.goto; + at = self.input.at(at.next_pos()); + } else { + return false; + } + } + Ranges(ref inst) => { + if inst.matches(at.char()) { + ip = inst.goto; + at = self.input.at(at.next_pos()); + } else { + return false; + } + } + Bytes(ref inst) => { + if let Some(b) = at.byte() { + if inst.matches(b) { + ip = inst.goto; + at = self.input.at(at.next_pos()); + continue; + } + } + return false; + } + } + } + } + + fn has_visited(&mut self, ip: InstPtr, at: InputAt) -> bool { + let k = ip * (self.input.len() + 1) + at.pos(); + let k1 = k / BIT_SIZE; + let k2 = usize_to_u32(1 << (k & (BIT_SIZE - 1))); + if self.m.visited[k1] & k2 == 0 { + self.m.visited[k1] |= k2; + false + } else { + true + } + } +} + +fn usize_to_u32(n: usize) -> u32 { + if (n as u64) > (::std::u32::MAX as u64) { + panic!("BUG: {} is too big to fit into u32", n) + } + n as u32 +} diff --git a/regex/src/compile.rs b/regex/src/compile.rs new file mode 100644 index 000000000..de62a5ce9 --- /dev/null +++ b/regex/src/compile.rs @@ -0,0 +1,1115 @@ +// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::iter; +use std::result; +use std::sync::Arc; + +use syntax::is_word_byte; +use syntax::hir::{self, Hir}; +use utf8_ranges::{Utf8Range, Utf8Sequence, Utf8Sequences}; + +use prog::{ + Program, Inst, InstPtr, EmptyLook, + InstSave, InstSplit, InstEmptyLook, InstChar, InstRanges, InstBytes, +}; + +use Error; + +type Result = result::Result<Patch, Error>; + +#[derive(Debug)] +struct Patch { + hole: Hole, + entry: InstPtr, +} + +/// A compiler translates a regular expression AST to a sequence of +/// instructions. The sequence of instructions represents an NFA. +pub struct Compiler { + insts: Vec<MaybeInst>, + compiled: Program, + capture_name_idx: HashMap<String, usize>, + num_exprs: usize, + size_limit: usize, + suffix_cache: SuffixCache, + utf8_seqs: Option<Utf8Sequences>, + byte_classes: ByteClassSet, +} + +impl Compiler { + /// Create a new regular expression compiler. + /// + /// Various options can be set before calling `compile` on an expression. + pub fn new() -> Self { + Compiler { + insts: vec![], + compiled: Program::new(), + capture_name_idx: HashMap::new(), + num_exprs: 0, + size_limit: 10 * (1 << 20), + suffix_cache: SuffixCache::new(1000), + utf8_seqs: Some(Utf8Sequences::new('\x00', '\x00')), + byte_classes: ByteClassSet::new(), + } + } + + /// The size of the resulting program is limited by size_limit. If + /// the program approximately exceeds the given size (in bytes), then + /// compilation will stop and return an error. + pub fn size_limit(mut self, size_limit: usize) -> Self { + self.size_limit = size_limit; + self + } + + /// If bytes is true, then the program is compiled as a byte based + /// automaton, which incorporates UTF-8 decoding into the machine. If it's + /// false, then the automaton is Unicode scalar value based, e.g., an + /// engine utilizing such an automaton is responsible for UTF-8 decoding. + /// + /// The specific invariant is that when returning a byte based machine, + /// the neither the `Char` nor `Ranges` instructions are produced. + /// Conversely, when producing a Unicode scalar value machine, the `Bytes` + /// instruction is never produced. + /// + /// Note that `dfa(true)` implies `bytes(true)`. + pub fn bytes(mut self, yes: bool) -> Self { + self.compiled.is_bytes = yes; + self + } + + /// When disabled, the program compiled may match arbitrary bytes. + /// + /// When enabled (the default), all compiled programs exclusively match + /// valid UTF-8 bytes. + pub fn only_utf8(mut self, yes: bool) -> Self { + self.compiled.only_utf8 = yes; + self + } + + /// When set, the machine returned is suitable for use in the DFA matching + /// engine. + /// + /// In particular, this ensures that if the regex is not anchored in the + /// beginning, then a preceding `.*?` is included in the program. (The NFA + /// based engines handle the preceding `.*?` explicitly, which is difficult + /// or impossible in the DFA engine.) + pub fn dfa(mut self, yes: bool) -> Self { + self.compiled.is_dfa = yes; + self + } + + /// When set, the machine returned is suitable for matching text in + /// reverse. In particular, all concatenations are flipped. + pub fn reverse(mut self, yes: bool) -> Self { + self.compiled.is_reverse = yes; + self + } + + /// Compile a regular expression given its AST. + /// + /// The compiler is guaranteed to succeed unless the program exceeds the + /// specified size limit. If the size limit is exceeded, then compilation + /// stops and returns an error. + pub fn compile( + mut self, + exprs: &[Hir], + ) -> result::Result<Program, Error> { + debug_assert!(exprs.len() >= 1); + self.num_exprs = exprs.len(); + if exprs.len() == 1 { + self.compile_one(&exprs[0]) + } else { + self.compile_many(exprs) + } + } + + fn compile_one(mut self, expr: &Hir) -> result::Result<Program, Error> { + // If we're compiling a forward DFA and we aren't anchored, then + // add a `.*?` before the first capture group. + // Other matching engines handle this by baking the logic into the + // matching engine itself. + let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 }; + self.compiled.is_anchored_start = expr.is_anchored_start(); + self.compiled.is_anchored_end = expr.is_anchored_end(); + if self.compiled.needs_dotstar() { + dotstar_patch = self.c_dotstar()?; + self.compiled.start = dotstar_patch.entry; + } + self.compiled.captures = vec![None]; + let patch = self.c_capture(0, expr)?; + if self.compiled.needs_dotstar() { + self.fill(dotstar_patch.hole, patch.entry); + } else { + self.compiled.start = patch.entry; + } + self.fill_to_next(patch.hole); + self.compiled.matches = vec![self.insts.len()]; + self.push_compiled(Inst::Match(0)); + self.compile_finish() + } + + fn compile_many( + mut self, + exprs: &[Hir], + ) -> result::Result<Program, Error> { + debug_assert!(exprs.len() > 1); + + self.compiled.is_anchored_start = + exprs.iter().all(|e| e.is_anchored_start()); + self.compiled.is_anchored_end = + exprs.iter().all(|e| e.is_anchored_end()); + let mut dotstar_patch = Patch { hole: Hole::None, entry: 0 }; + if self.compiled.needs_dotstar() { + dotstar_patch = self.c_dotstar()?; + self.compiled.start = dotstar_patch.entry; + } else { + self.compiled.start = 0; // first instruction is always split + } + self.fill_to_next(dotstar_patch.hole); + + let mut prev_hole = Hole::None; + for (i, expr) in exprs[0..exprs.len() - 1].iter().enumerate() { + self.fill_to_next(prev_hole); + let split = self.push_split_hole(); + let Patch { hole, entry } = self.c_capture(0, expr)?; + self.fill_to_next(hole); + self.compiled.matches.push(self.insts.len()); + self.push_compiled(Inst::Match(i)); + prev_hole = self.fill_split(split, Some(entry), None); + } + let i = exprs.len() - 1; + let Patch { hole, entry } = self.c_capture(0, &exprs[i])?; + self.fill(prev_hole, entry); + self.fill_to_next(hole); + self.compiled.matches.push(self.insts.len()); + self.push_compiled(Inst::Match(i)); + self.compile_finish() + } + + fn compile_finish(mut self) -> result::Result<Program, Error> { + self.compiled.insts = + self.insts.into_iter().map(|inst| inst.unwrap()).collect(); + self.compiled.byte_classes = self.byte_classes.byte_classes(); + self.compiled.capture_name_idx = Arc::new(self.capture_name_idx); + Ok(self.compiled) + } + + /// Compile expr into self.insts, returning a patch on success, + /// or an error if we run out of memory. + /// + /// All of the c_* methods of the compiler share the contract outlined + /// here. + /// + /// The main thing that a c_* method does is mutate `self.insts` + /// to add a list of mostly compiled instructions required to execute + /// the given expression. `self.insts` contains MaybeInsts rather than + /// Insts because there is some backpatching required. + /// + /// The `Patch` value returned by each c_* method provides metadata + /// about the compiled instructions emitted to `self.insts`. The + /// `entry` member of the patch refers to the first instruction + /// (the entry point), while the `hole` member contains zero or + /// more offsets to partial instructions that need to be backpatched. + /// The c_* routine can't know where its list of instructions are going to + /// jump to after execution, so it is up to the caller to patch + /// these jumps to point to the right place. So compiling some + /// expression, e, we would end up with a situation that looked like: + /// + /// ```text + /// self.insts = [ ..., i1, i2, ..., iexit1, ..., iexitn, ...] + /// ^ ^ ^ + /// | \ / + /// entry \ / + /// hole + /// ``` + /// + /// To compile two expressions, e1 and e2, concatinated together we + /// would do: + /// + /// ```ignore + /// let patch1 = self.c(e1); + /// let patch2 = self.c(e2); + /// ``` + /// + /// while leaves us with a situation that looks like + /// + /// ```text + /// self.insts = [ ..., i1, ..., iexit1, ..., i2, ..., iexit2 ] + /// ^ ^ ^ ^ + /// | | | | + /// entry1 hole1 entry2 hole2 + /// ``` + /// + /// Then to merge the two patches together into one we would backpatch + /// hole1 with entry2 and return a new patch that enters at entry1 + /// and has hole2 for a hole. In fact, if you look at the c_concat + /// method you will see that it does exactly this, though it handles + /// a list of expressions rather than just the two that we use for + /// an example. + fn c(&mut self, expr: &Hir) -> Result { + use prog; + use syntax::hir::HirKind::*; + + self.check_size()?; + match *expr.kind() { + Empty => Ok(Patch { hole: Hole::None, entry: self.insts.len() }), + Literal(hir::Literal::Unicode(c)) => { + self.c_char(c) + } + Literal(hir::Literal::Byte(b)) => { + assert!(self.compiled.uses_bytes()); + self.c_byte(b) + } + Class(hir::Class::Unicode(ref cls)) => { + self.c_class(cls.ranges()) + } + Class(hir::Class::Bytes(ref cls)) => { + if self.compiled.uses_bytes() { + self.c_class_bytes(cls.ranges()) + } else { + assert!(cls.is_all_ascii()); + let mut char_ranges = vec![]; + for r in cls.iter() { + let (s, e) = (r.start() as char, r.end() as char); + char_ranges.push(hir::ClassUnicodeRange::new(s, e)); + } + self.c_class(&char_ranges) + } + } + Anchor(hir::Anchor::StartLine) if self.compiled.is_reverse => { + self.byte_classes.set_range(b'\n', b'\n'); + self.c_empty_look(prog::EmptyLook::EndLine) + } + Anchor(hir::Anchor::StartLine) => { + self.byte_classes.set_range(b'\n', b'\n'); + self.c_empty_look(prog::EmptyLook::StartLine) + } + Anchor(hir::Anchor::EndLine) if self.compiled.is_reverse => { + self.byte_classes.set_range(b'\n', b'\n'); + self.c_empty_look(prog::EmptyLook::StartLine) + } + Anchor(hir::Anchor::EndLine) => { + self.byte_classes.set_range(b'\n', b'\n'); + self.c_empty_look(prog::EmptyLook::EndLine) + } + Anchor(hir::Anchor::StartText) if self.compiled.is_reverse => { + self.c_empty_look(prog::EmptyLook::EndText) + } + Anchor(hir::Anchor::StartText) => { + self.c_empty_look(prog::EmptyLook::StartText) + } + Anchor(hir::Anchor::EndText) if self.compiled.is_reverse => { + self.c_empty_look(prog::EmptyLook::StartText) + } + Anchor(hir::Anchor::EndText) => { + self.c_empty_look(prog::EmptyLook::EndText) + } + WordBoundary(hir::WordBoundary::Unicode) => { + self.compiled.has_unicode_word_boundary = true; + self.byte_classes.set_word_boundary(); + self.c_empty_look(prog::EmptyLook::WordBoundary) + } + WordBoundary(hir::WordBoundary::UnicodeNegate) => { + self.compiled.has_unicode_word_boundary = true; + self.byte_classes.set_word_boundary(); + self.c_empty_look(prog::EmptyLook::NotWordBoundary) + } + WordBoundary(hir::WordBoundary::Ascii) => { + self.byte_classes.set_word_boundary(); + self.c_empty_look(prog::EmptyLook::WordBoundaryAscii) + } + WordBoundary(hir::WordBoundary::AsciiNegate) => { + self.byte_classes.set_word_boundary(); + self.c_empty_look(prog::EmptyLook::NotWordBoundaryAscii) + } + Group(ref g) => { + match g.kind { + hir::GroupKind::NonCapturing => self.c(&g.hir), + hir::GroupKind::CaptureIndex(index) => { + if index as usize >= self.compiled.captures.len() { + self.compiled.captures.push(None); + } + self.c_capture(2 * index as usize, &g.hir) + } + hir::GroupKind::CaptureName { index, ref name } => { + if index as usize >= self.compiled.captures.len() { + let n = name.to_string(); + self.compiled.captures.push(Some(n.clone())); + self.capture_name_idx.insert(n, index as usize); + } + self.c_capture(2 * index as usize, &g.hir) + } + } + } + Concat(ref es) => { + if self.compiled.is_reverse { + self.c_concat(es.iter().rev()) + } else { + self.c_concat(es) + } + } + Alternation(ref es) => self.c_alternate(&**es), + Repetition(ref rep) => self.c_repeat(rep), + } + } + + fn c_capture(&mut self, first_slot: usize, expr: &Hir) -> Result { + if self.num_exprs > 1 || self.compiled.is_dfa { + // Don't ever compile Save instructions for regex sets because + // they are never used. They are also never used in DFA programs + // because DFAs can't handle captures. + self.c(expr) + } else { + let entry = self.insts.len(); + let hole = self.push_hole(InstHole::Save { slot: first_slot }); + let patch = self.c(expr)?; + self.fill(hole, patch.entry); + self.fill_to_next(patch.hole); + let hole = self.push_hole(InstHole::Save { slot: first_slot + 1 }); + Ok(Patch { hole: hole, entry: entry }) + } + } + + fn c_dotstar(&mut self) -> Result { + Ok(if !self.compiled.only_utf8() { + self.c(&Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::ZeroOrMore, + greedy: false, + hir: Box::new(Hir::any(true)), + }))? + } else { + self.c(&Hir::repetition(hir::Repetition { + kind: hir::RepetitionKind::ZeroOrMore, + greedy: false, + hir: Box::new(Hir::any(false)), + }))? + }) + } + + fn c_char(&mut self, c: char) -> Result { + self.c_class(&[hir::ClassUnicodeRange::new(c, c)]) + } + + fn c_class(&mut self, ranges: &[hir::ClassUnicodeRange]) -> Result { + assert!(!ranges.is_empty()); + if self.compiled.uses_bytes() { + CompileClass { + c: self, + ranges: ranges, + }.compile() + } else { + let ranges: Vec<(char, char)> = + ranges.iter().map(|r| (r.start(), r.end())).collect(); + let hole = if ranges.len() == 1 && ranges[0].0 == ranges[0].1 { + self.push_hole(InstHole::Char { c: ranges[0].0 }) + } else { + self.push_hole(InstHole::Ranges { ranges: ranges }) + }; + Ok(Patch { hole: hole, entry: self.insts.len() - 1 }) + } + } + + fn c_byte(&mut self, b: u8) -> Result { + self.c_class_bytes(&[hir::ClassBytesRange::new(b, b)]) + } + + fn c_class_bytes(&mut self, ranges: &[hir::ClassBytesRange]) -> Result { + debug_assert!(!ranges.is_empty()); + + let first_split_entry = self.insts.len(); + let mut holes = vec![]; + let mut prev_hole = Hole::None; + for r in &ranges[0..ranges.len() - 1] { + self.fill_to_next(prev_hole); + let split = self.push_split_hole(); + let next = self.insts.len(); + self.byte_classes.set_range(r.start(), r.end()); + holes.push(self.push_hole(InstHole::Bytes { + start: r.start(), end: r.end(), + })); + prev_hole = self.fill_split(split, Some(next), None); + } + let next = self.insts.len(); + let r = &ranges[ranges.len() - 1]; + self.byte_classes.set_range(r.start(), r.end()); + holes.push(self.push_hole(InstHole::Bytes { + start: r.start(), end: r.end(), + })); + self.fill(prev_hole, next); + Ok(Patch { hole: Hole::Many(holes), entry: first_split_entry }) + } + + fn c_empty_look(&mut self, look: EmptyLook) -> Result { + let hole = self.push_hole(InstHole::EmptyLook { look: look }); + Ok(Patch { hole: hole, entry: self.insts.len() - 1 }) + } + + fn c_concat<'a, I>(&mut self, exprs: I) -> Result + where I: IntoIterator<Item=&'a Hir> { + let mut exprs = exprs.into_iter(); + let first = match exprs.next() { + Some(expr) => expr, + None => { + return Ok(Patch { hole: Hole::None, entry: self.insts.len() }) + } + }; + let Patch { mut hole, entry } = self.c(first)?; + for e in exprs { + let p = self.c(e)?; + self.fill(hole, p.entry); + hole = p.hole; + } + Ok(Patch { hole: hole, entry: entry }) + } + + fn c_alternate(&mut self, exprs: &[Hir]) -> Result { + debug_assert!( + exprs.len() >= 2, "alternates must have at least 2 exprs"); + + // Initial entry point is always the first split. + let first_split_entry = self.insts.len(); + + // Save up all of the holes from each alternate. They will all get + // patched to point to the same location. + let mut holes = vec![]; + + let mut prev_hole = Hole::None; + for e in &exprs[0..exprs.len() - 1] { + self.fill_to_next(prev_hole); + let split = self.push_split_hole(); + let prev_entry = self.insts.len(); + let Patch { hole, entry } = self.c(e)?; + if prev_entry == self.insts.len() { + // TODO(burntsushi): It is kind of silly that we don't support + // empty-subexpressions in alternates, but it is supremely + // awkward to support them in the existing compiler + // infrastructure. This entire compiler needs to be thrown out + // anyway, so don't feel too bad. + return Err(Error::Syntax( + "alternations cannot currently contain \ + empty sub-expressions".to_string())); + } + holes.push(hole); + prev_hole = self.fill_split(split, Some(entry), None); + } + let prev_entry = self.insts.len(); + let Patch { hole, entry } = self.c(&exprs[exprs.len() - 1])?; + if prev_entry == self.insts.len() { + // TODO(burntsushi): See TODO above. + return Err(Error::Syntax( + "alternations cannot currently contain \ + empty sub-expressions".to_string())); + } + holes.push(hole); + self.fill(prev_hole, entry); + Ok(Patch { hole: Hole::Many(holes), entry: first_split_entry }) + } + + fn c_repeat(&mut self, rep: &hir::Repetition) -> Result { + use syntax::hir::RepetitionKind::*; + match rep.kind { + ZeroOrOne => self.c_repeat_zero_or_one(&rep.hir, rep.greedy), + ZeroOrMore => self.c_repeat_zero_or_more(&rep.hir, rep.greedy), + OneOrMore => self.c_repeat_one_or_more(&rep.hir, rep.greedy), + Range(hir::RepetitionRange::Exactly(min_max)) => { + self.c_repeat_range(&rep.hir, rep.greedy, min_max, min_max) + } + Range(hir::RepetitionRange::AtLeast(min)) => { + self.c_repeat_range_min_or_more(&rep.hir, rep.greedy, min) + } + Range(hir::RepetitionRange::Bounded(min, max)) => { + self.c_repeat_range(&rep.hir, rep.greedy, min, max) + } + } + } + + fn c_repeat_zero_or_one(&mut self, expr: &Hir, greedy: bool) -> Result { + let split_entry = self.insts.len(); + let split = self.push_split_hole(); + let Patch { hole: hole_rep, entry: entry_rep } = self.c(expr)?; + + let split_hole = if greedy { + self.fill_split(split, Some(entry_rep), None) + } else { + self.fill_split(split, None, Some(entry_rep)) + }; + let holes = vec![hole_rep, split_hole]; + Ok(Patch { hole: Hole::Many(holes), entry: split_entry }) + } + + fn c_repeat_zero_or_more(&mut self, expr: &Hir, greedy: bool) -> Result { + let split_entry = self.insts.len(); + let split = self.push_split_hole(); + let Patch { hole: hole_rep, entry: entry_rep } = self.c(expr)?; + + self.fill(hole_rep, split_entry); + let split_hole = if greedy { + self.fill_split(split, Some(entry_rep), None) + } else { + self.fill_split(split, None, Some(entry_rep)) + }; + Ok(Patch { hole: split_hole, entry: split_entry }) + } + + fn c_repeat_one_or_more(&mut self, expr: &Hir, greedy: bool) -> Result { + let Patch { hole: hole_rep, entry: entry_rep } = self.c(expr)?; + self.fill_to_next(hole_rep); + let split = self.push_split_hole(); + + let split_hole = if greedy { + self.fill_split(split, Some(entry_rep), None) + } else { + self.fill_split(split, None, Some(entry_rep)) + }; + Ok(Patch { hole: split_hole, entry: entry_rep }) + } + + fn c_repeat_range_min_or_more( + &mut self, + expr: &Hir, + greedy: bool, + min: u32, + ) -> Result { + let min = u32_to_usize(min); + let patch_concat = self.c_concat(iter::repeat(expr).take(min))?; + let patch_rep = self.c_repeat_zero_or_more(expr, greedy)?; + self.fill(patch_concat.hole, patch_rep.entry); + Ok(Patch { hole: patch_rep.hole, entry: patch_concat.entry }) + } + + fn c_repeat_range( + &mut self, + expr: &Hir, + greedy: bool, + min: u32, + max: u32, + ) -> Result { + let (min, max) = (u32_to_usize(min), u32_to_usize(max)); + let patch_concat = self.c_concat(iter::repeat(expr).take(min))?; + let initial_entry = patch_concat.entry; + if min == max { + return Ok(patch_concat); + } + // It is much simpler to compile, e.g., `a{2,5}` as: + // + // aaa?a?a? + // + // But you end up with a sequence of instructions like this: + // + // 0: 'a' + // 1: 'a', + // 2: split(3, 4) + // 3: 'a' + // 4: split(5, 6) + // 5: 'a' + // 6: split(7, 8) + // 7: 'a' + // 8: MATCH + // + // This is *incredibly* inefficient because the splits end + // up forming a chain, which has to be resolved everything a + // transition is followed. + let mut holes = vec![]; + let mut prev_hole = patch_concat.hole; + for _ in min..max { + self.fill_to_next(prev_hole); + let split = self.push_split_hole(); + let Patch { hole, entry } = self.c(expr)?; + prev_hole = hole; + if greedy { + holes.push(self.fill_split(split, Some(entry), None)); + } else { + holes.push(self.fill_split(split, None, Some(entry))); + } + } + holes.push(prev_hole); + Ok(Patch { hole: Hole::Many(holes), entry: initial_entry }) + } + + fn fill(&mut self, hole: Hole, goto: InstPtr) { + match hole { + Hole::None => {} + Hole::One(pc) => { + self.insts[pc].fill(goto); + } + Hole::Many(holes) => { + for hole in holes { + self.fill(hole, goto); + } + } + } + } + + fn fill_to_next(&mut self, hole: Hole) { + let next = self.insts.len(); + self.fill(hole, next); + } + + fn fill_split( + &mut self, + hole: Hole, + goto1: Option<InstPtr>, + goto2: Option<InstPtr>, + ) -> Hole { + match hole { + Hole::None => Hole::None, + Hole::One(pc) => { + match (goto1, goto2) { + (Some(goto1), Some(goto2)) => { + self.insts[pc].fill_split(goto1, goto2); + Hole::None + } + (Some(goto1), None) => { + self.insts[pc].half_fill_split_goto1(goto1); + Hole::One(pc) + } + (None, Some(goto2)) => { + self.insts[pc].half_fill_split_goto2(goto2); + Hole::One(pc) + } + (None, None) => unreachable!("at least one of the split \ + holes must be filled"), + } + } + Hole::Many(holes) => { + let mut new_holes = vec![]; + for hole in holes { + new_holes.push(self.fill_split(hole, goto1, goto2)); + } + if new_holes.is_empty() { + Hole::None + } else if new_holes.len() == 1 { + new_holes.pop().unwrap() + } else { + Hole::Many(new_holes) + } + } + } + } + + fn push_compiled(&mut self, inst: Inst) { + self.insts.push(MaybeInst::Compiled(inst)); + } + + fn push_hole(&mut self, inst: InstHole) -> Hole { + let hole = self.insts.len(); + self.insts.push(MaybeInst::Uncompiled(inst)); + Hole::One(hole) + } + + fn push_split_hole(&mut self) -> Hole { + let hole = self.insts.len(); + self.insts.push(MaybeInst::Split); + Hole::One(hole) + } + + fn check_size(&self) -> result::Result<(), Error> { + use std::mem::size_of; + + if self.insts.len() * size_of::<Inst>() > self.size_limit { + Err(Error::CompiledTooBig(self.size_limit)) + } else { + Ok(()) + } + } +} + +#[derive(Debug)] +enum Hole { + None, + One(InstPtr), + Many(Vec<Hole>), +} + +#[derive(Clone, Debug)] +enum MaybeInst { + Compiled(Inst), + Uncompiled(InstHole), + Split, + Split1(InstPtr), + Split2(InstPtr), +} + +impl MaybeInst { + fn fill(&mut self, goto: InstPtr) { + let filled = match *self { + MaybeInst::Uncompiled(ref inst) => inst.fill(goto), + MaybeInst::Split1(goto1) => { + Inst::Split(InstSplit { goto1: goto1, goto2: goto }) + } + MaybeInst::Split2(goto2) => { + Inst::Split(InstSplit { goto1: goto, goto2: goto2 }) + } + _ => unreachable!("not all instructions were compiled! \ + found uncompiled instruction: {:?}", self), + }; + *self = MaybeInst::Compiled(filled); + } + + fn fill_split(&mut self, goto1: InstPtr, goto2: InstPtr) { + let filled = match *self { + MaybeInst::Split => { + Inst::Split(InstSplit { goto1: goto1, goto2: goto2 }) + } + _ => unreachable!("must be called on Split instruction, \ + instead it was called on: {:?}", self), + }; + *self = MaybeInst::Compiled(filled); + } + + fn half_fill_split_goto1(&mut self, goto1: InstPtr) { + let half_filled = match *self { + MaybeInst::Split => goto1, + _ => unreachable!("must be called on Split instruction, \ + instead it was called on: {:?}", self), + }; + *self = MaybeInst::Split1(half_filled); + } + + fn half_fill_split_goto2(&mut self, goto2: InstPtr) { + let half_filled = match *self { + MaybeInst::Split => goto2, + _ => unreachable!("must be called on Split instruction, \ + instead it was called on: {:?}", self), + }; + *self = MaybeInst::Split2(half_filled); + } + + fn unwrap(self) -> Inst { + match self { + MaybeInst::Compiled(inst) => inst, + _ => unreachable!("must be called on a compiled instruction, \ + instead it was called on: {:?}", self), + } + } +} + +#[derive(Clone, Debug)] +enum InstHole { + Save { slot: usize }, + EmptyLook { look: EmptyLook }, + Char { c: char }, + Ranges { ranges: Vec<(char, char)> }, + Bytes { start: u8, end: u8 }, +} + +impl InstHole { + fn fill(&self, goto: InstPtr) -> Inst { + match *self { + InstHole::Save { slot } => Inst::Save(InstSave { + goto: goto, + slot: slot, + }), + InstHole::EmptyLook { look } => Inst::EmptyLook(InstEmptyLook { + goto: goto, + look: look, + }), + InstHole::Char { c } => Inst::Char(InstChar { + goto: goto, + c: c, + }), + InstHole::Ranges { ref ranges } => Inst::Ranges(InstRanges { + goto: goto, + ranges: ranges.clone(), + }), + InstHole::Bytes { start, end } => Inst::Bytes(InstBytes { + goto: goto, + start: start, + end: end, + }), + } + } +} + +struct CompileClass<'a, 'b> { + c: &'a mut Compiler, + ranges: &'b [hir::ClassUnicodeRange], +} + +impl<'a, 'b> CompileClass<'a, 'b> { + fn compile(mut self) -> Result { + let mut holes = vec![]; + let mut initial_entry = None; + let mut last_split = Hole::None; + let mut utf8_seqs = self.c.utf8_seqs.take().unwrap(); + self.c.suffix_cache.clear(); + + for (i, range) in self.ranges.iter().enumerate() { + let is_last_range = i + 1 == self.ranges.len(); + utf8_seqs.reset(range.start(), range.end()); + let mut it = (&mut utf8_seqs).peekable(); + loop { + let utf8_seq = match it.next() { + None => break, + Some(utf8_seq) => utf8_seq, + }; + if is_last_range && it.peek().is_none() { + let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?; + holes.push(hole); + self.c.fill(last_split, entry); + last_split = Hole::None; + if initial_entry.is_none() { + initial_entry = Some(entry); + } + } else { + if initial_entry.is_none() { + initial_entry = Some(self.c.insts.len()); + } + self.c.fill_to_next(last_split); + last_split = self.c.push_split_hole(); + let Patch { hole, entry } = self.c_utf8_seq(&utf8_seq)?; + holes.push(hole); + last_split = self.c.fill_split(last_split, Some(entry), None); + } + } + } + self.c.utf8_seqs = Some(utf8_seqs); + Ok(Patch { + hole: Hole::Many(holes), + entry: initial_entry.unwrap(), + }) + } + + fn c_utf8_seq(&mut self, seq: &Utf8Sequence) -> Result { + if self.c.compiled.is_reverse { + self.c_utf8_seq_(seq) + } else { + self.c_utf8_seq_(seq.into_iter().rev()) + } + } + + fn c_utf8_seq_<'r, I>(&mut self, seq: I) -> Result + where I: IntoIterator<Item=&'r Utf8Range> { + // The initial instruction for each UTF-8 sequence should be the same. + let mut from_inst = ::std::usize::MAX; + let mut last_hole = Hole::None; + for byte_range in seq { + let key = SuffixCacheKey { + from_inst: from_inst, + start: byte_range.start, + end: byte_range.end, + }; + { + let pc = self.c.insts.len(); + if let Some(cached_pc) = self.c.suffix_cache.get(key, pc) { + from_inst = cached_pc; + continue; + } + } + self.c.byte_classes.set_range(byte_range.start, byte_range.end); + if from_inst == ::std::usize::MAX { + last_hole = self.c.push_hole(InstHole::Bytes { + start: byte_range.start, + end: byte_range.end, + }); + } else { + self.c.push_compiled(Inst::Bytes(InstBytes { + goto: from_inst, + start: byte_range.start, + end: byte_range.end, + })); + } + from_inst = self.c.insts.len().checked_sub(1).unwrap(); + debug_assert!(from_inst < ::std::usize::MAX); + } + debug_assert!(from_inst < ::std::usize::MAX); + Ok(Patch { hole: last_hole, entry: from_inst }) + } +} + +/// `SuffixCache` is a simple bounded hash map for caching suffix entries in +/// UTF-8 automata. For example, consider the Unicode range \u{0}-\u{FFFF}. +/// The set of byte ranges looks like this: +/// +/// [0-7F] +/// [C2-DF][80-BF] +/// [E0][A0-BF][80-BF] +/// [E1-EC][80-BF][80-BF] +/// [ED][80-9F][80-BF] +/// [EE-EF][80-BF][80-BF] +/// +/// Each line above translates to one alternate in the compiled regex program. +/// However, all but one of the alternates end in the same suffix, which is +/// a waste of an instruction. The suffix cache facilitates reusing them across +/// alternates. +/// +/// Note that a HashMap could be trivially used for this, but we don't need its +/// overhead. Some small bounded space (LRU style) is more than enough. +/// +/// This uses similar idea to [`SparseSet`](../sparse/struct.SparseSet.html), +/// except it uses hashes as original indices and then compares full keys for +/// validation against `dense` array. +struct SuffixCache { + sparse: Box<[usize]>, + dense: Vec<SuffixCacheEntry>, +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +struct SuffixCacheEntry { + key: SuffixCacheKey, + pc: InstPtr, +} + +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +struct SuffixCacheKey { + from_inst: InstPtr, + start: u8, + end: u8, +} + +impl SuffixCache { + fn new(size: usize) -> Self { + SuffixCache { + sparse: vec![0usize; size].into(), + dense: Vec::with_capacity(size), + } + } + + fn get(&mut self, key: SuffixCacheKey, pc: InstPtr) -> Option<InstPtr> { + let hash = self.hash(&key); + let pos = &mut self.sparse[hash]; + if let Some(entry) = self.dense.get(*pos) { + if entry.key == key { + return Some(entry.pc); + } + } + *pos = self.dense.len(); + self.dense.push(SuffixCacheEntry { + key: key, + pc: pc, + }); + None + } + + fn clear(&mut self) { + self.dense.clear(); + } + + fn hash(&self, suffix: &SuffixCacheKey) -> usize { + // Basic FNV-1a hash as described: + // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + const FNV_PRIME: u64 = 1099511628211; + let mut h = 14695981039346656037; + h = (h ^ (suffix.from_inst as u64)).wrapping_mul(FNV_PRIME); + h = (h ^ (suffix.start as u64)).wrapping_mul(FNV_PRIME); + h = (h ^ (suffix.end as u64)).wrapping_mul(FNV_PRIME); + (h as usize) % self.sparse.len() + } +} + +struct ByteClassSet([bool; 256]); + +impl ByteClassSet { + fn new() -> Self { + ByteClassSet([false; 256]) + } + + fn set_range(&mut self, start: u8, end: u8) { + debug_assert!(start <= end); + if start > 0 { + self.0[start as usize - 1] = true; + } + self.0[end as usize] = true; + } + + fn set_word_boundary(&mut self) { + // We need to mark all ranges of bytes whose pairs result in + // evaluating \b differently. + let iswb = is_word_byte; + let mut b1: u16 = 0; + let mut b2: u16; + while b1 <= 255 { + b2 = b1 + 1; + while b2 <= 255 && iswb(b1 as u8) == iswb(b2 as u8) { + b2 += 1; + } + self.set_range(b1 as u8, (b2 - 1) as u8); + b1 = b2; + } + } + + fn byte_classes(&self) -> Vec<u8> { + // N.B. If you're debugging the DFA, it's useful to simply return + // `(0..256).collect()`, which effectively removes the byte classes + // and makes the transitions easier to read. + // (0usize..256).map(|x| x as u8).collect() + let mut byte_classes = vec![0; 256]; + let mut class = 0u8; + let mut i = 0; + loop { + byte_classes[i] = class as u8; + if i >= 255 { + break; + } + if self.0[i] { + class = class.checked_add(1).unwrap(); + } + i += 1; + } + byte_classes + } +} + +fn u32_to_usize(n: u32) -> usize { + // In case usize is less than 32 bits, we need to guard against overflow. + // On most platforms this compiles to nothing. + // TODO Use `std::convert::TryFrom` once it's stable. + if (n as u64) > (::std::usize::MAX as u64) { + panic!("BUG: {} is too big to be pointer sized", n) + } + n as usize +} + +#[cfg(test)] +mod tests { + use super::ByteClassSet; + + #[test] + fn byte_classes() { + let mut set = ByteClassSet::new(); + set.set_range(b'a', b'z'); + let classes = set.byte_classes(); + assert_eq!(classes[0], 0); + assert_eq!(classes[1], 0); + assert_eq!(classes[2], 0); + assert_eq!(classes[b'a' as usize - 1], 0); + assert_eq!(classes[b'a' as usize], 1); + assert_eq!(classes[b'm' as usize], 1); + assert_eq!(classes[b'z' as usize], 1); + assert_eq!(classes[b'z' as usize + 1], 2); + assert_eq!(classes[254], 2); + assert_eq!(classes[255], 2); + + let mut set = ByteClassSet::new(); + set.set_range(0, 2); + set.set_range(4, 6); + let classes = set.byte_classes(); + assert_eq!(classes[0], 0); + assert_eq!(classes[1], 0); + assert_eq!(classes[2], 0); + assert_eq!(classes[3], 1); + assert_eq!(classes[4], 2); + assert_eq!(classes[5], 2); + assert_eq!(classes[6], 2); + assert_eq!(classes[7], 3); + assert_eq!(classes[255], 3); + } + + #[test] + fn full_byte_classes() { + let mut set = ByteClassSet::new(); + for i in 0..256u16 { + set.set_range(i as u8, i as u8); + } + assert_eq!(set.byte_classes().len(), 256); + } +} diff --git a/regex/src/dfa.rs b/regex/src/dfa.rs new file mode 100644 index 000000000..e662b7338 --- /dev/null +++ b/regex/src/dfa.rs @@ -0,0 +1,1965 @@ +// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +The DFA matching engine. + +A DFA provides faster matching because the engine is in exactly one state at +any point in time. In the NFA, there may be multiple active states, and +considerable CPU cycles are spent shuffling them around. In finite automata +speak, the DFA follows epsilon transitions in the regex far less than the NFA. + +A DFA is a classic trade off between time and space. The NFA is slower, but +its memory requirements are typically small and predictable. The DFA is faster, +but given the right regex and the right input, the number of states in the +DFA can grow exponentially. To mitigate this space problem, we do two things: + +1. We implement an *online* DFA. That is, the DFA is constructed from the NFA + during a search. When a new state is computed, it is stored in a cache so + that it may be reused. An important consequence of this implementation + is that states that are never reached for a particular input are never + computed. (This is impossible in an "offline" DFA which needs to compute + all possible states up front.) +2. If the cache gets too big, we wipe it and continue matching. + +In pathological cases, a new state can be created for every byte of input. +(e.g., The regex `(a|b)*a(a|b){20}` on a long sequence of a's and b's.) +In this case, performance regresses to slightly slower than the full NFA +simulation, in large part because the cache becomes useless. If the cache +is wiped too frequently, the DFA quits and control falls back to one of the +NFA simulations. + +Because of the "lazy" nature of this DFA, the inner matching loop is +considerably more complex than one might expect out of a DFA. A number of +tricks are employed to make it fast. Tread carefully. + +N.B. While this implementation is heavily commented, Russ Cox's series of +articles on regexes is strongly recommended: https://swtch.com/~rsc/regexp/ +(As is the DFA implementation in RE2, which heavily influenced this +implementation.) +*/ + +use std::collections::HashMap; +use std::fmt; +use std::iter::repeat; +use std::mem; +use std::sync::Arc; + +use exec::ProgramCache; +use prog::{Inst, Program}; +use sparse::SparseSet; + +/// Return true if and only if the given program can be executed by a DFA. +/// +/// Generally, a DFA is always possible. A pathological case where it is not +/// possible is if the number of NFA states exceeds `u32::MAX`, in which case, +/// this function will return false. +/// +/// This function will also return false if the given program has any Unicode +/// instructions (Char or Ranges) since the DFA operates on bytes only. +pub fn can_exec(insts: &Program) -> bool { + use prog::Inst::*; + // If for some reason we manage to allocate a regex program with more + // than i32::MAX instructions, then we can't execute the DFA because we + // use 32 bit instruction pointer deltas for memory savings. + // If i32::MAX is the largest positive delta, + // then -i32::MAX == i32::MIN + 1 is the largest negative delta, + // and we are OK to use 32 bits. + if insts.dfa_size_limit == 0 || insts.len() > ::std::i32::MAX as usize { + return false; + } + for inst in insts { + match *inst { + Char(_) | Ranges(_) => return false, + EmptyLook(_) | Match(_) | Save(_) | Split(_) | Bytes(_) => {} + } + } + true +} + +/// A reusable cache of DFA states. +/// +/// This cache is reused between multiple invocations of the same regex +/// program. (It is not shared simultaneously between threads. If there is +/// contention, then new caches are created.) +#[derive(Debug)] +pub struct Cache { + /// Group persistent DFA related cache state together. The sparse sets + /// listed below are used as scratch space while computing uncached states. + inner: CacheInner, + /// qcur and qnext are ordered sets with constant time + /// addition/membership/clearing-whole-set and linear time iteration. They + /// are used to manage the sets of NFA states in DFA states when computing + /// cached DFA states. In particular, the order of the NFA states matters + /// for leftmost-first style matching. Namely, when computing a cached + /// state, the set of NFA states stops growing as soon as the first Match + /// instruction is observed. + qcur: SparseSet, + qnext: SparseSet, +} + +/// `CacheInner` is logically just a part of Cache, but groups together fields +/// that aren't passed as function parameters throughout search. (This split +/// is mostly an artifact of the borrow checker. It is happily paid.) +#[derive(Debug)] +struct CacheInner { + /// A cache of pre-compiled DFA states, keyed by the set of NFA states + /// and the set of empty-width flags set at the byte in the input when the + /// state was observed. + /// + /// A StatePtr is effectively a `*State`, but to avoid various inconvenient + /// things, we just pass indexes around manually. The performance impact of + /// this is probably an instruction or two in the inner loop. However, on + /// 64 bit, each StatePtr is half the size of a *State. + compiled: StateMap, + /// The transition table. + /// + /// The transition table is laid out in row-major order, where states are + /// rows and the transitions for each state are columns. At a high level, + /// given state `s` and byte `b`, the next state can be found at index + /// `s * 256 + b`. + /// + /// This is, of course, a lie. A StatePtr is actually a pointer to the + /// *start* of a row in this table. When indexing in the DFA's inner loop, + /// this removes the need to multiply the StatePtr by the stride. Yes, it + /// matters. This reduces the number of states we can store, but: the + /// stride is rarely 256 since we define transitions in terms of + /// *equivalence classes* of bytes. Each class corresponds to a set of + /// bytes that never discriminate a distinct path through the DFA from each + /// other. + trans: Transitions, + /// A set of cached start states, which are limited to the number of + /// permutations of flags set just before the initial byte of input. (The + /// index into this vec is a `EmptyFlags`.) + /// + /// N.B. A start state can be "dead" (i.e., no possible match), so we + /// represent it with a StatePtr. + start_states: Vec<StatePtr>, + /// Stack scratch space used to follow epsilon transitions in the NFA. + /// (This permits us to avoid recursion.) + /// + /// The maximum stack size is the number of NFA states. + stack: Vec<InstPtr>, + /// The total number of times this cache has been flushed by the DFA + /// because of space constraints. + flush_count: u64, + /// The total heap size of the DFA's cache. We use this to determine when + /// we should flush the cache. + size: usize, + /// Scratch space used when building instruction pointer lists for new + /// states. This helps amortize allocation. + insts_scratch_space: Vec<u8>, +} + +/// The transition table. +/// +/// It is laid out in row-major order, with states as rows and byte class +/// transitions as columns. +/// +/// The transition table is responsible for producing valid `StatePtrs`. A +/// `StatePtr` points to the start of a particular row in this table. When +/// indexing to find the next state this allows us to avoid a multiplication +/// when computing an index into the table. +#[derive(Clone)] +struct Transitions { + /// The table. + table: Vec<StatePtr>, + /// The stride. + num_byte_classes: usize, +} + +/// Fsm encapsulates the actual execution of the DFA. +#[derive(Debug)] +pub struct Fsm<'a> { + /// prog contains the NFA instruction opcodes. DFA execution uses either + /// the `dfa` instructions or the `dfa_reverse` instructions from + /// `exec::ExecReadOnly`. (It never uses `ExecReadOnly.nfa`, which may have + /// Unicode opcodes that cannot be executed by the DFA.) + prog: &'a Program, + /// The start state. We record it here because the pointer may change + /// when the cache is wiped. + start: StatePtr, + /// The current position in the input. + at: usize, + /// Should we quit after seeing the first match? e.g., When the caller + /// uses `is_match` or `shortest_match`. + quit_after_match: bool, + /// The last state that matched. + /// + /// When no match has occurred, this is set to STATE_UNKNOWN. + /// + /// This is only useful when matching regex sets. The last match state + /// is useful because it contains all of the match instructions seen, + /// thereby allowing us to enumerate which regexes in the set matched. + last_match_si: StatePtr, + /// The input position of the last cache flush. We use this to determine + /// if we're thrashing in the cache too often. If so, the DFA quits so + /// that we can fall back to the NFA algorithm. + last_cache_flush: usize, + /// All cached DFA information that is persisted between searches. + cache: &'a mut CacheInner, +} + +/// The result of running the DFA. +/// +/// Generally, the result is either a match or not a match, but sometimes the +/// DFA runs too slowly because the cache size is too small. In that case, it +/// gives up with the intent of falling back to the NFA algorithm. +/// +/// The DFA can also give up if it runs out of room to create new states, or if +/// it sees non-ASCII bytes in the presence of a Unicode word boundary. +#[derive(Clone, Debug)] +pub enum Result<T> { + Match(T), + NoMatch(usize), + Quit, +} + +impl<T> Result<T> { + /// Returns true if this result corresponds to a match. + pub fn is_match(&self) -> bool { + match *self { + Result::Match(_) => true, + Result::NoMatch(_) | Result::Quit => false, + } + } + + /// Maps the given function onto T and returns the result. + /// + /// If this isn't a match, then this is a no-op. + pub fn map<U, F: FnMut(T) -> U>(self, mut f: F) -> Result<U> { + match self { + Result::Match(t) => Result::Match(f(t)), + Result::NoMatch(x) => Result::NoMatch(x), + Result::Quit => Result::Quit, + } + } + + /// Sets the non-match position. + /// + /// If this isn't a non-match, then this is a no-op. + fn set_non_match(self, at: usize) -> Result<T> { + match self { + Result::NoMatch(_) => Result::NoMatch(at), + r => r, + } + } +} + +/// `State` is a DFA state. It contains an ordered set of NFA states (not +/// necessarily complete) and a smattering of flags. +/// +/// The flags are packed into the first byte of data. +/// +/// States don't carry their transitions. Instead, transitions are stored in +/// a single row-major table. +/// +/// Delta encoding is used to store the instruction pointers. +/// The first instruction pointer is stored directly starting +/// at data[1], and each following pointer is stored as an offset +/// to the previous one. If a delta is in the range -127..127, +/// it is packed into a single byte; Otherwise the byte 128 (-128 as an i8) +/// is coded as a flag, followed by 4 bytes encoding the delta. +#[derive(Clone, Eq, Hash, PartialEq)] +struct State { + data: Arc<[u8]>, +} + +/// `InstPtr` is a 32 bit pointer into a sequence of opcodes (i.e., it indexes +/// an NFA state). +/// +/// Throughout this library, this is usually set to `usize`, but we force a +/// `u32` here for the DFA to save on space. +type InstPtr = u32; + +/// Adds ip to data using delta encoding with respect to prev. +/// +/// After completion, `data` will contain `ip` and `prev` will be set to `ip`. +fn push_inst_ptr(data: &mut Vec<u8>, prev: &mut InstPtr, ip: InstPtr) { + let delta = (ip as i32) - (*prev as i32); + write_vari32(data, delta); + *prev = ip; +} + +struct InstPtrs<'a> { + base: usize, + data: &'a [u8], +} + +impl <'a>Iterator for InstPtrs<'a> { + type Item = usize; + + fn next(&mut self) -> Option<usize> { + if self.data.is_empty() { + return None; + } + let (delta, nread) = read_vari32(self.data); + let base = self.base as i32 + delta; + debug_assert!(base >= 0); + debug_assert!(nread > 0); + self.data = &self.data[nread..]; + self.base = base as usize; + Some(self.base) + } +} + +impl State { + fn flags(&self) -> StateFlags { + StateFlags(self.data[0]) + } + + fn inst_ptrs(&self) -> InstPtrs { + InstPtrs { + base: 0, + data: &self.data[1..], + } + } +} + +/// `StatePtr` is a 32 bit pointer to the start of a row in the transition +/// table. +/// +/// It has many special values. There are two types of special values: +/// sentinels and flags. +/// +/// Sentinels corresponds to special states that carry some kind of +/// significance. There are three such states: unknown, dead and quit states. +/// +/// Unknown states are states that haven't been computed yet. They indicate +/// that a transition should be filled in that points to either an existing +/// cached state or a new state altogether. In general, an unknown state means +/// "follow the NFA's epsilon transitions." +/// +/// Dead states are states that can never lead to a match, no matter what +/// subsequent input is observed. This means that the DFA should quit +/// immediately and return the longest match it has found thus far. +/// +/// Quit states are states that imply the DFA is not capable of matching the +/// regex correctly. Currently, this is only used when a Unicode word boundary +/// exists in the regex *and* a non-ASCII byte is observed. +/// +/// The other type of state pointer is a state pointer with special flag bits. +/// There are two flags: a start flag and a match flag. The lower bits of both +/// kinds always contain a "valid" `StatePtr` (indicated by the `STATE_MAX` +/// mask). +/// +/// The start flag means that the state is a start state, and therefore may be +/// subject to special prefix scanning optimizations. +/// +/// The match flag means that the state is a match state, and therefore the +/// current position in the input (while searching) should be recorded. +/// +/// The above exists mostly in the service of making the inner loop fast. +/// In particular, the inner *inner* loop looks something like this: +/// +/// ```ignore +/// while state <= STATE_MAX and i < len(text): +/// state = state.next[i] +/// ``` +/// +/// This is nice because it lets us execute a lazy DFA as if it were an +/// entirely offline DFA (i.e., with very few instructions). The loop will +/// quit only when we need to examine a case that needs special attention. +type StatePtr = u32; + +/// An unknown state means that the state has not been computed yet, and that +/// the only way to progress is to compute it. +const STATE_UNKNOWN: StatePtr = 1<<31; + +/// A dead state means that the state has been computed and it is known that +/// once it is entered, no future match can ever occur. +const STATE_DEAD: StatePtr = STATE_UNKNOWN + 1; + +/// A quit state means that the DFA came across some input that it doesn't +/// know how to process correctly. The DFA should quit and another matching +/// engine should be run in its place. +const STATE_QUIT: StatePtr = STATE_DEAD + 1; + +/// A start state is a state that the DFA can start in. +/// +/// Note that start states have their lower bits set to a state pointer. +const STATE_START: StatePtr = 1<<30; + +/// A match state means that the regex has successfully matched. +/// +/// Note that match states have their lower bits set to a state pointer. +const STATE_MATCH: StatePtr = 1<<29; + +/// The maximum state pointer. This is useful to mask out the "valid" state +/// pointer from a state with the "start" or "match" bits set. +/// +/// It doesn't make sense to use this with unknown, dead or quit state +/// pointers, since those pointers are sentinels and never have their lower +/// bits set to anything meaningful. +const STATE_MAX: StatePtr = STATE_MATCH - 1; + +/// Byte is a u8 in spirit, but a u16 in practice so that we can represent the +/// special EOF sentinel value. +#[derive(Copy, Clone, Debug)] +struct Byte(u16); + +/// A set of flags for zero-width assertions. +#[derive(Clone, Copy, Eq, Debug, Default, Hash, PartialEq)] +struct EmptyFlags { + start: bool, + end: bool, + start_line: bool, + end_line: bool, + word_boundary: bool, + not_word_boundary: bool, +} + +/// A set of flags describing various configurations of a DFA state. This is +/// represented by a `u8` so that it is compact. +#[derive(Clone, Copy, Eq, Default, Hash, PartialEq)] +struct StateFlags(u8); + +impl Cache { + /// Create new empty cache for the DFA engine. + pub fn new(prog: &Program) -> Self { + // We add 1 to account for the special EOF byte. + let num_byte_classes = (prog.byte_classes[255] as usize + 1) + 1; + let starts = vec![STATE_UNKNOWN; 256]; + let mut cache = Cache { + inner: CacheInner { + compiled: StateMap::new(num_byte_classes), + trans: Transitions::new(num_byte_classes), + start_states: starts, + stack: vec![], + flush_count: 0, + size: 0, + insts_scratch_space: vec![], + }, + qcur: SparseSet::new(prog.insts.len()), + qnext: SparseSet::new(prog.insts.len()), + }; + cache.inner.reset_size(); + cache + } +} + +impl CacheInner { + /// Resets the cache size to account for fixed costs, such as the program + /// and stack sizes. + fn reset_size(&mut self) { + self.size = + (self.start_states.len() * mem::size_of::<StatePtr>()) + + (self.stack.len() * mem::size_of::<InstPtr>()); + } +} + +impl<'a> Fsm<'a> { + #[inline(always)] // reduces constant overhead + pub fn forward( + prog: &'a Program, + cache: &ProgramCache, + quit_after_match: bool, + text: &[u8], + at: usize, + ) -> Result<usize> { + let mut cache = cache.borrow_mut(); + let cache = &mut cache.dfa; + let mut dfa = Fsm { + prog: prog, + start: 0, // filled in below + at: at, + quit_after_match: quit_after_match, + last_match_si: STATE_UNKNOWN, + last_cache_flush: at, + cache: &mut cache.inner, + }; + let (empty_flags, state_flags) = dfa.start_flags(text, at); + dfa.start = match dfa.start_state( + &mut cache.qcur, + empty_flags, + state_flags, + ) { + None => return Result::Quit, + Some(STATE_DEAD) => return Result::NoMatch(at), + Some(si) => si, + }; + debug_assert!(dfa.start != STATE_UNKNOWN); + dfa.exec_at(&mut cache.qcur, &mut cache.qnext, text) + } + + #[inline(always)] // reduces constant overhead + pub fn reverse( + prog: &'a Program, + cache: &ProgramCache, + quit_after_match: bool, + text: &[u8], + at: usize, + ) -> Result<usize> { + let mut cache = cache.borrow_mut(); + let cache = &mut cache.dfa_reverse; + let mut dfa = Fsm { + prog: prog, + start: 0, // filled in below + at: at, + quit_after_match: quit_after_match, + last_match_si: STATE_UNKNOWN, + last_cache_flush: at, + cache: &mut cache.inner, + }; + let (empty_flags, state_flags) = dfa.start_flags_reverse(text, at); + dfa.start = match dfa.start_state( + &mut cache.qcur, + empty_flags, + state_flags, + ) { + None => return Result::Quit, + Some(STATE_DEAD) => return Result::NoMatch(at), + Some(si) => si, + }; + debug_assert!(dfa.start != STATE_UNKNOWN); + dfa.exec_at_reverse(&mut cache.qcur, &mut cache.qnext, text) + } + + #[inline(always)] // reduces constant overhead + pub fn forward_many( + prog: &'a Program, + cache: &ProgramCache, + matches: &mut [bool], + text: &[u8], + at: usize, + ) -> Result<usize> { + debug_assert!(matches.len() == prog.matches.len()); + let mut cache = cache.borrow_mut(); + let cache = &mut cache.dfa; + let mut dfa = Fsm { + prog: prog, + start: 0, // filled in below + at: at, + quit_after_match: false, + last_match_si: STATE_UNKNOWN, + last_cache_flush: at, + cache: &mut cache.inner, + }; + let (empty_flags, state_flags) = dfa.start_flags(text, at); + dfa.start = match dfa.start_state( + &mut cache.qcur, + empty_flags, + state_flags, + ) { + None => return Result::Quit, + Some(STATE_DEAD) => return Result::NoMatch(at), + Some(si) => si, + }; + debug_assert!(dfa.start != STATE_UNKNOWN); + let result = dfa.exec_at(&mut cache.qcur, &mut cache.qnext, text); + if result.is_match() { + if matches.len() == 1 { + matches[0] = true; + } else { + debug_assert!(dfa.last_match_si != STATE_UNKNOWN); + debug_assert!(dfa.last_match_si != STATE_DEAD); + for ip in dfa.state(dfa.last_match_si).inst_ptrs() { + if let Inst::Match(slot) = dfa.prog[ip] { + matches[slot] = true; + } + } + } + } + result + } + + /// Executes the DFA on a forward NFA. + /// + /// {qcur,qnext} are scratch ordered sets which may be non-empty. + #[inline(always)] // reduces constant overhead + fn exec_at( + &mut self, + qcur: &mut SparseSet, + qnext: &mut SparseSet, + text: &[u8], + ) -> Result<usize> { + // For the most part, the DFA is basically: + // + // last_match = null + // while current_byte != EOF: + // si = current_state.next[current_byte] + // if si is match + // last_match = si + // return last_match + // + // However, we need to deal with a few things: + // + // 1. This is an *online* DFA, so the current state's next list + // may not point to anywhere yet, so we must go out and compute + // them. (They are then cached into the current state's next list + // to avoid re-computation.) + // 2. If we come across a state that is known to be dead (i.e., never + // leads to a match), then we can quit early. + // 3. If the caller just wants to know if a match occurs, then we + // can quit as soon as we know we have a match. (Full leftmost + // first semantics require continuing on.) + // 4. If we're in the start state, then we can use a pre-computed set + // of prefix literals to skip quickly along the input. + // 5. After the input is exhausted, we run the DFA on one symbol + // that stands for EOF. This is useful for handling empty width + // assertions. + // 6. We can't actually do state.next[byte]. Instead, we have to do + // state.next[byte_classes[byte]], which permits us to keep the + // 'next' list very small. + // + // Since there's a bunch of extra stuff we need to consider, we do some + // pretty hairy tricks to get the inner loop to run as fast as + // possible. + debug_assert!(!self.prog.is_reverse); + + // The last match is the currently known ending match position. It is + // reported as an index to the most recent byte that resulted in a + // transition to a match state and is always stored in capture slot `1` + // when searching forwards. Its maximum value is `text.len()`. + let mut result = Result::NoMatch(self.at); + let (mut prev_si, mut next_si) = (self.start, self.start); + let mut at = self.at; + while at < text.len() { + // This is the real inner loop. We take advantage of special bits + // set in the state pointer to determine whether a state is in the + // "common" case or not. Specifically, the common case is a + // non-match non-start non-dead state that has already been + // computed. So long as we remain in the common case, this inner + // loop will chew through the input. + // + // We also unroll the loop 4 times to amortize the cost of checking + // whether we've consumed the entire input. We are also careful + // to make sure that `prev_si` always represents the previous state + // and `next_si` always represents the next state after the loop + // exits, even if it isn't always true inside the loop. + while next_si <= STATE_MAX && at < text.len() { + // Argument for safety is in the definition of next_si. + prev_si = unsafe { self.next_si(next_si, text, at) }; + at += 1; + if prev_si > STATE_MAX || at + 2 >= text.len() { + mem::swap(&mut prev_si, &mut next_si); + break; + } + next_si = unsafe { self.next_si(prev_si, text, at) }; + at += 1; + if next_si > STATE_MAX { + break; + } + prev_si = unsafe { self.next_si(next_si, text, at) }; + at += 1; + if prev_si > STATE_MAX { + mem::swap(&mut prev_si, &mut next_si); + break; + } + next_si = unsafe { self.next_si(prev_si, text, at) }; + at += 1; + } + if next_si & STATE_MATCH > 0 { + // A match state is outside of the common case because it needs + // special case analysis. In particular, we need to record the + // last position as having matched and possibly quit the DFA if + // we don't need to keep matching. + next_si &= !STATE_MATCH; + result = Result::Match(at - 1); + if self.quit_after_match { + return result; + } + self.last_match_si = next_si; + prev_si = next_si; + + // This permits short-circuiting when matching a regex set. + // In particular, if this DFA state contains only match states, + // then it's impossible to extend the set of matches since + // match states are final. Therefore, we can quit. + if self.prog.matches.len() > 1 { + let state = self.state(next_si); + let just_matches = state.inst_ptrs() + .all(|ip| self.prog[ip].is_match()); + if just_matches { + return result; + } + } + + // Another inner loop! If the DFA stays in this particular + // match state, then we can rip through all of the input + // very quickly, and only recording the match location once + // we've left this particular state. + let cur = at; + while (next_si & !STATE_MATCH) == prev_si + && at + 2 < text.len() { + // Argument for safety is in the definition of next_si. + next_si = unsafe { + self.next_si(next_si & !STATE_MATCH, text, at) + }; + at += 1; + } + if at > cur { + result = Result::Match(at - 2); + } + } else if next_si & STATE_START > 0 { + // A start state isn't in the common case because we may + // what to do quick prefix scanning. If the program doesn't + // have a detected prefix, then start states are actually + // considered common and this case is never reached. + debug_assert!(self.has_prefix()); + next_si &= !STATE_START; + prev_si = next_si; + at = match self.prefix_at(text, at) { + None => return Result::NoMatch(text.len()), + Some(i) => i, + }; + } else if next_si >= STATE_UNKNOWN { + if next_si == STATE_QUIT { + return Result::Quit; + } + // Finally, this corresponds to the case where the transition + // entered a state that can never lead to a match or a state + // that hasn't been computed yet. The latter being the "slow" + // path. + let byte = Byte::byte(text[at - 1]); + // We no longer care about the special bits in the state + // pointer. + prev_si &= STATE_MAX; + // Record where we are. This is used to track progress for + // determining whether we should quit if we've flushed the + // cache too much. + self.at = at; + next_si = match self.next_state(qcur, qnext, prev_si, byte) { + None => return Result::Quit, + Some(STATE_DEAD) => return result.set_non_match(at), + Some(si) => si, + }; + debug_assert!(next_si != STATE_UNKNOWN); + if next_si & STATE_MATCH > 0 { + next_si &= !STATE_MATCH; + result = Result::Match(at - 1); + if self.quit_after_match { + return result; + } + self.last_match_si = next_si; + } + prev_si = next_si; + } else { + prev_si = next_si; + } + } + + // Run the DFA once more on the special EOF senitnel value. + // We don't care about the special bits in the state pointer any more, + // so get rid of them. + prev_si &= STATE_MAX; + prev_si = match self.next_state(qcur, qnext, prev_si, Byte::eof()) { + None => return Result::Quit, + Some(STATE_DEAD) => return result.set_non_match(text.len()), + Some(si) => si & !STATE_START, + }; + debug_assert!(prev_si != STATE_UNKNOWN); + if prev_si & STATE_MATCH > 0 { + prev_si &= !STATE_MATCH; + self.last_match_si = prev_si; + result = Result::Match(text.len()); + } + result + } + + /// Executes the DFA on a reverse NFA. + #[inline(always)] // reduces constant overhead + fn exec_at_reverse( + &mut self, + qcur: &mut SparseSet, + qnext: &mut SparseSet, + text: &[u8], + ) -> Result<usize> { + // The comments in `exec_at` above mostly apply here too. The main + // difference is that we move backwards over the input and we look for + // the longest possible match instead of the leftmost-first match. + // + // N.B. The code duplication here is regrettable. Efforts to improve + // it without sacrificing performance are welcome. ---AG + debug_assert!(self.prog.is_reverse); + let mut result = Result::NoMatch(self.at); + let (mut prev_si, mut next_si) = (self.start, self.start); + let mut at = self.at; + while at > 0 { + while next_si <= STATE_MAX && at > 0 { + // Argument for safety is in the definition of next_si. + at -= 1; + prev_si = unsafe { self.next_si(next_si, text, at) }; + if prev_si > STATE_MAX || at <= 4 { + mem::swap(&mut prev_si, &mut next_si); + break; + } + at -= 1; + next_si = unsafe { self.next_si(prev_si, text, at) }; + if next_si > STATE_MAX { + break; + } + at -= 1; + prev_si = unsafe { self.next_si(next_si, text, at) }; + if prev_si > STATE_MAX { + mem::swap(&mut prev_si, &mut next_si); + break; + } + at -= 1; + next_si = unsafe { self.next_si(prev_si, text, at) }; + } + if next_si & STATE_MATCH > 0 { + next_si &= !STATE_MATCH; + result = Result::Match(at + 1); + if self.quit_after_match { + return result + } + self.last_match_si = next_si; + prev_si = next_si; + let cur = at; + while (next_si & !STATE_MATCH) == prev_si && at >= 2 { + // Argument for safety is in the definition of next_si. + at -= 1; + next_si = unsafe { + self.next_si(next_si & !STATE_MATCH, text, at) + }; + } + if at < cur { + result = Result::Match(at + 2); + } + } else if next_si >= STATE_UNKNOWN { + if next_si == STATE_QUIT { + return Result::Quit; + } + let byte = Byte::byte(text[at]); + prev_si &= STATE_MAX; + self.at = at; + next_si = match self.next_state(qcur, qnext, prev_si, byte) { + None => return Result::Quit, + Some(STATE_DEAD) => return result.set_non_match(at), + Some(si) => si, + }; + debug_assert!(next_si != STATE_UNKNOWN); + if next_si & STATE_MATCH > 0 { + next_si &= !STATE_MATCH; + result = Result::Match(at + 1); + if self.quit_after_match { + return result; + } + self.last_match_si = next_si; + } + prev_si = next_si; + } else { + prev_si = next_si; + } + } + + // Run the DFA once more on the special EOF senitnel value. + prev_si = match self.next_state(qcur, qnext, prev_si, Byte::eof()) { + None => return Result::Quit, + Some(STATE_DEAD) => return result.set_non_match(0), + Some(si) => si, + }; + debug_assert!(prev_si != STATE_UNKNOWN); + if prev_si & STATE_MATCH > 0 { + prev_si &= !STATE_MATCH; + self.last_match_si = prev_si; + result = Result::Match(0); + } + result + } + + /// next_si transitions to the next state, where the transition input + /// corresponds to text[i]. + /// + /// This elides bounds checks, and is therefore unsafe. + #[inline(always)] + unsafe fn next_si(&self, si: StatePtr, text: &[u8], i: usize) -> StatePtr { + // What is the argument for safety here? + // We have three unchecked accesses that could possibly violate safety: + // + // 1. The given byte of input (`text[i]`). + // 2. The class of the byte of input (`classes[text[i]]`). + // 3. The transition for the class (`trans[si + cls]`). + // + // (1) is only safe when calling next_si is guarded by + // `i < text.len()`. + // + // (2) is the easiest case to guarantee since `text[i]` is always a + // `u8` and `self.prog.byte_classes` always has length `u8::MAX`. + // (See `ByteClassSet.byte_classes` in `compile.rs`.) + // + // (3) is only safe if (1)+(2) are safe. Namely, the transitions + // of every state are defined to have length equal to the number of + // byte classes in the program. Therefore, a valid class leads to a + // valid transition. (All possible transitions are valid lookups, even + // if it points to a state that hasn't been computed yet.) (3) also + // relies on `si` being correct, but StatePtrs should only ever be + // retrieved from the transition table, which ensures they are correct. + debug_assert!(i < text.len()); + let b = *text.get_unchecked(i); + debug_assert!((b as usize) < self.prog.byte_classes.len()); + let cls = *self.prog.byte_classes.get_unchecked(b as usize); + self.cache.trans.next_unchecked(si, cls as usize) + } + + /// Computes the next state given the current state and the current input + /// byte (which may be EOF). + /// + /// If STATE_DEAD is returned, then there is no valid state transition. + /// This implies that no permutation of future input can lead to a match + /// state. + /// + /// STATE_UNKNOWN can never be returned. + fn exec_byte( + &mut self, + qcur: &mut SparseSet, + qnext: &mut SparseSet, + mut si: StatePtr, + b: Byte, + ) -> Option<StatePtr> { + use prog::Inst::*; + + // Initialize a queue with the current DFA state's NFA states. + qcur.clear(); + for ip in self.state(si).inst_ptrs() { + qcur.insert(ip); + } + + // Before inspecting the current byte, we may need to also inspect + // whether the position immediately preceding the current byte + // satisfies the empty assertions found in the current state. + // + // We only need to do this step if there are any empty assertions in + // the current state. + let is_word_last = self.state(si).flags().is_word(); + let is_word = b.is_ascii_word(); + if self.state(si).flags().has_empty() { + // Compute the flags immediately preceding the current byte. + // This means we only care about the "end" or "end line" flags. + // (The "start" flags are computed immediately proceding the + // current byte and is handled below.) + let mut flags = EmptyFlags::default(); + if b.is_eof() { + flags.end = true; + flags.end_line = true; + } else if b.as_byte().map_or(false, |b| b == b'\n') { + flags.end_line = true; + } + if is_word_last == is_word { + flags.not_word_boundary = true; + } else { + flags.word_boundary = true; + } + // Now follow epsilon transitions from every NFA state, but make + // sure we only follow transitions that satisfy our flags. + qnext.clear(); + for &ip in &*qcur { + self.follow_epsilons(usize_to_u32(ip), qnext, flags); + } + mem::swap(qcur, qnext); + } + + // Now we set flags for immediately after the current byte. Since start + // states are processed separately, and are the only states that can + // have the StartText flag set, we therefore only need to worry about + // the StartLine flag here. + // + // We do also keep track of whether this DFA state contains a NFA state + // that is a matching state. This is precisely how we delay the DFA + // matching by one byte in order to process the special EOF sentinel + // byte. Namely, if this DFA state containing a matching NFA state, + // then it is the *next* DFA state that is marked as a match. + let mut empty_flags = EmptyFlags::default(); + let mut state_flags = StateFlags::default(); + empty_flags.start_line = b.as_byte().map_or(false, |b| b == b'\n'); + if b.is_ascii_word() { + state_flags.set_word(); + } + // Now follow all epsilon transitions again, but only after consuming + // the current byte. + qnext.clear(); + for &ip in &*qcur { + match self.prog[ip as usize] { + // These states never happen in a byte-based program. + Char(_) | Ranges(_) => unreachable!(), + // These states are handled when following epsilon transitions. + Save(_) | Split(_) | EmptyLook(_) => {} + Match(_) => { + state_flags.set_match(); + if !self.continue_past_first_match() { + break; + } else if self.prog.matches.len() > 1 + && !qnext.contains(ip as usize) { + // If we are continuing on to find other matches, + // then keep a record of the match states we've seen. + qnext.insert(ip); + } + } + Bytes(ref inst) => { + if b.as_byte().map_or(false, |b| inst.matches(b)) { + self.follow_epsilons( + inst.goto as InstPtr, qnext, empty_flags); + } + } + } + } + + let cache = + if b.is_eof() && self.prog.matches.len() > 1 { + // If we're processing the last byte of the input and we're + // matching a regex set, then make the next state contain the + // previous states transitions. We do this so that the main + // matching loop can extract all of the match instructions. + mem::swap(qcur, qnext); + // And don't cache this state because it's totally bunk. + false + } else { + true + }; + + // We've now built up the set of NFA states that ought to comprise the + // next DFA state, so try to find it in the cache, and if it doesn't + // exist, cache it. + // + // N.B. We pass `&mut si` here because the cache may clear itself if + // it has gotten too full. When that happens, the location of the + // current state may change. + let mut next = match self.cached_state( + qnext, + state_flags, + Some(&mut si), + ) { + None => return None, + Some(next) => next, + }; + if (self.start & !STATE_START) == next { + // Start states can never be match states since all matches are + // delayed by one byte. + debug_assert!(!self.state(next).flags().is_match()); + next = self.start_ptr(next); + } + if next <= STATE_MAX && self.state(next).flags().is_match() { + next |= STATE_MATCH; + } + debug_assert!(next != STATE_UNKNOWN); + // And now store our state in the current state's next list. + if cache { + let cls = self.byte_class(b); + self.cache.trans.set_next(si, cls, next); + } + Some(next) + } + + /// Follows the epsilon transitions starting at (and including) `ip`. The + /// resulting states are inserted into the ordered set `q`. + /// + /// Conditional epsilon transitions (i.e., empty width assertions) are only + /// followed if they are satisfied by the given flags, which should + /// represent the flags set at the current location in the input. + /// + /// If the current location corresponds to the empty string, then only the + /// end line and/or end text flags may be set. If the current location + /// corresponds to a real byte in the input, then only the start line + /// and/or start text flags may be set. + /// + /// As an exception to the above, when finding the initial state, any of + /// the above flags may be set: + /// + /// If matching starts at the beginning of the input, then start text and + /// start line should be set. If the input is empty, then end text and end + /// line should also be set. + /// + /// If matching starts after the beginning of the input, then only start + /// line should be set if the preceding byte is `\n`. End line should never + /// be set in this case. (Even if the proceding byte is a `\n`, it will + /// be handled in a subsequent DFA state.) + fn follow_epsilons( + &mut self, + ip: InstPtr, + q: &mut SparseSet, + flags: EmptyFlags, + ) { + use prog::Inst::*; + use prog::EmptyLook::*; + + // We need to traverse the NFA to follow epsilon transitions, so avoid + // recursion with an explicit stack. + self.cache.stack.push(ip); + while let Some(mut ip) = self.cache.stack.pop() { + // Try to munch through as many states as possible without + // pushes/pops to the stack. + loop { + // Don't visit states we've already added. + if q.contains(ip as usize) { + break; + } + q.insert(ip as usize); + match self.prog[ip as usize] { + Char(_) | Ranges(_) => unreachable!(), + Match(_) | Bytes(_) => { + break; + } + EmptyLook(ref inst) => { + // Only follow empty assertion states if our flags + // satisfy the assertion. + match inst.look { + StartLine if flags.start_line => { + ip = inst.goto as InstPtr; + } + EndLine if flags.end_line => { + ip = inst.goto as InstPtr; + } + StartText if flags.start => { + ip = inst.goto as InstPtr; + } + EndText if flags.end => { + ip = inst.goto as InstPtr; + } + WordBoundaryAscii if flags.word_boundary => { + ip = inst.goto as InstPtr; + } + NotWordBoundaryAscii if flags.not_word_boundary => { + ip = inst.goto as InstPtr; + } + WordBoundary if flags.word_boundary => { + ip = inst.goto as InstPtr; + } + NotWordBoundary if flags.not_word_boundary => { + ip = inst.goto as InstPtr; + } + StartLine | EndLine | StartText | EndText + | WordBoundaryAscii | NotWordBoundaryAscii + | WordBoundary | NotWordBoundary => { + break; + } + } + } + Save(ref inst) => { + ip = inst.goto as InstPtr; + } + Split(ref inst) => { + self.cache.stack.push(inst.goto2 as InstPtr); + ip = inst.goto1 as InstPtr; + } + } + } + } + } + + /// Find a previously computed state matching the given set of instructions + /// and is_match bool. + /// + /// The given set of instructions should represent a single state in the + /// NFA along with all states reachable without consuming any input. + /// + /// The is_match bool should be true if and only if the preceding DFA state + /// contains an NFA matching state. The cached state produced here will + /// then signify a match. (This enables us to delay a match by one byte, + /// in order to account for the EOF sentinel byte.) + /// + /// If the cache is full, then it is wiped before caching a new state. + /// + /// The current state should be specified if it exists, since it will need + /// to be preserved if the cache clears itself. (Start states are + /// always saved, so they should not be passed here.) It takes a mutable + /// pointer to the index because if the cache is cleared, the state's + /// location may change. + fn cached_state( + &mut self, + q: &SparseSet, + mut state_flags: StateFlags, + current_state: Option<&mut StatePtr>, + ) -> Option<StatePtr> { + // If we couldn't come up with a non-empty key to represent this state, + // then it is dead and can never lead to a match. + // + // Note that inst_flags represent the set of empty width assertions + // in q. We use this as an optimization in exec_byte to determine when + // we should follow epsilon transitions at the empty string preceding + // the current byte. + let key = match self.cached_state_key(q, &mut state_flags) { + None => return Some(STATE_DEAD), + Some(v) => v, + }; + // In the cache? Cool. Done. + if let Some(si) = self + .cache + .compiled + .get_ptr(&key) + { + return Some(si); + } + // If the cache has gotten too big, wipe it. + if self.approximate_size() > self.prog.dfa_size_limit + && !self.clear_cache_and_save(current_state) + { + // Ooops. DFA is giving up. + return None; + } + // Allocate room for our state and add it. + self.add_state(key) + } + + /// Produces a key suitable for describing a state in the DFA cache. + /// + /// The key invariant here is that equivalent keys are produced for any two + /// sets of ordered NFA states (and toggling of whether the previous NFA + /// states contain a match state) that do not discriminate a match for any + /// input. + /// + /// Specifically, q should be an ordered set of NFA states and is_match + /// should be true if and only if the previous NFA states contained a match + /// state. + fn cached_state_key( + &mut self, + q: &SparseSet, + state_flags: &mut StateFlags, + ) -> Option<State> { + use prog::Inst::*; + + // We need to build up enough information to recognize pre-built states + // in the DFA. Generally speaking, this includes every instruction + // except for those which are purely epsilon transitions, e.g., the + // Save and Split instructions. + // + // Empty width assertions are also epsilon transitions, but since they + // are conditional, we need to make them part of a state's key in the + // cache. + + let mut insts = mem::replace( + &mut self.cache.insts_scratch_space, + vec![], + ); + insts.clear(); + // Reserve 1 byte for flags. + insts.push(0); + + let mut prev = 0; + for &ip in q { + let ip = usize_to_u32(ip); + match self.prog[ip as usize] { + Char(_) | Ranges(_) => unreachable!(), + Save(_) | Split(_) => {} + Bytes(_) => push_inst_ptr(&mut insts, &mut prev, ip), + EmptyLook(_) => { + state_flags.set_empty(); + push_inst_ptr(&mut insts, &mut prev, ip) + } + Match(_) => { + push_inst_ptr(&mut insts, &mut prev, ip); + if !self.continue_past_first_match() { + break; + } + } + } + } + // If we couldn't transition to any other instructions and we didn't + // see a match when expanding NFA states previously, then this is a + // dead state and no amount of additional input can transition out + // of this state. + let opt_state = + if insts.len() == 1 && !state_flags.is_match() { + None + } else { + let StateFlags(f) = *state_flags; + insts[0] = f; + Some(State { data: Arc::from(&*insts) }) + }; + self.cache.insts_scratch_space = insts; + opt_state + } + + /// Clears the cache, but saves and restores current_state if it is not + /// none. + /// + /// The current state must be provided here in case its location in the + /// cache changes. + /// + /// This returns false if the cache is not cleared and the DFA should + /// give up. + fn clear_cache_and_save( + &mut self, + current_state: Option<&mut StatePtr>, + ) -> bool { + if self.cache.compiled.is_empty() { + // Nothing to clear... + return true; + } + match current_state { + None => self.clear_cache(), + Some(si) => { + let cur = self.state(*si).clone(); + if !self.clear_cache() { + return false; + } + // The unwrap is OK because we just cleared the cache and + // therefore know that the next state pointer won't exceed + // STATE_MAX. + *si = self.restore_state(cur).unwrap(); + true + } + } + } + + /// Wipes the state cache, but saves and restores the current start state. + /// + /// This returns false if the cache is not cleared and the DFA should + /// give up. + fn clear_cache(&mut self) -> bool { + // Bail out of the DFA if we're moving too "slowly." + // A heuristic from RE2: assume the DFA is too slow if it is processing + // 10 or fewer bytes per state. + // Additionally, we permit the cache to be flushed a few times before + // caling it quits. + let nstates = self.cache.compiled.len(); + if self.cache.flush_count >= 3 + && self.at >= self.last_cache_flush + && (self.at - self.last_cache_flush) <= 10 * nstates { + return false; + } + // Update statistics tracking cache flushes. + self.last_cache_flush = self.at; + self.cache.flush_count += 1; + + // OK, actually flush the cache. + let start = self.state(self.start & !STATE_START).clone(); + let last_match = if self.last_match_si <= STATE_MAX { + Some(self.state(self.last_match_si).clone()) + } else { + None + }; + self.cache.reset_size(); + self.cache.trans.clear(); + self.cache.compiled.clear(); + for s in &mut self.cache.start_states { + *s = STATE_UNKNOWN; + } + // The unwraps are OK because we just cleared the cache and therefore + // know that the next state pointer won't exceed STATE_MAX. + let start_ptr = self.restore_state(start).unwrap(); + self.start = self.start_ptr(start_ptr); + if let Some(last_match) = last_match { + self.last_match_si = self.restore_state(last_match).unwrap(); + } + true + } + + /// Restores the given state back into the cache, and returns a pointer + /// to it. + fn restore_state(&mut self, state: State) -> Option<StatePtr> { + // If we've already stored this state, just return a pointer to it. + // None will be the wiser. + if let Some(si) = self.cache.compiled.get_ptr(&state) { + return Some(si); + } + self.add_state(state) + } + + /// Returns the next state given the current state si and current byte + /// b. {qcur,qnext} are used as scratch space for storing ordered NFA + /// states. + /// + /// This tries to fetch the next state from the cache, but if that fails, + /// it computes the next state, caches it and returns a pointer to it. + /// + /// The pointer can be to a real state, or it can be STATE_DEAD. + /// STATE_UNKNOWN cannot be returned. + /// + /// None is returned if a new state could not be allocated (i.e., the DFA + /// ran out of space and thinks it's running too slowly). + fn next_state( + &mut self, + qcur: &mut SparseSet, + qnext: &mut SparseSet, + si: StatePtr, + b: Byte, + ) -> Option<StatePtr> { + if si == STATE_DEAD { + return Some(STATE_DEAD); + } + match self.cache.trans.next(si, self.byte_class(b)) { + STATE_UNKNOWN => self.exec_byte(qcur, qnext, si, b), + STATE_QUIT => None, + STATE_DEAD => Some(STATE_DEAD), + nsi => Some(nsi), + } + } + + /// Computes and returns the start state, where searching begins at + /// position `at` in `text`. If the state has already been computed, + /// then it is pulled from the cache. If the state hasn't been cached, + /// then it is computed, cached and a pointer to it is returned. + /// + /// This may return STATE_DEAD but never STATE_UNKNOWN. + #[inline(always)] // reduces constant overhead + fn start_state( + &mut self, + q: &mut SparseSet, + empty_flags: EmptyFlags, + state_flags: StateFlags, + ) -> Option<StatePtr> { + // Compute an index into our cache of start states based on the set + // of empty/state flags set at the current position in the input. We + // don't use every flag since not all flags matter. For example, since + // matches are delayed by one byte, start states can never be match + // states. + let flagi = { + (((empty_flags.start as u8) << 0) | + ((empty_flags.end as u8) << 1) | + ((empty_flags.start_line as u8) << 2) | + ((empty_flags.end_line as u8) << 3) | + ((empty_flags.word_boundary as u8) << 4) | + ((empty_flags.not_word_boundary as u8) << 5) | + ((state_flags.is_word() as u8) << 6)) + as usize + }; + match self.cache.start_states[flagi] { + STATE_UNKNOWN => {} + STATE_DEAD => return Some(STATE_DEAD), + si => return Some(si), + } + q.clear(); + let start = usize_to_u32(self.prog.start); + self.follow_epsilons(start, q, empty_flags); + // Start states can never be match states because we delay every match + // by one byte. Given an empty string and an empty match, the match + // won't actually occur until the DFA processes the special EOF + // sentinel byte. + let sp = match self.cached_state(q, state_flags, None) { + None => return None, + Some(sp) => self.start_ptr(sp), + }; + self.cache.start_states[flagi] = sp; + Some(sp) + } + + /// Computes the set of starting flags for the given position in text. + /// + /// This should only be used when executing the DFA forwards over the + /// input. + fn start_flags(&self, text: &[u8], at: usize) -> (EmptyFlags, StateFlags) { + let mut empty_flags = EmptyFlags::default(); + let mut state_flags = StateFlags::default(); + empty_flags.start = at == 0; + empty_flags.end = text.is_empty(); + empty_flags.start_line = at == 0 || text[at - 1] == b'\n'; + empty_flags.end_line = text.is_empty(); + + let is_word_last = at > 0 && Byte::byte(text[at - 1]).is_ascii_word(); + let is_word = at < text.len() && Byte::byte(text[at]).is_ascii_word(); + if is_word_last { + state_flags.set_word(); + } + if is_word == is_word_last { + empty_flags.not_word_boundary = true; + } else { + empty_flags.word_boundary = true; + } + (empty_flags, state_flags) + } + + /// Computes the set of starting flags for the given position in text. + /// + /// This should only be used when executing the DFA in reverse over the + /// input. + fn start_flags_reverse( + &self, + text: &[u8], + at: usize, + ) -> (EmptyFlags, StateFlags) { + let mut empty_flags = EmptyFlags::default(); + let mut state_flags = StateFlags::default(); + empty_flags.start = at == text.len(); + empty_flags.end = text.is_empty(); + empty_flags.start_line = at == text.len() || text[at] == b'\n'; + empty_flags.end_line = text.is_empty(); + + let is_word_last = + at < text.len() && Byte::byte(text[at]).is_ascii_word(); + let is_word = at > 0 && Byte::byte(text[at - 1]).is_ascii_word(); + if is_word_last { + state_flags.set_word(); + } + if is_word == is_word_last { + empty_flags.not_word_boundary = true; + } else { + empty_flags.word_boundary = true; + } + (empty_flags, state_flags) + } + + /// Returns a reference to a State given a pointer to it. + fn state(&self, si: StatePtr) -> &State { + self.cache.compiled.get_state(si).unwrap() + } + + /// Adds the given state to the DFA. + /// + /// This allocates room for transitions out of this state in + /// self.cache.trans. The transitions can be set with the returned + /// StatePtr. + /// + /// If None is returned, then the state limit was reached and the DFA + /// should quit. + fn add_state(&mut self, state: State) -> Option<StatePtr> { + // This will fail if the next state pointer exceeds STATE_PTR. In + // practice, the cache limit will prevent us from ever getting here, + // but maybe callers will set the cache size to something ridiculous... + let si = match self.cache.trans.add() { + None => return None, + Some(si) => si, + }; + // If the program has a Unicode word boundary, then set any transitions + // for non-ASCII bytes to STATE_QUIT. If the DFA stumbles over such a + // transition, then it will quit and an alternative matching engine + // will take over. + if self.prog.has_unicode_word_boundary { + for b in 128..256 { + let cls = self.byte_class(Byte::byte(b as u8)); + self.cache.trans.set_next(si, cls, STATE_QUIT); + } + } + // Finally, put our actual state on to our heap of states and index it + // so we can find it later. + self.cache.size += + self.cache.trans.state_heap_size() + + state.data.len() + + (2 * mem::size_of::<State>()) + + mem::size_of::<StatePtr>(); + self.cache.compiled.insert(state, si); + // Transition table and set of states and map should all be in sync. + debug_assert!(self.cache.compiled.len() + == self.cache.trans.num_states()); + Some(si) + } + + /// Quickly finds the next occurrence of any literal prefixes in the regex. + /// If there are no literal prefixes, then the current position is + /// returned. If there are literal prefixes and one could not be found, + /// then None is returned. + /// + /// This should only be called when the DFA is in a start state. + fn prefix_at(&self, text: &[u8], at: usize) -> Option<usize> { + self.prog.prefixes.find(&text[at..]).map(|(s, _)| at + s) + } + + /// Returns the number of byte classes required to discriminate transitions + /// in each state. + /// + /// invariant: num_byte_classes() == len(State.next) + fn num_byte_classes(&self) -> usize { + // We add 1 to account for the special EOF byte. + (self.prog.byte_classes[255] as usize + 1) + 1 + } + + /// Given an input byte or the special EOF sentinel, return its + /// corresponding byte class. + #[inline(always)] + fn byte_class(&self, b: Byte) -> usize { + match b.as_byte() { + None => self.num_byte_classes() - 1, + Some(b) => self.u8_class(b), + } + } + + /// Like byte_class, but explicitly for u8s. + #[inline(always)] + fn u8_class(&self, b: u8) -> usize { + self.prog.byte_classes[b as usize] as usize + } + + /// Returns true if the DFA should continue searching past the first match. + /// + /// Leftmost first semantics in the DFA are preserved by not following NFA + /// transitions after the first match is seen. + /// + /// On occasion, we want to avoid leftmost first semantics to find either + /// the longest match (for reverse search) or all possible matches (for + /// regex sets). + fn continue_past_first_match(&self) -> bool { + self.prog.is_reverse || self.prog.matches.len() > 1 + } + + /// Returns true if there is a prefix we can quickly search for. + fn has_prefix(&self) -> bool { + !self.prog.is_reverse + && !self.prog.prefixes.is_empty() + && !self.prog.is_anchored_start + } + + /// Sets the STATE_START bit in the given state pointer if and only if + /// we have a prefix to scan for. + /// + /// If there's no prefix, then it's a waste to treat the start state + /// specially. + fn start_ptr(&self, si: StatePtr) -> StatePtr { + if self.has_prefix() { + si | STATE_START + } else { + si + } + } + + /// Approximate size returns the approximate heap space currently used by + /// the DFA. It is used to determine whether the DFA's state cache needs to + /// be wiped. Namely, it is possible that for certain regexes on certain + /// inputs, a new state could be created for every byte of input. (This is + /// bad for memory use, so we bound it with a cache.) + fn approximate_size(&self) -> usize { + self.cache.size + self.prog.approximate_size() + } +} + +/// An abstraction for representing a map of states. The map supports two +/// different ways of state lookup. One is fast constant time access via a +/// state pointer. The other is a hashmap lookup based on the DFA's +/// constituent NFA states. +/// +/// A DFA state internally uses an Arc such that we only need to store the +/// set of NFA states on the heap once, even though we support looking up +/// states by two different means. A more natural way to express this might +/// use raw pointers, but an Arc is safe and effectively achieves the same +/// thing. +#[derive(Debug)] +struct StateMap { + /// The keys are not actually static but rely on always pointing to a + /// buffer in `states` which will never be moved except when clearing + /// the map or on drop, in which case the keys of this map will be + /// removed before + map: HashMap<State, StatePtr>, + /// Our set of states. Note that `StatePtr / num_byte_classes` indexes + /// this Vec rather than just a `StatePtr`. + states: Vec<State>, + /// The number of byte classes in the DFA. Used to index `states`. + num_byte_classes: usize, +} + +impl StateMap { + fn new(num_byte_classes: usize) -> StateMap { + StateMap { + map: HashMap::new(), + states: vec![], + num_byte_classes: num_byte_classes, + } + } + + fn len(&self) -> usize { + self.states.len() + } + + fn is_empty(&self) -> bool { + self.states.is_empty() + } + + fn get_ptr(&self, state: &State) -> Option<StatePtr> { + self.map.get(state).cloned() + } + + fn get_state(&self, si: StatePtr) -> Option<&State> { + self.states.get(si as usize / self.num_byte_classes) + } + + fn insert(&mut self, state: State, si: StatePtr) { + self.map.insert(state.clone(), si); + self.states.push(state); + } + + fn clear(&mut self) { + self.map.clear(); + self.states.clear(); + } +} + +impl Transitions { + /// Create a new transition table. + /// + /// The number of byte classes corresponds to the stride. Every state will + /// have `num_byte_classes` slots for transitions. + fn new(num_byte_classes: usize) -> Transitions { + Transitions { + table: vec![], + num_byte_classes: num_byte_classes, + } + } + + /// Returns the total number of states currently in this table. + fn num_states(&self) -> usize { + self.table.len() / self.num_byte_classes + } + + /// Allocates room for one additional state and returns a pointer to it. + /// + /// If there's no more room, None is returned. + fn add(&mut self) -> Option<StatePtr> { + let si = self.table.len(); + if si > STATE_MAX as usize { + return None; + } + self.table.extend(repeat(STATE_UNKNOWN).take(self.num_byte_classes)); + Some(usize_to_u32(si)) + } + + /// Clears the table of all states. + fn clear(&mut self) { + self.table.clear(); + } + + /// Sets the transition from (si, cls) to next. + fn set_next(&mut self, si: StatePtr, cls: usize, next: StatePtr) { + self.table[si as usize + cls] = next; + } + + /// Returns the transition corresponding to (si, cls). + fn next(&self, si: StatePtr, cls: usize) -> StatePtr { + self.table[si as usize + cls] + } + + /// The heap size, in bytes, of a single state in the transition table. + fn state_heap_size(&self) -> usize { + self.num_byte_classes * mem::size_of::<StatePtr>() + } + + /// Like `next`, but uses unchecked access and is therefore unsafe. + unsafe fn next_unchecked(&self, si: StatePtr, cls: usize) -> StatePtr { + debug_assert!((si as usize) < self.table.len()); + debug_assert!(cls < self.num_byte_classes); + *self.table.get_unchecked(si as usize + cls) + } +} + +impl StateFlags { + fn is_match(&self) -> bool { + self.0 & 0b0000000_1 > 0 + } + + fn set_match(&mut self) { + self.0 |= 0b0000000_1; + } + + fn is_word(&self) -> bool { + self.0 & 0b000000_1_0 > 0 + } + + fn set_word(&mut self) { + self.0 |= 0b000000_1_0; + } + + fn has_empty(&self) -> bool { + self.0 & 0b00000_1_00 > 0 + } + + fn set_empty(&mut self) { + self.0 |= 0b00000_1_00; + } +} + +impl Byte { + fn byte(b: u8) -> Self { Byte(b as u16) } + fn eof() -> Self { Byte(256) } + fn is_eof(&self) -> bool { self.0 == 256 } + + fn is_ascii_word(&self) -> bool { + let b = match self.as_byte() { + None => return false, + Some(b) => b, + }; + match b { + b'A'...b'Z' | b'a'...b'z' | b'0'...b'9' | b'_' => true, + _ => false, + } + } + + fn as_byte(&self) -> Option<u8> { + if self.is_eof() { + None + } else { + Some(self.0 as u8) + } + } +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let ips: Vec<usize> = self.inst_ptrs().collect(); + f.debug_struct("State") + .field("flags", &self.flags()) + .field("insts", &ips) + .finish() + } +} + +impl fmt::Debug for Transitions { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut fmtd = f.debug_map(); + for si in 0..self.num_states() { + let s = si * self.num_byte_classes; + let e = s + self.num_byte_classes; + fmtd.entry(&si.to_string(), &TransitionsRow(&self.table[s..e])); + } + fmtd.finish() + } +} + +struct TransitionsRow<'a>(&'a [StatePtr]); + +impl<'a> fmt::Debug for TransitionsRow<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut fmtd = f.debug_map(); + for (b, si) in self.0.iter().enumerate() { + match *si { + STATE_UNKNOWN => {} + STATE_DEAD => { + fmtd.entry(&vb(b as usize), &"DEAD"); + } + si => { + fmtd.entry(&vb(b as usize), &si.to_string()); + } + } + } + fmtd.finish() + } +} + +impl fmt::Debug for StateFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("StateFlags") + .field("is_match", &self.is_match()) + .field("is_word", &self.is_word()) + .field("has_empty", &self.has_empty()) + .finish() + } +} + +/// Helper function for formatting a byte as a nice-to-read escaped string. +fn vb(b: usize) -> String { + use std::ascii::escape_default; + + if b > ::std::u8::MAX as usize { + "EOF".to_owned() + } else { + let escaped = escape_default(b as u8).collect::<Vec<u8>>(); + String::from_utf8_lossy(&escaped).into_owned() + } +} + +fn usize_to_u32(n: usize) -> u32 { + if (n as u64) > (::std::u32::MAX as u64) { + panic!("BUG: {} is too big to fit into u32", n) + } + n as u32 +} + +#[allow(dead_code)] // useful for debugging +fn show_state_ptr(si: StatePtr) -> String { + let mut s = format!("{:?}", si & STATE_MAX); + if si == STATE_UNKNOWN { + s = format!("{} (unknown)", s); + } + if si == STATE_DEAD { + s = format!("{} (dead)", s); + } + if si == STATE_QUIT { + s = format!("{} (quit)", s); + } + if si & STATE_START > 0 { + s = format!("{} (start)", s); + } + if si & STATE_MATCH > 0 { + s = format!("{} (match)", s); + } + s +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +fn write_vari32(data: &mut Vec<u8>, n: i32) { + let mut un = (n as u32) << 1; + if n < 0 { + un = !un; + } + write_varu32(data, un) +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +fn read_vari32(data: &[u8]) -> (i32, usize) { + let (un, i) = read_varu32(data); + let mut n = (un >> 1) as i32; + if un & 1 != 0 { + n = !n; + } + (n, i) +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +fn write_varu32(data: &mut Vec<u8>, mut n: u32) { + while n >= 0b1000_0000 { + data.push((n as u8) | 0b1000_0000); + n >>= 7; + } + data.push(n as u8); +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +fn read_varu32(data: &[u8]) -> (u32, usize) { + let mut n: u32 = 0; + let mut shift: u32 = 0; + for (i, &b) in data.iter().enumerate() { + if b < 0b1000_0000 { + return (n | ((b as u32) << shift), i + 1); + } + n |= ((b as u32) & 0b0111_1111) << shift; + shift += 7; + } + (0, 0) +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use std::sync::Arc; + use quickcheck::{QuickCheck, StdGen, quickcheck}; + use super::{ + StateFlags, State, push_inst_ptr, + write_varu32, read_varu32, write_vari32, read_vari32, + }; + + #[test] + fn prop_state_encode_decode() { + fn p(ips: Vec<u32>, flags: u8) -> bool { + let mut data = vec![flags]; + let mut prev = 0; + for &ip in ips.iter() { + push_inst_ptr(&mut data, &mut prev, ip); + } + let state = State { data: Arc::from(&data[..]) }; + + let expected: Vec<usize> = + ips.into_iter().map(|ip| ip as usize).collect(); + let got: Vec<usize> = state.inst_ptrs().collect(); + expected == got && state.flags() == StateFlags(flags) + } + QuickCheck::new() + .gen(StdGen::new(self::rand::thread_rng(), 10_000)) + .quickcheck(p as fn(Vec<u32>, u8) -> bool); + } + + #[test] + fn prop_read_write_u32() { + fn p(n: u32) -> bool { + let mut buf = vec![]; + write_varu32(&mut buf, n); + let (got, nread) = read_varu32(&buf); + nread == buf.len() && got == n + } + quickcheck(p as fn(u32) -> bool); + } + + #[test] + fn prop_read_write_i32() { + fn p(n: i32) -> bool { + let mut buf = vec![]; + write_vari32(&mut buf, n); + let (got, nread) = read_vari32(&buf); + nread == buf.len() && got == n + } + quickcheck(p as fn(i32) -> bool); + } +} diff --git a/regex/src/error.rs b/regex/src/error.rs new file mode 100644 index 000000000..fff1969b4 --- /dev/null +++ b/regex/src/error.rs @@ -0,0 +1,84 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::iter::repeat; + +/// An error that occurred during parsing or compiling a regular expression. +#[derive(Clone, PartialEq)] +pub enum Error { + /// A syntax error. + Syntax(String), + /// The compiled program exceeded the set size limit. + /// The argument is the size limit imposed. + CompiledTooBig(usize), + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive, +} + +impl ::std::error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Syntax(ref err) => err, + Error::CompiledTooBig(_) => "compiled program too big", + Error::__Nonexhaustive => unreachable!(), + } + } + + fn cause(&self) -> Option<&::std::error::Error> { + None + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Syntax(ref err) => err.fmt(f), + Error::CompiledTooBig(limit) => { + write!(f, "Compiled regex exceeds size limit of {} bytes.", + limit) + } + Error::__Nonexhaustive => unreachable!(), + } + } +} + +// We implement our own Debug implementation so that we show nicer syntax +// errors when people use `Regex::new(...).unwrap()`. It's a little weird, +// but the `Syntax` variant is already storing a `String` anyway, so we might +// as well format it nicely. +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Syntax(ref err) => { + let hr: String = repeat('~').take(79).collect(); + writeln!(f, "Syntax(")?; + writeln!(f, "{}", hr)?; + writeln!(f, "{}", err)?; + writeln!(f, "{}", hr)?; + write!(f, ")")?; + Ok(()) + } + Error::CompiledTooBig(limit) => { + f.debug_tuple("CompiledTooBig") + .field(&limit) + .finish() + } + Error::__Nonexhaustive => { + f.debug_tuple("__Nonexhaustive").finish() + } + } + } +} diff --git a/regex/src/exec.rs b/regex/src/exec.rs new file mode 100644 index 000000000..e15d0b09f --- /dev/null +++ b/regex/src/exec.rs @@ -0,0 +1,1467 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::sync::Arc; + +use aho_corasick::{AhoCorasick, AhoCorasickBuilder, MatchKind}; +use thread_local::CachedThreadLocal; +use syntax::ParserBuilder; +use syntax::hir::Hir; +use syntax::hir::literal::Literals; + +use backtrack; +use compile::Compiler; +use dfa; +use error::Error; +use input::{ByteInput, CharInput}; +use literal::LiteralSearcher; +use pikevm; +use prog::Program; +use re_builder::RegexOptions; +use re_bytes; +use re_set; +use re_trait::{RegularExpression, Slot, Locations}; +use re_unicode; +use utf8::next_utf8; + +/// `Exec` manages the execution of a regular expression. +/// +/// In particular, this manages the various compiled forms of a single regular +/// expression and the choice of which matching engine to use to execute a +/// regular expression. +pub struct Exec { + /// All read only state. + ro: Arc<ExecReadOnly>, + /// Caches for the various matching engines. + cache: CachedThreadLocal<ProgramCache>, +} + +/// `ExecNoSync` is like `Exec`, except it embeds a reference to a cache. This +/// means it is no longer Sync, but we can now avoid the overhead of +/// synchronization to fetch the cache. +#[derive(Debug)] +pub struct ExecNoSync<'c> { + /// All read only state. + ro: &'c Arc<ExecReadOnly>, + /// Caches for the various matching engines. + cache: &'c ProgramCache, +} + +/// `ExecNoSyncStr` is like `ExecNoSync`, but matches on &str instead of &[u8]. +pub struct ExecNoSyncStr<'c>(ExecNoSync<'c>); + +/// `ExecReadOnly` comprises all read only state for a regex. Namely, all such +/// state is determined at compile time and never changes during search. +#[derive(Debug)] +struct ExecReadOnly { + /// The original regular expressions given by the caller to compile. + res: Vec<String>, + /// A compiled program that is used in the NFA simulation and backtracking. + /// It can be byte-based or Unicode codepoint based. + /// + /// N.B. It is not possibly to make this byte-based from the public API. + /// It is only used for testing byte based programs in the NFA simulations. + nfa: Program, + /// A compiled byte based program for DFA execution. This is only used + /// if a DFA can be executed. (Currently, only word boundary assertions are + /// not supported.) Note that this program contains an embedded `.*?` + /// preceding the first capture group, unless the regex is anchored at the + /// beginning. + dfa: Program, + /// The same as above, except the program is reversed (and there is no + /// preceding `.*?`). This is used by the DFA to find the starting location + /// of matches. + dfa_reverse: Program, + /// A set of suffix literals extracted from the regex. + /// + /// Prefix literals are stored on the `Program`, since they are used inside + /// the matching engines. + suffixes: LiteralSearcher, + /// An Aho-Corasick automaton with leftmost-first match semantics. + /// + /// This is only set when the entire regex is a simple unanchored + /// alternation of literals. We could probably use it more circumstances, + /// but this is already hacky enough in this architecture. + /// + /// N.B. We use u32 as a state ID representation under the assumption that + /// if we were to exhaust the ID space, we probably would have long + /// surpassed the compilation size limit. + ac: Option<AhoCorasick<u32>>, + /// match_type encodes as much upfront knowledge about how we're going to + /// execute a search as possible. + match_type: MatchType, +} + +/// Facilitates the construction of an executor by exposing various knobs +/// to control how a regex is executed and what kinds of resources it's +/// permitted to use. +pub struct ExecBuilder { + options: RegexOptions, + match_type: Option<MatchType>, + bytes: bool, + only_utf8: bool, +} + +/// Parsed represents a set of parsed regular expressions and their detected +/// literals. +struct Parsed { + exprs: Vec<Hir>, + prefixes: Literals, + suffixes: Literals, + bytes: bool, +} + +impl ExecBuilder { + /// Create a regex execution builder. + /// + /// This uses default settings for everything except the regex itself, + /// which must be provided. Further knobs can be set by calling methods, + /// and then finally, `build` to actually create the executor. + pub fn new(re: &str) -> Self { + Self::new_many(&[re]) + } + + /// Like new, but compiles the union of the given regular expressions. + /// + /// Note that when compiling 2 or more regular expressions, capture groups + /// are completely unsupported. (This means both `find` and `captures` + /// wont work.) + pub fn new_many<I, S>(res: I) -> Self + where S: AsRef<str>, I: IntoIterator<Item=S> { + let mut opts = RegexOptions::default(); + opts.pats = res.into_iter().map(|s| s.as_ref().to_owned()).collect(); + Self::new_options(opts) + } + + /// Create a regex execution builder. + pub fn new_options(opts: RegexOptions) -> Self { + ExecBuilder { + options: opts, + match_type: None, + bytes: false, + only_utf8: true, + } + } + + /// Set the matching engine to be automatically determined. + /// + /// This is the default state and will apply whatever optimizations are + /// possible, such as running a DFA. + /// + /// This overrides whatever was previously set via the `nfa` or + /// `bounded_backtracking` methods. + pub fn automatic(mut self) -> Self { + self.match_type = None; + self + } + + /// Sets the matching engine to use the NFA algorithm no matter what + /// optimizations are possible. + /// + /// This overrides whatever was previously set via the `automatic` or + /// `bounded_backtracking` methods. + pub fn nfa(mut self) -> Self { + self.match_type = Some(MatchType::Nfa(MatchNfaType::PikeVM)); + self + } + + /// Sets the matching engine to use a bounded backtracking engine no + /// matter what optimizations are possible. + /// + /// One must use this with care, since the bounded backtracking engine + /// uses memory proportion to `len(regex) * len(text)`. + /// + /// This overrides whatever was previously set via the `automatic` or + /// `nfa` methods. + pub fn bounded_backtracking(mut self) -> Self { + self.match_type = Some(MatchType::Nfa(MatchNfaType::Backtrack)); + self + } + + /// Compiles byte based programs for use with the NFA matching engines. + /// + /// By default, the NFA engines match on Unicode scalar values. They can + /// be made to use byte based programs instead. In general, the byte based + /// programs are slower because of a less efficient encoding of character + /// classes. + /// + /// Note that this does not impact DFA matching engines, which always + /// execute on bytes. + pub fn bytes(mut self, yes: bool) -> Self { + self.bytes = yes; + self + } + + /// When disabled, the program compiled may match arbitrary bytes. + /// + /// When enabled (the default), all compiled programs exclusively match + /// valid UTF-8 bytes. + pub fn only_utf8(mut self, yes: bool) -> Self { + self.only_utf8 = yes; + self + } + + /// Set the Unicode flag. + pub fn unicode(mut self, yes: bool) -> Self { + self.options.unicode = yes; + self + } + + /// Parse the current set of patterns into their AST and extract literals. + fn parse(&self) -> Result<Parsed, Error> { + let mut exprs = Vec::with_capacity(self.options.pats.len()); + let mut prefixes = Some(Literals::empty()); + let mut suffixes = Some(Literals::empty()); + let mut bytes = false; + let is_set = self.options.pats.len() > 1; + // If we're compiling a regex set and that set has any anchored + // expressions, then disable all literal optimizations. + for pat in &self.options.pats { + let mut parser = + ParserBuilder::new() + .octal(self.options.octal) + .case_insensitive(self.options.case_insensitive) + .multi_line(self.options.multi_line) + .dot_matches_new_line(self.options.dot_matches_new_line) + .swap_greed(self.options.swap_greed) + .ignore_whitespace(self.options.ignore_whitespace) + .unicode(self.options.unicode) + .allow_invalid_utf8(!self.only_utf8) + .nest_limit(self.options.nest_limit) + .build(); + let expr = parser + .parse(pat) + .map_err(|e| Error::Syntax(e.to_string()))?; + bytes = bytes || !expr.is_always_utf8(); + + if !expr.is_anchored_start() && expr.is_any_anchored_start() { + // Partial anchors unfortunately make it hard to use prefixes, + // so disable them. + prefixes = None; + } else if is_set && expr.is_anchored_start() { + // Regex sets with anchors do not go well with literal + // optimizations. + prefixes = None; + } + prefixes = prefixes.and_then(|mut prefixes| { + if !prefixes.union_prefixes(&expr) { + None + } else { + Some(prefixes) + } + }); + + if !expr.is_anchored_end() && expr.is_any_anchored_end() { + // Partial anchors unfortunately make it hard to use suffixes, + // so disable them. + suffixes = None; + } else if is_set && expr.is_anchored_end() { + // Regex sets with anchors do not go well with literal + // optimizations. + suffixes = None; + } + suffixes = suffixes.and_then(|mut suffixes| { + if !suffixes.union_suffixes(&expr) { + None + } else { + Some(suffixes) + } + }); + exprs.push(expr); + } + Ok(Parsed { + exprs: exprs, + prefixes: prefixes.unwrap_or_else(Literals::empty), + suffixes: suffixes.unwrap_or_else(Literals::empty), + bytes: bytes, + }) + } + + /// Build an executor that can run a regular expression. + pub fn build(self) -> Result<Exec, Error> { + // Special case when we have no patterns to compile. + // This can happen when compiling a regex set. + if self.options.pats.is_empty() { + let ro = Arc::new(ExecReadOnly { + res: vec![], + nfa: Program::new(), + dfa: Program::new(), + dfa_reverse: Program::new(), + suffixes: LiteralSearcher::empty(), + ac: None, + match_type: MatchType::Nothing, + }); + return Ok(Exec { ro: ro, cache: CachedThreadLocal::new() }); + } + let parsed = self.parse()?; + let mut nfa = + Compiler::new() + .size_limit(self.options.size_limit) + .bytes(self.bytes || parsed.bytes) + .only_utf8(self.only_utf8) + .compile(&parsed.exprs)?; + let mut dfa = + Compiler::new() + .size_limit(self.options.size_limit) + .dfa(true) + .only_utf8(self.only_utf8) + .compile(&parsed.exprs)?; + let mut dfa_reverse = + Compiler::new() + .size_limit(self.options.size_limit) + .dfa(true) + .only_utf8(self.only_utf8) + .reverse(true) + .compile(&parsed.exprs)?; + + let prefixes = parsed.prefixes.unambiguous_prefixes(); + let suffixes = parsed.suffixes.unambiguous_suffixes(); + nfa.prefixes = LiteralSearcher::prefixes(prefixes); + dfa.prefixes = nfa.prefixes.clone(); + dfa.dfa_size_limit = self.options.dfa_size_limit; + dfa_reverse.dfa_size_limit = self.options.dfa_size_limit; + + let mut ac = None; + if parsed.exprs.len() == 1 { + if let Some(lits) = alternation_literals(&parsed.exprs[0]) { + // If we have a small number of literals, then let Teddy + // handle things (see literal/mod.rs). + if lits.len() > 32 { + let fsm = AhoCorasickBuilder::new() + .match_kind(MatchKind::LeftmostFirst) + .auto_configure(&lits) + // We always want this to reduce size, regardless of + // what auto-configure does. + .byte_classes(true) + .build_with_size::<u32, _, _>(&lits) + .expect("AC automaton too big"); + ac = Some(fsm); + } + } + } + + let mut ro = ExecReadOnly { + res: self.options.pats, + nfa: nfa, + dfa: dfa, + dfa_reverse: dfa_reverse, + suffixes: LiteralSearcher::suffixes(suffixes), + ac: ac, + match_type: MatchType::Nothing, + }; + ro.match_type = ro.choose_match_type(self.match_type); + + let ro = Arc::new(ro); + Ok(Exec { ro: ro, cache: CachedThreadLocal::new() }) + } +} + +impl<'c> RegularExpression for ExecNoSyncStr<'c> { + type Text = str; + + fn slots_len(&self) -> usize { self.0.slots_len() } + + fn next_after_empty(&self, text: &str, i: usize) -> usize { + next_utf8(text.as_bytes(), i) + } + + #[inline(always)] // reduces constant overhead + fn shortest_match_at(&self, text: &str, start: usize) -> Option<usize> { + self.0.shortest_match_at(text.as_bytes(), start) + } + + #[inline(always)] // reduces constant overhead + fn is_match_at(&self, text: &str, start: usize) -> bool { + self.0.is_match_at(text.as_bytes(), start) + } + + #[inline(always)] // reduces constant overhead + fn find_at(&self, text: &str, start: usize) -> Option<(usize, usize)> { + self.0.find_at(text.as_bytes(), start) + } + + #[inline(always)] // reduces constant overhead + fn captures_read_at( + &self, + locs: &mut Locations, + text: &str, + start: usize, + ) -> Option<(usize, usize)> { + self.0.captures_read_at(locs, text.as_bytes(), start) + } +} + +impl<'c> RegularExpression for ExecNoSync<'c> { + type Text = [u8]; + + /// Returns the number of capture slots in the regular expression. (There + /// are two slots for every capture group, corresponding to possibly empty + /// start and end locations of the capture.) + fn slots_len(&self) -> usize { + self.ro.nfa.captures.len() * 2 + } + + fn next_after_empty(&self, _text: &[u8], i: usize) -> usize { + i + 1 + } + + /// Returns the end of a match location, possibly occurring before the + /// end location of the correct leftmost-first match. + #[inline(always)] // reduces constant overhead + fn shortest_match_at(&self, text: &[u8], start: usize) -> Option<usize> { + if !self.is_anchor_end_match(text) { + return None; + } + match self.ro.match_type { + MatchType::Literal(ty) => { + self.find_literals(ty, text, start).map(|(_, e)| e) + } + MatchType::Dfa | MatchType::DfaMany => { + match self.shortest_dfa(text, start) { + dfa::Result::Match(end) => Some(end), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => self.shortest_nfa(text, start), + } + } + MatchType::DfaAnchoredReverse => { + match dfa::Fsm::reverse( + &self.ro.dfa_reverse, + self.cache, + true, + &text[start..], + text.len(), + ) { + dfa::Result::Match(_) => Some(text.len()), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => self.shortest_nfa(text, start), + } + } + MatchType::DfaSuffix => { + match self.shortest_dfa_reverse_suffix(text, start) { + dfa::Result::Match(e) => Some(e), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => self.shortest_nfa(text, start), + } + } + MatchType::Nfa(ty) => self.shortest_nfa_type(ty, text, start), + MatchType::Nothing => None, + } + } + + /// Returns true if and only if the regex matches text. + /// + /// For single regular expressions, this is equivalent to calling + /// shortest_match(...).is_some(). + #[inline(always)] // reduces constant overhead + fn is_match_at(&self, text: &[u8], start: usize) -> bool { + if !self.is_anchor_end_match(text) { + return false; + } + // We need to do this dance because shortest_match relies on the NFA + // filling in captures[1], but a RegexSet has no captures. In other + // words, a RegexSet can't (currently) use shortest_match. ---AG + match self.ro.match_type { + MatchType::Literal(ty) => { + self.find_literals(ty, text, start).is_some() + } + MatchType::Dfa | MatchType::DfaMany => { + match self.shortest_dfa(text, start) { + dfa::Result::Match(_) => true, + dfa::Result::NoMatch(_) => false, + dfa::Result::Quit => self.match_nfa(text, start), + } + } + MatchType::DfaAnchoredReverse => { + match dfa::Fsm::reverse( + &self.ro.dfa_reverse, + self.cache, + true, + &text[start..], + text.len(), + ) { + dfa::Result::Match(_) => true, + dfa::Result::NoMatch(_) => false, + dfa::Result::Quit => self.match_nfa(text, start), + } + } + MatchType::DfaSuffix => { + match self.shortest_dfa_reverse_suffix(text, start) { + dfa::Result::Match(_) => true, + dfa::Result::NoMatch(_) => false, + dfa::Result::Quit => self.match_nfa(text, start), + } + } + MatchType::Nfa(ty) => self.match_nfa_type(ty, text, start), + MatchType::Nothing => false, + } + } + + /// Finds the start and end location of the leftmost-first match, starting + /// at the given location. + #[inline(always)] // reduces constant overhead + fn find_at(&self, text: &[u8], start: usize) -> Option<(usize, usize)> { + if !self.is_anchor_end_match(text) { + return None; + } + match self.ro.match_type { + MatchType::Literal(ty) => { + self.find_literals(ty, text, start) + } + MatchType::Dfa => { + match self.find_dfa_forward(text, start) { + dfa::Result::Match((s, e)) => Some((s, e)), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => { + self.find_nfa(MatchNfaType::Auto, text, start) + } + } + } + MatchType::DfaAnchoredReverse => { + match self.find_dfa_anchored_reverse(text, start) { + dfa::Result::Match((s, e)) => Some((s, e)), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => { + self.find_nfa(MatchNfaType::Auto, text, start) + } + } + } + MatchType::DfaSuffix => { + match self.find_dfa_reverse_suffix(text, start) { + dfa::Result::Match((s, e)) => Some((s, e)), + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => { + self.find_nfa(MatchNfaType::Auto, text, start) + } + } + } + MatchType::Nfa(ty) => self.find_nfa(ty, text, start), + MatchType::Nothing => None, + MatchType::DfaMany => { + unreachable!("BUG: RegexSet cannot be used with find") + } + } + } + + /// Finds the start and end location of the leftmost-first match and also + /// fills in all matching capture groups. + /// + /// The number of capture slots given should be equal to the total number + /// of capture slots in the compiled program. + /// + /// Note that the first two slots always correspond to the start and end + /// locations of the overall match. + fn captures_read_at( + &self, + locs: &mut Locations, + text: &[u8], + start: usize, + ) -> Option<(usize, usize)> { + let slots = locs.as_slots(); + for slot in slots.iter_mut() { + *slot = None; + } + // If the caller unnecessarily uses this, then we try to save them + // from themselves. + match slots.len() { + 0 => return self.find_at(text, start), + 2 => { + return self.find_at(text, start).map(|(s, e)| { + slots[0] = Some(s); + slots[1] = Some(e); + (s, e) + }); + } + _ => {} // fallthrough + } + if !self.is_anchor_end_match(text) { + return None; + } + match self.ro.match_type { + MatchType::Literal(ty) => { + self.find_literals(ty, text, start).and_then(|(s, e)| { + self.captures_nfa_type( + MatchNfaType::Auto, slots, text, s, e) + }) + } + MatchType::Dfa => { + if self.ro.nfa.is_anchored_start { + self.captures_nfa(slots, text, start) + } else { + match self.find_dfa_forward(text, start) { + dfa::Result::Match((s, e)) => { + self.captures_nfa_type( + MatchNfaType::Auto, slots, text, s, e) + } + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => { + self.captures_nfa(slots, text, start) + } + } + } + } + MatchType::DfaAnchoredReverse => { + match self.find_dfa_anchored_reverse(text, start) { + dfa::Result::Match((s, e)) => { + self.captures_nfa_type( + MatchNfaType::Auto, slots, text, s, e) + } + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => self.captures_nfa(slots, text, start), + } + } + MatchType::DfaSuffix => { + match self.find_dfa_reverse_suffix(text, start) { + dfa::Result::Match((s, e)) => { + self.captures_nfa_type( + MatchNfaType::Auto, slots, text, s, e) + } + dfa::Result::NoMatch(_) => None, + dfa::Result::Quit => self.captures_nfa(slots, text, start), + } + } + MatchType::Nfa(ty) => { + self.captures_nfa_type(ty, slots, text, start, text.len()) + } + MatchType::Nothing => None, + MatchType::DfaMany => { + unreachable!("BUG: RegexSet cannot be used with captures") + } + } + } +} + +impl<'c> ExecNoSync<'c> { + /// Finds the leftmost-first match using only literal search. + #[inline(always)] // reduces constant overhead + fn find_literals( + &self, + ty: MatchLiteralType, + text: &[u8], + start: usize, + ) -> Option<(usize, usize)> { + use self::MatchLiteralType::*; + match ty { + Unanchored => { + let lits = &self.ro.nfa.prefixes; + lits.find(&text[start..]) + .map(|(s, e)| (start + s, start + e)) + } + AnchoredStart => { + let lits = &self.ro.nfa.prefixes; + if !self.ro.nfa.is_anchored_start + || (self.ro.nfa.is_anchored_start && start == 0) { + lits.find_start(&text[start..]) + .map(|(s, e)| (start + s, start + e)) + } else { + None + } + } + AnchoredEnd => { + let lits = &self.ro.suffixes; + lits.find_end(&text[start..]) + .map(|(s, e)| (start + s, start + e)) + } + AhoCorasick => { + self.ro.ac.as_ref().unwrap() + .find(&text[start..]) + .map(|m| (start + m.start(), start + m.end())) + } + } + } + + /// Finds the leftmost-first match (start and end) using only the DFA. + /// + /// If the result returned indicates that the DFA quit, then another + /// matching engine should be used. + #[inline(always)] // reduces constant overhead + fn find_dfa_forward( + &self, + text: &[u8], + start: usize, + ) -> dfa::Result<(usize, usize)> { + use dfa::Result::*; + let end = match dfa::Fsm::forward( + &self.ro.dfa, + self.cache, + false, + text, + start, + ) { + NoMatch(i) => return NoMatch(i), + Quit => return Quit, + Match(end) if start == end => return Match((start, start)), + Match(end) => end, + }; + // Now run the DFA in reverse to find the start of the match. + match dfa::Fsm::reverse( + &self.ro.dfa_reverse, + self.cache, + false, + &text[start..], + end - start, + ) { + Match(s) => Match((start + s, end)), + NoMatch(i) => NoMatch(i), + Quit => Quit, + } + } + + /// Finds the leftmost-first match (start and end) using only the DFA, + /// but assumes the regex is anchored at the end and therefore starts at + /// the end of the regex and matches in reverse. + /// + /// If the result returned indicates that the DFA quit, then another + /// matching engine should be used. + #[inline(always)] // reduces constant overhead + fn find_dfa_anchored_reverse( + &self, + text: &[u8], + start: usize, + ) -> dfa::Result<(usize, usize)> { + use dfa::Result::*; + match dfa::Fsm::reverse( + &self.ro.dfa_reverse, + self.cache, + false, + &text[start..], + text.len() - start, + ) { + Match(s) => Match((start + s, text.len())), + NoMatch(i) => NoMatch(i), + Quit => Quit, + } + } + + /// Finds the end of the shortest match using only the DFA. + #[inline(always)] // reduces constant overhead + fn shortest_dfa(&self, text: &[u8], start: usize) -> dfa::Result<usize> { + dfa::Fsm::forward(&self.ro.dfa, self.cache, true, text, start) + } + + /// Finds the end of the shortest match using only the DFA by scanning for + /// suffix literals. + /// + #[inline(always)] // reduces constant overhead + fn shortest_dfa_reverse_suffix( + &self, + text: &[u8], + start: usize, + ) -> dfa::Result<usize> { + match self.exec_dfa_reverse_suffix(text, start) { + None => self.shortest_dfa(text, start), + Some(r) => r.map(|(_, end)| end), + } + } + + /// Finds the end of the shortest match using only the DFA by scanning for + /// suffix literals. It also reports the start of the match. + /// + /// Note that if None is returned, then the optimization gave up to avoid + /// worst case quadratic behavior. A forward scanning DFA should be tried + /// next. + /// + /// If a match is returned and the full leftmost-first match is desired, + /// then a forward scan starting from the beginning of the match must be + /// done. + /// + /// If the result returned indicates that the DFA quit, then another + /// matching engine should be used. + #[inline(always)] // reduces constant overhead + fn exec_dfa_reverse_suffix( + &self, + text: &[u8], + original_start: usize, + ) -> Option<dfa::Result<(usize, usize)>> { + use dfa::Result::*; + + let lcs = self.ro.suffixes.lcs(); + debug_assert!(lcs.len() >= 1); + let mut start = original_start; + let mut end = start; + let mut last_literal = start; + while end <= text.len() { + last_literal += match lcs.find(&text[last_literal..]) { + None => return Some(NoMatch(text.len())), + Some(i) => i, + }; + end = last_literal + lcs.len(); + match dfa::Fsm::reverse( + &self.ro.dfa_reverse, + self.cache, + false, + &text[start..end], + end - start, + ) { + Match(0) | NoMatch(0) => return None, + Match(i) => return Some(Match((start + i, end))), + NoMatch(i) => { + start += i; + last_literal += 1; + continue; + } + Quit => return Some(Quit), + }; + } + Some(NoMatch(text.len())) + } + + /// Finds the leftmost-first match (start and end) using only the DFA + /// by scanning for suffix literals. + /// + /// If the result returned indicates that the DFA quit, then another + /// matching engine should be used. + #[inline(always)] // reduces constant overhead + fn find_dfa_reverse_suffix( + &self, + text: &[u8], + start: usize, + ) -> dfa::Result<(usize, usize)> { + use dfa::Result::*; + + let match_start = match self.exec_dfa_reverse_suffix(text, start) { + None => return self.find_dfa_forward(text, start), + Some(Match((start, _))) => start, + Some(r) => return r, + }; + // At this point, we've found a match. The only way to quit now + // without a match is if the DFA gives up (seems unlikely). + // + // Now run the DFA forwards to find the proper end of the match. + // (The suffix literal match can only indicate the earliest + // possible end location, which may appear before the end of the + // leftmost-first match.) + match dfa::Fsm::forward( + &self.ro.dfa, + self.cache, + false, + text, + match_start, + ) { + NoMatch(_) => panic!("BUG: reverse match implies forward match"), + Quit => Quit, + Match(e) => Match((match_start, e)), + } + } + + /// Executes the NFA engine to return whether there is a match or not. + /// + /// Ideally, we could use shortest_nfa(...).is_some() and get the same + /// performance characteristics, but regex sets don't have captures, which + /// shortest_nfa depends on. + fn match_nfa( + &self, + text: &[u8], + start: usize, + ) -> bool { + self.match_nfa_type(MatchNfaType::Auto, text, start) + } + + /// Like match_nfa, but allows specification of the type of NFA engine. + fn match_nfa_type( + &self, + ty: MatchNfaType, + text: &[u8], + start: usize, + ) -> bool { + self.exec_nfa(ty, &mut [false], &mut [], true, text, start, text.len()) + } + + /// Finds the shortest match using an NFA. + fn shortest_nfa(&self, text: &[u8], start: usize) -> Option<usize> { + self.shortest_nfa_type(MatchNfaType::Auto, text, start) + } + + /// Like shortest_nfa, but allows specification of the type of NFA engine. + fn shortest_nfa_type( + &self, + ty: MatchNfaType, + text: &[u8], + start: usize, + ) -> Option<usize> { + let mut slots = [None, None]; + if self.exec_nfa( + ty, + &mut [false], + &mut slots, + true, + text, + start, + text.len() + ) { + slots[1] + } else { + None + } + } + + /// Like find, but executes an NFA engine. + fn find_nfa( + &self, + ty: MatchNfaType, + text: &[u8], + start: usize, + ) -> Option<(usize, usize)> { + let mut slots = [None, None]; + if self.exec_nfa( + ty, + &mut [false], + &mut slots, + false, + text, + start, + text.len() + ) { + match (slots[0], slots[1]) { + (Some(s), Some(e)) => Some((s, e)), + _ => None, + } + } else { + None + } + } + + /// Like find_nfa, but fills in captures. + /// + /// `slots` should have length equal to `2 * nfa.captures.len()`. + fn captures_nfa( + &self, + slots: &mut [Slot], + text: &[u8], + start: usize, + ) -> Option<(usize, usize)> { + self.captures_nfa_type( + MatchNfaType::Auto, slots, text, start, text.len()) + } + + /// Like captures_nfa, but allows specification of type of NFA engine. + fn captures_nfa_type( + &self, + ty: MatchNfaType, + slots: &mut [Slot], + text: &[u8], + start: usize, + end: usize, + ) -> Option<(usize, usize)> { + if self.exec_nfa(ty, &mut [false], slots, false, text, start, end) { + match (slots[0], slots[1]) { + (Some(s), Some(e)) => Some((s, e)), + _ => None, + } + } else { + None + } + } + + fn exec_nfa( + &self, + mut ty: MatchNfaType, + matches: &mut [bool], + slots: &mut [Slot], + quit_after_match: bool, + text: &[u8], + start: usize, + end: usize, + ) -> bool { + use self::MatchNfaType::*; + if let Auto = ty { + if backtrack::should_exec(self.ro.nfa.len(), text.len()) { + ty = Backtrack; + } else { + ty = PikeVM; + } + } + match ty { + Auto => unreachable!(), + Backtrack => self.exec_backtrack(matches, slots, text, start, end), + PikeVM => { + self.exec_pikevm( + matches, slots, quit_after_match, text, start, end) + } + } + } + + /// Always run the NFA algorithm. + fn exec_pikevm( + &self, + matches: &mut [bool], + slots: &mut [Slot], + quit_after_match: bool, + text: &[u8], + start: usize, + end: usize, + ) -> bool { + if self.ro.nfa.uses_bytes() { + pikevm::Fsm::exec( + &self.ro.nfa, + self.cache, + matches, + slots, + quit_after_match, + ByteInput::new(text, self.ro.nfa.only_utf8), + start, + end) + } else { + pikevm::Fsm::exec( + &self.ro.nfa, + self.cache, + matches, + slots, + quit_after_match, + CharInput::new(text), + start, + end) + } + } + + /// Always runs the NFA using bounded backtracking. + fn exec_backtrack( + &self, + matches: &mut [bool], + slots: &mut [Slot], + text: &[u8], + start: usize, + end: usize, + ) -> bool { + if self.ro.nfa.uses_bytes() { + backtrack::Bounded::exec( + &self.ro.nfa, + self.cache, + matches, + slots, + ByteInput::new(text, self.ro.nfa.only_utf8), + start, + end) + } else { + backtrack::Bounded::exec( + &self.ro.nfa, + self.cache, + matches, + slots, + CharInput::new(text), + start, + end) + } + } + + /// Finds which regular expressions match the given text. + /// + /// `matches` should have length equal to the number of regexes being + /// searched. + /// + /// This is only useful when one wants to know which regexes in a set + /// match some text. + pub fn many_matches_at( + &self, + matches: &mut [bool], + text: &[u8], + start: usize, + ) -> bool { + use self::MatchType::*; + if !self.is_anchor_end_match(text) { + return false; + } + match self.ro.match_type { + Literal(ty) => { + debug_assert_eq!(matches.len(), 1); + matches[0] = self.find_literals(ty, text, start).is_some(); + matches[0] + } + Dfa | DfaAnchoredReverse | DfaSuffix | DfaMany => { + match dfa::Fsm::forward_many( + &self.ro.dfa, + self.cache, + matches, + text, + start, + ) { + dfa::Result::Match(_) => true, + dfa::Result::NoMatch(_) => false, + dfa::Result::Quit => { + self.exec_nfa( + MatchNfaType::Auto, + matches, + &mut [], + false, + text, + start, + text.len()) + } + } + } + Nfa(ty) => { + self.exec_nfa( + ty, matches, &mut [], false, text, start, text.len()) + } + Nothing => false, + } + } + + #[inline(always)] // reduces constant overhead + fn is_anchor_end_match(&self, text: &[u8]) -> bool { + // Only do this check if the haystack is big (>1MB). + if text.len() > (1<<20) && self.ro.nfa.is_anchored_end { + let lcs = self.ro.suffixes.lcs(); + if lcs.len() >= 1 && !lcs.is_suffix(text) { + return false; + } + } + true + } + + pub fn capture_name_idx(&self) -> &Arc<HashMap<String, usize>> { + &self.ro.nfa.capture_name_idx + } +} + +impl<'c> ExecNoSyncStr<'c> { + pub fn capture_name_idx(&self) -> &Arc<HashMap<String, usize>> { + self.0.capture_name_idx() + } +} + +impl Exec { + /// Get a searcher that isn't Sync. + #[inline(always)] // reduces constant overhead + pub fn searcher(&self) -> ExecNoSync { + let create = || { + Box::new(RefCell::new(ProgramCacheInner::new(&self.ro))) + }; + ExecNoSync { + ro: &self.ro, // a clone is too expensive here! (and not needed) + cache: self.cache.get_or(create), + } + } + + /// Get a searcher that isn't Sync and can match on &str. + #[inline(always)] // reduces constant overhead + pub fn searcher_str(&self) -> ExecNoSyncStr { + ExecNoSyncStr(self.searcher()) + } + + /// Build a Regex from this executor. + pub fn into_regex(self) -> re_unicode::Regex { + re_unicode::Regex::from(self) + } + + /// Build a RegexSet from this executor. + pub fn into_regex_set(self) -> re_set::unicode::RegexSet { + re_set::unicode::RegexSet::from(self) + } + + /// Build a Regex from this executor that can match arbitrary bytes. + pub fn into_byte_regex(self) -> re_bytes::Regex { + re_bytes::Regex::from(self) + } + + /// Build a RegexSet from this executor that can match arbitrary bytes. + pub fn into_byte_regex_set(self) -> re_set::bytes::RegexSet { + re_set::bytes::RegexSet::from(self) + } + + /// The original regular expressions given by the caller that were + /// compiled. + pub fn regex_strings(&self) -> &[String] { + &self.ro.res + } + + /// Return a slice of capture names. + /// + /// Any capture that isn't named is None. + pub fn capture_names(&self) -> &[Option<String>] { + &self.ro.nfa.captures + } + + /// Return a reference to named groups mapping (from group name to + /// group position). + pub fn capture_name_idx(&self) -> &Arc<HashMap<String, usize>> { + &self.ro.nfa.capture_name_idx + } +} + +impl Clone for Exec { + fn clone(&self) -> Exec { + Exec { + ro: self.ro.clone(), + cache: CachedThreadLocal::new(), + } + } +} + +impl ExecReadOnly { + fn choose_match_type(&self, hint: Option<MatchType>) -> MatchType { + use self::MatchType::*; + if let Some(Nfa(_)) = hint { + return hint.unwrap(); + } + // If the NFA is empty, then we'll never match anything. + if self.nfa.insts.is_empty() { + return Nothing; + } + // If our set of prefixes is complete, then we can use it to find + // a match in lieu of a regex engine. This doesn't quite work well in + // the presence of multiple regexes, so only do it when there's one. + // + // TODO(burntsushi): Also, don't try to match literals if the regex is + // partially anchored. We could technically do it, but we'd need to + // create two sets of literals: all of them and then the subset that + // aren't anchored. We would then only search for all of them when at + // the beginning of the input and use the subset in all other cases. + if self.res.len() == 1 { + if self.ac.is_some() { + return Literal(MatchLiteralType::AhoCorasick); + } + if self.nfa.prefixes.complete() { + return if self.nfa.is_anchored_start { + Literal(MatchLiteralType::AnchoredStart) + } else { + Literal(MatchLiteralType::Unanchored) + }; + } + if self.suffixes.complete() { + return if self.nfa.is_anchored_end { + Literal(MatchLiteralType::AnchoredEnd) + } else { + // This case shouldn't happen. When the regex isn't + // anchored, then complete prefixes should imply complete + // suffixes. + Literal(MatchLiteralType::Unanchored) + }; + } + } + // If we can execute the DFA, then we totally should. + if dfa::can_exec(&self.dfa) { + // Regex sets require a slightly specialized path. + if self.res.len() >= 2 { + return DfaMany; + } + // If the regex is anchored at the end but not the start, then + // just match in reverse from the end of the haystack. + if !self.nfa.is_anchored_start && self.nfa.is_anchored_end { + return DfaAnchoredReverse; + } + // If there's a longish suffix literal, then it might be faster + // to look for that first. + if self.should_suffix_scan() { + return DfaSuffix; + } + // Fall back to your garden variety forward searching lazy DFA. + return Dfa; + } + // We're so totally hosed. + Nfa(MatchNfaType::Auto) + } + + /// Returns true if the program is amenable to suffix scanning. + /// + /// When this is true, as a heuristic, we assume it is OK to quickly scan + /// for suffix literals and then do a *reverse* DFA match from any matches + /// produced by the literal scan. (And then followed by a forward DFA + /// search, since the previously found suffix literal maybe not actually be + /// the end of a match.) + /// + /// This is a bit of a specialized optimization, but can result in pretty + /// big performance wins if 1) there are no prefix literals and 2) the + /// suffix literals are pretty rare in the text. (1) is obviously easy to + /// account for but (2) is harder. As a proxy, we assume that longer + /// strings are generally rarer, so we only enable this optimization when + /// we have a meaty suffix. + fn should_suffix_scan(&self) -> bool { + if self.suffixes.is_empty() { + return false; + } + let lcs_len = self.suffixes.lcs().char_len(); + lcs_len >= 3 && lcs_len > self.dfa.prefixes.lcp().char_len() + } +} + +#[derive(Clone, Copy, Debug)] +enum MatchType { + /// A single or multiple literal search. This is only used when the regex + /// can be decomposed into unambiguous literal search. + Literal(MatchLiteralType), + /// A normal DFA search. + Dfa, + /// A reverse DFA search starting from the end of a haystack. + DfaAnchoredReverse, + /// A reverse DFA search with suffix literal scanning. + DfaSuffix, + /// Use the DFA on two or more regular expressions. + DfaMany, + /// An NFA variant. + Nfa(MatchNfaType), + /// No match is ever possible, so don't ever try to search. + Nothing, +} + +#[derive(Clone, Copy, Debug)] +enum MatchLiteralType { + /// Match literals anywhere in text. + Unanchored, + /// Match literals only at the start of text. + AnchoredStart, + /// Match literals only at the end of text. + AnchoredEnd, + /// Use an Aho-Corasick automaton. This requires `ac` to be Some on + /// ExecReadOnly. + AhoCorasick, +} + +#[derive(Clone, Copy, Debug)] +enum MatchNfaType { + /// Choose between Backtrack and PikeVM. + Auto, + /// NFA bounded backtracking. + /// + /// (This is only set by tests, since it never makes sense to always want + /// backtracking.) + Backtrack, + /// The Pike VM. + /// + /// (This is only set by tests, since it never makes sense to always want + /// the Pike VM.) + PikeVM, +} + +/// `ProgramCache` maintains reusable allocations for each matching engine +/// available to a particular program. +pub type ProgramCache = RefCell<ProgramCacheInner>; + +#[derive(Debug)] +pub struct ProgramCacheInner { + pub pikevm: pikevm::Cache, + pub backtrack: backtrack::Cache, + pub dfa: dfa::Cache, + pub dfa_reverse: dfa::Cache, +} + +impl ProgramCacheInner { + fn new(ro: &ExecReadOnly) -> Self { + ProgramCacheInner { + pikevm: pikevm::Cache::new(&ro.nfa), + backtrack: backtrack::Cache::new(&ro.nfa), + dfa: dfa::Cache::new(&ro.dfa), + dfa_reverse: dfa::Cache::new(&ro.dfa_reverse), + } + } +} + +/// Alternation literals checks if the given HIR is a simple alternation of +/// literals, and if so, returns them. Otherwise, this returns None. +fn alternation_literals(expr: &Hir) -> Option<Vec<Vec<u8>>> { + use syntax::hir::{HirKind, Literal}; + + // This is pretty hacky, but basically, if `is_alternation_literal` is + // true, then we can make several assumptions about the structure of our + // HIR. This is what justifies the `unreachable!` statements below. + // + // This code should be refactored once we overhaul this crate's + // optimization pipeline, because this is a terribly inflexible way to go + // about things. + + if !expr.is_alternation_literal() { + return None; + } + let alts = match *expr.kind() { + HirKind::Alternation(ref alts) => alts, + _ => return None, // one literal isn't worth it + }; + + let extendlit = |lit: &Literal, dst: &mut Vec<u8>| { + match *lit { + Literal::Unicode(c) => { + let mut buf = [0; 4]; + dst.extend_from_slice(c.encode_utf8(&mut buf).as_bytes()); + } + Literal::Byte(b) => { + dst.push(b); + } + } + }; + + let mut lits = vec![]; + for alt in alts { + let mut lit = vec![]; + match *alt.kind() { + HirKind::Literal(ref x) => extendlit(x, &mut lit), + HirKind::Concat(ref exprs) => { + for e in exprs { + match *e.kind() { + HirKind::Literal(ref x) => extendlit(x, &mut lit), + _ => unreachable!("expected literal, got {:?}", e), + } + } + } + _ => unreachable!("expected literal or concat, got {:?}", alt), + } + lits.push(lit); + } + Some(lits) +} + +#[cfg(test)] +mod test { + #[test] + fn uppercut_s_backtracking_bytes_default_bytes_mismatch() { + use internal::ExecBuilder; + + let backtrack_bytes_re = ExecBuilder::new("^S") + .bounded_backtracking() + .only_utf8(false) + .build() + .map(|exec| exec.into_byte_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let default_bytes_re = ExecBuilder::new("^S") + .only_utf8(false) + .build() + .map(|exec| exec.into_byte_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let input = vec![83, 83]; + + let s1 = backtrack_bytes_re.split(&input); + let s2 = default_bytes_re.split(&input); + for (chunk1, chunk2) in s1.zip(s2) { + assert_eq!(chunk1, chunk2); + } + } + + #[test] + fn unicode_lit_star_backtracking_utf8bytes_default_utf8bytes_mismatch() { + use internal::ExecBuilder; + + let backtrack_bytes_re = ExecBuilder::new(r"^(?u:\*)") + .bounded_backtracking() + .bytes(true) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let default_bytes_re = ExecBuilder::new(r"^(?u:\*)") + .bytes(true) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let input = "**"; + + let s1 = backtrack_bytes_re.split(input); + let s2 = default_bytes_re.split(input); + for (chunk1, chunk2) in s1.zip(s2) { + assert_eq!(chunk1, chunk2); + } + } +} diff --git a/regex/src/expand.rs b/regex/src/expand.rs new file mode 100644 index 000000000..bc055a85a --- /dev/null +++ b/regex/src/expand.rs @@ -0,0 +1,215 @@ +use std::str; + +use memchr::memchr; + +use re_bytes; +use re_unicode; + +pub fn expand_str( + caps: &re_unicode::Captures, + mut replacement: &str, + dst: &mut String, +) { + while !replacement.is_empty() { + match memchr(b'$', replacement.as_bytes()) { + None => break, + Some(i) => { + dst.push_str(&replacement[..i]); + replacement = &replacement[i..]; + } + } + if replacement.as_bytes().get(1).map_or(false, |&b| b == b'$') { + dst.push_str("$"); + replacement = &replacement[2..]; + continue; + } + debug_assert!(!replacement.is_empty()); + let cap_ref = match find_cap_ref(replacement) { + Some(cap_ref) => cap_ref, + None => { + dst.push_str("$"); + replacement = &replacement[1..]; + continue; + } + }; + replacement = &replacement[cap_ref.end..]; + match cap_ref.cap { + Ref::Number(i) => { + dst.push_str( + caps.get(i).map(|m| m.as_str()).unwrap_or("")); + } + Ref::Named(name) => { + dst.push_str( + caps.name(name).map(|m| m.as_str()).unwrap_or("")); + } + } + } + dst.push_str(replacement); +} + +pub fn expand_bytes( + caps: &re_bytes::Captures, + mut replacement: &[u8], + dst: &mut Vec<u8>, +) { + while !replacement.is_empty() { + match memchr(b'$', replacement) { + None => break, + Some(i) => { + dst.extend(&replacement[..i]); + replacement = &replacement[i..]; + } + } + if replacement.get(1).map_or(false, |&b| b == b'$') { + dst.push(b'$'); + replacement = &replacement[2..]; + continue; + } + debug_assert!(!replacement.is_empty()); + let cap_ref = match find_cap_ref(replacement) { + Some(cap_ref) => cap_ref, + None => { + dst.push(b'$'); + replacement = &replacement[1..]; + continue; + } + }; + replacement = &replacement[cap_ref.end..]; + match cap_ref.cap { + Ref::Number(i) => { + dst.extend( + caps.get(i).map(|m| m.as_bytes()).unwrap_or(b"")); + } + Ref::Named(name) => { + dst.extend( + caps.name(name).map(|m| m.as_bytes()).unwrap_or(b"")); + } + } + } + dst.extend(replacement); +} + +/// `CaptureRef` represents a reference to a capture group inside some text. +/// The reference is either a capture group name or a number. +/// +/// It is also tagged with the position in the text immediately proceeding the +/// capture reference. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +struct CaptureRef<'a> { + cap: Ref<'a>, + end: usize, +} + +/// A reference to a capture group in some text. +/// +/// e.g., `$2`, `$foo`, `${foo}`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum Ref<'a> { + Named(&'a str), + Number(usize), +} + +impl<'a> From<&'a str> for Ref<'a> { + fn from(x: &'a str) -> Ref<'a> { + Ref::Named(x) + } +} + +impl From<usize> for Ref<'static> { + fn from(x: usize) -> Ref<'static> { + Ref::Number(x) + } +} + +/// Parses a possible reference to a capture group name in the given text, +/// starting at the beginning of `replacement`. +/// +/// If no such valid reference could be found, None is returned. +fn find_cap_ref<T: ?Sized + AsRef<[u8]>>( + replacement: &T, +) -> Option<CaptureRef> { + let mut i = 0; + let rep: &[u8] = replacement.as_ref(); + if rep.len() <= 1 || rep[0] != b'$' { + return None; + } + let mut brace = false; + i += 1; + if rep[i] == b'{' { + brace = true; + i += 1; + } + let mut cap_end = i; + while rep.get(cap_end).map_or(false, is_valid_cap_letter) { + cap_end += 1; + } + if cap_end == i { + return None; + } + // We just verified that the range 0..cap_end is valid ASCII, so it must + // therefore be valid UTF-8. If we really cared, we could avoid this UTF-8 + // check with either unsafe or by parsing the number straight from &[u8]. + let cap = str::from_utf8(&rep[i..cap_end]) + .expect("valid UTF-8 capture name"); + if brace { + if !rep.get(cap_end).map_or(false, |&b| b == b'}') { + return None; + } + cap_end += 1; + } + Some(CaptureRef { + cap: match cap.parse::<u32>() { + Ok(i) => Ref::Number(i as usize), + Err(_) => Ref::Named(cap), + }, + end: cap_end, + }) +} + +/// Returns true if and only if the given byte is allowed in a capture name. +fn is_valid_cap_letter(b: &u8) -> bool { + match *b { + b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z' | b'_' => true, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::{CaptureRef, find_cap_ref}; + + macro_rules! find { + ($name:ident, $text:expr) => { + #[test] + fn $name() { + assert_eq!(None, find_cap_ref($text)); + } + }; + ($name:ident, $text:expr, $capref:expr) => { + #[test] + fn $name() { + assert_eq!(Some($capref), find_cap_ref($text)); + } + }; + } + + macro_rules! c { + ($name_or_number:expr, $pos:expr) => { + CaptureRef { cap: $name_or_number.into(), end: $pos } + }; + } + + find!(find_cap_ref1, "$foo", c!("foo", 4)); + find!(find_cap_ref2, "${foo}", c!("foo", 6)); + find!(find_cap_ref3, "$0", c!(0, 2)); + find!(find_cap_ref4, "$5", c!(5, 2)); + find!(find_cap_ref5, "$10", c!(10, 3)); + find!(find_cap_ref6, "$42a", c!("42a", 4)); + find!(find_cap_ref7, "${42}a", c!(42, 5)); + find!(find_cap_ref8, "${42"); + find!(find_cap_ref9, "${42 "); + find!(find_cap_ref10, " $0 "); + find!(find_cap_ref11, "$"); + find!(find_cap_ref12, " "); + find!(find_cap_ref13, ""); +} diff --git a/regex/src/freqs.rs b/regex/src/freqs.rs new file mode 100644 index 000000000..92bafc199 --- /dev/null +++ b/regex/src/freqs.rs @@ -0,0 +1,271 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/frequencies.py", do not +// edit directly + +pub const BYTE_FREQUENCIES: [u8; 256] = [ + 55, // '\x00' + 52, // '\x01' + 51, // '\x02' + 50, // '\x03' + 49, // '\x04' + 48, // '\x05' + 47, // '\x06' + 46, // '\x07' + 45, // '\x08' + 103, // '\t' + 242, // '\n' + 66, // '\x0b' + 67, // '\x0c' + 229, // '\r' + 44, // '\x0e' + 43, // '\x0f' + 42, // '\x10' + 41, // '\x11' + 40, // '\x12' + 39, // '\x13' + 38, // '\x14' + 37, // '\x15' + 36, // '\x16' + 35, // '\x17' + 34, // '\x18' + 33, // '\x19' + 56, // '\x1a' + 32, // '\x1b' + 31, // '\x1c' + 30, // '\x1d' + 29, // '\x1e' + 28, // '\x1f' + 255, // ' ' + 148, // '!' + 164, // '"' + 149, // '#' + 136, // '$' + 160, // '%' + 155, // '&' + 173, // "'" + 221, // '(' + 222, // ')' + 134, // '*' + 122, // '+' + 232, // ',' + 202, // '-' + 215, // '.' + 224, // '/' + 208, // '0' + 220, // '1' + 204, // '2' + 187, // '3' + 183, // '4' + 179, // '5' + 177, // '6' + 168, // '7' + 178, // '8' + 200, // '9' + 226, // ':' + 195, // ';' + 154, // '<' + 184, // '=' + 174, // '>' + 126, // '?' + 120, // '@' + 191, // 'A' + 157, // 'B' + 194, // 'C' + 170, // 'D' + 189, // 'E' + 162, // 'F' + 161, // 'G' + 150, // 'H' + 193, // 'I' + 142, // 'J' + 137, // 'K' + 171, // 'L' + 176, // 'M' + 185, // 'N' + 167, // 'O' + 186, // 'P' + 112, // 'Q' + 175, // 'R' + 192, // 'S' + 188, // 'T' + 156, // 'U' + 140, // 'V' + 143, // 'W' + 123, // 'X' + 133, // 'Y' + 128, // 'Z' + 147, // '[' + 138, // '\\' + 146, // ']' + 114, // '^' + 223, // '_' + 151, // '`' + 249, // 'a' + 216, // 'b' + 238, // 'c' + 236, // 'd' + 253, // 'e' + 227, // 'f' + 218, // 'g' + 230, // 'h' + 247, // 'i' + 135, // 'j' + 180, // 'k' + 241, // 'l' + 233, // 'm' + 246, // 'n' + 244, // 'o' + 231, // 'p' + 139, // 'q' + 245, // 'r' + 243, // 's' + 251, // 't' + 235, // 'u' + 201, // 'v' + 196, // 'w' + 240, // 'x' + 214, // 'y' + 152, // 'z' + 182, // '{' + 205, // '|' + 181, // '}' + 127, // '~' + 27, // '\x7f' + 212, // '\x80' + 211, // '\x81' + 210, // '\x82' + 213, // '\x83' + 228, // '\x84' + 197, // '\x85' + 169, // '\x86' + 159, // '\x87' + 131, // '\x88' + 172, // '\x89' + 105, // '\x8a' + 80, // '\x8b' + 98, // '\x8c' + 96, // '\x8d' + 97, // '\x8e' + 81, // '\x8f' + 207, // '\x90' + 145, // '\x91' + 116, // '\x92' + 115, // '\x93' + 144, // '\x94' + 130, // '\x95' + 153, // '\x96' + 121, // '\x97' + 107, // '\x98' + 132, // '\x99' + 109, // '\x9a' + 110, // '\x9b' + 124, // '\x9c' + 111, // '\x9d' + 82, // '\x9e' + 108, // '\x9f' + 118, // '\xa0' + 141, // '¡' + 113, // '¢' + 129, // '£' + 119, // '¤' + 125, // '¥' + 165, // '¦' + 117, // '§' + 92, // '¨' + 106, // '©' + 83, // 'ª' + 72, // '«' + 99, // '¬' + 93, // '\xad' + 65, // '®' + 79, // '¯' + 166, // '°' + 237, // '±' + 163, // '²' + 199, // '³' + 190, // '´' + 225, // 'µ' + 209, // '¶' + 203, // '·' + 198, // '¸' + 217, // '¹' + 219, // 'º' + 206, // '»' + 234, // '¼' + 248, // '½' + 158, // '¾' + 239, // '¿' + 255, // 'À' + 255, // 'Á' + 255, // 'Â' + 255, // 'Ã' + 255, // 'Ä' + 255, // 'Å' + 255, // 'Æ' + 255, // 'Ç' + 255, // 'È' + 255, // 'É' + 255, // 'Ê' + 255, // 'Ë' + 255, // 'Ì' + 255, // 'Í' + 255, // 'Î' + 255, // 'Ï' + 255, // 'Ð' + 255, // 'Ñ' + 255, // 'Ò' + 255, // 'Ó' + 255, // 'Ô' + 255, // 'Õ' + 255, // 'Ö' + 255, // '×' + 255, // 'Ø' + 255, // 'Ù' + 255, // 'Ú' + 255, // 'Û' + 255, // 'Ü' + 255, // 'Ý' + 255, // 'Þ' + 255, // 'ß' + 255, // 'à' + 255, // 'á' + 255, // 'â' + 255, // 'ã' + 255, // 'ä' + 255, // 'å' + 255, // 'æ' + 255, // 'ç' + 255, // 'è' + 255, // 'é' + 255, // 'ê' + 255, // 'ë' + 255, // 'ì' + 255, // 'í' + 255, // 'î' + 255, // 'ï' + 255, // 'ð' + 255, // 'ñ' + 255, // 'ò' + 255, // 'ó' + 255, // 'ô' + 255, // 'õ' + 255, // 'ö' + 255, // '÷' + 255, // 'ø' + 255, // 'ù' + 255, // 'ú' + 255, // 'û' + 255, // 'ü' + 255, // 'ý' + 255, // 'þ' + 255, // 'ÿ' +]; diff --git a/regex/src/input.rs b/regex/src/input.rs new file mode 100644 index 000000000..56097bd56 --- /dev/null +++ b/regex/src/input.rs @@ -0,0 +1,420 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::char; +use std::cmp::Ordering; +use std::fmt; +use std::ops; +use std::u32; + +use syntax; + +use literal::LiteralSearcher; +use prog::InstEmptyLook; +use utf8::{decode_utf8, decode_last_utf8}; + +/// Represents a location in the input. +#[derive(Clone, Copy, Debug)] +pub struct InputAt { + pos: usize, + c: Char, + byte: Option<u8>, + len: usize, +} + +impl InputAt { + /// Returns true iff this position is at the beginning of the input. + pub fn is_start(&self) -> bool { + self.pos == 0 + } + + /// Returns true iff this position is past the end of the input. + pub fn is_end(&self) -> bool { + self.c.is_none() && self.byte.is_none() + } + + /// Returns the character at this position. + /// + /// If this position is just before or after the input, then an absent + /// character is returned. + pub fn char(&self) -> Char { + self.c + } + + /// Returns the byte at this position. + pub fn byte(&self) -> Option<u8> { + self.byte + } + + /// Returns the UTF-8 width of the character at this position. + pub fn len(&self) -> usize { + self.len + } + + /// Returns whether the UTF-8 width of the character at this position + /// is zero. + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns the byte offset of this position. + pub fn pos(&self) -> usize { + self.pos + } + + /// Returns the byte offset of the next position in the input. + pub fn next_pos(&self) -> usize { + self.pos + self.len + } +} + +/// An abstraction over input used in the matching engines. +pub trait Input { + /// Return an encoding of the position at byte offset `i`. + fn at(&self, i: usize) -> InputAt; + + /// Return the Unicode character occurring next to `at`. + /// + /// If no such character could be decoded, then `Char` is absent. + fn next_char(&self, at: InputAt) -> Char; + + /// Return the Unicode character occurring previous to `at`. + /// + /// If no such character could be decoded, then `Char` is absent. + fn previous_char(&self, at: InputAt) -> Char; + + /// Return true if the given empty width instruction matches at the + /// input position given. + fn is_empty_match(&self, at: InputAt, empty: &InstEmptyLook) -> bool; + + /// Scan the input for a matching prefix. + fn prefix_at( + &self, + prefixes: &LiteralSearcher, + at: InputAt, + ) -> Option<InputAt>; + + /// The number of bytes in the input. + fn len(&self) -> usize; + + /// Whether the input is empty. + fn is_empty(&self) -> bool { self.len() == 0 } + + /// Return the given input as a sequence of bytes. + fn as_bytes(&self) -> &[u8]; +} + +impl<'a, T: Input> Input for &'a T { + fn at(&self, i: usize) -> InputAt { (**self).at(i) } + + fn next_char(&self, at: InputAt) -> Char { (**self).next_char(at) } + + fn previous_char(&self, at: InputAt) -> Char { (**self).previous_char(at) } + + fn is_empty_match(&self, at: InputAt, empty: &InstEmptyLook) -> bool { + (**self).is_empty_match(at, empty) + } + + fn prefix_at( + &self, + prefixes: &LiteralSearcher, + at: InputAt, + ) -> Option<InputAt> { + (**self).prefix_at(prefixes, at) + } + + fn len(&self) -> usize { (**self).len() } + + fn as_bytes(&self) -> &[u8] { (**self).as_bytes() } +} + +/// An input reader over characters. +#[derive(Clone, Copy, Debug)] +pub struct CharInput<'t>(&'t [u8]); + +impl<'t> CharInput<'t> { + /// Return a new character input reader for the given string. + pub fn new(s: &'t [u8]) -> CharInput<'t> { + CharInput(s) + } +} + +impl<'t> ops::Deref for CharInput<'t> { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + self.0 + } +} + +impl<'t> Input for CharInput<'t> { + fn at(&self, i: usize) -> InputAt { + let c = decode_utf8(&self[i..]).map(|(c, _)| c).into(); + InputAt { + pos: i, + c: c, + byte: None, + len: c.len_utf8(), + } + } + + fn next_char(&self, at: InputAt) -> Char { + at.char() + } + + fn previous_char(&self, at: InputAt) -> Char { + decode_last_utf8(&self[..at.pos()]).map(|(c, _)| c).into() + } + + fn is_empty_match(&self, at: InputAt, empty: &InstEmptyLook) -> bool { + use prog::EmptyLook::*; + match empty.look { + StartLine => { + let c = self.previous_char(at); + at.pos() == 0 || c == '\n' + } + EndLine => { + let c = self.next_char(at); + at.pos() == self.len() || c == '\n' + } + StartText => at.pos() == 0, + EndText => at.pos() == self.len(), + WordBoundary => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_char() != c2.is_word_char() + } + NotWordBoundary => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_char() == c2.is_word_char() + } + WordBoundaryAscii => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_byte() != c2.is_word_byte() + } + NotWordBoundaryAscii => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_byte() == c2.is_word_byte() + } + } + } + + fn prefix_at( + &self, + prefixes: &LiteralSearcher, + at: InputAt, + ) -> Option<InputAt> { + prefixes.find(&self[at.pos()..]).map(|(s, _)| self.at(at.pos() + s)) + } + + fn len(&self) -> usize { + self.0.len() + } + + fn as_bytes(&self) -> &[u8] { + self.0 + } +} + +/// An input reader over bytes. +#[derive(Clone, Copy, Debug)] +pub struct ByteInput<'t> { + text: &'t [u8], + only_utf8: bool, +} + +impl<'t> ByteInput<'t> { + /// Return a new byte-based input reader for the given string. + pub fn new(text: &'t [u8], only_utf8: bool) -> ByteInput<'t> { + ByteInput { + text: text, + only_utf8: only_utf8, + } + } +} + +impl<'t> ops::Deref for ByteInput<'t> { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + self.text + } +} + +impl<'t> Input for ByteInput<'t> { + fn at(&self, i: usize) -> InputAt { + InputAt { + pos: i, + c: None.into(), + byte: self.get(i).cloned(), + len: 1, + } + } + + fn next_char(&self, at: InputAt) -> Char { + decode_utf8(&self[at.pos()..]).map(|(c, _)| c).into() + } + + fn previous_char(&self, at: InputAt) -> Char { + decode_last_utf8(&self[..at.pos()]).map(|(c, _)| c).into() + } + + fn is_empty_match(&self, at: InputAt, empty: &InstEmptyLook) -> bool { + use prog::EmptyLook::*; + match empty.look { + StartLine => { + let c = self.previous_char(at); + at.pos() == 0 || c == '\n' + } + EndLine => { + let c = self.next_char(at); + at.pos() == self.len() || c == '\n' + } + StartText => at.pos() == 0, + EndText => at.pos() == self.len(), + WordBoundary => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_char() != c2.is_word_char() + } + NotWordBoundary => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + c1.is_word_char() == c2.is_word_char() + } + WordBoundaryAscii => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + if self.only_utf8 { + // If we must match UTF-8, then we can't match word + // boundaries at invalid UTF-8. + if c1.is_none() && !at.is_start() { + return false; + } + if c2.is_none() && !at.is_end() { + return false; + } + } + c1.is_word_byte() != c2.is_word_byte() + } + NotWordBoundaryAscii => { + let (c1, c2) = (self.previous_char(at), self.next_char(at)); + if self.only_utf8 { + // If we must match UTF-8, then we can't match word + // boundaries at invalid UTF-8. + if c1.is_none() && !at.is_start() { + return false; + } + if c2.is_none() && !at.is_end() { + return false; + } + } + c1.is_word_byte() == c2.is_word_byte() + } + } + } + + fn prefix_at( + &self, + prefixes: &LiteralSearcher, + at: InputAt, + ) -> Option<InputAt> { + prefixes.find(&self[at.pos()..]).map(|(s, _)| self.at(at.pos() + s)) + } + + fn len(&self) -> usize { + self.text.len() + } + + fn as_bytes(&self) -> &[u8] { + self.text + } +} + +/// An inline representation of `Option<char>`. +/// +/// This eliminates the need to do case analysis on `Option<char>` to determine +/// ordinality with other characters. +/// +/// (The `Option<char>` is not related to encoding. Instead, it is used in the +/// matching engines to represent the beginning and ending boundaries of the +/// search text.) +#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Char(u32); + +impl fmt::Debug for Char { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match char::from_u32(self.0) { + None => write!(f, "Empty"), + Some(c) => write!(f, "{:?}", c), + } + } +} + +impl Char { + /// Returns true iff the character is absent. + #[inline] + pub fn is_none(self) -> bool { self.0 == u32::MAX } + + /// Returns the length of the character's UTF-8 encoding. + /// + /// If the character is absent, then `0` is returned. + #[inline] + pub fn len_utf8(self) -> usize { + char::from_u32(self.0).map_or(0, |c| c.len_utf8()) + } + + /// Returns true iff the character is a word character. + /// + /// If the character is absent, then false is returned. + pub fn is_word_char(self) -> bool { + char::from_u32(self.0).map_or(false, syntax::is_word_character) + } + + /// Returns true iff the byte is a word byte. + /// + /// If the byte is absent, then false is returned. + pub fn is_word_byte(self) -> bool { + match char::from_u32(self.0) { + Some(c) if c <= '\u{7F}' => syntax::is_word_byte(c as u8), + None | Some(_) => false, + } + } +} + +impl From<char> for Char { + fn from(c: char) -> Char { Char(c as u32) } +} + +impl From<Option<char>> for Char { + fn from(c: Option<char>) -> Char { + c.map_or(Char(u32::MAX), |c| c.into()) + } +} + +impl PartialEq<char> for Char { + #[inline] + fn eq(&self, other: &char) -> bool { self.0 == *other as u32 } +} + +impl PartialEq<Char> for char { + #[inline] + fn eq(&self, other: &Char) -> bool { *self as u32 == other.0 } +} + +impl PartialOrd<char> for Char { + #[inline] + fn partial_cmp(&self, other: &char) -> Option<Ordering> { + self.0.partial_cmp(&(*other as u32)) + } +} + +impl PartialOrd<Char> for char { + #[inline] + fn partial_cmp(&self, other: &Char) -> Option<Ordering> { + (*self as u32).partial_cmp(&other.0) + } +} diff --git a/regex/src/lib.rs b/regex/src/lib.rs new file mode 100644 index 000000000..4ea9f99a2 --- /dev/null +++ b/regex/src/lib.rs @@ -0,0 +1,683 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +This crate provides a library for parsing, compiling, and executing regular +expressions. Its syntax is similar to Perl-style regular expressions, but lacks +a few features like look around and backreferences. In exchange, all searches +execute in linear time with respect to the size of the regular expression and +search text. + +This crate's documentation provides some simple examples, describes +[Unicode support](#unicode) and exhaustively lists the +[supported syntax](#syntax). + +For more specific details on the API for regular expressions, please see the +documentation for the [`Regex`](struct.Regex.html) type. + +# Usage + +This crate is [on crates.io](https://crates.io/crates/regex) and can be +used by adding `regex` to your dependencies in your project's `Cargo.toml`. + +```toml +[dependencies] +regex = "1" +``` + +and this to your crate root: + +```rust +extern crate regex; +``` + +# Example: find a date + +General use of regular expressions in this package involves compiling an +expression and then using it to search, split or replace text. For example, +to confirm that some text resembles a date: + +```rust +use regex::Regex; +let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); +assert!(re.is_match("2014-01-01")); +``` + +Notice the use of the `^` and `$` anchors. In this crate, every expression +is executed with an implicit `.*?` at the beginning and end, which allows +it to match anywhere in the text. Anchors can be used to ensure that the +full text matches an expression. + +This example also demonstrates the utility of +[raw strings](https://doc.rust-lang.org/stable/reference/tokens.html#raw-string-literals) +in Rust, which +are just like regular strings except they are prefixed with an `r` and do +not process any escape sequences. For example, `"\\d"` is the same +expression as `r"\d"`. + +# Example: Avoid compiling the same regex in a loop + +It is an anti-pattern to compile the same regular expression in a loop +since compilation is typically expensive. (It takes anywhere from a few +microseconds to a few **milliseconds** depending on the size of the +regex.) Not only is compilation itself expensive, but this also prevents +optimizations that reuse allocations internally to the matching engines. + +In Rust, it can sometimes be a pain to pass regular expressions around if +they're used from inside a helper function. Instead, we recommend using the +[`lazy_static`](https://crates.io/crates/lazy_static) crate to ensure that +regular expressions are compiled exactly once. + +For example: + +```rust +#[macro_use] extern crate lazy_static; +extern crate regex; + +use regex::Regex; + +fn some_helper_function(text: &str) -> bool { + lazy_static! { + static ref RE: Regex = Regex::new("...").unwrap(); + } + RE.is_match(text) +} + +fn main() {} +``` + +Specifically, in this example, the regex will be compiled when it is used for +the first time. On subsequent uses, it will reuse the previous compilation. + +# Example: iterating over capture groups + +This crate provides convenient iterators for matching an expression +repeatedly against a search string to find successive non-overlapping +matches. For example, to find all dates in a string and be able to access +them by their component pieces: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap(); +let text = "2012-03-14, 2013-01-01 and 2014-07-05"; +for cap in re.captures_iter(text) { + println!("Month: {} Day: {} Year: {}", &cap[2], &cap[3], &cap[1]); +} +// Output: +// Month: 03 Day: 14 Year: 2012 +// Month: 01 Day: 01 Year: 2013 +// Month: 07 Day: 05 Year: 2014 +# } +``` + +Notice that the year is in the capture group indexed at `1`. This is +because the *entire match* is stored in the capture group at index `0`. + +# Example: replacement with named capture groups + +Building on the previous example, perhaps we'd like to rearrange the date +formats. This can be done with text replacement. But to make the code +clearer, we can *name* our capture groups and use those names as variables +in our replacement text: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap(); +let before = "2012-03-14, 2013-01-01 and 2014-07-05"; +let after = re.replace_all(before, "$m/$d/$y"); +assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014"); +# } +``` + +The `replace` methods are actually polymorphic in the replacement, which +provides more flexibility than is seen here. (See the documentation for +`Regex::replace` for more details.) + +Note that if your regex gets complicated, you can use the `x` flag to +enable insignificant whitespace mode, which also lets you write comments: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(?x) + (?P<y>\d{4}) # the year + - + (?P<m>\d{2}) # the month + - + (?P<d>\d{2}) # the day +").unwrap(); +let before = "2012-03-14, 2013-01-01 and 2014-07-05"; +let after = re.replace_all(before, "$m/$d/$y"); +assert_eq!(after, "03/14/2012, 01/01/2013 and 07/05/2014"); +# } +``` + +If you wish to match against whitespace in this mode, you can still use `\s`, +`\n`, `\t`, etc. For escaping a single space character, you can use its hex +character code `\x20` or temporarily disable the `x` flag, e.g., `(?-x: )`. + +# Example: match multiple regular expressions simultaneously + +This demonstrates how to use a `RegexSet` to match multiple (possibly +overlapping) regular expressions in a single scan of the search text: + +```rust +use regex::RegexSet; + +let set = RegexSet::new(&[ + r"\w+", + r"\d+", + r"\pL+", + r"foo", + r"bar", + r"barfoo", + r"foobar", +]).unwrap(); + +// Iterate over and collect all of the matches. +let matches: Vec<_> = set.matches("foobar").into_iter().collect(); +assert_eq!(matches, vec![0, 2, 3, 4, 6]); + +// You can also test whether a particular regex matched: +let matches = set.matches("foobar"); +assert!(!matches.matched(5)); +assert!(matches.matched(6)); +``` + +# Pay for what you use + +With respect to searching text with a regular expression, there are three +questions that can be asked: + +1. Does the text match this expression? +2. If so, where does it match? +3. Where did the capturing groups match? + +Generally speaking, this crate could provide a function to answer only #3, +which would subsume #1 and #2 automatically. However, it can be significantly +more expensive to compute the location of capturing group matches, so it's best +not to do it if you don't need to. + +Therefore, only use what you need. For example, don't use `find` if you +only need to test if an expression matches a string. (Use `is_match` +instead.) + +# Unicode + +This implementation executes regular expressions **only** on valid UTF-8 +while exposing match locations as byte indices into the search string. + +Only simple case folding is supported. Namely, when matching +case-insensitively, the characters are first mapped using the "simple" case +folding rules defined by Unicode. + +Regular expressions themselves are **only** interpreted as a sequence of +Unicode scalar values. This means you can use Unicode characters directly +in your expression: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(?i)Δ+").unwrap(); +let mat = re.find("ΔδΔ").unwrap(); +assert_eq!((mat.start(), mat.end()), (0, 6)); +# } +``` + +Most features of the regular expressions in this crate are Unicode aware. Here +are some examples: + +* `.` will match any valid UTF-8 encoded Unicode scalar value except for `\n`. + (To also match `\n`, enable the `s` flag, e.g., `(?s:.)`.) +* `\w`, `\d` and `\s` are Unicode aware. For example, `\s` will match all forms + of whitespace categorized by Unicode. +* `\b` matches a Unicode word boundary. +* Negated character classes like `[^a]` match all Unicode scalar values except + for `a`. +* `^` and `$` are **not** Unicode aware in multi-line mode. Namely, they only + recognize `\n` and not any of the other forms of line terminators defined + by Unicode. + +Unicode general categories, scripts, script extensions, ages and a smattering +of boolean properties are available as character classes. For example, you can +match a sequence of numerals, Greek or Cherokee letters: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"[\pN\p{Greek}\p{Cherokee}]+").unwrap(); +let mat = re.find("abcΔᎠβⅠᏴγδⅡxyz").unwrap(); +assert_eq!((mat.start(), mat.end()), (3, 23)); +# } +``` + +For a more detailed breakdown of Unicode support with respect to +[UTS#18](http://unicode.org/reports/tr18/), +please see the +[UNICODE](https://github.com/rust-lang/regex/blob/master/UNICODE.md) +document in the root of the regex repository. + +# Opt out of Unicode support + +The `bytes` sub-module provides a `Regex` type that can be used to match +on `&[u8]`. By default, text is interpreted as UTF-8 just like it is with +the main `Regex` type. However, this behavior can be disabled by turning +off the `u` flag, even if doing so could result in matching invalid UTF-8. +For example, when the `u` flag is disabled, `.` will match any byte instead +of any Unicode scalar value. + +Disabling the `u` flag is also possible with the standard `&str`-based `Regex` +type, but it is only allowed where the UTF-8 invariant is maintained. For +example, `(?-u:\w)` is an ASCII-only `\w` character class and is legal in an +`&str`-based `Regex`, but `(?-u:\xFF)` will attempt to match the raw byte +`\xFF`, which is invalid UTF-8 and therefore is illegal in `&str`-based +regexes. + +# Syntax + +The syntax supported in this crate is documented below. + +Note that the regular expression parser and abstract syntax are exposed in +a separate crate, [`regex-syntax`](https://docs.rs/regex-syntax). + +## Matching one character + +<pre class="rust"> +. any character except new line (includes new line with s flag) +\d digit (\p{Nd}) +\D not digit +\pN One-letter name Unicode character class +\p{Greek} Unicode character class (general category or script) +\PN Negated one-letter name Unicode character class +\P{Greek} negated Unicode character class (general category or script) +</pre> + +### Character classes + +<pre class="rust"> +[xyz] A character class matching either x, y or z (union). +[^xyz] A character class matching any character except x, y and z. +[a-z] A character class matching any character in range a-z. +[[:alpha:]] ASCII character class ([A-Za-z]) +[[:^alpha:]] Negated ASCII character class ([^A-Za-z]) +[x[^xyz]] Nested/grouping character class (matching any character except y and z) +[a-y&&xyz] Intersection (matching x or y) +[0-9&&[^4]] Subtraction using intersection and negation (matching 0-9 except 4) +[0-9--4] Direct subtraction (matching 0-9 except 4) +[a-g~~b-h] Symmetric difference (matching `a` and `h` only) +[\[\]] Escaping in character classes (matching [ or ]) +</pre> + +Any named character class may appear inside a bracketed `[...]` character +class. For example, `[\p{Greek}[:digit:]]` matches any Greek or ASCII +digit. `[\p{Greek}&&\pL]` matches Greek letters. + +Precedence in character classes, from most binding to least: + +1. Ranges: `a-cd` == `[a-c]d` +2. Union: `ab&&bc` == `[ab]&&[bc]` +3. Intersection: `^a-z&&b` == `^[a-z&&b]` +4. Negation + +## Composites + +<pre class="rust"> +xy concatenation (x followed by y) +x|y alternation (x or y, prefer x) +</pre> + +## Repetitions + +<pre class="rust"> +x* zero or more of x (greedy) +x+ one or more of x (greedy) +x? zero or one of x (greedy) +x*? zero or more of x (ungreedy/lazy) +x+? one or more of x (ungreedy/lazy) +x?? zero or one of x (ungreedy/lazy) +x{n,m} at least n x and at most m x (greedy) +x{n,} at least n x (greedy) +x{n} exactly n x +x{n,m}? at least n x and at most m x (ungreedy/lazy) +x{n,}? at least n x (ungreedy/lazy) +x{n}? exactly n x +</pre> + +## Empty matches + +<pre class="rust"> +^ the beginning of text (or start-of-line with multi-line mode) +$ the end of text (or end-of-line with multi-line mode) +\A only the beginning of text (even with multi-line mode enabled) +\z only the end of text (even with multi-line mode enabled) +\b a Unicode word boundary (\w on one side and \W, \A, or \z on other) +\B not a Unicode word boundary +</pre> + +## Grouping and flags + +<pre class="rust"> +(exp) numbered capture group (indexed by opening parenthesis) +(?P<name>exp) named (also numbered) capture group (allowed chars: [_0-9a-zA-Z]) +(?:exp) non-capturing group +(?flags) set flags within current group +(?flags:exp) set flags for exp (non-capturing) +</pre> + +Flags are each a single character. For example, `(?x)` sets the flag `x` +and `(?-x)` clears the flag `x`. Multiple flags can be set or cleared at +the same time: `(?xy)` sets both the `x` and `y` flags and `(?x-y)` sets +the `x` flag and clears the `y` flag. + +All flags are by default disabled unless stated otherwise. They are: + +<pre class="rust"> +i case-insensitive: letters match both upper and lower case +m multi-line mode: ^ and $ match begin/end of line +s allow . to match \n +U swap the meaning of x* and x*? +u Unicode support (enabled by default) +x ignore whitespace and allow line comments (starting with `#`) +</pre> + +Flags can be toggled within a pattern. Here's an example that matches +case-insensitively for the first part but case-sensitively for the second part: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(?i)a+(?-i)b+").unwrap(); +let cap = re.captures("AaAaAbbBBBb").unwrap(); +assert_eq!(&cap[0], "AaAaAbb"); +# } +``` + +Notice that the `a+` matches either `a` or `A`, but the `b+` only matches +`b`. + +Multi-line mode means `^` and `$` no longer match just at the beginning/end of +the input, but at the beginning/end of lines: + +``` +# use regex::Regex; +let re = Regex::new(r"(?m)^line \d+").unwrap(); +let m = re.find("line one\nline 2\n").unwrap(); +assert_eq!(m.as_str(), "line 2"); +``` + +Note that `^` matches after new lines, even at the end of input: + +``` +# use regex::Regex; +let re = Regex::new(r"(?m)^").unwrap(); +let m = re.find_iter("test\n").last().unwrap(); +assert_eq!((m.start(), m.end()), (5, 5)); +``` + +Here is an example that uses an ASCII word boundary instead of a Unicode +word boundary: + +```rust +# extern crate regex; use regex::Regex; +# fn main() { +let re = Regex::new(r"(?-u:\b).+(?-u:\b)").unwrap(); +let cap = re.captures("$$abc$$").unwrap(); +assert_eq!(&cap[0], "abc"); +# } +``` + +## Escape sequences + +<pre class="rust"> +\* literal *, works for any punctuation character: \.+*?()|[]{}^$ +\a bell (\x07) +\f form feed (\x0C) +\t horizontal tab +\n new line +\r carriage return +\v vertical tab (\x0B) +\123 octal character code (up to three digits) (when enabled) +\x7F hex character code (exactly two digits) +\x{10FFFF} any hex character code corresponding to a Unicode code point +\u007F hex character code (exactly four digits) +\u{7F} any hex character code corresponding to a Unicode code point +\U0000007F hex character code (exactly eight digits) +\U{7F} any hex character code corresponding to a Unicode code point +</pre> + +## Perl character classes (Unicode friendly) + +These classes are based on the definitions provided in +[UTS#18](http://www.unicode.org/reports/tr18/#Compatibility_Properties): + +<pre class="rust"> +\d digit (\p{Nd}) +\D not digit +\s whitespace (\p{White_Space}) +\S not whitespace +\w word character (\p{Alphabetic} + \p{M} + \d + \p{Pc} + \p{Join_Control}) +\W not word character +</pre> + +## ASCII character classes + +<pre class="rust"> +[[:alnum:]] alphanumeric ([0-9A-Za-z]) +[[:alpha:]] alphabetic ([A-Za-z]) +[[:ascii:]] ASCII ([\x00-\x7F]) +[[:blank:]] blank ([\t ]) +[[:cntrl:]] control ([\x00-\x1F\x7F]) +[[:digit:]] digits ([0-9]) +[[:graph:]] graphical ([!-~]) +[[:lower:]] lower case ([a-z]) +[[:print:]] printable ([ -~]) +[[:punct:]] punctuation ([!-/:-@\[-`{-~]) +[[:space:]] whitespace ([\t\n\v\f\r ]) +[[:upper:]] upper case ([A-Z]) +[[:word:]] word characters ([0-9A-Za-z_]) +[[:xdigit:]] hex digit ([0-9A-Fa-f]) +</pre> + +# Untrusted input + +This crate can handle both untrusted regular expressions and untrusted +search text. + +Untrusted regular expressions are handled by capping the size of a compiled +regular expression. +(See [`RegexBuilder::size_limit`](struct.RegexBuilder.html#method.size_limit).) +Without this, it would be trivial for an attacker to exhaust your system's +memory with expressions like `a{100}{100}{100}`. + +Untrusted search text is allowed because the matching engine(s) in this +crate have time complexity `O(mn)` (with `m ~ regex` and `n ~ search +text`), which means there's no way to cause exponential blow-up like with +some other regular expression engines. (We pay for this by disallowing +features like arbitrary look-ahead and backreferences.) + +When a DFA is used, pathological cases with exponential state blow-up are +avoided by constructing the DFA lazily or in an "online" manner. Therefore, +at most one new state can be created for each byte of input. This satisfies +our time complexity guarantees, but can lead to memory growth +proportional to the size of the input. As a stopgap, the DFA is only +allowed to store a fixed number of states. When the limit is reached, its +states are wiped and continues on, possibly duplicating previous work. If +the limit is reached too frequently, it gives up and hands control off to +another matching engine with fixed memory requirements. +(The DFA size limit can also be tweaked. See +[`RegexBuilder::dfa_size_limit`](struct.RegexBuilder.html#method.dfa_size_limit).) +*/ + +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![cfg_attr(feature = "pattern", feature(pattern))] + +#[cfg(not(feature = "use_std"))] +compile_error!("`use_std` feature is currently required to build this crate"); + +extern crate aho_corasick; +extern crate memchr; +extern crate thread_local; +#[cfg(test)] +#[macro_use] +extern crate quickcheck; +extern crate regex_syntax as syntax; +extern crate utf8_ranges; + +#[cfg(feature = "use_std")] +pub use error::Error; +#[cfg(feature = "use_std")] +pub use re_builder::unicode::*; +#[cfg(feature = "use_std")] +pub use re_builder::set_unicode::*; +#[cfg(feature = "use_std")] +pub use re_set::unicode::*; +#[cfg(feature = "use_std")] +#[cfg(feature = "use_std")] +pub use re_unicode::{ + Regex, Match, Captures, + CaptureNames, Matches, CaptureMatches, SubCaptureMatches, + CaptureLocations, Locations, + Replacer, ReplacerRef, NoExpand, Split, SplitN, + escape, +}; + +/** +Match regular expressions on arbitrary bytes. + +This module provides a nearly identical API to the one found in the +top-level of this crate. There are two important differences: + +1. Matching is done on `&[u8]` instead of `&str`. Additionally, `Vec<u8>` +is used where `String` would have been used. +2. Unicode support can be disabled even when disabling it would result in +matching invalid UTF-8 bytes. + +# Example: match null terminated string + +This shows how to find all null-terminated strings in a slice of bytes: + +```rust +# use regex::bytes::Regex; +let re = Regex::new(r"(?-u)(?P<cstr>[^\x00]+)\x00").unwrap(); +let text = b"foo\x00bar\x00baz\x00"; + +// Extract all of the strings without the null terminator from each match. +// The unwrap is OK here since a match requires the `cstr` capture to match. +let cstrs: Vec<&[u8]> = + re.captures_iter(text) + .map(|c| c.name("cstr").unwrap().as_bytes()) + .collect(); +assert_eq!(vec![&b"foo"[..], &b"bar"[..], &b"baz"[..]], cstrs); +``` + +# Example: selectively enable Unicode support + +This shows how to match an arbitrary byte pattern followed by a UTF-8 encoded +string (e.g., to extract a title from a Matroska file): + +```rust +# use std::str; +# use regex::bytes::Regex; +let re = Regex::new( + r"(?-u)\x7b\xa9(?:[\x80-\xfe]|[\x40-\xff].)(?u:(.*))" +).unwrap(); +let text = b"\x12\xd0\x3b\x5f\x7b\xa9\x85\xe2\x98\x83\x80\x98\x54\x76\x68\x65"; +let caps = re.captures(text).unwrap(); + +// Notice that despite the `.*` at the end, it will only match valid UTF-8 +// because Unicode mode was enabled with the `u` flag. Without the `u` flag, +// the `.*` would match the rest of the bytes. +let mat = caps.get(1).unwrap(); +assert_eq!((7, 10), (mat.start(), mat.end())); + +// If there was a match, Unicode mode guarantees that `title` is valid UTF-8. +let title = str::from_utf8(&caps[1]).unwrap(); +assert_eq!("☃", title); +``` + +In general, if the Unicode flag is enabled in a capture group and that capture +is part of the overall match, then the capture is *guaranteed* to be valid +UTF-8. + +# Syntax + +The supported syntax is pretty much the same as the syntax for Unicode +regular expressions with a few changes that make sense for matching arbitrary +bytes: + +1. The `u` flag can be disabled even when disabling it might cause the regex to +match invalid UTF-8. When the `u` flag is disabled, the regex is said to be in +"ASCII compatible" mode. +2. In ASCII compatible mode, neither Unicode scalar values nor Unicode +character classes are allowed. +3. In ASCII compatible mode, Perl character classes (`\w`, `\d` and `\s`) +revert to their typical ASCII definition. `\w` maps to `[[:word:]]`, `\d` maps +to `[[:digit:]]` and `\s` maps to `[[:space:]]`. +4. In ASCII compatible mode, word boundaries use the ASCII compatible `\w` to +determine whether a byte is a word byte or not. +5. Hexadecimal notation can be used to specify arbitrary bytes instead of +Unicode codepoints. For example, in ASCII compatible mode, `\xFF` matches the +literal byte `\xFF`, while in Unicode mode, `\xFF` is a Unicode codepoint that +matches its UTF-8 encoding of `\xC3\xBF`. Similarly for octal notation when +enabled. +6. `.` matches any *byte* except for `\n` instead of any Unicode scalar value. +When the `s` flag is enabled, `.` matches any byte. + +# Performance + +In general, one should expect performance on `&[u8]` to be roughly similar to +performance on `&str`. +*/ +#[cfg(feature = "use_std")] +pub mod bytes { + pub use re_builder::bytes::*; + pub use re_builder::set_bytes::*; + pub use re_bytes::*; + pub use re_set::bytes::*; +} + +mod backtrack; +mod utf8; +mod compile; +mod dfa; +mod error; +mod exec; +mod expand; +mod freqs; +mod input; +mod literal; +#[cfg(feature = "pattern")] +mod pattern; +mod pikevm; +mod prog; +mod re_builder; +mod re_bytes; +mod re_set; +mod re_trait; +mod re_unicode; +mod sparse; +#[cfg(any(regex_runtime_teddy_ssse3, regex_runtime_teddy_avx2))] +mod vector; + +/// The `internal` module exists to support suspicious activity, such as +/// testing different matching engines and supporting the `regex-debug` CLI +/// utility. +#[doc(hidden)] +#[cfg(feature = "use_std")] +pub mod internal { + pub use compile::Compiler; + pub use exec::{Exec, ExecBuilder}; + pub use input::{Char, Input, CharInput, InputAt}; + pub use literal::LiteralSearcher; + pub use prog::{Program, Inst, EmptyLook, InstRanges}; +} diff --git a/regex/src/literal/mod.rs b/regex/src/literal/mod.rs new file mode 100644 index 000000000..abafe35fa --- /dev/null +++ b/regex/src/literal/mod.rs @@ -0,0 +1,1145 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::mem; + +use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; +use memchr::{memchr, memchr2, memchr3}; +use syntax::hir::literal::{Literal, Literals}; + +use freqs::BYTE_FREQUENCIES; +use self::teddy_avx2::{Teddy as TeddyAVX2}; +use self::teddy_ssse3::{Teddy as TeddySSSE3}; + +mod teddy_avx2; +mod teddy_ssse3; + +/// A prefix extracted from a compiled regular expression. +/// +/// A regex prefix is a set of literal strings that *must* be matched at the +/// beginning of a regex in order for the entire regex to match. Similarly +/// for a regex suffix. +#[derive(Clone, Debug)] +pub struct LiteralSearcher { + complete: bool, + lcp: FreqyPacked, + lcs: FreqyPacked, + matcher: Matcher, +} + +#[derive(Clone, Debug)] +enum Matcher { + /// No literals. (Never advances through the input.) + Empty, + /// A set of four or more single byte literals. + Bytes(SingleByteSet), + /// A single substring, find using memchr and frequency analysis. + FreqyPacked(FreqyPacked), + /// A single substring, find using Boyer-Moore. + BoyerMoore(BoyerMooreSearch), + /// An Aho-Corasick automaton. + AC { ac: AhoCorasick<u32>, lits: Vec<Literal> }, + /// A simd accelerated multiple string matcher. Used only for a small + /// number of small literals. + TeddySSSE3(TeddySSSE3), + /// A simd accelerated multiple string matcher. Used only for a small + /// number of small literals. This uses 256-bit vectors. + TeddyAVX2(TeddyAVX2), +} + +impl LiteralSearcher { + /// Returns a matcher that never matches and never advances the input. + pub fn empty() -> Self { + Self::new(Literals::empty(), Matcher::Empty) + } + + /// Returns a matcher for literal prefixes from the given set. + pub fn prefixes(lits: Literals) -> Self { + let matcher = Matcher::prefixes(&lits); + Self::new(lits, matcher) + } + + /// Returns a matcher for literal suffixes from the given set. + pub fn suffixes(lits: Literals) -> Self { + let matcher = Matcher::suffixes(&lits); + Self::new(lits, matcher) + } + + fn new(lits: Literals, matcher: Matcher) -> Self { + let complete = lits.all_complete(); + LiteralSearcher { + complete: complete, + lcp: FreqyPacked::new(lits.longest_common_prefix().to_vec()), + lcs: FreqyPacked::new(lits.longest_common_suffix().to_vec()), + matcher: matcher, + } + } + + /// Returns true if all matches comprise the entire regular expression. + /// + /// This does not necessarily mean that a literal match implies a match + /// of the regular expression. For example, the regular expresison `^a` + /// is comprised of a single complete literal `a`, but the regular + /// expression demands that it only match at the beginning of a string. + pub fn complete(&self) -> bool { + self.complete && !self.is_empty() + } + + /// Find the position of a literal in `haystack` if it exists. + #[inline(always)] // reduces constant overhead + pub fn find(&self, haystack: &[u8]) -> Option<(usize, usize)> { + use self::Matcher::*; + match self.matcher { + Empty => Some((0, 0)), + Bytes(ref sset) => sset.find(haystack).map(|i| (i, i + 1)), + FreqyPacked(ref s) => s.find(haystack).map(|i| (i, i + s.len())), + BoyerMoore(ref s) => s.find(haystack).map(|i| (i, i + s.len())), + AC { ref ac, .. } => { + ac.find(haystack).map(|m| (m.start(), m.end())) + } + TeddySSSE3(ref t) => t.find(haystack).map(|m| (m.start, m.end)), + TeddyAVX2(ref t) => t.find(haystack).map(|m| (m.start, m.end)), + } + } + + /// Like find, except matches must start at index `0`. + pub fn find_start(&self, haystack: &[u8]) -> Option<(usize, usize)> { + for lit in self.iter() { + if lit.len() > haystack.len() { + continue; + } + if lit == &haystack[0..lit.len()] { + return Some((0, lit.len())); + } + } + None + } + + /// Like find, except matches must end at index `haystack.len()`. + pub fn find_end(&self, haystack: &[u8]) -> Option<(usize, usize)> { + for lit in self.iter() { + if lit.len() > haystack.len() { + continue; + } + if lit == &haystack[haystack.len() - lit.len()..] { + return Some((haystack.len() - lit.len(), haystack.len())); + } + } + None + } + + /// Returns an iterator over all literals to be matched. + pub fn iter(&self) -> LiteralIter { + match self.matcher { + Matcher::Empty => LiteralIter::Empty, + Matcher::Bytes(ref sset) => LiteralIter::Bytes(&sset.dense), + Matcher::FreqyPacked(ref s) => LiteralIter::Single(&s.pat), + Matcher::BoyerMoore(ref s) => LiteralIter::Single(&s.pattern), + Matcher::AC { ref lits, .. } => LiteralIter::AC(lits), + Matcher::TeddySSSE3(ref ted) => { + LiteralIter::TeddySSSE3(ted.patterns()) + } + Matcher::TeddyAVX2(ref ted) => { + LiteralIter::TeddyAVX2(ted.patterns()) + } + } + } + + /// Returns a matcher for the longest common prefix of this matcher. + pub fn lcp(&self) -> &FreqyPacked { + &self.lcp + } + + /// Returns a matcher for the longest common suffix of this matcher. + pub fn lcs(&self) -> &FreqyPacked { + &self.lcs + } + + /// Returns true iff this prefix is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of prefixes in this machine. + pub fn len(&self) -> usize { + use self::Matcher::*; + match self.matcher { + Empty => 0, + Bytes(ref sset) => sset.dense.len(), + FreqyPacked(_) => 1, + BoyerMoore(_) => 1, + AC { ref ac, .. } => ac.pattern_count(), + TeddySSSE3(ref ted) => ted.len(), + TeddyAVX2(ref ted) => ted.len(), + } + } + + /// Return the approximate heap usage of literals in bytes. + pub fn approximate_size(&self) -> usize { + use self::Matcher::*; + match self.matcher { + Empty => 0, + Bytes(ref sset) => sset.approximate_size(), + FreqyPacked(ref single) => single.approximate_size(), + BoyerMoore(ref single) => single.approximate_size(), + AC { ref ac, .. } => ac.heap_bytes(), + TeddySSSE3(ref ted) => ted.approximate_size(), + TeddyAVX2(ref ted) => ted.approximate_size(), + } + } +} + +impl Matcher { + fn prefixes(lits: &Literals) -> Self { + let sset = SingleByteSet::prefixes(lits); + Matcher::new(lits, sset) + } + + fn suffixes(lits: &Literals) -> Self { + let sset = SingleByteSet::suffixes(lits); + Matcher::new(lits, sset) + } + + fn new(lits: &Literals, sset: SingleByteSet) -> Self { + if lits.literals().is_empty() { + return Matcher::Empty; + } + if sset.dense.len() >= 26 { + // Avoid trying to match a large number of single bytes. + // This is *very* sensitive to a frequency analysis comparison + // between the bytes in sset and the composition of the haystack. + // No matter the size of sset, if its members all are rare in the + // haystack, then it'd be worth using it. How to tune this... IDK. + // ---AG + return Matcher::Empty; + } + if sset.complete { + return Matcher::Bytes(sset); + } + if lits.literals().len() == 1 { + let lit = lits.literals()[0].to_vec(); + if BoyerMooreSearch::should_use(lit.as_slice()) { + return Matcher::BoyerMoore(BoyerMooreSearch::new(lit)); + } else { + return Matcher::FreqyPacked(FreqyPacked::new(lit)); + } + } + let is_aho_corasick_fast = sset.dense.len() == 1 && sset.all_ascii; + if TeddyAVX2::available() && !is_aho_corasick_fast { + const MAX_TEDDY_LITERALS: usize = 32; + if lits.literals().len() <= MAX_TEDDY_LITERALS { + if let Some(ted) = TeddyAVX2::new(lits) { + return Matcher::TeddyAVX2(ted); + } + } + } + if TeddySSSE3::available() && !is_aho_corasick_fast { + // Only try Teddy if Aho-Corasick can't use memchr on an ASCII + // byte. Also, in its current form, Teddy doesn't scale well to + // lots of literals. + // + // We impose the ASCII restriction since an alternation of + // non-ASCII string literals in the same language is likely to all + // start with the same byte. Even worse, the corpus being searched + // probably has a similar composition, which ends up completely + // negating the benefit of memchr. + const MAX_TEDDY_LITERALS: usize = 32; + if lits.literals().len() <= MAX_TEDDY_LITERALS { + if let Some(ted) = TeddySSSE3::new(lits) { + return Matcher::TeddySSSE3(ted); + } + } + // Fallthrough to ol' reliable Aho-Corasick... + } + let pats = lits.literals().to_owned(); + let ac = AhoCorasickBuilder::new() + .dfa(true) + .build_with_size::<u32, _, _>(&pats) + .unwrap(); + Matcher::AC { ac, lits: pats } + } +} + +pub enum LiteralIter<'a> { + Empty, + Bytes(&'a [u8]), + Single(&'a [u8]), + AC(&'a [Literal]), + TeddySSSE3(&'a [Vec<u8>]), + TeddyAVX2(&'a [Vec<u8>]), +} + +impl<'a> Iterator for LiteralIter<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option<Self::Item> { + match *self { + LiteralIter::Empty => None, + LiteralIter::Bytes(ref mut many) => { + if many.is_empty() { + None + } else { + let next = &many[0..1]; + *many = &many[1..]; + Some(next) + } + } + LiteralIter::Single(ref mut one) => { + if one.is_empty() { + None + } else { + let next = &one[..]; + *one = &[]; + Some(next) + } + } + LiteralIter::AC(ref mut lits) => { + if lits.is_empty() { + None + } else { + let next = &lits[0]; + *lits = &lits[1..]; + Some(&**next) + } + } + LiteralIter::TeddySSSE3(ref mut lits) => { + if lits.is_empty() { + None + } else { + let next = &lits[0]; + *lits = &lits[1..]; + Some(&**next) + } + } + LiteralIter::TeddyAVX2(ref mut lits) => { + if lits.is_empty() { + None + } else { + let next = &lits[0]; + *lits = &lits[1..]; + Some(&**next) + } + } + } + } +} + +#[derive(Clone, Debug)] +struct SingleByteSet { + sparse: Vec<bool>, + dense: Vec<u8>, + complete: bool, + all_ascii: bool, +} + +impl SingleByteSet { + fn new() -> SingleByteSet { + SingleByteSet { + sparse: vec![false; 256], + dense: vec![], + complete: true, + all_ascii: true, + } + } + + fn prefixes(lits: &Literals) -> SingleByteSet { + let mut sset = SingleByteSet::new(); + for lit in lits.literals() { + sset.complete = sset.complete && lit.len() == 1; + if let Some(&b) = lit.get(0) { + if !sset.sparse[b as usize] { + if b > 0x7F { + sset.all_ascii = false; + } + sset.dense.push(b); + sset.sparse[b as usize] = true; + } + } + } + sset + } + + fn suffixes(lits: &Literals) -> SingleByteSet { + let mut sset = SingleByteSet::new(); + for lit in lits.literals() { + sset.complete = sset.complete && lit.len() == 1; + if let Some(&b) = lit.get(lit.len().checked_sub(1).unwrap()) { + if !sset.sparse[b as usize] { + if b > 0x7F { + sset.all_ascii = false; + } + sset.dense.push(b); + sset.sparse[b as usize] = true; + } + } + } + sset + } + + /// Faster find that special cases certain sizes to use memchr. + #[inline(always)] // reduces constant overhead + fn find(&self, text: &[u8]) -> Option<usize> { + match self.dense.len() { + 0 => None, + 1 => memchr(self.dense[0], text), + 2 => memchr2(self.dense[0], self.dense[1], text), + 3 => memchr3(self.dense[0], self.dense[1], self.dense[2], text), + _ => self._find(text), + } + } + + /// Generic find that works on any sized set. + fn _find(&self, haystack: &[u8]) -> Option<usize> { + for (i, &b) in haystack.iter().enumerate() { + if self.sparse[b as usize] { + return Some(i); + } + } + None + } + + fn approximate_size(&self) -> usize { + (self.dense.len() * mem::size_of::<u8>()) + + (self.sparse.len() * mem::size_of::<bool>()) + } +} + +/// Provides an implementation of fast subtring search using frequency +/// analysis. +/// +/// memchr is so fast that we do everything we can to keep the loop in memchr +/// for as long as possible. The easiest way to do this is to intelligently +/// pick the byte to send to memchr. The best byte is the byte that occurs +/// least frequently in the haystack. Since doing frequency analysis on the +/// haystack is far too expensive, we compute a set of fixed frequencies up +/// front and hard code them in src/freqs.rs. Frequency analysis is done via +/// scripts/frequencies.py. +#[derive(Clone, Debug)] +pub struct FreqyPacked { + /// The pattern. + pat: Vec<u8>, + /// The number of Unicode characters in the pattern. This is useful for + /// determining the effective length of a pattern when deciding which + /// optimizations to perform. A trailing incomplete UTF-8 sequence counts + /// as one character. + char_len: usize, + /// The rarest byte in the pattern, according to pre-computed frequency + /// analysis. + rare1: u8, + /// The offset of the rarest byte in `pat`. + rare1i: usize, + /// The second rarest byte in the pattern, according to pre-computed + /// frequency analysis. (This may be equivalent to the rarest byte.) + /// + /// The second rarest byte is used as a type of guard for quickly detecting + /// a mismatch after memchr locates an instance of the rarest byte. This + /// is a hedge against pathological cases where the pre-computed frequency + /// analysis may be off. (But of course, does not prevent *all* + /// pathological cases.) + rare2: u8, + /// The offset of the second rarest byte in `pat`. + rare2i: usize, +} + +impl FreqyPacked { + fn new(pat: Vec<u8>) -> FreqyPacked { + if pat.is_empty() { + return FreqyPacked::empty(); + } + + // Find the rarest two bytes. Try to make them distinct (but it's not + // required). + let mut rare1 = pat[0]; + let mut rare2 = pat[0]; + for b in pat[1..].iter().cloned() { + if freq_rank(b) < freq_rank(rare1) { + rare1 = b; + } + } + for &b in &pat { + if rare1 == rare2 { + rare2 = b + } else if b != rare1 && freq_rank(b) < freq_rank(rare2) { + rare2 = b; + } + } + + // And find the offsets of their last occurrences. + let rare1i = pat.iter().rposition(|&b| b == rare1).unwrap(); + let rare2i = pat.iter().rposition(|&b| b == rare2).unwrap(); + + let char_len = char_len_lossy(&pat); + FreqyPacked { + pat: pat, + char_len: char_len, + rare1: rare1, + rare1i: rare1i, + rare2: rare2, + rare2i: rare2i, + } + } + + fn empty() -> FreqyPacked { + FreqyPacked { + pat: vec![], + char_len: 0, + rare1: 0, + rare1i: 0, + rare2: 0, + rare2i: 0, + } + } + + #[inline(always)] // reduces constant overhead + pub fn find(&self, haystack: &[u8]) -> Option<usize> { + let pat = &*self.pat; + if haystack.len() < pat.len() || pat.is_empty() { + return None; + } + let mut i = self.rare1i; + while i < haystack.len() { + i += match memchr(self.rare1, &haystack[i..]) { + None => return None, + Some(i) => i, + }; + let start = i - self.rare1i; + let end = start + pat.len(); + if end > haystack.len() { + return None; + } + let aligned = &haystack[start..end]; + if aligned[self.rare2i] == self.rare2 && aligned == &*self.pat { + return Some(start); + } + i += 1; + } + None + } + + #[inline(always)] // reduces constant overhead + pub fn is_suffix(&self, text: &[u8]) -> bool { + if text.len() < self.len() { + return false; + } + text[text.len() - self.len()..] == *self.pat + } + + pub fn len(&self) -> usize { + self.pat.len() + } + + pub fn char_len(&self) -> usize { + self.char_len + } + + fn approximate_size(&self) -> usize { + self.pat.len() * mem::size_of::<u8>() + } +} + +fn char_len_lossy(bytes: &[u8]) -> usize { + String::from_utf8_lossy(bytes).chars().count() +} + +/// An implementation of Tuned Boyer-Moore as laid out by +/// Andrew Hume and Daniel Sunday in "Fast String Searching". +/// O(n) in the size of the input. +/// +/// Fast string searching algorithms come in many variations, +/// but they can generally be described in terms of three main +/// components. +/// +/// The skip loop is where the string searcher wants to spend +/// as much time as possible. Exactly which character in the +/// pattern the skip loop examines varies from algorithm to +/// algorithm, but in the simplest case this loop repeated +/// looks at the last character in the pattern and jumps +/// forward in the input if it is not in the pattern. +/// Robert Boyer and J Moore called this the "fast" loop in +/// their original paper. +/// +/// The match loop is responsible for actually examining the +/// whole potentially matching substring. In order to fail +/// faster, the match loop sometimes has a guard test attached. +/// The guard test uses frequency analysis of the different +/// characters in the pattern to choose the least frequency +/// occurring character and use it to find match failures +/// as quickly as possible. +/// +/// The shift rule governs how the algorithm will shuffle its +/// test window in the event of a failure during the match loop. +/// Certain shift rules allow the worst-case run time of the +/// algorithm to be shown to be O(n) in the size of the input +/// rather than O(nm) in the size of the input and the size +/// of the pattern (as naive Boyer-Moore is). +/// +/// "Fast String Searching", in addition to presenting a tuned +/// algorithm, provides a comprehensive taxonomy of the many +/// different flavors of string searchers. Under that taxonomy +/// TBM, the algorithm implemented here, uses an unrolled fast +/// skip loop with memchr fallback, a forward match loop with guard, +/// and the mini Sunday's delta shift rule. To unpack that you'll have to +/// read the paper. +#[derive(Clone, Debug)] +pub struct BoyerMooreSearch { + /// The pattern we are going to look for in the haystack. + pattern: Vec<u8>, + + /// The skip table for the skip loop. + /// + /// Maps the character at the end of the input + /// to a shift. + skip_table: Vec<usize>, + + /// The guard character (least frequently occurring char). + guard: u8, + /// The reverse-index of the guard character in the pattern. + guard_reverse_idx: usize, + + /// Daniel Sunday's mini generalized delta2 shift table. + /// + /// We use a skip loop, so we only have to provide a shift + /// for the skip char (last char). This is why it is a mini + /// shift rule. + md2_shift: usize, +} + +impl BoyerMooreSearch { + /// Create a new string searcher, performing whatever + /// compilation steps are required. + fn new(pattern: Vec<u8>) -> Self { + debug_assert!(pattern.len() > 0); + + let (g, gi) = Self::select_guard(pattern.as_slice()); + let skip_table = Self::compile_skip_table(pattern.as_slice()); + let md2_shift = Self::compile_md2_shift(pattern.as_slice()); + BoyerMooreSearch { + pattern: pattern, + skip_table: skip_table, + guard: g, + guard_reverse_idx: gi, + md2_shift: md2_shift, + } + } + + /// Find the pattern in `haystack`, returning the offset + /// of the start of the first occurrence of the pattern + /// in `haystack`. + #[inline] + fn find(&self, haystack: &[u8]) -> Option<usize> { + if haystack.len() < self.pattern.len() { + return None; + } + + let mut window_end = self.pattern.len() - 1; + + // Inspired by the grep source. It is a way + // to do correct loop unrolling without having to place + // a crashpad of terminating charicters at the end in + // the way described in the Fast String Searching paper. + const NUM_UNROLL: usize = 10; + // 1 for the initial position, and 1 for the md2 shift + let short_circut = (NUM_UNROLL + 2) * self.pattern.len(); + + if haystack.len() > short_circut { + // just 1 for the md2 shift + let backstop = haystack.len() - ((NUM_UNROLL + 1) * self.pattern.len()); + loop { + window_end = match self.skip_loop(haystack, window_end, backstop) { + Some(i) => i, + None => return None, + }; + if window_end >= backstop { + break; + } + + if self.check_match(haystack, window_end) { + return Some(window_end - (self.pattern.len() - 1)); + } else { + let skip = self.skip_table[haystack[window_end] as usize]; + window_end += + if skip == 0 { self.md2_shift } else { skip }; + continue; + } + } + } + + // now process the input after the backstop + while window_end < haystack.len() { + let mut skip = self.skip_table[haystack[window_end] as usize]; + if skip == 0 { + if self.check_match(haystack, window_end) { + return Some(window_end - (self.pattern.len() - 1)); + } else { + skip = self.md2_shift; + } + } + window_end += skip; + } + + None + } + + fn len(&self) -> usize { + return self.pattern.len() + } + + /// The key heuristic behind which the BoyerMooreSearch lives. + /// + /// See `rust-lang/regex/issues/408`. + /// + /// Tuned Boyer-Moore is actually pretty slow! It turns out a handrolled + /// platform-specific memchr routine with a bit of frequency + /// analysis sprinkled on top actually wins most of the time. + /// However, there are a few cases where Tuned Boyer-Moore still + /// wins. + /// + /// If the haystack is random, frequency analysis doesn't help us, + /// so Boyer-Moore will win for sufficiently large needles. + /// Unfortunately, there is no obvious way to determine this + /// ahead of time. + /// + /// If the pattern itself consists of very common characters, + /// frequency analysis won't get us anywhere. The most extreme + /// example of this is a pattern like `eeeeeeeeeeeeeeee`. Fortunately, + /// this case is wholly determined by the pattern, so we can actually + /// implement the heuristic. + /// + /// A third case is if the pattern is sufficiently long. The idea + /// here is that once the pattern gets long enough the Tuned + /// Boyer-Moore skip loop will start making strides long enough + /// to beat the asm deep magic that is memchr. + fn should_use(pattern: &[u8]) -> bool { + // The minimum pattern length required to use TBM. + const MIN_LEN: usize = 9; + // The minimum frequency rank (lower is rarer) that every byte in the + // pattern must have in order to use TBM. That is, if the pattern + // contains _any_ byte with a lower rank, then TBM won't be used. + const MIN_CUTOFF: usize = 150; + // The maximum frequency rank for any byte. + const MAX_CUTOFF: usize = 255; + // The scaling factor used to determine the actual cutoff frequency + // to use (keeping in mind that the minimum frequency rank is bounded + // by MIN_CUTOFF). This scaling factor is an attempt to make TBM more + // likely to be used as the pattern grows longer. That is, longer + // patterns permit somewhat less frequent bytes than shorter patterns, + // under the assumption that TBM gets better as the pattern gets + // longer. + const LEN_CUTOFF_PROPORTION: usize = 4; + + let scaled_rank = pattern.len().wrapping_mul(LEN_CUTOFF_PROPORTION); + let cutoff = cmp::max( + MIN_CUTOFF, + MAX_CUTOFF - cmp::min(MAX_CUTOFF, scaled_rank), + ); + // The pattern must be long enough to be worthwhile. e.g., memchr will + // be faster on `e` because it is short even though e is quite common. + pattern.len() > MIN_LEN + // all the bytes must be more common than the cutoff. + && pattern.iter().all(|c| freq_rank(*c) >= cutoff) + } + + /// Check to see if there is a match at the given position + #[inline] + fn check_match(&self, haystack: &[u8], window_end: usize) -> bool { + // guard test + if haystack[window_end - self.guard_reverse_idx] != self.guard { + return false; + } + + // match loop + let window_start = window_end - (self.pattern.len() - 1); + for i in 0..self.pattern.len() { + if self.pattern[i] != haystack[window_start + i] { + return false; + } + } + + true + } + + /// Skip forward according to the shift table. + /// + /// Returns the offset of the next occurrence + /// of the last char in the pattern, or the none + /// if it never reappears. If `skip_loop` hits the backstop + /// it will leave early. + #[inline] + fn skip_loop(&self, + haystack: &[u8], + mut window_end: usize, + backstop: usize, + ) -> Option<usize> { + let window_end_snapshot = window_end; + let skip_of = |we: usize| -> usize { + // Unsafe might make this faster, but the benchmarks + // were hard to interpret. + self.skip_table[haystack[we] as usize] + }; + + loop { + let mut skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + if skip != 0 { + skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + if skip != 0 { + skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + if skip != 0 { + skip = skip_of(window_end); window_end += skip; + skip = skip_of(window_end); window_end += skip; + + // If ten iterations did not make at least 16 words + // worth of progress, we just fall back on memchr. + if window_end - window_end_snapshot > + 16 * mem::size_of::<usize>() { + + // Returning a window_end >= backstop will immediatly + // break us out of the inner loop in `find`. + if window_end >= backstop { + return Some(window_end); + } + + continue; // we made enough progress + } else { + // In case we are already there, and so that + // we will catch the guard char. + window_end = window_end + .checked_sub(1 + self.guard_reverse_idx) + .unwrap_or(0); + + match memchr(self.guard, &haystack[window_end..]) { + None => return None, + Some(g_idx) => { + return Some(window_end + g_idx + self.guard_reverse_idx); + } + } + } + } + } + } + + return Some(window_end); + } + } + + /// Compute the ufast skip table. + fn compile_skip_table(pattern: &[u8]) -> Vec<usize> { + let mut tab = vec![pattern.len(); 256]; + + // For every char in the pattern, we write a skip + // that will line us up with the rightmost occurrence. + // + // N.B. the sentinel (0) is written by the last + // loop iteration. + for (i, c) in pattern.iter().enumerate() { + tab[*c as usize] = (pattern.len() - 1) - i; + } + + tab + } + + /// Select the guard character based off of the precomputed + /// frequency table. + fn select_guard(pattern: &[u8]) -> (u8, usize) { + let mut rarest = pattern[0]; + let mut rarest_rev_idx = pattern.len() - 1; + for (i, c) in pattern.iter().enumerate() { + if freq_rank(*c) < freq_rank(rarest) { + rarest = *c; + rarest_rev_idx = (pattern.len() - 1) - i; + } + } + + (rarest, rarest_rev_idx) + } + + /// If there is another occurrence of the skip + /// char, shift to it, otherwise just shift to + /// the next window. + fn compile_md2_shift(pattern: &[u8]) -> usize { + let shiftc = *pattern.last().unwrap(); + + // For a pattern of length 1 we will never apply the + // shift rule, so we use a poison value on the principle + // that failing fast is a good thing. + if pattern.len() == 1 { + return 0xDEADBEAF; + } + + let mut i = pattern.len() - 2; + while i > 0 { + if pattern[i] == shiftc { + return (pattern.len() - 1) - i; + } + i -= 1; + } + + // The skip char never re-occurs in the pattern, so + // we can just shift the whole window length. + pattern.len() - 1 + } + + fn approximate_size(&self) -> usize { + (self.pattern.len() * mem::size_of::<u8>()) + + (256 * mem::size_of::<usize>()) // skip table + } +} + +fn freq_rank(b: u8) -> usize { + BYTE_FREQUENCIES[b as usize] as usize +} + +#[cfg(test)] +mod tests { + use super::{BoyerMooreSearch, FreqyPacked}; + + // + // Unit Tests + // + + // The "hello, world" of string searching + #[test] + fn bm_find_subs() { + let searcher = BoyerMooreSearch::new(Vec::from(&b"pattern"[..])); + let haystack = b"I keep seeing patterns in this text"; + assert_eq!(14, searcher.find(haystack).unwrap()); + } + + #[test] + fn bm_find_no_subs() { + let searcher = BoyerMooreSearch::new(Vec::from(&b"pattern"[..])); + let haystack = b"I keep seeing needles in this text"; + assert_eq!(None, searcher.find(haystack)); + } + + // + // Regression Tests + // + + #[test] + fn bm_skip_reset_bug() { + let haystack = vec![0, 0, 0, 0, 0, 1, 1, 0]; + let needle = vec![0, 1, 1, 0]; + + let searcher = BoyerMooreSearch::new(needle); + let offset = searcher.find(haystack.as_slice()).unwrap(); + assert_eq!(4, offset); + } + + #[test] + fn bm_backstop_underflow_bug() { + let haystack = vec![0, 0]; + let needle = vec![0, 0]; + + let searcher = BoyerMooreSearch::new(needle); + let offset = searcher.find(haystack.as_slice()).unwrap(); + assert_eq!(0, offset); + } + + #[test] + fn bm_naive_off_by_one_bug() { + let haystack = vec![91]; + let needle = vec![91]; + + let naive_offset = naive_find(&needle, &haystack).unwrap(); + assert_eq!(0, naive_offset); + } + + #[test] + fn bm_memchr_fallback_indexing_bug() { + let mut haystack = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let needle = vec![1, 1, 1, 1, 32, 32, 87]; + let needle_start = haystack.len(); + haystack.extend(needle.clone()); + + let searcher = BoyerMooreSearch::new(needle); + assert_eq!(needle_start, searcher.find(haystack.as_slice()).unwrap()); + } + + #[test] + fn bm_backstop_boundary() { + let haystack = b"\ +// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +e_data.clone_created(entity_id, entity_to_add.entity_id); +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +".to_vec(); + let needle = b"clone_created".to_vec(); + + let searcher = BoyerMooreSearch::new(needle); + let result = searcher.find(&haystack); + assert_eq!(Some(43), result); + } + + #[test] + fn bm_win_gnu_indexing_bug() { + let haystack_raw = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let needle = vec![1, 1, 1, 1, 1, 1, 1]; + let haystack = haystack_raw.as_slice(); + + BoyerMooreSearch::new(needle.clone()).find(haystack); + } + + // + // QuickCheck Properties + // + + use quickcheck::TestResult; + + fn naive_find(needle: &[u8], haystack: &[u8]) -> Option<usize> { + assert!(needle.len() <= haystack.len()); + + for i in 0..(haystack.len() - (needle.len() - 1)) { + if haystack[i] == needle[0] + && &haystack[i..(i+needle.len())] == needle { + return Some(i) + } + } + + None + } + + quickcheck! { + fn qc_bm_equals_nieve_find(pile1: Vec<u8>, pile2: Vec<u8>) -> TestResult { + if pile1.len() == 0 || pile2.len() == 0 { + return TestResult::discard(); + } + + let (needle, haystack) = if pile1.len() < pile2.len() { + (pile1, pile2.as_slice()) + } else { + (pile2, pile1.as_slice()) + }; + + let searcher = BoyerMooreSearch::new(needle.clone()); + TestResult::from_bool( + searcher.find(haystack) == naive_find(&needle, haystack)) + } + + fn qc_bm_equals_single(pile1: Vec<u8>, pile2: Vec<u8>) -> TestResult { + if pile1.len() == 0 || pile2.len() == 0 { + return TestResult::discard(); + } + + let (needle, haystack) = if pile1.len() < pile2.len() { + (pile1, pile2.as_slice()) + } else { + (pile2, pile1.as_slice()) + }; + + let bm_searcher = BoyerMooreSearch::new(needle.clone()); + let freqy_memchr = FreqyPacked::new(needle); + TestResult::from_bool( + bm_searcher.find(haystack) == freqy_memchr.find(haystack)) + } + + fn qc_bm_finds_trailing_needle( + haystack_pre: Vec<u8>, + needle: Vec<u8> + ) -> TestResult { + if needle.len() == 0 { + return TestResult::discard(); + } + + let mut haystack = haystack_pre.clone(); + let searcher = BoyerMooreSearch::new(needle.clone()); + + if haystack.len() >= needle.len() && + searcher.find(haystack.as_slice()).is_some() { + return TestResult::discard(); + } + + haystack.extend(needle.clone()); + + // What if the the tail of the haystack can start the + // needle? + let start = haystack_pre.len() + .checked_sub(needle.len()) + .unwrap_or(0); + for i in 0..(needle.len() - 1) { + if searcher.find(&haystack[(i + start)..]).is_some() { + return TestResult::discard(); + } + } + + TestResult::from_bool( + searcher.find(haystack.as_slice()) + .map(|x| x == haystack_pre.len()) + .unwrap_or(false)) + } + + // qc_equals_* is only testing the negative case as @burntsushi + // pointed out in https://github.com/rust-lang/regex/issues/446. + // This quickcheck prop represents an effort to force testing of + // the positive case. qc_bm_finds_first and qc_bm_finds_trailing_needle + // already check some of the positive cases, but they don't cover + // cases where the needle is in the middle of haystack. This prop + // fills that hole. + fn qc_bm_finds_subslice( + haystack: Vec<u8>, + needle_start: usize, + needle_length: usize + ) -> TestResult { + if haystack.len() == 0 { + return TestResult::discard(); + } + + let needle_start = needle_start % haystack.len(); + let needle_length = needle_length % (haystack.len() - needle_start); + + if needle_length == 0 { + return TestResult::discard(); + } + + let needle = &haystack[needle_start..(needle_start + needle_length)]; + + let bm_searcher = BoyerMooreSearch::new(needle.to_vec()); + + let start = naive_find(&needle, &haystack); + match start { + None => TestResult::from_bool(false), + Some(nf_start) => + TestResult::from_bool( + nf_start <= needle_start + && bm_searcher.find(&haystack) == start + ) + } + } + + fn qc_bm_finds_first(needle: Vec<u8>) -> TestResult { + if needle.len() == 0 { + return TestResult::discard(); + } + + let mut haystack = needle.clone(); + let searcher = BoyerMooreSearch::new(needle.clone()); + haystack.extend(needle); + + TestResult::from_bool( + searcher.find(haystack.as_slice()) + .map(|x| x == 0) + .unwrap_or(false)) + } + } +} diff --git a/regex/src/literal/teddy_avx2/fallback.rs b/regex/src/literal/teddy_avx2/fallback.rs new file mode 100644 index 000000000..20524aabf --- /dev/null +++ b/regex/src/literal/teddy_avx2/fallback.rs @@ -0,0 +1,20 @@ +use syntax::hir::literal::Literals; + +#[derive(Debug, Clone)] +pub struct Teddy(()); + +#[derive(Debug, Clone)] +pub struct Match { + pub pat: usize, + pub start: usize, + pub end: usize, +} + +impl Teddy { + pub fn available() -> bool { false } + pub fn new(_pats: &Literals) -> Option<Teddy> { None } + pub fn patterns(&self) -> &[Vec<u8>] { &[] } + pub fn len(&self) -> usize { 0 } + pub fn approximate_size(&self) -> usize { 0 } + pub fn find(&self, _haystack: &[u8]) -> Option<Match> { None } +} diff --git a/regex/src/literal/teddy_avx2/imp.rs b/regex/src/literal/teddy_avx2/imp.rs new file mode 100644 index 000000000..3be0b1500 --- /dev/null +++ b/regex/src/literal/teddy_avx2/imp.rs @@ -0,0 +1,472 @@ +/*! +This is the Teddy searcher, but ported to AVX2. + +See the module comments in the SSSE3 Teddy searcher for a more in depth +explanation of how this algorithm works. For the most part, this port is +basically the same as the SSSE3 version, but using 256-bit vectors instead of +128-bit vectors, which increases throughput. +*/ + +use std::cmp; + +use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; +use syntax::hir::literal::Literals; + +use vector::avx2::{AVX2VectorBuilder, u8x32}; + +/// Corresponds to the number of bytes read at a time in the haystack. +const BLOCK_SIZE: usize = 32; + +/// Match reports match information. +#[derive(Debug, Clone)] +pub struct Match { + /// The index of the pattern that matched. The index is in correspondence + /// with the order of the patterns given at construction. + pub pat: usize, + /// The start byte offset of the match. + pub start: usize, + /// The end byte offset of the match. This is always `start + pat.len()`. + pub end: usize, +} + +/// A SIMD accelerated multi substring searcher. +#[derive(Debug, Clone)] +pub struct Teddy { + /// A builder for AVX2 empowered vectors. + vb: AVX2VectorBuilder, + /// A list of substrings to match. + pats: Vec<Vec<u8>>, + /// An Aho-Corasick automaton of the patterns. We use this when we need to + /// search pieces smaller than the Teddy block size. + ac: AhoCorasick, + /// A set of 8 buckets. Each bucket corresponds to a single member of a + /// bitset. A bucket contains zero or more substrings. This is useful + /// when the number of substrings exceeds 8, since our bitsets cannot have + /// more than 8 members. + buckets: Vec<Vec<usize>>, + /// Our set of masks. There's one mask for each byte in the fingerprint. + masks: Masks, +} + +impl Teddy { + /// Returns true if and only if Teddy is supported on this platform. + /// + /// If this returns `false`, then `Teddy::new(...)` is guaranteed to + /// return `None`. + pub fn available() -> bool { + AVX2VectorBuilder::new().is_some() + } + + /// Create a new `Teddy` multi substring matcher. + /// + /// If a `Teddy` matcher could not be created (e.g., `pats` is empty or has + /// an empty substring), then `None` is returned. + pub fn new(pats: &Literals) -> Option<Teddy> { + let vb = match AVX2VectorBuilder::new() { + None => return None, + Some(vb) => vb, + }; + if !Teddy::available() { + return None; + } + + let pats: Vec<_> = pats.literals().iter().map(|p|p.to_vec()).collect(); + let min_len = pats.iter().map(|p| p.len()).min().unwrap_or(0); + // Don't allow any empty patterns and require that we have at + // least one pattern. + if min_len < 1 { + return None; + } + // Pick the largest mask possible, but no larger than 3. + let nmasks = cmp::min(3, min_len); + let mut masks = Masks::new(vb, nmasks); + let mut buckets = vec![vec![]; 8]; + // Assign a substring to each bucket, and add the bucket's bitfield to + // the appropriate position in the mask. + for (pati, pat) in pats.iter().enumerate() { + let bucket = pati % 8; + buckets[bucket].push(pati); + masks.add(bucket as u8, pat); + } + let ac = AhoCorasickBuilder::new() + .dfa(true) + .prefilter(false) + .build(&pats); + Some(Teddy { + vb: vb, + pats: pats.to_vec(), + ac: ac, + buckets: buckets, + masks: masks, + }) + } + + /// Returns all of the substrings matched by this `Teddy`. + pub fn patterns(&self) -> &[Vec<u8>] { + &self.pats + } + + /// Returns the number of substrings in this matcher. + pub fn len(&self) -> usize { + self.pats.len() + } + + /// Returns the approximate size on the heap used by this matcher. + pub fn approximate_size(&self) -> usize { + self.pats.iter().fold(0, |a, b| a + b.len()) + } + + /// Searches `haystack` for the substrings in this `Teddy`. If a match was + /// found, then it is returned. Otherwise, `None` is returned. + pub fn find(&self, haystack: &[u8]) -> Option<Match> { + // This is safe because the only way we can construct a Teddy type + // is if AVX2 is available. + unsafe { self.find_impl(haystack) } + } + + #[allow(unused_attributes)] + #[target_feature(enable = "avx2")] + unsafe fn find_impl(&self, haystack: &[u8]) -> Option<Match> { + // If our haystack is smaller than the block size, then fall back to + // a naive brute force search. + if haystack.is_empty() || haystack.len() < (BLOCK_SIZE + 2) { + return self.slow(haystack, 0); + } + match self.masks.len() { + 0 => None, + 1 => self.find1(haystack), + 2 => self.find2(haystack), + 3 => self.find3(haystack), + _ => unreachable!(), + } + } + + /// `find1` is used when there is only 1 mask. This is the easy case and is + /// pretty much as described in the module documentation. + #[inline(always)] + fn find1(&self, haystack: &[u8]) -> Option<Match> { + let mut pos = 0; + let zero = self.vb.u8x32_splat(0); + let len = haystack.len(); + debug_assert!(len >= BLOCK_SIZE); + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-32. + let p = haystack.get_unchecked(pos..); + self.vb.u8x32_load_unchecked_unaligned(p) + }; + // N.B. `res0` is our `C` in the module documentation. + let res0 = self.masks.members1(h); + // Only do expensive verification if there are any non-zero bits. + let bitfield = res0.ne(zero).movemask(); + if bitfield != 0 { + if let Some(m) = self.verify(haystack, pos, res0, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + self.slow(haystack, pos) + } + + /// `find2` is used when there are 2 masks, e.g., the fingerprint is 2 bytes + /// long. + #[inline(always)] + fn find2(&self, haystack: &[u8]) -> Option<Match> { + // This is an exotic way to right shift a SIMD vector across lanes. + // See below at use for more details. + let zero = self.vb.u8x32_splat(0); + let len = haystack.len(); + // The previous value of `C` (from the module documentation) for the + // *first* byte in the fingerprint. On subsequent iterations, we take + // the last bitset from the previous `C` and insert it into the first + // position of the current `C`, shifting all other bitsets to the right + // one lane. This causes `C` for the first byte to line up with `C` for + // the second byte, so that they can be `AND`'d together. + let mut prev0 = self.vb.u8x32_splat(0xFF); + let mut pos = 1; + debug_assert!(len >= BLOCK_SIZE); + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-32. + let p = haystack.get_unchecked(pos..); + self.vb.u8x32_load_unchecked_unaligned(p) + }; + let (res0, res1) = self.masks.members2(h); + + // Do this: + // + // (prev0 << 15) | (res0 >> 1) + // + // This lets us line up our C values for each byte. + let res0prev0 = res0.alignr_15(prev0); + + // `AND`'s our `C` values together. + let res = res0prev0.and(res1); + prev0 = res0; + + let bitfield = res.ne(zero).movemask(); + if bitfield != 0 { + let pos = pos.checked_sub(1).unwrap(); + if let Some(m) = self.verify(haystack, pos, res, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + // The windowing above doesn't check the last byte in the last + // window, so start the slow search at the last byte of the last + // window. + self.slow(haystack, pos.checked_sub(1).unwrap()) + } + + /// `find3` is used when there are 3 masks, e.g., the fingerprint is 3 bytes + /// long. + /// + /// N.B. This is a straight-forward extrapolation of `find2`. The only + /// difference is that we need to keep track of two previous values of `C`, + /// since we now need to align for three bytes. + #[inline(always)] + fn find3(&self, haystack: &[u8]) -> Option<Match> { + let zero = self.vb.u8x32_splat(0); + let len = haystack.len(); + let mut prev0 = self.vb.u8x32_splat(0xFF); + let mut prev1 = self.vb.u8x32_splat(0xFF); + let mut pos = 2; + + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-32. + let p = haystack.get_unchecked(pos..); + self.vb.u8x32_load_unchecked_unaligned(p) + }; + let (res0, res1, res2) = self.masks.members3(h); + + let res0prev0 = res0.alignr_14(prev0); + let res1prev1 = res1.alignr_15(prev1); + let res = res0prev0.and(res1prev1).and(res2); + + prev0 = res0; + prev1 = res1; + + let bitfield = res.ne(zero).movemask(); + if bitfield != 0 { + let pos = pos.checked_sub(2).unwrap(); + if let Some(m) = self.verify(haystack, pos, res, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + // The windowing above doesn't check the last two bytes in the last + // window, so start the slow search at the penultimate byte of the + // last window. + // self.slow(haystack, pos.saturating_sub(2)) + self.slow(haystack, pos.checked_sub(2).unwrap()) + } + + /// Runs the verification procedure on `res` (i.e., `C` from the module + /// documentation), where the haystack block starts at `pos` in + /// `haystack`. `bitfield` has ones in the bit positions that `res` has + /// non-zero bytes. + /// + /// If a match exists, it returns the first one. + #[inline(always)] + fn verify( + &self, + haystack: &[u8], + pos: usize, + res: u8x32, + mut bitfield: u32, + ) -> Option<Match> { + while bitfield != 0 { + // The next offset, relative to pos, where some fingerprint + // matched. + let byte_pos = bitfield.trailing_zeros() as usize; + bitfield &= !(1 << byte_pos); + + // Offset relative to the beginning of the haystack. + let start = pos + byte_pos; + + // The bitfield telling us which patterns had fingerprints that + // match at this starting position. + let mut patterns = res.extract(byte_pos); + while patterns != 0 { + let bucket = patterns.trailing_zeros() as usize; + patterns &= !(1 << bucket); + + // Actual substring search verification. + if let Some(m) = self.verify_bucket(haystack, bucket, start) { + return Some(m); + } + } + } + + None + } + + /// Verifies whether any substring in the given bucket matches in haystack + /// at the given starting position. + #[inline(always)] + fn verify_bucket( + &self, + haystack: &[u8], + bucket: usize, + start: usize, + ) -> Option<Match> { + // This cycles through the patterns in the bucket in the order that + // the patterns were given. Therefore, we guarantee leftmost-first + // semantics. + for &pati in &self.buckets[bucket] { + let pat = &*self.pats[pati]; + if start + pat.len() > haystack.len() { + continue; + } + if pat == &haystack[start..start + pat.len()] { + return Some(Match { + pat: pati, + start: start, + end: start + pat.len(), + }); + } + } + None + } + + /// Slow substring search through all patterns in this matcher. + /// + /// This is used when we don't have enough bytes in the haystack for our + /// block based approach. + #[inline(never)] + fn slow(&self, haystack: &[u8], pos: usize) -> Option<Match> { + self.ac.find(&haystack[pos..]).map(|m| { + Match { + pat: m.pattern(), + start: pos + m.start(), + end: pos + m.end(), + } + }) + } +} + +/// A list of masks. This has length equal to the length of the fingerprint. +/// The length of the fingerprint is always `min(3, len(smallest_substring))`. +#[derive(Debug, Clone)] +struct Masks { + vb: AVX2VectorBuilder, + masks: [Mask; 3], + size: usize, +} + +impl Masks { + /// Create a new set of masks of size `n`, where `n` corresponds to the + /// number of bytes in a fingerprint. + fn new(vb: AVX2VectorBuilder, n: usize) -> Masks { + Masks { + vb: vb, + masks: [Mask::new(vb), Mask::new(vb), Mask::new(vb)], + size: n, + } + } + + /// Returns the number of masks. + fn len(&self) -> usize { + self.size + } + + /// Adds the given pattern to the given bucket. The bucket should be a + /// power of `2 <= 2^7`. + fn add(&mut self, bucket: u8, pat: &[u8]) { + for i in 0..self.len() { + self.masks[i].add(bucket, pat[i]); + } + } + + /// Finds the fingerprints that are in the given haystack block. i.e., this + /// returns `C` as described in the module documentation. + /// + /// More specifically, `for i in 0..16` and `j in 0..8, C[i][j] == 1` if and + /// only if `haystack_block[i]` corresponds to a fingerprint that is part + /// of a pattern in bucket `j`. + #[inline(always)] + fn members1(&self, haystack_block: u8x32) -> u8x32 { + let masklo = self.vb.u8x32_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)) + } + + /// Like members1, but computes C for the first and second bytes in the + /// fingerprint. + #[inline(always)] + fn members2(&self, haystack_block: u8x32) -> (u8x32, u8x32) { + let masklo = self.vb.u8x32_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + let res0 = + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)); + let res1 = + self.masks[1].lo.shuffle(hlo).and(self.masks[1].hi.shuffle(hhi)); + (res0, res1) + } + + /// Like `members1`, but computes `C` for the first, second and third bytes + /// in the fingerprint. + #[inline(always)] + fn members3(&self, haystack_block: u8x32) -> (u8x32, u8x32, u8x32) { + let masklo = self.vb.u8x32_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + let res0 = + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)); + let res1 = + self.masks[1].lo.shuffle(hlo).and(self.masks[1].hi.shuffle(hhi)); + let res2 = + self.masks[2].lo.shuffle(hlo).and(self.masks[2].hi.shuffle(hhi)); + (res0, res1, res2) + } +} + +/// A single mask. +#[derive(Debug, Clone, Copy)] +struct Mask { + /// Bitsets for the low nybbles in a fingerprint. + lo: u8x32, + /// Bitsets for the high nybbles in a fingerprint. + hi: u8x32, +} + +impl Mask { + /// Create a new mask with no members. + fn new(vb: AVX2VectorBuilder) -> Mask { + Mask { + lo: vb.u8x32_splat(0), + hi: vb.u8x32_splat(0), + } + } + + /// Adds the given byte to the given bucket. + fn add(&mut self, bucket: u8, byte: u8) { + // Split our byte into two nybbles, and add each nybble to our + // mask. + let byte_lo = (byte & 0xF) as usize; + let byte_hi = (byte >> 4) as usize; + + let lo = self.lo.extract(byte_lo) | ((1 << bucket) as u8); + self.lo.replace(byte_lo, lo); + self.lo.replace(byte_lo + 16, lo); + + let hi = self.hi.extract(byte_hi) | ((1 << bucket) as u8); + self.hi.replace(byte_hi, hi); + self.hi.replace(byte_hi + 16, hi); + } +} diff --git a/regex/src/literal/teddy_avx2/mod.rs b/regex/src/literal/teddy_avx2/mod.rs new file mode 100644 index 000000000..4a268163b --- /dev/null +++ b/regex/src/literal/teddy_avx2/mod.rs @@ -0,0 +1,14 @@ +pub use self::imp::*; + +#[cfg(all( + regex_runtime_teddy_avx2, + target_arch = "x86_64", +))] +mod imp; + +#[cfg(not(all( + regex_runtime_teddy_avx2, + target_arch = "x86_64", +)))] +#[path = "fallback.rs"] +mod imp; diff --git a/regex/src/literal/teddy_ssse3/fallback.rs b/regex/src/literal/teddy_ssse3/fallback.rs new file mode 100644 index 000000000..20524aabf --- /dev/null +++ b/regex/src/literal/teddy_ssse3/fallback.rs @@ -0,0 +1,20 @@ +use syntax::hir::literal::Literals; + +#[derive(Debug, Clone)] +pub struct Teddy(()); + +#[derive(Debug, Clone)] +pub struct Match { + pub pat: usize, + pub start: usize, + pub end: usize, +} + +impl Teddy { + pub fn available() -> bool { false } + pub fn new(_pats: &Literals) -> Option<Teddy> { None } + pub fn patterns(&self) -> &[Vec<u8>] { &[] } + pub fn len(&self) -> usize { 0 } + pub fn approximate_size(&self) -> usize { 0 } + pub fn find(&self, _haystack: &[u8]) -> Option<Match> { None } +} diff --git a/regex/src/literal/teddy_ssse3/imp.rs b/regex/src/literal/teddy_ssse3/imp.rs new file mode 100644 index 000000000..c3dc31e04 --- /dev/null +++ b/regex/src/literal/teddy_ssse3/imp.rs @@ -0,0 +1,780 @@ +/*! +Teddy is a simd accelerated multiple substring matching algorithm. The name +and the core ideas in the algorithm were learned from the [Hyperscan][1_u] +project. + + +Background +---------- + +The key idea of Teddy is to do *packed* substring matching. In the literature, +packed substring matching is the idea of examing multiple bytes in a haystack +at a time to detect matches. Implementations of, for example, memchr (which +detects matches of a single byte) have been doing this for years. Only +recently, with the introduction of various SIMD instructions, has this been +extended to substring matching. The PCMPESTRI instruction (and its relatives), +for example, implements substring matching in hardware. It is, however, limited +to substrings of length 16 bytes or fewer, but this restriction is fine in a +regex engine, since we rarely care about the performance difference between +searching for a 16 byte literal and a 16 + N literal; 16 is already long +enough. The key downside of the PCMPESTRI instruction, on current (2016) CPUs +at least, is its latency and throughput. As a result, it is often faster to do +substring search with a Boyer-Moore variant and a well placed memchr to quickly +skip through the haystack. + +There are fewer results from the literature on packed substring matching, +and even fewer for packed multiple substring matching. Ben-Kiki et al. [2] +describes use of PCMPESTRI for substring matching, but is mostly theoretical +and hand-waves performance. There is other theoretical work done by Bille [3] +as well. + +The rest of the work in the field, as far as I'm aware, is by Faro and Kulekci +and is generally focused on multiple pattern search. Their first paper [4a] +introduces the concept of a fingerprint, which is computed for every block of +N bytes in every pattern. The haystack is then scanned N bytes at a time and +a fingerprint is computed in the same way it was computed for blocks in the +patterns. If the fingerprint corresponds to one that was found in a pattern, +then a verification step follows to confirm that one of the substrings with the +corresponding fingerprint actually matches at the current location. Various +implementation tricks are employed to make sure the fingerprint lookup is fast; +typically by truncating the fingerprint. (This may, of course, provoke more +steps in the verification process, so a balance must be struck.) + +The main downside of [4a] is that the minimum substring length is 32 bytes, +presumably because of how the algorithm uses certain SIMD instructions. This +essentially makes it useless for general purpose regex matching, where a small +number of short patterns is far more likely. + +Faro and Kulekci published another paper [4b] that is conceptually very similar +to [4a]. The key difference is that it uses the CRC32 instruction (introduced +as part of SSE 4.2) to compute fingerprint values. This also enables the +algorithm to work effectively on substrings as short as 7 bytes with 4 byte +windows. 7 bytes is unfortunately still too long. The window could be +technically shrunk to 2 bytes, thereby reducing minimum length to 3, but the +small window size ends up negating most performance benefits—and it's likely +the common case in a general purpose regex engine. + +Faro and Kulekci also published [4c] that appears to be intended as a +replacement to using PCMPESTRI. In particular, it is specifically motivated by +the high throughput/latency time of PCMPESTRI and therefore chooses other SIMD +instructions that are faster. While this approach works for short substrings, +I personally couldn't see a way to generalize it to multiple substring search. + +Faro and Kulekci have another paper [4d] that I haven't been able to read +because it is behind a paywall. + + +Teddy +----- + +Finally, we get to Teddy. If the above literature review is complete, then it +appears that Teddy is a novel algorithm. More than that, in my experience, it +completely blows away the competition for short substrings, which is exactly +what we want in a general purpose regex engine. Again, the algorithm appears +to be developed by the authors of [Hyperscan][1_u]. Hyperscan was open sourced +late 2015, and no earlier history could be found. Therefore, tracking the exact +provenance of the algorithm with respect to the published literature seems +difficult. + +DISCLAIMER: My understanding of Teddy is limited to reading auto-generated C +code, its disassembly and observing its runtime behavior. + +At a high level, Teddy works somewhat similarly to the fingerprint algorithms +published by Faro and Kulekci, but Teddy does it in a way that scales a bit +better. Namely: + +1. Teddy's core algorithm scans the haystack in 16 byte chunks. 16 is + significant because it corresponds to the number of bytes in a SIMD vector. + If one used AVX2 instructions, then we could scan the haystack in 32 byte + chunks. Similarly, if one used AVX512 instructions, we could scan the + haystack in 64 byte chunks. Hyperscan implements SSE + AVX2, we only + implement SSE for the moment. +2. Bitwise operations are performed on each chunk to discover if any region of + it matches a set of precomputed fingerprints from the patterns. If there are + matches, then a verification step is performed. In this implementation, our + verification step is naive. This can be improved upon. + +The details to make this work are quite clever. First, we must choose how to +pick our fingerprints. In Hyperscan's implementation, I *believe* they use the +last N bytes of each substring, where N must be at least the minimum length of +any substring in the set being searched. In this implementation, we use the +first N bytes of each substring. (The tradeoffs between these choices aren't +yet clear to me.) We then must figure out how to quickly test whether an +occurrence of any fingerprint from the set of patterns appears in a 16 byte +block from the haystack. To keep things simple, let's assume N = 1 and examine +some examples to motivate the approach. Here are our patterns: + +```ignore +foo +bar +baz +``` + +The corresponding fingerprints, for N = 1, are `f`, `b` and `b`. Now let's set +our 16 byte block to: + +```ignore +bat cat foo bump +xxxxxxxxxxxxxxxx +``` + +To cut to the chase, Teddy works by using bitsets. In particular, Teddy creates +a mask that allows us to quickly compute membership of a fingerprint in a 16 +byte block that also tells which pattern the fingerprint corresponds to. In +this case, our fingerprint is a single byte, so an appropriate abstraction is +a map from a single byte to a list of patterns that contain that fingerprint: + +```ignore +f |--> foo +b |--> bar, baz +``` + +Now, all we need to do is figure out how to represent this map in vector space +and use normal SIMD operations to perform a lookup. The first simplification +we can make is to represent our patterns as bit fields occupying a single +byte. This is important, because a single SIMD vector can store 16 bytes. + +```ignore +f |--> 00000001 +b |--> 00000010, 00000100 +``` + +How do we perform lookup though? It turns out that SSSE3 introduced a very cool +instruction called PSHUFB. The instruction takes two SIMD vectors, `A` and `B`, +and returns a third vector `C`. All vectors are treated as 16 8-bit integers. +`C` is formed by `C[i] = A[B[i]]`. (This is a bit of a simplification, but true +for the purposes of this algorithm. For full details, see [Intel's Intrinsics +Guide][5_u].) This essentially lets us use the values in `B` to lookup values +in `A`. + +If we could somehow cause `B` to contain our 16 byte block from the haystack, +and if `A` could contain our bitmasks, then we'd end up with something like +this for `A`: + +```ignore + 0x00 0x01 ... 0x62 ... 0x66 ... 0xFF +A = 0 0 00000110 00000001 0 +``` + +And if `B` contains our window from our haystack, we could use shuffle to take +the values from `B` and use them to look up our bitsets in `A`. But of course, +we can't do this because `A` in the above example contains 256 bytes, which +is much larger than the size of a SIMD vector. + +Nybbles to the rescue! A nybble is 4 bits. Instead of one mask to hold all of +our bitsets, we can use two masks, where one mask corresponds to the lower four +bits of our fingerprint and the other mask corresponds to the upper four bits. +So our map now looks like: + +```ignore +'f' & 0xF = 0x6 |--> 00000001 +'f' >> 4 = 0x6 |--> 00000111 +'b' & 0xF = 0x2 |--> 00000110 +'b' >> 4 = 0x6 |--> 00000111 +``` + +Notice that the bitsets for each nybble correspond to the union of all +fingerprints that contain that nybble. For example, both `f` and `b` have the +same upper 4 bits but differ on the lower 4 bits. Putting this together, we +have `A0`, `A1` and `B`, where `A0` is our mask for the lower nybble, `A1` is +our mask for the upper nybble and `B` is our 16 byte block from the haystack: + +```ignore + 0x00 0x01 0x02 0x03 ... 0x06 ... 0xF +A0 = 0 0 00000110 0 00000001 0 +A1 = 0 0 0 0 00000111 0 +B = b a t _ t p +B = 0x62 0x61 0x74 0x20 0x74 0x70 +``` + +But of course, we can't use `B` with `PSHUFB` yet, since its values are 8 bits, +and we need indexes that are at most 4 bits (corresponding to one of 16 +values). We can apply the same transformation to split `B` into lower and upper +nybbles as we did `A`. As before, `B0` corresponds to the lower nybbles and +`B1` corresponds to the upper nybbles: + +```ignore + b a t _ c a t _ f o o _ b u m p +B0 = 0x2 0x1 0x4 0x0 0x3 0x1 0x4 0x0 0x6 0xF 0xF 0x0 0x2 0x5 0xD 0x0 +B1 = 0x6 0x6 0x7 0x2 0x6 0x6 0x7 0x2 0x6 0x6 0x6 0x2 0x6 0x7 0x6 0x7 +``` + +And now we have a nice correspondence. `B0` can index `A0` and `B1` can index +`A1`. Here's what we get when we apply `C0 = PSHUFB(A0, B0)`: + +```ignore + b a ... f o ... p + A0[0x2] A0[0x1] A0[0x6] A0[0xF] A0[0x0] +C0 = 00000110 0 00000001 0 0 +``` + +And `C1 = PSHUFB(A1, B1)`: + +```ignore + b a ... f o ... p + A1[0x6] A1[0x6] A1[0x6] A1[0x6] A1[0x7] +C1 = 00000111 00000111 00000111 00000111 0 +``` + +Notice how neither one of `C0` or `C1` is guaranteed to report fully correct +results all on its own. For example, `C1` claims that `b` is a fingerprint for +the pattern `foo` (since `A1[0x6] = 00000111`), and that `o` is a fingerprint +for all of our patterns. But if we combined `C0` and `C1` with an `AND` +operation: + +```ignore + b a ... f o ... p +C = 00000110 0 00000001 0 0 +``` + +Then we now have that `C[i]` contains a bitset corresponding to the matching +fingerprints in a haystack's 16 byte block, where `i` is the `ith` byte in that +block. + +Once we have that, we can look for the position of the least significant bit +in `C`. That position, modulo `8`, gives us the pattern that the fingerprint +matches. That position, integer divided by `8`, also gives us the byte offset +that the fingerprint occurs in inside the 16 byte haystack block. Using those +two pieces of information, we can run a verification procedure that tries +to match all substrings containing that fingerprint at that position in the +haystack. + + +Implementation notes +-------------------- + +The problem with the algorithm as described above is that it uses a single byte +for a fingerprint. This will work well if the fingerprints are rare in the +haystack (e.g., capital letters or special characters in normal English text), +but if the fingerprints are common, you'll wind up spending too much time in +the verification step, which effectively negate the performance benefits of +scanning 16 bytes at a time. Remember, the key to the performance of this +algorithm is to do as little work as possible per 16 bytes. + +This algorithm can be extrapolated in a relatively straight-forward way to use +larger fingerprints. That is, instead of a single byte prefix, we might use a +three byte prefix. The implementation below implements N = {1, 2, 3} and always +picks the largest N possible. The rationale is that the bigger the fingerprint, +the fewer verification steps we'll do. Of course, if N is too large, then we'll +end up doing too much on each step. + +The way to extend it is: + +1. Add a mask for each byte in the fingerprint. (Remember that each mask is + composed of two SIMD vectors.) This results in a value of `C` for each byte + in the fingerprint while searching. +2. When testing each 16 byte block, each value of `C` must be shifted so that + they are aligned. Once aligned, they should all be `AND`'d together. This + will give you only the bitsets corresponding to the full match of the + fingerprint. + +The implementation below is commented to fill in the nitty gritty details. + +References +---------- + +- **[1]** [Hyperscan on GitHub](https://github.com/01org/hyperscan), + [webpage](https://01.org/hyperscan) +- **[2a]** Ben-Kiki, O., Bille, P., Breslauer, D., Gasieniec, L., Grossi, R., + & Weimann, O. (2011). + _Optimal packed string matching_. + In LIPIcs-Leibniz International Proceedings in Informatics (Vol. 13). + Schloss Dagstuhl-Leibniz-Zentrum fuer Informatik. + DOI: 10.4230/LIPIcs.FSTTCS.2011.423. + [PDF](http://drops.dagstuhl.de/opus/volltexte/2011/3355/pdf/37.pdf). +- **[2b]** Ben-Kiki, O., Bille, P., Breslauer, D., Ga̧sieniec, L., Grossi, R., + & Weimann, O. (2014). + _Towards optimal packed string matching_. + Theoretical Computer Science, 525, 111-129. + DOI: 10.1016/j.tcs.2013.06.013. + [PDF](http://www.cs.haifa.ac.il/~oren/Publications/bpsm.pdf). +- **[3]** Bille, P. (2011). + _Fast searching in packed strings_. + Journal of Discrete Algorithms, 9(1), 49-56. + DOI: 10.1016/j.jda.2010.09.003. + [PDF](http://www.sciencedirect.com/science/article/pii/S1570866710000353). +- **[4a]** Faro, S., & Külekci, M. O. (2012, October). + _Fast multiple string matching using streaming SIMD extensions technology_. + In String Processing and Information Retrieval (pp. 217-228). + Springer Berlin Heidelberg. + DOI: 10.1007/978-3-642-34109-0_23. + [PDF](http://www.dmi.unict.it/~faro/papers/conference/faro32.pdf). +- **[4b]** Faro, S., & Külekci, M. O. (2013, September). + _Towards a Very Fast Multiple String Matching Algorithm for Short Patterns_. + In Stringology (pp. 78-91). + [PDF](http://www.dmi.unict.it/~faro/papers/conference/faro36.pdf). +- **[4c]** Faro, S., & Külekci, M. O. (2013, January). + _Fast packed string matching for short patterns_. + In Proceedings of the Meeting on Algorithm Engineering & Expermiments + (pp. 113-121). + Society for Industrial and Applied Mathematics. + [PDF](http://arxiv.org/pdf/1209.6449.pdf). +- **[4d]** Faro, S., & Külekci, M. O. (2014). + _Fast and flexible packed string matching_. + Journal of Discrete Algorithms, 28, 61-72. + DOI: 10.1016/j.jda.2014.07.003. + +[1_u]: https://github.com/01org/hyperscan +[5_u]: https://software.intel.com/sites/landingpage/IntrinsicsGuide +*/ + +use std::cmp; + +use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; +use syntax::hir::literal::Literals; + +use vector::ssse3::{SSSE3VectorBuilder, u8x16}; + +/// Corresponds to the number of bytes read at a time in the haystack. +const BLOCK_SIZE: usize = 16; + +/// Match reports match information. +#[derive(Debug, Clone)] +pub struct Match { + /// The index of the pattern that matched. The index is in correspondence + /// with the order of the patterns given at construction. + pub pat: usize, + /// The start byte offset of the match. + pub start: usize, + /// The end byte offset of the match. This is always `start + pat.len()`. + pub end: usize, +} + +/// A SIMD accelerated multi substring searcher. +#[derive(Debug, Clone)] +pub struct Teddy { + /// A builder for SSSE3 empowered vectors. + vb: SSSE3VectorBuilder, + /// A list of substrings to match. + pats: Vec<Vec<u8>>, + /// An Aho-Corasick automaton of the patterns. We use this when we need to + /// search pieces smaller than the Teddy block size. + ac: AhoCorasick, + /// A set of 8 buckets. Each bucket corresponds to a single member of a + /// bitset. A bucket contains zero or more substrings. This is useful + /// when the number of substrings exceeds 8, since our bitsets cannot have + /// more than 8 members. + buckets: Vec<Vec<usize>>, + /// Our set of masks. There's one mask for each byte in the fingerprint. + masks: Masks, +} + +impl Teddy { + /// Returns true if and only if Teddy is supported on this platform. + /// + /// If this returns `false`, then `Teddy::new(...)` is guaranteed to + /// return `None`. + pub fn available() -> bool { + SSSE3VectorBuilder::new().is_some() + } + + /// Create a new `Teddy` multi substring matcher. + /// + /// If a `Teddy` matcher could not be created (e.g., `pats` is empty or has + /// an empty substring), then `None` is returned. + pub fn new(pats: &Literals) -> Option<Teddy> { + let vb = match SSSE3VectorBuilder::new() { + None => return None, + Some(vb) => vb, + }; + if !Teddy::available() { + return None; + } + + let pats: Vec<_> = pats.literals().iter().map(|p|p.to_vec()).collect(); + let min_len = pats.iter().map(|p| p.len()).min().unwrap_or(0); + // Don't allow any empty patterns and require that we have at + // least one pattern. + if min_len < 1 { + return None; + } + // Pick the largest mask possible, but no larger than 3. + let nmasks = cmp::min(3, min_len); + let mut masks = Masks::new(vb, nmasks); + let mut buckets = vec![vec![]; 8]; + // Assign a substring to each bucket, and add the bucket's bitfield to + // the appropriate position in the mask. + for (pati, pat) in pats.iter().enumerate() { + let bucket = pati % 8; + buckets[bucket].push(pati); + masks.add(bucket as u8, pat); + } + let ac = AhoCorasickBuilder::new() + .dfa(true) + .prefilter(false) + .build(&pats); + Some(Teddy { + vb: vb, + pats: pats.to_vec(), + ac: ac, + buckets: buckets, + masks: masks, + }) + } + + /// Returns all of the substrings matched by this `Teddy`. + pub fn patterns(&self) -> &[Vec<u8>] { + &self.pats + } + + /// Returns the number of substrings in this matcher. + pub fn len(&self) -> usize { + self.pats.len() + } + + /// Returns the approximate size on the heap used by this matcher. + pub fn approximate_size(&self) -> usize { + self.pats.iter().fold(0, |a, b| a + b.len()) + } + + /// Searches `haystack` for the substrings in this `Teddy`. If a match was + /// found, then it is returned. Otherwise, `None` is returned. + pub fn find(&self, haystack: &[u8]) -> Option<Match> { + // This is safe because the only way we can construct a Teddy type + // is if SSSE3 is available. + unsafe { self.find_impl(haystack) } + } + + #[allow(unused_attributes)] + #[target_feature(enable = "ssse3")] + unsafe fn find_impl(&self, haystack: &[u8]) -> Option<Match> { + // If our haystack is smaller than the block size, then fall back to + // a naive brute force search. + if haystack.is_empty() || haystack.len() < (BLOCK_SIZE + 2) { + return self.slow(haystack, 0); + } + match self.masks.len() { + 0 => None, + 1 => self.find1(haystack), + 2 => self.find2(haystack), + 3 => self.find3(haystack), + _ => unreachable!(), + } + } + + /// `find1` is used when there is only 1 mask. This is the easy case and is + /// pretty much as described in the module documentation. + #[inline(always)] + fn find1(&self, haystack: &[u8]) -> Option<Match> { + let mut pos = 0; + let zero = self.vb.u8x16_splat(0); + let len = haystack.len(); + debug_assert!(len >= BLOCK_SIZE); + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-16. + let p = haystack.get_unchecked(pos..); + self.vb.u8x16_load_unchecked_unaligned(p) + }; + // N.B. `res0` is our `C` in the module documentation. + let res0 = self.masks.members1(h); + // Only do expensive verification if there are any non-zero bits. + let bitfield = res0.ne(zero).movemask(); + if bitfield != 0 { + if let Some(m) = self.verify(haystack, pos, res0, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + self.slow(haystack, pos) + } + + /// `find2` is used when there are 2 masks, e.g., the fingerprint is 2 bytes + /// long. + #[inline(always)] + fn find2(&self, haystack: &[u8]) -> Option<Match> { + // This is an exotic way to right shift a SIMD vector across lanes. + // See below at use for more details. + let zero = self.vb.u8x16_splat(0); + let len = haystack.len(); + // The previous value of `C` (from the module documentation) for the + // *first* byte in the fingerprint. On subsequent iterations, we take + // the last bitset from the previous `C` and insert it into the first + // position of the current `C`, shifting all other bitsets to the right + // one lane. This causes `C` for the first byte to line up with `C` for + // the second byte, so that they can be `AND`'d together. + let mut prev0 = self.vb.u8x16_splat(0xFF); + let mut pos = 1; + debug_assert!(len >= BLOCK_SIZE); + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-16. + let p = haystack.get_unchecked(pos..); + self.vb.u8x16_load_unchecked_unaligned(p) + }; + let (res0, res1) = self.masks.members2(h); + + // Do this: + // + // (prev0 << 15) | (res0 >> 1) + // + // This lets us line up our C values for each byte. + let res0prev0 = res0.alignr_15(prev0); + + // `AND`'s our `C` values together. + let res = res0prev0.and(res1); + prev0 = res0; + + let bitfield = res.ne(zero).movemask(); + if bitfield != 0 { + let pos = pos.checked_sub(1).unwrap(); + if let Some(m) = self.verify(haystack, pos, res, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + // The windowing above doesn't check the last byte in the last + // window, so start the slow search at the last byte of the last + // window. + self.slow(haystack, pos.checked_sub(1).unwrap()) + } + + /// `find3` is used when there are 3 masks, e.g., the fingerprint is 3 bytes + /// long. + /// + /// N.B. This is a straight-forward extrapolation of `find2`. The only + /// difference is that we need to keep track of two previous values of `C`, + /// since we now need to align for three bytes. + #[inline(always)] + fn find3(&self, haystack: &[u8]) -> Option<Match> { + let zero = self.vb.u8x16_splat(0); + let len = haystack.len(); + let mut prev0 = self.vb.u8x16_splat(0xFF); + let mut prev1 = self.vb.u8x16_splat(0xFF); + let mut pos = 2; + while pos <= len - BLOCK_SIZE { + let h = unsafe { + // I tried and failed to eliminate bounds checks in safe code. + // This is safe because of our loop invariant: pos is always + // <= len-16. + let p = haystack.get_unchecked(pos..); + self.vb.u8x16_load_unchecked_unaligned(p) + }; + let (res0, res1, res2) = self.masks.members3(h); + + let res0prev0 = res0.alignr_14(prev0); + let res1prev1 = res1.alignr_15(prev1); + let res = res0prev0.and(res1prev1).and(res2); + + prev0 = res0; + prev1 = res1; + + let bitfield = res.ne(zero).movemask(); + if bitfield != 0 { + let pos = pos.checked_sub(2).unwrap(); + if let Some(m) = self.verify(haystack, pos, res, bitfield) { + return Some(m); + } + } + pos += BLOCK_SIZE; + } + // The windowing above doesn't check the last two bytes in the last + // window, so start the slow search at the penultimate byte of the + // last window. + // self.slow(haystack, pos.saturating_sub(2)) + self.slow(haystack, pos.checked_sub(2).unwrap()) + } + + /// Runs the verification procedure on `res` (i.e., `C` from the module + /// documentation), where the haystack block starts at `pos` in + /// `haystack`. `bitfield` has ones in the bit positions that `res` has + /// non-zero bytes. + /// + /// If a match exists, it returns the first one. + #[inline(always)] + fn verify( + &self, + haystack: &[u8], + pos: usize, + res: u8x16, + mut bitfield: u32, + ) -> Option<Match> { + while bitfield != 0 { + // The next offset, relative to pos, where some fingerprint + // matched. + let byte_pos = bitfield.trailing_zeros() as usize; + bitfield &= !(1 << byte_pos); + + // Offset relative to the beginning of the haystack. + let start = pos + byte_pos; + + // The bitfield telling us which patterns had fingerprints that + // match at this starting position. + let mut patterns = res.extract(byte_pos); + while patterns != 0 { + let bucket = patterns.trailing_zeros() as usize; + patterns &= !(1 << bucket); + + // Actual substring search verification. + if let Some(m) = self.verify_bucket(haystack, bucket, start) { + return Some(m); + } + } + } + + None + } + + /// Verifies whether any substring in the given bucket matches in haystack + /// at the given starting position. + #[inline(always)] + fn verify_bucket( + &self, + haystack: &[u8], + bucket: usize, + start: usize, + ) -> Option<Match> { + // This cycles through the patterns in the bucket in the order that + // the patterns were given. Therefore, we guarantee leftmost-first + // semantics. + for &pati in &self.buckets[bucket] { + let pat = &*self.pats[pati]; + if start + pat.len() > haystack.len() { + continue; + } + if pat == &haystack[start..start + pat.len()] { + return Some(Match { + pat: pati, + start: start, + end: start + pat.len(), + }); + } + } + None + } + + /// Slow substring search through all patterns in this matcher. + /// + /// This is used when we don't have enough bytes in the haystack for our + /// block based approach. + #[inline(never)] + fn slow(&self, haystack: &[u8], pos: usize) -> Option<Match> { + self.ac.find(&haystack[pos..]).map(|m| { + Match { + pat: m.pattern(), + start: pos + m.start(), + end: pos + m.end(), + } + }) + } +} + +/// A list of masks. This has length equal to the length of the fingerprint. +/// The length of the fingerprint is always `min(3, len(smallest_substring))`. +#[derive(Debug, Clone)] +struct Masks { + vb: SSSE3VectorBuilder, + masks: [Mask; 3], + size: usize, +} + +impl Masks { + /// Create a new set of masks of size `n`, where `n` corresponds to the + /// number of bytes in a fingerprint. + fn new(vb: SSSE3VectorBuilder, n: usize) -> Masks { + Masks { + vb: vb, + masks: [Mask::new(vb), Mask::new(vb), Mask::new(vb)], + size: n, + } + } + + /// Returns the number of masks. + fn len(&self) -> usize { + self.size + } + + /// Adds the given pattern to the given bucket. The bucket should be a + /// power of `2 <= 2^7`. + fn add(&mut self, bucket: u8, pat: &[u8]) { + for i in 0..self.len() { + self.masks[i].add(bucket, pat[i]); + } + } + + /// Finds the fingerprints that are in the given haystack block. i.e., this + /// returns `C` as described in the module documentation. + /// + /// More specifically, `for i in 0..16` and `j in 0..8, C[i][j] == 1` if and + /// only if `haystack_block[i]` corresponds to a fingerprint that is part + /// of a pattern in bucket `j`. + #[inline(always)] + fn members1(&self, haystack_block: u8x16) -> u8x16 { + let masklo = self.vb.u8x16_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)) + } + + /// Like members1, but computes C for the first and second bytes in the + /// fingerprint. + #[inline(always)] + fn members2(&self, haystack_block: u8x16) -> (u8x16, u8x16) { + let masklo = self.vb.u8x16_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + let res0 = + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)); + let res1 = + self.masks[1].lo.shuffle(hlo).and(self.masks[1].hi.shuffle(hhi)); + (res0, res1) + } + + /// Like `members1`, but computes `C` for the first, second and third bytes + /// in the fingerprint. + #[inline(always)] + fn members3(&self, haystack_block: u8x16) -> (u8x16, u8x16, u8x16) { + let masklo = self.vb.u8x16_splat(0xF); + let hlo = haystack_block.and(masklo); + let hhi = haystack_block.bit_shift_right_4().and(masklo); + + let res0 = + self.masks[0].lo.shuffle(hlo).and(self.masks[0].hi.shuffle(hhi)); + let res1 = + self.masks[1].lo.shuffle(hlo).and(self.masks[1].hi.shuffle(hhi)); + let res2 = + self.masks[2].lo.shuffle(hlo).and(self.masks[2].hi.shuffle(hhi)); + (res0, res1, res2) + } +} + +/// A single mask. +#[derive(Debug, Clone, Copy)] +struct Mask { + /// Bitsets for the low nybbles in a fingerprint. + lo: u8x16, + /// Bitsets for the high nybbles in a fingerprint. + hi: u8x16, +} + +impl Mask { + /// Create a new mask with no members. + fn new(vb: SSSE3VectorBuilder) -> Mask { + Mask { + lo: vb.u8x16_splat(0), + hi: vb.u8x16_splat(0), + } + } + + /// Adds the given byte to the given bucket. + fn add(&mut self, bucket: u8, byte: u8) { + // Split our byte into two nybbles, and add each nybble to our + // mask. + let byte_lo = (byte & 0xF) as usize; + let byte_hi = (byte >> 4) as usize; + + let lo = self.lo.extract(byte_lo); + self.lo.replace(byte_lo, ((1 << bucket) as u8) | lo); + + let hi = self.hi.extract(byte_hi); + self.hi.replace(byte_hi, ((1 << bucket) as u8) | hi); + } +} diff --git a/regex/src/literal/teddy_ssse3/mod.rs b/regex/src/literal/teddy_ssse3/mod.rs new file mode 100644 index 000000000..8ffaeba57 --- /dev/null +++ b/regex/src/literal/teddy_ssse3/mod.rs @@ -0,0 +1,14 @@ +pub use self::imp::*; + +#[cfg(all( + regex_runtime_teddy_ssse3, + target_arch = "x86_64", +))] +mod imp; + +#[cfg(not(all( + regex_runtime_teddy_ssse3, + target_arch = "x86_64", +)))] +#[path = "fallback.rs"] +mod imp; diff --git a/regex/src/pattern.rs b/regex/src/pattern.rs new file mode 100644 index 000000000..37183c24e --- /dev/null +++ b/regex/src/pattern.rs @@ -0,0 +1,62 @@ +use std::str::pattern::{Pattern, Searcher, SearchStep}; + +use re_unicode::{Regex, Matches}; + +pub struct RegexSearcher<'r, 't> { + haystack: &'t str, + it: Matches<'r, 't>, + last_step_end: usize, + next_match: Option<(usize, usize)>, +} + +impl<'r, 't> Pattern<'t> for &'r Regex { + type Searcher = RegexSearcher<'r, 't>; + + fn into_searcher(self, haystack: &'t str) -> RegexSearcher<'r, 't> { + RegexSearcher { + haystack: haystack, + it: self.find_iter(haystack), + last_step_end: 0, + next_match: None, + } + } +} + +unsafe impl<'r, 't> Searcher<'t> for RegexSearcher<'r, 't> { + #[inline] + fn haystack(&self) -> &'t str { + self.haystack + } + + #[inline] + fn next(&mut self) -> SearchStep { + if let Some((s, e)) = self.next_match { + self.next_match = None; + self.last_step_end = e; + return SearchStep::Match(s, e); + } + match self.it.next() { + None => { + if self.last_step_end < self.haystack().len() { + let last = self.last_step_end; + self.last_step_end = self.haystack().len(); + SearchStep::Reject(last, self.haystack().len()) + } else { + SearchStep::Done + } + } + Some(m) => { + let (s, e) = (m.start(), m.end()); + if s == self.last_step_end { + self.last_step_end = e; + SearchStep::Match(s, e) + } else { + self.next_match = Some((s, e)); + let last = self.last_step_end; + self.last_step_end = s; + SearchStep::Reject(last, s) + } + } + } + } +} diff --git a/regex/src/pikevm.rs b/regex/src/pikevm.rs new file mode 100644 index 000000000..72f2b3cc8 --- /dev/null +++ b/regex/src/pikevm.rs @@ -0,0 +1,380 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This module implements the Pike VM. That is, it guarantees linear time +// search of a regex on any text with memory use proportional to the size of +// the regex. +// +// It is equal in power to the backtracking engine in this crate, except the +// backtracking engine is typically faster on small regexes/texts at the +// expense of a bigger memory footprint. +// +// It can do more than the DFA can (specifically, record capture locations +// and execute Unicode word boundary assertions), but at a slower speed. +// Specifically, the Pike VM exectues a DFA implicitly by repeatedly expanding +// epsilon transitions. That is, the Pike VM engine can be in multiple states +// at once where as the DFA is only ever in one state at a time. +// +// Therefore, the Pike VM is generally treated as the fallback when the other +// matching engines either aren't feasible to run or are insufficient. + +use std::mem; + +use exec::ProgramCache; +use input::{Input, InputAt}; +use prog::{Program, InstPtr}; +use re_trait::Slot; +use sparse::SparseSet; + +/// An NFA simulation matching engine. +#[derive(Debug)] +pub struct Fsm<'r, I> { + /// The sequence of opcodes (among other things) that is actually executed. + /// + /// The program may be byte oriented or Unicode codepoint oriented. + prog: &'r Program, + /// An explicit stack used for following epsilon transitions. (This is + /// borrowed from the cache.) + stack: &'r mut Vec<FollowEpsilon>, + /// The input to search. + input: I, +} + +/// A cached allocation that can be reused on each execution. +#[derive(Clone, Debug)] +pub struct Cache { + /// A pair of ordered sets for tracking NFA states. + clist: Threads, + nlist: Threads, + /// An explicit stack used for following epsilon transitions. + stack: Vec<FollowEpsilon>, +} + +/// An ordered set of NFA states and their captures. +#[derive(Clone, Debug)] +struct Threads { + /// An ordered set of opcodes (each opcode is an NFA state). + set: SparseSet, + /// Captures for every NFA state. + /// + /// It is stored in row-major order, where the columns are the capture + /// slots and the rows are the states. + caps: Vec<Slot>, + /// The number of capture slots stored per thread. (Every capture has + /// two slots.) + slots_per_thread: usize, +} + +/// A representation of an explicit stack frame when following epsilon +/// transitions. This is used to avoid recursion. +#[derive(Clone, Debug)] +enum FollowEpsilon { + /// Follow transitions at the given instruction pointer. + IP(InstPtr), + /// Restore the capture slot with the given position in the input. + Capture { slot: usize, pos: Slot }, +} + +impl Cache { + /// Create a new allocation used by the NFA machine to record execution + /// and captures. + pub fn new(_prog: &Program) -> Self { + Cache { + clist: Threads::new(), + nlist: Threads::new(), + stack: vec![], + } + } +} + +impl<'r, I: Input> Fsm<'r, I> { + /// Execute the NFA matching engine. + /// + /// If there's a match, `exec` returns `true` and populates the given + /// captures accordingly. + pub fn exec( + prog: &'r Program, + cache: &ProgramCache, + matches: &mut [bool], + slots: &mut [Slot], + quit_after_match: bool, + input: I, + start: usize, + end: usize, + ) -> bool { + let mut cache = cache.borrow_mut(); + let cache = &mut cache.pikevm; + cache.clist.resize(prog.len(), prog.captures.len()); + cache.nlist.resize(prog.len(), prog.captures.len()); + let at = input.at(start); + Fsm { + prog: prog, + stack: &mut cache.stack, + input: input, + }.exec_( + &mut cache.clist, + &mut cache.nlist, + matches, + slots, + quit_after_match, + at, + end, + ) + } + + fn exec_( + &mut self, + mut clist: &mut Threads, + mut nlist: &mut Threads, + matches: &mut [bool], + slots: &mut [Slot], + quit_after_match: bool, + mut at: InputAt, + end: usize, + ) -> bool { + let mut matched = false; + let mut all_matched = false; + clist.set.clear(); + nlist.set.clear(); +'LOOP: loop { + if clist.set.is_empty() { + // Three ways to bail out when our current set of threads is + // empty. + // + // 1. We have a match---so we're done exploring any possible + // alternatives. Time to quit. (We can't do this if we're + // looking for matches for multiple regexes, unless we know + // they all matched.) + // + // 2. If the expression starts with a '^' we can terminate as + // soon as the last thread dies. + if (matched && matches.len() <= 1) + || all_matched + || (!at.is_start() && self.prog.is_anchored_start) { + break; + } + + // 3. If there's a literal prefix for the program, try to + // jump ahead quickly. If it can't be found, then we can + // bail out early. + if !self.prog.prefixes.is_empty() { + at = match self.input.prefix_at(&self.prog.prefixes, at) { + None => break, + Some(at) => at, + }; + } + } + + // This simulates a preceding '.*?' for every regex by adding + // a state starting at the current position in the input for the + // beginning of the program only if we don't already have a match. + if clist.set.is_empty() + || (!self.prog.is_anchored_start && !all_matched) { + self.add(&mut clist, slots, 0, at); + } + // The previous call to "add" actually inspects the position just + // before the current character. For stepping through the machine, + // we can to look at the current character, so we advance the + // input. + let at_next = self.input.at(at.next_pos()); + for i in 0..clist.set.len() { + let ip = clist.set[i]; + if self.step( + &mut nlist, + matches, + slots, + clist.caps(ip), + ip, + at, + at_next, + ) { + matched = true; + all_matched = all_matched || matches.iter().all(|&b| b); + if quit_after_match { + // If we only care if a match occurs (not its + // position), then we can quit right now. + break 'LOOP; + } + if self.prog.matches.len() == 1 { + // We don't need to check the rest of the threads + // in this set because we've matched something + // ("leftmost-first"). However, we still need to check + // threads in the next set to support things like + // greedy matching. + // + // This is only true on normal regexes. For regex sets, + // we need to mush on to observe other matches. + break; + } + } + } + if at.pos() == end || at.is_end() { + break; + } + at = at_next; + mem::swap(clist, nlist); + nlist.set.clear(); + } + matched + } + + /// Step through the input, one token (byte or codepoint) at a time. + /// + /// nlist is the set of states that will be processed on the next token + /// in the input. + /// + /// caps is the set of captures passed by the caller of the NFA. They are + /// written to only when a match state is visited. + /// + /// thread_caps is the set of captures set for the current NFA state, ip. + /// + /// at and at_next are the current and next positions in the input. at or + /// at_next may be EOF. + fn step( + &mut self, + nlist: &mut Threads, + matches: &mut [bool], + slots: &mut [Slot], + thread_caps: &mut [Option<usize>], + ip: usize, + at: InputAt, + at_next: InputAt, + ) -> bool { + use prog::Inst::*; + match self.prog[ip] { + Match(match_slot) => { + if match_slot < matches.len() { + matches[match_slot] = true; + } + for (slot, val) in slots.iter_mut().zip(thread_caps.iter()) { + *slot = *val; + } + true + } + Char(ref inst) => { + if inst.c == at.char() { + self.add(nlist, thread_caps, inst.goto, at_next); + } + false + } + Ranges(ref inst) => { + if inst.matches(at.char()) { + self.add(nlist, thread_caps, inst.goto, at_next); + } + false + } + Bytes(ref inst) => { + if let Some(b) = at.byte() { + if inst.matches(b) { + self.add(nlist, thread_caps, inst.goto, at_next); + } + } + false + } + EmptyLook(_) | Save(_) | Split(_) => false, + } + } + + /// Follows epsilon transitions and adds them for processing to nlist, + /// starting at and including ip. + fn add( + &mut self, + nlist: &mut Threads, + thread_caps: &mut [Option<usize>], + ip: usize, + at: InputAt, + ) { + self.stack.push(FollowEpsilon::IP(ip)); + while let Some(frame) = self.stack.pop() { + match frame { + FollowEpsilon::IP(ip) => { + self.add_step(nlist, thread_caps, ip, at); + } + FollowEpsilon::Capture { slot, pos } => { + thread_caps[slot] = pos; + } + } + } + } + + /// A helper function for add that avoids excessive pushing to the stack. + fn add_step( + &mut self, + nlist: &mut Threads, + thread_caps: &mut [Option<usize>], + mut ip: usize, + at: InputAt, + ) { + // Instead of pushing and popping to the stack, we mutate ip as we + // traverse the set of states. We only push to the stack when we + // absolutely need recursion (restoring captures or following a + // branch). + use prog::Inst::*; + loop { + // Don't visit states we've already added. + if nlist.set.contains(ip) { + return; + } + nlist.set.insert(ip); + match self.prog[ip] { + EmptyLook(ref inst) => { + if self.input.is_empty_match(at, inst) { + ip = inst.goto; + } + } + Save(ref inst) => { + if inst.slot < thread_caps.len() { + self.stack.push(FollowEpsilon::Capture { + slot: inst.slot, + pos: thread_caps[inst.slot], + }); + thread_caps[inst.slot] = Some(at.pos()); + } + ip = inst.goto; + } + Split(ref inst) => { + self.stack.push(FollowEpsilon::IP(inst.goto2)); + ip = inst.goto1; + } + Match(_) | Char(_) | Ranges(_) | Bytes(_) => { + let t = &mut nlist.caps(ip); + for (slot, val) in t.iter_mut().zip(thread_caps.iter()) { + *slot = *val; + } + return; + } + } + } + } +} + +impl Threads { + fn new() -> Self { + Threads { + set: SparseSet::new(0), + caps: vec![], + slots_per_thread: 0, + } + } + + fn resize(&mut self, num_insts: usize, ncaps: usize) { + if num_insts == self.set.capacity() { + return; + } + self.slots_per_thread = ncaps * 2; + self.set = SparseSet::new(num_insts); + self.caps = vec![None; self.slots_per_thread * num_insts]; + } + + fn caps(&mut self, pc: usize) -> &mut [Option<usize>] { + let i = pc * self.slots_per_thread; + &mut self.caps[i..i + self.slots_per_thread] + } +} diff --git a/regex/src/prog.rs b/regex/src/prog.rs new file mode 100644 index 000000000..b62802f2b --- /dev/null +++ b/regex/src/prog.rs @@ -0,0 +1,423 @@ +use std::collections::HashMap; +use std::cmp::Ordering; +use std::fmt; +use std::ops::Deref; +use std::mem; +use std::slice; +use std::sync::Arc; + +use input::Char; +use literal::LiteralSearcher; + +/// `InstPtr` represents the index of an instruction in a regex program. +pub type InstPtr = usize; + +/// Program is a sequence of instructions and various facts about thos +/// instructions. +#[derive(Clone)] +pub struct Program { + /// A sequence of instructions that represents an NFA. + pub insts: Vec<Inst>, + /// Pointers to each Match instruction in the sequence. + /// + /// This is always length 1 unless this program represents a regex set. + pub matches: Vec<InstPtr>, + /// The ordered sequence of all capture groups extracted from the AST. + /// Unnamed groups are `None`. + pub captures: Vec<Option<String>>, + /// Pointers to all named capture groups into `captures`. + pub capture_name_idx: Arc<HashMap<String, usize>>, + /// A pointer to the start instruction. This can vary depending on how + /// the program was compiled. For example, programs for use with the DFA + /// engine have a `.*?` inserted at the beginning of unanchored regular + /// expressions. The actual starting point of the program is after the + /// `.*?`. + pub start: InstPtr, + /// A set of equivalence classes for discriminating bytes in the compiled + /// program. + pub byte_classes: Vec<u8>, + /// When true, this program can only match valid UTF-8. + pub only_utf8: bool, + /// When true, this program uses byte range instructions instead of Unicode + /// range instructions. + pub is_bytes: bool, + /// When true, the program is compiled for DFA matching. For example, this + /// implies `is_bytes` and also inserts a preceding `.*?` for unanchored + /// regexes. + pub is_dfa: bool, + /// When true, the program matches text in reverse (for use only in the + /// DFA). + pub is_reverse: bool, + /// Whether the regex must match from the start of the input. + pub is_anchored_start: bool, + /// Whether the regex must match at the end of the input. + pub is_anchored_end: bool, + /// Whether this program contains a Unicode word boundary instruction. + pub has_unicode_word_boundary: bool, + /// A possibly empty machine for very quickly matching prefix literals. + pub prefixes: LiteralSearcher, + /// A limit on the size of the cache that the DFA is allowed to use while + /// matching. + /// + /// The cache limit specifies approximately how much space we're willing to + /// give to the state cache. Once the state cache exceeds the size, it is + /// wiped and all states must be re-computed. + /// + /// Note that this value does not impact correctness. It can be set to 0 + /// and the DFA will run just fine. (It will only ever store exactly one + /// state in the cache, and will likely run very slowly, but it will work.) + /// + /// Also note that this limit is *per thread of execution*. That is, + /// if the same regex is used to search text across multiple threads + /// simultaneously, then the DFA cache is not shared. Instead, copies are + /// made. + pub dfa_size_limit: usize, +} + +impl Program { + /// Creates an empty instruction sequence. Fields are given default + /// values. + pub fn new() -> Self { + Program { + insts: vec![], + matches: vec![], + captures: vec![], + capture_name_idx: Arc::new(HashMap::new()), + start: 0, + byte_classes: vec![0; 256], + only_utf8: true, + is_bytes: false, + is_dfa: false, + is_reverse: false, + is_anchored_start: false, + is_anchored_end: false, + has_unicode_word_boundary: false, + prefixes: LiteralSearcher::empty(), + dfa_size_limit: 2 * (1<<20), + } + } + + /// If pc is an index to a no-op instruction (like Save), then return the + /// next pc that is not a no-op instruction. + pub fn skip(&self, mut pc: usize) -> usize { + loop { + match self[pc] { + Inst::Save(ref i) => pc = i.goto, + _ => return pc, + } + } + } + + /// Return true if and only if an execution engine at instruction `pc` will + /// always lead to a match. + pub fn leads_to_match(&self, pc: usize) -> bool { + if self.matches.len() > 1 { + // If we have a regex set, then we have more than one ending + // state, so leading to one of those states is generally + // meaningless. + return false; + } + match self[self.skip(pc)] { + Inst::Match(_) => true, + _ => false, + } + } + + /// Returns true if the current configuration demands that an implicit + /// `.*?` be prepended to the instruction sequence. + pub fn needs_dotstar(&self) -> bool { + self.is_dfa && !self.is_reverse && !self.is_anchored_start + } + + /// Returns true if this program uses Byte instructions instead of + /// Char/Range instructions. + pub fn uses_bytes(&self) -> bool { + self.is_bytes || self.is_dfa + } + + /// Returns true if this program exclusively matches valid UTF-8 bytes. + /// + /// That is, if an invalid UTF-8 byte is seen, then no match is possible. + pub fn only_utf8(&self) -> bool { + self.only_utf8 + } + + /// Return the approximate heap usage of this instruction sequence in + /// bytes. + pub fn approximate_size(&self) -> usize { + // The only instruction that uses heap space is Ranges (for + // Unicode codepoint programs) to store non-overlapping codepoint + // ranges. To keep this operation constant time, we ignore them. + (self.len() * mem::size_of::<Inst>()) + + (self.matches.len() * mem::size_of::<InstPtr>()) + + (self.captures.len() * mem::size_of::<Option<String>>()) + + (self.capture_name_idx.len() * + (mem::size_of::<String>() + mem::size_of::<usize>())) + + (self.byte_classes.len() * mem::size_of::<u8>()) + + self.prefixes.approximate_size() + } +} + +impl Deref for Program { + type Target = [Inst]; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &*self.insts + } +} + +impl fmt::Debug for Program { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Inst::*; + + fn with_goto(cur: usize, goto: usize, fmtd: String) -> String { + if goto == cur + 1 { + fmtd + } else { + format!("{} (goto: {})", fmtd, goto) + } + } + + fn visible_byte(b: u8) -> String { + use std::ascii::escape_default; + let escaped = escape_default(b).collect::<Vec<u8>>(); + String::from_utf8_lossy(&escaped).into_owned() + } + + for (pc, inst) in self.iter().enumerate() { + match *inst { + Match(slot) => { + write!(f, "{:04} Match({:?})", pc, slot)? + } + Save(ref inst) => { + let s = format!("{:04} Save({})", pc, inst.slot); + write!(f, "{}", with_goto(pc, inst.goto, s))?; + } + Split(ref inst) => { + write!( + f, "{:04} Split({}, {})", pc, inst.goto1, inst.goto2)?; + } + EmptyLook(ref inst) => { + let s = format!("{:?}", inst.look); + write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; + } + Char(ref inst) => { + let s = format!("{:?}", inst.c); + write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; + } + Ranges(ref inst) => { + let ranges = inst.ranges + .iter() + .map(|r| format!("{:?}-{:?}", r.0, r.1)) + .collect::<Vec<String>>() + .join(", "); + write!( + f, "{:04} {}", pc, with_goto(pc, inst.goto, ranges))?; + } + Bytes(ref inst) => { + let s = format!( + "Bytes({}, {})", + visible_byte(inst.start), + visible_byte(inst.end)); + write!(f, "{:04} {}", pc, with_goto(pc, inst.goto, s))?; + } + } + if pc == self.start { + write!(f, " (start)")?; + } + write!(f, "\n")?; + } + Ok(()) + } +} + +impl<'a> IntoIterator for &'a Program { + type Item = &'a Inst; + type IntoIter = slice::Iter<'a, Inst>; + fn into_iter(self) -> Self::IntoIter { self.iter() } +} + +/// Inst is an instruction code in a Regex program. +/// +/// Regrettably, a regex program either contains Unicode codepoint +/// instructions (Char and Ranges) or it contains byte instructions (Bytes). +/// A regex program can never contain both. +/// +/// It would be worth investigating splitting this into two distinct types and +/// then figuring out how to make the matching engines polymorphic over those +/// types without sacrificing performance. +/// +/// Other than the benefit of moving invariants into the type system, another +/// benefit is the decreased size. If we remove the `Char` and `Ranges` +/// instructions from the `Inst` enum, then its size shrinks from 40 bytes to +/// 24 bytes. (This is because of the removal of a `Vec` in the `Ranges` +/// variant.) Given that byte based machines are typically much bigger than +/// their Unicode analogues (because they can decode UTF-8 directly), this ends +/// up being a pretty significant savings. +#[derive(Clone, Debug)] +pub enum Inst { + /// Match indicates that the program has reached a match state. + /// + /// The number in the match corresponds to the Nth logical regular + /// expression in this program. This index is always 0 for normal regex + /// programs. Values greater than 0 appear when compiling regex sets, and + /// each match instruction gets its own unique value. The value corresponds + /// to the Nth regex in the set. + Match(usize), + /// Save causes the program to save the current location of the input in + /// the slot indicated by InstSave. + Save(InstSave), + /// Split causes the program to diverge to one of two paths in the + /// program, preferring goto1 in InstSplit. + Split(InstSplit), + /// EmptyLook represents a zero-width assertion in a regex program. A + /// zero-width assertion does not consume any of the input text. + EmptyLook(InstEmptyLook), + /// Char requires the regex program to match the character in InstChar at + /// the current position in the input. + Char(InstChar), + /// Ranges requires the regex program to match the character at the current + /// position in the input with one of the ranges specified in InstRanges. + Ranges(InstRanges), + /// Bytes is like Ranges, except it expresses a single byte range. It is + /// used in conjunction with Split instructions to implement multi-byte + /// character classes. + Bytes(InstBytes), +} + +impl Inst { + /// Returns true if and only if this is a match instruction. + pub fn is_match(&self) -> bool { + match *self { + Inst::Match(_) => true, + _ => false, + } + } +} + +/// Representation of the Save instruction. +#[derive(Clone, Debug)] +pub struct InstSave { + /// The next location to execute in the program. + pub goto: InstPtr, + /// The capture slot (there are two slots for every capture in a regex, + /// including the zeroth capture for the entire match). + pub slot: usize, +} + +/// Representation of the Split instruction. +#[derive(Clone, Debug)] +pub struct InstSplit { + /// The first instruction to try. A match resulting from following goto1 + /// has precedence over a match resulting from following goto2. + pub goto1: InstPtr, + /// The second instruction to try. A match resulting from following goto1 + /// has precedence over a match resulting from following goto2. + pub goto2: InstPtr, +} + +/// Representation of the `EmptyLook` instruction. +#[derive(Clone, Debug)] +pub struct InstEmptyLook { + /// The next location to execute in the program if this instruction + /// succeeds. + pub goto: InstPtr, + /// The type of zero-width assertion to check. + pub look: EmptyLook, +} + +/// The set of zero-width match instructions. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum EmptyLook { + /// Start of line or input. + StartLine, + /// End of line or input. + EndLine, + /// Start of input. + StartText, + /// End of input. + EndText, + /// Word character on one side and non-word character on other. + WordBoundary, + /// Word character on both sides or non-word character on both sides. + NotWordBoundary, + /// ASCII word boundary. + WordBoundaryAscii, + /// Not ASCII word boundary. + NotWordBoundaryAscii, +} + +/// Representation of the Char instruction. +#[derive(Clone, Debug)] +pub struct InstChar { + /// The next location to execute in the program if this instruction + /// succeeds. + pub goto: InstPtr, + /// The character to test. + pub c: char, +} + +/// Representation of the Ranges instruction. +#[derive(Clone, Debug)] +pub struct InstRanges { + /// The next location to execute in the program if this instruction + /// succeeds. + pub goto: InstPtr, + /// The set of Unicode scalar value ranges to test. + pub ranges: Vec<(char, char)>, +} + +impl InstRanges { + /// Tests whether the given input character matches this instruction. + pub fn matches(&self, c: Char) -> bool { + // This speeds up the `match_class_unicode` benchmark by checking + // some common cases quickly without binary search. e.g., Matching + // a Unicode class on predominantly ASCII text. + for r in self.ranges.iter().take(4) { + if c < r.0 { + return false; + } + if c <= r.1 { + return true; + } + } + self.ranges.binary_search_by(|r| { + if r.1 < c { + Ordering::Less + } else if r.0 > c { + Ordering::Greater + } else { + Ordering::Equal + } + }).is_ok() + } + + /// Return the number of distinct characters represented by all of the + /// ranges. + pub fn num_chars(&self) -> usize { + self.ranges.iter() + .map(|&(s, e)| 1 + (e as u32) - (s as u32)) + .fold(0, |acc, len| acc + len) + as usize + } +} + +/// Representation of the Bytes instruction. +#[derive(Clone, Debug)] +pub struct InstBytes { + /// The next location to execute in the program if this instruction + /// succeeds. + pub goto: InstPtr, + /// The start (inclusive) of this byte range. + pub start: u8, + /// The end (inclusive) of this byte range. + pub end: u8, +} + +impl InstBytes { + /// Returns true if and only if the given byte is in this range. + pub fn matches(&self, byte: u8) -> bool { + self.start <= byte && byte <= self.end + } +} diff --git a/regex/src/re_builder.rs b/regex/src/re_builder.rs new file mode 100644 index 000000000..470337f4a --- /dev/null +++ b/regex/src/re_builder.rs @@ -0,0 +1,388 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The set of user configurable options for compiling zero or more regexes. +#[derive(Clone, Debug)] +#[allow(missing_docs)] +pub struct RegexOptions { + pub pats: Vec<String>, + pub size_limit: usize, + pub dfa_size_limit: usize, + pub nest_limit: u32, + pub case_insensitive: bool, + pub multi_line: bool, + pub dot_matches_new_line: bool, + pub swap_greed: bool, + pub ignore_whitespace: bool, + pub unicode: bool, + pub octal: bool, +} + +impl Default for RegexOptions { + fn default() -> Self { + RegexOptions { + pats: vec![], + size_limit: 10 * (1<<20), + dfa_size_limit: 2 * (1<<20), + nest_limit: 250, + case_insensitive: false, + multi_line: false, + dot_matches_new_line: false, + swap_greed: false, + ignore_whitespace: false, + unicode: true, + octal: false, + } + } +} + +macro_rules! define_builder { + ($name:ident, $regex_mod:ident, $only_utf8:expr) => { + pub mod $name { + use error::Error; + use exec::ExecBuilder; + use super::RegexOptions; + + use $regex_mod::Regex; + +/// A configurable builder for a regular expression. +/// +/// A builder can be used to configure how the regex is built, for example, by +/// setting the default flags (which can be overridden in the expression +/// itself) or setting various limits. +pub struct RegexBuilder(RegexOptions); + +impl RegexBuilder { + /// Create a new regular expression builder with the given pattern. + /// + /// If the pattern is invalid, then an error will be returned when + /// `build` is called. + pub fn new(pattern: &str) -> RegexBuilder { + let mut builder = RegexBuilder(RegexOptions::default()); + builder.0.pats.push(pattern.to_owned()); + builder + } + + /// Consume the builder and compile the regular expression. + /// + /// Note that calling `as_str` on the resulting `Regex` will produce the + /// pattern given to `new` verbatim. Notably, it will not incorporate any + /// of the flags set on this builder. + pub fn build(&self) -> Result<Regex, Error> { + ExecBuilder::new_options(self.0.clone()) + .only_utf8($only_utf8) + .build() + .map(Regex::from) + } + + /// Set the value for the case insensitive (`i`) flag. + /// + /// When enabled, letters in the pattern will match both upper case and + /// lower case variants. + pub fn case_insensitive(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.case_insensitive = yes; + self + } + + /// Set the value for the multi-line matching (`m`) flag. + /// + /// When enabled, `^` matches the beginning of lines and `$` matches the + /// end of lines. + /// + /// By default, they match beginning/end of the input. + pub fn multi_line(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.multi_line = yes; + self + } + + /// Set the value for the any character (`s`) flag, where in `.` matches + /// anything when `s` is set and matches anything except for new line when + /// it is not set (the default). + /// + /// N.B. "matches anything" means "any byte" when Unicode is disabled and + /// means "any valid UTF-8 encoding of any Unicode scalar value" when + /// Unicode is enabled. + pub fn dot_matches_new_line(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.dot_matches_new_line = yes; + self + } + + /// Set the value for the greedy swap (`U`) flag. + /// + /// When enabled, a pattern like `a*` is lazy (tries to find shortest + /// match) and `a*?` is greedy (tries to find longest match). + /// + /// By default, `a*` is greedy and `a*?` is lazy. + pub fn swap_greed(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.swap_greed = yes; + self + } + + /// Set the value for the ignore whitespace (`x`) flag. + /// + /// When enabled, whitespace such as new lines and spaces will be ignored + /// between expressions of the pattern, and `#` can be used to start a + /// comment until the next new line. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.ignore_whitespace = yes; + self + } + + /// Set the value for the Unicode (`u`) flag. + /// + /// Enabled by default. When disabled, character classes such as `\w` only + /// match ASCII word characters instead of all Unicode word characters. + pub fn unicode(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.unicode = yes; + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut RegexBuilder { + self.0.octal = yes; + self + } + + /// Set the approximate size limit of the compiled regular expression. + /// + /// This roughly corresponds to the number of bytes occupied by a single + /// compiled program. If the program exceeds this number, then a + /// compilation error is returned. + pub fn size_limit(&mut self, limit: usize) -> &mut RegexBuilder { + self.0.size_limit = limit; + self + } + + /// Set the approximate size of the cache used by the DFA. + /// + /// This roughly corresponds to the number of bytes that the DFA will + /// use while searching. + /// + /// Note that this is a *per thread* limit. There is no way to set a global + /// limit. In particular, if a regex is used from multiple threads + /// simultaneously, then each thread may use up to the number of bytes + /// specified here. + pub fn dfa_size_limit(&mut self, limit: usize) -> &mut RegexBuilder { + self.0.dfa_size_limit = limit; + self + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire Ast is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// length of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut RegexBuilder { + self.0.nest_limit = limit; + self + } +} + } + } +} + +define_builder!(bytes, re_bytes, false); +define_builder!(unicode, re_unicode, true); + +macro_rules! define_set_builder { + ($name:ident, $regex_mod:ident, $only_utf8:expr) => { + pub mod $name { + use error::Error; + use exec::ExecBuilder; + use super::RegexOptions; + + use re_set::$regex_mod::RegexSet; + +/// A configurable builder for a set of regular expressions. +/// +/// A builder can be used to configure how the regexes are built, for example, +/// by setting the default flags (which can be overridden in the expression +/// itself) or setting various limits. +pub struct RegexSetBuilder(RegexOptions); + +impl RegexSetBuilder { + /// Create a new regular expression builder with the given pattern. + /// + /// If the pattern is invalid, then an error will be returned when + /// `build` is called. + pub fn new<I, S>(patterns: I) -> RegexSetBuilder + where S: AsRef<str>, I: IntoIterator<Item=S> { + let mut builder = RegexSetBuilder(RegexOptions::default()); + for pat in patterns { + builder.0.pats.push(pat.as_ref().to_owned()); + } + builder + } + + /// Consume the builder and compile the regular expressions into a set. + pub fn build(&self) -> Result<RegexSet, Error> { + ExecBuilder::new_options(self.0.clone()) + .only_utf8($only_utf8) + .build() + .map(RegexSet::from) + } + + /// Set the value for the case insensitive (`i`) flag. + pub fn case_insensitive(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.case_insensitive = yes; + self + } + + /// Set the value for the multi-line matching (`m`) flag. + pub fn multi_line(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.multi_line = yes; + self + } + + /// Set the value for the any character (`s`) flag, where in `.` matches + /// anything when `s` is set and matches anything except for new line when + /// it is not set (the default). + /// + /// N.B. "matches anything" means "any byte" for `regex::bytes::RegexSet` + /// expressions and means "any Unicode scalar value" for `regex::RegexSet` + /// expressions. + pub fn dot_matches_new_line(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.dot_matches_new_line = yes; + self + } + + /// Set the value for the greedy swap (`U`) flag. + pub fn swap_greed(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.swap_greed = yes; + self + } + + /// Set the value for the ignore whitespace (`x`) flag. + pub fn ignore_whitespace(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.ignore_whitespace = yes; + self + } + + /// Set the value for the Unicode (`u`) flag. + pub fn unicode(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.unicode = yes; + self + } + + /// Whether to support octal syntax or not. + /// + /// Octal syntax is a little-known way of uttering Unicode codepoints in + /// a regular expression. For example, `a`, `\x61`, `\u0061` and + /// `\141` are all equivalent regular expressions, where the last example + /// shows octal syntax. + /// + /// While supporting octal syntax isn't in and of itself a problem, it does + /// make good error messages harder. That is, in PCRE based regex engines, + /// syntax like `\0` invokes a backreference, which is explicitly + /// unsupported in Rust's regex engine. However, many users expect it to + /// be supported. Therefore, when octal support is disabled, the error + /// message will explicitly mention that backreferences aren't supported. + /// + /// Octal syntax is disabled by default. + pub fn octal(&mut self, yes: bool) -> &mut RegexSetBuilder { + self.0.octal = yes; + self + } + + /// Set the approximate size limit of the compiled regular expression. + /// + /// This roughly corresponds to the number of bytes occupied by a single + /// compiled program. If the program exceeds this number, then a + /// compilation error is returned. + pub fn size_limit(&mut self, limit: usize) -> &mut RegexSetBuilder { + self.0.size_limit = limit; + self + } + + /// Set the approximate size of the cache used by the DFA. + /// + /// This roughly corresponds to the number of bytes that the DFA will + /// use while searching. + /// + /// Note that this is a *per thread* limit. There is no way to set a global + /// limit. In particular, if a regex is used from multiple threads + /// simultaneously, then each thread may use up to the number of bytes + /// specified here. + pub fn dfa_size_limit(&mut self, limit: usize) -> &mut RegexSetBuilder { + self.0.dfa_size_limit = limit; + self + } + + /// Set the nesting limit for this parser. + /// + /// The nesting limit controls how deep the abstract syntax tree is allowed + /// to be. If the AST exceeds the given limit (e.g., with too many nested + /// groups), then an error is returned by the parser. + /// + /// The purpose of this limit is to act as a heuristic to prevent stack + /// overflow for consumers that do structural induction on an `Ast` using + /// explicit recursion. While this crate never does this (instead using + /// constant stack space and moving the call stack to the heap), other + /// crates may. + /// + /// This limit is not checked until the entire Ast is parsed. Therefore, + /// if callers want to put a limit on the amount of heap space used, then + /// they should impose a limit on the length, in bytes, of the concrete + /// pattern string. In particular, this is viable since this parser + /// implementation will limit itself to heap space proportional to the + /// length of the pattern string. + /// + /// Note that a nest limit of `0` will return a nest limit error for most + /// patterns but not all. For example, a nest limit of `0` permits `a` but + /// not `ab`, since `ab` requires a concatenation, which results in a nest + /// depth of `1`. In general, a nest limit is not something that manifests + /// in an obvious way in the concrete syntax, therefore, it should not be + /// used in a granular way. + pub fn nest_limit(&mut self, limit: u32) -> &mut RegexSetBuilder { + self.0.nest_limit = limit; + self + } + +} + } + } +} + +define_set_builder!(set_bytes, bytes, false); +define_set_builder!(set_unicode, unicode, true); diff --git a/regex/src/re_bytes.rs b/regex/src/re_bytes.rs new file mode 100644 index 000000000..8fdb133d4 --- /dev/null +++ b/regex/src/re_bytes.rs @@ -0,0 +1,1169 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt; +use std::ops::Index; +use std::str::FromStr; +use std::sync::Arc; + +use memchr::memchr; + +use exec::{Exec, ExecNoSync}; +use expand::expand_bytes; +use error::Error; +use re_builder::bytes::RegexBuilder; +use re_trait::{self, RegularExpression, SubCapturesPosIter}; + +/// Match represents a single match of a regex in a haystack. +/// +/// The lifetime parameter `'t` refers to the lifetime of the matched text. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Match<'t> { + text: &'t [u8], + start: usize, + end: usize, +} + +impl<'t> Match<'t> { + /// Returns the starting byte offset of the match in the haystack. + #[inline] + pub fn start(&self) -> usize { + self.start + } + + /// Returns the ending byte offset of the match in the haystack. + #[inline] + pub fn end(&self) -> usize { + self.end + } + + /// Returns the matched text. + #[inline] + pub fn as_bytes(&self) -> &'t [u8] { + &self.text[self.start..self.end] + } + + /// Creates a new match from the given haystack and byte offsets. + #[inline] + fn new(haystack: &'t [u8], start: usize, end: usize) -> Match<'t> { + Match { + text: haystack, + start: start, + end: end, + } + } +} + +/// A compiled regular expression for matching arbitrary bytes. +/// +/// It can be used to search, split or replace text. All searching is done with +/// an implicit `.*?` at the beginning and end of an expression. To force an +/// expression to match the whole string (or a prefix or a suffix), you must +/// use an anchor like `^` or `$` (or `\A` and `\z`). +/// +/// Like the `Regex` type in the parent module, matches with this regex return +/// byte offsets into the search text. **Unlike** the parent `Regex` type, +/// these byte offsets may not correspond to UTF-8 sequence boundaries since +/// the regexes in this module can match arbitrary bytes. +#[derive(Clone)] +pub struct Regex(Exec); + +impl fmt::Display for Regex { + /// Shows the original regular expression. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl fmt::Debug for Regex { + /// Shows the original regular expression. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// A constructor for Regex from an Exec. +/// +/// This is hidden because Exec isn't actually part of the public API. +#[doc(hidden)] +impl From<Exec> for Regex { + fn from(exec: Exec) -> Regex { + Regex(exec) + } +} + +impl FromStr for Regex { + type Err = Error; + + /// Attempts to parse a string into a regular expression + fn from_str(s: &str) -> Result<Regex, Error> { + Regex::new(s) + } +} + +/// Core regular expression methods. +impl Regex { + /// Compiles a regular expression. Once compiled, it can be used repeatedly + /// to search, split or replace text in a string. + /// + /// If an invalid expression is given, then an error is returned. + pub fn new(re: &str) -> Result<Regex, Error> { + RegexBuilder::new(re).build() + } + + /// Returns true if and only if the regex matches the string given. + /// + /// It is recommended to use this method if all you need to do is test + /// a match, since the underlying matching engine may be able to do less + /// work. + /// + /// # Example + /// + /// Test if some text contains at least one word with exactly 13 ASCII word + /// bytes: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let text = b"I categorically deny having triskaidekaphobia."; + /// assert!(Regex::new(r"\b\w{13}\b").unwrap().is_match(text)); + /// # } + /// ``` + pub fn is_match(&self, text: &[u8]) -> bool { + self.is_match_at(text, 0) + } + + /// Returns the start and end byte range of the leftmost-first match in + /// `text`. If no match exists, then `None` is returned. + /// + /// Note that this should only be used if you want to discover the position + /// of the match. Testing the existence of a match is faster if you use + /// `is_match`. + /// + /// # Example + /// + /// Find the start and end location of the first word with exactly 13 + /// ASCII word bytes: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let text = b"I categorically deny having triskaidekaphobia."; + /// let mat = Regex::new(r"\b\w{13}\b").unwrap().find(text).unwrap(); + /// assert_eq!((mat.start(), mat.end()), (2, 15)); + /// # } + /// ``` + pub fn find<'t>(&self, text: &'t [u8]) -> Option<Match<'t>> { + self.find_at(text, 0) + } + + /// Returns an iterator for each successive non-overlapping match in + /// `text`, returning the start and end byte indices with respect to + /// `text`. + /// + /// # Example + /// + /// Find the start and end location of every word with exactly 13 ASCII + /// word bytes: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let text = b"Retroactively relinquishing remunerations is reprehensible."; + /// for mat in Regex::new(r"\b\w{13}\b").unwrap().find_iter(text) { + /// println!("{:?}", mat); + /// } + /// # } + /// ``` + pub fn find_iter<'r, 't>(&'r self, text: &'t [u8]) -> Matches<'r, 't> { + Matches(self.0.searcher().find_iter(text)) + } + + /// Returns the capture groups corresponding to the leftmost-first + /// match in `text`. Capture group `0` always corresponds to the entire + /// match. If no match is found, then `None` is returned. + /// + /// You should only use `captures` if you need access to the location of + /// capturing group matches. Otherwise, `find` is faster for discovering + /// the location of the overall match. + /// + /// # Examples + /// + /// Say you have some text with movie names and their release years, + /// like "'Citizen Kane' (1941)". It'd be nice if we could search for text + /// looking like that, while also extracting the movie name and its release + /// year separately. + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"'([^']+)'\s+\((\d{4})\)").unwrap(); + /// let text = b"Not my favorite movie: 'Citizen Kane' (1941)."; + /// let caps = re.captures(text).unwrap(); + /// assert_eq!(caps.get(1).unwrap().as_bytes(), &b"Citizen Kane"[..]); + /// assert_eq!(caps.get(2).unwrap().as_bytes(), &b"1941"[..]); + /// assert_eq!(caps.get(0).unwrap().as_bytes(), &b"'Citizen Kane' (1941)"[..]); + /// // You can also access the groups by index using the Index notation. + /// // Note that this will panic on an invalid index. + /// assert_eq!(&caps[1], b"Citizen Kane"); + /// assert_eq!(&caps[2], b"1941"); + /// assert_eq!(&caps[0], b"'Citizen Kane' (1941)"); + /// # } + /// ``` + /// + /// Note that the full match is at capture group `0`. Each subsequent + /// capture group is indexed by the order of its opening `(`. + /// + /// We can make this example a bit clearer by using *named* capture groups: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)") + /// .unwrap(); + /// let text = b"Not my favorite movie: 'Citizen Kane' (1941)."; + /// let caps = re.captures(text).unwrap(); + /// assert_eq!(caps.name("title").unwrap().as_bytes(), b"Citizen Kane"); + /// assert_eq!(caps.name("year").unwrap().as_bytes(), b"1941"); + /// assert_eq!(caps.get(0).unwrap().as_bytes(), &b"'Citizen Kane' (1941)"[..]); + /// // You can also access the groups by name using the Index notation. + /// // Note that this will panic on an invalid group name. + /// assert_eq!(&caps["title"], b"Citizen Kane"); + /// assert_eq!(&caps["year"], b"1941"); + /// assert_eq!(&caps[0], b"'Citizen Kane' (1941)"); + /// + /// # } + /// ``` + /// + /// Here we name the capture groups, which we can access with the `name` + /// method or the `Index` notation with a `&str`. Note that the named + /// capture groups are still accessible with `get` or the `Index` notation + /// with a `usize`. + /// + /// The `0`th capture group is always unnamed, so it must always be + /// accessed with `get(0)` or `[0]`. + pub fn captures<'t>(&self, text: &'t [u8]) -> Option<Captures<'t>> { + let mut locs = self.capture_locations(); + self.captures_read_at(&mut locs, text, 0).map(move |_| Captures { + text: text, + locs: locs.0, + named_groups: self.0.capture_name_idx().clone(), + }) + } + + /// Returns an iterator over all the non-overlapping capture groups matched + /// in `text`. This is operationally the same as `find_iter`, except it + /// yields information about capturing group matches. + /// + /// # Example + /// + /// We can use this to find all movie titles and their release years in + /// some text, where the movie is formatted like "'Title' (xxxx)": + /// + /// ```rust + /// # extern crate regex; use std::str; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)") + /// .unwrap(); + /// let text = b"'Citizen Kane' (1941), 'The Wizard of Oz' (1939), 'M' (1931)."; + /// for caps in re.captures_iter(text) { + /// let title = str::from_utf8(&caps["title"]).unwrap(); + /// let year = str::from_utf8(&caps["year"]).unwrap(); + /// println!("Movie: {:?}, Released: {:?}", title, year); + /// } + /// // Output: + /// // Movie: Citizen Kane, Released: 1941 + /// // Movie: The Wizard of Oz, Released: 1939 + /// // Movie: M, Released: 1931 + /// # } + /// ``` + pub fn captures_iter<'r, 't>( + &'r self, + text: &'t [u8], + ) -> CaptureMatches<'r, 't> { + CaptureMatches(self.0.searcher().captures_iter(text)) + } + + /// Returns an iterator of substrings of `text` delimited by a match of the + /// regular expression. Namely, each element of the iterator corresponds to + /// text that *isn't* matched by the regular expression. + /// + /// This method will *not* copy the text given. + /// + /// # Example + /// + /// To split a string delimited by arbitrary amounts of spaces or tabs: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"[ \t]+").unwrap(); + /// let fields: Vec<&[u8]> = re.split(b"a b \t c\td e").collect(); + /// assert_eq!(fields, vec![ + /// &b"a"[..], &b"b"[..], &b"c"[..], &b"d"[..], &b"e"[..], + /// ]); + /// # } + /// ``` + pub fn split<'r, 't>(&'r self, text: &'t [u8]) -> Split<'r, 't> { + Split { + finder: self.find_iter(text), + last: 0, + } + } + + /// Returns an iterator of at most `limit` substrings of `text` delimited + /// by a match of the regular expression. (A `limit` of `0` will return no + /// substrings.) Namely, each element of the iterator corresponds to text + /// that *isn't* matched by the regular expression. The remainder of the + /// string that is not split will be the last element in the iterator. + /// + /// This method will *not* copy the text given. + /// + /// # Example + /// + /// Get the first two words in some text: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"\W+").unwrap(); + /// let fields: Vec<&[u8]> = re.splitn(b"Hey! How are you?", 3).collect(); + /// assert_eq!(fields, vec![&b"Hey"[..], &b"How"[..], &b"are you?"[..]]); + /// # } + /// ``` + pub fn splitn<'r, 't>( + &'r self, + text: &'t [u8], + limit: usize, + ) -> SplitN<'r, 't> { + SplitN { + splits: self.split(text), + n: limit, + } + } + + /// Replaces the leftmost-first match with the replacement provided. The + /// replacement can be a regular byte string (where `$N` and `$name` are + /// expanded to match capture groups) or a function that takes the matches' + /// `Captures` and returns the replaced byte string. + /// + /// If no match is found, then a copy of the byte string is returned + /// unchanged. + /// + /// # Replacement string syntax + /// + /// All instances of `$name` in the replacement text is replaced with the + /// corresponding capture group `name`. + /// + /// `name` may be an integer corresponding to the index of the + /// capture group (counted by order of opening parenthesis where `0` is the + /// entire match) or it can be a name (consisting of letters, digits or + /// underscores) corresponding to a named capture group. + /// + /// If `name` isn't a valid capture group (whether the name doesn't exist + /// or isn't a valid index), then it is replaced with the empty string. + /// + /// The longest possible name is used. e.g., `$1a` looks up the capture + /// group named `1a` and not the capture group at index `1`. To exert more + /// precise control over the name, use braces, e.g., `${1}a`. + /// + /// To write a literal `$` use `$$`. + /// + /// # Examples + /// + /// Note that this function is polymorphic with respect to the replacement. + /// In typical usage, this can just be a normal byte string: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new("[^01]+").unwrap(); + /// assert_eq!(re.replace(b"1078910", &b""[..]), &b"1010"[..]); + /// # } + /// ``` + /// + /// But anything satisfying the `Replacer` trait will work. For example, a + /// closure of type `|&Captures| -> Vec<u8>` provides direct access to the + /// captures corresponding to a match. This allows one to access capturing + /// group matches easily: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # use regex::bytes::Captures; fn main() { + /// let re = Regex::new(r"([^,\s]+),\s+(\S+)").unwrap(); + /// let result = re.replace(b"Springsteen, Bruce", |caps: &Captures| { + /// let mut replacement = caps[2].to_owned(); + /// replacement.push(b' '); + /// replacement.extend(&caps[1]); + /// replacement + /// }); + /// assert_eq!(result, &b"Bruce Springsteen"[..]); + /// # } + /// ``` + /// + /// But this is a bit cumbersome to use all the time. Instead, a simple + /// syntax is supported that expands `$name` into the corresponding capture + /// group. Here's the last example, but using this expansion technique + /// with named capture groups: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(?P<first>\S+)").unwrap(); + /// let result = re.replace(b"Springsteen, Bruce", &b"$first $last"[..]); + /// assert_eq!(result, &b"Bruce Springsteen"[..]); + /// # } + /// ``` + /// + /// Note that using `$2` instead of `$first` or `$1` instead of `$last` + /// would produce the same result. To write a literal `$` use `$$`. + /// + /// Sometimes the replacement string requires use of curly braces to + /// delineate a capture group replacement and surrounding literal text. + /// For example, if we wanted to join two words together with an + /// underscore: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let re = Regex::new(r"(?P<first>\w+)\s+(?P<second>\w+)").unwrap(); + /// let result = re.replace(b"deep fried", &b"${first}_$second"[..]); + /// assert_eq!(result, &b"deep_fried"[..]); + /// # } + /// ``` + /// + /// Without the curly braces, the capture group name `first_` would be + /// used, and since it doesn't exist, it would be replaced with the empty + /// string. + /// + /// Finally, sometimes you just want to replace a literal string with no + /// regard for capturing group expansion. This can be done by wrapping a + /// byte string with `NoExpand`: + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// use regex::bytes::NoExpand; + /// + /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(\S+)").unwrap(); + /// let result = re.replace(b"Springsteen, Bruce", NoExpand(b"$2 $last")); + /// assert_eq!(result, &b"$2 $last"[..]); + /// # } + /// ``` + pub fn replace<'t, R: Replacer>( + &self, + text: &'t [u8], + rep: R, + ) -> Cow<'t, [u8]> { + self.replacen(text, 1, rep) + } + + /// Replaces all non-overlapping matches in `text` with the replacement + /// provided. This is the same as calling `replacen` with `limit` set to + /// `0`. + /// + /// See the documentation for `replace` for details on how to access + /// capturing group matches in the replacement text. + pub fn replace_all<'t, R: Replacer>( + &self, + text: &'t [u8], + rep: R, + ) -> Cow<'t, [u8]> { + self.replacen(text, 0, rep) + } + + /// Replaces at most `limit` non-overlapping matches in `text` with the + /// replacement provided. If `limit` is 0, then all non-overlapping matches + /// are replaced. + /// + /// See the documentation for `replace` for details on how to access + /// capturing group matches in the replacement text. + pub fn replacen<'t, R: Replacer>( + &self, + text: &'t [u8], + limit: usize, + mut rep: R, + ) -> Cow<'t, [u8]> { + if let Some(rep) = rep.no_expansion() { + let mut it = self.find_iter(text).enumerate().peekable(); + if it.peek().is_none() { + return Cow::Borrowed(text); + } + let mut new = Vec::with_capacity(text.len()); + let mut last_match = 0; + for (i, m) in it { + if limit > 0 && i >= limit { + break + } + new.extend_from_slice(&text[last_match..m.start()]); + new.extend_from_slice(&rep); + last_match = m.end(); + } + new.extend_from_slice(&text[last_match..]); + return Cow::Owned(new); + } + + // The slower path, which we use if the replacement needs access to + // capture groups. + let mut it = self.captures_iter(text).enumerate().peekable(); + if it.peek().is_none() { + return Cow::Borrowed(text); + } + let mut new = Vec::with_capacity(text.len()); + let mut last_match = 0; + for (i, cap) in it { + if limit > 0 && i >= limit { + break + } + // unwrap on 0 is OK because captures only reports matches + let m = cap.get(0).unwrap(); + new.extend_from_slice(&text[last_match..m.start()]); + rep.replace_append(&cap, &mut new); + last_match = m.end(); + } + new.extend_from_slice(&text[last_match..]); + Cow::Owned(new) + } +} + +/// Advanced or "lower level" search methods. +impl Regex { + /// Returns the end location of a match in the text given. + /// + /// This method may have the same performance characteristics as + /// `is_match`, except it provides an end location for a match. In + /// particular, the location returned *may be shorter* than the proper end + /// of the leftmost-first match. + /// + /// # Example + /// + /// Typically, `a+` would match the entire first sequence of `a` in some + /// text, but `shortest_match` can give up as soon as it sees the first + /// `a`. + /// + /// ```rust + /// # extern crate regex; use regex::bytes::Regex; + /// # fn main() { + /// let text = b"aaaaa"; + /// let pos = Regex::new(r"a+").unwrap().shortest_match(text); + /// assert_eq!(pos, Some(1)); + /// # } + /// ``` + pub fn shortest_match(&self, text: &[u8]) -> Option<usize> { + self.shortest_match_at(text, 0) + } + + /// Returns the same as shortest_match, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn shortest_match_at( + &self, + text: &[u8], + start: usize, + ) -> Option<usize> { + self.0.searcher().shortest_match_at(text, start) + } + + /// Returns the same as is_match, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn is_match_at(&self, text: &[u8], start: usize) -> bool { + self.shortest_match_at(text, start).is_some() + } + + /// Returns the same as find, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn find_at<'t>( + &self, + text: &'t [u8], + start: usize, + ) -> Option<Match<'t>> { + self.0.searcher().find_at(text, start) + .map(|(s, e)| Match::new(text, s, e)) + } + + /// This is like `captures`, but uses + /// [`CaptureLocations`](struct.CaptureLocations.html) + /// instead of + /// [`Captures`](struct.Captures.html) in order to amortize allocations. + /// + /// To create a `CaptureLocations` value, use the + /// `Regex::capture_locations` method. + /// + /// This returns the overall match if this was successful, which is always + /// equivalence to the `0`th capture group. + pub fn captures_read<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t [u8], + ) -> Option<Match<'t>> { + self.captures_read_at(locs, text, 0) + } + + /// Returns the same as `captures_read`, but starts the search at the given + /// offset and populates the capture locations given. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn captures_read_at<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t [u8], + start: usize, + ) -> Option<Match<'t>> { + self.0 + .searcher() + .captures_read_at(&mut locs.0, text, start) + .map(|(s, e)| Match::new(text, s, e)) + } + + /// An undocumented alias for `captures_read_at`. + /// + /// The `regex-capi` crate previously used this routine, so to avoid + /// breaking that crate, we continue to provide the name as an undocumented + /// alias. + #[doc(hidden)] + pub fn read_captures_at<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t [u8], + start: usize, + ) -> Option<Match<'t>> { + self.captures_read_at(locs, text, start) + } +} + +/// Auxiliary methods. +impl Regex { + /// Returns the original string of this regex. + pub fn as_str(&self) -> &str { + &self.0.regex_strings()[0] + } + + /// Returns an iterator over the capture names. + pub fn capture_names(&self) -> CaptureNames { + CaptureNames(self.0.capture_names().iter()) + } + + /// Returns the number of captures. + pub fn captures_len(&self) -> usize { + self.0.capture_names().len() + } + + /// Returns an empty set of capture locations that can be reused in + /// multiple calls to `captures_read` or `captures_read_at`. + pub fn capture_locations(&self) -> CaptureLocations { + CaptureLocations(self.0.searcher().locations()) + } + + /// An alias for `capture_locations` to preserve backward compatibility. + /// + /// The `regex-capi` crate uses this method, so to avoid breaking that + /// crate, we continue to export it as an undocumented API. + #[doc(hidden)] + pub fn locations(&self) -> CaptureLocations { + CaptureLocations(self.0.searcher().locations()) + } +} + +/// An iterator over all non-overlapping matches for a particular string. +/// +/// The iterator yields a tuple of integers corresponding to the start and end +/// of the match. The indices are byte offsets. The iterator stops when no more +/// matches can be found. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the matched byte string. +pub struct Matches<'r, 't>(re_trait::Matches<'t, ExecNoSync<'r>>); + +impl<'r, 't> Iterator for Matches<'r, 't> { + type Item = Match<'t>; + + fn next(&mut self) -> Option<Match<'t>> { + let text = self.0.text(); + self.0.next().map(|(s, e)| Match::new(text, s, e)) + } +} + +/// An iterator that yields all non-overlapping capture groups matching a +/// particular regular expression. +/// +/// The iterator stops when no more matches can be found. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the matched byte string. +pub struct CaptureMatches<'r, 't>(re_trait::CaptureMatches<'t, ExecNoSync<'r>>); + +impl<'r, 't> Iterator for CaptureMatches<'r, 't> { + type Item = Captures<'t>; + + fn next(&mut self) -> Option<Captures<'t>> { + self.0.next().map(|locs| Captures { + text: self.0.text(), + locs: locs, + named_groups: self.0.regex().capture_name_idx().clone(), + }) + } +} + +/// Yields all substrings delimited by a regular expression match. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the byte string being split. +pub struct Split<'r, 't> { + finder: Matches<'r, 't>, + last: usize, +} + +impl<'r, 't> Iterator for Split<'r, 't> { + type Item = &'t [u8]; + + fn next(&mut self) -> Option<&'t [u8]> { + let text = self.finder.0.text(); + match self.finder.next() { + None => { + if self.last >= text.len() { + None + } else { + let s = &text[self.last..]; + self.last = text.len(); + Some(s) + } + } + Some(m) => { + let matched = &text[self.last..m.start()]; + self.last = m.end(); + Some(matched) + } + } + } +} + +/// Yields at most `N` substrings delimited by a regular expression match. +/// +/// The last substring will be whatever remains after splitting. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the byte string being split. +pub struct SplitN<'r, 't> { + splits: Split<'r, 't>, + n: usize, +} + +impl<'r, 't> Iterator for SplitN<'r, 't> { + type Item = &'t [u8]; + + fn next(&mut self) -> Option<&'t [u8]> { + if self.n == 0 { + return None + } + self.n -= 1; + if self.n == 0 { + let text = self.splits.finder.0.text(); + Some(&text[self.splits.last..]) + } else { + self.splits.next() + } + } +} + +/// An iterator over the names of all possible captures. +/// +/// `None` indicates an unnamed capture; the first element (capture 0, the +/// whole matched region) is always unnamed. +/// +/// `'r` is the lifetime of the compiled regular expression. +pub struct CaptureNames<'r>(::std::slice::Iter<'r, Option<String>>); + +impl<'r> Iterator for CaptureNames<'r> { + type Item = Option<&'r str>; + + fn next(&mut self) -> Option<Option<&'r str>> { + self.0.next().as_ref() + .map(|slot| slot.as_ref().map(|name| name.as_ref())) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +/// CaptureLocations is a low level representation of the raw offsets of each +/// submatch. +/// +/// You can think of this as a lower level +/// [`Captures`](struct.Captures.html), where this type does not support +/// named capturing groups directly and it does not borrow the text that these +/// offsets were matched on. +/// +/// Primarily, this type is useful when using the lower level `Regex` APIs +/// such as `read_captures`, which permits amortizing the allocation in which +/// capture match locations are stored. +/// +/// In order to build a value of this type, you'll need to call the +/// `capture_locations` method on the `Regex` being used to execute the search. +/// The value returned can then be reused in subsequent searches. +#[derive(Clone, Debug)] +pub struct CaptureLocations(re_trait::Locations); + +/// A type alias for `CaptureLocations` for backwards compatibility. +/// +/// Previously, we exported `CaptureLocations` as `Locations` in an +/// undocumented API. To prevent breaking that code (e.g., in `regex-capi`), +/// we continue re-exporting the same undocumented API. +#[doc(hidden)] +pub type Locations = CaptureLocations; + +impl CaptureLocations { + /// Returns the start and end positions of the Nth capture group. Returns + /// `None` if `i` is not a valid capture group or if the capture group did + /// not match anything. The positions returned are *always* byte indices + /// with respect to the original string matched. + #[inline] + pub fn get(&self, i: usize) -> Option<(usize, usize)> { + self.0.pos(i) + } + + /// Returns the total number of capturing groups. + /// + /// This is always at least `1` since every regex has at least `1` + /// capturing group that corresponds to the entire match. + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// An alias for the `get` method for backwards compatibility. + /// + /// Previously, we exported `get` as `pos` in an undocumented API. To + /// prevent breaking that code (e.g., in `regex-capi`), we continue + /// re-exporting the same undocumented API. + #[doc(hidden)] + #[inline] + pub fn pos(&self, i: usize) -> Option<(usize, usize)> { + self.get(i) + } +} + +/// Captures represents a group of captured byte strings for a single match. +/// +/// The 0th capture always corresponds to the entire match. Each subsequent +/// index corresponds to the next capture group in the regex. If a capture +/// group is named, then the matched byte string is *also* available via the +/// `name` method. (Note that the 0th capture is always unnamed and so must be +/// accessed with the `get` method.) +/// +/// Positions returned from a capture group are always byte indices. +/// +/// `'t` is the lifetime of the matched text. +pub struct Captures<'t> { + text: &'t [u8], + locs: re_trait::Locations, + named_groups: Arc<HashMap<String, usize>>, +} + +impl<'t> Captures<'t> { + /// Returns the match associated with the capture group at index `i`. If + /// `i` does not correspond to a capture group, or if the capture group + /// did not participate in the match, then `None` is returned. + /// + /// # Examples + /// + /// Get the text of the match with a default of an empty string if this + /// group didn't participate in the match: + /// + /// ```rust + /// # use regex::bytes::Regex; + /// let re = Regex::new(r"[a-z]+(?:([0-9]+)|([A-Z]+))").unwrap(); + /// let caps = re.captures(b"abc123").unwrap(); + /// + /// let text1 = caps.get(1).map_or(&b""[..], |m| m.as_bytes()); + /// let text2 = caps.get(2).map_or(&b""[..], |m| m.as_bytes()); + /// assert_eq!(text1, &b"123"[..]); + /// assert_eq!(text2, &b""[..]); + /// ``` + pub fn get(&self, i: usize) -> Option<Match<'t>> { + self.locs.pos(i).map(|(s, e)| Match::new(self.text, s, e)) + } + + /// Returns the match for the capture group named `name`. If `name` isn't a + /// valid capture group or didn't match anything, then `None` is returned. + pub fn name(&self, name: &str) -> Option<Match<'t>> { + self.named_groups.get(name).and_then(|&i| self.get(i)) + } + + /// An iterator that yields all capturing matches in the order in which + /// they appear in the regex. If a particular capture group didn't + /// participate in the match, then `None` is yielded for that capture. + /// + /// The first match always corresponds to the overall match of the regex. + pub fn iter<'c>(&'c self) -> SubCaptureMatches<'c, 't> { + SubCaptureMatches { + caps: self, + it: self.locs.iter(), + } + } + + /// Expands all instances of `$name` in `replacement` to the corresponding + /// capture group `name`, and writes them to the `dst` buffer given. + /// + /// `name` may be an integer corresponding to the index of the + /// capture group (counted by order of opening parenthesis where `0` is the + /// entire match) or it can be a name (consisting of letters, digits or + /// underscores) corresponding to a named capture group. + /// + /// If `name` isn't a valid capture group (whether the name doesn't exist + /// or isn't a valid index), then it is replaced with the empty string. + /// + /// The longest possible name is used. e.g., `$1a` looks up the capture + /// group named `1a` and not the capture group at index `1`. To exert more + /// precise control over the name, use braces, e.g., `${1}a`. + /// + /// To write a literal `$` use `$$`. + pub fn expand(&self, replacement: &[u8], dst: &mut Vec<u8>) { + expand_bytes(self, replacement, dst) + } + + /// Returns the number of captured groups. + /// + /// This is always at least `1`, since every regex has at least one capture + /// group that corresponds to the full match. + #[inline] + pub fn len(&self) -> usize { + self.locs.len() + } +} + +impl<'t> fmt::Debug for Captures<'t> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Captures").field(&CapturesDebug(self)).finish() + } +} + +struct CapturesDebug<'c, 't: 'c>(&'c Captures<'t>); + +impl<'c, 't> fmt::Debug for CapturesDebug<'c, 't> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn escape_bytes(bytes: &[u8]) -> String { + let mut s = String::new(); + for &b in bytes { + s.push_str(&escape_byte(b)); + } + s + } + + fn escape_byte(byte: u8) -> String { + use std::ascii::escape_default; + + let escaped: Vec<u8> = escape_default(byte).collect(); + String::from_utf8_lossy(&escaped).into_owned() + } + + // We'd like to show something nice here, even if it means an + // allocation to build a reverse index. + let slot_to_name: HashMap<&usize, &String> = + self.0.named_groups.iter().map(|(a, b)| (b, a)).collect(); + let mut map = f.debug_map(); + for (slot, m) in self.0.locs.iter().enumerate() { + let m = m.map(|(s, e)| escape_bytes(&self.0.text[s..e])); + if let Some(name) = slot_to_name.get(&slot) { + map.entry(&name, &m); + } else { + map.entry(&slot, &m); + } + } + map.finish() + } +} + +/// Get a group by index. +/// +/// `'t` is the lifetime of the matched text. +/// +/// The text can't outlive the `Captures` object if this method is +/// used, because of how `Index` is defined (normally `a[i]` is part +/// of `a` and can't outlive it); to do that, use `get()` instead. +/// +/// # Panics +/// +/// If there is no group at the given index. +impl<'t> Index<usize> for Captures<'t> { + type Output = [u8]; + + fn index(&self, i: usize) -> &[u8] { + self.get(i).map(|m| m.as_bytes()) + .unwrap_or_else(|| panic!("no group at index '{}'", i)) + } +} + +/// Get a group by name. +/// +/// `'t` is the lifetime of the matched text and `'i` is the lifetime +/// of the group name (the index). +/// +/// The text can't outlive the `Captures` object if this method is +/// used, because of how `Index` is defined (normally `a[i]` is part +/// of `a` and can't outlive it); to do that, use `name` instead. +/// +/// # Panics +/// +/// If there is no group named by the given value. +impl<'t, 'i> Index<&'i str> for Captures<'t> { + type Output = [u8]; + + fn index<'a>(&'a self, name: &'i str) -> &'a [u8] { + self.name(name).map(|m| m.as_bytes()) + .unwrap_or_else(|| panic!("no group named '{}'", name)) + } +} + +/// An iterator that yields all capturing matches in the order in which they +/// appear in the regex. +/// +/// If a particular capture group didn't participate in the match, then `None` +/// is yielded for that capture. The first match always corresponds to the +/// overall match of the regex. +/// +/// The lifetime `'c` corresponds to the lifetime of the `Captures` value, and +/// the lifetime `'t` corresponds to the originally matched text. +pub struct SubCaptureMatches<'c, 't: 'c> { + caps: &'c Captures<'t>, + it: SubCapturesPosIter<'c>, +} + +impl<'c, 't> Iterator for SubCaptureMatches<'c, 't> { + type Item = Option<Match<'t>>; + + fn next(&mut self) -> Option<Option<Match<'t>>> { + self.it.next() + .map(|cap| cap.map(|(s, e)| Match::new(self.caps.text, s, e))) + } +} + +/// Replacer describes types that can be used to replace matches in a byte +/// string. +/// +/// In general, users of this crate shouldn't need to implement this trait, +/// since implementations are already provided for `&[u8]` and +/// `FnMut(&Captures) -> Vec<u8>` (or any `FnMut(&Captures) -> T` +/// where `T: AsRef<[u8]>`), which covers most use cases. +pub trait Replacer { + /// Appends text to `dst` to replace the current match. + /// + /// The current match is represented by `caps`, which is guaranteed to + /// have a match at capture group `0`. + /// + /// For example, a no-op replacement would be + /// `dst.extend(&caps[0])`. + fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>); + + /// Return a fixed unchanging replacement byte string. + /// + /// When doing replacements, if access to `Captures` is not needed (e.g., + /// the replacement byte string does not need `$` expansion), then it can + /// be beneficial to avoid finding sub-captures. + /// + /// In general, this is called once for every call to `replacen`. + fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, [u8]>> { + None + } + + /// Return a `Replacer` that borrows and wraps this `Replacer`. + /// + /// This is useful when you want to take a generic `Replacer` (which might + /// not be cloneable) and use it without consuming it, so it can be used + /// more than once. + /// + /// # Example + /// + /// ``` + /// use regex::bytes::{Regex, Replacer}; + /// + /// fn replace_all_twice<R: Replacer>( + /// re: Regex, + /// src: &[u8], + /// mut rep: R, + /// ) -> Vec<u8> { + /// let dst = re.replace_all(src, rep.by_ref()); + /// let dst = re.replace_all(&dst, rep.by_ref()); + /// dst.into_owned() + /// } + /// ``` + fn by_ref<'r>(&'r mut self) -> ReplacerRef<'r, Self> { + ReplacerRef(self) + } +} + +/// By-reference adaptor for a `Replacer` +/// +/// Returned by [`Replacer::by_ref`](trait.Replacer.html#method.by_ref). +#[derive(Debug)] +pub struct ReplacerRef<'a, R: ?Sized + 'a>(&'a mut R); + +impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> { + fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) { + self.0.replace_append(caps, dst) + } + fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, [u8]>> { + self.0.no_expansion() + } +} + +impl<'a> Replacer for &'a [u8] { + fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) { + caps.expand(*self, dst); + } + + fn no_expansion(&mut self) -> Option<Cow<[u8]>> { + match memchr(b'$', *self) { + Some(_) => None, + None => Some(Cow::Borrowed(*self)), + } + } +} + +impl<F, T> Replacer for F where F: FnMut(&Captures) -> T, T: AsRef<[u8]> { + fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) { + dst.extend_from_slice((*self)(caps).as_ref()); + } +} + +/// `NoExpand` indicates literal byte string replacement. +/// +/// It can be used with `replace` and `replace_all` to do a literal byte string +/// replacement without expanding `$name` to their corresponding capture +/// groups. This can be both convenient (to avoid escaping `$`, for example) +/// and performant (since capture groups don't need to be found). +/// +/// `'t` is the lifetime of the literal text. +pub struct NoExpand<'t>(pub &'t [u8]); + +impl<'t> Replacer for NoExpand<'t> { + fn replace_append(&mut self, _: &Captures, dst: &mut Vec<u8>) { + dst.extend_from_slice(self.0); + } + + fn no_expansion(&mut self) -> Option<Cow<[u8]>> { + Some(Cow::Borrowed(self.0)) + } +} diff --git a/regex/src/re_set.rs b/regex/src/re_set.rs new file mode 100644 index 000000000..a9a6de3a2 --- /dev/null +++ b/regex/src/re_set.rs @@ -0,0 +1,462 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! define_set { + ($name:ident, $builder_mod:ident, $text_ty:ty, $as_bytes:expr, + $(#[$doc_regexset_example:meta])* ) => { + pub mod $name { + use std::fmt; + use std::iter; + use std::slice; + use std::vec; + + use error::Error; + use exec::Exec; + use re_builder::$builder_mod::RegexSetBuilder; + use re_trait::RegularExpression; + +/// Match multiple (possibly overlapping) regular expressions in a single scan. +/// +/// A regex set corresponds to the union of two or more regular expressions. +/// That is, a regex set will match text where at least one of its +/// constituent regular expressions matches. A regex set as its formulated here +/// provides a touch more power: it will also report *which* regular +/// expressions in the set match. Indeed, this is the key difference between +/// regex sets and a single `Regex` with many alternates, since only one +/// alternate can match at a time. +/// +/// For example, consider regular expressions to match email addresses and +/// domains: `[a-z]+@[a-z]+\.(com|org|net)` and `[a-z]+\.(com|org|net)`. If a +/// regex set is constructed from those regexes, then searching the text +/// `foo@example.com` will report both regexes as matching. Of course, one +/// could accomplish this by compiling each regex on its own and doing two +/// searches over the text. The key advantage of using a regex set is that it +/// will report the matching regexes using a *single pass through the text*. +/// If one has hundreds or thousands of regexes to match repeatedly (like a URL +/// router for a complex web application or a user agent matcher), then a regex +/// set can realize huge performance gains. +/// +/// # Example +/// +/// This shows how the above two regexes (for matching email addresses and +/// domains) might work: +/// +$(#[$doc_regexset_example])* +/// +/// Note that it would be possible to adapt the above example to using `Regex` +/// with an expression like: +/// +/// ```ignore +/// (?P<email>[a-z]+@(?P<email_domain>[a-z]+[.](com|org|net)))|(?P<domain>[a-z]+[.](com|org|net)) +/// ``` +/// +/// After a match, one could then inspect the capture groups to figure out +/// which alternates matched. The problem is that it is hard to make this +/// approach scale when there are many regexes since the overlap between each +/// alternate isn't always obvious to reason about. +/// +/// # Limitations +/// +/// Regex sets are limited to answering the following two questions: +/// +/// 1. Does any regex in the set match? +/// 2. If so, which regexes in the set match? +/// +/// As with the main `Regex` type, it is cheaper to ask (1) instead of (2) +/// since the matching engines can stop after the first match is found. +/// +/// Other features like finding the location of successive matches or their +/// sub-captures aren't supported. If you need this functionality, the +/// recommended approach is to compile each regex in the set independently and +/// selectively match them based on which regexes in the set matched. +/// +/// # Performance +/// +/// A `RegexSet` has the same performance characteristics as `Regex`. Namely, +/// search takes `O(mn)` time, where `m` is proportional to the size of the +/// regex set and `n` is proportional to the length of the search text. +#[derive(Clone)] +pub struct RegexSet(Exec); + +impl RegexSet { + /// Create a new regex set with the given regular expressions. + /// + /// This takes an iterator of `S`, where `S` is something that can produce + /// a `&str`. If any of the strings in the iterator are not valid regular + /// expressions, then an error is returned. + /// + /// # Example + /// + /// Create a new regex set from an iterator of strings: + /// + /// ```rust + /// # use regex::RegexSet; + /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap(); + /// assert!(set.is_match("foo")); + /// ``` + pub fn new<I, S>(exprs: I) -> Result<RegexSet, Error> + where S: AsRef<str>, I: IntoIterator<Item=S> { + RegexSetBuilder::new(exprs).build() + } + + /// Returns true if and only if one of the regexes in this set matches + /// the text given. + /// + /// This method should be preferred if you only need to test whether any + /// of the regexes in the set should match, but don't care about *which* + /// regexes matched. This is because the underlying matching engine will + /// quit immediately after seeing the first match instead of continuing to + /// find all matches. + /// + /// Note that as with searches using `Regex`, the expression is unanchored + /// by default. That is, if the regex does not start with `^` or `\A`, or + /// end with `$` or `\z`, then it is permitted to match anywhere in the + /// text. + /// + /// # Example + /// + /// Tests whether a set matches some text: + /// + /// ```rust + /// # use regex::RegexSet; + /// let set = RegexSet::new(&[r"\w+", r"\d+"]).unwrap(); + /// assert!(set.is_match("foo")); + /// assert!(!set.is_match("☃")); + /// ``` + pub fn is_match(&self, text: $text_ty) -> bool { + self.is_match_at(text, 0) + } + + /// Returns the same as is_match, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + #[doc(hidden)] + pub fn is_match_at(&self, text: $text_ty, start: usize) -> bool { + self.0.searcher().is_match_at($as_bytes(text), start) + } + + /// Returns the set of regular expressions that match in the given text. + /// + /// The set returned contains the index of each regular expression that + /// matches in the given text. The index is in correspondence with the + /// order of regular expressions given to `RegexSet`'s constructor. + /// + /// The set can also be used to iterate over the matched indices. + /// + /// Note that as with searches using `Regex`, the expression is unanchored + /// by default. That is, if the regex does not start with `^` or `\A`, or + /// end with `$` or `\z`, then it is permitted to match anywhere in the + /// text. + /// + /// # Example + /// + /// Tests which regular expressions match the given text: + /// + /// ```rust + /// # use regex::RegexSet; + /// let set = RegexSet::new(&[ + /// r"\w+", + /// r"\d+", + /// r"\pL+", + /// r"foo", + /// r"bar", + /// r"barfoo", + /// r"foobar", + /// ]).unwrap(); + /// let matches: Vec<_> = set.matches("foobar").into_iter().collect(); + /// assert_eq!(matches, vec![0, 2, 3, 4, 6]); + /// + /// // You can also test whether a particular regex matched: + /// let matches = set.matches("foobar"); + /// assert!(!matches.matched(5)); + /// assert!(matches.matched(6)); + /// ``` + pub fn matches(&self, text: $text_ty) -> SetMatches { + let mut matches = vec![false; self.0.regex_strings().len()]; + let any = self.read_matches_at(&mut matches, text, 0); + SetMatches { + matched_any: any, + matches: matches, + } + } + + /// Returns the same as matches, but starts the search at the given + /// offset and stores the matches into the slice given. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + /// + /// `matches` must have a length that is at least the number of regexes + /// in this set. + /// + /// This method returns true if and only if at least one member of + /// `matches` is true after executing the set against `text`. + #[doc(hidden)] + pub fn read_matches_at( + &self, + matches: &mut [bool], + text: $text_ty, + start: usize, + ) -> bool { + self.0.searcher().many_matches_at(matches, $as_bytes(text), start) + } + + /// Returns the total number of regular expressions in this set. + pub fn len(&self) -> usize { + self.0.regex_strings().len() + } + + /// Returns the patterns that this set will match on. + /// + /// This function can be used to determine the pattern for a match. The + /// slice returned has exactly as many patterns givens to this regex set, + /// and the order of the slice is the same as the order of the patterns + /// provided to the set. + /// + /// # Example + /// + /// ```rust + /// # use regex::RegexSet; + /// let set = RegexSet::new(&[ + /// r"\w+", + /// r"\d+", + /// r"\pL+", + /// r"foo", + /// r"bar", + /// r"barfoo", + /// r"foobar", + /// ]).unwrap(); + /// let matches: Vec<_> = set + /// .matches("foobar") + /// .into_iter() + /// .map(|match_idx| &set.patterns()[match_idx]) + /// .collect(); + /// assert_eq!(matches, vec![r"\w+", r"\pL+", r"foo", r"bar", r"foobar"]); + /// ``` + pub fn patterns(&self) -> &[String] { + self.0.regex_strings() + } +} + +/// A set of matches returned by a regex set. +#[derive(Clone, Debug)] +pub struct SetMatches { + matched_any: bool, + matches: Vec<bool>, +} + +impl SetMatches { + /// Whether this set contains any matches. + pub fn matched_any(&self) -> bool { + self.matched_any + } + + /// Whether the regex at the given index matched. + /// + /// The index for a regex is determined by its insertion order upon the + /// initial construction of a `RegexSet`, starting at `0`. + /// + /// # Panics + /// + /// If `regex_index` is greater than or equal to `self.len()`. + pub fn matched(&self, regex_index: usize) -> bool { + self.matches[regex_index] + } + + /// The total number of regexes in the set that created these matches. + pub fn len(&self) -> usize { + self.matches.len() + } + + /// Returns an iterator over indexes in the regex that matched. + /// + /// This will always produces matches in ascending order of index, where + /// the index corresponds to the index of the regex that matched with + /// respect to its position when initially building the set. + pub fn iter(&self) -> SetMatchesIter { + SetMatchesIter((&*self.matches).into_iter().enumerate()) + } +} + +impl IntoIterator for SetMatches { + type IntoIter = SetMatchesIntoIter; + type Item = usize; + + fn into_iter(self) -> Self::IntoIter { + SetMatchesIntoIter(self.matches.into_iter().enumerate()) + } +} + +impl<'a> IntoIterator for &'a SetMatches { + type IntoIter = SetMatchesIter<'a>; + type Item = usize; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// An owned iterator over the set of matches from a regex set. +/// +/// This will always produces matches in ascending order of index, where the +/// index corresponds to the index of the regex that matched with respect to +/// its position when initially building the set. +pub struct SetMatchesIntoIter(iter::Enumerate<vec::IntoIter<bool>>); + +impl Iterator for SetMatchesIntoIter { + type Item = usize; + + fn next(&mut self) -> Option<usize> { + loop { + match self.0.next() { + None => return None, + Some((_, false)) => {} + Some((i, true)) => return Some(i), + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl DoubleEndedIterator for SetMatchesIntoIter { + fn next_back(&mut self) -> Option<usize> { + loop { + match self.0.next_back() { + None => return None, + Some((_, false)) => {} + Some((i, true)) => return Some(i), + } + } + } +} + +/// A borrowed iterator over the set of matches from a regex set. +/// +/// The lifetime `'a` refers to the lifetime of a `SetMatches` value. +/// +/// This will always produces matches in ascending order of index, where the +/// index corresponds to the index of the regex that matched with respect to +/// its position when initially building the set. +#[derive(Clone)] +pub struct SetMatchesIter<'a>(iter::Enumerate<slice::Iter<'a, bool>>); + +impl<'a> Iterator for SetMatchesIter<'a> { + type Item = usize; + + fn next(&mut self) -> Option<usize> { + loop { + match self.0.next() { + None => return None, + Some((_, &false)) => {} + Some((i, &true)) => return Some(i), + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +impl<'a> DoubleEndedIterator for SetMatchesIter<'a> { + fn next_back(&mut self) -> Option<usize> { + loop { + match self.0.next_back() { + None => return None, + Some((_, &false)) => {} + Some((i, &true)) => return Some(i), + } + } + } +} + +#[doc(hidden)] +impl From<Exec> for RegexSet { + fn from(exec: Exec) -> Self { + RegexSet(exec) + } +} + +impl fmt::Debug for RegexSet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RegexSet({:?})", self.0.regex_strings()) + } +} + +#[allow(dead_code)] fn as_bytes_str(text: &str) -> &[u8] { text.as_bytes() } +#[allow(dead_code)] fn as_bytes_bytes(text: &[u8]) -> &[u8] { text } + } + } +} + +define_set! { + unicode, + set_unicode, + &str, + as_bytes_str, +/// ```rust +/// # use regex::RegexSet; +/// let set = RegexSet::new(&[ +/// r"[a-z]+@[a-z]+\.(com|org|net)", +/// r"[a-z]+\.(com|org|net)", +/// ]).unwrap(); +/// +/// // Ask whether any regexes in the set match. +/// assert!(set.is_match("foo@example.com")); +/// +/// // Identify which regexes in the set match. +/// let matches: Vec<_> = set.matches("foo@example.com").into_iter().collect(); +/// assert_eq!(vec![0, 1], matches); +/// +/// // Try again, but with text that only matches one of the regexes. +/// let matches: Vec<_> = set.matches("example.com").into_iter().collect(); +/// assert_eq!(vec![1], matches); +/// +/// // Try again, but with text that doesn't match any regex in the set. +/// let matches: Vec<_> = set.matches("example").into_iter().collect(); +/// assert!(matches.is_empty()); +/// ``` +} + +define_set! { + bytes, + set_bytes, + &[u8], + as_bytes_bytes, +/// ```rust +/// # use regex::bytes::RegexSet; +/// let set = RegexSet::new(&[ +/// r"[a-z]+@[a-z]+\.(com|org|net)", +/// r"[a-z]+\.(com|org|net)", +/// ]).unwrap(); +/// +/// // Ask whether any regexes in the set match. +/// assert!(set.is_match(b"foo@example.com")); +/// +/// // Identify which regexes in the set match. +/// let matches: Vec<_> = set.matches(b"foo@example.com").into_iter().collect(); +/// assert_eq!(vec![0, 1], matches); +/// +/// // Try again, but with text that only matches one of the regexes. +/// let matches: Vec<_> = set.matches(b"example.com").into_iter().collect(); +/// assert_eq!(vec![1], matches); +/// +/// // Try again, but with text that doesn't match any regex in the set. +/// let matches: Vec<_> = set.matches(b"example").into_iter().collect(); +/// assert!(matches.is_empty()); +/// ``` +} diff --git a/regex/src/re_trait.rs b/regex/src/re_trait.rs new file mode 100644 index 000000000..81a64bb25 --- /dev/null +++ b/regex/src/re_trait.rs @@ -0,0 +1,268 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Slot is a single saved capture location. Note that there are two slots for +/// every capture in a regular expression (one slot each for the start and end +/// of the capture). +pub type Slot = Option<usize>; + +/// Locations represents the offsets of each capturing group in a regex for +/// a single match. +/// +/// Unlike `Captures`, a `Locations` value only stores offsets. +#[doc(hidden)] +#[derive(Clone, Debug)] +pub struct Locations(Vec<Slot>); + +impl Locations { + /// Returns the start and end positions of the Nth capture group. Returns + /// `None` if `i` is not a valid capture group or if the capture group did + /// not match anything. The positions returned are *always* byte indices + /// with respect to the original string matched. + pub fn pos(&self, i: usize) -> Option<(usize, usize)> { + let (s, e) = (i * 2, i * 2 + 1); + match (self.0.get(s), self.0.get(e)) { + (Some(&Some(s)), Some(&Some(e))) => Some((s, e)), + _ => None, + } + } + + /// Creates an iterator of all the capture group positions in order of + /// appearance in the regular expression. Positions are byte indices + /// in terms of the original string matched. + pub fn iter(&self) -> SubCapturesPosIter { + SubCapturesPosIter { idx: 0, locs: self } + } + + /// Returns the total number of capturing groups. + /// + /// This is always at least `1` since every regex has at least `1` + /// capturing group that corresponds to the entire match. + pub fn len(&self) -> usize { + self.0.len() / 2 + } + + /// Return the individual slots as a slice. + pub(crate) fn as_slots(&mut self) -> &mut [Slot] { + &mut self.0 + } +} + +/// An iterator over capture group positions for a particular match of a +/// regular expression. +/// +/// Positions are byte indices in terms of the original string matched. +/// +/// `'c` is the lifetime of the captures. +pub struct SubCapturesPosIter<'c> { + idx: usize, + locs: &'c Locations, +} + +impl<'c> Iterator for SubCapturesPosIter<'c> { + type Item = Option<(usize, usize)>; + + fn next(&mut self) -> Option<Option<(usize, usize)>> { + if self.idx >= self.locs.len() { + return None; + } + let x = match self.locs.pos(self.idx) { + None => Some(None), + Some((s, e)) => { + Some(Some((s, e))) + } + }; + self.idx += 1; + x + } +} + +/// `RegularExpression` describes types that can implement regex searching. +/// +/// This trait is my attempt at reducing code duplication and to standardize +/// the internal API. Specific duplication that is avoided are the `find` +/// and `capture` iterators, which are slightly tricky. +/// +/// It's not clear whether this trait is worth it, and it also isn't +/// clear whether it's useful as a public trait or not. Methods like +/// `next_after_empty` reak of bad design, but the rest of the methods seem +/// somewhat reasonable. One particular thing this trait would expose would be +/// the ability to start the search of a regex anywhere in a haystack, which +/// isn't possible in the current public API. +pub trait RegularExpression: Sized { + /// The type of the haystack. + type Text: ?Sized; + + /// The number of capture slots in the compiled regular expression. This is + /// always two times the number of capture groups (two slots per group). + fn slots_len(&self) -> usize; + + /// Allocates fresh space for all capturing groups in this regex. + fn locations(&self) -> Locations { + Locations(vec![None; self.slots_len()]) + } + + /// Returns the position of the next character after `i`. + /// + /// For example, a haystack with type `&[u8]` probably returns `i+1`, + /// whereas a haystack with type `&str` probably returns `i` plus the + /// length of the next UTF-8 sequence. + fn next_after_empty(&self, text: &Self::Text, i: usize) -> usize; + + /// Returns the location of the shortest match. + fn shortest_match_at( + &self, + text: &Self::Text, + start: usize, + ) -> Option<usize>; + + /// Returns whether the regex matches the text given. + fn is_match_at( + &self, + text: &Self::Text, + start: usize, + ) -> bool; + + /// Returns the leftmost-first match location if one exists. + fn find_at( + &self, + text: &Self::Text, + start: usize, + ) -> Option<(usize, usize)>; + + /// Returns the leftmost-first match location if one exists, and also + /// fills in any matching capture slot locations. + fn captures_read_at( + &self, + locs: &mut Locations, + text: &Self::Text, + start: usize, + ) -> Option<(usize, usize)>; + + /// Returns an iterator over all non-overlapping successive leftmost-first + /// matches. + fn find_iter ( + self, + text: &Self::Text, + ) -> Matches<Self> { + Matches { + re: self, + text: text, + last_end: 0, + last_match: None, + } + } + + /// Returns an iterator over all non-overlapping successive leftmost-first + /// matches with captures. + fn captures_iter( + self, + text: &Self::Text, + ) -> CaptureMatches<Self> { + CaptureMatches(self.find_iter(text)) + } +} + +/// An iterator over all non-overlapping successive leftmost-first matches. +pub struct Matches<'t, R> where R: RegularExpression, R::Text: 't { + re: R, + text: &'t R::Text, + last_end: usize, + last_match: Option<usize>, +} + +impl<'t, R> Matches<'t, R> where R: RegularExpression, R::Text: 't { + /// Return the text being searched. + pub fn text(&self) -> &'t R::Text { + self.text + } + + /// Return the underlying regex. + pub fn regex(&self) -> &R { + &self.re + } +} + +impl<'t, R> Iterator for Matches<'t, R> + where R: RegularExpression, R::Text: 't + AsRef<[u8]> { + type Item = (usize, usize); + + fn next(&mut self) -> Option<(usize, usize)> { + if self.last_end > self.text.as_ref().len() { + return None; + } + let (s, e) = match self.re.find_at(self.text, self.last_end) { + None => return None, + Some((s, e)) => (s, e), + }; + if s == e { + // This is an empty match. To ensure we make progress, start + // the next search at the smallest possible starting position + // of the next match following this one. + self.last_end = self.re.next_after_empty(self.text, e); + // Don't accept empty matches immediately following a match. + // Just move on to the next match. + if Some(e) == self.last_match { + return self.next(); + } + } else { + self.last_end = e; + } + self.last_match = Some(e); + Some((s, e)) + } +} + +/// An iterator over all non-overlapping successive leftmost-first matches with +/// captures. +pub struct CaptureMatches<'t, R>(Matches<'t, R>) + where R: RegularExpression, R::Text: 't; + +impl<'t, R> CaptureMatches<'t, R> where R: RegularExpression, R::Text: 't { + /// Return the text being searched. + pub fn text(&self) -> &'t R::Text { + self.0.text() + } + + /// Return the underlying regex. + pub fn regex(&self) -> &R { + self.0.regex() + } +} + +impl<'t, R> Iterator for CaptureMatches<'t, R> + where R: RegularExpression, R::Text: 't + AsRef<[u8]> { + type Item = Locations; + + fn next(&mut self) -> Option<Locations> { + if self.0.last_end > self.0.text.as_ref().len() { + return None + } + let mut locs = self.0.re.locations(); + let (s, e) = match self.0.re.captures_read_at( + &mut locs, + self.0.text, + self.0.last_end, + ) { + None => return None, + Some((s, e)) => (s, e), + }; + if s == e { + self.0.last_end = self.0.re.next_after_empty(self.0.text, e); + if Some(e) == self.0.last_match { + return self.next(); + } + } else { + self.0.last_end = e; + } + self.0.last_match = Some(e); + Some(locs) + } +} diff --git a/regex/src/re_unicode.rs b/regex/src/re_unicode.rs new file mode 100644 index 000000000..f71e7f503 --- /dev/null +++ b/regex/src/re_unicode.rs @@ -0,0 +1,1211 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Cow; +use std::collections::HashMap; +use std::fmt; +use std::ops::Index; +use std::str::FromStr; +use std::sync::Arc; + +use memchr::memchr; +use syntax; + +use error::Error; +use exec::{Exec, ExecNoSyncStr}; +use expand::expand_str; +use re_builder::unicode::RegexBuilder; +use re_trait::{self, RegularExpression, SubCapturesPosIter}; + +/// Escapes all regular expression meta characters in `text`. +/// +/// The string returned may be safely used as a literal in a regular +/// expression. +pub fn escape(text: &str) -> String { + syntax::escape(text) +} + +/// Match represents a single match of a regex in a haystack. +/// +/// The lifetime parameter `'t` refers to the lifetime of the matched text. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Match<'t> { + text: &'t str, + start: usize, + end: usize, +} + +impl<'t> Match<'t> { + /// Returns the starting byte offset of the match in the haystack. + #[inline] + pub fn start(&self) -> usize { + self.start + } + + /// Returns the ending byte offset of the match in the haystack. + #[inline] + pub fn end(&self) -> usize { + self.end + } + + /// Returns the matched text. + #[inline] + pub fn as_str(&self) -> &'t str { + &self.text[self.start..self.end] + } + + /// Creates a new match from the given haystack and byte offsets. + #[inline] + fn new(haystack: &'t str, start: usize, end: usize) -> Match<'t> { + Match { + text: haystack, + start: start, + end: end, + } + } +} + +impl<'t> From<Match<'t>> for &'t str { + fn from(m: Match<'t>) -> &'t str { + m.as_str() + } +} + +/// A compiled regular expression for matching Unicode strings. +/// +/// It is represented as either a sequence of bytecode instructions (dynamic) +/// or as a specialized Rust function (native). It can be used to search, split +/// or replace text. All searching is done with an implicit `.*?` at the +/// beginning and end of an expression. To force an expression to match the +/// whole string (or a prefix or a suffix), you must use an anchor like `^` or +/// `$` (or `\A` and `\z`). +/// +/// While this crate will handle Unicode strings (whether in the regular +/// expression or in the search text), all positions returned are **byte +/// indices**. Every byte index is guaranteed to be at a Unicode code point +/// boundary. +/// +/// The lifetimes `'r` and `'t` in this crate correspond to the lifetime of a +/// compiled regular expression and text to search, respectively. +/// +/// The only methods that allocate new strings are the string replacement +/// methods. All other methods (searching and splitting) return borrowed +/// pointers into the string given. +/// +/// # Examples +/// +/// Find the location of a US phone number: +/// +/// ```rust +/// # use regex::Regex; +/// let re = Regex::new("[0-9]{3}-[0-9]{3}-[0-9]{4}").unwrap(); +/// let mat = re.find("phone: 111-222-3333").unwrap(); +/// assert_eq!((mat.start(), mat.end()), (7, 19)); +/// ``` +/// +/// # Using the `std::str::pattern` methods with `Regex` +/// +/// > **Note**: This section requires that this crate is compiled with the +/// > `pattern` Cargo feature enabled, which **requires nightly Rust**. +/// +/// Since `Regex` implements `Pattern`, you can use regexes with methods +/// defined on `&str`. For example, `is_match`, `find`, `find_iter` +/// and `split` can be replaced with `str::contains`, `str::find`, +/// `str::match_indices` and `str::split`. +/// +/// Here are some examples: +/// +/// ```rust,ignore +/// # use regex::Regex; +/// let re = Regex::new(r"\d+").unwrap(); +/// let haystack = "a111b222c"; +/// +/// assert!(haystack.contains(&re)); +/// assert_eq!(haystack.find(&re), Some(1)); +/// assert_eq!(haystack.match_indices(&re).collect::<Vec<_>>(), +/// vec![(1, 4), (5, 8)]); +/// assert_eq!(haystack.split(&re).collect::<Vec<_>>(), vec!["a", "b", "c"]); +/// ``` +#[derive(Clone)] +pub struct Regex(Exec); + +impl fmt::Display for Regex { + /// Shows the original regular expression. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +impl fmt::Debug for Regex { + /// Shows the original regular expression. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +#[doc(hidden)] +impl From<Exec> for Regex { + fn from(exec: Exec) -> Regex { + Regex(exec) + } +} + +impl FromStr for Regex { + type Err = Error; + + /// Attempts to parse a string into a regular expression + fn from_str(s: &str) -> Result<Regex, Error> { + Regex::new(s) + } +} + +/// Core regular expression methods. +impl Regex { + /// Compiles a regular expression. Once compiled, it can be used repeatedly + /// to search, split or replace text in a string. + /// + /// If an invalid expression is given, then an error is returned. + pub fn new(re: &str) -> Result<Regex, Error> { + RegexBuilder::new(re).build() + } + + /// Returns true if and only if the regex matches the string given. + /// + /// It is recommended to use this method if all you need to do is test + /// a match, since the underlying matching engine may be able to do less + /// work. + /// + /// # Example + /// + /// Test if some text contains at least one word with exactly 13 + /// Unicode word characters: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let text = "I categorically deny having triskaidekaphobia."; + /// assert!(Regex::new(r"\b\w{13}\b").unwrap().is_match(text)); + /// # } + /// ``` + pub fn is_match(&self, text: &str) -> bool { + self.is_match_at(text, 0) + } + + /// Returns the start and end byte range of the leftmost-first match in + /// `text`. If no match exists, then `None` is returned. + /// + /// Note that this should only be used if you want to discover the position + /// of the match. Testing the existence of a match is faster if you use + /// `is_match`. + /// + /// # Example + /// + /// Find the start and end location of the first word with exactly 13 + /// Unicode word characters: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let text = "I categorically deny having triskaidekaphobia."; + /// let mat = Regex::new(r"\b\w{13}\b").unwrap().find(text).unwrap(); + /// assert_eq!(mat.start(), 2); + /// assert_eq!(mat.end(), 15); + /// # } + /// ``` + pub fn find<'t>(&self, text: &'t str) -> Option<Match<'t>> { + self.find_at(text, 0) + } + + /// Returns an iterator for each successive non-overlapping match in + /// `text`, returning the start and end byte indices with respect to + /// `text`. + /// + /// # Example + /// + /// Find the start and end location of every word with exactly 13 Unicode + /// word characters: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let text = "Retroactively relinquishing remunerations is reprehensible."; + /// for mat in Regex::new(r"\b\w{13}\b").unwrap().find_iter(text) { + /// println!("{:?}", mat); + /// } + /// # } + /// ``` + pub fn find_iter<'r, 't>(&'r self, text: &'t str) -> Matches<'r, 't> { + Matches(self.0.searcher_str().find_iter(text)) + } + + /// Returns the capture groups corresponding to the leftmost-first + /// match in `text`. Capture group `0` always corresponds to the entire + /// match. If no match is found, then `None` is returned. + /// + /// You should only use `captures` if you need access to the location of + /// capturing group matches. Otherwise, `find` is faster for discovering + /// the location of the overall match. + /// + /// # Examples + /// + /// Say you have some text with movie names and their release years, + /// like "'Citizen Kane' (1941)". It'd be nice if we could search for text + /// looking like that, while also extracting the movie name and its release + /// year separately. + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"'([^']+)'\s+\((\d{4})\)").unwrap(); + /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; + /// let caps = re.captures(text).unwrap(); + /// assert_eq!(caps.get(1).unwrap().as_str(), "Citizen Kane"); + /// assert_eq!(caps.get(2).unwrap().as_str(), "1941"); + /// assert_eq!(caps.get(0).unwrap().as_str(), "'Citizen Kane' (1941)"); + /// // You can also access the groups by index using the Index notation. + /// // Note that this will panic on an invalid index. + /// assert_eq!(&caps[1], "Citizen Kane"); + /// assert_eq!(&caps[2], "1941"); + /// assert_eq!(&caps[0], "'Citizen Kane' (1941)"); + /// # } + /// ``` + /// + /// Note that the full match is at capture group `0`. Each subsequent + /// capture group is indexed by the order of its opening `(`. + /// + /// We can make this example a bit clearer by using *named* capture groups: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)") + /// .unwrap(); + /// let text = "Not my favorite movie: 'Citizen Kane' (1941)."; + /// let caps = re.captures(text).unwrap(); + /// assert_eq!(caps.name("title").unwrap().as_str(), "Citizen Kane"); + /// assert_eq!(caps.name("year").unwrap().as_str(), "1941"); + /// assert_eq!(caps.get(0).unwrap().as_str(), "'Citizen Kane' (1941)"); + /// // You can also access the groups by name using the Index notation. + /// // Note that this will panic on an invalid group name. + /// assert_eq!(&caps["title"], "Citizen Kane"); + /// assert_eq!(&caps["year"], "1941"); + /// assert_eq!(&caps[0], "'Citizen Kane' (1941)"); + /// + /// # } + /// ``` + /// + /// Here we name the capture groups, which we can access with the `name` + /// method or the `Index` notation with a `&str`. Note that the named + /// capture groups are still accessible with `get` or the `Index` notation + /// with a `usize`. + /// + /// The `0`th capture group is always unnamed, so it must always be + /// accessed with `get(0)` or `[0]`. + pub fn captures<'t>(&self, text: &'t str) -> Option<Captures<'t>> { + let mut locs = self.capture_locations(); + self.captures_read_at(&mut locs, text, 0).map(move |_| Captures { + text: text, + locs: locs.0, + named_groups: self.0.capture_name_idx().clone(), + }) + } + + /// Returns an iterator over all the non-overlapping capture groups matched + /// in `text`. This is operationally the same as `find_iter`, except it + /// yields information about capturing group matches. + /// + /// # Example + /// + /// We can use this to find all movie titles and their release years in + /// some text, where the movie is formatted like "'Title' (xxxx)": + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)") + /// .unwrap(); + /// let text = "'Citizen Kane' (1941), 'The Wizard of Oz' (1939), 'M' (1931)."; + /// for caps in re.captures_iter(text) { + /// println!("Movie: {:?}, Released: {:?}", + /// &caps["title"], &caps["year"]); + /// } + /// // Output: + /// // Movie: Citizen Kane, Released: 1941 + /// // Movie: The Wizard of Oz, Released: 1939 + /// // Movie: M, Released: 1931 + /// # } + /// ``` + pub fn captures_iter<'r, 't>( + &'r self, + text: &'t str, + ) -> CaptureMatches<'r, 't> { + CaptureMatches(self.0.searcher_str().captures_iter(text)) + } + + /// Returns an iterator of substrings of `text` delimited by a match of the + /// regular expression. Namely, each element of the iterator corresponds to + /// text that *isn't* matched by the regular expression. + /// + /// This method will *not* copy the text given. + /// + /// # Example + /// + /// To split a string delimited by arbitrary amounts of spaces or tabs: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"[ \t]+").unwrap(); + /// let fields: Vec<&str> = re.split("a b \t c\td e").collect(); + /// assert_eq!(fields, vec!["a", "b", "c", "d", "e"]); + /// # } + /// ``` + pub fn split<'r, 't>(&'r self, text: &'t str) -> Split<'r, 't> { + Split { + finder: self.find_iter(text), + last: 0, + } + } + + /// Returns an iterator of at most `limit` substrings of `text` delimited + /// by a match of the regular expression. (A `limit` of `0` will return no + /// substrings.) Namely, each element of the iterator corresponds to text + /// that *isn't* matched by the regular expression. The remainder of the + /// string that is not split will be the last element in the iterator. + /// + /// This method will *not* copy the text given. + /// + /// # Example + /// + /// Get the first two words in some text: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"\W+").unwrap(); + /// let fields: Vec<&str> = re.splitn("Hey! How are you?", 3).collect(); + /// assert_eq!(fields, vec!("Hey", "How", "are you?")); + /// # } + /// ``` + pub fn splitn<'r, 't>(&'r self, text: &'t str, limit: usize) + -> SplitN<'r, 't> { + SplitN { + splits: self.split(text), + n: limit, + } + } + + /// Replaces the leftmost-first match with the replacement provided. + /// The replacement can be a regular string (where `$N` and `$name` are + /// expanded to match capture groups) or a function that takes the matches' + /// `Captures` and returns the replaced string. + /// + /// If no match is found, then a copy of the string is returned unchanged. + /// + /// # Replacement string syntax + /// + /// All instances of `$name` in the replacement text is replaced with the + /// corresponding capture group `name`. + /// + /// `name` may be an integer corresponding to the index of the + /// capture group (counted by order of opening parenthesis where `0` is the + /// entire match) or it can be a name (consisting of letters, digits or + /// underscores) corresponding to a named capture group. + /// + /// If `name` isn't a valid capture group (whether the name doesn't exist + /// or isn't a valid index), then it is replaced with the empty string. + /// + /// The longest possible name is used. e.g., `$1a` looks up the capture + /// group named `1a` and not the capture group at index `1`. To exert more + /// precise control over the name, use braces, e.g., `${1}a`. + /// + /// To write a literal `$` use `$$`. + /// + /// # Examples + /// + /// Note that this function is polymorphic with respect to the replacement. + /// In typical usage, this can just be a normal string: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new("[^01]+").unwrap(); + /// assert_eq!(re.replace("1078910", ""), "1010"); + /// # } + /// ``` + /// + /// But anything satisfying the `Replacer` trait will work. For example, + /// a closure of type `|&Captures| -> String` provides direct access to the + /// captures corresponding to a match. This allows one to access + /// capturing group matches easily: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # use regex::Captures; fn main() { + /// let re = Regex::new(r"([^,\s]+),\s+(\S+)").unwrap(); + /// let result = re.replace("Springsteen, Bruce", |caps: &Captures| { + /// format!("{} {}", &caps[2], &caps[1]) + /// }); + /// assert_eq!(result, "Bruce Springsteen"); + /// # } + /// ``` + /// + /// But this is a bit cumbersome to use all the time. Instead, a simple + /// syntax is supported that expands `$name` into the corresponding capture + /// group. Here's the last example, but using this expansion technique + /// with named capture groups: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(?P<first>\S+)").unwrap(); + /// let result = re.replace("Springsteen, Bruce", "$first $last"); + /// assert_eq!(result, "Bruce Springsteen"); + /// # } + /// ``` + /// + /// Note that using `$2` instead of `$first` or `$1` instead of `$last` + /// would produce the same result. To write a literal `$` use `$$`. + /// + /// Sometimes the replacement string requires use of curly braces to + /// delineate a capture group replacement and surrounding literal text. + /// For example, if we wanted to join two words together with an + /// underscore: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let re = Regex::new(r"(?P<first>\w+)\s+(?P<second>\w+)").unwrap(); + /// let result = re.replace("deep fried", "${first}_$second"); + /// assert_eq!(result, "deep_fried"); + /// # } + /// ``` + /// + /// Without the curly braces, the capture group name `first_` would be + /// used, and since it doesn't exist, it would be replaced with the empty + /// string. + /// + /// Finally, sometimes you just want to replace a literal string with no + /// regard for capturing group expansion. This can be done by wrapping a + /// byte string with `NoExpand`: + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// use regex::NoExpand; + /// + /// let re = Regex::new(r"(?P<last>[^,\s]+),\s+(\S+)").unwrap(); + /// let result = re.replace("Springsteen, Bruce", NoExpand("$2 $last")); + /// assert_eq!(result, "$2 $last"); + /// # } + /// ``` + pub fn replace<'t, R: Replacer>( + &self, + text: &'t str, + rep: R, + ) -> Cow<'t, str> { + self.replacen(text, 1, rep) + } + + /// Replaces all non-overlapping matches in `text` with the replacement + /// provided. This is the same as calling `replacen` with `limit` set to + /// `0`. + /// + /// See the documentation for `replace` for details on how to access + /// capturing group matches in the replacement string. + pub fn replace_all<'t, R: Replacer>( + &self, + text: &'t str, + rep: R, + ) -> Cow<'t, str> { + self.replacen(text, 0, rep) + } + + /// Replaces at most `limit` non-overlapping matches in `text` with the + /// replacement provided. If `limit` is 0, then all non-overlapping matches + /// are replaced. + /// + /// See the documentation for `replace` for details on how to access + /// capturing group matches in the replacement string. + pub fn replacen<'t, R: Replacer>( + &self, + text: &'t str, + limit: usize, + mut rep: R, + ) -> Cow<'t, str> { + // If we know that the replacement doesn't have any capture expansions, + // then we can fast path. The fast path can make a tremendous + // difference: + // + // 1) We use `find_iter` instead of `captures_iter`. Not asking for + // captures generally makes the regex engines faster. + // 2) We don't need to look up all of the capture groups and do + // replacements inside the replacement string. We just push it + // at each match and be done with it. + if let Some(rep) = rep.no_expansion() { + let mut it = self.find_iter(text).enumerate().peekable(); + if it.peek().is_none() { + return Cow::Borrowed(text); + } + let mut new = String::with_capacity(text.len()); + let mut last_match = 0; + for (i, m) in it { + if limit > 0 && i >= limit { + break + } + new.push_str(&text[last_match..m.start()]); + new.push_str(&rep); + last_match = m.end(); + } + new.push_str(&text[last_match..]); + return Cow::Owned(new); + } + + // The slower path, which we use if the replacement needs access to + // capture groups. + let mut it = self.captures_iter(text).enumerate().peekable(); + if it.peek().is_none() { + return Cow::Borrowed(text); + } + let mut new = String::with_capacity(text.len()); + let mut last_match = 0; + for (i, cap) in it { + if limit > 0 && i >= limit { + break + } + // unwrap on 0 is OK because captures only reports matches + let m = cap.get(0).unwrap(); + new.push_str(&text[last_match..m.start()]); + rep.replace_append(&cap, &mut new); + last_match = m.end(); + } + new.push_str(&text[last_match..]); + Cow::Owned(new) + } +} + +/// Advanced or "lower level" search methods. +impl Regex { + /// Returns the end location of a match in the text given. + /// + /// This method may have the same performance characteristics as + /// `is_match`, except it provides an end location for a match. In + /// particular, the location returned *may be shorter* than the proper end + /// of the leftmost-first match. + /// + /// # Example + /// + /// Typically, `a+` would match the entire first sequence of `a` in some + /// text, but `shortest_match` can give up as soon as it sees the first + /// `a`. + /// + /// ```rust + /// # extern crate regex; use regex::Regex; + /// # fn main() { + /// let text = "aaaaa"; + /// let pos = Regex::new(r"a+").unwrap().shortest_match(text); + /// assert_eq!(pos, Some(1)); + /// # } + /// ``` + pub fn shortest_match(&self, text: &str) -> Option<usize> { + self.shortest_match_at(text, 0) + } + + /// Returns the same as shortest_match, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn shortest_match_at( + &self, + text: &str, + start: usize, + ) -> Option<usize> { + self.0.searcher_str().shortest_match_at(text, start) + } + + /// Returns the same as is_match, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn is_match_at(&self, text: &str, start: usize) -> bool { + self.shortest_match_at(text, start).is_some() + } + + /// Returns the same as find, but starts the search at the given + /// offset. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn find_at<'t>( + &self, + text: &'t str, + start: usize, + ) -> Option<Match<'t>> { + self.0.searcher_str().find_at(text, start).map(|(s, e)| { + Match::new(text, s, e) + }) + } + + /// This is like `captures`, but uses + /// [`CaptureLocations`](struct.CaptureLocations.html) + /// instead of + /// [`Captures`](struct.Captures.html) in order to amortize allocations. + /// + /// To create a `CaptureLocations` value, use the + /// `Regex::capture_locations` method. + /// + /// This returns the overall match if this was successful, which is always + /// equivalence to the `0`th capture group. + pub fn captures_read<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t str, + ) -> Option<Match<'t>> { + self.captures_read_at(locs, text, 0) + } + + /// Returns the same as captures, but starts the search at the given + /// offset and populates the capture locations given. + /// + /// The significance of the starting point is that it takes the surrounding + /// context into consideration. For example, the `\A` anchor can only + /// match when `start == 0`. + pub fn captures_read_at<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t str, + start: usize, + ) -> Option<Match<'t>> { + self.0 + .searcher_str() + .captures_read_at(&mut locs.0, text, start) + .map(|(s, e)| Match::new(text, s, e)) + } + + /// An undocumented alias for `captures_read_at`. + /// + /// The `regex-capi` crate previously used this routine, so to avoid + /// breaking that crate, we continue to provide the name as an undocumented + /// alias. + #[doc(hidden)] + pub fn read_captures_at<'t>( + &self, + locs: &mut CaptureLocations, + text: &'t str, + start: usize, + ) -> Option<Match<'t>> { + self.captures_read_at(locs, text, start) + } +} + +/// Auxiliary methods. +impl Regex { + /// Returns the original string of this regex. + pub fn as_str(&self) -> &str { + &self.0.regex_strings()[0] + } + + /// Returns an iterator over the capture names. + pub fn capture_names(&self) -> CaptureNames { + CaptureNames(self.0.capture_names().iter()) + } + + /// Returns the number of captures. + pub fn captures_len(&self) -> usize { + self.0.capture_names().len() + } + + /// Returns an empty set of capture locations that can be reused in + /// multiple calls to `captures_read` or `captures_read_at`. + pub fn capture_locations(&self) -> CaptureLocations { + CaptureLocations(self.0.searcher_str().locations()) + } + + /// An alias for `capture_locations` to preserve backward compatibility. + /// + /// The `regex-capi` crate uses this method, so to avoid breaking that + /// crate, we continue to export it as an undocumented API. + #[doc(hidden)] + pub fn locations(&self) -> CaptureLocations { + CaptureLocations(self.0.searcher_str().locations()) + } +} + +/// An iterator over the names of all possible captures. +/// +/// `None` indicates an unnamed capture; the first element (capture 0, the +/// whole matched region) is always unnamed. +/// +/// `'r` is the lifetime of the compiled regular expression. +pub struct CaptureNames<'r>(::std::slice::Iter<'r, Option<String>>); + +impl<'r> Iterator for CaptureNames<'r> { + type Item = Option<&'r str>; + + fn next(&mut self) -> Option<Option<&'r str>> { + self.0 + .next() + .as_ref() + .map(|slot| slot.as_ref().map(|name| name.as_ref())) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +/// Yields all substrings delimited by a regular expression match. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the string being split. +pub struct Split<'r, 't> { + finder: Matches<'r, 't>, + last: usize, +} + +impl<'r, 't> Iterator for Split<'r, 't> { + type Item = &'t str; + + fn next(&mut self) -> Option<&'t str> { + let text = self.finder.0.text(); + match self.finder.next() { + None => { + if self.last >= text.len() { + None + } else { + let s = &text[self.last..]; + self.last = text.len(); + Some(s) + } + } + Some(m) => { + let matched = &text[self.last..m.start()]; + self.last = m.end(); + Some(matched) + } + } + } +} + +/// Yields at most `N` substrings delimited by a regular expression match. +/// +/// The last substring will be whatever remains after splitting. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the string being split. +pub struct SplitN<'r, 't> { + splits: Split<'r, 't>, + n: usize, +} + +impl<'r, 't> Iterator for SplitN<'r, 't> { + type Item = &'t str; + + fn next(&mut self) -> Option<&'t str> { + if self.n == 0 { + return None + } + self.n -= 1; + if self.n == 0 { + let text = self.splits.finder.0.text(); + Some(&text[self.splits.last..]) + } else { + self.splits.next() + } + } +} + +/// CaptureLocations is a low level representation of the raw offsets of each +/// submatch. +/// +/// You can think of this as a lower level +/// [`Captures`](struct.Captures.html), where this type does not support +/// named capturing groups directly and it does not borrow the text that these +/// offsets were matched on. +/// +/// Primarily, this type is useful when using the lower level `Regex` APIs +/// such as `read_captures`, which permits amortizing the allocation in which +/// capture match locations are stored. +/// +/// In order to build a value of this type, you'll need to call the +/// `capture_locations` method on the `Regex` being used to execute the search. +/// The value returned can then be reused in subsequent searches. +#[derive(Clone, Debug)] +pub struct CaptureLocations(re_trait::Locations); + +/// A type alias for `CaptureLocations` for backwards compatibility. +/// +/// Previously, we exported `CaptureLocations` as `Locations` in an +/// undocumented API. To prevent breaking that code (e.g., in `regex-capi`), +/// we continue re-exporting the same undocumented API. +#[doc(hidden)] +pub type Locations = CaptureLocations; + +impl CaptureLocations { + /// Returns the start and end positions of the Nth capture group. Returns + /// `None` if `i` is not a valid capture group or if the capture group did + /// not match anything. The positions returned are *always* byte indices + /// with respect to the original string matched. + #[inline] + pub fn get(&self, i: usize) -> Option<(usize, usize)> { + self.0.pos(i) + } + + /// Returns the total number of capturing groups. + /// + /// This is always at least `1` since every regex has at least `1` + /// capturing group that corresponds to the entire match. + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// An alias for the `get` method for backwards compatibility. + /// + /// Previously, we exported `get` as `pos` in an undocumented API. To + /// prevent breaking that code (e.g., in `regex-capi`), we continue + /// re-exporting the same undocumented API. + #[doc(hidden)] + #[inline] + pub fn pos(&self, i: usize) -> Option<(usize, usize)> { + self.get(i) + } +} + +/// Captures represents a group of captured strings for a single match. +/// +/// The 0th capture always corresponds to the entire match. Each subsequent +/// index corresponds to the next capture group in the regex. If a capture +/// group is named, then the matched string is *also* available via the `name` +/// method. (Note that the 0th capture is always unnamed and so must be +/// accessed with the `get` method.) +/// +/// Positions returned from a capture group are always byte indices. +/// +/// `'t` is the lifetime of the matched text. +pub struct Captures<'t> { + text: &'t str, + locs: re_trait::Locations, + named_groups: Arc<HashMap<String, usize>>, +} + +impl<'t> Captures<'t> { + /// Returns the match associated with the capture group at index `i`. If + /// `i` does not correspond to a capture group, or if the capture group + /// did not participate in the match, then `None` is returned. + /// + /// # Examples + /// + /// Get the text of the match with a default of an empty string if this + /// group didn't participate in the match: + /// + /// ```rust + /// # use regex::Regex; + /// let re = Regex::new(r"[a-z]+(?:([0-9]+)|([A-Z]+))").unwrap(); + /// let caps = re.captures("abc123").unwrap(); + /// + /// let text1 = caps.get(1).map_or("", |m| m.as_str()); + /// let text2 = caps.get(2).map_or("", |m| m.as_str()); + /// assert_eq!(text1, "123"); + /// assert_eq!(text2, ""); + /// ``` + pub fn get(&self, i: usize) -> Option<Match<'t>> { + self.locs.pos(i).map(|(s, e)| Match::new(self.text, s, e)) + } + + /// Returns the match for the capture group named `name`. If `name` isn't a + /// valid capture group or didn't match anything, then `None` is returned. + pub fn name(&self, name: &str) -> Option<Match<'t>> { + self.named_groups.get(name).and_then(|&i| self.get(i)) + } + + /// An iterator that yields all capturing matches in the order in which + /// they appear in the regex. If a particular capture group didn't + /// participate in the match, then `None` is yielded for that capture. + /// + /// The first match always corresponds to the overall match of the regex. + pub fn iter<'c>(&'c self) -> SubCaptureMatches<'c, 't> { + SubCaptureMatches { + caps: self, + it: self.locs.iter(), + } + } + + /// Expands all instances of `$name` in `replacement` to the corresponding + /// capture group `name`, and writes them to the `dst` buffer given. + /// + /// `name` may be an integer corresponding to the index of the + /// capture group (counted by order of opening parenthesis where `0` is the + /// entire match) or it can be a name (consisting of letters, digits or + /// underscores) corresponding to a named capture group. + /// + /// If `name` isn't a valid capture group (whether the name doesn't exist + /// or isn't a valid index), then it is replaced with the empty string. + /// + /// The longest possible name is used. e.g., `$1a` looks up the capture + /// group named `1a` and not the capture group at index `1`. To exert more + /// precise control over the name, use braces, e.g., `${1}a`. + /// + /// To write a literal `$` use `$$`. + pub fn expand(&self, replacement: &str, dst: &mut String) { + expand_str(self, replacement, dst) + } + + /// Returns the number of captured groups. + /// + /// This is always at least `1`, since every regex has at least one capture + /// group that corresponds to the full match. + #[inline] + pub fn len(&self) -> usize { + self.locs.len() + } +} + +impl<'t> fmt::Debug for Captures<'t> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Captures").field(&CapturesDebug(self)).finish() + } +} + +struct CapturesDebug<'c, 't: 'c>(&'c Captures<'t>); + +impl<'c, 't> fmt::Debug for CapturesDebug<'c, 't> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // We'd like to show something nice here, even if it means an + // allocation to build a reverse index. + let slot_to_name: HashMap<&usize, &String> = + self.0.named_groups.iter().map(|(a, b)| (b, a)).collect(); + let mut map = f.debug_map(); + for (slot, m) in self.0.locs.iter().enumerate() { + let m = m.map(|(s, e)| &self.0.text[s..e]); + if let Some(name) = slot_to_name.get(&slot) { + map.entry(&name, &m); + } else { + map.entry(&slot, &m); + } + } + map.finish() + } +} + +/// Get a group by index. +/// +/// `'t` is the lifetime of the matched text. +/// +/// The text can't outlive the `Captures` object if this method is +/// used, because of how `Index` is defined (normally `a[i]` is part +/// of `a` and can't outlive it); to do that, use `get()` instead. +/// +/// # Panics +/// +/// If there is no group at the given index. +impl<'t> Index<usize> for Captures<'t> { + type Output = str; + + fn index(&self, i: usize) -> &str { + self.get(i).map(|m| m.as_str()) + .unwrap_or_else(|| panic!("no group at index '{}'", i)) + } +} + +/// Get a group by name. +/// +/// `'t` is the lifetime of the matched text and `'i` is the lifetime +/// of the group name (the index). +/// +/// The text can't outlive the `Captures` object if this method is +/// used, because of how `Index` is defined (normally `a[i]` is part +/// of `a` and can't outlive it); to do that, use `name` instead. +/// +/// # Panics +/// +/// If there is no group named by the given value. +impl<'t, 'i> Index<&'i str> for Captures<'t> { + type Output = str; + + fn index<'a>(&'a self, name: &'i str) -> &'a str { + self.name(name).map(|m| m.as_str()) + .unwrap_or_else(|| panic!("no group named '{}'", name)) + } +} + +/// An iterator that yields all capturing matches in the order in which they +/// appear in the regex. +/// +/// If a particular capture group didn't participate in the match, then `None` +/// is yielded for that capture. The first match always corresponds to the +/// overall match of the regex. +/// +/// The lifetime `'c` corresponds to the lifetime of the `Captures` value, and +/// the lifetime `'t` corresponds to the originally matched text. +pub struct SubCaptureMatches<'c, 't: 'c> { + caps: &'c Captures<'t>, + it: SubCapturesPosIter<'c>, +} + +impl<'c, 't> Iterator for SubCaptureMatches<'c, 't> { + type Item = Option<Match<'t>>; + + fn next(&mut self) -> Option<Option<Match<'t>>> { + self.it.next() + .map(|cap| cap.map(|(s, e)| Match::new(self.caps.text, s, e))) + } +} + +/// An iterator that yields all non-overlapping capture groups matching a +/// particular regular expression. +/// +/// The iterator stops when no more matches can be found. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the matched string. +pub struct CaptureMatches<'r, 't>(re_trait::CaptureMatches<'t, ExecNoSyncStr<'r>>); + +impl<'r, 't> Iterator for CaptureMatches<'r, 't> { + type Item = Captures<'t>; + + fn next(&mut self) -> Option<Captures<'t>> { + self.0.next().map(|locs| Captures { + text: self.0.text(), + locs: locs, + named_groups: self.0.regex().capture_name_idx().clone(), + }) + } +} + +/// An iterator over all non-overlapping matches for a particular string. +/// +/// The iterator yields a `Match` value. The iterator stops when no more +/// matches can be found. +/// +/// `'r` is the lifetime of the compiled regular expression and `'t` is the +/// lifetime of the matched string. +pub struct Matches<'r, 't>(re_trait::Matches<'t, ExecNoSyncStr<'r>>); + +impl<'r, 't> Iterator for Matches<'r, 't> { + type Item = Match<'t>; + + fn next(&mut self) -> Option<Match<'t>> { + let text = self.0.text(); + self.0.next().map(|(s, e)| Match::new(text, s, e)) + } +} + +/// Replacer describes types that can be used to replace matches in a string. +/// +/// In general, users of this crate shouldn't need to implement this trait, +/// since implementations are already provided for `&str` and +/// `FnMut(&Captures) -> String` (or any `FnMut(&Captures) -> T` +/// where `T: AsRef<str>`), which covers most use cases. +pub trait Replacer { + /// Appends text to `dst` to replace the current match. + /// + /// The current match is represented by `caps`, which is guaranteed to + /// have a match at capture group `0`. + /// + /// For example, a no-op replacement would be + /// `dst.extend(caps.get(0).unwrap().as_str())`. + fn replace_append(&mut self, caps: &Captures, dst: &mut String); + + /// Return a fixed unchanging replacement string. + /// + /// When doing replacements, if access to `Captures` is not needed (e.g., + /// the replacement byte string does not need `$` expansion), then it can + /// be beneficial to avoid finding sub-captures. + /// + /// In general, this is called once for every call to `replacen`. + fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, str>> { + None + } + + /// Return a `Replacer` that borrows and wraps this `Replacer`. + /// + /// This is useful when you want to take a generic `Replacer` (which might + /// not be cloneable) and use it without consuming it, so it can be used + /// more than once. + /// + /// # Example + /// + /// ``` + /// use regex::{Regex, Replacer}; + /// + /// fn replace_all_twice<R: Replacer>( + /// re: Regex, + /// src: &str, + /// mut rep: R, + /// ) -> String { + /// let dst = re.replace_all(src, rep.by_ref()); + /// let dst = re.replace_all(&dst, rep.by_ref()); + /// dst.into_owned() + /// } + /// ``` + fn by_ref<'r>(&'r mut self) -> ReplacerRef<'r, Self> { + ReplacerRef(self) + } +} + +/// By-reference adaptor for a `Replacer` +/// +/// Returned by [`Replacer::by_ref`](trait.Replacer.html#method.by_ref). +#[derive(Debug)] +pub struct ReplacerRef<'a, R: ?Sized + 'a>(&'a mut R); + +impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + self.0.replace_append(caps, dst) + } + fn no_expansion(&mut self) -> Option<Cow<str>> { + self.0.no_expansion() + } +} + +impl<'a> Replacer for &'a str { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + caps.expand(*self, dst); + } + + fn no_expansion(&mut self) -> Option<Cow<str>> { + match memchr(b'$', self.as_bytes()) { + Some(_) => None, + None => Some(Cow::Borrowed(*self)), + } + } +} + +impl<F, T> Replacer for F where F: FnMut(&Captures) -> T, T: AsRef<str> { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + dst.push_str((*self)(caps).as_ref()); + } +} + +/// `NoExpand` indicates literal string replacement. +/// +/// It can be used with `replace` and `replace_all` to do a literal string +/// replacement without expanding `$name` to their corresponding capture +/// groups. This can be both convenient (to avoid escaping `$`, for example) +/// and performant (since capture groups don't need to be found). +/// +/// `'t` is the lifetime of the literal text. +pub struct NoExpand<'t>(pub &'t str); + +impl<'t> Replacer for NoExpand<'t> { + fn replace_append(&mut self, _: &Captures, dst: &mut String) { + dst.push_str(self.0); + } + + fn no_expansion(&mut self) -> Option<Cow<str>> { + Some(Cow::Borrowed(self.0)) + } +} diff --git a/regex/src/sparse.rs b/regex/src/sparse.rs new file mode 100644 index 000000000..ae4cae4b9 --- /dev/null +++ b/regex/src/sparse.rs @@ -0,0 +1,75 @@ +use std::ops::Deref; +use std::slice; + +/// A sparse set used for representing ordered NFA states. +/// +/// This supports constant time addition and membership testing. Clearing an +/// entire set can also be done in constant time. Iteration yields elements +/// in the order in which they were inserted. +/// +/// The data structure is based on: http://research.swtch.com/sparse +/// Note though that we don't actually use uninitialized memory. We generally +/// reuse allocations, so the initial allocation cost is bareable. However, +/// its other properties listed above are extremely useful. +#[derive(Clone, Debug)] +pub struct SparseSet { + /// Dense contains the instruction pointers in the order in which they + /// were inserted. + dense: Vec<usize>, + /// Sparse maps instruction pointers to their location in dense. + /// + /// An instruction pointer is in the set if and only if + /// sparse[ip] < dense.len() && ip == dense[sparse[ip]]. + sparse: Box<[usize]>, +} + +impl SparseSet { + pub fn new(size: usize) -> SparseSet { + SparseSet { + dense: Vec::with_capacity(size), + sparse: vec![0; size].into_boxed_slice(), + } + } + + pub fn len(&self) -> usize { + self.dense.len() + } + + pub fn is_empty(&self) -> bool { + self.dense.is_empty() + } + + pub fn capacity(&self) -> usize { + self.dense.capacity() + } + + pub fn insert(&mut self, value: usize) { + let i = self.len(); + assert!(i < self.capacity()); + self.dense.push(value); + self.sparse[value] = i; + } + + pub fn contains(&self, value: usize) -> bool { + let i = self.sparse[value]; + self.dense.get(i) == Some(&value) + } + + pub fn clear(&mut self) { + self.dense.clear(); + } +} + +impl Deref for SparseSet { + type Target = [usize]; + + fn deref(&self) -> &Self::Target { + &self.dense + } +} + +impl<'a> IntoIterator for &'a SparseSet { + type Item = &'a usize; + type IntoIter = slice::Iter<'a, usize>; + fn into_iter(self) -> Self::IntoIter { self.iter() } +} diff --git a/regex/src/testdata/LICENSE b/regex/src/testdata/LICENSE new file mode 100644 index 000000000..f47dbf4c4 --- /dev/null +++ b/regex/src/testdata/LICENSE @@ -0,0 +1,19 @@ +The following license covers testregex.c and all associated test data. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of the +Software, and to permit persons to whom the Software is furnished to do +so, subject to the following disclaimer: + +THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/regex/src/testdata/README b/regex/src/testdata/README new file mode 100644 index 000000000..6efc2dad3 --- /dev/null +++ b/regex/src/testdata/README @@ -0,0 +1,17 @@ +Test data was taken from the Go distribution, which was in turn taken from the +testregex test suite: + + http://www2.research.att.com/~astopen/testregex/testregex.html + +The LICENSE in this directory corresponds to the LICENSE that the data was +released under. + +The tests themselves were modified for RE2/Go. A couple were modified further +by me (Andrew Gallant) (only in repetition.dat) so that RE2/Go would pass them. +(Yes, it seems like RE2/Go includes failing test cases.) This may or may not +have been a bad idea, but I think being consistent with an established Regex +library is worth something. + +Note that these files are read by 'scripts/regex-match-tests.py' and turned +into Rust tests found in 'regex_macros/tests/matches.rs'. + diff --git a/regex/src/testdata/basic.dat b/regex/src/testdata/basic.dat new file mode 100644 index 000000000..e55efaeec --- /dev/null +++ b/regex/src/testdata/basic.dat @@ -0,0 +1,221 @@ +NOTE all standard compliant implementations should pass these : 2002-05-31 + +BE abracadabra$ abracadabracadabra (7,18) +BE a...b abababbb (2,7) +BE XXXXXX ..XXXXXX (2,8) +E \) () (1,2) +BE a] a]a (0,2) +B } } (0,1) +E \} } (0,1) +BE \] ] (0,1) +B ] ] (0,1) +E ] ] (0,1) +B { { (0,1) +B } } (0,1) +BE ^a ax (0,1) +BE \^a a^a (1,3) +BE a\^ a^ (0,2) +BE a$ aa (1,2) +BE a\$ a$ (0,2) +BE ^$ NULL (0,0) +E $^ NULL (0,0) +E a($) aa (1,2)(2,2) +E a*(^a) aa (0,1)(0,1) +E (..)*(...)* a (0,0) +E (..)*(...)* abcd (0,4)(2,4) +E (ab|a)(bc|c) abc (0,3)(0,2)(2,3) +E (ab)c|abc abc (0,3)(0,2) +E a{0}b ab (1,2) +E (a*)(b?)(b+)b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7) +E (a*)(b{0,1})(b{1,})b{3} aaabbbbbbb (0,10)(0,3)(3,4)(4,7) +E a{9876543210} NULL BADBR +E ((a|a)|a) a (0,1)(0,1)(0,1) +E (a*)(a|aa) aaaa (0,4)(0,3)(3,4) +E a*(a.|aa) aaaa (0,4)(2,4) +E a(b)|c(d)|a(e)f aef (0,3)(?,?)(?,?)(1,2) +E (a|b)?.* b (0,1)(0,1) +E (a|b)c|a(b|c) ac (0,2)(0,1) +E (a|b)c|a(b|c) ab (0,2)(?,?)(1,2) +E (a|b)*c|(a|ab)*c abc (0,3)(1,2) +E (a|b)*c|(a|ab)*c xc (1,2) +E (.a|.b).*|.*(.a|.b) xa (0,2)(0,2) +E a?(ab|ba)ab abab (0,4)(0,2) +E a?(ac{0}b|ba)ab abab (0,4)(0,2) +E ab|abab abbabab (0,2) +E aba|bab|bba baaabbbaba (5,8) +E aba|bab baaabbbaba (6,9) +E (aa|aaa)*|(a|aaaaa) aa (0,2)(0,2) +E (a.|.a.)*|(a|.a...) aa (0,2)(0,2) +E ab|a xabc (1,3) +E ab|a xxabc (2,4) +Ei (Ab|cD)* aBcD (0,4)(2,4) +BE [^-] --a (2,3) +BE [a-]* --a (0,3) +BE [a-m-]* --amoma-- (0,4) +E :::1:::0:|:::1:1:0: :::0:::1:::1:::0: (8,17) +E :::1:::0:|:::1:1:1: :::0:::1:::1:::0: (8,17) +{E [[:upper:]] A (0,1) [[<element>]] not supported +E [[:lower:]]+ `az{ (1,3) +E [[:upper:]]+ @AZ[ (1,3) +# No collation in Go +#BE [[-]] [[-]] (2,4) +#BE [[.NIL.]] NULL ECOLLATE +#BE [[=aleph=]] NULL ECOLLATE +} +BE$ \n \n (0,1) +BEn$ \n \n (0,1) +BE$ [^a] \n (0,1) +BE$ \na \na (0,2) +E (a)(b)(c) abc (0,3)(0,1)(1,2)(2,3) +BE xxx xxx (0,3) +E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 6, (0,6) +E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) 2/7 (0,3) +E1 (^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$) feb 1,Feb 6 (5,11) +E3 ((((((((((((((((((((((((((((((x)))))))))))))))))))))))))))))) x (0,1)(0,1)(0,1) +E3 ((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))* xx (0,2)(1,2)(1,2) +E a?(ab|ba)* ababababababababababababababababababababababababababababababababababababababababa (0,81)(79,81) +E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabbbbaa (18,25) +E abaa|abbaa|abbbaa|abbbbaa ababbabbbabbbabbbbabaa (18,22) +E aaac|aabc|abac|abbc|baac|babc|bbac|bbbc baaabbbabac (7,11) +BE$ .* \x01\x7f (0,2) +E aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa (53,57) +L aaaa\nbbbb\ncccc\nddddd\neeeeee\nfffffff\ngggg\nhhhh\niiiii\njjjjj\nkkkkk\nllll XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa NOMATCH +E a*a*a*a*a*b aaaaaaaaab (0,10) +BE ^ NULL (0,0) +BE $ NULL (0,0) +BE ^$ NULL (0,0) +BE ^a$ a (0,1) +BE abc abc (0,3) +BE abc xabcy (1,4) +BE abc ababc (2,5) +BE ab*c abc (0,3) +BE ab*bc abc (0,3) +BE ab*bc abbc (0,4) +BE ab*bc abbbbc (0,6) +E ab+bc abbc (0,4) +E ab+bc abbbbc (0,6) +E ab?bc abbc (0,4) +E ab?bc abc (0,3) +E ab?c abc (0,3) +BE ^abc$ abc (0,3) +BE ^abc abcc (0,3) +BE abc$ aabc (1,4) +BE ^ abc (0,0) +BE $ abc (3,3) +BE a.c abc (0,3) +BE a.c axc (0,3) +BE a.*c axyzc (0,5) +BE a[bc]d abd (0,3) +BE a[b-d]e ace (0,3) +BE a[b-d] aac (1,3) +BE a[-b] a- (0,2) +BE a[b-] a- (0,2) +BE a] a] (0,2) +BE a[]]b a]b (0,3) +BE a[^bc]d aed (0,3) +BE a[^-b]c adc (0,3) +BE a[^]b]c adc (0,3) +E ab|cd abc (0,2) +E ab|cd abcd (0,2) +E a\(b a(b (0,3) +E a\(*b ab (0,2) +E a\(*b a((b (0,4) +E ((a)) abc (0,1)(0,1)(0,1) +E (a)b(c) abc (0,3)(0,1)(2,3) +E a+b+c aabbabc (4,7) +E a* aaa (0,3) +#E (a*)* - (0,0)(0,0) +E (a*)* - (0,0)(?,?) RE2/Go +E (a*)+ - (0,0)(0,0) +#E (a*|b)* - (0,0)(0,0) +E (a*|b)* - (0,0)(?,?) RE2/Go +E (a+|b)* ab (0,2)(1,2) +E (a+|b)+ ab (0,2)(1,2) +E (a+|b)? ab (0,1)(0,1) +BE [^ab]* cde (0,3) +#E (^)* - (0,0)(0,0) +E (^)* - (0,0)(?,?) RE2/Go +BE a* NULL (0,0) +E ([abc])*d abbbcd (0,6)(4,5) +E ([abc])*bcd abcd (0,4)(0,1) +E a|b|c|d|e e (0,1) +E (a|b|c|d|e)f ef (0,2)(0,1) +#E ((a*|b))* - (0,0)(0,0)(0,0) +E ((a*|b))* - (0,0)(?,?)(?,?) RE2/Go +BE abcd*efg abcdefg (0,7) +BE ab* xabyabbbz (1,3) +BE ab* xayabbbz (1,2) +E (ab|cd)e abcde (2,5)(2,4) +BE [abhgefdc]ij hij (0,3) +E (a|b)c*d abcd (1,4)(1,2) +E (ab|ab*)bc abc (0,3)(0,1) +E a([bc]*)c* abc (0,3)(1,3) +E a([bc]*)(c*d) abcd (0,4)(1,3)(3,4) +E a([bc]+)(c*d) abcd (0,4)(1,3)(3,4) +E a([bc]*)(c+d) abcd (0,4)(1,2)(2,4) +E a[bcd]*dcdcde adcdcde (0,7) +E (ab|a)b*c abc (0,3)(0,2) +E ((a)(b)c)(d) abcd (0,4)(0,3)(0,1)(1,2)(3,4) +BE [A-Za-z_][A-Za-z0-9_]* alpha (0,5) +E ^a(bc+|b[eh])g|.h$ abh (1,3) +E (bc+d$|ef*g.|h?i(j|k)) effgz (0,5)(0,5) +E (bc+d$|ef*g.|h?i(j|k)) ij (0,2)(0,2)(1,2) +E (bc+d$|ef*g.|h?i(j|k)) reffgz (1,6)(1,6) +E (((((((((a))))))))) a (0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1)(0,1) +BE multiple words multiple words yeah (0,14) +E (.*)c(.*) abcde (0,5)(0,2)(3,5) +BE abcd abcd (0,4) +E a(bc)d abcd (0,4)(1,3) +E a[-]?c ac (0,3) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qaddafi (0,15)(?,?)(10,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mo'ammar Gadhafi (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Kaddafi (0,15)(?,?)(10,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Qadhafi (0,15)(?,?)(10,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gadafi (0,14)(?,?)(10,11) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadafi (0,15)(?,?)(11,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moamar Gaddafi (0,14)(?,?)(9,11) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Mu'ammar Qadhdhafi (0,18)(?,?)(13,15) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Khaddafi (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafy (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghadafi (0,15)(?,?)(11,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Ghaddafi (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muamar Kaddafi (0,14)(?,?)(9,11) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Quathafi (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Muammar Gheddafi (0,16)(?,?)(11,13) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Khadafy (0,15)(?,?)(11,12) +E M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy] Moammar Qudhafi (0,15)(?,?)(10,12) +E a+(b|c)*d+ aabcdd (0,6)(3,4) +E ^.+$ vivi (0,4) +E ^(.+)$ vivi (0,4)(0,4) +E ^([^!.]+).att.com!(.+)$ gryphon.att.com!eby (0,19)(0,7)(16,19) +E ^([^!]+!)?([^!]+)$ bas (0,3)(?,?)(0,3) +E ^([^!]+!)?([^!]+)$ bar!bas (0,7)(0,4)(4,7) +E ^([^!]+!)?([^!]+)$ foo!bas (0,7)(0,4)(4,7) +E ^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(4,8)(8,11) +E ((foo)|(bar))!bas bar!bas (0,7)(0,3)(?,?)(0,3) +E ((foo)|(bar))!bas foo!bar!bas (4,11)(4,7)(?,?)(4,7) +E ((foo)|(bar))!bas foo!bas (0,7)(0,3)(0,3) +E ((foo)|bar)!bas bar!bas (0,7)(0,3) +E ((foo)|bar)!bas foo!bar!bas (4,11)(4,7) +E ((foo)|bar)!bas foo!bas (0,7)(0,3)(0,3) +E (foo|(bar))!bas bar!bas (0,7)(0,3)(0,3) +E (foo|(bar))!bas foo!bar!bas (4,11)(4,7)(4,7) +E (foo|(bar))!bas foo!bas (0,7)(0,3) +E (foo|bar)!bas bar!bas (0,7)(0,3) +E (foo|bar)!bas foo!bar!bas (4,11)(4,7) +E (foo|bar)!bas foo!bas (0,7)(0,3) +E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11) +E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bas (0,3)(?,?)(0,3) +E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ bar!bas (0,7)(0,4)(4,7) +E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bar!bas (0,11)(?,?)(?,?)(4,8)(8,11) +E ^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$ foo!bas (0,7)(0,4)(4,7) +E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bas (0,3)(0,3)(?,?)(0,3) +E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ bar!bas (0,7)(0,7)(0,4)(4,7) +E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bar!bas (0,11)(0,11)(?,?)(?,?)(4,8)(8,11) +E ^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$ foo!bas (0,7)(0,7)(0,4)(4,7) +E .*(/XXX).* /XXX (0,4)(0,4) +E .*(\\XXX).* \XXX (0,4)(0,4) +E \\XXX \XXX (0,4) +E .*(/000).* /000 (0,4)(0,4) +E .*(\\000).* \000 (0,4)(0,4) +E \\000 \000 (0,4) diff --git a/regex/src/testdata/nullsubexpr.dat b/regex/src/testdata/nullsubexpr.dat new file mode 100644 index 000000000..2e18fbb91 --- /dev/null +++ b/regex/src/testdata/nullsubexpr.dat @@ -0,0 +1,79 @@ +NOTE null subexpression matches : 2002-06-06 + +E (a*)* a (0,1)(0,1) +#E SAME x (0,0)(0,0) +E SAME x (0,0)(?,?) RE2/Go +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) +E (a*)+ a (0,1)(0,1) +E SAME x (0,0)(0,0) +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) +E (a+)* a (0,1)(0,1) +E SAME x (0,0) +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) +E (a+)+ a (0,1)(0,1) +E SAME x NOMATCH +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) + +E ([a]*)* a (0,1)(0,1) +#E SAME x (0,0)(0,0) +E SAME x (0,0)(?,?) RE2/Go +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) +E ([a]*)+ a (0,1)(0,1) +E SAME x (0,0)(0,0) +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaax (0,6)(0,6) +E ([^b]*)* a (0,1)(0,1) +#E SAME b (0,0)(0,0) +E SAME b (0,0)(?,?) RE2/Go +E SAME aaaaaa (0,6)(0,6) +E SAME aaaaaab (0,6)(0,6) +E ([ab]*)* a (0,1)(0,1) +E SAME aaaaaa (0,6)(0,6) +E SAME ababab (0,6)(0,6) +E SAME bababa (0,6)(0,6) +E SAME b (0,1)(0,1) +E SAME bbbbbb (0,6)(0,6) +E SAME aaaabcde (0,5)(0,5) +E ([^a]*)* b (0,1)(0,1) +E SAME bbbbbb (0,6)(0,6) +#E SAME aaaaaa (0,0)(0,0) +E SAME aaaaaa (0,0)(?,?) RE2/Go +E ([^ab]*)* ccccxx (0,6)(0,6) +#E SAME ababab (0,0)(0,0) +E SAME ababab (0,0)(?,?) RE2/Go + +E ((z)+|a)* zabcde (0,2)(1,2) + +#{E a+? aaaaaa (0,1) no *? +? mimimal match ops +#E (a) aaa (0,1)(0,1) +#E (a*?) aaa (0,0)(0,0) +#E (a)*? aaa (0,0) +#E (a*?)*? aaa (0,0) +#} + +B \(a*\)*\(x\) x (0,1)(0,0)(0,1) +B \(a*\)*\(x\) ax (0,2)(0,1)(1,2) +B \(a*\)*\(x\) axa (0,2)(0,1)(1,2) +B \(a*\)*\(x\)\(\1\) x (0,1)(0,0)(0,1)(1,1) +B \(a*\)*\(x\)\(\1\) ax (0,2)(1,1)(1,2)(2,2) +B \(a*\)*\(x\)\(\1\) axa (0,3)(0,1)(1,2)(2,3) +B \(a*\)*\(x\)\(\1\)\(x\) axax (0,4)(0,1)(1,2)(2,3)(3,4) +B \(a*\)*\(x\)\(\1\)\(x\) axxa (0,3)(1,1)(1,2)(2,2)(2,3) + +#E (a*)*(x) x (0,1)(0,0)(0,1) +E (a*)*(x) x (0,1)(?,?)(0,1) RE2/Go +E (a*)*(x) ax (0,2)(0,1)(1,2) +E (a*)*(x) axa (0,2)(0,1)(1,2) + +E (a*)+(x) x (0,1)(0,0)(0,1) +E (a*)+(x) ax (0,2)(0,1)(1,2) +E (a*)+(x) axa (0,2)(0,1)(1,2) + +E (a*){2}(x) x (0,1)(0,0)(0,1) +E (a*){2}(x) ax (0,2)(1,1)(1,2) +E (a*){2}(x) axa (0,2)(1,1)(1,2) diff --git a/regex/src/testdata/repetition.dat b/regex/src/testdata/repetition.dat new file mode 100644 index 000000000..3bb212118 --- /dev/null +++ b/regex/src/testdata/repetition.dat @@ -0,0 +1,163 @@ +NOTE implicit vs. explicit repetitions : 2009-02-02 + +# Glenn Fowler <gsf@research.att.com> +# conforming matches (column 4) must match one of the following BREs +# NOMATCH +# (0,.)\((\(.\),\(.\))(?,?)(\2,\3)\)* +# (0,.)\((\(.\),\(.\))(\2,\3)(?,?)\)* +# i.e., each 3-tuple has two identical elements and one (?,?) + +E ((..)|(.)) NULL NOMATCH +E ((..)|(.))((..)|(.)) NULL NOMATCH +E ((..)|(.))((..)|(.))((..)|(.)) NULL NOMATCH + +E ((..)|(.)){1} NULL NOMATCH +E ((..)|(.)){2} NULL NOMATCH +E ((..)|(.)){3} NULL NOMATCH + +E ((..)|(.))* NULL (0,0) + +E ((..)|(.)) a (0,1)(0,1)(?,?)(0,1) +E ((..)|(.))((..)|(.)) a NOMATCH +E ((..)|(.))((..)|(.))((..)|(.)) a NOMATCH + +E ((..)|(.)){1} a (0,1)(0,1)(?,?)(0,1) +E ((..)|(.)){2} a NOMATCH +E ((..)|(.)){3} a NOMATCH + +E ((..)|(.))* a (0,1)(0,1)(?,?)(0,1) + +E ((..)|(.)) aa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.))((..)|(.)) aa (0,2)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2) +E ((..)|(.))((..)|(.))((..)|(.)) aa NOMATCH + +E ((..)|(.)){1} aa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.)){2} aa (0,2)(1,2)(?,?)(1,2) +E ((..)|(.)){3} aa NOMATCH + +E ((..)|(.))* aa (0,2)(0,2)(0,2)(?,?) + +E ((..)|(.)) aaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.))((..)|(.)) aaa (0,3)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3) +E ((..)|(.))((..)|(.))((..)|(.)) aaa (0,3)(0,1)(?,?)(0,1)(1,2)(?,?)(1,2)(2,3)(?,?)(2,3) + +E ((..)|(.)){1} aaa (0,2)(0,2)(0,2)(?,?) +#E ((..)|(.)){2} aaa (0,3)(2,3)(?,?)(2,3) +E ((..)|(.)){2} aaa (0,3)(2,3)(0,2)(2,3) RE2/Go +E ((..)|(.)){3} aaa (0,3)(2,3)(?,?)(2,3) + +#E ((..)|(.))* aaa (0,3)(2,3)(?,?)(2,3) +E ((..)|(.))* aaa (0,3)(2,3)(0,2)(2,3) RE2/Go + +E ((..)|(.)) aaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?) +E ((..)|(.))((..)|(.))((..)|(.)) aaaa (0,4)(0,2)(0,2)(?,?)(2,3)(?,?)(2,3)(3,4)(?,?)(3,4) + +E ((..)|(.)){1} aaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.)){2} aaaa (0,4)(2,4)(2,4)(?,?) +#E ((..)|(.)){3} aaaa (0,4)(3,4)(?,?)(3,4) +E ((..)|(.)){3} aaaa (0,4)(3,4)(0,2)(3,4) RE2/Go + +E ((..)|(.))* aaaa (0,4)(2,4)(2,4)(?,?) + +E ((..)|(.)) aaaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.))((..)|(.)) aaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?) +E ((..)|(.))((..)|(.))((..)|(.)) aaaaa (0,5)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,5)(?,?)(4,5) + +E ((..)|(.)){1} aaaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.)){2} aaaaa (0,4)(2,4)(2,4)(?,?) +#E ((..)|(.)){3} aaaaa (0,5)(4,5)(?,?)(4,5) +E ((..)|(.)){3} aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go + +#E ((..)|(.))* aaaaa (0,5)(4,5)(?,?)(4,5) +E ((..)|(.))* aaaaa (0,5)(4,5)(2,4)(4,5) RE2/Go + +E ((..)|(.)) aaaaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.))((..)|(.)) aaaaaa (0,4)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?) +E ((..)|(.))((..)|(.))((..)|(.)) aaaaaa (0,6)(0,2)(0,2)(?,?)(2,4)(2,4)(?,?)(4,6)(4,6)(?,?) + +E ((..)|(.)){1} aaaaaa (0,2)(0,2)(0,2)(?,?) +E ((..)|(.)){2} aaaaaa (0,4)(2,4)(2,4)(?,?) +E ((..)|(.)){3} aaaaaa (0,6)(4,6)(4,6)(?,?) + +E ((..)|(.))* aaaaaa (0,6)(4,6)(4,6)(?,?) + +NOTE additional repetition tests graciously provided by Chris Kuklewicz www.haskell.org 2009-02-02 + +# These test a bug in OS X / FreeBSD / NetBSD, and libtree. +# Linux/GLIBC gets the {8,} and {8,8} wrong. + +:HA#100:E X(.?){0,}Y X1234567Y (0,9)(7,8) +:HA#101:E X(.?){1,}Y X1234567Y (0,9)(7,8) +:HA#102:E X(.?){2,}Y X1234567Y (0,9)(7,8) +:HA#103:E X(.?){3,}Y X1234567Y (0,9)(7,8) +:HA#104:E X(.?){4,}Y X1234567Y (0,9)(7,8) +:HA#105:E X(.?){5,}Y X1234567Y (0,9)(7,8) +:HA#106:E X(.?){6,}Y X1234567Y (0,9)(7,8) +:HA#107:E X(.?){7,}Y X1234567Y (0,9)(7,8) +:HA#108:E X(.?){8,}Y X1234567Y (0,9)(8,8) +#:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(7,8) +:HA#110:E X(.?){0,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(7,8) +:HA#111:E X(.?){1,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(7,8) +:HA#112:E X(.?){2,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(7,8) +:HA#113:E X(.?){3,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(7,8) +:HA#114:E X(.?){4,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(7,8) +:HA#115:E X(.?){5,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(7,8) +:HA#116:E X(.?){6,8}Y X1234567Y (0,9)(8,8) RE2/Go +#:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(7,8) +:HA#117:E X(.?){7,8}Y X1234567Y (0,9)(8,8) RE2/Go +:HA#118:E X(.?){8,8}Y X1234567Y (0,9)(8,8) + +# These test a fixed bug in my regex-tdfa that did not keep the expanded +# form properly grouped, so right association did the wrong thing with +# these ambiguous patterns (crafted just to test my code when I became +# suspicious of my implementation). The first subexpression should use +# "ab" then "a" then "bcd". + +# OS X / FreeBSD / NetBSD badly fail many of these, with impossible +# results like (0,6)(4,5)(6,6). + +:HA#260:E (a|ab|c|bcd){0,}(d*) ababcd (0,1)(0,1)(1,1) +:HA#261:E (a|ab|c|bcd){1,}(d*) ababcd (0,1)(0,1)(1,1) +:HA#262:E (a|ab|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#263:E (a|ab|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#264:E (a|ab|c|bcd){4,}(d*) ababcd NOMATCH +:HA#265:E (a|ab|c|bcd){0,10}(d*) ababcd (0,1)(0,1)(1,1) +:HA#266:E (a|ab|c|bcd){1,10}(d*) ababcd (0,1)(0,1)(1,1) +:HA#267:E (a|ab|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#268:E (a|ab|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#269:E (a|ab|c|bcd){4,10}(d*) ababcd NOMATCH +:HA#270:E (a|ab|c|bcd)*(d*) ababcd (0,1)(0,1)(1,1) +:HA#271:E (a|ab|c|bcd)+(d*) ababcd (0,1)(0,1)(1,1) + +# The above worked on Linux/GLIBC but the following often fail. +# They also trip up OS X / FreeBSD / NetBSD: + +#:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#280:E (ab|a|c|bcd){0,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#281:E (ab|a|c|bcd){1,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#282:E (ab|a|c|bcd){2,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(3,6)(6,6) +:HA#283:E (ab|a|c|bcd){3,}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +:HA#284:E (ab|a|c|bcd){4,}(d*) ababcd NOMATCH +#:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#285:E (ab|a|c|bcd){0,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#286:E (ab|a|c|bcd){1,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#287:E (ab|a|c|bcd){2,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(3,6)(6,6) +:HA#288:E (ab|a|c|bcd){3,10}(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +:HA#289:E (ab|a|c|bcd){4,10}(d*) ababcd NOMATCH +#:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(3,6)(6,6) +:HA#290:E (ab|a|c|bcd)*(d*) ababcd (0,6)(4,5)(5,6) RE2/Go +#:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(3,6)(6,6) +:HA#291:E (ab|a|c|bcd)+(d*) ababcd (0,6)(4,5)(5,6) RE2/Go diff --git a/regex/src/utf8.rs b/regex/src/utf8.rs new file mode 100644 index 000000000..ac38e6350 --- /dev/null +++ b/regex/src/utf8.rs @@ -0,0 +1,259 @@ +/// A few elementary UTF-8 encoding and decoding functions used by the matching +/// engines. +/// +/// In an ideal world, the matching engines operate on `&str` and we can just +/// lean on the standard library for all our UTF-8 needs. However, to support +/// byte based regexes (that can match on arbitrary bytes which may contain +/// UTF-8), we need to be capable of searching and decoding UTF-8 on a `&[u8]`. +/// The standard library doesn't really recognize this use case, so we have +/// to build it out ourselves. +/// +/// Should this be factored out into a separate crate? It seems independently +/// useful. There are other crates that already exist (e.g., `utf-8`) that have +/// overlapping use cases. Not sure what to do. + +use std::char; + +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO: u8 = 0b1100_0000; +const TAG_THREE: u8 = 0b1110_0000; +const TAG_FOUR: u8 = 0b1111_0000; + +/// Returns the smallest possible index of the next valid UTF-8 sequence +/// starting after `i`. +pub fn next_utf8(text: &[u8], i: usize) -> usize { + let b = match text.get(i) { + None => return i + 1, + Some(&b) => b, + }; + let inc = if b <= 0x7F { + 1 + } else if b <= 0b110_11111 { + 2 + } else if b <= 0b1110_1111 { + 3 + } else { + 4 + }; + i + inc +} + +/// Decode a single UTF-8 sequence into a single Unicode codepoint from `src`. +/// +/// If no valid UTF-8 sequence could be found, then `None` is returned. +/// Otherwise, the decoded codepoint and the number of bytes read is returned. +/// The number of bytes read (for a valid UTF-8 sequence) is guaranteed to be +/// 1, 2, 3 or 4. +/// +/// Note that a UTF-8 sequence is invalid if it is incorrect UTF-8, encodes a +/// codepoint that is out of range (surrogate codepoints are out of range) or +/// is not the shortest possible UTF-8 sequence for that codepoint. +#[inline] +pub fn decode_utf8(src: &[u8]) -> Option<(char, usize)> { + let b0 = match src.get(0) { + None => return None, + Some(&b) if b <= 0x7F => return Some((b as char, 1)), + Some(&b) => b, + }; + match b0 { + 0b110_00000 ... 0b110_11111 => { + if src.len() < 2 { + return None; + } + let b1 = src[1]; + if 0b11_000000 & b1 != TAG_CONT { + return None; + } + let cp = ((b0 & !TAG_TWO) as u32) << 6 + | ((b1 & !TAG_CONT) as u32); + match cp { + 0x80 ... 0x7FF => char::from_u32(cp).map(|cp| (cp, 2)), + _ => None, + } + } + 0b1110_0000 ... 0b1110_1111 => { + if src.len() < 3 { + return None; + } + let (b1, b2) = (src[1], src[2]); + if 0b11_000000 & b1 != TAG_CONT { + return None; + } + if 0b11_000000 & b2 != TAG_CONT { + return None; + } + let cp = ((b0 & !TAG_THREE) as u32) << 12 + | ((b1 & !TAG_CONT) as u32) << 6 + | ((b2 & !TAG_CONT) as u32); + match cp { + // char::from_u32 will disallow surrogate codepoints. + 0x800 ... 0xFFFF => char::from_u32(cp).map(|cp| (cp, 3)), + _ => None, + } + } + 0b11110_000 ... 0b11110_111 => { + if src.len() < 4 { + return None; + } + let (b1, b2, b3) = (src[1], src[2], src[3]); + if 0b11_000000 & b1 != TAG_CONT { + return None; + } + if 0b11_000000 & b2 != TAG_CONT { + return None; + } + if 0b11_000000 & b3 != TAG_CONT { + return None; + } + let cp = ((b0 & !TAG_FOUR) as u32) << 18 + | ((b1 & !TAG_CONT) as u32) << 12 + | ((b2 & !TAG_CONT) as u32) << 6 + | ((b3 & !TAG_CONT) as u32); + match cp { + 0x10000 ... 0x10FFFF => char::from_u32(cp).map(|cp| (cp, 4)), + _ => None, + } + } + _ => None, + } +} + +/// Like `decode_utf8`, but decodes the last UTF-8 sequence in `src` instead +/// of the first. +pub fn decode_last_utf8(src: &[u8]) -> Option<(char, usize)> { + if src.is_empty() { + return None; + } + let mut start = src.len() - 1; + if src[start] <= 0x7F { + return Some((src[start] as char, 1)); + } + while start > src.len().saturating_sub(4) { + start -= 1; + if is_start_byte(src[start]) { + break; + } + } + match decode_utf8(&src[start..]) { + None => None, + Some((_, n)) if n < src.len() - start => None, + Some((cp, n)) => Some((cp, n)), + } +} + +fn is_start_byte(b: u8) -> bool { + b & 0b11_000000 != 0b1_0000000 +} + +#[cfg(test)] +mod tests { + use std::str; + + use quickcheck::quickcheck; + + use super::{ + TAG_CONT, TAG_TWO, TAG_THREE, TAG_FOUR, + decode_utf8, decode_last_utf8, + }; + + #[test] + fn prop_roundtrip() { + fn p(given_cp: char) -> bool { + let mut tmp = [0; 4]; + let encoded_len = given_cp.encode_utf8(&mut tmp).len(); + let (got_cp, got_len) = decode_utf8(&tmp[..encoded_len]).unwrap(); + encoded_len == got_len && given_cp == got_cp + } + quickcheck(p as fn(char) -> bool) + } + + #[test] + fn prop_roundtrip_last() { + fn p(given_cp: char) -> bool { + let mut tmp = [0; 4]; + let encoded_len = given_cp.encode_utf8(&mut tmp).len(); + let (got_cp, got_len) = + decode_last_utf8(&tmp[..encoded_len]).unwrap(); + encoded_len == got_len && given_cp == got_cp + } + quickcheck(p as fn(char) -> bool) + } + + #[test] + fn prop_encode_matches_std() { + fn p(cp: char) -> bool { + let mut got = [0; 4]; + let n = cp.encode_utf8(&mut got).len(); + let expected = cp.to_string(); + &got[..n] == expected.as_bytes() + } + quickcheck(p as fn(char) -> bool) + } + + #[test] + fn prop_decode_matches_std() { + fn p(given_cp: char) -> bool { + let mut tmp = [0; 4]; + let n = given_cp.encode_utf8(&mut tmp).len(); + let (got_cp, _) = decode_utf8(&tmp[..n]).unwrap(); + let expected_cp = + str::from_utf8(&tmp[..n]).unwrap().chars().next().unwrap(); + got_cp == expected_cp + } + quickcheck(p as fn(char) -> bool) + } + + #[test] + fn prop_decode_last_matches_std() { + fn p(given_cp: char) -> bool { + let mut tmp = [0; 4]; + let n = given_cp.encode_utf8(&mut tmp).len(); + let (got_cp, _) = decode_last_utf8(&tmp[..n]).unwrap(); + let expected_cp = + str::from_utf8(&tmp[..n]).unwrap() + .chars().rev().next().unwrap(); + got_cp == expected_cp + } + quickcheck(p as fn(char) -> bool) + } + + #[test] + fn reject_invalid() { + // Invalid start byte + assert_eq!(decode_utf8(&[0xFF]), None); + // Surrogate pair + assert_eq!(decode_utf8(&[0xED, 0xA0, 0x81]), None); + // Invalid continuation byte. + assert_eq!(decode_utf8(&[0xD4, 0xC2]), None); + // Bad lengths + assert_eq!(decode_utf8(&[0xC3]), None); // 2 bytes + assert_eq!(decode_utf8(&[0xEF, 0xBF]), None); // 3 bytes + assert_eq!(decode_utf8(&[0xF4, 0x8F, 0xBF]), None); // 4 bytes + // Not a minimal UTF-8 sequence + assert_eq!(decode_utf8(&[TAG_TWO, TAG_CONT | b'a']), None); + assert_eq!(decode_utf8(&[TAG_THREE, TAG_CONT, TAG_CONT | b'a']), None); + assert_eq!(decode_utf8(&[ + TAG_FOUR, TAG_CONT, TAG_CONT, TAG_CONT | b'a', + ]), None); + } + + #[test] + fn reject_invalid_last() { + // Invalid start byte + assert_eq!(decode_last_utf8(&[0xFF]), None); + // Surrogate pair + assert_eq!(decode_last_utf8(&[0xED, 0xA0, 0x81]), None); + // Bad lengths + assert_eq!(decode_last_utf8(&[0xC3]), None); // 2 bytes + assert_eq!(decode_last_utf8(&[0xEF, 0xBF]), None); // 3 bytes + assert_eq!(decode_last_utf8(&[0xF4, 0x8F, 0xBF]), None); // 4 bytes + // Not a minimal UTF-8 sequence + assert_eq!(decode_last_utf8(&[TAG_TWO, TAG_CONT | b'a']), None); + assert_eq!(decode_last_utf8(&[ + TAG_THREE, TAG_CONT, TAG_CONT | b'a', + ]), None); + assert_eq!(decode_last_utf8(&[ + TAG_FOUR, TAG_CONT, TAG_CONT, TAG_CONT | b'a', + ]), None); + } +} diff --git a/regex/src/vector/avx2.rs b/regex/src/vector/avx2.rs new file mode 100644 index 000000000..db0532c3f --- /dev/null +++ b/regex/src/vector/avx2.rs @@ -0,0 +1,187 @@ +#![allow(dead_code)] + +use std::arch::x86_64::*; +use std::fmt; + +#[derive(Clone, Copy, Debug)] +pub struct AVX2VectorBuilder(()); + +impl AVX2VectorBuilder { + pub fn new() -> Option<AVX2VectorBuilder> { + if is_x86_feature_detected!("avx2") { + Some(AVX2VectorBuilder(())) + } else { + None + } + } + + /// Create a new u8x32 AVX2 vector where all of the bytes are set to + /// the given value. + #[inline] + pub fn u8x32_splat(self, n: u8) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { u8x32::splat(n) } + } + + /// Load 32 bytes from the given slice, with bounds checks. + #[inline] + pub fn u8x32_load_unaligned(self, slice: &[u8]) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { u8x32::load_unaligned(slice) } + } + + /// Load 32 bytes from the given slice, without bounds checks. + #[inline] + pub unsafe fn u8x32_load_unchecked_unaligned(self, slice: &[u8]) -> u8x32 { + // Safe because we know AVX2 is enabled, but still unsafe + // because we aren't doing bounds checks. + u8x32::load_unchecked_unaligned(slice) + } + + /// Load 32 bytes from the given slice, with bound and alignment checks. + #[inline] + pub fn u8x32_load(self, slice: &[u8]) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { u8x32::load(slice) } + } + + /// Load 32 bytes from the given slice, without bound or alignment checks. + #[inline] + pub unsafe fn u8x32_load_unchecked(self, slice: &[u8]) -> u8x32 { + // Safe because we know AVX2 is enabled, but still unsafe + // because we aren't doing bounds checks. + u8x32::load_unchecked(slice) + } +} + +#[derive(Clone, Copy)] +#[allow(non_camel_case_types)] +pub union u8x32 { + vector: __m256i, + bytes: [u8; 32], +} + +impl u8x32 { + #[inline] + unsafe fn splat(n: u8) -> u8x32 { + u8x32 { vector: _mm256_set1_epi8(n as i8) } + } + + #[inline] + unsafe fn load_unaligned(slice: &[u8]) -> u8x32 { + assert!(slice.len() >= 32); + u8x32::load_unchecked_unaligned(slice) + } + + #[inline] + unsafe fn load_unchecked_unaligned(slice: &[u8]) -> u8x32 { + let p = slice.as_ptr() as *const u8 as *const __m256i; + u8x32 { vector: _mm256_loadu_si256(p) } + } + + #[inline] + unsafe fn load(slice: &[u8]) -> u8x32 { + assert!(slice.len() >= 32); + assert!(slice.as_ptr() as usize % 32 == 0); + u8x32::load_unchecked(slice) + } + + #[inline] + unsafe fn load_unchecked(slice: &[u8]) -> u8x32 { + let p = slice.as_ptr() as *const u8 as *const __m256i; + u8x32 { vector: _mm256_load_si256(p) } + } + + #[inline] + pub fn extract(self, i: usize) -> u8 { + // Safe because `bytes` is always accessible. + unsafe { self.bytes[i] } + } + + #[inline] + pub fn replace(&mut self, i: usize, byte: u8) { + // Safe because `bytes` is always accessible. + unsafe { self.bytes[i] = byte; } + } + + #[inline] + pub fn shuffle(self, indices: u8x32) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + u8x32 { vector: _mm256_shuffle_epi8(self.vector, indices.vector) } + } + } + + #[inline] + pub fn ne(self, other: u8x32) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + let boolv = _mm256_cmpeq_epi8(self.vector, other.vector); + let ones = _mm256_set1_epi8(0xFF as u8 as i8); + u8x32 { vector: _mm256_andnot_si256(boolv, ones) } + } + } + + #[inline] + pub fn and(self, other: u8x32) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + u8x32 { vector: _mm256_and_si256(self.vector, other.vector) } + } + } + + #[inline] + pub fn movemask(self) -> u32 { + // Safe because we know AVX2 is enabled. + unsafe { + _mm256_movemask_epi8(self.vector) as u32 + } + } + + #[inline] + pub fn alignr_14(self, other: u8x32) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + // Credit goes to jneem for figuring this out: + // https://github.com/jneem/teddy/blob/9ab5e899ad6ef6911aecd3cf1033f1abe6e1f66c/src/x86/teddy_simd.rs#L145-L184 + // + // TL;DR avx2's PALIGNR instruction is actually just two 128-bit + // PALIGNR instructions, which is not what we want, so we need to + // do some extra shuffling. + let v = _mm256_permute2x128_si256(other.vector, self.vector, 0x21); + let v = _mm256_alignr_epi8(self.vector, v, 14); + u8x32 { vector: v } + } + } + + #[inline] + pub fn alignr_15(self, other: u8x32) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + // Credit goes to jneem for figuring this out: + // https://github.com/jneem/teddy/blob/9ab5e899ad6ef6911aecd3cf1033f1abe6e1f66c/src/x86/teddy_simd.rs#L145-L184 + // + // TL;DR avx2's PALIGNR instruction is actually just two 128-bit + // PALIGNR instructions, which is not what we want, so we need to + // do some extra shuffling. + let v = _mm256_permute2x128_si256(other.vector, self.vector, 0x21); + let v = _mm256_alignr_epi8(self.vector, v, 15); + u8x32 { vector: v } + } + } + + #[inline] + pub fn bit_shift_right_4(self) -> u8x32 { + // Safe because we know AVX2 is enabled. + unsafe { + u8x32 { vector: _mm256_srli_epi16(self.vector, 4) } + } + } +} + +impl fmt::Debug for u8x32 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Safe because `bytes` is always accessible. + unsafe { self.bytes.fmt(f) } + } +} diff --git a/regex/src/vector/mod.rs b/regex/src/vector/mod.rs new file mode 100644 index 000000000..2956f56db --- /dev/null +++ b/regex/src/vector/mod.rs @@ -0,0 +1,4 @@ +#[cfg(target_arch = "x86_64")] +pub mod avx2; +#[cfg(any(target_arch = "x86_64"))] +pub mod ssse3; diff --git a/regex/src/vector/ssse3.rs b/regex/src/vector/ssse3.rs new file mode 100644 index 000000000..0485657f0 --- /dev/null +++ b/regex/src/vector/ssse3.rs @@ -0,0 +1,192 @@ +#![allow(dead_code)] + +use std::arch::x86_64::*; +use std::fmt; + +/// A builder for SSSE3 empowered vectors. +/// +/// This builder represents a receipt that the SSSE3 target feature is enabled +/// on the currently running CPU. Namely, the only way to get a value of this +/// type is if the SSSE3 feature is enabled. +/// +/// This type can then be used to build vector types that use SSSE3 features +/// safely. +#[derive(Clone, Copy, Debug)] +pub struct SSSE3VectorBuilder(()); + +impl SSSE3VectorBuilder { + /// Create a new SSSE3 vector builder. + /// + /// If the SSSE3 feature is not enabled for the current target, then + /// return `None`. + pub fn new() -> Option<SSSE3VectorBuilder> { + if is_x86_feature_detected!("ssse3") { + Some(SSSE3VectorBuilder(())) + } else { + None + } + } + + /// Create a new u8x16 SSSE3 vector where all of the bytes are set to + /// the given value. + #[inline] + pub fn u8x16_splat(self, n: u8) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { u8x16::splat(n) } + } + + /// Load 16 bytes from the given slice, with bounds checks. + #[inline] + pub fn u8x16_load_unaligned(self, slice: &[u8]) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { u8x16::load_unaligned(slice) } + } + + /// Load 16 bytes from the given slice, without bounds checks. + #[inline] + pub unsafe fn u8x16_load_unchecked_unaligned(self, slice: &[u8]) -> u8x16 { + // Safe because we know SSSE3 is enabled, but still unsafe + // because we aren't doing bounds checks. + u8x16::load_unchecked_unaligned(slice) + } + + /// Load 16 bytes from the given slice, with bound and alignment checks. + #[inline] + pub fn u8x16_load(self, slice: &[u8]) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { u8x16::load(slice) } + } + + /// Load 16 bytes from the given slice, without bound or alignment checks. + #[inline] + pub unsafe fn u8x16_load_unchecked(self, slice: &[u8]) -> u8x16 { + // Safe because we know SSSE3 is enabled, but still unsafe + // because we aren't doing bounds checks. + u8x16::load_unchecked(slice) + } +} + +/// A u8x16 is a 128-bit vector with 16 single-byte lanes. +/// +/// It provides a safe API that uses only SSE2 or SSSE3 instructions. +/// The only way for callers to construct a value of this type is +/// through the SSSE3VectorBuilder type, and the only way to get a +/// SSSE3VectorBuilder is if the `ssse3` target feature is enabled. +/// +/// Note that generally speaking, all uses of this type should get +/// inlined, otherwise you probably have a performance bug. +#[derive(Clone, Copy)] +#[allow(non_camel_case_types)] +pub union u8x16 { + vector: __m128i, + bytes: [u8; 16], +} + +impl u8x16 { + #[inline] + unsafe fn splat(n: u8) -> u8x16 { + u8x16 { vector: _mm_set1_epi8(n as i8) } + } + + #[inline] + unsafe fn load_unaligned(slice: &[u8]) -> u8x16 { + assert!(slice.len() >= 16); + u8x16::load_unchecked(slice) + } + + #[inline] + unsafe fn load_unchecked_unaligned(slice: &[u8]) -> u8x16 { + let v = _mm_loadu_si128(slice.as_ptr() as *const u8 as *const __m128i); + u8x16 { vector: v } + } + + #[inline] + unsafe fn load(slice: &[u8]) -> u8x16 { + assert!(slice.len() >= 16); + assert!(slice.as_ptr() as usize % 16 == 0); + u8x16::load_unchecked(slice) + } + + #[inline] + unsafe fn load_unchecked(slice: &[u8]) -> u8x16 { + let v = _mm_load_si128(slice.as_ptr() as *const u8 as *const __m128i); + u8x16 { vector: v } + } + + #[inline] + pub fn extract(self, i: usize) -> u8 { + // Safe because `bytes` is always accessible. + unsafe { self.bytes[i] } + } + + #[inline] + pub fn replace(&mut self, i: usize, byte: u8) { + // Safe because `bytes` is always accessible. + unsafe { self.bytes[i] = byte; } + } + + #[inline] + pub fn shuffle(self, indices: u8x16) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + u8x16 { vector: _mm_shuffle_epi8(self.vector, indices.vector) } + } + } + + #[inline] + pub fn ne(self, other: u8x16) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + let boolv = _mm_cmpeq_epi8(self.vector, other.vector); + let ones = _mm_set1_epi8(0xFF as u8 as i8); + u8x16 { vector: _mm_andnot_si128(boolv, ones) } + } + } + + #[inline] + pub fn and(self, other: u8x16) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + u8x16 { vector: _mm_and_si128(self.vector, other.vector) } + } + } + + #[inline] + pub fn movemask(self) -> u32 { + // Safe because we know SSSE3 is enabled. + unsafe { + _mm_movemask_epi8(self.vector) as u32 + } + } + + #[inline] + pub fn alignr_14(self, other: u8x16) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + u8x16 { vector: _mm_alignr_epi8(self.vector, other.vector, 14) } + } + } + + #[inline] + pub fn alignr_15(self, other: u8x16) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + u8x16 { vector: _mm_alignr_epi8(self.vector, other.vector, 15) } + } + } + + #[inline] + pub fn bit_shift_right_4(self) -> u8x16 { + // Safe because we know SSSE3 is enabled. + unsafe { + u8x16 { vector: _mm_srli_epi16(self.vector, 4) } + } + } +} + +impl fmt::Debug for u8x16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Safe because `bytes` is always accessible. + unsafe { self.bytes.fmt(f) } + } +} diff --git a/regex/tests/api.rs b/regex/tests/api.rs new file mode 100644 index 000000000..e17afa933 --- /dev/null +++ b/regex/tests/api.rs @@ -0,0 +1,182 @@ +#[test] +fn empty_regex_empty_match() { + let re = regex!(""); + assert_eq!(vec![(0, 0)], findall!(re, "")); +} + +#[test] +fn empty_regex_nonempty_match() { + let re = regex!(""); + assert_eq!(vec![(0, 0), (1, 1), (2, 2), (3, 3)], findall!(re, "abc")); +} + +#[test] +fn one_zero_length_match() { + let re = regex!(r"\d*"); + assert_eq!(vec![(0, 0), (1, 2), (3, 4)], findall!(re, "a1b2")); +} + +#[test] +fn many_zero_length_match() { + let re = regex!(r"\d*"); + assert_eq!(vec![(0, 0), (1, 2), (3, 3), (4, 4), (5, 6)], + findall!(re, "a1bbb2")); +} + +#[test] +fn many_sequential_zero_length_match() { + let re = regex!(r"\d?"); + assert_eq!(vec![(0, 0), (1, 2), (2, 3), (4, 5), (6, 6)], + findall!(re, "a12b3c")); +} + +#[test] +fn quoted_bracket_set() { + let re = regex!(r"([\x{5b}\x{5d}])"); + assert_eq!(vec![(0, 1), (1, 2)], findall!(re, "[]")); + let re = regex!(r"([\[\]])"); + assert_eq!(vec![(0, 1), (1, 2)], findall!(re, "[]")); +} + +#[test] +fn first_range_starts_with_left_bracket() { + let re = regex!(r"([\[-z])"); + assert_eq!(vec![(0, 1), (1, 2)], findall!(re, "[]")); +} + +#[test] +fn range_ends_with_escape() { + let re = regex!(r"([\[-\x{5d}])"); + assert_eq!(vec![(0, 1), (1, 2)], findall!(re, "[]")); +} + +#[test] +fn empty_match_find_iter() { + let re = regex!(r".*?"); + assert_eq!(vec![(0, 0), (1, 1), (2, 2), (3, 3)], findall!(re, "abc")); +} + +#[test] +fn empty_match_captures_iter() { + let re = regex!(r".*?"); + let ms: Vec<_> = re.captures_iter(text!("abc")) + .map(|c| c.get(0).unwrap()) + .map(|m| (m.start(), m.end())) + .collect(); + assert_eq!(ms, vec![(0, 0), (1, 1), (2, 2), (3, 3)]); +} + +#[test] +fn capture_names() { + let re = regex!(r"(.)(?P<a>.)"); + assert_eq!(3, re.captures_len()); + assert_eq!((3, Some(3)), re.capture_names().size_hint()); + assert_eq!(vec![None, None, Some("a")], + re.capture_names().collect::<Vec<_>>()); +} + +#[test] +fn regex_string() { + assert_eq!(r"[a-zA-Z0-9]+", regex!(r"[a-zA-Z0-9]+").as_str()); + assert_eq!(r"[a-zA-Z0-9]+", &format!("{}", regex!(r"[a-zA-Z0-9]+"))); + assert_eq!(r"[a-zA-Z0-9]+", &format!("{:?}", regex!(r"[a-zA-Z0-9]+"))); +} + +#[test] +fn capture_index() { + let re = regex!(r"^(?P<name>.+)$"); + let cap = re.captures(t!("abc")).unwrap(); + assert_eq!(&cap[0], t!("abc")); + assert_eq!(&cap[1], t!("abc")); + assert_eq!(&cap["name"], t!("abc")); +} + +#[test] +#[should_panic] +#[cfg_attr(all(target_env = "msvc", target_pointer_width = "32"), ignore)] +fn capture_index_panic_usize() { + let re = regex!(r"^(?P<name>.+)$"); + let cap = re.captures(t!("abc")).unwrap(); + let _ = cap[2]; +} + +#[test] +#[should_panic] +#[cfg_attr(all(target_env = "msvc", target_pointer_width = "32"), ignore)] +fn capture_index_panic_name() { + let re = regex!(r"^(?P<name>.+)$"); + let cap = re.captures(t!("abc")).unwrap(); + let _ = cap["bad name"]; +} + +#[test] +fn capture_index_lifetime() { + // This is a test of whether the types on `caps["..."]` are general + // enough. If not, this will fail to typecheck. + fn inner(s: &str) -> usize { + let re = regex!(r"(?P<number>\d+)"); + let caps = re.captures(t!(s)).unwrap(); + caps["number"].len() + } + assert_eq!(3, inner("123")); +} + +#[test] +fn capture_misc() { + let re = regex!(r"(.)(?P<a>a)?(.)(?P<b>.)"); + let cap = re.captures(t!("abc")).unwrap(); + + assert_eq!(5, cap.len()); + + assert_eq!((0, 3), { let m = cap.get(0).unwrap(); (m.start(), m.end()) }); + assert_eq!(None, cap.get(2)); + assert_eq!((2, 3), { let m = cap.get(4).unwrap(); (m.start(), m.end()) }); + + assert_eq!(t!("abc"), match_text!(cap.get(0).unwrap())); + assert_eq!(None, cap.get(2)); + assert_eq!(t!("c"), match_text!(cap.get(4).unwrap())); + + assert_eq!(None, cap.name("a")); + assert_eq!(t!("c"), match_text!(cap.name("b").unwrap())); +} + +#[test] +fn sub_capture_matches() { + let re = regex!(r"([a-z])(([a-z])|([0-9]))"); + let cap = re.captures(t!("a5")).unwrap(); + let subs: Vec<_> = cap.iter().collect(); + + assert_eq!(5, subs.len()); + assert!(subs[0].is_some()); + assert!(subs[1].is_some()); + assert!(subs[2].is_some()); + assert!(subs[3].is_none()); + assert!(subs[4].is_some()); + + assert_eq!(t!("a5"), match_text!(subs[0].unwrap())); + assert_eq!(t!("a"), match_text!(subs[1].unwrap())); + assert_eq!(t!("5"), match_text!(subs[2].unwrap())); + assert_eq!(t!("5"), match_text!(subs[4].unwrap())); +} + +expand!(expand1, r"(?P<foo>\w+)", "abc", "$foo", "abc"); +expand!(expand2, r"(?P<foo>\w+)", "abc", "$0", "abc"); +expand!(expand3, r"(?P<foo>\w+)", "abc", "$1", "abc"); +expand!(expand4, r"(?P<foo>\w+)", "abc", "$$1", "$1"); +expand!(expand5, r"(?P<foo>\w+)", "abc", "$$foo", "$foo"); +expand!(expand6, r"(?P<a>\w+)\s+(?P<b>\d+)", + "abc 123", "$b$a", "123abc"); +expand!(expand7, r"(?P<a>\w+)\s+(?P<b>\d+)", + "abc 123", "z$bz$az", "z"); +expand!(expand8, r"(?P<a>\w+)\s+(?P<b>\d+)", + "abc 123", ".$b.$a.", ".123.abc."); +expand!(expand9, r"(?P<a>\w+)\s+(?P<b>\d+)", + "abc 123", " $b $a ", " 123 abc "); +expand!(expand10, r"(?P<a>\w+)\s+(?P<b>\d+)", + "abc 123", "$bz$az", ""); + +split!(split1, r"\s+", "a b\nc\td\n\t e", + &[t!("a"), t!("b"), t!("c"), t!("d"), t!("e")]); +split!(split2, r"\b", "a b c", + &[t!(""), t!("a"), t!(" "), t!("b"), t!(" "), t!("c")]); +split!(split3, r"a$", "a", &[t!("")]); diff --git a/regex/tests/api_str.rs b/regex/tests/api_str.rs new file mode 100644 index 000000000..410bd9036 --- /dev/null +++ b/regex/tests/api_str.rs @@ -0,0 +1,31 @@ +// These tests don't really make sense with the bytes API, so we only test them +// on the Unicode API. + +#[test] +fn empty_match_unicode_find_iter() { + // Tests that we still yield byte ranges at valid UTF-8 sequence boundaries + // even when we're susceptible to empty width matches. + let re = regex!(r".*?"); + assert_eq!(vec![(0, 0), (3, 3), (4, 4), (7, 7), (8, 8)], + findall!(re, "Ⅰ1Ⅱ2")); +} + +#[test] +fn empty_match_unicode_captures_iter() { + // Same as empty_match_unicode_find_iter, but tests capture iteration. + let re = regex!(r".*?"); + let ms: Vec<_> = re.captures_iter(text!("Ⅰ1Ⅱ2")) + .map(|c| c.get(0).unwrap()) + .map(|m| (m.start(), m.end())) + .collect(); + assert_eq!(vec![(0, 0), (3, 3), (4, 4), (7, 7), (8, 8)], ms); +} + +#[test] +fn match_as_str() { + let re = regex!(r"fo+"); + let caps = re.captures("barfoobar").unwrap(); + assert_eq!(caps.get(0).map(|m| m.as_str()), Some("foo")); + assert_eq!(caps.get(0).map(From::from), Some("foo")); + assert_eq!(caps.get(0).map(Into::into), Some("foo")); +} diff --git a/regex/tests/bytes.rs b/regex/tests/bytes.rs new file mode 100644 index 000000000..0b0f008d6 --- /dev/null +++ b/regex/tests/bytes.rs @@ -0,0 +1,72 @@ +// These are tests specifically crafted for regexes that can match arbitrary +// bytes. + +// A silly wrapper to make it possible to write and match raw bytes. +struct R<'a>(&'a [u8]); +impl<'a> R<'a> { fn as_bytes(&self) -> &'a [u8] { self.0 } } + +mat!(word_boundary, r"(?-u) \b", " δ", None); +mat!(word_boundary_unicode, r" \b", " δ", Some((0, 1))); +mat!(word_not_boundary, r"(?-u) \B", " δ", Some((0, 1))); +mat!(word_not_boundary_unicode, r" \B", " δ", None); + +mat!(perl_w_ascii, r"(?-u)\w+", "aδ", Some((0, 1))); +mat!(perl_w_unicode, r"\w+", "aδ", Some((0, 3))); +mat!(perl_d_ascii, r"(?-u)\d+", "1२३9", Some((0, 1))); +mat!(perl_d_unicode, r"\d+", "1२३9", Some((0, 8))); +mat!(perl_s_ascii, r"(?-u)\s+", " \u{1680}", Some((0, 1))); +mat!(perl_s_unicode, r"\s+", " \u{1680}", Some((0, 4))); + +// The first `(.+)` matches two Unicode codepoints, but can't match the 5th +// byte, which isn't valid UTF-8. The second (byte based) `(.+)` takes over and +// matches. +mat!(mixed1, r"(.+)(?-u)(.+)", R(b"\xCE\x93\xCE\x94\xFF"), + Some((0, 5)), Some((0, 4)), Some((4, 5))); + +mat!(case_ascii_one, r"(?i-u)a", "A", Some((0, 1))); +mat!(case_ascii_class, r"(?i-u)[a-z]+", "AaAaA", Some((0, 5))); +mat!(case_unicode, r"(?i)[a-z]+", "aA\u{212A}aA", Some((0, 7))); +mat!(case_not_unicode, r"(?i-u)[a-z]+", "aA\u{212A}aA", Some((0, 2))); + +mat!(negate_unicode, r"[^a]", "δ", Some((0, 2))); +mat!(negate_not_unicode, r"(?-u)[^a]", "δ", Some((0, 1))); + +// This doesn't match in a normal Unicode regex because the implicit preceding +// `.*?` is Unicode aware. +mat!(dotstar_prefix_not_unicode1, r"(?-u)a", R(b"\xFFa"), Some((1, 2))); +mat!(dotstar_prefix_not_unicode2, r"a", R(b"\xFFa"), Some((1, 2))); + +// Have fun with null bytes. +mat!(null_bytes, r"(?-u)(?P<cstr>[^\x00]+)\x00", + R(b"foo\x00"), Some((0, 4)), Some((0, 3))); + +// Test that lookahead operators work properly in the face of invalid UTF-8. +// See: https://github.com/rust-lang/regex/issues/277 +matiter!(invalidutf8_anchor1, + r"(?-u)\xcc?^", + R(b"\x8d#;\x1a\xa4s3\x05foobarX\\\x0f0t\xe4\x9b\xa4"), + (0, 0)); +matiter!(invalidutf8_anchor2, + r"(?-u)^\xf7|4\xff\d\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a##########[] d\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a\x8a##########\[] #####\x80\S7|$", + R(b"\x8d#;\x1a\xa4s3\x05foobarX\\\x0f0t\xe4\x9b\xa4"), + (22, 22)); +matiter!(invalidutf8_anchor3, + r"(?-u)^|ddp\xff\xffdddddlQd@\x80", + R(b"\x8d#;\x1a\xa4s3\x05foobarX\\\x0f0t\xe4\x9b\xa4"), + (0, 0)); + +// See https://github.com/rust-lang/regex/issues/303 +#[test] +fn negated_full_byte_range() { + assert!(::regex::bytes::Regex::new(r#"(?-u)[^\x00-\xff]"#).is_err()); +} + +matiter!(word_boundary_ascii1, r"(?-u:\B)x(?-u:\B)", "áxβ"); +matiter!(word_boundary_ascii2, r"(?-u:\B)", "0\u{7EF5E}", (2, 2), (3, 3), (4, 4), (5, 5)); + +// See: https://github.com/rust-lang/regex/issues/264 +mat!(ascii_boundary_no_capture, r"(?-u)\B", "\u{28f3e}", Some((0, 0))); +mat!(ascii_boundary_capture, r"(?-u)(\B)", "\u{28f3e}", Some((0, 0))); + +// See: https://github.com/rust-lang/regex/issues/271 +mat!(end_not_wb, r"$(?-u:\B)", "\u{5c124}\u{b576c}", Some((8, 8))); diff --git a/regex/tests/consistent.rs b/regex/tests/consistent.rs new file mode 100644 index 000000000..b61050e4b --- /dev/null +++ b/regex/tests/consistent.rs @@ -0,0 +1,213 @@ +use regex::internal::ExecBuilder; + +/// Given a regex, check if all of the backends produce the same +/// results on a number of different inputs. +/// +/// For now this just throws quickcheck at the problem, which +/// is not very good because it only really tests half of the +/// problem space. It is pretty unlikely that a random string +/// will match any given regex, so this will probably just +/// be checking that the different backends fail in the same +/// way. This is still worthwhile to test, but is definitely not +/// the whole story. +/// +/// TODO(ethan): In order to cover the other half of the problem +/// space, we should generate a random matching string by inspecting +/// the AST of the input regex. The right way to do this probably +/// involves adding a custom Arbitrary instance around a couple +/// of newtypes. That way we can respect the quickcheck size hinting +/// and shrinking and whatnot. +pub fn backends_are_consistent(re: &str) -> Result<u64, String> { + let standard_backends = vec![ + ("bounded_backtracking_re", + ExecBuilder::new(re) + .bounded_backtracking() + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + + ("pikevm_re", + ExecBuilder::new(re) + .nfa() + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + + ("default_re", + ExecBuilder::new(re) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + ]; + + let utf8bytes_backends = vec![ + ("bounded_backtracking_utf8bytes_re", + ExecBuilder::new(re) + .bounded_backtracking() + .bytes(true) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + + ("pikevm_utf8bytes_re", + ExecBuilder::new(re) + .nfa() + .bytes(true) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + + ("default_utf8bytes_re", + ExecBuilder::new(re) + .bytes(true) + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err))?), + ]; + + let bytes_backends = vec![ + ("bounded_backtracking_bytes_re", + ExecBuilder::new(re) + .bounded_backtracking() + .only_utf8(false) + .build() + .map(|exec| exec.into_byte_regex()) + .map_err(|err| format!("{}", err))?), + + ("pikevm_bytes_re", + ExecBuilder::new(re) + .nfa() + .only_utf8(false) + .build() + .map(|exec| exec.into_byte_regex()) + .map_err(|err| format!("{}", err))?), + + ("default_bytes_re", + ExecBuilder::new(re) + .only_utf8(false) + .build() + .map(|exec| exec.into_byte_regex()) + .map_err(|err| format!("{}", err))?), + ]; + + Ok(string_checker::check_backends(&standard_backends)? + + string_checker::check_backends(&utf8bytes_backends)? + + bytes_checker::check_backends(&bytes_backends)?) +} + +// +// A consistency checker parameterized by the input type (&str or &[u8]). +// + +macro_rules! checker { + ($module_name:ident, $regex_type:path, $mk_input:expr) => { + +mod $module_name { + use quickcheck; + use quickcheck::{TestResult, Arbitrary}; + + pub fn check_backends( + backends: &[(&str, $regex_type)] + ) -> Result<u64, String> { + let mut total_passed = 0; + for regex in backends[1..].iter() { + total_passed += quickcheck_regex_eq(&backends[0], regex)?; + } + + Ok(total_passed) + } + + fn quickcheck_regex_eq( + &(name1, ref re1): &(&str, $regex_type), + &(name2, ref re2): &(&str, $regex_type), + ) -> Result<u64, String> { + quickcheck::QuickCheck::new() + .quicktest(RegexEqualityTest::new(re1.clone(), re2.clone())) + .map_err(|err| + format!("{}(/{}/) and {}(/{}/) are inconsistent.\ + QuickCheck Err: {:?}", + name1, re1, name2, re2, err)) + } + + struct RegexEqualityTest { + re1: $regex_type, + re2: $regex_type, + } + impl RegexEqualityTest { + fn new(re1: $regex_type, re2: $regex_type) -> Self { + RegexEqualityTest { + re1: re1, + re2: re2, + } + } + } + + impl quickcheck::Testable for RegexEqualityTest { + fn result<G: quickcheck::Gen>(&self, gen: &mut G) -> TestResult { + let input = $mk_input(gen); + let input = &input; + + if self.re1.find(&input) != self.re2.find(input) { + return TestResult::error( + format!("find mismatch input={:?}", input)); + } + + let cap1 = self.re1.captures(input); + let cap2 = self.re2.captures(input); + match (cap1, cap2) { + (None, None) => {} + (Some(cap1), Some(cap2)) => { + for (c1, c2) in cap1.iter().zip(cap2.iter()) { + if c1 != c2 { + return TestResult::error( + format!("captures mismatch input={:?}", input)); + } + } + } + _ => return TestResult::error( + format!("captures mismatch input={:?}", input)), + } + + let fi1 = self.re1.find_iter(input); + let fi2 = self.re2.find_iter(input); + for (m1, m2) in fi1.zip(fi2) { + if m1 != m2 { + return TestResult::error( + format!("find_iter mismatch input={:?}", input)); + } + } + + let ci1 = self.re1.captures_iter(input); + let ci2 = self.re2.captures_iter(input); + for (cap1, cap2) in ci1.zip(ci2) { + for (c1, c2) in cap1.iter().zip(cap2.iter()) { + if c1 != c2 { + return TestResult::error( + format!("captures_iter mismatch input={:?}", input)); + } + } + } + + let s1 = self.re1.split(input); + let s2 = self.re2.split(input); + for (chunk1, chunk2) in s1.zip(s2) { + if chunk1 != chunk2 { + return TestResult::error( + format!("split mismatch input={:?}", input)); + } + } + + TestResult::from_bool(true) + } + } + +} // mod +} // rule case +} // macro_rules! + +checker!(string_checker, + ::regex::Regex, + |gen| String::arbitrary(gen)); +checker!(bytes_checker, + ::regex::bytes::Regex, + |gen| Vec::<u8>::arbitrary(gen)); diff --git a/regex/tests/crates_regex.rs b/regex/tests/crates_regex.rs new file mode 100644 index 000000000..1ccfe4710 --- /dev/null +++ b/regex/tests/crates_regex.rs @@ -0,0 +1,3129 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// DO NOT EDIT. Automatically generated by 'scripts/scrape_crates_io.py' +// on 2018-06-20 09:56:32.820354. + + + +// autoshutdown-0.1.0: r"\s*(\d+)(\w)\s*" +consistent!(autoshutdown_0, r"\s*(\d+)(\w)\s*"); + +// epub-1.1.1: r"/" +consistent!(epub_0, r"/"); + +// rpi-info-0.2.0: "^Revision\t+: ([0-9a-fA-F]+)" +consistent!(rpi_info_0, "^Revision\t+: ([0-9a-fA-F]+)"); + +// rpi-info-0.2.0: "Serial\t+: ([0-9a-fA-F]+)" +consistent!(rpi_info_1, "Serial\t+: ([0-9a-fA-F]+)"); + +// pnet_macros-0.21.0: r"^u([0-9]+)(be|le|he)?$" +consistent!(pnet_macros_0, r"^u([0-9]+)(be|le|he)?$"); + +// iban_validate-1.0.3: r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$" +consistent!(iban_validate_0, r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$"); + +// markifier-0.1.0: r".*\[(?P<percent>.+)%.*\].*" +consistent!(markifier_0, r".*\[(?P<percent>.+)%.*\].*"); + +// mallumo-0.3.0: r"(#include) (\S*)(.*)" +consistent!(mallumo_0, r"(#include) (\S*)(.*)"); + +// mallumo-0.3.0: r"(ERROR: \d+:)(\d+)(: )(.+)" +consistent!(mallumo_1, r"(ERROR: \d+:)(\d+)(: )(.+)"); + +// mallumo-0.3.0: r"(\d+\()(\d+)(?:\) : )(.+)" +consistent!(mallumo_2, r"(\d+\()(\d+)(?:\) : )(.+)"); + +// magnet_more-0.0.1: r"(.+?)(\[.*?\])?" +consistent!(magnet_more_0, r"(.+?)(\[.*?\])?"); + +// magnet_app-0.0.1: r":(?P<k>[a-zA-Z_]+)" +consistent!(magnet_app_0, r":(?P<k>[a-zA-Z_]+)"); + +// yubibomb-0.2.0: r"^\d{6}(?:\s*,\s*\d{6})*$" +consistent!(yubibomb_0, r"^\d{6}(?:\s*,\s*\d{6})*$"); + +// multirust-rs-0.0.4: r"[\\/]([^\\/?]+)(\?.*)?$" +consistent!(multirust_rs_0, r"[\\/]([^\\/?]+)(\?.*)?$"); + +// hueclient-0.3.2: "\"[a-z]*\":null" +consistent!(hueclient_0, "\"[a-z]*\":null"); + +// hueclient-0.3.2: ",+" +consistent!(hueclient_1, ",+"); + +// hueclient-0.3.2: ",\\}" +consistent!(hueclient_2, ",\\}"); + +// hueclient-0.3.2: "\\{," +consistent!(hueclient_3, "\\{,"); + +// aerial-0.1.0: r"[a-zA-Z_\$][a-zA-Z_0-9]*" +consistent!(aerial_0, r"[a-zA-Z_\$][a-zA-Z_0-9]*"); + +// aerial-0.1.0: r"thi[sng]+" +consistent!(aerial_1, r"thi[sng]+"); + +// rvue-0.1.0: r"(.+)\s+\((.+?)\)" +consistent!(rvue_0, r"(.+)\s+\((.+?)\)"); + +// rvue-0.1.0: r"([\d\.]+)\s*out\s*of\s*([\d\.]+)" +consistent!(rvue_1, r"([\d\.]+)\s*out\s*of\s*([\d\.]+)"); + +// rvue-0.1.0: r"^([\d\.]+)\s*(?:\(\))?$" +consistent!(rvue_2, r"^([\d\.]+)\s*(?:\(\))?$"); + +// rvue-0.1.0: r"([\d\.]+)\s*Points\s*Possible" +consistent!(rvue_3, r"([\d\.]+)\s*Points\s*Possible"); + +// rvue-0.1.0: r"([\d\.]+)\s*/\s*([\d\.]+)" +consistent!(rvue_4, r"([\d\.]+)\s*/\s*([\d\.]+)"); + +// rvsim-0.1.0: r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]" +consistent!(rvsim_0, r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]"); + +// nereon-0.1.4: "(.*[^\\\\])\\{\\}(.*)" +consistent!(nereon_0, "(.*[^\\\\])\\{\\}(.*)"); + +// next_episode-0.3.0: r"((?i)^(.+).s(\d+)e(\d+).*)$" +consistent!(next_episode_0, r"((?i)^(.+).s(\d+)e(\d+).*)$"); + +// migrant_lib-0.19.2: r"[^a-z0-9-]+" +consistent!(migrant_lib_0, r"[^a-z0-9-]+"); + +// migrant_lib-0.19.2: r"[0-9]{14}_[a-z0-9-]+" +consistent!(migrant_lib_1, r"[0-9]{14}_[a-z0-9-]+"); + +// migrant_lib-0.19.2: r"([0-9]{14}_)?[a-z0-9-]+" +consistent!(migrant_lib_2, r"([0-9]{14}_)?[a-z0-9-]+"); + +// minipre-0.2.0: "$_" +consistent!(minipre_0, "$_"); + +// minifier-0.0.13: r">\s+<" +consistent!(minifier_0, r">\s+<"); + +// minifier-0.0.13: r"\s{2,}|[\r\n]" +consistent!(minifier_1, r"\s{2,}|[\r\n]"); + +// minifier-0.0.13: r"<(style|script)[\w|\s].*?>" +consistent!(minifier_2, r"<(style|script)[\w|\s].*?>"); + +// minifier-0.0.13: "<!--(.|\n)*?-->" +consistent!(minifier_3, "<!--(.|\n)*?-->"); + +// minifier-0.0.13: r"<\w.*?>" +consistent!(minifier_4, r"<\w.*?>"); + +// minifier-0.0.13: r" \s+|\s +" +consistent!(minifier_5, r" \s+|\s +"); + +// minifier-0.0.13: r"\w\s+\w" +consistent!(minifier_6, r"\w\s+\w"); + +// minifier-0.0.13: r"'\s+>" +consistent!(minifier_7, r"'\s+>"); + +// minifier-0.0.13: r"\d\s+>" +consistent!(minifier_8, r"\d\s+>"); + +// ggp-rs-0.1.2: r"(?P<relation>\([^)]+\))|(?P<prop>[a-zA-Z0-9_]+)" +consistent!(ggp_rs_0, r"(?P<relation>\([^)]+\))|(?P<prop>[a-zA-Z0-9_]+)"); + +// ggp-rs-0.1.2: r"\((.*)\)." +consistent!(ggp_rs_1, r"\((.*)\)."); + +// poe-superfilter-0.2.0: "[A-Za-z0-9_]" +consistent!(poe_superfilter_0, "[A-Za-z0-9_]"); + +// poke-a-mango-0.5.0: r"(\d+)x(\d+)" +consistent!(poke_a_mango_0, r"(\d+)x(\d+)"); + +// pop3-rs-0.1.0: r"(?P<nmsg>\d+) (?P<size>\d+)" +consistent!(pop3_rs_0, r"(?P<nmsg>\d+) (?P<size>\d+)"); + +// pop3-rs-0.1.0: r"(?P<msgid>\d+) (?P<uidl>[\x21-\x7E]{1,70})" +consistent!(pop3_rs_1, r"(?P<msgid>\d+) (?P<uidl>[\x21-\x7E]{1,70})"); + +// pop3-rs-0.1.0: r"(<.*>)\r\n$" +consistent!(pop3_rs_2, r"(<.*>)\r\n$"); + +// pop3-rs-0.1.0: r"^(?P<status>\+OK|-ERR) (?P<statustext>.*)" +consistent!(pop3_rs_3, r"^(?P<status>\+OK|-ERR) (?P<statustext>.*)"); + +// pop3-1.0.6: r"^\.\r\n$" +consistent!(pop3_0, r"^\.\r\n$"); + +// pop3-1.0.6: r"\+OK(.*)" +consistent!(pop3_1, r"\+OK(.*)"); + +// pop3-1.0.6: r"-ERR(.*)" +consistent!(pop3_2, r"-ERR(.*)"); + +// pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" +consistent!(pop3_3, r"\+OK (\d+) (\d+)\r\n"); + +// pop3-1.0.6: r"(\d+) ([\x21-\x7e]+)\r\n" +consistent!(pop3_4, r"(\d+) ([\x21-\x7e]+)\r\n"); + +// pop3-1.0.6: r"\+OK (\d+) ([\x21-\x7e]+)\r\n" +consistent!(pop3_5, r"\+OK (\d+) ([\x21-\x7e]+)\r\n"); + +// pop3-1.0.6: r"(\d+) (\d+)\r\n" +consistent!(pop3_6, r"(\d+) (\d+)\r\n"); + +// pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" +consistent!(pop3_7, r"\+OK (\d+) (\d+)\r\n"); + +// polk-1.1.3: "github:(\\w+)/?(\\w+)?" +consistent!(polk_0, "github:(\\w+)/?(\\w+)?"); + +// geochunk-0.1.5: "^[0-9]{5}" +consistent!(geochunk_0, "^[0-9]{5}"); + +// generic-dns-update-1.1.4: r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))" +consistent!(generic_dns_update_0, r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))"); + +// generic-dns-update-1.1.4: r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))" +consistent!(generic_dns_update_1, r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))"); + +// generic-dns-update-1.1.4: r"<value><string>([0-9.]*)</string></value>" +consistent!(generic_dns_update_2, r"<value><string>([0-9.]*)</string></value>"); + +// generic-dns-update-1.1.4: r"<int>([0-9]+)</int>" +consistent!(generic_dns_update_3, r"<int>([0-9]+)</int>"); + +// generic-dns-update-1.1.4: r"<int>([0-9]+)</int>" +consistent!(generic_dns_update_4, r"<int>([0-9]+)</int>"); + +// generic-dns-update-1.1.4: r"<boolean>([0-1]*)</boolean>" +consistent!(generic_dns_update_5, r"<boolean>([0-1]*)</boolean>"); + +// generate-nix-pkg-0.3.0: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(generate_nix_pkg_0, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// generate-nix-pkg-0.3.0: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(generate_nix_pkg_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// genact-0.6.0: r"arch/([a-z0-9_])+/" +consistent!(genact_0, r"arch/([a-z0-9_])+/"); + +// genact-0.6.0: r"arch/([a-z0-9_])+/" +consistent!(genact_1, r"arch/([a-z0-9_])+/"); + +// cron_rs-0.1.6: r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$" +consistent!(cron_rs_0, r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$"); + +// systemfd-0.3.0: r"^([a-zA-Z]+)::(.+)$" +consistent!(systemfd_0, r"^([a-zA-Z]+)::(.+)$"); + +// symbolic-debuginfo-5.0.2: "__?hidden#\\d+_" +consistent!(symbolic_debuginfo_0, "__?hidden#\\d+_"); + +// symbolic-minidump-5.0.2: r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$" +consistent!(symbolic_minidump_0, r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$"); + +// graphql-idl-parser-0.1.1: "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" +consistent!(graphql_idl_parser_0, "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); + +// graphql-idl-parser-0.1.1: "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" +consistent!(graphql_idl_parser_1, "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); + +// graphql-idl-parser-0.1.1: "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*" +consistent!(graphql_idl_parser_2, "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*"); + +// graphql-idl-parser-0.1.1: "^(?u:!)" +consistent!(graphql_idl_parser_3, "^(?u:!)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\()" +consistent!(graphql_idl_parser_4, "^(?u:\\()"); + +// graphql-idl-parser-0.1.1: "^(?u:\\))" +consistent!(graphql_idl_parser_5, "^(?u:\\))"); + +// graphql-idl-parser-0.1.1: "^(?u:,)" +consistent!(graphql_idl_parser_6, "^(?u:,)"); + +// graphql-idl-parser-0.1.1: "^(?u::)" +consistent!(graphql_idl_parser_7, "^(?u::)"); + +// graphql-idl-parser-0.1.1: "^(?u:@)" +consistent!(graphql_idl_parser_8, "^(?u:@)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\[)" +consistent!(graphql_idl_parser_9, "^(?u:\\[)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\])" +consistent!(graphql_idl_parser_10, "^(?u:\\])"); + +// graphql-idl-parser-0.1.1: "^(?u:enum)" +consistent!(graphql_idl_parser_11, "^(?u:enum)"); + +// graphql-idl-parser-0.1.1: "^(?u:implements)" +consistent!(graphql_idl_parser_12, "^(?u:implements)"); + +// graphql-idl-parser-0.1.1: "^(?u:input)" +consistent!(graphql_idl_parser_13, "^(?u:input)"); + +// graphql-idl-parser-0.1.1: "^(?u:interface)" +consistent!(graphql_idl_parser_14, "^(?u:interface)"); + +// graphql-idl-parser-0.1.1: "^(?u:scalar)" +consistent!(graphql_idl_parser_15, "^(?u:scalar)"); + +// graphql-idl-parser-0.1.1: "^(?u:type)" +consistent!(graphql_idl_parser_16, "^(?u:type)"); + +// graphql-idl-parser-0.1.1: "^(?u:union)" +consistent!(graphql_idl_parser_17, "^(?u:union)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\{)" +consistent!(graphql_idl_parser_18, "^(?u:\\{)"); + +// graphql-idl-parser-0.1.1: "^(?u:\\})" +consistent!(graphql_idl_parser_19, "^(?u:\\})"); + +// grimoire-0.1.0: r"(?s)/\*(?P<config>.*?)\*/" +consistent!(grimoire_0, r"(?s)/\*(?P<config>.*?)\*/"); + +// phonenumber-0.2.0+8.9.0: r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?" +consistent!(phonenumber_0, r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?"); + +// phonenumber-0.2.0+8.9.0: r"[, \[\]]" +consistent!(phonenumber_1, r"[, \[\]]"); + +// phonenumber-0.2.0+8.9.0: r"[\\/] *x" +consistent!(phonenumber_2, r"[\\/] *x"); + +// phonenumber-0.2.0+8.9.0: r"[[\P{N}&&\P{L}]&&[^#]]+$" +consistent!(phonenumber_3, r"[[\P{N}&&\P{L}]&&[^#]]+$"); + +// phonenumber-0.2.0+8.9.0: r"(?:.*?[A-Za-z]){3}.*" +consistent!(phonenumber_4, r"(?:.*?[A-Za-z]){3}.*"); + +// phonenumber-0.2.0+8.9.0: r"(\D+)" +consistent!(phonenumber_5, r"(\D+)"); + +// phonenumber-0.2.0+8.9.0: r"(\$\d)" +consistent!(phonenumber_6, r"(\$\d)"); + +// phonenumber-0.2.0+8.9.0: r"\(?\$1\)?" +consistent!(phonenumber_7, r"\(?\$1\)?"); + +// phone_number-0.1.0: r"\D" +consistent!(phone_number_0, r"\D"); + +// phone_number-0.1.0: r"^0+" +consistent!(phone_number_1, r"^0+"); + +// phone_number-0.1.0: r"^89" +consistent!(phone_number_2, r"^89"); + +// phone_number-0.1.0: r"^8+" +consistent!(phone_number_3, r"^8+"); + +// phile-0.1.4: r"^ *(\^_*\^) *$" +consistent!(phile_0, r"^ *(\^_*\^) *$"); + +// phile-0.1.4: r"^[_\p{XID_Start}]$" +consistent!(phile_1, r"^[_\p{XID_Start}]$"); + +// phile-0.1.4: r"^\p{XID_Continue}$" +consistent!(phile_2, r"^\p{XID_Continue}$"); + +// uritemplate-0.1.2: "%25(?P<hex>[0-9a-fA-F][0-9a-fA-F])" +consistent!(uritemplate_0, "%25(?P<hex>[0-9a-fA-F][0-9a-fA-F])"); + +// urdf-rs-0.4.2: "^package://(\\w+)/" +consistent!(urdf_rs_0, "^package://(\\w+)/"); + +// url-match-0.1.7: r"(?P<key>[?&.])" +consistent!(url_match_0, r"(?P<key>[?&.])"); + +// url-match-0.1.7: r":(?P<key>[a-zA-Z0-9_-]+)" +consistent!(url_match_1, r":(?P<key>[a-zA-Z0-9_-]+)"); + +// tsm-sys-0.1.0: r"hello world" +consistent!(tsm_sys_0, r"hello world"); + +// deb-version-0.1.0: "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$" +consistent!(deb_version_0, "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$"); + +// debcargo-2.1.0: r"^(?i)(a|an|the)\s+" +consistent!(debcargo_0, r"^(?i)(a|an|the)\s+"); + +// debcargo-2.1.0: r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+" +consistent!(debcargo_1, r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+"); + +// feaders-0.2.0: r"^.*\.h$" +consistent!(feaders_0, r"^.*\.h$"); + +// feaders-0.2.0: r"^.*\.c$" +consistent!(feaders_1, r"^.*\.c$"); + +// feaders-0.2.0: r"^.*\.hpp$" +consistent!(feaders_2, r"^.*\.hpp$"); + +// feaders-0.2.0: r"^.*\.cc$" +consistent!(feaders_3, r"^.*\.cc$"); + +// feaders-0.2.0: r"^.*\.cpp$" +consistent!(feaders_4, r"^.*\.cpp$"); + +// hyperscan-0.1.6: r"CPtr\(\w+\)" +consistent!(hyperscan_0, r"CPtr\(\w+\)"); + +// hyperscan-0.1.6: r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$" +consistent!(hyperscan_1, r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$"); + +// hyperscan-0.1.6: r"RawDatabase<Block>\{db: \w+\}" +consistent!(hyperscan_2, r"RawDatabase<Block>\{db: \w+\}"); + +// hyperscan-0.1.6: r"RawSerializedDatabase\{p: \w+, len: \d+\}" +consistent!(hyperscan_3, r"RawSerializedDatabase\{p: \w+, len: \d+\}"); + +// ucd-parse-0.1.1: r"[0-9A-F]+" +consistent!(ucd_parse_0, r"[0-9A-F]+"); + +// afsort-0.2.0: r".*" +consistent!(afsort_0, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_1, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_2, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_3, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_4, r".*"); + +// afsort-0.2.0: r".*" +consistent!(afsort_5, r".*"); + +// afsort-0.2.0: r"^[a-z]+$" +consistent!(afsort_6, r"^[a-z]+$"); + +// afsort-0.2.0: r"^[a-z]+$" +consistent!(afsort_7, r"^[a-z]+$"); + +// tin-summer-1.21.4: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(tin_summer_0, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// tin-drummer-1.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$" +consistent!(tin_drummer_1, r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$"); + +// tin-drummer-1.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|\.js)$" +consistent!(tin_drummer_3, r".*?\.(stats|conf|h|out|cache.*|\.js)$"); + +// tin-drummer-1.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(tin_drummer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// tin-drummer-1.0.1: r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$" +consistent!(tin_drummer_5, r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$"); + +// tin-drummer-1.0.1: r".*?\.(ibc)$" +consistent!(tin_drummer_6, r".*?\.(ibc)$"); + +// tin-drummer-1.0.1: r"\.stack-work|dist-newstyle" +consistent!(tin_drummer_7, r"\.stack-work|dist-newstyle"); + +// timmy-0.3.0: r"_NET_WM_PID\(CARDINAL\) = (\d+)" +consistent!(timmy_0, r"_NET_WM_PID\(CARDINAL\) = (\d+)"); + +// timmy-0.3.0: r"today|yesterday|now" +consistent!(timmy_1, r"today|yesterday|now"); + +// timmy-0.3.0: r"(?P<day>\d{1,2})/(?P<month>\d{1,2})(/(?P<year>\d{4}|\d{2}))?" +consistent!(timmy_2, r"(?P<day>\d{1,2})/(?P<month>\d{1,2})(/(?P<year>\d{4}|\d{2}))?"); + +// timmy-0.3.0: r"(?P<n>\d+) (days?|ds?)(?P<ago>( ago)?)" +consistent!(timmy_3, r"(?P<n>\d+) (days?|ds?)(?P<ago>( ago)?)"); + +// timmy-0.3.0: r"(?P<hr>\d{2}):(?P<mins>\d{2})" +consistent!(timmy_4, r"(?P<hr>\d{2}):(?P<mins>\d{2})"); + +// tinfo-0.5.0: r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?" +consistent!(tinfo_0, r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?"); + +// tinfo-0.5.0: r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]" +consistent!(tinfo_1, r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]"); + +// timespan-0.0.4: r"(?:\\\{start\\\}|\\\{end\\\})" +consistent!(timespan_0, r"(?:\\\{start\\\}|\\\{end\\\})"); + +// timespan-0.0.4: r"(.*)\s+-\s+(.*)" +consistent!(timespan_1, r"(.*)\s+-\s+(.*)"); + +// timespan-0.0.4: r"(.*)\s+(\w+)$" +consistent!(timespan_2, r"(.*)\s+(\w+)$"); + +// timespan-0.0.4: r"(.*)\s+(\w+)$" +consistent!(timespan_3, r"(.*)\s+(\w+)$"); + +// timespan-0.0.4: r"(.*)\s+-\s+(.*)" +consistent!(timespan_4, r"(.*)\s+-\s+(.*)"); + +// titlecase-0.10.0: r"[[:lower:]]" +consistent!(titlecase_0, r"[[:lower:]]"); + +// tight-0.1.3: r"^\d+ (day|week|month|year)s?$" +consistent!(tight_0, r"^\d+ (day|week|month|year)s?$"); + +// tight-0.1.3: r"^\d+ (day|week|month|year)s?$" +consistent!(tight_1, r"^\d+ (day|week|month|year)s?$"); + +// yaml-0.2.1: r"^[-+]?(0|[1-9][0-9_]*)$" +consistent!(yaml_0, r"^[-+]?(0|[1-9][0-9_]*)$"); + +// yaml-0.2.1: r"^([-+]?)0o?([0-7_]+)$" +consistent!(yaml_1, r"^([-+]?)0o?([0-7_]+)$"); + +// yaml-0.2.1: r"^([-+]?)0x([0-9a-fA-F_]+)$" +consistent!(yaml_2, r"^([-+]?)0x([0-9a-fA-F_]+)$"); + +// yaml-0.2.1: r"^([-+]?)0b([0-1_]+)$" +consistent!(yaml_3, r"^([-+]?)0b([0-1_]+)$"); + +// yaml-0.2.1: r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$" +consistent!(yaml_4, r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$"); + +// yaml-0.2.1: r"^[+]?(\.inf|\.Inf|\.INF)$" +consistent!(yaml_5, r"^[+]?(\.inf|\.Inf|\.INF)$"); + +// yaml-0.2.1: r"^-(\.inf|\.Inf|\.INF)$" +consistent!(yaml_6, r"^-(\.inf|\.Inf|\.INF)$"); + +// yaml-0.2.1: r"^(\.nan|\.NaN|\.NAN)$" +consistent!(yaml_7, r"^(\.nan|\.NaN|\.NAN)$"); + +// yaml-0.2.1: r"^(null|Null|NULL|~)$" +consistent!(yaml_8, r"^(null|Null|NULL|~)$"); + +// yaml-0.2.1: r"^(true|True|TRUE|yes|Yes|YES)$" +consistent!(yaml_9, r"^(true|True|TRUE|yes|Yes|YES)$"); + +// yaml-0.2.1: r"^(false|False|FALSE|no|No|NO)$" +consistent!(yaml_10, r"^(false|False|FALSE|no|No|NO)$"); + +// kefia-0.1.0: r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$" +consistent!(kefia_0, r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$"); + +// risp-0.7.0: "^(\\s+|;.*?(\n|$))+" +consistent!(risp_0, "^(\\s+|;.*?(\n|$))+"); + +// risp-0.7.0: "^\".*?\"" +consistent!(risp_1, "^\".*?\""); + +// risp-0.7.0: r"^[^\s\{\}()\[\]]+" +consistent!(risp_2, r"^[^\s\{\}()\[\]]+"); + +// risp-0.7.0: r"^-?\d+" +consistent!(risp_3, r"^-?\d+"); + +// ripgrep-0.8.1: "^([0-9]+)([KMG])?$" +consistent!(ripgrep_0, "^([0-9]+)([KMG])?$"); + +// riquid-0.0.1: r"^\w+" +consistent!(riquid_0, r"^\w+"); + +// riquid-0.0.1: r"^\d+" +consistent!(riquid_1, r"^\d+"); + +// recursive_disassembler-2.1.2: r"\A(0x)?([a-fA-F0-9]+)\z" +consistent!(recursive_disassembler_0, r"\A(0x)?([a-fA-F0-9]+)\z"); + +// remake-0.1.0: r"^[a-zA-Z_][a-zA-Z0-9_]*" +consistent!(remake_0, r"^[a-zA-Z_][a-zA-Z0-9_]*"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_0, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_1, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_2, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_3, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_4, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_5, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)" +consistent!(regex_decode_6, r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_7, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" +consistent!(regex_decode_8, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_9, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_10, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_11, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_12, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" +consistent!(regex_decode_13, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); + +// regex-cache-0.2.0: "[0-9]{3}-[0-9]{3}-[0-9]{4}" +consistent!(regex_cache_0, "[0-9]{3}-[0-9]{3}-[0-9]{4}"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_1, r"^\d+$"); + +// regex-cache-0.2.0: r"^[a-z]+$" +consistent!(regex_cache_2, r"^[a-z]+$"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_3, r"^\d+$"); + +// regex-cache-0.2.0: r"^\d+$" +consistent!(regex_cache_4, r"^\d+$"); + +// regex_dfa-0.5.0: r"\d{4}-\d{2}-\d{2}" +consistent!(regex_dfa_0, r"\d{4}-\d{2}-\d{2}"); + +// reaper-2.0.0: r"^[0-9\p{L} _\\.]{3,16}$" +consistent!(reaper_0, r"^[0-9\p{L} _\\.]{3,16}$"); + +// retdec-0.1.0: r"^attachment; filename=(.+)$" +consistent!(retdec_0, r"^attachment; filename=(.+)$"); + +// renvsubst-0.1.2: r"(\\)(?P<head>\$[0-9A-Za-z_{])" +consistent!(renvsubst_0, r"(\\)(?P<head>\$[0-9A-Za-z_{])"); + +// renvsubst-0.1.2: r"\$([[:word:]]+)" +consistent!(renvsubst_1, r"\$([[:word:]]+)"); + +// renvsubst-0.1.2: r"\$\{([[:word:]]+)\}" +consistent!(renvsubst_2, r"\$\{([[:word:]]+)\}"); + +// rexpect-0.3.0: r"'[a-z]+'" +consistent!(rexpect_0, r"'[a-z]+'"); + +// rexpect-0.3.0: r"^\d{4}-\d{2}-\d{2}$" +consistent!(rexpect_1, r"^\d{4}-\d{2}-\d{2}$"); + +// rexpect-0.3.0: r"-\d{2}-" +consistent!(rexpect_2, r"-\d{2}-"); + +// luther-0.1.0: "^a(b|c)c*$" +consistent!(luther_0, "^a(b|c)c*$"); + +// little_boxes-1.6.0: r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]" +consistent!(little_boxes_0, r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]"); + +// libimagentrytag-0.8.0: "^[a-zA-Z]([a-zA-Z0-9_-]*)$" +consistent!(libimagentrytag_0, "^[a-zA-Z]([a-zA-Z0-9_-]*)$"); + +// libimaginteraction-0.8.0: r"^[Yy](\n?)$" +consistent!(libimaginteraction_0, r"^[Yy](\n?)$"); + +// libimaginteraction-0.8.0: r"^[Nn](\n?)$" +consistent!(libimaginteraction_1, r"^[Nn](\n?)$"); + +// libimagutil-0.8.0: "^(?P<KEY>([^=]*))=(.*)$" +consistent!(libimagutil_0, "^(?P<KEY>([^=]*))=(.*)$"); + +// libimagutil-0.8.0: "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$" +consistent!(libimagutil_1, "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$"); + +// linux_ip-0.1.0: r"\s+" +consistent!(linux_ip_0, r"\s+"); + +// linux_ip-0.1.0: r"\s*[\n\r]+\s*" +consistent!(linux_ip_1, r"\s*[\n\r]+\s*"); + +// linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" +consistent!(linux_ip_2, r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); + +// linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" +consistent!(linux_ip_3, r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); + +// linux_ip-0.1.0: r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$" +consistent!(linux_ip_4, r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$"); + +// linux_ip-0.1.0: r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$" +consistent!(linux_ip_5, r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$"); + +// linux_ip-0.1.0: r"\s*[\n\r]+\s*" +consistent!(linux_ip_6, r"\s*[\n\r]+\s*"); + +// linux_ip-0.1.0: r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$" +consistent!(linux_ip_7, r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$"); + +// linux_ip-0.1.0: r"\s*link/ether\s+([a-f0-9:]+)\s+.*" +consistent!(linux_ip_8, r"\s*link/ether\s+([a-f0-9:]+)\s+.*"); + +// linux_ip-0.1.0: r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*" +consistent!(linux_ip_9, r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*"); + +// linky-0.1.4: r"[^\w -]" +consistent!(linky_0, r"[^\w -]"); + +// linky-0.1.4: r"^(.*):(\d+): [^ ]* ([^ ]*)$" +consistent!(linky_1, r"^(.*):(\d+): [^ ]* ([^ ]*)$"); + +// limonite-0.2.1: r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$" +consistent!(limonite_0, r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$"); + +// process-queue-0.1.1: r"^[a-zA-Z]+$" +consistent!(process_queue_0, r"^[a-zA-Z]+$"); + +// pronghorn-0.1.2: r"^\{([a-zA-Z_]+)\}$" +consistent!(pronghorn_0, r"^\{([a-zA-Z_]+)\}$"); + +// protocol-ftp-client-0.1.1: "(?m:^(\\d{3}) (.+)\r$)" +consistent!(protocol_ftp_client_0, "(?m:^(\\d{3}) (.+)\r$)"); + +// protocol-ftp-client-0.1.1: "\"(.+)\"" +consistent!(protocol_ftp_client_1, "\"(.+)\""); + +// protocol-ftp-client-0.1.1: "(\\w+) [Tt]ype: (\\w+)" +consistent!(protocol_ftp_client_2, "(\\w+) [Tt]ype: (\\w+)"); + +// protocol-ftp-client-0.1.1: "(?m:^(\\d{3})-.+\r$)" +consistent!(protocol_ftp_client_3, "(?m:^(\\d{3})-.+\r$)"); + +// protocol-ftp-client-0.1.1: "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)" +consistent!(protocol_ftp_client_4, "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)"); + +// protocol-ftp-client-0.1.1: "(?m:^(.+)\r$)" +consistent!(protocol_ftp_client_5, "(?m:^(.+)\r$)"); + +// protocol-ftp-client-0.1.1: "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$" +consistent!(protocol_ftp_client_6, "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$"); + +// article-date-extractor-0.1.1: r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})" +consistent!(article_date_extractor_0, r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})"); + +// article-date-extractor-0.1.1: r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date" +consistent!(article_date_extractor_1, r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date"); + +// arthas_plugin-0.1.1: r"type\((.*)\)" +consistent!(arthas_plugin_0, r"type\((.*)\)"); + +// arthas_plugin-0.1.1: r"Vec<(.*)>" +consistent!(arthas_plugin_1, r"Vec<(.*)>"); + +// arthas_plugin-0.1.1: r"Option<(.*)>" +consistent!(arthas_plugin_2, r"Option<(.*)>"); + +// arthas_plugin-0.1.1: r"HashMap<[a-z0-9A-Z]+, *(.*)>" +consistent!(arthas_plugin_3, r"HashMap<[a-z0-9A-Z]+, *(.*)>"); + +// arthas_derive-0.1.0: "Vec *< *(.*) *>" +consistent!(arthas_derive_0, "Vec *< *(.*) *>"); + +// arthas_derive-0.1.0: r"Option *< *(.*) *>" +consistent!(arthas_derive_1, r"Option *< *(.*) *>"); + +// arthas_derive-0.1.0: r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>" +consistent!(arthas_derive_2, r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>"); + +// arpabet-0.2.0: r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$" +consistent!(arpabet_0, r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$"); + +// arpabet-0.2.0: r"^;;;\s+" +consistent!(arpabet_1, r"^;;;\s+"); + +// glossy_codegen-0.2.0: r"/\*.*?\*/|//.*" +consistent!(glossy_codegen_0, r"/\*.*?\*/|//.*"); + +// glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$" +consistent!(glossy_codegen_1, "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$"); + +// glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$" +consistent!(glossy_codegen_2, "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$"); + +// glossy_codegen-0.2.0: r"^\s*#\s*version\s+(\d+)" +consistent!(glossy_codegen_3, r"^\s*#\s*version\s+(\d+)"); + +// glossy_codegen-0.2.0: r"^\s*$" +consistent!(glossy_codegen_4, r"^\s*$"); + +// gluster-1.0.1: r"(?P<addr>via \S+)" +consistent!(gluster_0, r"(?P<addr>via \S+)"); + +// gluster-1.0.1: r"(?P<src>src \S+)" +consistent!(gluster_1, r"(?P<src>src \S+)"); + +// gl_helpers-0.1.7: r"(.*)\[\d+\]" +consistent!(gl_helpers_0, r"(.*)\[\d+\]"); + +// gl_helpers-0.1.7: r"(\d+).(\d+)" +consistent!(gl_helpers_1, r"(\d+).(\d+)"); + +// glr-parser-0.0.1: r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])" +consistent!(glr_parser_0, r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])"); + +// glr-parser-0.0.1: r"^\w+$" +consistent!(glr_parser_1, r"^\w+$"); + +// glr-parser-0.0.1: "'[^']+'" +consistent!(glr_parser_2, "'[^']+'"); + +// hoodlum-0.5.0: r"(?m)//.*" +consistent!(hoodlum_0, r"(?m)//.*"); + +// form-checker-0.2.2: r"^1\d{10}$" +consistent!(form_checker_0, r"^1\d{10}$"); + +// form-checker-0.2.2: r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$" +consistent!(form_checker_1, r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$"); + +// wikibase-0.2.0: r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)" +consistent!(wikibase_0, r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)"); + +// wifiscanner-0.3.6: r"Cell [0-9]{2,} - Address:" +consistent!(wifiscanner_0, r"Cell [0-9]{2,} - Address:"); + +// wifiscanner-0.3.6: r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}" +consistent!(wifiscanner_1, r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}"); + +// wifiscanner-0.3.6: r"Signal level=(\d+)/100" +consistent!(wifiscanner_2, r"Signal level=(\d+)/100"); + +// bbcode-1.0.2: r"(?s)\[b\](.*?)\[/b\]" +consistent!(bbcode_0, r"(?s)\[b\](.*?)\[/b\]"); + +// bbcode-1.0.2: r"(?s)\[i\](.*?)\[/i\]" +consistent!(bbcode_1, r"(?s)\[i\](.*?)\[/i\]"); + +// bbcode-1.0.2: r"(?s)\[u\](.*?)\[/u\]" +consistent!(bbcode_2, r"(?s)\[u\](.*?)\[/u\]"); + +// bbcode-1.0.2: r"(?s)\[s\](.*?)\[/s\]" +consistent!(bbcode_3, r"(?s)\[s\](.*?)\[/s\]"); + +// bbcode-1.0.2: r"(?s)\[size=(\d+)](.*?)\[/size\]" +consistent!(bbcode_4, r"(?s)\[size=(\d+)](.*?)\[/size\]"); + +// bbcode-1.0.2: r"(?s)\[color=(.+)](.*?)\[/color\]" +consistent!(bbcode_5, r"(?s)\[color=(.+)](.*?)\[/color\]"); + +// bbcode-1.0.2: r"(?s)\[center\](.*?)\[/center\]" +consistent!(bbcode_6, r"(?s)\[center\](.*?)\[/center\]"); + +// bbcode-1.0.2: r"(?s)\[left\](.*?)\[/left\]" +consistent!(bbcode_7, r"(?s)\[left\](.*?)\[/left\]"); + +// bbcode-1.0.2: r"(?s)\[right\](.*?)\[/right\]" +consistent!(bbcode_8, r"(?s)\[right\](.*?)\[/right\]"); + +// bbcode-1.0.2: r"(?s)\[table\](.*?)\[/table\]" +consistent!(bbcode_9, r"(?s)\[table\](.*?)\[/table\]"); + +// bbcode-1.0.2: r"(?s)\[td\](.*?)\[/td\]" +consistent!(bbcode_10, r"(?s)\[td\](.*?)\[/td\]"); + +// bbcode-1.0.2: r"(?s)\[tr\](.*?)\[/tr\]" +consistent!(bbcode_11, r"(?s)\[tr\](.*?)\[/tr\]"); + +// bbcode-1.0.2: r"(?s)\[th\](.*?)\[/th\]" +consistent!(bbcode_12, r"(?s)\[th\](.*?)\[/th\]"); + +// bbcode-1.0.2: r"(?s)\[url\](.*?)\[/url\]" +consistent!(bbcode_13, r"(?s)\[url\](.*?)\[/url\]"); + +// bbcode-1.0.2: r"(?s)\[url=(.+)\](.*?)\[/url\]" +consistent!(bbcode_14, r"(?s)\[url=(.+)\](.*?)\[/url\]"); + +// bbcode-1.0.2: r"(?s)\[quote\](.*?)\[/quote\]" +consistent!(bbcode_15, r"(?s)\[quote\](.*?)\[/quote\]"); + +// bbcode-1.0.2: r"(?s)\[quote=(.+)\](.*?)\[/quote\]" +consistent!(bbcode_16, r"(?s)\[quote=(.+)\](.*?)\[/quote\]"); + +// bbcode-1.0.2: r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_17, r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_18, r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[img(\b.*)?\](.*?)\[/img\]" +consistent!(bbcode_19, r"(?s)\[img(\b.*)?\](.*?)\[/img\]"); + +// bbcode-1.0.2: r"(?s)\[ol\](.*?)\[/ol\]" +consistent!(bbcode_20, r"(?s)\[ol\](.*?)\[/ol\]"); + +// bbcode-1.0.2: r"(?s)\[ul\](.*?)\[/ul\]" +consistent!(bbcode_21, r"(?s)\[ul\](.*?)\[/ul\]"); + +// bbcode-1.0.2: r"(?s)\[list\](.*?)\[/list\]" +consistent!(bbcode_22, r"(?s)\[list\](.*?)\[/list\]"); + +// bbcode-1.0.2: r"(?s)\[youtube\](.*?)\[/youtube\]" +consistent!(bbcode_23, r"(?s)\[youtube\](.*?)\[/youtube\]"); + +// bbcode-1.0.2: r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]" +consistent!(bbcode_24, r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]"); + +// bbcode-1.0.2: r"(?s)\[li\](.*?)\[/li\]" +consistent!(bbcode_25, r"(?s)\[li\](.*?)\[/li\]"); + +// block-utils-0.5.0: r"loop\d+" +consistent!(block_utils_0, r"loop\d+"); + +// block-utils-0.5.0: r"ram\d+" +consistent!(block_utils_1, r"ram\d+"); + +// block-utils-0.5.0: r"md\d+" +consistent!(block_utils_2, r"md\d+"); + +// kvvliveapi-0.1.0: r"^([1-9]) min$" +consistent!(kvvliveapi_0, r"^([1-9]) min$"); + +// rfc822_sanitizer-0.3.3: r"(\d{2}):(\d{2}):(\d{2})" +consistent!(rfc822_sanitizer_0, r"(\d{2}):(\d{2}):(\d{2})"); + +// rfc822_sanitizer-0.3.3: r"(\d{1,2}):(\d{1,2}):(\d{1,2})" +consistent!(rfc822_sanitizer_1, r"(\d{1,2}):(\d{1,2}):(\d{1,2})"); + +// faker-0.0.4: r"[2-9]" +consistent!(faker_0, r"[2-9]"); + +// faker-0.0.4: r"[1-9]" +consistent!(faker_1, r"[1-9]"); + +// faker-0.0.4: r"[0-9]" +consistent!(faker_2, r"[0-9]"); + +// faker-0.0.4: r"\d{10}" +consistent!(faker_3, r"\d{10}"); + +// faker-0.0.4: r"\d{1}" +consistent!(faker_4, r"\d{1}"); + +// faker-0.0.4: r"^\w+" +consistent!(faker_5, r"^\w+"); + +// faker-0.0.4: r"^\w+" +consistent!(faker_6, r"^\w+"); + +// faker-0.0.4: r"^(\w+\.? ?){2,3}$" +consistent!(faker_7, r"^(\w+\.? ?){2,3}$"); + +// faker-0.0.4: r"^[A-Z][a-z]+\.?$" +consistent!(faker_8, r"^[A-Z][a-z]+\.?$"); + +// faker-0.0.4: r"^[A-Z][A-Za-z]*\.?$" +consistent!(faker_9, r"^[A-Z][A-Za-z]*\.?$"); + +// faker-0.0.4: r"http://lorempixel.com/100/100/\w+" +consistent!(faker_10, r"http://lorempixel.com/100/100/\w+"); + +// faker-0.0.4: r"http://lorempixel.com/100/100/cats" +consistent!(faker_11, r"http://lorempixel.com/100/100/cats"); + +// fancy-regex-0.1.0: "(?i:ß)" +consistent!(fancy_regex_0, "(?i:ß)"); + +// fancy-regex-0.1.0: "(?i:\\x{0587})" +consistent!(fancy_regex_1, "(?i:\\x{0587})"); + +// fancy-regex-0.1.0: "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})" +consistent!(fancy_regex_2, "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})"); + +// fancy-prompt-0.1.5: r"/([^/])[^/]+/" +consistent!(fancy_prompt_0, r"/([^/])[^/]+/"); + +// fancy-prompt-0.1.5: r"^([^:]+):.*?(?::([^:]+))?$" +consistent!(fancy_prompt_1, r"^([^:]+):.*?(?::([^:]+))?$"); + +// fanta-0.2.0: r"^(/?__\w+__)/(.*)" +consistent!(fanta_0, r"^(/?__\w+__)/(.*)"); + +// fanta-cli-0.1.1: r"(.)([A-Z])" +consistent!(fanta_cli_0, r"(.)([A-Z])"); + +// fanta-cli-0.1.1: "\\{:[^\\s]+\\}" +consistent!(fanta_cli_1, "\\{:[^\\s]+\\}"); + +// amethyst_tools-0.7.1: "(?P<last>[^\r])\n" +consistent!(amethyst_tools_0, "(?P<last>[^\r])\n"); + +// amigo-0.3.1: r"^-?\d+(\.\d)?" +consistent!(amigo_0, r"^-?\d+(\.\d)?"); + +// amigo-0.3.1: r"^[a-zA-Z_]+[\w-]*[!?_]?" +consistent!(amigo_1, r"^[a-zA-Z_]+[\w-]*[!?_]?"); + +// amigo-0.3.1: r"^\(" +consistent!(amigo_2, r"^\("); + +// amigo-0.3.1: r"^\)" +consistent!(amigo_3, r"^\)"); + +// amigo-0.3.1: r"^\s+" +consistent!(amigo_4, r"^\s+"); + +// ethcore-logger-1.12.0: "\x1b\\[[^m]+m" +consistent!(ethcore_logger_0, "\x1b\\[[^m]+m"); + +// dash2html-1.0.1: r"__.*?__" +consistent!(dash2html_0, r"__.*?__"); + +// dash2html-1.0.1: r"(?i)@(?:time|clipboard|cursor|date)" +consistent!(dash2html_1, r"(?i)@(?:time|clipboard|cursor|date)"); + +// os_type-2.0.0: r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$" +consistent!(os_type_0, r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$"); + +// os_type-2.0.0: r"ProductName:\s([\w\s]+)\n" +consistent!(os_type_1, r"ProductName:\s([\w\s]+)\n"); + +// os_type-2.0.0: r"ProductVersion:\s(\w+\.\w+\.\w+)" +consistent!(os_type_2, r"ProductVersion:\s(\w+\.\w+\.\w+)"); + +// os_type-2.0.0: r"BuildVersion:\s(\w+)" +consistent!(os_type_3, r"BuildVersion:\s(\w+)"); + +// os_type-2.0.0: r"(\w+) Linux release" +consistent!(os_type_4, r"(\w+) Linux release"); + +// os_type-2.0.0: r"release\s([\w\.]+)" +consistent!(os_type_5, r"release\s([\w\.]+)"); + +// os_type-2.0.0: r"Distributor ID:\s(\w+)" +consistent!(os_type_6, r"Distributor ID:\s(\w+)"); + +// os_type-2.0.0: r"Release:\s([\w\.]+)" +consistent!(os_type_7, r"Release:\s([\w\.]+)"); + +// bindgen-0.37.0: r"typename type\-parameter\-\d+\-\d+::.+" +consistent!(bindgen_0, r"typename type\-parameter\-\d+\-\d+::.+"); + +// imap-0.8.1: "^+(.*)\r\n" +consistent!(imap_0, "^+(.*)\r\n"); + +// image-base64-0.1.0: r"^ffd8ffe0" +consistent!(image_base64_0, r"^ffd8ffe0"); + +// image-base64-0.1.0: r"^89504e47" +consistent!(image_base64_1, r"^89504e47"); + +// image-base64-0.1.0: r"^47494638" +consistent!(image_base64_2, r"^47494638"); + +// json-pointer-0.3.2: "^(/([^/~]|~[01])*)*$" +consistent!(json_pointer_0, "^(/([^/~]|~[01])*)*$"); + +// json-pointer-0.3.2: "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$" +consistent!(json_pointer_1, "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$"); + +// mysql_common-0.7.0: r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB" +consistent!(mysql_common_0, r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB"); + +// mysql_common-0.7.0: r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)" +consistent!(mysql_common_1, r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)"); + +// government_id-0.1.0: r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$" +consistent!(government_id_0, r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$"); + +// ohmers-0.1.1: r"UniqueIndexViolation: (\w+)" +consistent!(ohmers_0, r"UniqueIndexViolation: (\w+)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_0, r"(.*) you are (.*)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_1, r"(.*) you are (.*)"); + +// eliza-1.0.0: r"(.*) you are (.*)" +consistent!(eliza_2, r"(.*) you are (.*)"); + +// chema-0.0.5: "^\\s*\\*" +consistent!(chema_0, "^\\s*\\*"); + +// chema-0.0.5: "^\\s*@(\\w+)\\s+(.*)" +consistent!(chema_1, "^\\s*@(\\w+)\\s+(.*)"); + +// chord3-0.3.0: r"^\s*#" +consistent!(chord3_0, r"^\s*#"); + +// chord3-0.3.0: r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}" +consistent!(chord3_1, r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}"); + +// chord3-0.3.0: r"\{(eot|end_of_tab):?\s*" +consistent!(chord3_2, r"\{(eot|end_of_tab):?\s*"); + +// chord3-0.3.0: r"([^\[]*)(?:\[([^\]]*)\])?" +consistent!(chord3_3, r"([^\[]*)(?:\[([^\]]*)\])?"); + +// checkmail-0.1.1: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" +consistent!(checkmail_0, "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"); + +// cntk-0.2.1: r"\b\w\w+\b" +consistent!(cntk_0, r"\b\w\w+\b"); + +// cntk-0.2.1: r"\b\w\w+\b" +consistent!(cntk_1, r"\b\w\w+\b"); + +// cniguru-0.1.0: r"\(id: (\d+)\)" +consistent!(cniguru_0, r"\(id: (\d+)\)"); + +// upm_lib-0.3.0: r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$" +consistent!(upm_lib_0, r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$"); + +// avro-0.2.1: r"^\s*(\*+(\s+))?" +consistent!(avro_0, r"^\s*(\*+(\s+))?"); + +// avro-0.2.1: r"^\s*(\*+)?" +consistent!(avro_1, r"^\s*(\*+)?"); + +// nomi-0.0.2: "[0-9]+" +consistent!(nomi_0, "[0-9]+"); + +// nodes-0.1.0: "([0-9]+)@(?:nodes|n)?:([^@]+)?" +consistent!(nodes_0, "([0-9]+)@(?:nodes|n)?:([^@]+)?"); + +// not-stakkr-1.0.0: r"(?i)in (\d+) (second|minute|hour|day|week)s?" +consistent!(not_stakkr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); + +// notetxt-0.0.1: "^([A-Za-z0-9 -_:]+)\n-+\n" +consistent!(notetxt_0, "^([A-Za-z0-9 -_:]+)\n-+\n"); + +// nail-0.1.0-pre.0: r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$" +consistent!(nail_0, r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$"); + +// nail-0.1.0-pre.0: r"^-?[0-9]+$" +consistent!(nail_1, r"^-?[0-9]+$"); + +// askalono-0.2.0: r"[^\w\s\pP]+" +consistent!(askalono_0, r"[^\w\s\pP]+"); + +// askalono-0.2.0: r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+" +consistent!(askalono_1, r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+"); + +// askalono-0.2.0: r"\p{Pd}+" +consistent!(askalono_2, r"\p{Pd}+"); + +// askalono-0.2.0: r"\p{Ps}+" +consistent!(askalono_3, r"\p{Ps}+"); + +// askalono-0.2.0: r"\p{Pe}+" +consistent!(askalono_4, r"\p{Pe}+"); + +// askalono-0.2.0: r"\p{Pc}+" +consistent!(askalono_5, r"\p{Pc}+"); + +// askalono-0.2.0: r"[©Ⓒⓒ]" +consistent!(askalono_6, r"[©Ⓒⓒ]"); + +// askalono-0.2.0: r"[\r\n\v\f]" +consistent!(askalono_7, r"[\r\n\v\f]"); + +// askalono-0.2.0: r"\n{3,}" +consistent!(askalono_8, r"\n{3,}"); + +// askalono-0.2.0: r"[^\w\s]+" +consistent!(askalono_9, r"[^\w\s]+"); + +// askalono-0.2.0: r"\s+" +consistent!(askalono_10, r"\s+"); + +// assembunny_plus-0.0.3: r"[^0-9a-zA-Z_]" +consistent!(assembunny_plus_0, r"[^0-9a-zA-Z_]"); + +// assembunny_plus-0.0.3: r"[0-9]" +consistent!(assembunny_plus_1, r"[0-9]"); + +// salt-compressor-0.4.0: r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$" +consistent!(salt_compressor_0, r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$"); + +// sabisabi-0.4.1: r"</?[^>]+?>" +consistent!(sabisabi_0, r"</?[^>]+?>"); + +// sabisabi-0.4.1: r"\([^)]*\)" +consistent!(sabisabi_1, r"\([^)]*\)"); + +// sassers-0.13.5-h28: "@import \"([^\"]*)\";" +consistent!(sassers_0, "@import \"([^\"]*)\";"); + +// shadowsocks-0.6.2: r"[A-Za-z\d-]{1,63}$" +consistent!(shadowsocks_0, r"[A-Za-z\d-]{1,63}$"); + +// shkeleton-0.1.5: "[abc]+" +consistent!(shkeleton_0, "[abc]+"); + +// shellwords-0.1.0: r"([^A-Za-z0-9_\-.,:/@\n])" +consistent!(shellwords_0, r"([^A-Za-z0-9_\-.,:/@\n])"); + +// shellwords-0.1.0: r"\n" +consistent!(shellwords_1, r"\n"); + +// shush-0.1.5: "(?P<num>[0-9]+)(?P<units>[dhms])" +consistent!(shush_0, "(?P<num>[0-9]+)(?P<units>[dhms])"); + +// woothee-0.8.0: r"(?:Chrome|CrMo|CriOS)/([.0-9]+)" +consistent!(woothee_0, r"(?:Chrome|CrMo|CriOS)/([.0-9]+)"); + +// woothee-0.8.0: r"Vivaldi/([.0-9]+)" +consistent!(woothee_1, r"Vivaldi/([.0-9]+)"); + +// woothee-0.8.0: r"Firefox/([.0-9]+)" +consistent!(woothee_2, r"Firefox/([.0-9]+)"); + +// woothee-0.8.0: r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$" +consistent!(woothee_3, r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$"); + +// woothee-0.8.0: r"FxiOS/([.0-9]+)" +consistent!(woothee_4, r"FxiOS/([.0-9]+)"); + +// woothee-0.8.0: r"\(([^;)]+);FOMA;" +consistent!(woothee_5, r"\(([^;)]+);FOMA;"); + +// woothee-0.8.0: r"jig browser[^;]+; ([^);]+)" +consistent!(woothee_6, r"jig browser[^;]+; ([^);]+)"); + +// woothee-0.8.0: r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)" +consistent!(woothee_7, r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)"); + +// woothee-0.8.0: r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)" +consistent!(woothee_8, r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)"); + +// woothee-0.8.0: r"(?i)(?:feed|web) ?parser" +consistent!(woothee_9, r"(?i)(?:feed|web) ?parser"); + +// woothee-0.8.0: r"(?i)watch ?dog" +consistent!(woothee_10, r"(?i)watch ?dog"); + +// woothee-0.8.0: r"Edge/([.0-9]+)" +consistent!(woothee_11, r"Edge/([.0-9]+)"); + +// woothee-0.8.0: r"MSIE ([.0-9]+);" +consistent!(woothee_12, r"MSIE ([.0-9]+);"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_13, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"Opera[/ ]([.0-9]+)" +consistent!(woothee_14, r"Opera[/ ]([.0-9]+)"); + +// woothee-0.8.0: r"OPR/([.0-9]+)" +consistent!(woothee_15, r"OPR/([.0-9]+)"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_16, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)" +consistent!(woothee_17, r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)"); + +// woothee-0.8.0: r"Trident/([.0-9]+);" +consistent!(woothee_18, r"Trident/([.0-9]+);"); + +// woothee-0.8.0: r" rv:([.0-9]+)" +consistent!(woothee_19, r" rv:([.0-9]+)"); + +// woothee-0.8.0: r"IEMobile/([.0-9]+);" +consistent!(woothee_20, r"IEMobile/([.0-9]+);"); + +// woothee-0.8.0: r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)" +consistent!(woothee_21, r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)"); + +// woothee-0.8.0: r"Windows ([ .a-zA-Z0-9]+)[;\\)]" +consistent!(woothee_22, r"Windows ([ .a-zA-Z0-9]+)[;\\)]"); + +// woothee-0.8.0: r"^Phone(?: OS)? ([.0-9]+)" +consistent!(woothee_23, r"^Phone(?: OS)? ([.0-9]+)"); + +// woothee-0.8.0: r"iP(hone;|ad;|od) .*like Mac OS X" +consistent!(woothee_24, r"iP(hone;|ad;|od) .*like Mac OS X"); + +// woothee-0.8.0: r"Version/([.0-9]+)" +consistent!(woothee_25, r"Version/([.0-9]+)"); + +// woothee-0.8.0: r"rv:(\d+\.\d+\.\d+)" +consistent!(woothee_26, r"rv:(\d+\.\d+\.\d+)"); + +// woothee-0.8.0: r"FreeBSD ([^;\)]+);" +consistent!(woothee_27, r"FreeBSD ([^;\)]+);"); + +// woothee-0.8.0: r"CrOS ([^\)]+)\)" +consistent!(woothee_28, r"CrOS ([^\)]+)\)"); + +// woothee-0.8.0: r"Android[- ](\d+\.\d+(?:\.\d+)?)" +consistent!(woothee_29, r"Android[- ](\d+\.\d+(?:\.\d+)?)"); + +// woothee-0.8.0: r"PSP \(PlayStation Portable\); ([.0-9]+)\)" +consistent!(woothee_30, r"PSP \(PlayStation Portable\); ([.0-9]+)\)"); + +// woothee-0.8.0: r"PLAYSTATION 3;? ([.0-9]+)\)" +consistent!(woothee_31, r"PLAYSTATION 3;? ([.0-9]+)\)"); + +// woothee-0.8.0: r"PlayStation Vita ([.0-9]+)\)" +consistent!(woothee_32, r"PlayStation Vita ([.0-9]+)\)"); + +// woothee-0.8.0: r"PlayStation 4 ([.0-9]+)\)" +consistent!(woothee_33, r"PlayStation 4 ([.0-9]+)\)"); + +// woothee-0.8.0: r"BB10(?:.+)Version/([.0-9]+) " +consistent!(woothee_34, r"BB10(?:.+)Version/([.0-9]+) "); + +// woothee-0.8.0: r"BlackBerry(?:\d+)/([.0-9]+) " +consistent!(woothee_35, r"BlackBerry(?:\d+)/([.0-9]+) "); + +// woothee-0.8.0: r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X" +consistent!(woothee_36, r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X"); + +// woothee-0.8.0: r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)" +consistent!(woothee_37, r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)"); + +// woothee-0.8.0: r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)" +consistent!(woothee_38, r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)"); + +// woothee-0.8.0: r"[- ]HttpClient(/|$)" +consistent!(woothee_39, r"[- ]HttpClient(/|$)"); + +// woothee-0.8.0: r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)" +consistent!(woothee_40, r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)"); + +// woothee-0.8.0: r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)" +consistent!(woothee_41, r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)"); + +// woothee-0.8.0: r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)" +consistent!(woothee_42, r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)"); + +// woothee-0.8.0: r"Sleipnir/([.0-9]+)" +consistent!(woothee_43, r"Sleipnir/([.0-9]+)"); + +// word_replace-0.0.3: r"@@[a-z|A-Z|\d]+@@" +consistent!(word_replace_0, r"@@[a-z|A-Z|\d]+@@"); + +// wordcount-0.1.0: r"\w+" +consistent!(wordcount_0, r"\w+"); + +// just-0.3.12: "^([^=]+)=(.*)$" +consistent!(just_0, "^([^=]+)=(.*)$"); + +// emote-0.1.0: r":[a-zA-Z_]+?:" +consistent!(emote_0, r":[a-zA-Z_]+?:"); + +// emojicons-1.0.1: r":([a-zA-Z0-9_+-]+):" +consistent!(emojicons_0, r":([a-zA-Z0-9_+-]+):"); + +// git2_codecommit-0.1.2: r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com" +consistent!(git2_codecommit_0, r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com"); + +// git-workarea-3.1.2: r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$" +consistent!(git_workarea_0, r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$"); + +// git-shell-enforce-directory-1.0.0: r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$" +consistent!(git_shell_enforce_directory_0, r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$"); + +// git-journal-1.6.3: r"[ \n]:(.*?):" +consistent!(git_journal_0, r"[ \n]:(.*?):"); + +// git-find-0.3.2: r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$" +consistent!(git_find_0, r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$"); + +// gitlab-api-0.6.0: r"private_token=\w{20}" +consistent!(gitlab_api_0, r"private_token=\w{20}"); + +// td-client-0.7.0: "^(http://|https://)" +consistent!(td_client_0, "^(http://|https://)"); + +// karaconv-0.3.0: r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)" +consistent!(karaconv_0, r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)"); + +// katana-1.0.2: r"(?P<comp>et al\.)(?:\.)" +consistent!(katana_0, r"(?P<comp>et al\.)(?:\.)"); + +// katana-1.0.2: r"\.{3}" +consistent!(katana_1, r"\.{3}"); + +// katana-1.0.2: r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)" +consistent!(katana_2, r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)"); + +// katana-1.0.2: r"\s\.(?P<nums>[0-9]+)" +consistent!(katana_3, r"\s\.(?P<nums>[0-9]+)"); + +// katana-1.0.2: r"(?:[A-Za-z]\.){2,}" +consistent!(katana_4, r"(?:[A-Za-z]\.){2,}"); + +// katana-1.0.2: r"(?P<init>[A-Z])(?P<point>\.)" +consistent!(katana_5, r"(?P<init>[A-Z])(?P<point>\.)"); + +// katana-1.0.2: r"(?P<title>[A-Z][a-z]{1,3})(\.)" +consistent!(katana_6, r"(?P<title>[A-Z][a-z]{1,3})(\.)"); + +// katana-1.0.2: r"&==&(?P<p>[.!?])" +consistent!(katana_7, r"&==&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\^&(?P<p>[.!?])" +consistent!(katana_8, r"&\^&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\*\*&(?P<p>[.!?])" +consistent!(katana_9, r"&\*\*&(?P<p>[.!?])"); + +// katana-1.0.2: r"&=&(?P<p>[.!?])" +consistent!(katana_10, r"&=&(?P<p>[.!?])"); + +// katana-1.0.2: r"&##&(?P<p>[.!?])" +consistent!(katana_11, r"&##&(?P<p>[.!?])"); + +// katana-1.0.2: r"&\$&(?P<p>[.!?])" +consistent!(katana_12, r"&\$&(?P<p>[.!?])"); + +// kailua_syntax-1.1.0: r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)" +consistent!(kailua_syntax_0, r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)"); + +// kailua_syntax-1.1.0: r"<(\d+)>" +consistent!(kailua_syntax_1, r"<(\d+)>"); + +// ftp-3.0.1: r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)" +consistent!(ftp_0, r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)"); + +// ftp-3.0.1: r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b" +consistent!(ftp_1, r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b"); + +// ftp-3.0.1: r"\s+(\d+)\s*$" +consistent!(ftp_2, r"\s+(\d+)\s*$"); + +// vat-0.1.0: r"<countryCode>(.*?)</countryCode>" +consistent!(vat_0, r"<countryCode>(.*?)</countryCode>"); + +// vat-0.1.0: r"<vatNumber>(.*?)</vatNumber>" +consistent!(vat_1, r"<vatNumber>(.*?)</vatNumber>"); + +// vat-0.1.0: r"<name>(.*?)</name>" +consistent!(vat_2, r"<name>(.*?)</name>"); + +// vat-0.1.0: r"<address>(?s)(.*?)(?-s)</address>" +consistent!(vat_3, r"<address>(?s)(.*?)(?-s)</address>"); + +// vat-0.1.0: r"<valid>(true|false)</valid>" +consistent!(vat_4, r"<valid>(true|false)</valid>"); + +// vat-0.1.0: r"^ATU\d{8}$" +consistent!(vat_5, r"^ATU\d{8}$"); + +// vat-0.1.0: r"^BE0?\d{9, 10}$" +consistent!(vat_6, r"^BE0?\d{9, 10}$"); + +// vat-0.1.0: r"^BG\d{9,10}$" +consistent!(vat_7, r"^BG\d{9,10}$"); + +// vat-0.1.0: r"^HR\d{11}$" +consistent!(vat_8, r"^HR\d{11}$"); + +// vat-0.1.0: r"^CY\d{8}[A-Z]$" +consistent!(vat_9, r"^CY\d{8}[A-Z]$"); + +// vat-0.1.0: r"^CZ\d{8,10}$" +consistent!(vat_10, r"^CZ\d{8,10}$"); + +// vat-0.1.0: r"^DK\d{8}$" +consistent!(vat_11, r"^DK\d{8}$"); + +// vat-0.1.0: r"^EE\d{9}$" +consistent!(vat_12, r"^EE\d{9}$"); + +// vat-0.1.0: r"^FI\d{8}$" +consistent!(vat_13, r"^FI\d{8}$"); + +// vat-0.1.0: r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$" +consistent!(vat_14, r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$"); + +// vat-0.1.0: r"^DE\d{9}$" +consistent!(vat_15, r"^DE\d{9}$"); + +// vat-0.1.0: r"^EL\d{9}$" +consistent!(vat_16, r"^EL\d{9}$"); + +// vat-0.1.0: r"^HU\d{8}$" +consistent!(vat_17, r"^HU\d{8}$"); + +// vat-0.1.0: r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$" +consistent!(vat_18, r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$"); + +// vat-0.1.0: r"^IT\d{11}$" +consistent!(vat_19, r"^IT\d{11}$"); + +// vat-0.1.0: r"^LV\d{11}$" +consistent!(vat_20, r"^LV\d{11}$"); + +// vat-0.1.0: r"^LT(\d{9}|\d{12})$" +consistent!(vat_21, r"^LT(\d{9}|\d{12})$"); + +// vat-0.1.0: r"^LU\d{8}$" +consistent!(vat_22, r"^LU\d{8}$"); + +// vat-0.1.0: r"^MT\d{8}$" +consistent!(vat_23, r"^MT\d{8}$"); + +// vat-0.1.0: r"^NL\d{9}B\d{2}$" +consistent!(vat_24, r"^NL\d{9}B\d{2}$"); + +// vat-0.1.0: r"^PL\d{10}$" +consistent!(vat_25, r"^PL\d{10}$"); + +// vat-0.1.0: r"^PT\d{9}$" +consistent!(vat_26, r"^PT\d{9}$"); + +// vat-0.1.0: r"^RO\d{2,10}$" +consistent!(vat_27, r"^RO\d{2,10}$"); + +// vat-0.1.0: r"^SK\d{10}$" +consistent!(vat_28, r"^SK\d{10}$"); + +// vat-0.1.0: r"^SI\d{8}$" +consistent!(vat_29, r"^SI\d{8}$"); + +// vat-0.1.0: r"^ES[A-Z0-9]\d{7}[A-Z0-9]$" +consistent!(vat_30, r"^ES[A-Z0-9]\d{7}[A-Z0-9]$"); + +// vat-0.1.0: r"^SE\d{10}01$" +consistent!(vat_31, r"^SE\d{10}01$"); + +// vat-0.1.0: r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$" +consistent!(vat_32, r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$"); + +// eve-0.1.1: r"\{\{(.*)\}\}" +consistent!(eve_0, r"\{\{(.*)\}\}"); + +// egc-0.1.2: "^mio" +consistent!(egc_0, "^mio"); + +// pew-0.2.3: "" +consistent!(pew_0, ""); + +// pew-0.2.3: "" +consistent!(pew_1, ""); + +// mob-0.4.3: "y" +consistent!(mob_0, "y"); + +// lit-0.2.8: "@([a-z]+)" +consistent!(lit_0, "@([a-z]+)"); + +// lit-0.2.8: "([A-Z-]+):(.*)" +consistent!(lit_1, "([A-Z-]+):(.*)"); + +// lit-0.2.8: "^[a-zA-Z_][a-zA-Z0-9_]*$" +consistent!(lit_2, "^[a-zA-Z_][a-zA-Z0-9_]*$"); + +// avm-1.0.1: r"\d+\.\d+\.\d+" +consistent!(avm_0, r"\d+\.\d+\.\d+"); + +// avm-1.0.1: r"\d+\.\d+\.\d+" +consistent!(avm_1, r"\d+\.\d+\.\d+"); + +// orm-0.2.0: r"^Vec<(.+)>$" +consistent!(orm_0, r"^Vec<(.+)>$"); + +// sgf-0.1.5: r"\\(\r\n|\n\r|\n|\r)" +consistent!(sgf_0, r"\\(\r\n|\n\r|\n|\r)"); + +// sgf-0.1.5: r"\\(.)" +consistent!(sgf_1, r"\\(.)"); + +// sgf-0.1.5: r"\r\n|\n\r|\n|\r" +consistent!(sgf_2, r"\r\n|\n\r|\n|\r"); + +// sgf-0.1.5: r"([\]\\:])" +consistent!(sgf_3, r"([\]\\:])"); + +// dok-0.2.0: "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$" +consistent!(dok_0, "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$"); + +// d20-0.1.0: r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)" +consistent!(d20_0, r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)"); + +// dvb-0.3.0: "E" +consistent!(dvb_0, "E"); + +// dvb-0.3.0: "^F" +consistent!(dvb_1, "^F"); + +// dvb-0.3.0: "^S" +consistent!(dvb_2, "^S"); + +// ger-0.2.0: r"Change-Id: (I[a-f0-9]{40})$" +consistent!(ger_0, r"Change-Id: (I[a-f0-9]{40})$"); + +// ger-0.2.0: r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$" +consistent!(ger_1, r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$"); + +// n5-0.2.1: r"(\d+)(\.(\d+))?(\.(\d+))?(.*)" +consistent!(n5_0, r"(\d+)(\.(\d+))?(\.(\d+))?(.*)"); + +// po-0.1.4: r"[A-Za-z0-9]" +consistent!(po_0, r"[A-Za-z0-9]"); + +// carnix-0.8.5: "path is (‘|')?([^’'\n]*)(’|')?" +consistent!(carnix_0, "path is (‘|')?([^’'\n]*)(’|')?"); + +// carnix-0.8.5: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?" +consistent!(carnix_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?"); + +// carnix-0.8.5: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(carnix_2, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// carnix-0.8.5: r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?" +consistent!(carnix_3, r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?"); + +// caseless-0.2.1: r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$" +consistent!(caseless_0, r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$"); + +// caseless-0.2.1: r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);" +consistent!(caseless_1, r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);"); + +// cabot-0.2.0: "\r?\n\r?\n" +consistent!(cabot_0, "\r?\n\r?\n"); + +// cabot-0.2.0: "\r?\n" +consistent!(cabot_1, "\r?\n"); + +// card-validate-2.2.1: r"^600" +consistent!(card_validate_0, r"^600"); + +// card-validate-2.2.1: r"^5019" +consistent!(card_validate_1, r"^5019"); + +// card-validate-2.2.1: r"^4" +consistent!(card_validate_2, r"^4"); + +// card-validate-2.2.1: r"^(5[1-5]|2[2-7])" +consistent!(card_validate_3, r"^(5[1-5]|2[2-7])"); + +// card-validate-2.2.1: r"^3[47]" +consistent!(card_validate_4, r"^3[47]"); + +// card-validate-2.2.1: r"^3[0689]" +consistent!(card_validate_5, r"^3[0689]"); + +// card-validate-2.2.1: r"^6([045]|22)" +consistent!(card_validate_6, r"^6([045]|22)"); + +// card-validate-2.2.1: r"^(62|88)" +consistent!(card_validate_7, r"^(62|88)"); + +// card-validate-2.2.1: r"^35" +consistent!(card_validate_8, r"^35"); + +// card-validate-2.2.1: r"^[0-9]+$" +consistent!(card_validate_9, r"^[0-9]+$"); + +// cargo-testify-0.3.0: r"\d{1,} passed.*filtered out" +consistent!(cargo_testify_0, r"\d{1,} passed.*filtered out"); + +// cargo-testify-0.3.0: r"error(:|\[).*" +consistent!(cargo_testify_1, r"error(:|\[).*"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_0, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_1, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_2, r"<(.*?)>"); + +// cargo-wix-0.0.5: r"<(.*?)>" +consistent!(cargo_wix_3, r"<(.*?)>"); + +// cargo-incremental-0.1.23: r"(?m)^incremental: re-using (\d+) out of (\d+) modules$" +consistent!(cargo_incremental_0, r"(?m)^incremental: re-using (\d+) out of (\d+) modules$"); + +// cargo-incremental-0.1.23: "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$" +consistent!(cargo_incremental_1, "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$"); + +// cargo-incremental-0.1.23: r"(?m)^test (.*) \.\.\. (\w+)" +consistent!(cargo_incremental_2, r"(?m)^test (.*) \.\.\. (\w+)"); + +// cargo-incremental-0.1.23: r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured" +consistent!(cargo_incremental_3, r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured"); + +// cargo-testjs-0.1.2: r"^[^-]+-[0-9a-f]+\.js$" +consistent!(cargo_testjs_0, r"^[^-]+-[0-9a-f]+\.js$"); + +// cargo-tarpaulin-0.6.2: r"\s*//" +consistent!(cargo_tarpaulin_0, r"\s*//"); + +// cargo-tarpaulin-0.6.2: r"/\*" +consistent!(cargo_tarpaulin_1, r"/\*"); + +// cargo-tarpaulin-0.6.2: r"\*/" +consistent!(cargo_tarpaulin_2, r"\*/"); + +// cargo-culture-kit-0.1.0: r"^fo" +consistent!(cargo_culture_kit_0, r"^fo"); + +// cargo-screeps-0.1.3: "\\s+" +consistent!(cargo_screeps_0, "\\s+"); + +// cargo-brew-0.1.4: r"`(\S+) v([0-9.]+)" +consistent!(cargo_brew_0, r"`(\S+) v([0-9.]+)"); + +// cargo-release-0.10.2: "^\\[.+\\]" +consistent!(cargo_release_0, "^\\[.+\\]"); + +// cargo-release-0.10.2: "^\\[\\[.+\\]\\]" +consistent!(cargo_release_1, "^\\[\\[.+\\]\\]"); + +// cargo-edit-0.3.0-beta.1: r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" +consistent!(cargo_edit_0, r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); + +// cargo-edit-0.3.0-beta.1: r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" +consistent!(cargo_edit_1, r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); + +// cargo-disassemble-0.1.1: ".*" +consistent!(cargo_disassemble_0, ".*"); + +// cargo-demangle-0.1.2: r"(?m)(?P<symbol>_ZN[0-9]+.*E)" +consistent!(cargo_demangle_0, r"(?m)(?P<symbol>_ZN[0-9]+.*E)"); + +// cargo-coverage-annotations-0.1.5: r"^\s*\}(?:\)*;?|\s*else\s*\{)$" +consistent!(cargo_coverage_annotations_0, r"^\s*\}(?:\)*;?|\s*else\s*\{)$"); + +// cargo-urlcrate-1.0.1: "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]" +consistent!(cargo_urlcrate_0, "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]"); + +// cargo-script-0.2.8: r"^\s*\*( |$)" +consistent!(cargo_script_0, r"^\s*\*( |$)"); + +// cargo-script-0.2.8: r"^(\s+)" +consistent!(cargo_script_1, r"^(\s+)"); + +// cargo-script-0.2.8: r"/\*|\*/" +consistent!(cargo_script_2, r"/\*|\*/"); + +// cargo-script-0.2.8: r"^\s*//!" +consistent!(cargo_script_3, r"^\s*//!"); + +// cargo-script-0.2.8: r"^#![^\[].*?(\r\n|\n)" +consistent!(cargo_script_4, r"^#![^\[].*?(\r\n|\n)"); + +// cargo-update-1.5.2: r"cargo-install-update\.exe-v.+" +consistent!(cargo_update_0, r"cargo-install-update\.exe-v.+"); + +// canteen-0.4.1: r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$" +consistent!(canteen_0, r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$"); + +// thruster-cli-0.1.3: r"(.)([A-Z])" +consistent!(thruster_cli_0, r"(.)([A-Z])"); + +// thieves-cant-0.1.0: "([Z]+)$" +consistent!(thieves_cant_0, "([Z]+)$"); + +// codeowners-0.1.3: r"^@\S+/\S+" +consistent!(codeowners_0, r"^@\S+/\S+"); + +// codeowners-0.1.3: r"^@\S+" +consistent!(codeowners_1, r"^@\S+"); + +// codeowners-0.1.3: r"^\S+@\S+" +consistent!(codeowners_2, r"^\S+@\S+"); + +// conserve-0.4.2: r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$" +consistent!(conserve_0, r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$"); + +// commodore-0.3.0: r"(?P<greeting>\S+?) (?P<name>\S+?)$" +consistent!(commodore_0, r"(?P<greeting>\S+?) (?P<name>\S+?)$"); + +// corollary-0.3.0: r"([ \t]*)```haskell([\s\S]*?)```" +consistent!(corollary_0, r"([ \t]*)```haskell([\s\S]*?)```"); + +// corollary-0.3.0: r"\b((?:a|b|t)\d*)\b" +consistent!(corollary_1, r"\b((?:a|b|t)\d*)\b"); + +// colorizex-0.1.3: "NB" +consistent!(colorizex_0, "NB"); + +// colorstring-0.0.1: r"(?i)\[[a-z0-9_-]+\]" +consistent!(colorstring_0, r"(?i)\[[a-z0-9_-]+\]"); + +// colorstring-0.0.1: r"^(?i)(\[[a-z0-9_-]+\])+" +consistent!(colorstring_1, r"^(?i)(\[[a-z0-9_-]+\])+"); + +// cosmogony-0.3.0: "name:(.+)" +consistent!(cosmogony_0, "name:(.+)"); + +// cobalt-bin-0.12.1: r"(?m:^ {0,3}\[[^\]]+\]:.+$)" +consistent!(cobalt_bin_0, r"(?m:^ {0,3}\[[^\]]+\]:.+$)"); + +// comrak-0.2.12: r"[^\p{L}\p{M}\p{N}\p{Pc} -]" +consistent!(comrak_0, r"[^\p{L}\p{M}\p{N}\p{Pc} -]"); + +// content-blocker-0.2.3: "" +consistent!(content_blocker_0, ""); + +// content-blocker-0.2.3: "(?i)hi" +consistent!(content_blocker_1, "(?i)hi"); + +// content-blocker-0.2.3: "http[s]?://domain.org" +consistent!(content_blocker_2, "http[s]?://domain.org"); + +// content-blocker-0.2.3: "(?i)http[s]?://domain.org" +consistent!(content_blocker_3, "(?i)http[s]?://domain.org"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_4, "http://domain.org"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_5, "http://domain.org"); + +// content-blocker-0.2.3: "ad.html" +consistent!(content_blocker_6, "ad.html"); + +// content-blocker-0.2.3: "ad.html" +consistent!(content_blocker_7, "ad.html"); + +// content-blocker-0.2.3: "http://domain.org" +consistent!(content_blocker_8, "http://domain.org"); + +// content-blocker-0.2.3: "http://domain.org/nocookies.sjs" +consistent!(content_blocker_9, "http://domain.org/nocookies.sjs"); + +// content-blocker-0.2.3: "http://domain.org/nocookies.sjs" +consistent!(content_blocker_10, "http://domain.org/nocookies.sjs"); + +// content-blocker-0.2.3: "http://domain.org/hideme.jpg" +consistent!(content_blocker_11, "http://domain.org/hideme.jpg"); + +// content-blocker-0.2.3: "http://domain.org/ok.html" +consistent!(content_blocker_12, "http://domain.org/ok.html"); + +// content-blocker-0.2.3: "http://domain.org/ok.html\\?except_this=1" +consistent!(content_blocker_13, "http://domain.org/ok.html\\?except_this=1"); + +// victoria-dom-0.1.2: "[A-Za-z0-9=]" +consistent!(victoria_dom_0, "[A-Za-z0-9=]"); + +// numbat-1.0.0: r"^nsq://" +consistent!(numbat_0, r"^nsq://"); + +// airkorea-0.1.2: r"[\s\t\r\n]" +consistent!(airkorea_0, r"[\s\t\r\n]"); + +// airkorea-0.1.2: r"([\{\[,])|([\}\]])" +consistent!(airkorea_1, r"([\{\[,])|([\}\]])"); + +// airkorea-0.1.2: r"[^.\d]+$" +consistent!(airkorea_2, r"[^.\d]+$"); + +// rofl-0.0.1: r"\b" +// consistent!(rofl_0, r"\b"); + +// rogcat-0.2.15: r"--------- beginning of.*" +consistent!(rogcat_0, r"--------- beginning of.*"); + +// rogcat-0.2.15: r"a|e|i|o|u" +consistent!(rogcat_1, r"a|e|i|o|u"); + +// rogcat-0.2.15: r"^(\d+)([kMG])$" +consistent!(rogcat_2, r"^(\d+)([kMG])$"); + +// media_filename-0.1.4: "\\.([A-Za-z0-9]{2,4})$" +consistent!(media_filename_0, "\\.([A-Za-z0-9]{2,4})$"); + +// media_filename-0.1.4: "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})" +consistent!(media_filename_1, "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})"); + +// media_filename-0.1.4: "(?:^\\[([^]]+)\\]|- ?([^-]+)$)" +consistent!(media_filename_2, "(?:^\\[([^]]+)\\]|- ?([^-]+)$)"); + +// media_filename-0.1.4: "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])" +consistent!(media_filename_3, "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])"); + +// media_filename-0.1.4: "[sS]([0-9]{1,2})" +consistent!(media_filename_4, "[sS]([0-9]{1,2})"); + +// media_filename-0.1.4: "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)" +consistent!(media_filename_5, "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)"); + +// media_filename-0.1.4: "((19[0-9]|20[01])[0-9])" +consistent!(media_filename_6, "((19[0-9]|20[01])[0-9])"); + +// media_filename-0.1.4: "((?i)xvid|x264|h\\.?264)" +consistent!(media_filename_7, "((?i)xvid|x264|h\\.?264)"); + +// media_filename-0.1.4: "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)" +consistent!(media_filename_8, "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)"); + +// media_filename-0.1.4: "\\[([0-9A-F]{8})\\]" +consistent!(media_filename_9, "\\[([0-9A-F]{8})\\]"); + +// termimage-0.3.2: r"(\d+)[xX](\d+)" +consistent!(termimage_0, r"(\d+)[xX](\d+)"); + +// teensy-0.1.0: r".*(\d{4}-\d{2}-\d{2}).*" +consistent!(teensy_0, r".*(\d{4}-\d{2}-\d{2}).*"); + +// telescreen-0.1.3: r"<@(.+)>" +consistent!(telescreen_0, r"<@(.+)>"); + +// tempus_fugit-0.4.4: r"^(\d+)" +consistent!(tempus_fugit_0, r"^(\d+)"); + +// fselect-0.4.1: "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" +consistent!(fselect_0, "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); + +// fselect-0.4.1: "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" +consistent!(fselect_1, "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); + +// fs_eventbridge-0.1.0: r"^([A-Z]+)(?:\s(.+))?\s*" +consistent!(fs_eventbridge_0, r"^([A-Z]+)(?:\s(.+))?\s*"); + +// joseki-0.0.1: r"(\w{1,2})\[(.+?)\]" +consistent!(joseki_0, r"(\w{1,2})\[(.+?)\]"); + +// tweetr-0.2.1: r"(?i)in (\d+) (second|minute|hour|day|week)s?" +consistent!(tweetr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); + +// bullet_core-0.1.1: "^(?u:[0-9])+" +consistent!(bullet_core_0, "^(?u:[0-9])+"); + +// bullet_core-0.1.1: "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+" +consistent!(bullet_core_1, "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+"); + +// bullet_core-0.1.1: "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+" +consistent!(bullet_core_2, "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+"); + +// bullet_core-0.1.1: "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)" +consistent!(bullet_core_3, "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)"); + +// bullet_core-0.1.1: "^(?u:\\()" +consistent!(bullet_core_4, "^(?u:\\()"); + +// bullet_core-0.1.1: "^(?u:\\))" +consistent!(bullet_core_5, "^(?u:\\))"); + +// bullet_core-0.1.1: "^(?u:\\*)" +consistent!(bullet_core_6, "^(?u:\\*)"); + +// bullet_core-0.1.1: "^(?u:\\+)" +consistent!(bullet_core_7, "^(?u:\\+)"); + +// bullet_core-0.1.1: "^(?u:,)" +consistent!(bullet_core_8, "^(?u:,)"); + +// bullet_core-0.1.1: "^(?u:\\-)" +consistent!(bullet_core_9, "^(?u:\\-)"); + +// bullet_core-0.1.1: "^(?u:/)" +consistent!(bullet_core_10, "^(?u:/)"); + +// bullet_core-0.1.1: "^(?u:\\[)" +consistent!(bullet_core_11, "^(?u:\\[)"); + +// bullet_core-0.1.1: "^(?u:\\])" +consistent!(bullet_core_12, "^(?u:\\])"); + +// bullet_core-0.1.1: "^(?u:\\^)" +consistent!(bullet_core_13, "^(?u:\\^)"); + +// bullet_core-0.1.1: "^(?u:·)" +consistent!(bullet_core_14, "^(?u:·)"); + +// actix-web-0.6.13: "//+" +consistent!(actix_web_0, "//+"); + +// actix-web-0.6.13: "//+" +consistent!(actix_web_1, "//+"); + +// althea_kernel_interface-0.1.0: r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)" +consistent!(althea_kernel_interface_0, r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)"); + +// althea_kernel_interface-0.1.0: r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)" +consistent!(althea_kernel_interface_1, r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)"); + +// alcibiades-0.3.0: r"\buci(?:\s|$)" +consistent!(alcibiades_0, r"\buci(?:\s|$)"); + +// ruma-identifiers-0.11.0: r"\A[a-z0-9._=-]+\z" +consistent!(ruma_identifiers_0, r"\A[a-z0-9._=-]+\z"); + +// rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$" +consistent!(rusqbin_0, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$"); + +// rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$" +consistent!(rusqbin_1, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$"); + +// rust-install-0.0.4: r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$" +consistent!(rust_install_0, r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$"); + +// rust_inbox-0.0.5: "^+(.*)\r\n" +consistent!(rust_inbox_0, "^+(.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* CAPABILITY (.*)\r\n" +consistent!(rust_inbox_1, r"^\* CAPABILITY (.*)\r\n"); + +// rust_inbox-0.0.5: r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)" +consistent!(rust_inbox_2, r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)"); + +// rust_inbox-0.0.5: r"^\* (\d+) EXISTS\r\n" +consistent!(rust_inbox_3, r"^\* (\d+) EXISTS\r\n"); + +// rust_inbox-0.0.5: r"^\* (\d+) RECENT\r\n" +consistent!(rust_inbox_4, r"^\* (\d+) RECENT\r\n"); + +// rust_inbox-0.0.5: r"^\* FLAGS (.+)\r\n" +consistent!(rust_inbox_5, r"^\* FLAGS (.+)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UNSEEN (\d+)\](.*)\r\n" +consistent!(rust_inbox_6, r"^\* OK \[UNSEEN (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n" +consistent!(rust_inbox_7, r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n" +consistent!(rust_inbox_8, r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n"); + +// rust_inbox-0.0.5: r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n" +consistent!(rust_inbox_9, r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_0, r"^[a-z]+ (\d+)$"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_1, r"^[a-z]+ (\d+)$"); + +// rustml-0.0.7: r"^[a-z]+ (\d+)$" +consistent!(rustml_2, r"^[a-z]+ (\d+)$"); + +// rustfmt-0.10.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-core-0.4.0: r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)" +consistent!(rustfmt_core_0, r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)"); + +// rustfmt-core-0.4.0: r"^## `([^`]+)`" +consistent!(rustfmt_core_1, r"^## `([^`]+)`"); + +// rustfmt-core-0.4.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_core_2, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-core-0.4.0: r"\s;" +consistent!(rustfmt_core_3, r"\s;"); + +// rust-enum-derive-0.4.0: r"^(0x)?([:digit:]+)$" +consistent!(rust_enum_derive_0, r"^(0x)?([:digit:]+)$"); + +// rust-enum-derive-0.4.0: r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$" +consistent!(rust_enum_derive_1, r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$"); + +// rust-enum-derive-0.4.0: r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*," +consistent!(rust_enum_derive_2, r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*,"); + +// rust-enum-derive-0.4.0: r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)" +consistent!(rust_enum_derive_3, r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)"); + +// rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" +consistent!(rustsourcebundler_0, r"^\s*pub mod (.+);$"); + +// rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" +consistent!(rustsourcebundler_1, r"^\s*pub mod (.+);$"); + +// rustfmt-nightly-0.8.2: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" +consistent!(rustfmt_nightly_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); + +// rustfmt-nightly-0.8.2: r"\s;" +consistent!(rustfmt_nightly_1, r"\s;"); + +// rustache-0.1.0: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" +consistent!(rustache_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); + +// rustfilt-0.2.0: r"_ZN[\$\._[:alnum:]]*" +consistent!(rustfilt_0, r"_ZN[\$\._[:alnum:]]*"); + +// rustache-lists-0.1.2: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" +consistent!(rustache_lists_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); + +// rural-0.7.3: "(.+)=(.+)" +consistent!(rural_0, "(.+)=(.+)"); + +// rural-0.7.3: "(.*):(.+)" +consistent!(rural_1, "(.*):(.+)"); + +// rural-0.7.3: "(.+):=(.+)" +consistent!(rural_2, "(.+):=(.+)"); + +// rural-0.7.3: "(.*)==(.+)" +consistent!(rural_3, "(.*)==(.+)"); + +// rusoto_credential-0.11.0: r"^\[([^\]]+)\]$" +consistent!(rusoto_credential_0, r"^\[([^\]]+)\]$"); + +// rumblebars-0.3.0: "([:blank:]*)$" +consistent!(rumblebars_0, "([:blank:]*)$"); + +// rumblebars-0.3.0: "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" +consistent!(rumblebars_1, "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); + +// rumblebars-0.3.0: "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" +consistent!(rumblebars_2, "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); + +// rumblebars-0.3.0: "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$" +consistent!(rumblebars_3, "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$"); + +// rumblebars-0.3.0: "^([:blank:]*\r?\n)(.*)" +consistent!(rumblebars_4, "^([:blank:]*\r?\n)(.*)"); + +// diesel_cli-1.3.1: r"(?P<stamp>[\d-]*)_hello" +consistent!(diesel_cli_0, r"(?P<stamp>[\d-]*)_hello"); + +// dishub-0.1.1: r"(\d+)s" +consistent!(dishub_0, r"(\d+)s"); + +// spreadsheet_textconv-0.1.0: r"\n" +consistent!(spreadsheet_textconv_0, r"\n"); + +// spreadsheet_textconv-0.1.0: r"\r" +consistent!(spreadsheet_textconv_1, r"\r"); + +// spreadsheet_textconv-0.1.0: r"\t" +consistent!(spreadsheet_textconv_2, r"\t"); + +// split_aud-0.1.0: r"DELAY (-?\d+)ms" +consistent!(split_aud_0, r"DELAY (-?\d+)ms"); + +// split_aud-0.1.0: r"Trim\((\d+), ?(\d+)\)" +consistent!(split_aud_1, r"Trim\((\d+), ?(\d+)\)"); + +// spotrust-0.0.5: r"spotify:[a-z]+:[a-zA-Z0-9]+" +consistent!(spotrust_0, r"spotify:[a-z]+:[a-zA-Z0-9]+"); + +// spaceslugs-0.1.0: r"[^\x00-\x7F]" +consistent!(spaceslugs_0, r"[^\x00-\x7F]"); + +// spaceslugs-0.1.0: r"[']+" +consistent!(spaceslugs_1, r"[']+"); + +// spaceslugs-0.1.0: r"\W+" +consistent!(spaceslugs_2, r"\W+"); + +// spaceslugs-0.1.0: r"[ ]+" +consistent!(spaceslugs_3, r"[ ]+"); + +// space_email_api-0.1.1: "PHPSESSID=([0-9a-f]+)" +consistent!(space_email_api_0, "PHPSESSID=([0-9a-f]+)"); + +// lorikeet-0.7.0: "[^0-9.,]" +consistent!(lorikeet_0, "[^0-9.,]"); + +// claude-0.3.0: r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$" +consistent!(claude_0, r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$"); + +// clam-0.1.6: r"<%=\s*(.+?)\s*%>" +consistent!(clam_0, r"<%=\s*(.+?)\s*%>"); + +// classifier-0.0.3: r"(\s)" +consistent!(classifier_0, r"(\s)"); + +// click-0.3.2: r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)" +consistent!(click_0, r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)"); + +// click-0.3.2: r"-----BEGIN PRIVATE KEY-----" +consistent!(click_1, r"-----BEGIN PRIVATE KEY-----"); + +// ultrastar-txt-0.1.2: r"#([A-Z3a-z]*):(.*)" +consistent!(ultrastar_txt_0, r"#([A-Z3a-z]*):(.*)"); + +// ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s*$" +consistent!(ultrastar_txt_1, "^-\\s?(-?[0-9]+)\\s*$"); + +// ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)" +consistent!(ultrastar_txt_2, "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)"); + +// ultrastar-txt-0.1.2: "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)" +consistent!(ultrastar_txt_3, "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)"); + +// ultrastar-txt-0.1.2: "^P\\s?(-?[0-9]+)" +consistent!(ultrastar_txt_4, "^P\\s?(-?[0-9]+)"); + +// db-accelerate-2.0.0: r"^template\.add($|\..+$)" +consistent!(db_accelerate_0, r"^template\.add($|\..+$)"); + +// db-accelerate-2.0.0: r"^template\.sub($|\..+$)" +consistent!(db_accelerate_1, r"^template\.sub($|\..+$)"); + +// sterling-0.3.0: r"(\d+)([cegps])" +consistent!(sterling_0, r"(\d+)([cegps])"); + +// stache-0.2.0: r"[^\w]" +consistent!(stache_0, r"[^\w]"); + +// strukt-0.1.0: "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\"" +consistent!(strukt_0, "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\""); + +// steamid-ng-0.3.1: r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$" +consistent!(steamid_ng_0, r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$"); + +// steamid-ng-0.3.1: r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$" +consistent!(steamid_ng_1, r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$"); + +// strscan-0.1.1: r"^\w+" +consistent!(strscan_0, r"^\w+"); + +// strscan-0.1.1: r"^\s+" +consistent!(strscan_1, r"^\s+"); + +// strscan-0.1.1: r"^\w+" +consistent!(strscan_2, r"^\w+"); + +// strscan-0.1.1: r"^\s+" +consistent!(strscan_3, r"^\s+"); + +// strscan-0.1.1: r"^(\w+)\s+" +consistent!(strscan_4, r"^(\w+)\s+"); + +// tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" +consistent!(tk_carbon_0, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); + +// tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" +consistent!(tk_carbon_1, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); + +// evalrs-0.0.10: r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?" +consistent!(evalrs_0, r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?"); + +// evalrs-0.0.10: r"(?m)^# " +consistent!(evalrs_1, r"(?m)^# "); + +// evalrs-0.0.10: r"(?m)^\s*fn +main *\( *\)" +consistent!(evalrs_2, r"(?m)^\s*fn +main *\( *\)"); + +// evalrs-0.0.10: r"(extern\s+crate\s+[a-z0-9_]+\s*;)" +consistent!(evalrs_3, r"(extern\s+crate\s+[a-z0-9_]+\s*;)"); + +// gate_build-0.5.0: "(.*)_t([0-9]+)" +consistent!(gate_build_0, "(.*)_t([0-9]+)"); + +// rake-0.1.1: r"[^\P{P}-]|\s+-\s+" +consistent!(rake_0, r"[^\P{P}-]|\s+-\s+"); + +// rafy-0.2.1: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" +consistent!(rafy_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); + +// raven-0.2.1: r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$" +consistent!(raven_0, r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$"); + +// rargs-0.2.0: r"\{[[:space:]]*[^{}]*[[:space:]]*\}" +consistent!(rargs_0, r"\{[[:space:]]*[^{}]*[[:space:]]*\}"); + +// rargs-0.2.0: r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$" +consistent!(rargs_1, r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$"); + +// rargs-0.2.0: r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$" +consistent!(rargs_2, r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$"); + +// rargs-0.2.0: r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$" +consistent!(rargs_3, r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$"); + +// rargs-0.2.0: r"(.*?)[[:space:]]+|(.*?)$" +consistent!(rargs_4, r"(.*?)[[:space:]]+|(.*?)$"); + +// indradb-lib-0.15.0: r"[a-zA-Z0-9]{8}" +consistent!(indradb_lib_0, r"[a-zA-Z0-9]{8}"); + +// fungi-lang-0.1.50: r"::" +consistent!(fungi_lang_0, r"::"); + +// nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" +consistent!(nickel_0, "/hello/(?P<name>[a-zA-Z]+)"); + +// nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" +consistent!(nickel_1, "/hello/(?P<name>[a-zA-Z]+)"); + +// pact_verifier-0.4.0: r"\{(\w+)\}" +consistent!(pact_verifier_0, r"\{(\w+)\}"); + +// pact_matching-0.4.1: "application/.*json" +consistent!(pact_matching_0, "application/.*json"); + +// pact_matching-0.4.1: "application/json.*" +consistent!(pact_matching_1, "application/json.*"); + +// pact_matching-0.4.1: "application/.*xml" +consistent!(pact_matching_2, "application/.*xml"); + +// pangu-0.2.0: "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])" +consistent!(pangu_0, "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])"); + +// pangu-0.2.0: "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)" +consistent!(pangu_1, "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)"); + +// parser-haskell-0.2.0: r"\{-[\s\S]*?-\}" +consistent!(parser_haskell_0, r"\{-[\s\S]*?-\}"); + +// parser-haskell-0.2.0: r"(?m);+\s*$" +consistent!(parser_haskell_1, r"(?m);+\s*$"); + +// parser-haskell-0.2.0: r"(?m)^#(if|ifn?def|endif|else|include|elif).*" +consistent!(parser_haskell_2, r"(?m)^#(if|ifn?def|endif|else|include|elif).*"); + +// parser-haskell-0.2.0: r"'([^'\\]|\\[A-Z]{1,3}|\\.)'" +consistent!(parser_haskell_3, r"'([^'\\]|\\[A-Z]{1,3}|\\.)'"); + +// parser-haskell-0.2.0: r"forall\s+(.*?)\." +consistent!(parser_haskell_4, r"forall\s+(.*?)\."); + +// html2md-0.2.1: "\\s{2,}" +consistent!(html2md_0, "\\s{2,}"); + +// html2md-0.2.1: "\\n{2,}" +consistent!(html2md_1, "\\n{2,}"); + +// html2md-0.2.1: "(?m)(\\S) $" +consistent!(html2md_2, "(?m)(\\S) $"); + +// html2md-0.2.1: "(?m)^[-*] " +consistent!(html2md_3, "(?m)^[-*] "); + +// ovpnfile-0.1.2: r"#.*$" +consistent!(ovpnfile_0, r"#.*$"); + +// ovpnfile-0.1.2: r"^<(\S+)>" +consistent!(ovpnfile_1, r"^<(\S+)>"); + +// ovpnfile-0.1.2: r"^</(\S+)>" +consistent!(ovpnfile_2, r"^</(\S+)>"); + +// screenruster-saver-fractal-0.1.1: r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})" +consistent!(screenruster_saver_fractal_0, r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})"); + +// scarlet-0.2.2: r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)" +consistent!(scarlet_0, r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)"); + +// cpp_to_rust_generator-0.2.0: r"^([\w:]+)<(.+)>$" +consistent!(cpp_to_rust_generator_0, r"^([\w:]+)<(.+)>$"); + +// cpp_to_rust_generator-0.2.0: r"^type-parameter-(\d+)-(\d+)$" +consistent!(cpp_to_rust_generator_1, r"^type-parameter-(\d+)-(\d+)$"); + +// cpp_to_rust_generator-0.2.0: r"^([\w~]+)<[^<>]+>$" +consistent!(cpp_to_rust_generator_2, r"^([\w~]+)<[^<>]+>$"); + +// cpp_to_rust_generator-0.2.0: r"(signals|Q_SIGNALS)\s*:" +consistent!(cpp_to_rust_generator_3, r"(signals|Q_SIGNALS)\s*:"); + +// cpp_to_rust_generator-0.2.0: r"(slots|Q_SLOTS)\s*:" +consistent!(cpp_to_rust_generator_4, r"(slots|Q_SLOTS)\s*:"); + +// cpp_to_rust_generator-0.2.0: r"(public|protected|private)\s*:" +consistent!(cpp_to_rust_generator_5, r"(public|protected|private)\s*:"); + +// cpp_to_rust-0.5.3: r"^([\w:]+)<(.+)>$" +consistent!(cpp_to_rust_0, r"^([\w:]+)<(.+)>$"); + +// cpp_to_rust-0.5.3: r"^type-parameter-(\d+)-(\d+)$" +consistent!(cpp_to_rust_1, r"^type-parameter-(\d+)-(\d+)$"); + +// cpp_to_rust-0.5.3: r"^([\w~]+)<[^<>]+>$" +consistent!(cpp_to_rust_2, r"^([\w~]+)<[^<>]+>$"); + +// cpp_to_rust-0.5.3: r"(signals|Q_SIGNALS)\s*:" +consistent!(cpp_to_rust_3, r"(signals|Q_SIGNALS)\s*:"); + +// cpp_to_rust-0.5.3: r"(slots|Q_SLOTS)\s*:" +consistent!(cpp_to_rust_4, r"(slots|Q_SLOTS)\s*:"); + +// cpp_to_rust-0.5.3: r"(public|protected|private)\s*:" +consistent!(cpp_to_rust_5, r"(public|protected|private)\s*:"); + +// fritzbox_logs-0.2.0: "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)" +consistent!(fritzbox_logs_0, "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)"); + +// fractal-matrix-api-3.29.0: r"mxc://(?P<server>[^/]+)/(?P<media>.+)" +consistent!(fractal_matrix_api_0, r"mxc://(?P<server>[^/]+)/(?P<media>.+)"); + +// smtp2go-0.1.4: r"^api-[a-zA-Z0-9]{32}$" +consistent!(smtp2go_0, r"^api-[a-zA-Z0-9]{32}$"); + +// pusher-0.3.1: r"^[-a-zA-Z0-9_=@,.;]+$" +consistent!(pusher_0, r"^[-a-zA-Z0-9_=@,.;]+$"); + +// pusher-0.3.1: r"\A\d+\.\d+\z" +consistent!(pusher_1, r"\A\d+\.\d+\z"); + +// bakervm-0.9.0: r"^\.(.+?) +?(.+)$" +consistent!(bakervm_0, r"^\.(.+?) +?(.+)$"); + +// bakervm-0.9.0: r"^\.([^\s]+)$" +consistent!(bakervm_1, r"^\.([^\s]+)$"); + +// bakervm-0.9.0: r"^include! +([^\s]+)$" +consistent!(bakervm_2, r"^include! +([^\s]+)$"); + +// bakervm-0.9.0: r"^@(\d+)$" +consistent!(bakervm_3, r"^@(\d+)$"); + +// bakervm-0.9.0: r"^true|false$" +consistent!(bakervm_4, r"^true|false$"); + +// bakervm-0.9.0: r"^(-?\d+)?\.[0-9]+$" +consistent!(bakervm_5, r"^(-?\d+)?\.[0-9]+$"); + +// bakervm-0.9.0: r"^(-?\d+)?$" +consistent!(bakervm_6, r"^(-?\d+)?$"); + +// bakervm-0.9.0: r"^#([0-9abcdefABCDEF]{6})$" +consistent!(bakervm_7, r"^#([0-9abcdefABCDEF]{6})$"); + +// bakervm-0.9.0: r"^'(.)'$" +consistent!(bakervm_8, r"^'(.)'$"); + +// bakervm-0.9.0: r"^\$vi\((\d+)\)$" +consistent!(bakervm_9, r"^\$vi\((\d+)\)$"); + +// bakervm-0.9.0: r"^\$key\((\d+)\)$" +consistent!(bakervm_10, r"^\$key\((\d+)\)$"); + +// banana-0.0.2: "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)" +consistent!(banana_0, "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)"); + +// serial-key-2.0.0: r"[A-F0-9]{8}" +consistent!(serial_key_0, r"[A-F0-9]{8}"); + +// serde-hjson-0.8.1: "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_0, "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-hjson-0.8.1: "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_1, "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-hjson-0.8.1: "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" +consistent!(serde_hjson_2, "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); + +// serde-odbc-0.1.0: r"/todos/(?P<id>\d+)" +consistent!(serde_odbc_0, r"/todos/(?P<id>\d+)"); + +// sentry-0.6.0: r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)" +consistent!(sentry_0, r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)"); + +// sentiment-0.1.1: r"[^a-zA-Z0 -]+" +consistent!(sentiment_0, r"[^a-zA-Z0 -]+"); + +// sentiment-0.1.1: r" {2,}" +consistent!(sentiment_1, r" {2,}"); + +// verilog-0.0.1: r"(?m)//.*" +consistent!(verilog_0, r"(?m)//.*"); + +// verex-0.2.2: "(?P<robot>C3PO)" +consistent!(verex_0, "(?P<robot>C3PO)"); + +// handlebars-0.32.4: ">|<|\"|&" +consistent!(handlebars_0, ">|<|\"|&"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789]{4}$" +consistent!(haikunator_0, r"^\w+-\w+-[0123456789]{4}$"); + +// haikunator-0.1.2: r"^\w+@\w+@[0123456789]{4}$" +consistent!(haikunator_1, r"^\w+@\w+@[0123456789]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789abcdef]{4}$" +consistent!(haikunator_2, r"^\w+-\w+-[0123456789abcdef]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$" +consistent!(haikunator_3, r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$"); + +// haikunator-0.1.2: r"^\w+-\w+$" +consistent!(haikunator_4, r"^\w+-\w+$"); + +// haikunator-0.1.2: r"^\w+-\w+-[foo]{4}$" +consistent!(haikunator_5, r"^\w+-\w+-[foo]{4}$"); + +// haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$" +consistent!(haikunator_6, r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$"); + +// bobbin-cli-0.8.3: r"(.*)" +consistent!(bobbin_cli_0, r"(.*)"); + +// bobbin-cli-0.8.3: r"rustc (.*)" +consistent!(bobbin_cli_1, r"rustc (.*)"); + +// bobbin-cli-0.8.3: r"cargo (.*)" +consistent!(bobbin_cli_2, r"cargo (.*)"); + +// bobbin-cli-0.8.3: r"xargo (.*)\n" +consistent!(bobbin_cli_3, r"xargo (.*)\n"); + +// bobbin-cli-0.8.3: r"Open On-Chip Debugger (.*)" +consistent!(bobbin_cli_4, r"Open On-Chip Debugger (.*)"); + +// bobbin-cli-0.8.3: r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)" +consistent!(bobbin_cli_5, r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)"); + +// bobbin-cli-0.8.3: r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n" +consistent!(bobbin_cli_6, r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n"); + +// bobbin-cli-0.8.3: r"(?m)SEGGER J-Link Commander (.*)\n" +consistent!(bobbin_cli_7, r"(?m)SEGGER J-Link Commander (.*)\n"); + +// bobbin-cli-0.8.3: r"(?m)Teensy Loader, Command Line, Version (.*)\n" +consistent!(bobbin_cli_8, r"(?m)Teensy Loader, Command Line, Version (.*)\n"); + +// bobbin-cli-0.8.3: r"dfu-util (.*)\n" +consistent!(bobbin_cli_9, r"dfu-util (.*)\n"); + +// borsholder-0.9.1: r"^/static/[\w.]+$" +consistent!(borsholder_0, r"^/static/[\w.]+$"); + +// borsholder-0.9.1: r"^/timeline/([0-9]+)$" +consistent!(borsholder_1, r"^/timeline/([0-9]+)$"); + +// fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" +consistent!(fblog_0, "\u{001B}\\[[\\d;]*[^\\d;]"); + +// fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" +consistent!(fblog_1, "\u{001B}\\[[\\d;]*[^\\d;]"); + +// toml-query-0.6.0: r"^\[\d+\]$" +consistent!(toml_query_0, r"^\[\d+\]$"); + +// todo-txt-1.1.0: r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)" +consistent!(todo_txt_0, r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)"); + +// findr-0.1.5: r"\band\b" +consistent!(findr_0, r"\band\b"); + +// findr-0.1.5: r"\bor\b" +consistent!(findr_1, r"\bor\b"); + +// findr-0.1.5: r"\bnot\b" +consistent!(findr_2, r"\bnot\b"); + +// file-sniffer-3.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(file_sniffer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*|dat|pc|info)$" +consistent!(file_sniffer_1, r".*?\.(stats|conf|h|cache.*|dat|pc|info)$"); + +// file-sniffer-3.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" +consistent!(file_sniffer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); + +// file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*)$" +consistent!(file_sniffer_3, r".*?\.(stats|conf|h|cache.*)$"); + +// file-sniffer-3.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" +consistent!(file_sniffer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); + +// file_logger-0.1.0: "test" +consistent!(file_logger_0, "test"); + +// file_scanner-0.2.0: r"foo" +consistent!(file_scanner_0, r"foo"); + +// file_scanner-0.2.0: r"a+b" +consistent!(file_scanner_1, r"a+b"); + +// file_scanner-0.2.0: r"a[ab]*b" +consistent!(file_scanner_2, r"a[ab]*b"); + +// file_scanner-0.2.0: r"\s+" +consistent!(file_scanner_3, r"\s+"); + +// file_scanner-0.2.0: r"\s+" +consistent!(file_scanner_4, r"\s+"); + +// cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" +consistent!(cellsplit_0, r"^\s*([^\s]+) %cellsplit<\d+>$"); + +// cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" +consistent!(cellsplit_1, r"^\s*([^\s]+) %cellsplit<\d+>$"); + +// aterm-0.20.0: r"^[+\-]?[0-9]+" +consistent!(aterm_0, r"^[+\-]?[0-9]+"); + +// aterm-0.20.0: r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?" +consistent!(aterm_1, r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?"); + +// atarashii_imap-0.3.0: r"^[*] OK" +consistent!(atarashii_imap_0, r"^[*] OK"); + +// atarashii_imap-0.3.0: r"FLAGS\s\((.+)\)" +consistent!(atarashii_imap_1, r"FLAGS\s\((.+)\)"); + +// atarashii_imap-0.3.0: r"\[PERMANENTFLAGS\s\((.+)\)\]" +consistent!(atarashii_imap_2, r"\[PERMANENTFLAGS\s\((.+)\)\]"); + +// atarashii_imap-0.3.0: r"\[UIDVALIDITY\s(\d+)\]" +consistent!(atarashii_imap_3, r"\[UIDVALIDITY\s(\d+)\]"); + +// atarashii_imap-0.3.0: r"(\d+)\sEXISTS" +consistent!(atarashii_imap_4, r"(\d+)\sEXISTS"); + +// atarashii_imap-0.3.0: r"(\d+)\sRECENT" +consistent!(atarashii_imap_5, r"(\d+)\sRECENT"); + +// atarashii_imap-0.3.0: r"\[UNSEEN\s(\d+)\]" +consistent!(atarashii_imap_6, r"\[UNSEEN\s(\d+)\]"); + +// atarashii_imap-0.3.0: r"\[UIDNEXT\s(\d+)\]" +consistent!(atarashii_imap_7, r"\[UIDNEXT\s(\d+)\]"); + +// editorconfig-1.0.0: r"\\(\{|\})" +consistent!(editorconfig_0, r"\\(\{|\})"); + +// editorconfig-1.0.0: r"(^|[^\\])\\\|" +consistent!(editorconfig_1, r"(^|[^\\])\\\|"); + +// editorconfig-1.0.0: r"\[([^\]]*)$" +consistent!(editorconfig_2, r"\[([^\]]*)$"); + +// editorconfig-1.0.0: r"\[(.*/.*)\]" +consistent!(editorconfig_3, r"\[(.*/.*)\]"); + +// editorconfig-1.0.0: r"\{(-?\d+\\\.\\\.-?\d+)\}" +consistent!(editorconfig_4, r"\{(-?\d+\\\.\\\.-?\d+)\}"); + +// editorconfig-1.0.0: r"\{([^,]+)\}" +consistent!(editorconfig_5, r"\{([^,]+)\}"); + +// editorconfig-1.0.0: r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}" +consistent!(editorconfig_6, r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}"); + +// editorconfig-1.0.0: r"^/" +consistent!(editorconfig_7, r"^/"); + +// editorconfig-1.0.0: r"(^|[^\\])(\{|\})" +consistent!(editorconfig_8, r"(^|[^\\])(\{|\})"); + +// edmunge-1.0.0: "^#!.*\n" +consistent!(edmunge_0, "^#!.*\n"); + +// unicode_names2_macros-0.2.0: r"\\N\{(.*?)(?:\}|$)" +consistent!(unicode_names2_macros_0, r"\\N\{(.*?)(?:\}|$)"); + +// unidiff-0.2.1: r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" +consistent!(unidiff_0, r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); + +// unidiff-0.2.1: r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" +consistent!(unidiff_1, r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); + +// unidiff-0.2.1: r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)" +consistent!(unidiff_2, r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)"); + +// unidiff-0.2.1: r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)" +consistent!(unidiff_3, r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)"); + +// slippy-map-tiles-0.13.1: "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$" +consistent!(slippy_map_tiles_0, "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$"); + +// slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" +consistent!(slippy_map_tiles_1, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); + +// slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" +consistent!(slippy_map_tiles_2, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); + +// sonos-0.1.2: r"^https?://(.+?):1400/xml" +consistent!(sonos_0, r"^https?://(.+?):1400/xml"); + +// validator_derive-0.7.0: r"^[a-z]{2}$" +consistent!(validator_derive_0, r"^[a-z]{2}$"); + +// validator_derive-0.7.0: r"[a-z]{2}" +consistent!(validator_derive_1, r"[a-z]{2}"); + +// validator_derive-0.7.0: r"[a-z]{2}" +consistent!(validator_derive_2, r"[a-z]{2}"); + +// nginx-config-0.8.0: r"one of \d+ options" +consistent!(nginx_config_0, r"one of \d+ options"); + +// waltz-0.4.0: r"[\s,]" +consistent!(waltz_0, r"[\s,]"); + +// warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" +consistent!(warheadhateus_0, r"^aws_access_key_id = (.*)"); + +// warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" +consistent!(warheadhateus_1, r"^aws_secret_access_key = (.*)"); + +// warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" +consistent!(warheadhateus_2, r"^aws_access_key_id = (.*)"); + +// warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" +consistent!(warheadhateus_3, r"^aws_secret_access_key = (.*)"); + +// jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)" +consistent!(jieba_rs_0, r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)"); + +// jieba-rs-0.2.2: r"(\r\n|\s)" +consistent!(jieba_rs_1, r"(\r\n|\s)"); + +// jieba-rs-0.2.2: "([\u{4E00}-\u{9FD5}]+)" +consistent!(jieba_rs_2, "([\u{4E00}-\u{9FD5}]+)"); + +// jieba-rs-0.2.2: r"[^a-zA-Z0-9+#\n]" +consistent!(jieba_rs_3, r"[^a-zA-Z0-9+#\n]"); + +// jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}]+)" +consistent!(jieba_rs_4, r"([\u{4E00}-\u{9FD5}]+)"); + +// jieba-rs-0.2.2: r"([a-zA-Z0-9]+(?:.\d+)?%?)" +consistent!(jieba_rs_5, r"([a-zA-Z0-9]+(?:.\d+)?%?)"); + +// lalrpop-0.15.2: r"Span\([0-9 ,]*\)" +consistent!(lalrpop_0, r"Span\([0-9 ,]*\)"); + +// lalrpop-snap-0.15.2: r"Span\([0-9 ,]*\)" +consistent!(lalrpop_snap_0, r"Span\([0-9 ,]*\)"); + +// nlp-tokenize-0.1.0: r"[\S]+" +consistent!(nlp_tokenize_0, r"[\S]+"); + +// kbgpg-0.1.2: "[[:xdigit:]][70]" +consistent!(kbgpg_0, "[[:xdigit:]][70]"); + +// cdbd-0.1.1: r"^((?P<address>.*):)?(?P<port>\d+)$" +consistent!(cdbd_0, r"^((?P<address>.*):)?(?P<port>\d+)$"); + +// mbutiles-0.1.1: r"[\w\s=+-/]+\((\{(.|\n)*\})\);?" +consistent!(mbutiles_0, r"[\w\s=+-/]+\((\{(.|\n)*\})\);?"); + +// extrahop-0.2.5: r"^-\d+(?:ms|s|m|h|d|w|y)?$" +consistent!(extrahop_0, r"^-\d+(?:ms|s|m|h|d|w|y)?$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" +consistent!(pippin_0, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" +consistent!(pippin_1, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" +consistent!(pippin_2, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); + +// pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" +consistent!(pippin_3, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); + +// pippin-0.1.0: "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$" +consistent!(pippin_4, "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$"); + +// pippin-0.1.0: "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$" +consistent!(pippin_5, "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$"); + +// pinyin-0.3.0: r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]" +consistent!(pinyin_0, r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]"); + +// pinyin-0.3.0: r"([aeoiuvnm])([0-4])$" +consistent!(pinyin_1, r"([aeoiuvnm])([0-4])$"); + +// duration-parser-0.2.0: r"(?P<value>\d+)(?P<units>[a-z])" +consistent!(duration_parser_0, r"(?P<value>\d+)(?P<units>[a-z])"); + +// dutree-0.2.7: r"^\d+\D?$" +consistent!(dutree_0, r"^\d+\D?$"); + +// djangohashers-0.3.0: r"^[A-Za-z0-9]*$" +consistent!(djangohashers_0, r"^[A-Za-z0-9]*$"); + +// rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}$" +consistent!(rtag_0, r"^[A-Z][A-Z0-9]{2,}$"); + +// rtag-0.3.5: r"^http://www\.emusic\.com" +consistent!(rtag_1, r"^http://www\.emusic\.com"); + +// rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}" +consistent!(rtag_2, r"^[A-Z][A-Z0-9]{2,}"); + +// rtag-0.3.5: r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)" +consistent!(rtag_3, r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)"); + +// rtow-0.1.0: r"(\d+)[xX](\d+)" +consistent!(rtow_0, r"(\d+)[xX](\d+)"); + +// pleingres-sql-plugin-0.1.0: r"\$([a-zA-Z0-9_]+)" +consistent!(pleingres_sql_plugin_0, r"\$([a-zA-Z0-9_]+)"); + +// dono-2.0.0: "[\\n]+" +consistent!(dono_0, "[\\n]+"); + +// dono-2.0.0: "(?m)^\\n" +consistent!(dono_1, "(?m)^\\n"); + +// dono-2.0.0: "(?m)^\\n" +consistent!(dono_2, "(?m)^\\n"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.ed25519$" +consistent!(ssb_common_0, r"^[0-9A-Za-z\+/]{43}=\.ed25519$"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{86}==\.ed25519$" +consistent!(ssb_common_1, r"^[0-9A-Za-z\+/]{86}==\.ed25519$"); + +// ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.sha256$" +consistent!(ssb_common_2, r"^[0-9A-Za-z\+/]{43}=\.sha256$"); + +// mozversion-0.1.3: r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$" +consistent!(mozversion_0, r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$"); + +// monger-0.5.6: r"^(\d+)\.(\d+)$" +consistent!(monger_0, r"^(\d+)\.(\d+)$"); + +// mongo_rub-0.0.2: r"^[rv]2\.6" +consistent!(mongo_rub_0, r"^[rv]2\.6"); + +// flow-0.3.5: "body value" +consistent!(flow_0, "body value"); + +// flow-0.3.5: "start marker" +consistent!(flow_1, "start marker"); + +// flow-0.3.5: "end marker" +consistent!(flow_2, "end marker"); + +// flow-0.3.5: "body value" +consistent!(flow_3, "body value"); + +// vobsub-0.2.3: "^([A-Za-z/ ]+): (.*)" +consistent!(vobsub_0, "^([A-Za-z/ ]+): (.*)"); + +// voidmap-1.1.2: r"#([^\s=]+)*" +consistent!(voidmap_0, r"#([^\s=]+)*"); + +// voidmap-1.1.2: r"#(\S+)*" +consistent!(voidmap_1, r"#(\S+)*"); + +// voidmap-1.1.2: r"#prio=(\d+)" +consistent!(voidmap_2, r"#prio=(\d+)"); + +// voidmap-1.1.2: r"\[(\S+)\]" +consistent!(voidmap_3, r"\[(\S+)\]"); + +// voidmap-1.1.2: r"#limit=(\d+)" +consistent!(voidmap_4, r"#limit=(\d+)"); + +// voidmap-1.1.2: r"#tagged=(\S+)" +consistent!(voidmap_5, r"#tagged=(\S+)"); + +// voidmap-1.1.2: r"#rev\b" +consistent!(voidmap_6, r"#rev\b"); + +// voidmap-1.1.2: r"#done\b" +consistent!(voidmap_7, r"#done\b"); + +// voidmap-1.1.2: r"#open\b" +consistent!(voidmap_8, r"#open\b"); + +// voidmap-1.1.2: r"#since=(\S+)" +consistent!(voidmap_9, r"#since=(\S+)"); + +// voidmap-1.1.2: r"#until=(\S+)" +consistent!(voidmap_10, r"#until=(\S+)"); + +// voidmap-1.1.2: r"#plot=(\S+)" +consistent!(voidmap_11, r"#plot=(\S+)"); + +// voidmap-1.1.2: r"#n=(\d+)" +consistent!(voidmap_12, r"#n=(\d+)"); + +// voidmap-1.1.2: r"(\S+)" +consistent!(voidmap_13, r"(\S+)"); + +// voidmap-1.1.2: r"(?P<y>\d+)y" +consistent!(voidmap_14, r"(?P<y>\d+)y"); + +// voidmap-1.1.2: r"(?P<m>\d+)m" +consistent!(voidmap_15, r"(?P<m>\d+)m"); + +// voidmap-1.1.2: r"(?P<w>\d+)w" +consistent!(voidmap_16, r"(?P<w>\d+)w"); + +// voidmap-1.1.2: r"(?P<d>\d+)d" +consistent!(voidmap_17, r"(?P<d>\d+)d"); + +// voidmap-1.1.2: r"(?P<h>\d+)h" +consistent!(voidmap_18, r"(?P<h>\d+)h"); + +// voidmap-1.1.2: r"C-(.)" +consistent!(voidmap_19, r"C-(.)"); + +// qt_generator-0.2.0: r"^\.\./qt[^/]+/" +consistent!(qt_generator_0, r"^\.\./qt[^/]+/"); + +// qt_generator-0.2.0: "(href|src)=\"([^\"]*)\"" +consistent!(qt_generator_1, "(href|src)=\"([^\"]*)\""); + +// kryptos-0.6.1: r"[01]{5}" +consistent!(kryptos_0, r"[01]{5}"); + +// cifar_10_loader-0.2.0: "data_batch_[1-5].bin" +consistent!(cifar_10_loader_0, "data_batch_[1-5].bin"); + +// cifar_10_loader-0.2.0: "test_batch.bin" +consistent!(cifar_10_loader_1, "test_batch.bin"); + +// circadian-0.6.0: r"^\d+.\d+s$" +consistent!(circadian_0, r"^\d+.\d+s$"); + +// circadian-0.6.0: r"^\d+:\d+$" +consistent!(circadian_1, r"^\d+:\d+$"); + +// circadian-0.6.0: r"^\d+:\d+m$" +consistent!(circadian_2, r"^\d+:\d+m$"); + +// cicada-0.8.1: r"!!" +consistent!(cicada_0, r"!!"); + +// cicada-0.8.1: r"^([^`]*)`([^`]+)`(.*)$" +consistent!(cicada_1, r"^([^`]*)`([^`]+)`(.*)$"); + +// cicada-0.8.1: r"\*+" +consistent!(cicada_2, r"\*+"); + +// cicada-0.8.1: r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)" +consistent!(cicada_3, r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)"); + +// cicada-0.8.1: r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$" +consistent!(cicada_4, r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$"); + +// vterm-sys-0.1.0: r"hi" +consistent!(vterm_sys_0, r"hi"); + +// skim-0.5.0: r".*?\t" +consistent!(skim_0, r".*?\t"); + +// skim-0.5.0: r".*?[\t ]" +consistent!(skim_1, r".*?[\t ]"); + +// skim-0.5.0: r"(\{-?[0-9.,q]*?})" +consistent!(skim_2, r"(\{-?[0-9.,q]*?})"); + +// skim-0.5.0: r"[ \t\n]+" +consistent!(skim_3, r"[ \t\n]+"); + +// skim-0.5.0: r"[ \t\n]+" +consistent!(skim_4, r"[ \t\n]+"); + +// skim-0.5.0: r"([^ |]+( +\| +[^ |]*)+)|( +)" +consistent!(skim_5, r"([^ |]+( +\| +[^ |]*)+)|( +)"); + +// skim-0.5.0: r" +\| +" +consistent!(skim_6, r" +\| +"); + +// skim-0.5.0: r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$" +consistent!(skim_7, r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$"); + +// skim-0.5.0: "," +consistent!(skim_8, ","); + +// skim-0.5.0: ".*?," +consistent!(skim_9, ".*?,"); + +// skim-0.5.0: ".*?," +consistent!(skim_10, ".*?,"); + +// skim-0.5.0: "," +consistent!(skim_11, ","); + +// skim-0.5.0: r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))" +consistent!(skim_12, r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))"); + +// egg-mode-text-1.14.7: r"[-_./]\z" +consistent!(egg_mode_text_0, r"[-_./]\z"); + +// java-properties-1.1.1: "^[ \t\r\n\x0c]*[#!]" +consistent!(java_properties_0, "^[ \t\r\n\x0c]*[#!]"); + +// java-properties-1.1.1: r"^[ \t\x0c]*[#!][^\r\n]*$" +consistent!(java_properties_1, r"^[ \t\x0c]*[#!][^\r\n]*$"); + +// java-properties-1.1.1: r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$" +consistent!(java_properties_2, r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$"); + +// ipaddress-0.1.2: r":.+\." +consistent!(ipaddress_0, r":.+\."); + +// ipaddress-0.1.2: r"\." +consistent!(ipaddress_1, r"\."); + +// ipaddress-0.1.2: r":" +consistent!(ipaddress_2, r":"); + +// iptables-0.2.2: r"v(\d+)\.(\d+)\.(\d+)" +consistent!(iptables_0, r"v(\d+)\.(\d+)\.(\d+)"); + +// rsure-0.8.1: r"^([^-]+)-(.*)\.dat\.gz$" +consistent!(rsure_0, r"^([^-]+)-(.*)\.dat\.gz$"); + +// rs-jsonpath-0.1.0: "^(.*?)(<=|<|==|>=|>)(.*?)$" +consistent!(rs_jsonpath_0, "^(.*?)(<=|<|==|>=|>)(.*?)$"); + +// oatie-0.3.0: r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))" +consistent!(oatie_0, r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))"); + +// weld-0.2.0: "#.*$" +consistent!(weld_0, "#.*$"); + +// weld-0.2.0: r"^[A-Za-z$_][A-Za-z0-9$_]*$" +consistent!(weld_1, r"^[A-Za-z$_][A-Za-z0-9$_]*$"); + +// weld-0.2.0: r"^[0-9]+[cC]$" +consistent!(weld_2, r"^[0-9]+[cC]$"); + +// weld-0.2.0: r"^0b[0-1]+[cC]$" +consistent!(weld_3, r"^0b[0-1]+[cC]$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+[cC]$" +consistent!(weld_4, r"^0x[0-9a-fA-F]+[cC]$"); + +// weld-0.2.0: r"^[0-9]+$" +consistent!(weld_5, r"^[0-9]+$"); + +// weld-0.2.0: r"^0b[0-1]+$" +consistent!(weld_6, r"^0b[0-1]+$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+$" +consistent!(weld_7, r"^0x[0-9a-fA-F]+$"); + +// weld-0.2.0: r"^[0-9]+[lL]$" +consistent!(weld_8, r"^[0-9]+[lL]$"); + +// weld-0.2.0: r"^0b[0-1]+[lL]$" +consistent!(weld_9, r"^0b[0-1]+[lL]$"); + +// weld-0.2.0: r"^0x[0-9a-fA-F]+[lL]$" +consistent!(weld_10, r"^0x[0-9a-fA-F]+[lL]$"); + +// webgl_generator-0.1.0: "([(, ])enum\\b" +consistent!(webgl_generator_0, "([(, ])enum\\b"); + +// webgl_generator-0.1.0: "\\bAcquireResourcesCallback\\b" +consistent!(webgl_generator_1, "\\bAcquireResourcesCallback\\b"); + +// weave-0.2.0: r"^(\d+)(,(\d+))?([acd]).*$" +consistent!(weave_0, r"^(\d+)(,(\d+))?([acd]).*$"); + +// wemo-0.0.12: r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>" +consistent!(wemo_0, r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>"); + +// webscale-0.9.4: r"(http[s]?://[^\s]+)" +consistent!(webscale_0, r"(http[s]?://[^\s]+)"); + +// svgrep-1.1.0: r"^\d+.*$" +consistent!(svgrep_0, r"^\d+.*$"); + +// ignore-0.4.2: r"^[\pL\pN]+$" +consistent!(ignore_0, r"^[\pL\pN]+$"); + +// ommui_string_patterns-0.1.2: r"^([A-Za-z][0-9A-Za-z_]*)?$" +consistent!(ommui_string_patterns_0, r"^([A-Za-z][0-9A-Za-z_]*)?$"); + +// ommui_string_patterns-0.1.2: r"^(\S+(?:.*\S)?)?$" +consistent!(ommui_string_patterns_1, r"^(\S+(?:.*\S)?)?$"); + +// opcua-types-0.3.0: "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$" +consistent!(opcua_types_0, "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$"); + +// opcua-types-0.3.0: r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$" +consistent!(opcua_types_1, r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$"); + +// open_read_later-1.1.1: r"^(.+?)\s*:\s*(.+)$" +consistent!(open_read_later_0, r"^(.+?)\s*:\s*(.+)$"); + +// youtube-downloader-0.1.0: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" +consistent!(youtube_downloader_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); + +// yobot-0.1.1: "." +consistent!(yobot_0, "."); + +// yobot-0.1.1: r"." +consistent!(yobot_1, r"."); + +// yobot-0.1.1: r".+" +consistent!(yobot_2, r".+"); + +// yobot-0.1.1: r"." +consistent!(yobot_3, r"."); + +// ubiquity-0.1.5: r"foo" +consistent!(ubiquity_0, r"foo"); + +// ubiquity-0.1.5: r"/target/" +consistent!(ubiquity_1, r"/target/"); + +// ubiquity-0.1.5: r".DS_Store" +consistent!(ubiquity_2, r".DS_Store"); + +// qasm-1.0.0: r"//.*" +consistent!(qasm_0, r"//.*"); + +// drill-0.3.5: r"\{\{ *([a-z\._]+) *\}\}" +consistent!(drill_0, r"\{\{ *([a-z\._]+) *\}\}"); + +// queryst-2.0.0: r"^([^\]\[]+)" +consistent!(queryst_0, r"^([^\]\[]+)"); + +// queryst-2.0.0: r"(\[[^\]\[]*\])" +consistent!(queryst_1, r"(\[[^\]\[]*\])"); + +// qui-vive-0.1.0: r"^/(\w+)$" +consistent!(qui_vive_0, r"^/(\w+)$"); + +// qui-vive-0.1.0: r"^/key$" +consistent!(qui_vive_1, r"^/key$"); + +// qui-vive-0.1.0: r"^/key/(\w+)$" +consistent!(qui_vive_2, r"^/key/(\w+)$"); + +// qui-vive-0.1.0: r"^/url$" +consistent!(qui_vive_3, r"^/url$"); + +// qui-vive-0.1.0: r"^/url/(\w+)$" +consistent!(qui_vive_4, r"^/url/(\w+)$"); + +// qui-vive-0.1.0: r"^/inv$" +consistent!(qui_vive_5, r"^/inv$"); + +// qui-vive-0.1.0: r"^/inv/(\w+)$" +consistent!(qui_vive_6, r"^/inv/(\w+)$"); + +// subdiff-0.1.0: r"\b" +// consistent!(subdiff_0, r"\b"); + +// substudy-0.4.5: r"^(\d+)/(\d+)$" +consistent!(substudy_0, r"^(\d+)/(\d+)$"); + +// substudy-0.4.5: r"\s+" +consistent!(substudy_1, r"\s+"); + +// substudy-0.4.5: r"<[a-z/][^>]*>" +consistent!(substudy_2, r"<[a-z/][^>]*>"); + +// substudy-0.4.5: r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)" +consistent!(substudy_3, r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)"); + +// substudy-0.4.5: r"\s+" +consistent!(substudy_4, r"\s+"); + +// isbnid-0.1.3: r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$" +consistent!(isbnid_0, r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$"); + +// isbnid-0.1.3: r"[^0-9X]" +consistent!(isbnid_1, r"[^0-9X]"); + +// ispc-0.3.5: r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)" +consistent!(ispc_0, r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)"); + diff --git a/regex/tests/crazy.rs b/regex/tests/crazy.rs new file mode 100644 index 000000000..6fc4980eb --- /dev/null +++ b/regex/tests/crazy.rs @@ -0,0 +1,401 @@ +mat!(ascii_literal, r"a", "a", Some((0, 1))); + +// Some crazy expressions from regular-expressions.info. +mat!(match_ranges, + r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b", + "num: 255", Some((5, 8))); +mat!(match_ranges_not, + r"\b(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b", + "num: 256", None); +mat!(match_float1, r"[-+]?[0-9]*\.?[0-9]+", "0.1", Some((0, 3))); +mat!(match_float2, r"[-+]?[0-9]*\.?[0-9]+", "0.1.2", Some((0, 3))); +mat!(match_float3, r"[-+]?[0-9]*\.?[0-9]+", "a1.2", Some((1, 4))); +mat!(match_float4, r"^[-+]?[0-9]*\.?[0-9]+$", "1.a", None); +mat!(match_email, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b", + "mine is jam.slam@gmail.com ", Some((8, 26))); +mat!(match_email_not, r"(?i)\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b", + "mine is jam.slam@gmail ", None); +mat!(match_email_big, r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", + "mine is jam.slam@gmail.com ", Some((8, 26))); +mat!(match_date1, + r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$", + "1900-01-01", Some((0, 10))); +mat!(match_date2, + r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$", + "1900-00-01", None); +mat!(match_date3, + r"^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$", + "1900-13-01", None); + +// Do some crazy dancing with the start/end assertions. +matiter!(match_start_end_empty, r"^$", "", (0, 0)); +matiter!(match_start_end_empty_many_1, r"^$^$^$", "", (0, 0)); +matiter!(match_start_end_empty_many_2, r"^^^$$$", "", (0, 0)); +matiter!(match_start_end_empty_rev, r"$^", "", (0, 0)); +matiter!(match_start_end_empty_rep, r"(?:^$)*", "a\nb\nc", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)); +matiter!(match_start_end_empty_rep_rev, r"(?:$^)*", "a\nb\nc", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)); + +// Test negated character classes. +mat!(negclass_letters, r"[^ac]", "acx", Some((2, 3))); +mat!(negclass_letter_comma, r"[^a,]", "a,x", Some((2, 3))); +mat!(negclass_letter_space, r"[^a\s]", "a x", Some((2, 3))); +mat!(negclass_comma, r"[^,]", ",,x", Some((2, 3))); +mat!(negclass_space, r"[^\s]", " a", Some((1, 2))); +mat!(negclass_space_comma, r"[^,\s]", ", a", Some((2, 3))); +mat!(negclass_comma_space, r"[^\s,]", " ,a", Some((2, 3))); +mat!(negclass_ascii, r"[^[:alpha:]Z]", "A1", Some((1, 2))); + +// Test that repeated empty expressions don't loop forever. +mat!(lazy_many_many, r"((?:.*)*?)=", "a=b", Some((0, 2))); +mat!(lazy_many_optional, r"((?:.?)*?)=", "a=b", Some((0, 2))); +mat!(lazy_one_many_many, r"((?:.*)+?)=", "a=b", Some((0, 2))); +mat!(lazy_one_many_optional, r"((?:.?)+?)=", "a=b", Some((0, 2))); +mat!(lazy_range_min_many, r"((?:.*){1,}?)=", "a=b", Some((0, 2))); +mat!(lazy_range_many, r"((?:.*){1,2}?)=", "a=b", Some((0, 2))); +mat!(greedy_many_many, r"((?:.*)*)=", "a=b", Some((0, 2))); +mat!(greedy_many_optional, r"((?:.?)*)=", "a=b", Some((0, 2))); +mat!(greedy_one_many_many, r"((?:.*)+)=", "a=b", Some((0, 2))); +mat!(greedy_one_many_optional, r"((?:.?)+)=", "a=b", Some((0, 2))); +mat!(greedy_range_min_many, r"((?:.*){1,})=", "a=b", Some((0, 2))); +mat!(greedy_range_many, r"((?:.*){1,2})=", "a=b", Some((0, 2))); + +// Test that we handle various flavors of empty expressions. +matiter!(match_empty1, r"", "", (0, 0)); +matiter!(match_empty2, r"", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty3, r"()", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty4, r"()*", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty5, r"()+", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty6, r"()?", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty7, r"()()", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty8, r"()+|z", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty9, r"z|()+", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty10, r"()+|b", "abc", (0, 0), (1, 1), (2, 2), (3, 3)); +matiter!(match_empty11, r"b|()+", "abc", (0, 0), (1, 2), (3, 3)); + +// Test that the DFA can handle pathological cases. +// (This should result in the DFA's cache being flushed too frequently, which +// should cause it to quit and fall back to the NFA algorithm.) +#[test] +fn dfa_handles_pathological_case() { + fn ones_and_zeroes(count: usize) -> String { + use rand::{Rng, thread_rng}; + + let mut rng = thread_rng(); + let mut s = String::new(); + for _ in 0..count { + if rng.gen() { + s.push('1'); + } else { + s.push('0'); + } + } + s + } + + let re = regex!(r"[01]*1[01]{20}$"); + let text = { + let mut pieces = ones_and_zeroes(100_000); + pieces.push('1'); + pieces.push_str(&ones_and_zeroes(20)); + pieces + }; + assert!(re.is_match(text!(&*text))); +} + +#[test] +fn nest_limit_makes_it_parse() { + use regex::RegexBuilder; + + RegexBuilder::new( + r#" + 2(?: + [45]\d{3}| + 7(?: + 1[0-267]| + 2[0-289]| + 3[0-29]| + 4[01]| + 5[1-3]| + 6[013]| + 7[0178]| + 91 + )| + 8(?: + 0[125]| + [139][1-6]| + 2[0157-9]| + 41| + 6[1-35]| + 7[1-5]| + 8[1-8]| + 90 + )| + 9(?: + 0[0-2]| + 1[0-4]| + 2[568]| + 3[3-6]| + 5[5-7]| + 6[0167]| + 7[15]| + 8[0146-9] + ) + )\d{4}| + 3(?: + 12?[5-7]\d{2}| + 0(?: + 2(?: + [025-79]\d| + [348]\d{1,2} + )| + 3(?: + [2-4]\d| + [56]\d? + ) + )| + 2(?: + 1\d{2}| + 2(?: + [12]\d| + [35]\d{1,2}| + 4\d? + ) + )| + 3(?: + 1\d{2}| + 2(?: + [2356]\d| + 4\d{1,2} + ) + )| + 4(?: + 1\d{2}| + 2(?: + 2\d{1,2}| + [47]| + 5\d{2} + ) + )| + 5(?: + 1\d{2}| + 29 + )| + [67]1\d{2}| + 8(?: + 1\d{2}| + 2(?: + 2\d{2}| + 3| + 4\d + ) + ) + )\d{3}| + 4(?: + 0(?: + 2(?: + [09]\d| + 7 + )| + 33\d{2} + )| + 1\d{3}| + 2(?: + 1\d{2}| + 2(?: + [25]\d?| + [348]\d| + [67]\d{1,2} + ) + )| + 3(?: + 1\d{2}(?: + \d{2} + )?| + 2(?: + [045]\d| + [236-9]\d{1,2} + )| + 32\d{2} + )| + 4(?: + [18]\d{2}| + 2(?: + [2-46]\d{2}| + 3 + )| + 5[25]\d{2} + )| + 5(?: + 1\d{2}| + 2(?: + 3\d| + 5 + ) + )| + 6(?: + [18]\d{2}| + 2(?: + 3(?: + \d{2} + )?| + [46]\d{1,2}| + 5\d{2}| + 7\d + )| + 5(?: + 3\d?| + 4\d| + [57]\d{1,2}| + 6\d{2}| + 8 + ) + )| + 71\d{2}| + 8(?: + [18]\d{2}| + 23\d{2}| + 54\d{2} + )| + 9(?: + [18]\d{2}| + 2[2-5]\d{2}| + 53\d{1,2} + ) + )\d{3}| + 5(?: + 02[03489]\d{2}| + 1\d{2}| + 2(?: + 1\d{2}| + 2(?: + 2(?: + \d{2} + )?| + [457]\d{2} + ) + )| + 3(?: + 1\d{2}| + 2(?: + [37](?: + \d{2} + )?| + [569]\d{2} + ) + )| + 4(?: + 1\d{2}| + 2[46]\d{2} + )| + 5(?: + 1\d{2}| + 26\d{1,2} + )| + 6(?: + [18]\d{2}| + 2| + 53\d{2} + )| + 7(?: + 1| + 24 + )\d{2}| + 8(?: + 1| + 26 + )\d{2}| + 91\d{2} + )\d{3}| + 6(?: + 0(?: + 1\d{2}| + 2(?: + 3\d{2}| + 4\d{1,2} + ) + )| + 2(?: + 2[2-5]\d{2}| + 5(?: + [3-5]\d{2}| + 7 + )| + 8\d{2} + )| + 3(?: + 1| + 2[3478] + )\d{2}| + 4(?: + 1| + 2[34] + )\d{2}| + 5(?: + 1| + 2[47] + )\d{2}| + 6(?: + [18]\d{2}| + 6(?: + 2(?: + 2\d| + [34]\d{2} + )| + 5(?: + [24]\d{2}| + 3\d| + 5\d{1,2} + ) + ) + )| + 72[2-5]\d{2}| + 8(?: + 1\d{2}| + 2[2-5]\d{2} + )| + 9(?: + 1\d{2}| + 2[2-6]\d{2} + ) + )\d{3}| + 7(?: + (?: + 02| + [3-589]1| + 6[12]| + 72[24] + )\d{2}| + 21\d{3}| + 32 + )\d{3}| + 8(?: + (?: + 4[12]| + [5-7]2| + 1\d? + )| + (?: + 0| + 3[12]| + [5-7]1| + 217 + )\d + )\d{4}| + 9(?: + [35]1| + (?: + [024]2| + 81 + )\d| + (?: + 1| + [24]1 + )\d{2} + )\d{3} + "# + ) + .build() + .unwrap(); +} diff --git a/regex/tests/flags.rs b/regex/tests/flags.rs new file mode 100644 index 000000000..0c9b36c91 --- /dev/null +++ b/regex/tests/flags.rs @@ -0,0 +1,11 @@ +mat!(match_flag_case, "(?i)abc", "ABC", Some((0, 3))); +mat!(match_flag_weird_case, "(?i)a(?-i)bc", "Abc", Some((0, 3))); +mat!(match_flag_weird_case_not, "(?i)a(?-i)bc", "ABC", None); +mat!(match_flag_case_dotnl, "(?is)a.", "A\n", Some((0, 2))); +mat!(match_flag_case_dotnl_toggle, "(?is)a.(?-is)a.", "A\nab", Some((0, 4))); +mat!(match_flag_case_dotnl_toggle_not, "(?is)a.(?-is)a.", "A\na\n", None); +mat!(match_flag_case_dotnl_toggle_ok, "(?is)a.(?-is:a.)?", "A\na\n", Some((0, 2))); +mat!(match_flag_multi, "(?m)(?:^\\d+$\n?)+", "123\n456\n789", Some((0, 11))); +mat!(match_flag_ungreedy, "(?U)a+", "aa", Some((0, 1))); +mat!(match_flag_ungreedy_greedy, "(?U)a+?", "aa", Some((0, 2))); +mat!(match_flag_ungreedy_noop, "(?U)(?-U)a+", "aa", Some((0, 2))); diff --git a/regex/tests/fowler.rs b/regex/tests/fowler.rs new file mode 100644 index 000000000..a4d1a5bdf --- /dev/null +++ b/regex/tests/fowler.rs @@ -0,0 +1,371 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// DO NOT EDIT. Automatically generated by 'scripts/regex-match-tests.py' +// on 2015-02-28 11:00:00.161706. + +// Tests from basic.dat +mat!(match_basic_3, r"abracadabra$", r"abracadabracadabra", Some((7, 18))); +mat!(match_basic_4, r"a...b", r"abababbb", Some((2, 7))); +mat!(match_basic_5, r"XXXXXX", r"..XXXXXX", Some((2, 8))); +mat!(match_basic_6, r"\)", r"()", Some((1, 2))); +mat!(match_basic_7, r"a]", r"a]a", Some((0, 2))); +mat!(match_basic_9, r"\}", r"}", Some((0, 1))); +mat!(match_basic_10, r"\]", r"]", Some((0, 1))); +mat!(match_basic_12, r"]", r"]", Some((0, 1))); +mat!(match_basic_15, r"^a", r"ax", Some((0, 1))); +mat!(match_basic_16, r"\^a", r"a^a", Some((1, 3))); +mat!(match_basic_17, r"a\^", r"a^", Some((0, 2))); +mat!(match_basic_18, r"a$", r"aa", Some((1, 2))); +mat!(match_basic_19, r"a\$", r"a$", Some((0, 2))); +mat!(match_basic_20, r"^$", r"", Some((0, 0))); +mat!(match_basic_21, r"$^", r"", Some((0, 0))); +mat!(match_basic_22, r"a($)", r"aa", Some((1, 2)), Some((2, 2))); +mat!(match_basic_23, r"a*(^a)", r"aa", Some((0, 1)), Some((0, 1))); +mat!(match_basic_24, r"(..)*(...)*", r"a", Some((0, 0))); +mat!(match_basic_25, r"(..)*(...)*", r"abcd", Some((0, 4)), Some((2, 4))); +mat!(match_basic_26, r"(ab|a)(bc|c)", r"abc", Some((0, 3)), Some((0, 2)), Some((2, 3))); +mat!(match_basic_27, r"(ab)c|abc", r"abc", Some((0, 3)), Some((0, 2))); +mat!(match_basic_28, r"a{0}b", r"ab", Some((1, 2))); +mat!(match_basic_29, r"(a*)(b?)(b+)b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7))); +mat!(match_basic_30, r"(a*)(b{0,1})(b{1,})b{3}", r"aaabbbbbbb", Some((0, 10)), Some((0, 3)), Some((3, 4)), Some((4, 7))); +mat!(match_basic_32, r"((a|a)|a)", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1))); +mat!(match_basic_33, r"(a*)(a|aa)", r"aaaa", Some((0, 4)), Some((0, 3)), Some((3, 4))); +mat!(match_basic_34, r"a*(a.|aa)", r"aaaa", Some((0, 4)), Some((2, 4))); +mat!(match_basic_35, r"a(b)|c(d)|a(e)f", r"aef", Some((0, 3)), None, None, Some((1, 2))); +mat!(match_basic_36, r"(a|b)?.*", r"b", Some((0, 1)), Some((0, 1))); +mat!(match_basic_37, r"(a|b)c|a(b|c)", r"ac", Some((0, 2)), Some((0, 1))); +mat!(match_basic_38, r"(a|b)c|a(b|c)", r"ab", Some((0, 2)), None, Some((1, 2))); +mat!(match_basic_39, r"(a|b)*c|(a|ab)*c", r"abc", Some((0, 3)), Some((1, 2))); +mat!(match_basic_40, r"(a|b)*c|(a|ab)*c", r"xc", Some((1, 2))); +mat!(match_basic_41, r"(.a|.b).*|.*(.a|.b)", r"xa", Some((0, 2)), Some((0, 2))); +mat!(match_basic_42, r"a?(ab|ba)ab", r"abab", Some((0, 4)), Some((0, 2))); +mat!(match_basic_43, r"a?(ac{0}b|ba)ab", r"abab", Some((0, 4)), Some((0, 2))); +mat!(match_basic_44, r"ab|abab", r"abbabab", Some((0, 2))); +mat!(match_basic_45, r"aba|bab|bba", r"baaabbbaba", Some((5, 8))); +mat!(match_basic_46, r"aba|bab", r"baaabbbaba", Some((6, 9))); +mat!(match_basic_47, r"(aa|aaa)*|(a|aaaaa)", r"aa", Some((0, 2)), Some((0, 2))); +mat!(match_basic_48, r"(a.|.a.)*|(a|.a...)", r"aa", Some((0, 2)), Some((0, 2))); +mat!(match_basic_49, r"ab|a", r"xabc", Some((1, 3))); +mat!(match_basic_50, r"ab|a", r"xxabc", Some((2, 4))); +mat!(match_basic_51, r"(?i)(Ab|cD)*", r"aBcD", Some((0, 4)), Some((2, 4))); +mat!(match_basic_52, r"[^-]", r"--a", Some((2, 3))); +mat!(match_basic_53, r"[a-]*", r"--a", Some((0, 3))); +mat!(match_basic_54, r"[a-m-]*", r"--amoma--", Some((0, 4))); +mat!(match_basic_55, r":::1:::0:|:::1:1:0:", r":::0:::1:::1:::0:", Some((8, 17))); +mat!(match_basic_56, r":::1:::0:|:::1:1:1:", r":::0:::1:::1:::0:", Some((8, 17))); +mat!(match_basic_57, r"[[:upper:]]", r"A", Some((0, 1))); +mat!(match_basic_58, r"[[:lower:]]+", r"`az{", Some((1, 3))); +mat!(match_basic_59, r"[[:upper:]]+", r"@AZ[", Some((1, 3))); +mat!(match_basic_65, r" +", r" +", Some((0, 1))); +mat!(match_basic_66, r" +", r" +", Some((0, 1))); +mat!(match_basic_67, r"[^a]", r" +", Some((0, 1))); +mat!(match_basic_68, r" +a", r" +a", Some((0, 2))); +mat!(match_basic_69, r"(a)(b)(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((2, 3))); +mat!(match_basic_70, r"xxx", r"xxx", Some((0, 3))); +mat!(match_basic_71, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 6,", Some((0, 6))); +mat!(match_basic_72, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"2/7", Some((0, 3))); +mat!(match_basic_73, r"(^|[ (,;])((([Ff]eb[^ ]* *|0*2/|\* */?)0*[6-7]))([^0-9]|$)", r"feb 1,Feb 6", Some((5, 11))); +mat!(match_basic_74, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))", r"x", Some((0, 1)), Some((0, 1)), Some((0, 1))); +mat!(match_basic_75, r"((((((((((((((((((((((((((((((x))))))))))))))))))))))))))))))*", r"xx", Some((0, 2)), Some((1, 2)), Some((1, 2))); +mat!(match_basic_76, r"a?(ab|ba)*", r"ababababababababababababababababababababababababababababababababababababababababa", Some((0, 81)), Some((79, 81))); +mat!(match_basic_77, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabbbbaa", Some((18, 25))); +mat!(match_basic_78, r"abaa|abbaa|abbbaa|abbbbaa", r"ababbabbbabbbabbbbabaa", Some((18, 22))); +mat!(match_basic_79, r"aaac|aabc|abac|abbc|baac|babc|bbac|bbbc", r"baaabbbabac", Some((7, 11))); +mat!(match_basic_80, r".*", r"", Some((0, 2))); +mat!(match_basic_81, r"aaaa|bbbb|cccc|ddddd|eeeeee|fffffff|gggg|hhhh|iiiii|jjjjj|kkkkk|llll", r"XaaaXbbbXcccXdddXeeeXfffXgggXhhhXiiiXjjjXkkkXlllXcbaXaaaa", Some((53, 57))); +mat!(match_basic_83, r"a*a*a*a*a*b", r"aaaaaaaaab", Some((0, 10))); +mat!(match_basic_84, r"^", r"", Some((0, 0))); +mat!(match_basic_85, r"$", r"", Some((0, 0))); +mat!(match_basic_86, r"^$", r"", Some((0, 0))); +mat!(match_basic_87, r"^a$", r"a", Some((0, 1))); +mat!(match_basic_88, r"abc", r"abc", Some((0, 3))); +mat!(match_basic_89, r"abc", r"xabcy", Some((1, 4))); +mat!(match_basic_90, r"abc", r"ababc", Some((2, 5))); +mat!(match_basic_91, r"ab*c", r"abc", Some((0, 3))); +mat!(match_basic_92, r"ab*bc", r"abc", Some((0, 3))); +mat!(match_basic_93, r"ab*bc", r"abbc", Some((0, 4))); +mat!(match_basic_94, r"ab*bc", r"abbbbc", Some((0, 6))); +mat!(match_basic_95, r"ab+bc", r"abbc", Some((0, 4))); +mat!(match_basic_96, r"ab+bc", r"abbbbc", Some((0, 6))); +mat!(match_basic_97, r"ab?bc", r"abbc", Some((0, 4))); +mat!(match_basic_98, r"ab?bc", r"abc", Some((0, 3))); +mat!(match_basic_99, r"ab?c", r"abc", Some((0, 3))); +mat!(match_basic_100, r"^abc$", r"abc", Some((0, 3))); +mat!(match_basic_101, r"^abc", r"abcc", Some((0, 3))); +mat!(match_basic_102, r"abc$", r"aabc", Some((1, 4))); +mat!(match_basic_103, r"^", r"abc", Some((0, 0))); +mat!(match_basic_104, r"$", r"abc", Some((3, 3))); +mat!(match_basic_105, r"a.c", r"abc", Some((0, 3))); +mat!(match_basic_106, r"a.c", r"axc", Some((0, 3))); +mat!(match_basic_107, r"a.*c", r"axyzc", Some((0, 5))); +mat!(match_basic_108, r"a[bc]d", r"abd", Some((0, 3))); +mat!(match_basic_109, r"a[b-d]e", r"ace", Some((0, 3))); +mat!(match_basic_110, r"a[b-d]", r"aac", Some((1, 3))); +mat!(match_basic_111, r"a[-b]", r"a-", Some((0, 2))); +mat!(match_basic_112, r"a[b-]", r"a-", Some((0, 2))); +mat!(match_basic_113, r"a]", r"a]", Some((0, 2))); +mat!(match_basic_114, r"a[]]b", r"a]b", Some((0, 3))); +mat!(match_basic_115, r"a[^bc]d", r"aed", Some((0, 3))); +mat!(match_basic_116, r"a[^-b]c", r"adc", Some((0, 3))); +mat!(match_basic_117, r"a[^]b]c", r"adc", Some((0, 3))); +mat!(match_basic_118, r"ab|cd", r"abc", Some((0, 2))); +mat!(match_basic_119, r"ab|cd", r"abcd", Some((0, 2))); +mat!(match_basic_120, r"a\(b", r"a(b", Some((0, 3))); +mat!(match_basic_121, r"a\(*b", r"ab", Some((0, 2))); +mat!(match_basic_122, r"a\(*b", r"a((b", Some((0, 4))); +mat!(match_basic_123, r"((a))", r"abc", Some((0, 1)), Some((0, 1)), Some((0, 1))); +mat!(match_basic_124, r"(a)b(c)", r"abc", Some((0, 3)), Some((0, 1)), Some((2, 3))); +mat!(match_basic_125, r"a+b+c", r"aabbabc", Some((4, 7))); +mat!(match_basic_126, r"a*", r"aaa", Some((0, 3))); +mat!(match_basic_128, r"(a*)*", r"-", Some((0, 0)), None); +mat!(match_basic_129, r"(a*)+", r"-", Some((0, 0)), Some((0, 0))); +mat!(match_basic_131, r"(a*|b)*", r"-", Some((0, 0)), None); +mat!(match_basic_132, r"(a+|b)*", r"ab", Some((0, 2)), Some((1, 2))); +mat!(match_basic_133, r"(a+|b)+", r"ab", Some((0, 2)), Some((1, 2))); +mat!(match_basic_134, r"(a+|b)?", r"ab", Some((0, 1)), Some((0, 1))); +mat!(match_basic_135, r"[^ab]*", r"cde", Some((0, 3))); +mat!(match_basic_137, r"(^)*", r"-", Some((0, 0)), None); +mat!(match_basic_138, r"a*", r"", Some((0, 0))); +mat!(match_basic_139, r"([abc])*d", r"abbbcd", Some((0, 6)), Some((4, 5))); +mat!(match_basic_140, r"([abc])*bcd", r"abcd", Some((0, 4)), Some((0, 1))); +mat!(match_basic_141, r"a|b|c|d|e", r"e", Some((0, 1))); +mat!(match_basic_142, r"(a|b|c|d|e)f", r"ef", Some((0, 2)), Some((0, 1))); +mat!(match_basic_144, r"((a*|b))*", r"-", Some((0, 0)), None, None); +mat!(match_basic_145, r"abcd*efg", r"abcdefg", Some((0, 7))); +mat!(match_basic_146, r"ab*", r"xabyabbbz", Some((1, 3))); +mat!(match_basic_147, r"ab*", r"xayabbbz", Some((1, 2))); +mat!(match_basic_148, r"(ab|cd)e", r"abcde", Some((2, 5)), Some((2, 4))); +mat!(match_basic_149, r"[abhgefdc]ij", r"hij", Some((0, 3))); +mat!(match_basic_150, r"(a|b)c*d", r"abcd", Some((1, 4)), Some((1, 2))); +mat!(match_basic_151, r"(ab|ab*)bc", r"abc", Some((0, 3)), Some((0, 1))); +mat!(match_basic_152, r"a([bc]*)c*", r"abc", Some((0, 3)), Some((1, 3))); +mat!(match_basic_153, r"a([bc]*)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4))); +mat!(match_basic_154, r"a([bc]+)(c*d)", r"abcd", Some((0, 4)), Some((1, 3)), Some((3, 4))); +mat!(match_basic_155, r"a([bc]*)(c+d)", r"abcd", Some((0, 4)), Some((1, 2)), Some((2, 4))); +mat!(match_basic_156, r"a[bcd]*dcdcde", r"adcdcde", Some((0, 7))); +mat!(match_basic_157, r"(ab|a)b*c", r"abc", Some((0, 3)), Some((0, 2))); +mat!(match_basic_158, r"((a)(b)c)(d)", r"abcd", Some((0, 4)), Some((0, 3)), Some((0, 1)), Some((1, 2)), Some((3, 4))); +mat!(match_basic_159, r"[A-Za-z_][A-Za-z0-9_]*", r"alpha", Some((0, 5))); +mat!(match_basic_160, r"^a(bc+|b[eh])g|.h$", r"abh", Some((1, 3))); +mat!(match_basic_161, r"(bc+d$|ef*g.|h?i(j|k))", r"effgz", Some((0, 5)), Some((0, 5))); +mat!(match_basic_162, r"(bc+d$|ef*g.|h?i(j|k))", r"ij", Some((0, 2)), Some((0, 2)), Some((1, 2))); +mat!(match_basic_163, r"(bc+d$|ef*g.|h?i(j|k))", r"reffgz", Some((1, 6)), Some((1, 6))); +mat!(match_basic_164, r"(((((((((a)))))))))", r"a", Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1)), Some((0, 1))); +mat!(match_basic_165, r"multiple words", r"multiple words yeah", Some((0, 14))); +mat!(match_basic_166, r"(.*)c(.*)", r"abcde", Some((0, 5)), Some((0, 2)), Some((3, 5))); +mat!(match_basic_167, r"abcd", r"abcd", Some((0, 4))); +mat!(match_basic_168, r"a(bc)d", r"abcd", Some((0, 4)), Some((1, 3))); +mat!(match_basic_169, r"a[-]?c", r"ac", Some((0, 3))); +mat!(match_basic_170, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qaddafi", Some((0, 15)), None, Some((10, 12))); +mat!(match_basic_171, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mo'ammar Gadhafi", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_172, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Kaddafi", Some((0, 15)), None, Some((10, 12))); +mat!(match_basic_173, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Qadhafi", Some((0, 15)), None, Some((10, 12))); +mat!(match_basic_174, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gadafi", Some((0, 14)), None, Some((10, 11))); +mat!(match_basic_175, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadafi", Some((0, 15)), None, Some((11, 12))); +mat!(match_basic_176, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moamar Gaddafi", Some((0, 14)), None, Some((9, 11))); +mat!(match_basic_177, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Mu'ammar Qadhdhafi", Some((0, 18)), None, Some((13, 15))); +mat!(match_basic_178, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Khaddafi", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_179, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafy", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_180, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghadafi", Some((0, 15)), None, Some((11, 12))); +mat!(match_basic_181, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Ghaddafi", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_182, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muamar Kaddafi", Some((0, 14)), None, Some((9, 11))); +mat!(match_basic_183, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Quathafi", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_184, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Muammar Gheddafi", Some((0, 16)), None, Some((11, 13))); +mat!(match_basic_185, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Khadafy", Some((0, 15)), None, Some((11, 12))); +mat!(match_basic_186, r"M[ou]'?am+[ae]r .*([AEae]l[- ])?[GKQ]h?[aeu]+([dtz][dhz]?)+af[iy]", r"Moammar Qudhafi", Some((0, 15)), None, Some((10, 12))); +mat!(match_basic_187, r"a+(b|c)*d+", r"aabcdd", Some((0, 6)), Some((3, 4))); +mat!(match_basic_188, r"^.+$", r"vivi", Some((0, 4))); +mat!(match_basic_189, r"^(.+)$", r"vivi", Some((0, 4)), Some((0, 4))); +mat!(match_basic_190, r"^([^!.]+).att.com!(.+)$", r"gryphon.att.com!eby", Some((0, 19)), Some((0, 7)), Some((16, 19))); +mat!(match_basic_191, r"^([^!]+!)?([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3))); +mat!(match_basic_192, r"^([^!]+!)?([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_193, r"^([^!]+!)?([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_194, r"^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), Some((4, 8)), Some((8, 11))); +mat!(match_basic_195, r"((foo)|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), None, Some((0, 3))); +mat!(match_basic_196, r"((foo)|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), None, Some((4, 7))); +mat!(match_basic_197, r"((foo)|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))); +mat!(match_basic_198, r"((foo)|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3))); +mat!(match_basic_199, r"((foo)|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7))); +mat!(match_basic_200, r"((foo)|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))); +mat!(match_basic_201, r"(foo|(bar))!bas", r"bar!bas", Some((0, 7)), Some((0, 3)), Some((0, 3))); +mat!(match_basic_202, r"(foo|(bar))!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7)), Some((4, 7))); +mat!(match_basic_203, r"(foo|(bar))!bas", r"foo!bas", Some((0, 7)), Some((0, 3))); +mat!(match_basic_204, r"(foo|bar)!bas", r"bar!bas", Some((0, 7)), Some((0, 3))); +mat!(match_basic_205, r"(foo|bar)!bas", r"foo!bar!bas", Some((4, 11)), Some((4, 7))); +mat!(match_basic_206, r"(foo|bar)!bas", r"foo!bas", Some((0, 7)), Some((0, 3))); +mat!(match_basic_207, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))); +mat!(match_basic_208, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bas", Some((0, 3)), None, Some((0, 3))); +mat!(match_basic_209, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"bar!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_210, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bar!bas", Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))); +mat!(match_basic_211, r"^([^!]+!)?([^!]+)$|^.+!([^!]+!)([^!]+)$", r"foo!bas", Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_212, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bas", Some((0, 3)), Some((0, 3)), None, Some((0, 3))); +mat!(match_basic_213, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"bar!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_214, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bar!bas", Some((0, 11)), Some((0, 11)), None, None, Some((4, 8)), Some((8, 11))); +mat!(match_basic_215, r"^(([^!]+!)?([^!]+)|.+!([^!]+!)([^!]+))$", r"foo!bas", Some((0, 7)), Some((0, 7)), Some((0, 4)), Some((4, 7))); +mat!(match_basic_216, r".*(/XXX).*", r"/XXX", Some((0, 4)), Some((0, 4))); +mat!(match_basic_217, r".*(\\XXX).*", r"\XXX", Some((0, 4)), Some((0, 4))); +mat!(match_basic_218, r"\\XXX", r"\XXX", Some((0, 4))); +mat!(match_basic_219, r".*(/000).*", r"/000", Some((0, 4)), Some((0, 4))); +mat!(match_basic_220, r".*(\\000).*", r"\000", Some((0, 4)), Some((0, 4))); +mat!(match_basic_221, r"\\000", r"\000", Some((0, 4))); + +// Tests from nullsubexpr.dat +mat!(match_nullsubexpr_3, r"(a*)*", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_5, r"(a*)*", r"x", Some((0, 0)), None); +mat!(match_nullsubexpr_6, r"(a*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_7, r"(a*)*", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_8, r"(a*)+", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_9, r"(a*)+", r"x", Some((0, 0)), Some((0, 0))); +mat!(match_nullsubexpr_10, r"(a*)+", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_11, r"(a*)+", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_12, r"(a+)*", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_13, r"(a+)*", r"x", Some((0, 0))); +mat!(match_nullsubexpr_14, r"(a+)*", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_15, r"(a+)*", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_16, r"(a+)+", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_17, r"(a+)+", r"x", None); +mat!(match_nullsubexpr_18, r"(a+)+", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_19, r"(a+)+", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_21, r"([a]*)*", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_23, r"([a]*)*", r"x", Some((0, 0)), None); +mat!(match_nullsubexpr_24, r"([a]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_25, r"([a]*)*", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_26, r"([a]*)+", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_27, r"([a]*)+", r"x", Some((0, 0)), Some((0, 0))); +mat!(match_nullsubexpr_28, r"([a]*)+", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_29, r"([a]*)+", r"aaaaaax", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_30, r"([^b]*)*", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_32, r"([^b]*)*", r"b", Some((0, 0)), None); +mat!(match_nullsubexpr_33, r"([^b]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_34, r"([^b]*)*", r"aaaaaab", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_35, r"([ab]*)*", r"a", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_36, r"([ab]*)*", r"aaaaaa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_37, r"([ab]*)*", r"ababab", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_38, r"([ab]*)*", r"bababa", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_39, r"([ab]*)*", r"b", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_40, r"([ab]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_41, r"([ab]*)*", r"aaaabcde", Some((0, 5)), Some((0, 5))); +mat!(match_nullsubexpr_42, r"([^a]*)*", r"b", Some((0, 1)), Some((0, 1))); +mat!(match_nullsubexpr_43, r"([^a]*)*", r"bbbbbb", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_45, r"([^a]*)*", r"aaaaaa", Some((0, 0)), None); +mat!(match_nullsubexpr_46, r"([^ab]*)*", r"ccccxx", Some((0, 6)), Some((0, 6))); +mat!(match_nullsubexpr_48, r"([^ab]*)*", r"ababab", Some((0, 0)), None); +mat!(match_nullsubexpr_50, r"((z)+|a)*", r"zabcde", Some((0, 2)), Some((1, 2))); +mat!(match_nullsubexpr_69, r"(a*)*(x)", r"x", Some((0, 1)), None, Some((0, 1))); +mat!(match_nullsubexpr_70, r"(a*)*(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2))); +mat!(match_nullsubexpr_71, r"(a*)*(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2))); +mat!(match_nullsubexpr_73, r"(a*)+(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1))); +mat!(match_nullsubexpr_74, r"(a*)+(x)", r"ax", Some((0, 2)), Some((0, 1)), Some((1, 2))); +mat!(match_nullsubexpr_75, r"(a*)+(x)", r"axa", Some((0, 2)), Some((0, 1)), Some((1, 2))); +mat!(match_nullsubexpr_77, r"(a*){2}(x)", r"x", Some((0, 1)), Some((0, 0)), Some((0, 1))); +mat!(match_nullsubexpr_78, r"(a*){2}(x)", r"ax", Some((0, 2)), Some((1, 1)), Some((1, 2))); +mat!(match_nullsubexpr_79, r"(a*){2}(x)", r"axa", Some((0, 2)), Some((1, 1)), Some((1, 2))); + +// Tests from repetition.dat +mat!(match_repetition_10, r"((..)|(.))", r"", None); +mat!(match_repetition_11, r"((..)|(.))((..)|(.))", r"", None); +mat!(match_repetition_12, r"((..)|(.))((..)|(.))((..)|(.))", r"", None); +mat!(match_repetition_14, r"((..)|(.)){1}", r"", None); +mat!(match_repetition_15, r"((..)|(.)){2}", r"", None); +mat!(match_repetition_16, r"((..)|(.)){3}", r"", None); +mat!(match_repetition_18, r"((..)|(.))*", r"", Some((0, 0))); +mat!(match_repetition_20, r"((..)|(.))", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))); +mat!(match_repetition_21, r"((..)|(.))((..)|(.))", r"a", None); +mat!(match_repetition_22, r"((..)|(.))((..)|(.))((..)|(.))", r"a", None); +mat!(match_repetition_24, r"((..)|(.)){1}", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))); +mat!(match_repetition_25, r"((..)|(.)){2}", r"a", None); +mat!(match_repetition_26, r"((..)|(.)){3}", r"a", None); +mat!(match_repetition_28, r"((..)|(.))*", r"a", Some((0, 1)), Some((0, 1)), None, Some((0, 1))); +mat!(match_repetition_30, r"((..)|(.))", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_31, r"((..)|(.))((..)|(.))", r"aa", Some((0, 2)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2))); +mat!(match_repetition_32, r"((..)|(.))((..)|(.))((..)|(.))", r"aa", None); +mat!(match_repetition_34, r"((..)|(.)){1}", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_35, r"((..)|(.)){2}", r"aa", Some((0, 2)), Some((1, 2)), None, Some((1, 2))); +mat!(match_repetition_36, r"((..)|(.)){3}", r"aa", None); +mat!(match_repetition_38, r"((..)|(.))*", r"aa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_40, r"((..)|(.))", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_41, r"((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3))); +mat!(match_repetition_42, r"((..)|(.))((..)|(.))((..)|(.))", r"aaa", Some((0, 3)), Some((0, 1)), None, Some((0, 1)), Some((1, 2)), None, Some((1, 2)), Some((2, 3)), None, Some((2, 3))); +mat!(match_repetition_44, r"((..)|(.)){1}", r"aaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_46, r"((..)|(.)){2}", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3))); +mat!(match_repetition_47, r"((..)|(.)){3}", r"aaa", Some((0, 3)), Some((2, 3)), None, Some((2, 3))); +mat!(match_repetition_50, r"((..)|(.))*", r"aaa", Some((0, 3)), Some((2, 3)), Some((0, 2)), Some((2, 3))); +mat!(match_repetition_52, r"((..)|(.))", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_53, r"((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_54, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 3)), None, Some((2, 3)), Some((3, 4)), None, Some((3, 4))); +mat!(match_repetition_56, r"((..)|(.)){1}", r"aaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_57, r"((..)|(.)){2}", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_59, r"((..)|(.)){3}", r"aaaa", Some((0, 4)), Some((3, 4)), Some((0, 2)), Some((3, 4))); +mat!(match_repetition_61, r"((..)|(.))*", r"aaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_63, r"((..)|(.))", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_64, r"((..)|(.))((..)|(.))", r"aaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_65, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaa", Some((0, 5)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 5)), None, Some((4, 5))); +mat!(match_repetition_67, r"((..)|(.)){1}", r"aaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_68, r"((..)|(.)){2}", r"aaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_70, r"((..)|(.)){3}", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5))); +mat!(match_repetition_73, r"((..)|(.))*", r"aaaaa", Some((0, 5)), Some((4, 5)), Some((2, 4)), Some((4, 5))); +mat!(match_repetition_75, r"((..)|(.))", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_76, r"((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 4)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_77, r"((..)|(.))((..)|(.))((..)|(.))", r"aaaaaa", Some((0, 6)), Some((0, 2)), Some((0, 2)), None, Some((2, 4)), Some((2, 4)), None, Some((4, 6)), Some((4, 6)), None); +mat!(match_repetition_79, r"((..)|(.)){1}", r"aaaaaa", Some((0, 2)), Some((0, 2)), Some((0, 2)), None); +mat!(match_repetition_80, r"((..)|(.)){2}", r"aaaaaa", Some((0, 4)), Some((2, 4)), Some((2, 4)), None); +mat!(match_repetition_81, r"((..)|(.)){3}", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None); +mat!(match_repetition_83, r"((..)|(.))*", r"aaaaaa", Some((0, 6)), Some((4, 6)), Some((4, 6)), None); +mat!(match_repetition_90, r"X(.?){0,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_91, r"X(.?){1,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_92, r"X(.?){2,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_93, r"X(.?){3,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_94, r"X(.?){4,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_95, r"X(.?){5,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_96, r"X(.?){6,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_97, r"X(.?){7,}Y", r"X1234567Y", Some((0, 9)), Some((7, 8))); +mat!(match_repetition_98, r"X(.?){8,}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_100, r"X(.?){0,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_102, r"X(.?){1,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_104, r"X(.?){2,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_106, r"X(.?){3,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_108, r"X(.?){4,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_110, r"X(.?){5,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_112, r"X(.?){6,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_114, r"X(.?){7,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_115, r"X(.?){8,8}Y", r"X1234567Y", Some((0, 9)), Some((8, 8))); +mat!(match_repetition_126, r"(a|ab|c|bcd){0,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_127, r"(a|ab|c|bcd){1,}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_128, r"(a|ab|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))); +mat!(match_repetition_129, r"(a|ab|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))); +mat!(match_repetition_130, r"(a|ab|c|bcd){4,}(d*)", r"ababcd", None); +mat!(match_repetition_131, r"(a|ab|c|bcd){0,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_132, r"(a|ab|c|bcd){1,10}(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_133, r"(a|ab|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))); +mat!(match_repetition_134, r"(a|ab|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((3, 6)), Some((6, 6))); +mat!(match_repetition_135, r"(a|ab|c|bcd){4,10}(d*)", r"ababcd", None); +mat!(match_repetition_136, r"(a|ab|c|bcd)*(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_137, r"(a|ab|c|bcd)+(d*)", r"ababcd", Some((0, 1)), Some((0, 1)), Some((1, 1))); +mat!(match_repetition_143, r"(ab|a|c|bcd){0,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_145, r"(ab|a|c|bcd){1,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_147, r"(ab|a|c|bcd){2,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_149, r"(ab|a|c|bcd){3,}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_150, r"(ab|a|c|bcd){4,}(d*)", r"ababcd", None); +mat!(match_repetition_152, r"(ab|a|c|bcd){0,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_154, r"(ab|a|c|bcd){1,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_156, r"(ab|a|c|bcd){2,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_158, r"(ab|a|c|bcd){3,10}(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_159, r"(ab|a|c|bcd){4,10}(d*)", r"ababcd", None); +mat!(match_repetition_161, r"(ab|a|c|bcd)*(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); +mat!(match_repetition_163, r"(ab|a|c|bcd)+(d*)", r"ababcd", Some((0, 6)), Some((4, 5)), Some((5, 6))); + diff --git a/regex/tests/macros.rs b/regex/tests/macros.rs new file mode 100644 index 000000000..3c4b888b2 --- /dev/null +++ b/regex/tests/macros.rs @@ -0,0 +1,149 @@ +// Convenience macros. + +macro_rules! findall { + ($re:expr, $text:expr) => {{ + $re.find_iter(text!($text)) + .map(|m| (m.start(), m.end())).collect::<Vec<_>>() + }} +} + +// Macros for automatically producing tests. + +macro_rules! ismatch { + ($name:ident, $re:expr, $text:expr, $ismatch:expr) => { + #[test] + fn $name() { + let re = regex!($re); + assert_eq!($ismatch, re.is_match(text!($text))); + } + }; +} + +macro_rules! mat( + ($name:ident, $re:expr, $text:expr, $($loc:tt)+) => ( + #[test] + fn $name() { + let text = text!($text); + let expected: Vec<Option<_>> = vec![$($loc)+]; + let r = regex!($re); + let got: Vec<Option<_>> = match r.captures(text) { + Some(c) => { + assert!(r.is_match(text)); + assert!(r.shortest_match(text).is_some()); + r.capture_names() + .enumerate() + .map(|(i, _)| c.get(i).map(|m| (m.start(), m.end()))) + .collect() + } + None => vec![None], + }; + // The test set sometimes leave out capture groups, so truncate + // actual capture groups to match test set. + let mut sgot = &got[..]; + if sgot.len() > expected.len() { + sgot = &sgot[0..expected.len()] + } + if expected != sgot { + panic!("For RE '{}' against '{:?}', \ + expected '{:?}' but got '{:?}'", + $re, text, expected, sgot); + } + } + ); +); + +macro_rules! matiter( + ($name:ident, $re:expr, $text:expr) => ( + #[test] + fn $name() { + let text = text!($text); + let expected: Vec<(usize, usize)> = vec![]; + let r = regex!($re); + let got: Vec<_> = + r.find_iter(text).map(|m| (m.start(), m.end())).collect(); + if expected != got { + panic!("For RE '{}' against '{:?}', \ + expected '{:?}' but got '{:?}'", + $re, text, expected, got); + } + let captures_got: Vec<_> = + r.captures_iter(text) + .map(|c| c.get(0).unwrap()) + .map(|m| (m.start(), m.end())) + .collect(); + if captures_got != got { + panic!("For RE '{}' against '{:?}', \ + got '{:?}' using find_iter but got '{:?}' \ + using captures_iter", + $re, text, got, captures_got); + } + } + ); + ($name:ident, $re:expr, $text:expr, $($loc:tt)+) => ( + #[test] + fn $name() { + let text = text!($text); + let expected: Vec<_> = vec![$($loc)+]; + let r = regex!($re); + let got: Vec<_> = + r.find_iter(text).map(|m| (m.start(), m.end())).collect(); + if expected != got { + panic!("For RE '{}' against '{:?}', \ + expected '{:?}' but got '{:?}'", + $re, text, expected, got); + } + let captures_got: Vec<_> = + r.captures_iter(text) + .map(|c| c.get(0).unwrap()) + .map(|m| (m.start(), m.end())) + .collect(); + if captures_got != got { + panic!("For RE '{}' against '{:?}', \ + got '{:?}' using find_iter but got '{:?}' \ + using captures_iter", + $re, text, got, captures_got); + } + } + ); +); + +macro_rules! matset { + ($name:ident, $res:expr, $text:expr, $($match_index:expr),*) => { + #[test] + fn $name() { + let text = text!($text); + let set = regex_set!($res); + assert!(set.is_match(text)); + let expected = vec![$($match_index),*]; + let matches = set.matches(text); + assert!(matches.matched_any()); + let got: Vec<_> = matches.into_iter().collect(); + assert_eq!(expected, got); + } + } +} + +macro_rules! nomatset { + ($name:ident, $res:expr, $text:expr) => { + #[test] + fn $name() { + let text = text!($text); + let set = regex_set!($res); + assert!(!set.is_match(text)); + let matches = set.matches(text); + assert!(!matches.matched_any()); + assert_eq!(0, matches.into_iter().count()); + } + } +} + +macro_rules! split { + ($name:ident, $re:expr, $text:expr, $expected:expr) => { + #[test] + fn $name() { + let re = regex!($re); + let splitted: Vec<_> = re.split(t!($text)).collect(); + assert_eq!($expected, &*splitted); + } + } +} diff --git a/regex/tests/macros_bytes.rs b/regex/tests/macros_bytes.rs new file mode 100644 index 000000000..7605d69b2 --- /dev/null +++ b/regex/tests/macros_bytes.rs @@ -0,0 +1,39 @@ +// Macros for use in writing tests generic over &str/&[u8]. +macro_rules! text { ($text:expr) => { $text.as_bytes() } } +macro_rules! t { ($re:expr) => { text!($re) } } +macro_rules! match_text { ($text:expr) => { $text.as_bytes() } } +macro_rules! use_ { ($($path: tt)*) => { use regex::bytes::$($path)*; } } + +macro_rules! bytes { ($text:expr) => { $text } } + +macro_rules! no_expand { + ($text:expr) => {{ + use regex::bytes::NoExpand; + NoExpand(text!($text)) + }} +} + +macro_rules! show { + ($text:expr) => {{ + use std::ascii::escape_default; + let mut s = vec![]; + for &b in bytes!($text) { + s.extend(escape_default(b)); + } + String::from_utf8(s).unwrap() + }} +} + +macro_rules! expand { + ($name:ident, $re:expr, $text:expr, $expand:expr, $expected:expr) => { + #[test] + fn $name() { + let re = regex!($re); + let cap = re.captures(t!($text)).unwrap(); + + let mut got = vec![]; + cap.expand(t!($expand), &mut got); + assert_eq!(show!(t!($expected)), show!(&*got)); + } + } +} diff --git a/regex/tests/macros_str.rs b/regex/tests/macros_str.rs new file mode 100644 index 000000000..fda5814b8 --- /dev/null +++ b/regex/tests/macros_str.rs @@ -0,0 +1,36 @@ +// Macros for use in writing tests generic over &str/&[u8]. +macro_rules! text { ($text:expr) => { $text } } +macro_rules! t { ($text:expr) => { text!($text) } } +macro_rules! match_text { ($text:expr) => { $text.as_str() } } +macro_rules! use_ { ($($path: tt)*) => { use regex::$($path)*; } } + +macro_rules! no_expand { + ($text:expr) => {{ + use regex::NoExpand; + NoExpand(text!($text)) + }} +} + +macro_rules! show { ($text:expr) => { $text } } + +// N.B. The expansion API for &str and &[u8] APIs differs slightly for now, +// but they should be unified in 1.0. Then we can move this macro back into +// tests/api.rs where it is used. ---AG +macro_rules! expand { + ($name:ident, $re:expr, $text:expr, $expand:expr, $expected:expr) => { + #[test] + fn $name() { + let re = regex!($re); + let cap = re.captures(t!($text)).unwrap(); + + let mut got = String::new(); + cap.expand(t!($expand), &mut got); + assert_eq!(show!(t!($expected)), show!(&*got)); + } + } +} + +#[cfg(feature = "pattern")] +macro_rules! searcher_expr { ($e:expr) => ($e) } +#[cfg(not(feature = "pattern"))] +macro_rules! searcher_expr { ($e:expr) => ({}) } diff --git a/regex/tests/misc.rs b/regex/tests/misc.rs new file mode 100644 index 000000000..dfe28c970 --- /dev/null +++ b/regex/tests/misc.rs @@ -0,0 +1,14 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mat!(prefix_literal_match, r"^abc", r"abc", Some((0, 3))); +mat!(prefix_literal_nomatch, r"^abc", r"zabc", None); +mat!(one_literal_edge, r"abc", r"xxxxxab", None); +matiter!(terminates, r"a$", r"a", (0, 1)); diff --git a/regex/tests/multiline.rs b/regex/tests/multiline.rs new file mode 100644 index 000000000..191504aa7 --- /dev/null +++ b/regex/tests/multiline.rs @@ -0,0 +1,49 @@ +matiter!(match_multi_1, r"(?m)^[a-z]+$", "abc\ndef\nxyz", + (0, 3), (4, 7), (8, 11)); +matiter!(match_multi_2, r"(?m)^$", "abc\ndef\nxyz"); +matiter!(match_multi_3, r"(?m)^", "abc\ndef\nxyz", + (0, 0), (4, 4), (8, 8)); +matiter!(match_multi_4, r"(?m)$", "abc\ndef\nxyz", + (3, 3), (7, 7), (11, 11)); +matiter!(match_multi_5, r"(?m)^[a-z]", "abc\ndef\nxyz", + (0, 1), (4, 5), (8, 9)); +matiter!(match_multi_6, r"(?m)[a-z]^", "abc\ndef\nxyz"); +matiter!(match_multi_7, r"(?m)[a-z]$", "abc\ndef\nxyz", + (2, 3), (6, 7), (10, 11)); +matiter!(match_multi_8, r"(?m)$[a-z]", "abc\ndef\nxyz"); +matiter!(match_multi_9, r"(?m)^$", "", (0, 0)); + +matiter!(match_multi_rep_1, r"(?m)(?:^$)*", "a\nb\nc", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)); +matiter!(match_multi_rep_2, r"(?m)(?:^|a)+", "a\naaa\n", + (0, 0), (2, 2), (3, 5), (6, 6)); +matiter!(match_multi_rep_3, r"(?m)(?:^|a)*", "a\naaa\n", + (0, 1), (2, 5), (6, 6)); +matiter!(match_multi_rep_4, r"(?m)(?:^[a-z])+", "abc\ndef\nxyz", + (0, 1), (4, 5), (8, 9)); +matiter!(match_multi_rep_5, r"(?m)(?:^[a-z]{3}\n?)+", "abc\ndef\nxyz", + (0, 11)); +matiter!(match_multi_rep_6, r"(?m)(?:^[a-z]{3}\n?)*", "abc\ndef\nxyz", + (0, 11)); +matiter!(match_multi_rep_7, r"(?m)(?:\n?[a-z]{3}$)+", "abc\ndef\nxyz", + (0, 11)); +matiter!(match_multi_rep_8, r"(?m)(?:\n?[a-z]{3}$)*", "abc\ndef\nxyz", + (0, 11)); +matiter!(match_multi_rep_9, r"(?m)^*", "\naa\n", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4)); +matiter!(match_multi_rep_10, r"(?m)^+", "\naa\n", + (0, 0), (1, 1), (4, 4)); +matiter!(match_multi_rep_11, r"(?m)$*", "\naa\n", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4)); +matiter!(match_multi_rep_12, r"(?m)$+", "\naa\n", + (0, 0), (3, 3), (4, 4)); +matiter!(match_multi_rep_13, r"(?m)(?:$\n)+", "\n\naaa\n\n", + (0, 2), (5, 7)); +matiter!(match_multi_rep_14, r"(?m)(?:$\n)*", "\n\naaa\n\n", + (0, 2), (3, 3), (4, 4), (5, 7)); +matiter!(match_multi_rep_15, r"(?m)(?:$\n^)+", "\n\naaa\n\n", + (0, 2), (5, 7)); +matiter!(match_multi_rep_16, r"(?m)(?:^|$)+", "\n\naaa\n\n", + (0, 0), (1, 1), (2, 2), (5, 5), (6, 6), (7, 7)); +matiter!(match_multi_rep_17, r"(?m)(?:$\n)*", "\n\naaa\n\n", + (0, 2), (3, 3), (4, 4), (5, 7)); diff --git a/regex/tests/noparse.rs b/regex/tests/noparse.rs new file mode 100644 index 000000000..62eb5be77 --- /dev/null +++ b/regex/tests/noparse.rs @@ -0,0 +1,50 @@ +macro_rules! noparse( + ($name:ident, $re:expr) => ( + #[test] + fn $name() { + let re = $re; + match regex_new!(re) { + Err(_) => {}, + Ok(_) => panic!("Regex '{}' should cause a parse error.", re), + } + } + ); +); + +noparse!(fail_no_repeat_arg, "*"); +noparse!(fail_incomplete_escape, "\\"); +noparse!(fail_class_incomplete, "[A-"); +noparse!(fail_class_not_closed, "[A"); +noparse!(fail_class_no_begin, r"[\A]"); +noparse!(fail_class_no_end, r"[\z]"); +noparse!(fail_class_no_boundary, r"[\b]"); +noparse!(fail_open_paren, "("); +noparse!(fail_close_paren, ")"); +noparse!(fail_invalid_range, "[a-Z]"); +noparse!(fail_empty_capture_name, "(?P<>a)"); +noparse!(fail_bad_capture_name, "(?P<na-me>)"); +noparse!(fail_bad_flag, "(?a)a"); +noparse!(fail_too_big, "a{10000000}"); +noparse!(fail_counted_no_close, "a{1001"); +noparse!(fail_unfinished_cap, "(?"); +noparse!(fail_unfinished_escape, "\\"); +noparse!(fail_octal_digit, r"\8"); +noparse!(fail_hex_digit, r"\xG0"); +noparse!(fail_hex_short, r"\xF"); +noparse!(fail_hex_long_digits, r"\x{fffg}"); +noparse!(fail_flag_bad, "(?a)"); +noparse!(fail_flag_empty, "(?)"); +noparse!(fail_double_neg, "(?-i-i)"); +noparse!(fail_neg_empty, "(?i-)"); +noparse!(fail_dupe_named, "(?P<a>.)(?P<a>.)"); +noparse!(fail_range_end_no_class, "[a-[:lower:]]"); +noparse!(fail_range_end_no_begin, r"[a-\A]"); +noparse!(fail_range_end_no_end, r"[a-\z]"); +noparse!(fail_range_end_no_boundary, r"[a-\b]"); +noparse!(fail_empty_alt1, r"|z"); +noparse!(fail_empty_alt2, r"z|"); +noparse!(fail_empty_alt3, r"|"); +noparse!(fail_empty_alt4, r"||"); +noparse!(fail_empty_alt5, r"()|z"); +noparse!(fail_empty_alt6, r"z|()"); +noparse!(fail_empty_alt7, r"(|)"); diff --git a/regex/tests/regression.rs b/regex/tests/regression.rs new file mode 100644 index 000000000..bc3eac255 --- /dev/null +++ b/regex/tests/regression.rs @@ -0,0 +1,150 @@ +// See: https://github.com/rust-lang/regex/issues/48 +#[test] +fn invalid_regexes_no_crash() { + assert!(regex_new!("(*)").is_err()); + assert!(regex_new!("(?:?)").is_err()); + assert!(regex_new!("(?)").is_err()); + assert!(regex_new!("*").is_err()); +} + +// See: https://github.com/rust-lang/regex/issues/98 +#[test] +fn regression_many_repeat_stack_overflow() { + let re = regex!("^.{1,2500}"); + assert_eq!(vec![(0, 1)], findall!(re, "a")); +} + +// See: https://github.com/rust-lang/regex/issues/555 +#[test] +fn regression_invalid_repetition_expr() { + assert!(regex_new!("(?m){1,1}").is_err()); +} + +// See: https://github.com/rust-lang/regex/issues/527 +#[test] +fn regression_invalid_flags_expression() { + assert!(regex_new!("(((?x)))").is_ok()); +} + +// See: https://github.com/rust-lang/regex/issues/75 +mat!(regression_unsorted_binary_search_1, r"(?i)[a_]+", "A_", Some((0, 2))); +mat!(regression_unsorted_binary_search_2, r"(?i)[A_]+", "a_", Some((0, 2))); + +// See: https://github.com/rust-lang/regex/issues/99 +mat!(regression_negated_char_class_1, r"(?i)[^x]", "x", None); +mat!(regression_negated_char_class_2, r"(?i)[^x]", "X", None); + +// See: https://github.com/rust-lang/regex/issues/101 +mat!(regression_ascii_word_underscore, r"[[:word:]]", "_", Some((0, 1))); + +// See: https://github.com/rust-lang/regex/issues/129 +#[test] +fn regression_captures_rep() { + let re = regex!(r"([a-f]){2}(?P<foo>[x-z])"); + let caps = re.captures(text!("abx")).unwrap(); + assert_eq!(match_text!(caps.name("foo").unwrap()), text!("x")); +} + +// See: https://github.com/rust-lang/regex/issues/153 +mat!(regression_alt_in_alt1, r"ab?|$", "az", Some((0, 1))); +mat!(regression_alt_in_alt2, r"^(.*?)(\n|\r\n?|$)", "ab\rcd", Some((0, 3))); + +// See: https://github.com/rust-lang/regex/issues/169 +mat!(regression_leftmost_first_prefix, r"z*azb", "azb", Some((0, 3))); + +// See: https://github.com/rust-lang/regex/issues/76 +mat!(uni_case_lower_nocase_flag, r"(?i)\p{Ll}+", "ΛΘΓΔα", Some((0, 10))); + +// See: https://github.com/rust-lang/regex/issues/191 +mat!(many_alternates, r"1|2|3|4|5|6|7|8|9|10|int", "int", Some((0, 3))); + +// burntsushi was bad and didn't create an issue for this bug. +mat!(anchored_prefix1, r"^a\S", "a ", None); +mat!(anchored_prefix2, r"^a\S", "foo boo a ", None); +mat!(anchored_prefix3, r"^-[a-z]", "r-f", None); + +// See: https://github.com/rust-lang/regex/issues/204 +split!(split_on_word_boundary, r"\b", r"Should this (work?)", + &[t!(""), t!("Should"), t!(" "), t!("this"), + t!(" ("), t!("work"), t!("?)")]); +matiter!(word_boundary_dfa, r"\b", "a b c", + (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)); + +// See: https://github.com/rust-lang/regex/issues/268 +matiter!(partial_anchor, r"^a|b", "ba", (0, 1)); + +// See: https://github.com/rust-lang/regex/issues/280 +ismatch!(partial_anchor_alternate_begin, r"^a|z", "yyyyya", false); +ismatch!(partial_anchor_alternate_end, r"a$|z", "ayyyyy", false); + +// See: https://github.com/rust-lang/regex/issues/289 +mat!(lits_unambiguous1, r"(ABC|CDA|BC)X", "CDAX", Some((0, 4))); + +// See: https://github.com/rust-lang/regex/issues/291 +mat!(lits_unambiguous2, r"((IMG|CAM|MG|MB2)_|(DSCN|CIMG))(?P<n>[0-9]+)$", + "CIMG2341", Some((0, 8)), Some((0, 4)), None, Some((0, 4)), Some((4, 8))); + +// See: https://github.com/rust-lang/regex/issues/271 +mat!(endl_or_wb, r"(?m:$)|(?-u:\b)", "\u{6084e}", Some((4, 4))); +mat!(zero_or_end, r"(?i-u:\x00)|$", "\u{e682f}", Some((4, 4))); +mat!(y_or_endl, r"(?i-u:y)|(?m:$)", "\u{b4331}", Some((4, 4))); +mat!(wb_start_x, r"(?u:\b)^(?-u:X)", "X", Some((0, 1))); + +// See: https://github.com/rust-lang/regex/issues/321 +ismatch!(strange_anchor_non_complete_prefix, r"a^{2}", "", false); +ismatch!(strange_anchor_non_complete_suffix, r"${2}a", "", false); + +// See: https://github.com/BurntSushi/ripgrep/issues/1203 +ismatch!(reverse_suffix1, r"[0-4][0-4][0-4]000", "153.230000", true); +ismatch!(reverse_suffix2, r"\d\d\d000", "153.230000\n", true); +matiter!(reverse_suffix3, r"\d\d\d000", "153.230000\n", (4, 10)); + +// See: https://github.com/rust-lang/regex/issues/334 +// See: https://github.com/rust-lang/regex/issues/557 +mat!(captures_after_dfa_premature_end1, r"a(b*(X|$))?", "abcbX", + Some((0, 1)), None, None); +mat!(captures_after_dfa_premature_end2, r"a(bc*(X|$))?", "abcbX", + Some((0, 1)), None, None); +mat!(captures_after_dfa_premature_end3, r"(aa$)?", "aaz", + Some((0, 0))); + +// See: https://github.com/rust-lang/regex/issues/437 +ismatch!( + literal_panic, + r"typename type\-parameter\-\d+\-\d+::.+", + "test", + false); + +// See: https://github.com/rust-lang/regex/issues/533 +ismatch!( + blank_matches_nothing_between_space_and_tab, + r"[[:blank:]]", + "\u{a}\u{b}\u{c}\u{d}\u{e}\u{f}\ + \u{10}\u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\ + \u{18}\u{19}\u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f}", + false); + +ismatch!( + inverted_blank_matches_everything_between_space_and_tab, + r"^[[:^blank:]]+$", + "\u{a}\u{b}\u{c}\u{d}\u{e}\u{f}\ + \u{10}\u{11}\u{12}\u{13}\u{14}\u{15}\u{16}\u{17}\ + \u{18}\u{19}\u{1a}\u{1b}\u{1c}\u{1d}\u{1e}\u{1f}", + true); + +// Tests that our Aho-Corasick optimization works correctly. It only +// kicks in when we have >32 literals. +mat!( + ahocorasick1, + "samwise|sam|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|\ + A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z", + "samwise", + Some((0, 7)) +); + +// See: https://github.com/BurntSushi/ripgrep/issues/1247 +#[test] +fn regression_nfa_stops1() { + let re = ::regex::bytes::Regex::new(r"\bs(?:[ab])").unwrap(); + assert_eq!(0, re.find_iter(b"s\xE4").count()); +} diff --git a/regex/tests/replace.rs b/regex/tests/replace.rs new file mode 100644 index 000000000..6d5a5b13b --- /dev/null +++ b/regex/tests/replace.rs @@ -0,0 +1,50 @@ +macro_rules! replace( + ($name:ident, $which:ident, $re:expr, + $search:expr, $replace:expr, $result:expr) => ( + #[test] + fn $name() { + let re = regex!($re); + assert_eq!(re.$which(text!($search), $replace), text!($result)); + } + ); +); + +replace!(first, replace, r"\d", "age: 26", t!("Z"), "age: Z6"); +replace!(plus, replace, r"\d+", "age: 26", t!("Z"), "age: Z"); +replace!(all, replace_all, r"\d", "age: 26", t!("Z"), "age: ZZ"); +replace!(groups, replace, r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $1"), "w2 w1"); +replace!(double_dollar, replace, + r"(\S+)\s+(\S+)", "w1 w2", t!("$2 $$1"), "w2 $1"); +// replace!(adjacent_index, replace, + // r"([^aeiouy])ies$", "skies", t!("$1y"), "sky"); +replace!(named, replace_all, + r"(?P<first>\S+)\s+(?P<last>\S+)(?P<space>\s*)", + "w1 w2 w3 w4", t!("$last $first$space"), "w2 w1 w4 w3"); +replace!(trim, replace_all, "^[ \t]+|[ \t]+$", " \t trim me\t \t", + t!(""), "trim me"); +replace!(number_hypen, replace, r"(.)(.)", "ab", t!("$1-$2"), "a-b"); +// replace!(number_underscore, replace, r"(.)(.)", "ab", t!("$1_$2"), "a_b"); +replace!(simple_expand, replace_all, r"(\w) (\w)", "a b", t!("$2 $1"), "b a"); +replace!(literal_dollar1, replace_all, + r"(\w+) (\w+)", "a b", t!("$$1"), "$1"); +replace!(literal_dollar2, replace_all, + r"(\w+) (\w+)", "a b", t!("$2 $$c $1"), "b $c a"); +replace!(no_expand1, replace, + r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$2 $1"), "$2 $1"); +replace!(no_expand2, replace, + r"(\S+)\s+(\S+)", "w1 w2", no_expand!("$$1"), "$$1"); +use_!(Captures); +replace!(closure_returning_reference, replace, r"(\d+)", "age: 26", + | captures: &Captures | &match_text!(captures.get(1).unwrap())[0..1], "age: 2"); +replace!(closure_returning_value, replace, r"\d+", "age: 26", + | _captures: &Captures | t!("Z").to_owned(), "age: Z"); + + +// See https://github.com/rust-lang/regex/issues/314 +replace!(match_at_start_replace_with_empty, replace_all, r"foo", "foobar", t!(""), "bar"); + +// See https://github.com/rust-lang/regex/issues/393 +replace!(single_empty_match, replace, r"^", "bar", t!("foo"), "foobar"); + +// See https://github.com/rust-lang/regex/issues/399 +replace!(capture_longest_possible_name, replace_all, r"(.)", "b", t!("${1}a $1a"), "ba "); diff --git a/regex/tests/searcher.rs b/regex/tests/searcher.rs new file mode 100644 index 000000000..073fa5f96 --- /dev/null +++ b/regex/tests/searcher.rs @@ -0,0 +1,66 @@ +macro_rules! searcher { + ($name:ident, $re:expr, $haystack:expr) => ( + searcher!($name, $re, $haystack, vec vec![]); + ); + ($name:ident, $re:expr, $haystack:expr, $($steps:expr,)*) => ( + searcher!($name, $re, $haystack, vec vec![$($steps),*]); + ); + ($name:ident, $re:expr, $haystack:expr, $($steps:expr),*) => ( + searcher!($name, $re, $haystack, vec vec![$($steps),*]); + ); + ($name:ident, $re:expr, $haystack:expr, vec $expect_steps:expr) => ( + #[test] + #[allow(unused_imports)] + fn $name() { + searcher_expr! {{ + use std::str::pattern::{Pattern, Searcher}; + use std::str::pattern::SearchStep::{Match, Reject, Done}; + let re = regex!($re); + let mut se = re.into_searcher($haystack); + let mut got_steps = vec![]; + loop { + match se.next() { + Done => break, + step => { got_steps.push(step); } + } + } + assert_eq!(got_steps, $expect_steps); + }} + } + ); +} + +searcher!(searcher_empty_regex_empty_haystack, r"", "", Match(0, 0)); +searcher!(searcher_empty_regex, r"", "ab", + Match(0, 0), Reject(0, 1), Match(1, 1), Reject(1, 2), Match(2, 2)); +searcher!(searcher_empty_haystack, r"\d", ""); +searcher!(searcher_one_match, r"\d", "5", + Match(0, 1)); +searcher!(searcher_no_match, r"\d", "a", + Reject(0, 1)); +searcher!(searcher_two_adjacent_matches, r"\d", "56", + Match(0, 1), Match(1, 2)); +searcher!(searcher_two_non_adjacent_matches, r"\d", "5a6", + Match(0, 1), Reject(1, 2), Match(2, 3)); +searcher!(searcher_reject_first, r"\d", "a6", + Reject(0, 1), Match(1, 2)); +searcher!(searcher_one_zero_length_matches, r"\d*", "a1b2", + Match(0, 0), // ^ + Reject(0, 1), // a + Match(1, 2), // a1 + Reject(2, 3), // a1b + Match(3, 4), // a1b2 +); +searcher!(searcher_many_zero_length_matches, r"\d*", "a1bbb2", + Match(0, 0), // ^ + Reject(0, 1), // a + Match(1, 2), // a1 + Reject(2, 3), // a1b + Match(3, 3), // a1bb + Reject(3, 4), // a1bb + Match(4, 4), // a1bbb + Reject(4, 5), // a1bbb + Match(5, 6), // a1bbba +); +searcher!(searcher_unicode, r".+?", "Ⅰ1Ⅱ2", + Match(0, 3), Match(3, 4), Match(4, 7), Match(7, 8)); diff --git a/regex/tests/set.rs b/regex/tests/set.rs new file mode 100644 index 000000000..5beeed2f1 --- /dev/null +++ b/regex/tests/set.rs @@ -0,0 +1,38 @@ +matset!(set1, &["a", "a"], "a", 0, 1); +matset!(set2, &["a", "a"], "ba", 0, 1); +matset!(set3, &["a", "b"], "a", 0); +matset!(set4, &["a", "b"], "b", 1); +matset!(set5, &["a|b", "b|a"], "b", 0, 1); +matset!(set6, &["foo", "oo"], "foo", 0, 1); +matset!(set7, &["^foo", "bar$"], "foo", 0); +matset!(set8, &["^foo", "bar$"], "foo bar", 0, 1); +matset!(set9, &["^foo", "bar$"], "bar", 1); +matset!(set10, &[r"[a-z]+$", "foo"], "01234 foo", 0, 1); +matset!(set11, &[r"[a-z]+$", "foo"], "foo 01234", 1); +matset!(set12, &[r".*?", "a"], "zzzzzza", 0, 1); +matset!(set13, &[r".*", "a"], "zzzzzza", 0, 1); +matset!(set14, &[r".*", "a"], "zzzzzz", 0); +matset!(set15, &[r"\ba\b"], "hello a bye", 0); +matset!(set16, &["a"], "a", 0); +matset!(set17, &[".*a"], "a", 0); +matset!(set18, &["a", "β"], "β", 1); + +nomatset!(nset1, &["a", "a"], "b"); +nomatset!(nset2, &["^foo", "bar$"], "bar foo"); +nomatset!(nset3, { let xs: &[&str] = &[]; xs }, "a"); +nomatset!(nset4, &[r"^rooted$", r"\.log$"], "notrooted"); + +// See: https://github.com/rust-lang/regex/issues/187 +#[test] +fn regression_subsequent_matches() { + let set = regex_set!(&["ab", "b"]); + let text = text!("ba"); + assert!(set.matches(text).matched(1)); + assert!(set.matches(text).matched(1)); +} + +#[test] +fn get_set_patterns() { + let set = regex_set!(&["a", "b"]); + assert_eq!(vec!["a", "b"], set.patterns()); +} diff --git a/regex/tests/shortest_match.rs b/regex/tests/shortest_match.rs new file mode 100644 index 000000000..c964ab913 --- /dev/null +++ b/regex/tests/shortest_match.rs @@ -0,0 +1,14 @@ +macro_rules! shortmat { + ($name:ident, $re:expr, $text:expr, $shortest_match:expr) => { + #[test] + fn $name() { + let text = text!($text); + let re = regex!($re); + assert_eq!($shortest_match, re.shortest_match(text)); + } + } +} + +shortmat!(t01, r"a+", r"aa", Some(1)); +// Test that the reverse suffix optimization gets it right. +shortmat!(t02, r".*(?:abcd)+", r"abcdabcd", Some(4)); diff --git a/regex/tests/suffix_reverse.rs b/regex/tests/suffix_reverse.rs new file mode 100644 index 000000000..f2993553f --- /dev/null +++ b/regex/tests/suffix_reverse.rs @@ -0,0 +1,16 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mat!(t01, r".*abcd", r"abcd", Some((0, 4))); +mat!(t02, r".*(?:abcd)+", r"abcd", Some((0, 4))); +mat!(t03, r".*(?:abcd)+", r"abcdabcd", Some((0, 8))); +mat!(t04, r".*(?:abcd)+", r"abcdxabcd", Some((0, 9))); +mat!(t05, r".*x(?:abcd)+", r"abcdxabcd", Some((0, 9))); +mat!(t06, r"[^abcd]*x(?:abcd)+", r"abcdxabcd", Some((4, 9))); diff --git a/regex/tests/test_backtrack.rs b/regex/tests/test_backtrack.rs new file mode 100644 index 000000000..5516c840e --- /dev/null +++ b/regex/tests/test_backtrack.rs @@ -0,0 +1,64 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(feature = "pattern", feature(pattern))] + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re) + .bounded_backtracking().build().map(|e| e.into_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re) + .bounded_backtracking() + .build() + .map(|e| e.into_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_str.rs"); +include!("macros.rs"); + +mod api; +mod api_str; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod searcher; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_unicode; diff --git a/regex/tests/test_backtrack_bytes.rs b/regex/tests/test_backtrack_bytes.rs new file mode 100644 index 000000000..4ea60e7d0 --- /dev/null +++ b/regex/tests/test_backtrack_bytes.rs @@ -0,0 +1,65 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re) + .bounded_backtracking() + .only_utf8(false) + .build() + .map(|e| e.into_byte_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re) + .bounded_backtracking() + .only_utf8(false) + .build() + .map(|e| e.into_byte_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_bytes.rs"); +include!("macros.rs"); + +mod api; +mod bytes; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_ascii; diff --git a/regex/tests/test_backtrack_utf8bytes.rs b/regex/tests/test_backtrack_utf8bytes.rs new file mode 100644 index 000000000..a170d1932 --- /dev/null +++ b/regex/tests/test_backtrack_utf8bytes.rs @@ -0,0 +1,65 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(feature = "pattern", feature(pattern))] + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re) + .bounded_backtracking().bytes(true).build().map(|e| e.into_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re) + .bounded_backtracking() + .bytes(true) + .build() + .map(|e| e.into_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_str.rs"); +include!("macros.rs"); + +mod api; +mod api_str; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod searcher; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_unicode; diff --git a/regex/tests/test_crates_regex.rs b/regex/tests/test_crates_regex.rs new file mode 100644 index 000000000..1f9ce9277 --- /dev/null +++ b/regex/tests/test_crates_regex.rs @@ -0,0 +1,57 @@ +extern crate regex; +extern crate quickcheck; + +/* + * This test is a minimal version of <rofl_0> and <subdiff_0> + * + * Once this bug gets fixed, uncomment rofl_0 and subdiff_0 + * (in `tests/crates_regex.rs`). +#[test] +fn word_boundary_backtracking_default_mismatch() { + use regex::internal::ExecBuilder; + + let backtrack_re = ExecBuilder::new(r"\b") + .bounded_backtracking() + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let default_re = ExecBuilder::new(r"\b") + .build() + .map(|exec| exec.into_regex()) + .map_err(|err| format!("{}", err)) + .unwrap(); + + let input = "䅅\\u{a0}"; + + let fi1 = backtrack_re.find_iter(input); + let fi2 = default_re.find_iter(input); + for (m1, m2) in fi1.zip(fi2) { + assert_eq!(m1, m2); + } +} +*/ + +mod consistent; + +mod crates_regex { + + macro_rules! consistent { + ($test_name:ident, $regex_src:expr) => { + #[test] + fn $test_name() { + use super::consistent::backends_are_consistent; + + if option_env!("RUST_REGEX_RANDOM_TEST").is_some() { + match backends_are_consistent($regex_src) { + Ok(_) => {}, + Err(err) => panic!("{}", err), + } + } + } + } + } + + include!("crates_regex.rs"); +} diff --git a/regex/tests/test_default.rs b/regex/tests/test_default.rs new file mode 100644 index 000000000..cff213b63 --- /dev/null +++ b/regex/tests/test_default.rs @@ -0,0 +1,121 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(feature = "pattern", feature(pattern))] + +extern crate rand; +extern crate regex; + +// Due to macro scoping rules, this definition only applies for the modules +// defined below. Effectively, it allows us to use the same tests for both +// native and dynamic regexes. +// +// This is also used to test the various matching engines. This one exercises +// the normal code path which automatically chooses the engine based on the +// regex and the input. Other dynamic tests explicitly set the engine to use. +macro_rules! regex_new { + ($re:expr) => {{ + use regex::Regex; + Regex::new($re) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::RegexSet; + RegexSet::new($re) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_str.rs"); +include!("macros.rs"); + +mod api; +mod api_str; +mod crazy; +mod flags; +mod fowler; +mod misc; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod searcher; +mod set; +mod shortest_match; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_unicode; + +#[test] +fn disallow_non_utf8() { + assert!(regex::Regex::new(r"(?-u)\xFF").is_err()); + assert!(regex::Regex::new(r"(?-u).").is_err()); + assert!(regex::Regex::new(r"(?-u)[\xFF]").is_err()); + assert!(regex::Regex::new(r"(?-u)☃").is_err()); +} + +#[test] +fn disallow_octal() { + assert!(regex::Regex::new(r"\0").is_err()); +} + +#[test] +fn allow_octal() { + assert!(regex::RegexBuilder::new(r"\0").octal(true).build().is_ok()); +} + +#[test] +fn oibits() { + use std::panic::UnwindSafe; + use regex::{Regex, RegexBuilder}; + use regex::bytes; + + fn assert_send<T: Send>() {} + fn assert_sync<T: Sync>() {} + fn assert_unwind_safe<T: UnwindSafe>() {} + + assert_send::<Regex>(); + assert_sync::<Regex>(); + assert_unwind_safe::<Regex>(); + assert_send::<RegexBuilder>(); + assert_sync::<RegexBuilder>(); + assert_unwind_safe::<RegexBuilder>(); + + assert_send::<bytes::Regex>(); + assert_sync::<bytes::Regex>(); + assert_unwind_safe::<bytes::Regex>(); + assert_send::<bytes::RegexBuilder>(); + assert_sync::<bytes::RegexBuilder>(); + assert_unwind_safe::<bytes::RegexBuilder>(); +} + +// See: https://github.com/rust-lang/regex/issues/568 +#[test] +fn oibits_regression() { + use std::panic; + use regex::Regex; + + let _ = panic::catch_unwind(|| Regex::new("a").unwrap()); +} diff --git a/regex/tests/test_default_bytes.rs b/regex/tests/test_default_bytes.rs new file mode 100644 index 000000000..3ac3ce457 --- /dev/null +++ b/regex/tests/test_default_bytes.rs @@ -0,0 +1,73 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::bytes::Regex; + Regex::new($re) + }} +} + +macro_rules! regex_set_new { + ($res:expr) => {{ + use regex::bytes::RegexSet; + RegexSet::new($res) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_bytes.rs"); +include!("macros.rs"); + +// A silly wrapper to make it possible to write and match raw bytes. +struct R<'a>(&'a [u8]); +impl<'a> R<'a> { fn as_bytes(&self) -> &'a [u8] { self.0 } } + +// See: https://github.com/rust-lang/regex/issues/321 +// +// These tests are here because they do not have the same behavior in every +// regex engine. +mat!(invalid_utf8_nfa1, r".", R(b"\xD4\xC2\x65\x2B\x0E\xFE"), Some((2, 3))); +mat!(invalid_utf8_nfa2, r"${2}ä", R(b"\xD4\xC2\x65\x2B\x0E\xFE"), None); +mat!(invalid_utf8_nfa3, r".", R(b"\x0A\xDB\x82\x6E\x33\x01\xDD\x33\xCD"), + Some((1, 3))); +mat!(invalid_utf8_nfa4, r"${2}ä", R(b"\x0A\xDB\x82\x6E\x33\x01\xDD\x33\xCD"), + None); + +mod api; +mod bytes; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod set; +mod shortest_match; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_ascii; diff --git a/regex/tests/test_nfa.rs b/regex/tests/test_nfa.rs new file mode 100644 index 000000000..8a831c47d --- /dev/null +++ b/regex/tests/test_nfa.rs @@ -0,0 +1,60 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(feature = "pattern", feature(pattern))] + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re).nfa().build().map(|e| e.into_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re).nfa().build().map(|e| e.into_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_str.rs"); +include!("macros.rs"); + +mod api; +mod api_str; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod searcher; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_unicode; diff --git a/regex/tests/test_nfa_bytes.rs b/regex/tests/test_nfa_bytes.rs new file mode 100644 index 000000000..f376cefe1 --- /dev/null +++ b/regex/tests/test_nfa_bytes.rs @@ -0,0 +1,65 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re) + .nfa() + .only_utf8(false) + .build() + .map(|e| e.into_byte_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re) + .nfa() + .only_utf8(false) + .build() + .map(|e| e.into_byte_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_bytes.rs"); +include!("macros.rs"); + +mod api; +mod bytes; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_ascii; diff --git a/regex/tests/test_nfa_utf8bytes.rs b/regex/tests/test_nfa_utf8bytes.rs new file mode 100644 index 000000000..5d13685aa --- /dev/null +++ b/regex/tests/test_nfa_utf8bytes.rs @@ -0,0 +1,61 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(feature = "pattern", feature(pattern))] + +extern crate rand; +extern crate regex; + +macro_rules! regex_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new($re).nfa().bytes(true).build().map(|e| e.into_regex()) + }} +} + +macro_rules! regex { + ($re:expr) => { + regex_new!($re).unwrap() + } +} + +macro_rules! regex_set_new { + ($re:expr) => {{ + use regex::internal::ExecBuilder; + ExecBuilder::new_many($re) + .nfa().bytes(true).build().map(|e| e.into_regex_set()) + }} +} + +macro_rules! regex_set { + ($res:expr) => { + regex_set_new!($res).unwrap() + } +} + +// Must come before other module definitions. +include!("macros_str.rs"); +include!("macros.rs"); + +mod api; +mod api_str; +mod crazy; +mod flags; +mod fowler; +mod multiline; +mod noparse; +mod regression; +mod replace; +mod searcher; +mod set; +mod suffix_reverse; +mod unicode; +mod word_boundary; +mod word_boundary_unicode; diff --git a/regex/tests/unicode.rs b/regex/tests/unicode.rs new file mode 100644 index 000000000..56cfccbe6 --- /dev/null +++ b/regex/tests/unicode.rs @@ -0,0 +1,147 @@ +mat!(uni_literal, r"☃", "☃", Some((0, 3))); +mat!(uni_literal_plus, r"☃+", "☃", Some((0, 3))); +mat!(uni_literal_casei_plus, r"(?i)☃+", "☃", Some((0, 3))); +mat!(uni_class_plus, r"[☃Ⅰ]+", "☃", Some((0, 3))); +mat!(uni_one, r"\pN", "Ⅰ", Some((0, 3))); +mat!(uni_mixed, r"\pN+", "Ⅰ1Ⅱ2", Some((0, 8))); +mat!(uni_not, r"\PN+", "abⅠ", Some((0, 2))); +mat!(uni_not_class, r"[\PN]+", "abⅠ", Some((0, 2))); +mat!(uni_not_class_neg, r"[^\PN]+", "abⅠ", Some((2, 5))); +mat!(uni_case, r"(?i)Δ", "δ", Some((0, 2))); +mat!(uni_case_upper, r"\p{Lu}+", "ΛΘΓΔα", Some((0, 8))); +mat!(uni_case_upper_nocase_flag, r"(?i)\p{Lu}+", "ΛΘΓΔα", Some((0, 10))); +mat!(uni_case_upper_nocase, r"\p{L}+", "ΛΘΓΔα", Some((0, 10))); +mat!(uni_case_lower, r"\p{Ll}+", "ΛΘΓΔα", Some((8, 10))); + +// Test the Unicode friendliness of Perl character classes. +mat!(uni_perl_w, r"\w+", "dδd", Some((0, 4))); +mat!(uni_perl_w_not, r"\w+", "⥡", None); +mat!(uni_perl_w_neg, r"\W+", "⥡", Some((0, 3))); +mat!(uni_perl_d, r"\d+", "1२३9", Some((0, 8))); +mat!(uni_perl_d_not, r"\d+", "Ⅱ", None); +mat!(uni_perl_d_neg, r"\D+", "Ⅱ", Some((0, 3))); +mat!(uni_perl_s, r"\s+", " ", Some((0, 3))); +mat!(uni_perl_s_not, r"\s+", "☃", None); +mat!(uni_perl_s_neg, r"\S+", "☃", Some((0, 3))); + +// And do the same for word boundaries. +mat!(uni_boundary_none, r"\d\b", "6δ", None); +mat!(uni_boundary_ogham, r"\d\b", "6 ", Some((0, 1))); +mat!(uni_not_boundary_none, r"\d\B", "6δ", Some((0, 1))); +mat!(uni_not_boundary_ogham, r"\d\B", "6 ", None); + +// Test general categories. +// +// We should test more, but there's a lot. Write a script to generate more of +// these tests. +mat!(uni_class_gencat_cased_letter, + r"\p{Cased_Letter}", "A", Some((0, 3))); +mat!(uni_class_gencat_close_punctuation, + r"\p{Close_Punctuation}", "❯", Some((0, 3))); +mat!(uni_class_gencat_connector_punctuation, + r"\p{Connector_Punctuation}", "⁀", Some((0, 3))); +mat!(uni_class_gencat_control, + r"\p{Control}", "\u{9f}", Some((0, 2))); +mat!(uni_class_gencat_currency_symbol, + r"\p{Currency_Symbol}", "£", Some((0, 3))); +mat!(uni_class_gencat_dash_punctuation, + r"\p{Dash_Punctuation}", "〰", Some((0, 3))); +mat!(uni_class_gencat_decimal_numer, + r"\p{Decimal_Number}", "𑓙", Some((0, 4))); +mat!(uni_class_gencat_enclosing_mark, + r"\p{Enclosing_Mark}", "\u{A672}", Some((0, 3))); +mat!(uni_class_gencat_final_punctuation, + r"\p{Final_Punctuation}", "⸡", Some((0, 3))); +mat!(uni_class_gencat_format, + r"\p{Format}", "\u{E007F}", Some((0, 4))); +mat!(uni_class_gencat_initial_punctuation, + r"\p{Initial_Punctuation}", "⸜", Some((0, 3))); +mat!(uni_class_gencat_letter, + r"\p{Letter}", "Έ", Some((0, 2))); +mat!(uni_class_gencat_letter_number, + r"\p{Letter_Number}", "ↂ", Some((0, 3))); +mat!(uni_class_gencat_line_separator, + r"\p{Line_Separator}", "\u{2028}", Some((0, 3))); +mat!(uni_class_gencat_lowercase_letter, + r"\p{Lowercase_Letter}", "ϛ", Some((0, 2))); +mat!(uni_class_gencat_mark, + r"\p{Mark}", "\u{E01EF}", Some((0, 4))); +mat!(uni_class_gencat_math, + r"\p{Math}", "⋿", Some((0, 3))); +mat!(uni_class_gencat_modifier_letter, + r"\p{Modifier_Letter}", "𖭃", Some((0, 4))); +mat!(uni_class_gencat_modifier_symbol, + r"\p{Modifier_Symbol}", "🏿", Some((0, 4))); +mat!(uni_class_gencat_nonspacing_mark, + r"\p{Nonspacing_Mark}", "\u{1E94A}", Some((0, 4))); +mat!(uni_class_gencat_number, + r"\p{Number}", "⓿", Some((0, 3))); +mat!(uni_class_gencat_open_punctuation, + r"\p{Open_Punctuation}", "⦅", Some((0, 3))); +mat!(uni_class_gencat_other, + r"\p{Other}", "\u{bc9}", Some((0, 3))); +mat!(uni_class_gencat_other_letter, + r"\p{Other_Letter}", "ꓷ", Some((0, 3))); +mat!(uni_class_gencat_other_number, + r"\p{Other_Number}", "㉏", Some((0, 3))); +mat!(uni_class_gencat_other_punctuation, + r"\p{Other_Punctuation}", "𞥞", Some((0, 4))); +mat!(uni_class_gencat_other_symbol, + r"\p{Other_Symbol}", "⅌", Some((0, 3))); +mat!(uni_class_gencat_paragraph_separator, + r"\p{Paragraph_Separator}", "\u{2029}", Some((0, 3))); +mat!(uni_class_gencat_private_use, + r"\p{Private_Use}", "\u{10FFFD}", Some((0, 4))); +mat!(uni_class_gencat_punctuation, + r"\p{Punctuation}", "𑁍", Some((0, 4))); +mat!(uni_class_gencat_separator, + r"\p{Separator}", "\u{3000}", Some((0, 3))); +mat!(uni_class_gencat_space_separator, + r"\p{Space_Separator}", "\u{205F}", Some((0, 3))); +mat!(uni_class_gencat_spacing_mark, + r"\p{Spacing_Mark}", "\u{16F7E}", Some((0, 4))); +mat!(uni_class_gencat_symbol, + r"\p{Symbol}", "⯈", Some((0, 3))); +mat!(uni_class_gencat_titlecase_letter, + r"\p{Titlecase_Letter}", "ῼ", Some((0, 3))); +mat!(uni_class_gencat_unassigned, + r"\p{Unassigned}", "\u{10FFFF}", Some((0, 4))); +mat!(uni_class_gencat_uppercase_letter, + r"\p{Uppercase_Letter}", "Ꝋ", Some((0, 3))); + +// Test a smattering of properties. +mat!(uni_class_prop_emoji1, r"\p{Emoji}", "\u{23E9}", Some((0, 3))); +mat!(uni_class_prop_emoji2, r"\p{emoji}", "\u{1F21A}", Some((0, 4))); +mat!(uni_class_prop_picto1, + r"\p{extendedpictographic}", "\u{1FA6E}", Some((0, 4))); +mat!(uni_class_prop_picto2, + r"\p{extendedpictographic}", "\u{1FFFD}", Some((0, 4))); + +// grapheme_cluster_break +mat!(uni_class_gcb_prepend, + r"\p{grapheme_cluster_break=prepend}", "\u{11D46}", Some((0, 4))); +mat!(uni_class_gcb_ri1, + r"\p{gcb=regional_indicator}", "\u{1F1E6}", Some((0, 4))); +mat!(uni_class_gcb_ri2, + r"\p{gcb=ri}", "\u{1F1E7}", Some((0, 4))); +mat!(uni_class_gcb_ri3, + r"\p{gcb=regionalindicator}", "\u{1F1FF}", Some((0, 4))); +mat!(uni_class_gcb_lvt, + r"\p{gcb=lvt}", "\u{C989}", Some((0, 3))); +mat!(uni_class_gcb_zwj, + r"\p{gcb=zwj}", "\u{200D}", Some((0, 3))); + +// word_break +mat!(uni_class_wb1, + r"\p{word_break=Hebrew_Letter}", "\u{FB46}", Some((0, 3))); +mat!(uni_class_wb2, r"\p{wb=hebrewletter}", "\u{FB46}", Some((0, 3))); +mat!(uni_class_wb3, r"\p{wb=ExtendNumLet}", "\u{FF3F}", Some((0, 3))); +mat!(uni_class_wb4, r"\p{wb=WSegSpace}", "\u{3000}", Some((0, 3))); +mat!(uni_class_wb5, r"\p{wb=numeric}", "\u{1E950}", Some((0, 4))); + +// sentence_break +mat!(uni_class_sb1, r"\p{sentence_break=Lower}", "\u{0469}", Some((0, 2))); +mat!(uni_class_sb2, r"\p{sb=lower}", "\u{0469}", Some((0, 2))); +mat!(uni_class_sb3, r"\p{sb=Close}", "\u{FF60}", Some((0, 3))); +mat!(uni_class_sb4, r"\p{sb=Close}", "\u{1F677}", Some((0, 4))); +mat!(uni_class_sb5, r"\p{sb=SContinue}", "\u{FF64}", Some((0, 3))); diff --git a/regex/tests/word_boundary.rs b/regex/tests/word_boundary.rs new file mode 100644 index 000000000..7fe97a297 --- /dev/null +++ b/regex/tests/word_boundary.rs @@ -0,0 +1,89 @@ +// Many of these are cribbed from RE2's test suite. + +matiter!(wb1, r"\b", ""); +matiter!(wb2, r"\b", "a", (0, 0), (1, 1)); +matiter!(wb3, r"\b", "ab", (0, 0), (2, 2)); +matiter!(wb4, r"^\b", "ab", (0, 0)); +matiter!(wb5, r"\b$", "ab", (2, 2)); +matiter!(wb6, r"^\b$", "ab"); +matiter!(wb7, r"\bbar\b", "nobar bar foo bar", (6, 9), (14, 17)); +matiter!(wb8, r"a\b", "faoa x", (3, 4)); +matiter!(wb9, r"\bbar", "bar x", (0, 3)); +matiter!(wb10, r"\bbar", "foo\nbar x", (4, 7)); +matiter!(wb11, r"bar\b", "foobar", (3, 6)); +matiter!(wb12, r"bar\b", "foobar\nxxx", (3, 6)); +matiter!(wb13, r"(foo|bar|[A-Z])\b", "foo", (0, 3)); +matiter!(wb14, r"(foo|bar|[A-Z])\b", "foo\n", (0, 3)); +matiter!(wb15, r"\b(foo|bar|[A-Z])", "foo", (0, 3)); +matiter!(wb16, r"\b(foo|bar|[A-Z])\b", "X", (0, 1)); +matiter!(wb17, r"\b(foo|bar|[A-Z])\b", "XY"); +matiter!(wb18, r"\b(foo|bar|[A-Z])\b", "bar", (0, 3)); +matiter!(wb19, r"\b(foo|bar|[A-Z])\b", "foo", (0, 3)); +matiter!(wb20, r"\b(foo|bar|[A-Z])\b", "foo\n", (0, 3)); +matiter!(wb21, r"\b(foo|bar|[A-Z])\b", "ffoo bbar N x", (10, 11)); +matiter!(wb22, r"\b(fo|foo)\b", "fo", (0, 2)); +matiter!(wb23, r"\b(fo|foo)\b", "foo", (0, 3)); +matiter!(wb24, r"\b\b", ""); +matiter!(wb25, r"\b\b", "a", (0, 0), (1, 1)); +matiter!(wb26, r"\b$", ""); +matiter!(wb27, r"\b$", "x", (1, 1)); +matiter!(wb28, r"\b$", "y x", (3, 3)); +matiter!(wb29, r"\b.$", "x", (0, 1)); +matiter!(wb30, r"^\b(fo|foo)\b", "fo", (0, 2)); +matiter!(wb31, r"^\b(fo|foo)\b", "foo", (0, 3)); +matiter!(wb32, r"^\b$", ""); +matiter!(wb33, r"^\b$", "x"); +matiter!(wb34, r"^\b.$", "x", (0, 1)); +matiter!(wb35, r"^\b.\b$", "x", (0, 1)); +matiter!(wb36, r"^^^^^\b$$$$$", ""); +matiter!(wb37, r"^^^^^\b.$$$$$", "x", (0, 1)); +matiter!(wb38, r"^^^^^\b$$$$$", "x"); +matiter!(wb39, r"^^^^^\b\b\b.\b\b\b$$$$$", "x", (0, 1)); +matiter!(wb40, r"\b.+\b", "$$abc$$", (2, 5)); +matiter!(wb41, r"\b", "a b c", (0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)); + +matiter!(nb1, r"\Bfoo\B", "n foo xfoox that", (7, 10)); +matiter!(nb2, r"a\B", "faoa x", (1, 2)); +matiter!(nb3, r"\Bbar", "bar x"); +matiter!(nb4, r"\Bbar", "foo\nbar x"); +matiter!(nb5, r"bar\B", "foobar"); +matiter!(nb6, r"bar\B", "foobar\nxxx"); +matiter!(nb7, r"(foo|bar|[A-Z])\B", "foox", (0, 3)); +matiter!(nb8, r"(foo|bar|[A-Z])\B", "foo\n"); +matiter!(nb9, r"\B", "", (0, 0)); +matiter!(nb10, r"\B", "x"); +matiter!(nb11, r"\B(foo|bar|[A-Z])", "foo"); +matiter!(nb12, r"\B(foo|bar|[A-Z])\B", "xXy", (1, 2)); +matiter!(nb13, r"\B(foo|bar|[A-Z])\B", "XY"); +matiter!(nb14, r"\B(foo|bar|[A-Z])\B", "XYZ", (1, 2)); +matiter!(nb15, r"\B(foo|bar|[A-Z])\B", "abara", (1, 4)); +matiter!(nb16, r"\B(foo|bar|[A-Z])\B", "xfoo_", (1, 4)); +matiter!(nb17, r"\B(foo|bar|[A-Z])\B", "xfoo\n"); +matiter!(nb18, r"\B(foo|bar|[A-Z])\B", "foo bar vNX", (9, 10)); +matiter!(nb19, r"\B(fo|foo)\B", "xfoo", (1, 3)); +matiter!(nb20, r"\B(foo|fo)\B", "xfooo", (1, 4)); +matiter!(nb21, r"\B\B", "", (0, 0)); +matiter!(nb22, r"\B\B", "x"); +matiter!(nb23, r"\B$", "", (0, 0)); +matiter!(nb24, r"\B$", "x"); +matiter!(nb25, r"\B$", "y x"); +matiter!(nb26, r"\B.$", "x"); +matiter!(nb27, r"^\B(fo|foo)\B", "fo"); +matiter!(nb28, r"^\B(fo|foo)\B", "foo"); +matiter!(nb29, r"^\B", "", (0, 0)); +matiter!(nb30, r"^\B", "x"); +matiter!(nb31, r"^\B\B", "", (0, 0)); +matiter!(nb32, r"^\B\B", "x"); +matiter!(nb33, r"^\B$", "", (0, 0)); +matiter!(nb34, r"^\B$", "x"); +matiter!(nb35, r"^\B.$", "x"); +matiter!(nb36, r"^\B.\B$", "x"); +matiter!(nb37, r"^^^^^\B$$$$$", "", (0, 0)); +matiter!(nb38, r"^^^^^\B.$$$$$", "x"); +matiter!(nb39, r"^^^^^\B$$$$$", "x"); + +// These work for both Unicode and ASCII because all matches are reported as +// byte offsets, and « and » do not correspond to word boundaries at either +// the character or byte level. +matiter!(unicode1, r"\bx\b", "«x", (2, 3)); +matiter!(unicode2, r"\bx\b", "x»", (0, 1)); diff --git a/regex/tests/word_boundary_ascii.rs b/regex/tests/word_boundary_ascii.rs new file mode 100644 index 000000000..5a3cf1166 --- /dev/null +++ b/regex/tests/word_boundary_ascii.rs @@ -0,0 +1,9 @@ +// ASCII word boundaries are completely oblivious to Unicode characters. +// For Unicode word boundaries, the tests are precisely inverted. +matiter!(ascii1, r"(?-u:\b)x(?-u:\b)", "áxβ", (2, 3)); +matiter!(ascii2, r"(?-u:\B)x(?-u:\B)", "áxβ"); +matiter!(ascii3, r"(?-u:\B)", "0\u{7EF5E}", (2, 2), (3, 3), (4, 4), (5, 5)); + +// We still get Unicode word boundaries by default in byte regexes. +matiter!(unicode1, r"\bx\b", "áxβ"); +matiter!(unicode2, r"\Bx\B", "áxβ", (2, 3)); diff --git a/regex/tests/word_boundary_unicode.rs b/regex/tests/word_boundary_unicode.rs new file mode 100644 index 000000000..c41355ffc --- /dev/null +++ b/regex/tests/word_boundary_unicode.rs @@ -0,0 +1,6 @@ +// Unicode word boundaries know about Unicode characters. +// For ASCII word boundaries, the tests are precisely inverted. +matiter!(unicode1, r"\bx\b", "áxβ"); +matiter!(unicode2, r"\Bx\B", "áxβ", (2, 3)); + +matiter!(ascii1, r"(?-u:\b)x(?-u:\b)", "áxβ", (2, 3)); diff --git a/remove_dir_all/.cargo-checksum.json b/remove_dir_all/.cargo-checksum.json new file mode 100644 index 000000000..b1b065601 --- /dev/null +++ b/remove_dir_all/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"} \ No newline at end of file diff --git a/remove_dir_all/Cargo.toml b/remove_dir_all/Cargo.toml new file mode 100644 index 000000000..88d3cace7 --- /dev/null +++ b/remove_dir_all/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "remove_dir_all" +version = "0.5.1" +authors = ["Aaronepower <theaaronepower@gmail.com>"] +include = ["Cargo.toml", "LICENCE-APACHE", "LICENCE-MIT", "src/**/*"] +description = "A safe, reliable implementation of remove_dir_all for Windows" +readme = "README.md" +keywords = ["utility", "filesystem", "remove_dir", "windows"] +categories = ["filesystem"] +license = "MIT/Apache-2.0" +repository = "https://github.com/Aaronepower/remove_dir_all.git" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["std", "errhandlingapi", "winerror", "fileapi", "winbase"] diff --git a/remove_dir_all/LICENCE-APACHE b/remove_dir_all/LICENCE-APACHE new file mode 100644 index 000000000..01de39235 --- /dev/null +++ b/remove_dir_all/LICENCE-APACHE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +Copyright 2017 Aaron Power + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/remove_dir_all/LICENCE-MIT b/remove_dir_all/LICENCE-MIT new file mode 100644 index 000000000..627895f4e --- /dev/null +++ b/remove_dir_all/LICENCE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2017 Aaron Power + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/remove_dir_all/src/fs.rs b/remove_dir_all/src/fs.rs new file mode 100644 index 000000000..730582b8a --- /dev/null +++ b/remove_dir_all/src/fs.rs @@ -0,0 +1,265 @@ +use std::ffi::OsString; +use std::fs::{self, File, OpenOptions}; +use std::{io, ptr}; +use std::os::windows::prelude::*; +use std::path::{Path, PathBuf}; + +use winapi::shared::minwindef::*; +use winapi::shared::winerror::*; +use winapi::um::errhandlingapi::*; +use winapi::um::fileapi::*; +use winapi::um::minwinbase::*; +use winapi::um::winbase::*; +use winapi::um::winnt::*; + +pub const VOLUME_NAME_DOS: DWORD = 0x0; + +struct RmdirContext<'a> { + base_dir: &'a Path, + readonly: bool, + counter: u64, +} + +/// Reliably removes directory and all of it's children. +/// ```rust +/// extern crate remove_dir_all; +/// +/// use remove_dir_all::*; +/// +/// fn main() { +/// remove_dir_all("./temp/").unwrap(); +/// } +/// ``` +pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { + // On Windows it is not enough to just recursively remove the contents of a + // directory and then the directory itself. Deleting does not happen + // instantaneously, but is scheduled. + // To work around this, we move the file or directory to some `base_dir` + // right before deletion to avoid races. + // + // As `base_dir` we choose the parent dir of the directory we want to + // remove. We very probably have permission to create files here, as we + // already need write permission in this dir to delete the directory. And it + // should be on the same volume. + // + // To handle files with names like `CON` and `morse .. .`, and when a + // directory structure is so deep it needs long path names the path is first + // converted to a `//?/`-path with `get_path()`. + // + // To make sure we don't leave a moved file laying around if the process + // crashes before we can delete the file, we do all operations on an file + // handle. By opening a file with `FILE_FLAG_DELETE_ON_CLOSE` Windows will + // always delete the file when the handle closes. + // + // All files are renamed to be in the `base_dir`, and have their name + // changed to "rm-<counter>". After every rename the counter is increased. + // Rename should not overwrite possibly existing files in the base dir. So + // if it fails with `AlreadyExists`, we just increase the counter and try + // again. + // + // For read-only files and directories we first have to remove the read-only + // attribute before we can move or delete them. This also removes the + // attribute from possible hardlinks to the file, so just before closing we + // restore the read-only attribute. + // + // If 'path' points to a directory symlink or junction we should not + // recursively remove the target of the link, but only the link itself. + // + // Moving and deleting is guaranteed to succeed if we are able to open the + // file with `DELETE` permission. If others have the file open we only have + // `DELETE` permission if they have specified `FILE_SHARE_DELETE`. We can + // also delete the file now, but it will not disappear until all others have + // closed the file. But no-one can open the file after we have flagged it + // for deletion. + + // Open the path once to get the canonical path, file type and attributes. + let (path, metadata) = { + let path = path.as_ref(); + let mut opts = OpenOptions::new(); + opts.access_mode(FILE_READ_ATTRIBUTES); + opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT); + let file = opts.open(path)?; + (get_path(&file)?, path.metadata()?) + }; + + let mut ctx = RmdirContext { + base_dir: match path.parent() { + Some(dir) => dir, + None => return Err(io::Error::new(io::ErrorKind::PermissionDenied, + "Can't delete root directory")) + }, + readonly: metadata.permissions().readonly(), + counter: 0, + }; + + let filetype = metadata.file_type(); + if filetype.is_dir() { + if !filetype.is_symlink() { + remove_dir_all_recursive(path.as_ref(), &mut ctx) + } else { + remove_item(path.as_ref(), &mut ctx) + } + } else { + Err(io::Error::new(io::ErrorKind::PermissionDenied, "Not a directory")) + } +} + +fn remove_item(path: &Path, ctx: &mut RmdirContext) -> io::Result<()> { + if ctx.readonly { + // remove read-only permision + let mut permissions = path.metadata()?.permissions(); + permissions.set_readonly(false); + + fs::set_permissions(path, permissions)?; + } + + let mut opts = OpenOptions::new(); + opts.access_mode(DELETE); + opts.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | // delete directory + FILE_FLAG_OPEN_REPARSE_POINT | // delete symlink + FILE_FLAG_DELETE_ON_CLOSE); + let file = opts.open(path)?; + move_item(&file, ctx)?; + + if ctx.readonly { + // restore read-only flag just in case there are other hard links + match fs::metadata(&path) { + Ok(metadata) => { + let mut perm = metadata.permissions(); + perm.set_readonly(true); + fs::set_permissions(&path, perm)?; + }, + Err(ref err) if err.kind() == io::ErrorKind::NotFound => {}, + err => return err.map(|_| ()), + } + } + + Ok(()) +} + +fn move_item(file: &File, ctx: &mut RmdirContext) -> io::Result<()> { + let mut tmpname = ctx.base_dir.join(format!{"rm-{}", ctx.counter}); + ctx.counter += 1; + + // Try to rename the file. If it already exists, just retry with an other + // filename. + while let Err(err) = rename(file, &tmpname, false) { + if err.kind() != io::ErrorKind::AlreadyExists { return Err(err) }; + tmpname = ctx.base_dir.join(format!("rm-{}", ctx.counter)); + ctx.counter += 1; + } + + Ok(()) +} + +fn rename(file: &File, new: &Path, replace: bool) -> io::Result<()> { + // &self must be opened with DELETE permission + use std::iter; + #[cfg(target_arch = "x86")] + const STRUCT_SIZE: usize = 12; + #[cfg(target_arch = "x86_64")] + const STRUCT_SIZE: usize = 20; + + // FIXME: check for internal NULs in 'new' + let mut data: Vec<u16> = iter::repeat(0u16).take(STRUCT_SIZE/2) + .chain(new.as_os_str().encode_wide()) + .collect(); + data.push(0); + let size = data.len() * 2; + + unsafe { + // Thanks to alignment guarantees on Windows this works + // (8 for 32-bit and 16 for 64-bit) + let info = data.as_mut_ptr() as *mut FILE_RENAME_INFO; + // The type of ReplaceIfExists is BOOL, but it actually expects a + // BOOLEAN. This means true is -1, not c::TRUE. + (*info).ReplaceIfExists = if replace { -1 } else { FALSE }; + (*info).RootDirectory = ptr::null_mut(); + (*info).FileNameLength = (size - STRUCT_SIZE) as DWORD; + let result = SetFileInformationByHandle(file.as_raw_handle(), + FileRenameInfo, + data.as_mut_ptr() as *mut _ as *mut _, + size as DWORD); + + if result == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } +} + +fn get_path(f: &File) -> io::Result<PathBuf> { + + fill_utf16_buf(|buf, sz| unsafe { + GetFinalPathNameByHandleW(f.as_raw_handle(), buf, sz, VOLUME_NAME_DOS) + }, |buf| { + PathBuf::from(OsString::from_wide(buf)) + }) +} + +fn remove_dir_all_recursive(path: &Path, ctx: &mut RmdirContext) + -> io::Result<()> { + let dir_readonly = ctx.readonly; + for child in try!(fs::read_dir(path)) { + let child = try!(child); + let child_type = try!(child.file_type()); + ctx.readonly = try!(child.metadata()).permissions().readonly(); + if child_type.is_dir() { + try!(remove_dir_all_recursive(&child.path(), ctx)); + } else { + try!(remove_item(&child.path().as_ref(), ctx)); + } + } + ctx.readonly = dir_readonly; + remove_item(path, ctx) +} + +fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T> + where F1: FnMut(*mut u16, DWORD) -> DWORD, + F2: FnOnce(&[u16]) -> T +{ + // Start off with a stack buf but then spill over to the heap if we end up + // needing more space. + let mut stack_buf = [0u16; 512]; + let mut heap_buf = Vec::new(); + unsafe { + let mut n = stack_buf.len(); + + loop { + let buf = if n <= stack_buf.len() { + &mut stack_buf[..] + } else { + let extra = n - heap_buf.len(); + heap_buf.reserve(extra); + heap_buf.set_len(n); + &mut heap_buf[..] + }; + + // This function is typically called on windows API functions which + // will return the correct length of the string, but these functions + // also return the `0` on error. In some cases, however, the + // returned "correct length" may actually be 0! + // + // To handle this case we call `SetLastError` to reset it to 0 and + // then check it again if we get the "0 error value". If the "last + // error" is still 0 then we interpret it as a 0 length buffer and + // not an actual error. + SetLastError(0); + let k = match f1(buf.as_mut_ptr(), n as DWORD) { + 0 if GetLastError() == 0 => 0, + 0 => return Err(io::Error::last_os_error()), + n => n, + } as usize; + if k == n && GetLastError() == ERROR_INSUFFICIENT_BUFFER { + n *= 2; + } else if k >= n { + n = k; + } else { + return Ok(f2(&buf[..k])) + } + } + } +} + diff --git a/remove_dir_all/src/lib.rs b/remove_dir_all/src/lib.rs new file mode 100644 index 000000000..367d44e16 --- /dev/null +++ b/remove_dir_all/src/lib.rs @@ -0,0 +1,12 @@ +#[cfg(windows)] +extern crate winapi; + +#[cfg(windows)] +mod fs; + +#[cfg(windows)] +pub use self::fs::remove_dir_all; + +#[cfg(not(windows))] +pub use std::fs::remove_dir_all; + diff --git a/rustc-demangle/.cargo-checksum.json b/rustc-demangle/.cargo-checksum.json new file mode 100644 index 000000000..0e17126e4 --- /dev/null +++ b/rustc-demangle/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"} \ No newline at end of file diff --git a/rustc-demangle/Cargo.toml b/rustc-demangle/Cargo.toml new file mode 100644 index 000000000..07935ed46 --- /dev/null +++ b/rustc-demangle/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc-demangle" +version = "0.1.15" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +description = "Rust compiler symbol demangling.\n" +homepage = "https://github.com/alexcrichton/rustc-demangle" +documentation = "https://docs.rs/rustc-demangle" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/rustc-demangle" +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[features] +rustc-dep-of-std = ["core", "compiler_builtins"] diff --git a/rustc-demangle/LICENSE-APACHE b/rustc-demangle/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/rustc-demangle/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rustc-demangle/LICENSE-MIT b/rustc-demangle/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/rustc-demangle/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rustc-demangle/README.md b/rustc-demangle/README.md new file mode 100644 index 000000000..4b480b86c --- /dev/null +++ b/rustc-demangle/README.md @@ -0,0 +1,24 @@ +# rustc-demangle + +Symbol demangling for Rust + +[![Build Status](https://travis-ci.org/alexcrichton/rustc-demangle.svg?branch=master)](https://travis-ci.org/alexcrichton/rustc-demangle) + +[Documentation](https://docs.rs/rustc-demangle) + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in rustc-demangle you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/rustc-demangle/src/legacy.rs b/rustc-demangle/src/legacy.rs new file mode 100644 index 000000000..1e1824c6c --- /dev/null +++ b/rustc-demangle/src/legacy.rs @@ -0,0 +1,370 @@ +use core::fmt; + +/// Representation of a demangled symbol name. +pub struct Demangle<'a> { + inner: &'a str, + /// The number of ::-separated elements in the original name. + elements: usize, +} + +/// De-mangles a Rust symbol into a more readable version +/// +/// All Rust symbols by default are mangled as they contain characters that +/// cannot be represented in all object files. The mangling mechanism is similar +/// to C++'s, but Rust has a few specifics to handle items like lifetimes in +/// symbols. +/// +/// This function will take a **mangled** symbol and return a value. When printed, +/// the de-mangled version will be written. If the symbol does not look like +/// a mangled symbol, the original value will be written instead. +/// +/// # Examples +/// +/// ``` +/// use rustc_demangle::demangle; +/// +/// assert_eq!(demangle("_ZN4testE").to_string(), "test"); +/// assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar"); +/// assert_eq!(demangle("foo").to_string(), "foo"); +/// ``` + +// All Rust symbols are in theory lists of "::"-separated identifiers. Some +// assemblers, however, can't handle these characters in symbol names. To get +// around this, we use C++-style mangling. The mangling method is: +// +// 1. Prefix the symbol with "_ZN" +// 2. For each element of the path, emit the length plus the element +// 3. End the path with "E" +// +// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". +// +// We're the ones printing our backtraces, so we can't rely on anything else to +// demangle our symbols. It's *much* nicer to look at demangled symbols, so +// this function is implemented to give us nice pretty output. +// +// Note that this demangler isn't quite as fancy as it could be. We have lots +// of other information in our symbols like hashes, version, type information, +// etc. Additionally, this doesn't handle glue symbols at all. +pub fn demangle(s: &str) -> Result<Demangle, ()> { + // First validate the symbol. If it doesn't look like anything we're + // expecting, we just print it literally. Note that we must handle non-Rust + // symbols because we could have any function in the backtrace. + let inner; + if s.len() > 4 && s.starts_with("_ZN") && s.ends_with('E') { + inner = &s[3..s.len() - 1]; + } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with('E') { + // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" + // form too. + inner = &s[2..s.len() - 1]; + } else if s.len() > 5 && s.starts_with("__ZN") && s.ends_with('E') { + // On OSX, symbols are prefixed with an extra _ + inner = &s[4..s.len() - 1]; + } else { + return Err(()); + } + + // only work with ascii text + if inner.bytes().any(|c| c & 0x80 != 0) { + return Err(()); + } + + let mut elements = 0; + let mut chars = inner.chars().peekable(); + loop { + let mut i = 0usize; + while let Some(&c) = chars.peek() { + if !c.is_digit(10) { + break + } + chars.next(); + let next = i.checked_mul(10) + .and_then(|i| i.checked_add(c as usize - '0' as usize)); + i = match next { + Some(i) => i, + None => { + return Err(()); + } + }; + } + + if i == 0 { + if !chars.next().is_none() { + return Err(()); + } + break; + } else if chars.by_ref().take(i).count() != i { + return Err(()); + } else { + elements += 1; + } + } + + Ok(Demangle { + inner: inner, + elements: elements, + }) +} + +// Rust hashes are hex digits with an `h` prepended. +fn is_rust_hash(s: &str) -> bool { + s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16)) +} + +impl<'a> fmt::Display for Demangle<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Alright, let's do this. + let mut inner = self.inner; + for element in 0..self.elements { + let mut rest = inner; + while rest.chars().next().unwrap().is_digit(10) { + rest = &rest[1..]; + } + let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap(); + inner = &rest[i..]; + rest = &rest[..i]; + // Skip printing the hash if alternate formatting + // was requested. + if f.alternate() && element+1 == self.elements && is_rust_hash(&rest) { + break; + } + if element != 0 { + try!(f.write_str("::")); + } + if rest.starts_with("_$") { + rest = &rest[1..]; + } + while !rest.is_empty() { + if rest.starts_with('.') { + if let Some('.') = rest[1..].chars().next() { + try!(f.write_str("::")); + rest = &rest[2..]; + } else { + try!(f.write_str(".")); + rest = &rest[1..]; + } + } else if rest.starts_with('$') { + macro_rules! demangle { + ($($pat:expr => $demangled:expr,)*) => ({ + $(if rest.starts_with($pat) { + try!(f.write_str($demangled)); + rest = &rest[$pat.len()..]; + } else)* + { + try!(f.write_str(rest)); + break; + } + + }) + } + + // see src/librustc/back/link.rs for these mappings + demangle! { + "$SP$" => "@", + "$BP$" => "*", + "$RF$" => "&", + "$LT$" => "<", + "$GT$" => ">", + "$LP$" => "(", + "$RP$" => ")", + "$C$" => ",", + + // in theory we can demangle any Unicode code point, but + // for simplicity we just catch the common ones. + "$u7e$" => "~", + "$u20$" => " ", + "$u27$" => "'", + "$u3d$" => "=", + "$u5b$" => "[", + "$u5d$" => "]", + "$u7b$" => "{", + "$u7d$" => "}", + "$u3b$" => ";", + "$u2b$" => "+", + "$u21$" => "!", + "$u22$" => "\"", + } + } else { + let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { + None => rest.len(), + Some((i, _)) => i, + }; + try!(f.write_str(&rest[..idx])); + rest = &rest[idx..]; + } + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::prelude::v1::*; + + macro_rules! t { + ($a:expr, $b:expr) => (assert!(ok($a, $b))) + } + + macro_rules! t_err { + ($a:expr) => (assert!(ok_err($a))) + } + + macro_rules! t_nohash { + ($a:expr, $b:expr) => ({ + assert_eq!(format!("{:#}", ::demangle($a)), $b); + }) + } + + fn ok(sym: &str, expected: &str) -> bool { + match ::try_demangle(sym) { + Ok(s) => { + if s.to_string() == expected { + true + } else { + println!("\n{}\n!=\n{}\n", s, expected); + false + } + } + Err(_) => { + println!("error demangling"); + false + } + } + } + + fn ok_err(sym: &str) -> bool { + match ::try_demangle(sym) { + Ok(_) => { + println!("succeeded in demangling"); + false + } + Err(_) => ::demangle(sym).to_string() == sym, + } + } + + #[test] + fn demangle() { + t_err!("test"); + t!("_ZN4testE", "test"); + t_err!("_ZN4test"); + t!("_ZN4test1a2bcE", "test::a::bc"); + } + + #[test] + fn demangle_dollars() { + t!("_ZN4$RP$E", ")"); + t!("_ZN8$RF$testE", "&test"); + t!("_ZN8$BP$test4foobE", "*test::foob"); + t!("_ZN9$u20$test4foobE", " test::foob"); + t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); + } + + #[test] + fn demangle_many_dollars() { + t!("_ZN13test$u20$test4foobE", "test test::foob"); + t!("_ZN12test$BP$test4foobE", "test*test::foob"); + } + + + #[test] + fn demangle_osx() { + t!("__ZN5alloc9allocator6Layout9for_value17h02a996811f781011E", "alloc::allocator::Layout::for_value::h02a996811f781011"); + t!("__ZN38_$LT$core..option..Option$LT$T$GT$$GT$6unwrap18_MSG_FILE_LINE_COL17haf7cb8d5824ee659E", "<core::option::Option<T>>::unwrap::_MSG_FILE_LINE_COL::haf7cb8d5824ee659"); + t!("__ZN4core5slice89_$LT$impl$u20$core..iter..traits..IntoIterator$u20$for$u20$$RF$$u27$a$u20$$u5b$T$u5d$$GT$9into_iter17h450e234d27262170E", "core::slice::<impl core::iter::traits::IntoIterator for &'a [T]>::into_iter::h450e234d27262170"); + } + + #[test] + fn demangle_windows() { + t!("ZN4testE", "test"); + t!("ZN13test$u20$test4foobE", "test test::foob"); + t!("ZN12test$RF$test4foobE", "test&test::foob"); + } + + #[test] + fn demangle_elements_beginning_with_underscore() { + t!("_ZN13_$LT$test$GT$E", "<test>"); + t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); + t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); + } + + #[test] + fn demangle_trait_impls() { + t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", + "<Test + 'static as foo::Bar<Test>>::bar"); + } + + #[test] + fn demangle_without_hash() { + let s = "_ZN3foo17h05af221e174051e9E"; + t!(s, "foo::h05af221e174051e9"); + t_nohash!(s, "foo"); + } + + #[test] + fn demangle_without_hash_edgecases() { + // One element, no hash. + t_nohash!("_ZN3fooE", "foo"); + // Two elements, no hash. + t_nohash!("_ZN3foo3barE", "foo::bar"); + // Longer-than-normal hash. + t_nohash!("_ZN3foo20h05af221e174051e9abcE", "foo"); + // Shorter-than-normal hash. + t_nohash!("_ZN3foo5h05afE", "foo"); + // Valid hash, but not at the end. + t_nohash!("_ZN17h05af221e174051e93fooE", "h05af221e174051e9::foo"); + // Not a valid hash, missing the 'h'. + t_nohash!("_ZN3foo16ffaf221e174051e9E", "foo::ffaf221e174051e9"); + // Not a valid hash, has a non-hex-digit. + t_nohash!("_ZN3foo17hg5af221e174051e9E", "foo::hg5af221e174051e9"); + } + + #[test] + fn demangle_thinlto() { + // One element, no hash. + t!("_ZN3fooE.llvm.9D1C9369", "foo"); + t!("_ZN3fooE.llvm.9D1C9369@@16", "foo"); + t_nohash!("_ZN9backtrace3foo17hbb467fcdaea5d79bE.llvm.A5310EB9", "backtrace::foo"); + } + + #[test] + fn demangle_llvm_ir_branch_labels() { + t!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut::haf9727c2edfbc47b.exit.i.i"); + t_nohash!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut.exit.i.i"); + } + + #[test] + fn demangle_ignores_suffix_that_doesnt_look_like_a_symbol() { + t_err!("_ZN3fooE.llvm moocow"); + } + + #[test] + fn dont_panic() { + ::demangle("_ZN2222222222222222222222EE").to_string(); + ::demangle("_ZN5*70527e27.ll34csaғE").to_string(); + ::demangle("_ZN5*70527a54.ll34_$b.1E").to_string(); + ::demangle("\ + _ZN5~saäb4e\n\ + 2734cOsbE\n\ + 5usage20h)3\0\0\0\0\0\0\07e2734cOsbE\ + ").to_string(); + } + + #[test] + fn invalid_no_chop() { + t_err!("_ZNfooE"); + } + + #[test] + fn handle_assoc_types() { + t!("_ZN151_$LT$alloc..boxed..Box$LT$alloc..boxed..FnBox$LT$A$C$$u20$Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$9call_once17h69e8f44b3723e1caE", "<alloc::boxed::Box<alloc::boxed::FnBox<A, Output=R> + 'a> as core::ops::function::FnOnce<A>>::call_once::h69e8f44b3723e1ca"); + } + + #[test] + fn handle_bang() { + t!( + "_ZN88_$LT$core..result..Result$LT$$u21$$C$$u20$E$GT$$u20$as$u20$std..process..Termination$GT$6report17hfc41d0da4a40b3e8E", + "<core::result::Result<!, E> as std::process::Termination>::report::hfc41d0da4a40b3e8" + ); + } +} diff --git a/rustc-demangle/src/lib.rs b/rustc-demangle/src/lib.rs new file mode 100644 index 000000000..41bc796a3 --- /dev/null +++ b/rustc-demangle/src/lib.rs @@ -0,0 +1,365 @@ +//! Demangle Rust compiler symbol names. +//! +//! This crate provides a `demangle` function which will return a `Demangle` +//! sentinel value that can be used to learn about the demangled version of a +//! symbol name. The demangled representation will be the same as the original +//! if it doesn't look like a mangled symbol name. +//! +//! `Demangle` can be formatted with the `Display` trait. The alternate +//! modifier (`#`) can be used to format the symbol name without the +//! trailing hash value. +//! +//! # Examples +//! +//! ``` +//! use rustc_demangle::demangle; +//! +//! assert_eq!(demangle("_ZN4testE").to_string(), "test"); +//! assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar"); +//! assert_eq!(demangle("foo").to_string(), "foo"); +//! // With hash +//! assert_eq!(format!("{}", demangle("_ZN3foo17h05af221e174051e9E")), "foo::h05af221e174051e9"); +//! // Without hash +//! assert_eq!(format!("{:#}", demangle("_ZN3foo17h05af221e174051e9E")), "foo"); +//! ``` + +#![no_std] +#![deny(missing_docs)] + +#[cfg(test)] +#[macro_use] +extern crate std; + +mod legacy; +mod v0; + +use core::fmt; + +/// Representation of a demangled symbol name. +pub struct Demangle<'a> { + style: Option<DemangleStyle<'a>>, + original: &'a str, + suffix: &'a str, +} + +enum DemangleStyle<'a> { + Legacy(legacy::Demangle<'a>), + V0(v0::Demangle<'a>), +} + +/// De-mangles a Rust symbol into a more readable version +/// +/// This function will take a **mangled** symbol and return a value. When printed, +/// the de-mangled version will be written. If the symbol does not look like +/// a mangled symbol, the original value will be written instead. +/// +/// # Examples +/// +/// ``` +/// use rustc_demangle::demangle; +/// +/// assert_eq!(demangle("_ZN4testE").to_string(), "test"); +/// assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar"); +/// assert_eq!(demangle("foo").to_string(), "foo"); +/// ``` +pub fn demangle(mut s: &str) -> Demangle { + // During ThinLTO LLVM may import and rename internal symbols, so strip out + // those endings first as they're one of the last manglings applied to symbol + // names. + let llvm = ".llvm."; + if let Some(i) = s.find(llvm) { + let candidate = &s[i + llvm.len()..]; + let all_hex = candidate.chars().all(|c| { + match c { + 'A' ... 'F' | '0' ... '9' | '@' => true, + _ => false, + } + }); + + if all_hex { + s = &s[..i]; + } + } + + // Output like LLVM IR adds extra period-delimited words. See if + // we are in that case and save the trailing words if so. + let mut suffix = ""; + if let Some(i) = s.rfind("E.") { + let (head, tail) = s.split_at(i + 1); // After the E, before the period + + if is_symbol_like(tail) { + s = head; + suffix = tail; + } + } + + let style = match legacy::demangle(s) { + Ok(d) => Some(DemangleStyle::Legacy(d)), + Err(()) => match v0::demangle(s) { + Ok(d) => Some(DemangleStyle::V0(d)), + Err(v0::Invalid) => None, + }, + }; + Demangle { + style: style, + original: s, + suffix: suffix, + } +} + +/// Error returned from the `try_demangle` function below when demangling fails. +#[derive(Debug, Clone)] +pub struct TryDemangleError { + _priv: (), +} + +/// The same as `demangle`, except return an `Err` if the string does not appear +/// to be a Rust symbol, rather than "demangling" the given string as a no-op. +/// +/// ``` +/// extern crate rustc_demangle; +/// +/// let not_a_rust_symbol = "la la la"; +/// +/// // The `try_demangle` function will reject strings which are not Rust symbols. +/// assert!(rustc_demangle::try_demangle(not_a_rust_symbol).is_err()); +/// +/// // While `demangle` will just pass the non-symbol through as a no-op. +/// assert_eq!(rustc_demangle::demangle(not_a_rust_symbol).as_str(), not_a_rust_symbol); +/// ``` +pub fn try_demangle(s: &str) -> Result<Demangle, TryDemangleError> { + let sym = demangle(s); + if sym.style.is_some() { + Ok(sym) + } else { + Err(TryDemangleError { _priv: () }) + } +} + +impl<'a> Demangle<'a> { + /// Returns the underlying string that's being demangled. + pub fn as_str(&self) -> &'a str { + self.original + } +} + +fn is_symbol_like(s: &str) -> bool { + s.chars().all(|c| { + // Once `char::is_ascii_punctuation` and `char::is_ascii_alphanumeric` + // have been stable for long enough, use those instead for clarity + is_ascii_alphanumeric(c) || is_ascii_punctuation(c) + }) +} + +// Copied from the documentation of `char::is_ascii_alphanumeric` +fn is_ascii_alphanumeric(c: char) -> bool { + match c { + '\u{0041}' ... '\u{005A}' | + '\u{0061}' ... '\u{007A}' | + '\u{0030}' ... '\u{0039}' => true, + _ => false, + } +} + +// Copied from the documentation of `char::is_ascii_punctuation` +fn is_ascii_punctuation(c: char) -> bool { + match c { + '\u{0021}' ... '\u{002F}' | + '\u{003A}' ... '\u{0040}' | + '\u{005B}' ... '\u{0060}' | + '\u{007B}' ... '\u{007E}' => true, + _ => false, + } +} + +impl<'a> fmt::Display for Demangle<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.style { + None => try!(f.write_str(self.original)), + Some(DemangleStyle::Legacy(ref d)) => { + try!(fmt::Display::fmt(d, f)) + } + Some(DemangleStyle::V0(ref d)) => { + try!(fmt::Display::fmt(d, f)) + } + } + f.write_str(self.suffix) + } +} + +impl<'a> fmt::Debug for Demangle<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +#[cfg(test)] +mod tests { + use std::prelude::v1::*; + + macro_rules! t { + ($a:expr, $b:expr) => (assert!(ok($a, $b))) + } + + macro_rules! t_err { + ($a:expr) => (assert!(ok_err($a))) + } + + macro_rules! t_nohash { + ($a:expr, $b:expr) => ({ + assert_eq!(format!("{:#}", super::demangle($a)), $b); + }) + } + + fn ok(sym: &str, expected: &str) -> bool { + match super::try_demangle(sym) { + Ok(s) => { + if s.to_string() == expected { + true + } else { + println!("\n{}\n!=\n{}\n", s, expected); + false + } + } + Err(_) => { + println!("error demangling"); + false + } + } + } + + fn ok_err(sym: &str) -> bool { + match super::try_demangle(sym) { + Ok(_) => { + println!("succeeded in demangling"); + false + } + Err(_) => super::demangle(sym).to_string() == sym, + } + } + + #[test] + fn demangle() { + t_err!("test"); + t!("_ZN4testE", "test"); + t_err!("_ZN4test"); + t!("_ZN4test1a2bcE", "test::a::bc"); + } + + #[test] + fn demangle_dollars() { + t!("_ZN4$RP$E", ")"); + t!("_ZN8$RF$testE", "&test"); + t!("_ZN8$BP$test4foobE", "*test::foob"); + t!("_ZN9$u20$test4foobE", " test::foob"); + t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); + } + + #[test] + fn demangle_many_dollars() { + t!("_ZN13test$u20$test4foobE", "test test::foob"); + t!("_ZN12test$BP$test4foobE", "test*test::foob"); + } + + + #[test] + fn demangle_osx() { + t!("__ZN5alloc9allocator6Layout9for_value17h02a996811f781011E", "alloc::allocator::Layout::for_value::h02a996811f781011"); + t!("__ZN38_$LT$core..option..Option$LT$T$GT$$GT$6unwrap18_MSG_FILE_LINE_COL17haf7cb8d5824ee659E", "<core::option::Option<T>>::unwrap::_MSG_FILE_LINE_COL::haf7cb8d5824ee659"); + t!("__ZN4core5slice89_$LT$impl$u20$core..iter..traits..IntoIterator$u20$for$u20$$RF$$u27$a$u20$$u5b$T$u5d$$GT$9into_iter17h450e234d27262170E", "core::slice::<impl core::iter::traits::IntoIterator for &'a [T]>::into_iter::h450e234d27262170"); + } + + #[test] + fn demangle_windows() { + t!("ZN4testE", "test"); + t!("ZN13test$u20$test4foobE", "test test::foob"); + t!("ZN12test$RF$test4foobE", "test&test::foob"); + } + + #[test] + fn demangle_elements_beginning_with_underscore() { + t!("_ZN13_$LT$test$GT$E", "<test>"); + t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); + t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); + } + + #[test] + fn demangle_trait_impls() { + t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", + "<Test + 'static as foo::Bar<Test>>::bar"); + } + + #[test] + fn demangle_without_hash() { + let s = "_ZN3foo17h05af221e174051e9E"; + t!(s, "foo::h05af221e174051e9"); + t_nohash!(s, "foo"); + } + + #[test] + fn demangle_without_hash_edgecases() { + // One element, no hash. + t_nohash!("_ZN3fooE", "foo"); + // Two elements, no hash. + t_nohash!("_ZN3foo3barE", "foo::bar"); + // Longer-than-normal hash. + t_nohash!("_ZN3foo20h05af221e174051e9abcE", "foo"); + // Shorter-than-normal hash. + t_nohash!("_ZN3foo5h05afE", "foo"); + // Valid hash, but not at the end. + t_nohash!("_ZN17h05af221e174051e93fooE", "h05af221e174051e9::foo"); + // Not a valid hash, missing the 'h'. + t_nohash!("_ZN3foo16ffaf221e174051e9E", "foo::ffaf221e174051e9"); + // Not a valid hash, has a non-hex-digit. + t_nohash!("_ZN3foo17hg5af221e174051e9E", "foo::hg5af221e174051e9"); + } + + #[test] + fn demangle_thinlto() { + // One element, no hash. + t!("_ZN3fooE.llvm.9D1C9369", "foo"); + t!("_ZN3fooE.llvm.9D1C9369@@16", "foo"); + t_nohash!("_ZN9backtrace3foo17hbb467fcdaea5d79bE.llvm.A5310EB9", "backtrace::foo"); + } + + #[test] + fn demangle_llvm_ir_branch_labels() { + t!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut::haf9727c2edfbc47b.exit.i.i"); + t_nohash!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut.exit.i.i"); + } + + #[test] + fn demangle_ignores_suffix_that_doesnt_look_like_a_symbol() { + t_err!("_ZN3fooE.llvm moocow"); + } + + #[test] + fn dont_panic() { + super::demangle("_ZN2222222222222222222222EE").to_string(); + super::demangle("_ZN5*70527e27.ll34csaғE").to_string(); + super::demangle("_ZN5*70527a54.ll34_$b.1E").to_string(); + super::demangle("\ + _ZN5~saäb4e\n\ + 2734cOsbE\n\ + 5usage20h)3\0\0\0\0\0\0\07e2734cOsbE\ + ").to_string(); + } + + #[test] + fn invalid_no_chop() { + t_err!("_ZNfooE"); + } + + #[test] + fn handle_assoc_types() { + t!("_ZN151_$LT$alloc..boxed..Box$LT$alloc..boxed..FnBox$LT$A$C$$u20$Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$9call_once17h69e8f44b3723e1caE", "<alloc::boxed::Box<alloc::boxed::FnBox<A, Output=R> + 'a> as core::ops::function::FnOnce<A>>::call_once::h69e8f44b3723e1ca"); + } + + #[test] + fn handle_bang() { + t!( + "_ZN88_$LT$core..result..Result$LT$$u21$$C$$u20$E$GT$$u20$as$u20$std..process..Termination$GT$6report17hfc41d0da4a40b3e8E", + "<core::result::Result<!, E> as std::process::Termination>::report::hfc41d0da4a40b3e8" + ); + } +} diff --git a/rustc-demangle/src/v0.rs b/rustc-demangle/src/v0.rs new file mode 100644 index 000000000..8fdbe83d0 --- /dev/null +++ b/rustc-demangle/src/v0.rs @@ -0,0 +1,1067 @@ +use core::char; +use core::fmt; +use core::fmt::Display; + +/// Representation of a demangled symbol name. +pub struct Demangle<'a> { + inner: &'a str, +} + +/// De-mangles a Rust symbol into a more readable version +/// +/// This function will take a **mangled** symbol and return a value. When printed, +/// the de-mangled version will be written. If the symbol does not look like +/// a mangled symbol, the original value will be written instead. +pub fn demangle(s: &str) -> Result<Demangle, Invalid> { + // First validate the symbol. If it doesn't look like anything we're + // expecting, we just print it literally. Note that we must handle non-Rust + // symbols because we could have any function in the backtrace. + let inner; + if s.len() > 2 && s.starts_with("_R") { + inner = &s[2..]; + } else if s.len() > 1 && s.starts_with("R") { + // On Windows, dbghelp strips leading underscores, so we accept "R..." + // form too. + inner = &s[1..]; + } else if s.len() > 3 && s.starts_with("__R") { + // On OSX, symbols are prefixed with an extra _ + inner = &s[3..]; + } else { + return Err(Invalid); + } + + // Paths always start with uppercase characters. + match inner.as_bytes()[0] { + b'A'...b'Z' => {} + _ => return Err(Invalid), + } + + // only work with ascii text + if inner.bytes().any(|c| c & 0x80 != 0) { + return Err(Invalid); + } + + // Verify that the symbol is indeed a valid path. + let mut parser = Parser { + sym: inner, + next: 0, + }; + try!(parser.skip_path()); + if parser.next < parser.sym.len() { + // Instantiating crate. + try!(parser.skip_path()); + } + if parser.next != parser.sym.len() { + return Err(Invalid); + } + + Ok(Demangle { + inner: inner, + }) +} + +impl<'s> Display for Demangle<'s> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut printer = Printer { + parser: Ok(Parser { + sym: self.inner, + next: 0, + }), + out: f, + bound_lifetime_depth: 0, + }; + printer.print_path(true) + } +} + +#[derive(PartialEq, Eq)] +pub struct Invalid; + +struct Ident<'s> { + /// ASCII part of the identifier. + ascii: &'s str, + /// Punycode insertion codes for Unicode codepoints, if any. + punycode: &'s str, +} + +const SMALL_PUNYCODE_LEN: usize = 128; + +impl<'s> Ident<'s> { + /// Attempt to decode punycode on the stack (allocation-free), + /// and pass the char slice to the closure, if successful. + /// This supports up to `SMALL_PUNYCODE_LEN` characters. + fn try_small_punycode_decode<F: FnOnce(&[char]) -> R, R>( + &self, + f: F, + ) -> Option<R> { + let mut out = ['\0'; SMALL_PUNYCODE_LEN]; + let mut out_len = 0; + let r = self.punycode_decode(|i, c| { + // Check there's space left for another character. + try!(out.get(out_len).ok_or(())); + + // Move the characters after the insert position. + let mut j = out_len; + out_len += 1; + + while j > i { + out[j] = out[j - 1]; + j -= 1; + } + + // Insert the new character. + out[i] = c; + + Ok(()) + }); + if r.is_ok() { + Some(f(&out[..out_len])) + } else { + None + } + } + + /// Decode punycode as insertion positions and characters + /// and pass them to the closure, which can return `Err(())` + /// to stop the decoding process. + fn punycode_decode<F: FnMut(usize, char) -> Result<(), ()>>( + &self, + mut insert: F, + ) -> Result<(), ()> { + let mut punycode_bytes = self.punycode.bytes().peekable(); + if punycode_bytes.peek().is_none() { + return Err(()); + } + + let mut len = 0; + + // Populate initial output from ASCII fragment. + for c in self.ascii.chars() { + try!(insert(len, c)); + len += 1; + } + + // Punycode parameters and initial state. + let base = 36; + let t_min = 1; + let t_max = 26; + let skew = 38; + let mut damp = 700; + let mut bias = 72; + let mut i: usize = 0; + let mut n: usize = 0x80; + + loop { + // Read one delta value. + let mut delta: usize = 0; + let mut w = 1; + let mut k: usize = 0; + loop { + use core::cmp::{min, max}; + + k += base; + let t = min(max(k.saturating_sub(bias), t_min), t_max); + + let d = match punycode_bytes.next() { + Some(d @ b'a'...b'z') => d - b'a', + Some(d @ b'0'...b'9') => 26 + (d - b'0'), + _ => return Err(()), + }; + let d = d as usize; + delta = try!(delta.checked_add( + try!(d.checked_mul(w).ok_or(())) + ).ok_or(())); + if d < t { + break; + } + w = try!(w.checked_mul(base - t).ok_or(())); + } + + // Compute the new insert position and character. + len += 1; + i = try!(i.checked_add(delta).ok_or(())); + n = try!(n.checked_add(i / len).ok_or(())); + i %= len; + + let n_u32 = n as u32; + let c = if n_u32 as usize == n { + try!(char::from_u32(n_u32).ok_or(())) + } else { + return Err(()); + }; + + // Insert the new character and increment the insert position. + try!(insert(i, c)); + i += 1; + + // If there are no more deltas, decoding is complete. + if punycode_bytes.peek().is_none() { + return Ok(()); + } + + // Perform bias adaptation. + delta /= damp; + damp = 2; + + delta += delta / len; + let mut k = 0; + while delta > ((base - t_min) * t_max) / 2 { + delta /= base - t_min; + k += base; + } + bias = k + ((base - t_min + 1) * delta) / (delta + skew); + } + } +} + +impl<'s> Display for Ident<'s> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.try_small_punycode_decode(|chars| { + for &c in chars { + try!(c.fmt(f)); + } + Ok(()) + }).unwrap_or_else(|| { + if !self.punycode.is_empty() { + try!(f.write_str("punycode{")); + + // Reconstruct a standard Punycode encoding, + // by using `-` as the separator. + if !self.ascii.is_empty() { + try!(f.write_str(self.ascii)); + try!(f.write_str("-")); + } + try!(f.write_str(self.punycode)); + + f.write_str("}") + } else { + f.write_str(self.ascii) + } + }) + } +} + +fn basic_type(tag: u8) -> Option<&'static str> { + Some(match tag { + b'b' => "bool", + b'c' => "char", + b'e' => "str", + b'u' => "()", + b'a' => "i8", + b's' => "i16", + b'l' => "i32", + b'x' => "i64", + b'n' => "i128", + b'i' => "isize", + b'h' => "u8", + b't' => "u16", + b'm' => "u32", + b'y' => "u64", + b'o' => "u128", + b'j' => "usize", + b'f' => "f32", + b'd' => "f64", + b'z' => "!", + b'p' => "_", + b'v' => "...", + + _ => return None, + }) +} + +struct Parser<'s> { + sym: &'s str, + next: usize, +} + +impl<'s> Parser<'s> { + fn peek(&self) -> Option<u8> { + self.sym.as_bytes().get(self.next).cloned() + } + + fn eat(&mut self, b: u8) -> bool { + if self.peek() == Some(b) { + self.next += 1; + true + } else { + false + } + } + + fn next(&mut self) -> Result<u8, Invalid> { + let b = try!(self.peek().ok_or(Invalid)); + self.next += 1; + Ok(b) + } + + fn hex_nibbles(&mut self) -> Result<&'s str, Invalid> { + let start = self.next; + loop { + match try!(self.next()) { + b'0'...b'9' | b'a'...b'f' => {} + b'_' => break, + _ => return Err(Invalid), + } + } + Ok(&self.sym[start..self.next - 1]) + } + + fn digit_10(&mut self) -> Result<u8, Invalid> { + let d = match self.peek() { + Some(d @ b'0'...b'9') => d - b'0', + _ => return Err(Invalid), + }; + self.next += 1; + Ok(d) + } + + fn digit_62(&mut self) -> Result<u8, Invalid> { + let d = match self.peek() { + Some(d @ b'0'...b'9') => d - b'0', + Some(d @ b'a'...b'z') => 10 + (d - b'a'), + Some(d @ b'A'...b'Z') => 10 + 26 + (d - b'A'), + _ => return Err(Invalid), + }; + self.next += 1; + Ok(d) + } + + fn integer_62(&mut self) -> Result<u64, Invalid> { + if self.eat(b'_') { + return Ok(0); + } + + let mut x: u64 = 0; + while !self.eat(b'_') { + let d = try!(self.digit_62()) as u64; + x = try!(x.checked_mul(62).ok_or(Invalid)); + x = try!(x.checked_add(d).ok_or(Invalid)); + } + x.checked_add(1).ok_or(Invalid) + } + + fn opt_integer_62(&mut self, tag: u8) -> Result<u64, Invalid> { + if !self.eat(tag) { + return Ok(0); + } + try!(self.integer_62()).checked_add(1).ok_or(Invalid) + } + + fn disambiguator(&mut self) -> Result<u64, Invalid> { + self.opt_integer_62(b's') + } + + fn namespace(&mut self) -> Result<Option<char>, Invalid> { + match try!(self.next()) { + // Special namespaces, like closures and shims. + ns @ b'A'...b'Z' => Ok(Some(ns as char)), + + // Implementation-specific/unspecified namespaces. + b'a'...b'z' => Ok(None), + + _ => Err(Invalid), + } + } + + fn backref(&mut self) -> Result<Parser<'s>, Invalid> { + let s_start = self.next - 1; + let i = try!(self.integer_62()); + if i >= s_start as u64 { + return Err(Invalid); + } + Ok(Parser { + sym: self.sym, + next: i as usize, + }) + } + + fn ident(&mut self) -> Result<Ident<'s>, Invalid> { + let is_punycode = self.eat(b'u'); + let mut len = try!(self.digit_10()) as usize; + if len != 0 { + loop { + match self.digit_10() { + Ok(d) => { + len = try!(len.checked_mul(10).ok_or(Invalid)); + len = try!(len.checked_add(d as usize).ok_or(Invalid)); + } + Err(Invalid) => break, + } + } + } + + // Skip past the optional `_` separator. + self.eat(b'_'); + + let start = self.next; + self.next = try!(self.next.checked_add(len).ok_or(Invalid)); + if self.next > self.sym.len() { + return Err(Invalid); + } + + let ident = &self.sym[start..self.next]; + + if is_punycode { + let ident = match ident.bytes().rposition(|b| b == b'_') { + Some(i) => Ident { + ascii: &ident[..i], + punycode: &ident[i + 1..], + }, + None => Ident { + ascii: "", + punycode: ident, + }, + }; + if ident.punycode.is_empty() { + return Err(Invalid); + } + Ok(ident) + } else { + Ok(Ident { + ascii: ident, + punycode: "", + }) + } + } + + fn skip_path(&mut self) -> Result<(), Invalid> { + match try!(self.next()) { + b'C' => { + try!(self.disambiguator()); + try!(self.ident()); + } + b'N' => { + try!(self.namespace()); + try!(self.skip_path()); + try!(self.disambiguator()); + try!(self.ident()); + } + b'M' => { + try!(self.disambiguator()); + try!(self.skip_path()); + try!(self.skip_type()); + } + b'X' => { + try!(self.disambiguator()); + try!(self.skip_path()); + try!(self.skip_type()); + try!(self.skip_path()); + } + b'Y' => { + try!(self.skip_type()); + try!(self.skip_path()); + } + b'I' => { + try!(self.skip_path()); + while !self.eat(b'E') { + try!(self.skip_generic_arg()); + } + } + b'B' => { + try!(self.backref()); + } + _ => return Err(Invalid), + } + Ok(()) + } + + fn skip_generic_arg(&mut self) -> Result<(), Invalid> { + if self.eat(b'L') { + try!(self.integer_62()); + Ok(()) + } else if self.eat(b'K') { + self.skip_const() + } else { + self.skip_type() + } + } + + fn skip_type(&mut self) -> Result<(), Invalid> { + match try!(self.next()) { + tag if basic_type(tag).is_some() => {} + + b'R' | b'Q' => { + if self.eat(b'L') { + try!(self.integer_62()); + } + try!(self.skip_type()); + } + b'P' | b'O' | b'S' => try!(self.skip_type()), + b'A' => { + try!(self.skip_type()); + try!(self.skip_const()); + } + b'T' => while !self.eat(b'E') { + try!(self.skip_type()); + }, + b'F' => { + let _binder = try!(self.opt_integer_62(b'G')); + let _is_unsafe = self.eat(b'U'); + if self.eat(b'K') { + let c_abi = self.eat(b'C'); + if !c_abi { + let abi = try!(self.ident()); + if abi.ascii.is_empty() || !abi.punycode.is_empty() { + return Err(Invalid); + } + } + } + while !self.eat(b'E') { + try!(self.skip_type()); + } + try!(self.skip_type()); + } + b'D' => { + let _binder = try!(self.opt_integer_62(b'G')); + while !self.eat(b'E') { + try!(self.skip_path()); + while self.eat(b'p') { + try!(self.ident()); + try!(self.skip_type()); + } + } + if !self.eat(b'L') { + return Err(Invalid); + } + try!(self.integer_62()); + } + b'B' => { + try!(self.backref()); + } + _ => { + // Go back to the tag, so `skip_path` also sees it. + self.next -= 1; + try!(self.skip_path()); + } + } + Ok(()) + } + + fn skip_const(&mut self) -> Result<(), Invalid> { + if self.eat(b'B') { + try!(self.backref()); + return Ok(()); + } + + match try!(self.next()) { + // Unsigned integer types. + b'h' | b't' | b'm' | b'y' | b'o' | b'j' => {} + + _ => return Err(Invalid), + } + + if self.eat(b'p') { + return Ok(()); + } + try!(self.hex_nibbles()); + Ok(()) + } +} + +struct Printer<'a, 'b: 'a, 's> { + parser: Result<Parser<'s>, Invalid>, + out: &'a mut fmt::Formatter<'b>, + bound_lifetime_depth: u32, +} + +/// Mark the parser as errored, print `?` and return early. +/// This allows callers to keep printing the approximate +/// syntax of the path/type/const, despite having errors. +/// E.g. `Vec<[(A, ?); ?]>` instead of `Vec<[(A, ?`. +macro_rules! invalid { + ($printer:ident) => {{ + $printer.parser = Err(Invalid); + return $printer.out.write_str("?"); + }} +} + +/// Call a parser method (if the parser hasn't errored yet), +/// and mark the parser as errored if it returns `Err(Invalid)`. +/// +/// If the parser errored, before or now, prints `?`, and +/// returns early the current function (see `invalid!` above). +macro_rules! parse { + ($printer:ident, $method:ident $(($($arg:expr),*))*) => { + match $printer.parser_mut().and_then(|p| p.$method($($($arg),*)*)) { + Ok(x) => x, + Err(Invalid) => invalid!($printer), + } + }; +} + +impl<'a, 'b, 's> Printer<'a, 'b, 's> { + fn parser_mut<'c>(&'c mut self) -> Result<&'c mut Parser<'s>, Invalid> { + self.parser.as_mut().map_err(|_| Invalid) + } + + /// Eat the given character from the parser, + /// returning `false` if the parser errored. + fn eat(&mut self, b: u8) -> bool { + self.parser_mut().map(|p| p.eat(b)) == Ok(true) + } + + /// Return a nested parser for a backref. + fn backref_printer<'c>(&'c mut self) -> Printer<'c, 'b, 's> { + Printer { + parser: self.parser_mut().and_then(|p| p.backref()), + out: self.out, + bound_lifetime_depth: self.bound_lifetime_depth, + } + } + + /// Print the lifetime according to the previously decoded index. + /// An index of `0` always refers to `'_`, but starting with `1`, + /// indices refer to late-bound lifetimes introduced by a binder. + fn print_lifetime_from_index(&mut self, lt: u64) -> fmt::Result { + try!(self.out.write_str("'")); + if lt == 0 { + return self.out.write_str("_"); + } + match (self.bound_lifetime_depth as u64).checked_sub(lt) { + Some(depth) => { + // Try to print lifetimes alphabetically first. + if depth < 26 { + let c = (b'a' + depth as u8) as char; + c.fmt(self.out) + } else { + // Use `'_123` after running out of letters. + try!(self.out.write_str("_")); + depth.fmt(self.out) + } + } + None => invalid!(self), + } + } + + /// Optionally enter a binder ('G') for late-bound lifetimes, + /// printing e.g. `for<'a, 'b> ` before calling the closure, + /// and make those lifetimes visible to it (via depth level). + fn in_binder<F>(&mut self, f: F) -> fmt::Result + where F: FnOnce(&mut Self) -> fmt::Result, + { + let bound_lifetimes = parse!(self, opt_integer_62(b'G')); + + if bound_lifetimes > 0 { + try!(self.out.write_str("for<")); + for i in 0..bound_lifetimes { + if i > 0 { + try!(self.out.write_str(", ")); + } + self.bound_lifetime_depth += 1; + try!(self.print_lifetime_from_index(1)); + } + try!(self.out.write_str("> ")); + } + + let r = f(self); + + // Restore `bound_lifetime_depth` to the previous value. + self.bound_lifetime_depth -= bound_lifetimes as u32; + + r + } + + /// Print list elements using the given closure and separator, + /// until the end of the list ('E') is found, or the parser errors. + /// Returns the number of elements printed. + fn print_sep_list<F>(&mut self, f: F, sep: &str) -> Result<usize, fmt::Error> + where F: Fn(&mut Self) -> fmt::Result, + { + let mut i = 0; + while self.parser.is_ok() && !self.eat(b'E') { + if i > 0 { + try!(self.out.write_str(sep)); + } + try!(f(self)); + i += 1; + } + Ok(i) + } + + fn print_path(&mut self, in_value: bool) -> fmt::Result { + let tag = parse!(self, next); + match tag { + b'C' => { + let dis = parse!(self, disambiguator); + let name = parse!(self, ident); + + try!(name.fmt(self.out)); + if !self.out.alternate() { + try!(self.out.write_str("[")); + try!(fmt::LowerHex::fmt(&dis, self.out)); + try!(self.out.write_str("]")); + } + } + b'N' => { + let ns = parse!(self, namespace); + + try!(self.print_path(in_value)); + + let dis = parse!(self, disambiguator); + let name = parse!(self, ident); + + match ns { + // Special namespaces, like closures and shims. + Some(ns) => { + try!(self.out.write_str("::{")); + match ns { + 'C' => try!(self.out.write_str("closure")), + 'S' => try!(self.out.write_str("shim")), + _ => try!(ns.fmt(self.out)), + } + if !name.ascii.is_empty() || !name.punycode.is_empty() { + try!(self.out.write_str(":")); + try!(name.fmt(self.out)); + } + try!(self.out.write_str("#")); + try!(dis.fmt(self.out)); + try!(self.out.write_str("}")); + } + + // Implementation-specific/unspecified namespaces. + None => { + if !name.ascii.is_empty() || !name.punycode.is_empty() { + try!(self.out.write_str("::")); + try!(name.fmt(self.out)); + } + } + } + } + b'M' | b'X' | b'Y' => { + if tag != b'Y' { + // Ignore the `impl`'s own path. + parse!(self, disambiguator); + parse!(self, skip_path); + } + + try!(self.out.write_str("<")); + try!(self.print_type()); + if tag != b'M' { + try!(self.out.write_str(" as ")); + try!(self.print_path(false)); + } + try!(self.out.write_str(">")); + } + b'I' => { + try!(self.print_path(in_value)); + if in_value { + try!(self.out.write_str("::")); + } + try!(self.out.write_str("<")); + try!(self.print_sep_list(Self::print_generic_arg, ", ")); + try!(self.out.write_str(">")); + } + b'B' => { + try!(self.backref_printer().print_path(in_value)); + } + _ => invalid!(self), + } + Ok(()) + } + + fn print_generic_arg(&mut self) -> fmt::Result { + if self.eat(b'L') { + let lt = parse!(self, integer_62); + self.print_lifetime_from_index(lt) + } else if self.eat(b'K') { + self.print_const() + } else { + self.print_type() + } + } + + fn print_type(&mut self) -> fmt::Result { + let tag = parse!(self, next); + + match basic_type(tag) { + Some(ty) => return self.out.write_str(ty), + None => {} + } + + match tag { + b'R' | b'Q' => { + try!(self.out.write_str("&")); + if self.eat(b'L') { + let lt = parse!(self, integer_62); + if lt != 0 { + try!(self.print_lifetime_from_index(lt)); + try!(self.out.write_str(" ")); + } + } + if tag != b'R' { + try!(self.out.write_str("mut ")); + } + try!(self.print_type()); + } + + b'P' | b'O' => { + try!(self.out.write_str("*")); + if tag != b'P' { + try!(self.out.write_str("mut ")); + } else { + try!(self.out.write_str("const ")); + } + try!(self.print_type()); + } + + b'A' | b'S' => { + try!(self.out.write_str("[")); + try!(self.print_type()); + if tag == b'A' { + try!(self.out.write_str("; ")); + try!(self.print_const()); + } + try!(self.out.write_str("]")); + } + b'T' => { + try!(self.out.write_str("(")); + let count = try!(self.print_sep_list(Self::print_type, ", ")); + if count == 1 { + try!(self.out.write_str(",")); + } + try!(self.out.write_str(")")); + } + b'F' => try!(self.in_binder(|this| { + let is_unsafe = this.eat(b'U'); + let abi = if this.eat(b'K') { + if this.eat(b'C') { + Some("C") + } else { + let abi = parse!(this, ident); + if abi.ascii.is_empty() || !abi.punycode.is_empty() { + invalid!(this); + } + Some(abi.ascii) + } + } else { + None + }; + + if is_unsafe { + try!(this.out.write_str("unsafe ")); + } + + match abi { + Some(abi) => { + try!(this.out.write_str("extern \"")); + + // If the ABI had any `-`, they were replaced with `_`, + // so the parts between `_` have to be re-joined with `-`. + let mut parts = abi.split('_'); + try!(this.out.write_str(parts.next().unwrap())); + for part in parts { + try!(this.out.write_str("-")); + try!(this.out.write_str(part)); + } + + try!(this.out.write_str("\" ")); + } + None => {} + } + + try!(this.out.write_str("fn(")); + try!(this.print_sep_list(Self::print_type, ", ")); + try!(this.out.write_str(")")); + + if this.eat(b'u') { + // Skip printing the return type if it's 'u', i.e. `()`. + } else { + try!(this.out.write_str(" -> ")); + try!(this.print_type()); + } + + Ok(()) + })), + b'D' => { + try!(self.out.write_str("dyn ")); + try!(self.in_binder(|this| { + try!(this.print_sep_list(Self::print_dyn_trait, " + ")); + Ok(()) + })); + + if !self.eat(b'L') { + invalid!(self); + } + let lt = parse!(self, integer_62); + if lt != 0 { + try!(self.out.write_str(" + ")); + try!(self.print_lifetime_from_index(lt)); + } + } + b'B' => { + try!(self.backref_printer().print_type()); + } + _ => { + // Go back to the tag, so `print_path` also sees it. + let _ = self.parser_mut().map(|p| p.next -= 1); + try!(self.print_path(false)); + } + } + Ok(()) + } + + /// A trait in a trait object may have some "existential projections" + /// (i.e. associated type bindings) after it, which should be printed + /// in the `<...>` of the trait, e.g. `dyn Trait<T, U, Assoc=X>`. + /// To this end, this method will keep the `<...>` of an 'I' path + /// open, by omitting the `>`, and return `Ok(true)` in that case. + fn print_path_maybe_open_generics(&mut self) -> Result<bool, fmt::Error> { + if self.eat(b'B') { + self.backref_printer().print_path_maybe_open_generics() + } else if self.eat(b'I') { + try!(self.print_path(false)); + try!(self.out.write_str("<")); + try!(self.print_sep_list(Self::print_generic_arg, ", ")); + Ok(true) + } else { + try!(self.print_path(false)); + Ok(false) + } + } + + fn print_dyn_trait(&mut self) -> fmt::Result { + let mut open = try!(self.print_path_maybe_open_generics()); + + while self.eat(b'p') { + if !open { + try!(self.out.write_str("<")); + open = true; + } else { + try!(self.out.write_str(", ")); + } + + let name = parse!(self, ident); + try!(name.fmt(self.out)); + try!(self.out.write_str(" = ")); + try!(self.print_type()); + } + + if open { + try!(self.out.write_str(">")); + } + + Ok(()) + } + + fn print_const(&mut self) -> fmt::Result { + if self.eat(b'B') { + return self.backref_printer().print_const(); + } + + let ty_tag = parse!(self, next); + let ty = match ty_tag { + // Unsigned integer types. + b'h' | b't' | b'm' | b'y' | b'o' | b'j' => { + basic_type(ty_tag).unwrap() + } + + _ => invalid!(self), + }; + + + if self.eat(b'p') { + try!(self.out.write_str("_")); + } else { + try!(self.print_const_uint()); + } + + if !self.out.alternate() { + try!(self.out.write_str(": ")); + try!(self.out.write_str(ty)); + } + + Ok(()) + } + + fn print_const_uint(&mut self) -> fmt::Result { + let hex = parse!(self, hex_nibbles); + + // Print anything that doesn't fit in `u64` verbatim. + if hex.len() > 16 { + try!(self.out.write_str("0x")); + return self.out.write_str(hex); + } + + let mut v = 0; + for c in hex.chars() { + v = (v << 4) | (c.to_digit(16).unwrap() as u64); + } + v.fmt(self.out) + } +} + +#[cfg(test)] +mod tests { + macro_rules! t_nohash { + ($a:expr, $b:expr) => ({ + assert_eq!(format!("{:#}", ::demangle($a)), $b); + }) + } + macro_rules! t_nohash_type { + ($a:expr, $b:expr) => ( + t_nohash!(concat!("_RMC0", $a), concat!("<", $b, ">")) + ) + } + + #[test] + fn demangle_crate_with_leading_digit() { + t_nohash!( + "_RNvC6_123foo3bar", + "123foo::bar" + ); + } + + #[test] + fn demangle_utf8_idents() { + t_nohash!( + "_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y", + "utf8_idents::საჭმელად_გემრიელი_სადილი" + ); + } + + #[test] + fn demangle_closure() { + t_nohash!( + "_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_", + "cc::spawn::{closure#0}::{closure#0}" + ); + t_nohash!( + "_RNCINkXs25_NgCsbmNqQUJIY6D_4core5sliceINyB9_4IterhENuNgNoBb_4iter8iterator8Iterator9rpositionNCNgNpB9_6memchr7memrchrs_0E0Bb_", + "<core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}" + ); + } + + #[test] + fn demangle_dyn_trait() { + t_nohash!( + "_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std", + "alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>" + ); + } + + #[test] + fn demangle_const_generics() { + // NOTE(eddyb) this was hand-written, before rustc had working + // const generics support (but the mangling format did include them). + t_nohash_type!( + "INtC8arrayvec8ArrayVechKj7b_E", + "arrayvec::ArrayVec<u8, 123>" + ); + } + + #[test] + fn demangle_exponential_explosion() { + // NOTE(eddyb) because of the prefix added by `t_nohash_type!` is + // 3 bytes long, `B2_` refers to the start of the type, not `B_`. + // 6 backrefs (`B8_E` through `B3_E`) result in 2^6 = 64 copies of `_`. + // Also, because the `p` (`_`) type is after all of the starts of the + // backrefs, it can be replaced with any other type, independently. + t_nohash_type!( + concat!("TTTTTT", "p", "B8_E", "B7_E", "B6_E", "B5_E", "B4_E", "B3_E"), + "((((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \ + ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))), \ + (((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), \ + ((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))" + ); + } +} diff --git a/rustc-workspace-hack/.cargo-checksum.json b/rustc-workspace-hack/.cargo-checksum.json new file mode 100644 index 000000000..f24f6365c --- /dev/null +++ b/rustc-workspace-hack/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"} \ No newline at end of file diff --git a/rustc-workspace-hack/Cargo.toml b/rustc-workspace-hack/Cargo.toml new file mode 100644 index 000000000..e965c6af3 --- /dev/null +++ b/rustc-workspace-hack/Cargo.toml @@ -0,0 +1,20 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc-workspace-hack" +version = "1.0.0" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +description = "Hack for the compiler's own build system\n" +license = "MIT/Apache-2.0" + +[dependencies] diff --git a/rustc-workspace-hack/src/lib.rs b/rustc-workspace-hack/src/lib.rs new file mode 100644 index 000000000..31e1bb209 --- /dev/null +++ b/rustc-workspace-hack/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/rustc_version/.cargo-checksum.json b/rustc_version/.cargo-checksum.json new file mode 100644 index 000000000..87639f199 --- /dev/null +++ b/rustc_version/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"} \ No newline at end of file diff --git a/rustc_version/Cargo.toml b/rustc_version/Cargo.toml new file mode 100644 index 000000000..3b252b85a --- /dev/null +++ b/rustc_version/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc_version" +version = "0.2.3" +authors = ["Marvin Löbel <loebel.marvin@gmail.com>"] +description = "A library for querying the version of a installed rustc compiler" +documentation = "https://docs.rs/rustc_version/" +readme = "README.md" +keywords = ["version", "rustc"] +license = "MIT/Apache-2.0" +repository = "https://github.com/Kimundi/rustc-version-rs" +[dependencies.semver] +version = "0.9" +[badges.travis-ci] +repository = "Kimundi/rustc-version-rs" diff --git a/rustc_version/LICENSE-APACHE b/rustc_version/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/rustc_version/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rustc_version/LICENSE-MIT b/rustc_version/LICENSE-MIT new file mode 100644 index 000000000..40b8817a4 --- /dev/null +++ b/rustc_version/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rustc_version/README.md b/rustc_version/README.md new file mode 100644 index 000000000..f491ca964 --- /dev/null +++ b/rustc_version/README.md @@ -0,0 +1,75 @@ +rustc-version-rs +============== + +A library for querying the version of a `rustc` compiler. + +This can be used by build scripts or other tools dealing with Rust sources +to make decisions based on the version of the compiler. + +[![Travis-CI Status](https://travis-ci.org/Kimundi/rustc-version-rs.png?branch=master)](https://travis-ci.org/Kimundi/rustc-version-rs) + +# Getting Started + +[rustc-version-rs is available on crates.io](https://crates.io/crates/rustc_version). +It is recommended to look there for the newest released version, as well as links to the newest builds of the docs. + +At the point of the last update of this README, the latest published version could be used like this: + +Add the following dependency to your Cargo manifest... + +```toml +[build-dependencies] +rustc_version = "0.2" +``` + +...and see the [docs](http://kimundi.github.io/rustc-version-rs/rustc_version/index.html) for how to use it. + +# Example + +```rust +// This could be a cargo build script + +extern crate rustc_version; +use rustc_version::{version, version_meta, Channel, Version}; + +fn main() { + // Assert we haven't travelled back in time + assert!(version().unwrap().major >= 1); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=RUSTC_IS_STABLE"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=RUSTC_IS_BETA"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=RUSTC_IS_DEV"); + } + } + + // Check for a minimum version + if version().unwrap() >= Version::parse("1.4.0").unwrap() { + println!("cargo:rustc-cfg=compiler_has_important_bugfix"); + } +} +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/rustc_version/src/errors.rs b/rustc_version/src/errors.rs new file mode 100644 index 000000000..54557b6e2 --- /dev/null +++ b/rustc_version/src/errors.rs @@ -0,0 +1,79 @@ +use std::{self, error, fmt, io, str}; +use semver::{self, Identifier}; + +/// The error type for this crate. +#[derive(Debug)] +pub enum Error { + /// An error ocurrend when executing the `rustc` command. + CouldNotExecuteCommand(io::Error), + /// The output of `rustc -vV` was not valid utf-8. + Utf8Error(str::Utf8Error), + /// The output of `rustc -vV` was not in the expected format. + UnexpectedVersionFormat, + /// An error ocurred in parsing a `VersionReq`. + ReqParseError(semver::ReqParseError), + /// An error ocurred in parsing the semver. + SemVerError(semver::SemVerError), + /// The pre-release tag is unknown. + UnknownPreReleaseTag(Identifier), +} +use Error::*; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::error::Error; + match *self { + CouldNotExecuteCommand(ref e) => write!(f, "{}: {}", self.description(), e), + Utf8Error(_) => write!(f, "{}", self.description()), + UnexpectedVersionFormat => write!(f, "{}", self.description()), + ReqParseError(ref e) => write!(f, "{}: {}", self.description(), e), + SemVerError(ref e) => write!(f, "{}: {}", self.description(), e), + UnknownPreReleaseTag(ref i) => write!(f, "{}: {}", self.description(), i), + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + CouldNotExecuteCommand(ref e) => Some(e), + Utf8Error(ref e) => Some(e), + UnexpectedVersionFormat => None, + ReqParseError(ref e) => Some(e), + SemVerError(ref e) => Some(e), + UnknownPreReleaseTag(_) => None, + } + } + + fn description(&self) -> &str { + match *self { + CouldNotExecuteCommand(_) => "could not execute command", + Utf8Error(_) => "invalid UTF-8 output from `rustc -vV`", + UnexpectedVersionFormat => "unexpected `rustc -vV` format", + ReqParseError(_) => "error parsing version requirement", + SemVerError(_) => "error parsing version", + UnknownPreReleaseTag(_) => "unknown pre-release tag", + } + } +} + +macro_rules! impl_from { + ($($err_ty:ty => $variant:ident),* $(,)*) => { + $( + impl From<$err_ty> for Error { + fn from(e: $err_ty) -> Error { + Error::$variant(e) + } + } + )* + } +} + +impl_from! { + str::Utf8Error => Utf8Error, + semver::SemVerError => SemVerError, + semver::ReqParseError => ReqParseError, +} + +/// The result type for this crate. +pub type Result<T> = std::result::Result<T, Error>; diff --git a/rustc_version/src/lib.rs b/rustc_version/src/lib.rs new file mode 100644 index 000000000..c03828898 --- /dev/null +++ b/rustc_version/src/lib.rs @@ -0,0 +1,347 @@ +// Copyright 2016 rustc-version-rs developers +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![warn(missing_docs)] + +//! Simple library for getting the version information of a `rustc` +//! compiler. +//! +//! This can be used by build scripts or other tools dealing with Rust sources +//! to make decisions based on the version of the compiler. +//! +//! It calls `$RUSTC --version -v` and parses the output, falling +//! back to `rustc` if `$RUSTC` is not set. +//! +//! # Example +//! +//! ```rust +//! // This could be a cargo build script +//! +//! extern crate rustc_version; +//! use rustc_version::{version, version_meta, Channel, Version}; +//! +//! fn main() { +//! // Assert we haven't travelled back in time +//! assert!(version().unwrap().major >= 1); +//! +//! // Set cfg flags depending on release channel +//! match version_meta().unwrap().channel { +//! Channel::Stable => { +//! println!("cargo:rustc-cfg=RUSTC_IS_STABLE"); +//! } +//! Channel::Beta => { +//! println!("cargo:rustc-cfg=RUSTC_IS_BETA"); +//! } +//! Channel::Nightly => { +//! println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); +//! } +//! Channel::Dev => { +//! println!("cargo:rustc-cfg=RUSTC_IS_DEV"); +//! } +//! } +//! +//! // Check for a minimum version +//! if version().unwrap() >= Version::parse("1.4.0").unwrap() { +//! println!("cargo:rustc-cfg=compiler_has_important_bugfix"); +//! } +//! } +//! ``` + +extern crate semver; +use semver::Identifier; +use std::process::Command; +use std::{env, str}; +use std::ffi::OsString; + +// Convenience re-export to allow version comparison without needing to add +// semver crate. +pub use semver::Version; + +mod errors; +pub use errors::{Error, Result}; + +/// Release channel of the compiler. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum Channel { + /// Development release channel + Dev, + /// Nightly release channel + Nightly, + /// Beta release channel + Beta, + /// Stable release channel + Stable, +} + +/// Rustc version plus metada like git short hash and build date. +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct VersionMeta { + /// Version of the compiler + pub semver: Version, + + /// Git short hash of the build of the compiler + pub commit_hash: Option<String>, + + /// Commit date of the compiler + pub commit_date: Option<String>, + + /// Build date of the compiler; this was removed between Rust 1.0.0 and 1.1.0. + pub build_date: Option<String>, + + /// Release channel of the compiler + pub channel: Channel, + + /// Host target triple of the compiler + pub host: String, + + /// Short version string of the compiler + pub short_version_string: String, +} + +impl VersionMeta { + /// Returns the version metadata for `cmd`, which should be a `rustc` command. + pub fn for_command(cmd: Command) -> Result<VersionMeta> { + let mut cmd = cmd; + + let out = cmd.arg("-vV").output().map_err(Error::CouldNotExecuteCommand)?; + let out = str::from_utf8(&out.stdout)?; + + version_meta_for(out) + } +} + +/// Returns the `rustc` SemVer version. +pub fn version() -> Result<Version> { + Ok(version_meta()?.semver) +} + +/// Returns the `rustc` SemVer version and additional metadata +/// like the git short hash and build date. +pub fn version_meta() -> Result<VersionMeta> { + let cmd = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")); + + VersionMeta::for_command(Command::new(cmd)) +} + +/// Parses a "rustc -vV" output string and returns +/// the SemVer version and additional metadata +/// like the git short hash and build date. +pub fn version_meta_for(verbose_version_string: &str) -> Result<VersionMeta> { + let out: Vec<_> = verbose_version_string.lines().collect(); + + if !(out.len() >= 6 && out.len() <= 8) { + return Err(Error::UnexpectedVersionFormat); + } + + let short_version_string = out[0]; + + fn expect_prefix<'a>(line: &'a str, prefix: &str) -> Result<&'a str> { + if line.starts_with(prefix) { + Ok(&line[prefix.len()..]) + } else { + Err(Error::UnexpectedVersionFormat) + } + } + + let commit_hash = match expect_prefix(out[2], "commit-hash: ")? { + "unknown" => None, + hash => Some(hash.to_owned()), + }; + + let commit_date = match expect_prefix(out[3], "commit-date: ")? { + "unknown" => None, + hash => Some(hash.to_owned()), + }; + + // Handle that the build date may or may not be present. + let mut idx = 4; + let mut build_date = None; + if out[idx].starts_with("build-date") { + build_date = match expect_prefix(out[idx], "build-date: ")? { + "unknown" => None, + s => Some(s.to_owned()), + }; + idx += 1; + } + + let host = expect_prefix(out[idx], "host: ")?; + idx += 1; + let release = expect_prefix(out[idx], "release: ")?; + + let semver: Version = release.parse()?; + + let channel = if semver.pre.is_empty() { + Channel::Stable + } else { + match semver.pre[0] { + Identifier::AlphaNumeric(ref s) if s == "dev" => Channel::Dev, + Identifier::AlphaNumeric(ref s) if s == "beta" => Channel::Beta, + Identifier::AlphaNumeric(ref s) if s == "nightly" => Channel::Nightly, + ref x => return Err(Error::UnknownPreReleaseTag(x.clone())), + } + }; + + Ok(VersionMeta { + semver: semver, + commit_hash: commit_hash, + commit_date: commit_date, + build_date: build_date, + channel: channel, + host: host.into(), + short_version_string: short_version_string.into(), + }) +} + +#[test] +fn smoketest() { + let v = version().unwrap(); + assert!(v.major >= 1); + + let v = version_meta().unwrap(); + assert!(v.semver.major >= 1); + + assert!(version().unwrap() >= Version::parse("1.0.0").unwrap()); +} + +#[test] +fn parse_unexpected() { + let res = version_meta_for( +"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14) +binary: rustc +commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e +commit-date: 2015-05-13 +rust-birthday: 2015-05-14 +host: x86_64-unknown-linux-gnu +release: 1.0.0"); + + assert!(match res { + Err(Error::UnexpectedVersionFormat) => true, + _ => false, + }); + +} + +#[test] +fn parse_1_0_0() { + let version = version_meta_for( +"rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14) +binary: rustc +commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e +commit-date: 2015-05-13 +build-date: 2015-05-14 +host: x86_64-unknown-linux-gnu +release: 1.0.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.0.0").unwrap()); + assert_eq!(version.commit_hash, Some("a59de37e99060162a2674e3ff45409ac73595c0e".into())); + assert_eq!(version.commit_date, Some("2015-05-13".into())); + assert_eq!(version.build_date, Some("2015-05-14".into())); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)"); +} + + +#[test] +fn parse_unknown() { + let version = version_meta_for( +"rustc 1.3.0 +binary: rustc +commit-hash: unknown +commit-date: unknown +host: x86_64-unknown-linux-gnu +release: 1.3.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.3.0").unwrap()); + assert_eq!(version.commit_hash, None); + assert_eq!(version.commit_date, None); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.3.0"); +} + +#[test] +fn parse_nightly() { + let version = version_meta_for( +"rustc 1.5.0-nightly (65d5c0833 2015-09-29) +binary: rustc +commit-hash: 65d5c083377645a115c4ac23a620d3581b9562b6 +commit-date: 2015-09-29 +host: x86_64-unknown-linux-gnu +release: 1.5.0-nightly").unwrap(); + + assert_eq!(version.semver, Version::parse("1.5.0-nightly").unwrap()); + assert_eq!(version.commit_hash, Some("65d5c083377645a115c4ac23a620d3581b9562b6".into())); + assert_eq!(version.commit_date, Some("2015-09-29".into())); + assert_eq!(version.channel, Channel::Nightly); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.5.0-nightly (65d5c0833 2015-09-29)"); +} + +#[test] +fn parse_stable() { + let version = version_meta_for( +"rustc 1.3.0 (9a92aaf19 2015-09-15) +binary: rustc +commit-hash: 9a92aaf19a64603b02b4130fe52958cc12488900 +commit-date: 2015-09-15 +host: x86_64-unknown-linux-gnu +release: 1.3.0").unwrap(); + + assert_eq!(version.semver, Version::parse("1.3.0").unwrap()); + assert_eq!(version.commit_hash, Some("9a92aaf19a64603b02b4130fe52958cc12488900".into())); + assert_eq!(version.commit_date, Some("2015-09-15".into())); + assert_eq!(version.channel, Channel::Stable); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.3.0 (9a92aaf19 2015-09-15)"); +} + +#[test] +fn parse_1_16_0_nightly() { + let version = version_meta_for( +"rustc 1.16.0-nightly (5d994d8b7 2017-01-05) +binary: rustc +commit-hash: 5d994d8b7e482e87467d4a521911477bd8284ce3 +commit-date: 2017-01-05 +host: x86_64-unknown-linux-gnu +release: 1.16.0-nightly +LLVM version: 3.9").unwrap(); + + assert_eq!(version.semver, Version::parse("1.16.0-nightly").unwrap()); + assert_eq!(version.commit_hash, Some("5d994d8b7e482e87467d4a521911477bd8284ce3".into())); + assert_eq!(version.commit_date, Some("2017-01-05".into())); + assert_eq!(version.channel, Channel::Nightly); + assert_eq!(version.host, "x86_64-unknown-linux-gnu"); + assert_eq!(version.short_version_string, "rustc 1.16.0-nightly (5d994d8b7 2017-01-05)"); +} + +/* +#[test] +fn version_matches_replacement() { + let f = |s1: &str, s2: &str| { + let a = Version::parse(s1).unwrap(); + let b = Version::parse(s2).unwrap(); + println!("{} <= {} : {}", s1, s2, a <= b); + }; + + println!(); + + f("1.5.0", "1.5.0"); + f("1.5.0-nightly", "1.5.0"); + f("1.5.0", "1.5.0-nightly"); + f("1.5.0-nightly", "1.5.0-nightly"); + + f("1.5.0", "1.6.0"); + f("1.5.0-nightly", "1.6.0"); + f("1.5.0", "1.6.0-nightly"); + f("1.5.0-nightly", "1.6.0-nightly"); + + panic!(); + +} +*/ diff --git a/rustfix/.cargo-checksum.json b/rustfix/.cargo-checksum.json new file mode 100644 index 000000000..0edac8828 --- /dev/null +++ b/rustfix/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b96ea6eeae40f488397ccc9e1c0da19d720b23c75972bc63eaa6852b84d161e2"} \ No newline at end of file diff --git a/rustfix/Cargo.toml b/rustfix/Cargo.toml new file mode 100644 index 000000000..c3257d067 --- /dev/null +++ b/rustfix/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustfix" +version = "0.4.5" +authors = ["Pascal Hertleif <killercup@gmail.com>", "Oliver Schneider <oli-obk@users.noreply.github.com>"] +exclude = ["etc/*", "examples/*", "tests/*"] +description = "Automatically apply the suggestions made by rustc" +documentation = "https://docs.rs/rustfix" +readme = "Readme.md" +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang-nursery/rustfix" +[dependencies.failure] +version = "0.1.2" + +[dependencies.log] +version = "0.4.1" + +[dependencies.serde] +version = "1.0" + +[dependencies.serde_derive] +version = "1.0" + +[dependencies.serde_json] +version = "1.0" +[dev-dependencies.difference] +version = "2.0.0" + +[dev-dependencies.duct] +version = "0.9" + +[dev-dependencies.env_logger] +version = "0.5.0-rc.1" + +[dev-dependencies.log] +version = "0.4.1" + +[dev-dependencies.proptest] +version = "0.7.0" + +[dev-dependencies.tempdir] +version = "0.3.5" diff --git a/rustfix/LICENSE-APACHE b/rustfix/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/rustfix/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/rustfix/LICENSE-MIT b/rustfix/LICENSE-MIT new file mode 100644 index 000000000..458e9c6ce --- /dev/null +++ b/rustfix/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Pascal Hertleif + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/rustfix/Readme.md b/rustfix/Readme.md new file mode 100644 index 000000000..7efee7dc4 --- /dev/null +++ b/rustfix/Readme.md @@ -0,0 +1,44 @@ +# rustfix + +The goal of this tool is to read and apply the suggestions made by rustc. + +[![Build Status](https://travis-ci.org/rust-lang-nursery/rustfix.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rustfix) +[![Build status](https://ci.appveyor.com/api/projects/status/g8ljreo9ryu3s6ee/branch/master?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfix/branch/master) + +## Current status + +Currently, rustfix is split into two crates: + +- `rustfix`, a library for consuming and applying suggestions in the format that `rustc` outputs +- and `cargo-fix`, a binary that works as cargo subcommand and that end users will use to fix their code. + +The magic of rustfix is entirely dependent on the diagnostics implement in the Rust compiler (and external lints, like [clippy]). + +[clippy]: https://github.com/rust-lang-nursery/rust-clippy + +## Installation + +To use the rustfix library, add it to your `Cargo.toml`. + +To get the tool to automatically fix warnings in, run `cargo install cargo-fix`. This will give you `cargo fix`. + +## Using `cargo fix` to transition to Rust 2018 + +Instructions on how to use this tool to transition a crate to Rust 2018 can be +found [in the Rust Edition Guide.](https://rust-lang-nursery.github.io/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html) + +## License + +Licensed under either of + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/rustfix/bors.toml b/rustfix/bors.toml new file mode 100644 index 000000000..611828927 --- /dev/null +++ b/rustfix/bors.toml @@ -0,0 +1,4 @@ +status = [ + "continuous-integration/travis-ci/push", +] +required_approvals = 1 diff --git a/rustfix/proptest-regressions/replace.txt b/rustfix/proptest-regressions/replace.txt new file mode 100644 index 000000000..fc5bd1a8b --- /dev/null +++ b/rustfix/proptest-regressions/replace.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xs 358148376 3634975642 2528447681 3675516813 # shrinks to ref s = "" +xs 3127423015 3362740891 2605681441 2390162043 # shrinks to ref data = "", ref replacements = [(0..0, [])] diff --git a/rustfix/src/diagnostics.rs b/rustfix/src/diagnostics.rs new file mode 100644 index 000000000..d81c2c4aa --- /dev/null +++ b/rustfix/src/diagnostics.rs @@ -0,0 +1,87 @@ +//! Rustc Diagnostic JSON Output +//! +//! The following data types are copied from [rust-lang/rust](https://github.com/rust-lang/rust/blob/de78655bca47cac8e783dbb563e7e5c25c1fae40/src/libsyntax/json.rs) + +#[derive(Clone, Deserialize, Debug, Hash, Eq, PartialEq)] +pub struct Diagnostic { + /// The primary error message. + pub message: String, + pub code: Option<DiagnosticCode>, + /// "error: internal compiler error", "error", "warning", "note", "help". + level: String, + pub spans: Vec<DiagnosticSpan>, + /// Associated diagnostic messages. + pub children: Vec<Diagnostic>, + /// The message as rustc would render it. Currently this is only + /// `Some` for "suggestions", but eventually it will include all + /// snippets. + pub rendered: Option<String>, +} + +#[derive(Clone, Deserialize, Debug, Hash, Eq, PartialEq)] +pub struct DiagnosticSpan { + pub file_name: String, + pub byte_start: u32, + pub byte_end: u32, + /// 1-based. + pub line_start: usize, + pub line_end: usize, + /// 1-based, character offset. + pub column_start: usize, + pub column_end: usize, + /// Is this a "primary" span -- meaning the point, or one of the points, + /// where the error occurred? + is_primary: bool, + /// Source text from the start of line_start to the end of line_end. + pub text: Vec<DiagnosticSpanLine>, + /// Label that should be placed at this location (if any) + label: Option<String>, + /// If we are suggesting a replacement, this will contain text + /// that should be sliced in atop this span. You may prefer to + /// load the fully rendered version from the parent `Diagnostic`, + /// however. + pub suggested_replacement: Option<String>, + pub suggestion_applicability: Option<Applicability>, + /// Macro invocations that created the code at this span, if any. + expansion: Option<Box<DiagnosticSpanMacroExpansion>>, +} + +#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Hash, Eq)] +pub enum Applicability { + MachineApplicable, + HasPlaceholders, + MaybeIncorrect, + Unspecified, +} + +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] +pub struct DiagnosticSpanLine { + pub text: String, + + /// 1-based, character offset in self.text. + pub highlight_start: usize, + + pub highlight_end: usize, +} + +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] +struct DiagnosticSpanMacroExpansion { + /// span where macro was applied to generate this code; note that + /// this may itself derive from a macro (if + /// `span.expansion.is_some()`) + span: DiagnosticSpan, + + /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") + macro_decl_name: String, + + /// span where macro was defined (if known) + def_site_span: Option<DiagnosticSpan>, +} + +#[derive(Clone, Deserialize, Debug, Eq, PartialEq, Hash)] +pub struct DiagnosticCode { + /// The code itself. + pub code: String, + /// An explanation for the code. + explanation: Option<String>, +} diff --git a/rustfix/src/lib.rs b/rustfix/src/lib.rs new file mode 100644 index 000000000..8b7e575b5 --- /dev/null +++ b/rustfix/src/lib.rs @@ -0,0 +1,249 @@ +#[macro_use] +extern crate log; +#[macro_use] +extern crate failure; +#[cfg(test)] +#[macro_use] +extern crate proptest; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + +use std::collections::HashSet; +use std::ops::Range; + +use failure::Error; + +pub mod diagnostics; +use diagnostics::{Diagnostic, DiagnosticSpan}; +mod replace; + +#[derive(Debug, Clone, Copy)] +pub enum Filter { + MachineApplicableOnly, + Everything, +} + +pub fn get_suggestions_from_json<S: ::std::hash::BuildHasher>( + input: &str, + only: &HashSet<String, S>, + filter: Filter, +) -> serde_json::error::Result<Vec<Suggestion>> { + let mut result = Vec::new(); + for cargo_msg in serde_json::Deserializer::from_str(input).into_iter::<Diagnostic>() { + // One diagnostic line might have multiple suggestions + result.extend(collect_suggestions(&cargo_msg?, only, filter)); + } + Ok(result) +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct LinePosition { + pub line: usize, + pub column: usize, +} + +impl std::fmt::Display for LinePosition { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}:{}", self.line, self.column) + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct LineRange { + pub start: LinePosition, + pub end: LinePosition, +} + +impl std::fmt::Display for LineRange { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}-{}", self.start, self.end) + } +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +/// An error/warning and possible solutions for fixing it +pub struct Suggestion { + pub message: String, + pub snippets: Vec<Snippet>, + pub solutions: Vec<Solution>, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Solution { + pub message: String, + pub replacements: Vec<Replacement>, +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Snippet { + pub file_name: String, + pub line_range: LineRange, + pub range: Range<usize>, + /// leading surrounding text, text to replace, trailing surrounding text + /// + /// This split is useful for higlighting the part that gets replaced + pub text: (String, String, String), +} + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Replacement { + pub snippet: Snippet, + pub replacement: String, +} + +fn parse_snippet(span: &DiagnosticSpan) -> Option<Snippet> { + // unindent the snippet + let indent = span.text + .iter() + .map(|line| { + let indent = line.text + .chars() + .take_while(|&c| char::is_whitespace(c)) + .count(); + std::cmp::min(indent, line.highlight_start) + }) + .min()?; + let start = span.text[0].highlight_start - 1; + let end = span.text[0].highlight_end - 1; + let lead = span.text[0].text[indent..start].to_string(); + let mut body = span.text[0].text[start..end].to_string(); + for line in span.text.iter().take(span.text.len() - 1).skip(1) { + body.push('\n'); + body.push_str(&line.text[indent..]); + } + let mut tail = String::new(); + let last = &span.text[span.text.len() - 1]; + + // If we get a DiagnosticSpanLine where highlight_end > text.len(), we prevent an 'out of + // bounds' access by making sure the index is within the array bounds. + let last_tail_index = last.highlight_end.min(last.text.len()) - 1; + + if span.text.len() > 1 { + body.push('\n'); + body.push_str(&last.text[indent..last_tail_index]); + } + tail.push_str(&last.text[last_tail_index..]); + Some(Snippet { + file_name: span.file_name.clone(), + line_range: LineRange { + start: LinePosition { + line: span.line_start, + column: span.column_start, + }, + end: LinePosition { + line: span.line_end, + column: span.column_end, + }, + }, + range: (span.byte_start as usize)..(span.byte_end as usize), + text: (lead, body, tail), + }) +} + +fn collect_span(span: &DiagnosticSpan) -> Option<Replacement> { + let snippet = parse_snippet(span)?; + let replacement = span.suggested_replacement.clone()?; + Some(Replacement { snippet, replacement }) +} + +pub fn collect_suggestions<S: ::std::hash::BuildHasher>( + diagnostic: &Diagnostic, + only: &HashSet<String, S>, + filter: Filter, +) -> Option<Suggestion> { + if !only.is_empty() { + if let Some(ref code) = diagnostic.code { + if !only.contains(&code.code) { + // This is not the code we are looking for + return None; + } + } else { + // No code, probably a weird builtin warning/error + return None; + } + } + + let snippets = diagnostic + .spans + .iter() + .filter_map(|span| parse_snippet(span)) + .collect(); + + let solutions: Vec<_> = diagnostic + .children + .iter() + .filter_map(|child| { + let replacements: Vec<_> = child + .spans + .iter() + .filter(|span| { + use Filter::*; + use diagnostics::Applicability::*; + + match (filter, &span.suggestion_applicability) { + (MachineApplicableOnly, Some(MachineApplicable)) => true, + (MachineApplicableOnly, _) => false, + (Everything, _) => true, + } + }) + .filter_map(collect_span) + .collect(); + if replacements.len() == 1 { + Some(Solution { + message: child.message.clone(), + replacements, + }) + } else { + None + } + }) + .collect(); + + if solutions.is_empty() { + None + } else { + Some(Suggestion { + message: diagnostic.message.clone(), + snippets, + solutions, + }) + } +} + +pub struct CodeFix { + data: replace::Data, +} + +impl CodeFix { + pub fn new(s: &str) -> CodeFix { + CodeFix { + data: replace::Data::new(s.as_bytes()), + } + } + + pub fn apply(&mut self, suggestion: &Suggestion) -> Result<(), Error> { + for sol in &suggestion.solutions { + for r in &sol.replacements { + self.data.replace_range( + r.snippet.range.start, + r.snippet.range.end.saturating_sub(1), + r.replacement.as_bytes(), + )?; + } + } + Ok(()) + } + + pub fn finish(&self) -> Result<String, Error> { + Ok(String::from_utf8(self.data.to_vec())?) + } +} + +pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result<String, Error> { + let mut fix = CodeFix::new(code); + for suggestion in suggestions.iter().rev() { + fix.apply(suggestion)?; + } + fix.finish() +} diff --git a/rustfix/src/replace.rs b/rustfix/src/replace.rs new file mode 100644 index 000000000..9dfbd4d94 --- /dev/null +++ b/rustfix/src/replace.rs @@ -0,0 +1,327 @@ +//! A small module giving you a simple container that allows easy and cheap +//! replacement of parts of its content, with the ability to prevent changing +//! the same parts multiple times. + +use failure::Error; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum State { + Initial, + Replaced(Rc<[u8]>), + Inserted(Rc<[u8]>), +} + +impl State { + fn is_inserted(&self) -> bool { + if let State::Inserted(..) = *self { + true + } else { + false + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Span { + /// Start of this span in parent data + start: usize, + /// up to end including + end: usize, + data: State, +} + +/// A container that allows easily replacing chunks of its data +#[derive(Debug, Clone, Default)] +pub struct Data { + original: Vec<u8>, + parts: Vec<Span>, +} + +impl Data { + /// Create a new data container from a slice of bytes + pub fn new(data: &[u8]) -> Self { + Data { + original: data.into(), + parts: vec![ + Span { + data: State::Initial, + start: 0, + end: data.len().saturating_sub(1), + }, + ], + } + } + + /// Render this data as a vector of bytes + pub fn to_vec(&self) -> Vec<u8> { + if self.original.is_empty() { + return Vec::new(); + } + + self.parts.iter().fold(Vec::new(), |mut acc, d| { + match d.data { + State::Initial => acc.extend_from_slice(&self.original[d.start..=d.end]), + State::Replaced(ref d) | State::Inserted(ref d) => acc.extend_from_slice(&d), + }; + acc + }) + } + + /// Replace a chunk of data with the given slice, erroring when this part + /// was already changed previously. + pub fn replace_range( + &mut self, + from: usize, + up_to_and_including: usize, + data: &[u8], + ) -> Result<(), Error> { + let exclusive_end = up_to_and_including + 1; + + ensure!( + from <= exclusive_end, + "Invalid range {}...{}, start is larger than end", + from, + up_to_and_including + ); + + ensure!( + up_to_and_including <= self.original.len(), + "Invalid range {}...{} given, original data is only {} byte long", + from, + up_to_and_including, + self.original.len() + ); + + let insert_only = from == exclusive_end; + + // Since we error out when replacing an already replaced chunk of data, + // we can take some shortcuts here. For example, there can be no + // overlapping replacements -- we _always_ split a chunk of 'initial' + // data into three[^empty] parts, and there can't ever be two 'initial' + // parts touching. + // + // [^empty]: Leading and trailing ones might be empty if we replace + // the whole chunk. As an optimization and without loss of generality we + // don't add empty parts. + let new_parts = { + let index_of_part_to_split = self.parts + .iter() + .position(|p| { + !p.data.is_inserted() && p.start <= from && p.end >= up_to_and_including + }) + .ok_or_else(|| { + use log::Level::Debug; + if log_enabled!(Debug) { + let slices = self.parts + .iter() + .map(|p| { + ( + p.start, + p.end, + match p.data { + State::Initial => "initial", + State::Replaced(..) => "replaced", + State::Inserted(..) => "inserted", + }, + ) + }) + .collect::<Vec<_>>(); + debug!( + "no single slice covering {}...{}, current slices: {:?}", + from, up_to_and_including, slices, + ); + } + + format_err!( + "Could not replace range {}...{} in file \ + -- maybe parts of it were already replaced?", + from, + up_to_and_including + ) + })?; + + let part_to_split = &self.parts[index_of_part_to_split]; + + // If this replacement matches exactly the part that we would + // otherwise split then we ignore this for now. This means that you + // can replace the exact same range with the exact same content + // multiple times and we'll process and allow it. + // + // This is currently done to alleviate issues like + // rust-lang/rust#51211 although this clause likely wants to be + // removed if that's fixed deeper in the compiler. + if part_to_split.start == from && part_to_split.end == up_to_and_including { + if let State::Replaced(ref replacement) = part_to_split.data { + if &**replacement == data { + return Ok(()) + } + } + } + + ensure!( + part_to_split.data == State::Initial, + "Cannot replace slice of data that was already replaced" + ); + + let mut new_parts = Vec::with_capacity(self.parts.len() + 2); + + // Previous parts + if let Some(ps) = self.parts.get(..index_of_part_to_split) { + new_parts.extend_from_slice(&ps); + } + + // Keep initial data on left side of part + if from > part_to_split.start { + new_parts.push(Span { + start: part_to_split.start, + end: from.saturating_sub(1), + data: State::Initial, + }); + } + + // New part + new_parts.push(Span { + start: from, + end: up_to_and_including, + data: if insert_only { + State::Inserted(data.into()) + } else { + State::Replaced(data.into()) + }, + }); + + // Keep initial data on right side of part + if up_to_and_including < part_to_split.end { + new_parts.push(Span { + start: up_to_and_including + 1, + end: part_to_split.end, + data: State::Initial, + }); + } + + // Following parts + if let Some(ps) = self.parts.get(index_of_part_to_split + 1..) { + new_parts.extend_from_slice(&ps); + } + + new_parts + }; + + self.parts = new_parts; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use proptest::prelude::*; + + fn str(i: &[u8]) -> &str { + ::std::str::from_utf8(i).unwrap() + } + + #[test] + fn replace_some_stuff() { + let mut d = Data::new(b"foo bar baz"); + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + } + + #[test] + fn replace_a_single_char() { + let mut d = Data::new(b"let y = true;"); + d.replace_range(4, 4, b"mut y").unwrap(); + assert_eq!("let mut y = true;", str(&d.to_vec())); + } + + #[test] + fn replace_multiple_lines() { + let mut d = Data::new(b"lorem\nipsum\ndolor"); + + d.replace_range(6, 10, b"lol").unwrap(); + assert_eq!("lorem\nlol\ndolor", str(&d.to_vec())); + + d.replace_range(12, 16, b"lol").unwrap(); + assert_eq!("lorem\nlol\nlol", str(&d.to_vec())); + } + + #[test] + fn replace_multiple_lines_with_insert_only() { + let mut d = Data::new(b"foo!"); + + d.replace_range(3, 2, b"bar").unwrap(); + assert_eq!("foobar!", str(&d.to_vec())); + + d.replace_range(0, 2, b"baz").unwrap(); + assert_eq!("bazbar!", str(&d.to_vec())); + + d.replace_range(3, 3, b"?").unwrap(); + assert_eq!("bazbar?", str(&d.to_vec())); + } + + #[test] + fn replace_invalid_range() { + let mut d = Data::new(b"foo!"); + + assert!(d.replace_range(2, 0, b"bar").is_err()); + assert!(d.replace_range(0, 2, b"bar").is_ok()); + } + + #[test] + fn empty_to_vec_roundtrip() { + let s = ""; + assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice()); + } + + #[test] + #[should_panic(expected = "Cannot replace slice of data that was already replaced")] + fn replace_overlapping_stuff_errs() { + let mut d = Data::new(b"foo bar baz"); + + d.replace_range(4, 6, b"lol").unwrap(); + assert_eq!("foo lol baz", str(&d.to_vec())); + + d.replace_range(4, 6, b"lol2").unwrap(); + } + + #[test] + #[should_panic(expected = "original data is only 3 byte long")] + fn broken_replacements() { + let mut d = Data::new(b"foo"); + d.replace_range(4, 7, b"lol").unwrap(); + } + + #[test] + fn replace_same_twice() { + let mut d = Data::new(b"foo"); + d.replace_range(0, 0, b"b").unwrap(); + d.replace_range(0, 0, b"b").unwrap(); + assert_eq!("boo", str(&d.to_vec())); + } + + proptest! { + #[test] + #[ignore] + fn new_to_vec_roundtrip(ref s in "\\PC*") { + assert_eq!(s.as_bytes(), Data::new(s.as_bytes()).to_vec().as_slice()); + } + + #[test] + #[ignore] + fn replace_random_chunks( + ref data in "\\PC*", + ref replacements in prop::collection::vec( + (any::<::std::ops::Range<usize>>(), any::<Vec<u8>>()), + 1..1337, + ) + ) { + let mut d = Data::new(data.as_bytes()); + for &(ref range, ref bytes) in replacements { + let _ = d.replace_range(range.start, range.end, bytes); + } + } + } +} diff --git a/rusty-fork/.cargo-checksum.json b/rusty-fork/.cargo-checksum.json new file mode 100644 index 000000000..aeef3d6a5 --- /dev/null +++ b/rusty-fork/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"3dd93264e10c577503e926bd1430193eeb5d21b059148910082245309b424fae"} \ No newline at end of file diff --git a/rusty-fork/CHANGELOG.md b/rusty-fork/CHANGELOG.md new file mode 100644 index 000000000..4bbecc109 --- /dev/null +++ b/rusty-fork/CHANGELOG.md @@ -0,0 +1,31 @@ +## 0.2.2 + +### Minor changes + +- `wait_timeout` has been bumped to `0.2.0`. + +## 0.2.1 + +### Bug Fixes + +- Dependency on `wait_timeout` crate now requires `0.1.4` rather than `0.1` + since the build doesn't work with older versions. + +## 0.2.0 + +### Breaking changes + +- APIs which used to provide a `std::process::Child` now instead provide a + `rusty_fork::ChildWrapper`. + +### Bug fixes + +- Fix that using the "timeout" feature, or otherwise using `wait_timeout` on + the child process, could cause an unrelated process to get killed if the + child exits within the timeout. + +## 0.1.1 + +### Minor changes + +- `tempfile` updated to 3.0. diff --git a/rusty-fork/Cargo.toml b/rusty-fork/Cargo.toml new file mode 100644 index 000000000..0ab602395 --- /dev/null +++ b/rusty-fork/Cargo.toml @@ -0,0 +1,44 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rusty-fork" +version = "0.2.2" +authors = ["Jason Lingle"] +exclude = ["/gen-readme.sh", "/readme-*.md"] +description = "Cross-platform library for running Rust tests in sub-processes using a\nfork-like interface.\n" +documentation = "https://docs.rs/rusty-fork" +readme = "README.md" +keywords = ["testing", "process", "fork"] +categories = ["development-tools::testing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/altsysrq/rusty-fork" +[dependencies.fnv] +version = "1.0" + +[dependencies.quick-error] +version = "1.2" + +[dependencies.tempfile] +version = "3.0" + +[dependencies.wait-timeout] +version = "0.2" +optional = true + +[dev-dependencies] + +[features] +default = ["timeout"] +timeout = ["wait-timeout"] +[badges.travis-ci] +repository = "AltSysrq/rusty-fork" diff --git a/rusty-fork/LICENSE-APACHE b/rusty-fork/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/rusty-fork/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/rusty-fork/LICENSE-MIT b/rusty-fork/LICENSE-MIT new file mode 100644 index 000000000..63ceeec5c --- /dev/null +++ b/rusty-fork/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 FullContact, Inc + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rusty-fork/README.md b/rusty-fork/README.md new file mode 100644 index 000000000..b618d56e2 --- /dev/null +++ b/rusty-fork/README.md @@ -0,0 +1,115 @@ +# rusty-fork + +[![Build Status](https://travis-ci.org/AltSysrq/rusty-fork.svg?branch=master)](https://travis-ci.org/AltSysrq/rusty-fork) +[![](http://meritbadge.herokuapp.com/rusty-fork)](https://crates.io/crates/rusty-fork) + +Rusty-fork provides a way to "fork" unit tests into separate processes. + +There are a number of reasons to want to run some tests in isolated +processes: + +- When tests share a process, if any test causes the process to abort, +segfault, overflow the stack, etc., the entire test runner process dies. If +the test is in a subprocess, only the subprocess dies and the test runner +simply fails the test. + +- Isolating a test to a subprocess makes it possible to add a timeout to +the test and forcibly terminate it and produce a normal test failure. + +- Tests which need to interact with some inherently global property, such +as the current working directory, can do so without interfering with other +tests. + +This crate itself provides two things: + +- The [`rusty_fork_test!`](macro.rusty_fork_test.html) macro, which is a +simple way to wrap standard Rust tests to be run in subprocesses with +optional timeouts. + +- The [`fork`](fn.fork.html) function which can be used as a building block +to make other types of process isolation strategies. + +## Quick Start + +If you just want to run normal Rust tests in isolated processes, getting +started is pretty quick. + +In `Cargo.toml`, add + +```toml +[dev-dependencies] +rusty-fork = "0.2.1" +``` + +and to your crate root add + +```rust +#[macro_use] extern crate rusty_fork; +``` + +Then, you can simply wrap any test(s) to be isolated with the +[`rusty_fork_test!`](macro.rusty_fork_test.html) macro. + +```rust +#[macro_use] extern crate rusty_fork; + +rusty_fork_test! { + #[test] + fn my_test() { + assert_eq!(2, 1 + 1); + } + + // more tests... +} +``` + +For more advanced usage, have a look at the [`fork`](fn.fork.html) +function. + +## How rusty-fork works + +Unix-style process forking isn't really viable within the standard Rust +test environment for a number of reasons. + +- While true process forking can be done on Windows, it's neither fast nor +reliable. + +- The Rust test environment is multi-threaded, so attempting to do anything +non-trivial after a process fork would result in undefined behaviour. + +Rusty-fork instead works by _spawning_ a fresh instance of the current +process, after adjusting the command-line to ensure that only the desired +test is entered. Some additional coordination establishes the parent/child +branches and (not quite seamlessly) integrates the child's output with the +test output capture system. + +Coordination between the processes is performed via environment variables, +since there is otherwise no way to pass parameters to a test. + +Since it needs to spawn new copies of the test runner executable, +rusty-fork does need to know about the meaning of every flag passed by the +user. If any unknown flags are encountered, forking will fail. Please do +not hesitate to file +[issues](https://github.com/AltSysrq/rusty-fork/issues) if rusty-fork fails +to recognise any valid flags passed to the test runner. + +It is possible to inform rusty-fork of new flags without patching by +setting environment variables. For example, if a new `--frob-widgets` flag +were added to the test runner, you could set `RUSTY_FORK_FLAG_FROB_WIDGETS` +to one of the following: + +- `pass` — Pass the flag (just the flag) to the child process +- `pass-arg` — Pass the flag and its following argument to the child process +- `drop` — Don't pass the flag to the child process +- `drop-arg` — Don't pass the flag to the child process, and ignore whatever + argument follows. + +In general, arguments that affect which tests are run should be dropped, +and others should be passed. + + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/rusty-fork/src/child_wrapper.rs b/rusty-fork/src/child_wrapper.rs new file mode 100644 index 000000000..a16086283 --- /dev/null +++ b/rusty-fork/src/child_wrapper.rs @@ -0,0 +1,248 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::io; +use std::process::{Child, Output}; +#[cfg(feature = "timeout")] +use std::time::Duration; + +#[cfg(feature = "timeout")] +use wait_timeout::ChildExt; + +/// Wraps `std::process::ExitStatus`. Historically, this was due to the +/// `wait_timeout` crate having its own `ExitStatus` type. +/// +/// Method documentation is copied from the [Rust std +/// docs](https://doc.rust-lang.org/stable/std/process/struct.ExitStatus.html) +/// and the [`wait_timeout` +/// docs](https://docs.rs/wait-timeout/0.1.5/wait_timeout/struct.ExitStatus.html). +#[derive(Clone, Copy)] +pub struct ExitStatusWrapper(ExitStatusEnum); + +#[derive(Debug, Clone, Copy)] +enum ExitStatusEnum { + Std(::std::process::ExitStatus), +} + +impl ExitStatusWrapper { + fn std(es: ::std::process::ExitStatus) -> Self { + ExitStatusWrapper(ExitStatusEnum::Std(es)) + } + + /// Was termination successful? Signal termination is not considered a + /// success, and success is defined as a zero exit status. + pub fn success(&self) -> bool { + match self.0 { + ExitStatusEnum::Std(es) => es.success(), + } + } + + /// Returns the exit code of the process, if any. + /// + /// On Unix, this will return `None` if the process was terminated by a + /// signal; `std::os::unix` provides an extension trait for extracting the + /// signal and other details from the `ExitStatus`. + pub fn code(&self) -> Option<i32> { + match self.0 { + ExitStatusEnum::Std(es) => es.code(), + } + } + + /// Returns the Unix signal which terminated this process. + /// + /// Note that on Windows this will always return None and on Unix this will + /// return None if the process successfully exited otherwise. + /// + /// For simplicity and to match `wait_timeout`, this method is always + /// present even on systems that do not support it. + #[cfg(not(target_os = "windows"))] + pub fn unix_signal(&self) -> Option<i32> { + use std::os::unix::process::ExitStatusExt; + + match self.0 { + ExitStatusEnum::Std(es) => es.signal(), + } + } + + /// Returns the Unix signal which terminated this process. + /// + /// Note that on Windows this will always return None and on Unix this will + /// return None if the process successfully exited otherwise. + /// + /// For simplicity and to match `wait_timeout`, this method is always + /// present even on systems that do not support it. + #[cfg(target_os = "windows")] + pub fn unix_signal(&self) -> Option<i32> { + None + } +} + +impl fmt::Debug for ExitStatusWrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + ExitStatusEnum::Std(ref es) => fmt::Debug::fmt(es, f), + } + } +} + +impl fmt::Display for ExitStatusWrapper { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + ExitStatusEnum::Std(ref es) => fmt::Display::fmt(es, f), + } + } +} + +/// Wraps a `std::process::Child` to coordinate state between `std` and +/// `wait_timeout`. +/// +/// This is necessary because the completion of a call to +/// `wait_timeout::ChildExt::wait_timeout` leaves the `Child` in an +/// inconsistent state, as it does not know the child has exited, and on Unix +/// may end up referencing another process. +/// +/// Documentation for this struct's methods is largely copied from the [Rust +/// std docs](https://doc.rust-lang.org/stable/std/process/struct.Child.html). +#[derive(Debug)] +pub struct ChildWrapper { + child: Child, + exit_status: Option<ExitStatusWrapper>, +} + +impl ChildWrapper { + pub(crate) fn new(child: Child) -> Self { + ChildWrapper { child, exit_status: None } + } + + /// Return a reference to the inner `std::process::Child`. + /// + /// Use care on the returned object, as it does not necessarily reference + /// the correct process unless you know the child process has not exited + /// and no wait calls have succeeded. + pub fn inner(&self) -> &Child { + &self.child + } + + /// Return a mutable reference to the inner `std::process::Child`. + /// + /// Use care on the returned object, as it does not necessarily reference + /// the correct process unless you know the child process has not exited + /// and no wait calls have succeeded. + pub fn inner_mut(&mut self) -> &mut Child { + &mut self.child + } + + /// Forces the child to exit. This is equivalent to sending a SIGKILL on + /// unix platforms. + /// + /// If the process has already been reaped by this handle, returns a + /// `NotFound` error. + pub fn kill(&mut self) -> io::Result<()> { + if self.exit_status.is_none() { + self.child.kill() + } else { + Err(io::Error::new(io::ErrorKind::NotFound, "Process already reaped")) + } + } + + /// Returns the OS-assigned processor identifier associated with this child. + /// + /// This succeeds even if the child has already been reaped. In this case, + /// the process id may reference no process at all or even an unrelated + /// process. + pub fn id(&self) -> u32 { + self.child.id() + } + + /// Waits for the child to exit completely, returning the status that it + /// exited with. This function will continue to have the same return value + /// after it has been called at least once. + /// + /// The stdin handle to the child process, if any, will be closed before + /// waiting. This helps avoid deadlock: it ensures that the child does not + /// block waiting for input from the parent, while the parent waits for the + /// child to exit. + /// + /// If the child process has already been reaped, returns its exit status + /// without blocking. + pub fn wait(&mut self) -> io::Result<ExitStatusWrapper> { + if let Some(status) = self.exit_status { + Ok(status) + } else { + let status = ExitStatusWrapper::std(self.child.wait()?); + self.exit_status = Some(status); + Ok(status) + } + } + + /// Attempts to collect the exit status of the child if it has already exited. + /// + /// This function will not block the calling thread and will only + /// advisorily check to see if the child process has exited or not. If the + /// child has exited then on Unix the process id is reaped. This function + /// is guaranteed to repeatedly return a successful exit status so long as + /// the child has already exited. + /// + /// If the child has exited, then `Ok(Some(status))` is returned. If the + /// exit status is not available at this time then `Ok(None)` is returned. + /// If an error occurs, then that error is returned. + pub fn try_wait(&mut self) -> io::Result<Option<ExitStatusWrapper>> { + if let Some(status) = self.exit_status { + Ok(Some(status)) + } else { + let status = self.child.try_wait()?.map(ExitStatusWrapper::std); + self.exit_status = status; + Ok(status) + } + } + + /// Simultaneously waits for the child to exit and collect all remaining + /// output on the stdout/stderr handles, returning an `Output` instance. + /// + /// The stdin handle to the child process, if any, will be closed before + /// waiting. This helps avoid deadlock: it ensures that the child does not + /// block waiting for input from the parent, while the parent waits for the + /// child to exit. + /// + /// By default, stdin, stdout and stderr are inherited from the parent. (In + /// the context of `rusty_fork`, they are by default redirected to a file.) + /// In order to capture the output into this `Result<Output>` it is + /// necessary to create new pipes between parent and child. Use + /// `stdout(Stdio::piped())` or `stderr(Stdio::piped())`, respectively. + /// + /// If the process has already been reaped, returns a `NotFound` error. + pub fn wait_with_output(self) -> io::Result<Output> { + if self.exit_status.is_some() { + return Err(io::Error::new( + io::ErrorKind::NotFound, "Process already reaped")); + } + + self.child.wait_with_output() + } + + /// Wait for the child to exit, but only up to the given maximum duration. + /// + /// If the process has already been reaped, returns its exit status + /// immediately. Otherwise, if the process terminates within the duration, + /// returns `Ok(Sone(..))`, or `Ok(None)` otherwise. + /// + /// This is only present if the "timeout" feature is enabled. + #[cfg(feature = "timeout")] + pub fn wait_timeout(&mut self, dur: Duration) + -> io::Result<Option<ExitStatusWrapper>> { + if let Some(status) = self.exit_status { + Ok(Some(status)) + } else { + let status = self.child.wait_timeout(dur)?.map(ExitStatusWrapper::std); + self.exit_status = status; + Ok(status) + } + } +} diff --git a/rusty-fork/src/cmdline.rs b/rusty-fork/src/cmdline.rs new file mode 100644 index 000000000..b03317396 --- /dev/null +++ b/rusty-fork/src/cmdline.rs @@ -0,0 +1,257 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Internal module which parses and modifies the rust test command-line. + +use std::env; + +use error::*; + +/// How a hyphen-prefixed argument passed to the parent process should be +/// handled when constructing the command-line for the child process. +#[derive(Clone, Copy, Debug, PartialEq)] +enum FlagType { + /// Pass the flag through unchanged. The boolean indicates whether the flag + /// is followed by an argument. + Pass(bool), + /// Drop the flag entirely. The boolean indicates whether the flag is + /// followed by an argument. + Drop(bool), + /// Indicates a known flag that should never be encountered. The string is + /// a human-readable error message. + Error(&'static str), +} + +/// Table of all flags in the 2018-02-23 nightly build. +/// +/// A number of these that affect output are dropped because we append our own +/// options. +static KNOWN_FLAGS: &[(&str, FlagType)] = &[ + ("--ignored", FlagType::Pass(false)), + ("--test", FlagType::Pass(false)), + ("--bench", FlagType::Pass(false)), + ("--list", FlagType::Error("Tests run but --list passed to process?")), + ("-h", FlagType::Error("Tests run but -h passed to process?")), + ("--help", FlagType::Error("Tests run but --help passed to process?")), + ("--logfile", FlagType::Drop(true)), + ("--nocapture", FlagType::Drop(true)), + ("--test-threads", FlagType::Drop(true)), + ("--skip", FlagType::Drop(true)), + ("-q", FlagType::Drop(false)), + ("--quiet", FlagType::Drop(false)), + ("--exact", FlagType::Drop(false)), + ("--color", FlagType::Pass(true)), + ("--format", FlagType::Drop(true)), + ("-Z", FlagType::Pass(true)), +]; + +fn look_up_flag_from_table(flag: &str) -> Option<FlagType> { + KNOWN_FLAGS.iter().cloned().filter(|&(name, _)| name == flag) + .map(|(_, typ)| typ).next() +} + +pub(crate) fn env_var_for_flag(flag: &str) -> String { + let mut var = "RUSTY_FORK_FLAG_".to_owned(); + var.push_str( + &flag.trim_left_matches('-').to_uppercase().replace('-', "_")); + var +} + +fn look_up_flag_from_env(flag: &str) -> Option<FlagType> { + env::var(&env_var_for_flag(flag)).ok().map( + |value| match &*value { + "pass" => FlagType::Pass(false), + "pass-arg" => FlagType::Pass(true), + "drop" => FlagType::Drop(false), + "drop-arg" => FlagType::Drop(true), + _ => FlagType::Error("incorrect flag type in environment; \ + must be one of `pass`, `pass-arg`, \ + `drop`, `drop-arg`"), + }) +} + +fn look_up_flag(flag: &str) -> Option<FlagType> { + look_up_flag_from_table(flag).or_else(|| look_up_flag_from_env(flag)) +} + +fn look_up_flag_or_err(flag: &str) -> Result<(bool, bool)> { + match look_up_flag(flag) { + None => + Err(Error::UnknownFlag(flag.to_owned())), + Some(FlagType::Error(message)) => + Err(Error::DisallowedFlag(flag.to_owned(), message.to_owned())), + Some(FlagType::Pass(has_arg)) => Ok((true, has_arg)), + Some(FlagType::Drop(has_arg)) => Ok((false, has_arg)), + } +} + +/// Parse the full command line as would be given to the Rust test harness, and +/// strip out any flags that should be dropped as well as all filters. The +/// resulting argument list is also guaranteed to not have "--", so that new +/// flags can be appended. +/// +/// The zeroth argument (the command name) is also dropped. +pub(crate) fn strip_cmdline<A : Iterator<Item = String>> + (args: A) -> Result<Vec<String>> +{ + #[derive(Clone, Copy)] + enum State { + Ground, PassingArg, DroppingArg, + } + + // Start in DroppingArg since we need to drop the exec name. + let mut state = State::DroppingArg; + let mut ret = Vec::new(); + + for arg in args { + match state { + State::DroppingArg => { + state = State::Ground; + }, + + State::PassingArg => { + ret.push(arg); + state = State::Ground; + }, + + State::Ground => { + if &arg == "--" { + // Everything after this point is a filter + break; + } else if &arg == "-" { + // "-" by itself is interpreted as a filter + continue; + } else if arg.starts_with("--") { + let (pass, has_arg) = look_up_flag_or_err( + arg.split('=').next().expect("split returned empty"))?; + // If there's an = sign, the physical argument also + // contains the associated value, so don't pay attention to + // has_arg. + let has_arg = has_arg && !arg.contains('='); + if pass { + ret.push(arg); + if has_arg { + state = State::PassingArg; + } + } else if has_arg { + state = State::DroppingArg; + } + } else if arg.starts_with("-") { + let mut chars = arg.chars(); + let mut to_pass = "-".to_owned(); + + chars.next(); // skip initial '-' + while let Some(flag_ch) = chars.next() { + let flag = format!("-{}", flag_ch); + let (pass, has_arg) = look_up_flag_or_err(&flag)?; + if pass { + to_pass.push(flag_ch); + if has_arg { + if chars.clone().next().is_some() { + // Arg is attached to this one + to_pass.extend(chars); + } else { + // Arg is separate + state = State::PassingArg; + } + break; + } + } else if has_arg { + if chars.clone().next().is_none() { + // Arg is separate + state = State::DroppingArg; + } + break; + } + } + + if "-" != &to_pass { + ret.push(to_pass); + } + } else { + // It's a filter, drop + } + }, + } + } + + Ok(ret) +} + +/// Extra arguments to add after the stripped command line when running a +/// single test. +pub(crate) static RUN_TEST_ARGS: &[&str] = &[ + // --quiet because the test runner output is redundant + "--quiet", + // Single threaded because we get parallelism from the parent process + "--test-threads", "1", + // Disable capture since we want the output to be captured by the *parent* + // process. + "--nocapture", + // Match our test filter exactly so we run exactly one test + "--exact", + // Ensure everything else is interpreted as filters + "--", +]; + +#[cfg(test)] +mod test { + use super::*; + + fn strip(cmdline: &str) -> Result<String> { + strip_cmdline(cmdline.split_whitespace().map(|s| s.to_owned())) + .map(|strs| strs.join(" ")) + } + + #[test] + fn test_strip() { + assert_eq!("", &strip("test").unwrap()); + assert_eq!("--ignored", &strip("test --ignored").unwrap()); + assert_eq!("", &strip("test --quiet").unwrap()); + assert_eq!("", &strip("test -q").unwrap()); + assert_eq!("", &strip("test -qq").unwrap()); + assert_eq!("", &strip("test --test-threads 42").unwrap()); + assert_eq!("-Z unstable-options", + &strip("test -Z unstable-options").unwrap()); + assert_eq!("-Zunstable-options", + &strip("test -Zunstable-options").unwrap()); + assert_eq!("-Zunstable-options", + &strip("test -qZunstable-options").unwrap()); + assert_eq!("--color auto", &strip("test --color auto").unwrap()); + assert_eq!("--color=auto", &strip("test --color=auto").unwrap()); + assert_eq!("", &strip("test filter filter2").unwrap()); + assert_eq!("", &strip("test -- --color=auto").unwrap()); + + match strip("test --plugh").unwrap_err() { + Error::UnknownFlag(ref flag) => assert_eq!("--plugh", flag), + e => panic!("Unexpected error: {}", e), + } + match strip("test --help").unwrap_err() { + Error::DisallowedFlag(ref flag, _) => assert_eq!("--help", flag), + e => panic!("Unexpected error: {}", e), + } + } + + // Subprocess so we can change the environment without affecting other + // tests + rusty_fork_test! { + #[test] + fn define_args_via_env() { + env::set_var("RUSTY_FORK_FLAG_X", "pass"); + env::set_var("RUSTY_FORK_FLAG_FOO", "pass-arg"); + env::set_var("RUSTY_FORK_FLAG_BAR", "drop"); + env::set_var("RUSTY_FORK_FLAG_BAZ", "drop-arg"); + + assert_eq!("-X", &strip("test -X foo").unwrap()); + assert_eq!("--foo bar", &strip("test --foo bar").unwrap()); + assert_eq!("", &strip("test --bar").unwrap()); + assert_eq!("", &strip("test --baz --notaflag").unwrap()); + } + } +} diff --git a/rusty-fork/src/error.rs b/rusty-fork/src/error.rs new file mode 100644 index 000000000..021d06132 --- /dev/null +++ b/rusty-fork/src/error.rs @@ -0,0 +1,62 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::io; + +use cmdline; + +quick_error! { + /// Enum for errors produced by the rusty-fork crate. + #[derive(Debug)] + pub enum Error { + /// An unknown flag was encountered when examining the current + /// process's argument list. + /// + /// The string is the flag that was encountered. + UnknownFlag(flag: String) { + display("The flag '{:?}' was passed to the Rust test \ + process, but rusty-fork does not know how to \ + handle it.\n\ + If you are using the standard Rust \ + test harness and have the latest version of the \ + rusty-fork crate, please report a bug to\n\ + \thttps://github.com/AltSysrq/rusty-fork/issues\n\ + In the mean time, you can tell rusty-fork how to \ + handle this flag by setting the environment variable \ + `{}` to one of the following values:\n\ + \tpass - Pass the flag (alone) to the child process\n\ + \tpass-arg - Pass the flag and its following argument \ + to the child process.\n\ + \tdrop - Don't pass the flag to the child process.\n\ + \tdrop-arg - Don't pass the flag or its following \ + argument to the child process.", + flag, cmdline::env_var_for_flag(&flag)) + } + /// A flag was encountered when examining the current process's + /// argument list which is known but cannot be handled in any sensible + /// way. + /// + /// The strings are the flag encountered and a human-readable message + /// about why the flag could not be handled. + DisallowedFlag(flag: String, message: String) { + display("The flag '{:?}' was passed to the Rust test \ + process, but rusty-fork cannot handle it; \ + reason: {}", flag, message) + } + /// Spawning a subprocess failed. + SpawnError(err: io::Error) { + from() + cause(err) + display("Spawn failed: {}", err) + } + } +} + +/// General `Result` type for rusty-fork. +pub type Result<T> = ::std::result::Result<T, Error>; diff --git a/rusty-fork/src/file-preamble b/rusty-fork/src/file-preamble new file mode 100644 index 000000000..f7227ae45 --- /dev/null +++ b/rusty-fork/src/file-preamble @@ -0,0 +1,8 @@ +//- +// Copyright 2018 +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. diff --git a/rusty-fork/src/fork.rs b/rusty-fork/src/fork.rs new file mode 100644 index 000000000..a8b0ea92a --- /dev/null +++ b/rusty-fork/src/fork.rs @@ -0,0 +1,317 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fs; +use std::env; +use std::hash::{Hash, Hasher}; +use std::io::{self, BufRead, Seek}; +use std::panic; +use std::process; + +use fnv; +use tempfile; + +use cmdline; +use error::*; +use child_wrapper::ChildWrapper; + +const OCCURS_ENV: &str = "RUSTY_FORK_OCCURS"; +const OCCURS_TERM_LENGTH: usize = 17; /* ':' plus 16 hexits */ + +/// Simulate a process fork. +/// +/// The function documentation here only lists information unique to calling it +/// directly; please see the crate documentation for more details on how the +/// forking process works. +/// +/// Since this is not a true process fork, the calling code must be structured +/// to ensure that the child process, upon starting from the same entry point, +/// also reaches this same `fork()` call. Recursive forks are supported; the +/// child branch is taken from all child processes of the fork even if it is +/// not directly the child of a particular branch. However, encountering the +/// same fork point more than once in a single execution sequence of a child +/// process is not (e.g., putting this call in a recursive function) and +/// results in unspecified behaviour. +/// +/// The child's output is buffered into an anonymous temporary file. Before +/// this call returns, this output is copied to the parent's standard output +/// (passing through the redirect mechanism Rust test uses). +/// +/// `test_name` must exactly match the full path of the test function being +/// run. +/// +/// `fork_id` is a unique identifier identifying this particular fork location. +/// This *must* be stable across processes of the same executable; pointers are +/// not suitable stable, and string constants may not be suitably unique. The +/// [`rusty_fork_id!()`](macro.rusty_fork_id.html) macro is the recommended way +/// to supply this parameter. +/// +/// If this is the parent process, `in_parent` is invoked, and the return value +/// becomes the return value from this function. The callback is passed a +/// handle to the file which receives the child's output. If is the callee's +/// responsibility to wait for the child to exit. If this is the child process, +/// `in_child` is invoked, and when the callback returns, the child process +/// exits. +/// +/// If `in_parent` returns or panics before the child process has terminated, +/// the child process is killed. +/// +/// If `in_child` panics, the child process exits with a failure code +/// immediately rather than let the panic propagate out of the `fork()` call. +/// +/// `process_modifier` is invoked on the `std::process::Command` immediately +/// before spawning the new process. The callee may modify the process +/// parameters if desired, but should not do anything that would modify or +/// remove any environment variables beginning with `RUSTY_FORK_`. +/// +/// ## Panics +/// +/// Panics if the environment indicates that there are already at least 16 +/// levels of fork nesting. +/// +/// Panics if `std::env::current_exe()` fails determine the path to the current +/// executable. +/// +/// Panics if any argument to the current process is not valid UTF-8. +pub fn fork<ID, MODIFIER, PARENT, CHILD, R>( + test_name: &str, + fork_id: ID, + process_modifier: MODIFIER, + in_parent: PARENT, + in_child: CHILD) -> Result<R> +where + ID : Hash, + MODIFIER : FnOnce (&mut process::Command), + PARENT : FnOnce (&mut ChildWrapper, &mut fs::File) -> R, + CHILD : FnOnce () +{ + let fork_id = id_str(fork_id); + + // Erase the generics so we don't instantiate the actual implementation for + // every single test + let mut return_value = None; + let mut process_modifier = Some(process_modifier); + let mut in_parent = Some(in_parent); + let mut in_child = Some(in_child); + + fork_impl(test_name, fork_id, + &mut |cmd| process_modifier.take().unwrap()(cmd), + &mut |child, file| return_value = Some( + in_parent.take().unwrap()(child, file)), + &mut || in_child.take().unwrap()()) + .map(|_| return_value.unwrap()) +} + +fn fork_impl(test_name: &str, fork_id: String, + process_modifier: &mut FnMut (&mut process::Command), + in_parent: &mut FnMut (&mut ChildWrapper, &mut fs::File), + in_child: &mut FnMut ()) -> Result<()> { + let mut occurs = env::var(OCCURS_ENV).unwrap_or_else(|_| String::new()); + if occurs.contains(&fork_id) { + match panic::catch_unwind(panic::AssertUnwindSafe(in_child)) { + Ok(_) => process::exit(0), + // Assume that the default panic handler already printed something + // + // We don't use process::abort() since it produces core dumps on + // some systems and isn't something more special than a normal + // panic. + Err(_) => process::exit(70 /* EX_SOFTWARE */), + } + } else { + // Prevent misconfiguration creating a fork bomb + if occurs.len() > 16 * OCCURS_TERM_LENGTH { + panic!("rusty-fork: Not forking due to >=16 levels of recursion"); + } + + let file = tempfile::tempfile()?; + + struct KillOnDrop(ChildWrapper, fs::File); + impl Drop for KillOnDrop { + fn drop(&mut self) { + // Kill the child if it hasn't exited yet + let _ = self.0.kill(); + + // Copy the child's output to our own + // Awkwardly, `print!()` and `println!()` are our only gateway + // to putting things in the captured output. Generally test + // output really is text, so work on that assumption and read + // line-by-line, converting lossily into UTF-8 so we can + // println!() it. + let _ = self.1.seek(io::SeekFrom::Start(0)); + + let mut buf = Vec::new(); + let mut br = io::BufReader::new(&mut self.1); + loop { + // We can't use read_line() or lines() since they break if + // there's any non-UTF-8 output at all. \n occurs at the + // end of the line endings on all major platforms, so we + // can just use that as a delimiter. + if br.read_until(b'\n', &mut buf).is_err() { + break; + } + if buf.is_empty() { + break; + } + + // not println!() because we already have a line ending + // from above. + print!("{}", String::from_utf8_lossy(&buf)); + buf.clear(); + } + } + } + + occurs.push_str(&fork_id); + let mut command = + process::Command::new( + env::current_exe() + .expect("current_exe() failed, cannot fork")); + command + .args(cmdline::strip_cmdline(env::args())?) + .args(cmdline::RUN_TEST_ARGS) + .arg(test_name) + .env(OCCURS_ENV, &occurs) + .stdin(process::Stdio::null()) + .stdout(file.try_clone()?) + .stderr(file.try_clone()?); + process_modifier(&mut command); + + let mut child = command.spawn().map(ChildWrapper::new) + .map(|p| KillOnDrop(p, file))?; + + let ret = in_parent(&mut child.0, &mut child.1); + + Ok(ret) + } +} + +fn id_str<ID : Hash>(id: ID) -> String { + let mut hasher = fnv::FnvHasher::default(); + id.hash(&mut hasher); + + return format!(":{:016X}", hasher.finish()); +} + +#[cfg(test)] +mod test { + use std::io::Read; + use std::thread; + + use super::*; + + fn sleep(ms: u64) { + thread::sleep(::std::time::Duration::from_millis(ms)); + } + + fn capturing_output(cmd: &mut process::Command) { + // Only actually capture stdout since we can't use + // wait_with_output() since it for some reason consumes the `Child`. + cmd.stdout(process::Stdio::piped()) + .stderr(process::Stdio::inherit()); + } + + fn inherit_output(cmd: &mut process::Command) { + cmd.stdout(process::Stdio::inherit()) + .stderr(process::Stdio::inherit()); + } + + fn wait_for_child_output(child: &mut ChildWrapper, + _file: &mut fs::File) -> String { + let mut output = String::new(); + child.inner_mut().stdout.as_mut().unwrap() + .read_to_string(&mut output).unwrap(); + assert!(child.wait().unwrap().success()); + output + } + + fn wait_for_child(child: &mut ChildWrapper, + _file: &mut fs::File) { + assert!(child.wait().unwrap().success()); + } + + #[test] + fn fork_basically_works() { + let status = + fork("fork::test::fork_basically_works", rusty_fork_id!(), + |_| (), + |child, _| child.wait().unwrap(), + || println!("hello from child")).unwrap(); + assert!(status.success()); + } + + #[test] + fn child_output_captured_and_repeated() { + let output = fork( + "fork::test::child_output_captured_and_repeated", + rusty_fork_id!(), + capturing_output, wait_for_child_output, + || fork( + "fork::test::child_output_captured_and_repeated", + rusty_fork_id!(), + |_| (), wait_for_child, + || println!("hello from child")).unwrap()) + .unwrap(); + assert!(output.contains("hello from child")); + } + + #[test] + fn child_killed_if_parent_exits_first() { + let output = fork( + "fork::test::child_killed_if_parent_exits_first", + rusty_fork_id!(), + capturing_output, wait_for_child_output, + || fork( + "fork::test::child_killed_if_parent_exits_first", + rusty_fork_id!(), + inherit_output, |_, _| (), + || { + sleep(1_000); + println!("hello from child"); + }).unwrap()).unwrap(); + + sleep(2_000); + assert!(!output.contains("hello from child"), + "Had unexpected output:\n{}", output); + } + + #[test] + fn child_killed_if_parent_panics_first() { + let output = fork( + "fork::test::child_killed_if_parent_panics_first", + rusty_fork_id!(), + capturing_output, wait_for_child_output, + || { + assert!( + panic::catch_unwind(panic::AssertUnwindSafe(|| fork( + "fork::test::child_killed_if_parent_panics_first", + rusty_fork_id!(), + inherit_output, + |_, _| panic!("testing a panic, nothing to see here"), + || { + sleep(1_000); + println!("hello from child"); + }).unwrap())).is_err()); + }).unwrap(); + + sleep(2_000); + assert!(!output.contains("hello from child"), + "Had unexpected output:\n{}", output); + } + + #[test] + fn child_aborted_if_panics() { + let status = fork( + "fork::test::child_aborted_if_panics", + rusty_fork_id!(), + |_| (), + |child, _| child.wait().unwrap(), + || panic!("testing a panic, nothing to see here")).unwrap(); + assert_eq!(70, status.code().unwrap()); + } +} diff --git a/rusty-fork/src/fork_test.rs b/rusty-fork/src/fork_test.rs new file mode 100644 index 000000000..c95e8cc2c --- /dev/null +++ b/rusty-fork/src/fork_test.rs @@ -0,0 +1,207 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for the `rusty_fork_test!` macro and similar. +//! +//! Some functionality in this module is useful to other implementors and +//! unlikely to change. This subset is documented and considered stable. + +use std::process::Command; + +use child_wrapper::ChildWrapper; + +/// Run Rust tests in subprocesses. +/// +/// The basic usage is to simply put this macro around your `#[test]` +/// functions. +/// +/// ``` +/// #[macro_use] extern crate rusty_fork; +/// +/// rusty_fork_test! { +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// assert_eq!(2, 1 + 1); +/// } +/// +/// // more tests... +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +/// +/// Each test will be run in its own process. If the subprocess exits +/// unsuccessfully for any reason, including due to signals, the test fails. +/// +/// It is also possible to specify a timeout which is applied to all tests in +/// the block, like so: +/// +/// ``` +/// #[macro_use] extern crate rusty_fork; +/// +/// rusty_fork_test! { +/// #![rusty_fork(timeout_ms = 1000)] +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// do_some_expensive_computation(); +/// } +/// +/// // more tests... +/// } +/// # fn do_some_expensive_computation() { } +/// # fn main() { my_test(); } +/// ``` +/// +/// If any individual test takes more than the given timeout, the child is +/// terminated and the test panics. +/// +/// Using the timeout feature requires the `timeout` feature for this crate to +/// be enabled (which it is by default). +#[macro_export] +macro_rules! rusty_fork_test { + (#![rusty_fork(timeout_ms = $timeout:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident() $body:block + )*) => { $( + $(#[$meta])* + fn $test_name() { + // Eagerly convert everything to function pointers so that all + // tests use the same instantiation of `fork`. + fn body_fn() $body + let body: fn () = body_fn; + + fn supervise_fn(child: &mut $crate::ChildWrapper, + _file: &mut ::std::fs::File) { + $crate::fork_test::supervise_child(child, $timeout) + } + let supervise: + fn (&mut $crate::ChildWrapper, &mut ::std::fs::File) = + supervise_fn; + + $crate::fork( + rusty_fork_test_name!($test_name), + rusty_fork_id!(), + $crate::fork_test::no_configure_child, + supervise, body).expect("forking test failed") + } + )* }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident() $body:block + )*) => { + rusty_fork_test! { + #![rusty_fork(timeout_ms = 0)] + + $($(#[$meta])* fn $test_name() $body)* + } + }; +} + +/// Given the unqualified name of a `#[test]` function, produce a +/// `&'static str` corresponding to the name of the test as filtered by the +/// standard test harness. +/// +/// This is internally used by `rusty_fork_test!` but is made available since +/// other test wrapping implementations will likely need it too. +/// +/// This does not currently produce a constant expression. +#[macro_export] +macro_rules! rusty_fork_test_name { + ($function_name:ident) => { + $crate::fork_test::fix_module_path( + concat!(module_path!(), "::", stringify!($function_name))) + } +} + +#[allow(missing_docs)] +#[doc(hidden)] +pub fn supervise_child(child: &mut ChildWrapper, timeout_ms: u64) { + if timeout_ms > 0 { + wait_timeout(child, timeout_ms) + } else { + let status = child.wait().expect("failed to wait for child"); + assert!(status.success(), + "child exited unsuccessfully with {}", status); + } +} + +#[allow(missing_docs)] +#[doc(hidden)] +pub fn no_configure_child(_child: &mut Command) { } + +/// Transform a string representing a qualified path as generated via +/// `module_path!()` into a qualified path as expected by the standard Rust +/// test harness. +pub fn fix_module_path(path: &str) -> &str { + path.find("::").map(|ix| &path[ix+2..]).unwrap_or(path) +} + +#[cfg(feature = "timeout")] +fn wait_timeout(child: &mut ChildWrapper, timeout_ms: u64) { + use std::time::Duration; + + let timeout = Duration::from_millis(timeout_ms); + let status = child.wait_timeout(timeout).expect("failed to wait for child"); + if let Some(status) = status { + assert!(status.success(), + "child exited unsuccessfully with {}", status); + } else { + panic!("child process exceeded {} ms timeout", timeout_ms); + } +} + +#[cfg(not(feature = "timeout"))] +fn wait_timeout(_: &mut ChildWrapper, _: u64) { + panic!("Using the timeout feature of rusty_fork_test! requires \ + enabling the `timeout` feature on the rusty-fork crate."); +} + +#[cfg(test)] +mod test { + rusty_fork_test! { + #[test] + fn trivial() { } + + #[test] + #[should_panic] + fn panicking_child() { + panic!("just testing a panic, nothing to see here"); + } + + #[test] + #[should_panic] + fn aborting_child() { + ::std::process::abort(); + } + } + + rusty_fork_test! { + #![rusty_fork(timeout_ms = 1000)] + + #[test] + #[cfg(feature = "timeout")] + fn timeout_passes() { } + + #[test] + #[should_panic] + #[cfg(feature = "timeout")] + fn timeout_fails() { + println!("hello from child"); + ::std::thread::sleep( + ::std::time::Duration::from_millis(10000)); + println!("goodbye from child"); + } + } +} diff --git a/rusty-fork/src/lib.rs b/rusty-fork/src/lib.rs new file mode 100644 index 000000000..181072baa --- /dev/null +++ b/rusty-fork/src/lib.rs @@ -0,0 +1,137 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(missing_docs, unsafe_code)] + +//! Rusty-fork provides a way to "fork" unit tests into separate processes. +//! +//! There are a number of reasons to want to run some tests in isolated +//! processes: +//! +//! - When tests share a process, if any test causes the process to abort, +//! segfault, overflow the stack, etc., the entire test runner process dies. If +//! the test is in a subprocess, only the subprocess dies and the test runner +//! simply fails the test. +//! +//! - Isolating a test to a subprocess makes it possible to add a timeout to +//! the test and forcibly terminate it and produce a normal test failure. +//! +//! - Tests which need to interact with some inherently global property, such +//! as the current working directory, can do so without interfering with other +//! tests. +//! +//! This crate itself provides two things: +//! +//! - The [`rusty_fork_test!`](macro.rusty_fork_test.html) macro, which is a +//! simple way to wrap standard Rust tests to be run in subprocesses with +//! optional timeouts. +//! +//! - The [`fork`](fn.fork.html) function which can be used as a building block +//! to make other types of process isolation strategies. +//! +//! ## Quick Start +//! +//! If you just want to run normal Rust tests in isolated processes, getting +//! started is pretty quick. +//! +//! In `Cargo.toml`, add +//! +//! ```toml +//! [dev-dependencies] +//! rusty-fork = "0.2.1" +//! ``` +//! +//! and to your crate root add +//! +//! ```rust,ignore +//! #[macro_use] extern crate rusty_fork; +//! ``` +//! +//! Then, you can simply wrap any test(s) to be isolated with the +//! [`rusty_fork_test!`](macro.rusty_fork_test.html) macro. +//! +//! ```rust +//! #[macro_use] extern crate rusty_fork; +//! +//! rusty_fork_test! { +//! # /* NOREADME +//! #[test] +//! # NOREADME */ +//! fn my_test() { +//! assert_eq!(2, 1 + 1); +//! } +//! +//! // more tests... +//! } +//! # // NOREADME +//! # fn main() { my_test(); } // NOREADME +//! ``` +//! +//! For more advanced usage, have a look at the [`fork`](fn.fork.html) +//! function. +//! +//! ## How rusty-fork works +//! +//! Unix-style process forking isn't really viable within the standard Rust +//! test environment for a number of reasons. +//! +//! - While true process forking can be done on Windows, it's neither fast nor +//! reliable. +//! +//! - The Rust test environment is multi-threaded, so attempting to do anything +//! non-trivial after a process fork would result in undefined behaviour. +//! +//! Rusty-fork instead works by _spawning_ a fresh instance of the current +//! process, after adjusting the command-line to ensure that only the desired +//! test is entered. Some additional coordination establishes the parent/child +//! branches and (not quite seamlessly) integrates the child's output with the +//! test output capture system. +//! +//! Coordination between the processes is performed via environment variables, +//! since there is otherwise no way to pass parameters to a test. +//! +//! Since it needs to spawn new copies of the test runner executable, +//! rusty-fork does need to know about the meaning of every flag passed by the +//! user. If any unknown flags are encountered, forking will fail. Please do +//! not hesitate to file +//! [issues](https://github.com/AltSysrq/rusty-fork/issues) if rusty-fork fails +//! to recognise any valid flags passed to the test runner. +//! +//! It is possible to inform rusty-fork of new flags without patching by +//! setting environment variables. For example, if a new `--frob-widgets` flag +//! were added to the test runner, you could set `RUSTY_FORK_FLAG_FROB_WIDGETS` +//! to one of the following: +//! +//! - `pass` — Pass the flag (just the flag) to the child process +//! - `pass-arg` — Pass the flag and its following argument to the child process +//! - `drop` — Don't pass the flag to the child process +//! - `drop-arg` — Don't pass the flag to the child process, and ignore whatever +//! argument follows. +//! +//! In general, arguments that affect which tests are run should be dropped, +//! and others should be passed. +//! +//! <!-- ENDREADME --> + +extern crate fnv; +#[macro_use] extern crate quick_error; +extern crate tempfile; +#[cfg(feature = "timeout")] extern crate wait_timeout; + +#[macro_use] mod sugar; +#[macro_use] pub mod fork_test; +mod error; +mod cmdline; +mod fork; +mod child_wrapper; + +pub use sugar::RustyForkId; +pub use error::{Error, Result}; +pub use fork::fork; +pub use child_wrapper::{ChildWrapper, ExitStatusWrapper}; diff --git a/rusty-fork/src/sugar.rs b/rusty-fork/src/sugar.rs new file mode 100644 index 000000000..0e4f9eb1e --- /dev/null +++ b/rusty-fork/src/sugar.rs @@ -0,0 +1,42 @@ +//- +// Copyright 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Produce a hashable identifier unique to the particular macro invocation +/// which is stable across processes of the same executable. +/// +/// This is usually the best thing to pass for the `fork_id` argument of +/// [`fork`](fn.fork.html). +/// +/// The type of the expression this macro expands to is +/// [`RustyForkId`](struct.RustyForkId.html). +#[macro_export] +macro_rules! rusty_fork_id { () => { { + struct _RustyForkId; + $crate::RustyForkId::of(::std::any::TypeId::of::<_RustyForkId>()) +} } } + +/// The type of the value produced by +/// [`rusty_fork_id!`](macro.rusty_fork_id.html). +#[derive(Clone, Hash, PartialEq, Debug)] +pub struct RustyForkId(::std::any::TypeId); +impl RustyForkId { + #[allow(missing_docs)] + #[doc(hidden)] + pub fn of(id: ::std::any::TypeId) -> Self { + RustyForkId(id) + } +} + +#[cfg(test)] +mod test { + #[test] + fn ids_are_actually_distinct() { + assert_ne!(rusty_fork_id!(), rusty_fork_id!()); + } +} diff --git a/ryu/.cargo-checksum.json b/ryu/.cargo-checksum.json new file mode 100644 index 000000000..e9d59d2a9 --- /dev/null +++ b/ryu/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"} \ No newline at end of file diff --git a/ryu/Cargo.toml b/ryu/Cargo.toml new file mode 100644 index 000000000..82070c27d --- /dev/null +++ b/ryu/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "ryu" +version = "0.2.8" +authors = ["David Tolnay <dtolnay@gmail.com>"] +build = "build.rs" +description = "Fast floating point to string conversion" +documentation = "https://docs.rs/ryu" +readme = "README.md" +license = "Apache-2.0 OR BSL-1.0" +repository = "https://github.com/dtolnay/ryu" +[dependencies.no-panic] +version = "0.1" +optional = true +[dev-dependencies.num_cpus] +version = "1.8" + +[dev-dependencies.rand] +version = "0.5" + +[features] +small = [] +[badges.travis-ci] +repository = "dtolnay/ryu" diff --git a/ryu/LICENSE-APACHE b/ryu/LICENSE-APACHE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/ryu/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ryu/LICENSE-BOOST b/ryu/LICENSE-BOOST new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/ryu/LICENSE-BOOST @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/ryu/README.md b/ryu/README.md new file mode 100644 index 000000000..179674460 --- /dev/null +++ b/ryu/README.md @@ -0,0 +1,108 @@ +# RyÅ« + +[![Build Status](https://api.travis-ci.org/dtolnay/ryu.svg?branch=master)](https://travis-ci.org/dtolnay/ryu) +[![Latest Version](https://img.shields.io/crates/v/ryu.svg)](https://crates.io/crates/ryu) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/ryu) +[![Rustc Version 1.15+](https://img.shields.io/badge/rustc-1.15+-lightgray.svg)](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html) + +Pure Rust implementation of RyÅ«, an algorithm to quickly convert floating point +numbers to decimal strings. + +The PLDI'18 paper [*RyÅ«: fast float-to-string conversion*][paper] by Ulf Adams +includes a complete correctness proof of the algorithm. The paper is available +under the creative commons CC-BY-SA license. + +This Rust implementation is a line-by-line port of Ulf Adams' implementation in +C, [https://github.com/ulfjack/ryu][upstream]. The `ryu::raw` module exposes +exactly the API and formatting of the C implementation as unsafe pure Rust +functions. There is additionally a safe API as demonstrated in the example code +below. The safe API uses the same underlying RyÅ« algorithm but diverges from the +formatting of the C implementation to produce more human-readable output, for +example `0.3` rather than `3E-1`. + +*Requirements: this crate supports any compiler version back to rustc 1.15; it +uses nothing from the Rust standard library so is usable from no_std crates.* + +[paper]: https://dl.acm.org/citation.cfm?id=3192369 +[upstream]: https://github.com/ulfjack/ryu/tree/795c8b57aa454c723194bbea8e4bf2ccd28e865f + +```toml +[dependencies] +ryu = "0.2" +``` + +## Example + +```rust +fn main() { + let mut buffer = ryu::Buffer::new(); + let printed = buffer.format(1.234); + assert_eq!(printed, "1.234"); +} +``` + +## Performance + +You can run upstream's benchmarks with: + +```console +$ git clone https://github.com/ulfjack/ryu c-ryu +$ cd c-ryu +$ bazel run -c opt //ryu/benchmark +``` + +And the same benchmark against our implementation with: + +```console +$ git clone https://github.com/dtolnay/ryu rust-ryu +$ cd rust-ryu +$ cargo run --example upstream_benchmark --release +``` + +These benchmarks measure the average time to print a 32-bit float and average +time to print a 64-bit float, where the inputs are distributed as uniform random +bit patterns 32 and 64 bits wide. + +The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API +all perform the same, taking around 21 nanoseconds to format a 32-bit float and +31 nanoseconds to format a 64-bit float. + +There is also a Rust-specific benchmark comparing this implementation to the +standard library which you can run with: + +```console +$ cargo bench +``` + +The benchmark shows Ryu approximately 4-10x faster than the standard library +across a range of f32 and f64 inputs. Measurements are in nanoseconds per +iteration; smaller is better. + +| type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 28ns | 23ns | 22ns | +| STD | 40ns | 106ns | 128ns | 110ns | + +| type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +|:--------:|:----:|:------:|:-----------------:|:--------:| +| RYU | 3ns | 50ns | 35ns | 32ns | +| STD | 39ns | 105ns | 128ns | 202ns | + +## Formatting + +This library tends to produce more human-readable output than the standard +library's to\_string, which never uses scientific notation. Here are two +examples: + +- *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000 +- *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123 + +Both libraries print short decimals such as 0.0000123 without scientific +notation. + +## License + +Licensed under either of the following at your option. + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- Boost Software License 1.0 ([LICENSE-BOOST](LICENSE-BOOST) or https://www.boost.org/LICENSE_1_0.txt) diff --git a/ryu/benches/bench.rs b/ryu/benches/bench.rs new file mode 100644 index 000000000..f30f2888a --- /dev/null +++ b/ryu/benches/bench.rs @@ -0,0 +1,59 @@ +// cargo bench + +#![feature(test)] + +extern crate ryu; +extern crate test; + +macro_rules! benches { + ($($name:ident($value:expr),)*) => { + mod bench_ryu { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use ryu; + + let mut buf = ryu::Buffer::new(); + + b.iter(move || { + let value = black_box($value); + let formatted = buf.format(value); + black_box(formatted); + }); + } + )* + } + + mod bench_std_fmt { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use std::io::Write; + + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + let value = black_box($value); + write!(&mut buf, "{}", value).unwrap(); + black_box(buf.as_slice()); + }); + } + )* + } + } +} + +benches!( + bench_0_f64(0f64), + bench_short_f64(0.1234f64), + bench_e_f64(2.718281828459045f64), + bench_max_f64(::std::f64::MAX), + + bench_0_f32(0f32), + bench_short_f32(0.1234f32), + bench_e_f32(2.718281828459045f32), + bench_max_f32(::std::f32::MAX), +); diff --git a/ryu/build.rs b/ryu/build.rs new file mode 100644 index 000000000..b1ea2f159 --- /dev/null +++ b/ryu/build.rs @@ -0,0 +1,60 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // 128-bit integers stabilized in Rust 1.26: + // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html + // + // Disabled on Emscripten targets as Emscripten doesn't + // currently support integers larger than 64 bits. + if minor >= 26 && !emscripten { + println!("cargo:rustc-cfg=integer128"); + } + + // #[must_use] on functions stabilized in Rust 1.27: + // https://blog.rust-lang.org/2018/06/21/Rust-1.27.html + if minor >= 27 { + println!("cargo:rustc-cfg=must_use_return"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/ryu/examples/upstream_benchmark.rs b/ryu/examples/upstream_benchmark.rs new file mode 100644 index 000000000..f97730d6c --- /dev/null +++ b/ryu/examples/upstream_benchmark.rs @@ -0,0 +1,88 @@ +// cargo run --example upstream_benchmark --release + +extern crate rand; +extern crate ryu; + +use rand::{Rng, SeedableRng}; + +const SAMPLES: usize = 10000; +const ITERATIONS: usize = 1000; + +struct MeanAndVariance { + n: i64, + mean: f64, + m2: f64, +} + +impl MeanAndVariance { + fn new() -> Self { + MeanAndVariance { + n: 0, + mean: 0.0, + m2: 0.0, + } + } + + fn update(&mut self, x: f64) { + self.n += 1; + let d = x - self.mean; + self.mean += d / self.n as f64; + let d2 = x - self.mean; + self.m2 += d * d2; + } + + fn variance(&self) -> f64 { + self.m2 / (self.n - 1) as f64 + } + + fn stddev(&self) -> f64 { + self.variance().sqrt() + } +} + +macro_rules! benchmark { + ($name:ident, $ty:ident) => { + fn $name() -> usize { + let mut rng = rand::prng::XorShiftRng::from_seed([123u8; 16]); + let mut mv = MeanAndVariance::new(); + let mut throwaway = 0; + for _ in 0..SAMPLES { + let f = loop { + let f = $ty::from_bits(rng.gen()); + if f.is_finite() { + break f; + } + }; + + let t1 = std::time::SystemTime::now(); + for _ in 0..ITERATIONS { + throwaway += ryu::Buffer::new().format(f).len(); + } + let duration = t1.elapsed().unwrap(); + let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; + mv.update(nanos as f64 / ITERATIONS as f64); + } + println!( + "{:12} {:8.3} {:8.3}", + concat!(stringify!($name), ":"), + mv.mean, + mv.stddev(), + ); + throwaway + } + }; +} + +benchmark!(pretty32, f32); +benchmark!(pretty64, f64); + +fn main() { + println!("{:>20}{:>9}", "Average", "Stddev"); + let mut throwaway = 0; + throwaway += pretty32(); + throwaway += pretty64(); + if std::env::var_os("ryu-benchmark").is_some() { + // Prevent the compiler from optimizing the code away. + println!("{}", throwaway); + } +} diff --git a/ryu/src/buffer/mod.rs b/ryu/src/buffer/mod.rs new file mode 100644 index 000000000..ba7325f3c --- /dev/null +++ b/ryu/src/buffer/mod.rs @@ -0,0 +1,97 @@ +use core::{mem, slice, str}; + +use pretty; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +/// Safe API for formatting floating point numbers to text. +/// +/// ## Example +/// +/// ```edition2018 +/// let mut buffer = ryu::Buffer::new(); +/// let printed = buffer.format(1.234); +/// assert_eq!(printed, "1.234"); +/// ``` +#[derive(Copy, Clone)] +pub struct Buffer { + bytes: [u8; 24], +} + +impl Buffer { + /// This is a cheap operation; you don't need to worry about reusing buffers + /// for efficiency. + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn new() -> Self { + Buffer { + bytes: unsafe { mem::uninitialized() }, + } + } + + /// Print a floating point number into this buffer and return a reference to + /// its string representation within the buffer. + /// + /// # Special cases + /// + /// This function **does not** check for NaN or infinity. If the input + /// number is not a finite float, the printed representation will be some + /// correctly formatted but unspecified numerical value. + /// + /// Please check [`is_finite`] yourself before calling this function, or + /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. + /// + /// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite + /// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan + /// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + pub fn format<F: Float>(&mut self, f: F) -> &str { + unsafe { + let n = f.write_to_ryu_buffer(&mut self.bytes[0]); + debug_assert!(n <= self.bytes.len()); + let slice = slice::from_raw_parts(&self.bytes[0], n); + str::from_utf8_unchecked(slice) + } + } +} + +impl Default for Buffer { + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + fn default() -> Self { + Buffer::new() + } +} + +/// A floating point number, f32 or f64, that can be written into a +/// [`ryu::Buffer`][Buffer]. +/// +/// This trait is sealed and cannot be implemented for types outside of the +/// `ryu` crate. +pub trait Float: Sealed { + // Not public API. + #[doc(hidden)] + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize; +} + +impl Float for f32 { + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { + pretty::f2s_buffered_n(self, result) + } +} + +impl Float for f64 { + #[inline] + #[cfg_attr(feature = "no-panic", no_panic)] + unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { + pretty::d2s_buffered_n(self, result) + } +} + +pub trait Sealed {} +impl Sealed for f32 {} +impl Sealed for f64 {} diff --git a/ryu/src/common.rs b/ryu/src/common.rs new file mode 100644 index 000000000..651c136b2 --- /dev/null +++ b/ryu/src/common.rs @@ -0,0 +1,72 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use core::ptr; + +// Returns e == 0 ? 1 : ceil(log_2(5^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn pow5bits(e: i32) -> i32 { + // This approximation works up to the point that the multiplication overflows at e = 3529. + // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater + // than 2^9297. + debug_assert!(e >= 0); + debug_assert!(e <= 3528); + (((e as u32 * 1217359) >> 19) + 1) as i32 +} + +// Returns floor(log_10(2^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn log10_pow2(e: i32) -> u32 { + // The first value this approximation fails for is 2^1651 which is just greater than 10^297. + debug_assert!(e >= 0); + debug_assert!(e <= 1650); + (e as u32 * 78913) >> 18 +} + +// Returns floor(log_10(5^e)). +#[cfg_attr(feature = "no-panic", inline)] +pub fn log10_pow5(e: i32) -> u32 { + // The first value this approximation fails for is 5^2621 which is just greater than 10^1832. + debug_assert!(e >= 0); + debug_assert!(e <= 2620); + (e as u32 * 732923) >> 20 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn copy_special_str( + result: *mut u8, + sign: bool, + exponent: bool, + mantissa: bool, +) -> usize { + if mantissa { + ptr::copy_nonoverlapping(b"NaN".as_ptr(), result, 3); + return 3; + } + if sign { + *result = b'-'; + } + if exponent { + ptr::copy_nonoverlapping(b"Infinity".as_ptr(), result.offset(sign as isize), 8); + return sign as usize + 8; + } + ptr::copy_nonoverlapping(b"0E0".as_ptr(), result.offset(sign as isize), 3); + sign as usize + 3 +} diff --git a/ryu/src/d2s.rs b/ryu/src/d2s.rs new file mode 100644 index 000000000..545c55937 --- /dev/null +++ b/ryu/src/d2s.rs @@ -0,0 +1,581 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use core::{mem, ptr}; + +use common::*; +#[cfg(not(feature = "small"))] +use d2s_full_table::*; +#[cfg(feature = "small")] +use d2s_small_table::*; +use digit_table::*; +use d2s_intrinsics::*; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +pub const DOUBLE_MANTISSA_BITS: u32 = 52; +pub const DOUBLE_EXPONENT_BITS: u32 = 11; + +const DOUBLE_BIAS: i32 = 1023; +const DOUBLE_POW5_INV_BITCOUNT: i32 = 122; +const DOUBLE_POW5_BITCOUNT: i32 = 121; + +#[cfg_attr(feature = "no-panic", inline)] +fn pow5_factor(mut value: u64) -> u32 { + let mut count = 0u32; + loop { + debug_assert!(value != 0); + let q = div5(value); + let r = (value - 5 * q) as u32; + if r != 0 { + break; + } + value = q; + count += 1; + } + count +} + +// Returns true if value is divisible by 5^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_5(value: u64, p: u32) -> bool { + // I tried a case distinction on p, but there was no performance difference. + pow5_factor(value) >= p +} + +// Returns true if value is divisible by 2^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_2(value: u64, p: u32) -> bool { + // return __builtin_ctzll(value) >= p; + (value & ((1u64 << p) - 1)) == 0 +} + +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift(m: u64, mul: &(u64, u64), j: u32) -> u64 { + let b0 = m as u128 * mul.0 as u128; + let b2 = m as u128 * mul.1 as u128; + (((b0 >> 64) + b2) >> (j - 64)) as u64 +} + +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift_all( + m: u64, + mul: &(u64, u64), + j: u32, + vp: &mut u64, + vm: &mut u64, + mm_shift: u32, +) -> u64 { + *vp = mul_shift(4 * m + 2, mul, j); + *vm = mul_shift(4 * m - 1 - mm_shift as u64, mul, j); + mul_shift(4 * m, mul, j) +} + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift_all( + mut m: u64, + mul: &(u64, u64), + j: u32, + vp: &mut u64, + vm: &mut u64, + mm_shift: u32, +) -> u64 { + m <<= 1; + // m is maximum 55 bits + let (lo, tmp) = umul128(m, mul.0); + let (mut mid, mut hi) = umul128(m, mul.1); + mid = mid.wrapping_add(tmp); + hi = hi.wrapping_add((mid < tmp) as u64); // overflow into hi + + let lo2 = lo.wrapping_add(mul.0); + let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64); + let hi2 = hi.wrapping_add((mid2 < mid) as u64); + *vp = shiftright128(mid2, hi2, j - 64 - 1); + + if mm_shift == 1 { + let lo3 = lo.wrapping_sub(mul.0); + let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64); + let hi3 = hi.wrapping_sub((mid3 > mid) as u64); + *vm = shiftright128(mid3, hi3, j - 64 - 1); + } else { + let lo3 = lo + lo; + let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64); + let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64); + let lo4 = lo3.wrapping_sub(mul.0); + let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64); + let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64); + *vm = shiftright128(mid4, hi4, j - 64); + } + + shiftright128(mid, hi, j - 64 - 1) +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn decimal_length(v: u64) -> u32 { + // This is slightly faster than a loop. + // The average output length is 16.38 digits, so we check high-to-low. + // Function precondition: v is not an 18, 19, or 20-digit number. + // (17 digits are sufficient for round-tripping.) + debug_assert!(v < 100000000000000000); + + if v >= 10000000000000000 { + 17 + } else if v >= 1000000000000000 { + 16 + } else if v >= 100000000000000 { + 15 + } else if v >= 10000000000000 { + 14 + } else if v >= 1000000000000 { + 13 + } else if v >= 100000000000 { + 12 + } else if v >= 10000000000 { + 11 + } else if v >= 1000000000 { + 10 + } else if v >= 100000000 { + 9 + } else if v >= 10000000 { + 8 + } else if v >= 1000000 { + 7 + } else if v >= 100000 { + 6 + } else if v >= 10000 { + 5 + } else if v >= 1000 { + 4 + } else if v >= 100 { + 3 + } else if v >= 10 { + 2 + } else { + 1 + } +} + +// A floating decimal representing m * 10^e. +pub struct FloatingDecimal64 { + pub mantissa: u64, + pub exponent: i32, +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { + let (e2, m2) = if ieee_exponent == 0 { + ( + // We subtract 2 so that the bounds computation has 2 additional bits. + 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2, + ieee_mantissa, + ) + } else { + ( + ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2, + (1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa, + ) + }; + let even = (m2 & 1) == 0; + let accept_bounds = even; + + // Step 2: Determine the interval of valid decimal representations. + let mv = 4 * m2; + // Implicit bool -> int conversion. True is 1, false is 0. + let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32; + // We would compute mp and mm like this: + // uint64_t mp = 4 * m2 + 2; + // uint64_t mm = mv - 1 - mm_shift; + + // Step 3: Convert to a decimal power base using 128-bit arithmetic. + let mut vr: u64; + let mut vp: u64 = unsafe { mem::uninitialized() }; + let mut vm: u64 = unsafe { mem::uninitialized() }; + let e10: i32; + let mut vm_is_trailing_zeros = false; + let mut vr_is_trailing_zeros = false; + if e2 >= 0 { + // I tried special-casing q == 0, but there was no effect on performance. + // This expression is slightly faster than max(0, log10_pow2(e2) - 1). + let q = log10_pow2(e2) - (e2 > 3) as u32; + e10 = q as i32; + let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1; + let i = -e2 + q as i32 + k; + vr = mul_shift_all( + m2, + #[cfg(feature = "small")] + unsafe { + &compute_inv_pow5(q) + }, + #[cfg(not(feature = "small"))] + unsafe { + debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32); + DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize) + }, + i as u32, + &mut vp, + &mut vm, + mm_shift, + ); + if q <= 21 { + // This should use q <= 22, but I think 21 is also safe. Smaller values + // may still be safe, but it's more difficult to reason about them. + // Only one of mp, mv, and mm can be a multiple of 5, if any. + let mv_mod5 = (mv - 5 * div5(mv)) as u32; + if mv_mod5 == 0 { + vr_is_trailing_zeros = multiple_of_power_of_5(mv, q); + } else if accept_bounds { + // Same as min(e2 + (~mm & 1), pow5_factor(mm)) >= q + // <=> e2 + (~mm & 1) >= q && pow5_factor(mm) >= q + // <=> true && pow5_factor(mm) >= q, since e2 >= q. + vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q); + } else { + // Same as min(e2 + 1, pow5_factor(mp)) >= q. + vp -= multiple_of_power_of_5(mv + 2, q) as u64; + } + } + } else { + // This expression is slightly faster than max(0, log10_pow5(-e2) - 1). + let q = log10_pow5(-e2) - (-e2 > 1) as u32; + e10 = q as i32 + e2; + let i = -e2 - q as i32; + let k = pow5bits(i) - DOUBLE_POW5_BITCOUNT; + let j = q as i32 - k; + vr = mul_shift_all( + m2, + #[cfg(feature = "small")] + unsafe { + &compute_pow5(i as u32) + }, + #[cfg(not(feature = "small"))] + unsafe { + debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32); + DOUBLE_POW5_SPLIT.get_unchecked(i as usize) + }, + j as u32, + &mut vp, + &mut vm, + mm_shift, + ); + if q <= 1 { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 * m2, so it always has at least two trailing 0 bits. + vr_is_trailing_zeros = true; + if accept_bounds { + // mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1. + vm_is_trailing_zeros = mm_shift == 1; + } else { + // mp = mv + 2, so it always has at least one trailing 0 bit. + vp -= 1; + } + } else if q < 63 { + // TODO(ulfjack): Use a tighter bound here. + // We need to compute min(ntz(mv), pow5_factor(mv) - e2) >= q - 1 + // <=> ntz(mv) >= q - 1 && pow5_factor(mv) - e2 >= q - 1 + // <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q) + // <=> (mv & ((1 << (q - 1)) - 1)) == 0 + // We also need to make sure that the left shift does not overflow. + vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1); + } + } + + // Step 4: Find the shortest decimal representation in the interval of valid representations. + let mut removed = 0i32; + let mut last_removed_digit = 0u8; + // On average, we remove ~2 digits. + let output = if vm_is_trailing_zeros || vr_is_trailing_zeros { + // General case, which happens rarely (~0.7%). + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vm_mod10 = (vm - 10 * vm_div10) as u32; + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; + vm_is_trailing_zeros &= vm_mod10 == 0; + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + if vm_is_trailing_zeros { + loop { + let vm_div10 = div10(vm); + let vm_mod10 = (vm - 10 * vm_div10) as u32; + if vm_mod10 != 0 { + break; + } + let vp_div10 = div10(vp); + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + } + if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 { + // Round even if the exact number is .....50..0. + last_removed_digit = 4; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) + as u64 + } else { + // Specialized for the common case (~99.3%). Percentages below are relative to this. + let mut round_up = false; + let vp_div100 = div100(vp); + let vm_div100 = div100(vm); + // Optimization: remove two digits at a time (~86.2%). + if vp_div100 > vm_div100 { + let vr_div100 = div100(vr); + let vr_mod100 = (vr - 100 * vr_div100) as u32; + round_up = vr_mod100 >= 50; + vr = vr_div100; + vp = vp_div100; + vm = vm_div100; + removed += 2; + } + // Loop iterations below (approximately), without optimization above: + // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02% + // Loop iterations below (approximately), with optimization above: + // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; + round_up = vr_mod10 >= 5; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; + removed += 1; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + (vr == vm || round_up) as u64 + }; + let exp = e10 + removed; + + FloatingDecimal64 { + exponent: exp, + mantissa: output, + } +} + +#[cfg_attr(feature = "no-panic", inline)] +unsafe fn to_chars(v: FloatingDecimal64, sign: bool, result: *mut u8) -> usize { + // Step 5: Print the decimal representation. + let mut index = 0isize; + if sign { + *result.offset(index) = b'-'; + index += 1; + } + + let mut output = v.mantissa; + let olength = decimal_length(output); + + // Print the decimal digits. + // The following code is equivalent to: + // for (uint32_t i = 0; i < olength - 1; ++i) { + // const uint32_t c = output % 10; output /= 10; + // result[index + olength - i] = (char) ('0' + c); + // } + // result[index] = '0' + output % 10; + + let mut i = 0isize; + // We prefer 32-bit operations, even on 64-bit platforms. + // We have at most 17 digits, and uint32_t can store 9 digits. + // If output doesn't fit into uint32_t, we cut off 8 digits, + // so the rest will fit into uint32_t. + if (output >> 32) != 0 { + // Expensive 64-bit division. + let q = div100_000_000(output); + let mut output2 = (output - 100_000_000 * q) as u32; + output = q; + + let c = output2 % 10000; + output2 /= 10000; + let d = output2 % 10000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + let d0 = (d % 100) << 1; + let d1 = (d / 100) << 1; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c0 as usize), + result.offset(index + olength as isize - i - 1), + 2, + ); + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c1 as usize), + result.offset(index + olength as isize - i - 3), + 2, + ); + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(d0 as usize), + result.offset(index + olength as isize - i - 5), + 2, + ); + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(d1 as usize), + result.offset(index + olength as isize - i - 7), + 2, + ); + i += 8; + } + let mut output2 = output as u32; + while output2 >= 10000 { + let c = (output2 - 10000 * (output2 / 10000)) as u32; + output2 /= 10000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c0 as usize), + result.offset(index + olength as isize - i - 1), + 2, + ); + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c1 as usize), + result.offset(index + olength as isize - i - 3), + 2, + ); + i += 4; + } + if output2 >= 100 { + let c = ((output2 % 100) << 1) as u32; + output2 /= 100; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c as usize), + result.offset(index + olength as isize - i - 1), + 2, + ); + i += 2; + } + if output2 >= 10 { + let c = (output2 << 1) as u32; + // We can't use memcpy here: the decimal dot goes between these two digits. + *result.offset(index + olength as isize - i) = *DIGIT_TABLE.get_unchecked(c as usize + 1); + *result.offset(index) = *DIGIT_TABLE.get_unchecked(c as usize); + } else { + *result.offset(index) = b'0' + output2 as u8; + } + + // Print decimal point if needed. + if olength > 1 { + *result.offset(index + 1) = b'.'; + index += olength as isize + 1; + } else { + index += 1; + } + + // Print the exponent. + *result.offset(index) = b'E'; + index += 1; + let mut exp = v.exponent as i32 + olength as i32 - 1; + if exp < 0 { + *result.offset(index) = b'-'; + index += 1; + exp = -exp; + } + + if exp >= 100 { + let c = exp % 10; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked((2 * (exp / 10)) as usize), + result.offset(index), + 2, + ); + *result.offset(index + 2) = b'0' + c as u8; + index += 3; + } else if exp >= 10 { + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked((2 * exp) as usize), + result.offset(index), + 2, + ); + index += 2; + } else { + *result.offset(index) = b'0' + exp as u8; + index += 1; + } + + debug_assert!(index <= 24); + index as usize +} + +/// Print f64 to the given buffer and return number of bytes written. RyÅ«'s +/// original formatting. +/// +/// At most 24 bytes will be written. +/// +/// ## Special cases +/// +/// This function represents any NaN as `NaN`, positive infinity as `Infinity`, +/// and negative infinity as `-Infinity`. +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold RyÅ«'s representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// let f = 1.234f64; +/// +/// unsafe { +/// let mut buffer: [u8; 24] = std::mem::uninitialized(); +/// let n = ryu::raw::d2s_buffered_n(f, &mut buffer[0]); +/// let s = std::str::from_utf8_unchecked(&buffer[..n]); +/// assert_eq!(s, "1.234E0"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize { + // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. + let bits = mem::transmute::<f64, u64>(f); + + // Decode bits into sign, mantissa, and exponent. + let ieee_sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1); + let ieee_exponent = + (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1); + // Case distinction; exit early for the easy cases. + if ieee_exponent == ((1u32 << DOUBLE_EXPONENT_BITS) - 1) + || (ieee_exponent == 0 && ieee_mantissa == 0) + { + return copy_special_str(result, ieee_sign, ieee_exponent != 0, ieee_mantissa != 0); + } + + let v = d2d(ieee_mantissa, ieee_exponent); + to_chars(v, ieee_sign, result) +} diff --git a/ryu/src/d2s_full_table.rs b/ryu/src/d2s_full_table.rs new file mode 100644 index 000000000..eac50dcfc --- /dev/null +++ b/ryu/src/d2s_full_table.rs @@ -0,0 +1,643 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +pub static DOUBLE_POW5_INV_SPLIT: [(u64, u64); 292] = [ + (1, 288230376151711744), + (3689348814741910324, 230584300921369395), + (2951479051793528259, 184467440737095516), + (17118578500402463900, 147573952589676412), + (12632330341676300947, 236118324143482260), + (10105864273341040758, 188894659314785808), + (15463389048156653253, 151115727451828646), + (17362724847566824558, 241785163922925834), + (17579528692795369969, 193428131138340667), + (6684925324752475329, 154742504910672534), + (18074578149087781173, 247588007857076054), + (18149011334012135262, 198070406285660843), + (3451162622983977240, 158456325028528675), + (5521860196774363583, 253530120045645880), + (4417488157419490867, 202824096036516704), + (7223339340677503017, 162259276829213363), + (7867994130342094503, 259614842926741381), + (2605046489531765280, 207691874341393105), + (2084037191625412224, 166153499473114484), + (10713157136084480204, 265845599156983174), + (12259874523609494487, 212676479325586539), + (13497248433629505913, 170141183460469231), + (14216899864323388813, 272225893536750770), + (11373519891458711051, 217780714829400616), + (5409467098425058518, 174224571863520493), + (4965798542738183305, 278759314981632789), + (7661987648932456967, 223007451985306231), + (2440241304404055250, 178405961588244985), + (3904386087046488400, 285449538541191976), + (17880904128604832013, 228359630832953580), + (14304723302883865611, 182687704666362864), + (15133127457049002812, 146150163733090291), + (16834306301794583852, 233840261972944466), + (9778096226693756759, 187072209578355573), + (15201174610838826053, 149657767662684458), + (2185786488890659746, 239452428260295134), + (5437978005854438120, 191561942608236107), + (15418428848909281466, 153249554086588885), + (6222742084545298729, 245199286538542217), + (16046240111861969953, 196159429230833773), + (1768945645263844993, 156927543384667019), + (10209010661905972635, 251084069415467230), + (8167208529524778108, 200867255532373784), + (10223115638361732810, 160693804425899027), + (1599589762411131202, 257110087081438444), + (4969020624670815285, 205688069665150755), + (3975216499736652228, 164550455732120604), + (13739044029062464211, 263280729171392966), + (7301886408508061046, 210624583337114373), + (13220206756290269483, 168499666669691498), + (17462981995322520850, 269599466671506397), + (6591687966774196033, 215679573337205118), + (12652048002903177473, 172543658669764094), + (9175230360419352987, 276069853871622551), + (3650835473593572067, 220855883097298041), + (17678063637842498946, 176684706477838432), + (13527506561580357021, 282695530364541492), + (3443307619780464970, 226156424291633194), + (6443994910566282300, 180925139433306555), + (5155195928453025840, 144740111546645244), + (15627011115008661990, 231584178474632390), + (12501608892006929592, 185267342779705912), + (2622589484121723027, 148213874223764730), + (4196143174594756843, 237142198758023568), + (10735612169159626121, 189713759006418854), + (12277838550069611220, 151771007205135083), + (15955192865369467629, 242833611528216133), + (1696107848069843133, 194266889222572907), + (12424932722681605476, 155413511378058325), + (1433148282581017146, 248661618204893321), + (15903913885032455010, 198929294563914656), + (9033782293284053685, 159143435651131725), + (14454051669254485895, 254629497041810760), + (11563241335403588716, 203703597633448608), + (16629290697806691620, 162962878106758886), + (781423413297334329, 260740604970814219), + (4314487545379777786, 208592483976651375), + (3451590036303822229, 166873987181321100), + (5522544058086115566, 266998379490113760), + (4418035246468892453, 213598703592091008), + (10913125826658934609, 170878962873672806), + (10082303693170474728, 273406340597876490), + (8065842954536379782, 218725072478301192), + (17520720807854834795, 174980057982640953), + (5897060404116273733, 279968092772225526), + (1028299508551108663, 223974474217780421), + (15580034865808528224, 179179579374224336), + (17549358155809824511, 286687326998758938), + (2971440080422128639, 229349861599007151), + (17134547323305344204, 183479889279205720), + (13707637858644275364, 146783911423364576), + (14553522944347019935, 234854258277383322), + (4264120725993795302, 187883406621906658), + (10789994210278856888, 150306725297525326), + (9885293106962350374, 240490760476040522), + (529536856086059653, 192392608380832418), + (7802327114352668369, 153914086704665934), + (1415676938738538420, 246262538727465495), + (1132541550990830736, 197010030981972396), + (15663428499760305882, 157608024785577916), + (17682787970132668764, 252172839656924666), + (10456881561364224688, 201738271725539733), + (15744202878575200397, 161390617380431786), + (17812026976236499989, 258224987808690858), + (3181575136763469022, 206579990246952687), + (13613306553636506187, 165263992197562149), + (10713244041592678929, 264422387516099439), + (12259944048016053467, 211537910012879551), + (6118606423670932450, 169230328010303641), + (2411072648389671274, 270768524816485826), + (16686253377679378312, 216614819853188660), + (13349002702143502650, 173291855882550928), + (17669055508687693916, 277266969412081485), + (14135244406950155133, 221813575529665188), + (240149081334393137, 177450860423732151), + (11452284974360759988, 283921376677971441), + (5472479164746697667, 227137101342377153), + (11756680961281178780, 181709681073901722), + (2026647139541122378, 145367744859121378), + (18000030682233437097, 232588391774594204), + (18089373360528660001, 186070713419675363), + (3403452244197197031, 148856570735740291), + (16513570034941246220, 238170513177184465), + (13210856027952996976, 190536410541747572), + (3189987192878576934, 152429128433398058), + (1414630693863812771, 243886605493436893), + (8510402184574870864, 195109284394749514), + (10497670562401807014, 156087427515799611), + (9417575270359070576, 249739884025279378), + (14912757845771077107, 199791907220223502), + (4551508647133041040, 159833525776178802), + (10971762650154775986, 255733641241886083), + (16156107749607641435, 204586912993508866), + (9235537384944202825, 163669530394807093), + (11087511001168814197, 261871248631691349), + (12559357615676961681, 209496998905353079), + (13736834907283479668, 167597599124282463), + (18289587036911657145, 268156158598851941), + (10942320814787415393, 214524926879081553), + (16132554281313752961, 171619941503265242), + (11054691591134363444, 274591906405224388), + (16222450902391311402, 219673525124179510), + (12977960721913049122, 175738820099343608), + (17075388340318968271, 281182112158949773), + (2592264228029443648, 224945689727159819), + (5763160197165465241, 179956551781727855), + (9221056315464744386, 287930482850764568), + (14755542681855616155, 230344386280611654), + (15493782960226403247, 184275509024489323), + (1326979923955391628, 147420407219591459), + (9501865507812447252, 235872651551346334), + (11290841220991868125, 188698121241077067), + (1653975347309673853, 150958496992861654), + (10025058185179298811, 241533595188578646), + (4330697733401528726, 193226876150862917), + (14532604630946953951, 154581500920690333), + (1116074521063664381, 247330401473104534), + (4582208431592841828, 197864321178483627), + (14733813189500004432, 158291456942786901), + (16195403473716186445, 253266331108459042), + (5577625149489128510, 202613064886767234), + (8151448934333213131, 162090451909413787), + (16731667109675051333, 259344723055062059), + (17074682502481951390, 207475778444049647), + (6281048372501740465, 165980622755239718), + (6360328581260874421, 265568996408383549), + (8777611679750609860, 212455197126706839), + (10711438158542398211, 169964157701365471), + (9759603424184016492, 271942652322184754), + (11497031554089123517, 217554121857747803), + (16576322872755119460, 174043297486198242), + (11764721337440549842, 278469275977917188), + (16790474699436260520, 222775420782333750), + (13432379759549008416, 178220336625867000), + (3045063541568861850, 285152538601387201), + (17193446092222730773, 228122030881109760), + (13754756873778184618, 182497624704887808), + (18382503128506368341, 145998099763910246), + (3586563302416817083, 233596959622256395), + (2869250641933453667, 186877567697805116), + (17052795772514404226, 149502054158244092), + (12527077977055405469, 239203286653190548), + (17400360011128145022, 191362629322552438), + (2852241564676785048, 153090103458041951), + (15631632947708587046, 244944165532867121), + (8815957543424959314, 195955332426293697), + (18120812478965698421, 156764265941034957), + (14235904707377476180, 250822825505655932), + (4010026136418160298, 200658260404524746), + (17965416168102169531, 160526608323619796), + (2919224165770098987, 256842573317791675), + (2335379332616079190, 205474058654233340), + (1868303466092863352, 164379246923386672), + (6678634360490491686, 263006795077418675), + (5342907488392393349, 210405436061934940), + (4274325990713914679, 168324348849547952), + (10528270399884173809, 269318958159276723), + (15801313949391159694, 215455166527421378), + (1573004715287196786, 172364133221937103), + (17274202803427156150, 275782613155099364), + (17508711057483635243, 220626090524079491), + (10317620031244997871, 176500872419263593), + (12818843235250086271, 282401395870821749), + (13944423402941979340, 225921116696657399), + (14844887537095493795, 180736893357325919), + (15565258844418305359, 144589514685860735), + (6457670077359736959, 231343223497377177), + (16234182506113520537, 185074578797901741), + (9297997190148906106, 148059663038321393), + (11187446689496339446, 236895460861314229), + (12639306166338981880, 189516368689051383), + (17490142562555006151, 151613094951241106), + (2158786396894637579, 242580951921985771), + (16484424376483351356, 194064761537588616), + (9498190686444770762, 155251809230070893), + (11507756283569722895, 248402894768113429), + (12895553841597688639, 198722315814490743), + (17695140702761971558, 158977852651592594), + (17244178680193423523, 254364564242548151), + (10105994129412828495, 203491651394038521), + (4395446488788352473, 162793321115230817), + (10722063196803274280, 260469313784369307), + (1198952927958798777, 208375451027495446), + (15716557601334680315, 166700360821996356), + (17767794532651667857, 266720577315194170), + (14214235626121334286, 213376461852155336), + (7682039686155157106, 170701169481724269), + (1223217053622520399, 273121871170758831), + (15735968901865657612, 218497496936607064), + (16278123936234436413, 174797997549285651), + (219556594781725998, 279676796078857043), + (7554342905309201445, 223741436863085634), + (9732823138989271479, 178993149490468507), + (815121763415193074, 286389039184749612), + (11720143854957885429, 229111231347799689), + (13065463898708218666, 183288985078239751), + (6763022304224664610, 146631188062591801), + (3442138057275642729, 234609900900146882), + (13821756890046245153, 187687920720117505), + (11057405512036996122, 150150336576094004), + (6623802375033462826, 240240538521750407), + (16367088344252501231, 192192430817400325), + (13093670675402000985, 153753944653920260), + (2503129006933649959, 246006311446272417), + (13070549649772650937, 196805049157017933), + (17835137349301941396, 157444039325614346), + (2710778055689733971, 251910462920982955), + (2168622444551787177, 201528370336786364), + (5424246770383340065, 161222696269429091), + (1300097203129523457, 257956314031086546), + (15797473021471260058, 206365051224869236), + (8948629602435097724, 165092040979895389), + (3249760919670425388, 264147265567832623), + (9978506365220160957, 211317812454266098), + (15361502721659949412, 169054249963412878), + (2442311466204457120, 270486799941460606), + (16711244431931206989, 216389439953168484), + (17058344360286875914, 173111551962534787), + (12535955717491360170, 276978483140055660), + (10028764573993088136, 221582786512044528), + (15401709288678291155, 177266229209635622), + (9885339602917624555, 283625966735416996), + (4218922867592189321, 226900773388333597), + (14443184738299482427, 181520618710666877), + (4175850161155765295, 145216494968533502), + (10370709072591134795, 232346391949653603), + (15675264887556728482, 185877113559722882), + (5161514280561562140, 148701690847778306), + (879725219414678777, 237922705356445290), + (703780175531743021, 190338164285156232), + (11631070584651125387, 152270531428124985), + (162968861732249003, 243632850284999977), + (11198421533611530172, 194906280227999981), + (5269388412147313814, 155925024182399985), + (8431021459435702103, 249480038691839976), + (3055468352806651359, 199584030953471981), + (17201769941212962380, 159667224762777584), + (16454785461715008838, 255467559620444135), + (13163828369372007071, 204374047696355308), + (17909760324981426303, 163499238157084246), + (2830174816776909822, 261598781051334795), + (2264139853421527858, 209279024841067836), + (16568707141704863579, 167423219872854268), + (4373838538276319787, 267877151796566830), + (3499070830621055830, 214301721437253464), + (6488605479238754987, 171441377149802771), + (3003071137298187333, 274306203439684434), + (6091805724580460189, 219444962751747547), + (15941491023890099121, 175555970201398037), + (10748990379256517301, 280889552322236860), + (8599192303405213841, 224711641857789488), + (14258051472207991719, 179769313486231590), +]; + +pub static DOUBLE_POW5_SPLIT: [(u64, u64); 326] = [ + (0, 72057594037927936), + (0, 90071992547409920), + (0, 112589990684262400), + (0, 140737488355328000), + (0, 87960930222080000), + (0, 109951162777600000), + (0, 137438953472000000), + (0, 85899345920000000), + (0, 107374182400000000), + (0, 134217728000000000), + (0, 83886080000000000), + (0, 104857600000000000), + (0, 131072000000000000), + (0, 81920000000000000), + (0, 102400000000000000), + (0, 128000000000000000), + (0, 80000000000000000), + (0, 100000000000000000), + (0, 125000000000000000), + (0, 78125000000000000), + (0, 97656250000000000), + (0, 122070312500000000), + (0, 76293945312500000), + (0, 95367431640625000), + (0, 119209289550781250), + (4611686018427387904, 74505805969238281), + (10376293541461622784, 93132257461547851), + (8358680908399640576, 116415321826934814), + (612489549322387456, 72759576141834259), + (14600669991935148032, 90949470177292823), + (13639151471491547136, 113686837721616029), + (3213881284082270208, 142108547152020037), + (4314518811765112832, 88817841970012523), + (781462496279003136, 111022302462515654), + (10200200157203529728, 138777878078144567), + (13292654125893287936, 86736173798840354), + (7392445620511834112, 108420217248550443), + (4628871007212404736, 135525271560688054), + (16728102434789916672, 84703294725430033), + (7075069988205232128, 105879118406787542), + (18067209522111315968, 132348898008484427), + (8986162942105878528, 82718061255302767), + (6621017659204960256, 103397576569128459), + (3664586055578812416, 129246970711410574), + (16125424340018921472, 80779356694631608), + (1710036351314100224, 100974195868289511), + (15972603494424788992, 126217744835361888), + (9982877184015493120, 78886090522101180), + (12478596480019366400, 98607613152626475), + (10986559581596820096, 123259516440783094), + (2254913720070624656, 77037197775489434), + (12042014186943056628, 96296497219361792), + (15052517733678820785, 120370621524202240), + (9407823583549262990, 75231638452626400), + (11759779479436578738, 94039548065783000), + (14699724349295723422, 117549435082228750), + (4575641699882439235, 73468396926392969), + (10331238143280436948, 91835496157991211), + (8302361660673158281, 114794370197489014), + (1154580038986672043, 143492962746861268), + (9944984561221445835, 89683101716788292), + (12431230701526807293, 112103877145985365), + (1703980321626345405, 140129846432481707), + (17205888765512323542, 87581154020301066), + (12283988920035628619, 109476442525376333), + (1519928094762372062, 136845553156720417), + (12479170105294952299, 85528470722950260), + (15598962631618690374, 106910588403687825), + (5663645234241199255, 133638235504609782), + (17374836326682913246, 83523897190381113), + (7883487353071477846, 104404871487976392), + (9854359191339347308, 130506089359970490), + (10770660513014479971, 81566305849981556), + (13463325641268099964, 101957882312476945), + (2994098996302961243, 127447352890596182), + (15706369927971514489, 79654595556622613), + (5797904354682229399, 99568244445778267), + (2635694424925398845, 124460305557222834), + (6258995034005762182, 77787690973264271), + (3212057774079814824, 97234613716580339), + (17850130272881932242, 121543267145725423), + (18073860448192289507, 75964541966078389), + (8757267504958198172, 94955677457597987), + (6334898362770359811, 118694596821997484), + (13182683513586250689, 74184123013748427), + (11866668373555425458, 92730153767185534), + (5609963430089506015, 115912692208981918), + (17341285199088104971, 72445432630613698), + (12453234462005355406, 90556790788267123), + (10954857059079306353, 113195988485333904), + (13693571323849132942, 141494985606667380), + (17781854114260483896, 88434366004167112), + (3780573569116053255, 110542957505208891), + (114030942967678664, 138178696881511114), + (4682955357782187069, 86361685550944446), + (15077066234082509644, 107952106938680557), + (5011274737320973344, 134940133673350697), + (14661261756894078100, 84337583545844185), + (4491519140835433913, 105421979432305232), + (5614398926044292391, 131777474290381540), + (12732371365632458552, 82360921431488462), + (6692092170185797382, 102951151789360578), + (17588487249587022536, 128688939736700722), + (15604490549419276989, 80430587335437951), + (14893927168346708332, 100538234169297439), + (14005722942005997511, 125672792711621799), + (15671105866394830300, 78545495444763624), + (1142138259283986260, 98181869305954531), + (15262730879387146537, 122727336632443163), + (7233363790403272633, 76704585395276977), + (13653390756431478696, 95880731744096221), + (3231680390257184658, 119850914680120277), + (4325643253124434363, 74906821675075173), + (10018740084832930858, 93633527093843966), + (3300053069186387764, 117041908867304958), + (15897591223523656064, 73151193042065598), + (10648616992549794273, 91438991302581998), + (4087399203832467033, 114298739128227498), + (14332621041645359599, 142873423910284372), + (18181260187883125557, 89295889943927732), + (4279831161144355331, 111619862429909666), + (14573160988285219972, 139524828037387082), + (13719911636105650386, 87203017523366926), + (7926517508277287175, 109003771904208658), + (684774848491833161, 136254714880260823), + (7345513307948477581, 85159196800163014), + (18405263671790372785, 106448996000203767), + (18394893571310578077, 133061245000254709), + (13802651491282805250, 83163278125159193), + (3418256308821342851, 103954097656448992), + (4272820386026678563, 129942622070561240), + (2670512741266674102, 81214138794100775), + (17173198981865506339, 101517673492625968), + (3019754653622331308, 126897091865782461), + (4193189667727651020, 79310682416114038), + (14464859121514339583, 99138353020142547), + (13469387883465536574, 123922941275178184), + (8418367427165960359, 77451838296986365), + (15134645302384838353, 96814797871232956), + (471562554271496325, 121018497339041196), + (9518098633274461011, 75636560836900747), + (7285937273165688360, 94545701046125934), + (18330793628311886258, 118182126307657417), + (4539216990053847055, 73863828942285886), + (14897393274422084627, 92329786177857357), + (4786683537745442072, 115412232722321697), + (14520892257159371055, 72132645451451060), + (18151115321449213818, 90165806814313825), + (8853836096529353561, 112707258517892282), + (1843923083806916143, 140884073147365353), + (12681666973447792349, 88052545717103345), + (2017025661527576725, 110065682146379182), + (11744654113764246714, 137582102682973977), + (422879793461572340, 85988814176858736), + (528599741826965425, 107486017721073420), + (660749677283706782, 134357522151341775), + (7330497575943398595, 83973451344588609), + (13774807988356636147, 104966814180735761), + (3383451930163631472, 131208517725919702), + (15949715511634433382, 82005323578699813), + (6102086334260878016, 102506654473374767), + (3015921899398709616, 128133318091718459), + (18025852251620051174, 80083323807324036), + (4085571240815512351, 100104154759155046), + (14330336087874166247, 125130193448943807), + (15873989082562435760, 78206370905589879), + (15230800334775656796, 97757963631987349), + (5203442363187407284, 122197454539984187), + (946308467778435600, 76373409087490117), + (5794571603150432404, 95466761359362646), + (16466586540792816313, 119333451699203307), + (7985773578781816244, 74583407312002067), + (5370530955049882401, 93229259140002584), + (6713163693812353001, 116536573925003230), + (18030785363914884337, 72835358703127018), + (13315109668038829614, 91044198378908773), + (2808829029766373305, 113805247973635967), + (17346094342490130344, 142256559967044958), + (6229622945628943561, 88910349979403099), + (3175342663608791547, 111137937474253874), + (13192550366365765242, 138922421842817342), + (3633657960551215372, 86826513651760839), + (18377130505971182927, 108533142064701048), + (4524669058754427043, 135666427580876311), + (9745447189362598758, 84791517238047694), + (2958436949848472639, 105989396547559618), + (12921418224165366607, 132486745684449522), + (12687572408530742033, 82804216052780951), + (11247779492236039638, 103505270065976189), + (224666310012885835, 129381587582470237), + (2446259452971747599, 80863492239043898), + (12281196353069460307, 101079365298804872), + (15351495441336825384, 126349206623506090), + (14206370669262903769, 78968254139691306), + (8534591299723853903, 98710317674614133), + (15279925143082205283, 123387897093267666), + (14161639232853766206, 77117435683292291), + (13090363022639819853, 96396794604115364), + (16362953778299774816, 120495993255144205), + (12532689120651053212, 75309995784465128), + (15665861400813816515, 94137494730581410), + (10358954714162494836, 117671868413226763), + (4168503687137865320, 73544917758266727), + (598943590494943747, 91931147197833409), + (5360365506546067587, 114913933997291761), + (11312142901609972388, 143642417496614701), + (9375932322719926695, 89776510935384188), + (11719915403399908368, 112220638669230235), + (10038208235822497557, 140275798336537794), + (10885566165816448877, 87672373960336121), + (18218643725697949000, 109590467450420151), + (18161618638695048346, 136988084313025189), + (13656854658398099168, 85617552695640743), + (12459382304570236056, 107021940869550929), + (1739169825430631358, 133777426086938662), + (14922039196176308311, 83610891304336663), + (14040862976792997485, 104513614130420829), + (3716020665709083144, 130642017663026037), + (4628355925281870917, 81651261039391273), + (10397130925029726550, 102064076299239091), + (8384727637859770284, 127580095374048864), + (5240454773662356427, 79737559608780540), + (6550568467077945534, 99671949510975675), + (3576524565420044014, 124589936888719594), + (6847013871814915412, 77868710555449746), + (17782139376623420074, 97335888194312182), + (13004302183924499284, 121669860242890228), + (17351060901807587860, 76043662651806392), + (3242082053549933210, 95054578314757991), + (17887660622219580224, 118818222893447488), + (11179787888887237640, 74261389308404680), + (13974734861109047050, 92826736635505850), + (8245046539531533005, 116033420794382313), + (16682369133275677888, 72520887996488945), + (7017903361312433648, 90651109995611182), + (17995751238495317868, 113313887494513977), + (8659630992836983623, 141642359368142472), + (5412269370523114764, 88526474605089045), + (11377022731581281359, 110658093256361306), + (4997906377621825891, 138322616570451633), + (14652906532082110942, 86451635356532270), + (9092761128247862869, 108064544195665338), + (2142579373455052779, 135080680244581673), + (12868327154477877747, 84425425152863545), + (2250350887815183471, 105531781441079432), + (2812938609768979339, 131914726801349290), + (6369772649532999991, 82446704250843306), + (17185587848771025797, 103058380313554132), + (3035240737254230630, 128822975391942666), + (6508711479211282048, 80514359619964166), + (17359261385868878368, 100642949524955207), + (17087390713908710056, 125803686906194009), + (3762090168551861929, 78627304316371256), + (4702612710689827411, 98284130395464070), + (15101637925217060072, 122855162994330087), + (16356052730901744401, 76784476871456304), + (1998321839917628885, 95980596089320381), + (7109588318324424010, 119975745111650476), + (13666864735807540814, 74984840694781547), + (12471894901332038114, 93731050868476934), + (6366496589810271835, 117163813585596168), + (3979060368631419896, 73227383490997605), + (9585511479216662775, 91534229363747006), + (2758517312166052660, 114417786704683758), + (12671518677062341634, 143022233380854697), + (1002170145522881665, 89388895863034186), + (10476084718758377889, 111736119828792732), + (13095105898447972362, 139670149785990915), + (5878598177316288774, 87293843616244322), + (16571619758500136775, 109117304520305402), + (11491152661270395161, 136396630650381753), + (264441385652915120, 85247894156488596), + (330551732066143900, 106559867695610745), + (5024875683510067779, 133199834619513431), + (10058076329834874218, 83249896637195894), + (3349223375438816964, 104062370796494868), + (4186529219298521205, 130077963495618585), + (14145795808130045513, 81298727184761615), + (13070558741735168987, 101623408980952019), + (11726512408741573330, 127029261226190024), + (7329070255463483331, 79393288266368765), + (13773023837756742068, 99241610332960956), + (17216279797195927585, 124052012916201195), + (8454331864033760789, 77532508072625747), + (5956228811614813082, 96915635090782184), + (7445286014518516353, 121144543863477730), + (9264989777501460624, 75715339914673581), + (16192923240304213684, 94644174893341976), + (1794409976670715490, 118305218616677471), + (8039035263060279037, 73940761635423419), + (5437108060397960892, 92425952044279274), + (16019757112352226923, 115532440055349092), + (788976158365366019, 72207775034593183), + (14821278253238871236, 90259718793241478), + (9303225779693813237, 112824648491551848), + (11629032224617266546, 141030810614439810), + (11879831158813179495, 88144256634024881), + (1014730893234310657, 110180320792531102), + (10491785653397664129, 137725400990663877), + (8863209042587234033, 86078375619164923), + (6467325284806654637, 107597969523956154), + (17307528642863094104, 134497461904945192), + (10817205401789433815, 84060913690590745), + (18133192770664180173, 105076142113238431), + (18054804944902837312, 131345177641548039), + (18201782118205355176, 82090736025967524), + (4305483574047142354, 102613420032459406), + (14605226504413703751, 128266775040574257), + (2210737537617482988, 80166734400358911), + (16598479977304017447, 100208418000448638), + (11524727934775246001, 125260522500560798), + (2591268940807140847, 78287826562850499), + (17074144231291089770, 97859783203563123), + (16730994270686474309, 122324729004453904), + (10456871419179046443, 76452955627783690), + (3847717237119032246, 95566194534729613), + (9421332564826178211, 119457743168412016), + (5888332853016361382, 74661089480257510), + (16583788103125227536, 93326361850321887), + (16118049110479146516, 116657952312902359), + (16991309721690548428, 72911220195563974), + (12015765115258409727, 91139025244454968), + (15019706394073012159, 113923781555568710), + (9551260955736489391, 142404726944460888), + (5969538097335305869, 89002954340288055), + (2850236603241744433, 111253692925360069), +]; diff --git a/ryu/src/d2s_intrinsics.rs b/ryu/src/d2s_intrinsics.rs new file mode 100644 index 000000000..e0e280cec --- /dev/null +++ b/ryu/src/d2s_intrinsics.rs @@ -0,0 +1,79 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +// Returns (lo, hi). +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn umul128(a: u64, b: u64) -> (u64, u64) { + let a_lo = a as u32; + let a_hi = (a >> 32) as u32; + let b_lo = b as u32; + let b_hi = (b >> 32) as u32; + + let b00 = a_lo as u64 * b_lo as u64; + let b01 = a_lo as u64 * b_hi as u64; + let b10 = a_hi as u64 * b_lo as u64; + let b11 = a_hi as u64 * b_hi as u64; + + let b00_lo = b00 as u32; + let b00_hi = (b00 >> 32) as u32; + + let mid1 = b10 + b00_hi as u64; + let mid1_lo = mid1 as u32; + let mid1_hi = (mid1 >> 32) as u32; + + let mid2 = b01 + mid1_lo as u64; + let mid2_lo = mid2 as u32; + let mid2_hi = (mid2 >> 32) as u32; + + let p_hi = b11 + mid1_hi as u64 + mid2_hi as u64; + let p_lo = ((mid2_lo as u64) << 32) + b00_lo as u64; + + (p_lo, p_hi) +} + +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { + // We don't need to handle the case dist >= 64 here (see above). + debug_assert!(dist > 0); + debug_assert!(dist < 64); + (hi << (64 - dist)) | (lo >> dist) +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div5(x: u64) -> u64 { + x / 5 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div10(x: u64) -> u64 { + x / 10 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div100(x: u64) -> u64 { + x / 100 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div100_000_000(x: u64) -> u64 { + x / 100_000_000 +} diff --git a/ryu/src/d2s_small_table.rs b/ryu/src/d2s_small_table.rs new file mode 100644 index 000000000..fc4a1a2a3 --- /dev/null +++ b/ryu/src/d2s_small_table.rs @@ -0,0 +1,206 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use common::*; +#[cfg(not(integer128))] +use d2s_intrinsics::*; + +pub static DOUBLE_POW5_TABLE: [u64; 26] = [ + 1, + 5, + 25, + 125, + 625, + 3125, + 15625, + 78125, + 390625, + 1953125, + 9765625, + 48828125, + 244140625, + 1220703125, + 6103515625, + 30517578125, + 152587890625, + 762939453125, + 3814697265625, + 19073486328125, + 95367431640625, + 476837158203125, + 2384185791015625, + 11920928955078125, + 59604644775390625, + 298023223876953125, +]; + +pub static DOUBLE_POW5_SPLIT2: [(u64, u64); 13] = [ + (0, 72057594037927936), + (10376293541461622784, 93132257461547851), + (15052517733678820785, 120370621524202240), + (6258995034005762182, 77787690973264271), + (14893927168346708332, 100538234169297439), + (4272820386026678563, 129942622070561240), + (7330497575943398595, 83973451344588609), + (18377130505971182927, 108533142064701048), + (10038208235822497557, 140275798336537794), + (7017903361312433648, 90651109995611182), + (6366496589810271835, 117163813585596168), + (9264989777501460624, 75715339914673581), + (17074144231291089770, 97859783203563123), +]; + +// Unfortunately, the results are sometimes off by one. We use an additional +// lookup table to store those cases and adjust the result. +pub static POW5_OFFSETS: [u32; 13] = [ + 0x00000000, 0x00000000, 0x00000000, 0x033c55be, 0x03db77d8, 0x0265ffb2, 0x00000800, 0x01a8ff56, + 0x00000000, 0x0037a200, 0x00004000, 0x03fffffc, 0x00003ffe, +]; + +pub static DOUBLE_POW5_INV_SPLIT2: [(u64, u64); 13] = [ + (1, 288230376151711744), + (7661987648932456967, 223007451985306231), + (12652048002903177473, 172543658669764094), + (5522544058086115566, 266998379490113760), + (3181575136763469022, 206579990246952687), + (4551508647133041040, 159833525776178802), + (1116074521063664381, 247330401473104534), + (17400360011128145022, 191362629322552438), + (9297997190148906106, 148059663038321393), + (11720143854957885429, 229111231347799689), + (15401709288678291155, 177266229209635622), + (3003071137298187333, 274306203439684434), + (17516772882021341108, 212234145163966538), +]; + +pub static POW5_INV_OFFSETS: [u32; 20] = [ + 0x51505404, 0x55054514, 0x45555545, 0x05511411, 0x00505010, 0x00000004, 0x00000000, 0x00000000, + 0x55555040, 0x00505051, 0x00050040, 0x55554000, 0x51659559, 0x00001000, 0x15000010, 0x55455555, + 0x41404051, 0x00001010, 0x00000014, 0x00000000, +]; + +// Computes 5^i in the form required by Ryu. +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { + let base = i / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = i - base2; + debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize); + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let b0 = m as u128 * mul.0 as u128; + let b2 = m as u128 * mul.1 as u128; + let delta = pow5bits(i as i32) - pow5bits(base2 as i32); + debug_assert!(base < POW5_OFFSETS.len() as u32); + let shifted_sum = (b0 >> delta) + + (b2 << (64 - delta)) + + ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u128; + (shifted_sum as u64, (shifted_sum >> 64) as u64) +} + +// Computes 5^-i in the form required by Ryu. +#[cfg(integer128)] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = base2 - i; + debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2 + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); // 5^offset + let b0 = m as u128 * (mul.0 - 1) as u128; + let b2 = m as u128 * mul.1 as u128; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i + let delta = pow5bits(base2 as i32) - pow5bits(i as i32); + debug_assert!(base < POW5_INV_OFFSETS.len() as u32); + let shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + + 1 + + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u128; + (shifted_sum as u64, (shifted_sum >> 64) as u64) +} + +// Computes 5^i in the form required by Ryu, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_pow5(i: u32) -> (u64, u64) { + let base = i / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = i - base2; + debug_assert!(base < DOUBLE_POW5_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_SPLIT2.get_unchecked(base as usize); + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(i as i32) - pow5bits(base2 as i32); + debug_assert!(base < POW5_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + ((*POW5_OFFSETS.get_unchecked(base as usize) >> offset) & 1) as u64, + shiftright128(sum, high1, delta as u32), + ) +} + +// Computes 5^-i in the form required by Ryu, and stores it in the given pointer. +#[cfg(not(integer128))] +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn compute_inv_pow5(i: u32) -> (u64, u64) { + let base = (i + DOUBLE_POW5_TABLE.len() as u32 - 1) / DOUBLE_POW5_TABLE.len() as u32; + let base2 = base * DOUBLE_POW5_TABLE.len() as u32; + let offset = base2 - i; + debug_assert!(base < DOUBLE_POW5_INV_SPLIT2.len() as u32); + let mul = *DOUBLE_POW5_INV_SPLIT2.get_unchecked(base as usize); // 1/5^base2 + if offset == 0 { + return mul; + } + debug_assert!(offset < DOUBLE_POW5_TABLE.len() as u32); + let m = *DOUBLE_POW5_TABLE.get_unchecked(offset as usize); + let (low1, mut high1) = umul128(m, mul.1); + let (low0, high0) = umul128(m, mul.0 - 1); + let sum = high0 + low1; + if sum < high0 { + high1 += 1; // overflow into high1 + } + // high1 | sum | low0 + let delta = pow5bits(base2 as i32) - pow5bits(i as i32); + debug_assert!(base < POW5_INV_OFFSETS.len() as u32); + ( + shiftright128(low0, sum, delta as u32) + + 1 + + ((*POW5_INV_OFFSETS.get_unchecked((i / 16) as usize) >> ((i % 16) << 1)) & 3) as u64, + shiftright128(sum, high1, delta as u32), + ) +} diff --git a/ryu/src/digit_table.rs b/ryu/src/digit_table.rs new file mode 100644 index 000000000..d871f03f7 --- /dev/null +++ b/ryu/src/digit_table.rs @@ -0,0 +1,28 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +// A table of all two-digit numbers. This is used to speed up decimal digit +// generation by copying pairs of digits into the final output. +pub static DIGIT_TABLE: [u8; 200] = *b"\ + 0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; diff --git a/ryu/src/f2s.rs b/ryu/src/f2s.rs new file mode 100644 index 000000000..66e7a7aa2 --- /dev/null +++ b/ryu/src/f2s.rs @@ -0,0 +1,494 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +use core::{mem, ptr}; + +use common::*; +use digit_table::*; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +pub const FLOAT_MANTISSA_BITS: u32 = 23; +pub const FLOAT_EXPONENT_BITS: u32 = 8; + +const FLOAT_BIAS: i32 = 127; +const FLOAT_POW5_INV_BITCOUNT: i32 = 59; +const FLOAT_POW5_BITCOUNT: i32 = 61; + +// This table is generated by PrintFloatLookupTable. +static FLOAT_POW5_INV_SPLIT: [u64; 32] = [ + 576460752303423489, + 461168601842738791, + 368934881474191033, + 295147905179352826, + 472236648286964522, + 377789318629571618, + 302231454903657294, + 483570327845851670, + 386856262276681336, + 309485009821345069, + 495176015714152110, + 396140812571321688, + 316912650057057351, + 507060240091291761, + 405648192073033409, + 324518553658426727, + 519229685853482763, + 415383748682786211, + 332306998946228969, + 531691198313966350, + 425352958651173080, + 340282366920938464, + 544451787073501542, + 435561429658801234, + 348449143727040987, + 557518629963265579, + 446014903970612463, + 356811923176489971, + 570899077082383953, + 456719261665907162, + 365375409332725730, + 1 << 63, +]; + +static FLOAT_POW5_SPLIT: [u64; 47] = [ + 1152921504606846976, + 1441151880758558720, + 1801439850948198400, + 2251799813685248000, + 1407374883553280000, + 1759218604441600000, + 2199023255552000000, + 1374389534720000000, + 1717986918400000000, + 2147483648000000000, + 1342177280000000000, + 1677721600000000000, + 2097152000000000000, + 1310720000000000000, + 1638400000000000000, + 2048000000000000000, + 1280000000000000000, + 1600000000000000000, + 2000000000000000000, + 1250000000000000000, + 1562500000000000000, + 1953125000000000000, + 1220703125000000000, + 1525878906250000000, + 1907348632812500000, + 1192092895507812500, + 1490116119384765625, + 1862645149230957031, + 1164153218269348144, + 1455191522836685180, + 1818989403545856475, + 2273736754432320594, + 1421085471520200371, + 1776356839400250464, + 2220446049250313080, + 1387778780781445675, + 1734723475976807094, + 2168404344971008868, + 1355252715606880542, + 1694065894508600678, + 2117582368135750847, + 1323488980084844279, + 1654361225106055349, + 2067951531382569187, + 1292469707114105741, + 1615587133892632177, + 2019483917365790221, +]; + +#[cfg_attr(feature = "no-panic", inline)] +fn pow5_factor(mut value: u32) -> u32 { + let mut count = 0u32; + loop { + debug_assert!(value != 0); + let q = value / 5; + let r = value % 5; + if r != 0 { + break; + } + value = q; + count += 1; + } + count +} + +// Returns true if value is divisible by 5^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_5(value: u32, p: u32) -> bool { + pow5_factor(value) >= p +} + +// Returns true if value is divisible by 2^p. +#[cfg_attr(feature = "no-panic", inline)] +fn multiple_of_power_of_2(value: u32, p: u32) -> bool { + // return __builtin_ctz(value) >= p; + (value & ((1u32 << p) - 1)) == 0 +} + +// It seems to be slightly faster to avoid uint128_t here, although the +// generated code for uint128_t looks slightly nicer. +#[cfg_attr(feature = "no-panic", inline)] +fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 { + debug_assert!(shift > 32); + + // The casts here help MSVC to avoid calls to the __allmul library + // function. + let factor_lo = factor as u32; + let factor_hi = (factor >> 32) as u32; + let bits0 = m as u64 * factor_lo as u64; + let bits1 = m as u64 * factor_hi as u64; + + let sum = (bits0 >> 32) + bits1; + let shifted_sum = sum >> (shift - 32); + debug_assert!(shifted_sum <= u32::max_value() as u64); + shifted_sum as u32 +} + +#[cfg_attr(feature = "no-panic", inline)] +fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 { + debug_assert!(q < FLOAT_POW5_INV_SPLIT.len() as u32); + unsafe { mul_shift(m, *FLOAT_POW5_INV_SPLIT.get_unchecked(q as usize), j) } +} + +#[cfg_attr(feature = "no-panic", inline)] +fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 { + debug_assert!(i < FLOAT_POW5_SPLIT.len() as u32); + unsafe { mul_shift(m, *FLOAT_POW5_SPLIT.get_unchecked(i as usize), j) } +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn decimal_length(v: u32) -> u32 { + // Function precondition: v is not a 10-digit number. + // (9 digits are sufficient for round-tripping.) + debug_assert!(v < 1000000000); + + if v >= 100000000 { + 9 + } else if v >= 10000000 { + 8 + } else if v >= 1000000 { + 7 + } else if v >= 100000 { + 6 + } else if v >= 10000 { + 5 + } else if v >= 1000 { + 4 + } else if v >= 100 { + 3 + } else if v >= 10 { + 2 + } else { + 1 + } +} + +// A floating decimal representing m * 10^e. +pub struct FloatingDecimal32 { + pub mantissa: u32, + pub exponent: i32, +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 { + let (e2, m2) = if ieee_exponent == 0 { + ( + // We subtract 2 so that the bounds computation has 2 additional bits. + 1 - FLOAT_BIAS - FLOAT_MANTISSA_BITS as i32 - 2, + ieee_mantissa, + ) + } else { + ( + ieee_exponent as i32 - FLOAT_BIAS - FLOAT_MANTISSA_BITS as i32 - 2, + (1u32 << FLOAT_MANTISSA_BITS) | ieee_mantissa, + ) + }; + let even = (m2 & 1) == 0; + let accept_bounds = even; + + // Step 2: Determine the interval of valid decimal representations. + let mv = 4 * m2; + let mp = 4 * m2 + 2; + // Implicit bool -> int conversion. True is 1, false is 0. + let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32; + let mm = 4 * m2 - 1 - mm_shift; + + // Step 3: Convert to a decimal power base using 64-bit arithmetic. + let mut vr: u32; + let mut vp: u32; + let mut vm: u32; + let e10: i32; + let mut vm_is_trailing_zeros = false; + let mut vr_is_trailing_zeros = false; + let mut last_removed_digit = 0u8; + if e2 >= 0 { + let q = log10_pow2(e2); + e10 = q as i32; + let k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1; + let i = -e2 + q as i32 + k; + vr = mul_pow5_inv_div_pow2(mv, q, i); + vp = mul_pow5_inv_div_pow2(mp, q, i); + vm = mul_pow5_inv_div_pow2(mm, q, i); + if q != 0 && (vp - 1) / 10 <= vm / 10 { + // We need to know one removed digit even if we are not going to loop below. We could use + // q = X - 1 above, except that would require 33 bits for the result, and we've found that + // 32-bit arithmetic is faster even on 64-bit machines. + let l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32 - 1) - 1; + last_removed_digit = + (mul_pow5_inv_div_pow2(mv, q - 1, -e2 + q as i32 - 1 + l) % 10) as u8; + } + if q <= 9 { + // The largest power of 5 that fits in 24 bits is 5^10, but q <= 9 seems to be safe as well. + // Only one of mp, mv, and mm can be a multiple of 5, if any. + if mv % 5 == 0 { + vr_is_trailing_zeros = multiple_of_power_of_5(mv, q); + } else if accept_bounds { + vm_is_trailing_zeros = multiple_of_power_of_5(mm, q); + } else { + vp -= multiple_of_power_of_5(mp, q) as u32; + } + } + } else { + let q = log10_pow5(-e2); + e10 = q as i32 + e2; + let i = -e2 - q as i32; + let k = pow5bits(i) - FLOAT_POW5_BITCOUNT; + let mut j = q as i32 - k; + vr = mul_pow5_div_pow2(mv, i as u32, j); + vp = mul_pow5_div_pow2(mp, i as u32, j); + vm = mul_pow5_div_pow2(mm, i as u32, j); + if q != 0 && (vp - 1) / 10 <= vm / 10 { + j = q as i32 - 1 - (pow5bits(i + 1) - FLOAT_POW5_BITCOUNT); + last_removed_digit = (mul_pow5_div_pow2(mv, (i + 1) as u32, j) % 10) as u8; + } + if q <= 1 { + // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits. + // mv = 4 * m2, so it always has at least two trailing 0 bits. + vr_is_trailing_zeros = true; + if accept_bounds { + // mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1. + vm_is_trailing_zeros = mm_shift == 1; + } else { + // mp = mv + 2, so it always has at least one trailing 0 bit. + vp -= 1; + } + } else if q < 31 { + // TODO(ulfjack): Use a tighter bound here. + vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1); + } + } + + // Step 4: Find the shortest decimal representation in the interval of valid representations. + let mut removed = 0i32; + let output = if vm_is_trailing_zeros || vr_is_trailing_zeros { + // General case, which happens rarely (~4.0%). + while vp / 10 > vm / 10 { + vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0; + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + if vm_is_trailing_zeros { + while vm % 10 == 0 { + vr_is_trailing_zeros &= last_removed_digit == 0; + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + } + if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 { + // Round even if the exact number is .....50..0. + last_removed_digit = 4; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) + as u32 + } else { + // Specialized for the common case (~96.0%). Percentages below are relative to this. + // Loop iterations below (approximately): + // 0: 13.6%, 1: 70.7%, 2: 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01% + while vp / 10 > vm / 10 { + last_removed_digit = (vr % 10) as u8; + vr /= 10; + vp /= 10; + vm /= 10; + removed += 1; + } + // We need to take vr + 1 if vr is outside bounds or we need to round up. + vr + (vr == vm || last_removed_digit >= 5) as u32 + }; + let exp = e10 + removed; + + FloatingDecimal32 { + exponent: exp, + mantissa: output, + } +} + +#[cfg_attr(feature = "no-panic", inline)] +unsafe fn to_chars(v: FloatingDecimal32, sign: bool, result: *mut u8) -> usize { + // Step 5: Print the decimal representation. + let mut index = 0isize; + if sign { + *result.offset(index) = b'-'; + index += 1; + } + + let mut output = v.mantissa; + let olength = decimal_length(output); + + // Print the decimal digits. + // The following code is equivalent to: + // for (uint32_t i = 0; i < olength - 1; ++i) { + // const uint32_t c = output % 10; output /= 10; + // result[index + olength - i] = (char) ('0' + c); + // } + // result[index] = '0' + output % 10; + let mut i = 0isize; + while output >= 10000 { + let c = output - 10000 * (output / 10000); + output /= 10000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c0 as usize), + result.offset(index + olength as isize - i - 1), + 2, + ); + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c1 as usize), + result.offset(index + olength as isize - i - 3), + 2, + ); + i += 4; + } + if output >= 100 { + let c = (output % 100) << 1; + output /= 100; + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked(c as usize), + result.offset(index + olength as isize - i - 1), + 2, + ); + i += 2; + } + if output >= 10 { + let c = output << 1; + // We can't use memcpy here: the decimal dot goes between these two digits. + *result.offset(index + olength as isize - i) = *DIGIT_TABLE.get_unchecked(c as usize + 1); + *result.offset(index) = *DIGIT_TABLE.get_unchecked(c as usize); + } else { + *result.offset(index) = b'0' + output as u8; + } + + // Print decimal point if needed. + if olength > 1 { + *result.offset(index + 1) = b'.'; + index += olength as isize + 1; + } else { + index += 1; + } + + // Print the exponent. + *result.offset(index) = b'E'; + index += 1; + let mut exp = v.exponent + olength as i32 - 1; + if exp < 0 { + *result.offset(index) = b'-'; + index += 1; + exp = -exp; + } + + if exp >= 10 { + ptr::copy_nonoverlapping( + DIGIT_TABLE.get_unchecked((2 * exp) as usize), + result.offset(index), + 2, + ); + index += 2; + } else { + *result.offset(index) = b'0' + exp as u8; + index += 1; + } + + debug_assert!(index <= 15); + index as usize +} + +/// Print f32 to the given buffer and return number of bytes written. RyÅ«'s +/// original formatting. +/// +/// At most 15 bytes will be written. +/// +/// ## Special cases +/// +/// This function represents any NaN as `NaN`, positive infinity as `Infinity`, +/// and negative infinity as `-Infinity`. +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold RyÅ«'s representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// let f = 1.234f32; +/// +/// unsafe { +/// let mut buffer: [u8; 15] = std::mem::uninitialized(); +/// let n = ryu::raw::f2s_buffered_n(f, &mut buffer[0]); +/// let s = std::str::from_utf8_unchecked(&buffer[..n]); +/// assert_eq!(s, "1.234E0"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize { + // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. + let bits = mem::transmute::<f32, u32>(f); + + // Decode bits into sign, mantissa, and exponent. + let ieee_sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1); + let ieee_exponent = + ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32; + + // Case distinction; exit early for the easy cases. + if ieee_exponent == ((1u32 << FLOAT_EXPONENT_BITS) - 1) + || (ieee_exponent == 0 && ieee_mantissa == 0) + { + return copy_special_str(result, ieee_sign, ieee_exponent != 0, ieee_mantissa != 0); + } + + let v = f2d(ieee_mantissa, ieee_exponent); + to_chars(v, ieee_sign, result) +} diff --git a/ryu/src/lib.rs b/ryu/src/lib.rs new file mode 100644 index 000000000..332a2e557 --- /dev/null +++ b/ryu/src/lib.rs @@ -0,0 +1,126 @@ +//! Pure Rust implementation of RyÅ«, an algorithm to quickly convert floating +//! point numbers to decimal strings. +//! +//! The PLDI'18 paper [*RyÅ«: fast float-to-string conversion*][paper] by Ulf +//! Adams includes a complete correctness proof of the algorithm. The paper is +//! available under the creative commons CC-BY-SA license. +//! +//! This Rust implementation is a line-by-line port of Ulf Adams' implementation +//! in C, [https://github.com/ulfjack/ryu][upstream]. The [`ryu::raw`][raw] +//! module exposes exactly the API and formatting of the C implementation as +//! unsafe pure Rust functions. There is additionally a safe API as demonstrated +//! in the example code below. The safe API uses the same underlying RyÅ« +//! algorithm but diverges from the formatting of the C implementation to +//! produce more human-readable output, for example `0.3` rather than `3E-1`. +//! +//! [paper]: https://dl.acm.org/citation.cfm?id=3192369 +//! [upstream]: https://github.com/ulfjack/ryu +//! [raw]: raw/index.html +//! +//! # Example +//! +//! ```edition2018 +//! fn main() { +//! let mut buffer = ryu::Buffer::new(); +//! let printed = buffer.format(1.234); +//! assert_eq!(printed, "1.234"); +//! } +//! ``` +//! +//! ## Performance +//! +//! You can run upstream's benchmarks with: +//! +//! ```console +//! $ git clone https://github.com/ulfjack/ryu c-ryu +//! $ cd c-ryu +//! $ bazel run -c opt //ryu/benchmark +//! ``` +//! +//! And the same benchmark against our implementation with: +//! +//! ```console +//! $ git clone https://github.com/dtolnay/ryu rust-ryu +//! $ cd rust-ryu +//! $ cargo run --example upstream_benchmark --release +//! ``` +//! +//! These benchmarks measure the average time to print a 32-bit float and average +//! time to print a 64-bit float, where the inputs are distributed as uniform random +//! bit patterns 32 and 64 bits wide. +//! +//! The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API +//! all perform the same, taking around 21 nanoseconds to format a 32-bit float and +//! 31 nanoseconds to format a 64-bit float. +//! +//! There is also a Rust-specific benchmark comparing this implementation to the +//! standard library which you can run with: +//! +//! ```console +//! $ cargo bench +//! ``` +//! +//! The benchmark shows Ryu approximately 4-10x faster than the standard library +//! across a range of f32 and f64 inputs. Measurements are in nanoseconds per +//! iteration; smaller is better. +//! +//! | type=f32 | 0.0 | 0.1234 | 2.718281828459045 | f32::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 28ns | 23ns | 22ns | +//! | STD | 40ns | 106ns | 128ns | 110ns | +//! +//! | type=f64 | 0.0 | 0.1234 | 2.718281828459045 | f64::MAX | +//! |:--------:|:----:|:------:|:-----------------:|:--------:| +//! | RYU | 3ns | 50ns | 35ns | 32ns | +//! | STD | 39ns | 105ns | 128ns | 202ns | +//! +//! ## Formatting +//! +//! This library tends to produce more human-readable output than the standard +//! library's to\_string, which never uses scientific notation. Here are two +//! examples: +//! +//! - *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000 +//! - *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123 +//! +//! Both libraries print short decimals such as 0.0000123 without scientific +//! notation. + +#![no_std] +#![doc(html_root_url = "https://docs.rs/ryu/0.2.8")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr( + feature = "cargo-clippy", + allow( + cast_lossless, + cyclomatic_complexity, + many_single_char_names, + needless_pass_by_value, + unreadable_literal, + ) +)] + +#[cfg(feature = "no-panic")] +extern crate no_panic; + +mod buffer; +mod common; +mod d2s; +#[cfg(not(feature = "small"))] +mod d2s_full_table; +mod d2s_intrinsics; +#[cfg(feature = "small")] +mod d2s_small_table; +mod digit_table; +mod f2s; +mod pretty; + +pub use buffer::{Buffer, Float}; + +/// Unsafe functions that exactly mirror the API of the C implementation of RyÅ«. +pub mod raw { + pub use d2s::d2s_buffered_n; + pub use f2s::f2s_buffered_n; + pub use pretty::d2s_buffered_n as pretty_d2s_buffered_n; + pub use pretty::f2s_buffered_n as pretty_f2s_buffered_n; +} diff --git a/ryu/src/pretty/exponent.rs b/ryu/src/pretty/exponent.rs new file mode 100644 index 000000000..f10643f22 --- /dev/null +++ b/ryu/src/pretty/exponent.rs @@ -0,0 +1,49 @@ +use core::ptr; + +use digit_table::*; + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_exponent3(mut k: isize, mut result: *mut u8) -> usize { + let sign = k < 0; + if sign { + *result = b'-'; + result = result.offset(1); + k = -k; + } + + debug_assert!(k < 1000); + if k >= 100 { + *result = b'0' + (k / 100) as u8; + k %= 100; + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result.offset(1), 2); + sign as usize + 3 + } else if k >= 10 { + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result, 2); + sign as usize + 2 + } else { + *result = b'0' + k as u8; + sign as usize + 1 + } +} + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_exponent2(mut k: isize, mut result: *mut u8) -> usize { + let sign = k < 0; + if sign { + *result = b'-'; + result = result.offset(1); + k = -k; + } + + debug_assert!(k < 100); + if k >= 10 { + let d = DIGIT_TABLE.get_unchecked(k as usize * 2); + ptr::copy_nonoverlapping(d, result, 2); + sign as usize + 2 + } else { + *result = b'0' + k as u8; + sign as usize + 1 + } +} diff --git a/ryu/src/pretty/mantissa.rs b/ryu/src/pretty/mantissa.rs new file mode 100644 index 000000000..428023233 --- /dev/null +++ b/ryu/src/pretty/mantissa.rs @@ -0,0 +1,51 @@ +use core::ptr; + +use digit_table::*; + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_mantissa_long(mut output: u64, mut result: *mut u8) { + if (output >> 32) != 0 { + // One expensive 64-bit division. + let mut output2 = (output - 100_000_000 * (output / 100_000_000)) as u32; + output /= 100_000_000; + + let c = output2 % 10_000; + output2 /= 10_000; + let d = output2 % 10_000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + let d0 = (d % 100) << 1; + let d1 = (d / 100) << 1; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d0 as usize), result.offset(-6), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(d1 as usize), result.offset(-8), 2); + result = result.offset(-8); + } + write_mantissa(output as u32, result); +} + +#[cfg_attr(feature = "no-panic", inline)] +pub unsafe fn write_mantissa(mut output: u32, mut result: *mut u8) { + while output >= 10_000 { + let c = (output - 10_000 * (output / 10_000)) as u32; + output /= 10_000; + let c0 = (c % 100) << 1; + let c1 = (c / 100) << 1; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize), result.offset(-2), 2); + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize), result.offset(-4), 2); + result = result.offset(-4); + } + if output >= 100 { + let c = ((output % 100) << 1) as u32; + output /= 100; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); + result = result.offset(-2); + } + if output >= 10 { + let c = (output << 1) as u32; + ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize), result.offset(-2), 2); + } else { + *result.offset(-1) = b'0' + output as u8; + } +} diff --git a/ryu/src/pretty/mod.rs b/ryu/src/pretty/mod.rs new file mode 100644 index 000000000..e5f72c6a3 --- /dev/null +++ b/ryu/src/pretty/mod.rs @@ -0,0 +1,224 @@ +mod exponent; +mod mantissa; + +use core::{mem, ptr}; + +use self::exponent::*; +use self::mantissa::*; +use d2s; +use d2s::*; +use f2s; +use f2s::*; + +#[cfg(feature = "no-panic")] +use no_panic::no_panic; + +/// Print f64 to the given buffer and return number of bytes written. Human +/// readable formatting. +/// +/// At most 24 bytes will be written. +/// +/// ## Special cases +/// +/// This function **does not** check for NaN or infinity. If the input +/// number is not a finite float, the printed representation will be some +/// correctly formatted but unspecified numerical value. +/// +/// Please check [`is_finite`] yourself before calling this function, or +/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. +/// +/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite +/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan +/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold RyÅ«'s representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// let f = 1.234f64; +/// +/// unsafe { +/// let mut buffer: [u8; 24] = std::mem::uninitialized(); +/// let n = ryu::raw::pretty_d2s_buffered_n(f, &mut buffer[0]); +/// let s = std::str::from_utf8_unchecked(&buffer[..n]); +/// assert_eq!(s, "1.234"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn d2s_buffered_n(f: f64, result: *mut u8) -> usize { + let bits = mem::transmute::<f64, u64>(f); + let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1); + let ieee_exponent = + (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1); + + let mut index = 0isize; + if sign { + *result = b'-'; + index += 1; + } + + if ieee_exponent == 0 && ieee_mantissa == 0 { + ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3); + return sign as usize + 3; + } + + let v = d2d(ieee_mantissa, ieee_exponent); + + let length = d2s::decimal_length(v.mantissa) as isize; + let k = v.exponent as isize; + let kk = length + k; // 10^(kk-1) <= v < 10^kk + debug_assert!(k >= -324); + + if 0 <= k && kk <= 16 { + // 1234e7 -> 12340000000.0 + write_mantissa_long(v.mantissa, result.offset(index + length)); + for i in length..kk { + *result.offset(index + i) = b'0'; + } + *result.offset(index + kk) = b'.'; + *result.offset(index + kk + 1) = b'0'; + index as usize + kk as usize + 2 + } else if 0 < kk && kk <= 16 { + // 1234e-2 -> 12.34 + write_mantissa_long(v.mantissa, result.offset(index + length + 1)); + ptr::copy(result.offset(index + 1), result.offset(index), kk as usize); + *result.offset(index + kk) = b'.'; + index as usize + length as usize + 1 + } else if -5 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + *result.offset(index) = b'0'; + *result.offset(index + 1) = b'.'; + let offset = 2 - kk; + for i in 2..offset { + *result.offset(index + i) = b'0'; + } + write_mantissa_long(v.mantissa, result.offset(index + length + offset)); + index as usize + length as usize + offset as usize + } else if length == 1 { + // 1e30 + *result.offset(index) = b'0' + v.mantissa as u8; + *result.offset(index + 1) = b'e'; + index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2)) + } else { + // 1234e30 -> 1.234e33 + write_mantissa_long(v.mantissa, result.offset(index + length + 1)); + *result.offset(index) = *result.offset(index + 1); + *result.offset(index + 1) = b'.'; + *result.offset(index + length + 1) = b'e'; + index as usize + + length as usize + + 2 + + write_exponent3(kk - 1, result.offset(index + length + 2)) + } +} + +/// Print f32 to the given buffer and return number of bytes written. Human +/// readable formatting. +/// +/// At most 16 bytes will be written. +/// +/// ## Special cases +/// +/// This function **does not** check for NaN or infinity. If the input +/// number is not a finite float, the printed representation will be some +/// correctly formatted but unspecified numerical value. +/// +/// Please check [`is_finite`] yourself before calling this function, or +/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. +/// +/// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_finite +/// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_nan +/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f32.html#method.is_infinite +/// +/// ## Safety +/// +/// The `result` pointer argument must point to sufficiently many writable bytes +/// to hold RyÅ«'s representation of `f`. +/// +/// ## Example +/// +/// ```edition2018 +/// let f = 1.234f32; +/// +/// unsafe { +/// let mut buffer: [u8; 16] = std::mem::uninitialized(); +/// let n = ryu::raw::pretty_f2s_buffered_n(f, &mut buffer[0]); +/// let s = std::str::from_utf8_unchecked(&buffer[..n]); +/// assert_eq!(s, "1.234"); +/// } +/// ``` +#[cfg_attr(must_use_return, must_use)] +#[cfg_attr(feature = "no-panic", no_panic)] +pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize { + let bits = mem::transmute::<f32, u32>(f); + let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0; + let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1); + let ieee_exponent = + ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as u32; + + let mut index = 0isize; + if sign { + *result = b'-'; + index += 1; + } + + if ieee_exponent == 0 && ieee_mantissa == 0 { + ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3); + return sign as usize + 3; + } + + let v = f2d(ieee_mantissa, ieee_exponent); + + let length = f2s::decimal_length(v.mantissa) as isize; + let k = v.exponent as isize; + let kk = length + k; // 10^(kk-1) <= v < 10^kk + debug_assert!(k >= -45); + + if 0 <= k && kk <= 13 { + // 1234e7 -> 12340000000.0 + write_mantissa(v.mantissa, result.offset(index + length)); + for i in length..kk { + *result.offset(index + i) = b'0'; + } + *result.offset(index + kk) = b'.'; + *result.offset(index + kk + 1) = b'0'; + index as usize + kk as usize + 2 + } else if 0 < kk && kk <= 13 { + // 1234e-2 -> 12.34 + write_mantissa(v.mantissa, result.offset(index + length + 1)); + ptr::copy(result.offset(index + 1), result.offset(index), kk as usize); + *result.offset(index + kk) = b'.'; + index as usize + length as usize + 1 + } else if -6 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + *result.offset(index) = b'0'; + *result.offset(index + 1) = b'.'; + let offset = 2 - kk; + for i in 2..offset { + *result.offset(index + i) = b'0'; + } + write_mantissa(v.mantissa, result.offset(index + length + offset)); + index as usize + length as usize + offset as usize + } else if length == 1 { + // 1e30 + *result.offset(index) = b'0' + v.mantissa as u8; + *result.offset(index + 1) = b'e'; + index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2)) + } else { + // 1234e30 -> 1.234e33 + write_mantissa(v.mantissa, result.offset(index + length + 1)); + *result.offset(index) = *result.offset(index + 1); + *result.offset(index + 1) = b'.'; + *result.offset(index + length + 1) = b'e'; + index as usize + + length as usize + + 2 + + write_exponent2(kk - 1, result.offset(index + length + 2)) + } +} diff --git a/ryu/tests/d2s_table_test.rs b/ryu/tests/d2s_table_test.rs new file mode 100644 index 000000000..8f27726db --- /dev/null +++ b/ryu/tests/d2s_table_test.rs @@ -0,0 +1,52 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +#![allow(dead_code)] + +extern crate core; + +#[path = "../src/common.rs"] +mod common; + +#[path = "../src/d2s_full_table.rs"] +mod d2s_full_table; + +#[path = "../src/d2s_intrinsics.rs"] +mod d2s_intrinsics; + +#[path = "../src/d2s_small_table.rs"] +mod d2s_small_table; + +use d2s_full_table::*; +use d2s_small_table::*; + +#[test] +fn test_compute_pow5() { + for (i, entry) in DOUBLE_POW5_SPLIT.iter().enumerate() { + assert_eq!(*entry, unsafe { compute_pow5(i as u32) }, "entry {}", i); + } +} + +#[test] +fn test_compute_inv_pow5() { + for (i, entry) in DOUBLE_POW5_INV_SPLIT.iter().enumerate() { + assert_eq!(*entry, unsafe { compute_inv_pow5(i as u32) }, "entry {}", i); + } +} diff --git a/ryu/tests/d2s_test.rs b/ryu/tests/d2s_test.rs new file mode 100644 index 000000000..d4a26f05a --- /dev/null +++ b/ryu/tests/d2s_test.rs @@ -0,0 +1,224 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +extern crate rand; +extern crate ryu; + +#[macro_use] +mod macros; + +use std::{f64, str}; + +fn print(f: f64) -> String { + let mut bytes = [0u8; 24]; + let n = unsafe { ryu::raw::d2s_buffered_n(f, &mut bytes[0]) }; + let s = str::from_utf8(&bytes[..n]).unwrap(); + s.to_owned() +} + +fn pretty(f: f64) -> String { + ryu::Buffer::new().format(f).to_owned() +} + +fn ieee_parts_to_double(sign: bool, ieee_exponent: u32, ieee_mantissa: u64) -> f64 { + assert!(ieee_exponent <= 2047); + assert!(ieee_mantissa <= (1u64 << 53) - 1); + f64::from_bits(((sign as u64) << 63) | ((ieee_exponent as u64) << 52) | ieee_mantissa) +} + +#[test] +fn test_ryu() { + check!(3E-1, 0.3); + check!(1.234E15, 1234000000000000.0); + check!(1.234E16, 1.234e16); + check!(2.71828E0, 2.71828); + check!(1.1E128, 1.1e128); + check!(1.1E-64, 1.1e-64); + check!(2.718281828459045E0, 2.718281828459045); + check!(5E-324, 5e-324); + check!(1.7976931348623157E308, 1.7976931348623157e308); +} + +#[test] +fn test_random() { + let mut bytes = [0u8; 24]; + let mut buffer = ryu::Buffer::new(); + for _ in 0..1000000 { + let f = rand::random(); + let n = unsafe { ryu::raw::d2s_buffered_n(f, &mut bytes[0]) }; + assert_eq!(f, str::from_utf8(&bytes[..n]).unwrap().parse().unwrap()); + assert_eq!(f, buffer.format(f).parse().unwrap()); + } +} + +#[test] +fn test_non_finite() { + for i in 0u64..1 << 23 { + let f = f64::from_bits((((1 << 11) - 1) << 52) + (i << 29)); + assert!(!f.is_finite(), "f={}", f); + ryu::Buffer::new().format(f); + } +} + +#[test] +fn test_basic() { + check!(0E0, 0.0); + check!(-0E0, -0.0); + check!(1E0, 1.0); + check!(-1E0, -1.0); + assert_eq!(print(f64::NAN), "NaN"); + assert_eq!(print(f64::INFINITY), "Infinity"); + assert_eq!(print(f64::NEG_INFINITY), "-Infinity"); +} + +#[test] +fn test_switch_to_subnormal() { + check!(2.2250738585072014E-308, 2.2250738585072014e-308); +} + +#[test] +fn test_min_and_max() { + assert_eq!(f64::from_bits(0x7fefffffffffffff), 1.7976931348623157e308); + check!(1.7976931348623157E308, 1.7976931348623157e308); + assert_eq!(f64::from_bits(1), 5e-324); + check!(5E-324, 5e-324); +} + +#[test] +fn test_lots_of_trailing_zeros() { + check!(2.9802322387695312E-8, 2.9802322387695312e-8); +} + +#[test] +fn test_regression() { + check!(-2.109808898695963E16, -2.109808898695963e16); + check!(4.940656E-318, 4.940656e-318); + check!(1.18575755E-316, 1.18575755e-316); + check!(2.989102097996E-312, 2.989102097996e-312); + check!(9.0608011534336E15, 9060801153433600.0); + check!(4.708356024711512E18, 4.708356024711512e18); + check!(9.409340012568248E18, 9.409340012568248e18); + check!(1.2345678E0, 1.2345678); +} + +#[test] +fn test_looks_like_pow5() { + // These numbers have a mantissa that is a multiple of the largest power of + // 5 that fits, and an exponent that causes the computation for q to result + // in 22, which is a corner case for Ryu. + assert_eq!(f64::from_bits(0x4830F0CF064DD592), 5.764607523034235e39); + check!(5.764607523034235E39, 5.764607523034235e39); + assert_eq!(f64::from_bits(0x4840F0CF064DD592), 1.152921504606847e40); + check!(1.152921504606847E40, 1.152921504606847e40); + assert_eq!(f64::from_bits(0x4850F0CF064DD592), 2.305843009213694e40); + check!(2.305843009213694E40, 2.305843009213694e40); +} + +#[test] +fn test_output_length() { + check!(1E0, 1.0); // already tested in Basic + check!(1.2E0, 1.2); + check!(1.23E0, 1.23); + check!(1.234E0, 1.234); + check!(1.2345E0, 1.2345); + check!(1.23456E0, 1.23456); + check!(1.234567E0, 1.234567); + check!(1.2345678E0, 1.2345678); // already tested in Regression + check!(1.23456789E0, 1.23456789); + check!(1.234567895E0, 1.234567895); // 1.234567890 would be trimmed + check!(1.2345678901E0, 1.2345678901); + check!(1.23456789012E0, 1.23456789012); + check!(1.234567890123E0, 1.234567890123); + check!(1.2345678901234E0, 1.2345678901234); + check!(1.23456789012345E0, 1.23456789012345); + check!(1.234567890123456E0, 1.234567890123456); + check!(1.2345678901234567E0, 1.2345678901234567); + + // Test 32-bit chunking + check!(4.294967294E0, 4.294967294); // 2^32 - 2 + check!(4.294967295E0, 4.294967295); // 2^32 - 1 + check!(4.294967296E0, 4.294967296); // 2^32 + check!(4.294967297E0, 4.294967297); // 2^32 + 1 + check!(4.294967298E0, 4.294967298); // 2^32 + 2 +} + +// Test min, max shift values in shiftright128 +#[test] +fn test_min_max_shift() { + let max_mantissa = (1u64 << 53) - 1; + + // 32-bit opt-size=0: 49 <= dist <= 50 + // 32-bit opt-size=1: 30 <= dist <= 50 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 30 <= dist <= 50 + assert_eq!(1.7800590868057611E-307, ieee_parts_to_double(false, 4, 0)); + check!(1.7800590868057611E-307, 1.7800590868057611e-307); + // 32-bit opt-size=0: 49 <= dist <= 49 + // 32-bit opt-size=1: 28 <= dist <= 49 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 28 <= dist <= 50 + assert_eq!(2.8480945388892175E-306, ieee_parts_to_double(false, 6, max_mantissa)); + check!(2.8480945388892175E-306, 2.8480945388892175e-306); + // 32-bit opt-size=0: 52 <= dist <= 53 + // 32-bit opt-size=1: 2 <= dist <= 53 + // 64-bit opt-size=0: 53 <= dist <= 53 + // 64-bit opt-size=1: 2 <= dist <= 53 + assert_eq!(2.446494580089078E-296, ieee_parts_to_double(false, 41, 0)); + check!(2.446494580089078E-296, 2.446494580089078e-296); + // 32-bit opt-size=0: 52 <= dist <= 52 + // 32-bit opt-size=1: 2 <= dist <= 52 + // 64-bit opt-size=0: 53 <= dist <= 53 + // 64-bit opt-size=1: 2 <= dist <= 53 + assert_eq!(4.8929891601781557E-296, ieee_parts_to_double(false, 40, max_mantissa)); + check!(4.8929891601781557E-296, 4.8929891601781557e-296); + + // 32-bit opt-size=0: 57 <= dist <= 58 + // 32-bit opt-size=1: 57 <= dist <= 58 + // 64-bit opt-size=0: 58 <= dist <= 58 + // 64-bit opt-size=1: 58 <= dist <= 58 + assert_eq!(1.8014398509481984E16, ieee_parts_to_double(false, 1077, 0)); + check!(1.8014398509481984E16, 1.8014398509481984e16); + // 32-bit opt-size=0: 57 <= dist <= 57 + // 32-bit opt-size=1: 57 <= dist <= 57 + // 64-bit opt-size=0: 58 <= dist <= 58 + // 64-bit opt-size=1: 58 <= dist <= 58 + assert_eq!(3.6028797018963964E16, ieee_parts_to_double(false, 1076, max_mantissa)); + check!(3.6028797018963964E16, 3.6028797018963964e16); + // 32-bit opt-size=0: 51 <= dist <= 52 + // 32-bit opt-size=1: 51 <= dist <= 59 + // 64-bit opt-size=0: 52 <= dist <= 52 + // 64-bit opt-size=1: 52 <= dist <= 59 + assert_eq!(2.900835519859558E-216, ieee_parts_to_double(false, 307, 0)); + check!(2.900835519859558E-216, 2.900835519859558e-216); + // 32-bit opt-size=0: 51 <= dist <= 51 + // 32-bit opt-size=1: 51 <= dist <= 59 + // 64-bit opt-size=0: 52 <= dist <= 52 + // 64-bit opt-size=1: 52 <= dist <= 59 + assert_eq!(5.801671039719115E-216, ieee_parts_to_double(false, 306, max_mantissa)); + check!(5.801671039719115E-216, 5.801671039719115e-216); + + // https://github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483 + // 32-bit opt-size=0: 49 <= dist <= 49 + // 32-bit opt-size=1: 44 <= dist <= 49 + // 64-bit opt-size=0: 50 <= dist <= 50 + // 64-bit opt-size=1: 44 <= dist <= 50 + assert_eq!(3.196104012172126E-27, ieee_parts_to_double(false, 934, 0x000FA7161A4D6E0C)); + check!(3.196104012172126E-27, 3.196104012172126e-27); +} diff --git a/ryu/tests/exhaustive.rs b/ryu/tests/exhaustive.rs new file mode 100644 index 000000000..80e476e26 --- /dev/null +++ b/ryu/tests/exhaustive.rs @@ -0,0 +1,55 @@ +#![cfg(exhaustive)] + +extern crate num_cpus; +extern crate ryu; + +use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread; + +#[test] +fn test_exhaustive() { + const BATCH_SIZE: u32 = 1_000_000; + let counter = Arc::new(AtomicUsize::new(0)); + let finished = Arc::new(AtomicUsize::new(0)); + + let mut workers = Vec::new(); + for _ in 0..num_cpus::get() { + let counter = counter.clone(); + let finished = finished.clone(); + workers.push(thread::spawn(move || loop { + let batch = counter.fetch_add(1, Ordering::SeqCst) as u32; + if batch > u32::max_value() / BATCH_SIZE { + return; + } + + let min = batch * BATCH_SIZE; + let max = if batch == u32::max_value() / BATCH_SIZE { + u32::max_value() + } else { + min + BATCH_SIZE - 1 + }; + + let mut bytes = [0u8; 24]; + let mut buffer = ryu::Buffer::new(); + for u in min..=max { + let f = f32::from_bits(u); + if !f.is_finite() { + continue; + } + let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) }; + assert_eq!(Ok(Ok(f)), str::from_utf8(&bytes[..n]).map(str::parse)); + assert_eq!(Ok(f), buffer.format(f).parse()); + } + + let increment = (max - min + 1) as usize; + let update = finished.fetch_add(increment, Ordering::SeqCst); + println!("{}", update + increment); + })); + } + + for w in workers { + w.join().unwrap(); + } +} diff --git a/ryu/tests/f2s_test.rs b/ryu/tests/f2s_test.rs new file mode 100644 index 000000000..24cb814e2 --- /dev/null +++ b/ryu/tests/f2s_test.rs @@ -0,0 +1,183 @@ +// Translated from C to Rust. The original C code can be found at +// https://github.com/ulfjack/ryu and carries the following license: +// +// Copyright 2018 Ulf Adams +// +// The contents of this file may be used under the terms of the Apache License, +// Version 2.0. +// +// (See accompanying file LICENSE-Apache or copy at +// http://www.apache.org/licenses/LICENSE-2.0) +// +// Alternatively, the contents of this file may be used under the terms of +// the Boost Software License, Version 1.0. +// (See accompanying file LICENSE-Boost or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Unless required by applicable law or agreed to in writing, this software +// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. + +extern crate rand; +extern crate ryu; + +#[macro_use] +mod macros; + +use std::{f32, str}; + +fn print(f: f32) -> String { + let mut bytes = [0u8; 24]; + let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) }; + let s = str::from_utf8(&bytes[..n]).unwrap(); + s.to_owned() +} + +fn pretty(f: f32) -> String { + ryu::Buffer::new().format(f).to_owned() +} + +#[test] +fn test_ryu() { + check!(3E-1, 0.3); + check!(1.234E12, 1234000000000.0); + check!(1.234E13, 1.234e13); + check!(2.71828E0, 2.71828); + check!(1.1E32, 1.1e32); + check!(1.1E-32, 1.1e-32); + check!(2.7182817E0, 2.7182817); + check!(1E-45, 1e-45); + check!(3.4028235E38, 3.4028235e38); + check!(-1.234E-3, -0.001234); +} + +#[test] +fn test_random() { + let mut bytes = [0u8; 24]; + let mut buffer = ryu::Buffer::new(); + for _ in 0..1000000 { + let f = rand::random(); + let n = unsafe { ryu::raw::f2s_buffered_n(f, &mut bytes[0]) }; + assert_eq!(f, str::from_utf8(&bytes[..n]).unwrap().parse().unwrap()); + assert_eq!(f, buffer.format(f).parse().unwrap()); + } +} + +#[test] +fn test_non_finite() { + for i in 0u32..1 << 23 { + let f = f32::from_bits((((1 << 8) - 1) << 23) + i); + assert!(!f.is_finite(), "f={}", f); + ryu::Buffer::new().format(f); + } +} + +#[test] +fn test_basic() { + check!(0E0, 0.0); + check!(-0E0, -0.0); + check!(1E0, 1.0); + check!(-1E0, -1.0); + assert_eq!(print(f32::NAN), "NaN"); + assert_eq!(print(f32::INFINITY), "Infinity"); + assert_eq!(print(f32::NEG_INFINITY), "-Infinity"); +} + +#[test] +fn test_switch_to_subnormal() { + check!(1.1754944E-38, 1.1754944e-38); +} + +#[test] +fn test_min_and_max() { + assert_eq!(f32::from_bits(0x7f7fffff), 3.4028235e38); + check!(3.4028235E38, 3.4028235e38); + assert_eq!(f32::from_bits(1), 1e-45); + check!(1E-45, 1e-45); +} + +// Check that we return the exact boundary if it is the shortest +// representation, but only if the original floating point number is even. +#[test] +fn test_boundary_round_even() { + check!(3.355445E7, 33554450.0); + check!(9E9, 9000000000.0); + check!(3.436672E10, 34366720000.0); +} + +// If the exact value is exactly halfway between two shortest representations, +// then we round to even. It seems like this only makes a difference if the +// last two digits are ...2|5 or ...7|5, and we cut off the 5. +#[test] +fn test_exact_value_round_even() { + check!(3.0540412E5, 305404.12); + check!(8.0990312E3, 8099.0312); +} + +#[test] +fn test_lots_of_trailing_zeros() { + // Pattern for the first test: 00111001100000000000000000000000 + check!(2.4414062E-4, 0.00024414062); + check!(2.4414062E-3, 0.0024414062); + check!(4.3945312E-3, 0.0043945312); + check!(6.3476562E-3, 0.0063476562); +} + +#[test] +fn test_regression() { + check!(4.7223665E21, 4.7223665e21); + check!(8.388608E6, 8388608.0); + check!(1.6777216E7, 16777216.0); + check!(3.3554436E7, 33554436.0); + check!(6.7131496E7, 67131496.0); + check!(1.9310392E-38, 1.9310392e-38); + check!(-2.47E-43, -2.47e-43); + check!(1.993244E-38, 1.993244e-38); + check!(4.1039004E3, 4103.9004); + check!(5.3399997E9, 5339999700.0); + check!(6.0898E-39, 6.0898e-39); + check!(1.0310042E-3, 0.0010310042); + check!(2.882326E17, 2.882326e17); + check!(7.038531E-26, 7.038531e-26); + check!(9.223404E17, 9.223404e17); + check!(6.710887E7, 67108870.0); + check!(1E-44, 1e-44); + check!(2.816025E14, 2.816025e14); + check!(9.223372E18, 9.223372e18); + check!(1.5846086E29, 1.5846086e29); + check!(1.1811161E19, 1.1811161e19); + check!(5.368709E18, 5.368709e18); + check!(4.6143166E18, 4.6143166e18); + check!(7.812537E-3, 0.007812537); + check!(1E-45, 1e-45); + check!(1.18697725E20, 1.18697725e20); + check!(1.00014165E-36, 1.00014165e-36); + check!(2E2, 200.0); + check!(3.3554432E7, 33554432.0); +} + +#[test] +fn test_looks_like_pow5() { + // These numbers have a mantissa that is the largest power of 5 that fits, + // and an exponent that causes the computation for q to result in 10, which + // is a corner case for Ryu. + assert_eq!(f32::from_bits(0x5D1502F9), 6.7108864e17); + check!(6.7108864E17, 6.7108864e17); + assert_eq!(f32::from_bits(0x5D9502F9), 1.3421773e18); + check!(1.3421773E18, 1.3421773e18); + assert_eq!(f32::from_bits(0x5E1502F9), 2.6843546e18); + check!(2.6843546E18, 2.6843546e18); +} + +#[test] +fn test_output_length() { + check!(1E0, 1.0); // already tested in Basic + check!(1.2E0, 1.2); + check!(1.23E0, 1.23); + check!(1.234E0, 1.234); + check!(1.2345E0, 1.2345); + check!(1.23456E0, 1.23456); + check!(1.234567E0, 1.234567); + check!(1.2345678E0, 1.2345678); + check!(1.23456735E-36, 1.23456735e-36); +} diff --git a/ryu/tests/macros/mod.rs b/ryu/tests/macros/mod.rs new file mode 100644 index 000000000..09cd218b9 --- /dev/null +++ b/ryu/tests/macros/mod.rs @@ -0,0 +1,12 @@ +macro_rules! check { + ($ryu:tt, $pretty:tt) => { + assert_eq!($ryu, $pretty); + assert_eq!(print($ryu), stringify!($ryu)); + assert_eq!(pretty($pretty), stringify!($pretty)); + }; + (-$ryu:tt, -$pretty:tt) => { + assert_eq!(-$ryu, -$pretty); + assert_eq!(print(-$ryu), concat!("-", stringify!($ryu))); + assert_eq!(pretty(-$pretty), concat!("-", stringify!($pretty))); + }; +} diff --git a/same-file/.cargo-checksum.json b/same-file/.cargo-checksum.json new file mode 100644 index 000000000..4d08738b6 --- /dev/null +++ b/same-file/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"} \ No newline at end of file diff --git a/same-file/COPYING b/same-file/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/same-file/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/same-file/Cargo.toml b/same-file/Cargo.toml new file mode 100644 index 000000000..cb3ab928f --- /dev/null +++ b/same-file/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "same-file" +version = "1.0.4" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A simple crate for determining whether two file paths point to the same file.\n" +homepage = "https://github.com/BurntSushi/same-file" +documentation = "https://docs.rs/same-file" +readme = "README.md" +keywords = ["same", "file", "equal", "inode"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/same-file" +[dev-dependencies.rand] +version = "0.4" +[target."cfg(windows)".dependencies.winapi-util] +version = "0.1.1" diff --git a/same-file/LICENSE-MIT b/same-file/LICENSE-MIT new file mode 100644 index 000000000..3303149e5 --- /dev/null +++ b/same-file/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/same-file/README.md b/same-file/README.md new file mode 100644 index 000000000..2a114b9a4 --- /dev/null +++ b/same-file/README.md @@ -0,0 +1,45 @@ +same-file +========= +A safe and simple **cross platform** crate to determine whether two files or +directories are the same. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/same-file.png)](https://travis-ci.org/BurntSushi/same-file) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/same-file?svg=true)](https://ci.appveyor.com/project/BurntSushi/same-file) +[![](http://meritbadge.herokuapp.com/same-file)](https://crates.io/crates/same-file) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +https://docs.rs/same-file + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +same-file = "1" +``` + +and this to your crate root: + +```rust +extern crate same_file; +``` + +### Example + +The simplest use of this crate is to use the `is_same_file` function, which +takes two file paths and returns true if and only if they refer to the same +file: + +```rust +extern crate same_file; + +use same_file::is_same_file; + +fn main() { + assert!(is_same_file("/bin/sh", "/usr/bin/sh").unwrap()); +} +``` diff --git a/same-file/UNLICENSE b/same-file/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/same-file/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/same-file/examples/is_same_file.rs b/same-file/examples/is_same_file.rs new file mode 100644 index 000000000..451a6af89 --- /dev/null +++ b/same-file/examples/is_same_file.rs @@ -0,0 +1,13 @@ +extern crate same_file; + +use std::error::Error; +use same_file::is_same_file; + +fn try_main() -> Result<(), Box<Error>> { + assert!(is_same_file("/bin/sh", "/usr/bin/sh")?); + Ok(()) +} + +fn main() { + try_main().unwrap(); +} diff --git a/same-file/examples/is_stderr.rs b/same-file/examples/is_stderr.rs new file mode 100644 index 000000000..8ddf8493f --- /dev/null +++ b/same-file/examples/is_stderr.rs @@ -0,0 +1,33 @@ +extern crate same_file; + +use std::io; +use std::process; + +use same_file::Handle; + +fn main() { + if let Err(err) = run() { + println!("{}", err); + process::exit(1); + } +} + +fn run() -> io::Result<()> { + // Run with `cargo run --example is_stderr 2> examples/stderr` to see + // interesting output. + let candidates = &[ + "examples/is_same_file.rs", + "examples/is_stderr.rs", + "examples/stderr", + ]; + let stderr_handle = Handle::stderr()?; + for candidate in candidates { + let handle = Handle::from_path(candidate)?; + if stderr_handle == handle { + println!("{:?} is stderr!", candidate); + } else { + println!("{:?} is NOT stderr!", candidate); + } + } + Ok(()) +} diff --git a/same-file/src/lib.rs b/same-file/src/lib.rs new file mode 100644 index 000000000..69831db7b --- /dev/null +++ b/same-file/src/lib.rs @@ -0,0 +1,530 @@ +/*! +This crate provides a safe and simple **cross platform** way to determine +whether two file paths refer to the same file or directory. + +Most uses of this crate should be limited to the top-level [`is_same_file`] +function, which takes two file paths and returns true if they refer to the +same file or directory: + +```rust,no_run +# use std::error::Error; +use same_file::is_same_file; + +# fn try_main() -> Result<(), Box<Error>> { +assert!(is_same_file("/bin/sh", "/usr/bin/sh")?); +# Ok(()) +# } +# +# fn main() { +# try_main().unwrap(); +# } +``` + +Additionally, this crate provides a [`Handle`] type that permits a more efficient +equality check depending on your access pattern. For example, if one wanted to +check whether any path in a list of paths corresponded to the process' stdout +handle, then one could build a handle once for stdout. The equality check for +each file in the list then only requires one stat call instead of two. The code +might look like this: + +```rust,no_run +# use std::error::Error; +use same_file::Handle; + +# fn try_main() -> Result<(), Box<Error>> { +let candidates = &[ + "examples/is_same_file.rs", + "examples/is_stderr.rs", + "examples/stderr", +]; +let stdout_handle = Handle::stdout()?; +for candidate in candidates { + let handle = Handle::from_path(candidate)?; + if stdout_handle == handle { + println!("{:?} is stdout!", candidate); + } else { + println!("{:?} is NOT stdout!", candidate); + } +} +# Ok(()) +# } +# +# fn main() { +# try_main().unwrap(); +# } +``` + +See [`examples/is_stderr.rs`] for a runnable example and compare the output of: + +- `cargo run --example is_stderr 2> examples/stderr` and +- `cargo run --example is_stderr`. + +[`is_same_file`]: fn.is_same_file.html +[`Handle`]: struct.Handle.html +[`examples/is_stderr.rs`]: https://github.com/BurntSushi/same-file/blob/master/examples/is_same_file.rs + +*/ + +#![doc(html_root_url = "https://docs.rs/same-file/1.0.0")] +#![deny(missing_docs)] + +#[cfg(windows)] +extern crate winapi_util; + +use std::fs::File; +use std::io; +use std::path::Path; + +#[cfg(any(target_os = "redox", unix))] +use unix as imp; +#[cfg(windows)] +use win as imp; + +#[cfg(any(target_os = "redox", unix))] +mod unix; +#[cfg(windows)] +mod win; + +/// A handle to a file that can be tested for equality with other handles. +/// +/// If two files are the same, then any two handles of those files will compare +/// equal. If two files are not the same, then any two handles of those files +/// will compare not-equal. +/// +/// A handle consumes an open file resource as long as it exists. +/// +/// Equality is determined by comparing inode numbers on Unix and a combination +/// of identifier, volume serial, and file size on Windows. Note that it's +/// possible for comparing two handles to produce a false positive on some +/// platforms. Namely, two handles can compare equal even if the two handles +/// *don't* point to the same file. Check the [source] for specific +/// implementation details. +/// +/// [source]: https://github.com/BurntSushi/same-file/tree/master/src +#[derive(Debug, Eq, PartialEq)] +pub struct Handle(imp::Handle); + +impl Handle { + /// Construct a handle from a path. + /// + /// Note that the underlying [`File`] is opened in read-only mode on all + /// platforms. + /// + /// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html + /// + /// # Errors + /// This method will return an [`io::Error`] if the path cannot + /// be opened, or the file's metadata cannot be obtained. + /// The most common reasons for this are: the path does not + /// exist, or there were not enough permissions. + /// + /// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html + /// + /// # Examples + /// Check that two paths are not the same file: + /// + /// ```rust,no_run + /// # use std::error::Error; + /// use same_file::Handle; + /// + /// # fn try_main() -> Result<(), Box<Error>> { + /// let source = Handle::from_path("./source")?; + /// let target = Handle::from_path("./target")?; + /// assert_ne!(source, target, "The files are the same."); + /// # Ok(()) + /// # } + /// # + /// # fn main() { + /// # try_main().unwrap(); + /// # } + /// ``` + pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> { + imp::Handle::from_path(p).map(Handle) + } + + /// Construct a handle from a file. + /// + /// # Errors + /// This method will return an [`io::Error`] if the metadata for + /// the given [`File`] cannot be obtained. + /// + /// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html + /// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html + /// + /// # Examples + /// Check that two files are not in fact the same file: + /// + /// ```rust,no_run + /// # use std::error::Error; + /// # use std::fs::File; + /// use same_file::Handle; + /// + /// # fn try_main() -> Result<(), Box<Error>> { + /// let source = File::open("./source")?; + /// let target = File::open("./target")?; + /// + /// assert_ne!( + /// Handle::from_file(source)?, + /// Handle::from_file(target)?, + /// "The files are the same." + /// ); + /// # Ok(()) + /// # } + /// # + /// # fn main() { + /// # try_main().unwrap(); + /// # } + /// ``` + pub fn from_file(file: File) -> io::Result<Handle> { + imp::Handle::from_file(file).map(Handle) + } + + /// Construct a handle from stdin. + /// + /// # Errors + /// This method will return an [`io::Error`] if stdin cannot + /// be opened due to any I/O-related reason. + /// + /// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html + /// + /// # Examples + /// + /// ```rust + /// # use std::error::Error; + /// use same_file::Handle; + /// + /// # fn try_main() -> Result<(), Box<Error>> { + /// let stdin = Handle::stdin()?; + /// let stdout = Handle::stdout()?; + /// let stderr = Handle::stderr()?; + /// + /// if stdin == stdout { + /// println!("stdin == stdout"); + /// } + /// if stdin == stderr { + /// println!("stdin == stderr"); + /// } + /// if stdout == stderr { + /// println!("stdout == stderr"); + /// } + /// # + /// # Ok(()) + /// # } + /// # + /// # fn main() { + /// # try_main().unwrap(); + /// # } + /// ``` + /// + /// The output differs depending on the platform. + /// + /// On Linux: + /// + /// ```text + /// $ ./example + /// stdin == stdout + /// stdin == stderr + /// stdout == stderr + /// $ ./example > result + /// $ cat result + /// stdin == stderr + /// $ ./example > result 2>&1 + /// $ cat result + /// stdout == stderr + /// ``` + /// + /// Windows: + /// + /// ```text + /// > example + /// > example > result 2>&1 + /// > type result + /// stdout == stderr + /// ``` + pub fn stdin() -> io::Result<Handle> { + imp::Handle::stdin().map(Handle) + } + + /// Construct a handle from stdout. + /// + /// # Errors + /// This method will return an [`io::Error`] if stdout cannot + /// be opened due to any I/O-related reason. + /// + /// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html + /// + /// # Examples + /// See the example for [`stdin()`]. + /// + /// [`stdin()`]: #method.stdin + pub fn stdout() -> io::Result<Handle> { + imp::Handle::stdout().map(Handle) + } + + /// Construct a handle from stderr. + /// + /// # Errors + /// This method will return an [`io::Error`] if stderr cannot + /// be opened due to any I/O-related reason. + /// + /// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html + /// + /// # Examples + /// See the example for [`stdin()`]. + /// + /// [`stdin()`]: #method.stdin + pub fn stderr() -> io::Result<Handle> { + imp::Handle::stderr().map(Handle) + } + + /// Return a reference to the underlying file. + /// + /// # Examples + /// Ensure that the target file is not the same as the source one, + /// and copy the data to it: + /// + /// ```rust,no_run + /// # use std::error::Error; + /// use std::io::prelude::*; + /// use std::io::Write; + /// use std::fs::File; + /// use same_file::Handle; + /// + /// # fn try_main() -> Result<(), Box<Error>> { + /// let source = File::open("source")?; + /// let target = File::create("target")?; + /// + /// let source_handle = Handle::from_file(source)?; + /// let mut target_handle = Handle::from_file(target)?; + /// assert_ne!(source_handle, target_handle, "The files are the same."); + /// + /// let mut source = source_handle.as_file(); + /// let target = target_handle.as_file_mut(); + /// + /// let mut buffer = Vec::new(); + /// // data copy is simplified for the purposes of the example + /// source.read_to_end(&mut buffer)?; + /// target.write_all(&buffer)?; + /// # + /// # Ok(()) + /// # } + /// # + /// # fn main() { + /// # try_main().unwrap(); + /// # } + /// ``` + pub fn as_file(&self) -> &File { + self.0.as_file() + } + + /// Return a mutable reference to the underlying file. + /// + /// # Examples + /// See the example for [`as_file()`]. + /// + /// [`as_file()`]: #method.as_file + pub fn as_file_mut(&mut self) -> &mut File { + self.0.as_file_mut() + } + + /// Return the underlying device number of this handle. + /// + /// Note that this only works on unix platforms. + #[cfg(any(target_os = "redox", unix))] + pub fn dev(&self) -> u64 { + self.0.dev() + } + + /// Return the underlying inode number of this handle. + /// + /// Note that this only works on unix platforms. + #[cfg(any(target_os = "redox", unix))] + pub fn ino(&self) -> u64 { + self.0.ino() + } +} + +/// Returns true if the two file paths may correspond to the same file. +/// +/// Note that it's possible for this to produce a false positive on some +/// platforms. Namely, this can return true even if the two file paths *don't* +/// resolve to the same file. +/// # Errors +/// This function will return an [`io::Error`] if any of the two paths cannot +/// be opened. The most common reasons for this are: the path does not exist, +/// or there were not enough permissions. +/// +/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html +/// +/// # Example +/// +/// ```rust,no_run +/// use same_file::is_same_file; +/// +/// assert!(is_same_file("./foo", "././foo").unwrap_or(false)); +/// ``` +pub fn is_same_file<P, Q>( + path1: P, + path2: Q, +) -> io::Result<bool> where P: AsRef<Path>, Q: AsRef<Path> { + Ok(Handle::from_path(path1)? == Handle::from_path(path2)?) +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use std::env; + use std::fs::{self, File}; + use std::io; + use std::path::{Path, PathBuf}; + + use self::rand::Rng; + + use super::is_same_file; + + struct TempDir(PathBuf); + + impl TempDir { + fn path<'a>(&'a self) -> &'a Path { + &self.0 + } + } + + impl Drop for TempDir { + fn drop(&mut self) { + fs::remove_dir_all(&self.0).unwrap(); + } + } + + fn tmpdir() -> TempDir { + let p = env::temp_dir(); + let mut r = self::rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); + fs::create_dir(&ret).unwrap(); + TempDir(ret) + } + + #[cfg(unix)] + pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, + ) -> io::Result<()> { + use std::os::unix::fs::symlink; + symlink(src, dst) + } + + #[cfg(unix)] + pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, + ) -> io::Result<()> { + soft_link_dir(src, dst) + } + + #[cfg(windows)] + pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, + ) -> io::Result<()> { + use std::os::windows::fs::symlink_dir; + symlink_dir(src, dst) + } + + #[cfg(windows)] + pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, + ) -> io::Result<()> { + use std::os::windows::fs::symlink_file; + symlink_file(src, dst) + } + + // These tests are rather uninteresting. The really interesting tests + // would stress the edge cases. On Unix, this might be comparing two files + // on different mount points with the same inode number. On Windows, this + // might be comparing two files whose file indices are the same on file + // systems where such things aren't guaranteed to be unique. + // + // Alas, I don't know how to create those environmental conditions. ---AG + + #[test] + fn same_file_trivial() { + let tdir = tmpdir(); + let dir = tdir.path(); + + File::create(dir.join("a")).unwrap(); + assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap()); + } + + #[test] + fn same_dir_trivial() { + let tdir = tmpdir(); + let dir = tdir.path(); + + fs::create_dir(dir.join("a")).unwrap(); + assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap()); + } + + #[test] + fn not_same_file_trivial() { + let tdir = tmpdir(); + let dir = tdir.path(); + + File::create(dir.join("a")).unwrap(); + File::create(dir.join("b")).unwrap(); + assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap()); + } + + #[test] + fn not_same_dir_trivial() { + let tdir = tmpdir(); + let dir = tdir.path(); + + fs::create_dir(dir.join("a")).unwrap(); + fs::create_dir(dir.join("b")).unwrap(); + assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap()); + } + + #[test] + fn same_file_hard() { + let tdir = tmpdir(); + let dir = tdir.path(); + + File::create(dir.join("a")).unwrap(); + fs::hard_link(dir.join("a"), dir.join("alink")).unwrap(); + assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap()); + } + + #[test] + fn same_file_soft() { + let tdir = tmpdir(); + let dir = tdir.path(); + + File::create(dir.join("a")).unwrap(); + soft_link_file(dir.join("a"), dir.join("alink")).unwrap(); + assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap()); + } + + #[test] + fn same_dir_soft() { + let tdir = tmpdir(); + let dir = tdir.path(); + + fs::create_dir(dir.join("a")).unwrap(); + soft_link_dir(dir.join("a"), dir.join("alink")).unwrap(); + assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap()); + } + + #[test] + fn test_send() { + fn assert_send<T: Send>() {} + assert_send::<super::Handle>(); + } + + #[test] + fn test_sync() { + fn assert_sync<T: Sync>() {} + assert_sync::<super::Handle>(); + } +} diff --git a/same-file/src/unix.rs b/same-file/src/unix.rs new file mode 100644 index 000000000..d232cd5c4 --- /dev/null +++ b/same-file/src/unix.rs @@ -0,0 +1,112 @@ +use std::fs::{File, OpenOptions}; +use std::hash::{Hash, Hasher}; +use std::io; +use std::os::unix::fs::MetadataExt; +use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use std::path::Path; + +#[derive(Debug)] +pub struct Handle { + file: Option<File>, + // If is_std is true, then we don't drop the corresponding File since it + // will close the handle. + is_std: bool, + dev: u64, + ino: u64, +} + +impl Drop for Handle { + fn drop(&mut self) { + if self.is_std { + // unwrap() will not panic. Since we were able to open an + // std stream successfully, then `file` is guaranteed to be Some() + self.file.take().unwrap().into_raw_fd(); + } + } +} + +impl Eq for Handle {} + +impl PartialEq for Handle { + fn eq(&self, other: &Handle) -> bool { + (self.dev, self.ino) == (other.dev, other.ino) + } +} + +impl AsRawFd for ::Handle { + fn as_raw_fd(&self) -> RawFd { + // unwrap() will not panic. Since we were able to open the + // file successfully, then `file` is guaranteed to be Some() + self.0.file.as_ref().take().unwrap().as_raw_fd() + } +} + +impl IntoRawFd for ::Handle { + fn into_raw_fd(mut self) -> RawFd { + // unwrap() will not panic. Since we were able to open the + // file successfully, then `file` is guaranteed to be Some() + self.0.file.take().unwrap().into_raw_fd() + } +} + +impl Hash for Handle { + fn hash<H: Hasher>(&self, state: &mut H) { + self.dev.hash(state); + self.ino.hash(state); + } +} + +impl Handle { + pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> { + Handle::from_file(OpenOptions::new().read(true).open(p)?) + } + + pub fn from_file(file: File) -> io::Result<Handle> { + let md = file.metadata()?; + Ok(Handle { + file: Some(file), + is_std: false, + dev: md.dev(), + ino: md.ino(), + }) + } + + pub fn from_std(file: File) -> io::Result<Handle> { + Handle::from_file(file).map(|mut h| { + h.is_std = true; + h + }) + } + + pub fn stdin() -> io::Result<Handle> { + Handle::from_std(unsafe { File::from_raw_fd(0) }) + } + + pub fn stdout() -> io::Result<Handle> { + Handle::from_std(unsafe { File::from_raw_fd(1) }) + } + + pub fn stderr() -> io::Result<Handle> { + Handle::from_std(unsafe { File::from_raw_fd(2) }) + } + + pub fn as_file(&self) -> &File { + // unwrap() will not panic. Since we were able to open the + // file successfully, then `file` is guaranteed to be Some() + self.file.as_ref().take().unwrap() + } + + pub fn as_file_mut(&mut self) -> &mut File { + // unwrap() will not panic. Since we were able to open the + // file successfully, then `file` is guaranteed to be Some() + self.file.as_mut().take().unwrap() + } + + pub fn dev(&self) -> u64 { + self.dev + } + + pub fn ino(&self) -> u64 { + self.ino + } +} diff --git a/same-file/src/win.rs b/same-file/src/win.rs new file mode 100644 index 000000000..46d842d99 --- /dev/null +++ b/same-file/src/win.rs @@ -0,0 +1,174 @@ +use std::fs::File; +use std::hash::{Hash, Hasher}; +use std::io; +use std::os::windows::io::{ + AsRawHandle, IntoRawHandle, RawHandle, +}; +use std::path::Path; + +use winapi_util as winutil; + +// For correctness, it is critical that both file handles remain open while +// their attributes are checked for equality. In particular, the file index +// numbers on a Windows stat object are not guaranteed to remain stable over +// time. +// +// See the docs and remarks on MSDN: +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx +// +// It gets worse. It appears that the index numbers are not always +// guaranteed to be unique. Namely, ReFS uses 128 bit numbers for unique +// identifiers. This requires a distinct syscall to get `FILE_ID_INFO` +// documented here: +// https://msdn.microsoft.com/en-us/library/windows/desktop/hh802691(v=vs.85).aspx +// +// It seems straight-forward enough to modify this code to use +// `FILE_ID_INFO` when available (minimum Windows Server 2012), but I don't +// have access to such Windows machines. +// +// Two notes. +// +// 1. Java's NIO uses the approach implemented here and appears to ignore +// `FILE_ID_INFO` altogether. So Java's NIO and this code are +// susceptible to bugs when running on a file system where +// `nFileIndex{Low,High}` are not unique. +// +// 2. LLVM has a bug where they fetch the id of a file and continue to use +// it even after the handle has been closed, so that uniqueness is no +// longer guaranteed (when `nFileIndex{Low,High}` are unique). +// bug report: http://lists.llvm.org/pipermail/llvm-bugs/2014-December/037218.html +// +// All said and done, checking whether two files are the same on Windows +// seems quite tricky. Moreover, even if the code is technically incorrect, +// it seems like the chances of actually observing incorrect behavior are +// extremely small. Nevertheless, we mitigate this by checking size too. +// +// In the case where this code is erroneous, two files will be reported +// as equivalent when they are in fact distinct. This will cause the loop +// detection code to report a false positive, which will prevent descending +// into the offending directory. As far as failure modes goes, this isn't +// that bad. + +#[derive(Debug)] +pub struct Handle { + kind: HandleKind, + key: Option<Key>, +} + +#[derive(Debug)] +enum HandleKind { + /// Used when opening a file or acquiring ownership of a file. + Owned(winutil::Handle), + /// Used for stdio. + Borrowed(winutil::HandleRef), +} + +#[derive(Debug, Eq, PartialEq, Hash)] +struct Key { + volume: u64, + index: u64, +} + +impl Eq for Handle {} + +impl PartialEq for Handle { + fn eq(&self, other: &Handle) -> bool { + // Need this branch to satisfy `Eq` since `Handle`s with + // `key.is_none()` wouldn't otherwise. + if self as *const Handle == other as *const Handle { + return true; + } else if self.key.is_none() || other.key.is_none() { + return false; + } + self.key == other.key + } +} + +impl AsRawHandle for ::Handle { + fn as_raw_handle(&self) -> RawHandle { + match self.0.kind { + HandleKind::Owned(ref h) => h.as_raw_handle(), + HandleKind::Borrowed(ref h) => h.as_raw_handle(), + } + } +} + +impl IntoRawHandle for ::Handle { + fn into_raw_handle(self) -> RawHandle { + match self.0.kind { + HandleKind::Owned(h) => h.into_raw_handle(), + HandleKind::Borrowed(h) => h.as_raw_handle(), + } + } +} + +impl Hash for Handle { + fn hash<H: Hasher>(&self, state: &mut H) { + self.key.hash(state); + } +} + +impl Handle { + pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> { + let h = winutil::Handle::from_path_any(p)?; + let info = winutil::file::information(&h)?; + Ok(Handle::from_info(HandleKind::Owned(h), info)) + } + + pub fn from_file(file: File) -> io::Result<Handle> { + let h = winutil::Handle::from_file(file); + let info = winutil::file::information(&h)?; + Ok(Handle::from_info(HandleKind::Owned(h), info)) + } + + fn from_std_handle(h: winutil::HandleRef) -> io::Result<Handle> { + match winutil::file::information(&h) { + Ok(info) => Ok(Handle::from_info(HandleKind::Borrowed(h), info)), + // In a Windows console, if there is no pipe attached to a STD + // handle, then GetFileInformationByHandle will return an error. + // We don't really care. The only thing we care about is that + // this handle is never equivalent to any other handle, which is + // accomplished by setting key to None. + Err(_) => Ok(Handle { kind: HandleKind::Borrowed(h), key: None }), + } + } + + fn from_info( + kind: HandleKind, + info: winutil::file::Information, + ) -> Handle { + Handle { + kind: kind, + key: Some(Key { + volume: info.volume_serial_number(), + index: info.file_index(), + }), + } + } + + pub fn stdin() -> io::Result<Handle> { + Handle::from_std_handle(winutil::HandleRef::stdin()) + } + + pub fn stdout() -> io::Result<Handle> { + Handle::from_std_handle(winutil::HandleRef::stdout()) + } + + pub fn stderr() -> io::Result<Handle> { + Handle::from_std_handle(winutil::HandleRef::stderr()) + } + + pub fn as_file(&self) -> &File { + match self.kind { + HandleKind::Owned(ref h) => h.as_file(), + HandleKind::Borrowed(ref h) => h.as_file(), + } + } + + pub fn as_file_mut(&mut self) -> &mut File { + match self.kind { + HandleKind::Owned(ref mut h) => h.as_file_mut(), + HandleKind::Borrowed(ref mut h) => h.as_file_mut(), + } + } +} diff --git a/schannel/.cargo-checksum.json b/schannel/.cargo-checksum.json new file mode 100644 index 000000000..4176088c1 --- /dev/null +++ b/schannel/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"} \ No newline at end of file diff --git a/schannel/Cargo.toml b/schannel/Cargo.toml new file mode 100644 index 000000000..44a8d3bd0 --- /dev/null +++ b/schannel/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "schannel" +version = "0.1.15" +authors = ["Steven Fackler <sfackler@gmail.com>", "Steffen Butzer <steffen.butzer@outlook.com>"] +description = "Schannel bindings for rust, allowing SSL/TLS (e.g. https) without openssl" +documentation = "https://docs.rs/schannel/0/x86_64-pc-windows-gnu/schannel/" +readme = "README.md" +keywords = ["windows", "schannel", "tls", "ssl", "https"] +license = "MIT" +repository = "https://github.com/steffengy/schannel-rs" +[dependencies.lazy_static] +version = "1.0" + +[dependencies.winapi] +version = "0.3" +features = ["lmcons", "minschannel", "securitybaseapi", "schannel", "sspi", "sysinfoapi", "timezoneapi", "winbase", "wincrypt", "winerror"] diff --git a/schannel/LICENSE.md b/schannel/LICENSE.md new file mode 100644 index 000000000..0d9d26dcb --- /dev/null +++ b/schannel/LICENSE.md @@ -0,0 +1,7 @@ +Copyright (c) 2015 steffengy + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/schannel/README.md b/schannel/README.md new file mode 100644 index 000000000..737a6af71 --- /dev/null +++ b/schannel/README.md @@ -0,0 +1,6 @@ +schannel-rs [![Build status](https://ci.appveyor.com/api/projects/status/vefyauaf0oj10swu/branch/master?svg=true)](https://ci.appveyor.com/project/steffengy/schannel-rs/branch/master) +===== + +[Documentation](https://docs.rs/schannel/0/x86_64-pc-windows-gnu/schannel/) + +Rust bindings to the Windows SChannel APIs providing TLS client and server functionality. diff --git a/schannel/appveyor.yml b/schannel/appveyor.yml new file mode 100644 index 000000000..d79de826a --- /dev/null +++ b/schannel/appveyor.yml @@ -0,0 +1,26 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + VERSION: nightly + - TARGET: i686-pc-windows-msvc + VERSION: nightly + - TARGET: x86_64-pc-windows-gnu + VERSION: nightly + - TARGET: i686-pc-windows-gnu + VERSION: 1.24.1 + access_token: + secure: ZxcrtxQXwszRYNN6c1ZIagczEqzmQQZeYHY58izcmF0jdq/cptxJvFUoVxDmnoqj +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:VERSION}-${env:TARGET}.exe" -FileName "rust-nightly.exe" + - ps: .\rust-nightly.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - rustc -vV + - cargo -vV + - echo install + +build: off + +test_script: + # TODO remove this loop when server 2016 lands on appveyor; related to https://github.com/steffengy/schannel-rs/issues/8 + - set RUST_BACKTRACE=1 + - ps: for($i=1; $i -le 3; $i++) { cmd /c "cargo test 2>&1"; if ($?) { break } } diff --git a/schannel/src/cert_chain.rs b/schannel/src/cert_chain.rs new file mode 100644 index 000000000..472693396 --- /dev/null +++ b/schannel/src/cert_chain.rs @@ -0,0 +1,139 @@ +//! Bindings to winapi's certificate-chain related APIs. + +use std::mem; +use std::slice; +use winapi::um::wincrypt; + +use cert_context::CertContext; +use Inner; + +/// A certificate chain context (consisting of multiple chains) +pub struct CertChainContext(pub wincrypt::PCERT_CHAIN_CONTEXT); + +unsafe impl Sync for CertChainContext {} +unsafe impl Send for CertChainContext {} + +impl Clone for CertChainContext { + fn clone(&self) -> Self { + let rced = unsafe { + wincrypt::CertDuplicateCertificateChain(self.0) as *mut _ + }; + CertChainContext(rced) + } +} + +impl Drop for CertChainContext { + fn drop(&mut self) { + unsafe { + wincrypt::CertFreeCertificateChain(self.0); + } + } +} + +impl CertChainContext { + /// Get the final (for a successful verification this means successful) certificate chain + /// + /// https://msdn.microsoft.com/de-de/library/windows/desktop/aa377182(v=vs.85).aspx + /// rgpChain[cChain - 1] is the final chain + pub fn final_chain(&self) -> Option<CertChain> { + if let Some(chain) = self.chains().last(){ + return Some(CertChain(chain.0, self.clone())); + } + None + } + + /// Retrieves the specified chain from the context. + pub fn get_chain(&self, index :usize) -> Option<CertChain> { + let cert_chain = unsafe { + let cert_chain = *self.0; + if index >= cert_chain.cChain as usize { + None + } else { + let chain_slice = slice::from_raw_parts( + cert_chain.rgpChain as *mut wincrypt::PCERT_SIMPLE_CHAIN, + cert_chain.cChain as usize); + Some(CertChain(chain_slice[index], self.clone())) + } + }; + return cert_chain; + } + + /// Return an iterator over all certificate chains in this context + pub fn chains(&self) -> CertificateChains { + CertificateChains { + context: self, + idx: 0 + } + } +} + +/// A (simple) certificate chain +pub struct CertChain(wincrypt::PCERT_SIMPLE_CHAIN, CertChainContext); + +impl CertChain { + /// Returns the number of certificates in the chain + pub fn len(&self) -> usize { + unsafe { + (*self.0).cElement as usize + } + } + + /// Get the n-th certificate from the current chain + pub fn get(&self, idx: usize) -> Option<CertContext> { + let elements = unsafe { + let cert_chain = *self.0; + slice::from_raw_parts( + cert_chain.rgpElement as *mut &mut wincrypt::CERT_CHAIN_ELEMENT, + cert_chain.cElement as usize) + }; + elements.get(idx).map(|el| { + let cert = unsafe { + CertContext::from_inner(el.pCertContext) + }; + let rc_cert = cert.clone(); + mem::forget(cert); + rc_cert + }) + } + + /// Return an iterator over all certificates in this chain + pub fn certificates(&self) -> Certificates { + Certificates { + chain: self, + idx: 0, + } + } +} + + +/// An iterator that iterates over all chains in a context +pub struct CertificateChains<'a> { + context: &'a CertChainContext, + idx: usize, +} + +impl<'a> Iterator for CertificateChains<'a> { + type Item = CertChain; + + fn next(&mut self) -> Option<CertChain> { + let idx = self.idx; + self.idx += 1; + self.context.get_chain(idx) + } +} + +/// An iterator that iterates over all certificates in a chain +pub struct Certificates<'a> { + chain: &'a CertChain, + idx: usize, +} + +impl<'a> Iterator for Certificates<'a> { + type Item = CertContext; + + fn next(&mut self) -> Option<CertContext> { + let idx = self.idx; + self.idx += 1; + self.chain.get(idx) + } +} diff --git a/schannel/src/cert_context.rs b/schannel/src/cert_context.rs new file mode 100644 index 000000000..6e9af7520 --- /dev/null +++ b/schannel/src/cert_context.rs @@ -0,0 +1,672 @@ +//! Bindings to winapi's `PCCERT_CONTEXT` APIs. + +use std::ffi::{CStr, OsString}; +use std::io; +use std::mem; +use std::os::windows::prelude::*; +use std::ptr; +use std::slice; +use winapi::shared::minwindef as winapi; +use winapi::shared::ntdef; +use winapi::shared::winerror; +use winapi::um::wincrypt; + +use Inner; +use ncrypt_key::NcryptKey; +use crypt_prov::{CryptProv, ProviderType}; +use cert_store::CertStore; + +/// A supported hashing algorithm +pub struct HashAlgorithm(winapi::DWORD, usize); + +#[allow(missing_docs)] +impl HashAlgorithm { + pub fn md5() -> HashAlgorithm { + HashAlgorithm(wincrypt::CALG_MD5, 16) + } + + pub fn sha1() -> HashAlgorithm{ + HashAlgorithm(wincrypt::CALG_SHA1, 20) + } + + pub fn sha256() -> HashAlgorithm { + HashAlgorithm(wincrypt::CALG_SHA_256, 32) + } + + pub fn sha384() -> HashAlgorithm { + HashAlgorithm(wincrypt::CALG_SHA_384, 48) + } + + pub fn sha512() -> HashAlgorithm { + HashAlgorithm(wincrypt::CALG_SHA_512, 64) + } +} + +/// Wrapper of a winapi certificate, or a `PCCERT_CONTEXT`. +#[derive(Debug)] +pub struct CertContext(wincrypt::PCCERT_CONTEXT); + +unsafe impl Sync for CertContext {} +unsafe impl Send for CertContext {} + +impl Drop for CertContext { + fn drop(&mut self) { + unsafe { + wincrypt::CertFreeCertificateContext(self.0); + } + } +} + +impl Clone for CertContext { + fn clone(&self) -> CertContext { + unsafe { CertContext(wincrypt::CertDuplicateCertificateContext(self.0)) } + } +} + +inner!(CertContext, wincrypt::PCCERT_CONTEXT); + +impl CertContext { + /// Decodes a DER-formatted X509 certificate. + pub fn new(data: &[u8]) -> io::Result<CertContext> { + let ret = unsafe { + wincrypt::CertCreateCertificateContext(wincrypt::X509_ASN_ENCODING | + wincrypt::PKCS_7_ASN_ENCODING, + data.as_ptr(), + data.len() as winapi::DWORD) + }; + if ret.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CertContext(ret)) + } + } + + /// Get certificate in binary DER form + pub fn to_der<'a>(&'a self) -> &'a [u8] { + self.get_encoded_bytes() + } + + /// Certificate subject public key info + pub fn subject_public_key_info_der(&self) -> io::Result<Vec<u8>> { + unsafe { + let mut len:u32 = 0; + let ok = wincrypt::CryptEncodeObjectEx(wincrypt::X509_ASN_ENCODING, + wincrypt::CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG as *const u32 as *const _, + &(*(*self.0).pCertInfo).SubjectPublicKeyInfo as *const wincrypt::CERT_PUBLIC_KEY_INFO as _, + 0, + ptr::null_mut(), + ptr::null_mut(), + &mut len as *mut _); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + if len > 0 { + let mut buf = vec![0; len as usize]; + let ok = wincrypt::CryptEncodeObjectEx(wincrypt::X509_ASN_ENCODING, + wincrypt::CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG as *const u32 as *const _, + &(*(*self.0).pCertInfo).SubjectPublicKeyInfo as *const wincrypt::CERT_PUBLIC_KEY_INFO as _, + 0, + ptr::null_mut(), + buf.as_mut_ptr() as _, + &mut len as *mut _); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + return Ok(buf); + } + } + Err(io::Error::last_os_error()) + } + + /// Decodes a PEM-formatted X509 certificate. + pub fn from_pem(pem: &str) -> io::Result<CertContext> { + unsafe { + assert!(pem.len() <= winapi::DWORD::max_value() as usize); + + let mut len = 0; + let ok = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR, + pem.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64HEADER, + ptr::null_mut(), + &mut len, + ptr::null_mut(), + ptr::null_mut()); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + let mut buf = vec![0; len as usize]; + let ok = wincrypt::CryptStringToBinaryA(pem.as_ptr() as ntdef::LPCSTR, + pem.len() as winapi::DWORD, + wincrypt::CRYPT_STRING_BASE64HEADER, + buf.as_mut_ptr(), + &mut len, + ptr::null_mut(), + ptr::null_mut()); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + CertContext::new(&buf) + } + } + + /// Get certificate as PEM-formatted X509 certificate. + pub fn to_pem(&self) -> io::Result<String> { + unsafe { + let mut len = 0; + let ok = wincrypt::CryptBinaryToStringA( + (*self.0).pbCertEncoded, + (*self.0).cbCertEncoded, + wincrypt::CRYPT_STRING_BASE64HEADER, + ptr::null_mut(), + &mut len, + ); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + let mut buf = vec![0; len as usize]; + let ok = wincrypt::CryptBinaryToStringA( + (*self.0).pbCertEncoded, + (*self.0).cbCertEncoded, + wincrypt::CRYPT_STRING_BASE64HEADER, + buf.as_mut_ptr(), + &mut len, + ); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + Ok(CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned()) + } + } + + /// Returns a hash of this certificate + pub fn fingerprint(&self, alg: HashAlgorithm) -> io::Result<Vec<u8>> { + unsafe { + let mut buf = vec![0u8; alg.1]; + let mut len = buf.len() as winapi::DWORD; + + let ret = wincrypt::CryptHashCertificate(0, + alg.0, + 0, + (*self.0).pbCertEncoded, + (*self.0).cbCertEncoded, + buf.as_mut_ptr(), + &mut len); + + if ret != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + Ok(buf) + } + } + + /// Returns the sha1 hash of this certificate + /// + /// The sha1 is returned as a 20-byte array representing the bits of the + /// sha1 hash. + #[deprecated(note = "please use fingerprint instead")] + pub fn sha1(&self) -> io::Result<[u8; 20]> { + let mut out = [0u8; 20]; + out.copy_from_slice(&try!(self.fingerprint(HashAlgorithm::sha1()))); + Ok(out) + } + + /// Returns the `<SIGNATURE>/<HASH>` string representing the certificate + /// signature. + /// + /// The `<SIGNATURE>` value identifies the CNG public key + /// algorithm. The `<HASH>` value identifies the CNG hash algorithm. + /// + /// Common examples are: + /// + /// * `RSA/SHA1` + /// * `RSA/SHA256` + /// * `ECDSA/SHA256` + pub fn sign_hash_algorithms(&self) -> io::Result<String> { + self.get_string(wincrypt::CERT_SIGN_HASH_CNG_ALG_PROP_ID) + } + + /// Returns the signature hash. + pub fn signature_hash(&self) -> io::Result<Vec<u8>> { + self.get_bytes(wincrypt::CERT_SIGNATURE_HASH_PROP_ID) + } + + /// Returns the property displayed by the certificate UI. This property + /// allows the user to describe the certificate's use. + pub fn description(&self) -> io::Result<Vec<u8>> { + self.get_bytes(wincrypt::CERT_DESCRIPTION_PROP_ID) + } + + /// Returns a string that contains the display name for the certificate. + pub fn friendly_name(&self) -> io::Result<String> { + self.get_string(wincrypt::CERT_FRIENDLY_NAME_PROP_ID) + } + + /// Configures the string that contains the display name for this + /// certificate. + pub fn set_friendly_name(&self, name: &str) -> io::Result<()> { + self.set_string(wincrypt::CERT_FRIENDLY_NAME_PROP_ID, name) + } + + /// Verifies the time validity of this certificate relative to the system's + /// current time. + pub fn is_time_valid(&self) -> io::Result<bool> { + let ret = unsafe { wincrypt::CertVerifyTimeValidity(ptr::null_mut(), (*self.0).pCertInfo) }; + Ok(ret == 0) + } + + /// Returns a builder used to acquire the private key corresponding to this certificate. + pub fn private_key<'a>(&'a self) -> AcquirePrivateKeyOptions<'a> { + AcquirePrivateKeyOptions { + cert: self, + flags: 0, + } + } + + /// Deletes this certificate from its certificate store. + pub fn delete(self) -> io::Result<()> { + unsafe { + let ret = wincrypt::CertDeleteCertificateFromStore(self.0); + mem::forget(self); + if ret == winapi::TRUE { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } + + /// Returns a builder used to set the private key associated with this certificate. + pub fn set_key_prov_info<'a>(&'a self) -> SetKeyProvInfo<'a> { + SetKeyProvInfo { + cert: self, + container: None, + provider: None, + type_: 0, + flags: 0, + key_spec: 0, + } + } + + /// Returns the valid uses for this certificate + pub fn valid_uses(&self) -> io::Result<ValidUses> { + unsafe { + let mut buf_len = 0; + let ok = wincrypt::CertGetEnhancedKeyUsage(self.0, 0, ptr::null_mut(), &mut buf_len); + + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + let mut buf = vec![0u8; buf_len as usize]; + let cert_enhkey_usage = buf.as_mut_ptr() as *mut wincrypt::CERT_ENHKEY_USAGE; + + let ok = wincrypt::CertGetEnhancedKeyUsage(self.0, 0, cert_enhkey_usage, &mut buf_len); + if ok != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + let use_cnt = (*cert_enhkey_usage).cUsageIdentifier; + if use_cnt == 0 { + let last_error = io::Error::last_os_error(); + match last_error.raw_os_error() { + Some(winerror::CRYPT_E_NOT_FOUND) => return Ok(ValidUses::All), + Some(0) => (), + _ => return Err(last_error), + }; + } + + let mut oids: Vec<String> = Vec::with_capacity(use_cnt as usize); + for i in 0..use_cnt { + let oid_ptr = (*cert_enhkey_usage).rgpszUsageIdentifier; + oids.push( + CStr::from_ptr(*(oid_ptr.offset(i as isize))) + .to_string_lossy() + .into_owned(), + ); + } + Ok(ValidUses::Oids(oids)) + } + } + + /// For a remote certificate, returns a certificate store containing any intermediate + /// certificates provided by the remote sender. + pub fn cert_store(&self) -> Option<CertStore> { + unsafe { + let chain = (*self.0).hCertStore; + if chain.is_null() { + None + } else { + Some(CertStore::from_inner(wincrypt::CertDuplicateStore(chain))) + } + } + } + + fn get_encoded_bytes<'a>(&'a self) -> &'a [u8] { + unsafe { + let cert_ctx = *self.0; + slice::from_raw_parts(cert_ctx.pbCertEncoded, cert_ctx.cbCertEncoded as usize) + } + } + + fn get_bytes(&self, prop: winapi::DWORD) -> io::Result<Vec<u8>> { + unsafe { + let mut len = 0; + let ret = + wincrypt::CertGetCertificateContextProperty(self.0, prop, ptr::null_mut(), &mut len); + if ret != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + let mut buf = vec![0u8; len as usize]; + let ret = wincrypt::CertGetCertificateContextProperty(self.0, + prop, + buf.as_mut_ptr() as winapi::LPVOID, + &mut len); + if ret != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + Ok(buf) + } + } + + fn get_string(&self, prop: winapi::DWORD) -> io::Result<String> { + unsafe { + let mut len = 0; + let ret = + wincrypt::CertGetCertificateContextProperty(self.0, prop, ptr::null_mut(), &mut len); + if ret != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + // Divide by 2 b/c `len` is the byte length, but we're allocating + // u16 pairs which are 2 bytes each. + let amt = (len / 2) as usize; + let mut buf = vec![0u16; amt]; + let ret = wincrypt::CertGetCertificateContextProperty(self.0, + prop, + buf.as_mut_ptr() as winapi::LPVOID, + &mut len); + if ret != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + + // Chop off the trailing nul byte + Ok(OsString::from_wide(&buf[..amt - 1]).into_string().unwrap()) + } + } + + fn set_string(&self, prop: winapi::DWORD, s: &str) -> io::Result<()> { + unsafe { + let data = s.encode_utf16().chain(Some(0)).collect::<Vec<_>>(); + let data = wincrypt::CRYPT_DATA_BLOB { + cbData: (data.len() * 2) as winapi::DWORD, + pbData: data.as_ptr() as *mut _, + }; + let ret = wincrypt::CertSetCertificateContextProperty(self.0, + prop, + 0, + &data as *const _ as *const _); + if ret != winapi::TRUE { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} + +impl PartialEq for CertContext { + fn eq(&self, other: &CertContext) -> bool { + self.get_encoded_bytes() == other.get_encoded_bytes() + } +} + +/// A builder type for certificate private key lookup. +pub struct AcquirePrivateKeyOptions<'a> { + cert: &'a CertContext, + flags: winapi::DWORD, +} + +impl<'a> AcquirePrivateKeyOptions<'a> { + /// If set, the certificate's public key will be compared with the private key to ensure a + /// match. + pub fn compare_key(&mut self, compare_key: bool) -> &mut AcquirePrivateKeyOptions<'a> { + self.flag(wincrypt::CRYPT_ACQUIRE_COMPARE_KEY_FLAG, compare_key) + } + + /// If set, the lookup will not display any user interface, even if that causes the lookup to + /// fail. + pub fn silent(&mut self, silent: bool) -> &mut AcquirePrivateKeyOptions<'a> { + self.flag(wincrypt::CRYPT_ACQUIRE_SILENT_FLAG, silent) + } + + fn flag(&mut self, flag: winapi::DWORD, set: bool) -> &mut AcquirePrivateKeyOptions<'a> { + if set { + self.flags |= flag; + } else { + self.flags &= !flag; + } + self + } + + /// Acquires the private key handle. + pub fn acquire(&self) -> io::Result<PrivateKey> { + unsafe { + let flags = self.flags | wincrypt::CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; + let mut handle = 0; + let mut spec = 0; + let mut free = winapi::FALSE; + let res = wincrypt::CryptAcquireCertificatePrivateKey(self.cert.0, + flags, + ptr::null_mut(), + &mut handle, + &mut spec, + &mut free); + if res != winapi::TRUE { + return Err(io::Error::last_os_error()); + } + assert!(free == winapi::TRUE); + if spec & wincrypt::CERT_NCRYPT_KEY_SPEC != 0 { + Ok(PrivateKey::NcryptKey(NcryptKey::from_inner(handle))) + } else { + Ok(PrivateKey::CryptProv(CryptProv::from_inner(handle))) + } + } + } +} + +/// The private key associated with a certificate context. +pub enum PrivateKey { + /// A CryptoAPI provider. + CryptProv(CryptProv), + /// A CNG provider. + NcryptKey(NcryptKey), +} + +/// A builder used to set the private key associated with a certificate. +pub struct SetKeyProvInfo<'a> { + cert: &'a CertContext, + container: Option<Vec<u16>>, + provider: Option<Vec<u16>>, + type_: winapi::DWORD, + flags: winapi::DWORD, + key_spec: winapi::DWORD, +} + +impl<'a> SetKeyProvInfo<'a> { + /// The name of the key container. + /// + /// If `type_` is not provided, this specifies the name of the key withing + /// the CNG key storage provider. + pub fn container(&mut self, container: &str) -> &mut SetKeyProvInfo<'a> { + self.container = Some(container.encode_utf16().chain(Some(0)).collect()); + self + } + + /// The name of the CSP. + /// + /// If `type_` is not provided, this contains the name of the CNG key + /// storage provider. + pub fn provider(&mut self, provider: &str) -> &mut SetKeyProvInfo<'a> { + self.provider = Some(provider.encode_utf16().chain(Some(0)).collect()); + self + } + + /// Sets the CSP type. + /// + /// If not provided, the key container is one of the CNG key storage + /// providers. + pub fn type_(&mut self, type_: ProviderType) -> &mut SetKeyProvInfo<'a> { + self.type_ = type_.as_raw(); + self + } + + /// If set, the handle to the key provider can be kept open for subsequent + /// calls to cryptographic functions. + pub fn keep_open(&mut self, keep_open: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(wincrypt::CERT_SET_KEY_PROV_HANDLE_PROP_ID, keep_open) + } + + /// If set, the key container contains machine keys. + pub fn machine_keyset(&mut self, machine_keyset: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(wincrypt::CRYPT_MACHINE_KEYSET, machine_keyset) + } + + /// If set, the key container will attempt to open keys without any user + /// interface prompts. + pub fn silent(&mut self, silent: bool) -> &mut SetKeyProvInfo<'a> { + self.flag(wincrypt::CRYPT_SILENT, silent) + } + + fn flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut SetKeyProvInfo<'a> { + if on { + self.flags |= flag; + } else { + self.flags &= !flag; + } + self + } + + /// The specification of the private key to retrieve. + pub fn key_spec(&mut self, key_spec: KeySpec) -> &mut SetKeyProvInfo<'a> { + self.key_spec = key_spec.0; + self + } + + /// Sets the private key for this certificate. + pub fn set(&mut self) -> io::Result<()> { + unsafe { + let container = self.container.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let provider = self.provider.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + + let info = wincrypt::CRYPT_KEY_PROV_INFO { + pwszContainerName: container as *mut _, + pwszProvName: provider as *mut _, + dwProvType: self.type_, + dwFlags: self.flags, + cProvParam: 0, + rgProvParam: ptr::null_mut(), + dwKeySpec: self.key_spec, + }; + + let res = + wincrypt::CertSetCertificateContextProperty(self.cert.0, + wincrypt::CERT_KEY_PROV_INFO_PROP_ID, + 0, + &info as *const _ as *const _); + if res == winapi::TRUE { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +/// The specification of a private key. +#[derive(Copy, Clone)] +pub struct KeySpec(winapi::DWORD); + +impl KeySpec { + /// A key used to encrypt/decrypt session keys. + pub fn key_exchange() -> KeySpec { + KeySpec(wincrypt::AT_KEYEXCHANGE) + } + + /// A key used to create and verify digital signatures. + pub fn signature() -> KeySpec { + KeySpec(wincrypt::AT_SIGNATURE) + } +} + +/// Valid uses of a Certificate - All, or specific OIDs +pub enum ValidUses { + /// Certificate is valid for all uses + All, + + /// Certificate is valid for uses specified. No entries means that the certificate + /// has no valid uses. + Oids(Vec<String>), +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn decode() { + let der = include_bytes!("../test/cert.der"); + let pem = include_str!("../test/cert.pem"); + + let der = CertContext::new(der).unwrap(); + let pem = CertContext::from_pem(pem).unwrap(); + assert_eq!(der, pem); + } + + #[test] + fn certcontext_to_der() { + let der = include_bytes!("../test/cert.der"); + let cert = CertContext::new(der).unwrap(); + let der2 = CertContext::to_der(&cert); + assert_eq!(der as &[u8], der2); + } + + #[test] + fn certcontext_to_pem() { + let der = include_bytes!("../test/cert.der"); + let pem1 = include_str!("../test/cert.pem").replace("\r", ""); + + let der = CertContext::new(der).unwrap(); + let pem2 = CertContext::to_pem(&der).unwrap().replace("\r", ""); + assert_eq!(pem1, pem2); + } + + #[test] + fn fingerprint() { + let der = include_bytes!("../test/cert.der"); + let pem = include_str!("../test/cert.pem"); + + let der = CertContext::new(der).unwrap(); + let pem = CertContext::from_pem(pem).unwrap(); + + let hash = der.fingerprint(HashAlgorithm::sha1()).unwrap(); + assert_eq!(hash, vec![‎ + 0x59, 0x17, 0x2D, 0x93, 0x13, 0xE8, 0x44, 0x59, 0xBC, 0xFF, + 0x27, 0xF9, 0x67, 0xE7, 0x9E, 0x6E, 0x92, 0x17, 0xE5, 0x84 + ]); + assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha1()).unwrap()); + + let hash = der.fingerprint(HashAlgorithm::sha256()).unwrap(); + assert_eq!(hash, vec![ + 0x47, 0x12, 0xB9, 0x39, 0xFB, 0xCB, 0x42, 0xA6, 0xB5, 0x10, + 0x1B, 0x42, 0x13, 0x9A, 0x25, 0xB1, 0x4F, 0x81, 0xB4, 0x18, + 0xFA, 0xCA, 0xBD, 0x37, 0x87, 0x46, 0xF1, 0x2F, 0x85, 0xCC, + 0x65, 0x44 + ]); + assert_eq!(hash, pem.fingerprint(HashAlgorithm::sha256()).unwrap()); + } +} diff --git a/schannel/src/cert_store.rs b/schannel/src/cert_store.rs new file mode 100644 index 000000000..5eff9ec1a --- /dev/null +++ b/schannel/src/cert_store.rs @@ -0,0 +1,446 @@ +//! Bindings to winapi's certificate-store related APIs. + +use std::cmp; +use std::ffi::OsStr; +use std::fmt; +use std::io; +use std::mem; +use std::os::windows::prelude::*; +use std::ptr; +use winapi::shared::minwindef as winapi; +use winapi::shared::ntdef; +use winapi::um::wincrypt; + +use cert_context::CertContext; +use ctl_context::CtlContext; + +use Inner; + +/// Representation of certificate store on Windows, wrapping a `HCERTSTORE`. +pub struct CertStore(wincrypt::HCERTSTORE); + +unsafe impl Sync for CertStore {} +unsafe impl Send for CertStore {} + +impl fmt::Debug for CertStore { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("CertStore").finish() + } +} + +impl Drop for CertStore { + fn drop(&mut self) { + unsafe { + wincrypt::CertCloseStore(self.0, 0); + } + } +} + +impl Clone for CertStore { + fn clone(&self) -> CertStore { + unsafe { CertStore(wincrypt::CertDuplicateStore(self.0)) } + } +} + +inner!(CertStore, wincrypt::HCERTSTORE); + +/// Argument to the `add_cert` function indicating how a certificate should be +/// added to a `CertStore`. +pub enum CertAdd { + /// The function makes no check for an existing matching certificate or link + /// to a matching certificate. A new certificate is always added to the + /// store. This can lead to duplicates in a store. + Always = wincrypt::CERT_STORE_ADD_ALWAYS as isize, + + /// If a matching certificate or a link to a matching certificate exists, + /// the operation fails. + New = wincrypt::CERT_STORE_ADD_NEW as isize, + + /// If a matching certificate or a link to a matching certificate exists and + /// the NotBefore time of the existing context is equal to or greater than + /// the NotBefore time of the new context being added, the operation fails. + /// + /// If the NotBefore time of the existing context is less than the NotBefore + /// time of the new context being added, the existing certificate or link is + /// deleted and a new certificate is created and added to the store. If a + /// matching certificate or a link to a matching certificate does not exist, + /// a new link is added. + Newer = wincrypt::CERT_STORE_ADD_NEWER as isize, + + /// If a matching certificate or a link to a matching certificate exists and + /// the NotBefore time of the existing context is equal to or greater than + /// the NotBefore time of the new context being added, the operation fails. + /// + /// If the NotBefore time of the existing context is less than the NotBefore + /// time of the new context being added, the existing context is deleted + /// before creating and adding the new context. The new added context + /// inherits properties from the existing certificate. + NewerInheritProperties = wincrypt::CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES as isize, + + /// If a link to a matching certificate exists, that existing certificate or + /// link is deleted and a new certificate is created and added to the store. + /// If a matching certificate or a link to a matching certificate does not + /// exist, a new link is added. + ReplaceExisting = wincrypt::CERT_STORE_ADD_REPLACE_EXISTING as isize, + + /// If a matching certificate exists in the store, the existing context is + /// not replaced. The existing context inherits properties from the new + /// certificate. + ReplaceExistingInheritProperties = + wincrypt::CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES as isize, + + /// If a matching certificate or a link to a matching certificate exists, + /// that existing certificate or link is used and properties from the + /// new certificate are added. The function does not fail, but it does + /// not add a new context. The existing context is duplicated and returned. + /// + /// If a matching certificate or a link to a matching certificate does + /// not exist, a new certificate is added. + UseExisting = wincrypt::CERT_STORE_ADD_USE_EXISTING as isize, +} + +impl CertStore { + /// Opens up the specified key store within the context of the current user. + /// + /// Known valid values for `which` are "Root" and "My". + pub fn open_current_user(which: &str) -> io::Result<CertStore> { + unsafe { + let data = OsStr::new(which) + .encode_wide() + .chain(Some(0)) + .collect::<Vec<_>>(); + let store = wincrypt::CertOpenStore(wincrypt::CERT_STORE_PROV_SYSTEM_W as ntdef::LPCSTR, + 0, + 0, + wincrypt::CERT_SYSTEM_STORE_CURRENT_USER, + data.as_ptr() as *mut _); + if store.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CertStore(store)) + } + } + } + + /// Opens up the specified key store within the context of the local + /// machine. + /// + /// Known valid values for `which` are "Root" and "My". + pub fn open_local_machine(which: &str) -> io::Result<CertStore> { + unsafe { + let data = OsStr::new(which) + .encode_wide() + .chain(Some(0)) + .collect::<Vec<_>>(); + let store = wincrypt::CertOpenStore(wincrypt::CERT_STORE_PROV_SYSTEM_W as ntdef::LPCSTR, + 0, + 0, + wincrypt::CERT_SYSTEM_STORE_LOCAL_MACHINE, + data.as_ptr() as *mut _); + if store.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CertStore(store)) + } + } + } + + /// Imports a PKCS#12-encoded key/certificate pair, returned as a + /// `CertStore` instance. + /// + /// The password must also be provided to decrypt the encoded data. + pub fn import_pkcs12(data: &[u8], + password: Option<&str>) + -> io::Result<CertStore> { + unsafe { + let mut blob = wincrypt::CRYPT_INTEGER_BLOB { + cbData: data.len() as winapi::DWORD, + pbData: data.as_ptr() as *mut u8, + }; + let password = password.map(|s| { + OsStr::new(s).encode_wide() + .chain(Some(0)) + .collect::<Vec<_>>() + }); + let password = password.as_ref().map(|s| s.as_ptr()); + let password = password.unwrap_or(ptr::null()); + let res = wincrypt::PFXImportCertStore(&mut blob, + password, + 0); + if res.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(CertStore(res)) + } + } + } + + /// Returns an iterator over the certificates in this certificate store. + pub fn certs(&self) -> Certs { + Certs { store: self, cur: None } + } + + /// Adds a certificate context to this store. + /// + /// This function will add the certificate specified in `cx` to this store. + /// A copy of the added certificate is returned. + pub fn add_cert(&mut self, + cx: &CertContext, + how: CertAdd) -> io::Result<CertContext> { + unsafe { + let how = how as winapi::DWORD; + let mut ret = ptr::null(); + let res = wincrypt::CertAddCertificateContextToStore(self.0, + cx.as_inner(), + how, + &mut ret); + if res != winapi::TRUE { + Err(io::Error::last_os_error()) + } else { + Ok(CertContext::from_inner(ret)) + } + } + } + + /// Exports this certificate store as a PKCS#12-encoded blob. + /// + /// The password specified will be the password used to unlock the returned + /// data. + pub fn export_pkcs12(&self, password: &str) -> io::Result<Vec<u8>> { + unsafe { + let password = password.encode_utf16().chain(Some(0)).collect::<Vec<_>>(); + let mut blob = wincrypt::CRYPT_DATA_BLOB { + cbData: 0, + pbData: 0 as *mut _, + }; + let res = wincrypt::PFXExportCertStore(self.0, + &mut blob, + password.as_ptr(), + wincrypt::EXPORT_PRIVATE_KEYS); + if res != winapi::TRUE { + return Err(io::Error::last_os_error()) + } + let mut ret = Vec::with_capacity(blob.cbData as usize); + blob.pbData = ret.as_mut_ptr(); + let res = wincrypt::PFXExportCertStore(self.0, + &mut blob, + password.as_ptr(), + wincrypt::EXPORT_PRIVATE_KEYS); + if res != winapi::TRUE { + return Err(io::Error::last_os_error()) + } + ret.set_len(blob.cbData as usize); + Ok(ret) + } + } +} + +/// An iterator over the certificates contained in a `CertStore`, returned by +/// `CertStore::iter` +pub struct Certs<'a> { + store: &'a CertStore, + cur: Option<CertContext>, +} + +impl<'a> Iterator for Certs<'a> { + type Item = CertContext; + + fn next(&mut self) -> Option<CertContext> { + unsafe { + let cur = self.cur.take().map(|p| { + let ptr = p.as_inner(); + mem::forget(p); + ptr + }); + let cur = cur.unwrap_or(ptr::null_mut()); + let next = wincrypt::CertEnumCertificatesInStore(self.store.0, cur); + + if next.is_null() { + self.cur = None; + None + } else { + let next = CertContext::from_inner(next); + self.cur = Some(next.clone()); + Some(next) + } + } + } +} + +/// A builder type for imports of PKCS #12 archives. +#[derive(Default)] +pub struct PfxImportOptions { + password: Option<Vec<u16>>, + flags: winapi::DWORD, +} + +impl PfxImportOptions { + /// Returns a new `PfxImportOptions` with default settings. + pub fn new() -> PfxImportOptions { + PfxImportOptions::default() + } + + /// Sets the password to be used to decrypt the archive. + pub fn password(&mut self, password: &str) -> &mut PfxImportOptions { + self.password = Some(password.encode_utf16().chain(Some(0)).collect()); + self + } + + /// If set, the private key in the archive will not be persisted. + /// + /// If not set, private keys are persisted on disk and must be manually deleted. + pub fn no_persist_key(&mut self, no_persist_key: bool) -> &mut PfxImportOptions { + self.flag(wincrypt::PKCS12_NO_PERSIST_KEY, no_persist_key) + } + + /// If set, all extended properties of the certificate will be imported. + pub fn include_extended_properties(&mut self, + include_extended_properties: bool) + -> &mut PfxImportOptions { + self.flag(wincrypt::PKCS12_INCLUDE_EXTENDED_PROPERTIES, include_extended_properties) + } + + fn flag(&mut self, flag: winapi::DWORD, set: bool) -> &mut PfxImportOptions { + if set { + self.flags |= flag; + } else { + self.flags &= !flag; + } + self + } + + /// Imports certificates from a PKCS #12 archive, returning a `CertStore` containing them. + pub fn import(&self, data: &[u8]) -> io::Result<CertStore> { + unsafe { + let mut blob = wincrypt::CRYPT_DATA_BLOB { + cbData: cmp::min(data.len(), winapi::DWORD::max_value() as usize) as winapi::DWORD, + pbData: data.as_ptr() as *const _ as *mut _, + }; + let password = self.password.as_ref().map_or(ptr::null(), |p| p.as_ptr()); + + let store = wincrypt::PFXImportCertStore(&mut blob, password, self.flags); + if store.is_null() { + return Err(io::Error::last_os_error()); + } + Ok(CertStore(store)) + } + } +} + +/// Representation of an in-memory certificate store. +/// +/// Internally this contains a `CertStore` which this type can be converted to. +pub struct Memory(CertStore); + +impl Memory { + /// Creates a new in-memory certificate store which certificates and CTLs + /// can be added to. + /// + /// Initially the returned certificate store contains no certificates. + pub fn new() -> io::Result<Memory> { + unsafe { + let store = wincrypt::CertOpenStore(wincrypt::CERT_STORE_PROV_MEMORY as ntdef::LPCSTR, + 0, + 0, + 0, + ptr::null_mut()); + if store.is_null() { + Err(io::Error::last_os_error()) + } else { + Ok(Memory(CertStore(store))) + } + } + } + + /// Adds a new certificate to this memory store. + /// + /// For example the bytes could be a DER-encoded certificate. + pub fn add_encoded_certificate(&mut self, cert: &[u8]) -> io::Result<CertContext> { + unsafe { + let mut cert_context = ptr::null(); + + let res = wincrypt::CertAddEncodedCertificateToStore((self.0).0, + wincrypt::X509_ASN_ENCODING | + wincrypt::PKCS_7_ASN_ENCODING, + cert.as_ptr() as *const _, + cert.len() as winapi::DWORD, + wincrypt::CERT_STORE_ADD_ALWAYS, + &mut cert_context); + if res == winapi::TRUE { + Ok(CertContext::from_inner(cert_context)) + } else { + Err(io::Error::last_os_error()) + } + } + } + + /// Adds a new CTL to this memory store, in its encoded form. + /// + /// This can be created through the `ctl_context::Builder` type. + pub fn add_encoded_ctl(&mut self, ctl: &[u8]) -> io::Result<CtlContext> { + unsafe { + let mut ctl_context = ptr::null(); + + let res = wincrypt::CertAddEncodedCTLToStore((self.0).0, + wincrypt::X509_ASN_ENCODING | + wincrypt::PKCS_7_ASN_ENCODING, + ctl.as_ptr() as *const _, + ctl.len() as winapi::DWORD, + wincrypt::CERT_STORE_ADD_ALWAYS, + &mut ctl_context); + if res == winapi::TRUE { + Ok(CtlContext::from_inner(ctl_context)) + } else { + Err(io::Error::last_os_error()) + } + } + } + + /// Consumes this memory store, returning the underlying `CertStore`. + pub fn into_store(self) -> CertStore { + self.0 + } +} + +#[cfg(test)] +mod test { + use super::*; + use ctl_context::CtlContext; + + #[test] + fn load() { + let cert = include_bytes!("../test/cert.der"); + let mut store = Memory::new().unwrap(); + store.add_encoded_certificate(cert).unwrap(); + } + + #[test] + fn create_ctl() { + let cert = include_bytes!("../test/self-signed.badssl.com.cer"); + let mut store = Memory::new().unwrap(); + let cert = store.add_encoded_certificate(cert).unwrap(); + + CtlContext::builder() + .certificate(cert) + .usage("1.3.6.1.4.1.311.2.2.2") + .encode_and_sign() + .unwrap(); + } + + #[test] + fn pfx_import() { + let pfx = include_bytes!("../test/identity.p12"); + let store = PfxImportOptions::new() + .include_extended_properties(true) + .password("mypass") + .import(pfx) + .unwrap(); + assert_eq!(store.certs().count(), 2); + let pkeys = store.certs() + .filter(|c| { + c.private_key().compare_key(true).silent(true).acquire().is_ok() + }) + .count(); + assert_eq!(pkeys, 1); + } +} diff --git a/schannel/src/context_buffer.rs b/schannel/src/context_buffer.rs new file mode 100644 index 000000000..efad51443 --- /dev/null +++ b/schannel/src/context_buffer.rs @@ -0,0 +1,21 @@ +use winapi::shared::sspi; +use std::ops::Deref; +use std::slice; + +pub struct ContextBuffer(pub sspi::SecBuffer); + +impl Drop for ContextBuffer { + fn drop(&mut self) { + unsafe { + sspi::FreeContextBuffer(self.0.pvBuffer); + } + } +} + +impl Deref for ContextBuffer { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.0.pvBuffer as *const _, self.0.cbBuffer as usize) } + } +} diff --git a/schannel/src/crypt_key.rs b/schannel/src/crypt_key.rs new file mode 100644 index 000000000..e64b5f2b0 --- /dev/null +++ b/schannel/src/crypt_key.rs @@ -0,0 +1,15 @@ +//! CryptoAPI private keys. +use winapi::um::wincrypt; + +/// A handle to a key. +pub struct CryptKey(wincrypt::HCRYPTKEY); + +impl Drop for CryptKey { + fn drop(&mut self) { + unsafe { + wincrypt::CryptDestroyKey(self.0); + } + } +} + +inner!(CryptKey, wincrypt::HCRYPTKEY); diff --git a/schannel/src/crypt_prov.rs b/schannel/src/crypt_prov.rs new file mode 100644 index 000000000..dc97fa90a --- /dev/null +++ b/schannel/src/crypt_prov.rs @@ -0,0 +1,224 @@ +//! CryptoAPI key providers. +use std::io; +use std::ptr; +use winapi::shared::minwindef as winapi; +use winapi::um::winbase; +use winapi::um::wincrypt; + +use Inner; +use crypt_key::CryptKey; + +/// A CryptoAPI handle to a provider of a key. +pub struct CryptProv(wincrypt::HCRYPTPROV); + +impl Drop for CryptProv { + fn drop(&mut self) { + unsafe { + wincrypt::CryptReleaseContext(self.0, 0); + } + } +} + +inner!(CryptProv, wincrypt::HCRYPTPROV); + +impl CryptProv { + /// Imports a key into this provider. + pub fn import<'a>(&'a mut self) -> ImportOptions<'a> { + ImportOptions { + prov: self, + flags: 0, + } + } +} + +/// A builder for `CryptProv`s. +pub struct AcquireOptions { + container: Option<Vec<u16>>, + provider: Option<Vec<u16>>, + flags: winapi::DWORD, +} + +impl AcquireOptions { + /// Returns a new builder with default settings. + pub fn new() -> AcquireOptions { + AcquireOptions { + container: None, + provider: None, + flags: 0, + } + } + + /// Sets the name for this key container. + /// + /// This should not be set if `verify_context` is set. + pub fn container(&mut self, container: &str) -> &mut AcquireOptions { + self.container = Some(container.encode_utf16().chain(Some(0)).collect()); + self + } + + /// Sets the name of the CSP to be used. + pub fn provider(&mut self, provider: &str) -> &mut AcquireOptions { + self.provider = Some(provider.encode_utf16().chain(Some(0)).collect()); + self + } + + /// If set, private keys will not be accessible or persisted. + pub fn verify_context(&mut self, verify_context: bool) -> &mut AcquireOptions { + self.flag(wincrypt::CRYPT_VERIFYCONTEXT, verify_context) + } + + /// If set, the container will be created. + pub fn new_keyset(&mut self, new_keyset: bool) -> &mut AcquireOptions { + self.flag(wincrypt::CRYPT_NEWKEYSET, new_keyset) + } + + /// If set, the container will be stored as a machine rather than user keys. + pub fn machine_keyset(&mut self, machine_keyset: bool) -> &mut AcquireOptions { + self.flag(wincrypt::CRYPT_MACHINE_KEYSET, machine_keyset) + } + + /// If set, an error will be returned if user intervention is required + /// rather than displaying a dialog. + pub fn silent(&mut self, silent: bool) -> &mut AcquireOptions { + self.flag(wincrypt::CRYPT_SILENT, silent) + } + + fn flag(&mut self, flag: winapi::DWORD, on: bool) -> &mut AcquireOptions { + if on { + self.flags |= flag; + } else { + self.flags &= !flag; + } + + self + } + + /// Acquires a container. + pub fn acquire(&self, type_: ProviderType) -> io::Result<CryptProv> { + unsafe { + let container = self.container.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + let provider = self.provider.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()); + + let mut prov = 0; + let res = wincrypt::CryptAcquireContextW(&mut prov, + container as *mut _, + provider as *mut _, + type_.0, + self.flags); + if res == winapi::TRUE { + Ok(CryptProv(prov)) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +/// An identifier of the type of cryptography provider to be used with a +/// container. +#[derive(Copy, Clone)] +pub struct ProviderType(winapi::DWORD); + +#[allow(missing_docs)] +impl ProviderType { + pub fn rsa_full() -> ProviderType { + ProviderType(wincrypt::PROV_RSA_FULL) + } + + pub fn rsa_aes() -> ProviderType { + ProviderType(wincrypt::PROV_RSA_AES) + } + + pub fn rsa_sig() -> ProviderType { + ProviderType(wincrypt::PROV_RSA_SIG) + } + + pub fn rsa_schannel() -> ProviderType { + ProviderType(wincrypt::PROV_RSA_SCHANNEL) + } + + pub fn dss() -> ProviderType { + ProviderType(wincrypt::PROV_DSS) + } + + pub fn dss_dh() -> ProviderType { + ProviderType(wincrypt::PROV_DSS_DH) + } + + pub fn dh_schannel() -> ProviderType { + ProviderType(wincrypt::PROV_DH_SCHANNEL) + } + + pub fn fortezza() -> ProviderType { + ProviderType(wincrypt::PROV_FORTEZZA) + } + + pub fn ms_exchange() -> ProviderType { + ProviderType(wincrypt::PROV_MS_EXCHANGE) + } + + pub fn ssl() -> ProviderType { + ProviderType(wincrypt::PROV_SSL) + } + + pub fn as_raw(&self) -> winapi::DWORD { + self.0 + } +} + +/// A builder for key imports. +pub struct ImportOptions<'a> { + prov: &'a mut CryptProv, + flags: winapi::DWORD, +} + +impl<'a> ImportOptions<'a> { + /// Imports a DER-encoded private key. + pub fn import(&mut self, der: &[u8]) -> io::Result<CryptKey> { + unsafe { + assert!(der.len() <= winapi::DWORD::max_value() as usize); + let mut buf = ptr::null_mut(); + let mut len = 0; + let res = wincrypt::CryptDecodeObjectEx(wincrypt::X509_ASN_ENCODING | + wincrypt::PKCS_7_ASN_ENCODING, + wincrypt::PKCS_RSA_PRIVATE_KEY, + der.as_ptr(), + der.len() as winapi::DWORD, + wincrypt::CRYPT_DECODE_ALLOC_FLAG, + ptr::null_mut(), + &mut buf as *mut _ as winapi::LPVOID, + &mut len); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()); + } + + let mut key = 0; + let res = wincrypt::CryptImportKey(self.prov.0, buf, len, 0, self.flags, &mut key); + winbase::LocalFree(buf as *mut _); + + if res == winapi::TRUE { + Ok(CryptKey::from_inner(key)) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn rsa_key() { + let key = include_bytes!("../test/key.key"); + + let mut context = AcquireOptions::new() + .verify_context(true) + .acquire(ProviderType::rsa_full()) + .unwrap(); + context.import() + .import(key) + .unwrap(); + } +} diff --git a/schannel/src/ctl_context.rs b/schannel/src/ctl_context.rs new file mode 100644 index 000000000..e9f2769e3 --- /dev/null +++ b/schannel/src/ctl_context.rs @@ -0,0 +1,187 @@ +//! Bindings to Certificate Trust Lists (CTL) in winapi. + +#![allow(dead_code)] + +use std::io; +use std::mem; +use std::ptr; +use winapi::shared::minwindef as winapi; +use winapi::shared::ntdef; +use winapi::um::wincrypt; + +use cert_context::CertContext; +use Inner; + +lazy_static! { + static ref szOID_OIWSEC_sha1: Vec<u8> = + wincrypt::szOID_OIWSEC_sha1.bytes().chain(Some(0)).collect(); +} + +/// Wrapped `PCCTL_CONTEXT` which represents a certificate trust list to +/// Windows. +pub struct CtlContext(wincrypt::PCCTL_CONTEXT); + +unsafe impl Send for CtlContext {} +unsafe impl Sync for CtlContext {} + +impl Drop for CtlContext { + fn drop(&mut self) { + unsafe { + wincrypt::CertFreeCTLContext(self.0); + } + } +} + +impl Inner<wincrypt::PCCTL_CONTEXT> for CtlContext { + unsafe fn from_inner(t: wincrypt::PCCTL_CONTEXT) -> CtlContext { + CtlContext(t) + } + + fn as_inner(&self) -> wincrypt::PCCTL_CONTEXT { + self.0 + } + + fn get_mut(&mut self) -> &mut wincrypt::PCCTL_CONTEXT { + &mut self.0 + } +} + +impl CtlContext { + /// Returns a builder reader to create an encoded `CtlContext`. + pub fn builder() -> Builder { + Builder { + certificates: vec![], + usages: vec![], + } + } +} + +/// Used to build an encoded `CtlContext` which can be added to a `Memory` store +/// to get back the actual `CtlContext`. +pub struct Builder { + certificates: Vec<CertContext>, + usages: Vec<Vec<u8>>, +} + +impl Builder { + /// Adds a certificate to be passed to `CryptMsgEncodeAndSignCTL` later on. + pub fn certificate(&mut self, cert: CertContext) -> &mut Builder { + self.certificates.push(cert); + self + } + + /// Adds a usage string to be passed in the `SubjectUsage` field to + /// `CryptMsgEncodeAndSignCTL` later on. + pub fn usage(&mut self, usage: &str) -> &mut Builder { + let mut usage = usage.as_bytes().to_owned(); + usage.push(0); + self.usages.push(usage); + self + } + + /// Calls `CryptMsgEncodeAndSignCTL` to encode this list of certificates + /// into a CTL. + /// + /// This can later be passed to `Memory::add_encoded_ctl`. + pub fn encode_and_sign(&self) -> io::Result<Vec<u8>> { + unsafe { + let encoding = wincrypt::X509_ASN_ENCODING | wincrypt::PKCS_7_ASN_ENCODING; + + let mut usages = self.usages.iter().map(|u| u.as_ptr()).collect::<Vec<_>>(); + let mut entry_data = vec![]; + let mut entries = vec![]; + for certificate in &self.certificates { + let data = try!(cert_entry(certificate)); + entries.push(*(data.as_ptr() as *const wincrypt::CTL_ENTRY)); + entry_data.push(data); + } + + let mut ctl_info: wincrypt::CTL_INFO = mem::zeroed(); + ctl_info.dwVersion = wincrypt::CTL_V1; + ctl_info.SubjectUsage.cUsageIdentifier = usages.len() as winapi::DWORD; + ctl_info.SubjectUsage.rgpszUsageIdentifier = usages.as_mut_ptr() as *mut ntdef::LPSTR; + ctl_info.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1.as_ptr() as ntdef::LPSTR; + ctl_info.cCTLEntry = entries.len() as winapi::DWORD; + ctl_info.rgCTLEntry = entries.as_mut_ptr(); + + let mut sign_info: wincrypt::CMSG_SIGNED_ENCODE_INFO = mem::zeroed(); + sign_info.cbSize = mem::size_of_val(&sign_info) as winapi::DWORD; + let mut encoded_certs = self.certificates + .iter() + .map(|c| { + wincrypt::CERT_BLOB { + cbData: (*c.as_inner()).cbCertEncoded, + pbData: (*c.as_inner()).pbCertEncoded, + } + }) + .collect::<Vec<_>>(); + sign_info.rgCertEncoded = encoded_certs.as_mut_ptr(); + sign_info.cCertEncoded = encoded_certs.len() as winapi::DWORD; + + let flags = wincrypt::CMSG_ENCODE_SORTED_CTL_FLAG | + wincrypt::CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG; + + let mut size = 0; + + let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding, + &mut ctl_info, + &mut sign_info, + flags, + ptr::null_mut(), + &mut size); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()) + } + + let mut encoded = vec![0; size as usize]; + + let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding, + &mut ctl_info, + &mut sign_info, + flags, + encoded.as_mut_ptr() as *mut winapi::BYTE, + &mut size); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()) + } + + Ok(encoded) + } + } +} + +fn cert_entry(cert: &CertContext) -> io::Result<Vec<u8>> { + // FIXME: Seems to be missing since the winapi 0.3 upgrade? + const CTL_ENTRY_FROM_PROP_CHAIN_FLAG: winapi::DWORD = 1; + + unsafe { + let mut size = 0; + + let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties( + cert.as_inner(), + 0, + ptr::null_mut(), + CTL_ENTRY_FROM_PROP_CHAIN_FLAG, + ptr::null_mut(), + ptr::null_mut(), + &mut size); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()); + } + + let mut entry = vec![0u8; size as usize]; + let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties( + cert.as_inner(), + 0, + ptr::null_mut(), + CTL_ENTRY_FROM_PROP_CHAIN_FLAG, + ptr::null_mut(), + entry.as_mut_ptr() as wincrypt::PCTL_ENTRY, + &mut size); + if res == winapi::FALSE { + Err(io::Error::last_os_error()) + } else { + Ok(entry) + } + } +} diff --git a/schannel/src/key_handle.rs b/schannel/src/key_handle.rs new file mode 100644 index 000000000..7e458f274 --- /dev/null +++ b/schannel/src/key_handle.rs @@ -0,0 +1,5 @@ +//! Deprecated. +#![deprecated(note = "use cert_context::PrivateKey", since = "0.1.5")] + +#[deprecated(note = "use cert_context::PrivateKey", since = "0.1.5")] +pub use cert_context::PrivateKey as KeyHandle; diff --git a/schannel/src/lib.rs b/schannel/src/lib.rs new file mode 100644 index 000000000..4743e6ca5 --- /dev/null +++ b/schannel/src/lib.rs @@ -0,0 +1,87 @@ +//! Bindings to the Windows SChannel APIs. +#![cfg(windows)] +#![warn(missing_docs)] +#![allow(non_upper_case_globals)] + +extern crate winapi; + +#[macro_use] +extern crate lazy_static; + +use std::ptr; +use winapi::ctypes; +use winapi::shared::sspi; + +macro_rules! inner { + ($t:path, $raw:ty) => { + impl ::Inner<$raw> for $t { + unsafe fn from_inner(t: $raw) -> Self { + $t(t) + } + + fn as_inner(&self) -> $raw { + self.0 + } + + fn get_mut(&mut self) -> &mut $raw { + &mut self.0 + } + } + } +} + +pub mod cert_chain; +pub mod cert_context; +pub mod cert_store; +pub mod crypt_key; +pub mod crypt_prov; +/* pub */ mod ctl_context; +pub mod key_handle; +pub mod ncrypt_key; +pub mod schannel_cred; +pub mod tls_stream; + +mod context_buffer; +mod security_context; + +#[cfg(test)] +mod test; + +const ACCEPT_REQUESTS: ctypes::c_ulong = + sspi::ASC_REQ_ALLOCATE_MEMORY | sspi::ASC_REQ_CONFIDENTIALITY | + sspi::ASC_REQ_SEQUENCE_DETECT | sspi::ASC_REQ_STREAM | + sspi::ASC_REQ_REPLAY_DETECT; + +const INIT_REQUESTS: ctypes::c_ulong = + sspi::ISC_REQ_CONFIDENTIALITY | sspi::ISC_REQ_INTEGRITY | sspi::ISC_REQ_REPLAY_DETECT | + sspi::ISC_REQ_SEQUENCE_DETECT | sspi::ISC_REQ_MANUAL_CRED_VALIDATION | + sspi::ISC_REQ_ALLOCATE_MEMORY | sspi::ISC_REQ_STREAM | sspi::ISC_REQ_USE_SUPPLIED_CREDS; + +trait Inner<T> { + unsafe fn from_inner(t: T) -> Self; + + fn as_inner(&self) -> T; + + fn get_mut(&mut self) -> &mut T; +} + +unsafe fn secbuf(buftype: ctypes::c_ulong, + bytes: Option<&mut [u8]>) -> sspi::SecBuffer { + let (ptr, len) = match bytes { + Some(bytes) => (bytes.as_mut_ptr(), bytes.len() as ctypes::c_ulong), + None => (ptr::null_mut(), 0), + }; + sspi::SecBuffer { + BufferType: buftype, + cbBuffer: len, + pvBuffer: ptr as *mut ctypes::c_void, + } +} + +unsafe fn secbuf_desc(bufs: &mut [sspi::SecBuffer]) -> sspi::SecBufferDesc { + sspi::SecBufferDesc { + ulVersion: sspi::SECBUFFER_VERSION, + cBuffers: bufs.len() as ctypes::c_ulong, + pBuffers: bufs.as_mut_ptr(), + } +} diff --git a/schannel/src/ncrypt_key.rs b/schannel/src/ncrypt_key.rs new file mode 100644 index 000000000..1b5af3b9c --- /dev/null +++ b/schannel/src/ncrypt_key.rs @@ -0,0 +1,15 @@ +//! CNG private keys. +use winapi::um::ncrypt; + +/// A CNG handle to a key. +pub struct NcryptKey(ncrypt::NCRYPT_KEY_HANDLE); + +impl Drop for NcryptKey { + fn drop(&mut self) { + unsafe { + ncrypt::NCryptFreeObject(self.0); + } + } +} + +inner!(NcryptKey, ncrypt::NCRYPT_KEY_HANDLE); diff --git a/schannel/src/schannel_cred.rs b/schannel/src/schannel_cred.rs new file mode 100644 index 000000000..840db1695 --- /dev/null +++ b/schannel/src/schannel_cred.rs @@ -0,0 +1,262 @@ +//! Schannel credentials. +use winapi::shared::{sspi, winerror}; +use winapi::shared::minwindef as winapi; +use winapi::um::{self, wincrypt}; +use std::io; +use std::mem; +use std::ptr; + +use Inner; +use cert_context::CertContext; + +lazy_static! { + static ref UNISP_NAME: Vec<u8> = um::schannel::UNISP_NAME.bytes().chain(Some(0)).collect(); +} + +/// The communication direction that an `SchannelCred` will support. +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +pub enum Direction { + /// Server-side, inbound connections. + Inbound, + /// Client-side, outbound connections. + Outbound, +} + +/// Algorithms supported by Schannel. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +pub enum Algorithm { + /// Advanced Encryption Standard (AES). + Aes = wincrypt::CALG_AES, + /// 128 bit AES. + Aes128 = wincrypt::CALG_AES_128, + /// 192 bit AES. + Aes192 = wincrypt::CALG_AES_192, + /// 256 bit AES. + Aes256 = wincrypt::CALG_AES_256, + /// Temporary algorithm identifier for handles of Diffie-Hellman–agreed keys. + AgreedkeyAny = wincrypt::CALG_AGREEDKEY_ANY, + /// An algorithm to create a 40-bit DES key that has parity bits and zeroed key bits to make + /// its key length 64 bits. + CylinkMek = wincrypt::CALG_CYLINK_MEK, + /// DES encryption algorithm. + Des = wincrypt::CALG_DES, + /// DESX encryption algorithm. + Desx = wincrypt::CALG_DESX, + /// Diffie-Hellman ephemeral key exchange algorithm. + DhEphem = wincrypt::CALG_DH_EPHEM, + /// Diffie-Hellman store and forward key exchange algorithm. + DhSf = wincrypt::CALG_DH_SF, + /// DSA public key signature algorithm. + DssSign = wincrypt::CALG_DSS_SIGN, + /// Elliptic curve Diffie-Hellman key exchange algorithm. + Ecdh = wincrypt::CALG_ECDH, + // https://github.com/retep998/wincrypt-rs/issues/287 + // /// Ephemeral elliptic curve Diffie-Hellman key exchange algorithm. + // EcdhEphem = wincrypt::CALG_ECDH_EPHEM, + /// Elliptic curve digital signature algorithm. + Ecdsa = wincrypt::CALG_ECDSA, + /// One way function hashing algorithm. + HashReplaceOwf = wincrypt::CALG_HASH_REPLACE_OWF, + /// Hughes MD5 hashing algorithm. + HughesMd5 = wincrypt::CALG_HUGHES_MD5, + /// HMAC keyed hash algorithm. + Hmac = wincrypt::CALG_HMAC, + /// MAC keyed hash algorithm. + Mac = wincrypt::CALG_MAC, + /// MD2 hashing algorithm. + Md2 = wincrypt::CALG_MD2, + /// MD4 hashing algorithm. + Md4 = wincrypt::CALG_MD4, + /// MD5 hashing algorithm. + Md5 = wincrypt::CALG_MD5, + /// No signature algorithm.. + NoSign = wincrypt::CALG_NO_SIGN, + /// RC2 block encryption algorithm. + Rc2 = wincrypt::CALG_RC2, + /// RC4 stream encryption algorithm. + Rc4 = wincrypt::CALG_RC4, + /// RC5 block encryption algorithm. + Rc5 = wincrypt::CALG_RC5, + /// RSA public key exchange algorithm. + RsaKeyx = wincrypt::CALG_RSA_KEYX, + /// RSA public key signature algorithm. + RsaSign = wincrypt::CALG_RSA_SIGN, + /// SHA hashing algorithm. + Sha1 = wincrypt::CALG_SHA1, + /// 256 bit SHA hashing algorithm. + Sha256 = wincrypt::CALG_SHA_256, + /// 384 bit SHA hashing algorithm. + Sha384 = wincrypt::CALG_SHA_384, + /// 512 bit SHA hashing algorithm. + Sha512 = wincrypt::CALG_SHA_512, + /// Triple DES encryption algorithm. + TripleDes = wincrypt::CALG_3DES, + /// Two-key triple DES encryption with effective key length equal to 112 bits. + TripleDes112 = wincrypt::CALG_3DES_112, + #[doc(hidden)] + __ForExtensibility, +} + +/// Protocols supported by Schannel. +#[derive(Debug, Copy, Clone)] +pub enum Protocol { + /// Secure Sockets Layer 3.0 + Ssl3, + /// Transport Layer Security 1.0 + Tls10, + /// Transport Layer Security 1.1 + Tls11, + /// Transport Layer Security 1.2 + Tls12, + #[doc(hidden)] + __ForExtensibility, +} + +impl Protocol { + fn dword(self, direction: Direction) -> winapi::DWORD { + match (self, direction) { + (Protocol::Ssl3, Direction::Inbound) => um::schannel::SP_PROT_SSL3_SERVER, + (Protocol::Tls10, Direction::Inbound) => um::schannel::SP_PROT_TLS1_0_SERVER, + (Protocol::Tls11, Direction::Inbound) => um::schannel::SP_PROT_TLS1_1_SERVER, + (Protocol::Tls12, Direction::Inbound) => um::schannel::SP_PROT_TLS1_2_SERVER, + (Protocol::Ssl3, Direction::Outbound) => um::schannel::SP_PROT_SSL3_CLIENT, + (Protocol::Tls10, Direction::Outbound) => um::schannel::SP_PROT_TLS1_0_CLIENT, + (Protocol::Tls11, Direction::Outbound) => um::schannel::SP_PROT_TLS1_1_CLIENT, + (Protocol::Tls12, Direction::Outbound) => um::schannel::SP_PROT_TLS1_2_CLIENT, + (Protocol::__ForExtensibility, _) => unreachable!(), + } + } +} + +/// A builder type for `SchannelCred`s. +#[derive(Default, Debug)] +pub struct Builder { + supported_algorithms: Option<Vec<Algorithm>>, + enabled_protocols: Option<Vec<Protocol>>, + certs: Vec<CertContext>, +} + +impl Builder { + /// Returns a new `Builder`. + pub fn new() -> Builder { + Builder::default() + } + + /// Sets the algorithms supported for credentials created from this builder. + pub fn supported_algorithms(&mut self, + supported_algorithms: &[Algorithm]) + -> &mut Builder { + assert!(supported_algorithms.iter() + .all(|a| { + match *a { + Algorithm::__ForExtensibility => false, + _ => true, + } + })); + self.supported_algorithms = Some(supported_algorithms.to_owned()); + self + } + + /// Sets the protocols enabled for credentials created from this builder. + pub fn enabled_protocols(&mut self, + enabled_protocols: &[Protocol]) + -> &mut Builder { + assert!(enabled_protocols.iter() + .all(|a| { + match *a { + Protocol::__ForExtensibility => false, + _ => true, + } + })); + self.enabled_protocols = Some(enabled_protocols.to_owned()); + self + } + + /// Add a certificate to get passed down when the credentials are acquired. + /// + /// Certificates passed here may specify a certificate that contains a + /// private key to be used in authenticating the application. Typically, + /// this is called once for each key exchange method supported by + /// servers. + /// + /// Clients often do not call this function and either depend on Schannel to + /// find an appropriate certificate or create a certificate later if needed. + pub fn cert(&mut self, cx: CertContext) -> &mut Builder { + self.certs.push(cx); + self + } + + /// Creates a new `SchannelCred`. + pub fn acquire(&self, direction: Direction) -> io::Result<SchannelCred> { + unsafe { + let mut handle = mem::zeroed(); + let mut cred_data: um::schannel::SCHANNEL_CRED = mem::zeroed(); + cred_data.dwVersion = um::schannel::SCHANNEL_CRED_VERSION; + cred_data.dwFlags = um::schannel::SCH_USE_STRONG_CRYPTO | um::schannel::SCH_CRED_NO_DEFAULT_CREDS; + if let Some(ref supported_algorithms) = self.supported_algorithms { + cred_data.cSupportedAlgs = supported_algorithms.len() as winapi::DWORD; + cred_data.palgSupportedAlgs = supported_algorithms.as_ptr() as *mut _; + } + if let Some(ref enabled_protocols) = self.enabled_protocols { + cred_data.grbitEnabledProtocols = enabled_protocols.iter() + .map(|p| p.dword(direction)) + .fold(0, |acc, p| acc | p); + } + let mut certs = self.certs.iter().map(|c| c.as_inner()).collect::<Vec<_>>(); + cred_data.cCreds = certs.len() as winapi::DWORD; + cred_data.paCred = certs.as_mut_ptr(); + + let direction = match direction { + Direction::Inbound => sspi::SECPKG_CRED_INBOUND, + Direction::Outbound => sspi::SECPKG_CRED_OUTBOUND, + }; + + match sspi::AcquireCredentialsHandleA(ptr::null_mut(), + UNISP_NAME.as_ptr() as *const _ as *mut _, + direction, + ptr::null_mut(), + &mut cred_data as *mut _ as *mut _, + None, + ptr::null_mut(), + &mut handle, + ptr::null_mut()) { + winerror::SEC_E_OK => Ok(SchannelCred(handle)), + err => Err(io::Error::from_raw_os_error(err as i32)), + } + } + } +} + +/// An SChannel credential. +pub struct SchannelCred(sspi::CredHandle); + +impl Drop for SchannelCred { + fn drop(&mut self) { + unsafe { + sspi::FreeCredentialsHandle(&mut self.0); + } + } +} + +impl Inner<sspi::CredHandle> for SchannelCred { + unsafe fn from_inner(inner: sspi::CredHandle) -> SchannelCred { + SchannelCred(inner) + } + + fn as_inner(&self) -> sspi::CredHandle { + self.0 + } + + fn get_mut(&mut self) -> &mut sspi::CredHandle { + &mut self.0 + } +} + +impl SchannelCred { + /// Returns a builder. + pub fn builder() -> Builder { + Builder::new() + } +} diff --git a/schannel/src/security_context.rs b/schannel/src/security_context.rs new file mode 100644 index 000000000..0eea1dfa8 --- /dev/null +++ b/schannel/src/security_context.rs @@ -0,0 +1,112 @@ +use winapi::shared::{sspi, winerror}; +use winapi::shared::minwindef::ULONG; +use winapi::um::{minschannel}; +use std::mem; +use std::ptr; +use std::io; + +use {INIT_REQUESTS, Inner, secbuf, secbuf_desc}; +use cert_context::CertContext; +use context_buffer::ContextBuffer; + +use schannel_cred::SchannelCred; + +pub struct SecurityContext(sspi::CtxtHandle); + +impl Drop for SecurityContext { + fn drop(&mut self) { + unsafe { + sspi::DeleteSecurityContext(&mut self.0); + } + } +} + +impl Inner<sspi::CtxtHandle> for SecurityContext { + unsafe fn from_inner(inner: sspi::CtxtHandle) -> SecurityContext { + SecurityContext(inner) + } + + fn as_inner(&self) -> sspi::CtxtHandle { + self.0 + } + + fn get_mut(&mut self) -> &mut sspi::CtxtHandle { + &mut self.0 + } +} + +impl SecurityContext { + pub fn initialize(cred: &mut SchannelCred, + accept: bool, + domain: Option<&[u16]>) + -> io::Result<(SecurityContext, Option<ContextBuffer>)> { + unsafe { + let mut ctxt = mem::zeroed(); + + if accept { + // If we're performing an accept then we need to wait to call + // `AcceptSecurityContext` until we've actually read some data. + return Ok((SecurityContext(ctxt), None)) + } + + let domain = domain.map(|b| b.as_ptr() as *mut u16).unwrap_or(ptr::null_mut()); + + let mut outbuf = [secbuf(sspi::SECBUFFER_EMPTY, None)]; + let mut outbuf_desc = secbuf_desc(&mut outbuf); + + let mut attributes = 0; + + match sspi::InitializeSecurityContextW(cred.get_mut(), + ptr::null_mut(), + domain, + INIT_REQUESTS, + 0, + 0, + ptr::null_mut(), + 0, + &mut ctxt, + &mut outbuf_desc, + &mut attributes, + ptr::null_mut()) { + winerror::SEC_I_CONTINUE_NEEDED => { + Ok((SecurityContext(ctxt), Some(ContextBuffer(outbuf[0])))) + } + err => { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + } + } + + unsafe fn attribute<T>(&self, attr: ULONG) -> io::Result<T> { + let mut value = mem::uninitialized::<T>(); + let status = sspi::QueryContextAttributesW(&self.0 as *const _ as *mut _, + attr, + &mut value as *mut _ as *mut _); + if status == winerror::SEC_E_OK { + Ok(value) + } else { + Err(io::Error::from_raw_os_error(status as i32)) + } + } + + pub fn stream_sizes(&self) -> io::Result<sspi::SecPkgContext_StreamSizes> { + unsafe { + self.attribute(sspi::SECPKG_ATTR_STREAM_SIZES) + } + } + + pub fn remote_cert(&self) -> io::Result<CertContext> { + unsafe { + self.attribute(minschannel::SECPKG_ATTR_REMOTE_CERT_CONTEXT) + .map(|p| CertContext::from_inner(p)) + } + } + + pub fn local_cert(&self) -> io::Result<CertContext> { + unsafe { + self.attribute(minschannel::SECPKG_ATTR_LOCAL_CERT_CONTEXT) + .map(|p| CertContext::from_inner(p)) + } + } +} diff --git a/schannel/src/test.rs b/schannel/src/test.rs new file mode 100644 index 000000000..8f0a26a2c --- /dev/null +++ b/schannel/src/test.rs @@ -0,0 +1,655 @@ +use std::env; +use std::io::{self, Read, Write, Error}; +use std::mem; +use std::net::{TcpStream, TcpListener}; +use std::ptr; +use std::sync::{Once, ONCE_INIT}; +use std::thread; +use winapi::shared::minwindef as winapi; +use winapi::shared::{basetsd, ntdef, lmcons, winerror}; +use winapi::um::{minwinbase, sysinfoapi, timezoneapi, wincrypt}; + +use Inner; +use crypt_prov::{AcquireOptions, ProviderType}; +use cert_context::{CertContext, KeySpec, HashAlgorithm}; +use cert_store::{CertStore, Memory, CertAdd}; +use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred}; +use tls_stream::{self, HandshakeError}; + +#[test] +fn basic() { + let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("google.com") + .connect(creds, stream) + .unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut out = vec![]; + stream.read_to_end(&mut out).unwrap(); + assert!(out.starts_with(b"HTTP/1.0 200 OK") || out.starts_with(b"HTTP/1.0 302 Found")); + assert!(out.ends_with(b"</html>") || out.ends_with(b"</HTML>\r\n")); +} + +#[test] +fn invalid_algorithms() { + let creds = SchannelCred::builder() + .supported_algorithms(&[Algorithm::Rc2, Algorithm::Ecdsa]) + .acquire(Direction::Outbound); + assert_eq!(creds.err().unwrap().raw_os_error().unwrap(), + winerror::SEC_E_ALGORITHM_MISMATCH as i32); +} + +#[test] +fn valid_algorithms() { + let creds = SchannelCred::builder() + .supported_algorithms(&[Algorithm::Aes128, Algorithm::Ecdsa]) + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("google.com") + .connect(creds, stream) + .unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut out = vec![]; + stream.read_to_end(&mut out).unwrap(); + assert!(out.starts_with(b"HTTP/1.0 200 OK") || out.starts_with(b"HTTP/1.0 302 Found")); + assert!(out.ends_with(b"</html>") || out.ends_with(b"</HTML>\r\n")); +} + +fn unwrap_handshake<S>(e: HandshakeError<S>) -> io::Error { + match e { + HandshakeError::Failure(e) => e, + HandshakeError::Interrupted(_) => panic!("not an I/O error"), + } +} + +#[test] +#[ignore] // google's inconsistent about disallowing sslv3 +fn invalid_protocol() { + let creds = SchannelCred::builder() + .enabled_protocols(&[Protocol::Ssl3]) + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("google.com") + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), + winerror::SEC_E_UNSUPPORTED_FUNCTION as i32); +} + +#[test] +fn valid_protocol() { + let creds = SchannelCred::builder() + .enabled_protocols(&[Protocol::Tls12]) + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("google.com") + .connect(creds, stream) + .unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut out = vec![]; + stream.read_to_end(&mut out).unwrap(); + assert!(out.starts_with(b"HTTP/1.0 200 OK") || out.starts_with(b"HTTP/1.0 302 Found")); + assert!(out.ends_with(b"</html>") || out.ends_with(b"</HTML>\r\n")); +} + +#[test] +fn valid_protocol_with_intermediate_certs() { + let creds = SchannelCred::builder() + .enabled_protocols(&[Protocol::Tls12]) + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("lh3.googleusercontent.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("lh3.googleusercontent.com") + .connect(creds, stream) + .unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut out = vec![]; + stream.read_to_end(&mut out).unwrap(); + assert!(out.starts_with(b"HTTP/1.0 200 OK") || out.starts_with(b"HTTP/1.0 302 Found")); + assert!(out.ends_with(b"</html>") || out.ends_with(b"</HTML>\r\n")); +} + +#[test] +fn expired_cert() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("expired.badssl.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("expired.badssl.com") + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), winerror::CERT_E_EXPIRED as i32); +} + +#[test] +fn self_signed_cert() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("self-signed.badssl.com") + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), + winerror::CERT_E_UNTRUSTEDROOT as i32); +} + +#[test] +fn self_signed_cert_manual_trust() { + let cert = include_bytes!("../test/self-signed.badssl.com.cer"); + let mut store = Memory::new().unwrap(); + store.add_encoded_certificate(cert).unwrap(); + + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap(); + tls_stream::Builder::new() + .domain("self-signed.badssl.com") + .cert_store(store.into_store()) + .connect(creds, stream) + .unwrap(); +} + +#[test] +fn wrong_host_cert() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("wrong.host.badssl.com") + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), + winerror::CERT_E_CN_NO_MATCH as i32); +} + +#[test] +fn wrong_host_cert_ignored() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap(); + tls_stream::Builder::new() + .domain("wrong.host.badssl.com") + .accept_invalid_hostnames(true) + .connect(creds, stream) + .unwrap(); +} + +#[test] +fn shutdown() { + let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("google.com") + .connect(creds, stream) + .unwrap(); + stream.shutdown().unwrap(); +} + +#[test] +fn validation_failure_is_permanent() { + let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap(); + let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap(); + // temporarily switch to nonblocking to allow us to construct the stream + // without validating + stream.set_nonblocking(true).unwrap(); + let stream = tls_stream::Builder::new() + .domain("self-signed.badssl.com") + .connect(creds, stream); + let stream = match stream { + Err(HandshakeError::Interrupted(s)) => s, + _ => panic!(), + }; + stream.get_ref().set_nonblocking(false).unwrap(); + let err = unwrap_handshake(stream.handshake().err().unwrap()); + assert_eq!(err.raw_os_error().unwrap(), + winerror::CERT_E_UNTRUSTEDROOT as i32); +} + +#[test] +fn verify_callback_success() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("self-signed.badssl.com") + .verify_callback(|validation_result| { + assert!(validation_result.result().is_err()); + Ok(()) + }) + .connect(creds, stream) + .unwrap(); + stream.write_all(b"GET / HTTP/1.0\r\nHost: self-signed.badssl.com\r\n\r\n").unwrap(); + let mut out = vec![]; + stream.read_to_end(&mut out).unwrap(); + assert!(out.starts_with(b"HTTP/1.1 200 OK")); + assert!(out.ends_with(b"</html>\n")); +} + +#[test] +fn verify_callback_error() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("google.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("google.com") + .verify_callback(|validation_result| { + assert!(validation_result.result().is_ok()); + Err(io::Error::from_raw_os_error(winerror::CERT_E_UNTRUSTEDROOT)) + }) + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), + winerror::CERT_E_UNTRUSTEDROOT as i32); +} + +#[test] +fn verify_callback_gives_failed_cert() { + let creds = SchannelCred::builder() + .acquire(Direction::Outbound) + .unwrap(); + let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap(); + let err = tls_stream::Builder::new() + .domain("self-signed.badssl.com") + .verify_callback(|validation_result| { + let expected_finger = vec!(122, 87, 211, 36, 62, 157, 55, 233, 199, 67, 98, 104, 235, 3, 235, 46, 216, 240, 82, 150); + assert_eq!(validation_result.failed_certificate().unwrap().fingerprint(HashAlgorithm::sha1()).unwrap(), expected_finger); + Err(io::Error::from_raw_os_error(winerror::CERT_E_UNTRUSTEDROOT)) + }) + .connect(creds, stream) + .err() + .unwrap(); + let err = unwrap_handshake(err); + assert_eq!(err.raw_os_error().unwrap(), + winerror::CERT_E_UNTRUSTEDROOT as i32); +} + +const FRIENDLY_NAME: &'static str = "schannel-rs localhost testing cert"; + +lazy_static! { + static ref szOID_RSA_SHA256RSA: Vec<u8> = + wincrypt::szOID_RSA_SHA256RSA.bytes().chain(Some(0)).collect(); +} + +fn install_certificate() -> io::Result<CertContext> { + unsafe { + let mut provider = 0; + let mut hkey = 0; + + let mut buffer = "schannel-rs test suite".encode_utf16() + .chain(Some(0)) + .collect::<Vec<_>>(); + let res = wincrypt::CryptAcquireContextW(&mut provider, + buffer.as_ptr(), + ptr::null_mut(), + wincrypt::PROV_RSA_FULL, + wincrypt::CRYPT_MACHINE_KEYSET); + if res != winapi::TRUE { + // create a new key container (since it does not exist) + let res = wincrypt::CryptAcquireContextW(&mut provider, + buffer.as_ptr(), + ptr::null_mut(), + wincrypt::PROV_RSA_FULL, + wincrypt::CRYPT_NEWKEYSET | wincrypt::CRYPT_MACHINE_KEYSET); + if res != winapi::TRUE { + return Err(Error::last_os_error()) + } + } + + // create a new keypair (RSA-2048) + let res = wincrypt::CryptGenKey(provider, + wincrypt::AT_SIGNATURE, + 0x0800<<16 | wincrypt::CRYPT_EXPORTABLE, + &mut hkey); + if res != winapi::TRUE { + return Err(Error::last_os_error()); + } + + // start creating the certificate + let name = "CN=localhost,O=schannel-rs,OU=schannel-rs,G=schannel_rs".encode_utf16() + .chain(Some(0)) + .collect::<Vec<_>>(); + let mut cname_buffer: [ntdef::WCHAR; lmcons::UNLEN as usize + 1] = mem::zeroed(); + let mut cname_len = cname_buffer.len() as winapi::DWORD; + let res = wincrypt::CertStrToNameW(wincrypt::X509_ASN_ENCODING, + name.as_ptr(), + wincrypt::CERT_X500_NAME_STR, + ptr::null_mut(), + cname_buffer.as_mut_ptr() as *mut u8, + &mut cname_len, + ptr::null_mut()); + if res != winapi::TRUE { + return Err(Error::last_os_error()); + } + + let mut subject_issuer = wincrypt::CERT_NAME_BLOB { + cbData: cname_len, + pbData: cname_buffer.as_ptr() as *mut u8, + }; + let mut key_provider = wincrypt::CRYPT_KEY_PROV_INFO { + pwszContainerName: buffer.as_mut_ptr(), + pwszProvName: ptr::null_mut(), + dwProvType: wincrypt::PROV_RSA_FULL, + dwFlags: wincrypt::CRYPT_MACHINE_KEYSET, + cProvParam: 0, + rgProvParam: ptr::null_mut(), + dwKeySpec: wincrypt::AT_SIGNATURE, + }; + let mut sig_algorithm = wincrypt::CRYPT_ALGORITHM_IDENTIFIER { + pszObjId: szOID_RSA_SHA256RSA.as_ptr() as *mut _, + Parameters: mem::zeroed(), + }; + let mut expiration_date: minwinbase::SYSTEMTIME = mem::zeroed(); + sysinfoapi::GetSystemTime(&mut expiration_date); + let mut file_time: winapi::FILETIME = mem::zeroed(); + let res = timezoneapi::SystemTimeToFileTime(&mut expiration_date, + &mut file_time); + if res != winapi::TRUE { + return Err(Error::last_os_error()); + } + let mut timestamp: u64 = file_time.dwLowDateTime as u64 | + (file_time.dwHighDateTime as u64) << 32; + // one day, timestamp unit is in 100 nanosecond intervals + timestamp += (1E9 as u64) / 100 * (60 * 60 * 24); + file_time.dwLowDateTime = timestamp as u32; + file_time.dwHighDateTime = (timestamp >> 32) as u32; + let res = timezoneapi::FileTimeToSystemTime(&file_time, + &mut expiration_date); + if res != winapi::TRUE { + return Err(Error::last_os_error()); + } + + // create a self signed certificate + let cert_context = wincrypt::CertCreateSelfSignCertificate(0 as basetsd::ULONG_PTR, + &mut subject_issuer, + 0, + &mut key_provider, + &mut sig_algorithm, + ptr::null_mut(), + &mut expiration_date, + ptr::null_mut()); + if cert_context.is_null() { + return Err(Error::last_os_error()); + } + let cert_context = CertContext::from_inner(cert_context); + try!(cert_context.set_friendly_name(FRIENDLY_NAME)); + + // install the certificate to the machine's local store + io::stdout().write_all(br#" + +The schannel-rs test suite is about to add a certificate to your set of root +and trusted certificates. This certificate should be for the domain "localhost" +with the description related to "schannel". This certificate is only valid for +one day and will be automatically deleted if you re-run the schannel-rs test +suite later. + +If you would rather not do this please cancel the addition and re-run the +test suite with SCHANNEL_RS_SKIP_SERVER_TESTS=1. + +"#).unwrap(); + try!(local_root_store().add_cert(&cert_context, CertAdd::ReplaceExisting)); + Ok(cert_context) + } +} + +fn local_root_store() -> CertStore { + if env::var("APPVEYOR").is_ok() { + CertStore::open_local_machine("Root").unwrap() + } else { + CertStore::open_current_user("Root").unwrap() + } +} + +fn localhost_cert() -> Option<CertContext> { + if env::var("SCHANNEL_RS_SKIP_SERVER_TESTS").is_ok() { + return None + } + + // Our tests need a certficiate that the system trusts to run with, and we + // do this by basically generating a certificate on the fly. This + // initialization block synchronizes tests to ensure that we only generate + // one certificate which is then used by all the tests. + // + // First we check to see if the root trust store already has one of our + // certificates, identified by the "friendly name" we set when the + // certificate was created. If it's expired, then we delete it and generate + // another. If none is found, we also generate another. + // + // Note that generating a certificate and adding it to the root trust store + // will likely trigger a prompt to the user asking if they want to do that, + // so we generate certificates that are valid for some amount of time so you + // don't have to hit the "OK" button each time you run `cargo test`. + // + // After the initialization is performed we just probe the root store again + // and find the certificate we added (or was already there). + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + for cert in local_root_store().certs() { + let name = match cert.friendly_name() { + Ok(name) => name, + Err(_) => continue, + }; + if name != FRIENDLY_NAME { + continue + } + if !cert.is_time_valid().unwrap() { + io::stdout().write_all(br#" + +The schannel-rs test suite is about to delete an old copy of one of its +certificates from your root trust store. This certificate was only valid for one +day and it is no longer needed. The host should be "localhost" and the +description should mention "schannel". + +"#).unwrap(); + cert.delete().unwrap(); + } else { + return + } + } + + install_certificate().unwrap(); + }); + + for cert in local_root_store().certs() { + let name = match cert.friendly_name() { + Ok(name) => name, + Err(_) => continue, + }; + if name == FRIENDLY_NAME { + return Some(cert) + } + } + + panic!("couldn't find a cert"); +} + +#[test] +fn accept_a_socket() { + let cert = match localhost_cert() { + Some(cert) => cert, + None => return, + }; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let t = thread::spawn(move || { + let stream = TcpStream::connect(&addr).unwrap(); + let creds = SchannelCred::builder() + .acquire(Direction::Outbound).unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("localhost") + .connect(creds, stream) + .unwrap(); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.shutdown().unwrap(); + }); + + let stream = listener.accept().unwrap().0; + let creds = SchannelCred::builder() + .cert(cert) + .acquire(Direction::Inbound) + .unwrap(); + let mut stream = tls_stream::Builder::new() + .accept(creds, stream) + .unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + let mut buf = [0; 1]; + assert_eq!(stream.read(&mut buf).unwrap(), 0); + + t.join().unwrap(); +} + +#[test] +fn accept_one_byte_at_a_time() { + let cert = match localhost_cert() { + Some(cert) => cert, + None => return, + }; + + #[derive(Debug)] + struct OneByteAtATime<S> { + inner: S, + } + + impl<S: Read> Read for OneByteAtATime<S> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.read(&mut buf[..1]) + } + } + + impl<S: Write> Write for OneByteAtATime<S> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.inner.write(&buf[..1]) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } + } + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let t = thread::spawn(move || { + let stream = TcpStream::connect(&addr).unwrap(); + let creds = SchannelCred::builder() + .acquire(Direction::Outbound).unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("localhost") + .connect(creds, OneByteAtATime { inner: stream }) + .unwrap(); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.shutdown().unwrap(); + }); + + let stream = listener.accept().unwrap().0; + let creds = SchannelCred::builder() + .cert(cert) + .acquire(Direction::Inbound) + .unwrap(); + let mut stream = tls_stream::Builder::new() + .accept(creds, OneByteAtATime { inner: stream }) + .unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + let mut buf = [0; 1]; + assert_eq!(stream.read(&mut buf).unwrap(), 0); + + t.join().unwrap(); +} + +#[test] +fn split_cert_key() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let t = thread::spawn(move || { + let cert = include_bytes!("../test/cert.der"); + let mut store = Memory::new().unwrap(); + store.add_encoded_certificate(cert).unwrap(); + let store = store.into_store(); + + let stream = TcpStream::connect(&addr).unwrap(); + let creds = SchannelCred::builder() + .acquire(Direction::Outbound).unwrap(); + let mut stream = tls_stream::Builder::new() + .domain("foobar.com") + .cert_store(store) + .connect(creds, stream) + .unwrap(); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.shutdown().unwrap(); + }); + + let cert = include_bytes!("../test/cert.der"); + let cert = CertContext::new(cert).unwrap(); + + let mut options = AcquireOptions::new(); + options.container("schannel-test"); + let type_ = ProviderType::rsa_full(); + + let mut container = match options.acquire(type_) { + Ok(container) => container, + Err(_) => options.new_keyset(true).acquire(type_).unwrap(), + }; + let key = include_bytes!("../test/key.key"); + container.import() + .import(key) + .unwrap(); + + cert.set_key_prov_info() + .container("schannel-test") + .type_(type_) + .keep_open(true) + .key_spec(KeySpec::key_exchange()) + .set() + .unwrap(); + + let stream = listener.accept().unwrap().0; + let creds = SchannelCred::builder() + .cert(cert) + .acquire(Direction::Inbound) + .unwrap(); + let mut stream = tls_stream::Builder::new() + .accept(creds, stream) + .unwrap(); + assert_eq!(stream.read(&mut [0; 1024]).unwrap(), 4); + stream.write_all(&[1, 2, 3, 4]).unwrap(); + stream.flush().unwrap(); + let mut buf = [0; 1]; + assert_eq!(stream.read(&mut buf).unwrap(), 0); + + t.join().unwrap(); +} diff --git a/schannel/src/tls_stream.rs b/schannel/src/tls_stream.rs new file mode 100644 index 000000000..b9ba19645 --- /dev/null +++ b/schannel/src/tls_stream.rs @@ -0,0 +1,944 @@ +//! Schannel TLS streams. +use std::any::Any; +use std::cmp; +use std::error::Error; +use std::fmt; +use std::io::{self, Read, BufRead, Write, Cursor}; +use std::mem; +use std::ptr; +use std::slice; +use std::sync::Arc; +use winapi::shared::minwindef as winapi; +use winapi::shared::{ntdef, sspi, winerror}; +use winapi::um::{self, wincrypt}; + +use {INIT_REQUESTS, ACCEPT_REQUESTS, Inner, secbuf, secbuf_desc}; +use cert_chain::{CertChain, CertChainContext}; +use cert_store::{CertAdd, CertStore}; +use cert_context::CertContext; +use security_context::SecurityContext; +use context_buffer::ContextBuffer; +use schannel_cred::SchannelCred; + +lazy_static! { + static ref szOID_PKIX_KP_SERVER_AUTH: Vec<u8> = + wincrypt::szOID_PKIX_KP_SERVER_AUTH.bytes().chain(Some(0)).collect(); + static ref szOID_SERVER_GATED_CRYPTO: Vec<u8> = + wincrypt::szOID_SERVER_GATED_CRYPTO.bytes().chain(Some(0)).collect(); + static ref szOID_SGC_NETSCAPE: Vec<u8> = + wincrypt::szOID_SGC_NETSCAPE.bytes().chain(Some(0)).collect(); +} + +/// A builder type for `TlsStream`s. +pub struct Builder { + domain: Option<Vec<u16>>, + use_sni: bool, + accept_invalid_hostnames: bool, + verify_callback: Option<Arc<Fn(CertValidationResult) -> io::Result<()> + Sync + Send>>, + cert_store: Option<CertStore>, +} + +impl Default for Builder { + fn default() -> Builder { + Builder { + domain: None, + use_sni: true, + accept_invalid_hostnames: false, + verify_callback: None, + cert_store: None, + } + } +} + +impl Builder { + /// Returns a new `Builder`. + pub fn new() -> Builder { + Builder::default() + } + + /// Sets the domain associated with connections created with this `Builder`. + /// + /// The domain will be used for Server Name Indication as well as + /// certificate validation. + pub fn domain(&mut self, domain: &str) -> &mut Builder { + self.domain = Some(domain.encode_utf16().chain(Some(0)).collect()); + self + } + + /// Determines if Server Name Indication (SNI) will be used. + /// + /// Defaults to `true`. + pub fn use_sni(&mut self, use_sni: bool) -> &mut Builder { + self.use_sni = use_sni; + self + } + + /// Determines if the server's hostname will be checked during certificate verification. + /// + /// Defaults to `false`. + pub fn accept_invalid_hostnames(&mut self, accept_invalid_hostnames: bool) -> &mut Builder { + self.accept_invalid_hostnames = accept_invalid_hostnames; + self + } + + /// Set a verification callback to be used for connections created with this `Builder`. + /// + /// The callback is provided with an io::Result indicating if the (pre)validation was + /// successful. The Ok() variant indicates a successful validation while the Err() variant + /// contains the errorcode returned from the internal verification process. + /// The validated certificate, is accessible through the second argument of the closure. + pub fn verify_callback<F>(&mut self, callback: F) -> &mut Builder + where F: Fn(CertValidationResult) -> io::Result<()> + 'static + Sync + Send + { + self.verify_callback = Some(Arc::new(callback)); + self + } + + /// Specifies a custom certificate store which is later used when validating + /// a server's certificate. + /// + /// This option is only used for client connections and is used to construct + /// the certificate chain which the server's certificate is validated + /// against. + /// + /// Note that adding certificates here means that they are + /// implicitly trusted. + pub fn cert_store(&mut self, cert_store: CertStore) -> &mut Builder { + self.cert_store = Some(cert_store); + self + } + + /// Initialize a new TLS session where the stream provided will be + /// connecting to a remote TLS server. + /// + /// If the stream provided is a blocking stream then the entire handshake + /// will be performed if possible, but if the stream is in nonblocking mode + /// then a `HandshakeError::Interrupted` variant may be returned. This + /// type can then be extracted to later call + /// `MidHandshakeTlsStream::handshake` when data becomes available. + pub fn connect<S>(&mut self, + cred: SchannelCred, + stream: S) + -> Result<TlsStream<S>, HandshakeError<S>> + where S: Read + Write + { + self.initialize(cred, false, stream) + } + + /// Initialize a new TLS session where the stream provided will be + /// accepting a connection. + /// + /// This method will tweak the protocol for "who talks first" and also + /// currently disables validation of the client that's connecting to us. + /// + /// If the stream provided is a blocking stream then the entire handshake + /// will be performed if possible, but if the stream is in nonblocking mode + /// then a `HandshakeError::Interrupted` variant may be returned. This + /// type can then be extracted to later call + /// `MidHandshakeTlsStream::handshake` when data becomes available. + pub fn accept<S>(&mut self, + cred: SchannelCred, + stream: S) + -> Result<TlsStream<S>, HandshakeError<S>> + where S: Read + Write + { + self.initialize(cred, true, stream) + } + + fn initialize<S>(&mut self, + mut cred: SchannelCred, + server: bool, + stream: S) + -> Result<TlsStream<S>, HandshakeError<S>> + where S: Read + Write + { + let domain = match self.domain { + Some(ref domain) if self.use_sni => Some(&domain[..]), + _ => None, + }; + let (ctxt, buf) = match SecurityContext::initialize(&mut cred, + server, + domain) { + Ok(pair) => pair, + Err(e) => return Err(HandshakeError::Failure(e)), + }; + + let stream = TlsStream { + cred: cred, + context: ctxt, + cert_store: self.cert_store.clone(), + domain: self.domain.clone(), + use_sni: self.use_sni, + accept_invalid_hostnames: self.accept_invalid_hostnames, + verify_callback: self.verify_callback.clone(), + stream: stream, + server: server, + accept_first: true, + state: State::Initializing { + needs_flush: false, + more_calls: true, + shutting_down: false, + validated: false, + }, + needs_read: 1, + dec_in: Cursor::new(Vec::new()), + enc_in: Cursor::new(Vec::new()), + out_buf: Cursor::new(buf.map(|b| b.to_owned()).unwrap_or(Vec::new())), + last_write_len: 0, + }; + + MidHandshakeTlsStream { + inner: stream, + }.handshake() + } +} + +enum State { + Initializing { + needs_flush: bool, + more_calls: bool, + shutting_down: bool, + validated: bool, + }, + Streaming { sizes: sspi::SecPkgContext_StreamSizes, }, + Shutdown, +} + +/// An Schannel TLS stream. +pub struct TlsStream<S> { + cred: SchannelCred, + context: SecurityContext, + cert_store: Option<CertStore>, + domain: Option<Vec<u16>>, + use_sni: bool, + accept_invalid_hostnames: bool, + verify_callback: Option<Arc<Fn(CertValidationResult) -> io::Result<()> + Sync + Send>>, + stream: S, + state: State, + server: bool, + accept_first: bool, + needs_read: usize, + // valid from position() to len() + dec_in: Cursor<Vec<u8>>, + // valid from 0 to position() + enc_in: Cursor<Vec<u8>>, + // valid from position() to len() + out_buf: Cursor<Vec<u8>>, + /// the (unencrypted) length of the last write call used to track writes + last_write_len: usize, +} + +/// ensures that a TlsStream is always Sync/Send +fn _is_sync() { + fn sync<T: Sync + Send>() {} + sync::<TlsStream<()>>(); +} + +/// A failure which can happen during the `Builder::initialize` phase, either an +/// I/O error or an intermediate stream which has not completed its handshake. +#[derive(Debug)] +pub enum HandshakeError<S> { + /// A fatal I/O error occurred + Failure(io::Error), + /// The stream connection is in progress, but the handshake is not completed + /// yet. + Interrupted(MidHandshakeTlsStream<S>), +} + +/// A struct used to wrap various cert chain validation results for callback processing. +pub struct CertValidationResult { + chain: CertChainContext, + res: i32, + chain_index: i32, + element_index: i32, +} + +impl CertValidationResult { + /// Returns the certificate that failed validation if applicable + pub fn failed_certificate(&self) -> Option<CertContext> { + if let Some(cert_chain) = self.chain.get_chain(self.chain_index as usize) { + return cert_chain.get(self.element_index as usize); + } + None + } + + /// Returns the final certificate chain in the certificate context if applicable + pub fn chain(&self) -> Option<CertChain> { + self.chain.final_chain() + } + + /// Returns the result of the built-in certificate verification process. + pub fn result(&self) -> io::Result<()> { + if self.res as u32 != winerror::ERROR_SUCCESS { + Err(io::Error::from_raw_os_error(self.res)) + } else { + Ok(()) + } + } +} + +impl<S: fmt::Debug + Any> Error for HandshakeError<S> { + fn description(&self) -> &str { + match *self { + HandshakeError::Failure(_) => "failed to perform handshake", + HandshakeError::Interrupted(_) => "interrupted performing handshake", + } + } + + fn cause(&self) -> Option<&Error> { + match *self { + HandshakeError::Failure(ref e) => Some(e), + HandshakeError::Interrupted(_) => None, + } + } +} + +impl<S: fmt::Debug + Any> fmt::Display for HandshakeError<S> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(f.write_str(self.description())); + if let Some(e) = self.cause() { + try!(write!(f, ": {}", e)); + } + Ok(()) + } +} + +/// A stream which has not yet completed its handshake. +#[derive(Debug)] +pub struct MidHandshakeTlsStream<S> { + inner: TlsStream<S>, +} + +impl<S> fmt::Debug for TlsStream<S> + where S: fmt::Debug +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("TlsStream") + .field("stream", &self.stream) + .finish() + } +} + +impl<S> TlsStream<S> + where S: Read + Write +{ + /// Returns a reference to the wrapped stream. + pub fn get_ref(&self) -> &S { + &self.stream + } + + /// Returns a mutable reference to the wrapped stream. + pub fn get_mut(&mut self) -> &mut S { + &mut self.stream + } + + /// Indicates if this stream is the server- or client-side of a TLS session. + pub fn is_server(&self) -> bool { + self.server + } + + /// Returns the certificate used to identify this side of the TLS session. + /// + /// Its associated cert store contains any intermediate certificates sent + /// along with the leaf. + pub fn certificate(&self) -> io::Result<CertContext> { + self.context.local_cert() + } + + /// Returns the peer's certificate, if available. + /// + /// Its associated cert store contains any intermediate certificates sent + /// by the server. + pub fn peer_certificate(&self) -> io::Result<CertContext> { + self.context.remote_cert() + } + + /// Returns a reference to the buffer of pending data. + /// + /// Like `BufRead::fill_buf` except that it will return an empty slice + /// rather than reading from the wrapped stream if there is no buffered + /// data. + pub fn get_buf(&self) -> &[u8] { + &self.dec_in.get_ref()[self.dec_in.position() as usize..] + } + + /// Shuts the TLS session down. + pub fn shutdown(&mut self) -> io::Result<()> { + match self.state { + State::Shutdown => return Ok(()), + State::Initializing { shutting_down: true, .. } => {} + _ => { + unsafe { + let mut token = um::schannel::SCHANNEL_SHUTDOWN; + let ptr = &mut token as *mut _ as *mut u8; + let size = mem::size_of_val(&token); + let token = slice::from_raw_parts_mut(ptr, size); + let mut buf = [secbuf(sspi::SECBUFFER_TOKEN, Some(token))]; + let mut desc = secbuf_desc(&mut buf); + + match sspi::ApplyControlToken(self.context.get_mut(), &mut desc) { + winerror::SEC_E_OK => {} + err => return Err(io::Error::from_raw_os_error(err as i32)), + } + } + + self.state = State::Initializing { + needs_flush: false, + more_calls: true, + shutting_down: true, + validated: false, + }; + self.needs_read = 0; + } + } + + self.initialize().map(|_| ()) + } + + fn step_initialize(&mut self) -> io::Result<()> { + unsafe { + let pos = self.enc_in.position() as usize; + let mut inbufs = [secbuf(sspi::SECBUFFER_TOKEN, + Some(&mut self.enc_in.get_mut()[..pos])), + secbuf(sspi::SECBUFFER_EMPTY, None)]; + let mut inbuf_desc = secbuf_desc(&mut inbufs); + + let mut outbufs = [secbuf(sspi::SECBUFFER_TOKEN, None), + secbuf(sspi::SECBUFFER_ALERT, None), + secbuf(sspi::SECBUFFER_EMPTY, None)]; + let mut outbuf_desc = secbuf_desc(&mut outbufs); + + let mut attributes = 0; + + let status = if self.server { + let ptr = if self.accept_first { + ptr::null_mut() + } else { + self.context.get_mut() + }; + sspi::AcceptSecurityContext(self.cred.get_mut(), + ptr, + &mut inbuf_desc, + ACCEPT_REQUESTS, + 0, + self.context.get_mut(), + &mut outbuf_desc, + &mut attributes, + ptr::null_mut()) + } else { + let domain = match self.domain { + Some(ref domain) if self.use_sni => domain.as_ptr() as *mut u16, + _ => ptr::null_mut(), + }; + + sspi::InitializeSecurityContextW(self.cred.get_mut(), + self.context.get_mut(), + domain, + INIT_REQUESTS, + 0, + 0, + &mut inbuf_desc, + 0, + ptr::null_mut(), + &mut outbuf_desc, + &mut attributes, + ptr::null_mut()) + }; + + for buf in &outbufs[1..] { + if !buf.pvBuffer.is_null() { + sspi::FreeContextBuffer(buf.pvBuffer); + } + } + + match status { + winerror::SEC_I_CONTINUE_NEEDED => { + // Windows apparently doesn't like AcceptSecurityContext + // being called as if it were the second time unless the + // first call to AcceptSecurityContext succeeded with + // CONTINUE_NEEDED. + // + // In other words, if we were to set `accept_first` to + // `false` after the literal first call to + // `AcceptSecurityContext` while the call returned + // INCOMPLETE_MESSAGE, the next call would return an error. + // + // For that reason we only set `accept_first` to false here + // once we've actually successfully received the full + // "token" from the client. + self.accept_first = false; + let nread = if inbufs[1].BufferType == sspi::SECBUFFER_EXTRA { + self.enc_in.position() as usize - inbufs[1].cbBuffer as usize + } else { + self.enc_in.position() as usize + }; + let to_write = ContextBuffer(outbufs[0]); + + self.consume_enc_in(nread); + self.needs_read = (self.enc_in.position() == 0) as usize; + self.out_buf.get_mut().extend_from_slice(&to_write); + } + winerror::SEC_E_INCOMPLETE_MESSAGE => { + self.needs_read = if inbufs[1].BufferType == sspi::SECBUFFER_MISSING { + inbufs[1].cbBuffer as usize + } else { + 1 + }; + } + winerror::SEC_E_OK => { + let nread = if inbufs[1].BufferType == sspi::SECBUFFER_EXTRA { + self.enc_in.position() as usize - inbufs[1].cbBuffer as usize + } else { + self.enc_in.position() as usize + }; + let to_write = if outbufs[0].pvBuffer.is_null() { + None + } else { + Some(ContextBuffer(outbufs[0])) + }; + + self.consume_enc_in(nread); + self.needs_read = (self.enc_in.position() == 0) as usize; + if let Some(to_write) = to_write { + self.out_buf.get_mut().extend_from_slice(&to_write); + } + if self.enc_in.position() != 0 { + try!(self.decrypt()); + } + if let State::Initializing { ref mut more_calls, .. } = self.state { + *more_calls = false; + } + } + _ => { + return Err(io::Error::from_raw_os_error(status as i32)) + } + } + Ok(()) + } + } + + fn initialize(&mut self) -> io::Result<Option<sspi::SecPkgContext_StreamSizes>> { + loop { + match self.state { + State::Initializing { mut needs_flush, more_calls, shutting_down, validated } => { + if try!(self.write_out()) > 0 { + needs_flush = true; + if let State::Initializing { ref mut needs_flush, .. } = self.state { + *needs_flush = true; + } + } + + if needs_flush { + try!(self.stream.flush()); + if let State::Initializing { ref mut needs_flush, .. } = self.state { + *needs_flush = false; + } + } + + if !shutting_down && !validated { + // on the last call, we require a valid certificate + if try!(self.validate(!more_calls)) { + if let State::Initializing { ref mut validated, .. } = self.state { + *validated = true; + } + } + } + + if !more_calls { + self.state = if shutting_down { + State::Shutdown + } else { + State::Streaming { sizes: try!(self.context.stream_sizes()) } + }; + continue; + } + + if self.needs_read > 0 { + if try!(self.read_in()) == 0 { + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, + "unexpected EOF during handshake")); + } + } + + try!(self.step_initialize()); + } + State::Streaming { sizes } => return Ok(Some(sizes)), + State::Shutdown => return Ok(None), + } + } + } + + /// Returns true when the certificate was succesfully verified + /// Returns false, when a verification isn't necessary (yet) + /// Returns an error when the verification failed + fn validate(&mut self, require_cert: bool) -> io::Result<bool> { + // If we're accepting connections then we don't perform any validation + // for the remote certificate, that's what they're doing! + if self.server { + return Ok(false); + } + + let cert_context = match self.context.remote_cert() { + Err(_) if !require_cert => return Ok(false), + ret => try!(ret) + }; + + let cert_chain = unsafe { + let cert_store = match (cert_context.cert_store(), &self.cert_store) { + (Some(ref mut chain_certs), &Some(ref extra_certs)) => { + for extra_cert in extra_certs.certs() { + try!(chain_certs.add_cert(&extra_cert, CertAdd::ReplaceExisting)); + } + chain_certs.as_inner() + }, + (Some(chain_certs), &None) => chain_certs.as_inner(), + (None, &Some(ref extra_certs)) => extra_certs.as_inner(), + (None, &None) => ptr::null_mut() + }; + + let flags = wincrypt::CERT_CHAIN_CACHE_END_CERT | + wincrypt::CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY | + wincrypt::CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; + + let mut para: wincrypt::CERT_CHAIN_PARA = mem::zeroed(); + para.cbSize = mem::size_of_val(¶) as winapi::DWORD; + para.RequestedUsage.dwType = wincrypt::USAGE_MATCH_TYPE_OR; + + let mut identifiers = [szOID_PKIX_KP_SERVER_AUTH.as_ptr() as ntdef::LPSTR, + szOID_SERVER_GATED_CRYPTO.as_ptr() as ntdef::LPSTR, + szOID_SGC_NETSCAPE.as_ptr() as ntdef::LPSTR]; + para.RequestedUsage.Usage.cUsageIdentifier = identifiers.len() as winapi::DWORD; + para.RequestedUsage.Usage.rgpszUsageIdentifier = identifiers.as_mut_ptr(); + + let mut cert_chain = mem::zeroed(); + + let res = wincrypt::CertGetCertificateChain(ptr::null_mut(), + cert_context.as_inner(), + ptr::null_mut(), + cert_store, + &mut para, + flags, + ptr::null_mut(), + &mut cert_chain); + + if res == winapi::TRUE { + CertChainContext(cert_chain as *mut _) + } else { + return Err(io::Error::last_os_error()) + } + }; + + unsafe { + // check if we trust the root-CA explicitly + let mut para_flags = wincrypt::CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS; + if let Some(ref mut store) = self.cert_store { + if let Some(chain) = cert_chain.final_chain() { + // check if any cert of the chain is in the passed store (and therefore trusted) + if chain.certificates().any(|cert| store.certs().any(|root_cert| root_cert == cert)) { + para_flags |= wincrypt::CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG; + } + } + } + + let mut extra_para: wincrypt::SSL_EXTRA_CERT_CHAIN_POLICY_PARA = mem::zeroed(); + *extra_para.u.cbSize_mut() = mem::size_of_val(&extra_para) as winapi::DWORD; + extra_para.dwAuthType = wincrypt::AUTHTYPE_SERVER; + match self.domain { + Some(ref mut domain) if !self.accept_invalid_hostnames => { + extra_para.pwszServerName = domain.as_mut_ptr(); + } + _ => {} + } + + let mut para: wincrypt::CERT_CHAIN_POLICY_PARA = mem::zeroed(); + para.cbSize = mem::size_of_val(¶) as winapi::DWORD; + para.dwFlags = para_flags; + para.pvExtraPolicyPara = &mut extra_para as *mut _ as *mut _; + + let mut status: wincrypt::CERT_CHAIN_POLICY_STATUS = mem::zeroed(); + status.cbSize = mem::size_of_val(&status) as winapi::DWORD; + + let verify_chain_policy_structure = wincrypt::CERT_CHAIN_POLICY_SSL as ntdef::LPCSTR; + let res = wincrypt::CertVerifyCertificateChainPolicy(verify_chain_policy_structure, + cert_chain.0, + &mut para, + &mut status); + if res == winapi::FALSE { + return Err(io::Error::last_os_error()) + } + + let mut verify_result = if status.dwError != winerror::ERROR_SUCCESS { + Err(io::Error::from_raw_os_error(status.dwError as i32)) + } else { + Ok(()) + }; + + // check if there's a user-specified verify callback + if let Some(ref callback) = self.verify_callback { + verify_result = callback(CertValidationResult{ + chain: cert_chain, + res: status.dwError as i32, + chain_index: status.lChainIndex, + element_index: status.lElementIndex}); + } + try!(verify_result); + } + Ok(true) + } + + fn write_out(&mut self) -> io::Result<usize> { + let mut out = 0; + while self.out_buf.position() as usize != self.out_buf.get_ref().len() { + let position = self.out_buf.position() as usize; + let nwritten = try!(self.stream.write(&self.out_buf.get_ref()[position..])); + out += nwritten; + self.out_buf.set_position((position + nwritten) as u64); + } + + Ok(out) + } + + fn read_in(&mut self) -> io::Result<usize> { + let mut sum_nread = 0; + + while self.needs_read > 0 { + let existing_len = self.enc_in.position() as usize; + let min_len = cmp::max(cmp::max(1024, 2 * existing_len), self.needs_read); + if self.enc_in.get_ref().len() < min_len { + self.enc_in.get_mut().resize(min_len, 0); + } + let nread = { + let buf = &mut self.enc_in.get_mut()[existing_len..]; + try!(self.stream.read(buf)) + }; + self.enc_in.set_position((existing_len + nread) as u64); + self.needs_read = self.needs_read.saturating_sub(nread); + if nread == 0 { + break; + } + sum_nread += nread; + } + + Ok(sum_nread) + } + + fn consume_enc_in(&mut self, nread: usize) { + let size = self.enc_in.position() as usize; + assert!(size >= nread); + let count = size - nread; + + if count > 0 { + self.enc_in.get_mut().drain(..nread); + } + + self.enc_in.set_position(count as u64); + } + + fn decrypt(&mut self) -> io::Result<bool> { + unsafe { + let position = self.enc_in.position() as usize; + let mut bufs = [secbuf(sspi::SECBUFFER_DATA, + Some(&mut self.enc_in.get_mut()[..position])), + secbuf(sspi::SECBUFFER_EMPTY, None), + secbuf(sspi::SECBUFFER_EMPTY, None), + secbuf(sspi::SECBUFFER_EMPTY, None)]; + let mut bufdesc = secbuf_desc(&mut bufs); + + match sspi::DecryptMessage(self.context.get_mut(), + &mut bufdesc, + 0, + ptr::null_mut()) { + winerror::SEC_E_OK => { + let start = bufs[1].pvBuffer as usize - self.enc_in.get_ref().as_ptr() as usize; + let end = start + bufs[1].cbBuffer as usize; + self.dec_in.get_mut().clear(); + self.dec_in + .get_mut() + .extend_from_slice(&self.enc_in.get_ref()[start..end]); + self.dec_in.set_position(0); + + let nread = if bufs[3].BufferType == sspi::SECBUFFER_EXTRA { + self.enc_in.position() as usize - bufs[3].cbBuffer as usize + } else { + self.enc_in.position() as usize + }; + self.consume_enc_in(nread); + self.needs_read = (self.enc_in.position() == 0) as usize; + Ok(false) + } + winerror::SEC_E_INCOMPLETE_MESSAGE => { + self.needs_read = if bufs[1].BufferType == sspi::SECBUFFER_MISSING { + bufs[1].cbBuffer as usize + } else { + 1 + }; + Ok(false) + } + winerror::SEC_I_CONTEXT_EXPIRED => Ok(true), + winerror::SEC_I_RENEGOTIATE => { + self.state = State::Initializing { + needs_flush: false, + more_calls: true, + shutting_down: false, + validated: false, + }; + + let nread = if bufs[3].BufferType == sspi::SECBUFFER_EXTRA { + self.enc_in.position() as usize - bufs[3].cbBuffer as usize + } else { + self.enc_in.position() as usize + }; + self.consume_enc_in(nread); + self.needs_read = 0; + Ok(false) + } + e => Err(io::Error::from_raw_os_error(e as i32)), + } + } + } + + fn encrypt(&mut self, buf: &[u8], sizes: &sspi::SecPkgContext_StreamSizes) -> io::Result<()> { + assert!(buf.len() <= sizes.cbMaximumMessage as usize); + + unsafe { + let len = sizes.cbHeader as usize + buf.len() + sizes.cbTrailer as usize; + + if self.out_buf.get_ref().len() < len { + self.out_buf.get_mut().resize(len, 0); + } + + let message_start = sizes.cbHeader as usize; + self.out_buf + .get_mut()[message_start..message_start + buf.len()] + .clone_from_slice(buf); + + let mut bufs = { + let out_buf = self.out_buf.get_mut(); + let size = sizes.cbHeader as usize; + + let header = secbuf(sspi::SECBUFFER_STREAM_HEADER, + Some(&mut out_buf[..size])); + let data = secbuf(sspi::SECBUFFER_DATA, + Some(&mut out_buf[size..size + buf.len()])); + let trailer = secbuf(sspi::SECBUFFER_STREAM_TRAILER, + Some(&mut out_buf[size + buf.len()..])); + let empty = secbuf(sspi::SECBUFFER_EMPTY, None); + [header, data, trailer, empty] + }; + let mut bufdesc = secbuf_desc(&mut bufs); + + match sspi::EncryptMessage(self.context.get_mut(), 0, &mut bufdesc, 0) { + winerror::SEC_E_OK => { + let len = bufs[0].cbBuffer + bufs[1].cbBuffer + bufs[2].cbBuffer; + self.out_buf.get_mut().truncate(len as usize); + self.out_buf.set_position(0); + Ok(()) + } + err => Err(io::Error::from_raw_os_error(err as i32)), + } + } + } +} + +impl<S> MidHandshakeTlsStream<S> + where S: Read + Write, +{ + /// Returns a shared reference to the inner stream. + pub fn get_ref(&self) -> &S { + self.inner.get_ref() + } + + /// Returns a mutable reference to the inner stream. + pub fn get_mut(&mut self) -> &mut S { + self.inner.get_mut() + } + + /// Restarts the handshake process. + pub fn handshake(mut self) -> Result<TlsStream<S>, HandshakeError<S>> { + match self.inner.initialize() { + Ok(_) => Ok(self.inner), + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + Err(HandshakeError::Interrupted(self)) + } + Err(e) => Err(HandshakeError::Failure(e)), + } + } +} + +impl<S> Write for TlsStream<S> + where S: Read + Write +{ + /// In the case of a WouldBlock error, we expect another call + /// starting with the same input data + /// This is similar to the use of ACCEPT_MOVING_WRITE_BUFFER in openssl + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let sizes = match try!(self.initialize()) { + Some(sizes) => sizes, + None => return Err(io::Error::from_raw_os_error(winerror::SEC_E_CONTEXT_EXPIRED as i32)), + }; + + // if we have pending output data, it must have been because a previous + // attempt to send this part of the data ran into an error. + if self.out_buf.position() == self.out_buf.get_ref().len() as u64 { + let len = cmp::min(buf.len(), sizes.cbMaximumMessage as usize); + try!(self.encrypt(&buf[..len], &sizes)); + self.last_write_len = len; + } + try!(self.write_out()); + + Ok(self.last_write_len) + } + + fn flush(&mut self) -> io::Result<()> { + // Make sure the write buffer is emptied + try!(self.write_out()); + self.stream.flush() + } +} + +impl<S> Read for TlsStream<S> + where S: Read + Write +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let nread = { + let read_buf = try!(self.fill_buf()); + let nread = cmp::min(buf.len(), read_buf.len()); + buf[..nread].copy_from_slice(&read_buf[..nread]); + nread + }; + self.consume(nread); + Ok(nread) + } +} + +impl<S> BufRead for TlsStream<S> + where S: Read + Write +{ + fn fill_buf(&mut self) -> io::Result<&[u8]> { + while self.get_buf().is_empty() { + if let None = try!(self.initialize()) { + break; + } + + if self.needs_read > 0 { + if try!(self.read_in()) == 0 { + break; + } + self.needs_read = 0; + } + + let eof = try!(self.decrypt()); + if eof { + break; + } + } + + Ok(self.get_buf()) + } + + fn consume(&mut self, amt: usize) { + let pos = self.dec_in.position() + amt as u64; + assert!(pos <= self.dec_in.get_ref().len() as u64); + self.dec_in.set_position(pos); + } +} diff --git a/schannel/test/cert.der b/schannel/test/cert.der new file mode 100644 index 0000000000000000000000000000000000000000..e1f964d6b79bd199b8487206aab0ff9b58af4fd3 GIT binary patch literal 799 zcmXqLVwN^&Vq#|EWN0t^zW3b>{iO!HY@Awc9&O)w85y}*84O$vxeYkkm_u3Egqa*e z4TTK^K^zVquHgLKRNdf`#FA7)MFV+|AQz8>XI@EaQC@0^LU?9MdS*$nLO@BSf=@|` zft)z6p_ze&p^2fnfq{W>lsK;uh-(Dp8bndW8kqB#dAQQ@^OF*b^pf*)4VoC0kbT9- z%D~*j$j<;2=VEGNWMo+JMYYFev-skG)_=+q+b>j@NqdU_*LA=ARQg_y*`H}US?oWV z-`oG*SZG)3(N9mddwH%rrIeDd@a3w>M86eJ?e|~hkSq#lSU7Fcg;^VCb(tmke|0+X z_0`NXtY=GhDm-}^AEm1Lb<Y|;)8L>(iU+Qo2>+#bt$zQhOBJhr`8~AqNUewzYn&aj zx;G(CHnisTf{E*{OuD8%`Q~cY4Lp5mOBYT~zcrbMktejd<zdIp?dN_^TlMvTXU>(> zb0-+@y5-zs*kZkKb6#21LR;aE$#Q;2ulF!`2ZgQrx9gQioJ7^Ll!+TJiwGOvKF=R` z_SxMjcb435dH>8WKqN9|!M6)*t<7F&ahozRGcqtDhY&E{fg!}m;Ps7tM`tCsvpb8^ z`K5tpcWk?`!Gu>c;(PWyyKiefCn@v1y4IrF{^8Bq@V-33MT$XkQyAMHUrW_}=-2W> zKdtb?^fT_0^_aBo+VE`kQroZotK}fOXW^-3`yM^fHCehL?TGrPD?!W+O*_~vCtFVS z;Aqjj$LxPMV($43ca8Ve?fv_0#-iS&uFkNI#%mFxLS=g&8z*pP2I%-DJ-qDBm0_H6 zf0N_)UPG?VgOZxHA11#x+y1xILCN2vgRO#@_2TpSe<t@oQV($~N>y5IcB9$j*-?4n zJ4dqPWNsa@neKn}ecLL>mok$DQv)U}RW{yJnNd^H+iW`Z%F&<g0sRjZXO;+Dt^oib CT|oH& literal 0 HcmV?d00001 diff --git a/schannel/test/cert.pem b/schannel/test/cert.pem new file mode 100644 index 000000000..032fe60e9 --- /dev/null +++ b/schannel/test/cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- diff --git a/schannel/test/identity.p12 b/schannel/test/identity.p12 new file mode 100644 index 0000000000000000000000000000000000000000..d16abb8c70627bd959667495e578fb6f010a7f1d GIT binary patch literal 3386 zcmY+Fc{CIb*T-kZ%-F^<GWN)p5XK%F35CSim$7Bnqa<5M8G}j4*fSBbXJ3+iD;n8F zmP8|CNw%?OowwgP@B2Q_bMCq4-t)c7pWhD>$D#rP(jjrM6DXq;ULSwJ0;C7#;$Z7w z9PHO$c@c@DfAsGWG#5wj^;dEO0RexD!@nm$qyUuZe?P#0P$Vmufe?7XI$4!A4gxU% zusC`o{$ASWtHZ!%6&Yr};{6u`2KLv+>Oc-hrRqJ_6t51LvyFjb*MY2v@UpI}BEGHo zvK<0`n{R9EEh2758@vOSP&dDqOy0%>n)6OY2s1K@{ZZ4dUib$1=yGu{qy4)68IXNX zkk#_0j(a5M*dt*Sb*_j1P%B2^j47C!ky#GS(OVUX<!@Bb+r6V}7QCEOlVQeob~fWo z=ona;dSVh<_byjOV7x%`$(>x=1c`4$i|hrFN!o2AI7yk$-hcE5vQ_4v$r`H0%4V>8 z@eO82W_dR!EPHOKwd{tqnGp6|1N4%pQ^bZ&wmM^1xKK`mmp5~Z!-*jOxzzTtyjI@N znR!#3*mi1n<$H_glj<q`^JKMkdnVLk<XJ8pf&|6k%q$)sv(v-T$TA6q{q>nHMOm{8 zY+OW$1dI#%nC00mv=w|&H?Ds_&Q&>zV$~?as>se&LcGBkC+KuH))CEF+bqRg55Y-3 z?~vHFBT!PxQJ=a_tK7s`O43jI#e<T(QdezvNFi6N%alxC*n=poP<g01!=?QfwPDvc z+$59JIE9pH2(^a0M<rZ+(I*%lTvZs_EGRX<=nZ+txHAM@Vz~HAVwXjqJbPU<U%TTE zR%~#(<=~2O<t^>nGN$Sir<+d_5iA)Nn{pocY~r%FKRo?P!z?Yz^^ltS`1rG&W|$}6 zIK1R;ZV;$x`_4<MW_R(>!Z3O$S$y|fdG=LX_+wEsUm|gb|J|R6=$2&5w5;*9HoUf+ zLC&xB@i{S7wciFKq`HokLs&MYUDh;a#&Nq`>{RQv)JdX8iEVvb{5|aGL9i^^AOpXY z&L6LF6u+99$t7+kFys94TO$8LR-yenXgMarH6$3GlTQl|GYr#AJ*J8<*w1~fu~s1O zdhUXpvVUHaLYgm_R_B=VPu;^q1k37|S#Az*#kI@%`yAGFcpg*|9J$55Dn2i3qil7T z#{o*c=&(?Um6=WCnJ<;C^yU0Wn5+U;LCTeF5LRZG`&7h5u>K>DCz<s(m#vhA&p^Sa z(3#M7vtwWrc0$eXlIndjxh#V>^!_kAQ+Uk_>p^ZJ-AG#sMX^}swaF9O348d8KL2>E z)<=Onr|{6URV7{c-I=%8nti`|U(Z3YP74t0c_K)3>xS6vW%e^B29#WNrqLHAUIEy{ zzB?q&G}1_h*%0C4?15@moi|7#SL*3DFn*TcNo)PGTXh0X35{``dR4uHIDDveSU-f9 z{K;uqKl-Nv+V4mA(kBrDEVii_A1b!KJS}U4Iyn5L=6`(p(ctU_de;X1DiO>4u2__k zVlWt+97!S9u=F;5c}*O*ufnS<m~YBYtxXZ2?W0b)$^TNXH`&|?oC)_MWFp`Qw_fQZ zaO4#tp~V+fa>{X8;m3K*h#T0PXmn;cX%gWvELfIb5GGobB|9yhDDpE&NP`u@Gnp&0 zQZLqLDBx6TpRdU#?(psb%LU%s+uHH3^q4!9CoL-jgzIVo56|~LFj*Dya8o&rW&R9f z#MCF&8DNgw4~2m6o|%0c4_>q*LnYa8v7A*R-OG2mtCse5WW>N06;mbHTJR0ly~=vb zjkL_*lL_>a|0oF63*HEu&>67XeZie|`a^`89-;zuIMvx0wZDKHFrH{;{>A+ay$ZLY zQ&)*|(POvl>U&=z{Tg-ooGiy<a98$`)S3ceBWvk3A~Sa6wOEGA=5?DiLvsbq*5i6L zvx3`1K*OVNwDgo%m9gkZR-dQE$H6>ts!|CuF0TS^0VgtL{JJ0I`v@^G`!EHbzFi}2 zL*x~uu?J$3fnQa7=3r+w1G;jan4eqgmvr-O)nlM%Da;H8qk?wE67l%l<S$+e?Nti` zidPo&H(?PytYJYsLP)l4_t;b=*kaRe{@{yDElDHHBjyLkA;4Z#YDFK~FR*4^6<F}A z2$ed#dSj(p*-5)L5iuND`J0?mGQ4hPo7B4f%;du3tb8vnaevwI2Yk`CSpuI|SBXkA z>cqMyzw_r@o02)63je6Xu1-n29!*PLHn-90_SxMGSU5yp=aUNgA<uHX;H}BF%`P9h z8-wrak`|E&Zwjkb)5l*el#O3E^!h29?e(pfqf7<1!8X^WFcmkITJ&t(0&znpY`xj^ zkwMMr_&~c`y>Pf&JU@M3Mr*>n3*Qfs4@UZdr)3<49u!j(8;{>P^eE^Osav(h>l?db zz-D`eK9#oSSADv+c=1$Wl1_5pV%p++fJluaNC@?&3cRf~mUihw;wH~1NpD-OAhEp@ zp%J>UkR&rBuE;-O(>><WU6<{>(RI-$%WT}_LVD?y;mD%UYD&1i4MAzBQ}1OKO=ov1 zqOb6W(VoB8*XL$(xwOFE$}X1Q4kfSMF15mhjE{%TXEK8mEZLjGl#c@Kdami3&$?8R z3X0QOt>y=BbRV!lHr4bxPL(_bvynK6$A17e7YDHh;~?gLW%S=PgfjmhZkd3fTpV}< zi36|x7lrBmq3~Tpke%T}RQEp=2IIiJs)bH-t;&|}Fh+NaTeU~I+z6U$<K>_st%d4& z-GhEwwpii2MIE&MtZ#2+NiaN#V8qoDMFa~9WuL=dYyA0VF!^rHt`>`@lvQaI9rjF% zf>&A5%p>?lyx=A)lifEe-ZTF_&hx;HqdgC=j^D`xrXHl2F1=@bAN8)917)sJ6!*me z<7HAMfY#b&Kyj?9V{7jX0ex*Do!y1*jQ4BlZqzj@WpzG)?+b1vXK$aw@ws>CE|ZxA z5+_}aqAICBLaX0@Sx&A-B{8<Fy?y==yn;{Fg^P$gLyCGZdK{|WH4meL!m4-uT}6uT z*E~Y^V4)zq_})=pP3)t_F~tL`?);o<vPat=G2w-FZhQR$XWkqdo(e_+@2Q2#_<~k+ z>F6=5ieD+o4bn7mz)?DFYwS9ISfcSkc1D?^7F(MYzNFqebD~<*>|~&C#$*Y)t41%< zSUb^f@Dm)@x`dT(>NzTU>>Qbs5c=rJ4Yz`@*9~DI<0a2AHA?iN*a+E<qEGk4o-5od zDAy=$TG!=5H63NrxT7_0#qLe$lRk-(np4Afy5#{w<0qPhm<cwPUr$y;)cK=1a1`7` zDlA1KMxmjbYPu-Iq`it8yc-s6Xm!0Ez6ED8FVg`QV<y8BnbIBQQ~UfK5g2b#mKTe2 zMIF+0EzR+8P5c`<$48q3;qf0e5SJZJ_c*5k;kB`qM3iG8pd8<QcZ2rI19mxrXhX`< zBCH*B(s_CdwNVnRp#iC>!i8J>{0~PG?gk>1>Zj*jW^JtpfIAm$MRWkXoi1Cv@Ar>b zH0;ah2{C4g3|27>74O!U!X+684ZU@I&-k@Ud2^qCUNAL{TZwyyN$G#HNDrFsP#65c zrxf~mk;jg7wV|ONPtWwMdR6?%)Ot`$mI?|@QaMOVx=?!cXeO8~Fz9+qIZ5WmPKHb7 zgofgUUSjO+ua`8j{?2gr-`{@-43inOgBoKao68B6iAOcPQPh6Q%T2XayOCFbynb>X zH$308<S8(Z@sbrG2_W<3A$1QsoV=;dwxxI8XQb`R8xf<7c;z;TupGwu4(zIamHkDa z!!;uUr3rAS*(wNePFm6RuqPzeiOqs+A`v;4OA$sr1)K?fFg`cnX}quKEyi$Dbh6<4 zq-s^++*@*q7B|YlFb*JWlzDDeH@c)J!H+2G!hc^ycj;|-g~aH6f}Fi`ZwJ$oe%#X! zJWd=SED`)QLQW`PU|+!him_tNn=3kP=G=&W{i4PWO5#q@{>=bjoRmehcbbLNXtZBq z0J~mAB-w(EFUlR4pRu`v?GEVIWM&zLpe{CcX2(DI&Sy^R84J751Y9rEzC(o6CO0>y z=E{ugtGsQie~J<l6ZVeG?6fOu$_8KbHH`@VZH}+<;yX_t@ZE<?x?|7FTHQlYh^py- z6vbMoKrP$aQE>(y5De$j6$PK5iB=^dz9SE8W5!8={%vccv}UmILPt41Z;;(tc^)R{ zZ=k`tzDp0hSkCT9WhKp4h<F0t(iFb*YE@iyc*@31QoFpGK{xG@5rP#KEizeS&Dt~- zoy!b_aAv$`_w>)^M!%VaxWo6p-<cF0o9i6rEZG~?*>gp4Xnu=HqXHv&7k?hh-$IK1 zzdJH=%5w>F0z3c@{)P*{8Q=$y1-Sn0@Bil#LY@oEY0E8>a&AS}wv{Gv=((Kjlgzys zg_K7MBN?F(X;wNA9|QpA+;x-8N-+3rFwTsLlk6hIQoAssV1}Dt>u@5F2fhDT>Hh%N CKSRy{ literal 0 HcmV?d00001 diff --git a/schannel/test/key.key b/schannel/test/key.key new file mode 100644 index 0000000000000000000000000000000000000000..6b6209fd1fbe809a335cf29b263d9ffd5d1b9da0 GIT binary patch literal 1193 zcmV;a1XlYnf&`@k0RRGm0RaH0^d*c$vlpXKh5jRvhtPO78%Y=cEl1Pk8{TX-{Fb={ zKk_%;zwa{=x@E=k<hM#msmdZ`Zy@y5G?7lI<v+jG2pMuvfT5O>(3-KDiZ)_T^+L$? z>Y2<1&2+gS<mq2pB_;K|tPV9(Qo<p?)W}!*F4lj)%F=kM`cC0GNM(3g7J-{otBqh@ z9aVhmppmZBlGZ1a*{cPx431`{p_6CYlMDe2RfB}#h`G1U`<ANpz)5V>WzNU}-9~KQ z0JJ-yvu<{Jp*<6blO9gR*Ngy5QdX+|y6O~O7<%Spk+IVh6EoY-4^hqL-IUy<--Pex zPEZtCT%h*Qtvfd8Dho9N0|5X50)hbn0HWjQgNX#C=#|Xr&A$|rAR_`nfqF|^vE_8` z2c;+X<lj9Dxnu9<opuxP<y;-Oy-l(HDHLt9_jt=1!5qU8s8Fh7W;{t40fhj|^eKzc zjSY+E+`5B#&LdU_kSQ;z^nHWPN>ic=e9axd|18_NU|`$ffBzVJy-gC)6avm8%*V7+ z1_t59C&GpC32iN`4t(E-NYO%S826Zkzq)RE-9;wc-Dij33EfeuV78P~IUh%vwBN$d zUuB8qY|+1c=rJpFKxztASvyT0VYFz>Ale5sRNp4S{nINLoMDnh=E1$>Sj%&We`-04 zD6-p!AX~h6p-Yy6u@-u^M}Wq};R1ny0NAAnWQ2}*Vp0Xd$s`2|+6&-Z^Jw64)*}Oe z_ZN-bl4Y`U<$d+gHhH?YTP@XHpnS=_BWd)T@pQ{zf1mZnNv|7%7taIPbaQBV@>vVq zlnF=rT5HUlPd}Js`tzJjjqL`sMzU8@_HXu73mwh=6n7FH11b$&pV_g%67N_VEdqgo z0LP_7AoFjmabS**<C9cVx=*Il5f(zmOA61T%>yghHl8Mb3mflu0`YEQeF@TZ_gdtw zEc(=g$haaDlImCWw1;_$@)<sED`NvPZcs^H8OLr;)T)PLe-HPwrFI+(zW5&DP282Q z(8akV{kr}p@wpFI%HLmD#3O3JJyoxQDFT6je!$QWKb||m3e02@+Xy&0D+#h#m)rTi zm+j2n#NjjQ8>Tfl=wXrA&5!v9SK+2j=d}R*Us=Y3ml_81q}yMRZ0lo68qD3r%wQ}z zCh$?VD_8lNJ;)IZEa5cszT}I=-Vin!#_nK~-yQfqD9Qx}WJE1n9G8VxsXpFnHLng~ z0)c@5$3<8fBcg?ttnc3gA>8||Z7*<P54{?@a8V10Vej-|CB6Fem9LRBsM4zsZ!A}T zMT8cvT(+IdOs@x~6s|KHJXOB1BQ8TcpBZD$<LEa!x9W^ojMb7P6GjA6)a~taaj7uv zOpQbBxJ@#2=bj=p2dEy>>D~Kv+I$4zvy%An0)c@5lTMfFGT$Uqdt4*iAJD?I-!9|> zzMbamG^Li-7cR;pil@zMtqV5(6vNh9$_2EtOFf*w{_oidMMYJv9np`#NYn@sB~M&Z zz?Rudqk|Hf$ThqmY;O335u@G`JIt;LBKLY&wcpw~C?sGlQ<zG%=ZiV6YN7fcmqdsA H0__qn=66oN literal 0 HcmV?d00001 diff --git a/schannel/test/key.pem b/schannel/test/key.pem new file mode 100644 index 000000000..d381795d3 --- /dev/null +++ b/schannel/test/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk +3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN +DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM +x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 +H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm +wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ +JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ +n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL +Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL +Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r +YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE +I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo +YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 +yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH +RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F +hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx +qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf +0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d +0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T +mEq154s5rmqh+h+XRIf7Au0SLw== +-----END PRIVATE KEY----- diff --git a/schannel/test/self-signed.badssl.com.cer b/schannel/test/self-signed.badssl.com.cer new file mode 100644 index 0000000000000000000000000000000000000000..b9f424edf6052b2a3d3bf7a075674b6fb9abf73c GIT binary patch literal 893 zcmXqLVy-l3VoF@V%*4pV#L4h8q3iJ+^)Fuyc-c6$+C196^D;7WvoaVY8FCwNvN4CU zun9AT1{(?+2!c2qJY3F+IhkqsMR}QthGGUHAVGE>-r&SM1-GKayyVQ{<a|SZpkY99 zE*>_g#FXG*A45?CVUPeb5092!QesMRagJVcey)L>IIp3FfrX)|p{bFfsd1DzuaN<e zYXarc#SKl2O2}SkWMyD(V&rEqXkz4IYGPz$IK=YiN6$N!Lz`~|TrG$=Gg;zw%!&-p z4N6;oPMx<=Tc^w}=YV&DkI$=3TMqCyY}@d&=wuty<y8VeR_DBi?&nPSFc6UzRSD z*z?WN>8RUfv3B+OC9k>W3I?eu7U#71RE9penEisy)<ZOC?PiVJtN!QxPnhaeo^AP2 z<)Y!XyS@jG{0ZKf>$G-j&A)YDMK2k9JXb0_en_M$N8^>b*Zo&HTZ^{TMJ*D$lesb6 z<u;el>U)Rz-AiH|l^)LeDLwhwS|v73y^Xs(Wq8!*E&kp8-JytK%_NSSJ>f0EjjX4i z{mTxS;h^4nTwr%`!TU@JM|RiHnx855wmOGb*1Vo9<<oZYR4WrRBLm}NV7!1+gRC$M zlL3Q)GB7q}1zBVaq?%A-w22ETc2N@)FjN^CR{d7H=I&!XWApj<5{B7Z%l?&l+%-Gq zqQo<`z580)rE?6o{qEo4`Ll;D)@AXcLY;(Zv(?x%U9SXH%bC{i7pN-`RO`I;_NPp7 zSbLG)<FY+(jxP4>P`8lok7{EoHF08{DI6!*>6LKVwOVoVYn~L{rL{~2JDwbTn)PzR zsV$y|o*r_je{_B6l79={ZhE`?@anqj#j6gae{{d8eZ*o(Nbr`V6+%W*{j;8b{=f3Z zt7p@9yxJ`Fzki)kB;SG+ZmB-2HVG*@a7QGx-d9_*HlpWM4~LMn@B2`LHDM76&u4zC rF+23d>vpVh@u8<t7HrSg2u|4b>R(ES*%9+&2@9=*->|Sxk}(AUwIooL literal 0 HcmV?d00001 diff --git a/scopeguard/.cargo-checksum.json b/scopeguard/.cargo-checksum.json new file mode 100644 index 000000000..bf07e4cfd --- /dev/null +++ b/scopeguard/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"} \ No newline at end of file diff --git a/scopeguard/Cargo.toml b/scopeguard/Cargo.toml new file mode 100644 index 000000000..4a0d52b93 --- /dev/null +++ b/scopeguard/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "scopeguard" +version = "0.3.3" +authors = ["bluss"] +description = "A RAII scope guard that will run a given closure when it goes out of scope,\neven if the code between panics (assuming unwinding panic).\n\nDefines the macros `defer!` and `defer_on_unwind!`; the latter only runs\nif the scope is extited through unwinding on panic.\n" +documentation = "https://docs.rs/scopeguard/" +keywords = ["scope-guard", "defer", "panic"] +categories = ["rust-patterns"] +license = "MIT/Apache-2.0" +repository = "https://github.com/bluss/scopeguard" +[package.metadata.release] +no-dev-version = true + +[features] +default = ["use_std"] +use_std = [] diff --git a/scopeguard/LICENSE-APACHE b/scopeguard/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/scopeguard/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/scopeguard/LICENSE-MIT b/scopeguard/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/scopeguard/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/scopeguard/README.rst b/scopeguard/README.rst new file mode 100644 index 000000000..d4699eafb --- /dev/null +++ b/scopeguard/README.rst @@ -0,0 +1,81 @@ + +scopeguard +========== + +Rust crate for a convenient RAII scope guard that will run a given closure when +it goes out of scope, even if the code between panics (assuming unwinding panic). + +The `defer!` macro and `guard` are `no_std` compatible (require only core), +but the on unwinding strategy requires linking to `std`. + +Requires Rust 1.11. + + +Please read the `API documentation here`__ + +__ https://docs.rs/scopeguard/ + +|build_status|_ |crates|_ + +.. |build_status| image:: https://travis-ci.org/bluss/scopeguard.svg +.. _build_status: https://travis-ci.org/bluss/scopeguard + +.. |crates| image:: http://meritbadge.herokuapp.com/scopeguard +.. _crates: https://crates.io/crates/scopeguard + +How to use +---------- + +.. code:: rust + + #[macro_use(defer)] extern crate scopeguard; + + use scopeguard::guard; + + fn f() { + defer!(println!("Called at return or panic")); + panic!(); + } + + use std::fs::File; + use std::io::Write; + + fn g() { + let f = File::create("newfile.txt").unwrap(); + let mut file = guard(f, |f| { + // write file at return or panic + let _ = f.sync_all(); + }); + // Access the file through the scope guard itself + file.write(b"test me\n").unwrap(); + } + +Recent Changes +-------------- + +- 0.3.3 + + - Use ``#[inline]`` on a few more functions by @stjepang (#14) + - Add examples to crate documentation + +- 0.3.2 + + - Add crate categories + +- 0.3.1 + + - Add ``defer_on_unwind!``, ``Strategy`` trait + - Rename ``Guard`` → ``ScopeGuard`` + - Add ``ScopeGuard::with_strategy``. + - ``ScopeGuard`` now implements ``Debug``. + - Require Rust 1.11 + +- 0.2.0 + + - Require Rust 1.6 + - Use `no_std` unconditionally + - No other changes + +- 0.1.2 + + - Add macro ``defer!()`` diff --git a/scopeguard/examples/readme.rs b/scopeguard/examples/readme.rs new file mode 100644 index 000000000..904bc544e --- /dev/null +++ b/scopeguard/examples/readme.rs @@ -0,0 +1,27 @@ + +#[macro_use(defer)] extern crate scopeguard; + +use scopeguard::guard; + +fn f() { + defer!(println!("Called at return or panic")); + panic!(); +} + +use std::fs::File; +use std::io::Write; + +fn g() { + let f = File::create("newfile.txt").unwrap(); + let mut file = guard(f, |f| { + // write file at return or panic + let _ = f.sync_all(); + }); + // Access the file through the scope guard itself + file.write(b"test me\n").unwrap(); +} + +fn main() { + f(); + g(); +} diff --git a/scopeguard/src/lib.rs b/scopeguard/src/lib.rs new file mode 100644 index 000000000..ff3929ada --- /dev/null +++ b/scopeguard/src/lib.rs @@ -0,0 +1,409 @@ +#![cfg_attr(not(any(test, feature = "use_std")), no_std)] + +//! A scope guard will run a given closure when it goes out of scope, +//! even if the code between panics. +//! (as long as panic doesn't abort) +//! +//! # Examples +//! +//! ## `defer!` +//! +//! Use the `defer` macro to run an operation at scope exit, +//! either regular scope exit or during unwinding from a panic. +//! +//! ``` +//! #[macro_use(defer)] extern crate scopeguard; +//! +//! use std::cell::Cell; +//! +//! fn main() { +//! // use a cell to observe drops during and after the scope guard is active +//! let drop_counter = Cell::new(0); +//! { +//! // Create a scope guard using `defer!` for the current scope +//! defer! {{ +//! drop_counter.set(1 + drop_counter.get()); +//! }}; +//! +//! // Do regular operations here in the meantime. +//! +//! // Just before scope exit: it hasn't run yet. +//! assert_eq!(drop_counter.get(), 0); +//! +//! // The following scope end is where the defer closure is called +//! } +//! assert_eq!(drop_counter.get(), 1); +//! } +//! ``` +//! +//! ## Scope Guard with Value +//! +//! If the scope guard closure needs to access an outer value that is also +//! mutated outside of the scope guard, then you may want to use the scope guard +//! with a value. The guard works like a smart pointer, so the inner value can +//! be accessed by reference or by mutable reference. +//! +//! ### 1. The guard owns a file +//! +//! In this example, the scope guard owns a file and ensures pending writes are +//! synced at scope exit. +//! +//! ``` +//! extern crate scopeguard; +//! +//! use std::fs::File; +//! use std::io::{self, Write}; +//! +//! fn try_main() -> io::Result<()> { +//! let f = File::create("newfile.txt")?; +//! let mut file = scopeguard::guard(f, |f| { +//! // ensure we flush file at return or panic +//! let _ = f.sync_all(); +//! }); +//! // Access the file through the scope guard itself +//! file.write(b"test me\n").map(|_| ()) +//! } +//! +//! fn main() { +//! try_main().unwrap(); +//! } +//! +//! ``` +//! +//! ### 2. The guard restores an invariant on scope exit +//! +//! ``` +//! extern crate scopeguard; +//! +//! use std::mem::ManuallyDrop; +//! use std::ptr; +//! +//! // This function, just for this example, takes the first element +//! // and inserts it into the assumed sorted tail of the vector. +//! // +//! // For optimization purposes we temporarily violate an invariant of the +//! // Vec, that it owns all of its elements. +//! // +//! // The safe approach is to use swap, which means two writes to memory, +//! // the optimization is to use a “hole” which uses only one write of memory +//! // for each position it moves. +//! // +//! // We *must* use a scope guard to run this code safely. We +//! // are running arbitrary user code (comparison operators) that may panic. +//! // The scope guard ensures we restore the invariant after successful +//! // exit or during unwinding from panic. +//! fn insertion_sort_first<T>(v: &mut Vec<T>) +//! where T: PartialOrd +//! { +//! struct Hole<'a, T: 'a> { +//! v: &'a mut Vec<T>, +//! index: usize, +//! value: ManuallyDrop<T>, +//! } +//! +//! unsafe { +//! // Create a moved-from location in the vector, a “hole”. +//! let value = ptr::read(&v[0]); +//! let mut hole = Hole { v: v, index: 0, value: ManuallyDrop::new(value) }; +//! +//! // Use a scope guard with a value. +//! // At scope exit, plug the hole so that the vector is fully +//! // initialized again. +//! // The scope guard owns the hole, but we can access it through the guard. +//! let mut hole_guard = scopeguard::guard(hole, |hole| { +//! // plug the hole in the vector with the value that was // taken out +//! let index = hole.index; +//! ptr::copy_nonoverlapping(&*hole.value, &mut hole.v[index], 1); +//! }); +//! +//! // run algorithm that moves the hole in the vector here +//! // move the hole until it's in a sorted position +//! for i in 1..hole_guard.v.len() { +//! if *hole_guard.value >= hole_guard.v[i] { +//! // move the element back and the hole forward +//! let index = hole_guard.index; +//! ptr::copy_nonoverlapping(&hole_guard.v[index + 1], &mut hole_guard.v[index], 1); +//! hole_guard.index += 1; +//! } else { +//! break; +//! } +//! } +//! +//! // When the scope exits here, the Vec becomes whole again! +//! } +//! } +//! +//! fn main() { +//! let string = String::from; +//! let mut data = vec![string("c"), string("a"), string("b"), string("d")]; +//! insertion_sort_first(&mut data); +//! assert_eq!(data, vec!["a", "b", "c", "d"]); +//! } +//! +//! ``` +//! +//! +//! # Crate features: +//! +//! - `use_std` +//! + Enabled by default. Enables the `OnUnwind` strategy. +//! + Disable to use `no_std`. + +#[cfg(not(any(test, feature = "use_std")))] +extern crate core as std; + +use std::fmt; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +pub trait Strategy { + /// Return `true` if the guard’s associated code should run + /// (in the context where this method is called). + fn should_run() -> bool; +} + +/// Always run on scope exit. +/// +/// “Always” run: on regular exit from a scope or on unwinding from a panic. +/// Can not run on abort, process exit, and other catastrophic events where +/// destructors don’t run. +#[derive(Debug)] +pub enum Always {} + +/// Run on scope exit through unwinding. +/// +/// Requires crate feature `use_std`. +#[cfg(feature = "use_std")] +#[derive(Debug)] +pub enum OnUnwind {} + +/// Run on regular scope exit, when not unwinding. +/// +/// Requires crate feature `use_std`. +#[cfg(feature = "use_std")] +#[derive(Debug)] +#[cfg(test)] +enum OnSuccess {} + +impl Strategy for Always { + #[inline(always)] + fn should_run() -> bool { true } +} + +#[cfg(feature = "use_std")] +impl Strategy for OnUnwind { + #[inline(always)] + fn should_run() -> bool { std::thread::panicking() } +} + +#[cfg(feature = "use_std")] +#[cfg(test)] +impl Strategy for OnSuccess { + #[inline(always)] + fn should_run() -> bool { !std::thread::panicking() } +} + +/// Macro to create a `ScopeGuard` (always run). +/// +/// The macro takes one expression `$e`, which is the body of a closure +/// that will run when the scope is exited. The expression can +/// be a whole block. +#[macro_export] +macro_rules! defer { + ($e:expr) => { + let _guard = $crate::guard((), |_| $e); + } +} + +/// Macro to create a `ScopeGuard` (run on successful scope exit). +/// +/// The macro takes one expression `$e`, which is the body of a closure +/// that will run when the scope is exited. The expression can +/// be a whole block. +/// +/// Requires crate feature `use_std`. +#[cfg(test)] +macro_rules! defer_on_success { + ($e:expr) => { + let _guard = $crate::guard_on_success((), |_| $e); + } +} + +/// Macro to create a `ScopeGuard` (run on unwinding from panic). +/// +/// The macro takes one expression `$e`, which is the body of a closure +/// that will run when the scope is exited. The expression can +/// be a whole block. +/// +/// Requires crate feature `use_std`. +#[macro_export] +macro_rules! defer_on_unwind { + ($e:expr) => { + let _guard = $crate::guard_on_unwind((), |_| $e); + } +} + +/// `ScopeGuard` is a scope guard that may own a protected value. +/// +/// If you place a guard in a local variable, the closure can +/// run regardless how you leave the scope — through regular return or panic +/// (except if panic or other code aborts; so as long as destructors run). +/// It is run only once. +/// +/// The `S` parameter for [`Strategy`](Strategy.t.html) determines if +/// the closure actually runs. +/// +/// The guard's closure will be called with a mut ref to the held value +/// in the destructor. It's called only once. +/// +/// The `ScopeGuard` implements `Deref` so that you can access the inner value. +pub struct ScopeGuard<T, F, S: Strategy = Always> + where F: FnMut(&mut T) +{ + __dropfn: F, + __value: T, + strategy: PhantomData<S>, +} +impl<T, F, S> ScopeGuard<T, F, S> + where F: FnMut(&mut T), + S: Strategy, +{ + /// Create a `ScopeGuard` that owns `v` (accessible through deref) and calls + /// `dropfn` when its destructor runs. + /// + /// The `Strategy` decides whether the scope guard's closure should run. + #[inline] + pub fn with_strategy(v: T, dropfn: F) -> ScopeGuard<T, F, S> { + ScopeGuard { + __value: v, + __dropfn: dropfn, + strategy: PhantomData, + } + } +} + + +/// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. +#[inline] +pub fn guard<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, Always> + where F: FnMut(&mut T) +{ + ScopeGuard::with_strategy(v, dropfn) +} + +/// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. +/// +/// Requires crate feature `use_std`. +#[cfg(feature = "use_std")] +#[cfg(test)] +#[inline] +fn guard_on_success<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnSuccess> + where F: FnMut(&mut T) +{ + ScopeGuard::with_strategy(v, dropfn) +} + +/// Create a new `ScopeGuard` owning `v` and with deferred closure `dropfn`. +/// +/// Requires crate feature `use_std`. +#[cfg(feature = "use_std")] +#[inline] +pub fn guard_on_unwind<T, F>(v: T, dropfn: F) -> ScopeGuard<T, F, OnUnwind> + where F: FnMut(&mut T) +{ + ScopeGuard::with_strategy(v, dropfn) +} + +impl<T, F, S: Strategy> Deref for ScopeGuard<T, F, S> + where F: FnMut(&mut T) +{ + type Target = T; + fn deref(&self) -> &T { + &self.__value + } + +} + +impl<T, F, S: Strategy> DerefMut for ScopeGuard<T, F, S> + where F: FnMut(&mut T) +{ + fn deref_mut(&mut self) -> &mut T { + &mut self.__value + } +} + +impl<T, F, S: Strategy> Drop for ScopeGuard<T, F, S> + where F: FnMut(&mut T) +{ + fn drop(&mut self) { + if S::should_run() { + (self.__dropfn)(&mut self.__value) + } + } +} + +impl<T, F, S> fmt::Debug for ScopeGuard<T, F, S> + where T: fmt::Debug, + F: FnMut(&mut T), + S: Strategy + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ScopeGuard") + .field("value", &self.__value) + .finish() + } +} + +#[cfg(test)] +mod tests { + use std::cell::Cell; + use std::panic::catch_unwind; + use std::panic::AssertUnwindSafe; + + #[test] + fn test_defer() { + let drops = Cell::new(0); + defer!(drops.set(1000)); + assert_eq!(drops.get(), 0); + } + + #[test] + fn test_defer_success_1() { + let drops = Cell::new(0); + { + defer_on_success!(drops.set(1)); + assert_eq!(drops.get(), 0); + } + assert_eq!(drops.get(), 1); + } + + #[test] + fn test_defer_success_2() { + let drops = Cell::new(0); + let _ = catch_unwind(AssertUnwindSafe(|| { + defer_on_success!(drops.set(1)); + panic!("failure") + })); + assert_eq!(drops.get(), 0); + } + + #[test] + fn test_defer_unwind_1() { + let drops = Cell::new(0); + let _ = catch_unwind(AssertUnwindSafe(|| { + defer_on_unwind!(drops.set(1)); + assert_eq!(drops.get(), 0); + panic!("failure") + })); + assert_eq!(drops.get(), 1); + } + + #[test] + fn test_defer_unwind_2() { + let drops = Cell::new(0); + { + defer_on_unwind!(drops.set(1)); + } + assert_eq!(drops.get(), 0); + } +} diff --git a/semver-parser/.cargo-checksum.json b/semver-parser/.cargo-checksum.json new file mode 100644 index 000000000..d2dc51388 --- /dev/null +++ b/semver-parser/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"} \ No newline at end of file diff --git a/semver-parser/Cargo.toml b/semver-parser/Cargo.toml new file mode 100644 index 000000000..c2be8783d --- /dev/null +++ b/semver-parser/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "semver-parser" +version = "0.7.0" +authors = ["Steve Klabnik <steve@steveklabnik.com>"] +license = "MIT/Apache-2.0" +repository = "https://github.com/steveklabnik/semver-parser" +homepage = "https://github.com/steveklabnik/semver-parser" +documentation = "https://docs.rs/semver-parser" +description = """ +Parsing of the semver spec. +""" diff --git a/semver-parser/LICENSE-APACHE b/semver-parser/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/semver-parser/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/semver-parser/LICENSE-MIT b/semver-parser/LICENSE-MIT new file mode 100644 index 000000000..fb7494ab8 --- /dev/null +++ b/semver-parser/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Steve Klabnik + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/semver-parser/src/common.rs b/semver-parser/src/common.rs new file mode 100644 index 000000000..267b4d92f --- /dev/null +++ b/semver-parser/src/common.rs @@ -0,0 +1,66 @@ +use version::Identifier; +use recognize::{Recognize, Alt, OneOrMore, Inclusive, OneByte}; +use std::str::from_utf8; + +// by the time we get here, we know that it's all valid characters, so this doesn't need to return +// a result or anything +fn parse_meta(s: &str) -> Vec<Identifier> { + // Originally, I wanted to implement this method via calling parse, but parse is tolerant of + // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not + // numeric. So the strategy is to check with a recognizer first, and then call parse once + // we've determined that it's a number without a leading zero. + s.split(".") + .map(|part| { + // another wrinkle: we made sure that any number starts with a + // non-zero. But there's a problem: an actual zero is a number, yet + // gets left out by this heuristic. So let's also check for the + // single, lone zero. + if is_alpha_numeric(part) { + Identifier::AlphaNumeric(part.to_string()) + } else { + // we can unwrap here because we know it is only digits due to the regex + Identifier::Numeric(part.parse().unwrap()) + } + }).collect() +} + +// parse optional metadata (preceded by the prefix character) +pub fn parse_optional_meta(s: &[u8], prefix_char: u8)-> Result<(Vec<Identifier>, usize), String> { + if let Some(len) = prefix_char.p(s) { + let start = len; + if let Some(len) = letters_numbers_dash_dot(&s[start..]) { + let end = start + len; + Ok((parse_meta(from_utf8(&s[start..end]).unwrap()), end)) + } else { + Err("Error parsing prerelease".to_string()) + } + } else { + Ok((Vec::new(), 0)) + } +} + +pub fn is_alpha_numeric(s: &str) -> bool { + if let Some((_val, len)) = numeric_identifier(s.as_bytes()) { + // Return true for number with leading zero + // Note: doing it this way also handily makes overflow fail over. + len != s.len() + } else { + true + } +} + +// Note: could plumb overflow error up to return value as Result +pub fn numeric_identifier(s: &[u8]) -> Option<(u64, usize)> { + if let Some(len) = Alt(b'0', OneOrMore(Inclusive(b'0'..b'9'))).p(s) { + from_utf8(&s[0..len]).unwrap().parse().ok().map(|val| (val, len)) + } else { + None + } +} + +pub fn letters_numbers_dash_dot(s: &[u8]) -> Option<usize> { + OneOrMore(OneByte(|c| c == b'-' || c == b'.' || + (b'0' <= c && c <= b'9') || + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z'))).p(s) +} diff --git a/semver-parser/src/lib.rs b/semver-parser/src/lib.rs new file mode 100644 index 000000000..3b0d8f051 --- /dev/null +++ b/semver-parser/src/lib.rs @@ -0,0 +1,8 @@ +pub mod version; +pub mod range; + +// for private stuff the two share +mod common; + +// for recognizer combinators +mod recognize; diff --git a/semver-parser/src/range.rs b/semver-parser/src/range.rs new file mode 100644 index 000000000..858be9fbc --- /dev/null +++ b/semver-parser/src/range.rs @@ -0,0 +1,696 @@ +use common::{self, numeric_identifier, letters_numbers_dash_dot}; +use version::Identifier; +use std::str::{FromStr, from_utf8}; +use recognize::*; + +#[derive(Debug)] +pub struct VersionReq { + pub predicates: Vec<Predicate>, +} + +#[derive(PartialEq,Debug)] +pub enum WildcardVersion { + Major, + Minor, + Patch, +} + +#[derive(PartialEq,Debug)] +pub enum Op { + Ex, // Exact + Gt, // Greater than + GtEq, // Greater than or equal to + Lt, // Less than + LtEq, // Less than or equal to + Tilde, // e.g. ~1.0.0 + Compatible, // compatible by definition of semver, indicated by ^ + Wildcard(WildcardVersion), // x.y.*, x.*, * +} + +impl FromStr for Op { + type Err = String; + + fn from_str(s: &str) -> Result<Op, String> { + match s { + "=" => Ok(Op::Ex), + ">" => Ok(Op::Gt), + ">=" => Ok(Op::GtEq), + "<" => Ok(Op::Lt), + "<=" => Ok(Op::LtEq), + "~" => Ok(Op::Tilde), + "^" => Ok(Op::Compatible), + _ => Err(String::from("Could not parse Op")), + } + } +} + +#[derive(PartialEq,Debug)] +pub struct Predicate { + pub op: Op, + pub major: u64, + pub minor: Option<u64>, + pub patch: Option<u64>, + pub pre: Vec<Identifier>, +} + +fn numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> { + if let Some((val, len)) = numeric_identifier(s) { + Some((Some(val), len)) + } else if let Some(len) = OneOf(b"*xX").p(s) { + Some((None, len)) + } else { + None + } +} + +fn dot_numeric_or_wild(s: &[u8]) -> Option<(Option<u64>, usize)> { + b'.'.p(s).and_then(|len| + numeric_or_wild(&s[len..]).map(|(val, len2)| (val, len + len2)) + ) +} + +fn operation(s: &[u8]) -> Option<(Op, usize)> { + if let Some(len) = "=".p(s) { + Some((Op::Ex, len)) + } else if let Some(len) = ">=".p(s) { + Some((Op::GtEq, len)) + } else if let Some(len) = ">".p(s) { + Some((Op::Gt, len)) + } else if let Some(len) = "<=".p(s) { + Some((Op::LtEq, len)) + } else if let Some(len) = "<".p(s) { + Some((Op::Lt, len)) + } else if let Some(len) = "~".p(s) { + Some((Op::Tilde, len)) + } else if let Some(len) = "^".p(s) { + Some((Op::Compatible, len)) + } else { + None + } +} + +fn whitespace(s: &[u8]) -> Option<usize> { + ZeroOrMore(OneOf(b"\t\r\n ")).p(s) +} + +pub fn parse_predicate(range: &str) -> Result<Predicate, String> { + let s = range.trim().as_bytes(); + let mut i = 0; + let mut operation = if let Some((op, len)) = operation(&s[i..]) { + i += len; + op + } else { + // operations default to Compatible + Op::Compatible + }; + if let Some(len) = whitespace.p(&s[i..]) { + i += len; + } + let major = if let Some((major, len)) = numeric_identifier(&s[i..]) { + i += len; + major + } else { + return Err("Error parsing major version number: ".to_string()); + }; + let minor = if let Some((minor, len)) = dot_numeric_or_wild(&s[i..]) { + i += len; + if minor.is_none() { + operation = Op::Wildcard(WildcardVersion::Minor); + } + minor + } else { + None + }; + let patch = if let Some((patch, len)) = dot_numeric_or_wild(&s[i..]) { + i += len; + if patch.is_none() { + operation = Op::Wildcard(WildcardVersion::Patch); + } + patch + } else { + None + }; + let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?; + i += pre_len; + if let Some(len) = (b'+', letters_numbers_dash_dot).p(&s[i..]) { + i += len; + } + if i != s.len() { + return Err("Extra junk after valid predicate: ".to_string() + + from_utf8(&s[i..]).unwrap()); + } + Ok(Predicate { + op: operation, + major: major, + minor: minor, + patch: patch, + pre: pre, + }) +} + +pub fn parse(ranges: &str) -> Result<VersionReq, String> { + // null is an error + if ranges == "\0" { + return Err(String::from("Null is not a valid VersionReq")); + } + + // an empty range is a major version wildcard + // so is a lone * or x of either capitalization + if (ranges == "") + || (ranges == "*") + || (ranges == "x") + || (ranges == "X") { + return Ok(VersionReq { + predicates: vec![Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }], + }); + } + + + let ranges = ranges.trim(); + + let predicates: Result<Vec<_>, String> = ranges + .split(",") + .map(|range| { + parse_predicate(range) + }) + .collect(); + + let predicates = try!(predicates); + + if predicates.len() == 0 { + return Err(String::from("VersionReq did not parse properly")); + } + + Ok(VersionReq { + predicates: predicates, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use range; + use version::Identifier; + + #[test] + fn test_parsing_default() { + let r = range::parse("1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_01() { + let r = range::parse("=1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_02() { + let r = range::parse("=0.9.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 0, + minor: Some(9), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_exact_03() { + let r = range::parse("=0.1.0-beta2.a").unwrap(); + + assert_eq!(Predicate { + op: Op::Ex, + major: 0, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("beta2")), + Identifier::AlphaNumeric(String::from("a"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than() { + let r = range::parse("> 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Gt, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than_01() { + let r = range::parse(">= 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_greater_than_02() { + let r = range::parse(">= 2.1.0-alpha2").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 2, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_less_than() { + let r = range::parse("< 1.0.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Lt, + major: 1, + minor: Some(0), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_less_than_eq() { + let r = range::parse("<= 2.1.0-alpha2").unwrap(); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 2, + minor: Some(1), + patch: Some(0), + pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_tilde() { + let r = range::parse("~1").unwrap(); + + assert_eq!(Predicate { + op: Op::Tilde, + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_parsing_compatible() { + let r = range::parse("^0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_blank() { + let r = range::parse("").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_wildcard() { + let r = range::parse("*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_x() { + let r = range::parse("x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_capital_x() { + let r = range::parse("X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Major), + major: 0, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_star() { + let r = range::parse("1.*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_x() { + let r = range::parse("1.x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_minor_wildcard_capital_x() { + let r = range::parse("1.X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Minor), + major: 1, + minor: None, + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_star() { + let r = range::parse("1.2.*").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_x() { + let r = range::parse("1.2.x").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + fn test_parsing_patch_wildcard_capital_x() { + let r = range::parse("1.2.X").unwrap(); + + assert_eq!(Predicate { + op: Op::Wildcard(WildcardVersion::Patch), + major: 1, + minor: Some(2), + patch: None, + pre: Vec::new(), + }, + r.predicates[0] + ); + } + + #[test] + pub fn test_multiple_01() { + let r = range::parse("> 0.0.9, <= 2.5.3").unwrap(); + + assert_eq!(Predicate { + op: Op::Gt, + major: 0, + minor: Some(0), + patch: Some(9), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 2, + minor: Some(5), + patch: Some(3), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_02() { + let r = range::parse("0.3.0, 0.4.0").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(3), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(4), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_03() { + let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap(); + + assert_eq!(Predicate { + op: Op::LtEq, + major: 0, + minor: Some(2), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 0, + minor: Some(5), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + pub fn test_multiple_04() { + let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap(); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(0), + pre: Vec::new(), + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(4), + pre: Vec::new(), + }, + r.predicates[1] + ); + + assert_eq!(Predicate { + op: Op::Compatible, + major: 0, + minor: Some(1), + patch: Some(6), + pre: Vec::new(), + }, + r.predicates[2] + ); + } + + #[test] + pub fn test_multiple_05() { + let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap(); + + assert_eq!(Predicate { + op: Op::GtEq, + major: 0, + minor: Some(5), + patch: Some(1), + pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))], + }, + r.predicates[0] + ); + + assert_eq!(Predicate { + op: Op::Lt, + major: 0, + minor: Some(6), + patch: None, + pre: Vec::new(), + }, + r.predicates[1] + ); + } + + #[test] + fn test_parse_build_metadata_with_predicate() { + assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op, + Op::Compatible); + assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op, + Op::Tilde); + assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op, + Op::Ex); + assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op, + Op::LtEq); + assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op, + Op::GtEq); + assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op, + Op::Lt); + assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op, + Op::Gt); + } + + #[test] + pub fn test_parse_errors() { + assert!(range::parse("\0").is_err()); + assert!(range::parse(">= >= 0.0.2").is_err()); + assert!(range::parse(">== 0.0.2").is_err()); + assert!(range::parse("a.0.0").is_err()); + assert!(range::parse("1.0.0-").is_err()); + assert!(range::parse(">=").is_err()); + assert!(range::parse("> 0.1.0,").is_err()); + assert!(range::parse("> 0.3.0, ,").is_err()); + } + + #[test] + pub fn test_large_major_version() { + assert!(range::parse("18446744073709551617.0.0").is_err()); + } + + #[test] + pub fn test_large_minor_version() { + assert!(range::parse("0.18446744073709551617.0").is_err()); + } + + #[test] + pub fn test_large_patch_version() { + assert!(range::parse("0.0.18446744073709551617").is_err()); + } +} diff --git a/semver-parser/src/recognize.rs b/semver-parser/src/recognize.rs new file mode 100644 index 000000000..c0dd771fc --- /dev/null +++ b/semver-parser/src/recognize.rs @@ -0,0 +1,154 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Licensed under either of MIT or Apache License, Version 2.0, +// at your option. +// +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Simple recognizer combinators. + +// This version is similar to a similar one in the "lang" module of +// xi-editor, but is stripped down to only the needed combinators. + +use std::ops; + +pub trait Recognize { + fn p(&self, s: &[u8]) -> Option<usize>; +} + +impl<F: Fn(&[u8]) -> Option<usize>> Recognize for F { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + self(s) + } +} + +pub struct OneByte<F>(pub F); + +impl<F: Fn(u8) -> bool> Recognize for OneByte<F> { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + if s.is_empty() || !self.0(s[0]) { + None + } else { + Some(1) + } + } +} + +impl Recognize for u8 { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + OneByte(|b| b == *self).p(s) + } +} + +/// Use Inclusive(a..b) to indicate an inclusive range. When a...b syntax becomes +/// stable, we can get rid of this and switch to that. +pub struct Inclusive<T>(pub T); + +impl Recognize for Inclusive<ops::Range<u8>> { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + OneByte(|x| x >= self.0.start && x <= self.0.end).p(s) + } +} + +impl<'a> Recognize for &'a [u8] { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + let len = self.len(); + if s.len() >= len && &s[..len] == *self { + Some(len) + } else { + None + } + } +} + +impl<'a> Recognize for &'a str { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + self.as_bytes().p(s) + } +} + +impl<P1: Recognize, P2: Recognize> Recognize for (P1, P2) { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + self.0.p(s).and_then(|len1| + self.1.p(&s[len1..]).map(|len2| + len1 + len2)) + } +} + +/// Choice from two heterogeneous alternatives. +pub struct Alt<P1, P2>(pub P1, pub P2); + +impl<P1: Recognize, P2: Recognize> Recognize for Alt<P1, P2> { + #[inline(always)] + fn p(&self, s: &[u8]) -> Option<usize> { + self.0.p(s).or_else(|| self.1.p(s)) + } +} + +/// Choice from a homogenous slice of parsers. +pub struct OneOf<'a, P: 'a>(pub &'a [P]); + +impl<'a, P: Recognize> Recognize for OneOf<'a, P> { + #[inline] + fn p(&self, s: &[u8]) -> Option<usize> { + for ref p in self.0 { + if let Some(len) = p.p(s) { + return Some(len); + } + } + None + } +} + +pub struct OneOrMore<P>(pub P); + +impl<P: Recognize> Recognize for OneOrMore<P> { + #[inline] + fn p(&self, s: &[u8]) -> Option<usize> { + let mut i = 0; + let mut count = 0; + while let Some(len) = self.0.p(&s[i..]) { + i += len; + count += 1; + } + if count >= 1 { + Some(i) + } else { + None + } + } +} + +pub struct ZeroOrMore<P>(pub P); + +impl<P: Recognize> Recognize for ZeroOrMore<P> { + #[inline] + fn p(&self, s: &[u8]) -> Option<usize> { + let mut i = 0; + while let Some(len) = self.0.p(&s[i..]) { + i += len; + } + Some(i) + } +} diff --git a/semver-parser/src/version.rs b/semver-parser/src/version.rs new file mode 100644 index 000000000..570f94768 --- /dev/null +++ b/semver-parser/src/version.rs @@ -0,0 +1,365 @@ +use std::fmt; +use std::str::from_utf8; + +use recognize::*; + +use common::{self, numeric_identifier}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Version { + pub major: u64, + pub minor: u64, + pub patch: u64, + pub pre: Vec<Identifier>, + pub build: Vec<Identifier>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Identifier { + /// An identifier that's solely numbers. + Numeric(u64), + /// An identifier with letters and numbers. + AlphaNumeric(String), +} + +pub fn parse(version: &str) -> Result<Version, String> { + let s = version.trim().as_bytes(); + let mut i = 0; + let major = if let Some((major, len)) = numeric_identifier(&s[i..]) { + i += len; + major + } else { + return Err("Error parsing major identifier".to_string()); + }; + if let Some(len) = b'.'.p(&s[i..]) { + i += len; + } else { + return Err("Expected dot".to_string()); + } + let minor = if let Some((minor, len)) = numeric_identifier(&s[i..]) { + i += len; + minor + } else { + return Err("Error parsing minor identifier".to_string()); + }; + if let Some(len) = b'.'.p(&s[i..]) { + i += len; + } else { + return Err("Expected dot".to_string()); + } + let patch = if let Some((patch, len)) = numeric_identifier(&s[i..]) { + i += len; + patch + } else { + return Err("Error parsing patch identifier".to_string()); + }; + let (pre, pre_len) = common::parse_optional_meta(&s[i..], b'-')?; + i += pre_len; + let (build, build_len) = common::parse_optional_meta(&s[i..], b'+')?; + i += build_len; + if i != s.len() { + return Err("Extra junk after valid version: ".to_string() + + from_utf8(&s[i..]).unwrap()); + } + Ok(Version { + major: major, + minor: minor, + patch: patch, + pre: pre, + build: build, + }) +} + +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); + if !self.pre.is_empty() { + let strs: Vec<_> = + self.pre.iter().map(ToString::to_string).collect(); + try!(write!(f, "-{}", strs.join("."))); + } + if !self.build.is_empty() { + let strs: Vec<_> = + self.build.iter().map(ToString::to_string).collect(); + try!(write!(f, "+{}", strs.join("."))); + } + Ok(()) + } +} + +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Identifier::Numeric(ref id) => id.fmt(f), + Identifier::AlphaNumeric(ref id) => id.fmt(f), + } + } +} + +#[cfg(test)] +mod tests { + use version; + use super::*; + + #[test] + fn parse_empty() { + let version = ""; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "empty string incorrectly considered a valid parse"); + } + + #[test] + fn parse_blank() { + let version = " "; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "blank string incorrectly considered a valid parse"); + } + + #[test] + fn parse_no_minor_patch() { + let version = "1"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_no_patch() { + let version = "1.2"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_empty_pre() { + let version = "1.2.3-"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_letters() { + let version = "a.b.c"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_with_letters() { + let version = "1.2.3 a.b.c"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); + } + + #[test] + fn parse_basic_version() { + let version = "1.2.3"; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(1, parsed.major); + assert_eq!(2, parsed.minor); + assert_eq!(3, parsed.patch); + } + + #[test] + fn parse_trims_input() { + let version = " 1.2.3 "; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(1, parsed.major); + assert_eq!(2, parsed.minor); + assert_eq!(3, parsed.patch); + } + + #[test] + fn parse_no_major_leading_zeroes() { + let version = "01.0.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid major version"); + } + + #[test] + fn parse_no_minor_leading_zeroes() { + let version = "0.01.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid minor version"); + } + + #[test] + fn parse_no_patch_leading_zeroes() { + let version = "0.0.01"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); + } + + #[test] + fn parse_no_major_overflow() { + let version = "98765432109876543210.0.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid major version"); + } + + #[test] + fn parse_no_minor_overflow() { + let version = "0.98765432109876543210.0"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid minor version"); + } + + #[test] + fn parse_no_patch_overflow() { + let version = "0.0.98765432109876543210"; + + let parsed = version::parse(version); + + assert!(parsed.is_err(), "98765432109876543210 incorrectly considered a valid patch version"); + } + + #[test] + fn parse_basic_prerelease() { + let version = "1.2.3-pre"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_prerelease_alphanumeric() { + let version = "1.2.3-alpha1"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_prerelease_zero() { + let version = "1.2.3-pre.0"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre")), + Identifier::Numeric(0)]; + assert_eq!(expected_pre, parsed.pre); + } + + #[test] + fn parse_basic_build() { + let version = "1.2.3+build"; + + let parsed = version::parse(version).unwrap(); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_build_alphanumeric() { + let version = "1.2.3+build5"; + + let parsed = version::parse(version).unwrap(); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_pre_and_build() { + let version = "1.2.3-alpha1+build5"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_complex_metadata_01() { + let version = "1.2.3-1.alpha1.9+build5.7.3aedf "; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_complex_metadata_02() { + let version = "0.4.0-beta.1+0851523"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_metadata_overflow() { + let version = "0.4.0-beta.1+98765432109876543210"; + + let parsed = version::parse(version).unwrap(); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1)]; + assert_eq!(expected_pre, parsed.pre); + + let expected_build = vec![Identifier::AlphaNumeric(String::from("98765432109876543210"))]; + assert_eq!(expected_build, parsed.build); + } + + #[test] + fn parse_regression_01() { + let version = "0.0.0-WIP"; + + let parsed = version::parse(version).unwrap(); + + assert_eq!(0, parsed.major); + assert_eq!(0, parsed.minor); + assert_eq!(0, parsed.patch); + + let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))]; + assert_eq!(expected_pre, parsed.pre); + } +} diff --git a/semver/.cargo-checksum.json b/semver/.cargo-checksum.json new file mode 100644 index 000000000..cada88550 --- /dev/null +++ b/semver/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"} \ No newline at end of file diff --git a/semver/Cargo.toml b/semver/Cargo.toml new file mode 100644 index 000000000..7749f76c3 --- /dev/null +++ b/semver/Cargo.toml @@ -0,0 +1,45 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "semver" +version = "0.9.0" +authors = ["Steve Klabnik <steve@steveklabnik.com>", "The Rust Project Developers"] +description = "Semantic version parsing and comparison.\n" +homepage = "https://docs.rs/crate/semver/" +documentation = "https://docs.rs/crate/semver/" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/steveklabnik/semver" +[dependencies.semver-parser] +version = "0.7.0" + +[dependencies.serde] +version = "1.0" +optional = true +[dev-dependencies.crates-index] +version = "0.5.0" + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.tempdir] +version = "0.3.4" + +[features] +default = [] +ci = ["serde"] +[badges.travis-ci] +repository = "steveklabnik/semver" diff --git a/semver/LICENSE-APACHE b/semver/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/semver/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/semver/LICENSE-MIT b/semver/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/semver/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/semver/README.md b/semver/README.md new file mode 100644 index 000000000..2a5306d4c --- /dev/null +++ b/semver/README.md @@ -0,0 +1,103 @@ +semver +====== + +Semantic version parsing and comparison. + +[![Build Status](https://api.travis-ci.org/steveklabnik/semver.svg?branch=master)](https://travis-ci.org/steveklabnik/semver) + +[Documentation](https://steveklabnik.github.io/semver) + +Semantic versioning (see http://semver.org/) is a set of rules for +assigning version numbers. + +## SemVer and the Rust ecosystem + +Rust itself follows the SemVer specification, as does its standard libraries. The two are +not tied together. + +[Cargo](https://crates.io), Rust's package manager, uses SemVer to determine which versions of +packages you need installed. + +## Installation + +To use `semver`, add this to your `[dependencies]` section: + +```toml +semver = "0.7.0" +``` + +And this to your crate root: + +```rust +extern crate semver; +``` + +## Versions + +At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse` +method: + +```rust +use semver::Version; + +assert!(Version::parse("1.2.3") == Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec!(), + build: vec!(), +})); +``` + +If you have multiple `Version`s, you can use the usual comparison operators to compare them: + +```rust +use semver::Version; + +assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); +assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); +``` + +## Requirements + +The `semver` crate also provides the ability to compare requirements, which are more complex +comparisons. + +For example, creating a requirement that only matches versions greater than or +equal to 1.0.0: + +```rust +use semver::Version; +use semver::VersionReq; + +let r = VersionReq::parse(">= 1.0.0").unwrap(); +let v = Version::parse("1.0.0").unwrap(); + +assert!(r.to_string() == ">= 1.0.0".to_string()); +assert!(r.matches(&v)) +``` + +It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at +https://www.npmjs.org/doc/misc/semver.html + +**Tilde requirements** specify a minimal version with some updates: + +```notrust +~1.2.3 := >=1.2.3 <1.3.0 +~1.2 := >=1.2.0 <1.3.0 +~1 := >=1.0.0 <2.0.0 +``` + +**Caret requirements** allow SemVer compatible updates to a specified version, +`0.x` and `0.x+1` are not considered compatible, but `1.x` and `1.x+1` are. + +`0.0.x` is not considered compatible with any other version. +Missing minor and patch versions are desugared to `0` but allow flexibility for that value. + +```notrust +^1.2.3 := >=1.2.3 <2.0.0 +^0.2.3 := >=0.2.3 <0.3.0 +^0.0.3 := >=0.0.3 <0.0.4 +^0.0 := >=0.0.0 <0.1.0 +^0 := >=0.0.0 <1.0.0 +``` diff --git a/semver/src/lib.rs b/semver/src/lib.rs new file mode 100644 index 000000000..a38aae0e1 --- /dev/null +++ b/semver/src/lib.rs @@ -0,0 +1,182 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Semantic version parsing and comparison. +//! +//! Semantic versioning (see http://semver.org/) is a set of rules for +//! assigning version numbers. +//! +//! ## SemVer overview +//! +//! Given a version number MAJOR.MINOR.PATCH, increment the: +//! +//! 1. MAJOR version when you make incompatible API changes, +//! 2. MINOR version when you add functionality in a backwards-compatible +//! manner, and +//! 3. PATCH version when you make backwards-compatible bug fixes. +//! +//! Additional labels for pre-release and build metadata are available as +//! extensions to the MAJOR.MINOR.PATCH format. +//! +//! Any references to 'the spec' in this documentation refer to [version 2.0 of +//! the SemVer spec](http://semver.org/spec/v2.0.0.html). +//! +//! ## SemVer and the Rust ecosystem +//! +//! Rust itself follows the SemVer specification, as does its standard +//! libraries. The two are not tied together. +//! +//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine +//! which versions of packages you need installed. +//! +//! ## Versions +//! +//! At its simplest, the `semver` crate allows you to construct `Version` +//! objects using the `parse` method: +//! +//! ```{rust} +//! use semver::Version; +//! +//! assert!(Version::parse("1.2.3") == Ok(Version { +//! major: 1, +//! minor: 2, +//! patch: 3, +//! pre: vec!(), +//! build: vec!(), +//! })); +//! ``` +//! +//! If you have multiple `Version`s, you can use the usual comparison operators +//! to compare them: +//! +//! ```{rust} +//! use semver::Version; +//! +//! assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); +//! assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); +//! ``` +//! +//! If you explicitly need to modify a Version, SemVer also allows you to +//! increment the major, minor, and patch numbers in accordance with the spec. +//! +//! Please note that in order to do this, you must use a mutable Version: +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut bugfix_release = Version::parse("1.0.0").unwrap(); +//! bugfix_release.increment_patch(); +//! +//! assert_eq!(Ok(bugfix_release), Version::parse("1.0.1")); +//! ``` +//! +//! When incrementing the minor version number, the patch number resets to zero +//! (in accordance with section 7 of the spec) +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut feature_release = Version::parse("1.4.6").unwrap(); +//! feature_release.increment_minor(); +//! +//! assert_eq!(Ok(feature_release), Version::parse("1.5.0")); +//! ``` +//! +//! Similarly, when incrementing the major version number, the patch and minor +//! numbers reset to zero (in accordance with section 8 of the spec) +//! +//! ```{rust} +//! use semver::Version; +//! +//! let mut chrome_release = Version::parse("41.5.5377").unwrap(); +//! chrome_release.increment_major(); +//! +//! assert_eq!(Ok(chrome_release), Version::parse("42.0.0")); +//! ``` +//! +//! ## Requirements +//! +//! The `semver` crate also provides the ability to compare requirements, which +//! are more complex comparisons. +//! +//! For example, creating a requirement that only matches versions greater than +//! or equal to 1.0.0: +//! +//! ```{rust} +//! # #![allow(unstable)] +//! use semver::Version; +//! use semver::VersionReq; +//! +//! let r = VersionReq::parse(">= 1.0.0").unwrap(); +//! let v = Version::parse("1.0.0").unwrap(); +//! +//! assert!(r.to_string() == ">= 1.0.0".to_string()); +//! assert!(r.matches(&v)) +//! ``` +//! +//! It also allows parsing of `~x.y.z` and `^x.y.z` requirements as defined at +//! https://www.npmjs.org/doc/misc/semver.html +//! +//! **Tilde requirements** specify a minimal version with some updates: +//! +//! ```notrust +//! ~1.2.3 := >=1.2.3 <1.3.0 +//! ~1.2 := >=1.2.0 <1.3.0 +//! ~1 := >=1.0.0 <2.0.0 +//! ``` +//! +//! **Caret requirements** allow SemVer compatible updates to a specified +//! verion, `0.x` and `0.x+1` are not considered compatible, but `1.x` and +//! `1.x+1` are. +//! +//! `0.0.x` is not considered compatible with any other version. +//! Missing minor and patch versions are desugared to `0` but allow flexibility +//! for that value. +//! +//! ```notrust +//! ^1.2.3 := >=1.2.3 <2.0.0 +//! ^0.2.3 := >=0.2.3 <0.3.0 +//! ^0.0.3 := >=0.0.3 <0.0.4 +//! ^0.0 := >=0.0.0 <0.1.0 +//! ^0 := >=0.0.0 <1.0.0 +//! ``` +//! +//! **Wildcard requirements** allows parsing of version requirements of the +//! formats `*`, `x.*` and `x.y.*`. +//! +//! ```notrust +//! * := >=0.0.0 +//! 1.* := >=1.0.0 <2.0.0 +//! 1.2.* := >=1.2.0 <1.3.0 +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +extern crate semver_parser; + +// Serialization and deserialization support for version numbers +#[cfg(feature = "serde")] +extern crate serde; + +// We take the common approach of keeping our own module system private, and +// just re-exporting the interface that we want. + +pub use version::{Version, Identifier, SemVerError}; +pub use version::Identifier::{Numeric, AlphaNumeric}; +pub use version_req::{VersionReq, ReqParseError}; + +// SemVer-compliant versions. +mod version; + +// advanced version comparisons +mod version_req; diff --git a/semver/src/version.rs b/semver/src/version.rs new file mode 100644 index 000000000..38de13319 --- /dev/null +++ b/semver/src/version.rs @@ -0,0 +1,759 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The `version` module gives you tools to create and compare SemVer-compliant +//! versions. + +use std::cmp::{self, Ordering}; +use std::fmt; +use std::hash; +use std::error::Error; + +use std::result; +use std::str; + +use semver_parser; + +#[cfg(feature = "serde")] +use serde::ser::{Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde::de::{self, Deserialize, Deserializer, Visitor}; + +/// An identifier in the pre-release or build metadata. +/// +/// See sections 9 and 10 of the spec for more about pre-release identifers and +/// build metadata. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Identifier { + /// An identifier that's solely numbers. + Numeric(u64), + /// An identifier with letters and numbers. + AlphaNumeric(String), +} + +impl From<semver_parser::version::Identifier> for Identifier { + fn from(other: semver_parser::version::Identifier) -> Identifier { + match other { + semver_parser::version::Identifier::Numeric(n) => Identifier::Numeric(n), + semver_parser::version::Identifier::AlphaNumeric(s) => Identifier::AlphaNumeric(s), + } + } +} + +impl fmt::Display for Identifier { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Identifier::Numeric(ref n) => fmt::Display::fmt(n, f), + Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f), + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for Identifier { + fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> + where S: Serializer + { + // Serialize Identifier as a number or string. + match *self { + Identifier::Numeric(n) => serializer.serialize_u64(n), + Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s), + } + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Identifier { + fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> + where D: Deserializer<'de> + { + struct IdentifierVisitor; + + // Deserialize Identifier from a number or string. + impl<'de> Visitor<'de> for IdentifierVisitor { + type Value = Identifier; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer pre-release or build identifier") + } + + fn visit_u64<E>(self, numeric: u64) -> result::Result<Self::Value, E> + where E: de::Error + { + Ok(Identifier::Numeric(numeric)) + } + + fn visit_str<E>(self, alphanumeric: &str) -> result::Result<Self::Value, E> + where E: de::Error + { + Ok(Identifier::AlphaNumeric(alphanumeric.to_owned())) + } + } + + deserializer.deserialize_any(IdentifierVisitor) + } +} + +/// Represents a version number conforming to the semantic versioning scheme. +#[derive(Clone, Eq, Debug)] +pub struct Version { + /// The major version, to be incremented on incompatible changes. + pub major: u64, + /// The minor version, to be incremented when functionality is added in a + /// backwards-compatible manner. + pub minor: u64, + /// The patch version, to be incremented when backwards-compatible bug + /// fixes are made. + pub patch: u64, + /// The pre-release version identifier, if one exists. + pub pre: Vec<Identifier>, + /// The build metadata, ignored when determining version precedence. + pub build: Vec<Identifier>, +} + +impl From<semver_parser::version::Version> for Version { + fn from(other: semver_parser::version::Version) -> Version { + Version { + major: other.major, + minor: other.minor, + patch: other.patch, + pre: other.pre.into_iter().map(From::from).collect(), + build: other.build.into_iter().map(From::from).collect(), + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for Version { + fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> + where S: Serializer + { + // Serialize Version as a string. + serializer.collect_str(self) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Version { + fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> + where D: Deserializer<'de> + { + struct VersionVisitor; + + // Deserialize Version from a string. + impl<'de> Visitor<'de> for VersionVisitor { + type Value = Version; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer version as a string") + } + + fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E> + where E: de::Error + { + Version::parse(v).map_err(de::Error::custom) + } + } + + deserializer.deserialize_str(VersionVisitor) + } +} + +/// An error type for this crate +/// +/// Currently, just a generic error. Will make this nicer later. +#[derive(Clone,PartialEq,Debug,PartialOrd)] +pub enum SemVerError { + /// An error ocurred while parsing. + ParseError(String), +} + +impl fmt::Display for SemVerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &SemVerError::ParseError(ref m) => write!(f, "{}", m), + } + } +} + +impl Error for SemVerError { + fn description(&self) -> &str { + match self { + &SemVerError::ParseError(ref m) => m, + } + } +} + +/// A Result type for errors +pub type Result<T> = result::Result<T, SemVerError>; + +impl Version { + + /// Contructs the simple case without pre or build. + pub fn new(major: u64, minor: u64, patch: u64) -> Version { + Version { + major: major, + minor: minor, + patch: patch, + pre: Vec::new(), + build: Vec::new() + } + } + + /// Parse a string into a semver object. + pub fn parse(version: &str) -> Result<Version> { + let res = semver_parser::version::parse(version); + + match res { + // Convert plain String error into proper ParseError + Err(e) => Err(SemVerError::ParseError(e)), + Ok(v) => Ok(From::from(v)), + } + } + + /// Clears the build metadata + fn clear_metadata(&mut self) { + self.build = Vec::new(); + self.pre = Vec::new(); + } + + /// Increments the patch number for this Version (Must be mutable) + pub fn increment_patch(&mut self) { + self.patch += 1; + self.clear_metadata(); + } + + /// Increments the minor version number for this Version (Must be mutable) + /// + /// As instructed by section 7 of the spec, the patch number is reset to 0. + pub fn increment_minor(&mut self) { + self.minor += 1; + self.patch = 0; + self.clear_metadata(); + } + + /// Increments the major version number for this Version (Must be mutable) + /// + /// As instructed by section 8 of the spec, the minor and patch numbers are + /// reset to 0 + pub fn increment_major(&mut self) { + self.major += 1; + self.minor = 0; + self.patch = 0; + self.clear_metadata(); + } + + /// Checks to see if the current Version is in pre-release status + pub fn is_prerelease(&self) -> bool { + !self.pre.is_empty() + } +} + +impl str::FromStr for Version { + type Err = SemVerError; + + fn from_str(s: &str) -> Result<Version> { + Version::parse(s) + } +} + +impl fmt::Display for Version { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); + if !self.pre.is_empty() { + try!(write!(f, "-")); + for (i, x) in self.pre.iter().enumerate() { + if i != 0 { + try!(write!(f, ".")) + } + try!(write!(f, "{}", x)); + } + } + if !self.build.is_empty() { + try!(write!(f, "+")); + for (i, x) in self.build.iter().enumerate() { + if i != 0 { + try!(write!(f, ".")) + } + try!(write!(f, "{}", x)); + } + } + Ok(()) + } +} + +impl cmp::PartialEq for Version { + #[inline] + fn eq(&self, other: &Version) -> bool { + // We should ignore build metadata here, otherwise versions v1 and v2 + // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which + // violate strict total ordering rules. + self.major == other.major && self.minor == other.minor && self.patch == other.patch && + self.pre == other.pre + } +} + +impl cmp::PartialOrd for Version { + fn partial_cmp(&self, other: &Version) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl cmp::Ord for Version { + fn cmp(&self, other: &Version) -> Ordering { + match self.major.cmp(&other.major) { + Ordering::Equal => {} + r => return r, + } + + match self.minor.cmp(&other.minor) { + Ordering::Equal => {} + r => return r, + } + + match self.patch.cmp(&other.patch) { + Ordering::Equal => {} + r => return r, + } + + // NB: semver spec says 0.0.0-pre < 0.0.0 + // but the version of ord defined for vec + // says that [] < [pre] so we alter it here + match (self.pre.len(), other.pre.len()) { + (0, 0) => Ordering::Equal, + (0, _) => Ordering::Greater, + (_, 0) => Ordering::Less, + (_, _) => self.pre.cmp(&other.pre), + } + } +} + +impl hash::Hash for Version { + fn hash<H: hash::Hasher>(&self, into: &mut H) { + self.major.hash(into); + self.minor.hash(into); + self.patch.hash(into); + self.pre.hash(into); + } +} + +impl From<(u64,u64,u64)> for Version { + fn from(tuple: (u64,u64,u64)) -> Version { + let (major, minor, patch) = tuple; + Version::new(major, minor, patch) + } +} + +#[cfg(test)] +mod tests { + use std::result; + use super::Version; + use super::Identifier; + use super::SemVerError; + + #[test] + fn test_parse() { + fn parse_error(e: &str) -> result::Result<Version, SemVerError> { + return Err(SemVerError::ParseError(e.to_string())); + } + + assert_eq!(Version::parse(""), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse(" "), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse("1"), + parse_error("Expected dot")); + assert_eq!(Version::parse("1.2"), + parse_error("Expected dot")); + assert_eq!(Version::parse("1.2.3-"), + parse_error("Error parsing prerelease")); + assert_eq!(Version::parse("a.b.c"), + parse_error("Error parsing major identifier")); + assert_eq!(Version::parse("1.2.3 abc"), + parse_error("Extra junk after valid version: abc")); + + assert_eq!(Version::parse("1.2.3"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + + assert_eq!(Version::parse("1.2.3"), + Ok(Version::new(1,2,3))); + + assert_eq!(Version::parse(" 1.2.3 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!(Version::parse("1.2.3-alpha1"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(Version::parse(" 1.2.3-alpha1 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(Version::parse("1.2.3+build5"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse(" 1.2.3+build5 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse("1.2.3-alpha1+build5"), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse(" 1.2.3-alpha1+build5 "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf "), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9), + ], + build: vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf")), + ], + })); + assert_eq!(Version::parse("0.4.0-beta.1+0851523"), + Ok(Version { + major: 0, + minor: 4, + patch: 0, + pre: vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1), + ], + build: vec![Identifier::AlphaNumeric(String::from("0851523"))], + })); + + } + + #[test] + fn test_increment_patch() { + let mut buggy_release = Version::parse("0.1.0").unwrap(); + buggy_release.increment_patch(); + assert_eq!(buggy_release, Version::parse("0.1.1").unwrap()); + } + + #[test] + fn test_increment_minor() { + let mut feature_release = Version::parse("1.4.6").unwrap(); + feature_release.increment_minor(); + assert_eq!(feature_release, Version::parse("1.5.0").unwrap()); + } + + #[test] + fn test_increment_major() { + let mut chrome_release = Version::parse("46.1.246773").unwrap(); + chrome_release.increment_major(); + assert_eq!(chrome_release, Version::parse("47.0.0").unwrap()); + } + + #[test] + fn test_increment_keep_prerelease() { + let mut release = Version::parse("1.0.0-alpha").unwrap(); + release.increment_patch(); + + assert_eq!(release, Version::parse("1.0.1").unwrap()); + + release.increment_minor(); + + assert_eq!(release, Version::parse("1.1.0").unwrap()); + + release.increment_major(); + + assert_eq!(release, Version::parse("2.0.0").unwrap()); + } + + + #[test] + fn test_increment_clear_metadata() { + let mut release = Version::parse("1.0.0+4442").unwrap(); + release.increment_patch(); + + assert_eq!(release, Version::parse("1.0.1").unwrap()); + release = Version::parse("1.0.1+hello").unwrap(); + + release.increment_minor(); + + assert_eq!(release, Version::parse("1.1.0").unwrap()); + release = Version::parse("1.1.3747+hello").unwrap(); + + release.increment_major(); + + assert_eq!(release, Version::parse("2.0.0").unwrap()); + } + + #[test] + fn test_eq() { + assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3")); + assert_eq!(Version::parse("1.2.3-alpha1"), + Version::parse("1.2.3-alpha1")); + assert_eq!(Version::parse("1.2.3+build.42"), + Version::parse("1.2.3+build.42")); + assert_eq!(Version::parse("1.2.3-alpha1+42"), + Version::parse("1.2.3-alpha1+42")); + assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42")); + } + + #[test] + fn test_ne() { + assert!(Version::parse("0.0.0") != Version::parse("0.0.1")); + assert!(Version::parse("0.0.0") != Version::parse("0.1.0")); + assert!(Version::parse("0.0.0") != Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta")); + } + + #[test] + fn test_show() { + assert_eq!(format!("{}", Version::parse("1.2.3").unwrap()), + "1.2.3".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3-alpha1").unwrap()), + "1.2.3-alpha1".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3+build.42").unwrap()), + "1.2.3+build.42".to_string()); + assert_eq!(format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()), + "1.2.3-alpha1+42".to_string()); + } + + #[test] + fn test_to_string() { + assert_eq!(Version::parse("1.2.3").unwrap().to_string(), + "1.2.3".to_string()); + assert_eq!(Version::parse("1.2.3-alpha1").unwrap().to_string(), + "1.2.3-alpha1".to_string()); + assert_eq!(Version::parse("1.2.3+build.42").unwrap().to_string(), + "1.2.3+build.42".to_string()); + assert_eq!(Version::parse("1.2.3-alpha1+42").unwrap().to_string(), + "1.2.3-alpha1+42".to_string()); + } + + #[test] + fn test_lt() { + assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3")); + assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2")); + assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2"))); + assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42"))); + } + + #[test] + fn test_le() { + assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42")); + } + + #[test] + fn test_gt() { + assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0")); + assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1")); + assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2")); + assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2"))); + assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42"))); + } + + #[test] + fn test_ge() { + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1")); + assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2")); + assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42")); + } + + #[test] + fn test_prerelease_check() { + assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false); + assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false); + assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease()); + assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease()); + } + + #[test] + fn test_spec_order() { + let vs = ["1.0.0-alpha", + "1.0.0-alpha.1", + "1.0.0-alpha.beta", + "1.0.0-beta", + "1.0.0-beta.2", + "1.0.0-beta.11", + "1.0.0-rc.1", + "1.0.0"]; + let mut i = 1; + while i < vs.len() { + let a = Version::parse(vs[i - 1]); + let b = Version::parse(vs[i]); + assert!(a < b, "nope {:?} < {:?}", a, b); + i += 1; + } + } + + #[test] + fn test_from_str() { + assert_eq!("1.2.3".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!(" 1.2.3 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: Vec::new(), + })); + assert_eq!("1.2.3-alpha1".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!(" 1.2.3-alpha1 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: Vec::new(), + })); + assert_eq!("1.2.3+build5".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(" 1.2.3+build5 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: Vec::new(), + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!("1.2.3-alpha1+build5".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!(" 1.2.3-alpha1+build5 ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))], + build: vec![Identifier::AlphaNumeric(String::from("build5"))], + })); + assert_eq!("1.2.3-1.alpha1.9+build5.7.3aedf ".parse(), + Ok(Version { + major: 1, + minor: 2, + patch: 3, + pre: vec![Identifier::Numeric(1), + Identifier::AlphaNumeric(String::from("alpha1")), + Identifier::Numeric(9), + ], + build: vec![Identifier::AlphaNumeric(String::from("build5")), + Identifier::Numeric(7), + Identifier::AlphaNumeric(String::from("3aedf")), + ], + })); + assert_eq!("0.4.0-beta.1+0851523".parse(), + Ok(Version { + major: 0, + minor: 4, + patch: 0, + pre: vec![Identifier::AlphaNumeric(String::from("beta")), + Identifier::Numeric(1), + ], + build: vec![Identifier::AlphaNumeric(String::from("0851523"))], + })); + + } + + #[test] + fn test_from_str_errors() { + fn parse_error(e: &str) -> result::Result<Version, SemVerError> { + return Err(SemVerError::ParseError(e.to_string())); + } + + assert_eq!("".parse(), parse_error("Error parsing major identifier")); + assert_eq!(" ".parse(), parse_error("Error parsing major identifier")); + assert_eq!("1".parse(), parse_error("Expected dot")); + assert_eq!("1.2".parse(), + parse_error("Expected dot")); + assert_eq!("1.2.3-".parse(), + parse_error("Error parsing prerelease")); + assert_eq!("a.b.c".parse(), + parse_error("Error parsing major identifier")); + assert_eq!("1.2.3 abc".parse(), + parse_error("Extra junk after valid version: abc")); + } +} diff --git a/semver/src/version_req.rs b/semver/src/version_req.rs new file mode 100644 index 000000000..6e6a542b8 --- /dev/null +++ b/semver/src/version_req.rs @@ -0,0 +1,895 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::error::Error; +use std::fmt; +use std::result; +use std::str; + +use Version; +use version::Identifier; +use semver_parser; + +#[cfg(feature = "serde")] +use serde::ser::{Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde::de::{self, Deserialize, Deserializer, Visitor}; + +use self::Op::{Ex, Gt, GtEq, Lt, LtEq, Tilde, Compatible, Wildcard}; +use self::WildcardVersion::{Major, Minor, Patch}; +use self::ReqParseError::*; + +/// A `VersionReq` is a struct containing a list of predicates that can apply to ranges of version +/// numbers. Matching operations can then be done with the `VersionReq` against a particular +/// version to see if it satisfies some or all of the constraints. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct VersionReq { + predicates: Vec<Predicate>, +} + +impl From<semver_parser::range::VersionReq> for VersionReq { + fn from(other: semver_parser::range::VersionReq) -> VersionReq { + VersionReq { predicates: other.predicates.into_iter().map(From::from).collect() } + } +} + +#[cfg(feature = "serde")] +impl Serialize for VersionReq { + fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error> + where S: Serializer + { + // Serialize VersionReq as a string. + serializer.collect_str(self) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for VersionReq { + fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error> + where D: Deserializer<'de> + { + struct VersionReqVisitor; + + /// Deserialize `VersionReq` from a string. + impl<'de> Visitor<'de> for VersionReqVisitor { + type Value = VersionReq; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a SemVer version requirement as a string") + } + + fn visit_str<E>(self, v: &str) -> result::Result<Self::Value, E> + where E: de::Error + { + VersionReq::parse(v).map_err(de::Error::custom) + } + } + + deserializer.deserialize_str(VersionReqVisitor) + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum WildcardVersion { + Major, + Minor, + Patch, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +enum Op { + Ex, // Exact + Gt, // Greater than + GtEq, // Greater than or equal to + Lt, // Less than + LtEq, // Less than or equal to + Tilde, // e.g. ~1.0.0 + Compatible, // compatible by definition of semver, indicated by ^ + Wildcard(WildcardVersion), // x.y.*, x.*, * +} + +impl From<semver_parser::range::Op> for Op { + fn from(other: semver_parser::range::Op) -> Op { + use semver_parser::range; + match other { + range::Op::Ex => Op::Ex, + range::Op::Gt => Op::Gt, + range::Op::GtEq => Op::GtEq, + range::Op::Lt => Op::Lt, + range::Op::LtEq => Op::LtEq, + range::Op::Tilde => Op::Tilde, + range::Op::Compatible => Op::Compatible, + range::Op::Wildcard(version) => { + match version { + range::WildcardVersion::Major => Op::Wildcard(WildcardVersion::Major), + range::WildcardVersion::Minor => Op::Wildcard(WildcardVersion::Minor), + range::WildcardVersion::Patch => Op::Wildcard(WildcardVersion::Patch), + } + } + } + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +struct Predicate { + op: Op, + major: u64, + minor: Option<u64>, + patch: Option<u64>, + pre: Vec<Identifier>, +} + +impl From<semver_parser::range::Predicate> for Predicate { + fn from(other: semver_parser::range::Predicate) -> Predicate { + Predicate { + op: From::from(other.op), + major: other.major, + minor: other.minor, + patch: other.patch, + pre: other.pre.into_iter().map(From::from).collect(), + } + } +} + +/// A `ReqParseError` is returned from methods which parse a string into a `VersionReq`. Each +/// enumeration is one of the possible errors that can occur. +#[derive(Clone, Debug, PartialEq)] +pub enum ReqParseError { + /// The given version requirement is invalid. + InvalidVersionRequirement, + /// You have already provided an operation, such as `=`, `~`, or `^`. Only use one. + OpAlreadySet, + /// The sigil you have written is not correct. + InvalidSigil, + /// All components of a version must be numeric. + VersionComponentsMustBeNumeric, + /// There was an error parsing an identifier. + InvalidIdentifier, + /// At least a major version is required. + MajorVersionRequired, + /// An unimplemented version requirement. + UnimplementedVersionRequirement, + /// This form of requirement is deprecated. + DeprecatedVersionRequirement(VersionReq), +} + +impl fmt::Display for ReqParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Error for ReqParseError { + fn description(&self) -> &str { + match self { + &InvalidVersionRequirement => "the given version requirement is invalid", + &OpAlreadySet => { + "you have already provided an operation, such as =, ~, or ^; only use one" + }, + &InvalidSigil => "the sigil you have written is not correct", + &VersionComponentsMustBeNumeric => "version components must be numeric", + &InvalidIdentifier => "invalid identifier", + &MajorVersionRequired => "at least a major version number is required", + &UnimplementedVersionRequirement => { + "the given version requirement is not implemented, yet" + }, + &DeprecatedVersionRequirement(_) => "This requirement is deprecated", + } + } +} + +impl From<String> for ReqParseError { + fn from(other: String) -> ReqParseError { + match &*other { + "Null is not a valid VersionReq" => ReqParseError::InvalidVersionRequirement, + "VersionReq did not parse properly." => ReqParseError::OpAlreadySet, + _ => ReqParseError::InvalidVersionRequirement, + } + } +} + +impl VersionReq { + /// `any()` is a factory method which creates a `VersionReq` with no constraints. In other + /// words, any version will match against it. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// + /// let anything = VersionReq::any(); + /// ``` + pub fn any() -> VersionReq { + VersionReq { predicates: vec![] } + } + + /// `parse()` is the main constructor of a `VersionReq`. It takes a string like `"^1.2.3"` + /// and turns it into a `VersionReq` that matches that particular constraint. + /// + /// A `Result` is returned which contains a `ReqParseError` if there was a problem parsing the + /// `VersionReq`. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// + /// let version = VersionReq::parse("=1.2.3"); + /// let version = VersionReq::parse(">1.2.3"); + /// let version = VersionReq::parse("<1.2.3"); + /// let version = VersionReq::parse("~1.2.3"); + /// let version = VersionReq::parse("^1.2.3"); + /// let version = VersionReq::parse("1.2.3"); // synonym for ^1.2.3 + /// let version = VersionReq::parse("<=1.2.3"); + /// let version = VersionReq::parse(">=1.2.3"); + /// ``` + /// + /// This example demonstrates error handling, and will panic. + /// + /// ```should-panic + /// use semver::VersionReq; + /// + /// let version = match VersionReq::parse("not a version") { + /// Ok(version) => version, + /// Err(e) => panic!("There was a problem parsing: {}", e), + /// } + /// ``` + pub fn parse(input: &str) -> Result<VersionReq, ReqParseError> { + let res = semver_parser::range::parse(input); + + if let Ok(v) = res { + return Ok(From::from(v)); + } + + return match VersionReq::parse_deprecated(input) { + Some(v) => { + Err(ReqParseError::DeprecatedVersionRequirement(v)) + } + None => Err(From::from(res.err().unwrap())), + } + } + + fn parse_deprecated(version: &str) -> Option<VersionReq> { + return match version { + ".*" => Some(VersionReq::any()), + "0.1.0." => Some(VersionReq::parse("0.1.0").unwrap()), + "0.3.1.3" => Some(VersionReq::parse("0.3.13").unwrap()), + "0.2*" => Some(VersionReq::parse("0.2.*").unwrap()), + "*.0" => Some(VersionReq::any()), + _ => None, + } + } + + /// `exact()` is a factory method which creates a `VersionReq` with one exact constraint. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// use semver::Version; + /// + /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] }; + /// let exact = VersionReq::exact(&version); + /// ``` + pub fn exact(version: &Version) -> VersionReq { + VersionReq { predicates: vec![Predicate::exact(version)] } + } + + /// `matches()` matches a given `Version` against this `VersionReq`. + /// + /// # Examples + /// + /// ``` + /// use semver::VersionReq; + /// use semver::Version; + /// + /// let version = Version { major: 1, minor: 1, patch: 1, pre: vec![], build: vec![] }; + /// let exact = VersionReq::exact(&version); + /// + /// assert!(exact.matches(&version)); + /// ``` + pub fn matches(&self, version: &Version) -> bool { + // no predicates means anything matches + if self.predicates.is_empty() { + return true; + } + + self.predicates.iter().all(|p| p.matches(version)) && + self.predicates.iter().any(|p| p.pre_tag_is_compatible(version)) + } +} + +impl str::FromStr for VersionReq { + type Err = ReqParseError; + + fn from_str(s: &str) -> Result<VersionReq, ReqParseError> { + VersionReq::parse(s) + } +} + +impl Predicate { + fn exact(version: &Version) -> Predicate { + Predicate { + op: Ex, + major: version.major, + minor: Some(version.minor), + patch: Some(version.patch), + pre: version.pre.clone(), + } + } + + /// `matches()` takes a `Version` and determines if it matches this particular `Predicate`. + pub fn matches(&self, ver: &Version) -> bool { + match self.op { + Ex => self.is_exact(ver), + Gt => self.is_greater(ver), + GtEq => self.is_exact(ver) || self.is_greater(ver), + Lt => !self.is_exact(ver) && !self.is_greater(ver), + LtEq => !self.is_greater(ver), + Tilde => self.matches_tilde(ver), + Compatible => self.is_compatible(ver), + Wildcard(_) => self.matches_wildcard(ver), + } + } + + fn is_exact(&self, ver: &Version) -> bool { + if self.major != ver.major { + return false; + } + + match self.minor { + Some(minor) => { + if minor != ver.minor { + return false; + } + } + None => return true, + } + + match self.patch { + Some(patch) => { + if patch != ver.patch { + return false; + } + } + None => return true, + } + + if self.pre != ver.pre { + return false; + } + + true + } + + // https://docs.npmjs.com/misc/semver#prerelease-tags + fn pre_tag_is_compatible(&self, ver: &Version) -> bool { + // If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will + // only be + // allowed to satisfy comparator sets if at least one comparator with the same + // [major, + // minor, patch] tuple also has a prerelease tag. + !ver.is_prerelease() || + (self.major == ver.major && self.minor == Some(ver.minor) && + self.patch == Some(ver.patch) && !self.pre.is_empty()) + } + + fn is_greater(&self, ver: &Version) -> bool { + if self.major != ver.major { + return ver.major > self.major; + } + + match self.minor { + Some(minor) => { + if minor != ver.minor { + return ver.minor > minor; + } + } + None => return false, + } + + match self.patch { + Some(patch) => { + if patch != ver.patch { + return ver.patch > patch; + } + } + None => return false, + } + + if !self.pre.is_empty() { + return ver.pre.is_empty() || ver.pre > self.pre; + } + + false + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn matches_tilde(&self, ver: &Version) -> bool { + let minor = match self.minor { + Some(n) => n, + None => return self.major == ver.major, + }; + + match self.patch { + Some(patch) => { + self.major == ver.major && minor == ver.minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver))) + } + None => self.major == ver.major && minor == ver.minor, + } + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn is_compatible(&self, ver: &Version) -> bool { + if self.major != ver.major { + return false; + } + + let minor = match self.minor { + Some(n) => n, + None => return self.major == ver.major, + }; + + match self.patch { + Some(patch) => { + if self.major == 0 { + if minor == 0 { + ver.minor == minor && ver.patch == patch && self.pre_is_compatible(ver) + } else { + ver.minor == minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver))) + } + } else { + ver.minor > minor || + (ver.minor == minor && + (ver.patch > patch || (ver.patch == patch && self.pre_is_compatible(ver)))) + } + } + None => { + if self.major == 0 { + ver.minor == minor + } else { + ver.minor >= minor + } + } + } + } + + fn pre_is_compatible(&self, ver: &Version) -> bool { + ver.pre.is_empty() || ver.pre >= self.pre + } + + // see https://www.npmjs.org/doc/misc/semver.html for behavior + fn matches_wildcard(&self, ver: &Version) -> bool { + match self.op { + Wildcard(Major) => true, + Wildcard(Minor) => self.major == ver.major, + Wildcard(Patch) => { + match self.minor { + Some(minor) => self.major == ver.major && minor == ver.minor, + None => { + // minor and patch version astericks mean match on major + self.major == ver.major + } + } + } + _ => false, // unreachable + } + } +} + +impl fmt::Display for VersionReq { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + if self.predicates.is_empty() { + try!(write!(fmt, "*")); + } else { + for (i, ref pred) in self.predicates.iter().enumerate() { + if i == 0 { + try!(write!(fmt, "{}", pred)); + } else { + try!(write!(fmt, ", {}", pred)); + } + } + } + + Ok(()) + } +} + +impl fmt::Display for Predicate { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.op { + Wildcard(Major) => try!(write!(fmt, "*")), + Wildcard(Minor) => try!(write!(fmt, "{}.*", self.major)), + Wildcard(Patch) => { + if let Some(minor) = self.minor { + try!(write!(fmt, "{}.{}.*", self.major, minor)) + } else { + try!(write!(fmt, "{}.*.*", self.major)) + } + } + _ => { + try!(write!(fmt, "{}{}", self.op, self.major)); + + match self.minor { + Some(v) => try!(write!(fmt, ".{}", v)), + None => (), + } + + match self.patch { + Some(v) => try!(write!(fmt, ".{}", v)), + None => (), + } + + if !self.pre.is_empty() { + try!(write!(fmt, "-")); + for (i, x) in self.pre.iter().enumerate() { + if i != 0 { + try!(write!(fmt, ".")) + } + try!(write!(fmt, "{}", x)); + } + } + } + } + + Ok(()) + } +} + +impl fmt::Display for Op { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match *self { + Ex => try!(write!(fmt, "= ")), + Gt => try!(write!(fmt, "> ")), + GtEq => try!(write!(fmt, ">= ")), + Lt => try!(write!(fmt, "< ")), + LtEq => try!(write!(fmt, "<= ")), + Tilde => try!(write!(fmt, "~")), + Compatible => try!(write!(fmt, "^")), + // gets handled specially in Predicate::fmt + Wildcard(_) => try!(write!(fmt, "")), + } + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::{VersionReq, Op}; + use super::super::version::Version; + use std::hash::{Hash, Hasher}; + + fn req(s: &str) -> VersionReq { + VersionReq::parse(s).unwrap() + } + + fn version(s: &str) -> Version { + match Version::parse(s) { + Ok(v) => v, + Err(e) => panic!("`{}` is not a valid version. Reason: {:?}", s, e), + } + } + + fn assert_match(req: &VersionReq, vers: &[&str]) { + for ver in vers.iter() { + assert!(req.matches(&version(*ver)), "did not match {}", ver); + } + } + + fn assert_not_match(req: &VersionReq, vers: &[&str]) { + for ver in vers.iter() { + assert!(!req.matches(&version(*ver)), "matched {}", ver); + } + } + + fn calculate_hash<T: Hash>(t: T) -> u64 { + use std::collections::hash_map::DefaultHasher; + + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_parsing_default() { + let r = req("1.0.0"); + + assert_eq!(r.to_string(), "^1.0.0".to_string()); + + assert_match(&r, &["1.0.0", "1.0.1"]); + assert_not_match(&r, &["0.9.9", "0.10.0", "0.1.0"]); + } + + #[test] + fn test_parsing_exact() { + let r = req("=1.0.0"); + + assert!(r.to_string() == "= 1.0.0".to_string()); + assert_eq!(r.to_string(), "= 1.0.0".to_string()); + + assert_match(&r, &["1.0.0"]); + assert_not_match(&r, &["1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"]); + + let r = req("=0.9.0"); + + assert_eq!(r.to_string(), "= 0.9.0".to_string()); + + assert_match(&r, &["0.9.0"]); + assert_not_match(&r, &["0.9.1", "1.9.0", "0.0.9"]); + + let r = req("=0.1.0-beta2.a"); + + assert_eq!(r.to_string(), "= 0.1.0-beta2.a".to_string()); + + assert_match(&r, &["0.1.0-beta2.a"]); + assert_not_match(&r, &["0.9.1", "0.1.0", "0.1.1-beta2.a", "0.1.0-beta2"]); + } + + #[test] + fn test_parse_metadata_see_issue_88_see_issue_88() { + for op in &[Op::Compatible, Op::Ex, Op::Gt, Op::GtEq, Op::Lt, Op::LtEq, Op::Tilde] { + req(&format!("{} 1.2.3+meta", op)); + } + } + + #[test] + pub fn test_parsing_greater_than() { + let r = req(">= 1.0.0"); + + assert_eq!(r.to_string(), ">= 1.0.0".to_string()); + + assert_match(&r, &["1.0.0", "2.0.0"]); + assert_not_match(&r, &["0.1.0", "0.0.1", "1.0.0-pre", "2.0.0-pre"]); + + let r = req(">= 2.1.0-alpha2"); + + assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha3", "2.1.0", "3.0.0"]); + assert_not_match(&r, + &["2.0.0", "2.1.0-alpha1", "2.0.0-alpha2", "3.0.0-alpha2"]); + } + + #[test] + pub fn test_parsing_less_than() { + let r = req("< 1.0.0"); + + assert_eq!(r.to_string(), "< 1.0.0".to_string()); + + assert_match(&r, &["0.1.0", "0.0.1"]); + assert_not_match(&r, &["1.0.0", "1.0.0-beta", "1.0.1", "0.9.9-alpha"]); + + let r = req("<= 2.1.0-alpha2"); + + assert_match(&r, &["2.1.0-alpha2", "2.1.0-alpha1", "2.0.0", "1.0.0"]); + assert_not_match(&r, + &["2.1.0", "2.2.0-alpha1", "2.0.0-alpha2", "1.0.0-alpha2"]); + } + + #[test] + pub fn test_multiple() { + let r = req("> 0.0.9, <= 2.5.3"); + assert_eq!(r.to_string(), "> 0.0.9, <= 2.5.3".to_string()); + assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]); + assert_not_match(&r, &["0.0.8", "2.5.4"]); + + let r = req("0.3.0, 0.4.0"); + assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string()); + assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]); + + let r = req("<= 0.2.0, >= 0.5.0"); + assert_eq!(r.to_string(), "<= 0.2.0, >= 0.5.0".to_string()); + assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]); + + let r = req("0.1.0, 0.1.4, 0.1.6"); + assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string()); + assert_match(&r, &["0.1.6", "0.1.9"]); + assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]); + + assert!(VersionReq::parse("> 0.1.0,").is_err()); + assert!(VersionReq::parse("> 0.3.0, ,").is_err()); + + let r = req(">=0.5.1-alpha3, <0.6"); + assert_eq!(r.to_string(), ">= 0.5.1-alpha3, < 0.6".to_string()); + assert_match(&r, + &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); + assert_not_match(&r, + &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"]); + assert_not_match(&r, &["0.6.0", "0.6.0-pre"]); + } + + #[test] + pub fn test_parsing_tilde() { + let r = req("~1"); + assert_match(&r, &["1.0.0", "1.0.1", "1.1.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "0.0.9"]); + + let r = req("~1.2"); + assert_match(&r, &["1.2.0", "1.2.1"]); + assert_not_match(&r, &["1.1.1", "1.3.0", "0.0.9"]); + + let r = req("~1.2.2"); + assert_match(&r, &["1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.2.1", "1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + + let r = req("~1.2.3-beta.2"); + assert_match(&r, &["1.2.3", "1.2.4", "1.2.3-beta.2", "1.2.3-beta.4"]); + assert_not_match(&r, &["1.3.3", "1.1.4", "1.2.3-beta.1", "1.2.4-beta.2"]); + } + + #[test] + pub fn test_parsing_compatible() { + let r = req("^1"); + assert_match(&r, &["1.1.2", "1.1.0", "1.2.1", "1.0.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "0.1.4"]); + assert_not_match(&r, &["1.0.0-beta1", "0.1.0-alpha", "1.0.1-pre"]); + + let r = req("^1.1"); + assert_match(&r, &["1.1.2", "1.1.0", "1.2.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.0.1", "0.1.4"]); + + let r = req("^1.1.2"); + assert_match(&r, &["1.1.2", "1.1.4", "1.2.1"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]); + assert_not_match(&r, &["1.1.2-alpha1", "1.1.3-alpha1", "2.9.0-alpha1"]); + + let r = req("^0.1.2"); + assert_match(&r, &["0.1.2", "0.1.4"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1"]); + assert_not_match(&r, &["0.1.2-beta", "0.1.3-alpha", "0.2.0-pre"]); + + let r = req("^0.5.1-alpha3"); + assert_match(&r, + &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); + assert_not_match(&r, + &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre", "0.6.0"]); + + let r = req("^0.0.2"); + assert_match(&r, &["0.0.2"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.0.1", "0.1.4"]); + + let r = req("^0.0"); + assert_match(&r, &["0.0.2", "0.0.0"]); + assert_not_match(&r, &["0.9.1", "2.9.0", "1.1.1", "0.1.4"]); + + let r = req("^0"); + assert_match(&r, &["0.9.1", "0.0.2", "0.0.0"]); + assert_not_match(&r, &["2.9.0", "1.1.1"]); + + let r = req("^1.4.2-beta.5"); + assert_match(&r, + &["1.4.2", "1.4.3", "1.4.2-beta.5", "1.4.2-beta.6", "1.4.2-c"]); + assert_not_match(&r, + &["0.9.9", "2.0.0", "1.4.2-alpha", "1.4.2-beta.4", "1.4.3-beta.5"]); + } + + #[test] + pub fn test_parsing_wildcard() { + let r = req(""); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("*"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("x"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + let r = req("X"); + assert_match(&r, &["0.9.1", "2.9.0", "0.0.9", "1.0.1", "1.1.1"]); + assert_not_match(&r, &[]); + + let r = req("1.*"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + let r = req("1.x"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + let r = req("1.X"); + assert_match(&r, &["1.2.0", "1.2.1", "1.1.1", "1.3.0"]); + assert_not_match(&r, &["0.0.9"]); + + let r = req("1.2.*"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + let r = req("1.2.x"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + let r = req("1.2.X"); + assert_match(&r, &["1.2.0", "1.2.2", "1.2.4"]); + assert_not_match(&r, &["1.9.0", "1.0.9", "2.0.1", "0.1.3"]); + } + + #[test] + pub fn test_any() { + let r = VersionReq::any(); + assert_match(&r, &["0.0.1", "0.1.0", "1.0.0"]); + } + + #[test] + pub fn test_pre() { + let r = req("=2.1.1-really.0"); + assert_match(&r, &["2.1.1-really.0"]); + } + + // #[test] + // pub fn test_parse_errors() { + // assert_eq!(Err(InvalidVersionRequirement), VersionReq::parse("\0")); + // assert_eq!(Err(OpAlreadySet), VersionReq::parse(">= >= 0.0.2")); + // assert_eq!(Err(InvalidSigil), VersionReq::parse(">== 0.0.2")); + // assert_eq!(Err(VersionComponentsMustBeNumeric), + // VersionReq::parse("a.0.0")); + // assert_eq!(Err(InvalidIdentifier), VersionReq::parse("1.0.0-")); + // assert_eq!(Err(MajorVersionRequired), VersionReq::parse(">=")); + // } + + #[test] + pub fn test_from_str() { + assert_eq!("1.0.0".parse::<VersionReq>().unwrap().to_string(), + "^1.0.0".to_string()); + assert_eq!("=1.0.0".parse::<VersionReq>().unwrap().to_string(), + "= 1.0.0".to_string()); + assert_eq!("~1".parse::<VersionReq>().unwrap().to_string(), + "~1".to_string()); + assert_eq!("~1.2".parse::<VersionReq>().unwrap().to_string(), + "~1.2".to_string()); + assert_eq!("^1".parse::<VersionReq>().unwrap().to_string(), + "^1".to_string()); + assert_eq!("^1.1".parse::<VersionReq>().unwrap().to_string(), + "^1.1".to_string()); + assert_eq!("*".parse::<VersionReq>().unwrap().to_string(), + "*".to_string()); + assert_eq!("1.*".parse::<VersionReq>().unwrap().to_string(), + "1.*".to_string()); + assert_eq!("< 1.0.0".parse::<VersionReq>().unwrap().to_string(), + "< 1.0.0".to_string()); + } + + // #[test] + // pub fn test_from_str_errors() { + // assert_eq!(Err(InvalidVersionRequirement), "\0".parse::<VersionReq>()); + // assert_eq!(Err(OpAlreadySet), ">= >= 0.0.2".parse::<VersionReq>()); + // assert_eq!(Err(InvalidSigil), ">== 0.0.2".parse::<VersionReq>()); + // assert_eq!(Err(VersionComponentsMustBeNumeric), + // "a.0.0".parse::<VersionReq>()); + // assert_eq!(Err(InvalidIdentifier), "1.0.0-".parse::<VersionReq>()); + // assert_eq!(Err(MajorVersionRequired), ">=".parse::<VersionReq>()); + // } + + #[test] + fn test_cargo3202() { + let v = "0.*.*".parse::<VersionReq>().unwrap(); + assert_eq!("0.*.*", format!("{}", v.predicates[0])); + + let v = "0.0.*".parse::<VersionReq>().unwrap(); + assert_eq!("0.0.*", format!("{}", v.predicates[0])); + + let r = req("0.*.*"); + assert_match(&r, &["0.5.0"]); + } + + #[test] + fn test_eq_hash() { + assert!(req("^1") == req("^1")); + assert!(calculate_hash(req("^1")) == calculate_hash(req("^1"))); + assert!(req("^1") != req("^2")); + } + + #[test] + fn test_ordering() { + assert!(req("=1") < req("*")); + assert!(req(">1") < req("*")); + assert!(req(">=1") < req("*")); + assert!(req("<1") < req("*")); + assert!(req("<=1") < req("*")); + assert!(req("~1") < req("*")); + assert!(req("^1") < req("*")); + assert!(req("*") == req("*")); + } +} diff --git a/semver/tests/deprecation.rs b/semver/tests/deprecation.rs new file mode 100644 index 000000000..a5f533a34 --- /dev/null +++ b/semver/tests/deprecation.rs @@ -0,0 +1,22 @@ +extern crate semver; + +#[test] +fn test_regressions() { + use semver::VersionReq; + use semver::ReqParseError; + + let versions = vec![ + (".*", VersionReq::any()), + ("0.1.0.", VersionReq::parse("0.1.0").unwrap()), + ("0.3.1.3", VersionReq::parse("0.3.13").unwrap()), + ("0.2*", VersionReq::parse("0.2.*").unwrap()), + ("*.0", VersionReq::any()), + ]; + + for (version, requirement) in versions.into_iter() { + let parsed = VersionReq::parse(version); + let error = parsed.err().unwrap(); + + assert_eq!(ReqParseError::DeprecatedVersionRequirement(requirement), error); + } +} diff --git a/semver/tests/regression.rs b/semver/tests/regression.rs new file mode 100644 index 000000000..ef568a7d3 --- /dev/null +++ b/semver/tests/regression.rs @@ -0,0 +1,25 @@ +extern crate semver; +extern crate crates_index; +extern crate tempdir; + +// This test checks to see if every existing crate parses successfully. Important to not break the +// Rust universe! + +#[cfg(feature = "ci")] +#[test] +fn test_regressions() { + use tempdir::TempDir; + use crates_index::Index; + use semver::Version; + + let dir = TempDir::new("semver").unwrap(); + let index = Index::new(dir.into_path()); + index.clone().unwrap(); + + for krate in index.crates() { + for version in krate.versions() { + let v = version.version(); + assert!(Version::parse(v).is_ok(), "failed: {} ({})", version.name(), v); + } + } +} diff --git a/semver/tests/serde.rs b/semver/tests/serde.rs new file mode 100644 index 000000000..bcb92643c --- /dev/null +++ b/semver/tests/serde.rs @@ -0,0 +1,90 @@ +#![cfg(feature = "serde")] + +#[macro_use] +extern crate serde_derive; + +extern crate semver; +extern crate serde_json; + +use semver::{Identifier, Version, VersionReq}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct Identified { + name: String, + identifier: Identifier, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +struct Versioned { + name: String, + vers: Version, +} + +#[test] +fn serialize_identifier() { + let id = Identified { + name: "serde".to_owned(), + identifier: Identifier::Numeric(100), + }; + let j = serde_json::to_string(&id).unwrap(); + assert_eq!(j, r#"{"name":"serde","identifier":100}"#); + + let id = Identified { + name: "serde".to_owned(), + identifier: Identifier::AlphaNumeric("b100".to_owned()), + }; + let j = serde_json::to_string(&id).unwrap(); + assert_eq!(j, r#"{"name":"serde","identifier":"b100"}"#); +} + +#[test] +fn deserialize_identifier() { + let j = r#"{"name":"serde","identifier":100}"#; + let id = serde_json::from_str::<Identified>(j).unwrap(); + let expected = Identified { + name: "serde".to_owned(), + identifier: Identifier::Numeric(100), + }; + assert_eq!(id, expected); + + let j = r#"{"name":"serde","identifier":"b100"}"#; + let id = serde_json::from_str::<Identified>(j).unwrap(); + let expected = Identified { + name: "serde".to_owned(), + identifier: Identifier::AlphaNumeric("b100".to_owned()), + }; + assert_eq!(id, expected); +} + +#[test] +fn serialize_version() { + let v = Versioned { + name: "serde".to_owned(), + vers: Version::parse("1.0.0").unwrap(), + }; + let j = serde_json::to_string(&v).unwrap(); + assert_eq!(j, r#"{"name":"serde","vers":"1.0.0"}"#); +} + +#[test] +fn deserialize_version() { + let j = r#"{"name":"serde","vers":"1.0.0"}"#; + let v = serde_json::from_str::<Versioned>(j).unwrap(); + let expected = Versioned { + name: "serde".to_owned(), + vers: Version::parse("1.0.0").unwrap(), + }; + assert_eq!(v, expected); +} + +#[test] +fn serialize_versionreq() { + let v = VersionReq::exact(&Version::parse("1.0.0").unwrap()); + + assert_eq!(serde_json::to_string(&v).unwrap(), r#""= 1.0.0""#); +} + +#[test] +fn deserialize_versionreq() { + assert_eq!("1.0.0".parse::<VersionReq>().unwrap(), serde_json::from_str(r#""1.0.0""#).unwrap()); +} diff --git a/serde/.cargo-checksum.json b/serde/.cargo-checksum.json new file mode 100644 index 000000000..fbe567d05 --- /dev/null +++ b/serde/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd"} \ No newline at end of file diff --git a/serde/Cargo.toml b/serde/Cargo.toml new file mode 100644 index 000000000..612294d69 --- /dev/null +++ b/serde/Cargo.toml @@ -0,0 +1,46 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "serde" +version = "1.0.91" +authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] +build = "build.rs" +include = ["Cargo.toml", "build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +description = "A generic serialization/deserialization framework" +homepage = "https://serde.rs" +documentation = "https://docs.serde.rs/serde/" +readme = "crates-io.md" +keywords = ["serde", "serialization", "no_std"] +categories = ["encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/serde-rs/serde" +[package.metadata.playground] +features = ["derive", "rc"] +[dependencies.serde_derive] +version = "1.0" +optional = true +[dev-dependencies.serde_derive] +version = "1.0" + +[features] +alloc = ["unstable"] +default = ["std"] +derive = ["serde_derive"] +rc = [] +std = [] +unstable = [] +[badges.appveyor] +repository = "serde-rs/serde" + +[badges.travis-ci] +repository = "serde-rs/serde" diff --git a/serde/LICENSE-APACHE b/serde/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/serde/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/serde/LICENSE-MIT b/serde/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/serde/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/serde/README.md b/serde/README.md new file mode 100644 index 000000000..b2626db94 --- /dev/null +++ b/serde/README.md @@ -0,0 +1,99 @@ +# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc] + +[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master +[travis]: https://travis-ci.org/serde-rs/serde +[Latest Version]: https://img.shields.io/crates/v/serde.svg +[crates.io]: https://crates.io/crates/serde +[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg +[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Examples](https://serde.rs/examples.html) +- [API documentation](https://docs.serde.rs/serde/) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +<details> +<summary> +Click to show Cargo.toml. +<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a> +</summary> + +```toml +[dependencies] + +# The core APIs, including the Serialize and Deserialize traits. Always +# required when using Serde. The "derive" feature is only required when +# using #[derive(Serialize, Deserialize)] to make Serde work with structs +# and enums defined in your crate. +serde = { version = "1.0", features = ["derive"] } + +# Each data format lives in its own crate; the sample code below uses JSON +# but you may be using a different one. +serde_json = "1.0" +``` + +</details> +<p></p> + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The +\#rust channel is also a good resource with generally faster response time but +less specific knowledge about Serde. If IRC is not your thing or you don't get a +good response, we are happy to respond to [GitHub issues][issues] as well. + +[irc]: https://wiki.mozilla.org/IRC +[issues]: https://github.com/serde-rs/serde/issues/new/choose + +## License + +Serde is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/serde/build.rs b/serde/build.rs new file mode 100644 index 000000000..e27e2f34f --- /dev/null +++ b/serde/build.rs @@ -0,0 +1,100 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + let target = env::var("TARGET").unwrap(); + let emscripten = target == "asmjs-unknown-emscripten" || target == "wasm32-unknown-emscripten"; + + // std::collections::Bound was stabilized in Rust 1.17 + // but it was moved to core::ops later in Rust 1.26: + // https://doc.rust-lang.org/core/ops/enum.Bound.html + if minor >= 26 { + println!("cargo:rustc-cfg=ops_bound"); + } else if minor >= 17 && cfg!(feature = "std") { + println!("cargo:rustc-cfg=collections_bound"); + } + + // core::cmp::Reverse stabilized in Rust 1.19: + // https://doc.rust-lang.org/stable/core/cmp/struct.Reverse.html + if minor >= 19 { + println!("cargo:rustc-cfg=core_reverse"); + } + + // CString::into_boxed_c_str stabilized in Rust 1.20: + // https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str + if minor >= 20 { + println!("cargo:rustc-cfg=de_boxed_c_str"); + } + + // From<Box<T>> for Rc<T> / Arc<T> stabilized in Rust 1.21: + // https://doc.rust-lang.org/std/rc/struct.Rc.html#impl-From<Box<T>> + // https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-From<Box<T>> + if minor >= 21 { + println!("cargo:rustc-cfg=de_rc_dst"); + } + + // Duration available in core since Rust 1.25: + // https://blog.rust-lang.org/2018/03/29/Rust-1.25.html#library-stabilizations + if minor >= 25 { + println!("cargo:rustc-cfg=core_duration"); + } + + // 128-bit integers stabilized in Rust 1.26: + // https://blog.rust-lang.org/2018/05/10/Rust-1.26.html + // + // Disabled on Emscripten targets as Emscripten doesn't + // currently support integers larger than 64 bits. + if minor >= 26 && !emscripten { + println!("cargo:rustc-cfg=integer128"); + } + + // Inclusive ranges methods stabilized in Rust 1.27: + // https://github.com/rust-lang/rust/pull/50758 + if minor >= 27 { + println!("cargo:rustc-cfg=range_inclusive"); + } + + // Non-zero integers stabilized in Rust 1.28: + // https://github.com/rust-lang/rust/pull/50808 + if minor >= 28 { + println!("cargo:rustc-cfg=num_nonzero"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + u32::from_str(next).ok() +} diff --git a/serde/crates-io.md b/serde/crates-io.md new file mode 100644 index 000000000..3c6caa1a1 --- /dev/null +++ b/serde/crates-io.md @@ -0,0 +1,52 @@ +<!-- Serde readme rendered on crates.io --> + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Examples](https://serde.rs/examples.html) +- [API documentation](https://docs.serde.rs/serde/) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The +\#rust channel is also a good resource with generally faster response time but +less specific knowledge about Serde. If IRC is not your thing or you don't get a +good response, we are happy to respond to [GitHub issues][issues] as well. + +[irc]: https://wiki.mozilla.org/IRC +[issues]: https://github.com/serde-rs/serde/issues/new/choose diff --git a/serde/src/de/from_primitive.rs b/serde/src/de/from_primitive.rs new file mode 100644 index 000000000..544f3f1b8 --- /dev/null +++ b/serde/src/de/from_primitive.rs @@ -0,0 +1,260 @@ +use lib::*; + +macro_rules! int_to_int { + ($dst:ident, $n:ident) => { + if $dst::min_value() as i64 <= $n as i64 && $n as i64 <= $dst::max_value() as i64 { + Some($n as $dst) + } else { + None + } + }; +} + +macro_rules! int_to_uint { + ($dst:ident, $n:ident) => { + if 0 <= $n && $n as u64 <= $dst::max_value() as u64 { + Some($n as $dst) + } else { + None + } + }; +} + +macro_rules! uint_to { + ($dst:ident, $n:ident) => { + if $n as u64 <= $dst::max_value() as u64 { + Some($n as $dst) + } else { + None + } + }; +} + +pub trait FromPrimitive: Sized { + fn from_i8(n: i8) -> Option<Self>; + fn from_i16(n: i16) -> Option<Self>; + fn from_i32(n: i32) -> Option<Self>; + fn from_i64(n: i64) -> Option<Self>; + fn from_u8(n: u8) -> Option<Self>; + fn from_u16(n: u16) -> Option<Self>; + fn from_u32(n: u32) -> Option<Self>; + fn from_u64(n: u64) -> Option<Self>; +} + +macro_rules! impl_from_primitive_for_int { + ($t:ident) => { + impl FromPrimitive for $t { + #[inline] + fn from_i8(n: i8) -> Option<Self> { + int_to_int!($t, n) + } + #[inline] + fn from_i16(n: i16) -> Option<Self> { + int_to_int!($t, n) + } + #[inline] + fn from_i32(n: i32) -> Option<Self> { + int_to_int!($t, n) + } + #[inline] + fn from_i64(n: i64) -> Option<Self> { + int_to_int!($t, n) + } + #[inline] + fn from_u8(n: u8) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u16(n: u16) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u32(n: u32) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u64(n: u64) -> Option<Self> { + uint_to!($t, n) + } + } + }; +} + +macro_rules! impl_from_primitive_for_uint { + ($t:ident) => { + impl FromPrimitive for $t { + #[inline] + fn from_i8(n: i8) -> Option<Self> { + int_to_uint!($t, n) + } + #[inline] + fn from_i16(n: i16) -> Option<Self> { + int_to_uint!($t, n) + } + #[inline] + fn from_i32(n: i32) -> Option<Self> { + int_to_uint!($t, n) + } + #[inline] + fn from_i64(n: i64) -> Option<Self> { + int_to_uint!($t, n) + } + #[inline] + fn from_u8(n: u8) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u16(n: u16) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u32(n: u32) -> Option<Self> { + uint_to!($t, n) + } + #[inline] + fn from_u64(n: u64) -> Option<Self> { + uint_to!($t, n) + } + } + }; +} + +macro_rules! impl_from_primitive_for_float { + ($t:ident) => { + impl FromPrimitive for $t { + #[inline] + fn from_i8(n: i8) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_i16(n: i16) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_i32(n: i32) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_i64(n: i64) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_u8(n: u8) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_u16(n: u16) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_u32(n: u32) -> Option<Self> { + Some(n as Self) + } + #[inline] + fn from_u64(n: u64) -> Option<Self> { + Some(n as Self) + } + } + }; +} + +impl_from_primitive_for_int!(isize); +impl_from_primitive_for_int!(i8); +impl_from_primitive_for_int!(i16); +impl_from_primitive_for_int!(i32); +impl_from_primitive_for_int!(i64); +impl_from_primitive_for_uint!(usize); +impl_from_primitive_for_uint!(u8); +impl_from_primitive_for_uint!(u16); +impl_from_primitive_for_uint!(u32); +impl_from_primitive_for_uint!(u64); +impl_from_primitive_for_float!(f32); +impl_from_primitive_for_float!(f64); + +serde_if_integer128! { + impl FromPrimitive for i128 { + #[inline] + fn from_i8(n: i8) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_i16(n: i16) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_i32(n: i32) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_i64(n: i64) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_u8(n: u8) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_u16(n: u16) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_u32(n: u32) -> Option<Self> { + Some(n as i128) + } + #[inline] + fn from_u64(n: u64) -> Option<Self> { + Some(n as i128) + } + } + + impl FromPrimitive for u128 { + #[inline] + fn from_i8(n: i8) -> Option<Self> { + if n >= 0 { + Some(n as u128) + } else { + None + } + } + #[inline] + fn from_i16(n: i16) -> Option<Self> { + if n >= 0 { + Some(n as u128) + } else { + None + } + } + #[inline] + fn from_i32(n: i32) -> Option<Self> { + if n >= 0 { + Some(n as u128) + } else { + None + } + } + #[inline] + fn from_i64(n: i64) -> Option<Self> { + if n >= 0 { + Some(n as u128) + } else { + None + } + } + #[inline] + fn from_u8(n: u8) -> Option<Self> { + Some(n as u128) + } + #[inline] + fn from_u16(n: u16) -> Option<Self> { + Some(n as u128) + } + #[inline] + fn from_u32(n: u32) -> Option<Self> { + Some(n as u128) + } + #[inline] + fn from_u64(n: u64) -> Option<Self> { + Some(n as u128) + } + } +} diff --git a/serde/src/de/ignored_any.rs b/serde/src/de/ignored_any.rs new file mode 100644 index 000000000..855d68e1a --- /dev/null +++ b/serde/src/de/ignored_any.rs @@ -0,0 +1,218 @@ +use lib::*; + +use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + +/// An efficient way of discarding data from a deserializer. +/// +/// Think of this like `serde_json::Value` in that it can be deserialized from +/// any type, except that it does not store any information about the data that +/// gets deserialized. +/// +/// ```edition2018 +/// use std::fmt; +/// use std::marker::PhantomData; +/// +/// use serde::de::{ +/// self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, SeqAccess, Visitor, +/// }; +/// +/// /// A seed that can be used to deserialize only the `n`th element of a sequence +/// /// while efficiently discarding elements of any type before or after index `n`. +/// /// +/// /// For example to deserialize only the element at index 3: +/// /// +/// /// ``` +/// /// NthElement::new(3).deserialize(deserializer) +/// /// ``` +/// pub struct NthElement<T> { +/// n: usize, +/// marker: PhantomData<T>, +/// } +/// +/// impl<T> NthElement<T> { +/// pub fn new(n: usize) -> Self { +/// NthElement { +/// n: n, +/// marker: PhantomData, +/// } +/// } +/// } +/// +/// impl<'de, T> Visitor<'de> for NthElement<T> +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!( +/// formatter, +/// "a sequence in which we care about element {}", +/// self.n +/// ) +/// } +/// +/// fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> +/// where +/// A: SeqAccess<'de>, +/// { +/// // Skip over the first `n` elements. +/// for i in 0..self.n { +/// // It is an error if the sequence ends before we get to element `n`. +/// if seq.next_element::<IgnoredAny>()?.is_none() { +/// return Err(de::Error::invalid_length(i, &self)); +/// } +/// } +/// +/// // Deserialize the one we care about. +/// let nth = match seq.next_element()? { +/// Some(nth) => nth, +/// None => { +/// return Err(de::Error::invalid_length(self.n, &self)); +/// } +/// }; +/// +/// // Skip over any remaining elements in the sequence after `n`. +/// while let Some(IgnoredAny) = seq.next_element()? { +/// // ignore +/// } +/// +/// Ok(nth) +/// } +/// } +/// +/// impl<'de, T> DeserializeSeed<'de> for NthElement<T> +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = T; +/// +/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> +/// where +/// D: Deserializer<'de>, +/// { +/// deserializer.deserialize_seq(self) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// // Deserialize only the sequence element at index 3 from this deserializer. +/// // The element at index 3 is required to be a string. Elements before and +/// // after index 3 are allowed to be of any type. +/// let s: String = NthElement::new(3).deserialize(deserializer)?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Copy, Clone, Debug, Default)] +pub struct IgnoredAny; + +impl<'de> Visitor<'de> for IgnoredAny { + type Value = IgnoredAny; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("anything at all") + } + + #[inline] + fn visit_bool<E>(self, x: bool) -> Result<Self::Value, E> { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_i64<E>(self, x: i64) -> Result<Self::Value, E> { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_u64<E>(self, x: u64) -> Result<Self::Value, E> { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_f64<E>(self, x: f64) -> Result<Self::Value, E> { + let _ = x; + Ok(IgnoredAny) + } + + #[inline] + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + let _ = s; + Ok(IgnoredAny) + } + + #[inline] + fn visit_none<E>(self) -> Result<Self::Value, E> { + Ok(IgnoredAny) + } + + #[inline] + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + IgnoredAny::deserialize(deserializer) + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> { + Ok(IgnoredAny) + } + + #[inline] + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + while let Some(IgnoredAny) = try!(seq.next_element()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + while let Some((IgnoredAny, IgnoredAny)) = try!(map.next_entry()) { + // Gobble + } + Ok(IgnoredAny) + } + + #[inline] + fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + let _ = bytes; + Ok(IgnoredAny) + } +} + +impl<'de> Deserialize<'de> for IgnoredAny { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<IgnoredAny, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_ignored_any(IgnoredAny) + } +} diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs new file mode 100644 index 000000000..1c18fd969 --- /dev/null +++ b/serde/src/de/impls.rs @@ -0,0 +1,2547 @@ +use lib::*; + +use de::{ + Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess, Visitor, +}; + +#[cfg(any(core_duration, feature = "std", feature = "alloc"))] +use de::MapAccess; + +use de::from_primitive::FromPrimitive; +use private::de::InPlaceSeed; + +#[cfg(any(feature = "std", feature = "alloc"))] +use private::de::size_hint; + +//////////////////////////////////////////////////////////////////////////////// + +struct UnitVisitor; + +impl<'de> Visitor<'de> for UnitVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Ok(()) + } +} + +impl<'de> Deserialize<'de> for () { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_unit(UnitVisitor) + } +} + +#[cfg(feature = "unstable")] +impl<'de> Deserialize<'de> for ! { + fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Err(Error::custom("cannot deserialize `!`")) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BoolVisitor; + +impl<'de> Visitor<'de> for BoolVisitor { + type Value = bool; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a boolean") + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } +} + +impl<'de> Deserialize<'de> for bool { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_bool(BoolVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! visit_integer_method { + ($src_ty:ident, $method:ident, $from_method:ident, $group:ident, $group_ty:ident) => { + #[inline] + fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E> + where + E: Error, + { + match FromPrimitive::$from_method(v) { + Some(v) => Ok(v), + None => Err(Error::invalid_value(Unexpected::$group(v as $group_ty), &self)), + } + } + } +} + +macro_rules! visit_float_method { + ($src_ty:ident, $method:ident) => { + #[inline] + fn $method<E>(self, v: $src_ty) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v as Self::Value) + } + } +} + +macro_rules! impl_deserialize_num { + ($ty:ident, $method:ident, $($visit:ident),*) => { + impl<'de> Deserialize<'de> for $ty { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct PrimitiveVisitor; + + impl<'de> Visitor<'de> for PrimitiveVisitor { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(stringify!($ty)) + } + + $( + impl_deserialize_num!($visit $ty); + )* + } + + deserializer.$method(PrimitiveVisitor) + } + } + }; + + (integer $ty:ident) => { + visit_integer_method!(i8, visit_i8, from_i8, Signed, i64); + visit_integer_method!(i16, visit_i16, from_i16, Signed, i64); + visit_integer_method!(i32, visit_i32, from_i32, Signed, i64); + visit_integer_method!(i64, visit_i64, from_i64, Signed, i64); + + visit_integer_method!(u8, visit_u8, from_u8, Unsigned, u64); + visit_integer_method!(u16, visit_u16, from_u16, Unsigned, u64); + visit_integer_method!(u32, visit_u32, from_u32, Unsigned, u64); + visit_integer_method!(u64, visit_u64, from_u64, Unsigned, u64); + }; + + (float $ty:ident) => { + visit_float_method!(f32, visit_f32); + visit_float_method!(f64, visit_f64); + }; +} + +impl_deserialize_num!(i8, deserialize_i8, integer); +impl_deserialize_num!(i16, deserialize_i16, integer); +impl_deserialize_num!(i32, deserialize_i32, integer); +impl_deserialize_num!(i64, deserialize_i64, integer); +impl_deserialize_num!(isize, deserialize_i64, integer); + +impl_deserialize_num!(u8, deserialize_u8, integer); +impl_deserialize_num!(u16, deserialize_u16, integer); +impl_deserialize_num!(u32, deserialize_u32, integer); +impl_deserialize_num!(u64, deserialize_u64, integer); +impl_deserialize_num!(usize, deserialize_u64, integer); + +impl_deserialize_num!(f32, deserialize_f32, integer, float); +impl_deserialize_num!(f64, deserialize_f64, integer, float); + +serde_if_integer128! { + impl<'de> Deserialize<'de> for i128 { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct PrimitiveVisitor; + + impl<'de> Visitor<'de> for PrimitiveVisitor { + type Value = i128; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("i128") + } + + impl_deserialize_num!(integer i128); + + #[inline] + fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } + + #[inline] + fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E> + where + E: Error, + { + if v <= i128::max_value() as u128 { + Ok(v as i128) + } else { + Err(Error::invalid_value(Unexpected::Other("u128"), &self)) + } + } + } + + deserializer.deserialize_i128(PrimitiveVisitor) + } + } + + impl<'de> Deserialize<'de> for u128 { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct PrimitiveVisitor; + + impl<'de> Visitor<'de> for PrimitiveVisitor { + type Value = u128; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("u128") + } + + impl_deserialize_num!(integer u128); + + #[inline] + fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E> + where + E: Error, + { + if v >= 0 { + Ok(v as u128) + } else { + Err(Error::invalid_value(Unexpected::Other("i128"), &self)) + } + } + + #[inline] + fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } + } + + deserializer.deserialize_u128(PrimitiveVisitor) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct CharVisitor; + +impl<'de> Visitor<'de> for CharVisitor { + type Value = char; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a character") + } + + #[inline] + fn visit_char<E>(self, v: char) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } + + #[inline] + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + let mut iter = v.chars(); + match (iter.next(), iter.next()) { + (Some(c), None) => Ok(c), + _ => Err(Error::invalid_value(Unexpected::Str(v), &self)), + } + } +} + +impl<'de> Deserialize<'de> for char { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_char(CharVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringVisitor; +#[cfg(any(feature = "std", feature = "alloc"))] +struct StringInPlaceVisitor<'a>(&'a mut String); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de> Visitor<'de> for StringVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v.to_owned()) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(s.to_owned()), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(s), + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de> Visitor<'de> for StringInPlaceVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + self.0.clear(); + self.0.push_str(v); + Ok(()) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + *self.0 = v; + Ok(()) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => { + self.0.clear(); + self.0.push_str(s); + Ok(()) + } + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => { + *self.0 = s; + Ok(()) + } + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de> Deserialize<'de> for String { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor) + } + + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(StringInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct StrVisitor; + +impl<'a> Visitor<'a> for StrVisitor { + type Value = &'a str; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed string") + } + + fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) // so easy + } + + fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E> + where + E: Error, + { + str::from_utf8(v).map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a str { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(StrVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct BytesVisitor; + +impl<'a> Visitor<'a> for BytesVisitor { + type Value = &'a [u8]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed byte array") + } + + fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v) + } + + fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v.as_bytes()) + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a [u8] { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +struct CStringVisitor; + +#[cfg(feature = "std")] +impl<'de> Visitor<'de> for CStringVisitor { + type Value = CString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("byte array") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let len = size_hint::cautious(seq.size_hint()); + let mut values = Vec::with_capacity(len); + + while let Some(value) = try!(seq.next_element()) { + values.push(value); + } + + CString::new(values).map_err(Error::custom) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + CString::new(v).map_err(Error::custom) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for CString { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_byte_buf(CStringVisitor) + } +} + +macro_rules! forwarded_impl { + ( + $(#[doc = $doc:tt])* + ( $($id: ident),* ), $ty: ty, $func: expr + ) => { + $(#[doc = $doc])* + impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map($func) + } + } + } +} + +#[cfg(all(feature = "std", de_boxed_c_str))] +forwarded_impl!((), Box<CStr>, CString::into_boxed_c_str); + +#[cfg(core_reverse)] +forwarded_impl!((T), Reverse<T>, Reverse); + +//////////////////////////////////////////////////////////////////////////////// + +struct OptionVisitor<T> { + marker: PhantomData<T>, +} + +impl<'de, T> Visitor<'de> for OptionVisitor<T> +where + T: Deserialize<'de>, +{ + type Value = Option<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_none<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Ok(None) + } + + #[inline] + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Some) + } + + #[doc(hidden)] + fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()> + where + D: Deserializer<'de>, + { + Ok(T::deserialize(deserializer).ok()) + } +} + +impl<'de, T> Deserialize<'de> for Option<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_option(OptionVisitor { + marker: PhantomData, + }) + } + + // The Some variant's repr is opaque, so we can't play cute tricks with its + // tag to have deserialize_in_place build the content in place unconditionally. + // + // FIXME: investigate whether branching on the old value being Some to + // deserialize_in_place the value is profitable (probably data-dependent?) +} + +//////////////////////////////////////////////////////////////////////////////// + +struct PhantomDataVisitor<T: ?Sized> { + marker: PhantomData<T>, +} + +impl<'de, T: ?Sized> Visitor<'de> for PhantomDataVisitor<T> { + type Value = PhantomData<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("unit") + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Ok(PhantomData) + } +} + +impl<'de, T: ?Sized> Deserialize<'de> for PhantomData<T> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let visitor = PhantomDataVisitor { + marker: PhantomData, + }; + deserializer.deserialize_unit_struct("PhantomData", visitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! seq_impl { + ( + $ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, + $access:ident, + $clear:expr, + $with_capacity:expr, + $reserve:expr, + $insert:expr + ) => { + impl<'de, T $(, $typaram)*> Deserialize<'de> for $ty<T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct SeqVisitor<T $(, $typaram)*> { + marker: PhantomData<$ty<T $(, $typaram)*>>, + } + + impl<'de, T $(, $typaram)*> Visitor<'de> for SeqVisitor<T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = $ty<T $(, $typaram)*>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq<A>(self, mut $access: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let mut values = $with_capacity; + + while let Some(value) = try!($access.next_element()) { + $insert(&mut values, value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { marker: PhantomData }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T: 'a $(, $typaram: 'a)*>(&'a mut $ty<T $(, $typaram)*>); + + impl<'a, 'de, T $(, $typaram)*> Visitor<'de> for SeqInPlaceVisitor<'a, T $(, $typaram)*> + where + T: Deserialize<'de> $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*,)* + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[inline] + fn visit_seq<A>(mut self, mut $access: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + $clear(&mut self.0); + $reserve(&mut self.0, size_hint::cautious($access.size_hint())); + + // FIXME: try to overwrite old values here? (Vec, VecDeque, LinkedList) + while let Some(value) = try!($access.next_element()) { + $insert(&mut self.0, value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } + } +} + +// Dummy impl of reserve +#[cfg(any(feature = "std", feature = "alloc"))] +fn nop_reserve<T>(_seq: T, _n: usize) {} + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!( + BinaryHeap<T: Ord>, + seq, + BinaryHeap::clear, + BinaryHeap::with_capacity(size_hint::cautious(seq.size_hint())), + BinaryHeap::reserve, + BinaryHeap::push); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!( + BTreeSet<T: Eq + Ord>, + seq, + BTreeSet::clear, + BTreeSet::new(), + nop_reserve, + BTreeSet::insert); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!( + LinkedList<T>, + seq, + LinkedList::clear, + LinkedList::new(), + nop_reserve, + LinkedList::push_back +); + +#[cfg(feature = "std")] +seq_impl!( + HashSet<T: Eq + Hash, S: BuildHasher + Default>, + seq, + HashSet::clear, + HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), + HashSet::reserve, + HashSet::insert); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!( + VecDeque<T>, + seq, + VecDeque::clear, + VecDeque::with_capacity(size_hint::cautious(seq.size_hint())), + VecDeque::reserve, + VecDeque::push_back +); + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, T> Deserialize<'de> for Vec<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct VecVisitor<T> { + marker: PhantomData<T>, + } + + impl<'de, T> Visitor<'de> for VecVisitor<T> + where + T: Deserialize<'de>, + { + type Value = Vec<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let mut values = Vec::with_capacity(size_hint::cautious(seq.size_hint())); + + while let Some(value) = try!(seq.next_element()) { + values.push(value); + } + + Ok(values) + } + } + + let visitor = VecVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct VecInPlaceVisitor<'a, T: 'a>(&'a mut Vec<T>); + + impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let hint = size_hint::cautious(seq.size_hint()); + if let Some(additional) = hint.checked_sub(self.0.len()) { + self.0.reserve(additional); + } + + for i in 0..self.0.len() { + let next = { + let next_place = InPlaceSeed(&mut self.0[i]); + try!(seq.next_element_seed(next_place)) + }; + if next.is_none() { + self.0.truncate(i); + return Ok(()); + } + } + + while let Some(value) = try!(seq.next_element()) { + self.0.push(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(VecInPlaceVisitor(place)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +struct ArrayVisitor<A> { + marker: PhantomData<A>, +} +struct ArrayInPlaceVisitor<'a, A: 'a>(&'a mut A); + +impl<A> ArrayVisitor<A> { + fn new() -> Self { + ArrayVisitor { + marker: PhantomData, + } + } +} + +impl<'de, T> Visitor<'de> for ArrayVisitor<[T; 0]> { + type Value = [T; 0]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an empty array") + } + + #[inline] + fn visit_seq<A>(self, _: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + Ok([]) + } +} + +// Does not require T: Deserialize<'de>. +impl<'de, T> Deserialize<'de> for [T; 0] { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(0, ArrayVisitor::<[T; 0]>::new()) + } +} + +macro_rules! array_impls { + ($($len:expr => ($($n:tt $name:ident)+))+) => { + $( + impl<'de, T> Visitor<'de> for ArrayVisitor<[T; $len]> + where + T: Deserialize<'de>, + { + type Value = [T; $len]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + $( + let $name = match try!(seq.next_element()) { + Some(val) => val, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ + + Ok([$($name),+]) + } + } + + impl<'a, 'de, T> Visitor<'de> for ArrayInPlaceVisitor<'a, [T; $len]> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("an array of length ", $len)) + } + + #[inline] + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let mut fail_idx = None; + for (idx, dest) in self.0[..].iter_mut().enumerate() { + if try!(seq.next_element_seed(InPlaceSeed(dest))).is_none() { + fail_idx = Some(idx); + break; + } + } + if let Some(idx) = fail_idx { + return Err(Error::invalid_length(idx, &self)); + } + Ok(()) + } + } + + impl<'de, T> Deserialize<'de> for [T; $len] + where + T: Deserialize<'de>, + { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayVisitor::<[T; $len]>::new()) + } + + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple($len, ArrayInPlaceVisitor(place)) + } + } + )+ + } +} + +array_impls! { + 1 => (0 a) + 2 => (0 a 1 b) + 3 => (0 a 1 b 2 c) + 4 => (0 a 1 b 2 c 3 d) + 5 => (0 a 1 b 2 c 3 d 4 e) + 6 => (0 a 1 b 2 c 3 d 4 e 5 f) + 7 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g) + 8 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h) + 9 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i) + 10 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j) + 11 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k) + 12 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l) + 13 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m) + 14 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n) + 15 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o) + 16 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p) + 17 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q) + 18 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r) + 19 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s) + 20 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t) + 21 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u) + 22 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v) + 23 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w) + 24 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x) + 25 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y) + 26 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z) + 27 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa) + 28 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab) + 29 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac) + 30 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad) + 31 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae) + 32 => (0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26 aa 27 ab 28 ac 29 ad 30 ae 31 af) +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:tt => ($($n:tt $name:ident)+))+) => { + $( + impl<'de, $($name: Deserialize<'de>),+> Deserialize<'de> for ($($name,)+) { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct TupleVisitor<$($name,)+> { + marker: PhantomData<($($name,)+)>, + } + + impl<'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleVisitor<$($name,)+> { + type Value = ($($name,)+); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } + + #[inline] + #[allow(non_snake_case)] + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + $( + let $name = match try!(seq.next_element()) { + Some(value) => value, + None => return Err(Error::invalid_length($n, &self)), + }; + )+ + + Ok(($($name,)+)) + } + } + + deserializer.deserialize_tuple($len, TupleVisitor { marker: PhantomData }) + } + + #[inline] + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct TupleInPlaceVisitor<'a, $($name: 'a,)+>(&'a mut ($($name,)+)); + + impl<'a, 'de, $($name: Deserialize<'de>),+> Visitor<'de> for TupleInPlaceVisitor<'a, $($name,)+> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a tuple of size ", $len)) + } + + #[inline] + #[allow(non_snake_case)] + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + $( + if try!(seq.next_element_seed(InPlaceSeed(&mut (self.0).$n))).is_none() { + return Err(Error::invalid_length($n, &self)); + } + )+ + + Ok(()) + } + } + + deserializer.deserialize_tuple($len, TupleInPlaceVisitor(place)) + } + } + )+ + } +} + +tuple_impls! { + 1 => (0 T0) + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! map_impl { + ( + $ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, + $access:ident, + $with_capacity:expr + ) => { + impl<'de, K, V $(, $typaram)*> Deserialize<'de> for $ty<K, V $(, $typaram)*> + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct MapVisitor<K, V $(, $typaram)*> { + marker: PhantomData<$ty<K, V $(, $typaram)*>>, + } + + impl<'de, K, V $(, $typaram)*> Visitor<'de> for MapVisitor<K, V $(, $typaram)*> + where + K: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + V: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Value = $ty<K, V $(, $typaram)*>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + #[inline] + fn visit_map<A>(self, mut $access: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let mut values = $with_capacity; + + while let Some((key, value)) = try!($access.next_entry()) { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { marker: PhantomData }; + deserializer.deserialize_map(visitor) + } + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +map_impl!( + BTreeMap<K: Ord, V>, + map, + BTreeMap::new()); + +#[cfg(feature = "std")] +map_impl!( + HashMap<K: Eq + Hash, V, S: BuildHasher + Default>, + map, + HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())); + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +macro_rules! parse_ip_impl { + ($expecting:tt $ty:ty; $size:tt) => { + impl<'de> Deserialize<'de> for $ty { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + struct IpAddrVisitor; + + impl<'de> Visitor<'de> for IpAddrVisitor { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str($expecting) + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(IpAddrVisitor) + } else { + <[u8; $size]>::deserialize(deserializer).map(<$ty>::from) + } + } + } + }; +} + +#[cfg(feature = "std")] +macro_rules! variant_identifier { + ( + $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) + $expecting_message: expr, + $variants_name: ident + ) => { + enum $name_kind { + $( $variant ),* + } + + static $variants_name: &'static [&'static str] = &[ $( stringify!($variant) ),*]; + + impl<'de> Deserialize<'de> for $name_kind { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct KindVisitor; + + impl<'de> Visitor<'de> for KindVisitor { + type Value = $name_kind; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str($expecting_message) + } + + fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> + where + E: Error, + { + match value { + $( + $index => Ok($name_kind :: $variant), + )* + _ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),), + } + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + $( + stringify!($variant) => Ok($name_kind :: $variant), + )* + _ => Err(Error::unknown_variant(value, $variants_name)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + $( + $bytes => Ok($name_kind :: $variant), + )* + _ => { + match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, $variants_name)), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(value), &self)), + } + } + } + } + } + + deserializer.deserialize_identifier(KindVisitor) + } + } + } +} + +#[cfg(feature = "std")] +macro_rules! deserialize_enum { + ( + $name: ident $name_kind: ident ( $($variant: ident; $bytes: expr; $index: expr),* ) + $expecting_message: expr, + $deserializer: expr + ) => { + variant_identifier!{ + $name_kind ( $($variant; $bytes; $index),* ) + $expecting_message, + VARIANTS + } + + struct EnumVisitor; + impl<'de> Visitor<'de> for EnumVisitor { + type Value = $name; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(concat!("a ", stringify!($name))) + } + + + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + match try!(data.variant()) { + $( + ($name_kind :: $variant, v) => v.newtype_variant().map($name :: $variant), + )* + } + } + } + $deserializer.deserialize_enum(stringify!($name), VARIANTS, EnumVisitor) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for net::IpAddr { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + struct IpAddrVisitor; + + impl<'de> Visitor<'de> for IpAddrVisitor { + type Value = net::IpAddr; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("IP address") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(IpAddrVisitor) + } else { + use lib::net::IpAddr; + deserialize_enum! { + IpAddr IpAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(feature = "std")] +parse_ip_impl!("IPv4 address" net::Ipv4Addr; 4); + +#[cfg(feature = "std")] +parse_ip_impl!("IPv6 address" net::Ipv6Addr; 16); + +#[cfg(feature = "std")] +macro_rules! parse_socket_impl { + ($expecting:tt $ty:ty, $new:expr) => { + impl<'de> Deserialize<'de> for $ty { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + struct SocketAddrVisitor; + + impl<'de> Visitor<'de> for SocketAddrVisitor { + type Value = $ty; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str($expecting) + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(SocketAddrVisitor) + } else { + <(_, u16)>::deserialize(deserializer).map(|(ip, port)| $new(ip, port)) + } + } + } + }; +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for net::SocketAddr { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + if deserializer.is_human_readable() { + struct SocketAddrVisitor; + + impl<'de> Visitor<'de> for SocketAddrVisitor { + type Value = net::SocketAddr; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("socket address") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: Error, + { + s.parse().map_err(Error::custom) + } + } + + deserializer.deserialize_str(SocketAddrVisitor) + } else { + use lib::net::SocketAddr; + deserialize_enum! { + SocketAddr SocketAddrKind (V4; b"V4"; 0, V6; b"V6"; 1) + "`V4` or `V6`", + deserializer + } + } + } +} + +#[cfg(feature = "std")] +parse_socket_impl!("IPv4 socket address" net::SocketAddrV4, net::SocketAddrV4::new); + +#[cfg(feature = "std")] +parse_socket_impl!("IPv6 socket address" net::SocketAddrV6, |ip, port| net::SocketAddrV6::new( + ip, port, 0, 0 +)); + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +struct PathVisitor; + +#[cfg(feature = "std")] +impl<'a> Visitor<'a> for PathVisitor { + type Value = &'a Path; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a borrowed path") + } + + fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(v.as_ref()) + } + + fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E> + where + E: Error, + { + str::from_utf8(v) + .map(AsRef::as_ref) + .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self)) + } +} + +#[cfg(feature = "std")] +impl<'de: 'a, 'a> Deserialize<'de> for &'a Path { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(PathVisitor) + } +} + +#[cfg(feature = "std")] +struct PathBufVisitor; + +#[cfg(feature = "std")] +impl<'de> Visitor<'de> for PathBufVisitor { + type Value = PathBuf; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("path string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(From::from(v)) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + Ok(From::from(v)) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for PathBuf { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(PathBufVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// If this were outside of the serde crate, it would just use: +// +// #[derive(Deserialize)] +// #[serde(variant_identifier)] +#[cfg(all(feature = "std", any(unix, windows)))] +variant_identifier! { + OsStringKind (Unix; b"Unix"; 0, Windows; b"Windows"; 1) + "`Unix` or `Windows`", + OSSTR_VARIANTS +} + +#[cfg(all(feature = "std", any(unix, windows)))] +struct OsStringVisitor; + +#[cfg(all(feature = "std", any(unix, windows)))] +impl<'de> Visitor<'de> for OsStringVisitor { + type Value = OsString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("os string") + } + + #[cfg(unix)] + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + use std::os::unix::ffi::OsStringExt; + + match try!(data.variant()) { + (OsStringKind::Unix, v) => v.newtype_variant().map(OsString::from_vec), + (OsStringKind::Windows, _) => Err(Error::custom( + "cannot deserialize Windows OS string on Unix", + )), + } + } + + #[cfg(windows)] + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + use std::os::windows::ffi::OsStringExt; + + match try!(data.variant()) { + (OsStringKind::Windows, v) => v + .newtype_variant::<Vec<u16>>() + .map(|vec| OsString::from_wide(&vec)), + (OsStringKind::Unix, _) => Err(Error::custom( + "cannot deserialize Unix OS string on Windows", + )), + } + } +} + +#[cfg(all(feature = "std", any(unix, windows)))] +impl<'de> Deserialize<'de> for OsString { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_enum("OsString", OSSTR_VARIANTS, OsStringVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +forwarded_impl!((T), Box<T>, Box::new); + +#[cfg(any(feature = "std", feature = "alloc"))] +forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice); + +#[cfg(any(feature = "std", feature = "alloc"))] +forwarded_impl!((), Box<str>, String::into_boxed_str); + +#[cfg(all( + not(de_rc_dst), + feature = "rc", + any(feature = "std", feature = "alloc") +))] +forwarded_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Deserializing a data structure containing `Arc` will not attempt to + /// deduplicate `Arc` references to the same data. Every deserialized `Arc` + /// will end up with a strong count of 1. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + (T), Arc<T>, Arc::new +} + +#[cfg(all( + not(de_rc_dst), + feature = "rc", + any(feature = "std", feature = "alloc") +))] +forwarded_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Deserializing a data structure containing `Rc` will not attempt to + /// deduplicate `Rc` references to the same data. Every deserialized `Rc` + /// will end up with a strong count of 1. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + (T), Rc<T>, Rc::new +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> +where + T: ToOwned, + T::Owned: Deserialize<'de>, +{ + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + T::Owned::deserialize(deserializer).map(Cow::Owned) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak<T>` has a reference count of 0 and cannot be upgraded. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<'de, T: ?Sized> Deserialize<'de> for RcWeak<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + try!(Option::<T>::deserialize(deserializer)); + Ok(RcWeak::new()) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak<T>` has a reference count of 0 and cannot be upgraded. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<'de, T: ?Sized> Deserialize<'de> for ArcWeak<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + try!(Option::<T>::deserialize(deserializer)); + Ok(ArcWeak::new()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] +macro_rules! box_forwarded_impl { + ( + $(#[doc = $doc:tt])* + $t:ident + ) => { + $(#[doc = $doc])* + impl<'de, T: ?Sized> Deserialize<'de> for $t<T> + where + Box<T>: Deserialize<'de>, + { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Box::deserialize(deserializer).map(Into::into) + } + } + }; +} + +#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] +box_forwarded_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Deserializing a data structure containing `Rc` will not attempt to + /// deduplicate `Rc` references to the same data. Every deserialized `Rc` + /// will end up with a strong count of 1. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + Rc +} + +#[cfg(all(de_rc_dst, feature = "rc", any(feature = "std", feature = "alloc")))] +box_forwarded_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Deserializing a data structure containing `Arc` will not attempt to + /// deduplicate `Arc` references to the same data. Every deserialized `Arc` + /// will end up with a strong count of 1. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + Arc +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T> Deserialize<'de> for Cell<T> +where + T: Deserialize<'de> + Copy, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + T::deserialize(deserializer).map(Cell::new) + } +} + +forwarded_impl!((T), RefCell<T>, RefCell::new); + +#[cfg(feature = "std")] +forwarded_impl!((T), Mutex<T>, Mutex::new); + +#[cfg(feature = "std")] +forwarded_impl!((T), RwLock<T>, RwLock::new); + +//////////////////////////////////////////////////////////////////////////////// + +// This is a cleaned-up version of the impl generated by: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Duration { +// secs: u64, +// nanos: u32, +// } +#[cfg(any(core_duration, feature = "std"))] +impl<'de> Deserialize<'de> for Duration { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Secs, + Nanos, + }; + + impl<'de> Deserialize<'de> for Field { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`secs` or `nanos`") + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + "secs" => Ok(Field::Secs), + "nanos" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + b"secs" => Ok(Field::Secs), + b"nanos" => Ok(Field::Nanos), + _ => { + let value = ::export::from_utf8_lossy(value); + Err(Error::unknown_field(&value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct DurationVisitor; + + impl<'de> Visitor<'de> for DurationVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Duration") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let secs: u64 = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + let nanos: u32 = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(1, &self)); + } + }; + Ok(Duration::new(secs, nanos)) + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let mut secs: Option<u64> = None; + let mut nanos: Option<u32> = None; + while let Some(key) = try!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(<A::Error as Error>::duplicate_field("secs")); + } + secs = Some(try!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(<A::Error as Error>::duplicate_field("nanos")); + } + nanos = Some(try!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(<A::Error as Error>::missing_field("secs")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(<A::Error as Error>::missing_field("nanos")), + }; + Ok(Duration::new(secs, nanos)) + } + } + + const FIELDS: &'static [&'static str] = &["secs", "nanos"]; + deserializer.deserialize_struct("Duration", FIELDS, DurationVisitor) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for SystemTime { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + // Reuse duration + enum Field { + Secs, + Nanos, + }; + + impl<'de> Deserialize<'de> for Field { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`secs_since_epoch` or `nanos_since_epoch`") + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + "secs_since_epoch" => Ok(Field::Secs), + "nanos_since_epoch" => Ok(Field::Nanos), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + b"secs_since_epoch" => Ok(Field::Secs), + b"nanos_since_epoch" => Ok(Field::Nanos), + _ => { + let value = String::from_utf8_lossy(value); + Err(Error::unknown_field(&value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct DurationVisitor; + + impl<'de> Visitor<'de> for DurationVisitor { + type Value = Duration; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SystemTime") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let secs: u64 = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + let nanos: u32 = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(1, &self)); + } + }; + Ok(Duration::new(secs, nanos)) + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let mut secs: Option<u64> = None; + let mut nanos: Option<u32> = None; + while let Some(key) = try!(map.next_key()) { + match key { + Field::Secs => { + if secs.is_some() { + return Err(<A::Error as Error>::duplicate_field( + "secs_since_epoch", + )); + } + secs = Some(try!(map.next_value())); + } + Field::Nanos => { + if nanos.is_some() { + return Err(<A::Error as Error>::duplicate_field( + "nanos_since_epoch", + )); + } + nanos = Some(try!(map.next_value())); + } + } + } + let secs = match secs { + Some(secs) => secs, + None => return Err(<A::Error as Error>::missing_field("secs_since_epoch")), + }; + let nanos = match nanos { + Some(nanos) => nanos, + None => return Err(<A::Error as Error>::missing_field("nanos_since_epoch")), + }; + Ok(Duration::new(secs, nanos)) + } + } + + const FIELDS: &'static [&'static str] = &["secs_since_epoch", "nanos_since_epoch"]; + let duration = try!(deserializer.deserialize_struct("SystemTime", FIELDS, DurationVisitor)); + Ok(UNIX_EPOCH + duration) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Similar to: +// +// #[derive(Deserialize)] +// #[serde(deny_unknown_fields)] +// struct Range { +// start: u64, +// end: u32, +// } +impl<'de, Idx> Deserialize<'de> for Range<Idx> +where + Idx: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let (start, end) = deserializer.deserialize_struct( + "Range", + range::FIELDS, + range::RangeVisitor { + expecting: "struct Range", + phantom: PhantomData, + }, + )?; + Ok(start..end) + } +} + +#[cfg(range_inclusive)] +impl<'de, Idx> Deserialize<'de> for RangeInclusive<Idx> +where + Idx: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let (start, end) = deserializer.deserialize_struct( + "RangeInclusive", + range::FIELDS, + range::RangeVisitor { + expecting: "struct RangeInclusive", + phantom: PhantomData, + }, + )?; + Ok(RangeInclusive::new(start, end)) + } +} + +mod range { + use lib::*; + + use de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; + + pub const FIELDS: &'static [&'static str] = &["start", "end"]; + + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Start, + End, + } + + impl<'de> Deserialize<'de> for Field { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`start` or `end`") + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + "start" => Ok(Field::Start), + "end" => Ok(Field::End), + _ => Err(Error::unknown_field(value, FIELDS)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + b"start" => Ok(Field::Start), + b"end" => Ok(Field::End), + _ => { + let value = ::export::from_utf8_lossy(value); + Err(Error::unknown_field(&value, FIELDS)) + } + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + pub struct RangeVisitor<Idx> { + pub expecting: &'static str, + pub phantom: PhantomData<Idx>, + } + + impl<'de, Idx> Visitor<'de> for RangeVisitor<Idx> + where + Idx: Deserialize<'de>, + { + type Value = (Idx, Idx); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self.expecting) + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let start: Idx = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(0, &self)); + } + }; + let end: Idx = match try!(seq.next_element()) { + Some(value) => value, + None => { + return Err(Error::invalid_length(1, &self)); + } + }; + Ok((start, end)) + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let mut start: Option<Idx> = None; + let mut end: Option<Idx> = None; + while let Some(key) = try!(map.next_key()) { + match key { + Field::Start => { + if start.is_some() { + return Err(<A::Error as Error>::duplicate_field("start")); + } + start = Some(try!(map.next_value())); + } + Field::End => { + if end.is_some() { + return Err(<A::Error as Error>::duplicate_field("end")); + } + end = Some(try!(map.next_value())); + } + } + } + let start = match start { + Some(start) => start, + None => return Err(<A::Error as Error>::missing_field("start")), + }; + let end = match end { + Some(end) => end, + None => return Err(<A::Error as Error>::missing_field("end")), + }; + Ok((start, end)) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(ops_bound, collections_bound))] +impl<'de, T> Deserialize<'de> for Bound<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + enum Field { + Unbounded, + Included, + Excluded, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`Unbounded`, `Included` or `Excluded`") + } + + fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> + where + E: Error, + { + match value { + 0 => Ok(Field::Unbounded), + 1 => Ok(Field::Included), + 2 => Ok(Field::Excluded), + _ => Err(Error::invalid_value( + Unexpected::Unsigned(value as u64), + &self, + )), + } + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + "Unbounded" => Ok(Field::Unbounded), + "Included" => Ok(Field::Included), + "Excluded" => Ok(Field::Excluded), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + b"Unbounded" => Ok(Field::Unbounded), + b"Included" => Ok(Field::Included), + b"Excluded" => Ok(Field::Excluded), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct BoundVisitor<T>(PhantomData<Bound<T>>); + + impl<'de, T> Visitor<'de> for BoundVisitor<T> + where + T: Deserialize<'de>, + { + type Value = Bound<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Bound") + } + + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + match try!(data.variant()) { + (Field::Unbounded, v) => v.unit_variant().map(|()| Bound::Unbounded), + (Field::Included, v) => v.newtype_variant().map(Bound::Included), + (Field::Excluded, v) => v.newtype_variant().map(Bound::Excluded), + } + } + } + + const VARIANTS: &'static [&'static str] = &["Unbounded", "Included", "Excluded"]; + + deserializer.deserialize_enum("Bound", VARIANTS, BoundVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! nonzero_integers { + ( $( $T: ident, )+ ) => { + $( + #[cfg(num_nonzero)] + impl<'de> Deserialize<'de> for num::$T { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let value = try!(Deserialize::deserialize(deserializer)); + match <num::$T>::new(value) { + Some(nonzero) => Ok(nonzero), + None => Err(Error::custom("expected a non-zero value")), + } + } + } + )+ + }; +} + +nonzero_integers! { + // Not including signed NonZeroI* since they might be removed + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroUsize, +} + +// Currently 128-bit integers do not work on Emscripten targets so we need an +// additional `#[cfg]` +serde_if_integer128! { + nonzero_integers! { + NonZeroU128, + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, T, E> Deserialize<'de> for Result<T, E> +where + T: Deserialize<'de>, + E: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + // If this were outside of the serde crate, it would just use: + // + // #[derive(Deserialize)] + // #[serde(variant_identifier)] + enum Field { + Ok, + Err, + } + + impl<'de> Deserialize<'de> for Field { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`Ok` or `Err`") + } + + fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> + where + E: Error, + { + match value { + 0 => Ok(Field::Ok), + 1 => Ok(Field::Err), + _ => Err(Error::invalid_value( + Unexpected::Unsigned(value as u64), + &self, + )), + } + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: Error, + { + match value { + "Ok" => Ok(Field::Ok), + "Err" => Ok(Field::Err), + _ => Err(Error::unknown_variant(value, VARIANTS)), + } + } + + fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match value { + b"Ok" => Ok(Field::Ok), + b"Err" => Ok(Field::Err), + _ => match str::from_utf8(value) { + Ok(value) => Err(Error::unknown_variant(value, VARIANTS)), + Err(_) => { + Err(Error::invalid_value(Unexpected::Bytes(value), &self)) + } + }, + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct ResultVisitor<T, E>(PhantomData<Result<T, E>>); + + impl<'de, T, E> Visitor<'de> for ResultVisitor<T, E> + where + T: Deserialize<'de>, + E: Deserialize<'de>, + { + type Value = Result<T, E>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("enum Result") + } + + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + match try!(data.variant()) { + (Field::Ok, v) => v.newtype_variant().map(Ok), + (Field::Err, v) => v.newtype_variant().map(Err), + } + } + } + + const VARIANTS: &'static [&'static str] = &["Ok", "Err"]; + + deserializer.deserialize_enum("Result", VARIANTS, ResultVisitor(PhantomData)) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl<'de, T> Deserialize<'de> for Wrapping<T> +where + T: Deserialize<'de>, +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Wrapping) + } +} diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs new file mode 100644 index 000000000..896b1a600 --- /dev/null +++ b/serde/src/de/mod.rs @@ -0,0 +1,2269 @@ +//! Generic data structure deserialization framework. +//! +//! The two most important traits in this module are [`Deserialize`] and +//! [`Deserializer`]. +//! +//! - **A type that implements `Deserialize` is a data structure** that can be +//! deserialized from any data format supported by Serde, and conversely +//! - **A type that implements `Deserializer` is a data format** that can +//! deserialize any data structure supported by Serde. +//! +//! # The Deserialize trait +//! +//! Serde provides [`Deserialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. All of these can be +//! deserialized using Serde out of the box. +//! +//! Additionally, Serde provides a procedural macro called [`serde_derive`] to +//! automatically generate [`Deserialize`] implementations for structs and enums +//! in your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Deserialize`] manually for +//! some type in your program. See the [Implementing `Deserialize`] section of +//! the manual for more about this. +//! +//! Third-party crates may provide [`Deserialize`] implementations for types +//! that they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap<K, V>`] type that is deserializable by Serde because the +//! crate provides an implementation of [`Deserialize`] for it. +//! +//! # The Deserializer trait +//! +//! [`Deserializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`bincode`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Deserialize provided by Serde +//! +//! This is a slightly different set of types than what is supported for +//! serialization. Some types can be serialized by Serde but not deserialized. +//! One example is `OsStr`. +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - **Compound types**: +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\<T\> +//! - Result\<T, E\> +//! - PhantomData\<T\> +//! - **Wrapper types**: +//! - Box\<T\> +//! - Box\<\[T\]\> +//! - Box\<str\> +//! - Cow\<'a, T\> +//! - Cell\<T\> +//! - RefCell\<T\> +//! - Mutex\<T\> +//! - RwLock\<T\> +//! - Rc\<T\> *(if* features = ["rc"] *is enabled)* +//! - Arc\<T\> *(if* features = ["rc"] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\<K, V\> +//! - BTreeSet\<T\> +//! - BinaryHeap\<T\> +//! - HashMap\<K, V, H\> +//! - HashSet\<T, H\> +//! - LinkedList\<T\> +//! - VecDeque\<T\> +//! - Vec\<T\> +//! - **Zero-copy types**: +//! - &str +//! - &\[u8\] +//! - **FFI types**: +//! - CString +//! - Box\<CStr\> +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\<T\> +//! - RangeInclusive\<T\> +//! - Bound\<T\> +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Deserialize`]: https://serde.rs/impl-deserialize.html +//! [`Deserialize`]: ../trait.Deserialize.html +//! [`Deserializer`]: ../trait.Deserializer.html +//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map +//! [`serde_derive`]: https://crates.io/crates/serde_derive +//! [`serde_json`]: https://github.com/serde-rs/json +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use lib::*; + +//////////////////////////////////////////////////////////////////////////////// + +pub mod value; + +mod from_primitive; +mod ignored_any; +mod impls; +mod utf8; + +pub use self::ignored_any::IgnoredAny; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// The `Error` trait allows `Deserialize` implementations to create descriptive + /// error messages belonging to the `Deserializer` against which they are + /// currently running. + /// + /// Every `Deserializer` declares an `Error` type that encompasses both + /// general-purpose deserialization errors as well as errors specific to the + /// particular deserialization format. For example the `Error` type of + /// `serde_json` can represent errors like an invalid JSON escape sequence or an + /// unterminated string literal, in addition to the error cases that are part of + /// this trait. + /// + /// Most deserializers should only need to provide the `Error::custom` method + /// and inherit the default behavior for the other methods. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// type appropriate for a basic JSON data format. + /// + /// [example data format]: https://serde.rs/data-format.html + pub trait Error: Sized $(+ $($supertrait)::+)* { + /// Raised when there is general error when deserializing a type. + /// + /// The message should not be capitalized and should not end with a period. + /// + /// ```edition2018 + /// # use std::str::FromStr; + /// # + /// # struct IpAddr; + /// # + /// # impl FromStr for IpAddr { + /// # type Err = String; + /// # + /// # fn from_str(_: &str) -> Result<Self, String> { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for IpAddr { + /// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + /// where + /// D: Deserializer<'de>, + /// { + /// let s = String::deserialize(deserializer)?; + /// s.parse().map_err(de::Error::custom) + /// } + /// } + /// ``` + fn custom<T>(msg: T) -> Self + where + T: Display; + + /// Raised when a `Deserialize` receives a type different from what it was + /// expecting. + /// + /// The `unexp` argument provides information about what type was received. + /// This is the type that was present in the input file or other source data + /// of the Deserializer. + /// + /// The `exp` argument provides information about what type was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of a JSON file + /// containing an integer, the unexpected type is the integer and the + /// expected type is the string. + #[cold] + fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } + + /// Raised when a `Deserialize` receives a value of the right type but that + /// is wrong for some other reason. + /// + /// The `unexp` argument provides information about what value was received. + /// This is the value that was present in the input file or other source + /// data of the Deserializer. + /// + /// The `exp` argument provides information about what value was being + /// expected. This is the type that is written in the program. + /// + /// For example if we try to deserialize a String out of some binary data + /// that is not valid UTF-8, the unexpected value is the bytes and the + /// expected value is a string. + #[cold] + fn invalid_value(unexp: Unexpected, exp: &Expected) -> Self { + Error::custom(format_args!("invalid value: {}, expected {}", unexp, exp)) + } + + /// Raised when deserializing a sequence or map and the input data contains + /// too many or too few elements. + /// + /// The `len` argument is the number of elements encountered. The sequence + /// or map may have expected more arguments or fewer arguments. + /// + /// The `exp` argument provides information about what data was being + /// expected. For example `exp` might say that a tuple of size 6 was + /// expected. + #[cold] + fn invalid_length(len: usize, exp: &Expected) -> Self { + Error::custom(format_args!("invalid length {}, expected {}", len, exp)) + } + + /// Raised when a `Deserialize` enum type received a variant with an + /// unrecognized name. + #[cold] + fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown variant `{}`, there are no variants", + variant + )) + } else { + Error::custom(format_args!( + "unknown variant `{}`, expected {}", + variant, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type received a field with an + /// unrecognized name. + #[cold] + fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self { + if expected.is_empty() { + Error::custom(format_args!( + "unknown field `{}`, there are no fields", + field + )) + } else { + Error::custom(format_args!( + "unknown field `{}`, expected {}", + field, + OneOf { names: expected } + )) + } + } + + /// Raised when a `Deserialize` struct type expected to receive a required + /// field with a particular name but that field was not present in the + /// input. + #[cold] + fn missing_field(field: &'static str) -> Self { + Error::custom(format_args!("missing field `{}`", field)) + } + + /// Raised when a `Deserialize` struct type received more than one of the + /// same field. + #[cold] + fn duplicate_field(field: &'static str) -> Self { + Error::custom(format_args!("duplicate field `{}`", field)) + } + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + error::Error); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +/// `Unexpected` represents an unexpected invocation of any one of the `Visitor` +/// trait methods. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. +/// +/// ```edition2018 +/// # use std::fmt; +/// # +/// # use serde::de::{self, Unexpected, Visitor}; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Unexpected<'a> { + /// The input contained a boolean value that was not expected. + Bool(bool), + + /// The input contained an unsigned integer `u8`, `u16`, `u32` or `u64` that + /// was not expected. + Unsigned(u64), + + /// The input contained a signed integer `i8`, `i16`, `i32` or `i64` that + /// was not expected. + Signed(i64), + + /// The input contained a floating point `f32` or `f64` that was not + /// expected. + Float(f64), + + /// The input contained a `char` that was not expected. + Char(char), + + /// The input contained a `&str` or `String` that was not expected. + Str(&'a str), + + /// The input contained a `&[u8]` or `Vec<u8>` that was not expected. + Bytes(&'a [u8]), + + /// The input contained a unit `()` that was not expected. + Unit, + + /// The input contained an `Option<T>` that was not expected. + Option, + + /// The input contained a newtype struct that was not expected. + NewtypeStruct, + + /// The input contained a sequence that was not expected. + Seq, + + /// The input contained a map that was not expected. + Map, + + /// The input contained an enum that was not expected. + Enum, + + /// The input contained a unit variant that was not expected. + UnitVariant, + + /// The input contained a newtype variant that was not expected. + NewtypeVariant, + + /// The input contained a tuple variant that was not expected. + TupleVariant, + + /// The input contained a struct variant that was not expected. + StructVariant, + + /// A message stating what uncategorized thing the input contained that was + /// not expected. + /// + /// The message should be a noun or noun phrase, not capitalized and without + /// a period. An example message is "unoriginal superhero". + Other(&'a str), +} + +impl<'a> fmt::Display for Unexpected<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use self::Unexpected::*; + match *self { + Bool(b) => write!(formatter, "boolean `{}`", b), + Unsigned(i) => write!(formatter, "integer `{}`", i), + Signed(i) => write!(formatter, "integer `{}`", i), + Float(f) => write!(formatter, "floating point `{}`", f), + Char(c) => write!(formatter, "character `{}`", c), + Str(s) => write!(formatter, "string {:?}", s), + Bytes(_) => write!(formatter, "byte array"), + Unit => write!(formatter, "unit value"), + Option => write!(formatter, "Option value"), + NewtypeStruct => write!(formatter, "newtype struct"), + Seq => write!(formatter, "sequence"), + Map => write!(formatter, "map"), + Enum => write!(formatter, "enum"), + UnitVariant => write!(formatter, "unit variant"), + NewtypeVariant => write!(formatter, "newtype variant"), + TupleVariant => write!(formatter, "tuple variant"), + StructVariant => write!(formatter, "struct variant"), + Other(other) => formatter.write_str(other), + } + } +} + +/// `Expected` represents an explanation of what data a `Visitor` was expecting +/// to receive. +/// +/// This is used as an argument to the `invalid_type`, `invalid_value`, and +/// `invalid_length` methods of the `Error` trait to build error messages. The +/// message should be a noun or noun phrase that completes the sentence "This +/// Visitor expects to receive ...", for example the message could be "an +/// integer between 0 and 64". The message should not be capitalized and should +/// not end with a period. +/// +/// Within the context of a `Visitor` implementation, the `Visitor` itself +/// (`&self`) is an implementation of this trait. +/// +/// ```edition2018 +/// # use std::fmt; +/// # +/// # use serde::de::{self, Unexpected, Visitor}; +/// # +/// # struct Example; +/// # +/// # impl<'de> Visitor<'de> for Example { +/// # type Value = (); +/// # +/// # fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// # write!(formatter, "definitely not a boolean") +/// # } +/// # +/// fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> +/// where +/// E: de::Error, +/// { +/// Err(de::Error::invalid_type(Unexpected::Bool(v), &self)) +/// } +/// # } +/// ``` +/// +/// Outside of a `Visitor`, `&"..."` can be used. +/// +/// ```edition2018 +/// # use serde::de::{self, Unexpected}; +/// # +/// # fn example<E>() -> Result<(), E> +/// # where +/// # E: de::Error, +/// # { +/// # let v = true; +/// return Err(de::Error::invalid_type(Unexpected::Bool(v), &"a negative integer")); +/// # } +/// ``` +pub trait Expected { + /// Format an explanation of what data was being expected. Same signature as + /// the `Display` and `Debug` traits. + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; +} + +impl<'de, T> Expected for T +where + T: Visitor<'de>, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.expecting(formatter) + } +} + +impl<'a> Expected for &'a str { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(self) + } +} + +impl<'a> Display for Expected + 'a { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Expected::fmt(self, formatter) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be deserialized from any data format supported +/// by Serde. +/// +/// Serde provides `Deserialize` implementations for many Rust primitive and +/// standard library types. The complete list is [here][de]. All of these can +/// be deserialized using Serde out of the box. +/// +/// Additionally, Serde provides a procedural macro called `serde_derive` to +/// automatically generate `Deserialize` implementations for structs and enums +/// in your program. See the [derive section of the manual][derive] for how to +/// use this. +/// +/// In rare cases it may be necessary to implement `Deserialize` manually for +/// some type in your program. See the [Implementing +/// `Deserialize`][impl-deserialize] section of the manual for more about this. +/// +/// Third-party crates may provide `Deserialize` implementations for types that +/// they expose. For example the `linked-hash-map` crate provides a +/// `LinkedHashMap<K, V>` type that is deserializable by Serde because the crate +/// provides an implementation of `Deserialize` for it. +/// +/// [de]: https://docs.serde.rs/serde/de/index.html +/// [derive]: https://serde.rs/derive.html +/// [impl-deserialize]: https://serde.rs/impl-deserialize.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self` when deserialized. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +pub trait Deserialize<'de>: Sized { + /// Deserialize this value from the given Serde deserializer. + /// + /// See the [Implementing `Deserialize`][impl-deserialize] section of the + /// manual for more information about how to implement this method. + /// + /// [impl-deserialize]: https://serde.rs/impl-deserialize.html + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>; + + /// Deserializes a value into `self` from the given Deserializer. + /// + /// The purpose of this method is to allow the deserializer to reuse + /// resources and avoid copies. As such, if this method returns an error, + /// `self` will be in an indeterminate state where some parts of the struct + /// have been overwritten. Although whatever state that is will be + /// memory-safe. + /// + /// This is generally useful when repeatedly deserializing values that + /// are processed one at a time, where the value of `self` doesn't matter + /// when the next deserialization occurs. + /// + /// If you manually implement this, your recursive deserializations should + /// use `deserialize_in_place`. + /// + /// This method is stable and an official public API, but hidden from the + /// documentation because it is almost never what newbies are looking for. + /// Showing it in rustdoc would cause it to be featured more prominently + /// than it deserves. + #[doc(hidden)] + fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + // Default implementation just delegates to `deserialize` impl. + *place = Deserialize::deserialize(deserializer)?; + Ok(()) + } +} + +/// A data structure that can be deserialized without borrowing any data from +/// the deserializer. +/// +/// This is primarily useful for trait bounds on functions. For example a +/// `from_str` function may be able to deserialize a data structure that borrows +/// from the input string, but a `from_reader` function may only deserialize +/// owned data. +/// +/// ```edition2018 +/// # use serde::de::{Deserialize, DeserializeOwned}; +/// # use std::io::{Read, Result}; +/// # +/// # trait Ignore { +/// fn from_str<'a, T>(s: &'a str) -> Result<T> +/// where +/// T: Deserialize<'a>; +/// +/// fn from_reader<R, T>(rdr: R) -> Result<T> +/// where +/// R: Read, +/// T: DeserializeOwned; +/// # } +/// ``` +/// +/// # Lifetime +/// +/// The relationship between `Deserialize` and `DeserializeOwned` in trait +/// bounds is explained in more detail on the page [Understanding deserializer +/// lifetimes]. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +pub trait DeserializeOwned: for<'de> Deserialize<'de> {} +impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {} + +/// `DeserializeSeed` is the stateful form of the `Deserialize` trait. If you +/// ever find yourself looking for a way to pass data into a `Deserialize` impl, +/// this trait is the way to do it. +/// +/// As one example of stateful deserialization consider deserializing a JSON +/// array into an existing buffer. Using the `Deserialize` trait we could +/// deserialize a JSON array into a `Vec<T>` but it would be a freshly allocated +/// `Vec<T>`; there is no way for `Deserialize` to reuse a previously allocated +/// buffer. Using `DeserializeSeed` instead makes this possible as in the +/// example code below. +/// +/// The canonical API for stateless deserialization looks like this: +/// +/// ```edition2018 +/// # use serde::Deserialize; +/// # +/// # enum Error {} +/// # +/// fn func<'de, T: Deserialize<'de>>() -> Result<T, Error> +/// # { +/// # unimplemented!() +/// # } +/// ``` +/// +/// Adjusting an API like this to support stateful deserialization is a matter +/// of accepting a seed as input: +/// +/// ```edition2018 +/// # use serde::de::DeserializeSeed; +/// # +/// # enum Error {} +/// # +/// fn func_seed<'de, T: DeserializeSeed<'de>>(seed: T) -> Result<T::Value, Error> +/// # { +/// # let _ = seed; +/// # unimplemented!() +/// # } +/// ``` +/// +/// In practice the majority of deserialization is stateless. An API expecting a +/// seed can be appeased by passing `std::marker::PhantomData` as a seed in the +/// case of stateless deserialization. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by `Self::Value` when deserialized. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// Suppose we have JSON that looks like `[[1, 2], [3, 4, 5], [6]]` and we need +/// to deserialize it into a flat representation like `vec![1, 2, 3, 4, 5, 6]`. +/// Allocating a brand new `Vec<T>` for each subarray would be slow. Instead we +/// would like to allocate a single `Vec<T>` and then deserialize each subarray +/// into it. This requires stateful deserialization using the `DeserializeSeed` +/// trait. +/// +/// ```edition2018 +/// use std::fmt; +/// use std::marker::PhantomData; +/// +/// use serde::de::{Deserialize, DeserializeSeed, Deserializer, SeqAccess, Visitor}; +/// +/// // A DeserializeSeed implementation that uses stateful deserialization to +/// // append array elements onto the end of an existing vector. The preexisting +/// // state ("seed") in this case is the Vec<T>. The `deserialize` method of +/// // `ExtendVec` will be traversing the inner arrays of the JSON input and +/// // appending each integer into the existing Vec. +/// struct ExtendVec<'a, T: 'a>(&'a mut Vec<T>); +/// +/// impl<'de, 'a, T> DeserializeSeed<'de> for ExtendVec<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// // The return type of the `deserialize` method. This implementation +/// // appends onto an existing vector but does not create any new data +/// // structure, so the return type is (). +/// type Value = (); +/// +/// fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> +/// where +/// D: Deserializer<'de>, +/// { +/// // Visitor implementation that will walk an inner array of the JSON +/// // input. +/// struct ExtendVecVisitor<'a, T: 'a>(&'a mut Vec<T>); +/// +/// impl<'de, 'a, T> Visitor<'de> for ExtendVecVisitor<'a, T> +/// where +/// T: Deserialize<'de>, +/// { +/// type Value = (); +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of integers") +/// } +/// +/// fn visit_seq<A>(self, mut seq: A) -> Result<(), A::Error> +/// where +/// A: SeqAccess<'de>, +/// { +/// // Visit each element in the inner array and push it onto +/// // the existing vector. +/// while let Some(elem) = seq.next_element()? { +/// self.0.push(elem); +/// } +/// Ok(()) +/// } +/// } +/// +/// deserializer.deserialize_seq(ExtendVecVisitor(self.0)) +/// } +/// } +/// +/// // Visitor implementation that will walk the outer array of the JSON input. +/// struct FlattenedVecVisitor<T>(PhantomData<T>); +/// +/// impl<'de, T> Visitor<'de> for FlattenedVecVisitor<T> +/// where +/// T: Deserialize<'de>, +/// { +/// // This Visitor constructs a single Vec<T> to hold the flattened +/// // contents of the inner arrays. +/// type Value = Vec<T>; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "an array of arrays") +/// } +/// +/// fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error> +/// where +/// A: SeqAccess<'de>, +/// { +/// // Create a single Vec to hold the flattened contents. +/// let mut vec = Vec::new(); +/// +/// // Each iteration through this loop is one inner array. +/// while let Some(()) = seq.next_element_seed(ExtendVec(&mut vec))? { +/// // Nothing to do; inner array has been appended into `vec`. +/// } +/// +/// // Return the finished vec. +/// Ok(vec) +/// } +/// } +/// +/// # fn example<'de, D>(deserializer: D) -> Result<(), D::Error> +/// # where +/// # D: Deserializer<'de>, +/// # { +/// let visitor = FlattenedVecVisitor(PhantomData); +/// let flattened: Vec<u64> = deserializer.deserialize_seq(visitor)?; +/// # Ok(()) +/// # } +/// ``` +pub trait DeserializeSeed<'de>: Sized { + /// The type produced by using this seed. + type Value; + + /// Equivalent to the more common `Deserialize::deserialize` method, except + /// with some initial piece of data (the seed) passed in. + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>; +} + +impl<'de, T> DeserializeSeed<'de> for PhantomData<T> +where + T: Deserialize<'de>, +{ + type Value = T; + + #[inline] + fn deserialize<D>(self, deserializer: D) -> Result<T, D::Error> + where + D: Deserializer<'de>, + { + T::deserialize(deserializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can deserialize any data structure supported by +/// Serde. +/// +/// The role of this trait is to define the deserialization half of the [Serde +/// data model], which is a way to categorize every Rust data type into one of +/// 29 possible types. Each method of the `Serializer` trait corresponds to one +/// of the types of the data model. +/// +/// Implementations of `Deserialize` map themselves into this data model by +/// passing to the `Deserializer` a `Visitor` implementation that can receive +/// these various types. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData<T>`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example `Vec<T>` +/// or `HashSet<T>`. When serializing, the length may or may not be known +/// before iterating through all the data. When deserializing, the length +/// is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec<T>)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap<K, V>`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the serialized +/// data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`. +/// +/// The `Deserializer` trait supports two entry point styles which enables +/// different kinds of deserialization. +/// +/// 1. The `deserialize` method. Self-describing data formats like JSON are able +/// to look at the serialized data and tell what it represents. For example +/// the JSON deserializer may see an opening curly brace (`{`) and know that +/// it is seeing a map. If the data format supports +/// `Deserializer::deserialize_any`, it will drive the Visitor using whatever +/// type it sees in the input. JSON uses this approach when deserializing +/// `serde_json::Value` which is an enum that can represent any JSON +/// document. Without knowing what is in a JSON document, we can deserialize +/// it to `serde_json::Value` by going through +/// `Deserializer::deserialize_any`. +/// +/// 2. The various `deserialize_*` methods. Non-self-describing formats like +/// Bincode need to be told what is in the input in order to deserialize it. +/// The `deserialize_*` methods are hints to the deserializer for how to +/// interpret the next piece of input. Non-self-describing formats are not +/// able to deserialize something like `serde_json::Value` which relies on +/// `Deserializer::deserialize_any`. +/// +/// When implementing `Deserialize`, you should avoid relying on +/// `Deserializer::deserialize_any` unless you need to be told by the +/// Deserializer what type is in the input. Know that relying on +/// `Deserializer::deserialize_any` means your data type will be able to +/// deserialize from self-describing formats only, ruling out Bincode and many +/// others. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the input when deserializing. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// a basic JSON `Deserializer`. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait Deserializer<'de>: Sized { + /// The error type that can be returned if some error occurs during + /// deserialization. + type Error: Error; + + /// Require the `Deserializer` to figure out how to drive the visitor based + /// on what data type is in the input. + /// + /// When implementing `Deserialize`, you should avoid relying on + /// `Deserializer::deserialize_any` unless you need to be told by the + /// Deserializer what type is in the input. Know that relying on + /// `Deserializer::deserialize_any` means your data type will be able to + /// deserialize from self-describing formats only, ruling out Bincode and + /// many others. + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `bool` value. + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i8` value. + fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i16` value. + fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i32` value. + fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an `i64` value. + fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + serde_if_integer128! { + /// Hint that the `Deserialize` type is expecting an `i128` value. + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default behavior unconditionally returns an error. + fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de> + { + let _ = visitor; + Err(Error::custom("i128 is not supported")) + } + } + + /// Hint that the `Deserialize` type is expecting a `u8` value. + fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u16` value. + fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u32` value. + fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `u64` value. + fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + serde_if_integer128! { + /// Hint that the `Deserialize` type is expecting an `u128` value. + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default behavior unconditionally returns an error. + fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de> + { + let _ = visitor; + Err(Error::custom("u128 is not supported")) + } + } + + /// Hint that the `Deserialize` type is expecting a `f32` value. + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `f64` value. + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a `char` value. + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and does + /// not benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `String` data, + /// indiciate this to the `Deserializer` by using `deserialize_string` + /// instead. + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a string value and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `String` + /// data, indicate that to the `Deserializer` by using `deserialize_str` + /// instead. + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and does not + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would benefit from taking ownership of `Vec<u8>` data, + /// indicate this to the `Deserializer` by using `deserialize_byte_buf` + /// instead. + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a byte array and would + /// benefit from taking ownership of buffered data owned by the + /// `Deserializer`. + /// + /// If the `Visitor` would not benefit from taking ownership of `Vec<u8>` + /// data, indicate that to the `Deserializer` by using `deserialize_bytes` + /// instead. + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an optional value. + /// + /// This allows deserializers that encode an optional value as a nullable + /// value to convert the null value into `None` and a regular value into + /// `Some(value)`. + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit value. + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a unit struct with a + /// particular name. + fn deserialize_unit_struct<V>( + self, + name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a newtype struct with a + /// particular name. + fn deserialize_newtype_struct<V>( + self, + name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values. + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a sequence of values and + /// knows how many values there are without looking at the serialized data. + fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a tuple struct with a + /// particular name and number of fields. + fn deserialize_tuple_struct<V>( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a map of key-value pairs. + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting a struct with a particular + /// name and fields. + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting an enum value with a + /// particular name and possible variants. + fn deserialize_enum<V>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type is expecting the name of a struct + /// field or the discriminant of an enum variant. + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Hint that the `Deserialize` type needs to deserialize a value whose type + /// doesn't matter because it is ignored. + /// + /// Deserializers for non-self-describing formats may not support this mode. + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Determine whether `Deserialize` implementations should expect to + /// deserialize their human-readable form. + /// + /// Some types have a human-readable form that may be somewhat expensive to + /// construct, as well as a binary form that is compact and efficient. + /// Generally text-based formats like JSON and YAML will prefer to use the + /// human-readable one and binary formats like Bincode will prefer the + /// compact one. + /// + /// ```edition2018 + /// # use std::ops::Add; + /// # use std::str::FromStr; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # const EPOCH: Timestamp = Timestamp; + /// # } + /// # + /// # impl FromStr for Timestamp { + /// # type Err = String; + /// # fn from_str(_: &str) -> Result<Self, Self::Err> { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # struct Duration; + /// # + /// # impl Duration { + /// # fn seconds(_: u64) -> Self { unimplemented!() } + /// # } + /// # + /// # impl Add<Duration> for Timestamp { + /// # type Output = Timestamp; + /// # fn add(self, _: Duration) -> Self::Output { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::de::{self, Deserialize, Deserializer}; + /// + /// impl<'de> Deserialize<'de> for Timestamp { + /// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + /// where + /// D: Deserializer<'de>, + /// { + /// if deserializer.is_human_readable() { + /// // Deserialize from a human-readable string like "2015-05-15T17:01:00Z". + /// let s = String::deserialize(deserializer)?; + /// Timestamp::from_str(&s).map_err(de::Error::custom) + /// } else { + /// // Deserialize from a compact binary representation, seconds since + /// // the Unix epoch. + /// let n = u64::deserialize(deserializer)?; + /// Ok(Timestamp::EPOCH + Duration::seconds(n)) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + fn is_human_readable(&self) -> bool { + true + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// This trait represents a visitor that walks through a deserializer. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the requirement for lifetime of data +/// that may be borrowed by `Self::Value`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```edition2018 +/// # use std::fmt; +/// # +/// # use serde::de::{self, Unexpected, Visitor}; +/// # +/// /// A visitor that deserializes a long string - a string containing at least +/// /// some minimum number of bytes. +/// struct LongString { +/// min: usize, +/// } +/// +/// impl<'de> Visitor<'de> for LongString { +/// type Value = String; +/// +/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +/// write!(formatter, "a string containing at least {} bytes", self.min) +/// } +/// +/// fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> +/// where +/// E: de::Error, +/// { +/// if s.len() >= self.min { +/// Ok(s.to_owned()) +/// } else { +/// Err(de::Error::invalid_value(Unexpected::Str(s), &self)) +/// } +/// } +/// } +/// ``` +pub trait Visitor<'de>: Sized { + /// The value produced by this visitor. + type Value; + + /// Format a message stating what data this Visitor expects to receive. + /// + /// This is used in error messages. The message should complete the sentence + /// "This Visitor expects to receive ...", for example the message could be + /// "an integer between 0 and 64". The message should not be capitalized and + /// should not end with a period. + /// + /// ```edition2018 + /// # use std::fmt; + /// # + /// # struct S { + /// # max: usize, + /// # } + /// # + /// # impl<'de> serde::de::Visitor<'de> for S { + /// # type Value = (); + /// # + /// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// write!(formatter, "an integer between 0 and {}", self.max) + /// } + /// # } + /// ``` + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result; + + /// The input contains a boolean. + /// + /// The default implementation fails with a type error. + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Bool(v), &self)) + } + + /// The input contains an `i8`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i16`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i32`. + /// + /// The default implementation forwards to [`visit_i64`]. + /// + /// [`visit_i64`]: #method.visit_i64 + fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_i64(v as i64) + } + + /// The input contains an `i64`. + /// + /// The default implementation fails with a type error. + fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Signed(v), &self)) + } + + serde_if_integer128! { + /// The input contains a `i128`. + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default implementation fails with a type error. + fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E> + where + E: Error, + { + let _ = v; + Err(Error::invalid_type(Unexpected::Other("i128"), &self)) + } + } + + /// The input contains a `u8`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u16`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u32`. + /// + /// The default implementation forwards to [`visit_u64`]. + /// + /// [`visit_u64`]: #method.visit_u64 + fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_u64(v as u64) + } + + /// The input contains a `u64`. + /// + /// The default implementation fails with a type error. + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unsigned(v), &self)) + } + + serde_if_integer128! { + /// The input contains a `u128`. + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default implementation fails with a type error. + fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E> + where + E: Error, + { + let _ = v; + Err(Error::invalid_type(Unexpected::Other("u128"), &self)) + } + } + + /// The input contains an `f32`. + /// + /// The default implementation forwards to [`visit_f64`]. + /// + /// [`visit_f64`]: #method.visit_f64 + fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_f64(v as f64) + } + + /// The input contains an `f64`. + /// + /// The default implementation fails with a type error. + fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Float(v), &self)) + } + + /// The input contains a `char`. + /// + /// The default implementation forwards to [`visit_str`] as a one-character + /// string. + /// + /// [`visit_str`]: #method.visit_str + #[inline] + fn visit_char<E>(self, v: char) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_str(utf8::encode(v).as_str()) + } + + /// The input contains a string. The lifetime of the string is ephemeral and + /// it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_str` rather than + /// `Deserializer::deserialize_string`. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Str(v), &self)) + } + + /// The input contains a string that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of strings in some formats. For + /// example JSON input containing the JSON string `"borrowed"` can be + /// deserialized with zero copying into a `&'a str` as long as the input + /// data outlives `'a`. + /// + /// The default implementation forwards to `visit_str`. + #[inline] + fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_str(v) + } + + /// The input contains a string and ownership of the string is being given + /// to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a string created by the `Deserializer`. `Deserialize` implementations + /// that benefit from taking ownership of `String` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_string` rather + /// than `Deserializer::deserialize_str`, although not every deserializer + /// will honor such a request. + /// + /// It is never correct to implement `visit_string` without implementing + /// `visit_str`. Implement neither, both, or just `visit_str`. + /// + /// The default implementation forwards to `visit_str` and then drops the + /// `String`. + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_str(&v) + } + + /// The input contains a byte array. The lifetime of the byte array is + /// ephemeral and it may be destroyed after this method returns. + /// + /// This method allows the `Deserializer` to avoid a copy by retaining + /// ownership of any buffered data. `Deserialize` implementations that do + /// not benefit from taking ownership of `Vec<u8>` data should indicate that + /// to the deserializer by using `Deserializer::deserialize_bytes` rather + /// than `Deserializer::deserialize_byte_buf`. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + let _ = v; + Err(Error::invalid_type(Unexpected::Bytes(v), &self)) + } + + /// The input contains a byte array that lives at least as long as the + /// `Deserializer`. + /// + /// This enables zero-copy deserialization of bytes in some formats. For + /// example Bincode data containing bytes can be deserialized with zero + /// copying into a `&'a [u8]` as long as the input data outlives `'a`. + /// + /// The default implementation forwards to `visit_bytes`. + #[inline] + fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_bytes(v) + } + + /// The input contains a byte array and ownership of the byte array is being + /// given to the `Visitor`. + /// + /// This method allows the `Visitor` to avoid a copy by taking ownership of + /// a byte buffer created by the `Deserializer`. `Deserialize` + /// implementations that benefit from taking ownership of `Vec<u8>` data + /// should indicate that to the deserializer by using + /// `Deserializer::deserialize_byte_buf` rather than + /// `Deserializer::deserialize_bytes`, although not every deserializer will + /// honor such a request. + /// + /// It is never correct to implement `visit_byte_buf` without implementing + /// `visit_bytes`. Implement neither, both, or just `visit_bytes`. + /// + /// The default implementation forwards to `visit_bytes` and then drops the + /// `Vec<u8>`. + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + self.visit_bytes(&v) + } + + /// The input contains an optional that is absent. + /// + /// The default implementation fails with a type error. + fn visit_none<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains an optional that is present. + /// + /// The default implementation fails with a type error. + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::Option, &self)) + } + + /// The input contains a unit `()`. + /// + /// The default implementation fails with a type error. + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: Error, + { + Err(Error::invalid_type(Unexpected::Unit, &self)) + } + + /// The input contains a newtype struct. + /// + /// The content of the newtype struct may be read from the given + /// `Deserializer`. + /// + /// The default implementation fails with a type error. + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + let _ = deserializer; + Err(Error::invalid_type(Unexpected::NewtypeStruct, &self)) + } + + /// The input contains a sequence of elements. + /// + /// The default implementation fails with a type error. + fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccess<'de>, + { + let _ = seq; + Err(Error::invalid_type(Unexpected::Seq, &self)) + } + + /// The input contains a key-value map. + /// + /// The default implementation fails with a type error. + fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> + where + A: MapAccess<'de>, + { + let _ = map; + Err(Error::invalid_type(Unexpected::Map, &self)) + } + + /// The input contains an enum. + /// + /// The default implementation fails with a type error. + fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error> + where + A: EnumAccess<'de>, + { + let _ = data; + Err(Error::invalid_type(Unexpected::Enum, &self)) + } + + // Used when deserializing a flattened Option field. Not public API. + #[doc(hidden)] + fn __private_visit_untagged_option<D>(self, _: D) -> Result<Self::Value, ()> + where + D: Deserializer<'de>, + { + Err(()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each element of a sequence in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation, +/// which deserializes each item in a sequence. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized sequence elements. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SeqAccess` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SeqAccess<'de> { + /// The error type that can be returned if some error occurs during + /// deserialization. + type Error: Error; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// `Deserialize` implementations should typically use + /// `SeqAccess::next_element` instead. + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeSeed<'de>; + + /// This returns `Ok(Some(value))` for the next value in the sequence, or + /// `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `SeqAccess` implementations should not override the default behavior. + #[inline] + fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error> + where + T: Deserialize<'de>, + { + self.next_element_seed(PhantomData) + } + + /// Returns the number of elements remaining in the sequence, if known. + #[inline] + fn size_hint(&self) -> Option<usize> { + None + } +} + +impl<'de, 'a, A> SeqAccess<'de> for &'a mut A +where + A: SeqAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeSeed<'de>, + { + (**self).next_element_seed(seed) + } + + #[inline] + fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error> + where + T: Deserialize<'de>, + { + (**self).next_element() + } + + #[inline] + fn size_hint(&self) -> Option<usize> { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to each entry of a map in the input. +/// +/// This is a trait that a `Deserializer` passes to a `Visitor` implementation. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by deserialized map entries. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `MapAccess` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait MapAccess<'de> { + /// The error type that can be returned if some error occurs during + /// deserialization. + type Error: Error; + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_key` or `MapAccess::next_entry` instead. + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> + where + K: DeserializeSeed<'de>; + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_value` instead. + /// + /// # Panics + /// + /// Calling `next_value_seed` before `next_key_seed` is incorrect and is + /// allowed to panic or return bogus results. + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> + where + V: DeserializeSeed<'de>; + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// `MapAccess` implementations should override the default behavior if a + /// more efficient implementation is possible. + /// + /// `Deserialize` implementations should typically use + /// `MapAccess::next_entry` instead. + #[inline] + fn next_entry_seed<K, V>( + &mut self, + kseed: K, + vseed: V, + ) -> Result<Option<(K::Value, V::Value)>, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + match try!(self.next_key_seed(kseed)) { + Some(key) => { + let value = try!(self.next_value_seed(vseed)); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + /// This returns `Ok(Some(key))` for the next key in the map, or `Ok(None)` + /// if there are no more remaining entries. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_key<K>(&mut self) -> Result<Option<K>, Self::Error> + where + K: Deserialize<'de>, + { + self.next_key_seed(PhantomData) + } + + /// This returns a `Ok(value)` for the next value in the map. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + /// + /// # Panics + /// + /// Calling `next_value` before `next_key` is incorrect and is allowed to + /// panic or return bogus results. + #[inline] + fn next_value<V>(&mut self) -> Result<V, Self::Error> + where + V: Deserialize<'de>, + { + self.next_value_seed(PhantomData) + } + + /// This returns `Ok(Some((key, value)))` for the next (key-value) pair in + /// the map, or `Ok(None)` if there are no more remaining items. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `MapAccess` implementations should not override the default behavior. + #[inline] + fn next_entry<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + self.next_entry_seed(PhantomData, PhantomData) + } + + /// Returns the number of entries remaining in the map, if known. + #[inline] + fn size_hint(&self) -> Option<usize> { + None + } +} + +impl<'de, 'a, A> MapAccess<'de> for &'a mut A +where + A: MapAccess<'de>, +{ + type Error = A::Error; + + #[inline] + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> + where + K: DeserializeSeed<'de>, + { + (**self).next_key_seed(seed) + } + + #[inline] + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> + where + V: DeserializeSeed<'de>, + { + (**self).next_value_seed(seed) + } + + #[inline] + fn next_entry_seed<K, V>( + &mut self, + kseed: K, + vseed: V, + ) -> Result<Option<(K::Value, V::Value)>, Self::Error> + where + K: DeserializeSeed<'de>, + V: DeserializeSeed<'de>, + { + (**self).next_entry_seed(kseed, vseed) + } + + #[inline] + fn next_entry<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error> + where + K: Deserialize<'de>, + V: Deserialize<'de>, + { + (**self).next_entry() + } + + #[inline] + fn next_key<K>(&mut self) -> Result<Option<K>, Self::Error> + where + K: Deserialize<'de>, + { + (**self).next_key() + } + + #[inline] + fn next_value<V>(&mut self) -> Result<V, Self::Error> + where + V: Deserialize<'de>, + { + (**self).next_value() + } + + #[inline] + fn size_hint(&self) -> Option<usize> { + (**self).size_hint() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Provides a `Visitor` access to the data of an enum in the input. +/// +/// `EnumAccess` is created by the `Deserializer` and passed to the +/// `Visitor` in order to identify which variant of an enum to deserialize. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `EnumAccess` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait EnumAccess<'de>: Sized { + /// The error type that can be returned if some error occurs during + /// deserialization. + type Error: Error; + /// The `Visitor` that will be used to deserialize the content of the enum + /// variant. + type Variant: VariantAccess<'de, Error = Self::Error>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// `Deserialize` implementations should typically use `EnumAccess::variant` + /// instead. + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>; + + /// `variant` is called to identify which variant to deserialize. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `EnumAccess` implementations should not override the default behavior. + #[inline] + fn variant<V>(self) -> Result<(V, Self::Variant), Self::Error> + where + V: Deserialize<'de>, + { + self.variant_seed(PhantomData) + } +} + +/// `VariantAccess` is a visitor that is created by the `Deserializer` and +/// passed to the `Deserialize` to deserialize the content of a particular enum +/// variant. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed by the deserialized enum variant. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `VariantAccess` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait VariantAccess<'de>: Sized { + /// The error type that can be returned if some error occurs during + /// deserialization. Must match the error type of our `EnumAccess`. + type Error: Error; + + /// Called when deserializing a variant with no values. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2018 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// fn unit_variant(self) -> Result<(), Self::Error> { + /// // What the data actually contained; suppose it is a tuple variant. + /// let unexp = Unexpected::TupleVariant; + /// Err(de::Error::invalid_type(unexp, &"unit variant")) + /// } + /// # + /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn unit_variant(self) -> Result<(), Self::Error>; + + /// Called when deserializing a variant with a single value. + /// + /// `Deserialize` implementations should typically use + /// `VariantAccess::newtype_variant` instead. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2018 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error> + /// where + /// T: DeserializeSeed<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"newtype variant")) + /// } + /// # + /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeSeed<'de>; + + /// Called when deserializing a variant with a single value. + /// + /// This method exists as a convenience for `Deserialize` implementations. + /// `VariantAccess` implementations should not override the default + /// behavior. + #[inline] + fn newtype_variant<T>(self) -> Result<T, Self::Error> + where + T: Deserialize<'de>, + { + self.newtype_variant_seed(PhantomData) + } + + /// Called when deserializing a tuple-like variant. + /// + /// The `len` is the number of fields expected in the tuple variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2018 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// fn tuple_variant<V>( + /// self, + /// _len: usize, + /// _visitor: V, + /// ) -> Result<V::Value, Self::Error> + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"tuple variant")) + /// } + /// # + /// # fn struct_variant<V>(self, _: &[&str], _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; + + /// Called when deserializing a struct-like variant. + /// + /// The `fields` are the names of the fields of the struct variant. + /// + /// If the data contains a different type of variant, the following + /// `invalid_type` error should be constructed: + /// + /// ```edition2018 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, Unexpected}; + /// # + /// # struct X; + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// # fn newtype_variant_seed<T>(self, _: T) -> Result<T::Value, Self::Error> + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error> + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// fn struct_variant<V>( + /// self, + /// _fields: &'static [&'static str], + /// _visitor: V, + /// ) -> Result<V::Value, Self::Error> + /// where + /// V: Visitor<'de>, + /// { + /// // What the data actually contained; suppose it is a unit variant. + /// let unexp = Unexpected::UnitVariant; + /// Err(de::Error::invalid_type(unexp, &"struct variant")) + /// } + /// # } + /// ``` + fn struct_variant<V>( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Converts an existing value into a `Deserializer` from which other values can +/// be deserialized. +/// +/// # Lifetime +/// +/// The `'de` lifetime of this trait is the lifetime of data that may be +/// borrowed from the resulting `Deserializer`. See the page [Understanding +/// deserializer lifetimes] for a more detailed explanation of these lifetimes. +/// +/// [Understanding deserializer lifetimes]: https://serde.rs/lifetimes.html +/// +/// # Example +/// +/// ```edition2018 +/// use std::str::FromStr; +/// use serde::Deserialize; +/// use serde::de::{value, IntoDeserializer}; +/// +/// #[derive(Deserialize)] +/// enum Setting { +/// On, +/// Off, +/// } +/// +/// impl FromStr for Setting { +/// type Err = value::Error; +/// +/// fn from_str(s: &str) -> Result<Self, Self::Err> { +/// Self::deserialize(s.into_deserializer()) +/// } +/// } +/// ``` +pub trait IntoDeserializer<'de, E: Error = value::Error> { + /// The type of the deserializer being converted into. + type Deserializer: Deserializer<'de, Error = E>; + + /// Convert this value into a deserializer. + fn into_deserializer(self) -> Self::Deserializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Used in error messages. +/// +/// - expected `a` +/// - expected `a` or `b` +/// - expected one of `a`, `b`, `c` +/// +/// The slice of names must not be empty. +struct OneOf { + names: &'static [&'static str], +} + +impl Display for OneOf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.names.len() { + 0 => panic!(), // special case elsewhere + 1 => write!(formatter, "`{}`", self.names[0]), + 2 => write!(formatter, "`{}` or `{}`", self.names[0], self.names[1]), + _ => { + try!(write!(formatter, "one of ")); + for (i, alt) in self.names.iter().enumerate() { + if i > 0 { + try!(write!(formatter, ", ")); + } + try!(write!(formatter, "`{}`", alt)); + } + Ok(()) + } + } + } +} diff --git a/serde/src/de/utf8.rs b/serde/src/de/utf8.rs new file mode 100644 index 000000000..576fd03cf --- /dev/null +++ b/serde/src/de/utf8.rs @@ -0,0 +1,46 @@ +use lib::*; + +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +#[inline] +pub fn encode(c: char) -> Encode { + let code = c as u32; + let mut buf = [0; 4]; + let pos = if code < MAX_ONE_B { + buf[3] = code as u8; + 3 + } else if code < MAX_TWO_B { + buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B { + buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + 1 + } else { + buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; + buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + buf[3] = (code & 0x3F) as u8 | TAG_CONT; + 0 + }; + Encode { buf: buf, pos: pos } +} + +pub struct Encode { + buf: [u8; 4], + pos: usize, +} + +impl Encode { + pub fn as_str(&self) -> &str { + str::from_utf8(&self.buf[self.pos..]).unwrap() + } +} diff --git a/serde/src/de/value.rs b/serde/src/de/value.rs new file mode 100644 index 000000000..d0a185da2 --- /dev/null +++ b/serde/src/de/value.rs @@ -0,0 +1,1497 @@ +//! Building blocks for deserializing basic values using the `IntoDeserializer` +//! trait. +//! +//! ```edition2018 +//! use std::str::FromStr; +//! use serde::Deserialize; +//! use serde::de::{value, IntoDeserializer}; +//! +//! #[derive(Deserialize)] +//! enum Setting { +//! On, +//! Off, +//! } +//! +//! impl FromStr for Setting { +//! type Err = value::Error; +//! +//! fn from_str(s: &str) -> Result<Self, Self::Err> { +//! Self::deserialize(s.into_deserializer()) +//! } +//! } +//! ``` + +use lib::*; + +use self::private::{First, Second}; +use de::{self, Expected, IntoDeserializer, SeqAccess}; +use private::de::size_hint; +use ser; + +//////////////////////////////////////////////////////////////////////////////// + +// For structs that contain a PhantomData. We do not want the trait +// bound `E: Clone` inferred by derive(Clone). +macro_rules! impl_copy_clone { + ($ty:ident $(<$lifetime:tt>)*) => { + impl<$($lifetime,)* E> Copy for $ty<$($lifetime,)* E> {} + + impl<$($lifetime,)* E> Clone for $ty<$($lifetime,)* E> { + fn clone(&self) -> Self { + *self + } + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A minimal representation of all possible errors that can occur using the +/// `IntoDeserializer` trait. +#[derive(Clone, Debug, PartialEq)] +pub struct Error { + err: ErrorImpl, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +type ErrorImpl = Box<str>; +#[cfg(not(any(feature = "std", feature = "alloc")))] +type ErrorImpl = (); + +impl de::Error for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + #[cold] + fn custom<T>(msg: T) -> Self + where + T: Display, + { + Error { + err: msg.to_string().into_boxed_str(), + } + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + #[cold] + fn custom<T>(msg: T) -> Self + where + T: Display, + { + let _ = msg; + Error { err: () } + } +} + +impl ser::Error for Error { + #[cold] + fn custom<T>(msg: T) -> Self + where + T: Display, + { + de::Error::custom(msg) + } +} + +impl Display for Error { + #[cfg(any(feature = "std", feature = "alloc"))] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.write_str(&self.err) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.write_str("Serde deserialization error") + } +} + +#[cfg(feature = "std")] +impl error::Error for Error { + fn description(&self) -> &str { + &self.err + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<'de, E> IntoDeserializer<'de, E> for () +where + E: de::Error, +{ + type Deserializer = UnitDeserializer<E>; + + fn into_deserializer(self) -> UnitDeserializer<E> { + UnitDeserializer { + marker: PhantomData, + } + } +} + +/// A deserializer holding a `()`. +#[derive(Debug)] +pub struct UnitDeserializer<E> { + marker: PhantomData<E>, +} + +impl_copy_clone!(UnitDeserializer); + +impl<'de, E> de::Deserializer<'de> for UnitDeserializer<E> +where + E: de::Error, +{ + type Error = E; + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct newtype_struct seq tuple tuple_struct + map struct enum identifier ignored_any + } + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_none() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer that cannot be instantiated. +#[cfg(feature = "unstable")] +pub struct NeverDeserializer<E> { + never: !, + marker: PhantomData<E>, +} + +#[cfg(feature = "unstable")] +impl<'de, E> IntoDeserializer<'de, E> for ! +where + E: de::Error, +{ + type Deserializer = NeverDeserializer<E>; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +#[cfg(feature = "unstable")] +impl<'de, E> de::Deserializer<'de> for NeverDeserializer<E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + self.never + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! primitive_deserializer { + ($ty:ty, $doc:tt, $name:ident, $method:ident $($cast:tt)*) => { + #[doc = "A deserializer holding"] + #[doc = $doc] + #[derive(Debug)] + pub struct $name<E> { + value: $ty, + marker: PhantomData<E> + } + + impl_copy_clone!($name); + + impl<'de, E> IntoDeserializer<'de, E> for $ty + where + E: de::Error, + { + type Deserializer = $name<E>; + + fn into_deserializer(self) -> $name<E> { + $name { + value: self, + marker: PhantomData, + } + } + } + + impl<'de, E> de::Deserializer<'de> for $name<E> + where + E: de::Error, + { + type Error = E; + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str + string bytes byte_buf option unit unit_struct newtype_struct seq + tuple tuple_struct map struct enum identifier ignored_any + } + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.$method(self.value $($cast)*) + } + } + } +} + +primitive_deserializer!(bool, "a `bool`.", BoolDeserializer, visit_bool); +primitive_deserializer!(i8, "an `i8`.", I8Deserializer, visit_i8); +primitive_deserializer!(i16, "an `i16`.", I16Deserializer, visit_i16); +primitive_deserializer!(i32, "an `i32`.", I32Deserializer, visit_i32); +primitive_deserializer!(i64, "an `i64`.", I64Deserializer, visit_i64); +primitive_deserializer!(isize, "an `isize`.", IsizeDeserializer, visit_i64 as i64); +primitive_deserializer!(u8, "a `u8`.", U8Deserializer, visit_u8); +primitive_deserializer!(u16, "a `u16`.", U16Deserializer, visit_u16); +primitive_deserializer!(u64, "a `u64`.", U64Deserializer, visit_u64); +primitive_deserializer!(usize, "a `usize`.", UsizeDeserializer, visit_u64 as u64); +primitive_deserializer!(f32, "an `f32`.", F32Deserializer, visit_f32); +primitive_deserializer!(f64, "an `f64`.", F64Deserializer, visit_f64); +primitive_deserializer!(char, "a `char`.", CharDeserializer, visit_char); + +serde_if_integer128! { + primitive_deserializer!(i128, "an `i128`.", I128Deserializer, visit_i128); + primitive_deserializer!(u128, "a `u128`.", U128Deserializer, visit_u128); +} + +/// A deserializer holding a `u32`. +#[derive(Debug)] +pub struct U32Deserializer<E> { + value: u32, + marker: PhantomData<E>, +} + +impl_copy_clone!(U32Deserializer); + +impl<'de, E> IntoDeserializer<'de, E> for u32 +where + E: de::Error, +{ + type Deserializer = U32Deserializer<E>; + + fn into_deserializer(self) -> U32Deserializer<E> { + U32Deserializer { + value: self, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for U32Deserializer<E> +where + E: de::Error, +{ + type Error = E; + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_u32(self.value) + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } +} + +impl<'de, E> de::EnumAccess<'de> for U32Deserializer<E> +where + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly<E>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `&str`. +#[derive(Debug)] +pub struct StrDeserializer<'a, E> { + value: &'a str, + marker: PhantomData<E>, +} + +impl_copy_clone!(StrDeserializer<'de>); + +impl<'de, 'a, E> IntoDeserializer<'de, E> for &'a str +where + E: de::Error, +{ + type Deserializer = StrDeserializer<'a, E>; + + fn into_deserializer(self) -> StrDeserializer<'a, E> { + StrDeserializer { + value: self, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> de::Deserializer<'de> for StrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_str(self.value) + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +impl<'de, 'a, E> de::EnumAccess<'de> for StrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly<E>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `&str` with a lifetime tied to another +/// deserializer. +#[derive(Debug)] +pub struct BorrowedStrDeserializer<'de, E> { + value: &'de str, + marker: PhantomData<E>, +} + +impl_copy_clone!(BorrowedStrDeserializer<'de>); + +impl<'de, E> BorrowedStrDeserializer<'de, E> { + /// Create a new borrowed deserializer from the given string. + pub fn new(value: &'de str) -> BorrowedStrDeserializer<'de, E> { + BorrowedStrDeserializer { + value: value, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for BorrowedStrDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(self.value) + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +impl<'de, E> de::EnumAccess<'de> for BorrowedStrDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly<E>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `String`. +#[cfg(any(feature = "std", feature = "alloc"))] +#[derive(Debug)] +pub struct StringDeserializer<E> { + value: String, + marker: PhantomData<E>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<E> Clone for StringDeserializer<E> { + fn clone(&self) -> Self { + StringDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, E> IntoDeserializer<'de, E> for String +where + E: de::Error, +{ + type Deserializer = StringDeserializer<E>; + + fn into_deserializer(self) -> StringDeserializer<E> { + StringDeserializer { + value: self, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, E> de::Deserializer<'de> for StringDeserializer<E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_string(self.value) + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> de::EnumAccess<'de> for StringDeserializer<E> +where + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly<E>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `Cow<str>`. +#[cfg(any(feature = "std", feature = "alloc"))] +#[derive(Debug)] +pub struct CowStrDeserializer<'a, E> { + value: Cow<'a, str>, + marker: PhantomData<E>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, E> Clone for CowStrDeserializer<'a, E> { + fn clone(&self) -> Self { + CowStrDeserializer { + value: self.value.clone(), + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> IntoDeserializer<'de, E> for Cow<'a, str> +where + E: de::Error, +{ + type Deserializer = CowStrDeserializer<'a, E>; + + fn into_deserializer(self) -> CowStrDeserializer<'a, E> { + CowStrDeserializer { + value: self, + marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> de::Deserializer<'de> for CowStrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Cow::Borrowed(string) => visitor.visit_str(string), + Cow::Owned(string) => visitor.visit_string(string), + } + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, E> de::EnumAccess<'de> for CowStrDeserializer<'a, E> +where + E: de::Error, +{ + type Error = E; + type Variant = private::UnitOnly<E>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(private::unit_only) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `&[u8]` with a lifetime tied to another +/// deserializer. +#[derive(Debug)] +pub struct BorrowedBytesDeserializer<'de, E> { + value: &'de [u8], + marker: PhantomData<E>, +} + +impl_copy_clone!(BorrowedBytesDeserializer<'de>); + +impl<'de, E> BorrowedBytesDeserializer<'de, E> { + /// Create a new borrowed deserializer from the given byte slice. + pub fn new(value: &'de [u8]) -> BorrowedBytesDeserializer<'de, E> { + BorrowedBytesDeserializer { + value: value, + marker: PhantomData, + } + } +} + +impl<'de, E> de::Deserializer<'de> for BorrowedBytesDeserializer<'de, E> +where + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_bytes(self.value) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any enum + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer that iterates over a sequence. +#[derive(Clone, Debug)] +pub struct SeqDeserializer<I, E> { + iter: iter::Fuse<I>, + count: usize, + marker: PhantomData<E>, +} + +impl<I, E> SeqDeserializer<I, E> +where + I: Iterator, +{ + /// Construct a new `SeqDeserializer<I, E>`. + pub fn new(iter: I) -> Self { + SeqDeserializer { + iter: iter.fuse(), + count: 0, + marker: PhantomData, + } + } +} + +impl<I, E> SeqDeserializer<I, E> +where + I: Iterator, + E: de::Error, +{ + /// Check for remaining elements after passing a `SeqDeserializer` to + /// `Visitor::visit_seq`. + pub fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInSeq(self.count), + )) + } + } +} + +impl<'de, I, T, E> de::Deserializer<'de> for SeqDeserializer<I, E> +where + I: Iterator<Item = T>, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let v = try!(visitor.visit_seq(&mut self)); + try!(self.end()); + Ok(v) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de, I, T, E> de::SeqAccess<'de> for SeqDeserializer<I, E> +where + I: Iterator<Item = T>, + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed<V>(&mut self, seed: V) -> Result<Option<V::Value>, Self::Error> + where + V: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => { + self.count += 1; + seed.deserialize(value.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } +} + +struct ExpectedInSeq(usize); + +impl Expected for ExpectedInSeq { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "1 element in sequence") + } else { + write!(formatter, "{} elements in sequence", self.0) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, T, E> IntoDeserializer<'de, E> for Vec<T> +where + T: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, T, E> IntoDeserializer<'de, E> for BTreeSet<T> +where + T: IntoDeserializer<'de, E> + Eq + Ord, + E: de::Error, +{ + type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +#[cfg(feature = "std")] +impl<'de, T, S, E> IntoDeserializer<'de, E> for HashSet<T, S> +where + T: IntoDeserializer<'de, E> + Eq + Hash, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = SeqDeserializer<<Self as IntoIterator>::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + SeqDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `SeqAccess`. +#[derive(Clone, Debug)] +pub struct SeqAccessDeserializer<A> { + seq: A, +} + +impl<A> SeqAccessDeserializer<A> { + /// Construct a new `SeqAccessDeserializer<A>`. + pub fn new(seq: A) -> Self { + SeqAccessDeserializer { seq: seq } + } +} + +impl<'de, A> de::Deserializer<'de> for SeqAccessDeserializer<A> +where + A: de::SeqAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_seq(self.seq) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer that iterates over a map. +pub struct MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + iter: iter::Fuse<I>, + value: Option<Second<I::Item>>, + count: usize, + lifetime: PhantomData<&'de ()>, + error: PhantomData<E>, +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + /// Construct a new `MapDeserializer<I, E>`. + pub fn new(iter: I) -> Self { + MapDeserializer { + iter: iter.fuse(), + value: None, + count: 0, + lifetime: PhantomData, + error: PhantomData, + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + E: de::Error, +{ + /// Check for remaining elements after passing a `MapDeserializer` to + /// `Visitor::visit_map`. + pub fn end(self) -> Result<(), E> { + let remaining = self.iter.count(); + if remaining == 0 { + Ok(()) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length( + self.count + remaining, + &ExpectedInMap(self.count), + )) + } + } +} + +impl<'de, I, E> MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, +{ + fn next_pair(&mut self) -> Option<(First<I::Item>, Second<I::Item>)> { + match self.iter.next() { + Some(kv) => { + self.count += 1; + Some(private::Pair::split(kv)) + } + None => None, + } + } +} + +impl<'de, I, E> de::Deserializer<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First<I::Item>: IntoDeserializer<'de, E>, + Second<I::Item>: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let value = try!(visitor.visit_map(&mut self)); + try!(self.end()); + Ok(value) + } + + fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let value = try!(visitor.visit_seq(&mut self)); + try!(self.end()); + Ok(value) + } + + fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let _ = len; + self.deserialize_seq(visitor) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct tuple_struct map + struct enum identifier ignored_any + } +} + +impl<'de, I, E> de::MapAccess<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First<I::Item>: IntoDeserializer<'de, E>, + Second<I::Item>: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(key.into_deserializer()).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + let value = self.value.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let value = value.expect("MapAccess::visit_value called before visit_key"); + seed.deserialize(value.into_deserializer()) + } + + fn next_entry_seed<TK, TV>( + &mut self, + kseed: TK, + vseed: TV, + ) -> Result<Option<(TK::Value, TV::Value)>, Self::Error> + where + TK: de::DeserializeSeed<'de>, + TV: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((key, value)) => { + let key = try!(kseed.deserialize(key.into_deserializer())); + let value = try!(vseed.deserialize(value.into_deserializer())); + Ok(Some((key, value))) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } +} + +impl<'de, I, E> de::SeqAccess<'de> for MapDeserializer<'de, I, E> +where + I: Iterator, + I::Item: private::Pair, + First<I::Item>: IntoDeserializer<'de, E>, + Second<I::Item>: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.next_pair() { + Some((k, v)) => { + let de = PairDeserializer(k, v, PhantomData); + seed.deserialize(de).map(Some) + } + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } +} + +// Cannot #[derive(Clone)] because of the bound `Second<I::Item>: Clone`. +impl<'de, I, E> Clone for MapDeserializer<'de, I, E> +where + I: Iterator + Clone, + I::Item: private::Pair, + Second<I::Item>: Clone, +{ + fn clone(&self) -> Self { + MapDeserializer { + iter: self.iter.clone(), + value: self.value.clone(), + count: self.count, + lifetime: self.lifetime, + error: self.error, + } + } +} + +// Cannot #[derive(Debug)] because of the bound `Second<I::Item>: Debug`. +impl<'de, I, E> Debug for MapDeserializer<'de, I, E> +where + I: Iterator + Debug, + I::Item: private::Pair, + Second<I::Item>: Debug, +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_struct("MapDeserializer") + .field("iter", &self.iter) + .field("value", &self.value) + .field("count", &self.count) + .field("lifetime", &self.lifetime) + .field("error", &self.error) + .finish() + } +} + +// Used in the `impl SeqAccess for MapDeserializer` to visit the map as a +// sequence of pairs. +struct PairDeserializer<A, B, E>(A, B, PhantomData<E>); + +impl<'de, A, B, E> de::Deserializer<'de> for PairDeserializer<A, B, E> +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct tuple_struct map + struct enum identifier ignored_any + } + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let mut pair_visitor = PairVisitor(Some(self.0), Some(self.1), PhantomData); + let pair = try!(visitor.visit_seq(&mut pair_visitor)); + if pair_visitor.1.is_none() { + Ok(pair) + } else { + let remaining = pair_visitor.size_hint().unwrap(); + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(2 - remaining))) + } + } + + fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + if len == 2 { + self.deserialize_seq(visitor) + } else { + // First argument is the number of elements in the data, second + // argument is the number of elements expected by the Deserialize. + Err(de::Error::invalid_length(2, &ExpectedInSeq(len))) + } + } +} + +struct PairVisitor<A, B, E>(Option<A>, Option<B>, PhantomData<E>); + +impl<'de, A, B, E> de::SeqAccess<'de> for PairVisitor<A, B, E> +where + A: IntoDeserializer<'de, E>, + B: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Error = E; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + if let Some(k) = self.0.take() { + seed.deserialize(k.into_deserializer()).map(Some) + } else if let Some(v) = self.1.take() { + seed.deserialize(v.into_deserializer()).map(Some) + } else { + Ok(None) + } + } + + fn size_hint(&self) -> Option<usize> { + if self.0.is_some() { + Some(2) + } else if self.1.is_some() { + Some(1) + } else { + Some(0) + } + } +} + +struct ExpectedInMap(usize); + +impl Expected for ExpectedInMap { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + if self.0 == 1 { + write!(formatter, "1 element in map") + } else { + write!(formatter, "{} elements in map", self.0) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, K, V, E> IntoDeserializer<'de, E> for BTreeMap<K, V> +where + K: IntoDeserializer<'de, E> + Eq + Ord, + V: IntoDeserializer<'de, E>, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +#[cfg(feature = "std")] +impl<'de, K, V, S, E> IntoDeserializer<'de, E> for HashMap<K, V, S> +where + K: IntoDeserializer<'de, E> + Eq + Hash, + V: IntoDeserializer<'de, E>, + S: BuildHasher, + E: de::Error, +{ + type Deserializer = MapDeserializer<'de, <Self as IntoIterator>::IntoIter, E>; + + fn into_deserializer(self) -> Self::Deserializer { + MapDeserializer::new(self.into_iter()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A deserializer holding a `MapAccess`. +#[derive(Clone, Debug)] +pub struct MapAccessDeserializer<A> { + map: A, +} + +impl<A> MapAccessDeserializer<A> { + /// Construct a new `MapAccessDeserializer<A>`. + pub fn new(map: A) -> Self { + MapAccessDeserializer { map: map } + } +} + +impl<'de, A> de::Deserializer<'de> for MapAccessDeserializer<A> +where + A: de::MapAccess<'de>, +{ + type Error = A::Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_map(self.map) + } + + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +impl<'de, A> de::EnumAccess<'de> for MapAccessDeserializer<A> +where + A: de::MapAccess<'de>, +{ + type Error = A::Error; + type Variant = private::MapAsEnum<A>; + + fn variant_seed<T>(mut self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.map.next_key_seed(seed)? { + Some(key) => Ok((key, private::map_as_enum(self.map))), + None => Err(de::Error::invalid_type(de::Unexpected::Map, &"enum")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +mod private { + use lib::*; + + use de::{self, DeserializeSeed, Deserializer, MapAccess, Unexpected, VariantAccess, Visitor}; + + #[derive(Clone, Debug)] + pub struct UnitOnly<E> { + marker: PhantomData<E>, + } + + pub fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) { + ( + t, + UnitOnly { + marker: PhantomData, + }, + ) + } + + impl<'de, E> de::VariantAccess<'de> for UnitOnly<E> + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } + } + + #[derive(Clone, Debug)] + pub struct MapAsEnum<A> { + map: A, + } + + pub fn map_as_enum<A>(map: A) -> MapAsEnum<A> { + MapAsEnum { map: map } + } + + impl<'de, A> VariantAccess<'de> for MapAsEnum<A> + where + A: MapAccess<'de>, + { + type Error = A::Error; + + fn unit_variant(mut self) -> Result<(), Self::Error> { + self.map.next_value() + } + + fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeSeed<'de>, + { + self.map.next_value_seed(seed) + } + + fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.map.next_value_seed(SeedTupleVariant { + len: len, + visitor: visitor, + }) + } + + fn struct_variant<V>( + mut self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.map + .next_value_seed(SeedStructVariant { visitor: visitor }) + } + } + + struct SeedTupleVariant<V> { + len: usize, + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedTupleVariant<V> + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_tuple(self.len, self.visitor) + } + } + + struct SeedStructVariant<V> { + visitor: V, + } + + impl<'de, V> DeserializeSeed<'de> for SeedStructVariant<V> + where + V: Visitor<'de>, + { + type Value = V::Value; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(self.visitor) + } + } + + /// Avoid having to restate the generic types on `MapDeserializer`. The + /// `Iterator::Item` contains enough information to figure out K and V. + pub trait Pair { + type First; + type Second; + fn split(self) -> (Self::First, Self::Second); + } + + impl<A, B> Pair for (A, B) { + type First = A; + type Second = B; + fn split(self) -> (A, B) { + self + } + } + + pub type First<T> = <T as Pair>::First; + pub type Second<T> = <T as Pair>::Second; +} diff --git a/serde/src/export.rs b/serde/src/export.rs new file mode 100644 index 000000000..805f45abc --- /dev/null +++ b/serde/src/export.rs @@ -0,0 +1,36 @@ +pub use lib::clone::Clone; +pub use lib::convert::{From, Into}; +pub use lib::default::Default; +pub use lib::fmt::{self, Formatter}; +pub use lib::marker::PhantomData; +pub use lib::option::Option::{self, None, Some}; +pub use lib::result::Result::{self, Err, Ok}; + +pub use self::string::from_utf8_lossy; + +#[cfg(any(feature = "alloc", feature = "std"))] +pub use lib::Vec; + +mod string { + use lib::*; + + #[cfg(any(feature = "std", feature = "alloc"))] + pub fn from_utf8_lossy(bytes: &[u8]) -> Cow<str> { + String::from_utf8_lossy(bytes) + } + + // The generated code calls this like: + // + // let value = &_serde::export::from_utf8_lossy(bytes); + // Err(_serde::de::Error::unknown_variant(value, VARIANTS)) + // + // so it is okay for the return type to be different from the std case as long + // as the above works. + #[cfg(not(any(feature = "std", feature = "alloc")))] + pub fn from_utf8_lossy(bytes: &[u8]) -> &str { + // Three unicode replacement characters if it fails. They look like a + // white-on-black question mark. The user will recognize it as invalid + // UTF-8. + str::from_utf8(bytes).unwrap_or("\u{fffd}\u{fffd}\u{fffd}") + } +} diff --git a/serde/src/integer128.rs b/serde/src/integer128.rs new file mode 100644 index 000000000..7a24e50ad --- /dev/null +++ b/serde/src/integer128.rs @@ -0,0 +1,82 @@ +/// Conditional compilation depending on whether Serde is built with support for +/// 128-bit integers. +/// +/// Data formats that wish to support Rust compiler versions older than 1.26 may +/// place the i128 / u128 methods of their Serializer and Deserializer behind +/// this macro. +/// +/// Data formats that require a minimum Rust compiler version of at least 1.26 +/// do not need to bother with this macro and may assume support for 128-bit +/// integers. +/// +/// ```edition2018 +/// # use serde::private::ser::Error; +/// # +/// # struct MySerializer; +/// # +/// use serde::{serde_if_integer128, Serializer}; +/// +/// impl Serializer for MySerializer { +/// type Ok = (); +/// type Error = Error; +/// +/// fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> { +/// /* ... */ +/// # unimplemented!() +/// } +/// +/// /* ... */ +/// +/// serde_if_integer128! { +/// fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> { +/// /* ... */ +/// # unimplemented!() +/// } +/// +/// fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> { +/// /* ... */ +/// # unimplemented!() +/// } +/// } +/// # +/// # serde::__serialize_unimplemented! { +/// # bool i8 i16 i32 u8 u16 u32 u64 f32 f64 char str bytes none some +/// # unit unit_struct unit_variant newtype_struct newtype_variant seq +/// # tuple tuple_struct tuple_variant map struct struct_variant +/// # } +/// } +/// ``` +/// +/// When Serde is built with support for 128-bit integers, this macro expands +/// transparently into just the input tokens. +/// +/// ```edition2018 +/// macro_rules! serde_if_integer128 { +/// ($($tt:tt)*) => { +/// $($tt)* +/// }; +/// } +/// ``` +/// +/// When built without support for 128-bit integers, this macro expands to +/// nothing. +/// +/// ```edition2018 +/// macro_rules! serde_if_integer128 { +/// ($($tt:tt)*) => {}; +/// } +/// ``` +#[cfg(integer128)] +#[macro_export] +macro_rules! serde_if_integer128 { + ($($tt:tt)*) => { + $($tt)* + }; +} + +#[cfg(not(integer128))] +#[macro_export] +#[doc(hidden)] +macro_rules! serde_if_integer128 { + ($($tt:tt)*) => {}; +} diff --git a/serde/src/lib.rs b/serde/src/lib.rs new file mode 100644 index 000000000..021ae9b5a --- /dev/null +++ b/serde/src/lib.rs @@ -0,0 +1,254 @@ +//! # Serde +//! +//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data +//! structures efficiently and generically. +//! +//! The Serde ecosystem consists of data structures that know how to serialize +//! and deserialize themselves along with data formats that know how to +//! serialize and deserialize other things. Serde provides the layer by which +//! these two groups interact with each other, allowing any supported data +//! structure to be serialized and deserialized using any supported data format. +//! +//! See the Serde website [https://serde.rs/] for additional documentation and +//! usage examples. +//! +//! [https://serde.rs/]: https://serde.rs/ +//! +//! ## Design +//! +//! Where many other languages rely on runtime reflection for serializing data, +//! Serde is instead built on Rust's powerful trait system. A data structure +//! that knows how to serialize and deserialize itself is one that implements +//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive +//! attribute to automatically generate implementations at compile time). This +//! avoids any overhead of reflection or runtime type information. In fact in +//! many situations the interaction between data structure and data format can +//! be completely optimized away by the Rust compiler, leaving Serde +//! serialization to perform the same speed as a handwritten serializer for the +//! specific selection of data structure and data format. +//! +//! ## Data formats +//! +//! The following is a partial list of data formats that have been implemented +//! for Serde by the community. +//! +//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs. +//! - [Bincode], a compact binary format +//! used for IPC within the Servo rendering engine. +//! - [CBOR], a Concise Binary Object Representation designed for small message +//! size without the need for version negotiation. +//! - [YAML], a popular human-friendly configuration language that ain't markup +//! language. +//! - [MessagePack], an efficient binary format that resembles a compact JSON. +//! - [TOML], a minimal configuration format used by [Cargo]. +//! - [Pickle], a format common in the Python world. +//! - [RON], a Rusty Object Notation. +//! - [BSON], the data storage and network transfer format used by MongoDB. +//! - [Avro], a binary format used within Apache Hadoop, with support for schema +//! definition. +//! - [JSON5], A superset of JSON including some productions from ES5. +//! - [URL], the x-www-form-urlencoded format. +//! - [Envy], a way to deserialize environment variables into Rust structs. +//! *(deserialization only)* +//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into +//! Rust structs. *(deserialization only)* +//! +//! [JSON]: https://github.com/serde-rs/json +//! [Bincode]: https://github.com/TyOverby/bincode +//! [CBOR]: https://github.com/pyfisch/cbor +//! [YAML]: https://github.com/dtolnay/serde-yaml +//! [MessagePack]: https://github.com/3Hren/msgpack-rust +//! [TOML]: https://github.com/alexcrichton/toml-rs +//! [Pickle]: https://github.com/birkenfeld/serde-pickle +//! [RON]: https://github.com/ron-rs/ron +//! [BSON]: https://github.com/zonyitoo/bson-rs +//! [Avro]: https://github.com/flavray/avro-rs +//! [JSON5]: https://github.com/callum-oakley/json5-rs +//! [URL]: https://github.com/nox/serde_urlencoded +//! [Envy]: https://github.com/softprops/envy +//! [Envy Store]: https://github.com/softprops/envy-store +//! [Cargo]: http://doc.crates.io/manifest.html +//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html + +//////////////////////////////////////////////////////////////////////////////// + +// Serde types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/serde/1.0.91")] +// Support using Serde without the standard library! +#![cfg_attr(not(feature = "std"), no_std)] +// Unstable functionality only if the user asks for it. For tracking and +// discussion of these features please refer to this issue: +// +// https://github.com/serde-rs/serde/issues/812 +#![cfg_attr(feature = "unstable", feature(specialization, never_type))] +#![cfg_attr(feature = "alloc", feature(alloc))] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] +// Ignored clippy and clippy_pedantic lints +#![cfg_attr( + feature = "cargo-clippy", + allow( + // not available in our oldest supported compiler + const_static_lifetime, + empty_enum, + redundant_field_names, + // integer and float ser/de requires these sorts of casts + cast_possible_truncation, + cast_possible_wrap, + cast_precision_loss, + cast_sign_loss, + // things are often more readable this way + cast_lossless, + module_name_repetitions, + single_match_else, + type_complexity, + use_self, + zero_prefixed_literal, + // not practical + needless_pass_by_value, + similar_names, + // preference + doc_markdown, + ) +)] +// Rustc lints. +#![deny(missing_docs, unused_imports)] + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "alloc")] +extern crate alloc; + +/// A facade around all the types we need from the `std`, `core`, and `alloc` +/// crates. This avoids elaborate import wrangling having to happen in every +/// module. +mod lib { + mod core { + #[cfg(not(feature = "std"))] + pub use core::*; + #[cfg(feature = "std")] + pub use std::*; + } + + pub use self::core::{cmp, iter, mem, num, slice, str}; + pub use self::core::{f32, f64}; + pub use self::core::{i16, i32, i64, i8, isize}; + pub use self::core::{u16, u32, u64, u8, usize}; + + pub use self::core::cell::{Cell, RefCell}; + pub use self::core::clone::{self, Clone}; + pub use self::core::convert::{self, From, Into}; + pub use self::core::default::{self, Default}; + pub use self::core::fmt::{self, Debug, Display}; + pub use self::core::marker::{self, PhantomData}; + pub use self::core::ops::Range; + pub use self::core::option::{self, Option}; + pub use self::core::result::{self, Result}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::borrow::{Cow, ToOwned}; + #[cfg(feature = "std")] + pub use std::borrow::{Cow, ToOwned}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::string::{String, ToString}; + #[cfg(feature = "std")] + pub use std::string::String; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::vec::Vec; + #[cfg(feature = "std")] + pub use std::vec::Vec; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::boxed::Box; + #[cfg(feature = "std")] + pub use std::boxed::Box; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::rc::{Rc, Weak as RcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::rc::{Rc, Weak as RcWeak}; + + #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))] + pub use alloc::sync::{Arc, Weak as ArcWeak}; + #[cfg(all(feature = "rc", feature = "std"))] + pub use std::sync::{Arc, Weak as ArcWeak}; + + #[cfg(all(feature = "alloc", not(feature = "std")))] + pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + #[cfg(feature = "std")] + pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; + + #[cfg(feature = "std")] + pub use std::{error, net}; + + #[cfg(feature = "std")] + pub use std::collections::{HashMap, HashSet}; + #[cfg(feature = "std")] + pub use std::ffi::{CStr, CString, OsStr, OsString}; + #[cfg(feature = "std")] + pub use std::hash::{BuildHasher, Hash}; + #[cfg(feature = "std")] + pub use std::io::Write; + #[cfg(feature = "std")] + pub use std::num::Wrapping; + #[cfg(feature = "std")] + pub use std::path::{Path, PathBuf}; + #[cfg(feature = "std")] + pub use std::sync::{Mutex, RwLock}; + #[cfg(feature = "std")] + pub use std::time::{SystemTime, UNIX_EPOCH}; + + #[cfg(all(feature = "std", collections_bound))] + pub use std::collections::Bound; + + #[cfg(core_reverse)] + pub use self::core::cmp::Reverse; + + #[cfg(ops_bound)] + pub use self::core::ops::Bound; + + #[cfg(range_inclusive)] + pub use self::core::ops::RangeInclusive; + + #[cfg(any(core_duration, feature = "std"))] + pub use self::core::time::Duration; +} + +//////////////////////////////////////////////////////////////////////////////// + +#[macro_use] +mod macros; + +#[macro_use] +mod integer128; + +pub mod de; +pub mod ser; + +#[doc(inline)] +pub use de::{Deserialize, Deserializer}; +#[doc(inline)] +pub use ser::{Serialize, Serializer}; + +// Generated code uses these to support no_std. Not public API. +#[doc(hidden)] +pub mod export; + +// Helpers used by generated code and doc tests. Not public API. +#[doc(hidden)] +pub mod private; + +// Re-export #[derive(Serialize, Deserialize)]. +// +// The reason re-exporting is not enabled by default is that disabling it would +// be annoying for crates that provide handwritten impls or data formats. They +// would need to disable default features and then explicitly re-enable std. +#[cfg(feature = "serde_derive")] +#[allow(unused_imports)] +#[macro_use] +extern crate serde_derive; +#[cfg(feature = "serde_derive")] +#[doc(hidden)] +pub use serde_derive::*; diff --git a/serde/src/macros.rs b/serde/src/macros.rs new file mode 100644 index 000000000..57600a535 --- /dev/null +++ b/serde/src/macros.rs @@ -0,0 +1,236 @@ +// Super explicit first paragraph because this shows up at the top level and +// trips up people who are just looking for basic Serialize / Deserialize +// documentation. +// +/// Helper macro when implementing the `Deserializer` part of a new data format +/// for Serde. +/// +/// Some [`Deserializer`] implementations for self-describing formats do not +/// care what hint the [`Visitor`] gives them, they just want to blindly call +/// the [`Visitor`] method corresponding to the data they can tell is in the +/// input. This requires repetitive implementations of all the [`Deserializer`] +/// trait methods. +/// +/// ```edition2018 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// # impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error> +/// # where +/// # V: Visitor<'de>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// #[inline] +/// fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> +/// where +/// V: Visitor<'de>, +/// { +/// self.deserialize_any(visitor) +/// } +/// # +/// # forward_to_deserialize_any! { +/// # i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string +/// # bytes byte_buf option unit unit_struct newtype_struct seq tuple +/// # tuple_struct map struct enum identifier ignored_any +/// # } +/// # } +/// ``` +/// +/// The `forward_to_deserialize_any!` macro implements these simple forwarding +/// methods so that they forward directly to [`Deserializer::deserialize_any`]. +/// You can choose which methods to forward. +/// +/// ```edition2018 +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer; +/// # +/// impl<'de> Deserializer<'de> for MyDeserializer { +/// # type Error = value::Error; +/// # +/// fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> +/// where +/// V: Visitor<'de>, +/// { +/// /* ... */ +/// # let _ = visitor; +/// # unimplemented!() +/// } +/// +/// forward_to_deserialize_any! { +/// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string +/// bytes byte_buf option unit unit_struct newtype_struct seq tuple +/// tuple_struct map struct enum identifier ignored_any +/// } +/// } +/// ``` +/// +/// The macro assumes the convention that your `Deserializer` lifetime parameter +/// is called `'de` and that the `Visitor` type parameters on each method are +/// called `V`. A different type parameter and a different lifetime can be +/// specified explicitly if necessary. +/// +/// ```edition2018 +/// # use std::marker::PhantomData; +/// # +/// # use serde::forward_to_deserialize_any; +/// # use serde::de::{value, Deserializer, Visitor}; +/// # +/// # struct MyDeserializer<V>(PhantomData<V>); +/// # +/// # impl<'q, V> Deserializer<'q> for MyDeserializer<V> { +/// # type Error = value::Error; +/// # +/// # fn deserialize_any<W>(self, visitor: W) -> Result<W::Value, Self::Error> +/// # where +/// # W: Visitor<'q>, +/// # { +/// # unimplemented!() +/// # } +/// # +/// forward_to_deserialize_any! { +/// <W: Visitor<'q>> +/// bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string +/// bytes byte_buf option unit unit_struct newtype_struct seq tuple +/// tuple_struct map struct enum identifier ignored_any +/// } +/// # } +/// ``` +/// +/// [`Deserializer`]: trait.Deserializer.html +/// [`Visitor`]: de/trait.Visitor.html +/// [`Deserializer::deserialize_any`]: trait.Deserializer.html#tymethod.deserialize_any +#[macro_export(local_inner_macros)] +macro_rules! forward_to_deserialize_any { + (<$visitor:ident: Visitor<$lifetime:tt>> $($func:ident)*) => { + $(forward_to_deserialize_any_helper!{$func<$lifetime, $visitor>})* + }; + // This case must be after the previous one. + ($($func:ident)*) => { + $(forward_to_deserialize_any_helper!{$func<'de, V>})* + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! forward_to_deserialize_any_method { + ($func:ident<$l:tt, $v:ident>($($arg:ident : $ty:ty),*)) => { + #[inline] + fn $func<$v>(self, $($arg: $ty,)* visitor: $v) -> $crate::export::Result<$v::Value, Self::Error> + where + $v: $crate::de::Visitor<$l>, + { + $( + let _ = $arg; + )* + self.deserialize_any(visitor) + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! forward_to_deserialize_any_helper { + (bool<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bool<$l, $v>()} + }; + (i8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i8<$l, $v>()} + }; + (i16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i16<$l, $v>()} + }; + (i32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i32<$l, $v>()} + }; + (i64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_i64<$l, $v>()} + }; + (i128<$l:tt, $v:ident>) => { + serde_if_integer128! { + forward_to_deserialize_any_method!{deserialize_i128<$l, $v>()} + } + }; + (u8<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u8<$l, $v>()} + }; + (u16<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u16<$l, $v>()} + }; + (u32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u32<$l, $v>()} + }; + (u64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_u64<$l, $v>()} + }; + (u128<$l:tt, $v:ident>) => { + serde_if_integer128! { + forward_to_deserialize_any_method!{deserialize_u128<$l, $v>()} + } + }; + (f32<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f32<$l, $v>()} + }; + (f64<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_f64<$l, $v>()} + }; + (char<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_char<$l, $v>()} + }; + (str<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_str<$l, $v>()} + }; + (string<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_string<$l, $v>()} + }; + (bytes<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_bytes<$l, $v>()} + }; + (byte_buf<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_byte_buf<$l, $v>()} + }; + (option<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_option<$l, $v>()} + }; + (unit<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit<$l, $v>()} + }; + (unit_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_unit_struct<$l, $v>(name: &'static str)} + }; + (newtype_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_newtype_struct<$l, $v>(name: &'static str)} + }; + (seq<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_seq<$l, $v>()} + }; + (tuple<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple<$l, $v>(len: usize)} + }; + (tuple_struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_tuple_struct<$l, $v>(name: &'static str, len: usize)} + }; + (map<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_map<$l, $v>()} + }; + (struct<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_struct<$l, $v>(name: &'static str, fields: &'static [&'static str])} + }; + (enum<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_enum<$l, $v>(name: &'static str, variants: &'static [&'static str])} + }; + (identifier<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_identifier<$l, $v>()} + }; + (ignored_any<$l:tt, $v:ident>) => { + forward_to_deserialize_any_method!{deserialize_ignored_any<$l, $v>()} + }; +} diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs new file mode 100644 index 000000000..feb3d4c7b --- /dev/null +++ b/serde/src/private/de.rs @@ -0,0 +1,2935 @@ +use lib::*; + +use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use de::{MapAccess, Unexpected}; + +#[cfg(any(feature = "std", feature = "alloc"))] +pub use self::content::{ + Content, ContentDeserializer, ContentRefDeserializer, EnumDeserializer, + InternallyTaggedUnitVisitor, TagContentOtherField, TagContentOtherFieldVisitor, + TagOrContentField, TagOrContentFieldVisitor, TaggedContentVisitor, UntaggedUnitVisitor, +}; + +/// If the missing field is of type `Option<T>` then treat is as `None`, +/// otherwise it is an error. +pub fn missing_field<'de, V, E>(field: &'static str) -> Result<V, E> +where + V: Deserialize<'de>, + E: Error, +{ + struct MissingFieldDeserializer<E>(&'static str, PhantomData<E>); + + impl<'de, E> Deserializer<'de> for MissingFieldDeserializer<E> + where + E: Error, + { + type Error = E; + + fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + Err(Error::missing_field(self.0)) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + visitor.visit_none() + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } + } + + let deserializer = MissingFieldDeserializer(field, PhantomData); + Deserialize::deserialize(deserializer) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn borrow_cow_str<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, str>, D::Error> +where + D: Deserializer<'de>, +{ + struct CowStrVisitor; + + impl<'a> Visitor<'a> for CowStrVisitor { + type Value = Cow<'a, str>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v.to_owned())) + } + + fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Borrowed(v)) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v)) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(Cow::Owned(s.to_owned())), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E> + where + E: Error, + { + match str::from_utf8(v) { + Ok(s) => Ok(Cow::Borrowed(s)), + Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)), + } + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(Cow::Owned(s)), + Err(e) => Err(Error::invalid_value( + Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } + } + + deserializer.deserialize_str(CowStrVisitor) +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub fn borrow_cow_bytes<'de: 'a, 'a, D>(deserializer: D) -> Result<Cow<'a, [u8]>, D::Error> +where + D: Deserializer<'de>, +{ + struct CowBytesVisitor; + + impl<'a> Visitor<'a> for CowBytesVisitor { + type Value = Cow<'a, [u8]>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a byte array") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v.as_bytes().to_vec())) + } + + fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Borrowed(v.as_bytes())) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v.into_bytes())) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v.to_vec())) + } + + fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Borrowed(v)) + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: Error, + { + Ok(Cow::Owned(v)) + } + } + + deserializer.deserialize_bytes(CowBytesVisitor) +} + +pub mod size_hint { + use lib::*; + + pub fn from_bounds<I>(iter: &I) -> Option<usize> + where + I: Iterator, + { + helper(iter.size_hint()) + } + + #[inline] + pub fn cautious(hint: Option<usize>) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } + + fn helper(bounds: (usize, Option<usize>)) -> Option<usize> { + match bounds { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +mod content { + // This module is private and nothing here should be used outside of + // generated code. + // + // We will iterate on the implementation for a few releases and only have to + // worry about backward compatibility for the `untagged` and `tag` attributes + // rather than for this entire mechanism. + // + // This issue is tracking making some of this stuff public: + // https://github.com/serde-rs/serde/issues/741 + + use lib::*; + + use super::size_hint; + use de::{ + self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny, + MapAccess, SeqAccess, Unexpected, Visitor, + }; + + /// Used from generated code to buffer the contents of the Deserializer when + /// deserializing untagged enums and internally tagged enums. + /// + /// Not public API. Use serde-value instead. + #[derive(Debug)] + pub enum Content<'de> { + Bool(bool), + + U8(u8), + U16(u16), + U32(u32), + U64(u64), + + I8(i8), + I16(i16), + I32(i32), + I64(i64), + + F32(f32), + F64(f64), + + Char(char), + String(String), + Str(&'de str), + ByteBuf(Vec<u8>), + Bytes(&'de [u8]), + + None, + Some(Box<Content<'de>>), + + Unit, + Newtype(Box<Content<'de>>), + Seq(Vec<Content<'de>>), + Map(Vec<(Content<'de>, Content<'de>)>), + } + + impl<'de> Content<'de> { + pub fn as_str(&self) -> Option<&str> { + match *self { + Content::Str(x) => Some(x), + Content::String(ref x) => Some(x), + Content::Bytes(x) => str::from_utf8(x).ok(), + Content::ByteBuf(ref x) => str::from_utf8(x).ok(), + _ => None, + } + } + + #[cold] + fn unexpected(&self) -> Unexpected { + match *self { + Content::Bool(b) => Unexpected::Bool(b), + Content::U8(n) => Unexpected::Unsigned(n as u64), + Content::U16(n) => Unexpected::Unsigned(n as u64), + Content::U32(n) => Unexpected::Unsigned(n as u64), + Content::U64(n) => Unexpected::Unsigned(n), + Content::I8(n) => Unexpected::Signed(n as i64), + Content::I16(n) => Unexpected::Signed(n as i64), + Content::I32(n) => Unexpected::Signed(n as i64), + Content::I64(n) => Unexpected::Signed(n), + Content::F32(f) => Unexpected::Float(f as f64), + Content::F64(f) => Unexpected::Float(f), + Content::Char(c) => Unexpected::Char(c), + Content::String(ref s) => Unexpected::Str(s), + Content::Str(s) => Unexpected::Str(s), + Content::ByteBuf(ref b) => Unexpected::Bytes(b), + Content::Bytes(b) => Unexpected::Bytes(b), + Content::None | Content::Some(_) => Unexpected::Option, + Content::Unit => Unexpected::Unit, + Content::Newtype(_) => Unexpected::NewtypeStruct, + Content::Seq(_) => Unexpected::Seq, + Content::Map(_) => Unexpected::Map, + } + } + } + + impl<'de> Deserialize<'de> for Content<'de> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + // Untagged and internally tagged enums are only supported in + // self-describing formats. + let visitor = ContentVisitor { value: PhantomData }; + deserializer.deserialize_any(visitor) + } + } + + struct ContentVisitor<'de> { + value: PhantomData<Content<'de>>, + } + + impl<'de> ContentVisitor<'de> { + fn new() -> Self { + ContentVisitor { value: PhantomData } + } + } + + impl<'de> Visitor<'de> for ContentVisitor<'de> { + type Value = Content<'de>; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("any value") + } + + fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::Bool(value)) + } + + fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::I8(value)) + } + + fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::I16(value)) + } + + fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::I32(value)) + } + + fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::I64(value)) + } + + fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::U8(value)) + } + + fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::U16(value)) + } + + fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::U32(value)) + } + + fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::U64(value)) + } + + fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::F32(value)) + } + + fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::F64(value)) + } + + fn visit_char<F>(self, value: char) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::Char(value)) + } + + fn visit_str<F>(self, value: &str) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::String(value.into())) + } + + fn visit_borrowed_str<F>(self, value: &'de str) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::Str(value)) + } + + fn visit_string<F>(self, value: String) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::String(value)) + } + + fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::ByteBuf(value.into())) + } + + fn visit_borrowed_bytes<F>(self, value: &'de [u8]) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::Bytes(value)) + } + + fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::ByteBuf(value)) + } + + fn visit_unit<F>(self) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::Unit) + } + + fn visit_none<F>(self) -> Result<Self::Value, F> + where + F: de::Error, + { + Ok(Content::None) + } + + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(|v| Content::Some(Box::new(v))) + } + + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(|v| Content::Newtype(Box::new(v))) + } + + fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: SeqAccess<'de>, + { + let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); + while let Some(e) = try!(visitor.next_element()) { + vec.push(e); + } + Ok(Content::Seq(vec)) + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: MapAccess<'de>, + { + let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint())); + while let Some(kv) = try!(visitor.next_entry()) { + vec.push(kv); + } + Ok(Content::Map(vec)) + } + + fn visit_enum<V>(self, _visitor: V) -> Result<Self::Value, V::Error> + where + V: EnumAccess<'de>, + { + Err(de::Error::custom( + "untagged and internally tagged enums do not support enum input", + )) + } + } + + /// This is the type of the map keys in an internally tagged enum. + /// + /// Not public API. + pub enum TagOrContent<'de> { + Tag, + Content(Content<'de>), + } + + struct TagOrContentVisitor<'de> { + name: &'static str, + value: PhantomData<TagOrContent<'de>>, + } + + impl<'de> TagOrContentVisitor<'de> { + fn new(name: &'static str) -> Self { + TagOrContentVisitor { + name: name, + value: PhantomData, + } + } + } + + impl<'de> DeserializeSeed<'de> for TagOrContentVisitor<'de> { + type Value = TagOrContent<'de>; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + // Internally tagged enums are only supported in self-describing + // formats. + deserializer.deserialize_any(self) + } + } + + impl<'de> Visitor<'de> for TagOrContentVisitor<'de> { + type Value = TagOrContent<'de>; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "a type tag `{}` or any other value", self.name) + } + + fn visit_bool<F>(self, value: bool) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_bool(value) + .map(TagOrContent::Content) + } + + fn visit_i8<F>(self, value: i8) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_i8(value) + .map(TagOrContent::Content) + } + + fn visit_i16<F>(self, value: i16) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_i16(value) + .map(TagOrContent::Content) + } + + fn visit_i32<F>(self, value: i32) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_i32(value) + .map(TagOrContent::Content) + } + + fn visit_i64<F>(self, value: i64) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_i64(value) + .map(TagOrContent::Content) + } + + fn visit_u8<F>(self, value: u8) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_u8(value) + .map(TagOrContent::Content) + } + + fn visit_u16<F>(self, value: u16) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_u16(value) + .map(TagOrContent::Content) + } + + fn visit_u32<F>(self, value: u32) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_u32(value) + .map(TagOrContent::Content) + } + + fn visit_u64<F>(self, value: u64) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_u64(value) + .map(TagOrContent::Content) + } + + fn visit_f32<F>(self, value: f32) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_f32(value) + .map(TagOrContent::Content) + } + + fn visit_f64<F>(self, value: f64) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_f64(value) + .map(TagOrContent::Content) + } + + fn visit_char<F>(self, value: char) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_char(value) + .map(TagOrContent::Content) + } + + fn visit_str<F>(self, value: &str) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_str(value) + .map(TagOrContent::Content) + } + } + + fn visit_borrowed_str<F>(self, value: &'de str) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_borrowed_str(value) + .map(TagOrContent::Content) + } + } + + fn visit_string<F>(self, value: String) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_string(value) + .map(TagOrContent::Content) + } + } + + fn visit_bytes<F>(self, value: &[u8]) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_bytes(value) + .map(TagOrContent::Content) + } + } + + fn visit_borrowed_bytes<F>(self, value: &'de [u8]) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_borrowed_bytes(value) + .map(TagOrContent::Content) + } + } + + fn visit_byte_buf<F>(self, value: Vec<u8>) -> Result<Self::Value, F> + where + F: de::Error, + { + if value == self.name.as_bytes() { + Ok(TagOrContent::Tag) + } else { + ContentVisitor::new() + .visit_byte_buf(value) + .map(TagOrContent::Content) + } + } + + fn visit_unit<F>(self) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_unit() + .map(TagOrContent::Content) + } + + fn visit_none<F>(self) -> Result<Self::Value, F> + where + F: de::Error, + { + ContentVisitor::new() + .visit_none() + .map(TagOrContent::Content) + } + + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + ContentVisitor::new() + .visit_some(deserializer) + .map(TagOrContent::Content) + } + + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + ContentVisitor::new() + .visit_newtype_struct(deserializer) + .map(TagOrContent::Content) + } + + fn visit_seq<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where + V: SeqAccess<'de>, + { + ContentVisitor::new() + .visit_seq(visitor) + .map(TagOrContent::Content) + } + + fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where + V: MapAccess<'de>, + { + ContentVisitor::new() + .visit_map(visitor) + .map(TagOrContent::Content) + } + + fn visit_enum<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where + V: EnumAccess<'de>, + { + ContentVisitor::new() + .visit_enum(visitor) + .map(TagOrContent::Content) + } + } + + /// Used by generated code to deserialize an internally tagged enum. + /// + /// Not public API. + pub struct TaggedContent<'de, T> { + pub tag: T, + pub content: Content<'de>, + } + + /// Not public API. + pub struct TaggedContentVisitor<'de, T> { + tag_name: &'static str, + value: PhantomData<TaggedContent<'de, T>>, + } + + impl<'de, T> TaggedContentVisitor<'de, T> { + /// Visitor for the content of an internally tagged enum with the given + /// tag name. + pub fn new(name: &'static str) -> Self { + TaggedContentVisitor { + tag_name: name, + value: PhantomData, + } + } + } + + impl<'de, T> DeserializeSeed<'de> for TaggedContentVisitor<'de, T> + where + T: Deserialize<'de>, + { + type Value = TaggedContent<'de, T>; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + // Internally tagged enums are only supported in self-describing + // formats. + deserializer.deserialize_any(self) + } + } + + impl<'de, T> Visitor<'de> for TaggedContentVisitor<'de, T> + where + T: Deserialize<'de>, + { + type Value = TaggedContent<'de, T>; + + fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str("internally tagged enum") + } + + fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error> + where + S: SeqAccess<'de>, + { + let tag = match try!(seq.next_element()) { + Some(tag) => tag, + None => { + return Err(de::Error::missing_field(self.tag_name)); + } + }; + let rest = de::value::SeqAccessDeserializer::new(seq); + Ok(TaggedContent { + tag: tag, + content: try!(Content::deserialize(rest)), + }) + } + + fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> + where + M: MapAccess<'de>, + { + let mut tag = None; + let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint())); + while let Some(k) = try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) { + match k { + TagOrContent::Tag => { + if tag.is_some() { + return Err(de::Error::duplicate_field(self.tag_name)); + } + tag = Some(try!(map.next_value())); + } + TagOrContent::Content(k) => { + let v = try!(map.next_value()); + vec.push((k, v)); + } + } + } + match tag { + None => Err(de::Error::missing_field(self.tag_name)), + Some(tag) => Ok(TaggedContent { + tag: tag, + content: Content::Map(vec), + }), + } + } + } + + /// Used by generated code to deserialize an adjacently tagged enum. + /// + /// Not public API. + pub enum TagOrContentField { + Tag, + Content, + } + + /// Not public API. + pub struct TagOrContentFieldVisitor { + pub tag: &'static str, + pub content: &'static str, + } + + impl<'de> DeserializeSeed<'de> for TagOrContentFieldVisitor { + type Value = TagOrContentField; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } + } + + impl<'de> Visitor<'de> for TagOrContentFieldVisitor { + type Value = TagOrContentField; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "{:?} or {:?}", self.tag, self.content) + } + + fn visit_str<E>(self, field: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + if field == self.tag { + Ok(TagOrContentField::Tag) + } else if field == self.content { + Ok(TagOrContentField::Content) + } else { + Err(de::Error::invalid_value(Unexpected::Str(field), &self)) + } + } + } + + /// Used by generated code to deserialize an adjacently tagged enum when + /// ignoring unrelated fields is allowed. + /// + /// Not public API. + pub enum TagContentOtherField { + Tag, + Content, + Other, + } + + /// Not public API. + pub struct TagContentOtherFieldVisitor { + pub tag: &'static str, + pub content: &'static str, + } + + impl<'de> DeserializeSeed<'de> for TagContentOtherFieldVisitor { + type Value = TagContentOtherField; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } + } + + impl<'de> Visitor<'de> for TagContentOtherFieldVisitor { + type Value = TagContentOtherField; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "{:?}, {:?}, or other ignored fields", + self.tag, self.content + ) + } + + fn visit_str<E>(self, field: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + if field == self.tag { + Ok(TagContentOtherField::Tag) + } else if field == self.content { + Ok(TagContentOtherField::Content) + } else { + Ok(TagContentOtherField::Other) + } + } + } + + /// Not public API + pub struct ContentDeserializer<'de, E> { + content: Content<'de>, + err: PhantomData<E>, + } + + impl<'de, E> ContentDeserializer<'de, E> + where + E: de::Error, + { + #[cold] + fn invalid_type(self, exp: &Expected) -> E { + de::Error::invalid_type(self.content.unexpected(), exp) + } + + fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match self.content { + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + } + + fn visit_content_seq<'de, V, E>(content: Vec<Content<'de>>, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + E: de::Error, + { + let seq = content.into_iter().map(ContentDeserializer::new); + let mut seq_visitor = de::value::SeqDeserializer::new(seq); + let value = try!(visitor.visit_seq(&mut seq_visitor)); + try!(seq_visitor.end()); + Ok(value) + } + + fn visit_content_map<'de, V, E>( + content: Vec<(Content<'de>, Content<'de>)>, + visitor: V, + ) -> Result<V::Value, E> + where + V: Visitor<'de>, + E: de::Error, + { + let map = content + .into_iter() + .map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v))); + let mut map_visitor = de::value::MapDeserializer::new(map); + let value = try!(visitor.visit_map(&mut map_visitor)); + try!(map_visitor.end()); + Ok(value) + } + + /// Used when deserializing an internally tagged enum because the content + /// will be used exactly once. + impl<'de, E> Deserializer<'de> for ContentDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Bool(v) => visitor.visit_bool(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::Char(v) => visitor.visit_char(v), + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Unit => visitor.visit_unit(), + Content::None => visitor.visit_none(), + Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)), + Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)), + Content::Seq(v) => visit_content_seq(v, visitor), + Content::Map(v) => visit_content_map(v, visitor), + } + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::F64(v) => visitor.visit_f64(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Char(v) => visitor.visit_char(v), + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(v) => visit_content_seq(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::None => visitor.visit_none(), + Content::Some(v) => visitor.visit_some(ContentDeserializer::new(*v)), + Content::Unit => visitor.visit_unit(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Unit => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + // As a special case, allow deserializing untagged newtype + // variant containing unit struct. + // + // #[derive(Deserialize)] + // struct Info; + // + // #[derive(Deserialize)] + // #[serde(tag = "topic")] + // enum Message { + // Info(Info), + // } + // + // We want {"topic":"Info"} to deserialize even though + // ordinarily unit structs do not deserialize from empty map. + Content::Map(ref v) if v.is_empty() => visitor.visit_unit(), + _ => self.deserialize_any(visitor), + } + } + + fn deserialize_newtype_struct<V>( + self, + _name: &str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Newtype(v) => visitor.visit_newtype_struct(ContentDeserializer::new(*v)), + _ => visitor.visit_newtype_struct(self), + } + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Seq(v) => visit_content_seq(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct<V>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Map(v) => visit_content_map(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct<V>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::Seq(v) => visit_content_seq(v, visitor), + Content::Map(v) => visit_content_map(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + let (variant, value) = match self.content { + Content::Map(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + s @ Content::String(_) | s @ Content::Str(_) => (s, None), + other => { + return Err(de::Error::invalid_type( + other.unexpected(), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumDeserializer::new(variant, value)) + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self.content { + Content::String(v) => visitor.visit_string(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(v) => visitor.visit_byte_buf(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::U8(v) => visitor.visit_u8(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } + } + + impl<'de, E> ContentDeserializer<'de, E> { + /// private API, don't use + pub fn new(content: Content<'de>) -> Self { + ContentDeserializer { + content: content, + err: PhantomData, + } + } + } + + pub struct EnumDeserializer<'de, E> + where + E: de::Error, + { + variant: Content<'de>, + value: Option<Content<'de>>, + err: PhantomData<E>, + } + + impl<'de, E> EnumDeserializer<'de, E> + where + E: de::Error, + { + pub fn new(variant: Content<'de>, value: Option<Content<'de>>) -> EnumDeserializer<'de, E> { + EnumDeserializer { + variant: variant, + value: value, + err: PhantomData, + } + } + } + + impl<'de, E> de::EnumAccess<'de> for EnumDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + type Variant = VariantDeserializer<'de, Self::Error>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), E> + where + V: de::DeserializeSeed<'de>, + { + let visitor = VariantDeserializer { + value: self.value, + err: PhantomData, + }; + seed.deserialize(ContentDeserializer::new(self.variant)) + .map(|v| (v, visitor)) + } + } + + pub struct VariantDeserializer<'de, E> + where + E: de::Error, + { + value: Option<Content<'de>>, + err: PhantomData<E>, + } + + impl<'de, E> de::VariantAccess<'de> for VariantDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), E> { + match self.value { + Some(value) => de::Deserialize::deserialize(ContentDeserializer::new(value)), + None => Ok(()), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, E> + where + T: de::DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Some(Content::Seq(v)) => { + de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Some(Content::Map(v)) => { + de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + } + Some(Content::Seq(v)) => { + de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + _ => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } + } + } + + struct SeqDeserializer<'de, E> + where + E: de::Error, + { + iter: <Vec<Content<'de>> as IntoIterator>::IntoIter, + err: PhantomData<E>, + } + + impl<'de, E> SeqDeserializer<'de, E> + where + E: de::Error, + { + fn new(vec: Vec<Content<'de>>) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + err: PhantomData, + } + } + } + + impl<'de, E> de::Deserializer<'de> for SeqDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + #[inline] + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = try!(visitor.visit_seq(&mut self)); + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(de::Error::invalid_length(len, &"fewer elements in array")) + } + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } + } + + impl<'de, E> de::SeqAccess<'de> for SeqDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } + } + + struct MapDeserializer<'de, E> + where + E: de::Error, + { + iter: <Vec<(Content<'de>, Content<'de>)> as IntoIterator>::IntoIter, + value: Option<Content<'de>>, + err: PhantomData<E>, + } + + impl<'de, E> MapDeserializer<'de, E> + where + E: de::Error, + { + fn new(map: Vec<(Content<'de>, Content<'de>)>) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + err: PhantomData, + } + } + } + + impl<'de, E> de::MapAccess<'de> for MapDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + seed.deserialize(ContentDeserializer::new(key)).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } + } + + impl<'de, E> de::Deserializer<'de> for MapDeserializer<'de, E> + where + E: de::Error, + { + type Error = E; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_map(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } + } + + /// Not public API. + pub struct ContentRefDeserializer<'a, 'de: 'a, E> { + content: &'a Content<'de>, + err: PhantomData<E>, + } + + impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + #[cold] + fn invalid_type(self, exp: &Expected) -> E { + de::Error::invalid_type(self.content.unexpected(), exp) + } + + fn deserialize_integer<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match *self.content { + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + } + + fn visit_content_seq_ref<'a, 'de, V, E>( + content: &'a [Content<'de>], + visitor: V, + ) -> Result<V::Value, E> + where + V: Visitor<'de>, + E: de::Error, + { + let seq = content.iter().map(ContentRefDeserializer::new); + let mut seq_visitor = de::value::SeqDeserializer::new(seq); + let value = try!(visitor.visit_seq(&mut seq_visitor)); + try!(seq_visitor.end()); + Ok(value) + } + + fn visit_content_map_ref<'a, 'de, V, E>( + content: &'a [(Content<'de>, Content<'de>)], + visitor: V, + ) -> Result<V::Value, E> + where + V: Visitor<'de>, + E: de::Error, + { + let map = content.iter().map(|&(ref k, ref v)| { + ( + ContentRefDeserializer::new(k), + ContentRefDeserializer::new(v), + ) + }); + let mut map_visitor = de::value::MapDeserializer::new(map); + let value = try!(visitor.visit_map(&mut map_visitor)); + try!(map_visitor.end()); + Ok(value) + } + + /// Used when deserializing an untagged enum because the content may need + /// to be used more than once. + impl<'de, 'a, E> Deserializer<'de> for ContentRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match *self.content { + Content::Bool(v) => visitor.visit_bool(v), + Content::U8(v) => visitor.visit_u8(v), + Content::U16(v) => visitor.visit_u16(v), + Content::U32(v) => visitor.visit_u32(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I8(v) => visitor.visit_i8(v), + Content::I16(v) => visitor.visit_i16(v), + Content::I32(v) => visitor.visit_i32(v), + Content::I64(v) => visitor.visit_i64(v), + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::Char(v) => visitor.visit_char(v), + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Unit => visitor.visit_unit(), + Content::None => visitor.visit_none(), + Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)), + Content::Newtype(ref v) => { + visitor.visit_newtype_struct(ContentRefDeserializer::new(v)) + } + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + Content::Map(ref v) => visit_content_map_ref(v, visitor), + } + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_integer(visitor) + } + + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::F32(v) => visitor.visit_f32(v), + Content::F64(v) => visitor.visit_f64(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::F64(v) => visitor.visit_f64(v), + Content::U64(v) => visitor.visit_u64(v), + Content::I64(v) => visitor.visit_i64(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Char(v) => visitor.visit_char(v), + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match *self.content { + Content::None => visitor.visit_none(), + Content::Some(ref v) => visitor.visit_some(ContentRefDeserializer::new(v)), + Content::Unit => visitor.visit_unit(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Unit => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, E> + where + V: Visitor<'de>, + { + match *self.content { + Content::Newtype(ref v) => { + visitor.visit_newtype_struct(ContentRefDeserializer::new(v)) + } + _ => visitor.visit_newtype_struct(self), + } + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct<V>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Map(ref v) => visit_content_map_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct<V>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::Seq(ref v) => visit_content_seq_ref(v, visitor), + Content::Map(ref v) => visit_content_map_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + let (variant, value) = match *self.content { + Content::Map(ref value) => { + let mut iter = value.iter(); + let &(ref variant, ref value) = match iter.next() { + Some(v) => v, + None => { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(de::Error::invalid_value( + de::Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None), + ref other => { + return Err(de::Error::invalid_type( + other.unexpected(), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumRefDeserializer { + variant: variant, + value: value, + err: PhantomData, + }) + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self.content { + Content::String(ref v) => visitor.visit_str(v), + Content::Str(v) => visitor.visit_borrowed_str(v), + Content::ByteBuf(ref v) => visitor.visit_bytes(v), + Content::Bytes(v) => visitor.visit_borrowed_bytes(v), + Content::U8(v) => visitor.visit_u8(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + } + + impl<'a, 'de, E> ContentRefDeserializer<'a, 'de, E> { + /// private API, don't use + pub fn new(content: &'a Content<'de>) -> Self { + ContentRefDeserializer { + content: content, + err: PhantomData, + } + } + } + + struct EnumRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + variant: &'a Content<'de>, + value: Option<&'a Content<'de>>, + err: PhantomData<E>, + } + + impl<'de, 'a, E> de::EnumAccess<'de> for EnumRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + type Variant = VariantRefDeserializer<'a, 'de, Self::Error>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let visitor = VariantRefDeserializer { + value: self.value, + err: PhantomData, + }; + seed.deserialize(ContentRefDeserializer::new(self.variant)) + .map(|v| (v, visitor)) + } + } + + struct VariantRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + value: Option<&'a Content<'de>>, + err: PhantomData<E>, + } + + impl<'de, 'a, E> de::VariantAccess<'de> for VariantRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn unit_variant(self) -> Result<(), E> { + match self.value { + Some(value) => de::Deserialize::deserialize(ContentRefDeserializer::new(value)), + None => Ok(()), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, E> + where + T: de::DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Some(&Content::Seq(ref v)) => { + de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Some(&Content::Map(ref v)) => { + de::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor) + } + Some(&Content::Seq(ref v)) => { + de::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + } + Some(other) => Err(de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + _ => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } + } + } + + struct SeqRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + iter: <&'a [Content<'de>] as IntoIterator>::IntoIter, + err: PhantomData<E>, + } + + impl<'a, 'de, E> SeqRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + fn new(slice: &'a [Content<'de>]) -> Self { + SeqRefDeserializer { + iter: slice.iter(), + err: PhantomData, + } + } + } + + impl<'de, 'a, E> de::Deserializer<'de> for SeqRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + #[inline] + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = try!(visitor.visit_seq(&mut self)); + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(de::Error::invalid_length(len, &"fewer elements in array")) + } + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } + } + + impl<'de, 'a, E> de::SeqAccess<'de> for SeqRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed + .deserialize(ContentRefDeserializer::new(value)) + .map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } + } + + struct MapRefDeserializer<'a, 'de: 'a, E> + where + E: de::Error, + { + iter: <&'a [(Content<'de>, Content<'de>)] as IntoIterator>::IntoIter, + value: Option<&'a Content<'de>>, + err: PhantomData<E>, + } + + impl<'a, 'de, E> MapRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + fn new(map: &'a [(Content<'de>, Content<'de>)]) -> Self { + MapRefDeserializer { + iter: map.iter(), + value: None, + err: PhantomData, + } + } + } + + impl<'de, 'a, E> de::MapAccess<'de> for MapRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(&(ref key, ref value)) => { + self.value = Some(value); + seed.deserialize(ContentRefDeserializer::new(key)).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), + None => Err(de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option<usize> { + size_hint::from_bounds(&self.iter) + } + } + + impl<'de, 'a, E> de::Deserializer<'de> for MapRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Error = E; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_map(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } + } + + impl<'de, E> de::IntoDeserializer<'de, E> for ContentDeserializer<'de, E> + where + E: de::Error, + { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } + } + + impl<'de, 'a, E> de::IntoDeserializer<'de, E> for ContentRefDeserializer<'a, 'de, E> + where + E: de::Error, + { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } + } + + /// Visitor for deserializing an internally tagged unit variant. + /// + /// Not public API. + pub struct InternallyTaggedUnitVisitor<'a> { + type_name: &'a str, + variant_name: &'a str, + } + + impl<'a> InternallyTaggedUnitVisitor<'a> { + /// Not public API. + pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { + InternallyTaggedUnitVisitor { + type_name: type_name, + variant_name: variant_name, + } + } + } + + impl<'de, 'a> Visitor<'de> for InternallyTaggedUnitVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "unit variant {}::{}", + self.type_name, self.variant_name + ) + } + + fn visit_seq<S>(self, _: S) -> Result<(), S::Error> + where + S: SeqAccess<'de>, + { + Ok(()) + } + + fn visit_map<M>(self, mut access: M) -> Result<(), M::Error> + where + M: MapAccess<'de>, + { + while let Some(_) = try!(access.next_entry::<IgnoredAny, IgnoredAny>()) {} + Ok(()) + } + } + + /// Visitor for deserializing an untagged unit variant. + /// + /// Not public API. + pub struct UntaggedUnitVisitor<'a> { + type_name: &'a str, + variant_name: &'a str, + } + + impl<'a> UntaggedUnitVisitor<'a> { + /// Not public API. + pub fn new(type_name: &'a str, variant_name: &'a str) -> Self { + UntaggedUnitVisitor { + type_name: type_name, + variant_name: variant_name, + } + } + } + + impl<'de, 'a> Visitor<'de> for UntaggedUnitVisitor<'a> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "unit variant {}::{}", + self.type_name, self.variant_name + ) + } + + fn visit_unit<E>(self) -> Result<(), E> + where + E: de::Error, + { + Ok(()) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Like `IntoDeserializer` but also implemented for `&[u8]`. This is used for +// the newtype fallthrough case of `field_identifier`. +// +// #[derive(Deserialize)] +// #[serde(field_identifier)] +// enum F { +// A, +// B, +// Other(String), // deserialized using IdentifierDeserializer +// } +pub trait IdentifierDeserializer<'de, E: Error> { + type Deserializer: Deserializer<'de, Error = E>; + + fn from(self) -> Self::Deserializer; +} + +impl<'de, E> IdentifierDeserializer<'de, E> for u32 +where + E: Error, +{ + type Deserializer = <u32 as IntoDeserializer<'de, E>>::Deserializer; + + fn from(self) -> Self::Deserializer { + self.into_deserializer() + } +} + +pub struct StrDeserializer<'a, E> { + value: &'a str, + marker: PhantomData<E>, +} + +impl<'a, E> IdentifierDeserializer<'a, E> for &'a str +where + E: Error, +{ + type Deserializer = StrDeserializer<'a, E>; + + fn from(self) -> Self::Deserializer { + StrDeserializer { + value: self, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> Deserializer<'de> for StrDeserializer<'a, E> +where + E: Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_str(self.value) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +pub struct BytesDeserializer<'a, E> { + value: &'a [u8], + marker: PhantomData<E>, +} + +impl<'a, E> IdentifierDeserializer<'a, E> for &'a [u8] +where + E: Error, +{ + type Deserializer = BytesDeserializer<'a, E>; + + fn from(self) -> Self::Deserializer { + BytesDeserializer { + value: self, + marker: PhantomData, + } + } +} + +impl<'de, 'a, E> Deserializer<'de> for BytesDeserializer<'a, E> +where + E: Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_bytes(self.value) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +/// A DeserializeSeed helper for implementing deserialize_in_place Visitors. +/// +/// Wraps a mutable reference and calls deserialize_in_place on it. +pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T); + +impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T> +where + T: Deserialize<'de>, +{ + type Value = (); + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + T::deserialize_in_place(deserializer, self.0) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapDeserializer<'a, 'de: 'a, E>( + pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>, + pub PhantomData<E>, +); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E> +where + E: Error, +{ + fn deserialize_other<V>() -> Result<V, E> { + Err(Error::custom("can only flatten structs and maps")) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! forward_to_deserialize_other { + ($($func:ident ( $($arg:ty),* ))*) => { + $( + fn $func<V>(self, $(_: $arg,)* _visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + Self::deserialize_other() + } + )* + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E> +where + E: Error, +{ + type Error = E; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_map(FlatInternallyTaggedAccess { + iter: self.0.iter_mut(), + pending: None, + _marker: PhantomData, + }) + } + + fn deserialize_enum<V>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + for item in self.0.iter_mut() { + // items in the vector are nulled out when used. So we can only use + // an item if it's still filled in and if the field is one we care + // about. + let use_item = match *item { + None => false, + Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)), + }; + + if use_item { + let (key, value) = item.take().unwrap(); + return visitor.visit_enum(EnumDeserializer::new(key, Some(value))); + } + } + + Err(Error::custom(format_args!( + "no variant of enum {} found in flattened data", + name + ))) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_map(FlatMapAccess::new(self.0.iter())) + } + + fn deserialize_struct<V>( + self, + _: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields)) + } + + fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match visitor.__private_visit_untagged_option(self) { + Ok(value) => Ok(value), + Err(()) => Self::deserialize_other(), + } + } + + forward_to_deserialize_other! { + deserialize_bool() + deserialize_i8() + deserialize_i16() + deserialize_i32() + deserialize_i64() + deserialize_u8() + deserialize_u16() + deserialize_u32() + deserialize_u64() + deserialize_f32() + deserialize_f64() + deserialize_char() + deserialize_str() + deserialize_string() + deserialize_bytes() + deserialize_byte_buf() + deserialize_unit() + deserialize_unit_struct(&'static str) + deserialize_seq() + deserialize_tuple(usize) + deserialize_tuple_struct(&'static str, usize) + deserialize_identifier() + deserialize_ignored_any() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapAccess<'a, 'de: 'a, E> { + iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, + pending_content: Option<&'a Content<'de>>, + _marker: PhantomData<E>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> { + fn new( + iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, + ) -> FlatMapAccess<'a, 'de, E> { + FlatMapAccess { + iter: iter, + pending_content: None, + _marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> +where + E: Error, +{ + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeSeed<'de>, + { + while let Some(item) = self.iter.next() { + // Items in the vector are nulled out when used by a struct. + if let Some((ref key, ref content)) = *item { + self.pending_content = Some(content); + return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); + } + } + Ok(None) + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeSeed<'de>, + { + match self.pending_content.take() { + Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), + None => Err(Error::custom("value is missing")), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatStructAccess<'a, 'de: 'a, E> { + iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, + pending_content: Option<Content<'de>>, + fields: &'static [&'static str], + _marker: PhantomData<E>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> { + fn new( + iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, + fields: &'static [&'static str], + ) -> FlatStructAccess<'a, 'de, E> { + FlatStructAccess { + iter: iter, + pending_content: None, + fields: fields, + _marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E> +where + E: Error, +{ + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeSeed<'de>, + { + while let Some(item) = self.iter.next() { + // items in the vector are nulled out when used. So we can only use + // an item if it's still filled in and if the field is one we care + // about. In case we do not know which fields we want, we take them all. + let use_item = match *item { + None => false, + Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)), + }; + + if use_item { + let (key, content) = item.take().unwrap(); + self.pending_content = Some(content); + return seed.deserialize(ContentDeserializer::new(key)).map(Some); + } + } + Ok(None) + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeSeed<'de>, + { + match self.pending_content.take() { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(Error::custom("value is missing")), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> { + iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, + pending: Option<&'a Content<'de>>, + _marker: PhantomData<E>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E> +where + E: Error, +{ + type Error = E; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeSeed<'de>, + { + while let Some(item) = self.iter.next() { + if let Some((ref key, ref content)) = *item { + // Do not take(), instead borrow this entry. The internally tagged + // enum does its own buffering so we can't tell whether this entry + // is going to be consumed. Borrowing here leaves the entry + // available for later flattened fields. + self.pending = Some(content); + return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); + } + } + Ok(None) + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeSeed<'de>, + { + match self.pending.take() { + Some(value) => seed.deserialize(ContentRefDeserializer::new(value)), + None => panic!("value is missing"), + } + } +} diff --git a/serde/src/private/macros.rs b/serde/src/private/macros.rs new file mode 100644 index 000000000..4f7054f5d --- /dev/null +++ b/serde/src/private/macros.rs @@ -0,0 +1,140 @@ +#[doc(hidden)] +#[macro_export] +macro_rules! __private_serialize { + () => { + trait Serialize { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: $crate::Serializer; + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __private_deserialize { + () => { + trait Deserialize<'de>: Sized { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: $crate::Deserializer<'de>; + } + }; +} + +/// Used only by Serde doc tests. Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented { + ($($func:ident)*) => { + $( + __serialize_unimplemented_helper!($func); + )* + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __serialize_unimplemented_method { + ($func:ident $(<$t:ident>)* ($($arg:ty),*) -> $ret:ident) => { + fn $func $(<$t: ?Sized + $crate::Serialize>)* (self $(, _: $arg)*) -> $crate::export::Result<Self::$ret, Self::Error> { + unimplemented!() + } + }; +} + +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! __serialize_unimplemented_helper { + (bool) => { + __serialize_unimplemented_method!(serialize_bool(bool) -> Ok); + }; + (i8) => { + __serialize_unimplemented_method!(serialize_i8(i8) -> Ok); + }; + (i16) => { + __serialize_unimplemented_method!(serialize_i16(i16) -> Ok); + }; + (i32) => { + __serialize_unimplemented_method!(serialize_i32(i32) -> Ok); + }; + (i64) => { + __serialize_unimplemented_method!(serialize_i64(i64) -> Ok); + }; + (u8) => { + __serialize_unimplemented_method!(serialize_u8(u8) -> Ok); + }; + (u16) => { + __serialize_unimplemented_method!(serialize_u16(u16) -> Ok); + }; + (u32) => { + __serialize_unimplemented_method!(serialize_u32(u32) -> Ok); + }; + (u64) => { + __serialize_unimplemented_method!(serialize_u64(u64) -> Ok); + }; + (f32) => { + __serialize_unimplemented_method!(serialize_f32(f32) -> Ok); + }; + (f64) => { + __serialize_unimplemented_method!(serialize_f64(f64) -> Ok); + }; + (char) => { + __serialize_unimplemented_method!(serialize_char(char) -> Ok); + }; + (str) => { + __serialize_unimplemented_method!(serialize_str(&str) -> Ok); + }; + (bytes) => { + __serialize_unimplemented_method!(serialize_bytes(&[u8]) -> Ok); + }; + (none) => { + __serialize_unimplemented_method!(serialize_none() -> Ok); + }; + (some) => { + __serialize_unimplemented_method!(serialize_some<T>(&T) -> Ok); + }; + (unit) => { + __serialize_unimplemented_method!(serialize_unit() -> Ok); + }; + (unit_struct) => { + __serialize_unimplemented_method!(serialize_unit_struct(&str) -> Ok); + }; + (unit_variant) => { + __serialize_unimplemented_method!(serialize_unit_variant(&str, u32, &str) -> Ok); + }; + (newtype_struct) => { + __serialize_unimplemented_method!(serialize_newtype_struct<T>(&str, &T) -> Ok); + }; + (newtype_variant) => { + __serialize_unimplemented_method!(serialize_newtype_variant<T>(&str, u32, &str, &T) -> Ok); + }; + (seq) => { + type SerializeSeq = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_seq(Option<usize>) -> SerializeSeq); + }; + (tuple) => { + type SerializeTuple = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_tuple(usize) -> SerializeTuple); + }; + (tuple_struct) => { + type SerializeTupleStruct = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_tuple_struct(&str, usize) -> SerializeTupleStruct); + }; + (tuple_variant) => { + type SerializeTupleVariant = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_tuple_variant(&str, u32, &str, usize) -> SerializeTupleVariant); + }; + (map) => { + type SerializeMap = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_map(Option<usize>) -> SerializeMap); + }; + (struct) => { + type SerializeStruct = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_struct(&str, usize) -> SerializeStruct); + }; + (struct_variant) => { + type SerializeStructVariant = $crate::ser::Impossible<Self::Ok, Self::Error>; + __serialize_unimplemented_method!(serialize_struct_variant(&str, u32, &str, usize) -> SerializeStructVariant); + }; +} diff --git a/serde/src/private/mod.rs b/serde/src/private/mod.rs new file mode 100644 index 000000000..79e0a7d00 --- /dev/null +++ b/serde/src/private/mod.rs @@ -0,0 +1,4 @@ +mod macros; + +pub mod de; +pub mod ser; diff --git a/serde/src/private/ser.rs b/serde/src/private/ser.rs new file mode 100644 index 000000000..05f7e40af --- /dev/null +++ b/serde/src/private/ser.rs @@ -0,0 +1,1326 @@ +use lib::*; + +use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use self::content::{ + Content, ContentSerializer, SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue, +}; + +/// Used to check that serde(getter) attributes return the expected type. +/// Not public API. +pub fn constrain<T: ?Sized>(t: &T) -> &T { + t +} + +/// Not public API. +pub fn serialize_tagged_newtype<S, T>( + serializer: S, + type_ident: &'static str, + variant_ident: &'static str, + tag: &'static str, + variant_name: &'static str, + value: &T, +) -> Result<S::Ok, S::Error> +where + S: Serializer, + T: Serialize, +{ + value.serialize(TaggedSerializer { + type_ident: type_ident, + variant_ident: variant_ident, + tag: tag, + variant_name: variant_name, + delegate: serializer, + }) +} + +struct TaggedSerializer<S> { + type_ident: &'static str, + variant_ident: &'static str, + tag: &'static str, + variant_name: &'static str, + delegate: S, +} + +enum Unsupported { + Boolean, + Integer, + Float, + Char, + String, + ByteArray, + Optional, + Unit, + #[cfg(any(feature = "std", feature = "alloc"))] + UnitStruct, + Sequence, + Tuple, + TupleStruct, + Enum, +} + +impl Display for Unsupported { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match *self { + Unsupported::Boolean => formatter.write_str("a boolean"), + Unsupported::Integer => formatter.write_str("an integer"), + Unsupported::Float => formatter.write_str("a float"), + Unsupported::Char => formatter.write_str("a char"), + Unsupported::String => formatter.write_str("a string"), + Unsupported::ByteArray => formatter.write_str("a byte array"), + Unsupported::Optional => formatter.write_str("an optional"), + Unsupported::Unit => formatter.write_str("unit"), + #[cfg(any(feature = "std", feature = "alloc"))] + Unsupported::UnitStruct => formatter.write_str("unit struct"), + Unsupported::Sequence => formatter.write_str("a sequence"), + Unsupported::Tuple => formatter.write_str("a tuple"), + Unsupported::TupleStruct => formatter.write_str("a tuple struct"), + Unsupported::Enum => formatter.write_str("an enum"), + } + } +} + +impl<S> TaggedSerializer<S> +where + S: Serializer, +{ + fn bad_type(self, what: Unsupported) -> S::Error { + ser::Error::custom(format_args!( + "cannot serialize tagged newtype variant {}::{} containing {}", + self.type_ident, self.variant_ident, what + )) + } +} + +impl<S> Serializer for TaggedSerializer<S> +where + S: Serializer, +{ + type Ok = S::Ok; + type Error = S::Error; + + type SerializeSeq = Impossible<S::Ok, S::Error>; + type SerializeTuple = Impossible<S::Ok, S::Error>; + type SerializeTupleStruct = Impossible<S::Ok, S::Error>; + type SerializeMap = S::SerializeMap; + type SerializeStruct = S::SerializeStruct; + + #[cfg(not(any(feature = "std", feature = "alloc")))] + type SerializeTupleVariant = Impossible<S::Ok, S::Error>; + #[cfg(any(feature = "std", feature = "alloc"))] + type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>; + + #[cfg(not(any(feature = "std", feature = "alloc")))] + type SerializeStructVariant = Impossible<S::Ok, S::Error>; + #[cfg(any(feature = "std", feature = "alloc"))] + type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>; + + fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Boolean)) + } + + fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Char)) + } + + fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::String)) + } + + fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::ByteArray)) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Optional)) + } + + fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(self.bad_type(Unsupported::Optional)) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Unit)) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { + let mut map = try!(self.delegate.serialize_map(Some(1))); + try!(map.serialize_entry(self.tag, self.variant_name)); + map.end() + } + + fn serialize_unit_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + let mut map = try!(self.delegate.serialize_map(Some(2))); + try!(map.serialize_entry(self.tag, self.variant_name)); + try!(map.serialize_entry(inner_variant, &())); + map.end() + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + inner_value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + let mut map = try!(self.delegate.serialize_map(Some(2))); + try!(map.serialize_entry(self.tag, self.variant_name)); + try!(map.serialize_entry(inner_variant, inner_value)); + map.end() + } + + fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(self.bad_type(Unsupported::Sequence)) + } + + fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(self.bad_type(Unsupported::Tuple)) + } + + fn serialize_tuple_struct( + self, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(self.bad_type(Unsupported::TupleStruct)) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + // Lack of push-based serialization means we need to buffer the content + // of the tuple variant, so it requires std. + Err(self.bad_type(Unsupported::Enum)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + let mut map = try!(self.delegate.serialize_map(Some(2))); + try!(map.serialize_entry(self.tag, self.variant_name)); + try!(map.serialize_key(inner_variant)); + Ok(SerializeTupleVariantAsMapValue::new( + map, + inner_variant, + len, + )) + } + + fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1))); + try!(map.serialize_entry(self.tag, self.variant_name)); + Ok(map) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + let mut state = try!(self.delegate.serialize_struct(name, len + 1)); + try!(state.serialize_field(self.tag, self.variant_name)); + Ok(state) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + // Lack of push-based serialization means we need to buffer the content + // of the struct variant, so it requires std. + Err(self.bad_type(Unsupported::Enum)) + } + + #[cfg(any(feature = "std", feature = "alloc"))] + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + let mut map = try!(self.delegate.serialize_map(Some(2))); + try!(map.serialize_entry(self.tag, self.variant_name)); + try!(map.serialize_key(inner_variant)); + Ok(SerializeStructVariantAsMapValue::new( + map, + inner_variant, + len, + )) + } + + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error> + where + T: Display, + { + Err(self.bad_type(Unsupported::String)) + } +} + +/// Used only by Serde doc tests. Not public API. +#[doc(hidden)] +#[derive(Debug)] +pub struct Error; + +impl ser::Error for Error { + fn custom<T>(_: T) -> Self + where + T: Display, + { + unimplemented!() + } +} + +#[cfg(feature = "std")] +impl error::Error for Error { + fn description(&self) -> &str { + unimplemented!() + } +} + +impl Display for Error { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +mod content { + use lib::*; + + use ser::{self, Serialize, Serializer}; + + pub struct SerializeTupleVariantAsMapValue<M> { + map: M, + name: &'static str, + fields: Vec<Content>, + } + + impl<M> SerializeTupleVariantAsMapValue<M> { + pub fn new(map: M, name: &'static str, len: usize) -> Self { + SerializeTupleVariantAsMapValue { + map: map, + name: name, + fields: Vec::with_capacity(len), + } + } + } + + impl<M> ser::SerializeTupleVariant for SerializeTupleVariantAsMapValue<M> + where + M: ser::SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), M::Error> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<M::Error>::new())); + self.fields.push(value); + Ok(()) + } + + fn end(mut self) -> Result<M::Ok, M::Error> { + try!(self + .map + .serialize_value(&Content::TupleStruct(self.name, self.fields))); + self.map.end() + } + } + + pub struct SerializeStructVariantAsMapValue<M> { + map: M, + name: &'static str, + fields: Vec<(&'static str, Content)>, + } + + impl<M> SerializeStructVariantAsMapValue<M> { + pub fn new(map: M, name: &'static str, len: usize) -> Self { + SerializeStructVariantAsMapValue { + map: map, + name: name, + fields: Vec::with_capacity(len), + } + } + } + + impl<M> ser::SerializeStructVariant for SerializeStructVariantAsMapValue<M> + where + M: ser::SerializeMap, + { + type Ok = M::Ok; + type Error = M::Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), M::Error> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<M::Error>::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(mut self) -> Result<M::Ok, M::Error> { + try!(self + .map + .serialize_value(&Content::Struct(self.name, self.fields))); + self.map.end() + } + } + + #[derive(Debug)] + pub enum Content { + Bool(bool), + + U8(u8), + U16(u16), + U32(u32), + U64(u64), + + I8(i8), + I16(i16), + I32(i32), + I64(i64), + + F32(f32), + F64(f64), + + Char(char), + String(String), + Bytes(Vec<u8>), + + None, + Some(Box<Content>), + + Unit, + UnitStruct(&'static str), + UnitVariant(&'static str, u32, &'static str), + NewtypeStruct(&'static str, Box<Content>), + NewtypeVariant(&'static str, u32, &'static str, Box<Content>), + + Seq(Vec<Content>), + Tuple(Vec<Content>), + TupleStruct(&'static str, Vec<Content>), + TupleVariant(&'static str, u32, &'static str, Vec<Content>), + Map(Vec<(Content, Content)>), + Struct(&'static str, Vec<(&'static str, Content)>), + StructVariant( + &'static str, + u32, + &'static str, + Vec<(&'static str, Content)>, + ), + } + + impl Serialize for Content { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + Content::Bool(b) => serializer.serialize_bool(b), + Content::U8(u) => serializer.serialize_u8(u), + Content::U16(u) => serializer.serialize_u16(u), + Content::U32(u) => serializer.serialize_u32(u), + Content::U64(u) => serializer.serialize_u64(u), + Content::I8(i) => serializer.serialize_i8(i), + Content::I16(i) => serializer.serialize_i16(i), + Content::I32(i) => serializer.serialize_i32(i), + Content::I64(i) => serializer.serialize_i64(i), + Content::F32(f) => serializer.serialize_f32(f), + Content::F64(f) => serializer.serialize_f64(f), + Content::Char(c) => serializer.serialize_char(c), + Content::String(ref s) => serializer.serialize_str(s), + Content::Bytes(ref b) => serializer.serialize_bytes(b), + Content::None => serializer.serialize_none(), + Content::Some(ref c) => serializer.serialize_some(&**c), + Content::Unit => serializer.serialize_unit(), + Content::UnitStruct(n) => serializer.serialize_unit_struct(n), + Content::UnitVariant(n, i, v) => serializer.serialize_unit_variant(n, i, v), + Content::NewtypeStruct(n, ref c) => serializer.serialize_newtype_struct(n, &**c), + Content::NewtypeVariant(n, i, v, ref c) => { + serializer.serialize_newtype_variant(n, i, v, &**c) + } + Content::Seq(ref elements) => elements.serialize(serializer), + Content::Tuple(ref elements) => { + use ser::SerializeTuple; + let mut tuple = try!(serializer.serialize_tuple(elements.len())); + for e in elements { + try!(tuple.serialize_element(e)); + } + tuple.end() + } + Content::TupleStruct(n, ref fields) => { + use ser::SerializeTupleStruct; + let mut ts = try!(serializer.serialize_tuple_struct(n, fields.len())); + for f in fields { + try!(ts.serialize_field(f)); + } + ts.end() + } + Content::TupleVariant(n, i, v, ref fields) => { + use ser::SerializeTupleVariant; + let mut tv = try!(serializer.serialize_tuple_variant(n, i, v, fields.len())); + for f in fields { + try!(tv.serialize_field(f)); + } + tv.end() + } + Content::Map(ref entries) => { + use ser::SerializeMap; + let mut map = try!(serializer.serialize_map(Some(entries.len()))); + for &(ref k, ref v) in entries { + try!(map.serialize_entry(k, v)); + } + map.end() + } + Content::Struct(n, ref fields) => { + use ser::SerializeStruct; + let mut s = try!(serializer.serialize_struct(n, fields.len())); + for &(k, ref v) in fields { + try!(s.serialize_field(k, v)); + } + s.end() + } + Content::StructVariant(n, i, v, ref fields) => { + use ser::SerializeStructVariant; + let mut sv = try!(serializer.serialize_struct_variant(n, i, v, fields.len())); + for &(k, ref v) in fields { + try!(sv.serialize_field(k, v)); + } + sv.end() + } + } + } + } + + pub struct ContentSerializer<E> { + error: PhantomData<E>, + } + + impl<E> ContentSerializer<E> { + pub fn new() -> Self { + ContentSerializer { error: PhantomData } + } + } + + impl<E> Serializer for ContentSerializer<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + type SerializeSeq = SerializeSeq<E>; + type SerializeTuple = SerializeTuple<E>; + type SerializeTupleStruct = SerializeTupleStruct<E>; + type SerializeTupleVariant = SerializeTupleVariant<E>; + type SerializeMap = SerializeMap<E>; + type SerializeStruct = SerializeStruct<E>; + type SerializeStructVariant = SerializeStructVariant<E>; + + fn serialize_bool(self, v: bool) -> Result<Content, E> { + Ok(Content::Bool(v)) + } + + fn serialize_i8(self, v: i8) -> Result<Content, E> { + Ok(Content::I8(v)) + } + + fn serialize_i16(self, v: i16) -> Result<Content, E> { + Ok(Content::I16(v)) + } + + fn serialize_i32(self, v: i32) -> Result<Content, E> { + Ok(Content::I32(v)) + } + + fn serialize_i64(self, v: i64) -> Result<Content, E> { + Ok(Content::I64(v)) + } + + fn serialize_u8(self, v: u8) -> Result<Content, E> { + Ok(Content::U8(v)) + } + + fn serialize_u16(self, v: u16) -> Result<Content, E> { + Ok(Content::U16(v)) + } + + fn serialize_u32(self, v: u32) -> Result<Content, E> { + Ok(Content::U32(v)) + } + + fn serialize_u64(self, v: u64) -> Result<Content, E> { + Ok(Content::U64(v)) + } + + fn serialize_f32(self, v: f32) -> Result<Content, E> { + Ok(Content::F32(v)) + } + + fn serialize_f64(self, v: f64) -> Result<Content, E> { + Ok(Content::F64(v)) + } + + fn serialize_char(self, v: char) -> Result<Content, E> { + Ok(Content::Char(v)) + } + + fn serialize_str(self, value: &str) -> Result<Content, E> { + Ok(Content::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<Content, E> { + Ok(Content::Bytes(value.to_owned())) + } + + fn serialize_none(self) -> Result<Content, E> { + Ok(Content::None) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Content, E> + where + T: Serialize, + { + Ok(Content::Some(Box::new(try!(value.serialize(self))))) + } + + fn serialize_unit(self) -> Result<Content, E> { + Ok(Content::Unit) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result<Content, E> { + Ok(Content::UnitStruct(name)) + } + + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result<Content, E> { + Ok(Content::UnitVariant(name, variant_index, variant)) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + name: &'static str, + value: &T, + ) -> Result<Content, E> + where + T: Serialize, + { + Ok(Content::NewtypeStruct( + name, + Box::new(try!(value.serialize(self))), + )) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<Content, E> + where + T: Serialize, + { + Ok(Content::NewtypeVariant( + name, + variant_index, + variant, + Box::new(try!(value.serialize(self))), + )) + } + + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, E> { + Ok(SerializeSeq { + elements: Vec::with_capacity(len.unwrap_or(0)), + error: PhantomData, + }) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, E> { + Ok(SerializeTuple { + elements: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, E> { + Ok(SerializeTupleStruct { + name: name, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, E> { + Ok(SerializeTupleVariant { + name: name, + variant_index: variant_index, + variant: variant, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, E> { + Ok(SerializeMap { + entries: Vec::with_capacity(len.unwrap_or(0)), + key: None, + error: PhantomData, + }) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, E> { + Ok(SerializeStruct { + name: name, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeStructVariant, E> { + Ok(SerializeStructVariant { + name: name, + variant_index: variant_index, + variant: variant, + fields: Vec::with_capacity(len), + error: PhantomData, + }) + } + } + + pub struct SerializeSeq<E> { + elements: Vec<Content>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeSeq for SerializeSeq<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.elements.push(value); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::Seq(self.elements)) + } + } + + pub struct SerializeTuple<E> { + elements: Vec<Content>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeTuple for SerializeTuple<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.elements.push(value); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::Tuple(self.elements)) + } + } + + pub struct SerializeTupleStruct<E> { + name: &'static str, + fields: Vec<Content>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeTupleStruct for SerializeTupleStruct<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::TupleStruct(self.name, self.fields)) + } + } + + pub struct SerializeTupleVariant<E> { + name: &'static str, + variant_index: u32, + variant: &'static str, + fields: Vec<Content>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeTupleVariant for SerializeTupleVariant<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::TupleVariant( + self.name, + self.variant_index, + self.variant, + self.fields, + )) + } + } + + pub struct SerializeMap<E> { + entries: Vec<(Content, Content)>, + key: Option<Content>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeMap for SerializeMap<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), E> + where + T: Serialize, + { + let key = try!(key.serialize(ContentSerializer::<E>::new())); + self.key = Some(key); + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), E> + where + T: Serialize, + { + let key = self + .key + .take() + .expect("serialize_value called before serialize_key"); + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.entries.push((key, value)); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::Map(self.entries)) + } + + fn serialize_entry<K: ?Sized, V: ?Sized>(&mut self, key: &K, value: &V) -> Result<(), E> + where + K: Serialize, + V: Serialize, + { + let key = try!(key.serialize(ContentSerializer::<E>::new())); + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.entries.push((key, value)); + Ok(()) + } + } + + pub struct SerializeStruct<E> { + name: &'static str, + fields: Vec<(&'static str, Content)>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeStruct for SerializeStruct<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::Struct(self.name, self.fields)) + } + } + + pub struct SerializeStructVariant<E> { + name: &'static str, + variant_index: u32, + variant: &'static str, + fields: Vec<(&'static str, Content)>, + error: PhantomData<E>, + } + + impl<E> ser::SerializeStructVariant for SerializeStructVariant<E> + where + E: ser::Error, + { + type Ok = Content; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), E> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<E>::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result<Content, E> { + Ok(Content::StructVariant( + self.name, + self.variant_index, + self.variant, + self.fields, + )) + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializer<'a, M: 'a>(pub &'a mut M); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializer<'a, M> +where + M: SerializeMap + 'a, +{ + fn bad_type(self, what: Unsupported) -> M::Error { + ser::Error::custom(format_args!( + "can only flatten structs and maps (got {})", + what + )) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> Serializer for FlatMapSerializer<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + type SerializeSeq = Impossible<Self::Ok, M::Error>; + type SerializeTuple = Impossible<Self::Ok, M::Error>; + type SerializeTupleStruct = Impossible<Self::Ok, M::Error>; + type SerializeMap = FlatMapSerializeMap<'a, M>; + type SerializeStruct = FlatMapSerializeStruct<'a, M>; + type SerializeTupleVariant = Impossible<Self::Ok, M::Error>; + type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>; + + fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Boolean)) + } + + fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Integer)) + } + + fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Float)) + } + + fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Char)) + } + + fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::String)) + } + + fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::ByteArray)) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Ok(()) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Unit)) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::UnitStruct)) + } + + fn serialize_unit_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Err(self.bad_type(Unsupported::Enum)) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _: &'static str, + _: u32, + variant: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + try!(self.0.serialize_key(variant)); + self.0.serialize_value(value) + } + + fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(self.bad_type(Unsupported::Sequence)) + } + + fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(self.bad_type(Unsupported::Tuple)) + } + + fn serialize_tuple_struct( + self, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(self.bad_type(Unsupported::TupleStruct)) + } + + fn serialize_tuple_variant( + self, + _: &'static str, + _: u32, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(self.bad_type(Unsupported::Enum)) + } + + fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Ok(FlatMapSerializeMap(self.0)) + } + + fn serialize_struct( + self, + _: &'static str, + _: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Ok(FlatMapSerializeStruct(self.0)) + } + + fn serialize_struct_variant( + self, + _: &'static str, + _: u32, + inner_variant: &'static str, + _: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + try!(self.0.serialize_key(inner_variant)); + Ok(FlatMapSerializeStructVariantAsMapValue::new( + self.0, + inner_variant, + )) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializeMap<'a, M: 'a>(&'a mut M); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> ser::SerializeMap for FlatMapSerializeMap<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error> + where + T: Serialize, + { + self.0.serialize_key(key) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize, + { + self.0.serialize_value(value) + } + + fn end(self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializeStruct<'a, M: 'a>(&'a mut M); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: Serialize, + { + self.0.serialize_entry(key, value) + } + + fn end(self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> { + map: &'a mut M, + name: &'static str, + fields: Vec<(&'static str, Content)>, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> { + FlatMapSerializeStructVariantAsMapValue { + map: map, + name: name, + fields: Vec::new(), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::<M::Error>::new())); + self.fields.push((key, value)); + Ok(()) + } + + fn end(self) -> Result<(), Self::Error> { + try!(self + .map + .serialize_value(&Content::Struct(self.name, self.fields))); + Ok(()) + } +} diff --git a/serde/src/ser/impls.rs b/serde/src/ser/impls.rs new file mode 100644 index 000000000..49b7477a4 --- /dev/null +++ b/serde/src/ser/impls.rs @@ -0,0 +1,840 @@ +use lib::*; + +use ser::{Error, Serialize, SerializeTuple, Serializer}; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! primitive_impl { + ($ty:ident, $method:ident $($cast:tt)*) => { + impl Serialize for $ty { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.$method(*self $($cast)*) + } + } + } +} + +primitive_impl!(bool, serialize_bool); +primitive_impl!(isize, serialize_i64 as i64); +primitive_impl!(i8, serialize_i8); +primitive_impl!(i16, serialize_i16); +primitive_impl!(i32, serialize_i32); +primitive_impl!(i64, serialize_i64); +primitive_impl!(usize, serialize_u64 as u64); +primitive_impl!(u8, serialize_u8); +primitive_impl!(u16, serialize_u16); +primitive_impl!(u32, serialize_u32); +primitive_impl!(u64, serialize_u64); +primitive_impl!(f32, serialize_f32); +primitive_impl!(f64, serialize_f64); +primitive_impl!(char, serialize_char); + +serde_if_integer128! { + primitive_impl!(i128, serialize_i128); + primitive_impl!(u128, serialize_u128); +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for str { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl Serialize for String { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_str(self) + } +} + +impl<'a> Serialize for fmt::Arguments<'a> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.collect_str(self) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl Serialize for CStr { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +#[cfg(feature = "std")] +impl Serialize for CString { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_bytes(self.to_bytes()) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<T> Serialize for Option<T> +where + T: Serialize, +{ + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + Some(ref value) => serializer.serialize_some(value), + None => serializer.serialize_none(), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<T: ?Sized> Serialize for PhantomData<T> { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_unit_struct("PhantomData") + } +} + +//////////////////////////////////////////////////////////////////////////////// + +// Does not require T: Serialize. +impl<T> Serialize for [T; 0] { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + try!(serializer.serialize_tuple(0)).end() + } +} + +macro_rules! array_impls { + ($($len:tt)+) => { + $( + impl<T> Serialize for [T; $len] + where + T: Serialize, + { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = try!(serializer.serialize_tuple($len)); + for e in self { + try!(seq.serialize_element(e)); + } + seq.end() + } + } + )+ + } +} + +array_impls! { + 01 02 03 04 05 06 07 08 09 10 + 11 12 13 14 15 16 17 18 19 20 + 21 22 23 24 25 26 27 28 29 30 + 31 32 +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<T> Serialize for [T] +where + T: Serialize, +{ + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.collect_seq(self) + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! seq_impl { + ($ty:ident < T $(: $tbound1:ident $(+ $tbound2:ident)*)* $(, $typaram:ident : $bound:ident)* >) => { + impl<T $(, $typaram)*> Serialize for $ty<T $(, $typaram)*> + where + T: Serialize $(+ $tbound1 $(+ $tbound2)*)*, + $($typaram: $bound,)* + { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(BinaryHeap<T: Ord>); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(BTreeSet<T: Ord>); + +#[cfg(feature = "std")] +seq_impl!(HashSet<T: Eq + Hash, H: BuildHasher>); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(LinkedList<T>); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(Vec<T>); + +#[cfg(any(feature = "std", feature = "alloc"))] +seq_impl!(VecDeque<T>); + +//////////////////////////////////////////////////////////////////////////////// + +impl<Idx> Serialize for Range<Idx> +where + Idx: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use super::SerializeStruct; + let mut state = try!(serializer.serialize_struct("Range", 2)); + try!(state.serialize_field("start", &self.start)); + try!(state.serialize_field("end", &self.end)); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(range_inclusive)] +impl<Idx> Serialize for RangeInclusive<Idx> +where + Idx: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use super::SerializeStruct; + let mut state = try!(serializer.serialize_struct("RangeInclusive", 2)); + try!(state.serialize_field("start", &self.start())); + try!(state.serialize_field("end", &self.end())); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(ops_bound, collections_bound))] +impl<T> Serialize for Bound<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + Bound::Unbounded => serializer.serialize_unit_variant("Bound", 0, "Unbounded"), + Bound::Included(ref value) => { + serializer.serialize_newtype_variant("Bound", 1, "Included", value) + } + Bound::Excluded(ref value) => { + serializer.serialize_newtype_variant("Bound", 2, "Excluded", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl Serialize for () { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.serialize_unit() + } +} + +#[cfg(feature = "unstable")] +impl Serialize for ! { + fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + *self + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! tuple_impls { + ($($len:expr => ($($n:tt $name:ident)+))+) => { + $( + impl<$($name),+> Serialize for ($($name,)+) + where + $($name: Serialize,)+ + { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut tuple = try!(serializer.serialize_tuple($len)); + $( + try!(tuple.serialize_element(&self.$n)); + )+ + tuple.end() + } + } + )+ + } +} + +tuple_impls! { + 1 => (0 T0) + 2 => (0 T0 1 T1) + 3 => (0 T0 1 T1 2 T2) + 4 => (0 T0 1 T1 2 T2 3 T3) + 5 => (0 T0 1 T1 2 T2 3 T3 4 T4) + 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5) + 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6) + 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7) + 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8) + 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9) + 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10) + 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11) + 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12) + 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13) + 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14) + 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15) +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +macro_rules! map_impl { + ($ty:ident < K $(: $kbound1:ident $(+ $kbound2:ident)*)*, V $(, $typaram:ident : $bound:ident)* >) => { + impl<K, V $(, $typaram)*> Serialize for $ty<K, V $(, $typaram)*> + where + K: Serialize $(+ $kbound1 $(+ $kbound2)*)*, + V: Serialize, + $($typaram: $bound,)* + { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + serializer.collect_map(self) + } + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +map_impl!(BTreeMap<K: Ord, V>); + +#[cfg(feature = "std")] +map_impl!(HashMap<K: Eq + Hash, V, H: BuildHasher>); + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! deref_impl { + ( + $(#[doc = $doc:tt])* + <$($desc:tt)+ + ) => { + $(#[doc = $doc])* + impl <$($desc)+ { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + (**self).serialize(serializer) + } + } + }; +} + +deref_impl!(<'a, T: ?Sized> Serialize for &'a T where T: Serialize); +deref_impl!(<'a, T: ?Sized> Serialize for &'a mut T where T: Serialize); + +#[cfg(any(feature = "std", feature = "alloc"))] +deref_impl!(<T: ?Sized> Serialize for Box<T> where T: Serialize); + +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Rc` will serialize a copy of + /// the contents of the `Rc` each time the `Rc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + <T: ?Sized> Serialize for Rc<T> where T: Serialize +} + +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +deref_impl! { + /// This impl requires the [`"rc"`] Cargo feature of Serde. + /// + /// Serializing a data structure containing `Arc` will serialize a copy of + /// the contents of the `Arc` each time the `Arc` is referenced within the + /// data structure. Serialization will not attempt to deduplicate these + /// repeated data. + /// + /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc + <T: ?Sized> Serialize for Arc<T> where T: Serialize +} + +#[cfg(any(feature = "std", feature = "alloc"))] +deref_impl!(<'a, T: ?Sized> Serialize for Cow<'a, T> where T: Serialize + ToOwned); + +//////////////////////////////////////////////////////////////////////////////// + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<T: ?Sized> Serialize for RcWeak<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<T: ?Sized> Serialize for ArcWeak<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.upgrade().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! nonzero_integers { + ( $( $T: ident, )+ ) => { + $( + #[cfg(num_nonzero)] + impl Serialize for num::$T { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.get().serialize(serializer) + } + } + )+ + } +} + +nonzero_integers! { + // Not including signed NonZeroI* since they might be removed + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroUsize, +} + +// Currently 128-bit integers do not work on Emscripten targets so we need an +// additional `#[cfg]` +serde_if_integer128! { + nonzero_integers! { + NonZeroU128, + } +} + +impl<T> Serialize for Cell<T> +where + T: Serialize + Copy, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.get().serialize(serializer) + } +} + +impl<T> Serialize for RefCell<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self.try_borrow() { + Ok(value) => value.serialize(serializer), + Err(_) => Err(S::Error::custom("already mutably borrowed")), + } + } +} + +#[cfg(feature = "std")] +impl<T> Serialize for Mutex<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self.lock() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +#[cfg(feature = "std")] +impl<T> Serialize for RwLock<T> +where + T: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self.read() { + Ok(locked) => locked.serialize(serializer), + Err(_) => Err(S::Error::custom("lock poison error while serializing")), + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +impl<T, E> Serialize for Result<T, E> +where + T: Serialize, + E: Serialize, +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match *self { + Result::Ok(ref value) => serializer.serialize_newtype_variant("Result", 0, "Ok", value), + Result::Err(ref value) => { + serializer.serialize_newtype_variant("Result", 1, "Err", value) + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(core_duration, feature = "std"))] +impl Serialize for Duration { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use super::SerializeStruct; + let mut state = try!(serializer.serialize_struct("Duration", 2)); + try!(state.serialize_field("secs", &self.as_secs())); + try!(state.serialize_field("nanos", &self.subsec_nanos())); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl Serialize for SystemTime { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use super::SerializeStruct; + let duration_since_epoch = self + .duration_since(UNIX_EPOCH) + .expect("SystemTime must be later than UNIX_EPOCH"); + let mut state = try!(serializer.serialize_struct("SystemTime", 2)); + try!(state.serialize_field("secs_since_epoch", &duration_since_epoch.as_secs())); + try!(state.serialize_field("nanos_since_epoch", &duration_since_epoch.subsec_nanos())); + state.end() + } +} + +//////////////////////////////////////////////////////////////////////////////// + +/// Serialize a value that implements `Display` as a string, when that string is +/// statically known to never have more than a constant `MAX_LEN` bytes. +/// +/// Panics if the `Display` impl tries to write more than `MAX_LEN` bytes. +#[cfg(feature = "std")] +macro_rules! serialize_display_bounded_length { + ($value:expr, $max:expr, $serializer:expr) => {{ + let mut buffer: [u8; $max] = unsafe { mem::uninitialized() }; + let remaining_len = { + let mut remaining = &mut buffer[..]; + write!(remaining, "{}", $value).unwrap(); + remaining.len() + }; + let written_len = buffer.len() - remaining_len; + let written = &buffer[..written_len]; + + // write! only provides fmt::Formatter to Display implementations, which + // has methods write_str and write_char but no method to write arbitrary + // bytes. Therefore `written` must be valid UTF-8. + let written_str = unsafe { str::from_utf8_unchecked(written) }; + $serializer.serialize_str(written_str) + }}; +} + +#[cfg(feature = "std")] +impl Serialize for net::IpAddr { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::IpAddr::V4(ref a) => a.serialize(serializer), + net::IpAddr::V6(ref a) => a.serialize(serializer), + } + } else { + match *self { + net::IpAddr::V4(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 0, "V4", a) + } + net::IpAddr::V6(ref a) => { + serializer.serialize_newtype_variant("IpAddr", 1, "V6", a) + } + } + } + } +} + +#[cfg(feature = "std")] +impl Serialize for net::Ipv4Addr { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 15; + debug_assert_eq!(MAX_LEN, "101.102.103.104".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } + } +} + +#[cfg(feature = "std")] +impl Serialize for net::Ipv6Addr { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 39; + debug_assert_eq!(MAX_LEN, "1001:1002:1003:1004:1005:1006:1007:1008".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + self.octets().serialize(serializer) + } + } +} + +#[cfg(feature = "std")] +impl Serialize for net::SocketAddr { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + match *self { + net::SocketAddr::V4(ref addr) => addr.serialize(serializer), + net::SocketAddr::V6(ref addr) => addr.serialize(serializer), + } + } else { + match *self { + net::SocketAddr::V4(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 0, "V4", addr) + } + net::SocketAddr::V6(ref addr) => { + serializer.serialize_newtype_variant("SocketAddr", 1, "V6", addr) + } + } + } + } +} + +#[cfg(feature = "std")] +impl Serialize for net::SocketAddrV4 { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 21; + debug_assert_eq!(MAX_LEN, "101.102.103.104:65000".len()); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +#[cfg(feature = "std")] +impl Serialize for net::SocketAddrV6 { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + if serializer.is_human_readable() { + const MAX_LEN: usize = 47; + debug_assert_eq!( + MAX_LEN, + "[1001:1002:1003:1004:1005:1006:1007:1008]:65000".len() + ); + serialize_display_bounded_length!(self, MAX_LEN, serializer) + } else { + (self.ip(), self.port()).serialize(serializer) + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl Serialize for Path { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self.to_str() { + Some(s) => s.serialize(serializer), + None => Err(Error::custom("path contains invalid UTF-8 characters")), + } + } +} + +#[cfg(feature = "std")] +impl Serialize for PathBuf { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.as_path().serialize(serializer) + } +} + +#[cfg(all(feature = "std", any(unix, windows)))] +impl Serialize for OsStr { + #[cfg(unix)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use std::os::unix::ffi::OsStrExt; + serializer.serialize_newtype_variant("OsString", 0, "Unix", self.as_bytes()) + } + + #[cfg(windows)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use std::os::windows::ffi::OsStrExt; + let val = self.encode_wide().collect::<Vec<_>>(); + serializer.serialize_newtype_variant("OsString", 1, "Windows", &val) + } +} + +#[cfg(all(feature = "std", any(unix, windows)))] +impl Serialize for OsString { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.as_os_str().serialize(serializer) + } +} + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(feature = "std")] +impl<T> Serialize for Wrapping<T> +where + T: Serialize, +{ + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.0.serialize(serializer) + } +} + +#[cfg(core_reverse)] +impl<T> Serialize for Reverse<T> +where + T: Serialize, +{ + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + self.0.serialize(serializer) + } +} diff --git a/serde/src/ser/impossible.rs b/serde/src/ser/impossible.rs new file mode 100644 index 000000000..90bab29a0 --- /dev/null +++ b/serde/src/ser/impossible.rs @@ -0,0 +1,216 @@ +//! This module contains `Impossible` serializer and its implementations. + +use lib::*; + +use ser::{ + self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, +}; + +/// Helper type for implementing a `Serializer` that does not support +/// serializing one of the compound types. +/// +/// This type cannot be instantiated, but implements every one of the traits +/// corresponding to the [`Serializer`] compound types: [`SerializeSeq`], +/// [`SerializeTuple`], [`SerializeTupleStruct`], [`SerializeTupleVariant`], +/// [`SerializeMap`], [`SerializeStruct`], and [`SerializeStructVariant`]. +/// +/// ```edition2018 +/// # use serde::ser::{Serializer, Impossible}; +/// # use serde::private::ser::Error; +/// # +/// # struct MySerializer; +/// # +/// impl Serializer for MySerializer { +/// type Ok = (); +/// type Error = Error; +/// +/// type SerializeSeq = Impossible<(), Error>; +/// /* other associated types */ +/// +/// /// This data format does not support serializing sequences. +/// fn serialize_seq(self, +/// len: Option<usize>) +/// -> Result<Self::SerializeSeq, Error> { +/// // Given Impossible cannot be instantiated, the only +/// // thing we can do here is to return an error. +/// # stringify! { +/// Err(...) +/// # }; +/// # unimplemented!() +/// } +/// +/// /* other Serializer methods */ +/// # serde::__serialize_unimplemented! { +/// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes none some +/// # unit unit_struct unit_variant newtype_struct newtype_variant +/// # tuple tuple_struct tuple_variant map struct struct_variant +/// # } +/// } +/// ``` +/// +/// [`Serializer`]: trait.Serializer.html +/// [`SerializeSeq`]: trait.SerializeSeq.html +/// [`SerializeTuple`]: trait.SerializeTuple.html +/// [`SerializeTupleStruct`]: trait.SerializeTupleStruct.html +/// [`SerializeTupleVariant`]: trait.SerializeTupleVariant.html +/// [`SerializeMap`]: trait.SerializeMap.html +/// [`SerializeStruct`]: trait.SerializeStruct.html +/// [`SerializeStructVariant`]: trait.SerializeStructVariant.html +pub struct Impossible<Ok, Error> { + void: Void, + ok: PhantomData<Ok>, + error: PhantomData<Error>, +} + +enum Void {} + +impl<Ok, Error> SerializeSeq for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeTuple for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeTupleStruct for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeTupleVariant for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeMap for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = key; + match self.void {} + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeStruct for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} + +impl<Ok, Error> SerializeStructVariant for Impossible<Ok, Error> +where + Error: ser::Error, +{ + type Ok = Ok; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + let _ = key; + let _ = value; + match self.void {} + } + + fn end(self) -> Result<Ok, Error> { + match self.void {} + } +} diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs new file mode 100644 index 000000000..318b3799a --- /dev/null +++ b/serde/src/ser/mod.rs @@ -0,0 +1,1988 @@ +//! Generic data structure serialization framework. +//! +//! The two most important traits in this module are [`Serialize`] and +//! [`Serializer`]. +//! +//! - **A type that implements `Serialize` is a data structure** that can be +//! serialized to any data format supported by Serde, and conversely +//! - **A type that implements `Serializer` is a data format** that can +//! serialize any data structure supported by Serde. +//! +//! # The Serialize trait +//! +//! Serde provides [`Serialize`] implementations for many Rust primitive and +//! standard library types. The complete list is below. All of these can be +//! serialized using Serde out of the box. +//! +//! Additionally, Serde provides a procedural macro called [`serde_derive`] to +//! automatically generate [`Serialize`] implementations for structs and enums +//! in your program. See the [derive section of the manual] for how to use this. +//! +//! In rare cases it may be necessary to implement [`Serialize`] manually for +//! some type in your program. See the [Implementing `Serialize`] section of the +//! manual for more about this. +//! +//! Third-party crates may provide [`Serialize`] implementations for types that +//! they expose. For example the [`linked-hash-map`] crate provides a +//! [`LinkedHashMap<K, V>`] type that is serializable by Serde because the crate +//! provides an implementation of [`Serialize`] for it. +//! +//! # The Serializer trait +//! +//! [`Serializer`] implementations are provided by third-party crates, for +//! example [`serde_json`], [`serde_yaml`] and [`bincode`]. +//! +//! A partial list of well-maintained formats is given on the [Serde +//! website][data formats]. +//! +//! # Implementations of Serialize provided by Serde +//! +//! - **Primitive types**: +//! - bool +//! - i8, i16, i32, i64, i128, isize +//! - u8, u16, u32, u64, u128, usize +//! - f32, f64 +//! - char +//! - str +//! - &T and &mut T +//! - **Compound types**: +//! - \[T\] +//! - \[T; 0\] through \[T; 32\] +//! - tuples up to size 16 +//! - **Common standard library types**: +//! - String +//! - Option\<T\> +//! - Result\<T, E\> +//! - PhantomData\<T\> +//! - **Wrapper types**: +//! - Box\<T\> +//! - Cow\<'a, T\> +//! - Cell\<T\> +//! - RefCell\<T\> +//! - Mutex\<T\> +//! - RwLock\<T\> +//! - Rc\<T\> *(if* features = ["rc"] *is enabled)* +//! - Arc\<T\> *(if* features = ["rc"] *is enabled)* +//! - **Collection types**: +//! - BTreeMap\<K, V\> +//! - BTreeSet\<T\> +//! - BinaryHeap\<T\> +//! - HashMap\<K, V, H\> +//! - HashSet\<T, H\> +//! - LinkedList\<T\> +//! - VecDeque\<T\> +//! - Vec\<T\> +//! - **FFI types**: +//! - CStr +//! - CString +//! - OsStr +//! - OsString +//! - **Miscellaneous standard library types**: +//! - Duration +//! - SystemTime +//! - Path +//! - PathBuf +//! - Range\<T\> +//! - RangeInclusive\<T\> +//! - Bound\<T\> +//! - num::NonZero* +//! - `!` *(unstable)* +//! - **Net types**: +//! - IpAddr +//! - Ipv4Addr +//! - Ipv6Addr +//! - SocketAddr +//! - SocketAddrV4 +//! - SocketAddrV6 +//! +//! [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +//! [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +//! [`Serialize`]: ../trait.Serialize.html +//! [`Serializer`]: ../trait.Serializer.html +//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map +//! [`serde_derive`]: https://crates.io/crates/serde_derive +//! [`serde_json`]: https://github.com/serde-rs/json +//! [`serde_yaml`]: https://github.com/dtolnay/serde-yaml +//! [derive section of the manual]: https://serde.rs/derive.html +//! [data formats]: https://serde.rs/#data-formats + +use lib::*; + +mod impls; +mod impossible; + +pub use self::impossible::Impossible; + +//////////////////////////////////////////////////////////////////////////////// + +macro_rules! declare_error_trait { + (Error: Sized $(+ $($supertrait:ident)::+)*) => { + /// Trait used by `Serialize` implementations to generically construct + /// errors belonging to the `Serializer` against which they are + /// currently running. + /// + /// # Example implementation + /// + /// The [example data format] presented on the website shows an error + /// type appropriate for a basic JSON data format. + /// + /// [example data format]: https://serde.rs/data-format.html + pub trait Error: Sized $(+ $($supertrait)::+)* { + /// Used when a [`Serialize`] implementation encounters any error + /// while serializing a type. + /// + /// The message should not be capitalized and should not end with a + /// period. + /// + /// For example, a filesystem [`Path`] may refuse to serialize + /// itself if it contains invalid UTF-8 data. + /// + /// ```edition2018 + /// # struct Path; + /// # + /// # impl Path { + /// # fn to_str(&self) -> Option<&str> { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{self, Serialize, Serializer}; + /// + /// impl Serialize for Path { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match self.to_str() { + /// Some(s) => serializer.serialize_str(s), + /// None => Err(ser::Error::custom("path contains invalid UTF-8 characters")), + /// } + /// } + /// } + /// ``` + /// + /// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html + /// [`Serialize`]: ../trait.Serialize.html + fn custom<T>(msg: T) -> Self + where + T: Display; + } + } +} + +#[cfg(feature = "std")] +declare_error_trait!(Error: Sized + error::Error); + +#[cfg(not(feature = "std"))] +declare_error_trait!(Error: Sized + Debug + Display); + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data structure** that can be serialized into any data format supported +/// by Serde. +/// +/// Serde provides `Serialize` implementations for many Rust primitive and +/// standard library types. The complete list is [here][ser]. All of these can +/// be serialized using Serde out of the box. +/// +/// Additionally, Serde provides a procedural macro called [`serde_derive`] to +/// automatically generate `Serialize` implementations for structs and enums in +/// your program. See the [derive section of the manual] for how to use this. +/// +/// In rare cases it may be necessary to implement `Serialize` manually for some +/// type in your program. See the [Implementing `Serialize`] section of the +/// manual for more about this. +/// +/// Third-party crates may provide `Serialize` implementations for types that +/// they expose. For example the [`linked-hash-map`] crate provides a +/// [`LinkedHashMap<K, V>`] type that is serializable by Serde because the crate +/// provides an implementation of `Serialize` for it. +/// +/// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html +/// [`LinkedHashMap<K, V>`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html +/// [`linked-hash-map`]: https://crates.io/crates/linked-hash-map +/// [`serde_derive`]: https://crates.io/crates/serde_derive +/// [derive section of the manual]: https://serde.rs/derive.html +/// [ser]: https://docs.serde.rs/serde/ser/index.html +pub trait Serialize { + /// Serialize this value into the given Serde serializer. + /// + /// See the [Implementing `Serialize`] section of the manual for more + /// information about how to implement this method. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Person { + /// name: String, + /// age: u8, + /// phones: Vec<String>, + /// } + /// + /// // This is what #[derive(Serialize)] would generate. + /// impl Serialize for Person { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut s = serializer.serialize_struct("Person", 3)?; + /// s.serialize_field("name", &self.name)?; + /// s.serialize_field("age", &self.age)?; + /// s.serialize_field("phones", &self.phones)?; + /// s.end() + /// } + /// } + /// ``` + /// + /// [Implementing `Serialize`]: https://serde.rs/impl-serialize.html + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer; +} + +//////////////////////////////////////////////////////////////////////////////// + +/// A **data format** that can serialize any data structure supported by Serde. +/// +/// The role of this trait is to define the serialization half of the [Serde +/// data model], which is a way to categorize every Rust data structure into one +/// of 29 possible types. Each method of the `Serializer` trait corresponds to +/// one of the types of the data model. +/// +/// Implementations of `Serialize` map themselves into this data model by +/// invoking exactly one of the `Serializer` methods. +/// +/// The types that make up the Serde data model are: +/// +/// - **14 primitive types** +/// - bool +/// - i8, i16, i32, i64, i128 +/// - u8, u16, u32, u64, u128 +/// - f32, f64 +/// - char +/// - **string** +/// - UTF-8 bytes with a length and no null terminator. +/// - When serializing, all strings are handled equally. When deserializing, +/// there are three flavors of strings: transient, owned, and borrowed. +/// - **byte array** - \[u8\] +/// - Similar to strings, during deserialization byte arrays can be +/// transient, owned, or borrowed. +/// - **option** +/// - Either none or some value. +/// - **unit** +/// - The type of `()` in Rust. It represents an anonymous value containing +/// no data. +/// - **unit_struct** +/// - For example `struct Unit` or `PhantomData<T>`. It represents a named +/// value containing no data. +/// - **unit_variant** +/// - For example the `E::A` and `E::B` in `enum E { A, B }`. +/// - **newtype_struct** +/// - For example `struct Millimeters(u8)`. +/// - **newtype_variant** +/// - For example the `E::N` in `enum E { N(u8) }`. +/// - **seq** +/// - A variably sized heterogeneous sequence of values, for example +/// `Vec<T>` or `HashSet<T>`. When serializing, the length may or may not +/// be known before iterating through all the data. When deserializing, +/// the length is determined by looking at the serialized data. +/// - **tuple** +/// - A statically sized heterogeneous sequence of values for which the +/// length will be known at deserialization time without looking at the +/// serialized data, for example `(u8,)` or `(String, u64, Vec<T>)` or +/// `[u64; 10]`. +/// - **tuple_struct** +/// - A named tuple, for example `struct Rgb(u8, u8, u8)`. +/// - **tuple_variant** +/// - For example the `E::T` in `enum E { T(u8, u8) }`. +/// - **map** +/// - A heterogeneous key-value pairing, for example `BTreeMap<K, V>`. +/// - **struct** +/// - A heterogeneous key-value pairing in which the keys are strings and +/// will be known at deserialization time without looking at the +/// serialized data, for example `struct S { r: u8, g: u8, b: u8 }`. +/// - **struct_variant** +/// - For example the `E::S` in `enum E { S { r: u8, g: u8, b: u8 } }`. +/// +/// Many Serde serializers produce text or binary data as output, for example +/// JSON or Bincode. This is not a requirement of the `Serializer` trait, and +/// there are serializers that do not produce text or binary output. One example +/// is the `serde_json::value::Serializer` (distinct from the main `serde_json` +/// serializer) that produces a `serde_json::Value` data structure in memory as +/// output. +/// +/// [Serde data model]: https://serde.rs/data-model.html +/// +/// # Example implementation +/// +/// The [example data format] presented on the website contains example code for +/// a basic JSON `Serializer`. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait Serializer: Sized { + /// The output type produced by this `Serializer` during successful + /// serialization. Most serializers that produce text or binary output + /// should set `Ok = ()` and serialize into an [`io::Write`] or buffer + /// contained within the `Serializer` instance. Serializers that build + /// in-memory data structures may be simplified by using `Ok` to propagate + /// the data structure around. + /// + /// [`io::Write`]: https://doc.rust-lang.org/std/io/trait.Write.html + type Ok; + + /// The error type when some error occurs during serialization. + type Error: Error; + + /// Type returned from [`serialize_seq`] for serializing the content of the + /// sequence. + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + type SerializeSeq: SerializeSeq<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_tuple`] for serializing the content of + /// the tuple. + /// + /// [`serialize_tuple`]: #tymethod.serialize_tuple + type SerializeTuple: SerializeTuple<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_tuple_struct`] for serializing the + /// content of the tuple struct. + /// + /// [`serialize_tuple_struct`]: #tymethod.serialize_tuple_struct + type SerializeTupleStruct: SerializeTupleStruct<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_tuple_variant`] for serializing the + /// content of the tuple variant. + /// + /// [`serialize_tuple_variant`]: #tymethod.serialize_tuple_variant + type SerializeTupleVariant: SerializeTupleVariant<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_map`] for serializing the content of the + /// map. + /// + /// [`serialize_map`]: #tymethod.serialize_map + type SerializeMap: SerializeMap<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_struct`] for serializing the content of + /// the struct. + /// + /// [`serialize_struct`]: #tymethod.serialize_struct + type SerializeStruct: SerializeStruct<Ok = Self::Ok, Error = Self::Error>; + + /// Type returned from [`serialize_struct_variant`] for serializing the + /// content of the struct variant. + /// + /// [`serialize_struct_variant`]: #tymethod.serialize_struct_variant + type SerializeStructVariant: SerializeStructVariant<Ok = Self::Ok, Error = Self::Error>; + + /// Serialize a `bool` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for bool { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_bool(*self) + /// } + /// } + /// ``` + fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error>; + + /// Serialize an `i8` value. + /// + /// If the format does not differentiate between `i8` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for i8 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i8(*self) + /// } + /// } + /// ``` + fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error>; + + /// Serialize an `i16` value. + /// + /// If the format does not differentiate between `i16` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for i16 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i16(*self) + /// } + /// } + /// ``` + fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error>; + + /// Serialize an `i32` value. + /// + /// If the format does not differentiate between `i32` and `i64`, a + /// reasonable implementation would be to cast the value to `i64` and + /// forward to `serialize_i64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for i32 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i32(*self) + /// } + /// } + /// ``` + fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error>; + + /// Serialize an `i64` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for i64 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i64(*self) + /// } + /// } + /// ``` + fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error>; + + serde_if_integer128! { + /// Serialize an `i128` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for i128 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_i128(*self) + /// } + /// } + /// ``` + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default behavior unconditionally returns an error. + fn serialize_i128(self, v: i128) -> Result<Self::Ok, Self::Error> { + let _ = v; + Err(Error::custom("i128 is not supported")) + } + } + + /// Serialize a `u8` value. + /// + /// If the format does not differentiate between `u8` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for u8 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u8(*self) + /// } + /// } + /// ``` + fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error>; + + /// Serialize a `u16` value. + /// + /// If the format does not differentiate between `u16` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for u16 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u16(*self) + /// } + /// } + /// ``` + fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error>; + + /// Serialize a `u32` value. + /// + /// If the format does not differentiate between `u32` and `u64`, a + /// reasonable implementation would be to cast the value to `u64` and + /// forward to `serialize_u64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for u32 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u32(*self) + /// } + /// } + /// ``` + fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error>; + + /// Serialize a `u64` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for u64 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u64(*self) + /// } + /// } + /// ``` + fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error>; + + serde_if_integer128! { + /// Serialize a `u128` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for u128 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_u128(*self) + /// } + /// } + /// ``` + /// + /// This method is available only on Rust compiler versions >=1.26. The + /// default behavior unconditionally returns an error. + fn serialize_u128(self, v: u128) -> Result<Self::Ok, Self::Error> { + let _ = v; + Err(Error::custom("u128 is not supported")) + } + } + + /// Serialize an `f32` value. + /// + /// If the format does not differentiate between `f32` and `f64`, a + /// reasonable implementation would be to cast the value to `f64` and + /// forward to `serialize_f64`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for f32 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f32(*self) + /// } + /// } + /// ``` + fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error>; + + /// Serialize an `f64` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for f64 { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_f64(*self) + /// } + /// } + /// ``` + fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error>; + + /// Serialize a character. + /// + /// If the format does not support characters, it is reasonable to serialize + /// it as a single element `str` or a `u32`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for char { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_char(*self) + /// } + /// } + /// ``` + fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error>; + + /// Serialize a `&str`. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for str { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_str(self) + /// } + /// } + /// ``` + fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error>; + + /// Serialize a chunk of raw byte data. + /// + /// Enables serializers to serialize byte slices more compactly or more + /// efficiently than other types of slices. If no efficient implementation + /// is available, a reasonable implementation would be to forward to + /// `serialize_seq`. If forwarded, the implementation looks usually just + /// like this: + /// + /// ```edition2018 + /// # use serde::ser::{Serializer, SerializeSeq}; + /// # use serde::private::ser::Error; + /// # + /// # struct MySerializer; + /// # + /// # impl Serializer for MySerializer { + /// # type Ok = (); + /// # type Error = Error; + /// # + /// fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> { + /// let mut seq = self.serialize_seq(Some(v.len()))?; + /// for b in v { + /// seq.serialize_element(b)?; + /// } + /// seq.end() + /// } + /// # + /// # serde::__serialize_unimplemented! { + /// # bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str none some + /// # unit unit_struct unit_variant newtype_struct newtype_variant + /// # seq tuple tuple_struct tuple_variant map struct struct_variant + /// # } + /// # } + /// ``` + fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error>; + + /// Serialize a [`None`] value. + /// + /// ```edition2018 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option<T> { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl<T> Serialize for Option<T> + /// where + /// T: Serialize, + /// { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + fn serialize_none(self) -> Result<Self::Ok, Self::Error>; + + /// Serialize a [`Some(T)`] value. + /// + /// ```edition2018 + /// # use serde::{Serialize, Serializer}; + /// # + /// # enum Option<T> { + /// # Some(T), + /// # None, + /// # } + /// # + /// # use self::Option::{Some, None}; + /// # + /// impl<T> Serialize for Option<T> + /// where + /// T: Serialize, + /// { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// Some(ref value) => serializer.serialize_some(value), + /// None => serializer.serialize_none(), + /// } + /// } + /// } + /// # + /// # fn main() {} + /// ``` + /// + /// [`Some(T)`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize; + + /// Serialize a `()` value. + /// + /// ```edition2018 + /// # use serde::Serializer; + /// # + /// # serde::__private_serialize!(); + /// # + /// impl Serialize for () { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit() + /// } + /// } + /// ``` + fn serialize_unit(self) -> Result<Self::Ok, Self::Error>; + + /// Serialize a unit struct like `struct Unit` or `PhantomData<T>`. + /// + /// A reasonable implementation would be to forward to `serialize_unit`. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// + /// struct Nothing; + /// + /// impl Serialize for Nothing { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_unit_struct("Nothing") + /// } + /// } + /// ``` + fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error>; + + /// Serialize a unit variant like `E::A` in `enum E { A, B }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// A, + /// B, + /// } + /// + /// impl Serialize for E { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::A => serializer.serialize_unit_variant("E", 0, "A"), + /// E::B => serializer.serialize_unit_variant("E", 1, "B"), + /// } + /// } + /// } + /// ``` + fn serialize_unit_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + ) -> Result<Self::Ok, Self::Error>; + + /// Serialize a newtype struct like `struct Millimeters(u8)`. + /// + /// Serializers are encouraged to treat newtype structs as insignificant + /// wrappers around the data they contain. A reasonable implementation would + /// be to forward to `value.serialize(self)`. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// + /// struct Millimeters(u8); + /// + /// impl Serialize for Millimeters { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.serialize_newtype_struct("Millimeters", &self.0) + /// } + /// } + /// ``` + fn serialize_newtype_struct<T: ?Sized>( + self, + name: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize; + + /// Serialize a newtype variant like `E::N` in `enum E { N(u8) }`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, and the `variant` is the name of the + /// variant. The `value` is the data contained within this newtype variant. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// + /// enum E { + /// M(String), + /// N(u8), + /// } + /// + /// impl Serialize for E { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::M(ref s) => serializer.serialize_newtype_variant("E", 0, "M", s), + /// E::N(n) => serializer.serialize_newtype_variant("E", 1, "N", &n), + /// } + /// } + /// } + /// ``` + fn serialize_newtype_variant<T: ?Sized>( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize; + + /// Begin to serialize a variably sized sequence. This call must be + /// followed by zero or more calls to `serialize_element`, then a call to + /// `end`. + /// + /// The argument is the number of elements in the sequence, which may or may + /// not be computable before the sequence is iterated. Some serializers only + /// support sequences whose length is known up front. + /// + /// ```edition2018 + /// # use std::marker::PhantomData; + /// # + /// # struct Vec<T>(PhantomData<T>); + /// # + /// # impl<T> Vec<T> { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, T> IntoIterator for &'a Vec<T> { + /// # type Item = &'a T; + /// # type IntoIter = Box<Iterator<Item = &'a T>>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, Serializer, SerializeSeq}; + /// + /// impl<T> Serialize for Vec<T> + /// where + /// T: Serialize, + /// { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_seq(Some(self.len()))?; + /// for element in self { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error>; + + /// Begin to serialize a statically sized sequence whose length will be + /// known at deserialization time without looking at the serialized data. + /// This call must be followed by zero or more calls to `serialize_element`, + /// then a call to `end`. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, Serializer, SerializeTuple}; + /// + /// # mod fool { + /// # trait Serialize {} + /// impl<A, B, C> Serialize for (A, B, C) + /// # {} + /// # } + /// # + /// # struct Tuple3<A, B, C>(A, B, C); + /// # + /// # impl<A, B, C> Serialize for Tuple3<A, B, C> + /// where + /// A: Serialize, + /// B: Serialize, + /// C: Serialize, + /// { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut tup = serializer.serialize_tuple(3)?; + /// tup.serialize_element(&self.0)?; + /// tup.serialize_element(&self.1)?; + /// tup.serialize_element(&self.2)?; + /// tup.end() + /// } + /// } + /// ``` + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeTuple, Serializer}; + /// + /// const VRAM_SIZE: usize = 386; + /// struct Vram([u16; VRAM_SIZE]); + /// + /// impl Serialize for Vram { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut seq = serializer.serialize_tuple(VRAM_SIZE)?; + /// for element in &self.0[..] { + /// seq.serialize_element(element)?; + /// } + /// seq.end() + /// } + /// } + /// ``` + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error>; + + /// Begin to serialize a tuple struct like `struct Rgb(u8, u8, u8)`. This + /// call must be followed by zero or more calls to `serialize_field`, then a + /// call to `end`. + /// + /// The `name` is the name of the tuple struct and the `len` is the number + /// of data fields that will be serialized. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; + /// + /// struct Rgb(u8, u8, u8); + /// + /// impl Serialize for Rgb { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; + /// ts.serialize_field(&self.0)?; + /// ts.serialize_field(&self.1)?; + /// ts.serialize_field(&self.2)?; + /// ts.end() + /// } + /// } + /// ``` + fn serialize_tuple_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error>; + + /// Begin to serialize a tuple variant like `E::T` in `enum E { T(u8, u8) + /// }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, the `variant` is the name of the variant, + /// and the `len` is the number of data fields that will be serialized. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; + /// + /// enum E { + /// T(u8, u8), + /// U(String, u32, u32), + /// } + /// + /// impl Serialize for E { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::T(ref a, ref b) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.end() + /// } + /// E::U(ref a, ref b, ref c) => { + /// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; + /// tv.serialize_field(a)?; + /// tv.serialize_field(b)?; + /// tv.serialize_field(c)?; + /// tv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error>; + + /// Begin to serialize a map. This call must be followed by zero or more + /// calls to `serialize_key` and `serialize_value`, then a call to `end`. + /// + /// The argument is the number of elements in the map, which may or may not + /// be computable before the map is iterated. Some serializers only support + /// maps whose length is known up front. + /// + /// ```edition2018 + /// # use std::marker::PhantomData; + /// # + /// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>); + /// # + /// # impl<K, V> HashMap<K, V> { + /// # fn len(&self) -> usize { + /// # unimplemented!() + /// # } + /// # } + /// # + /// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> { + /// # type Item = (&'a K, &'a V); + /// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>; + /// # + /// # fn into_iter(self) -> Self::IntoIter { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::ser::{Serialize, Serializer, SerializeMap}; + /// + /// impl<K, V> Serialize for HashMap<K, V> + /// where + /// K: Serialize, + /// V: Serialize, + /// { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut map = serializer.serialize_map(Some(self.len()))?; + /// for (k, v) in self { + /// map.serialize_entry(k, v)?; + /// } + /// map.end() + /// } + /// } + /// ``` + fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error>; + + /// Begin to serialize a struct like `struct Rgb { r: u8, g: u8, b: u8 }`. + /// This call must be followed by zero or more calls to `serialize_field`, + /// then a call to `end`. + /// + /// The `name` is the name of the struct and the `len` is the number of + /// data fields that will be serialized. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeStruct, Serializer}; + /// + /// struct Rgb { + /// r: u8, + /// g: u8, + /// b: u8, + /// } + /// + /// impl Serialize for Rgb { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// let mut rgb = serializer.serialize_struct("Rgb", 3)?; + /// rgb.serialize_field("r", &self.r)?; + /// rgb.serialize_field("g", &self.g)?; + /// rgb.serialize_field("b", &self.b)?; + /// rgb.end() + /// } + /// } + /// ``` + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, Self::Error>; + + /// Begin to serialize a struct variant like `E::S` in `enum E { S { r: u8, + /// g: u8, b: u8 } }`. This call must be followed by zero or more calls to + /// `serialize_field`, then a call to `end`. + /// + /// The `name` is the name of the enum, the `variant_index` is the index of + /// this variant within the enum, the `variant` is the name of the variant, + /// and the `len` is the number of data fields that will be serialized. + /// + /// ```edition2018 + /// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; + /// + /// enum E { + /// S { r: u8, g: u8, b: u8 }, + /// } + /// + /// impl Serialize for E { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// match *self { + /// E::S { + /// ref r, + /// ref g, + /// ref b, + /// } => { + /// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; + /// sv.serialize_field("r", r)?; + /// sv.serialize_field("g", g)?; + /// sv.serialize_field("b", b)?; + /// sv.end() + /// } + /// } + /// } + /// } + /// ``` + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error>; + + /// Collect an iterator as a sequence. + /// + /// The default implementation serializes each item yielded by the iterator + /// using [`serialize_seq`]. Implementors should not need to override this + /// method. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// + /// struct SecretlyOneHigher { + /// data: Vec<i32>, + /// } + /// + /// impl Serialize for SecretlyOneHigher { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.collect_seq(self.data.iter().map(|x| x + 1)) + /// } + /// } + /// ``` + /// + /// [`serialize_seq`]: #tymethod.serialize_seq + fn collect_seq<I>(self, iter: I) -> Result<Self::Ok, Self::Error> + where + I: IntoIterator, + <I as IntoIterator>::Item: Serialize, + { + let iter = iter.into_iter(); + let mut serializer = try!(self.serialize_seq(iter.len_hint())); + for item in iter { + try!(serializer.serialize_element(&item)); + } + serializer.end() + } + + /// Collect an iterator as a map. + /// + /// The default implementation serializes each pair yielded by the iterator + /// using [`serialize_map`]. Implementors should not need to override this + /// method. + /// + /// ```edition2018 + /// use serde::{Serialize, Serializer}; + /// use std::collections::BTreeSet; + /// + /// struct MapToUnit { + /// keys: BTreeSet<i32>, + /// } + /// + /// // Serializes as a map in which the values are all unit. + /// impl Serialize for MapToUnit { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.collect_map(self.keys.iter().map(|k| (k, ()))) + /// } + /// } + /// ``` + /// + /// [`serialize_map`]: #tymethod.serialize_map + fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error> + where + K: Serialize, + V: Serialize, + I: IntoIterator<Item = (K, V)>, + { + let iter = iter.into_iter(); + let mut serializer = try!(self.serialize_map(iter.len_hint())); + for (key, value) in iter { + try!(serializer.serialize_entry(&key, &value)); + } + serializer.end() + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// The default implementation builds a heap-allocated [`String`] and + /// delegates to [`serialize_str`]. Serializers are encouraged to provide a + /// more efficient implementation if possible. + /// + /// ```edition2018 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", + /// self.naive_local(), + /// self.offset())) + /// } + /// } + /// ``` + /// + /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html + /// [`serialize_str`]: #tymethod.serialize_str + #[cfg(any(feature = "std", feature = "alloc"))] + fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> + where + T: Display, + { + use lib::fmt::Write; + let mut string = String::new(); + write!(string, "{}", value).unwrap(); + self.serialize_str(&string) + } + + /// Serialize a string produced by an implementation of `Display`. + /// + /// Serializers that use `no_std` are required to provide an implementation + /// of this method. If no more sensible behavior is possible, the + /// implementation is expected to return an error. + /// + /// ```edition2018 + /// # struct DateTime; + /// # + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for DateTime { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", + /// self.naive_local(), + /// self.offset())) + /// } + /// } + /// ``` + #[cfg(not(any(feature = "std", feature = "alloc")))] + fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> + where + T: Display; + + /// Determine whether `Serialize` implementations should serialize in + /// human-readable form. + /// + /// Some types have a human-readable form that may be somewhat expensive to + /// construct, as well as a binary form that is compact and efficient. + /// Generally text-based formats like JSON and YAML will prefer to use the + /// human-readable one and binary formats like Bincode will prefer the + /// compact one. + /// + /// ```edition2018 + /// # use std::fmt::{self, Display}; + /// # + /// # struct Timestamp; + /// # + /// # impl Timestamp { + /// # fn seconds_since_epoch(&self) -> u64 { unimplemented!() } + /// # } + /// # + /// # impl Display for Timestamp { + /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// # unimplemented!() + /// # } + /// # } + /// # + /// use serde::{Serialize, Serializer}; + /// + /// impl Serialize for Timestamp { + /// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + /// where + /// S: Serializer, + /// { + /// if serializer.is_human_readable() { + /// // Serialize to a human-readable string "2015-05-15T17:01:00Z". + /// self.to_string().serialize(serializer) + /// } else { + /// // Serialize to a compact binary representation. + /// self.seconds_since_epoch().serialize(serializer) + /// } + /// } + /// } + /// ``` + /// + /// The default implementation of this method returns `true`. Data formats + /// may override this to `false` to request a compact form for types that + /// support one. Note that modifying this method to change a format from + /// human-readable to compact or vice versa should be regarded as a breaking + /// change, as a value serialized in human-readable mode is not required to + /// deserialize from the same data in compact mode. + #[inline] + fn is_human_readable(&self) -> bool { + true + } +} + +/// Returned from `Serializer::serialize_seq`. +/// +/// # Example use +/// +/// ```edition2018 +/// # use std::marker::PhantomData; +/// # +/// # struct Vec<T>(PhantomData<T>); +/// # +/// # impl<T> Vec<T> { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Vec<T> { +/// # type Item = &'a T; +/// # type IntoIter = Box<Iterator<Item = &'a T>>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, Serializer, SerializeSeq}; +/// +/// impl<T> Serialize for Vec<T> +/// where +/// T: Serialize, +/// { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_seq(Some(self.len()))?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeSeq` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeSeq { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a sequence element. + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Finish serializing a sequence. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_tuple`. +/// +/// # Example use +/// +/// ```edition2018 +/// use serde::ser::{Serialize, Serializer, SerializeTuple}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl<A, B, C> Serialize for (A, B, C) +/// # {} +/// # } +/// # +/// # struct Tuple3<A, B, C>(A, B, C); +/// # +/// # impl<A, B, C> Serialize for Tuple3<A, B, C> +/// where +/// A: Serialize, +/// B: Serialize, +/// C: Serialize, +/// { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut tup = serializer.serialize_tuple(3)?; +/// tup.serialize_element(&self.0)?; +/// tup.serialize_element(&self.1)?; +/// tup.serialize_element(&self.2)?; +/// tup.end() +/// } +/// } +/// ``` +/// +/// ```edition2018 +/// # use std::marker::PhantomData; +/// # +/// # struct Array<T>(PhantomData<T>); +/// # +/// # impl<T> Array<T> { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, T> IntoIterator for &'a Array<T> { +/// # type Item = &'a T; +/// # type IntoIter = Box<Iterator<Item = &'a T>>; +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, Serializer, SerializeTuple}; +/// +/// # mod fool { +/// # trait Serialize {} +/// impl<T> Serialize for [T; 16] +/// # {} +/// # } +/// # +/// # impl<T> Serialize for Array<T> +/// where +/// T: Serialize, +/// { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut seq = serializer.serialize_tuple(16)?; +/// for element in self { +/// seq.serialize_element(element)?; +/// } +/// seq.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeTuple` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeTuple { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple element. + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Finish serializing a tuple. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_tuple_struct`. +/// +/// # Example use +/// +/// ```edition2018 +/// use serde::ser::{Serialize, SerializeTupleStruct, Serializer}; +/// +/// struct Rgb(u8, u8, u8); +/// +/// impl Serialize for Rgb { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut ts = serializer.serialize_tuple_struct("Rgb", 3)?; +/// ts.serialize_field(&self.0)?; +/// ts.serialize_field(&self.1)?; +/// ts.serialize_field(&self.2)?; +/// ts.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeTupleStruct` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeTupleStruct { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple struct field. + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Finish serializing a tuple struct. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_tuple_variant`. +/// +/// # Example use +/// +/// ```edition2018 +/// use serde::ser::{Serialize, SerializeTupleVariant, Serializer}; +/// +/// enum E { +/// T(u8, u8), +/// U(String, u32, u32), +/// } +/// +/// impl Serialize for E { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::T(ref a, ref b) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 0, "T", 2)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.end() +/// } +/// E::U(ref a, ref b, ref c) => { +/// let mut tv = serializer.serialize_tuple_variant("E", 1, "U", 3)?; +/// tv.serialize_field(a)?; +/// tv.serialize_field(b)?; +/// tv.serialize_field(c)?; +/// tv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeTupleVariant` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeTupleVariant { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a tuple variant field. + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Finish serializing a tuple variant. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_map`. +/// +/// # Example use +/// +/// ```edition2018 +/// # use std::marker::PhantomData; +/// # +/// # struct HashMap<K, V>(PhantomData<K>, PhantomData<V>); +/// # +/// # impl<K, V> HashMap<K, V> { +/// # fn len(&self) -> usize { +/// # unimplemented!() +/// # } +/// # } +/// # +/// # impl<'a, K, V> IntoIterator for &'a HashMap<K, V> { +/// # type Item = (&'a K, &'a V); +/// # type IntoIter = Box<Iterator<Item = (&'a K, &'a V)>>; +/// # +/// # fn into_iter(self) -> Self::IntoIter { +/// # unimplemented!() +/// # } +/// # } +/// # +/// use serde::ser::{Serialize, Serializer, SerializeMap}; +/// +/// impl<K, V> Serialize for HashMap<K, V> +/// where +/// K: Serialize, +/// V: Serialize, +/// { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut map = serializer.serialize_map(Some(self.len()))?; +/// for (k, v) in self { +/// map.serialize_entry(k, v)?; +/// } +/// map.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeMap` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeMap { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a map key. + /// + /// If possible, `Serialize` implementations are encouraged to use + /// `serialize_entry` instead as it may be implemented more efficiently in + /// some formats compared to a pair of calls to `serialize_key` and + /// `serialize_value`. + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Serialize a map value. + /// + /// # Panics + /// + /// Calling `serialize_value` before `serialize_key` is incorrect and is + /// allowed to panic or produce bogus results. + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize; + + /// Serialize a map entry consisting of a key and a value. + /// + /// Some [`Serialize`] types are not able to hold a key and value in memory + /// at the same time so `SerializeMap` implementations are required to + /// support [`serialize_key`] and [`serialize_value`] individually. The + /// `serialize_entry` method allows serializers to optimize for the case + /// where key and value are both available. [`Serialize`] implementations + /// are encouraged to use `serialize_entry` if possible. + /// + /// The default implementation delegates to [`serialize_key`] and + /// [`serialize_value`]. This is appropriate for serializers that do not + /// care about performance or are not able to optimize `serialize_entry` any + /// better than this. + /// + /// [`Serialize`]: ../trait.Serialize.html + /// [`serialize_key`]: #tymethod.serialize_key + /// [`serialize_value`]: #tymethod.serialize_value + fn serialize_entry<K: ?Sized, V: ?Sized>( + &mut self, + key: &K, + value: &V, + ) -> Result<(), Self::Error> + where + K: Serialize, + V: Serialize, + { + try!(self.serialize_key(key)); + self.serialize_value(value) + } + + /// Finish serializing a map. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_struct`. +/// +/// # Example use +/// +/// ```edition2018 +/// use serde::ser::{Serialize, SerializeStruct, Serializer}; +/// +/// struct Rgb { +/// r: u8, +/// g: u8, +/// b: u8, +/// } +/// +/// impl Serialize for Rgb { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// let mut rgb = serializer.serialize_struct("Rgb", 3)?; +/// rgb.serialize_field("r", &self.r)?; +/// rgb.serialize_field("g", &self.g)?; +/// rgb.serialize_field("b", &self.b)?; +/// rgb.end() +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeStruct` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeStruct { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct field. + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: Serialize; + + /// Indicate that a struct field has been skipped. + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { + let _ = key; + Ok(()) + } + + /// Finish serializing a struct. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +/// Returned from `Serializer::serialize_struct_variant`. +/// +/// # Example use +/// +/// ```edition2018 +/// use serde::ser::{Serialize, SerializeStructVariant, Serializer}; +/// +/// enum E { +/// S { r: u8, g: u8, b: u8 }, +/// } +/// +/// impl Serialize for E { +/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> +/// where +/// S: Serializer, +/// { +/// match *self { +/// E::S { +/// ref r, +/// ref g, +/// ref b, +/// } => { +/// let mut sv = serializer.serialize_struct_variant("E", 0, "S", 3)?; +/// sv.serialize_field("r", r)?; +/// sv.serialize_field("g", g)?; +/// sv.serialize_field("b", b)?; +/// sv.end() +/// } +/// } +/// } +/// } +/// ``` +/// +/// # Example implementation +/// +/// The [example data format] presented on the website demonstrates an +/// implementation of `SerializeStructVariant` for a basic JSON data format. +/// +/// [example data format]: https://serde.rs/data-format.html +pub trait SerializeStructVariant { + /// Must match the `Ok` type of our `Serializer`. + type Ok; + + /// Must match the `Error` type of our `Serializer`. + type Error: Error; + + /// Serialize a struct variant field. + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: Serialize; + + /// Indicate that a struct variant field has been skipped. + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { + let _ = key; + Ok(()) + } + + /// Finish serializing a struct variant. + fn end(self) -> Result<Self::Ok, Self::Error>; +} + +trait LenHint: Iterator { + fn len_hint(&self) -> Option<usize>; +} + +impl<I> LenHint for I +where + I: Iterator, +{ + #[cfg(not(feature = "unstable"))] + fn len_hint(&self) -> Option<usize> { + iterator_len_hint(self) + } + + #[cfg(feature = "unstable")] + default fn len_hint(&self) -> Option<usize> { + iterator_len_hint(self) + } +} + +#[cfg(feature = "unstable")] +impl<I> LenHint for I +where + I: ExactSizeIterator, +{ + fn len_hint(&self) -> Option<usize> { + Some(self.len()) + } +} + +fn iterator_len_hint<I>(iter: &I) -> Option<usize> +where + I: Iterator, +{ + match iter.size_hint() { + (lo, Some(hi)) if lo == hi => Some(lo), + _ => None, + } +} diff --git a/serde_derive/.cargo-checksum.json b/serde_derive/.cargo-checksum.json new file mode 100644 index 000000000..ddabf595e --- /dev/null +++ b/serde_derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f"} \ No newline at end of file diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml new file mode 100644 index 000000000..3d7b8e93a --- /dev/null +++ b/serde_derive/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "serde_derive" +version = "1.0.91" +authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] +include = ["Cargo.toml", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" +homepage = "https://serde.rs" +documentation = "https://serde.rs/derive.html" +readme = "crates-io.md" +keywords = ["serde", "serialization", "no_std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/serde-rs/serde" + +[lib] +name = "serde_derive" +proc-macro = true +[dependencies.proc-macro2] +version = "0.4" + +[dependencies.quote] +version = "0.6.3" + +[dependencies.syn] +version = "0.15.22" +features = ["visit"] +[dev-dependencies.serde] +version = "1.0" + +[features] +default = [] +deserialize_in_place = [] +[badges.appveyor] +repository = "serde-rs/serde" + +[badges.travis-ci] +repository = "serde-rs/serde" diff --git a/serde_derive/LICENSE-APACHE b/serde_derive/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/serde_derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/serde_derive/LICENSE-MIT b/serde_derive/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/serde_derive/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/serde_derive/README.md b/serde_derive/README.md new file mode 100644 index 000000000..b2626db94 --- /dev/null +++ b/serde_derive/README.md @@ -0,0 +1,99 @@ +# Serde   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.13+]][rustc] + +[Build Status]: https://api.travis-ci.org/serde-rs/serde.svg?branch=master +[travis]: https://travis-ci.org/serde-rs/serde +[Latest Version]: https://img.shields.io/crates/v/serde.svg +[crates.io]: https://crates.io/crates/serde +[Rustc Version 1.13+]: https://img.shields.io/badge/rustc-1.13+-lightgray.svg +[rustc]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Examples](https://serde.rs/examples.html) +- [API documentation](https://docs.serde.rs/serde/) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +<details> +<summary> +Click to show Cargo.toml. +<a href="https://play.rust-lang.org/?edition=2018&gist=72755f28f99afc95e01d63174b28c1f5" target="_blank">Run this code in the playground.</a> +</summary> + +```toml +[dependencies] + +# The core APIs, including the Serialize and Deserialize traits. Always +# required when using Serde. The "derive" feature is only required when +# using #[derive(Serialize, Deserialize)] to make Serde work with structs +# and enums defined in your crate. +serde = { version = "1.0", features = ["derive"] } + +# Each data format lives in its own crate; the sample code below uses JSON +# but you may be using a different one. +serde_json = "1.0" +``` + +</details> +<p></p> + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The +\#rust channel is also a good resource with generally faster response time but +less specific knowledge about Serde. If IRC is not your thing or you don't get a +good response, we are happy to respond to [GitHub issues][issues] as well. + +[irc]: https://wiki.mozilla.org/IRC +[issues]: https://github.com/serde-rs/serde/issues/new/choose + +## License + +Serde is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/serde_derive/crates-io.md b/serde_derive/crates-io.md new file mode 100644 index 000000000..3c6caa1a1 --- /dev/null +++ b/serde_derive/crates-io.md @@ -0,0 +1,52 @@ +<!-- Serde readme rendered on crates.io --> + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +You may be looking for: + +- [An overview of Serde](https://serde.rs/) +- [Data formats supported by Serde](https://serde.rs/#data-formats) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/derive.html) +- [Examples](https://serde.rs/examples.html) +- [API documentation](https://docs.serde.rs/serde/) +- [Release notes](https://github.com/serde-rs/serde/releases) + +## Serde in action + +```rust +use serde::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct Point { + x: i32, + y: i32, +} + +fn main() { + let point = Point { x: 1, y: 2 }; + + // Convert the Point to a JSON string. + let serialized = serde_json::to_string(&point).unwrap(); + + // Prints serialized = {"x":1,"y":2} + println!("serialized = {}", serialized); + + // Convert the JSON string back to a Point. + let deserialized: Point = serde_json::from_str(&serialized).unwrap(); + + // Prints deserialized = Point { x: 1, y: 2 } + println!("deserialized = {:?}", deserialized); +} +``` + +## Getting help + +Serde developers live in the #serde channel on [`irc.mozilla.org`][irc]. The +\#rust channel is also a good resource with generally faster response time but +less specific knowledge about Serde. If IRC is not your thing or you don't get a +good response, we are happy to respond to [GitHub issues][issues] as well. + +[irc]: https://wiki.mozilla.org/IRC +[issues]: https://github.com/serde-rs/serde/issues/new/choose diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs new file mode 100644 index 000000000..7257862de --- /dev/null +++ b/serde_derive/src/bound.rs @@ -0,0 +1,317 @@ +use std::collections::HashSet; + +use syn; +use syn::punctuated::{Pair, Punctuated}; +use syn::visit::{self, Visit}; + +use internals::ast::{Container, Data}; +use internals::attr; + +use proc_macro2::Span; + +// Remove the default from every type parameter because in the generated impls +// they look like associated types: "error: associated type bindings are not +// allowed here". +pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { + syn::Generics { + params: generics + .params + .iter() + .map(|param| match *param { + syn::GenericParam::Type(ref param) => syn::GenericParam::Type(syn::TypeParam { + eq_token: None, + default: None, + ..param.clone() + }), + _ => param.clone(), + }) + .collect(), + ..generics.clone() + } +} + +pub fn with_where_predicates( + generics: &syn::Generics, + predicates: &[syn::WherePredicate], +) -> syn::Generics { + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .extend(predicates.iter().cloned()); + generics +} + +pub fn with_where_predicates_from_fields( + cont: &Container, + generics: &syn::Generics, + from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let predicates = cont + .data + .all_fields() + .flat_map(|field| from_field(&field.attrs)) + .flat_map(|predicates| predicates.to_vec()); + + let mut generics = generics.clone(); + generics.make_where_clause().predicates.extend(predicates); + generics +} + +pub fn with_where_predicates_from_variants( + cont: &Container, + generics: &syn::Generics, + from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>, +) -> syn::Generics { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { + return generics.clone(); + } + }; + + let predicates = variants + .iter() + .flat_map(|variant| from_variant(&variant.attrs)) + .flat_map(|predicates| predicates.to_vec()); + + let mut generics = generics.clone(); + generics.make_where_clause().predicates.extend(predicates); + generics +} + +// Puts the given bound on any generic type parameters that are used in fields +// for which filter returns true. +// +// For example, the following struct needs the bound `A: Serialize, B: +// Serialize`. +// +// struct S<'b, A, B: 'b, C> { +// a: A, +// b: Option<&'b B> +// #[serde(skip_serializing)] +// c: C, +// } +pub fn with_bound( + cont: &Container, + generics: &syn::Generics, + filter: fn(&attr::Field, Option<&attr::Variant>) -> bool, + bound: &syn::Path, +) -> syn::Generics { + struct FindTyParams<'ast> { + // Set of all generic type parameters on the current struct (A, B, C in + // the example). Initialized up front. + all_type_params: HashSet<syn::Ident>, + + // Set of generic type parameters used in fields for which filter + // returns true (A and B in the example). Filled in as the visitor sees + // them. + relevant_type_params: HashSet<syn::Ident>, + + // Fields whose type is an associated type of one of the generic type + // parameters. + associated_type_usage: Vec<&'ast syn::TypePath>, + } + impl<'ast> Visit<'ast> for FindTyParams<'ast> { + fn visit_field(&mut self, field: &'ast syn::Field) { + if let syn::Type::Path(ref ty) = field.ty { + if let Some(Pair::Punctuated(ref t, _)) = ty.path.segments.first() { + if self.all_type_params.contains(&t.ident) { + self.associated_type_usage.push(ty); + } + } + } + self.visit_type(&field.ty); + } + + fn visit_path(&mut self, path: &'ast syn::Path) { + if let Some(seg) = path.segments.last() { + if seg.into_value().ident == "PhantomData" { + // Hardcoded exception, because PhantomData<T> implements + // Serialize and Deserialize whether or not T implements it. + return; + } + } + if path.leading_colon.is_none() && path.segments.len() == 1 { + let id = &path.segments[0].ident; + if self.all_type_params.contains(id) { + self.relevant_type_params.insert(id.clone()); + } + } + visit::visit_path(self, path); + } + + // Type parameter should not be considered used by a macro path. + // + // struct TypeMacro<T> { + // mac: T!(), + // marker: PhantomData<T>, + // } + fn visit_macro(&mut self, _mac: &'ast syn::Macro) {} + } + + let all_type_params = generics + .type_params() + .map(|param| param.ident.clone()) + .collect(); + + let mut visitor = FindTyParams { + all_type_params: all_type_params, + relevant_type_params: HashSet::new(), + associated_type_usage: Vec::new(), + }; + match cont.data { + Data::Enum(ref variants) => { + for variant in variants.iter() { + let relevant_fields = variant + .fields + .iter() + .filter(|field| filter(&field.attrs, Some(&variant.attrs))); + for field in relevant_fields { + visitor.visit_field(field.original); + } + } + } + Data::Struct(_, ref fields) => { + for field in fields.iter().filter(|field| filter(&field.attrs, None)) { + visitor.visit_field(field.original); + } + } + } + + let relevant_type_params = visitor.relevant_type_params; + let associated_type_usage = visitor.associated_type_usage; + let new_predicates = generics + .type_params() + .map(|param| param.ident.clone()) + .filter(|id| relevant_type_params.contains(id)) + .map(|id| syn::TypePath { + qself: None, + path: id.into(), + }) + .chain(associated_type_usage.into_iter().cloned()) + .map(|bounded_ty| { + syn::WherePredicate::Type(syn::PredicateType { + lifetimes: None, + // the type parameter that is being bounded e.g. T + bounded_ty: syn::Type::Path(bounded_ty), + colon_token: <Token![:]>::default(), + // the bound e.g. Serialize + bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: bound.clone(), + })] + .into_iter() + .collect(), + }) + }); + + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .extend(new_predicates); + generics +} + +pub fn with_self_bound( + cont: &Container, + generics: &syn::Generics, + bound: &syn::Path, +) -> syn::Generics { + let mut generics = generics.clone(); + generics + .make_where_clause() + .predicates + .push(syn::WherePredicate::Type(syn::PredicateType { + lifetimes: None, + // the type that is being bounded e.g. MyStruct<'a, T> + bounded_ty: type_of_item(cont), + colon_token: <Token![:]>::default(), + // the bound e.g. Default + bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: bound.clone(), + })] + .into_iter() + .collect(), + })); + generics +} + +pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { + let bound = syn::Lifetime::new(lifetime, Span::call_site()); + let def = syn::LifetimeDef { + attrs: Vec::new(), + lifetime: bound.clone(), + colon_token: None, + bounds: Punctuated::new(), + }; + + let params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params.iter().cloned().map(|mut param| { + match param { + syn::GenericParam::Lifetime(ref mut param) => { + param.bounds.push(bound.clone()); + } + syn::GenericParam::Type(ref mut param) => { + param + .bounds + .push(syn::TypeParamBound::Lifetime(bound.clone())); + } + syn::GenericParam::Const(_) => {} + } + param + })) + .collect(); + + syn::Generics { + params: params, + ..generics.clone() + } +} + +fn type_of_item(cont: &Container) -> syn::Type { + syn::Type::Path(syn::TypePath { + qself: None, + path: syn::Path { + leading_colon: None, + segments: vec![syn::PathSegment { + ident: cont.ident.clone(), + arguments: syn::PathArguments::AngleBracketed( + syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: <Token![<]>::default(), + args: cont + .generics + .params + .iter() + .map(|param| match *param { + syn::GenericParam::Type(ref param) => { + syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { + qself: None, + path: param.ident.clone().into(), + })) + } + syn::GenericParam::Lifetime(ref param) => { + syn::GenericArgument::Lifetime(param.lifetime.clone()) + } + syn::GenericParam::Const(_) => { + panic!("Serde does not support const generics yet"); + } + }) + .collect(), + gt_token: <Token![>]>::default(), + }, + ), + }] + .into_iter() + .collect(), + }, + }) +} diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs new file mode 100644 index 000000000..4c788845c --- /dev/null +++ b/serde_derive/src/de.rs @@ -0,0 +1,3011 @@ +use proc_macro2::{Literal, Span, TokenStream}; +use quote::ToTokens; +use syn::punctuated::Punctuated; +use syn::spanned::Spanned; +use syn::{self, Ident, Index, Member}; + +use bound; +use dummy; +use fragment::{Expr, Fragment, Match, Stmts}; +use internals::ast::{Container, Data, Field, Style, Variant}; +use internals::{attr, Ctxt, Derive}; +use pretend; + +use std::collections::BTreeSet; + +pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> { + let ctxt = Ctxt::new(); + let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; + precondition(&ctxt, &cont); + try!(ctxt.check()); + + let ident = &cont.ident; + let params = Parameters::new(&cont); + let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(¶ms); + let body = Stmts(deserialize_body(&cont, ¶ms)); + let delife = params.borrowed.de_lifetime(); + let serde = cont.attrs.serde_path(); + + let impl_block = if let Some(remote) = cont.attrs.remote() { + let vis = &input.vis; + let used = pretend::pretend_used(&cont); + quote! { + impl #de_impl_generics #ident #ty_generics #where_clause { + #vis fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result<#remote #ty_generics, __D::Error> + where + __D: #serde::Deserializer<#delife>, + { + #used + #body + } + } + } + } else { + let fn_deserialize_in_place = deserialize_in_place_body(&cont, ¶ms); + + quote! { + #[automatically_derived] + impl #de_impl_generics #serde::Deserialize<#delife> for #ident #ty_generics #where_clause { + fn deserialize<__D>(__deserializer: __D) -> #serde::export::Result<Self, __D::Error> + where + __D: #serde::Deserializer<#delife>, + { + #body + } + + #fn_deserialize_in_place + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + "DESERIALIZE", + ident, + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + precondition_sized(cx, cont); + precondition_no_de_lifetime(cx, cont); +} + +fn precondition_sized(cx: &Ctxt, cont: &Container) { + if let Data::Struct(_, ref fields) = cont.data { + if let Some(last) = fields.last() { + if let syn::Type::Slice(_) = *last.ty { + cx.error_spanned_by( + cont.original, + "cannot deserialize a dynamically sized struct", + ); + } + } + } +} + +fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) { + if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) { + for param in cont.generics.lifetimes() { + if param.lifetime.to_string() == "'de" { + cx.error_spanned_by( + ¶m.lifetime, + "cannot deserialize when there is a lifetime parameter called 'de", + ); + return; + } + } + } +} + +struct Parameters { + /// Name of the type the `derive` is on. + local: syn::Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types or `some::remote::Ident` for remote types. Does not include + /// generic parameters. + this: syn::Path, + + /// Generics including any explicit and inferred bounds for the impl. + generics: syn::Generics, + + /// Lifetimes borrowed from the deserializer. These will become bounds on + /// the `'de` lifetime of the deserializer. + borrowed: BorrowedLifetimes, + + /// At least one field has a serde(getter) attribute, implying that the + /// remote type has a private field. + has_getter: bool, +} + +impl Parameters { + fn new(cont: &Container) -> Self { + let local = cont.ident.clone(); + let this = match cont.attrs.remote() { + Some(remote) => remote.clone(), + None => cont.ident.clone().into(), + }; + let borrowed = borrowed_lifetimes(cont); + let generics = build_generics(cont, &borrowed); + let has_getter = cont.data.has_getter(); + + Parameters { + local: local, + this: this, + generics: generics, + borrowed: borrowed, + has_getter: has_getter, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Deserializer methods. + fn type_name(&self) -> String { + self.this.segments.last().unwrap().value().ident.to_string() + } +} + +// All the generics in the input, plus a bound `T: Deserialize` for each generic +// field type that will be deserialized by us, plus a bound `T: Default` for +// each generic field type that will be set to a default value. +fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = bound::with_where_predicates_from_fields(cont, &generics, attr::Field::de_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::de_bound); + + match cont.attrs.de_bound() { + Some(predicates) => bound::with_where_predicates(&generics, predicates), + None => { + let generics = match *cont.attrs.default() { + attr::Default::Default => { + bound::with_self_bound(cont, &generics, &parse_quote!(_serde::export::Default)) + } + attr::Default::None | attr::Default::Path(_) => generics, + }; + + let delife = borrowed.de_lifetime(); + let generics = bound::with_bound( + cont, + &generics, + needs_deserialize_bound, + &parse_quote!(_serde::Deserialize<#delife>), + ); + + bound::with_bound( + cont, + &generics, + requires_default, + &parse_quote!(_serde::export::Default), + ) + } + } +} + +// Fields with a `skip_deserializing` or `deserialize_with` attribute, or which +// belong to a variant with a `skip_deserializing` or `deserialize_with` +// attribute, are not deserialized by us so we do not generate a bound. Fields +// with a `bound` attribute specify their own bound so we do not generate one. +// All other fields may need a `T: Deserialize` bound where T is the type of the +// field. +fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_deserializing() + && field.deserialize_with().is_none() + && field.de_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_deserializing() + && variant.deserialize_with().is_none() + && variant.de_bound().is_none() + }) +} + +// Fields with a `default` attribute (not `default=...`), and fields with a +// `skip_deserializing` attribute that do not also have `default=...`. +fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool { + if let attr::Default::Default = *field.default() { + true + } else { + false + } +} + +enum BorrowedLifetimes { + Borrowed(BTreeSet<syn::Lifetime>), + Static, +} + +impl BorrowedLifetimes { + fn de_lifetime(&self) -> syn::Lifetime { + match *self { + BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de", Span::call_site()), + BorrowedLifetimes::Static => syn::Lifetime::new("'static", Span::call_site()), + } + } + + fn de_lifetime_def(&self) -> Option<syn::LifetimeDef> { + match *self { + BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: bounds.iter().cloned().collect(), + }), + BorrowedLifetimes::Static => None, + } + } +} + +// The union of lifetimes borrowed by each field of the container. +// +// These turn into bounds on the `'de` lifetime of the Deserialize impl. If +// lifetimes `'a` and `'b` are borrowed but `'c` is not, the impl is: +// +// impl<'de: 'a + 'b, 'a, 'b, 'c> Deserialize<'de> for S<'a, 'b, 'c> +// +// If any borrowed lifetime is `'static`, then `'de: 'static` would be redundant +// and we use plain `'static` instead of `'de`. +fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes { + let mut lifetimes = BTreeSet::new(); + for field in cont.data.all_fields() { + if !field.attrs.skip_deserializing() { + lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned()); + } + } + if lifetimes.iter().any(|b| b.to_string() == "'static") { + BorrowedLifetimes::Static + } else { + BorrowedLifetimes::Borrowed(lifetimes) + } +} + +fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + deserialize_transparent(cont, params) + } else if let Some(type_from) = cont.attrs.type_from() { + deserialize_from(type_from) + } else if let attr::Identifier::No = cont.attrs.identifier() { + match cont.data { + Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), + Data::Struct(Style::Struct, ref fields) => { + deserialize_struct(None, params, fields, &cont.attrs, None, &Untagged::No) + } + Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => { + deserialize_tuple(None, params, fields, &cont.attrs, None) + } + Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), + } + } else { + match cont.data { + Data::Enum(ref variants) => { + deserialize_custom_identifier(params, variants, &cont.attrs) + } + Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), + } + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<Stmts> { + // Only remote derives have getters, and we do not generate + // deserialize_in_place for remote derives. + assert!(!params.has_getter); + + if cont.attrs.transparent() + || cont.attrs.type_from().is_some() + || cont.attrs.identifier().is_some() + || cont + .data + .all_fields() + .all(|f| f.attrs.deserialize_with().is_some()) + { + return None; + } + + let code = match cont.data { + Data::Struct(Style::Struct, ref fields) => { + if let Some(code) = deserialize_struct_in_place(None, params, fields, &cont.attrs, None) + { + code + } else { + return None; + } + } + Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => { + deserialize_tuple_in_place(None, params, fields, &cont.attrs, None) + } + Data::Enum(_) | Data::Struct(Style::Unit, _) => { + return None; + } + }; + + let delife = params.borrowed.de_lifetime(); + let stmts = Stmts(code); + + let fn_deserialize_in_place = quote_block! { + fn deserialize_in_place<__D>(__deserializer: __D, __place: &mut Self) -> _serde::export::Result<(), __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + #stmts + } + }; + + Some(Stmts(fn_deserialize_in_place)) +} + +#[cfg(not(feature = "deserialize_in_place"))] +fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<Stmts> { + None +} + +fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment { + let fields = match cont.data { + Data::Struct(_, ref fields) => fields, + Data::Enum(_) => unreachable!(), + }; + + let this = ¶ms.this; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + + let path = match transparent_field.attrs.deserialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Deserialize::deserialize) + } + }; + + let assign = fields.iter().map(|field| { + let member = &field.member; + if field as *const Field == transparent_field as *const Field { + quote!(#member: __transparent) + } else { + let value = match *field.attrs.default() { + attr::Default::Default => quote!(_serde::export::Default::default()), + attr::Default::Path(ref path) => quote!(#path()), + attr::Default::None => quote!(_serde::export::PhantomData), + }; + quote!(#member: #value) + } + }); + + quote_block! { + _serde::export::Result::map( + #path(__deserializer), + |__transparent| #this { #(#assign),* }) + } +} + +fn deserialize_from(type_from: &syn::Type) -> Fragment { + quote_block! { + _serde::export::Result::map( + <#type_from as _serde::Deserialize>::deserialize(__deserializer), + _serde::export::From::from) + } +} + +fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { + let this = ¶ms.this; + let type_name = cattrs.name().deserialize_name(); + + let expecting = format!("unit struct {}", params.type_name()); + + quote_block! { + struct __Visitor; + + impl<'de> _serde::de::Visitor<'de> for __Visitor { + type Value = #this; + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_unit<__E>(self) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(#this) + } + } + + _serde::Deserializer::deserialize_unit_struct(__deserializer, #type_name, __Visitor) + } +} + +fn deserialize_tuple( + variant_ident: Option<&syn::Ident>, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + deserializer: Option<TokenStream>, +) -> Fragment { + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + assert!(!cattrs.has_flatten()); + + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this) + }; + + let is_enum = variant_ident.is_some(); + let type_path = match variant_ident { + Some(ref variant_ident) => quote!(#construct::#variant_ident), + None => construct, + }; + let expecting = match variant_ident { + Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), + None => format!("tuple struct {}", params.type_name()), + }; + + let nfields = fields.len(); + + let visit_newtype_struct = if !is_enum && nfields == 1 { + Some(deserialize_newtype_struct(&type_path, params, &fields[0])) + } else { + None + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, false, cattrs, &expecting, + )); + + let visitor_expr = quote! { + __Visitor { + marker: _serde::export::PhantomData::<#this #ty_generics>, + lifetime: _serde::export::PhantomData, + } + }; + let dispatch = if let Some(deserializer) = deserializer { + quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) + } else if is_enum { + quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) + } else if nfields == 1 { + let type_name = cattrs.name().deserialize_name(); + quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) + } else { + let type_name = cattrs.name().deserialize_name(); + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let visitor_var = if all_skipped { + quote!(_) + } else { + quote!(mut __seq) + }; + + quote_block! { + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_tuple_in_place( + variant_ident: Option<syn::Ident>, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + deserializer: Option<TokenStream>, +) -> Fragment { + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + assert!(!cattrs.has_flatten()); + + let is_enum = variant_ident.is_some(); + let expecting = match variant_ident { + Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident), + None => format!("tuple struct {}", params.type_name()), + }; + + let nfields = fields.len(); + + let visit_newtype_struct = if !is_enum && nfields == 1 { + Some(deserialize_newtype_struct_in_place(params, &fields[0])) + } else { + None + }; + + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); + + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::export::PhantomData, + } + }; + + let dispatch = if let Some(deserializer) = deserializer { + quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #nfields, #visitor_expr)) + } else if is_enum { + quote!(_serde::de::VariantAccess::tuple_variant(__variant, #nfields, #visitor_expr)) + } else if nfields == 1 { + let type_name = cattrs.name().deserialize_name(); + quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) + } else { + let type_name = cattrs.name().deserialize_name(); + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #nfields, #visitor_expr)) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let visitor_var = if all_skipped { + quote!(_) + } else { + quote!(mut __seq) + }; + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + quote_block! { + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this #ty_generics, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +fn deserialize_seq( + type_path: &TokenStream, + params: &Parameters, + fields: &[Field], + is_struct: bool, + cattrs: &attr::Container, + expecting: &str, +) -> Fragment { + let vars = (0..fields.len()).map(field_i as fn(_) -> _); + + let deserialized_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let expecting = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } else { + format!("{} with {} elements", expecting, deserialized_count) + }; + + let mut index_in_seq = 0_usize; + let let_values = vars.clone().zip(fields).map(|(var, field)| { + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + let #var = #default; + } + } else { + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::SeqAccess::next_element::<#field_ty>); + quote!(try!(#func(&mut __seq))) + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + _serde::export::Option::map( + try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)), + |__wrap| __wrap.value) + }) + } + }; + let value_if_none = match *field.attrs.default() { + attr::Default::Default => quote!(_serde::export::Default::default()), + attr::Default::Path(ref path) => quote!(#path()), + attr::Default::None => quote!( + return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); + ), + }; + let assign = quote! { + let #var = match #visit { + _serde::export::Some(__value) => __value, + _serde::export::None => { + #value_if_none + } + }; + }; + index_in_seq += 1; + assign + } + }); + + let mut result = if is_struct { + let names = fields.iter().map(|f| &f.member); + quote! { + #type_path { #( #names: #vars ),* } + } + } else { + quote! { + #type_path ( #(#vars),* ) + } + }; + + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + + let let_default = match *cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::export::Default::default(); + )), + attr::Default::Path(ref path) => Some(quote!( + let __default: Self::Value = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + quote_block! { + #let_default + #(#let_values)* + _serde::export::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_seq_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + expecting: &str, +) -> Fragment { + let deserialized_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + let expecting = if deserialized_count == 1 { + format!("{} with 1 element", expecting) + } else { + format!("{} with {} elements", expecting, deserialized_count) + }; + + let mut index_in_seq = 0usize; + let write_values = fields.iter().map(|field| { + let member = &field.member; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + quote! { + self.place.#member = #default; + } + } else { + let value_if_none = match *field.attrs.default() { + attr::Default::Default => quote!( + self.place.#member = _serde::export::Default::default(); + ), + attr::Default::Path(ref path) => quote!( + self.place.#member = #path(); + ), + attr::Default::None => quote!( + return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); + ), + }; + let write = match field.attrs.deserialize_with() { + None => { + quote! { + if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq, + _serde::private::de::InPlaceSeed(&mut self.place.#member))) + { + #value_if_none + } + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match try!(_serde::de::SeqAccess::next_element::<#wrapper_ty>(&mut __seq)) { + _serde::export::Some(__wrap) => { + self.place.#member = __wrap.value; + } + _serde::export::None => { + #value_if_none + } + } + }) + } + }; + index_in_seq += 1; + write + } + }); + + let this = ¶ms.this; + let (_, ty_generics, _) = params.generics.split_for_impl(); + let let_default = match *cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this #ty_generics = _serde::export::Default::default(); + )), + attr::Default::Path(ref path) => Some(quote!( + let __default: #this #ty_generics = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + quote_block! { + #let_default + #(#write_values)* + _serde::export::Ok(()) + } +} + +fn deserialize_newtype_struct( + type_path: &TokenStream, + params: &Parameters, + field: &Field, +) -> TokenStream { + let delife = params.borrowed.de_lifetime(); + let field_ty = field.ty; + + let value = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote! { + try!(#func(__e)) + } + } + Some(path) => { + quote! { + try!(#path(__e)) + } + } + }; + + let mut result = quote!(#type_path(__field0)); + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + + quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error> + where + __E: _serde::Deserializer<#delife>, + { + let __field0: #field_ty = #value; + _serde::export::Ok(#result) + } + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> TokenStream { + // We do not generate deserialize_in_place if every field has a + // deserialize_with. + assert!(field.attrs.deserialize_with().is_none()); + + let delife = params.borrowed.de_lifetime(); + + quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::export::Result<Self::Value, __E::Error> + where + __E: _serde::Deserializer<#delife>, + { + _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) + } + } +} + +enum Untagged { + Yes, + No, +} + +fn deserialize_struct( + variant_ident: Option<&syn::Ident>, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + deserializer: Option<TokenStream>, + untagged: &Untagged, +) -> Fragment { + let is_enum = variant_ident.is_some(); + + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this) + }; + + let type_path = match variant_ident { + Some(ref variant_ident) => quote!(#construct::#variant_ident), + None => construct, + }; + let expecting = match variant_ident { + Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), + None => format!("struct {}", params.type_name()), + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, true, cattrs, &expecting, + )); + + let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() { + deserialize_struct_as_map_visitor(&type_path, params, fields, cattrs) + } else { + deserialize_struct_as_struct_visitor(&type_path, params, fields, cattrs) + }; + let field_visitor = Stmts(field_visitor); + let fields_stmt = fields_stmt.map(Stmts); + let visit_map = Stmts(visit_map); + + let visitor_expr = quote! { + __Visitor { + marker: _serde::export::PhantomData::<#this #ty_generics>, + lifetime: _serde::export::PhantomData, + } + }; + let dispatch = if let Some(deserializer) = deserializer { + quote! { + _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + } + } else if is_enum && cattrs.has_flatten() { + quote! { + _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) + } + } else if is_enum { + quote! { + _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) + } + } else if cattrs.has_flatten() { + quote! { + _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) + } + } else { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) + } + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let visitor_var = if all_skipped { + quote!(_) + } else { + quote!(mut __seq) + }; + + // untagged struct variants do not get a visit_seq method. The same applies to + // structs that only have a map representation. + let visit_seq = match *untagged { + Untagged::No if !cattrs.has_flatten() => Some(quote! { + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + }), + _ => None, + }; + + let visitor_seed = if is_enum && cattrs.has_flatten() { + Some(quote! { + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result<Self::Value, __D::Error> + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_map(__deserializer, self) + } + } + }) + } else { + None + }; + + quote_block! { + #field_visitor + + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #visit_seq + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #visitor_seed + + #fields_stmt + + #dispatch + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_struct_in_place( + variant_ident: Option<syn::Ident>, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + deserializer: Option<TokenStream>, +) -> Option<Fragment> { + let is_enum = variant_ident.is_some(); + + // for now we do not support in_place deserialization for structs that + // are represented as map. + if cattrs.has_flatten() { + return None; + } + + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let expecting = match variant_ident { + Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident), + None => format!("struct {}", params.type_name()), + }; + + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); + + let (field_visitor, fields_stmt, visit_map) = + deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs); + + let field_visitor = Stmts(field_visitor); + let fields_stmt = Stmts(fields_stmt); + let visit_map = Stmts(visit_map); + + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::export::PhantomData, + } + }; + let dispatch = if let Some(deserializer) = deserializer { + quote! { + _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + } + } else if is_enum { + quote! { + _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) + } + } else { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) + } + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let visitor_var = if all_skipped { + quote!(_) + } else { + quote!(mut __seq) + }; + + let visit_seq = quote! { + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + }; + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + Some(quote_block! { + #field_visitor + + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this #ty_generics, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #visit_seq + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #fields_stmt + + #dispatch + }) +} + +fn deserialize_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + match *cattrs.tag() { + attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), + attr::TagType::Internal { ref tag } => { + deserialize_internally_tagged_enum(params, variants, cattrs, tag) + } + attr::TagType::Adjacent { + ref tag, + ref content, + } => deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content), + attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs), + } +} + +fn prepare_enum_variant_enum( + variants: &[Variant], + cattrs: &attr::Container, +) -> (TokenStream, Stmts) { + let variant_names_idents: Vec<_> = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + ( + variant.attrs.name().deserialize_name(), + field_i(i), + variant.attrs.aliases(), + ) + }) + .collect(); + + let other_idx = variants + .iter() + .position(|ref variant| variant.attrs.other()); + + let variants_stmt = { + let variant_names = variant_names_idents.iter().map(|&(ref name, _, _)| name); + quote! { + const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; + } + }; + + let variant_visitor = Stmts(deserialize_generated_identifier( + &variant_names_idents, + cattrs, + true, + other_idx, + )); + + (variants_stmt, variant_visitor) +} + +fn deserialize_externally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let type_name = cattrs.name().deserialize_name(); + let expecting = format!("enum {}", params.type_name()); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_externally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + (__Field::#variant_name, __variant) => #block + } + }); + + let all_skipped = variants + .iter() + .all(|variant| variant.attrs.skip_deserializing()); + let match_variant = if all_skipped { + // This is an empty enum like `enum Impossible {}` or an enum in which + // all variants have `#[serde(skip_deserializing)]`. + quote! { + // FIXME: Once we drop support for Rust 1.15: + // let _serde::export::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); + // _serde::export::Err(__err) + _serde::export::Result::map( + _serde::de::EnumAccess::variant::<__Field>(__data), + |(__impossible, _)| match __impossible {}) + } + } else { + quote! { + match try!(_serde::de::EnumAccess::variant(__data)) { + #(#variant_arms)* + } + } + }; + + quote_block! { + #variant_visitor + + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + fn visit_enum<__A>(self, __data: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::EnumAccess<#delife>, + { + #match_variant + } + } + + #variants_stmt + + _serde::Deserializer::deserialize_enum( + __deserializer, + #type_name, + VARIANTS, + __Visitor { + marker: _serde::export::PhantomData::<#this #ty_generics>, + lifetime: _serde::export::PhantomData, + }, + ) + } +} + +fn deserialize_internally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_internally_tagged_variant( + params, + variant, + cattrs, + quote! { + _serde::private::de::ContentDeserializer::<__D::Error>::new(__tagged.content) + }, + )); + + quote! { + __Field::#variant_name => #block + } + }); + + quote_block! { + #variant_visitor + + #variants_stmt + + let __tagged = try!(_serde::Deserializer::deserialize_any( + __deserializer, + _serde::private::de::TaggedContentVisitor::<__Field>::new(#tag))); + + match __tagged.tag { + #(#variant_arms)* + } + } +} + +fn deserialize_adjacently_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, + content: &str, +) -> Fragment { + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs); + + let variant_arms: &Vec<_> = &variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_index = field_i(i); + + let block = Match(deserialize_untagged_variant( + params, + variant, + cattrs, + quote!(__deserializer), + )); + + quote! { + __Field::#variant_index => #block + } + }) + .collect(); + + let expecting = format!("adjacently tagged enum {}", params.type_name()); + let type_name = cattrs.name().deserialize_name(); + let deny_unknown_fields = cattrs.deny_unknown_fields(); + + // If unknown fields are allowed, we pick the visitor that can step over + // those. Otherwise we pick the visitor that fails on unknown keys. + let field_visitor_ty = if deny_unknown_fields { + quote! { _serde::private::de::TagOrContentFieldVisitor } + } else { + quote! { _serde::private::de::TagContentOtherFieldVisitor } + }; + + let tag_or_content = quote! { + #field_visitor_ty { + tag: #tag, + content: #content, + } + }; + + fn is_unit(variant: &Variant) -> bool { + match variant.style { + Style::Unit => true, + Style::Struct | Style::Tuple | Style::Newtype => false, + } + } + + let mut missing_content = quote! { + _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) + }; + if variants.iter().any(is_unit) { + let fallthrough = if variants.iter().all(is_unit) { + None + } else { + Some(quote! { + _ => #missing_content + }) + }; + let arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing() && is_unit(variant)) + .map(|(i, variant)| { + let variant_index = field_i(i); + let variant_ident = &variant.ident; + quote! { + __Field::#variant_index => _serde::export::Ok(#this::#variant_ident), + } + }); + missing_content = quote! { + match __field { + #(#arms)* + #fallthrough + } + }; + } + + // Advance the map by one key, returning early in case of error. + let next_key = quote! { + try!(_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)) + }; + + // When allowing unknown fields, we want to transparently step through keys + // we don't care about until we find `tag`, `content`, or run out of keys. + let next_relevant_key = if deny_unknown_fields { + next_key + } else { + quote!({ + let mut __rk : _serde::export::Option<_serde::private::de::TagOrContentField> = _serde::export::None; + while let _serde::export::Some(__k) = #next_key { + match __k { + _serde::private::de::TagContentOtherField::Other => { + try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); + continue; + }, + _serde::private::de::TagContentOtherField::Tag => { + __rk = _serde::export::Some(_serde::private::de::TagOrContentField::Tag); + break; + } + _serde::private::de::TagContentOtherField::Content => { + __rk = _serde::export::Some(_serde::private::de::TagOrContentField::Content); + break; + } + } + } + + __rk + }) + }; + + // Step through remaining keys, looking for duplicates of previously-seen + // keys. When unknown fields are denied, any key that isn't a duplicate will + // at this point immediately produce an error. + let visit_remaining_keys = quote! { + match #next_relevant_key { + _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { + _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { + _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + _serde::export::None => _serde::export::Ok(__ret), + } + }; + + let finish_content_then_tag = if variant_arms.is_empty() { + quote! { + match try!(_serde::de::MapAccess::next_value::<__Field>(&mut __map)) {} + } + } else { + quote! { + let __ret = try!(match try!(_serde::de::MapAccess::next_value(&mut __map)) { + // Deserialize the buffered content now that we know the variant. + #(#variant_arms)* + }); + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + }; + + quote_block! { + #variant_visitor + + #variants_stmt + + struct __Seed #de_impl_generics #where_clause { + field: __Field, + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::export::Result<Self::Value, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + match self.field { + #(#variant_arms)* + } + } + } + + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + fn visit_map<__A>(self, mut __map: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::MapAccess<#delife>, + { + // Visit the first relevant key. + match #next_relevant_key { + // First key is the tag. + _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { + // Parse the tag. + let __field = try!(_serde::de::MapAccess::next_value(&mut __map)); + // Visit the second key. + match #next_relevant_key { + // Second key is a duplicate of the tag. + _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { + _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + // Second key is the content. + _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { + let __ret = try!(_serde::de::MapAccess::next_value_seed(&mut __map, + __Seed { + field: __field, + marker: _serde::export::PhantomData, + lifetime: _serde::export::PhantomData, + })); + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + // There is no second key; might be okay if the we have a unit variant. + _serde::export::None => #missing_content + } + } + // First key is the content. + _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { + // Buffer up the content. + let __content = try!(_serde::de::MapAccess::next_value::<_serde::private::de::Content>(&mut __map)); + // Visit the second key. + match #next_relevant_key { + // Second key is the tag. + _serde::export::Some(_serde::private::de::TagOrContentField::Tag) => { + let __deserializer = _serde::private::de::ContentDeserializer::<__A::Error>::new(__content); + #finish_content_then_tag + } + // Second key is a duplicate of the content. + _serde::export::Some(_serde::private::de::TagOrContentField::Content) => { + _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + // There is no second key. + _serde::export::None => { + _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + // There is no first key. + _serde::export::None => { + _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + + fn visit_seq<__A>(self, mut __seq: __A) -> _serde::export::Result<Self::Value, __A::Error> + where + __A: _serde::de::SeqAccess<#delife>, + { + // Visit the first element - the tag. + match try!(_serde::de::SeqAccess::next_element(&mut __seq)) { + _serde::export::Some(__field) => { + // Visit the second element - the content. + match try!(_serde::de::SeqAccess::next_element_seed( + &mut __seq, + __Seed { + field: __field, + marker: _serde::export::PhantomData, + lifetime: _serde::export::PhantomData, + }, + )) { + _serde::export::Some(__ret) => _serde::export::Ok(__ret), + // There is no second element. + _serde::export::None => { + _serde::export::Err(_serde::de::Error::invalid_length(1, &self)) + } + } + } + // There is no first element. + _serde::export::None => { + _serde::export::Err(_serde::de::Error::invalid_length(0, &self)) + } + } + } + } + + const FIELDS: &'static [&'static str] = &[#tag, #content]; + _serde::Deserializer::deserialize_struct( + __deserializer, + #type_name, + FIELDS, + __Visitor { + marker: _serde::export::PhantomData::<#this #ty_generics>, + lifetime: _serde::export::PhantomData, + }, + ) + } +} + +fn deserialize_untagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let attempts = variants + .iter() + .filter(|variant| !variant.attrs.skip_deserializing()) + .map(|variant| { + Expr(deserialize_untagged_variant( + params, + variant, + cattrs, + quote!(_serde::private::de::ContentRefDeserializer::<__D::Error>::new(&__content)), + )) + }); + + // TODO this message could be better by saving the errors from the failed + // attempts. The heuristic used by TOML was to count the number of fields + // processed before an error, and use the error that happened after the + // largest number of fields. I'm not sure I like that. Maybe it would be + // better to save all the errors and combine them into one message that + // explains why none of the variants matched. + let fallthrough_msg = format!( + "data did not match any variant of untagged enum {}", + params.type_name() + ); + + quote_block! { + let __content = try!(<_serde::private::de::Content as _serde::Deserialize>::deserialize(__deserializer)); + + #( + if let _serde::export::Ok(__ok) = #attempts { + return _serde::export::Ok(__ok); + } + )* + + _serde::export::Err(_serde::de::Error::custom(#fallthrough_msg)) + } +} + +fn deserialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); + return quote_block! { + #wrapper + _serde::export::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this = ¶ms.this; + quote_block! { + try!(_serde::de::VariantAccess::unit_variant(__variant)); + _serde::export::Ok(#this::#variant_ident) + } + } + Style::Newtype => { + deserialize_externally_tagged_newtype_variant(variant_ident, params, &variant.fields[0]) + } + Style::Tuple => { + deserialize_tuple(Some(variant_ident), params, &variant.fields, cattrs, None) + } + Style::Struct => deserialize_struct( + Some(variant_ident), + params, + &variant.fields, + cattrs, + None, + &Untagged::No, + ), + } +} + +fn deserialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + deserializer: TokenStream, +) -> Fragment { + if variant.attrs.deserialize_with().is_some() { + return deserialize_untagged_variant(params, variant, cattrs, deserializer); + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this = ¶ms.this; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + quote_block! { + try!(_serde::Deserializer::deserialize_any(#deserializer, _serde::private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))); + _serde::export::Ok(#this::#variant_ident) + } + } + Style::Newtype => deserialize_untagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + &deserializer, + ), + Style::Struct => deserialize_struct( + Some(variant_ident), + params, + &variant.fields, + cattrs, + Some(deserializer), + &Untagged::No, + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} + +fn deserialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + deserializer: TokenStream, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); + return quote_block! { + #wrapper + _serde::export::Result::map( + <#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this = ¶ms.this; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + quote_expr! { + match _serde::Deserializer::deserialize_any( + #deserializer, + _serde::private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) + ) { + _serde::export::Ok(()) => _serde::export::Ok(#this::#variant_ident), + _serde::export::Err(__err) => _serde::export::Err(__err), + } + } + } + Style::Newtype => deserialize_untagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + &deserializer, + ), + Style::Tuple => deserialize_tuple( + Some(variant_ident), + params, + &variant.fields, + cattrs, + Some(deserializer), + ), + Style::Struct => deserialize_struct( + Some(variant_ident), + params, + &variant.fields, + cattrs, + Some(deserializer), + &Untagged::Yes, + ), + } +} + +fn deserialize_externally_tagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, +) -> Fragment { + let this = ¶ms.this; + match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); + quote_expr! { + _serde::export::Result::map(#func(__variant), #this::#variant_ident) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote_block! { + #wrapper + _serde::export::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), + |__wrapper| #this::#variant_ident(__wrapper.value)) + } + } + } +} + +fn deserialize_untagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, + deserializer: &TokenStream, +) -> Fragment { + let this = ¶ms.this; + let field_ty = field.ty; + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote_expr! { + _serde::export::Result::map(#func(#deserializer), #this::#variant_ident) + } + } + Some(path) => { + quote_block! { + let __value: _serde::export::Result<#field_ty, _> = #path(#deserializer); + _serde::export::Result::map(__value, #this::#variant_ident) + } + } + } +} + +fn deserialize_generated_identifier( + fields: &[(String, Ident, Vec<String>)], + cattrs: &attr::Container, + is_variant: bool, + other_idx: Option<usize>, +) -> Fragment { + let this = quote!(__Field); + let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident, _)| ident).collect(); + + let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { + let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),); + let fallthrough = quote!(_serde::export::Ok(__Field::__other(__value))); + (Some(ignore_variant), Some(fallthrough)) + } else if let Some(other_idx) = other_idx { + let ignore_variant = fields[other_idx].1.clone(); + let fallthrough = quote!(_serde::export::Ok(__Field::#ignore_variant)); + (None, Some(fallthrough)) + } else if is_variant || cattrs.deny_unknown_fields() { + (None, None) + } else { + let ignore_variant = quote!(__ignore,); + let fallthrough = quote!(_serde::export::Ok(__Field::__ignore)); + (Some(ignore_variant), Some(fallthrough)) + }; + + let visitor_impl = Stmts(deserialize_identifier( + &this, + fields, + is_variant, + fallthrough, + !is_variant && cattrs.has_flatten(), + )); + + let lifetime = if !is_variant && cattrs.has_flatten() { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + struct __FieldVisitor; + + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error> + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + +fn deserialize_custom_identifier( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let is_variant = match cattrs.identifier() { + attr::Identifier::Variant => true, + attr::Identifier::Field => false, + attr::Identifier::No => unreachable!(), + }; + + let this = ¶ms.this; + let this = quote!(#this); + + let (ordinary, fallthrough) = if let Some(last) = variants.last() { + let last_ident = &last.ident; + if last.attrs.other() { + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = quote!(_serde::export::Ok(#this::#last_ident)); + (ordinary, Some(fallthrough)) + } else if let Style::Newtype = last.style { + let ordinary = &variants[..variants.len() - 1]; + let deserializer = quote!(_serde::private::de::IdentifierDeserializer::from(__value)); + let fallthrough = quote! { + _serde::export::Result::map( + _serde::Deserialize::deserialize(#deserializer), + #this::#last_ident) + }; + (ordinary, Some(fallthrough)) + } else { + (variants, None) + } + } else { + (variants, None) + }; + + let names_idents: Vec<_> = ordinary + .iter() + .map(|variant| { + ( + variant.attrs.name().deserialize_name(), + variant.ident.clone(), + variant.attrs.aliases(), + ) + }) + .collect(); + + let names = names_idents.iter().map(|&(ref name, _, _)| name); + + let names_const = if fallthrough.is_some() { + None + } else if is_variant { + let variants = quote! { + const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(variants) + } else { + let fields = quote! { + const FIELDS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(fields) + }; + + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + let visitor_impl = Stmts(deserialize_identifier( + &this, + &names_idents, + is_variant, + fallthrough, + false, + )); + + quote_block! { + #names_const + + struct __FieldVisitor #de_impl_generics #where_clause { + marker: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::de::Visitor<#delife> for __FieldVisitor #de_ty_generics #where_clause { + type Value = #this #ty_generics; + + #visitor_impl + } + + let __visitor = __FieldVisitor { + marker: _serde::export::PhantomData::<#this #ty_generics>, + lifetime: _serde::export::PhantomData, + }; + _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) + } +} + +fn deserialize_identifier( + this: &TokenStream, + fields: &[(String, Ident, Vec<String>)], + is_variant: bool, + fallthrough: Option<TokenStream>, + collect_other_fields: bool, +) -> Fragment { + let mut flat_fields = Vec::new(); + for &(_, ref ident, ref aliases) in fields { + flat_fields.extend(aliases.iter().map(|alias| (alias, ident))) + } + + let field_strs = flat_fields.iter().map(|&(ref name, _)| name); + let field_borrowed_strs = flat_fields.iter().map(|&(ref name, _)| name); + let field_bytes = flat_fields + .iter() + .map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); + let field_borrowed_bytes = flat_fields + .iter() + .map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); + + let constructors: &Vec<_> = &flat_fields + .iter() + .map(|&(_, ref ident)| quote!(#this::#ident)) + .collect(); + let main_constructors: &Vec<_> = &fields + .iter() + .map(|&(_, ref ident, _)| quote!(#this::#ident)) + .collect(); + + let expecting = if is_variant { + "variant identifier" + } else { + "field identifier" + }; + + let index_expecting = if is_variant { "variant" } else { "field" }; + + let bytes_to_str = if fallthrough.is_some() || collect_other_fields { + None + } else { + Some(quote! { + let __value = &_serde::export::from_utf8_lossy(__value); + }) + }; + + let ( + value_as_str_content, + value_as_borrowed_str_content, + value_as_bytes_content, + value_as_borrowed_bytes_content, + ) = if collect_other_fields { + ( + Some(quote! { + let __value = _serde::private::de::Content::String(__value.to_string()); + }), + Some(quote! { + let __value = _serde::private::de::Content::Str(__value); + }), + Some(quote! { + let __value = _serde::private::de::Content::ByteBuf(__value.to_vec()); + }), + Some(quote! { + let __value = _serde::private::de::Content::Bytes(__value); + }), + ) + } else { + (None, None, None, None) + }; + + let fallthrough_arm = if let Some(fallthrough) = fallthrough { + fallthrough + } else if is_variant { + quote! { + _serde::export::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) + } + } else { + quote! { + _serde::export::Err(_serde::de::Error::unknown_field(__value, FIELDS)) + } + }; + + let variant_indices = 0_u64..; + let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); + let visit_other = if collect_other_fields { + quote! { + fn visit_bool<__E>(self, __value: bool) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::Bool(__value))) + } + + fn visit_i8<__E>(self, __value: i8) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::I8(__value))) + } + + fn visit_i16<__E>(self, __value: i16) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::I16(__value))) + } + + fn visit_i32<__E>(self, __value: i32) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::I32(__value))) + } + + fn visit_i64<__E>(self, __value: i64) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::I64(__value))) + } + + fn visit_u8<__E>(self, __value: u8) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::U8(__value))) + } + + fn visit_u16<__E>(self, __value: u16) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::U16(__value))) + } + + fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::U32(__value))) + } + + fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::U64(__value))) + } + + fn visit_f32<__E>(self, __value: f32) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::F32(__value))) + } + + fn visit_f64<__E>(self, __value: f64) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::F64(__value))) + } + + fn visit_char<__E>(self, __value: char) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::Char(__value))) + } + + fn visit_unit<__E>(self) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + _serde::export::Ok(__Field::__other(_serde::private::de::Content::Unit)) + } + + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #( + #field_borrowed_strs => _serde::export::Ok(#constructors), + )* + _ => { + #value_as_borrowed_str_content + #fallthrough_arm + } + } + } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #( + #field_borrowed_bytes => _serde::export::Ok(#constructors), + )* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_arm + } + } + } + } + } else { + quote! { + fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #( + #variant_indices => _serde::export::Ok(#main_constructors), + )* + _ => _serde::export::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + } + } + } + }; + + quote_block! { + fn expecting(&self, __formatter: &mut _serde::export::Formatter) -> _serde::export::fmt::Result { + _serde::export::Formatter::write_str(__formatter, #expecting) + } + + #visit_other + + fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #( + #field_strs => _serde::export::Ok(#constructors), + )* + _ => { + #value_as_str_content + #fallthrough_arm + } + } + } + + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::export::Result<Self::Value, __E> + where + __E: _serde::de::Error, + { + match __value { + #( + #field_bytes => _serde::export::Ok(#constructors), + )* + _ => { + #bytes_to_str + #value_as_bytes_content + #fallthrough_arm + } + } + } + } +} + +fn deserialize_struct_as_struct_visitor( + struct_path: &TokenStream, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> (Fragment, Option<Fragment>, Fragment) { + assert!(!cattrs.has_flatten()); + + let field_names_idents: Vec<_> = fields + .iter() + .enumerate() + .filter(|&(_, field)| !field.attrs.skip_deserializing()) + .map(|(i, field)| { + ( + field.attrs.name().deserialize_name(), + field_i(i), + field.attrs.aliases(), + ) + }) + .collect(); + + let fields_stmt = { + let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name); + quote_block! { + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + } + }; + + let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); + + let visit_map = deserialize_map(struct_path, params, fields, cattrs); + + (field_visitor, Some(fields_stmt), visit_map) +} + +fn deserialize_struct_as_map_visitor( + struct_path: &TokenStream, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> (Fragment, Option<Fragment>, Fragment) { + let field_names_idents: Vec<_> = fields + .iter() + .enumerate() + .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(i, field)| { + ( + field.attrs.name().deserialize_name(), + field_i(i), + field.attrs.aliases(), + ) + }) + .collect(); + + let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); + + let visit_map = deserialize_map(struct_path, params, fields, cattrs); + + (field_visitor, None, visit_map) +} + +fn deserialize_map( + struct_path: &TokenStream, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // Declare each field that will be deserialized. + let let_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|&(field, ref name)| { + let field_ty = field.ty; + quote! { + let mut #name: _serde::export::Option<#field_ty> = _serde::export::None; + } + }); + + // Collect contents for flatten fields into a buffer + let let_collect = if cattrs.has_flatten() { + Some(quote! { + let mut __collect = _serde::export::Vec::<_serde::export::Option<( + _serde::private::de::Content, + _serde::private::de::Content + )>>::new(); + }) + } else { + None + }; + + // Match arms to extract a value for a field. + let value_arms = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|&(field, ref name)| { + let deser_name = field.attrs.name().deserialize_name(); + + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); + quote! { + try!(#func(&mut __map)) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::export::Ok(__wrapper) => __wrapper.value, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + } + }) + } + }; + quote! { + __Field::#name => { + if _serde::export::Option::is_some(&#name) { + return _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #name = _serde::export::Some(#visit); + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if cattrs.has_flatten() { + Some(quote! { + __Field::__other(__name) => { + __collect.push(_serde::export::Some(( + __name, + try!(_serde::de::MapAccess::next_value(&mut __map))))); + } + }) + } else if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once we drop support for Rust 1.15: + // let _serde::export::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); + _serde::export::Option::map( + try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::export::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) { + match __key { + #(#value_arms)* + #ignored_arm + } + } + } + }; + + let extract_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|&(field, ref name)| { + let missing_expr = Match(expr_is_missing(field, cattrs)); + + quote! { + let #name = match #name { + _serde::export::Some(#name) => #name, + _serde::export::None => #missing_expr + }; + } + }); + + let extract_collected = fields_names + .iter() + .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) + .map(|&(field, ref name)| { + let field_ty = field.ty; + let func = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + quote_spanned!(span=> _serde::de::Deserialize::deserialize) + } + Some(path) => quote!(#path), + }; + quote! { + let #name: #field_ty = try!(#func( + _serde::private::de::FlatMapDeserializer( + &mut __collect, + _serde::export::PhantomData))); + } + }); + + let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { + Some(quote! { + if let _serde::export::Some(_serde::export::Some((__key, _))) = + __collect.into_iter().filter(_serde::export::Option::is_some).next() + { + if let _serde::export::Some(__key) = __key.as_str() { + return _serde::export::Err( + _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); + } else { + return _serde::export::Err( + _serde::de::Error::custom(format_args!("unexpected map key"))); + } + } + }) + } else { + None + }; + + let result = fields_names.iter().map(|&(field, ref name)| { + let member = &field.member; + if field.attrs.skip_deserializing() { + let value = Expr(expr_is_missing(field, cattrs)); + quote!(#member: #value) + } else { + quote!(#member: #name) + } + }); + + let let_default = match *cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::export::Default::default(); + )), + attr::Default::Path(ref path) => Some(quote!( + let __default: Self::Value = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + let mut result = quote!(#struct_path { #(#result),* }); + if params.has_getter { + let this = ¶ms.this; + result = quote! { + _serde::export::Into::<#this>::into(#result) + }; + } + + quote_block! { + #(#let_values)* + + #let_collect + + #match_keys + + #let_default + + #(#extract_values)* + + #(#extract_collected)* + + #collected_deny_unknown_fields + + _serde::export::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_struct_as_struct_in_place_visitor( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> (Fragment, Fragment, Fragment) { + assert!(!cattrs.has_flatten()); + + let field_names_idents: Vec<_> = fields + .iter() + .enumerate() + .filter(|&(_, field)| !field.attrs.skip_deserializing()) + .map(|(i, field)| { + ( + field.attrs.name().deserialize_name(), + field_i(i), + field.attrs.aliases(), + ) + }) + .collect(); + + let fields_stmt = { + let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name); + quote_block! { + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + } + }; + + let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None); + + let visit_map = deserialize_map_in_place(params, fields, cattrs); + + (field_visitor, fields_stmt, visit_map) +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_map_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!(!cattrs.has_flatten()); + + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // For deserialize_in_place, declare booleans for each field that will be + // deserialized. + let let_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|&(_, ref name)| { + quote! { + let mut #name: bool = false; + } + }); + + // Match arms to extract a value for a field. + let value_arms_from = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|&(field, ref name)| { + let deser_name = field.attrs.name().deserialize_name(); + let member = &field.member; + + let visit = match field.attrs.deserialize_with() { + None => { + quote! { + try!(_serde::de::MapAccess::next_value_seed(&mut __map, _serde::private::de::InPlaceSeed(&mut self.place.#member))) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::export::Ok(__wrapper) => __wrapper.value, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + }; + }) + } + }; + quote! { + __Field::#name => { + if #name { + return _serde::export::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #visit; + #name = true; + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once we drop support for Rust 1.15: + // let _serde::export::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); + _serde::export::Option::map( + try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::export::Some(__key) = try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)) { + match __key { + #(#value_arms_from)* + #ignored_arm + } + } + } + }; + + let check_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|&(field, ref name)| { + let missing_expr = expr_is_missing(field, cattrs); + // If missing_expr unconditionally returns an error, don't try + // to assign its value to self.place. + if field.attrs.default().is_none() + && cattrs.default().is_none() + && field.attrs.deserialize_with().is_some() + { + let missing_expr = Stmts(missing_expr); + quote! { + if !#name { + #missing_expr; + } + } + } else { + let member = &field.member; + let missing_expr = Expr(missing_expr); + quote! { + if !#name { + self.place.#member = #missing_expr; + }; + } + } + }); + + let this = ¶ms.this; + let (_, _, ty_generics, _) = split_with_de_lifetime(params); + + let let_default = match *cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this #ty_generics = _serde::export::Default::default(); + )), + attr::Default::Path(ref path) => Some(quote!( + let __default: #this #ty_generics = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + quote_block! { + #(#let_flags)* + + #match_keys + + #let_default + + #(#check_flags)* + + _serde::export::Ok(()) + } +} + +fn field_i(i: usize) -> Ident { + Ident::new(&format!("__field{}", i), Span::call_site()) +} + +/// This function wraps the expression in `#[serde(deserialize_with = "...")]` +/// in a trait to prevent it from accessing the internal `Deserialize` state. +fn wrap_deserialize_with( + params: &Parameters, + value_ty: &TokenStream, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + let this = ¶ms.this; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = + split_with_de_lifetime(params); + let delife = params.borrowed.de_lifetime(); + + let wrapper = quote! { + struct __DeserializeWith #de_impl_generics #where_clause { + value: #value_ty, + phantom: _serde::export::PhantomData<#this #ty_generics>, + lifetime: _serde::export::PhantomData<&#delife ()>, + } + + impl #de_impl_generics _serde::Deserialize<#delife> for __DeserializeWith #de_ty_generics #where_clause { + fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error> + where + __D: _serde::Deserializer<#delife>, + { + _serde::export::Ok(__DeserializeWith { + value: try!(#deserialize_with(__deserializer)), + phantom: _serde::export::PhantomData, + lifetime: _serde::export::PhantomData, + }) + } + } + }; + + let wrapper_ty = quote!(__DeserializeWith #de_ty_generics); + + (wrapper, wrapper_ty) +} + +fn wrap_deserialize_field_with( + params: &Parameters, + field_ty: &syn::Type, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream) { + wrap_deserialize_with(params, "e!(#field_ty), deserialize_with) +} + +fn wrap_deserialize_variant_with( + params: &Parameters, + variant: &Variant, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream, TokenStream) { + let this = ¶ms.this; + let variant_ident = &variant.ident; + + let field_tys = variant.fields.iter().map(|field| field.ty); + let (wrapper, wrapper_ty) = + wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); + + let field_access = (0..variant.fields.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + let unwrap_fn = match variant.style { + Style::Struct if variant.fields.len() == 1 => { + let member = &variant.fields[0].member; + quote! { + |__wrap| #this::#variant_ident { #member: __wrap.value } + } + } + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote! { + |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* } + } + } + Style::Tuple => quote! { + |__wrap| #this::#variant_ident(#(__wrap.value.#field_access),*) + }, + Style::Newtype => quote! { + |__wrap| #this::#variant_ident(__wrap.value) + }, + Style::Unit => quote! { + |__wrap| #this::#variant_ident + }, + }; + + (wrapper, wrapper_ty, unwrap_fn) +} + +fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment { + match *field.attrs.default() { + attr::Default::Default => { + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::export::Default::default); + return quote_expr!(#func()); + } + attr::Default::Path(ref path) => { + return quote_expr!(#path()); + } + attr::Default::None => { /* below */ } + } + + match *cattrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let member = &field.member; + return quote_expr!(__default.#member); + } + attr::Default::None => { /* below */ } + } + + let name = field.attrs.name().deserialize_name(); + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::private::de::missing_field); + quote_expr! { + try!(#func(#name)) + } + } + Some(_) => { + quote_expr! { + return _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#name)) + } + } + } +} + +struct DeImplGenerics<'a>(&'a Parameters); +#[cfg(feature = "deserialize_in_place")] +struct InPlaceImplGenerics<'a>(&'a Parameters); + +impl<'a> ToTokens for DeImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let place_lifetime = place_lifetime(); + let mut generics = self.0.generics.clone(); + + // Add lifetime for `&'place mut Self, and `'a: 'place` + for param in &mut generics.params { + match *param { + syn::GenericParam::Lifetime(ref mut param) => { + param.bounds.push(place_lifetime.lifetime.clone()); + } + syn::GenericParam::Type(ref mut param) => { + param.bounds.push(syn::TypeParamBound::Lifetime( + place_lifetime.lifetime.clone(), + )); + } + syn::GenericParam::Const(_) => {} + } + } + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (impl_generics, _, _) = generics.split_for_impl(); + impl_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeImplGenerics<'a> { + fn in_place(self) -> InPlaceImplGenerics<'a> { + InPlaceImplGenerics(self.0) + } +} + +struct DeTypeGenerics<'a>(&'a Parameters); +#[cfg(feature = "deserialize_in_place")] +struct InPlaceTypeGenerics<'a>(&'a Parameters); + +impl<'a> ToTokens for DeTypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + if self.0.borrowed.de_lifetime_def().is_some() { + let def = syn::LifetimeDef { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + }; + generics.params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (_, ty_generics, _) = generics.split_for_impl(); + ty_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> ToTokens for InPlaceTypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut generics = self.0.generics.clone(); + generics.params = Some(syn::GenericParam::Lifetime(place_lifetime())) + .into_iter() + .chain(generics.params) + .collect(); + + if self.0.borrowed.de_lifetime_def().is_some() { + let def = syn::LifetimeDef { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'de", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + }; + generics.params = Some(syn::GenericParam::Lifetime(def)) + .into_iter() + .chain(generics.params) + .collect(); + } + let (_, ty_generics, _) = generics.split_for_impl(); + ty_generics.to_tokens(tokens); + } +} + +#[cfg(feature = "deserialize_in_place")] +impl<'a> DeTypeGenerics<'a> { + fn in_place(self) -> InPlaceTypeGenerics<'a> { + InPlaceTypeGenerics(self.0) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn place_lifetime() -> syn::LifetimeDef { + syn::LifetimeDef { + attrs: Vec::new(), + lifetime: syn::Lifetime::new("'place", Span::call_site()), + colon_token: None, + bounds: Punctuated::new(), + } +} + +fn split_with_de_lifetime( + params: &Parameters, +) -> ( + DeImplGenerics, + DeTypeGenerics, + syn::TypeGenerics, + Option<&syn::WhereClause>, +) { + let de_impl_generics = DeImplGenerics(params); + let de_ty_generics = DeTypeGenerics(params); + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + (de_impl_generics, de_ty_generics, ty_generics, where_clause) +} diff --git a/serde_derive/src/dummy.rs b/serde_derive/src/dummy.rs new file mode 100644 index 000000000..90a3514ca --- /dev/null +++ b/serde_derive/src/dummy.rs @@ -0,0 +1,47 @@ +use proc_macro2::{Ident, Span, TokenStream}; + +use syn; +use try; + +pub fn wrap_in_const( + serde_path: Option<&syn::Path>, + trait_: &str, + ty: &Ident, + code: TokenStream, +) -> TokenStream { + let try_replacement = try::replacement(); + + let dummy_const = Ident::new( + &format!("_IMPL_{}_FOR_{}", trait_, unraw(ty)), + Span::call_site(), + ); + + let use_serde = match serde_path { + Some(path) => quote! { + use #path as _serde; + }, + None => quote! { + #[allow(unknown_lints)] + #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))] + #[allow(rust_2018_idioms)] + extern crate serde as _serde; + }, + }; + + quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + #use_serde + #try_replacement + #code + }; + } +} + +#[allow(deprecated)] +fn unraw(ident: &Ident) -> String { + // str::trim_start_matches was added in 1.30, trim_left_matches deprecated + // in 1.33. We currently support rustc back to 1.15 so we need to continue + // to use the deprecated one. + ident.to_string().trim_left_matches("r#").to_owned() +} diff --git a/serde_derive/src/fragment.rs b/serde_derive/src/fragment.rs new file mode 100644 index 000000000..85a579746 --- /dev/null +++ b/serde_derive/src/fragment.rs @@ -0,0 +1,74 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::token; + +pub enum Fragment { + /// Tokens that can be used as an expression. + Expr(TokenStream), + /// Tokens that can be used inside a block. The surrounding curly braces are + /// not part of these tokens. + Block(TokenStream), +} + +macro_rules! quote_expr { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Expr(quote!($($tt)*)) + } +} + +macro_rules! quote_block { + ($($tt:tt)*) => { + $crate::fragment::Fragment::Block(quote!($($tt)*)) + } +} + +/// Interpolate a fragment in place of an expression. This involves surrounding +/// Block fragments in curly braces. +pub struct Expr(pub Fragment); +impl ToTokens for Expr { + fn to_tokens(&self, out: &mut TokenStream) { + match self.0 { + Fragment::Expr(ref expr) => expr.to_tokens(out), + Fragment::Block(ref block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +/// Interpolate a fragment as the statements of a block. +pub struct Stmts(pub Fragment); +impl ToTokens for Stmts { + fn to_tokens(&self, out: &mut TokenStream) { + match self.0 { + Fragment::Expr(ref expr) => expr.to_tokens(out), + Fragment::Block(ref block) => block.to_tokens(out), + } + } +} + +/// Interpolate a fragment as the value part of a `match` expression. This +/// involves putting a comma after expressions and curly braces around blocks. +pub struct Match(pub Fragment); +impl ToTokens for Match { + fn to_tokens(&self, out: &mut TokenStream) { + match self.0 { + Fragment::Expr(ref expr) => { + expr.to_tokens(out); + <Token![,]>::default().to_tokens(out); + } + Fragment::Block(ref block) => { + token::Brace::default().surround(out, |out| block.to_tokens(out)); + } + } + } +} + +impl AsRef<TokenStream> for Fragment { + fn as_ref(&self) -> &TokenStream { + match *self { + Fragment::Expr(ref expr) => expr, + Fragment::Block(ref block) => block, + } + } +} diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs new file mode 100644 index 000000000..c66b8cff5 --- /dev/null +++ b/serde_derive/src/internals/ast.rs @@ -0,0 +1,204 @@ +//! A Serde ast, parsed from the Syn ast and ready to generate Rust code. + +use internals::attr; +use internals::check; +use internals::{Ctxt, Derive}; +use syn; +use syn::punctuated::Punctuated; + +/// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`, +/// parsed into an internal representation. +pub struct Container<'a> { + /// The struct or enum name (without generics). + pub ident: syn::Ident, + /// Attributes on the structure, parsed for Serde. + pub attrs: attr::Container, + /// The contents of the struct or enum. + pub data: Data<'a>, + /// Any generics on the struct or enum. + pub generics: &'a syn::Generics, + /// Original input. + pub original: &'a syn::DeriveInput, +} + +/// The fields of a struct or enum. +/// +/// Analagous to `syn::Data`. +pub enum Data<'a> { + Enum(Vec<Variant<'a>>), + Struct(Style, Vec<Field<'a>>), +} + +/// A variant of an enum. +pub struct Variant<'a> { + pub ident: syn::Ident, + pub attrs: attr::Variant, + pub style: Style, + pub fields: Vec<Field<'a>>, + pub original: &'a syn::Variant, +} + +/// A field of a struct. +pub struct Field<'a> { + pub member: syn::Member, + pub attrs: attr::Field, + pub ty: &'a syn::Type, + pub original: &'a syn::Field, +} + +#[derive(Copy, Clone)] +pub enum Style { + /// Named fields. + Struct, + /// Many unnamed fields. + Tuple, + /// One unnamed field. + Newtype, + /// No fields. + Unit, +} + +impl<'a> Container<'a> { + /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. + pub fn from_ast( + cx: &Ctxt, + item: &'a syn::DeriveInput, + derive: Derive, + ) -> Option<Container<'a>> { + let mut attrs = attr::Container::from_ast(cx, item); + + let mut data = match item.data { + syn::Data::Enum(ref data) => { + Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())) + } + syn::Data::Struct(ref data) => { + let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); + Data::Struct(style, fields) + } + syn::Data::Union(_) => { + cx.error_spanned_by(item, "Serde does not support derive for unions"); + return None; + } + }; + + let mut has_flatten = false; + match data { + Data::Enum(ref mut variants) => { + for variant in variants { + variant.attrs.rename_by_rules(attrs.rename_all_rules()); + for field in &mut variant.fields { + if field.attrs.flatten() { + has_flatten = true; + } + field + .attrs + .rename_by_rules(variant.attrs.rename_all_rules()); + } + } + } + Data::Struct(_, ref mut fields) => { + for field in fields { + if field.attrs.flatten() { + has_flatten = true; + } + field.attrs.rename_by_rules(attrs.rename_all_rules()); + } + } + } + + if has_flatten { + attrs.mark_has_flatten(); + } + + let mut item = Container { + ident: item.ident.clone(), + attrs: attrs, + data: data, + generics: &item.generics, + original: item, + }; + check::check(cx, &mut item, derive); + Some(item) + } +} + +impl<'a> Data<'a> { + pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> { + match *self { + Data::Enum(ref variants) => { + Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) + } + Data::Struct(_, ref fields) => Box::new(fields.iter()), + } + } + + pub fn has_getter(&self) -> bool { + self.all_fields().any(|f| f.attrs.getter().is_some()) + } +} + +fn enum_from_ast<'a>( + cx: &Ctxt, + variants: &'a Punctuated<syn::Variant, Token![,]>, + container_default: &attr::Default, +) -> Vec<Variant<'a>> { + variants + .iter() + .map(|variant| { + let attrs = attr::Variant::from_ast(cx, variant); + let (style, fields) = + struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); + Variant { + ident: variant.ident.clone(), + attrs: attrs, + style: style, + fields: fields, + original: variant, + } + }) + .collect() +} + +fn struct_from_ast<'a>( + cx: &Ctxt, + fields: &'a syn::Fields, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> (Style, Vec<Field<'a>>) { + match *fields { + syn::Fields::Named(ref fields) => ( + Style::Struct, + fields_from_ast(cx, &fields.named, attrs, container_default), + ), + syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => ( + Style::Newtype, + fields_from_ast(cx, &fields.unnamed, attrs, container_default), + ), + syn::Fields::Unnamed(ref fields) => ( + Style::Tuple, + fields_from_ast(cx, &fields.unnamed, attrs, container_default), + ), + syn::Fields::Unit => (Style::Unit, Vec::new()), + } +} + +fn fields_from_ast<'a>( + cx: &Ctxt, + fields: &'a Punctuated<syn::Field, Token![,]>, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> Vec<Field<'a>> { + fields + .iter() + .enumerate() + .map(|(i, field)| Field { + member: match field.ident { + Some(ref ident) => syn::Member::Named(ident.clone()), + None => syn::Member::Unnamed(i.into()), + }, + attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), + ty: &field.ty, + original: field, + }) + .collect() +} diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs new file mode 100644 index 000000000..2bf7dc3f2 --- /dev/null +++ b/serde_derive/src/internals/attr.rs @@ -0,0 +1,1974 @@ +use internals::Ctxt; +use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use quote::ToTokens; +use std::borrow::Cow; +use std::collections::BTreeSet; +use std::str::FromStr; +use syn; +use syn::parse::{self, Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::Ident; +use syn::Meta::{List, NameValue, Word}; +use syn::NestedMeta::{Literal, Meta}; + +// This module handles parsing of `#[serde(...)]` attributes. The entrypoints +// are `attr::Container::from_ast`, `attr::Variant::from_ast`, and +// `attr::Field::from_ast`. Each returns an instance of the corresponding +// struct. Note that none of them return a Result. Unrecognized, malformed, or +// duplicated attributes result in a span_err but otherwise are ignored. The +// user will see errors simultaneously for all bad attributes in the crate +// rather than just the first. + +pub use internals::case::RenameRule; + +struct Attr<'c, T> { + cx: &'c Ctxt, + name: &'static str, + tokens: TokenStream, + value: Option<T>, +} + +impl<'c, T> Attr<'c, T> { + fn none(cx: &'c Ctxt, name: &'static str) -> Self { + Attr { + cx: cx, + name: name, + tokens: TokenStream::new(), + value: None, + } + } + + fn set<A: ToTokens>(&mut self, obj: A, value: T) { + let tokens = obj.into_token_stream(); + + if self.value.is_some() { + self.cx + .error_spanned_by(tokens, format!("duplicate serde attribute `{}`", self.name)); + } else { + self.tokens = tokens; + self.value = Some(value); + } + } + + fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) { + if let Some(value) = value { + self.set(obj, value); + } + } + + fn set_if_none(&mut self, value: T) { + if self.value.is_none() { + self.value = Some(value); + } + } + + fn get(self) -> Option<T> { + self.value + } + + fn get_with_tokens(self) -> Option<(TokenStream, T)> { + match self.value { + Some(v) => Some((self.tokens, v)), + None => None, + } + } +} + +struct BoolAttr<'c>(Attr<'c, ()>); + +impl<'c> BoolAttr<'c> { + fn none(cx: &'c Ctxt, name: &'static str) -> Self { + BoolAttr(Attr::none(cx, name)) + } + + fn set_true<A: ToTokens>(&mut self, obj: A) { + self.0.set(obj, ()); + } + + fn get(&self) -> bool { + self.0.value.is_some() + } +} + +struct VecAttr<'c, T> { + cx: &'c Ctxt, + name: &'static str, + first_dup_tokens: TokenStream, + values: Vec<T>, +} + +impl<'c, T> VecAttr<'c, T> { + fn none(cx: &'c Ctxt, name: &'static str) -> Self { + VecAttr { + cx: cx, + name: name, + first_dup_tokens: TokenStream::new(), + values: Vec::new(), + } + } + + fn insert<A: ToTokens>(&mut self, obj: A, value: T) { + if self.values.len() == 1 { + self.first_dup_tokens = obj.into_token_stream(); + } + self.values.push(value); + } + + fn at_most_one(mut self) -> Result<Option<T>, ()> { + if self.values.len() > 1 { + let dup_token = self.first_dup_tokens; + self.cx.error_spanned_by( + dup_token, + format!("duplicate serde attribute `{}`", self.name), + ); + Err(()) + } else { + Ok(self.values.pop()) + } + } + + fn get(self) -> Vec<T> { + self.values + } +} + +pub struct Name { + serialize: String, + serialize_renamed: bool, + deserialize: String, + deserialize_renamed: bool, + deserialize_aliases: Vec<String>, +} + +#[allow(deprecated)] +fn unraw(ident: &Ident) -> String { + // str::trim_start_matches was added in 1.30, trim_left_matches deprecated + // in 1.33. We currently support rustc back to 1.15 so we need to continue + // to use the deprecated one. + ident.to_string().trim_left_matches("r#").to_owned() +} + +impl Name { + fn from_attrs( + source_name: String, + ser_name: Attr<String>, + de_name: Attr<String>, + de_aliases: Option<VecAttr<String>>, + ) -> Name { + let deserialize_aliases = match de_aliases { + Some(de_aliases) => { + let mut alias_list = BTreeSet::new(); + for alias_name in de_aliases.get() { + alias_list.insert(alias_name); + } + alias_list.into_iter().collect() + } + None => Vec::new(), + }; + + let ser_name = ser_name.get(); + let ser_renamed = ser_name.is_some(); + let de_name = de_name.get(); + let de_renamed = de_name.is_some(); + Name { + serialize: ser_name.unwrap_or_else(|| source_name.clone()), + serialize_renamed: ser_renamed, + deserialize: de_name.unwrap_or(source_name), + deserialize_renamed: de_renamed, + deserialize_aliases: deserialize_aliases, + } + } + + /// Return the container name for the container when serializing. + pub fn serialize_name(&self) -> String { + self.serialize.clone() + } + + /// Return the container name for the container when deserializing. + pub fn deserialize_name(&self) -> String { + self.deserialize.clone() + } + + fn deserialize_aliases(&self) -> Vec<String> { + let mut aliases = self.deserialize_aliases.clone(); + let main_name = self.deserialize_name(); + if !aliases.contains(&main_name) { + aliases.push(main_name); + } + aliases + } +} + +pub struct RenameAllRules { + serialize: RenameRule, + deserialize: RenameRule, +} + +/// Represents struct or enum attribute information. +pub struct Container { + name: Name, + transparent: bool, + deny_unknown_fields: bool, + default: Default, + rename_all_rules: RenameAllRules, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + tag: TagType, + type_from: Option<syn::Type>, + type_into: Option<syn::Type>, + remote: Option<syn::Path>, + identifier: Identifier, + has_flatten: bool, + serde_path: Option<syn::Path>, +} + +/// Styles of representing an enum. +pub enum TagType { + /// The default. + /// + /// ```json + /// {"variant1": {"key1": "value1", "key2": "value2"}} + /// ``` + External, + + /// `#[serde(tag = "type")]` + /// + /// ```json + /// {"type": "variant1", "key1": "value1", "key2": "value2"} + /// ``` + Internal { tag: String }, + + /// `#[serde(tag = "t", content = "c")]` + /// + /// ```json + /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} + /// ``` + Adjacent { tag: String, content: String }, + + /// `#[serde(untagged)]` + /// + /// ```json + /// {"key1": "value1", "key2": "value2"} + /// ``` + None, +} + +/// Whether this enum represents the fields of a struct or the variants of an +/// enum. +#[derive(Copy, Clone)] +pub enum Identifier { + /// It does not. + No, + + /// This enum represents the fields of a struct. All of the variants must be + /// unit variants, except possibly one which is annotated with + /// `#[serde(other)]` and is a newtype variant. + Field, + + /// This enum represents the variants of an enum. All of the variants must + /// be unit variants. + Variant, +} + +impl Identifier { + #[cfg(feature = "deserialize_in_place")] + pub fn is_some(self) -> bool { + match self { + Identifier::No => false, + Identifier::Field | Identifier::Variant => true, + } + } +} + +impl Container { + /// Extract out the `#[serde(...)]` attributes from an item. + pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { + let mut ser_name = Attr::none(cx, "rename"); + let mut de_name = Attr::none(cx, "rename"); + let mut transparent = BoolAttr::none(cx, "transparent"); + let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); + let mut default = Attr::none(cx, "default"); + let mut rename_all_ser_rule = Attr::none(cx, "rename_all"); + let mut rename_all_de_rule = Attr::none(cx, "rename_all"); + let mut ser_bound = Attr::none(cx, "bound"); + let mut de_bound = Attr::none(cx, "bound"); + let mut untagged = BoolAttr::none(cx, "untagged"); + let mut internal_tag = Attr::none(cx, "tag"); + let mut content = Attr::none(cx, "content"); + let mut type_from = Attr::none(cx, "from"); + let mut type_into = Attr::none(cx, "into"); + let mut remote = Attr::none(cx, "remote"); + let mut field_identifier = BoolAttr::none(cx, "field_identifier"); + let mut variant_identifier = BoolAttr::none(cx, "variant_identifier"); + let mut serde_path = Attr::none(cx, "crate"); + + for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) { + for meta_item in meta_items { + match meta_item { + // Parse `#[serde(rename = "foo")]` + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + ser_name.set(&m.ident, s.value()); + de_name.set(&m.ident, s.value()); + } + } + + // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + de_name.set_opt(&m.ident, de.map(syn::LitStr::value)); + } + } + + // Parse `#[serde(rename_all = "foo")]` + Meta(NameValue(ref m)) if m.ident == "rename_all" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + match RenameRule::from_str(&s.value()) { + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule); + rename_all_de_rule.set(&m.ident, rename_rule); + } + Err(()) => cx.error_spanned_by( + s, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + s.value(), + ), + ), + } + } + } + + // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename_all" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule) + } + Err(()) => cx.error_spanned_by( + ser, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + ser.value(), + ), + ), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => { + rename_all_de_rule.set(&m.ident, rename_rule) + } + Err(()) => cx.error_spanned_by( + de, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + de.value(), + ), + ), + } + } + } + } + + // Parse `#[serde(transparent)]` + Meta(Word(ref word)) if word == "transparent" => { + transparent.set_true(word); + } + + // Parse `#[serde(deny_unknown_fields)]` + Meta(Word(ref word)) if word == "deny_unknown_fields" => { + deny_unknown_fields.set_true(word); + } + + // Parse `#[serde(default)]` + Meta(Word(ref word)) if word == "default" => match item.data { + syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields { + syn::Fields::Named(_) => { + default.set(word, Default::Default); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( + fields, + "#[serde(default)] can only be used on structs \ + with named fields", + ), + }, + syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx + .error_spanned_by( + enum_token, + "#[serde(default)] can only be used on structs \ + with named fields", + ), + syn::Data::Union(syn::DataUnion { + ref union_token, .. + }) => cx.error_spanned_by( + union_token, + "#[serde(default)] can only be used on structs \ + with named fields", + ), + }, + + // Parse `#[serde(default = "...")]` + Meta(NameValue(ref m)) if m.ident == "default" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + match item.data { + syn::Data::Struct(syn::DataStruct { ref fields, .. }) => { + match *fields { + syn::Fields::Named(_) => { + default.set(&m.ident, Default::Path(path)); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => cx + .error_spanned_by( + fields, + "#[serde(default = \"...\")] can only be used \ + on structs with named fields", + ), + } + } + syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx + .error_spanned_by( + enum_token, + "#[serde(default = \"...\")] can only be used \ + on structs with named fields", + ), + syn::Data::Union(syn::DataUnion { + ref union_token, .. + }) => cx.error_spanned_by( + union_token, + "#[serde(default = \"...\")] can only be used \ + on structs with named fields", + ), + } + } + } + + // Parse `#[serde(bound = "T: SomeBound")]` + Meta(NameValue(ref m)) if m.ident == "bound" => { + if let Ok(where_predicates) = + parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) + { + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); + } + } + + // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` + Meta(List(ref m)) if m.ident == "bound" => { + if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); + } + } + + // Parse `#[serde(untagged)]` + Meta(Word(ref word)) if word == "untagged" => match item.data { + syn::Data::Enum(_) => { + untagged.set_true(word); + } + syn::Data::Struct(syn::DataStruct { + ref struct_token, .. + }) => { + cx.error_spanned_by( + struct_token, + "#[serde(untagged)] can only be used on enums", + ); + } + syn::Data::Union(syn::DataUnion { + ref union_token, .. + }) => { + cx.error_spanned_by( + union_token, + "#[serde(untagged)] can only be used on enums", + ); + } + }, + + // Parse `#[serde(tag = "type")]` + Meta(NameValue(ref m)) if m.ident == "tag" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + match item.data { + syn::Data::Enum(_) => { + internal_tag.set(&m.ident, s.value()); + } + syn::Data::Struct(syn::DataStruct { ref fields, .. }) => { + match *fields { + syn::Fields::Named(_) => { + internal_tag.set(&m.ident, s.value()); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => { + cx.error_spanned_by( + fields, + "#[serde(tag = \"...\")] can only be used on enums \ + and structs with named fields", + ); + } + } + } + syn::Data::Union(syn::DataUnion { + ref union_token, .. + }) => { + cx.error_spanned_by( + union_token, + "#[serde(tag = \"...\")] can only be used on enums \ + and structs with named fields", + ); + } + } + } + } + + // Parse `#[serde(content = "c")]` + Meta(NameValue(ref m)) if m.ident == "content" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + match item.data { + syn::Data::Enum(_) => { + content.set(&m.ident, s.value()); + } + syn::Data::Struct(syn::DataStruct { + ref struct_token, .. + }) => { + cx.error_spanned_by( + struct_token, + "#[serde(content = \"...\")] can only be used on enums", + ); + } + syn::Data::Union(syn::DataUnion { + ref union_token, .. + }) => { + cx.error_spanned_by( + union_token, + "#[serde(content = \"...\")] can only be used on enums", + ); + } + } + } + } + + // Parse `#[serde(from = "Type")] + Meta(NameValue(ref m)) if m.ident == "from" => { + if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) { + type_from.set_opt(&m.ident, Some(from_ty)); + } + } + + // Parse `#[serde(into = "Type")] + Meta(NameValue(ref m)) if m.ident == "into" => { + if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) { + type_into.set_opt(&m.ident, Some(into_ty)); + } + } + + // Parse `#[serde(remote = "...")]` + Meta(NameValue(ref m)) if m.ident == "remote" => { + if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) { + if is_primitive_path(&path, "Self") { + remote.set(&m.ident, item.ident.clone().into()); + } else { + remote.set(&m.ident, path); + } + } + } + + // Parse `#[serde(field_identifier)]` + Meta(Word(ref word)) if word == "field_identifier" => { + field_identifier.set_true(word); + } + + // Parse `#[serde(variant_identifier)]` + Meta(Word(ref word)) if word == "variant_identifier" => { + variant_identifier.set_true(word); + } + + // Parse `#[serde(crate = "foo")]` + Meta(NameValue(ref m)) if m.ident == "crate" => { + if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) { + serde_path.set(&m.ident, path) + } + } + + Meta(ref meta_item) => { + cx.error_spanned_by( + meta_item.name(), + format!("unknown serde container attribute `{}`", meta_item.name()), + ); + } + + Literal(ref lit) => { + cx.error_spanned_by(lit, "unexpected literal in serde container attribute"); + } + } + } + } + + Container { + name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), + transparent: transparent.get(), + deny_unknown_fields: deny_unknown_fields.get(), + default: default.get().unwrap_or(Default::None), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + tag: decide_tag(cx, item, untagged, internal_tag, content), + type_from: type_from.get(), + type_into: type_into.get(), + remote: remote.get(), + identifier: decide_identifier(cx, item, field_identifier, variant_identifier), + has_flatten: false, + serde_path: serde_path.get(), + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn rename_all_rules(&self) -> &RenameAllRules { + &self.rename_all_rules + } + + pub fn transparent(&self) -> bool { + self.transparent + } + + pub fn deny_unknown_fields(&self) -> bool { + self.deny_unknown_fields + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn tag(&self) -> &TagType { + &self.tag + } + + pub fn type_from(&self) -> Option<&syn::Type> { + self.type_from.as_ref() + } + + pub fn type_into(&self) -> Option<&syn::Type> { + self.type_into.as_ref() + } + + pub fn remote(&self) -> Option<&syn::Path> { + self.remote.as_ref() + } + + pub fn identifier(&self) -> Identifier { + self.identifier + } + + pub fn has_flatten(&self) -> bool { + self.has_flatten + } + + pub fn mark_has_flatten(&mut self) { + self.has_flatten = true; + } + + pub fn custom_serde_path(&self) -> Option<&syn::Path> { + self.serde_path.as_ref() + } + + pub fn serde_path(&self) -> Cow<syn::Path> { + self.custom_serde_path() + .map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed) + } +} + +fn decide_tag( + cx: &Ctxt, + item: &syn::DeriveInput, + untagged: BoolAttr, + internal_tag: Attr<String>, + content: Attr<String>, +) -> TagType { + match ( + untagged.0.get_with_tokens(), + internal_tag.get_with_tokens(), + content.get_with_tokens(), + ) { + (None, None, None) => TagType::External, + (Some(_), None, None) => TagType::None, + (None, Some((_, tag)), None) => { + // Check that there are no tuple variants. + if let syn::Data::Enum(ref data) = item.data { + for variant in &data.variants { + match variant.fields { + syn::Fields::Named(_) | syn::Fields::Unit => {} + syn::Fields::Unnamed(ref fields) => { + if fields.unnamed.len() != 1 { + cx.error_spanned_by( + variant, + "#[serde(tag = \"...\")] cannot be used with tuple \ + variants", + ); + break; + } + } + } + } + } + TagType::Internal { tag: tag } + } + (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { + cx.error_spanned_by( + untagged_tokens, + "enum cannot be both untagged and internally tagged", + ); + cx.error_spanned_by( + tag_tokens, + "enum cannot be both untagged and internally tagged", + ); + TagType::External // doesn't matter, will error + } + (None, None, Some((content_tokens, _))) => { + cx.error_spanned_by( + content_tokens, + "#[serde(tag = \"...\", content = \"...\")] must be used together", + ); + TagType::External + } + (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { + cx.error_spanned_by( + untagged_tokens, + "untagged enum cannot have #[serde(content = \"...\")]", + ); + cx.error_spanned_by( + content_tokens, + "untagged enum cannot have #[serde(content = \"...\")]", + ); + TagType::External + } + (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { + tag: tag, + content: content, + }, + (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { + cx.error_spanned_by( + untagged_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); + cx.error_spanned_by( + tag_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); + cx.error_spanned_by( + content_tokens, + "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", + ); + TagType::External + } + } +} + +fn decide_identifier( + cx: &Ctxt, + item: &syn::DeriveInput, + field_identifier: BoolAttr, + variant_identifier: BoolAttr, +) -> Identifier { + match ( + &item.data, + field_identifier.0.get_with_tokens(), + variant_identifier.0.get_with_tokens(), + ) { + (_, None, None) => Identifier::No, + (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { + cx.error_spanned_by( + field_identifier_tokens, + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", + ); + cx.error_spanned_by( + variant_identifier_tokens, + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", + ); + Identifier::No + } + (&syn::Data::Enum(_), Some(_), None) => Identifier::Field, + (&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, + ( + &syn::Data::Struct(syn::DataStruct { + ref struct_token, .. + }), + Some(_), + None, + ) => { + cx.error_spanned_by( + struct_token, + "#[serde(field_identifier)] can only be used on an enum", + ); + Identifier::No + } + ( + &syn::Data::Union(syn::DataUnion { + ref union_token, .. + }), + Some(_), + None, + ) => { + cx.error_spanned_by( + union_token, + "#[serde(field_identifier)] can only be used on an enum", + ); + Identifier::No + } + ( + &syn::Data::Struct(syn::DataStruct { + ref struct_token, .. + }), + None, + Some(_), + ) => { + cx.error_spanned_by( + struct_token, + "#[serde(variant_identifier)] can only be used on an enum", + ); + Identifier::No + } + ( + &syn::Data::Union(syn::DataUnion { + ref union_token, .. + }), + None, + Some(_), + ) => { + cx.error_spanned_by( + union_token, + "#[serde(variant_identifier)] can only be used on an enum", + ); + Identifier::No + } + } +} + +/// Represents variant attribute information +pub struct Variant { + name: Name, + rename_all_rules: RenameAllRules, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + skip_deserializing: bool, + skip_serializing: bool, + other: bool, + serialize_with: Option<syn::ExprPath>, + deserialize_with: Option<syn::ExprPath>, + borrow: Option<syn::Meta>, +} + +impl Variant { + pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { + let mut ser_name = Attr::none(cx, "rename"); + let mut de_name = Attr::none(cx, "rename"); + let mut de_aliases = VecAttr::none(cx, "rename"); + let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); + let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); + let mut rename_all_ser_rule = Attr::none(cx, "rename_all"); + let mut rename_all_de_rule = Attr::none(cx, "rename_all"); + let mut ser_bound = Attr::none(cx, "bound"); + let mut de_bound = Attr::none(cx, "bound"); + let mut other = BoolAttr::none(cx, "other"); + let mut serialize_with = Attr::none(cx, "serialize_with"); + let mut deserialize_with = Attr::none(cx, "deserialize_with"); + let mut borrow = Attr::none(cx, "borrow"); + + for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { + for meta_item in meta_items { + match meta_item { + // Parse `#[serde(rename = "foo")]` + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + ser_name.set(&m.ident, s.value()); + de_name.set_if_none(s.value()); + de_aliases.insert(&m.ident, s.value()); + } + } + + // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&m.ident, de_value.value()); + } + } + } + + // Parse `#[serde(alias = "foo")]` + Meta(NameValue(ref m)) if m.ident == "alias" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + de_aliases.insert(&m.ident, s.value()); + } + } + + // Parse `#[serde(rename_all = "foo")]` + Meta(NameValue(ref m)) if m.ident == "rename_all" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + match RenameRule::from_str(&s.value()) { + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule); + rename_all_de_rule.set(&m.ident, rename_rule); + } + Err(()) => cx.error_spanned_by( + s, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + s.value() + ), + ), + } + } + } + + // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename_all" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule) + } + Err(()) => cx.error_spanned_by( + ser, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + ser.value(), + ), + ), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => { + rename_all_de_rule.set(&m.ident, rename_rule) + } + Err(()) => cx.error_spanned_by( + de, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + de.value(), + ), + ), + } + } + } + } + + // Parse `#[serde(skip)]` + Meta(Word(ref word)) if word == "skip" => { + skip_serializing.set_true(word); + skip_deserializing.set_true(word); + } + + // Parse `#[serde(skip_deserializing)]` + Meta(Word(ref word)) if word == "skip_deserializing" => { + skip_deserializing.set_true(word); + } + + // Parse `#[serde(skip_serializing)]` + Meta(Word(ref word)) if word == "skip_serializing" => { + skip_serializing.set_true(word); + } + + // Parse `#[serde(other)]` + Meta(Word(ref word)) if word == "other" => { + other.set_true(word); + } + + // Parse `#[serde(bound = "T: SomeBound")]` + Meta(NameValue(ref m)) if m.ident == "bound" => { + if let Ok(where_predicates) = + parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) + { + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); + } + } + + // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` + Meta(List(ref m)) if m.ident == "bound" => { + if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); + } + } + + // Parse `#[serde(with = "...")]` + Meta(NameValue(ref m)) if m.ident == "with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + let mut ser_path = path.clone(); + ser_path + .path + .segments + .push(Ident::new("serialize", Span::call_site()).into()); + serialize_with.set(&m.ident, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", Span::call_site()).into()); + deserialize_with.set(&m.ident, de_path); + } + } + + // Parse `#[serde(serialize_with = "...")]` + Meta(NameValue(ref m)) if m.ident == "serialize_with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + serialize_with.set(&m.ident, path); + } + } + + // Parse `#[serde(deserialize_with = "...")]` + Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + deserialize_with.set(&m.ident, path); + } + } + + // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` + Meta(ref m) if m.name() == "borrow" => match variant.fields { + syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => { + borrow.set(m.name(), m.clone()); + } + _ => { + cx.error_spanned_by( + variant, + "#[serde(borrow)] may only be used on newtype variants", + ); + } + }, + + Meta(ref meta_item) => { + cx.error_spanned_by( + meta_item.name(), + format!("unknown serde variant attribute `{}`", meta_item.name()), + ); + } + + Literal(ref lit) => { + cx.error_spanned_by(lit, "unexpected literal in serde variant attribute"); + } + } + } + } + + Variant { + name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + skip_deserializing: skip_deserializing.get(), + skip_serializing: skip_serializing.get(), + other: other.get(), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + borrow: borrow.get(), + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn aliases(&self) -> Vec<String> { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); + } + if !self.name.deserialize_renamed { + self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); + } + } + + pub fn rename_all_rules(&self) -> &RenameAllRules { + &self.rename_all_rules + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } + + pub fn other(&self) -> bool { + self.other + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { + self.deserialize_with.as_ref() + } +} + +/// Represents field attribute information +pub struct Field { + name: Name, + skip_serializing: bool, + skip_deserializing: bool, + skip_serializing_if: Option<syn::ExprPath>, + default: Default, + serialize_with: Option<syn::ExprPath>, + deserialize_with: Option<syn::ExprPath>, + ser_bound: Option<Vec<syn::WherePredicate>>, + de_bound: Option<Vec<syn::WherePredicate>>, + borrowed_lifetimes: BTreeSet<syn::Lifetime>, + getter: Option<syn::ExprPath>, + flatten: bool, + transparent: bool, +} + +/// Represents the default to use for a field when deserializing. +pub enum Default { + /// Field must always be specified because it does not have a default. + None, + /// The default is given by `std::default::Default::default()`. + Default, + /// The default is given by this function. + Path(syn::ExprPath), +} + +impl Default { + pub fn is_none(&self) -> bool { + match *self { + Default::None => true, + Default::Default | Default::Path(_) => false, + } + } +} + +impl Field { + /// Extract out the `#[serde(...)]` attributes from a struct field. + pub fn from_ast( + cx: &Ctxt, + index: usize, + field: &syn::Field, + attrs: Option<&Variant>, + container_default: &Default, + ) -> Self { + let mut ser_name = Attr::none(cx, "rename"); + let mut de_name = Attr::none(cx, "rename"); + let mut de_aliases = VecAttr::none(cx, "rename"); + let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); + let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); + let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if"); + let mut default = Attr::none(cx, "default"); + let mut serialize_with = Attr::none(cx, "serialize_with"); + let mut deserialize_with = Attr::none(cx, "deserialize_with"); + let mut ser_bound = Attr::none(cx, "bound"); + let mut de_bound = Attr::none(cx, "bound"); + let mut borrowed_lifetimes = Attr::none(cx, "borrow"); + let mut getter = Attr::none(cx, "getter"); + let mut flatten = BoolAttr::none(cx, "flatten"); + + let ident = match field.ident { + Some(ref ident) => unraw(ident), + None => index.to_string(), + }; + + let variant_borrow = attrs + .and_then(|variant| variant.borrow.as_ref()) + .map(|borrow| vec![Meta(borrow.clone())]); + + for meta_items in field + .attrs + .iter() + .filter_map(get_serde_meta_items) + .chain(variant_borrow) + { + for meta_item in meta_items { + match meta_item { + // Parse `#[serde(rename = "foo")]` + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + ser_name.set(&m.ident, s.value()); + de_name.set_if_none(s.value()); + de_aliases.insert(&m.ident, s.value()); + } + } + + // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { + ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&m.ident, de_value.value()); + } + } + } + + // Parse `#[serde(alias = "foo")]` + Meta(NameValue(ref m)) if m.ident == "alias" => { + if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { + de_aliases.insert(&m.ident, s.value()); + } + } + + // Parse `#[serde(default)]` + Meta(Word(ref word)) if word == "default" => { + default.set(word, Default::Default); + } + + // Parse `#[serde(default = "...")]` + Meta(NameValue(ref m)) if m.ident == "default" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + default.set(&m.ident, Default::Path(path)); + } + } + + // Parse `#[serde(skip_serializing)]` + Meta(Word(ref word)) if word == "skip_serializing" => { + skip_serializing.set_true(word); + } + + // Parse `#[serde(skip_deserializing)]` + Meta(Word(ref word)) if word == "skip_deserializing" => { + skip_deserializing.set_true(word); + } + + // Parse `#[serde(skip)]` + Meta(Word(ref word)) if word == "skip" => { + skip_serializing.set_true(word); + skip_deserializing.set_true(word); + } + + // Parse `#[serde(skip_serializing_if = "...")]` + Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + skip_serializing_if.set(&m.ident, path); + } + } + + // Parse `#[serde(serialize_with = "...")]` + Meta(NameValue(ref m)) if m.ident == "serialize_with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + serialize_with.set(&m.ident, path); + } + } + + // Parse `#[serde(deserialize_with = "...")]` + Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + deserialize_with.set(&m.ident, path); + } + } + + // Parse `#[serde(with = "...")]` + Meta(NameValue(ref m)) if m.ident == "with" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + let mut ser_path = path.clone(); + ser_path + .path + .segments + .push(Ident::new("serialize", Span::call_site()).into()); + serialize_with.set(&m.ident, ser_path); + let mut de_path = path; + de_path + .path + .segments + .push(Ident::new("deserialize", Span::call_site()).into()); + deserialize_with.set(&m.ident, de_path); + } + } + + // Parse `#[serde(bound = "T: SomeBound")]` + Meta(NameValue(ref m)) if m.ident == "bound" => { + if let Ok(where_predicates) = + parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit) + { + ser_bound.set(&m.ident, where_predicates.clone()); + de_bound.set(&m.ident, where_predicates); + } + } + + // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` + Meta(List(ref m)) if m.ident == "bound" => { + if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { + ser_bound.set_opt(&m.ident, ser); + de_bound.set_opt(&m.ident, de); + } + } + + // Parse `#[serde(borrow)]` + Meta(Word(ref word)) if word == "borrow" => { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(word, borrowable); + } + } + + // Parse `#[serde(borrow = "'a + 'b")]` + Meta(NameValue(ref m)) if m.ident == "borrow" => { + if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + for lifetime in &lifetimes { + if !borrowable.contains(lifetime) { + cx.error_spanned_by( + field, + format!( + "field `{}` does not have lifetime {}", + ident, lifetime + ), + ); + } + } + borrowed_lifetimes.set(&m.ident, lifetimes); + } + } + } + + // Parse `#[serde(getter = "...")]` + Meta(NameValue(ref m)) if m.ident == "getter" => { + if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { + getter.set(&m.ident, path); + } + } + + // Parse `#[serde(flatten)]` + Meta(Word(ref word)) if word == "flatten" => { + flatten.set_true(word); + } + + Meta(ref meta_item) => { + cx.error_spanned_by( + meta_item.name(), + format!("unknown serde field attribute `{}`", meta_item.name()), + ); + } + + Literal(ref lit) => { + cx.error_spanned_by(lit, "unexpected literal in serde field attribute"); + } + } + } + } + + // Is skip_deserializing, initialize the field to Default::default() unless a + // different default is specified by `#[serde(default = "...")]` on + // ourselves or our container (e.g. the struct we are in). + if let Default::None = *container_default { + if skip_deserializing.0.value.is_some() { + default.set_if_none(Default::Default); + } + } + + let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); + if !borrowed_lifetimes.is_empty() { + // Cow<str> and Cow<[u8]> never borrow by default: + // + // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> + // + // A #[serde(borrow)] attribute enables borrowing that corresponds + // roughly to these impls: + // + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> + // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> + if is_cow(&field.ty, is_str) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + path.segments + .push(Ident::new("_serde", Span::call_site()).into()); + path.segments + .push(Ident::new("private", Span::call_site()).into()); + path.segments + .push(Ident::new("de", Span::call_site()).into()); + path.segments + .push(Ident::new("borrow_cow_str", Span::call_site()).into()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path: path, + }; + deserialize_with.set_if_none(expr); + } else if is_cow(&field.ty, is_slice_u8) { + let mut path = syn::Path { + leading_colon: None, + segments: Punctuated::new(), + }; + path.segments + .push(Ident::new("_serde", Span::call_site()).into()); + path.segments + .push(Ident::new("private", Span::call_site()).into()); + path.segments + .push(Ident::new("de", Span::call_site()).into()); + path.segments + .push(Ident::new("borrow_cow_bytes", Span::call_site()).into()); + let expr = syn::ExprPath { + attrs: Vec::new(), + qself: None, + path: path, + }; + deserialize_with.set_if_none(expr); + } + } else if is_implicitly_borrowed(&field.ty) { + // Types &str and &[u8] are always implicitly borrowed. No need for + // a #[serde(borrow)]. + collect_lifetimes(&field.ty, &mut borrowed_lifetimes); + } + + Field { + name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), + skip_serializing: skip_serializing.get(), + skip_deserializing: skip_deserializing.get(), + skip_serializing_if: skip_serializing_if.get(), + default: default.get().unwrap_or(Default::None), + serialize_with: serialize_with.get(), + deserialize_with: deserialize_with.get(), + ser_bound: ser_bound.get(), + de_bound: de_bound.get(), + borrowed_lifetimes: borrowed_lifetimes, + getter: getter.get(), + flatten: flatten.get(), + transparent: false, + } + } + + pub fn name(&self) -> &Name { + &self.name + } + + pub fn aliases(&self) -> Vec<String> { + self.name.deserialize_aliases() + } + + pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { + if !self.name.serialize_renamed { + self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); + } + if !self.name.deserialize_renamed { + self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); + } + } + + pub fn skip_serializing(&self) -> bool { + self.skip_serializing + } + + pub fn skip_deserializing(&self) -> bool { + self.skip_deserializing + } + + pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { + self.skip_serializing_if.as_ref() + } + + pub fn default(&self) -> &Default { + &self.default + } + + pub fn serialize_with(&self) -> Option<&syn::ExprPath> { + self.serialize_with.as_ref() + } + + pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { + self.deserialize_with.as_ref() + } + + pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { + self.ser_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { + self.de_bound.as_ref().map(|vec| &vec[..]) + } + + pub fn borrowed_lifetimes(&self) -> &BTreeSet<syn::Lifetime> { + &self.borrowed_lifetimes + } + + pub fn getter(&self) -> Option<&syn::ExprPath> { + self.getter.as_ref() + } + + pub fn flatten(&self) -> bool { + self.flatten + } + + pub fn transparent(&self) -> bool { + self.transparent + } + + pub fn mark_transparent(&mut self) { + self.transparent = true; + } +} + +type SerAndDe<T> = (Option<T>, Option<T>); + +fn get_ser_and_de<'a, 'b, T, F>( + cx: &'b Ctxt, + attr_name: &'static str, + metas: &'a Punctuated<syn::NestedMeta, Token![,]>, + f: F, +) -> Result<(VecAttr<'b, T>, VecAttr<'b, T>), ()> +where + T: 'a, + F: Fn(&Ctxt, &Ident, &Ident, &'a syn::Lit) -> Result<T, ()>, +{ + let mut ser_meta = VecAttr::none(cx, attr_name); + let mut de_meta = VecAttr::none(cx, attr_name); + let attr_name = Ident::new(attr_name, Span::call_site()); + + for meta in metas { + match *meta { + Meta(NameValue(ref meta)) if meta.ident == "serialize" => { + if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) { + ser_meta.insert(&meta.ident, v); + } + } + + Meta(NameValue(ref meta)) if meta.ident == "deserialize" => { + if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) { + de_meta.insert(&meta.ident, v); + } + } + + _ => { + cx.error_spanned_by( + meta, + format!( + "malformed {0} attribute, expected `{0}(serialize = ..., \ + deserialize = ...)`", + attr_name + ), + ); + return Err(()); + } + } + } + + Ok((ser_meta, de_meta)) +} + +fn get_renames<'a>( + cx: &Ctxt, + items: &'a Punctuated<syn::NestedMeta, Token![,]>, +) -> Result<SerAndDe<&'a syn::LitStr>, ()> { + let (ser, de) = try!(get_ser_and_de(cx, "rename", items, get_lit_str)); + Ok((try!(ser.at_most_one()), try!(de.at_most_one()))) +} + +fn get_multiple_renames<'a>( + cx: &Ctxt, + items: &'a Punctuated<syn::NestedMeta, Token![,]>, +) -> Result<(Option<&'a syn::LitStr>, Vec<&'a syn::LitStr>), ()> { + let (ser, de) = try!(get_ser_and_de(cx, "rename", items, get_lit_str)); + Ok((try!(ser.at_most_one()), de.get())) +} + +fn get_where_predicates( + cx: &Ctxt, + items: &Punctuated<syn::NestedMeta, Token![,]>, +) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> { + let (ser, de) = try!(get_ser_and_de(cx, "bound", items, parse_lit_into_where)); + Ok((try!(ser.at_most_one()), try!(de.at_most_one()))) +} + +pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> { + if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "serde" { + match attr.interpret_meta() { + Some(List(ref meta)) => Some(meta.nested.iter().cloned().collect()), + _ => { + // TODO: produce an error + None + } + } + } else { + None + } +} + +fn get_lit_str<'a>( + cx: &Ctxt, + attr_name: &Ident, + meta_item_name: &Ident, + lit: &'a syn::Lit, +) -> Result<&'a syn::LitStr, ()> { + if let syn::Lit::Str(ref lit) = *lit { + Ok(lit) + } else { + cx.error_spanned_by( + lit, + format!( + "expected serde {} attribute to be a string: `{} = \"...\"`", + attr_name, meta_item_name + ), + ); + Err(()) + } +} + +fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Path, ()> { + let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); + parse_lit_str(string).map_err(|_| { + cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) + }) +} + +fn parse_lit_into_expr_path( + cx: &Ctxt, + attr_name: &Ident, + lit: &syn::Lit, +) -> Result<syn::ExprPath, ()> { + let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); + parse_lit_str(string).map_err(|_| { + cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) + }) +} + +fn parse_lit_into_where( + cx: &Ctxt, + attr_name: &Ident, + meta_item_name: &Ident, + lit: &syn::Lit, +) -> Result<Vec<syn::WherePredicate>, ()> { + let string = try!(get_lit_str(cx, attr_name, meta_item_name, lit)); + if string.value().is_empty() { + return Ok(Vec::new()); + } + + let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span()); + + parse_lit_str::<syn::WhereClause>(&where_string) + .map(|wh| wh.predicates.into_iter().collect()) + .map_err(|err| cx.error_spanned_by(lit, err)) +} + +fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Type, ()> { + let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); + + parse_lit_str(string).map_err(|_| { + cx.error_spanned_by( + lit, + format!("failed to parse type: {} = {:?}", attr_name, string.value()), + ) + }) +} + +// Parses a string literal like "'a + 'b + 'c" containing a nonempty list of +// lifetimes separated by `+`. +fn parse_lit_into_lifetimes( + cx: &Ctxt, + attr_name: &Ident, + lit: &syn::Lit, +) -> Result<BTreeSet<syn::Lifetime>, ()> { + let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); + if string.value().is_empty() { + cx.error_spanned_by(lit, "at least one lifetime must be borrowed"); + return Err(()); + } + + struct BorrowedLifetimes(Punctuated<syn::Lifetime, Token![+]>); + + impl Parse for BorrowedLifetimes { + fn parse(input: ParseStream) -> parse::Result<Self> { + Punctuated::parse_separated_nonempty(input).map(BorrowedLifetimes) + } + } + + if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { + let mut set = BTreeSet::new(); + for lifetime in lifetimes { + if !set.insert(lifetime.clone()) { + cx.error_spanned_by(lit, format!("duplicate borrowed lifetime `{}`", lifetime)); + } + } + return Ok(set); + } + + cx.error_spanned_by( + lit, + format!("failed to parse borrowed lifetimes: {:?}", string.value()), + ); + Err(()) +} + +fn is_implicitly_borrowed(ty: &syn::Type) -> bool { + is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference) +} + +fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { + is_reference(ty, is_str) || is_reference(ty, is_slice_u8) +} + +// Whether the type looks like it might be `std::borrow::Cow<T>` where elem="T". +// This can have false negatives and false positives. +// +// False negative: +// +// use std::borrow::Cow as Pig; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// pig: Pig<'a, str>, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// #[serde(borrow)] +// cow: Cow<'a, str>, +// } +fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match *ty { + syn::Type::Path(ref ty) => &ty.path, + _ => { + return false; + } + }; + let seg = match path.segments.last() { + Some(seg) => seg.into_value(), + None => { + return false; + } + }; + let args = match seg.arguments { + syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Cow" + && args.len() == 2 + && match (&args[0], &args[1]) { + (&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => elem(arg), + _ => false, + } +} + +fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + let path = match *ty { + syn::Type::Path(ref ty) => &ty.path, + _ => { + return false; + } + }; + let seg = match path.segments.last() { + Some(seg) => seg.into_value(), + None => { + return false; + } + }; + let args = match seg.arguments { + syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args, + _ => { + return false; + } + }; + seg.ident == "Option" + && args.len() == 1 + && match args[0] { + syn::GenericArgument::Type(ref arg) => elem(arg), + _ => false, + } +} + +// Whether the type looks like it might be `&T` where elem="T". This can have +// false negatives and false positives. +// +// False negative: +// +// type Yarn = str; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a Yarn, +// } +// +// False positive: +// +// type str = [i16]; +// +// #[derive(Deserialize)] +// struct S<'a> { +// r: &'a str, +// } +fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { + match *ty { + syn::Type::Reference(ref ty) => ty.mutability.is_none() && elem(&ty.elem), + _ => false, + } +} + +fn is_str(ty: &syn::Type) -> bool { + is_primitive_type(ty, "str") +} + +fn is_slice_u8(ty: &syn::Type) -> bool { + match *ty { + syn::Type::Slice(ref ty) => is_primitive_type(&ty.elem, "u8"), + _ => false, + } +} + +fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { + match *ty { + syn::Type::Path(ref ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), + _ => false, + } +} + +fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { + path.leading_colon.is_none() + && path.segments.len() == 1 + && path.segments[0].ident == primitive + && path.segments[0].arguments.is_empty() +} + +// All lifetimes that this type could borrow from a Deserializer. +// +// For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand +// a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. +// +// This is used when there is an explicit or implicit `#[serde(borrow)]` +// attribute on the field so there must be at least one borrowable lifetime. +fn borrowable_lifetimes( + cx: &Ctxt, + name: &str, + field: &syn::Field, +) -> Result<BTreeSet<syn::Lifetime>, ()> { + let mut lifetimes = BTreeSet::new(); + collect_lifetimes(&field.ty, &mut lifetimes); + if lifetimes.is_empty() { + cx.error_spanned_by( + field, + format!("field `{}` has no lifetimes to borrow", name), + ); + Err(()) + } else { + Ok(lifetimes) + } +} + +fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) { + match *ty { + syn::Type::Slice(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Array(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Ptr(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Reference(ref ty) => { + out.extend(ty.lifetime.iter().cloned()); + collect_lifetimes(&ty.elem, out); + } + syn::Type::Tuple(ref ty) => { + for elem in &ty.elems { + collect_lifetimes(elem, out); + } + } + syn::Type::Path(ref ty) => { + if let Some(ref qself) = ty.qself { + collect_lifetimes(&qself.ty, out); + } + for seg in &ty.path.segments { + if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments { + for arg in &bracketed.args { + match *arg { + syn::GenericArgument::Lifetime(ref lifetime) => { + out.insert(lifetime.clone()); + } + syn::GenericArgument::Type(ref ty) => { + collect_lifetimes(ty, out); + } + syn::GenericArgument::Binding(ref binding) => { + collect_lifetimes(&binding.ty, out); + } + syn::GenericArgument::Constraint(_) + | syn::GenericArgument::Const(_) => {} + } + } + } + } + } + syn::Type::Paren(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Group(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::BareFn(_) + | syn::Type::Never(_) + | syn::Type::TraitObject(_) + | syn::Type::ImplTrait(_) + | syn::Type::Infer(_) + | syn::Type::Macro(_) + | syn::Type::Verbatim(_) => {} + } +} + +fn parse_lit_str<T>(s: &syn::LitStr) -> parse::Result<T> +where + T: Parse, +{ + let tokens = try!(spanned_tokens(s)); + syn::parse2(tokens) +} + +fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> { + let stream = try!(syn::parse_str(&s.value())); + Ok(respan_token_stream(stream, s.span())) +} + +fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { + stream + .into_iter() + .map(|token| respan_token_tree(token, span)) + .collect() +} + +fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { + if let TokenTree::Group(ref mut g) = token { + *g = Group::new(g.delimiter(), respan_token_stream(g.stream().clone(), span)); + } + token.set_span(span); + token +} diff --git a/serde_derive/src/internals/case.rs b/serde_derive/src/internals/case.rs new file mode 100644 index 000000000..3fcbb32db --- /dev/null +++ b/serde_derive/src/internals/case.rs @@ -0,0 +1,174 @@ +//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the +//! case of the source (e.g. `my-field`, `MY_FIELD`). + +// See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726 +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; + +use std::str::FromStr; + +use self::RenameRule::*; + +/// The different possible ways to change case of fields in a struct, or variants in an enum. +#[derive(Copy, Clone, PartialEq)] +pub enum RenameRule { + /// Don't apply a default rename rule. + None, + /// Rename direct children to "lowercase" style. + LowerCase, + /// Rename direct children to "UPPERCASE" style. + UPPERCASE, + /// Rename direct children to "PascalCase" style, as typically used for + /// enum variants. + PascalCase, + /// Rename direct children to "camelCase" style. + CamelCase, + /// Rename direct children to "snake_case" style, as commonly used for + /// fields. + SnakeCase, + /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly + /// used for constants. + ScreamingSnakeCase, + /// Rename direct children to "kebab-case" style. + KebabCase, + /// Rename direct children to "SCREAMING-KEBAB-CASE" style. + ScreamingKebabCase, +} + +impl RenameRule { + /// Apply a renaming rule to an enum variant, returning the version expected in the source. + pub fn apply_to_variant(&self, variant: &str) -> String { + match *self { + None | PascalCase => variant.to_owned(), + LowerCase => variant.to_ascii_lowercase(), + UPPERCASE => variant.to_ascii_uppercase(), + CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], + SnakeCase => { + let mut snake = String::new(); + for (i, ch) in variant.char_indices() { + if i > 0 && ch.is_uppercase() { + snake.push('_'); + } + snake.push(ch.to_ascii_lowercase()); + } + snake + } + ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), + KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase + .apply_to_variant(variant) + .replace('_', "-"), + } + } + + /// Apply a renaming rule to a struct field, returning the version expected in the source. + pub fn apply_to_field(&self, field: &str) -> String { + match *self { + None | LowerCase | SnakeCase => field.to_owned(), + UPPERCASE => field.to_ascii_uppercase(), + PascalCase => { + let mut pascal = String::new(); + let mut capitalize = true; + for ch in field.chars() { + if ch == '_' { + capitalize = true; + } else if capitalize { + pascal.push(ch.to_ascii_uppercase()); + capitalize = false; + } else { + pascal.push(ch); + } + } + pascal + } + CamelCase => { + let pascal = PascalCase.apply_to_field(field); + pascal[..1].to_ascii_lowercase() + &pascal[1..] + } + ScreamingSnakeCase => field.to_ascii_uppercase(), + KebabCase => field.replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), + } + } +} + +impl FromStr for RenameRule { + type Err = (); + + fn from_str(rename_all_str: &str) -> Result<Self, Self::Err> { + match rename_all_str { + "lowercase" => Ok(LowerCase), + "UPPERCASE" => Ok(UPPERCASE), + "PascalCase" => Ok(PascalCase), + "camelCase" => Ok(CamelCase), + "snake_case" => Ok(SnakeCase), + "SCREAMING_SNAKE_CASE" => Ok(ScreamingSnakeCase), + "kebab-case" => Ok(KebabCase), + "SCREAMING-KEBAB-CASE" => Ok(ScreamingKebabCase), + _ => Err(()), + } + } +} + +#[test] +fn rename_variants() { + for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ + ( + "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "VeryTasty", + "verytasty", + "VERYTASTY", + "veryTasty", + "very_tasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("A", "a", "A", "a", "a", "A", "a", "A"), + ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(None.apply_to_variant(original), original); + assert_eq!(LowerCase.apply_to_variant(original), lower); + assert_eq!(UPPERCASE.apply_to_variant(original), upper); + assert_eq!(PascalCase.apply_to_variant(original), original); + assert_eq!(CamelCase.apply_to_variant(original), camel); + assert_eq!(SnakeCase.apply_to_variant(original), snake); + assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); + assert_eq!(KebabCase.apply_to_variant(original), kebab); + assert_eq!( + ScreamingKebabCase.apply_to_variant(original), + screaming_kebab + ); + } +} + +#[test] +fn rename_fields() { + for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ + ( + "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "very_tasty", + "VERY_TASTY", + "VeryTasty", + "veryTasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("a", "A", "A", "a", "A", "a", "A"), + ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(None.apply_to_field(original), original); + assert_eq!(UPPERCASE.apply_to_field(original), upper); + assert_eq!(PascalCase.apply_to_field(original), pascal); + assert_eq!(CamelCase.apply_to_field(original), camel); + assert_eq!(SnakeCase.apply_to_field(original), original); + assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); + assert_eq!(KebabCase.apply_to_field(original), kebab); + assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); + } +} diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs new file mode 100644 index 000000000..19d8dd874 --- /dev/null +++ b/serde_derive/src/internals/check.rs @@ -0,0 +1,412 @@ +use internals::ast::{Container, Data, Field, Style}; +use internals::attr::{Identifier, TagType}; +use internals::{Ctxt, Derive}; +use syn::{Member, Type}; + +/// Cross-cutting checks that require looking at more than a single attrs +/// object. Simpler checks should happen when parsing and building the attrs. +pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_getter(cx, cont); + check_flatten(cx, cont); + check_identifier(cx, cont); + check_variant_skip_attrs(cx, cont); + check_internal_tag_field_name_conflict(cx, cont); + check_adjacent_tag_conflict(cx, cont); + check_transparent(cx, cont, derive); +} + +/// Getters are only allowed inside structs (not enums) with the `remote` +/// attribute. +fn check_getter(cx: &Ctxt, cont: &Container) { + match cont.data { + Data::Enum(_) => { + if cont.data.has_getter() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] is not allowed in an enum", + ); + } + } + Data::Struct(_, _) => { + if cont.data.has_getter() && cont.attrs.remote().is_none() { + cx.error_spanned_by( + cont.original, + "#[serde(getter = \"...\")] can only be used in structs \ + that have #[serde(remote = \"...\")]", + ); + } + } + } +} + +/// Flattening has some restrictions we can test. +fn check_flatten(cx: &Ctxt, cont: &Container) { + match cont.data { + Data::Enum(ref variants) => { + for variant in variants { + for field in &variant.fields { + check_flatten_field(cx, variant.style, field); + } + } + } + Data::Struct(style, ref fields) => { + for field in fields { + check_flatten_field(cx, style, field); + } + } + } +} + +fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { + if !field.attrs.flatten() { + return; + } + match style { + Style::Tuple => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on tuple structs", + ); + } + Style::Newtype => { + cx.error_spanned_by( + field.original, + "#[serde(flatten)] cannot be used on newtype structs", + ); + } + _ => {} + } +} + +/// The `other` attribute must be used at most once and it must be the last +/// variant of an enum. +/// +/// Inside a `variant_identifier` all variants must be unit variants. Inside a +/// `field_identifier` all but possibly one variant must be unit variants. The +/// last variant may be a newtype variant which is an implicit "other" case. +fn check_identifier(cx: &Ctxt, cont: &Container) { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { + return; + } + }; + + for (i, variant) in variants.iter().enumerate() { + match ( + variant.style, + cont.attrs.identifier(), + variant.attrs.other(), + cont.attrs.tag(), + ) { + // The `other` attribute may not be used in a variant_identifier. + (_, Identifier::Variant, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] may not be used on a variant identifier", + ); + } + + // Variant with `other` attribute cannot appear in untagged enum + (_, Identifier::No, true, &TagType::None) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] cannot appear on untagged enum", + ); + } + + // Variant with `other` attribute must be the last one. + (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on the last variant", + ); + } + } + + // Variant with `other` attribute must be a unit variant. + (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(other)] must be on a unit variant", + ); + } + + // Any sort of variant is allowed if this is not an identifier. + (_, Identifier::No, false, _) => {} + + // Unit variant without `other` attribute is always fine. + (Style::Unit, _, false, _) => {} + + // The last field is allowed to be a newtype catch-all. + (Style::Newtype, Identifier::Field, false, _) => { + if i < variants.len() - 1 { + cx.error_spanned_by( + variant.original, + format!("`{}` must be the last variant", variant.ident), + ); + } + } + + (_, Identifier::Field, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(field_identifier)] may only contain unit variants", + ); + } + + (_, Identifier::Variant, false, _) => { + cx.error_spanned_by( + variant.original, + "#[serde(variant_identifier)] may only contain unit variants", + ); + } + } + } +} + +/// Skip-(de)serializing attributes are not allowed on variants marked +/// (de)serialize_with. +fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { + return; + } + }; + + for variant in variants.iter() { + if variant.attrs.serialize_with().is_some() { + if variant.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and \ + #[serde(skip_serializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + let member = member_message(&field.member); + + if field.attrs.skip_serializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and \ + a field {} marked with #[serde(skip_serializing)]", + variant.ident, member + ), + ); + } + + if field.attrs.skip_serializing_if().is_some() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(serialize_with)] and \ + a field {} marked with #[serde(skip_serializing_if)]", + variant.ident, member + ), + ); + } + } + } + + if variant.attrs.deserialize_with().is_some() { + if variant.attrs.skip_deserializing() { + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] and \ + #[serde(skip_deserializing)]", + variant.ident + ), + ); + } + + for field in &variant.fields { + if field.attrs.skip_deserializing() { + let member = member_message(&field.member); + + cx.error_spanned_by( + variant.original, + format!( + "variant `{}` cannot have both #[serde(deserialize_with)] \ + and a field {} marked with #[serde(skip_deserializing)]", + variant.ident, member + ), + ); + } + } + } + } +} + +/// The tag of an internally-tagged struct variant must not be +/// the same as either one of its fields, as this would result in +/// duplicate keys in the serialized output and/or ambiguity in +/// the to-be-deserialized input. +fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => return, + }; + + let tag = match *cont.attrs.tag() { + TagType::Internal { ref tag } => tag.as_str(), + TagType::External | TagType::Adjacent { .. } | TagType::None => return, + }; + + let diagnose_conflict = || { + cx.error_spanned_by( + cont.original, + format!("variant field name `{}` conflicts with internal tag", tag), + ) + }; + + for variant in variants { + match variant.style { + Style::Struct => { + for field in &variant.fields { + let check_ser = !field.attrs.skip_serializing(); + let check_de = !field.attrs.skip_deserializing(); + let name = field.attrs.name(); + let ser_name = name.serialize_name(); + + if check_ser && ser_name == tag { + diagnose_conflict(); + return; + } + + for de_name in field.attrs.aliases() { + if check_de && de_name == tag { + diagnose_conflict(); + return; + } + } + } + } + Style::Unit | Style::Newtype | Style::Tuple => {} + } + } +} + +/// In the case of adjacently-tagged enums, the type and the +/// contents tag must differ, for the same reason. +fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { + let (type_tag, content_tag) = match *cont.attrs.tag() { + TagType::Adjacent { + ref tag, + ref content, + } => (tag, content), + TagType::Internal { .. } | TagType::External | TagType::None => return, + }; + + if type_tag == content_tag { + cx.error_spanned_by( + cont.original, + format!( + "enum tags `{}` for type and content conflict with each other", + type_tag + ), + ); + } +} + +/// Enums and unit structs cannot be transparent. +fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { + if !cont.attrs.transparent() { + return; + } + + if cont.attrs.type_from().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", + ); + } + + if cont.attrs.type_into().is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", + ); + } + + let fields = match cont.data { + Data::Enum(_) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on an enum", + ); + return; + } + Data::Struct(Style::Unit, _) => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] is not allowed on a unit struct", + ); + return; + } + Data::Struct(_, ref mut fields) => fields, + }; + + let mut transparent_field = None; + + for field in fields { + if allow_transparent(field, derive) { + if transparent_field.is_some() { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires struct to have at most one transparent field", + ); + return; + } + transparent_field = Some(field); + } + } + + match transparent_field { + Some(transparent_field) => transparent_field.attrs.mark_transparent(), + None => match derive { + Derive::Serialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is not skipped", + ); + } + Derive::Deserialize => { + cx.error_spanned_by( + cont.original, + "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", + ); + } + }, + } +} + +fn member_message(member: &Member) -> String { + match *member { + Member::Named(ref ident) => format!("`{}`", ident), + Member::Unnamed(ref i) => format!("#{}", i.index), + } +} + +fn allow_transparent(field: &Field, derive: Derive) -> bool { + if let Type::Path(ref ty) = *field.ty { + if let Some(seg) = ty.path.segments.last() { + if seg.into_value().ident == "PhantomData" { + return false; + } + } + } + + match derive { + Derive::Serialize => !field.attrs.skip_serializing(), + Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), + } +} diff --git a/serde_derive/src/internals/ctxt.rs b/serde_derive/src/internals/ctxt.rs new file mode 100644 index 000000000..84261cf1a --- /dev/null +++ b/serde_derive/src/internals/ctxt.rs @@ -0,0 +1,57 @@ +use quote::ToTokens; +use std::cell::RefCell; +use std::fmt::Display; +use std::thread; +use syn; + +/// A type to collect errors together and format them. +/// +/// Dropping this object will cause a panic. It must be consumed using `check`. +/// +/// References can be shared since this type uses run-time exclusive mut checking. +#[derive(Default)] +pub struct Ctxt { + // The contents will be set to `None` during checking. This is so that checking can be + // enforced. + errors: RefCell<Option<Vec<syn::Error>>>, +} + +impl Ctxt { + /// Create a new context object. + /// + /// This object contains no errors, but will still trigger a panic if it is not `check`ed. + pub fn new() -> Self { + Ctxt { + errors: RefCell::new(Some(Vec::new())), + } + } + + /// Add an error to the context object with a tokenenizable object. + /// + /// The object is used for spanning in error messages. + pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) { + self.errors + .borrow_mut() + .as_mut() + .unwrap() + // Curb monomorphization from generating too many identical methods. + .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); + } + + /// Consume this object, producing a formatted error string if there are errors. + pub fn check(self) -> Result<(), Vec<syn::Error>> { + let errors = self.errors.borrow_mut().take().unwrap(); + match errors.len() { + 0 => Ok(()), + _ => Err(errors), + } + } +} + +impl Drop for Ctxt { + fn drop(&mut self) { + if !thread::panicking() && self.errors.borrow().is_some() { + panic!("forgot to check for errors"); + } + } +} diff --git a/serde_derive/src/internals/mod.rs b/serde_derive/src/internals/mod.rs new file mode 100644 index 000000000..c31b3f9fa --- /dev/null +++ b/serde_derive/src/internals/mod.rs @@ -0,0 +1,14 @@ +pub mod ast; +pub mod attr; + +mod ctxt; +pub use self::ctxt::Ctxt; + +mod case; +mod check; + +#[derive(Copy, Clone)] +pub enum Derive { + Serialize, + Deserialize, +} diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs new file mode 100644 index 000000000..bf0f2c0f2 --- /dev/null +++ b/serde_derive/src/lib.rs @@ -0,0 +1,96 @@ +//! This crate provides Serde's two derive macros. +//! +//! ```edition2018 +//! # use serde_derive::{Serialize, Deserialize}; +//! # +//! #[derive(Serialize, Deserialize)] +//! # struct S; +//! # +//! # fn main() {} +//! ``` +//! +//! Please refer to [https://serde.rs/derive.html] for how to set this up. +//! +//! [https://serde.rs/derive.html]: https://serde.rs/derive.html + +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.91")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] +// Ignored clippy lints +#![cfg_attr( + feature = "cargo-clippy", + allow( + cognitive_complexity, + enum_variant_names, + needless_pass_by_value, + redundant_field_names, + too_many_arguments, + trivially_copy_pass_by_ref, + used_underscore_binding, + ) +)] +// Ignored clippy_pedantic lints +#![cfg_attr( + feature = "cargo-clippy", + allow( + cast_possible_truncation, + doc_markdown, + enum_glob_use, + filter_map, + indexing_slicing, + items_after_statements, + match_same_arms, + module_name_repetitions, + similar_names, + single_match_else, + unseparated_literal_suffix, + use_self, + ) +)] +// The `quote!` macro requires deep recursion. +#![recursion_limit = "512"] + +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; + +extern crate proc_macro; +extern crate proc_macro2; + +mod internals; + +use proc_macro::TokenStream; +use syn::DeriveInput; + +#[macro_use] +mod bound; +#[macro_use] +mod fragment; + +mod de; +mod dummy; +mod pretend; +mod ser; +mod try; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn derive_serialize(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + ser::expand_derive_serialize(&input) + .unwrap_or_else(to_compile_errors) + .into() +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn derive_deserialize(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + de::expand_derive_deserialize(&input) + .unwrap_or_else(to_compile_errors) + .into() +} + +fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream { + let compile_errors = errors.iter().map(syn::Error::to_compile_error); + quote!(#(#compile_errors)*) +} diff --git a/serde_derive/src/pretend.rs b/serde_derive/src/pretend.rs new file mode 100644 index 000000000..c4ffe12da --- /dev/null +++ b/serde_derive/src/pretend.rs @@ -0,0 +1,140 @@ +use proc_macro2::{Span, TokenStream}; +use syn::Ident; + +use internals::ast::{Container, Data, Field, Style}; + +// Suppress dead_code warnings that would otherwise appear when using a remote +// derive. Other than this pretend code, a struct annotated with remote derive +// never has its fields referenced and an enum annotated with remote derive +// never has its variants constructed. +// +// warning: field is never used: `i` +// --> src/main.rs:4:20 +// | +// 4 | struct StructDef { i: i32 } +// | ^^^^^^ +// +// warning: variant is never constructed: `V` +// --> src/main.rs:8:16 +// | +// 8 | enum EnumDef { V } +// | ^ +// +pub fn pretend_used(cont: &Container) -> TokenStream { + let pretend_fields = pretend_fields_used(cont); + let pretend_variants = pretend_variants_used(cont); + + quote! { + #pretend_fields + #pretend_variants + } +} + +// For structs with named fields, expands to: +// +// match None::<T> { +// Some(T { a: ref __v0, b: ref __v1 }) => {} +// _ => {} +// } +// +// For enums, expands to the following but only including struct variants: +// +// match None::<T> { +// Some(T::A { a: ref __v0 }) => {} +// Some(T::B { b: ref __v0 }) => {} +// _ => {} +// } +// +// The `ref` is important in case the user has written a Drop impl on their +// type. Rust does not allow destructuring a struct or enum that has a Drop +// impl. +fn pretend_fields_used(cont: &Container) -> TokenStream { + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + + let patterns = match cont.data { + Data::Enum(ref variants) => variants + .iter() + .filter_map(|variant| match variant.style { + Style::Struct => { + let variant_ident = &variant.ident; + let pat = struct_pattern(&variant.fields); + Some(quote!(#type_ident::#variant_ident #pat)) + } + _ => None, + }) + .collect::<Vec<_>>(), + Data::Struct(Style::Struct, ref fields) => { + let pat = struct_pattern(fields); + vec![quote!(#type_ident #pat)] + } + Data::Struct(_, _) => { + return quote!(); + } + }; + + quote! { + match _serde::export::None::<#type_ident #ty_generics> { + #( + _serde::export::Some(#patterns) => {} + )* + _ => {} + } + } +} + +// Expands to one of these per enum variant: +// +// match None { +// Some((__v0, __v1,)) => { +// let _ = E::V { a: __v0, b: __v1 }; +// } +// _ => {} +// } +// +fn pretend_variants_used(cont: &Container) -> TokenStream { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { + return quote!(); + } + }; + + let type_ident = &cont.ident; + let (_, ty_generics, _) = cont.generics.split_for_impl(); + let turbofish = ty_generics.as_turbofish(); + + let cases = variants.iter().map(|variant| { + let variant_ident = &variant.ident; + let placeholders = &(0..variant.fields.len()) + .map(|i| Ident::new(&format!("__v{}", i), Span::call_site())) + .collect::<Vec<_>>(); + + let pat = match variant.style { + Style::Struct => { + let members = variant.fields.iter().map(|field| &field.member); + quote!({ #(#members: #placeholders),* }) + } + Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), + Style::Unit => quote!(), + }; + + quote! { + match _serde::export::None { + _serde::export::Some((#(#placeholders,)*)) => { + let _ = #type_ident::#variant_ident #turbofish #pat; + } + _ => {} + } + } + }); + + quote!(#(#cases)*) +} + +fn struct_pattern(fields: &[Field]) -> TokenStream { + let members = fields.iter().map(|field| &field.member); + let placeholders = + (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); + quote!({ #(#members: ref #placeholders),* }) +} diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs new file mode 100644 index 000000000..c5388aff3 --- /dev/null +++ b/serde_derive/src/ser.rs @@ -0,0 +1,1315 @@ +use proc_macro2::{Span, TokenStream}; +use syn::spanned::Spanned; +use syn::{self, Ident, Index, Member}; + +use bound; +use dummy; +use fragment::{Fragment, Match, Stmts}; +use internals::ast::{Container, Data, Field, Style, Variant}; +use internals::{attr, Ctxt, Derive}; +use pretend; + +pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> { + let ctxt = Ctxt::new(); + let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) { + Some(cont) => cont, + None => return Err(ctxt.check().unwrap_err()), + }; + precondition(&ctxt, &cont); + try!(ctxt.check()); + + let ident = &cont.ident; + let params = Parameters::new(&cont); + let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); + let body = Stmts(serialize_body(&cont, ¶ms)); + let serde = cont.attrs.serde_path(); + + let impl_block = if let Some(remote) = cont.attrs.remote() { + let vis = &input.vis; + let used = pretend::pretend_used(&cont); + quote! { + impl #impl_generics #ident #ty_generics #where_clause { + #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error> + where + __S: #serde::Serializer, + { + #used + #body + } + } + } + } else { + quote! { + #[automatically_derived] + impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> #serde::export::Result<__S::Ok, __S::Error> + where + __S: #serde::Serializer, + { + #body + } + } + } + }; + + Ok(dummy::wrap_in_const( + cont.attrs.custom_serde_path(), + "SERIALIZE", + ident, + impl_block, + )) +} + +fn precondition(cx: &Ctxt, cont: &Container) { + match cont.attrs.identifier() { + attr::Identifier::No => {} + attr::Identifier::Field => { + cx.error_spanned_by(cont.original, "field identifiers cannot be serialized"); + } + attr::Identifier::Variant => { + cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized"); + } + } +} + +struct Parameters { + /// Variable holding the value being serialized. Either `self` for local + /// types or `__self` for remote types. + self_var: Ident, + + /// Path to the type the impl is for. Either a single `Ident` for local + /// types or `some::remote::Ident` for remote types. Does not include + /// generic parameters. + this: syn::Path, + + /// Generics including any explicit and inferred bounds for the impl. + generics: syn::Generics, + + /// Type has a `serde(remote = "...")` attribute. + is_remote: bool, +} + +impl Parameters { + fn new(cont: &Container) -> Self { + let is_remote = cont.attrs.remote().is_some(); + let self_var = if is_remote { + Ident::new("__self", Span::call_site()) + } else { + Ident::new("self", Span::call_site()) + }; + + let this = match cont.attrs.remote() { + Some(remote) => remote.clone(), + None => cont.ident.clone().into(), + }; + + let generics = build_generics(cont); + + Parameters { + self_var: self_var, + this: this, + generics: generics, + is_remote: is_remote, + } + } + + /// Type name to use in error messages and `&'static str` arguments to + /// various Serializer methods. + fn type_name(&self) -> String { + self.this.segments.last().unwrap().value().ident.to_string() + } +} + +// All the generics in the input, plus a bound `T: Serialize` for each generic +// field type that will be serialized by us. +fn build_generics(cont: &Container) -> syn::Generics { + let generics = bound::without_defaults(cont.generics); + + let generics = + bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound); + + let generics = + bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound); + + match cont.attrs.ser_bound() { + Some(predicates) => bound::with_where_predicates(&generics, predicates), + None => bound::with_bound( + cont, + &generics, + needs_serialize_bound, + &parse_quote!(_serde::Serialize), + ), + } +} + +// Fields with a `skip_serializing` or `serialize_with` attribute, or which +// belong to a variant with a 'skip_serializing` or `serialize_with` attribute, +// are not serialized by us so we do not generate a bound. Fields with a `bound` +// attribute specify their own bound so we do not generate one. All other fields +// may need a `T: Serialize` bound where T is the type of the field. +fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { + !field.skip_serializing() + && field.serialize_with().is_none() + && field.ser_bound().is_none() + && variant.map_or(true, |variant| { + !variant.skip_serializing() + && variant.serialize_with().is_none() + && variant.ser_bound().is_none() + }) +} + +fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { + if cont.attrs.transparent() { + serialize_transparent(cont, params) + } else if let Some(type_into) = cont.attrs.type_into() { + serialize_into(params, type_into) + } else { + match cont.data { + Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), + Data::Struct(Style::Struct, ref fields) => { + serialize_struct(params, fields, &cont.attrs) + } + Data::Struct(Style::Tuple, ref fields) => { + serialize_tuple_struct(params, fields, &cont.attrs) + } + Data::Struct(Style::Newtype, ref fields) => { + serialize_newtype_struct(params, &fields[0], &cont.attrs) + } + Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), + } + } +} + +fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { + let fields = match cont.data { + Data::Struct(_, ref fields) => fields, + Data::Enum(_) => unreachable!(), + }; + + let self_var = ¶ms.self_var; + let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); + let member = &transparent_field.member; + + let path = match transparent_field.attrs.serialize_with() { + Some(path) => quote!(#path), + None => { + let span = transparent_field.original.span(); + quote_spanned!(span=> _serde::Serialize::serialize) + } + }; + + quote_block! { + #path(&#self_var.#member, __serializer) + } +} + +fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { + let self_var = ¶ms.self_var; + quote_block! { + _serde::Serialize::serialize( + &_serde::export::Into::<#type_into>::into(_serde::export::Clone::clone(#self_var)), + __serializer) + } +} + +fn serialize_unit_struct(cattrs: &attr::Container) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + quote_expr! { + _serde::Serializer::serialize_unit_struct(__serializer, #type_name) + } +} + +fn serialize_newtype_struct( + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + + let mut field_expr = get_member( + params, + field, + &Member::Unnamed(Index { + index: 0, + span: Span::call_site(), + }), + ); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct); + quote_expr! { + #func(__serializer, #type_name, #field_expr) + } +} + +fn serialize_tuple_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_stmts = + serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); + + let type_name = cattrs.name().serialize_name(); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|&(_, ref field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let index = syn::Index { + index: i as u32, + span: Span::call_site(), + }; + let field_expr = get_member(params, field, &Member::Unnamed(index)); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)); + #(#serialize_stmts)* + _serde::ser::SerializeTupleStruct::end(__serde_state) + } +} + +fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { + assert!(fields.len() as u64 <= u64::from(u32::max_value())); + + if cattrs.has_flatten() { + serialize_struct_as_map(params, fields, cattrs) + } else { + serialize_struct_as_struct(params, fields, cattrs) + } +} + +fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream { + match *cattrs.tag() { + attr::TagType::Internal { ref tag } => { + let type_name = cattrs.name().serialize_name(); + let func = struct_trait.serialize_field(Span::call_site()); + quote! { + try!(#func(&mut __serde_state, #tag, #type_name)); + } + } + _ => quote! {}, + } +} + +fn serialize_struct_as_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct); + + let type_name = cattrs.name().serialize_name(); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + let len = serialized_fields + .map(|field| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = get_member(params, field, &field.member); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold( + quote!(#tag_field_exists as usize), + |sum, expr| quote!(#sum + #expr), + ); + + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len)); + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } +} + +fn serialize_struct_as_map( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + let serialize_fields = + serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap); + + let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap); + let tag_field_exists = !tag_field.is_empty(); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); + + let len = if cattrs.has_flatten() { + quote!(_serde::export::None) + } else { + let len = serialized_fields + .map(|field| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = get_member(params, field, &field.member); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold( + quote!(#tag_field_exists as usize), + |sum, expr| quote!(#sum + #expr), + ); + quote!(_serde::export::Some(#len)) + }; + + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len)); + #tag_field + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } +} + +fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { + assert!(variants.len() as u64 <= u64::from(u32::max_value())); + + let self_var = ¶ms.self_var; + + let arms: Vec<_> = variants + .iter() + .enumerate() + .map(|(variant_index, variant)| { + serialize_variant(params, variant, variant_index as u32, cattrs) + }) + .collect(); + + quote_expr! { + match *#self_var { + #(#arms)* + } + } +} + +fn serialize_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> TokenStream { + let this = ¶ms.this; + let variant_ident = &variant.ident; + + if variant.attrs.skip_serializing() { + let skipped_msg = format!( + "the enum variant {}::{} cannot be serialized", + params.type_name(), + variant_ident + ); + let skipped_err = quote! { + _serde::export::Err(_serde::ser::Error::custom(#skipped_msg)) + }; + let fields_pat = match variant.style { + Style::Unit => quote!(), + Style::Newtype | Style::Tuple => quote!((..)), + Style::Struct => quote!({ .. }), + }; + quote! { + #this::#variant_ident #fields_pat => #skipped_err, + } + } else { + // variant wasn't skipped + let case = match variant.style { + Style::Unit => { + quote! { + #this::#variant_ident + } + } + Style::Newtype => { + quote! { + #this::#variant_ident(ref __field0) + } + } + Style::Tuple => { + let field_names = (0..variant.fields.len()) + .map(|i| Ident::new(&format!("__field{}", i), Span::call_site())); + quote! { + #this::#variant_ident(#(ref #field_names),*) + } + } + Style::Struct => { + let members = variant.fields.iter().map(|f| &f.member); + quote! { + #this::#variant_ident { #(ref #members),* } + } + } + }; + + let body = Match(match *cattrs.tag() { + attr::TagType::External => { + serialize_externally_tagged_variant(params, variant, variant_index, cattrs) + } + attr::TagType::Internal { ref tag } => { + serialize_internally_tagged_variant(params, variant, cattrs, tag) + } + attr::TagType::Adjacent { + ref tag, + ref content, + } => serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content), + attr::TagType::None => serialize_untagged_variant(params, variant, cattrs), + }); + + quote! { + #case => #body + } + } +} + +fn serialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + variant_index: u32, + cattrs: &attr::Container, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serializer::serialize_newtype_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #ser, + ) + }; + } + + match variant.style { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + ) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant); + quote_expr! { + #func( + __serializer, + #type_name, + #variant_index, + #variant_name, + #field_expr, + ) + } + } + Style::Tuple => serialize_tuple_variant( + TupleVariant::ExternallyTagged { + type_name: type_name, + variant_index: variant_index, + variant_name: variant_name, + }, + params, + &variant.fields, + ), + Style::Struct => serialize_struct_variant( + StructVariant::ExternallyTagged { + variant_index: variant_index, + variant_name: variant_name, + }, + params, + &variant.fields, + &type_name, + ), + } +} + +fn serialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + let enum_ident_str = params.type_name(); + let variant_ident_str = variant.ident.to_string(); + + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::private::ser::serialize_tagged_newtype( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #ser, + ) + }; + } + + match variant.style { + Style::Unit => { + quote_block! { + let mut __struct = try!(_serde::Serializer::serialize_struct( + __serializer, #type_name, 1)); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)); + _serde::ser::SerializeStruct::end(__struct) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::private::ser::serialize_tagged_newtype); + quote_expr! { + #func( + __serializer, + #enum_ident_str, + #variant_ident_str, + #tag, + #variant_name, + #field_expr, + ) + } + } + Style::Struct => serialize_struct_variant( + StructVariant::InternallyTagged { + tag: tag, + variant_name: variant_name, + }, + params, + &variant.fields, + &type_name, + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} + +fn serialize_adjacently_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, + tag: &str, + content: &str, +) -> Fragment { + let this = ¶ms.this; + let type_name = cattrs.name().serialize_name(); + let variant_name = variant.attrs.name().serialize_name(); + + let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + } + } else { + match variant.style { + Style::Unit => { + return quote_block! { + let mut __struct = try!(_serde::Serializer::serialize_struct( + __serializer, #type_name, 1)); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)); + _serde::ser::SerializeStruct::end(__struct) + }; + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); + return quote_block! { + let mut __struct = try!(_serde::Serializer::serialize_struct( + __serializer, #type_name, 2)); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)); + try!(#func( + &mut __struct, #content, #field_expr)); + _serde::ser::SerializeStruct::end(__struct) + }; + } + Style::Tuple => { + serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields) + } + Style::Struct => serialize_struct_variant( + StructVariant::Untagged, + params, + &variant.fields, + &variant_name, + ), + } + }); + + let fields_ty = variant.fields.iter().map(|f| &f.ty); + let fields_ident: &Vec<_> = &match variant.style { + Style::Unit => { + if variant.attrs.serialize_with().is_some() { + vec![] + } else { + unreachable!() + } + } + Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))], + Style::Tuple => (0..variant.fields.len()) + .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site()))) + .collect(), + Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(), + }; + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if fields_ident.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + struct __AdjacentlyTagged #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::export::PhantomData<#this #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + let (#(#fields_ident,)*) = self.data; + #inner + } + } + + let mut __struct = try!(_serde::Serializer::serialize_struct( + __serializer, #type_name, 2)); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __struct, #tag, #variant_name)); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __struct, #content, &__AdjacentlyTagged { + data: (#(#fields_ident,)*), + phantom: _serde::export::PhantomData::<#this #ty_generics>, + })); + _serde::ser::SerializeStruct::end(__struct) + } +} + +fn serialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.serialize_with() { + let ser = wrap_serialize_variant_with(params, path, variant); + return quote_expr! { + _serde::Serialize::serialize(#ser, __serializer) + }; + } + + match variant.style { + Style::Unit => { + quote_expr! { + _serde::Serializer::serialize_unit(__serializer) + } + } + Style::Newtype => { + let field = &variant.fields[0]; + let mut field_expr = quote!(__field0); + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote_expr! { + #func(#field_expr, __serializer) + } + } + Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), + Style::Struct => { + let type_name = cattrs.name().serialize_name(); + serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, &type_name) + } + } +} + +enum TupleVariant { + ExternallyTagged { + type_name: String, + variant_index: u32, + variant_name: String, + }, + Untagged, +} + +fn serialize_tuple_variant( + context: TupleVariant, + params: &Parameters, + fields: &[Field], +) -> Fragment { + let tuple_trait = match context { + TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant, + TupleVariant::Untagged => TupleTrait::SerializeTuple, + }; + + let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|&(_, ref field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = Ident::new(&format!("__field{}", i), Span::call_site()); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + TupleVariant::ExternallyTagged { + type_name, + variant_index, + variant_name, + } => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant( + __serializer, + #type_name, + #variant_index, + #variant_name, + #len)); + #(#serialize_stmts)* + _serde::ser::SerializeTupleVariant::end(__serde_state) + } + } + TupleVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple( + __serializer, + #len)); + #(#serialize_stmts)* + _serde::ser::SerializeTuple::end(__serde_state) + } + } + } +} + +enum StructVariant<'a> { + ExternallyTagged { + variant_index: u32, + variant_name: String, + }, + InternallyTagged { + tag: &'a str, + variant_name: String, + }, + Untagged, +} + +fn serialize_struct_variant<'a>( + context: StructVariant<'a>, + params: &Parameters, + fields: &[Field], + name: &str, +) -> Fragment { + if fields.iter().any(|field| field.attrs.flatten()) { + return serialize_struct_variant_with_flatten(context, params, fields, name); + } + + let struct_trait = match context { + StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant), + StructVariant::InternallyTagged { .. } | StructVariant::Untagged => { + (StructTrait::SerializeStruct) + } + }; + + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|field| { + let member = &field.member; + + match field.attrs.skip_serializing_if() { + Some(path) => quote!(if #path(#member) { 0 } else { 1 }), + None => quote!(1), + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant( + __serializer, + #name, + #variant_index, + #variant_name, + #len, + )); + #(#serialize_fields)* + _serde::ser::SerializeStructVariant::end(__serde_state) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let mut __serde_state = try!(_serde::Serializer::serialize_struct( + __serializer, + #name, + #len + 1, + )); + try!(_serde::ser::SerializeStruct::serialize_field( + &mut __serde_state, + #tag, + #variant_name, + )); + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } + } + StructVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct( + __serializer, + #name, + #len, + )); + #(#serialize_fields)* + _serde::ser::SerializeStruct::end(__serde_state) + } + } + } +} + +fn serialize_struct_variant_with_flatten<'a>( + context: StructVariant<'a>, + params: &Parameters, + fields: &[Field], + name: &str, +) -> Fragment { + let struct_trait = StructTrait::SerializeMap; + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + let this = ¶ms.this; + let fields_ty = fields.iter().map(|f| &f.ty); + let members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>(); + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + struct __EnumFlatten #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::export::PhantomData<#this #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + let (#(#members,)*) = self.data; + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + + _serde::Serializer::serialize_newtype_variant( + __serializer, + #name, + #variant_index, + #variant_name, + &__EnumFlatten { + data: (#(#members,)*), + phantom: _serde::export::PhantomData::<#this #ty_generics>, + }) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + try!(_serde::ser::SerializeMap::serialize_entry( + &mut __serde_state, + #tag, + #variant_name, + )); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + StructVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + } +} + +fn serialize_tuple_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + tuple_trait: &TupleTrait, +) -> Vec<TokenStream> { + fields + .iter() + .enumerate() + .filter(|&(_, ref field)| !field.attrs.skip_serializing()) + .map(|(i, field)| { + let mut field_expr = if is_enum { + let id = Ident::new(&format!("__field{}", i), Span::call_site()); + quote!(#id) + } else { + get_member( + params, + field, + &Member::Unnamed(Index { + index: i as u32, + span: Span::call_site(), + }), + ) + }; + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let func = tuple_trait.serialize_element(span); + let ser = quote! { + try!(#func(&mut __serde_state, #field_expr)); + }; + + match skip { + None => ser, + Some(skip) => quote!(if !#skip { #ser }), + } + }) + .collect() +} + +fn serialize_struct_visitor( + fields: &[Field], + params: &Parameters, + is_enum: bool, + struct_trait: &StructTrait, +) -> Vec<TokenStream> { + fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .map(|field| { + let member = &field.member; + + let mut field_expr = if is_enum { + quote!(#member) + } else { + get_member(params, field, &member) + }; + + let key_expr = field.attrs.name().serialize_name(); + + let skip = field + .attrs + .skip_serializing_if() + .map(|path| quote!(#path(#field_expr))); + + if let Some(path) = field.attrs.serialize_with() { + field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); + } + + let span = field.original.span(); + let ser = if field.attrs.flatten() { + let func = quote_spanned!(span=> _serde::Serialize::serialize); + quote! { + try!(#func(&#field_expr, _serde::private::ser::FlatMapSerializer(&mut __serde_state))); + } + } else { + let func = struct_trait.serialize_field(span); + quote! { + try!(#func(&mut __serde_state, #key_expr, #field_expr)); + } + }; + + match skip { + None => ser, + Some(skip) => { + if let Some(skip_func) = struct_trait.skip_field(span) { + quote! { + if !#skip { + #ser + } else { + try!(#skip_func(&mut __serde_state, #key_expr)); + } + } + } else { + quote! { + if !#skip { + #ser + } + } + } + } + } + }) + .collect() +} + +fn wrap_serialize_field_with( + params: &Parameters, + field_ty: &syn::Type, + serialize_with: &syn::ExprPath, + field_expr: &TokenStream, +) -> TokenStream { + wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)]) +} + +fn wrap_serialize_variant_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + variant: &Variant, +) -> TokenStream { + let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); + let field_exprs: Vec<_> = variant + .fields + .iter() + .map(|field| { + let id = match field.member { + Member::Named(ref ident) => ident.clone(), + Member::Unnamed(ref member) => { + Ident::new(&format!("__field{}", member.index), Span::call_site()) + } + }; + quote!(#id) + }) + .collect(); + wrap_serialize_with( + params, + serialize_with, + field_tys.as_slice(), + field_exprs.as_slice(), + ) +} + +fn wrap_serialize_with( + params: &Parameters, + serialize_with: &syn::ExprPath, + field_tys: &[&syn::Type], + field_exprs: &[TokenStream], +) -> TokenStream { + let this = ¶ms.this; + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + + let wrapper_generics = if field_exprs.is_empty() { + params.generics.clone() + } else { + bound::with_lifetime_bound(¶ms.generics, "'__a") + }; + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + let field_access = (0..field_exprs.len()).map(|n| { + Member::Unnamed(Index { + index: n as u32, + span: Span::call_site(), + }) + }); + + quote!({ + struct __SerializeWith #wrapper_impl_generics #where_clause { + values: (#(&'__a #field_tys, )*), + phantom: _serde::export::PhantomData<#this #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __s: __S) -> _serde::export::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + #serialize_with(#(self.values.#field_access, )* __s) + } + } + + &__SerializeWith { + values: (#(#field_exprs, )*), + phantom: _serde::export::PhantomData::<#this #ty_generics>, + } + }) +} + +// Serialization of an empty struct results in code like: +// +// let mut __serde_state = try!(serializer.serialize_struct("S", 0)); +// _serde::ser::SerializeStruct::end(__serde_state) +// +// where we want to omit the `mut` to avoid a warning. +fn mut_if(is_mut: bool) -> Option<TokenStream> { + if is_mut { + Some(quote!(mut)) + } else { + None + } +} + +fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream { + let self_var = ¶ms.self_var; + match (params.is_remote, field.attrs.getter()) { + (false, None) => quote!(&#self_var.#member), + (true, None) => { + let inner = quote!(&#self_var.#member); + let ty = field.ty; + quote!(_serde::private::ser::constrain::<#ty>(#inner)) + } + (true, Some(getter)) => { + let ty = field.ty; + quote!(_serde::private::ser::constrain::<#ty>(&#getter(#self_var))) + } + (false, Some(_)) => { + unreachable!("getter is only allowed for remote impls"); + } + } +} + +enum StructTrait { + SerializeMap, + SerializeStruct, + SerializeStructVariant, +} + +impl StructTrait { + fn serialize_field(&self, span: Span) -> TokenStream { + match *self { + StructTrait::SerializeMap => { + quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) + } + StructTrait::SerializeStruct => { + quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field) + } + StructTrait::SerializeStructVariant => { + quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field) + } + } + } + + fn skip_field(&self, span: Span) -> Option<TokenStream> { + match *self { + StructTrait::SerializeMap => None, + StructTrait::SerializeStruct => { + Some(quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)) + } + StructTrait::SerializeStructVariant => { + Some(quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)) + } + } + } +} + +enum TupleTrait { + SerializeTuple, + SerializeTupleStruct, + SerializeTupleVariant, +} + +impl TupleTrait { + fn serialize_element(&self, span: Span) -> TokenStream { + match *self { + TupleTrait::SerializeTuple => { + quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) + } + TupleTrait::SerializeTupleStruct => { + quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field) + } + TupleTrait::SerializeTupleVariant => { + quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field) + } + } + } +} diff --git a/serde_derive/src/try.rs b/serde_derive/src/try.rs new file mode 100644 index 000000000..48829b635 --- /dev/null +++ b/serde_derive/src/try.rs @@ -0,0 +1,24 @@ +use proc_macro2::{Punct, Spacing, TokenStream}; + +// None of our generated code requires the `From::from` error conversion +// performed by the standard library's `try!` macro. With this simplified macro +// we see a significant improvement in type checking and borrow checking time of +// the generated code and a slight improvement in binary size. +pub fn replacement() -> TokenStream { + // Cannot pass `$expr` to `quote!` prior to Rust 1.17.0 so interpolate it. + let dollar = Punct::new('$', Spacing::Alone); + + quote! { + #[allow(unused_macros)] + macro_rules! try { + (#dollar __expr:expr) => { + match #dollar __expr { + _serde::export::Ok(__val) => __val, + _serde::export::Err(__err) => { + return _serde::export::Err(__err); + } + } + } + } + } +} diff --git a/serde_ignored/.cargo-checksum.json b/serde_ignored/.cargo-checksum.json new file mode 100644 index 000000000..c9a1eb6f6 --- /dev/null +++ b/serde_ignored/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"} \ No newline at end of file diff --git a/serde_ignored/Cargo.toml b/serde_ignored/Cargo.toml new file mode 100644 index 000000000..8ab5a24e6 --- /dev/null +++ b/serde_ignored/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "serde_ignored" +version = "0.0.4" # update version in readme for breaking changes +authors = ["David Tolnay <dtolnay@gmail.com>"] +license = "MIT/Apache-2.0" +description = "Find out about keys that are ignored when deserializing data" +repository = "https://github.com/dtolnay/serde-ignored" +keywords = ["serde"] +categories = ["encoding"] + +[dependencies] +serde = "1.0" + +[dev-dependencies] +serde_derive = "1.0" +serde_json = "1.0" diff --git a/serde_ignored/LICENSE-APACHE b/serde_ignored/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/serde_ignored/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/serde_ignored/LICENSE-MIT b/serde_ignored/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/serde_ignored/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/serde_ignored/README.md b/serde_ignored/README.md new file mode 100644 index 000000000..cc54f7247 --- /dev/null +++ b/serde_ignored/README.md @@ -0,0 +1,98 @@ +# Serde ignored + +[![Build Status](https://api.travis-ci.org/dtolnay/serde-ignored.svg?branch=master)](https://travis-ci.org/dtolnay/serde-ignored) +[![Latest Version](https://img.shields.io/crates/v/serde-ignored.svg)](https://crates.io/crates/serde-ignored) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/serde_ignored) + +Find out about keys that are ignored when deserializing data. This crate +provides a wrapper that works with any existing Serde `Deserializer` and invokes +a callback on every ignored field. + +You can use this to warn users about extraneous keys in a config file, for +example. + +Note that if you want unrecognized fields to be an error, consider using the +`#[serde(deny_unknown_fields)]` [attribute] instead. + +[attribute]: https://serde.rs/attributes.html + +```toml +[dependencies] +serde = "1.0" +serde_ignored = "0.0.4" +``` + +```rust +#[macro_use] +extern crate serde_derive; + +extern crate serde; +extern crate serde_json; +extern crate serde_ignored; + +use std::collections::{BTreeSet as Set, BTreeMap as Map}; + +#[derive(Debug, PartialEq, Deserialize)] +struct Package { + name: String, + dependencies: Map<String, Dependency>, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct Dependency { + version: String, +} + +fn main() { + let j = r#"{ + "name": "demo", + "dependencies": { + "serde": { + "version": "0.9", + "typo1": "" + } + }, + "typo2": { + "inner": "" + }, + "typo3": {} + }"#; + + // Some Deserializer. + let jd = &mut serde_json::Deserializer::from_str(j); + + // We will build a set of paths to the unused elements. + let mut unused = Set::new(); + + let p: Package = serde_ignored::deserialize(jd, |path| { + unused.insert(path.to_string()); + }).unwrap(); + + // Deserialized as normal. + println!("{:?}", p); + + // There were three ignored keys. + let mut expected = Set::new(); + expected.insert("dependencies.serde.typo1".to_owned()); + expected.insert("typo2".to_owned()); + expected.insert("typo3".to_owned()); + assert_eq!(unused, expected); +} +``` + +## License + +This crate is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/serde_ignored/src/lib.rs b/serde_ignored/src/lib.rs new file mode 100644 index 000000000..4abe968eb --- /dev/null +++ b/serde_ignored/src/lib.rs @@ -0,0 +1,1104 @@ +//! ```rust +//! #[macro_use] +//! extern crate serde_derive; +//! +//! extern crate serde; +//! extern crate serde_json; +//! extern crate serde_ignored; +//! +//! use std::collections::{BTreeSet as Set, BTreeMap as Map}; +//! +//! #[derive(Debug, PartialEq, Deserialize)] +//! struct Package { +//! name: String, +//! dependencies: Map<String, Dependency>, +//! } +//! +//! #[derive(Debug, PartialEq, Deserialize)] +//! struct Dependency { +//! version: String, +//! } +//! +//! # fn try_main() -> Result<(), Box<::std::error::Error>> { +//! let j = r#"{ +//! "name": "demo", +//! "dependencies": { +//! "serde": { +//! "version": "0.9", +//! "typo1": "" +//! } +//! }, +//! "typo2": { +//! "inner": "" +//! }, +//! "typo3": {} +//! }"#; +//! +//! // Some Deserializer. +//! let jd = &mut serde_json::Deserializer::from_str(j); +//! +//! // We will build a set of paths to the unused elements. +//! let mut unused = Set::new(); +//! +//! let p: Package = serde_ignored::deserialize(jd, |path| { +//! unused.insert(path.to_string()); +//! })?; +//! +//! assert_eq!(p, Package { +//! name: "demo".to_owned(), +//! dependencies: { +//! let mut map = Map::new(); +//! map.insert("serde".to_owned(), Dependency { +//! version: "0.9".to_owned(), +//! }); +//! map +//! }, +//! }); +//! +//! assert_eq!(unused, { +//! let mut expected = Set::new(); +//! expected.insert("dependencies.serde.typo1".to_owned()); +//! expected.insert("typo2".to_owned()); +//! expected.insert("typo3".to_owned()); +//! expected +//! }); +//! +//! # Ok(()) } +//! # fn main() { try_main().unwrap() } +//! ``` + +extern crate serde; + +use std::fmt::{self, Display}; +use serde::de::{self, Deserialize, DeserializeSeed, Visitor}; + +/// Entry point. See crate documentation for an example. +pub fn deserialize<'de, D, F, T>(deserializer: D, mut callback: F) -> Result<T, D::Error> + where D: de::Deserializer<'de>, + F: FnMut(Path), + T: Deserialize<'de> +{ + T::deserialize(Deserializer::new(deserializer, &mut callback)) +} + +/// Deserializer adapter that invokes a callback with the path to every unused +/// field of the input. +pub struct Deserializer<'a, 'b, D, F: 'b> { + de: D, + callback: &'b mut F, + path: Path<'a>, +} + +impl<'a, 'b, D, F> Deserializer<'a, 'b, D, F> + where F: FnMut(Path) +{ + pub fn new(de: D, callback: &'b mut F) -> Self { + Deserializer { + de: de, + callback: callback, + path: Path::Root, + } + } +} + +/// Path to the current value in the input, like `dependencies.serde.typo1`. +pub enum Path<'a> { + Root, + Seq { parent: &'a Path<'a>, index: usize }, + Map { parent: &'a Path<'a>, key: String }, + Some { parent: &'a Path<'a> }, + NewtypeStruct { parent: &'a Path<'a> }, + NewtypeVariant { parent: &'a Path<'a> }, +} + +impl<'a> Display for Path<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + struct Parent<'a>(&'a Path<'a>); + + impl<'a> Display for Parent<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self.0 { + Path::Root => Ok(()), + ref path => write!(formatter, "{}.", path), + } + } + } + + match *self { + Path::Root => formatter.write_str("."), + Path::Seq { parent, index } => write!(formatter, "{}{}", Parent(parent), index), + Path::Map { parent, ref key } => write!(formatter, "{}{}", Parent(parent), key), + Path::Some { parent } | + Path::NewtypeStruct { parent } | + Path::NewtypeVariant { parent } => write!(formatter, "{}?", Parent(parent)), + } + } +} + +/// Plain old forwarding impl except for `deserialize_ignored_any` which invokes +/// the callback. +impl<'a, 'b, 'de, D, F> de::Deserializer<'de> for Deserializer<'a, 'b, D, F> + where D: de::Deserializer<'de>, + F: FnMut(Path) +{ + type Error = D::Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_any(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_bool(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_u8(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_u16(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_u32(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_u64(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_i8(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_i16(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_i32(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_i64(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_f32(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_f64(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_char(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_str(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_string(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_bytes(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_byte_buf(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_option(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_unit(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_unit_struct<V>(self, + name: &'static str, + visitor: V) + -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_unit_struct(name, Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_newtype_struct<V>(self, + name: &'static str, + visitor: V) + -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_newtype_struct(name, Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_seq(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_tuple(len, Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_tuple_struct<V>(self, + name: &'static str, + len: usize, + visitor: V) + -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_tuple_struct(name, len, Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_map(Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_struct<V>(self, + name: &'static str, + fields: &'static [&'static str], + visitor: V) + -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_struct(name, fields, Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_enum<V>(self, + name: &'static str, + variants: &'static [&'static str], + visitor: V) + -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_enum(name, + variants, + Wrap::new(visitor, self.callback, &self.path)) + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + (self.callback)(self.path); + self.de.deserialize_ignored_any(visitor) + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, D::Error> + where V: Visitor<'de> + { + self.de.deserialize_identifier(visitor) + } +} + +/// Wrapper that attaches context to a `Visitor`, `SeqAccess`, `EnumAccess` or +/// `VariantAccess`. +struct Wrap<'a, 'b, X, F: 'b> { + delegate: X, + callback: &'b mut F, + path: &'a Path<'a>, +} + +impl<'a, 'b, X, F> Wrap<'a, 'b, X, F> { + fn new(delegate: X, callback: &'b mut F, path: &'a Path<'a>) -> Self { + Wrap { + delegate: delegate, + callback: callback, + path: path, + } + } +} + +/// Forwarding impl to preserve context. +impl<'a, 'b, 'de, X, F> Visitor<'de> for Wrap<'a, 'b, X, F> + where X: Visitor<'de>, + F: FnMut(Path) +{ + type Value = X::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.delegate.expecting(formatter) + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_bool(v) + } + + fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i8(v) + } + + fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i16(v) + } + + fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i32(v) + } + + fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i64(v) + } + + fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u8(v) + } + + fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u16(v) + } + + fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u32(v) + } + + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u64(v) + } + + fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_f32(v) + } + + fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_f64(v) + } + + fn visit_char<E>(self, v: char) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_char(v) + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_str(v) + } + + fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_borrowed_str(v) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_string(v) + } + + fn visit_unit<E>(self) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_unit() + } + + fn visit_none<E>(self) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_none() + } + + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where D: de::Deserializer<'de> + { + self.delegate.visit_some(Deserializer { + de: deserializer, + callback: self.callback, + path: Path::Some { parent: self.path }, + }) + } + + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where D: de::Deserializer<'de> + { + self.delegate.visit_newtype_struct(Deserializer { + de: deserializer, + callback: self.callback, + path: Path::NewtypeStruct { parent: self.path }, + }) + } + + fn visit_seq<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::SeqAccess<'de> + { + self.delegate.visit_seq(SeqAccess::new(visitor, self.callback, self.path)) + } + + fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::MapAccess<'de> + { + self.delegate.visit_map(MapAccess::new(visitor, self.callback, self.path)) + } + + fn visit_enum<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::EnumAccess<'de> + { + self.delegate.visit_enum(Wrap::new(visitor, self.callback, self.path)) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_bytes(v) + } + + fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_borrowed_bytes(v) + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_byte_buf(v) + } +} + +/// Forwarding impl to preserve context. +impl<'a, 'b, 'de, X: 'a, F: 'b> de::EnumAccess<'de> for Wrap<'a, 'b, X, F> + where X: de::EnumAccess<'de>, + F: FnMut(Path) +{ + type Error = X::Error; + type Variant = Wrap<'a, 'b, X::Variant, F>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), X::Error> + where V: DeserializeSeed<'de> + { + let callback = self.callback; + let path = self.path; + self.delegate + .variant_seed(seed) + .map(move |(v, vis)| (v, Wrap::new(vis, callback, path))) + } +} + +/// Forwarding impl to preserve context. +impl<'a, 'b, 'de, X, F> de::VariantAccess<'de> for Wrap<'a, 'b, X, F> + where X: de::VariantAccess<'de>, + F: FnMut(Path) +{ + type Error = X::Error; + + fn unit_variant(self) -> Result<(), X::Error> { + self.delegate.unit_variant() + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, X::Error> + where T: DeserializeSeed<'de> + { + let path = Path::NewtypeVariant { parent: self.path }; + self.delegate + .newtype_variant_seed(TrackedSeed::new(seed, self.callback, path)) + } + + fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.tuple_variant(len, Wrap::new(visitor, self.callback, self.path)) + } + + fn struct_variant<V>(self, + fields: &'static [&'static str], + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.struct_variant(fields, Wrap::new(visitor, self.callback, self.path)) + } +} + +/// Seed that saves the string into the given optional during `visit_str` and +/// `visit_string`. +struct CaptureKey<'a, X> { + delegate: X, + key: &'a mut Option<String>, +} + +impl<'a, X> CaptureKey<'a, X> { + fn new(delegate: X, key: &'a mut Option<String>) -> Self { + CaptureKey { + delegate: delegate, + key: key, + } + } +} + +/// Forwarding impl. +impl<'a, 'de, X> DeserializeSeed<'de> for CaptureKey<'a, X> + where X: DeserializeSeed<'de> +{ + type Value = X::Value; + + fn deserialize<D>(self, deserializer: D) -> Result<X::Value, D::Error> + where D: de::Deserializer<'de> + { + self.delegate.deserialize(CaptureKey::new(deserializer, self.key)) + } +} + +/// Forwarding impl. +impl<'a, 'de, X> de::Deserializer<'de> for CaptureKey<'a, X> + where X: de::Deserializer<'de> +{ + type Error = X::Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_any(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_bool(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_u8(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_u16(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_u32(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_u64(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_i8(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_i16(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_i32(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_i64(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_f32(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_f64(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_char(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_str(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_string(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_bytes(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_byte_buf(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_option(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_unit(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_unit_struct<V>(self, + name: &'static str, + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_unit_struct(name, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_newtype_struct<V>(self, + name: &'static str, + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_newtype_struct(name, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_seq(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_tuple(len, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_tuple_struct<V>(self, + name: &'static str, + len: usize, + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_tuple_struct(name, len, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_map(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_struct<V>(self, + name: &'static str, + fields: &'static [&'static str], + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_struct(name, fields, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_enum<V>(self, + name: &'static str, + variants: &'static [&'static str], + visitor: V) + -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_enum(name, variants, CaptureKey::new(visitor, self.key)) + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_ignored_any(CaptureKey::new(visitor, self.key)) + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, X::Error> + where V: Visitor<'de> + { + self.delegate.deserialize_identifier(CaptureKey::new(visitor, self.key)) + } +} + +/// Forwarding impl except `visit_str` and `visit_string` which save the string. +impl<'a, 'de, X> Visitor<'de> for CaptureKey<'a, X> + where X: Visitor<'de> +{ + type Value = X::Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + self.delegate.expecting(formatter) + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_bool(v) + } + + fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i8(v) + } + + fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i16(v) + } + + fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i32(v) + } + + fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_i64(v) + } + + fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u8(v) + } + + fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u16(v) + } + + fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u32(v) + } + + fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_u64(v) + } + + fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_f32(v) + } + + fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_f64(v) + } + + fn visit_char<E>(self, v: char) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_char(v) + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where E: de::Error + { + *self.key = Some(v.to_owned()); + self.delegate.visit_str(v) + } + + fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E> + where E: de::Error + { + *self.key = Some(v.to_owned()); + self.delegate.visit_borrowed_str(v) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where E: de::Error + { + *self.key = Some(v.clone()); + self.delegate.visit_string(v) + } + + fn visit_unit<E>(self) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_unit() + } + + fn visit_none<E>(self) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_none() + } + + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where D: de::Deserializer<'de> + { + self.delegate.visit_some(deserializer) + } + + fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where D: de::Deserializer<'de> + { + self.delegate.visit_newtype_struct(deserializer) + } + + fn visit_seq<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::SeqAccess<'de> + { + self.delegate.visit_seq(visitor) + } + + fn visit_map<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::MapAccess<'de> + { + self.delegate.visit_map(visitor) + } + + fn visit_enum<V>(self, visitor: V) -> Result<Self::Value, V::Error> + where V: de::EnumAccess<'de> + { + self.delegate.visit_enum(visitor) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_bytes(v) + } + + fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_borrowed_bytes(v) + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where E: de::Error + { + self.delegate.visit_byte_buf(v) + } +} + +/// Seed used for map values, sequence elements and newtype variants to track +/// their path. +struct TrackedSeed<'a, X, F: 'a> { + seed: X, + callback: &'a mut F, + path: Path<'a>, +} + +impl<'a, X, F> TrackedSeed<'a, X, F> { + fn new(seed: X, callback: &'a mut F, path: Path<'a>) -> Self { + TrackedSeed { + seed: seed, + callback: callback, + path: path, + } + } +} + +impl<'a, 'de, X, F> DeserializeSeed<'de> for TrackedSeed<'a, X, F> + where X: DeserializeSeed<'de>, + F: FnMut(Path) +{ + type Value = X::Value; + + fn deserialize<D>(self, deserializer: D) -> Result<X::Value, D::Error> + where D: de::Deserializer<'de> + { + self.seed.deserialize(Deserializer { + de: deserializer, + callback: self.callback, + path: self.path, + }) + } +} + +/// Seq visitor that tracks the index of its elements. +struct SeqAccess<'a, 'b, X, F: 'b> { + delegate: X, + callback: &'b mut F, + path: &'a Path<'a>, + index: usize, +} + +impl<'a, 'b, X, F> SeqAccess<'a, 'b, X, F> { + fn new(delegate: X, callback: &'b mut F, path: &'a Path<'a>) -> Self { + SeqAccess { + delegate: delegate, + callback: callback, + path: path, + index: 0, + } + } +} + +/// Forwarding impl to preserve context. +impl<'a, 'b, 'de, X, F> de::SeqAccess<'de> for SeqAccess<'a, 'b, X, F> + where X: de::SeqAccess<'de>, + F: FnMut(Path) +{ + type Error = X::Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, X::Error> + where T: DeserializeSeed<'de> + { + let path = Path::Seq { + parent: self.path, + index: self.index, + }; + self.index += 1; + self.delegate.next_element_seed(TrackedSeed::new(seed, self.callback, path)) + } + + fn size_hint(&self) -> Option<usize> { + self.delegate.size_hint() + } +} + +/// Map visitor that captures the string value of its keys and uses that to +/// track the path to its values. +struct MapAccess<'a, 'b, X, F: 'b> { + delegate: X, + callback: &'b mut F, + path: &'a Path<'a>, + key: Option<String>, +} + +impl<'a, 'b, X, F> MapAccess<'a, 'b, X, F> { + fn new(delegate: X, callback: &'b mut F, path: &'a Path<'a>) -> Self { + MapAccess { + delegate: delegate, + callback: callback, + path: path, + key: None, + } + } + + fn key<E>(&mut self) -> Result<String, E> + where E: de::Error + { + self.key.take().ok_or_else(|| E::custom("non-string key")) + } +} + +impl<'a, 'b, 'de, X, F> de::MapAccess<'de> for MapAccess<'a, 'b, X, F> + where X: de::MapAccess<'de>, + F: FnMut(Path) +{ + type Error = X::Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, X::Error> + where K: DeserializeSeed<'de> + { + self.delegate.next_key_seed(CaptureKey::new(seed, &mut self.key)) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, X::Error> + where V: DeserializeSeed<'de> + { + let path = Path::Map { + parent: self.path, + key: self.key()?, + }; + self.delegate.next_value_seed(TrackedSeed::new(seed, self.callback, path)) + } + + fn size_hint(&self) -> Option<usize> { + self.delegate.size_hint() + } +} diff --git a/serde_json/.cargo-checksum.json b/serde_json/.cargo-checksum.json new file mode 100644 index 000000000..3453f311f --- /dev/null +++ b/serde_json/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"} \ No newline at end of file diff --git a/serde_json/Cargo.toml b/serde_json/Cargo.toml new file mode 100644 index 000000000..6a39a9810 --- /dev/null +++ b/serde_json/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "serde_json" +version = "1.0.39" +authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] +include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] +description = "A JSON serialization file format" +documentation = "http://docs.serde.rs/serde_json/" +readme = "README.md" +keywords = ["json", "serde", "serialization"] +categories = ["encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/serde-rs/json" +[package.metadata.docs.rs] +features = ["raw_value", "unbounded_depth"] + +[package.metadata.playground] +features = ["raw_value"] +[dependencies.indexmap] +version = "1.0" +optional = true + +[dependencies.itoa] +version = "0.4.3" + +[dependencies.ryu] +version = "0.2" + +[dependencies.serde] +version = "1.0.60" +[dev-dependencies.automod] +version = "0.1" + +[dev-dependencies.compiletest_rs] +version = "0.3" +features = ["stable"] + +[dev-dependencies.serde_bytes] +version = "0.10" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.serde_stacker] +version = "0.1" + +[features] +arbitrary_precision = [] +default = [] +preserve_order = ["indexmap"] +raw_value = [] +unbounded_depth = [] +[badges.appveyor] +repository = "serde-rs/json" + +[badges.travis-ci] +repository = "serde-rs/json" diff --git a/serde_json/LICENSE-APACHE b/serde_json/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/serde_json/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/serde_json/LICENSE-MIT b/serde_json/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/serde_json/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/serde_json/README.md b/serde_json/README.md new file mode 100644 index 000000000..7ca22e464 --- /dev/null +++ b/serde_json/README.md @@ -0,0 +1,354 @@ +# Serde JSON   [![Build Status]][travis] [![Latest Version]][crates.io] [![Rustc Version 1.15+]][rustc] + +[Build Status]: https://api.travis-ci.org/serde-rs/json.svg?branch=master +[travis]: https://travis-ci.org/serde-rs/json +[Latest Version]: https://img.shields.io/crates/v/serde_json.svg +[crates.io]: https://crates.io/crates/serde\_json +[Rustc Version 1.15+]: https://img.shields.io/badge/rustc-1.15+-lightgray.svg +[rustc]: https://blog.rust-lang.org/2017/02/02/Rust-1.15.html + +**Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** + +--- + +```toml +[dependencies] +serde_json = "1.0" +``` + +You may be looking for: + +- [JSON API documentation](https://docs.serde.rs/serde_json/) +- [Serde API documentation](https://docs.serde.rs/serde/) +- [Detailed documentation about Serde](https://serde.rs/) +- [Setting up `#[derive(Serialize, Deserialize)]`](https://serde.rs/codegen.html) +- [Release notes](https://github.com/serde-rs/json/releases) + +JSON is a ubiquitous open-standard format that uses human-readable text to +transmit data objects consisting of key-value pairs. + +```json +{ + "name": "John Doe", + "age": 43, + "address": { + "street": "10 Downing Street", + "city": "London" + }, + "phones": [ + "+44 1234567", + "+44 2345678" + ] +} +``` + +There are three common ways that you might find yourself needing to work +with JSON data in Rust. + + - **As text data.** An unprocessed string of JSON data that you receive on + an HTTP endpoint, read from a file, or prepare to send to a remote + server. + - **As an untyped or loosely typed representation.** Maybe you want to + check that some JSON data is valid before passing it on, but without + knowing the structure of what it contains. Or you want to do very basic + manipulations like insert a key in a particular spot. + - **As a strongly typed Rust data structure.** When you expect all or most + of your data to conform to a particular structure and want to get real + work done without JSON's loosey-goosey nature tripping you up. + +Serde JSON provides efficient, flexible, safe ways of converting data +between each of these representations. + +## Operating on untyped JSON values + +Any valid JSON data can be manipulated in the following recursive enum +representation. This data structure is [`serde_json::Value`][value]. + +```rust +enum Value { + Null, + Bool(bool), + Number(Number), + String(String), + Array(Vec<Value>), + Object(Map<String, Value>), +} +``` + +A string of JSON data can be parsed into a `serde_json::Value` by the +[`serde_json::from_str`][from_str] function. There is also +[`from_slice`][from_slice] for parsing from a byte slice &[u8] and +[`from_reader`][from_reader] for parsing from any `io::Read` like a File or +a TCP stream. + +<a href="https://play.rust-lang.org/?edition=2018&gist=d69d8e3156d4bb81c4461b60b772ab72" target="_blank"> +<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png"> +</a> + +```rust +use serde_json::{Result, Value}; + +fn untyped_example() -> Result<()> { + // Some JSON input data as a &str. Maybe this comes from the user. + let data = r#" + { + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }"#; + + // Parse the string of data into serde_json::Value. + let v: Value = serde_json::from_str(data)?; + + // Access parts of the data by indexing with square brackets. + println!("Please call {} at the number {}", v["name"], v["phones"][0]); + + Ok(()) +} +``` + +The result of square bracket indexing like `v["name"]` is a borrow of the data +at that index, so the type is `&Value`. A JSON map can be indexed with string +keys, while a JSON array can be indexed with integer keys. If the type of the +data is not right for the type with which it is being indexed, or if a map does +not contain the key being indexed, or if the index into a vector is out of +bounds, the returned element is `Value::Null`. + +When a `Value` is printed, it is printed as a JSON string. So in the code above, +the output looks like `Please call "John Doe" at the number "+44 1234567"`. The +quotation marks appear because `v["name"]` is a `&Value` containing a JSON +string and its JSON representation is `"John Doe"`. Printing as a plain string +without quotation marks involves converting from a JSON string to a Rust string +with [`as_str()`] or avoiding the use of `Value` as described in the following +section. + +[`as_str()`]: https://docs.serde.rs/serde_json/enum.Value.html#method.as_str + +The `Value` representation is sufficient for very basic tasks but can be tedious +to work with for anything more significant. Error handling is verbose to +implement correctly, for example imagine trying to detect the presence of +unrecognized fields in the input data. The compiler is powerless to help you +when you make a mistake, for example imagine typoing `v["name"]` as `v["nmae"]` +in one of the dozens of places it is used in your code. + +## Parsing JSON as strongly typed data structures + +Serde provides a powerful way of mapping JSON data into Rust data structures +largely automatically. + +<a href="https://play.rust-lang.org/?edition=2018&gist=15cfab66d38ff8a15a9cf1d8d897ac68" target="_blank"> +<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png"> +</a> + +```rust +use serde::{Deserialize, Serialize}; +use serde_json::Result; + +#[derive(Serialize, Deserialize)] +struct Person { + name: String, + age: u8, + phones: Vec<String>, +} + +fn typed_example() -> Result<()> { + // Some JSON input data as a &str. Maybe this comes from the user. + let data = r#" + { + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }"#; + + // Parse the string of data into a Person object. This is exactly the + // same function as the one that produced serde_json::Value above, but + // now we are asking it for a Person as output. + let p: Person = serde_json::from_str(data)?; + + // Do things just like with any other Rust data structure. + println!("Please call {} at the number {}", p.name, p.phones[0]); + + Ok(()) +} +``` + +This is the same `serde_json::from_str` function as before, but this time we +assign the return value to a variable of type `Person` so Serde will +automatically interpret the input data as a `Person` and produce informative +error messages if the layout does not conform to what a `Person` is expected +to look like. + +Any type that implements Serde's `Deserialize` trait can be deserialized +this way. This includes built-in Rust standard library types like `Vec<T>` +and `HashMap<K, V>`, as well as any structs or enums annotated with +`#[derive(Deserialize)]`. + +Once we have `p` of type `Person`, our IDE and the Rust compiler can help us +use it correctly like they do for any other Rust code. The IDE can +autocomplete field names to prevent typos, which was impossible in the +`serde_json::Value` representation. And the Rust compiler can check that +when we write `p.phones[0]`, then `p.phones` is guaranteed to be a +`Vec<String>` so indexing into it makes sense and produces a `String`. + +## Constructing JSON values + +Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +objects with very natural JSON syntax. In order to use this macro, +`serde_json` needs to be imported with the `#[macro_use]` attribute. + +<a href="https://play.rust-lang.org/?edition=2018&gist=6ccafad431d72b62e77cc34c8e879b24" target="_blank"> +<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png"> +</a> + +```rust +use serde_json::json; + +fn main() { + // The type of `john` is `serde_json::Value` + let john = json!({ + "name": "John Doe", + "age": 43, + "phones": [ + "+44 1234567", + "+44 2345678" + ] + }); + + println!("first phone number: {}", john["phones"][0]); + + // Convert to a string of JSON and print it out + println!("{}", john.to_string()); +} +``` + +The `Value::to_string()` function converts a `serde_json::Value` into a +`String` of JSON text. + +One neat thing about the `json!` macro is that variables and expressions can +be interpolated directly into the JSON value as you are building it. Serde +will check at compile time that the value you are interpolating is able to +be represented as JSON. + +<a href="https://play.rust-lang.org/?edition=2018&gist=f9101a6e61dfc9e02c6a67f315ed24f2" target="_blank"> +<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png"> +</a> + +```rust +let full_name = "John Doe"; +let age_last_year = 42; + +// The type of `john` is `serde_json::Value` +let john = json!({ + "name": full_name, + "age": age_last_year + 1, + "phones": [ + format!("+44 {}", random_phone()) + ] +}); +``` + +This is amazingly convenient but we have the problem we had before with +`Value` which is that the IDE and Rust compiler cannot help us if we get it +wrong. Serde JSON provides a better way of serializing strongly-typed data +structures into JSON text. + +## Creating JSON by serializing data structures + +A data structure can be converted to a JSON string by +[`serde_json::to_string`][to_string]. There is also +[`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and +[`serde_json::to_writer`][to_writer] which serializes to any `io::Write` +such as a File or a TCP stream. + +<a href="https://play.rust-lang.org/?edition=2018&gist=3472242a08ed2ff88a944f2a2283b0ee" target="_blank"> +<img align="right" width="50" src="https://raw.githubusercontent.com/serde-rs/serde-rs.github.io/master/img/run.png"> +</a> + +```rust +use serde::{Deserialize, Serialize}; +use serde_json::Result; + +#[derive(Serialize, Deserialize)] +struct Address { + street: String, + city: String, +} + +fn print_an_address() -> Result<()> { + // Some data structure. + let address = Address { + street: "10 Downing Street".to_owned(), + city: "London".to_owned(), + }; + + // Serialize it to a JSON string. + let j = serde_json::to_string(&address)?; + + // Print, write to a file, or send to an HTTP server. + println!("{}", j); + + Ok(()) +} +``` + +Any type that implements Serde's `Serialize` trait can be serialized this +way. This includes built-in Rust standard library types like `Vec<T>` and +`HashMap<K, V>`, as well as any structs or enums annotated with +`#[derive(Serialize)]`. + +## Performance + +It is fast. You should expect in the ballpark of 500 to 1000 megabytes per +second deserialization and 600 to 900 megabytes per second serialization, +depending on the characteristics of your data. This is competitive with the +fastest C and C++ JSON libraries or even 30% faster for many use cases. +Benchmarks live in the [serde-rs/json-benchmark] repo. + +[serde-rs/json-benchmark]: https://github.com/serde-rs/json-benchmark + +## Getting help + +Serde developers live in the #serde channel on +[`irc.mozilla.org`](https://wiki.mozilla.org/IRC). The #rust channel is also a +good resource with generally faster response time but less specific knowledge +about Serde. If IRC is not your thing, we are happy to respond to [GitHub +issues](https://github.com/serde-rs/json/issues/new) as well. + +## No-std support + +This crate currently requires the Rust standard library. For JSON support in +Serde without a standard library, please see the [`serde-json-core`] crate. + +[`serde-json-core`]: https://japaric.github.io/serde-json-core/serde_json_core/ + +## License + +Serde JSON is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde JSON by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + +[value]: https://docs.serde.rs/serde_json/value/enum.Value.html +[from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html +[from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html +[from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html +[to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html +[to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html +[to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html +[macro]: https://docs.serde.rs/serde_json/macro.json.html diff --git a/serde_json/src/de.rs b/serde_json/src/de.rs new file mode 100644 index 000000000..e3effc365 --- /dev/null +++ b/serde_json/src/de.rs @@ -0,0 +1,2317 @@ +//! Deserialize JSON data to a Rust data structure. + +use std::io; +use std::marker::PhantomData; +use std::result; +use std::str::FromStr; +use std::{i32, u64}; + +use serde::de::{self, Expected, Unexpected}; + +use super::error::{Error, ErrorCode, Result}; + +use read::{self, Reference}; + +pub use read::{IoRead, Read, SliceRead, StrRead}; + +use number::Number; +#[cfg(feature = "arbitrary_precision")] +use number::NumberDeserializer; + +////////////////////////////////////////////////////////////////////////////// + +/// A structure that deserializes JSON into Rust values. +pub struct Deserializer<R> { + read: R, + scratch: Vec<u8>, + remaining_depth: u8, + #[cfg(feature = "unbounded_depth")] + disable_recursion_limit: bool, +} + +impl<'de, R> Deserializer<R> +where + R: read::Read<'de>, +{ + /// Create a JSON deserializer from one of the possible serde_json input + /// sources. + /// + /// Typically it is more convenient to use one of these methods instead: + /// + /// - Deserializer::from_str + /// - Deserializer::from_bytes + /// - Deserializer::from_reader + pub fn new(read: R) -> Self { + #[cfg(not(feature = "unbounded_depth"))] + { + Deserializer { + read: read, + scratch: Vec::new(), + remaining_depth: 128, + } + } + + #[cfg(feature = "unbounded_depth")] + { + Deserializer { + read: read, + scratch: Vec::new(), + remaining_depth: 128, + disable_recursion_limit: false, + } + } + } +} + +impl<R> Deserializer<read::IoRead<R>> +where + R: io::Read, +{ + /// Creates a JSON deserializer from an `io::Read`. + pub fn from_reader(reader: R) -> Self { + Deserializer::new(read::IoRead::new(reader)) + } +} + +impl<'a> Deserializer<read::SliceRead<'a>> { + /// Creates a JSON deserializer from a `&[u8]`. + pub fn from_slice(bytes: &'a [u8]) -> Self { + Deserializer::new(read::SliceRead::new(bytes)) + } +} + +impl<'a> Deserializer<read::StrRead<'a>> { + /// Creates a JSON deserializer from a `&str`. + pub fn from_str(s: &'a str) -> Self { + Deserializer::new(read::StrRead::new(s)) + } +} + +macro_rules! overflow { + ($a:ident * 10 + $b:ident, $c:expr) => { + $a >= $c / 10 && ($a > $c / 10 || $b > $c % 10) + }; +} + +// Not public API. Should be pub(crate). +#[doc(hidden)] +pub enum ParserNumber { + F64(f64), + U64(u64), + I64(i64), + #[cfg(feature = "arbitrary_precision")] + String(String), +} + +impl ParserNumber { + fn visit<'de, V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match self { + ParserNumber::F64(x) => visitor.visit_f64(x), + ParserNumber::U64(x) => visitor.visit_u64(x), + ParserNumber::I64(x) => visitor.visit_i64(x), + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(x) => visitor.visit_map(NumberDeserializer { number: x.into() }), + } + } + + fn invalid_type(self, exp: &Expected) -> Error { + match self { + ParserNumber::F64(x) => de::Error::invalid_type(Unexpected::Float(x), exp), + ParserNumber::U64(x) => de::Error::invalid_type(Unexpected::Unsigned(x), exp), + ParserNumber::I64(x) => de::Error::invalid_type(Unexpected::Signed(x), exp), + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(_) => de::Error::invalid_type(Unexpected::Other("number"), exp), + } + } +} + +impl<'de, R: Read<'de>> Deserializer<R> { + /// The `Deserializer::end` method should be called after a value has been fully deserialized. + /// This allows the `Deserializer` to validate that the input stream is at the end or that it + /// only has trailing whitespace. + pub fn end(&mut self) -> Result<()> { + match try!(self.parse_whitespace()) { + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Ok(()), + } + } + + /// Turn a JSON deserializer into an iterator over values of type T. + pub fn into_iter<T>(self) -> StreamDeserializer<'de, R, T> + where + T: de::Deserialize<'de>, + { + // This cannot be an implementation of std::iter::IntoIterator because + // we need the caller to choose what T is. + let offset = self.read.byte_offset(); + StreamDeserializer { + de: self, + offset: offset, + output: PhantomData, + lifetime: PhantomData, + } + } + + /// Parse arbitrarily deep JSON structures without any consideration for + /// overflowing the stack. + /// + /// You will want to provide some other way to protect against stack + /// overflows, such as by wrapping your Deserializer in the dynamically + /// growing stack adapter provided by the serde_stacker crate. Additionally + /// you will need to be careful around other recursive operations on the + /// parsed result which may overflow the stack after deserialization has + /// completed, including, but not limited to, Display and Debug and Drop + /// impls. + /// + /// *This method is only available if serde_json is built with the + /// `"unbounded_depth"` feature.* + /// + /// # Examples + /// + /// ```edition2018 + /// use serde::Deserialize; + /// use serde_json::Value; + /// + /// fn main() { + /// let mut json = String::new(); + /// for _ in 0..10000 { + /// json = format!("[{}]", json); + /// } + /// + /// let mut deserializer = serde_json::Deserializer::from_str(&json); + /// deserializer.disable_recursion_limit(); + /// let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + /// let value = Value::deserialize(deserializer).unwrap(); + /// + /// carefully_drop_nested_arrays(value); + /// } + /// + /// fn carefully_drop_nested_arrays(value: Value) { + /// let mut stack = vec![value]; + /// while let Some(value) = stack.pop() { + /// if let Value::Array(array) = value { + /// stack.extend(array); + /// } + /// } + /// } + /// ``` + #[cfg(feature = "unbounded_depth")] + pub fn disable_recursion_limit(&mut self) { + self.disable_recursion_limit = true; + } + + fn peek(&mut self) -> Result<Option<u8>> { + self.read.peek() + } + + fn peek_or_null(&mut self) -> Result<u8> { + Ok(try!(self.peek()).unwrap_or(b'\x00')) + } + + fn eat_char(&mut self) { + self.read.discard(); + } + + fn next_char(&mut self) -> Result<Option<u8>> { + self.read.next() + } + + fn next_char_or_null(&mut self) -> Result<u8> { + Ok(try!(self.next_char()).unwrap_or(b'\x00')) + } + + /// Error caused by a byte from next_char(). + #[cold] + fn error(&self, reason: ErrorCode) -> Error { + let position = self.read.position(); + Error::syntax(reason, position.line, position.column) + } + + /// Error caused by a byte from peek(). + #[cold] + fn peek_error(&self, reason: ErrorCode) -> Error { + let position = self.read.peek_position(); + Error::syntax(reason, position.line, position.column) + } + + /// Returns the first non-whitespace byte without consuming it, or `None` if + /// EOF is encountered. + fn parse_whitespace(&mut self) -> Result<Option<u8>> { + loop { + match try!(self.peek()) { + Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') => { + self.eat_char(); + } + other => { + return Ok(other); + } + } + } + } + + #[cold] + fn peek_invalid_type(&mut self, exp: &Expected) -> Error { + let err = match self.peek_or_null().unwrap_or(b'\x00') { + b'n' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"ull") { + return err; + } + de::Error::invalid_type(Unexpected::Unit, exp) + } + b't' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"rue") { + return err; + } + de::Error::invalid_type(Unexpected::Bool(true), exp) + } + b'f' => { + self.eat_char(); + if let Err(err) = self.parse_ident(b"alse") { + return err; + } + de::Error::invalid_type(Unexpected::Bool(false), exp) + } + b'-' => { + self.eat_char(); + match self.parse_any_number(false) { + Ok(n) => n.invalid_type(exp), + Err(err) => return err, + } + } + b'0'...b'9' => match self.parse_any_number(true) { + Ok(n) => n.invalid_type(exp), + Err(err) => return err, + }, + b'"' => { + self.eat_char(); + self.scratch.clear(); + match self.read.parse_str(&mut self.scratch) { + Ok(s) => de::Error::invalid_type(Unexpected::Str(&s), exp), + Err(err) => return err, + } + } + b'[' => de::Error::invalid_type(Unexpected::Seq, exp), + b'{' => de::Error::invalid_type(Unexpected::Map, exp), + _ => self.peek_error(ErrorCode::ExpectedSomeValue), + }; + + self.fix_position(err) + } + + fn deserialize_prim_number<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'-' => { + self.eat_char(); + try!(self.parse_integer(false)).visit(visitor) + } + b'0'...b'9' => try!(self.parse_integer(true)).visit(visitor), + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + serde_if_integer128! { + fn scan_integer128(&mut self, buf: &mut String) -> Result<()> { + match try!(self.next_char_or_null()) { + b'0' => { + buf.push('0'); + // There can be only one leading '0'. + match try!(self.peek_or_null()) { + b'0'...b'9' => { + Err(self.peek_error(ErrorCode::InvalidNumber)) + } + _ => Ok(()), + } + } + c @ b'1'...b'9' => { + buf.push(c as char); + while let c @ b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + } + Ok(()) + } + _ => { + Err(self.error(ErrorCode::InvalidNumber)) + } + } + } + } + + #[cold] + fn fix_position(&self, err: Error) -> Error { + err.fix_position(move |code| self.error(code)) + } + + fn parse_ident(&mut self, ident: &[u8]) -> Result<()> { + for expected in ident { + match try!(self.next_char()) { + None => { + return Err(self.error(ErrorCode::EofWhileParsingValue)); + } + Some(next) => { + if next != *expected { + return Err(self.error(ErrorCode::ExpectedSomeIdent)); + } + } + } + } + + Ok(()) + } + + fn parse_integer(&mut self, positive: bool) -> Result<ParserNumber> { + match try!(self.next_char_or_null()) { + b'0' => { + // There can be only one leading '0'. + match try!(self.peek_or_null()) { + b'0'...b'9' => Err(self.peek_error(ErrorCode::InvalidNumber)), + _ => self.parse_number(positive, 0), + } + } + c @ b'1'...b'9' => { + let mut res = (c - b'0') as u64; + + loop { + match try!(self.peek_or_null()) { + c @ b'0'...b'9' => { + self.eat_char(); + let digit = (c - b'0') as u64; + + // We need to be careful with overflow. If we can, try to keep the + // number as a `u64` until we grow too large. At that point, switch to + // parsing the value as a `f64`. + if overflow!(res * 10 + digit, u64::max_value()) { + return Ok(ParserNumber::F64(try!(self.parse_long_integer( + positive, + res, + 1, // res * 10^1 + )))); + } + + res = res * 10 + digit; + } + _ => { + return self.parse_number(positive, res); + } + } + } + } + _ => Err(self.error(ErrorCode::InvalidNumber)), + } + } + + fn parse_long_integer( + &mut self, + positive: bool, + significand: u64, + mut exponent: i32, + ) -> Result<f64> { + loop { + match try!(self.peek_or_null()) { + b'0'...b'9' => { + self.eat_char(); + // This could overflow... if your integer is gigabytes long. + // Ignore that possibility. + exponent += 1; + } + b'.' => { + return self.parse_decimal(positive, significand, exponent); + } + b'e' | b'E' => { + return self.parse_exponent(positive, significand, exponent); + } + _ => { + return self.f64_from_parts(positive, significand, exponent); + } + } + } + } + + fn parse_number(&mut self, positive: bool, significand: u64) -> Result<ParserNumber> { + Ok(match try!(self.peek_or_null()) { + b'.' => ParserNumber::F64(try!(self.parse_decimal(positive, significand, 0))), + b'e' | b'E' => ParserNumber::F64(try!(self.parse_exponent(positive, significand, 0))), + _ => { + if positive { + ParserNumber::U64(significand) + } else { + let neg = (significand as i64).wrapping_neg(); + + // Convert into a float if we underflow. + if neg > 0 { + ParserNumber::F64(-(significand as f64)) + } else { + ParserNumber::I64(neg) + } + } + } + }) + } + + fn parse_decimal( + &mut self, + positive: bool, + mut significand: u64, + mut exponent: i32, + ) -> Result<f64> { + self.eat_char(); + + let mut at_least_one_digit = false; + while let c @ b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + let digit = (c - b'0') as u64; + at_least_one_digit = true; + + if overflow!(significand * 10 + digit, u64::max_value()) { + // The next multiply/add would overflow, so just ignore all + // further digits. + while let b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + } + break; + } + + significand = significand * 10 + digit; + exponent -= 1; + } + + if !at_least_one_digit { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + + match try!(self.peek_or_null()) { + b'e' | b'E' => self.parse_exponent(positive, significand, exponent), + _ => self.f64_from_parts(positive, significand, exponent), + } + } + + fn parse_exponent( + &mut self, + positive: bool, + significand: u64, + starting_exp: i32, + ) -> Result<f64> { + self.eat_char(); + + let positive_exp = match try!(self.peek_or_null()) { + b'+' => { + self.eat_char(); + true + } + b'-' => { + self.eat_char(); + false + } + _ => true, + }; + + // Make sure a digit follows the exponent place. + let mut exp = match try!(self.next_char_or_null()) { + c @ b'0'...b'9' => (c - b'0') as i32, + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + }; + + while let c @ b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + let digit = (c - b'0') as i32; + + if overflow!(exp * 10 + digit, i32::max_value()) { + return self.parse_exponent_overflow(positive, significand, positive_exp); + } + + exp = exp * 10 + digit; + } + + let final_exp = if positive_exp { + starting_exp.saturating_add(exp) + } else { + starting_exp.saturating_sub(exp) + }; + + self.f64_from_parts(positive, significand, final_exp) + } + + // This cold code should not be inlined into the middle of the hot + // exponent-parsing loop above. + #[cold] + #[inline(never)] + fn parse_exponent_overflow( + &mut self, + positive: bool, + significand: u64, + positive_exp: bool, + ) -> Result<f64> { + // Error instead of +/- infinity. + if significand != 0 && positive_exp { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + + while let b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + } + Ok(if positive { 0.0 } else { -0.0 }) + } + + fn parse_any_signed_number(&mut self) -> Result<ParserNumber> { + let peek = match try!(self.peek()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'-' => { + self.eat_char(); + self.parse_any_number(false) + } + b'0'...b'9' => self.parse_any_number(true), + _ => Err(self.peek_error(ErrorCode::InvalidNumber)), + }; + + let value = match try!(self.peek()) { + Some(_) => Err(self.peek_error(ErrorCode::InvalidNumber)), + None => value, + }; + + match value { + Ok(value) => Ok(value), + // The de::Error impl creates errors with unknown line and column. + // Fill in the position here by looking at the current index in the + // input. There is no way to tell whether this should call `error` + // or `peek_error` so pick the one that seems correct more often. + // Worst case, the position is off by one character. + Err(err) => Err(self.fix_position(err)), + } + } + + #[cfg(not(feature = "arbitrary_precision"))] + fn parse_any_number(&mut self, positive: bool) -> Result<ParserNumber> { + self.parse_integer(positive) + } + + #[cfg(feature = "arbitrary_precision")] + fn parse_any_number(&mut self, positive: bool) -> Result<ParserNumber> { + let mut buf = String::with_capacity(16); + if !positive { + buf.push('-'); + } + self.scan_integer(&mut buf)?; + Ok(ParserNumber::String(buf)) + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_or_null(&mut self, buf: &mut String) -> Result<u8> { + match try!(self.next_char()) { + Some(b) => { + buf.push(b as char); + Ok(b) + } + None => Ok(b'\x00'), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_integer(&mut self, buf: &mut String) -> Result<()> { + match try!(self.scan_or_null(buf)) { + b'0' => { + // There can be only one leading '0'. + match try!(self.peek_or_null()) { + b'0'...b'9' => Err(self.peek_error(ErrorCode::InvalidNumber)), + _ => self.scan_number(buf), + } + } + b'1'...b'9' => loop { + match try!(self.peek_or_null()) { + c @ b'0'...b'9' => { + self.eat_char(); + buf.push(c as char); + } + _ => { + return self.scan_number(buf); + } + } + }, + _ => Err(self.error(ErrorCode::InvalidNumber)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_number(&mut self, buf: &mut String) -> Result<()> { + match try!(self.peek_or_null()) { + b'.' => self.scan_decimal(buf), + b'e' | b'E' => self.scan_exponent(buf), + _ => Ok(()), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_decimal(&mut self, buf: &mut String) -> Result<()> { + self.eat_char(); + buf.push('.'); + + let mut at_least_one_digit = false; + while let c @ b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + at_least_one_digit = true; + } + + if !at_least_one_digit { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + + match try!(self.peek_or_null()) { + b'e' | b'E' => self.scan_exponent(buf), + _ => Ok(()), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn scan_exponent(&mut self, buf: &mut String) -> Result<()> { + self.eat_char(); + buf.push('e'); + + match try!(self.peek_or_null()) { + b'+' => { + self.eat_char(); + } + b'-' => { + self.eat_char(); + buf.push('-'); + } + _ => {} + } + + // Make sure a digit follows the exponent place. + match try!(self.scan_or_null(buf)) { + b'0'...b'9' => {} + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + while let c @ b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + buf.push(c as char); + } + + Ok(()) + } + + fn f64_from_parts( + &mut self, + positive: bool, + significand: u64, + mut exponent: i32, + ) -> Result<f64> { + let mut f = significand as f64; + loop { + match POW10.get(exponent.wrapping_abs() as usize) { + Some(&pow) => { + if exponent >= 0 { + f *= pow; + if f.is_infinite() { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + } else { + f /= pow; + } + break; + } + None => { + if f == 0.0 { + break; + } + if exponent >= 0 { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + f /= 1e308; + exponent += 308; + } + } + } + Ok(if positive { f } else { -f }) + } + + fn parse_object_colon(&mut self) -> Result<()> { + match try!(self.parse_whitespace()) { + Some(b':') => { + self.eat_char(); + Ok(()) + } + Some(_) => Err(self.peek_error(ErrorCode::ExpectedColon)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + fn end_seq(&mut self) -> Result<()> { + match try!(self.parse_whitespace()) { + Some(b']') => { + self.eat_char(); + Ok(()) + } + Some(b',') => { + self.eat_char(); + match self.parse_whitespace() { + Ok(Some(b']')) => Err(self.peek_error(ErrorCode::TrailingComma)), + _ => Err(self.peek_error(ErrorCode::TrailingCharacters)), + } + } + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingList)), + } + } + + fn end_map(&mut self) -> Result<()> { + match try!(self.parse_whitespace()) { + Some(b'}') => { + self.eat_char(); + Ok(()) + } + Some(b',') => Err(self.peek_error(ErrorCode::TrailingComma)), + Some(_) => Err(self.peek_error(ErrorCode::TrailingCharacters)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + fn ignore_value(&mut self) -> Result<()> { + self.scratch.clear(); + let mut enclosing = None; + + loop { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let frame = match peek { + b'n' => { + self.eat_char(); + try!(self.parse_ident(b"ull")); + None + } + b't' => { + self.eat_char(); + try!(self.parse_ident(b"rue")); + None + } + b'f' => { + self.eat_char(); + try!(self.parse_ident(b"alse")); + None + } + b'-' => { + self.eat_char(); + try!(self.ignore_integer()); + None + } + b'0'...b'9' => { + try!(self.ignore_integer()); + None + } + b'"' => { + self.eat_char(); + try!(self.read.ignore_str()); + None + } + frame @ b'[' | frame @ b'{' => { + self.scratch.extend(enclosing.take()); + self.eat_char(); + Some(frame) + } + _ => return Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + }; + + let (mut accept_comma, mut frame) = match frame { + Some(frame) => (false, frame), + None => match enclosing.take() { + Some(frame) => (true, frame), + None => match self.scratch.pop() { + Some(frame) => (true, frame), + None => return Ok(()), + }, + }, + }; + + loop { + match try!(self.parse_whitespace()) { + Some(b',') if accept_comma => { + self.eat_char(); + break; + } + Some(b']') if frame == b'[' => {} + Some(b'}') if frame == b'{' => {} + Some(_) => { + if accept_comma { + return Err(self.peek_error(match frame { + b'[' => ErrorCode::ExpectedListCommaOrEnd, + b'{' => ErrorCode::ExpectedObjectCommaOrEnd, + _ => unreachable!(), + })); + } else { + break; + } + } + None => { + return Err(self.peek_error(match frame { + b'[' => ErrorCode::EofWhileParsingList, + b'{' => ErrorCode::EofWhileParsingObject, + _ => unreachable!(), + })); + } + } + + self.eat_char(); + frame = match self.scratch.pop() { + Some(frame) => frame, + None => return Ok(()), + }; + accept_comma = true; + } + + if frame == b'{' { + match try!(self.parse_whitespace()) { + Some(b'"') => self.eat_char(), + Some(_) => return Err(self.peek_error(ErrorCode::KeyMustBeAString)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + try!(self.read.ignore_str()); + match try!(self.parse_whitespace()) { + Some(b':') => self.eat_char(), + Some(_) => return Err(self.peek_error(ErrorCode::ExpectedColon)), + None => return Err(self.peek_error(ErrorCode::EofWhileParsingObject)), + } + } + + enclosing = Some(frame); + } + } + + fn ignore_integer(&mut self) -> Result<()> { + match try!(self.next_char_or_null()) { + b'0' => { + // There can be only one leading '0'. + if let b'0'...b'9' = try!(self.peek_or_null()) { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + } + b'1'...b'9' => { + while let b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + } + } + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + match try!(self.peek_or_null()) { + b'.' => self.ignore_decimal(), + b'e' | b'E' => self.ignore_exponent(), + _ => Ok(()), + } + } + + fn ignore_decimal(&mut self) -> Result<()> { + self.eat_char(); + + let mut at_least_one_digit = false; + while let b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + at_least_one_digit = true; + } + + if !at_least_one_digit { + return Err(self.peek_error(ErrorCode::InvalidNumber)); + } + + match try!(self.peek_or_null()) { + b'e' | b'E' => self.ignore_exponent(), + _ => Ok(()), + } + } + + fn ignore_exponent(&mut self) -> Result<()> { + self.eat_char(); + + match try!(self.peek_or_null()) { + b'+' | b'-' => self.eat_char(), + _ => {} + } + + // Make sure a digit follows the exponent place. + match try!(self.next_char_or_null()) { + b'0'...b'9' => {} + _ => { + return Err(self.error(ErrorCode::InvalidNumber)); + } + } + + while let b'0'...b'9' = try!(self.peek_or_null()) { + self.eat_char(); + } + + Ok(()) + } + + #[cfg(feature = "raw_value")] + fn deserialize_raw_value<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.parse_whitespace()?; + self.read.begin_raw_buffering(); + self.ignore_value()?; + self.read.end_raw_buffering(visitor) + } +} + +impl FromStr for Number { + type Err = Error; + + fn from_str(s: &str) -> result::Result<Self, Self::Err> { + Deserializer::from_str(s) + .parse_any_signed_number() + .map(Into::into) + } +} + +static POW10: [f64; 309] = [ + 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009, // + 1e010, 1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019, // + 1e020, 1e021, 1e022, 1e023, 1e024, 1e025, 1e026, 1e027, 1e028, 1e029, // + 1e030, 1e031, 1e032, 1e033, 1e034, 1e035, 1e036, 1e037, 1e038, 1e039, // + 1e040, 1e041, 1e042, 1e043, 1e044, 1e045, 1e046, 1e047, 1e048, 1e049, // + 1e050, 1e051, 1e052, 1e053, 1e054, 1e055, 1e056, 1e057, 1e058, 1e059, // + 1e060, 1e061, 1e062, 1e063, 1e064, 1e065, 1e066, 1e067, 1e068, 1e069, // + 1e070, 1e071, 1e072, 1e073, 1e074, 1e075, 1e076, 1e077, 1e078, 1e079, // + 1e080, 1e081, 1e082, 1e083, 1e084, 1e085, 1e086, 1e087, 1e088, 1e089, // + 1e090, 1e091, 1e092, 1e093, 1e094, 1e095, 1e096, 1e097, 1e098, 1e099, // + 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, // + 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, // + 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, // + 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, // + 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, // + 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, // + 1e160, 1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169, // + 1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178, 1e179, // + 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187, 1e188, 1e189, // + 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, 1e197, 1e198, 1e199, // + 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, 1e206, 1e207, 1e208, 1e209, // + 1e210, 1e211, 1e212, 1e213, 1e214, 1e215, 1e216, 1e217, 1e218, 1e219, // + 1e220, 1e221, 1e222, 1e223, 1e224, 1e225, 1e226, 1e227, 1e228, 1e229, // + 1e230, 1e231, 1e232, 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, // + 1e240, 1e241, 1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, // + 1e250, 1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259, // + 1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268, 1e269, // + 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277, 1e278, 1e279, // + 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286, 1e287, 1e288, 1e289, // + 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, 1e296, 1e297, 1e298, 1e299, // + 1e300, 1e301, 1e302, 1e303, 1e304, 1e305, 1e306, 1e307, 1e308, +]; + +macro_rules! deserialize_prim_number { + ($method:ident) => { + fn $method<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_prim_number(visitor) + } + } +} + +#[cfg(not(feature = "unbounded_depth"))] +macro_rules! if_checking_recursion_limit { + ($($body:tt)*) => { + $($body)* + }; +} + +#[cfg(feature = "unbounded_depth")] +macro_rules! if_checking_recursion_limit { + ($this:ident $($body:tt)*) => { + if !$this.disable_recursion_limit { + $this $($body)* + } + }; +} + +macro_rules! check_recursion { + ($this:ident $($body:tt)*) => { + if_checking_recursion_limit! { + $this.remaining_depth -= 1; + if $this.remaining_depth == 0 { + return Err($this.peek_error(ErrorCode::RecursionLimitExceeded)); + } + } + + $this $($body)* + + if_checking_recursion_limit! { + $this.remaining_depth += 1; + } + }; +} + +impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> { + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'n' => { + self.eat_char(); + try!(self.parse_ident(b"ull")); + visitor.visit_unit() + } + b't' => { + self.eat_char(); + try!(self.parse_ident(b"rue")); + visitor.visit_bool(true) + } + b'f' => { + self.eat_char(); + try!(self.parse_ident(b"alse")); + visitor.visit_bool(false) + } + b'-' => { + self.eat_char(); + try!(self.parse_any_number(false)).visit(visitor) + } + b'0'...b'9' => try!(self.parse_any_number(true)).visit(visitor), + b'"' => { + self.eat_char(); + self.scratch.clear(); + match try!(self.read.parse_str(&mut self.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + }; + + match value { + Ok(value) => Ok(value), + // The de::Error impl creates errors with unknown line and column. + // Fill in the position here by looking at the current index in the + // input. There is no way to tell whether this should call `error` + // or `peek_error` so pick the one that seems correct more often. + // Worst case, the position is off by one character. + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b't' => { + self.eat_char(); + try!(self.parse_ident(b"rue")); + visitor.visit_bool(true) + } + b'f' => { + self.eat_char(); + try!(self.parse_ident(b"alse")); + visitor.visit_bool(false) + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + deserialize_prim_number!(deserialize_i8); + deserialize_prim_number!(deserialize_i16); + deserialize_prim_number!(deserialize_i32); + deserialize_prim_number!(deserialize_i64); + deserialize_prim_number!(deserialize_u8); + deserialize_prim_number!(deserialize_u16); + deserialize_prim_number!(deserialize_u32); + deserialize_prim_number!(deserialize_u64); + deserialize_prim_number!(deserialize_f32); + deserialize_prim_number!(deserialize_f64); + + serde_if_integer128! { + fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let mut buf = String::new(); + + match try!(self.parse_whitespace()) { + Some(b'-') => { + self.eat_char(); + buf.push('-'); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + try!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_i128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match try!(self.parse_whitespace()) { + Some(b'-') => { + return Err(self.peek_error(ErrorCode::NumberOutOfRange)); + } + Some(_) => {} + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + } + + let mut buf = String::new(); + try!(self.scan_integer128(&mut buf)); + + let value = match buf.parse() { + Ok(int) => visitor.visit_u128(int), + Err(_) => { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'"' => { + self.eat_char(); + self.scratch.clear(); + match try!(self.read.parse_str(&mut self.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + /// Parses a JSON string as bytes. Note that this function does not check + /// whether the bytes represent a valid UTF-8 string. + /// + /// The relevant part of the JSON specification is Section 8.2 of [RFC + /// 7159]: + /// + /// > When all the strings represented in a JSON text are composed entirely + /// > of Unicode characters (however escaped), then that JSON text is + /// > interoperable in the sense that all software implementations that + /// > parse it will agree on the contents of names and of string values in + /// > objects and arrays. + /// > + /// > However, the ABNF in this specification allows member names and string + /// > values to contain bit sequences that cannot encode Unicode characters; + /// > for example, "\uDEAD" (a single unpaired UTF-16 surrogate). Instances + /// > of this have been observed, for example, when a library truncates a + /// > UTF-16 string without checking whether the truncation split a + /// > surrogate pair. The behavior of software that receives JSON texts + /// > containing such values is unpredictable; for example, implementations + /// > might return different values for the length of a string value or even + /// > suffer fatal runtime exceptions. + /// + /// [RFC 7159]: https://tools.ietf.org/html/rfc7159 + /// + /// The behavior of serde_json is specified to fail on non-UTF-8 strings + /// when deserializing into Rust UTF-8 string types such as String, and + /// succeed with non-UTF-8 bytes when deserializing using this method. + /// + /// Escape sequences are processed as usual, and for `\uXXXX` escapes it is + /// still checked if the hex number represents a valid Unicode code point. + /// + /// # Examples + /// + /// You can use this to parse JSON strings containing invalid UTF-8 bytes. + /// + /// ```edition2018 + /// use serde_bytes::ByteBuf; + /// + /// fn look_at_bytes() -> Result<(), serde_json::Error> { + /// let json_data = b"\"some bytes: \xe5\x00\xe5\""; + /// let bytes: ByteBuf = serde_json::from_slice(json_data)?; + /// + /// assert_eq!(b'\xe5', bytes[12]); + /// assert_eq!(b'\0', bytes[13]); + /// assert_eq!(b'\xe5', bytes[14]); + /// + /// Ok(()) + /// } + /// # + /// # fn main() { + /// # look_at_bytes().unwrap(); + /// # } + /// ``` + /// + /// Backslash escape sequences like `\n` are still interpreted and required + /// to be valid, and `\u` escape sequences are required to represent valid + /// Unicode code points. + /// + /// ```edition2018 + /// use serde_bytes::ByteBuf; + /// + /// fn look_at_bytes() { + /// let json_data = b"\"invalid unicode surrogate: \\uD801\""; + /// let parsed: Result<ByteBuf, _> = serde_json::from_slice(json_data); + /// + /// assert!(parsed.is_err()); + /// + /// let expected_msg = "unexpected end of hex escape at line 1 column 35"; + /// assert_eq!(expected_msg, parsed.unwrap_err().to_string()); + /// } + /// # + /// # fn main() { + /// # look_at_bytes(); + /// # } + /// ``` + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'"' => { + self.eat_char(); + self.scratch.clear(); + match try!(self.read.parse_str_raw(&mut self.scratch)) { + Reference::Borrowed(b) => visitor.visit_borrowed_bytes(b), + Reference::Copied(b) => visitor.visit_bytes(b), + } + } + b'[' => self.deserialize_seq(visitor), + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + #[inline] + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + /// Parses a `null` as a None, and any other values as a `Some(...)`. + #[inline] + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match try!(self.parse_whitespace()) { + Some(b'n') => { + self.eat_char(); + try!(self.parse_ident(b"ull")); + visitor.visit_none() + } + _ => visitor.visit_some(self), + } + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'n' => { + self.eat_char(); + try!(self.parse_ident(b"ull")); + visitor.visit_unit() + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + /// Parses a newtype struct as the underlying value. + #[inline] + fn deserialize_newtype_struct<V>(self, name: &str, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == ::raw::TOKEN { + return self.deserialize_raw_value(visitor); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct<V>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + fn deserialize_struct<V>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + let peek = match try!(self.parse_whitespace()) { + Some(b) => b, + None => { + return Err(self.peek_error(ErrorCode::EofWhileParsingValue)); + } + }; + + let value = match peek { + b'[' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_seq(SeqAccess::new(self)); + } + + match (ret, self.end_seq()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + b'{' => { + check_recursion! { + self.eat_char(); + let ret = visitor.visit_map(MapAccess::new(self)); + } + + match (ret, self.end_map()) { + (Ok(ret), Ok(())) => Ok(ret), + (Err(err), _) | (_, Err(err)) => Err(err), + } + } + _ => Err(self.peek_invalid_type(&visitor)), + }; + + match value { + Ok(value) => Ok(value), + Err(err) => Err(self.fix_position(err)), + } + } + + /// Parses an enum as an object like `{"$KEY":$VALUE}`, where $VALUE is either a straight + /// value, a `[..]`, or a `{..}`. + #[inline] + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + match try!(self.parse_whitespace()) { + Some(b'{') => { + check_recursion! { + self.eat_char(); + let value = try!(visitor.visit_enum(VariantAccess::new(self))); + } + + match try!(self.parse_whitespace()) { + Some(b'}') => { + self.eat_char(); + Ok(value) + } + Some(_) => Err(self.error(ErrorCode::ExpectedSomeValue)), + None => Err(self.error(ErrorCode::EofWhileParsingObject)), + } + } + Some(b'"') => visitor.visit_enum(UnitVariantAccess::new(self)), + Some(_) => Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + None => Err(self.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + try!(self.ignore_value()); + visitor.visit_unit() + } +} + +struct SeqAccess<'a, R: 'a> { + de: &'a mut Deserializer<R>, + first: bool, +} + +impl<'a, R: 'a> SeqAccess<'a, R> { + fn new(de: &'a mut Deserializer<R>) -> Self { + SeqAccess { + de: de, + first: true, + } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::SeqAccess<'de> for SeqAccess<'a, R> { + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>> + where + T: de::DeserializeSeed<'de>, + { + let peek = match try!(self.de.parse_whitespace()) { + Some(b']') => { + return Ok(None); + } + Some(b',') if !self.first => { + self.de.eat_char(); + try!(self.de.parse_whitespace()) + } + Some(b) => { + if self.first { + self.first = false; + Some(b) + } else { + return Err(self.de.peek_error(ErrorCode::ExpectedListCommaOrEnd)); + } + } + None => { + return Err(self.de.peek_error(ErrorCode::EofWhileParsingList)); + } + }; + + match peek { + Some(b']') => Err(self.de.peek_error(ErrorCode::TrailingComma)), + Some(_) => Ok(Some(try!(seed.deserialize(&mut *self.de)))), + None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + } + } +} + +struct MapAccess<'a, R: 'a> { + de: &'a mut Deserializer<R>, + first: bool, +} + +impl<'a, R: 'a> MapAccess<'a, R> { + fn new(de: &'a mut Deserializer<R>) -> Self { + MapAccess { + de: de, + first: true, + } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::MapAccess<'de> for MapAccess<'a, R> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>> + where + K: de::DeserializeSeed<'de>, + { + let peek = match try!(self.de.parse_whitespace()) { + Some(b'}') => { + return Ok(None); + } + Some(b',') if !self.first => { + self.de.eat_char(); + try!(self.de.parse_whitespace()) + } + Some(b) => { + if self.first { + self.first = false; + Some(b) + } else { + return Err(self.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd)); + } + } + None => { + return Err(self.de.peek_error(ErrorCode::EofWhileParsingObject)); + } + }; + + match peek { + Some(b'"') => seed.deserialize(MapKey { de: &mut *self.de }).map(Some), + Some(b'}') => Err(self.de.peek_error(ErrorCode::TrailingComma)), + Some(_) => Err(self.de.peek_error(ErrorCode::KeyMustBeAString)), + None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value> + where + V: de::DeserializeSeed<'de>, + { + try!(self.de.parse_object_colon()); + + seed.deserialize(&mut *self.de) + } +} + +struct VariantAccess<'a, R: 'a> { + de: &'a mut Deserializer<R>, +} + +impl<'a, R: 'a> VariantAccess<'a, R> { + fn new(de: &'a mut Deserializer<R>) -> Self { + VariantAccess { de: de } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::EnumAccess<'de> for VariantAccess<'a, R> { + type Error = Error; + type Variant = Self; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self)> + where + V: de::DeserializeSeed<'de>, + { + let val = try!(seed.deserialize(&mut *self.de)); + try!(self.de.parse_object_colon()); + Ok((val, self)) + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::VariantAccess<'de> for VariantAccess<'a, R> { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + de::Deserialize::deserialize(self.de) + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(self.de) + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_seq(self.de, visitor) + } + + fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_struct(self.de, "", fields, visitor) + } +} + +struct UnitVariantAccess<'a, R: 'a> { + de: &'a mut Deserializer<R>, +} + +impl<'a, R: 'a> UnitVariantAccess<'a, R> { + fn new(de: &'a mut Deserializer<R>) -> Self { + UnitVariantAccess { de: de } + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::EnumAccess<'de> for UnitVariantAccess<'a, R> { + type Error = Error; + type Variant = Self; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self)> + where + V: de::DeserializeSeed<'de>, + { + let variant = try!(seed.deserialize(&mut *self.de)); + Ok((variant, self)) + } +} + +impl<'de, 'a, R: Read<'de> + 'a> de::VariantAccess<'de> for UnitVariantAccess<'a, R> { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value> + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant<V>(self, _fields: &'static [&'static str], _visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} + +/// Only deserialize from this after peeking a '"' byte! Otherwise it may +/// deserialize invalid JSON successfully. +struct MapKey<'a, R: 'a> { + de: &'a mut Deserializer<R>, +} + +macro_rules! deserialize_integer_key { + ($method:ident => $visit:ident) => { + fn $method<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + self.de.scratch.clear(); + let string = try!(self.de.read.parse_str(&mut self.de.scratch)); + match (string.parse(), string) { + (Ok(integer), _) => visitor.$visit(integer), + (Err(_), Reference::Borrowed(s)) => visitor.visit_borrowed_str(s), + (Err(_), Reference::Copied(s)) => visitor.visit_str(s), + } + } + } +} + +impl<'de, 'a, R> de::Deserializer<'de> for MapKey<'a, R> +where + R: Read<'de>, +{ + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.de.eat_char(); + self.de.scratch.clear(); + match try!(self.de.read.parse_str(&mut self.de.scratch)) { + Reference::Borrowed(s) => visitor.visit_borrowed_str(s), + Reference::Copied(s) => visitor.visit_str(s), + } + } + + deserialize_integer_key!(deserialize_i8 => visit_i8); + deserialize_integer_key!(deserialize_i16 => visit_i16); + deserialize_integer_key!(deserialize_i32 => visit_i32); + deserialize_integer_key!(deserialize_i64 => visit_i64); + deserialize_integer_key!(deserialize_u8 => visit_u8); + deserialize_integer_key!(deserialize_u16 => visit_u16); + deserialize_integer_key!(deserialize_u32 => visit_u32); + deserialize_integer_key!(deserialize_u64 => visit_u64); + + serde_if_integer128! { + deserialize_integer_key!(deserialize_i128 => visit_i128); + deserialize_integer_key!(deserialize_u128 => visit_u128); + } + + #[inline] + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + // Map keys cannot be null. + visitor.visit_some(self) + } + + #[inline] + fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + #[inline] + fn deserialize_enum<V>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.de.deserialize_enum(name, variants, visitor) + } + + #[inline] + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.de.deserialize_bytes(visitor) + } + + #[inline] + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value> + where + V: de::Visitor<'de>, + { + self.de.deserialize_bytes(visitor) + } + + forward_to_deserialize_any! { + bool f32 f64 char str string unit unit_struct seq tuple tuple_struct map + struct identifier ignored_any + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// Iterator that deserializes a stream into multiple JSON values. +/// +/// A stream deserializer can be created from any JSON deserializer using the +/// `Deserializer::into_iter` method. +/// +/// The data can consist of any JSON value. Values need to be a self-delineating value e.g. +/// arrays, objects, or strings, or be followed by whitespace or a self-delineating value. +/// +/// ```edition2018 +/// use serde_json::{Deserializer, Value}; +/// +/// fn main() { +/// let data = "{\"k\": 3}1\"cool\"\"stuff\" 3{} [0, 1, 2]"; +/// +/// let stream = Deserializer::from_str(data).into_iter::<Value>(); +/// +/// for value in stream { +/// println!("{}", value.unwrap()); +/// } +/// } +/// ``` +pub struct StreamDeserializer<'de, R, T> { + de: Deserializer<R>, + offset: usize, + output: PhantomData<T>, + lifetime: PhantomData<&'de ()>, +} + +impl<'de, R, T> StreamDeserializer<'de, R, T> +where + R: read::Read<'de>, + T: de::Deserialize<'de>, +{ + /// Create a JSON stream deserializer from one of the possible serde_json + /// input sources. + /// + /// Typically it is more convenient to use one of these methods instead: + /// + /// - Deserializer::from_str(...).into_iter() + /// - Deserializer::from_bytes(...).into_iter() + /// - Deserializer::from_reader(...).into_iter() + pub fn new(read: R) -> Self { + let offset = read.byte_offset(); + StreamDeserializer { + de: Deserializer::new(read), + offset: offset, + output: PhantomData, + lifetime: PhantomData, + } + } + + /// Returns the number of bytes so far deserialized into a successful `T`. + /// + /// If a stream deserializer returns an EOF error, new data can be joined to + /// `old_data[stream.byte_offset()..]` to try again. + /// + /// ```edition2018 + /// let data = b"[0] [1] ["; + /// + /// let de = serde_json::Deserializer::from_slice(data); + /// let mut stream = de.into_iter::<Vec<i32>>(); + /// assert_eq!(0, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // [0] + /// assert_eq!(3, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // [1] + /// assert_eq!(7, stream.byte_offset()); + /// + /// println!("{:?}", stream.next()); // error + /// assert_eq!(8, stream.byte_offset()); + /// + /// // If err.is_eof(), can join the remaining data to new data and continue. + /// let remaining = &data[stream.byte_offset()..]; + /// ``` + /// + /// *Note:* In the future this method may be changed to return the number of + /// bytes so far deserialized into a successful T *or* syntactically valid + /// JSON skipped over due to a type error. See [serde-rs/json#70] for an + /// example illustrating this. + /// + /// [serde-rs/json#70]: https://github.com/serde-rs/json/issues/70 + pub fn byte_offset(&self) -> usize { + self.offset + } + + fn peek_end_of_value(&mut self) -> Result<()> { + match try!(self.de.peek()) { + Some(b' ') | Some(b'\n') | Some(b'\t') | Some(b'\r') | Some(b'"') | Some(b'[') + | Some(b']') | Some(b'{') | Some(b'}') | Some(b',') | Some(b':') | None => Ok(()), + Some(_) => { + let position = self.de.read.peek_position(); + Err(Error::syntax( + ErrorCode::TrailingCharacters, + position.line, + position.column, + )) + } + } + } +} + +impl<'de, R, T> Iterator for StreamDeserializer<'de, R, T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + type Item = Result<T>; + + fn next(&mut self) -> Option<Result<T>> { + // skip whitespaces, if any + // this helps with trailing whitespaces, since whitespaces between + // values are handled for us. + match self.de.parse_whitespace() { + Ok(None) => { + self.offset = self.de.read.byte_offset(); + None + } + Ok(Some(b)) => { + // If the value does not have a clear way to show the end of the value + // (like numbers, null, true etc.) we have to look for whitespace or + // the beginning of a self-delineated value. + let self_delineated_value = match b { + b'[' | b'"' | b'{' => true, + _ => false, + }; + self.offset = self.de.read.byte_offset(); + let result = de::Deserialize::deserialize(&mut self.de); + + Some(match result { + Ok(value) => { + self.offset = self.de.read.byte_offset(); + if self_delineated_value { + Ok(value) + } else { + self.peek_end_of_value().map(|_| value) + } + } + Err(e) => Err(e), + }) + } + Err(e) => Some(Err(e)), + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +fn from_trait<'de, R, T>(read: R) -> Result<T> +where + R: Read<'de>, + T: de::Deserialize<'de>, +{ + let mut de = Deserializer::new(read); + let value = try!(de::Deserialize::deserialize(&mut de)); + + // Make sure the whole stream has been consumed. + try!(de.end()); + Ok(value) +} + +/// Deserialize an instance of type `T` from an IO stream of JSON. +/// +/// The content of the IO stream is deserialized directly from the stream +/// without being buffered in memory by serde_json. +/// +/// When reading from a source against which short reads are not efficient, such +/// as a [`File`], you will want to apply your own buffering because serde_json +/// will not buffer the input. See [`std::io::BufReader`]. +/// +/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html +/// [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// use serde::Deserialize; +/// +/// use std::error::Error; +/// use std::fs::File; +/// use std::io::BufReader; +/// use std::path::Path; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn read_user_from_file<P: AsRef<Path>>(path: P) -> Result<User, Box<Error>> { +/// // Open the file in read-only mode with buffer. +/// let file = File::open(path)?; +/// let reader = BufReader::new(file); +/// +/// // Read the JSON contents of the file as an instance of `User`. +/// let u = serde_json::from_reader(reader)?; +/// +/// // Return the `User`. +/// Ok(u) +/// } +/// +/// fn main() { +/// # } +/// # fn fake_main() { +/// let u = read_user_from_file("test.json").unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_reader<R, T>(rdr: R) -> Result<T> +where + R: io::Read, + T: de::DeserializeOwned, +{ + from_trait(read::IoRead::new(rdr)) +} + +/// Deserialize an instance of type `T` from bytes of JSON text. +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// use serde::Deserialize; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `&[u8]` +/// let j = b" +/// { +/// \"fingerprint\": \"0xF9BA143B95FF6D82\", +/// \"location\": \"Menlo Park, CA\" +/// }"; +/// +/// let u: User = serde_json::from_slice(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_slice<'a, T>(v: &'a [u8]) -> Result<T> +where + T: de::Deserialize<'a>, +{ + from_trait(read::SliceRead::new(v)) +} + +/// Deserialize an instance of type `T` from a string of JSON text. +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// use serde::Deserialize; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `&str` +/// let j = " +/// { +/// \"fingerprint\": \"0xF9BA143B95FF6D82\", +/// \"location\": \"Menlo Park, CA\" +/// }"; +/// +/// let u: User = serde_json::from_str(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the input does not match the +/// structure expected by `T`, for example if `T` is a struct type but the input +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_str<'a, T>(s: &'a str) -> Result<T> +where + T: de::Deserialize<'a>, +{ + from_trait(read::StrRead::new(s)) +} diff --git a/serde_json/src/error.rs b/serde_json/src/error.rs new file mode 100644 index 000000000..42f09373a --- /dev/null +++ b/serde_json/src/error.rs @@ -0,0 +1,472 @@ +//! When serializing or deserializing JSON goes wrong. + +use std::error; +use std::fmt::{self, Debug, Display}; +use std::io; +use std::result; +use std::str::FromStr; + +use serde::de; +use serde::ser; + +/// This type represents all possible errors that can occur when serializing or +/// deserializing JSON data. +pub struct Error { + /// This `Box` allows us to keep the size of `Error` as small as possible. A + /// larger `Error` type was substantially slower due to all the functions + /// that pass around `Result<T, Error>`. + err: Box<ErrorImpl>, +} + +/// Alias for a `Result` with the error type `serde_json::Error`. +pub type Result<T> = result::Result<T, Error>; + +impl Error { + /// One-based line number at which the error was detected. + /// + /// Characters in the first line of the input (before the first newline + /// character) are in line 1. + pub fn line(&self) -> usize { + self.err.line + } + + /// One-based column number at which the error was detected. + /// + /// The first character in the input and any characters immediately + /// following a newline character are in column 1. + /// + /// Note that errors may occur in column 0, for example if a read from an IO + /// stream fails immediately following a previously read newline character. + pub fn column(&self) -> usize { + self.err.column + } + + /// Categorizes the cause of this error. + /// + /// - `Category::Io` - failure to read or write bytes on an IO stream + /// - `Category::Syntax` - input that is not syntactically valid JSON + /// - `Category::Data` - input data that is semantically incorrect + /// - `Category::Eof` - unexpected end of the input data + pub fn classify(&self) -> Category { + match self.err.code { + ErrorCode::Message(_) => Category::Data, + ErrorCode::Io(_) => Category::Io, + ErrorCode::EofWhileParsingList + | ErrorCode::EofWhileParsingObject + | ErrorCode::EofWhileParsingString + | ErrorCode::EofWhileParsingValue => Category::Eof, + ErrorCode::ExpectedColon + | ErrorCode::ExpectedListCommaOrEnd + | ErrorCode::ExpectedObjectCommaOrEnd + | ErrorCode::ExpectedObjectOrArray + | ErrorCode::ExpectedSomeIdent + | ErrorCode::ExpectedSomeValue + | ErrorCode::ExpectedSomeString + | ErrorCode::InvalidEscape + | ErrorCode::InvalidNumber + | ErrorCode::NumberOutOfRange + | ErrorCode::InvalidUnicodeCodePoint + | ErrorCode::ControlCharacterWhileParsingString + | ErrorCode::KeyMustBeAString + | ErrorCode::LoneLeadingSurrogateInHexEscape + | ErrorCode::TrailingComma + | ErrorCode::TrailingCharacters + | ErrorCode::UnexpectedEndOfHexEscape + | ErrorCode::RecursionLimitExceeded => Category::Syntax, + } + } + + /// Returns true if this error was caused by a failure to read or write + /// bytes on an IO stream. + pub fn is_io(&self) -> bool { + self.classify() == Category::Io + } + + /// Returns true if this error was caused by input that was not + /// syntactically valid JSON. + pub fn is_syntax(&self) -> bool { + self.classify() == Category::Syntax + } + + /// Returns true if this error was caused by input data that was + /// semantically incorrect. + /// + /// For example, JSON containing a number is semantically incorrect when the + /// type being deserialized into holds a String. + pub fn is_data(&self) -> bool { + self.classify() == Category::Data + } + + /// Returns true if this error was caused by prematurely reaching the end of + /// the input data. + /// + /// Callers that process streaming input may be interested in retrying the + /// deserialization once more data is available. + pub fn is_eof(&self) -> bool { + self.classify() == Category::Eof + } +} + +/// Categorizes the cause of a `serde_json::Error`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Category { + /// The error was caused by a failure to read or write bytes on an IO + /// stream. + Io, + + /// The error was caused by input that was not syntactically valid JSON. + Syntax, + + /// The error was caused by input data that was semantically incorrect. + /// + /// For example, JSON containing a number is semantically incorrect when the + /// type being deserialized into holds a String. + Data, + + /// The error was caused by prematurely reaching the end of the input data. + /// + /// Callers that process streaming input may be interested in retrying the + /// deserialization once more data is available. + Eof, +} + +#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))] +impl From<Error> for io::Error { + /// Convert a `serde_json::Error` into an `io::Error`. + /// + /// JSON syntax and data errors are turned into `InvalidData` IO errors. + /// EOF errors are turned into `UnexpectedEof` IO errors. + /// + /// ```edition2018 + /// use std::io; + /// + /// enum MyError { + /// Io(io::Error), + /// Json(serde_json::Error), + /// } + /// + /// impl From<serde_json::Error> for MyError { + /// fn from(err: serde_json::Error) -> MyError { + /// use serde_json::error::Category; + /// match err.classify() { + /// Category::Io => { + /// MyError::Io(err.into()) + /// } + /// Category::Syntax | Category::Data | Category::Eof => { + /// MyError::Json(err) + /// } + /// } + /// } + /// } + /// ``` + fn from(j: Error) -> Self { + if let ErrorCode::Io(err) = j.err.code { + err + } else { + match j.classify() { + Category::Io => unreachable!(), + Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j), + Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j), + } + } + } +} + +struct ErrorImpl { + code: ErrorCode, + line: usize, + column: usize, +} + +// Not public API. Should be pub(crate). +#[doc(hidden)] +pub enum ErrorCode { + /// Catchall for syntax error messages + Message(Box<str>), + + /// Some IO error occurred while serializing or deserializing. + Io(io::Error), + + /// EOF while parsing a list. + EofWhileParsingList, + + /// EOF while parsing an object. + EofWhileParsingObject, + + /// EOF while parsing a string. + EofWhileParsingString, + + /// EOF while parsing a JSON value. + EofWhileParsingValue, + + /// Expected this character to be a `':'`. + ExpectedColon, + + /// Expected this character to be either a `','` or a `']'`. + ExpectedListCommaOrEnd, + + /// Expected this character to be either a `','` or a `'}'`. + ExpectedObjectCommaOrEnd, + + /// Expected this character to be either a `'{'` or a `'['`. + ExpectedObjectOrArray, + + /// Expected to parse either a `true`, `false`, or a `null`. + ExpectedSomeIdent, + + /// Expected this character to start a JSON value. + ExpectedSomeValue, + + /// Expected this character to start a JSON string. + ExpectedSomeString, + + /// Invalid hex escape code. + InvalidEscape, + + /// Invalid number. + InvalidNumber, + + /// Number is bigger than the maximum value of its type. + NumberOutOfRange, + + /// Invalid unicode code point. + InvalidUnicodeCodePoint, + + /// Control character found while parsing a string. + ControlCharacterWhileParsingString, + + /// Object key is not a string. + KeyMustBeAString, + + /// Lone leading surrogate in hex escape. + LoneLeadingSurrogateInHexEscape, + + /// JSON has a comma after the last value in an array or map. + TrailingComma, + + /// JSON has non-whitespace trailing characters after the value. + TrailingCharacters, + + /// Unexpected end of hex excape. + UnexpectedEndOfHexEscape, + + /// Encountered nesting of JSON maps and arrays more than 128 layers deep. + RecursionLimitExceeded, +} + +impl Error { + // Not public API. Should be pub(crate). + #[doc(hidden)] + #[cold] + pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self { + Error { + err: Box::new(ErrorImpl { + code: code, + line: line, + column: column, + }), + } + } + + // Not public API. Should be pub(crate). + // + // Update `eager_json` crate when this function changes. + #[doc(hidden)] + #[cold] + pub fn io(error: io::Error) -> Self { + Error { + err: Box::new(ErrorImpl { + code: ErrorCode::Io(error), + line: 0, + column: 0, + }), + } + } + + // Not public API. Should be pub(crate). + #[doc(hidden)] + #[cold] + pub fn fix_position<F>(self, f: F) -> Self + where + F: FnOnce(ErrorCode) -> Error, + { + if self.err.line == 0 { + f(self.err.code) + } else { + self + } + } +} + +impl Display for ErrorCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ErrorCode::Message(ref msg) => f.write_str(msg), + ErrorCode::Io(ref err) => Display::fmt(err, f), + ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"), + ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"), + ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"), + ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"), + ErrorCode::ExpectedColon => f.write_str("expected `:`"), + ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"), + ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"), + ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"), + ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"), + ErrorCode::ExpectedSomeValue => f.write_str("expected value"), + ErrorCode::ExpectedSomeString => f.write_str("expected string"), + ErrorCode::InvalidEscape => f.write_str("invalid escape"), + ErrorCode::InvalidNumber => f.write_str("invalid number"), + ErrorCode::NumberOutOfRange => f.write_str("number out of range"), + ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"), + ErrorCode::ControlCharacterWhileParsingString => { + f.write_str("control character (\\u0000-\\u001F) found while parsing a string") + } + ErrorCode::KeyMustBeAString => f.write_str("key must be a string"), + ErrorCode::LoneLeadingSurrogateInHexEscape => { + f.write_str("lone leading surrogate in hex escape") + } + ErrorCode::TrailingComma => f.write_str("trailing comma"), + ErrorCode::TrailingCharacters => f.write_str("trailing characters"), + ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"), + ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match self.err.code { + ErrorCode::Io(ref err) => error::Error::description(err), + _ => { + // If you want a better message, use Display::fmt or to_string(). + "JSON error" + } + } + } + + fn cause(&self) -> Option<&error::Error> { + match self.err.code { + ErrorCode::Io(ref err) => Some(err), + _ => None, + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&*self.err, f) + } +} + +impl Display for ErrorImpl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.line == 0 { + Display::fmt(&self.code, f) + } else { + write!( + f, + "{} at line {} column {}", + self.code, self.line, self.column + ) + } + } +} + +// Remove two layers of verbosity from the debug representation. Humans often +// end up seeing this representation because it is what unwrap() shows. +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "Error({:?}, line: {}, column: {})", + self.err.code.to_string(), + self.err.line, + self.err.column + ) + } +} + +impl de::Error for Error { + #[cold] + fn custom<T: Display>(msg: T) -> Error { + make_error(msg.to_string()) + } + + #[cold] + fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self { + if let de::Unexpected::Unit = unexp { + Error::custom(format_args!("invalid type: null, expected {}", exp)) + } else { + Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp)) + } + } +} + +impl ser::Error for Error { + #[cold] + fn custom<T: Display>(msg: T) -> Error { + make_error(msg.to_string()) + } +} + +// Parse our own error message that looks like "{} at line {} column {}" to work +// around erased-serde round-tripping the error through de::Error::custom. +fn make_error(mut msg: String) -> Error { + let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0)); + Error { + err: Box::new(ErrorImpl { + code: ErrorCode::Message(msg.into_boxed_str()), + line: line, + column: column, + }), + } +} + +fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> { + let start_of_suffix = match msg.rfind(" at line ") { + Some(index) => index, + None => return None, + }; + + // Find start and end of line number. + let start_of_line = start_of_suffix + " at line ".len(); + let mut end_of_line = start_of_line; + while starts_with_digit(&msg[end_of_line..]) { + end_of_line += 1; + } + + if !msg[end_of_line..].starts_with(" column ") { + return None; + } + + // Find start and end of column number. + let start_of_column = end_of_line + " column ".len(); + let mut end_of_column = start_of_column; + while starts_with_digit(&msg[end_of_column..]) { + end_of_column += 1; + } + + if end_of_column < msg.len() { + return None; + } + + // Parse numbers. + let line = match usize::from_str(&msg[start_of_line..end_of_line]) { + Ok(line) => line, + Err(_) => return None, + }; + let column = match usize::from_str(&msg[start_of_column..end_of_column]) { + Ok(column) => column, + Err(_) => return None, + }; + + msg.truncate(start_of_suffix); + Some((line, column)) +} + +fn starts_with_digit(slice: &str) -> bool { + match slice.as_bytes().get(0) { + None => false, + Some(&byte) => byte >= b'0' && byte <= b'9', + } +} diff --git a/serde_json/src/iter.rs b/serde_json/src/iter.rs new file mode 100644 index 000000000..1a9a954d1 --- /dev/null +++ b/serde_json/src/iter.rs @@ -0,0 +1,70 @@ +use std::io; + +pub struct LineColIterator<I> { + iter: I, + + /// Index of the current line. Characters in the first line of the input + /// (before the first newline character) are in line 1. + line: usize, + + /// Index of the current column. The first character in the input and any + /// characters immediately following a newline character are in column 1. + /// The column is 0 immediately after a newline character has been read. + col: usize, + + /// Byte offset of the start of the current line. This is the sum of lenghts + /// of all previous lines. Keeping track of things this way allows efficient + /// computation of the current line, column, and byte offset while only + /// updating one of the counters in `next()` in the common case. + start_of_line: usize, +} + +impl<I> LineColIterator<I> +where + I: Iterator<Item = io::Result<u8>>, +{ + pub fn new(iter: I) -> LineColIterator<I> { + LineColIterator { + iter: iter, + line: 1, + col: 0, + start_of_line: 0, + } + } + + pub fn line(&self) -> usize { + self.line + } + + pub fn col(&self) -> usize { + self.col + } + + pub fn byte_offset(&self) -> usize { + self.start_of_line + self.col + } +} + +impl<I> Iterator for LineColIterator<I> +where + I: Iterator<Item = io::Result<u8>>, +{ + type Item = io::Result<u8>; + + fn next(&mut self) -> Option<io::Result<u8>> { + match self.iter.next() { + None => None, + Some(Ok(b'\n')) => { + self.start_of_line += self.col + 1; + self.line += 1; + self.col = 0; + Some(Ok(b'\n')) + } + Some(Ok(c)) => { + self.col += 1; + Some(Ok(c)) + } + Some(Err(e)) => Some(Err(e)), + } + } +} diff --git a/serde_json/src/lib.rs b/serde_json/src/lib.rs new file mode 100644 index 000000000..c9babc07e --- /dev/null +++ b/serde_json/src/lib.rs @@ -0,0 +1,365 @@ +//! # Serde JSON +//! +//! JSON is a ubiquitous open-standard format that uses human-readable text to +//! transmit data objects consisting of key-value pairs. +//! +//! ```json +//! { +//! "name": "John Doe", +//! "age": 43, +//! "address": { +//! "street": "10 Downing Street", +//! "city": "London" +//! }, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! } +//! ``` +//! +//! There are three common ways that you might find yourself needing to work +//! with JSON data in Rust. +//! +//! - **As text data.** An unprocessed string of JSON data that you receive on +//! an HTTP endpoint, read from a file, or prepare to send to a remote +//! server. +//! - **As an untyped or loosely typed representation.** Maybe you want to +//! check that some JSON data is valid before passing it on, but without +//! knowing the structure of what it contains. Or you want to do very basic +//! manipulations like insert a key in a particular spot. +//! - **As a strongly typed Rust data structure.** When you expect all or most +//! of your data to conform to a particular structure and want to get real +//! work done without JSON's loosey-goosey nature tripping you up. +//! +//! Serde JSON provides efficient, flexible, safe ways of converting data +//! between each of these representations. +//! +//! # Operating on untyped JSON values +//! +//! Any valid JSON data can be manipulated in the following recursive enum +//! representation. This data structure is [`serde_json::Value`][value]. +//! +//! ```edition2018 +//! # use serde_json::{Number, Map}; +//! # +//! # #[allow(dead_code)] +//! enum Value { +//! Null, +//! Bool(bool), +//! Number(Number), +//! String(String), +//! Array(Vec<Value>), +//! Object(Map<String, Value>), +//! } +//! ``` +//! +//! A string of JSON data can be parsed into a `serde_json::Value` by the +//! [`serde_json::from_str`][from_str] function. There is also +//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and +//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or +//! a TCP stream. +//! +//! ```edition2018 +//! use serde_json::{Result, Value}; +//! +//! fn untyped_example() -> Result<()> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into serde_json::Value. +//! let v: Value = serde_json::from_str(data)?; +//! +//! // Access parts of the data by indexing with square brackets. +//! println!("Please call {} at the number {}", v["name"], v["phones"][0]); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # untyped_example().unwrap(); +//! # } +//! ``` +//! +//! The result of square bracket indexing like `v["name"]` is a borrow of the +//! data at that index, so the type is `&Value`. A JSON map can be indexed with +//! string keys, while a JSON array can be indexed with integer keys. If the +//! type of the data is not right for the type with which it is being indexed, +//! or if a map does not contain the key being indexed, or if the index into a +//! vector is out of bounds, the returned element is `Value::Null`. +//! +//! When a `Value` is printed, it is printed as a JSON string. So in the code +//! above, the output looks like `Please call "John Doe" at the number "+44 +//! 1234567"`. The quotation marks appear because `v["name"]` is a `&Value` +//! containing a JSON string and its JSON representation is `"John Doe"`. +//! Printing as a plain string without quotation marks involves converting from +//! a JSON string to a Rust string with [`as_str()`] or avoiding the use of +//! `Value` as described in the following section. +//! +//! [`as_str()`]: https://docs.serde.rs/serde_json/enum.Value.html#method.as_str +//! +//! The `Value` representation is sufficient for very basic tasks but can be +//! tedious to work with for anything more significant. Error handling is +//! verbose to implement correctly, for example imagine trying to detect the +//! presence of unrecognized fields in the input data. The compiler is powerless +//! to help you when you make a mistake, for example imagine typoing `v["name"]` +//! as `v["nmae"]` in one of the dozens of places it is used in your code. +//! +//! # Parsing JSON as strongly typed data structures +//! +//! Serde provides a powerful way of mapping JSON data into Rust data structures +//! largely automatically. +//! +//! ```edition2018 +//! # use serde_derive::{Deserialize, Serialize}; +//! use serde::{Deserialize, Serialize}; +//! use serde_json::Result; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Person { +//! name: String, +//! age: u8, +//! phones: Vec<String>, +//! } +//! +//! fn typed_example() -> Result<()> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into a Person object. This is exactly the +//! // same function as the one that produced serde_json::Value above, but +//! // now we are asking it for a Person as output. +//! let p: Person = serde_json::from_str(data)?; +//! +//! // Do things just like with any other Rust data structure. +//! println!("Please call {} at the number {}", p.name, p.phones[0]); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # typed_example().unwrap(); +//! # } +//! ``` +//! +//! This is the same `serde_json::from_str` function as before, but this time we +//! assign the return value to a variable of type `Person` so Serde will +//! automatically interpret the input data as a `Person` and produce informative +//! error messages if the layout does not conform to what a `Person` is expected +//! to look like. +//! +//! Any type that implements Serde's `Deserialize` trait can be deserialized +//! this way. This includes built-in Rust standard library types like `Vec<T>` +//! and `HashMap<K, V>`, as well as any structs or enums annotated with +//! `#[derive(Deserialize)]`. +//! +//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us +//! use it correctly like they do for any other Rust code. The IDE can +//! autocomplete field names to prevent typos, which was impossible in the +//! `serde_json::Value` representation. And the Rust compiler can check that +//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a +//! `Vec<String>` so indexing into it makes sense and produces a `String`. +//! +//! # Constructing JSON values +//! +//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +//! objects with very natural JSON syntax. In order to use this macro, +//! `serde_json` needs to be imported with the `#[macro_use]` attribute. +//! +//! ```edition2018 +//! use serde_json::json; +//! +//! fn main() { +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }); +//! +//! println!("first phone number: {}", john["phones"][0]); +//! +//! // Convert to a string of JSON and print it out +//! println!("{}", john.to_string()); +//! } +//! ``` +//! +//! The `Value::to_string()` function converts a `serde_json::Value` into a +//! `String` of JSON text. +//! +//! One neat thing about the `json!` macro is that variables and expressions can +//! be interpolated directly into the JSON value as you are building it. Serde +//! will check at compile time that the value you are interpolating is able to +//! be represented as JSON. +//! +//! ```edition2018 +//! # use serde_json::json; +//! # +//! # fn random_phone() -> u16 { 0 } +//! # +//! let full_name = "John Doe"; +//! let age_last_year = 42; +//! +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": full_name, +//! "age": age_last_year + 1, +//! "phones": [ +//! format!("+44 {}", random_phone()) +//! ] +//! }); +//! ``` +//! +//! This is amazingly convenient but we have the problem we had before with +//! `Value` which is that the IDE and Rust compiler cannot help us if we get it +//! wrong. Serde JSON provides a better way of serializing strongly-typed data +//! structures into JSON text. +//! +//! # Creating JSON by serializing data structures +//! +//! A data structure can be converted to a JSON string by +//! [`serde_json::to_string`][to_string]. There is also +//! [`serde_json::to_vec`][to_vec] which serializes to a `Vec<u8>` and +//! [`serde_json::to_writer`][to_writer] which serializes to any `io::Write` +//! such as a File or a TCP stream. +//! +//! ```edition2018 +//! # use serde_derive::{Deserialize, Serialize}; +//! use serde::{Deserialize, Serialize}; +//! use serde_json::Result; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Address { +//! street: String, +//! city: String, +//! } +//! +//! fn print_an_address() -> Result<()> { +//! // Some data structure. +//! let address = Address { +//! street: "10 Downing Street".to_owned(), +//! city: "London".to_owned(), +//! }; +//! +//! // Serialize it to a JSON string. +//! let j = serde_json::to_string(&address)?; +//! +//! // Print, write to a file, or send to an HTTP server. +//! println!("{}", j); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # print_an_address().unwrap(); +//! # } +//! ``` +//! +//! Any type that implements Serde's `Serialize` trait can be serialized this +//! way. This includes built-in Rust standard library types like `Vec<T>` and +//! `HashMap<K, V>`, as well as any structs or enums annotated with +//! `#[derive(Serialize)]`. +//! +//! # No-std support +//! +//! This crate currently requires the Rust standard library. For JSON support in +//! Serde without a standard library, please see the [`serde-json-core`] crate. +//! +//! [value]: https://docs.serde.rs/serde_json/value/enum.Value.html +//! [from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html +//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html +//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html +//! [to_string]: https://docs.serde.rs/serde_json/ser/fn.to_string.html +//! [to_vec]: https://docs.serde.rs/serde_json/ser/fn.to_vec.html +//! [to_writer]: https://docs.serde.rs/serde_json/ser/fn.to_writer.html +//! [macro]: https://docs.serde.rs/serde_json/macro.json.html +//! [`serde-json-core`]: https://japaric.github.io/serde-json-core/serde_json_core/ + +#![doc(html_root_url = "https://docs.rs/serde_json/1.0.39")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] +// Ignored clippy lints +#![cfg_attr(feature = "cargo-clippy", allow(deprecated_cfg_attr, doc_markdown))] +// Ignored clippy_pedantic lints +#![cfg_attr(feature = "cargo-clippy", allow( + // Deserializer::from_str, into_iter + should_implement_trait, + // integer and float ser/de requires these sorts of casts + cast_possible_wrap, + cast_precision_loss, + cast_sign_loss, + // things are often more readable this way + cast_lossless, + module_name_repetitions, + shadow_unrelated, + single_match_else, + use_self, + zero_prefixed_literal, + // we support older compilers + redundant_field_names, +))] +#![deny(missing_docs)] + +#[macro_use] +extern crate serde; +#[cfg(feature = "preserve_order")] +extern crate indexmap; +extern crate itoa; +extern crate ryu; + +#[doc(inline)] +pub use self::de::{from_reader, from_slice, from_str, Deserializer, StreamDeserializer}; +#[doc(inline)] +pub use self::error::{Error, Result}; +#[doc(inline)] +pub use self::ser::{ + to_string, to_string_pretty, to_vec, to_vec_pretty, to_writer, to_writer_pretty, Serializer, +}; +#[doc(inline)] +pub use self::value::{from_value, to_value, Map, Number, Value}; + +// We only use our own error type; no need for From conversions provided by the +// standard library's try! macro. This reduces lines of LLVM IR by 4%. +macro_rules! try { + ($e:expr) => { + match $e { + ::std::result::Result::Ok(val) => val, + ::std::result::Result::Err(err) => return ::std::result::Result::Err(err), + } + }; +} + +#[macro_use] +mod macros; + +pub mod de; +pub mod error; +pub mod map; +pub mod ser; +pub mod value; + +mod iter; +mod number; +mod read; + +#[cfg(feature = "raw_value")] +mod raw; diff --git a/serde_json/src/macros.rs b/serde_json/src/macros.rs new file mode 100644 index 000000000..16116a017 --- /dev/null +++ b/serde_json/src/macros.rs @@ -0,0 +1,292 @@ +/// Construct a `serde_json::Value` from a JSON literal. +/// +/// ```edition2018 +/// # use serde_json::json; +/// # +/// let value = json!({ +/// "code": 200, +/// "success": true, +/// "payload": { +/// "features": [ +/// "serde", +/// "json" +/// ] +/// } +/// }); +/// ``` +/// +/// Variables or expressions can be interpolated into the JSON literal. Any type +/// interpolated into an array element or object value must implement Serde's +/// `Serialize` trait, while any type interpolated into a object key must +/// implement `Into<String>`. If the `Serialize` implementation of the +/// interpolated type decides to fail, or if the interpolated type contains a +/// map with non-string keys, the `json!` macro will panic. +/// +/// ```edition2018 +/// # use serde_json::json; +/// # +/// let code = 200; +/// let features = vec!["serde", "json"]; +/// +/// let value = json!({ +/// "code": code, +/// "success": code == 200, +/// "payload": { +/// features[0]: features[1] +/// } +/// }); +/// ``` +/// +/// Trailing commas are allowed inside both arrays and objects. +/// +/// ```edition2018 +/// # use serde_json::json; +/// # +/// let value = json!([ +/// "notice", +/// "the", +/// "trailing", +/// "comma -->", +/// ]); +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! json { + // Hide distracting implementation details from the generated rustdoc. + ($($json:tt)+) => { + json_internal!($($json)+) + }; +} + +// Rocket relies on this because they export their own `json!` with a different +// doc comment than ours, and various Rust bugs prevent them from calling our +// `json!` from their `json!` so they call `json_internal!` directly. Check with +// @SergioBenitez before making breaking changes to this macro. +// +// Changes are fine as long as `json_internal!` does not call any new helper +// macros and can still be invoked as `json_internal!($($json)+)`. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! json_internal { + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an array [...]. Produces a vec![...] + // of the elements. + // + // Must be invoked as: json_internal!(@array [] $($tt)*) + ////////////////////////////////////////////////////////////////////////// + + // Done with trailing comma. + (@array [$($elems:expr,)*]) => { + json_internal_vec![$($elems,)*] + }; + + // Done without trailing comma. + (@array [$($elems:expr),*]) => { + json_internal_vec![$($elems),*] + }; + + // Next element is `null`. + (@array [$($elems:expr,)*] null $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*) + }; + + // Next element is `true`. + (@array [$($elems:expr,)*] true $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*) + }; + + // Next element is `false`. + (@array [$($elems:expr,)*] false $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*) + }; + + // Next element is an array. + (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*) + }; + + // Next element is a map. + (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*) + }; + + // Next element is an expression followed by comma. + (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => { + json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*) + }; + + // Last element is an expression with no trailing comma. + (@array [$($elems:expr,)*] $last:expr) => { + json_internal!(@array [$($elems,)* json_internal!($last)]) + }; + + // Comma after the most recent element. + (@array [$($elems:expr),*] , $($rest:tt)*) => { + json_internal!(@array [$($elems,)*] $($rest)*) + }; + + // Unexpected token after most recent element. + (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected) + }; + + ////////////////////////////////////////////////////////////////////////// + // TT muncher for parsing the inside of an object {...}. Each entry is + // inserted into the given map variable. + // + // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*)) + // + // We require two copies of the input tokens so that we can match on one + // copy and trigger errors on the other copy. + ////////////////////////////////////////////////////////////////////////// + + // Done. + (@object $object:ident () () ()) => {}; + + // Insert the current entry followed by trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => { + let _ = $object.insert(($($key)+).into(), $value); + json_internal!(@object $object () ($($rest)*) ($($rest)*)); + }; + + // Current entry followed by unexpected token. + (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => { + json_unexpected!($unexpected); + }; + + // Insert the last entry without trailing comma. + (@object $object:ident [$($key:tt)+] ($value:expr)) => { + let _ = $object.insert(($($key)+).into(), $value); + }; + + // Next value is `null`. + (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*); + }; + + // Next value is `true`. + (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*); + }; + + // Next value is `false`. + (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*); + }; + + // Next value is an array. + (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*); + }; + + // Next value is a map. + (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*); + }; + + // Next value is an expression followed by comma. + (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*); + }; + + // Last value is an expression with no trailing comma. + (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => { + json_internal!(@object $object [$($key)+] (json_internal!($value))); + }; + + // Missing value for last entry. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)+) (:) $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Missing colon and value for last entry. Trigger a reasonable error + // message. + (@object $object:ident ($($key:tt)+) () $copy:tt) => { + // "unexpected end of macro invocation" + json_internal!(); + }; + + // Misplaced colon. Trigger a reasonable error message. + (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `:`". + json_unexpected!($colon); + }; + + // Found a comma inside a key. Trigger a reasonable error message. + (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => { + // Takes no arguments so "no rules expected the token `,`". + json_unexpected!($comma); + }; + + // Key is fully parenthesized. This avoids clippy double_parens false + // positives because the parenthesization may be necessary here. + (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*)); + }; + + // Munch a token into the current key. + (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => { + json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*)); + }; + + ////////////////////////////////////////////////////////////////////////// + // The main implementation. + // + // Must be invoked as: json_internal!($($json)+) + ////////////////////////////////////////////////////////////////////////// + + (null) => { + $crate::Value::Null + }; + + (true) => { + $crate::Value::Bool(true) + }; + + (false) => { + $crate::Value::Bool(false) + }; + + ([]) => { + $crate::Value::Array(json_internal_vec![]) + }; + + ([ $($tt:tt)+ ]) => { + $crate::Value::Array(json_internal!(@array [] $($tt)+)) + }; + + ({}) => { + $crate::Value::Object($crate::Map::new()) + }; + + ({ $($tt:tt)+ }) => { + $crate::Value::Object({ + let mut object = $crate::Map::new(); + json_internal!(@object object () ($($tt)+) ($($tt)+)); + object + }) + }; + + // Any Serialize type: numbers, strings, struct literals, variables etc. + // Must be below every other rule. + ($other:expr) => { + $crate::to_value(&$other).unwrap() + }; +} + +// The json_internal macro above cannot invoke vec directly because it uses +// local_inner_macros. A vec invocation there would resolve to $crate::vec. +// Instead invoke vec here outside of local_inner_macros. +#[macro_export] +#[doc(hidden)] +macro_rules! json_internal_vec { + ($($content:tt)*) => { + vec![$($content)*] + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! json_unexpected { + () => {}; +} diff --git a/serde_json/src/map.rs b/serde_json/src/map.rs new file mode 100644 index 000000000..642463032 --- /dev/null +++ b/serde_json/src/map.rs @@ -0,0 +1,814 @@ +//! A map of String to serde_json::Value. +//! +//! By default the map is backed by a [`BTreeMap`]. Enable the `preserve_order` +//! feature of serde_json to use [`IndexMap`] instead. +//! +//! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html +//! [`IndexMap`]: https://docs.rs/indexmap/*/indexmap/map/struct.IndexMap.html + +use serde::{de, ser}; +use std::borrow::Borrow; +use std::fmt::{self, Debug}; +use std::hash::Hash; +use std::iter::FromIterator; +use std::ops; +use value::Value; + +#[cfg(not(feature = "preserve_order"))] +use std::collections::{btree_map, BTreeMap}; + +#[cfg(feature = "preserve_order")] +use indexmap::{self, IndexMap}; + +/// Represents a JSON key/value type. +pub struct Map<K, V> { + map: MapImpl<K, V>, +} + +#[cfg(not(feature = "preserve_order"))] +type MapImpl<K, V> = BTreeMap<K, V>; +#[cfg(feature = "preserve_order")] +type MapImpl<K, V> = IndexMap<K, V>; + +impl Map<String, Value> { + /// Makes a new empty Map. + #[inline] + pub fn new() -> Self { + Map { + map: MapImpl::new(), + } + } + + #[cfg(not(feature = "preserve_order"))] + /// Makes a new empty Map with the given initial capacity. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + // does not support with_capacity + let _ = capacity; + Map { + map: BTreeMap::new(), + } + } + + #[cfg(feature = "preserve_order")] + /// Makes a new empty Map with the given initial capacity. + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Map { + map: IndexMap::with_capacity(capacity), + } + } + + /// Clears the map, removing all values. + #[inline] + pub fn clear(&mut self) { + self.map.clear() + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&Value> + where + String: Borrow<Q>, + Q: Ord + Eq + Hash, + { + self.map.get(key) + } + + /// Returns true if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool + where + String: Borrow<Q>, + Q: Ord + Eq + Hash, + { + self.map.contains_key(key) + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut Value> + where + String: Borrow<Q>, + Q: Ord + Eq + Hash, + { + self.map.get_mut(key) + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, `None` is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. + #[inline] + pub fn insert(&mut self, k: String, v: Value) -> Option<Value> { + self.map.insert(k, v) + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but the ordering + /// on the borrowed form *must* match the ordering on the key type. + #[inline] + pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<Value> + where + String: Borrow<Q>, + Q: Ord + Eq + Hash, + { + self.map.remove(key) + } + + /// Gets the given key's corresponding entry in the map for in-place + /// manipulation. + pub fn entry<S>(&mut self, key: S) -> Entry + where + S: Into<String>, + { + #[cfg(feature = "preserve_order")] + use indexmap::map::Entry as EntryImpl; + #[cfg(not(feature = "preserve_order"))] + use std::collections::btree_map::Entry as EntryImpl; + + match self.map.entry(key.into()) { + EntryImpl::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant: vacant }), + EntryImpl::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied: occupied }), + } + } + + /// Returns the number of elements in the map. + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns true if the map contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Gets an iterator over the entries of the map. + #[inline] + pub fn iter(&self) -> Iter { + Iter { + iter: self.map.iter(), + } + } + + /// Gets a mutable iterator over the entries of the map. + #[inline] + pub fn iter_mut(&mut self) -> IterMut { + IterMut { + iter: self.map.iter_mut(), + } + } + + /// Gets an iterator over the keys of the map. + #[inline] + pub fn keys(&self) -> Keys { + Keys { + iter: self.map.keys(), + } + } + + /// Gets an iterator over the values of the map. + #[inline] + pub fn values(&self) -> Values { + Values { + iter: self.map.values(), + } + } + + /// Gets an iterator over mutable values of the map. + #[inline] + pub fn values_mut(&mut self) -> ValuesMut { + ValuesMut { + iter: self.map.values_mut(), + } + } +} + +impl Default for Map<String, Value> { + #[inline] + fn default() -> Self { + Map { + map: MapImpl::new(), + } + } +} + +impl Clone for Map<String, Value> { + #[inline] + fn clone(&self) -> Self { + Map { + map: self.map.clone(), + } + } +} + +impl PartialEq for Map<String, Value> { + #[inline] + fn eq(&self, other: &Self) -> bool { + if cfg!(feature = "preserve_order") { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } else { + self.map.eq(&other.map) + } + } +} + +/// Access an element of this map. Panics if the given key is not present in the +/// map. +/// +/// ```edition2018 +/// # use serde_json::Value; +/// # +/// # let val = &Value::String("".to_owned()); +/// # let _ = +/// match *val { +/// Value::String(ref s) => Some(s.as_str()), +/// Value::Array(ref arr) => arr[0].as_str(), +/// Value::Object(ref map) => map["type"].as_str(), +/// _ => None, +/// } +/// # ; +/// ``` +impl<'a, Q: ?Sized> ops::Index<&'a Q> for Map<String, Value> +where + String: Borrow<Q>, + Q: Ord + Eq + Hash, +{ + type Output = Value; + + fn index(&self, index: &Q) -> &Value { + self.map.index(index) + } +} + +/// Mutably access an element of this map. Panics if the given key is not +/// present in the map. +/// +/// ```edition2018 +/// # use serde_json::json; +/// # +/// # let mut map = serde_json::Map::new(); +/// # map.insert("key".to_owned(), serde_json::Value::Null); +/// # +/// map["key"] = json!("value"); +/// ``` +impl<'a, Q: ?Sized> ops::IndexMut<&'a Q> for Map<String, Value> +where + String: Borrow<Q>, + Q: Ord + Eq + Hash, +{ + fn index_mut(&mut self, index: &Q) -> &mut Value { + self.map.get_mut(index).expect("no entry found for key") + } +} + +impl Debug for Map<String, Value> { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.map.fmt(formatter) + } +} + +impl ser::Serialize for Map<String, Value> { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + use serde::ser::SerializeMap; + let mut map = try!(serializer.serialize_map(Some(self.len()))); + for (k, v) in self { + try!(map.serialize_key(k)); + try!(map.serialize_value(v)); + } + map.end() + } +} + +impl<'de> de::Deserialize<'de> for Map<String, Value> { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Map<String, Value>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a map") + } + + #[inline] + fn visit_unit<E>(self) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(Map::new()) + } + + #[inline] + fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: de::MapAccess<'de>, + { + let mut values = Map::new(); + + while let Some((key, value)) = try!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(values) + } + } + + deserializer.deserialize_map(Visitor) + } +} + +impl FromIterator<(String, Value)> for Map<String, Value> { + fn from_iter<T>(iter: T) -> Self + where + T: IntoIterator<Item = (String, Value)>, + { + Map { + map: FromIterator::from_iter(iter), + } + } +} + +impl Extend<(String, Value)> for Map<String, Value> { + fn extend<T>(&mut self, iter: T) + where + T: IntoIterator<Item = (String, Value)>, + { + self.map.extend(iter); + } +} + +macro_rules! delegate_iterator { + (($name:ident $($generics:tt)*) => $item:ty) => { + impl $($generics)* Iterator for $name $($generics)* { + type Item = $item; + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } + } + + impl $($generics)* DoubleEndedIterator for $name $($generics)* { + #[inline] + fn next_back(&mut self) -> Option<Self::Item> { + self.iter.next_back() + } + } + + impl $($generics)* ExactSizeIterator for $name $($generics)* { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`Map`]. +/// +/// [`entry`]: struct.Map.html#method.entry +/// [`Map`]: struct.Map.html +pub enum Entry<'a> { + /// A vacant Entry. + Vacant(VacantEntry<'a>), + /// An occupied Entry. + Occupied(OccupiedEntry<'a>), +} + +/// A vacant Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +pub struct VacantEntry<'a> { + vacant: VacantEntryImpl<'a>, +} + +/// An occupied Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +pub struct OccupiedEntry<'a> { + occupied: OccupiedEntryImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type VacantEntryImpl<'a> = btree_map::VacantEntry<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type VacantEntryImpl<'a> = indexmap::map::VacantEntry<'a, String, Value>; + +#[cfg(not(feature = "preserve_order"))] +type OccupiedEntryImpl<'a> = btree_map::OccupiedEntry<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type OccupiedEntryImpl<'a> = indexmap::map::OccupiedEntry<'a, String, Value>; + +impl<'a> Entry<'a> { + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ```edition2018 + /// let mut map = serde_json::Map::new(); + /// assert_eq!(map.entry("serde").key(), &"serde"); + /// ``` + pub fn key(&self) -> &String { + match *self { + Entry::Vacant(ref e) => e.key(), + Entry::Occupied(ref e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and + /// returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut map = serde_json::Map::new(); + /// map.entry("serde").or_insert(json!(12)); + /// + /// assert_eq!(map["serde"], 12); + /// ``` + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + Entry::Vacant(entry) => entry.insert(default), + Entry::Occupied(entry) => entry.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut map = serde_json::Map::new(); + /// map.entry("serde").or_insert_with(|| json!("hoho")); + /// + /// assert_eq!(map["serde"], "hoho".to_owned()); + /// ``` + pub fn or_insert_with<F>(self, default: F) -> &'a mut Value + where + F: FnOnce() -> Value, + { + match self { + Entry::Vacant(entry) => entry.insert(default()), + Entry::Occupied(entry) => entry.into_mut(), + } + } +} + +impl<'a> VacantEntry<'a> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// + /// match map.entry("serde") { + /// Entry::Vacant(vacant) => { + /// assert_eq!(vacant.key(), &"serde"); + /// } + /// Entry::Occupied(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn key(&self) -> &String { + self.vacant.key() + } + + /// Sets the value of the entry with the VacantEntry's key, and returns a + /// mutable reference to it. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// + /// match map.entry("serde") { + /// Entry::Vacant(vacant) => { + /// vacant.insert(json!("hoho")); + /// } + /// Entry::Occupied(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn insert(self, value: Value) -> &'a mut Value { + self.vacant.insert(value) + } +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.key(), &"serde"); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn key(&self) -> &String { + self.occupied.key() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.get(), 12); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn get(&self) -> &Value { + self.occupied.get() + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!([1, 2, 3])); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// occupied.get_mut().as_array_mut().unwrap().push(json!(4)); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// + /// assert_eq!(map["serde"].as_array().unwrap().len(), 4); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut Value { + self.occupied.get_mut() + } + + /// Converts the entry into a mutable reference to its value. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!([1, 2, 3])); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// occupied.into_mut().as_array_mut().unwrap().push(json!(4)); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// + /// assert_eq!(map["serde"].as_array().unwrap().len(), 4); + /// ``` + #[inline] + pub fn into_mut(self) -> &'a mut Value { + self.occupied.into_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, and returns + /// the entry's old value. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(mut occupied) => { + /// assert_eq!(occupied.insert(json!(13)), 12); + /// assert_eq!(occupied.get(), 13); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn insert(&mut self, value: Value) -> Value { + self.occupied.insert(value) + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// use serde_json::map::Entry; + /// + /// let mut map = serde_json::Map::new(); + /// map.insert("serde".to_owned(), json!(12)); + /// + /// match map.entry("serde") { + /// Entry::Occupied(occupied) => { + /// assert_eq!(occupied.remove(), 12); + /// } + /// Entry::Vacant(_) => unimplemented!(), + /// } + /// ``` + #[inline] + pub fn remove(self) -> Value { + self.occupied.remove() + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> IntoIterator for &'a Map<String, Value> { + type Item = (&'a String, &'a Value); + type IntoIter = Iter<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + Iter { + iter: self.map.iter(), + } + } +} + +/// An iterator over a serde_json::Map's entries. +pub struct Iter<'a> { + iter: IterImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type IterImpl<'a> = btree_map::Iter<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type IterImpl<'a> = indexmap::map::Iter<'a, String, Value>; + +delegate_iterator!((Iter<'a>) => (&'a String, &'a Value)); + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> IntoIterator for &'a mut Map<String, Value> { + type Item = (&'a String, &'a mut Value); + type IntoIter = IterMut<'a>; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IterMut { + iter: self.map.iter_mut(), + } + } +} + +/// A mutable iterator over a serde_json::Map's entries. +pub struct IterMut<'a> { + iter: IterMutImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type IterMutImpl<'a> = btree_map::IterMut<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type IterMutImpl<'a> = indexmap::map::IterMut<'a, String, Value>; + +delegate_iterator!((IterMut<'a>) => (&'a String, &'a mut Value)); + +////////////////////////////////////////////////////////////////////////////// + +impl IntoIterator for Map<String, Value> { + type Item = (String, Value); + type IntoIter = IntoIter; + #[inline] + fn into_iter(self) -> Self::IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +/// An owning iterator over a serde_json::Map's entries. +pub struct IntoIter { + iter: IntoIterImpl, +} + +#[cfg(not(feature = "preserve_order"))] +type IntoIterImpl = btree_map::IntoIter<String, Value>; +#[cfg(feature = "preserve_order")] +type IntoIterImpl = indexmap::map::IntoIter<String, Value>; + +delegate_iterator!((IntoIter) => (String, Value)); + +////////////////////////////////////////////////////////////////////////////// + +/// An iterator over a serde_json::Map's keys. +pub struct Keys<'a> { + iter: KeysImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type KeysImpl<'a> = btree_map::Keys<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type KeysImpl<'a> = indexmap::map::Keys<'a, String, Value>; + +delegate_iterator!((Keys<'a>) => &'a String); + +////////////////////////////////////////////////////////////////////////////// + +/// An iterator over a serde_json::Map's values. +pub struct Values<'a> { + iter: ValuesImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type ValuesImpl<'a> = btree_map::Values<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type ValuesImpl<'a> = indexmap::map::Values<'a, String, Value>; + +delegate_iterator!((Values<'a>) => &'a Value); + +////////////////////////////////////////////////////////////////////////////// + +/// A mutable iterator over a serde_json::Map's values. +pub struct ValuesMut<'a> { + iter: ValuesMutImpl<'a>, +} + +#[cfg(not(feature = "preserve_order"))] +type ValuesMutImpl<'a> = btree_map::ValuesMut<'a, String, Value>; +#[cfg(feature = "preserve_order")] +type ValuesMutImpl<'a> = indexmap::map::ValuesMut<'a, String, Value>; + +delegate_iterator!((ValuesMut<'a>) => &'a mut Value); diff --git a/serde_json/src/number.rs b/serde_json/src/number.rs new file mode 100644 index 000000000..70a8f6d65 --- /dev/null +++ b/serde_json/src/number.rs @@ -0,0 +1,752 @@ +use error::Error; +use serde::de::{self, Unexpected, Visitor}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt::{self, Debug, Display}; + +#[cfg(feature = "arbitrary_precision")] +use itoa; +#[cfg(feature = "arbitrary_precision")] +use ryu; +#[cfg(feature = "arbitrary_precision")] +use serde::de::{IntoDeserializer, MapAccess}; + +use de::ParserNumber; + +#[cfg(feature = "arbitrary_precision")] +use error::ErrorCode; + +#[cfg(feature = "arbitrary_precision")] +/// Not public API. Should be pub(crate). +#[doc(hidden)] +pub const TOKEN: &'static str = "$serde_json::private::Number"; + +/// Represents a JSON number, whether integer or floating point. +#[derive(Clone, PartialEq)] +pub struct Number { + n: N, +} + +#[cfg(not(feature = "arbitrary_precision"))] +#[derive(Copy, Clone, PartialEq)] +enum N { + PosInt(u64), + /// Always less than zero. + NegInt(i64), + /// Always finite. + Float(f64), +} + +#[cfg(feature = "arbitrary_precision")] +type N = String; + +impl Number { + /// Returns true if the `Number` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Number on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert!(v["a"].is_i64()); + /// + /// // Greater than i64::MAX. + /// assert!(!v["b"].is_i64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i64()); + /// ``` + #[inline] + pub fn is_i64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(v) => v <= i64::max_value() as u64, + N::NegInt(_) => true, + N::Float(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + self.as_i64().is_some() + } + + /// Returns true if the `Number` is an integer between zero and `u64::MAX`. + /// + /// For any Number on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert!(v["a"].is_u64()); + /// + /// // Negative integer. + /// assert!(!v["b"].is_u64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u64()); + /// ``` + #[inline] + pub fn is_u64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(_) => true, + N::NegInt(_) | N::Float(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + self.as_u64().is_some() + } + + /// Returns true if the `Number` can be represented by f64. + /// + /// For any Number on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert!(v["a"].is_f64()); + /// + /// // Integers. + /// assert!(!v["b"].is_f64()); + /// assert!(!v["c"].is_f64()); + /// ``` + #[inline] + pub fn is_f64(&self) -> bool { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::Float(_) => true, + N::PosInt(_) | N::NegInt(_) => false, + } + #[cfg(feature = "arbitrary_precision")] + { + for c in self.n.chars() { + if c == '.' || c == 'e' || c == 'E' { + return self.n.parse::<f64>().ok().map_or(false, |f| f.is_finite()); + } + } + false + } + } + + /// If the `Number` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_i64(), Some(64)); + /// assert_eq!(v["b"].as_i64(), None); + /// assert_eq!(v["c"].as_i64(), None); + /// ``` + #[inline] + pub fn as_i64(&self) -> Option<i64> { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => { + if n <= i64::max_value() as u64 { + Some(n as i64) + } else { + None + } + } + N::NegInt(n) => Some(n), + N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// If the `Number` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_u64(), Some(64)); + /// assert_eq!(v["b"].as_u64(), None); + /// assert_eq!(v["c"].as_u64(), None); + /// ``` + #[inline] + pub fn as_u64(&self) -> Option<u64> { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n), + N::NegInt(_) | N::Float(_) => None, + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// Represents the number as f64 if possible. Returns None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert_eq!(v["a"].as_f64(), Some(256.0)); + /// assert_eq!(v["b"].as_f64(), Some(64.0)); + /// assert_eq!(v["c"].as_f64(), Some(-64.0)); + /// ``` + #[inline] + pub fn as_f64(&self) -> Option<f64> { + #[cfg(not(feature = "arbitrary_precision"))] + match self.n { + N::PosInt(n) => Some(n as f64), + N::NegInt(n) => Some(n as f64), + N::Float(n) => Some(n), + } + #[cfg(feature = "arbitrary_precision")] + self.n.parse().ok() + } + + /// Converts a finite `f64` to a `Number`. Infinite or NaN values are not JSON + /// numbers. + /// + /// ```edition2018 + /// # use std::f64; + /// # + /// # use serde_json::Number; + /// # + /// assert!(Number::from_f64(256.0).is_some()); + /// + /// assert!(Number::from_f64(f64::NAN).is_none()); + /// ``` + #[inline] + pub fn from_f64(f: f64) -> Option<Number> { + if f.is_finite() { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f) + } + #[cfg(feature = "arbitrary_precision")] + { + ryu::Buffer::new().format(f).to_owned() + } + }; + Some(Number { n: n }) + } else { + None + } + } + + #[cfg(feature = "arbitrary_precision")] + /// Not public API. Only tests use this. + #[doc(hidden)] + #[inline] + pub fn from_string_unchecked(n: String) -> Self { + Number { n: n } + } +} + +impl fmt::Display for Number { + #[cfg(not(feature = "arbitrary_precision"))] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.n { + N::PosInt(u) => Display::fmt(&u, formatter), + N::NegInt(i) => Display::fmt(&i, formatter), + N::Float(f) => Display::fmt(&f, formatter), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.n, formatter) + } +} + +impl Debug for Number { + #[cfg(not(feature = "arbitrary_precision"))] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut debug = formatter.debug_tuple("Number"); + match self.n { + N::PosInt(i) => { + debug.field(&i); + } + N::NegInt(i) => { + debug.field(&i); + } + N::Float(f) => { + debug.field(&f); + } + } + debug.finish() + } + + #[cfg(feature = "arbitrary_precision")] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Number({})", &self.n) + } +} + +impl Serialize for Number { + #[cfg(not(feature = "arbitrary_precision"))] + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + match self.n { + N::PosInt(u) => serializer.serialize_u64(u), + N::NegInt(i) => serializer.serialize_i64(i), + N::Float(f) => serializer.serialize_f64(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct(TOKEN, 1)?; + s.serialize_field(TOKEN, &self.n)?; + s.end() + } +} + +impl<'de> Deserialize<'de> for Number { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Number, D::Error> + where + D: Deserializer<'de>, + { + struct NumberVisitor; + + impl<'de> Visitor<'de> for NumberVisitor { + type Value = Number; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a JSON number") + } + + #[inline] + fn visit_i64<E>(self, value: i64) -> Result<Number, E> { + Ok(value.into()) + } + + #[inline] + fn visit_u64<E>(self, value: u64) -> Result<Number, E> { + Ok(value.into()) + } + + #[inline] + fn visit_f64<E>(self, value: f64) -> Result<Number, E> + where + E: de::Error, + { + Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number")) + } + + #[cfg(feature = "arbitrary_precision")] + #[inline] + fn visit_map<V>(self, mut visitor: V) -> Result<Number, V::Error> + where + V: de::MapAccess<'de>, + { + let value = visitor.next_key::<NumberKey>()?; + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + let v: NumberFromString = visitor.next_value()?; + Ok(v.value) + } + } + + deserializer.deserialize_any(NumberVisitor) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberKey; + +#[cfg(feature = "arbitrary_precision")] +impl<'de> de::Deserialize<'de> for NumberKey { + fn deserialize<D>(deserializer: D) -> Result<NumberKey, D::Error> + where + D: de::Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid number field") + } + + fn visit_str<E>(self, s: &str) -> Result<(), E> + where + E: de::Error, + { + if s == TOKEN { + Ok(()) + } else { + Err(de::Error::custom("expected field with custom name")) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok(NumberKey) + } +} + +#[cfg(feature = "arbitrary_precision")] +pub struct NumberFromString { + pub value: Number, +} + +#[cfg(feature = "arbitrary_precision")] +impl<'de> de::Deserialize<'de> for NumberFromString { + fn deserialize<D>(deserializer: D) -> Result<NumberFromString, D::Error> + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = NumberFromString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("string containing a number") + } + + fn visit_str<E>(self, s: &str) -> Result<NumberFromString, E> + where + E: de::Error, + { + let n = try!(s.parse().map_err(de::Error::custom)); + Ok(NumberFromString { value: n }) + } + } + + deserializer.deserialize_str(Visitor) + } +} + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +macro_rules! deserialize_any { + (@expand [$($num_string:tt)*]) => { + #[cfg(not(feature = "arbitrary_precision"))] + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self.n { + N::PosInt(u) => visitor.visit_u64(u), + N::NegInt(i) => visitor.visit_i64(i), + N::Float(f) => visitor.visit_f64(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: Visitor<'de> + { + if let Some(u) = self.as_u64() { + return visitor.visit_u64(u); + } else if let Some(i) = self.as_i64() { + return visitor.visit_i64(i); + } else if let Some(f) = self.as_f64() { + if ryu::Buffer::new().format(f) == self.n || f.to_string() == self.n { + return visitor.visit_f64(f); + } + } + + visitor.visit_map(NumberDeserializer { + number: Some(self.$($num_string)*), + }) + } + }; + + (owned) => { + deserialize_any!(@expand [n]); + }; + + (ref) => { + deserialize_any!(@expand [n.clone()]); + }; +} + +macro_rules! deserialize_number { + ($deserialize:ident => $visit:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $deserialize<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + self.deserialize_any(visitor) + } + + #[cfg(feature = "arbitrary_precision")] + fn $deserialize<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: de::Visitor<'de>, + { + visitor.$visit(self.n.parse().map_err(|_| invalid_number())?) + } + } +} + +impl<'de> Deserializer<'de> for Number { + type Error = Error; + + deserialize_any!(owned); + + deserialize_number!(deserialize_i8 => visit_i8); + deserialize_number!(deserialize_i16 => visit_i16); + deserialize_number!(deserialize_i32 => visit_i32); + deserialize_number!(deserialize_i64 => visit_i64); + deserialize_number!(deserialize_u8 => visit_u8); + deserialize_number!(deserialize_u16 => visit_u16); + deserialize_number!(deserialize_u32 => visit_u32); + deserialize_number!(deserialize_u64 => visit_u64); + deserialize_number!(deserialize_f32 => visit_f32); + deserialize_number!(deserialize_f64 => visit_f64); + + serde_if_integer128! { + deserialize_number!(deserialize_i128 => visit_i128); + deserialize_number!(deserialize_u128 => visit_u128); + } + + forward_to_deserialize_any! { + bool char str string bytes byte_buf option unit unit_struct + newtype_struct seq tuple tuple_struct map struct enum identifier + ignored_any + } +} + +impl<'de, 'a> Deserializer<'de> for &'a Number { + type Error = Error; + + deserialize_any!(ref); + + deserialize_number!(deserialize_i8 => visit_i8); + deserialize_number!(deserialize_i16 => visit_i16); + deserialize_number!(deserialize_i32 => visit_i32); + deserialize_number!(deserialize_i64 => visit_i64); + deserialize_number!(deserialize_u8 => visit_u8); + deserialize_number!(deserialize_u16 => visit_u16); + deserialize_number!(deserialize_u32 => visit_u32); + deserialize_number!(deserialize_u64 => visit_u64); + deserialize_number!(deserialize_f32 => visit_f32); + deserialize_number!(deserialize_f64 => visit_f64); + + serde_if_integer128! { + deserialize_number!(deserialize_i128 => visit_i128); + deserialize_number!(deserialize_u128 => visit_u128); + } + + forward_to_deserialize_any! { + bool char str string bytes byte_buf option unit unit_struct + newtype_struct seq tuple tuple_struct map struct enum identifier + ignored_any + } +} + +#[cfg(feature = "arbitrary_precision")] +// Not public API. Should be pub(crate). +#[doc(hidden)] +pub struct NumberDeserializer { + pub number: Option<String>, +} + +#[cfg(feature = "arbitrary_precision")] +impl<'de> MapAccess<'de> for NumberDeserializer { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.number.is_none() { + return Ok(None); + } + seed.deserialize(NumberFieldDeserializer).map(Some) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(self.number.take().unwrap().into_deserializer()) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberFieldDeserializer; + +#[cfg(feature = "arbitrary_precision")] +impl<'de> Deserializer<'de> for NumberFieldDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(TOKEN) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +impl From<ParserNumber> for Number { + fn from(value: ParserNumber) -> Self { + let n = match value { + ParserNumber::F64(f) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::Float(f) + } + #[cfg(feature = "arbitrary_precision")] + { + f.to_string() + } + } + ParserNumber::U64(u) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::PosInt(u) + } + #[cfg(feature = "arbitrary_precision")] + { + u.to_string() + } + } + ParserNumber::I64(i) => { + #[cfg(not(feature = "arbitrary_precision"))] + { + N::NegInt(i) + } + #[cfg(feature = "arbitrary_precision")] + { + i.to_string() + } + } + #[cfg(feature = "arbitrary_precision")] + ParserNumber::String(s) => s, + }; + Number { n: n } + } +} + +macro_rules! impl_from_unsigned { + ( + $($ty:ty),* + ) => { + $( + impl From<$ty> for Number { + #[inline] + fn from(u: $ty) -> Self { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { N::PosInt(u as u64) } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(u).to_owned() + } + }; + Number { n: n } + } + } + )* + }; +} + +macro_rules! impl_from_signed { + ( + $($ty:ty),* + ) => { + $( + impl From<$ty> for Number { + #[inline] + fn from(i: $ty) -> Self { + let n = { + #[cfg(not(feature = "arbitrary_precision"))] + { + if i < 0 { + N::NegInt(i as i64) + } else { + N::PosInt(i as u64) + } + } + #[cfg(feature = "arbitrary_precision")] + { + itoa::Buffer::new().format(i).to_owned() + } + }; + Number { n: n } + } + } + )* + }; +} + +impl_from_unsigned!(u8, u16, u32, u64, usize); +impl_from_signed!(i8, i16, i32, i64, isize); + +#[cfg(feature = "arbitrary_precision")] +serde_if_integer128! { + impl From<i128> for Number { + fn from(i: i128) -> Self { + Number { n: i.to_string() } + } + } + + impl From<u128> for Number { + fn from(u: u128) -> Self { + Number { n: u.to_string() } + } + } +} + +impl Number { + #[cfg(not(feature = "arbitrary_precision"))] + // Not public API. Should be pub(crate). + #[doc(hidden)] + #[cold] + pub fn unexpected(&self) -> Unexpected { + match self.n { + N::PosInt(u) => Unexpected::Unsigned(u), + N::NegInt(i) => Unexpected::Signed(i), + N::Float(f) => Unexpected::Float(f), + } + } + + #[cfg(feature = "arbitrary_precision")] + // Not public API. Should be pub(crate). + #[doc(hidden)] + #[cold] + pub fn unexpected(&self) -> Unexpected { + Unexpected::Other("number") + } +} diff --git a/serde_json/src/raw.rs b/serde_json/src/raw.rs new file mode 100644 index 000000000..9be7cc7a1 --- /dev/null +++ b/serde_json/src/raw.rs @@ -0,0 +1,458 @@ +use std::fmt::{self, Debug, Display}; +use std::mem; + +use serde::de::value::BorrowedStrDeserializer; +use serde::de::{ + self, Deserialize, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, Unexpected, + Visitor, +}; +use serde::ser::{Serialize, SerializeStruct, Serializer}; + +use error::Error; + +/// Reference to a range of bytes encompassing a single valid JSON value in the +/// input data. +/// +/// A `RawValue` can be used to defer parsing parts of a payload until later, +/// or to avoid parsing it at all in the case that part of the payload just +/// needs to be transferred verbatim into a different output object. +/// +/// When serializing, a value of this type will retain its original formatting +/// and will not be minified or pretty-printed. +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::{Deserialize, Serialize}; +/// use serde::{Deserialize, Serialize}; +/// use serde_json::{Result, value::RawValue}; +/// +/// #[derive(Deserialize)] +/// struct Input<'a> { +/// code: u32, +/// #[serde(borrow)] +/// payload: &'a RawValue, +/// } +/// +/// #[derive(Serialize)] +/// struct Output<'a> { +/// info: (u32, &'a RawValue), +/// } +/// +/// // Efficiently rearrange JSON input containing separate "code" and "payload" +/// // keys into a single "info" key holding an array of code and payload. +/// // +/// // This could be done equivalently using serde_json::Value as the type for +/// // payload, but &RawValue will perform netter because it does not require +/// // memory allocation. The correct range of bytes is borrowed from the input +/// // data and pasted verbatim into the output. +/// fn rearrange(input: &str) -> Result<String> { +/// let input: Input = serde_json::from_str(input)?; +/// +/// let output = Output { +/// info: (input.code, input.payload), +/// }; +/// +/// serde_json::to_string(&output) +/// } +/// +/// fn main() -> Result<()> { +/// let out = rearrange(r#" {"code": 200, "payload": {}} "#)?; +/// +/// assert_eq!(out, r#"{"info":[200,{}]}"#); +/// +/// Ok(()) +/// } +/// ``` +/// +/// # Ownership +/// +/// The typical usage of `RawValue` will be in the borrowed form: +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// # use serde_json::value::RawValue; +/// # +/// #[derive(Deserialize)] +/// struct SomeStruct<'a> { +/// #[serde(borrow)] +/// raw_value: &'a RawValue, +/// } +/// ``` +/// +/// The borrowed form is suitable when deserializing through +/// [`serde_json::from_str`] and [`serde_json::from_slice`] which support +/// borrowing from the input data without memory allocation. +/// +/// When deserializing through [`serde_json::from_reader`] you will need to use +/// the boxed form of `RawValue` instead. This is almost as efficient but +/// involves buffering the raw value from the I/O stream into memory. +/// +/// [`serde_json::from_str`]: ../fn.from_str.html +/// [`serde_json::from_slice`]: ../fn.from_slice.html +/// [`serde_json::from_reader`]: ../fn.from_reader.html +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// # use serde_json::value::RawValue; +/// # +/// #[derive(Deserialize)] +/// struct SomeStruct { +/// raw_value: Box<RawValue>, +/// } +/// ``` +/// +/// # Note +/// +/// `RawValue` is only available if serde\_json is built with the `"raw_value"` +/// feature. +/// +/// ```toml +/// [dependencies] +/// serde_json = { version = "1.0", features = ["raw_value"] } +/// ``` +#[repr(C)] +pub struct RawValue { + json: str, +} + +impl RawValue { + fn from_borrowed(json: &str) -> &Self { + unsafe { mem::transmute::<&str, &RawValue>(json) } + } + + fn from_owned(json: Box<str>) -> Box<Self> { + unsafe { mem::transmute::<Box<str>, Box<RawValue>>(json) } + } +} + +impl Clone for Box<RawValue> { + fn clone(&self) -> Self { + (**self).to_owned() + } +} + +impl ToOwned for RawValue { + type Owned = Box<RawValue>; + + fn to_owned(&self) -> Self::Owned { + RawValue::from_owned(self.json.to_owned().into_boxed_str()) + } +} + +impl Default for Box<RawValue> { + fn default() -> Self { + RawValue::from_borrowed("null").to_owned() + } +} + +impl Debug for RawValue { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_tuple("RawValue") + .field(&format_args!("{}", &self.json)) + .finish() + } +} + +impl Display for RawValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.json) + } +} + +impl RawValue { + /// Convert an owned `String` of JSON data to an owned `RawValue`. + /// + /// This function is equivalent to `serde_json::from_str::<Box<RawValue>>` + /// except that we avoid an allocation and memcpy if both of the following + /// are true: + /// + /// - the input has no leading or trailing whitespace, and + /// - the input has capacity equal to its length. + pub fn from_string(json: String) -> Result<Box<Self>, Error> { + { + let borrowed = ::from_str::<&Self>(&json)?; + if borrowed.json.len() < json.len() { + return Ok(borrowed.to_owned()); + } + } + Ok(Self::from_owned(json.into_boxed_str())) + } + + /// Access the JSON text underlying a raw value. + /// + /// # Example + /// + /// ```edition2018 + /// # use serde_derive::Deserialize; + /// use serde::Deserialize; + /// use serde_json::{Result, value::RawValue}; + /// + /// #[derive(Deserialize)] + /// struct Response<'a> { + /// code: u32, + /// #[serde(borrow)] + /// payload: &'a RawValue, + /// } + /// + /// fn process(input: &str) -> Result<()> { + /// let response: Response = serde_json::from_str(input)?; + /// + /// let payload = response.payload.get(); + /// if payload.starts_with('{') { + /// // handle a payload which is a JSON map + /// } else { + /// // handle any other type + /// } + /// + /// Ok(()) + /// } + /// + /// fn main() -> Result<()> { + /// process(r#" {"code": 200, "payload": {}} "#)?; + /// Ok(()) + /// } + /// ``` + pub fn get(&self) -> &str { + &self.json + } +} + +pub const TOKEN: &'static str = "$serde_json::private::RawValue"; + +impl Serialize for RawValue { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut s = serializer.serialize_struct(TOKEN, 1)?; + s.serialize_field(TOKEN, &self.json)?; + s.end() + } +} + +impl<'de: 'a, 'a> Deserialize<'de> for &'a RawValue { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct ReferenceVisitor; + + impl<'de> Visitor<'de> for ReferenceVisitor { + type Value = &'de RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "any valid JSON value") + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: MapAccess<'de>, + { + let value = visitor.next_key::<RawKey>()?; + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + visitor.next_value_seed(ReferenceFromString) + } + } + + deserializer.deserialize_newtype_struct(TOKEN, ReferenceVisitor) + } +} + +impl<'de> Deserialize<'de> for Box<RawValue> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct BoxedVisitor; + + impl<'de> Visitor<'de> for BoxedVisitor { + type Value = Box<RawValue>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "any valid JSON value") + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> + where + V: MapAccess<'de>, + { + let value = visitor.next_key::<RawKey>()?; + if value.is_none() { + return Err(de::Error::invalid_type(Unexpected::Map, &self)); + } + visitor.next_value_seed(BoxedFromString) + } + } + + deserializer.deserialize_newtype_struct(TOKEN, BoxedVisitor) + } +} + +struct RawKey; + +impl<'de> Deserialize<'de> for RawKey { + fn deserialize<D>(deserializer: D) -> Result<RawKey, D::Error> + where + D: Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_str<E>(self, s: &str) -> Result<(), E> + where + E: de::Error, + { + if s == TOKEN { + Ok(()) + } else { + Err(de::Error::custom("unexpected raw value")) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok(RawKey) + } +} + +pub struct ReferenceFromString; + +impl<'de> DeserializeSeed<'de> for ReferenceFromString { + type Value = &'de RawValue; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for ReferenceFromString { + type Value = &'de RawValue; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_borrowed_str<E>(self, s: &'de str) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(RawValue::from_borrowed(s)) + } +} + +pub struct BoxedFromString; + +impl<'de> DeserializeSeed<'de> for BoxedFromString { + type Value = Box<RawValue>; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for BoxedFromString { + type Value = Box<RawValue>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("raw value") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + self.visit_string(s.to_owned()) + } + + fn visit_string<E>(self, s: String) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(RawValue::from_owned(s.into_boxed_str())) + } +} + +struct RawKeyDeserializer; + +impl<'de> Deserializer<'de> for RawKeyDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(TOKEN) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct ignored_any + unit_struct tuple_struct tuple enum identifier + } +} + +pub struct OwnedRawDeserializer { + pub raw_value: Option<String>, +} + +impl<'de> MapAccess<'de> for OwnedRawDeserializer { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.raw_value.is_none() { + return Ok(None); + } + seed.deserialize(RawKeyDeserializer).map(Some) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(self.raw_value.take().unwrap().into_deserializer()) + } +} + +pub struct BorrowedRawDeserializer<'de> { + pub raw_value: Option<&'de str>, +} + +impl<'de> MapAccess<'de> for BorrowedRawDeserializer<'de> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.raw_value.is_none() { + return Ok(None); + } + seed.deserialize(RawKeyDeserializer).map(Some) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: de::DeserializeSeed<'de>, + { + seed.deserialize(BorrowedStrDeserializer::new(self.raw_value.take().unwrap())) + } +} diff --git a/serde_json/src/read.rs b/serde_json/src/read.rs new file mode 100644 index 000000000..71b050413 --- /dev/null +++ b/serde_json/src/read.rs @@ -0,0 +1,859 @@ +use std::ops::Deref; +use std::{char, cmp, io, str}; + +#[cfg(feature = "raw_value")] +use serde::de::Visitor; + +use iter::LineColIterator; + +use error::{Error, ErrorCode, Result}; + +#[cfg(feature = "raw_value")] +use raw::{BorrowedRawDeserializer, OwnedRawDeserializer}; + +/// Trait used by the deserializer for iterating over input. This is manually +/// "specialized" for iterating over &[u8]. Once feature(specialization) is +/// stable we can use actual specialization. +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_json`. +pub trait Read<'de>: private::Sealed { + #[doc(hidden)] + fn next(&mut self) -> Result<Option<u8>>; + #[doc(hidden)] + fn peek(&mut self) -> Result<Option<u8>>; + + /// Only valid after a call to peek(). Discards the peeked byte. + #[doc(hidden)] + fn discard(&mut self); + + /// Position of the most recent call to next(). + /// + /// The most recent call was probably next() and not peek(), but this method + /// should try to return a sensible result if the most recent call was + /// actually peek() because we don't always know. + /// + /// Only called in case of an error, so performance is not important. + #[doc(hidden)] + fn position(&self) -> Position; + + /// Position of the most recent call to peek(). + /// + /// The most recent call was probably peek() and not next(), but this method + /// should try to return a sensible result if the most recent call was + /// actually next() because we don't always know. + /// + /// Only called in case of an error, so performance is not important. + #[doc(hidden)] + fn peek_position(&self) -> Position; + + /// Offset from the beginning of the input to the next byte that would be + /// returned by next() or peek(). + #[doc(hidden)] + fn byte_offset(&self) -> usize; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark using the given scratch space if + /// necessary. The scratch space is initially empty. + #[doc(hidden)] + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>>; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark using the given scratch space if + /// necessary. The scratch space is initially empty. + /// + /// This function returns the raw bytes in the string with escape sequences + /// expanded but without performing unicode validation. + #[doc(hidden)] + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec<u8>, + ) -> Result<Reference<'de, 's, [u8]>>; + + /// Assumes the previous byte was a quotation mark. Parses a JSON-escaped + /// string until the next quotation mark but discards the data. + #[doc(hidden)] + fn ignore_str(&mut self) -> Result<()>; + + /// Assumes the previous byte was a hex escape sequnce ('\u') in a string. + /// Parses next hexadecimal sequence. + #[doc(hidden)] + fn decode_hex_escape(&mut self) -> Result<u16>; + + /// Switch raw buffering mode on. + /// + /// This is used when deserializing `RawValue`. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn begin_raw_buffering(&mut self); + + /// Switch raw buffering mode off and provides the raw buffered data to the + /// given visitor. + #[cfg(feature = "raw_value")] + #[doc(hidden)] + fn end_raw_buffering<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: Visitor<'de>; +} + +pub struct Position { + pub line: usize, + pub column: usize, +} + +pub enum Reference<'b, 'c, T: ?Sized + 'static> { + Borrowed(&'b T), + Copied(&'c T), +} + +impl<'b, 'c, T: ?Sized + 'static> Deref for Reference<'b, 'c, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + match *self { + Reference::Borrowed(b) => b, + Reference::Copied(c) => c, + } + } +} + +/// JSON input source that reads from a std::io input stream. +pub struct IoRead<R> +where + R: io::Read, +{ + iter: LineColIterator<io::Bytes<R>>, + /// Temporary storage of peeked byte. + ch: Option<u8>, + #[cfg(feature = "raw_value")] + raw_buffer: Option<Vec<u8>>, +} + +/// JSON input source that reads from a slice of bytes. +// +// This is more efficient than other iterators because peek() can be read-only +// and we can compute line/col position only if an error happens. +pub struct SliceRead<'a> { + slice: &'a [u8], + /// Index of the *next* byte that will be returned by next() or peek(). + index: usize, + #[cfg(feature = "raw_value")] + raw_buffering_start_index: usize, +} + +/// JSON input source that reads from a UTF-8 string. +// +// Able to elide UTF-8 checks by assuming that the input is valid UTF-8. +pub struct StrRead<'a> { + delegate: SliceRead<'a>, + #[cfg(feature = "raw_value")] + data: &'a str, +} + +// Prevent users from implementing the Read trait. +mod private { + pub trait Sealed {} +} + +////////////////////////////////////////////////////////////////////////////// + +impl<R> IoRead<R> +where + R: io::Read, +{ + /// Create a JSON input source to read from a std::io input stream. + pub fn new(reader: R) -> Self { + #[cfg(not(feature = "raw_value"))] + { + IoRead { + iter: LineColIterator::new(reader.bytes()), + ch: None, + } + } + #[cfg(feature = "raw_value")] + { + IoRead { + iter: LineColIterator::new(reader.bytes()), + ch: None, + raw_buffer: None, + } + } + } +} + +impl<R> private::Sealed for IoRead<R> where R: io::Read {} + +impl<R> IoRead<R> +where + R: io::Read, +{ + fn parse_str_bytes<'s, T, F>( + &'s mut self, + scratch: &'s mut Vec<u8>, + validate: bool, + result: F, + ) -> Result<T> + where + T: 's, + F: FnOnce(&'s Self, &'s [u8]) -> Result<T>, + { + loop { + let ch = try!(next_or_eof(self)); + if !ESCAPE[ch as usize] { + scratch.push(ch); + continue; + } + match ch { + b'"' => { + return result(self, scratch); + } + b'\\' => { + try!(parse_escape(self, scratch)); + } + _ => { + if validate { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + scratch.push(ch); + } + } + } + } +} + +impl<'de, R> Read<'de> for IoRead<R> +where + R: io::Read, +{ + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + match self.ch.take() { + Some(ch) => { + #[cfg(feature = "raw_value")] + { + if let Some(ref mut buf) = self.raw_buffer { + buf.push(ch); + } + } + Ok(Some(ch)) + } + None => match self.iter.next() { + Some(Err(err)) => Err(Error::io(err)), + Some(Ok(ch)) => { + #[cfg(feature = "raw_value")] + { + if let Some(ref mut buf) = self.raw_buffer { + buf.push(ch); + } + } + Ok(Some(ch)) + } + None => Ok(None), + }, + } + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + match self.ch { + Some(ch) => Ok(Some(ch)), + None => match self.iter.next() { + Some(Err(err)) => Err(Error::io(err)), + Some(Ok(ch)) => { + self.ch = Some(ch); + Ok(self.ch) + } + None => Ok(None), + }, + } + } + + #[cfg(not(feature = "raw_value"))] + #[inline] + fn discard(&mut self) { + self.ch = None; + } + + #[cfg(feature = "raw_value")] + fn discard(&mut self) { + if let Some(ch) = self.ch.take() { + if let Some(ref mut buf) = self.raw_buffer { + buf.push(ch); + } + } + } + + fn position(&self) -> Position { + Position { + line: self.iter.line(), + column: self.iter.col(), + } + } + + fn peek_position(&self) -> Position { + // The LineColIterator updates its position during peek() so it has the + // right one here. + self.position() + } + + fn byte_offset(&self) -> usize { + match self.ch { + Some(_) => self.iter.byte_offset() - 1, + None => self.iter.byte_offset(), + } + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>> { + self.parse_str_bytes(scratch, true, as_str) + .map(Reference::Copied) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec<u8>, + ) -> Result<Reference<'de, 's, [u8]>> { + self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes)) + .map(Reference::Copied) + } + + fn ignore_str(&mut self) -> Result<()> { + loop { + let ch = try!(next_or_eof(self)); + if !ESCAPE[ch as usize] { + continue; + } + match ch { + b'"' => { + return Ok(()); + } + b'\\' => { + try!(ignore_escape(self)); + } + _ => { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } + + fn decode_hex_escape(&mut self) -> Result<u16> { + let mut n = 0; + for _ in 0..4 { + match decode_hex_val(try!(next_or_eof(self))) { + None => return error(self, ErrorCode::InvalidEscape), + Some(val) => { + n = (n << 4) + val; + } + } + } + Ok(n) + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffer = Some(Vec::new()); + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: Visitor<'de>, + { + let raw = self.raw_buffer.take().unwrap(); + let raw = String::from_utf8(raw).unwrap(); + visitor.visit_map(OwnedRawDeserializer { + raw_value: Some(raw), + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> SliceRead<'a> { + /// Create a JSON input source to read from a slice of bytes. + pub fn new(slice: &'a [u8]) -> Self { + #[cfg(not(feature = "raw_value"))] + { + SliceRead { + slice: slice, + index: 0, + } + } + #[cfg(feature = "raw_value")] + { + SliceRead { + slice: slice, + index: 0, + raw_buffering_start_index: 0, + } + } + } + + fn position_of_index(&self, i: usize) -> Position { + let mut position = Position { line: 1, column: 0 }; + for ch in &self.slice[..i] { + match *ch { + b'\n' => { + position.line += 1; + position.column = 0; + } + _ => { + position.column += 1; + } + } + } + position + } + + /// The big optimization here over IoRead is that if the string contains no + /// backslash escape sequences, the returned &str is a slice of the raw JSON + /// data so we avoid copying into the scratch space. + fn parse_str_bytes<'s, T: ?Sized, F>( + &'s mut self, + scratch: &'s mut Vec<u8>, + validate: bool, + result: F, + ) -> Result<Reference<'a, 's, T>> + where + T: 's, + F: for<'f> FnOnce(&'s Self, &'f [u8]) -> Result<&'f T>, + { + // Index of the first byte not yet copied into the scratch space. + let mut start = self.index; + + loop { + while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] { + self.index += 1; + } + if self.index == self.slice.len() { + return error(self, ErrorCode::EofWhileParsingString); + } + match self.slice[self.index] { + b'"' => { + if scratch.is_empty() { + // Fast path: return a slice of the raw JSON without any + // copying. + let borrowed = &self.slice[start..self.index]; + self.index += 1; + return result(self, borrowed).map(Reference::Borrowed); + } else { + scratch.extend_from_slice(&self.slice[start..self.index]); + self.index += 1; + return result(self, scratch).map(Reference::Copied); + } + } + b'\\' => { + scratch.extend_from_slice(&self.slice[start..self.index]); + self.index += 1; + try!(parse_escape(self, scratch)); + start = self.index; + } + _ => { + self.index += 1; + if validate { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } + } +} + +impl<'a> private::Sealed for SliceRead<'a> {} + +impl<'a> Read<'a> for SliceRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + // `Ok(self.slice.get(self.index).map(|ch| { self.index += 1; *ch }))` + // is about 10% slower. + Ok(if self.index < self.slice.len() { + let ch = self.slice[self.index]; + self.index += 1; + Some(ch) + } else { + None + }) + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + // `Ok(self.slice.get(self.index).map(|ch| *ch))` is about 10% slower + // for some reason. + Ok(if self.index < self.slice.len() { + Some(self.slice[self.index]) + } else { + None + }) + } + + #[inline] + fn discard(&mut self) { + self.index += 1; + } + + fn position(&self) -> Position { + self.position_of_index(self.index) + } + + fn peek_position(&self) -> Position { + // Cap it at slice.len() just in case the most recent call was next() + // and it returned the last byte. + self.position_of_index(cmp::min(self.slice.len(), self.index + 1)) + } + + fn byte_offset(&self) -> usize { + self.index + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'a, 's, str>> { + self.parse_str_bytes(scratch, true, as_str) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec<u8>, + ) -> Result<Reference<'a, 's, [u8]>> { + self.parse_str_bytes(scratch, false, |_, bytes| Ok(bytes)) + } + + fn ignore_str(&mut self) -> Result<()> { + loop { + while self.index < self.slice.len() && !ESCAPE[self.slice[self.index] as usize] { + self.index += 1; + } + if self.index == self.slice.len() { + return error(self, ErrorCode::EofWhileParsingString); + } + match self.slice[self.index] { + b'"' => { + self.index += 1; + return Ok(()); + } + b'\\' => { + self.index += 1; + try!(ignore_escape(self)); + } + _ => { + return error(self, ErrorCode::ControlCharacterWhileParsingString); + } + } + } + } + + fn decode_hex_escape(&mut self) -> Result<u16> { + if self.index + 4 > self.slice.len() { + self.index = self.slice.len(); + return error(self, ErrorCode::EofWhileParsingString); + } + + let mut n = 0; + for _ in 0..4 { + let ch = decode_hex_val(self.slice[self.index]); + self.index += 1; + match ch { + None => return error(self, ErrorCode::InvalidEscape), + Some(val) => { + n = (n << 4) + val; + } + } + } + Ok(n) + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.raw_buffering_start_index = self.index; + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: Visitor<'a>, + { + let raw = &self.slice[self.raw_buffering_start_index..self.index]; + let raw = str::from_utf8(raw).unwrap(); + visitor.visit_map(BorrowedRawDeserializer { + raw_value: Some(raw), + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl<'a> StrRead<'a> { + /// Create a JSON input source to read from a UTF-8 string. + pub fn new(s: &'a str) -> Self { + #[cfg(not(feature = "raw_value"))] + { + StrRead { + delegate: SliceRead::new(s.as_bytes()), + } + } + #[cfg(feature = "raw_value")] + { + StrRead { + delegate: SliceRead::new(s.as_bytes()), + data: s, + } + } + } +} + +impl<'a> private::Sealed for StrRead<'a> {} + +impl<'a> Read<'a> for StrRead<'a> { + #[inline] + fn next(&mut self) -> Result<Option<u8>> { + self.delegate.next() + } + + #[inline] + fn peek(&mut self) -> Result<Option<u8>> { + self.delegate.peek() + } + + #[inline] + fn discard(&mut self) { + self.delegate.discard(); + } + + fn position(&self) -> Position { + self.delegate.position() + } + + fn peek_position(&self) -> Position { + self.delegate.peek_position() + } + + fn byte_offset(&self) -> usize { + self.delegate.byte_offset() + } + + fn parse_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'a, 's, str>> { + self.delegate.parse_str_bytes(scratch, true, |_, bytes| { + // The input is assumed to be valid UTF-8 and the \u-escapes are + // checked along the way, so don't need to check here. + Ok(unsafe { str::from_utf8_unchecked(bytes) }) + }) + } + + fn parse_str_raw<'s>( + &'s mut self, + scratch: &'s mut Vec<u8>, + ) -> Result<Reference<'a, 's, [u8]>> { + self.delegate.parse_str_raw(scratch) + } + + fn ignore_str(&mut self) -> Result<()> { + self.delegate.ignore_str() + } + + fn decode_hex_escape(&mut self) -> Result<u16> { + self.delegate.decode_hex_escape() + } + + #[cfg(feature = "raw_value")] + fn begin_raw_buffering(&mut self) { + self.delegate.begin_raw_buffering() + } + + #[cfg(feature = "raw_value")] + fn end_raw_buffering<V>(&mut self, visitor: V) -> Result<V::Value> + where + V: Visitor<'a>, + { + let raw = &self.data[self.delegate.raw_buffering_start_index..self.delegate.index]; + visitor.visit_map(BorrowedRawDeserializer { + raw_value: Some(raw), + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +// Lookup table of bytes that must be escaped. A value of true at index i means +// that byte i requires an escape sequence in the input. +static ESCAPE: [bool; 256] = { + const CT: bool = true; // control character \x00...\x1F + const QU: bool = true; // quote \x22 + const BS: bool = true; // backslash \x5C + const __: bool = false; // allow unescaped + [ + // 1 2 3 4 5 6 7 8 9 A B C D E F + CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 0 + CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, CT, // 1 + __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F + ] +}; + +fn next_or_eof<'de, R: ?Sized + Read<'de>>(read: &mut R) -> Result<u8> { + match try!(read.next()) { + Some(b) => Ok(b), + None => error(read, ErrorCode::EofWhileParsingString), + } +} + +fn error<'de, R: ?Sized + Read<'de>, T>(read: &R, reason: ErrorCode) -> Result<T> { + let position = read.position(); + Err(Error::syntax(reason, position.line, position.column)) +} + +fn as_str<'de, 's, R: Read<'de>>(read: &R, slice: &'s [u8]) -> Result<&'s str> { + str::from_utf8(slice).or_else(|_| error(read, ErrorCode::InvalidUnicodeCodePoint)) +} + +/// Parses a JSON escape sequence and appends it into the scratch space. Assumes +/// the previous byte read was a backslash. +fn parse_escape<'de, R: Read<'de>>(read: &mut R, scratch: &mut Vec<u8>) -> Result<()> { + let ch = try!(next_or_eof(read)); + + match ch { + b'"' => scratch.push(b'"'), + b'\\' => scratch.push(b'\\'), + b'/' => scratch.push(b'/'), + b'b' => scratch.push(b'\x08'), + b'f' => scratch.push(b'\x0c'), + b'n' => scratch.push(b'\n'), + b'r' => scratch.push(b'\r'), + b't' => scratch.push(b'\t'), + b'u' => { + let c = match try!(read.decode_hex_escape()) { + 0xDC00...0xDFFF => { + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800...0xDBFF => { + if try!(next_or_eof(read)) != b'\\' { + return error(read, ErrorCode::UnexpectedEndOfHexEscape); + } + if try!(next_or_eof(read)) != b'u' { + return error(read, ErrorCode::UnexpectedEndOfHexEscape); + } + + let n2 = try!(read.decode_hex_escape()); + + if n2 < 0xDC00 || n2 > 0xDFFF { + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + + let n = (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000; + + match char::from_u32(n) { + Some(c) => c, + None => { + return error(read, ErrorCode::InvalidUnicodeCodePoint); + } + } + } + + n => match char::from_u32(n as u32) { + Some(c) => c, + None => { + return error(read, ErrorCode::InvalidUnicodeCodePoint); + } + }, + }; + + scratch.extend_from_slice(c.encode_utf8(&mut [0_u8; 4]).as_bytes()); + } + _ => { + return error(read, ErrorCode::InvalidEscape); + } + } + + Ok(()) +} + +/// Parses a JSON escape sequence and discards the value. Assumes the previous +/// byte read was a backslash. +fn ignore_escape<'de, R: ?Sized + Read<'de>>(read: &mut R) -> Result<()> { + let ch = try!(next_or_eof(read)); + + match ch { + b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't' => {} + b'u' => { + let n = match try!(read.decode_hex_escape()) { + 0xDC00...0xDFFF => { + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800...0xDBFF => { + if try!(next_or_eof(read)) != b'\\' { + return error(read, ErrorCode::UnexpectedEndOfHexEscape); + } + if try!(next_or_eof(read)) != b'u' { + return error(read, ErrorCode::UnexpectedEndOfHexEscape); + } + + let n2 = try!(read.decode_hex_escape()); + + if n2 < 0xDC00 || n2 > 0xDFFF { + return error(read, ErrorCode::LoneLeadingSurrogateInHexEscape); + } + + (((n1 - 0xD800) as u32) << 10 | (n2 - 0xDC00) as u32) + 0x1_0000 + } + + n => n as u32, + }; + + if char::from_u32(n).is_none() { + return error(read, ErrorCode::InvalidUnicodeCodePoint); + } + } + _ => { + return error(read, ErrorCode::InvalidEscape); + } + } + + Ok(()) +} + +static HEX: [u8; 256] = { + const __: u8 = 255; // not a hex digit + [ + // 1 2 3 4 5 6 7 8 9 A B C D E F + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 0 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, __, __, __, __, __, __, // 3 + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 5 + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F + ] +}; + +fn decode_hex_val(val: u8) -> Option<u16> { + let n = HEX[val as usize] as u16; + if n == 255 { + None + } else { + Some(n) + } +} diff --git a/serde_json/src/ser.rs b/serde_json/src/ser.rs new file mode 100644 index 000000000..463c15a16 --- /dev/null +++ b/serde_json/src/ser.rs @@ -0,0 +1,2262 @@ +//! Serialize a Rust data structure into JSON data. + +use std::fmt; +use std::io; +use std::num::FpCategory; +use std::str; + +use super::error::{Error, ErrorCode, Result}; +use serde::ser::{self, Impossible, Serialize}; + +use itoa; +use ryu; + +/// A structure for serializing Rust values into JSON. +pub struct Serializer<W, F = CompactFormatter> { + writer: W, + formatter: F, +} + +impl<W> Serializer<W> +where + W: io::Write, +{ + /// Creates a new JSON serializer. + #[inline] + pub fn new(writer: W) -> Self { + Serializer::with_formatter(writer, CompactFormatter) + } +} + +impl<'a, W> Serializer<W, PrettyFormatter<'a>> +where + W: io::Write, +{ + /// Creates a new JSON pretty print serializer. + #[inline] + pub fn pretty(writer: W) -> Self { + Serializer::with_formatter(writer, PrettyFormatter::new()) + } +} + +impl<W, F> Serializer<W, F> +where + W: io::Write, + F: Formatter, +{ + /// Creates a new JSON visitor whose output will be written to the writer + /// specified. + #[inline] + pub fn with_formatter(writer: W, formatter: F) -> Self { + Serializer { + writer: writer, + formatter: formatter, + } + } + + /// Unwrap the `Writer` from the `Serializer`. + #[inline] + pub fn into_inner(self) -> W { + self.writer + } +} + +impl<'a, W, F> ser::Serializer for &'a mut Serializer<W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + type SerializeSeq = Compound<'a, W, F>; + type SerializeTuple = Compound<'a, W, F>; + type SerializeTupleStruct = Compound<'a, W, F>; + type SerializeTupleVariant = Compound<'a, W, F>; + type SerializeMap = Compound<'a, W, F>; + type SerializeStruct = Compound<'a, W, F>; + type SerializeStructVariant = Compound<'a, W, F>; + + #[inline] + fn serialize_bool(self, value: bool) -> Result<()> { + try!(self + .formatter + .write_bool(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result<()> { + try!(self + .formatter + .write_i8(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result<()> { + try!(self + .formatter + .write_i16(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result<()> { + try!(self + .formatter + .write_i32(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_i64(self, value: i64) -> Result<()> { + try!(self + .formatter + .write_i64(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + serde_if_integer128! { + fn serialize_i128(self, value: i128) -> Result<()> { + self.formatter + .write_number_str(&mut self.writer, &value.to_string()) + .map_err(Error::io) + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result<()> { + try!(self + .formatter + .write_u8(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result<()> { + try!(self + .formatter + .write_u16(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result<()> { + try!(self + .formatter + .write_u32(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result<()> { + try!(self + .formatter + .write_u64(&mut self.writer, value) + .map_err(Error::io)); + Ok(()) + } + + serde_if_integer128! { + fn serialize_u128(self, value: u128) -> Result<()> { + self.formatter + .write_number_str(&mut self.writer, &value.to_string()) + .map_err(Error::io) + } + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result<()> { + match value.classify() { + FpCategory::Nan | FpCategory::Infinite => { + try!(self + .formatter + .write_null(&mut self.writer) + .map_err(Error::io)); + } + _ => { + try!(self + .formatter + .write_f32(&mut self.writer, value) + .map_err(Error::io)); + } + } + Ok(()) + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result<()> { + match value.classify() { + FpCategory::Nan | FpCategory::Infinite => { + try!(self + .formatter + .write_null(&mut self.writer) + .map_err(Error::io)); + } + _ => { + try!(self + .formatter + .write_f64(&mut self.writer, value) + .map_err(Error::io)); + } + } + Ok(()) + } + + #[inline] + fn serialize_char(self, value: char) -> Result<()> { + // A char encoded as UTF-8 takes 4 bytes at most. + let mut buf = [0; 4]; + self.serialize_str(value.encode_utf8(&mut buf)) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + try!(format_escaped_str(&mut self.writer, &mut self.formatter, value).map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_bytes(self, value: &[u8]) -> Result<()> { + use serde::ser::SerializeSeq; + let mut seq = try!(self.serialize_seq(Some(value.len()))); + for byte in value { + try!(seq.serialize_element(byte)); + } + seq.end() + } + + #[inline] + fn serialize_unit(self) -> Result<()> { + try!(self + .formatter + .write_null(&mut self.writer) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.serialize_str(variant) + } + + /// Serialize newtypes without an object wrapper. + #[inline] + fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<()> + where + T: Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<()> + where + T: Serialize, + { + try!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + try!(self.serialize_str(variant)); + try!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + try!(value.serialize(&mut *self)); + try!(self + .formatter + .end_object_value(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .end_object(&mut self.writer) + .map_err(Error::io)); + Ok(()) + } + + #[inline] + fn serialize_none(self) -> Result<()> { + self.serialize_unit() + } + + #[inline] + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<()> + where + T: Serialize, + { + value.serialize(self) + } + + #[inline] + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> { + if len == Some(0) { + try!(self + .formatter + .begin_array(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .end_array(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::Empty, + }) + } else { + try!(self + .formatter + .begin_array(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::First, + }) + } + } + + #[inline] + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct> { + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant> { + try!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + try!(self.serialize_str(variant)); + try!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + self.serialize_seq(Some(len)) + } + + #[inline] + fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> { + if len == Some(0) { + try!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .end_object(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::Empty, + }) + } else { + try!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + Ok(Compound::Map { + ser: self, + state: State::First, + }) + } + } + + #[inline] + fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> { + match name { + #[cfg(feature = "arbitrary_precision")] + ::number::TOKEN => Ok(Compound::Number { ser: self }), + #[cfg(feature = "raw_value")] + ::raw::TOKEN => Ok(Compound::RawValue { ser: self }), + _ => self.serialize_map(Some(len)), + } + } + + #[inline] + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeStructVariant> { + try!(self + .formatter + .begin_object(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_key(&mut self.writer, true) + .map_err(Error::io)); + try!(self.serialize_str(variant)); + try!(self + .formatter + .end_object_key(&mut self.writer) + .map_err(Error::io)); + try!(self + .formatter + .begin_object_value(&mut self.writer) + .map_err(Error::io)); + self.serialize_map(Some(len)) + } + + fn collect_str<T: ?Sized>(self, value: &T) -> Result<Self::Ok> + where + T: fmt::Display, + { + use std::fmt::Write; + + struct Adapter<'ser, W: 'ser, F: 'ser> { + writer: &'ser mut W, + formatter: &'ser mut F, + error: Option<io::Error>, + } + + impl<'ser, W, F> Write for Adapter<'ser, W, F> + where + W: io::Write, + F: Formatter, + { + fn write_str(&mut self, s: &str) -> fmt::Result { + assert!(self.error.is_none()); + match format_escaped_str_contents(self.writer, self.formatter, s) { + Ok(()) => Ok(()), + Err(err) => { + self.error = Some(err); + Err(fmt::Error) + } + } + } + } + + try!(self + .formatter + .begin_string(&mut self.writer) + .map_err(Error::io)); + { + let mut adapter = Adapter { + writer: &mut self.writer, + formatter: &mut self.formatter, + error: None, + }; + match write!(adapter, "{}", value) { + Ok(()) => assert!(adapter.error.is_none()), + Err(fmt::Error) => { + return Err(Error::io(adapter.error.expect("there should be an error"))); + } + } + } + try!(self + .formatter + .end_string(&mut self.writer) + .map_err(Error::io)); + Ok(()) + } +} + +#[derive(Eq, PartialEq)] +/// Not public API. Should be pub(crate). +#[doc(hidden)] +pub enum State { + Empty, + First, + Rest, +} + +/// Not public API. Should be pub(crate). +#[doc(hidden)] +pub enum Compound<'a, W: 'a, F: 'a> { + Map { + ser: &'a mut Serializer<W, F>, + state: State, + }, + #[cfg(feature = "arbitrary_precision")] + Number { ser: &'a mut Serializer<W, F> }, + #[cfg(feature = "raw_value")] + RawValue { ser: &'a mut Serializer<W, F> }, +} + +impl<'a, W, F> ser::SerializeSeq for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()> + where + T: Serialize, + { + match *self { + Compound::Map { + ref mut ser, + ref mut state, + } => { + try!(ser + .formatter + .begin_array_value(&mut ser.writer, *state == State::First) + .map_err(Error::io)); + *state = State::Rest; + try!(value.serialize(&mut **ser)); + try!(ser + .formatter + .end_array_value(&mut ser.writer) + .map_err(Error::io)); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => try!(ser.formatter.end_array(&mut ser.writer).map_err(Error::io)), + } + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeTuple for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()> + where + T: Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, W, F> ser::SerializeTupleStruct for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()> + where + T: Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, W, F> ser::SerializeTupleVariant for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<()> + where + T: Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => try!(ser.formatter.end_array(&mut ser.writer).map_err(Error::io)), + } + try!(ser + .formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io)); + try!(ser.formatter.end_object(&mut ser.writer).map_err(Error::io)); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeMap for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<()> + where + T: Serialize, + { + match *self { + Compound::Map { + ref mut ser, + ref mut state, + } => { + try!(ser + .formatter + .begin_object_key(&mut ser.writer, *state == State::First) + .map_err(Error::io)); + *state = State::Rest; + + try!(key.serialize(MapKeySerializer { ser: *ser })); + + try!(ser + .formatter + .end_object_key(&mut ser.writer) + .map_err(Error::io)); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<()> + where + T: Serialize, + { + match *self { + Compound::Map { ref mut ser, .. } => { + try!(ser + .formatter + .begin_object_value(&mut ser.writer) + .map_err(Error::io)); + try!(value.serialize(&mut **ser)); + try!(ser + .formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io)); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => try!(ser.formatter.end_object(&mut ser.writer).map_err(Error::io)), + } + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +impl<'a, W, F> ser::SerializeStruct for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: Serialize, + { + match *self { + Compound::Map { .. } => { + try!(ser::SerializeMap::serialize_key(self, key)); + ser::SerializeMap::serialize_value(self, value) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { ref mut ser, .. } => { + if key == ::number::TOKEN { + try!(value.serialize(NumberStrEmitter(&mut *ser))); + Ok(()) + } else { + Err(invalid_number()) + } + } + #[cfg(feature = "raw_value")] + Compound::RawValue { ref mut ser, .. } => { + if key == ::raw::TOKEN { + try!(value.serialize(RawValueStrEmitter(&mut *ser))); + Ok(()) + } else { + Err(invalid_raw_value()) + } + } + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { .. } => ser::SerializeMap::end(self), + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => Ok(()), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => Ok(()), + } + } +} + +impl<'a, W, F> ser::SerializeStructVariant for Compound<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: Serialize, + { + match *self { + Compound::Map { .. } => ser::SerializeStruct::serialize_field(self, key, value), + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } + + #[inline] + fn end(self) -> Result<()> { + match self { + Compound::Map { ser, state } => { + match state { + State::Empty => {} + _ => try!(ser.formatter.end_object(&mut ser.writer).map_err(Error::io)), + } + try!(ser + .formatter + .end_object_value(&mut ser.writer) + .map_err(Error::io)); + try!(ser.formatter.end_object(&mut ser.writer).map_err(Error::io)); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + Compound::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + Compound::RawValue { .. } => unreachable!(), + } + } +} + +struct MapKeySerializer<'a, W: 'a, F: 'a> { + ser: &'a mut Serializer<W, F>, +} + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +#[cfg(feature = "raw_value")] +fn invalid_raw_value() -> Error { + Error::syntax(ErrorCode::ExpectedSomeValue, 0, 0) +} + +fn key_must_be_a_string() -> Error { + Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) +} + +impl<'a, W, F> ser::Serializer for MapKeySerializer<'a, W, F> +where + W: io::Write, + F: Formatter, +{ + type Ok = (); + type Error = Error; + + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + self.ser.serialize_str(value) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.ser.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) -> Result<()> + where + T: Serialize, + { + value.serialize(self) + } + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, _value: bool) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_i8(self, value: i8) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_i8(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_i16(self, value: i16) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_i16(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_i32(self, value: i32) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_i32(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_i64(self, value: i64) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_i64(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + serde_if_integer128! { + fn serialize_i128(self, value: i128) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_number_str(&mut self.ser.writer, &value.to_string()) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + } + + fn serialize_u8(self, value: u8) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_u8(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_u16(self, value: u16) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_u16(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_u32(self, value: u32) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_u32(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + fn serialize_u64(self, value: u64) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_u64(&mut self.ser.writer, value) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + + serde_if_integer128! { + fn serialize_u128(self, value: u128) -> Result<()> { + try!(self + .ser + .formatter + .begin_string(&mut self.ser.writer) + .map_err(Error::io)); + try!(self + .ser + .formatter + .write_number_str(&mut self.ser.writer, &value.to_string()) + .map_err(Error::io)); + try!(self + .ser + .formatter + .end_string(&mut self.ser.writer) + .map_err(Error::io)); + Ok(()) + } + } + + fn serialize_f32(self, _value: f32) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_char(self, value: char) -> Result<()> { + self.ser.serialize_str(&value.to_string()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<()> + where + T: Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant> { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant> { + Err(key_must_be_a_string()) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberStrEmitter<'a, W: 'a + io::Write, F: 'a + Formatter>(&'a mut Serializer<W, F>); + +#[cfg(feature = "arbitrary_precision")] +impl<'a, W: io::Write, F: Formatter> ser::Serializer for NumberStrEmitter<'a, W, F> { + type Ok = (); + type Error = Error; + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_i8(self, _v: i8) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_i16(self, _v: i16) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_i32(self, _v: i32) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_i64(self, _v: i64) -> Result<Self::Ok> { + Err(invalid_number()) + } + + serde_if_integer128! { + fn serialize_i128(self, _v: i128) -> Result<Self::Ok> { + Err(invalid_number()) + } + } + + fn serialize_u8(self, _v: u8) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_u16(self, _v: u16) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_u32(self, _v: u32) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_u64(self, _v: u64) -> Result<Self::Ok> { + Err(invalid_number()) + } + + serde_if_integer128! { + fn serialize_u128(self, _v: u128) -> Result<Self::Ok> { + Err(invalid_number()) + } + } + + fn serialize_f32(self, _v: f32) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_f64(self, _v: f64) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_char(self, _v: char) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_str(self, value: &str) -> Result<Self::Ok> { + let NumberStrEmitter(serializer) = self; + serializer + .formatter + .write_number_str(&mut serializer.writer, value) + .map_err(Error::io) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_none(self) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_unit(self) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<Self::Ok> { + Err(invalid_number()) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<Self::Ok> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> { + Err(invalid_number()) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> { + Err(invalid_number()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct> { + Err(invalid_number()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant> { + Err(invalid_number()) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> { + Err(invalid_number()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> { + Err(invalid_number()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant> { + Err(invalid_number()) + } +} + +#[cfg(feature = "raw_value")] +struct RawValueStrEmitter<'a, W: 'a + io::Write, F: 'a + Formatter>(&'a mut Serializer<W, F>); + +#[cfg(feature = "raw_value")] +impl<'a, W: io::Write, F: Formatter> ser::Serializer for RawValueStrEmitter<'a, W, F> { + type Ok = (); + type Error = Error; + + type SerializeSeq = Impossible<(), Error>; + type SerializeTuple = Impossible<(), Error>; + type SerializeTupleStruct = Impossible<(), Error>; + type SerializeTupleVariant = Impossible<(), Error>; + type SerializeMap = Impossible<(), Error>; + type SerializeStruct = Impossible<(), Error>; + type SerializeStructVariant = Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i8(self, _v: i8) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i16(self, _v: i16) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i32(self, _v: i32) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_i64(self, _v: i64) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + serde_if_integer128! { + fn serialize_i128(self, _v: i128) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + } + + fn serialize_u8(self, _v: u8) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u16(self, _v: u16) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u32(self, _v: u32) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_u64(self, _v: u64) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + serde_if_integer128! { + fn serialize_u128(self, _v: u128) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + } + + fn serialize_f32(self, _v: f32) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_f64(self, _v: f64) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_char(self, _v: char) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_str(self, value: &str) -> Result<Self::Ok> { + let RawValueStrEmitter(serializer) = self; + serializer + .formatter + .write_raw_fragment(&mut serializer.writer, value) + .map_err(Error::io) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_none(self) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok> + where + T: Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit(self) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<Self::Ok> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<Self::Ok> + where + T: Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok> + where + T: Serialize, + { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> { + Err(ser::Error::custom("expected RawValue")) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant> { + Err(ser::Error::custom("expected RawValue")) + } +} + +/// Represents a character escape code in a type-safe manner. +pub enum CharEscape { + /// An escaped quote `"` + Quote, + /// An escaped reverse solidus `\` + ReverseSolidus, + /// An escaped solidus `/` + Solidus, + /// An escaped backspace character (usually escaped as `\b`) + Backspace, + /// An escaped form feed character (usually escaped as `\f`) + FormFeed, + /// An escaped line feed character (usually escaped as `\n`) + LineFeed, + /// An escaped carriage return character (usually escaped as `\r`) + CarriageReturn, + /// An escaped tab character (usually escaped as `\t`) + Tab, + /// An escaped ASCII plane control character (usually escaped as + /// `\u00XX` where `XX` are two hex characters) + AsciiControl(u8), +} + +impl CharEscape { + #[inline] + fn from_escape_table(escape: u8, byte: u8) -> CharEscape { + match escape { + self::BB => CharEscape::Backspace, + self::TT => CharEscape::Tab, + self::NN => CharEscape::LineFeed, + self::FF => CharEscape::FormFeed, + self::RR => CharEscape::CarriageReturn, + self::QU => CharEscape::Quote, + self::BS => CharEscape::ReverseSolidus, + self::UU => CharEscape::AsciiControl(byte), + _ => unreachable!(), + } + } +} + +/// This trait abstracts away serializing the JSON control characters, which allows the user to +/// optionally pretty print the JSON output. +pub trait Formatter { + /// Writes a `null` value to the specified writer. + #[inline] + fn write_null<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"null") + } + + /// Writes a `true` or `false` value to the specified writer. + #[inline] + fn write_bool<W: ?Sized>(&mut self, writer: &mut W, value: bool) -> io::Result<()> + where + W: io::Write, + { + let s = if value { + b"true" as &[u8] + } else { + b"false" as &[u8] + }; + writer.write_all(s) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i8<W: ?Sized>(&mut self, writer: &mut W, value: i8) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i16<W: ?Sized>(&mut self, writer: &mut W, value: i16) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i32<W: ?Sized>(&mut self, writer: &mut W, value: i32) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `-123` to the specified writer. + #[inline] + fn write_i64<W: ?Sized>(&mut self, writer: &mut W, value: i64) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u8<W: ?Sized>(&mut self, writer: &mut W, value: u8) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u16<W: ?Sized>(&mut self, writer: &mut W, value: u16) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u32<W: ?Sized>(&mut self, writer: &mut W, value: u32) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes an integer value like `123` to the specified writer. + #[inline] + fn write_u64<W: ?Sized>(&mut self, writer: &mut W, value: u64) -> io::Result<()> + where + W: io::Write, + { + itoa::write(writer, value).map(drop) + } + + /// Writes a floating point value like `-31.26e+12` to the specified writer. + #[inline] + fn write_f32<W: ?Sized>(&mut self, writer: &mut W, value: f32) -> io::Result<()> + where + W: io::Write, + { + let mut buffer = ryu::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes a floating point value like `-31.26e+12` to the specified writer. + #[inline] + fn write_f64<W: ?Sized>(&mut self, writer: &mut W, value: f64) -> io::Result<()> + where + W: io::Write, + { + let mut buffer = ryu::Buffer::new(); + let s = buffer.format(value); + writer.write_all(s.as_bytes()) + } + + /// Writes a number that has already been rendered to a string. + #[inline] + fn write_number_str<W: ?Sized>(&mut self, writer: &mut W, value: &str) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(value.as_bytes()) + } + + /// Called before each series of `write_string_fragment` and + /// `write_char_escape`. Writes a `"` to the specified writer. + #[inline] + fn begin_string<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"\"") + } + + /// Called after each series of `write_string_fragment` and + /// `write_char_escape`. Writes a `"` to the specified writer. + #[inline] + fn end_string<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"\"") + } + + /// Writes a string fragment that doesn't need any escaping to the + /// specified writer. + #[inline] + fn write_string_fragment<W: ?Sized>(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(fragment.as_bytes()) + } + + /// Writes a character escape code to the specified writer. + #[inline] + fn write_char_escape<W: ?Sized>( + &mut self, + writer: &mut W, + char_escape: CharEscape, + ) -> io::Result<()> + where + W: io::Write, + { + use self::CharEscape::*; + + let s = match char_escape { + Quote => b"\\\"", + ReverseSolidus => b"\\\\", + Solidus => b"\\/", + Backspace => b"\\b", + FormFeed => b"\\f", + LineFeed => b"\\n", + CarriageReturn => b"\\r", + Tab => b"\\t", + AsciiControl(byte) => { + static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef"; + let bytes = &[ + b'\\', + b'u', + b'0', + b'0', + HEX_DIGITS[(byte >> 4) as usize], + HEX_DIGITS[(byte & 0xF) as usize], + ]; + return writer.write_all(bytes); + } + }; + + writer.write_all(s) + } + + /// Called before every array. Writes a `[` to the specified + /// writer. + #[inline] + fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"[") + } + + /// Called after every array. Writes a `]` to the specified + /// writer. + #[inline] + fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"]") + } + + /// Called before every array value. Writes a `,` if needed to + /// the specified writer. + #[inline] + fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b",") + } + } + + /// Called after every array value. + #[inline] + fn end_array_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + Ok(()) + } + + /// Called before every object. Writes a `{` to the specified + /// writer. + #[inline] + fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"{") + } + + /// Called after every object. Writes a `}` to the specified + /// writer. + #[inline] + fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b"}") + } + + /// Called before every object key. + #[inline] + fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: io::Write, + { + if first { + Ok(()) + } else { + writer.write_all(b",") + } + } + + /// Called after every object key. A `:` should be written to the + /// specified writer by either this method or + /// `begin_object_value`. + #[inline] + fn end_object_key<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + Ok(()) + } + + /// Called before every object value. A `:` should be written to + /// the specified writer by either this method or + /// `end_object_key`. + #[inline] + fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b":") + } + + /// Called after every object value. + #[inline] + fn end_object_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + Ok(()) + } + + /// Writes a raw JSON fragment that doesn't need any escaping to the + /// specified writer. + #[inline] + fn write_raw_fragment<W: ?Sized>(&mut self, writer: &mut W, fragment: &str) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(fragment.as_bytes()) + } +} + +/// This structure compacts a JSON value with no extra whitespace. +#[derive(Clone, Debug)] +pub struct CompactFormatter; + +impl Formatter for CompactFormatter {} + +/// This structure pretty prints a JSON value to make it human readable. +#[derive(Clone, Debug)] +pub struct PrettyFormatter<'a> { + current_indent: usize, + has_value: bool, + indent: &'a [u8], +} + +impl<'a> PrettyFormatter<'a> { + /// Construct a pretty printer formatter that defaults to using two spaces for indentation. + pub fn new() -> Self { + PrettyFormatter::with_indent(b" ") + } + + /// Construct a pretty printer formatter that uses the `indent` string for indentation. + pub fn with_indent(indent: &'a [u8]) -> Self { + PrettyFormatter { + current_indent: 0, + has_value: false, + indent: indent, + } + } +} + +impl<'a> Default for PrettyFormatter<'a> { + fn default() -> Self { + PrettyFormatter::new() + } +} + +impl<'a> Formatter for PrettyFormatter<'a> { + #[inline] + fn begin_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"[") + } + + #[inline] + fn end_array<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.current_indent -= 1; + + if self.has_value { + try!(writer.write_all(b"\n")); + try!(indent(writer, self.current_indent, self.indent)); + } + + writer.write_all(b"]") + } + + #[inline] + fn begin_array_value<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: io::Write, + { + if first { + try!(writer.write_all(b"\n")); + } else { + try!(writer.write_all(b",\n")); + } + try!(indent(writer, self.current_indent, self.indent)); + Ok(()) + } + + #[inline] + fn end_array_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.has_value = true; + Ok(()) + } + + #[inline] + fn begin_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.current_indent += 1; + self.has_value = false; + writer.write_all(b"{") + } + + #[inline] + fn end_object<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.current_indent -= 1; + + if self.has_value { + try!(writer.write_all(b"\n")); + try!(indent(writer, self.current_indent, self.indent)); + } + + writer.write_all(b"}") + } + + #[inline] + fn begin_object_key<W: ?Sized>(&mut self, writer: &mut W, first: bool) -> io::Result<()> + where + W: io::Write, + { + if first { + try!(writer.write_all(b"\n")); + } else { + try!(writer.write_all(b",\n")); + } + indent(writer, self.current_indent, self.indent) + } + + #[inline] + fn begin_object_value<W: ?Sized>(&mut self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(b": ") + } + + #[inline] + fn end_object_value<W: ?Sized>(&mut self, _writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.has_value = true; + Ok(()) + } +} + +fn format_escaped_str<W: ?Sized, F: ?Sized>( + writer: &mut W, + formatter: &mut F, + value: &str, +) -> io::Result<()> +where + W: io::Write, + F: Formatter, +{ + try!(formatter.begin_string(writer)); + try!(format_escaped_str_contents(writer, formatter, value)); + try!(formatter.end_string(writer)); + Ok(()) +} + +fn format_escaped_str_contents<W: ?Sized, F: ?Sized>( + writer: &mut W, + formatter: &mut F, + value: &str, +) -> io::Result<()> +where + W: io::Write, + F: Formatter, +{ + let bytes = value.as_bytes(); + + let mut start = 0; + + for (i, &byte) in bytes.iter().enumerate() { + let escape = ESCAPE[byte as usize]; + if escape == 0 { + continue; + } + + if start < i { + try!(formatter.write_string_fragment(writer, &value[start..i])); + } + + let char_escape = CharEscape::from_escape_table(escape, byte); + try!(formatter.write_char_escape(writer, char_escape)); + + start = i + 1; + } + + if start != bytes.len() { + try!(formatter.write_string_fragment(writer, &value[start..])); + } + + Ok(()) +} + +const BB: u8 = b'b'; // \x08 +const TT: u8 = b't'; // \x09 +const NN: u8 = b'n'; // \x0A +const FF: u8 = b'f'; // \x0C +const RR: u8 = b'r'; // \x0D +const QU: u8 = b'"'; // \x22 +const BS: u8 = b'\\'; // \x5C +const UU: u8 = b'u'; // \x00...\x1F except the ones above +const __: u8 = 0; + +// Lookup table of escape sequences. A value of b'x' at index i means that byte +// i is escaped as "\x" in JSON. A value of 0 means that byte i is not escaped. +static ESCAPE: [u8; 256] = [ + // 1 2 3 4 5 6 7 8 9 A B C D E F + UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, // 0 + UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, // 1 + __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 3 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, // 5 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 8 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 9 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // A + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // B + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // C + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // D + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // E + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F +]; + +/// Serialize the given data structure as JSON into the IO stream. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_writer<W, T: ?Sized>(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: Serialize, +{ + let mut ser = Serializer::new(writer); + try!(value.serialize(&mut ser)); + Ok(()) +} + +/// Serialize the given data structure as pretty-printed JSON into the IO +/// stream. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_writer_pretty<W, T: ?Sized>(writer: W, value: &T) -> Result<()> +where + W: io::Write, + T: Serialize, +{ + let mut ser = Serializer::pretty(writer); + try!(value.serialize(&mut ser)); + Ok(()) +} + +/// Serialize the given data structure as a JSON byte vector. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>> +where + T: Serialize, +{ + let mut writer = Vec::with_capacity(128); + try!(to_writer(&mut writer, value)); + Ok(writer) +} + +/// Serialize the given data structure as a pretty-printed JSON byte vector. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_vec_pretty<T: ?Sized>(value: &T) -> Result<Vec<u8>> +where + T: Serialize, +{ + let mut writer = Vec::with_capacity(128); + try!(to_writer_pretty(&mut writer, value)); + Ok(writer) +} + +/// Serialize the given data structure as a String of JSON. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_string<T: ?Sized>(value: &T) -> Result<String> +where + T: Serialize, +{ + let vec = try!(to_vec(value)); + let string = unsafe { + // We do not emit invalid UTF-8. + String::from_utf8_unchecked(vec) + }; + Ok(string) +} + +/// Serialize the given data structure as a pretty-printed String of JSON. +/// +/// # Errors +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +#[inline] +pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String> +where + T: Serialize, +{ + let vec = try!(to_vec_pretty(value)); + let string = unsafe { + // We do not emit invalid UTF-8. + String::from_utf8_unchecked(vec) + }; + Ok(string) +} + +fn indent<W: ?Sized>(wr: &mut W, n: usize, s: &[u8]) -> io::Result<()> +where + W: io::Write, +{ + for _ in 0..n { + try!(wr.write_all(s)); + } + + Ok(()) +} diff --git a/serde_json/src/value/de.rs b/serde_json/src/value/de.rs new file mode 100644 index 000000000..a1f40cf92 --- /dev/null +++ b/serde_json/src/value/de.rs @@ -0,0 +1,1480 @@ +use std::borrow::Cow; +use std::fmt; +use std::slice; +use std::str; +use std::vec; + +use serde; +use serde::de::{ + Deserialize, DeserializeSeed, EnumAccess, Expected, IntoDeserializer, MapAccess, SeqAccess, + Unexpected, VariantAccess, Visitor, +}; + +use error::Error; +use map::Map; +use number::Number; +use value::Value; + +use serde::de; + +#[cfg(feature = "arbitrary_precision")] +use number::NumberFromString; + +impl<'de> Deserialize<'de> for Value { + #[inline] + fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> + where + D: serde::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any valid JSON value") + } + + #[inline] + fn visit_bool<E>(self, value: bool) -> Result<Value, E> { + Ok(Value::Bool(value)) + } + + #[inline] + fn visit_i64<E>(self, value: i64) -> Result<Value, E> { + Ok(Value::Number(value.into())) + } + + #[inline] + fn visit_u64<E>(self, value: u64) -> Result<Value, E> { + Ok(Value::Number(value.into())) + } + + #[inline] + fn visit_f64<E>(self, value: f64) -> Result<Value, E> { + Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) + } + + #[inline] + fn visit_str<E>(self, value: &str) -> Result<Value, E> + where + E: serde::de::Error, + { + self.visit_string(String::from(value)) + } + + #[inline] + fn visit_string<E>(self, value: String) -> Result<Value, E> { + Ok(Value::String(value)) + } + + #[inline] + fn visit_none<E>(self) -> Result<Value, E> { + Ok(Value::Null) + } + + #[inline] + fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error> + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer) + } + + #[inline] + fn visit_unit<E>(self) -> Result<Value, E> { + Ok(Value::Null) + } + + #[inline] + fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error> + where + V: SeqAccess<'de>, + { + let mut vec = Vec::new(); + + while let Some(elem) = try!(visitor.next_element()) { + vec.push(elem); + } + + Ok(Value::Array(vec)) + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error> + where + V: MapAccess<'de>, + { + match visitor.next_key_seed(KeyClassifier)? { + #[cfg(feature = "arbitrary_precision")] + Some(KeyClass::Number) => { + let number: NumberFromString = visitor.next_value()?; + Ok(Value::Number(number.value)) + } + #[cfg(feature = "raw_value")] + Some(KeyClass::RawValue) => { + let value = visitor.next_value_seed(::raw::BoxedFromString)?; + ::from_str(value.get()).map_err(de::Error::custom) + } + Some(KeyClass::Map(first_key)) => { + let mut values = Map::new(); + + values.insert(first_key, try!(visitor.next_value())); + while let Some((key, value)) = try!(visitor.next_entry()) { + values.insert(key, value); + } + + Ok(Value::Object(values)) + } + None => Ok(Value::Object(Map::new())), + } + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl str::FromStr for Value { + type Err = Error; + fn from_str(s: &str) -> Result<Value, Error> { + super::super::de::from_str(s) + } +} + +macro_rules! deserialize_prim_number { + ($method:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $method<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn $method<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self { + Value::Number(n) => n.$method(visitor), + _ => self.deserialize_any(visitor), + } + } + } +} + +fn visit_array<'de, V>(array: Vec<Value>, visitor: V) -> Result<V::Value, Error> +where + V: Visitor<'de>, +{ + let len = array.len(); + let mut deserializer = SeqDeserializer::new(array); + let seq = try!(visitor.visit_seq(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } +} + +fn visit_object<'de, V>(object: Map<String, Value>, visitor: V) -> Result<V::Value, Error> +where + V: Visitor<'de>, +{ + let len = object.len(); + let mut deserializer = MapDeserializer::new(object); + let map = try!(visitor.visit_map(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in map", + )) + } +} + +impl<'de> serde::Deserializer<'de> for Value { + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::Number(n) => n.deserialize_any(visitor), + Value::String(v) => visitor.visit_string(v), + Value::Array(v) => visit_array(v, visitor), + Value::Object(v) => visit_object(v, visitor), + } + } + + deserialize_prim_number!(deserialize_i8); + deserialize_prim_number!(deserialize_i16); + deserialize_prim_number!(deserialize_i32); + deserialize_prim_number!(deserialize_i64); + deserialize_prim_number!(deserialize_u8); + deserialize_prim_number!(deserialize_u16); + deserialize_prim_number!(deserialize_u32); + deserialize_prim_number!(deserialize_u64); + deserialize_prim_number!(deserialize_f32); + deserialize_prim_number!(deserialize_f64); + + serde_if_integer128! { + deserialize_prim_number!(deserialize_i128); + deserialize_prim_number!(deserialize_u128); + } + + #[inline] + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + #[inline] + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + let (variant, value) = match self { + Value::Object(value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + Value::String(variant) => (variant, None), + other => { + return Err(serde::de::Error::invalid_type( + other.unexpected(), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumDeserializer { + variant: variant, + value: value, + }) + } + + #[inline] + fn deserialize_newtype_struct<V>( + self, + name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == ::raw::TOKEN { + return visitor.visit_map(::raw::OwnedRawDeserializer { + raw_value: Some(self.to_string()), + }); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_string(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_byte_buf(visitor) + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::String(v) => visitor.visit_string(v), + Value::Array(v) => visit_array(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct<V>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::Object(v) => visit_object(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct<V>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match self { + Value::Array(v) => visit_array(v, visitor), + Value::Object(v) => visit_object(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_string(visitor) + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + drop(self); + visitor.visit_unit() + } +} + +struct EnumDeserializer { + variant: String, + value: Option<Value>, +} + +impl<'de> EnumAccess<'de> for EnumDeserializer { + type Error = Error; + type Variant = VariantDeserializer; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +struct VariantDeserializer { + value: Option<Value>, +} + +impl<'de> VariantAccess<'de> for VariantDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error> + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Array(v)) => { + serde::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self.value { + Some(Value::Object(v)) => { + serde::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + _ => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqDeserializer { + iter: vec::IntoIter<Value>, +} + +impl SeqDeserializer { + fn new(vec: Vec<Value>) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + } + } +} + +impl<'de> serde::Deserializer<'de> for SeqDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = try!(visitor.visit_seq(&mut self)); + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de> SeqAccess<'de> for SeqDeserializer { + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapDeserializer { + iter: <Map<String, Value> as IntoIterator>::IntoIter, + value: Option<Value>, +} + +impl MapDeserializer { + fn new(map: Map<String, Value>) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapDeserializer { + type Error = Error; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + let key_de = MapKeyDeserializer { + key: Cow::Owned(key), + }; + seed.deserialize(key_de).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Error> + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> serde::Deserializer<'de> for MapDeserializer { + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +macro_rules! deserialize_value_ref_number { + ($method:ident) => { + #[cfg(not(feature = "arbitrary_precision"))] + fn $method<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match *self { + Value::Number(ref n) => n.deserialize_any(visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + #[cfg(feature = "arbitrary_precision")] + fn $method<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match *self { + Value::Number(ref n) => n.$method(visitor), + _ => self.deserialize_any(visitor), + } + } + } +} + +fn visit_array_ref<'de, V>(array: &'de [Value], visitor: V) -> Result<V::Value, Error> +where + V: Visitor<'de>, +{ + let len = array.len(); + let mut deserializer = SeqRefDeserializer::new(array); + let seq = try!(visitor.visit_seq(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } +} + +fn visit_object_ref<'de, V>(object: &'de Map<String, Value>, visitor: V) -> Result<V::Value, Error> +where + V: Visitor<'de>, +{ + let len = object.len(); + let mut deserializer = MapRefDeserializer::new(object); + let map = try!(visitor.visit_map(&mut deserializer)); + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in map", + )) + } +} + +impl<'de> serde::Deserializer<'de> for &'de Value { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match *self { + Value::Null => visitor.visit_unit(), + Value::Bool(v) => visitor.visit_bool(v), + Value::Number(ref n) => n.deserialize_any(visitor), + Value::String(ref v) => visitor.visit_borrowed_str(v), + Value::Array(ref v) => visit_array_ref(v, visitor), + Value::Object(ref v) => visit_object_ref(v, visitor), + } + } + + deserialize_value_ref_number!(deserialize_i8); + deserialize_value_ref_number!(deserialize_i16); + deserialize_value_ref_number!(deserialize_i32); + deserialize_value_ref_number!(deserialize_i64); + deserialize_value_ref_number!(deserialize_u8); + deserialize_value_ref_number!(deserialize_u16); + deserialize_value_ref_number!(deserialize_u32); + deserialize_value_ref_number!(deserialize_u64); + deserialize_value_ref_number!(deserialize_f32); + deserialize_value_ref_number!(deserialize_f64); + + serde_if_integer128! { + deserialize_prim_number!(deserialize_i128); + deserialize_prim_number!(deserialize_u128); + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match *self { + Value::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } + + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + let (variant, value) = match *self { + Value::Object(ref value) => { + let mut iter = value.into_iter(); + let (variant, value) = match iter.next() { + Some(v) => v, + None => { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + }; + // enums are encoded in json as maps with a single key:value pair + if iter.next().is_some() { + return Err(serde::de::Error::invalid_value( + Unexpected::Map, + &"map with a single key", + )); + } + (variant, Some(value)) + } + Value::String(ref variant) => (variant, None), + ref other => { + return Err(serde::de::Error::invalid_type( + other.unexpected(), + &"string or map", + )); + } + }; + + visitor.visit_enum(EnumRefDeserializer { + variant: variant, + value: value, + }) + } + + #[inline] + fn deserialize_newtype_struct<V>( + self, + name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + #[cfg(feature = "raw_value")] + { + if name == ::raw::TOKEN { + return visitor.visit_map(::raw::OwnedRawDeserializer { + raw_value: Some(self.to_string()), + }); + } + } + + let _ = name; + visitor.visit_newtype_struct(self) + } + + fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::Bool(v) => visitor.visit_bool(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::String(ref v) => visitor.visit_borrowed_str(v), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::String(ref v) => visitor.visit_borrowed_str(v), + Value::Array(ref v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::Null => visitor.visit_unit(), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_unit_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_unit(visitor) + } + + fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::Array(ref v) => visit_array_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_tuple_struct<V>( + self, + _name: &'static str, + _len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_seq(visitor) + } + + fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::Object(ref v) => visit_object_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_struct<V>( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + match *self { + Value::Array(ref v) => visit_array_ref(v, visitor), + Value::Object(ref v) => visit_object_ref(v, visitor), + _ => Err(self.invalid_type(&visitor)), + } + } + + fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: Visitor<'de>, + { + visitor.visit_unit() + } +} + +struct EnumRefDeserializer<'de> { + variant: &'de str, + value: Option<&'de Value>, +} + +impl<'de> EnumAccess<'de> for EnumRefDeserializer<'de> { + type Error = Error; + type Variant = VariantRefDeserializer<'de>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error> + where + V: DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantRefDeserializer { value: self.value }; + seed.deserialize(variant).map(|v| (v, visitor)) + } +} + +struct VariantRefDeserializer<'de> { + value: Option<&'de Value>, +} + +impl<'de> VariantAccess<'de> for VariantRefDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Error> { + match self.value { + Some(value) => Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error> + where + T: DeserializeSeed<'de>, + { + match self.value { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self.value { + Some(&Value::Array(ref v)) => { + serde::Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor) + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"tuple variant", + )), + None => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match self.value { + Some(&Value::Object(ref v)) => { + serde::Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor) + } + Some(other) => Err(serde::de::Error::invalid_type( + other.unexpected(), + &"struct variant", + )), + _ => Err(serde::de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )), + } + } +} + +struct SeqRefDeserializer<'de> { + iter: slice::Iter<'de, Value>, +} + +impl<'de> SeqRefDeserializer<'de> { + fn new(slice: &'de [Value]) -> Self { + SeqRefDeserializer { iter: slice.iter() } + } +} + +impl<'de> serde::Deserializer<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + #[inline] + fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + let len = self.iter.len(); + if len == 0 { + visitor.visit_unit() + } else { + let ret = try!(visitor.visit_seq(&mut self)); + let remaining = self.iter.len(); + if remaining == 0 { + Ok(ret) + } else { + Err(serde::de::Error::invalid_length( + len, + &"fewer elements in array", + )) + } + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de> SeqAccess<'de> for SeqRefDeserializer<'de> { + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapRefDeserializer<'de> { + iter: <&'de Map<String, Value> as IntoIterator>::IntoIter, + value: Option<&'de Value>, +} + +impl<'de> MapRefDeserializer<'de> { + fn new(map: &'de Map<String, Value>) -> Self { + MapRefDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> MapAccess<'de> for MapRefDeserializer<'de> { + type Error = Error; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Error> + where + T: DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some(value); + let key_de = MapKeyDeserializer { + key: Cow::Borrowed(&**key), + }; + seed.deserialize(key_de).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Error> + where + T: DeserializeSeed<'de>, + { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => Err(serde::de::Error::custom("value is missing")), + } + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> serde::Deserializer<'de> for MapRefDeserializer<'de> { + type Error = Error; + + #[inline] + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +struct MapKeyDeserializer<'de> { + key: Cow<'de, str>, +} + +macro_rules! deserialize_integer_key { + ($method:ident => $visit:ident) => { + fn $method<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + match (self.key.parse(), self.key) { + (Ok(integer), _) => visitor.$visit(integer), + (Err(_), Cow::Borrowed(s)) => visitor.visit_borrowed_str(s), + (Err(_), Cow::Owned(s)) => visitor.visit_string(s), + } + } + } +} + +impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor) + } + + deserialize_integer_key!(deserialize_i8 => visit_i8); + deserialize_integer_key!(deserialize_i16 => visit_i16); + deserialize_integer_key!(deserialize_i32 => visit_i32); + deserialize_integer_key!(deserialize_i64 => visit_i64); + deserialize_integer_key!(deserialize_u8 => visit_u8); + deserialize_integer_key!(deserialize_u16 => visit_u16); + deserialize_integer_key!(deserialize_u32 => visit_u32); + deserialize_integer_key!(deserialize_u64 => visit_u64); + + serde_if_integer128! { + deserialize_integer_key!(deserialize_i128 => visit_i128); + deserialize_integer_key!(deserialize_u128 => visit_u128); + } + + #[inline] + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + // Map keys cannot be null. + visitor.visit_some(self) + } + + #[inline] + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_enum<V>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: Visitor<'de>, + { + self.key + .into_deserializer() + .deserialize_enum(name, variants, visitor) + } + + forward_to_deserialize_any! { + bool f32 f64 char str string bytes byte_buf unit unit_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +struct KeyClassifier; + +enum KeyClass { + Map(String), + #[cfg(feature = "arbitrary_precision")] + Number, + #[cfg(feature = "raw_value")] + RawValue, +} + +impl<'de> DeserializeSeed<'de> for KeyClassifier { + type Value = KeyClass; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(self) + } +} + +impl<'de> Visitor<'de> for KeyClassifier { + type Value = KeyClass; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string key") + } + + fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> + where + E: de::Error, + { + match s { + #[cfg(feature = "arbitrary_precision")] + ::number::TOKEN => Ok(KeyClass::Number), + #[cfg(feature = "raw_value")] + ::raw::TOKEN => Ok(KeyClass::RawValue), + _ => Ok(KeyClass::Map(s.to_owned())), + } + } + + fn visit_string<E>(self, s: String) -> Result<Self::Value, E> + where + E: de::Error, + { + match s.as_str() { + #[cfg(feature = "arbitrary_precision")] + ::number::TOKEN => Ok(KeyClass::Number), + #[cfg(feature = "raw_value")] + ::raw::TOKEN => Ok(KeyClass::RawValue), + _ => Ok(KeyClass::Map(s)), + } + } +} + +impl Value { + #[cold] + fn invalid_type<E>(&self, exp: &Expected) -> E + where + E: serde::de::Error, + { + serde::de::Error::invalid_type(self.unexpected(), exp) + } + + #[cold] + fn unexpected(&self) -> Unexpected { + match *self { + Value::Null => Unexpected::Unit, + Value::Bool(b) => Unexpected::Bool(b), + Value::Number(ref n) => n.unexpected(), + Value::String(ref s) => Unexpected::Str(s), + Value::Array(_) => Unexpected::Seq, + Value::Object(_) => Unexpected::Map, + } + } +} + +struct BorrowedCowStrDeserializer<'de> { + value: Cow<'de, str>, +} + +impl<'de> BorrowedCowStrDeserializer<'de> { + fn new(value: Cow<'de, str>) -> Self { + BorrowedCowStrDeserializer { value: value } + } +} + +impl<'de> de::Deserializer<'de> for BorrowedCowStrDeserializer<'de> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value { + Cow::Borrowed(string) => visitor.visit_borrowed_str(string), + Cow::Owned(string) => visitor.visit_string(string), + } + } + + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + visitor.visit_enum(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct identifier ignored_any + } +} + +impl<'de> de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> { + type Error = Error; + type Variant = UnitOnly; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: de::DeserializeSeed<'de>, + { + let value = seed.deserialize(self)?; + Ok((value, UnitOnly)) + } +} + +struct UnitOnly; + +impl<'de> de::VariantAccess<'de> for UnitOnly { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + Err(de::Error::invalid_type( + Unexpected::UnitVariant, + &"struct variant", + )) + } +} diff --git a/serde_json/src/value/from.rs b/serde_json/src/value/from.rs new file mode 100644 index 000000000..d647deae8 --- /dev/null +++ b/serde_json/src/value/from.rs @@ -0,0 +1,213 @@ +use std::borrow::Cow; + +use super::Value; +use map::Map; +use number::Number; + +macro_rules! from_integer { + ($($ty:ident)*) => { + $( + impl From<$ty> for Value { + fn from(n: $ty) -> Self { + Value::Number(n.into()) + } + } + )* + }; +} + +from_integer! { + i8 i16 i32 i64 isize + u8 u16 u32 u64 usize +} + +#[cfg(feature = "arbitrary_precision")] +serde_if_integer128! { + from_integer! { + i128 u128 + } +} + +impl From<f32> for Value { + /// Convert 32-bit floating point number to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let f: f32 = 13.37; + /// let x: Value = f.into(); + /// ``` + fn from(f: f32) -> Self { + From::from(f as f64) + } +} + +impl From<f64> for Value { + /// Convert 64-bit floating point number to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let f: f64 = 13.37; + /// let x: Value = f.into(); + /// ``` + fn from(f: f64) -> Self { + Number::from_f64(f).map_or(Value::Null, Value::Number) + } +} + +impl From<bool> for Value { + /// Convert boolean to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let b = false; + /// let x: Value = b.into(); + /// ``` + fn from(f: bool) -> Self { + Value::Bool(f) + } +} + +impl From<String> for Value { + /// Convert `String` to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let s: String = "lorem".to_string(); + /// let x: Value = s.into(); + /// ``` + fn from(f: String) -> Self { + Value::String(f) + } +} + +impl<'a> From<&'a str> for Value { + /// Convert string slice to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let s: &str = "lorem"; + /// let x: Value = s.into(); + /// ``` + fn from(f: &str) -> Self { + Value::String(f.to_string()) + } +} + +impl<'a> From<Cow<'a, str>> for Value { + /// Convert copy-on-write string to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow<str> = Cow::Borrowed("lorem"); + /// let x: Value = s.into(); + /// ``` + /// + /// ```edition2018 + /// use serde_json::Value; + /// use std::borrow::Cow; + /// + /// let s: Cow<str> = Cow::Owned("lorem".to_string()); + /// let x: Value = s.into(); + /// ``` + fn from(f: Cow<'a, str>) -> Self { + Value::String(f.into_owned()) + } +} + +impl From<Map<String, Value>> for Value { + /// Convert map (with string keys) to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::{Map, Value}; + /// + /// let mut m = Map::new(); + /// m.insert("Lorem".to_string(), "ipsum".into()); + /// let x: Value = m.into(); + /// ``` + fn from(f: Map<String, Value>) -> Self { + Value::Object(f) + } +} + +impl<T: Into<Value>> From<Vec<T>> for Value { + /// Convert a `Vec` to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let v = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: Vec<T>) -> Self { + Value::Array(f.into_iter().map(Into::into).collect()) + } +} + +impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value { + /// Convert a slice to `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let v: &[&str] = &["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into(); + /// ``` + fn from(f: &'a [T]) -> Self { + Value::Array(f.iter().cloned().map(Into::into).collect()) + } +} + +impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value { + /// Convert an iteratable type to a `Value` + /// + /// # Examples + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let v = std::iter::repeat(42).take(5); + /// let x: Value = v.collect(); + /// ``` + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"]; + /// let x: Value = v.into_iter().collect(); + /// ``` + /// + /// ```edition2018 + /// use std::iter::FromIterator; + /// use serde_json::Value; + /// + /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]); + /// ``` + fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { + Value::Array(iter.into_iter().map(Into::into).collect()) + } +} diff --git a/serde_json/src/value/index.rs b/serde_json/src/value/index.rs new file mode 100644 index 000000000..47990a547 --- /dev/null +++ b/serde_json/src/value/index.rs @@ -0,0 +1,257 @@ +use std::fmt; +use std::ops; + +use super::Value; +use map::Map; + +/// A type that can be used to index into a `serde_json::Value`. +/// +/// The [`get`] and [`get_mut`] methods of `Value` accept any type that +/// implements `Index`, as does the [square-bracket indexing operator]. This +/// trait is implemented for strings which are used as the index into a JSON +/// map, and for `usize` which is used as the index into a JSON array. +/// +/// [`get`]: ../enum.Value.html#method.get +/// [`get_mut`]: ../enum.Value.html#method.get_mut +/// [square-bracket indexing operator]: ../enum.Value.html#impl-Index%3CI%3E +/// +/// This trait is sealed and cannot be implemented for types outside of +/// `serde_json`. +/// +/// # Examples +/// +/// ```edition2018 +/// # use serde_json::json; +/// # +/// let data = json!({ "inner": [1, 2, 3] }); +/// +/// // Data is a JSON map so it can be indexed with a string. +/// let inner = &data["inner"]; +/// +/// // Inner is a JSON array so it can be indexed with an integer. +/// let first = &inner[0]; +/// +/// assert_eq!(first, 1); +/// ``` +pub trait Index: private::Sealed { + /// Return None if the key is not already in the array or object. + #[doc(hidden)] + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value>; + + /// Return None if the key is not already in the array or object. + #[doc(hidden)] + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value>; + + /// Panic if array index out of bounds. If key is not already in the object, + /// insert it with a value of null. Panic if Value is a type that cannot be + /// indexed into, except if Value is null then it can be treated as an empty + /// object. + #[doc(hidden)] + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value; +} + +impl Index for usize { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match *v { + Value::Array(ref vec) => vec.get(*self), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match *v { + Value::Array(ref mut vec) => vec.get_mut(*self), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + match *v { + Value::Array(ref mut vec) => { + let len = vec.len(); + vec.get_mut(*self).unwrap_or_else(|| { + panic!( + "cannot access index {} of JSON array of length {}", + self, len + ) + }) + } + _ => panic!("cannot access index {} of JSON {}", self, Type(v)), + } + } +} + +impl Index for str { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + match *v { + Value::Object(ref map) => map.get(self), + _ => None, + } + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + match *v { + Value::Object(ref mut map) => map.get_mut(self), + _ => None, + } + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + if let Value::Null = *v { + *v = Value::Object(Map::new()); + } + match *v { + Value::Object(ref mut map) => map.entry(self.to_owned()).or_insert(Value::Null), + _ => panic!("cannot access key {:?} in JSON {}", self, Type(v)), + } + } +} + +impl Index for String { + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + self[..].index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + self[..].index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + self[..].index_or_insert(v) + } +} + +impl<'a, T: ?Sized> Index for &'a T +where + T: Index, +{ + fn index_into<'v>(&self, v: &'v Value) -> Option<&'v Value> { + (**self).index_into(v) + } + fn index_into_mut<'v>(&self, v: &'v mut Value) -> Option<&'v mut Value> { + (**self).index_into_mut(v) + } + fn index_or_insert<'v>(&self, v: &'v mut Value) -> &'v mut Value { + (**self).index_or_insert(v) + } +} + +// Prevent users from implementing the Index trait. +mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for String {} + impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {} +} + +/// Used in panic messages. +struct Type<'a>(&'a Value); + +impl<'a> fmt::Display for Type<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match *self.0 { + Value::Null => formatter.write_str("null"), + Value::Bool(_) => formatter.write_str("boolean"), + Value::Number(_) => formatter.write_str("number"), + Value::String(_) => formatter.write_str("string"), + Value::Array(_) => formatter.write_str("array"), + Value::Object(_) => formatter.write_str("object"), + } + } +} + +// The usual semantics of Index is to panic on invalid indexing. +// +// That said, the usual semantics are for things like Vec and BTreeMap which +// have different use cases than Value. If you are working with a Vec, you know +// that you are working with a Vec and you can get the len of the Vec and make +// sure your indices are within bounds. The Value use cases are more +// loosey-goosey. You got some JSON from an endpoint and you want to pull values +// out of it. Outside of this Index impl, you already have the option of using +// value.as_array() and working with the Vec directly, or matching on +// Value::Array and getting the Vec directly. The Index impl means you can skip +// that and index directly into the thing using a concise syntax. You don't have +// to check the type, you don't have to check the len, it is all about what you +// expect the Value to look like. +// +// Basically the use cases that would be well served by panicking here are +// better served by using one of the other approaches: get and get_mut, +// as_array, or match. The value of this impl is that it adds a way of working +// with Value that is not well served by the existing approaches: concise and +// careless and sometimes that is exactly what you want. +impl<I> ops::Index<I> for Value +where + I: Index, +{ + type Output = Value; + + /// Index into a `serde_json::Value` using the syntax `value[0]` or + /// `value["k"]`. + /// + /// Returns `Value::Null` if the type of `self` does not match the type of + /// the index, for example if the index is a string and `self` is an array + /// or a number. Also returns `Value::Null` if the given key does not exist + /// in the map or the given index is not within the bounds of the array. + /// + /// For retrieving deeply nested values, you should have a look at the + /// `Value::pointer` method. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// assert_eq!(data["x"]["y"], json!(["z", "zz"])); + /// assert_eq!(data["x"]["y"][0], json!("z")); + /// + /// assert_eq!(data["a"], json!(null)); // returns null for undefined values + /// assert_eq!(data["a"]["b"], json!(null)); // does not panic + /// ``` + fn index(&self, index: I) -> &Value { + static NULL: Value = Value::Null; + index.index_into(self).unwrap_or(&NULL) + } +} + +impl<I> ops::IndexMut<I> for Value +where + I: Index, +{ + /// Write into a `serde_json::Value` using the syntax `value[0] = ...` or + /// `value["k"] = ...`. + /// + /// If the index is a number, the value must be an array of length bigger + /// than the index. Indexing into a value that is not an array or an array + /// that is too small will panic. + /// + /// If the index is a string, the value must be an object or null which is + /// treated like an empty object. If the key is not already present in the + /// object, it will be inserted with a value of null. Indexing into a value + /// that is neither an object nor null will panic. + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut data = json!({ "x": 0 }); + /// + /// // replace an existing key + /// data["x"] = json!(1); + /// + /// // insert a new key + /// data["y"] = json!([false, false, false]); + /// + /// // replace an array value + /// data["y"][0] = json!(true); + /// + /// // inserted a deeply nested key + /// data["a"]["b"]["c"]["d"] = json!(true); + /// + /// println!("{}", data); + /// ``` + fn index_mut(&mut self, index: I) -> &mut Value { + index.index_or_insert(self) + } +} diff --git a/serde_json/src/value/mod.rs b/serde_json/src/value/mod.rs new file mode 100644 index 000000000..55803a191 --- /dev/null +++ b/serde_json/src/value/mod.rs @@ -0,0 +1,1011 @@ +//! The Value enum, a loosely typed way of representing any valid JSON value. +//! +//! # Constructing JSON +//! +//! Serde JSON provides a [`json!` macro][macro] to build `serde_json::Value` +//! objects with very natural JSON syntax. In order to use this macro, +//! `serde_json` needs to be imported with the `#[macro_use]` attribute. +//! +//! ```edition2018 +//! use serde_json::json; +//! +//! fn main() { +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }); +//! +//! println!("first phone number: {}", john["phones"][0]); +//! +//! // Convert to a string of JSON and print it out +//! println!("{}", john.to_string()); +//! } +//! ``` +//! +//! The `Value::to_string()` function converts a `serde_json::Value` into a +//! `String` of JSON text. +//! +//! One neat thing about the `json!` macro is that variables and expressions can +//! be interpolated directly into the JSON value as you are building it. Serde +//! will check at compile time that the value you are interpolating is able to +//! be represented as JSON. +//! +//! ```edition2018 +//! # use serde_json::json; +//! # +//! # fn random_phone() -> u16 { 0 } +//! # +//! let full_name = "John Doe"; +//! let age_last_year = 42; +//! +//! // The type of `john` is `serde_json::Value` +//! let john = json!({ +//! "name": full_name, +//! "age": age_last_year + 1, +//! "phones": [ +//! format!("+44 {}", random_phone()) +//! ] +//! }); +//! ``` +//! +//! A string of JSON data can be parsed into a `serde_json::Value` by the +//! [`serde_json::from_str`][from_str] function. There is also +//! [`from_slice`][from_slice] for parsing from a byte slice `&[u8]` and +//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or +//! a TCP stream. +//! +//! ```edition2018 +//! use serde_json::{json, Value, Error}; +//! +//! fn untyped_example() -> Result<(), Error> { +//! // Some JSON input data as a &str. Maybe this comes from the user. +//! let data = r#" +//! { +//! "name": "John Doe", +//! "age": 43, +//! "phones": [ +//! "+44 1234567", +//! "+44 2345678" +//! ] +//! }"#; +//! +//! // Parse the string of data into serde_json::Value. +//! let v: Value = serde_json::from_str(data)?; +//! +//! // Access parts of the data by indexing with square brackets. +//! println!("Please call {} at the number {}", v["name"], v["phones"][0]); +//! +//! Ok(()) +//! } +//! # +//! # fn main() { +//! # untyped_example().unwrap(); +//! # } +//! ``` +//! +//! [macro]: https://docs.serde.rs/serde_json/macro.json.html +//! [from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html +//! [from_slice]: https://docs.serde.rs/serde_json/de/fn.from_slice.html +//! [from_reader]: https://docs.serde.rs/serde_json/de/fn.from_reader.html + +use std::fmt::{self, Debug}; +use std::io; +use std::mem; +use std::str; + +use serde::de::DeserializeOwned; +use serde::ser::Serialize; + +use error::Error; +pub use map::Map; +pub use number::Number; + +#[cfg(feature = "raw_value")] +pub use raw::RawValue; + +pub use self::index::Index; + +use self::ser::Serializer; + +/// Represents any valid JSON value. +/// +/// See the `serde_json::value` module documentation for usage examples. +#[derive(Clone, PartialEq)] +pub enum Value { + /// Represents a JSON null value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!(null); + /// ``` + Null, + + /// Represents a JSON boolean. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!(true); + /// ``` + Bool(bool), + + /// Represents a JSON number, whether integer or floating point. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!(12.5); + /// ``` + Number(Number), + + /// Represents a JSON string. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!("a string"); + /// ``` + String(String), + + /// Represents a JSON array. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!(["an", "array"]); + /// ``` + Array(Vec<Value>), + + /// Represents a JSON object. + /// + /// By default the map is backed by a BTreeMap. Enable the `preserve_order` + /// feature of serde_json to use IndexMap instead, which preserves + /// entries in the order they are inserted into the map. In particular, this + /// allows JSON data to be deserialized into a Value and serialized to a + /// string while retaining the order of map keys in the input. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "an": "object" }); + /// ``` + Object(Map<String, Value>), +} + +impl Debug for Value { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match *self { + Value::Null => formatter.debug_tuple("Null").finish(), + Value::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(), + Value::Number(ref v) => Debug::fmt(v, formatter), + Value::String(ref v) => formatter.debug_tuple("String").field(v).finish(), + Value::Array(ref v) => formatter.debug_tuple("Array").field(v).finish(), + Value::Object(ref v) => formatter.debug_tuple("Object").field(v).finish(), + } + } +} + +struct WriterFormatter<'a, 'b: 'a> { + inner: &'a mut fmt::Formatter<'b>, +} + +impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + fn io_error<E>(_: E) -> io::Error { + // Error value does not matter because fmt::Display impl below just + // maps it to fmt::Error + io::Error::new(io::ErrorKind::Other, "fmt error") + } + let s = try!(str::from_utf8(buf).map_err(io_error)); + try!(self.inner.write_str(s).map_err(io_error)); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl fmt::Display for Value { + /// Display a JSON value as a string. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let json = json!({ "city": "London", "street": "10 Downing Street" }); + /// + /// // Compact format: + /// // + /// // {"city":"London","street":"10 Downing Street"} + /// let compact = format!("{}", json); + /// assert_eq!(compact, + /// "{\"city\":\"London\",\"street\":\"10 Downing Street\"}"); + /// + /// // Pretty format: + /// // + /// // { + /// // "city": "London", + /// // "street": "10 Downing Street" + /// // } + /// let pretty = format!("{:#}", json); + /// assert_eq!(pretty, + /// "{\n \"city\": \"London\",\n \"street\": \"10 Downing Street\"\n}"); + /// ``` + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let alternate = f.alternate(); + let mut wr = WriterFormatter { inner: f }; + if alternate { + // {:#} + super::ser::to_writer_pretty(&mut wr, self).map_err(|_| fmt::Error) + } else { + // {} + super::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error) + } + } +} + +fn parse_index(s: &str) -> Option<usize> { + if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) { + return None; + } + s.parse().ok() +} + +impl Value { + /// Index into a JSON array or map. A string index can be used to access a + /// value in a map, and a usize index can be used to access an element of an + /// array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let object = json!({ "A": 65, "B": 66, "C": 67 }); + /// assert_eq!(*object.get("A").unwrap(), json!(65)); + /// + /// let array = json!([ "A", "B", "C" ]); + /// assert_eq!(*array.get(2).unwrap(), json!("C")); + /// + /// assert_eq!(array.get("A"), None); + /// ``` + /// + /// Square brackets can also be used to index into a value in a more concise + /// way. This returns `Value::Null` in cases where `get` would have returned + /// `None`. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let object = json!({ + /// "A": ["a", "á", "à"], + /// "B": ["b", "b́"], + /// "C": ["c", "ć", "ć̣", "ḉ"], + /// }); + /// assert_eq!(object["B"][0], json!("b")); + /// + /// assert_eq!(object["D"], json!(null)); + /// assert_eq!(object[0]["x"]["y"]["z"], json!(null)); + /// ``` + pub fn get<I: Index>(&self, index: I) -> Option<&Value> { + index.index_into(self) + } + + /// Mutably index into a JSON array or map. A string index can be used to + /// access a value in a map, and a usize index can be used to access an + /// element of an array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut object = json!({ "A": 65, "B": 66, "C": 67 }); + /// *object.get_mut("A").unwrap() = json!(69); + /// + /// let mut array = json!([ "A", "B", "C" ]); + /// *array.get_mut(2).unwrap() = json!("D"); + /// ``` + pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> { + index.index_into_mut(self) + } + + /// Returns true if the `Value` is an Object. Returns false otherwise. + /// + /// For any Value on which `is_object` returns true, `as_object` and + /// `as_object_mut` are guaranteed to return the map representation of the + /// object. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let obj = json!({ "a": { "nested": true }, "b": ["an", "array"] }); + /// + /// assert!(obj.is_object()); + /// assert!(obj["a"].is_object()); + /// + /// // array, not an object + /// assert!(!obj["b"].is_object()); + /// ``` + pub fn is_object(&self) -> bool { + self.as_object().is_some() + } + + /// If the `Value` is an Object, returns the associated Map. Returns None + /// otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": { "nested": true }, "b": ["an", "array"] }); + /// + /// // The length of `{"nested": true}` is 1 entry. + /// assert_eq!(v["a"].as_object().unwrap().len(), 1); + /// + /// // The array `["an", "array"]` is not an object. + /// assert_eq!(v["b"].as_object(), None); + /// ``` + pub fn as_object(&self) -> Option<&Map<String, Value>> { + match *self { + Value::Object(ref map) => Some(map), + _ => None, + } + } + + /// If the `Value` is an Object, returns the associated mutable Map. + /// Returns None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut v = json!({ "a": { "nested": true } }); + /// + /// v["a"].as_object_mut().unwrap().clear(); + /// assert_eq!(v, json!({ "a": {} })); + /// ``` + pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> { + match *self { + Value::Object(ref mut map) => Some(map), + _ => None, + } + } + + /// Returns true if the `Value` is an Array. Returns false otherwise. + /// + /// For any Value on which `is_array` returns true, `as_array` and + /// `as_array_mut` are guaranteed to return the vector representing the + /// array. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let obj = json!({ "a": ["an", "array"], "b": { "an": "object" } }); + /// + /// assert!(obj["a"].is_array()); + /// + /// // an object, not an array + /// assert!(!obj["b"].is_array()); + /// ``` + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// If the `Value` is an Array, returns the associated vector. Returns None + /// otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": ["an", "array"], "b": { "an": "object" } }); + /// + /// // The length of `["an", "array"]` is 2 elements. + /// assert_eq!(v["a"].as_array().unwrap().len(), 2); + /// + /// // The object `{"an": "object"}` is not an array. + /// assert_eq!(v["b"].as_array(), None); + /// ``` + pub fn as_array(&self) -> Option<&Vec<Value>> { + match *self { + Value::Array(ref array) => Some(&*array), + _ => None, + } + } + + /// If the `Value` is an Array, returns the associated mutable vector. + /// Returns None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut v = json!({ "a": ["an", "array"] }); + /// + /// v["a"].as_array_mut().unwrap().clear(); + /// assert_eq!(v, json!({ "a": [] })); + /// ``` + pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> { + match *self { + Value::Array(ref mut list) => Some(list), + _ => None, + } + } + + /// Returns true if the `Value` is a String. Returns false otherwise. + /// + /// For any Value on which `is_string` returns true, `as_str` is guaranteed + /// to return the string slice. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": "some string", "b": false }); + /// + /// assert!(v["a"].is_string()); + /// + /// // The boolean `false` is not a string. + /// assert!(!v["b"].is_string()); + /// ``` + pub fn is_string(&self) -> bool { + self.as_str().is_some() + } + + /// If the `Value` is a String, returns the associated str. Returns None + /// otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": "some string", "b": false }); + /// + /// assert_eq!(v["a"].as_str(), Some("some string")); + /// + /// // The boolean `false` is not a string. + /// assert_eq!(v["b"].as_str(), None); + /// + /// // JSON values are printed in JSON representation, so strings are in quotes. + /// // + /// // The value is: "some string" + /// println!("The value is: {}", v["a"]); + /// + /// // Rust strings are printed without quotes. + /// // + /// // The value is: some string + /// println!("The value is: {}", v["a"].as_str().unwrap()); + /// ``` + pub fn as_str(&self) -> Option<&str> { + match *self { + Value::String(ref s) => Some(s), + _ => None, + } + } + + /// Returns true if the `Value` is a Number. Returns false otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 1, "b": "2" }); + /// + /// assert!(v["a"].is_number()); + /// + /// // The string `"2"` is a string, not a number. + /// assert!(!v["b"].is_number()); + /// ``` + pub fn is_number(&self) -> bool { + match *self { + Value::Number(_) => true, + _ => false, + } + } + + /// Returns true if the `Value` is an integer between `i64::MIN` and + /// `i64::MAX`. + /// + /// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to + /// return the integer value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert!(v["a"].is_i64()); + /// + /// // Greater than i64::MAX. + /// assert!(!v["b"].is_i64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_i64()); + /// ``` + pub fn is_i64(&self) -> bool { + match *self { + Value::Number(ref n) => n.is_i64(), + _ => false, + } + } + + /// Returns true if the `Value` is an integer between zero and `u64::MAX`. + /// + /// For any Value on which `is_u64` returns true, `as_u64` is guaranteed to + /// return the integer value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert!(v["a"].is_u64()); + /// + /// // Negative integer. + /// assert!(!v["b"].is_u64()); + /// + /// // Numbers with a decimal point are not considered integers. + /// assert!(!v["c"].is_u64()); + /// ``` + pub fn is_u64(&self) -> bool { + match *self { + Value::Number(ref n) => n.is_u64(), + _ => false, + } + } + + /// Returns true if the `Value` is a number that can be represented by f64. + /// + /// For any Value on which `is_f64` returns true, `as_f64` is guaranteed to + /// return the floating point value. + /// + /// Currently this function returns true if and only if both `is_i64` and + /// `is_u64` return false but this is not a guarantee in the future. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert!(v["a"].is_f64()); + /// + /// // Integers. + /// assert!(!v["b"].is_f64()); + /// assert!(!v["c"].is_f64()); + /// ``` + pub fn is_f64(&self) -> bool { + match *self { + Value::Number(ref n) => n.is_f64(), + _ => false, + } + } + + /// If the `Value` is an integer, represent it as i64 if possible. Returns + /// None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let big = i64::max_value() as u64 + 10; + /// let v = json!({ "a": 64, "b": big, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_i64(), Some(64)); + /// assert_eq!(v["b"].as_i64(), None); + /// assert_eq!(v["c"].as_i64(), None); + /// ``` + pub fn as_i64(&self) -> Option<i64> { + match *self { + Value::Number(ref n) => n.as_i64(), + _ => None, + } + } + + /// If the `Value` is an integer, represent it as u64 if possible. Returns + /// None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 64, "b": -64, "c": 256.0 }); + /// + /// assert_eq!(v["a"].as_u64(), Some(64)); + /// assert_eq!(v["b"].as_u64(), None); + /// assert_eq!(v["c"].as_u64(), None); + /// ``` + pub fn as_u64(&self) -> Option<u64> { + match *self { + Value::Number(ref n) => n.as_u64(), + _ => None, + } + } + + /// If the `Value` is a number, represent it as f64 if possible. Returns + /// None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": 256.0, "b": 64, "c": -64 }); + /// + /// assert_eq!(v["a"].as_f64(), Some(256.0)); + /// assert_eq!(v["b"].as_f64(), Some(64.0)); + /// assert_eq!(v["c"].as_f64(), Some(-64.0)); + /// ``` + pub fn as_f64(&self) -> Option<f64> { + match *self { + Value::Number(ref n) => n.as_f64(), + _ => None, + } + } + + /// Returns true if the `Value` is a Boolean. Returns false otherwise. + /// + /// For any Value on which `is_boolean` returns true, `as_bool` is + /// guaranteed to return the boolean value. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": false, "b": "false" }); + /// + /// assert!(v["a"].is_boolean()); + /// + /// // The string `"false"` is a string, not a boolean. + /// assert!(!v["b"].is_boolean()); + /// ``` + pub fn is_boolean(&self) -> bool { + self.as_bool().is_some() + } + + /// If the `Value` is a Boolean, returns the associated bool. Returns None + /// otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": false, "b": "false" }); + /// + /// assert_eq!(v["a"].as_bool(), Some(false)); + /// + /// // The string `"false"` is a string, not a boolean. + /// assert_eq!(v["b"].as_bool(), None); + /// ``` + pub fn as_bool(&self) -> Option<bool> { + match *self { + Value::Bool(b) => Some(b), + _ => None, + } + } + + /// Returns true if the `Value` is a Null. Returns false otherwise. + /// + /// For any Value on which `is_null` returns true, `as_null` is guaranteed + /// to return `Some(())`. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": null, "b": false }); + /// + /// assert!(v["a"].is_null()); + /// + /// // The boolean `false` is not null. + /// assert!(!v["b"].is_null()); + /// ``` + pub fn is_null(&self) -> bool { + self.as_null().is_some() + } + + /// If the `Value` is a Null, returns (). Returns None otherwise. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let v = json!({ "a": null, "b": false }); + /// + /// assert_eq!(v["a"].as_null(), Some(())); + /// + /// // The boolean `false` is not null. + /// assert_eq!(v["b"].as_null(), None); + /// ``` + pub fn as_null(&self) -> Option<()> { + match *self { + Value::Null => Some(()), + _ => None, + } + } + + /// Looks up a value by a JSON Pointer. + /// + /// JSON Pointer defines a string syntax for identifying a specific value + /// within a JavaScript Object Notation (JSON) document. + /// + /// A Pointer is a Unicode string with the reference tokens separated by `/`. + /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The + /// addressed value is returned and if there is no such value `None` is + /// returned. + /// + /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901). + /// + /// # Examples + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let data = json!({ + /// "x": { + /// "y": ["z", "zz"] + /// } + /// }); + /// + /// assert_eq!(data.pointer("/x/y/1").unwrap(), &json!("zz")); + /// assert_eq!(data.pointer("/a/b/c"), None); + /// ``` + pub fn pointer<'a>(&'a self, pointer: &str) -> Option<&'a Value> { + if pointer == "" { + return Some(self); + } + if !pointer.starts_with('/') { + return None; + } + let tokens = pointer + .split('/') + .skip(1) + .map(|x| x.replace("~1", "/").replace("~0", "~")); + let mut target = self; + + for token in tokens { + let target_opt = match *target { + Value::Object(ref map) => map.get(&token), + Value::Array(ref list) => parse_index(&token).and_then(|x| list.get(x)), + _ => return None, + }; + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) + } + + /// Looks up a value by a JSON Pointer and returns a mutable reference to + /// that value. + /// + /// JSON Pointer defines a string syntax for identifying a specific value + /// within a JavaScript Object Notation (JSON) document. + /// + /// A Pointer is a Unicode string with the reference tokens separated by `/`. + /// Inside tokens `/` is replaced by `~1` and `~` is replaced by `~0`. The + /// addressed value is returned and if there is no such value `None` is + /// returned. + /// + /// For more information read [RFC6901](https://tools.ietf.org/html/rfc6901). + /// + /// # Example of Use + /// + /// ```edition2018 + /// use serde_json::Value; + /// + /// fn main() { + /// let s = r#"{"x": 1.0, "y": 2.0}"#; + /// let mut value: Value = serde_json::from_str(s).unwrap(); + /// + /// // Check value using read-only pointer + /// assert_eq!(value.pointer("/x"), Some(&1.0.into())); + /// // Change value with direct assignment + /// *value.pointer_mut("/x").unwrap() = 1.5.into(); + /// // Check that new value was written + /// assert_eq!(value.pointer("/x"), Some(&1.5.into())); + /// + /// // "Steal" ownership of a value. Can replace with any valid Value. + /// let old_x = value.pointer_mut("/x").map(Value::take).unwrap(); + /// assert_eq!(old_x, 1.5); + /// assert_eq!(value.pointer("/x").unwrap(), &Value::Null); + /// } + /// ``` + pub fn pointer_mut<'a>(&'a mut self, pointer: &str) -> Option<&'a mut Value> { + if pointer == "" { + return Some(self); + } + if !pointer.starts_with('/') { + return None; + } + let tokens = pointer + .split('/') + .skip(1) + .map(|x| x.replace("~1", "/").replace("~0", "~")); + let mut target = self; + + for token in tokens { + // borrow checker gets confused about `target` being mutably borrowed too many times because of the loop + // this once-per-loop binding makes the scope clearer and circumvents the error + let target_once = target; + let target_opt = match *target_once { + Value::Object(ref mut map) => map.get_mut(&token), + Value::Array(ref mut list) => { + parse_index(&token).and_then(move |x| list.get_mut(x)) + } + _ => return None, + }; + if let Some(t) = target_opt { + target = t; + } else { + return None; + } + } + Some(target) + } + + /// Takes the value out of the `Value`, leaving a `Null` in its place. + /// + /// ```edition2018 + /// # use serde_json::json; + /// # + /// let mut v = json!({ "x": "y" }); + /// assert_eq!(v["x"].take(), json!("y")); + /// assert_eq!(v, json!({ "x": null })); + /// ``` + pub fn take(&mut self) -> Value { + mem::replace(self, Value::Null) + } +} + +/// The default value is `Value::Null`. +/// +/// This is useful for handling omitted `Value` fields when deserializing. +/// +/// # Examples +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// use serde_json::Value; +/// +/// #[derive(Deserialize)] +/// struct Settings { +/// level: i32, +/// #[serde(default)] +/// extras: Value, +/// } +/// +/// # fn try_main() -> Result<(), serde_json::Error> { +/// let data = r#" { "level": 42 } "#; +/// let s: Settings = serde_json::from_str(data)?; +/// +/// assert_eq!(s.level, 42); +/// assert_eq!(s.extras, Value::Null); +/// # +/// # Ok(()) +/// # } +/// # +/// # fn main() { +/// # try_main().unwrap() +/// # } +/// ``` +impl Default for Value { + fn default() -> Value { + Value::Null + } +} + +mod de; +mod from; +mod index; +mod partial_eq; +mod ser; + +/// Convert a `T` into `serde_json::Value` which is an enum that can represent +/// any valid JSON data. +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::Serialize; +/// use serde::Serialize; +/// use serde_json::json; +/// +/// use std::error::Error; +/// +/// #[derive(Serialize)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn compare_json_values() -> Result<(), Box<Error>> { +/// let u = User { +/// fingerprint: "0xF9BA143B95FF6D82".to_owned(), +/// location: "Menlo Park, CA".to_owned(), +/// }; +/// +/// // The type of `expected` is `serde_json::Value` +/// let expected = json!({ +/// "fingerprint": "0xF9BA143B95FF6D82", +/// "location": "Menlo Park, CA", +/// }); +/// +/// let v = serde_json::to_value(u).unwrap(); +/// assert_eq!(v, expected); +/// +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # compare_json_values().unwrap(); +/// # } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if `T`'s implementation of `Serialize` decides to +/// fail, or if `T` contains a map with non-string keys. +/// +/// ```edition2018 +/// use std::collections::BTreeMap; +/// +/// fn main() { +/// // The keys in this map are vectors, not strings. +/// let mut map = BTreeMap::new(); +/// map.insert(vec![32, 64], "x86"); +/// +/// println!("{}", serde_json::to_value(map).unwrap_err()); +/// } +/// ``` +// Taking by value is more friendly to iterator adapters, option and result +// consumers, etc. See https://github.com/serde-rs/json/pull/149. +pub fn to_value<T>(value: T) -> Result<Value, Error> +where + T: Serialize, +{ + value.serialize(Serializer) +} + +/// Interpret a `serde_json::Value` as an instance of type `T`. +/// +/// # Example +/// +/// ```edition2018 +/// # use serde_derive::Deserialize; +/// use serde::Deserialize; +/// use serde_json::json; +/// +/// #[derive(Deserialize, Debug)] +/// struct User { +/// fingerprint: String, +/// location: String, +/// } +/// +/// fn main() { +/// // The type of `j` is `serde_json::Value` +/// let j = json!({ +/// "fingerprint": "0xF9BA143B95FF6D82", +/// "location": "Menlo Park, CA" +/// }); +/// +/// let u: User = serde_json::from_value(j).unwrap(); +/// println!("{:#?}", u); +/// } +/// ``` +/// +/// # Errors +/// +/// This conversion can fail if the structure of the Value does not match the +/// structure expected by `T`, for example if `T` is a struct type but the Value +/// contains something other than a JSON map. It can also fail if the structure +/// is correct but `T`'s implementation of `Deserialize` decides that something +/// is wrong with the data, for example required struct fields are missing from +/// the JSON map or some number is too big to fit in the expected primitive +/// type. +pub fn from_value<T>(value: Value) -> Result<T, Error> +where + T: DeserializeOwned, +{ + T::deserialize(value) +} diff --git a/serde_json/src/value/partial_eq.rs b/serde_json/src/value/partial_eq.rs new file mode 100644 index 000000000..cfcf95706 --- /dev/null +++ b/serde_json/src/value/partial_eq.rs @@ -0,0 +1,94 @@ +use super::Value; + +fn eq_i64(value: &Value, other: i64) -> bool { + value.as_i64().map_or(false, |i| i == other) +} + +fn eq_u64(value: &Value, other: u64) -> bool { + value.as_u64().map_or(false, |i| i == other) +} + +fn eq_f64(value: &Value, other: f64) -> bool { + value.as_f64().map_or(false, |i| i == other) +} + +fn eq_bool(value: &Value, other: bool) -> bool { + value.as_bool().map_or(false, |i| i == other) +} + +fn eq_str(value: &Value, other: &str) -> bool { + value.as_str().map_or(false, |i| i == other) +} + +impl PartialEq<str> for Value { + fn eq(&self, other: &str) -> bool { + eq_str(self, other) + } +} + +impl<'a> PartialEq<&'a str> for Value { + fn eq(&self, other: &&str) -> bool { + eq_str(self, *other) + } +} + +impl PartialEq<Value> for str { + fn eq(&self, other: &Value) -> bool { + eq_str(other, self) + } +} + +impl<'a> PartialEq<Value> for &'a str { + fn eq(&self, other: &Value) -> bool { + eq_str(other, *self) + } +} + +impl PartialEq<String> for Value { + fn eq(&self, other: &String) -> bool { + eq_str(self, other.as_str()) + } +} + +impl PartialEq<Value> for String { + fn eq(&self, other: &Value) -> bool { + eq_str(other, self.as_str()) + } +} + +macro_rules! partialeq_numeric { + ($($eq:ident [$($ty:ty)*])*) => { + $($( + impl PartialEq<$ty> for Value { + fn eq(&self, other: &$ty) -> bool { + $eq(self, *other as _) + } + } + + impl PartialEq<Value> for $ty { + fn eq(&self, other: &Value) -> bool { + $eq(other, *self as _) + } + } + + impl<'a> PartialEq<$ty> for &'a Value { + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + + impl<'a> PartialEq<$ty> for &'a mut Value { + fn eq(&self, other: &$ty) -> bool { + $eq(*self, *other as _) + } + } + )*)* + } +} + +partialeq_numeric! { + eq_i64[i8 i16 i32 i64 isize] + eq_u64[u8 u16 u32 u64 usize] + eq_f64[f32 f64] + eq_bool[bool] +} diff --git a/serde_json/src/value/ser.rs b/serde_json/src/value/ser.rs new file mode 100644 index 000000000..b0e09beb5 --- /dev/null +++ b/serde_json/src/value/ser.rs @@ -0,0 +1,1018 @@ +use serde::ser::Impossible; +use serde::{self, Serialize}; + +use error::{Error, ErrorCode}; +use map::Map; +use number::Number; +use value::{to_value, Value}; + +impl Serialize for Value { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ::serde::Serializer, + { + match *self { + Value::Null => serializer.serialize_unit(), + Value::Bool(b) => serializer.serialize_bool(b), + Value::Number(ref n) => n.serialize(serializer), + Value::String(ref s) => serializer.serialize_str(s), + Value::Array(ref v) => v.serialize(serializer), + Value::Object(ref m) => { + use serde::ser::SerializeMap; + let mut map = try!(serializer.serialize_map(Some(m.len()))); + for (k, v) in m { + try!(map.serialize_key(k)); + try!(map.serialize_value(v)); + } + map.end() + } + } + } +} + +pub struct Serializer; + +impl serde::Serializer for Serializer { + type Ok = Value; + type Error = Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = SerializeStructVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result<Value, Error> { + Ok(Value::Bool(value)) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result<Value, Error> { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result<Value, Error> { + self.serialize_i64(value as i64) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result<Value, Error> { + self.serialize_i64(value as i64) + } + + fn serialize_i64(self, value: i64) -> Result<Value, Error> { + Ok(Value::Number(value.into())) + } + + #[cfg(feature = "arbitrary_precision")] + serde_if_integer128! { + fn serialize_i128(self, value: i128) -> Result<Value, Error> { + Ok(Value::Number(value.into())) + } + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result<Value, Error> { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result<Value, Error> { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result<Value, Error> { + self.serialize_u64(value as u64) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result<Value, Error> { + Ok(Value::Number(value.into())) + } + + #[cfg(feature = "arbitrary_precision")] + serde_if_integer128! { + fn serialize_u128(self, value: u128) -> Result<Value, Error> { + Ok(Value::Number(value.into())) + } + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result<Value, Error> { + self.serialize_f64(value as f64) + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result<Value, Error> { + Ok(Number::from_f64(value).map_or(Value::Null, Value::Number)) + } + + #[inline] + fn serialize_char(self, value: char) -> Result<Value, Error> { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<Value, Error> { + Ok(Value::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<Value, Error> { + let vec = value.iter().map(|&b| Value::Number(b.into())).collect(); + Ok(Value::Array(vec)) + } + + #[inline] + fn serialize_unit(self) -> Result<Value, Error> { + Ok(Value::Null) + } + + #[inline] + fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> { + self.serialize_unit() + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<Value, Error> { + self.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<Value, Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<Value, Error> + where + T: Serialize, + { + let mut values = Map::new(); + values.insert(String::from(variant), try!(to_value(&value))); + Ok(Value::Object(values)) + } + + #[inline] + fn serialize_none(self) -> Result<Value, Error> { + self.serialize_unit() + } + + #[inline] + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Value, Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Error> { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)), + }) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Error> { + Ok(SerializeTupleVariant { + name: String::from(variant), + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> { + Ok(SerializeMap::Map { + map: Map::new(), + next_key: None, + }) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, Error> { + match name { + #[cfg(feature = "arbitrary_precision")] + ::number::TOKEN => Ok(SerializeMap::Number { out_value: None }), + #[cfg(feature = "raw_value")] + ::raw::TOKEN => Ok(SerializeMap::RawValue { out_value: None }), + _ => self.serialize_map(Some(len)), + } + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Error> { + Ok(SerializeStructVariant { + name: String::from(variant), + map: Map::new(), + }) + } +} + +pub struct SerializeVec { + vec: Vec<Value>, +} + +pub struct SerializeTupleVariant { + name: String, + vec: Vec<Value>, +} + +pub enum SerializeMap { + Map { + map: Map<String, Value>, + next_key: Option<String>, + }, + #[cfg(feature = "arbitrary_precision")] + Number { out_value: Option<Value> }, + #[cfg(feature = "raw_value")] + RawValue { out_value: Option<Value> }, +} + +pub struct SerializeStructVariant { + name: String, + map: Map<String, Value>, +} + +impl serde::ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.vec.push(try!(to_value(&value))); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + Ok(Value::Array(self.vec)) + } +} + +impl serde::ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleVariant for SerializeTupleVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.vec.push(try!(to_value(&value))); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + let mut object = Map::new(); + + object.insert(self.name, Value::Array(self.vec)); + + Ok(Value::Object(object)) + } +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Error> + where + T: Serialize, + { + match *self { + SerializeMap::Map { + ref mut next_key, .. + } => { + *next_key = Some(try!(key.serialize(MapKeySerializer))); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: Serialize, + { + match *self { + SerializeMap::Map { + ref mut map, + ref mut next_key, + } => { + let key = next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + map.insert(key, try!(to_value(&value))); + Ok(()) + } + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } + + fn end(self) -> Result<Value, Error> { + match self { + SerializeMap::Map { map, .. } => Ok(Value::Object(map)), + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { .. } => unreachable!(), + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { .. } => unreachable!(), + } + } +} + +struct MapKeySerializer; + +fn key_must_be_a_string() -> Error { + Error::syntax(ErrorCode::KeyMustBeAString, 0, 0) +} + +impl serde::Serializer for MapKeySerializer { + type Ok = String; + type Error = Error; + + type SerializeSeq = Impossible<String, Error>; + type SerializeTuple = Impossible<String, Error>; + type SerializeTupleStruct = Impossible<String, Error>; + type SerializeTupleVariant = Impossible<String, Error>; + type SerializeMap = Impossible<String, Error>; + type SerializeStruct = Impossible<String, Error>; + type SerializeStructVariant = Impossible<String, Error>; + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Ok(variant.to_owned()) + } + + #[inline] + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_i8(self, value: i8) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_i16(self, value: i16) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_i32(self, value: i32) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_i64(self, value: i64) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_u8(self, value: u8) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_u16(self, value: u16) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_u32(self, value: u32) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_u64(self, value: u64) -> Result<Self::Ok, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + #[inline] + fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> { + Ok({ + let mut s = String::new(); + s.push(value); + s + }) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> { + Ok(value.to_owned()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(key_must_be_a_string()) + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + match *self { + SerializeMap::Map { .. } => { + try!(serde::ser::SerializeMap::serialize_key(self, key)); + serde::ser::SerializeMap::serialize_value(self, value) + } + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { ref mut out_value } => { + if key == ::number::TOKEN { + *out_value = Some(value.serialize(NumberValueEmitter)?); + Ok(()) + } else { + Err(invalid_number()) + } + } + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { ref mut out_value } => { + if key == ::raw::TOKEN { + *out_value = Some(value.serialize(RawValueEmitter)?); + Ok(()) + } else { + Err(invalid_raw_value()) + } + } + } + } + + fn end(self) -> Result<Value, Error> { + match self { + SerializeMap::Map { .. } => serde::ser::SerializeMap::end(self), + #[cfg(feature = "arbitrary_precision")] + SerializeMap::Number { out_value, .. } => { + Ok(out_value.expect("number value was not emitted")) + } + #[cfg(feature = "raw_value")] + SerializeMap::RawValue { out_value, .. } => { + Ok(out_value.expect("raw value was not emitted")) + } + } + } +} + +impl serde::ser::SerializeStructVariant for SerializeStructVariant { + type Ok = Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Error> + where + T: Serialize, + { + self.map.insert(String::from(key), try!(to_value(&value))); + Ok(()) + } + + fn end(self) -> Result<Value, Error> { + let mut object = Map::new(); + + object.insert(self.name, Value::Object(self.map)); + + Ok(Value::Object(object)) + } +} + +#[cfg(feature = "arbitrary_precision")] +struct NumberValueEmitter; + +#[cfg(feature = "arbitrary_precision")] +fn invalid_number() -> Error { + Error::syntax(ErrorCode::InvalidNumber, 0, 0) +} + +#[cfg(feature = "arbitrary_precision")] +impl serde::ser::Serializer for NumberValueEmitter { + type Ok = Value; + type Error = Error; + + type SerializeSeq = Impossible<Value, Error>; + type SerializeTuple = Impossible<Value, Error>; + type SerializeTupleStruct = Impossible<Value, Error>; + type SerializeTupleVariant = Impossible<Value, Error>; + type SerializeMap = Impossible<Value, Error>; + type SerializeStruct = Impossible<Value, Error>; + type SerializeStructVariant = Impossible<Value, Error>; + + fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> { + let n = try!(value.to_owned().parse()); + Ok(Value::Number(n)) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Err(invalid_number()) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_number()) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(invalid_number()) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(invalid_number()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(invalid_number()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(invalid_number()) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(invalid_number()) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(invalid_number()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(invalid_number()) + } +} + +#[cfg(feature = "raw_value")] +struct RawValueEmitter; + +#[cfg(feature = "raw_value")] +fn invalid_raw_value() -> Error { + Error::syntax(ErrorCode::ExpectedSomeValue, 0, 0) +} + +#[cfg(feature = "raw_value")] +impl serde::ser::Serializer for RawValueEmitter { + type Ok = Value; + type Error = Error; + + type SerializeSeq = Impossible<Value, Error>; + type SerializeTuple = Impossible<Value, Error>; + type SerializeTupleStruct = Impossible<Value, Error>; + type SerializeTupleVariant = Impossible<Value, Error>; + type SerializeMap = Impossible<Value, Error>; + type SerializeStruct = Impossible<Value, Error>; + type SerializeStructVariant = Impossible<Value, Error>; + + fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> { + ::from_str(value) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: Serialize, + { + Err(invalid_raw_value()) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(invalid_raw_value()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(invalid_raw_value()) + } +} diff --git a/shell-escape/.cargo-checksum.json b/shell-escape/.cargo-checksum.json new file mode 100644 index 000000000..b390b229e --- /dev/null +++ b/shell-escape/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"} \ No newline at end of file diff --git a/shell-escape/Cargo.toml b/shell-escape/Cargo.toml new file mode 100644 index 000000000..ffc38d496 --- /dev/null +++ b/shell-escape/Cargo.toml @@ -0,0 +1,21 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "shell-escape" +version = "0.1.4" +authors = ["Steven Fackler <sfackler@gmail.com>"] +description = "Escape characters that may have a special meaning in a shell" +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/shell-escape" + +[dependencies] diff --git a/shell-escape/LICENSE-APACHE b/shell-escape/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/shell-escape/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/shell-escape/LICENSE-MIT b/shell-escape/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/shell-escape/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/shell-escape/README.md b/shell-escape/README.md new file mode 100644 index 000000000..e43ade364 --- /dev/null +++ b/shell-escape/README.md @@ -0,0 +1,23 @@ +# shell-escape + +[![Build Status](https://travis-ci.org/sfackler/shell-escape.svg?branch=master)](https://travis-ci.org/sfackler/shell-escape) + +[Documentation](https://docs.rs/shell-escape) + +Escape characters that may have a special meaning in a shell. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/shell-escape/src/lib.rs b/shell-escape/src/lib.rs new file mode 100644 index 000000000..565af3817 --- /dev/null +++ b/shell-escape/src/lib.rs @@ -0,0 +1,133 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Escape characters that may have special meaning in a shell. +#![doc(html_root_url="https://docs.rs/shell-escape/0.1")] + +use std::borrow::Cow; +use std::env; + +/// Escape characters that may have special meaning in a shell. +pub fn escape(s: Cow<str>) -> Cow<str> { + if cfg!(unix) || env::var("MSYSTEM").is_ok() { + unix::escape(s) + } else { + windows::escape(s) + } +} + +/// Windows-specific escaping. +pub mod windows { + use std::borrow::Cow; + use std::iter::repeat; + + /// Escape for the windows cmd.exe shell. + /// + /// See [here][msdn] for more information. + /// + /// [msdn]: http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx + pub fn escape(s: Cow<str>) -> Cow<str> { + let mut needs_escape = false; + for ch in s.chars() { + match ch { + '"' | '\t' | '\n' | ' ' => needs_escape = true, + _ => {} + } + } + if !needs_escape { + return s + } + let mut es = String::with_capacity(s.len()); + es.push('"'); + let mut chars = s.chars().peekable(); + loop { + let mut nslashes = 0; + while let Some(&'\\') = chars.peek() { + chars.next(); + nslashes += 1; + } + + match chars.next() { + Some('"') => { + es.extend(repeat('\\').take(nslashes * 2 + 1)); + es.push('"'); + } + Some(c) => { + es.extend(repeat('\\').take(nslashes)); + es.push(c); + } + None => { + es.extend(repeat('\\').take(nslashes * 2)); + break; + } + } + + } + es.push('"'); + es.into() + } + + #[test] + fn test_escape() { + assert_eq!(escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc"); + assert_eq!(escape("linker=gcc -L/foo -Wl,bar".into()), + r#""linker=gcc -L/foo -Wl,bar""#); + assert_eq!(escape(r#"--features="default""#.into()), + r#""--features=\"default\"""#); + assert_eq!(escape(r#"\path\to\my documents\"#.into()), + r#""\path\to\my documents\\""#); + } +} + +/// Unix-specific escaping. +pub mod unix { + use std::borrow::Cow; + + fn non_whitelisted(ch: char) -> bool { + match ch { + 'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' | '=' | '/' | ',' | '.' | '+' => false, + _ => true, + } + } + + /// Escape characters that may have special meaning in a shell, including spaces. + pub fn escape(s: Cow<str>) -> Cow<str> { + if !s.contains(non_whitelisted) { + return s; + } + + let mut es = String::with_capacity(s.len() + 2); + es.push('\''); + for ch in s.chars() { + match ch { + '\'' | '!' => { + es.push_str("'\\"); + es.push(ch); + es.push('\''); + } + _ => es.push(ch), + } + } + es.push('\''); + es.into() + } + + #[test] + fn test_escape() { + assert_eq!( + escape("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_=/,.+".into()), + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_=/,.+" + ); + assert_eq!(escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc"); + assert_eq!(escape("linker=gcc -L/foo -Wl,bar".into()), r#"'linker=gcc -L/foo -Wl,bar'"#); + assert_eq!(escape(r#"--features="default""#.into()), r#"'--features="default"'"#); + assert_eq!(escape(r#"'!\$`\\\n "#.into()), r#"''\'''\!'\$`\\\n '"#); + } +} + diff --git a/sized-chunks/.cargo-checksum.json b/sized-chunks/.cargo-checksum.json new file mode 100644 index 000000000..2aefb7d47 --- /dev/null +++ b/sized-chunks/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9d3e7f23bad2d6694e0f46f5e470ec27eb07b8f3e8b309a4b0dc17501928b9f2"} \ No newline at end of file diff --git a/sized-chunks/CHANGELOG.md b/sized-chunks/CHANGELOG.md new file mode 100644 index 000000000..eb8d042ec --- /dev/null +++ b/sized-chunks/CHANGELOG.md @@ -0,0 +1,43 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic +Versioning](http://semver.org/spec/v2.0.0.html). + +## [0.1.3] - 2019-04-12 + +### ADDED + +- `SparseChunk` now has a default length of `U64`. +- `Chunk` now has `PartialEq` defined for anything that can be borrowed as a + slice. +- `SparseChunk<A>` likewise has `PartialEq` defined for `BTreeMap<usize, A>` and + `HashMap<usize, A>`. These are intended for debugging and aren't optimally + `efficient. +- `Chunk` and `SparseChunk` now have a new method `capacity()` which returns its + maximum capacity (the number in the type) as a usize. +- Added an `entries()` method to `SparseChunk`. +- `SparseChunk` now has a `Debug` implementation. + +### FIXED + +- Extensive integration tests were added for `Chunk` and `SparseChunk`. +- `Chunk::clear` is now very slightly faster. + +## [0.1.2] - 2019-03-11 + +### FIXED + +- Fixed an alignment issue in `Chunk::drain_from_back`. (#1) + +## [0.1.1] - 2019-02-19 + +### FIXED + +- Some 2018 edition issues. + +## [0.1.0] - 2019-02-19 + +Initial release. diff --git a/sized-chunks/CODE_OF_CONDUCT.md b/sized-chunks/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..02a086970 --- /dev/null +++ b/sized-chunks/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at admin@immutable.rs. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/sized-chunks/Cargo.toml b/sized-chunks/Cargo.toml new file mode 100644 index 000000000..4b225b308 --- /dev/null +++ b/sized-chunks/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "sized-chunks" +version = "0.1.3" +authors = ["Bodil Stokke <bodil@bodil.org>"] +exclude = ["release.toml", "proptest-regressions/**"] +description = "Efficient sized chunk datatypes" +documentation = "http://docs.rs/sized-chunks" +readme = "./README.md" +keywords = ["sparse-array"] +categories = ["data-structures"] +license = "MPL-2.0+" +repository = "https://github.com/bodil/sized-chunks" +[dependencies.typenum] +version = "1.10.0" +[dev-dependencies.proptest] +version = "0.9.1" + +[dev-dependencies.proptest-derive] +version = "0.1.0" +[badges.travis-ci] +repository = "bodil/sized-chunks" diff --git a/sized-chunks/LICENCE.md b/sized-chunks/LICENCE.md new file mode 100644 index 000000000..cd44203cd --- /dev/null +++ b/sized-chunks/LICENCE.md @@ -0,0 +1,355 @@ +Mozilla Public License Version 2.0 +================================== + +### 1. Definitions + +**1.1. “Contributor”** + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +**1.2. “Contributor Version”** + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +**1.3. “Contribution”** + means Covered Software of a particular Contributor. + +**1.4. “Covered Software”** + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +**1.5. “Incompatible With Secondary Licenses”** + means + +* **(a)** that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or +* **(b)** that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +**1.6. “Executable Form”** + means any form of the work other than Source Code Form. + +**1.7. “Larger Work”** + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +**1.8. “License”** + means this document. + +**1.9. “Licensable”** + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +**1.10. “Modifications”** + means any of the following: + +* **(a)** any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or +* **(b)** any new file in Source Code Form that contains any Covered + Software. + +**1.11. “Patent Claims” of a Contributor** + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +**1.12. “Secondary License”** + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +**1.13. “Source Code Form”** + means the form of the work preferred for making modifications. + +**1.14. “You” (or “Your”)** + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, “control” means **(a)** the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or **(b)** ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + + +### 2. License Grants and Conditions + +#### 2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +* **(a)** under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and +* **(b)** under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +#### 2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +#### 2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +* **(a)** for any code that a Contributor has removed from Covered Software; + or +* **(b)** for infringements caused by: **(i)** Your and any other third party's + modifications of Covered Software, or **(ii)** the combination of its + Contributions with other software (except as part of its Contributor + Version); or +* **(c)** under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +#### 2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +#### 2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +#### 2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +#### 2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + + +### 3. Responsibilities + +#### 3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +#### 3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +* **(a)** such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +* **(b)** You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +#### 3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +#### 3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +#### 3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + + +### 4. Inability to Comply Due to Statute or Regulation + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: **(a)** comply with +the terms of this License to the maximum extent possible; and **(b)** +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + + +### 5. Termination + +**5.1.** The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated **(a)** provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and **(b)** on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +**5.2.** If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + + +### 6. Disclaimer of Warranty + +> Covered Software is provided under this License on an “as is” +> basis, without warranty of any kind, either expressed, implied, or +> statutory, including, without limitation, warranties that the +> Covered Software is free of defects, merchantable, fit for a +> particular purpose or non-infringing. The entire risk as to the +> quality and performance of the Covered Software is with You. +> Should any Covered Software prove defective in any respect, You +> (not any Contributor) assume the cost of any necessary servicing, +> repair, or correction. This disclaimer of warranty constitutes an +> essential part of this License. No use of any Covered Software is +> authorized under this License except under this disclaimer. + +### 7. Limitation of Liability + +> Under no circumstances and under no legal theory, whether tort +> (including negligence), contract, or otherwise, shall any +> Contributor, or anyone who distributes Covered Software as +> permitted above, be liable to You for any direct, indirect, +> special, incidental, or consequential damages of any character +> including, without limitation, damages for lost profits, loss of +> goodwill, work stoppage, computer failure or malfunction, or any +> and all other commercial damages or losses, even if such party +> shall have been informed of the possibility of such damages. This +> limitation of liability shall not apply to liability for death or +> personal injury resulting from such party's negligence to the +> extent applicable law prohibits such limitation. Some +> jurisdictions do not allow the exclusion or limitation of +> incidental or consequential damages, so this exclusion and +> limitation may not apply to You. + + +### 8. Litigation + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + + +### 9. Miscellaneous + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + + +### 10. Versions of the License + +#### 10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +#### 10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +#### 10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +## Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +## Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/sized-chunks/README.md b/sized-chunks/README.md new file mode 100644 index 000000000..0bb3c31a7 --- /dev/null +++ b/sized-chunks/README.md @@ -0,0 +1,35 @@ +# sized-chunks + +Various fixed length array data types, designed for [immutable.rs]. + +## Overview + +This crate provides the core building blocks for the immutable data structures +in [immutable.rs]: a sized array with O(1) amortised double ended push/pop and +smarter insert/remove performance (used by `im::Vector` and `im::OrdMap`), and a +fixed size sparse array (used by `im::HashMap`). + +In a nutshell, this crate contains the unsafe bits from [immutable.rs], which +may or may not be useful to anyone else, and have been split out for ease of +auditing. + +## Documentation + +* [API docs](https://docs.rs/sized-chunks) + +## Licence + +Copyright 2019 Bodil Stokke + +This software is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/. + +## Code of Conduct + +Please note that this project is released with a [Contributor Code of +Conduct][coc]. By participating in this project you agree to abide by its +terms. + +[immutable.rs]: https://immutable.rs/ +[coc]: https://github.com/bodil/sized-chunks/blob/master/CODE_OF_CONDUCT.md diff --git a/sized-chunks/src/bitmap.rs b/sized-chunks/src/bitmap.rs new file mode 100644 index 000000000..8ffab2a03 --- /dev/null +++ b/sized-chunks/src/bitmap.rs @@ -0,0 +1,165 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! A fixed capacity sparse array. +//! +//! See [`Bitmap`](struct.Bitmap.html) + +use std::fmt::{Debug, Error, Formatter}; + +use crate::types::Bits; + +/// A compact array of bits. +/// +/// The bitmap is stored as a primitive type, so the maximum value of `Size` is +/// currently 128, corresponding to a type of `u128`. The type used to store the +/// bitmap will be the minimum unsigned integer type required to fit the number +/// of bits required, from `u8` to `u128`. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate sized_chunks; +/// # extern crate typenum; +/// # use sized_chunks::bitmap::Bitmap; +/// # use typenum::U10; +/// # fn main() { +/// let mut bitmap = Bitmap::<U10>::new(); +/// assert_eq!(bitmap.set(5, true), false); +/// assert_eq!(bitmap.set(5, true), true); +/// assert_eq!(bitmap.get(5), true); +/// assert_eq!(bitmap.get(6), false); +/// assert_eq!(bitmap.len(), 1); +/// assert_eq!(bitmap.set(3, true), false); +/// assert_eq!(bitmap.len(), 2); +/// assert_eq!(bitmap.first_index(), Some(3)); +/// # } +/// ``` +pub struct Bitmap<Size: Bits> { + data: Size::Store, +} + +impl<Size: Bits> Clone for Bitmap<Size> { + fn clone(&self) -> Self { + Bitmap { data: self.data } + } +} + +impl<Size: Bits> Copy for Bitmap<Size> {} + +impl<Size: Bits> Default for Bitmap<Size> { + fn default() -> Self { + Bitmap { + data: Size::Store::default(), + } + } +} + +impl<Size: Bits> PartialEq for Bitmap<Size> { + fn eq(&self, other: &Self) -> bool { + self.data == other.data + } +} + +impl<Size: Bits> Debug for Bitmap<Size> { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + self.data.fmt(f) + } +} + +impl<Size: Bits> Bitmap<Size> { + /// Construct an empty bitmap. + #[inline] + pub fn new() -> Self { + Self::default() + } + + /// Count the number of `true` bits in the bitmap. + #[inline] + pub fn len(self) -> usize { + Size::len(&self.data) + } + + /// Test if the bitmap contains only `false` bits. + #[inline] + pub fn is_empty(self) -> bool { + self.first_index().is_none() + } + + /// Get the value of the bit at a given index. + #[inline] + pub fn get(self, index: usize) -> bool { + Size::get(&self.data, index) + } + + /// Set the value of the bit at a given index. + /// + /// Returns the previous value of the bit. + #[inline] + pub fn set(&mut self, index: usize, value: bool) -> bool { + Size::set(&mut self.data, index, value) + } + + /// Find the index of the first `true` bit in the bitmap. + #[inline] + pub fn first_index(self) -> Option<usize> { + Size::first_index(&self.data) + } +} + +impl<Size: Bits> IntoIterator for Bitmap<Size> { + type Item = usize; + type IntoIter = Iter<Size>; + + fn into_iter(self) -> Self::IntoIter { + Iter { + index: 0, + data: self.data, + } + } +} + +pub struct Iter<Size: Bits> { + index: usize, + data: Size::Store, +} + +impl<Size: Bits> Iterator for Iter<Size> { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + if self.index >= Size::USIZE { + return None; + } + if Size::get(&self.data, self.index) { + self.index += 1; + Some(self.index - 1) + } else { + self.index += 1; + self.next() + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::collection::btree_set; + use proptest::proptest; + use typenum::U64; + + proptest! { + #[test] + fn get_set_and_iter(bits in btree_set(0..64usize, 0..64)) { + let mut bitmap = Bitmap::<U64>::new(); + for i in &bits { + bitmap.set(*i, true); + } + for i in 0..64 { + assert_eq!(bitmap.get(i), bits.contains(&i)); + } + assert!(bitmap.into_iter().eq(bits.into_iter())); + } + } +} diff --git a/sized-chunks/src/lib.rs b/sized-chunks/src/lib.rs new file mode 100644 index 000000000..98017e872 --- /dev/null +++ b/sized-chunks/src/lib.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +pub mod bitmap; +pub mod sized_chunk; +pub mod sparse_chunk; +pub mod types; + +#[cfg(test)] +mod tests; + +#[doc(inline)] +pub use crate::bitmap::Bitmap; +#[doc(inline)] +pub use crate::sized_chunk::Chunk; +#[doc(inline)] +pub use crate::sparse_chunk::SparseChunk; diff --git a/sized-chunks/src/sized_chunk.rs b/sized-chunks/src/sized_chunk.rs new file mode 100644 index 000000000..90b1fec6c --- /dev/null +++ b/sized-chunks/src/sized_chunk.rs @@ -0,0 +1,1178 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! A fixed capacity smart array. +//! +//! See [`Chunk`](struct.Chunk.html) + +use std::borrow::{Borrow, BorrowMut}; +use std::cmp::Ordering; +use std::fmt::{Debug, Error, Formatter}; +use std::hash::{Hash, Hasher}; +use std::io; +use std::iter::{FromIterator, FusedIterator}; +use std::mem::{self, replace, ManuallyDrop}; +use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::ptr; +use std::slice::{ + from_raw_parts, from_raw_parts_mut, Iter as SliceIter, IterMut as SliceIterMut, SliceIndex, +}; + +use typenum::U64; + +use crate::types::ChunkLength; + +/// A fixed capacity smart array. +/// +/// An inline array of items with a variable length but a fixed, preallocated +/// capacity given by the `N` type, which must be an [`Unsigned`][Unsigned] type +/// level numeral. +/// +/// It's 'smart' because it's able to reorganise its contents based on expected +/// behaviour. If you construct one using `push_back`, it will be laid out like +/// a `Vec` with space at the end. If you `push_front` it will start filling in +/// values from the back instead of the front, so that you still get linear time +/// push as long as you don't reverse direction. If you do, and there's no room +/// at the end you're pushing to, it'll shift its contents over to the other +/// side, creating more space to push into. This technique is tuned for +/// `Chunk`'s expected use case in [im::Vector]: usually, chunks always see +/// either `push_front` or `push_back`, but not both unless they move around +/// inside the tree, in which case they're able to reorganise themselves with +/// reasonable efficiency to suit their new usage patterns. +/// +/// It maintains a `left` index and a `right` index instead of a simple length +/// counter in order to accomplish this, much like a ring buffer would, except +/// that the `Chunk` keeps all its items sequentially in memory so that you can +/// always get a `&[A]` slice for them, at the price of the occasional +/// reordering operation. The allocated size of a `Chunk` is thus `usize` * 2 + +/// `A` * `N`. +/// +/// This technique also lets us choose to shift the shortest side to account for +/// the inserted or removed element when performing insert and remove +/// operations, unlike `Vec` where you always need to shift the right hand side. +/// +/// Unlike a `Vec`, the `Chunk` has a fixed capacity and cannot grow beyond it. +/// Being intended for low level use, it expects you to know or test whether +/// you're pushing to a full array, and has an API more geared towards panics +/// than returning `Option`s, on the assumption that you know what you're doing. +/// Of course, if you don't, you can expect it to panic immediately rather than +/// do something undefined and usually bad. +/// +/// ## Isn't this just a less efficient ring buffer? +/// +/// You might be wondering why you would want to use this data structure rather +/// than a [ring buffer], which is similar but doesn't need to shift its content +/// around when it hits the sides of the allocated buffer. The answer is that +/// `Chunk` can be dereferenced into a slice, while a ring buffer can not. If +/// you don't need to be able to do that, a ring buffer will generally be the +/// more efficient choice. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate sized_chunks; +/// # extern crate typenum; +/// # use sized_chunks::Chunk; +/// # use typenum::U64; +/// # fn main() { +/// // Construct a chunk with a 64 item capacity +/// let mut chunk = Chunk::<i32, U64>::new(); +/// // Fill it with descending numbers +/// chunk.extend((0..64).rev()); +/// // It derefs to a slice so we can use standard slice methods +/// chunk.sort(); +/// // It's got all the amenities like `FromIterator` and `Eq` +/// let expected: Chunk<i32, U64> = (0..64).collect(); +/// assert_eq!(expected, chunk); +/// # } +/// ``` +/// +/// [Unsigned]: https://docs.rs/typenum/1.10.0/typenum/marker_traits/trait.Unsigned.html +/// [im::Vector]: https://docs.rs/im/latest/im/vector/enum.Vector.html +/// [ring buffer]: https://en.wikipedia.org/wiki/Circular_buffer +pub struct Chunk<A, N = U64> +where + N: ChunkLength<A>, +{ + left: usize, + right: usize, + data: ManuallyDrop<N::SizedType>, +} + +impl<A, N> Drop for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn drop(&mut self) { + if mem::needs_drop::<A>() { + for i in self.left..self.right { + unsafe { Chunk::force_drop(i, self) } + } + } + } +} + +impl<A, N> Clone for Chunk<A, N> +where + A: Clone, + N: ChunkLength<A>, +{ + fn clone(&self) -> Self { + let mut out = Self::new(); + out.left = self.left; + out.right = self.right; + for index in self.left..self.right { + unsafe { Chunk::force_write(index, self.values()[index].clone(), &mut out) } + } + out + } +} + +impl<A, N> Chunk<A, N> +where + N: ChunkLength<A>, +{ + /// Construct a new empty chunk. + pub fn new() -> Self { + let mut chunk: Self; + unsafe { + chunk = mem::zeroed(); + ptr::write(&mut chunk.left, 0); + ptr::write(&mut chunk.right, 0); + } + chunk + } + + /// Construct a new chunk with one item. + pub fn unit(value: A) -> Self { + let mut chunk: Self; + unsafe { + chunk = mem::zeroed(); + ptr::write(&mut chunk.left, 0); + ptr::write(&mut chunk.right, 1); + Chunk::force_write(0, value, &mut chunk); + } + chunk + } + + /// Construct a new chunk with two items. + pub fn pair(left: A, right: A) -> Self { + let mut chunk: Self; + unsafe { + chunk = mem::zeroed(); + ptr::write(&mut chunk.left, 0); + ptr::write(&mut chunk.right, 2); + Chunk::force_write(0, left, &mut chunk); + Chunk::force_write(1, right, &mut chunk); + } + chunk + } + + /// Construct a new chunk and move every item from `other` into the new + /// chunk. + /// + /// Time: O(n) + pub fn drain_from(other: &mut Self) -> Self { + let other_len = other.len(); + Self::from_front(other, other_len) + } + + /// Construct a new chunk and populate it by taking `count` items from the + /// iterator `iter`. + /// + /// Panics if the iterator contains less than `count` items. + /// + /// Time: O(n) + pub fn collect_from<I>(iter: &mut I, mut count: usize) -> Self + where + I: Iterator<Item = A>, + { + let mut chunk = Self::new(); + while count > 0 { + count -= 1; + chunk.push_back( + iter.next() + .expect("Chunk::collect_from: underfull iterator"), + ); + } + chunk + } + + /// Construct a new chunk and populate it by taking `count` items from the + /// front of `other`. + /// + /// Time: O(n) for the number of items moved + pub fn from_front(other: &mut Self, count: usize) -> Self { + let other_len = other.len(); + debug_assert!(count <= other_len); + let mut chunk = Self::new(); + unsafe { Chunk::force_copy_to(other.left, 0, count, other, &mut chunk) }; + chunk.right = count; + other.left += count; + chunk + } + + /// Construct a new chunk and populate it by taking `count` items from the + /// back of `other`. + /// + /// Time: O(n) for the number of items moved + pub fn from_back(other: &mut Self, count: usize) -> Self { + let other_len = other.len(); + debug_assert!(count <= other_len); + let mut chunk = Self::new(); + unsafe { Chunk::force_copy_to(other.right - count, 0, count, other, &mut chunk) }; + chunk.right = count; + other.right -= count; + chunk + } + + /// Get the length of the chunk. + #[inline] + pub fn len(&self) -> usize { + self.right - self.left + } + + /// Get the capacity of a chunk of this type. + #[inline] + pub fn capacity() -> usize { + N::USIZE + } + + /// Test if the chunk is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.left == self.right + } + + /// Test if the chunk is at capacity. + #[inline] + pub fn is_full(&self) -> bool { + self.left == 0 && self.right == N::USIZE + } + + #[inline] + fn values(&self) -> &[A] { + unsafe { + from_raw_parts( + &self.data as *const ManuallyDrop<N::SizedType> as *const A, + N::USIZE, + ) + } + } + + #[inline] + fn values_mut(&mut self) -> &mut [A] { + unsafe { + from_raw_parts_mut( + &mut self.data as *mut ManuallyDrop<N::SizedType> as *mut A, + N::USIZE, + ) + } + } + + /// Copy the value at an index, discarding ownership of the copied value + #[inline] + unsafe fn force_read(index: usize, chunk: &mut Self) -> A { + ptr::read(&chunk.values()[index]) + } + + /// Write a value at an index without trying to drop what's already there + #[inline] + unsafe fn force_write(index: usize, value: A, chunk: &mut Self) { + ptr::write(&mut chunk.values_mut()[index], value) + } + + /// Drop the value at an index + #[inline] + unsafe fn force_drop(index: usize, chunk: &mut Self) { + ptr::drop_in_place(&mut chunk.values_mut()[index]) + } + + /// Copy a range within a chunk + #[inline] + unsafe fn force_copy(from: usize, to: usize, count: usize, chunk: &mut Self) { + if count > 0 { + ptr::copy(&chunk.values()[from], &mut chunk.values_mut()[to], count) + } + } + + /// Copy a range between chunks + #[inline] + unsafe fn force_copy_to( + from: usize, + to: usize, + count: usize, + chunk: &mut Self, + other: &mut Self, + ) { + if count > 0 { + ptr::copy_nonoverlapping(&chunk.values()[from], &mut other.values_mut()[to], count) + } + } + + /// Push an item to the front of the chunk. + /// + /// Panics if the capacity of the chunk is exceeded. + /// + /// Time: O(1) if there's room at the front, O(n) otherwise + pub fn push_front(&mut self, value: A) { + if self.is_full() { + panic!("Chunk::push_front: can't push to full chunk"); + } + if self.is_empty() { + self.left = N::USIZE; + self.right = N::USIZE; + } else if self.left == 0 { + self.left = N::USIZE - self.right; + unsafe { Chunk::force_copy(0, self.left, self.right, self) }; + self.right = N::USIZE; + } + self.left -= 1; + unsafe { Chunk::force_write(self.left, value, self) } + } + + /// Push an item to the back of the chunk. + /// + /// Panics if the capacity of the chunk is exceeded. + /// + /// Time: O(1) if there's room at the back, O(n) otherwise + pub fn push_back(&mut self, value: A) { + if self.is_full() { + panic!("Chunk::push_back: can't push to full chunk"); + } + if self.is_empty() { + self.left = 0; + self.right = 0; + } else if self.right == N::USIZE { + unsafe { Chunk::force_copy(self.left, 0, self.len(), self) }; + self.right = N::USIZE - self.left; + self.left = 0; + } + unsafe { Chunk::force_write(self.right, value, self) } + self.right += 1; + } + + /// Pop an item off the front of the chunk. + /// + /// Panics if the chunk is empty. + /// + /// Time: O(1) + pub fn pop_front(&mut self) -> A { + if self.is_empty() { + panic!("Chunk::pop_front: can't pop from empty chunk"); + } else { + let value = unsafe { Chunk::force_read(self.left, self) }; + self.left += 1; + value + } + } + + /// Pop an item off the back of the chunk. + /// + /// Panics if the chunk is empty. + /// + /// Time: O(1) + pub fn pop_back(&mut self) -> A { + if self.is_empty() { + panic!("Chunk::pop_back: can't pop from empty chunk"); + } else { + self.right -= 1; + unsafe { Chunk::force_read(self.right, self) } + } + } + + /// Discard all items up to but not including `index`. + /// + /// Panics if `index` is out of bounds. + /// + /// Time: O(n) for the number of items dropped + pub fn drop_left(&mut self, index: usize) { + if index > 0 { + if index > self.len() { + panic!("Chunk::drop_left: index out of bounds"); + } + let start = self.left; + for i in start..(start + index) { + unsafe { Chunk::force_drop(i, self) } + } + self.left += index; + } + } + + /// Discard all items from `index` onward. + /// + /// Panics if `index` is out of bounds. + /// + /// Time: O(n) for the number of items dropped + pub fn drop_right(&mut self, index: usize) { + if index > self.len() { + panic!("Chunk::drop_right: index out of bounds"); + } + if index == self.len() { + return; + } + let start = self.left + index; + for i in start..self.right { + unsafe { Chunk::force_drop(i, self) } + } + self.right = start; + } + + /// Split a chunk into two, the original chunk containing + /// everything up to `index` and the returned chunk containing + /// everything from `index` onwards. + /// + /// Panics if `index` is out of bounds. + /// + /// Time: O(n) for the number of items in the new chunk + pub fn split_off(&mut self, index: usize) -> Self { + if index > self.len() { + panic!("Chunk::split: index out of bounds"); + } + if index == self.len() { + return Self::new(); + } + let mut right_chunk = Self::new(); + let start = self.left + index; + let len = self.right - start; + unsafe { Chunk::force_copy_to(start, 0, len, self, &mut right_chunk) }; + right_chunk.right = len; + self.right = start; + right_chunk + } + + /// Remove all items from `other` and append them to the back of `self`. + /// + /// Panics if the capacity of the chunk is exceeded. + /// + /// Time: O(n) for the number of items moved + pub fn append(&mut self, other: &mut Self) { + let self_len = self.len(); + let other_len = other.len(); + if self_len + other_len > N::USIZE { + panic!("Chunk::append: chunk size overflow"); + } + if self.right + other_len > N::USIZE { + unsafe { Chunk::force_copy(self.left, 0, self_len, self) }; + self.right -= self.left; + self.left = 0; + } + unsafe { Chunk::force_copy_to(other.left, self.right, other_len, other, self) }; + self.right += other_len; + other.left = 0; + other.right = 0; + } + + /// Remove `count` items from the front of `other` and append them to the + /// back of `self`. + /// + /// Panics if `self` doesn't have `count` items left, or if `other` has + /// fewer than `count` items. + /// + /// Time: O(n) for the number of items moved + pub fn drain_from_front(&mut self, other: &mut Self, count: usize) { + let self_len = self.len(); + let other_len = other.len(); + debug_assert!(self_len + count <= N::USIZE); + debug_assert!(other_len >= count); + if self.right + count > N::USIZE { + unsafe { Chunk::force_copy(self.left, 0, self_len, self) }; + self.right -= self.left; + self.left = 0; + } + unsafe { Chunk::force_copy_to(other.left, self.right, count, other, self) }; + self.right += count; + other.left += count; + } + + /// Remove `count` items from the back of `other` and append them to the + /// front of `self`. + /// + /// Panics if `self` doesn't have `count` items left, or if `other` has + /// fewer than `count` items. + /// + /// Time: O(n) for the number of items moved + pub fn drain_from_back(&mut self, other: &mut Self, count: usize) { + let self_len = self.len(); + let other_len = other.len(); + debug_assert!(self_len + count <= N::USIZE); + debug_assert!(other_len >= count); + if self.left < count { + unsafe { Chunk::force_copy(self.left, N::USIZE - self_len, self_len, self) }; + self.left = N::USIZE - self_len; + self.right = N::USIZE; + } + unsafe { Chunk::force_copy_to(other.right - count, self.left - count, count, other, self) }; + self.left -= count; + other.right -= count; + } + + /// Update the value at index `index`, returning the old value. + /// + /// Panics if `index` is out of bounds. + /// + /// Time: O(1) + pub fn set(&mut self, index: usize, value: A) -> A { + replace(&mut self[index], value) + } + + /// Insert a new value at index `index`, shifting all the following values + /// to the right. + /// + /// Panics if the index is out of bounds. + /// + /// Time: O(n) for the number of items shifted + pub fn insert(&mut self, index: usize, value: A) { + if self.is_full() { + panic!("Chunk::insert: chunk is full"); + } + if index > self.len() { + panic!("Chunk::insert: index out of bounds"); + } + let real_index = index + self.left; + let left_size = index; + let right_size = self.right - real_index; + if self.right == N::USIZE || (self.left > 0 && left_size < right_size) { + unsafe { + Chunk::force_copy(self.left, self.left - 1, left_size, self); + Chunk::force_write(real_index - 1, value, self); + } + self.left -= 1; + } else { + unsafe { + Chunk::force_copy(real_index, real_index + 1, right_size, self); + Chunk::force_write(real_index, value, self); + } + self.right += 1; + } + } + + /// Remove the value at index `index`, shifting all the following values to + /// the left. + /// + /// Returns the removed value. + /// + /// Panics if the index is out of bounds. + /// + /// Time: O(n) for the number of items shifted + pub fn remove(&mut self, index: usize) -> A { + if index >= self.len() { + panic!("Chunk::remove: index out of bounds"); + } + let real_index = index + self.left; + let value = unsafe { Chunk::force_read(real_index, self) }; + let left_size = index; + let right_size = self.right - real_index - 1; + if left_size < right_size { + unsafe { Chunk::force_copy(self.left, self.left + 1, left_size, self) }; + self.left += 1; + } else { + unsafe { Chunk::force_copy(real_index + 1, real_index, right_size, self) }; + self.right -= 1; + } + value + } + + /// Construct an iterator that drains values from the front of the chunk. + pub fn drain(&mut self) -> Drain<'_, A, N> { + Drain { chunk: self } + } + + /// Discard the contents of the chunk. + /// + /// Time: O(n) + pub fn clear(&mut self) { + for i in self.left..self.right { + unsafe { Chunk::force_drop(i, self) } + } + self.left = 0; + self.right = 0; + } + + /// Get a reference to the contents of the chunk as a slice. + pub fn as_slice(&self) -> &[A] { + unsafe { + from_raw_parts( + (&self.data as *const ManuallyDrop<N::SizedType> as *const A).add(self.left), + self.len(), + ) + } + } + + /// Get a reference to the contents of the chunk as a mutable slice. + pub fn as_mut_slice(&mut self) -> &mut [A] { + unsafe { + from_raw_parts_mut( + (&mut self.data as *mut ManuallyDrop<N::SizedType> as *mut A).add(self.left), + self.len(), + ) + } + } +} + +impl<A, N> Default for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn default() -> Self { + Self::new() + } +} + +impl<A, N, I> Index<I> for Chunk<A, N> +where + I: SliceIndex<[A]>, + N: ChunkLength<A>, +{ + type Output = I::Output; + fn index(&self, index: I) -> &Self::Output { + self.as_slice().index(index) + } +} + +impl<A, N, I> IndexMut<I> for Chunk<A, N> +where + I: SliceIndex<[A]>, + N: ChunkLength<A>, +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.as_mut_slice().index_mut(index) + } +} + +impl<A, N> Debug for Chunk<A, N> +where + A: Debug, + N: ChunkLength<A>, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.write_str("Chunk")?; + f.debug_list().entries(self.iter()).finish() + } +} + +impl<A, N> Hash for Chunk<A, N> +where + A: Hash, + N: ChunkLength<A>, +{ + fn hash<H>(&self, hasher: &mut H) + where + H: Hasher, + { + for item in self { + item.hash(hasher) + } + } +} + +impl<A, N, Slice> PartialEq<Slice> for Chunk<A, N> +where + Slice: Borrow<[A]>, + A: PartialEq, + N: ChunkLength<A>, +{ + fn eq(&self, other: &Slice) -> bool { + self.as_slice() == other.borrow() + } +} + +impl<A, N> Eq for Chunk<A, N> +where + A: Eq, + N: ChunkLength<A>, +{ +} + +impl<A, N> PartialOrd for Chunk<A, N> +where + A: PartialOrd, + N: ChunkLength<A>, +{ + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.iter().partial_cmp(other.iter()) + } +} + +impl<A, N> Ord for Chunk<A, N> +where + A: Ord, + N: ChunkLength<A>, +{ + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl<N> io::Write for Chunk<u8, N> +where + N: ChunkLength<u8>, +{ + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let old_len = self.len(); + self.extend(buf.iter().cloned().take(N::USIZE - old_len)); + Ok(self.len() - old_len) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl<A, N> Borrow<[A]> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn borrow(&self) -> &[A] { + self.as_slice() + } +} + +impl<A, N> BorrowMut<[A]> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn borrow_mut(&mut self) -> &mut [A] { + self.as_mut_slice() + } +} + +impl<A, N> AsRef<[A]> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn as_ref(&self) -> &[A] { + self.as_slice() + } +} + +impl<A, N> AsMut<[A]> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn as_mut(&mut self) -> &mut [A] { + self.as_mut_slice() + } +} + +impl<A, N> Deref for Chunk<A, N> +where + N: ChunkLength<A>, +{ + type Target = [A]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +impl<A, N> DerefMut for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() + } +} + +impl<A, N> FromIterator<A> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + fn from_iter<I>(it: I) -> Self + where + I: IntoIterator<Item = A>, + { + let mut chunk = Self::new(); + for item in it { + chunk.push_back(item); + } + chunk + } +} + +impl<'a, A, N> IntoIterator for &'a Chunk<A, N> +where + N: ChunkLength<A>, +{ + type Item = &'a A; + type IntoIter = SliceIter<'a, A>; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A, N> IntoIterator for &'a mut Chunk<A, N> +where + N: ChunkLength<A>, +{ + type Item = &'a mut A; + type IntoIter = SliceIterMut<'a, A>; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +impl<A, N> Extend<A> for Chunk<A, N> +where + N: ChunkLength<A>, +{ + /// Append the contents of the iterator to the back of the chunk. + /// + /// Panics if the chunk exceeds its capacity. + /// + /// Time: O(n) for the length of the iterator + fn extend<I>(&mut self, it: I) + where + I: IntoIterator<Item = A>, + { + for item in it { + self.push_back(item); + } + } +} + +impl<'a, A, N> Extend<&'a A> for Chunk<A, N> +where + A: 'a + Copy, + N: ChunkLength<A>, +{ + /// Append the contents of the iterator to the back of the chunk. + /// + /// Panics if the chunk exceeds its capacity. + /// + /// Time: O(n) for the length of the iterator + fn extend<I>(&mut self, it: I) + where + I: IntoIterator<Item = &'a A>, + { + for item in it { + self.push_back(*item); + } + } +} + +pub struct Iter<A, N> +where + N: ChunkLength<A>, +{ + chunk: Chunk<A, N>, +} + +impl<A, N> Iterator for Iter<A, N> +where + N: ChunkLength<A>, +{ + type Item = A; + fn next(&mut self) -> Option<Self::Item> { + if self.chunk.is_empty() { + None + } else { + Some(self.chunk.pop_front()) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.chunk.len(), Some(self.chunk.len())) + } +} + +impl<A, N> DoubleEndedIterator for Iter<A, N> +where + N: ChunkLength<A>, +{ + fn next_back(&mut self) -> Option<Self::Item> { + if self.chunk.is_empty() { + None + } else { + Some(self.chunk.pop_back()) + } + } +} + +impl<A, N> ExactSizeIterator for Iter<A, N> where N: ChunkLength<A> {} + +impl<A, N> FusedIterator for Iter<A, N> where N: ChunkLength<A> {} + +impl<A, N> IntoIterator for Chunk<A, N> +where + N: ChunkLength<A>, +{ + type Item = A; + type IntoIter = Iter<A, N>; + + fn into_iter(self) -> Self::IntoIter { + Iter { chunk: self } + } +} + +pub struct Drain<'a, A, N> +where + A: 'a, + N: ChunkLength<A> + 'a, +{ + chunk: &'a mut Chunk<A, N>, +} + +impl<'a, A, N> Iterator for Drain<'a, A, N> +where + A: 'a, + N: ChunkLength<A> + 'a, +{ + type Item = A; + + fn next(&mut self) -> Option<Self::Item> { + if self.chunk.is_empty() { + None + } else { + Some(self.chunk.pop_front()) + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.chunk.len(), Some(self.chunk.len())) + } +} + +impl<'a, A, N> ExactSizeIterator for Drain<'a, A, N> +where + A: 'a, + N: ChunkLength<A> + 'a, +{ +} + +impl<'a, A, N> FusedIterator for Drain<'a, A, N> +where + A: 'a, + N: ChunkLength<A> + 'a, +{ +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn is_full() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + assert_eq!(false, chunk.is_full()); + chunk.push_back(i); + } + assert_eq!(true, chunk.is_full()); + } + + #[test] + fn push_back_front() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 12..20 { + chunk.push_back(i); + } + assert_eq!(8, chunk.len()); + for i in (0..12).rev() { + chunk.push_front(i); + } + assert_eq!(20, chunk.len()); + for i in 20..32 { + chunk.push_back(i); + } + assert_eq!(32, chunk.len()); + let right: Vec<i32> = chunk.into_iter().collect(); + let left: Vec<i32> = (0..32).collect(); + assert_eq!(left, right); + } + + #[test] + fn push_and_pop() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + chunk.push_back(i); + } + for i in 0..64 { + assert_eq!(i, chunk.pop_front()); + } + for i in 0..64 { + chunk.push_front(i); + } + for i in 0..64 { + assert_eq!(i, chunk.pop_back()); + } + } + + #[test] + fn drop_left() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..6 { + chunk.push_back(i); + } + chunk.drop_left(3); + let vec: Vec<i32> = chunk.into_iter().collect(); + assert_eq!(vec![3, 4, 5], vec); + } + + #[test] + fn drop_right() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..6 { + chunk.push_back(i); + } + chunk.drop_right(3); + let vec: Vec<i32> = chunk.into_iter().collect(); + assert_eq!(vec![0, 1, 2], vec); + } + + #[test] + fn split_off() { + let mut left = Chunk::<_, U64>::new(); + for i in 0..6 { + left.push_back(i); + } + let right = left.split_off(3); + let left_vec: Vec<i32> = left.into_iter().collect(); + let right_vec: Vec<i32> = right.into_iter().collect(); + assert_eq!(vec![0, 1, 2], left_vec); + assert_eq!(vec![3, 4, 5], right_vec); + } + + #[test] + fn append() { + let mut left = Chunk::<_, U64>::new(); + for i in 0..32 { + left.push_back(i); + } + let mut right = Chunk::<_, U64>::new(); + for i in (32..64).rev() { + right.push_front(i); + } + left.append(&mut right); + let out_vec: Vec<i32> = left.into_iter().collect(); + let should_vec: Vec<i32> = (0..64).collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn ref_iter() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + chunk.push_back(i); + } + let out_vec: Vec<&i32> = chunk.iter().collect(); + let should_vec_p: Vec<i32> = (0..64).collect(); + let should_vec: Vec<&i32> = should_vec_p.iter().collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn mut_ref_iter() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + chunk.push_back(i); + } + let out_vec: Vec<&mut i32> = chunk.iter_mut().collect(); + let mut should_vec_p: Vec<i32> = (0..64).collect(); + let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn consuming_iter() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + chunk.push_back(i); + } + let out_vec: Vec<i32> = chunk.into_iter().collect(); + let should_vec: Vec<i32> = (0..64).collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn insert_middle() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..32 { + chunk.push_back(i); + } + for i in 33..64 { + chunk.push_back(i); + } + chunk.insert(32, 32); + let out_vec: Vec<i32> = chunk.into_iter().collect(); + let should_vec: Vec<i32> = (0..64).collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn insert_back() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..63 { + chunk.push_back(i); + } + chunk.insert(63, 63); + let out_vec: Vec<i32> = chunk.into_iter().collect(); + let should_vec: Vec<i32> = (0..64).collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn insert_front() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 1..64 { + chunk.push_front(64 - i); + } + chunk.insert(0, 0); + let out_vec: Vec<i32> = chunk.into_iter().collect(); + let should_vec: Vec<i32> = (0..64).collect(); + assert_eq!(should_vec, out_vec); + } + + #[test] + fn remove_value() { + let mut chunk = Chunk::<_, U64>::new(); + for i in 0..64 { + chunk.push_back(i); + } + chunk.remove(32); + let out_vec: Vec<i32> = chunk.into_iter().collect(); + let should_vec: Vec<i32> = (0..32).chain(33..64).collect(); + assert_eq!(should_vec, out_vec); + } + + use std::sync::atomic::{AtomicUsize, Ordering}; + + struct DropTest<'a> { + counter: &'a AtomicUsize, + } + + impl<'a> DropTest<'a> { + fn new(counter: &'a AtomicUsize) -> Self { + counter.fetch_add(1, Ordering::Relaxed); + DropTest { counter } + } + } + + impl<'a> Drop for DropTest<'a> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + #[test] + fn dropping() { + let counter = AtomicUsize::new(0); + { + let mut chunk: Chunk<DropTest> = Chunk::new(); + for _i in 0..20 { + chunk.push_back(DropTest::new(&counter)) + } + for _i in 0..20 { + chunk.push_front(DropTest::new(&counter)) + } + assert_eq!(40, counter.load(Ordering::Relaxed)); + for _i in 0..10 { + chunk.pop_back(); + } + assert_eq!(30, counter.load(Ordering::Relaxed)); + } + assert_eq!(0, counter.load(Ordering::Relaxed)); + } +} diff --git a/sized-chunks/src/sparse_chunk.rs b/sized-chunks/src/sparse_chunk.rs new file mode 100644 index 000000000..8a7a0a99d --- /dev/null +++ b/sized-chunks/src/sparse_chunk.rs @@ -0,0 +1,454 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +//! A fixed capacity sparse array. +//! +//! See [`SparseChunk`](struct.SparseChunk.html) + +use std::collections::{BTreeMap, HashMap}; +use std::fmt::{Debug, Error, Formatter}; +use std::mem::{self, ManuallyDrop}; +use std::ops::Index; +use std::ops::IndexMut; +use std::ptr; +use std::slice::{from_raw_parts, from_raw_parts_mut}; + +use typenum::U64; + +use crate::bitmap::{Bitmap, Iter as BitmapIter}; +use crate::types::{Bits, ChunkLength}; + +/// A fixed capacity sparse array. +/// +/// An inline sparse array of up to `N` items of type `A`, where `N` is an +/// [`Unsigned`][Unsigned] type level numeral. You can think of it as an array +/// of `Option<A>`, where the discriminant (whether the value is `Some<A>` or +/// `None`) is kept in a bitmap instead of adjacent to the value. +/// +/// Because the bitmap is kept in a primitive type, the maximum value of `N` is +/// currently 128, corresponding to a type of `u128`. The type of the bitmap +/// will be the minimum unsigned integer type required to fit the number of bits +/// required. Thus, disregarding memory alignment rules, the allocated size of a +/// `SparseChunk` will be `uX` + `A` * `N` where `uX` is the type of the +/// discriminant bitmap, either `u8`, `u16`, `u32`, `u64` or `u128`. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate sized_chunks; +/// # extern crate typenum; +/// # use sized_chunks::SparseChunk; +/// # use typenum::U20; +/// # fn main() { +/// // Construct a chunk with a 20 item capacity +/// let mut chunk = SparseChunk::<i32, U20>::new(); +/// // Set the 18th index to the value 5. +/// chunk.insert(18, 5); +/// // Set the 5th index to the value 23. +/// chunk.insert(5, 23); +/// +/// assert_eq!(chunk.len(), 2); +/// assert_eq!(chunk.get(5), Some(&23)); +/// assert_eq!(chunk.get(6), None); +/// assert_eq!(chunk.get(18), Some(&5)); +/// # } +/// ``` +/// +/// [Unsigned]: https://docs.rs/typenum/1.10.0/typenum/marker_traits/trait.Unsigned.html +pub struct SparseChunk<A, N: Bits + ChunkLength<A> = U64> { + map: Bitmap<N>, + data: ManuallyDrop<N::SizedType>, +} + +impl<A, N: Bits + ChunkLength<A>> Drop for SparseChunk<A, N> { + fn drop(&mut self) { + if mem::needs_drop::<A>() { + for index in self.map { + unsafe { SparseChunk::force_drop(index, self) } + } + } + } +} + +impl<A: Clone, N: Bits + ChunkLength<A>> Clone for SparseChunk<A, N> { + fn clone(&self) -> Self { + let mut out = Self::new(); + for index in self.map { + out.insert(index, self[index].clone()); + } + out + } +} + +impl<A, N: Bits + ChunkLength<A>> SparseChunk<A, N> { + #[inline] + fn values(&self) -> &[A] { + unsafe { + from_raw_parts( + &self.data as *const ManuallyDrop<N::SizedType> as *const A, + N::USIZE, + ) + } + } + + #[inline] + fn values_mut(&mut self) -> &mut [A] { + unsafe { + from_raw_parts_mut( + &mut self.data as *mut ManuallyDrop<N::SizedType> as *mut A, + N::USIZE, + ) + } + } + + /// Copy the value at an index, discarding ownership of the copied value + #[inline] + unsafe fn force_read(index: usize, chunk: &Self) -> A { + ptr::read(&chunk.values()[index as usize]) + } + + /// Write a value at an index without trying to drop what's already there + #[inline] + unsafe fn force_write(index: usize, value: A, chunk: &mut Self) { + ptr::write(&mut chunk.values_mut()[index as usize], value) + } + + /// Drop the value at an index + #[inline] + unsafe fn force_drop(index: usize, chunk: &mut Self) { + ptr::drop_in_place(&mut chunk.values_mut()[index]) + } + + /// Construct a new empty chunk. + pub fn new() -> Self { + let mut chunk: Self; + unsafe { + chunk = mem::zeroed(); + ptr::write(&mut chunk.map, Bitmap::new()); + } + chunk + } + + /// Construct a new chunk with one item. + pub fn unit(index: usize, value: A) -> Self { + let mut chunk = Self::new(); + chunk.insert(index, value); + chunk + } + + /// Construct a new chunk with two items. + pub fn pair(index1: usize, value1: A, index2: usize, value2: A) -> Self { + let mut chunk = Self::new(); + chunk.insert(index1, value1); + chunk.insert(index2, value2); + chunk + } + + /// Get the length of the chunk. + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Get the capacity of a chunk of this type. + #[inline] + pub fn capacity() -> usize { + N::USIZE + } + + /// Test if the chunk is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.map.len() == 0 + } + + /// Test if the chunk is at capacity. + #[inline] + pub fn is_full(&self) -> bool { + self.len() == N::USIZE + } + + /// Insert a new value at a given index. + /// + /// Returns the previous value at that index, if any. + pub fn insert(&mut self, index: usize, value: A) -> Option<A> { + if index >= N::USIZE { + panic!("SparseChunk::insert: index out of bounds"); + } + let prev = if self.map.set(index, true) { + Some(unsafe { SparseChunk::force_read(index, self) }) + } else { + None + }; + unsafe { SparseChunk::force_write(index, value, self) }; + prev + } + + /// Remove the value at a given index. + /// + /// Returns the value, or `None` if the index had no value. + pub fn remove(&mut self, index: usize) -> Option<A> { + if index >= N::USIZE { + panic!("SparseChunk::remove: index out of bounds"); + } + if self.map.set(index, false) { + Some(unsafe { SparseChunk::force_read(index, self) }) + } else { + None + } + } + + /// Remove the first value present in the array. + /// + /// Returns the value that was removed, or `None` if the array was empty. + pub fn pop(&mut self) -> Option<A> { + self.first_index().and_then(|index| self.remove(index)) + } + + /// Get the value at a given index. + pub fn get(&self, index: usize) -> Option<&A> { + if index >= N::USIZE { + return None; + } + if self.map.get(index) { + Some(&self.values()[index]) + } else { + None + } + } + + /// Get a mutable reference to the value at a given index. + pub fn get_mut(&mut self, index: usize) -> Option<&mut A> { + if index >= N::USIZE { + return None; + } + if self.map.get(index) { + Some(&mut self.values_mut()[index]) + } else { + None + } + } + + /// Make an iterator over the indices which contain values. + pub fn indices(&self) -> BitmapIter<N> { + self.map.into_iter() + } + + /// Find the first index which contains a value. + pub fn first_index(&self) -> Option<usize> { + self.map.first_index() + } + + /// Make an iterator of references to the values contained in the array. + pub fn iter(&self) -> Iter<'_, A, N> { + Iter { + indices: self.indices(), + chunk: self, + } + } + + /// Make an iterator of mutable references to the values contained in the + /// array. + pub fn iter_mut(&mut self) -> IterMut<'_, A, N> { + IterMut { + indices: self.indices(), + chunk: self, + } + } + + /// Turn the chunk into an iterator over the values contained within it. + pub fn drain(self) -> Drain<A, N> { + Drain { chunk: self } + } + + /// Make an iterator of pairs of indices and references to the values + /// contained in the array. + pub fn entries(&self) -> impl Iterator<Item = (usize, &A)> { + self.indices().zip(self.iter()) + } +} + +impl<A, N: Bits + ChunkLength<A>> Index<usize> for SparseChunk<A, N> { + type Output = A; + + #[inline] + fn index(&self, index: usize) -> &Self::Output { + self.get(index).unwrap() + } +} + +impl<A, N: Bits + ChunkLength<A>> IndexMut<usize> for SparseChunk<A, N> { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.get_mut(index).unwrap() + } +} + +impl<A, N: Bits + ChunkLength<A>> IntoIterator for SparseChunk<A, N> { + type Item = A; + type IntoIter = Drain<A, N>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.drain() + } +} + +impl<A, N> PartialEq for SparseChunk<A, N> +where + A: PartialEq, + N: Bits + ChunkLength<A>, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + for index in self.indices() { + if self.get(index) != other.get(index) { + return false; + } + } + true + } +} + +impl<A, N> PartialEq<BTreeMap<usize, A>> for SparseChunk<A, N> +where + A: PartialEq, + N: Bits + ChunkLength<A>, +{ + fn eq(&self, other: &BTreeMap<usize, A>) -> bool { + if self.len() != other.len() { + return false; + } + for index in 0..N::USIZE { + if self.get(index) != other.get(&index) { + return false; + } + } + true + } +} + +impl<A, N> PartialEq<HashMap<usize, A>> for SparseChunk<A, N> +where + A: PartialEq, + N: Bits + ChunkLength<A>, +{ + fn eq(&self, other: &HashMap<usize, A>) -> bool { + if self.len() != other.len() { + return false; + } + for index in 0..N::USIZE { + if self.get(index) != other.get(&index) { + return false; + } + } + true + } +} + +impl<A, N> Eq for SparseChunk<A, N> +where + A: Eq, + N: Bits + ChunkLength<A>, +{ +} + +impl<A, N> Debug for SparseChunk<A, N> +where + A: Debug, + N: Bits + ChunkLength<A>, +{ + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + f.write_str("SparseChunk")?; + f.debug_map().entries(self.entries()).finish() + } +} + +pub struct Iter<'a, A: 'a, N: 'a + Bits + ChunkLength<A>> { + indices: BitmapIter<N>, + chunk: &'a SparseChunk<A, N>, +} + +impl<'a, A, N: Bits + ChunkLength<A>> Iterator for Iter<'a, A, N> { + type Item = &'a A; + + fn next(&mut self) -> Option<Self::Item> { + self.indices.next().map(|index| &self.chunk.values()[index]) + } +} + +pub struct IterMut<'a, A: 'a, N: 'a + Bits + ChunkLength<A>> { + indices: BitmapIter<N>, + chunk: &'a mut SparseChunk<A, N>, +} + +impl<'a, A, N: Bits + ChunkLength<A>> Iterator for IterMut<'a, A, N> { + type Item = &'a mut A; + + fn next(&mut self) -> Option<Self::Item> { + if let Some(index) = self.indices.next() { + unsafe { + let p: *mut A = &mut self.chunk.values_mut()[index]; + Some(&mut *p) + } + } else { + None + } + } +} + +pub struct Drain<A, N: Bits + ChunkLength<A>> { + chunk: SparseChunk<A, N>, +} + +impl<'a, A, N: Bits + ChunkLength<A>> Iterator for Drain<A, N> { + type Item = A; + + fn next(&mut self) -> Option<Self::Item> { + self.chunk.pop() + } +} + +#[cfg(test)] +mod test { + use super::*; + use typenum::U32; + + #[test] + fn insert_remove_iterate() { + let mut chunk: SparseChunk<_, U32> = SparseChunk::new(); + assert_eq!(None, chunk.insert(5, 5)); + assert_eq!(None, chunk.insert(1, 1)); + assert_eq!(None, chunk.insert(24, 42)); + assert_eq!(None, chunk.insert(22, 22)); + assert_eq!(Some(42), chunk.insert(24, 24)); + assert_eq!(None, chunk.insert(31, 31)); + assert_eq!(Some(24), chunk.remove(24)); + assert_eq!(4, chunk.len()); + let indices: Vec<_> = chunk.indices().collect(); + assert_eq!(vec![1, 5, 22, 31], indices); + let values: Vec<_> = chunk.into_iter().collect(); + assert_eq!(vec![1, 5, 22, 31], values); + } + + #[test] + fn clone_chunk() { + let mut chunk: SparseChunk<_, U32> = SparseChunk::new(); + assert_eq!(None, chunk.insert(5, 5)); + assert_eq!(None, chunk.insert(1, 1)); + assert_eq!(None, chunk.insert(24, 42)); + assert_eq!(None, chunk.insert(22, 22)); + let cloned = chunk.clone(); + let right_indices: Vec<_> = chunk.indices().collect(); + let left_indices: Vec<_> = cloned.indices().collect(); + let right: Vec<_> = chunk.into_iter().collect(); + let left: Vec<_> = cloned.into_iter().collect(); + assert_eq!(left, right); + assert_eq!(left_indices, right_indices); + assert_eq!(vec![1, 5, 22, 24], left_indices); + assert_eq!(vec![1, 5, 22, 24], right_indices); + } +} diff --git a/sized-chunks/src/tests/mod.rs b/sized-chunks/src/tests/mod.rs new file mode 100644 index 000000000..ec258fa04 --- /dev/null +++ b/sized-chunks/src/tests/mod.rs @@ -0,0 +1,9 @@ +mod sized_chunk; +mod sparse_chunk; + +pub fn action_count() -> usize { + std::env::var("ACTION_COUNT") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(100) +} diff --git a/sized-chunks/src/tests/sized_chunk.rs b/sized-chunks/src/tests/sized_chunk.rs new file mode 100644 index 000000000..2990fb983 --- /dev/null +++ b/sized-chunks/src/tests/sized_chunk.rs @@ -0,0 +1,286 @@ +#![allow(clippy::unit_arg)] + +use std::fmt::Debug; +use std::iter::FromIterator; +use std::panic::{catch_unwind, AssertUnwindSafe}; + +use proptest::{arbitrary::any, collection::vec, prelude::*, proptest}; +use proptest_derive::Arbitrary; + +use crate::sized_chunk::Chunk; + +#[derive(Debug)] +struct InputVec<A>(Vec<A>); + +impl<A> InputVec<A> { + fn unwrap(self) -> Vec<A> { + self.0 + } +} + +impl<A> Arbitrary for InputVec<A> +where + A: Arbitrary + Debug, + <A as Arbitrary>::Strategy: 'static, +{ + type Parameters = usize; + type Strategy = BoxedStrategy<InputVec<A>>; + fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { + #[allow(clippy::redundant_closure)] + proptest::collection::vec(any::<A>(), 0..64) + .prop_map(|v| InputVec(v)) + .boxed() + } +} + +#[derive(Arbitrary, Debug)] +enum Construct<A> +where + A: Arbitrary, + <A as Arbitrary>::Strategy: 'static, +{ + Empty, + Single(A), + Pair((A, A)), + DrainFrom(InputVec<A>), + CollectFrom(InputVec<A>, usize), + FromFront(InputVec<A>, usize), + FromBack(InputVec<A>, usize), +} + +#[derive(Arbitrary, Debug)] +enum Action<A> +where + A: Arbitrary, + <A as Arbitrary>::Strategy: 'static, +{ + PushFront(A), + PushBack(A), + PopFront, + PopBack, + DropLeft(usize), + DropRight(usize), + SplitOff(usize), + Append(Construct<A>), + DrainFromFront(Construct<A>, usize), + DrainFromBack(Construct<A>, usize), + Set(usize, A), + Insert(usize, A), + Remove(usize), + Drain, + Clear, +} + +impl<A> Construct<A> +where + A: Arbitrary + Clone + Debug + Eq, + <A as Arbitrary>::Strategy: 'static, +{ + fn make(self) -> Chunk<A> { + match self { + Construct::Empty => { + let out = Chunk::new(); + assert!(out.is_empty()); + out + } + Construct::Single(value) => { + let out = Chunk::unit(value.clone()); + assert_eq!(out, vec![value]); + out + } + Construct::Pair((left, right)) => { + let out = Chunk::pair(left.clone(), right.clone()); + assert_eq!(out, vec![left, right]); + out + } + Construct::DrainFrom(vec) => { + let vec = vec.unwrap(); + let mut source = Chunk::from_iter(vec.iter().cloned()); + let out = Chunk::drain_from(&mut source); + assert!(source.is_empty()); + assert_eq!(out, vec); + out + } + Construct::CollectFrom(vec, len) => { + let mut vec = vec.unwrap(); + if vec.is_empty() { + return Chunk::new(); + } + let len = len % vec.len(); + let mut source = vec.clone().into_iter(); + let out = Chunk::collect_from(&mut source, len); + let expected_remainder = vec.split_off(len); + let remainder: Vec<_> = source.collect(); + assert_eq!(expected_remainder, remainder); + assert_eq!(out, vec); + out + } + Construct::FromFront(vec, len) => { + let mut vec = vec.unwrap(); + if vec.is_empty() { + return Chunk::new(); + } + let len = len % vec.len(); + let mut source = Chunk::from_iter(vec.iter().cloned()); + let out = Chunk::from_front(&mut source, len); + let remainder = vec.split_off(len); + assert_eq!(source, remainder); + assert_eq!(out, vec); + out + } + Construct::FromBack(vec, len) => { + let mut vec = vec.unwrap(); + if vec.is_empty() { + return Chunk::new(); + } + let len = len % vec.len(); + let mut source = Chunk::from_iter(vec.iter().cloned()); + let out = Chunk::from_back(&mut source, len); + let remainder = vec.split_off(vec.len() - len); + assert_eq!(out, remainder); + assert_eq!(source, vec); + out + } + } + } +} + +proptest! { + #[test] + fn test_constructors(cons: Construct<u32>) { + cons.make(); + } + + #[test] + fn test_actions(cons: Construct<u32>, actions in vec(any::<Action<u32>>(), 0..super::action_count())) { + let capacity = Chunk::<u32>::capacity(); + let mut chunk = cons.make(); + let mut guide: Vec<_> = chunk.iter().cloned().collect(); + for action in actions { + match action { + Action::PushFront(value) => { + if chunk.is_full() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.push_front(value))).is_err()); + } else { + chunk.push_front(value); + guide.insert(0, value); + } + } + Action::PushBack(value) => { + if chunk.is_full() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.push_back(value))).is_err()); + } else { + chunk.push_back(value); + guide.push(value); + } + } + Action::PopFront => { + if chunk.is_empty() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.pop_front())).is_err()); + } else { + assert_eq!(chunk.pop_front(), guide.remove(0)); + } + } + Action::PopBack => { + if chunk.is_empty() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.pop_back())).is_err()); + } else { + assert_eq!(chunk.pop_back(), guide.pop().unwrap()); + } + } + Action::DropLeft(index) => { + if index >= chunk.len() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.drop_left(index))).is_err()); + } else { + chunk.drop_left(index); + guide.drain(..index); + } + } + Action::DropRight(index) => { + if index >= chunk.len() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.drop_right(index))).is_err()); + } else { + chunk.drop_right(index); + guide.drain(index..); + } + } + Action::SplitOff(index) => { + if index >= chunk.len() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.split_off(index))).is_err()); + } else { + let chunk_off = chunk.split_off(index); + let guide_off = guide.split_off(index); + assert_eq!(chunk_off, guide_off); + } + } + Action::Append(other) => { + let mut other = other.make(); + let mut other_guide: Vec<_> = other.iter().cloned().collect(); + if other.len() + chunk.len() > capacity { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.append(&mut other))).is_err()); + } else { + chunk.append(&mut other); + guide.append(&mut other_guide); + } + } + Action::DrainFromFront(other, count) => { + let mut other = other.make(); + let mut other_guide: Vec<_> = other.iter().cloned().collect(); + if count >= other.len() || chunk.len() + count > capacity { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.drain_from_front(&mut other, count))).is_err()); + } else { + chunk.drain_from_front(&mut other, count); + guide.extend(other_guide.drain(..count)); + assert_eq!(other, other_guide); + } + } + Action::DrainFromBack(other, count) => { + let mut other = other.make(); + let mut other_guide: Vec<_> = other.iter().cloned().collect(); + if count >= other.len() || chunk.len() + count > capacity { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.drain_from_back(&mut other, count))).is_err()); + } else { + chunk.drain_from_back(&mut other, count); + let other_index = other.len() - count; + guide = other_guide.drain(other_index..).chain(guide.into_iter()).collect(); + assert_eq!(other, other_guide); + } + } + Action::Set(index, value) => { + if index >= chunk.len() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.set(index, value))).is_err()); + } else { + chunk.set(index, value); + guide[index] = value; + } + } + Action::Insert(index, value) => { + if index >= chunk.len() || chunk.is_full() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.insert(index, value))).is_err()); + } else { + chunk.insert(index, value); + guide.insert(index, value); + } + } + Action::Remove(index) => { + if index >= chunk.len() { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.remove(index))).is_err()); + } else { + assert_eq!(chunk.remove(index), guide.remove(index)); + } + } + Action::Drain => { + let drained: Vec<_> = chunk.drain().collect(); + let drained_guide: Vec<_> = guide.drain(..).collect(); + assert_eq!(drained, drained_guide); + } + Action::Clear => { + chunk.clear(); + guide.clear(); + } + } + assert_eq!(chunk, guide); + assert!(guide.len() <= capacity); + } + } +} diff --git a/sized-chunks/src/tests/sparse_chunk.rs b/sized-chunks/src/tests/sparse_chunk.rs new file mode 100644 index 000000000..eb2189981 --- /dev/null +++ b/sized-chunks/src/tests/sparse_chunk.rs @@ -0,0 +1,99 @@ +#![allow(clippy::unit_arg)] + +use std::collections::BTreeMap; +use std::fmt::Debug; +use std::panic::{catch_unwind, AssertUnwindSafe}; + +use proptest::{arbitrary::any, collection::vec, prelude::*, proptest}; +use proptest_derive::Arbitrary; + +use crate::sparse_chunk::SparseChunk; + +#[derive(Arbitrary, Debug)] +enum Construct<A> { + Empty, + Single((usize, A)), + Pair((usize, A, usize, A)), +} + +#[derive(Arbitrary, Debug)] +enum Action<A> { + Insert(usize, A), + Remove(usize), + Pop, +} + +impl<A> Construct<A> +where + A: Arbitrary + Clone + Debug + Eq, + <A as Arbitrary>::Strategy: 'static, +{ + fn make(self) -> SparseChunk<A> { + match self { + Construct::Empty => { + let out = SparseChunk::new(); + assert!(out.is_empty()); + out + } + Construct::Single((index, value)) => { + let index = index % SparseChunk::<A>::capacity(); + let out = SparseChunk::unit(index, value.clone()); + let mut guide = BTreeMap::new(); + guide.insert(index, value); + assert_eq!(out, guide); + out + } + Construct::Pair((left_index, left, right_index, right)) => { + let left_index = left_index % SparseChunk::<A>::capacity(); + let right_index = right_index % SparseChunk::<A>::capacity(); + let out = SparseChunk::pair(left_index, left.clone(), right_index, right.clone()); + let mut guide = BTreeMap::new(); + guide.insert(left_index, left); + guide.insert(right_index, right); + assert_eq!(out, guide); + out + } + } + } +} + +proptest! { + #[test] + fn test_constructors(cons: Construct<u32>) { + cons.make(); + } + + #[test] + fn test_actions(cons: Construct<u32>, actions in vec(any::<Action<u32>>(), 0..super::action_count())) { + let capacity = SparseChunk::<u32>::capacity(); + let mut chunk = cons.make(); + let mut guide: BTreeMap<_, _> = chunk.entries().map(|(i, v)| (i, *v)).collect(); + for action in actions { + match action { + Action::Insert(index, value) => { + if index >= capacity { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.insert(index, value))).is_err()); + } else { + assert_eq!(chunk.insert(index, value), guide.insert(index, value)); + } + } + Action::Remove(index) => { + if index >= capacity { + assert!(catch_unwind(AssertUnwindSafe(|| chunk.remove(index))).is_err()); + } else { + assert_eq!(chunk.remove(index), guide.remove(&index)); + } + } + Action::Pop => { + if let Some(index) = chunk.first_index() { + assert_eq!(chunk.pop(), guide.remove(&index)); + } else { + assert_eq!(chunk.pop(), None); + } + } + } + assert_eq!(chunk, guide); + assert!(guide.len() <= SparseChunk::<u32>::capacity()); + } + } +} diff --git a/sized-chunks/src/types.rs b/sized-chunks/src/types.rs new file mode 100644 index 000000000..ebfff0536 --- /dev/null +++ b/sized-chunks/src/types.rs @@ -0,0 +1,244 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use std::fmt::Debug; +use std::marker::PhantomData; + +use typenum::*; + +// Chunk sizes + +pub trait ChunkLength<A>: Unsigned { + type SizedType; +} + +impl<A> ChunkLength<A> for UTerm { + type SizedType = (); +} + +#[doc(hidden)] +#[allow(dead_code)] +pub struct SizeEven<A, B> { + parent1: B, + parent2: B, + _marker: PhantomData<A>, +} + +#[doc(hidden)] +#[allow(dead_code)] +pub struct SizeOdd<A, B> { + parent1: B, + parent2: B, + data: A, +} + +impl<A, N> ChunkLength<A> for UInt<N, B0> +where + N: ChunkLength<A>, +{ + type SizedType = SizeEven<A, N::SizedType>; +} + +impl<A, N> ChunkLength<A> for UInt<N, B1> +where + N: ChunkLength<A>, +{ + type SizedType = SizeOdd<A, N::SizedType>; +} + +// Bit field sizes + +/// A type level number signifying the number of bits in a bitmap. +/// +/// This trait is implemented for type level numbers from `U1` to `U128`. +/// +/// # Examples +/// +/// ```rust +/// # #[macro_use] extern crate sized_chunks; +/// # extern crate typenum; +/// # use sized_chunks::types::Bits; +/// # use typenum::U10; +/// # fn main() { +/// assert_eq!( +/// std::mem::size_of::<<U10 as Bits>::Store>(), +/// std::mem::size_of::<u16>() +/// ); +/// # } +/// ``` +pub trait Bits: Unsigned { + /// A primitive integer type suitable for storing this many bits. + type Store: Default + Copy + PartialEq + Debug; + + fn get(bits: &Self::Store, index: usize) -> bool; + fn set(bits: &mut Self::Store, index: usize, value: bool) -> bool; + fn len(bits: &Self::Store) -> usize; + fn first_index(bits: &Self::Store) -> Option<usize>; +} + +macro_rules! bits_for { + ($num:ty, $result:ty) => { + impl Bits for $num { + type Store = $result; + + fn get(bits: &$result, index: usize) -> bool { + debug_assert!(index < Self::USIZE); + bits & (1 << index) != 0 + } + + fn set(bits: &mut $result, index: usize, value: bool) -> bool { + debug_assert!(index < Self::USIZE); + let mask = 1 << index; + let prev = *bits & mask; + if value { + *bits |= mask; + } else { + *bits &= !mask; + } + prev != 0 + } + + fn len(bits: &$result) -> usize { + bits.count_ones() as usize + } + + fn first_index(bits: &$result) -> Option<usize> { + if *bits == 0 { + None + } else { + Some(bits.trailing_zeros() as usize) + } + } + } + }; +} + +bits_for!(U1, u8); +bits_for!(U2, u8); +bits_for!(U3, u8); +bits_for!(U4, u8); +bits_for!(U5, u8); +bits_for!(U6, u8); +bits_for!(U7, u8); +bits_for!(U8, u8); +bits_for!(U9, u16); +bits_for!(U10, u16); +bits_for!(U11, u16); +bits_for!(U12, u16); +bits_for!(U13, u16); +bits_for!(U14, u16); +bits_for!(U15, u16); +bits_for!(U16, u16); +bits_for!(U17, u32); +bits_for!(U18, u32); +bits_for!(U19, u32); +bits_for!(U20, u32); +bits_for!(U21, u32); +bits_for!(U22, u32); +bits_for!(U23, u32); +bits_for!(U24, u32); +bits_for!(U25, u32); +bits_for!(U26, u32); +bits_for!(U27, u32); +bits_for!(U28, u32); +bits_for!(U29, u32); +bits_for!(U30, u32); +bits_for!(U31, u32); +bits_for!(U32, u32); +bits_for!(U33, u64); +bits_for!(U34, u64); +bits_for!(U35, u64); +bits_for!(U36, u64); +bits_for!(U37, u64); +bits_for!(U38, u64); +bits_for!(U39, u64); +bits_for!(U40, u64); +bits_for!(U41, u64); +bits_for!(U42, u64); +bits_for!(U43, u64); +bits_for!(U44, u64); +bits_for!(U45, u64); +bits_for!(U46, u64); +bits_for!(U47, u64); +bits_for!(U48, u64); +bits_for!(U49, u64); +bits_for!(U50, u64); +bits_for!(U51, u64); +bits_for!(U52, u64); +bits_for!(U53, u64); +bits_for!(U54, u64); +bits_for!(U55, u64); +bits_for!(U56, u64); +bits_for!(U57, u64); +bits_for!(U58, u64); +bits_for!(U59, u64); +bits_for!(U60, u64); +bits_for!(U61, u64); +bits_for!(U62, u64); +bits_for!(U63, u64); +bits_for!(U64, u64); +bits_for!(U65, u128); +bits_for!(U66, u128); +bits_for!(U67, u128); +bits_for!(U68, u128); +bits_for!(U69, u128); +bits_for!(U70, u128); +bits_for!(U71, u128); +bits_for!(U72, u128); +bits_for!(U73, u128); +bits_for!(U74, u128); +bits_for!(U75, u128); +bits_for!(U76, u128); +bits_for!(U77, u128); +bits_for!(U78, u128); +bits_for!(U79, u128); +bits_for!(U80, u128); +bits_for!(U81, u128); +bits_for!(U82, u128); +bits_for!(U83, u128); +bits_for!(U84, u128); +bits_for!(U85, u128); +bits_for!(U86, u128); +bits_for!(U87, u128); +bits_for!(U88, u128); +bits_for!(U89, u128); +bits_for!(U90, u128); +bits_for!(U91, u128); +bits_for!(U92, u128); +bits_for!(U93, u128); +bits_for!(U94, u128); +bits_for!(U95, u128); +bits_for!(U96, u128); +bits_for!(U97, u128); +bits_for!(U98, u128); +bits_for!(U99, u128); +bits_for!(U100, u128); +bits_for!(U101, u128); +bits_for!(U102, u128); +bits_for!(U103, u128); +bits_for!(U104, u128); +bits_for!(U105, u128); +bits_for!(U106, u128); +bits_for!(U107, u128); +bits_for!(U108, u128); +bits_for!(U109, u128); +bits_for!(U110, u128); +bits_for!(U111, u128); +bits_for!(U112, u128); +bits_for!(U113, u128); +bits_for!(U114, u128); +bits_for!(U115, u128); +bits_for!(U116, u128); +bits_for!(U117, u128); +bits_for!(U118, u128); +bits_for!(U119, u128); +bits_for!(U120, u128); +bits_for!(U121, u128); +bits_for!(U122, u128); +bits_for!(U123, u128); +bits_for!(U124, u128); +bits_for!(U125, u128); +bits_for!(U126, u128); +bits_for!(U127, u128); +bits_for!(U128, u128); diff --git a/smallvec/.cargo-checksum.json b/smallvec/.cargo-checksum.json new file mode 100644 index 000000000..1eb9661ca --- /dev/null +++ b/smallvec/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"} \ No newline at end of file diff --git a/smallvec/Cargo.toml b/smallvec/Cargo.toml new file mode 100644 index 000000000..5bcd9063f --- /dev/null +++ b/smallvec/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "smallvec" +version = "0.6.9" +authors = ["Simon Sapin <simon.sapin@exyr.org>"] +description = "'Small vector' optimization: store up to a small number of items on the stack" +documentation = "https://doc.servo.org/smallvec/" +readme = "README.md" +keywords = ["small", "vec", "vector", "stack", "no_std"] +categories = ["data-structures"] +license = "MIT/Apache-2.0" +repository = "https://github.com/servo/rust-smallvec" + +[lib] +name = "smallvec" +path = "lib.rs" +[dependencies.serde] +version = "1" +optional = true +[dev-dependencies.bincode] +version = "1.0.1" + +[features] +default = ["std"] +may_dangle = [] +specialization = [] +std = [] +union = [] diff --git a/smallvec/LICENSE-APACHE b/smallvec/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/smallvec/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/smallvec/LICENSE-MIT b/smallvec/LICENSE-MIT new file mode 100644 index 000000000..9729c1284 --- /dev/null +++ b/smallvec/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 The Servo Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/smallvec/README.md b/smallvec/README.md new file mode 100644 index 000000000..fda7fd4d2 --- /dev/null +++ b/smallvec/README.md @@ -0,0 +1,8 @@ +rust-smallvec +============= + +[Documentation](https://docs.rs/smallvec/) + +[Release notes](https://github.com/servo/rust-smallvec/releases) + +"Small vector" optimization for Rust: store up to a small number of items on the stack diff --git a/smallvec/benches/bench.rs b/smallvec/benches/bench.rs new file mode 100644 index 000000000..36cb1333f --- /dev/null +++ b/smallvec/benches/bench.rs @@ -0,0 +1,295 @@ +#![feature(test)] + +#[macro_use] +extern crate smallvec; +extern crate test; + +use self::test::Bencher; +use smallvec::{ExtendFromSlice, SmallVec}; + +const VEC_SIZE: usize = 16; +const SPILLED_SIZE: usize = 100; + +trait Vector<T>: for<'a> From<&'a [T]> + Extend<T> + ExtendFromSlice<T> { + fn new() -> Self; + fn push(&mut self, val: T); + fn pop(&mut self) -> Option<T>; + fn remove(&mut self, p: usize) -> T; + fn insert(&mut self, n: usize, val: T); + fn from_elem(val: T, n: usize) -> Self; + fn from_elems(val: &[T]) -> Self; +} + +impl<T: Copy> Vector<T> for Vec<T> { + fn new() -> Self { + Self::with_capacity(VEC_SIZE) + } + + fn push(&mut self, val: T) { + self.push(val) + } + + fn pop(&mut self) -> Option<T> { + self.pop() + } + + fn remove(&mut self, p: usize) -> T { + self.remove(p) + } + + fn insert(&mut self, n: usize, val: T) { + self.insert(n, val) + } + + fn from_elem(val: T, n: usize) -> Self { + vec![val; n] + } + + fn from_elems(val: &[T]) -> Self { + val.to_owned() + } +} + +impl<T: Copy> Vector<T> for SmallVec<[T; VEC_SIZE]> { + fn new() -> Self { + Self::new() + } + + fn push(&mut self, val: T) { + self.push(val) + } + + fn pop(&mut self) -> Option<T> { + self.pop() + } + + fn remove(&mut self, p: usize) -> T { + self.remove(p) + } + + fn insert(&mut self, n: usize, val: T) { + self.insert(n, val) + } + + fn from_elem(val: T, n: usize) -> Self { + smallvec![val; n] + } + + fn from_elems(val: &[T]) -> Self { + SmallVec::from_slice(val) + } +} + +macro_rules! make_benches { + ($typ:ty { $($b_name:ident => $g_name:ident($($args:expr),*),)* }) => { + $( + #[bench] + fn $b_name(b: &mut Bencher) { + $g_name::<$typ>($($args,)* b) + } + )* + } +} + +make_benches! { + SmallVec<[u64; VEC_SIZE]> { + bench_push => gen_push(SPILLED_SIZE as _), + bench_push_small => gen_push(VEC_SIZE as _), + bench_insert => gen_insert(SPILLED_SIZE as _), + bench_insert_small => gen_insert(VEC_SIZE as _), + bench_remove => gen_remove(SPILLED_SIZE as _), + bench_remove_small => gen_remove(VEC_SIZE as _), + bench_extend => gen_extend(SPILLED_SIZE as _), + bench_extend_small => gen_extend(VEC_SIZE as _), + bench_from_iter => gen_from_iter(SPILLED_SIZE as _), + bench_from_iter_small => gen_from_iter(VEC_SIZE as _), + bench_from_slice => gen_from_slice(SPILLED_SIZE as _), + bench_from_slice_small => gen_from_slice(VEC_SIZE as _), + bench_extend_from_slice => gen_extend_from_slice(SPILLED_SIZE as _), + bench_extend_from_slice_small => gen_extend_from_slice(VEC_SIZE as _), + bench_macro_from_elem => gen_from_elem(SPILLED_SIZE as _), + bench_macro_from_elem_small => gen_from_elem(VEC_SIZE as _), + bench_pushpop => gen_pushpop(), + } +} + +make_benches! { + Vec<u64> { + bench_push_vec => gen_push(SPILLED_SIZE as _), + bench_push_vec_small => gen_push(VEC_SIZE as _), + bench_insert_vec => gen_insert(SPILLED_SIZE as _), + bench_insert_vec_small => gen_insert(VEC_SIZE as _), + bench_remove_vec => gen_remove(SPILLED_SIZE as _), + bench_remove_vec_small => gen_remove(VEC_SIZE as _), + bench_extend_vec => gen_extend(SPILLED_SIZE as _), + bench_extend_vec_small => gen_extend(VEC_SIZE as _), + bench_from_iter_vec => gen_from_iter(SPILLED_SIZE as _), + bench_from_iter_vec_small => gen_from_iter(VEC_SIZE as _), + bench_from_slice_vec => gen_from_slice(SPILLED_SIZE as _), + bench_from_slice_vec_small => gen_from_slice(VEC_SIZE as _), + bench_extend_from_slice_vec => gen_extend_from_slice(SPILLED_SIZE as _), + bench_extend_from_slice_vec_small => gen_extend_from_slice(VEC_SIZE as _), + bench_macro_from_elem_vec => gen_from_elem(SPILLED_SIZE as _), + bench_macro_from_elem_vec_small => gen_from_elem(VEC_SIZE as _), + bench_pushpop_vec => gen_pushpop(), + } +} + +fn gen_push<V: Vector<u64>>(n: u64, b: &mut Bencher) { + #[inline(never)] + fn push_noinline<V: Vector<u64>>(vec: &mut V, x: u64) { + vec.push(x); + } + + b.iter(|| { + let mut vec = V::new(); + for x in 0..n { + push_noinline(&mut vec, x); + } + vec + }); +} + +fn gen_insert<V: Vector<u64>>(n: u64, b: &mut Bencher) { + #[inline(never)] + fn insert_noinline<V: Vector<u64>>(vec: &mut V, p: usize, x: u64) { + vec.insert(p, x) + } + + b.iter(|| { + let mut vec = V::new(); + // Add one element, with each iteration we insert one before the end. + // This means that we benchmark the insertion operation and not the + // time it takes to `ptr::copy` the data. + vec.push(0); + for x in 0..n { + insert_noinline(&mut vec, x as _, x); + } + vec + }); +} + +fn gen_remove<V: Vector<u64>>(n: usize, b: &mut Bencher) { + #[inline(never)] + fn remove_noinline<V: Vector<u64>>(vec: &mut V, p: usize) -> u64 { + vec.remove(p) + } + + b.iter(|| { + let mut vec = V::from_elem(0, n as _); + + for x in (0..n - 1).rev() { + remove_noinline(&mut vec, x); + } + }); +} + +fn gen_extend<V: Vector<u64>>(n: u64, b: &mut Bencher) { + b.iter(|| { + let mut vec = V::new(); + vec.extend(0..n); + vec + }); +} + +fn gen_from_iter<V: Vector<u64>>(n: u64, b: &mut Bencher) { + let v: Vec<u64> = (0..n).collect(); + b.iter(|| { + let vec = V::from(&v); + vec + }); +} + +fn gen_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) { + let v: Vec<u64> = (0..n).collect(); + b.iter(|| { + let vec = V::from_elems(&v); + vec + }); +} + +fn gen_extend_from_slice<V: Vector<u64>>(n: u64, b: &mut Bencher) { + let v: Vec<u64> = (0..n).collect(); + b.iter(|| { + let mut vec = V::new(); + vec.extend_from_slice(&v); + vec + }); +} + +fn gen_pushpop<V: Vector<u64>>(b: &mut Bencher) { + #[inline(never)] + fn pushpop_noinline<V: Vector<u64>>(vec: &mut V, x: u64) -> Option<u64> { + vec.push(x); + vec.pop() + } + + b.iter(|| { + let mut vec = V::new(); + for x in 0..SPILLED_SIZE as _ { + pushpop_noinline(&mut vec, x); + } + vec + }); +} + +fn gen_from_elem<V: Vector<u64>>(n: usize, b: &mut Bencher) { + b.iter(|| { + let vec = V::from_elem(42, n); + vec + }); +} + +#[bench] +fn bench_insert_many(b: &mut Bencher) { + #[inline(never)] + fn insert_many_noinline<I: IntoIterator<Item = u64>>( + vec: &mut SmallVec<[u64; VEC_SIZE]>, + index: usize, + iterable: I, + ) { + vec.insert_many(index, iterable) + } + + b.iter(|| { + let mut vec = SmallVec::<[u64; VEC_SIZE]>::new(); + insert_many_noinline(&mut vec, 0, 0..SPILLED_SIZE as _); + insert_many_noinline(&mut vec, 0, 0..SPILLED_SIZE as _); + vec + }); +} + +#[bench] +fn bench_insert_from_slice(b: &mut Bencher) { + let v: Vec<u64> = (0..SPILLED_SIZE as _).collect(); + b.iter(|| { + let mut vec = SmallVec::<[u64; VEC_SIZE]>::new(); + vec.insert_from_slice(0, &v); + vec.insert_from_slice(0, &v); + vec + }); +} + +#[bench] +fn bench_macro_from_list(b: &mut Bencher) { + b.iter(|| { + let vec: SmallVec<[u64; 16]> = smallvec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, + 0x80000, 0x100000, + ]; + vec + }); +} + +#[bench] +fn bench_macro_from_list_vec(b: &mut Bencher) { + b.iter(|| { + let vec: Vec<u64> = vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, + 0x80000, 0x100000, + ]; + vec + }); +} diff --git a/smallvec/lib.rs b/smallvec/lib.rs new file mode 100644 index 000000000..4b869e070 --- /dev/null +++ b/smallvec/lib.rs @@ -0,0 +1,2314 @@ +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Small vectors in various sizes. These store a certain number of elements inline, and fall back +//! to the heap for larger allocations. This can be a useful optimization for improving cache +//! locality and reducing allocator traffic for workloads that fit within the inline buffer. +//! +//! ## no_std support +//! +//! By default, `smallvec` depends on `libstd`. However, it can be configured to use the unstable +//! `liballoc` API instead, for use on platforms that have `liballoc` but not `libstd`. This +//! configuration is currently unstable and is not guaranteed to work on all versions of Rust. +//! +//! To depend on `smallvec` without `libstd`, use `default-features = false` in the `smallvec` +//! section of Cargo.toml to disable its `"std"` feature. +//! +//! ## `union` feature +//! +//! When the `union` feature is enabled `smallvec` will track its state (inline or spilled) +//! without the use of an enum tag, reducing the size of the `smallvec` by one machine word. +//! This means that there is potentially no space overhead compared to `Vec`. +//! Note that `smallvec` can still be larger than `Vec` if the inline buffer is larger than two +//! machine words. +//! +//! To use this feature add `features = ["union"]` in the `smallvec` section of Cargo.toml. +//! Note that this feature requires a nightly compiler (for now). + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc))] +#![cfg_attr(feature = "union", feature(untagged_unions))] +#![cfg_attr(feature = "specialization", feature(specialization))] +#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] +#![deny(missing_docs)] + + +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +#[cfg(feature = "serde")] +extern crate serde; + +#[cfg(not(feature = "std"))] +mod std { + pub use core::*; +} + +use std::borrow::{Borrow, BorrowMut}; +use std::cmp; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::iter::{IntoIterator, FromIterator, repeat}; +use std::mem; +use std::mem::ManuallyDrop; +use std::ops; +use std::ptr; +use std::slice; +#[cfg(feature = "std")] +use std::io; +#[cfg(feature = "serde")] +use serde::ser::{Serialize, Serializer, SerializeSeq}; +#[cfg(feature = "serde")] +use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; +#[cfg(feature = "serde")] +use std::marker::PhantomData; + +/// Creates a [`SmallVec`] containing the arguments. +/// +/// `smallvec!` allows `SmallVec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a [`SmallVec`] containing a given list of elements: +/// +/// ``` +/// # #[macro_use] extern crate smallvec; +/// # use smallvec::SmallVec; +/// # fn main() { +/// let v: SmallVec<[_; 128]> = smallvec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// # } +/// ``` +/// +/// - Create a [`SmallVec`] from a given element and size: +/// +/// ``` +/// # #[macro_use] extern crate smallvec; +/// # use smallvec::SmallVec; +/// # fn main() { +/// let v: SmallVec<[_; 0x8000]> = smallvec![1; 3]; +/// assert_eq!(v, SmallVec::from_buf([1, 1, 1])); +/// # } +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement [`Clone`] and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone` to duplicate an expression, so one should be careful +/// using this with types having a nonstandard `Clone` implementation. For +/// example, `smallvec![Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. + +#[macro_export] +macro_rules! smallvec { + // count helper: transform any expression into 1 + (@one $x:expr) => (1usize); + ($elem:expr; $n:expr) => ({ + $crate::SmallVec::from_elem($elem, $n) + }); + ($($x:expr),*$(,)*) => ({ + let count = 0usize $(+ smallvec!(@one $x))*; + let mut vec = $crate::SmallVec::new(); + if count <= vec.inline_size() { + $(vec.push($x);)* + vec + } else { + $crate::SmallVec::from_vec(vec![$($x,)*]) + } + }); +} + +/// Hint to the optimizer that any code path which calls this function is +/// statically unreachable and can be removed. +/// +/// Equivalent to `std::hint::unreachable_unchecked` but works in older versions of Rust. +#[inline] +pub unsafe fn unreachable() -> ! { + enum Void {} + let x: &Void = mem::transmute(1usize); + match *x {} +} + +/// `panic!()` in debug builds, optimization hint in release. +#[cfg(not(feature = "union"))] +macro_rules! debug_unreachable { + () => { debug_unreachable!("entered unreachable code") }; + ($e:expr) => { + if cfg!(not(debug_assertions)) { + unreachable(); + } else { + panic!($e); + } + } +} + +/// Common operations implemented by both `Vec` and `SmallVec`. +/// +/// This can be used to write generic code that works with both `Vec` and `SmallVec`. +/// +/// ## Example +/// +/// ```rust +/// use smallvec::{VecLike, SmallVec}; +/// +/// fn initialize<V: VecLike<u8>>(v: &mut V) { +/// for i in 0..5 { +/// v.push(i); +/// } +/// } +/// +/// let mut vec = Vec::new(); +/// initialize(&mut vec); +/// +/// let mut small_vec = SmallVec::<[u8; 8]>::new(); +/// initialize(&mut small_vec); +/// ``` +#[deprecated(note = "Use `Extend` and `Deref<[T]>` instead")] +pub trait VecLike<T>: + ops::Index<usize, Output=T> + + ops::IndexMut<usize> + + ops::Index<ops::Range<usize>, Output=[T]> + + ops::IndexMut<ops::Range<usize>> + + ops::Index<ops::RangeFrom<usize>, Output=[T]> + + ops::IndexMut<ops::RangeFrom<usize>> + + ops::Index<ops::RangeTo<usize>, Output=[T]> + + ops::IndexMut<ops::RangeTo<usize>> + + ops::Index<ops::RangeFull, Output=[T]> + + ops::IndexMut<ops::RangeFull> + + ops::DerefMut<Target = [T]> + + Extend<T> { + + /// Append an element to the vector. + fn push(&mut self, value: T); +} + +#[allow(deprecated)] +impl<T> VecLike<T> for Vec<T> { + #[inline] + fn push(&mut self, value: T) { + Vec::push(self, value); + } +} + +/// Trait to be implemented by a collection that can be extended from a slice +/// +/// ## Example +/// +/// ```rust +/// use smallvec::{ExtendFromSlice, SmallVec}; +/// +/// fn initialize<V: ExtendFromSlice<u8>>(v: &mut V) { +/// v.extend_from_slice(b"Test!"); +/// } +/// +/// let mut vec = Vec::new(); +/// initialize(&mut vec); +/// assert_eq!(&vec, b"Test!"); +/// +/// let mut small_vec = SmallVec::<[u8; 8]>::new(); +/// initialize(&mut small_vec); +/// assert_eq!(&small_vec as &[_], b"Test!"); +/// ``` +pub trait ExtendFromSlice<T> { + /// Extends a collection from a slice of its element type + fn extend_from_slice(&mut self, other: &[T]); +} + +impl<T: Clone> ExtendFromSlice<T> for Vec<T> { + fn extend_from_slice(&mut self, other: &[T]) { + Vec::extend_from_slice(self, other) + } +} + +unsafe fn deallocate<T>(ptr: *mut T, capacity: usize) { + let _vec: Vec<T> = Vec::from_raw_parts(ptr, 0, capacity); + // Let it drop. +} + +/// An iterator that removes the items from a `SmallVec` and yields them by value. +/// +/// Returned from [`SmallVec::drain`][1]. +/// +/// [1]: struct.SmallVec.html#method.drain +pub struct Drain<'a, T: 'a> { + iter: slice::IterMut<'a,T>, +} + +impl<'a, T: 'a> Iterator for Drain<'a,T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option<T> { + self.iter.next().map(|reference| unsafe { ptr::read(reference) }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<T> { + self.iter.next_back().map(|reference| unsafe { ptr::read(reference) }) + } +} + +impl<'a, T> ExactSizeIterator for Drain<'a, T> { } + +impl<'a, T: 'a> Drop for Drain<'a,T> { + fn drop(&mut self) { + // Destroy the remaining elements. + for _ in self.by_ref() {} + } +} + +#[cfg(feature = "union")] +union SmallVecData<A: Array> { + inline: ManuallyDrop<A>, + heap: (*mut A::Item, usize), +} + +#[cfg(feature = "union")] +impl<A: Array> SmallVecData<A> { + #[inline] + unsafe fn inline(&self) -> &A { + &self.inline + } + #[inline] + unsafe fn inline_mut(&mut self) -> &mut A { + &mut self.inline + } + #[inline] + fn from_inline(inline: A) -> SmallVecData<A> { + SmallVecData { inline: ManuallyDrop::new(inline) } + } + #[inline] + unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) } + #[inline] + unsafe fn heap(&self) -> (*mut A::Item, usize) { + self.heap + } + #[inline] + unsafe fn heap_mut(&mut self) -> &mut (*mut A::Item, usize) { + &mut self.heap + } + #[inline] + fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData<A> { + SmallVecData { heap: (ptr, len) } + } +} + +#[cfg(not(feature = "union"))] +enum SmallVecData<A: Array> { + Inline(ManuallyDrop<A>), + Heap((*mut A::Item, usize)), +} + +#[cfg(not(feature = "union"))] +impl<A: Array> SmallVecData<A> { + #[inline] + unsafe fn inline(&self) -> &A { + match *self { + SmallVecData::Inline(ref a) => a, + _ => debug_unreachable!(), + } + } + #[inline] + unsafe fn inline_mut(&mut self) -> &mut A { + match *self { + SmallVecData::Inline(ref mut a) => a, + _ => debug_unreachable!(), + } + } + #[inline] + fn from_inline(inline: A) -> SmallVecData<A> { + SmallVecData::Inline(ManuallyDrop::new(inline)) + } + #[inline] + unsafe fn into_inline(self) -> A { + match self { + SmallVecData::Inline(a) => ManuallyDrop::into_inner(a), + _ => debug_unreachable!(), + } + } + #[inline] + unsafe fn heap(&self) -> (*mut A::Item, usize) { + match *self { + SmallVecData::Heap(data) => data, + _ => debug_unreachable!(), + } + } + #[inline] + unsafe fn heap_mut(&mut self) -> &mut (*mut A::Item, usize) { + match *self { + SmallVecData::Heap(ref mut data) => data, + _ => debug_unreachable!(), + } + } + #[inline] + fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData<A> { + SmallVecData::Heap((ptr, len)) + } +} + +unsafe impl<A: Array + Send> Send for SmallVecData<A> {} +unsafe impl<A: Array + Sync> Sync for SmallVecData<A> {} + +/// A `Vec`-like container that can store a small number of elements inline. +/// +/// `SmallVec` acts like a vector, but can store a limited amount of data inline within the +/// `Smallvec` struct rather than in a separate allocation. If the data exceeds this limit, the +/// `SmallVec` will "spill" its data onto the heap, allocating a new buffer to hold it. +/// +/// The amount of data that a `SmallVec` can store inline depends on its backing store. The backing +/// store can be any type that implements the `Array` trait; usually it is a small fixed-sized +/// array. For example a `SmallVec<[u64; 8]>` can hold up to eight 64-bit integers inline. +/// +/// ## Example +/// +/// ```rust +/// use smallvec::SmallVec; +/// let mut v = SmallVec::<[u8; 4]>::new(); // initialize an empty vector +/// +/// // The vector can hold up to 4 items without spilling onto the heap. +/// v.extend(0..4); +/// assert_eq!(v.len(), 4); +/// assert!(!v.spilled()); +/// +/// // Pushing another element will force the buffer to spill: +/// v.push(4); +/// assert_eq!(v.len(), 5); +/// assert!(v.spilled()); +/// ``` +pub struct SmallVec<A: Array> { + // The capacity field is used to determine which of the storage variants is active: + // If capacity <= A::size() then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use). + // If capacity > A::size() then the heap variant is used and capacity holds the size of the memory allocation. + capacity: usize, + data: SmallVecData<A>, +} + +impl<A: Array> SmallVec<A> { + /// Construct an empty vector + #[inline] + pub fn new() -> SmallVec<A> { + unsafe { + SmallVec { + capacity: 0, + data: SmallVecData::from_inline(mem::uninitialized()), + } + } + } + + /// Construct an empty vector with enough capacity pre-allocated to store at least `n` + /// elements. + /// + /// Will create a heap allocation only if `n` is larger than the inline capacity. + /// + /// ``` + /// # use smallvec::SmallVec; + /// + /// let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(100); + /// + /// assert!(v.is_empty()); + /// assert!(v.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity(n: usize) -> Self { + let mut v = SmallVec::new(); + v.reserve_exact(n); + v + } + + /// Construct a new `SmallVec` from a `Vec<A::Item>`. + /// + /// Elements will be copied to the inline buffer if vec.capacity() <= A::size(). + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let vec = vec![1, 2, 3, 4, 5]; + /// let small_vec: SmallVec<[_; 3]> = SmallVec::from_vec(vec); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> { + if vec.capacity() <= A::size() { + unsafe { + let mut data = SmallVecData::<A>::from_inline(mem::uninitialized()); + let len = vec.len(); + vec.set_len(0); + ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len); + + SmallVec { + capacity: len, + data, + } + } + } else { + let (ptr, cap, len) = (vec.as_mut_ptr(), vec.capacity(), vec.len()); + mem::forget(vec); + + SmallVec { + capacity: cap, + data: SmallVecData::from_heap(ptr, len), + } + } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5]; + /// let small_vec: SmallVec<_> = SmallVec::from_buf(buf); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_buf(buf: A) -> SmallVec<A> { + SmallVec { + capacity: A::size(), + data: SmallVecData::from_inline(buf), + } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. Also sets the length, which must be less or + /// equal to the size of `buf`. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; + /// let small_vec: SmallVec<_> = SmallVec::from_buf_and_len(buf, 5); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec<A> { + assert!(len <= A::size()); + unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. Also sets the length. The user is responsible + /// for ensuring that `len <= A::size()`. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; + /// let small_vec: SmallVec<_> = unsafe { + /// SmallVec::from_buf_and_len_unchecked(buf, 5) + /// }; + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> { + SmallVec { + capacity: len, + data: SmallVecData::from_inline(buf), + } + } + + + /// Sets the length of a vector. + /// + /// This will explicitly set the size of the vector, without actually + /// modifying its buffers, so it is up to the caller to ensure that the + /// vector is actually the specified size. + pub unsafe fn set_len(&mut self, new_len: usize) { + let (_, len_ptr, _) = self.triple_mut(); + *len_ptr = new_len; + } + + /// The maximum number of elements this vector can hold inline + #[inline] + pub fn inline_size(&self) -> usize { + A::size() + } + + /// The number of elements stored in the vector + #[inline] + pub fn len(&self) -> usize { + self.triple().1 + } + + /// Returns `true` if the vector is empty + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The number of items the vector can hold without reallocating + #[inline] + pub fn capacity(&self) -> usize { + self.triple().2 + } + + /// Returns a tuple with (data ptr, len, capacity) + /// Useful to get all SmallVec properties with a single check of the current storage variant. + #[inline] + fn triple(&self) -> (*const A::Item, usize, usize) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + (ptr, len, self.capacity) + } else { + (self.data.inline().ptr(), self.capacity, A::size()) + } + } + } + + /// Returns a tuple with (data ptr, len ptr, capacity) + #[inline] + fn triple_mut(&mut self) -> (*mut A::Item, &mut usize, usize) { + unsafe { + if self.spilled() { + let &mut (ptr, ref mut len_ptr) = self.data.heap_mut(); + (ptr, len_ptr, self.capacity) + } else { + (self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size()) + } + } + } + + /// Returns `true` if the data has spilled into a separate heap-allocated buffer. + #[inline] + pub fn spilled(&self) -> bool { + self.capacity > A::size() + } + + /// Empty the vector and return an iterator over its former contents. + pub fn drain(&mut self) -> Drain<A::Item> { + unsafe { + let ptr = self.as_mut_ptr(); + + let current_len = self.len(); + self.set_len(0); + + let slice = slice::from_raw_parts_mut(ptr, current_len); + + Drain { + iter: slice.iter_mut(), + } + } + } + + /// Append an item to the vector. + #[inline] + pub fn push(&mut self, value: A::Item) { + unsafe { + let (_, &mut len, cap) = self.triple_mut(); + if len == cap { + self.reserve(1); + } + let (ptr, len_ptr, _) = self.triple_mut(); + *len_ptr = len + 1; + ptr::write(ptr.offset(len as isize), value); + } + } + + /// Remove an item from the end of the vector and return it, or None if empty. + #[inline] + pub fn pop(&mut self) -> Option<A::Item> { + unsafe { + let (ptr, len_ptr, _) = self.triple_mut(); + if *len_ptr == 0 { + return None; + } + let last_index = *len_ptr - 1; + *len_ptr = last_index; + Some(ptr::read(ptr.offset(last_index as isize))) + } + } + + /// Re-allocate to set the capacity to `max(new_cap, inline_size())`. + /// + /// Panics if `new_cap` is less than the vector's length. + pub fn grow(&mut self, new_cap: usize) { + unsafe { + let (ptr, &mut len, cap) = self.triple_mut(); + let unspilled = !self.spilled(); + assert!(new_cap >= len); + if new_cap <= self.inline_size() { + if unspilled { + return; + } + self.data = SmallVecData::from_inline(mem::uninitialized()); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); + } else if new_cap != cap { + let mut vec = Vec::with_capacity(new_cap); + let new_alloc = vec.as_mut_ptr(); + mem::forget(vec); + ptr::copy_nonoverlapping(ptr, new_alloc, len); + self.data = SmallVecData::from_heap(new_alloc, len); + self.capacity = new_cap; + if unspilled { + return; + } + } + deallocate(ptr, cap); + } + } + + /// Reserve capacity for `additional` more elements to be inserted. + /// + /// May reserve more space to avoid frequent reallocations. + /// + /// If the new capacity would overflow `usize` then it will be set to `usize::max_value()` + /// instead. (This means that inserting `additional` new elements is not guaranteed to be + /// possible after calling this function.) + #[inline] + pub fn reserve(&mut self, additional: usize) { + // prefer triple_mut() even if triple() would work + // so that the optimizer removes duplicated calls to it + // from callers like insert() + let (_, &mut len, cap) = self.triple_mut(); + if cap - len < additional { + let new_cap = len.checked_add(additional). + and_then(usize::checked_next_power_of_two). + unwrap_or(usize::max_value()); + self.grow(new_cap); + } + } + + /// Reserve the minimum capacity for `additional` more elements to be inserted. + /// + /// Panics if the new capacity overflows `usize`. + pub fn reserve_exact(&mut self, additional: usize) { + let (_, &mut len, cap) = self.triple_mut(); + if cap - len < additional { + match len.checked_add(additional) { + Some(cap) => self.grow(cap), + None => panic!("reserve_exact overflow"), + } + } + } + + /// Shrink the capacity of the vector as much as possible. + /// + /// When possible, this will move data from an external heap buffer to the vector's inline + /// storage. + pub fn shrink_to_fit(&mut self) { + if !self.spilled() { + return; + } + let len = self.len(); + if self.inline_size() >= len { + unsafe { + let (ptr, len) = self.data.heap(); + self.data = SmallVecData::from_inline(mem::uninitialized()); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); + deallocate(ptr, self.capacity); + self.capacity = len; + } + } else if self.capacity() > len { + self.grow(len); + } + } + + /// Shorten the vector, keeping the first `len` elements and dropping the rest. + /// + /// If `len` is greater than or equal to the vector's current length, this has no + /// effect. + /// + /// This does not re-allocate. If you want the vector's capacity to shrink, call + /// `shrink_to_fit` after truncating. + pub fn truncate(&mut self, len: usize) { + unsafe { + let (ptr, len_ptr, _) = self.triple_mut(); + while len < *len_ptr { + let last_index = *len_ptr - 1; + *len_ptr = last_index; + ptr::drop_in_place(ptr.offset(last_index as isize)); + } + } + } + + /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. + pub fn as_slice(&self) -> &[A::Item] { + self + } + + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. + pub fn as_mut_slice(&mut self) -> &mut [A::Item] { + self + } + + /// Remove the element at position `index`, replacing it with the last element. + /// + /// This does not preserve ordering, but is O(1). + /// + /// Panics if `index` is out of bounds. + #[inline] + pub fn swap_remove(&mut self, index: usize) -> A::Item { + let len = self.len(); + self.swap(len - 1, index); + self.pop().unwrap_or_else(|| unsafe { unreachable() }) + } + + /// Remove all elements from the vector. + #[inline] + pub fn clear(&mut self) { + self.truncate(0); + } + + /// Remove and return the element at position `index`, shifting all elements after it to the + /// left. + /// + /// Panics if `index` is out of bounds. + pub fn remove(&mut self, index: usize) -> A::Item { + unsafe { + let (mut ptr, len_ptr, _) = self.triple_mut(); + let len = *len_ptr; + assert!(index < len); + *len_ptr = len - 1; + ptr = ptr.offset(index as isize); + let item = ptr::read(ptr); + ptr::copy(ptr.offset(1), ptr, len - index - 1); + item + } + } + + /// Insert an element at position `index`, shifting all elements after it to the right. + /// + /// Panics if `index` is out of bounds. + pub fn insert(&mut self, index: usize, element: A::Item) { + self.reserve(1); + + unsafe { + let (mut ptr, len_ptr, _) = self.triple_mut(); + let len = *len_ptr; + assert!(index <= len); + *len_ptr = len + 1; + ptr = ptr.offset(index as isize); + ptr::copy(ptr, ptr.offset(1), len - index); + ptr::write(ptr, element); + } + } + + /// Insert multiple elements at position `index`, shifting all following elements toward the + /// back. + pub fn insert_many<I: IntoIterator<Item=A::Item>>(&mut self, index: usize, iterable: I) { + let iter = iterable.into_iter(); + if index == self.len() { + return self.extend(iter); + } + + let (lower_size_bound, _) = iter.size_hint(); + assert!(lower_size_bound <= std::isize::MAX as usize); // Ensure offset is indexable + assert!(index + lower_size_bound >= index); // Protect against overflow + self.reserve(lower_size_bound); + + unsafe { + let old_len = self.len(); + assert!(index <= old_len); + let mut ptr = self.as_mut_ptr().offset(index as isize); + + // Move the trailing elements. + ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index); + + // In case the iterator panics, don't double-drop the items we just copied above. + self.set_len(index); + + let mut num_added = 0; + for element in iter { + let mut cur = ptr.offset(num_added as isize); + if num_added >= lower_size_bound { + // Iterator provided more elements than the hint. Move trailing items again. + self.reserve(1); + ptr = self.as_mut_ptr().offset(index as isize); + cur = ptr.offset(num_added as isize); + ptr::copy(cur, cur.offset(1), old_len - index); + } + ptr::write(cur, element); + num_added += 1; + } + if num_added < lower_size_bound { + // Iterator provided fewer elements than the hint + ptr::copy(ptr.offset(lower_size_bound as isize), ptr.offset(num_added as isize), old_len - index); + } + + self.set_len(old_len + num_added); + } + } + + /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto + /// the heap. + pub fn into_vec(self) -> Vec<A::Item> { + if self.spilled() { + unsafe { + let (ptr, len) = self.data.heap(); + let v = Vec::from_raw_parts(ptr, len, self.capacity); + mem::forget(self); + v + } + } else { + self.into_iter().collect() + } + } + + /// Convert the SmallVec into an `A` if possible. Otherwise return `Err(Self)`. + /// + /// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements), + /// or if the SmallVec is too long (and all the elements were spilled to the heap). + pub fn into_inner(self) -> Result<A, Self> { + if self.spilled() || self.len() != A::size() { + Err(self) + } else { + unsafe { + let data = ptr::read(&self.data); + mem::forget(self); + Ok(data.into_inline()) + } + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// This method operates in place and preserves the order of the retained + /// elements. + pub fn retain<F: FnMut(&mut A::Item) -> bool>(&mut self, mut f: F) { + let mut del = 0; + let len = self.len(); + for i in 0..len { + if !f(&mut self[i]) { + del += 1; + } else if del > 0 { + self.swap(i - del, i); + } + } + self.truncate(len - del); + } + + /// Removes consecutive duplicate elements. + pub fn dedup(&mut self) where A::Item: PartialEq<A::Item> { + self.dedup_by(|a, b| a == b); + } + + /// Removes consecutive duplicate elements using the given equality relation. + pub fn dedup_by<F>(&mut self, mut same_bucket: F) + where F: FnMut(&mut A::Item, &mut A::Item) -> bool + { + // See the implementation of Vec::dedup_by in the + // standard library for an explanation of this algorithm. + let len = self.len(); + if len <= 1 { + return; + } + + let ptr = self.as_mut_ptr(); + let mut w: usize = 1; + + unsafe { + for r in 1..len { + let p_r = ptr.offset(r as isize); + let p_wm1 = ptr.offset((w - 1) as isize); + if !same_bucket(&mut *p_r, &mut *p_wm1) { + if r != w { + let p_w = p_wm1.offset(1); + mem::swap(&mut *p_r, &mut *p_w); + } + w += 1; + } + } + } + + self.truncate(w); + } + + /// Removes consecutive elements that map to the same key. + pub fn dedup_by_key<F, K>(&mut self, mut key: F) + where F: FnMut(&mut A::Item) -> K, + K: PartialEq<K> + { + self.dedup_by(|a, b| key(a) == key(b)); + } + + /// Creates a `SmallVec` directly from the raw components of another + /// `SmallVec`. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` needs to have been previously allocated via `SmallVec` for its + /// spilled storage (at least, it's highly likely to be incorrect if it + /// wasn't). + /// * `ptr`'s `A::Item` type needs to be the same size and alignment that + /// it was allocated with + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated + /// with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. + /// + /// Additionally, `capacity` must be greater than the amount of inline + /// storage `A` has; that is, the new `SmallVec` must need to spill over + /// into heap allocated storage. This condition is asserted against. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `SmallVec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate smallvec; + /// # use smallvec::SmallVec; + /// use std::mem; + /// use std::ptr; + /// + /// fn main() { + /// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3]; + /// + /// // Pull out the important parts of `v`. + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// let spilled = v.spilled(); + /// + /// unsafe { + /// // Forget all about `v`. The heap allocation that stored the + /// // three values won't be deallocated. + /// mem::forget(v); + /// + /// // Overwrite memory with [4, 5, 6]. + /// // + /// // This is only safe if `spilled` is true! Otherwise, we are + /// // writing into the old `SmallVec`'s inline storage on the + /// // stack. + /// assert!(spilled); + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); + /// } + /// + /// // Put everything back together into a SmallVec with a different + /// // amount of inline storage, but which is still less than `cap`. + /// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap); + /// assert_eq!(&*rebuilt, &[4, 5, 6]); + /// } + /// } + pub unsafe fn from_raw_parts( + ptr: *mut A::Item, + length: usize, + capacity: usize, + ) -> SmallVec<A> { + assert!(capacity > A::size()); + SmallVec { + capacity, + data: SmallVecData::from_heap(ptr, length), + } + } +} + +impl<A: Array> SmallVec<A> where A::Item: Copy { + /// Copy the elements from a slice into a new `SmallVec`. + /// + /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`. + pub fn from_slice(slice: &[A::Item]) -> Self { + let len = slice.len(); + if len <= A::size() { + SmallVec { + capacity: len, + data: SmallVecData::from_inline(unsafe { + let mut data: A = mem::uninitialized(); + ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len); + data + }) + } + } else { + let mut b = slice.to_vec(); + let (ptr, cap) = (b.as_mut_ptr(), b.capacity()); + mem::forget(b); + SmallVec { + capacity: cap, + data: SmallVecData::from_heap(ptr, len), + } + } + } + + /// Copy elements from a slice into the vector at position `index`, shifting any following + /// elements toward the back. + /// + /// For slices of `Copy` types, this is more efficient than `insert`. + pub fn insert_from_slice(&mut self, index: usize, slice: &[A::Item]) { + self.reserve(slice.len()); + + let len = self.len(); + assert!(index <= len); + + unsafe { + let slice_ptr = slice.as_ptr(); + let ptr = self.as_mut_ptr().offset(index as isize); + ptr::copy(ptr, ptr.offset(slice.len() as isize), len - index); + ptr::copy_nonoverlapping(slice_ptr, ptr, slice.len()); + self.set_len(len + slice.len()); + } + } + + /// Copy elements from a slice and append them to the vector. + /// + /// For slices of `Copy` types, this is more efficient than `extend`. + #[inline] + pub fn extend_from_slice(&mut self, slice: &[A::Item]) { + let len = self.len(); + self.insert_from_slice(len, slice); + } +} + +impl<A: Array> SmallVec<A> where A::Item: Clone { + /// Resizes the vector so that its length is equal to `len`. + /// + /// If `len` is less than the current length, the vector simply truncated. + /// + /// If `len` is greater than the current length, `value` is appended to the + /// vector until its length equals `len`. + pub fn resize(&mut self, len: usize, value: A::Item) { + let old_len = self.len(); + + if len > old_len { + self.extend(repeat(value).take(len - old_len)); + } else { + self.truncate(len); + } + } + + /// Creates a `SmallVec` with `n` copies of `elem`. + /// ``` + /// use smallvec::SmallVec; + /// + /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); + /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); + /// ``` + pub fn from_elem(elem: A::Item, n: usize) -> Self { + if n > A::size() { + vec![elem; n].into() + } else { + let mut v = SmallVec::<A>::new(); + unsafe { + let (ptr, len_ptr, _) = v.triple_mut(); + let mut local_len = SetLenOnDrop::new(len_ptr); + + for i in 0..n as isize { + ::std::ptr::write(ptr.offset(i), elem.clone()); + local_len.increment_len(1); + } + } + v + } + } +} + +impl<A: Array> ops::Deref for SmallVec<A> { + type Target = [A::Item]; + #[inline] + fn deref(&self) -> &[A::Item] { + unsafe { + let (ptr, len, _) = self.triple(); + slice::from_raw_parts(ptr, len) + } + } +} + +impl<A: Array> ops::DerefMut for SmallVec<A> { + #[inline] + fn deref_mut(&mut self) -> &mut [A::Item] { + unsafe { + let (ptr, &mut len, _) = self.triple_mut(); + slice::from_raw_parts_mut(ptr, len) + } + } +} + +impl<A: Array> AsRef<[A::Item]> for SmallVec<A> { + #[inline] + fn as_ref(&self) -> &[A::Item] { + self + } +} + +impl<A: Array> AsMut<[A::Item]> for SmallVec<A> { + #[inline] + fn as_mut(&mut self) -> &mut [A::Item] { + self + } +} + +impl<A: Array> Borrow<[A::Item]> for SmallVec<A> { + #[inline] + fn borrow(&self) -> &[A::Item] { + self + } +} + +impl<A: Array> BorrowMut<[A::Item]> for SmallVec<A> { + #[inline] + fn borrow_mut(&mut self) -> &mut [A::Item] { + self + } +} + +#[cfg(feature = "std")] +impl<A: Array<Item = u8>> io::Write for SmallVec<A> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "serde")] +impl<A: Array> Serialize for SmallVec<A> where A::Item: Serialize { + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { + let mut state = serializer.serialize_seq(Some(self.len()))?; + for item in self { + state.serialize_element(&item)?; + } + state.end() + } +} + +#[cfg(feature = "serde")] +impl<'de, A: Array> Deserialize<'de> for SmallVec<A> where A::Item: Deserialize<'de> { + fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { + deserializer.deserialize_seq(SmallVecVisitor{phantom: PhantomData}) + } +} + +#[cfg(feature = "serde")] +struct SmallVecVisitor<A> { + phantom: PhantomData<A> +} + +#[cfg(feature = "serde")] +impl<'de, A: Array> Visitor<'de> for SmallVecVisitor<A> +where A::Item: Deserialize<'de>, +{ + type Value = SmallVec<A>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq<B>(self, mut seq: B) -> Result<Self::Value, B::Error> + where + B: SeqAccess<'de>, + { + let len = seq.size_hint().unwrap_or(0); + let mut values = SmallVec::with_capacity(len); + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } +} + + +#[cfg(feature = "specialization")] +trait SpecFrom<A: Array, S> { + fn spec_from(slice: S) -> SmallVec<A>; +} + +#[cfg(feature = "specialization")] +impl<'a, A: Array> SpecFrom<A, &'a [A::Item]> for SmallVec<A> where A::Item: Clone { + #[inline] + default fn spec_from(slice: &'a [A::Item]) -> SmallVec<A> { + slice.into_iter().cloned().collect() + } +} + +#[cfg(feature = "specialization")] +impl<'a, A: Array> SpecFrom<A, &'a [A::Item]> for SmallVec<A> where A::Item: Copy { + #[inline] + fn spec_from(slice: &'a [A::Item]) -> SmallVec<A> { + SmallVec::from_slice(slice) + } +} + +impl<'a, A: Array> From<&'a [A::Item]> for SmallVec<A> where A::Item: Clone { + #[cfg(not(feature = "specialization"))] + #[inline] + fn from(slice: &'a [A::Item]) -> SmallVec<A> { + slice.into_iter().cloned().collect() + } + + #[cfg(feature = "specialization")] + #[inline] + fn from(slice: &'a [A::Item]) -> SmallVec<A> { + SmallVec::spec_from(slice) + } +} + +impl<A: Array> From<Vec<A::Item>> for SmallVec<A> { + #[inline] + fn from(vec: Vec<A::Item>) -> SmallVec<A> { + SmallVec::from_vec(vec) + } +} + +impl<A: Array> From<A> for SmallVec<A> { + #[inline] + fn from(array: A) -> SmallVec<A> { + SmallVec::from_buf(array) + } +} + +macro_rules! impl_index { + ($index_type: ty, $output_type: ty) => { + impl<A: Array> ops::Index<$index_type> for SmallVec<A> { + type Output = $output_type; + #[inline] + fn index(&self, index: $index_type) -> &$output_type { + &(&**self)[index] + } + } + + impl<A: Array> ops::IndexMut<$index_type> for SmallVec<A> { + #[inline] + fn index_mut(&mut self, index: $index_type) -> &mut $output_type { + &mut (&mut **self)[index] + } + } + } +} + +impl_index!(usize, A::Item); +impl_index!(ops::Range<usize>, [A::Item]); +impl_index!(ops::RangeFrom<usize>, [A::Item]); +impl_index!(ops::RangeTo<usize>, [A::Item]); +impl_index!(ops::RangeFull, [A::Item]); + +impl<A: Array> ExtendFromSlice<A::Item> for SmallVec<A> where A::Item: Copy { + fn extend_from_slice(&mut self, other: &[A::Item]) { + SmallVec::extend_from_slice(self, other) + } +} + +#[allow(deprecated)] +impl<A: Array> VecLike<A::Item> for SmallVec<A> { + #[inline] + fn push(&mut self, value: A::Item) { + SmallVec::push(self, value); + } +} + +impl<A: Array> FromIterator<A::Item> for SmallVec<A> { + fn from_iter<I: IntoIterator<Item=A::Item>>(iterable: I) -> SmallVec<A> { + let mut v = SmallVec::new(); + v.extend(iterable); + v + } +} + +impl<A: Array> Extend<A::Item> for SmallVec<A> { + fn extend<I: IntoIterator<Item=A::Item>>(&mut self, iterable: I) { + let mut iter = iterable.into_iter(); + let (lower_size_bound, _) = iter.size_hint(); + self.reserve(lower_size_bound); + + unsafe { + let (ptr, len_ptr, cap) = self.triple_mut(); + let mut len = SetLenOnDrop::new(len_ptr); + while len.get() < cap { + if let Some(out) = iter.next() { + ptr::write(ptr.offset(len.get() as isize), out); + len.increment_len(1); + } else { + break; + } + } + } + + for elem in iter { + self.push(elem); + } + } +} + +impl<A: Array> fmt::Debug for SmallVec<A> where A::Item: fmt::Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<A: Array> Default for SmallVec<A> { + #[inline] + fn default() -> SmallVec<A> { + SmallVec::new() + } +} + +#[cfg(feature = "may_dangle")] +unsafe impl<#[may_dangle] A: Array> Drop for SmallVec<A> { + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } + } +} + +#[cfg(not(feature = "may_dangle"))] +impl<A: Array> Drop for SmallVec<A> { + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } + } +} + +impl<A: Array> Clone for SmallVec<A> where A::Item: Clone { + fn clone(&self) -> SmallVec<A> { + let mut new_vector = SmallVec::with_capacity(self.len()); + for element in self.iter() { + new_vector.push((*element).clone()) + } + new_vector + } +} + +impl<A: Array, B: Array> PartialEq<SmallVec<B>> for SmallVec<A> + where A::Item: PartialEq<B::Item> { + #[inline] + fn eq(&self, other: &SmallVec<B>) -> bool { self[..] == other[..] } + #[inline] + fn ne(&self, other: &SmallVec<B>) -> bool { self[..] != other[..] } +} + +impl<A: Array> Eq for SmallVec<A> where A::Item: Eq {} + +impl<A: Array> PartialOrd for SmallVec<A> where A::Item: PartialOrd { + #[inline] + fn partial_cmp(&self, other: &SmallVec<A>) -> Option<cmp::Ordering> { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +impl<A: Array> Ord for SmallVec<A> where A::Item: Ord { + #[inline] + fn cmp(&self, other: &SmallVec<A>) -> cmp::Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl<A: Array> Hash for SmallVec<A> where A::Item: Hash { + fn hash<H: Hasher>(&self, state: &mut H) { + (**self).hash(state) + } +} + +unsafe impl<A: Array> Send for SmallVec<A> where A::Item: Send {} + +/// An iterator that consumes a `SmallVec` and yields its items by value. +/// +/// Returned from [`SmallVec::into_iter`][1]. +/// +/// [1]: struct.SmallVec.html#method.into_iter +pub struct IntoIter<A: Array> { + data: SmallVec<A>, + current: usize, + end: usize, +} + +impl<A: Array> Drop for IntoIter<A> { + fn drop(&mut self) { + for _ in self { } + } +} + +impl<A: Array> Iterator for IntoIter<A> { + type Item = A::Item; + + #[inline] + fn next(&mut self) -> Option<A::Item> { + if self.current == self.end { + None + } + else { + unsafe { + let current = self.current as isize; + self.current += 1; + Some(ptr::read(self.data.as_ptr().offset(current))) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let size = self.end - self.current; + (size, Some(size)) + } +} + +impl<A: Array> DoubleEndedIterator for IntoIter<A> { + #[inline] + fn next_back(&mut self) -> Option<A::Item> { + if self.current == self.end { + None + } + else { + unsafe { + self.end -= 1; + Some(ptr::read(self.data.as_ptr().offset(self.end as isize))) + } + } + } +} + +impl<A: Array> ExactSizeIterator for IntoIter<A> { } + +impl<A: Array> IntoIterator for SmallVec<A> { + type IntoIter = IntoIter<A>; + type Item = A::Item; + fn into_iter(mut self) -> Self::IntoIter { + unsafe { + // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements + let len = self.len(); + self.set_len(0); + IntoIter { + data: self, + current: 0, + end: len, + } + } + } +} + +impl<'a, A: Array> IntoIterator for &'a SmallVec<A> { + type IntoIter = slice::Iter<'a, A::Item>; + type Item = &'a A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut SmallVec<A> { + type IntoIter = slice::IterMut<'a, A::Item>; + type Item = &'a mut A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +/// Types that can be used as the backing store for a SmallVec +pub unsafe trait Array { + /// The type of the array's elements. + type Item; + /// Returns the number of items the array can hold. + fn size() -> usize; + /// Returns a pointer to the first element of the array. + fn ptr(&self) -> *const Self::Item; + /// Returns a mutable pointer to the first element of the array. + fn ptr_mut(&mut self) -> *mut Self::Item; +} + +/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +/// +/// Copied from https://github.com/rust-lang/rust/pull/36355 +struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { local_len: *len, len: len } + } + + #[inline] + fn get(&self) -> usize { + self.local_len + } + + #[inline] + fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl<'a> Drop for SetLenOnDrop<'a> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} + +macro_rules! impl_array( + ($($size:expr),+) => { + $( + unsafe impl<T> Array for [T; $size] { + type Item = T; + fn size() -> usize { $size } + fn ptr(&self) -> *const T { self.as_ptr() } + fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() } + } + )+ + } +); + +impl_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, + 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, + 0x10000, 0x20000, 0x40000, 0x80000, 0x100000); + +#[cfg(test)] +mod tests { + use SmallVec; + + use std::iter::FromIterator; + + #[cfg(feature = "std")] + use std::borrow::ToOwned; + #[cfg(not(feature = "std"))] + use alloc::borrow::ToOwned; + #[cfg(feature = "std")] + use std::rc::Rc; + #[cfg(not(feature = "std"))] + use alloc::rc::Rc; + #[cfg(not(feature = "std"))] + use alloc::boxed::Box; + #[cfg(not(feature = "std"))] + use alloc::vec::Vec; + + #[test] + pub fn test_zero() { + let mut v = SmallVec::<[_; 0]>::new(); + assert!(!v.spilled()); + v.push(0usize); + assert!(v.spilled()); + assert_eq!(&*v, &[0]); + } + + // We heap allocate all these strings so that double frees will show up under valgrind. + + #[test] + pub fn test_inline() { + let mut v = SmallVec::<[_; 16]>::new(); + v.push("hello".to_owned()); + v.push("there".to_owned()); + assert_eq!(&*v, &[ + "hello".to_owned(), + "there".to_owned(), + ][..]); + } + + #[test] + pub fn test_spill() { + let mut v = SmallVec::<[_; 2]>::new(); + v.push("hello".to_owned()); + assert_eq!(v[0], "hello"); + v.push("there".to_owned()); + v.push("burma".to_owned()); + assert_eq!(v[0], "hello"); + v.push("shave".to_owned()); + assert_eq!(&*v, &[ + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned(), + ][..]); + } + + #[test] + pub fn test_double_spill() { + let mut v = SmallVec::<[_; 2]>::new(); + v.push("hello".to_owned()); + v.push("there".to_owned()); + v.push("burma".to_owned()); + v.push("shave".to_owned()); + v.push("hello".to_owned()); + v.push("there".to_owned()); + v.push("burma".to_owned()); + v.push("shave".to_owned()); + assert_eq!(&*v, &[ + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned(), + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned(), + ][..]); + } + + /// https://github.com/servo/rust-smallvec/issues/4 + #[test] + fn issue_4() { + SmallVec::<[Box<u32>; 2]>::new(); + } + + /// https://github.com/servo/rust-smallvec/issues/5 + #[test] + fn issue_5() { + assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some()); + } + + #[test] + fn test_with_capacity() { + let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(1); + assert!(v.is_empty()); + assert!(!v.spilled()); + assert_eq!(v.capacity(), 3); + + let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(10); + assert!(v.is_empty()); + assert!(v.spilled()); + assert_eq!(v.capacity(), 10); + } + + #[test] + fn drain() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().collect::<Vec<_>>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().collect::<Vec<_>>(), &[3, 4, 5]); + } + + #[test] + fn drain_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().rev().collect::<Vec<_>>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().rev().collect::<Vec<_>>(), &[5, 4, 3]); + } + + #[test] + fn into_iter() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.into_iter().collect::<Vec<_>>(), &[3]); + + // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.into_iter().collect::<Vec<_>>(), &[3, 4, 5]); + } + + #[test] + fn into_iter_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.into_iter().rev().collect::<Vec<_>>(), &[3]); + + // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.into_iter().rev().collect::<Vec<_>>(), &[5, 4, 3]); + } + + #[test] + fn into_iter_drop() { + use std::cell::Cell; + + struct DropCounter<'a>(&'a Cell<i32>); + + impl<'a> Drop for DropCounter<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.into_iter(); + assert_eq!(cell.get(), 1); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 2); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 3); + } + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + { + let mut it = v.into_iter(); + assert!(it.next().is_some()); + assert!(it.next_back().is_some()); + } + assert_eq!(cell.get(), 3); + } + } + + #[test] + fn test_capacity() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.reserve(1); + assert_eq!(v.capacity(), 2); + assert!(!v.spilled()); + + v.reserve_exact(0x100); + assert!(v.capacity() >= 0x100); + + v.push(0); + v.push(1); + v.push(2); + v.push(3); + + v.shrink_to_fit(); + assert!(v.capacity() < 0x100); + } + + #[test] + fn test_truncate() { + let mut v: SmallVec<[Box<u8>; 8]> = SmallVec::new(); + + for x in 0..8 { + v.push(Box::new(x)); + } + v.truncate(4); + + assert_eq!(v.len(), 4); + assert!(!v.spilled()); + + assert_eq!(*v.swap_remove(1), 1); + assert_eq!(*v.remove(1), 3); + v.insert(1, Box::new(3)); + + assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[0, 3, 2]); + } + + #[test] + fn test_insert_many() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many(1, [5, 6].iter().cloned()); + assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]); + } + + struct MockHintIter<T: Iterator>{x: T, hint: usize} + impl<T: Iterator> Iterator for MockHintIter<T> { + type Item = T::Item; + fn next(&mut self) -> Option<Self::Item> {self.x.next()} + fn size_hint(&self) -> (usize, Option<usize>) {(self.hint, None)} + } + + #[test] + fn test_insert_many_short_hint() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 5}); + assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]); + } + + #[test] + fn test_insert_many_long_hint() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 1}); + assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]); + } + + #[cfg(feature = "std")] + #[test] + // https://github.com/servo/rust-smallvec/issues/96 + fn test_insert_many_panic() { + struct PanicOnDoubleDrop { + dropped: Box<bool> + } + + impl Drop for PanicOnDoubleDrop { + fn drop(&mut self) { + assert!(!*self.dropped, "already dropped"); + *self.dropped = true; + } + } + + struct BadIter; + impl Iterator for BadIter { + type Item = PanicOnDoubleDrop; + fn size_hint(&self) -> (usize, Option<usize>) { (1, None) } + fn next(&mut self) -> Option<Self::Item> { panic!() } + } + + let mut vec: SmallVec<[PanicOnDoubleDrop; 0]> = vec![ + PanicOnDoubleDrop { dropped: Box::new(false) }, + PanicOnDoubleDrop { dropped: Box::new(false) }, + ].into(); + let result = ::std::panic::catch_unwind(move || { + vec.insert_many(0, BadIter); + }); + assert!(result.is_err()); + } + + #[test] + #[should_panic] + fn test_invalid_grow() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + v.extend(0..8); + v.grow(5); + } + + #[test] + fn test_insert_from_slice() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_from_slice(1, &[5, 6]); + assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]); + } + + #[test] + fn test_extend_from_slice() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.extend_from_slice(&[5, 6]); + assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 1, 2, 3, 5, 6]); + } + + #[test] + #[should_panic] + fn test_drop_panic_smallvec() { + // This test should only panic once, and not double panic, + // which would mean a double drop + struct DropPanic; + + impl Drop for DropPanic { + fn drop(&mut self) { + panic!("drop"); + } + } + + let mut v = SmallVec::<[_; 1]>::new(); + v.push(DropPanic); + } + + #[test] + fn test_eq() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let mut b: SmallVec<[u32; 2]> = SmallVec::new(); + let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + // a = [1, 2] + a.push(1); + a.push(2); + // b = [1, 2] + b.push(1); + b.push(2); + // c = [3, 4] + c.push(3); + c.push(4); + + assert!(a == b); + assert!(a != c); + } + + #[test] + fn test_ord() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let mut b: SmallVec<[u32; 2]> = SmallVec::new(); + let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + // a = [1] + a.push(1); + // b = [1, 1] + b.push(1); + b.push(1); + // c = [1, 2] + c.push(1); + c.push(2); + + assert!(a < b); + assert!(b > a); + assert!(b < c); + assert!(c > b); + } + + #[cfg(feature = "std")] + #[test] + fn test_hash() { + use std::hash::Hash; + use std::collections::hash_map::DefaultHasher; + + { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let b = [1, 2]; + a.extend(b.iter().cloned()); + let mut hasher = DefaultHasher::new(); + assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); + } + { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let b = [1, 2, 11, 12]; + a.extend(b.iter().cloned()); + let mut hasher = DefaultHasher::new(); + assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); + } + } + + #[test] + fn test_as_ref() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_ref(), [1]); + a.push(2); + assert_eq!(a.as_ref(), [1, 2]); + a.push(3); + assert_eq!(a.as_ref(), [1, 2, 3]); + } + + #[test] + fn test_as_mut() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_mut(), [1]); + a.push(2); + assert_eq!(a.as_mut(), [1, 2]); + a.push(3); + assert_eq!(a.as_mut(), [1, 2, 3]); + a.as_mut()[1] = 4; + assert_eq!(a.as_mut(), [1, 4, 3]); + } + + #[test] + fn test_borrow() { + use std::borrow::Borrow; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow(), [1]); + a.push(2); + assert_eq!(a.borrow(), [1, 2]); + a.push(3); + assert_eq!(a.borrow(), [1, 2, 3]); + } + + #[test] + fn test_borrow_mut() { + use std::borrow::BorrowMut; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow_mut(), [1]); + a.push(2); + assert_eq!(a.borrow_mut(), [1, 2]); + a.push(3); + assert_eq!(a.borrow_mut(), [1, 2, 3]); + BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; + assert_eq!(a.borrow_mut(), [1, 4, 3]); + } + + #[test] + fn test_from() { + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1][..])[..], [1]); + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1, 2, 3][..])[..], [1, 2, 3]); + + let vec = vec![]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let array = [1]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from(array); + assert_eq!(&*small_vec, &[1]); + drop(small_vec); + + let array = [99; 128]; + let small_vec: SmallVec<[u8; 128]> = SmallVec::from(array); + assert_eq!(&*small_vec, vec![99u8; 128].as_slice()); + drop(small_vec); + } + + #[test] + fn test_from_slice() { + assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1][..])[..], [1]); + assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], [1, 2, 3]); + } + + #[test] + fn test_exact_size_iterator() { + let mut vec = SmallVec::<[u32; 2]>::from(&[1, 2, 3][..]); + assert_eq!(vec.clone().into_iter().len(), 3); + assert_eq!(vec.drain().len(), 3); + } + + #[test] + #[allow(deprecated)] + fn veclike_deref_slice() { + use super::VecLike; + + fn test<T: VecLike<i32>>(vec: &mut T) { + assert!(!vec.is_empty()); + assert_eq!(vec.len(), 3); + + vec.sort(); + assert_eq!(&vec[..], [1, 2, 3]); + } + + let mut vec = SmallVec::<[i32; 2]>::from(&[3, 1, 2][..]); + test(&mut vec); + } + + #[test] + fn shrink_to_fit_unspill() { + let mut vec = SmallVec::<[u8; 2]>::from_iter(0..3); + vec.pop(); + assert!(vec.spilled()); + vec.shrink_to_fit(); + assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible"); + } + + #[test] + fn test_into_vec() { + let vec = SmallVec::<[u8; 2]>::from_iter(0..2); + assert_eq!(vec.into_vec(), vec![0, 1]); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..3); + assert_eq!(vec.into_vec(), vec![0, 1, 2]); + } + + #[test] + fn test_into_inner() { + let vec = SmallVec::<[u8; 2]>::from_iter(0..2); + assert_eq!(vec.into_inner(), Ok([0, 1])); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..1); + assert_eq!(vec.clone().into_inner(), Err(vec)); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..3); + assert_eq!(vec.clone().into_inner(), Err(vec)); + } + + #[test] + fn test_from_vec() { + let vec = vec![]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![1]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1]); + drop(small_vec); + + let vec = vec![1, 2, 3]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + } + + #[test] + fn test_retain() { + // Test inline data storate + let mut sv: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); + sv.retain(|&mut i| i != 3); + assert_eq!(sv.pop(), Some(4)); + assert_eq!(sv.pop(), Some(2)); + assert_eq!(sv.pop(), Some(1)); + assert_eq!(sv.pop(), None); + + // Test spilled data storage + let mut sv: SmallVec<[i32; 3]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); + sv.retain(|&mut i| i != 3); + assert_eq!(sv.pop(), Some(4)); + assert_eq!(sv.pop(), Some(2)); + assert_eq!(sv.pop(), Some(1)); + assert_eq!(sv.pop(), None); + + // Test that drop implementations are called for inline. + let one = Rc::new(1); + let mut sv: SmallVec<[Rc<i32>; 3]> = SmallVec::new(); + sv.push(Rc::clone(&one)); + assert_eq!(Rc::strong_count(&one), 2); + sv.retain(|_| false); + assert_eq!(Rc::strong_count(&one), 1); + + // Test that drop implementations are called for spilled data. + let mut sv: SmallVec<[Rc<i32>; 1]> = SmallVec::new(); + sv.push(Rc::clone(&one)); + sv.push(Rc::new(2)); + assert_eq!(Rc::strong_count(&one), 2); + sv.retain(|_| false); + assert_eq!(Rc::strong_count(&one), 1); + } + + #[test] + fn test_dedup() { + let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); + dupes.dedup(); + assert_eq!(&*dupes, &[1, 2, 3]); + + let mut empty: SmallVec<[i32; 5]> = SmallVec::new(); + empty.dedup(); + assert!(empty.is_empty()); + + let mut all_ones: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 1, 1, 1]); + all_ones.dedup(); + assert_eq!(all_ones.len(), 1); + + let mut no_dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 4, 5]); + no_dupes.dedup(); + assert_eq!(no_dupes.len(), 5); + } + + #[test] + fn test_resize() { + let mut v: SmallVec<[i32; 8]> = SmallVec::new(); + v.push(1); + v.resize(5, 0); + assert_eq!(v[..], [1, 0, 0, 0, 0][..]); + + v.resize(2, -1); + assert_eq!(v[..], [1, 0][..]); + } + + #[cfg(feature = "std")] + #[test] + fn test_write() { + use io::Write; + + let data = [1, 2, 3, 4, 5]; + + let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); + let len = small_vec.write(&data[..]).unwrap(); + assert_eq!(len, 5); + assert_eq!(small_vec.as_ref(), data.as_ref()); + + let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); + small_vec.write_all(&data[..]).unwrap(); + assert_eq!(small_vec.as_ref(), data.as_ref()); + } + + #[cfg(feature = "serde")] + extern crate bincode; + + #[cfg(feature = "serde")] + #[test] + fn test_serde() { + use self::bincode::{config, deserialize}; + let mut small_vec: SmallVec<[i32; 2]> = SmallVec::new(); + small_vec.push(1); + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); + small_vec.push(2); + // Spill the vec + small_vec.push(3); + small_vec.push(4); + // Check again after spilling. + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); + } +} diff --git a/socket2/.cargo-checksum.json b/socket2/.cargo-checksum.json new file mode 100644 index 000000000..50f48bcb7 --- /dev/null +++ b/socket2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"4e626972d3593207547f14bf5fc9efa4d0e7283deb73fef1dff313dae9ab8878"} \ No newline at end of file diff --git a/socket2/Cargo.toml b/socket2/Cargo.toml new file mode 100644 index 000000000..7526094bd --- /dev/null +++ b/socket2/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "socket2" +version = "0.3.9" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +description = "Utilities for handling networking sockets with a maximal amount of configuration\npossible intended.\n" +homepage = "https://github.com/alexcrichton/socket2-rs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/socket2-rs" +[package.metadata.docs.rs] +all-features = true +[dev-dependencies.tempdir] +version = "0.3" + +[features] +pair = [] +reuseport = [] +unix = [] +[target."cfg(any(unix, target_os = \"redox\"))".dependencies.cfg-if] +version = "0.1" + +[target."cfg(any(unix, target_os = \"redox\"))".dependencies.libc] +version = "0.2.42" +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1.38" +[target."cfg(windows)".dependencies.winapi] +version = "0.3.3" +features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] diff --git a/socket2/LICENSE-APACHE b/socket2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/socket2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/socket2/LICENSE-MIT b/socket2/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/socket2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/socket2/README.md b/socket2/README.md new file mode 100644 index 000000000..0e9e91481 --- /dev/null +++ b/socket2/README.md @@ -0,0 +1,23 @@ +# socket2-rs + +[![Build Status](https://travis-ci.com/alexcrichton/socket2-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/socket2-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/hovebj1gr4bgm3d9?svg=true)](https://ci.appveyor.com/project/alexcrichton/socket2-rs) + +[Documentation](https://docs.rs/socket2) + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, + shall be dual licensed as above, without any additional terms or conditions. diff --git a/socket2/src/lib.rs b/socket2/src/lib.rs new file mode 100644 index 000000000..16e745d4e --- /dev/null +++ b/socket2/src/lib.rs @@ -0,0 +1,153 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utilities for handling sockets +//! +//! This crate is sort of an evolution of the `net2` crate after seeing the +//! issues on it over time. The intention of this crate is to provide as direct +//! as possible access to the system's functionality for sockets as possible. No +//! extra fluff (e.g. multiple syscalls or builders) provided in this crate. As +//! a result using this crate can be a little wordy, but it should give you +//! maximal flexibility over configuration of sockets. +//! +//! # Examples +//! +//! ```no_run +//! use std::net::SocketAddr; +//! use socket2::{Socket, Domain, Type}; +//! +//! // create a TCP listener bound to two addresses +//! let socket = Socket::new(Domain::ipv6(), Type::stream(), None).unwrap(); +//! +//! socket.bind(&"[::1]:12345".parse::<SocketAddr>().unwrap().into()).unwrap(); +//! socket.set_only_v6(false); +//! socket.listen(128).unwrap(); +//! +//! let listener = socket.into_tcp_listener(); +//! // ... +//! ``` + +#![doc(html_root_url = "https://docs.rs/socket2/0.3")] +#![deny(missing_docs)] + +#[cfg(unix)] +#[macro_use] +extern crate cfg_if; +#[cfg(target_os = "redox")] +extern crate cfg_if; +#[cfg(any(unix, target_os = "redox"))] +extern crate libc; +#[cfg(target_os = "redox")] +extern crate syscall; + +#[cfg(windows)] +extern crate winapi; + +#[cfg(test)] +extern crate tempdir; + +use utils::NetInt; + +#[cfg(any(unix, target_os = "redox"))] +use libc::{sockaddr_storage, socklen_t}; +#[cfg(windows)] +use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage; +#[cfg(windows)] +use winapi::um::ws2tcpip::socklen_t; + +mod sockaddr; +mod socket; +mod utils; + +#[cfg_attr(unix, path = "sys/unix/mod.rs")] +#[cfg_attr(target_os = "redox", path = "sys/redox/mod.rs")] +#[cfg_attr(windows, path = "sys/windows.rs")] +mod sys; + +/// Newtype, owned, wrapper around a system socket. +/// +/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix +/// and an instance of `SOCKET` on Windows. This is the main type exported by +/// this crate and is intended to mirror the raw semantics of sockets on +/// platforms as closely as possible. Almost all methods correspond to +/// precisely one libc or OS API call which is essentially just a "Rustic +/// translation" of what's below. +/// +/// # Examples +/// +/// ```no_run +/// use std::net::SocketAddr; +/// use socket2::{Socket, Domain, Type, SockAddr}; +/// +/// // create a TCP listener bound to two addresses +/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +/// +/// socket.bind(&"127.0.0.1:12345".parse::<SocketAddr>().unwrap().into()).unwrap(); +/// socket.bind(&"127.0.0.1:12346".parse::<SocketAddr>().unwrap().into()).unwrap(); +/// socket.listen(128).unwrap(); +/// +/// let listener = socket.into_tcp_listener(); +/// // ... +/// ``` +pub struct Socket { + inner: sys::Socket, +} + +/// The address of a socket. +/// +/// `SockAddr`s may be constructed directly to and from the standard library +/// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types. +pub struct SockAddr { + storage: sockaddr_storage, + len: socklen_t, +} + +/// Specification of the communication domain for a socket. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. Convenience constructors +/// such as `Domain::ipv4`, `Domain::ipv6`, etc, are provided to avoid reaching +/// into libc for various constants. +/// +/// This type is freely interconvertible with the `i32` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone)] +pub struct Domain(i32); + +/// Specification of communication semantics on a socket. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. Convenience constructors +/// such as `Type::stream`, `Type::dgram`, etc, are provided to avoid reaching +/// into libc for various constants. +/// +/// This type is freely interconvertible with the `i32` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone)] +pub struct Type(i32); + +/// Protocol specification used for creating sockets via `Socket::new`. +/// +/// This is a newtype wrapper around an integer which provides a nicer API in +/// addition to an injection point for documentation. +/// +/// This type is freely interconvertible with the `i32` type, however, if a raw +/// value needs to be provided. +#[derive(Copy, Clone)] +pub struct Protocol(i32); + +fn hton<I: NetInt>(i: I) -> I { + i.to_be() +} + +#[cfg(not(target_os = "redox"))] +fn ntoh<I: NetInt>(i: I) -> I { + I::from_be(i) +} diff --git a/socket2/src/sockaddr.rs b/socket2/src/sockaddr.rs new file mode 100644 index 000000000..9806ad832 --- /dev/null +++ b/socket2/src/sockaddr.rs @@ -0,0 +1,212 @@ +use std::fmt; +use std::mem; +use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::ptr; + +#[cfg(any(unix, target_os = "redox"))] +use libc::{sa_family_t, sockaddr, sockaddr_in, sockaddr_storage, socklen_t, AF_INET6, + sockaddr_in6, AF_INET}; +#[cfg(windows)] +use winapi::shared::ws2def::{ADDRESS_FAMILY as sa_family_t, AF_INET6, SOCKADDR as sockaddr, + SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, + AF_INET}; +#[cfg(windows)] +use winapi::um::ws2tcpip::socklen_t; +#[cfg(windows)] +use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; + +use SockAddr; + +impl fmt::Debug for SockAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let mut builder = fmt.debug_struct("SockAddr"); + builder.field("family", &self.family()); + if let Some(addr) = self.as_inet() { + builder.field("inet", &addr); + } else if let Some(addr) = self.as_inet6() { + builder.field("inet6", &addr); + } + builder.finish() + } +} + +impl SockAddr { + /// Constructs a `SockAddr` from its raw components. + pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { + let mut storage = mem::uninitialized::<sockaddr_storage>(); + ptr::copy_nonoverlapping( + addr as *const _ as *const u8, + &mut storage as *mut _ as *mut u8, + len as usize, + ); + + SockAddr { + storage: storage, + len: len, + } + } + + /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. + /// + /// This function is only available on Unix when the `unix` feature is + /// enabled. + /// + /// # Failure + /// + /// Returns an error if the path is longer than `SUN_LEN`. + #[cfg(all(unix, feature = "unix"))] + pub fn unix<P>(path: P) -> ::std::io::Result<SockAddr> + where + P: AsRef<::std::path::Path>, + { + use std::cmp::Ordering; + use std::io; + use std::os::unix::ffi::OsStrExt; + use libc::{c_char, sockaddr_un, AF_UNIX}; + + unsafe { + let mut addr = mem::zeroed::<sockaddr_un>(); + addr.sun_family = AF_UNIX as sa_family_t; + + let bytes = path.as_ref().as_os_str().as_bytes(); + + match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) { + // Abstract paths don't need a null terminator + (Some(&0), Ordering::Greater) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be no longer than SUN_LEN", + )); + } + (Some(&0), _) => {} + (_, Ordering::Greater) | (_, Ordering::Equal) => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + _ => {} + } + + for (dst, src) in addr.sun_path.iter_mut().zip(bytes) { + *dst = *src as c_char; + } + // null byte for pathname is already there since we zeroed up front + + let base = &addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + let sun_path_offset = path - base; + + let mut len = sun_path_offset + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok(SockAddr::from_raw_parts( + &addr as *const _ as *const _, + len as socklen_t, + )) + } + } + + unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> { + if self.storage.ss_family != family { + return None; + } + + Some(mem::transmute_copy(&self.storage)) + } + + /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET` + /// family. + pub fn as_inet(&self) -> Option<SocketAddrV4> { + unsafe { self.as_(AF_INET as sa_family_t) } + } + + /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6` + /// family. + pub fn as_inet6(&self) -> Option<SocketAddrV6> { + unsafe { self.as_(AF_INET6 as sa_family_t) } + } + + /// Returns this address's family. + pub fn family(&self) -> sa_family_t { + self.storage.ss_family + } + + /// Returns the size of this address in bytes. + pub fn len(&self) -> socklen_t { + self.len + } + + /// Returns a raw pointer to the address. + pub fn as_ptr(&self) -> *const sockaddr { + &self.storage as *const _ as *const _ + } +} + +// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6 + +// check to make sure that the sizes at least match up +fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) { + unsafe { + mem::transmute::<SocketAddrV4, sockaddr_in>(v4); + mem::transmute::<SocketAddrV6, sockaddr_in6>(v6); + } +} + +impl From<SocketAddrV4> for SockAddr { + fn from(addr: SocketAddrV4) -> SockAddr { + unsafe { + SockAddr::from_raw_parts( + &addr as *const _ as *const _, + mem::size_of::<SocketAddrV4>() as socklen_t, + ) + } + } +} + +impl From<SocketAddrV6> for SockAddr { + fn from(addr: SocketAddrV6) -> SockAddr { + unsafe { + SockAddr::from_raw_parts( + &addr as *const _ as *const _, + mem::size_of::<SocketAddrV6>() as socklen_t, + ) + } + } +} + +impl From<SocketAddr> for SockAddr { + fn from(addr: SocketAddr) -> SockAddr { + match addr { + SocketAddr::V4(addr) => addr.into(), + SocketAddr::V6(addr) => addr.into(), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn inet() { + let raw = "127.0.0.1:80".parse::<SocketAddrV4>().unwrap(); + let addr = SockAddr::from(raw); + assert!(addr.as_inet6().is_none()); + let addr = addr.as_inet().unwrap(); + assert_eq!(raw, addr); + } + + #[test] + fn inet6() { + let raw = "[2001:db8::ff00:42:8329]:80" + .parse::<SocketAddrV6>() + .unwrap(); + let addr = SockAddr::from(raw); + assert!(addr.as_inet().is_none()); + let addr = addr.as_inet6().unwrap(); + assert_eq!(raw, addr); + } +} diff --git a/socket2/src/socket.rs b/socket2/src/socket.rs new file mode 100644 index 000000000..439600220 --- /dev/null +++ b/socket2/src/socket.rs @@ -0,0 +1,997 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::io::{self, Read, Write}; +use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; +use std::time::Duration; +#[cfg(all(unix, feature = "unix"))] +use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; + +#[cfg(any(unix, target_os = "redox"))] +use libc as c; +#[cfg(windows)] +use winapi::shared::ws2def as c; + +use sys; +use {Domain, Protocol, SockAddr, Socket, Type}; + +impl Socket { + /// Creates a new socket ready to be configured. + /// + /// This function corresponds to `socket(2)` and simply creates a new + /// socket, no other configuration is done and further functions must be + /// invoked to configure this socket. + pub fn new(domain: Domain, type_: Type, protocol: Option<Protocol>) -> io::Result<Socket> { + let protocol = protocol.map(|p| p.0).unwrap_or(0); + Ok(Socket { + inner: sys::Socket::new(domain.0, type_.0, protocol)?, + }) + } + + /// Creates a pair of sockets which are connected to each other. + /// + /// This function corresponds to `socketpair(2)`. + /// + /// This function is only available on Unix when the `pair` feature is + /// enabled. + #[cfg(all(unix, feature = "pair"))] + pub fn pair( + domain: Domain, + type_: Type, + protocol: Option<Protocol>, + ) -> io::Result<(Socket, Socket)> { + let protocol = protocol.map(|p| p.0).unwrap_or(0); + let sockets = sys::Socket::pair(domain.0, type_.0, protocol)?; + Ok((Socket { inner: sockets.0 }, Socket { inner: sockets.1 })) + } + + /// Consumes this `Socket`, converting it to a `TcpStream`. + pub fn into_tcp_stream(self) -> net::TcpStream { + self.into() + } + + /// Consumes this `Socket`, converting it to a `TcpListener`. + pub fn into_tcp_listener(self) -> net::TcpListener { + self.into() + } + + /// Consumes this `Socket`, converting it to a `UdpSocket`. + pub fn into_udp_socket(self) -> net::UdpSocket { + self.into() + } + + /// Consumes this `Socket`, converting it into a `UnixStream`. + /// + /// This function is only available on Unix when the `unix` feature is + /// enabled. + #[cfg(all(unix, feature = "unix"))] + pub fn into_unix_stream(self) -> UnixStream { + self.into() + } + + /// Consumes this `Socket`, converting it into a `UnixListener`. + /// + /// This function is only available on Unix when the `unix` feature is + /// enabled. + #[cfg(all(unix, feature = "unix"))] + pub fn into_unix_listener(self) -> UnixListener { + self.into() + } + + /// Consumes this `Socket`, converting it into a `UnixDatagram`. + /// + /// This function is only available on Unix when the `unix` feature is + /// enabled. + #[cfg(all(unix, feature = "unix"))] + pub fn into_unix_datagram(self) -> UnixDatagram { + self.into() + } + + /// Initiate a connection on this socket to the specified address. + /// + /// This function directly corresponds to the connect(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { + self.inner.connect(addr) + } + + /// Initiate a connection on this socket to the specified address, only + /// only waiting for a certain period of time for the connection to be + /// established. + /// + /// Unlike many other methods on `Socket`, this does *not* correspond to a + /// single C function. It sets the socket to nonblocking mode, connects via + /// connect(2), and then waits for the connection to complete with poll(2) + /// on Unix and select on Windows. When the connection is complete, the + /// socket is set back to blocking mode. On Unix, this will loop over + /// `EINTR` errors. + /// + /// # Warnings + /// + /// The nonblocking state of the socket is overridden by this function - + /// it will be returned in blocking mode on success, and in an indeterminate + /// state on failure. + /// + /// If the connection request times out, it may still be processing in the + /// background - a second call to `connect` or `connect_timeout` may fail. + pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { + self.inner.connect_timeout(addr, timeout) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { + self.inner.bind(addr) + } + + /// Mark a socket as ready to accept incoming connection requests using + /// accept() + /// + /// This function directly corresponds to the listen(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn listen(&self, backlog: i32) -> io::Result<()> { + self.inner.listen(backlog) + } + + /// Accept a new incoming connection from this listener. + /// + /// This function will block the calling thread until a new connection is + /// established. When established, the corresponding `Socket` and the + /// remote peer's address will be returned. + pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { + self.inner + .accept() + .map(|(socket, addr)| (Socket { inner: socket }, addr)) + } + + /// Returns the socket address of the local half of this TCP connection. + pub fn local_addr(&self) -> io::Result<SockAddr> { + self.inner.local_addr() + } + + /// Returns the socket address of the remote peer of this TCP connection. + pub fn peer_addr(&self) -> io::Result<SockAddr> { + self.inner.peer_addr() + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `TcpStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + pub fn try_clone(&self) -> io::Result<Socket> { + self.inner.try_clone().map(|s| Socket { inner: s }) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.inner.take_error() + } + + /// Moves this TCP stream into or out of nonblocking mode. + /// + /// On Unix this corresponds to calling fcntl, and on Windows this + /// corresponds to calling ioctlsocket. + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.inner.set_nonblocking(nonblocking) + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O on the specified + /// portions to return immediately with an appropriate value. + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.inner.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected. + /// + /// The [`connect`] method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + /// + /// [`connect`]: #method.connect + pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.recv(buf) + } + + /// Receives data on the socket from the remote adress to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.peek(buf) + } + + /// Receives data from the socket. On success, returns the number of bytes + /// read and the address from whence the data came. + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.inner.recv_from(buf) + } + + /// Receives data from the socket, without removing it from the queue. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// On success, returns the number of bytes peeked and the address from + /// whence the data came. + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.inner.peek_from(buf) + } + + /// Sends data on the socket to a connected peer. + /// + /// This is typically used on TCP sockets or datagram sockets which have + /// been connected. + /// + /// On success returns the number of bytes that were sent. + pub fn send(&self, buf: &[u8]) -> io::Result<usize> { + self.inner.send(buf) + } + + /// Sends data on the socket to the given address. On success, returns the + /// number of bytes written. + /// + /// This is typically used on UDP or datagram-oriented sockets. On success + /// returns the number of bytes that were sent. + pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { + self.inner.send_to(buf, addr) + } + + // ================================================ + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #method.set_ttl + pub fn ttl(&self) -> io::Result<u32> { + self.inner.ttl() + } + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This value sets the time-to-live field that is used in every packet sent + /// from this socket. + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + self.inner.set_ttl(ttl) + } + + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + pub fn unicast_hops_v6(&self) -> io::Result<u32> { + self.inner.unicast_hops_v6() + } + + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + pub fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()> { + self.inner.set_unicast_hops_v6(ttl) + } + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see [`set_only_v6`][link]. + /// + /// [link]: #method.set_only_v6 + pub fn only_v6(&self) -> io::Result<bool> { + self.inner.only_v6() + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// If this is set to `true` then the socket is restricted to sending and + /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications + /// can bind the same port at the same time. + /// + /// If this is set to `false` then the socket can be used to send and + /// receive packets from an IPv4-mapped IPv6 address. + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + self.inner.set_only_v6(only_v6) + } + + /// Returns the read timeout of this socket. + /// + /// If the timeout is `None`, then `read` calls will block indefinitely. + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.inner.read_timeout() + } + + /// Sets the read timeout to the timeout specified. + /// + /// If the value specified is `None`, then `read` calls will block + /// indefinitely. It is an error to pass the zero `Duration` to this + /// method. + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.inner.set_read_timeout(dur) + } + + /// Returns the write timeout of this socket. + /// + /// If the timeout is `None`, then `write` calls will block indefinitely. + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.inner.write_timeout() + } + + /// Sets the write timeout to the timeout specified. + /// + /// If the value specified is `None`, then `write` calls will block + /// indefinitely. It is an error to pass the zero `Duration` to this + /// method. + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.inner.set_write_timeout(dur) + } + + /// Gets the value of the `TCP_NODELAY` option on this socket. + /// + /// For more information about this option, see [`set_nodelay`][link]. + /// + /// [link]: #method.set_nodelay + pub fn nodelay(&self) -> io::Result<bool> { + self.inner.nodelay() + } + + /// Sets the value of the `TCP_NODELAY` option on this socket. + /// + /// If set, this option disables the Nagle algorithm. This means that + /// segments are always sent as soon as possible, even if there is only a + /// small amount of data. When not set, data is buffered until there is a + /// sufficient amount to send out, thereby avoiding the frequent sending of + /// small packets. + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + self.inner.set_nodelay(nodelay) + } + + /// Sets the value of the `SO_BROADCAST` option for this socket. + /// + /// When enabled, this socket is allowed to send packets to a broadcast + /// address. + pub fn broadcast(&self) -> io::Result<bool> { + self.inner.broadcast() + } + + /// Gets the value of the `SO_BROADCAST` option for this socket. + /// + /// For more information about this option, see + /// [`set_broadcast`][link]. + /// + /// [link]: #method.set_broadcast + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + self.inner.set_broadcast(broadcast) + } + + /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v4`][link]. + /// + /// [link]: #method.set_multicast_loop_v4 + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + self.inner.multicast_loop_v4() + } + + /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// If enabled, multicast packets will be looped back to the local socket. + /// Note that this may not have any affect on IPv6 sockets. + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + self.inner.set_multicast_loop_v4(multicast_loop_v4) + } + + /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_ttl_v4`][link]. + /// + /// [link]: #method.set_multicast_ttl_v4 + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + self.inner.multicast_ttl_v4() + } + + /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// Indicates the time-to-live value of outgoing multicast packets for + /// this socket. The default value is 1 which means that multicast packets + /// don't leave the local network unless explicitly requested. + /// + /// Note that this may not have any affect on IPv6 sockets. + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + self.inner.set_multicast_ttl_v4(multicast_ttl_v4) + } + + /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket + /// + /// For more information about this option, see + /// [`set_multicast_hops_v6`][link]. + /// + /// [link]: #method.set_multicast_hops_v6 + pub fn multicast_hops_v6(&self) -> io::Result<u32> { + self.inner.multicast_hops_v6() + } + + /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket + /// + /// Indicates the number of "routers" multicast packets will transit for + /// this socket. The default value is 1 which means that multicast packets + /// don't leave the local network unless explicitly requested. + pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { + self.inner.set_multicast_hops_v6(hops) + } + + /// Gets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_if_v4`][link]. + /// + /// [link]: #method.set_multicast_if_v4 + /// + /// Returns the interface to use for routing multicast packets. + pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { + self.inner.multicast_if_v4() + } + + /// Sets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { + self.inner.set_multicast_if_v4(interface) + } + + /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_if_v6`][link]. + /// + /// [link]: #method.set_multicast_if_v6 + /// + /// Returns the interface to use for routing multicast packets. + pub fn multicast_if_v6(&self) -> io::Result<u32> { + self.inner.multicast_if_v6() + } + + /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. Unlike ipv4, this + /// is generally required in ipv6 contexts where network routing prefixes may + /// overlap. + pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { + self.inner.set_multicast_if_v6(interface) + } + + /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v6`][link]. + /// + /// [link]: #method.set_multicast_loop_v6 + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + self.inner.multicast_loop_v6() + } + + /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// Controls whether this socket sees the multicast packets it sends itself. + /// Note that this may not have any affect on IPv4 sockets. + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + self.inner.set_multicast_loop_v6(multicast_loop_v6) + } + + /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// address of the local interface with which the system should join the + /// multicast group. If it's equal to `INADDR_ANY` then an appropriate + /// interface is chosen by the system. + pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + self.inner.join_multicast_v4(multiaddr, interface) + } + + /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// index of the interface to join/leave (or 0 to indicate any interface). + pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + self.inner.join_multicast_v6(multiaddr, interface) + } + + /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v4`][link]. + /// + /// [link]: #method.join_multicast_v4 + pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + self.inner.leave_multicast_v4(multiaddr, interface) + } + + /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v6`][link]. + /// + /// [link]: #method.join_multicast_v6 + pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + self.inner.leave_multicast_v6(multiaddr, interface) + } + + /// Reads the linger duration for this socket by getting the SO_LINGER + /// option + pub fn linger(&self) -> io::Result<Option<Duration>> { + self.inner.linger() + } + + /// Sets the linger duration of this socket by setting the SO_LINGER option + pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + self.inner.set_linger(dur) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn reuse_address(&self) -> io::Result<bool> { + self.inner.reuse_address() + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This indicates that futher calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { + self.inner.set_reuse_address(reuse) + } + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see + /// [`set_recv_buffer_size`][link]. + /// + /// [link]: #method.set_recv_buffer_size + pub fn recv_buffer_size(&self) -> io::Result<usize> { + self.inner.recv_buffer_size() + } + + /// Sets the value of the `SO_RCVBUF` option on this socket. + /// + /// Changes the size of the operating system's receive buffer associated + /// with the socket. + pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + self.inner.set_recv_buffer_size(size) + } + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #method.set_send_buffer + pub fn send_buffer_size(&self) -> io::Result<usize> { + self.inner.send_buffer_size() + } + + /// Sets the value of the `SO_SNDBUF` option on this socket. + /// + /// Changes the size of the operating system's send buffer associated with + /// the socket. + pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + self.inner.set_send_buffer_size(size) + } + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the duration of time between them. + /// + /// For more information about this option, see [`set_keepalive`][link]. + /// + /// [link]: #method.set_keepalive + pub fn keepalive(&self) -> io::Result<Option<Duration>> { + self.inner.keepalive() + } + + /// Sets whether keepalive messages are enabled to be sent on this socket. + /// + /// On Unix, this option will set the `SO_KEEPALIVE` as well as the + /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). + /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. + /// + /// If `None` is specified then keepalive messages are disabled, otherwise + /// the duration specified will be the time to remain idle before sending a + /// TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second + /// specifications may be omitted. + pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { + self.inner.set_keepalive(keepalive) + } + + /// Check the value of the `SO_REUSEPORT` option on this socket. + /// + /// This function is only available on Unix when the `reuseport` feature is + /// enabled. + #[cfg(all(unix, feature = "reuseport"))] + pub fn reuse_port(&self) -> io::Result<bool> { + self.inner.reuse_port() + } + + /// Set value for the `SO_REUSEPORT` option on this socket. + /// + /// This indicates that futher calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + /// + /// This function is only available on Unix when the `reuseport` feature is + /// enabled. + #[cfg(all(unix, feature = "reuseport"))] + pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { + self.inner.set_reuse_port(reuse) + } +} + +impl Read for Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.read(buf) + } +} + +impl<'a> Read for &'a Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + (&self.inner).read(buf) + } +} + +impl Write for Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +impl<'a> Write for &'a Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + (&self.inner).write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + (&self.inner).flush() + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl From<net::TcpStream> for Socket { + fn from(socket: net::TcpStream) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +impl From<net::TcpListener> for Socket { + fn from(socket: net::TcpListener) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +impl From<net::UdpSocket> for Socket { + fn from(socket: net::UdpSocket) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixStream> for Socket { + fn from(socket: UnixStream) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixListener> for Socket { + fn from(socket: UnixListener) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixDatagram> for Socket { + fn from(socket: UnixDatagram) -> Socket { + Socket { + inner: socket.into(), + } + } +} + +impl From<Socket> for net::TcpStream { + fn from(socket: Socket) -> net::TcpStream { + socket.inner.into() + } +} + +impl From<Socket> for net::TcpListener { + fn from(socket: Socket) -> net::TcpListener { + socket.inner.into() + } +} + +impl From<Socket> for net::UdpSocket { + fn from(socket: Socket) -> net::UdpSocket { + socket.inner.into() + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixStream { + fn from(socket: Socket) -> UnixStream { + socket.inner.into() + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixListener { + fn from(socket: Socket) -> UnixListener { + socket.inner.into() + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixDatagram { + fn from(socket: Socket) -> UnixDatagram { + socket.inner.into() + } +} + +impl Domain { + /// Domain for IPv4 communication, corresponding to `AF_INET`. + pub fn ipv4() -> Domain { + Domain(c::AF_INET) + } + + /// Domain for IPv6 communication, corresponding to `AF_INET6`. + pub fn ipv6() -> Domain { + Domain(c::AF_INET6) + } + + /// Domain for Unix socket communication, corresponding to `AF_UNIX`. + /// + /// This function is only available on Unix when the `unix` feature is + /// activated. + #[cfg(all(unix, feature = "unix"))] + pub fn unix() -> Domain { + Domain(c::AF_UNIX) + } +} + +impl From<i32> for Domain { + fn from(a: i32) -> Domain { + Domain(a) + } +} + +impl From<Domain> for i32 { + fn from(a: Domain) -> i32 { + a.0 + } +} + +impl Type { + /// Type corresponding to `SOCK_STREAM` + /// + /// Used for protocols such as TCP. + pub fn stream() -> Type { + Type(c::SOCK_STREAM) + } + + /// Type corresponding to `SOCK_DGRAM` + /// + /// Used for protocols such as UDP. + pub fn dgram() -> Type { + Type(c::SOCK_DGRAM) + } + + /// Type corresponding to `SOCK_SEQPACKET` + pub fn seqpacket() -> Type { + Type(sys::SOCK_SEQPACKET) + } + + /// Type corresponding to `SOCK_RAW` + pub fn raw() -> Type { + Type(sys::SOCK_RAW) + } +} + +impl ::Protocol { + /// Protocol corresponding to `ICMPv4` + pub fn icmpv4() -> Self { + ::Protocol(sys::IPPROTO_ICMP) + } + + /// Protocol corresponding to `ICMPv6` + pub fn icmpv6() -> Self { + ::Protocol(sys::IPPROTO_ICMPV6) + } + + /// Protocol corresponding to `TCP` + pub fn tcp() -> Self { + ::Protocol(sys::IPPROTO_TCP) + } + + /// Protocol corresponding to `UDP` + pub fn udp() -> Self { + ::Protocol(sys::IPPROTO_UDP) + } +} + +impl From<i32> for Type { + fn from(a: i32) -> Type { + Type(a) + } +} + +impl From<Type> for i32 { + fn from(a: Type) -> i32 { + a.0 + } +} + +impl From<i32> for Protocol { + fn from(a: i32) -> Protocol { + Protocol(a) + } +} + +impl From<Protocol> for i32 { + fn from(a: Protocol) -> i32 { + a.0 + } +} + +#[cfg(test)] +mod test { + use std::net::SocketAddr; + + use super::*; + + #[test] + fn connect_timeout_unrouteable() { + // this IP is unroutable, so connections should always time out + let addr = "10.255.255.1:80".parse::<SocketAddr>().unwrap().into(); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + match socket.connect_timeout(&addr, Duration::from_millis(250)) { + Ok(_) => panic!("unexpected success"), + Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} + Err(e) => panic!("unexpected error {}", e), + } + } + + #[test] + fn connect_timeout_unbound() { + // bind and drop a socket to track down a "probably unassigned" port + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into(); + socket.bind(&addr).unwrap(); + let addr = socket.local_addr().unwrap(); + drop(socket); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + match socket.connect_timeout(&addr, Duration::from_millis(250)) { + Ok(_) => panic!("unexpected success"), + Err(ref e) + if e.kind() == io::ErrorKind::ConnectionRefused + || e.kind() == io::ErrorKind::TimedOut => {} + Err(e) => panic!("unexpected error {}", e), + } + } + + #[test] + fn connect_timeout_valid() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket + .bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into()) + .unwrap(); + socket.listen(128).unwrap(); + + let addr = socket.local_addr().unwrap(); + + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket + .connect_timeout(&addr, Duration::from_millis(250)) + .unwrap(); + } + + #[test] + #[cfg(all(unix, feature = "pair", feature = "unix"))] + fn pair() { + let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); + a.write_all(b"hello world").unwrap(); + let mut buf = [0; 11]; + b.read_exact(&mut buf).unwrap(); + assert_eq!(buf, &b"hello world"[..]); + } + + #[test] + #[cfg(all(unix, feature = "unix"))] + fn unix() { + use tempdir::TempDir; + + let dir = TempDir::new("unix").unwrap(); + let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); + + let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); + listener.bind(&addr).unwrap(); + listener.listen(10).unwrap(); + + let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); + a.connect(&addr).unwrap(); + + let mut b = listener.accept().unwrap().0; + + a.write_all(b"hello world").unwrap(); + let mut buf = [0; 11]; + b.read_exact(&mut buf).unwrap(); + assert_eq!(buf, &b"hello world"[..]); + } + + #[test] + fn keepalive() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); + // socket.keepalive() doesn't work on Windows #24 + #[cfg(unix)] + assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); + socket.set_keepalive(None).unwrap(); + #[cfg(unix)] + assert_eq!(socket.keepalive().unwrap(), None); + } + + #[test] + fn nodelay() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + + assert!(socket.set_nodelay(true).is_ok()); + + let result = socket.nodelay(); + + assert!(result.is_ok()); + assert!(result.unwrap()); + } +} diff --git a/socket2/src/sys/redox/mod.rs b/socket2/src/sys/redox/mod.rs new file mode 100644 index 000000000..3882fc991 --- /dev/null +++ b/socket2/src/sys/redox/mod.rs @@ -0,0 +1,832 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::fmt; +use std::io::{ErrorKind, Read, Write}; +use std::io; +use std::mem; +use std::net::Shutdown; +use std::net::{self, Ipv4Addr, Ipv6Addr}; +use std::ops::Neg; +use std::os::unix::prelude::*; +use std::time::Duration; +use syscall; +use std::fs::File; + +use libc::{self, c_uint, c_int, c_void, socklen_t, ssize_t}; + +use libc::IPV6_ADD_MEMBERSHIP; +use libc::IPV6_DROP_MEMBERSHIP; + +const MSG_NOSIGNAL: c_int = 0x0; + +use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + +use SockAddr; +use utils::One; + +pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; + +pub const IPPROTO_ICMP: i32 = -1; +pub const IPPROTO_ICMPV6: i32 = -1; +pub const IPPROTO_UDP: i32 = -1; +pub const SOCK_RAW: i32 = -1; +pub const SOCK_SEQPACKET: i32 = -1; + +pub struct Socket { + fd: c_int, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> { + if ty == -1 { + return Err(io::Error::new(ErrorKind::Other, "Type not implemented yet")); + } + if protocol == -1 { + return Err(io::Error::new(ErrorKind::Other, "Protocol not implemented yet")); + } + unsafe { + let fd = cvt(libc::socket(family, ty, protocol))?; + let fd = Socket::from_raw_fd(fd as RawFd); + set_cloexec(fd.as_raw_fd() as c_int)?; + Ok(fd) + } + } + + pub fn pair(_family: c_int, _ty: c_int, _protocol: c_int) -> io::Result<(Socket, Socket)> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) } + } + + pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) } + } + + pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new( + ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + if timeout.as_secs() > ::std::i64::MAX as u64 { + return Err(io::Error::new( + ErrorKind::InvalidInput, + "too large duration", + )); + } + + self.connect(addr)?; + + let mut event = File::open("event:")?; + let mut time = File::open("time:")?; + + event.write(&syscall::Event { + id: self.fd as usize, + flags: syscall::EVENT_WRITE, + data: 0 + })?; + + event.write(&syscall::Event { + id: time.as_raw_fd(), + flags: syscall::EVENT_WRITE, + data: 1 + })?; + + let mut current = syscall::TimeSpec::default(); + time.read(&mut current)?; + current.tv_sec += timeout.as_secs() as i64; + current.tv_nsec += timeout.subsec_nanos() as i32; + time.write(¤t)?; + + let mut out = syscall::Event::default(); + event.read(&mut out)?; + + if out.data == 1 { // the timeout we registered + return Err(io::Error::new( + ErrorKind::TimedOut, + "connection timed out", + )); + } + + Ok(()) + } + + pub fn local_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + cvt(libc::getsockname( + self.fd, + &mut storage as *mut _ as *mut _, + &mut len, + ))?; + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len, + )) + } + } + + pub fn peer_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + cvt(libc::getpeername( + self.fd, + &mut storage as *mut _ as *mut _, + &mut len + ))?; + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len as c_uint, + )) + } + } + + pub fn try_clone(&self) -> io::Result<Socket> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + #[allow(unused_mut)] + pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?; + if raw == 0 { + Ok(None) + } else { + Ok(Some(io::Error::from_raw_os_error(raw as i32))) + } + } + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; + let new = if nonblocking { + previous | libc::O_NONBLOCK + } else { + previous & !libc::O_NONBLOCK + }; + if new != previous { + cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; + } + Ok(()) + } + } + + pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::recv( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + 0, + ) + })?; + Ok(n as usize) + } + } + + pub fn peek(&self, _buf: &mut [u8]) -> io::Result<usize> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.recvfrom(buf, 0) + } + + pub fn peek_from(&self, _buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut addrlen = mem::size_of_val(&storage) as socklen_t; + + let n = cvt({ + libc::recvfrom( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + })?; + let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); + Ok((n as usize, addr)) + } + } + + pub fn send(&self, buf: &[u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::send( + self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len()), + MSG_NOSIGNAL, + ) + })?; + Ok(n as usize) + } + } + + pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::sendto( + self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len()), + MSG_NOSIGNAL, + addr.as_ptr(), + addr.len(), + ) + })?; + Ok(n as usize) + } + } + + // ================================================ + + pub fn ttl(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } + } + + pub fn unicast_hops_v6(&self) -> io::Result<u32> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn set_unicast_hops_v6(&self, _hops: u32) -> io::Result<()> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn only_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?; + Ok(raw != 0) + } + } + + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) } + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(timeval2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_RCVTIMEO, + )?)) + } + } + + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) } + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(timeval2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_SNDTIMEO, + )?)) + } + } + + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) } + } + + pub fn nodelay(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?; + Ok(raw != 0) + } + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } + } + + pub fn broadcast(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?; + Ok(raw != 0) + } + } + + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) } + } + + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, + multicast_loop_v4 as c_int, + ) + } + } + + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IP, + libc::IP_MULTICAST_TTL, + multicast_ttl_v4 as c_int, + ) + } + } + + pub fn multicast_hops_v6(&self) -> io::Result<u32> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn multicast_if_v6(&self) -> io::Result<u32> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> { + return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); + } + + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int, + ) + } + } + + pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = libc::ip_mreq { + imr_multiaddr: libc::in_addr { s_addr: multiaddr }, + imr_interface: libc::in_addr { s_addr: interface }, + }; + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) } + } + + pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = libc::ipv6_mreq { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = libc::ip_mreq { + imr_multiaddr: libc::in_addr { s_addr: multiaddr }, + imr_interface: libc::in_addr { s_addr: interface }, + }; + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = libc::ipv6_mreq { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } + } + + pub fn linger(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(linger2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_LINGER, + )?)) + } + } + + pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) } + } + + pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) } + } + + pub fn reuse_address(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?; + Ok(raw != 0) + } + } + + pub fn recv_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?; + Ok(raw as usize) + } + } + + pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int) + } + } + + pub fn send_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?; + Ok(raw as usize) + } + } + + pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int) + } + } + + pub fn keepalive(&self) -> io::Result<Option<Duration>> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?; + if raw == 0 { + return Ok(None); + } + let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?; + Ok(Some(Duration::new(secs as u64, 0))) + } + } + + pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::SOL_SOCKET, + libc::SO_KEEPALIVE, + keepalive.is_some() as c_int, + )?; + if let Some(dur) = keepalive { + // TODO: checked cast here + self.setsockopt( + libc::IPPROTO_TCP, + KEEPALIVE_OPTION, + dur.as_secs() as c_int, + )?; + } + Ok(()) + } + } + + unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> + where + T: Copy, + { + let payload = &payload as *const T as *const c_void; + cvt(libc::setsockopt( + self.fd, + opt, + val, + payload, + mem::size_of::<T>() as libc::socklen_t, + ))?; + Ok(()) + } + + unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::<T>() as libc::socklen_t; + cvt(libc::getsockopt( + self.fd, + opt, + val, + &mut slot as *mut _ as *mut _, + &mut len, + ))?; + assert_eq!(len as usize, mem::size_of::<T>()); + Ok(slot) + } +} + +impl Read for Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + <&Socket>::read(&mut &*self, buf) + } +} + +impl<'a> Read for &'a Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::read( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + ) + })?; + Ok(n as usize) + } + } +} + +impl Write for Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + <&Socket>::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + <&Socket>::flush(&mut &*self) + } +} + +impl<'a> Write for &'a Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.send(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Socket"); + f.field("fd", &self.fd); + if let Ok(addr) = self.local_addr() { + f.field("local_addr", &addr); + } + if let Ok(addr) = self.peer_addr() { + f.field("peer_addr", &addr); + } + f.finish() + } +} + +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.fd as RawFd + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + let fd = self.fd as RawFd; + mem::forget(self); + return fd; + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(fd: RawFd) -> Socket { + Socket { fd: fd as c_int } + } +} + +impl AsRawFd for ::Socket { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +impl IntoRawFd for ::Socket { + fn into_raw_fd(self) -> RawFd { + self.inner.into_raw_fd() + } +} + +impl FromRawFd for ::Socket { + unsafe fn from_raw_fd(fd: RawFd) -> ::Socket { + ::Socket { + inner: Socket::from_raw_fd(fd), + } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} + +impl From<Socket> for net::TcpStream { + fn from(socket: Socket) -> net::TcpStream { + unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<Socket> for net::TcpListener { + fn from(socket: Socket) -> net::TcpListener { + unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<Socket> for net::UdpSocket { + fn from(socket: Socket) -> net::UdpSocket { + unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::TcpStream> for Socket { + fn from(socket: net::TcpStream) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::TcpListener> for Socket { + fn from(socket: net::TcpListener) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::UdpSocket> for Socket { + fn from(socket: net::UdpSocket) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +fn max_len() -> usize { + // The maximum read limit on most posix-like systems is `SSIZE_MAX`, + // with the man page quoting that if the count of bytes to read is + // greater than `SSIZE_MAX` the result is "unspecified". + <ssize_t>::max_value() as usize +} + +fn cvt<T: One + PartialEq + Neg<Output = T>>(t: T) -> io::Result<T> { + let one: T = T::one(); + if t == -one { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +fn set_cloexec(fd: c_int) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; + let new = previous | syscall::O_CLOEXEC as i32; + if new != previous { + cvt(libc::fcntl(fd, libc::F_SETFD, new))?; + } + Ok(()) + } +} + +fn dur2timeval(dur: Option<Duration>) -> io::Result<libc::timeval> { + match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::new( + ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + + let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { + libc::time_t::max_value() + } else { + dur.as_secs() as libc::time_t + }; + let mut timeout = libc::timeval { + tv_sec: secs, + tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + Ok(timeout) + } + None => Ok(libc::timeval { + tv_sec: 0, + tv_usec: 0, + }), + } +} + +fn timeval2dur(raw: libc::timeval) -> Option<Duration> { + if raw.tv_sec == 0 && raw.tv_usec == 0 { + None + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Some(Duration::new(sec, nsec)) + } +} + +fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { + let octets = addr.octets(); + ::hton( + ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) + | ((octets[2] as libc::in_addr_t) << 8) | ((octets[3] as libc::in_addr_t) << 0), + ) +} + +fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr { + let mut ret: libc::in6_addr = unsafe { mem::zeroed() }; + ret.s6_addr = addr.octets(); + return ret; +} + +fn to_ipv6mr_interface(value: u32) -> libc::c_uint { + value as libc::c_uint +} + +fn linger2dur(linger_opt: libc::linger) -> Option<Duration> { + if linger_opt.l_onoff == 0 { + None + } else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +fn dur2linger(dur: Option<Duration>) -> libc::linger { + match dur { + Some(d) => libc::linger { + l_onoff: 1, + l_linger: d.as_secs() as c_int, + }, + None => libc::linger { + l_onoff: 0, + l_linger: 0, + }, + } +} + +#[test] +fn test_ip() { + let ip = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(ip, from_s_addr(to_s_addr(&ip))); +} diff --git a/socket2/src/sys/unix/mod.rs b/socket2/src/sys/unix/mod.rs new file mode 100644 index 000000000..96e01b782 --- /dev/null +++ b/socket2/src/sys/unix/mod.rs @@ -0,0 +1,1116 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::fmt; +use std::io::{ErrorKind, Read, Write}; +use std::io; +use std::mem; +use std::net::Shutdown; +use std::net::{self, Ipv4Addr, Ipv6Addr}; +use std::ops::Neg; +use std::os::unix::prelude::*; +use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; +use std::time::{Duration, Instant}; +#[cfg(feature = "unix")] +use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; + +use libc::{self, c_int, c_void, socklen_t, ssize_t}; + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", + target_os = "ios", target_os = "macos", + target_os = "openbsd", target_os = "netbsd", + target_os = "solaris", target_os = "haiku"))] { + use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + } else { + use libc::IPV6_ADD_MEMBERSHIP; + use libc::IPV6_DROP_MEMBERSHIP; + } +} + +cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig"))] { + use libc::MSG_NOSIGNAL; + } else { + const MSG_NOSIGNAL: c_int = 0x0; + } +} + +cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] { + use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; + } else { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } +} + +use SockAddr; +use utils::One; + +pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; +pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; +pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; +pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP; +pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; +pub const SOCK_RAW: i32 = libc::SOCK_RAW; + +#[macro_use] +#[cfg(target_os = "linux")] +mod weak; + +pub struct Socket { + fd: c_int, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> { + unsafe { + // On linux we first attempt to pass the SOCK_CLOEXEC flag to + // atomically create the socket and set it as CLOEXEC. Support for + // this option, however, was added in 2.6.27, and we still support + // 2.6.18 as a kernel, so if the returned error is EINVAL we + // fallthrough to the fallback. + #[cfg(target_os = "linux")] + { + match cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, protocol)) { + Ok(fd) => return Ok(Socket::from_raw_fd(fd)), + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} + Err(e) => return Err(e), + } + } + + let fd = cvt(libc::socket(family, ty, protocol))?; + let fd = Socket::from_raw_fd(fd); + set_cloexec(fd.as_raw_fd())?; + #[cfg(target_os = "macos")] + { + fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; + } + Ok(fd) + } + } + + pub fn pair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<(Socket, Socket)> { + unsafe { + let mut fds = [0, 0]; + cvt(libc::socketpair(family, ty, protocol, fds.as_mut_ptr()))?; + let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1])); + set_cloexec(fds.0.as_raw_fd())?; + set_cloexec(fds.1.as_raw_fd())?; + #[cfg(target_os = "macos")] + { + fds.0 + .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; + fds.1 + .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; + } + Ok(fds) + } + } + + pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) } + } + + pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) } + } + + pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = self.connect(addr); + self.set_nonblocking(false)?; + + match r { + Ok(()) => return Ok(()), + // there's no io::ErrorKind conversion registered for EINPROGRESS :( + Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} + Err(e) => return Err(e), + } + + let mut pollfd = libc::pollfd { + fd: self.fd, + events: libc::POLLOUT, + revents: 0, + }; + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + + let start = Instant::now(); + + loop { + let elapsed = start.elapsed(); + if elapsed >= timeout { + return Err(io::Error::new( + io::ErrorKind::TimedOut, + "connection timed out", + )); + } + + let timeout = timeout - elapsed; + let mut timeout = timeout + .as_secs() + .saturating_mul(1_000) + .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); + if timeout == 0 { + timeout = 1; + } + + let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; + + match unsafe { libc::poll(&mut pollfd, 1, timeout) } { + -1 => { + let err = io::Error::last_os_error(); + if err.kind() != io::ErrorKind::Interrupted { + return Err(err); + } + } + 0 => { + return Err(io::Error::new( + io::ErrorKind::TimedOut, + "connection timed out", + )) + } + _ => { + // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look + // for POLLHUP rather than read readiness + if pollfd.revents & libc::POLLHUP != 0 { + let e = self.take_error()?.unwrap_or_else(|| { + io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") + }); + return Err(e); + } + return Ok(()); + } + } + } + } + + pub fn local_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + cvt(libc::getsockname( + self.fd, + &mut storage as *mut _ as *mut _, + &mut len, + ))?; + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len, + )) + } + } + + pub fn peer_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + cvt(libc::getpeername( + self.fd, + &mut storage as *mut _ as *mut _, + &mut len, + ))?; + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len, + )) + } + } + + pub fn try_clone(&self) -> io::Result<Socket> { + // implementation lifted from libstd + #[cfg(any(target_os = "android", target_os = "haiku"))] + use libc::F_DUPFD as F_DUPFD_CLOEXEC; + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + use libc::F_DUPFD_CLOEXEC; + + static CLOEXEC_FAILED: AtomicBool = ATOMIC_BOOL_INIT; + unsafe { + if !CLOEXEC_FAILED.load(Ordering::Relaxed) { + match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) { + Ok(fd) => { + let fd = Socket::from_raw_fd(fd); + if cfg!(target_os = "linux") { + set_cloexec(fd.as_raw_fd())?; + } + return Ok(fd); + } + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { + CLOEXEC_FAILED.store(true, Ordering::Relaxed); + } + Err(e) => return Err(e), + } + } + let fd = cvt(libc::fcntl(self.fd, libc::F_DUPFD, 0))?; + let fd = Socket::from_raw_fd(fd); + set_cloexec(fd.as_raw_fd())?; + Ok(fd) + } + } + + #[allow(unused_mut)] + pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { + let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as socklen_t; + + let mut socket = None; + #[cfg(target_os = "linux")] + { + weak! { + fn accept4(c_int, *mut libc::sockaddr, *mut socklen_t, c_int) -> c_int + } + if let Some(f) = accept4.get() { + let res = cvt_r(|| unsafe { + f( + self.fd, + &mut storage as *mut _ as *mut _, + &mut len, + libc::SOCK_CLOEXEC, + ) + }); + match res { + Ok(fd) => socket = Some(Socket { fd: fd }), + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} + Err(e) => return Err(e), + } + } + } + + let socket = match socket { + Some(socket) => socket, + None => unsafe { + let fd = + cvt_r(|| libc::accept(self.fd, &mut storage as *mut _ as *mut _, &mut len))?; + let fd = Socket::from_raw_fd(fd); + set_cloexec(fd.as_raw_fd())?; + fd + }, + }; + let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, len) }; + Ok((socket, addr)) + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?; + if raw == 0 { + Ok(None) + } else { + Ok(Some(io::Error::from_raw_os_error(raw as i32))) + } + } + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; + let new = if nonblocking { + previous | libc::O_NONBLOCK + } else { + previous & !libc::O_NONBLOCK + }; + if new != previous { + cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; + } + Ok(()) + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => libc::SHUT_WR, + Shutdown::Read => libc::SHUT_RD, + Shutdown::Both => libc::SHUT_RDWR, + }; + cvt(unsafe { libc::shutdown(self.fd, how) })?; + Ok(()) + } + + pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::recv( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + 0, + ) + })?; + Ok(n as usize) + } + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::recv( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + libc::MSG_PEEK, + ) + })?; + Ok(n as usize) + } + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.recvfrom(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.recvfrom(buf, libc::MSG_PEEK) + } + + fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { + unsafe { + let mut storage: libc::sockaddr_storage = mem::zeroed(); + let mut addrlen = mem::size_of_val(&storage) as socklen_t; + + let n = cvt({ + libc::recvfrom( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + })?; + let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); + Ok((n as usize, addr)) + } + } + + pub fn send(&self, buf: &[u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::send( + self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len()), + MSG_NOSIGNAL, + ) + })?; + Ok(n as usize) + } + } + + pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::sendto( + self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), max_len()), + MSG_NOSIGNAL, + addr.as_ptr(), + addr.len(), + ) + })?; + Ok(n as usize) + } + } + + // ================================================ + + pub fn ttl(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } + } + + pub fn unicast_hops_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; + Ok(raw as u32) + } + } + + pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IPV6 as c_int, + libc::IPV6_UNICAST_HOPS, + hops as c_int, + ) + } + } + + pub fn only_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?; + Ok(raw != 0) + } + } + + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) } + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(timeval2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_RCVTIMEO, + )?)) + } + } + + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) } + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(timeval2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_SNDTIMEO, + )?)) + } + } + + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) } + } + + pub fn nodelay(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?; + Ok(raw != 0) + } + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } + } + + pub fn broadcast(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?; + Ok(raw != 0) + } + } + + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) } + } + + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IP, + libc::IP_MULTICAST_LOOP, + multicast_loop_v4 as c_int, + ) + } + } + + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IP, + libc::IP_MULTICAST_TTL, + multicast_ttl_v4 as c_int, + ) + } + } + + pub fn multicast_hops_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS, hops as c_int) } + } + + pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { + unsafe { + let imr_interface: libc::in_addr = + self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF)?; + Ok(from_s_addr(imr_interface.s_addr)) + } + } + + pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { + let interface = to_s_addr(interface); + let imr_interface = libc::in_addr { s_addr: interface }; + + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF, imr_interface) } + } + + pub fn multicast_if_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_IF, + interface as c_int, + ) + } + } + + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int, + ) + } + } + + pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = libc::ip_mreq { + imr_multiaddr: libc::in_addr { s_addr: multiaddr }, + imr_interface: libc::in_addr { s_addr: interface }, + }; + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) } + } + + pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = libc::ipv6_mreq { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = libc::ip_mreq { + imr_multiaddr: libc::in_addr { s_addr: multiaddr }, + imr_interface: libc::in_addr { s_addr: interface }, + }; + unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = libc::ipv6_mreq { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } + } + + pub fn linger(&self) -> io::Result<Option<Duration>> { + unsafe { + Ok(linger2dur(self.getsockopt( + libc::SOL_SOCKET, + libc::SO_LINGER, + )?)) + } + } + + pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) } + } + + pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) } + } + + pub fn reuse_address(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?; + Ok(raw != 0) + } + } + + pub fn recv_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?; + Ok(raw as usize) + } + } + + pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int) + } + } + + pub fn send_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?; + Ok(raw as usize) + } + } + + pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int) + } + } + + pub fn keepalive(&self) -> io::Result<Option<Duration>> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?; + if raw == 0 { + return Ok(None); + } + let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?; + Ok(Some(Duration::new(secs as u64, 0))) + } + } + + pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { + unsafe { + self.setsockopt( + libc::SOL_SOCKET, + libc::SO_KEEPALIVE, + keepalive.is_some() as c_int, + )?; + if let Some(dur) = keepalive { + // TODO: checked cast here + self.setsockopt( + libc::IPPROTO_TCP, + KEEPALIVE_OPTION, + dur.as_secs() as c_int, + )?; + } + Ok(()) + } + } + + #[cfg(all(unix, feature = "reuseport"))] + pub fn reuse_port(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; + Ok(raw != 0) + } + } + + #[cfg(all(unix, feature = "reuseport"))] + pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } + } + + unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> + where + T: Copy, + { + let payload = &payload as *const T as *const c_void; + cvt(libc::setsockopt( + self.fd, + opt, + val, + payload, + mem::size_of::<T>() as libc::socklen_t, + ))?; + Ok(()) + } + + unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::<T>() as libc::socklen_t; + cvt(libc::getsockopt( + self.fd, + opt, + val, + &mut slot as *mut _ as *mut _, + &mut len, + ))?; + assert_eq!(len as usize, mem::size_of::<T>()); + Ok(slot) + } +} + +impl Read for Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + <&Socket>::read(&mut &*self, buf) + } +} + +impl<'a> Read for &'a Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = cvt({ + libc::read( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), max_len()), + ) + })?; + Ok(n as usize) + } + } +} + +impl Write for Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + <&Socket>::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + <&Socket>::flush(&mut &*self) + } +} + +impl<'a> Write for &'a Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.send(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Socket"); + f.field("fd", &self.fd); + if let Ok(addr) = self.local_addr() { + f.field("local_addr", &addr); + } + if let Ok(addr) = self.peer_addr() { + f.field("peer_addr", &addr); + } + f.finish() + } +} + +impl AsRawFd for Socket { + fn as_raw_fd(&self) -> c_int { + self.fd + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + return fd; + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(fd: c_int) -> Socket { + Socket { fd: fd } + } +} + +impl AsRawFd for ::Socket { + fn as_raw_fd(&self) -> c_int { + self.inner.as_raw_fd() + } +} + +impl IntoRawFd for ::Socket { + fn into_raw_fd(self) -> c_int { + self.inner.into_raw_fd() + } +} + +impl FromRawFd for ::Socket { + unsafe fn from_raw_fd(fd: c_int) -> ::Socket { + ::Socket { + inner: Socket::from_raw_fd(fd), + } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} + +impl From<Socket> for net::TcpStream { + fn from(socket: Socket) -> net::TcpStream { + unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<Socket> for net::TcpListener { + fn from(socket: Socket) -> net::TcpListener { + unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<Socket> for net::UdpSocket { + fn from(socket: Socket) -> net::UdpSocket { + unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixStream { + fn from(socket: Socket) -> UnixStream { + unsafe { UnixStream::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixListener { + fn from(socket: Socket) -> UnixListener { + unsafe { UnixListener::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<Socket> for UnixDatagram { + fn from(socket: Socket) -> UnixDatagram { + unsafe { UnixDatagram::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::TcpStream> for Socket { + fn from(socket: net::TcpStream) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::TcpListener> for Socket { + fn from(socket: net::TcpListener) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +impl From<net::UdpSocket> for Socket { + fn from(socket: net::UdpSocket) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixStream> for Socket { + fn from(socket: UnixStream) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixListener> for Socket { + fn from(socket: UnixListener) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +#[cfg(all(unix, feature = "unix"))] +impl From<UnixDatagram> for Socket { + fn from(socket: UnixDatagram) -> Socket { + unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } + } +} + +fn max_len() -> usize { + // The maximum read limit on most posix-like systems is `SSIZE_MAX`, + // with the man page quoting that if the count of bytes to read is + // greater than `SSIZE_MAX` the result is "unspecified". + // + // On macOS, however, apparently the 64-bit libc is either buggy or + // intentionally showing odd behavior by rejecting any read with a size + // larger than or equal to INT_MAX. To handle both of these the read + // size is capped on both platforms. + if cfg!(target_os = "macos") { + <c_int>::max_value() as usize - 1 + } else { + <ssize_t>::max_value() as usize + } +} + +fn cvt<T: One + PartialEq + Neg<Output = T>>(t: T) -> io::Result<T> { + let one: T = T::one(); + if t == -one { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +fn cvt_r<F, T>(mut f: F) -> io::Result<T> +where + F: FnMut() -> T, + T: One + PartialEq + Neg<Output = T>, +{ + loop { + match cvt(f()) { + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + other => return other, + } + } +} + +fn set_cloexec(fd: c_int) -> io::Result<()> { + unsafe { + let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; + let new = previous | libc::FD_CLOEXEC; + if new != previous { + cvt(libc::fcntl(fd, libc::F_SETFD, new))?; + } + Ok(()) + } +} + +fn dur2timeval(dur: Option<Duration>) -> io::Result<libc::timeval> { + match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + + let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { + libc::time_t::max_value() + } else { + dur.as_secs() as libc::time_t + }; + let mut timeout = libc::timeval { + tv_sec: secs, + tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + Ok(timeout) + } + None => Ok(libc::timeval { + tv_sec: 0, + tv_usec: 0, + }), + } +} + +fn timeval2dur(raw: libc::timeval) -> Option<Duration> { + if raw.tv_sec == 0 && raw.tv_usec == 0 { + None + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Some(Duration::new(sec, nsec)) + } +} + +fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { + let octets = addr.octets(); + ::hton( + ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) + | ((octets[2] as libc::in_addr_t) << 8) | ((octets[3] as libc::in_addr_t) << 0), + ) +} + +fn from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr { + let h_addr = ::ntoh(in_addr); + + let a: u8 = (h_addr >> 24) as u8; + let b: u8 = (h_addr >> 16) as u8; + let c: u8 = (h_addr >> 8) as u8; + let d: u8 = (h_addr >> 0) as u8; + + Ipv4Addr::new(a, b, c, d) +} + +fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr { + let mut ret: libc::in6_addr = unsafe { mem::zeroed() }; + ret.s6_addr = addr.octets(); + return ret; +} + +#[cfg(target_os = "android")] +fn to_ipv6mr_interface(value: u32) -> c_int { + value as c_int +} + +#[cfg(not(target_os = "android"))] +fn to_ipv6mr_interface(value: u32) -> libc::c_uint { + value as libc::c_uint +} + +fn linger2dur(linger_opt: libc::linger) -> Option<Duration> { + if linger_opt.l_onoff == 0 { + None + } else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +fn dur2linger(dur: Option<Duration>) -> libc::linger { + match dur { + Some(d) => libc::linger { + l_onoff: 1, + l_linger: d.as_secs() as c_int, + }, + None => libc::linger { + l_onoff: 0, + l_linger: 0, + }, + } +} + +#[test] +fn test_ip() { + let ip = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(ip, from_s_addr(to_s_addr(&ip))); +} diff --git a/socket2/src/sys/unix/weak.rs b/socket2/src/sys/unix/weak.rs new file mode 100644 index 000000000..6767a0f9c --- /dev/null +++ b/socket2/src/sys/unix/weak.rs @@ -0,0 +1,59 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker; +use std::mem; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use libc; + +macro_rules! weak { + (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + #[allow(bad_style)] + static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> = + ::sys::weak::Weak { + name: concat!(stringify!($name), "\0"), + addr: ::std::sync::atomic::ATOMIC_USIZE_INIT, + _marker: ::std::marker::PhantomData, + }; + ) +} + +pub struct Weak<F> { + pub name: &'static str, + pub addr: AtomicUsize, + pub _marker: marker::PhantomData<F>, +} + +impl<F> Weak<F> { + pub fn get(&self) -> Option<&F> { + assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); + unsafe { + if self.addr.load(Ordering::SeqCst) == 0 { + let ptr = match fetch(self.name) { + 1 => 1, + n => n, + }; + self.addr.store(ptr, Ordering::SeqCst); + } + if self.addr.load(Ordering::SeqCst) == 0 { + None + } else { + mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) + } + } + } +} + +unsafe fn fetch(name: &str) -> usize { + let name = name.as_bytes(); + assert_eq!(name[name.len() - 1], 0); + libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize +} diff --git a/socket2/src/sys/windows.rs b/socket2/src/sys/windows.rs new file mode 100644 index 000000000..eb9329f21 --- /dev/null +++ b/socket2/src/sys/windows.rs @@ -0,0 +1,974 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::fmt; +use std::io::{Read, Write}; +use std::io; +use std::mem; +use std::net::Shutdown; +use std::net::{self, Ipv4Addr, Ipv6Addr}; +use std::os::windows::prelude::*; +use std::ptr; +use std::sync::{Once, ONCE_INIT}; +use std::time::Duration; + +use winapi::ctypes::{c_char, c_int, c_long, c_ulong}; +use winapi::shared::inaddr::*; +use winapi::shared::in6addr::*; +use winapi::shared::minwindef::DWORD; +use winapi::shared::ntdef::{HANDLE, ULONG}; +use winapi::shared::ws2def::*; +use winapi::shared::ws2def; +use winapi::shared::ws2ipdef::*; +use winapi::um::handleapi::SetHandleInformation; +use winapi::um::processthreadsapi::GetCurrentProcessId; +use winapi::um::winbase::INFINITE; +use winapi::um::winsock2 as sock; + +use SockAddr; + +const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; +const MSG_PEEK: c_int = 0x2; +const SD_BOTH: c_int = 2; +const SD_RECEIVE: c_int = 0; +const SD_SEND: c_int = 1; +const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; +const WSA_FLAG_OVERLAPPED: DWORD = 0x01; + +pub const IPPROTO_ICMP: i32 = ws2def::IPPROTO_ICMP as i32; +pub const IPPROTO_ICMPV6: i32 = ws2def::IPPROTO_ICMPV6 as i32; +pub const IPPROTO_TCP: i32 = ws2def::IPPROTO_TCP as i32; +pub const IPPROTO_UDP: i32 = ws2def::IPPROTO_UDP as i32; +pub const SOCK_SEQPACKET: i32 = ws2def::SOCK_SEQPACKET as i32; +pub const SOCK_RAW: i32 = ws2def::SOCK_RAW as i32; + +#[repr(C)] +struct tcp_keepalive { + onoff: c_ulong, + keepalivetime: c_ulong, + keepaliveinterval: c_ulong, +} + +fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + // Initialize winsock through the standard library by just creating a + // dummy socket. Whether this is successful or not we drop the result as + // libstd will be sure to have initialized winsock. + let _ = net::UdpSocket::bind("127.0.0.1:34254"); + }); +} + +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { sock::WSAGetLastError() }) +} + +pub struct Socket { + socket: sock::SOCKET, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result<Socket> { + init(); + unsafe { + let socket = match sock::WSASocketW( + family, + ty, + protocol, + ptr::null_mut(), + 0, + WSA_FLAG_OVERLAPPED, + ) { + sock::INVALID_SOCKET => return Err(last_error()), + socket => socket, + }; + let socket = Socket::from_raw_socket(socket as RawSocket); + socket.set_no_inherit()?; + Ok(socket) + } + } + + pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { + if sock::bind(self.socket, addr.as_ptr(), addr.len()) == 0 { + Ok(()) + } else { + Err(last_error()) + } + } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { + if sock::listen(self.socket, backlog) == 0 { + Ok(()) + } else { + Err(last_error()) + } + } + } + + pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { + unsafe { + if sock::connect(self.socket, addr.as_ptr(), addr.len()) == 0 { + Ok(()) + } else { + Err(last_error()) + } + } + } + + pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = self.connect(addr); + self.set_nonblocking(false)?; + + match r { + Ok(()) => return Ok(()), + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} + Err(e) => return Err(e), + } + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + + let mut timeout = sock::timeval { + tv_sec: timeout.as_secs() as c_long, + tv_usec: (timeout.subsec_nanos() / 1000) as c_long, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + + let fds = unsafe { + let mut fds = mem::zeroed::<sock::fd_set>(); + fds.fd_count = 1; + fds.fd_array[0] = self.socket; + fds + }; + + let mut writefds = fds; + let mut errorfds = fds; + + match unsafe { sock::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) } { + sock::SOCKET_ERROR => return Err(io::Error::last_os_error()), + 0 => { + return Err(io::Error::new( + io::ErrorKind::TimedOut, + "connection timed out", + )) + } + _ => { + if writefds.fd_count != 1 { + if let Some(e) = self.take_error()? { + return Err(e); + } + } + Ok(()) + } + } + } + + pub fn local_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: SOCKADDR_STORAGE = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c_int; + if sock::getsockname(self.socket, &mut storage as *mut _ as *mut _, &mut len) != 0 { + return Err(last_error()); + } + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len, + )) + } + } + + pub fn peer_addr(&self) -> io::Result<SockAddr> { + unsafe { + let mut storage: SOCKADDR_STORAGE = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c_int; + if sock::getpeername(self.socket, &mut storage as *mut _ as *mut _, &mut len) != 0 { + return Err(last_error()); + } + Ok(SockAddr::from_raw_parts( + &storage as *const _ as *const _, + len, + )) + } + } + + pub fn try_clone(&self) -> io::Result<Socket> { + unsafe { + let mut info: sock::WSAPROTOCOL_INFOW = mem::zeroed(); + let r = sock::WSADuplicateSocketW(self.socket, GetCurrentProcessId(), &mut info); + if r != 0 { + return Err(io::Error::last_os_error()); + } + let socket = sock::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + WSA_FLAG_OVERLAPPED, + ); + let socket = match socket { + sock::INVALID_SOCKET => return Err(last_error()), + n => Socket::from_raw_socket(n as RawSocket), + }; + socket.set_no_inherit()?; + Ok(socket) + } + } + + pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { + unsafe { + let mut storage: SOCKADDR_STORAGE = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c_int; + let socket = { sock::accept(self.socket, &mut storage as *mut _ as *mut _, &mut len) }; + let socket = match socket { + sock::INVALID_SOCKET => return Err(last_error()), + socket => Socket::from_raw_socket(socket as RawSocket), + }; + socket.set_no_inherit()?; + let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, len); + Ok((socket, addr)) + } + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_ERROR)?; + if raw == 0 { + Ok(None) + } else { + Ok(Some(io::Error::from_raw_os_error(raw as i32))) + } + } + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + unsafe { + let mut nonblocking = nonblocking as c_ulong; + let r = sock::ioctlsocket(self.socket, sock::FIONBIO as c_int, &mut nonblocking); + if r == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => SD_SEND, + Shutdown::Read => SD_RECEIVE, + Shutdown::Both => SD_BOTH, + }; + if unsafe { sock::shutdown(self.socket, how) == 0 } { + Ok(()) + } else { + Err(last_error()) + } + } + + pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = { + sock::recv( + self.socket, + buf.as_mut_ptr() as *mut c_char, + clamp(buf.len()), + 0, + ) + }; + match n { + sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => Ok(0), + sock::SOCKET_ERROR => Err(last_error()), + n => Ok(n as usize), + } + } + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + let n = { + sock::recv( + self.socket, + buf.as_mut_ptr() as *mut c_char, + clamp(buf.len()), + MSG_PEEK, + ) + }; + match n { + sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => Ok(0), + sock::SOCKET_ERROR => Err(last_error()), + n => Ok(n as usize), + } + } + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.recvfrom(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { + self.recvfrom(buf, MSG_PEEK) + } + + fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { + unsafe { + let mut storage: SOCKADDR_STORAGE = mem::zeroed(); + let mut addrlen = mem::size_of_val(&storage) as c_int; + + let n = { + sock::recvfrom( + self.socket, + buf.as_mut_ptr() as *mut c_char, + clamp(buf.len()), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + }; + let n = match n { + sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => 0, + sock::SOCKET_ERROR => return Err(last_error()), + n => n as usize, + }; + let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); + Ok((n, addr)) + } + } + + pub fn send(&self, buf: &[u8]) -> io::Result<usize> { + unsafe { + let n = { + sock::send( + self.socket, + buf.as_ptr() as *const c_char, + clamp(buf.len()), + 0, + ) + }; + if n == sock::SOCKET_ERROR { + Err(last_error()) + } else { + Ok(n as usize) + } + } + } + + pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> { + unsafe { + let n = { + sock::sendto( + self.socket, + buf.as_ptr() as *const c_char, + clamp(buf.len()), + 0, + addr.as_ptr(), + addr.len(), + ) + }; + if n == sock::SOCKET_ERROR { + Err(last_error()) + } else { + Ok(n as usize) + } + } + } + + // ================================================ + + pub fn ttl(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IP, IP_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IP, IP_TTL, ttl as c_int) } + } + + pub fn unicast_hops_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_UNICAST_HOPS)?; + Ok(raw as u32) + } + } + + pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_UNICAST_HOPS, hops as c_int) } + } + + pub fn only_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_V6ONLY)?; + Ok(raw != 0) + } + } + + pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_V6ONLY, only_v6 as c_int) } + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { Ok(ms2dur(self.getsockopt(SOL_SOCKET, SO_RCVTIMEO)?)) } + } + + pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_RCVTIMEO, dur2ms(dur)?) } + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + unsafe { Ok(ms2dur(self.getsockopt(SOL_SOCKET, SO_SNDTIMEO)?)) } + } + + pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_SNDTIMEO, dur2ms(dur)?) } + } + + pub fn nodelay(&self) -> io::Result<bool> { + unsafe { + let raw: c_char = self.getsockopt(IPPROTO_TCP, TCP_NODELAY)?; + Ok(raw != 0) + } + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_TCP, TCP_NODELAY, nodelay as c_char) } + } + + pub fn broadcast(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_BROADCAST)?; + Ok(raw != 0) + } + } + + pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_BROADCAST, broadcast as c_int) } + } + + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IP, IP_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) } + } + + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IP, IP_MULTICAST_TTL)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) } + } + + pub fn multicast_hops_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_HOPS)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_HOPS, hops as c_int) } + } + + pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { + unsafe { + let imr_interface: IN_ADDR = self.getsockopt(IPPROTO_IP, IP_MULTICAST_IF)?; + Ok(from_s_addr(imr_interface.S_un)) + } + } + + pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { + let interface = to_s_addr(interface); + let imr_interface = IN_ADDR { S_un: interface }; + + unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_IF, imr_interface) } + } + + pub fn multicast_if_v6(&self) -> io::Result<u32> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_IF)?; + Ok(raw as u32) + } + } + + pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { + unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_IF, interface as c_int) } + } + + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_LOOP)?; + Ok(raw != 0) + } + } + + pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + unsafe { + self.setsockopt( + IPPROTO_IPV6 as c_int, + IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int, + ) + } + } + + pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = IP_MREQ { + imr_multiaddr: IN_ADDR { S_un: multiaddr }, + imr_interface: IN_ADDR { S_un: interface }, + }; + unsafe { self.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq) } + } + + pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = IPV6_MREQ { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: interface, + }; + unsafe { self.setsockopt(IPPROTO_IP, IPV6_ADD_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { + let multiaddr = to_s_addr(multiaddr); + let interface = to_s_addr(interface); + let mreq = IP_MREQ { + imr_multiaddr: IN_ADDR { S_un: multiaddr }, + imr_interface: IN_ADDR { S_un: interface }, + }; + unsafe { self.setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) } + } + + pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { + let multiaddr = to_in6_addr(multiaddr); + let mreq = IPV6_MREQ { + ipv6mr_multiaddr: multiaddr, + ipv6mr_interface: interface, + }; + unsafe { self.setsockopt(IPPROTO_IP, IPV6_DROP_MEMBERSHIP, mreq) } + } + + pub fn linger(&self) -> io::Result<Option<Duration>> { + unsafe { Ok(linger2dur(self.getsockopt(SOL_SOCKET, SO_LINGER)?)) } + } + + pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_LINGER, dur2linger(dur)) } + } + + pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_REUSEADDR, reuse as c_int) } + } + + pub fn reuse_address(&self) -> io::Result<bool> { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_REUSEADDR)?; + Ok(raw != 0) + } + } + + pub fn recv_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_RCVBUF)?; + Ok(raw as usize) + } + } + + pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(SOL_SOCKET, SO_RCVBUF, size as c_int) + } + } + + pub fn send_buffer_size(&self) -> io::Result<usize> { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_SNDBUF)?; + Ok(raw as usize) + } + } + + pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + unsafe { + // TODO: casting usize to a c_int should be a checked cast + self.setsockopt(SOL_SOCKET, SO_SNDBUF, size as c_int) + } + } + + pub fn keepalive(&self) -> io::Result<Option<Duration>> { + let mut ka = tcp_keepalive { + onoff: 0, + keepalivetime: 0, + keepaliveinterval: 0, + }; + let n = unsafe { + sock::WSAIoctl( + self.socket, + SIO_KEEPALIVE_VALS, + 0 as *mut _, + 0, + &mut ka as *mut _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0 as *mut _, + None, + ) + }; + if n == 0 { + Ok(if ka.onoff == 0 { + None + } else if ka.keepaliveinterval == 0 { + None + } else { + let seconds = ka.keepaliveinterval / 1000; + let nanos = (ka.keepaliveinterval % 1000) * 1_000_000; + Some(Duration::new(seconds as u64, nanos as u32)) + }) + } else { + Err(last_error()) + } + } + + pub fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { + let ms = dur2ms(keepalive)?; + // TODO: checked casts here + let ka = tcp_keepalive { + onoff: keepalive.is_some() as c_ulong, + keepalivetime: ms as c_ulong, + keepaliveinterval: ms as c_ulong, + }; + let mut out = 0; + let n = unsafe { + sock::WSAIoctl( + self.socket, + SIO_KEEPALIVE_VALS, + &ka as *const _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0, + &mut out, + 0 as *mut _, + None, + ) + }; + if n == 0 { + Ok(()) + } else { + Err(last_error()) + } + } + + unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> + where + T: Copy, + { + let payload = &payload as *const T as *const c_char; + if sock::setsockopt(self.socket, opt, val, payload, mem::size_of::<T>() as c_int) == 0 { + Ok(()) + } else { + Err(last_error()) + } + } + + unsafe fn getsockopt<T: Copy>(&self, opt: c_int, val: c_int) -> io::Result<T> { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::<T>() as c_int; + if sock::getsockopt( + self.socket, + opt, + val, + &mut slot as *mut _ as *mut _, + &mut len, + ) == 0 + { + assert_eq!(len as usize, mem::size_of::<T>()); + Ok(slot) + } else { + Err(last_error()) + } + } + + fn set_no_inherit(&self) -> io::Result<()> { + unsafe { + let r = SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0); + if r == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} + +impl Read for Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + <&Socket>::read(&mut &*self, buf) + } +} + +impl<'a> Read for &'a Socket { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.recv(buf) + } +} + +impl Write for Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + <&Socket>::write(&mut &*self, buf) + } + + fn flush(&mut self) -> io::Result<()> { + <&Socket>::flush(&mut &*self) + } +} + +impl<'a> Write for &'a Socket { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.send(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Socket"); + f.field("socket", &self.socket); + if let Ok(addr) = self.local_addr() { + f.field("local_addr", &addr); + } + if let Ok(addr) = self.peer_addr() { + f.field("peer_addr", &addr); + } + f.finish() + } +} + +impl AsRawSocket for Socket { + fn as_raw_socket(&self) -> RawSocket { + self.socket as RawSocket + } +} + +impl IntoRawSocket for Socket { + fn into_raw_socket(self) -> RawSocket { + let socket = self.socket; + mem::forget(self); + socket as RawSocket + } +} + +impl FromRawSocket for Socket { + unsafe fn from_raw_socket(socket: RawSocket) -> Socket { + Socket { + socket: socket as sock::SOCKET, + } + } +} + +impl AsRawSocket for ::Socket { + fn as_raw_socket(&self) -> RawSocket { + self.inner.as_raw_socket() + } +} + +impl IntoRawSocket for ::Socket { + fn into_raw_socket(self) -> RawSocket { + self.inner.into_raw_socket() + } +} + +impl FromRawSocket for ::Socket { + unsafe fn from_raw_socket(socket: RawSocket) -> ::Socket { + ::Socket { + inner: Socket::from_raw_socket(socket), + } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = sock::closesocket(self.socket); + } + } +} + +impl From<Socket> for net::TcpStream { + fn from(socket: Socket) -> net::TcpStream { + unsafe { net::TcpStream::from_raw_socket(socket.into_raw_socket()) } + } +} + +impl From<Socket> for net::TcpListener { + fn from(socket: Socket) -> net::TcpListener { + unsafe { net::TcpListener::from_raw_socket(socket.into_raw_socket()) } + } +} + +impl From<Socket> for net::UdpSocket { + fn from(socket: Socket) -> net::UdpSocket { + unsafe { net::UdpSocket::from_raw_socket(socket.into_raw_socket()) } + } +} + +impl From<net::TcpStream> for Socket { + fn from(socket: net::TcpStream) -> Socket { + unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } + } +} + +impl From<net::TcpListener> for Socket { + fn from(socket: net::TcpListener) -> Socket { + unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } + } +} + +impl From<net::UdpSocket> for Socket { + fn from(socket: net::UdpSocket) -> Socket { + unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } + } +} + +fn clamp(input: usize) -> c_int { + cmp::min(input, <c_int>::max_value() as usize) as c_int +} + +fn dur2ms(dur: Option<Duration>) -> io::Result<DWORD> { + match dur { + Some(dur) => { + // Note that a duration is a (u64, u32) (seconds, nanoseconds) + // pair, and the timeouts in windows APIs are typically u32 + // milliseconds. To translate, we have two pieces to take care of: + // + // * Nanosecond precision is rounded up + // * Greater than u32::MAX milliseconds (50 days) is rounded up to + // INFINITE (never time out). + let ms = dur.as_secs() + .checked_mul(1000) + .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) + .and_then(|ms| { + ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { + 1 + } else { + 0 + }) + }) + .map(|ms| { + if ms > <DWORD>::max_value() as u64 { + INFINITE + } else { + ms as DWORD + } + }) + .unwrap_or(INFINITE); + if ms == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout", + )); + } + Ok(ms) + } + None => Ok(0), + } +} + +fn ms2dur(raw: DWORD) -> Option<Duration> { + if raw == 0 { + None + } else { + let secs = raw / 1000; + let nsec = (raw % 1000) * 1000000; + Some(Duration::new(secs as u64, nsec as u32)) + } +} + +fn to_s_addr(addr: &Ipv4Addr) -> in_addr_S_un { + let octets = addr.octets(); + let res = ::hton( + ((octets[0] as ULONG) << 24) | ((octets[1] as ULONG) << 16) | ((octets[2] as ULONG) << 8) + | ((octets[3] as ULONG) << 0), + ); + let mut new_addr: in_addr_S_un = unsafe { mem::zeroed() }; + unsafe { *(new_addr.S_addr_mut()) = res }; + new_addr +} + +fn from_s_addr(in_addr: in_addr_S_un) -> Ipv4Addr { + let h_addr = ::ntoh(unsafe { *in_addr.S_addr() }); + + let a: u8 = (h_addr >> 24) as u8; + let b: u8 = (h_addr >> 16) as u8; + let c: u8 = (h_addr >> 8) as u8; + let d: u8 = (h_addr >> 0) as u8; + + Ipv4Addr::new(a, b, c, d) +} + +fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr { + let mut ret_addr: in6_addr_u = unsafe { mem::zeroed() }; + unsafe { *(ret_addr.Byte_mut()) = addr.octets() }; + let mut ret: in6_addr = unsafe { mem::zeroed() }; + ret.u = ret_addr; + ret +} + +fn linger2dur(linger_opt: sock::linger) -> Option<Duration> { + if linger_opt.l_onoff == 0 { + None + } else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +fn dur2linger(dur: Option<Duration>) -> sock::linger { + match dur { + Some(d) => sock::linger { + l_onoff: 1, + l_linger: d.as_secs() as u16, + }, + None => sock::linger { + l_onoff: 0, + l_linger: 0, + }, + } +} + +#[test] +fn test_ip() { + let ip = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(ip, from_s_addr(to_s_addr(&ip))); +} diff --git a/socket2/src/utils.rs b/socket2/src/utils.rs new file mode 100644 index 000000000..e676489f3 --- /dev/null +++ b/socket2/src/utils.rs @@ -0,0 +1,48 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(hidden)] +pub trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +#[doc(hidden)] +pub trait One { + fn one() -> Self; +} + +macro_rules! one { + ($($t:ident)*) => ($( + impl One for $t { fn one() -> $t { 1 } } + )*) +} + +one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +#[doc(hidden)] +pub trait Zero { + fn zero() -> Self; +} + +macro_rules! zero { + ($($t:ident)*) => ($( + impl Zero for $t { fn zero() -> $t { 0 } } + )*) +} + +zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } diff --git a/strsim/.cargo-checksum.json b/strsim/.cargo-checksum.json new file mode 100644 index 000000000..4134b4179 --- /dev/null +++ b/strsim/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"} \ No newline at end of file diff --git a/strsim/CHANGELOG.md b/strsim/CHANGELOG.md new file mode 100644 index 000000000..48d6359ea --- /dev/null +++ b/strsim/CHANGELOG.md @@ -0,0 +1,123 @@ +# Change Log +This project attempts to adhere to [Semantic Versioning](http://semver.org). + +## [Unreleased] + +## [0.8.0] - (2018-08-19) +### Added +- Normalized versions of Levenshtein and Damerau-Levenshtein (thanks [@gentoid](https://github.com/gentoid)) + +## [0.7.0] - (2018-01-17) +### Changed +- Faster Levenshtein implementation (thanks [@wdv4758h](https://github.com/wdv4758h)) + +### Removed +- Remove the "against_vec" functions. They are one-liners now, so they don't + seem to add enough value to justify making the API larger. I didn't find + anybody using them when I skimmed through a GitHub search. If you do use them, + you can change the calls to something like: +```rust +let distances = strings.iter().map(|a| jaro(target, a)).collect(); +``` + +## [0.6.0] - (2016-12-26) +### Added +- Add optimal string alignment distance + +### Fixed +- Fix Damerau-Levenshtein implementation (previous implementation was actually + optimal string alignment; see this [Damerau-Levenshtein explanation]) + +## [0.5.2] - (2016-11-21) +### Changed +- Remove Cargo generated documentation in favor of a [docs.rs] link + +## [0.5.1] - (2016-08-23) +### Added +- Add Cargo generated documentation + +### Fixed +- Fix panic when Jaro or Jaro-Winkler are given strings both with a length of + one + +## [0.5.0] - (2016-08-11) +### Changed +- Make Hamming faster (thanks @IBUzPE9) when the two strings have the same + length but slower when they have different lengths + +## [0.4.1] - (2016-04-18) +### Added +- Add Vagrant setup for development +- Add AppVeyor configuration for Windows CI + +### Fixed +- Fix metrics when given strings with multibyte characters (thanks @WanzenBug) + +## [0.4.0] - (2015-06-10) +### Added +- For each metric, add a function that takes a vector of strings and returns a +vector of results (thanks @ovarene) + +## [0.3.0] - (2015-04-30) +### Changed +- Remove usage of unstable Rust features + +## [0.2.5] - (2015-04-24) +### Fixed +- Remove unnecessary `Float` import from doc tests + +## [0.2.4] - (2015-04-15) +### Fixed +- Remove unused `core` feature flag + +## [0.2.3] - (2015-04-01) +### Fixed +- Remove now unnecessary `Float` import + +## [0.2.2] - (2015-03-29) +### Fixed +- Remove usage of `char_at` (marked as unstable) + +## [0.2.1] - (2015-02-20) +### Fixed +- Update bit vector import to match Rust update + +## [0.2.0] - (2015-02-19) +### Added +- Implement Damerau-Levenshtein +- Add tests in docs + +## [0.1.1] - (2015-02-10) +### Added +- Configure Travis for CI +- Add rustdoc comments + +### Fixed +- Limit Jaro-Winkler return value to a maximum of 1.0 +- Fix float comparisons in tests + +## [0.1.0] - (2015-02-09) +### Added +- Implement Hamming, Jaro, Jaro-Winkler, and Levenshtein + +[Unreleased]: https://github.com/dguo/strsim-rs/compare/0.8.0...HEAD +[0.8.0]: https://github.com/dguo/strsim-rs/compare/0.7.0...0.8.0 +[0.7.0]: https://github.com/dguo/strsim-rs/compare/0.6.0...0.7.0 +[0.6.0]: https://github.com/dguo/strsim-rs/compare/0.5.2...0.6.0 +[0.5.2]: https://github.com/dguo/strsim-rs/compare/0.5.1...0.5.2 +[0.5.1]: https://github.com/dguo/strsim-rs/compare/0.5.0...0.5.1 +[0.5.0]: https://github.com/dguo/strsim-rs/compare/0.4.1...0.5.0 +[0.4.1]: https://github.com/dguo/strsim-rs/compare/0.4.0...0.4.1 +[0.4.0]: https://github.com/dguo/strsim-rs/compare/0.3.0...0.4.0 +[0.3.0]: https://github.com/dguo/strsim-rs/compare/0.2.5...0.3.0 +[0.2.5]: https://github.com/dguo/strsim-rs/compare/0.2.4...0.2.5 +[0.2.4]: https://github.com/dguo/strsim-rs/compare/0.2.3...0.2.4 +[0.2.3]: https://github.com/dguo/strsim-rs/compare/0.2.2...0.2.3 +[0.2.2]: https://github.com/dguo/strsim-rs/compare/0.2.1...0.2.2 +[0.2.1]: https://github.com/dguo/strsim-rs/compare/0.2.0...0.2.1 +[0.2.0]: https://github.com/dguo/strsim-rs/compare/0.1.1...0.2.0 +[0.1.1]: https://github.com/dguo/strsim-rs/compare/0.1.0...0.1.1 +[0.1.0]: https://github.com/dguo/strsim-rs/compare/fabad4...0.1.0 +[docs.rs]: https://docs.rs/strsim/ +[Damerau-Levenshtein explanation]: +http://scarcitycomputing.blogspot.com/2013/04/damerau-levenshtein-edit-distance.html diff --git a/strsim/Cargo.toml b/strsim/Cargo.toml new file mode 100644 index 000000000..38d37aee5 --- /dev/null +++ b/strsim/Cargo.toml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "strsim" +version = "0.8.0" +authors = ["Danny Guo <dannyguo91@gmail.com>"] +description = "Implementations of string similarity metrics.\nIncludes Hamming, Levenshtein, OSA, Damerau-Levenshtein, Jaro, and Jaro-Winkler.\n" +homepage = "https://github.com/dguo/strsim-rs" +documentation = "https://docs.rs/strsim/" +readme = "README.md" +keywords = ["string", "similarity", "Hamming", "Levenshtein", "Jaro"] +license = "MIT" +repository = "https://github.com/dguo/strsim-rs" +[badges.appveyor] +repository = "dguo/strsim-rs" + +[badges.travis-ci] +repository = "dguo/strsim-rs" diff --git a/strsim/LICENSE b/strsim/LICENSE new file mode 100644 index 000000000..1aacdb864 --- /dev/null +++ b/strsim/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2015 Danny Guo +Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/strsim/README.md b/strsim/README.md new file mode 100644 index 000000000..8765ea85f --- /dev/null +++ b/strsim/README.md @@ -0,0 +1,69 @@ +# strsim-rs [![Crates.io](https://img.shields.io/crates/v/strsim.svg)](https://crates.io/crates/strsim) [![Crates.io](https://img.shields.io/crates/l/strsim.svg?maxAge=2592000)](https://github.com/dguo/strsim-rs/blob/master/LICENSE) [![Linux build status](https://travis-ci.org/dguo/strsim-rs.svg?branch=master)](https://travis-ci.org/dguo/strsim-rs) [![Windows build status](https://ci.appveyor.com/api/projects/status/ggue6i785618a39w?svg=true)](https://ci.appveyor.com/project/dguo/strsim-rs) + +[Rust](https://www.rust-lang.org) implementations of [string similarity metrics]: + - [Hamming] + - [Levenshtein] - distance & normalized + - [Optimal string alignment] + - [Damerau-Levenshtein] - distance & normalized + - [Jaro and Jaro-Winkler] - this implementation of Jaro-Winkler does not limit the common prefix length + +### Installation +```toml +# Cargo.toml +[dependencies] +strsim = "0.8.0" +``` + +### [Documentation](https://docs.rs/strsim/) +You can change the version in the url to see the documentation for an older +version in the +[changelog](https://github.com/dguo/strsim-rs/blob/master/CHANGELOG.md). + +### Usage +```rust +extern crate strsim; + +use strsim::{hamming, levenshtein, normalized_levenshtein, osa_distance, + damerau_levenshtein, normalized_damerau_levenshtein, jaro, + jaro_winkler}; + +fn main() { + match hamming("hamming", "hammers") { + Ok(distance) => assert_eq!(3, distance), + Err(why) => panic!("{:?}", why) + } + + assert_eq!(3, levenshtein("kitten", "sitting")); + + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); + + assert_eq!(3, osa_distance("ac", "cba")); + + assert_eq!(2, damerau_levenshtein("ac", "cba")); + + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001) + + assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < + 0.001); + + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); +} +``` + +### Development +If you don't want to install Rust itself, you can run `$ ./dev` for a +development CLI if you have [Docker] installed. + +Benchmarks require a Nightly toolchain. They are run by `cargo +nightly bench`. + +### License +[MIT](https://github.com/dguo/strsim-rs/blob/master/LICENSE) + +[string similarity metrics]:http://en.wikipedia.org/wiki/String_metric +[Damerau-Levenshtein]:http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance +[Jaro and Jaro-Winkler]:http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance +[Levenshtein]:http://en.wikipedia.org/wiki/Levenshtein_distance +[Hamming]:http://en.wikipedia.org/wiki/Hamming_distance +[Optimal string alignment]:https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance#Optimal_string_alignment_distance +[Docker]:https://docs.docker.com/engine/installation/ diff --git a/strsim/appveyor.yml b/strsim/appveyor.yml new file mode 100644 index 000000000..fb992db82 --- /dev/null +++ b/strsim/appveyor.yml @@ -0,0 +1,13 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-beta-x86_64-pc-windows-gnu.exe' + - rust-beta-x86_64-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo build + - cargo test --verbose + diff --git a/strsim/benches/benches.rs b/strsim/benches/benches.rs new file mode 100644 index 000000000..a6d5372e8 --- /dev/null +++ b/strsim/benches/benches.rs @@ -0,0 +1,84 @@ +//! Benchmarks for strsim. + +#![feature(test)] + +extern crate strsim; + +mod benches { + use super::*; + + extern crate test; + use self::test::Bencher; + + #[bench] + fn bench_hamming(bencher: &mut Bencher) { + let a = "ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGG"; + let b = "CCTGGAGGGTGGCCCCACCGGCCGAGACAGCGAGCATATGCAGGAAGC"; + bencher.iter(|| { + strsim::hamming(&a, &b).unwrap(); + }) + } + + #[bench] + fn bench_jaro(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::jaro(&a, &b); + }) + } + + #[bench] + fn bench_jaro_winkler(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::jaro_winkler(&a, &b); + }) + } + + #[bench] + fn bench_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_normalized_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::normalized_levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_osa_distance(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::osa_distance(&a, &b); + }) + } + + #[bench] + fn bench_damerau_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::damerau_levenshtein(&a, &b); + }) + } + + #[bench] + fn bench_normalized_damerau_levenshtein(bencher: &mut Bencher) { + let a = "Philosopher Friedrich Nietzsche"; + let b = "Philosopher Jean-Paul Sartre"; + bencher.iter(|| { + strsim::normalized_damerau_levenshtein(&a, &b); + }) + } +} diff --git a/strsim/dev b/strsim/dev new file mode 100755 index 000000000..4c85a494b --- /dev/null +++ b/strsim/dev @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# ./dev --help + +import argparse +import os +from subprocess import run +import sys + +parser = argparse.ArgumentParser(prog='./dev') +subparsers = parser.add_subparsers(metavar='<command>', title='commands') +command = [ + 'docker', 'run', '-it', '--rm', '-v', os.getcwd() + ':/src:cached', + '-w=/src', 'rust:1.21.0' +] + +def cargo(args, remaining): + sys.exit(run(command + ['cargo'] + remaining or []).returncode) + +parser_cargo = subparsers.add_parser('cargo', help='run a cargo command') +parser_cargo.set_defaults(func=cargo) + +def sh(args, remaining): + sys.exit(run(command + ['bash']).returncode) + +parser_sh = subparsers.add_parser('sh', help='bring up a shell') +parser_sh.set_defaults(func=sh) + +def test(args, remaining): + sys.exit(run(command + ['cargo', 'test']).returncode) + +parser_test = subparsers.add_parser('test', help='run tests') +parser_test.set_defaults(func=test) + +if len(sys.argv) > 1: + args, remaining = parser.parse_known_args() + try: + args.func(args, remaining) + except FileNotFoundError: + sys.exit('Please install Docker.') +else: + parser.print_help() diff --git a/strsim/src/lib.rs b/strsim/src/lib.rs new file mode 100644 index 000000000..8c56843b3 --- /dev/null +++ b/strsim/src/lib.rs @@ -0,0 +1,786 @@ +//! This library implements string similarity metrics. + +use std::char; +use std::cmp::{max, min}; +use std::collections::HashMap; + +#[derive(Debug, PartialEq)] +pub enum StrSimError { + DifferentLengthArgs +} + +pub type HammingResult = Result<usize, StrSimError>; + +/// Calculates the number of positions in the two strings where the characters +/// differ. Returns an error if the strings have different lengths. +/// +/// ``` +/// use strsim::hamming; +/// +/// match hamming("hamming", "hammers") { +/// Ok(distance) => assert_eq!(3, distance), +/// Err(why) => panic!("{:?}", why) +/// } +/// ``` +pub fn hamming(a: &str, b: &str) -> HammingResult { + let (mut ita, mut itb, mut count) = (a.chars(), b.chars(), 0); + loop { + match (ita.next(), itb.next()){ + (Some(x), Some(y)) => if x != y { count += 1 }, + (None, None) => return Ok(count), + _ => return Err(StrSimError::DifferentLengthArgs), + } + } +} + +/// Calculates the Jaro similarity between two strings. The returned value +/// is between 0.0 and 1.0 (higher value means more similar). +/// +/// ``` +/// use strsim::jaro; +/// +/// assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < +/// 0.001); +/// ``` +pub fn jaro(a: &str, b: &str) -> f64 { + if a == b { return 1.0; } + + let a_len = a.chars().count(); + let b_len = b.chars().count(); + + // The check for lengths of one here is to prevent integer overflow when + // calculating the search range. + if a_len == 0 || b_len == 0 || (a_len == 1 && b_len == 1) { + return 0.0; + } + + let search_range = (max(a_len, b_len) / 2) - 1; + + let mut b_consumed = Vec::with_capacity(b_len); + for _ in 0..b_len { + b_consumed.push(false); + } + let mut matches = 0.0; + + let mut transpositions = 0.0; + let mut b_match_index = 0; + + for (i, a_char) in a.chars().enumerate() { + let min_bound = + // prevent integer wrapping + if i > search_range { + max(0, i - search_range) + } else { + 0 + }; + + let max_bound = min(b_len - 1, i + search_range); + + if min_bound > max_bound { + continue; + } + + for (j, b_char) in b.chars().enumerate() { + if min_bound <= j && j <= max_bound && a_char == b_char && + !b_consumed[j] { + b_consumed[j] = true; + matches += 1.0; + + if j < b_match_index { + transpositions += 1.0; + } + b_match_index = j; + + break; + } + } + } + + if matches == 0.0 { + 0.0 + } else { + (1.0 / 3.0) * ((matches / a_len as f64) + + (matches / b_len as f64) + + ((matches - transpositions) / matches)) + } +} + +/// Like Jaro but gives a boost to strings that have a common prefix. +/// +/// ``` +/// use strsim::jaro_winkler; +/// +/// assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < +/// 0.001); +/// ``` +pub fn jaro_winkler(a: &str, b: &str) -> f64 { + let jaro_distance = jaro(a, b); + + // Don't limit the length of the common prefix + let prefix_length = a.chars() + .zip(b.chars()) + .take_while(|&(a_char, b_char)| a_char == b_char) + .count(); + + let jaro_winkler_distance = + jaro_distance + (0.1 * prefix_length as f64 * (1.0 - jaro_distance)); + + if jaro_winkler_distance <= 1.0 { + jaro_winkler_distance + } else { + 1.0 + } +} + +/// Calculates the minimum number of insertions, deletions, and substitutions +/// required to change one string into the other. +/// +/// ``` +/// use strsim::levenshtein; +/// +/// assert_eq!(3, levenshtein("kitten", "sitting")); +/// ``` +pub fn levenshtein(a: &str, b: &str) -> usize { + if a == b { return 0; } + + let a_len = a.chars().count(); + let b_len = b.chars().count(); + + if a_len == 0 { return b_len; } + if b_len == 0 { return a_len; } + + let mut cache: Vec<usize> = (1..b_len+1).collect(); + + let mut result = 0; + let mut distance_a; + let mut distance_b; + + for (i, a_char) in a.chars().enumerate() { + result = i; + distance_b = i; + + for (j, b_char) in b.chars().enumerate() { + let cost = if a_char == b_char { 0 } else { 1 }; + distance_a = distance_b + cost; + distance_b = cache[j]; + result = min(result + 1, min(distance_a, distance_b + 1)); + cache[j] = result; + } + } + + result +} + +/// Calculates a normalized score of the Levenshtein algorithm between 0.0 and +/// 1.0 (inclusive), where 1.0 means the strings are the same. +/// +/// ``` +/// use strsim::normalized_levenshtein; +/// +/// assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); +/// assert!((normalized_levenshtein("", "") - 1.0).abs() < 0.00001); +/// assert!(normalized_levenshtein("", "second").abs() < 0.00001); +/// assert!(normalized_levenshtein("first", "").abs() < 0.00001); +/// assert!((normalized_levenshtein("string", "string") - 1.0).abs() < 0.00001); +/// ``` +pub fn normalized_levenshtein(a: &str, b: &str) -> f64 { + if a.is_empty() && b.is_empty() { + return 1.0; + } + 1.0 - (levenshtein(a, b) as f64) / (a.chars().count().max(b.chars().count()) as f64) +} + +/// Like Levenshtein but allows for adjacent transpositions. Each substring can +/// only be edited once. +/// +/// ``` +/// use strsim::osa_distance; +/// +/// assert_eq!(3, osa_distance("ab", "bca")); +/// ``` +pub fn osa_distance(a: &str, b: &str) -> usize { + let a_len = a.chars().count(); + let b_len = b.chars().count(); + if a == b { return 0; } + else if a_len == 0 { return b_len; } + else if b_len == 0 { return a_len; } + + let mut prev_two_distances: Vec<usize> = Vec::with_capacity(b_len + 1); + let mut prev_distances: Vec<usize> = Vec::with_capacity(b_len + 1); + let mut curr_distances: Vec<usize> = Vec::with_capacity(b_len + 1); + + let mut prev_a_char = char::MAX; + let mut prev_b_char = char::MAX; + + for i in 0..(b_len + 1) { + prev_two_distances.push(i); + prev_distances.push(i); + curr_distances.push(0); + } + + for (i, a_char) in a.chars().enumerate() { + curr_distances[0] = i + 1; + + for (j, b_char) in b.chars().enumerate() { + let cost = if a_char == b_char { 0 } else { 1 }; + curr_distances[j + 1] = min(curr_distances[j] + 1, + min(prev_distances[j + 1] + 1, + prev_distances[j] + cost)); + if i > 0 && j > 0 && a_char != b_char && + a_char == prev_b_char && b_char == prev_a_char { + curr_distances[j + 1] = min(curr_distances[j + 1], + prev_two_distances[j - 1] + 1); + } + + prev_b_char = b_char; + } + + prev_two_distances.clone_from(&prev_distances); + prev_distances.clone_from(&curr_distances); + prev_a_char = a_char; + } + + curr_distances[b_len] + +} + +/// Like optimal string alignment, but substrings can be edited an unlimited +/// number of times, and the triangle inequality holds. +/// +/// ``` +/// use strsim::damerau_levenshtein; +/// +/// assert_eq!(2, damerau_levenshtein("ab", "bca")); +/// ``` +pub fn damerau_levenshtein(a: &str, b: &str) -> usize { + if a == b { return 0; } + + let a_chars: Vec<char> = a.chars().collect(); + let b_chars: Vec<char> = b.chars().collect(); + let a_len = a_chars.len(); + let b_len = b_chars.len(); + + if a_len == 0 { return b_len; } + if b_len == 0 { return a_len; } + + let mut distances = vec![vec![0; b_len + 2]; a_len + 2]; + let max_distance = a_len + b_len; + distances[0][0] = max_distance; + + for i in 0..(a_len + 1) { + distances[i + 1][0] = max_distance; + distances[i + 1][1] = i; + } + + for j in 0..(b_len + 1) { + distances[0][j + 1] = max_distance; + distances[1][j + 1] = j; + } + + let mut chars: HashMap<char, usize> = HashMap::new(); + + for i in 1..(a_len + 1) { + let mut db = 0; + + for j in 1..(b_len + 1) { + let k = match chars.get(&b_chars[j - 1]) { + Some(value) => value.clone(), + None => 0 + }; + + let l = db; + + let mut cost = 1; + if a_chars[i - 1] == b_chars[j - 1] { + cost = 0; + db = j; + } + + let substitution_cost = distances[i][j] + cost; + let insertion_cost = distances[i][j + 1] + 1; + let deletion_cost = distances[i + 1][j] + 1; + let transposition_cost = distances[k][l] + (i - k - 1) + 1 + + (j - l - 1); + + distances[i + 1][j + 1] = min(substitution_cost, + min(insertion_cost, + min(deletion_cost, + transposition_cost))); + } + + chars.insert(a_chars[i - 1], i); + } + + distances[a_len + 1][b_len + 1] +} + +/// Calculates a normalized score of the Damerau–Levenshtein algorithm between +/// 0.0 and 1.0 (inclusive), where 1.0 means the strings are the same. +/// +/// ``` +/// use strsim::normalized_damerau_levenshtein; +/// +/// assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); +/// assert!((normalized_damerau_levenshtein("", "") - 1.0).abs() < 0.00001); +/// assert!(normalized_damerau_levenshtein("", "flower").abs() < 0.00001); +/// assert!(normalized_damerau_levenshtein("tree", "").abs() < 0.00001); +/// assert!((normalized_damerau_levenshtein("sunglasses", "sunglasses") - 1.0).abs() < 0.00001); +/// ``` +pub fn normalized_damerau_levenshtein(a: &str, b: &str) -> f64 { + if a.is_empty() && b.is_empty() { + return 1.0; + } + 1.0 - (damerau_levenshtein(a, b) as f64) / (a.chars().count().max(b.chars().count()) as f64) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hamming_empty() { + match hamming("", "") { + Ok(distance) => { assert_eq!(0, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_same() { + match hamming("hamming", "hamming") { + Ok(distance) => { assert_eq!(0, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_diff() { + match hamming("hamming", "hammers") { + Ok(distance) => { assert_eq!(3, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_diff_multibyte() { + match hamming("hamming", "h香mmüng") { + Ok(distance) => { assert_eq!(2, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn hamming_unequal_length() { + match hamming("ham", "hamming") { + Ok(_) => { panic!(); }, + Err(why) => { assert_eq!(why, StrSimError::DifferentLengthArgs); } + } + } + + #[test] + fn hamming_names() { + match hamming("Friedrich Nietzs", "Jean-Paul Sartre") { + Ok(distance) => { assert_eq!(14, distance); }, + Err(why) => { panic!("{:?}", why); } + } + } + + #[test] + fn jaro_both_empty() { + assert_eq!(1.0, jaro("", "")); + } + + #[test] + fn jaro_first_empty() { + assert_eq!(0.0, jaro("", "jaro")); + } + + #[test] + fn jaro_second_empty() { + assert_eq!(0.0, jaro("distance", "")); + } + + #[test] + fn jaro_same() { + assert_eq!(1.0, jaro("jaro", "jaro")); + } + + #[test] + fn jaro_multibyte() { + assert!((0.818 - jaro("testabctest", "testöঙ香test")) < 0.001); + assert!((0.818 - jaro("testöঙ香test", "testabctest")) < 0.001); + } + + #[test] + fn jaro_diff_short() { + assert!((0.767 - jaro("dixon", "dicksonx")).abs() < 0.001); + } + + #[test] + fn jaro_diff_one_character() { + assert_eq!(0.0, jaro("a", "b")); + } + + #[test] + fn jaro_diff_one_and_two() { + assert!((0.83 - jaro("a", "ab")).abs() < 0.01); + } + + #[test] + fn jaro_diff_two_and_one() { + assert!((0.83 - jaro("ab", "a")).abs() < 0.01); + } + + #[test] + fn jaro_diff_no_transposition() { + assert!((0.822 - jaro("dwayne", "duane")).abs() < 0.001); + } + + #[test] + fn jaro_diff_with_transposition() { + assert!((0.944 - jaro("martha", "marhta")).abs() < 0.001); + } + + #[test] + fn jaro_names() { + assert!((0.392 - jaro("Friedrich Nietzsche", + "Jean-Paul Sartre")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_both_empty() { + assert_eq!(1.0, jaro_winkler("", "")); + } + + #[test] + fn jaro_winkler_first_empty() { + assert_eq!(0.0, jaro_winkler("", "jaro-winkler")); + } + + #[test] + fn jaro_winkler_second_empty() { + assert_eq!(0.0, jaro_winkler("distance", "")); + } + + #[test] + fn jaro_winkler_same() { + assert_eq!(1.0, jaro_winkler("Jaro-Winkler", "Jaro-Winkler")); + } + + #[test] + fn jaro_winkler_multibyte() { + assert!((0.89 - jaro_winkler("testabctest", "testöঙ香test")).abs() < + 0.001); + assert!((0.89 - jaro_winkler("testöঙ香test", "testabctest")).abs() < + 0.001); + } + + #[test] + fn jaro_winkler_diff_short() { + assert!((0.813 - jaro_winkler("dixon", "dicksonx")).abs() < 0.001); + assert!((0.813 - jaro_winkler("dicksonx", "dixon")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_diff_one_character() { + assert_eq!(0.0, jaro_winkler("a", "b")); + } + + #[test] + fn jaro_winkler_diff_no_transposition() { + assert!((0.840 - jaro_winkler("dwayne", "duane")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_diff_with_transposition() { + assert!((0.961 - jaro_winkler("martha", "marhta")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_names() { + assert!((0.562 - jaro_winkler("Friedrich Nietzsche", + "Fran-Paul Sartre")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_long_prefix() { + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); + } + + #[test] + fn jaro_winkler_more_names() { + assert!((0.868 - jaro_winkler("Thorkel", "Thorgier")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_length_of_one() { + assert!((0.738 - jaro_winkler("Dinsdale", "D")).abs() < 0.001); + } + + #[test] + fn jaro_winkler_very_long_prefix() { + assert!((1.0 - jaro_winkler("thequickbrownfoxjumpedoverx", + "thequickbrownfoxjumpedovery")).abs() < + 0.001); + } + + #[test] + fn levenshtein_empty() { + assert_eq!(0, levenshtein("", "")); + } + + #[test] + fn levenshtein_same() { + assert_eq!(0, levenshtein("levenshtein", "levenshtein")); + } + + #[test] + fn levenshtein_diff_short() { + assert_eq!(3, levenshtein("kitten", "sitting")); + } + + #[test] + fn levenshtein_diff_with_space() { + assert_eq!(5, levenshtein("hello, world", "bye, world")); + } + + #[test] + fn levenshtein_diff_multibyte() { + assert_eq!(3, levenshtein("öঙ香", "abc")); + assert_eq!(3, levenshtein("abc", "öঙ香")); + } + + #[test] + fn levenshtein_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lorem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(37, levenshtein(a, b)); + } + + #[test] + fn levenshtein_first_empty() { + assert_eq!(7, levenshtein("", "sitting")); + } + + #[test] + fn levenshtein_second_empty() { + assert_eq!(6, levenshtein("kitten", "")); + } + + #[test] + fn normalized_levenshtein_diff_short() { + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_for_empty_strings() { + assert!((normalized_levenshtein("", "") - 1.0).abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_first_empty() { + assert!(normalized_levenshtein("", "second").abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_second_empty() { + assert!(normalized_levenshtein("first", "").abs() < 0.00001); + } + + #[test] + fn normalized_levenshtein_identical_strings() { + assert!((normalized_levenshtein("identical", "identical") - 1.0).abs() < 0.00001); + } + + #[test] + fn osa_distance_empty() { + assert_eq!(0, osa_distance("", "")); + } + + #[test] + fn osa_distance_same() { + assert_eq!(0, osa_distance("damerau", "damerau")); + } + + #[test] + fn osa_distance_first_empty() { + assert_eq!(7, osa_distance("", "damerau")); + } + + #[test] + fn osa_distance_second_empty() { + assert_eq!(7, osa_distance("damerau", "")); + } + + #[test] + fn osa_distance_diff() { + assert_eq!(3, osa_distance("ca", "abc")); + } + + #[test] + fn osa_distance_diff_short() { + assert_eq!(3, osa_distance("damerau", "aderua")); + } + + #[test] + fn osa_distance_diff_reversed() { + assert_eq!(3, osa_distance("aderua", "damerau")); + } + + #[test] + fn osa_distance_diff_multibyte() { + assert_eq!(3, osa_distance("öঙ香", "abc")); + assert_eq!(3, osa_distance("abc", "öঙ香")); + } + + #[test] + fn osa_distance_diff_unequal_length() { + assert_eq!(6, osa_distance("damerau", "aderuaxyz")); + } + + #[test] + fn osa_distance_diff_unequal_length_reversed() { + assert_eq!(6, osa_distance("aderuaxyz", "damerau")); + } + + #[test] + fn osa_distance_diff_comedians() { + assert_eq!(5, osa_distance("Stewart", "Colbert")); + } + + #[test] + fn osa_distance_many_transpositions() { + assert_eq!(4, osa_distance("abcdefghijkl", "bacedfgihjlk")); + } + + #[test] + fn osa_distance_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lehem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(36, osa_distance(a, b)); + } + + #[test] + fn osa_distance_beginning_transposition() { + assert_eq!(1, osa_distance("foobar", "ofobar")); + } + + #[test] + fn osa_distance_end_transposition() { + assert_eq!(1, osa_distance("specter", "spectre")); + } + + #[test] + fn osa_distance_restricted_edit() { + assert_eq!(4, osa_distance("a cat", "an abct")); + } + + #[test] + fn damerau_levenshtein_empty() { + assert_eq!(0, damerau_levenshtein("", "")); + } + + #[test] + fn damerau_levenshtein_same() { + assert_eq!(0, damerau_levenshtein("damerau", "damerau")); + } + + #[test] + fn damerau_levenshtein_first_empty() { + assert_eq!(7, damerau_levenshtein("", "damerau")); + } + + #[test] + fn damerau_levenshtein_second_empty() { + assert_eq!(7, damerau_levenshtein("damerau", "")); + } + + #[test] + fn damerau_levenshtein_diff() { + assert_eq!(2, damerau_levenshtein("ca", "abc")); + } + + #[test] + fn damerau_levenshtein_diff_short() { + assert_eq!(3, damerau_levenshtein("damerau", "aderua")); + } + + #[test] + fn damerau_levenshtein_diff_reversed() { + assert_eq!(3, damerau_levenshtein("aderua", "damerau")); + } + + #[test] + fn damerau_levenshtein_diff_multibyte() { + assert_eq!(3, damerau_levenshtein("öঙ香", "abc")); + assert_eq!(3, damerau_levenshtein("abc", "öঙ香")); + } + + #[test] + fn damerau_levenshtein_diff_unequal_length() { + assert_eq!(6, damerau_levenshtein("damerau", "aderuaxyz")); + } + + #[test] + fn damerau_levenshtein_diff_unequal_length_reversed() { + assert_eq!(6, damerau_levenshtein("aderuaxyz", "damerau")); + } + + #[test] + fn damerau_levenshtein_diff_comedians() { + assert_eq!(5, damerau_levenshtein("Stewart", "Colbert")); + } + + #[test] + fn damerau_levenshtein_many_transpositions() { + assert_eq!(4, damerau_levenshtein("abcdefghijkl", "bacedfgihjlk")); + } + + #[test] + fn damerau_levenshtein_diff_longer() { + let a = "The quick brown fox jumped over the angry dog."; + let b = "Lehem ipsum dolor sit amet, dicta latine an eam."; + assert_eq!(36, damerau_levenshtein(a, b)); + } + + #[test] + fn damerau_levenshtein_beginning_transposition() { + assert_eq!(1, damerau_levenshtein("foobar", "ofobar")); + } + + #[test] + fn damerau_levenshtein_end_transposition() { + assert_eq!(1, damerau_levenshtein("specter", "spectre")); + } + + #[test] + fn damerau_levenshtein_unrestricted_edit() { + assert_eq!(3, damerau_levenshtein("a cat", "an abct")); + } + + #[test] + fn normalized_damerau_levenshtein_diff_short() { + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_for_empty_strings() { + assert!((normalized_damerau_levenshtein("", "") - 1.0).abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_first_empty() { + assert!(normalized_damerau_levenshtein("", "flower").abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_second_empty() { + assert!(normalized_damerau_levenshtein("tree", "").abs() < 0.00001); + } + + #[test] + fn normalized_damerau_levenshtein_identical_strings() { + assert!((normalized_damerau_levenshtein("sunglasses", "sunglasses") - 1.0).abs() < 0.00001); + } +} diff --git a/strsim/tests/lib.rs b/strsim/tests/lib.rs new file mode 100644 index 000000000..ad7af513a --- /dev/null +++ b/strsim/tests/lib.rs @@ -0,0 +1,49 @@ +extern crate strsim; + +use strsim::{hamming, levenshtein, normalized_levenshtein, osa_distance,damerau_levenshtein, + normalized_damerau_levenshtein, jaro, jaro_winkler}; + +#[test] +fn hamming_works() { + match hamming("hamming", "hammers") { + Ok(distance) => assert_eq!(3, distance), + Err(why) => panic!("{:?}", why) + } +} + +#[test] +fn levenshtein_works() { + assert_eq!(3, levenshtein("kitten", "sitting")); +} + +#[test] +fn normalized_levenshtein_works() { + assert!((normalized_levenshtein("kitten", "sitting") - 0.57142).abs() < 0.00001); +} + +#[test] +fn osa_distance_works() { + assert_eq!(3, osa_distance("ac", "cba")); +} + +#[test] +fn damerau_levenshtein_works() { + assert_eq!(2, damerau_levenshtein("ac", "cba")); +} + +#[test] +fn normalized_damerau_levenshtein_works() { + assert!((normalized_damerau_levenshtein("levenshtein", "löwenbräu") - 0.27272).abs() < 0.00001); +} + +#[test] +fn jaro_works() { + assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() < + 0.001); +} + +#[test] +fn jaro_winkler_works() { + assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() < + 0.001); +} diff --git a/syn/.cargo-checksum.json b/syn/.cargo-checksum.json new file mode 100644 index 000000000..6e126d422 --- /dev/null +++ b/syn/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"} \ No newline at end of file diff --git a/syn/Cargo.toml b/syn/Cargo.toml new file mode 100644 index 000000000..f71d675a5 --- /dev/null +++ b/syn/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "syn" +version = "0.15.34" +authors = ["David Tolnay <dtolnay@gmail.com>"] +include = ["/build.rs", "/Cargo.toml", "/LICENSE-APACHE", "/LICENSE-MIT", "/README.md", "/src/**/*.rs"] +description = "Parser for Rust source code" +documentation = "https://docs.rs/syn" +readme = "README.md" +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT/Apache-2.0" +repository = "https://github.com/dtolnay/syn" +[package.metadata.docs.rs] +all-features = true + +[package.metadata.playground] +all-features = true +[dependencies.proc-macro2] +version = "0.4.4" +default-features = false + +[dependencies.quote] +version = "0.6" +optional = true +default-features = false + +[dependencies.unicode-xid] +version = "0.1" +[dev-dependencies.colored] +version = "1.7" + +[dev-dependencies.insta] +version = "0.7" + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.regex] +version = "1.0" + +[dev-dependencies.walkdir] +version = "2.1" + +[features] +clone-impls = [] +default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"] +derive = [] +extra-traits = [] +fold = [] +full = [] +parsing = [] +printing = ["quote"] +proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"] +visit = [] +visit-mut = [] +[badges.travis-ci] +repository = "dtolnay/syn" diff --git a/syn/LICENSE-APACHE b/syn/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/syn/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/syn/LICENSE-MIT b/syn/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/syn/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/syn/README.md b/syn/README.md new file mode 100644 index 000000000..ecc6eb878 --- /dev/null +++ b/syn/README.md @@ -0,0 +1,256 @@ +Parser for Rust source code +=========================== + +[![Build Status](https://api.travis-ci.org/dtolnay/syn.svg?branch=master)](https://travis-ci.org/dtolnay/syn) +[![Latest Version](https://img.shields.io/crates/v/syn.svg)](https://crates.io/crates/syn) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/syn/0.15/syn/) +[![Rustc Version 1.15+](https://img.shields.io/badge/rustc-1.15+-lightgray.svg)](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html) + +Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree +of Rust source code. + +Currently this library is geared toward use in Rust procedural macros, but +contains some APIs that may be useful more generally. + +[custom derive]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md + +- **Data structures** — Syn provides a complete syntax tree that can represent + any valid Rust source code. The syntax tree is rooted at [`syn::File`] which + represents a full source file, but there are other entry points that may be + useful to procedural macros including [`syn::Item`], [`syn::Expr`] and + [`syn::Type`]. + +- **Custom derives** — Of particular interest to custom derives is + [`syn::DeriveInput`] which is any of the three legal input items to a derive + macro. An example below shows using this type in a library that can derive + implementations of a trait of your own. + +- **Parsing** — Parsing in Syn is built around [parser functions] with the + signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined by + Syn is individually parsable and may be used as a building block for custom + syntaxes, or you may dream up your own brand new syntax without involving any + of our syntax tree types. + +- **Location information** — Every token parsed by Syn is associated with a + `Span` that tracks line and column information back to the source of that + token. These spans allow a procedural macro to display detailed error messages + pointing to all the right places in the user's code. There is an example of + this below. + +- **Feature flags** — Functionality is aggressively feature gated so your + procedural macros enable only what they need, and do not pay in compile time + for all the rest. + +[`syn::File`]: https://docs.rs/syn/0.15/syn/struct.File.html +[`syn::Item`]: https://docs.rs/syn/0.15/syn/enum.Item.html +[`syn::Expr`]: https://docs.rs/syn/0.15/syn/enum.Expr.html +[`syn::Type`]: https://docs.rs/syn/0.15/syn/enum.Type.html +[`syn::DeriveInput`]: https://docs.rs/syn/0.15/syn/struct.DeriveInput.html +[parser functions]: https://docs.rs/syn/0.15/syn/parse/index.html + +If you get stuck with anything involving procedural macros in Rust I am happy to +provide help even if the issue is not related to Syn. Please file a ticket in +this repo. + +*Version requirement: Syn supports any compiler version back to Rust's very +first support for procedural macros in Rust 1.15.0. Some features especially +around error reporting are only available in newer compilers or on the nightly +channel.* + +[*Release notes*](https://github.com/dtolnay/syn/releases) + +## Example of a custom derive + +The canonical custom derive using Syn looks like this. We write an ordinary Rust +function tagged with a `proc_macro_derive` attribute and the name of the trait +we are deriving. Any time that derive appears in the user's code, the Rust +compiler passes their data structure as tokens into our macro. We get to execute +arbitrary Rust code to figure out what to do with those tokens, then hand some +tokens back to the compiler to compile into the user's crate. + +[`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html + +```toml +[dependencies] +syn = "0.15" +quote = "0.6" + +[lib] +proc-macro = true +``` + +```rust +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(MyMacro)] +pub fn my_macro(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + // Build the output, possibly using quasi-quotation + let expanded = quote! { + // ... + }; + + // Hand the output tokens back to the compiler + TokenStream::from(expanded) +} +``` + +The [`heapsize`] example directory shows a complete working Macros 1.1 +implementation of a custom derive. It works on any Rust compiler 1.15+. The +example derives a `HeapSize` trait which computes an estimate of the amount of +heap memory owned by a value. + +[`heapsize`]: examples/heapsize + +```rust +pub trait HeapSize { + /// Total number of bytes of heap memory owned by `self`. + fn heap_size_of_children(&self) -> usize; +} +``` + +The custom derive allows users to write `#[derive(HeapSize)]` on data structures +in their program. + +```rust +#[derive(HeapSize)] +struct Demo<'a, T: ?Sized> { + a: Box<T>, + b: u8, + c: &'a str, + d: String, +} +``` + +## Spans and error reporting + +The token-based procedural macro API provides great control over where the +compiler's error messages are displayed in user code. Consider the error the +user sees if one of their field types does not implement `HeapSize`. + +```rust +#[derive(HeapSize)] +struct Broken { + ok: String, + bad: std::thread::Thread, +} +``` + +By tracking span information all the way through the expansion of a procedural +macro as shown in the `heapsize` example, token-based macros in Syn are able to +trigger errors that directly pinpoint the source of the problem. + +``` +error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied + --> src/main.rs:7:5 + | +7 | bad: std::thread::Thread, + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `std::thread::Thread` +``` + +## Parsing a custom syntax + +The [`lazy-static`] example directory shows the implementation of a +`functionlike!(...)` procedural macro in which the input tokens are parsed using +Syn's parsing API. + +[`lazy-static`]: examples/lazy-static + +The example reimplements the popular `lazy_static` crate from crates.io as a +procedural macro. + +``` +lazy_static! { + static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); +} +``` + +The implementation shows how to trigger custom warnings and error messages on +the macro input. + +``` +warning: come on, pick a more creative name + --> src/main.rs:10:16 + | +10 | static ref FOO: String = "lazy_static".to_owned(); + | ^^^ +``` + +## Debugging + +When developing a procedural macro it can be helpful to look at what the +generated code looks like. Use `cargo rustc -- -Zunstable-options +--pretty=expanded` or the [`cargo expand`] subcommand. + +[`cargo expand`]: https://github.com/dtolnay/cargo-expand + +To show the expanded code for some crate that uses your procedural macro, run +`cargo expand` from that crate. To show the expanded code for one of your own +test cases, run `cargo expand --test the_test_case` where the last argument is +the name of the test file without the `.rs` extension. + +This write-up by Brandon W Maister discusses debugging in more detail: +[Debugging Rust's new Custom Derive system][debugging]. + +[debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ + +## Optional features + +Syn puts a lot of functionality behind optional features in order to optimize +compile time for the most common use cases. The following features are +available. + +- **`derive`** *(enabled by default)* — Data structures for representing the + possible input to a custom derive, including structs and enums and types. +- **`full`** — Data structures for representing the syntax tree of all valid + Rust source code, including items and expressions. +- **`parsing`** *(enabled by default)* — Ability to parse input tokens into a + syntax tree node of a chosen type. +- **`printing`** *(enabled by default)* — Ability to print a syntax tree node as + tokens of Rust source code. +- **`visit`** — Trait for traversing a syntax tree. +- **`visit-mut`** — Trait for traversing and mutating in place a syntax tree. +- **`fold`** — Trait for transforming an owned syntax tree. +- **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree + types. +- **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree + types. +- **`proc-macro`** *(enabled by default)* — Runtime dependency on the dynamic + library libproc_macro from rustc toolchain. + +## Proc macro shim + +Syn uses the [proc-macro2] crate to emulate the compiler's procedural macro API +in a stable way that works all the way back to Rust 1.15.0. This shim makes it +possible to write code without regard for whether the current compiler version +supports the features we use. + +In general all of your code should be written against proc-macro2 rather than +proc-macro. The one exception is in the signatures of procedural macro entry +points, which are required by the language to use `proc_macro::TokenStream`. + +The proc-macro2 crate will automatically detect and use the compiler's data +structures on sufficiently new compilers. + +[proc-macro2]: https://github.com/alexcrichton/proc-macro2 + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. diff --git a/syn/build.rs b/syn/build.rs new file mode 100644 index 000000000..2b2a41964 --- /dev/null +++ b/syn/build.rs @@ -0,0 +1,72 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let compiler = match rustc_version() { + Some(compiler) => compiler, + None => return, + }; + + if compiler.minor >= 19 { + println!("cargo:rustc-cfg=syn_can_use_thread_id"); + } + + if compiler.minor >= 20 { + println!("cargo:rustc-cfg=syn_can_use_associated_constants"); + } + + // Macro modularization allows re-exporting the `quote!` macro in 1.30+. + if compiler.minor >= 30 { + println!("cargo:rustc-cfg=syn_can_call_macro_by_path"); + } + + if !compiler.nightly { + println!("cargo:rustc-cfg=syn_disable_nightly_tests"); + } +} + +struct Compiler { + minor: u32, + nightly: bool, +} + +fn rustc_version() -> Option<Compiler> { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + let minor = match u32::from_str(next) { + Ok(minor) => minor, + Err(_) => return None, + }; + + Some(Compiler { + minor: minor, + nightly: version.contains("nightly"), + }) +} diff --git a/syn/src/attr.rs b/syn/src/attr.rs new file mode 100644 index 000000000..ae90eaa3a --- /dev/null +++ b/syn/src/attr.rs @@ -0,0 +1,681 @@ +use super::*; +use punctuated::Punctuated; + +use std::iter; + +use proc_macro2::TokenStream; +#[cfg(not(feature = "parsing"))] +use proc_macro2::{Delimiter, Spacing, TokenTree}; + +#[cfg(feature = "parsing")] +use parse::{ParseStream, Result}; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(feature = "extra-traits")] +use tt::TokenStreamHelper; + +ast_struct! { + /// An attribute like `#[repr(transparent)]`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax + /// + /// Rust has six types of attributes. + /// + /// - Outer attributes like `#[repr(transparent)]`. These appear outside or + /// in front of the item they describe. + /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside + /// of the item they describe, usually a module. + /// - Outer doc comments like `/// # Example`. + /// - Inner doc comments like `//! Please file an issue`. + /// - Outer block comments `/** # Example */`. + /// - Inner block comments `/*! Please file an issue */`. + /// + /// The `style` field of type `AttrStyle` distinguishes whether an attribute + /// is outer or inner. Doc comments and block comments are promoted to + /// attributes, as this is how they are processed by the compiler and by + /// `macro_rules!` macros. + /// + /// The `path` field gives the possibly colon-delimited path against which + /// the attribute is resolved. It is equal to `"doc"` for desugared doc + /// comments. The `tts` field contains the rest of the attribute body as + /// tokens. + /// + /// ```text + /// #[derive(Copy)] #[crate::precondition x < 5] + /// ^^^^^^~~~~~~ ^^^^^^^^^^^^^^^^^^^ ~~~~~ + /// path tts path tts + /// ``` + /// + /// Use the [`parse_meta`] method to try parsing the tokens of an attribute + /// into the structured representation that is used by convention across + /// most Rust libraries. + /// + /// [`parse_meta`]: #method.parse_meta + /// + /// # Parsing + /// + /// This type does not implement the [`Parse`] trait and thus cannot be + /// parsed directly by [`ParseStream::parse`]. Instead use + /// [`ParseStream::call`] with one of the two parser functions + /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on + /// which you intend to parse. + /// + /// [`Parse`]: parse/trait.Parse.html + /// [`ParseStream::parse`]: parse/struct.ParseBuffer.html#method.parse + /// [`ParseStream::call`]: parse/struct.ParseBuffer.html#method.call + /// [`Attribute::parse_outer`]: #method.parse_outer + /// [`Attribute::parse_inner`]: #method.parse_inner + /// + /// ```edition2018 + /// use syn::{Attribute, Ident, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a unit struct with attributes. + /// // + /// // #[path = "s.tmpl"] + /// // struct S; + /// struct UnitStruct { + /// attrs: Vec<Attribute>, + /// struct_token: Token![struct], + /// name: Ident, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for UnitStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(UnitStruct { + /// attrs: input.call(Attribute::parse_outer)?, + /// struct_token: input.parse()?, + /// name: input.parse()?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// ``` + pub struct Attribute #manual_extra_traits { + pub pound_token: Token![#], + pub style: AttrStyle, + pub bracket_token: token::Bracket, + pub path: Path, + pub tts: TokenStream, + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Attribute {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Attribute { + fn eq(&self, other: &Self) -> bool { + self.style == other.style + && self.pound_token == other.pound_token + && self.bracket_token == other.bracket_token + && self.path == other.path + && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Attribute { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + self.style.hash(state); + self.pound_token.hash(state); + self.bracket_token.hash(state); + self.path.hash(state); + TokenStreamHelper(&self.tts).hash(state); + } +} + +impl Attribute { + /// Parses the content of the attribute, consisting of the path and tts, as + /// a [`Meta`](enum.Meta.html) if possible. + /// + /// Deprecated; use `parse_meta` instead. + #[doc(hidden)] + pub fn interpret_meta(&self) -> Option<Meta> { + #[cfg(feature = "parsing")] + { + self.parse_meta().ok() + } + + #[cfg(not(feature = "parsing"))] + { + let name = if self.path.segments.len() == 1 { + &self.path.segments.first().unwrap().value().ident + } else { + return None; + }; + + if self.tts.is_empty() { + return Some(Meta::Word(name.clone())); + } + + let tts = self.tts.clone().into_iter().collect::<Vec<_>>(); + + if tts.len() == 1 { + if let Some(meta) = Attribute::extract_meta_list(name.clone(), &tts[0]) { + return Some(meta); + } + } + + if tts.len() == 2 { + if let Some(meta) = Attribute::extract_name_value(name.clone(), &tts[0], &tts[1]) { + return Some(meta); + } + } + + None + } + } + + /// Parses the content of the attribute, consisting of the path and tts, as + /// a [`Meta`](enum.Meta.html) if possible. + #[cfg(feature = "parsing")] + pub fn parse_meta(&self) -> Result<Meta> { + if let Some(ref colon) = self.path.leading_colon { + return Err(Error::new(colon.spans[0], "expected meta identifier")); + } + + let first_segment = self + .path + .segments + .first() + .expect("paths have at least one segment"); + if let Some(colon) = first_segment.punct() { + return Err(Error::new(colon.spans[0], "expected meta value")); + } + let ident = first_segment.value().ident.clone(); + + let parser = |input: ParseStream| parsing::parse_meta_after_ident(ident, input); + parse::Parser::parse2(parser, self.tts.clone()) + } + + /// Parses zero or more outer attributes from the stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { + let mut attrs = Vec::new(); + while input.peek(Token![#]) { + attrs.push(input.call(parsing::single_parse_outer)?); + } + Ok(attrs) + } + + /// Parses zero or more inner attributes from the stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { + let mut attrs = Vec::new(); + while input.peek(Token![#]) && input.peek2(Token![!]) { + attrs.push(input.call(parsing::single_parse_inner)?); + } + Ok(attrs) + } + + #[cfg(not(feature = "parsing"))] + fn extract_meta_list(ident: Ident, tt: &TokenTree) -> Option<Meta> { + let g = match *tt { + TokenTree::Group(ref g) => g, + _ => return None, + }; + if g.delimiter() != Delimiter::Parenthesis { + return None; + } + let tokens = g.stream().clone().into_iter().collect::<Vec<_>>(); + let nested = match list_of_nested_meta_items_from_tokens(&tokens) { + Some(n) => n, + None => return None, + }; + Some(Meta::List(MetaList { + paren_token: token::Paren(g.span()), + ident: ident, + nested: nested, + })) + } + + #[cfg(not(feature = "parsing"))] + fn extract_name_value(ident: Ident, a: &TokenTree, b: &TokenTree) -> Option<Meta> { + let a = match *a { + TokenTree::Punct(ref o) => o, + _ => return None, + }; + if a.spacing() != Spacing::Alone { + return None; + } + if a.as_char() != '=' { + return None; + } + + match *b { + TokenTree::Literal(ref l) if !l.to_string().starts_with('/') => { + Some(Meta::NameValue(MetaNameValue { + ident: ident, + eq_token: Token![=]([a.span()]), + lit: Lit::new(l.clone()), + })) + } + TokenTree::Ident(ref v) => match &v.to_string()[..] { + v @ "true" | v @ "false" => Some(Meta::NameValue(MetaNameValue { + ident: ident, + eq_token: Token![=]([a.span()]), + lit: Lit::Bool(LitBool { + value: v == "true", + span: b.span(), + }), + })), + _ => None, + }, + _ => None, + } + } +} + +#[cfg(not(feature = "parsing"))] +fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMeta, &[TokenTree])> { + assert!(!tts.is_empty()); + + match tts[0] { + TokenTree::Literal(ref lit) => { + if lit.to_string().starts_with('/') { + None + } else { + let lit = Lit::new(lit.clone()); + Some((NestedMeta::Literal(lit), &tts[1..])) + } + } + + TokenTree::Ident(ref ident) => { + if tts.len() >= 3 { + if let Some(meta) = Attribute::extract_name_value(ident.clone(), &tts[1], &tts[2]) { + return Some((NestedMeta::Meta(meta), &tts[3..])); + } + } + + if tts.len() >= 2 { + if let Some(meta) = Attribute::extract_meta_list(ident.clone(), &tts[1]) { + return Some((NestedMeta::Meta(meta), &tts[2..])); + } + } + + let nested_meta = if ident == "true" || ident == "false" { + NestedMeta::Literal(Lit::Bool(LitBool { + value: ident == "true", + span: ident.span(), + })) + } else { + NestedMeta::Meta(Meta::Word(ident.clone())) + }; + Some((nested_meta, &tts[1..])) + } + + _ => None, + } +} + +#[cfg(not(feature = "parsing"))] +fn list_of_nested_meta_items_from_tokens( + mut tts: &[TokenTree], +) -> Option<Punctuated<NestedMeta, Token![,]>> { + let mut nested_meta_items = Punctuated::new(); + let mut first = true; + + while !tts.is_empty() { + let prev_comma = if first { + first = false; + None + } else if let TokenTree::Punct(ref op) = tts[0] { + if op.spacing() != Spacing::Alone { + return None; + } + if op.as_char() != ',' { + return None; + } + let tok = Token![,]([op.span()]); + tts = &tts[1..]; + if tts.is_empty() { + break; + } + Some(tok) + } else { + return None; + }; + let (nested, rest) = match nested_meta_item_from_tokens(tts) { + Some(pair) => pair, + None => return None, + }; + if let Some(comma) = prev_comma { + nested_meta_items.push_punct(comma); + } + nested_meta_items.push_value(nested); + tts = rest; + } + + Some(nested_meta_items) +} + +ast_enum! { + /// Distinguishes between attributes that decorate an item and attributes + /// that are contained within an item. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Outer attributes + /// + /// - `#[repr(transparent)]` + /// - `/// # Example` + /// - `/** Please file an issue */` + /// + /// # Inner attributes + /// + /// - `#![feature(proc_macro)]` + /// - `//! # Example` + /// - `/*! Please file an issue */` + #[cfg_attr(feature = "clone-impls", derive(Copy))] + pub enum AttrStyle { + Outer, + Inner(Token![!]), + } +} + +ast_enum_of_structs! { + /// Content of a compile-time structured attribute. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// ## Word + /// + /// A meta word is like the `test` in `#[test]`. + /// + /// ## List + /// + /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. + /// + /// ## NameValue + /// + /// A name-value meta is like the `path = "..."` in `#[path = + /// "sys/windows.rs"]`. + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Meta { + pub Word(Ident), + /// A structured list within an attribute, like `derive(Copy, Clone)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub List(MetaList { + pub ident: Ident, + pub paren_token: token::Paren, + pub nested: Punctuated<NestedMeta, Token![,]>, + }), + /// A name-value pair within an attribute, like `feature = "nightly"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub NameValue(MetaNameValue { + pub ident: Ident, + pub eq_token: Token![=], + pub lit: Lit, + }), + } +} + +impl Meta { + /// Returns the identifier that begins this structured meta item. + /// + /// For example this would return the `test` in `#[test]`, the `derive` in + /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`. + pub fn name(&self) -> Ident { + match *self { + Meta::Word(ref meta) => meta.clone(), + Meta::List(ref meta) => meta.ident.clone(), + Meta::NameValue(ref meta) => meta.ident.clone(), + } + } +} + +ast_enum_of_structs! { + /// Element of a compile-time attribute list. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum NestedMeta { + /// A structured meta item, like the `Copy` in `#[derive(Copy)]` which + /// would be a nested `Meta::Word`. + pub Meta(Meta), + + /// A Rust literal, like the `"new_name"` in `#[rename("new_name")]`. + pub Literal(Lit), + } +} + +/// Conventional argument type associated with an invocation of an attribute +/// macro. +/// +/// For example if we are developing an attribute macro that is intended to be +/// invoked on function items as follows: +/// +/// ```edition2018 +/// # const IGNORE: &str = stringify! { +/// #[my_attribute(path = "/v1/refresh")] +/// # }; +/// pub fn refresh() { +/// /* ... */ +/// } +/// ``` +/// +/// The implementation of this macro would want to parse its attribute arguments +/// as type `AttributeArgs`. +/// +/// ```edition2018 +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::{parse_macro_input, AttributeArgs, ItemFn}; +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro_attribute] +/// # }; +/// pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream { +/// let args = parse_macro_input!(args as AttributeArgs); +/// let input = parse_macro_input!(input as ItemFn); +/// +/// /* ... */ +/// # "".parse().unwrap() +/// } +/// ``` +pub type AttributeArgs = Vec<NestedMeta>; + +pub trait FilterAttrs<'a> { + type Ret: Iterator<Item = &'a Attribute>; + + fn outer(self) -> Self::Ret; + fn inner(self) -> Self::Ret; +} + +impl<'a, T> FilterAttrs<'a> for T +where + T: IntoIterator<Item = &'a Attribute>, +{ + type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>; + + fn outer(self) -> Self::Ret { + #[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))] + fn is_outer(attr: &&Attribute) -> bool { + match attr.style { + AttrStyle::Outer => true, + _ => false, + } + } + self.into_iter().filter(is_outer) + } + + fn inner(self) -> Self::Ret { + #[cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))] + fn is_inner(attr: &&Attribute) -> bool { + match attr.style { + AttrStyle::Inner(_) => true, + _ => false, + } + } + self.into_iter().filter(is_inner) + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use ext::IdentExt; + use parse::{Parse, ParseStream, Result}; + #[cfg(feature = "full")] + use private; + + pub fn single_parse_inner(input: ParseStream) -> Result<Attribute> { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Inner(input.parse()?), + bracket_token: bracketed!(content in input), + path: content.call(Path::parse_mod_style)?, + tts: content.parse()?, + }) + } + + pub fn single_parse_outer(input: ParseStream) -> Result<Attribute> { + let content; + Ok(Attribute { + pound_token: input.parse()?, + style: AttrStyle::Outer, + bracket_token: bracketed!(content in input), + path: content.call(Path::parse_mod_style)?, + tts: content.parse()?, + }) + } + + #[cfg(feature = "full")] + impl private { + pub fn attrs(outer: Vec<Attribute>, inner: Vec<Attribute>) -> Vec<Attribute> { + let mut attrs = outer; + attrs.extend(inner); + attrs + } + } + + impl Parse for Meta { + fn parse(input: ParseStream) -> Result<Self> { + let ident = input.call(Ident::parse_any)?; + parse_meta_after_ident(ident, input) + } + } + + impl Parse for MetaList { + fn parse(input: ParseStream) -> Result<Self> { + let ident = input.call(Ident::parse_any)?; + parse_meta_list_after_ident(ident, input) + } + } + + impl Parse for MetaNameValue { + fn parse(input: ParseStream) -> Result<Self> { + let ident = input.call(Ident::parse_any)?; + parse_meta_name_value_after_ident(ident, input) + } + } + + impl Parse for NestedMeta { + fn parse(input: ParseStream) -> Result<Self> { + let ahead = input.fork(); + + if ahead.peek(Lit) && !(ahead.peek(LitBool) && ahead.peek2(Token![=])) { + input.parse().map(NestedMeta::Literal) + } else if ahead.call(Ident::parse_any).is_ok() { + input.parse().map(NestedMeta::Meta) + } else { + Err(input.error("expected identifier or literal")) + } + } + } + + pub fn parse_meta_after_ident(ident: Ident, input: ParseStream) -> Result<Meta> { + if input.peek(token::Paren) { + parse_meta_list_after_ident(ident, input).map(Meta::List) + } else if input.peek(Token![=]) { + parse_meta_name_value_after_ident(ident, input).map(Meta::NameValue) + } else { + Ok(Meta::Word(ident)) + } + } + + fn parse_meta_list_after_ident(ident: Ident, input: ParseStream) -> Result<MetaList> { + let content; + Ok(MetaList { + ident: ident, + paren_token: parenthesized!(content in input), + nested: content.parse_terminated(NestedMeta::parse)?, + }) + } + + fn parse_meta_name_value_after_ident( + ident: Ident, + input: ParseStream, + ) -> Result<MetaNameValue> { + Ok(MetaNameValue { + ident: ident, + eq_token: input.parse()?, + lit: input.parse()?, + }) + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use proc_macro2::TokenStream; + use quote::ToTokens; + + impl ToTokens for Attribute { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pound_token.to_tokens(tokens); + if let AttrStyle::Inner(ref b) = self.style { + b.to_tokens(tokens); + } + self.bracket_token.surround(tokens, |tokens| { + self.path.to_tokens(tokens); + self.tts.to_tokens(tokens); + }); + } + } + + impl ToTokens for MetaList { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.nested.to_tokens(tokens); + }) + } + } + + impl ToTokens for MetaNameValue { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.lit.to_tokens(tokens); + } + } +} diff --git a/syn/src/buffer.rs b/syn/src/buffer.rs new file mode 100644 index 000000000..8c326451e --- /dev/null +++ b/syn/src/buffer.rs @@ -0,0 +1,366 @@ +//! A stably addressed token buffer supporting efficient traversal based on a +//! cheaply copyable cursor. +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +// This module is heavily commented as it contains most of the unsafe code in +// Syn, and caution should be used when editing it. The public-facing interface +// is 100% safe but the implementation is fragile internally. + +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" +))] +use proc_macro as pm; +use proc_macro2::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +use std::marker::PhantomData; +use std::ptr; + +use private; +use Lifetime; + +/// Internal type which is used instead of `TokenTree` to represent a token tree +/// within a `TokenBuffer`. +enum Entry { + // Mimicking types from proc-macro. + Group(Group, TokenBuffer), + Ident(Ident), + Punct(Punct), + Literal(Literal), + // End entries contain a raw pointer to the entry from the containing + // token tree, or null if this is the outermost level. + End(*const Entry), +} + +/// A buffer that can be efficiently traversed multiple times, unlike +/// `TokenStream` which requires a deep copy in order to traverse more than +/// once. +/// +/// *This type is available if Syn is built with the `"parsing"` feature.* +pub struct TokenBuffer { + // NOTE: Do not derive clone on this - there are raw pointers inside which + // will be messed up. Moving the `TokenBuffer` itself is safe as the actual + // backing slices won't be moved. + data: Box<[Entry]>, +} + +impl TokenBuffer { + // NOTE: DO NOT MUTATE THE `Vec` RETURNED FROM THIS FUNCTION ONCE IT + // RETURNS, THE ADDRESS OF ITS BACKING MEMORY MUST REMAIN STABLE. + fn inner_new(stream: TokenStream, up: *const Entry) -> TokenBuffer { + // Build up the entries list, recording the locations of any Groups + // in the list to be processed later. + let mut entries = Vec::new(); + let mut seqs = Vec::new(); + for tt in stream { + match tt { + TokenTree::Ident(sym) => { + entries.push(Entry::Ident(sym)); + } + TokenTree::Punct(op) => { + entries.push(Entry::Punct(op)); + } + TokenTree::Literal(l) => { + entries.push(Entry::Literal(l)); + } + TokenTree::Group(g) => { + // Record the index of the interesting entry, and store an + // `End(null)` there temporarially. + seqs.push((entries.len(), g)); + entries.push(Entry::End(ptr::null())); + } + } + } + // Add an `End` entry to the end with a reference to the enclosing token + // stream which was passed in. + entries.push(Entry::End(up)); + + // NOTE: This is done to ensure that we don't accidentally modify the + // length of the backing buffer. The backing buffer must remain at a + // constant address after this point, as we are going to store a raw + // pointer into it. + let mut entries = entries.into_boxed_slice(); + for (idx, group) in seqs { + // We know that this index refers to one of the temporary + // `End(null)` entries, and we know that the last entry is + // `End(up)`, so the next index is also valid. + let seq_up = &entries[idx + 1] as *const Entry; + + // The end entry stored at the end of this Entry::Group should + // point to the Entry which follows the Group in the list. + let inner = Self::inner_new(group.stream(), seq_up); + entries[idx] = Entry::Group(group, inner); + } + + TokenBuffer { data: entries } + } + + /// Creates a `TokenBuffer` containing all the tokens from the input + /// `TokenStream`. + /// + /// *This method is available if Syn is built with both the `"parsing"` and + /// `"proc-macro"` features.* + #[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" + ))] + pub fn new(stream: pm::TokenStream) -> TokenBuffer { + Self::new2(stream.into()) + } + + /// Creates a `TokenBuffer` containing all the tokens from the input + /// `TokenStream`. + pub fn new2(stream: TokenStream) -> TokenBuffer { + Self::inner_new(stream, ptr::null()) + } + + /// Creates a cursor referencing the first token in the buffer and able to + /// traverse until the end of the buffer. + pub fn begin(&self) -> Cursor { + unsafe { Cursor::create(&self.data[0], &self.data[self.data.len() - 1]) } + } +} + +/// A cheaply copyable cursor into a `TokenBuffer`. +/// +/// This cursor holds a shared reference into the immutable data which is used +/// internally to represent a `TokenStream`, and can be efficiently manipulated +/// and copied around. +/// +/// An empty `Cursor` can be created directly, or one may create a `TokenBuffer` +/// object and get a cursor to its first token with `begin()`. +/// +/// Two cursors are equal if they have the same location in the same input +/// stream, and have the same scope. +/// +/// *This type is available if Syn is built with the `"parsing"` feature.* +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct Cursor<'a> { + // The current entry which the `Cursor` is pointing at. + ptr: *const Entry, + // This is the only `Entry::End(..)` object which this cursor is allowed to + // point at. All other `End` objects are skipped over in `Cursor::create`. + scope: *const Entry, + // Cursor is covariant in 'a. This field ensures that our pointers are still + // valid. + marker: PhantomData<&'a Entry>, +} + +impl<'a> Cursor<'a> { + /// Creates a cursor referencing a static empty TokenStream. + pub fn empty() -> Self { + // It's safe in this situation for us to put an `Entry` object in global + // storage, despite it not actually being safe to send across threads + // (`Ident` is a reference into a thread-local table). This is because + // this entry never includes a `Ident` object. + // + // This wrapper struct allows us to break the rules and put a `Sync` + // object in global storage. + struct UnsafeSyncEntry(Entry); + unsafe impl Sync for UnsafeSyncEntry {} + static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0 as *const Entry)); + + Cursor { + ptr: &EMPTY_ENTRY.0, + scope: &EMPTY_ENTRY.0, + marker: PhantomData, + } + } + + /// This create method intelligently exits non-explicitly-entered + /// `None`-delimited scopes when the cursor reaches the end of them, + /// allowing for them to be treated transparently. + unsafe fn create(mut ptr: *const Entry, scope: *const Entry) -> Self { + // NOTE: If we're looking at a `End(..)`, we want to advance the cursor + // past it, unless `ptr == scope`, which means that we're at the edge of + // our cursor's scope. We should only have `ptr != scope` at the exit + // from None-delimited groups entered with `ignore_none`. + while let Entry::End(exit) = *ptr { + if ptr == scope { + break; + } + ptr = exit; + } + + Cursor { + ptr: ptr, + scope: scope, + marker: PhantomData, + } + } + + /// Get the current entry. + fn entry(self) -> &'a Entry { + unsafe { &*self.ptr } + } + + /// Bump the cursor to point at the next token after the current one. This + /// is undefined behavior if the cursor is currently looking at an + /// `Entry::End`. + unsafe fn bump(self) -> Cursor<'a> { + Cursor::create(self.ptr.offset(1), self.scope) + } + + /// If the cursor is looking at a `None`-delimited group, move it to look at + /// the first token inside instead. If the group is empty, this will move + /// the cursor past the `None`-delimited group. + /// + /// WARNING: This mutates its argument. + fn ignore_none(&mut self) { + if let Entry::Group(ref group, ref buf) = *self.entry() { + if group.delimiter() == Delimiter::None { + // NOTE: We call `Cursor::create` here to make sure that + // situations where we should immediately exit the span after + // entering it are handled correctly. + unsafe { + *self = Cursor::create(&buf.data[0], self.scope); + } + } + } + } + + /// Checks whether the cursor is currently pointing at the end of its valid + /// scope. + #[inline] + pub fn eof(self) -> bool { + // We're at eof if we're at the end of our scope. + self.ptr == self.scope + } + + /// If the cursor is pointing at a `Group` with the given delimiter, returns + /// a cursor into that group and one pointing to the next `TokenTree`. + pub fn group(mut self, delim: Delimiter) -> Option<(Cursor<'a>, Span, Cursor<'a>)> { + // If we're not trying to enter a none-delimited group, we want to + // ignore them. We have to make sure to _not_ ignore them when we want + // to enter them, of course. For obvious reasons. + if delim != Delimiter::None { + self.ignore_none(); + } + + if let Entry::Group(ref group, ref buf) = *self.entry() { + if group.delimiter() == delim { + return Some((buf.begin(), group.span(), unsafe { self.bump() })); + } + } + + None + } + + /// If the cursor is pointing at a `Ident`, returns it along with a cursor + /// pointing at the next `TokenTree`. + pub fn ident(mut self) -> Option<(Ident, Cursor<'a>)> { + self.ignore_none(); + match *self.entry() { + Entry::Ident(ref ident) => Some((ident.clone(), unsafe { self.bump() })), + _ => None, + } + } + + /// If the cursor is pointing at an `Punct`, returns it along with a cursor + /// pointing at the next `TokenTree`. + pub fn punct(mut self) -> Option<(Punct, Cursor<'a>)> { + self.ignore_none(); + match *self.entry() { + Entry::Punct(ref op) if op.as_char() != '\'' => { + Some((op.clone(), unsafe { self.bump() })) + } + _ => None, + } + } + + /// If the cursor is pointing at a `Literal`, return it along with a cursor + /// pointing at the next `TokenTree`. + pub fn literal(mut self) -> Option<(Literal, Cursor<'a>)> { + self.ignore_none(); + match *self.entry() { + Entry::Literal(ref lit) => Some((lit.clone(), unsafe { self.bump() })), + _ => None, + } + } + + /// If the cursor is pointing at a `Lifetime`, returns it along with a + /// cursor pointing at the next `TokenTree`. + pub fn lifetime(mut self) -> Option<(Lifetime, Cursor<'a>)> { + self.ignore_none(); + match *self.entry() { + Entry::Punct(ref op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { + let next = unsafe { self.bump() }; + match next.ident() { + Some((ident, rest)) => { + let lifetime = Lifetime { + apostrophe: op.span(), + ident: ident, + }; + Some((lifetime, rest)) + } + None => None, + } + } + _ => None, + } + } + + /// Copies all remaining tokens visible from this cursor into a + /// `TokenStream`. + pub fn token_stream(self) -> TokenStream { + let mut tts = Vec::new(); + let mut cursor = self; + while let Some((tt, rest)) = cursor.token_tree() { + tts.push(tt); + cursor = rest; + } + tts.into_iter().collect() + } + + /// If the cursor is pointing at a `TokenTree`, returns it along with a + /// cursor pointing at the next `TokenTree`. + /// + /// Returns `None` if the cursor has reached the end of its stream. + /// + /// This method does not treat `None`-delimited groups as transparent, and + /// will return a `Group(None, ..)` if the cursor is looking at one. + pub fn token_tree(self) -> Option<(TokenTree, Cursor<'a>)> { + let tree = match *self.entry() { + Entry::Group(ref group, _) => group.clone().into(), + Entry::Literal(ref lit) => lit.clone().into(), + Entry::Ident(ref ident) => ident.clone().into(), + Entry::Punct(ref op) => op.clone().into(), + Entry::End(..) => { + return None; + } + }; + + Some((tree, unsafe { self.bump() })) + } + + /// Returns the `Span` of the current token, or `Span::call_site()` if this + /// cursor points to eof. + pub fn span(self) -> Span { + match *self.entry() { + Entry::Group(ref group, _) => group.span(), + Entry::Literal(ref l) => l.span(), + Entry::Ident(ref t) => t.span(), + Entry::Punct(ref o) => o.span(), + Entry::End(..) => Span::call_site(), + } + } +} + +impl private { + #[cfg(procmacro2_semver_exempt)] + pub fn open_span_of_group(cursor: Cursor) -> Span { + match *cursor.entry() { + Entry::Group(ref group, _) => group.span_open(), + _ => cursor.span(), + } + } + + #[cfg(procmacro2_semver_exempt)] + pub fn close_span_of_group(cursor: Cursor) -> Span { + match *cursor.entry() { + Entry::Group(ref group, _) => group.span_close(), + _ => cursor.span(), + } + } +} diff --git a/syn/src/custom_keyword.rs b/syn/src/custom_keyword.rs new file mode 100644 index 000000000..ab3d5b64f --- /dev/null +++ b/syn/src/custom_keyword.rs @@ -0,0 +1,252 @@ +/// Define a type that supports parsing and printing a given identifier as if it +/// were a keyword. +/// +/// # Usage +/// +/// As a convention, it is recommended that this macro be invoked within a +/// module called `kw` or `keyword` and that the resulting parser be invoked +/// with a `kw::` or `keyword::` prefix. +/// +/// ```edition2018 +/// mod kw { +/// syn::custom_keyword!(whatever); +/// } +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in keyword token. +/// +/// - [Peeking] — `input.peek(kw::whatever)` +/// +/// - [Parsing] — `input.parse::<kw::whatever>()?` +/// +/// - [Printing] — `quote!( ... #whatever_token ... )` +/// +/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)` +/// +/// - Field access to its span — `let sp = whatever_token.span` +/// +/// [Peeking]: parse/struct.ParseBuffer.html#method.peek +/// [Parsing]: parse/struct.ParseBuffer.html#method.parse +/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html +/// +/// # Example +/// +/// This example parses input that looks like `bool = true` or `str = "value"`. +/// The key must be either the identifier `bool` or the identifier `str`. If +/// `bool`, the value may be either `true` or `false`. If `str`, the value may +/// be any string literal. +/// +/// The symbols `bool` and `str` are not reserved keywords in Rust so these are +/// not considered keywords in the `syn::token` module. Like any other +/// identifier that is not a keyword, these can be declared as custom keywords +/// by crates that need to use them as such. +/// +/// ```edition2018 +/// use syn::{LitBool, LitStr, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// mod kw { +/// syn::custom_keyword!(bool); +/// syn::custom_keyword!(str); +/// } +/// +/// enum Argument { +/// Bool { +/// bool_token: kw::bool, +/// eq_token: Token![=], +/// value: LitBool, +/// }, +/// Str { +/// str_token: kw::str, +/// eq_token: Token![=], +/// value: LitStr, +/// }, +/// } +/// +/// impl Parse for Argument { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(kw::bool) { +/// Ok(Argument::Bool { +/// bool_token: input.parse::<kw::bool>()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else if lookahead.peek(kw::str) { +/// Ok(Argument::Str { +/// str_token: input.parse::<kw::str>()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_keyword { + ($ident:ident) => { + #[allow(non_camel_case_types)] + pub struct $ident { + pub span: $crate::export::Span, + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>( + span: __S, + ) -> $ident { + $ident { + span: $crate::export::IntoSpans::into_spans(span)[0], + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident { + span: $crate::export::Span::call_site(), + } + } + } + + impl_parse_for_custom_keyword!($ident); + impl_to_tokens_for_custom_keyword!($ident); + impl_clone_for_custom_keyword!($ident); + impl_extra_traits_for_custom_keyword!($ident); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => { + // For peek. + impl $crate::token::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> $crate::export::bool { + if let Some((ident, _rest)) = cursor.ident() { + ident == stringify!($ident) + } else { + false + } + } + + fn display() -> &'static $crate::export::str { + concat!("`", stringify!($ident), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + input.step(|cursor| { + if let $crate::export::Some((ident, rest)) = cursor.ident() { + if ident == stringify!($ident) { + return $crate::export::Ok(($ident { span: ident.span() }, rest)); + } + } + $crate::export::Err(cursor.error(concat!( + "expected `", + stringify!($ident), + "`" + ))) + }) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + let ident = $crate::Ident::new(stringify!($ident), self.span); + $crate::export::TokenStreamExt::append(tokens, ident); + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::Debug for $ident { + fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { + $crate::export::Formatter::write_str( + f, + concat!("Keyword [", stringify!($ident), "]"), + ) + } + } + + impl $crate::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => {}; +} diff --git a/syn/src/custom_punctuation.rs b/syn/src/custom_punctuation.rs new file mode 100644 index 000000000..8d7d4443f --- /dev/null +++ b/syn/src/custom_punctuation.rs @@ -0,0 +1,309 @@ +/// Define a type that supports parsing and printing a multi-character symbol +/// as if it were a punctuation token. +/// +/// # Usage +/// +/// ```edition2018 +/// syn::custom_punctuation!(LeftRightArrow, <=>); +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in punctuation token. +/// +/// - [Peeking] — `input.peek(LeftRightArrow)` +/// +/// - [Parsing] — `input.parse::<LeftRightArrow>()?` +/// +/// - [Printing] — `quote!( ... #lrarrow ... )` +/// +/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)` +/// +/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])` +/// +/// - Field access to its spans — `let spans = lrarrow.spans` +/// +/// [Peeking]: parse/struct.ParseBuffer.html#method.peek +/// [Parsing]: parse/struct.ParseBuffer.html#method.parse +/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html +/// +/// # Example +/// +/// ```edition2018 +/// use proc_macro2::{TokenStream, TokenTree}; +/// use syn::parse::{Parse, ParseStream, Peek, Result}; +/// use syn::punctuated::Punctuated; +/// use syn::Expr; +/// +/// syn::custom_punctuation!(PathSeparator, </>); +/// +/// // expr </> expr </> expr ... +/// struct PathSegments { +/// segments: Punctuated<Expr, PathSeparator>, +/// } +/// +/// impl Parse for PathSegments { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let mut segments = Punctuated::new(); +/// +/// let first = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(first)?); +/// +/// while input.peek(PathSeparator) { +/// segments.push_punct(input.parse()?); +/// +/// let next = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(next)?); +/// } +/// +/// Ok(PathSegments { segments }) +/// } +/// } +/// +/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> { +/// let mut tokens = TokenStream::new(); +/// while !input.is_empty() && !input.peek(end) { +/// let next: TokenTree = input.parse()?; +/// tokens.extend(Some(next)); +/// } +/// Ok(tokens) +/// } +/// +/// fn main() { +/// let input = r#" a::b </> c::d::e "#; +/// let _: PathSegments = syn::parse_str(input).unwrap(); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + pub struct $ident { + pub spans: custom_punctuation_repr!($($tt)+), + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>( + spans: __S, + ) -> $ident { + let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*; + $ident { + spans: $crate::export::IntoSpans::into_spans(spans) + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident($crate::export::Span::call_site()) + } + } + + impl_parse_for_custom_punctuation!($ident, $($tt)+); + impl_to_tokens_for_custom_punctuation!($ident, $($tt)+); + impl_clone_for_custom_punctuation!($ident, $($tt)+); + impl_extra_traits_for_custom_punctuation!($ident, $($tt)+); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::token::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> bool { + $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+)) + } + + fn display() -> &'static $crate::export::str { + custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + let spans: custom_punctuation_repr!($($tt)+) = + $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?; + Ok($ident(spans)) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::Debug for $ident { + fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { + $crate::export::Formatter::write_str(f, stringify!($ident)) + } + } + + impl $crate::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation_repr { + ($($tt:tt)+) => { + [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+] + }; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +#[cfg_attr(rustfmt, rustfmt_skip)] +macro_rules! custom_punctuation_len { + ($mode:ident, +) => { 1 }; + ($mode:ident, +=) => { 2 }; + ($mode:ident, &) => { 1 }; + ($mode:ident, &&) => { 2 }; + ($mode:ident, &=) => { 2 }; + ($mode:ident, @) => { 1 }; + ($mode:ident, !) => { 1 }; + ($mode:ident, ^) => { 1 }; + ($mode:ident, ^=) => { 2 }; + ($mode:ident, :) => { 1 }; + ($mode:ident, ::) => { 2 }; + ($mode:ident, ,) => { 1 }; + ($mode:ident, /) => { 1 }; + ($mode:ident, /=) => { 2 }; + ($mode:ident, .) => { 1 }; + ($mode:ident, ..) => { 2 }; + ($mode:ident, ...) => { 3 }; + ($mode:ident, ..=) => { 3 }; + ($mode:ident, =) => { 1 }; + ($mode:ident, ==) => { 2 }; + ($mode:ident, >=) => { 2 }; + ($mode:ident, >) => { 1 }; + ($mode:ident, <=) => { 2 }; + ($mode:ident, <) => { 1 }; + ($mode:ident, *=) => { 2 }; + ($mode:ident, !=) => { 2 }; + ($mode:ident, |) => { 1 }; + ($mode:ident, |=) => { 2 }; + ($mode:ident, ||) => { 2 }; + ($mode:ident, #) => { 1 }; + ($mode:ident, ?) => { 1 }; + ($mode:ident, ->) => { 2 }; + ($mode:ident, <-) => { 2 }; + ($mode:ident, %) => { 1 }; + ($mode:ident, %=) => { 2 }; + ($mode:ident, =>) => { 2 }; + ($mode:ident, ;) => { 1 }; + ($mode:ident, <<) => { 2 }; + ($mode:ident, <<=) => { 3 }; + ($mode:ident, >>) => { 2 }; + ($mode:ident, >>=) => { 3 }; + ($mode:ident, *) => { 1 }; + ($mode:ident, -) => { 1 }; + ($mode:ident, -=) => { 2 }; + ($mode:ident, ~) => { 1 }; + (lenient, $tt:tt) => { 0 }; + (strict, $tt:tt) => {{ custom_punctuation_unexpected!($tt); 0 }}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_unexpected { + () => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! stringify_punct { + ($($tt:tt)+) => { + concat!($(stringify!($tt)),+) + }; +} + +// Not public API. +// Without this, local_inner_macros breaks when looking for concat! +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_concat { + ($($tt:tt)*) => { + concat!($($tt)*) + }; +} diff --git a/syn/src/data.rs b/syn/src/data.rs new file mode 100644 index 000000000..f54f5b9af --- /dev/null +++ b/syn/src/data.rs @@ -0,0 +1,384 @@ +use super::*; +use punctuated::Punctuated; + +ast_struct! { + /// An enum variant. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Variant { + /// Attributes tagged on the variant. + pub attrs: Vec<Attribute>, + + /// Name of the variant. + pub ident: Ident, + + /// Content stored in the variant. + pub fields: Fields, + + /// Explicit discriminant: `Variant = 1` + pub discriminant: Option<(Token![=], Expr)>, + } +} + +ast_enum_of_structs! { + /// Data stored within an enum variant or struct. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Fields { + /// Named fields of a struct or struct variant such as `Point { x: f64, + /// y: f64 }`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Named(FieldsNamed { + pub brace_token: token::Brace, + pub named: Punctuated<Field, Token![,]>, + }), + + /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Unnamed(FieldsUnnamed { + pub paren_token: token::Paren, + pub unnamed: Punctuated<Field, Token![,]>, + }), + + /// Unit struct or unit variant such as `None`. + pub Unit, + } +} + +impl Fields { + /// Get an iterator over the borrowed [`Field`] items in this object. This + /// iterator can be used to iterate over a named or unnamed struct or + /// variant's fields uniformly. + /// + /// [`Field`]: struct.Field.html + pub fn iter(&self) -> punctuated::Iter<Field> { + match *self { + Fields::Unit => private::empty_punctuated_iter(), + Fields::Named(ref f) => f.named.iter(), + Fields::Unnamed(ref f) => f.unnamed.iter(), + } + } + + /// Get an iterator over the mutably borrowed [`Field`] items in this + /// object. This iterator can be used to iterate over a named or unnamed + /// struct or variant's fields uniformly. + /// + /// [`Field`]: struct.Field.html + pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> { + match *self { + Fields::Unit => private::empty_punctuated_iter_mut(), + Fields::Named(ref mut f) => f.named.iter_mut(), + Fields::Unnamed(ref mut f) => f.unnamed.iter_mut(), + } + } +} + +impl<'a> IntoIterator for &'a Fields { + type Item = &'a Field; + type IntoIter = punctuated::Iter<'a, Field>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a> IntoIterator for &'a mut Fields { + type Item = &'a mut Field; + type IntoIter = punctuated::IterMut<'a, Field>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +ast_struct! { + /// A field of a struct or enum variant. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Field { + /// Attributes tagged on the field. + pub attrs: Vec<Attribute>, + + /// Visibility of the field. + pub vis: Visibility, + + /// Name of the field, if any. + /// + /// Fields of tuple structs have no names. + pub ident: Option<Ident>, + + pub colon_token: Option<Token![:]>, + + /// Type of the field. + pub ty: Type, + } +} + +ast_enum_of_structs! { + /// The visibility level of an item: inherited or `pub` or + /// `pub(restricted)`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Visibility { + /// A public visibility level: `pub`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Public(VisPublic { + pub pub_token: Token![pub], + }), + + /// A crate-level visibility: `crate`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Crate(VisCrate { + pub crate_token: Token![crate], + }), + + /// A visibility level restricted to some path: `pub(self)` or + /// `pub(super)` or `pub(crate)` or `pub(in some::module)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Restricted(VisRestricted { + pub pub_token: Token![pub], + pub paren_token: token::Paren, + pub in_token: Option<Token![in]>, + pub path: Box<Path>, + }), + + /// An inherited visibility, which usually means private. + pub Inherited, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use ext::IdentExt; + use parse::{Parse, ParseStream, Result}; + + impl Parse for Variant { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Variant { + attrs: input.call(Attribute::parse_outer)?, + ident: input.parse()?, + fields: { + if input.peek(token::Brace) { + Fields::Named(input.parse()?) + } else if input.peek(token::Paren) { + Fields::Unnamed(input.parse()?) + } else { + Fields::Unit + } + }, + discriminant: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let discriminant: Expr = input.parse()?; + Some((eq_token, discriminant)) + } else { + None + } + }, + }) + } + } + + impl Parse for FieldsNamed { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(FieldsNamed { + brace_token: braced!(content in input), + named: content.parse_terminated(Field::parse_named)?, + }) + } + } + + impl Parse for FieldsUnnamed { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(FieldsUnnamed { + paren_token: parenthesized!(content in input), + unnamed: content.parse_terminated(Field::parse_unnamed)?, + }) + } + } + + impl Field { + /// Parses a named (braced struct) field. + pub fn parse_named(input: ParseStream) -> Result<Self> { + Ok(Field { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + ident: Some(input.parse()?), + colon_token: Some(input.parse()?), + ty: input.parse()?, + }) + } + + /// Parses an unnamed (tuple struct) field. + pub fn parse_unnamed(input: ParseStream) -> Result<Self> { + Ok(Field { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + ident: None, + colon_token: None, + ty: input.parse()?, + }) + } + } + + impl Parse for Visibility { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![pub]) { + Self::parse_pub(input) + } else if input.peek(Token![crate]) { + Self::parse_crate(input) + } else { + Ok(Visibility::Inherited) + } + } + } + + impl Visibility { + fn parse_pub(input: ParseStream) -> Result<Self> { + let pub_token = input.parse::<Token![pub]>()?; + + if input.peek(token::Paren) { + let ahead = input.fork(); + let mut content; + parenthesized!(content in ahead); + + if content.peek(Token![crate]) + || content.peek(Token![self]) + || content.peek(Token![super]) + { + return Ok(Visibility::Restricted(VisRestricted { + pub_token: pub_token, + paren_token: parenthesized!(content in input), + in_token: None, + path: Box::new(Path::from(content.call(Ident::parse_any)?)), + })); + } else if content.peek(Token![in]) { + return Ok(Visibility::Restricted(VisRestricted { + pub_token: pub_token, + paren_token: parenthesized!(content in input), + in_token: Some(content.parse()?), + path: Box::new(content.call(Path::parse_mod_style)?), + })); + } + } + + Ok(Visibility::Public(VisPublic { + pub_token: pub_token, + })) + } + + fn parse_crate(input: ParseStream) -> Result<Self> { + if input.peek2(Token![::]) { + Ok(Visibility::Inherited) + } else { + Ok(Visibility::Crate(VisCrate { + crate_token: input.parse()?, + })) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use print::TokensOrDefault; + + impl ToTokens for Variant { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.ident.to_tokens(tokens); + self.fields.to_tokens(tokens); + if let Some((ref eq_token, ref disc)) = self.discriminant { + eq_token.to_tokens(tokens); + disc.to_tokens(tokens); + } + } + } + + impl ToTokens for FieldsNamed { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + self.named.to_tokens(tokens); + }); + } + } + + impl ToTokens for FieldsUnnamed { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.unnamed.to_tokens(tokens); + }); + } + } + + impl ToTokens for Field { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.vis.to_tokens(tokens); + if let Some(ref ident) = self.ident { + ident.to_tokens(tokens); + TokensOrDefault(&self.colon_token).to_tokens(tokens); + } + self.ty.to_tokens(tokens); + } + } + + impl ToTokens for VisPublic { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pub_token.to_tokens(tokens) + } + } + + impl ToTokens for VisCrate { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.crate_token.to_tokens(tokens); + } + } + + impl ToTokens for VisRestricted { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pub_token.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + // TODO: If we have a path which is not "self" or "super" or + // "crate", automatically add the "in" token. + self.in_token.to_tokens(tokens); + self.path.to_tokens(tokens); + }); + } + } +} diff --git a/syn/src/derive.rs b/syn/src/derive.rs new file mode 100644 index 000000000..48ae7e46e --- /dev/null +++ b/syn/src/derive.rs @@ -0,0 +1,255 @@ +use super::*; +use punctuated::Punctuated; + +ast_struct! { + /// Data structure sent to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` feature.* + pub struct DeriveInput { + /// Attributes tagged on the whole struct or enum. + pub attrs: Vec<Attribute>, + + /// Visibility of the struct or enum. + pub vis: Visibility, + + /// Name of the struct or enum. + pub ident: Ident, + + /// Generics required to complete the definition. + pub generics: Generics, + + /// Data within the struct or enum. + pub data: Data, + } +} + +ast_enum_of_structs! { + /// The storage of a struct, enum or union data structure. + /// + /// *This type is available if Syn is built with the `"derive"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Data { + /// A struct input to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` + /// feature.* + pub Struct(DataStruct { + pub struct_token: Token![struct], + pub fields: Fields, + pub semi_token: Option<Token![;]>, + }), + + /// An enum input to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` + /// feature.* + pub Enum(DataEnum { + pub enum_token: Token![enum], + pub brace_token: token::Brace, + pub variants: Punctuated<Variant, Token![,]>, + }), + + /// A tagged union input to a `proc_macro_derive` macro. + /// + /// *This type is available if Syn is built with the `"derive"` + /// feature.* + pub Union(DataUnion { + pub union_token: Token![union], + pub fields: FieldsNamed, + }), + } + + do_not_generate_to_tokens +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + impl Parse for DeriveInput { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![struct]) { + let struct_token = input.parse::<Token![struct]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields, semi) = data_struct(input)?; + Ok(DeriveInput { + attrs: attrs, + vis: vis, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + data: Data::Struct(DataStruct { + struct_token: struct_token, + fields: fields, + semi_token: semi, + }), + }) + } else if lookahead.peek(Token![enum]) { + let enum_token = input.parse::<Token![enum]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, brace, variants) = data_enum(input)?; + Ok(DeriveInput { + attrs: attrs, + vis: vis, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + data: Data::Enum(DataEnum { + enum_token: enum_token, + brace_token: brace, + variants: variants, + }), + }) + } else if lookahead.peek(Token![union]) { + let union_token = input.parse::<Token![union]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields) = data_union(input)?; + Ok(DeriveInput { + attrs: attrs, + vis: vis, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + data: Data::Union(DataUnion { + union_token: union_token, + fields: fields, + }), + }) + } else { + Err(lookahead.error()) + } + } + } + + pub fn data_struct( + input: ParseStream, + ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> { + let mut lookahead = input.lookahead1(); + let mut where_clause = None; + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if where_clause.is_none() && lookahead.peek(token::Paren) { + let fields = input.parse()?; + + lookahead = input.lookahead1(); + if lookahead.peek(Token![where]) { + where_clause = Some(input.parse()?); + lookahead = input.lookahead1(); + } + + if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unnamed(fields), Some(semi))) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(token::Brace) { + let fields = input.parse()?; + Ok((where_clause, Fields::Named(fields), None)) + } else if lookahead.peek(Token![;]) { + let semi = input.parse()?; + Ok((where_clause, Fields::Unit, Some(semi))) + } else { + Err(lookahead.error()) + } + } + + pub fn data_enum( + input: ParseStream, + ) -> Result<( + Option<WhereClause>, + token::Brace, + Punctuated<Variant, Token![,]>, + )> { + let where_clause = input.parse()?; + + let content; + let brace = braced!(content in input); + let variants = content.parse_terminated(Variant::parse)?; + + Ok((where_clause, brace, variants)) + } + + pub fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> { + let where_clause = input.parse()?; + let fields = input.parse()?; + Ok((where_clause, fields)) + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::ToTokens; + + use attr::FilterAttrs; + use print::TokensOrDefault; + + impl ToTokens for DeriveInput { + fn to_tokens(&self, tokens: &mut TokenStream) { + for attr in self.attrs.outer() { + attr.to_tokens(tokens); + } + self.vis.to_tokens(tokens); + match self.data { + Data::Struct(ref d) => d.struct_token.to_tokens(tokens), + Data::Enum(ref d) => d.enum_token.to_tokens(tokens), + Data::Union(ref d) => d.union_token.to_tokens(tokens), + } + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + match self.data { + Data::Struct(ref data) => match data.fields { + Fields::Named(ref fields) => { + self.generics.where_clause.to_tokens(tokens); + fields.to_tokens(tokens); + } + Fields::Unnamed(ref fields) => { + fields.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&data.semi_token).to_tokens(tokens); + } + Fields::Unit => { + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&data.semi_token).to_tokens(tokens); + } + }, + Data::Enum(ref data) => { + self.generics.where_clause.to_tokens(tokens); + data.brace_token.surround(tokens, |tokens| { + data.variants.to_tokens(tokens); + }); + } + Data::Union(ref data) => { + self.generics.where_clause.to_tokens(tokens); + data.fields.to_tokens(tokens); + } + } + } + } +} diff --git a/syn/src/error.rs b/syn/src/error.rs new file mode 100644 index 000000000..097a6b84a --- /dev/null +++ b/syn/src/error.rs @@ -0,0 +1,221 @@ +use std; +use std::fmt::{self, Debug, Display}; +use std::iter::FromIterator; + +use proc_macro2::{ + Delimiter, Group, Ident, LexError, Literal, Punct, Spacing, Span, TokenStream, TokenTree, +}; +#[cfg(feature = "printing")] +use quote::ToTokens; + +#[cfg(feature = "parsing")] +use buffer::Cursor; +#[cfg(all(procmacro2_semver_exempt, feature = "parsing"))] +use private; +use thread::ThreadBound; + +/// The result of a Syn parser. +pub type Result<T> = std::result::Result<T, Error>; + +/// Error returned when a Syn parser cannot parse the input tokens. +/// +/// Refer to the [module documentation] for details about parsing in Syn. +/// +/// [module documentation]: index.html +/// +/// *This type is available if Syn is built with the `"parsing"` feature.* +pub struct Error { + // Span is implemented as an index into a thread-local interner to keep the + // size small. It is not safe to access from a different thread. We want + // errors to be Send and Sync to play nicely with the Failure crate, so pin + // the span we're given to its original thread and assume it is + // Span::call_site if accessed from any other thread. + start_span: ThreadBound<Span>, + end_span: ThreadBound<Span>, + message: String, +} + +#[cfg(test)] +struct _Test +where + Error: Send + Sync; + +impl Error { + /// Usually the [`ParseStream::error`] method will be used instead, which + /// automatically uses the correct span from the current position of the + /// parse stream. + /// + /// Use `Error::new` when the error needs to be triggered on some span other + /// than where the parse stream is currently positioned. + /// + /// [`ParseStream::error`]: struct.ParseBuffer.html#method.error + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{Error, Ident, LitStr, Result, Token}; + /// use syn::parse::ParseStream; + /// + /// // Parses input that looks like `name = "string"` where the key must be + /// // the identifier `name` and the value may be any string literal. + /// // Returns the string literal. + /// fn parse_name(input: ParseStream) -> Result<LitStr> { + /// let name_token: Ident = input.parse()?; + /// if name_token != "name" { + /// // Trigger an error not on the current position of the stream, + /// // but on the position of the unexpected identifier. + /// return Err(Error::new(name_token.span(), "expected `name`")); + /// } + /// input.parse::<Token![=]>()?; + /// let s: LitStr = input.parse()?; + /// Ok(s) + /// } + /// ``` + pub fn new<T: Display>(span: Span, message: T) -> Self { + Error { + start_span: ThreadBound::new(span), + end_span: ThreadBound::new(span), + message: message.to_string(), + } + } + + /// Creates an error with the specified message spanning the given syntax + /// tree node. + /// + /// Unlike the `Error::new` constructor, this constructor takes an argument + /// `tokens` which is a syntax tree node. This allows the resulting `Error` + /// to attempt to span all tokens inside of `tokens`. While you would + /// typically be able to use the `Spanned` trait with the above `Error::new` + /// constructor, implementation limitations today mean that + /// `Error::new_spanned` may provide a higher-quality error message on + /// stable Rust. + /// + /// When in doubt it's recommended to stick to `Error::new` (or + /// `ParseStream::error`)! + #[cfg(feature = "printing")] + pub fn new_spanned<T: ToTokens, U: Display>(tokens: T, message: U) -> Self { + let mut iter = tokens.into_token_stream().into_iter(); + let start = iter.next().map_or_else(Span::call_site, |t| t.span()); + let end = iter.last().map_or(start, |t| t.span()); + Error { + start_span: ThreadBound::new(start), + end_span: ThreadBound::new(end), + message: message.to_string(), + } + } + + /// The source location of the error. + /// + /// Spans are not thread-safe so this function returns `Span::call_site()` + /// if called from a different thread than the one on which the `Error` was + /// originally created. + pub fn span(&self) -> Span { + let start = match self.start_span.get() { + Some(span) => *span, + None => return Span::call_site(), + }; + + #[cfg(procmacro2_semver_exempt)] + { + let end = match self.end_span.get() { + Some(span) => *span, + None => return Span::call_site(), + }; + start.join(end).unwrap_or(start) + } + #[cfg(not(procmacro2_semver_exempt))] + { + start + } + } + + /// Render the error as an invocation of [`compile_error!`]. + /// + /// The [`parse_macro_input!`] macro provides a convenient way to invoke + /// this method correctly in a procedural macro. + /// + /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html + /// [`parse_macro_input!`]: ../macro.parse_macro_input.html + pub fn to_compile_error(&self) -> TokenStream { + let start = self + .start_span + .get() + .cloned() + .unwrap_or_else(Span::call_site); + let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site); + + // compile_error!($message) + TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("compile_error", start)), + TokenTree::Punct({ + let mut punct = Punct::new('!', Spacing::Alone); + punct.set_span(start); + punct + }), + TokenTree::Group({ + let mut group = Group::new(Delimiter::Brace, { + TokenStream::from_iter(vec![TokenTree::Literal({ + let mut string = Literal::string(&self.message); + string.set_span(end); + string + })]) + }); + group.set_span(end); + group + }), + ]) + } +} + +#[cfg(feature = "parsing")] +pub fn new_at<T: Display>(scope: Span, cursor: Cursor, message: T) -> Error { + if cursor.eof() { + Error::new(scope, format!("unexpected end of input, {}", message)) + } else { + #[cfg(procmacro2_semver_exempt)] + let span = private::open_span_of_group(cursor); + #[cfg(not(procmacro2_semver_exempt))] + let span = cursor.span(); + Error::new(span, message) + } +} + +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.debug_tuple("Error").field(&self.message).finish() + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str(&self.message) + } +} + +impl Clone for Error { + fn clone(&self) -> Self { + let start = self + .start_span + .get() + .cloned() + .unwrap_or_else(Span::call_site); + let end = self.end_span.get().cloned().unwrap_or_else(Span::call_site); + Error { + start_span: ThreadBound::new(start), + end_span: ThreadBound::new(end), + message: self.message.clone(), + } + } +} + +impl std::error::Error for Error { + fn description(&self) -> &str { + "parse error" + } +} + +impl From<LexError> for Error { + fn from(err: LexError) -> Self { + Error::new(Span::call_site(), format!("{:?}", err)) + } +} diff --git a/syn/src/export.rs b/syn/src/export.rs new file mode 100644 index 000000000..8e270bd01 --- /dev/null +++ b/syn/src/export.rs @@ -0,0 +1,35 @@ +pub use std::clone::Clone; +pub use std::cmp::{Eq, PartialEq}; +pub use std::convert::From; +pub use std::default::Default; +pub use std::fmt::{self, Debug, Formatter}; +pub use std::hash::{Hash, Hasher}; +pub use std::marker::Copy; +pub use std::option::Option::{None, Some}; +pub use std::result::Result::{Err, Ok}; + +#[cfg(feature = "printing")] +pub extern crate quote; + +pub use proc_macro2::{Span, TokenStream as TokenStream2}; + +pub use span::IntoSpans; + +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" +))] +pub use proc_macro::TokenStream; + +#[cfg(feature = "printing")] +pub use quote::{ToTokens, TokenStreamExt}; + +#[allow(non_camel_case_types)] +pub type bool = help::Bool; +#[allow(non_camel_case_types)] +pub type str = help::Str; + +mod help { + pub type Bool = bool; + pub type Str = str; +} diff --git a/syn/src/expr.rs b/syn/src/expr.rs new file mode 100644 index 000000000..8889be886 --- /dev/null +++ b/syn/src/expr.rs @@ -0,0 +1,3816 @@ +use super::*; +use proc_macro2::{Span, TokenStream}; +use punctuated::Punctuated; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(all(feature = "parsing", feature = "full"))] +use std::mem; +#[cfg(feature = "extra-traits")] +use tt::TokenStreamHelper; + +ast_enum_of_structs! { + /// A Rust expression. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enums + /// + /// This type is a syntax tree enum. In Syn this and other syntax tree enums + /// are designed to be traversed using the following rebinding idiom. + /// + /// ```edition2018 + /// # use syn::Expr; + /// # + /// # fn example(expr: Expr) { + /// # const IGNORE: &str = stringify! { + /// let expr: Expr = /* ... */; + /// # }; + /// match expr { + /// Expr::MethodCall(expr) => { + /// /* ... */ + /// } + /// Expr::Cast(expr) => { + /// /* ... */ + /// } + /// Expr::If(expr) => { + /// /* ... */ + /// } + /// + /// /* ... */ + /// # _ => {} + /// # } + /// # } + /// ``` + /// + /// We begin with a variable `expr` of type `Expr` that has no fields + /// (because it is an enum), and by matching on it and rebinding a variable + /// with the same name `expr` we effectively imbue our variable with all of + /// the data fields provided by the variant that it turned out to be. So for + /// example above if we ended up in the `MethodCall` case then we get to use + /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get + /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`. + /// + /// This approach avoids repeating the variant names twice on every line. + /// + /// ```edition2018 + /// # use syn::{Expr, ExprMethodCall}; + /// # + /// # fn example(expr: Expr) { + /// // Repetitive; recommend not doing this. + /// match expr { + /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { + /// # } + /// # _ => {} + /// # } + /// # } + /// ``` + /// + /// In general, the name to which a syntax tree enum variant is bound should + /// be a suitable name for the complete syntax tree enum type. + /// + /// ```edition2018 + /// # use syn::{Expr, ExprField}; + /// # + /// # fn example(discriminant: ExprField) { + /// // Binding is called `base` which is the name I would use if I were + /// // assigning `*discriminant.base` without an `if let`. + /// if let Expr::Tuple(base) = *discriminant.base { + /// # } + /// # } + /// ``` + /// + /// A sign that you may not be choosing the right variable names is if you + /// see names getting repeated in your code, like accessing + /// `receiver.receiver` or `pat.pat` or `cond.cond`. + pub enum Expr { + /// A box expression: `box f`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Box(ExprBox #full { + pub attrs: Vec<Attribute>, + pub box_token: Token![box], + pub expr: Box<Expr>, + }), + + /// A placement expression: `place <- value`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub InPlace(ExprInPlace #full { + pub attrs: Vec<Attribute>, + pub place: Box<Expr>, + pub arrow_token: Token![<-], + pub value: Box<Expr>, + }), + + /// A slice literal expression: `[a, b, c, d]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Array(ExprArray #full { + pub attrs: Vec<Attribute>, + pub bracket_token: token::Bracket, + pub elems: Punctuated<Expr, Token![,]>, + }), + + /// A function call expression: `invoke(a, b)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Call(ExprCall { + pub attrs: Vec<Attribute>, + pub func: Box<Expr>, + pub paren_token: token::Paren, + pub args: Punctuated<Expr, Token![,]>, + }), + + /// A method call expression: `x.foo::<T>(a, b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub MethodCall(ExprMethodCall #full { + pub attrs: Vec<Attribute>, + pub receiver: Box<Expr>, + pub dot_token: Token![.], + pub method: Ident, + pub turbofish: Option<MethodTurbofish>, + pub paren_token: token::Paren, + pub args: Punctuated<Expr, Token![,]>, + }), + + /// A tuple expression: `(a, b, c, d)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Tuple(ExprTuple #full { + pub attrs: Vec<Attribute>, + pub paren_token: token::Paren, + pub elems: Punctuated<Expr, Token![,]>, + }), + + /// A binary operation: `a + b`, `a * b`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Binary(ExprBinary { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub op: BinOp, + pub right: Box<Expr>, + }), + + /// A unary operation: `!x`, `*x`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Unary(ExprUnary { + pub attrs: Vec<Attribute>, + pub op: UnOp, + pub expr: Box<Expr>, + }), + + /// A literal in place of an expression: `1`, `"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Lit(ExprLit { + pub attrs: Vec<Attribute>, + pub lit: Lit, + }), + + /// A cast expression: `foo as f64`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Cast(ExprCast { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub as_token: Token![as], + pub ty: Box<Type>, + }), + + /// A type ascription expression: `foo: f64`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Type(ExprType #full { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub colon_token: Token![:], + pub ty: Box<Type>, + }), + + /// A `let` guard: `let Some(x) = opt`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Let(ExprLet #full { + pub attrs: Vec<Attribute>, + pub let_token: Token![let], + pub pats: Punctuated<Pat, Token![|]>, + pub eq_token: Token![=], + pub expr: Box<Expr>, + }), + + /// An `if` expression with an optional `else` block: `if expr { ... } + /// else { ... }`. + /// + /// The `else` branch expression may only be an `If` or `Block` + /// expression, not any of the other types of expression. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub If(ExprIf #full { + pub attrs: Vec<Attribute>, + pub if_token: Token![if], + pub cond: Box<Expr>, + pub then_branch: Block, + pub else_branch: Option<(Token![else], Box<Expr>)>, + }), + + /// A while loop: `while expr { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub While(ExprWhile #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub while_token: Token![while], + pub cond: Box<Expr>, + pub body: Block, + }), + + /// A for loop: `for pat in expr { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub ForLoop(ExprForLoop #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub for_token: Token![for], + pub pat: Box<Pat>, + pub in_token: Token![in], + pub expr: Box<Expr>, + pub body: Block, + }), + + /// Conditionless loop: `loop { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Loop(ExprLoop #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub loop_token: Token![loop], + pub body: Block, + }), + + /// A `match` expression: `match n { Some(n) => {}, None => {} }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Match(ExprMatch #full { + pub attrs: Vec<Attribute>, + pub match_token: Token![match], + pub expr: Box<Expr>, + pub brace_token: token::Brace, + pub arms: Vec<Arm>, + }), + + /// A closure expression: `|a, b| a + b`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Closure(ExprClosure #full { + pub attrs: Vec<Attribute>, + pub asyncness: Option<Token![async]>, + pub movability: Option<Token![static]>, + pub capture: Option<Token![move]>, + pub or1_token: Token![|], + pub inputs: Punctuated<FnArg, Token![,]>, + pub or2_token: Token![|], + pub output: ReturnType, + pub body: Box<Expr>, + }), + + /// An unsafe block: `unsafe { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Unsafe(ExprUnsafe #full { + pub attrs: Vec<Attribute>, + pub unsafe_token: Token![unsafe], + pub block: Block, + }), + + /// A blocked scope: `{ ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Block(ExprBlock #full { + pub attrs: Vec<Attribute>, + pub label: Option<Label>, + pub block: Block, + }), + + /// An assignment expression: `a = compute()`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Assign(ExprAssign #full { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub eq_token: Token![=], + pub right: Box<Expr>, + }), + + /// A compound assignment expression: `counter += 1`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub AssignOp(ExprAssignOp #full { + pub attrs: Vec<Attribute>, + pub left: Box<Expr>, + pub op: BinOp, + pub right: Box<Expr>, + }), + + /// Access of a named struct field (`obj.k`) or unnamed tuple struct + /// field (`obj.0`). + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Field(ExprField { + pub attrs: Vec<Attribute>, + pub base: Box<Expr>, + pub dot_token: Token![.], + pub member: Member, + }), + + /// A square bracketed indexing expression: `vector[2]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Index(ExprIndex { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub bracket_token: token::Bracket, + pub index: Box<Expr>, + }), + + /// A range expression: `1..2`, `1..`, `..2`, `1..=2`, `..=2`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Range(ExprRange #full { + pub attrs: Vec<Attribute>, + pub from: Option<Box<Expr>>, + pub limits: RangeLimits, + pub to: Option<Box<Expr>>, + }), + + /// A path like `std::mem::replace` possibly containing generic + /// parameters and a qualified self-type. + /// + /// A plain identifier like `x` is a path of length 1. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Path(ExprPath { + pub attrs: Vec<Attribute>, + pub qself: Option<QSelf>, + pub path: Path, + }), + + /// A referencing operation: `&a` or `&mut a`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Reference(ExprReference #full { + pub attrs: Vec<Attribute>, + pub and_token: Token![&], + pub mutability: Option<Token![mut]>, + pub expr: Box<Expr>, + }), + + /// A `break`, with an optional label to break and an optional + /// expression. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Break(ExprBreak #full { + pub attrs: Vec<Attribute>, + pub break_token: Token![break], + pub label: Option<Lifetime>, + pub expr: Option<Box<Expr>>, + }), + + /// A `continue`, with an optional label. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Continue(ExprContinue #full { + pub attrs: Vec<Attribute>, + pub continue_token: Token![continue], + pub label: Option<Lifetime>, + }), + + /// A `return`, with an optional value to be returned. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Return(ExprReturn #full { + pub attrs: Vec<Attribute>, + pub return_token: Token![return], + pub expr: Option<Box<Expr>>, + }), + + /// A macro invocation expression: `format!("{}", q)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(ExprMacro #full { + pub attrs: Vec<Attribute>, + pub mac: Macro, + }), + + /// A struct literal expression: `Point { x: 1, y: 1 }`. + /// + /// The `rest` provides the value of the remaining fields as in `S { a: + /// 1, b: 1, ..rest }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Struct(ExprStruct #full { + pub attrs: Vec<Attribute>, + pub path: Path, + pub brace_token: token::Brace, + pub fields: Punctuated<FieldValue, Token![,]>, + pub dot2_token: Option<Token![..]>, + pub rest: Option<Box<Expr>>, + }), + + /// An array literal constructed from one repeated element: `[0u8; N]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Repeat(ExprRepeat #full { + pub attrs: Vec<Attribute>, + pub bracket_token: token::Bracket, + pub expr: Box<Expr>, + pub semi_token: Token![;], + pub len: Box<Expr>, + }), + + /// A parenthesized expression: `(a + b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Paren(ExprParen { + pub attrs: Vec<Attribute>, + pub paren_token: token::Paren, + pub expr: Box<Expr>, + }), + + /// An expression contained within invisible delimiters. + /// + /// This variant is important for faithfully representing the precedence + /// of expressions and is related to `None`-delimited spans in a + /// `TokenStream`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Group(ExprGroup #full { + pub attrs: Vec<Attribute>, + pub group_token: token::Group, + pub expr: Box<Expr>, + }), + + /// A try-expression: `expr?`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Try(ExprTry #full { + pub attrs: Vec<Attribute>, + pub expr: Box<Expr>, + pub question_token: Token![?], + }), + + /// An async block: `async { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Async(ExprAsync #full { + pub attrs: Vec<Attribute>, + pub async_token: Token![async], + pub capture: Option<Token![move]>, + pub block: Block, + }), + + /// A try block: `try { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub TryBlock(ExprTryBlock #full { + pub attrs: Vec<Attribute>, + pub try_token: Token![try], + pub block: Block, + }), + + /// A yield expression: `yield expr`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Yield(ExprYield #full { + pub attrs: Vec<Attribute>, + pub yield_token: Token![yield], + pub expr: Option<Box<Expr>>, + }), + + /// Tokens in expression position not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Verbatim(ExprVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ExprVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ExprVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ExprVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +impl Expr { + #[cfg(all(feature = "parsing", feature = "full"))] + fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> { + match *self { + Expr::Box(ExprBox { ref mut attrs, .. }) + | Expr::InPlace(ExprInPlace { ref mut attrs, .. }) + | Expr::Array(ExprArray { ref mut attrs, .. }) + | Expr::Call(ExprCall { ref mut attrs, .. }) + | Expr::MethodCall(ExprMethodCall { ref mut attrs, .. }) + | Expr::Tuple(ExprTuple { ref mut attrs, .. }) + | Expr::Binary(ExprBinary { ref mut attrs, .. }) + | Expr::Unary(ExprUnary { ref mut attrs, .. }) + | Expr::Lit(ExprLit { ref mut attrs, .. }) + | Expr::Cast(ExprCast { ref mut attrs, .. }) + | Expr::Type(ExprType { ref mut attrs, .. }) + | Expr::Let(ExprLet { ref mut attrs, .. }) + | Expr::If(ExprIf { ref mut attrs, .. }) + | Expr::While(ExprWhile { ref mut attrs, .. }) + | Expr::ForLoop(ExprForLoop { ref mut attrs, .. }) + | Expr::Loop(ExprLoop { ref mut attrs, .. }) + | Expr::Match(ExprMatch { ref mut attrs, .. }) + | Expr::Closure(ExprClosure { ref mut attrs, .. }) + | Expr::Unsafe(ExprUnsafe { ref mut attrs, .. }) + | Expr::Block(ExprBlock { ref mut attrs, .. }) + | Expr::Assign(ExprAssign { ref mut attrs, .. }) + | Expr::AssignOp(ExprAssignOp { ref mut attrs, .. }) + | Expr::Field(ExprField { ref mut attrs, .. }) + | Expr::Index(ExprIndex { ref mut attrs, .. }) + | Expr::Range(ExprRange { ref mut attrs, .. }) + | Expr::Path(ExprPath { ref mut attrs, .. }) + | Expr::Reference(ExprReference { ref mut attrs, .. }) + | Expr::Break(ExprBreak { ref mut attrs, .. }) + | Expr::Continue(ExprContinue { ref mut attrs, .. }) + | Expr::Return(ExprReturn { ref mut attrs, .. }) + | Expr::Macro(ExprMacro { ref mut attrs, .. }) + | Expr::Struct(ExprStruct { ref mut attrs, .. }) + | Expr::Repeat(ExprRepeat { ref mut attrs, .. }) + | Expr::Paren(ExprParen { ref mut attrs, .. }) + | Expr::Group(ExprGroup { ref mut attrs, .. }) + | Expr::Try(ExprTry { ref mut attrs, .. }) + | Expr::Async(ExprAsync { ref mut attrs, .. }) + | Expr::TryBlock(ExprTryBlock { ref mut attrs, .. }) + | Expr::Yield(ExprYield { ref mut attrs, .. }) => mem::replace(attrs, new), + Expr::Verbatim(_) => Vec::new(), + } + } +} + +ast_enum! { + /// A struct or tuple struct field accessed in a struct literal or field + /// expression. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum Member { + /// A named field like `self.x`. + Named(Ident), + /// An unnamed field like `self.0`. + Unnamed(Index), + } +} + +ast_struct! { + /// The index of an unnamed tuple struct field. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Index #manual_extra_traits { + pub index: u32, + pub span: Span, + } +} + +impl From<usize> for Index { + fn from(index: usize) -> Index { + assert!(index < u32::max_value() as usize); + Index { + index: index as u32, + span: Span::call_site(), + } + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Index {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Index { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Index { + fn hash<H: Hasher>(&self, state: &mut H) { + self.index.hash(state); + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// The `::<>` explicit type parameters passed to a method call: + /// `parse::<u64>()`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct MethodTurbofish { + pub colon2_token: Token![::], + pub lt_token: Token![<], + pub args: Punctuated<GenericMethodArgument, Token![,]>, + pub gt_token: Token![>], + } +} + +#[cfg(feature = "full")] +ast_enum! { + /// An individual generic argument to a method, like `T`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub enum GenericMethodArgument { + /// A type argument. + Type(Type), + /// A const expression. Must be inside of a block. + /// + /// NOTE: Identity expressions are represented as Type arguments, as + /// they are indistinguishable syntactically. + Const(Expr), + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// A field-value pair in a struct literal. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct FieldValue { + /// Attributes tagged on the field. + pub attrs: Vec<Attribute>, + + /// Name or index of the field. + pub member: Member, + + /// The colon in `Struct { x: x }`. If written in shorthand like + /// `Struct { x }`, there is no colon. + pub colon_token: Option<Token![:]>, + + /// Value of the field. + pub expr: Expr, + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// A lifetime labeling a `for`, `while`, or `loop`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Label { + pub name: Lifetime, + pub colon_token: Token![:], + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// A braced block containing Rust statements. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Block { + pub brace_token: token::Brace, + /// Statements in a block + pub stmts: Vec<Stmt>, + } +} + +#[cfg(feature = "full")] +ast_enum! { + /// A statement, usually ending in a semicolon. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub enum Stmt { + /// A local (let) binding. + Local(Local), + + /// An item definition. + Item(Item), + + /// Expr without trailing semicolon. + Expr(Expr), + + /// Expression with trailing semicolon. + Semi(Expr, Token![;]), + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// A local `let` binding: `let x: u64 = s.parse()?`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Local { + pub attrs: Vec<Attribute>, + pub let_token: Token![let], + pub pats: Punctuated<Pat, Token![|]>, + pub ty: Option<(Token![:], Box<Type>)>, + pub init: Option<(Token![=], Box<Expr>)>, + pub semi_token: Token![;], + } +} + +#[cfg(feature = "full")] +ast_enum_of_structs! { + /// A pattern in a local binding, function signature, match expression, or + /// various other places. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Pat { + /// A pattern that matches any value: `_`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Wild(PatWild { + pub underscore_token: Token![_], + }), + + /// A pattern that binds a new variable: `ref mut binding @ SUBPATTERN`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Ident(PatIdent { + pub by_ref: Option<Token![ref]>, + pub mutability: Option<Token![mut]>, + pub ident: Ident, + pub subpat: Option<(Token![@], Box<Pat>)>, + }), + + /// A struct or struct variant pattern: `Variant { x, y, .. }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Struct(PatStruct { + pub path: Path, + pub brace_token: token::Brace, + pub fields: Punctuated<FieldPat, Token![,]>, + pub dot2_token: Option<Token![..]>, + }), + + /// A tuple struct or tuple variant pattern: `Variant(x, y, .., z)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub TupleStruct(PatTupleStruct { + pub path: Path, + pub pat: PatTuple, + }), + + /// A path pattern like `Color::Red`, optionally qualified with a + /// self-type. + /// + /// Unqualified path patterns can legally refer to variants, structs, + /// constants or associated constants. Qualified path patterns like + /// `<A>::B::C` and `<A as Trait>::B::C` can only legally refer to + /// associated constants. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Path(PatPath { + pub qself: Option<QSelf>, + pub path: Path, + }), + + /// A tuple pattern: `(a, b)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Tuple(PatTuple { + pub paren_token: token::Paren, + pub front: Punctuated<Pat, Token![,]>, + pub dot2_token: Option<Token![..]>, + pub comma_token: Option<Token![,]>, + pub back: Punctuated<Pat, Token![,]>, + }), + + /// A box pattern: `box v`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Box(PatBox { + pub box_token: Token![box], + pub pat: Box<Pat>, + }), + + /// A reference pattern: `&mut (first, second)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Ref(PatRef { + pub and_token: Token![&], + pub mutability: Option<Token![mut]>, + pub pat: Box<Pat>, + }), + + /// A literal pattern: `0`. + /// + /// This holds an `Expr` rather than a `Lit` because negative numbers + /// are represented as an `Expr::Unary`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Lit(PatLit { + pub expr: Box<Expr>, + }), + + /// A range pattern: `1..=2`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Range(PatRange { + pub lo: Box<Expr>, + pub limits: RangeLimits, + pub hi: Box<Expr>, + }), + + /// A dynamically sized slice pattern: `[a, b, i.., y, z]`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Slice(PatSlice { + pub bracket_token: token::Bracket, + pub front: Punctuated<Pat, Token![,]>, + pub middle: Option<Box<Pat>>, + pub dot2_token: Option<Token![..]>, + pub comma_token: Option<Token![,]>, + pub back: Punctuated<Pat, Token![,]>, + }), + + /// A macro in expression position. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(PatMacro { + pub mac: Macro, + }), + + /// Tokens in pattern position not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Verbatim(PatVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(all(feature = "full", feature = "extra-traits"))] +impl Eq for PatVerbatim {} + +#[cfg(all(feature = "full", feature = "extra-traits"))] +impl PartialEq for PatVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(all(feature = "full", feature = "extra-traits"))] +impl Hash for PatVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// One arm of a `match` expression: `0...10 => { return true; }`. + /// + /// As in: + /// + /// ```edition2018 + /// # fn f() -> bool { + /// # let n = 0; + /// match n { + /// 0...10 => { + /// return true; + /// } + /// // ... + /// # _ => {} + /// } + /// # false + /// # } + /// ``` + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct Arm { + pub attrs: Vec<Attribute>, + pub leading_vert: Option<Token![|]>, + pub pats: Punctuated<Pat, Token![|]>, + pub guard: Option<(Token![if], Box<Expr>)>, + pub fat_arrow_token: Token![=>], + pub body: Box<Expr>, + pub comma: Option<Token![,]>, + } +} + +#[cfg(feature = "full")] +ast_enum! { + /// Limit types of a range, inclusive or exclusive. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + #[cfg_attr(feature = "clone-impls", derive(Copy))] + pub enum RangeLimits { + /// Inclusive at the beginning, exclusive at the end. + HalfOpen(Token![..]), + /// Inclusive at the beginning and end. + Closed(Token![..=]), + } +} + +#[cfg(feature = "full")] +ast_struct! { + /// A single field in a struct pattern. + /// + /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` are treated + /// the same as `x: x, y: ref y, z: ref mut z` but there is no colon token. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct FieldPat { + pub attrs: Vec<Attribute>, + pub member: Member, + pub colon_token: Option<Token![:]>, + pub pat: Box<Pat>, + } +} + +#[cfg(any(feature = "parsing", feature = "printing"))] +#[cfg(feature = "full")] +fn requires_terminator(expr: &Expr) -> bool { + // see https://github.com/rust-lang/rust/blob/eb8f2586e/src/libsyntax/parse/classify.rs#L17-L37 + match *expr { + Expr::Unsafe(..) + | Expr::Block(..) + | Expr::If(..) + | Expr::Match(..) + | Expr::While(..) + | Expr::Loop(..) + | Expr::ForLoop(..) + | Expr::Async(..) + | Expr::TryBlock(..) => false, + _ => true, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + #[cfg(feature = "full")] + use ext::IdentExt; + use parse::{Parse, ParseStream, Result}; + use path; + + // When we're parsing expressions which occur before blocks, like in an if + // statement's condition, we cannot parse a struct literal. + // + // Struct literals are ambiguous in certain positions + // https://github.com/rust-lang/rfcs/pull/92 + #[derive(Copy, Clone)] + pub struct AllowStruct(bool); + + #[derive(Copy, Clone, PartialEq, PartialOrd)] + enum Precedence { + Any, + Assign, + Placement, + Range, + Or, + And, + Compare, + BitOr, + BitXor, + BitAnd, + Shift, + Arithmetic, + Term, + Cast, + } + + impl Precedence { + fn of(op: &BinOp) -> Self { + match *op { + BinOp::Add(_) | BinOp::Sub(_) => Precedence::Arithmetic, + BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Term, + BinOp::And(_) => Precedence::And, + BinOp::Or(_) => Precedence::Or, + BinOp::BitXor(_) => Precedence::BitXor, + BinOp::BitAnd(_) => Precedence::BitAnd, + BinOp::BitOr(_) => Precedence::BitOr, + BinOp::Shl(_) | BinOp::Shr(_) => Precedence::Shift, + BinOp::Eq(_) + | BinOp::Lt(_) + | BinOp::Le(_) + | BinOp::Ne(_) + | BinOp::Ge(_) + | BinOp::Gt(_) => Precedence::Compare, + BinOp::AddEq(_) + | BinOp::SubEq(_) + | BinOp::MulEq(_) + | BinOp::DivEq(_) + | BinOp::RemEq(_) + | BinOp::BitXorEq(_) + | BinOp::BitAndEq(_) + | BinOp::BitOrEq(_) + | BinOp::ShlEq(_) + | BinOp::ShrEq(_) => Precedence::Assign, + } + } + } + + impl Parse for Expr { + fn parse(input: ParseStream) -> Result<Self> { + ambiguous_expr(input, AllowStruct(true)) + } + } + + #[cfg(feature = "full")] + fn expr_no_struct(input: ParseStream) -> Result<Expr> { + ambiguous_expr(input, AllowStruct(false)) + } + + #[cfg(feature = "full")] + fn parse_expr( + input: ParseStream, + mut lhs: Expr, + allow_struct: AllowStruct, + base: Precedence, + ) -> Result<Expr> { + loop { + if input + .fork() + .parse::<BinOp>() + .ok() + .map_or(false, |op| Precedence::of(&op) >= base) + { + let op: BinOp = input.parse()?; + let precedence = Precedence::of(&op); + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > precedence || next == precedence && precedence == Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = if precedence == Precedence::Assign { + Expr::AssignOp(ExprAssignOp { + attrs: Vec::new(), + left: Box::new(lhs), + op: op, + right: Box::new(rhs), + }) + } else { + Expr::Binary(ExprBinary { + attrs: Vec::new(), + left: Box::new(lhs), + op: op, + right: Box::new(rhs), + }) + }; + } else if Precedence::Assign >= base + && input.peek(Token![=]) + && !input.peek(Token![==]) + && !input.peek(Token![=>]) + { + let eq_token: Token![=] = input.parse()?; + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next >= Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = Expr::Assign(ExprAssign { + attrs: Vec::new(), + left: Box::new(lhs), + eq_token: eq_token, + right: Box::new(rhs), + }); + } else if Precedence::Placement >= base && input.peek(Token![<-]) { + let arrow_token: Token![<-] = input.parse()?; + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > Precedence::Placement { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = Expr::InPlace(ExprInPlace { + attrs: Vec::new(), + place: Box::new(lhs), + arrow_token: arrow_token, + value: Box::new(rhs), + }); + } else if Precedence::Range >= base && input.peek(Token![..]) { + let limits: RangeLimits = input.parse()?; + let rhs = if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > Precedence::Range { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + Some(rhs) + }; + lhs = Expr::Range(ExprRange { + attrs: Vec::new(), + from: Some(Box::new(lhs)), + limits: limits, + to: rhs.map(Box::new), + }); + } else if Precedence::Cast >= base && input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Cast(ExprCast { + attrs: Vec::new(), + expr: Box::new(lhs), + as_token: as_token, + ty: Box::new(ty), + }); + } else if Precedence::Cast >= base && input.peek(Token![:]) && !input.peek(Token![::]) { + let colon_token: Token![:] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Type(ExprType { + attrs: Vec::new(), + expr: Box::new(lhs), + colon_token: colon_token, + ty: Box::new(ty), + }); + } else { + break; + } + } + Ok(lhs) + } + + #[cfg(not(feature = "full"))] + fn parse_expr( + input: ParseStream, + mut lhs: Expr, + allow_struct: AllowStruct, + base: Precedence, + ) -> Result<Expr> { + loop { + if input + .fork() + .parse::<BinOp>() + .ok() + .map_or(false, |op| Precedence::of(&op) >= base) + { + let op: BinOp = input.parse()?; + let precedence = Precedence::of(&op); + let mut rhs = unary_expr(input, allow_struct)?; + loop { + let next = peek_precedence(input); + if next > precedence || next == precedence && precedence == Precedence::Assign { + rhs = parse_expr(input, rhs, allow_struct, next)?; + } else { + break; + } + } + lhs = Expr::Binary(ExprBinary { + attrs: Vec::new(), + left: Box::new(lhs), + op: op, + right: Box::new(rhs), + }); + } else if Precedence::Cast >= base && input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let ty = input.call(Type::without_plus)?; + lhs = Expr::Cast(ExprCast { + attrs: Vec::new(), + expr: Box::new(lhs), + as_token: as_token, + ty: Box::new(ty), + }); + } else { + break; + } + } + Ok(lhs) + } + + fn peek_precedence(input: ParseStream) -> Precedence { + if let Ok(op) = input.fork().parse() { + Precedence::of(&op) + } else if input.peek(Token![=]) && !input.peek(Token![=>]) { + Precedence::Assign + } else if input.peek(Token![<-]) { + Precedence::Placement + } else if input.peek(Token![..]) { + Precedence::Range + } else if input.peek(Token![as]) || input.peek(Token![:]) && !input.peek(Token![::]) { + Precedence::Cast + } else { + Precedence::Any + } + } + + // Parse an arbitrary expression. + fn ambiguous_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let lhs = unary_expr(input, allow_struct)?; + parse_expr(input, lhs, allow_struct, Precedence::Any) + } + + // <UnOp> <trailer> + // & <trailer> + // &mut <trailer> + // box <trailer> + #[cfg(feature = "full")] + fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + if ahead.peek(Token![&]) + || ahead.peek(Token![box]) + || ahead.peek(Token![*]) + || ahead.peek(Token![!]) + || ahead.peek(Token![-]) + { + let attrs = input.call(Attribute::parse_outer)?; + if input.peek(Token![&]) { + Ok(Expr::Reference(ExprReference { + attrs: attrs, + and_token: input.parse()?, + mutability: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else if input.peek(Token![box]) { + Ok(Expr::Box(ExprBox { + attrs: attrs, + box_token: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else { + Ok(Expr::Unary(ExprUnary { + attrs: attrs, + op: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } + } else { + trailer_expr(input, allow_struct) + } + } + + #[cfg(not(feature = "full"))] + fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) { + Ok(Expr::Unary(ExprUnary { + attrs: input.call(Attribute::parse_outer)?, + op: input.parse()?, + expr: Box::new(unary_expr(input, allow_struct)?), + })) + } else { + trailer_expr(input, allow_struct) + } + } + + // <atom> (..<args>) ... + // <atom> . <ident> (..<args>) ... + // <atom> . <ident> ... + // <atom> . <lit> ... + // <atom> [ <expr> ] ... + // <atom> ? ... + #[cfg(feature = "full")] + fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(token::Group) { + return input.call(expr_group).map(Expr::Group); + } + + let outer_attrs = input.call(Attribute::parse_outer)?; + + let atom = atom_expr(input, allow_struct)?; + let mut e = trailer_helper(input, atom)?; + + let inner_attrs = e.replace_attrs(Vec::new()); + let attrs = private::attrs(outer_attrs, inner_attrs); + e.replace_attrs(attrs); + Ok(e) + } + + #[cfg(feature = "full")] + fn trailer_helper(input: ParseStream, mut e: Expr) -> Result<Expr> { + loop { + if input.peek(token::Paren) { + let content; + e = Expr::Call(ExprCall { + attrs: Vec::new(), + func: Box::new(e), + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + } else if input.peek(Token![.]) && !input.peek(Token![..]) { + let dot_token: Token![.] = input.parse()?; + let member: Member = input.parse()?; + let turbofish = if member.is_named() && input.peek(Token![::]) { + Some(MethodTurbofish { + colon2_token: input.parse()?, + lt_token: input.parse()?, + args: { + let mut args = Punctuated::new(); + loop { + if input.peek(Token![>]) { + break; + } + let value = input.call(generic_method_argument)?; + args.push_value(value); + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + args.push_punct(punct); + } + args + }, + gt_token: input.parse()?, + }) + } else { + None + }; + + if turbofish.is_some() || input.peek(token::Paren) { + if let Member::Named(method) = member { + let content; + e = Expr::MethodCall(ExprMethodCall { + attrs: Vec::new(), + receiver: Box::new(e), + dot_token: dot_token, + method: method, + turbofish: turbofish, + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + continue; + } + } + + e = Expr::Field(ExprField { + attrs: Vec::new(), + base: Box::new(e), + dot_token: dot_token, + member: member, + }); + } else if input.peek(token::Bracket) { + let content; + e = Expr::Index(ExprIndex { + attrs: Vec::new(), + expr: Box::new(e), + bracket_token: bracketed!(content in input), + index: content.parse()?, + }); + } else if input.peek(Token![?]) { + e = Expr::Try(ExprTry { + attrs: Vec::new(), + expr: Box::new(e), + question_token: input.parse()?, + }); + } else { + break; + } + } + Ok(e) + } + + #[cfg(not(feature = "full"))] + fn trailer_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let mut e = atom_expr(input, allow_struct)?; + + loop { + if input.peek(token::Paren) { + let content; + e = Expr::Call(ExprCall { + attrs: Vec::new(), + func: Box::new(e), + paren_token: parenthesized!(content in input), + args: content.parse_terminated(Expr::parse)?, + }); + } else if input.peek(Token![.]) { + e = Expr::Field(ExprField { + attrs: Vec::new(), + base: Box::new(e), + dot_token: input.parse()?, + member: input.parse()?, + }); + } else if input.peek(token::Bracket) { + let content; + e = Expr::Index(ExprIndex { + attrs: Vec::new(), + expr: Box::new(e), + bracket_token: bracketed!(content in input), + index: content.parse()?, + }); + } else { + break; + } + } + + Ok(e) + } + + // Parse all atomic expressions which don't have to worry about precedence + // interactions, as they are fully contained. + #[cfg(feature = "full")] + fn atom_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(token::Group) { + input.call(expr_group).map(Expr::Group) + } else if input.peek(Lit) { + input.parse().map(Expr::Lit) + } else if input.peek(Token![async]) + && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace)) + { + input.call(expr_async).map(Expr::Async) + } else if input.peek(Token![try]) && input.peek2(token::Brace) { + input.call(expr_try_block).map(Expr::TryBlock) + } else if input.peek(Token![|]) + || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move])) + || input.peek(Token![static]) + || input.peek(Token![move]) + { + expr_closure(input, allow_struct).map(Expr::Closure) + } else if input.peek(Ident) + || input.peek(Token![::]) + || input.peek(Token![<]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + path_or_macro_or_struct(input, allow_struct) + } else if input.peek(token::Paren) { + paren_or_tuple(input) + } else if input.peek(Token![break]) { + expr_break(input, allow_struct).map(Expr::Break) + } else if input.peek(Token![continue]) { + input.call(expr_continue).map(Expr::Continue) + } else if input.peek(Token![return]) { + expr_ret(input, allow_struct).map(Expr::Return) + } else if input.peek(token::Bracket) { + array_or_repeat(input) + } else if input.peek(Token![let]) { + input.call(expr_let).map(Expr::Let) + } else if input.peek(Token![if]) { + input.parse().map(Expr::If) + } else if input.peek(Token![while]) { + input.parse().map(Expr::While) + } else if input.peek(Token![for]) { + input.parse().map(Expr::ForLoop) + } else if input.peek(Token![loop]) { + input.parse().map(Expr::Loop) + } else if input.peek(Token![match]) { + input.parse().map(Expr::Match) + } else if input.peek(Token![yield]) { + input.call(expr_yield).map(Expr::Yield) + } else if input.peek(Token![unsafe]) { + input.call(expr_unsafe).map(Expr::Unsafe) + } else if input.peek(token::Brace) { + input.call(expr_block).map(Expr::Block) + } else if input.peek(Token![..]) { + expr_range(input, allow_struct).map(Expr::Range) + } else if input.peek(Lifetime) { + let the_label: Label = input.parse()?; + let mut expr = if input.peek(Token![while]) { + Expr::While(input.parse()?) + } else if input.peek(Token![for]) { + Expr::ForLoop(input.parse()?) + } else if input.peek(Token![loop]) { + Expr::Loop(input.parse()?) + } else if input.peek(token::Brace) { + Expr::Block(input.call(expr_block)?) + } else { + return Err(input.error("expected loop or block expression")); + }; + match expr { + Expr::While(ExprWhile { ref mut label, .. }) + | Expr::ForLoop(ExprForLoop { ref mut label, .. }) + | Expr::Loop(ExprLoop { ref mut label, .. }) + | Expr::Block(ExprBlock { ref mut label, .. }) => *label = Some(the_label), + _ => unreachable!(), + } + Ok(expr) + } else { + Err(input.error("expected expression")) + } + } + + #[cfg(not(feature = "full"))] + fn atom_expr(input: ParseStream, _allow_struct: AllowStruct) -> Result<Expr> { + if input.peek(Lit) { + input.parse().map(Expr::Lit) + } else if input.peek(token::Paren) { + input.call(expr_paren).map(Expr::Paren) + } else if input.peek(Ident) + || input.peek(Token![::]) + || input.peek(Token![<]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + input.parse().map(Expr::Path) + } else { + Err(input.error("unsupported expression; enable syn's features=[\"full\"]")) + } + } + + #[cfg(feature = "full")] + fn path_or_macro_or_struct(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> { + let expr: ExprPath = input.parse()?; + if expr.qself.is_some() { + return Ok(Expr::Path(expr)); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &expr.path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tts) = mac::parse_delimiter(input)?; + return Ok(Expr::Macro(ExprMacro { + attrs: Vec::new(), + mac: Macro { + path: expr.path, + bang_token: bang_token, + delimiter: delimiter, + tts: tts, + }, + })); + } + } + + if allow_struct.0 && input.peek(token::Brace) { + let outer_attrs = Vec::new(); + expr_struct_helper(input, outer_attrs, expr.path).map(Expr::Struct) + } else { + Ok(Expr::Path(expr)) + } + } + + #[cfg(feature = "full")] + fn paren_or_tuple(input: ParseStream) -> Result<Expr> { + let content; + let paren_token = parenthesized!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + if content.is_empty() { + return Ok(Expr::Tuple(ExprTuple { + attrs: inner_attrs, + paren_token: paren_token, + elems: Punctuated::new(), + })); + } + + let first: Expr = content.parse()?; + if content.is_empty() { + return Ok(Expr::Paren(ExprParen { + attrs: inner_attrs, + paren_token: paren_token, + expr: Box::new(first), + })); + } + + let mut elems = Punctuated::new(); + elems.push_value(first); + while !content.is_empty() { + let punct = content.parse()?; + elems.push_punct(punct); + if content.is_empty() { + break; + } + let value = content.parse()?; + elems.push_value(value); + } + Ok(Expr::Tuple(ExprTuple { + attrs: inner_attrs, + paren_token: paren_token, + elems: elems, + })) + } + + #[cfg(feature = "full")] + fn array_or_repeat(input: ParseStream) -> Result<Expr> { + let content; + let bracket_token = bracketed!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + if content.is_empty() { + return Ok(Expr::Array(ExprArray { + attrs: inner_attrs, + bracket_token: bracket_token, + elems: Punctuated::new(), + })); + } + + let first: Expr = content.parse()?; + if content.is_empty() || content.peek(Token![,]) { + let mut elems = Punctuated::new(); + elems.push_value(first); + while !content.is_empty() { + let punct = content.parse()?; + elems.push_punct(punct); + if content.is_empty() { + break; + } + let value = content.parse()?; + elems.push_value(value); + } + Ok(Expr::Array(ExprArray { + attrs: inner_attrs, + bracket_token: bracket_token, + elems: elems, + })) + } else if content.peek(Token![;]) { + let semi_token: Token![;] = content.parse()?; + let len: Expr = content.parse()?; + Ok(Expr::Repeat(ExprRepeat { + attrs: inner_attrs, + bracket_token: bracket_token, + expr: Box::new(first), + semi_token: semi_token, + len: Box::new(len), + })) + } else { + Err(content.error("expected `,` or `;`")) + } + } + + #[cfg(feature = "full")] + fn expr_early(input: ParseStream) -> Result<Expr> { + let mut attrs = input.call(Attribute::parse_outer)?; + let mut expr = if input.peek(Token![if]) { + Expr::If(input.parse()?) + } else if input.peek(Token![while]) { + Expr::While(input.parse()?) + } else if input.peek(Token![for]) { + Expr::ForLoop(input.parse()?) + } else if input.peek(Token![loop]) { + Expr::Loop(input.parse()?) + } else if input.peek(Token![match]) { + Expr::Match(input.parse()?) + } else if input.peek(Token![try]) && input.peek2(token::Brace) { + Expr::TryBlock(input.call(expr_try_block)?) + } else if input.peek(Token![unsafe]) { + Expr::Unsafe(input.call(expr_unsafe)?) + } else if input.peek(token::Brace) { + Expr::Block(input.call(expr_block)?) + } else { + let allow_struct = AllowStruct(true); + let mut expr = unary_expr(input, allow_struct)?; + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + + return parse_expr(input, expr, allow_struct, Precedence::Any); + }; + + if input.peek(Token![.]) || input.peek(Token![?]) { + expr = trailer_helper(input, expr)?; + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + + let allow_struct = AllowStruct(true); + return parse_expr(input, expr, allow_struct, Precedence::Any); + } + + attrs.extend(expr.replace_attrs(Vec::new())); + expr.replace_attrs(attrs); + Ok(expr) + } + + impl Parse for ExprLit { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ExprLit { + attrs: Vec::new(), + lit: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + fn expr_group(input: ParseStream) -> Result<ExprGroup> { + let group = private::parse_group(input)?; + Ok(ExprGroup { + attrs: Vec::new(), + group_token: group.token, + expr: group.content.parse()?, + }) + } + + #[cfg(not(feature = "full"))] + fn expr_paren(input: ParseStream) -> Result<ExprParen> { + let content; + Ok(ExprParen { + attrs: Vec::new(), + paren_token: parenthesized!(content in input), + expr: content.parse()?, + }) + } + + #[cfg(feature = "full")] + fn generic_method_argument(input: ParseStream) -> Result<GenericMethodArgument> { + // TODO parse const generics as well + input.parse().map(GenericMethodArgument::Type) + } + + #[cfg(feature = "full")] + fn expr_let(input: ParseStream) -> Result<ExprLet> { + Ok(ExprLet { + attrs: Vec::new(), + let_token: input.parse()?, + pats: { + let mut pats = Punctuated::new(); + input.parse::<Option<Token![|]>>()?; + let value: Pat = input.parse()?; + pats.push_value(value); + while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { + let punct = input.parse()?; + pats.push_punct(punct); + let value: Pat = input.parse()?; + pats.push_value(value); + } + pats + }, + eq_token: input.parse()?, + expr: Box::new(input.call(expr_no_struct)?), + }) + } + + #[cfg(feature = "full")] + impl Parse for ExprIf { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ExprIf { + attrs: Vec::new(), + if_token: input.parse()?, + cond: Box::new(input.call(expr_no_struct)?), + then_branch: input.parse()?, + else_branch: { + if input.peek(Token![else]) { + Some(input.call(else_block)?) + } else { + None + } + }, + }) + } + } + + #[cfg(feature = "full")] + fn else_block(input: ParseStream) -> Result<(Token![else], Box<Expr>)> { + let else_token: Token![else] = input.parse()?; + + let lookahead = input.lookahead1(); + let else_branch = if input.peek(Token![if]) { + input.parse().map(Expr::If)? + } else if input.peek(token::Brace) { + Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: input.parse()?, + }) + } else { + return Err(lookahead.error()); + }; + + Ok((else_token, Box::new(else_branch))) + } + + #[cfg(feature = "full")] + impl Parse for ExprForLoop { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let for_token: Token![for] = input.parse()?; + let pat: Pat = input.parse()?; + let in_token: Token![in] = input.parse()?; + let expr: Expr = input.call(expr_no_struct)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprForLoop { + attrs: inner_attrs, + label: label, + for_token: for_token, + pat: Box::new(pat), + in_token: in_token, + expr: Box::new(expr), + body: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprLoop { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let loop_token: Token![loop] = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprLoop { + attrs: inner_attrs, + label: label, + loop_token: loop_token, + body: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprMatch { + fn parse(input: ParseStream) -> Result<Self> { + let match_token: Token![match] = input.parse()?; + let expr = expr_no_struct(input)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut arms = Vec::new(); + while !content.is_empty() { + arms.push(content.call(Arm::parse)?); + } + + Ok(ExprMatch { + attrs: inner_attrs, + match_token: match_token, + expr: Box::new(expr), + brace_token: brace_token, + arms: arms, + }) + } + } + + macro_rules! impl_by_parsing_expr { + ($expr_type:ty, $variant:ident, $msg:expr) => ( + #[cfg(all(feature = "full", feature = "printing"))] + impl Parse for $expr_type { + fn parse(input: ParseStream) -> Result<Self> { + let mut expr: Expr = input.parse()?; + loop { + match expr { + Expr::$variant(inner) => return Ok(inner), + Expr::Group(ExprGroup { expr: next, .. }) => expr = *next, + _ => return Err(Error::new_spanned(expr, $msg)) + } + } + } + } + ) + } + + impl_by_parsing_expr!(ExprBox, Box, "expected box expression"); + impl_by_parsing_expr!(ExprInPlace, InPlace, "expected placement expression"); + impl_by_parsing_expr!(ExprArray, Array, "expected slice literal expression"); + impl_by_parsing_expr!(ExprCall, Call, "expected function call expression"); + impl_by_parsing_expr!(ExprMethodCall, MethodCall, "expected method call expression"); + impl_by_parsing_expr!(ExprTuple, Tuple, "expected tuple expression"); + impl_by_parsing_expr!(ExprBinary, Binary, "expected binary operation"); + impl_by_parsing_expr!(ExprUnary, Unary, "expected unary operation"); + impl_by_parsing_expr!(ExprCast, Cast, "expected cast expression"); + impl_by_parsing_expr!(ExprType, Type, "expected type ascription expression"); + impl_by_parsing_expr!(ExprLet, Let, "expected let guard"); + impl_by_parsing_expr!(ExprClosure, Closure, "expected closure expression"); + impl_by_parsing_expr!(ExprUnsafe, Unsafe, "expected unsafe block"); + impl_by_parsing_expr!(ExprBlock, Block, "expected blocked scope"); + impl_by_parsing_expr!(ExprAssign, Assign, "expected assignment expression"); + impl_by_parsing_expr!(ExprAssignOp, AssignOp, "expected compound assignment expression"); + impl_by_parsing_expr!(ExprField, Field, "expected struct field access"); + impl_by_parsing_expr!(ExprIndex, Index, "expected indexing expression"); + impl_by_parsing_expr!(ExprRange, Range, "expected range expression"); + impl_by_parsing_expr!(ExprReference, Reference, "expected referencing operation"); + impl_by_parsing_expr!(ExprBreak, Break, "expected break expression"); + impl_by_parsing_expr!(ExprContinue, Continue, "expected continue expression"); + impl_by_parsing_expr!(ExprReturn, Return, "expected return expression"); + impl_by_parsing_expr!(ExprMacro, Macro, "expected macro invocation expression"); + impl_by_parsing_expr!(ExprStruct, Struct, "expected struct literal expression"); + impl_by_parsing_expr!(ExprRepeat, Repeat, "expected array literal constructed from one repeated element"); + impl_by_parsing_expr!(ExprParen, Paren, "expected parenthesized expression"); + impl_by_parsing_expr!(ExprTry, Try, "expected try expression"); + impl_by_parsing_expr!(ExprAsync, Async, "expected async block"); + impl_by_parsing_expr!(ExprTryBlock, TryBlock, "expected try block"); + impl_by_parsing_expr!(ExprYield, Yield, "expected yield expression"); + + #[cfg(feature = "full")] + fn expr_try_block(input: ParseStream) -> Result<ExprTryBlock> { + Ok(ExprTryBlock { + attrs: Vec::new(), + try_token: input.parse()?, + block: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn expr_yield(input: ParseStream) -> Result<ExprYield> { + Ok(ExprYield { + attrs: Vec::new(), + yield_token: input.parse()?, + expr: { + if !input.is_empty() && !input.peek(Token![,]) && !input.peek(Token![;]) { + Some(input.parse()?) + } else { + None + } + }, + }) + } + + #[cfg(feature = "full")] + fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprClosure> { + let asyncness: Option<Token![async]> = input.parse()?; + let movability: Option<Token![static]> = if asyncness.is_none() { + input.parse()? + } else { + None + }; + let capture: Option<Token![move]> = input.parse()?; + let or1_token: Token![|] = input.parse()?; + + let mut inputs = Punctuated::new(); + loop { + if input.peek(Token![|]) { + break; + } + let value = fn_arg(input)?; + inputs.push_value(value); + if input.peek(Token![|]) { + break; + } + let punct: Token![,] = input.parse()?; + inputs.push_punct(punct); + } + + let or2_token: Token![|] = input.parse()?; + + let (output, body) = if input.peek(Token![->]) { + let arrow_token: Token![->] = input.parse()?; + let ty: Type = input.parse()?; + let body: Block = input.parse()?; + let output = ReturnType::Type(arrow_token, Box::new(ty)); + let block = Expr::Block(ExprBlock { + attrs: Vec::new(), + label: None, + block: body, + }); + (output, block) + } else { + let body = ambiguous_expr(input, allow_struct)?; + (ReturnType::Default, body) + }; + + Ok(ExprClosure { + attrs: Vec::new(), + asyncness: asyncness, + movability: movability, + capture: capture, + or1_token: or1_token, + inputs: inputs, + or2_token: or2_token, + output: output, + body: Box::new(body), + }) + } + + #[cfg(feature = "full")] + fn expr_async(input: ParseStream) -> Result<ExprAsync> { + Ok(ExprAsync { + attrs: Vec::new(), + async_token: input.parse()?, + capture: input.parse()?, + block: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn fn_arg(input: ParseStream) -> Result<FnArg> { + let pat: Pat = input.parse()?; + + if input.peek(Token![:]) { + Ok(FnArg::Captured(ArgCaptured { + pat: pat, + colon_token: input.parse()?, + ty: input.parse()?, + })) + } else { + Ok(FnArg::Inferred(pat)) + } + } + + #[cfg(feature = "full")] + impl Parse for ExprWhile { + fn parse(input: ParseStream) -> Result<Self> { + let label: Option<Label> = input.parse()?; + let while_token: Token![while] = input.parse()?; + let cond = expr_no_struct(input)?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprWhile { + attrs: inner_attrs, + label: label, + while_token: while_token, + cond: Box::new(cond), + body: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Label { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Label { + name: input.parse()?, + colon_token: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Option<Label> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + #[cfg(feature = "full")] + fn expr_continue(input: ParseStream) -> Result<ExprContinue> { + Ok(ExprContinue { + attrs: Vec::new(), + continue_token: input.parse()?, + label: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn expr_break(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprBreak> { + Ok(ExprBreak { + attrs: Vec::new(), + break_token: input.parse()?, + label: input.parse()?, + expr: { + if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let expr = ambiguous_expr(input, allow_struct)?; + Some(Box::new(expr)) + } + }, + }) + } + + #[cfg(feature = "full")] + fn expr_ret(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprReturn> { + Ok(ExprReturn { + attrs: Vec::new(), + return_token: input.parse()?, + expr: { + if input.is_empty() || input.peek(Token![,]) || input.peek(Token![;]) { + None + } else { + // NOTE: return is greedy and eats blocks after it even when in a + // position where structs are not allowed, such as in if statement + // conditions. For example: + // + // if return { println!("A") } {} // Prints "A" + let expr = ambiguous_expr(input, allow_struct)?; + Some(Box::new(expr)) + } + }, + }) + } + + #[cfg(feature = "full")] + impl Parse for FieldValue { + fn parse(input: ParseStream) -> Result<Self> { + let member: Member = input.parse()?; + let (colon_token, value) = if input.peek(Token![:]) || !member.is_named() { + let colon_token: Token![:] = input.parse()?; + let value: Expr = input.parse()?; + (Some(colon_token), value) + } else if let Member::Named(ref ident) = member { + let value = Expr::Path(ExprPath { + attrs: Vec::new(), + qself: None, + path: Path::from(ident.clone()), + }); + (None, value) + } else { + unreachable!() + }; + + Ok(FieldValue { + attrs: Vec::new(), + member: member, + colon_token: colon_token, + expr: value, + }) + } + } + + #[cfg(feature = "full")] + fn expr_struct_helper( + input: ParseStream, + outer_attrs: Vec<Attribute>, + path: Path, + ) -> Result<ExprStruct> { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut fields = Punctuated::new(); + loop { + let attrs = content.call(Attribute::parse_outer)?; + if content.fork().parse::<Member>().is_err() { + if attrs.is_empty() { + break; + } else { + return Err(content.error("expected struct field")); + } + } + + fields.push(FieldValue { + attrs: attrs, + ..content.parse()? + }); + + if !content.peek(Token![,]) { + break; + } + let punct: Token![,] = content.parse()?; + fields.push_punct(punct); + } + + let (dot2_token, rest) = if fields.empty_or_trailing() && content.peek(Token![..]) { + let dot2_token: Token![..] = content.parse()?; + let rest: Expr = content.parse()?; + (Some(dot2_token), Some(Box::new(rest))) + } else { + (None, None) + }; + + Ok(ExprStruct { + attrs: private::attrs(outer_attrs, inner_attrs), + brace_token: brace_token, + path: path, + fields: fields, + dot2_token: dot2_token, + rest: rest, + }) + } + + #[cfg(feature = "full")] + fn expr_unsafe(input: ParseStream) -> Result<ExprUnsafe> { + let unsafe_token: Token![unsafe] = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprUnsafe { + attrs: inner_attrs, + unsafe_token: unsafe_token, + block: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + + #[cfg(feature = "full")] + pub fn expr_block(input: ParseStream) -> Result<ExprBlock> { + let label: Option<Label> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ExprBlock { + attrs: inner_attrs, + label: label, + block: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + + #[cfg(feature = "full")] + fn expr_range(input: ParseStream, allow_struct: AllowStruct) -> Result<ExprRange> { + Ok(ExprRange { + attrs: Vec::new(), + from: None, + limits: input.parse()?, + to: { + if input.is_empty() + || input.peek(Token![,]) + || input.peek(Token![;]) + || !allow_struct.0 && input.peek(token::Brace) + { + None + } else { + let to = ambiguous_expr(input, allow_struct)?; + Some(Box::new(to)) + } + }, + }) + } + + #[cfg(feature = "full")] + impl Parse for RangeLimits { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![..=]) { + input.parse().map(RangeLimits::Closed) + } else if lookahead.peek(Token![...]) { + let dot3: Token![...] = input.parse()?; + Ok(RangeLimits::Closed(Token![..=](dot3.spans))) + } else if lookahead.peek(Token![..]) { + input.parse().map(RangeLimits::HalfOpen) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ExprPath { + fn parse(input: ParseStream) -> Result<Self> { + #[cfg(not(feature = "full"))] + let attrs = Vec::new(); + #[cfg(feature = "full")] + let attrs = input.call(Attribute::parse_outer)?; + + let (qself, path) = path::parsing::qpath(input, true)?; + + Ok(ExprPath { + attrs: attrs, + qself: qself, + path: path, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Block { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(Block { + brace_token: braced!(content in input), + stmts: content.call(Block::parse_within)?, + }) + } + } + + #[cfg(feature = "full")] + impl Block { + /// Parse the body of a block as zero or more statements, possibly + /// including one trailing expression. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parse a function with no generics or parameter list. + /// // + /// // fn playground { + /// // let mut x = 1; + /// // x += 1; + /// // println!("{}", x); + /// // } + /// struct MiniFunction { + /// attrs: Vec<Attribute>, + /// fn_token: Token![fn], + /// name: Ident, + /// brace_token: token::Brace, + /// stmts: Vec<Stmt>, + /// } + /// + /// impl Parse for MiniFunction { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let outer_attrs = input.call(Attribute::parse_outer)?; + /// let fn_token: Token![fn] = input.parse()?; + /// let name: Ident = input.parse()?; + /// + /// let content; + /// let brace_token = braced!(content in input); + /// let inner_attrs = content.call(Attribute::parse_inner)?; + /// let stmts = content.call(Block::parse_within)?; + /// + /// Ok(MiniFunction { + /// attrs: { + /// let mut attrs = outer_attrs; + /// attrs.extend(inner_attrs); + /// attrs + /// }, + /// fn_token: fn_token, + /// name: name, + /// brace_token: brace_token, + /// stmts: stmts, + /// }) + /// } + /// } + /// ``` + pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> { + let mut stmts = Vec::new(); + loop { + while input.peek(Token![;]) { + input.parse::<Token![;]>()?; + } + if input.is_empty() { + break; + } + let s = parse_stmt(input, true)?; + let requires_semicolon = if let Stmt::Expr(ref s) = s { + requires_terminator(s) + } else { + false + }; + stmts.push(s); + if input.is_empty() { + break; + } else if requires_semicolon { + return Err(input.error("unexpected token")); + } + } + Ok(stmts) + } + } + + #[cfg(feature = "full")] + impl Parse for Stmt { + fn parse(input: ParseStream) -> Result<Self> { + parse_stmt(input, false) + } + } + + #[cfg(feature = "full")] + fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + + if { + let ahead = ahead.fork(); + // Only parse braces here; paren and bracket will get parsed as + // expression statements + ahead.call(Path::parse_mod_style).is_ok() + && ahead.parse::<Token![!]>().is_ok() + && (ahead.peek(token::Brace) || ahead.peek(Ident)) + } { + stmt_mac(input) + } else if ahead.peek(Token![let]) { + stmt_local(input).map(Stmt::Local) + } else if ahead.peek(Token![pub]) + || ahead.peek(Token![crate]) && !ahead.peek2(Token![::]) + || ahead.peek(Token![extern]) && !ahead.peek2(Token![::]) + || ahead.peek(Token![use]) + || ahead.peek(Token![static]) && (ahead.peek2(Token![mut]) || ahead.peek2(Ident)) + || ahead.peek(Token![const]) + || ahead.peek(Token![unsafe]) && !ahead.peek2(token::Brace) + || ahead.peek(Token![async]) && (ahead.peek2(Token![extern]) || ahead.peek2(Token![fn])) + || ahead.peek(Token![fn]) + || ahead.peek(Token![mod]) + || ahead.peek(Token![type]) + || ahead.peek(Token![existential]) && ahead.peek2(Token![type]) + || ahead.peek(Token![struct]) + || ahead.peek(Token![enum]) + || ahead.peek(Token![union]) && ahead.peek2(Ident) + || ahead.peek(Token![auto]) && ahead.peek2(Token![trait]) + || ahead.peek(Token![trait]) + || ahead.peek(Token![default]) + && (ahead.peek2(Token![unsafe]) || ahead.peek2(Token![impl])) + || ahead.peek(Token![impl]) + || ahead.peek(Token![macro]) + { + input.parse().map(Stmt::Item) + } else { + stmt_expr(input, allow_nosemi) + } + } + + #[cfg(feature = "full")] + fn stmt_mac(input: ParseStream) -> Result<Stmt> { + let attrs = input.call(Attribute::parse_outer)?; + let path = input.call(Path::parse_mod_style)?; + let bang_token: Token![!] = input.parse()?; + let ident: Option<Ident> = input.parse()?; + let (delimiter, tts) = mac::parse_delimiter(input)?; + let semi_token: Option<Token![;]> = input.parse()?; + + Ok(Stmt::Item(Item::Macro(ItemMacro { + attrs: attrs, + ident: ident, + mac: Macro { + path: path, + bang_token: bang_token, + delimiter: delimiter, + tts: tts, + }, + semi_token: semi_token, + }))) + } + + #[cfg(feature = "full")] + fn stmt_local(input: ParseStream) -> Result<Local> { + Ok(Local { + attrs: input.call(Attribute::parse_outer)?, + let_token: input.parse()?, + pats: { + let mut pats = Punctuated::new(); + let value: Pat = input.parse()?; + pats.push_value(value); + while input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=]) { + let punct = input.parse()?; + pats.push_punct(punct); + let value: Pat = input.parse()?; + pats.push_value(value); + } + pats + }, + ty: { + if input.peek(Token![:]) { + let colon_token: Token![:] = input.parse()?; + let ty: Type = input.parse()?; + Some((colon_token, Box::new(ty))) + } else { + None + } + }, + init: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let init: Expr = input.parse()?; + Some((eq_token, Box::new(init))) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn stmt_expr(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> { + let mut attrs = input.call(Attribute::parse_outer)?; + let mut e = expr_early(input)?; + + attrs.extend(e.replace_attrs(Vec::new())); + e.replace_attrs(attrs); + + if input.peek(Token![;]) { + return Ok(Stmt::Semi(e, input.parse()?)); + } + + if allow_nosemi || !requires_terminator(&e) { + Ok(Stmt::Expr(e)) + } else { + Err(input.error("expected semicolon")) + } + } + + #[cfg(feature = "full")] + impl Parse for Pat { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![_]) { + input.call(pat_wild).map(Pat::Wild) + } else if lookahead.peek(Token![box]) { + input.call(pat_box).map(Pat::Box) + } else if lookahead.peek(Token![-]) || lookahead.peek(Lit) { + pat_lit_or_range(input) + } else if input.peek(Ident) + && ({ + input.peek2(Token![::]) + || input.peek2(Token![!]) + || input.peek2(token::Brace) + || input.peek2(token::Paren) + || input.peek2(Token![..]) + && !{ + let ahead = input.fork(); + ahead.parse::<Ident>()?; + ahead.parse::<RangeLimits>()?; + ahead.is_empty() || ahead.peek(Token![,]) + } + }) + || input.peek(Token![self]) && input.peek2(Token![::]) + || input.peek(Token![::]) + || input.peek(Token![<]) + || input.peek(Token![Self]) + || input.peek(Token![super]) + || input.peek(Token![extern]) + || input.peek(Token![crate]) + { + pat_path_or_macro_or_struct_or_range(input) + } else if input.peek(Token![ref]) + || input.peek(Token![mut]) + || input.peek(Token![self]) + || input.peek(Ident) + { + input.call(pat_ident).map(Pat::Ident) + } else if lookahead.peek(token::Paren) { + input.call(pat_tuple).map(Pat::Tuple) + } else if lookahead.peek(Token![&]) { + input.call(pat_ref).map(Pat::Ref) + } else if lookahead.peek(token::Bracket) { + input.call(pat_slice).map(Pat::Slice) + } else { + Err(lookahead.error()) + } + } + } + + #[cfg(feature = "full")] + fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> { + let (qself, path) = path::parsing::qpath(input, true)?; + + if input.peek(Token![..]) { + return pat_range(input, qself, path).map(Pat::Range); + } + + if qself.is_some() { + return Ok(Pat::Path(PatPath { + qself: qself, + path: path, + })); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tts) = mac::parse_delimiter(input)?; + return Ok(Pat::Macro(PatMacro { + mac: Macro { + path: path, + bang_token: bang_token, + delimiter: delimiter, + tts: tts, + }, + })); + } + } + + if input.peek(token::Brace) { + pat_struct(input, path).map(Pat::Struct) + } else if input.peek(token::Paren) { + pat_tuple_struct(input, path).map(Pat::TupleStruct) + } else if input.peek(Token![..]) { + pat_range(input, qself, path).map(Pat::Range) + } else { + Ok(Pat::Path(PatPath { + qself: qself, + path: path, + })) + } + } + + #[cfg(feature = "full")] + fn pat_wild(input: ParseStream) -> Result<PatWild> { + Ok(PatWild { + underscore_token: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn pat_box(input: ParseStream) -> Result<PatBox> { + Ok(PatBox { + box_token: input.parse()?, + pat: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn pat_ident(input: ParseStream) -> Result<PatIdent> { + Ok(PatIdent { + by_ref: input.parse()?, + mutability: input.parse()?, + ident: input.call(Ident::parse_any)?, + subpat: { + if input.peek(Token![@]) { + let at_token: Token![@] = input.parse()?; + let subpat: Pat = input.parse()?; + Some((at_token, Box::new(subpat))) + } else { + None + } + }, + }) + } + + #[cfg(feature = "full")] + fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> { + Ok(PatTupleStruct { + path: path, + pat: input.call(pat_tuple)?, + }) + } + + #[cfg(feature = "full")] + fn pat_struct(input: ParseStream, path: Path) -> Result<PatStruct> { + let content; + let brace_token = braced!(content in input); + + let mut fields = Punctuated::new(); + while !content.is_empty() && !content.peek(Token![..]) { + let value = content.call(field_pat)?; + fields.push_value(value); + if !content.peek(Token![,]) { + break; + } + let punct: Token![,] = content.parse()?; + fields.push_punct(punct); + } + + let dot2_token = if fields.empty_or_trailing() && content.peek(Token![..]) { + Some(content.parse()?) + } else { + None + }; + + Ok(PatStruct { + path: path, + brace_token: brace_token, + fields: fields, + dot2_token: dot2_token, + }) + } + + #[cfg(feature = "full")] + fn field_pat(input: ParseStream) -> Result<FieldPat> { + let boxed: Option<Token![box]> = input.parse()?; + let by_ref: Option<Token![ref]> = input.parse()?; + let mutability: Option<Token![mut]> = input.parse()?; + let member: Member = input.parse()?; + + if boxed.is_none() && by_ref.is_none() && mutability.is_none() && input.peek(Token![:]) + || member.is_unnamed() + { + return Ok(FieldPat { + attrs: Vec::new(), + member: member, + colon_token: input.parse()?, + pat: input.parse()?, + }); + } + + let ident = match member { + Member::Named(ident) => ident, + Member::Unnamed(_) => unreachable!(), + }; + + let mut pat = Pat::Ident(PatIdent { + by_ref: by_ref, + mutability: mutability, + ident: ident.clone(), + subpat: None, + }); + + if let Some(boxed) = boxed { + pat = Pat::Box(PatBox { + pat: Box::new(pat), + box_token: boxed, + }); + } + + Ok(FieldPat { + member: Member::Named(ident), + pat: Box::new(pat), + attrs: Vec::new(), + colon_token: None, + }) + } + + impl Parse for Member { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Ident) { + input.parse().map(Member::Named) + } else if input.peek(LitInt) { + input.parse().map(Member::Unnamed) + } else { + Err(input.error("expected identifier or integer")) + } + } + } + + #[cfg(feature = "full")] + impl Parse for Arm { + fn parse(input: ParseStream) -> Result<Arm> { + let requires_comma; + Ok(Arm { + attrs: input.call(Attribute::parse_outer)?, + leading_vert: input.parse()?, + pats: { + let mut pats = Punctuated::new(); + let value: Pat = input.parse()?; + pats.push_value(value); + loop { + if !input.peek(Token![|]) { + break; + } + let punct = input.parse()?; + pats.push_punct(punct); + let value: Pat = input.parse()?; + pats.push_value(value); + } + pats + }, + guard: { + if input.peek(Token![if]) { + let if_token: Token![if] = input.parse()?; + let guard: Expr = input.parse()?; + Some((if_token, Box::new(guard))) + } else { + None + } + }, + fat_arrow_token: input.parse()?, + body: { + let body = input.call(expr_early)?; + requires_comma = requires_terminator(&body); + Box::new(body) + }, + comma: { + if requires_comma && !input.is_empty() { + Some(input.parse()?) + } else { + input.parse()? + } + }, + }) + } + } + + impl Parse for Index { + fn parse(input: ParseStream) -> Result<Self> { + let lit: LitInt = input.parse()?; + if let IntSuffix::None = lit.suffix() { + Ok(Index { + index: lit.value() as u32, + span: lit.span(), + }) + } else { + Err(Error::new(lit.span(), "expected unsuffixed integer")) + } + } + } + + #[cfg(feature = "full")] + fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatRange> { + Ok(PatRange { + lo: Box::new(Expr::Path(ExprPath { + attrs: Vec::new(), + qself: qself, + path: path, + })), + limits: input.parse()?, + hi: input.call(pat_lit_expr)?, + }) + } + + #[cfg(feature = "full")] + fn pat_tuple(input: ParseStream) -> Result<PatTuple> { + let content; + let paren_token = parenthesized!(content in input); + + let mut front = Punctuated::new(); + let mut dot2_token = None::<Token![..]>; + let mut comma_token = None::<Token![,]>; + loop { + if content.is_empty() { + break; + } + if content.peek(Token![..]) { + dot2_token = Some(content.parse()?); + comma_token = content.parse()?; + break; + } + let value: Pat = content.parse()?; + front.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + front.push_punct(punct); + } + + let mut back = Punctuated::new(); + while !content.is_empty() { + let value: Pat = content.parse()?; + back.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + back.push_punct(punct); + } + + Ok(PatTuple { + paren_token: paren_token, + front: front, + dot2_token: dot2_token, + comma_token: comma_token, + back: back, + }) + } + + #[cfg(feature = "full")] + fn pat_ref(input: ParseStream) -> Result<PatRef> { + Ok(PatRef { + and_token: input.parse()?, + mutability: input.parse()?, + pat: input.parse()?, + }) + } + + #[cfg(feature = "full")] + fn pat_lit_or_range(input: ParseStream) -> Result<Pat> { + let lo = input.call(pat_lit_expr)?; + if input.peek(Token![..]) { + Ok(Pat::Range(PatRange { + lo: lo, + limits: input.parse()?, + hi: input.call(pat_lit_expr)?, + })) + } else { + Ok(Pat::Lit(PatLit { expr: lo })) + } + } + + #[cfg(feature = "full")] + fn pat_lit_expr(input: ParseStream) -> Result<Box<Expr>> { + let neg: Option<Token![-]> = input.parse()?; + + let lookahead = input.lookahead1(); + let expr = if lookahead.peek(Lit) { + Expr::Lit(input.parse()?) + } else if lookahead.peek(Ident) + || lookahead.peek(Token![::]) + || lookahead.peek(Token![<]) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![Self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + { + Expr::Path(input.parse()?) + } else { + return Err(lookahead.error()); + }; + + Ok(Box::new(if let Some(neg) = neg { + Expr::Unary(ExprUnary { + attrs: Vec::new(), + op: UnOp::Neg(neg), + expr: Box::new(expr), + }) + } else { + expr + })) + } + + #[cfg(feature = "full")] + fn pat_slice(input: ParseStream) -> Result<PatSlice> { + let content; + let bracket_token = bracketed!(content in input); + + let mut front = Punctuated::new(); + let mut middle = None; + loop { + if content.is_empty() || content.peek(Token![..]) { + break; + } + let value: Pat = content.parse()?; + if content.peek(Token![..]) { + middle = Some(Box::new(value)); + break; + } + front.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + front.push_punct(punct); + } + + let dot2_token: Option<Token![..]> = content.parse()?; + let mut comma_token = None::<Token![,]>; + let mut back = Punctuated::new(); + if dot2_token.is_some() { + comma_token = content.parse()?; + if comma_token.is_some() { + loop { + if content.is_empty() { + break; + } + let value: Pat = content.parse()?; + back.push_value(value); + if content.is_empty() { + break; + } + let punct = content.parse()?; + back.push_punct(punct); + } + } + } + + Ok(PatSlice { + bracket_token: bracket_token, + front: front, + middle: middle, + dot2_token: dot2_token, + comma_token: comma_token, + back: back, + }) + } + + #[cfg(feature = "full")] + impl Member { + fn is_named(&self) -> bool { + match *self { + Member::Named(_) => true, + Member::Unnamed(_) => false, + } + } + + fn is_unnamed(&self) -> bool { + match *self { + Member::Named(_) => false, + Member::Unnamed(_) => true, + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::{Literal, TokenStream}; + use quote::{ToTokens, TokenStreamExt}; + + #[cfg(feature = "full")] + use attr::FilterAttrs; + #[cfg(feature = "full")] + use print::TokensOrDefault; + + // If the given expression is a bare `ExprStruct`, wraps it in parenthesis + // before appending it to `TokenStream`. + #[cfg(feature = "full")] + fn wrap_bare_struct(tokens: &mut TokenStream, e: &Expr) { + if let Expr::Struct(_) = *e { + token::Paren::default().surround(tokens, |tokens| { + e.to_tokens(tokens); + }); + } else { + e.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + fn outer_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) { + tokens.append_all(attrs.outer()); + } + + #[cfg(feature = "full")] + fn inner_attrs_to_tokens(attrs: &[Attribute], tokens: &mut TokenStream) { + tokens.append_all(attrs.inner()); + } + + #[cfg(not(feature = "full"))] + fn outer_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {} + + #[cfg(not(feature = "full"))] + fn inner_attrs_to_tokens(_attrs: &[Attribute], _tokens: &mut TokenStream) {} + + #[cfg(feature = "full")] + impl ToTokens for ExprBox { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.box_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprInPlace { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.place.to_tokens(tokens); + self.arrow_token.to_tokens(tokens); + self.value.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprArray { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.bracket_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + self.elems.to_tokens(tokens); + }) + } + } + + impl ToTokens for ExprCall { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.func.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.args.to_tokens(tokens); + }) + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprMethodCall { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.receiver.to_tokens(tokens); + self.dot_token.to_tokens(tokens); + self.method.to_tokens(tokens); + self.turbofish.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.args.to_tokens(tokens); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for MethodTurbofish { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.colon2_token.to_tokens(tokens); + self.lt_token.to_tokens(tokens); + self.args.to_tokens(tokens); + self.gt_token.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for GenericMethodArgument { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + GenericMethodArgument::Type(ref t) => t.to_tokens(tokens), + GenericMethodArgument::Const(ref c) => c.to_tokens(tokens), + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprTuple { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.paren_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + self.elems.to_tokens(tokens); + // If we only have one argument, we need a trailing comma to + // distinguish ExprTuple from ExprParen. + if self.elems.len() == 1 && !self.elems.trailing_punct() { + <Token![,]>::default().to_tokens(tokens); + } + }) + } + } + + impl ToTokens for ExprBinary { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.left.to_tokens(tokens); + self.op.to_tokens(tokens); + self.right.to_tokens(tokens); + } + } + + impl ToTokens for ExprUnary { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.op.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + impl ToTokens for ExprLit { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.lit.to_tokens(tokens); + } + } + + impl ToTokens for ExprCast { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + self.as_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprType { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + fn maybe_wrap_else(tokens: &mut TokenStream, else_: &Option<(Token![else], Box<Expr>)>) { + if let Some((ref else_token, ref else_)) = *else_ { + else_token.to_tokens(tokens); + + // If we are not one of the valid expressions to exist in an else + // clause, wrap ourselves in a block. + match **else_ { + Expr::If(_) | Expr::Block(_) => { + else_.to_tokens(tokens); + } + _ => { + token::Brace::default().surround(tokens, |tokens| { + else_.to_tokens(tokens); + }); + } + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprLet { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.let_token.to_tokens(tokens); + self.pats.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.expr); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprIf { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.if_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.cond); + self.then_branch.to_tokens(tokens); + maybe_wrap_else(tokens, &self.else_branch); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprWhile { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.label.to_tokens(tokens); + self.while_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.cond); + self.body.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.body.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprForLoop { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.label.to_tokens(tokens); + self.for_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + self.in_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.expr); + self.body.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.body.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprLoop { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.label.to_tokens(tokens); + self.loop_token.to_tokens(tokens); + self.body.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.body.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprMatch { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.match_token.to_tokens(tokens); + wrap_bare_struct(tokens, &self.expr); + self.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + for (i, arm) in self.arms.iter().enumerate() { + arm.to_tokens(tokens); + // Ensure that we have a comma after a non-block arm, except + // for the last one. + let is_last = i == self.arms.len() - 1; + if !is_last && requires_terminator(&arm.body) && arm.comma.is_none() { + <Token![,]>::default().to_tokens(tokens); + } + } + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprAsync { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.async_token.to_tokens(tokens); + self.capture.to_tokens(tokens); + self.block.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprTryBlock { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.try_token.to_tokens(tokens); + self.block.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprYield { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.yield_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprClosure { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.asyncness.to_tokens(tokens); + self.movability.to_tokens(tokens); + self.capture.to_tokens(tokens); + self.or1_token.to_tokens(tokens); + for input in self.inputs.pairs() { + match **input.value() { + FnArg::Captured(ArgCaptured { + ref pat, + ty: Type::Infer(_), + .. + }) => { + pat.to_tokens(tokens); + } + _ => input.value().to_tokens(tokens), + } + input.punct().to_tokens(tokens); + } + self.or2_token.to_tokens(tokens); + self.output.to_tokens(tokens); + self.body.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprUnsafe { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.unsafe_token.to_tokens(tokens); + self.block.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.block.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprBlock { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.label.to_tokens(tokens); + self.block.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + tokens.append_all(&self.block.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprAssign { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.left.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.right.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprAssignOp { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.left.to_tokens(tokens); + self.op.to_tokens(tokens); + self.right.to_tokens(tokens); + } + } + + impl ToTokens for ExprField { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.base.to_tokens(tokens); + self.dot_token.to_tokens(tokens); + self.member.to_tokens(tokens); + } + } + + impl ToTokens for Member { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + Member::Named(ref ident) => ident.to_tokens(tokens), + Member::Unnamed(ref index) => index.to_tokens(tokens), + } + } + } + + impl ToTokens for Index { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut lit = Literal::i64_unsuffixed(i64::from(self.index)); + lit.set_span(self.span); + tokens.append(lit); + } + } + + impl ToTokens for ExprIndex { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + self.bracket_token.surround(tokens, |tokens| { + self.index.to_tokens(tokens); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprRange { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.from.to_tokens(tokens); + match self.limits { + RangeLimits::HalfOpen(ref t) => t.to_tokens(tokens), + RangeLimits::Closed(ref t) => t.to_tokens(tokens), + } + self.to.to_tokens(tokens); + } + } + + impl ToTokens for ExprPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + private::print_path(tokens, &self.qself, &self.path); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprReference { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.and_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprBreak { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.break_token.to_tokens(tokens); + self.label.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprContinue { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.continue_token.to_tokens(tokens); + self.label.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprReturn { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.return_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.mac.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.path.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + self.fields.to_tokens(tokens); + if self.rest.is_some() { + TokensOrDefault(&self.dot2_token).to_tokens(tokens); + self.rest.to_tokens(tokens); + } + }) + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprRepeat { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.bracket_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + self.len.to_tokens(tokens); + }) + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprGroup { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.group_token.surround(tokens, |tokens| { + self.expr.to_tokens(tokens); + }); + } + } + + impl ToTokens for ExprParen { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.paren_token.surround(tokens, |tokens| { + inner_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for ExprTry { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.expr.to_tokens(tokens); + self.question_token.to_tokens(tokens); + } + } + + impl ToTokens for ExprVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for Label { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.name.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for FieldValue { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.member.to_tokens(tokens); + if let Some(ref colon_token) = self.colon_token { + colon_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for Arm { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.leading_vert.to_tokens(tokens); + self.pats.to_tokens(tokens); + if let Some((ref if_token, ref guard)) = self.guard { + if_token.to_tokens(tokens); + guard.to_tokens(tokens); + } + self.fat_arrow_token.to_tokens(tokens); + self.body.to_tokens(tokens); + self.comma.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatWild { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.underscore_token.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatIdent { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.by_ref.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.ident.to_tokens(tokens); + if let Some((ref at_token, ref subpat)) = self.subpat { + at_token.to_tokens(tokens); + subpat.to_tokens(tokens); + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.path.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + self.fields.to_tokens(tokens); + // NOTE: We need a comma before the dot2 token if it is present. + if !self.fields.empty_or_trailing() && self.dot2_token.is_some() { + <Token![,]>::default().to_tokens(tokens); + } + self.dot2_token.to_tokens(tokens); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatTupleStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.path.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatPath { + fn to_tokens(&self, tokens: &mut TokenStream) { + private::print_path(tokens, &self.qself, &self.path); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatTuple { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.front.to_tokens(tokens); + if let Some(ref dot2_token) = self.dot2_token { + if !self.front.empty_or_trailing() { + // Ensure there is a comma before the .. token. + <Token![,]>::default().to_tokens(tokens); + } + dot2_token.to_tokens(tokens); + self.comma_token.to_tokens(tokens); + if self.comma_token.is_none() && !self.back.is_empty() { + // Ensure there is a comma after the .. token. + <Token![,]>::default().to_tokens(tokens); + } + } + self.back.to_tokens(tokens); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatBox { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.box_token.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatRef { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.and_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.pat.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatLit { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.expr.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatRange { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lo.to_tokens(tokens); + match self.limits { + RangeLimits::HalfOpen(ref t) => t.to_tokens(tokens), + RangeLimits::Closed(ref t) => Token![...](t.spans).to_tokens(tokens), + } + self.hi.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatSlice { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bracket_token.surround(tokens, |tokens| { + self.front.to_tokens(tokens); + + // If we need a comma before the middle or standalone .. token, + // then make sure it's present. + if !self.front.empty_or_trailing() + && (self.middle.is_some() || self.dot2_token.is_some()) + { + <Token![,]>::default().to_tokens(tokens); + } + + // If we have an identifier, we always need a .. token. + if self.middle.is_some() { + self.middle.to_tokens(tokens); + TokensOrDefault(&self.dot2_token).to_tokens(tokens); + } else if self.dot2_token.is_some() { + self.dot2_token.to_tokens(tokens); + } + + // Make sure we have a comma before the back half. + if !self.back.is_empty() { + TokensOrDefault(&self.comma_token).to_tokens(tokens); + self.back.to_tokens(tokens); + } else { + self.comma_token.to_tokens(tokens); + } + }) + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.mac.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for PatVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for FieldPat { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(ref colon_token) = self.colon_token { + self.member.to_tokens(tokens); + colon_token.to_tokens(tokens); + } + self.pat.to_tokens(tokens); + } + } + + #[cfg(feature = "full")] + impl ToTokens for Block { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(&self.stmts); + }); + } + } + + #[cfg(feature = "full")] + impl ToTokens for Stmt { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + Stmt::Local(ref local) => local.to_tokens(tokens), + Stmt::Item(ref item) => item.to_tokens(tokens), + Stmt::Expr(ref expr) => expr.to_tokens(tokens), + Stmt::Semi(ref expr, ref semi) => { + expr.to_tokens(tokens); + semi.to_tokens(tokens); + } + } + } + } + + #[cfg(feature = "full")] + impl ToTokens for Local { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.let_token.to_tokens(tokens); + self.pats.to_tokens(tokens); + if let Some((ref colon_token, ref ty)) = self.ty { + colon_token.to_tokens(tokens); + ty.to_tokens(tokens); + } + if let Some((ref eq_token, ref init)) = self.init { + eq_token.to_tokens(tokens); + init.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } +} diff --git a/syn/src/ext.rs b/syn/src/ext.rs new file mode 100644 index 000000000..17721d56d --- /dev/null +++ b/syn/src/ext.rs @@ -0,0 +1,145 @@ +//! Extension traits to provide parsing methods on foreign types. +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +use proc_macro2::Ident; + +use parse::{ParseStream, Result}; + +#[cfg(syn_can_use_associated_constants)] +use buffer::Cursor; +#[cfg(syn_can_use_associated_constants)] +use parse::Peek; +#[cfg(syn_can_use_associated_constants)] +use sealed::lookahead; +#[cfg(syn_can_use_associated_constants)] +use token::CustomToken; + +/// Additional methods for `Ident` not provided by proc-macro2 or libproc_macro. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. It +/// is implemented only for `proc_macro2::Ident`. +/// +/// *This trait is available if Syn is built with the `"parsing"` feature.* +pub trait IdentExt: Sized + private::Sealed { + /// Parses any identifier including keywords. + /// + /// This is useful when parsing macro input which allows Rust keywords as + /// identifiers. + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{Error, Ident, Result, Token}; + /// use syn::ext::IdentExt; + /// use syn::parse::ParseStream; + /// + /// mod kw { + /// syn::custom_keyword!(name); + /// } + /// + /// // Parses input that looks like `name = NAME` where `NAME` can be + /// // any identifier. + /// // + /// // Examples: + /// // + /// // name = anything + /// // name = impl + /// fn parse_dsl(input: ParseStream) -> Result<Ident> { + /// input.parse::<kw::name>()?; + /// input.parse::<Token![=]>()?; + /// let name = input.call(Ident::parse_any)?; + /// Ok(name) + /// } + /// ``` + fn parse_any(input: ParseStream) -> Result<Self>; + + /// Peeks any identifier including keywords. Usage: + /// `input.peek(Ident::peek_any)` + /// + /// This is different from `input.peek(Ident)` which only returns true in + /// the case of an ident which is not a Rust keyword. + #[cfg(syn_can_use_associated_constants)] + #[allow(non_upper_case_globals)] + const peek_any: private::PeekFn = private::PeekFn; + + /// Strips the raw marker `r#`, if any, from the beginning of an ident. + /// + /// - unraw(`x`) = `x` + /// - unraw(`move`) = `move` + /// - unraw(`r#move`) = `move` + /// + /// # Example + /// + /// In the case of interop with other languages like Python that have a + /// different set of keywords than Rust, we might come across macro input + /// that involves raw identifiers to refer to ordinary variables in the + /// other language with a name that happens to be a Rust keyword. + /// + /// The function below appends an identifier from the caller's input onto a + /// fixed prefix. Without using `unraw()`, this would tend to produce + /// invalid identifiers like `__pyo3_get_r#move`. + /// + /// ```edition2018 + /// use proc_macro2::Span; + /// use syn::Ident; + /// use syn::ext::IdentExt; + /// + /// fn ident_for_getter(variable: &Ident) -> Ident { + /// let getter = format!("__pyo3_get_{}", variable.unraw()); + /// Ident::new(&getter, Span::call_site()) + /// } + /// ``` + fn unraw(&self) -> Ident; +} + +impl IdentExt for Ident { + fn parse_any(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.ident() { + Some((ident, rest)) => Ok((ident, rest)), + None => Err(cursor.error("expected ident")), + }) + } + + fn unraw(&self) -> Ident { + let string = self.to_string(); + if string.starts_with("r#") { + Ident::new(&string[2..], self.span()) + } else { + self.clone() + } + } +} + +#[cfg(syn_can_use_associated_constants)] +impl Peek for private::PeekFn { + type Token = private::IdentAny; +} + +#[cfg(syn_can_use_associated_constants)] +impl CustomToken for private::IdentAny { + fn peek(cursor: Cursor) -> bool { + cursor.ident().is_some() + } + + fn display() -> &'static str { + "identifier" + } +} + +#[cfg(syn_can_use_associated_constants)] +impl lookahead::Sealed for private::PeekFn {} + +mod private { + use proc_macro2::Ident; + + pub trait Sealed {} + + impl Sealed for Ident {} + + #[cfg(syn_can_use_associated_constants)] + #[derive(Copy, Clone)] + pub struct PeekFn; + #[cfg(syn_can_use_associated_constants)] + pub struct IdentAny; +} diff --git a/syn/src/file.rs b/syn/src/file.rs new file mode 100644 index 000000000..30defe7df --- /dev/null +++ b/syn/src/file.rs @@ -0,0 +1,113 @@ +use super::*; + +ast_struct! { + /// A complete file of Rust source code. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Example + /// + /// Parse a Rust source file into a `syn::File` and print out a debug + /// representation of the syntax tree. + /// + /// ```edition2018 + /// use std::env; + /// use std::fs::File; + /// use std::io::Read; + /// use std::process; + /// + /// fn main() { + /// # } + /// # + /// # fn fake_main() { + /// let mut args = env::args(); + /// let _ = args.next(); // executable name + /// + /// let filename = match (args.next(), args.next()) { + /// (Some(filename), None) => filename, + /// _ => { + /// eprintln!("Usage: dump-syntax path/to/filename.rs"); + /// process::exit(1); + /// } + /// }; + /// + /// let mut file = File::open(&filename).expect("Unable to open file"); + /// + /// let mut src = String::new(); + /// file.read_to_string(&mut src).expect("Unable to read file"); + /// + /// let syntax = syn::parse_file(&src).expect("Unable to parse file"); + /// println!("{:#?}", syntax); + /// } + /// ``` + /// + /// Running with its own source code as input, this program prints output + /// that begins with: + /// + /// ```text + /// File { + /// shebang: None, + /// attrs: [], + /// items: [ + /// ExternCrate( + /// ItemExternCrate { + /// attrs: [], + /// vis: Inherited, + /// extern_token: Extern, + /// crate_token: Crate, + /// ident: Ident { + /// term: Term( + /// "syn" + /// ), + /// span: Span + /// }, + /// rename: None, + /// semi_token: Semi + /// } + /// ), + /// ... + /// ``` + pub struct File { + pub shebang: Option<String>, + pub attrs: Vec<Attribute>, + pub items: Vec<Item>, + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + impl Parse for File { + fn parse(input: ParseStream) -> Result<Self> { + Ok(File { + shebang: None, + attrs: input.call(Attribute::parse_inner)?, + items: { + let mut items = Vec::new(); + while !input.is_empty() { + items.push(input.parse()?); + } + items + }, + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use attr::FilterAttrs; + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + impl ToTokens for File { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&self.items); + } + } +} diff --git a/syn/src/gen/fold.rs b/syn/src/gen/fold.rs new file mode 100644 index 000000000..c8a0d6912 --- /dev/null +++ b/syn/src/gen/fold.rs @@ -0,0 +1,2937 @@ +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT + +#![allow(unreachable_code)] +#[cfg(any(feature = "full", feature = "derive"))] +use gen::helper::fold::*; +use proc_macro2::Span; +#[cfg(any(feature = "full", feature = "derive"))] +use token::{Brace, Bracket, Group, Paren}; +use *; +#[cfg(feature = "full")] +macro_rules! full { + ($e:expr) => { + $e + }; +} +#[cfg(all(feature = "derive", not(feature = "full")))] +macro_rules! full { + ($e:expr) => { + unreachable!() + }; +} +/// Syntax tree traversal to transform the nodes of an owned syntax tree. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: index.html +/// +/// *This trait is available if Syn is built with the `"fold"` feature.* +pub trait Fold { + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_abi(&mut self, i: Abi) -> Abi { + fold_abi(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_angle_bracketed_generic_arguments( + &mut self, + i: AngleBracketedGenericArguments, + ) -> AngleBracketedGenericArguments { + fold_angle_bracketed_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn fold_arg_captured(&mut self, i: ArgCaptured) -> ArgCaptured { + fold_arg_captured(self, i) + } + #[cfg(feature = "full")] + fn fold_arg_self(&mut self, i: ArgSelf) -> ArgSelf { + fold_arg_self(self, i) + } + #[cfg(feature = "full")] + fn fold_arg_self_ref(&mut self, i: ArgSelfRef) -> ArgSelfRef { + fold_arg_self_ref(self, i) + } + #[cfg(feature = "full")] + fn fold_arm(&mut self, i: Arm) -> Arm { + fold_arm(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_attr_style(&mut self, i: AttrStyle) -> AttrStyle { + fold_attr_style(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_attribute(&mut self, i: Attribute) -> Attribute { + fold_attribute(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bare_fn_arg(&mut self, i: BareFnArg) -> BareFnArg { + fold_bare_fn_arg(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bare_fn_arg_name(&mut self, i: BareFnArgName) -> BareFnArgName { + fold_bare_fn_arg_name(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bin_op(&mut self, i: BinOp) -> BinOp { + fold_bin_op(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_binding(&mut self, i: Binding) -> Binding { + fold_binding(self, i) + } + #[cfg(feature = "full")] + fn fold_block(&mut self, i: Block) -> Block { + fold_block(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_bound_lifetimes(&mut self, i: BoundLifetimes) -> BoundLifetimes { + fold_bound_lifetimes(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_const_param(&mut self, i: ConstParam) -> ConstParam { + fold_const_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_constraint(&mut self, i: Constraint) -> Constraint { + fold_constraint(self, i) + } + #[cfg(feature = "derive")] + fn fold_data(&mut self, i: Data) -> Data { + fold_data(self, i) + } + #[cfg(feature = "derive")] + fn fold_data_enum(&mut self, i: DataEnum) -> DataEnum { + fold_data_enum(self, i) + } + #[cfg(feature = "derive")] + fn fold_data_struct(&mut self, i: DataStruct) -> DataStruct { + fold_data_struct(self, i) + } + #[cfg(feature = "derive")] + fn fold_data_union(&mut self, i: DataUnion) -> DataUnion { + fold_data_union(self, i) + } + #[cfg(feature = "derive")] + fn fold_derive_input(&mut self, i: DeriveInput) -> DeriveInput { + fold_derive_input(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr(&mut self, i: Expr) -> Expr { + fold_expr(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_array(&mut self, i: ExprArray) -> ExprArray { + fold_expr_array(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_assign(&mut self, i: ExprAssign) -> ExprAssign { + fold_expr_assign(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_assign_op(&mut self, i: ExprAssignOp) -> ExprAssignOp { + fold_expr_assign_op(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_async(&mut self, i: ExprAsync) -> ExprAsync { + fold_expr_async(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_binary(&mut self, i: ExprBinary) -> ExprBinary { + fold_expr_binary(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_block(&mut self, i: ExprBlock) -> ExprBlock { + fold_expr_block(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_box(&mut self, i: ExprBox) -> ExprBox { + fold_expr_box(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_break(&mut self, i: ExprBreak) -> ExprBreak { + fold_expr_break(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_call(&mut self, i: ExprCall) -> ExprCall { + fold_expr_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_cast(&mut self, i: ExprCast) -> ExprCast { + fold_expr_cast(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_closure(&mut self, i: ExprClosure) -> ExprClosure { + fold_expr_closure(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_continue(&mut self, i: ExprContinue) -> ExprContinue { + fold_expr_continue(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_field(&mut self, i: ExprField) -> ExprField { + fold_expr_field(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_for_loop(&mut self, i: ExprForLoop) -> ExprForLoop { + fold_expr_for_loop(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_group(&mut self, i: ExprGroup) -> ExprGroup { + fold_expr_group(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_if(&mut self, i: ExprIf) -> ExprIf { + fold_expr_if(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_in_place(&mut self, i: ExprInPlace) -> ExprInPlace { + fold_expr_in_place(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_index(&mut self, i: ExprIndex) -> ExprIndex { + fold_expr_index(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_let(&mut self, i: ExprLet) -> ExprLet { + fold_expr_let(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_lit(&mut self, i: ExprLit) -> ExprLit { + fold_expr_lit(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_loop(&mut self, i: ExprLoop) -> ExprLoop { + fold_expr_loop(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_macro(&mut self, i: ExprMacro) -> ExprMacro { + fold_expr_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_match(&mut self, i: ExprMatch) -> ExprMatch { + fold_expr_match(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_method_call(&mut self, i: ExprMethodCall) -> ExprMethodCall { + fold_expr_method_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_paren(&mut self, i: ExprParen) -> ExprParen { + fold_expr_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_path(&mut self, i: ExprPath) -> ExprPath { + fold_expr_path(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_range(&mut self, i: ExprRange) -> ExprRange { + fold_expr_range(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_reference(&mut self, i: ExprReference) -> ExprReference { + fold_expr_reference(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_repeat(&mut self, i: ExprRepeat) -> ExprRepeat { + fold_expr_repeat(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_return(&mut self, i: ExprReturn) -> ExprReturn { + fold_expr_return(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_struct(&mut self, i: ExprStruct) -> ExprStruct { + fold_expr_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_try(&mut self, i: ExprTry) -> ExprTry { + fold_expr_try(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_try_block(&mut self, i: ExprTryBlock) -> ExprTryBlock { + fold_expr_try_block(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_tuple(&mut self, i: ExprTuple) -> ExprTuple { + fold_expr_tuple(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_type(&mut self, i: ExprType) -> ExprType { + fold_expr_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_unary(&mut self, i: ExprUnary) -> ExprUnary { + fold_expr_unary(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_unsafe(&mut self, i: ExprUnsafe) -> ExprUnsafe { + fold_expr_unsafe(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_expr_verbatim(&mut self, i: ExprVerbatim) -> ExprVerbatim { + fold_expr_verbatim(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_while(&mut self, i: ExprWhile) -> ExprWhile { + fold_expr_while(self, i) + } + #[cfg(feature = "full")] + fn fold_expr_yield(&mut self, i: ExprYield) -> ExprYield { + fold_expr_yield(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_field(&mut self, i: Field) -> Field { + fold_field(self, i) + } + #[cfg(feature = "full")] + fn fold_field_pat(&mut self, i: FieldPat) -> FieldPat { + fold_field_pat(self, i) + } + #[cfg(feature = "full")] + fn fold_field_value(&mut self, i: FieldValue) -> FieldValue { + fold_field_value(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_fields(&mut self, i: Fields) -> Fields { + fold_fields(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_fields_named(&mut self, i: FieldsNamed) -> FieldsNamed { + fold_fields_named(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_fields_unnamed(&mut self, i: FieldsUnnamed) -> FieldsUnnamed { + fold_fields_unnamed(self, i) + } + #[cfg(feature = "full")] + fn fold_file(&mut self, i: File) -> File { + fold_file(self, i) + } + #[cfg(feature = "full")] + fn fold_fn_arg(&mut self, i: FnArg) -> FnArg { + fold_fn_arg(self, i) + } + #[cfg(feature = "full")] + fn fold_fn_decl(&mut self, i: FnDecl) -> FnDecl { + fold_fn_decl(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item(&mut self, i: ForeignItem) -> ForeignItem { + fold_foreign_item(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item_fn(&mut self, i: ForeignItemFn) -> ForeignItemFn { + fold_foreign_item_fn(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item_macro(&mut self, i: ForeignItemMacro) -> ForeignItemMacro { + fold_foreign_item_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item_static(&mut self, i: ForeignItemStatic) -> ForeignItemStatic { + fold_foreign_item_static(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item_type(&mut self, i: ForeignItemType) -> ForeignItemType { + fold_foreign_item_type(self, i) + } + #[cfg(feature = "full")] + fn fold_foreign_item_verbatim(&mut self, i: ForeignItemVerbatim) -> ForeignItemVerbatim { + fold_foreign_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_generic_argument(&mut self, i: GenericArgument) -> GenericArgument { + fold_generic_argument(self, i) + } + #[cfg(feature = "full")] + fn fold_generic_method_argument(&mut self, i: GenericMethodArgument) -> GenericMethodArgument { + fold_generic_method_argument(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_generic_param(&mut self, i: GenericParam) -> GenericParam { + fold_generic_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_generics(&mut self, i: Generics) -> Generics { + fold_generics(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem { + fold_impl_item(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_const(&mut self, i: ImplItemConst) -> ImplItemConst { + fold_impl_item_const(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_existential(&mut self, i: ImplItemExistential) -> ImplItemExistential { + fold_impl_item_existential(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_macro(&mut self, i: ImplItemMacro) -> ImplItemMacro { + fold_impl_item_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_method(&mut self, i: ImplItemMethod) -> ImplItemMethod { + fold_impl_item_method(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_type(&mut self, i: ImplItemType) -> ImplItemType { + fold_impl_item_type(self, i) + } + #[cfg(feature = "full")] + fn fold_impl_item_verbatim(&mut self, i: ImplItemVerbatim) -> ImplItemVerbatim { + fold_impl_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_index(&mut self, i: Index) -> Index { + fold_index(self, i) + } + #[cfg(feature = "full")] + fn fold_item(&mut self, i: Item) -> Item { + fold_item(self, i) + } + #[cfg(feature = "full")] + fn fold_item_const(&mut self, i: ItemConst) -> ItemConst { + fold_item_const(self, i) + } + #[cfg(feature = "full")] + fn fold_item_enum(&mut self, i: ItemEnum) -> ItemEnum { + fold_item_enum(self, i) + } + #[cfg(feature = "full")] + fn fold_item_existential(&mut self, i: ItemExistential) -> ItemExistential { + fold_item_existential(self, i) + } + #[cfg(feature = "full")] + fn fold_item_extern_crate(&mut self, i: ItemExternCrate) -> ItemExternCrate { + fold_item_extern_crate(self, i) + } + #[cfg(feature = "full")] + fn fold_item_fn(&mut self, i: ItemFn) -> ItemFn { + fold_item_fn(self, i) + } + #[cfg(feature = "full")] + fn fold_item_foreign_mod(&mut self, i: ItemForeignMod) -> ItemForeignMod { + fold_item_foreign_mod(self, i) + } + #[cfg(feature = "full")] + fn fold_item_impl(&mut self, i: ItemImpl) -> ItemImpl { + fold_item_impl(self, i) + } + #[cfg(feature = "full")] + fn fold_item_macro(&mut self, i: ItemMacro) -> ItemMacro { + fold_item_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_item_macro2(&mut self, i: ItemMacro2) -> ItemMacro2 { + fold_item_macro2(self, i) + } + #[cfg(feature = "full")] + fn fold_item_mod(&mut self, i: ItemMod) -> ItemMod { + fold_item_mod(self, i) + } + #[cfg(feature = "full")] + fn fold_item_static(&mut self, i: ItemStatic) -> ItemStatic { + fold_item_static(self, i) + } + #[cfg(feature = "full")] + fn fold_item_struct(&mut self, i: ItemStruct) -> ItemStruct { + fold_item_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_item_trait(&mut self, i: ItemTrait) -> ItemTrait { + fold_item_trait(self, i) + } + #[cfg(feature = "full")] + fn fold_item_trait_alias(&mut self, i: ItemTraitAlias) -> ItemTraitAlias { + fold_item_trait_alias(self, i) + } + #[cfg(feature = "full")] + fn fold_item_type(&mut self, i: ItemType) -> ItemType { + fold_item_type(self, i) + } + #[cfg(feature = "full")] + fn fold_item_union(&mut self, i: ItemUnion) -> ItemUnion { + fold_item_union(self, i) + } + #[cfg(feature = "full")] + fn fold_item_use(&mut self, i: ItemUse) -> ItemUse { + fold_item_use(self, i) + } + #[cfg(feature = "full")] + fn fold_item_verbatim(&mut self, i: ItemVerbatim) -> ItemVerbatim { + fold_item_verbatim(self, i) + } + #[cfg(feature = "full")] + fn fold_label(&mut self, i: Label) -> Label { + fold_label(self, i) + } + fn fold_lifetime(&mut self, i: Lifetime) -> Lifetime { + fold_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lifetime_def(&mut self, i: LifetimeDef) -> LifetimeDef { + fold_lifetime_def(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit(&mut self, i: Lit) -> Lit { + fold_lit(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_bool(&mut self, i: LitBool) -> LitBool { + fold_lit_bool(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_byte(&mut self, i: LitByte) -> LitByte { + fold_lit_byte(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_byte_str(&mut self, i: LitByteStr) -> LitByteStr { + fold_lit_byte_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_char(&mut self, i: LitChar) -> LitChar { + fold_lit_char(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_float(&mut self, i: LitFloat) -> LitFloat { + fold_lit_float(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_int(&mut self, i: LitInt) -> LitInt { + fold_lit_int(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_str(&mut self, i: LitStr) -> LitStr { + fold_lit_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_lit_verbatim(&mut self, i: LitVerbatim) -> LitVerbatim { + fold_lit_verbatim(self, i) + } + #[cfg(feature = "full")] + fn fold_local(&mut self, i: Local) -> Local { + fold_local(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_macro(&mut self, i: Macro) -> Macro { + fold_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_macro_delimiter(&mut self, i: MacroDelimiter) -> MacroDelimiter { + fold_macro_delimiter(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_member(&mut self, i: Member) -> Member { + fold_member(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta(&mut self, i: Meta) -> Meta { + fold_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta_list(&mut self, i: MetaList) -> MetaList { + fold_meta_list(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_meta_name_value(&mut self, i: MetaNameValue) -> MetaNameValue { + fold_meta_name_value(self, i) + } + #[cfg(feature = "full")] + fn fold_method_sig(&mut self, i: MethodSig) -> MethodSig { + fold_method_sig(self, i) + } + #[cfg(feature = "full")] + fn fold_method_turbofish(&mut self, i: MethodTurbofish) -> MethodTurbofish { + fold_method_turbofish(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_nested_meta(&mut self, i: NestedMeta) -> NestedMeta { + fold_nested_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_parenthesized_generic_arguments( + &mut self, + i: ParenthesizedGenericArguments, + ) -> ParenthesizedGenericArguments { + fold_parenthesized_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn fold_pat(&mut self, i: Pat) -> Pat { + fold_pat(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_box(&mut self, i: PatBox) -> PatBox { + fold_pat_box(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_ident(&mut self, i: PatIdent) -> PatIdent { + fold_pat_ident(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_lit(&mut self, i: PatLit) -> PatLit { + fold_pat_lit(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_macro(&mut self, i: PatMacro) -> PatMacro { + fold_pat_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_path(&mut self, i: PatPath) -> PatPath { + fold_pat_path(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_range(&mut self, i: PatRange) -> PatRange { + fold_pat_range(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_ref(&mut self, i: PatRef) -> PatRef { + fold_pat_ref(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_slice(&mut self, i: PatSlice) -> PatSlice { + fold_pat_slice(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_struct(&mut self, i: PatStruct) -> PatStruct { + fold_pat_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_tuple(&mut self, i: PatTuple) -> PatTuple { + fold_pat_tuple(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_tuple_struct(&mut self, i: PatTupleStruct) -> PatTupleStruct { + fold_pat_tuple_struct(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_verbatim(&mut self, i: PatVerbatim) -> PatVerbatim { + fold_pat_verbatim(self, i) + } + #[cfg(feature = "full")] + fn fold_pat_wild(&mut self, i: PatWild) -> PatWild { + fold_pat_wild(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path(&mut self, i: Path) -> Path { + fold_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path_arguments(&mut self, i: PathArguments) -> PathArguments { + fold_path_arguments(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_path_segment(&mut self, i: PathSegment) -> PathSegment { + fold_path_segment(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_eq(&mut self, i: PredicateEq) -> PredicateEq { + fold_predicate_eq(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_lifetime(&mut self, i: PredicateLifetime) -> PredicateLifetime { + fold_predicate_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_predicate_type(&mut self, i: PredicateType) -> PredicateType { + fold_predicate_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_qself(&mut self, i: QSelf) -> QSelf { + fold_qself(self, i) + } + #[cfg(feature = "full")] + fn fold_range_limits(&mut self, i: RangeLimits) -> RangeLimits { + fold_range_limits(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_return_type(&mut self, i: ReturnType) -> ReturnType { + fold_return_type(self, i) + } + #[cfg(feature = "full")] + fn fold_stmt(&mut self, i: Stmt) -> Stmt { + fold_stmt(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_trait_bound(&mut self, i: TraitBound) -> TraitBound { + fold_trait_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_trait_bound_modifier(&mut self, i: TraitBoundModifier) -> TraitBoundModifier { + fold_trait_bound_modifier(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem { + fold_trait_item(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item_const(&mut self, i: TraitItemConst) -> TraitItemConst { + fold_trait_item_const(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item_macro(&mut self, i: TraitItemMacro) -> TraitItemMacro { + fold_trait_item_macro(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item_method(&mut self, i: TraitItemMethod) -> TraitItemMethod { + fold_trait_item_method(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item_type(&mut self, i: TraitItemType) -> TraitItemType { + fold_trait_item_type(self, i) + } + #[cfg(feature = "full")] + fn fold_trait_item_verbatim(&mut self, i: TraitItemVerbatim) -> TraitItemVerbatim { + fold_trait_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type(&mut self, i: Type) -> Type { + fold_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_array(&mut self, i: TypeArray) -> TypeArray { + fold_type_array(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_bare_fn(&mut self, i: TypeBareFn) -> TypeBareFn { + fold_type_bare_fn(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_group(&mut self, i: TypeGroup) -> TypeGroup { + fold_type_group(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_impl_trait(&mut self, i: TypeImplTrait) -> TypeImplTrait { + fold_type_impl_trait(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_infer(&mut self, i: TypeInfer) -> TypeInfer { + fold_type_infer(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_macro(&mut self, i: TypeMacro) -> TypeMacro { + fold_type_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_never(&mut self, i: TypeNever) -> TypeNever { + fold_type_never(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_param(&mut self, i: TypeParam) -> TypeParam { + fold_type_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_param_bound(&mut self, i: TypeParamBound) -> TypeParamBound { + fold_type_param_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_paren(&mut self, i: TypeParen) -> TypeParen { + fold_type_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_path(&mut self, i: TypePath) -> TypePath { + fold_type_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_ptr(&mut self, i: TypePtr) -> TypePtr { + fold_type_ptr(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_reference(&mut self, i: TypeReference) -> TypeReference { + fold_type_reference(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_slice(&mut self, i: TypeSlice) -> TypeSlice { + fold_type_slice(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_trait_object(&mut self, i: TypeTraitObject) -> TypeTraitObject { + fold_type_trait_object(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_tuple(&mut self, i: TypeTuple) -> TypeTuple { + fold_type_tuple(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_type_verbatim(&mut self, i: TypeVerbatim) -> TypeVerbatim { + fold_type_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_un_op(&mut self, i: UnOp) -> UnOp { + fold_un_op(self, i) + } + #[cfg(feature = "full")] + fn fold_use_glob(&mut self, i: UseGlob) -> UseGlob { + fold_use_glob(self, i) + } + #[cfg(feature = "full")] + fn fold_use_group(&mut self, i: UseGroup) -> UseGroup { + fold_use_group(self, i) + } + #[cfg(feature = "full")] + fn fold_use_name(&mut self, i: UseName) -> UseName { + fold_use_name(self, i) + } + #[cfg(feature = "full")] + fn fold_use_path(&mut self, i: UsePath) -> UsePath { + fold_use_path(self, i) + } + #[cfg(feature = "full")] + fn fold_use_rename(&mut self, i: UseRename) -> UseRename { + fold_use_rename(self, i) + } + #[cfg(feature = "full")] + fn fold_use_tree(&mut self, i: UseTree) -> UseTree { + fold_use_tree(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_variant(&mut self, i: Variant) -> Variant { + fold_variant(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_crate(&mut self, i: VisCrate) -> VisCrate { + fold_vis_crate(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_public(&mut self, i: VisPublic) -> VisPublic { + fold_vis_public(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_vis_restricted(&mut self, i: VisRestricted) -> VisRestricted { + fold_vis_restricted(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_visibility(&mut self, i: Visibility) -> Visibility { + fold_visibility(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_where_clause(&mut self, i: WhereClause) -> WhereClause { + fold_where_clause(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn fold_where_predicate(&mut self, i: WherePredicate) -> WherePredicate { + fold_where_predicate(self, i) + } + fn fold_span(&mut self, i: Span) -> Span { + fold_span(self, i) + } + fn fold_ident(&mut self, i: Ident) -> Ident { + fold_ident(self, i) + } +} +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! fold_span_only { + ($f:ident : $t:ident) => { + pub fn $f<V: Fold + ?Sized>(_visitor: &mut V, mut _i: $t) -> $t { + let span = _visitor.fold_span(_i.span()); + _i.set_span(span); + _i + } + }; +} +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_byte: LitByte); +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_byte_str: LitByteStr); +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_char: LitChar); +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_float: LitFloat); +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_int: LitInt); +#[cfg(any(feature = "full", feature = "derive"))] +fold_span_only!(fold_lit_str: LitStr); +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_abi<V: Fold + ?Sized>(_visitor: &mut V, _i: Abi) -> Abi { + Abi { + extern_token: Token![extern](tokens_helper(_visitor, &_i.extern_token.span)), + name: (_i.name).map(|it| _visitor.fold_lit_str(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_angle_bracketed_generic_arguments<V: Fold + ?Sized>( + _visitor: &mut V, + _i: AngleBracketedGenericArguments, +) -> AngleBracketedGenericArguments { + AngleBracketedGenericArguments { + colon2_token: (_i.colon2_token) + .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))), + lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)), + args: FoldHelper::lift(_i.args, |it| _visitor.fold_generic_argument(it)), + gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_arg_captured<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgCaptured) -> ArgCaptured { + ArgCaptured { + pat: _visitor.fold_pat(_i.pat), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: _visitor.fold_type(_i.ty), + } +} +#[cfg(feature = "full")] +pub fn fold_arg_self<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgSelf) -> ArgSelf { + ArgSelf { + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + self_token: Token![self](tokens_helper(_visitor, &_i.self_token.span)), + } +} +#[cfg(feature = "full")] +pub fn fold_arg_self_ref<V: Fold + ?Sized>(_visitor: &mut V, _i: ArgSelfRef) -> ArgSelfRef { + ArgSelfRef { + and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)), + lifetime: (_i.lifetime).map(|it| _visitor.fold_lifetime(it)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + self_token: Token![self](tokens_helper(_visitor, &_i.self_token.span)), + } +} +#[cfg(feature = "full")] +pub fn fold_arm<V: Fold + ?Sized>(_visitor: &mut V, _i: Arm) -> Arm { + Arm { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + leading_vert: (_i.leading_vert).map(|it| Token ! [ | ](tokens_helper(_visitor, &it.spans))), + pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)), + guard: (_i.guard).map(|it| { + ( + Token![if](tokens_helper(_visitor, &(it).0.span)), + Box::new(_visitor.fold_expr(*(it).1)), + ) + }), + fat_arrow_token: Token ! [ => ](tokens_helper(_visitor, &_i.fat_arrow_token.spans)), + body: Box::new(_visitor.fold_expr(*_i.body)), + comma: (_i.comma).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_attr_style<V: Fold + ?Sized>(_visitor: &mut V, _i: AttrStyle) -> AttrStyle { + match _i { + AttrStyle::Outer => AttrStyle::Outer, + AttrStyle::Inner(_binding_0) => { + AttrStyle::Inner(Token![!](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_attribute<V: Fold + ?Sized>(_visitor: &mut V, _i: Attribute) -> Attribute { + Attribute { + pound_token: Token ! [ # ](tokens_helper(_visitor, &_i.pound_token.spans)), + style: _visitor.fold_attr_style(_i.style), + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + path: _visitor.fold_path(_i.path), + tts: _i.tts, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bare_fn_arg<V: Fold + ?Sized>(_visitor: &mut V, _i: BareFnArg) -> BareFnArg { + BareFnArg { + name: (_i.name).map(|it| { + ( + _visitor.fold_bare_fn_arg_name((it).0), + Token ! [ : ](tokens_helper(_visitor, &(it).1.spans)), + ) + }), + ty: _visitor.fold_type(_i.ty), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bare_fn_arg_name<V: Fold + ?Sized>( + _visitor: &mut V, + _i: BareFnArgName, +) -> BareFnArgName { + match _i { + BareFnArgName::Named(_binding_0) => BareFnArgName::Named(_visitor.fold_ident(_binding_0)), + BareFnArgName::Wild(_binding_0) => { + BareFnArgName::Wild(Token![_](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bin_op<V: Fold + ?Sized>(_visitor: &mut V, _i: BinOp) -> BinOp { + match _i { + BinOp::Add(_binding_0) => { + BinOp::Add(Token ! [ + ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Sub(_binding_0) => { + BinOp::Sub(Token ! [ - ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Mul(_binding_0) => { + BinOp::Mul(Token ! [ * ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Div(_binding_0) => { + BinOp::Div(Token ! [ / ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Rem(_binding_0) => { + BinOp::Rem(Token ! [ % ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::And(_binding_0) => { + BinOp::And(Token ! [ && ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Or(_binding_0) => { + BinOp::Or(Token ! [ || ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitXor(_binding_0) => { + BinOp::BitXor(Token ! [ ^ ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitAnd(_binding_0) => { + BinOp::BitAnd(Token ! [ & ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitOr(_binding_0) => { + BinOp::BitOr(Token ! [ | ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Shl(_binding_0) => { + BinOp::Shl(Token ! [ << ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Shr(_binding_0) => { + BinOp::Shr(Token ! [ >> ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Eq(_binding_0) => { + BinOp::Eq(Token ! [ == ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Lt(_binding_0) => { + BinOp::Lt(Token ! [ < ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Le(_binding_0) => { + BinOp::Le(Token ! [ <= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Ne(_binding_0) => { + BinOp::Ne(Token ! [ != ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Ge(_binding_0) => { + BinOp::Ge(Token ! [ >= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::Gt(_binding_0) => { + BinOp::Gt(Token ! [ > ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::AddEq(_binding_0) => { + BinOp::AddEq(Token ! [ += ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::SubEq(_binding_0) => { + BinOp::SubEq(Token ! [ -= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::MulEq(_binding_0) => { + BinOp::MulEq(Token ! [ *= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::DivEq(_binding_0) => { + BinOp::DivEq(Token ! [ /= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::RemEq(_binding_0) => { + BinOp::RemEq(Token ! [ %= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitXorEq(_binding_0) => { + BinOp::BitXorEq(Token ! [ ^= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitAndEq(_binding_0) => { + BinOp::BitAndEq(Token ! [ &= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::BitOrEq(_binding_0) => { + BinOp::BitOrEq(Token ! [ |= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::ShlEq(_binding_0) => { + BinOp::ShlEq(Token ! [ <<= ](tokens_helper(_visitor, &_binding_0.spans))) + } + BinOp::ShrEq(_binding_0) => { + BinOp::ShrEq(Token ! [ >>= ](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_binding<V: Fold + ?Sized>(_visitor: &mut V, _i: Binding) -> Binding { + Binding { + ident: _visitor.fold_ident(_i.ident), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + ty: _visitor.fold_type(_i.ty), + } +} +#[cfg(feature = "full")] +pub fn fold_block<V: Fold + ?Sized>(_visitor: &mut V, _i: Block) -> Block { + Block { + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + stmts: FoldHelper::lift(_i.stmts, |it| _visitor.fold_stmt(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_bound_lifetimes<V: Fold + ?Sized>( + _visitor: &mut V, + _i: BoundLifetimes, +) -> BoundLifetimes { + BoundLifetimes { + for_token: Token![for](tokens_helper(_visitor, &_i.for_token.span)), + lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)), + lifetimes: FoldHelper::lift(_i.lifetimes, |it| _visitor.fold_lifetime_def(it)), + gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_const_param<V: Fold + ?Sized>(_visitor: &mut V, _i: ConstParam) -> ConstParam { + ConstParam { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + const_token: Token![const](tokens_helper(_visitor, &_i.const_token.span)), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: _visitor.fold_type(_i.ty), + eq_token: (_i.eq_token).map(|it| Token ! [ = ](tokens_helper(_visitor, &it.spans))), + default: (_i.default).map(|it| _visitor.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_constraint<V: Fold + ?Sized>(_visitor: &mut V, _i: Constraint) -> Constraint { + Constraint { + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data<V: Fold + ?Sized>(_visitor: &mut V, _i: Data) -> Data { + match _i { + Data::Struct(_binding_0) => Data::Struct(_visitor.fold_data_struct(_binding_0)), + Data::Enum(_binding_0) => Data::Enum(_visitor.fold_data_enum(_binding_0)), + Data::Union(_binding_0) => Data::Union(_visitor.fold_data_union(_binding_0)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_enum<V: Fold + ?Sized>(_visitor: &mut V, _i: DataEnum) -> DataEnum { + DataEnum { + enum_token: Token![enum](tokens_helper(_visitor, &_i.enum_token.span)), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + variants: FoldHelper::lift(_i.variants, |it| _visitor.fold_variant(it)), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: DataStruct) -> DataStruct { + DataStruct { + struct_token: Token![struct](tokens_helper(_visitor, &_i.struct_token.span)), + fields: _visitor.fold_fields(_i.fields), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "derive")] +pub fn fold_data_union<V: Fold + ?Sized>(_visitor: &mut V, _i: DataUnion) -> DataUnion { + DataUnion { + union_token: Token![union](tokens_helper(_visitor, &_i.union_token.span)), + fields: _visitor.fold_fields_named(_i.fields), + } +} +#[cfg(feature = "derive")] +pub fn fold_derive_input<V: Fold + ?Sized>(_visitor: &mut V, _i: DeriveInput) -> DeriveInput { + DeriveInput { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + data: _visitor.fold_data(_i.data), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr<V: Fold + ?Sized>(_visitor: &mut V, _i: Expr) -> Expr { + match _i { + Expr::Box(_binding_0) => Expr::Box(full!(_visitor.fold_expr_box(_binding_0))), + Expr::InPlace(_binding_0) => Expr::InPlace(full!(_visitor.fold_expr_in_place(_binding_0))), + Expr::Array(_binding_0) => Expr::Array(full!(_visitor.fold_expr_array(_binding_0))), + Expr::Call(_binding_0) => Expr::Call(_visitor.fold_expr_call(_binding_0)), + Expr::MethodCall(_binding_0) => { + Expr::MethodCall(full!(_visitor.fold_expr_method_call(_binding_0))) + } + Expr::Tuple(_binding_0) => Expr::Tuple(full!(_visitor.fold_expr_tuple(_binding_0))), + Expr::Binary(_binding_0) => Expr::Binary(_visitor.fold_expr_binary(_binding_0)), + Expr::Unary(_binding_0) => Expr::Unary(_visitor.fold_expr_unary(_binding_0)), + Expr::Lit(_binding_0) => Expr::Lit(_visitor.fold_expr_lit(_binding_0)), + Expr::Cast(_binding_0) => Expr::Cast(_visitor.fold_expr_cast(_binding_0)), + Expr::Type(_binding_0) => Expr::Type(full!(_visitor.fold_expr_type(_binding_0))), + Expr::Let(_binding_0) => Expr::Let(full!(_visitor.fold_expr_let(_binding_0))), + Expr::If(_binding_0) => Expr::If(full!(_visitor.fold_expr_if(_binding_0))), + Expr::While(_binding_0) => Expr::While(full!(_visitor.fold_expr_while(_binding_0))), + Expr::ForLoop(_binding_0) => Expr::ForLoop(full!(_visitor.fold_expr_for_loop(_binding_0))), + Expr::Loop(_binding_0) => Expr::Loop(full!(_visitor.fold_expr_loop(_binding_0))), + Expr::Match(_binding_0) => Expr::Match(full!(_visitor.fold_expr_match(_binding_0))), + Expr::Closure(_binding_0) => Expr::Closure(full!(_visitor.fold_expr_closure(_binding_0))), + Expr::Unsafe(_binding_0) => Expr::Unsafe(full!(_visitor.fold_expr_unsafe(_binding_0))), + Expr::Block(_binding_0) => Expr::Block(full!(_visitor.fold_expr_block(_binding_0))), + Expr::Assign(_binding_0) => Expr::Assign(full!(_visitor.fold_expr_assign(_binding_0))), + Expr::AssignOp(_binding_0) => { + Expr::AssignOp(full!(_visitor.fold_expr_assign_op(_binding_0))) + } + Expr::Field(_binding_0) => Expr::Field(_visitor.fold_expr_field(_binding_0)), + Expr::Index(_binding_0) => Expr::Index(_visitor.fold_expr_index(_binding_0)), + Expr::Range(_binding_0) => Expr::Range(full!(_visitor.fold_expr_range(_binding_0))), + Expr::Path(_binding_0) => Expr::Path(_visitor.fold_expr_path(_binding_0)), + Expr::Reference(_binding_0) => { + Expr::Reference(full!(_visitor.fold_expr_reference(_binding_0))) + } + Expr::Break(_binding_0) => Expr::Break(full!(_visitor.fold_expr_break(_binding_0))), + Expr::Continue(_binding_0) => { + Expr::Continue(full!(_visitor.fold_expr_continue(_binding_0))) + } + Expr::Return(_binding_0) => Expr::Return(full!(_visitor.fold_expr_return(_binding_0))), + Expr::Macro(_binding_0) => Expr::Macro(full!(_visitor.fold_expr_macro(_binding_0))), + Expr::Struct(_binding_0) => Expr::Struct(full!(_visitor.fold_expr_struct(_binding_0))), + Expr::Repeat(_binding_0) => Expr::Repeat(full!(_visitor.fold_expr_repeat(_binding_0))), + Expr::Paren(_binding_0) => Expr::Paren(_visitor.fold_expr_paren(_binding_0)), + Expr::Group(_binding_0) => Expr::Group(full!(_visitor.fold_expr_group(_binding_0))), + Expr::Try(_binding_0) => Expr::Try(full!(_visitor.fold_expr_try(_binding_0))), + Expr::Async(_binding_0) => Expr::Async(full!(_visitor.fold_expr_async(_binding_0))), + Expr::TryBlock(_binding_0) => { + Expr::TryBlock(full!(_visitor.fold_expr_try_block(_binding_0))) + } + Expr::Yield(_binding_0) => Expr::Yield(full!(_visitor.fold_expr_yield(_binding_0))), + Expr::Verbatim(_binding_0) => Expr::Verbatim(_visitor.fold_expr_verbatim(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_array<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprArray) -> ExprArray { + ExprArray { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_expr(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_assign<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAssign) -> ExprAssign { + ExprAssign { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + left: Box::new(_visitor.fold_expr(*_i.left)), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + right: Box::new(_visitor.fold_expr(*_i.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_assign_op<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAssignOp) -> ExprAssignOp { + ExprAssignOp { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + left: Box::new(_visitor.fold_expr(*_i.left)), + op: _visitor.fold_bin_op(_i.op), + right: Box::new(_visitor.fold_expr(*_i.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_async<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprAsync) -> ExprAsync { + ExprAsync { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + async_token: Token![async](tokens_helper(_visitor, &_i.async_token.span)), + capture: (_i.capture).map(|it| Token![move](tokens_helper(_visitor, &it.span))), + block: _visitor.fold_block(_i.block), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_binary<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBinary) -> ExprBinary { + ExprBinary { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + left: Box::new(_visitor.fold_expr(*_i.left)), + op: _visitor.fold_bin_op(_i.op), + right: Box::new(_visitor.fold_expr(*_i.right)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_block<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBlock) -> ExprBlock { + ExprBlock { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + label: (_i.label).map(|it| _visitor.fold_label(it)), + block: _visitor.fold_block(_i.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_box<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBox) -> ExprBox { + ExprBox { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + box_token: Token![box](tokens_helper(_visitor, &_i.box_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_break<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprBreak) -> ExprBreak { + ExprBreak { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + break_token: Token![break](tokens_helper(_visitor, &_i.break_token.span)), + label: (_i.label).map(|it| _visitor.fold_lifetime(it)), + expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_call<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprCall) -> ExprCall { + ExprCall { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + func: Box::new(_visitor.fold_expr(*_i.func)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + args: FoldHelper::lift(_i.args, |it| _visitor.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_cast<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprCast) -> ExprCast { + ExprCast { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + as_token: Token![as](tokens_helper(_visitor, &_i.as_token.span)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_closure<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprClosure) -> ExprClosure { + ExprClosure { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + asyncness: (_i.asyncness).map(|it| Token![async](tokens_helper(_visitor, &it.span))), + movability: (_i.movability).map(|it| Token![static](tokens_helper(_visitor, &it.span))), + capture: (_i.capture).map(|it| Token![move](tokens_helper(_visitor, &it.span))), + or1_token: Token ! [ | ](tokens_helper(_visitor, &_i.or1_token.spans)), + inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_fn_arg(it)), + or2_token: Token ! [ | ](tokens_helper(_visitor, &_i.or2_token.spans)), + output: _visitor.fold_return_type(_i.output), + body: Box::new(_visitor.fold_expr(*_i.body)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_continue<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprContinue) -> ExprContinue { + ExprContinue { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + continue_token: Token![continue](tokens_helper(_visitor, &_i.continue_token.span)), + label: (_i.label).map(|it| _visitor.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_field<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprField) -> ExprField { + ExprField { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + base: Box::new(_visitor.fold_expr(*_i.base)), + dot_token: Token ! [ . ](tokens_helper(_visitor, &_i.dot_token.spans)), + member: _visitor.fold_member(_i.member), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_for_loop<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprForLoop) -> ExprForLoop { + ExprForLoop { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + label: (_i.label).map(|it| _visitor.fold_label(it)), + for_token: Token![for](tokens_helper(_visitor, &_i.for_token.span)), + pat: Box::new(_visitor.fold_pat(*_i.pat)), + in_token: Token![in](tokens_helper(_visitor, &_i.in_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + body: _visitor.fold_block(_i.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_group<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprGroup) -> ExprGroup { + ExprGroup { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + group_token: Group(tokens_helper(_visitor, &_i.group_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_if<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIf) -> ExprIf { + ExprIf { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + if_token: Token![if](tokens_helper(_visitor, &_i.if_token.span)), + cond: Box::new(_visitor.fold_expr(*_i.cond)), + then_branch: _visitor.fold_block(_i.then_branch), + else_branch: (_i.else_branch).map(|it| { + ( + Token![else](tokens_helper(_visitor, &(it).0.span)), + Box::new(_visitor.fold_expr(*(it).1)), + ) + }), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_in_place<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprInPlace) -> ExprInPlace { + ExprInPlace { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + place: Box::new(_visitor.fold_expr(*_i.place)), + arrow_token: Token ! [ <- ](tokens_helper(_visitor, &_i.arrow_token.spans)), + value: Box::new(_visitor.fold_expr(*_i.value)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_index<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprIndex) -> ExprIndex { + ExprIndex { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + index: Box::new(_visitor.fold_expr(*_i.index)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_let<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLet) -> ExprLet { + ExprLet { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + let_token: Token![let](tokens_helper(_visitor, &_i.let_token.span)), + pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLit) -> ExprLit { + ExprLit { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + lit: _visitor.fold_lit(_i.lit), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_loop<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprLoop) -> ExprLoop { + ExprLoop { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + label: (_i.label).map(|it| _visitor.fold_label(it)), + loop_token: Token![loop](tokens_helper(_visitor, &_i.loop_token.span)), + body: _visitor.fold_block(_i.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprMacro) -> ExprMacro { + ExprMacro { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + mac: _visitor.fold_macro(_i.mac), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_match<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprMatch) -> ExprMatch { + ExprMatch { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + match_token: Token![match](tokens_helper(_visitor, &_i.match_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + arms: FoldHelper::lift(_i.arms, |it| _visitor.fold_arm(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_method_call<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ExprMethodCall, +) -> ExprMethodCall { + ExprMethodCall { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + receiver: Box::new(_visitor.fold_expr(*_i.receiver)), + dot_token: Token ! [ . ](tokens_helper(_visitor, &_i.dot_token.spans)), + method: _visitor.fold_ident(_i.method), + turbofish: (_i.turbofish).map(|it| _visitor.fold_method_turbofish(it)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + args: FoldHelper::lift(_i.args, |it| _visitor.fold_expr(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_paren<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprParen) -> ExprParen { + ExprParen { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_path<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprPath) -> ExprPath { + ExprPath { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + qself: (_i.qself).map(|it| _visitor.fold_qself(it)), + path: _visitor.fold_path(_i.path), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_range<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprRange) -> ExprRange { + ExprRange { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + from: (_i.from).map(|it| Box::new(_visitor.fold_expr(*it))), + limits: _visitor.fold_range_limits(_i.limits), + to: (_i.to).map(|it| Box::new(_visitor.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_reference<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprReference) -> ExprReference { + ExprReference { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_repeat<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprRepeat) -> ExprRepeat { + ExprRepeat { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + len: Box::new(_visitor.fold_expr(*_i.len)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_return<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprReturn) -> ExprReturn { + ExprReturn { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + return_token: Token![return](tokens_helper(_visitor, &_i.return_token.span)), + expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprStruct) -> ExprStruct { + ExprStruct { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + path: _visitor.fold_path(_i.path), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + fields: FoldHelper::lift(_i.fields, |it| _visitor.fold_field_value(it)), + dot2_token: (_i.dot2_token).map(|it| Token![..](tokens_helper(_visitor, &it.spans))), + rest: (_i.rest).map(|it| Box::new(_visitor.fold_expr(*it))), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_try<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTry) -> ExprTry { + ExprTry { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + question_token: Token ! [ ? ](tokens_helper(_visitor, &_i.question_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_try_block<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTryBlock) -> ExprTryBlock { + ExprTryBlock { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + try_token: Token![try](tokens_helper(_visitor, &_i.try_token.span)), + block: _visitor.fold_block(_i.block), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprTuple) -> ExprTuple { + ExprTuple { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_expr(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprType) -> ExprType { + ExprType { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_unary<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprUnary) -> ExprUnary { + ExprUnary { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + op: _visitor.fold_un_op(_i.op), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_unsafe<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprUnsafe) -> ExprUnsafe { + ExprUnsafe { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + unsafe_token: Token![unsafe](tokens_helper(_visitor, &_i.unsafe_token.span)), + block: _visitor.fold_block(_i.block), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_expr_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprVerbatim) -> ExprVerbatim { + ExprVerbatim { tts: _i.tts } +} +#[cfg(feature = "full")] +pub fn fold_expr_while<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprWhile) -> ExprWhile { + ExprWhile { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + label: (_i.label).map(|it| _visitor.fold_label(it)), + while_token: Token![while](tokens_helper(_visitor, &_i.while_token.span)), + cond: Box::new(_visitor.fold_expr(*_i.cond)), + body: _visitor.fold_block(_i.body), + } +} +#[cfg(feature = "full")] +pub fn fold_expr_yield<V: Fold + ?Sized>(_visitor: &mut V, _i: ExprYield) -> ExprYield { + ExprYield { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + yield_token: Token![yield](tokens_helper(_visitor, &_i.yield_token.span)), + expr: (_i.expr).map(|it| Box::new(_visitor.fold_expr(*it))), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_field<V: Fold + ?Sized>(_visitor: &mut V, _i: Field) -> Field { + Field { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + ident: (_i.ident).map(|it| _visitor.fold_ident(it)), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + ty: _visitor.fold_type(_i.ty), + } +} +#[cfg(feature = "full")] +pub fn fold_field_pat<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldPat) -> FieldPat { + FieldPat { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + member: _visitor.fold_member(_i.member), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + pat: Box::new(_visitor.fold_pat(*_i.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_field_value<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldValue) -> FieldValue { + FieldValue { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + member: _visitor.fold_member(_i.member), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + expr: _visitor.fold_expr(_i.expr), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields<V: Fold + ?Sized>(_visitor: &mut V, _i: Fields) -> Fields { + match _i { + Fields::Named(_binding_0) => Fields::Named(_visitor.fold_fields_named(_binding_0)), + Fields::Unnamed(_binding_0) => Fields::Unnamed(_visitor.fold_fields_unnamed(_binding_0)), + Fields::Unit => Fields::Unit, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields_named<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldsNamed) -> FieldsNamed { + FieldsNamed { + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + named: FoldHelper::lift(_i.named, |it| _visitor.fold_field(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_fields_unnamed<V: Fold + ?Sized>(_visitor: &mut V, _i: FieldsUnnamed) -> FieldsUnnamed { + FieldsUnnamed { + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + unnamed: FoldHelper::lift(_i.unnamed, |it| _visitor.fold_field(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_file<V: Fold + ?Sized>(_visitor: &mut V, _i: File) -> File { + File { + shebang: _i.shebang, + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + items: FoldHelper::lift(_i.items, |it| _visitor.fold_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_fn_arg<V: Fold + ?Sized>(_visitor: &mut V, _i: FnArg) -> FnArg { + match _i { + FnArg::SelfRef(_binding_0) => FnArg::SelfRef(_visitor.fold_arg_self_ref(_binding_0)), + FnArg::SelfValue(_binding_0) => FnArg::SelfValue(_visitor.fold_arg_self(_binding_0)), + FnArg::Captured(_binding_0) => FnArg::Captured(_visitor.fold_arg_captured(_binding_0)), + FnArg::Inferred(_binding_0) => FnArg::Inferred(_visitor.fold_pat(_binding_0)), + FnArg::Ignored(_binding_0) => FnArg::Ignored(_visitor.fold_type(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_fn_decl<V: Fold + ?Sized>(_visitor: &mut V, _i: FnDecl) -> FnDecl { + FnDecl { + fn_token: Token![fn](tokens_helper(_visitor, &_i.fn_token.span)), + generics: _visitor.fold_generics(_i.generics), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_fn_arg(it)), + variadic: (_i.variadic).map(|it| Token ! [ ... ](tokens_helper(_visitor, &it.spans))), + output: _visitor.fold_return_type(_i.output), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item<V: Fold + ?Sized>(_visitor: &mut V, _i: ForeignItem) -> ForeignItem { + match _i { + ForeignItem::Fn(_binding_0) => ForeignItem::Fn(_visitor.fold_foreign_item_fn(_binding_0)), + ForeignItem::Static(_binding_0) => { + ForeignItem::Static(_visitor.fold_foreign_item_static(_binding_0)) + } + ForeignItem::Type(_binding_0) => { + ForeignItem::Type(_visitor.fold_foreign_item_type(_binding_0)) + } + ForeignItem::Macro(_binding_0) => { + ForeignItem::Macro(_visitor.fold_foreign_item_macro(_binding_0)) + } + ForeignItem::Verbatim(_binding_0) => { + ForeignItem::Verbatim(_visitor.fold_foreign_item_verbatim(_binding_0)) + } + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_fn<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ForeignItemFn, +) -> ForeignItemFn { + ForeignItemFn { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + ident: _visitor.fold_ident(_i.ident), + decl: Box::new(_visitor.fold_fn_decl(*_i.decl)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_macro<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ForeignItemMacro, +) -> ForeignItemMacro { + ForeignItemMacro { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + mac: _visitor.fold_macro(_i.mac), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_static<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ForeignItemStatic, +) -> ForeignItemStatic { + ForeignItemStatic { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + static_token: Token![static](tokens_helper(_visitor, &_i.static_token.span)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_type<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ForeignItemType, +) -> ForeignItemType { + ForeignItemType { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_foreign_item_verbatim<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ForeignItemVerbatim, +) -> ForeignItemVerbatim { + ForeignItemVerbatim { tts: _i.tts } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generic_argument<V: Fold + ?Sized>( + _visitor: &mut V, + _i: GenericArgument, +) -> GenericArgument { + match _i { + GenericArgument::Lifetime(_binding_0) => { + GenericArgument::Lifetime(_visitor.fold_lifetime(_binding_0)) + } + GenericArgument::Type(_binding_0) => GenericArgument::Type(_visitor.fold_type(_binding_0)), + GenericArgument::Binding(_binding_0) => { + GenericArgument::Binding(_visitor.fold_binding(_binding_0)) + } + GenericArgument::Constraint(_binding_0) => { + GenericArgument::Constraint(_visitor.fold_constraint(_binding_0)) + } + GenericArgument::Const(_binding_0) => { + GenericArgument::Const(_visitor.fold_expr(_binding_0)) + } + } +} +#[cfg(feature = "full")] +pub fn fold_generic_method_argument<V: Fold + ?Sized>( + _visitor: &mut V, + _i: GenericMethodArgument, +) -> GenericMethodArgument { + match _i { + GenericMethodArgument::Type(_binding_0) => { + GenericMethodArgument::Type(_visitor.fold_type(_binding_0)) + } + GenericMethodArgument::Const(_binding_0) => { + GenericMethodArgument::Const(_visitor.fold_expr(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generic_param<V: Fold + ?Sized>(_visitor: &mut V, _i: GenericParam) -> GenericParam { + match _i { + GenericParam::Type(_binding_0) => GenericParam::Type(_visitor.fold_type_param(_binding_0)), + GenericParam::Lifetime(_binding_0) => { + GenericParam::Lifetime(_visitor.fold_lifetime_def(_binding_0)) + } + GenericParam::Const(_binding_0) => { + GenericParam::Const(_visitor.fold_const_param(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_generics<V: Fold + ?Sized>(_visitor: &mut V, _i: Generics) -> Generics { + Generics { + lt_token: (_i.lt_token).map(|it| Token ! [ < ](tokens_helper(_visitor, &it.spans))), + params: FoldHelper::lift(_i.params, |it| _visitor.fold_generic_param(it)), + gt_token: (_i.gt_token).map(|it| Token ! [ > ](tokens_helper(_visitor, &it.spans))), + where_clause: (_i.where_clause).map(|it| _visitor.fold_where_clause(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item<V: Fold + ?Sized>(_visitor: &mut V, _i: ImplItem) -> ImplItem { + match _i { + ImplItem::Const(_binding_0) => ImplItem::Const(_visitor.fold_impl_item_const(_binding_0)), + ImplItem::Method(_binding_0) => { + ImplItem::Method(_visitor.fold_impl_item_method(_binding_0)) + } + ImplItem::Type(_binding_0) => ImplItem::Type(_visitor.fold_impl_item_type(_binding_0)), + ImplItem::Existential(_binding_0) => { + ImplItem::Existential(_visitor.fold_impl_item_existential(_binding_0)) + } + ImplItem::Macro(_binding_0) => ImplItem::Macro(_visitor.fold_impl_item_macro(_binding_0)), + ImplItem::Verbatim(_binding_0) => { + ImplItem::Verbatim(_visitor.fold_impl_item_verbatim(_binding_0)) + } + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_const<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ImplItemConst, +) -> ImplItemConst { + ImplItemConst { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + defaultness: (_i.defaultness).map(|it| Token![default](tokens_helper(_visitor, &it.span))), + const_token: Token![const](tokens_helper(_visitor, &_i.const_token.span)), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: _visitor.fold_type(_i.ty), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + expr: _visitor.fold_expr(_i.expr), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_existential<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ImplItemExistential, +) -> ImplItemExistential { + ImplItemExistential { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + existential_token: Token![existential](tokens_helper(_visitor, &_i.existential_token.span)), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_macro<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ImplItemMacro, +) -> ImplItemMacro { + ImplItemMacro { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + mac: _visitor.fold_macro(_i.mac), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_method<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ImplItemMethod, +) -> ImplItemMethod { + ImplItemMethod { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + defaultness: (_i.defaultness).map(|it| Token![default](tokens_helper(_visitor, &it.span))), + sig: _visitor.fold_method_sig(_i.sig), + block: _visitor.fold_block(_i.block), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ImplItemType) -> ImplItemType { + ImplItemType { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + defaultness: (_i.defaultness).map(|it| Token![default](tokens_helper(_visitor, &it.span))), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + ty: _visitor.fold_type(_i.ty), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_impl_item_verbatim<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ImplItemVerbatim, +) -> ImplItemVerbatim { + ImplItemVerbatim { tts: _i.tts } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_index<V: Fold + ?Sized>(_visitor: &mut V, _i: Index) -> Index { + Index { + index: _i.index, + span: _visitor.fold_span(_i.span), + } +} +#[cfg(feature = "full")] +pub fn fold_item<V: Fold + ?Sized>(_visitor: &mut V, _i: Item) -> Item { + match _i { + Item::ExternCrate(_binding_0) => { + Item::ExternCrate(_visitor.fold_item_extern_crate(_binding_0)) + } + Item::Use(_binding_0) => Item::Use(_visitor.fold_item_use(_binding_0)), + Item::Static(_binding_0) => Item::Static(_visitor.fold_item_static(_binding_0)), + Item::Const(_binding_0) => Item::Const(_visitor.fold_item_const(_binding_0)), + Item::Fn(_binding_0) => Item::Fn(_visitor.fold_item_fn(_binding_0)), + Item::Mod(_binding_0) => Item::Mod(_visitor.fold_item_mod(_binding_0)), + Item::ForeignMod(_binding_0) => { + Item::ForeignMod(_visitor.fold_item_foreign_mod(_binding_0)) + } + Item::Type(_binding_0) => Item::Type(_visitor.fold_item_type(_binding_0)), + Item::Existential(_binding_0) => { + Item::Existential(_visitor.fold_item_existential(_binding_0)) + } + Item::Struct(_binding_0) => Item::Struct(_visitor.fold_item_struct(_binding_0)), + Item::Enum(_binding_0) => Item::Enum(_visitor.fold_item_enum(_binding_0)), + Item::Union(_binding_0) => Item::Union(_visitor.fold_item_union(_binding_0)), + Item::Trait(_binding_0) => Item::Trait(_visitor.fold_item_trait(_binding_0)), + Item::TraitAlias(_binding_0) => { + Item::TraitAlias(_visitor.fold_item_trait_alias(_binding_0)) + } + Item::Impl(_binding_0) => Item::Impl(_visitor.fold_item_impl(_binding_0)), + Item::Macro(_binding_0) => Item::Macro(_visitor.fold_item_macro(_binding_0)), + Item::Macro2(_binding_0) => Item::Macro2(_visitor.fold_item_macro2(_binding_0)), + Item::Verbatim(_binding_0) => Item::Verbatim(_visitor.fold_item_verbatim(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_const<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemConst) -> ItemConst { + ItemConst { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + const_token: Token![const](tokens_helper(_visitor, &_i.const_token.span)), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_enum<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemEnum) -> ItemEnum { + ItemEnum { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + enum_token: Token![enum](tokens_helper(_visitor, &_i.enum_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + variants: FoldHelper::lift(_i.variants, |it| _visitor.fold_variant(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_existential<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ItemExistential, +) -> ItemExistential { + ItemExistential { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + existential_token: Token![existential](tokens_helper(_visitor, &_i.existential_token.span)), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_extern_crate<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ItemExternCrate, +) -> ItemExternCrate { + ItemExternCrate { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + extern_token: Token![extern](tokens_helper(_visitor, &_i.extern_token.span)), + crate_token: Token![crate](tokens_helper(_visitor, &_i.crate_token.span)), + ident: _visitor.fold_ident(_i.ident), + rename: (_i.rename).map(|it| { + ( + Token![as](tokens_helper(_visitor, &(it).0.span)), + _visitor.fold_ident((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_fn<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemFn) -> ItemFn { + ItemFn { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + constness: (_i.constness).map(|it| Token![const](tokens_helper(_visitor, &it.span))), + unsafety: (_i.unsafety).map(|it| Token![unsafe](tokens_helper(_visitor, &it.span))), + asyncness: (_i.asyncness).map(|it| Token![async](tokens_helper(_visitor, &it.span))), + abi: (_i.abi).map(|it| _visitor.fold_abi(it)), + ident: _visitor.fold_ident(_i.ident), + decl: Box::new(_visitor.fold_fn_decl(*_i.decl)), + block: Box::new(_visitor.fold_block(*_i.block)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_foreign_mod<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ItemForeignMod, +) -> ItemForeignMod { + ItemForeignMod { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + abi: _visitor.fold_abi(_i.abi), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + items: FoldHelper::lift(_i.items, |it| _visitor.fold_foreign_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_impl<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemImpl) -> ItemImpl { + ItemImpl { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + defaultness: (_i.defaultness).map(|it| Token![default](tokens_helper(_visitor, &it.span))), + unsafety: (_i.unsafety).map(|it| Token![unsafe](tokens_helper(_visitor, &it.span))), + impl_token: Token![impl](tokens_helper(_visitor, &_i.impl_token.span)), + generics: _visitor.fold_generics(_i.generics), + trait_: (_i.trait_).map(|it| { + ( + ((it).0).map(|it| Token![!](tokens_helper(_visitor, &it.spans))), + _visitor.fold_path((it).1), + Token![for](tokens_helper(_visitor, &(it).2.span)), + ) + }), + self_ty: Box::new(_visitor.fold_type(*_i.self_ty)), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + items: FoldHelper::lift(_i.items, |it| _visitor.fold_impl_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMacro) -> ItemMacro { + ItemMacro { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + ident: (_i.ident).map(|it| _visitor.fold_ident(it)), + mac: _visitor.fold_macro(_i.mac), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_macro2<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMacro2) -> ItemMacro2 { + ItemMacro2 { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + macro_token: Token![macro](tokens_helper(_visitor, &_i.macro_token.span)), + ident: _visitor.fold_ident(_i.ident), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + args: _i.args, + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + body: _i.body, + } +} +#[cfg(feature = "full")] +pub fn fold_item_mod<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemMod) -> ItemMod { + ItemMod { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + mod_token: Token![mod](tokens_helper(_visitor, &_i.mod_token.span)), + ident: _visitor.fold_ident(_i.ident), + content: (_i.content).map(|it| { + ( + Brace(tokens_helper(_visitor, &(it).0.span)), + FoldHelper::lift((it).1, |it| _visitor.fold_item(it)), + ) + }), + semi: (_i.semi).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_static<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemStatic) -> ItemStatic { + ItemStatic { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + static_token: Token![static](tokens_helper(_visitor, &_i.static_token.span)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + expr: Box::new(_visitor.fold_expr(*_i.expr)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemStruct) -> ItemStruct { + ItemStruct { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + struct_token: Token![struct](tokens_helper(_visitor, &_i.struct_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + fields: _visitor.fold_fields(_i.fields), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_item_trait<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemTrait) -> ItemTrait { + ItemTrait { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + unsafety: (_i.unsafety).map(|it| Token![unsafe](tokens_helper(_visitor, &it.span))), + auto_token: (_i.auto_token).map(|it| Token![auto](tokens_helper(_visitor, &it.span))), + trait_token: Token![trait](tokens_helper(_visitor, &_i.trait_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + supertraits: FoldHelper::lift(_i.supertraits, |it| _visitor.fold_type_param_bound(it)), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + items: FoldHelper::lift(_i.items, |it| _visitor.fold_trait_item(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_trait_alias<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ItemTraitAlias, +) -> ItemTraitAlias { + ItemTraitAlias { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + trait_token: Token![trait](tokens_helper(_visitor, &_i.trait_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemType) -> ItemType { + ItemType { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_union<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemUnion) -> ItemUnion { + ItemUnion { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + union_token: Token![union](tokens_helper(_visitor, &_i.union_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + fields: _visitor.fold_fields_named(_i.fields), + } +} +#[cfg(feature = "full")] +pub fn fold_item_use<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemUse) -> ItemUse { + ItemUse { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + vis: _visitor.fold_visibility(_i.vis), + use_token: Token![use](tokens_helper(_visitor, &_i.use_token.span)), + leading_colon: (_i.leading_colon) + .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))), + tree: _visitor.fold_use_tree(_i.tree), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_item_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: ItemVerbatim) -> ItemVerbatim { + ItemVerbatim { tts: _i.tts } +} +#[cfg(feature = "full")] +pub fn fold_label<V: Fold + ?Sized>(_visitor: &mut V, _i: Label) -> Label { + Label { + name: _visitor.fold_lifetime(_i.name), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + } +} +pub fn fold_lifetime<V: Fold + ?Sized>(_visitor: &mut V, _i: Lifetime) -> Lifetime { + Lifetime { + apostrophe: _visitor.fold_span(_i.apostrophe), + ident: _visitor.fold_ident(_i.ident), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lifetime_def<V: Fold + ?Sized>(_visitor: &mut V, _i: LifetimeDef) -> LifetimeDef { + LifetimeDef { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + lifetime: _visitor.fold_lifetime(_i.lifetime), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: Lit) -> Lit { + match _i { + Lit::Str(_binding_0) => Lit::Str(_visitor.fold_lit_str(_binding_0)), + Lit::ByteStr(_binding_0) => Lit::ByteStr(_visitor.fold_lit_byte_str(_binding_0)), + Lit::Byte(_binding_0) => Lit::Byte(_visitor.fold_lit_byte(_binding_0)), + Lit::Char(_binding_0) => Lit::Char(_visitor.fold_lit_char(_binding_0)), + Lit::Int(_binding_0) => Lit::Int(_visitor.fold_lit_int(_binding_0)), + Lit::Float(_binding_0) => Lit::Float(_visitor.fold_lit_float(_binding_0)), + Lit::Bool(_binding_0) => Lit::Bool(_visitor.fold_lit_bool(_binding_0)), + Lit::Verbatim(_binding_0) => Lit::Verbatim(_visitor.fold_lit_verbatim(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_bool<V: Fold + ?Sized>(_visitor: &mut V, _i: LitBool) -> LitBool { + LitBool { + value: _i.value, + span: _visitor.fold_span(_i.span), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_lit_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: LitVerbatim) -> LitVerbatim { + LitVerbatim { token: _i.token } +} +#[cfg(feature = "full")] +pub fn fold_local<V: Fold + ?Sized>(_visitor: &mut V, _i: Local) -> Local { + Local { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + let_token: Token![let](tokens_helper(_visitor, &_i.let_token.span)), + pats: FoldHelper::lift(_i.pats, |it| _visitor.fold_pat(it)), + ty: (_i.ty).map(|it| { + ( + Token ! [ : ](tokens_helper(_visitor, &(it).0.spans)), + Box::new(_visitor.fold_type(*(it).1)), + ) + }), + init: (_i.init).map(|it| { + ( + Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)), + Box::new(_visitor.fold_expr(*(it).1)), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: Macro) -> Macro { + Macro { + path: _visitor.fold_path(_i.path), + bang_token: Token![!](tokens_helper(_visitor, &_i.bang_token.spans)), + delimiter: _visitor.fold_macro_delimiter(_i.delimiter), + tts: _i.tts, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_macro_delimiter<V: Fold + ?Sized>( + _visitor: &mut V, + _i: MacroDelimiter, +) -> MacroDelimiter { + match _i { + MacroDelimiter::Paren(_binding_0) => { + MacroDelimiter::Paren(Paren(tokens_helper(_visitor, &_binding_0.span))) + } + MacroDelimiter::Brace(_binding_0) => { + MacroDelimiter::Brace(Brace(tokens_helper(_visitor, &_binding_0.span))) + } + MacroDelimiter::Bracket(_binding_0) => { + MacroDelimiter::Bracket(Bracket(tokens_helper(_visitor, &_binding_0.span))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_member<V: Fold + ?Sized>(_visitor: &mut V, _i: Member) -> Member { + match _i { + Member::Named(_binding_0) => Member::Named(_visitor.fold_ident(_binding_0)), + Member::Unnamed(_binding_0) => Member::Unnamed(_visitor.fold_index(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta<V: Fold + ?Sized>(_visitor: &mut V, _i: Meta) -> Meta { + match _i { + Meta::Word(_binding_0) => Meta::Word(_visitor.fold_ident(_binding_0)), + Meta::List(_binding_0) => Meta::List(_visitor.fold_meta_list(_binding_0)), + Meta::NameValue(_binding_0) => Meta::NameValue(_visitor.fold_meta_name_value(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta_list<V: Fold + ?Sized>(_visitor: &mut V, _i: MetaList) -> MetaList { + MetaList { + ident: _visitor.fold_ident(_i.ident), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + nested: FoldHelper::lift(_i.nested, |it| _visitor.fold_nested_meta(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_meta_name_value<V: Fold + ?Sized>( + _visitor: &mut V, + _i: MetaNameValue, +) -> MetaNameValue { + MetaNameValue { + ident: _visitor.fold_ident(_i.ident), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + lit: _visitor.fold_lit(_i.lit), + } +} +#[cfg(feature = "full")] +pub fn fold_method_sig<V: Fold + ?Sized>(_visitor: &mut V, _i: MethodSig) -> MethodSig { + MethodSig { + constness: (_i.constness).map(|it| Token![const](tokens_helper(_visitor, &it.span))), + unsafety: (_i.unsafety).map(|it| Token![unsafe](tokens_helper(_visitor, &it.span))), + asyncness: (_i.asyncness).map(|it| Token![async](tokens_helper(_visitor, &it.span))), + abi: (_i.abi).map(|it| _visitor.fold_abi(it)), + ident: _visitor.fold_ident(_i.ident), + decl: _visitor.fold_fn_decl(_i.decl), + } +} +#[cfg(feature = "full")] +pub fn fold_method_turbofish<V: Fold + ?Sized>( + _visitor: &mut V, + _i: MethodTurbofish, +) -> MethodTurbofish { + MethodTurbofish { + colon2_token: Token ! [ :: ](tokens_helper(_visitor, &_i.colon2_token.spans)), + lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)), + args: FoldHelper::lift(_i.args, |it| _visitor.fold_generic_method_argument(it)), + gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_nested_meta<V: Fold + ?Sized>(_visitor: &mut V, _i: NestedMeta) -> NestedMeta { + match _i { + NestedMeta::Meta(_binding_0) => NestedMeta::Meta(_visitor.fold_meta(_binding_0)), + NestedMeta::Literal(_binding_0) => NestedMeta::Literal(_visitor.fold_lit(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_parenthesized_generic_arguments<V: Fold + ?Sized>( + _visitor: &mut V, + _i: ParenthesizedGenericArguments, +) -> ParenthesizedGenericArguments { + ParenthesizedGenericArguments { + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_type(it)), + output: _visitor.fold_return_type(_i.output), + } +} +#[cfg(feature = "full")] +pub fn fold_pat<V: Fold + ?Sized>(_visitor: &mut V, _i: Pat) -> Pat { + match _i { + Pat::Wild(_binding_0) => Pat::Wild(_visitor.fold_pat_wild(_binding_0)), + Pat::Ident(_binding_0) => Pat::Ident(_visitor.fold_pat_ident(_binding_0)), + Pat::Struct(_binding_0) => Pat::Struct(_visitor.fold_pat_struct(_binding_0)), + Pat::TupleStruct(_binding_0) => { + Pat::TupleStruct(_visitor.fold_pat_tuple_struct(_binding_0)) + } + Pat::Path(_binding_0) => Pat::Path(_visitor.fold_pat_path(_binding_0)), + Pat::Tuple(_binding_0) => Pat::Tuple(_visitor.fold_pat_tuple(_binding_0)), + Pat::Box(_binding_0) => Pat::Box(_visitor.fold_pat_box(_binding_0)), + Pat::Ref(_binding_0) => Pat::Ref(_visitor.fold_pat_ref(_binding_0)), + Pat::Lit(_binding_0) => Pat::Lit(_visitor.fold_pat_lit(_binding_0)), + Pat::Range(_binding_0) => Pat::Range(_visitor.fold_pat_range(_binding_0)), + Pat::Slice(_binding_0) => Pat::Slice(_visitor.fold_pat_slice(_binding_0)), + Pat::Macro(_binding_0) => Pat::Macro(_visitor.fold_pat_macro(_binding_0)), + Pat::Verbatim(_binding_0) => Pat::Verbatim(_visitor.fold_pat_verbatim(_binding_0)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_box<V: Fold + ?Sized>(_visitor: &mut V, _i: PatBox) -> PatBox { + PatBox { + box_token: Token![box](tokens_helper(_visitor, &_i.box_token.span)), + pat: Box::new(_visitor.fold_pat(*_i.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_ident<V: Fold + ?Sized>(_visitor: &mut V, _i: PatIdent) -> PatIdent { + PatIdent { + by_ref: (_i.by_ref).map(|it| Token![ref](tokens_helper(_visitor, &it.span))), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + ident: _visitor.fold_ident(_i.ident), + subpat: (_i.subpat).map(|it| { + ( + Token ! [ @ ](tokens_helper(_visitor, &(it).0.spans)), + Box::new(_visitor.fold_pat(*(it).1)), + ) + }), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_lit<V: Fold + ?Sized>(_visitor: &mut V, _i: PatLit) -> PatLit { + PatLit { + expr: Box::new(_visitor.fold_expr(*_i.expr)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: PatMacro) -> PatMacro { + PatMacro { + mac: _visitor.fold_macro(_i.mac), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_path<V: Fold + ?Sized>(_visitor: &mut V, _i: PatPath) -> PatPath { + PatPath { + qself: (_i.qself).map(|it| _visitor.fold_qself(it)), + path: _visitor.fold_path(_i.path), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_range<V: Fold + ?Sized>(_visitor: &mut V, _i: PatRange) -> PatRange { + PatRange { + lo: Box::new(_visitor.fold_expr(*_i.lo)), + limits: _visitor.fold_range_limits(_i.limits), + hi: Box::new(_visitor.fold_expr(*_i.hi)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_ref<V: Fold + ?Sized>(_visitor: &mut V, _i: PatRef) -> PatRef { + PatRef { + and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + pat: Box::new(_visitor.fold_pat(*_i.pat)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_slice<V: Fold + ?Sized>(_visitor: &mut V, _i: PatSlice) -> PatSlice { + PatSlice { + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + front: FoldHelper::lift(_i.front, |it| _visitor.fold_pat(it)), + middle: (_i.middle).map(|it| Box::new(_visitor.fold_pat(*it))), + dot2_token: (_i.dot2_token).map(|it| Token![..](tokens_helper(_visitor, &it.spans))), + comma_token: (_i.comma_token).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))), + back: FoldHelper::lift(_i.back, |it| _visitor.fold_pat(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_struct<V: Fold + ?Sized>(_visitor: &mut V, _i: PatStruct) -> PatStruct { + PatStruct { + path: _visitor.fold_path(_i.path), + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + fields: FoldHelper::lift(_i.fields, |it| _visitor.fold_field_pat(it)), + dot2_token: (_i.dot2_token).map(|it| Token![..](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: PatTuple) -> PatTuple { + PatTuple { + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + front: FoldHelper::lift(_i.front, |it| _visitor.fold_pat(it)), + dot2_token: (_i.dot2_token).map(|it| Token![..](tokens_helper(_visitor, &it.spans))), + comma_token: (_i.comma_token).map(|it| Token ! [ , ](tokens_helper(_visitor, &it.spans))), + back: FoldHelper::lift(_i.back, |it| _visitor.fold_pat(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_tuple_struct<V: Fold + ?Sized>( + _visitor: &mut V, + _i: PatTupleStruct, +) -> PatTupleStruct { + PatTupleStruct { + path: _visitor.fold_path(_i.path), + pat: _visitor.fold_pat_tuple(_i.pat), + } +} +#[cfg(feature = "full")] +pub fn fold_pat_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: PatVerbatim) -> PatVerbatim { + PatVerbatim { tts: _i.tts } +} +#[cfg(feature = "full")] +pub fn fold_pat_wild<V: Fold + ?Sized>(_visitor: &mut V, _i: PatWild) -> PatWild { + PatWild { + underscore_token: Token![_](tokens_helper(_visitor, &_i.underscore_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path<V: Fold + ?Sized>(_visitor: &mut V, _i: Path) -> Path { + Path { + leading_colon: (_i.leading_colon) + .map(|it| Token ! [ :: ](tokens_helper(_visitor, &it.spans))), + segments: FoldHelper::lift(_i.segments, |it| _visitor.fold_path_segment(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path_arguments<V: Fold + ?Sized>(_visitor: &mut V, _i: PathArguments) -> PathArguments { + match _i { + PathArguments::None => PathArguments::None, + PathArguments::AngleBracketed(_binding_0) => PathArguments::AngleBracketed( + _visitor.fold_angle_bracketed_generic_arguments(_binding_0), + ), + PathArguments::Parenthesized(_binding_0) => { + PathArguments::Parenthesized(_visitor.fold_parenthesized_generic_arguments(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_path_segment<V: Fold + ?Sized>(_visitor: &mut V, _i: PathSegment) -> PathSegment { + PathSegment { + ident: _visitor.fold_ident(_i.ident), + arguments: _visitor.fold_path_arguments(_i.arguments), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_eq<V: Fold + ?Sized>(_visitor: &mut V, _i: PredicateEq) -> PredicateEq { + PredicateEq { + lhs_ty: _visitor.fold_type(_i.lhs_ty), + eq_token: Token ! [ = ](tokens_helper(_visitor, &_i.eq_token.spans)), + rhs_ty: _visitor.fold_type(_i.rhs_ty), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_lifetime<V: Fold + ?Sized>( + _visitor: &mut V, + _i: PredicateLifetime, +) -> PredicateLifetime { + PredicateLifetime { + lifetime: _visitor.fold_lifetime(_i.lifetime), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_lifetime(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_predicate_type<V: Fold + ?Sized>(_visitor: &mut V, _i: PredicateType) -> PredicateType { + PredicateType { + lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)), + bounded_ty: _visitor.fold_type(_i.bounded_ty), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_qself<V: Fold + ?Sized>(_visitor: &mut V, _i: QSelf) -> QSelf { + QSelf { + lt_token: Token ! [ < ](tokens_helper(_visitor, &_i.lt_token.spans)), + ty: Box::new(_visitor.fold_type(*_i.ty)), + position: _i.position, + as_token: (_i.as_token).map(|it| Token![as](tokens_helper(_visitor, &it.span))), + gt_token: Token ! [ > ](tokens_helper(_visitor, &_i.gt_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_range_limits<V: Fold + ?Sized>(_visitor: &mut V, _i: RangeLimits) -> RangeLimits { + match _i { + RangeLimits::HalfOpen(_binding_0) => { + RangeLimits::HalfOpen(Token![..](tokens_helper(_visitor, &_binding_0.spans))) + } + RangeLimits::Closed(_binding_0) => { + RangeLimits::Closed(Token ! [ ..= ](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_return_type<V: Fold + ?Sized>(_visitor: &mut V, _i: ReturnType) -> ReturnType { + match _i { + ReturnType::Default => ReturnType::Default, + ReturnType::Type(_binding_0, _binding_1) => ReturnType::Type( + Token ! [ -> ](tokens_helper(_visitor, &_binding_0.spans)), + Box::new(_visitor.fold_type(*_binding_1)), + ), + } +} +#[cfg(feature = "full")] +pub fn fold_stmt<V: Fold + ?Sized>(_visitor: &mut V, _i: Stmt) -> Stmt { + match _i { + Stmt::Local(_binding_0) => Stmt::Local(_visitor.fold_local(_binding_0)), + Stmt::Item(_binding_0) => Stmt::Item(_visitor.fold_item(_binding_0)), + Stmt::Expr(_binding_0) => Stmt::Expr(_visitor.fold_expr(_binding_0)), + Stmt::Semi(_binding_0, _binding_1) => Stmt::Semi( + _visitor.fold_expr(_binding_0), + Token ! [ ; ](tokens_helper(_visitor, &_binding_1.spans)), + ), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_trait_bound<V: Fold + ?Sized>(_visitor: &mut V, _i: TraitBound) -> TraitBound { + TraitBound { + paren_token: (_i.paren_token).map(|it| Paren(tokens_helper(_visitor, &it.span))), + modifier: _visitor.fold_trait_bound_modifier(_i.modifier), + lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)), + path: _visitor.fold_path(_i.path), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_trait_bound_modifier<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitBoundModifier, +) -> TraitBoundModifier { + match _i { + TraitBoundModifier::None => TraitBoundModifier::None, + TraitBoundModifier::Maybe(_binding_0) => { + TraitBoundModifier::Maybe(Token ! [ ? ](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item<V: Fold + ?Sized>(_visitor: &mut V, _i: TraitItem) -> TraitItem { + match _i { + TraitItem::Const(_binding_0) => { + TraitItem::Const(_visitor.fold_trait_item_const(_binding_0)) + } + TraitItem::Method(_binding_0) => { + TraitItem::Method(_visitor.fold_trait_item_method(_binding_0)) + } + TraitItem::Type(_binding_0) => TraitItem::Type(_visitor.fold_trait_item_type(_binding_0)), + TraitItem::Macro(_binding_0) => { + TraitItem::Macro(_visitor.fold_trait_item_macro(_binding_0)) + } + TraitItem::Verbatim(_binding_0) => { + TraitItem::Verbatim(_visitor.fold_trait_item_verbatim(_binding_0)) + } + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_const<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitItemConst, +) -> TraitItemConst { + TraitItemConst { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + const_token: Token![const](tokens_helper(_visitor, &_i.const_token.span)), + ident: _visitor.fold_ident(_i.ident), + colon_token: Token ! [ : ](tokens_helper(_visitor, &_i.colon_token.spans)), + ty: _visitor.fold_type(_i.ty), + default: (_i.default).map(|it| { + ( + Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)), + _visitor.fold_expr((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_macro<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitItemMacro, +) -> TraitItemMacro { + TraitItemMacro { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + mac: _visitor.fold_macro(_i.mac), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_method<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitItemMethod, +) -> TraitItemMethod { + TraitItemMethod { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + sig: _visitor.fold_method_sig(_i.sig), + default: (_i.default).map(|it| _visitor.fold_block(it)), + semi_token: (_i.semi_token).map(|it| Token ! [ ; ](tokens_helper(_visitor, &it.spans))), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_type<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitItemType, +) -> TraitItemType { + TraitItemType { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + type_token: Token![type](tokens_helper(_visitor, &_i.type_token.span)), + ident: _visitor.fold_ident(_i.ident), + generics: _visitor.fold_generics(_i.generics), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + default: (_i.default).map(|it| { + ( + Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)), + _visitor.fold_type((it).1), + ) + }), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_trait_item_verbatim<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TraitItemVerbatim, +) -> TraitItemVerbatim { + TraitItemVerbatim { tts: _i.tts } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type<V: Fold + ?Sized>(_visitor: &mut V, _i: Type) -> Type { + match _i { + Type::Slice(_binding_0) => Type::Slice(_visitor.fold_type_slice(_binding_0)), + Type::Array(_binding_0) => Type::Array(_visitor.fold_type_array(_binding_0)), + Type::Ptr(_binding_0) => Type::Ptr(_visitor.fold_type_ptr(_binding_0)), + Type::Reference(_binding_0) => Type::Reference(_visitor.fold_type_reference(_binding_0)), + Type::BareFn(_binding_0) => Type::BareFn(_visitor.fold_type_bare_fn(_binding_0)), + Type::Never(_binding_0) => Type::Never(_visitor.fold_type_never(_binding_0)), + Type::Tuple(_binding_0) => Type::Tuple(_visitor.fold_type_tuple(_binding_0)), + Type::Path(_binding_0) => Type::Path(_visitor.fold_type_path(_binding_0)), + Type::TraitObject(_binding_0) => { + Type::TraitObject(_visitor.fold_type_trait_object(_binding_0)) + } + Type::ImplTrait(_binding_0) => Type::ImplTrait(_visitor.fold_type_impl_trait(_binding_0)), + Type::Paren(_binding_0) => Type::Paren(_visitor.fold_type_paren(_binding_0)), + Type::Group(_binding_0) => Type::Group(_visitor.fold_type_group(_binding_0)), + Type::Infer(_binding_0) => Type::Infer(_visitor.fold_type_infer(_binding_0)), + Type::Macro(_binding_0) => Type::Macro(_visitor.fold_type_macro(_binding_0)), + Type::Verbatim(_binding_0) => Type::Verbatim(_visitor.fold_type_verbatim(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_array<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeArray) -> TypeArray { + TypeArray { + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + elem: Box::new(_visitor.fold_type(*_i.elem)), + semi_token: Token ! [ ; ](tokens_helper(_visitor, &_i.semi_token.spans)), + len: _visitor.fold_expr(_i.len), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_bare_fn<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeBareFn) -> TypeBareFn { + TypeBareFn { + lifetimes: (_i.lifetimes).map(|it| _visitor.fold_bound_lifetimes(it)), + unsafety: (_i.unsafety).map(|it| Token![unsafe](tokens_helper(_visitor, &it.span))), + abi: (_i.abi).map(|it| _visitor.fold_abi(it)), + fn_token: Token![fn](tokens_helper(_visitor, &_i.fn_token.span)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + inputs: FoldHelper::lift(_i.inputs, |it| _visitor.fold_bare_fn_arg(it)), + variadic: (_i.variadic).map(|it| Token ! [ ... ](tokens_helper(_visitor, &it.spans))), + output: _visitor.fold_return_type(_i.output), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_group<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeGroup) -> TypeGroup { + TypeGroup { + group_token: Group(tokens_helper(_visitor, &_i.group_token.span)), + elem: Box::new(_visitor.fold_type(*_i.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_impl_trait<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TypeImplTrait, +) -> TypeImplTrait { + TypeImplTrait { + impl_token: Token![impl](tokens_helper(_visitor, &_i.impl_token.span)), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_infer<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeInfer) -> TypeInfer { + TypeInfer { + underscore_token: Token![_](tokens_helper(_visitor, &_i.underscore_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_macro<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeMacro) -> TypeMacro { + TypeMacro { + mac: _visitor.fold_macro(_i.mac), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_never<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeNever) -> TypeNever { + TypeNever { + bang_token: Token![!](tokens_helper(_visitor, &_i.bang_token.spans)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_param<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeParam) -> TypeParam { + TypeParam { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + ident: _visitor.fold_ident(_i.ident), + colon_token: (_i.colon_token).map(|it| Token ! [ : ](tokens_helper(_visitor, &it.spans))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + eq_token: (_i.eq_token).map(|it| Token ! [ = ](tokens_helper(_visitor, &it.spans))), + default: (_i.default).map(|it| _visitor.fold_type(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_param_bound<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TypeParamBound, +) -> TypeParamBound { + match _i { + TypeParamBound::Trait(_binding_0) => { + TypeParamBound::Trait(_visitor.fold_trait_bound(_binding_0)) + } + TypeParamBound::Lifetime(_binding_0) => { + TypeParamBound::Lifetime(_visitor.fold_lifetime(_binding_0)) + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_paren<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeParen) -> TypeParen { + TypeParen { + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + elem: Box::new(_visitor.fold_type(*_i.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_path<V: Fold + ?Sized>(_visitor: &mut V, _i: TypePath) -> TypePath { + TypePath { + qself: (_i.qself).map(|it| _visitor.fold_qself(it)), + path: _visitor.fold_path(_i.path), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_ptr<V: Fold + ?Sized>(_visitor: &mut V, _i: TypePtr) -> TypePtr { + TypePtr { + star_token: Token ! [ * ](tokens_helper(_visitor, &_i.star_token.spans)), + const_token: (_i.const_token).map(|it| Token![const](tokens_helper(_visitor, &it.span))), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + elem: Box::new(_visitor.fold_type(*_i.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_reference<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeReference) -> TypeReference { + TypeReference { + and_token: Token ! [ & ](tokens_helper(_visitor, &_i.and_token.spans)), + lifetime: (_i.lifetime).map(|it| _visitor.fold_lifetime(it)), + mutability: (_i.mutability).map(|it| Token![mut](tokens_helper(_visitor, &it.span))), + elem: Box::new(_visitor.fold_type(*_i.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_slice<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeSlice) -> TypeSlice { + TypeSlice { + bracket_token: Bracket(tokens_helper(_visitor, &_i.bracket_token.span)), + elem: Box::new(_visitor.fold_type(*_i.elem)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_trait_object<V: Fold + ?Sized>( + _visitor: &mut V, + _i: TypeTraitObject, +) -> TypeTraitObject { + TypeTraitObject { + dyn_token: (_i.dyn_token).map(|it| Token![dyn](tokens_helper(_visitor, &it.span))), + bounds: FoldHelper::lift(_i.bounds, |it| _visitor.fold_type_param_bound(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_tuple<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeTuple) -> TypeTuple { + TypeTuple { + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + elems: FoldHelper::lift(_i.elems, |it| _visitor.fold_type(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_type_verbatim<V: Fold + ?Sized>(_visitor: &mut V, _i: TypeVerbatim) -> TypeVerbatim { + TypeVerbatim { tts: _i.tts } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_un_op<V: Fold + ?Sized>(_visitor: &mut V, _i: UnOp) -> UnOp { + match _i { + UnOp::Deref(_binding_0) => { + UnOp::Deref(Token ! [ * ](tokens_helper(_visitor, &_binding_0.spans))) + } + UnOp::Not(_binding_0) => UnOp::Not(Token![!](tokens_helper(_visitor, &_binding_0.spans))), + UnOp::Neg(_binding_0) => { + UnOp::Neg(Token ! [ - ](tokens_helper(_visitor, &_binding_0.spans))) + } + } +} +#[cfg(feature = "full")] +pub fn fold_use_glob<V: Fold + ?Sized>(_visitor: &mut V, _i: UseGlob) -> UseGlob { + UseGlob { + star_token: Token ! [ * ](tokens_helper(_visitor, &_i.star_token.spans)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_group<V: Fold + ?Sized>(_visitor: &mut V, _i: UseGroup) -> UseGroup { + UseGroup { + brace_token: Brace(tokens_helper(_visitor, &_i.brace_token.span)), + items: FoldHelper::lift(_i.items, |it| _visitor.fold_use_tree(it)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_name<V: Fold + ?Sized>(_visitor: &mut V, _i: UseName) -> UseName { + UseName { + ident: _visitor.fold_ident(_i.ident), + } +} +#[cfg(feature = "full")] +pub fn fold_use_path<V: Fold + ?Sized>(_visitor: &mut V, _i: UsePath) -> UsePath { + UsePath { + ident: _visitor.fold_ident(_i.ident), + colon2_token: Token ! [ :: ](tokens_helper(_visitor, &_i.colon2_token.spans)), + tree: Box::new(_visitor.fold_use_tree(*_i.tree)), + } +} +#[cfg(feature = "full")] +pub fn fold_use_rename<V: Fold + ?Sized>(_visitor: &mut V, _i: UseRename) -> UseRename { + UseRename { + ident: _visitor.fold_ident(_i.ident), + as_token: Token![as](tokens_helper(_visitor, &_i.as_token.span)), + rename: _visitor.fold_ident(_i.rename), + } +} +#[cfg(feature = "full")] +pub fn fold_use_tree<V: Fold + ?Sized>(_visitor: &mut V, _i: UseTree) -> UseTree { + match _i { + UseTree::Path(_binding_0) => UseTree::Path(_visitor.fold_use_path(_binding_0)), + UseTree::Name(_binding_0) => UseTree::Name(_visitor.fold_use_name(_binding_0)), + UseTree::Rename(_binding_0) => UseTree::Rename(_visitor.fold_use_rename(_binding_0)), + UseTree::Glob(_binding_0) => UseTree::Glob(_visitor.fold_use_glob(_binding_0)), + UseTree::Group(_binding_0) => UseTree::Group(_visitor.fold_use_group(_binding_0)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_variant<V: Fold + ?Sized>(_visitor: &mut V, _i: Variant) -> Variant { + Variant { + attrs: FoldHelper::lift(_i.attrs, |it| _visitor.fold_attribute(it)), + ident: _visitor.fold_ident(_i.ident), + fields: _visitor.fold_fields(_i.fields), + discriminant: (_i.discriminant).map(|it| { + ( + Token ! [ = ](tokens_helper(_visitor, &(it).0.spans)), + _visitor.fold_expr((it).1), + ) + }), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_crate<V: Fold + ?Sized>(_visitor: &mut V, _i: VisCrate) -> VisCrate { + VisCrate { + crate_token: Token![crate](tokens_helper(_visitor, &_i.crate_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_public<V: Fold + ?Sized>(_visitor: &mut V, _i: VisPublic) -> VisPublic { + VisPublic { + pub_token: Token![pub](tokens_helper(_visitor, &_i.pub_token.span)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_vis_restricted<V: Fold + ?Sized>(_visitor: &mut V, _i: VisRestricted) -> VisRestricted { + VisRestricted { + pub_token: Token![pub](tokens_helper(_visitor, &_i.pub_token.span)), + paren_token: Paren(tokens_helper(_visitor, &_i.paren_token.span)), + in_token: (_i.in_token).map(|it| Token![in](tokens_helper(_visitor, &it.span))), + path: Box::new(_visitor.fold_path(*_i.path)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_visibility<V: Fold + ?Sized>(_visitor: &mut V, _i: Visibility) -> Visibility { + match _i { + Visibility::Public(_binding_0) => Visibility::Public(_visitor.fold_vis_public(_binding_0)), + Visibility::Crate(_binding_0) => Visibility::Crate(_visitor.fold_vis_crate(_binding_0)), + Visibility::Restricted(_binding_0) => { + Visibility::Restricted(_visitor.fold_vis_restricted(_binding_0)) + } + Visibility::Inherited => Visibility::Inherited, + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_where_clause<V: Fold + ?Sized>(_visitor: &mut V, _i: WhereClause) -> WhereClause { + WhereClause { + where_token: Token![where](tokens_helper(_visitor, &_i.where_token.span)), + predicates: FoldHelper::lift(_i.predicates, |it| _visitor.fold_where_predicate(it)), + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn fold_where_predicate<V: Fold + ?Sized>( + _visitor: &mut V, + _i: WherePredicate, +) -> WherePredicate { + match _i { + WherePredicate::Type(_binding_0) => { + WherePredicate::Type(_visitor.fold_predicate_type(_binding_0)) + } + WherePredicate::Lifetime(_binding_0) => { + WherePredicate::Lifetime(_visitor.fold_predicate_lifetime(_binding_0)) + } + WherePredicate::Eq(_binding_0) => { + WherePredicate::Eq(_visitor.fold_predicate_eq(_binding_0)) + } + } +} +pub fn fold_span<V: Fold + ?Sized>(_visitor: &mut V, _i: Span) -> Span { + _i +} +pub fn fold_ident<V: Fold + ?Sized>(_visitor: &mut V, _i: Ident) -> Ident { + let mut _i = _i; + let span = _visitor.fold_span(_i.span()); + _i.set_span(span); + _i +} diff --git a/syn/src/gen/visit.rs b/syn/src/gen/visit.rs new file mode 100644 index 000000000..e449a0b9d --- /dev/null +++ b/syn/src/gen/visit.rs @@ -0,0 +1,3371 @@ +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT + +#![cfg_attr(feature = "cargo-clippy", allow(trivially_copy_pass_by_ref))] +#[cfg(any(feature = "full", feature = "derive"))] +use gen::helper::visit::*; +use proc_macro2::Span; +#[cfg(any(feature = "full", feature = "derive"))] +use punctuated::Punctuated; +use *; +#[cfg(feature = "full")] +macro_rules! full { + ($e:expr) => { + $e + }; +} +#[cfg(all(feature = "derive", not(feature = "full")))] +macro_rules! full { + ($e:expr) => { + unreachable!() + }; +} +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! skip { + ($($tt:tt)*) => {}; +} +/// Syntax tree traversal to walk a shared borrow of a syntax tree. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: index.html +/// +/// *This trait is available if Syn is built with the `"visit"` feature.* +pub trait Visit<'ast> { + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_abi(&mut self, i: &'ast Abi) { + visit_abi(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_angle_bracketed_generic_arguments(&mut self, i: &'ast AngleBracketedGenericArguments) { + visit_angle_bracketed_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_captured(&mut self, i: &'ast ArgCaptured) { + visit_arg_captured(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_self(&mut self, i: &'ast ArgSelf) { + visit_arg_self(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_self_ref(&mut self, i: &'ast ArgSelfRef) { + visit_arg_self_ref(self, i) + } + #[cfg(feature = "full")] + fn visit_arm(&mut self, i: &'ast Arm) { + visit_arm(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attr_style(&mut self, i: &'ast AttrStyle) { + visit_attr_style(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attribute(&mut self, i: &'ast Attribute) { + visit_attribute(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg(&mut self, i: &'ast BareFnArg) { + visit_bare_fn_arg(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg_name(&mut self, i: &'ast BareFnArgName) { + visit_bare_fn_arg_name(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bin_op(&mut self, i: &'ast BinOp) { + visit_bin_op(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_binding(&mut self, i: &'ast Binding) { + visit_binding(self, i) + } + #[cfg(feature = "full")] + fn visit_block(&mut self, i: &'ast Block) { + visit_block(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bound_lifetimes(&mut self, i: &'ast BoundLifetimes) { + visit_bound_lifetimes(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_const_param(&mut self, i: &'ast ConstParam) { + visit_const_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_constraint(&mut self, i: &'ast Constraint) { + visit_constraint(self, i) + } + #[cfg(feature = "derive")] + fn visit_data(&mut self, i: &'ast Data) { + visit_data(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_enum(&mut self, i: &'ast DataEnum) { + visit_data_enum(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_struct(&mut self, i: &'ast DataStruct) { + visit_data_struct(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_union(&mut self, i: &'ast DataUnion) { + visit_data_union(self, i) + } + #[cfg(feature = "derive")] + fn visit_derive_input(&mut self, i: &'ast DeriveInput) { + visit_derive_input(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr(&mut self, i: &'ast Expr) { + visit_expr(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_array(&mut self, i: &'ast ExprArray) { + visit_expr_array(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign(&mut self, i: &'ast ExprAssign) { + visit_expr_assign(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_op(&mut self, i: &'ast ExprAssignOp) { + visit_expr_assign_op(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_async(&mut self, i: &'ast ExprAsync) { + visit_expr_async(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_binary(&mut self, i: &'ast ExprBinary) { + visit_expr_binary(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_block(&mut self, i: &'ast ExprBlock) { + visit_expr_block(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_box(&mut self, i: &'ast ExprBox) { + visit_expr_box(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_break(&mut self, i: &'ast ExprBreak) { + visit_expr_break(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_call(&mut self, i: &'ast ExprCall) { + visit_expr_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_cast(&mut self, i: &'ast ExprCast) { + visit_expr_cast(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_closure(&mut self, i: &'ast ExprClosure) { + visit_expr_closure(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_continue(&mut self, i: &'ast ExprContinue) { + visit_expr_continue(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_field(&mut self, i: &'ast ExprField) { + visit_expr_field(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_for_loop(&mut self, i: &'ast ExprForLoop) { + visit_expr_for_loop(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_group(&mut self, i: &'ast ExprGroup) { + visit_expr_group(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_if(&mut self, i: &'ast ExprIf) { + visit_expr_if(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_in_place(&mut self, i: &'ast ExprInPlace) { + visit_expr_in_place(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_index(&mut self, i: &'ast ExprIndex) { + visit_expr_index(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_let(&mut self, i: &'ast ExprLet) { + visit_expr_let(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_lit(&mut self, i: &'ast ExprLit) { + visit_expr_lit(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_loop(&mut self, i: &'ast ExprLoop) { + visit_expr_loop(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_macro(&mut self, i: &'ast ExprMacro) { + visit_expr_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_match(&mut self, i: &'ast ExprMatch) { + visit_expr_match(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_method_call(&mut self, i: &'ast ExprMethodCall) { + visit_expr_method_call(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_paren(&mut self, i: &'ast ExprParen) { + visit_expr_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_path(&mut self, i: &'ast ExprPath) { + visit_expr_path(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_range(&mut self, i: &'ast ExprRange) { + visit_expr_range(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_reference(&mut self, i: &'ast ExprReference) { + visit_expr_reference(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_repeat(&mut self, i: &'ast ExprRepeat) { + visit_expr_repeat(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_return(&mut self, i: &'ast ExprReturn) { + visit_expr_return(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_struct(&mut self, i: &'ast ExprStruct) { + visit_expr_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try(&mut self, i: &'ast ExprTry) { + visit_expr_try(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_block(&mut self, i: &'ast ExprTryBlock) { + visit_expr_try_block(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_tuple(&mut self, i: &'ast ExprTuple) { + visit_expr_tuple(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_type(&mut self, i: &'ast ExprType) { + visit_expr_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_unary(&mut self, i: &'ast ExprUnary) { + visit_expr_unary(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_unsafe(&mut self, i: &'ast ExprUnsafe) { + visit_expr_unsafe(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_verbatim(&mut self, i: &'ast ExprVerbatim) { + visit_expr_verbatim(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_while(&mut self, i: &'ast ExprWhile) { + visit_expr_while(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_yield(&mut self, i: &'ast ExprYield) { + visit_expr_yield(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_field(&mut self, i: &'ast Field) { + visit_field(self, i) + } + #[cfg(feature = "full")] + fn visit_field_pat(&mut self, i: &'ast FieldPat) { + visit_field_pat(self, i) + } + #[cfg(feature = "full")] + fn visit_field_value(&mut self, i: &'ast FieldValue) { + visit_field_value(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields(&mut self, i: &'ast Fields) { + visit_fields(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_named(&mut self, i: &'ast FieldsNamed) { + visit_fields_named(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_unnamed(&mut self, i: &'ast FieldsUnnamed) { + visit_fields_unnamed(self, i) + } + #[cfg(feature = "full")] + fn visit_file(&mut self, i: &'ast File) { + visit_file(self, i) + } + #[cfg(feature = "full")] + fn visit_fn_arg(&mut self, i: &'ast FnArg) { + visit_fn_arg(self, i) + } + #[cfg(feature = "full")] + fn visit_fn_decl(&mut self, i: &'ast FnDecl) { + visit_fn_decl(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { + visit_foreign_item(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_fn(&mut self, i: &'ast ForeignItemFn) { + visit_foreign_item_fn(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_macro(&mut self, i: &'ast ForeignItemMacro) { + visit_foreign_item_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_static(&mut self, i: &'ast ForeignItemStatic) { + visit_foreign_item_static(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_type(&mut self, i: &'ast ForeignItemType) { + visit_foreign_item_type(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_verbatim(&mut self, i: &'ast ForeignItemVerbatim) { + visit_foreign_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_argument(&mut self, i: &'ast GenericArgument) { + visit_generic_argument(self, i) + } + #[cfg(feature = "full")] + fn visit_generic_method_argument(&mut self, i: &'ast GenericMethodArgument) { + visit_generic_method_argument(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_param(&mut self, i: &'ast GenericParam) { + visit_generic_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generics(&mut self, i: &'ast Generics) { + visit_generics(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item(&mut self, i: &'ast ImplItem) { + visit_impl_item(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_const(&mut self, i: &'ast ImplItemConst) { + visit_impl_item_const(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_existential(&mut self, i: &'ast ImplItemExistential) { + visit_impl_item_existential(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_macro(&mut self, i: &'ast ImplItemMacro) { + visit_impl_item_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_method(&mut self, i: &'ast ImplItemMethod) { + visit_impl_item_method(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_type(&mut self, i: &'ast ImplItemType) { + visit_impl_item_type(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_verbatim(&mut self, i: &'ast ImplItemVerbatim) { + visit_impl_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_index(&mut self, i: &'ast Index) { + visit_index(self, i) + } + #[cfg(feature = "full")] + fn visit_item(&mut self, i: &'ast Item) { + visit_item(self, i) + } + #[cfg(feature = "full")] + fn visit_item_const(&mut self, i: &'ast ItemConst) { + visit_item_const(self, i) + } + #[cfg(feature = "full")] + fn visit_item_enum(&mut self, i: &'ast ItemEnum) { + visit_item_enum(self, i) + } + #[cfg(feature = "full")] + fn visit_item_existential(&mut self, i: &'ast ItemExistential) { + visit_item_existential(self, i) + } + #[cfg(feature = "full")] + fn visit_item_extern_crate(&mut self, i: &'ast ItemExternCrate) { + visit_item_extern_crate(self, i) + } + #[cfg(feature = "full")] + fn visit_item_fn(&mut self, i: &'ast ItemFn) { + visit_item_fn(self, i) + } + #[cfg(feature = "full")] + fn visit_item_foreign_mod(&mut self, i: &'ast ItemForeignMod) { + visit_item_foreign_mod(self, i) + } + #[cfg(feature = "full")] + fn visit_item_impl(&mut self, i: &'ast ItemImpl) { + visit_item_impl(self, i) + } + #[cfg(feature = "full")] + fn visit_item_macro(&mut self, i: &'ast ItemMacro) { + visit_item_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_item_macro2(&mut self, i: &'ast ItemMacro2) { + visit_item_macro2(self, i) + } + #[cfg(feature = "full")] + fn visit_item_mod(&mut self, i: &'ast ItemMod) { + visit_item_mod(self, i) + } + #[cfg(feature = "full")] + fn visit_item_static(&mut self, i: &'ast ItemStatic) { + visit_item_static(self, i) + } + #[cfg(feature = "full")] + fn visit_item_struct(&mut self, i: &'ast ItemStruct) { + visit_item_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_item_trait(&mut self, i: &'ast ItemTrait) { + visit_item_trait(self, i) + } + #[cfg(feature = "full")] + fn visit_item_trait_alias(&mut self, i: &'ast ItemTraitAlias) { + visit_item_trait_alias(self, i) + } + #[cfg(feature = "full")] + fn visit_item_type(&mut self, i: &'ast ItemType) { + visit_item_type(self, i) + } + #[cfg(feature = "full")] + fn visit_item_union(&mut self, i: &'ast ItemUnion) { + visit_item_union(self, i) + } + #[cfg(feature = "full")] + fn visit_item_use(&mut self, i: &'ast ItemUse) { + visit_item_use(self, i) + } + #[cfg(feature = "full")] + fn visit_item_verbatim(&mut self, i: &'ast ItemVerbatim) { + visit_item_verbatim(self, i) + } + #[cfg(feature = "full")] + fn visit_label(&mut self, i: &'ast Label) { + visit_label(self, i) + } + fn visit_lifetime(&mut self, i: &'ast Lifetime) { + visit_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lifetime_def(&mut self, i: &'ast LifetimeDef) { + visit_lifetime_def(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit(&mut self, i: &'ast Lit) { + visit_lit(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_bool(&mut self, i: &'ast LitBool) { + visit_lit_bool(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte(&mut self, i: &'ast LitByte) { + visit_lit_byte(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_str(&mut self, i: &'ast LitByteStr) { + visit_lit_byte_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_char(&mut self, i: &'ast LitChar) { + visit_lit_char(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_float(&mut self, i: &'ast LitFloat) { + visit_lit_float(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_int(&mut self, i: &'ast LitInt) { + visit_lit_int(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_str(&mut self, i: &'ast LitStr) { + visit_lit_str(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_verbatim(&mut self, i: &'ast LitVerbatim) { + visit_lit_verbatim(self, i) + } + #[cfg(feature = "full")] + fn visit_local(&mut self, i: &'ast Local) { + visit_local(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro(&mut self, i: &'ast Macro) { + visit_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_delimiter(&mut self, i: &'ast MacroDelimiter) { + visit_macro_delimiter(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_member(&mut self, i: &'ast Member) { + visit_member(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta(&mut self, i: &'ast Meta) { + visit_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_list(&mut self, i: &'ast MetaList) { + visit_meta_list(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_name_value(&mut self, i: &'ast MetaNameValue) { + visit_meta_name_value(self, i) + } + #[cfg(feature = "full")] + fn visit_method_sig(&mut self, i: &'ast MethodSig) { + visit_method_sig(self, i) + } + #[cfg(feature = "full")] + fn visit_method_turbofish(&mut self, i: &'ast MethodTurbofish) { + visit_method_turbofish(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_nested_meta(&mut self, i: &'ast NestedMeta) { + visit_nested_meta(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_parenthesized_generic_arguments(&mut self, i: &'ast ParenthesizedGenericArguments) { + visit_parenthesized_generic_arguments(self, i) + } + #[cfg(feature = "full")] + fn visit_pat(&mut self, i: &'ast Pat) { + visit_pat(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_box(&mut self, i: &'ast PatBox) { + visit_pat_box(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ident(&mut self, i: &'ast PatIdent) { + visit_pat_ident(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_lit(&mut self, i: &'ast PatLit) { + visit_pat_lit(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_macro(&mut self, i: &'ast PatMacro) { + visit_pat_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_path(&mut self, i: &'ast PatPath) { + visit_pat_path(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_range(&mut self, i: &'ast PatRange) { + visit_pat_range(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ref(&mut self, i: &'ast PatRef) { + visit_pat_ref(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_slice(&mut self, i: &'ast PatSlice) { + visit_pat_slice(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_struct(&mut self, i: &'ast PatStruct) { + visit_pat_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple(&mut self, i: &'ast PatTuple) { + visit_pat_tuple(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_struct(&mut self, i: &'ast PatTupleStruct) { + visit_pat_tuple_struct(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_verbatim(&mut self, i: &'ast PatVerbatim) { + visit_pat_verbatim(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_wild(&mut self, i: &'ast PatWild) { + visit_pat_wild(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path(&mut self, i: &'ast Path) { + visit_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_arguments(&mut self, i: &'ast PathArguments) { + visit_path_arguments(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_segment(&mut self, i: &'ast PathSegment) { + visit_path_segment(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_eq(&mut self, i: &'ast PredicateEq) { + visit_predicate_eq(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_lifetime(&mut self, i: &'ast PredicateLifetime) { + visit_predicate_lifetime(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_type(&mut self, i: &'ast PredicateType) { + visit_predicate_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_qself(&mut self, i: &'ast QSelf) { + visit_qself(self, i) + } + #[cfg(feature = "full")] + fn visit_range_limits(&mut self, i: &'ast RangeLimits) { + visit_range_limits(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_return_type(&mut self, i: &'ast ReturnType) { + visit_return_type(self, i) + } + #[cfg(feature = "full")] + fn visit_stmt(&mut self, i: &'ast Stmt) { + visit_stmt(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound(&mut self, i: &'ast TraitBound) { + visit_trait_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound_modifier(&mut self, i: &'ast TraitBoundModifier) { + visit_trait_bound_modifier(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item(&mut self, i: &'ast TraitItem) { + visit_trait_item(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_const(&mut self, i: &'ast TraitItemConst) { + visit_trait_item_const(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_macro(&mut self, i: &'ast TraitItemMacro) { + visit_trait_item_macro(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_method(&mut self, i: &'ast TraitItemMethod) { + visit_trait_item_method(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_type(&mut self, i: &'ast TraitItemType) { + visit_trait_item_type(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_verbatim(&mut self, i: &'ast TraitItemVerbatim) { + visit_trait_item_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type(&mut self, i: &'ast Type) { + visit_type(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_array(&mut self, i: &'ast TypeArray) { + visit_type_array(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_bare_fn(&mut self, i: &'ast TypeBareFn) { + visit_type_bare_fn(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_group(&mut self, i: &'ast TypeGroup) { + visit_type_group(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_impl_trait(&mut self, i: &'ast TypeImplTrait) { + visit_type_impl_trait(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_infer(&mut self, i: &'ast TypeInfer) { + visit_type_infer(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_macro(&mut self, i: &'ast TypeMacro) { + visit_type_macro(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_never(&mut self, i: &'ast TypeNever) { + visit_type_never(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param(&mut self, i: &'ast TypeParam) { + visit_type_param(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_bound(&mut self, i: &'ast TypeParamBound) { + visit_type_param_bound(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_paren(&mut self, i: &'ast TypeParen) { + visit_type_paren(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_path(&mut self, i: &'ast TypePath) { + visit_type_path(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_ptr(&mut self, i: &'ast TypePtr) { + visit_type_ptr(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_reference(&mut self, i: &'ast TypeReference) { + visit_type_reference(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_slice(&mut self, i: &'ast TypeSlice) { + visit_type_slice(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_trait_object(&mut self, i: &'ast TypeTraitObject) { + visit_type_trait_object(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_tuple(&mut self, i: &'ast TypeTuple) { + visit_type_tuple(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_verbatim(&mut self, i: &'ast TypeVerbatim) { + visit_type_verbatim(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_un_op(&mut self, i: &'ast UnOp) { + visit_un_op(self, i) + } + #[cfg(feature = "full")] + fn visit_use_glob(&mut self, i: &'ast UseGlob) { + visit_use_glob(self, i) + } + #[cfg(feature = "full")] + fn visit_use_group(&mut self, i: &'ast UseGroup) { + visit_use_group(self, i) + } + #[cfg(feature = "full")] + fn visit_use_name(&mut self, i: &'ast UseName) { + visit_use_name(self, i) + } + #[cfg(feature = "full")] + fn visit_use_path(&mut self, i: &'ast UsePath) { + visit_use_path(self, i) + } + #[cfg(feature = "full")] + fn visit_use_rename(&mut self, i: &'ast UseRename) { + visit_use_rename(self, i) + } + #[cfg(feature = "full")] + fn visit_use_tree(&mut self, i: &'ast UseTree) { + visit_use_tree(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_variant(&mut self, i: &'ast Variant) { + visit_variant(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_crate(&mut self, i: &'ast VisCrate) { + visit_vis_crate(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_public(&mut self, i: &'ast VisPublic) { + visit_vis_public(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_restricted(&mut self, i: &'ast VisRestricted) { + visit_vis_restricted(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_visibility(&mut self, i: &'ast Visibility) { + visit_visibility(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_clause(&mut self, i: &'ast WhereClause) { + visit_where_clause(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_predicate(&mut self, i: &'ast WherePredicate) { + visit_where_predicate(self, i) + } + fn visit_span(&mut self, i: &'ast Span) { + visit_span(self, i) + } + fn visit_ident(&mut self, i: &'ast Ident) { + visit_ident(self, i) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_abi<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Abi) { + tokens_helper(_visitor, &_i.extern_token.span); + if let Some(ref it) = _i.name { + _visitor.visit_lit_str(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_angle_bracketed_generic_arguments<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast AngleBracketedGenericArguments, +) { + if let Some(ref it) = _i.colon2_token { + tokens_helper(_visitor, &it.spans) + }; + tokens_helper(_visitor, &_i.lt_token.spans); + for el in Punctuated::pairs(&_i.args) { + let it = el.value(); + _visitor.visit_generic_argument(it) + } + tokens_helper(_visitor, &_i.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_arg_captured<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgCaptured) { + _visitor.visit_pat(&_i.pat); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&_i.ty); +} +#[cfg(feature = "full")] +pub fn visit_arg_self<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgSelf) { + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.self_token.span); +} +#[cfg(feature = "full")] +pub fn visit_arg_self_ref<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ArgSelfRef) { + tokens_helper(_visitor, &_i.and_token.spans); + if let Some(ref it) = _i.lifetime { + _visitor.visit_lifetime(it) + }; + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.self_token.span); +} +#[cfg(feature = "full")] +pub fn visit_arm<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Arm) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.leading_vert { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.pats) { + let it = el.value(); + _visitor.visit_pat(it) + } + if let Some(ref it) = _i.guard { + tokens_helper(_visitor, &(it).0.span); + _visitor.visit_expr(&*(it).1); + }; + tokens_helper(_visitor, &_i.fat_arrow_token.spans); + _visitor.visit_expr(&*_i.body); + if let Some(ref it) = _i.comma { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attr_style<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast AttrStyle) { + match *_i { + AttrStyle::Outer => {} + AttrStyle::Inner(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attribute<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Attribute) { + tokens_helper(_visitor, &_i.pound_token.spans); + _visitor.visit_attr_style(&_i.style); + tokens_helper(_visitor, &_i.bracket_token.span); + _visitor.visit_path(&_i.path); + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast BareFnArg) { + if let Some(ref it) = _i.name { + _visitor.visit_bare_fn_arg_name(&(it).0); + tokens_helper(_visitor, &(it).1.spans); + }; + _visitor.visit_type(&_i.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg_name<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast BareFnArgName, +) { + match *_i { + BareFnArgName::Named(ref _binding_0) => { + _visitor.visit_ident(_binding_0); + } + BareFnArgName::Wild(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bin_op<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast BinOp) { + match *_i { + BinOp::Add(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Sub(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Mul(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Div(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Rem(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::And(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Or(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitXor(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitAnd(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitOr(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Shl(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Shr(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Eq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Lt(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Le(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Ne(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Ge(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::Gt(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::AddEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::SubEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::MulEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::DivEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::RemEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitXorEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitAndEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::BitOrEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::ShlEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + BinOp::ShrEq(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_binding<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Binding) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_type(&_i.ty); +} +#[cfg(feature = "full")] +pub fn visit_block<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Block) { + tokens_helper(_visitor, &_i.brace_token.span); + for it in &_i.stmts { + _visitor.visit_stmt(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bound_lifetimes<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast BoundLifetimes, +) { + tokens_helper(_visitor, &_i.for_token.span); + tokens_helper(_visitor, &_i.lt_token.spans); + for el in Punctuated::pairs(&_i.lifetimes) { + let it = el.value(); + _visitor.visit_lifetime_def(it) + } + tokens_helper(_visitor, &_i.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_const_param<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ConstParam) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.const_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&_i.ty); + if let Some(ref it) = _i.eq_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.default { + _visitor.visit_expr(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_constraint<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Constraint) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } +} +#[cfg(feature = "derive")] +pub fn visit_data<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Data) { + match *_i { + Data::Struct(ref _binding_0) => { + _visitor.visit_data_struct(_binding_0); + } + Data::Enum(ref _binding_0) => { + _visitor.visit_data_enum(_binding_0); + } + Data::Union(ref _binding_0) => { + _visitor.visit_data_union(_binding_0); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_enum<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataEnum) { + tokens_helper(_visitor, &_i.enum_token.span); + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.variants) { + let it = el.value(); + _visitor.visit_variant(it) + } +} +#[cfg(feature = "derive")] +pub fn visit_data_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataStruct) { + tokens_helper(_visitor, &_i.struct_token.span); + _visitor.visit_fields(&_i.fields); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "derive")] +pub fn visit_data_union<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DataUnion) { + tokens_helper(_visitor, &_i.union_token.span); + _visitor.visit_fields_named(&_i.fields); +} +#[cfg(feature = "derive")] +pub fn visit_derive_input<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast DeriveInput) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + _visitor.visit_data(&_i.data); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Expr) { + match *_i { + Expr::Box(ref _binding_0) => { + full!(_visitor.visit_expr_box(_binding_0)); + } + Expr::InPlace(ref _binding_0) => { + full!(_visitor.visit_expr_in_place(_binding_0)); + } + Expr::Array(ref _binding_0) => { + full!(_visitor.visit_expr_array(_binding_0)); + } + Expr::Call(ref _binding_0) => { + _visitor.visit_expr_call(_binding_0); + } + Expr::MethodCall(ref _binding_0) => { + full!(_visitor.visit_expr_method_call(_binding_0)); + } + Expr::Tuple(ref _binding_0) => { + full!(_visitor.visit_expr_tuple(_binding_0)); + } + Expr::Binary(ref _binding_0) => { + _visitor.visit_expr_binary(_binding_0); + } + Expr::Unary(ref _binding_0) => { + _visitor.visit_expr_unary(_binding_0); + } + Expr::Lit(ref _binding_0) => { + _visitor.visit_expr_lit(_binding_0); + } + Expr::Cast(ref _binding_0) => { + _visitor.visit_expr_cast(_binding_0); + } + Expr::Type(ref _binding_0) => { + full!(_visitor.visit_expr_type(_binding_0)); + } + Expr::Let(ref _binding_0) => { + full!(_visitor.visit_expr_let(_binding_0)); + } + Expr::If(ref _binding_0) => { + full!(_visitor.visit_expr_if(_binding_0)); + } + Expr::While(ref _binding_0) => { + full!(_visitor.visit_expr_while(_binding_0)); + } + Expr::ForLoop(ref _binding_0) => { + full!(_visitor.visit_expr_for_loop(_binding_0)); + } + Expr::Loop(ref _binding_0) => { + full!(_visitor.visit_expr_loop(_binding_0)); + } + Expr::Match(ref _binding_0) => { + full!(_visitor.visit_expr_match(_binding_0)); + } + Expr::Closure(ref _binding_0) => { + full!(_visitor.visit_expr_closure(_binding_0)); + } + Expr::Unsafe(ref _binding_0) => { + full!(_visitor.visit_expr_unsafe(_binding_0)); + } + Expr::Block(ref _binding_0) => { + full!(_visitor.visit_expr_block(_binding_0)); + } + Expr::Assign(ref _binding_0) => { + full!(_visitor.visit_expr_assign(_binding_0)); + } + Expr::AssignOp(ref _binding_0) => { + full!(_visitor.visit_expr_assign_op(_binding_0)); + } + Expr::Field(ref _binding_0) => { + _visitor.visit_expr_field(_binding_0); + } + Expr::Index(ref _binding_0) => { + _visitor.visit_expr_index(_binding_0); + } + Expr::Range(ref _binding_0) => { + full!(_visitor.visit_expr_range(_binding_0)); + } + Expr::Path(ref _binding_0) => { + _visitor.visit_expr_path(_binding_0); + } + Expr::Reference(ref _binding_0) => { + full!(_visitor.visit_expr_reference(_binding_0)); + } + Expr::Break(ref _binding_0) => { + full!(_visitor.visit_expr_break(_binding_0)); + } + Expr::Continue(ref _binding_0) => { + full!(_visitor.visit_expr_continue(_binding_0)); + } + Expr::Return(ref _binding_0) => { + full!(_visitor.visit_expr_return(_binding_0)); + } + Expr::Macro(ref _binding_0) => { + full!(_visitor.visit_expr_macro(_binding_0)); + } + Expr::Struct(ref _binding_0) => { + full!(_visitor.visit_expr_struct(_binding_0)); + } + Expr::Repeat(ref _binding_0) => { + full!(_visitor.visit_expr_repeat(_binding_0)); + } + Expr::Paren(ref _binding_0) => { + _visitor.visit_expr_paren(_binding_0); + } + Expr::Group(ref _binding_0) => { + full!(_visitor.visit_expr_group(_binding_0)); + } + Expr::Try(ref _binding_0) => { + full!(_visitor.visit_expr_try(_binding_0)); + } + Expr::Async(ref _binding_0) => { + full!(_visitor.visit_expr_async(_binding_0)); + } + Expr::TryBlock(ref _binding_0) => { + full!(_visitor.visit_expr_try_block(_binding_0)); + } + Expr::Yield(ref _binding_0) => { + full!(_visitor.visit_expr_yield(_binding_0)); + } + Expr::Verbatim(ref _binding_0) => { + _visitor.visit_expr_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_array<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprArray) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.bracket_token.span); + for el in Punctuated::pairs(&_i.elems) { + let it = el.value(); + _visitor.visit_expr(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_assign<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprAssign) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.left); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_expr(&*_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_op<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprAssignOp, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.left); + _visitor.visit_bin_op(&_i.op); + _visitor.visit_expr(&*_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_async<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprAsync) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.async_token.span); + if let Some(ref it) = _i.capture { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_block(&_i.block); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_binary<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBinary) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.left); + _visitor.visit_bin_op(&_i.op); + _visitor.visit_expr(&*_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_block<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBlock) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.label { + _visitor.visit_label(it) + }; + _visitor.visit_block(&_i.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_box<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBox) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.box_token.span); + _visitor.visit_expr(&*_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_break<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprBreak) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.break_token.span); + if let Some(ref it) = _i.label { + _visitor.visit_lifetime(it) + }; + if let Some(ref it) = _i.expr { + _visitor.visit_expr(&**it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_call<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprCall) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.func); + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.args) { + let it = el.value(); + _visitor.visit_expr(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_cast<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprCast) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.as_token.span); + _visitor.visit_type(&*_i.ty); +} +#[cfg(feature = "full")] +pub fn visit_expr_closure<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprClosure) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.asyncness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.movability { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.capture { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.or1_token.spans); + for el in Punctuated::pairs(&_i.inputs) { + let it = el.value(); + _visitor.visit_fn_arg(it) + } + tokens_helper(_visitor, &_i.or2_token.spans); + _visitor.visit_return_type(&_i.output); + _visitor.visit_expr(&*_i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_continue<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprContinue, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.continue_token.span); + if let Some(ref it) = _i.label { + _visitor.visit_lifetime(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_field<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprField) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.base); + tokens_helper(_visitor, &_i.dot_token.spans); + _visitor.visit_member(&_i.member); +} +#[cfg(feature = "full")] +pub fn visit_expr_for_loop<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprForLoop) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.label { + _visitor.visit_label(it) + }; + tokens_helper(_visitor, &_i.for_token.span); + _visitor.visit_pat(&*_i.pat); + tokens_helper(_visitor, &_i.in_token.span); + _visitor.visit_expr(&*_i.expr); + _visitor.visit_block(&_i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprGroup) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.group_token.span); + _visitor.visit_expr(&*_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_if<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIf) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.if_token.span); + _visitor.visit_expr(&*_i.cond); + _visitor.visit_block(&_i.then_branch); + if let Some(ref it) = _i.else_branch { + tokens_helper(_visitor, &(it).0.span); + _visitor.visit_expr(&*(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_in_place<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprInPlace) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.place); + tokens_helper(_visitor, &_i.arrow_token.spans); + _visitor.visit_expr(&*_i.value); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_index<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprIndex) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.bracket_token.span); + _visitor.visit_expr(&*_i.index); +} +#[cfg(feature = "full")] +pub fn visit_expr_let<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLet) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.let_token.span); + for el in Punctuated::pairs(&_i.pats) { + let it = el.value(); + _visitor.visit_pat(it) + } + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_expr(&*_i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLit) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_lit(&_i.lit); +} +#[cfg(feature = "full")] +pub fn visit_expr_loop<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprLoop) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.label { + _visitor.visit_label(it) + }; + tokens_helper(_visitor, &_i.loop_token.span); + _visitor.visit_block(&_i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprMacro) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_macro(&_i.mac); +} +#[cfg(feature = "full")] +pub fn visit_expr_match<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprMatch) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.match_token.span); + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.brace_token.span); + for it in &_i.arms { + _visitor.visit_arm(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_method_call<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprMethodCall, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.receiver); + tokens_helper(_visitor, &_i.dot_token.spans); + _visitor.visit_ident(&_i.method); + if let Some(ref it) = _i.turbofish { + _visitor.visit_method_turbofish(it) + }; + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.args) { + let it = el.value(); + _visitor.visit_expr(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_paren<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprParen) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.paren_token.span); + _visitor.visit_expr(&*_i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprPath) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.qself { + _visitor.visit_qself(it) + }; + _visitor.visit_path(&_i.path); +} +#[cfg(feature = "full")] +pub fn visit_expr_range<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprRange) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.from { + _visitor.visit_expr(&**it) + }; + _visitor.visit_range_limits(&_i.limits); + if let Some(ref it) = _i.to { + _visitor.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_reference<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprReference, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.and_token.spans); + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_expr(&*_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_repeat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprRepeat) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.bracket_token.span); + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.semi_token.spans); + _visitor.visit_expr(&*_i.len); +} +#[cfg(feature = "full")] +pub fn visit_expr_return<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprReturn) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.return_token.span); + if let Some(ref it) = _i.expr { + _visitor.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprStruct) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_path(&_i.path); + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.fields) { + let it = el.value(); + _visitor.visit_field_value(it) + } + if let Some(ref it) = _i.dot2_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.rest { + _visitor.visit_expr(&**it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_try<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprTry) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.question_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_expr_try_block<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprTryBlock, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.try_token.span); + _visitor.visit_block(&_i.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprTuple) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.elems) { + let it = el.value(); + _visitor.visit_expr(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprType) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&*_i.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_unary<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprUnary) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_un_op(&_i.op); + _visitor.visit_expr(&*_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_unsafe<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprUnsafe) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.unsafe_token.span); + _visitor.visit_block(&_i.block); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ExprVerbatim, +) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_expr_while<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprWhile) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.label { + _visitor.visit_label(it) + }; + tokens_helper(_visitor, &_i.while_token.span); + _visitor.visit_expr(&*_i.cond); + _visitor.visit_block(&_i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_yield<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ExprYield) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.yield_token.span); + if let Some(ref it) = _i.expr { + _visitor.visit_expr(&**it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_field<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Field) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.ident { + _visitor.visit_ident(it) + }; + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_type(&_i.ty); +} +#[cfg(feature = "full")] +pub fn visit_field_pat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldPat) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_member(&_i.member); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_pat(&*_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_field_value<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldValue) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_member(&_i.member); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_expr(&_i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Fields) { + match *_i { + Fields::Named(ref _binding_0) => { + _visitor.visit_fields_named(_binding_0); + } + Fields::Unnamed(ref _binding_0) => { + _visitor.visit_fields_unnamed(_binding_0); + } + Fields::Unit => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_named<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FieldsNamed) { + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.named) { + let it = el.value(); + _visitor.visit_field(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_unnamed<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast FieldsUnnamed, +) { + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.unnamed) { + let it = el.value(); + _visitor.visit_field(it) + } +} +#[cfg(feature = "full")] +pub fn visit_file<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast File) { + skip!(_i.shebang); + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + for it in &_i.items { + _visitor.visit_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_fn_arg<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FnArg) { + match *_i { + FnArg::SelfRef(ref _binding_0) => { + _visitor.visit_arg_self_ref(_binding_0); + } + FnArg::SelfValue(ref _binding_0) => { + _visitor.visit_arg_self(_binding_0); + } + FnArg::Captured(ref _binding_0) => { + _visitor.visit_arg_captured(_binding_0); + } + FnArg::Inferred(ref _binding_0) => { + _visitor.visit_pat(_binding_0); + } + FnArg::Ignored(ref _binding_0) => { + _visitor.visit_type(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_fn_decl<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast FnDecl) { + tokens_helper(_visitor, &_i.fn_token.span); + _visitor.visit_generics(&_i.generics); + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.inputs) { + let it = el.value(); + _visitor.visit_fn_arg(it) + } + if let Some(ref it) = _i.variadic { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_return_type(&_i.output); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ForeignItem) { + match *_i { + ForeignItem::Fn(ref _binding_0) => { + _visitor.visit_foreign_item_fn(_binding_0); + } + ForeignItem::Static(ref _binding_0) => { + _visitor.visit_foreign_item_static(_binding_0); + } + ForeignItem::Type(ref _binding_0) => { + _visitor.visit_foreign_item_type(_binding_0); + } + ForeignItem::Macro(ref _binding_0) => { + _visitor.visit_foreign_item_macro(_binding_0); + } + ForeignItem::Verbatim(ref _binding_0) => { + _visitor.visit_foreign_item_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_fn<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ForeignItemFn, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + _visitor.visit_ident(&_i.ident); + _visitor.visit_fn_decl(&*_i.decl); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_macro<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ForeignItemMacro, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_macro(&_i.mac); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_static<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ForeignItemStatic, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.static_token.span); + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&*_i.ty); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_type<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ForeignItemType, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ForeignItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_argument<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast GenericArgument, +) { + match *_i { + GenericArgument::Lifetime(ref _binding_0) => { + _visitor.visit_lifetime(_binding_0); + } + GenericArgument::Type(ref _binding_0) => { + _visitor.visit_type(_binding_0); + } + GenericArgument::Binding(ref _binding_0) => { + _visitor.visit_binding(_binding_0); + } + GenericArgument::Constraint(ref _binding_0) => { + _visitor.visit_constraint(_binding_0); + } + GenericArgument::Const(ref _binding_0) => { + _visitor.visit_expr(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_generic_method_argument<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast GenericMethodArgument, +) { + match *_i { + GenericMethodArgument::Type(ref _binding_0) => { + _visitor.visit_type(_binding_0); + } + GenericMethodArgument::Const(ref _binding_0) => { + _visitor.visit_expr(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_param<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast GenericParam, +) { + match *_i { + GenericParam::Type(ref _binding_0) => { + _visitor.visit_type_param(_binding_0); + } + GenericParam::Lifetime(ref _binding_0) => { + _visitor.visit_lifetime_def(_binding_0); + } + GenericParam::Const(ref _binding_0) => { + _visitor.visit_const_param(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generics<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Generics) { + if let Some(ref it) = _i.lt_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.params) { + let it = el.value(); + _visitor.visit_generic_param(it) + } + if let Some(ref it) = _i.gt_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.where_clause { + _visitor.visit_where_clause(it) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ImplItem) { + match *_i { + ImplItem::Const(ref _binding_0) => { + _visitor.visit_impl_item_const(_binding_0); + } + ImplItem::Method(ref _binding_0) => { + _visitor.visit_impl_item_method(_binding_0); + } + ImplItem::Type(ref _binding_0) => { + _visitor.visit_impl_item_type(_binding_0); + } + ImplItem::Existential(ref _binding_0) => { + _visitor.visit_impl_item_existential(_binding_0); + } + ImplItem::Macro(ref _binding_0) => { + _visitor.visit_impl_item_macro(_binding_0); + } + ImplItem::Verbatim(ref _binding_0) => { + _visitor.visit_impl_item_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_impl_item_const<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemConst, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.defaultness { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.const_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&_i.ty); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_expr(&_i.expr); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_existential<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemExistential, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.existential_token.span); + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_macro<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemMacro, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_macro(&_i.mac); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item_method<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemMethod, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.defaultness { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_method_sig(&_i.sig); + _visitor.visit_block(&_i.block); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_type<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemType, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.defaultness { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_type(&_i.ty); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ImplItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_index<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Index) { + skip!(_i.index); + _visitor.visit_span(&_i.span); +} +#[cfg(feature = "full")] +pub fn visit_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Item) { + match *_i { + Item::ExternCrate(ref _binding_0) => { + _visitor.visit_item_extern_crate(_binding_0); + } + Item::Use(ref _binding_0) => { + _visitor.visit_item_use(_binding_0); + } + Item::Static(ref _binding_0) => { + _visitor.visit_item_static(_binding_0); + } + Item::Const(ref _binding_0) => { + _visitor.visit_item_const(_binding_0); + } + Item::Fn(ref _binding_0) => { + _visitor.visit_item_fn(_binding_0); + } + Item::Mod(ref _binding_0) => { + _visitor.visit_item_mod(_binding_0); + } + Item::ForeignMod(ref _binding_0) => { + _visitor.visit_item_foreign_mod(_binding_0); + } + Item::Type(ref _binding_0) => { + _visitor.visit_item_type(_binding_0); + } + Item::Existential(ref _binding_0) => { + _visitor.visit_item_existential(_binding_0); + } + Item::Struct(ref _binding_0) => { + _visitor.visit_item_struct(_binding_0); + } + Item::Enum(ref _binding_0) => { + _visitor.visit_item_enum(_binding_0); + } + Item::Union(ref _binding_0) => { + _visitor.visit_item_union(_binding_0); + } + Item::Trait(ref _binding_0) => { + _visitor.visit_item_trait(_binding_0); + } + Item::TraitAlias(ref _binding_0) => { + _visitor.visit_item_trait_alias(_binding_0); + } + Item::Impl(ref _binding_0) => { + _visitor.visit_item_impl(_binding_0); + } + Item::Macro(ref _binding_0) => { + _visitor.visit_item_macro(_binding_0); + } + Item::Macro2(ref _binding_0) => { + _visitor.visit_item_macro2(_binding_0); + } + Item::Verbatim(ref _binding_0) => { + _visitor.visit_item_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_item_const<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemConst) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.const_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&*_i.ty); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_enum<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemEnum) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.enum_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.variants) { + let it = el.value(); + _visitor.visit_variant(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_existential<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ItemExistential, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.existential_token.span); + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_extern_crate<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ItemExternCrate, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.extern_token.span); + tokens_helper(_visitor, &_i.crate_token.span); + _visitor.visit_ident(&_i.ident); + if let Some(ref it) = _i.rename { + tokens_helper(_visitor, &(it).0.span); + _visitor.visit_ident(&(it).1); + }; + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_fn<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemFn) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.constness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.unsafety { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.asyncness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.abi { + _visitor.visit_abi(it) + }; + _visitor.visit_ident(&_i.ident); + _visitor.visit_fn_decl(&*_i.decl); + _visitor.visit_block(&*_i.block); +} +#[cfg(feature = "full")] +pub fn visit_item_foreign_mod<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ItemForeignMod, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_abi(&_i.abi); + tokens_helper(_visitor, &_i.brace_token.span); + for it in &_i.items { + _visitor.visit_foreign_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_impl<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemImpl) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.defaultness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.unsafety { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.impl_token.span); + _visitor.visit_generics(&_i.generics); + if let Some(ref it) = _i.trait_ { + if let Some(ref it) = (it).0 { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_path(&(it).1); + tokens_helper(_visitor, &(it).2.span); + }; + _visitor.visit_type(&*_i.self_ty); + tokens_helper(_visitor, &_i.brace_token.span); + for it in &_i.items { + _visitor.visit_impl_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMacro) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + if let Some(ref it) = _i.ident { + _visitor.visit_ident(it) + }; + _visitor.visit_macro(&_i.mac); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_macro2<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMacro2) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.macro_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.paren_token.span); + skip!(_i.args); + tokens_helper(_visitor, &_i.brace_token.span); + skip!(_i.body); +} +#[cfg(feature = "full")] +pub fn visit_item_mod<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemMod) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.mod_token.span); + _visitor.visit_ident(&_i.ident); + if let Some(ref it) = _i.content { + tokens_helper(_visitor, &(it).0.span); + for it in &(it).1 { + _visitor.visit_item(it) + } + }; + if let Some(ref it) = _i.semi { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_static<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemStatic) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.static_token.span); + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&*_i.ty); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_expr(&*_i.expr); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemStruct) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.struct_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + _visitor.visit_fields(&_i.fields); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_trait<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemTrait) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + if let Some(ref it) = _i.unsafety { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.auto_token { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.trait_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.supertraits) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + tokens_helper(_visitor, &_i.brace_token.span); + for it in &_i.items { + _visitor.visit_trait_item(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_trait_alias<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ItemTraitAlias, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.trait_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + tokens_helper(_visitor, &_i.eq_token.spans); + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemType) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_type(&*_i.ty); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_union<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemUnion) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.union_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + _visitor.visit_fields_named(&_i.fields); +} +#[cfg(feature = "full")] +pub fn visit_item_use<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ItemUse) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_visibility(&_i.vis); + tokens_helper(_visitor, &_i.use_token.span); + if let Some(ref it) = _i.leading_colon { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_use_tree(&_i.tree); + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_label<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Label) { + _visitor.visit_lifetime(&_i.name); + tokens_helper(_visitor, &_i.colon_token.spans); +} +pub fn visit_lifetime<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Lifetime) { + _visitor.visit_span(&_i.apostrophe); + _visitor.visit_ident(&_i.ident); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lifetime_def<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LifetimeDef) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_lifetime(&_i.lifetime); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_lifetime(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Lit) { + match *_i { + Lit::Str(ref _binding_0) => { + _visitor.visit_lit_str(_binding_0); + } + Lit::ByteStr(ref _binding_0) => { + _visitor.visit_lit_byte_str(_binding_0); + } + Lit::Byte(ref _binding_0) => { + _visitor.visit_lit_byte(_binding_0); + } + Lit::Char(ref _binding_0) => { + _visitor.visit_lit_char(_binding_0); + } + Lit::Int(ref _binding_0) => { + _visitor.visit_lit_int(_binding_0); + } + Lit::Float(ref _binding_0) => { + _visitor.visit_lit_float(_binding_0); + } + Lit::Bool(ref _binding_0) => { + _visitor.visit_lit_bool(_binding_0); + } + Lit::Verbatim(ref _binding_0) => { + _visitor.visit_lit_verbatim(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_bool<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitBool) { + skip!(_i.value); + _visitor.visit_span(&_i.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitByte) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_str<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitByteStr) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_char<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitChar) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_float<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitFloat) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_int<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitInt) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_str<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitStr) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_verbatim<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast LitVerbatim) { + skip!(_i.token); +} +#[cfg(feature = "full")] +pub fn visit_local<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Local) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.let_token.span); + for el in Punctuated::pairs(&_i.pats) { + let it = el.value(); + _visitor.visit_pat(it) + } + if let Some(ref it) = _i.ty { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_type(&*(it).1); + }; + if let Some(ref it) = _i.init { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_expr(&*(it).1); + }; + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Macro) { + _visitor.visit_path(&_i.path); + tokens_helper(_visitor, &_i.bang_token.spans); + _visitor.visit_macro_delimiter(&_i.delimiter); + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_delimiter<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast MacroDelimiter, +) { + match *_i { + MacroDelimiter::Paren(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.span); + } + MacroDelimiter::Brace(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.span); + } + MacroDelimiter::Bracket(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.span); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_member<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Member) { + match *_i { + Member::Named(ref _binding_0) => { + _visitor.visit_ident(_binding_0); + } + Member::Unnamed(ref _binding_0) => { + _visitor.visit_index(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Meta) { + match *_i { + Meta::Word(ref _binding_0) => { + _visitor.visit_ident(_binding_0); + } + Meta::List(ref _binding_0) => { + _visitor.visit_meta_list(_binding_0); + } + Meta::NameValue(ref _binding_0) => { + _visitor.visit_meta_name_value(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_list<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast MetaList) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.nested) { + let it = el.value(); + _visitor.visit_nested_meta(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_name_value<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast MetaNameValue, +) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_lit(&_i.lit); +} +#[cfg(feature = "full")] +pub fn visit_method_sig<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast MethodSig) { + if let Some(ref it) = _i.constness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.unsafety { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.asyncness { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.abi { + _visitor.visit_abi(it) + }; + _visitor.visit_ident(&_i.ident); + _visitor.visit_fn_decl(&_i.decl); +} +#[cfg(feature = "full")] +pub fn visit_method_turbofish<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast MethodTurbofish, +) { + tokens_helper(_visitor, &_i.colon2_token.spans); + tokens_helper(_visitor, &_i.lt_token.spans); + for el in Punctuated::pairs(&_i.args) { + let it = el.value(); + _visitor.visit_generic_method_argument(it) + } + tokens_helper(_visitor, &_i.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_nested_meta<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast NestedMeta) { + match *_i { + NestedMeta::Meta(ref _binding_0) => { + _visitor.visit_meta(_binding_0); + } + NestedMeta::Literal(ref _binding_0) => { + _visitor.visit_lit(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_parenthesized_generic_arguments<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast ParenthesizedGenericArguments, +) { + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.inputs) { + let it = el.value(); + _visitor.visit_type(it) + } + _visitor.visit_return_type(&_i.output); +} +#[cfg(feature = "full")] +pub fn visit_pat<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Pat) { + match *_i { + Pat::Wild(ref _binding_0) => { + _visitor.visit_pat_wild(_binding_0); + } + Pat::Ident(ref _binding_0) => { + _visitor.visit_pat_ident(_binding_0); + } + Pat::Struct(ref _binding_0) => { + _visitor.visit_pat_struct(_binding_0); + } + Pat::TupleStruct(ref _binding_0) => { + _visitor.visit_pat_tuple_struct(_binding_0); + } + Pat::Path(ref _binding_0) => { + _visitor.visit_pat_path(_binding_0); + } + Pat::Tuple(ref _binding_0) => { + _visitor.visit_pat_tuple(_binding_0); + } + Pat::Box(ref _binding_0) => { + _visitor.visit_pat_box(_binding_0); + } + Pat::Ref(ref _binding_0) => { + _visitor.visit_pat_ref(_binding_0); + } + Pat::Lit(ref _binding_0) => { + _visitor.visit_pat_lit(_binding_0); + } + Pat::Range(ref _binding_0) => { + _visitor.visit_pat_range(_binding_0); + } + Pat::Slice(ref _binding_0) => { + _visitor.visit_pat_slice(_binding_0); + } + Pat::Macro(ref _binding_0) => { + _visitor.visit_pat_macro(_binding_0); + } + Pat::Verbatim(ref _binding_0) => { + _visitor.visit_pat_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_box<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatBox) { + tokens_helper(_visitor, &_i.box_token.span); + _visitor.visit_pat(&*_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_ident<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatIdent) { + if let Some(ref it) = _i.by_ref { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_ident(&_i.ident); + if let Some(ref it) = _i.subpat { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_pat(&*(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_lit<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatLit) { + _visitor.visit_expr(&*_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_pat_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatMacro) { + _visitor.visit_macro(&_i.mac); +} +#[cfg(feature = "full")] +pub fn visit_pat_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatPath) { + if let Some(ref it) = _i.qself { + _visitor.visit_qself(it) + }; + _visitor.visit_path(&_i.path); +} +#[cfg(feature = "full")] +pub fn visit_pat_range<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatRange) { + _visitor.visit_expr(&*_i.lo); + _visitor.visit_range_limits(&_i.limits); + _visitor.visit_expr(&*_i.hi); +} +#[cfg(feature = "full")] +pub fn visit_pat_ref<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatRef) { + tokens_helper(_visitor, &_i.and_token.spans); + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_pat(&*_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_slice<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatSlice) { + tokens_helper(_visitor, &_i.bracket_token.span); + for el in Punctuated::pairs(&_i.front) { + let it = el.value(); + _visitor.visit_pat(it) + } + if let Some(ref it) = _i.middle { + _visitor.visit_pat(&**it) + }; + if let Some(ref it) = _i.dot2_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.comma_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.back) { + let it = el.value(); + _visitor.visit_pat(it) + } +} +#[cfg(feature = "full")] +pub fn visit_pat_struct<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatStruct) { + _visitor.visit_path(&_i.path); + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.fields) { + let it = el.value(); + _visitor.visit_field_pat(it) + } + if let Some(ref it) = _i.dot2_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatTuple) { + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.front) { + let it = el.value(); + _visitor.visit_pat(it) + } + if let Some(ref it) = _i.dot2_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.comma_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.back) { + let it = el.value(); + _visitor.visit_pat(it) + } +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_struct<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast PatTupleStruct, +) { + _visitor.visit_path(&_i.path); + _visitor.visit_pat_tuple(&_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_verbatim<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatVerbatim) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_pat_wild<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PatWild) { + tokens_helper(_visitor, &_i.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Path) { + if let Some(ref it) = _i.leading_colon { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.segments) { + let it = el.value(); + _visitor.visit_path_segment(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_arguments<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast PathArguments, +) { + match *_i { + PathArguments::None => {} + PathArguments::AngleBracketed(ref _binding_0) => { + _visitor.visit_angle_bracketed_generic_arguments(_binding_0); + } + PathArguments::Parenthesized(ref _binding_0) => { + _visitor.visit_parenthesized_generic_arguments(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_segment<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PathSegment) { + _visitor.visit_ident(&_i.ident); + _visitor.visit_path_arguments(&_i.arguments); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_eq<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast PredicateEq) { + _visitor.visit_type(&_i.lhs_ty); + tokens_helper(_visitor, &_i.eq_token.spans); + _visitor.visit_type(&_i.rhs_ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_lifetime<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast PredicateLifetime, +) { + _visitor.visit_lifetime(&_i.lifetime); + tokens_helper(_visitor, &_i.colon_token.spans); + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_lifetime(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_type<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast PredicateType, +) { + if let Some(ref it) = _i.lifetimes { + _visitor.visit_bound_lifetimes(it) + }; + _visitor.visit_type(&_i.bounded_ty); + tokens_helper(_visitor, &_i.colon_token.spans); + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_qself<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast QSelf) { + tokens_helper(_visitor, &_i.lt_token.spans); + _visitor.visit_type(&*_i.ty); + skip!(_i.position); + if let Some(ref it) = _i.as_token { + tokens_helper(_visitor, &it.span) + }; + tokens_helper(_visitor, &_i.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_range_limits<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast RangeLimits) { + match *_i { + RangeLimits::HalfOpen(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + RangeLimits::Closed(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_return_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast ReturnType) { + match *_i { + ReturnType::Default => {} + ReturnType::Type(ref _binding_0, ref _binding_1) => { + tokens_helper(_visitor, &_binding_0.spans); + _visitor.visit_type(&**_binding_1); + } + } +} +#[cfg(feature = "full")] +pub fn visit_stmt<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Stmt) { + match *_i { + Stmt::Local(ref _binding_0) => { + _visitor.visit_local(_binding_0); + } + Stmt::Item(ref _binding_0) => { + _visitor.visit_item(_binding_0); + } + Stmt::Expr(ref _binding_0) => { + _visitor.visit_expr(_binding_0); + } + Stmt::Semi(ref _binding_0, ref _binding_1) => { + _visitor.visit_expr(_binding_0); + tokens_helper(_visitor, &_binding_1.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TraitBound) { + if let Some(ref it) = _i.paren_token { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_trait_bound_modifier(&_i.modifier); + if let Some(ref it) = _i.lifetimes { + _visitor.visit_bound_lifetimes(it) + }; + _visitor.visit_path(&_i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_modifier<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitBoundModifier, +) { + match *_i { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TraitItem) { + match *_i { + TraitItem::Const(ref _binding_0) => { + _visitor.visit_trait_item_const(_binding_0); + } + TraitItem::Method(ref _binding_0) => { + _visitor.visit_trait_item_method(_binding_0); + } + TraitItem::Type(ref _binding_0) => { + _visitor.visit_trait_item_type(_binding_0); + } + TraitItem::Macro(ref _binding_0) => { + _visitor.visit_trait_item_macro(_binding_0); + } + TraitItem::Verbatim(ref _binding_0) => { + _visitor.visit_trait_item_verbatim(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_const<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitItemConst, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.const_token.span); + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon_token.spans); + _visitor.visit_type(&_i.ty); + if let Some(ref it) = _i.default { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_expr(&(it).1); + }; + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_macro<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitItemMacro, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_macro(&_i.mac); + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_method<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitItemMethod, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_method_sig(&_i.sig); + if let Some(ref it) = _i.default { + _visitor.visit_block(it) + }; + if let Some(ref it) = _i.semi_token { + tokens_helper(_visitor, &it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_type<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitItemType, +) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + tokens_helper(_visitor, &_i.type_token.span); + _visitor.visit_ident(&_i.ident); + _visitor.visit_generics(&_i.generics); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + if let Some(ref it) = _i.default { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_type(&(it).1); + }; + tokens_helper(_visitor, &_i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TraitItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Type) { + match *_i { + Type::Slice(ref _binding_0) => { + _visitor.visit_type_slice(_binding_0); + } + Type::Array(ref _binding_0) => { + _visitor.visit_type_array(_binding_0); + } + Type::Ptr(ref _binding_0) => { + _visitor.visit_type_ptr(_binding_0); + } + Type::Reference(ref _binding_0) => { + _visitor.visit_type_reference(_binding_0); + } + Type::BareFn(ref _binding_0) => { + _visitor.visit_type_bare_fn(_binding_0); + } + Type::Never(ref _binding_0) => { + _visitor.visit_type_never(_binding_0); + } + Type::Tuple(ref _binding_0) => { + _visitor.visit_type_tuple(_binding_0); + } + Type::Path(ref _binding_0) => { + _visitor.visit_type_path(_binding_0); + } + Type::TraitObject(ref _binding_0) => { + _visitor.visit_type_trait_object(_binding_0); + } + Type::ImplTrait(ref _binding_0) => { + _visitor.visit_type_impl_trait(_binding_0); + } + Type::Paren(ref _binding_0) => { + _visitor.visit_type_paren(_binding_0); + } + Type::Group(ref _binding_0) => { + _visitor.visit_type_group(_binding_0); + } + Type::Infer(ref _binding_0) => { + _visitor.visit_type_infer(_binding_0); + } + Type::Macro(ref _binding_0) => { + _visitor.visit_type_macro(_binding_0); + } + Type::Verbatim(ref _binding_0) => { + _visitor.visit_type_verbatim(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_array<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeArray) { + tokens_helper(_visitor, &_i.bracket_token.span); + _visitor.visit_type(&*_i.elem); + tokens_helper(_visitor, &_i.semi_token.spans); + _visitor.visit_expr(&_i.len); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_bare_fn<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeBareFn) { + if let Some(ref it) = _i.lifetimes { + _visitor.visit_bound_lifetimes(it) + }; + if let Some(ref it) = _i.unsafety { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.abi { + _visitor.visit_abi(it) + }; + tokens_helper(_visitor, &_i.fn_token.span); + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.inputs) { + let it = el.value(); + _visitor.visit_bare_fn_arg(it) + } + if let Some(ref it) = _i.variadic { + tokens_helper(_visitor, &it.spans) + }; + _visitor.visit_return_type(&_i.output); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeGroup) { + tokens_helper(_visitor, &_i.group_token.span); + _visitor.visit_type(&*_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_impl_trait<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TypeImplTrait, +) { + tokens_helper(_visitor, &_i.impl_token.span); + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_infer<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeInfer) { + tokens_helper(_visitor, &_i.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_macro<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeMacro) { + _visitor.visit_macro(&_i.mac); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_never<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeNever) { + tokens_helper(_visitor, &_i.bang_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeParam) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_ident(&_i.ident); + if let Some(ref it) = _i.colon_token { + tokens_helper(_visitor, &it.spans) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } + if let Some(ref it) = _i.eq_token { + tokens_helper(_visitor, &it.spans) + }; + if let Some(ref it) = _i.default { + _visitor.visit_type(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_bound<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TypeParamBound, +) { + match *_i { + TypeParamBound::Trait(ref _binding_0) => { + _visitor.visit_trait_bound(_binding_0); + } + TypeParamBound::Lifetime(ref _binding_0) => { + _visitor.visit_lifetime(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_paren<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeParen) { + tokens_helper(_visitor, &_i.paren_token.span); + _visitor.visit_type(&*_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypePath) { + if let Some(ref it) = _i.qself { + _visitor.visit_qself(it) + }; + _visitor.visit_path(&_i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_ptr<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypePtr) { + tokens_helper(_visitor, &_i.star_token.spans); + if let Some(ref it) = _i.const_token { + tokens_helper(_visitor, &it.span) + }; + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_type(&*_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_reference<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TypeReference, +) { + tokens_helper(_visitor, &_i.and_token.spans); + if let Some(ref it) = _i.lifetime { + _visitor.visit_lifetime(it) + }; + if let Some(ref it) = _i.mutability { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_type(&*_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_slice<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeSlice) { + tokens_helper(_visitor, &_i.bracket_token.span); + _visitor.visit_type(&*_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_trait_object<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TypeTraitObject, +) { + if let Some(ref it) = _i.dyn_token { + tokens_helper(_visitor, &it.span) + }; + for el in Punctuated::pairs(&_i.bounds) { + let it = el.value(); + _visitor.visit_type_param_bound(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_tuple<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast TypeTuple) { + tokens_helper(_visitor, &_i.paren_token.span); + for el in Punctuated::pairs(&_i.elems) { + let it = el.value(); + _visitor.visit_type(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_verbatim<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast TypeVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_un_op<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UnOp) { + match *_i { + UnOp::Deref(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + UnOp::Not(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + UnOp::Neg(ref _binding_0) => { + tokens_helper(_visitor, &_binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_glob<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseGlob) { + tokens_helper(_visitor, &_i.star_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_use_group<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseGroup) { + tokens_helper(_visitor, &_i.brace_token.span); + for el in Punctuated::pairs(&_i.items) { + let it = el.value(); + _visitor.visit_use_tree(it) + } +} +#[cfg(feature = "full")] +pub fn visit_use_name<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseName) { + _visitor.visit_ident(&_i.ident); +} +#[cfg(feature = "full")] +pub fn visit_use_path<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UsePath) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.colon2_token.spans); + _visitor.visit_use_tree(&*_i.tree); +} +#[cfg(feature = "full")] +pub fn visit_use_rename<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseRename) { + _visitor.visit_ident(&_i.ident); + tokens_helper(_visitor, &_i.as_token.span); + _visitor.visit_ident(&_i.rename); +} +#[cfg(feature = "full")] +pub fn visit_use_tree<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast UseTree) { + match *_i { + UseTree::Path(ref _binding_0) => { + _visitor.visit_use_path(_binding_0); + } + UseTree::Name(ref _binding_0) => { + _visitor.visit_use_name(_binding_0); + } + UseTree::Rename(ref _binding_0) => { + _visitor.visit_use_rename(_binding_0); + } + UseTree::Glob(ref _binding_0) => { + _visitor.visit_use_glob(_binding_0); + } + UseTree::Group(ref _binding_0) => { + _visitor.visit_use_group(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variant<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Variant) { + for it in &_i.attrs { + _visitor.visit_attribute(it) + } + _visitor.visit_ident(&_i.ident); + _visitor.visit_fields(&_i.fields); + if let Some(ref it) = _i.discriminant { + tokens_helper(_visitor, &(it).0.spans); + _visitor.visit_expr(&(it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_crate<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast VisCrate) { + tokens_helper(_visitor, &_i.crate_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_public<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast VisPublic) { + tokens_helper(_visitor, &_i.pub_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_restricted<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast VisRestricted, +) { + tokens_helper(_visitor, &_i.pub_token.span); + tokens_helper(_visitor, &_i.paren_token.span); + if let Some(ref it) = _i.in_token { + tokens_helper(_visitor, &it.span) + }; + _visitor.visit_path(&*_i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_visibility<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Visibility) { + match *_i { + Visibility::Public(ref _binding_0) => { + _visitor.visit_vis_public(_binding_0); + } + Visibility::Crate(ref _binding_0) => { + _visitor.visit_vis_crate(_binding_0); + } + Visibility::Restricted(ref _binding_0) => { + _visitor.visit_vis_restricted(_binding_0); + } + Visibility::Inherited => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_clause<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast WhereClause) { + tokens_helper(_visitor, &_i.where_token.span); + for el in Punctuated::pairs(&_i.predicates) { + let it = el.value(); + _visitor.visit_where_predicate(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_predicate<'ast, V: Visit<'ast> + ?Sized>( + _visitor: &mut V, + _i: &'ast WherePredicate, +) { + match *_i { + WherePredicate::Type(ref _binding_0) => { + _visitor.visit_predicate_type(_binding_0); + } + WherePredicate::Lifetime(ref _binding_0) => { + _visitor.visit_predicate_lifetime(_binding_0); + } + WherePredicate::Eq(ref _binding_0) => { + _visitor.visit_predicate_eq(_binding_0); + } + } +} +pub fn visit_span<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Span) {} +pub fn visit_ident<'ast, V: Visit<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Ident) {} diff --git a/syn/src/gen/visit_mut.rs b/syn/src/gen/visit_mut.rs new file mode 100644 index 000000000..399609ec5 --- /dev/null +++ b/syn/src/gen/visit_mut.rs @@ -0,0 +1,3278 @@ +// THIS FILE IS AUTOMATICALLY GENERATED; DO NOT EDIT + +#[cfg(any(feature = "full", feature = "derive"))] +use gen::helper::visit_mut::*; +use proc_macro2::Span; +#[cfg(any(feature = "full", feature = "derive"))] +use punctuated::Punctuated; +use *; +#[cfg(feature = "full")] +macro_rules! full { + ($e:expr) => { + $e + }; +} +#[cfg(all(feature = "derive", not(feature = "full")))] +macro_rules! full { + ($e:expr) => { + unreachable!() + }; +} +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! skip { + ($($tt:tt)*) => {}; +} +/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in +/// place. +/// +/// See the [module documentation] for details. +/// +/// [module documentation]: index.html +/// +/// *This trait is available if Syn is built with the `"visit-mut"` feature.* +pub trait VisitMut { + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_abi_mut(&mut self, i: &mut Abi) { + visit_abi_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_angle_bracketed_generic_arguments_mut( + &mut self, + i: &mut AngleBracketedGenericArguments, + ) { + visit_angle_bracketed_generic_arguments_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_captured_mut(&mut self, i: &mut ArgCaptured) { + visit_arg_captured_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_self_mut(&mut self, i: &mut ArgSelf) { + visit_arg_self_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_arg_self_ref_mut(&mut self, i: &mut ArgSelfRef) { + visit_arg_self_ref_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_arm_mut(&mut self, i: &mut Arm) { + visit_arm_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attr_style_mut(&mut self, i: &mut AttrStyle) { + visit_attr_style_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_attribute_mut(&mut self, i: &mut Attribute) { + visit_attribute_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg_mut(&mut self, i: &mut BareFnArg) { + visit_bare_fn_arg_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bare_fn_arg_name_mut(&mut self, i: &mut BareFnArgName) { + visit_bare_fn_arg_name_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bin_op_mut(&mut self, i: &mut BinOp) { + visit_bin_op_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_binding_mut(&mut self, i: &mut Binding) { + visit_binding_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_block_mut(&mut self, i: &mut Block) { + visit_block_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_bound_lifetimes_mut(&mut self, i: &mut BoundLifetimes) { + visit_bound_lifetimes_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_const_param_mut(&mut self, i: &mut ConstParam) { + visit_const_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_constraint_mut(&mut self, i: &mut Constraint) { + visit_constraint_mut(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_mut(&mut self, i: &mut Data) { + visit_data_mut(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_enum_mut(&mut self, i: &mut DataEnum) { + visit_data_enum_mut(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_struct_mut(&mut self, i: &mut DataStruct) { + visit_data_struct_mut(self, i) + } + #[cfg(feature = "derive")] + fn visit_data_union_mut(&mut self, i: &mut DataUnion) { + visit_data_union_mut(self, i) + } + #[cfg(feature = "derive")] + fn visit_derive_input_mut(&mut self, i: &mut DeriveInput) { + visit_derive_input_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_mut(&mut self, i: &mut Expr) { + visit_expr_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_array_mut(&mut self, i: &mut ExprArray) { + visit_expr_array_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_mut(&mut self, i: &mut ExprAssign) { + visit_expr_assign_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_assign_op_mut(&mut self, i: &mut ExprAssignOp) { + visit_expr_assign_op_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_async_mut(&mut self, i: &mut ExprAsync) { + visit_expr_async_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_binary_mut(&mut self, i: &mut ExprBinary) { + visit_expr_binary_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_block_mut(&mut self, i: &mut ExprBlock) { + visit_expr_block_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_box_mut(&mut self, i: &mut ExprBox) { + visit_expr_box_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_break_mut(&mut self, i: &mut ExprBreak) { + visit_expr_break_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_call_mut(&mut self, i: &mut ExprCall) { + visit_expr_call_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_cast_mut(&mut self, i: &mut ExprCast) { + visit_expr_cast_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_closure_mut(&mut self, i: &mut ExprClosure) { + visit_expr_closure_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_continue_mut(&mut self, i: &mut ExprContinue) { + visit_expr_continue_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_field_mut(&mut self, i: &mut ExprField) { + visit_expr_field_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_for_loop_mut(&mut self, i: &mut ExprForLoop) { + visit_expr_for_loop_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_group_mut(&mut self, i: &mut ExprGroup) { + visit_expr_group_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_if_mut(&mut self, i: &mut ExprIf) { + visit_expr_if_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_in_place_mut(&mut self, i: &mut ExprInPlace) { + visit_expr_in_place_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_index_mut(&mut self, i: &mut ExprIndex) { + visit_expr_index_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_let_mut(&mut self, i: &mut ExprLet) { + visit_expr_let_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_lit_mut(&mut self, i: &mut ExprLit) { + visit_expr_lit_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_loop_mut(&mut self, i: &mut ExprLoop) { + visit_expr_loop_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_macro_mut(&mut self, i: &mut ExprMacro) { + visit_expr_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_match_mut(&mut self, i: &mut ExprMatch) { + visit_expr_match_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_method_call_mut(&mut self, i: &mut ExprMethodCall) { + visit_expr_method_call_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_paren_mut(&mut self, i: &mut ExprParen) { + visit_expr_paren_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_path_mut(&mut self, i: &mut ExprPath) { + visit_expr_path_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_range_mut(&mut self, i: &mut ExprRange) { + visit_expr_range_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_reference_mut(&mut self, i: &mut ExprReference) { + visit_expr_reference_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_repeat_mut(&mut self, i: &mut ExprRepeat) { + visit_expr_repeat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_return_mut(&mut self, i: &mut ExprReturn) { + visit_expr_return_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_struct_mut(&mut self, i: &mut ExprStruct) { + visit_expr_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_mut(&mut self, i: &mut ExprTry) { + visit_expr_try_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_try_block_mut(&mut self, i: &mut ExprTryBlock) { + visit_expr_try_block_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_tuple_mut(&mut self, i: &mut ExprTuple) { + visit_expr_tuple_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_type_mut(&mut self, i: &mut ExprType) { + visit_expr_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_unary_mut(&mut self, i: &mut ExprUnary) { + visit_expr_unary_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_unsafe_mut(&mut self, i: &mut ExprUnsafe) { + visit_expr_unsafe_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_expr_verbatim_mut(&mut self, i: &mut ExprVerbatim) { + visit_expr_verbatim_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_while_mut(&mut self, i: &mut ExprWhile) { + visit_expr_while_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_expr_yield_mut(&mut self, i: &mut ExprYield) { + visit_expr_yield_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_field_mut(&mut self, i: &mut Field) { + visit_field_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_field_pat_mut(&mut self, i: &mut FieldPat) { + visit_field_pat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_field_value_mut(&mut self, i: &mut FieldValue) { + visit_field_value_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_mut(&mut self, i: &mut Fields) { + visit_fields_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_named_mut(&mut self, i: &mut FieldsNamed) { + visit_fields_named_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_fields_unnamed_mut(&mut self, i: &mut FieldsUnnamed) { + visit_fields_unnamed_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_file_mut(&mut self, i: &mut File) { + visit_file_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_fn_arg_mut(&mut self, i: &mut FnArg) { + visit_fn_arg_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_fn_decl_mut(&mut self, i: &mut FnDecl) { + visit_fn_decl_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_mut(&mut self, i: &mut ForeignItem) { + visit_foreign_item_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_fn_mut(&mut self, i: &mut ForeignItemFn) { + visit_foreign_item_fn_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_macro_mut(&mut self, i: &mut ForeignItemMacro) { + visit_foreign_item_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_static_mut(&mut self, i: &mut ForeignItemStatic) { + visit_foreign_item_static_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_type_mut(&mut self, i: &mut ForeignItemType) { + visit_foreign_item_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_foreign_item_verbatim_mut(&mut self, i: &mut ForeignItemVerbatim) { + visit_foreign_item_verbatim_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_argument_mut(&mut self, i: &mut GenericArgument) { + visit_generic_argument_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_generic_method_argument_mut(&mut self, i: &mut GenericMethodArgument) { + visit_generic_method_argument_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generic_param_mut(&mut self, i: &mut GenericParam) { + visit_generic_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_generics_mut(&mut self, i: &mut Generics) { + visit_generics_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_mut(&mut self, i: &mut ImplItem) { + visit_impl_item_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_const_mut(&mut self, i: &mut ImplItemConst) { + visit_impl_item_const_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_existential_mut(&mut self, i: &mut ImplItemExistential) { + visit_impl_item_existential_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_macro_mut(&mut self, i: &mut ImplItemMacro) { + visit_impl_item_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_method_mut(&mut self, i: &mut ImplItemMethod) { + visit_impl_item_method_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_type_mut(&mut self, i: &mut ImplItemType) { + visit_impl_item_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_impl_item_verbatim_mut(&mut self, i: &mut ImplItemVerbatim) { + visit_impl_item_verbatim_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_index_mut(&mut self, i: &mut Index) { + visit_index_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_mut(&mut self, i: &mut Item) { + visit_item_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_const_mut(&mut self, i: &mut ItemConst) { + visit_item_const_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_enum_mut(&mut self, i: &mut ItemEnum) { + visit_item_enum_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_existential_mut(&mut self, i: &mut ItemExistential) { + visit_item_existential_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_extern_crate_mut(&mut self, i: &mut ItemExternCrate) { + visit_item_extern_crate_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_fn_mut(&mut self, i: &mut ItemFn) { + visit_item_fn_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_foreign_mod_mut(&mut self, i: &mut ItemForeignMod) { + visit_item_foreign_mod_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_impl_mut(&mut self, i: &mut ItemImpl) { + visit_item_impl_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_macro_mut(&mut self, i: &mut ItemMacro) { + visit_item_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_macro2_mut(&mut self, i: &mut ItemMacro2) { + visit_item_macro2_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_mod_mut(&mut self, i: &mut ItemMod) { + visit_item_mod_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_static_mut(&mut self, i: &mut ItemStatic) { + visit_item_static_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_struct_mut(&mut self, i: &mut ItemStruct) { + visit_item_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_trait_mut(&mut self, i: &mut ItemTrait) { + visit_item_trait_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_trait_alias_mut(&mut self, i: &mut ItemTraitAlias) { + visit_item_trait_alias_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_type_mut(&mut self, i: &mut ItemType) { + visit_item_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_union_mut(&mut self, i: &mut ItemUnion) { + visit_item_union_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_use_mut(&mut self, i: &mut ItemUse) { + visit_item_use_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_item_verbatim_mut(&mut self, i: &mut ItemVerbatim) { + visit_item_verbatim_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_label_mut(&mut self, i: &mut Label) { + visit_label_mut(self, i) + } + fn visit_lifetime_mut(&mut self, i: &mut Lifetime) { + visit_lifetime_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lifetime_def_mut(&mut self, i: &mut LifetimeDef) { + visit_lifetime_def_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_mut(&mut self, i: &mut Lit) { + visit_lit_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_bool_mut(&mut self, i: &mut LitBool) { + visit_lit_bool_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_mut(&mut self, i: &mut LitByte) { + visit_lit_byte_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_byte_str_mut(&mut self, i: &mut LitByteStr) { + visit_lit_byte_str_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_char_mut(&mut self, i: &mut LitChar) { + visit_lit_char_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_float_mut(&mut self, i: &mut LitFloat) { + visit_lit_float_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_int_mut(&mut self, i: &mut LitInt) { + visit_lit_int_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_str_mut(&mut self, i: &mut LitStr) { + visit_lit_str_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_lit_verbatim_mut(&mut self, i: &mut LitVerbatim) { + visit_lit_verbatim_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_local_mut(&mut self, i: &mut Local) { + visit_local_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_mut(&mut self, i: &mut Macro) { + visit_macro_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_macro_delimiter_mut(&mut self, i: &mut MacroDelimiter) { + visit_macro_delimiter_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_member_mut(&mut self, i: &mut Member) { + visit_member_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_mut(&mut self, i: &mut Meta) { + visit_meta_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_list_mut(&mut self, i: &mut MetaList) { + visit_meta_list_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_meta_name_value_mut(&mut self, i: &mut MetaNameValue) { + visit_meta_name_value_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_method_sig_mut(&mut self, i: &mut MethodSig) { + visit_method_sig_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_method_turbofish_mut(&mut self, i: &mut MethodTurbofish) { + visit_method_turbofish_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_nested_meta_mut(&mut self, i: &mut NestedMeta) { + visit_nested_meta_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_parenthesized_generic_arguments_mut(&mut self, i: &mut ParenthesizedGenericArguments) { + visit_parenthesized_generic_arguments_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_mut(&mut self, i: &mut Pat) { + visit_pat_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_box_mut(&mut self, i: &mut PatBox) { + visit_pat_box_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) { + visit_pat_ident_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_lit_mut(&mut self, i: &mut PatLit) { + visit_pat_lit_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_macro_mut(&mut self, i: &mut PatMacro) { + visit_pat_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_path_mut(&mut self, i: &mut PatPath) { + visit_pat_path_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_range_mut(&mut self, i: &mut PatRange) { + visit_pat_range_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_ref_mut(&mut self, i: &mut PatRef) { + visit_pat_ref_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_slice_mut(&mut self, i: &mut PatSlice) { + visit_pat_slice_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_struct_mut(&mut self, i: &mut PatStruct) { + visit_pat_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_mut(&mut self, i: &mut PatTuple) { + visit_pat_tuple_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_tuple_struct_mut(&mut self, i: &mut PatTupleStruct) { + visit_pat_tuple_struct_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_verbatim_mut(&mut self, i: &mut PatVerbatim) { + visit_pat_verbatim_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_pat_wild_mut(&mut self, i: &mut PatWild) { + visit_pat_wild_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_mut(&mut self, i: &mut Path) { + visit_path_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_arguments_mut(&mut self, i: &mut PathArguments) { + visit_path_arguments_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_path_segment_mut(&mut self, i: &mut PathSegment) { + visit_path_segment_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_eq_mut(&mut self, i: &mut PredicateEq) { + visit_predicate_eq_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_lifetime_mut(&mut self, i: &mut PredicateLifetime) { + visit_predicate_lifetime_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_predicate_type_mut(&mut self, i: &mut PredicateType) { + visit_predicate_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_qself_mut(&mut self, i: &mut QSelf) { + visit_qself_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_range_limits_mut(&mut self, i: &mut RangeLimits) { + visit_range_limits_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_return_type_mut(&mut self, i: &mut ReturnType) { + visit_return_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_stmt_mut(&mut self, i: &mut Stmt) { + visit_stmt_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound_mut(&mut self, i: &mut TraitBound) { + visit_trait_bound_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_trait_bound_modifier_mut(&mut self, i: &mut TraitBoundModifier) { + visit_trait_bound_modifier_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_mut(&mut self, i: &mut TraitItem) { + visit_trait_item_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_const_mut(&mut self, i: &mut TraitItemConst) { + visit_trait_item_const_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_macro_mut(&mut self, i: &mut TraitItemMacro) { + visit_trait_item_macro_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_method_mut(&mut self, i: &mut TraitItemMethod) { + visit_trait_item_method_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_type_mut(&mut self, i: &mut TraitItemType) { + visit_trait_item_type_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_trait_item_verbatim_mut(&mut self, i: &mut TraitItemVerbatim) { + visit_trait_item_verbatim_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_mut(&mut self, i: &mut Type) { + visit_type_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_array_mut(&mut self, i: &mut TypeArray) { + visit_type_array_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_bare_fn_mut(&mut self, i: &mut TypeBareFn) { + visit_type_bare_fn_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_group_mut(&mut self, i: &mut TypeGroup) { + visit_type_group_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_impl_trait_mut(&mut self, i: &mut TypeImplTrait) { + visit_type_impl_trait_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_infer_mut(&mut self, i: &mut TypeInfer) { + visit_type_infer_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_macro_mut(&mut self, i: &mut TypeMacro) { + visit_type_macro_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_never_mut(&mut self, i: &mut TypeNever) { + visit_type_never_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_mut(&mut self, i: &mut TypeParam) { + visit_type_param_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_param_bound_mut(&mut self, i: &mut TypeParamBound) { + visit_type_param_bound_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_paren_mut(&mut self, i: &mut TypeParen) { + visit_type_paren_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_path_mut(&mut self, i: &mut TypePath) { + visit_type_path_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_ptr_mut(&mut self, i: &mut TypePtr) { + visit_type_ptr_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_reference_mut(&mut self, i: &mut TypeReference) { + visit_type_reference_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_slice_mut(&mut self, i: &mut TypeSlice) { + visit_type_slice_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_trait_object_mut(&mut self, i: &mut TypeTraitObject) { + visit_type_trait_object_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_tuple_mut(&mut self, i: &mut TypeTuple) { + visit_type_tuple_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_type_verbatim_mut(&mut self, i: &mut TypeVerbatim) { + visit_type_verbatim_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_un_op_mut(&mut self, i: &mut UnOp) { + visit_un_op_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_glob_mut(&mut self, i: &mut UseGlob) { + visit_use_glob_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_group_mut(&mut self, i: &mut UseGroup) { + visit_use_group_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_name_mut(&mut self, i: &mut UseName) { + visit_use_name_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_path_mut(&mut self, i: &mut UsePath) { + visit_use_path_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_rename_mut(&mut self, i: &mut UseRename) { + visit_use_rename_mut(self, i) + } + #[cfg(feature = "full")] + fn visit_use_tree_mut(&mut self, i: &mut UseTree) { + visit_use_tree_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_variant_mut(&mut self, i: &mut Variant) { + visit_variant_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_crate_mut(&mut self, i: &mut VisCrate) { + visit_vis_crate_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_public_mut(&mut self, i: &mut VisPublic) { + visit_vis_public_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_vis_restricted_mut(&mut self, i: &mut VisRestricted) { + visit_vis_restricted_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_visibility_mut(&mut self, i: &mut Visibility) { + visit_visibility_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_clause_mut(&mut self, i: &mut WhereClause) { + visit_where_clause_mut(self, i) + } + #[cfg(any(feature = "derive", feature = "full"))] + fn visit_where_predicate_mut(&mut self, i: &mut WherePredicate) { + visit_where_predicate_mut(self, i) + } + fn visit_span_mut(&mut self, i: &mut Span) { + visit_span_mut(self, i) + } + fn visit_ident_mut(&mut self, i: &mut Ident) { + visit_ident_mut(self, i) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_abi_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Abi) { + tokens_helper(_visitor, &mut _i.extern_token.span); + if let Some(ref mut it) = _i.name { + _visitor.visit_lit_str_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_angle_bracketed_generic_arguments_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut AngleBracketedGenericArguments, +) { + if let Some(ref mut it) = _i.colon2_token { + tokens_helper(_visitor, &mut it.spans) + }; + tokens_helper(_visitor, &mut _i.lt_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.args) { + let it = el.value_mut(); + _visitor.visit_generic_argument_mut(it) + } + tokens_helper(_visitor, &mut _i.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_arg_captured_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgCaptured) { + _visitor.visit_pat_mut(&mut _i.pat); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut _i.ty); +} +#[cfg(feature = "full")] +pub fn visit_arg_self_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgSelf) { + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.self_token.span); +} +#[cfg(feature = "full")] +pub fn visit_arg_self_ref_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ArgSelfRef) { + tokens_helper(_visitor, &mut _i.and_token.spans); + if let Some(ref mut it) = _i.lifetime { + _visitor.visit_lifetime_mut(it) + }; + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.self_token.span); +} +#[cfg(feature = "full")] +pub fn visit_arm_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Arm) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.leading_vert { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.pats) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } + if let Some(ref mut it) = _i.guard { + tokens_helper(_visitor, &mut (it).0.span); + _visitor.visit_expr_mut(&mut *(it).1); + }; + tokens_helper(_visitor, &mut _i.fat_arrow_token.spans); + _visitor.visit_expr_mut(&mut *_i.body); + if let Some(ref mut it) = _i.comma { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attr_style_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut AttrStyle) { + match *_i { + AttrStyle::Outer => {} + AttrStyle::Inner(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_attribute_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Attribute) { + tokens_helper(_visitor, &mut _i.pound_token.spans); + _visitor.visit_attr_style_mut(&mut _i.style); + tokens_helper(_visitor, &mut _i.bracket_token.span); + _visitor.visit_path_mut(&mut _i.path); + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BareFnArg) { + if let Some(ref mut it) = _i.name { + _visitor.visit_bare_fn_arg_name_mut(&mut (it).0); + tokens_helper(_visitor, &mut (it).1.spans); + }; + _visitor.visit_type_mut(&mut _i.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bare_fn_arg_name_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BareFnArgName) { + match *_i { + BareFnArgName::Named(ref mut _binding_0) => { + _visitor.visit_ident_mut(_binding_0); + } + BareFnArgName::Wild(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bin_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BinOp) { + match *_i { + BinOp::Add(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Sub(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Mul(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Div(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Rem(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::And(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Or(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitXor(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitAnd(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitOr(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Shl(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Shr(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Eq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Lt(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Le(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Ne(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Ge(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::Gt(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::AddEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::SubEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::MulEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::DivEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::RemEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitXorEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitAndEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::BitOrEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::ShlEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + BinOp::ShrEq(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_binding_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Binding) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_type_mut(&mut _i.ty); +} +#[cfg(feature = "full")] +pub fn visit_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Block) { + tokens_helper(_visitor, &mut _i.brace_token.span); + for it in &mut _i.stmts { + _visitor.visit_stmt_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_bound_lifetimes_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut BoundLifetimes) { + tokens_helper(_visitor, &mut _i.for_token.span); + tokens_helper(_visitor, &mut _i.lt_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.lifetimes) { + let it = el.value_mut(); + _visitor.visit_lifetime_def_mut(it) + } + tokens_helper(_visitor, &mut _i.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_const_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ConstParam) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.const_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut _i.ty); + if let Some(ref mut it) = _i.eq_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.default { + _visitor.visit_expr_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_constraint_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Constraint) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } +} +#[cfg(feature = "derive")] +pub fn visit_data_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Data) { + match *_i { + Data::Struct(ref mut _binding_0) => { + _visitor.visit_data_struct_mut(_binding_0); + } + Data::Enum(ref mut _binding_0) => { + _visitor.visit_data_enum_mut(_binding_0); + } + Data::Union(ref mut _binding_0) => { + _visitor.visit_data_union_mut(_binding_0); + } + } +} +#[cfg(feature = "derive")] +pub fn visit_data_enum_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataEnum) { + tokens_helper(_visitor, &mut _i.enum_token.span); + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.variants) { + let it = el.value_mut(); + _visitor.visit_variant_mut(it) + } +} +#[cfg(feature = "derive")] +pub fn visit_data_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataStruct) { + tokens_helper(_visitor, &mut _i.struct_token.span); + _visitor.visit_fields_mut(&mut _i.fields); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "derive")] +pub fn visit_data_union_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DataUnion) { + tokens_helper(_visitor, &mut _i.union_token.span); + _visitor.visit_fields_named_mut(&mut _i.fields); +} +#[cfg(feature = "derive")] +pub fn visit_derive_input_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut DeriveInput) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + _visitor.visit_data_mut(&mut _i.data); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Expr) { + match *_i { + Expr::Box(ref mut _binding_0) => { + full!(_visitor.visit_expr_box_mut(_binding_0)); + } + Expr::InPlace(ref mut _binding_0) => { + full!(_visitor.visit_expr_in_place_mut(_binding_0)); + } + Expr::Array(ref mut _binding_0) => { + full!(_visitor.visit_expr_array_mut(_binding_0)); + } + Expr::Call(ref mut _binding_0) => { + _visitor.visit_expr_call_mut(_binding_0); + } + Expr::MethodCall(ref mut _binding_0) => { + full!(_visitor.visit_expr_method_call_mut(_binding_0)); + } + Expr::Tuple(ref mut _binding_0) => { + full!(_visitor.visit_expr_tuple_mut(_binding_0)); + } + Expr::Binary(ref mut _binding_0) => { + _visitor.visit_expr_binary_mut(_binding_0); + } + Expr::Unary(ref mut _binding_0) => { + _visitor.visit_expr_unary_mut(_binding_0); + } + Expr::Lit(ref mut _binding_0) => { + _visitor.visit_expr_lit_mut(_binding_0); + } + Expr::Cast(ref mut _binding_0) => { + _visitor.visit_expr_cast_mut(_binding_0); + } + Expr::Type(ref mut _binding_0) => { + full!(_visitor.visit_expr_type_mut(_binding_0)); + } + Expr::Let(ref mut _binding_0) => { + full!(_visitor.visit_expr_let_mut(_binding_0)); + } + Expr::If(ref mut _binding_0) => { + full!(_visitor.visit_expr_if_mut(_binding_0)); + } + Expr::While(ref mut _binding_0) => { + full!(_visitor.visit_expr_while_mut(_binding_0)); + } + Expr::ForLoop(ref mut _binding_0) => { + full!(_visitor.visit_expr_for_loop_mut(_binding_0)); + } + Expr::Loop(ref mut _binding_0) => { + full!(_visitor.visit_expr_loop_mut(_binding_0)); + } + Expr::Match(ref mut _binding_0) => { + full!(_visitor.visit_expr_match_mut(_binding_0)); + } + Expr::Closure(ref mut _binding_0) => { + full!(_visitor.visit_expr_closure_mut(_binding_0)); + } + Expr::Unsafe(ref mut _binding_0) => { + full!(_visitor.visit_expr_unsafe_mut(_binding_0)); + } + Expr::Block(ref mut _binding_0) => { + full!(_visitor.visit_expr_block_mut(_binding_0)); + } + Expr::Assign(ref mut _binding_0) => { + full!(_visitor.visit_expr_assign_mut(_binding_0)); + } + Expr::AssignOp(ref mut _binding_0) => { + full!(_visitor.visit_expr_assign_op_mut(_binding_0)); + } + Expr::Field(ref mut _binding_0) => { + _visitor.visit_expr_field_mut(_binding_0); + } + Expr::Index(ref mut _binding_0) => { + _visitor.visit_expr_index_mut(_binding_0); + } + Expr::Range(ref mut _binding_0) => { + full!(_visitor.visit_expr_range_mut(_binding_0)); + } + Expr::Path(ref mut _binding_0) => { + _visitor.visit_expr_path_mut(_binding_0); + } + Expr::Reference(ref mut _binding_0) => { + full!(_visitor.visit_expr_reference_mut(_binding_0)); + } + Expr::Break(ref mut _binding_0) => { + full!(_visitor.visit_expr_break_mut(_binding_0)); + } + Expr::Continue(ref mut _binding_0) => { + full!(_visitor.visit_expr_continue_mut(_binding_0)); + } + Expr::Return(ref mut _binding_0) => { + full!(_visitor.visit_expr_return_mut(_binding_0)); + } + Expr::Macro(ref mut _binding_0) => { + full!(_visitor.visit_expr_macro_mut(_binding_0)); + } + Expr::Struct(ref mut _binding_0) => { + full!(_visitor.visit_expr_struct_mut(_binding_0)); + } + Expr::Repeat(ref mut _binding_0) => { + full!(_visitor.visit_expr_repeat_mut(_binding_0)); + } + Expr::Paren(ref mut _binding_0) => { + _visitor.visit_expr_paren_mut(_binding_0); + } + Expr::Group(ref mut _binding_0) => { + full!(_visitor.visit_expr_group_mut(_binding_0)); + } + Expr::Try(ref mut _binding_0) => { + full!(_visitor.visit_expr_try_mut(_binding_0)); + } + Expr::Async(ref mut _binding_0) => { + full!(_visitor.visit_expr_async_mut(_binding_0)); + } + Expr::TryBlock(ref mut _binding_0) => { + full!(_visitor.visit_expr_try_block_mut(_binding_0)); + } + Expr::Yield(ref mut _binding_0) => { + full!(_visitor.visit_expr_yield_mut(_binding_0)); + } + Expr::Verbatim(ref mut _binding_0) => { + _visitor.visit_expr_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_expr_array_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprArray) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.bracket_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.elems) { + let it = el.value_mut(); + _visitor.visit_expr_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAssign) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.left); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_expr_mut(&mut *_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_assign_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAssignOp) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.left); + _visitor.visit_bin_op_mut(&mut _i.op); + _visitor.visit_expr_mut(&mut *_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_async_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprAsync) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.async_token.span); + if let Some(ref mut it) = _i.capture { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_block_mut(&mut _i.block); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_binary_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBinary) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.left); + _visitor.visit_bin_op_mut(&mut _i.op); + _visitor.visit_expr_mut(&mut *_i.right); +} +#[cfg(feature = "full")] +pub fn visit_expr_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBlock) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.label { + _visitor.visit_label_mut(it) + }; + _visitor.visit_block_mut(&mut _i.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_box_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBox) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.box_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_break_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprBreak) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.break_token.span); + if let Some(ref mut it) = _i.label { + _visitor.visit_lifetime_mut(it) + }; + if let Some(ref mut it) = _i.expr { + _visitor.visit_expr_mut(&mut **it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_call_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprCall) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.func); + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.args) { + let it = el.value_mut(); + _visitor.visit_expr_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_cast_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprCast) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.as_token.span); + _visitor.visit_type_mut(&mut *_i.ty); +} +#[cfg(feature = "full")] +pub fn visit_expr_closure_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprClosure) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.asyncness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.movability { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.capture { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.or1_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.inputs) { + let it = el.value_mut(); + _visitor.visit_fn_arg_mut(it) + } + tokens_helper(_visitor, &mut _i.or2_token.spans); + _visitor.visit_return_type_mut(&mut _i.output); + _visitor.visit_expr_mut(&mut *_i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_continue_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprContinue) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.continue_token.span); + if let Some(ref mut it) = _i.label { + _visitor.visit_lifetime_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_field_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprField) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.base); + tokens_helper(_visitor, &mut _i.dot_token.spans); + _visitor.visit_member_mut(&mut _i.member); +} +#[cfg(feature = "full")] +pub fn visit_expr_for_loop_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprForLoop) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.label { + _visitor.visit_label_mut(it) + }; + tokens_helper(_visitor, &mut _i.for_token.span); + _visitor.visit_pat_mut(&mut *_i.pat); + tokens_helper(_visitor, &mut _i.in_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); + _visitor.visit_block_mut(&mut _i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprGroup) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.group_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_if_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIf) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.if_token.span); + _visitor.visit_expr_mut(&mut *_i.cond); + _visitor.visit_block_mut(&mut _i.then_branch); + if let Some(ref mut it) = _i.else_branch { + tokens_helper(_visitor, &mut (it).0.span); + _visitor.visit_expr_mut(&mut *(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_in_place_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprInPlace) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.place); + tokens_helper(_visitor, &mut _i.arrow_token.spans); + _visitor.visit_expr_mut(&mut *_i.value); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_index_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprIndex) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.bracket_token.span); + _visitor.visit_expr_mut(&mut *_i.index); +} +#[cfg(feature = "full")] +pub fn visit_expr_let_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLet) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.let_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.pats) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLit) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_lit_mut(&mut _i.lit); +} +#[cfg(feature = "full")] +pub fn visit_expr_loop_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprLoop) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.label { + _visitor.visit_label_mut(it) + }; + tokens_helper(_visitor, &mut _i.loop_token.span); + _visitor.visit_block_mut(&mut _i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMacro) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_macro_mut(&mut _i.mac); +} +#[cfg(feature = "full")] +pub fn visit_expr_match_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMatch) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.match_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.brace_token.span); + for it in &mut _i.arms { + _visitor.visit_arm_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_method_call_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprMethodCall) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.receiver); + tokens_helper(_visitor, &mut _i.dot_token.spans); + _visitor.visit_ident_mut(&mut _i.method); + if let Some(ref mut it) = _i.turbofish { + _visitor.visit_method_turbofish_mut(it) + }; + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.args) { + let it = el.value_mut(); + _visitor.visit_expr_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_paren_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprParen) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.paren_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprPath) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.qself { + _visitor.visit_qself_mut(it) + }; + _visitor.visit_path_mut(&mut _i.path); +} +#[cfg(feature = "full")] +pub fn visit_expr_range_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprRange) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.from { + _visitor.visit_expr_mut(&mut **it) + }; + _visitor.visit_range_limits_mut(&mut _i.limits); + if let Some(ref mut it) = _i.to { + _visitor.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_reference_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprReference) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.and_token.spans); + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_repeat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprRepeat) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.bracket_token.span); + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.semi_token.spans); + _visitor.visit_expr_mut(&mut *_i.len); +} +#[cfg(feature = "full")] +pub fn visit_expr_return_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprReturn) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.return_token.span); + if let Some(ref mut it) = _i.expr { + _visitor.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprStruct) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_path_mut(&mut _i.path); + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.fields) { + let it = el.value_mut(); + _visitor.visit_field_value_mut(it) + } + if let Some(ref mut it) = _i.dot2_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.rest { + _visitor.visit_expr_mut(&mut **it) + }; +} +#[cfg(feature = "full")] +pub fn visit_expr_try_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTry) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.question_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_expr_try_block_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTryBlock) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.try_token.span); + _visitor.visit_block_mut(&mut _i.block); +} +#[cfg(feature = "full")] +pub fn visit_expr_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprTuple) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.elems) { + let it = el.value_mut(); + _visitor.visit_expr_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_expr_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprType) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_unary_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprUnary) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_un_op_mut(&mut _i.op); + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_expr_unsafe_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprUnsafe) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.unsafe_token.span); + _visitor.visit_block_mut(&mut _i.block); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_expr_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprVerbatim) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_expr_while_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprWhile) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.label { + _visitor.visit_label_mut(it) + }; + tokens_helper(_visitor, &mut _i.while_token.span); + _visitor.visit_expr_mut(&mut *_i.cond); + _visitor.visit_block_mut(&mut _i.body); +} +#[cfg(feature = "full")] +pub fn visit_expr_yield_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ExprYield) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.yield_token.span); + if let Some(ref mut it) = _i.expr { + _visitor.visit_expr_mut(&mut **it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_field_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Field) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.ident { + _visitor.visit_ident_mut(it) + }; + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_type_mut(&mut _i.ty); +} +#[cfg(feature = "full")] +pub fn visit_field_pat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldPat) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_member_mut(&mut _i.member); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_pat_mut(&mut *_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_field_value_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldValue) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_member_mut(&mut _i.member); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_expr_mut(&mut _i.expr); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Fields) { + match *_i { + Fields::Named(ref mut _binding_0) => { + _visitor.visit_fields_named_mut(_binding_0); + } + Fields::Unnamed(ref mut _binding_0) => { + _visitor.visit_fields_unnamed_mut(_binding_0); + } + Fields::Unit => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_named_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldsNamed) { + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.named) { + let it = el.value_mut(); + _visitor.visit_field_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_fields_unnamed_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FieldsUnnamed) { + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.unnamed) { + let it = el.value_mut(); + _visitor.visit_field_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_file_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut File) { + skip!(_i.shebang); + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + for it in &mut _i.items { + _visitor.visit_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_fn_arg_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FnArg) { + match *_i { + FnArg::SelfRef(ref mut _binding_0) => { + _visitor.visit_arg_self_ref_mut(_binding_0); + } + FnArg::SelfValue(ref mut _binding_0) => { + _visitor.visit_arg_self_mut(_binding_0); + } + FnArg::Captured(ref mut _binding_0) => { + _visitor.visit_arg_captured_mut(_binding_0); + } + FnArg::Inferred(ref mut _binding_0) => { + _visitor.visit_pat_mut(_binding_0); + } + FnArg::Ignored(ref mut _binding_0) => { + _visitor.visit_type_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_fn_decl_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut FnDecl) { + tokens_helper(_visitor, &mut _i.fn_token.span); + _visitor.visit_generics_mut(&mut _i.generics); + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.inputs) { + let it = el.value_mut(); + _visitor.visit_fn_arg_mut(it) + } + if let Some(ref mut it) = _i.variadic { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_return_type_mut(&mut _i.output); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ForeignItem) { + match *_i { + ForeignItem::Fn(ref mut _binding_0) => { + _visitor.visit_foreign_item_fn_mut(_binding_0); + } + ForeignItem::Static(ref mut _binding_0) => { + _visitor.visit_foreign_item_static_mut(_binding_0); + } + ForeignItem::Type(ref mut _binding_0) => { + _visitor.visit_foreign_item_type_mut(_binding_0); + } + ForeignItem::Macro(ref mut _binding_0) => { + _visitor.visit_foreign_item_macro_mut(_binding_0); + } + ForeignItem::Verbatim(ref mut _binding_0) => { + _visitor.visit_foreign_item_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ForeignItemFn) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_fn_decl_mut(&mut *_i.decl); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_macro_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ForeignItemMacro, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_macro_mut(&mut _i.mac); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_static_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ForeignItemStatic, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.static_token.span); + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_type_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ForeignItemType, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_foreign_item_verbatim_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ForeignItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_argument_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut GenericArgument, +) { + match *_i { + GenericArgument::Lifetime(ref mut _binding_0) => { + _visitor.visit_lifetime_mut(_binding_0); + } + GenericArgument::Type(ref mut _binding_0) => { + _visitor.visit_type_mut(_binding_0); + } + GenericArgument::Binding(ref mut _binding_0) => { + _visitor.visit_binding_mut(_binding_0); + } + GenericArgument::Constraint(ref mut _binding_0) => { + _visitor.visit_constraint_mut(_binding_0); + } + GenericArgument::Const(ref mut _binding_0) => { + _visitor.visit_expr_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_generic_method_argument_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut GenericMethodArgument, +) { + match *_i { + GenericMethodArgument::Type(ref mut _binding_0) => { + _visitor.visit_type_mut(_binding_0); + } + GenericMethodArgument::Const(ref mut _binding_0) => { + _visitor.visit_expr_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generic_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut GenericParam) { + match *_i { + GenericParam::Type(ref mut _binding_0) => { + _visitor.visit_type_param_mut(_binding_0); + } + GenericParam::Lifetime(ref mut _binding_0) => { + _visitor.visit_lifetime_def_mut(_binding_0); + } + GenericParam::Const(ref mut _binding_0) => { + _visitor.visit_const_param_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_generics_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Generics) { + if let Some(ref mut it) = _i.lt_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.params) { + let it = el.value_mut(); + _visitor.visit_generic_param_mut(it) + } + if let Some(ref mut it) = _i.gt_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.where_clause { + _visitor.visit_where_clause_mut(it) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItem) { + match *_i { + ImplItem::Const(ref mut _binding_0) => { + _visitor.visit_impl_item_const_mut(_binding_0); + } + ImplItem::Method(ref mut _binding_0) => { + _visitor.visit_impl_item_method_mut(_binding_0); + } + ImplItem::Type(ref mut _binding_0) => { + _visitor.visit_impl_item_type_mut(_binding_0); + } + ImplItem::Existential(ref mut _binding_0) => { + _visitor.visit_impl_item_existential_mut(_binding_0); + } + ImplItem::Macro(ref mut _binding_0) => { + _visitor.visit_impl_item_macro_mut(_binding_0); + } + ImplItem::Verbatim(ref mut _binding_0) => { + _visitor.visit_impl_item_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_impl_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemConst) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.defaultness { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.const_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut _i.ty); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_expr_mut(&mut _i.expr); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_existential_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ImplItemExistential, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.existential_token.span); + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemMacro) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_macro_mut(&mut _i.mac); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_impl_item_method_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemMethod) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.defaultness { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_method_sig_mut(&mut _i.sig); + _visitor.visit_block_mut(&mut _i.block); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ImplItemType) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.defaultness { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_type_mut(&mut _i.ty); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_impl_item_verbatim_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ImplItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_index_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Index) { + skip!(_i.index); + _visitor.visit_span_mut(&mut _i.span); +} +#[cfg(feature = "full")] +pub fn visit_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Item) { + match *_i { + Item::ExternCrate(ref mut _binding_0) => { + _visitor.visit_item_extern_crate_mut(_binding_0); + } + Item::Use(ref mut _binding_0) => { + _visitor.visit_item_use_mut(_binding_0); + } + Item::Static(ref mut _binding_0) => { + _visitor.visit_item_static_mut(_binding_0); + } + Item::Const(ref mut _binding_0) => { + _visitor.visit_item_const_mut(_binding_0); + } + Item::Fn(ref mut _binding_0) => { + _visitor.visit_item_fn_mut(_binding_0); + } + Item::Mod(ref mut _binding_0) => { + _visitor.visit_item_mod_mut(_binding_0); + } + Item::ForeignMod(ref mut _binding_0) => { + _visitor.visit_item_foreign_mod_mut(_binding_0); + } + Item::Type(ref mut _binding_0) => { + _visitor.visit_item_type_mut(_binding_0); + } + Item::Existential(ref mut _binding_0) => { + _visitor.visit_item_existential_mut(_binding_0); + } + Item::Struct(ref mut _binding_0) => { + _visitor.visit_item_struct_mut(_binding_0); + } + Item::Enum(ref mut _binding_0) => { + _visitor.visit_item_enum_mut(_binding_0); + } + Item::Union(ref mut _binding_0) => { + _visitor.visit_item_union_mut(_binding_0); + } + Item::Trait(ref mut _binding_0) => { + _visitor.visit_item_trait_mut(_binding_0); + } + Item::TraitAlias(ref mut _binding_0) => { + _visitor.visit_item_trait_alias_mut(_binding_0); + } + Item::Impl(ref mut _binding_0) => { + _visitor.visit_item_impl_mut(_binding_0); + } + Item::Macro(ref mut _binding_0) => { + _visitor.visit_item_macro_mut(_binding_0); + } + Item::Macro2(ref mut _binding_0) => { + _visitor.visit_item_macro2_mut(_binding_0); + } + Item::Verbatim(ref mut _binding_0) => { + _visitor.visit_item_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemConst) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.const_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_enum_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemEnum) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.enum_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.variants) { + let it = el.value_mut(); + _visitor.visit_variant_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_existential_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ItemExistential, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.existential_token.span); + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_extern_crate_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ItemExternCrate, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.extern_token.span); + tokens_helper(_visitor, &mut _i.crate_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + if let Some(ref mut it) = _i.rename { + tokens_helper(_visitor, &mut (it).0.span); + _visitor.visit_ident_mut(&mut (it).1); + }; + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemFn) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.constness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.unsafety { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.asyncness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.abi { + _visitor.visit_abi_mut(it) + }; + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_fn_decl_mut(&mut *_i.decl); + _visitor.visit_block_mut(&mut *_i.block); +} +#[cfg(feature = "full")] +pub fn visit_item_foreign_mod_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemForeignMod) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_abi_mut(&mut _i.abi); + tokens_helper(_visitor, &mut _i.brace_token.span); + for it in &mut _i.items { + _visitor.visit_foreign_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_impl_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemImpl) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.defaultness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.unsafety { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.impl_token.span); + _visitor.visit_generics_mut(&mut _i.generics); + if let Some(ref mut it) = _i.trait_ { + if let Some(ref mut it) = (it).0 { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_path_mut(&mut (it).1); + tokens_helper(_visitor, &mut (it).2.span); + }; + _visitor.visit_type_mut(&mut *_i.self_ty); + tokens_helper(_visitor, &mut _i.brace_token.span); + for it in &mut _i.items { + _visitor.visit_impl_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMacro) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + if let Some(ref mut it) = _i.ident { + _visitor.visit_ident_mut(it) + }; + _visitor.visit_macro_mut(&mut _i.mac); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_macro2_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMacro2) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.macro_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.paren_token.span); + skip!(_i.args); + tokens_helper(_visitor, &mut _i.brace_token.span); + skip!(_i.body); +} +#[cfg(feature = "full")] +pub fn visit_item_mod_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemMod) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.mod_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + if let Some(ref mut it) = _i.content { + tokens_helper(_visitor, &mut (it).0.span); + for it in &mut (it).1 { + _visitor.visit_item_mut(it) + } + }; + if let Some(ref mut it) = _i.semi { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_static_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemStatic) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.static_token.span); + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_expr_mut(&mut *_i.expr); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemStruct) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.struct_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + _visitor.visit_fields_mut(&mut _i.fields); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_item_trait_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemTrait) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + if let Some(ref mut it) = _i.unsafety { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.auto_token { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.trait_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.supertraits) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + tokens_helper(_visitor, &mut _i.brace_token.span); + for it in &mut _i.items { + _visitor.visit_trait_item_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_item_trait_alias_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemTraitAlias) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.trait_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + tokens_helper(_visitor, &mut _i.eq_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemType) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_union_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemUnion) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.union_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + _visitor.visit_fields_named_mut(&mut _i.fields); +} +#[cfg(feature = "full")] +pub fn visit_item_use_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemUse) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_visibility_mut(&mut _i.vis); + tokens_helper(_visitor, &mut _i.use_token.span); + if let Some(ref mut it) = _i.leading_colon { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_use_tree_mut(&mut _i.tree); + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_item_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ItemVerbatim) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_label_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Label) { + _visitor.visit_lifetime_mut(&mut _i.name); + tokens_helper(_visitor, &mut _i.colon_token.spans); +} +pub fn visit_lifetime_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Lifetime) { + _visitor.visit_span_mut(&mut _i.apostrophe); + _visitor.visit_ident_mut(&mut _i.ident); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lifetime_def_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LifetimeDef) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_lifetime_mut(&mut _i.lifetime); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_lifetime_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Lit) { + match *_i { + Lit::Str(ref mut _binding_0) => { + _visitor.visit_lit_str_mut(_binding_0); + } + Lit::ByteStr(ref mut _binding_0) => { + _visitor.visit_lit_byte_str_mut(_binding_0); + } + Lit::Byte(ref mut _binding_0) => { + _visitor.visit_lit_byte_mut(_binding_0); + } + Lit::Char(ref mut _binding_0) => { + _visitor.visit_lit_char_mut(_binding_0); + } + Lit::Int(ref mut _binding_0) => { + _visitor.visit_lit_int_mut(_binding_0); + } + Lit::Float(ref mut _binding_0) => { + _visitor.visit_lit_float_mut(_binding_0); + } + Lit::Bool(ref mut _binding_0) => { + _visitor.visit_lit_bool_mut(_binding_0); + } + Lit::Verbatim(ref mut _binding_0) => { + _visitor.visit_lit_verbatim_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_bool_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitBool) { + skip!(_i.value); + _visitor.visit_span_mut(&mut _i.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitByte) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_byte_str_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitByteStr) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_char_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitChar) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_float_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitFloat) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_int_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitInt) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_str_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitStr) {} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_lit_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut LitVerbatim) { + skip!(_i.token); +} +#[cfg(feature = "full")] +pub fn visit_local_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Local) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.let_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.pats) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } + if let Some(ref mut it) = _i.ty { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_type_mut(&mut *(it).1); + }; + if let Some(ref mut it) = _i.init { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_expr_mut(&mut *(it).1); + }; + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Macro) { + _visitor.visit_path_mut(&mut _i.path); + tokens_helper(_visitor, &mut _i.bang_token.spans); + _visitor.visit_macro_delimiter_mut(&mut _i.delimiter); + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_macro_delimiter_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MacroDelimiter) { + match *_i { + MacroDelimiter::Paren(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.span); + } + MacroDelimiter::Brace(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.span); + } + MacroDelimiter::Bracket(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.span); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_member_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Member) { + match *_i { + Member::Named(ref mut _binding_0) => { + _visitor.visit_ident_mut(_binding_0); + } + Member::Unnamed(ref mut _binding_0) => { + _visitor.visit_index_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Meta) { + match *_i { + Meta::Word(ref mut _binding_0) => { + _visitor.visit_ident_mut(_binding_0); + } + Meta::List(ref mut _binding_0) => { + _visitor.visit_meta_list_mut(_binding_0); + } + Meta::NameValue(ref mut _binding_0) => { + _visitor.visit_meta_name_value_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_list_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MetaList) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.nested) { + let it = el.value_mut(); + _visitor.visit_nested_meta_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_meta_name_value_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MetaNameValue) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_lit_mut(&mut _i.lit); +} +#[cfg(feature = "full")] +pub fn visit_method_sig_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut MethodSig) { + if let Some(ref mut it) = _i.constness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.unsafety { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.asyncness { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.abi { + _visitor.visit_abi_mut(it) + }; + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_fn_decl_mut(&mut _i.decl); +} +#[cfg(feature = "full")] +pub fn visit_method_turbofish_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut MethodTurbofish, +) { + tokens_helper(_visitor, &mut _i.colon2_token.spans); + tokens_helper(_visitor, &mut _i.lt_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.args) { + let it = el.value_mut(); + _visitor.visit_generic_method_argument_mut(it) + } + tokens_helper(_visitor, &mut _i.gt_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_nested_meta_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut NestedMeta) { + match *_i { + NestedMeta::Meta(ref mut _binding_0) => { + _visitor.visit_meta_mut(_binding_0); + } + NestedMeta::Literal(ref mut _binding_0) => { + _visitor.visit_lit_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_parenthesized_generic_arguments_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut ParenthesizedGenericArguments, +) { + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.inputs) { + let it = el.value_mut(); + _visitor.visit_type_mut(it) + } + _visitor.visit_return_type_mut(&mut _i.output); +} +#[cfg(feature = "full")] +pub fn visit_pat_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Pat) { + match *_i { + Pat::Wild(ref mut _binding_0) => { + _visitor.visit_pat_wild_mut(_binding_0); + } + Pat::Ident(ref mut _binding_0) => { + _visitor.visit_pat_ident_mut(_binding_0); + } + Pat::Struct(ref mut _binding_0) => { + _visitor.visit_pat_struct_mut(_binding_0); + } + Pat::TupleStruct(ref mut _binding_0) => { + _visitor.visit_pat_tuple_struct_mut(_binding_0); + } + Pat::Path(ref mut _binding_0) => { + _visitor.visit_pat_path_mut(_binding_0); + } + Pat::Tuple(ref mut _binding_0) => { + _visitor.visit_pat_tuple_mut(_binding_0); + } + Pat::Box(ref mut _binding_0) => { + _visitor.visit_pat_box_mut(_binding_0); + } + Pat::Ref(ref mut _binding_0) => { + _visitor.visit_pat_ref_mut(_binding_0); + } + Pat::Lit(ref mut _binding_0) => { + _visitor.visit_pat_lit_mut(_binding_0); + } + Pat::Range(ref mut _binding_0) => { + _visitor.visit_pat_range_mut(_binding_0); + } + Pat::Slice(ref mut _binding_0) => { + _visitor.visit_pat_slice_mut(_binding_0); + } + Pat::Macro(ref mut _binding_0) => { + _visitor.visit_pat_macro_mut(_binding_0); + } + Pat::Verbatim(ref mut _binding_0) => { + _visitor.visit_pat_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_pat_box_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatBox) { + tokens_helper(_visitor, &mut _i.box_token.span); + _visitor.visit_pat_mut(&mut *_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_ident_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatIdent) { + if let Some(ref mut it) = _i.by_ref { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_ident_mut(&mut _i.ident); + if let Some(ref mut it) = _i.subpat { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_pat_mut(&mut *(it).1); + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_lit_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatLit) { + _visitor.visit_expr_mut(&mut *_i.expr); +} +#[cfg(feature = "full")] +pub fn visit_pat_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatMacro) { + _visitor.visit_macro_mut(&mut _i.mac); +} +#[cfg(feature = "full")] +pub fn visit_pat_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatPath) { + if let Some(ref mut it) = _i.qself { + _visitor.visit_qself_mut(it) + }; + _visitor.visit_path_mut(&mut _i.path); +} +#[cfg(feature = "full")] +pub fn visit_pat_range_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatRange) { + _visitor.visit_expr_mut(&mut *_i.lo); + _visitor.visit_range_limits_mut(&mut _i.limits); + _visitor.visit_expr_mut(&mut *_i.hi); +} +#[cfg(feature = "full")] +pub fn visit_pat_ref_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatRef) { + tokens_helper(_visitor, &mut _i.and_token.spans); + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_pat_mut(&mut *_i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_slice_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatSlice) { + tokens_helper(_visitor, &mut _i.bracket_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.front) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } + if let Some(ref mut it) = _i.middle { + _visitor.visit_pat_mut(&mut **it) + }; + if let Some(ref mut it) = _i.dot2_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.comma_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.back) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_pat_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatStruct) { + _visitor.visit_path_mut(&mut _i.path); + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.fields) { + let it = el.value_mut(); + _visitor.visit_field_pat_mut(it) + } + if let Some(ref mut it) = _i.dot2_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatTuple) { + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.front) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } + if let Some(ref mut it) = _i.dot2_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.comma_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.back) { + let it = el.value_mut(); + _visitor.visit_pat_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_pat_tuple_struct_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatTupleStruct) { + _visitor.visit_path_mut(&mut _i.path); + _visitor.visit_pat_tuple_mut(&mut _i.pat); +} +#[cfg(feature = "full")] +pub fn visit_pat_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatVerbatim) { + skip!(_i.tts); +} +#[cfg(feature = "full")] +pub fn visit_pat_wild_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PatWild) { + tokens_helper(_visitor, &mut _i.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Path) { + if let Some(ref mut it) = _i.leading_colon { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.segments) { + let it = el.value_mut(); + _visitor.visit_path_segment_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_arguments_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PathArguments) { + match *_i { + PathArguments::None => {} + PathArguments::AngleBracketed(ref mut _binding_0) => { + _visitor.visit_angle_bracketed_generic_arguments_mut(_binding_0); + } + PathArguments::Parenthesized(ref mut _binding_0) => { + _visitor.visit_parenthesized_generic_arguments_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_path_segment_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PathSegment) { + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_path_arguments_mut(&mut _i.arguments); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_eq_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PredicateEq) { + _visitor.visit_type_mut(&mut _i.lhs_ty); + tokens_helper(_visitor, &mut _i.eq_token.spans); + _visitor.visit_type_mut(&mut _i.rhs_ty); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_lifetime_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut PredicateLifetime, +) { + _visitor.visit_lifetime_mut(&mut _i.lifetime); + tokens_helper(_visitor, &mut _i.colon_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_lifetime_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_predicate_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut PredicateType) { + if let Some(ref mut it) = _i.lifetimes { + _visitor.visit_bound_lifetimes_mut(it) + }; + _visitor.visit_type_mut(&mut _i.bounded_ty); + tokens_helper(_visitor, &mut _i.colon_token.spans); + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_qself_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut QSelf) { + tokens_helper(_visitor, &mut _i.lt_token.spans); + _visitor.visit_type_mut(&mut *_i.ty); + skip!(_i.position); + if let Some(ref mut it) = _i.as_token { + tokens_helper(_visitor, &mut it.span) + }; + tokens_helper(_visitor, &mut _i.gt_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_range_limits_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut RangeLimits) { + match *_i { + RangeLimits::HalfOpen(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + RangeLimits::Closed(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_return_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut ReturnType) { + match *_i { + ReturnType::Default => {} + ReturnType::Type(ref mut _binding_0, ref mut _binding_1) => { + tokens_helper(_visitor, &mut _binding_0.spans); + _visitor.visit_type_mut(&mut **_binding_1); + } + } +} +#[cfg(feature = "full")] +pub fn visit_stmt_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Stmt) { + match *_i { + Stmt::Local(ref mut _binding_0) => { + _visitor.visit_local_mut(_binding_0); + } + Stmt::Item(ref mut _binding_0) => { + _visitor.visit_item_mut(_binding_0); + } + Stmt::Expr(ref mut _binding_0) => { + _visitor.visit_expr_mut(_binding_0); + } + Stmt::Semi(ref mut _binding_0, ref mut _binding_1) => { + _visitor.visit_expr_mut(_binding_0); + tokens_helper(_visitor, &mut _binding_1.spans); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitBound) { + if let Some(ref mut it) = _i.paren_token { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_trait_bound_modifier_mut(&mut _i.modifier); + if let Some(ref mut it) = _i.lifetimes { + _visitor.visit_bound_lifetimes_mut(it) + }; + _visitor.visit_path_mut(&mut _i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_trait_bound_modifier_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut TraitBoundModifier, +) { + match *_i { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItem) { + match *_i { + TraitItem::Const(ref mut _binding_0) => { + _visitor.visit_trait_item_const_mut(_binding_0); + } + TraitItem::Method(ref mut _binding_0) => { + _visitor.visit_trait_item_method_mut(_binding_0); + } + TraitItem::Type(ref mut _binding_0) => { + _visitor.visit_trait_item_type_mut(_binding_0); + } + TraitItem::Macro(ref mut _binding_0) => { + _visitor.visit_trait_item_macro_mut(_binding_0); + } + TraitItem::Verbatim(ref mut _binding_0) => { + _visitor.visit_trait_item_verbatim_mut(_binding_0); + } + } +} +#[cfg(feature = "full")] +pub fn visit_trait_item_const_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemConst) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.const_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon_token.spans); + _visitor.visit_type_mut(&mut _i.ty); + if let Some(ref mut it) = _i.default { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_expr_mut(&mut (it).1); + }; + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemMacro) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_macro_mut(&mut _i.mac); + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_method_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut TraitItemMethod, +) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_method_sig_mut(&mut _i.sig); + if let Some(ref mut it) = _i.default { + _visitor.visit_block_mut(it) + }; + if let Some(ref mut it) = _i.semi_token { + tokens_helper(_visitor, &mut it.spans) + }; +} +#[cfg(feature = "full")] +pub fn visit_trait_item_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TraitItemType) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + tokens_helper(_visitor, &mut _i.type_token.span); + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_generics_mut(&mut _i.generics); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + if let Some(ref mut it) = _i.default { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_type_mut(&mut (it).1); + }; + tokens_helper(_visitor, &mut _i.semi_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_trait_item_verbatim_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut TraitItemVerbatim, +) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Type) { + match *_i { + Type::Slice(ref mut _binding_0) => { + _visitor.visit_type_slice_mut(_binding_0); + } + Type::Array(ref mut _binding_0) => { + _visitor.visit_type_array_mut(_binding_0); + } + Type::Ptr(ref mut _binding_0) => { + _visitor.visit_type_ptr_mut(_binding_0); + } + Type::Reference(ref mut _binding_0) => { + _visitor.visit_type_reference_mut(_binding_0); + } + Type::BareFn(ref mut _binding_0) => { + _visitor.visit_type_bare_fn_mut(_binding_0); + } + Type::Never(ref mut _binding_0) => { + _visitor.visit_type_never_mut(_binding_0); + } + Type::Tuple(ref mut _binding_0) => { + _visitor.visit_type_tuple_mut(_binding_0); + } + Type::Path(ref mut _binding_0) => { + _visitor.visit_type_path_mut(_binding_0); + } + Type::TraitObject(ref mut _binding_0) => { + _visitor.visit_type_trait_object_mut(_binding_0); + } + Type::ImplTrait(ref mut _binding_0) => { + _visitor.visit_type_impl_trait_mut(_binding_0); + } + Type::Paren(ref mut _binding_0) => { + _visitor.visit_type_paren_mut(_binding_0); + } + Type::Group(ref mut _binding_0) => { + _visitor.visit_type_group_mut(_binding_0); + } + Type::Infer(ref mut _binding_0) => { + _visitor.visit_type_infer_mut(_binding_0); + } + Type::Macro(ref mut _binding_0) => { + _visitor.visit_type_macro_mut(_binding_0); + } + Type::Verbatim(ref mut _binding_0) => { + _visitor.visit_type_verbatim_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_array_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeArray) { + tokens_helper(_visitor, &mut _i.bracket_token.span); + _visitor.visit_type_mut(&mut *_i.elem); + tokens_helper(_visitor, &mut _i.semi_token.spans); + _visitor.visit_expr_mut(&mut _i.len); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_bare_fn_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeBareFn) { + if let Some(ref mut it) = _i.lifetimes { + _visitor.visit_bound_lifetimes_mut(it) + }; + if let Some(ref mut it) = _i.unsafety { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.abi { + _visitor.visit_abi_mut(it) + }; + tokens_helper(_visitor, &mut _i.fn_token.span); + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.inputs) { + let it = el.value_mut(); + _visitor.visit_bare_fn_arg_mut(it) + } + if let Some(ref mut it) = _i.variadic { + tokens_helper(_visitor, &mut it.spans) + }; + _visitor.visit_return_type_mut(&mut _i.output); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeGroup) { + tokens_helper(_visitor, &mut _i.group_token.span); + _visitor.visit_type_mut(&mut *_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_impl_trait_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeImplTrait) { + tokens_helper(_visitor, &mut _i.impl_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_infer_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeInfer) { + tokens_helper(_visitor, &mut _i.underscore_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_macro_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeMacro) { + _visitor.visit_macro_mut(&mut _i.mac); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_never_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeNever) { + tokens_helper(_visitor, &mut _i.bang_token.spans); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParam) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_ident_mut(&mut _i.ident); + if let Some(ref mut it) = _i.colon_token { + tokens_helper(_visitor, &mut it.spans) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } + if let Some(ref mut it) = _i.eq_token { + tokens_helper(_visitor, &mut it.spans) + }; + if let Some(ref mut it) = _i.default { + _visitor.visit_type_mut(it) + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_param_bound_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParamBound) { + match *_i { + TypeParamBound::Trait(ref mut _binding_0) => { + _visitor.visit_trait_bound_mut(_binding_0); + } + TypeParamBound::Lifetime(ref mut _binding_0) => { + _visitor.visit_lifetime_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_paren_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeParen) { + tokens_helper(_visitor, &mut _i.paren_token.span); + _visitor.visit_type_mut(&mut *_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypePath) { + if let Some(ref mut it) = _i.qself { + _visitor.visit_qself_mut(it) + }; + _visitor.visit_path_mut(&mut _i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_ptr_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypePtr) { + tokens_helper(_visitor, &mut _i.star_token.spans); + if let Some(ref mut it) = _i.const_token { + tokens_helper(_visitor, &mut it.span) + }; + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_type_mut(&mut *_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_reference_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeReference) { + tokens_helper(_visitor, &mut _i.and_token.spans); + if let Some(ref mut it) = _i.lifetime { + _visitor.visit_lifetime_mut(it) + }; + if let Some(ref mut it) = _i.mutability { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_type_mut(&mut *_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_slice_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeSlice) { + tokens_helper(_visitor, &mut _i.bracket_token.span); + _visitor.visit_type_mut(&mut *_i.elem); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_trait_object_mut<V: VisitMut + ?Sized>( + _visitor: &mut V, + _i: &mut TypeTraitObject, +) { + if let Some(ref mut it) = _i.dyn_token { + tokens_helper(_visitor, &mut it.span) + }; + for mut el in Punctuated::pairs_mut(&mut _i.bounds) { + let it = el.value_mut(); + _visitor.visit_type_param_bound_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_tuple_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeTuple) { + tokens_helper(_visitor, &mut _i.paren_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.elems) { + let it = el.value_mut(); + _visitor.visit_type_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_type_verbatim_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut TypeVerbatim) { + skip!(_i.tts); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_un_op_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UnOp) { + match *_i { + UnOp::Deref(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + UnOp::Not(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + UnOp::Neg(ref mut _binding_0) => { + tokens_helper(_visitor, &mut _binding_0.spans); + } + } +} +#[cfg(feature = "full")] +pub fn visit_use_glob_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseGlob) { + tokens_helper(_visitor, &mut _i.star_token.spans); +} +#[cfg(feature = "full")] +pub fn visit_use_group_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseGroup) { + tokens_helper(_visitor, &mut _i.brace_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.items) { + let it = el.value_mut(); + _visitor.visit_use_tree_mut(it) + } +} +#[cfg(feature = "full")] +pub fn visit_use_name_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseName) { + _visitor.visit_ident_mut(&mut _i.ident); +} +#[cfg(feature = "full")] +pub fn visit_use_path_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UsePath) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.colon2_token.spans); + _visitor.visit_use_tree_mut(&mut *_i.tree); +} +#[cfg(feature = "full")] +pub fn visit_use_rename_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseRename) { + _visitor.visit_ident_mut(&mut _i.ident); + tokens_helper(_visitor, &mut _i.as_token.span); + _visitor.visit_ident_mut(&mut _i.rename); +} +#[cfg(feature = "full")] +pub fn visit_use_tree_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut UseTree) { + match *_i { + UseTree::Path(ref mut _binding_0) => { + _visitor.visit_use_path_mut(_binding_0); + } + UseTree::Name(ref mut _binding_0) => { + _visitor.visit_use_name_mut(_binding_0); + } + UseTree::Rename(ref mut _binding_0) => { + _visitor.visit_use_rename_mut(_binding_0); + } + UseTree::Glob(ref mut _binding_0) => { + _visitor.visit_use_glob_mut(_binding_0); + } + UseTree::Group(ref mut _binding_0) => { + _visitor.visit_use_group_mut(_binding_0); + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_variant_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Variant) { + for it in &mut _i.attrs { + _visitor.visit_attribute_mut(it) + } + _visitor.visit_ident_mut(&mut _i.ident); + _visitor.visit_fields_mut(&mut _i.fields); + if let Some(ref mut it) = _i.discriminant { + tokens_helper(_visitor, &mut (it).0.spans); + _visitor.visit_expr_mut(&mut (it).1); + }; +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_crate_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisCrate) { + tokens_helper(_visitor, &mut _i.crate_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_public_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisPublic) { + tokens_helper(_visitor, &mut _i.pub_token.span); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_vis_restricted_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut VisRestricted) { + tokens_helper(_visitor, &mut _i.pub_token.span); + tokens_helper(_visitor, &mut _i.paren_token.span); + if let Some(ref mut it) = _i.in_token { + tokens_helper(_visitor, &mut it.span) + }; + _visitor.visit_path_mut(&mut *_i.path); +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_visibility_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Visibility) { + match *_i { + Visibility::Public(ref mut _binding_0) => { + _visitor.visit_vis_public_mut(_binding_0); + } + Visibility::Crate(ref mut _binding_0) => { + _visitor.visit_vis_crate_mut(_binding_0); + } + Visibility::Restricted(ref mut _binding_0) => { + _visitor.visit_vis_restricted_mut(_binding_0); + } + Visibility::Inherited => {} + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_clause_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut WhereClause) { + tokens_helper(_visitor, &mut _i.where_token.span); + for mut el in Punctuated::pairs_mut(&mut _i.predicates) { + let it = el.value_mut(); + _visitor.visit_where_predicate_mut(it) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +pub fn visit_where_predicate_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut WherePredicate) { + match *_i { + WherePredicate::Type(ref mut _binding_0) => { + _visitor.visit_predicate_type_mut(_binding_0); + } + WherePredicate::Lifetime(ref mut _binding_0) => { + _visitor.visit_predicate_lifetime_mut(_binding_0); + } + WherePredicate::Eq(ref mut _binding_0) => { + _visitor.visit_predicate_eq_mut(_binding_0); + } + } +} +pub fn visit_span_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Span) {} +pub fn visit_ident_mut<V: VisitMut + ?Sized>(_visitor: &mut V, _i: &mut Ident) {} diff --git a/syn/src/gen_helper.rs b/syn/src/gen_helper.rs new file mode 100644 index 000000000..b15b42be1 --- /dev/null +++ b/syn/src/gen_helper.rs @@ -0,0 +1,154 @@ +#[cfg(feature = "fold")] +pub mod fold { + use fold::Fold; + use proc_macro2::Span; + use punctuated::{Pair, Punctuated}; + + pub trait FoldHelper { + type Item; + fn lift<F>(self, f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item; + } + + impl<T> FoldHelper for Vec<T> { + type Item = T; + fn lift<F>(self, f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item, + { + self.into_iter().map(f).collect() + } + } + + impl<T, U> FoldHelper for Punctuated<T, U> { + type Item = T; + fn lift<F>(self, mut f: F) -> Self + where + F: FnMut(Self::Item) -> Self::Item, + { + self.into_pairs() + .map(Pair::into_tuple) + .map(|(t, u)| Pair::new(f(t), u)) + .collect() + } + } + + pub fn tokens_helper<F: Fold + ?Sized, S: Spans>(folder: &mut F, spans: &S) -> S { + spans.fold(folder) + } + + pub trait Spans { + fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self; + } + + impl Spans for Span { + fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self { + folder.fold_span(*self) + } + } + + impl Spans for [Span; 1] { + fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self { + [folder.fold_span(self[0])] + } + } + + impl Spans for [Span; 2] { + fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self { + [folder.fold_span(self[0]), folder.fold_span(self[1])] + } + } + + impl Spans for [Span; 3] { + fn fold<F: Fold + ?Sized>(&self, folder: &mut F) -> Self { + [ + folder.fold_span(self[0]), + folder.fold_span(self[1]), + folder.fold_span(self[2]), + ] + } + } +} + +#[cfg(feature = "visit")] +pub mod visit { + use proc_macro2::Span; + use visit::Visit; + + pub fn tokens_helper<'ast, V: Visit<'ast> + ?Sized, S: Spans>(visitor: &mut V, spans: &'ast S) { + spans.visit(visitor); + } + + pub trait Spans { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V); + } + + impl Spans for Span { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) { + visitor.visit_span(self); + } + } + + impl Spans for [Span; 1] { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) { + visitor.visit_span(&self[0]); + } + } + + impl Spans for [Span; 2] { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) { + visitor.visit_span(&self[0]); + visitor.visit_span(&self[1]); + } + } + + impl Spans for [Span; 3] { + fn visit<'ast, V: Visit<'ast> + ?Sized>(&'ast self, visitor: &mut V) { + visitor.visit_span(&self[0]); + visitor.visit_span(&self[1]); + visitor.visit_span(&self[2]); + } + } +} + +#[cfg(feature = "visit-mut")] +pub mod visit_mut { + use proc_macro2::Span; + use visit_mut::VisitMut; + + pub fn tokens_helper<V: VisitMut + ?Sized, S: Spans>(visitor: &mut V, spans: &mut S) { + spans.visit_mut(visitor); + } + + pub trait Spans { + fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V); + } + + impl Spans for Span { + fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) { + visitor.visit_span_mut(self); + } + } + + impl Spans for [Span; 1] { + fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) { + visitor.visit_span_mut(&mut self[0]); + } + } + + impl Spans for [Span; 2] { + fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) { + visitor.visit_span_mut(&mut self[0]); + visitor.visit_span_mut(&mut self[1]); + } + } + + impl Spans for [Span; 3] { + fn visit_mut<V: VisitMut + ?Sized>(&mut self, visitor: &mut V) { + visitor.visit_span_mut(&mut self[0]); + visitor.visit_span_mut(&mut self[1]); + visitor.visit_span_mut(&mut self[2]); + } + } +} diff --git a/syn/src/generics.rs b/syn/src/generics.rs new file mode 100644 index 000000000..59c7c4523 --- /dev/null +++ b/syn/src/generics.rs @@ -0,0 +1,1116 @@ +use super::*; +use punctuated::{Iter, IterMut, Punctuated}; + +ast_struct! { + /// Lifetimes and type parameters attached to a declaration of a function, + /// enum, trait, etc. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + #[derive(Default)] + pub struct Generics { + pub lt_token: Option<Token![<]>, + pub params: Punctuated<GenericParam, Token![,]>, + pub gt_token: Option<Token![>]>, + pub where_clause: Option<WhereClause>, + } +} + +ast_enum_of_structs! { + /// A generic type parameter, lifetime, or const generic: `T: Into<String>`, + /// `'a: 'b`, `const LEN: usize`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum GenericParam { + /// A generic type parameter: `T: Into<String>`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Type(TypeParam { + pub attrs: Vec<Attribute>, + pub ident: Ident, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub eq_token: Option<Token![=]>, + pub default: Option<Type>, + }), + + /// A lifetime definition: `'a: 'b + 'c + 'd`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Lifetime(LifetimeDef { + pub attrs: Vec<Attribute>, + pub lifetime: Lifetime, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<Lifetime, Token![+]>, + }), + + /// A const generic parameter: `const LENGTH: usize`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Const(ConstParam { + pub attrs: Vec<Attribute>, + pub const_token: Token![const], + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Type, + pub eq_token: Option<Token![=]>, + pub default: Option<Expr>, + }), + } +} + +impl Generics { + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &</code><a + /// href="struct.TypeParam.html"><code + /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code + /// style="padding-left:0;">></code> + /// over the type parameters in `self.params`. + pub fn type_params(&self) -> TypeParams { + TypeParams(self.params.iter()) + } + + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &mut </code><a + /// href="struct.TypeParam.html"><code + /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code + /// style="padding-left:0;">></code> + /// over the type parameters in `self.params`. + pub fn type_params_mut(&mut self) -> TypeParamsMut { + TypeParamsMut(self.params.iter_mut()) + } + + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &</code><a + /// href="struct.LifetimeDef.html"><code + /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code + /// style="padding-left:0;">></code> + /// over the lifetime parameters in `self.params`. + pub fn lifetimes(&self) -> Lifetimes { + Lifetimes(self.params.iter()) + } + + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &mut </code><a + /// href="struct.LifetimeDef.html"><code + /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code + /// style="padding-left:0;">></code> + /// over the lifetime parameters in `self.params`. + pub fn lifetimes_mut(&mut self) -> LifetimesMut { + LifetimesMut(self.params.iter_mut()) + } + + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &</code><a + /// href="struct.ConstParam.html"><code + /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code + /// style="padding-left:0;">></code> + /// over the constant parameters in `self.params`. + pub fn const_params(&self) -> ConstParams { + ConstParams(self.params.iter()) + } + + /// Returns an + /// <code + /// style="padding-right:0;">Iterator<Item = &mut </code><a + /// href="struct.ConstParam.html"><code + /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code + /// style="padding-left:0;">></code> + /// over the constant parameters in `self.params`. + pub fn const_params_mut(&mut self) -> ConstParamsMut { + ConstParamsMut(self.params.iter_mut()) + } + + /// Initializes an empty `where`-clause if there is not one present already. + pub fn make_where_clause(&mut self) -> &mut WhereClause { + // This is Option::get_or_insert_with in Rust 1.20. + if self.where_clause.is_none() { + self.where_clause = Some(WhereClause { + where_token: <Token![where]>::default(), + predicates: Punctuated::new(), + }); + } + match self.where_clause { + Some(ref mut where_clause) => where_clause, + None => unreachable!(), + } + } +} + +pub struct TypeParams<'a>(Iter<'a, GenericParam>); + +impl<'a> Iterator for TypeParams<'a> { + type Item = &'a TypeParam; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Type(ref type_param) = *next { + Some(type_param) + } else { + self.next() + } + } +} + +pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>); + +impl<'a> Iterator for TypeParamsMut<'a> { + type Item = &'a mut TypeParam; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Type(ref mut type_param) = *next { + Some(type_param) + } else { + self.next() + } + } +} + +pub struct Lifetimes<'a>(Iter<'a, GenericParam>); + +impl<'a> Iterator for Lifetimes<'a> { + type Item = &'a LifetimeDef; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Lifetime(ref lifetime) = *next { + Some(lifetime) + } else { + self.next() + } + } +} + +pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>); + +impl<'a> Iterator for LifetimesMut<'a> { + type Item = &'a mut LifetimeDef; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Lifetime(ref mut lifetime) = *next { + Some(lifetime) + } else { + self.next() + } + } +} + +pub struct ConstParams<'a>(Iter<'a, GenericParam>); + +impl<'a> Iterator for ConstParams<'a> { + type Item = &'a ConstParam; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Const(ref const_param) = *next { + Some(const_param) + } else { + self.next() + } + } +} + +pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>); + +impl<'a> Iterator for ConstParamsMut<'a> { + type Item = &'a mut ConstParam; + + fn next(&mut self) -> Option<Self::Item> { + let next = match self.0.next() { + Some(item) => item, + None => return None, + }; + if let GenericParam::Const(ref mut const_param) = *next { + Some(const_param) + } else { + self.next() + } + } +} + +/// Returned by `Generics::split_for_impl`. +/// +/// *This type is available if Syn is built with the `"derive"` or `"full"` +/// feature and the `"printing"` feature.* +#[cfg(feature = "printing")] +#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] +#[cfg_attr(feature = "clone-impls", derive(Clone))] +pub struct ImplGenerics<'a>(&'a Generics); + +/// Returned by `Generics::split_for_impl`. +/// +/// *This type is available if Syn is built with the `"derive"` or `"full"` +/// feature and the `"printing"` feature.* +#[cfg(feature = "printing")] +#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] +#[cfg_attr(feature = "clone-impls", derive(Clone))] +pub struct TypeGenerics<'a>(&'a Generics); + +/// Returned by `TypeGenerics::as_turbofish`. +/// +/// *This type is available if Syn is built with the `"derive"` or `"full"` +/// feature and the `"printing"` feature.* +#[cfg(feature = "printing")] +#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] +#[cfg_attr(feature = "clone-impls", derive(Clone))] +pub struct Turbofish<'a>(&'a Generics); + +#[cfg(feature = "printing")] +impl Generics { + /// Split a type's generics into the pieces required for impl'ing a trait + /// for that type. + /// + /// ```edition2018 + /// # use proc_macro2::{Span, Ident}; + /// # use quote::quote; + /// # + /// # fn main() { + /// # let generics: syn::Generics = Default::default(); + /// # let name = Ident::new("MyType", Span::call_site()); + /// # + /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + /// quote! { + /// impl #impl_generics MyTrait for #name #ty_generics #where_clause { + /// // ... + /// } + /// } + /// # ; + /// # } + /// ``` + /// + /// *This method is available if Syn is built with the `"derive"` or + /// `"full"` feature and the `"printing"` feature.* + pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) { + ( + ImplGenerics(self), + TypeGenerics(self), + self.where_clause.as_ref(), + ) + } +} + +#[cfg(feature = "printing")] +impl<'a> TypeGenerics<'a> { + /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`. + /// + /// *This method is available if Syn is built with the `"derive"` or + /// `"full"` feature and the `"printing"` feature.* + pub fn as_turbofish(&self) -> Turbofish { + Turbofish(self.0) + } +} + +ast_struct! { + /// A set of bound lifetimes: `for<'a, 'b, 'c>`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + #[derive(Default)] + pub struct BoundLifetimes { + pub for_token: Token![for], + pub lt_token: Token![<], + pub lifetimes: Punctuated<LifetimeDef, Token![,]>, + pub gt_token: Token![>], + } +} + +impl LifetimeDef { + pub fn new(lifetime: Lifetime) -> Self { + LifetimeDef { + attrs: Vec::new(), + lifetime: lifetime, + colon_token: None, + bounds: Punctuated::new(), + } + } +} + +impl From<Ident> for TypeParam { + fn from(ident: Ident) -> Self { + TypeParam { + attrs: vec![], + ident: ident, + colon_token: None, + bounds: Punctuated::new(), + eq_token: None, + default: None, + } + } +} + +ast_enum_of_structs! { + /// A trait or lifetime used as a bound on a type parameter. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum TypeParamBound { + pub Trait(TraitBound), + pub Lifetime(Lifetime), + } +} + +ast_struct! { + /// A trait used as a bound on a type parameter. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct TraitBound { + pub paren_token: Option<token::Paren>, + pub modifier: TraitBoundModifier, + /// The `for<'a>` in `for<'a> Foo<&'a T>` + pub lifetimes: Option<BoundLifetimes>, + /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>` + pub path: Path, + } +} + +ast_enum! { + /// A modifier on a trait bound, currently only used for the `?` in + /// `?Sized`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + #[cfg_attr(feature = "clone-impls", derive(Copy))] + pub enum TraitBoundModifier { + None, + Maybe(Token![?]), + } +} + +ast_struct! { + /// A `where` clause in a definition: `where T: Deserialize<'de>, D: + /// 'static`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct WhereClause { + pub where_token: Token![where], + pub predicates: Punctuated<WherePredicate, Token![,]>, + } +} + +ast_enum_of_structs! { + /// A single predicate in a `where` clause: `T: Deserialize<'de>`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum WherePredicate { + /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Type(PredicateType { + /// Any lifetimes from a `for` binding + pub lifetimes: Option<BoundLifetimes>, + /// The type being bounded + pub bounded_ty: Type, + pub colon_token: Token![:], + /// Trait and lifetime bounds (`Clone+Send+'static`) + pub bounds: Punctuated<TypeParamBound, Token![+]>, + }), + + /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Lifetime(PredicateLifetime { + pub lifetime: Lifetime, + pub colon_token: Token![:], + pub bounds: Punctuated<Lifetime, Token![+]>, + }), + + /// An equality predicate in a `where` clause (unsupported). + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Eq(PredicateEq { + pub lhs_ty: Type, + pub eq_token: Token![=], + pub rhs_ty: Type, + }), + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + impl Parse for Generics { + fn parse(input: ParseStream) -> Result<Self> { + if !input.peek(Token![<]) { + return Ok(Generics::default()); + } + + let lt_token: Token![<] = input.parse()?; + + let mut params = Punctuated::new(); + let mut has_type_param = false; + loop { + if input.peek(Token![>]) { + break; + } + + let attrs = input.call(Attribute::parse_outer)?; + let lookahead = input.lookahead1(); + if !has_type_param && lookahead.peek(Lifetime) { + params.push_value(GenericParam::Lifetime(LifetimeDef { + attrs: attrs, + ..input.parse()? + })); + } else if lookahead.peek(Ident) { + has_type_param = true; + params.push_value(GenericParam::Type(TypeParam { + attrs: attrs, + ..input.parse()? + })); + } else { + return Err(lookahead.error()); + } + + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + params.push_punct(punct); + } + + let gt_token: Token![>] = input.parse()?; + + Ok(Generics { + lt_token: Some(lt_token), + params: params, + gt_token: Some(gt_token), + where_clause: None, + }) + } + } + + impl Parse for GenericParam { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) { + Ok(GenericParam::Type(TypeParam { + attrs: attrs, + ..input.parse()? + })) + } else if lookahead.peek(Lifetime) { + Ok(GenericParam::Lifetime(LifetimeDef { + attrs: attrs, + ..input.parse()? + })) + } else if lookahead.peek(Token![const]) { + Ok(GenericParam::Const(ConstParam { + attrs: attrs, + ..input.parse()? + })) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for LifetimeDef { + fn parse(input: ParseStream) -> Result<Self> { + let has_colon; + Ok(LifetimeDef { + attrs: input.call(Attribute::parse_outer)?, + lifetime: input.parse()?, + colon_token: { + if input.peek(Token![:]) { + has_colon = true; + Some(input.parse()?) + } else { + has_colon = false; + None + } + }, + bounds: { + let mut bounds = Punctuated::new(); + if has_colon { + loop { + if input.peek(Token![,]) || input.peek(Token![>]) { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + } + bounds + }, + }) + } + } + + impl Parse for BoundLifetimes { + fn parse(input: ParseStream) -> Result<Self> { + Ok(BoundLifetimes { + for_token: input.parse()?, + lt_token: input.parse()?, + lifetimes: { + let mut lifetimes = Punctuated::new(); + while !input.peek(Token![>]) { + lifetimes.push_value(input.parse()?); + if input.peek(Token![>]) { + break; + } + lifetimes.push_punct(input.parse()?); + } + lifetimes + }, + gt_token: input.parse()?, + }) + } + } + + impl Parse for Option<BoundLifetimes> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![for]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + impl Parse for TypeParam { + fn parse(input: ParseStream) -> Result<Self> { + let has_colon; + let has_default; + Ok(TypeParam { + attrs: input.call(Attribute::parse_outer)?, + ident: input.parse()?, + colon_token: { + if input.peek(Token![:]) { + has_colon = true; + Some(input.parse()?) + } else { + has_colon = false; + None + } + }, + bounds: { + let mut bounds = Punctuated::new(); + if has_colon { + loop { + if input.peek(Token![,]) + || input.peek(Token![>]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + } + bounds + }, + eq_token: { + if input.peek(Token![=]) { + has_default = true; + Some(input.parse()?) + } else { + has_default = false; + None + } + }, + default: { + if has_default { + Some(input.parse()?) + } else { + None + } + }, + }) + } + } + + impl Parse for TypeParamBound { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) { + return input.parse().map(TypeParamBound::Lifetime); + } + + if input.peek(token::Paren) { + let content; + let paren_token = parenthesized!(content in input); + let mut bound: TraitBound = content.parse()?; + bound.paren_token = Some(paren_token); + return Ok(TypeParamBound::Trait(bound)); + } + + input.parse().map(TypeParamBound::Trait) + } + } + + impl Parse for TraitBound { + fn parse(input: ParseStream) -> Result<Self> { + let modifier: TraitBoundModifier = input.parse()?; + let lifetimes: Option<BoundLifetimes> = input.parse()?; + + let mut path: Path = input.parse()?; + if path.segments.last().unwrap().value().arguments.is_empty() + && input.peek(token::Paren) + { + let parenthesized = PathArguments::Parenthesized(input.parse()?); + path.segments.last_mut().unwrap().value_mut().arguments = parenthesized; + } + + Ok(TraitBound { + paren_token: None, + modifier: modifier, + lifetimes: lifetimes, + path: path, + }) + } + } + + impl Parse for TraitBoundModifier { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![?]) { + input.parse().map(TraitBoundModifier::Maybe) + } else { + Ok(TraitBoundModifier::None) + } + } + } + + impl Parse for ConstParam { + fn parse(input: ParseStream) -> Result<Self> { + let mut default = None; + Ok(ConstParam { + attrs: input.call(Attribute::parse_outer)?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: { + if input.peek(Token![=]) { + let eq_token = input.parse()?; + default = Some(input.parse::<Expr>()?); + Some(eq_token) + } else { + None + } + }, + default: default, + }) + } + } + + impl Parse for WhereClause { + fn parse(input: ParseStream) -> Result<Self> { + Ok(WhereClause { + where_token: input.parse()?, + predicates: { + let mut predicates = Punctuated::new(); + loop { + if input.is_empty() + || input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) && !input.peek(Token![::]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + predicates.push_value(value); + if !input.peek(Token![,]) { + break; + } + let punct = input.parse()?; + predicates.push_punct(punct); + } + predicates + }, + }) + } + } + + impl Parse for Option<WhereClause> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![where]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } + + impl Parse for WherePredicate { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) && input.peek2(Token![:]) { + Ok(WherePredicate::Lifetime(PredicateLifetime { + lifetime: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + })) + } else { + Ok(WherePredicate::Type(PredicateType { + lifetimes: input.parse()?, + bounded_ty: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.peek(token::Brace) + || input.peek(Token![,]) + || input.peek(Token![;]) + || input.peek(Token![:]) && !input.peek(Token![::]) + || input.peek(Token![=]) + { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + })) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use attr::FilterAttrs; + use print::TokensOrDefault; + + impl ToTokens for Generics { + fn to_tokens(&self, tokens: &mut TokenStream) { + if self.params.is_empty() { + return; + } + + TokensOrDefault(&self.lt_token).to_tokens(tokens); + + // Print lifetimes before types and consts, regardless of their + // order in self.params. + // + // TODO: ordering rules for const parameters vs type parameters have + // not been settled yet. https://github.com/rust-lang/rust/issues/44580 + let mut trailing_or_empty = true; + for param in self.params.pairs() { + if let GenericParam::Lifetime(_) = **param.value() { + param.to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + } + for param in self.params.pairs() { + match **param.value() { + GenericParam::Type(_) | GenericParam::Const(_) => { + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + trailing_or_empty = true; + } + param.to_tokens(tokens); + } + GenericParam::Lifetime(_) => {} + } + } + + TokensOrDefault(&self.gt_token).to_tokens(tokens); + } + } + + impl<'a> ToTokens for ImplGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if self.0.params.is_empty() { + return; + } + + TokensOrDefault(&self.0.lt_token).to_tokens(tokens); + + // Print lifetimes before types and consts, regardless of their + // order in self.params. + // + // TODO: ordering rules for const parameters vs type parameters have + // not been settled yet. https://github.com/rust-lang/rust/issues/44580 + let mut trailing_or_empty = true; + for param in self.0.params.pairs() { + if let GenericParam::Lifetime(_) = **param.value() { + param.to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + } + for param in self.0.params.pairs() { + if let GenericParam::Lifetime(_) = **param.value() { + continue; + } + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + trailing_or_empty = true; + } + match **param.value() { + GenericParam::Lifetime(_) => unreachable!(), + GenericParam::Type(ref param) => { + // Leave off the type parameter defaults + tokens.append_all(param.attrs.outer()); + param.ident.to_tokens(tokens); + if !param.bounds.is_empty() { + TokensOrDefault(¶m.colon_token).to_tokens(tokens); + param.bounds.to_tokens(tokens); + } + } + GenericParam::Const(ref param) => { + // Leave off the const parameter defaults + tokens.append_all(param.attrs.outer()); + param.const_token.to_tokens(tokens); + param.ident.to_tokens(tokens); + param.colon_token.to_tokens(tokens); + param.ty.to_tokens(tokens); + } + } + param.punct().to_tokens(tokens); + } + + TokensOrDefault(&self.0.gt_token).to_tokens(tokens); + } + } + + impl<'a> ToTokens for TypeGenerics<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if self.0.params.is_empty() { + return; + } + + TokensOrDefault(&self.0.lt_token).to_tokens(tokens); + + // Print lifetimes before types and consts, regardless of their + // order in self.params. + // + // TODO: ordering rules for const parameters vs type parameters have + // not been settled yet. https://github.com/rust-lang/rust/issues/44580 + let mut trailing_or_empty = true; + for param in self.0.params.pairs() { + if let GenericParam::Lifetime(ref def) = **param.value() { + // Leave off the lifetime bounds and attributes + def.lifetime.to_tokens(tokens); + param.punct().to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + } + for param in self.0.params.pairs() { + if let GenericParam::Lifetime(_) = **param.value() { + continue; + } + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + trailing_or_empty = true; + } + match **param.value() { + GenericParam::Lifetime(_) => unreachable!(), + GenericParam::Type(ref param) => { + // Leave off the type parameter defaults + param.ident.to_tokens(tokens); + } + GenericParam::Const(ref param) => { + // Leave off the const parameter defaults + param.ident.to_tokens(tokens); + } + } + param.punct().to_tokens(tokens); + } + + TokensOrDefault(&self.0.gt_token).to_tokens(tokens); + } + } + + impl<'a> ToTokens for Turbofish<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if !self.0.params.is_empty() { + <Token![::]>::default().to_tokens(tokens); + TypeGenerics(self.0).to_tokens(tokens); + } + } + } + + impl ToTokens for BoundLifetimes { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.for_token.to_tokens(tokens); + self.lt_token.to_tokens(tokens); + self.lifetimes.to_tokens(tokens); + self.gt_token.to_tokens(tokens); + } + } + + impl ToTokens for LifetimeDef { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.lifetime.to_tokens(tokens); + if !self.bounds.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + } + + impl ToTokens for TypeParam { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.ident.to_tokens(tokens); + if !self.bounds.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + if self.default.is_some() { + TokensOrDefault(&self.eq_token).to_tokens(tokens); + self.default.to_tokens(tokens); + } + } + } + + impl ToTokens for TraitBound { + fn to_tokens(&self, tokens: &mut TokenStream) { + let to_tokens = |tokens: &mut TokenStream| { + self.modifier.to_tokens(tokens); + self.lifetimes.to_tokens(tokens); + self.path.to_tokens(tokens); + }; + match self.paren_token { + Some(ref paren) => paren.surround(tokens, to_tokens), + None => to_tokens(tokens), + } + } + } + + impl ToTokens for TraitBoundModifier { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + TraitBoundModifier::None => {} + TraitBoundModifier::Maybe(ref t) => t.to_tokens(tokens), + } + } + } + + impl ToTokens for ConstParam { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.const_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + if self.default.is_some() { + TokensOrDefault(&self.eq_token).to_tokens(tokens); + self.default.to_tokens(tokens); + } + } + } + + impl ToTokens for WhereClause { + fn to_tokens(&self, tokens: &mut TokenStream) { + if !self.predicates.is_empty() { + self.where_token.to_tokens(tokens); + self.predicates.to_tokens(tokens); + } + } + } + + impl ToTokens for PredicateType { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lifetimes.to_tokens(tokens); + self.bounded_ty.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + + impl ToTokens for PredicateLifetime { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lifetime.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + + impl ToTokens for PredicateEq { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lhs_ty.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.rhs_ty.to_tokens(tokens); + } + } +} diff --git a/syn/src/group.rs b/syn/src/group.rs new file mode 100644 index 000000000..272e435f2 --- /dev/null +++ b/syn/src/group.rs @@ -0,0 +1,283 @@ +use proc_macro2::{Delimiter, Span}; + +use error::Result; +use parse::{ParseBuffer, ParseStream}; +use private; +use token; + +// Not public API. +#[doc(hidden)] +pub struct Parens<'a> { + pub token: token::Paren, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub struct Braces<'a> { + pub token: token::Brace, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub struct Brackets<'a> { + pub token: token::Bracket, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[cfg(any(feature = "full", feature = "derive"))] +#[doc(hidden)] +pub struct Group<'a> { + pub token: token::Group, + pub content: ParseBuffer<'a>, +} + +// Not public API. +#[doc(hidden)] +pub fn parse_parens(input: ParseStream) -> Result<Parens> { + parse_delimited(input, Delimiter::Parenthesis).map(|(span, content)| Parens { + token: token::Paren(span), + content: content, + }) +} + +// Not public API. +#[doc(hidden)] +pub fn parse_braces(input: ParseStream) -> Result<Braces> { + parse_delimited(input, Delimiter::Brace).map(|(span, content)| Braces { + token: token::Brace(span), + content: content, + }) +} + +// Not public API. +#[doc(hidden)] +pub fn parse_brackets(input: ParseStream) -> Result<Brackets> { + parse_delimited(input, Delimiter::Bracket).map(|(span, content)| Brackets { + token: token::Bracket(span), + content: content, + }) +} + +#[cfg(any(feature = "full", feature = "derive"))] +impl private { + pub fn parse_group(input: ParseStream) -> Result<Group> { + parse_delimited(input, Delimiter::None).map(|(span, content)| Group { + token: token::Group(span), + content: content, + }) + } +} + +fn parse_delimited(input: ParseStream, delimiter: Delimiter) -> Result<(Span, ParseBuffer)> { + input.step(|cursor| { + if let Some((content, span, rest)) = cursor.group(delimiter) { + #[cfg(procmacro2_semver_exempt)] + let scope = private::close_span_of_group(*cursor); + #[cfg(not(procmacro2_semver_exempt))] + let scope = span; + let nested = private::advance_step_cursor(cursor, content); + let unexpected = private::get_unexpected(input); + let content = private::new_parse_buffer(scope, nested, unexpected); + Ok(((span, content), rest)) + } else { + let message = match delimiter { + Delimiter::Parenthesis => "expected parentheses", + Delimiter::Brace => "expected curly braces", + Delimiter::Bracket => "expected square brackets", + Delimiter::None => "expected invisible group", + }; + Err(cursor.error(message)) + } + }) +} + +/// Parse a set of parentheses and expose their content to subsequent parsers. +/// +/// # Example +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// use syn::{parenthesized, token, Ident, Result, Token, Type}; +/// use syn::parse::{Parse, ParseStream}; +/// use syn::punctuated::Punctuated; +/// +/// // Parse a simplified tuple struct syntax like: +/// // +/// // struct S(A, B); +/// struct TupleStruct { +/// struct_token: Token![struct], +/// ident: Ident, +/// paren_token: token::Paren, +/// fields: Punctuated<Type, Token![,]>, +/// semi_token: Token![;], +/// } +/// +/// impl Parse for TupleStruct { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(TupleStruct { +/// struct_token: input.parse()?, +/// ident: input.parse()?, +/// paren_token: parenthesized!(content in input), +/// fields: content.parse_terminated(Type::parse)?, +/// semi_token: input.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # struct S(A, B); +/// # }; +/// # syn::parse2::<TupleStruct>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! parenthesized { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_parens(&$cursor) { + $crate::export::Ok(parens) => { + $content = parens.content; + parens.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} + +/// Parse a set of curly braces and expose their content to subsequent parsers. +/// +/// # Example +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// use syn::{braced, token, Ident, Result, Token, Type}; +/// use syn::parse::{Parse, ParseStream}; +/// use syn::punctuated::Punctuated; +/// +/// // Parse a simplified struct syntax like: +/// // +/// // struct S { +/// // a: A, +/// // b: B, +/// // } +/// struct Struct { +/// struct_token: Token![struct], +/// ident: Ident, +/// brace_token: token::Brace, +/// fields: Punctuated<Field, Token![,]>, +/// } +/// +/// struct Field { +/// name: Ident, +/// colon_token: Token![:], +/// ty: Type, +/// } +/// +/// impl Parse for Struct { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(Struct { +/// struct_token: input.parse()?, +/// ident: input.parse()?, +/// brace_token: braced!(content in input), +/// fields: content.parse_terminated(Field::parse)?, +/// }) +/// } +/// } +/// +/// impl Parse for Field { +/// fn parse(input: ParseStream) -> Result<Self> { +/// Ok(Field { +/// name: input.parse()?, +/// colon_token: input.parse()?, +/// ty: input.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # struct S { +/// # a: A, +/// # b: B, +/// # } +/// # }; +/// # syn::parse2::<Struct>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! braced { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_braces(&$cursor) { + $crate::export::Ok(braces) => { + $content = braces.content; + braces.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} + +/// Parse a set of square brackets and expose their content to subsequent +/// parsers. +/// +/// # Example +/// +/// ```edition2018 +/// # use quote::quote; +/// # +/// use proc_macro2::TokenStream; +/// use syn::{bracketed, token, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// // Parse an outer attribute like: +/// // +/// // #[repr(C, packed)] +/// struct OuterAttribute { +/// pound_token: Token![#], +/// bracket_token: token::Bracket, +/// content: TokenStream, +/// } +/// +/// impl Parse for OuterAttribute { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let content; +/// Ok(OuterAttribute { +/// pound_token: input.parse()?, +/// bracket_token: bracketed!(content in input), +/// content: content.parse()?, +/// }) +/// } +/// } +/// # +/// # fn main() { +/// # let input = quote! { +/// # #[repr(C, packed)] +/// # }; +/// # syn::parse2::<OuterAttribute>(input).unwrap(); +/// # } +/// ``` +#[macro_export] +macro_rules! bracketed { + ($content:ident in $cursor:expr) => { + match $crate::group::parse_brackets(&$cursor) { + $crate::export::Ok(brackets) => { + $content = brackets.content; + brackets.token + } + $crate::export::Err(error) => { + return $crate::export::Err(error); + } + } + }; +} diff --git a/syn/src/ident.rs b/syn/src/ident.rs new file mode 100644 index 000000000..f5a76a1de --- /dev/null +++ b/syn/src/ident.rs @@ -0,0 +1,86 @@ +#[cfg(feature = "parsing")] +use buffer::Cursor; +#[cfg(feature = "parsing")] +use lookahead; +#[cfg(feature = "parsing")] +use parse::{Parse, ParseStream, Result}; +#[cfg(feature = "parsing")] +use token::Token; + +pub use proc_macro2::Ident; + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Ident(marker: lookahead::TokenMarker) -> Ident { + match marker {} +} + +#[cfg(feature = "parsing")] +fn accept_as_ident(ident: &Ident) -> bool { + match ident.to_string().as_str() { + "_" + // Based on https://doc.rust-lang.org/grammar.html#keywords + // and https://github.com/rust-lang/rfcs/blob/master/text/2421-unreservations-2018.md + // and https://github.com/rust-lang/rfcs/blob/master/text/2420-unreserve-proc.md + | "abstract" | "as" | "become" | "box" | "break" | "const" + | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" + | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" + | "mod" | "move" | "mut" | "override" | "priv" | "pub" + | "ref" | "return" | "Self" | "self" | "static" | "struct" + | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" + | "virtual" | "where" | "while" | "yield" => false, + _ => true, + } +} + +#[cfg(feature = "parsing")] +impl Parse for Ident { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if accept_as_ident(&ident) { + return Ok((ident, rest)); + } + } + Err(cursor.error("expected identifier")) + }) + } +} + +#[cfg(feature = "parsing")] +impl Token for Ident { + fn peek(cursor: Cursor) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + accept_as_ident(&ident) + } else { + false + } + } + + fn display() -> &'static str { + "identifier" + } +} + +macro_rules! ident_from_token { + ($token:ident) => { + impl From<Token![$token]> for Ident { + fn from(token: Token![$token]) -> Ident { + Ident::new(stringify!($token), token.span) + } + } + }; +} + +ident_from_token!(self); +ident_from_token!(Self); +ident_from_token!(super); +ident_from_token!(crate); +ident_from_token!(extern); + +impl From<Token![_]> for Ident { + fn from(token: Token![_]) -> Ident { + Ident::new("_", token.span) + } +} diff --git a/syn/src/item.rs b/syn/src/item.rs new file mode 100644 index 000000000..118ed4e17 --- /dev/null +++ b/syn/src/item.rs @@ -0,0 +1,2677 @@ +use super::*; +use derive::{Data, DeriveInput}; +use proc_macro2::TokenStream; +use punctuated::Punctuated; +use token::{Brace, Paren}; + +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(feature = "extra-traits")] +use tt::TokenStreamHelper; + +ast_enum_of_structs! { + /// Things that can appear directly inside of a module or scope. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Item { + /// An `extern crate` item: `extern crate serde`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub ExternCrate(ItemExternCrate { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub extern_token: Token![extern], + pub crate_token: Token![crate], + pub ident: Ident, + pub rename: Option<(Token![as], Ident)>, + pub semi_token: Token![;], + }), + + /// A use declaration: `use std::collections::HashMap`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Use(ItemUse { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub use_token: Token![use], + pub leading_colon: Option<Token![::]>, + pub tree: UseTree, + pub semi_token: Token![;], + }), + + /// A static item: `static BIKE: Shed = Shed(42)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Static(ItemStatic { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub static_token: Token![static], + pub mutability: Option<Token![mut]>, + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Box<Type>, + pub eq_token: Token![=], + pub expr: Box<Expr>, + pub semi_token: Token![;], + }), + + /// A constant item: `const MAX: u16 = 65535`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Const(ItemConst { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub const_token: Token![const], + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Box<Type>, + pub eq_token: Token![=], + pub expr: Box<Expr>, + pub semi_token: Token![;], + }), + + /// A free-standing function: `fn process(n: usize) -> Result<()> { ... + /// }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Fn(ItemFn { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub constness: Option<Token![const]>, + pub unsafety: Option<Token![unsafe]>, + pub asyncness: Option<Token![async]>, + pub abi: Option<Abi>, + pub ident: Ident, + pub decl: Box<FnDecl>, + pub block: Box<Block>, + }), + + /// A module or module declaration: `mod m` or `mod m { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Mod(ItemMod { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub mod_token: Token![mod], + pub ident: Ident, + pub content: Option<(token::Brace, Vec<Item>)>, + pub semi: Option<Token![;]>, + }), + + /// A block of foreign items: `extern "C" { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub ForeignMod(ItemForeignMod { + pub attrs: Vec<Attribute>, + pub abi: Abi, + pub brace_token: token::Brace, + pub items: Vec<ForeignItem>, + }), + + /// A type alias: `type Result<T> = std::result::Result<T, MyError>`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Type(ItemType { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub type_token: Token![type], + pub ident: Ident, + pub generics: Generics, + pub eq_token: Token![=], + pub ty: Box<Type>, + pub semi_token: Token![;], + }), + + /// An existential type: `existential type Iter: Iterator<Item = u8>`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Existential(ItemExistential { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub existential_token: Token![existential], + pub type_token: Token![type], + pub ident: Ident, + pub generics: Generics, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub semi_token: Token![;], + }), + + /// A struct definition: `struct Foo<A> { x: A }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Struct(ItemStruct { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub struct_token: Token![struct], + pub ident: Ident, + pub generics: Generics, + pub fields: Fields, + pub semi_token: Option<Token![;]>, + }), + + /// An enum definition: `enum Foo<A, B> { C<A>, D<B> }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Enum(ItemEnum { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub enum_token: Token![enum], + pub ident: Ident, + pub generics: Generics, + pub brace_token: token::Brace, + pub variants: Punctuated<Variant, Token![,]>, + }), + + /// A union definition: `union Foo<A, B> { x: A, y: B }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Union(ItemUnion { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub union_token: Token![union], + pub ident: Ident, + pub generics: Generics, + pub fields: FieldsNamed, + }), + + /// A trait definition: `pub trait Iterator { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Trait(ItemTrait { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub unsafety: Option<Token![unsafe]>, + pub auto_token: Option<Token![auto]>, + pub trait_token: Token![trait], + pub ident: Ident, + pub generics: Generics, + pub colon_token: Option<Token![:]>, + pub supertraits: Punctuated<TypeParamBound, Token![+]>, + pub brace_token: token::Brace, + pub items: Vec<TraitItem>, + }), + + /// A trait alias: `pub trait SharableIterator = Iterator + Sync`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub TraitAlias(ItemTraitAlias { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub trait_token: Token![trait], + pub ident: Ident, + pub generics: Generics, + pub eq_token: Token![=], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub semi_token: Token![;], + }), + + /// An impl block providing trait or associated items: `impl<A> Trait + /// for Data<A> { ... }`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Impl(ItemImpl { + pub attrs: Vec<Attribute>, + pub defaultness: Option<Token![default]>, + pub unsafety: Option<Token![unsafe]>, + pub impl_token: Token![impl], + pub generics: Generics, + /// Trait this impl implements. + pub trait_: Option<(Option<Token![!]>, Path, Token![for])>, + /// The Self type of the impl. + pub self_ty: Box<Type>, + pub brace_token: token::Brace, + pub items: Vec<ImplItem>, + }), + + /// A macro invocation, which includes `macro_rules!` definitions. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(ItemMacro { + pub attrs: Vec<Attribute>, + /// The `example` in `macro_rules! example { ... }`. + pub ident: Option<Ident>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + }), + + /// A 2.0-style declarative macro introduced by the `macro` keyword. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro2(ItemMacro2 #manual_extra_traits { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub macro_token: Token![macro], + pub ident: Ident, + pub paren_token: Paren, + pub args: TokenStream, + pub brace_token: Brace, + pub body: TokenStream, + }), + + /// Tokens forming an item not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Verbatim(ItemVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ItemMacro2 {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ItemMacro2 { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.macro_token == other.macro_token + && self.ident == other.ident + && self.paren_token == other.paren_token + && TokenStreamHelper(&self.args) == TokenStreamHelper(&other.args) + && self.brace_token == other.brace_token + && TokenStreamHelper(&self.body) == TokenStreamHelper(&other.body) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ItemMacro2 { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.macro_token.hash(state); + self.ident.hash(state); + self.paren_token.hash(state); + TokenStreamHelper(&self.args).hash(state); + self.brace_token.hash(state); + TokenStreamHelper(&self.body).hash(state); + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ItemVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ItemVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ItemVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +impl From<DeriveInput> for Item { + fn from(input: DeriveInput) -> Item { + match input.data { + Data::Struct(data) => Item::Struct(ItemStruct { + attrs: input.attrs, + vis: input.vis, + struct_token: data.struct_token, + ident: input.ident, + generics: input.generics, + fields: data.fields, + semi_token: data.semi_token, + }), + Data::Enum(data) => Item::Enum(ItemEnum { + attrs: input.attrs, + vis: input.vis, + enum_token: data.enum_token, + ident: input.ident, + generics: input.generics, + brace_token: data.brace_token, + variants: data.variants, + }), + Data::Union(data) => Item::Union(ItemUnion { + attrs: input.attrs, + vis: input.vis, + union_token: data.union_token, + ident: input.ident, + generics: input.generics, + fields: data.fields, + }), + } + } +} + +ast_enum_of_structs! { + /// A suffix of an import tree in a `use` item: `Type as Renamed` or `*`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum UseTree { + /// A path prefix of imports in a `use` item: `std::...`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Path(UsePath { + pub ident: Ident, + pub colon2_token: Token![::], + pub tree: Box<UseTree>, + }), + + /// An identifier imported by a `use` item: `HashMap`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Name(UseName { + pub ident: Ident, + }), + + /// An renamed identifier imported by a `use` item: `HashMap as Map`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Rename(UseRename { + pub ident: Ident, + pub as_token: Token![as], + pub rename: Ident, + }), + + /// A glob import in a `use` item: `*`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Glob(UseGlob { + pub star_token: Token![*], + }), + + /// A braced group of imports in a `use` item: `{A, B, C}`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Group(UseGroup { + pub brace_token: token::Brace, + pub items: Punctuated<UseTree, Token![,]>, + }), + } +} + +ast_enum_of_structs! { + /// An item within an `extern` block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum ForeignItem { + /// A foreign function in an `extern` block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Fn(ForeignItemFn { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub ident: Ident, + pub decl: Box<FnDecl>, + pub semi_token: Token![;], + }), + + /// A foreign static item in an `extern` block: `static ext: u8`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Static(ForeignItemStatic { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub static_token: Token![static], + pub mutability: Option<Token![mut]>, + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Box<Type>, + pub semi_token: Token![;], + }), + + /// A foreign type in an `extern` block: `type void`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Type(ForeignItemType { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub type_token: Token![type], + pub ident: Ident, + pub semi_token: Token![;], + }), + + /// A macro invocation within an extern block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(ForeignItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + }), + + /// Tokens in an `extern` block not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Verbatim(ForeignItemVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ForeignItemVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ForeignItemVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ForeignItemVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +ast_enum_of_structs! { + /// An item declaration within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum TraitItem { + /// An associated constant within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Const(TraitItemConst { + pub attrs: Vec<Attribute>, + pub const_token: Token![const], + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Type, + pub default: Option<(Token![=], Expr)>, + pub semi_token: Token![;], + }), + + /// A trait method within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Method(TraitItemMethod { + pub attrs: Vec<Attribute>, + pub sig: MethodSig, + pub default: Option<Block>, + pub semi_token: Option<Token![;]>, + }), + + /// An associated type within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Type(TraitItemType { + pub attrs: Vec<Attribute>, + pub type_token: Token![type], + pub ident: Ident, + pub generics: Generics, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub default: Option<(Token![=], Type)>, + pub semi_token: Token![;], + }), + + /// A macro invocation within the definition of a trait. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(TraitItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + }), + + /// Tokens within the definition of a trait not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Verbatim(TraitItemVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for TraitItemVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for TraitItemVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for TraitItemVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +ast_enum_of_structs! { + /// An item within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum ImplItem { + /// An associated constant within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Const(ImplItemConst { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub defaultness: Option<Token![default]>, + pub const_token: Token![const], + pub ident: Ident, + pub colon_token: Token![:], + pub ty: Type, + pub eq_token: Token![=], + pub expr: Expr, + pub semi_token: Token![;], + }), + + /// A method within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Method(ImplItemMethod { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub defaultness: Option<Token![default]>, + pub sig: MethodSig, + pub block: Block, + }), + + /// An associated type within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Type(ImplItemType { + pub attrs: Vec<Attribute>, + pub vis: Visibility, + pub defaultness: Option<Token![default]>, + pub type_token: Token![type], + pub ident: Ident, + pub generics: Generics, + pub eq_token: Token![=], + pub ty: Type, + pub semi_token: Token![;], + }), + + /// An existential type within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Existential(ImplItemExistential { + pub attrs: Vec<Attribute>, + pub existential_token: Token![existential], + pub type_token: Token![type], + pub ident: Ident, + pub generics: Generics, + pub colon_token: Option<Token![:]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + pub semi_token: Token![;], + }), + + /// A macro invocation within an impl block. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Macro(ImplItemMacro { + pub attrs: Vec<Attribute>, + pub mac: Macro, + pub semi_token: Option<Token![;]>, + }), + + /// Tokens within an impl block not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Verbatim(ImplItemVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for ImplItemVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for ImplItemVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for ImplItemVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +ast_struct! { + /// A method's signature in a trait or implementation: `unsafe fn + /// initialize(&self)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct MethodSig { + pub constness: Option<Token![const]>, + pub unsafety: Option<Token![unsafe]>, + pub asyncness: Option<Token![async]>, + pub abi: Option<Abi>, + pub ident: Ident, + pub decl: FnDecl, + } +} + +ast_struct! { + /// Header of a function declaration, without including the body. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub struct FnDecl { + pub fn_token: Token![fn], + pub generics: Generics, + pub paren_token: token::Paren, + pub inputs: Punctuated<FnArg, Token![,]>, + pub variadic: Option<Token![...]>, + pub output: ReturnType, + } +} + +ast_enum_of_structs! { + /// An argument in a function signature: the `n: usize` in `fn f(n: usize)`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum FnArg { + /// Self captured by reference in a function signature: `&self` or `&mut + /// self`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub SelfRef(ArgSelfRef { + pub and_token: Token![&], + pub lifetime: Option<Lifetime>, + pub mutability: Option<Token![mut]>, + pub self_token: Token![self], + }), + + /// Self captured by value in a function signature: `self` or `mut + /// self`. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub SelfValue(ArgSelf { + pub mutability: Option<Token![mut]>, + pub self_token: Token![self], + }), + + /// An explicitly typed pattern captured by a function signature. + /// + /// *This type is available if Syn is built with the `"full"` feature.* + pub Captured(ArgCaptured { + pub pat: Pat, + pub colon_token: Token![:], + pub ty: Type, + }), + + /// A pattern whose type is inferred captured by a function signature. + pub Inferred(Pat), + /// A type not bound to any pattern in a function signature. + pub Ignored(Type), + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use ext::IdentExt; + use parse::{Parse, ParseStream, Result}; + use proc_macro2::{Punct, Spacing, TokenTree}; + use std::iter::FromIterator; + + impl Parse for Item { + fn parse(input: ParseStream) -> Result<Self> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + let vis: Visibility = ahead.parse()?; + + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![extern]) { + ahead.parse::<Token![extern]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![crate]) { + input.parse().map(Item::ExternCrate) + } else if lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else if lookahead.peek(token::Brace) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(LitStr) { + ahead.parse::<LitStr>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(token::Brace) { + input.parse().map(Item::ForeignMod) + } else if lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![use]) { + input.parse().map(Item::Use) + } else if lookahead.peek(Token![static]) { + input.parse().map(Item::Static) + } else if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) || lookahead.peek(Token![_]) { + input.parse().map(Item::Const) + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![unsafe]) { + ahead.parse::<Token![unsafe]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![trait]) + || lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) + { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) { + input.parse().map(Item::Impl) + } else if lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(Item::Fn) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![async]) || lookahead.peek(Token![fn]) { + input.parse().map(Item::Fn) + } else if lookahead.peek(Token![mod]) { + input.parse().map(Item::Mod) + } else if lookahead.peek(Token![type]) { + input.parse().map(Item::Type) + } else if lookahead.peek(Token![existential]) { + input.parse().map(Item::Existential) + } else if lookahead.peek(Token![struct]) { + input.parse().map(Item::Struct) + } else if lookahead.peek(Token![enum]) { + input.parse().map(Item::Enum) + } else if lookahead.peek(Token![union]) && ahead.peek2(Ident) { + input.parse().map(Item::Union) + } else if lookahead.peek(Token![trait]) { + input.call(parse_trait_or_trait_alias) + } else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) { + input.parse().map(Item::Trait) + } else if lookahead.peek(Token![impl]) + || lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) + { + input.parse().map(Item::Impl) + } else if lookahead.peek(Token![macro]) { + input.parse().map(Item::Macro2) + } else if vis.is_inherited() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(Item::Macro) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let path = input.call(Path::parse_mod_style)?; + let bang_token: Token![!] = input.parse()?; + let ident: Option<Ident> = input.parse()?; + let (delimiter, tts) = input.call(mac::parse_delimiter)?; + let semi_token: Option<Token![;]> = if !delimiter.is_brace() { + Some(input.parse()?) + } else { + None + }; + Ok(ItemMacro { + attrs: attrs, + ident: ident, + mac: Macro { + path: path, + bang_token: bang_token, + delimiter: delimiter, + tts: tts, + }, + semi_token: semi_token, + }) + } + } + + // TODO: figure out the actual grammar; is body required to be braced? + impl Parse for ItemMacro2 { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let macro_token: Token![macro] = input.parse()?; + let ident: Ident = input.parse()?; + + let paren_token; + let args; + let brace_token; + let body; + let lookahead = input.lookahead1(); + if lookahead.peek(token::Paren) { + let paren_content; + paren_token = parenthesized!(paren_content in input); + args = paren_content.parse()?; + + let brace_content; + brace_token = braced!(brace_content in input); + body = brace_content.parse()?; + } else if lookahead.peek(token::Brace) { + // Hack: the ItemMacro2 syntax tree will need to change so that + // we can store None for the args. + // + // https://github.com/dtolnay/syn/issues/548 + // + // For now, store some sentinel tokens that are otherwise + // illegal. + paren_token = token::Paren::default(); + args = TokenStream::from_iter(vec![ + TokenTree::Punct(Punct::new('$', Spacing::Alone)), + TokenTree::Punct(Punct::new('$', Spacing::Alone)), + ]); + + let brace_content; + brace_token = braced!(brace_content in input); + body = brace_content.parse()?; + } else { + return Err(lookahead.error()); + } + + Ok(ItemMacro2 { + attrs: attrs, + vis: vis, + macro_token: macro_token, + ident: ident, + paren_token: paren_token, + args: args, + brace_token: brace_token, + body: body, + }) + } + } + + impl Parse for ItemExternCrate { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemExternCrate { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + extern_token: input.parse()?, + crate_token: input.parse()?, + ident: { + if input.peek(Token![self]) { + input.call(Ident::parse_any)? + } else { + input.parse()? + } + }, + rename: { + if input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let rename: Ident = input.parse()?; + Some((as_token, rename)) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemUse { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemUse { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + use_token: input.parse()?, + leading_colon: input.parse()?, + tree: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for UseTree { + fn parse(input: ParseStream) -> Result<UseTree> { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![extern]) + { + let ident = input.call(Ident::parse_any)?; + if input.peek(Token![::]) { + Ok(UseTree::Path(UsePath { + ident: ident, + colon2_token: input.parse()?, + tree: Box::new(input.parse()?), + })) + } else if input.peek(Token![as]) { + Ok(UseTree::Rename(UseRename { + ident: ident, + as_token: input.parse()?, + rename: { + if input.peek(Ident) { + input.parse()? + } else if input.peek(Token![_]) { + Ident::from(input.parse::<Token![_]>()?) + } else { + return Err(input.error("expected identifier or underscore")); + } + }, + })) + } else { + Ok(UseTree::Name(UseName { ident: ident })) + } + } else if lookahead.peek(Token![*]) { + Ok(UseTree::Glob(UseGlob { + star_token: input.parse()?, + })) + } else if lookahead.peek(token::Brace) { + let content; + Ok(UseTree::Group(UseGroup { + brace_token: braced!(content in input), + items: content.parse_terminated(UseTree::parse)?, + })) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ItemStatic { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemStatic { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + static_token: input.parse()?, + mutability: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemConst { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + const_token: input.parse()?, + ident: { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) || lookahead.peek(Token![_]) { + input.call(Ident::parse_any)? + } else { + return Err(lookahead.error()); + } + }, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemFn { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let constness: Option<Token![const]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = content.parse_terminated(FnArg::parse)?; + let variadic: Option<Token![...]> = match inputs.last() { + Some(punctuated::Pair::End(&FnArg::Captured(ArgCaptured { + ty: Type::Verbatim(TypeVerbatim { ref tts }), + .. + }))) => parse2(tts.clone()).ok(), + _ => None, + }; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ItemFn { + attrs: private::attrs(outer_attrs, inner_attrs), + vis: vis, + constness: constness, + unsafety: unsafety, + asyncness: asyncness, + abi: abi, + ident: ident, + decl: Box::new(FnDecl { + fn_token: fn_token, + paren_token: paren_token, + inputs: inputs, + output: output, + variadic: variadic, + generics: Generics { + where_clause: where_clause, + ..generics + }, + }), + block: Box::new(Block { + brace_token: brace_token, + stmts: stmts, + }), + }) + } + } + + impl Parse for FnArg { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![&]) { + let ahead = input.fork(); + if ahead.call(arg_self_ref).is_ok() && !ahead.peek(Token![:]) { + return input.call(arg_self_ref).map(FnArg::SelfRef); + } + } + + if input.peek(Token![mut]) || input.peek(Token![self]) { + let ahead = input.fork(); + if ahead.call(arg_self).is_ok() && !ahead.peek(Token![:]) { + return input.call(arg_self).map(FnArg::SelfValue); + } + } + + let ahead = input.fork(); + let err = match ahead.call(arg_captured) { + Ok(_) => return input.call(arg_captured).map(FnArg::Captured), + Err(err) => err, + }; + + let ahead = input.fork(); + if ahead.parse::<Type>().is_ok() { + return input.parse().map(FnArg::Ignored); + } + + Err(err) + } + } + + fn arg_self_ref(input: ParseStream) -> Result<ArgSelfRef> { + Ok(ArgSelfRef { + and_token: input.parse()?, + lifetime: input.parse()?, + mutability: input.parse()?, + self_token: input.parse()?, + }) + } + + fn arg_self(input: ParseStream) -> Result<ArgSelf> { + Ok(ArgSelf { + mutability: input.parse()?, + self_token: input.parse()?, + }) + } + + fn arg_captured(input: ParseStream) -> Result<ArgCaptured> { + Ok(ArgCaptured { + pat: input.parse()?, + colon_token: input.parse()?, + ty: match input.parse::<Token![...]>() { + Ok(dot3) => { + let args = vec![ + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Joint)), + TokenTree::Punct(Punct::new('.', Spacing::Alone)), + ]; + let tokens = TokenStream::from_iter(args.into_iter().zip(&dot3.spans).map( + |(mut arg, span)| { + arg.set_span(*span); + arg + }, + )); + Type::Verbatim(TypeVerbatim { tts: tokens }) + } + Err(_) => input.parse()?, + }, + }) + } + + impl Parse for ItemMod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let mod_token: Token![mod] = input.parse()?; + let ident: Ident = input.parse()?; + + let lookahead = input.lookahead1(); + if lookahead.peek(Token![;]) { + Ok(ItemMod { + attrs: outer_attrs, + vis: vis, + mod_token: mod_token, + ident: ident, + content: None, + semi: Some(input.parse()?), + }) + } else if lookahead.peek(token::Brace) { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemMod { + attrs: private::attrs(outer_attrs, inner_attrs), + vis: vis, + mod_token: mod_token, + ident: ident, + content: Some((brace_token, items)), + semi: None, + }) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ItemForeignMod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let abi: Abi = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemForeignMod { + attrs: private::attrs(outer_attrs, inner_attrs), + abi: abi, + brace_token: brace_token, + items: items, + }) + } + } + + impl Parse for ForeignItem { + fn parse(input: ParseStream) -> Result<Self> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + let vis: Visibility = ahead.parse()?; + + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![fn]) { + input.parse().map(ForeignItem::Fn) + } else if lookahead.peek(Token![static]) { + input.parse().map(ForeignItem::Static) + } else if lookahead.peek(Token![type]) { + input.parse().map(ForeignItem::Type) + } else if vis.is_inherited() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(ForeignItem::Macro) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ForeignItemFn { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let mut inputs = Punctuated::new(); + while !content.is_empty() && !content.peek(Token![...]) { + inputs.push_value(content.parse()?); + if content.is_empty() { + break; + } + inputs.push_punct(content.parse()?); + } + let variadic: Option<Token![...]> = if inputs.empty_or_trailing() { + content.parse()? + } else { + None + }; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + let semi_token: Token![;] = input.parse()?; + + Ok(ForeignItemFn { + attrs: attrs, + vis: vis, + ident: ident, + decl: Box::new(FnDecl { + fn_token: fn_token, + paren_token: paren_token, + inputs: inputs, + output: output, + variadic: variadic, + generics: Generics { + where_clause: where_clause, + ..generics + }, + }), + semi_token: semi_token, + }) + } + } + + impl Parse for ForeignItemStatic { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ForeignItemStatic { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + static_token: input.parse()?, + mutability: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ForeignItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ForeignItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ForeignItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(ForeignItemMacro { + attrs: attrs, + mac: mac, + semi_token: semi_token, + }) + } + } + + impl Parse for ItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + generics: { + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + generics + }, + eq_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemExistential { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ItemExistential { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + existential_token: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + generics: { + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + generics + }, + colon_token: Some(input.parse()?), + bounds: { + let mut bounds = Punctuated::new(); + while !input.peek(Token![;]) { + if !bounds.is_empty() { + bounds.push_punct(input.parse()?); + } + bounds.push_value(input.parse()?); + } + bounds + }, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ItemStruct { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let struct_token = input.parse::<Token![struct]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields, semi_token) = derive::parsing::data_struct(input)?; + Ok(ItemStruct { + attrs: attrs, + vis: vis, + struct_token: struct_token, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + fields: fields, + semi_token: semi_token, + }) + } + } + + impl Parse for ItemEnum { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let enum_token = input.parse::<Token![enum]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, brace_token, variants) = derive::parsing::data_enum(input)?; + Ok(ItemEnum { + attrs: attrs, + vis: vis, + enum_token: enum_token, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + brace_token: brace_token, + variants: variants, + }) + } + } + + impl Parse for ItemUnion { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis = input.parse::<Visibility>()?; + let union_token = input.parse::<Token![union]>()?; + let ident = input.parse::<Ident>()?; + let generics = input.parse::<Generics>()?; + let (where_clause, fields) = derive::parsing::data_union(input)?; + Ok(ItemUnion { + attrs: attrs, + vis: vis, + union_token: union_token, + ident: ident, + generics: Generics { + where_clause: where_clause, + ..generics + }, + fields: fields, + }) + } + } + + fn parse_trait_or_trait_alias(input: ParseStream) -> Result<Item> { + let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; + let lookahead = input.lookahead1(); + if lookahead.peek(token::Brace) + || lookahead.peek(Token![:]) + || lookahead.peek(Token![where]) + { + let unsafety = None; + let auto_token = None; + parse_rest_of_trait( + input, + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + ) + .map(Item::Trait) + } else if lookahead.peek(Token![=]) { + parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) + .map(Item::TraitAlias) + } else { + Err(lookahead.error()) + } + } + + impl Parse for ItemTrait { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let auto_token: Option<Token![auto]> = input.parse()?; + let trait_token: Token![trait] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + parse_rest_of_trait( + input, + attrs, + vis, + unsafety, + auto_token, + trait_token, + ident, + generics, + ) + } + } + + fn parse_rest_of_trait( + input: ParseStream, + attrs: Vec<Attribute>, + vis: Visibility, + unsafety: Option<Token![unsafe]>, + auto_token: Option<Token![auto]>, + trait_token: Token![trait], + ident: Ident, + mut generics: Generics, + ) -> Result<ItemTrait> { + let colon_token: Option<Token![:]> = input.parse()?; + + let mut supertraits = Punctuated::new(); + if colon_token.is_some() { + loop { + supertraits.push_value(input.parse()?); + if input.peek(Token![where]) || input.peek(token::Brace) { + break; + } + supertraits.push_punct(input.parse()?); + if input.peek(Token![where]) || input.peek(token::Brace) { + break; + } + } + } + + generics.where_clause = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemTrait { + attrs: attrs, + vis: vis, + unsafety: unsafety, + auto_token: auto_token, + trait_token: trait_token, + ident: ident, + generics: generics, + colon_token: colon_token, + supertraits: supertraits, + brace_token: brace_token, + items: items, + }) + } + + impl Parse for ItemTraitAlias { + fn parse(input: ParseStream) -> Result<Self> { + let (attrs, vis, trait_token, ident, generics) = parse_start_of_trait_alias(input)?; + parse_rest_of_trait_alias(input, attrs, vis, trait_token, ident, generics) + } + } + + fn parse_start_of_trait_alias( + input: ParseStream, + ) -> Result<(Vec<Attribute>, Visibility, Token![trait], Ident, Generics)> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let trait_token: Token![trait] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + Ok((attrs, vis, trait_token, ident, generics)) + } + + fn parse_rest_of_trait_alias( + input: ParseStream, + attrs: Vec<Attribute>, + vis: Visibility, + trait_token: Token![trait], + ident: Ident, + mut generics: Generics, + ) -> Result<ItemTraitAlias> { + let eq_token: Token![=] = input.parse()?; + + let mut bounds = Punctuated::new(); + loop { + if input.peek(Token![where]) || input.peek(Token![;]) { + break; + } + bounds.push_value(input.parse()?); + if input.peek(Token![where]) || input.peek(Token![;]) { + break; + } + bounds.push_punct(input.parse()?); + } + + generics.where_clause = input.parse()?; + let semi_token: Token![;] = input.parse()?; + + Ok(ItemTraitAlias { + attrs: attrs, + vis: vis, + trait_token: trait_token, + ident: ident, + generics: generics, + eq_token: eq_token, + bounds: bounds, + semi_token: semi_token, + }) + } + + impl Parse for TraitItem { + fn parse(input: ParseStream) -> Result<Self> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + + let lookahead = ahead.lookahead1(); + if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) { + input.parse().map(TraitItem::Const) + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(TraitItem::Method) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(TraitItem::Method) + } else if lookahead.peek(Token![type]) { + input.parse().map(TraitItem::Type) + } else if lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::]) + { + input.parse().map(TraitItem::Macro) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for TraitItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TraitItemConst { + attrs: input.call(Attribute::parse_outer)?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + default: { + if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let default: Expr = input.parse()?; + Some((eq_token, default)) + } else { + None + } + }, + semi_token: input.parse()?, + }) + } + } + + impl Parse for TraitItemMethod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let constness: Option<Token![const]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = content.parse_terminated(FnArg::parse)?; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let lookahead = input.lookahead1(); + let (brace_token, inner_attrs, stmts, semi_token) = if lookahead.peek(token::Brace) { + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + (Some(brace_token), inner_attrs, stmts, None) + } else if lookahead.peek(Token![;]) { + let semi_token: Token![;] = input.parse()?; + (None, Vec::new(), Vec::new(), Some(semi_token)) + } else { + return Err(lookahead.error()); + }; + + Ok(TraitItemMethod { + attrs: private::attrs(outer_attrs, inner_attrs), + sig: MethodSig { + constness: constness, + unsafety: unsafety, + asyncness: None, + abi: abi, + ident: ident, + decl: FnDecl { + fn_token: fn_token, + paren_token: paren_token, + inputs: inputs, + output: output, + variadic: None, + generics: Generics { + where_clause: where_clause, + ..generics + }, + }, + }, + default: brace_token.map(|brace_token| Block { + brace_token: brace_token, + stmts: stmts, + }), + semi_token: semi_token, + }) + } + } + + impl Parse for TraitItemType { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let type_token: Token![type] = input.parse()?; + let ident: Ident = input.parse()?; + let mut generics: Generics = input.parse()?; + let colon_token: Option<Token![:]> = input.parse()?; + + let mut bounds = Punctuated::new(); + if colon_token.is_some() { + while !input.peek(Token![where]) && !input.peek(Token![=]) && !input.peek(Token![;]) + { + if !bounds.is_empty() { + bounds.push_punct(input.parse()?); + } + bounds.push_value(input.parse()?); + } + } + + generics.where_clause = input.parse()?; + let default = if input.peek(Token![=]) { + let eq_token: Token![=] = input.parse()?; + let default: Type = input.parse()?; + Some((eq_token, default)) + } else { + None + }; + let semi_token: Token![;] = input.parse()?; + + Ok(TraitItemType { + attrs: attrs, + type_token: type_token, + ident: ident, + generics: generics, + colon_token: colon_token, + bounds: bounds, + default: default, + semi_token: semi_token, + }) + } + } + + impl Parse for TraitItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(TraitItemMacro { + attrs: attrs, + mac: mac, + semi_token: semi_token, + }) + } + } + + impl Parse for ItemImpl { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let defaultness: Option<Token![default]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let impl_token: Token![impl] = input.parse()?; + + let has_generics = input.peek(Token![<]) + && (input.peek2(Token![>]) + || input.peek2(Token![#]) + || (input.peek2(Ident) || input.peek2(Lifetime)) + && (input.peek3(Token![:]) + || input.peek3(Token![,]) + || input.peek3(Token![>]))); + let generics: Generics = if has_generics { + input.parse()? + } else { + Generics::default() + }; + + let trait_ = { + let ahead = input.fork(); + if ahead.parse::<Option<Token![!]>>().is_ok() + && ahead.parse::<Path>().is_ok() + && ahead.parse::<Token![for]>().is_ok() + { + let polarity: Option<Token![!]> = input.parse()?; + let path: Path = input.parse()?; + let for_token: Token![for] = input.parse()?; + Some((polarity, path, for_token)) + } else { + None + } + }; + let self_ty: Type = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + + let mut items = Vec::new(); + while !content.is_empty() { + items.push(content.parse()?); + } + + Ok(ItemImpl { + attrs: private::attrs(outer_attrs, inner_attrs), + defaultness: defaultness, + unsafety: unsafety, + impl_token: impl_token, + generics: Generics { + where_clause: where_clause, + ..generics + }, + trait_: trait_, + self_ty: Box::new(self_ty), + brace_token: brace_token, + items: items, + }) + } + } + + impl Parse for ImplItem { + fn parse(input: ParseStream) -> Result<Self> { + let ahead = input.fork(); + ahead.call(Attribute::parse_outer)?; + let vis: Visibility = ahead.parse()?; + + let mut lookahead = ahead.lookahead1(); + let defaultness = if lookahead.peek(Token![default]) && !ahead.peek2(Token![!]) { + let defaultness: Token![default] = ahead.parse()?; + lookahead = ahead.lookahead1(); + Some(defaultness) + } else { + None + }; + + if lookahead.peek(Token![const]) { + ahead.parse::<Token![const]>()?; + let lookahead = ahead.lookahead1(); + if lookahead.peek(Ident) { + input.parse().map(ImplItem::Const) + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(ImplItem::Method) + } else { + Err(lookahead.error()) + } + } else if lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![async]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![fn]) + { + input.parse().map(ImplItem::Method) + } else if lookahead.peek(Token![type]) { + input.parse().map(ImplItem::Type) + } else if vis.is_inherited() + && defaultness.is_none() + && lookahead.peek(Token![existential]) + { + input.parse().map(ImplItem::Existential) + } else if vis.is_inherited() + && defaultness.is_none() + && (lookahead.peek(Ident) + || lookahead.peek(Token![self]) + || lookahead.peek(Token![super]) + || lookahead.peek(Token![extern]) + || lookahead.peek(Token![crate]) + || lookahead.peek(Token![::])) + { + input.parse().map(ImplItem::Macro) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for ImplItemConst { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ImplItemConst { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + const_token: input.parse()?, + ident: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + eq_token: input.parse()?, + expr: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ImplItemMethod { + fn parse(input: ParseStream) -> Result<Self> { + let outer_attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let defaultness: Option<Token![default]> = input.parse()?; + let constness: Option<Token![const]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse()?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let inputs = content.parse_terminated(FnArg::parse)?; + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + let brace_token = braced!(content in input); + let inner_attrs = content.call(Attribute::parse_inner)?; + let stmts = content.call(Block::parse_within)?; + + Ok(ImplItemMethod { + attrs: private::attrs(outer_attrs, inner_attrs), + vis: vis, + defaultness: defaultness, + sig: MethodSig { + constness: constness, + unsafety: unsafety, + asyncness: asyncness, + abi: abi, + ident: ident, + decl: FnDecl { + fn_token: fn_token, + paren_token: paren_token, + inputs: inputs, + output: output, + variadic: None, + generics: Generics { + where_clause: where_clause, + ..generics + }, + }, + }, + block: Block { + brace_token: brace_token, + stmts: stmts, + }, + }) + } + } + + impl Parse for ImplItemType { + fn parse(input: ParseStream) -> Result<Self> { + Ok(ImplItemType { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + type_token: input.parse()?, + ident: input.parse()?, + generics: { + let mut generics: Generics = input.parse()?; + generics.where_clause = input.parse()?; + generics + }, + eq_token: input.parse()?, + ty: input.parse()?, + semi_token: input.parse()?, + }) + } + } + + impl Parse for ImplItemExistential { + fn parse(input: ParseStream) -> Result<Self> { + let ety: ItemExistential = input.parse()?; + Ok(ImplItemExistential { + attrs: ety.attrs, + existential_token: ety.existential_token, + type_token: ety.type_token, + ident: ety.ident, + generics: ety.generics, + colon_token: ety.colon_token, + bounds: ety.bounds, + semi_token: ety.semi_token, + }) + } + } + + impl Parse for ImplItemMacro { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let mac: Macro = input.parse()?; + let semi_token: Option<Token![;]> = if mac.delimiter.is_brace() { + None + } else { + Some(input.parse()?) + }; + Ok(ImplItemMacro { + attrs: attrs, + mac: mac, + semi_token: semi_token, + }) + } + } + + impl Visibility { + fn is_inherited(&self) -> bool { + match *self { + Visibility::Inherited => true, + _ => false, + } + } + } + + impl MacroDelimiter { + fn is_brace(&self) -> bool { + match *self { + MacroDelimiter::Brace(_) => true, + MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false, + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + use attr::FilterAttrs; + use print::TokensOrDefault; + + impl ToTokens for ItemExternCrate { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.extern_token.to_tokens(tokens); + self.crate_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + if let Some((ref as_token, ref rename)) = self.rename { + as_token.to_tokens(tokens); + rename.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemUse { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.use_token.to_tokens(tokens); + self.leading_colon.to_tokens(tokens); + self.tree.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemStatic { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.static_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemConst { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.const_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.constness.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.asyncness.to_tokens(tokens); + self.abi.to_tokens(tokens); + NamedDecl(&self.decl, &self.ident).to_tokens(tokens); + self.block.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&self.block.stmts); + }); + } + } + + impl ToTokens for ItemMod { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.mod_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + if let Some((ref brace, ref items)) = self.content { + brace.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(items); + }); + } else { + TokensOrDefault(&self.semi).to_tokens(tokens); + } + } + } + + impl ToTokens for ItemForeignMod { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.abi.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&self.items); + }); + } + } + + impl ToTokens for ItemType { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemExistential { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.existential_token.to_tokens(tokens); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + if !self.bounds.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemEnum { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.enum_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + self.variants.to_tokens(tokens); + }); + } + } + + impl ToTokens for ItemStruct { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.struct_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + match self.fields { + Fields::Named(ref fields) => { + self.generics.where_clause.to_tokens(tokens); + fields.to_tokens(tokens); + } + Fields::Unnamed(ref fields) => { + fields.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&self.semi_token).to_tokens(tokens); + } + Fields::Unit => { + self.generics.where_clause.to_tokens(tokens); + TokensOrDefault(&self.semi_token).to_tokens(tokens); + } + } + } + } + + impl ToTokens for ItemUnion { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.union_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.fields.to_tokens(tokens); + } + } + + impl ToTokens for ItemTrait { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.auto_token.to_tokens(tokens); + self.trait_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + if !self.supertraits.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.supertraits.to_tokens(tokens); + } + self.generics.where_clause.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(&self.items); + }); + } + } + + impl ToTokens for ItemTraitAlias { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.trait_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemImpl { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.defaultness.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.impl_token.to_tokens(tokens); + self.generics.to_tokens(tokens); + if let Some((ref polarity, ref path, ref for_token)) = self.trait_ { + polarity.to_tokens(tokens); + path.to_tokens(tokens); + for_token.to_tokens(tokens); + } + self.self_ty.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&self.items); + }); + } + } + + impl ToTokens for ItemMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.mac.path.to_tokens(tokens); + self.mac.bang_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + match self.mac.delimiter { + MacroDelimiter::Paren(ref paren) => { + paren.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens)); + } + MacroDelimiter::Brace(ref brace) => { + brace.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens)); + } + MacroDelimiter::Bracket(ref bracket) => { + bracket.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens)); + } + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ItemMacro2 { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.macro_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + + // Hack: see comment in impl Parse for ItemMacro2. + if self.args.to_string() != "$ $" { + self.paren_token.surround(tokens, |tokens| { + self.args.to_tokens(tokens); + }); + } + + self.brace_token.surround(tokens, |tokens| { + self.body.to_tokens(tokens); + }); + } + } + + impl ToTokens for ItemVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + impl ToTokens for UsePath { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.colon2_token.to_tokens(tokens); + self.tree.to_tokens(tokens); + } + } + + impl ToTokens for UseName { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + } + } + + impl ToTokens for UseRename { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.as_token.to_tokens(tokens); + self.rename.to_tokens(tokens); + } + } + + impl ToTokens for UseGlob { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.star_token.to_tokens(tokens); + } + } + + impl ToTokens for UseGroup { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.brace_token.surround(tokens, |tokens| { + self.items.to_tokens(tokens); + }); + } + } + + impl ToTokens for TraitItemConst { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.const_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + if let Some((ref eq_token, ref default)) = self.default { + eq_token.to_tokens(tokens); + default.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for TraitItemMethod { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.sig.to_tokens(tokens); + match self.default { + Some(ref block) => { + block.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&block.stmts); + }); + } + None => { + TokensOrDefault(&self.semi_token).to_tokens(tokens); + } + } + } + } + + impl ToTokens for TraitItemType { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + if !self.bounds.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + self.generics.where_clause.to_tokens(tokens); + if let Some((ref eq_token, ref default)) = self.default { + eq_token.to_tokens(tokens); + default.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for TraitItemMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.mac.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for TraitItemVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + impl ToTokens for ImplItemConst { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.defaultness.to_tokens(tokens); + self.const_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.expr.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ImplItemMethod { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.defaultness.to_tokens(tokens); + self.sig.to_tokens(tokens); + self.block.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.attrs.inner()); + tokens.append_all(&self.block.stmts); + }); + } + } + + impl ToTokens for ImplItemType { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.defaultness.to_tokens(tokens); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ImplItemExistential { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.existential_token.to_tokens(tokens); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + self.generics.where_clause.to_tokens(tokens); + if !self.bounds.is_empty() { + TokensOrDefault(&self.colon_token).to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ImplItemMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.mac.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ImplItemVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + impl ToTokens for ForeignItemFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + NamedDecl(&self.decl, &self.ident).to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ForeignItemStatic { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.static_token.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ForeignItemType { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.vis.to_tokens(tokens); + self.type_token.to_tokens(tokens); + self.ident.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ForeignItemMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.outer()); + self.mac.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } + } + + impl ToTokens for ForeignItemVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + impl ToTokens for MethodSig { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.constness.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.asyncness.to_tokens(tokens); + self.abi.to_tokens(tokens); + NamedDecl(&self.decl, &self.ident).to_tokens(tokens); + } + } + + struct NamedDecl<'a>(&'a FnDecl, &'a Ident); + + impl<'a> ToTokens for NamedDecl<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.0.fn_token.to_tokens(tokens); + self.1.to_tokens(tokens); + self.0.generics.to_tokens(tokens); + self.0.paren_token.surround(tokens, |tokens| { + self.0.inputs.to_tokens(tokens); + if self.0.variadic.is_some() && !self.0.inputs.empty_or_trailing() { + <Token![,]>::default().to_tokens(tokens); + } + self.0.variadic.to_tokens(tokens); + }); + self.0.output.to_tokens(tokens); + self.0.generics.where_clause.to_tokens(tokens); + } + } + + impl ToTokens for ArgSelfRef { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.and_token.to_tokens(tokens); + self.lifetime.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.self_token.to_tokens(tokens); + } + } + + impl ToTokens for ArgSelf { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.mutability.to_tokens(tokens); + self.self_token.to_tokens(tokens); + } + } + + impl ToTokens for ArgCaptured { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.pat.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + } + } +} diff --git a/syn/src/keyword.rs b/syn/src/keyword.rs new file mode 100644 index 000000000..e69de29bb diff --git a/syn/src/lib.rs b/syn/src/lib.rs new file mode 100644 index 000000000..bfd6db871 --- /dev/null +++ b/syn/src/lib.rs @@ -0,0 +1,727 @@ +//! Syn is a parsing library for parsing a stream of Rust tokens into a syntax +//! tree of Rust source code. +//! +//! Currently this library is geared toward use in Rust procedural macros, but +//! contains some APIs that may be useful more generally. +//! +//! - **Data structures** — Syn provides a complete syntax tree that can +//! represent any valid Rust source code. The syntax tree is rooted at +//! [`syn::File`] which represents a full source file, but there are other +//! entry points that may be useful to procedural macros including +//! [`syn::Item`], [`syn::Expr`] and [`syn::Type`]. +//! +//! - **Custom derives** — Of particular interest to custom derives is +//! [`syn::DeriveInput`] which is any of the three legal input items to a +//! derive macro. An example below shows using this type in a library that can +//! derive implementations of a trait of your own. +//! +//! - **Parsing** — Parsing in Syn is built around [parser functions] with the +//! signature `fn(ParseStream) -> Result<T>`. Every syntax tree node defined +//! by Syn is individually parsable and may be used as a building block for +//! custom syntaxes, or you may dream up your own brand new syntax without +//! involving any of our syntax tree types. +//! +//! - **Location information** — Every token parsed by Syn is associated with a +//! `Span` that tracks line and column information back to the source of that +//! token. These spans allow a procedural macro to display detailed error +//! messages pointing to all the right places in the user's code. There is an +//! example of this below. +//! +//! - **Feature flags** — Functionality is aggressively feature gated so your +//! procedural macros enable only what they need, and do not pay in compile +//! time for all the rest. +//! +//! [`syn::File`]: struct.File.html +//! [`syn::Item`]: enum.Item.html +//! [`syn::Expr`]: enum.Expr.html +//! [`syn::Type`]: enum.Type.html +//! [`syn::DeriveInput`]: struct.DeriveInput.html +//! [parser functions]: parse/index.html +//! +//! *Version requirement: Syn supports any compiler version back to Rust's very +//! first support for procedural macros in Rust 1.15.0. Some features especially +//! around error reporting are only available in newer compilers or on the +//! nightly channel.* +//! +//! ## Example of a custom derive +//! +//! The canonical custom derive using Syn looks like this. We write an ordinary +//! Rust function tagged with a `proc_macro_derive` attribute and the name of +//! the trait we are deriving. Any time that derive appears in the user's code, +//! the Rust compiler passes their data structure as tokens into our macro. We +//! get to execute arbitrary Rust code to figure out what to do with those +//! tokens, then hand some tokens back to the compiler to compile into the +//! user's crate. +//! +//! [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html +//! +//! ```toml +//! [dependencies] +//! syn = "0.15" +//! quote = "0.6" +//! +//! [lib] +//! proc-macro = true +//! ``` +//! +//! ```edition2018 +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use quote::quote; +//! use syn::{parse_macro_input, DeriveInput}; +//! +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[proc_macro_derive(MyMacro)] +//! # }; +//! pub fn my_macro(input: TokenStream) -> TokenStream { +//! // Parse the input tokens into a syntax tree +//! let input = parse_macro_input!(input as DeriveInput); +//! +//! // Build the output, possibly using quasi-quotation +//! let expanded = quote! { +//! // ... +//! }; +//! +//! // Hand the output tokens back to the compiler +//! TokenStream::from(expanded) +//! } +//! ``` +//! +//! The [`heapsize`] example directory shows a complete working Macros 1.1 +//! implementation of a custom derive. It works on any Rust compiler 1.15+. +//! The example derives a `HeapSize` trait which computes an estimate of the +//! amount of heap memory owned by a value. +//! +//! [`heapsize`]: https://github.com/dtolnay/syn/tree/master/examples/heapsize +//! +//! ```edition2018 +//! pub trait HeapSize { +//! /// Total number of bytes of heap memory owned by `self`. +//! fn heap_size_of_children(&self) -> usize; +//! } +//! ``` +//! +//! The custom derive allows users to write `#[derive(HeapSize)]` on data +//! structures in their program. +//! +//! ```edition2018 +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[derive(HeapSize)] +//! # }; +//! struct Demo<'a, T: ?Sized> { +//! a: Box<T>, +//! b: u8, +//! c: &'a str, +//! d: String, +//! } +//! ``` +//! +//! ## Spans and error reporting +//! +//! The token-based procedural macro API provides great control over where the +//! compiler's error messages are displayed in user code. Consider the error the +//! user sees if one of their field types does not implement `HeapSize`. +//! +//! ```edition2018 +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[derive(HeapSize)] +//! # }; +//! struct Broken { +//! ok: String, +//! bad: std::thread::Thread, +//! } +//! ``` +//! +//! By tracking span information all the way through the expansion of a +//! procedural macro as shown in the `heapsize` example, token-based macros in +//! Syn are able to trigger errors that directly pinpoint the source of the +//! problem. +//! +//! ```text +//! error[E0277]: the trait bound `std::thread::Thread: HeapSize` is not satisfied +//! --> src/main.rs:7:5 +//! | +//! 7 | bad: std::thread::Thread, +//! | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HeapSize` is not implemented for `Thread` +//! ``` +//! +//! ## Parsing a custom syntax +//! +//! The [`lazy-static`] example directory shows the implementation of a +//! `functionlike!(...)` procedural macro in which the input tokens are parsed +//! using Syn's parsing API. +//! +//! [`lazy-static`]: https://github.com/dtolnay/syn/tree/master/examples/lazy-static +//! +//! The example reimplements the popular `lazy_static` crate from crates.io as a +//! procedural macro. +//! +//! ```edition2018 +//! # macro_rules! lazy_static { +//! # ($($tt:tt)*) => {} +//! # } +//! # +//! lazy_static! { +//! static ref USERNAME: Regex = Regex::new("^[a-z0-9_-]{3,16}$").unwrap(); +//! } +//! ``` +//! +//! The implementation shows how to trigger custom warnings and error messages +//! on the macro input. +//! +//! ```text +//! warning: come on, pick a more creative name +//! --> src/main.rs:10:16 +//! | +//! 10 | static ref FOO: String = "lazy_static".to_owned(); +//! | ^^^ +//! ``` +//! +//! ## Debugging +//! +//! When developing a procedural macro it can be helpful to look at what the +//! generated code looks like. Use `cargo rustc -- -Zunstable-options +//! --pretty=expanded` or the [`cargo expand`] subcommand. +//! +//! [`cargo expand`]: https://github.com/dtolnay/cargo-expand +//! +//! To show the expanded code for some crate that uses your procedural macro, +//! run `cargo expand` from that crate. To show the expanded code for one of +//! your own test cases, run `cargo expand --test the_test_case` where the last +//! argument is the name of the test file without the `.rs` extension. +//! +//! This write-up by Brandon W Maister discusses debugging in more detail: +//! [Debugging Rust's new Custom Derive system][debugging]. +//! +//! [debugging]: https://quodlibetor.github.io/posts/debugging-rusts-new-custom-derive-system/ +//! +//! ## Optional features +//! +//! Syn puts a lot of functionality behind optional features in order to +//! optimize compile time for the most common use cases. The following features +//! are available. +//! +//! - **`derive`** *(enabled by default)* — Data structures for representing the +//! possible input to a custom derive, including structs and enums and types. +//! - **`full`** — Data structures for representing the syntax tree of all valid +//! Rust source code, including items and expressions. +//! - **`parsing`** *(enabled by default)* — Ability to parse input tokens into +//! a syntax tree node of a chosen type. +//! - **`printing`** *(enabled by default)* — Ability to print a syntax tree +//! node as tokens of Rust source code. +//! - **`visit`** — Trait for traversing a syntax tree. +//! - **`visit-mut`** — Trait for traversing and mutating in place a syntax +//! tree. +//! - **`fold`** — Trait for transforming an owned syntax tree. +//! - **`clone-impls`** *(enabled by default)* — Clone impls for all syntax tree +//! types. +//! - **`extra-traits`** — Debug, Eq, PartialEq, Hash impls for all syntax tree +//! types. +//! - **`proc-macro`** *(enabled by default)* — Runtime dependency on the +//! dynamic library libproc_macro from rustc toolchain. + +// Syn types in rustdoc of other crates get linked to here. +#![doc(html_root_url = "https://docs.rs/syn/0.15.34")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] +// Ignored clippy lints. +#![cfg_attr( + feature = "cargo-clippy", + allow( + block_in_if_condition_stmt, + cognitive_complexity, + const_static_lifetime, + deprecated_cfg_attr, + doc_markdown, + eval_order_dependence, + large_enum_variant, + needless_pass_by_value, + never_loop, + redundant_field_names, + too_many_arguments, + ) +)] +// Ignored clippy_pedantic lints. +#![cfg_attr( + feature = "cargo-clippy", + allow( + cast_possible_truncation, + cast_possible_wrap, + empty_enum, + if_not_else, + items_after_statements, + module_name_repetitions, + shadow_unrelated, + similar_names, + single_match_else, + unseparated_literal_suffix, + use_self, + used_underscore_binding, + ) +)] + +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" +))] +extern crate proc_macro; +extern crate proc_macro2; +extern crate unicode_xid; + +#[cfg(feature = "printing")] +extern crate quote; + +#[macro_use] +mod macros; + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_use] +pub mod group; + +#[macro_use] +pub mod token; + +mod ident; +pub use ident::Ident; + +#[cfg(any(feature = "full", feature = "derive"))] +mod attr; +#[cfg(any(feature = "full", feature = "derive"))] +pub use attr::{AttrStyle, Attribute, AttributeArgs, Meta, MetaList, MetaNameValue, NestedMeta}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod data; +#[cfg(any(feature = "full", feature = "derive"))] +pub use data::{ + Field, Fields, FieldsNamed, FieldsUnnamed, Variant, VisCrate, VisPublic, VisRestricted, + Visibility, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod expr; +#[cfg(any(feature = "full", feature = "derive"))] +pub use expr::{ + Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprBinary, ExprBlock, ExprBox, + ExprBreak, ExprCall, ExprCast, ExprClosure, ExprContinue, ExprField, ExprForLoop, ExprGroup, + ExprIf, ExprInPlace, ExprIndex, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch, + ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, + ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprVerbatim, + ExprWhile, ExprYield, Index, Member, +}; + +#[cfg(feature = "full")] +pub use expr::{ + Arm, Block, FieldPat, FieldValue, GenericMethodArgument, Label, Local, MethodTurbofish, Pat, + PatBox, PatIdent, PatLit, PatMacro, PatPath, PatRange, PatRef, PatSlice, PatStruct, PatTuple, + PatTupleStruct, PatVerbatim, PatWild, RangeLimits, Stmt, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod generics; +#[cfg(any(feature = "full", feature = "derive"))] +pub use generics::{ + BoundLifetimes, ConstParam, GenericParam, Generics, LifetimeDef, PredicateEq, + PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, + WhereClause, WherePredicate, +}; +#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] +pub use generics::{ImplGenerics, Turbofish, TypeGenerics}; + +#[cfg(feature = "full")] +mod item; +#[cfg(feature = "full")] +pub use item::{ + ArgCaptured, ArgSelf, ArgSelfRef, FnArg, FnDecl, ForeignItem, ForeignItemFn, ForeignItemMacro, + ForeignItemStatic, ForeignItemType, ForeignItemVerbatim, ImplItem, ImplItemConst, + ImplItemExistential, ImplItemMacro, ImplItemMethod, ImplItemType, ImplItemVerbatim, Item, + ItemConst, ItemEnum, ItemExistential, ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, + ItemMacro, ItemMacro2, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType, + ItemUnion, ItemUse, ItemVerbatim, MethodSig, TraitItem, TraitItemConst, TraitItemMacro, + TraitItemMethod, TraitItemType, TraitItemVerbatim, UseGlob, UseGroup, UseName, UsePath, + UseRename, UseTree, +}; + +#[cfg(feature = "full")] +mod file; +#[cfg(feature = "full")] +pub use file::File; + +mod lifetime; +pub use lifetime::Lifetime; + +#[cfg(any(feature = "full", feature = "derive"))] +mod lit; +#[cfg(any(feature = "full", feature = "derive"))] +pub use lit::{ + FloatSuffix, IntSuffix, Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr, + LitVerbatim, StrStyle, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod mac; +#[cfg(any(feature = "full", feature = "derive"))] +pub use mac::{Macro, MacroDelimiter}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod derive; +#[cfg(feature = "derive")] +pub use derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod op; +#[cfg(any(feature = "full", feature = "derive"))] +pub use op::{BinOp, UnOp}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod ty; +#[cfg(any(feature = "full", feature = "derive"))] +pub use ty::{ + Abi, BareFnArg, BareFnArgName, ReturnType, Type, TypeArray, TypeBareFn, TypeGroup, + TypeImplTrait, TypeInfer, TypeMacro, TypeNever, TypeParen, TypePath, TypePtr, TypeReference, + TypeSlice, TypeTraitObject, TypeTuple, TypeVerbatim, +}; + +#[cfg(any(feature = "full", feature = "derive"))] +mod path; +#[cfg(any(feature = "full", feature = "derive"))] +pub use path::{ + AngleBracketedGenericArguments, Binding, Constraint, GenericArgument, + ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, +}; + +#[cfg(feature = "parsing")] +pub mod buffer; +#[cfg(feature = "parsing")] +pub mod ext; +pub mod punctuated; +#[cfg(all(any(feature = "full", feature = "derive"), feature = "extra-traits"))] +mod tt; + +// Not public API except the `parse_quote!` macro. +#[cfg(feature = "parsing")] +#[doc(hidden)] +pub mod parse_quote; + +// Not public API except the `parse_macro_input!` macro. +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "parsing", + feature = "proc-macro" +))] +#[doc(hidden)] +pub mod parse_macro_input; + +#[cfg(all(feature = "parsing", feature = "printing"))] +pub mod spanned; + +mod gen { + /// Syntax tree traversal to walk a shared borrow of a syntax tree. + /// + /// Each method of the [`Visit`] trait is a hook that can be overridden to + /// customize the behavior when visiting the corresponding type of node. By + /// default, every method recursively visits the substructure of the input + /// by invoking the right visitor method of each of its fields. + /// + /// [`Visit`]: trait.Visit.html + /// + /// ```edition2018 + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait Visit<'ast> { + /// /* ... */ + /// + /// fn visit_expr_binary(&mut self, node: &'ast ExprBinary) { + /// for attr in &node.attrs { + /// self.visit_attribute(attr); + /// } + /// self.visit_expr(&*node.left); + /// self.visit_bin_op(&node.op); + /// self.visit_expr(&*node.right); + /// } + /// + /// /* ... */ + /// # fn visit_attribute(&mut self, node: &'ast Attribute); + /// # fn visit_expr(&mut self, node: &'ast Expr); + /// # fn visit_bin_op(&mut self, node: &'ast BinOp); + /// } + /// ``` + /// + /// *This module is available if Syn is built with the `"visit"` feature.* + #[cfg(feature = "visit")] + pub mod visit; + + /// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in + /// place. + /// + /// Each method of the [`VisitMut`] trait is a hook that can be overridden + /// to customize the behavior when mutating the corresponding type of node. + /// By default, every method recursively visits the substructure of the + /// input by invoking the right visitor method of each of its fields. + /// + /// [`VisitMut`]: trait.VisitMut.html + /// + /// ```edition2018 + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait VisitMut { + /// /* ... */ + /// + /// fn visit_expr_binary_mut(&mut self, node: &mut ExprBinary) { + /// for attr in &mut node.attrs { + /// self.visit_attribute_mut(attr); + /// } + /// self.visit_expr_mut(&mut *node.left); + /// self.visit_bin_op_mut(&mut node.op); + /// self.visit_expr_mut(&mut *node.right); + /// } + /// + /// /* ... */ + /// # fn visit_attribute_mut(&mut self, node: &mut Attribute); + /// # fn visit_expr_mut(&mut self, node: &mut Expr); + /// # fn visit_bin_op_mut(&mut self, node: &mut BinOp); + /// } + /// ``` + /// + /// *This module is available if Syn is built with the `"visit-mut"` + /// feature.* + #[cfg(feature = "visit-mut")] + pub mod visit_mut; + + /// Syntax tree traversal to transform the nodes of an owned syntax tree. + /// + /// Each method of the [`Fold`] trait is a hook that can be overridden to + /// customize the behavior when transforming the corresponding type of node. + /// By default, every method recursively visits the substructure of the + /// input by invoking the right visitor method of each of its fields. + /// + /// [`Fold`]: trait.Fold.html + /// + /// ```edition2018 + /// # use syn::{Attribute, BinOp, Expr, ExprBinary}; + /// # + /// pub trait Fold { + /// /* ... */ + /// + /// fn fold_expr_binary(&mut self, node: ExprBinary) -> ExprBinary { + /// ExprBinary { + /// attrs: node.attrs + /// .into_iter() + /// .map(|attr| self.fold_attribute(attr)) + /// .collect(), + /// left: Box::new(self.fold_expr(*node.left)), + /// op: self.fold_bin_op(node.op), + /// right: Box::new(self.fold_expr(*node.right)), + /// } + /// } + /// + /// /* ... */ + /// # fn fold_attribute(&mut self, node: Attribute) -> Attribute; + /// # fn fold_expr(&mut self, node: Expr) -> Expr; + /// # fn fold_bin_op(&mut self, node: BinOp) -> BinOp; + /// } + /// ``` + /// + /// *This module is available if Syn is built with the `"fold"` feature.* + #[cfg(feature = "fold")] + pub mod fold; + + #[cfg(any(feature = "full", feature = "derive"))] + #[path = "../gen_helper.rs"] + mod helper; +} +pub use gen::*; + +// Not public API. +#[doc(hidden)] +pub mod export; + +mod custom_keyword; +mod custom_punctuation; +mod sealed; + +#[cfg(feature = "parsing")] +mod lookahead; + +#[cfg(feature = "parsing")] +pub mod parse; + +mod span; + +#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] +mod print; + +mod thread; + +//////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "parsing", feature = "full", feature = "derive"))] +#[allow(non_camel_case_types)] +struct private; + +//////////////////////////////////////////////////////////////////////////////// + +mod error; +pub use error::{Error, Result}; + +/// Parse tokens of source code into the chosen syntax tree node. +/// +/// This is preferred over parsing a string because tokens are able to preserve +/// information about where in the user's code they were originally written (the +/// "span" of the token), possibly allowing the compiler to produce better error +/// messages. +/// +/// This function parses a `proc_macro::TokenStream` which is the type used for +/// interop with the compiler in a procedural macro. To parse a +/// `proc_macro2::TokenStream`, use [`syn::parse2`] instead. +/// +/// [`syn::parse2`]: fn.parse2.html +/// +/// *This function is available if Syn is built with both the `"parsing"` and +/// `"proc-macro"` features.* +/// +/// # Examples +/// +/// ```edition2018 +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use quote::quote; +/// use syn::DeriveInput; +/// +/// # const IGNORE_TOKENS: &str = stringify! { +/// #[proc_macro_derive(MyMacro)] +/// # }; +/// pub fn my_macro(input: TokenStream) -> TokenStream { +/// // Parse the tokens into a syntax tree +/// let ast: DeriveInput = syn::parse(input).unwrap(); +/// +/// // Build the output, possibly using quasi-quotation +/// let expanded = quote! { +/// /* ... */ +/// }; +/// +/// // Convert into a token stream and return it +/// expanded.into() +/// } +/// ``` +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "parsing", + feature = "proc-macro" +))] +pub fn parse<T: parse::Parse>(tokens: proc_macro::TokenStream) -> Result<T> { + parse::Parser::parse(T::parse, tokens) +} + +/// Parse a proc-macro2 token stream into the chosen syntax tree node. +/// +/// This function parses a `proc_macro2::TokenStream` which is commonly useful +/// when the input comes from a node of the Syn syntax tree, for example the tts +/// of a [`Macro`] node. When in a procedural macro parsing the +/// `proc_macro::TokenStream` provided by the compiler, use [`syn::parse`] +/// instead. +/// +/// [`Macro`]: struct.Macro.html +/// [`syn::parse`]: fn.parse.html +/// +/// *This function is available if Syn is built with the `"parsing"` feature.* +#[cfg(feature = "parsing")] +pub fn parse2<T: parse::Parse>(tokens: proc_macro2::TokenStream) -> Result<T> { + parse::Parser::parse2(T::parse, tokens) +} + +/// Parse a string of Rust code into the chosen syntax tree node. +/// +/// *This function is available if Syn is built with the `"parsing"` feature.* +/// +/// # Hygiene +/// +/// Every span in the resulting syntax tree will be set to resolve at the macro +/// call site. +/// +/// # Examples +/// +/// ```edition2018 +/// use syn::{Expr, Result}; +/// +/// fn run() -> Result<()> { +/// let code = "assert_eq!(u8::max_value(), 255)"; +/// let expr = syn::parse_str::<Expr>(code)?; +/// println!("{:#?}", expr); +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # run().unwrap(); +/// # } +/// ``` +#[cfg(feature = "parsing")] +pub fn parse_str<T: parse::Parse>(s: &str) -> Result<T> { + parse::Parser::parse_str(T::parse, s) +} + +// FIXME the name parse_file makes it sound like you might pass in a path to a +// file, rather than the content. +/// Parse the content of a file of Rust code. +/// +/// This is different from `syn::parse_str::<File>(content)` in two ways: +/// +/// - It discards a leading byte order mark `\u{FEFF}` if the file has one. +/// - It preserves the shebang line of the file, such as `#!/usr/bin/env rustx`. +/// +/// If present, either of these would be an error using `from_str`. +/// +/// *This function is available if Syn is built with the `"parsing"` and +/// `"full"` features.* +/// +/// # Examples +/// +/// ```edition2018,no_run +/// use std::error::Error; +/// use std::fs::File; +/// use std::io::Read; +/// +/// fn run() -> Result<(), Box<Error>> { +/// let mut file = File::open("path/to/code.rs")?; +/// let mut content = String::new(); +/// file.read_to_string(&mut content)?; +/// +/// let ast = syn::parse_file(&content)?; +/// if let Some(shebang) = ast.shebang { +/// println!("{}", shebang); +/// } +/// println!("{} items", ast.items.len()); +/// +/// Ok(()) +/// } +/// # +/// # fn main() { +/// # run().unwrap(); +/// # } +/// ``` +#[cfg(all(feature = "parsing", feature = "full"))] +pub fn parse_file(mut content: &str) -> Result<File> { + // Strip the BOM if it is present + const BOM: &'static str = "\u{feff}"; + if content.starts_with(BOM) { + content = &content[BOM.len()..]; + } + + let mut shebang = None; + if content.starts_with("#!") && !content.starts_with("#![") { + if let Some(idx) = content.find('\n') { + shebang = Some(content[..idx].to_string()); + content = &content[idx..]; + } else { + shebang = Some(content.to_string()); + content = ""; + } + } + + let mut file: File = parse_str(content)?; + file.shebang = shebang; + Ok(file) +} diff --git a/syn/src/lifetime.rs b/syn/src/lifetime.rs new file mode 100644 index 000000000..461560c91 --- /dev/null +++ b/syn/src/lifetime.rs @@ -0,0 +1,155 @@ +use std::cmp::Ordering; +use std::fmt::{self, Display}; +use std::hash::{Hash, Hasher}; + +use proc_macro2::{Ident, Span}; +use unicode_xid::UnicodeXID; + +#[cfg(feature = "parsing")] +use lookahead; + +/// A Rust lifetime: `'a`. +/// +/// Lifetime names must conform to the following rules: +/// +/// - Must start with an apostrophe. +/// - Must not consist of just an apostrophe: `'`. +/// - Character after the apostrophe must be `_` or a Unicode code point with +/// the XID_Start property. +/// - All following characters must be Unicode code points with the XID_Continue +/// property. +/// +/// *This type is available if Syn is built with the `"derive"` or `"full"` +/// feature.* +#[cfg_attr(feature = "extra-traits", derive(Debug))] +#[derive(Clone)] +pub struct Lifetime { + pub apostrophe: Span, + pub ident: Ident, +} + +impl Lifetime { + /// # Panics + /// + /// Panics if the lifetime does not conform to the bulleted rules above. + /// + /// # Invocation + /// + /// ```edition2018 + /// # use proc_macro2::Span; + /// # use syn::Lifetime; + /// # + /// # fn f() -> Lifetime { + /// Lifetime::new("'a", Span::call_site()) + /// # } + /// ``` + pub fn new(symbol: &str, span: Span) -> Self { + if !symbol.starts_with('\'') { + panic!( + "lifetime name must start with apostrophe as in \"'a\", got {:?}", + symbol + ); + } + + if symbol == "'" { + panic!("lifetime name must not be empty"); + } + + fn xid_ok(symbol: &str) -> bool { + let mut chars = symbol.chars(); + let first = chars.next().unwrap(); + if !(UnicodeXID::is_xid_start(first) || first == '_') { + return false; + } + for ch in chars { + if !UnicodeXID::is_xid_continue(ch) { + return false; + } + } + true + } + + if !xid_ok(&symbol[1..]) { + panic!("{:?} is not a valid lifetime name", symbol); + } + + Lifetime { + apostrophe: span, + ident: Ident::new(&symbol[1..], span), + } + } +} + +impl Display for Lifetime { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + "'".fmt(formatter)?; + self.ident.fmt(formatter) + } +} + +impl PartialEq for Lifetime { + fn eq(&self, other: &Lifetime) -> bool { + self.ident.eq(&other.ident) + } +} + +impl Eq for Lifetime {} + +impl PartialOrd for Lifetime { + fn partial_cmp(&self, other: &Lifetime) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Lifetime { + fn cmp(&self, other: &Lifetime) -> Ordering { + self.ident.cmp(&other.ident) + } +} + +impl Hash for Lifetime { + fn hash<H: Hasher>(&self, h: &mut H) { + self.ident.hash(h) + } +} + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime { + match marker {} +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + impl Parse for Lifetime { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + cursor + .lifetime() + .ok_or_else(|| cursor.error("expected lifetime")) + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::{Punct, Spacing, TokenStream}; + use quote::{ToTokens, TokenStreamExt}; + + impl ToTokens for Lifetime { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut apostrophe = Punct::new('\'', Spacing::Joint); + apostrophe.set_span(self.apostrophe); + tokens.append(apostrophe); + self.ident.to_tokens(tokens); + } + } +} diff --git a/syn/src/lit.rs b/syn/src/lit.rs new file mode 100644 index 000000000..3a66cb763 --- /dev/null +++ b/syn/src/lit.rs @@ -0,0 +1,1103 @@ +use proc_macro2::{Literal, Span}; +use std::str; + +#[cfg(feature = "printing")] +use proc_macro2::Ident; + +#[cfg(feature = "parsing")] +use proc_macro2::TokenStream; + +use proc_macro2::TokenTree; + +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; + +#[cfg(feature = "parsing")] +use lookahead; +#[cfg(feature = "parsing")] +use parse::{Parse, Parser, Result}; + +ast_enum_of_structs! { + /// A Rust literal such as a string or integer or boolean. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Lit { + /// A UTF-8 string literal: `"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Str(LitStr #manual_extra_traits { + token: Literal, + }), + + /// A byte string literal: `b"foo"`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub ByteStr(LitByteStr #manual_extra_traits { + token: Literal, + }), + + /// A byte literal: `b'f'`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Byte(LitByte #manual_extra_traits { + token: Literal, + }), + + /// A character literal: `'a'`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Char(LitChar #manual_extra_traits { + token: Literal, + }), + + /// An integer literal: `1` or `1u16`. + /// + /// Holds up to 64 bits of data. Use `LitVerbatim` for any larger + /// integer literal. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Int(LitInt #manual_extra_traits { + token: Literal, + }), + + /// A floating point literal: `1f64` or `1.0e10f64`. + /// + /// Must be finite. May not be infinte or NaN. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Float(LitFloat #manual_extra_traits { + token: Literal, + }), + + /// A boolean literal: `true` or `false`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Bool(LitBool #manual_extra_traits { + pub value: bool, + pub span: Span, + }), + + /// A raw token literal not interpreted by Syn, possibly because it + /// represents an integer larger than 64 bits. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Verbatim(LitVerbatim #manual_extra_traits { + pub token: Literal, + }), + } +} + +impl LitStr { + pub fn new(value: &str, span: Span) -> Self { + let mut lit = Literal::string(value); + lit.set_span(span); + LitStr { token: lit } + } + + pub fn value(&self) -> String { + value::parse_lit_str(&self.token.to_string()) + } + + /// Parse a syntax tree node from the content of this string literal. + /// + /// All spans in the syntax tree will point to the span of this `LitStr`. + /// + /// # Example + /// + /// ```edition2018 + /// use proc_macro2::Span; + /// use syn::{Attribute, Error, Ident, Lit, Meta, MetaNameValue, Path, Result}; + /// + /// // Parses the path from an attribute that looks like: + /// // + /// // #[path = "a::b::c"] + /// // + /// // or returns `None` if the input is some other attribute. + /// fn get_path(attr: &Attribute) -> Result<Option<Path>> { + /// if !attr.path.is_ident("path") { + /// return Ok(None); + /// } + /// + /// match attr.parse_meta()? { + /// Meta::NameValue(MetaNameValue { lit: Lit::Str(lit_str), .. }) => { + /// lit_str.parse().map(Some) + /// } + /// _ => { + /// let message = "expected #[path = \"...\"]"; + /// Err(Error::new_spanned(attr, message)) + /// } + /// } + /// } + /// ``` + #[cfg(feature = "parsing")] + pub fn parse<T: Parse>(&self) -> Result<T> { + self.parse_with(T::parse) + } + + /// Invoke parser on the content of this string literal. + /// + /// All spans in the syntax tree will point to the span of this `LitStr`. + /// + /// # Example + /// + /// ```edition2018 + /// # use proc_macro2::Span; + /// # use syn::{LitStr, Result}; + /// # + /// # fn main() -> Result<()> { + /// # let lit_str = LitStr::new("a::b::c", Span::call_site()); + /// # + /// # const IGNORE: &str = stringify! { + /// let lit_str: LitStr = /* ... */; + /// # }; + /// + /// // Parse a string literal like "a::b::c" into a Path, not allowing + /// // generic arguments on any of the path segments. + /// let basic_path = lit_str.parse_with(syn::Path::parse_mod_style)?; + /// # + /// # Ok(()) + /// # } + /// ``` + #[cfg(feature = "parsing")] + pub fn parse_with<F: Parser>(&self, parser: F) -> Result<F::Output> { + use proc_macro2::Group; + + // Token stream with every span replaced by the given one. + fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream { + stream + .into_iter() + .map(|token| respan_token_tree(token, span)) + .collect() + } + + // Token tree with every span replaced by the given one. + fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree { + match token { + TokenTree::Group(ref mut g) => { + let stream = respan_token_stream(g.stream().clone(), span); + *g = Group::new(g.delimiter(), stream); + g.set_span(span); + } + ref mut other => other.set_span(span), + } + token + } + + // Parse string literal into a token stream with every span equal to the + // original literal's span. + let mut tokens = ::parse_str(&self.value())?; + tokens = respan_token_stream(tokens, self.span()); + + parser.parse2(tokens) + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +impl LitByteStr { + pub fn new(value: &[u8], span: Span) -> Self { + let mut token = Literal::byte_string(value); + token.set_span(span); + LitByteStr { token: token } + } + + pub fn value(&self) -> Vec<u8> { + value::parse_lit_byte_str(&self.token.to_string()) + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +impl LitByte { + pub fn new(value: u8, span: Span) -> Self { + let mut token = Literal::u8_suffixed(value); + token.set_span(span); + LitByte { token: token } + } + + pub fn value(&self) -> u8 { + value::parse_lit_byte(&self.token.to_string()) + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +impl LitChar { + pub fn new(value: char, span: Span) -> Self { + let mut token = Literal::character(value); + token.set_span(span); + LitChar { token: token } + } + + pub fn value(&self) -> char { + value::parse_lit_char(&self.token.to_string()) + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +impl LitInt { + pub fn new(value: u64, suffix: IntSuffix, span: Span) -> Self { + let mut token = match suffix { + IntSuffix::Isize => Literal::isize_suffixed(value as isize), + IntSuffix::I8 => Literal::i8_suffixed(value as i8), + IntSuffix::I16 => Literal::i16_suffixed(value as i16), + IntSuffix::I32 => Literal::i32_suffixed(value as i32), + IntSuffix::I64 => Literal::i64_suffixed(value as i64), + IntSuffix::I128 => value::to_literal(&format!("{}i128", value)), + IntSuffix::Usize => Literal::usize_suffixed(value as usize), + IntSuffix::U8 => Literal::u8_suffixed(value as u8), + IntSuffix::U16 => Literal::u16_suffixed(value as u16), + IntSuffix::U32 => Literal::u32_suffixed(value as u32), + IntSuffix::U64 => Literal::u64_suffixed(value), + IntSuffix::U128 => value::to_literal(&format!("{}u128", value)), + IntSuffix::None => Literal::u64_unsuffixed(value), + }; + token.set_span(span); + LitInt { token: token } + } + + pub fn value(&self) -> u64 { + value::parse_lit_int(&self.token.to_string()).unwrap() + } + + pub fn suffix(&self) -> IntSuffix { + let value = self.token.to_string(); + for (s, suffix) in vec![ + ("i8", IntSuffix::I8), + ("i16", IntSuffix::I16), + ("i32", IntSuffix::I32), + ("i64", IntSuffix::I64), + ("i128", IntSuffix::I128), + ("isize", IntSuffix::Isize), + ("u8", IntSuffix::U8), + ("u16", IntSuffix::U16), + ("u32", IntSuffix::U32), + ("u64", IntSuffix::U64), + ("u128", IntSuffix::U128), + ("usize", IntSuffix::Usize), + ] { + if value.ends_with(s) { + return suffix; + } + } + IntSuffix::None + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +impl LitFloat { + pub fn new(value: f64, suffix: FloatSuffix, span: Span) -> Self { + let mut token = match suffix { + FloatSuffix::F32 => Literal::f32_suffixed(value as f32), + FloatSuffix::F64 => Literal::f64_suffixed(value), + FloatSuffix::None => Literal::f64_unsuffixed(value), + }; + token.set_span(span); + LitFloat { token: token } + } + + pub fn value(&self) -> f64 { + value::parse_lit_float(&self.token.to_string()) + } + + pub fn suffix(&self) -> FloatSuffix { + let value = self.token.to_string(); + for (s, suffix) in vec![("f32", FloatSuffix::F32), ("f64", FloatSuffix::F64)] { + if value.ends_with(s) { + return suffix; + } + } + FloatSuffix::None + } + + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +macro_rules! lit_extra_traits { + ($ty:ident, $field:ident) => { + #[cfg(feature = "extra-traits")] + impl Eq for $ty {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $ty { + fn eq(&self, other: &Self) -> bool { + self.$field.to_string() == other.$field.to_string() + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $ty { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + self.$field.to_string().hash(state); + } + } + + #[cfg(feature = "parsing")] + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ty(marker: lookahead::TokenMarker) -> $ty { + match marker {} + } + }; +} + +impl LitVerbatim { + pub fn span(&self) -> Span { + self.token.span() + } + + pub fn set_span(&mut self, span: Span) { + self.token.set_span(span) + } +} + +lit_extra_traits!(LitStr, token); +lit_extra_traits!(LitByteStr, token); +lit_extra_traits!(LitByte, token); +lit_extra_traits!(LitChar, token); +lit_extra_traits!(LitInt, token); +lit_extra_traits!(LitFloat, token); +lit_extra_traits!(LitBool, value); +lit_extra_traits!(LitVerbatim, token); + +ast_enum! { + /// The style of a string literal, either plain quoted or a raw string like + /// `r##"data"##`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum StrStyle #no_visit { + /// An ordinary string like `"data"`. + Cooked, + /// A raw string like `r##"data"##`. + /// + /// The unsigned integer is the number of `#` symbols used. + Raw(usize), + } +} + +ast_enum! { + /// The suffix on an integer literal if any, like the `u8` in `127u8`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum IntSuffix #no_visit { + I8, + I16, + I32, + I64, + I128, + Isize, + U8, + U16, + U32, + U64, + U128, + Usize, + None, + } +} + +ast_enum! { + /// The suffix on a floating point literal if any, like the `f32` in + /// `1.0f32`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum FloatSuffix #no_visit { + F32, + F64, + None, + } +} + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn Lit(marker: lookahead::TokenMarker) -> Lit { + match marker {} +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + use parse::{Parse, ParseStream, Result}; + + impl Parse for Lit { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((lit, rest)) = cursor.literal() { + return Ok((Lit::new(lit), rest)); + } + while let Some((ident, rest)) = cursor.ident() { + let value = if ident == "true" { + true + } else if ident == "false" { + false + } else { + break; + }; + let lit_bool = LitBool { + value: value, + span: ident.span(), + }; + return Ok((Lit::Bool(lit_bool), rest)); + } + Err(cursor.error("expected literal")) + }) + } + } + + impl Parse for LitStr { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Str(lit) => Ok(lit), + _ => Err(head.error("expected string literal")), + } + } + } + + impl Parse for LitByteStr { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::ByteStr(lit) => Ok(lit), + _ => Err(head.error("expected byte string literal")), + } + } + } + + impl Parse for LitByte { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Byte(lit) => Ok(lit), + _ => Err(head.error("expected byte literal")), + } + } + } + + impl Parse for LitChar { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Char(lit) => Ok(lit), + _ => Err(head.error("expected character literal")), + } + } + } + + impl Parse for LitInt { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Int(lit) => Ok(lit), + _ => Err(head.error("expected integer literal")), + } + } + } + + impl Parse for LitFloat { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Float(lit) => Ok(lit), + _ => Err(head.error("expected floating point literal")), + } + } + } + + impl Parse for LitBool { + fn parse(input: ParseStream) -> Result<Self> { + let head = input.fork(); + match input.parse()? { + Lit::Bool(lit) => Ok(lit), + _ => Err(head.error("expected boolean literal")), + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + impl ToTokens for LitStr { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitByteStr { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitByte { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitChar { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitInt { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitFloat { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } + + impl ToTokens for LitBool { + fn to_tokens(&self, tokens: &mut TokenStream) { + let s = if self.value { "true" } else { "false" }; + tokens.append(Ident::new(s, self.span)); + } + } + + impl ToTokens for LitVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.token.to_tokens(tokens); + } + } +} + +mod value { + use super::*; + use proc_macro2::TokenStream; + use std::char; + use std::ops::{Index, RangeFrom}; + + impl Lit { + /// Interpret a Syn literal from a proc-macro2 literal. + /// + /// Not all proc-macro2 literals are valid Syn literals. In particular, + /// doc comments are considered by proc-macro2 to be literals but in Syn + /// they are [`Attribute`]. + /// + /// [`Attribute`]: struct.Attribute.html + /// + /// # Panics + /// + /// Panics if the input is a doc comment literal. + pub fn new(token: Literal) -> Self { + let value = token.to_string(); + + match value::byte(&value, 0) { + b'"' | b'r' => return Lit::Str(LitStr { token: token }), + b'b' => match value::byte(&value, 1) { + b'"' | b'r' => return Lit::ByteStr(LitByteStr { token: token }), + b'\'' => return Lit::Byte(LitByte { token: token }), + _ => {} + }, + b'\'' => return Lit::Char(LitChar { token: token }), + b'0'...b'9' => { + if number_is_int(&value) { + return Lit::Int(LitInt { token: token }); + } else if number_is_float(&value) { + return Lit::Float(LitFloat { token: token }); + } else { + // number overflow + return Lit::Verbatim(LitVerbatim { token: token }); + } + } + _ => { + if value == "true" || value == "false" { + return Lit::Bool(LitBool { + value: value == "true", + span: token.span(), + }); + } + } + } + + panic!("Unrecognized literal: {}", value); + } + } + + fn number_is_int(value: &str) -> bool { + if number_is_float(value) { + false + } else { + value::parse_lit_int(value).is_some() + } + } + + fn number_is_float(value: &str) -> bool { + if value.contains('.') { + true + } else if value.starts_with("0x") || value.ends_with("size") { + false + } else { + value.contains('e') || value.contains('E') + } + } + + /// Get the byte at offset idx, or a default of `b'\0'` if we're looking + /// past the end of the input buffer. + pub fn byte<S: AsRef<[u8]> + ?Sized>(s: &S, idx: usize) -> u8 { + let s = s.as_ref(); + if idx < s.len() { + s[idx] + } else { + 0 + } + } + + fn next_chr(s: &str) -> char { + s.chars().next().unwrap_or('\0') + } + + pub fn parse_lit_str(s: &str) -> String { + match byte(s, 0) { + b'"' => parse_lit_str_cooked(s), + b'r' => parse_lit_str_raw(s), + _ => unreachable!(), + } + } + + // Clippy false positive + // https://github.com/rust-lang-nursery/rust-clippy/issues/2329 + #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))] + fn parse_lit_str_cooked(mut s: &str) -> String { + assert_eq!(byte(s, 0), b'"'); + s = &s[1..]; + + let mut out = String::new(); + 'outer: loop { + let ch = match byte(s, 0) { + b'"' => break, + b'\\' => { + let b = byte(s, 1); + s = &s[2..]; + match b { + b'x' => { + let (byte, rest) = backslash_x(s); + s = rest; + assert!(byte <= 0x80, "Invalid \\x byte in string literal"); + char::from_u32(u32::from(byte)).unwrap() + } + b'u' => { + let (chr, rest) = backslash_u(s); + s = rest; + chr + } + b'n' => '\n', + b'r' => '\r', + b't' => '\t', + b'\\' => '\\', + b'0' => '\0', + b'\'' => '\'', + b'"' => '"', + b'\r' | b'\n' => loop { + let ch = next_chr(s); + if ch.is_whitespace() { + s = &s[ch.len_utf8()..]; + } else { + continue 'outer; + } + }, + b => panic!("unexpected byte {:?} after \\ character in byte literal", b), + } + } + b'\r' => { + assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string"); + s = &s[2..]; + '\n' + } + _ => { + let ch = next_chr(s); + s = &s[ch.len_utf8()..]; + ch + } + }; + out.push(ch); + } + + assert_eq!(s, "\""); + out + } + + fn parse_lit_str_raw(mut s: &str) -> String { + assert_eq!(byte(s, 0), b'r'); + s = &s[1..]; + + let mut pounds = 0; + while byte(s, pounds) == b'#' { + pounds += 1; + } + assert_eq!(byte(s, pounds), b'"'); + assert_eq!(byte(s, s.len() - pounds - 1), b'"'); + for end in s[s.len() - pounds..].bytes() { + assert_eq!(end, b'#'); + } + + s[pounds + 1..s.len() - pounds - 1].to_owned() + } + + pub fn parse_lit_byte_str(s: &str) -> Vec<u8> { + assert_eq!(byte(s, 0), b'b'); + match byte(s, 1) { + b'"' => parse_lit_byte_str_cooked(s), + b'r' => parse_lit_byte_str_raw(s), + _ => unreachable!(), + } + } + + // Clippy false positive + // https://github.com/rust-lang-nursery/rust-clippy/issues/2329 + #[cfg_attr(feature = "cargo-clippy", allow(needless_continue))] + fn parse_lit_byte_str_cooked(mut s: &str) -> Vec<u8> { + assert_eq!(byte(s, 0), b'b'); + assert_eq!(byte(s, 1), b'"'); + s = &s[2..]; + + // We're going to want to have slices which don't respect codepoint boundaries. + let mut s = s.as_bytes(); + + let mut out = Vec::new(); + 'outer: loop { + let byte = match byte(s, 0) { + b'"' => break, + b'\\' => { + let b = byte(s, 1); + s = &s[2..]; + match b { + b'x' => { + let (b, rest) = backslash_x(s); + s = rest; + b + } + b'n' => b'\n', + b'r' => b'\r', + b't' => b'\t', + b'\\' => b'\\', + b'0' => b'\0', + b'\'' => b'\'', + b'"' => b'"', + b'\r' | b'\n' => loop { + let byte = byte(s, 0); + let ch = char::from_u32(u32::from(byte)).unwrap(); + if ch.is_whitespace() { + s = &s[1..]; + } else { + continue 'outer; + } + }, + b => panic!("unexpected byte {:?} after \\ character in byte literal", b), + } + } + b'\r' => { + assert_eq!(byte(s, 1), b'\n', "Bare CR not allowed in string"); + s = &s[2..]; + b'\n' + } + b => { + s = &s[1..]; + b + } + }; + out.push(byte); + } + + assert_eq!(s, b"\""); + out + } + + fn parse_lit_byte_str_raw(s: &str) -> Vec<u8> { + assert_eq!(byte(s, 0), b'b'); + parse_lit_str_raw(&s[1..]).into_bytes() + } + + pub fn parse_lit_byte(s: &str) -> u8 { + assert_eq!(byte(s, 0), b'b'); + assert_eq!(byte(s, 1), b'\''); + + // We're going to want to have slices which don't respect codepoint boundaries. + let mut s = s[2..].as_bytes(); + + let b = match byte(s, 0) { + b'\\' => { + let b = byte(s, 1); + s = &s[2..]; + match b { + b'x' => { + let (b, rest) = backslash_x(s); + s = rest; + b + } + b'n' => b'\n', + b'r' => b'\r', + b't' => b'\t', + b'\\' => b'\\', + b'0' => b'\0', + b'\'' => b'\'', + b'"' => b'"', + b => panic!("unexpected byte {:?} after \\ character in byte literal", b), + } + } + b => { + s = &s[1..]; + b + } + }; + + assert_eq!(byte(s, 0), b'\''); + b + } + + pub fn parse_lit_char(mut s: &str) -> char { + assert_eq!(byte(s, 0), b'\''); + s = &s[1..]; + + let ch = match byte(s, 0) { + b'\\' => { + let b = byte(s, 1); + s = &s[2..]; + match b { + b'x' => { + let (byte, rest) = backslash_x(s); + s = rest; + assert!(byte <= 0x80, "Invalid \\x byte in string literal"); + char::from_u32(u32::from(byte)).unwrap() + } + b'u' => { + let (chr, rest) = backslash_u(s); + s = rest; + chr + } + b'n' => '\n', + b'r' => '\r', + b't' => '\t', + b'\\' => '\\', + b'0' => '\0', + b'\'' => '\'', + b'"' => '"', + b => panic!("unexpected byte {:?} after \\ character in byte literal", b), + } + } + _ => { + let ch = next_chr(s); + s = &s[ch.len_utf8()..]; + ch + } + }; + assert_eq!(s, "\'", "Expected end of char literal"); + ch + } + + fn backslash_x<S>(s: &S) -> (u8, &S) + where + S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized, + { + let mut ch = 0; + let b0 = byte(s, 0); + let b1 = byte(s, 1); + ch += 0x10 + * match b0 { + b'0'...b'9' => b0 - b'0', + b'a'...b'f' => 10 + (b0 - b'a'), + b'A'...b'F' => 10 + (b0 - b'A'), + _ => panic!("unexpected non-hex character after \\x"), + }; + ch += match b1 { + b'0'...b'9' => b1 - b'0', + b'a'...b'f' => 10 + (b1 - b'a'), + b'A'...b'F' => 10 + (b1 - b'A'), + _ => panic!("unexpected non-hex character after \\x"), + }; + (ch, &s[2..]) + } + + fn backslash_u(mut s: &str) -> (char, &str) { + if byte(s, 0) != b'{' { + panic!("expected {{ after \\u"); + } + s = &s[1..]; + + let mut ch = 0; + for _ in 0..6 { + let b = byte(s, 0); + match b { + b'0'...b'9' => { + ch *= 0x10; + ch += u32::from(b - b'0'); + s = &s[1..]; + } + b'a'...b'f' => { + ch *= 0x10; + ch += u32::from(10 + b - b'a'); + s = &s[1..]; + } + b'A'...b'F' => { + ch *= 0x10; + ch += u32::from(10 + b - b'A'); + s = &s[1..]; + } + b'}' => break, + _ => panic!("unexpected non-hex character after \\u"), + } + } + assert!(byte(s, 0) == b'}'); + s = &s[1..]; + + if let Some(ch) = char::from_u32(ch) { + (ch, s) + } else { + panic!("character code {:x} is not a valid unicode character", ch); + } + } + + pub fn parse_lit_int(mut s: &str) -> Option<u64> { + let base = match (byte(s, 0), byte(s, 1)) { + (b'0', b'x') => { + s = &s[2..]; + 16 + } + (b'0', b'o') => { + s = &s[2..]; + 8 + } + (b'0', b'b') => { + s = &s[2..]; + 2 + } + (b'0'...b'9', _) => 10, + _ => unreachable!(), + }; + + let mut value = 0u64; + loop { + let b = byte(s, 0); + let digit = match b { + b'0'...b'9' => u64::from(b - b'0'), + b'a'...b'f' if base > 10 => 10 + u64::from(b - b'a'), + b'A'...b'F' if base > 10 => 10 + u64::from(b - b'A'), + b'_' => { + s = &s[1..]; + continue; + } + // NOTE: Looking at a floating point literal, we don't want to + // consider these integers. + b'.' if base == 10 => return None, + b'e' | b'E' if base == 10 => return None, + _ => break, + }; + + if digit >= base { + panic!("Unexpected digit {:x} out of base range", digit); + } + + value = match value.checked_mul(base) { + Some(value) => value, + None => return None, + }; + value = match value.checked_add(digit) { + Some(value) => value, + None => return None, + }; + s = &s[1..]; + } + + Some(value) + } + + pub fn parse_lit_float(input: &str) -> f64 { + // Rust's floating point literals are very similar to the ones parsed by + // the standard library, except that rust's literals can contain + // ignorable underscores. Let's remove those underscores. + let mut bytes = input.to_owned().into_bytes(); + let mut write = 0; + for read in 0..bytes.len() { + if bytes[read] == b'_' { + continue; // Don't increase write + } + if write != read { + let x = bytes[read]; + bytes[write] = x; + } + write += 1; + } + bytes.truncate(write); + let input = String::from_utf8(bytes).unwrap(); + let end = input.find('f').unwrap_or_else(|| input.len()); + input[..end].parse().unwrap() + } + + pub fn to_literal(s: &str) -> Literal { + let stream = s.parse::<TokenStream>().unwrap(); + match stream.into_iter().next().unwrap() { + TokenTree::Literal(l) => l, + _ => unreachable!(), + } + } +} diff --git a/syn/src/lookahead.rs b/syn/src/lookahead.rs new file mode 100644 index 000000000..0f5afe189 --- /dev/null +++ b/syn/src/lookahead.rs @@ -0,0 +1,168 @@ +use std::cell::RefCell; + +use proc_macro2::{Delimiter, Span}; + +use buffer::Cursor; +use error::{self, Error}; +use sealed::lookahead::Sealed; +use span::IntoSpans; +use token::Token; + +/// Support for checking the next token in a stream to decide how to parse. +/// +/// An important advantage over [`ParseStream::peek`] is that here we +/// automatically construct an appropriate error message based on the token +/// alternatives that get peeked. If you are producing your own error message, +/// go ahead and use `ParseStream::peek` instead. +/// +/// Use [`ParseStream::lookahead1`] to construct this object. +/// +/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek +/// [`ParseStream::lookahead1`]: struct.ParseBuffer.html#method.lookahead1 +/// +/// # Example +/// +/// ```edition2018 +/// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// // A generic parameter, a single one of the comma-separated elements inside +/// // angle brackets in: +/// // +/// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } +/// // +/// // On invalid input, lookahead gives us a reasonable error message. +/// // +/// // error: expected one of: identifier, lifetime, `const` +/// // | +/// // 5 | fn f<!Sized>() {} +/// // | ^ +/// enum GenericParam { +/// Type(TypeParam), +/// Lifetime(LifetimeDef), +/// Const(ConstParam), +/// } +/// +/// impl Parse for GenericParam { +/// fn parse(input: ParseStream) -> Result<Self> { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(Ident) { +/// input.parse().map(GenericParam::Type) +/// } else if lookahead.peek(Lifetime) { +/// input.parse().map(GenericParam::Lifetime) +/// } else if lookahead.peek(Token![const]) { +/// input.parse().map(GenericParam::Const) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +pub struct Lookahead1<'a> { + scope: Span, + cursor: Cursor<'a>, + comparisons: RefCell<Vec<&'static str>>, +} + +pub fn new(scope: Span, cursor: Cursor) -> Lookahead1 { + Lookahead1 { + scope: scope, + cursor: cursor, + comparisons: RefCell::new(Vec::new()), + } +} + +fn peek_impl( + lookahead: &Lookahead1, + peek: fn(Cursor) -> bool, + display: fn() -> &'static str, +) -> bool { + if peek(lookahead.cursor) { + return true; + } + lookahead.comparisons.borrow_mut().push(display()); + false +} + +impl<'a> Lookahead1<'a> { + /// Looks at the next token in the parse stream to determine whether it + /// matches the requested type of token. + /// + /// # Syntax + /// + /// Note that this method does not use turbofish syntax. Pass the peek type + /// inside of parentheses. + /// + /// - `input.peek(Token![struct])` + /// - `input.peek(Token![==])` + /// - `input.peek(Ident)` *(does not accept keywords)* + /// - `input.peek(Ident::peek_any)` + /// - `input.peek(Lifetime)` + /// - `input.peek(token::Brace)` + pub fn peek<T: Peek>(&self, token: T) -> bool { + let _ = token; + peek_impl(self, T::Token::peek, T::Token::display) + } + + /// Triggers an error at the current position of the parse stream. + /// + /// The error message will identify all of the expected token types that + /// have been peeked against this lookahead instance. + pub fn error(self) -> Error { + let comparisons = self.comparisons.borrow(); + match comparisons.len() { + 0 => { + if self.cursor.eof() { + Error::new(self.scope, "unexpected end of input") + } else { + Error::new(self.cursor.span(), "unexpected token") + } + } + 1 => { + let message = format!("expected {}", comparisons[0]); + error::new_at(self.scope, self.cursor, message) + } + 2 => { + let message = format!("expected {} or {}", comparisons[0], comparisons[1]); + error::new_at(self.scope, self.cursor, message) + } + _ => { + let join = comparisons.join(", "); + let message = format!("expected one of: {}", join); + error::new_at(self.scope, self.cursor, message) + } + } + } +} + +/// Types that can be parsed by looking at just one token. +/// +/// Use [`ParseStream::peek`] to peek one of these types in a parse stream +/// without consuming it from the stream. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. +/// +/// [`ParseStream::peek`]: struct.ParseBuffer.html#method.peek +pub trait Peek: Sealed { + // Not public API. + #[doc(hidden)] + type Token: Token; +} + +impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Peek for F { + type Token = T; +} + +pub enum TokenMarker {} + +impl<S> IntoSpans<S> for TokenMarker { + fn into_spans(self) -> S { + match self {} + } +} + +pub fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool { + cursor.group(delimiter).is_some() +} + +impl<F: Copy + FnOnce(TokenMarker) -> T, T: Token> Sealed for F {} diff --git a/syn/src/mac.rs b/syn/src/mac.rs new file mode 100644 index 000000000..46dc5dd57 --- /dev/null +++ b/syn/src/mac.rs @@ -0,0 +1,131 @@ +use super::*; +use proc_macro2::TokenStream; +#[cfg(feature = "parsing")] +use proc_macro2::{Delimiter, TokenTree}; +use token::{Brace, Bracket, Paren}; + +#[cfg(feature = "parsing")] +use parse::{ParseStream, Result}; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(feature = "extra-traits")] +use tt::TokenStreamHelper; + +ast_struct! { + /// A macro invocation: `println!("{}", mac)`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Macro #manual_extra_traits { + pub path: Path, + pub bang_token: Token![!], + pub delimiter: MacroDelimiter, + pub tts: TokenStream, + } +} + +ast_enum! { + /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum MacroDelimiter { + Paren(Paren), + Brace(Brace), + Bracket(Bracket), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Macro {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Macro { + fn eq(&self, other: &Self) -> bool { + self.path == other.path + && self.bang_token == other.bang_token + && self.delimiter == other.delimiter + && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Macro { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + self.path.hash(state); + self.bang_token.hash(state); + self.delimiter.hash(state); + TokenStreamHelper(&self.tts).hash(state); + } +} + +#[cfg(feature = "parsing")] +pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> { + input.step(|cursor| { + if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() { + let span = g.span(); + let delimiter = match g.delimiter() { + Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)), + Delimiter::Brace => MacroDelimiter::Brace(Brace(span)), + Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)), + Delimiter::None => { + return Err(cursor.error("expected delimiter")); + } + }; + Ok(((delimiter, g.stream().clone()), rest)) + } else { + Err(cursor.error("expected delimiter")) + } + }) +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + impl Parse for Macro { + fn parse(input: ParseStream) -> Result<Self> { + let tts; + Ok(Macro { + path: input.call(Path::parse_mod_style)?, + bang_token: input.parse()?, + delimiter: { + let (delimiter, content) = parse_delimiter(input)?; + tts = content; + delimiter + }, + tts: tts, + }) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use proc_macro2::TokenStream; + use quote::ToTokens; + + impl ToTokens for Macro { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.path.to_tokens(tokens); + self.bang_token.to_tokens(tokens); + match self.delimiter { + MacroDelimiter::Paren(ref paren) => { + paren.surround(tokens, |tokens| self.tts.to_tokens(tokens)); + } + MacroDelimiter::Brace(ref brace) => { + brace.surround(tokens, |tokens| self.tts.to_tokens(tokens)); + } + MacroDelimiter::Bracket(ref bracket) => { + bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens)); + } + } + } + } +} diff --git a/syn/src/macros.rs b/syn/src/macros.rs new file mode 100644 index 000000000..bb59063a6 --- /dev/null +++ b/syn/src/macros.rs @@ -0,0 +1,165 @@ +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! ast_struct { + ( + $(#[$attr:meta])* + pub struct $name:ident #full $($rest:tt)* + ) => { + #[cfg(feature = "full")] + $(#[$attr])* + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + pub struct $name $($rest)* + + #[cfg(not(feature = "full"))] + $(#[$attr])* + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + pub struct $name { + _noconstruct: (), + } + }; + + ( + $(#[$attr:meta])* + pub struct $name:ident #manual_extra_traits $($rest:tt)* + ) => { + $(#[$attr])* + #[cfg_attr(feature = "extra-traits", derive(Debug))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + pub struct $name $($rest)* + }; + + ( + $(#[$attr:meta])* + pub struct $name:ident $($rest:tt)* + ) => { + $(#[$attr])* + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + pub struct $name $($rest)* + }; +} + +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! ast_enum { + ( + $(#[$enum_attr:meta])* + pub enum $name:ident $(# $tags:ident)* { $($variants:tt)* } + ) => ( + $(#[$enum_attr])* + #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] + #[cfg_attr(feature = "clone-impls", derive(Clone))] + pub enum $name { + $($variants)* + } + ) +} + +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! ast_enum_of_structs { + ( + $(#[$enum_attr:meta])* + pub enum $name:ident { + $( + $(#[$variant_attr:meta])* + pub $variant:ident $( ($member:ident $($rest:tt)*) )*, + )* + } + + $($remaining:tt)* + ) => ( + ast_enum! { + $(#[$enum_attr])* + pub enum $name { + $( + $(#[$variant_attr])* + $variant $( ($member) )*, + )* + } + } + + $( + maybe_ast_struct! { + $(#[$variant_attr])* + $( + pub struct $member $($rest)* + )* + } + + $( + impl From<$member> for $name { + fn from(e: $member) -> $name { + $name::$variant(e) + } + } + )* + )* + + #[cfg(feature = "printing")] + generate_to_tokens! { + $($remaining)* + () + tokens + $name { $($variant $( [$($rest)*] )*,)* } + } + ) +} + +#[cfg(all(feature = "printing", any(feature = "full", feature = "derive")))] +macro_rules! generate_to_tokens { + (do_not_generate_to_tokens $($foo:tt)*) => (); + + (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident, $($next:tt)*}) => { + generate_to_tokens!( + ($($arms)* $name::$variant => {}) + $tokens $name { $($next)* } + ); + }; + + (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident [$($rest:tt)*], $($next:tt)*}) => { + generate_to_tokens!( + ($($arms)* $name::$variant(ref _e) => to_tokens_call!(_e, $tokens, $($rest)*),) + $tokens $name { $($next)* } + ); + }; + + (($($arms:tt)*) $tokens:ident $name:ident {}) => { + impl ::quote::ToTokens for $name { + fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) { + match *self { + $($arms)* + } + } + } + }; +} + +#[cfg(all(feature = "printing", feature = "full"))] +macro_rules! to_tokens_call { + ($e:ident, $tokens:ident, $($rest:tt)*) => { + $e.to_tokens($tokens) + }; +} + +#[cfg(all(feature = "printing", feature = "derive", not(feature = "full")))] +macro_rules! to_tokens_call { + // If the variant is marked as #full, don't auto-generate to-tokens for it. + ($e:ident, $tokens:ident, #full $($rest:tt)*) => { + unreachable!() + }; + ($e:ident, $tokens:ident, $($rest:tt)*) => { + $e.to_tokens($tokens) + }; +} + +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! maybe_ast_struct { + ( + $(#[$attr:meta])* + $( + pub struct $name:ident + )* + ) => (); + + ($($rest:tt)*) => (ast_struct! { $($rest)* }); +} diff --git a/syn/src/op.rs b/syn/src/op.rs new file mode 100644 index 000000000..96d8c9958 --- /dev/null +++ b/syn/src/op.rs @@ -0,0 +1,231 @@ +ast_enum! { + /// A binary operator: `+`, `+=`, `&`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + #[cfg_attr(feature = "clone-impls", derive(Copy))] + pub enum BinOp { + /// The `+` operator (addition) + Add(Token![+]), + /// The `-` operator (subtraction) + Sub(Token![-]), + /// The `*` operator (multiplication) + Mul(Token![*]), + /// The `/` operator (division) + Div(Token![/]), + /// The `%` operator (modulus) + Rem(Token![%]), + /// The `&&` operator (logical and) + And(Token![&&]), + /// The `||` operator (logical or) + Or(Token![||]), + /// The `^` operator (bitwise xor) + BitXor(Token![^]), + /// The `&` operator (bitwise and) + BitAnd(Token![&]), + /// The `|` operator (bitwise or) + BitOr(Token![|]), + /// The `<<` operator (shift left) + Shl(Token![<<]), + /// The `>>` operator (shift right) + Shr(Token![>>]), + /// The `==` operator (equality) + Eq(Token![==]), + /// The `<` operator (less than) + Lt(Token![<]), + /// The `<=` operator (less than or equal to) + Le(Token![<=]), + /// The `!=` operator (not equal to) + Ne(Token![!=]), + /// The `>=` operator (greater than or equal to) + Ge(Token![>=]), + /// The `>` operator (greater than) + Gt(Token![>]), + /// The `+=` operator + AddEq(Token![+=]), + /// The `-=` operator + SubEq(Token![-=]), + /// The `*=` operator + MulEq(Token![*=]), + /// The `/=` operator + DivEq(Token![/=]), + /// The `%=` operator + RemEq(Token![%=]), + /// The `^=` operator + BitXorEq(Token![^=]), + /// The `&=` operator + BitAndEq(Token![&=]), + /// The `|=` operator + BitOrEq(Token![|=]), + /// The `<<=` operator + ShlEq(Token![<<=]), + /// The `>>=` operator + ShrEq(Token![>>=]), + } +} + +ast_enum! { + /// A unary operator: `*`, `!`, `-`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + #[cfg_attr(feature = "clone-impls", derive(Copy))] + pub enum UnOp { + /// The `*` operator for dereferencing + Deref(Token![*]), + /// The `!` operator for logical inversion + Not(Token![!]), + /// The `-` operator for negation + Neg(Token![-]), + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + + fn parse_binop(input: ParseStream) -> Result<BinOp> { + if input.peek(Token![&&]) { + input.parse().map(BinOp::And) + } else if input.peek(Token![||]) { + input.parse().map(BinOp::Or) + } else if input.peek(Token![<<]) { + input.parse().map(BinOp::Shl) + } else if input.peek(Token![>>]) { + input.parse().map(BinOp::Shr) + } else if input.peek(Token![==]) { + input.parse().map(BinOp::Eq) + } else if input.peek(Token![<=]) { + input.parse().map(BinOp::Le) + } else if input.peek(Token![!=]) { + input.parse().map(BinOp::Ne) + } else if input.peek(Token![>=]) { + input.parse().map(BinOp::Ge) + } else if input.peek(Token![+]) { + input.parse().map(BinOp::Add) + } else if input.peek(Token![-]) { + input.parse().map(BinOp::Sub) + } else if input.peek(Token![*]) { + input.parse().map(BinOp::Mul) + } else if input.peek(Token![/]) { + input.parse().map(BinOp::Div) + } else if input.peek(Token![%]) { + input.parse().map(BinOp::Rem) + } else if input.peek(Token![^]) { + input.parse().map(BinOp::BitXor) + } else if input.peek(Token![&]) { + input.parse().map(BinOp::BitAnd) + } else if input.peek(Token![|]) { + input.parse().map(BinOp::BitOr) + } else if input.peek(Token![<]) { + input.parse().map(BinOp::Lt) + } else if input.peek(Token![>]) { + input.parse().map(BinOp::Gt) + } else { + Err(input.error("expected binary operator")) + } + } + + impl Parse for BinOp { + #[cfg(not(feature = "full"))] + fn parse(input: ParseStream) -> Result<Self> { + parse_binop(input) + } + + #[cfg(feature = "full")] + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![+=]) { + input.parse().map(BinOp::AddEq) + } else if input.peek(Token![-=]) { + input.parse().map(BinOp::SubEq) + } else if input.peek(Token![*=]) { + input.parse().map(BinOp::MulEq) + } else if input.peek(Token![/=]) { + input.parse().map(BinOp::DivEq) + } else if input.peek(Token![%=]) { + input.parse().map(BinOp::RemEq) + } else if input.peek(Token![^=]) { + input.parse().map(BinOp::BitXorEq) + } else if input.peek(Token![&=]) { + input.parse().map(BinOp::BitAndEq) + } else if input.peek(Token![|=]) { + input.parse().map(BinOp::BitOrEq) + } else if input.peek(Token![<<=]) { + input.parse().map(BinOp::ShlEq) + } else if input.peek(Token![>>=]) { + input.parse().map(BinOp::ShrEq) + } else { + parse_binop(input) + } + } + } + + impl Parse for UnOp { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![*]) { + input.parse().map(UnOp::Deref) + } else if lookahead.peek(Token![!]) { + input.parse().map(UnOp::Not) + } else if lookahead.peek(Token![-]) { + input.parse().map(UnOp::Neg) + } else { + Err(lookahead.error()) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use proc_macro2::TokenStream; + use quote::ToTokens; + + impl ToTokens for BinOp { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + BinOp::Add(ref t) => t.to_tokens(tokens), + BinOp::Sub(ref t) => t.to_tokens(tokens), + BinOp::Mul(ref t) => t.to_tokens(tokens), + BinOp::Div(ref t) => t.to_tokens(tokens), + BinOp::Rem(ref t) => t.to_tokens(tokens), + BinOp::And(ref t) => t.to_tokens(tokens), + BinOp::Or(ref t) => t.to_tokens(tokens), + BinOp::BitXor(ref t) => t.to_tokens(tokens), + BinOp::BitAnd(ref t) => t.to_tokens(tokens), + BinOp::BitOr(ref t) => t.to_tokens(tokens), + BinOp::Shl(ref t) => t.to_tokens(tokens), + BinOp::Shr(ref t) => t.to_tokens(tokens), + BinOp::Eq(ref t) => t.to_tokens(tokens), + BinOp::Lt(ref t) => t.to_tokens(tokens), + BinOp::Le(ref t) => t.to_tokens(tokens), + BinOp::Ne(ref t) => t.to_tokens(tokens), + BinOp::Ge(ref t) => t.to_tokens(tokens), + BinOp::Gt(ref t) => t.to_tokens(tokens), + BinOp::AddEq(ref t) => t.to_tokens(tokens), + BinOp::SubEq(ref t) => t.to_tokens(tokens), + BinOp::MulEq(ref t) => t.to_tokens(tokens), + BinOp::DivEq(ref t) => t.to_tokens(tokens), + BinOp::RemEq(ref t) => t.to_tokens(tokens), + BinOp::BitXorEq(ref t) => t.to_tokens(tokens), + BinOp::BitAndEq(ref t) => t.to_tokens(tokens), + BinOp::BitOrEq(ref t) => t.to_tokens(tokens), + BinOp::ShlEq(ref t) => t.to_tokens(tokens), + BinOp::ShrEq(ref t) => t.to_tokens(tokens), + } + } + } + + impl ToTokens for UnOp { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + UnOp::Deref(ref t) => t.to_tokens(tokens), + UnOp::Not(ref t) => t.to_tokens(tokens), + UnOp::Neg(ref t) => t.to_tokens(tokens), + } + } + } +} diff --git a/syn/src/parse.rs b/syn/src/parse.rs new file mode 100644 index 000000000..c5786e740 --- /dev/null +++ b/syn/src/parse.rs @@ -0,0 +1,1111 @@ +//! Parsing interface for parsing a token stream into a syntax tree node. +//! +//! Parsing in Syn is built on parser functions that take in a [`ParseStream`] +//! and produce a [`Result<T>`] where `T` is some syntax tree node. Underlying +//! these parser functions is a lower level mechanism built around the +//! [`Cursor`] type. `Cursor` is a cheaply copyable cursor over a range of +//! tokens in a token stream. +//! +//! [`ParseStream`]: type.ParseStream.html +//! [`Result<T>`]: type.Result.html +//! [`Cursor`]: ../buffer/index.html +//! +//! # Example +//! +//! Here is a snippet of parsing code to get a feel for the style of the +//! library. We define data structures for a subset of Rust syntax including +//! enums (not shown) and structs, then provide implementations of the [`Parse`] +//! trait to parse these syntax tree data structures from a token stream. +//! +//! Once `Parse` impls have been defined, they can be called conveniently from a +//! procedural macro through [`parse_macro_input!`] as shown at the bottom of +//! the snippet. If the caller provides syntactically invalid input to the +//! procedural macro, they will receive a helpful compiler error message +//! pointing out the exact token that triggered the failure to parse. +//! +//! [`parse_macro_input!`]: ../macro.parse_macro_input.html +//! +//! ```edition2018 +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use syn::{braced, parse_macro_input, token, Field, Ident, Result, Token}; +//! use syn::parse::{Parse, ParseStream}; +//! use syn::punctuated::Punctuated; +//! +//! enum Item { +//! Struct(ItemStruct), +//! Enum(ItemEnum), +//! } +//! +//! struct ItemStruct { +//! struct_token: Token![struct], +//! ident: Ident, +//! brace_token: token::Brace, +//! fields: Punctuated<Field, Token![,]>, +//! } +//! # +//! # enum ItemEnum {} +//! +//! impl Parse for Item { +//! fn parse(input: ParseStream) -> Result<Self> { +//! let lookahead = input.lookahead1(); +//! if lookahead.peek(Token![struct]) { +//! input.parse().map(Item::Struct) +//! } else if lookahead.peek(Token![enum]) { +//! input.parse().map(Item::Enum) +//! } else { +//! Err(lookahead.error()) +//! } +//! } +//! } +//! +//! impl Parse for ItemStruct { +//! fn parse(input: ParseStream) -> Result<Self> { +//! let content; +//! Ok(ItemStruct { +//! struct_token: input.parse()?, +//! ident: input.parse()?, +//! brace_token: braced!(content in input), +//! fields: content.parse_terminated(Field::parse_named)?, +//! }) +//! } +//! } +//! # +//! # impl Parse for ItemEnum { +//! # fn parse(input: ParseStream) -> Result<Self> { +//! # unimplemented!() +//! # } +//! # } +//! +//! # const IGNORE: &str = stringify! { +//! #[proc_macro] +//! # }; +//! pub fn my_macro(tokens: TokenStream) -> TokenStream { +//! let input = parse_macro_input!(tokens as Item); +//! +//! /* ... */ +//! # "".parse().unwrap() +//! } +//! ``` +//! +//! # The `syn::parse*` functions +//! +//! The [`syn::parse`], [`syn::parse2`], and [`syn::parse_str`] functions serve +//! as an entry point for parsing syntax tree nodes that can be parsed in an +//! obvious default way. These functions can return any syntax tree node that +//! implements the [`Parse`] trait, which includes most types in Syn. +//! +//! [`syn::parse`]: ../fn.parse.html +//! [`syn::parse2`]: ../fn.parse2.html +//! [`syn::parse_str`]: ../fn.parse_str.html +//! [`Parse`]: trait.Parse.html +//! +//! ```edition2018 +//! use syn::Type; +//! +//! # fn run_parser() -> syn::Result<()> { +//! let t: Type = syn::parse_str("std::collections::HashMap<String, Value>")?; +//! # Ok(()) +//! # } +//! # +//! # fn main() { +//! # run_parser().unwrap(); +//! # } +//! ``` +//! +//! The [`parse_quote!`] macro also uses this approach. +//! +//! [`parse_quote!`]: ../macro.parse_quote.html +//! +//! # The `Parser` trait +//! +//! Some types can be parsed in several ways depending on context. For example +//! an [`Attribute`] can be either "outer" like `#[...]` or "inner" like +//! `#![...]` and parsing the wrong one would be a bug. Similarly [`Punctuated`] +//! may or may not allow trailing punctuation, and parsing it the wrong way +//! would either reject valid input or accept invalid input. +//! +//! [`Attribute`]: ../struct.Attribute.html +//! [`Punctuated`]: ../punctuated/index.html +//! +//! The `Parse` trait is not implemented in these cases because there is no good +//! behavior to consider the default. +//! +//! ```edition2018,compile_fail +//! # extern crate proc_macro; +//! # +//! # use syn::punctuated::Punctuated; +//! # use syn::{PathSegment, Result, Token}; +//! # +//! # fn f(tokens: proc_macro::TokenStream) -> Result<()> { +//! # +//! // Can't parse `Punctuated` without knowing whether trailing punctuation +//! // should be allowed in this context. +//! let path: Punctuated<PathSegment, Token![::]> = syn::parse(tokens)?; +//! # +//! # Ok(()) +//! # } +//! ``` +//! +//! In these cases the types provide a choice of parser functions rather than a +//! single `Parse` implementation, and those parser functions can be invoked +//! through the [`Parser`] trait. +//! +//! [`Parser`]: trait.Parser.html +//! +//! ```edition2018 +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! use syn::parse::Parser; +//! use syn::punctuated::Punctuated; +//! use syn::{Attribute, Expr, PathSegment, Result, Token}; +//! +//! fn call_some_parser_methods(input: TokenStream) -> Result<()> { +//! // Parse a nonempty sequence of path segments separated by `::` punctuation +//! // with no trailing punctuation. +//! let tokens = input.clone(); +//! let parser = Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty; +//! let _path = parser.parse(tokens)?; +//! +//! // Parse a possibly empty sequence of expressions terminated by commas with +//! // an optional trailing punctuation. +//! let tokens = input.clone(); +//! let parser = Punctuated::<Expr, Token![,]>::parse_terminated; +//! let _args = parser.parse(tokens)?; +//! +//! // Parse zero or more outer attributes but not inner attributes. +//! let tokens = input.clone(); +//! let parser = Attribute::parse_outer; +//! let _attrs = parser.parse(tokens)?; +//! +//! Ok(()) +//! } +//! ``` +//! +//! --- +//! +//! *This module is available if Syn is built with the `"parsing"` feature.* + +use std::cell::Cell; +use std::fmt::{self, Debug, Display}; +use std::marker::PhantomData; +use std::mem; +use std::ops::Deref; +use std::rc::Rc; +use std::str::FromStr; + +#[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" +))] +use proc_macro; +use proc_macro2::{self, Delimiter, Group, Literal, Punct, Span, TokenStream, TokenTree}; + +use buffer::{Cursor, TokenBuffer}; +use error; +use lookahead; +use private; +use punctuated::Punctuated; +use token::Token; + +pub use error::{Error, Result}; +pub use lookahead::{Lookahead1, Peek}; + +/// Parsing interface implemented by all types that can be parsed in a default +/// way from a token stream. +pub trait Parse: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +/// Input to a Syn parser function. +/// +/// See the methods of this type under the documentation of [`ParseBuffer`]. For +/// an overview of parsing in Syn, refer to the [module documentation]. +/// +/// [module documentation]: index.html +pub type ParseStream<'a> = &'a ParseBuffer<'a>; + +/// Cursor position within a buffered token stream. +/// +/// This type is more commonly used through the type alias [`ParseStream`] which +/// is an alias for `&ParseBuffer`. +/// +/// `ParseStream` is the input type for all parser functions in Syn. They have +/// the signature `fn(ParseStream) -> Result<T>`. +/// +/// ## Calling a parser function +/// +/// There is no public way to construct a `ParseBuffer`. Instead, if you are +/// looking to invoke a parser function that requires `ParseStream` as input, +/// you will need to go through one of the public parsing entry points. +/// +/// - The [`parse_macro_input!`] macro if parsing input of a procedural macro; +/// - One of [the `syn::parse*` functions][syn-parse]; or +/// - A method of the [`Parser`] trait. +/// +/// [`parse_macro_input!`]: ../macro.parse_macro_input.html +/// [syn-parse]: index.html#the-synparse-functions +pub struct ParseBuffer<'a> { + scope: Span, + // Instead of Cell<Cursor<'a>> so that ParseBuffer<'a> is covariant in 'a. + // The rest of the code in this module needs to be careful that only a + // cursor derived from this `cell` is ever assigned to this `cell`. + // + // Cell<Cursor<'a>> cannot be covariant in 'a because then we could take a + // ParseBuffer<'a>, upcast to ParseBuffer<'short> for some lifetime shorter + // than 'a, and then assign a Cursor<'short> into the Cell. + // + // By extension, it would not be safe to expose an API that accepts a + // Cursor<'a> and trusts that it lives as long as the cursor currently in + // the cell. + cell: Cell<Cursor<'static>>, + marker: PhantomData<Cursor<'a>>, + unexpected: Rc<Cell<Option<Span>>>, +} + +impl<'a> Drop for ParseBuffer<'a> { + fn drop(&mut self) { + if !self.is_empty() && self.unexpected.get().is_none() { + self.unexpected.set(Some(self.cursor().span())); + } + } +} + +impl<'a> Display for ParseBuffer<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.cursor().token_stream(), f) + } +} + +impl<'a> Debug for ParseBuffer<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.cursor().token_stream(), f) + } +} + +/// Cursor state associated with speculative parsing. +/// +/// This type is the input of the closure provided to [`ParseStream::step`]. +/// +/// [`ParseStream::step`]: struct.ParseBuffer.html#method.step +/// +/// # Example +/// +/// ```edition2018 +/// use proc_macro2::TokenTree; +/// use syn::Result; +/// use syn::parse::ParseStream; +/// +/// // This function advances the stream past the next occurrence of `@`. If +/// // no `@` is present in the stream, the stream position is unchanged and +/// // an error is returned. +/// fn skip_past_next_at(input: ParseStream) -> Result<()> { +/// input.step(|cursor| { +/// let mut rest = *cursor; +/// while let Some((tt, next)) = rest.token_tree() { +/// match &tt { +/// TokenTree::Punct(punct) if punct.as_char() == '@' => { +/// return Ok(((), next)); +/// } +/// _ => rest = next, +/// } +/// } +/// Err(cursor.error("no `@` was found after this point")) +/// }) +/// } +/// # +/// # fn remainder_after_skipping_past_next_at( +/// # input: ParseStream, +/// # ) -> Result<proc_macro2::TokenStream> { +/// # skip_past_next_at(input)?; +/// # input.parse() +/// # } +/// # +/// # fn main() { +/// # use syn::parse::Parser; +/// # let remainder = remainder_after_skipping_past_next_at +/// # .parse_str("a @ b c") +/// # .unwrap(); +/// # assert_eq!(remainder.to_string(), "b c"); +/// # } +/// ``` +#[derive(Copy, Clone)] +pub struct StepCursor<'c, 'a> { + scope: Span, + // This field is covariant in 'c. + cursor: Cursor<'c>, + // This field is contravariant in 'c. Together these make StepCursor + // invariant in 'c. Also covariant in 'a. The user cannot cast 'c to a + // different lifetime but can upcast into a StepCursor with a shorter + // lifetime 'a. + // + // As long as we only ever construct a StepCursor for which 'c outlives 'a, + // this means if ever a StepCursor<'c, 'a> exists we are guaranteed that 'c + // outlives 'a. + marker: PhantomData<fn(Cursor<'c>) -> Cursor<'a>>, +} + +impl<'c, 'a> Deref for StepCursor<'c, 'a> { + type Target = Cursor<'c>; + + fn deref(&self) -> &Self::Target { + &self.cursor + } +} + +impl<'c, 'a> StepCursor<'c, 'a> { + /// Triggers an error at the current position of the parse stream. + /// + /// The `ParseStream::step` invocation will return this same error without + /// advancing the stream state. + pub fn error<T: Display>(self, message: T) -> Error { + error::new_at(self.scope, self.cursor, message) + } +} + +impl private { + pub fn advance_step_cursor<'c, 'a>(proof: StepCursor<'c, 'a>, to: Cursor<'c>) -> Cursor<'a> { + // Refer to the comments within the StepCursor definition. We use the + // fact that a StepCursor<'c, 'a> exists as proof that 'c outlives 'a. + // Cursor is covariant in its lifetime parameter so we can cast a + // Cursor<'c> to one with the shorter lifetime Cursor<'a>. + let _ = proof; + unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(to) } + } +} + +fn skip(input: ParseStream) -> bool { + input + .step(|cursor| { + if let Some((_lifetime, rest)) = cursor.lifetime() { + Ok((true, rest)) + } else if let Some((_token, rest)) = cursor.token_tree() { + Ok((true, rest)) + } else { + Ok((false, *cursor)) + } + }) + .unwrap() +} + +impl private { + pub fn new_parse_buffer( + scope: Span, + cursor: Cursor, + unexpected: Rc<Cell<Option<Span>>>, + ) -> ParseBuffer { + ParseBuffer { + scope: scope, + // See comment on `cell` in the struct definition. + cell: Cell::new(unsafe { mem::transmute::<Cursor, Cursor<'static>>(cursor) }), + marker: PhantomData, + unexpected: unexpected, + } + } + + pub fn get_unexpected(buffer: &ParseBuffer) -> Rc<Cell<Option<Span>>> { + buffer.unexpected.clone() + } +} + +impl<'a> ParseBuffer<'a> { + /// Parses a syntax tree node of type `T`, advancing the position of our + /// parse stream past it. + pub fn parse<T: Parse>(&self) -> Result<T> { + T::parse(self) + } + + /// Calls the given parser function to parse a syntax tree node of type `T` + /// from this stream. + /// + /// # Example + /// + /// The parser below invokes [`Attribute::parse_outer`] to parse a vector of + /// zero or more outer attributes. + /// + /// [`Attribute::parse_outer`]: ../struct.Attribute.html#method.parse_outer + /// + /// ```edition2018 + /// use syn::{Attribute, Ident, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a unit struct with attributes. + /// // + /// // #[path = "s.tmpl"] + /// // struct S; + /// struct UnitStruct { + /// attrs: Vec<Attribute>, + /// struct_token: Token![struct], + /// name: Ident, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for UnitStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(UnitStruct { + /// attrs: input.call(Attribute::parse_outer)?, + /// struct_token: input.parse()?, + /// name: input.parse()?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// ``` + pub fn call<T>(&self, function: fn(ParseStream) -> Result<T>) -> Result<T> { + function(self) + } + + /// Looks at the next token in the parse stream to determine whether it + /// matches the requested type of token. + /// + /// Does not advance the position of the parse stream. + /// + /// # Syntax + /// + /// Note that this method does not use turbofish syntax. Pass the peek type + /// inside of parentheses. + /// + /// - `input.peek(Token![struct])` + /// - `input.peek(Token![==])` + /// - `input.peek(Ident)` *(does not accept keywords)* + /// - `input.peek(Ident::peek_any)` + /// - `input.peek(Lifetime)` + /// - `input.peek(token::Brace)` + /// + /// # Example + /// + /// In this example we finish parsing the list of supertraits when the next + /// token in the input is either `where` or an opening curly brace. + /// + /// ```edition2018 + /// use syn::{braced, token, Generics, Ident, Result, Token, TypeParamBound}; + /// use syn::parse::{Parse, ParseStream}; + /// use syn::punctuated::Punctuated; + /// + /// // Parses a trait definition containing no associated items. + /// // + /// // trait Marker<'de, T>: A + B<'de> where Box<T>: Clone {} + /// struct MarkerTrait { + /// trait_token: Token![trait], + /// ident: Ident, + /// generics: Generics, + /// colon_token: Option<Token![:]>, + /// supertraits: Punctuated<TypeParamBound, Token![+]>, + /// brace_token: token::Brace, + /// } + /// + /// impl Parse for MarkerTrait { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let trait_token: Token![trait] = input.parse()?; + /// let ident: Ident = input.parse()?; + /// let mut generics: Generics = input.parse()?; + /// let colon_token: Option<Token![:]> = input.parse()?; + /// + /// let mut supertraits = Punctuated::new(); + /// if colon_token.is_some() { + /// loop { + /// supertraits.push_value(input.parse()?); + /// if input.peek(Token![where]) || input.peek(token::Brace) { + /// break; + /// } + /// supertraits.push_punct(input.parse()?); + /// } + /// } + /// + /// generics.where_clause = input.parse()?; + /// let content; + /// let empty_brace_token = braced!(content in input); + /// + /// Ok(MarkerTrait { + /// trait_token: trait_token, + /// ident: ident, + /// generics: generics, + /// colon_token: colon_token, + /// supertraits: supertraits, + /// brace_token: empty_brace_token, + /// }) + /// } + /// } + /// ``` + pub fn peek<T: Peek>(&self, token: T) -> bool { + let _ = token; + T::Token::peek(self.cursor()) + } + + /// Looks at the second-next token in the parse stream. + /// + /// This is commonly useful as a way to implement contextual keywords. + /// + /// # Example + /// + /// This example needs to use `peek2` because the symbol `union` is not a + /// keyword in Rust. We can't use just `peek` and decide to parse a union if + /// the very next token is `union`, because someone is free to write a `mod + /// union` and a macro invocation that looks like `union::some_macro! { ... + /// }`. In other words `union` is a contextual keyword. + /// + /// ```edition2018 + /// use syn::{Ident, ItemUnion, Macro, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses either a union or a macro invocation. + /// enum UnionOrMacro { + /// // union MaybeUninit<T> { uninit: (), value: T } + /// Union(ItemUnion), + /// // lazy_static! { ... } + /// Macro(Macro), + /// } + /// + /// impl Parse for UnionOrMacro { + /// fn parse(input: ParseStream) -> Result<Self> { + /// if input.peek(Token![union]) && input.peek2(Ident) { + /// input.parse().map(UnionOrMacro::Union) + /// } else { + /// input.parse().map(UnionOrMacro::Macro) + /// } + /// } + /// } + /// ``` + pub fn peek2<T: Peek>(&self, token: T) -> bool { + let ahead = self.fork(); + skip(&ahead) && ahead.peek(token) + } + + /// Looks at the third-next token in the parse stream. + pub fn peek3<T: Peek>(&self, token: T) -> bool { + let ahead = self.fork(); + skip(&ahead) && skip(&ahead) && ahead.peek(token) + } + + /// Parses zero or more occurrences of `T` separated by punctuation of type + /// `P`, with optional trailing punctuation. + /// + /// Parsing continues until the end of this parse stream. The entire content + /// of this parse stream must consist of `T` and `P`. + /// + /// # Example + /// + /// ```edition2018 + /// # use quote::quote; + /// # + /// use syn::{parenthesized, token, Ident, Result, Token, Type}; + /// use syn::parse::{Parse, ParseStream}; + /// use syn::punctuated::Punctuated; + /// + /// // Parse a simplified tuple struct syntax like: + /// // + /// // struct S(A, B); + /// struct TupleStruct { + /// struct_token: Token![struct], + /// ident: Ident, + /// paren_token: token::Paren, + /// fields: Punctuated<Type, Token![,]>, + /// semi_token: Token![;], + /// } + /// + /// impl Parse for TupleStruct { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let content; + /// Ok(TupleStruct { + /// struct_token: input.parse()?, + /// ident: input.parse()?, + /// paren_token: parenthesized!(content in input), + /// fields: content.parse_terminated(Type::parse)?, + /// semi_token: input.parse()?, + /// }) + /// } + /// } + /// # + /// # fn main() { + /// # let input = quote! { + /// # struct S(A, B); + /// # }; + /// # syn::parse2::<TupleStruct>(input).unwrap(); + /// # } + /// ``` + pub fn parse_terminated<T, P: Parse>( + &self, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Punctuated<T, P>> { + Punctuated::parse_terminated_with(self, parser) + } + + /// Returns whether there are tokens remaining in this stream. + /// + /// This method returns true at the end of the content of a set of + /// delimiters, as well as at the very end of the complete macro input. + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{braced, token, Ident, Item, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Parses a Rust `mod m { ... }` containing zero or more items. + /// struct Mod { + /// mod_token: Token![mod], + /// name: Ident, + /// brace_token: token::Brace, + /// items: Vec<Item>, + /// } + /// + /// impl Parse for Mod { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let content; + /// Ok(Mod { + /// mod_token: input.parse()?, + /// name: input.parse()?, + /// brace_token: braced!(content in input), + /// items: { + /// let mut items = Vec::new(); + /// while !content.is_empty() { + /// items.push(content.parse()?); + /// } + /// items + /// }, + /// }) + /// } + /// } + /// ``` + pub fn is_empty(&self) -> bool { + self.cursor().eof() + } + + /// Constructs a helper for peeking at the next token in this stream and + /// building an error message if it is not one of a set of expected tokens. + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{ConstParam, Ident, Lifetime, LifetimeDef, Result, Token, TypeParam}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // A generic parameter, a single one of the comma-separated elements inside + /// // angle brackets in: + /// // + /// // fn f<T: Clone, 'a, 'b: 'a, const N: usize>() { ... } + /// // + /// // On invalid input, lookahead gives us a reasonable error message. + /// // + /// // error: expected one of: identifier, lifetime, `const` + /// // | + /// // 5 | fn f<!Sized>() {} + /// // | ^ + /// enum GenericParam { + /// Type(TypeParam), + /// Lifetime(LifetimeDef), + /// Const(ConstParam), + /// } + /// + /// impl Parse for GenericParam { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let lookahead = input.lookahead1(); + /// if lookahead.peek(Ident) { + /// input.parse().map(GenericParam::Type) + /// } else if lookahead.peek(Lifetime) { + /// input.parse().map(GenericParam::Lifetime) + /// } else if lookahead.peek(Token![const]) { + /// input.parse().map(GenericParam::Const) + /// } else { + /// Err(lookahead.error()) + /// } + /// } + /// } + /// ``` + pub fn lookahead1(&self) -> Lookahead1<'a> { + lookahead::new(self.scope, self.cursor()) + } + + /// Forks a parse stream so that parsing tokens out of either the original + /// or the fork does not advance the position of the other. + /// + /// # Performance + /// + /// Forking a parse stream is a cheap fixed amount of work and does not + /// involve copying token buffers. Where you might hit performance problems + /// is if your macro ends up parsing a large amount of content more than + /// once. + /// + /// ```edition2018 + /// # use syn::{Expr, Result}; + /// # use syn::parse::ParseStream; + /// # + /// # fn bad(input: ParseStream) -> Result<Expr> { + /// // Do not do this. + /// if input.fork().parse::<Expr>().is_ok() { + /// return input.parse::<Expr>(); + /// } + /// # unimplemented!() + /// # } + /// ``` + /// + /// As a rule, avoid parsing an unbounded amount of tokens out of a forked + /// parse stream. Only use a fork when the amount of work performed against + /// the fork is small and bounded. + /// + /// For a lower level but occasionally more performant way to perform + /// speculative parsing, consider using [`ParseStream::step`] instead. + /// + /// [`ParseStream::step`]: #method.step + /// + /// # Example + /// + /// The parse implementation shown here parses possibly restricted `pub` + /// visibilities. + /// + /// - `pub` + /// - `pub(crate)` + /// - `pub(self)` + /// - `pub(super)` + /// - `pub(in some::path)` + /// + /// To handle the case of visibilities inside of tuple structs, the parser + /// needs to distinguish parentheses that specify visibility restrictions + /// from parentheses that form part of a tuple type. + /// + /// ```edition2018 + /// # struct A; + /// # struct B; + /// # struct C; + /// # + /// struct S(pub(crate) A, pub (B, C)); + /// ``` + /// + /// In this example input the first tuple struct element of `S` has + /// `pub(crate)` visibility while the second tuple struct element has `pub` + /// visibility; the parentheses around `(B, C)` are part of the type rather + /// than part of a visibility restriction. + /// + /// The parser uses a forked parse stream to check the first token inside of + /// parentheses after the `pub` keyword. This is a small bounded amount of + /// work performed against the forked parse stream. + /// + /// ```edition2018 + /// use syn::{parenthesized, token, Ident, Path, Result, Token}; + /// use syn::ext::IdentExt; + /// use syn::parse::{Parse, ParseStream}; + /// + /// struct PubVisibility { + /// pub_token: Token![pub], + /// restricted: Option<Restricted>, + /// } + /// + /// struct Restricted { + /// paren_token: token::Paren, + /// in_token: Option<Token![in]>, + /// path: Path, + /// } + /// + /// impl Parse for PubVisibility { + /// fn parse(input: ParseStream) -> Result<Self> { + /// let pub_token: Token![pub] = input.parse()?; + /// + /// if input.peek(token::Paren) { + /// let ahead = input.fork(); + /// let mut content; + /// parenthesized!(content in ahead); + /// + /// if content.peek(Token![crate]) + /// || content.peek(Token![self]) + /// || content.peek(Token![super]) + /// { + /// return Ok(PubVisibility { + /// pub_token: pub_token, + /// restricted: Some(Restricted { + /// paren_token: parenthesized!(content in input), + /// in_token: None, + /// path: Path::from(content.call(Ident::parse_any)?), + /// }), + /// }); + /// } else if content.peek(Token![in]) { + /// return Ok(PubVisibility { + /// pub_token: pub_token, + /// restricted: Some(Restricted { + /// paren_token: parenthesized!(content in input), + /// in_token: Some(content.parse()?), + /// path: content.call(Path::parse_mod_style)?, + /// }), + /// }); + /// } + /// } + /// + /// Ok(PubVisibility { + /// pub_token: pub_token, + /// restricted: None, + /// }) + /// } + /// } + /// ``` + pub fn fork(&self) -> Self { + ParseBuffer { + scope: self.scope, + cell: self.cell.clone(), + marker: PhantomData, + // Not the parent's unexpected. Nothing cares whether the clone + // parses all the way. + unexpected: Rc::new(Cell::new(None)), + } + } + + /// Triggers an error at the current position of the parse stream. + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{Expr, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // Some kind of loop: `while` or `for` or `loop`. + /// struct Loop { + /// expr: Expr, + /// } + /// + /// impl Parse for Loop { + /// fn parse(input: ParseStream) -> Result<Self> { + /// if input.peek(Token![while]) + /// || input.peek(Token![for]) + /// || input.peek(Token![loop]) + /// { + /// Ok(Loop { + /// expr: input.parse()?, + /// }) + /// } else { + /// Err(input.error("expected some kind of loop")) + /// } + /// } + /// } + /// ``` + pub fn error<T: Display>(&self, message: T) -> Error { + error::new_at(self.scope, self.cursor(), message) + } + + /// Speculatively parses tokens from this parse stream, advancing the + /// position of this stream only if parsing succeeds. + /// + /// This is a powerful low-level API used for defining the `Parse` impls of + /// the basic built-in token types. It is not something that will be used + /// widely outside of the Syn codebase. + /// + /// # Example + /// + /// ```edition2018 + /// use proc_macro2::TokenTree; + /// use syn::Result; + /// use syn::parse::ParseStream; + /// + /// // This function advances the stream past the next occurrence of `@`. If + /// // no `@` is present in the stream, the stream position is unchanged and + /// // an error is returned. + /// fn skip_past_next_at(input: ParseStream) -> Result<()> { + /// input.step(|cursor| { + /// let mut rest = *cursor; + /// while let Some((tt, next)) = rest.token_tree() { + /// match &tt { + /// TokenTree::Punct(punct) if punct.as_char() == '@' => { + /// return Ok(((), next)); + /// } + /// _ => rest = next, + /// } + /// } + /// Err(cursor.error("no `@` was found after this point")) + /// }) + /// } + /// # + /// # fn remainder_after_skipping_past_next_at( + /// # input: ParseStream, + /// # ) -> Result<proc_macro2::TokenStream> { + /// # skip_past_next_at(input)?; + /// # input.parse() + /// # } + /// # + /// # fn main() { + /// # use syn::parse::Parser; + /// # let remainder = remainder_after_skipping_past_next_at + /// # .parse_str("a @ b c") + /// # .unwrap(); + /// # assert_eq!(remainder.to_string(), "b c"); + /// # } + /// ``` + pub fn step<F, R>(&self, function: F) -> Result<R> + where + F: for<'c> FnOnce(StepCursor<'c, 'a>) -> Result<(R, Cursor<'c>)>, + { + // Since the user's function is required to work for any 'c, we know + // that the Cursor<'c> they return is either derived from the input + // StepCursor<'c, 'a> or from a Cursor<'static>. + // + // It would not be legal to write this function without the invariant + // lifetime 'c in StepCursor<'c, 'a>. If this function were written only + // in terms of 'a, the user could take our ParseBuffer<'a>, upcast it to + // a ParseBuffer<'short> which some shorter lifetime than 'a, invoke + // `step` on their ParseBuffer<'short> with a closure that returns + // Cursor<'short>, and we would wrongly write that Cursor<'short> into + // the Cell intended to hold Cursor<'a>. + // + // In some cases it may be necessary for R to contain a Cursor<'a>. + // Within Syn we solve this using `private::advance_step_cursor` which + // uses the existence of a StepCursor<'c, 'a> as proof that it is safe + // to cast from Cursor<'c> to Cursor<'a>. If needed outside of Syn, it + // would be safe to expose that API as a method on StepCursor. + let (node, rest) = function(StepCursor { + scope: self.scope, + cursor: self.cell.get(), + marker: PhantomData, + })?; + self.cell.set(rest); + Ok(node) + } + + /// Provides low-level access to the token representation underlying this + /// parse stream. + /// + /// Cursors are immutable so no operations you perform against the cursor + /// will affect the state of this parse stream. + pub fn cursor(&self) -> Cursor<'a> { + self.cell.get() + } + + fn check_unexpected(&self) -> Result<()> { + match self.unexpected.get() { + Some(span) => Err(Error::new(span, "unexpected token")), + None => Ok(()), + } + } +} + +impl<T: Parse> Parse for Box<T> { + fn parse(input: ParseStream) -> Result<Self> { + input.parse().map(Box::new) + } +} + +impl<T: Parse + Token> Parse for Option<T> { + fn parse(input: ParseStream) -> Result<Self> { + if T::peek(input.cursor()) { + Ok(Some(input.parse()?)) + } else { + Ok(None) + } + } +} + +impl Parse for TokenStream { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| Ok((cursor.token_stream(), Cursor::empty()))) + } +} + +impl Parse for TokenTree { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.token_tree() { + Some((tt, rest)) => Ok((tt, rest)), + None => Err(cursor.error("expected token tree")), + }) + } +} + +impl Parse for Group { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + for delim in &[Delimiter::Parenthesis, Delimiter::Brace, Delimiter::Bracket] { + if let Some((inside, span, rest)) = cursor.group(*delim) { + let mut group = Group::new(*delim, inside.token_stream()); + group.set_span(span); + return Ok((group, rest)); + } + } + Err(cursor.error("expected group token")) + }) + } +} + +impl Parse for Punct { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.punct() { + Some((punct, rest)) => Ok((punct, rest)), + None => Err(cursor.error("expected punctuation token")), + }) + } +} + +impl Parse for Literal { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| match cursor.literal() { + Some((literal, rest)) => Ok((literal, rest)), + None => Err(cursor.error("expected literal token")), + }) + } +} + +/// Parser that can parse Rust tokens into a particular syntax tree node. +/// +/// Refer to the [module documentation] for details about parsing in Syn. +/// +/// [module documentation]: index.html +/// +/// *This trait is available if Syn is built with the `"parsing"` feature.* +pub trait Parser: Sized { + type Output; + + /// Parse a proc-macro2 token stream into the chosen syntax tree node. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the stream, an error is returned. + fn parse2(self, tokens: TokenStream) -> Result<Self::Output>; + + /// Parse tokens of source code into the chosen syntax tree node. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the stream, an error is returned. + /// + /// *This method is available if Syn is built with both the `"parsing"` and + /// `"proc-macro"` features.* + #[cfg(all( + not(all(target_arch = "wasm32", target_os = "unknown")), + feature = "proc-macro" + ))] + fn parse(self, tokens: proc_macro::TokenStream) -> Result<Self::Output> { + self.parse2(proc_macro2::TokenStream::from(tokens)) + } + + /// Parse a string of Rust code into the chosen syntax tree node. + /// + /// This function will check that the input is fully parsed. If there are + /// any unparsed tokens at the end of the string, an error is returned. + /// + /// # Hygiene + /// + /// Every span in the resulting syntax tree will be set to resolve at the + /// macro call site. + fn parse_str(self, s: &str) -> Result<Self::Output> { + self.parse2(proc_macro2::TokenStream::from_str(s)?) + } +} + +fn tokens_to_parse_buffer(tokens: &TokenBuffer) -> ParseBuffer { + let scope = Span::call_site(); + let cursor = tokens.begin(); + let unexpected = Rc::new(Cell::new(None)); + private::new_parse_buffer(scope, cursor, unexpected) +} + +impl<F, T> Parser for F +where + F: FnOnce(ParseStream) -> Result<T>, +{ + type Output = T; + + fn parse2(self, tokens: TokenStream) -> Result<T> { + let buf = TokenBuffer::new2(tokens); + let state = tokens_to_parse_buffer(&buf); + let node = self(&state)?; + state.check_unexpected()?; + if state.is_empty() { + Ok(node) + } else { + Err(state.error("unexpected token")) + } + } +} diff --git a/syn/src/parse_macro_input.rs b/syn/src/parse_macro_input.rs new file mode 100644 index 000000000..9d8f6aea2 --- /dev/null +++ b/syn/src/parse_macro_input.rs @@ -0,0 +1,103 @@ +/// Parse the input TokenStream of a macro, triggering a compile error if the +/// tokens fail to parse. +/// +/// Refer to the [`parse` module] documentation for more details about parsing +/// in Syn. +/// +/// [`parse` module]: parse/index.html +/// +/// # Intended usage +/// +/// ```edition2018 +/// extern crate proc_macro; +/// +/// use proc_macro::TokenStream; +/// use syn::{parse_macro_input, Result}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// struct MyMacroInput { +/// /* ... */ +/// } +/// +/// impl Parse for MyMacroInput { +/// fn parse(input: ParseStream) -> Result<Self> { +/// /* ... */ +/// # Ok(MyMacroInput {}) +/// } +/// } +/// +/// # const IGNORE: &str = stringify! { +/// #[proc_macro] +/// # }; +/// pub fn my_macro(tokens: TokenStream) -> TokenStream { +/// let input = parse_macro_input!(tokens as MyMacroInput); +/// +/// /* ... */ +/// # "".parse().unwrap() +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! parse_macro_input { + ($tokenstream:ident as $ty:ty) => { + match $crate::parse_macro_input::parse::<$ty>($tokenstream) { + $crate::export::Ok(data) => data, + $crate::export::Err(err) => { + return $crate::export::TokenStream::from(err.to_compile_error()); + } + } + }; + ($tokenstream:ident) => { + parse_macro_input!($tokenstream as _) + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Can parse any type that implements Parse. + +use parse::{Parse, ParseStream, Parser, Result}; +use proc_macro::TokenStream; + +// Not public API. +#[doc(hidden)] +pub fn parse<T: ParseMacroInput>(token_stream: TokenStream) -> Result<T> { + T::parse.parse(token_stream) +} + +// Not public API. +#[doc(hidden)] +pub trait ParseMacroInput: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +impl<T: Parse> ParseMacroInput for T { + fn parse(input: ParseStream) -> Result<Self> { + <T as Parse>::parse(input) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Any other types that we want `parse_macro_input!` to be able to parse. + +#[cfg(any(feature = "full", feature = "derive"))] +use AttributeArgs; + +#[cfg(any(feature = "full", feature = "derive"))] +impl ParseMacroInput for AttributeArgs { + fn parse(input: ParseStream) -> Result<Self> { + let mut metas = Vec::new(); + + loop { + if input.is_empty() { + break; + } + let value = input.parse()?; + metas.push(value); + if input.is_empty() { + break; + } + input.parse::<Token![,]>()?; + } + + Ok(metas) + } +} diff --git a/syn/src/parse_quote.rs b/syn/src/parse_quote.rs new file mode 100644 index 000000000..08012f5e8 --- /dev/null +++ b/syn/src/parse_quote.rs @@ -0,0 +1,144 @@ +/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses +/// type inference to figure out a return type for those tokens. +/// +/// [`quote!`]: https://docs.rs/quote/0.6/quote/index.html +/// +/// The return type can be any syntax tree node that implements the [`Parse`] +/// trait. +/// +/// [`Parse`]: parse/trait.Parse.html +/// +/// ```edition2018 +/// use quote::quote; +/// use syn::{parse_quote, Stmt}; +/// +/// fn main() { +/// let name = quote!(v); +/// let ty = quote!(u8); +/// +/// let stmt: Stmt = parse_quote! { +/// let #name: #ty = Default::default(); +/// }; +/// +/// println!("{:#?}", stmt); +/// } +/// ``` +/// +/// *This macro is available if Syn is built with the `"parsing"` feature, +/// although interpolation of syntax tree nodes into the quoted tokens is only +/// supported if Syn is built with the `"printing"` feature as well.* +/// +/// # Example +/// +/// The following helper function adds a bound `T: HeapSize` to every type +/// parameter `T` in the input generics. +/// +/// ```edition2018 +/// use syn::{parse_quote, Generics, GenericParam}; +/// +/// // Add a bound `T: HeapSize` to every type parameter T. +/// fn add_trait_bounds(mut generics: Generics) -> Generics { +/// for param in &mut generics.params { +/// if let GenericParam::Type(type_param) = param { +/// type_param.bounds.push(parse_quote!(HeapSize)); +/// } +/// } +/// generics +/// } +/// ``` +/// +/// # Special cases +/// +/// This macro can parse the following additional types as a special case even +/// though they do not implement the `Parse` trait. +/// +/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]` +/// or inner like `#![...]` +/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation +/// `P` with optional trailing punctuation +/// +/// [`Attribute`]: struct.Attribute.html +/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html +/// +/// # Panics +/// +/// Panics if the tokens fail to parse as the expected syntax tree type. The +/// caller is responsible for ensuring that the input tokens are syntactically +/// valid. +#[macro_export(local_inner_macros)] +macro_rules! parse_quote { + ($($tt:tt)*) => { + $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*))) + }; +} + +#[cfg(not(syn_can_call_macro_by_path))] +#[doc(hidden)] +#[macro_export] +macro_rules! quote_impl { + ($($tt:tt)*) => { + // Require caller to have their own `#[macro_use] extern crate quote`. + quote!($($tt)*) + }; +} + +#[cfg(syn_can_call_macro_by_path)] +#[doc(hidden)] +#[macro_export] +macro_rules! quote_impl { + ($($tt:tt)*) => { + $crate::export::quote::quote!($($tt)*) + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// Can parse any type that implements Parse. + +use parse::{Parse, ParseStream, Parser, Result}; +use proc_macro2::TokenStream; + +// Not public API. +#[doc(hidden)] +pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { + let parser = T::parse; + match parser.parse2(token_stream) { + Ok(t) => t, + Err(err) => panic!("{}", err), + } +} + +// Not public API. +#[doc(hidden)] +pub trait ParseQuote: Sized { + fn parse(input: ParseStream) -> Result<Self>; +} + +impl<T: Parse> ParseQuote for T { + fn parse(input: ParseStream) -> Result<Self> { + <T as Parse>::parse(input) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Any other types that we want `parse_quote!` to be able to parse. + +use punctuated::Punctuated; +#[cfg(any(feature = "full", feature = "derive"))] +use {attr, Attribute}; + +#[cfg(any(feature = "full", feature = "derive"))] +impl ParseQuote for Attribute { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![#]) && input.peek2(Token![!]) { + attr::parsing::single_parse_inner(input) + } else { + attr::parsing::single_parse_outer(input) + } + } +} + +impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_terminated(input) + } +} diff --git a/syn/src/path.rs b/syn/src/path.rs new file mode 100644 index 000000000..afdecc2ee --- /dev/null +++ b/syn/src/path.rs @@ -0,0 +1,704 @@ +use super::*; +use punctuated::Punctuated; + +ast_struct! { + /// A path at which a named item is exported: `std::collections::HashMap`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Path { + pub leading_colon: Option<Token![::]>, + pub segments: Punctuated<PathSegment, Token![::]>, + } +} + +impl<T> From<T> for Path +where + T: Into<PathSegment>, +{ + fn from(segment: T) -> Self { + let mut path = Path { + leading_colon: None, + segments: Punctuated::new(), + }; + path.segments.push_value(segment.into()); + path + } +} + +ast_struct! { + /// A segment of a path together with any path arguments on that segment. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct PathSegment { + pub ident: Ident, + pub arguments: PathArguments, + } +} + +impl<T> From<T> for PathSegment +where + T: Into<Ident>, +{ + fn from(ident: T) -> Self { + PathSegment { + ident: ident.into(), + arguments: PathArguments::None, + } + } +} + +ast_enum! { + /// Angle bracketed or parenthesized arguments of a path segment. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// ## Angle bracketed + /// + /// The `<'a, T>` in `std::slice::iter<'a, T>`. + /// + /// ## Parenthesized + /// + /// The `(A, B) -> C` in `Fn(A, B) -> C`. + pub enum PathArguments { + None, + /// The `<'a, T>` in `std::slice::iter<'a, T>`. + AngleBracketed(AngleBracketedGenericArguments), + /// The `(A, B) -> C` in `Fn(A, B) -> C`. + Parenthesized(ParenthesizedGenericArguments), + } +} + +impl Default for PathArguments { + fn default() -> Self { + PathArguments::None + } +} + +impl PathArguments { + pub fn is_empty(&self) -> bool { + match *self { + PathArguments::None => true, + PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(), + PathArguments::Parenthesized(_) => false, + } + } + + #[cfg(feature = "parsing")] + fn is_none(&self) -> bool { + match *self { + PathArguments::None => true, + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, + } + } +} + +ast_enum! { + /// An individual generic argument, like `'a`, `T`, or `Item = T`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum GenericArgument { + /// A lifetime argument. + Lifetime(Lifetime), + /// A type argument. + Type(Type), + /// A binding (equality constraint) on an associated type: the `Item = + /// u8` in `Iterator<Item = u8>`. + Binding(Binding), + /// An associated type bound: `Iterator<Item: Display>`. + Constraint(Constraint), + /// A const expression. Must be inside of a block. + /// + /// NOTE: Identity expressions are represented as Type arguments, as + /// they are indistinguishable syntactically. + Const(Expr), + } +} + +ast_struct! { + /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, + /// V>`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct AngleBracketedGenericArguments { + pub colon2_token: Option<Token![::]>, + pub lt_token: Token![<], + pub args: Punctuated<GenericArgument, Token![,]>, + pub gt_token: Token![>], + } +} + +ast_struct! { + /// A binding (equality constraint) on an associated type: `Item = u8`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Binding { + pub ident: Ident, + pub eq_token: Token![=], + pub ty: Type, + } +} + +ast_struct! { + /// An associated type bound: `Iterator<Item: Display>`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Constraint { + pub ident: Ident, + pub colon_token: Token![:], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + } +} + +ast_struct! { + /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> + /// C`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct ParenthesizedGenericArguments { + pub paren_token: token::Paren, + /// `(A, B)` + pub inputs: Punctuated<Type, Token![,]>, + /// `C` + pub output: ReturnType, + } +} + +ast_struct! { + /// The explicit Self type in a qualified path: the `T` in `<T as + /// Display>::fmt`. + /// + /// The actual path, including the trait and the associated item, is stored + /// separately. The `position` field represents the index of the associated + /// item qualified with this Self type. + /// + /// ```text + /// <Vec<T> as a::b::Trait>::AssociatedItem + /// ^~~~~~ ~~~~~~~~~~~~~~^ + /// ty position = 3 + /// + /// <Vec<T>>::AssociatedItem + /// ^~~~~~ ^ + /// ty position = 0 + /// ``` + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct QSelf { + pub lt_token: Token![<], + pub ty: Box<Type>, + pub position: usize, + pub as_token: Option<Token![as]>, + pub gt_token: Token![>], + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + #[cfg(feature = "full")] + use expr; + use ext::IdentExt; + use parse::{Parse, ParseStream, Result}; + + impl Parse for Path { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_helper(input, false) + } + } + + impl Parse for GenericArgument { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Lifetime) && !input.peek2(Token![+]) { + return Ok(GenericArgument::Lifetime(input.parse()?)); + } + + if input.peek(Ident) && input.peek2(Token![=]) { + return Ok(GenericArgument::Binding(input.parse()?)); + } + + #[cfg(feature = "full")] + { + if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) { + return Ok(GenericArgument::Constraint(input.parse()?)); + } + + if input.peek(Lit) { + let lit = input.parse()?; + return Ok(GenericArgument::Const(Expr::Lit(lit))); + } + + if input.peek(token::Brace) { + let block = input.call(expr::parsing::expr_block)?; + return Ok(GenericArgument::Const(Expr::Block(block))); + } + } + + input.parse().map(GenericArgument::Type) + } + } + + impl Parse for AngleBracketedGenericArguments { + fn parse(input: ParseStream) -> Result<Self> { + Ok(AngleBracketedGenericArguments { + colon2_token: input.parse()?, + lt_token: input.parse()?, + args: { + let mut args = Punctuated::new(); + loop { + if input.peek(Token![>]) { + break; + } + let value = input.parse()?; + args.push_value(value); + if input.peek(Token![>]) { + break; + } + let punct = input.parse()?; + args.push_punct(punct); + } + args + }, + gt_token: input.parse()?, + }) + } + } + + impl Parse for ParenthesizedGenericArguments { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(ParenthesizedGenericArguments { + paren_token: parenthesized!(content in input), + inputs: content.parse_terminated(Type::parse)?, + output: input.call(ReturnType::without_plus)?, + }) + } + } + + impl Parse for PathSegment { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse_helper(input, false) + } + } + + impl PathSegment { + fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { + if input.peek(Token![super]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![crate]) + || input.peek(Token![extern]) + { + let ident = input.call(Ident::parse_any)?; + return Ok(PathSegment::from(ident)); + } + + let ident = input.parse()?; + if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) + || input.peek(Token![::]) && input.peek3(Token![<]) + { + Ok(PathSegment { + ident: ident, + arguments: PathArguments::AngleBracketed(input.parse()?), + }) + } else { + Ok(PathSegment::from(ident)) + } + } + } + + impl Parse for Binding { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Binding { + ident: input.parse()?, + eq_token: input.parse()?, + ty: input.parse()?, + }) + } + } + + #[cfg(feature = "full")] + impl Parse for Constraint { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Constraint { + ident: input.parse()?, + colon_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + loop { + if input.peek(Token![,]) || input.peek(Token![>]) { + break; + } + let value = input.parse()?; + bounds.push_value(value); + if !input.peek(Token![+]) { + break; + } + let punct = input.parse()?; + bounds.push_punct(punct); + } + bounds + }, + }) + } + } + + impl Path { + /// Parse a `Path` containing no path arguments on any of its segments. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + /// + /// # Example + /// + /// ```edition2018 + /// use syn::{Path, Result, Token}; + /// use syn::parse::{Parse, ParseStream}; + /// + /// // A simplified single `use` statement like: + /// // + /// // use std::collections::HashMap; + /// // + /// // Note that generic parameters are not allowed in a `use` statement + /// // so the following must not be accepted. + /// // + /// // use a::<b>::c; + /// struct SingleUse { + /// use_token: Token![use], + /// path: Path, + /// } + /// + /// impl Parse for SingleUse { + /// fn parse(input: ParseStream) -> Result<Self> { + /// Ok(SingleUse { + /// use_token: input.parse()?, + /// path: input.call(Path::parse_mod_style)?, + /// }) + /// } + /// } + /// ``` + pub fn parse_mod_style(input: ParseStream) -> Result<Self> { + Ok(Path { + leading_colon: input.parse()?, + segments: { + let mut segments = Punctuated::new(); + loop { + if !input.peek(Ident) + && !input.peek(Token![super]) + && !input.peek(Token![self]) + && !input.peek(Token![Self]) + && !input.peek(Token![crate]) + && !input.peek(Token![extern]) + { + break; + } + let ident = Ident::parse_any(input)?; + segments.push_value(PathSegment::from(ident)); + if !input.peek(Token![::]) { + break; + } + let punct = input.parse()?; + segments.push_punct(punct); + } + if segments.is_empty() { + return Err(input.error("expected path")); + } else if segments.trailing_punct() { + return Err(input.error("expected path segment")); + } + segments + }, + }) + } + + /// Determines whether this is a path of length 1 equal to the given + /// ident. + /// + /// For them to compare equal, it must be the case that: + /// + /// - the path has no leading colon, + /// - the number of path segments is 1, + /// - the first path segment has no angle bracketed or parenthesized + /// path arguments + /// - and the ident of the first path segment is equal to the given one. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + pub fn is_ident<I>(&self, ident: I) -> bool + where + Ident: PartialEq<I>, + { + self.leading_colon.is_none() + && self.segments.len() == 1 + && self.segments[0].arguments.is_none() + && self.segments[0].ident == ident + } + + fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { + if input.peek(Token![dyn]) { + return Err(input.error("expected path")); + } + + Ok(Path { + leading_colon: input.parse()?, + segments: { + let mut segments = Punctuated::new(); + let value = PathSegment::parse_helper(input, expr_style)?; + segments.push_value(value); + while input.peek(Token![::]) { + let punct: Token![::] = input.parse()?; + segments.push_punct(punct); + let value = PathSegment::parse_helper(input, expr_style)?; + segments.push_value(value); + } + segments + }, + }) + } + } + + pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { + if input.peek(Token![<]) { + let lt_token: Token![<] = input.parse()?; + let this: Type = input.parse()?; + let path = if input.peek(Token![as]) { + let as_token: Token![as] = input.parse()?; + let path: Path = input.parse()?; + Some((as_token, path)) + } else { + None + }; + let gt_token: Token![>] = input.parse()?; + let colon2_token: Token![::] = input.parse()?; + let mut rest = Punctuated::new(); + loop { + let path = PathSegment::parse_helper(input, expr_style)?; + rest.push_value(path); + if !input.peek(Token![::]) { + break; + } + let punct: Token![::] = input.parse()?; + rest.push_punct(punct); + } + let (position, as_token, path) = match path { + Some((as_token, mut path)) => { + let pos = path.segments.len(); + path.segments.push_punct(colon2_token); + path.segments.extend(rest.into_pairs()); + (pos, Some(as_token), path) + } + None => { + let path = Path { + leading_colon: Some(colon2_token), + segments: rest, + }; + (0, None, path) + } + }; + let qself = QSelf { + lt_token: lt_token, + ty: Box::new(this), + position: position, + as_token: as_token, + gt_token: gt_token, + }; + Ok((Some(qself), path)) + } else { + let path = Path::parse_helper(input, expr_style)?; + Ok((None, path)) + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::ToTokens; + + use print::TokensOrDefault; + + impl ToTokens for Path { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.leading_colon.to_tokens(tokens); + self.segments.to_tokens(tokens); + } + } + + impl ToTokens for PathSegment { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.arguments.to_tokens(tokens); + } + } + + impl ToTokens for PathArguments { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + PathArguments::None => {} + PathArguments::AngleBracketed(ref arguments) => { + arguments.to_tokens(tokens); + } + PathArguments::Parenthesized(ref arguments) => { + arguments.to_tokens(tokens); + } + } + } + } + + impl ToTokens for GenericArgument { + #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens), + GenericArgument::Type(ref ty) => ty.to_tokens(tokens), + GenericArgument::Binding(ref tb) => tb.to_tokens(tokens), + GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens), + GenericArgument::Const(ref e) => match *e { + Expr::Lit(_) => e.to_tokens(tokens), + + // NOTE: We should probably support parsing blocks with only + // expressions in them without the full feature for const + // generics. + #[cfg(feature = "full")] + Expr::Block(_) => e.to_tokens(tokens), + + // ERROR CORRECTION: Add braces to make sure that the + // generated code is valid. + _ => token::Brace::default().surround(tokens, |tokens| { + e.to_tokens(tokens); + }), + }, + } + } + } + + impl ToTokens for AngleBracketedGenericArguments { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.colon2_token.to_tokens(tokens); + self.lt_token.to_tokens(tokens); + + // Print lifetimes before types and consts, all before bindings, + // regardless of their order in self.args. + // + // TODO: ordering rules for const arguments vs type arguments have + // not been settled yet. https://github.com/rust-lang/rust/issues/44580 + let mut trailing_or_empty = true; + for param in self.args.pairs() { + match **param.value() { + GenericArgument::Lifetime(_) => { + param.to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + GenericArgument::Type(_) + | GenericArgument::Binding(_) + | GenericArgument::Constraint(_) + | GenericArgument::Const(_) => {} + } + } + for param in self.args.pairs() { + match **param.value() { + GenericArgument::Type(_) | GenericArgument::Const(_) => { + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + } + param.to_tokens(tokens); + trailing_or_empty = param.punct().is_some(); + } + GenericArgument::Lifetime(_) + | GenericArgument::Binding(_) + | GenericArgument::Constraint(_) => {} + } + } + for param in self.args.pairs() { + match **param.value() { + GenericArgument::Binding(_) | GenericArgument::Constraint(_) => { + if !trailing_or_empty { + <Token![,]>::default().to_tokens(tokens); + trailing_or_empty = true; + } + param.to_tokens(tokens); + } + GenericArgument::Lifetime(_) + | GenericArgument::Type(_) + | GenericArgument::Const(_) => {} + } + } + + self.gt_token.to_tokens(tokens); + } + } + + impl ToTokens for Binding { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.eq_token.to_tokens(tokens); + self.ty.to_tokens(tokens); + } + } + + impl ToTokens for Constraint { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.colon_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + + impl ToTokens for ParenthesizedGenericArguments { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.inputs.to_tokens(tokens); + }); + self.output.to_tokens(tokens); + } + } + + impl private { + pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { + let qself = match *qself { + Some(ref qself) => qself, + None => { + path.to_tokens(tokens); + return; + } + }; + qself.lt_token.to_tokens(tokens); + qself.ty.to_tokens(tokens); + + let pos = if qself.position > 0 && qself.position >= path.segments.len() { + path.segments.len() - 1 + } else { + qself.position + }; + let mut segments = path.segments.pairs(); + if pos > 0 { + TokensOrDefault(&qself.as_token).to_tokens(tokens); + path.leading_colon.to_tokens(tokens); + for (i, segment) in segments.by_ref().take(pos).enumerate() { + if i + 1 == pos { + segment.value().to_tokens(tokens); + qself.gt_token.to_tokens(tokens); + segment.punct().to_tokens(tokens); + } else { + segment.to_tokens(tokens); + } + } + } else { + qself.gt_token.to_tokens(tokens); + path.leading_colon.to_tokens(tokens); + } + for segment in segments { + segment.to_tokens(tokens); + } + } + } +} diff --git a/syn/src/print.rs b/syn/src/print.rs new file mode 100644 index 000000000..90570a040 --- /dev/null +++ b/syn/src/print.rs @@ -0,0 +1,16 @@ +use proc_macro2::TokenStream; +use quote::ToTokens; + +pub struct TokensOrDefault<'a, T: 'a>(pub &'a Option<T>); + +impl<'a, T> ToTokens for TokensOrDefault<'a, T> +where + T: ToTokens + Default, +{ + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self.0 { + Some(ref t) => t.to_tokens(tokens), + None => T::default().to_tokens(tokens), + } + } +} diff --git a/syn/src/punctuated.rs b/syn/src/punctuated.rs new file mode 100644 index 000000000..5aa519ffe --- /dev/null +++ b/syn/src/punctuated.rs @@ -0,0 +1,836 @@ +//! A punctuated sequence of syntax tree nodes separated by punctuation. +//! +//! Lots of things in Rust are punctuated sequences. +//! +//! - The fields of a struct are `Punctuated<Field, Token![,]>`. +//! - The segments of a path are `Punctuated<PathSegment, Token![::]>`. +//! - The bounds on a generic parameter are `Punctuated<TypeParamBound, +//! Token![+]>`. +//! - The arguments to a function call are `Punctuated<Expr, Token![,]>`. +//! +//! This module provides a common representation for these punctuated sequences +//! in the form of the [`Punctuated<T, P>`] type. We store a vector of pairs of +//! syntax tree node + punctuation, where every node in the sequence is followed +//! by punctuation except for possibly the final one. +//! +//! [`Punctuated<T, P>`]: struct.Punctuated.html +//! +//! ```text +//! a_function_call(arg1, arg2, arg3); +//! ^^^^^ ~~~~~ ^^^^ +//! ``` + +#[cfg(feature = "extra-traits")] +use std::fmt::{self, Debug}; +#[cfg(any(feature = "full", feature = "derive"))] +use std::iter; +use std::iter::FromIterator; +use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; +use std::option; +use std::slice; +use std::vec; + +#[cfg(feature = "parsing")] +use parse::{Parse, ParseStream, Result}; +#[cfg(any(feature = "full", feature = "derive"))] +use private; +#[cfg(feature = "parsing")] +use token::Token; + +/// A punctuated sequence of syntax tree nodes of type `T` separated by +/// punctuation of type `P`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))] +#[cfg_attr(feature = "clone-impls", derive(Clone))] +pub struct Punctuated<T, P> { + inner: Vec<(T, P)>, + last: Option<Box<T>>, +} + +impl<T, P> Punctuated<T, P> { + /// Creates an empty punctuated sequence. + pub fn new() -> Punctuated<T, P> { + Punctuated { + inner: Vec::new(), + last: None, + } + } + + /// Determines whether this punctuated sequence is empty, meaning it + /// contains no syntax tree nodes or punctuation. + pub fn is_empty(&self) -> bool { + self.inner.len() == 0 && self.last.is_none() + } + + /// Returns the number of syntax tree nodes in this punctuated sequence. + /// + /// This is the number of nodes of type `T`, not counting the punctuation of + /// type `P`. + pub fn len(&self) -> usize { + self.inner.len() + if self.last.is_some() { 1 } else { 0 } + } + + /// Borrows the first punctuated pair in this sequence. + pub fn first(&self) -> Option<Pair<&T, &P>> { + self.pairs().next() + } + + /// Borrows the last punctuated pair in this sequence. + pub fn last(&self) -> Option<Pair<&T, &P>> { + if self.last.is_some() { + self.last.as_ref().map(|t| Pair::End(t.as_ref())) + } else { + self.inner + .last() + .map(|&(ref t, ref d)| Pair::Punctuated(t, d)) + } + } + + /// Mutably borrows the last punctuated pair in this sequence. + pub fn last_mut(&mut self) -> Option<Pair<&mut T, &mut P>> { + if self.last.is_some() { + self.last.as_mut().map(|t| Pair::End(t.as_mut())) + } else { + self.inner + .last_mut() + .map(|&mut (ref mut t, ref mut d)| Pair::Punctuated(t, d)) + } + } + + /// Returns an iterator over borrowed syntax tree nodes of type `&T`. + pub fn iter(&self) -> Iter<T> { + Iter { + inner: Box::new(PrivateIter { + inner: self.inner.iter(), + last: self.last.as_ref().map(Box::as_ref).into_iter(), + }), + } + } + + /// Returns an iterator over mutably borrowed syntax tree nodes of type + /// `&mut T`. + pub fn iter_mut(&mut self) -> IterMut<T> { + IterMut { + inner: Box::new(PrivateIterMut { + inner: self.inner.iter_mut(), + last: self.last.as_mut().map(Box::as_mut).into_iter(), + }), + } + } + + /// Returns an iterator over the contents of this sequence as borrowed + /// punctuated pairs. + pub fn pairs(&self) -> Pairs<T, P> { + Pairs { + inner: self.inner.iter(), + last: self.last.as_ref().map(Box::as_ref).into_iter(), + } + } + + /// Returns an iterator over the contents of this sequence as mutably + /// borrowed punctuated pairs. + pub fn pairs_mut(&mut self) -> PairsMut<T, P> { + PairsMut { + inner: self.inner.iter_mut(), + last: self.last.as_mut().map(Box::as_mut).into_iter(), + } + } + + /// Returns an iterator over the contents of this sequence as owned + /// punctuated pairs. + pub fn into_pairs(self) -> IntoPairs<T, P> { + IntoPairs { + inner: self.inner.into_iter(), + last: self.last.map(|t| *t).into_iter(), + } + } + + /// Appends a syntax tree node onto the end of this punctuated sequence. The + /// sequence must previously have a trailing punctuation. + /// + /// Use [`push`] instead if the punctuated sequence may or may not already + /// have trailing punctuation. + /// + /// [`push`]: #method.push + /// + /// # Panics + /// + /// Panics if the sequence does not already have a trailing punctuation when + /// this method is called. + pub fn push_value(&mut self, value: T) { + assert!(self.empty_or_trailing()); + self.last = Some(Box::new(value)); + } + + /// Appends a trailing punctuation onto the end of this punctuated sequence. + /// The sequence must be non-empty and must not already have trailing + /// punctuation. + /// + /// # Panics + /// + /// Panics if the sequence is empty or already has a trailing punctuation. + pub fn push_punct(&mut self, punctuation: P) { + assert!(self.last.is_some()); + let last = self.last.take().unwrap(); + self.inner.push((*last, punctuation)); + } + + /// Removes the last punctuated pair from this sequence, or `None` if the + /// sequence is empty. + pub fn pop(&mut self) -> Option<Pair<T, P>> { + if self.last.is_some() { + self.last.take().map(|t| Pair::End(*t)) + } else { + self.inner.pop().map(|(t, d)| Pair::Punctuated(t, d)) + } + } + + /// Determines whether this punctuated sequence ends with a trailing + /// punctuation. + pub fn trailing_punct(&self) -> bool { + self.last.is_none() && !self.is_empty() + } + + /// Returns true if either this `Punctuated` is empty, or it has a trailing + /// punctuation. + /// + /// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`. + pub fn empty_or_trailing(&self) -> bool { + self.last.is_none() + } + + /// Appends a syntax tree node onto the end of this punctuated sequence. + /// + /// If there is not a trailing punctuation in this sequence when this method + /// is called, the default value of punctuation type `P` is inserted before + /// the given value of type `T`. + pub fn push(&mut self, value: T) + where + P: Default, + { + if !self.empty_or_trailing() { + self.push_punct(Default::default()); + } + self.push_value(value); + } + + /// Inserts an element at position `index`. + /// + /// # Panics + /// + /// Panics if `index` is greater than the number of elements previously in + /// this punctuated sequence. + pub fn insert(&mut self, index: usize, value: T) + where + P: Default, + { + assert!(index <= self.len()); + + if index == self.len() { + self.push(value); + } else { + self.inner.insert(index, (value, Default::default())); + } + } + + /// Parses zero or more occurrences of `T` separated by punctuation of type + /// `P`, with optional trailing punctuation. + /// + /// Parsing continues until the end of this parse stream. The entire content + /// of this parse stream must consist of `T` and `P`. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_terminated(input: ParseStream) -> Result<Self> + where + T: Parse, + P: Parse, + { + Self::parse_terminated_with(input, T::parse) + } + + /// Parses zero or more occurrences of `T` using the given parse function, + /// separated by punctuation of type `P`, with optional trailing + /// punctuation. + /// + /// Like [`parse_terminated`], the entire content of this stream is expected + /// to be parsed. + /// + /// [`parse_terminated`]: #method.parse_terminated + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_terminated_with( + input: ParseStream, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Self> + where + P: Parse, + { + let mut punctuated = Punctuated::new(); + + loop { + if input.is_empty() { + break; + } + let value = parser(input)?; + punctuated.push_value(value); + if input.is_empty() { + break; + } + let punct = input.parse()?; + punctuated.push_punct(punct); + } + + Ok(punctuated) + } + + /// Parses one or more occurrences of `T` separated by punctuation of type + /// `P`, not accepting trailing punctuation. + /// + /// Parsing continues as long as punctuation `P` is present at the head of + /// the stream. This method returns upon parsing a `T` and observing that it + /// is not followed by a `P`, even if there are remaining tokens in the + /// stream. + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_separated_nonempty(input: ParseStream) -> Result<Self> + where + T: Parse, + P: Token + Parse, + { + Self::parse_separated_nonempty_with(input, T::parse) + } + + /// Parses one or more occurrences of `T` using the given parse function, + /// separated by punctuation of type `P`, not accepting trailing + /// punctuation. + /// + /// Like [`parse_separated_nonempty`], may complete early without parsing + /// the entire content of this stream. + /// + /// [`parse_separated_nonempty`]: #method.parse_separated_nonempty + /// + /// *This function is available if Syn is built with the `"parsing"` + /// feature.* + #[cfg(feature = "parsing")] + pub fn parse_separated_nonempty_with( + input: ParseStream, + parser: fn(ParseStream) -> Result<T>, + ) -> Result<Self> + where + P: Token + Parse, + { + let mut punctuated = Punctuated::new(); + + loop { + let value = parser(input)?; + punctuated.push_value(value); + if !P::peek(input.cursor()) { + break; + } + let punct = input.parse()?; + punctuated.push_punct(punct); + } + + Ok(punctuated) + } +} + +#[cfg(feature = "extra-traits")] +impl<T: Debug, P: Debug> Debug for Punctuated<T, P> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut list = f.debug_list(); + for &(ref t, ref p) in &self.inner { + list.entry(t); + list.entry(p); + } + if let Some(ref last) = self.last { + list.entry(last); + } + list.finish() + } +} + +impl<T, P> FromIterator<T> for Punctuated<T, P> +where + P: Default, +{ + fn from_iter<I: IntoIterator<Item = T>>(i: I) -> Self { + let mut ret = Punctuated::new(); + ret.extend(i); + ret + } +} + +impl<T, P> Extend<T> for Punctuated<T, P> +where + P: Default, +{ + fn extend<I: IntoIterator<Item = T>>(&mut self, i: I) { + for value in i { + self.push(value); + } + } +} + +impl<T, P> FromIterator<Pair<T, P>> for Punctuated<T, P> { + fn from_iter<I: IntoIterator<Item = Pair<T, P>>>(i: I) -> Self { + let mut ret = Punctuated::new(); + ret.extend(i); + ret + } +} + +impl<T, P> Extend<Pair<T, P>> for Punctuated<T, P> { + fn extend<I: IntoIterator<Item = Pair<T, P>>>(&mut self, i: I) { + assert!(self.empty_or_trailing()); + let mut nomore = false; + for pair in i { + if nomore { + panic!("Punctuated extended with items after a Pair::End"); + } + match pair { + Pair::Punctuated(a, b) => self.inner.push((a, b)), + Pair::End(a) => { + self.last = Some(Box::new(a)); + nomore = true; + } + } + } + } +} + +impl<T, P> IntoIterator for Punctuated<T, P> { + type Item = T; + type IntoIter = IntoIter<T, P>; + + fn into_iter(self) -> Self::IntoIter { + let mut elements = Vec::with_capacity(self.len()); + elements.extend(self.inner.into_iter().map(|pair| pair.0)); + elements.extend(self.last.map(|t| *t)); + + IntoIter { + inner: elements.into_iter(), + marker: PhantomData, + } + } +} + +impl<'a, T, P> IntoIterator for &'a Punctuated<T, P> { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Punctuated::iter(self) + } +} + +impl<'a, T, P> IntoIterator for &'a mut Punctuated<T, P> { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + Punctuated::iter_mut(self) + } +} + +impl<T, P> Default for Punctuated<T, P> { + fn default() -> Self { + Punctuated::new() + } +} + +/// An iterator over borrowed pairs of type `Pair<&T, &P>`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +pub struct Pairs<'a, T: 'a, P: 'a> { + inner: slice::Iter<'a, (T, P)>, + last: option::IntoIter<&'a T>, +} + +impl<'a, T, P> Iterator for Pairs<'a, T, P> { + type Item = Pair<&'a T, &'a P>; + + fn next(&mut self) -> Option<Self::Item> { + self.inner + .next() + .map(|&(ref t, ref p)| Pair::Punctuated(t, p)) + .or_else(|| self.last.next().map(Pair::End)) + } +} + +impl<'a, T, P> ExactSizeIterator for Pairs<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +// No Clone bound on T or P. +impl<'a, T, P> Clone for Pairs<'a, T, P> { + fn clone(&self) -> Self { + Pairs { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + +/// An iterator over mutably borrowed pairs of type `Pair<&mut T, &mut P>`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +pub struct PairsMut<'a, T: 'a, P: 'a> { + inner: slice::IterMut<'a, (T, P)>, + last: option::IntoIter<&'a mut T>, +} + +impl<'a, T, P> Iterator for PairsMut<'a, T, P> { + type Item = Pair<&'a mut T, &'a mut P>; + + fn next(&mut self) -> Option<Self::Item> { + self.inner + .next() + .map(|&mut (ref mut t, ref mut p)| Pair::Punctuated(t, p)) + .or_else(|| self.last.next().map(Pair::End)) + } +} + +impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +/// An iterator over owned pairs of type `Pair<T, P>`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +#[derive(Clone)] +pub struct IntoPairs<T, P> { + inner: vec::IntoIter<(T, P)>, + last: option::IntoIter<T>, +} + +impl<T, P> Iterator for IntoPairs<T, P> { + type Item = Pair<T, P>; + + fn next(&mut self) -> Option<Self::Item> { + self.inner + .next() + .map(|(t, p)| Pair::Punctuated(t, p)) + .or_else(|| self.last.next().map(Pair::End)) + } +} + +impl<T, P> ExactSizeIterator for IntoPairs<T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +/// An iterator over owned values of type `T`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +#[derive(Clone)] +pub struct IntoIter<T, P> { + inner: vec::IntoIter<T>, + + // TODO: remove P type parameter in the next breaking change + marker: PhantomData<P>, +} + +impl<T, P> Iterator for IntoIter<T, P> { + type Item = T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } +} + +impl<T, P> ExactSizeIterator for IntoIter<T, P> { + fn len(&self) -> usize { + self.inner.len() + } +} + +/// An iterator over borrowed values of type `&T`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +pub struct Iter<'a, T: 'a> { + // The `Item = &'a T` needs to be specified to support rustc 1.31 and older. + // On modern compilers we would be able to write just IterTrait<'a, T> where + // Item can be inferred unambiguously from the supertrait. + inner: Box<IterTrait<'a, T, Item = &'a T> + 'a>, +} + +trait IterTrait<'a, T: 'a>: ExactSizeIterator<Item = &'a T> { + fn clone_box(&self) -> Box<IterTrait<'a, T, Item = &'a T> + 'a>; +} + +struct PrivateIter<'a, T: 'a, P: 'a> { + inner: slice::Iter<'a, (T, P)>, + last: option::IntoIter<&'a T>, +} + +#[cfg(any(feature = "full", feature = "derive"))] +impl private { + pub fn empty_punctuated_iter<'a, T>() -> Iter<'a, T> { + Iter { + inner: Box::new(iter::empty()), + } + } +} + +// No Clone bound on T. +impl<'a, T> Clone for Iter<'a, T> { + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone_box(), + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for Iter<'a, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl<'a, T, P> Iterator for PrivateIter<'a, T, P> { + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner + .next() + .map(|pair| &pair.0) + .or_else(|| self.last.next()) + } +} + +impl<'a, T, P> ExactSizeIterator for PrivateIter<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +// No Clone bound on T or P. +impl<'a, T, P> Clone for PrivateIter<'a, T, P> { + fn clone(&self) -> Self { + PrivateIter { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + +impl<'a, T: 'a, I: 'a> IterTrait<'a, T> for I +where + I: ExactSizeIterator<Item = &'a T> + Clone, +{ + fn clone_box(&self) -> Box<IterTrait<'a, T, Item = &'a T> + 'a> { + Box::new(self.clone()) + } +} + +/// An iterator over mutably borrowed values of type `&mut T`. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +pub struct IterMut<'a, T: 'a> { + inner: Box<ExactSizeIterator<Item = &'a mut T> + 'a>, +} + +struct PrivateIterMut<'a, T: 'a, P: 'a> { + inner: slice::IterMut<'a, (T, P)>, + last: option::IntoIter<&'a mut T>, +} + +#[cfg(any(feature = "full", feature = "derive"))] +impl private { + pub fn empty_punctuated_iter_mut<'a, T>() -> IterMut<'a, T> { + IterMut { + inner: Box::new(iter::empty()), + } + } +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for IterMut<'a, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl<'a, T, P> Iterator for PrivateIterMut<'a, T, P> { + type Item = &'a mut T; + + fn next(&mut self) -> Option<Self::Item> { + self.inner + .next() + .map(|pair| &mut pair.0) + .or_else(|| self.last.next()) + } +} + +impl<'a, T, P> ExactSizeIterator for PrivateIterMut<'a, T, P> { + fn len(&self) -> usize { + self.inner.len() + self.last.len() + } +} + +/// A single syntax tree node of type `T` followed by its trailing punctuation +/// of type `P` if any. +/// +/// Refer to the [module documentation] for details about punctuated sequences. +/// +/// [module documentation]: index.html +#[cfg_attr(feature = "clone-impls", derive(Clone))] +pub enum Pair<T, P> { + Punctuated(T, P), + End(T), +} + +impl<T, P> Pair<T, P> { + /// Extracts the syntax tree node from this punctuated pair, discarding the + /// following punctuation. + pub fn into_value(self) -> T { + match self { + Pair::Punctuated(t, _) | Pair::End(t) => t, + } + } + + /// Borrows the syntax tree node from this punctuated pair. + pub fn value(&self) -> &T { + match *self { + Pair::Punctuated(ref t, _) | Pair::End(ref t) => t, + } + } + + /// Mutably borrows the syntax tree node from this punctuated pair. + pub fn value_mut(&mut self) -> &mut T { + match *self { + Pair::Punctuated(ref mut t, _) | Pair::End(ref mut t) => t, + } + } + + /// Borrows the punctuation from this punctuated pair, unless this pair is + /// the final one and there is no trailing punctuation. + pub fn punct(&self) -> Option<&P> { + match *self { + Pair::Punctuated(_, ref d) => Some(d), + Pair::End(_) => None, + } + } + + /// Creates a punctuated pair out of a syntax tree node and an optional + /// following punctuation. + pub fn new(t: T, d: Option<P>) -> Self { + match d { + Some(d) => Pair::Punctuated(t, d), + None => Pair::End(t), + } + } + + /// Produces this punctuated pair as a tuple of syntax tree node and + /// optional following punctuation. + pub fn into_tuple(self) -> (T, Option<P>) { + match self { + Pair::Punctuated(t, d) => (t, Some(d)), + Pair::End(t) => (t, None), + } + } +} + +impl<T, P> Index<usize> for Punctuated<T, P> { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + if index == self.len() - 1 { + match self.last { + Some(ref t) => t, + None => &self.inner[index].0, + } + } else { + &self.inner[index].0 + } + } +} + +impl<T, P> IndexMut<usize> for Punctuated<T, P> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index == self.len() - 1 { + match self.last { + Some(ref mut t) => t, + None => &mut self.inner[index].0, + } + } else { + &mut self.inner[index].0 + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + use proc_macro2::TokenStream; + use quote::{ToTokens, TokenStreamExt}; + + impl<T, P> ToTokens for Punctuated<T, P> + where + T: ToTokens, + P: ToTokens, + { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.pairs()) + } + } + + impl<T, P> ToTokens for Pair<T, P> + where + T: ToTokens, + P: ToTokens, + { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + Pair::Punctuated(ref a, ref b) => { + a.to_tokens(tokens); + b.to_tokens(tokens); + } + Pair::End(ref a) => a.to_tokens(tokens), + } + } + } +} diff --git a/syn/src/sealed.rs b/syn/src/sealed.rs new file mode 100644 index 000000000..0b11bc99a --- /dev/null +++ b/syn/src/sealed.rs @@ -0,0 +1,4 @@ +#[cfg(feature = "parsing")] +pub mod lookahead { + pub trait Sealed: Copy {} +} diff --git a/syn/src/span.rs b/syn/src/span.rs new file mode 100644 index 000000000..27a7fe846 --- /dev/null +++ b/syn/src/span.rs @@ -0,0 +1,67 @@ +use proc_macro2::Span; + +pub trait IntoSpans<S> { + fn into_spans(self) -> S; +} + +impl IntoSpans<[Span; 1]> for Span { + fn into_spans(self) -> [Span; 1] { + [self] + } +} + +impl IntoSpans<[Span; 2]> for Span { + fn into_spans(self) -> [Span; 2] { + [self, self] + } +} + +impl IntoSpans<[Span; 3]> for Span { + fn into_spans(self) -> [Span; 3] { + [self, self, self] + } +} + +impl IntoSpans<[Span; 1]> for [Span; 1] { + fn into_spans(self) -> [Span; 1] { + self + } +} + +impl IntoSpans<[Span; 2]> for [Span; 2] { + fn into_spans(self) -> [Span; 2] { + self + } +} + +impl IntoSpans<[Span; 3]> for [Span; 3] { + fn into_spans(self) -> [Span; 3] { + self + } +} + +#[cfg(feature = "parsing")] +pub trait FromSpans: Sized { + fn from_spans(spans: &[Span]) -> Self; +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 1] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0]] + } +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 2] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0], spans[1]] + } +} + +#[cfg(feature = "parsing")] +impl FromSpans for [Span; 3] { + fn from_spans(spans: &[Span]) -> Self { + [spans[0], spans[1], spans[2]] + } +} diff --git a/syn/src/spanned.rs b/syn/src/spanned.rs new file mode 100644 index 000000000..79e23dfbb --- /dev/null +++ b/syn/src/spanned.rs @@ -0,0 +1,144 @@ +//! A trait that can provide the `Span` of the complete contents of a syntax +//! tree node. +//! +//! *This module is available if Syn is built with both the `"parsing"` and +//! `"printing"` features.* +//! +//! # Example +//! +//! Suppose in a procedural macro we have a [`Type`] that we want to assert +//! implements the [`Sync`] trait. Maybe this is the type of one of the fields +//! of a struct for which we are deriving a trait implementation, and we need to +//! be able to pass a reference to one of those fields across threads. +//! +//! [`Type`]: ../enum.Type.html +//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! +//! If the field type does *not* implement `Sync` as required, we want the +//! compiler to report an error pointing out exactly which type it was. +//! +//! The following macro code takes a variable `ty` of type `Type` and produces a +//! static assertion that `Sync` is implemented for that type. +//! +//! ```edition2018 +//! # extern crate proc_macro; +//! # +//! use proc_macro::TokenStream; +//! use proc_macro2::Span; +//! use quote::quote_spanned; +//! use syn::Type; +//! use syn::spanned::Spanned; +//! +//! # const IGNORE_TOKENS: &str = stringify! { +//! #[proc_macro_derive(MyMacro)] +//! # }; +//! pub fn my_macro(input: TokenStream) -> TokenStream { +//! # let ty = get_a_type(); +//! /* ... */ +//! +//! let assert_sync = quote_spanned! {ty.span()=> +//! struct _AssertSync where #ty: Sync; +//! }; +//! +//! /* ... */ +//! # input +//! } +//! # +//! # fn get_a_type() -> Type { +//! # unimplemented!() +//! # } +//! ``` +//! +//! By inserting this `assert_sync` fragment into the output code generated by +//! our macro, the user's code will fail to compile if `ty` does not implement +//! `Sync`. The errors they would see look like the following. +//! +//! ```text +//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied +//! --> src/main.rs:10:21 +//! | +//! 10 | bad_field: *const i32, +//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely +//! ``` +//! +//! In this technique, using the `Type`'s span for the error message makes the +//! error appear in the correct place underlining the right type. + +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; + +/// A trait that can provide the `Span` of the complete contents of a syntax +/// tree node. +/// +/// This trait is automatically implemented for all types that implement +/// [`ToTokens`] from the `quote` crate. It is sealed and cannot be implemented +/// outside of the Syn crate other than by implementing `ToTokens`. +/// +/// [`ToTokens`]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +/// +/// See the [module documentation] for an example. +/// +/// [module documentation]: index.html +/// +/// *This trait is available if Syn is built with both the `"parsing"` and +/// `"printing"` features.* +pub trait Spanned: private::Sealed { + /// Returns a `Span` covering the complete contents of this syntax tree + /// node, or [`Span::call_site()`] if this node is empty. + /// + /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.call_site + fn span(&self) -> Span; +} + +mod private { + use quote::ToTokens; + pub trait Sealed {} + impl<T: ToTokens> Sealed for T {} +} + +impl<T> Spanned for T +where + T: ToTokens, +{ + fn span(&self) -> Span { + join_spans(self.into_token_stream()) + } +} + +fn join_spans(tokens: TokenStream) -> Span { + let mut iter = tokens.into_iter().filter_map(|tt| { + // FIXME: This shouldn't be required, since optimally spans should + // never be invalid. This filter_map can probably be removed when + // https://github.com/rust-lang/rust/issues/43081 is resolved. + let span = tt.span(); + let debug = format!("{:?}", span); + if debug.ends_with("bytes(0..0)") { + None + } else { + Some(span) + } + }); + + let mut joined = match iter.next() { + Some(span) => span, + None => return Span::call_site(), + }; + + #[cfg(procmacro2_semver_exempt)] + { + for next in iter { + if let Some(span) = joined.join(next) { + joined = span; + } + } + } + + #[cfg(not(procmacro2_semver_exempt))] + { + // We can't join spans without procmacro2_semver_exempt so just grab the + // first one. + joined = joined; + } + + joined +} diff --git a/syn/src/thread.rs b/syn/src/thread.rs new file mode 100644 index 000000000..ff47e4af4 --- /dev/null +++ b/syn/src/thread.rs @@ -0,0 +1,83 @@ +use std::fmt::{self, Debug}; + +use self::thread_id::ThreadId; + +/// ThreadBound is a Sync-maker and Send-maker that allows accessing a value +/// of type T only from the original thread on which the ThreadBound was +/// constructed. +pub struct ThreadBound<T> { + value: T, + thread_id: ThreadId, +} + +unsafe impl<T> Sync for ThreadBound<T> {} + +// Send bound requires Copy, as otherwise Drop could run in the wrong place. +unsafe impl<T: Copy> Send for ThreadBound<T> {} + +impl<T> ThreadBound<T> { + pub fn new(value: T) -> Self { + ThreadBound { + value: value, + thread_id: thread_id::current(), + } + } + + pub fn get(&self) -> Option<&T> { + if thread_id::current() == self.thread_id { + Some(&self.value) + } else { + None + } + } +} + +impl<T: Debug> Debug for ThreadBound<T> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + Some(value) => Debug::fmt(value, formatter), + None => formatter.write_str("unknown"), + } + } +} + +#[cfg(syn_can_use_thread_id)] +mod thread_id { + use std::thread; + + pub use std::thread::ThreadId; + + pub fn current() -> ThreadId { + thread::current().id() + } +} + +#[cfg(not(syn_can_use_thread_id))] +mod thread_id { + #[allow(deprecated)] + use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + + thread_local! { + static THREAD_ID: usize = { + #[allow(deprecated)] + static NEXT_THREAD_ID: AtomicUsize = ATOMIC_USIZE_INIT; + + // Ordering::Relaxed because our only requirement for the ids is + // that they are unique. It is okay for the compiler to rearrange + // other memory reads around this fetch. It's still an atomic + // fetch_add, so no two threads will be able to read the same value + // from it. + // + // The main thing which these orderings affect is other memory reads + // around the atomic read, which for our case are irrelevant as this + // atomic guards nothing. + NEXT_THREAD_ID.fetch_add(1, Ordering::Relaxed) + }; + } + + pub type ThreadId = usize; + + pub fn current() -> ThreadId { + THREAD_ID.with(|id| *id) + } +} diff --git a/syn/src/token.rs b/syn/src/token.rs new file mode 100644 index 000000000..55264133e --- /dev/null +++ b/syn/src/token.rs @@ -0,0 +1,950 @@ +//! Tokens representing Rust punctuation, keywords, and delimiters. +//! +//! The type names in this module can be difficult to keep straight, so we +//! prefer to use the [`Token!`] macro instead. This is a type-macro that +//! expands to the token type of the given token. +//! +//! [`Token!`]: ../macro.Token.html +//! +//! # Example +//! +//! The [`ItemStatic`] syntax tree node is defined like this. +//! +//! [`ItemStatic`]: ../struct.ItemStatic.html +//! +//! ```edition2018 +//! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility}; +//! # +//! pub struct ItemStatic { +//! pub attrs: Vec<Attribute>, +//! pub vis: Visibility, +//! pub static_token: Token![static], +//! pub mutability: Option<Token![mut]>, +//! pub ident: Ident, +//! pub colon_token: Token![:], +//! pub ty: Box<Type>, +//! pub eq_token: Token![=], +//! pub expr: Box<Expr>, +//! pub semi_token: Token![;], +//! } +//! ``` +//! +//! # Parsing +//! +//! Keywords and punctuation can be parsed through the [`ParseStream::parse`] +//! method. Delimiter tokens are parsed using the [`parenthesized!`], +//! [`bracketed!`] and [`braced!`] macros. +//! +//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse +//! [`parenthesized!`]: ../macro.parenthesized.html +//! [`bracketed!`]: ../macro.bracketed.html +//! [`braced!`]: ../macro.braced.html +//! +//! ```edition2018 +//! use syn::{Attribute, Result}; +//! use syn::parse::{Parse, ParseStream}; +//! # +//! # enum ItemStatic {} +//! +//! // Parse the ItemStatic struct shown above. +//! impl Parse for ItemStatic { +//! fn parse(input: ParseStream) -> Result<Self> { +//! # use syn::ItemStatic; +//! # fn parse(input: ParseStream) -> Result<ItemStatic> { +//! Ok(ItemStatic { +//! attrs: input.call(Attribute::parse_outer)?, +//! vis: input.parse()?, +//! static_token: input.parse()?, +//! mutability: input.parse()?, +//! ident: input.parse()?, +//! colon_token: input.parse()?, +//! ty: input.parse()?, +//! eq_token: input.parse()?, +//! expr: input.parse()?, +//! semi_token: input.parse()?, +//! }) +//! # } +//! # unimplemented!() +//! } +//! } +//! ``` +//! +//! # Other operations +//! +//! Every keyword and punctuation token supports the following operations. +//! +//! - [Peeking] — `input.peek(Token![...])` +//! +//! - [Parsing] — `input.parse::<Token![...]>()?` +//! +//! - [Printing] — `quote!( ... #the_token ... )` +//! +//! - Construction from a [`Span`] — `let the_token = Token![...](sp)` +//! +//! - Field access to its span — `let sp = the_token.span` +//! +//! [Peeking]: ../parse/struct.ParseBuffer.html#method.peek +//! [Parsing]: ../parse/struct.ParseBuffer.html#method.parse +//! [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +//! [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html + +use std; +#[cfg(feature = "extra-traits")] +use std::cmp; +#[cfg(feature = "extra-traits")] +use std::fmt::{self, Debug}; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +use std::ops::{Deref, DerefMut}; + +#[cfg(feature = "parsing")] +use proc_macro2::Delimiter; +#[cfg(any(feature = "parsing", feature = "printing"))] +use proc_macro2::Ident; +use proc_macro2::Span; +#[cfg(feature = "printing")] +use proc_macro2::TokenStream; +#[cfg(feature = "printing")] +use quote::{ToTokens, TokenStreamExt}; + +use self::private::WithSpan; +#[cfg(feature = "parsing")] +use buffer::Cursor; +#[cfg(feature = "parsing")] +use error::Result; +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +use lifetime::Lifetime; +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +use lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; +#[cfg(feature = "parsing")] +use lookahead; +#[cfg(feature = "parsing")] +use parse::{Parse, ParseStream}; +use span::IntoSpans; + +/// Marker trait for types that represent single tokens. +/// +/// This trait is sealed and cannot be implemented for types outside of Syn. +#[cfg(feature = "parsing")] +pub trait Token: private::Sealed { + // Not public API. + #[doc(hidden)] + fn peek(cursor: Cursor) -> bool; + + // Not public API. + #[doc(hidden)] + fn display() -> &'static str; +} + +mod private { + use proc_macro2::Span; + + #[cfg(feature = "parsing")] + pub trait Sealed {} + + /// Support writing `token.span` rather than `token.spans[0]` on tokens that + /// hold a single span. + #[repr(C)] + pub struct WithSpan { + pub span: Span, + } +} + +#[cfg(feature = "parsing")] +impl private::Sealed for Ident {} + +#[cfg(any(feature = "full", feature = "derive"))] +#[cfg(feature = "parsing")] +fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { + use std::cell::Cell; + use std::rc::Rc; + + let scope = Span::call_site(); + let unexpected = Rc::new(Cell::new(None)); + let buffer = ::private::new_parse_buffer(scope, cursor, unexpected); + peek(&buffer) +} + +#[cfg(any(feature = "full", feature = "derive"))] +macro_rules! impl_token { + ($name:ident $display:expr) => { + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + fn peek(input: ParseStream) -> bool { + <$name as Parse>::parse(input).is_ok() + } + peek_impl(cursor, peek) + } + + fn display() -> &'static str { + $display + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + }; +} + +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(Lifetime "lifetime"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(Lit "literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitStr "string literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitByteStr "byte string literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitByte "byte literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitChar "character literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitInt "integer literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitFloat "floating point literal"); +#[cfg(any(feature = "full", feature = "derive"))] +impl_token!(LitBool "boolean literal"); + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "parsing")] +pub trait CustomToken { + fn peek(cursor: Cursor) -> bool; + fn display() -> &'static str; +} + +#[cfg(feature = "parsing")] +impl<T: CustomToken> private::Sealed for T {} + +#[cfg(feature = "parsing")] +impl<T: CustomToken> Token for T { + fn peek(cursor: Cursor) -> bool { + <Self as CustomToken>::peek(cursor) + } + + fn display() -> &'static str { + <Self as CustomToken>::display() + } +} + +macro_rules! define_keywords { + ($($token:tt pub struct $name:ident #[$doc:meta])*) => { + $( + #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] + #[$doc] + /// + /// Don't try to remember the name of this type -- use the [`Token!`] + /// macro instead. + /// + /// [`Token!`]: index.html + pub struct $name { + pub span: Span, + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name { + $name { + span: span.into_spans()[0], + } + } + + impl std::default::Default for $name { + fn default() -> Self { + $name { + span: Span::call_site(), + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + #[cfg(feature = "printing")] + impl ToTokens for $name { + fn to_tokens(&self, tokens: &mut TokenStream) { + printing::keyword($token, self.span, tokens); + } + } + + #[cfg(feature = "parsing")] + impl Parse for $name { + fn parse(input: ParseStream) -> Result<Self> { + Ok($name { + span: parsing::keyword(input, $token)?, + }) + } + } + + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + parsing::peek_keyword(cursor, $token) + } + + fn display() -> &'static str { + concat!("`", $token, "`") + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +macro_rules! impl_deref_if_len_is_1 { + ($name:ident/1) => { + impl Deref for $name { + type Target = WithSpan; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const WithSpan) } + } + } + + impl DerefMut for $name { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut WithSpan) } + } + } + }; + + ($name:ident/$len:tt) => {}; +} + +macro_rules! define_punctuation_structs { + ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => { + $( + #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] + #[repr(C)] + #[$doc] + /// + /// Don't try to remember the name of this type -- use the [`Token!`] + /// macro instead. + /// + /// [`Token!`]: index.html + pub struct $name { + pub spans: [Span; $len], + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name { + $name { + spans: spans.into_spans(), + } + } + + impl std::default::Default for $name { + fn default() -> Self { + $name { + spans: [Span::call_site(); $len], + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + impl_deref_if_len_is_1!($name/$len); + )* + }; +} + +macro_rules! define_punctuation { + ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => { + $( + define_punctuation_structs! { + $token pub struct $name/$len #[$doc] + } + + #[cfg(feature = "printing")] + impl ToTokens for $name { + fn to_tokens(&self, tokens: &mut TokenStream) { + printing::punct($token, &self.spans, tokens); + } + } + + #[cfg(feature = "parsing")] + impl Parse for $name { + fn parse(input: ParseStream) -> Result<Self> { + Ok($name { + spans: parsing::punct(input, $token)?, + }) + } + } + + #[cfg(feature = "parsing")] + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + parsing::peek_punct(cursor, $token) + } + + fn display() -> &'static str { + concat!("`", $token, "`") + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +macro_rules! define_delimiters { + ($($token:tt pub struct $name:ident #[$doc:meta])*) => { + $( + #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] + #[$doc] + pub struct $name { + pub span: Span, + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $name<S: IntoSpans<[Span; 1]>>(span: S) -> $name { + $name { + span: span.into_spans()[0], + } + } + + impl std::default::Default for $name { + fn default() -> Self { + $name { + span: Span::call_site(), + } + } + } + + #[cfg(feature = "extra-traits")] + impl Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "extra-traits")] + impl cmp::Eq for $name {} + + #[cfg(feature = "extra-traits")] + impl PartialEq for $name { + fn eq(&self, _other: &$name) -> bool { + true + } + } + + #[cfg(feature = "extra-traits")] + impl Hash for $name { + fn hash<H: Hasher>(&self, _state: &mut H) {} + } + + impl $name { + #[cfg(feature = "printing")] + pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) + where + F: FnOnce(&mut TokenStream), + { + printing::delim($token, self.span, tokens, f); + } + } + + #[cfg(feature = "parsing")] + impl private::Sealed for $name {} + )* + }; +} + +define_punctuation_structs! { + "_" pub struct Underscore/1 /// `_` +} + +#[cfg(feature = "printing")] +impl ToTokens for Underscore { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append(Ident::new("_", self.span)); + } +} + +#[cfg(feature = "parsing")] +impl Parse for Underscore { + fn parse(input: ParseStream) -> Result<Self> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if ident == "_" { + return Ok((Underscore(ident.span()), rest)); + } + } + if let Some((punct, rest)) = cursor.punct() { + if punct.as_char() == '_' { + return Ok((Underscore(punct.span()), rest)); + } + } + Err(cursor.error("expected `_`")) + }) + } +} + +#[cfg(feature = "parsing")] +impl Token for Underscore { + fn peek(cursor: Cursor) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + return ident == "_"; + } + if let Some((punct, _rest)) = cursor.punct() { + return punct.as_char() == '_'; + } + false + } + + fn display() -> &'static str { + "`_`" + } +} + +#[cfg(feature = "parsing")] +impl private::Sealed for Underscore {} + +#[cfg(feature = "parsing")] +impl Token for Paren { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Parenthesis) + } + + fn display() -> &'static str { + "parentheses" + } +} + +#[cfg(feature = "parsing")] +impl Token for Brace { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Brace) + } + + fn display() -> &'static str { + "curly braces" + } +} + +#[cfg(feature = "parsing")] +impl Token for Bracket { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::Bracket) + } + + fn display() -> &'static str { + "square brackets" + } +} + +#[cfg(feature = "parsing")] +impl Token for Group { + fn peek(cursor: Cursor) -> bool { + lookahead::is_delimiter(cursor, Delimiter::None) + } + + fn display() -> &'static str { + "invisible group" + } +} + +define_keywords! { + "abstract" pub struct Abstract /// `abstract` + "as" pub struct As /// `as` + "async" pub struct Async /// `async` + "auto" pub struct Auto /// `auto` + "become" pub struct Become /// `become` + "box" pub struct Box /// `box` + "break" pub struct Break /// `break` + "const" pub struct Const /// `const` + "continue" pub struct Continue /// `continue` + "crate" pub struct Crate /// `crate` + "default" pub struct Default /// `default` + "do" pub struct Do /// `do` + "dyn" pub struct Dyn /// `dyn` + "else" pub struct Else /// `else` + "enum" pub struct Enum /// `enum` + "existential" pub struct Existential /// `existential` + "extern" pub struct Extern /// `extern` + "final" pub struct Final /// `final` + "fn" pub struct Fn /// `fn` + "for" pub struct For /// `for` + "if" pub struct If /// `if` + "impl" pub struct Impl /// `impl` + "in" pub struct In /// `in` + "let" pub struct Let /// `let` + "loop" pub struct Loop /// `loop` + "macro" pub struct Macro /// `macro` + "match" pub struct Match /// `match` + "mod" pub struct Mod /// `mod` + "move" pub struct Move /// `move` + "mut" pub struct Mut /// `mut` + "override" pub struct Override /// `override` + "priv" pub struct Priv /// `priv` + "pub" pub struct Pub /// `pub` + "ref" pub struct Ref /// `ref` + "return" pub struct Return /// `return` + "Self" pub struct SelfType /// `Self` + "self" pub struct SelfValue /// `self` + "static" pub struct Static /// `static` + "struct" pub struct Struct /// `struct` + "super" pub struct Super /// `super` + "trait" pub struct Trait /// `trait` + "try" pub struct Try /// `try` + "type" pub struct Type /// `type` + "typeof" pub struct Typeof /// `typeof` + "union" pub struct Union /// `union` + "unsafe" pub struct Unsafe /// `unsafe` + "unsized" pub struct Unsized /// `unsized` + "use" pub struct Use /// `use` + "virtual" pub struct Virtual /// `virtual` + "where" pub struct Where /// `where` + "while" pub struct While /// `while` + "yield" pub struct Yield /// `yield` +} + +define_punctuation! { + "+" pub struct Add/1 /// `+` + "+=" pub struct AddEq/2 /// `+=` + "&" pub struct And/1 /// `&` + "&&" pub struct AndAnd/2 /// `&&` + "&=" pub struct AndEq/2 /// `&=` + "@" pub struct At/1 /// `@` + "!" pub struct Bang/1 /// `!` + "^" pub struct Caret/1 /// `^` + "^=" pub struct CaretEq/2 /// `^=` + ":" pub struct Colon/1 /// `:` + "::" pub struct Colon2/2 /// `::` + "," pub struct Comma/1 /// `,` + "/" pub struct Div/1 /// `/` + "/=" pub struct DivEq/2 /// `/=` + "$" pub struct Dollar/1 /// `$` + "." pub struct Dot/1 /// `.` + ".." pub struct Dot2/2 /// `..` + "..." pub struct Dot3/3 /// `...` + "..=" pub struct DotDotEq/3 /// `..=` + "=" pub struct Eq/1 /// `=` + "==" pub struct EqEq/2 /// `==` + ">=" pub struct Ge/2 /// `>=` + ">" pub struct Gt/1 /// `>` + "<=" pub struct Le/2 /// `<=` + "<" pub struct Lt/1 /// `<` + "*=" pub struct MulEq/2 /// `*=` + "!=" pub struct Ne/2 /// `!=` + "|" pub struct Or/1 /// `|` + "|=" pub struct OrEq/2 /// `|=` + "||" pub struct OrOr/2 /// `||` + "#" pub struct Pound/1 /// `#` + "?" pub struct Question/1 /// `?` + "->" pub struct RArrow/2 /// `->` + "<-" pub struct LArrow/2 /// `<-` + "%" pub struct Rem/1 /// `%` + "%=" pub struct RemEq/2 /// `%=` + "=>" pub struct FatArrow/2 /// `=>` + ";" pub struct Semi/1 /// `;` + "<<" pub struct Shl/2 /// `<<` + "<<=" pub struct ShlEq/3 /// `<<=` + ">>" pub struct Shr/2 /// `>>` + ">>=" pub struct ShrEq/3 /// `>>=` + "*" pub struct Star/1 /// `*` + "-" pub struct Sub/1 /// `-` + "-=" pub struct SubEq/2 /// `-=` + "~" pub struct Tilde/1 /// `~` +} + +define_delimiters! { + "{" pub struct Brace /// `{...}` + "[" pub struct Bracket /// `[...]` + "(" pub struct Paren /// `(...)` + " " pub struct Group /// None-delimited group +} + +/// A type-macro that expands to the name of the Rust type representation of a +/// given token. +/// +/// See the [token module] documentation for details and examples. +/// +/// [token module]: token/index.html +// Unfortunate duplication due to a rustdoc bug. +// https://github.com/rust-lang/rust/issues/45939 +#[macro_export] +#[cfg_attr(rustfmt, rustfmt_skip)] +macro_rules! Token { + (abstract) => { $crate::token::Abstract }; + (as) => { $crate::token::As }; + (async) => { $crate::token::Async }; + (auto) => { $crate::token::Auto }; + (become) => { $crate::token::Become }; + (box) => { $crate::token::Box }; + (break) => { $crate::token::Break }; + (const) => { $crate::token::Const }; + (continue) => { $crate::token::Continue }; + (crate) => { $crate::token::Crate }; + (default) => { $crate::token::Default }; + (do) => { $crate::token::Do }; + (dyn) => { $crate::token::Dyn }; + (else) => { $crate::token::Else }; + (enum) => { $crate::token::Enum }; + (existential) => { $crate::token::Existential }; + (extern) => { $crate::token::Extern }; + (final) => { $crate::token::Final }; + (fn) => { $crate::token::Fn }; + (for) => { $crate::token::For }; + (if) => { $crate::token::If }; + (impl) => { $crate::token::Impl }; + (in) => { $crate::token::In }; + (let) => { $crate::token::Let }; + (loop) => { $crate::token::Loop }; + (macro) => { $crate::token::Macro }; + (match) => { $crate::token::Match }; + (mod) => { $crate::token::Mod }; + (move) => { $crate::token::Move }; + (mut) => { $crate::token::Mut }; + (override) => { $crate::token::Override }; + (priv) => { $crate::token::Priv }; + (pub) => { $crate::token::Pub }; + (ref) => { $crate::token::Ref }; + (return) => { $crate::token::Return }; + (Self) => { $crate::token::SelfType }; + (self) => { $crate::token::SelfValue }; + (static) => { $crate::token::Static }; + (struct) => { $crate::token::Struct }; + (super) => { $crate::token::Super }; + (trait) => { $crate::token::Trait }; + (try) => { $crate::token::Try }; + (type) => { $crate::token::Type }; + (typeof) => { $crate::token::Typeof }; + (union) => { $crate::token::Union }; + (unsafe) => { $crate::token::Unsafe }; + (unsized) => { $crate::token::Unsized }; + (use) => { $crate::token::Use }; + (virtual) => { $crate::token::Virtual }; + (where) => { $crate::token::Where }; + (while) => { $crate::token::While }; + (yield) => { $crate::token::Yield }; + (+) => { $crate::token::Add }; + (+=) => { $crate::token::AddEq }; + (&) => { $crate::token::And }; + (&&) => { $crate::token::AndAnd }; + (&=) => { $crate::token::AndEq }; + (@) => { $crate::token::At }; + (!) => { $crate::token::Bang }; + (^) => { $crate::token::Caret }; + (^=) => { $crate::token::CaretEq }; + (:) => { $crate::token::Colon }; + (::) => { $crate::token::Colon2 }; + (,) => { $crate::token::Comma }; + (/) => { $crate::token::Div }; + (/=) => { $crate::token::DivEq }; + (.) => { $crate::token::Dot }; + (..) => { $crate::token::Dot2 }; + (...) => { $crate::token::Dot3 }; + (..=) => { $crate::token::DotDotEq }; + (=) => { $crate::token::Eq }; + (==) => { $crate::token::EqEq }; + (>=) => { $crate::token::Ge }; + (>) => { $crate::token::Gt }; + (<=) => { $crate::token::Le }; + (<) => { $crate::token::Lt }; + (*=) => { $crate::token::MulEq }; + (!=) => { $crate::token::Ne }; + (|) => { $crate::token::Or }; + (|=) => { $crate::token::OrEq }; + (||) => { $crate::token::OrOr }; + (#) => { $crate::token::Pound }; + (?) => { $crate::token::Question }; + (->) => { $crate::token::RArrow }; + (<-) => { $crate::token::LArrow }; + (%) => { $crate::token::Rem }; + (%=) => { $crate::token::RemEq }; + (=>) => { $crate::token::FatArrow }; + (;) => { $crate::token::Semi }; + (<<) => { $crate::token::Shl }; + (<<=) => { $crate::token::ShlEq }; + (>>) => { $crate::token::Shr }; + (>>=) => { $crate::token::ShrEq }; + (*) => { $crate::token::Star }; + (-) => { $crate::token::Sub }; + (-=) => { $crate::token::SubEq }; + (~) => { $crate::token::Tilde }; + (_) => { $crate::token::Underscore }; +} + +// Old names. TODO: remove these re-exports in a breaking change. +// https://github.com/dtolnay/syn/issues/486 +#[doc(hidden)] +pub use self::SelfType as CapSelf; +#[doc(hidden)] +pub use self::SelfValue as Self_; + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "parsing")] +pub mod parsing { + use proc_macro2::{Spacing, Span}; + + use buffer::Cursor; + use error::{Error, Result}; + use parse::ParseStream; + use span::FromSpans; + + pub fn keyword(input: ParseStream, token: &str) -> Result<Span> { + input.step(|cursor| { + if let Some((ident, rest)) = cursor.ident() { + if ident == token { + return Ok((ident.span(), rest)); + } + } + Err(cursor.error(format!("expected `{}`", token))) + }) + } + + pub fn peek_keyword(cursor: Cursor, token: &str) -> bool { + if let Some((ident, _rest)) = cursor.ident() { + ident == token + } else { + false + } + } + + pub fn punct<S: FromSpans>(input: ParseStream, token: &str) -> Result<S> { + let mut spans = [input.cursor().span(); 3]; + punct_helper(input, token, &mut spans)?; + Ok(S::from_spans(&spans)) + } + + fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span; 3]) -> Result<()> { + input.step(|cursor| { + let mut cursor = *cursor; + assert!(token.len() <= spans.len()); + + for (i, ch) in token.chars().enumerate() { + match cursor.punct() { + Some((punct, rest)) => { + spans[i] = punct.span(); + if punct.as_char() != ch { + break; + } else if i == token.len() - 1 { + return Ok(((), rest)); + } else if punct.spacing() != Spacing::Joint { + break; + } + cursor = rest; + } + None => break, + } + } + + Err(Error::new(spans[0], format!("expected `{}`", token))) + }) + } + + pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool { + for (i, ch) in token.chars().enumerate() { + match cursor.punct() { + Some((punct, rest)) => { + if punct.as_char() != ch { + break; + } else if i == token.len() - 1 { + return true; + } else if punct.spacing() != Spacing::Joint { + break; + } + cursor = rest; + } + None => break, + } + } + false + } +} + +// Not public API. +#[doc(hidden)] +#[cfg(feature = "printing")] +pub mod printing { + use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream}; + use quote::TokenStreamExt; + + pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) { + assert_eq!(s.len(), spans.len()); + + let mut chars = s.chars(); + let mut spans = spans.iter(); + let ch = chars.next_back().unwrap(); + let span = spans.next_back().unwrap(); + for (ch, span) in chars.zip(spans) { + let mut op = Punct::new(ch, Spacing::Joint); + op.set_span(*span); + tokens.append(op); + } + + let mut op = Punct::new(ch, Spacing::Alone); + op.set_span(*span); + tokens.append(op); + } + + pub fn keyword(s: &str, span: Span, tokens: &mut TokenStream) { + tokens.append(Ident::new(s, span)); + } + + pub fn delim<F>(s: &str, span: Span, tokens: &mut TokenStream, f: F) + where + F: FnOnce(&mut TokenStream), + { + let delim = match s { + "(" => Delimiter::Parenthesis, + "[" => Delimiter::Bracket, + "{" => Delimiter::Brace, + " " => Delimiter::None, + _ => panic!("unknown delimiter: {}", s), + }; + let mut inner = TokenStream::new(); + f(&mut inner); + let mut g = Group::new(delim, inner); + g.set_span(span); + tokens.append(g); + } +} diff --git a/syn/src/tt.rs b/syn/src/tt.rs new file mode 100644 index 000000000..72bc3c11e --- /dev/null +++ b/syn/src/tt.rs @@ -0,0 +1,110 @@ +use std::hash::{Hash, Hasher}; + +use proc_macro2::{Delimiter, TokenStream, TokenTree}; + +pub struct TokenTreeHelper<'a>(pub &'a TokenTree); + +impl<'a> PartialEq for TokenTreeHelper<'a> { + fn eq(&self, other: &Self) -> bool { + use proc_macro2::Spacing; + + match (self.0, other.0) { + (&TokenTree::Group(ref g1), &TokenTree::Group(ref g2)) => { + match (g1.delimiter(), g2.delimiter()) { + (Delimiter::Parenthesis, Delimiter::Parenthesis) + | (Delimiter::Brace, Delimiter::Brace) + | (Delimiter::Bracket, Delimiter::Bracket) + | (Delimiter::None, Delimiter::None) => {} + _ => return false, + } + + let s1 = g1.stream().clone().into_iter(); + let mut s2 = g2.stream().clone().into_iter(); + + for item1 in s1 { + let item2 = match s2.next() { + Some(item) => item, + None => return false, + }; + if TokenTreeHelper(&item1) != TokenTreeHelper(&item2) { + return false; + } + } + s2.next().is_none() + } + (&TokenTree::Punct(ref o1), &TokenTree::Punct(ref o2)) => { + o1.as_char() == o2.as_char() + && match (o1.spacing(), o2.spacing()) { + (Spacing::Alone, Spacing::Alone) | (Spacing::Joint, Spacing::Joint) => true, + _ => false, + } + } + (&TokenTree::Literal(ref l1), &TokenTree::Literal(ref l2)) => { + l1.to_string() == l2.to_string() + } + (&TokenTree::Ident(ref s1), &TokenTree::Ident(ref s2)) => s1 == s2, + _ => false, + } + } +} + +impl<'a> Hash for TokenTreeHelper<'a> { + fn hash<H: Hasher>(&self, h: &mut H) { + use proc_macro2::Spacing; + + match *self.0 { + TokenTree::Group(ref g) => { + 0u8.hash(h); + match g.delimiter() { + Delimiter::Parenthesis => 0u8.hash(h), + Delimiter::Brace => 1u8.hash(h), + Delimiter::Bracket => 2u8.hash(h), + Delimiter::None => 3u8.hash(h), + } + + for item in g.stream().clone() { + TokenTreeHelper(&item).hash(h); + } + 0xffu8.hash(h); // terminator w/ a variant we don't normally hash + } + TokenTree::Punct(ref op) => { + 1u8.hash(h); + op.as_char().hash(h); + match op.spacing() { + Spacing::Alone => 0u8.hash(h), + Spacing::Joint => 1u8.hash(h), + } + } + TokenTree::Literal(ref lit) => (2u8, lit.to_string()).hash(h), + TokenTree::Ident(ref word) => (3u8, word).hash(h), + } + } +} + +pub struct TokenStreamHelper<'a>(pub &'a TokenStream); + +impl<'a> PartialEq for TokenStreamHelper<'a> { + fn eq(&self, other: &Self) -> bool { + let left = self.0.clone().into_iter().collect::<Vec<_>>(); + let right = other.0.clone().into_iter().collect::<Vec<_>>(); + if left.len() != right.len() { + return false; + } + for (a, b) in left.into_iter().zip(right) { + if TokenTreeHelper(&a) != TokenTreeHelper(&b) { + return false; + } + } + true + } +} + +impl<'a> Hash for TokenStreamHelper<'a> { + fn hash<H: Hasher>(&self, state: &mut H) { + let tts = self.0.clone().into_iter().collect::<Vec<_>>(); + tts.len().hash(state); + for tt in tts { + TokenTreeHelper(&tt).hash(state); + } + } +} diff --git a/syn/src/ty.rs b/syn/src/ty.rs new file mode 100644 index 000000000..d4852f6be --- /dev/null +++ b/syn/src/ty.rs @@ -0,0 +1,994 @@ +use super::*; +use proc_macro2::TokenStream; +use punctuated::Punctuated; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; +#[cfg(feature = "extra-traits")] +use tt::TokenStreamHelper; + +ast_enum_of_structs! { + /// The possible types that a Rust value could have. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + /// + /// # Syntax tree enum + /// + /// This type is a [syntax tree enum]. + /// + /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + pub enum Type { + /// A dynamically sized slice type: `[T]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Slice(TypeSlice { + pub bracket_token: token::Bracket, + pub elem: Box<Type>, + }), + + /// A fixed size array type: `[T; n]`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Array(TypeArray { + pub bracket_token: token::Bracket, + pub elem: Box<Type>, + pub semi_token: Token![;], + pub len: Expr, + }), + + /// A raw pointer type: `*const T` or `*mut T`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Ptr(TypePtr { + pub star_token: Token![*], + pub const_token: Option<Token![const]>, + pub mutability: Option<Token![mut]>, + pub elem: Box<Type>, + }), + + /// A reference type: `&'a T` or `&'a mut T`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Reference(TypeReference { + pub and_token: Token![&], + pub lifetime: Option<Lifetime>, + pub mutability: Option<Token![mut]>, + pub elem: Box<Type>, + }), + + /// A bare function type: `fn(usize) -> bool`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub BareFn(TypeBareFn { + pub lifetimes: Option<BoundLifetimes>, + pub unsafety: Option<Token![unsafe]>, + pub abi: Option<Abi>, + pub fn_token: Token![fn], + pub paren_token: token::Paren, + pub inputs: Punctuated<BareFnArg, Token![,]>, + pub variadic: Option<Token![...]>, + pub output: ReturnType, + }), + + /// The never type: `!`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Never(TypeNever { + pub bang_token: Token![!], + }), + + /// A tuple type: `(A, B, C, String)`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Tuple(TypeTuple { + pub paren_token: token::Paren, + pub elems: Punctuated<Type, Token![,]>, + }), + + /// A path like `std::slice::Iter`, optionally qualified with a + /// self-type as in `<Vec<T> as SomeTrait>::Associated`. + /// + /// Type arguments are stored in the Path itself. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Path(TypePath { + pub qself: Option<QSelf>, + pub path: Path, + }), + + /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a + /// trait or a lifetime. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub TraitObject(TypeTraitObject { + pub dyn_token: Option<Token![dyn]>, + pub bounds: Punctuated<TypeParamBound, Token![+]>, + }), + + /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or + /// a lifetime. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub ImplTrait(TypeImplTrait { + pub impl_token: Token![impl], + pub bounds: Punctuated<TypeParamBound, Token![+]>, + }), + + /// A parenthesized type equivalent to the inner type. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Paren(TypeParen { + pub paren_token: token::Paren, + pub elem: Box<Type>, + }), + + /// A type contained within invisible delimiters. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Group(TypeGroup { + pub group_token: token::Group, + pub elem: Box<Type>, + }), + + /// Indication that a type should be inferred by the compiler: `_`. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Infer(TypeInfer { + pub underscore_token: Token![_], + }), + + /// A macro in the type position. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Macro(TypeMacro { + pub mac: Macro, + }), + + /// Tokens in type position not interpreted by Syn. + /// + /// *This type is available if Syn is built with the `"derive"` or + /// `"full"` feature.* + pub Verbatim(TypeVerbatim #manual_extra_traits { + pub tts: TokenStream, + }), + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for TypeVerbatim {} + +#[cfg(feature = "extra-traits")] +impl PartialEq for TypeVerbatim { + fn eq(&self, other: &Self) -> bool { + TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts) + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for TypeVerbatim { + fn hash<H>(&self, state: &mut H) + where + H: Hasher, + { + TokenStreamHelper(&self.tts).hash(state); + } +} + +ast_struct! { + /// The binary interface of a function: `extern "C"`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct Abi { + pub extern_token: Token![extern], + pub name: Option<LitStr>, + } +} + +ast_struct! { + /// An argument in a function type: the `usize` in `fn(usize) -> bool`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub struct BareFnArg { + pub name: Option<(BareFnArgName, Token![:])>, + pub ty: Type, + } +} + +ast_enum! { + /// Name of an argument in a function type: the `n` in `fn(n: usize)`. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum BareFnArgName { + /// Argument given a name. + Named(Ident), + /// Argument not given a name, matched with `_`. + Wild(Token![_]), + } +} + +ast_enum! { + /// Return type of a function signature. + /// + /// *This type is available if Syn is built with the `"derive"` or `"full"` + /// feature.* + pub enum ReturnType { + /// Return type is not specified. + /// + /// Functions default to `()` and closures default to type inference. + Default, + /// A particular type is returned. + Type(Token![->], Box<Type>), + } +} + +#[cfg(feature = "parsing")] +pub mod parsing { + use super::*; + + use parse::{Parse, ParseStream, Result}; + use path; + + impl Parse for Type { + fn parse(input: ParseStream) -> Result<Self> { + ambig_ty(input, true) + } + } + + impl Type { + /// In some positions, types may not contain the `+` character, to + /// disambiguate them. For example in the expression `1 as T`, T may not + /// contain a `+` character. + /// + /// This parser does not allow a `+`, while the default parser does. + pub fn without_plus(input: ParseStream) -> Result<Self> { + ambig_ty(input, false) + } + } + + fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> { + if input.peek(token::Group) { + return input.parse().map(Type::Group); + } + + let mut lifetimes = None::<BoundLifetimes>; + let mut lookahead = input.lookahead1(); + if lookahead.peek(Token![for]) { + lifetimes = input.parse()?; + lookahead = input.lookahead1(); + if !lookahead.peek(Ident) + && !lookahead.peek(Token![fn]) + && !lookahead.peek(Token![unsafe]) + && !lookahead.peek(Token![extern]) + && !lookahead.peek(Token![super]) + && !lookahead.peek(Token![self]) + && !lookahead.peek(Token![Self]) + && !lookahead.peek(Token![crate]) + { + return Err(lookahead.error()); + } + } + + if lookahead.peek(token::Paren) { + let content; + let paren_token = parenthesized!(content in input); + if content.is_empty() { + return Ok(Type::Tuple(TypeTuple { + paren_token: paren_token, + elems: Punctuated::new(), + })); + } + if content.peek(Lifetime) { + return Ok(Type::Paren(TypeParen { + paren_token: paren_token, + elem: Box::new(Type::TraitObject(content.parse()?)), + })); + } + if content.peek(Token![?]) { + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds: { + let mut bounds = Punctuated::new(); + bounds.push_value(TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + ..content.parse()? + })); + while let Some(plus) = input.parse()? { + bounds.push_punct(plus); + bounds.push_value(input.parse()?); + } + bounds + }, + })); + } + let first: Type = content.parse()?; + if content.peek(Token![,]) { + return Ok(Type::Tuple(TypeTuple { + paren_token: paren_token, + elems: { + let mut elems = Punctuated::new(); + elems.push_value(first); + elems.push_punct(content.parse()?); + let rest: Punctuated<Type, Token![,]> = + content.parse_terminated(Parse::parse)?; + elems.extend(rest); + elems + }, + })); + } + if allow_plus && input.peek(Token![+]) { + loop { + let first = match first { + Type::Path(TypePath { qself: None, path }) => { + TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + modifier: TraitBoundModifier::None, + lifetimes: None, + path: path, + }) + } + Type::TraitObject(TypeTraitObject { + dyn_token: None, + ref bounds, + }) => { + if bounds.len() > 1 || bounds.trailing_punct() { + break; + } + match first { + Type::TraitObject(TypeTraitObject { bounds, .. }) => { + match bounds.into_iter().next().unwrap() { + TypeParamBound::Trait(trait_bound) => { + TypeParamBound::Trait(TraitBound { + paren_token: Some(paren_token), + ..trait_bound + }) + } + other => other, + } + } + _ => unreachable!(), + } + } + _ => break, + }; + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds: { + let mut bounds = Punctuated::new(); + bounds.push_value(first); + while let Some(plus) = input.parse()? { + bounds.push_punct(plus); + bounds.push_value(input.parse()?); + } + bounds + }, + })); + } + } + Ok(Type::Paren(TypeParen { + paren_token: paren_token, + elem: Box::new(first), + })) + } else if lookahead.peek(Token![fn]) + || lookahead.peek(Token![unsafe]) + || lookahead.peek(Token![extern]) && !input.peek2(Token![::]) + { + let mut bare_fn: TypeBareFn = input.parse()?; + bare_fn.lifetimes = lifetimes; + Ok(Type::BareFn(bare_fn)) + } else if lookahead.peek(Ident) + || input.peek(Token![super]) + || input.peek(Token![self]) + || input.peek(Token![Self]) + || input.peek(Token![crate]) + || input.peek(Token![extern]) + || lookahead.peek(Token![::]) + || lookahead.peek(Token![<]) + { + if input.peek(Token![dyn]) { + let mut trait_object: TypeTraitObject = input.parse()?; + if lifetimes.is_some() { + match *trait_object.bounds.iter_mut().next().unwrap() { + TypeParamBound::Trait(ref mut trait_bound) => { + trait_bound.lifetimes = lifetimes; + } + TypeParamBound::Lifetime(_) => unreachable!(), + } + } + return Ok(Type::TraitObject(trait_object)); + } + + let ty: TypePath = input.parse()?; + if ty.qself.is_some() { + return Ok(Type::Path(ty)); + } + + if input.peek(Token![!]) && !input.peek(Token![!=]) { + let mut contains_arguments = false; + for segment in &ty.path.segments { + match segment.arguments { + PathArguments::None => {} + PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => { + contains_arguments = true; + } + } + } + + if !contains_arguments { + let bang_token: Token![!] = input.parse()?; + let (delimiter, tts) = mac::parse_delimiter(input)?; + return Ok(Type::Macro(TypeMacro { + mac: Macro { + path: ty.path, + bang_token: bang_token, + delimiter: delimiter, + tts: tts, + }, + })); + } + } + + if lifetimes.is_some() || allow_plus && input.peek(Token![+]) { + let mut bounds = Punctuated::new(); + bounds.push_value(TypeParamBound::Trait(TraitBound { + paren_token: None, + modifier: TraitBoundModifier::None, + lifetimes: lifetimes, + path: ty.path, + })); + if allow_plus { + while input.peek(Token![+]) { + bounds.push_punct(input.parse()?); + if input.peek(Token![>]) { + break; + } + bounds.push_value(input.parse()?); + } + } + return Ok(Type::TraitObject(TypeTraitObject { + dyn_token: None, + bounds: bounds, + })); + } + + Ok(Type::Path(ty)) + } else if lookahead.peek(token::Bracket) { + let content; + let bracket_token = bracketed!(content in input); + let elem: Type = content.parse()?; + if content.peek(Token![;]) { + Ok(Type::Array(TypeArray { + bracket_token: bracket_token, + elem: Box::new(elem), + semi_token: content.parse()?, + len: content.parse()?, + })) + } else { + Ok(Type::Slice(TypeSlice { + bracket_token: bracket_token, + elem: Box::new(elem), + })) + } + } else if lookahead.peek(Token![*]) { + input.parse().map(Type::Ptr) + } else if lookahead.peek(Token![&]) { + input.parse().map(Type::Reference) + } else if lookahead.peek(Token![!]) && !input.peek(Token![=]) { + input.parse().map(Type::Never) + } else if lookahead.peek(Token![impl]) { + input.parse().map(Type::ImplTrait) + } else if lookahead.peek(Token![_]) { + input.parse().map(Type::Infer) + } else if lookahead.peek(Lifetime) { + input.parse().map(Type::TraitObject) + } else { + Err(lookahead.error()) + } + } + + impl Parse for TypeSlice { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(TypeSlice { + bracket_token: bracketed!(content in input), + elem: content.parse()?, + }) + } + } + + impl Parse for TypeArray { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(TypeArray { + bracket_token: bracketed!(content in input), + elem: content.parse()?, + semi_token: content.parse()?, + len: content.parse()?, + }) + } + } + + impl Parse for TypePtr { + fn parse(input: ParseStream) -> Result<Self> { + let star_token: Token![*] = input.parse()?; + + let lookahead = input.lookahead1(); + let (const_token, mutability) = if lookahead.peek(Token![const]) { + (Some(input.parse()?), None) + } else if lookahead.peek(Token![mut]) { + (None, Some(input.parse()?)) + } else { + return Err(lookahead.error()); + }; + + Ok(TypePtr { + star_token: star_token, + const_token: const_token, + mutability: mutability, + elem: Box::new(input.call(Type::without_plus)?), + }) + } + } + + impl Parse for TypeReference { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeReference { + and_token: input.parse()?, + lifetime: input.parse()?, + mutability: input.parse()?, + // & binds tighter than +, so we don't allow + here. + elem: Box::new(input.call(Type::without_plus)?), + }) + } + } + + impl Parse for TypeBareFn { + fn parse(input: ParseStream) -> Result<Self> { + let args; + let allow_variadic; + Ok(TypeBareFn { + lifetimes: input.parse()?, + unsafety: input.parse()?, + abi: input.parse()?, + fn_token: input.parse()?, + paren_token: parenthesized!(args in input), + inputs: { + let mut inputs = Punctuated::new(); + while !args.is_empty() && !args.peek(Token![...]) { + inputs.push_value(args.parse()?); + if args.is_empty() { + break; + } + inputs.push_punct(args.parse()?); + } + allow_variadic = inputs.empty_or_trailing(); + inputs + }, + variadic: { + if allow_variadic && args.peek(Token![...]) { + Some(args.parse()?) + } else { + None + } + }, + output: input.call(ReturnType::without_plus)?, + }) + } + } + + impl Parse for TypeNever { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeNever { + bang_token: input.parse()?, + }) + } + } + + impl Parse for TypeInfer { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeInfer { + underscore_token: input.parse()?, + }) + } + } + + impl Parse for TypeTuple { + fn parse(input: ParseStream) -> Result<Self> { + let content; + Ok(TypeTuple { + paren_token: parenthesized!(content in input), + elems: content.parse_terminated(Type::parse)?, + }) + } + } + + impl Parse for TypeMacro { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeMacro { + mac: input.parse()?, + }) + } + } + + impl Parse for TypePath { + fn parse(input: ParseStream) -> Result<Self> { + let (qself, mut path) = path::parsing::qpath(input, false)?; + + if path.segments.last().unwrap().value().arguments.is_empty() + && input.peek(token::Paren) + { + let args: ParenthesizedGenericArguments = input.parse()?; + let parenthesized = PathArguments::Parenthesized(args); + path.segments.last_mut().unwrap().value_mut().arguments = parenthesized; + } + + Ok(TypePath { + qself: qself, + path: path, + }) + } + } + + impl ReturnType { + pub fn without_plus(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + + pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + if input.peek(Token![->]) { + let arrow = input.parse()?; + let ty = ambig_ty(input, allow_plus)?; + Ok(ReturnType::Type(arrow, Box::new(ty))) + } else { + Ok(ReturnType::Default) + } + } + } + + impl Parse for ReturnType { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, true) + } + } + + impl Parse for TypeTraitObject { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, true) + } + } + + fn at_least_one_type(bounds: &Punctuated<TypeParamBound, Token![+]>) -> bool { + for bound in bounds { + if let TypeParamBound::Trait(_) = *bound { + return true; + } + } + false + } + + impl TypeTraitObject { + pub fn without_plus(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + + // Only allow multiple trait references if allow_plus is true. + pub fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + Ok(TypeTraitObject { + dyn_token: input.parse()?, + bounds: { + let mut bounds = Punctuated::new(); + if allow_plus { + loop { + bounds.push_value(input.parse()?); + if !input.peek(Token![+]) { + break; + } + bounds.push_punct(input.parse()?); + if input.peek(Token![>]) { + break; + } + } + } else { + bounds.push_value(input.parse()?); + } + // Just lifetimes like `'a + 'b` is not a TraitObject. + if !at_least_one_type(&bounds) { + return Err(input.error("expected at least one type")); + } + bounds + }, + }) + } + } + + impl Parse for TypeImplTrait { + fn parse(input: ParseStream) -> Result<Self> { + Ok(TypeImplTrait { + impl_token: input.parse()?, + // NOTE: rust-lang/rust#34511 includes discussion about whether + // or not + should be allowed in ImplTrait directly without (). + bounds: { + let mut bounds = Punctuated::new(); + loop { + bounds.push_value(input.parse()?); + if !input.peek(Token![+]) { + break; + } + bounds.push_punct(input.parse()?); + } + bounds + }, + }) + } + } + + impl Parse for TypeGroup { + fn parse(input: ParseStream) -> Result<Self> { + let group = private::parse_group(input)?; + Ok(TypeGroup { + group_token: group.token, + elem: group.content.parse()?, + }) + } + } + + impl Parse for TypeParen { + fn parse(input: ParseStream) -> Result<Self> { + Self::parse(input, false) + } + } + + impl TypeParen { + fn parse(input: ParseStream, allow_plus: bool) -> Result<Self> { + let content; + Ok(TypeParen { + paren_token: parenthesized!(content in input), + elem: Box::new(ambig_ty(&content, allow_plus)?), + }) + } + } + + impl Parse for BareFnArg { + fn parse(input: ParseStream) -> Result<Self> { + Ok(BareFnArg { + name: { + if (input.peek(Ident) || input.peek(Token![_])) + && !input.peek2(Token![::]) + && input.peek2(Token![:]) + { + let name: BareFnArgName = input.parse()?; + let colon: Token![:] = input.parse()?; + Some((name, colon)) + } else { + None + } + }, + ty: input.parse()?, + }) + } + } + + impl Parse for BareFnArgName { + fn parse(input: ParseStream) -> Result<Self> { + let lookahead = input.lookahead1(); + if lookahead.peek(Ident) { + input.parse().map(BareFnArgName::Named) + } else if lookahead.peek(Token![_]) { + input.parse().map(BareFnArgName::Wild) + } else { + Err(lookahead.error()) + } + } + } + + impl Parse for Abi { + fn parse(input: ParseStream) -> Result<Self> { + Ok(Abi { + extern_token: input.parse()?, + name: input.parse()?, + }) + } + } + + impl Parse for Option<Abi> { + fn parse(input: ParseStream) -> Result<Self> { + if input.peek(Token![extern]) { + input.parse().map(Some) + } else { + Ok(None) + } + } + } +} + +#[cfg(feature = "printing")] +mod printing { + use super::*; + + use proc_macro2::TokenStream; + use quote::ToTokens; + + use print::TokensOrDefault; + + impl ToTokens for TypeSlice { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bracket_token.surround(tokens, |tokens| { + self.elem.to_tokens(tokens); + }); + } + } + + impl ToTokens for TypeArray { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bracket_token.surround(tokens, |tokens| { + self.elem.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + self.len.to_tokens(tokens); + }); + } + } + + impl ToTokens for TypePtr { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.star_token.to_tokens(tokens); + match self.mutability { + Some(ref tok) => tok.to_tokens(tokens), + None => { + TokensOrDefault(&self.const_token).to_tokens(tokens); + } + } + self.elem.to_tokens(tokens); + } + } + + impl ToTokens for TypeReference { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.and_token.to_tokens(tokens); + self.lifetime.to_tokens(tokens); + self.mutability.to_tokens(tokens); + self.elem.to_tokens(tokens); + } + } + + impl ToTokens for TypeBareFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.lifetimes.to_tokens(tokens); + self.unsafety.to_tokens(tokens); + self.abi.to_tokens(tokens); + self.fn_token.to_tokens(tokens); + self.paren_token.surround(tokens, |tokens| { + self.inputs.to_tokens(tokens); + if let Some(ref variadic) = self.variadic { + if !self.inputs.empty_or_trailing() { + let span = variadic.spans[0]; + Token![,](span).to_tokens(tokens); + } + variadic.to_tokens(tokens); + } + }); + self.output.to_tokens(tokens); + } + } + + impl ToTokens for TypeNever { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bang_token.to_tokens(tokens); + } + } + + impl ToTokens for TypeTuple { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.elems.to_tokens(tokens); + }); + } + } + + impl ToTokens for TypePath { + fn to_tokens(&self, tokens: &mut TokenStream) { + private::print_path(tokens, &self.qself, &self.path); + } + } + + impl ToTokens for TypeTraitObject { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.dyn_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + + impl ToTokens for TypeImplTrait { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.impl_token.to_tokens(tokens); + self.bounds.to_tokens(tokens); + } + } + + impl ToTokens for TypeGroup { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.group_token.surround(tokens, |tokens| { + self.elem.to_tokens(tokens); + }); + } + } + + impl ToTokens for TypeParen { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| { + self.elem.to_tokens(tokens); + }); + } + } + + impl ToTokens for TypeInfer { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.underscore_token.to_tokens(tokens); + } + } + + impl ToTokens for TypeMacro { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.mac.to_tokens(tokens); + } + } + + impl ToTokens for TypeVerbatim { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.tts.to_tokens(tokens); + } + } + + impl ToTokens for ReturnType { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + ReturnType::Default => {} + ReturnType::Type(ref arrow, ref ty) => { + arrow.to_tokens(tokens); + ty.to_tokens(tokens); + } + } + } + } + + impl ToTokens for BareFnArg { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some((ref name, ref colon)) = self.name { + name.to_tokens(tokens); + colon.to_tokens(tokens); + } + self.ty.to_tokens(tokens); + } + } + + impl ToTokens for BareFnArgName { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + BareFnArgName::Named(ref t) => t.to_tokens(tokens), + BareFnArgName::Wild(ref t) => t.to_tokens(tokens), + } + } + } + + impl ToTokens for Abi { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.extern_token.to_tokens(tokens); + self.name.to_tokens(tokens); + } + } +} diff --git a/synstructure/.cargo-checksum.json b/synstructure/.cargo-checksum.json new file mode 100644 index 000000000..8ded0b2b6 --- /dev/null +++ b/synstructure/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"} \ No newline at end of file diff --git a/synstructure/Cargo.toml b/synstructure/Cargo.toml new file mode 100644 index 000000000..b1a6899df --- /dev/null +++ b/synstructure/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "synstructure" +version = "0.10.2" +authors = ["Nika Layzell <nika@thelayzells.com>"] +include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"] +description = "Helper methods and macros for custom derives" +documentation = "https://docs.rs/synstructure" +readme = "README.md" +keywords = ["syn", "macros", "derive", "expand_substructure", "enum"] +license = "MIT" +repository = "https://github.com/mystor/synstructure" +[dependencies.proc-macro2] +version = "0.4" + +[dependencies.quote] +version = "0.6" + +[dependencies.syn] +version = "0.15" +features = ["visit", "extra-traits"] + +[dependencies.unicode-xid] +version = "0.1" +[dev-dependencies.synstructure_test_traits] +version = "0.1" + +[features] +simple-derive = [] diff --git a/synstructure/LICENSE b/synstructure/LICENSE new file mode 100644 index 000000000..f78f1c15d --- /dev/null +++ b/synstructure/LICENSE @@ -0,0 +1,7 @@ +Copyright 2016 Nika Layzell + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/synstructure/README.md b/synstructure/README.md new file mode 100644 index 000000000..65dca6ba4 --- /dev/null +++ b/synstructure/README.md @@ -0,0 +1,159 @@ +# synstructure + +[![Latest Version](https://img.shields.io/crates/v/synstructure.svg)](https://crates.io/crates/synstructure) +[![Documentation](https://docs.rs/synstructure/badge.svg)](https://docs.rs/synstructure) +[![Build Status](https://travis-ci.org/mystor/synstructure.svg?branch=master)](https://travis-ci.org/mystor/synstructure) +[![Rustc Version 1.15+](https://img.shields.io/badge/rustc-1.15+-lightgray.svg)](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html) + +> NOTE: What follows is an exerpt from the module level documentation. For full +> details read the docs on [docs.rs](https://docs.rs/synstructure/) + +This crate provides helper types for matching against enum variants, and +extracting bindings to each of the fields in the deriving Struct or Enum in +a generic way. + +If you are writing a `#[derive]` which needs to perform some operation on +every field, then you have come to the right place! + +# Example: `WalkFields` +### Trait Implementation +```rust +pub trait WalkFields: std::any::Any { + fn walk_fields(&self, walk: &mut FnMut(&WalkFields)); +} +impl WalkFields for i32 { + fn walk_fields(&self, _walk: &mut FnMut(&WalkFields)) {} +} +``` + +### Custom Derive +```rust +#[macro_use] +extern crate synstructure; +#[macro_use] +extern crate quote; +extern crate proc_macro2; + +fn walkfields_derive(s: synstructure::Structure) -> proc_macro2::TokenStream { + let body = s.each(|bi| quote!{ + walk(#bi) + }); + + s.bound_impl(quote!(example_traits::WalkFields), quote!{ + fn walk_fields(&self, walk: &mut FnMut(&example_traits::WalkFields)) { + match *self { #body } + } + }) +} +decl_derive!([WalkFields] => walkfields_derive); + +/* + * Test Case + */ +fn main() { + test_derive! { + walkfields_derive { + enum A<T> { + B(i32, T), + C(i32), + } + } + expands to { + #[allow(non_upper_case_globals)] + const _DERIVE_example_traits_WalkFields_FOR_A: () = { + extern crate example_traits; + impl<T> example_traits::WalkFields for A<T> + where T: example_traits::WalkFields + { + fn walk_fields(&self, walk: &mut FnMut(&example_traits::WalkFields)) { + match *self { + A::B(ref __binding_0, ref __binding_1,) => { + { walk(__binding_0) } + { walk(__binding_1) } + } + A::C(ref __binding_0,) => { + { walk(__binding_0) } + } + } + } + } + }; + } + } +} +``` + +# Example: `Interest` +### Trait Implementation +```rust +pub trait Interest { + fn interesting(&self) -> bool; +} +impl Interest for i32 { + fn interesting(&self) -> bool { *self > 0 } +} +``` + +### Custom Derive +```rust +#[macro_use] +extern crate synstructure; +#[macro_use] +extern crate quote; +extern crate proc_macro2; + +fn interest_derive(mut s: synstructure::Structure) -> proc_macro2::TokenStream { + let body = s.fold(false, |acc, bi| quote!{ + #acc || example_traits::Interest::interesting(#bi) + }); + + s.bound_impl(quote!(example_traits::Interest), quote!{ + fn interesting(&self) -> bool { + match *self { + #body + } + } + }) +} +decl_derive!([Interest] => interest_derive); + +/* + * Test Case + */ +fn main() { + test_derive!{ + interest_derive { + enum A<T> { + B(i32, T), + C(i32), + } + } + expands to { + #[allow(non_upper_case_globals)] + const _DERIVE_example_traits_Interest_FOR_A: () = { + extern crate example_traits; + impl<T> example_traits::Interest for A<T> + where T: example_traits::Interest + { + fn interesting(&self) -> bool { + match *self { + A::B(ref __binding_0, ref __binding_1,) => { + false || + example_traits::Interest::interesting(__binding_0) || + example_traits::Interest::interesting(__binding_1) + } + A::C(ref __binding_0,) => { + false || + example_traits::Interest::interesting(__binding_0) + } + } + } + } + }; + } + } +} +``` + +For more example usage, consider investigating the `abomonation_derive` crate, +which makes use of this crate, and is fairly simple. diff --git a/synstructure/src/lib.rs b/synstructure/src/lib.rs new file mode 100644 index 000000000..bcb5d4019 --- /dev/null +++ b/synstructure/src/lib.rs @@ -0,0 +1,2301 @@ +//! This crate provides helper types for matching against enum variants, and +//! extracting bindings to each of the fields in the deriving Struct or Enum in +//! a generic way. +//! +//! If you are writing a `#[derive]` which needs to perform some operation on +//! every field, then you have come to the right place! +//! +//! # Example: `WalkFields` +//! ### Trait Implementation +//! ``` +//! pub trait WalkFields: std::any::Any { +//! fn walk_fields(&self, walk: &mut FnMut(&WalkFields)); +//! } +//! impl WalkFields for i32 { +//! fn walk_fields(&self, _walk: &mut FnMut(&WalkFields)) {} +//! } +//! ``` +//! +//! ### Custom Derive +//! ``` +//! #[macro_use] +//! extern crate synstructure; +//! #[macro_use] +//! extern crate quote; +//! extern crate proc_macro2; +//! +//! fn walkfields_derive(s: synstructure::Structure) -> proc_macro2::TokenStream { +//! let body = s.each(|bi| quote!{ +//! walk(#bi) +//! }); +//! +//! s.gen_impl(quote! { +//! extern crate synstructure_test_traits; +//! +//! gen impl synstructure_test_traits::WalkFields for @Self { +//! fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) { +//! match *self { #body } +//! } +//! } +//! }) +//! } +//! # const _IGNORE: &'static str = stringify!( +//! decl_derive!([WalkFields] => walkfields_derive); +//! # ); +//! +//! /* +//! * Test Case +//! */ +//! fn main() { +//! test_derive! { +//! walkfields_derive { +//! enum A<T> { +//! B(i32, T), +//! C(i32), +//! } +//! } +//! expands to { +//! #[allow(non_upper_case_globals)] +//! const _DERIVE_synstructure_test_traits_WalkFields_FOR_A: () = { +//! extern crate synstructure_test_traits; +//! impl<T> synstructure_test_traits::WalkFields for A<T> +//! where T: synstructure_test_traits::WalkFields +//! { +//! fn walk_fields(&self, walk: &mut FnMut(&synstructure_test_traits::WalkFields)) { +//! match *self { +//! A::B(ref __binding_0, ref __binding_1,) => { +//! { walk(__binding_0) } +//! { walk(__binding_1) } +//! } +//! A::C(ref __binding_0,) => { +//! { walk(__binding_0) } +//! } +//! } +//! } +//! } +//! }; +//! } +//! } +//! } +//! ``` +//! +//! # Example: `Interest` +//! ### Trait Implementation +//! ``` +//! pub trait Interest { +//! fn interesting(&self) -> bool; +//! } +//! impl Interest for i32 { +//! fn interesting(&self) -> bool { *self > 0 } +//! } +//! ``` +//! +//! ### Custom Derive +//! ``` +//! #[macro_use] +//! extern crate synstructure; +//! #[macro_use] +//! extern crate quote; +//! extern crate proc_macro2; +//! +//! fn interest_derive(mut s: synstructure::Structure) -> proc_macro2::TokenStream { +//! let body = s.fold(false, |acc, bi| quote!{ +//! #acc || synstructure_test_traits::Interest::interesting(#bi) +//! }); +//! +//! s.gen_impl(quote! { +//! extern crate synstructure_test_traits; +//! gen impl synstructure_test_traits::Interest for @Self { +//! fn interesting(&self) -> bool { +//! match *self { +//! #body +//! } +//! } +//! } +//! }) +//! } +//! # const _IGNORE: &'static str = stringify!( +//! decl_derive!([Interest] => interest_derive); +//! # ); +//! +//! /* +//! * Test Case +//! */ +//! fn main() { +//! test_derive!{ +//! interest_derive { +//! enum A<T> { +//! B(i32, T), +//! C(i32), +//! } +//! } +//! expands to { +//! #[allow(non_upper_case_globals)] +//! const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = { +//! extern crate synstructure_test_traits; +//! impl<T> synstructure_test_traits::Interest for A<T> +//! where T: synstructure_test_traits::Interest +//! { +//! fn interesting(&self) -> bool { +//! match *self { +//! A::B(ref __binding_0, ref __binding_1,) => { +//! false || +//! synstructure_test_traits::Interest::interesting(__binding_0) || +//! synstructure_test_traits::Interest::interesting(__binding_1) +//! } +//! A::C(ref __binding_0,) => { +//! false || +//! synstructure_test_traits::Interest::interesting(__binding_0) +//! } +//! } +//! } +//! } +//! }; +//! } +//! } +//! } +//! ``` +//! +//! For more example usage, consider investigating the `abomonation_derive` crate, +//! which makes use of this crate, and is fairly simple. + +extern crate proc_macro; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +#[macro_use] +extern crate syn; +extern crate unicode_xid; + +use std::collections::HashSet; + +use syn::visit::{self, Visit}; +use syn::{ + punctuated, token, Attribute, Data, DeriveInput, Expr, Field, Fields, FieldsNamed, + FieldsUnnamed, GenericParam, Generics, Ident, PredicateType, TraitBound, Type, TypeMacro, + TypeParamBound, TypePath, WhereClause, WherePredicate, +}; + +// re-export the quote! macro so we can depend on it being around in our macro's +// implementations. +use proc_macro2::{TokenStream, TokenTree}; +#[doc(hidden)] +pub use quote::*; + +use unicode_xid::UnicodeXID; + +use proc_macro2::Span; + +// NOTE: This module has documentation hidden, as it only exports macros (which +// always appear in the root of the crate) and helper methods / re-exports used +// in the implementation of those macros. +#[doc(hidden)] +pub mod macros; + +/// Changes how bounds are added +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum AddBounds { + /// Add for fields and generics + Both, + /// Fields only + Fields, + /// Generics only + Generics, + /// None + None, + #[doc(hidden)] + __Nonexhaustive, +} + +/// The type of binding to use when generating a pattern. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum BindStyle { + /// `x` + Move, + /// `mut x` + MoveMut, + /// `ref x` + Ref, + /// `ref mut x` + RefMut, +} + +impl ToTokens for BindStyle { + fn to_tokens(&self, tokens: &mut TokenStream) { + match *self { + BindStyle::Move => {} + BindStyle::MoveMut => quote_spanned!(Span::call_site() => mut).to_tokens(tokens), + BindStyle::Ref => quote_spanned!(Span::call_site() => ref).to_tokens(tokens), + BindStyle::RefMut => quote_spanned!(Span::call_site() => ref mut).to_tokens(tokens), + } + } +} + +// Internal method for merging seen_generics arrays together. +fn generics_fuse(res: &mut Vec<bool>, new: &[bool]) { + for (i, &flag) in new.iter().enumerate() { + if i == res.len() { + res.push(false); + } + if flag { + res[i] = true; + } + } +} + +// Internal method for extracting the set of generics which have been matched. +fn fetch_generics<'a>(set: &[bool], generics: &'a Generics) -> Vec<&'a Ident> { + let mut tys = vec![]; + for (&seen, param) in set.iter().zip(generics.params.iter()) { + if seen { + match *param { + GenericParam::Type(ref tparam) => tys.push(&tparam.ident), + _ => {} + } + } + } + tys +} + +// Internal method for sanitizing an identifier for hygiene purposes. +fn sanitize_ident(s: &str) -> Ident { + let mut res = String::with_capacity(s.len()); + for mut c in s.chars() { + if !UnicodeXID::is_xid_continue(c) { + c = '_' + } + // Deduplicate consecutive _ characters. + if res.ends_with('_') && c == '_' { + continue; + } + res.push(c); + } + Ident::new(&res, Span::call_site()) +} + +// Internal method to merge two Generics objects together intelligently. +fn merge_generics(into: &mut Generics, from: &Generics) { + // Try to add the param into `into`, and merge parmas with identical names. + 'outer: for p in &from.params { + for op in &into.params { + match (op, p) { + (&GenericParam::Type(ref otp), &GenericParam::Type(ref tp)) => { + // NOTE: This is only OK because syn ignores the span for equality purposes. + if otp.ident == tp.ident { + panic!( + "Attempted to merge conflicting generic params: {} and {}", + quote! {#op}, + quote! {#p} + ); + } + } + (&GenericParam::Lifetime(ref olp), &GenericParam::Lifetime(ref lp)) => { + // NOTE: This is only OK because syn ignores the span for equality purposes. + if olp.lifetime == lp.lifetime { + panic!( + "Attempted to merge conflicting generic params: {} and {}", + quote! {#op}, + quote! {#p} + ); + } + } + // We don't support merging Const parameters, because that wouldn't make much sense. + _ => (), + } + } + into.params.push(p.clone()); + } + + // Add any where clauses from the input generics object. + if let Some(ref from_clause) = from.where_clause { + into.make_where_clause() + .predicates + .extend(from_clause.predicates.iter().cloned()); + } +} + +/// Information about a specific binding. This contains both an `Ident` +/// reference to the given field, and the syn `&'a Field` descriptor for that +/// field. +/// +/// This type supports `quote::ToTokens`, so can be directly used within the +/// `quote!` macro. It expands to a reference to the matched field. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct BindingInfo<'a> { + /// The name which this BindingInfo will bind to. + pub binding: Ident, + + /// The type of binding which this BindingInfo will create. + pub style: BindStyle, + + field: &'a Field, + + // These are used to determine which type parameters are avaliable. + generics: &'a Generics, + seen_generics: Vec<bool>, +} + +impl<'a> ToTokens for BindingInfo<'a> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.binding.to_tokens(tokens); + } +} + +impl<'a> BindingInfo<'a> { + /// Returns a reference to the underlying `syn` AST node which this + /// `BindingInfo` references + pub fn ast(&self) -> &'a Field { + self.field + } + + /// Generates the pattern fragment for this field binding. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B{ a: i32, b: i32 }, + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].bindings()[0].pat().to_string(), + /// quote! { + /// ref __binding_0 + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn pat(&self) -> TokenStream { + let BindingInfo { + ref binding, + ref style, + .. + } = *self; + quote!(#style #binding) + } + + /// Returns a list of the type parameters which are referenced in this + /// field's type. + /// + /// # Caveat + /// + /// If the field contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # extern crate proc_macro2; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// struct A<T, U> { + /// a: Option<T>, + /// b: U, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].bindings()[0].referenced_ty_params(), + /// &[&(syn::Ident::new("T", proc_macro2::Span::call_site()))] + /// ); + /// # } + /// ``` + pub fn referenced_ty_params(&self) -> Vec<&'a Ident> { + fetch_generics(&self.seen_generics, self.generics) + } +} + +/// This type is similar to `syn`'s `Variant` type, however each of the fields +/// are references rather than owned. When this is used as the AST for a real +/// variant, this struct simply borrows the fields of the `syn::Variant`, +/// however this type may also be used as the sole variant for a struct. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct VariantAst<'a> { + pub attrs: &'a [Attribute], + pub ident: &'a Ident, + pub fields: &'a Fields, + pub discriminant: &'a Option<(token::Eq, Expr)>, +} + +/// A wrapper around a `syn::DeriveInput`'s variant which provides utilities +/// for destructuring `Variant`s with `match` expressions. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct VariantInfo<'a> { + pub prefix: Option<&'a Ident>, + bindings: Vec<BindingInfo<'a>>, + omitted_fields: bool, + ast: VariantAst<'a>, + generics: &'a Generics, +} + +/// Helper function used by the VariantInfo constructor. Walks all of the types +/// in `field` and returns a list of the type parameters from `ty_params` which +/// are referenced in the field. +fn get_ty_params<'a>(field: &Field, generics: &Generics) -> Vec<bool> { + // Helper type. Discovers all identifiers inside of the visited type, + // and calls a callback with them. + struct BoundTypeLocator<'a> { + result: Vec<bool>, + generics: &'a Generics, + } + + impl<'a> Visit<'a> for BoundTypeLocator<'a> { + // XXX: This also (intentionally) captures paths like T::SomeType. Is + // this desirable? + fn visit_ident(&mut self, id: &Ident) { + for (idx, i) in self.generics.params.iter().enumerate() { + if let GenericParam::Type(ref tparam) = *i { + if tparam.ident == *id { + self.result[idx] = true; + } + } + } + } + + fn visit_type_macro(&mut self, x: &'a TypeMacro) { + // If we see a type_mac declaration, then we can't know what type parameters + // it might be binding, so we presume it binds all of them. + for r in &mut self.result { + *r = true; + } + visit::visit_type_macro(self, x) + } + } + + let mut btl = BoundTypeLocator { + result: vec![false; generics.params.len()], + generics: generics, + }; + + btl.visit_type(&field.ty); + + btl.result +} + +impl<'a> VariantInfo<'a> { + fn new(ast: VariantAst<'a>, prefix: Option<&'a Ident>, generics: &'a Generics) -> Self { + let bindings = match *ast.fields { + Fields::Unit => vec![], + Fields::Unnamed(FieldsUnnamed { + unnamed: ref fields, + .. + }) + | Fields::Named(FieldsNamed { + named: ref fields, .. + }) => { + fields + .into_iter() + .enumerate() + .map(|(i, field)| { + BindingInfo { + // XXX: This has to be call_site to avoid privacy + // when deriving on private fields. + binding: Ident::new(&format!("__binding_{}", i), Span::call_site()), + style: BindStyle::Ref, + field: field, + generics: generics, + seen_generics: get_ty_params(field, generics), + } + }) + .collect::<Vec<_>>() + } + }; + + VariantInfo { + prefix: prefix, + bindings: bindings, + omitted_fields: false, + ast: ast, + generics: generics, + } + } + + /// Returns a slice of the bindings in this Variant. + pub fn bindings(&self) -> &[BindingInfo<'a>] { + &self.bindings + } + + /// Returns a mut slice of the bindings in this Variant. + pub fn bindings_mut(&mut self) -> &mut [BindingInfo<'a>] { + &mut self.bindings + } + + /// Returns a `VariantAst` object which contains references to the + /// underlying `syn` AST node which this `Variant` was created from. + pub fn ast(&self) -> VariantAst<'a> { + self.ast + } + + /// True if any bindings were omitted due to a `filter` call. + pub fn omitted_bindings(&self) -> bool { + self.omitted_fields + } + + /// Generates the match-arm pattern which could be used to match against this Variant. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].pat().to_string(), + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn pat(&self) -> TokenStream { + let mut t = TokenStream::new(); + if let Some(prefix) = self.prefix { + prefix.to_tokens(&mut t); + quote!(::).to_tokens(&mut t); + } + self.ast.ident.to_tokens(&mut t); + match *self.ast.fields { + Fields::Unit => { + assert!(self.bindings.len() == 0); + } + Fields::Unnamed(..) => token::Paren(Span::call_site()).surround(&mut t, |t| { + for binding in &self.bindings { + binding.pat().to_tokens(t); + quote!(,).to_tokens(t); + } + if self.omitted_fields { + quote!(..).to_tokens(t); + } + }), + Fields::Named(..) => token::Brace(Span::call_site()).surround(&mut t, |t| { + for binding in &self.bindings { + binding.field.ident.to_tokens(t); + quote!(:).to_tokens(t); + binding.pat().to_tokens(t); + quote!(,).to_tokens(t); + } + if self.omitted_fields { + quote!(..).to_tokens(t); + } + }), + } + t + } + + /// Generates the token stream required to construct the current variant. + /// + /// The init array initializes each of the fields in the order they are + /// written in `variant.ast().fields`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(usize, usize), + /// C{ v: usize }, + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].construct(|_, i| quote!(#i)).to_string(), + /// + /// quote!{ + /// A::B(0usize, 1usize,) + /// }.to_string() + /// ); + /// + /// assert_eq!( + /// s.variants()[1].construct(|_, i| quote!(#i)).to_string(), + /// + /// quote!{ + /// A::C{ v: 0usize, } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn construct<F, T>(&self, mut func: F) -> TokenStream + where + F: FnMut(&Field, usize) -> T, + T: ToTokens, + { + let mut t = TokenStream::new(); + if let Some(prefix) = self.prefix { + quote!(#prefix ::).to_tokens(&mut t); + } + self.ast.ident.to_tokens(&mut t); + + match *self.ast.fields { + Fields::Unit => (), + Fields::Unnamed(FieldsUnnamed { ref unnamed, .. }) => { + token::Paren::default().surround(&mut t, |t| { + for (i, field) in unnamed.into_iter().enumerate() { + func(field, i).to_tokens(t); + quote!(,).to_tokens(t); + } + }) + } + Fields::Named(FieldsNamed { ref named, .. }) => { + token::Brace::default().surround(&mut t, |t| { + for (i, field) in named.into_iter().enumerate() { + field.ident.to_tokens(t); + quote!(:).to_tokens(t); + func(field, i).to_tokens(t); + quote!(,).to_tokens(t); + } + }) + } + } + t + } + + /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`. + /// and generating a `match` arm which evaluates the returned tokens. + /// + /// This method will ignore fields which are ignored through the `filter` + /// method. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) => { + /// { println!("{:?}", __binding_0) } + /// { println!("{:?}", __binding_1) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn each<F, R>(&self, mut f: F) -> TokenStream + where + F: FnMut(&BindingInfo) -> R, + R: ToTokens, + { + let pat = self.pat(); + let mut body = TokenStream::new(); + for binding in &self.bindings { + token::Brace::default().surround(&mut body, |body| { + f(binding).to_tokens(body); + }); + } + quote!(#pat => { #body }) + } + + /// Runs the passed-in function once for each bound field, passing in the + /// result of the previous call, and a `BindingInfo`. generating a `match` + /// arm which evaluates to the resulting tokens. + /// + /// This method will ignore fields which are ignored through the `filter` + /// method. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].fold(quote!(0), |acc, bi| quote!(#acc + #bi)).to_string(), + /// + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) => { + /// 0 + __binding_0 + __binding_1 + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream + where + F: FnMut(TokenStream, &BindingInfo) -> R, + I: ToTokens, + R: ToTokens, + { + let pat = self.pat(); + let body = self.bindings.iter().fold(quote!(#init), |i, bi| { + let r = f(i, bi); + quote!(#r) + }); + quote!(#pat => { #body }) + } + + /// Filter the bindings created by this `Variant` object. This has 2 effects: + /// + /// * The bindings will no longer appear in match arms generated by methods + /// on this `Variant` or its subobjects. + /// + /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl` + /// method only consider type parameters referenced in the types of + /// non-filtered fields. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # extern crate proc_macro2; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B{ a: i32, b: i32 }, + /// C{ a: u32 }, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.variants_mut()[0].filter(|bi| { + /// bi.ast().ident == Some(syn::Ident::new("b", proc_macro2::Span::call_site())) + /// }); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B{ b: ref __binding_1, .. } => { + /// { println!("{:?}", __binding_1) } + /// } + /// A::C{ a: ref __binding_0, } => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn filter<F>(&mut self, f: F) -> &mut Self + where + F: FnMut(&BindingInfo) -> bool, + { + let before_len = self.bindings.len(); + self.bindings.retain(f); + if self.bindings.len() != before_len { + self.omitted_fields = true; + } + self + } + + /// Remove the binding at the given index. + /// + /// # Panics + /// + /// Panics if the index is out of range. + pub fn remove_binding(&mut self, idx: usize) -> &mut Self { + self.bindings.remove(idx); + self.omitted_fields = true; + self + } + + /// Updates the `BindStyle` for each of the passed-in fields by calling the + /// passed-in function for each `BindingInfo`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.variants_mut()[0].bind_with(|bi| BindStyle::RefMut); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B(ref mut __binding_0, ref mut __binding_1,) => { + /// { println!("{:?}", __binding_0) } + /// { println!("{:?}", __binding_1) } + /// } + /// A::C(ref __binding_0,) => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self + where + F: FnMut(&BindingInfo) -> BindStyle, + { + for binding in &mut self.bindings { + binding.style = f(&binding); + } + self + } + + /// Updates the binding name for each fo the passed-in fields by calling the + /// passed-in function for each `BindingInfo`. + /// + /// The function will be called with the `BindingInfo` and its index in the + /// enclosing variant. + /// + /// The default name is `__binding_{}` where `{}` is replaced with an + /// increasing number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B{ a: i32, b: i32 }, + /// C{ a: u32 }, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.variants_mut()[0].binding_name(|bi, i| bi.ident.clone().unwrap()); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B{ a: ref a, b: ref b, } => { + /// { println!("{:?}", a) } + /// { println!("{:?}", b) } + /// } + /// A::C{ a: ref __binding_0, } => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self + where + F: FnMut(&Field, usize) -> Ident, + { + for (it, binding) in self.bindings.iter_mut().enumerate() { + binding.binding = f(binding.field, it); + } + self + } + + /// Returns a list of the type parameters which are referenced in this + /// field's type. + /// + /// # Caveat + /// + /// If the field contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # extern crate proc_macro2; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// struct A<T, U> { + /// a: Option<T>, + /// b: U, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// assert_eq!( + /// s.variants()[0].bindings()[0].referenced_ty_params(), + /// &[&(syn::Ident::new("T", proc_macro2::Span::call_site()))] + /// ); + /// # } + /// ``` + pub fn referenced_ty_params(&self) -> Vec<&'a Ident> { + let mut flags = Vec::new(); + for binding in &self.bindings { + generics_fuse(&mut flags, &binding.seen_generics); + } + fetch_generics(&flags, self.generics) + } +} + +/// A wrapper around a `syn::DeriveInput` which provides utilities for creating +/// custom derive trait implementations. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Structure<'a> { + variants: Vec<VariantInfo<'a>>, + omitted_variants: bool, + ast: &'a DeriveInput, + extra_impl: Vec<GenericParam>, + add_bounds: AddBounds, +} + +impl<'a> Structure<'a> { + /// Create a new `Structure` with the variants and fields from the passed-in + /// `DeriveInput`. + pub fn new(ast: &'a DeriveInput) -> Self { + let variants = match ast.data { + Data::Enum(ref data) => (&data.variants) + .into_iter() + .map(|v| { + VariantInfo::new( + VariantAst { + attrs: &v.attrs, + ident: &v.ident, + fields: &v.fields, + discriminant: &v.discriminant, + }, + Some(&ast.ident), + &ast.generics, + ) + }) + .collect::<Vec<_>>(), + Data::Struct(ref data) => { + // SAFETY NOTE: Normally putting an `Expr` in static storage + // wouldn't be safe, because it could contain `Term` objects + // which use thread-local interning. However, this static always + // contains the value `None`. Thus, it will never contain any + // unsafe values. + struct UnsafeMakeSync(Option<(token::Eq, Expr)>); + unsafe impl Sync for UnsafeMakeSync {} + static NONE_DISCRIMINANT: UnsafeMakeSync = UnsafeMakeSync(None); + + vec![VariantInfo::new( + VariantAst { + attrs: &ast.attrs, + ident: &ast.ident, + fields: &data.fields, + discriminant: &NONE_DISCRIMINANT.0, + }, + None, + &ast.generics, + )] + } + Data::Union(_) => { + panic!( + "synstructure does not handle untagged unions \ + (https://github.com/mystor/synstructure/issues/6)" + ); + } + }; + + Structure { + variants: variants, + omitted_variants: false, + ast: ast, + extra_impl: vec![], + add_bounds: AddBounds::Both, + } + } + + /// Returns a slice of the variants in this Structure. + pub fn variants(&self) -> &[VariantInfo<'a>] { + &self.variants + } + + /// Returns a mut slice of the variants in this Structure. + pub fn variants_mut(&mut self) -> &mut [VariantInfo<'a>] { + &mut self.variants + } + + /// Returns a reference to the underlying `syn` AST node which this + /// `Structure` was created from. + pub fn ast(&self) -> &'a DeriveInput { + self.ast + } + + /// True if any variants were omitted due to a `filter_variants` call. + pub fn omitted_variants(&self) -> bool { + self.omitted_variants + } + + /// Runs the passed-in function once for each bound field, passing in a `BindingInfo`. + /// and generating `match` arms which evaluate the returned tokens. + /// + /// This method will ignore variants or fields which are ignored through the + /// `filter` and `filter_variant` methods. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) => { + /// { println!("{:?}", __binding_0) } + /// { println!("{:?}", __binding_1) } + /// } + /// A::C(ref __binding_0,) => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn each<F, R>(&self, mut f: F) -> TokenStream + where + F: FnMut(&BindingInfo) -> R, + R: ToTokens, + { + let mut t = TokenStream::new(); + for variant in &self.variants { + variant.each(&mut f).to_tokens(&mut t); + } + if self.omitted_variants { + quote!(_ => {}).to_tokens(&mut t); + } + t + } + + /// Runs the passed-in function once for each bound field, passing in the + /// result of the previous call, and a `BindingInfo`. generating `match` + /// arms which evaluate to the resulting tokens. + /// + /// This method will ignore variants or fields which are ignored through the + /// `filter` and `filter_variant` methods. + /// + /// If a variant has been ignored, it will return the `init` value. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.fold(quote!(0), |acc, bi| quote!(#acc + #bi)).to_string(), + /// + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) => { + /// 0 + __binding_0 + __binding_1 + /// } + /// A::C(ref __binding_0,) => { + /// 0 + __binding_0 + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn fold<F, I, R>(&self, init: I, mut f: F) -> TokenStream + where + F: FnMut(TokenStream, &BindingInfo) -> R, + I: ToTokens, + R: ToTokens, + { + let mut t = TokenStream::new(); + for variant in &self.variants { + variant.fold(&init, &mut f).to_tokens(&mut t); + } + if self.omitted_variants { + quote!(_ => { #init }).to_tokens(&mut t); + } + t + } + + /// Runs the passed-in function once for each variant, passing in a + /// `VariantInfo`. and generating `match` arms which evaluate the returned + /// tokens. + /// + /// This method will ignore variants and not bind fields which are ignored + /// through the `filter` and `filter_variant` methods. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let s = Structure::new(&di); + /// + /// assert_eq!( + /// s.each_variant(|v| { + /// let name = &v.ast().ident; + /// quote!(println!(stringify!(#name))) + /// }).to_string(), + /// + /// quote!{ + /// A::B(ref __binding_0, ref __binding_1,) => { + /// println!(stringify!(B)) + /// } + /// A::C(ref __binding_0,) => { + /// println!(stringify!(C)) + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn each_variant<F, R>(&self, mut f: F) -> TokenStream + where + F: FnMut(&VariantInfo) -> R, + R: ToTokens, + { + let mut t = TokenStream::new(); + for variant in &self.variants { + let pat = variant.pat(); + let body = f(variant); + quote!(#pat => { #body }).to_tokens(&mut t); + } + if self.omitted_variants { + quote!(_ => {}).to_tokens(&mut t); + } + t + } + + /// Filter the bindings created by this `Structure` object. This has 2 effects: + /// + /// * The bindings will no longer appear in match arms generated by methods + /// on this `Structure` or its subobjects. + /// + /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl` + /// method only consider type parameters referenced in the types of + /// non-filtered fields. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # extern crate proc_macro2; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B{ a: i32, b: i32 }, + /// C{ a: u32 }, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter(|bi| { + /// bi.ast().ident == Some(syn::Ident::new("a", proc_macro2::Span::call_site())) + /// }); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B{ a: ref __binding_0, .. } => { + /// { println!("{:?}", __binding_0) } + /// } + /// A::C{ a: ref __binding_0, } => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn filter<F>(&mut self, mut f: F) -> &mut Self + where + F: FnMut(&BindingInfo) -> bool, + { + for variant in &mut self.variants { + variant.filter(&mut f); + } + self + } + + /// Specify which bounds should be generated by impl-generating functions + /// such as `gen_impl`, `bound_impl`, and `unsafe_bound_impl`. + /// + /// The default behaviour is to generate both field and generic bounds from + /// type parameters. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// // Limit bounds to only generics. + /// s.add_bounds(AddBounds::Generics); + /// + /// assert_eq!( + /// s.bound_impl(quote!(krate::Trait), quote!{ + /// fn a() {} + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// impl<T, U> krate::Trait for A<T, U> + /// where T: krate::Trait, + /// U: krate::Trait + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn add_bounds(&mut self, mode: AddBounds) -> &mut Self { + self.add_bounds = mode; + self + } + + /// Filter the variants matched by this `Structure` object. This has 2 effects: + /// + /// * Match arms destructuring these variants will no longer be generated by + /// methods on this `Structure` + /// + /// * Impl blocks created with the `bound_impl` or `unsafe_bound_impl` + /// method only consider type parameters referenced in the types of + /// fields in non-fitered variants. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::C(ref __binding_0,) => { + /// { println!("{:?}", __binding_0) } + /// } + /// _ => {} + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn filter_variants<F>(&mut self, f: F) -> &mut Self + where + F: FnMut(&VariantInfo) -> bool, + { + let before_len = self.variants.len(); + self.variants.retain(f); + if self.variants.len() != before_len { + self.omitted_variants = true; + } + self + } + + /// Remove the variant at the given index. + /// + /// # Panics + /// + /// Panics if the index is out of range. + pub fn remove_variant(&mut self, idx: usize) -> &mut Self { + self.variants.remove(idx); + self.omitted_variants = true; + self + } + + /// Updates the `BindStyle` for each of the passed-in fields by calling the + /// passed-in function for each `BindingInfo`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B(i32, i32), + /// C(u32), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.bind_with(|bi| BindStyle::RefMut); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B(ref mut __binding_0, ref mut __binding_1,) => { + /// { println!("{:?}", __binding_0) } + /// { println!("{:?}", __binding_1) } + /// } + /// A::C(ref mut __binding_0,) => { + /// { println!("{:?}", __binding_0) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn bind_with<F>(&mut self, mut f: F) -> &mut Self + where + F: FnMut(&BindingInfo) -> BindStyle, + { + for variant in &mut self.variants { + variant.bind_with(&mut f); + } + self + } + + /// Updates the binding name for each fo the passed-in fields by calling the + /// passed-in function for each `BindingInfo`. + /// + /// The function will be called with the `BindingInfo` and its index in the + /// enclosing variant. + /// + /// The default name is `__binding_{}` where `{}` is replaced with an + /// increasing number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A { + /// B{ a: i32, b: i32 }, + /// C{ a: u32 }, + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.binding_name(|bi, i| bi.ident.clone().unwrap()); + /// + /// assert_eq!( + /// s.each(|bi| quote!(println!("{:?}", #bi))).to_string(), + /// + /// quote!{ + /// A::B{ a: ref a, b: ref b, } => { + /// { println!("{:?}", a) } + /// { println!("{:?}", b) } + /// } + /// A::C{ a: ref a, } => { + /// { println!("{:?}", a) } + /// } + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn binding_name<F>(&mut self, mut f: F) -> &mut Self + where + F: FnMut(&Field, usize) -> Ident, + { + for variant in &mut self.variants { + variant.binding_name(&mut f); + } + self + } + + /// Returns a list of the type parameters which are refrenced in the types + /// of non-filtered fields / variants. + /// + /// # Caveat + /// + /// If the struct contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # extern crate proc_macro2; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T, i32), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "C"); + /// + /// assert_eq!( + /// s.referenced_ty_params(), + /// &[&(syn::Ident::new("T", proc_macro2::Span::call_site()))] + /// ); + /// # } + /// ``` + pub fn referenced_ty_params(&self) -> Vec<&'a Ident> { + let mut flags = Vec::new(); + for variant in &self.variants { + for binding in &variant.bindings { + generics_fuse(&mut flags, &binding.seen_generics); + } + } + fetch_generics(&flags, &self.ast.generics) + } + + /// Adds an `impl<>` generic parameter. + /// This can be used when the trait to be derived needs some extra generic parameters. + /// + /// # Example + /// ``` + /// # #![recursion_limit="128"] + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// let generic: syn::GenericParam = parse_quote!(X: krate::AnotherTrait); + /// + /// assert_eq!( + /// s.add_impl_generic(generic) + /// .bound_impl(quote!(krate::Trait<X>), + /// quote!{ + /// fn a() {} + /// } + /// ).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_X_FOR_A: () = { + /// extern crate krate; + /// impl<T, U, X: krate::AnotherTrait> krate::Trait<X> for A<T, U> + /// where T : krate :: Trait < X >, + /// Option<U>: krate::Trait<X>, + /// U: krate::Trait<X> + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn add_impl_generic(&mut self, param: GenericParam) -> &mut Self { + self.extra_impl.push(param); + self + } + + /// Add trait bounds for a trait with the given path for each type parmaeter + /// referenced in the types of non-filtered fields. + /// + /// # Caveat + /// + /// If the method contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + pub fn add_trait_bounds( + &self, + bound: &TraitBound, + where_clause: &mut Option<WhereClause>, + mode: AddBounds, + ) { + let mut seen = HashSet::new(); + let mut pred = |ty: Type| { + if !seen.contains(&ty) { + seen.insert(ty.clone()); + + // Ensure we have a where clause, because we need to use it. We + // can't use `get_or_insert_with`, because it isn't supported on all + // rustc versions we support (this is a Rust 1.20+ feature). + if where_clause.is_none() { + *where_clause = Some(WhereClause { + where_token: Default::default(), + predicates: punctuated::Punctuated::new(), + }); + } + let clause = where_clause.as_mut().unwrap(); + + // Add a predicate. + clause.predicates.push(WherePredicate::Type(PredicateType { + lifetimes: None, + bounded_ty: ty, + colon_token: Default::default(), + bounds: Some(punctuated::Pair::End(TypeParamBound::Trait(bound.clone()))) + .into_iter() + .collect(), + })); + } + }; + + for variant in &self.variants { + for binding in &variant.bindings { + match mode { + AddBounds::Both | AddBounds::Fields => { + for &seen in &binding.seen_generics { + if seen { + pred(binding.ast().ty.clone()); + break; + } + } + } + _ => {} + } + + match mode { + AddBounds::Both | AddBounds::Generics => { + for param in binding.referenced_ty_params() { + pred(Type::Path(TypePath { + qself: None, + path: (*param).clone().into(), + })); + } + } + _ => {} + } + } + } + } + + /// > NOTE: This methods' features are superceded by `Structure::gen_impl`. + /// + /// Creates an `impl` block with the required generic type fields filled in + /// to implement the trait `path`. + /// + /// This method also adds where clauses to the impl requiring that all + /// referenced type parmaeters implement the trait `path`. + /// + /// # Hygiene and Paths + /// + /// This method wraps the impl block inside of a `const` (see the example + /// below). In this scope, the first segment of the passed-in path is + /// `extern crate`-ed in. If you don't want to generate that `extern crate` + /// item, use a global path. + /// + /// This means that if you are implementing `my_crate::Trait`, you simply + /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the + /// entirety of the definition, you can refer to your crate as `my_crate`. + /// + /// # Caveat + /// + /// If the method contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Panics + /// + /// Panics if the path string parameter is not a valid `TraitBound`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.bound_impl(quote!(krate::Trait), quote!{ + /// fn a() {} + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// impl<T, U> krate::Trait for A<T, U> + /// where Option<U>: krate::Trait, + /// U: krate::Trait + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream { + self.impl_internal( + path.into_token_stream(), + body.into_token_stream(), + quote!(), + None, + ) + } + + /// > NOTE: This methods' features are superceded by `Structure::gen_impl`. + /// + /// Creates an `impl` block with the required generic type fields filled in + /// to implement the unsafe trait `path`. + /// + /// This method also adds where clauses to the impl requiring that all + /// referenced type parmaeters implement the trait `path`. + /// + /// # Hygiene and Paths + /// + /// This method wraps the impl block inside of a `const` (see the example + /// below). In this scope, the first segment of the passed-in path is + /// `extern crate`-ed in. If you don't want to generate that `extern crate` + /// item, use a global path. + /// + /// This means that if you are implementing `my_crate::Trait`, you simply + /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the + /// entirety of the definition, you can refer to your crate as `my_crate`. + /// + /// # Caveat + /// + /// If the method contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Panics + /// + /// Panics if the path string parameter is not a valid `TraitBound`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.unsafe_bound_impl(quote!(krate::Trait), quote!{ + /// fn a() {} + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// unsafe impl<T, U> krate::Trait for A<T, U> + /// where Option<U>: krate::Trait, + /// U: krate::Trait + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn unsafe_bound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream { + self.impl_internal( + path.into_token_stream(), + body.into_token_stream(), + quote!(unsafe), + None, + ) + } + + /// > NOTE: This methods' features are superceded by `Structure::gen_impl`. + /// + /// Creates an `impl` block with the required generic type fields filled in + /// to implement the trait `path`. + /// + /// This method will not add any where clauses to the impl. + /// + /// # Hygiene and Paths + /// + /// This method wraps the impl block inside of a `const` (see the example + /// below). In this scope, the first segment of the passed-in path is + /// `extern crate`-ed in. If you don't want to generate that `extern crate` + /// item, use a global path. + /// + /// This means that if you are implementing `my_crate::Trait`, you simply + /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the + /// entirety of the definition, you can refer to your crate as `my_crate`. + /// + /// # Panics + /// + /// Panics if the path string parameter is not a valid `TraitBound`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.unbound_impl(quote!(krate::Trait), quote!{ + /// fn a() {} + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// impl<T, U> krate::Trait for A<T, U> { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + pub fn unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream { + self.impl_internal( + path.into_token_stream(), + body.into_token_stream(), + quote!(), + Some(AddBounds::None), + ) + } + + /// > NOTE: This methods' features are superceded by `Structure::gen_impl`. + /// + /// Creates an `impl` block with the required generic type fields filled in + /// to implement the unsafe trait `path`. + /// + /// This method will not add any where clauses to the impl. + /// + /// # Hygiene and Paths + /// + /// This method wraps the impl block inside of a `const` (see the example + /// below). In this scope, the first segment of the passed-in path is + /// `extern crate`-ed in. If you don't want to generate that `extern crate` + /// item, use a global path. + /// + /// This means that if you are implementing `my_crate::Trait`, you simply + /// write `s.bound_impl(quote!(my_crate::Trait), quote!(...))`, and for the + /// entirety of the definition, you can refer to your crate as `my_crate`. + /// + /// # Panics + /// + /// Panics if the path string parameter is not a valid `TraitBound`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.unsafe_unbound_impl(quote!(krate::Trait), quote!{ + /// fn a() {} + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// #[doc(hidden)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// unsafe impl<T, U> krate::Trait for A<T, U> { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + #[deprecated] + pub fn unsafe_unbound_impl<P: ToTokens, B: ToTokens>(&self, path: P, body: B) -> TokenStream { + self.impl_internal( + path.into_token_stream(), + body.into_token_stream(), + quote!(unsafe), + Some(AddBounds::None), + ) + } + + fn impl_internal( + &self, + path: TokenStream, + body: TokenStream, + safety: TokenStream, + mode: Option<AddBounds>, + ) -> TokenStream { + let mode = mode.unwrap_or(self.add_bounds); + let name = &self.ast.ident; + let mut gen_clone = self.ast.generics.clone(); + gen_clone.params.extend(self.extra_impl.clone().into_iter()); + let (impl_generics, _, _) = gen_clone.split_for_impl(); + let (_, ty_generics, where_clause) = self.ast.generics.split_for_impl(); + + let bound = syn::parse2::<TraitBound>(path.into()) + .expect("`path` argument must be a valid rust trait bound"); + + let mut where_clause = where_clause.cloned(); + self.add_trait_bounds(&bound, &mut where_clause, mode); + + let dummy_const: Ident = sanitize_ident(&format!( + "_DERIVE_{}_FOR_{}", + (&bound).into_token_stream(), + name.into_token_stream(), + )); + + // This function is smart. If a global path is passed, no extern crate + // statement will be generated, however, a relative path will cause the + // crate which it is relative to to be imported within the current + // scope. + let mut extern_crate = quote!(); + if bound.path.leading_colon.is_none() { + if let Some(ref seg) = bound.path.segments.first() { + let seg = seg.value(); + extern_crate = quote! { extern crate #seg; }; + } + } + + quote! { + #[allow(non_upper_case_globals)] + #[doc(hidden)] + const #dummy_const: () = { + #extern_crate + #safety impl #impl_generics #bound for #name #ty_generics #where_clause { + #body + } + }; + } + } + + /// Generate an impl block for the given struct. This impl block will + /// automatically use hygiene tricks to avoid polluting the caller's + /// namespace, and will automatically add trait bounds for generic type + /// parameters. + /// + /// # Syntax + /// + /// This function accepts its arguments as a `TokenStream`. The recommended way + /// to call this function is passing the result of invoking the `quote!` + /// macro to it. + /// + /// ```ignore + /// s.gen_impl(quote! { + /// // You can write any items which you want to import into scope here. + /// // For example, you may want to include an `extern crate` for the + /// // crate which implements your trait. These items will only be + /// // visible to the code you generate, and won't be exposed to the + /// // consuming crate + /// extern crate krate; + /// + /// // You can also add `use` statements here to bring types or traits + /// // into scope. + /// // + /// // WARNING: Try not to use common names here, because the stable + /// // version of syn does not support hygiene and you could accidentally + /// // shadow types from the caller crate. + /// use krate::Trait as MyTrait; + /// + /// // The actual impl block is a `gen impl` or `gen unsafe impl` block. + /// // You can use `@Self` to refer to the structure's type. + /// gen impl MyTrait for @Self { + /// fn f(&self) { ... } + /// } + /// }) + /// ``` + /// + /// The most common usage of this trait involves loading the crate the + /// target trait comes from with `extern crate`, and then invoking a `gen + /// impl` block. + /// + /// # Hygiene + /// + /// This method tries to handle hygiene intelligenly for both stable and + /// unstable proc-macro implementations, however there are visible + /// differences. + /// + /// The output of every `gen_impl` function is wrapped in a dummy `const` + /// value, to ensure that it is given its own scope, and any values brought + /// into scope are not leaked to the calling crate. For example, the above + /// invocation may generate an output like the following: + /// + /// ```ignore + /// const _DERIVE_krate_Trait_FOR_Struct: () = { + /// extern crate krate; + /// use krate::Trait as MyTrait; + /// impl<T> MyTrait for Struct<T> where T: MyTrait { + /// fn f(&self) { ... } + /// } + /// }; + /// ``` + /// + /// ### Using the `std` crate + /// + /// If you are using `quote!()` to implement your trait, with the + /// `proc-macro2/nightly` feature, `std` isn't considered to be in scope for + /// your macro. This means that if you use types from `std` in your + /// procedural macro, you'll want to explicitly load it with an `extern + /// crate std;`. + /// + /// ### Absolute paths + /// + /// You should generally avoid using absolute paths in your generated code, + /// as they will resolve very differently when using the stable and nightly + /// versions of `proc-macro2`. Instead, load the crates you need to use + /// explictly with `extern crate` and + /// + /// # Trait Bounds + /// + /// This method will automatically add trait bounds for any type parameters + /// which are referenced within the types of non-ignored fields. + /// + /// Additional type parameters may be added with the generics syntax after + /// the `impl` keyword. + /// + /// ### Type Macro Caveat + /// + /// If the method contains any macros in type position, all parameters will + /// be considered bound. This is because we cannot determine which type + /// parameters are bound by type macros. + /// + /// # Panics + /// + /// This function will panic if the input `TokenStream` is not well-formed, or + /// if additional type parameters added by `impl<..>` conflict with generic + /// type parameters on the original struct. + /// + /// # Example Usage + /// + /// ``` + /// # #![recursion_limit="128"] + /// # #[macro_use] extern crate quote; + /// # extern crate synstructure; + /// # #[macro_use] extern crate syn; + /// # use synstructure::*; + /// # fn main() { + /// let di: syn::DeriveInput = parse_quote! { + /// enum A<T, U> { + /// B(T), + /// C(Option<U>), + /// } + /// }; + /// let mut s = Structure::new(&di); + /// + /// s.filter_variants(|v| v.ast().ident != "B"); + /// + /// assert_eq!( + /// s.gen_impl(quote! { + /// extern crate krate; + /// gen impl krate::Trait for @Self { + /// fn a() {} + /// } + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// const _DERIVE_krate_Trait_FOR_A: () = { + /// extern crate krate; + /// impl<T, U> krate::Trait for A<T, U> + /// where + /// Option<U>: krate::Trait, + /// U: krate::Trait + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// + /// // NOTE: You can also add extra generics after the impl + /// assert_eq!( + /// s.gen_impl(quote! { + /// extern crate krate; + /// gen impl<X: krate::OtherTrait> krate::Trait<X> for @Self + /// where + /// X: Send + Sync, + /// { + /// fn a() {} + /// } + /// }).to_string(), + /// quote!{ + /// #[allow(non_upper_case_globals)] + /// const _DERIVE_krate_Trait_X_FOR_A: () = { + /// extern crate krate; + /// impl<X: krate::OtherTrait, T, U> krate::Trait<X> for A<T, U> + /// where + /// X: Send + Sync, + /// Option<U>: krate::Trait<X>, + /// U: krate::Trait<X> + /// { + /// fn a() {} + /// } + /// }; + /// }.to_string() + /// ); + /// # } + /// ``` + /// + /// Use `add_bounds` to change which bounds are generated. + pub fn gen_impl(&self, cfg: TokenStream) -> TokenStream { + use syn::parse::{ParseStream, Parser, Result}; + + // Syn requires parsers to be methods conforming to a strict signature + let do_parse = |input: ParseStream| -> Result<TokenStream> { + // Helper lambda to parse the prefix of a gen block. + let parse_prefix = |input: ParseStream| -> Result<_> { + if input.parse::<Ident>()? != "gen" { + return Err(input.error("")); + } + let safety = input.parse::<Option<Token![unsafe]>>()?; + let _ = input.parse::<Token![impl]>()?; + Ok(safety) + }; + + let mut before = vec![]; + loop { + if let Ok(_) = parse_prefix(&input.fork()) { + break; + } + before.push(input.parse::<TokenTree>()?); + } + + // Parse the prefix "for real" + let safety = parse_prefix(input)?; + + // optional `<>` + let mut generics = input.parse::<Generics>()?; + + // @bound + let bound = input.parse::<TraitBound>()?; + + // `for @Self` + let _ = input.parse::<Token![for]>()?; + let _ = input.parse::<Token![@]>()?; + let _ = input.parse::<Token![Self]>()?; + + // optional `where ...` + generics.where_clause = input.parse()?; + + // Body of the impl + let body; + braced!(body in input); + let body = body.parse::<TokenStream>()?; + + // Tokens following impl + let after = input.parse::<TokenStream>()?; + + /* Codegen Logic */ + let name = &self.ast.ident; + + // Add the generics from the original struct in, and then add any + // additional trait bounds which we need on the type. + merge_generics(&mut generics, &self.ast.generics); + self.add_trait_bounds(&bound, &mut generics.where_clause, self.add_bounds); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + let (_, ty_generics, _) = self.ast.generics.split_for_impl(); + + let dummy_const: Ident = sanitize_ident(&format!( + "_DERIVE_{}_FOR_{}", + (&bound).into_token_stream(), + name.into_token_stream(), + )); + + Ok(quote! { + #[allow(non_upper_case_globals)] + const #dummy_const: () = { + #(#before)* + #safety impl #impl_generics #bound for #name #ty_generics #where_clause { + #body + } + #after + }; + }) + }; + Parser::parse2(do_parse, cfg).expect("Failed to parse gen_impl") + } +} + +/// Dumps an unpretty version of a tokenstream. Takes any type which implements +/// `Display`. +/// +/// This is mostly useful for visualizing the output of a procedural macro, as +/// it makes it marginally more readable. It is used in the implementation of +/// `test_derive!` to unprettily print the output. +/// +/// # Stability +/// +/// The stability of the output of this function is not guaranteed. Do not +/// assert that the output of this function does not change between minor +/// versions. +/// +/// # Example +/// +/// ``` +/// # extern crate synstructure; +/// # #[macro_use] extern crate quote; +/// # fn main() { +/// assert_eq!( +/// synstructure::unpretty_print(quote! { +/// #[allow(non_upper_case_globals)] +/// const _DERIVE_krate_Trait_FOR_A: () = { +/// extern crate krate; +/// impl<T, U> krate::Trait for A<T, U> +/// where +/// Option<U>: krate::Trait, +/// U: krate::Trait +/// { +/// fn a() {} +/// } +/// }; +/// }), +/// "# [ +/// allow ( +/// non_upper_case_globals ) +/// ] +/// const _DERIVE_krate_Trait_FOR_A : ( +/// ) +/// = { +/// extern crate krate ; +/// impl < T , U > krate :: Trait for A < T , U > where Option < U > : krate :: Trait , U : krate :: Trait { +/// fn a ( +/// ) +/// { +/// } +/// } +/// } +/// ; +/// " +/// ) +/// # } +/// ``` +pub fn unpretty_print<T: std::fmt::Display>(ts: T) -> String { + let mut res = String::new(); + + let raw_s = ts.to_string(); + let mut s = &raw_s[..]; + let mut indent = 0; + while let Some(i) = s.find(&['(', '{', '[', ')', '}', ']', ';'][..]) { + match &s[i..i + 1] { + "(" | "{" | "[" => indent += 1, + ")" | "}" | "]" => indent -= 1, + _ => {} + } + res.push_str(&s[..i + 1]); + res.push('\n'); + for _ in 0..indent { + res.push_str(" "); + } + s = s[i + 1..].trim_left_matches(' '); + } + res.push_str(s); + res +} diff --git a/synstructure/src/macros.rs b/synstructure/src/macros.rs new file mode 100644 index 000000000..f729b486d --- /dev/null +++ b/synstructure/src/macros.rs @@ -0,0 +1,471 @@ +//! This module provides two utility macros for testing custom derives. They can +//! be used together to eliminate some of the boilerplate required in order to +//! declare and test custom derive implementations. + +// Re-exports used by the decl_derive! and test_derive! +pub use proc_macro::TokenStream; +pub use proc_macro2::TokenStream as TokenStream2; +pub use syn::{parse, parse_str, DeriveInput}; + +/// The `decl_derive!` macro declares a custom derive wrapper. It will parse the +/// incoming `TokenStream` into a `synstructure::Structure` object, and pass it +/// into the inner function. +/// +/// Your inner function should have the following type: +/// +/// ``` +/// # extern crate quote; +/// # extern crate proc_macro2; +/// # extern crate synstructure; +/// fn derive(input: synstructure::Structure) -> proc_macro2::TokenStream { +/// unimplemented!() +/// } +/// ``` +/// +/// # Usage +/// +/// ### Without Attributes +/// ``` +/// # #[macro_use] extern crate quote; +/// # extern crate proc_macro2; +/// # extern crate synstructure; +/// # fn main() {} +/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream { +/// quote! { ... } +/// } +/// +/// # const _IGNORE: &'static str = stringify! { +/// decl_derive!([Interesting] => derive_interesting); +/// # }; +/// ``` +/// +/// ### With Attributes +/// ``` +/// # #[macro_use] extern crate quote; +/// # extern crate proc_macro2; +/// # extern crate synstructure; +/// # fn main() {} +/// fn derive_interesting(_input: synstructure::Structure) -> proc_macro2::TokenStream { +/// quote! { ... } +/// } +/// +/// # const _IGNORE: &'static str = stringify! { +/// decl_derive!([Interesting, attributes(interesting_ignore)] => derive_interesting); +/// # }; +/// ``` +#[macro_export] +macro_rules! decl_derive { + // XXX: Switch to using this variant everywhere? + ([$derives:ident $($derive_t:tt)*] => $inner:path) => { + #[proc_macro_derive($derives $($derive_t)*)] + #[allow(non_snake_case)] + pub fn $derives( + i: $crate::macros::TokenStream + ) -> $crate::macros::TokenStream + { + let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i) + .expect(concat!("Failed to parse input to `#[derive(", + stringify!($derives), + ")]`")); + $inner($crate::Structure::new(&parsed)).into() + } + }; +} + +/// The `decl_attribute!` macro declares a custom attribute wrapper. It will +/// parse the incoming `TokenStream` into a `synstructure::Structure` object, +/// and pass it into the inner function. +/// +/// Your inner function should have the following type: +/// +/// ``` +/// # extern crate quote; +/// # extern crate proc_macro2; +/// # extern crate synstructure; +/// fn attribute( +/// attr: proc_macro2::TokenStream, +/// structure: synstructure::Structure, +/// ) -> proc_macro2::TokenStream { +/// unimplemented!() +/// } +/// ``` +/// +/// # Usage +/// +/// ``` +/// # #[macro_use] extern crate quote; +/// # extern crate proc_macro2; +/// # extern crate synstructure; +/// # fn main() {} +/// fn attribute_interesting( +/// _attr: proc_macro2::TokenStream, +/// _structure: synstructure::Structure, +/// ) -> proc_macro2::TokenStream { +/// quote! { ... } +/// } +/// +/// # const _IGNORE: &'static str = stringify! { +/// decl_attribute!([interesting] => attribute_interesting); +/// # }; +/// ``` +/// ``` +#[macro_export] +macro_rules! decl_attribute { + ([$attribute:ident] => $inner:path) => { + #[proc_macro_attribute] + pub fn $attribute( + attr: $crate::macros::TokenStream, + i: $crate::macros::TokenStream, + ) -> $crate::macros::TokenStream { + let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i).expect(concat!( + "Failed to parse input to `#[", + stringify!($attribute), + "]`" + )); + $inner(attr.into(), $crate::Structure::new(&parsed)).into() + } + }; +} + +/// Run a test on a custom derive. This macro expands both the original struct +/// and the expansion to ensure that they compile correctly, and confirms that +/// feeding the original struct into the named derive will produce the written +/// output. +/// +/// You can add `no_build` to the end of the macro invocation to disable +/// checking that the written code compiles. This is useful in contexts where +/// the procedural macro cannot depend on the crate where it is used during +/// tests. +/// +/// # Usage +/// +/// ``` +/// # #[macro_use] extern crate quote; +/// # extern crate proc_macro2; +/// # #[macro_use] extern crate synstructure; +/// fn test_derive_example(_s: synstructure::Structure) -> proc_macro2::TokenStream { +/// quote! { const YOUR_OUTPUT: &'static str = "here"; } +/// } +/// +/// fn main() { +/// test_derive!{ +/// test_derive_example { +/// struct A; +/// } +/// expands to { +/// const YOUR_OUTPUT: &'static str = "here"; +/// } +/// } +/// } +/// ``` +#[macro_export] +macro_rules! test_derive { + ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => { + { + #[allow(dead_code)] + fn ensure_compiles() { + $($i)* + $($o)* + } + + test_derive!($name { $($i)* } expands to { $($o)* } no_build); + } + }; + + ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => { + { + let i = stringify!( $($i)* ); + let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i) + .expect(concat!("Failed to parse input to `#[derive(", + stringify!($name), + ")]`")); + + let res = $name($crate::Structure::new(&parsed)); + let expected = stringify!( $($o)* ) + .parse::<$crate::macros::TokenStream2>() + .expect("output should be a valid TokenStream"); + let mut expected_toks = $crate::macros::TokenStream2::from(expected); + if res.to_string() != expected_toks.to_string() { + panic!("\ +test_derive failed: +expected: +``` +{} +``` + +got: +``` +{} +```\n", + $crate::unpretty_print(&expected_toks), + $crate::unpretty_print(&res), + ); + } + // assert_eq!(res, expected_toks) + } + }; +} + +/// A helper macro for declaring relatively straightforward derive +/// implementations. It provides mechanisms for operating over structures +/// performing modifications on each field etc. +/// +/// This macro doesn't define the actual derive, but rather the implementation +/// method. Use `decl_derive!` to generate the implementation wrapper. +/// +/// # Stability Warning +/// +/// This is an unstable experimental macro API, which may be changed or removed +/// in a future version. I'm not yet confident enough that this API is useful +/// enough to warrant its complexity and inclusion in `synstructure`. +/// +/// # Caveat +/// +/// The `quote!` macro from `quote` must be imported in the calling crate, as +/// this macro depends on it. +/// +/// # Note +/// +/// This feature is implemented behind the `simple-derive` feature, and is only +/// available when that feature is enabled. +/// +/// # Example +/// +/// ``` +/// extern crate syn; +/// #[macro_use] +/// extern crate quote; +/// #[macro_use] +/// extern crate synstructure; +/// extern crate proc_macro2; +/// # const _IGNORE: &'static str = stringify! { +/// decl_derive!([Interest] => derive_interest); +/// # }; +/// +/// simple_derive! { +/// // This macro implements the `Interesting` method exported by the `aa` +/// // crate. It will explicitly add an `extern crate` invocation to import the +/// // crate into the expanded context. +/// derive_interest impl synstructure_test_traits::Interest { +/// // A "filter" block can be added. It evaluates its body with the (s) +/// // variable bound to a mutable reference to the input `Structure` +/// // object. +/// // +/// // This block can be used to perform general transformations, such as +/// // filtering out fields which should be ignored by all methods and for +/// // the purposes of binding type parameters. +/// filter(s) { +/// s.filter(|bi| bi.ast().ident != Some(syn::Ident::new("a", +/// proc_macro2::Span::call_site()))); +/// } +/// +/// // This is an implementation of a method in the implemented crate. The +/// // return value should be the series of match patterns to destructure +/// // the `self` argument with. +/// fn interesting(&self as s) -> bool { +/// s.fold(false, |acc, bi| { +/// quote!(#acc || synstructure_test_traits::Interest::interesting(#bi)) +/// }) +/// } +/// } +/// } +/// +/// fn main() { +/// test_derive!{ +/// derive_interest { +/// struct A<T> { +/// x: i32, +/// a: bool, // Will be ignored by filter +/// c: T, +/// } +/// } +/// expands to { +/// #[allow(non_upper_case_globals)] +/// #[doc(hidden)] +/// const _DERIVE_synstructure_test_traits_Interest_FOR_A: () = { +/// extern crate synstructure_test_traits; +/// impl<T> synstructure_test_traits::Interest for A<T> +/// where T: synstructure_test_traits::Interest +/// { +/// fn interesting(&self) -> bool { +/// match *self { +/// A { +/// x: ref __binding_0, +/// c: ref __binding_2, +/// .. +/// } => { +/// false || +/// synstructure_test_traits::Interest::interesting(__binding_0) || +/// synstructure_test_traits::Interest::interesting(__binding_2) +/// } +/// } +/// } +/// } +/// }; +/// } +/// } +/// } +/// ``` +#[cfg(feature = "simple-derive")] +#[macro_export] +macro_rules! simple_derive { + // entry point + ( + $iname:ident impl $path:path { $($rest:tt)* } + ) => { + simple_derive!(__I [$iname, $path] { $($rest)* } [] []); + }; + + // Adding a filter block + ( + __I $opt:tt { + filter($s:ident) { + $($body:tt)* + } + $($rest:tt)* + } [$($done:tt)*] [$($filter:tt)*] + ) => { + simple_derive!( + __I $opt { $($rest)* } [$($done)*] [ + $($filter)* + [ + st_name = $s, + body = { + $($body)* + }, + ] + ] + ); + }; + + // &self bound method + ( + __I $opt:tt { + fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* { + $($body:tt)* + } + $($rest:tt)* + } [$($done:tt)*] [$($filter:tt)*] + ) => { + simple_derive!( + __I $opt { $($rest)* } [ + $($done)* + [ + st_name = $s, + bind_style = Ref, + body = { $($body)* }, + result = result, + expanded = { + fn $fn_name(&self $($params)*) $(-> $t)* { + match *self { #result } + } + }, + ] + ] [$($filter)*] + ); + }; + + // &mut self bound method + ( + __I $opt:tt { + fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* { + $($body:tt)* + } + $($rest:tt)* + } [$($done:tt)*] [$($filter:tt)*] + ) => { + simple_derive!( + __I $opt { $($rest)* } [ + $($done)* + [ + st_name = $s, + bind_style = RefMut, + body = { $($body)* }, + result = result, + expanded = { + fn $fn_name(&mut self $($params)*) $(-> $t)* { + match *self { #result } + } + }, + ] + ] [$($filter)*] + ); + }; + + // self bound method + ( + __I $opt:tt { + fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* { + $($body:tt)* + } + $($rest:tt)* + } [$($done:tt)*] [$($filter:tt)*] + ) => { + simple_derive!( + __I $opt { $($rest)* } [ + $($done)* + [ + st_name = $s, + bind_style = Move, + body = { $($body)* }, + result = result, + expanded = { + fn $fn_name(self $($params)*) $(-> $t)* { + match self { #result } + } + }, + ] + ] [$($filter)*] + ); + }; + + // XXX: Static methods? + + // codegen after data collection + ( + __I [$iname:ident, $path:path] {} [$( + [ + st_name = $st_name:ident, + bind_style = $bind_style:ident, + body = $body:tt, + result = $result:ident, + expanded = { $($expanded:tt)* }, + ] + )*] [$( + [ + st_name = $filter_st_name:ident, + body = $filter_body:tt, + ] + )*] + ) => { + fn $iname(mut st: $crate::Structure) -> $crate::macros::TokenStream2 { + let _ = &mut st; // Silence the unused mut warning + + // Filter/transform the `Structure` object before cloning it for + // individual methods. + $( + { + let $filter_st_name = &mut st; + $filter_body + } + )* + + // Clone the `Structure` object and set the correct binding style, + // then perform method specific expansion. + $( + let $result = { + let mut $st_name = st.clone(); + $st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style); + let $result = { + $body + }; + quote!{ $($expanded)* } + }; + )* + + st.bound_impl(quote!($path), quote!{ + $(#$result)* + }) + } + } +} diff --git a/tar/.cargo-checksum.json b/tar/.cargo-checksum.json new file mode 100644 index 000000000..439d22c6b --- /dev/null +++ b/tar/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3"} \ No newline at end of file diff --git a/tar/Cargo.toml b/tar/Cargo.toml new file mode 100644 index 000000000..6fbe0b6c4 --- /dev/null +++ b/tar/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "tar" +version = "0.4.26" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +exclude = ["tests/archives/*"] +description = "A Rust implementation of a TAR file reader and writer. This library does not\ncurrently handle compression, but it is abstract over all I/O readers and\nwriters. Additionally, great lengths are taken to ensure that the entire\ncontents are never required to be entirely resident in memory all at once.\n" +homepage = "https://github.com/alexcrichton/tar-rs" +documentation = "https://docs.rs/tar" +readme = "README.md" +keywords = ["tar", "tarfile", "encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/tar-rs" +[dependencies.filetime] +version = "0.2.6" +[dev-dependencies.tempdir] +version = "0.3" + +[features] +default = ["xattr"] +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" +[target."cfg(unix)".dependencies.libc] +version = "0.2" + +[target."cfg(unix)".dependencies.xattr] +version = "0.2" +optional = true diff --git a/tar/LICENSE-APACHE b/tar/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/tar/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/tar/LICENSE-MIT b/tar/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/tar/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/tar/README.md b/tar/README.md new file mode 100644 index 000000000..77963e288 --- /dev/null +++ b/tar/README.md @@ -0,0 +1,80 @@ +# tar-rs + +[![Build Status](https://travis-ci.com/alexcrichton/tar-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/tar-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/0udgokm2fc6ljorj?svg=true)](https://ci.appveyor.com/project/alexcrichton/tar-rs) +[![Coverage Status](https://coveralls.io/repos/alexcrichton/tar-rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/alexcrichton/tar-rs?branch=master) + +[Documentation](https://docs.rs/tar) + +A tar archive reading/writing library for Rust. + +```toml +# Cargo.toml +[dependencies] +tar = "0.4" +``` + +## Reading an archive + +```rust,no_run +extern crate tar; + +use std::io::prelude::*; +use std::fs::File; +use tar::Archive; + +fn main() { + let file = File::open("foo.tar").unwrap(); + let mut a = Archive::new(file); + + for file in a.entries().unwrap() { + // Make sure there wasn't an I/O error + let mut file = file.unwrap(); + + // Inspect metadata about the file + println!("{:?}", file.header().path().unwrap()); + println!("{}", file.header().size().unwrap()); + + // files implement the Read trait + let mut s = String::new(); + file.read_to_string(&mut s).unwrap(); + println!("{}", s); + } +} + +``` + +## Writing an archive + +```rust,no_run +extern crate tar; + +use std::io::prelude::*; +use std::fs::File; +use tar::Builder; + +fn main() { + let file = File::create("foo.tar").unwrap(); + let mut a = Builder::new(file); + + a.append_path("file1.txt").unwrap(); + a.append_file("file2.txt", &mut File::open("file3.txt").unwrap()).unwrap(); +} +``` + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. diff --git a/tar/appveyor.yml b/tar/appveyor.yml new file mode 100644 index 000000000..7fdb2ee9a --- /dev/null +++ b/tar/appveyor.yml @@ -0,0 +1,20 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS_BITS: 32 + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose --target %TARGET% diff --git a/tar/examples/extract_file.rs b/tar/examples/extract_file.rs new file mode 100644 index 000000000..425e9a350 --- /dev/null +++ b/tar/examples/extract_file.rs @@ -0,0 +1,25 @@ +//! An example of extracting a file in an archive. +//! +//! Takes a tarball on standard input, looks for an entry with a listed file +//! name as the first argument provided, and then prints the contents of that +//! file to stdout. + +extern crate tar; + +use std::env::args_os; +use std::io::{copy, stdin, stdout}; +use std::path::Path; + +use tar::Archive; + +fn main() { + let first_arg = args_os().skip(1).next().unwrap(); + let filename = Path::new(&first_arg); + let mut ar = Archive::new(stdin()); + for file in ar.entries().unwrap() { + let mut f = file.unwrap(); + if f.path().unwrap() == filename { + copy(&mut f, &mut stdout()).unwrap(); + } + } +} diff --git a/tar/examples/list.rs b/tar/examples/list.rs new file mode 100644 index 000000000..e2d58daf6 --- /dev/null +++ b/tar/examples/list.rs @@ -0,0 +1,17 @@ +//! An example of listing the file names of entries in an archive. +//! +//! Takes a tarball on stdin and prints out all of the entries inside. + +extern crate tar; + +use std::io::stdin; + +use tar::Archive; + +fn main() { + let mut ar = Archive::new(stdin()); + for file in ar.entries().unwrap() { + let f = file.unwrap(); + println!("{}", f.path().unwrap().display()); + } +} diff --git a/tar/examples/raw_list.rs b/tar/examples/raw_list.rs new file mode 100644 index 000000000..9b86da229 --- /dev/null +++ b/tar/examples/raw_list.rs @@ -0,0 +1,48 @@ +//! An example of listing raw entries in an archive. +//! +//! Takes a tarball on stdin and prints out all of the entries inside. + +extern crate tar; + +use std::io::stdin; + +use tar::Archive; + +fn main() { + let mut ar = Archive::new(stdin()); + for (i, file) in ar.entries().unwrap().raw(true).enumerate() { + println!("-------------------------- Entry {}", i); + let mut f = file.unwrap(); + println!("path: {}", f.path().unwrap().display()); + println!("size: {}", f.header().size().unwrap()); + println!("entry size: {}", f.header().entry_size().unwrap()); + println!("link name: {:?}", f.link_name().unwrap()); + println!("file type: {:#x}", f.header().entry_type().as_byte()); + println!("mode: {:#o}", f.header().mode().unwrap()); + println!("uid: {}", f.header().uid().unwrap()); + println!("gid: {}", f.header().gid().unwrap()); + println!("mtime: {}", f.header().mtime().unwrap()); + println!("username: {:?}", f.header().username().unwrap()); + println!("groupname: {:?}", f.header().groupname().unwrap()); + + if f.header().as_ustar().is_some() { + println!("kind: UStar"); + } else if f.header().as_gnu().is_some() { + println!("kind: GNU"); + } else { + println!("kind: normal"); + } + + if let Ok(Some(extensions)) = f.pax_extensions() { + println!("pax extensions:"); + for e in extensions { + let e = e.unwrap(); + println!( + "\t{:?} = {:?}", + String::from_utf8_lossy(e.key_bytes()), + String::from_utf8_lossy(e.value_bytes()) + ); + } + } + } +} diff --git a/tar/examples/write.rs b/tar/examples/write.rs new file mode 100644 index 000000000..167263d97 --- /dev/null +++ b/tar/examples/write.rs @@ -0,0 +1,13 @@ +extern crate tar; + +use std::fs::File; +use tar::Builder; + +fn main() { + let file = File::create("foo.tar").unwrap(); + let mut a = Builder::new(file); + + a.append_path("README.md").unwrap(); + a.append_file("lib.rs", &mut File::open("src/lib.rs").unwrap()) + .unwrap(); +} diff --git a/tar/src/archive.rs b/tar/src/archive.rs new file mode 100644 index 000000000..433c6de32 --- /dev/null +++ b/tar/src/archive.rs @@ -0,0 +1,488 @@ +use std::cell::{Cell, RefCell}; +use std::cmp; +use std::io; +use std::io::prelude::*; +use std::marker; +use std::path::Path; + +use crate::entry::{EntryFields, EntryIo}; +use crate::error::TarError; +use crate::other; +use crate::{Entry, GnuExtSparseHeader, GnuSparseHeader, Header}; + +/// A top-level representation of an archive file. +/// +/// This archive can have an entry added to it and it can be iterated over. +pub struct Archive<R: ?Sized + Read> { + inner: ArchiveInner<R>, +} + +pub struct ArchiveInner<R: ?Sized> { + pos: Cell<u64>, + unpack_xattrs: bool, + preserve_permissions: bool, + preserve_mtime: bool, + ignore_zeros: bool, + obj: RefCell<R>, +} + +/// An iterator over the entries of an archive. +pub struct Entries<'a, R: 'a + Read> { + fields: EntriesFields<'a>, + _ignored: marker::PhantomData<&'a Archive<R>>, +} + +struct EntriesFields<'a> { + archive: &'a Archive<Read + 'a>, + next: u64, + done: bool, + raw: bool, +} + +impl<R: Read> Archive<R> { + /// Create a new archive with the underlying object as the reader. + pub fn new(obj: R) -> Archive<R> { + Archive { + inner: ArchiveInner { + unpack_xattrs: false, + preserve_permissions: false, + preserve_mtime: true, + ignore_zeros: false, + obj: RefCell::new(obj), + pos: Cell::new(0), + }, + } + } + + /// Unwrap this archive, returning the underlying object. + pub fn into_inner(self) -> R { + self.inner.obj.into_inner() + } + + /// Construct an iterator over the entries in this archive. + /// + /// Note that care must be taken to consider each entry within an archive in + /// sequence. If entries are processed out of sequence (from what the + /// iterator returns), then the contents read for each entry may be + /// corrupted. + pub fn entries(&mut self) -> io::Result<Entries<R>> { + let me: &mut Archive<Read> = self; + me._entries().map(|fields| Entries { + fields: fields, + _ignored: marker::PhantomData, + }) + } + + /// Unpacks the contents tarball into the specified `dst`. + /// + /// This function will iterate over the entire contents of this tarball, + /// extracting each file in turn to the location specified by the entry's + /// path name. + /// + /// This operation is relatively sensitive in that it will not write files + /// outside of the path specified by `dst`. Files in the archive which have + /// a '..' in their path are skipped during the unpacking process. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use tar::Archive; + /// + /// let mut ar = Archive::new(File::open("foo.tar").unwrap()); + /// ar.unpack("foo").unwrap(); + /// ``` + pub fn unpack<P: AsRef<Path>>(&mut self, dst: P) -> io::Result<()> { + let me: &mut Archive<Read> = self; + me._unpack(dst.as_ref()) + } + + /// Indicate whether extended file attributes (xattrs on Unix) are preserved + /// when unpacking this archive. + /// + /// This flag is disabled by default and is currently only implemented on + /// Unix using xattr support. This may eventually be implemented for + /// Windows, however, if other archive implementations are found which do + /// this as well. + pub fn set_unpack_xattrs(&mut self, unpack_xattrs: bool) { + self.inner.unpack_xattrs = unpack_xattrs; + } + + /// Indicate whether extended permissions (like suid on Unix) are preserved + /// when unpacking this entry. + /// + /// This flag is disabled by default and is currently only implemented on + /// Unix. + pub fn set_preserve_permissions(&mut self, preserve: bool) { + self.inner.preserve_permissions = preserve; + } + + /// Indicate whether access time information is preserved when unpacking + /// this entry. + /// + /// This flag is enabled by default. + pub fn set_preserve_mtime(&mut self, preserve: bool) { + self.inner.preserve_mtime = preserve; + } + + /// Ignore zeroed headers, which would otherwise indicate to the archive that it has no more + /// entries. + /// + /// This can be used in case multiple tar archives have been concatenated together. + pub fn set_ignore_zeros(&mut self, ignore_zeros: bool) { + self.inner.ignore_zeros = ignore_zeros; + } +} + +impl<'a> Archive<Read + 'a> { + fn _entries(&mut self) -> io::Result<EntriesFields> { + if self.inner.pos.get() != 0 { + return Err(other( + "cannot call entries unless archive is at \ + position 0", + )); + } + Ok(EntriesFields { + archive: self, + done: false, + next: 0, + raw: false, + }) + } + + fn _unpack(&mut self, dst: &Path) -> io::Result<()> { + for entry in self._entries()? { + let mut file = entry.map_err(|e| TarError::new("failed to iterate over archive", e))?; + file.unpack_in(dst)?; + } + Ok(()) + } + + fn skip(&self, mut amt: u64) -> io::Result<()> { + let mut buf = [0u8; 4096 * 8]; + while amt > 0 { + let n = cmp::min(amt, buf.len() as u64); + let n = (&self.inner).read(&mut buf[..n as usize])?; + if n == 0 { + return Err(other("unexpected EOF during skip")); + } + amt -= n as u64; + } + Ok(()) + } +} + +impl<'a, R: Read> Entries<'a, R> { + /// Indicates whether this iterator will return raw entries or not. + /// + /// If the raw list of entries are returned, then no preprocessing happens + /// on account of this library, for example taking into accout GNU long name + /// or long link archive members. Raw iteration is disabled by default. + pub fn raw(self, raw: bool) -> Entries<'a, R> { + Entries { + fields: EntriesFields { + raw: raw, + ..self.fields + }, + _ignored: marker::PhantomData, + } + } +} +impl<'a, R: Read> Iterator for Entries<'a, R> { + type Item = io::Result<Entry<'a, R>>; + + fn next(&mut self) -> Option<io::Result<Entry<'a, R>>> { + self.fields + .next() + .map(|result| result.map(|e| EntryFields::from(e).into_entry())) + } +} + +impl<'a> EntriesFields<'a> { + fn next_entry_raw(&mut self) -> io::Result<Option<Entry<'a, io::Empty>>> { + let mut header = Header::new_old(); + let mut header_pos = self.next; + + loop { + // Seek to the start of the next header in the archive + let delta = self.next - self.archive.inner.pos.get(); + self.archive.skip(delta)?; + + // EOF is an indicator that we are at the end of the archive. + if !try_read_all(&mut &self.archive.inner, header.as_mut_bytes())? { + return Ok(None); + } + + // If a header is not all zeros, we have another valid header. + // Otherwise, check if we are ignoring zeros and continue, or break as if this is the + // end of the archive. + if !header.as_bytes().iter().all(|i| *i == 0) { + self.next += 512; + break; + } + + if !self.archive.inner.ignore_zeros { + return Ok(None); + } + + self.next += 512; + header_pos = self.next; + } + + // Make sure the checksum is ok + let sum = header.as_bytes()[..148] + .iter() + .chain(&header.as_bytes()[156..]) + .fold(0, |a, b| a + (*b as u32)) + + 8 * 32; + let cksum = header.cksum()?; + if sum != cksum { + return Err(other("archive header checksum mismatch")); + } + + let file_pos = self.next; + let size = header.entry_size()?; + + let ret = EntryFields { + size: size, + header_pos: header_pos, + file_pos: file_pos, + data: vec![EntryIo::Data((&self.archive.inner).take(size))], + header: header, + long_pathname: None, + long_linkname: None, + pax_extensions: None, + unpack_xattrs: self.archive.inner.unpack_xattrs, + preserve_permissions: self.archive.inner.preserve_permissions, + preserve_mtime: self.archive.inner.preserve_mtime, + }; + + // Store where the next entry is, rounding up by 512 bytes (the size of + // a header); + let size = (size + 511) & !(512 - 1); + self.next += size; + + Ok(Some(ret.into_entry())) + } + + fn next_entry(&mut self) -> io::Result<Option<Entry<'a, io::Empty>>> { + if self.raw { + return self.next_entry_raw(); + } + + let mut gnu_longname = None; + let mut gnu_longlink = None; + let mut pax_extensions = None; + let mut processed = 0; + loop { + processed += 1; + let entry = match self.next_entry_raw()? { + Some(entry) => entry, + None if processed > 1 => { + return Err(other( + "members found describing a future member \ + but no future member found", + )); + } + None => return Ok(None), + }; + + if entry.header().as_gnu().is_some() && entry.header().entry_type().is_gnu_longname() { + if gnu_longname.is_some() { + return Err(other( + "two long name entries describing \ + the same member", + )); + } + gnu_longname = Some(EntryFields::from(entry).read_all()?); + continue; + } + + if entry.header().as_gnu().is_some() && entry.header().entry_type().is_gnu_longlink() { + if gnu_longlink.is_some() { + return Err(other( + "two long name entries describing \ + the same member", + )); + } + gnu_longlink = Some(EntryFields::from(entry).read_all()?); + continue; + } + + if entry.header().as_ustar().is_some() + && entry.header().entry_type().is_pax_local_extensions() + { + if pax_extensions.is_some() { + return Err(other( + "two pax extensions entries describing \ + the same member", + )); + } + pax_extensions = Some(EntryFields::from(entry).read_all()?); + continue; + } + + let mut fields = EntryFields::from(entry); + fields.long_pathname = gnu_longname; + fields.long_linkname = gnu_longlink; + fields.pax_extensions = pax_extensions; + self.parse_sparse_header(&mut fields)?; + return Ok(Some(fields.into_entry())); + } + } + + fn parse_sparse_header(&mut self, entry: &mut EntryFields<'a>) -> io::Result<()> { + if !entry.header.entry_type().is_gnu_sparse() { + return Ok(()); + } + let gnu = match entry.header.as_gnu() { + Some(gnu) => gnu, + None => return Err(other("sparse entry type listed but not GNU header")), + }; + + // Sparse files are represented internally as a list of blocks that are + // read. Blocks are either a bunch of 0's or they're data from the + // underlying archive. + // + // Blocks of a sparse file are described by the `GnuSparseHeader` + // structure, some of which are contained in `GnuHeader` but some of + // which may also be contained after the first header in further + // headers. + // + // We read off all the blocks here and use the `add_block` function to + // incrementally add them to the list of I/O block (in `entry.data`). + // The `add_block` function also validates that each chunk comes after + // the previous, we don't overrun the end of the file, and each block is + // aligned to a 512-byte boundary in the archive itself. + // + // At the end we verify that the sparse file size (`Header::size`) is + // the same as the current offset (described by the list of blocks) as + // well as the amount of data read equals the size of the entry + // (`Header::entry_size`). + entry.data.truncate(0); + + let mut cur = 0; + let mut remaining = entry.size; + { + let data = &mut entry.data; + let reader = &self.archive.inner; + let size = entry.size; + let mut add_block = |block: &GnuSparseHeader| -> io::Result<_> { + if block.is_empty() { + return Ok(()); + } + let off = block.offset()?; + let len = block.length()?; + + if (size - remaining) % 512 != 0 { + return Err(other( + "previous block in sparse file was not \ + aligned to 512-byte boundary", + )); + } else if off < cur { + return Err(other( + "out of order or overlapping sparse \ + blocks", + )); + } else if cur < off { + let block = io::repeat(0).take(off - cur); + data.push(EntryIo::Pad(block)); + } + cur = off + .checked_add(len) + .ok_or_else(|| other("more bytes listed in sparse file than u64 can hold"))?; + remaining = remaining.checked_sub(len).ok_or_else(|| { + other( + "sparse file consumed more data than the header \ + listed", + ) + })?; + data.push(EntryIo::Data(reader.take(len))); + Ok(()) + }; + for block in gnu.sparse.iter() { + add_block(block)? + } + if gnu.is_extended() { + let mut ext = GnuExtSparseHeader::new(); + ext.isextended[0] = 1; + while ext.is_extended() { + if !try_read_all(&mut &self.archive.inner, ext.as_mut_bytes())? { + return Err(other("failed to read extension")); + } + + self.next += 512; + for block in ext.sparse.iter() { + add_block(block)?; + } + } + } + } + if cur != gnu.real_size()? { + return Err(other( + "mismatch in sparse file chunks and \ + size in header", + )); + } + entry.size = cur; + if remaining > 0 { + return Err(other( + "mismatch in sparse file chunks and \ + entry size in header", + )); + } + Ok(()) + } +} + +impl<'a> Iterator for EntriesFields<'a> { + type Item = io::Result<Entry<'a, io::Empty>>; + + fn next(&mut self) -> Option<io::Result<Entry<'a, io::Empty>>> { + if self.done { + None + } else { + match self.next_entry() { + Ok(Some(e)) => Some(Ok(e)), + Ok(None) => { + self.done = true; + None + } + Err(e) => { + self.done = true; + Some(Err(e)) + } + } + } + } +} + +impl<'a, R: ?Sized + Read> Read for &'a ArchiveInner<R> { + fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { + self.obj.borrow_mut().read(into).map(|i| { + self.pos.set(self.pos.get() + i as u64); + i + }) + } +} + +/// Try to fill the buffer from the reader. +/// +/// If the reader reaches its end before filling the buffer at all, returns `false`. +/// Otherwise returns `true`. +fn try_read_all<R: Read>(r: &mut R, buf: &mut [u8]) -> io::Result<bool> { + let mut read = 0; + while read < buf.len() { + match r.read(&mut buf[read..])? { + 0 => { + if read == 0 { + return Ok(false); + } + + return Err(other("failed to read entire block")); + } + n => read += n, + } + } + Ok(true) +} diff --git a/tar/src/builder.rs b/tar/src/builder.rs new file mode 100644 index 000000000..de24f593b --- /dev/null +++ b/tar/src/builder.rs @@ -0,0 +1,535 @@ +use std::borrow::Cow; +use std::fs; +use std::io; +use std::io::prelude::*; +use std::path::Path; + +use crate::header::{bytes2path, path2bytes, HeaderMode}; +use crate::{other, EntryType, Header}; + +/// A structure for building archives +/// +/// This structure has methods for building up an archive from scratch into any +/// arbitrary writer. +pub struct Builder<W: Write> { + mode: HeaderMode, + follow: bool, + finished: bool, + obj: Option<W>, +} + +impl<W: Write> Builder<W> { + /// Create a new archive builder with the underlying object as the + /// destination of all data written. The builder will use + /// `HeaderMode::Complete` by default. + pub fn new(obj: W) -> Builder<W> { + Builder { + mode: HeaderMode::Complete, + follow: true, + finished: false, + obj: Some(obj), + } + } + + /// Changes the HeaderMode that will be used when reading fs Metadata for + /// methods that implicitly read metadata for an input Path. Notably, this + /// does _not_ apply to `append(Header)`. + pub fn mode(&mut self, mode: HeaderMode) { + self.mode = mode; + } + + /// Follow symlinks, archiving the contents of the file they point to rather + /// than adding a symlink to the archive. Defaults to true. + pub fn follow_symlinks(&mut self, follow: bool) { + self.follow = follow; + } + + /// Gets shared reference to the underlying object. + pub fn get_ref(&self) -> &W { + self.obj.as_ref().unwrap() + } + + /// Gets mutable reference to the underlying object. + /// + /// Note that care must be taken while writing to the underlying + /// object. But, e.g. `get_mut().flush()` is clamed to be safe and + /// useful in the situations when one needs to be ensured that + /// tar entry was flushed to the disk. + pub fn get_mut(&mut self) -> &mut W { + self.obj.as_mut().unwrap() + } + + /// Unwrap this archive, returning the underlying object. + /// + /// This function will finish writing the archive if the `finish` function + /// hasn't yet been called, returning any I/O error which happens during + /// that operation. + pub fn into_inner(mut self) -> io::Result<W> { + if !self.finished { + self.finish()?; + } + Ok(self.obj.take().unwrap()) + } + + /// Adds a new entry to this archive. + /// + /// This function will append the header specified, followed by contents of + /// the stream specified by `data`. To produce a valid archive the `size` + /// field of `header` must be the same as the length of the stream that's + /// being written. Additionally the checksum for the header should have been + /// set via the `set_cksum` method. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all entries have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Errors + /// + /// This function will return an error for any intermittent I/O error which + /// occurs when either reading or writing. + /// + /// # Examples + /// + /// ``` + /// use tar::{Builder, Header}; + /// + /// let mut header = Header::new_gnu(); + /// header.set_path("foo").unwrap(); + /// header.set_size(4); + /// header.set_cksum(); + /// + /// let mut data: &[u8] = &[1, 2, 3, 4]; + /// + /// let mut ar = Builder::new(Vec::new()); + /// ar.append(&header, data).unwrap(); + /// let data = ar.into_inner().unwrap(); + /// ``` + pub fn append<R: Read>(&mut self, header: &Header, mut data: R) -> io::Result<()> { + append(self.get_mut(), header, &mut data) + } + + /// Adds a new entry to this archive with the specified path. + /// + /// This function will set the specified path in the given header, which may + /// require appending a GNU long-name extension entry to the archive first. + /// The checksum for the header will be automatically updated via the + /// `set_cksum` method after setting the path. No other metadata in the + /// header will be modified. + /// + /// Then it will append the header, followed by contents of the stream + /// specified by `data`. To produce a valid archive the `size` field of + /// `header` must be the same as the length of the stream that's being + /// written. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all entries have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Errors + /// + /// This function will return an error for any intermittent I/O error which + /// occurs when either reading or writing. + /// + /// # Examples + /// + /// ``` + /// use tar::{Builder, Header}; + /// + /// let mut header = Header::new_gnu(); + /// header.set_size(4); + /// header.set_cksum(); + /// + /// let mut data: &[u8] = &[1, 2, 3, 4]; + /// + /// let mut ar = Builder::new(Vec::new()); + /// ar.append_data(&mut header, "really/long/path/to/foo", data).unwrap(); + /// let data = ar.into_inner().unwrap(); + /// ``` + pub fn append_data<P: AsRef<Path>, R: Read>( + &mut self, + header: &mut Header, + path: P, + data: R, + ) -> io::Result<()> { + prepare_header_path(self.get_mut(), header, path.as_ref())?; + header.set_cksum(); + self.append(&header, data) + } + + /// Adds a file on the local filesystem to this archive. + /// + /// This function will open the file specified by `path` and insert the file + /// into the archive with the appropriate metadata set, returning any I/O + /// error which occurs while writing. The path name for the file inside of + /// this archive will be the same as `path`, and it is required that the + /// path is a relative path. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all files have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Examples + /// + /// ```no_run + /// use tar::Builder; + /// + /// let mut ar = Builder::new(Vec::new()); + /// + /// ar.append_path("foo/bar.txt").unwrap(); + /// ``` + pub fn append_path<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> { + let mode = self.mode.clone(); + let follow = self.follow; + append_path_with_name(self.get_mut(), path.as_ref(), None, mode, follow) + } + + /// Adds a file on the local filesystem to this archive under another name. + /// + /// This function will open the file specified by `path` and insert the file + /// into the archive as `name` with appropriate metadata set, returning any + /// I/O error which occurs while writing. The path name for the file inside + /// of this archive will be `name` and `path` is required to be a relative + /// path. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all files have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Examples + /// + /// ```no_run + /// use tar::Builder; + /// + /// let mut ar = Builder::new(Vec::new()); + /// + /// // Insert the local file "foo/bar.txt" in the archive but with the name + /// // "bar/foo.txt". + /// ar.append_path_with_name("foo/bar.txt", "bar/foo.txt").unwrap(); + /// ``` + pub fn append_path_with_name<P: AsRef<Path>, N: AsRef<Path>>( + &mut self, + path: P, + name: N, + ) -> io::Result<()> { + let mode = self.mode.clone(); + let follow = self.follow; + append_path_with_name( + self.get_mut(), + path.as_ref(), + Some(name.as_ref()), + mode, + follow, + ) + } + + /// Adds a file to this archive with the given path as the name of the file + /// in the archive. + /// + /// This will use the metadata of `file` to populate a `Header`, and it will + /// then append the file to the archive with the name `path`. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all files have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use tar::Builder; + /// + /// let mut ar = Builder::new(Vec::new()); + /// + /// // Open the file at one location, but insert it into the archive with a + /// // different name. + /// let mut f = File::open("foo/bar/baz.txt").unwrap(); + /// ar.append_file("bar/baz.txt", &mut f).unwrap(); + /// ``` + pub fn append_file<P: AsRef<Path>>(&mut self, path: P, file: &mut fs::File) -> io::Result<()> { + let mode = self.mode.clone(); + append_file(self.get_mut(), path.as_ref(), file, mode) + } + + /// Adds a directory to this archive with the given path as the name of the + /// directory in the archive. + /// + /// This will use `stat` to populate a `Header`, and it will then append the + /// directory to the archive with the name `path`. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all files have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use tar::Builder; + /// + /// let mut ar = Builder::new(Vec::new()); + /// + /// // Use the directory at one location, but insert it into the archive + /// // with a different name. + /// ar.append_dir("bardir", ".").unwrap(); + /// ``` + pub fn append_dir<P, Q>(&mut self, path: P, src_path: Q) -> io::Result<()> + where + P: AsRef<Path>, + Q: AsRef<Path>, + { + let mode = self.mode.clone(); + append_dir(self.get_mut(), path.as_ref(), src_path.as_ref(), mode) + } + + /// Adds a directory and all of its contents (recursively) to this archive + /// with the given path as the name of the directory in the archive. + /// + /// Note that this will not attempt to seek the archive to a valid position, + /// so if the archive is in the middle of a read or some other similar + /// operation then this may corrupt the archive. + /// + /// Also note that after all files have been written to an archive the + /// `finish` function needs to be called to finish writing the archive. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use tar::Builder; + /// + /// let mut ar = Builder::new(Vec::new()); + /// + /// // Use the directory at one location, but insert it into the archive + /// // with a different name. + /// ar.append_dir_all("bardir", ".").unwrap(); + /// ``` + pub fn append_dir_all<P, Q>(&mut self, path: P, src_path: Q) -> io::Result<()> + where + P: AsRef<Path>, + Q: AsRef<Path>, + { + let mode = self.mode.clone(); + let follow = self.follow; + append_dir_all( + self.get_mut(), + path.as_ref(), + src_path.as_ref(), + mode, + follow, + ) + } + + /// Finish writing this archive, emitting the termination sections. + /// + /// This function should only be called when the archive has been written + /// entirely and if an I/O error happens the underlying object still needs + /// to be acquired. + /// + /// In most situations the `into_inner` method should be preferred. + pub fn finish(&mut self) -> io::Result<()> { + if self.finished { + return Ok(()); + } + self.finished = true; + self.get_mut().write_all(&[0; 1024]) + } +} + +fn append(mut dst: &mut Write, header: &Header, mut data: &mut Read) -> io::Result<()> { + dst.write_all(header.as_bytes())?; + let len = io::copy(&mut data, &mut dst)?; + + // Pad with zeros if necessary. + let buf = [0; 512]; + let remaining = 512 - (len % 512); + if remaining < 512 { + dst.write_all(&buf[..remaining as usize])?; + } + + Ok(()) +} + +fn append_path_with_name( + dst: &mut Write, + path: &Path, + name: Option<&Path>, + mode: HeaderMode, + follow: bool, +) -> io::Result<()> { + let stat = if follow { + fs::metadata(path).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting metadata for {}", err, path.display()), + ) + })? + } else { + fs::symlink_metadata(path).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting metadata for {}", err, path.display()), + ) + })? + }; + let ar_name = name.unwrap_or(path); + if stat.is_file() { + append_fs(dst, ar_name, &stat, &mut fs::File::open(path)?, mode, None) + } else if stat.is_dir() { + append_fs(dst, ar_name, &stat, &mut io::empty(), mode, None) + } else if stat.file_type().is_symlink() { + let link_name = fs::read_link(path)?; + append_fs( + dst, + ar_name, + &stat, + &mut io::empty(), + mode, + Some(&link_name), + ) + } else { + Err(other(&format!("{} has unknown file type", path.display()))) + } +} + +fn append_file( + dst: &mut Write, + path: &Path, + file: &mut fs::File, + mode: HeaderMode, +) -> io::Result<()> { + let stat = file.metadata()?; + append_fs(dst, path, &stat, file, mode, None) +} + +fn append_dir(dst: &mut Write, path: &Path, src_path: &Path, mode: HeaderMode) -> io::Result<()> { + let stat = fs::metadata(src_path)?; + append_fs(dst, path, &stat, &mut io::empty(), mode, None) +} + +fn prepare_header(size: u64, entry_type: u8) -> Header { + let mut header = Header::new_gnu(); + let name = b"././@LongLink"; + header.as_gnu_mut().unwrap().name[..name.len()].clone_from_slice(&name[..]); + header.set_mode(0o644); + header.set_uid(0); + header.set_gid(0); + header.set_mtime(0); + // + 1 to be compliant with GNU tar + header.set_size(size + 1); + header.set_entry_type(EntryType::new(entry_type)); + header.set_cksum(); + header +} + +fn prepare_header_path(dst: &mut Write, header: &mut Header, path: &Path) -> io::Result<()> { + // Try to encode the path directly in the header, but if it ends up not + // working (probably because it's too long) then try to use the GNU-specific + // long name extension by emitting an entry which indicates that it's the + // filename. + if let Err(e) = header.set_path(path) { + let data = path2bytes(&path)?; + let max = header.as_old().name.len(); + // Since e isn't specific enough to let us know the path is indeed too + // long, verify it first before using the extension. + if data.len() < max { + return Err(e); + } + let header2 = prepare_header(data.len() as u64, b'L'); + // null-terminated string + let mut data2 = data.chain(io::repeat(0).take(1)); + append(dst, &header2, &mut data2)?; + // Truncate the path to store in the header we're about to emit to + // ensure we've got something at least mentioned. + let path = bytes2path(Cow::Borrowed(&data[..max]))?; + header.set_path(&path)?; + } + Ok(()) +} + +fn prepare_header_link(dst: &mut Write, header: &mut Header, link_name: &Path) -> io::Result<()> { + // Same as previous function but for linkname + if let Err(e) = header.set_link_name(&link_name) { + let data = path2bytes(&link_name)?; + if data.len() < header.as_old().linkname.len() { + return Err(e); + } + let header2 = prepare_header(data.len() as u64, b'K'); + let mut data2 = data.chain(io::repeat(0).take(1)); + append(dst, &header2, &mut data2)?; + } + Ok(()) +} + +fn append_fs( + dst: &mut Write, + path: &Path, + meta: &fs::Metadata, + read: &mut Read, + mode: HeaderMode, + link_name: Option<&Path>, +) -> io::Result<()> { + let mut header = Header::new_gnu(); + + prepare_header_path(dst, &mut header, path)?; + header.set_metadata_in_mode(meta, mode); + if let Some(link_name) = link_name { + prepare_header_link(dst, &mut header, link_name)?; + } + header.set_cksum(); + append(dst, &header, read) +} + +fn append_dir_all( + dst: &mut Write, + path: &Path, + src_path: &Path, + mode: HeaderMode, + follow: bool, +) -> io::Result<()> { + let mut stack = vec![(src_path.to_path_buf(), true, false)]; + while let Some((src, is_dir, is_symlink)) = stack.pop() { + let dest = path.join(src.strip_prefix(&src_path).unwrap()); + // In case of a symlink pointing to a directory, is_dir is false, but src.is_dir() will return true + if is_dir || (is_symlink && follow && src.is_dir()) { + for entry in fs::read_dir(&src)? { + let entry = entry?; + let file_type = entry.file_type()?; + stack.push((entry.path(), file_type.is_dir(), file_type.is_symlink())); + } + if dest != Path::new("") { + append_dir(dst, &dest, &src, mode)?; + } + } else if !follow && is_symlink { + let stat = fs::symlink_metadata(&src)?; + let link_name = fs::read_link(&src)?; + append_fs(dst, &dest, &stat, &mut io::empty(), mode, Some(&link_name))?; + } else { + append_file(dst, &dest, &mut fs::File::open(src)?, mode)?; + } + } + Ok(()) +} + +impl<W: Write> Drop for Builder<W> { + fn drop(&mut self) { + let _ = self.finish(); + } +} diff --git a/tar/src/entry.rs b/tar/src/entry.rs new file mode 100644 index 000000000..52b5a3df8 --- /dev/null +++ b/tar/src/entry.rs @@ -0,0 +1,781 @@ +use std::borrow::Cow; +use std::cmp; +use std::fs; +use std::fs::OpenOptions; +use std::io::prelude::*; +use std::io::{self, Error, ErrorKind, SeekFrom}; +use std::marker; +use std::path::{Component, Path, PathBuf}; + +use filetime::{self, FileTime}; + +use crate::archive::ArchiveInner; +use crate::error::TarError; +use crate::header::bytes2path; +use crate::other; +use crate::pax::pax_extensions; +use crate::{Archive, Header, PaxExtensions}; + +/// A read-only view into an entry of an archive. +/// +/// This structure is a window into a portion of a borrowed archive which can +/// be inspected. It acts as a file handle by implementing the Reader trait. An +/// entry cannot be rewritten once inserted into an archive. +pub struct Entry<'a, R: 'a + Read> { + fields: EntryFields<'a>, + _ignored: marker::PhantomData<&'a Archive<R>>, +} + +// private implementation detail of `Entry`, but concrete (no type parameters) +// and also all-public to be constructed from other modules. +pub struct EntryFields<'a> { + pub long_pathname: Option<Vec<u8>>, + pub long_linkname: Option<Vec<u8>>, + pub pax_extensions: Option<Vec<u8>>, + pub header: Header, + pub size: u64, + pub header_pos: u64, + pub file_pos: u64, + pub data: Vec<EntryIo<'a>>, + pub unpack_xattrs: bool, + pub preserve_permissions: bool, + pub preserve_mtime: bool, +} + +pub enum EntryIo<'a> { + Pad(io::Take<io::Repeat>), + Data(io::Take<&'a ArchiveInner<Read + 'a>>), +} + +/// When unpacking items the unpacked thing is returned to allow custom +/// additional handling by users. Today the File is returned, in future +/// the enum may be extended with kinds for links, directories etc. +#[derive(Debug)] +pub enum Unpacked { + /// A file was unpacked. + File(std::fs::File), + /// A directory, hardlink, symlink, or other node was unpacked. + #[doc(hidden)] + __Nonexhaustive, +} + +impl<'a, R: Read> Entry<'a, R> { + /// Returns the path name for this entry. + /// + /// This method may fail if the pathname is not valid unicode and this is + /// called on a Windows platform. + /// + /// Note that this function will convert any `\` characters to directory + /// separators, and it will not always return the same value as + /// `self.header().path()` as some archive formats have support for longer + /// path names described in separate entries. + /// + /// It is recommended to use this method instead of inspecting the `header` + /// directly to ensure that various archive formats are handled correctly. + pub fn path(&self) -> io::Result<Cow<Path>> { + self.fields.path() + } + + /// Returns the raw bytes listed for this entry. + /// + /// Note that this function will convert any `\` characters to directory + /// separators, and it will not always return the same value as + /// `self.header().path_bytes()` as some archive formats have support for + /// longer path names described in separate entries. + pub fn path_bytes(&self) -> Cow<[u8]> { + self.fields.path_bytes() + } + + /// Returns the link name for this entry, if any is found. + /// + /// This method may fail if the pathname is not valid unicode and this is + /// called on a Windows platform. `Ok(None)` being returned, however, + /// indicates that the link name was not present. + /// + /// Note that this function will convert any `\` characters to directory + /// separators, and it will not always return the same value as + /// `self.header().link_name()` as some archive formats have support for + /// longer path names described in separate entries. + /// + /// It is recommended to use this method instead of inspecting the `header` + /// directly to ensure that various archive formats are handled correctly. + pub fn link_name(&self) -> io::Result<Option<Cow<Path>>> { + self.fields.link_name() + } + + /// Returns the link name for this entry, in bytes, if listed. + /// + /// Note that this will not always return the same value as + /// `self.header().link_name_bytes()` as some archive formats have support for + /// longer path names described in separate entries. + pub fn link_name_bytes(&self) -> Option<Cow<[u8]>> { + self.fields.link_name_bytes() + } + + /// Returns an iterator over the pax extensions contained in this entry. + /// + /// Pax extensions are a form of archive where extra metadata is stored in + /// key/value pairs in entries before the entry they're intended to + /// describe. For example this can be used to describe long file name or + /// other metadata like atime/ctime/mtime in more precision. + /// + /// The returned iterator will yield key/value pairs for each extension. + /// + /// `None` will be returned if this entry does not indicate that it itself + /// contains extensions, or if there were no previous extensions describing + /// it. + /// + /// Note that global pax extensions are intended to be applied to all + /// archive entries. + /// + /// Also note that this function will read the entire entry if the entry + /// itself is a list of extensions. + pub fn pax_extensions(&mut self) -> io::Result<Option<PaxExtensions>> { + self.fields.pax_extensions() + } + + /// Returns access to the header of this entry in the archive. + /// + /// This provides access to the the metadata for this entry in the archive. + pub fn header(&self) -> &Header { + &self.fields.header + } + + /// Returns the starting position, in bytes, of the header of this entry in + /// the archive. + /// + /// The header is always a contiguous section of 512 bytes, so if the + /// underlying reader implements `Seek`, then the slice from `header_pos` to + /// `header_pos + 512` contains the raw header bytes. + pub fn raw_header_position(&self) -> u64 { + self.fields.header_pos + } + + /// Returns the starting position, in bytes, of the file of this entry in + /// the archive. + /// + /// If the file of this entry is continuous (e.g. not a sparse file), and + /// if the underlying reader implements `Seek`, then the slice from + /// `file_pos` to `file_pos + entry_size` contains the raw file bytes. + pub fn raw_file_position(&self) -> u64 { + self.fields.file_pos + } + + /// Writes this file to the specified location. + /// + /// This function will write the entire contents of this file into the + /// location specified by `dst`. Metadata will also be propagated to the + /// path `dst`. + /// + /// This function will create a file at the path `dst`, and it is required + /// that the intermediate directories are created. Any existing file at the + /// location `dst` will be overwritten. + /// + /// > **Note**: This function does not have as many sanity checks as + /// > `Archive::unpack` or `Entry::unpack_in`. As a result if you're + /// > thinking of unpacking untrusted tarballs you may want to review the + /// > implementations of the previous two functions and perhaps implement + /// > similar logic yourself. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use tar::Archive; + /// + /// let mut ar = Archive::new(File::open("foo.tar").unwrap()); + /// + /// for (i, file) in ar.entries().unwrap().enumerate() { + /// let mut file = file.unwrap(); + /// file.unpack(format!("file-{}", i)).unwrap(); + /// } + /// ``` + pub fn unpack<P: AsRef<Path>>(&mut self, dst: P) -> io::Result<Unpacked> { + self.fields.unpack(None, dst.as_ref()) + } + + /// Extracts this file under the specified path, avoiding security issues. + /// + /// This function will write the entire contents of this file into the + /// location obtained by appending the path of this file in the archive to + /// `dst`, creating any intermediate directories if needed. Metadata will + /// also be propagated to the path `dst`. Any existing file at the location + /// `dst` will be overwritten. + /// + /// This function carefully avoids writing outside of `dst`. If the file has + /// a '..' in its path, this function will skip it and return false. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use tar::Archive; + /// + /// let mut ar = Archive::new(File::open("foo.tar").unwrap()); + /// + /// for (i, file) in ar.entries().unwrap().enumerate() { + /// let mut file = file.unwrap(); + /// file.unpack_in("target").unwrap(); + /// } + /// ``` + pub fn unpack_in<P: AsRef<Path>>(&mut self, dst: P) -> io::Result<bool> { + self.fields.unpack_in(dst.as_ref()) + } + + /// Indicate whether extended file attributes (xattrs on Unix) are preserved + /// when unpacking this entry. + /// + /// This flag is disabled by default and is currently only implemented on + /// Unix using xattr support. This may eventually be implemented for + /// Windows, however, if other archive implementations are found which do + /// this as well. + pub fn set_unpack_xattrs(&mut self, unpack_xattrs: bool) { + self.fields.unpack_xattrs = unpack_xattrs; + } + + /// Indicate whether extended permissions (like suid on Unix) are preserved + /// when unpacking this entry. + /// + /// This flag is disabled by default and is currently only implemented on + /// Unix. + pub fn set_preserve_permissions(&mut self, preserve: bool) { + self.fields.preserve_permissions = preserve; + } + + /// Indicate whether access time information is preserved when unpacking + /// this entry. + /// + /// This flag is enabled by default. + pub fn set_preserve_mtime(&mut self, preserve: bool) { + self.fields.preserve_mtime = preserve; + } +} + +impl<'a, R: Read> Read for Entry<'a, R> { + fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { + self.fields.read(into) + } +} + +impl<'a> EntryFields<'a> { + pub fn from<R: Read>(entry: Entry<R>) -> EntryFields { + entry.fields + } + + pub fn into_entry<R: Read>(self) -> Entry<'a, R> { + Entry { + fields: self, + _ignored: marker::PhantomData, + } + } + + pub fn read_all(&mut self) -> io::Result<Vec<u8>> { + // Preallocate some data but don't let ourselves get too crazy now. + let cap = cmp::min(self.size, 128 * 1024); + let mut v = Vec::with_capacity(cap as usize); + self.read_to_end(&mut v).map(|_| v) + } + + fn path(&self) -> io::Result<Cow<Path>> { + bytes2path(self.path_bytes()) + } + + fn path_bytes(&self) -> Cow<[u8]> { + match self.long_pathname { + Some(ref bytes) => { + if let Some(&0) = bytes.last() { + Cow::Borrowed(&bytes[..bytes.len() - 1]) + } else { + Cow::Borrowed(bytes) + } + } + None => { + if let Some(ref pax) = self.pax_extensions { + let pax = pax_extensions(pax) + .filter_map(|f| f.ok()) + .find(|f| f.key_bytes() == b"path") + .map(|f| f.value_bytes()); + if let Some(field) = pax { + return Cow::Borrowed(field); + } + } + self.header.path_bytes() + } + } + } + + /// Gets the path in a "lossy" way, used for error reporting ONLY. + fn path_lossy(&self) -> String { + String::from_utf8_lossy(&self.path_bytes()).to_string() + } + + fn link_name(&self) -> io::Result<Option<Cow<Path>>> { + match self.link_name_bytes() { + Some(bytes) => bytes2path(bytes).map(Some), + None => Ok(None), + } + } + + fn link_name_bytes(&self) -> Option<Cow<[u8]>> { + match self.long_linkname { + Some(ref bytes) => { + if let Some(&0) = bytes.last() { + Some(Cow::Borrowed(&bytes[..bytes.len() - 1])) + } else { + Some(Cow::Borrowed(bytes)) + } + } + None => self.header.link_name_bytes(), + } + } + + fn pax_extensions(&mut self) -> io::Result<Option<PaxExtensions>> { + if self.pax_extensions.is_none() { + if !self.header.entry_type().is_pax_global_extensions() + && !self.header.entry_type().is_pax_local_extensions() + { + return Ok(None); + } + self.pax_extensions = Some(self.read_all()?); + } + Ok(Some(pax_extensions(self.pax_extensions.as_ref().unwrap()))) + } + + fn unpack_in(&mut self, dst: &Path) -> io::Result<bool> { + // Notes regarding bsdtar 2.8.3 / libarchive 2.8.3: + // * Leading '/'s are trimmed. For example, `///test` is treated as + // `test`. + // * If the filename contains '..', then the file is skipped when + // extracting the tarball. + // * '//' within a filename is effectively skipped. An error is + // logged, but otherwise the effect is as if any two or more + // adjacent '/'s within the filename were consolidated into one + // '/'. + // + // Most of this is handled by the `path` module of the standard + // library, but we specially handle a few cases here as well. + + let mut file_dst = dst.to_path_buf(); + { + let path = self.path().map_err(|e| { + TarError::new( + &format!("invalid path in entry header: {}", self.path_lossy()), + e, + ) + })?; + for part in path.components() { + match part { + // Leading '/' characters, root paths, and '.' + // components are just ignored and treated as "empty + // components" + Component::Prefix(..) | Component::RootDir | Component::CurDir => continue, + + // If any part of the filename is '..', then skip over + // unpacking the file to prevent directory traversal + // security issues. See, e.g.: CVE-2001-1267, + // CVE-2002-0399, CVE-2005-1918, CVE-2007-4131 + Component::ParentDir => return Ok(false), + + Component::Normal(part) => file_dst.push(part), + } + } + } + + // Skip cases where only slashes or '.' parts were seen, because + // this is effectively an empty filename. + if *dst == *file_dst { + return Ok(true); + } + + // Skip entries without a parent (i.e. outside of FS root) + let parent = match file_dst.parent() { + Some(p) => p, + None => return Ok(false), + }; + + if parent.symlink_metadata().is_err() { + fs::create_dir_all(&parent).map_err(|e| { + TarError::new(&format!("failed to create `{}`", parent.display()), e) + })?; + } + + let canon_target = self.validate_inside_dst(&dst, parent)?; + + self.unpack(Some(&canon_target), &file_dst) + .map_err(|e| TarError::new(&format!("failed to unpack `{}`", file_dst.display()), e))?; + + Ok(true) + } + + /// Unpack as destination directory `dst`. + fn unpack_dir(&mut self, dst: &Path) -> io::Result<()> { + // If the directory already exists just let it slide + fs::create_dir(dst).or_else(|err| { + if err.kind() == ErrorKind::AlreadyExists { + let prev = fs::metadata(dst); + if prev.map(|m| m.is_dir()).unwrap_or(false) { + return Ok(()); + } + } + Err(Error::new( + err.kind(), + format!("{} when creating dir {}", err, dst.display()), + )) + }) + } + + /// Returns access to the header of this entry in the archive. + fn unpack(&mut self, target_base: Option<&Path>, dst: &Path) -> io::Result<Unpacked> { + let kind = self.header.entry_type(); + + if kind.is_dir() { + self.unpack_dir(dst)?; + if let Ok(mode) = self.header.mode() { + set_perms(dst, None, mode, self.preserve_permissions)?; + } + return Ok(Unpacked::__Nonexhaustive); + } else if kind.is_hard_link() || kind.is_symlink() { + let src = match self.link_name()? { + Some(name) => name, + None => { + return Err(other(&format!( + "hard link listed for {} but no link name found", + String::from_utf8_lossy(self.header.as_bytes()) + ))); + } + }; + + if src.iter().count() == 0 { + return Err(other(&format!( + "symlink destination for {} is empty", + String::from_utf8_lossy(self.header.as_bytes()) + ))); + } + + if kind.is_hard_link() { + let link_src = match target_base { + // If we're unpacking within a directory then ensure that + // the destination of this hard link is both present and + // inside our own directory. This is needed because we want + // to make sure to not overwrite anything outside the root. + // + // Note that this logic is only needed for hard links + // currently. With symlinks the `validate_inside_dst` which + // happens before this method as part of `unpack_in` will + // use canonicalization to ensure this guarantee. For hard + // links though they're canonicalized to their existing path + // so we need to validate at this time. + Some(ref p) => { + let link_src = p.join(src); + self.validate_inside_dst(p, &link_src)?; + link_src + } + None => src.into_owned(), + }; + fs::hard_link(&link_src, dst).map_err(|err| { + Error::new( + err.kind(), + format!( + "{} when hard linking {} to {}", + err, + link_src.display(), + dst.display() + ), + ) + })?; + } else { + symlink(&src, dst).map_err(|err| { + Error::new( + err.kind(), + format!( + "{} when symlinking {} to {}", + err, + src.display(), + dst.display() + ), + ) + })?; + }; + return Ok(Unpacked::__Nonexhaustive); + + #[cfg(target_arch = "wasm32")] + #[allow(unused_variables)] + fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) + } + + #[cfg(windows)] + fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + ::std::os::windows::fs::symlink_file(src, dst) + } + + #[cfg(any(unix, target_os = "redox"))] + fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + ::std::os::unix::fs::symlink(src, dst) + } + } else if kind.is_pax_global_extensions() + || kind.is_pax_local_extensions() + || kind.is_gnu_longname() + || kind.is_gnu_longlink() + { + return Ok(Unpacked::__Nonexhaustive); + }; + + // Old BSD-tar compatibility. + // Names that have a trailing slash should be treated as a directory. + // Only applies to old headers. + if self.header.as_ustar().is_none() && self.path_bytes().ends_with(b"/") { + self.unpack_dir(dst)?; + if let Ok(mode) = self.header.mode() { + set_perms(dst, None, mode, self.preserve_permissions)?; + } + return Ok(Unpacked::__Nonexhaustive); + } + + // Note the lack of `else` clause above. According to the FreeBSD + // documentation: + // + // > A POSIX-compliant implementation must treat any unrecognized + // > typeflag value as a regular file. + // + // As a result if we don't recognize the kind we just write out the file + // as we would normally. + + // Ensure we write a new file rather than overwriting in-place which + // is attackable; if an existing file is found unlink it. + fn open(dst: &Path) -> io::Result<std::fs::File> { + OpenOptions::new().write(true).create_new(true).open(dst) + }; + let mut f = (|| -> io::Result<std::fs::File> { + let mut f = open(dst).or_else(|err| { + if err.kind() != ErrorKind::AlreadyExists { + Err(err) + } else { + match fs::remove_file(dst) { + Ok(()) => open(dst), + Err(ref e) if e.kind() == io::ErrorKind::NotFound => open(dst), + Err(e) => Err(e), + } + } + })?; + for io in self.data.drain(..) { + match io { + EntryIo::Data(mut d) => { + let expected = d.limit(); + if io::copy(&mut d, &mut f)? != expected { + return Err(other("failed to write entire file")); + } + } + EntryIo::Pad(d) => { + // TODO: checked cast to i64 + let to = SeekFrom::Current(d.limit() as i64); + let size = f.seek(to)?; + f.set_len(size)?; + } + } + } + Ok(f) + })() + .map_err(|e| { + let header = self.header.path_bytes(); + TarError::new( + &format!( + "failed to unpack `{}` into `{}`", + String::from_utf8_lossy(&header), + dst.display() + ), + e, + ) + })?; + + if self.preserve_mtime { + if let Ok(mtime) = self.header.mtime() { + let mtime = FileTime::from_unix_time(mtime as i64, 0); + filetime::set_file_handle_times(&f, Some(mtime), Some(mtime)).map_err(|e| { + TarError::new(&format!("failed to set mtime for `{}`", dst.display()), e) + })?; + } + } + if let Ok(mode) = self.header.mode() { + set_perms(dst, Some(&mut f), mode, self.preserve_permissions)?; + } + if self.unpack_xattrs { + set_xattrs(self, dst)?; + } + return Ok(Unpacked::File(f)); + + fn set_perms( + dst: &Path, + f: Option<&mut std::fs::File>, + mode: u32, + preserve: bool, + ) -> Result<(), TarError> { + _set_perms(dst, f, mode, preserve).map_err(|e| { + TarError::new( + &format!( + "failed to set permissions to {:o} \ + for `{}`", + mode, + dst.display() + ), + e, + ) + }) + } + + #[cfg(any(unix, target_os = "redox"))] + fn _set_perms( + dst: &Path, + f: Option<&mut std::fs::File>, + mode: u32, + preserve: bool, + ) -> io::Result<()> { + use std::os::unix::prelude::*; + + let mode = if preserve { mode } else { mode & 0o777 }; + let perm = fs::Permissions::from_mode(mode as _); + match f { + Some(f) => f.set_permissions(perm), + None => fs::set_permissions(dst, perm), + } + } + + #[cfg(windows)] + fn _set_perms( + dst: &Path, + f: Option<&mut std::fs::File>, + mode: u32, + _preserve: bool, + ) -> io::Result<()> { + if mode & 0o200 == 0o200 { + return Ok(()); + } + match f { + Some(f) => { + let mut perm = f.metadata()?.permissions(); + perm.set_readonly(true); + f.set_permissions(perm) + } + None => { + let mut perm = fs::metadata(dst)?.permissions(); + perm.set_readonly(true); + fs::set_permissions(dst, perm) + } + } + } + + #[cfg(target_arch = "wasm32")] + #[allow(unused_variables)] + fn _set_perms( + dst: &Path, + f: Option<&mut std::fs::File>, + mode: u32, + _preserve: bool, + ) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) + } + + #[cfg(all(unix, feature = "xattr"))] + fn set_xattrs(me: &mut EntryFields, dst: &Path) -> io::Result<()> { + use std::ffi::OsStr; + use std::os::unix::prelude::*; + + let exts = match me.pax_extensions() { + Ok(Some(e)) => e, + _ => return Ok(()), + }; + let exts = exts + .filter_map(|e| e.ok()) + .filter_map(|e| { + let key = e.key_bytes(); + let prefix = b"SCHILY.xattr."; + if key.starts_with(prefix) { + Some((&key[prefix.len()..], e)) + } else { + None + } + }) + .map(|(key, e)| (OsStr::from_bytes(key), e.value_bytes())); + + for (key, value) in exts { + xattr::set(dst, key, value).map_err(|e| { + TarError::new( + &format!( + "failed to set extended \ + attributes to {}. \ + Xattrs: key={:?}, value={:?}.", + dst.display(), + key, + String::from_utf8_lossy(value) + ), + e, + ) + })?; + } + + Ok(()) + } + // Windows does not completely support posix xattrs + // https://en.wikipedia.org/wiki/Extended_file_attributes#Windows_NT + #[cfg(any( + windows, + target_os = "redox", + not(feature = "xattr"), + target_arch = "wasm32" + ))] + fn set_xattrs(_: &mut EntryFields, _: &Path) -> io::Result<()> { + Ok(()) + } + } + + fn validate_inside_dst(&self, dst: &Path, file_dst: &Path) -> io::Result<PathBuf> { + // Abort if target (canonical) parent is outside of `dst` + let canon_parent = file_dst.canonicalize().map_err(|err| { + Error::new( + err.kind(), + format!("{} while canonicalizing {}", err, file_dst.display()), + ) + })?; + let canon_target = dst.canonicalize().map_err(|err| { + Error::new( + err.kind(), + format!("{} while canonicalizing {}", err, dst.display()), + ) + })?; + if !canon_parent.starts_with(&canon_target) { + let err = TarError::new( + &format!( + "trying to unpack outside of destination path: {}", + canon_target.display() + ), + // TODO: use ErrorKind::InvalidInput here? (minor breaking change) + Error::new(ErrorKind::Other, "Invalid argument"), + ); + return Err(err.into()); + } + Ok(canon_target) + } +} + +impl<'a> Read for EntryFields<'a> { + fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { + loop { + match self.data.get_mut(0).map(|io| io.read(into)) { + Some(Ok(0)) => { + self.data.remove(0); + } + Some(r) => return r, + None => return Ok(0), + } + } + } +} + +impl<'a> Read for EntryIo<'a> { + fn read(&mut self, into: &mut [u8]) -> io::Result<usize> { + match *self { + EntryIo::Pad(ref mut io) => io.read(into), + EntryIo::Data(ref mut io) => io.read(into), + } + } +} diff --git a/tar/src/entry_type.rs b/tar/src/entry_type.rs new file mode 100644 index 000000000..951388d57 --- /dev/null +++ b/tar/src/entry_type.rs @@ -0,0 +1,193 @@ +// See https://en.wikipedia.org/wiki/Tar_%28computing%29#UStar_format +/// Indicate for the type of file described by a header. +/// +/// Each `Header` has an `entry_type` method returning an instance of this type +/// which can be used to inspect what the header is describing. + +/// A non-exhaustive enum representing the possible entry types +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum EntryType { + /// Regular file + Regular, + /// Hard link + Link, + /// Symbolic link + Symlink, + /// Character device + Char, + /// Block device + Block, + /// Directory + Directory, + /// Named pipe (fifo) + Fifo, + /// Implementation-defined 'high-performance' type, treated as regular file + Continuous, + /// GNU extension - long file name + GNULongName, + /// GNU extension - long link name (link target) + GNULongLink, + /// GNU extension - sparse file + GNUSparse, + /// Global extended header + XGlobalHeader, + /// Extended Header + XHeader, + /// Hints that destructuring should not be exhaustive. + /// + /// This enum may grow additional variants, so this makes sure clients + /// don't count on exhaustive matching. (Otherwise, adding a new variant + /// could break existing code.) + #[doc(hidden)] + __Nonexhaustive(u8), +} + +impl EntryType { + /// Creates a new entry type from a raw byte. + /// + /// Note that the other named constructors of entry type may be more + /// appropriate to create a file type from. + pub fn new(byte: u8) -> EntryType { + match byte { + b'\x00' | b'0' => EntryType::Regular, + b'1' => EntryType::Link, + b'2' => EntryType::Symlink, + b'3' => EntryType::Char, + b'4' => EntryType::Block, + b'5' => EntryType::Directory, + b'6' => EntryType::Fifo, + b'7' => EntryType::Continuous, + b'x' => EntryType::XHeader, + b'g' => EntryType::XGlobalHeader, + b'L' => EntryType::GNULongName, + b'K' => EntryType::GNULongLink, + b'S' => EntryType::GNUSparse, + b => EntryType::__Nonexhaustive(b), + } + } + + /// Returns the raw underlying byte that this entry type represents. + pub fn as_byte(&self) -> u8 { + match *self { + EntryType::Regular => b'0', + EntryType::Link => b'1', + EntryType::Symlink => b'2', + EntryType::Char => b'3', + EntryType::Block => b'4', + EntryType::Directory => b'5', + EntryType::Fifo => b'6', + EntryType::Continuous => b'7', + EntryType::XHeader => b'x', + EntryType::XGlobalHeader => b'g', + EntryType::GNULongName => b'L', + EntryType::GNULongLink => b'K', + EntryType::GNUSparse => b'S', + EntryType::__Nonexhaustive(b) => b, + } + } + + /// Creates a new entry type representing a regular file. + pub fn file() -> EntryType { + EntryType::Regular + } + + /// Creates a new entry type representing a hard link. + pub fn hard_link() -> EntryType { + EntryType::Link + } + + /// Creates a new entry type representing a symlink. + pub fn symlink() -> EntryType { + EntryType::Symlink + } + + /// Creates a new entry type representing a character special device. + pub fn character_special() -> EntryType { + EntryType::Char + } + + /// Creates a new entry type representing a block special device. + pub fn block_special() -> EntryType { + EntryType::Block + } + + /// Creates a new entry type representing a directory. + pub fn dir() -> EntryType { + EntryType::Directory + } + + /// Creates a new entry type representing a FIFO. + pub fn fifo() -> EntryType { + EntryType::Fifo + } + + /// Creates a new entry type representing a contiguous file. + pub fn contiguous() -> EntryType { + EntryType::Continuous + } + + /// Returns whether this type represents a regular file. + pub fn is_file(&self) -> bool { + self == &EntryType::Regular + } + + /// Returns whether this type represents a hard link. + pub fn is_hard_link(&self) -> bool { + self == &EntryType::Link + } + + /// Returns whether this type represents a symlink. + pub fn is_symlink(&self) -> bool { + self == &EntryType::Symlink + } + + /// Returns whether this type represents a character special device. + pub fn is_character_special(&self) -> bool { + self == &EntryType::Char + } + + /// Returns whether this type represents a block special device. + pub fn is_block_special(&self) -> bool { + self == &EntryType::Block + } + + /// Returns whether this type represents a directory. + pub fn is_dir(&self) -> bool { + self == &EntryType::Directory + } + + /// Returns whether this type represents a FIFO. + pub fn is_fifo(&self) -> bool { + self == &EntryType::Fifo + } + + /// Returns whether this type represents a contiguous file. + pub fn is_contiguous(&self) -> bool { + self == &EntryType::Continuous + } + + /// Returns whether this type represents a GNU long name header. + pub fn is_gnu_longname(&self) -> bool { + self == &EntryType::GNULongName + } + + /// Returns whether this type represents a GNU sparse header. + pub fn is_gnu_sparse(&self) -> bool { + self == &EntryType::GNUSparse + } + + /// Returns whether this type represents a GNU long link header. + pub fn is_gnu_longlink(&self) -> bool { + self == &EntryType::GNULongLink + } + + /// Returns whether this type represents a GNU long name header. + pub fn is_pax_global_extensions(&self) -> bool { + self == &EntryType::XGlobalHeader + } + + /// Returns whether this type represents a GNU long link header. + pub fn is_pax_local_extensions(&self) -> bool { + self == &EntryType::XHeader + } +} diff --git a/tar/src/error.rs b/tar/src/error.rs new file mode 100644 index 000000000..bfe6af9c3 --- /dev/null +++ b/tar/src/error.rs @@ -0,0 +1,40 @@ +use std::error; +use std::fmt; +use std::io::{self, Error}; + +#[derive(Debug)] +pub struct TarError { + desc: String, + io: io::Error, +} + +impl TarError { + pub fn new(desc: &str, err: Error) -> TarError { + TarError { + desc: desc.to_string(), + io: err, + } + } +} + +impl error::Error for TarError { + fn description(&self) -> &str { + &self.desc + } + + fn source(&self) -> Option<&(error::Error + 'static)> { + Some(&self.io) + } +} + +impl fmt::Display for TarError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.desc.fmt(f) + } +} + +impl From<TarError> for Error { + fn from(t: TarError) -> Error { + Error::new(t.io.kind(), t) + } +} diff --git a/tar/src/header.rs b/tar/src/header.rs new file mode 100644 index 000000000..2a79a5f68 --- /dev/null +++ b/tar/src/header.rs @@ -0,0 +1,1626 @@ +#[cfg(any(unix, target_os = "redox"))] +use std::os::unix::prelude::*; +#[cfg(windows)] +use std::os::windows::prelude::*; + +use std::borrow::Cow; +use std::fmt; +use std::fs; +use std::io; +use std::iter; +use std::iter::repeat; +use std::mem; +use std::path::{Component, Path, PathBuf}; +use std::str; + +use crate::other; +use crate::EntryType; + +/// Representation of the header of an entry in an archive +#[repr(C)] +#[allow(missing_docs)] +pub struct Header { + bytes: [u8; 512], +} + +/// Declares the information that should be included when filling a Header +/// from filesystem metadata. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum HeaderMode { + /// All supported metadata, including mod/access times and ownership will + /// be included. + Complete, + + /// Only metadata that is directly relevant to the identity of a file will + /// be included. In particular, ownership and mod/access times are excluded. + Deterministic, + + #[doc(hidden)] + __Nonexhaustive, +} + +/// Representation of the header of an entry in an archive +#[repr(C)] +#[allow(missing_docs)] +pub struct OldHeader { + pub name: [u8; 100], + pub mode: [u8; 8], + pub uid: [u8; 8], + pub gid: [u8; 8], + pub size: [u8; 12], + pub mtime: [u8; 12], + pub cksum: [u8; 8], + pub linkflag: [u8; 1], + pub linkname: [u8; 100], + pub pad: [u8; 255], +} + +/// Representation of the header of an entry in an archive +#[repr(C)] +#[allow(missing_docs)] +pub struct UstarHeader { + pub name: [u8; 100], + pub mode: [u8; 8], + pub uid: [u8; 8], + pub gid: [u8; 8], + pub size: [u8; 12], + pub mtime: [u8; 12], + pub cksum: [u8; 8], + pub typeflag: [u8; 1], + pub linkname: [u8; 100], + + // UStar format + pub magic: [u8; 6], + pub version: [u8; 2], + pub uname: [u8; 32], + pub gname: [u8; 32], + pub dev_major: [u8; 8], + pub dev_minor: [u8; 8], + pub prefix: [u8; 155], + pub pad: [u8; 12], +} + +/// Representation of the header of an entry in an archive +#[repr(C)] +#[allow(missing_docs)] +pub struct GnuHeader { + pub name: [u8; 100], + pub mode: [u8; 8], + pub uid: [u8; 8], + pub gid: [u8; 8], + pub size: [u8; 12], + pub mtime: [u8; 12], + pub cksum: [u8; 8], + pub typeflag: [u8; 1], + pub linkname: [u8; 100], + + // GNU format + pub magic: [u8; 6], + pub version: [u8; 2], + pub uname: [u8; 32], + pub gname: [u8; 32], + pub dev_major: [u8; 8], + pub dev_minor: [u8; 8], + pub atime: [u8; 12], + pub ctime: [u8; 12], + pub offset: [u8; 12], + pub longnames: [u8; 4], + pub unused: [u8; 1], + pub sparse: [GnuSparseHeader; 4], + pub isextended: [u8; 1], + pub realsize: [u8; 12], + pub pad: [u8; 17], +} + +/// Description of the header of a spare entry. +/// +/// Specifies the offset/number of bytes of a chunk of data in octal. +#[repr(C)] +#[allow(missing_docs)] +pub struct GnuSparseHeader { + pub offset: [u8; 12], + pub numbytes: [u8; 12], +} + +/// Representation of the entry found to represent extended GNU sparse files. +/// +/// When a `GnuHeader` has the `isextended` flag set to `1` then the contents of +/// the next entry will be one of these headers. +#[repr(C)] +#[allow(missing_docs)] +pub struct GnuExtSparseHeader { + pub sparse: [GnuSparseHeader; 21], + pub isextended: [u8; 1], + pub padding: [u8; 7], +} + +impl Header { + /// Creates a new blank GNU header. + /// + /// The GNU style header is the default for this library and allows various + /// extensions such as long path names, long link names, and setting the + /// atime/ctime metadata attributes of files. + pub fn new_gnu() -> Header { + let mut header = Header { bytes: [0; 512] }; + unsafe { + let gnu = cast_mut::<_, GnuHeader>(&mut header); + gnu.magic = *b"ustar "; + gnu.version = *b" \0"; + } + header.set_mtime(0); + header + } + + /// Creates a new blank UStar header. + /// + /// The UStar style header is an extension of the original archive header + /// which enables some extra metadata along with storing a longer (but not + /// too long) path name. + /// + /// UStar is also the basis used for pax archives. + pub fn new_ustar() -> Header { + let mut header = Header { bytes: [0; 512] }; + unsafe { + let gnu = cast_mut::<_, UstarHeader>(&mut header); + gnu.magic = *b"ustar\0"; + gnu.version = *b"00"; + } + header.set_mtime(0); + header + } + + /// Creates a new blank old header. + /// + /// This header format is the original archive header format which all other + /// versions are compatible with (e.g. they are a superset). This header + /// format limits the path name limit and isn't able to contain extra + /// metadata like atime/ctime. + pub fn new_old() -> Header { + let mut header = Header { bytes: [0; 512] }; + header.set_mtime(0); + header + } + + fn is_ustar(&self) -> bool { + let ustar = unsafe { cast::<_, UstarHeader>(self) }; + ustar.magic[..] == b"ustar\0"[..] && ustar.version[..] == b"00"[..] + } + + fn is_gnu(&self) -> bool { + let ustar = unsafe { cast::<_, UstarHeader>(self) }; + ustar.magic[..] == b"ustar "[..] && ustar.version[..] == b" \0"[..] + } + + /// View this archive header as a raw "old" archive header. + /// + /// This view will always succeed as all archive header formats will fill + /// out at least the fields specified in the old header format. + pub fn as_old(&self) -> &OldHeader { + unsafe { cast(self) } + } + + /// Same as `as_old`, but the mutable version. + pub fn as_old_mut(&mut self) -> &mut OldHeader { + unsafe { cast_mut(self) } + } + + /// View this archive header as a raw UStar archive header. + /// + /// The UStar format is an extension to the tar archive format which enables + /// longer pathnames and a few extra attributes such as the group and user + /// name. + /// + /// This cast may not succeed as this function will test whether the + /// magic/version fields of the UStar format have the appropriate values, + /// returning `None` if they aren't correct. + pub fn as_ustar(&self) -> Option<&UstarHeader> { + if self.is_ustar() { + Some(unsafe { cast(self) }) + } else { + None + } + } + + /// Same as `as_ustar_mut`, but the mutable version. + pub fn as_ustar_mut(&mut self) -> Option<&mut UstarHeader> { + if self.is_ustar() { + Some(unsafe { cast_mut(self) }) + } else { + None + } + } + + /// View this archive header as a raw GNU archive header. + /// + /// The GNU format is an extension to the tar archive format which enables + /// longer pathnames and a few extra attributes such as the group and user + /// name. + /// + /// This cast may not succeed as this function will test whether the + /// magic/version fields of the GNU format have the appropriate values, + /// returning `None` if they aren't correct. + pub fn as_gnu(&self) -> Option<&GnuHeader> { + if self.is_gnu() { + Some(unsafe { cast(self) }) + } else { + None + } + } + + /// Same as `as_gnu`, but the mutable version. + pub fn as_gnu_mut(&mut self) -> Option<&mut GnuHeader> { + if self.is_gnu() { + Some(unsafe { cast_mut(self) }) + } else { + None + } + } + + /// Treats the given byte slice as a header. + /// + /// Panics if the length of the passed slice is not equal to 512. + pub fn from_byte_slice(bytes: &[u8]) -> &Header { + assert_eq!(bytes.len(), mem::size_of::<Header>()); + assert_eq!(mem::align_of_val(bytes), mem::align_of::<Header>()); + unsafe { &*(bytes.as_ptr() as *const Header) } + } + + /// Returns a view into this header as a byte array. + pub fn as_bytes(&self) -> &[u8; 512] { + &self.bytes + } + + /// Returns a view into this header as a byte array. + pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] { + &mut self.bytes + } + + /// Blanket sets the metadata in this header from the metadata argument + /// provided. + /// + /// This is useful for initializing a `Header` from the OS's metadata from a + /// file. By default, this will use `HeaderMode::Complete` to include all + /// metadata. + pub fn set_metadata(&mut self, meta: &fs::Metadata) { + self.fill_from(meta, HeaderMode::Complete); + } + + /// Sets only the metadata relevant to the given HeaderMode in this header + /// from the metadata argument provided. + pub fn set_metadata_in_mode(&mut self, meta: &fs::Metadata, mode: HeaderMode) { + self.fill_from(meta, mode); + } + + /// Returns the size of entry's data this header represents. + /// + /// This is different from `Header::size` for sparse files, which have + /// some longer `size()` but shorter `entry_size()`. The `entry_size()` + /// listed here should be the number of bytes in the archive this header + /// describes. + /// + /// May return an error if the field is corrupted. + pub fn entry_size(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.as_old().size).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting size for {}", err, self.path_lossy()), + ) + }) + } + + /// Returns the file size this header represents. + /// + /// May return an error if the field is corrupted. + pub fn size(&self) -> io::Result<u64> { + if self.entry_type().is_gnu_sparse() { + self.as_gnu() + .ok_or_else(|| other("sparse header was not a gnu header")) + .and_then(|h| h.real_size()) + } else { + self.entry_size() + } + } + + /// Encodes the `size` argument into the size field of this header. + pub fn set_size(&mut self, size: u64) { + num_field_wrapper_into(&mut self.as_old_mut().size, size); + } + + /// Returns the raw path name stored in this header. + /// + /// This method may fail if the pathname is not valid unicode and this is + /// called on a Windows platform. + /// + /// Note that this function will convert any `\` characters to directory + /// separators. + pub fn path(&self) -> io::Result<Cow<Path>> { + bytes2path(self.path_bytes()) + } + + /// Returns the pathname stored in this header as a byte array. + /// + /// This function is guaranteed to succeed, but you may wish to call the + /// `path` method to convert to a `Path`. + /// + /// Note that this function will convert any `\` characters to directory + /// separators. + pub fn path_bytes(&self) -> Cow<[u8]> { + if let Some(ustar) = self.as_ustar() { + ustar.path_bytes() + } else { + let name = truncate(&self.as_old().name); + Cow::Borrowed(name) + } + } + + /// Gets the path in a "lossy" way, used for error reporting ONLY. + fn path_lossy(&self) -> String { + String::from_utf8_lossy(&self.path_bytes()).to_string() + } + + /// Sets the path name for this header. + /// + /// This function will set the pathname listed in this header, encoding it + /// in the appropriate format. May fail if the path is too long or if the + /// path specified is not unicode and this is a Windows platform. + pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> { + self._set_path(p.as_ref()) + } + + fn _set_path(&mut self, path: &Path) -> io::Result<()> { + if let Some(ustar) = self.as_ustar_mut() { + return ustar.set_path(path); + } + copy_path_into(&mut self.as_old_mut().name, path, false).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting path for {}", err, self.path_lossy()), + ) + }) + } + + /// Returns the link name stored in this header, if any is found. + /// + /// This method may fail if the pathname is not valid unicode and this is + /// called on a Windows platform. `Ok(None)` being returned, however, + /// indicates that the link name was not present. + /// + /// Note that this function will convert any `\` characters to directory + /// separators. + pub fn link_name(&self) -> io::Result<Option<Cow<Path>>> { + match self.link_name_bytes() { + Some(bytes) => bytes2path(bytes).map(Some), + None => Ok(None), + } + } + + /// Returns the link name stored in this header as a byte array, if any. + /// + /// This function is guaranteed to succeed, but you may wish to call the + /// `link_name` method to convert to a `Path`. + /// + /// Note that this function will convert any `\` characters to directory + /// separators. + pub fn link_name_bytes(&self) -> Option<Cow<[u8]>> { + let old = self.as_old(); + if old.linkname[0] != 0 { + Some(Cow::Borrowed(truncate(&old.linkname))) + } else { + None + } + } + + /// Sets the link name for this header. + /// + /// This function will set the linkname listed in this header, encoding it + /// in the appropriate format. May fail if the link name is too long or if + /// the path specified is not unicode and this is a Windows platform. + pub fn set_link_name<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> { + self._set_link_name(p.as_ref()) + } + + fn _set_link_name(&mut self, path: &Path) -> io::Result<()> { + copy_path_into(&mut self.as_old_mut().linkname, path, true).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting link name for {}", err, self.path_lossy()), + ) + }) + } + + /// Returns the mode bits for this file + /// + /// May return an error if the field is corrupted. + pub fn mode(&self) -> io::Result<u32> { + octal_from(&self.as_old().mode) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting mode for {}", err, self.path_lossy()), + ) + }) + } + + /// Encodes the `mode` provided into this header. + pub fn set_mode(&mut self, mode: u32) { + octal_into(&mut self.as_old_mut().mode, mode); + } + + /// Returns the value of the owner's user ID field + /// + /// May return an error if the field is corrupted. + pub fn uid(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.as_old().uid) + .map(|u| u as u64) + .map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting uid for {}", err, self.path_lossy()), + ) + }) + } + + /// Encodes the `uid` provided into this header. + pub fn set_uid(&mut self, uid: u64) { + num_field_wrapper_into(&mut self.as_old_mut().uid, uid); + } + + /// Returns the value of the group's user ID field + pub fn gid(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.as_old().gid) + .map(|u| u as u64) + .map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting gid for {}", err, self.path_lossy()), + ) + }) + } + + /// Encodes the `gid` provided into this header. + pub fn set_gid(&mut self, gid: u64) { + num_field_wrapper_into(&mut self.as_old_mut().gid, gid); + } + + /// Returns the last modification time in Unix time format + pub fn mtime(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.as_old().mtime).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting mtime for {}", err, self.path_lossy()), + ) + }) + } + + /// Encodes the `mtime` provided into this header. + /// + /// Note that this time is typically a number of seconds passed since + /// January 1, 1970. + pub fn set_mtime(&mut self, mtime: u64) { + num_field_wrapper_into(&mut self.as_old_mut().mtime, mtime); + } + + /// Return the user name of the owner of this file. + /// + /// A return value of `Ok(Some(..))` indicates that the user name was + /// present and was valid utf-8, `Ok(None)` indicates that the user name is + /// not present in this archive format, and `Err` indicates that the user + /// name was present but was not valid utf-8. + pub fn username(&self) -> Result<Option<&str>, str::Utf8Error> { + match self.username_bytes() { + Some(bytes) => str::from_utf8(bytes).map(Some), + None => Ok(None), + } + } + + /// Returns the user name of the owner of this file, if present. + /// + /// A return value of `None` indicates that the user name is not present in + /// this header format. + pub fn username_bytes(&self) -> Option<&[u8]> { + if let Some(ustar) = self.as_ustar() { + Some(ustar.username_bytes()) + } else if let Some(gnu) = self.as_gnu() { + Some(gnu.username_bytes()) + } else { + None + } + } + + /// Sets the username inside this header. + /// + /// This function will return an error if this header format cannot encode a + /// user name or the name is too long. + pub fn set_username(&mut self, name: &str) -> io::Result<()> { + if let Some(ustar) = self.as_ustar_mut() { + return ustar.set_username(name); + } + if let Some(gnu) = self.as_gnu_mut() { + gnu.set_username(name) + } else { + Err(other("not a ustar or gnu archive, cannot set username")) + } + } + + /// Return the group name of the owner of this file. + /// + /// A return value of `Ok(Some(..))` indicates that the group name was + /// present and was valid utf-8, `Ok(None)` indicates that the group name is + /// not present in this archive format, and `Err` indicates that the group + /// name was present but was not valid utf-8. + pub fn groupname(&self) -> Result<Option<&str>, str::Utf8Error> { + match self.groupname_bytes() { + Some(bytes) => str::from_utf8(bytes).map(Some), + None => Ok(None), + } + } + + /// Returns the group name of the owner of this file, if present. + /// + /// A return value of `None` indicates that the group name is not present in + /// this header format. + pub fn groupname_bytes(&self) -> Option<&[u8]> { + if let Some(ustar) = self.as_ustar() { + Some(ustar.groupname_bytes()) + } else if let Some(gnu) = self.as_gnu() { + Some(gnu.groupname_bytes()) + } else { + None + } + } + + /// Sets the group name inside this header. + /// + /// This function will return an error if this header format cannot encode a + /// group name or the name is too long. + pub fn set_groupname(&mut self, name: &str) -> io::Result<()> { + if let Some(ustar) = self.as_ustar_mut() { + return ustar.set_groupname(name); + } + if let Some(gnu) = self.as_gnu_mut() { + gnu.set_groupname(name) + } else { + Err(other("not a ustar or gnu archive, cannot set groupname")) + } + } + + /// Returns the device major number, if present. + /// + /// This field may not be present in all archives, and it may not be + /// correctly formed in all archives. `Ok(Some(..))` means it was present + /// and correctly decoded, `Ok(None)` indicates that this header format does + /// not include the device major number, and `Err` indicates that it was + /// present and failed to decode. + pub fn device_major(&self) -> io::Result<Option<u32>> { + if let Some(ustar) = self.as_ustar() { + ustar.device_major().map(Some) + } else if let Some(gnu) = self.as_gnu() { + gnu.device_major().map(Some) + } else { + Ok(None) + } + } + + /// Encodes the value `major` into the dev_major field of this header. + /// + /// This function will return an error if this header format cannot encode a + /// major device number. + pub fn set_device_major(&mut self, major: u32) -> io::Result<()> { + if let Some(ustar) = self.as_ustar_mut() { + return Ok(ustar.set_device_major(major)); + } + if let Some(gnu) = self.as_gnu_mut() { + Ok(gnu.set_device_major(major)) + } else { + Err(other("not a ustar or gnu archive, cannot set dev_major")) + } + } + + /// Returns the device minor number, if present. + /// + /// This field may not be present in all archives, and it may not be + /// correctly formed in all archives. `Ok(Some(..))` means it was present + /// and correctly decoded, `Ok(None)` indicates that this header format does + /// not include the device minor number, and `Err` indicates that it was + /// present and failed to decode. + pub fn device_minor(&self) -> io::Result<Option<u32>> { + if let Some(ustar) = self.as_ustar() { + ustar.device_minor().map(Some) + } else if let Some(gnu) = self.as_gnu() { + gnu.device_minor().map(Some) + } else { + Ok(None) + } + } + + /// Encodes the value `minor` into the dev_minor field of this header. + /// + /// This function will return an error if this header format cannot encode a + /// minor device number. + pub fn set_device_minor(&mut self, minor: u32) -> io::Result<()> { + if let Some(ustar) = self.as_ustar_mut() { + return Ok(ustar.set_device_minor(minor)); + } + if let Some(gnu) = self.as_gnu_mut() { + Ok(gnu.set_device_minor(minor)) + } else { + Err(other("not a ustar or gnu archive, cannot set dev_minor")) + } + } + + /// Returns the type of file described by this header. + pub fn entry_type(&self) -> EntryType { + EntryType::new(self.as_old().linkflag[0]) + } + + /// Sets the type of file that will be described by this header. + pub fn set_entry_type(&mut self, ty: EntryType) { + self.as_old_mut().linkflag = [ty.as_byte()]; + } + + /// Returns the checksum field of this header. + /// + /// May return an error if the field is corrupted. + pub fn cksum(&self) -> io::Result<u32> { + octal_from(&self.as_old().cksum) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting cksum for {}", err, self.path_lossy()), + ) + }) + } + + /// Sets the checksum field of this header based on the current fields in + /// this header. + pub fn set_cksum(&mut self) { + let cksum = self.calculate_cksum(); + octal_into(&mut self.as_old_mut().cksum, cksum); + } + + fn calculate_cksum(&self) -> u32 { + let old = self.as_old(); + let start = old as *const _ as usize; + let cksum_start = old.cksum.as_ptr() as *const _ as usize; + let offset = cksum_start - start; + let len = old.cksum.len(); + self.bytes[0..offset] + .iter() + .chain(iter::repeat(&b' ').take(len)) + .chain(&self.bytes[offset + len..]) + .fold(0, |a, b| a + (*b as u32)) + } + + fn fill_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) { + self.fill_platform_from(meta, mode); + // Set size of directories to zero + self.set_size(if meta.is_dir() || meta.file_type().is_symlink() { + 0 + } else { + meta.len() + }); + if let Some(ustar) = self.as_ustar_mut() { + ustar.set_device_major(0); + ustar.set_device_minor(0); + } + if let Some(gnu) = self.as_gnu_mut() { + gnu.set_device_major(0); + gnu.set_device_minor(0); + } + } + + #[cfg(target_arch = "wasm32")] + #[allow(unused_variables)] + fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) { + unimplemented!(); + } + + #[cfg(any(unix, target_os = "redox"))] + fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) { + match mode { + HeaderMode::Complete => { + self.set_mtime(meta.mtime() as u64); + self.set_uid(meta.uid() as u64); + self.set_gid(meta.gid() as u64); + self.set_mode(meta.mode() as u32); + } + HeaderMode::Deterministic => { + self.set_mtime(0); + self.set_uid(0); + self.set_gid(0); + + // Use a default umask value, but propagate the (user) execute bit. + let fs_mode = if meta.is_dir() || (0o100 & meta.mode() == 0o100) { + 0o755 + } else { + 0o644 + }; + self.set_mode(fs_mode); + } + HeaderMode::__Nonexhaustive => panic!(), + } + + // Note that if we are a GNU header we *could* set atime/ctime, except + // the `tar` utility doesn't do that by default and it causes problems + // with 7-zip [1]. + // + // It's always possible to fill them out manually, so we just don't fill + // it out automatically here. + // + // [1]: https://github.com/alexcrichton/tar-rs/issues/70 + + // TODO: need to bind more file types + self.set_entry_type(entry_type(meta.mode())); + + #[cfg(not(target_os = "redox"))] + fn entry_type(mode: u32) -> EntryType { + match mode as libc::mode_t & libc::S_IFMT { + libc::S_IFREG => EntryType::file(), + libc::S_IFLNK => EntryType::symlink(), + libc::S_IFCHR => EntryType::character_special(), + libc::S_IFBLK => EntryType::block_special(), + libc::S_IFDIR => EntryType::dir(), + libc::S_IFIFO => EntryType::fifo(), + _ => EntryType::new(b' '), + } + } + + #[cfg(target_os = "redox")] + fn entry_type(mode: u32) -> EntryType { + use syscall; + match mode as u16 & syscall::MODE_TYPE { + syscall::MODE_FILE => EntryType::file(), + syscall::MODE_SYMLINK => EntryType::symlink(), + syscall::MODE_DIR => EntryType::dir(), + _ => EntryType::new(b' '), + } + } + } + + #[cfg(windows)] + fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) { + // There's no concept of a file mode on windows, so do a best approximation here. + match mode { + HeaderMode::Complete => { + self.set_uid(0); + self.set_gid(0); + // The dates listed in tarballs are always seconds relative to + // January 1, 1970. On Windows, however, the timestamps are returned as + // dates relative to January 1, 1601 (in 100ns intervals), so we need to + // add in some offset for those dates. + let mtime = (meta.last_write_time() / (1_000_000_000 / 100)) - 11644473600; + self.set_mtime(mtime); + let fs_mode = { + const FILE_ATTRIBUTE_READONLY: u32 = 0x00000001; + let readonly = meta.file_attributes() & FILE_ATTRIBUTE_READONLY; + match (meta.is_dir(), readonly != 0) { + (true, false) => 0o755, + (true, true) => 0o555, + (false, false) => 0o644, + (false, true) => 0o444, + } + }; + self.set_mode(fs_mode); + } + HeaderMode::Deterministic => { + self.set_uid(0); + self.set_gid(0); + self.set_mtime(0); + let fs_mode = if meta.is_dir() { 0o755 } else { 0o644 }; + self.set_mode(fs_mode); + } + HeaderMode::__Nonexhaustive => panic!(), + } + + let ft = meta.file_type(); + self.set_entry_type(if ft.is_dir() { + EntryType::dir() + } else if ft.is_file() { + EntryType::file() + } else if ft.is_symlink() { + EntryType::symlink() + } else { + EntryType::new(b' ') + }); + } + + fn debug_fields(&self, b: &mut fmt::DebugStruct) { + if let Ok(entry_size) = self.entry_size() { + b.field("entry_size", &entry_size); + } + if let Ok(size) = self.size() { + b.field("size", &size); + } + if let Ok(path) = self.path() { + b.field("path", &path); + } + if let Ok(link_name) = self.link_name() { + b.field("link_name", &link_name); + } + if let Ok(mode) = self.mode() { + b.field("mode", &DebugAsOctal(mode)); + } + if let Ok(uid) = self.uid() { + b.field("uid", &uid); + } + if let Ok(gid) = self.gid() { + b.field("gid", &gid); + } + if let Ok(mtime) = self.mtime() { + b.field("mtime", &mtime); + } + if let Ok(username) = self.username() { + b.field("username", &username); + } + if let Ok(groupname) = self.groupname() { + b.field("groupname", &groupname); + } + if let Ok(device_major) = self.device_major() { + b.field("device_major", &device_major); + } + if let Ok(device_minor) = self.device_minor() { + b.field("device_minor", &device_minor); + } + if let Ok(cksum) = self.cksum() { + b.field("cksum", &cksum); + b.field("cksum_valid", &(cksum == self.calculate_cksum())); + } + } +} + +struct DebugAsOctal<T>(T); + +impl<T: fmt::Octal> fmt::Debug for DebugAsOctal<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Octal::fmt(&self.0, f) + } +} + +unsafe fn cast<T, U>(a: &T) -> &U { + assert_eq!(mem::size_of_val(a), mem::size_of::<U>()); + assert_eq!(mem::align_of_val(a), mem::align_of::<U>()); + &*(a as *const T as *const U) +} + +unsafe fn cast_mut<T, U>(a: &mut T) -> &mut U { + assert_eq!(mem::size_of_val(a), mem::size_of::<U>()); + assert_eq!(mem::align_of_val(a), mem::align_of::<U>()); + &mut *(a as *mut T as *mut U) +} + +impl Clone for Header { + fn clone(&self) -> Header { + Header { bytes: self.bytes } + } +} + +impl fmt::Debug for Header { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(me) = self.as_ustar() { + me.fmt(f) + } else if let Some(me) = self.as_gnu() { + me.fmt(f) + } else { + self.as_old().fmt(f) + } + } +} + +impl OldHeader { + /// Views this as a normal `Header` + pub fn as_header(&self) -> &Header { + unsafe { cast(self) } + } + + /// Views this as a normal `Header` + pub fn as_header_mut(&mut self) -> &mut Header { + unsafe { cast_mut(self) } + } +} + +impl fmt::Debug for OldHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("OldHeader"); + self.as_header().debug_fields(&mut f); + f.finish() + } +} + +impl UstarHeader { + /// See `Header::path_bytes` + pub fn path_bytes(&self) -> Cow<[u8]> { + if self.prefix[0] == 0 && !self.name.contains(&b'\\') { + Cow::Borrowed(truncate(&self.name)) + } else { + let mut bytes = Vec::new(); + let prefix = truncate(&self.prefix); + if prefix.len() > 0 { + bytes.extend_from_slice(prefix); + bytes.push(b'/'); + } + bytes.extend_from_slice(truncate(&self.name)); + Cow::Owned(bytes) + } + } + + /// Gets the path in a "lossy" way, used for error reporting ONLY. + fn path_lossy(&self) -> String { + String::from_utf8_lossy(&self.path_bytes()).to_string() + } + + /// See `Header::set_path` + pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> { + self._set_path(p.as_ref()) + } + + fn _set_path(&mut self, path: &Path) -> io::Result<()> { + // This can probably be optimized quite a bit more, but for now just do + // something that's relatively easy and readable. + // + // First up, if the path fits within `self.name` then we just shove it + // in there. If not then we try to split it between some existing path + // components where it can fit in name/prefix. To do that we peel off + // enough until the path fits in `prefix`, then we try to put both + // halves into their destination. + let bytes = path2bytes(path)?; + let (maxnamelen, maxprefixlen) = (self.name.len(), self.prefix.len()); + if bytes.len() <= maxnamelen { + copy_path_into(&mut self.name, path, false).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting path for {}", err, self.path_lossy()), + ) + })?; + } else { + let mut prefix = path; + let mut prefixlen; + loop { + match prefix.parent() { + Some(parent) => prefix = parent, + None => { + return Err(other(&format!( + "path cannot be split to be inserted into archive: {}", + path.display() + ))); + } + } + prefixlen = path2bytes(prefix)?.len(); + if prefixlen <= maxprefixlen { + break; + } + } + copy_path_into(&mut self.prefix, prefix, false).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting path for {}", err, self.path_lossy()), + ) + })?; + let path = bytes2path(Cow::Borrowed(&bytes[prefixlen + 1..]))?; + copy_path_into(&mut self.name, &path, false).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting path for {}", err, self.path_lossy()), + ) + })?; + } + Ok(()) + } + + /// See `Header::username_bytes` + pub fn username_bytes(&self) -> &[u8] { + truncate(&self.uname) + } + + /// See `Header::set_username` + pub fn set_username(&mut self, name: &str) -> io::Result<()> { + copy_into(&mut self.uname, name.as_bytes()).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting username for {}", err, self.path_lossy()), + ) + }) + } + + /// See `Header::groupname_bytes` + pub fn groupname_bytes(&self) -> &[u8] { + truncate(&self.gname) + } + + /// See `Header::set_groupname` + pub fn set_groupname(&mut self, name: &str) -> io::Result<()> { + copy_into(&mut self.gname, name.as_bytes()).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when setting groupname for {}", err, self.path_lossy()), + ) + }) + } + + /// See `Header::device_major` + pub fn device_major(&self) -> io::Result<u32> { + octal_from(&self.dev_major) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when getting device_major for {}", + err, + self.path_lossy() + ), + ) + }) + } + + /// See `Header::set_device_major` + pub fn set_device_major(&mut self, major: u32) { + octal_into(&mut self.dev_major, major); + } + + /// See `Header::device_minor` + pub fn device_minor(&self) -> io::Result<u32> { + octal_from(&self.dev_minor) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when getting device_minor for {}", + err, + self.path_lossy() + ), + ) + }) + } + + /// See `Header::set_device_minor` + pub fn set_device_minor(&mut self, minor: u32) { + octal_into(&mut self.dev_minor, minor); + } + + /// Views this as a normal `Header` + pub fn as_header(&self) -> &Header { + unsafe { cast(self) } + } + + /// Views this as a normal `Header` + pub fn as_header_mut(&mut self) -> &mut Header { + unsafe { cast_mut(self) } + } +} + +impl fmt::Debug for UstarHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("UstarHeader"); + self.as_header().debug_fields(&mut f); + f.finish() + } +} + +impl GnuHeader { + /// See `Header::username_bytes` + pub fn username_bytes(&self) -> &[u8] { + truncate(&self.uname) + } + + /// Gets the fullname (group:user) in a "lossy" way, used for error reporting ONLY. + fn fullname_lossy(&self) -> String { + format!( + "{}:{}", + String::from_utf8_lossy(&self.groupname_bytes()), + String::from_utf8_lossy(&self.username_bytes()), + ) + } + + /// See `Header::set_username` + pub fn set_username(&mut self, name: &str) -> io::Result<()> { + copy_into(&mut self.uname, name.as_bytes()).map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when setting username for {}", + err, + self.fullname_lossy() + ), + ) + }) + } + + /// See `Header::groupname_bytes` + pub fn groupname_bytes(&self) -> &[u8] { + truncate(&self.gname) + } + + /// See `Header::set_groupname` + pub fn set_groupname(&mut self, name: &str) -> io::Result<()> { + copy_into(&mut self.gname, name.as_bytes()).map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when setting groupname for {}", + err, + self.fullname_lossy() + ), + ) + }) + } + + /// See `Header::device_major` + pub fn device_major(&self) -> io::Result<u32> { + octal_from(&self.dev_major) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when getting device_major for {}", + err, + self.fullname_lossy() + ), + ) + }) + } + + /// See `Header::set_device_major` + pub fn set_device_major(&mut self, major: u32) { + octal_into(&mut self.dev_major, major); + } + + /// See `Header::device_minor` + pub fn device_minor(&self) -> io::Result<u32> { + octal_from(&self.dev_minor) + .map(|u| u as u32) + .map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when getting device_minor for {}", + err, + self.fullname_lossy() + ), + ) + }) + } + + /// See `Header::set_device_minor` + pub fn set_device_minor(&mut self, minor: u32) { + octal_into(&mut self.dev_minor, minor); + } + + /// Returns the last modification time in Unix time format + pub fn atime(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.atime).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting atime for {}", err, self.fullname_lossy()), + ) + }) + } + + /// Encodes the `atime` provided into this header. + /// + /// Note that this time is typically a number of seconds passed since + /// January 1, 1970. + pub fn set_atime(&mut self, atime: u64) { + num_field_wrapper_into(&mut self.atime, atime); + } + + /// Returns the last modification time in Unix time format + pub fn ctime(&self) -> io::Result<u64> { + num_field_wrapper_from(&self.ctime).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting ctime for {}", err, self.fullname_lossy()), + ) + }) + } + + /// Encodes the `ctime` provided into this header. + /// + /// Note that this time is typically a number of seconds passed since + /// January 1, 1970. + pub fn set_ctime(&mut self, ctime: u64) { + num_field_wrapper_into(&mut self.ctime, ctime); + } + + /// Returns the "real size" of the file this header represents. + /// + /// This is applicable for sparse files where the returned size here is the + /// size of the entire file after the sparse regions have been filled in. + pub fn real_size(&self) -> io::Result<u64> { + octal_from(&self.realsize).map_err(|err| { + io::Error::new( + err.kind(), + format!( + "{} when getting real_size for {}", + err, + self.fullname_lossy() + ), + ) + }) + } + + /// Indicates whether this header will be followed by additional + /// sparse-header records. + /// + /// Note that this is handled internally by this library, and is likely only + /// interesting if a `raw` iterator is being used. + pub fn is_extended(&self) -> bool { + self.isextended[0] == 1 + } + + /// Views this as a normal `Header` + pub fn as_header(&self) -> &Header { + unsafe { cast(self) } + } + + /// Views this as a normal `Header` + pub fn as_header_mut(&mut self) -> &mut Header { + unsafe { cast_mut(self) } + } +} + +impl fmt::Debug for GnuHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("GnuHeader"); + self.as_header().debug_fields(&mut f); + if let Ok(atime) = self.atime() { + f.field("atime", &atime); + } + if let Ok(ctime) = self.ctime() { + f.field("ctime", &ctime); + } + f.field("is_extended", &self.is_extended()) + .field("sparse", &DebugSparseHeaders(&self.sparse)) + .finish() + } +} + +struct DebugSparseHeaders<'a>(&'a [GnuSparseHeader]); + +impl<'a> fmt::Debug for DebugSparseHeaders<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_list(); + for header in self.0 { + if !header.is_empty() { + f.entry(header); + } + } + f.finish() + } +} + +impl GnuSparseHeader { + /// Returns true if block is empty + pub fn is_empty(&self) -> bool { + self.offset[0] == 0 || self.numbytes[0] == 0 + } + + /// Offset of the block from the start of the file + /// + /// Returns `Err` for a malformed `offset` field. + pub fn offset(&self) -> io::Result<u64> { + octal_from(&self.offset).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting offset from sparce header", err), + ) + }) + } + + /// Length of the block + /// + /// Returns `Err` for a malformed `numbytes` field. + pub fn length(&self) -> io::Result<u64> { + octal_from(&self.numbytes).map_err(|err| { + io::Error::new( + err.kind(), + format!("{} when getting length from sparse header", err), + ) + }) + } +} + +impl fmt::Debug for GnuSparseHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("GnuSparseHeader"); + if let Ok(offset) = self.offset() { + f.field("offset", &offset); + } + if let Ok(length) = self.length() { + f.field("length", &length); + } + f.finish() + } +} + +impl GnuExtSparseHeader { + /// Crates a new zero'd out sparse header entry. + pub fn new() -> GnuExtSparseHeader { + unsafe { mem::zeroed() } + } + + /// Returns a view into this header as a byte array. + pub fn as_bytes(&self) -> &[u8; 512] { + debug_assert_eq!(mem::size_of_val(self), 512); + unsafe { mem::transmute(self) } + } + + /// Returns a view into this header as a byte array. + pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] { + debug_assert_eq!(mem::size_of_val(self), 512); + unsafe { mem::transmute(self) } + } + + /// Returns a slice of the underlying sparse headers. + /// + /// Some headers may represent empty chunks of both the offset and numbytes + /// fields are 0. + pub fn sparse(&self) -> &[GnuSparseHeader; 21] { + &self.sparse + } + + /// Indicates if another sparse header should be following this one. + pub fn is_extended(&self) -> bool { + self.isextended[0] == 1 + } +} + +impl Default for GnuExtSparseHeader { + fn default() -> Self { + Self::new() + } +} + +fn octal_from(slice: &[u8]) -> io::Result<u64> { + let trun = truncate(slice); + let num = match str::from_utf8(trun) { + Ok(n) => n, + Err(_) => { + return Err(other(&format!( + "numeric field did not have utf-8 text: {}", + String::from_utf8_lossy(trun) + ))); + } + }; + match u64::from_str_radix(num.trim(), 8) { + Ok(n) => Ok(n), + Err(_) => Err(other(&format!("numeric field was not a number: {}", num))), + } +} + +fn octal_into<T: fmt::Octal>(dst: &mut [u8], val: T) { + let o = format!("{:o}", val); + let value = o.bytes().rev().chain(repeat(b'0')); + for (slot, value) in dst.iter_mut().rev().skip(1).zip(value) { + *slot = value; + } +} + +// Wrapper to figure out if we should fill the header field using tar's numeric +// extension (binary) or not (octal). +fn num_field_wrapper_into(dst: &mut [u8], src: u64) { + if src >= 8589934592 || (src >= 2097152 && dst.len() == 8) { + numeric_extended_into(dst, src); + } else { + octal_into(dst, src); + } +} + +// Wrapper to figure out if we should read the header field in binary (numeric +// extension) or octal (standard encoding). +fn num_field_wrapper_from(src: &[u8]) -> io::Result<u64> { + if src[0] & 0x80 != 0 { + Ok(numeric_extended_from(src)) + } else { + octal_from(src) + } +} + +// When writing numeric fields with is the extended form, the high bit of the +// first byte is set to 1 and the remainder of the field is treated as binary +// instead of octal ascii. +// This handles writing u64 to 8 (uid, gid) or 12 (size, *time) bytes array. +fn numeric_extended_into(dst: &mut [u8], src: u64) { + let len: usize = dst.len(); + for (slot, val) in dst.iter_mut().zip( + repeat(0) + .take(len - 8) // to zero init extra bytes + .chain((0..8).rev().map(|x| ((src >> (8 * x)) & 0xff) as u8)), + ) { + *slot = val; + } + dst[0] |= 0x80; +} + +fn numeric_extended_from(src: &[u8]) -> u64 { + let mut dst: u64 = 0; + let mut b_to_skip = 1; + if src.len() == 8 { + // read first byte without extension flag bit + dst = (src[0] ^ 0x80) as u64; + } else { + // only read last 8 bytes + b_to_skip = src.len() - 8; + } + for byte in src.iter().skip(b_to_skip) { + dst <<= 8; + dst |= *byte as u64; + } + dst +} + +fn truncate(slice: &[u8]) -> &[u8] { + match slice.iter().position(|i| *i == 0) { + Some(i) => &slice[..i], + None => slice, + } +} + +/// Copies `bytes` into the `slot` provided, returning an error if the `bytes` +/// array is too long or if it contains any nul bytes. +fn copy_into(slot: &mut [u8], bytes: &[u8]) -> io::Result<()> { + if bytes.len() > slot.len() { + Err(other("provided value is too long")) + } else if bytes.iter().any(|b| *b == 0) { + Err(other("provided value contains a nul byte")) + } else { + for (slot, val) in slot.iter_mut().zip(bytes.iter().chain(Some(&0))) { + *slot = *val; + } + Ok(()) + } +} + +/// Copies `path` into the `slot` provided +/// +/// Returns an error if: +/// +/// * the path is too long to fit +/// * a nul byte was found +/// * an invalid path component is encountered (e.g. a root path or parent dir) +/// * the path itself is empty +fn copy_path_into(mut slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> { + let mut emitted = false; + let mut needs_slash = false; + for component in path.components() { + let bytes = path2bytes(Path::new(component.as_os_str()))?; + match (component, is_link_name) { + (Component::Prefix(..), false) | (Component::RootDir, false) => { + return Err(other("paths in archives must be relative")); + } + (Component::ParentDir, false) => { + return Err(other("paths in archives must not have `..`")); + } + // Allow "./" as the path + (Component::CurDir, false) if path.components().count() == 1 => {} + (Component::CurDir, false) => continue, + (Component::Normal(_), _) | (_, true) => {} + }; + if needs_slash { + copy(&mut slot, b"/")?; + } + if bytes.contains(&b'/') { + if let Component::Normal(..) = component { + return Err(other("path component in archive cannot contain `/`")); + } + } + copy(&mut slot, &*bytes)?; + if &*bytes != b"/" { + needs_slash = true; + } + emitted = true; + } + if !emitted { + return Err(other("paths in archives must have at least one component")); + } + if ends_with_slash(path) { + copy(&mut slot, &[b'/'])?; + } + return Ok(()); + + fn copy(slot: &mut &mut [u8], bytes: &[u8]) -> io::Result<()> { + copy_into(*slot, bytes)?; + let tmp = mem::replace(slot, &mut []); + *slot = &mut tmp[bytes.len()..]; + Ok(()) + } +} + +#[cfg(target_arch = "wasm32")] +fn ends_with_slash(p: &Path) -> bool { + p.to_string_lossy().ends_with('/') +} + +#[cfg(windows)] +fn ends_with_slash(p: &Path) -> bool { + let last = p.as_os_str().encode_wide().last(); + last == Some(b'/' as u16) || last == Some(b'\\' as u16) +} + +#[cfg(any(unix, target_os = "redox"))] +fn ends_with_slash(p: &Path) -> bool { + p.as_os_str().as_bytes().ends_with(&[b'/']) +} + +#[cfg(any(windows, target_arch = "wasm32"))] +pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> { + p.as_os_str() + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| other(&format!("path {} was not valid unicode", p.display()))) + .map(|bytes| { + if bytes.contains(&b'\\') { + // Normalize to Unix-style path separators + let mut bytes = bytes.to_owned(); + for b in &mut bytes { + if *b == b'\\' { + *b = b'/'; + } + } + Cow::Owned(bytes) + } else { + Cow::Borrowed(bytes) + } + }) +} + +#[cfg(any(unix, target_os = "redox"))] +/// On unix this will never fail +pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> { + Ok(p.as_os_str().as_bytes()).map(Cow::Borrowed) +} + +#[cfg(windows)] +/// On windows we cannot accept non-unicode bytes because it +/// is impossible to convert it to UTF-16. +pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> { + return match bytes { + Cow::Borrowed(bytes) => { + let s = r#try!(str::from_utf8(bytes).map_err(|_| not_unicode(bytes))); + Ok(Cow::Borrowed(Path::new(s))) + } + Cow::Owned(bytes) => { + let s = + r#try!(String::from_utf8(bytes).map_err(|uerr| not_unicode(&uerr.into_bytes()))); + Ok(Cow::Owned(PathBuf::from(s))) + } + }; + + fn not_unicode(v: &[u8]) -> io::Error { + other(&format!( + "only unicode paths are supported on windows: {}", + String::from_utf8_lossy(v) + )) + } +} + +#[cfg(any(unix, target_os = "redox"))] +/// On unix this operation can never fail. +pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> { + use std::ffi::{OsStr, OsString}; + + Ok(match bytes { + Cow::Borrowed(bytes) => Cow::Borrowed({ Path::new(OsStr::from_bytes(bytes)) }), + Cow::Owned(bytes) => Cow::Owned({ PathBuf::from(OsString::from_vec(bytes)) }), + }) +} + +#[cfg(target_arch = "wasm32")] +pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> { + Ok(match bytes { + Cow::Borrowed(bytes) => { + Cow::Borrowed({ Path::new(str::from_utf8(bytes).map_err(invalid_utf8)?) }) + } + Cow::Owned(bytes) => { + Cow::Owned({ PathBuf::from(String::from_utf8(bytes).map_err(invalid_utf8)?) }) + } + }) +} + +#[cfg(target_arch = "wasm32")] +fn invalid_utf8<T>(_: T) -> io::Error { + io::Error::new(io::ErrorKind::InvalidData, "Invalid utf8") +} diff --git a/tar/src/lib.rs b/tar/src/lib.rs new file mode 100644 index 000000000..52251cd2c --- /dev/null +++ b/tar/src/lib.rs @@ -0,0 +1,44 @@ +//! A library for reading and writing TAR archives +//! +//! This library provides utilities necessary to manage [TAR archives][1] +//! abstracted over a reader or writer. Great strides are taken to ensure that +//! an archive is never required to be fully resident in memory, and all objects +//! provide largely a streaming interface to read bytes from. +//! +//! [1]: http://en.wikipedia.org/wiki/Tar_%28computing%29 + +// More docs about the detailed tar format can also be found here: +// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5&manpath=FreeBSD+8-current + +// NB: some of the coding patterns and idioms here may seem a little strange. +// This is currently attempting to expose a super generic interface while +// also not forcing clients to codegen the entire crate each time they use +// it. To that end lots of work is done to ensure that concrete +// implementations are all found in this crate and the generic functions are +// all just super thin wrappers (e.g. easy to codegen). + +#![doc(html_root_url = "https://docs.rs/tar/0.4")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +use std::io::{Error, ErrorKind}; + +pub use crate::archive::{Archive, Entries}; +pub use crate::builder::Builder; +pub use crate::entry::{Entry, Unpacked}; +pub use crate::entry_type::EntryType; +pub use crate::header::GnuExtSparseHeader; +pub use crate::header::{GnuHeader, GnuSparseHeader, Header, HeaderMode, OldHeader, UstarHeader}; +pub use crate::pax::{PaxExtension, PaxExtensions}; + +mod archive; +mod builder; +mod entry; +mod entry_type; +mod error; +mod header; +mod pax; + +fn other(msg: &str) -> Error { + Error::new(ErrorKind::Other, msg) +} diff --git a/tar/src/pax.rs b/tar/src/pax.rs new file mode 100644 index 000000000..e0298d533 --- /dev/null +++ b/tar/src/pax.rs @@ -0,0 +1,91 @@ +use std::io; +use std::slice; +use std::str; + +use crate::other; + +/// An iterator over the pax extensions in an archive entry. +/// +/// This iterator yields structures which can themselves be parsed into +/// key/value pairs. +pub struct PaxExtensions<'entry> { + data: slice::Split<'entry, u8, fn(&u8) -> bool>, +} + +/// A key/value pair corresponding to a pax extension. +pub struct PaxExtension<'entry> { + key: &'entry [u8], + value: &'entry [u8], +} + +pub fn pax_extensions(a: &[u8]) -> PaxExtensions { + fn is_newline(a: &u8) -> bool { + *a == b'\n' + } + PaxExtensions { + data: a.split(is_newline), + } +} + +impl<'entry> Iterator for PaxExtensions<'entry> { + type Item = io::Result<PaxExtension<'entry>>; + + fn next(&mut self) -> Option<io::Result<PaxExtension<'entry>>> { + let line = match self.data.next() { + Some(line) if line.is_empty() => return None, + Some(line) => line, + None => return None, + }; + + Some( + line.iter() + .position(|b| *b == b' ') + .and_then(|i| { + str::from_utf8(&line[..i]) + .ok() + .and_then(|len| len.parse::<usize>().ok().map(|j| (i + 1, j))) + }) + .and_then(|(kvstart, reported_len)| { + if line.len() + 1 == reported_len { + line[kvstart..] + .iter() + .position(|b| *b == b'=') + .map(|equals| (kvstart, equals)) + } else { + None + } + }) + .map(|(kvstart, equals)| PaxExtension { + key: &line[kvstart..kvstart + equals], + value: &line[kvstart + equals + 1..], + }) + .ok_or_else(|| other("malformed pax extension")), + ) + } +} + +impl<'entry> PaxExtension<'entry> { + /// Returns the key for this key/value pair parsed as a string. + /// + /// May fail if the key isn't actually utf-8. + pub fn key(&self) -> Result<&'entry str, str::Utf8Error> { + str::from_utf8(self.key) + } + + /// Returns the underlying raw bytes for the key of this key/value pair. + pub fn key_bytes(&self) -> &'entry [u8] { + self.key + } + + /// Returns the value for this key/value pair parsed as a string. + /// + /// May fail if the value isn't actually utf-8. + pub fn value(&self) -> Result<&'entry str, str::Utf8Error> { + str::from_utf8(self.value) + } + + /// Returns the underlying raw bytes for this value of this key/value pair. + pub fn value_bytes(&self) -> &'entry [u8] { + self.value + } +} diff --git a/tar/tests/all.rs b/tar/tests/all.rs new file mode 100644 index 000000000..254dffbf5 --- /dev/null +++ b/tar/tests/all.rs @@ -0,0 +1,1013 @@ +extern crate filetime; +extern crate tar; +extern crate tempdir; +#[cfg(all(unix, feature = "xattr"))] +extern crate xattr; + +use std::fs::{self, File}; +use std::io::prelude::*; +use std::io::{self, Cursor}; +use std::iter::repeat; +use std::path::{Path, PathBuf}; + +use self::tempdir::TempDir; +use filetime::FileTime; +use tar::{Archive, Builder, EntryType, Header}; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(v) => v, + Err(e) => panic!("{} returned {}", stringify!($e), e), + } + }; +} + +macro_rules! tar { + ($e:expr) => { + &include_bytes!(concat!("archives/", $e))[..] + }; +} + +mod header; + +/// test that we can concatenate the simple.tar archive and extract the same entries twice when we +/// use the ignore_zeros option. +#[test] +fn simple_concat() { + let bytes = tar!("simple.tar"); + let mut archive_bytes = Vec::new(); + archive_bytes.extend(bytes); + + let original_names: Vec<String> = decode_names(&mut Archive::new(Cursor::new(&archive_bytes))); + let expected: Vec<&str> = original_names.iter().map(|n| n.as_str()).collect(); + + // concat two archives (with null in-between); + archive_bytes.extend(bytes); + + // test now that when we read the archive, it stops processing at the first zero header. + let actual = decode_names(&mut Archive::new(Cursor::new(&archive_bytes))); + assert_eq!(expected, actual); + + // extend expected by itself. + let expected: Vec<&str> = { + let mut o = Vec::new(); + o.extend(&expected); + o.extend(&expected); + o + }; + + let mut ar = Archive::new(Cursor::new(&archive_bytes)); + ar.set_ignore_zeros(true); + + let actual = decode_names(&mut ar); + assert_eq!(expected, actual); + + fn decode_names<R>(ar: &mut Archive<R>) -> Vec<String> + where + R: Read, + { + let mut names = Vec::new(); + + for entry in t!(ar.entries()) { + let e = t!(entry); + names.push(t!(::std::str::from_utf8(&e.path_bytes())).to_string()); + } + + names + } +} + +#[test] +fn header_impls() { + let mut ar = Archive::new(Cursor::new(tar!("simple.tar"))); + let hn = Header::new_old(); + let hnb = hn.as_bytes(); + for file in t!(ar.entries()) { + let file = t!(file); + let h1 = file.header(); + let h1b = h1.as_bytes(); + let h2 = h1.clone(); + let h2b = h2.as_bytes(); + assert!(h1b[..] == h2b[..] && h2b[..] != hnb[..]) + } +} + +#[test] +fn header_impls_missing_last_header() { + let mut ar = Archive::new(Cursor::new(tar!("simple_missing_last_header.tar"))); + let hn = Header::new_old(); + let hnb = hn.as_bytes(); + for file in t!(ar.entries()) { + let file = t!(file); + let h1 = file.header(); + let h1b = h1.as_bytes(); + let h2 = h1.clone(); + let h2b = h2.as_bytes(); + assert!(h1b[..] == h2b[..] && h2b[..] != hnb[..]) + } +} + +#[test] +fn reading_files() { + let rdr = Cursor::new(tar!("reading_files.tar")); + let mut ar = Archive::new(rdr); + let mut entries = t!(ar.entries()); + + let mut a = t!(entries.next().unwrap()); + assert_eq!(&*a.header().path_bytes(), b"a"); + let mut s = String::new(); + t!(a.read_to_string(&mut s)); + assert_eq!(s, "a\na\na\na\na\na\na\na\na\na\na\n"); + + let mut b = t!(entries.next().unwrap()); + assert_eq!(&*b.header().path_bytes(), b"b"); + s.truncate(0); + t!(b.read_to_string(&mut s)); + assert_eq!(s, "b\nb\nb\nb\nb\nb\nb\nb\nb\nb\nb\n"); + + assert!(entries.next().is_none()); +} + +#[test] +fn writing_files() { + let mut ar = Builder::new(Vec::new()); + let td = t!(TempDir::new("tar-rs")); + + let path = td.path().join("test"); + t!(t!(File::create(&path)).write_all(b"test")); + + t!(ar.append_file("test2", &mut t!(File::open(&path)))); + + let data = t!(ar.into_inner()); + let mut ar = Archive::new(Cursor::new(data)); + let mut entries = t!(ar.entries()); + let mut f = t!(entries.next().unwrap()); + + assert_eq!(&*f.header().path_bytes(), b"test2"); + assert_eq!(f.header().size().unwrap(), 4); + let mut s = String::new(); + t!(f.read_to_string(&mut s)); + assert_eq!(s, "test"); + + assert!(entries.next().is_none()); +} + +#[test] +fn large_filename() { + let mut ar = Builder::new(Vec::new()); + let td = t!(TempDir::new("tar-rs")); + + let path = td.path().join("test"); + t!(t!(File::create(&path)).write_all(b"test")); + + let filename = repeat("abcd/").take(50).collect::<String>(); + let mut header = Header::new_ustar(); + header.set_path(&filename).unwrap(); + header.set_metadata(&t!(fs::metadata(&path))); + header.set_cksum(); + t!(ar.append(&header, &b"test"[..])); + let too_long = repeat("abcd").take(200).collect::<String>(); + t!(ar.append_file(&too_long, &mut t!(File::open(&path)))); + t!(ar.append_data(&mut header, &too_long, &b"test"[..])); + + let rd = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rd); + let mut entries = t!(ar.entries()); + + // The short entry added with `append` + let mut f = entries.next().unwrap().unwrap(); + assert_eq!(&*f.header().path_bytes(), filename.as_bytes()); + assert_eq!(f.header().size().unwrap(), 4); + let mut s = String::new(); + t!(f.read_to_string(&mut s)); + assert_eq!(s, "test"); + + // The long entry added with `append_file` + let mut f = entries.next().unwrap().unwrap(); + assert_eq!(&*f.path_bytes(), too_long.as_bytes()); + assert_eq!(f.header().size().unwrap(), 4); + let mut s = String::new(); + t!(f.read_to_string(&mut s)); + assert_eq!(s, "test"); + + // The long entry added with `append_data` + let mut f = entries.next().unwrap().unwrap(); + assert!(f.header().path_bytes().len() < too_long.len()); + assert_eq!(&*f.path_bytes(), too_long.as_bytes()); + assert_eq!(f.header().size().unwrap(), 4); + let mut s = String::new(); + t!(f.read_to_string(&mut s)); + assert_eq!(s, "test"); + + assert!(entries.next().is_none()); +} + +#[test] +fn reading_entries() { + let rdr = Cursor::new(tar!("reading_files.tar")); + let mut ar = Archive::new(rdr); + let mut entries = t!(ar.entries()); + let mut a = t!(entries.next().unwrap()); + assert_eq!(&*a.header().path_bytes(), b"a"); + let mut s = String::new(); + t!(a.read_to_string(&mut s)); + assert_eq!(s, "a\na\na\na\na\na\na\na\na\na\na\n"); + s.truncate(0); + t!(a.read_to_string(&mut s)); + assert_eq!(s, ""); + let mut b = t!(entries.next().unwrap()); + + assert_eq!(&*b.header().path_bytes(), b"b"); + s.truncate(0); + t!(b.read_to_string(&mut s)); + assert_eq!(s, "b\nb\nb\nb\nb\nb\nb\nb\nb\nb\nb\n"); + assert!(entries.next().is_none()); +} + +fn check_dirtree(td: &TempDir) { + let dir_a = td.path().join("a"); + let dir_b = td.path().join("a/b"); + let file_c = td.path().join("a/c"); + assert!(fs::metadata(&dir_a).map(|m| m.is_dir()).unwrap_or(false)); + assert!(fs::metadata(&dir_b).map(|m| m.is_dir()).unwrap_or(false)); + assert!(fs::metadata(&file_c).map(|m| m.is_file()).unwrap_or(false)); +} + +#[test] +fn extracting_directories() { + let td = t!(TempDir::new("tar-rs")); + let rdr = Cursor::new(tar!("directory.tar")); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + check_dirtree(&td); +} + +#[test] +#[cfg(all(unix, feature = "xattr"))] +fn xattrs() { + // If /tmp is a tmpfs, xattr will fail + // The xattr crate's unit tests also use /var/tmp for this reason + let td = t!(TempDir::new_in("/var/tmp", "tar-rs")); + let rdr = Cursor::new(tar!("xattrs.tar")); + let mut ar = Archive::new(rdr); + ar.set_unpack_xattrs(true); + t!(ar.unpack(td.path())); + + let val = xattr::get(td.path().join("a/b"), "user.pax.flags").unwrap(); + assert_eq!(val.unwrap(), "epm".as_bytes()); +} + +#[test] +#[cfg(all(unix, feature = "xattr"))] +fn no_xattrs() { + // If /tmp is a tmpfs, xattr will fail + // The xattr crate's unit tests also use /var/tmp for this reason + let td = t!(TempDir::new_in("/var/tmp", "tar-rs")); + let rdr = Cursor::new(tar!("xattrs.tar")); + let mut ar = Archive::new(rdr); + ar.set_unpack_xattrs(false); + t!(ar.unpack(td.path())); + + assert_eq!( + xattr::get(td.path().join("a/b"), "user.pax.flags").unwrap(), + None + ); +} + +#[test] +fn writing_and_extracting_directories() { + let td = t!(TempDir::new("tar-rs")); + + let mut ar = Builder::new(Vec::new()); + let tmppath = td.path().join("tmpfile"); + t!(t!(File::create(&tmppath)).write_all(b"c")); + t!(ar.append_dir("a", ".")); + t!(ar.append_dir("a/b", ".")); + t!(ar.append_file("a/c", &mut t!(File::open(&tmppath)))); + t!(ar.finish()); + + let rdr = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + check_dirtree(&td); +} + +#[test] +fn writing_directories_recursively() { + let td = t!(TempDir::new("tar-rs")); + + let base_dir = td.path().join("base"); + t!(fs::create_dir(&base_dir)); + t!(t!(File::create(base_dir.join("file1"))).write_all(b"file1")); + let sub_dir = base_dir.join("sub"); + t!(fs::create_dir(&sub_dir)); + t!(t!(File::create(sub_dir.join("file2"))).write_all(b"file2")); + + let mut ar = Builder::new(Vec::new()); + t!(ar.append_dir_all("foobar", base_dir)); + let data = t!(ar.into_inner()); + + let mut ar = Archive::new(Cursor::new(data)); + t!(ar.unpack(td.path())); + let base_dir = td.path().join("foobar"); + assert!(fs::metadata(&base_dir).map(|m| m.is_dir()).unwrap_or(false)); + let file1_path = base_dir.join("file1"); + assert!(fs::metadata(&file1_path) + .map(|m| m.is_file()) + .unwrap_or(false)); + let sub_dir = base_dir.join("sub"); + assert!(fs::metadata(&sub_dir).map(|m| m.is_dir()).unwrap_or(false)); + let file2_path = sub_dir.join("file2"); + assert!(fs::metadata(&file2_path) + .map(|m| m.is_file()) + .unwrap_or(false)); +} + +#[test] +fn append_dir_all_blank_dest() { + let td = t!(TempDir::new("tar-rs")); + + let base_dir = td.path().join("base"); + t!(fs::create_dir(&base_dir)); + t!(t!(File::create(base_dir.join("file1"))).write_all(b"file1")); + let sub_dir = base_dir.join("sub"); + t!(fs::create_dir(&sub_dir)); + t!(t!(File::create(sub_dir.join("file2"))).write_all(b"file2")); + + let mut ar = Builder::new(Vec::new()); + t!(ar.append_dir_all("", base_dir)); + let data = t!(ar.into_inner()); + + let mut ar = Archive::new(Cursor::new(data)); + t!(ar.unpack(td.path())); + let base_dir = td.path(); + assert!(fs::metadata(&base_dir).map(|m| m.is_dir()).unwrap_or(false)); + let file1_path = base_dir.join("file1"); + assert!(fs::metadata(&file1_path) + .map(|m| m.is_file()) + .unwrap_or(false)); + let sub_dir = base_dir.join("sub"); + assert!(fs::metadata(&sub_dir).map(|m| m.is_dir()).unwrap_or(false)); + let file2_path = sub_dir.join("file2"); + assert!(fs::metadata(&file2_path) + .map(|m| m.is_file()) + .unwrap_or(false)); +} + +#[test] +fn append_dir_all_does_not_work_on_non_directory() { + let td = t!(TempDir::new("tar-rs")); + let path = td.path().join("test"); + t!(t!(File::create(&path)).write_all(b"test")); + + let mut ar = Builder::new(Vec::new()); + let result = ar.append_dir_all("test", path); + assert!(result.is_err()); +} + +#[test] +fn extracting_duplicate_dirs() { + let td = t!(TempDir::new("tar-rs")); + let rdr = Cursor::new(tar!("duplicate_dirs.tar")); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + + let some_dir = td.path().join("some_dir"); + assert!(fs::metadata(&some_dir).map(|m| m.is_dir()).unwrap_or(false)); +} + +#[test] +fn unpack_old_style_bsd_dir() { + let td = t!(TempDir::new("tar-rs")); + + let mut ar = Builder::new(Vec::new()); + + let mut header = Header::new_old(); + header.set_entry_type(EntryType::Regular); + t!(header.set_path("testdir/")); + header.set_size(0); + header.set_cksum(); + t!(ar.append(&header, &mut io::empty())); + + // Extracting + let rdr = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + + // Iterating + let rdr = Cursor::new(ar.into_inner().into_inner()); + let mut ar = Archive::new(rdr); + assert!(t!(ar.entries()).all(|fr| fr.is_ok())); + + assert!(td.path().join("testdir").is_dir()); +} + +#[test] +fn handling_incorrect_file_size() { + let td = t!(TempDir::new("tar-rs")); + + let mut ar = Builder::new(Vec::new()); + + let path = td.path().join("tmpfile"); + t!(File::create(&path)); + let mut file = t!(File::open(&path)); + let mut header = Header::new_old(); + t!(header.set_path("somepath")); + header.set_metadata(&t!(file.metadata())); + header.set_size(2048); // past the end of file null blocks + header.set_cksum(); + t!(ar.append(&header, &mut file)); + + // Extracting + let rdr = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rdr); + assert!(ar.unpack(td.path()).is_err()); + + // Iterating + let rdr = Cursor::new(ar.into_inner().into_inner()); + let mut ar = Archive::new(rdr); + assert!(t!(ar.entries()).any(|fr| fr.is_err())); +} + +#[test] +fn extracting_malicious_tarball() { + let td = t!(TempDir::new("tar-rs")); + + let mut evil_tar = Vec::new(); + + { + let mut a = Builder::new(&mut evil_tar); + let mut append = |path: &str| { + let mut header = Header::new_gnu(); + assert!(header.set_path(path).is_err(), "was ok: {:?}", path); + { + let h = header.as_gnu_mut().unwrap(); + for (a, b) in h.name.iter_mut().zip(path.as_bytes()) { + *a = *b; + } + } + header.set_size(1); + header.set_cksum(); + t!(a.append(&header, io::repeat(1).take(1))); + }; + append("/tmp/abs_evil.txt"); + append("//tmp/abs_evil2.txt"); + append("///tmp/abs_evil3.txt"); + append("/./tmp/abs_evil4.txt"); + append("//./tmp/abs_evil5.txt"); + append("///./tmp/abs_evil6.txt"); + append("/../tmp/rel_evil.txt"); + append("../rel_evil2.txt"); + append("./../rel_evil3.txt"); + append("some/../../rel_evil4.txt"); + append(""); + append("././//./.."); + append(".."); + append("/////////.."); + append("/////////"); + } + + let mut ar = Archive::new(&evil_tar[..]); + t!(ar.unpack(td.path())); + + assert!(fs::metadata("/tmp/abs_evil.txt").is_err()); + assert!(fs::metadata("/tmp/abs_evil.txt2").is_err()); + assert!(fs::metadata("/tmp/abs_evil.txt3").is_err()); + assert!(fs::metadata("/tmp/abs_evil.txt4").is_err()); + assert!(fs::metadata("/tmp/abs_evil.txt5").is_err()); + assert!(fs::metadata("/tmp/abs_evil.txt6").is_err()); + assert!(fs::metadata("/tmp/rel_evil.txt").is_err()); + assert!(fs::metadata("/tmp/rel_evil.txt").is_err()); + assert!(fs::metadata(td.path().join("../tmp/rel_evil.txt")).is_err()); + assert!(fs::metadata(td.path().join("../rel_evil2.txt")).is_err()); + assert!(fs::metadata(td.path().join("../rel_evil3.txt")).is_err()); + assert!(fs::metadata(td.path().join("../rel_evil4.txt")).is_err()); + + // The `some` subdirectory should not be created because the only + // filename that references this has '..'. + assert!(fs::metadata(td.path().join("some")).is_err()); + + // The `tmp` subdirectory should be created and within this + // subdirectory, there should be files named `abs_evil.txt` through + // `abs_evil6.txt`. + assert!(fs::metadata(td.path().join("tmp")) + .map(|m| m.is_dir()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil2.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil3.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil4.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil5.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); + assert!(fs::metadata(td.path().join("tmp/abs_evil6.txt")) + .map(|m| m.is_file()) + .unwrap_or(false)); +} + +#[test] +fn octal_spaces() { + let rdr = Cursor::new(tar!("spaces.tar")); + let mut ar = Archive::new(rdr); + + let entry = ar.entries().unwrap().next().unwrap().unwrap(); + assert_eq!(entry.header().mode().unwrap() & 0o777, 0o777); + assert_eq!(entry.header().uid().unwrap(), 0); + assert_eq!(entry.header().gid().unwrap(), 0); + assert_eq!(entry.header().size().unwrap(), 2); + assert_eq!(entry.header().mtime().unwrap(), 0o12440016664); + assert_eq!(entry.header().cksum().unwrap(), 0o4253); +} + +#[test] +fn extracting_malformed_tar_null_blocks() { + let td = t!(TempDir::new("tar-rs")); + + let mut ar = Builder::new(Vec::new()); + + let path1 = td.path().join("tmpfile1"); + let path2 = td.path().join("tmpfile2"); + t!(File::create(&path1)); + t!(File::create(&path2)); + t!(ar.append_file("tmpfile1", &mut t!(File::open(&path1)))); + let mut data = t!(ar.into_inner()); + let amt = data.len(); + data.truncate(amt - 512); + let mut ar = Builder::new(data); + t!(ar.append_file("tmpfile2", &mut t!(File::open(&path2)))); + t!(ar.finish()); + + let data = t!(ar.into_inner()); + let mut ar = Archive::new(&data[..]); + assert!(ar.unpack(td.path()).is_ok()); +} + +#[test] +fn empty_filename() { + let td = t!(TempDir::new("tar-rs")); + let rdr = Cursor::new(tar!("empty_filename.tar")); + let mut ar = Archive::new(rdr); + assert!(ar.unpack(td.path()).is_ok()); +} + +#[test] +fn file_times() { + let td = t!(TempDir::new("tar-rs")); + let rdr = Cursor::new(tar!("file_times.tar")); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + + let meta = fs::metadata(td.path().join("a")).unwrap(); + let mtime = FileTime::from_last_modification_time(&meta); + let atime = FileTime::from_last_access_time(&meta); + assert_eq!(mtime.unix_seconds(), 1000000000); + assert_eq!(mtime.nanoseconds(), 0); + assert_eq!(atime.unix_seconds(), 1000000000); + assert_eq!(atime.nanoseconds(), 0); +} + +#[test] +fn backslash_treated_well() { + // Insert a file into an archive with a backslash + let td = t!(TempDir::new("tar-rs")); + let mut ar = Builder::new(Vec::<u8>::new()); + t!(ar.append_dir("foo\\bar", td.path())); + let mut ar = Archive::new(Cursor::new(t!(ar.into_inner()))); + let f = t!(t!(ar.entries()).next().unwrap()); + if cfg!(unix) { + assert_eq!(t!(f.header().path()).to_str(), Some("foo\\bar")); + } else { + assert_eq!(t!(f.header().path()).to_str(), Some("foo/bar")); + } + + // Unpack an archive with a backslash in the name + let mut ar = Builder::new(Vec::<u8>::new()); + let mut header = Header::new_gnu(); + header.set_metadata(&t!(fs::metadata(td.path()))); + header.set_size(0); + for (a, b) in header.as_old_mut().name.iter_mut().zip(b"foo\\bar\x00") { + *a = *b; + } + header.set_cksum(); + t!(ar.append(&header, &mut io::empty())); + let data = t!(ar.into_inner()); + let mut ar = Archive::new(&data[..]); + let f = t!(t!(ar.entries()).next().unwrap()); + assert_eq!(t!(f.header().path()).to_str(), Some("foo\\bar")); + + let mut ar = Archive::new(&data[..]); + t!(ar.unpack(td.path())); + assert!(fs::metadata(td.path().join("foo\\bar")).is_ok()); +} + +#[cfg(unix)] +#[test] +fn nul_bytes_in_path() { + use std::ffi::OsStr; + use std::os::unix::prelude::*; + + let nul_path = OsStr::from_bytes(b"foo\0"); + let td = t!(TempDir::new("tar-rs")); + let mut ar = Builder::new(Vec::<u8>::new()); + let err = ar.append_dir(nul_path, td.path()).unwrap_err(); + assert!(err.to_string().contains("contains a nul byte")); +} + +#[test] +fn links() { + let mut ar = Archive::new(Cursor::new(tar!("link.tar"))); + let mut entries = t!(ar.entries()); + let link = t!(entries.next().unwrap()); + assert_eq!( + t!(link.header().link_name()).as_ref().map(|p| &**p), + Some(Path::new("file")) + ); + let other = t!(entries.next().unwrap()); + assert!(t!(other.header().link_name()).is_none()); +} + +#[test] +#[cfg(unix)] // making symlinks on windows is hard +fn unpack_links() { + let td = t!(TempDir::new("tar-rs")); + let mut ar = Archive::new(Cursor::new(tar!("link.tar"))); + t!(ar.unpack(td.path())); + + let md = t!(fs::symlink_metadata(td.path().join("lnk"))); + assert!(md.file_type().is_symlink()); + assert_eq!( + &*t!(fs::read_link(td.path().join("lnk"))), + Path::new("file") + ); + t!(File::open(td.path().join("lnk"))); +} + +#[test] +fn pax_simple() { + let mut ar = Archive::new(tar!("pax.tar")); + let mut entries = t!(ar.entries()); + + let mut first = t!(entries.next().unwrap()); + let mut attributes = t!(first.pax_extensions()).unwrap(); + let first = t!(attributes.next().unwrap()); + let second = t!(attributes.next().unwrap()); + let third = t!(attributes.next().unwrap()); + assert!(attributes.next().is_none()); + + assert_eq!(first.key(), Ok("mtime")); + assert_eq!(first.value(), Ok("1453146164.953123768")); + assert_eq!(second.key(), Ok("atime")); + assert_eq!(second.value(), Ok("1453251915.24892486")); + assert_eq!(third.key(), Ok("ctime")); + assert_eq!(third.value(), Ok("1453146164.953123768")); +} + +#[test] +fn pax_path() { + let mut ar = Archive::new(tar!("pax2.tar")); + let mut entries = t!(ar.entries()); + + let first = t!(entries.next().unwrap()); + assert!(first.path().unwrap().ends_with("aaaaaaaaaaaaaaa")); +} + +#[test] +fn long_name_trailing_nul() { + let mut b = Builder::new(Vec::<u8>::new()); + + let mut h = Header::new_gnu(); + t!(h.set_path("././@LongLink")); + h.set_size(4); + h.set_entry_type(EntryType::new(b'L')); + h.set_cksum(); + t!(b.append(&h, "foo\0".as_bytes())); + let mut h = Header::new_gnu(); + + t!(h.set_path("bar")); + h.set_size(6); + h.set_entry_type(EntryType::file()); + h.set_cksum(); + t!(b.append(&h, "foobar".as_bytes())); + + let contents = t!(b.into_inner()); + let mut a = Archive::new(&contents[..]); + + let e = t!(t!(a.entries()).next().unwrap()); + assert_eq!(&*e.path_bytes(), b"foo"); +} + +#[test] +fn long_linkname_trailing_nul() { + let mut b = Builder::new(Vec::<u8>::new()); + + let mut h = Header::new_gnu(); + t!(h.set_path("././@LongLink")); + h.set_size(4); + h.set_entry_type(EntryType::new(b'K')); + h.set_cksum(); + t!(b.append(&h, "foo\0".as_bytes())); + let mut h = Header::new_gnu(); + + t!(h.set_path("bar")); + h.set_size(6); + h.set_entry_type(EntryType::file()); + h.set_cksum(); + t!(b.append(&h, "foobar".as_bytes())); + + let contents = t!(b.into_inner()); + let mut a = Archive::new(&contents[..]); + + let e = t!(t!(a.entries()).next().unwrap()); + assert_eq!(&*e.link_name_bytes().unwrap(), b"foo"); +} + +#[test] +fn encoded_long_name_has_trailing_nul() { + let td = t!(TempDir::new("tar-rs")); + let path = td.path().join("foo"); + t!(t!(File::create(&path)).write_all(b"test")); + + let mut b = Builder::new(Vec::<u8>::new()); + let long = repeat("abcd").take(200).collect::<String>(); + + t!(b.append_file(&long, &mut t!(File::open(&path)))); + + let contents = t!(b.into_inner()); + let mut a = Archive::new(&contents[..]); + + let mut e = t!(t!(a.entries()).raw(true).next().unwrap()); + let mut name = Vec::new(); + t!(e.read_to_end(&mut name)); + assert_eq!(name[name.len() - 1], 0); + + let header_name = &e.header().as_gnu().unwrap().name; + assert!(header_name.starts_with(b"././@LongLink\x00")); +} + +#[test] +fn reading_sparse() { + let rdr = Cursor::new(tar!("sparse.tar")); + let mut ar = Archive::new(rdr); + let mut entries = t!(ar.entries()); + + let mut a = t!(entries.next().unwrap()); + let mut s = String::new(); + assert_eq!(&*a.header().path_bytes(), b"sparse_begin.txt"); + t!(a.read_to_string(&mut s)); + assert_eq!(&s[..5], "test\n"); + assert!(s[5..].chars().all(|x| x == '\u{0}')); + + let mut a = t!(entries.next().unwrap()); + let mut s = String::new(); + assert_eq!(&*a.header().path_bytes(), b"sparse_end.txt"); + t!(a.read_to_string(&mut s)); + assert!(s[..s.len() - 9].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[s.len() - 9..], "test_end\n"); + + let mut a = t!(entries.next().unwrap()); + let mut s = String::new(); + assert_eq!(&*a.header().path_bytes(), b"sparse_ext.txt"); + t!(a.read_to_string(&mut s)); + assert!(s[..0x1000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x1000..0x1000 + 5], "text\n"); + assert!(s[0x1000 + 5..0x3000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x3000..0x3000 + 5], "text\n"); + assert!(s[0x3000 + 5..0x5000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x5000..0x5000 + 5], "text\n"); + assert!(s[0x5000 + 5..0x7000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x7000..0x7000 + 5], "text\n"); + assert!(s[0x7000 + 5..0x9000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x9000..0x9000 + 5], "text\n"); + assert!(s[0x9000 + 5..0xb000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0xb000..0xb000 + 5], "text\n"); + + let mut a = t!(entries.next().unwrap()); + let mut s = String::new(); + assert_eq!(&*a.header().path_bytes(), b"sparse.txt"); + t!(a.read_to_string(&mut s)); + assert!(s[..0x1000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x1000..0x1000 + 6], "hello\n"); + assert!(s[0x1000 + 6..0x2fa0].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x2fa0..0x2fa0 + 6], "world\n"); + assert!(s[0x2fa0 + 6..0x4000].chars().all(|x| x == '\u{0}')); + + assert!(entries.next().is_none()); +} + +#[test] +fn extract_sparse() { + let rdr = Cursor::new(tar!("sparse.tar")); + let mut ar = Archive::new(rdr); + let td = t!(TempDir::new("tar-rs")); + t!(ar.unpack(td.path())); + + let mut s = String::new(); + t!(t!(File::open(td.path().join("sparse_begin.txt"))).read_to_string(&mut s)); + assert_eq!(&s[..5], "test\n"); + assert!(s[5..].chars().all(|x| x == '\u{0}')); + + s.truncate(0); + t!(t!(File::open(td.path().join("sparse_end.txt"))).read_to_string(&mut s)); + assert!(s[..s.len() - 9].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[s.len() - 9..], "test_end\n"); + + s.truncate(0); + t!(t!(File::open(td.path().join("sparse_ext.txt"))).read_to_string(&mut s)); + assert!(s[..0x1000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x1000..0x1000 + 5], "text\n"); + assert!(s[0x1000 + 5..0x3000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x3000..0x3000 + 5], "text\n"); + assert!(s[0x3000 + 5..0x5000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x5000..0x5000 + 5], "text\n"); + assert!(s[0x5000 + 5..0x7000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x7000..0x7000 + 5], "text\n"); + assert!(s[0x7000 + 5..0x9000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x9000..0x9000 + 5], "text\n"); + assert!(s[0x9000 + 5..0xb000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0xb000..0xb000 + 5], "text\n"); + + s.truncate(0); + t!(t!(File::open(td.path().join("sparse.txt"))).read_to_string(&mut s)); + assert!(s[..0x1000].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x1000..0x1000 + 6], "hello\n"); + assert!(s[0x1000 + 6..0x2fa0].chars().all(|x| x == '\u{0}')); + assert_eq!(&s[0x2fa0..0x2fa0 + 6], "world\n"); + assert!(s[0x2fa0 + 6..0x4000].chars().all(|x| x == '\u{0}')); +} + +#[test] +fn path_separators() { + let mut ar = Builder::new(Vec::new()); + let td = t!(TempDir::new("tar-rs")); + + let path = td.path().join("test"); + t!(t!(File::create(&path)).write_all(b"test")); + + let short_path: PathBuf = repeat("abcd").take(2).collect(); + let long_path: PathBuf = repeat("abcd").take(50).collect(); + + // Make sure UStar headers normalize to Unix path separators + let mut header = Header::new_ustar(); + + t!(header.set_path(&short_path)); + assert_eq!(t!(header.path()), short_path); + assert!(!header.path_bytes().contains(&b'\\')); + + t!(header.set_path(&long_path)); + assert_eq!(t!(header.path()), long_path); + assert!(!header.path_bytes().contains(&b'\\')); + + // Make sure GNU headers normalize to Unix path separators, + // including the `@LongLink` fallback used by `append_file`. + t!(ar.append_file(&short_path, &mut t!(File::open(&path)))); + t!(ar.append_file(&long_path, &mut t!(File::open(&path)))); + + let rd = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rd); + let mut entries = t!(ar.entries()); + + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), short_path); + assert!(!entry.path_bytes().contains(&b'\\')); + + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), long_path); + assert!(!entry.path_bytes().contains(&b'\\')); + + assert!(entries.next().is_none()); +} + +#[test] +#[cfg(unix)] +fn append_path_symlink() { + use std::borrow::Cow; + use std::env; + use std::os::unix::fs::symlink; + + let mut ar = Builder::new(Vec::new()); + ar.follow_symlinks(false); + let td = t!(TempDir::new("tar-rs")); + + let long_linkname = repeat("abcd").take(30).collect::<String>(); + let long_pathname = repeat("dcba").take(30).collect::<String>(); + t!(env::set_current_dir(td.path())); + // "short" path name / short link name + t!(symlink("testdest", "test")); + t!(ar.append_path("test")); + // short path name / long link name + t!(symlink(&long_linkname, "test2")); + t!(ar.append_path("test2")); + // long path name / long link name + t!(symlink(&long_linkname, &long_pathname)); + t!(ar.append_path(&long_pathname)); + + let rd = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rd); + let mut entries = t!(ar.entries()); + + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), Path::new("test")); + assert_eq!( + t!(entry.link_name()), + Some(Cow::from(Path::new("testdest"))) + ); + assert_eq!(t!(entry.header().size()), 0); + + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), Path::new("test2")); + assert_eq!( + t!(entry.link_name()), + Some(Cow::from(Path::new(&long_linkname))) + ); + assert_eq!(t!(entry.header().size()), 0); + + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), Path::new(&long_pathname)); + assert_eq!( + t!(entry.link_name()), + Some(Cow::from(Path::new(&long_linkname))) + ); + assert_eq!(t!(entry.header().size()), 0); + + assert!(entries.next().is_none()); +} + +#[test] +fn name_with_slash_doesnt_fool_long_link_and_bsd_compat() { + let td = t!(TempDir::new("tar-rs")); + + let mut ar = Builder::new(Vec::new()); + + let mut h = Header::new_gnu(); + t!(h.set_path("././@LongLink")); + h.set_size(4); + h.set_entry_type(EntryType::new(b'L')); + h.set_cksum(); + t!(ar.append(&h, "foo\0".as_bytes())); + + let mut header = Header::new_gnu(); + header.set_entry_type(EntryType::Regular); + t!(header.set_path("testdir/")); + header.set_size(0); + header.set_cksum(); + t!(ar.append(&header, &mut io::empty())); + + // Extracting + let rdr = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rdr); + t!(ar.unpack(td.path())); + + // Iterating + let rdr = Cursor::new(ar.into_inner().into_inner()); + let mut ar = Archive::new(rdr); + assert!(t!(ar.entries()).all(|fr| fr.is_ok())); + + assert!(td.path().join("foo").is_file()); +} + +#[test] +fn insert_local_file_different_name() { + let mut ar = Builder::new(Vec::new()); + let td = t!(TempDir::new("tar-rs")); + let path = td.path().join("directory"); + t!(fs::create_dir(&path)); + ar.append_path_with_name(&path, "archive/dir").unwrap(); + let path = td.path().join("file"); + t!(t!(File::create(&path)).write_all(b"test")); + ar.append_path_with_name(&path, "archive/dir/f").unwrap(); + + let rd = Cursor::new(t!(ar.into_inner())); + let mut ar = Archive::new(rd); + let mut entries = t!(ar.entries()); + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), Path::new("archive/dir")); + let entry = t!(entries.next().unwrap()); + assert_eq!(t!(entry.path()), Path::new("archive/dir/f")); + assert!(entries.next().is_none()); +} + +#[test] +#[cfg(unix)] +fn tar_directory_containing_symlink_to_directory() { + use std::os::unix::fs::symlink; + + let td = t!(TempDir::new("tar-rs")); + let dummy_src = t!(TempDir::new("dummy_src")); + let dummy_dst = td.path().join("dummy_dst"); + let mut ar = Builder::new(Vec::new()); + t!(symlink(dummy_src.path().display().to_string(), &dummy_dst)); + + assert!(dummy_dst.read_link().is_ok()); + assert!(dummy_dst.read_link().unwrap().is_dir()); + ar.append_dir_all("symlinks", td.path()).unwrap(); + ar.finish().unwrap(); +} diff --git a/tar/tests/entry.rs b/tar/tests/entry.rs new file mode 100644 index 000000000..5d3c8ca4b --- /dev/null +++ b/tar/tests/entry.rs @@ -0,0 +1,348 @@ +extern crate tar; +extern crate tempdir; + +use std::fs::File; +use std::io::Read; + +use tempdir::TempDir; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(v) => v, + Err(e) => panic!("{} returned {}", stringify!($e), e), + } + }; +} + +#[test] +fn absolute_symlink() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("/bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + t!(ar.unpack(td.path())); + + t!(td.path().join("foo").symlink_metadata()); + + let mut ar = tar::Archive::new(&bytes[..]); + let mut entries = t!(ar.entries()); + let entry = t!(entries.next().unwrap()); + assert_eq!(&*entry.link_name_bytes().unwrap(), b"/bar"); +} + +#[test] +fn absolute_hardlink() { + let td = t!(TempDir::new("tar")); + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Link); + t!(header.set_path("bar")); + // This absolute path under tempdir will be created at unpack time + t!(header.set_link_name(td.path().join("foo"))); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + t!(ar.unpack(td.path())); + t!(td.path().join("foo").metadata()); + t!(td.path().join("bar").metadata()); +} + +#[test] +fn relative_hardlink() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Link); + t!(header.set_path("bar")); + t!(header.set_link_name("foo")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + t!(ar.unpack(td.path())); + t!(td.path().join("foo").metadata()); + t!(td.path().join("bar").metadata()); +} + +#[test] +fn absolute_link_deref_error() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("/")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo/bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + assert!(ar.unpack(td.path()).is_err()); + t!(td.path().join("foo").symlink_metadata()); + assert!(File::open(td.path().join("foo").join("bar")).is_err()); +} + +#[test] +fn relative_link_deref_error() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("../../../../")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo/bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + assert!(ar.unpack(td.path()).is_err()); + t!(td.path().join("foo").symlink_metadata()); + assert!(File::open(td.path().join("foo").join("bar")).is_err()); +} + +#[test] +#[cfg(unix)] +fn directory_maintains_permissions() { + use ::std::os::unix::fs::PermissionsExt; + + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Directory); + t!(header.set_path("foo")); + header.set_mode(0o777); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + t!(ar.unpack(td.path())); + let f = t!(File::open(td.path().join("foo"))); + let md = t!(f.metadata()); + assert!(md.is_dir()); + assert_eq!(md.permissions().mode(), 0o40777); +} + +#[test] +fn modify_link_just_created() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("bar/foo")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo/bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + t!(ar.unpack(td.path())); + + t!(File::open(td.path().join("bar/foo"))); + t!(File::open(td.path().join("bar/bar"))); + t!(File::open(td.path().join("foo/foo"))); + t!(File::open(td.path().join("foo/bar"))); +} + +#[test] +fn parent_paths_error() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("..")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo/bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + assert!(ar.unpack(td.path()).is_err()); + t!(td.path().join("foo").symlink_metadata()); + assert!(File::open(td.path().join("foo").join("bar")).is_err()); +} + +#[test] +#[cfg(unix)] +fn good_parent_paths_ok() { + use std::path::PathBuf; + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path(PathBuf::from("foo").join("bar"))); + t!(header.set_link_name(PathBuf::from("..").join("bar"))); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("bar")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + t!(ar.unpack(td.path())); + t!(td.path().join("foo").join("bar").read_link()); + let dst = t!(td.path().join("foo").join("bar").canonicalize()); + t!(File::open(dst)); +} + +#[test] +fn modify_hard_link_just_created() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Link); + t!(header.set_path("foo")); + t!(header.set_link_name("../test")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(1); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_cksum(); + t!(ar.append(&header, &b"x"[..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + + let test = td.path().join("test"); + t!(File::create(&test)); + + let dir = td.path().join("dir"); + assert!(ar.unpack(&dir).is_err()); + + let mut contents = Vec::new(); + t!(t!(File::open(&test)).read_to_end(&mut contents)); + assert_eq!(contents.len(), 0); +} + +#[test] +fn modify_symlink_just_created() { + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Symlink); + t!(header.set_path("foo")); + t!(header.set_link_name("../test")); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(1); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_cksum(); + t!(ar.append(&header, &b"x"[..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + + let td = t!(TempDir::new("tar")); + + let test = td.path().join("test"); + t!(File::create(&test)); + + let dir = td.path().join("dir"); + t!(ar.unpack(&dir)); + + let mut contents = Vec::new(); + t!(t!(File::open(&test)).read_to_end(&mut contents)); + assert_eq!(contents.len(), 0); +} diff --git a/tar/tests/header/mod.rs b/tar/tests/header/mod.rs new file mode 100644 index 000000000..6f4b735fd --- /dev/null +++ b/tar/tests/header/mod.rs @@ -0,0 +1,236 @@ +use std::fs::{self, File}; +use std::io::{self, Write}; +use std::path::Path; +use std::{iter, mem, thread, time}; + +use tempdir::TempDir; + +use tar::{GnuHeader, Header, HeaderMode}; + +#[test] +fn default_gnu() { + let mut h = Header::new_gnu(); + assert!(h.as_gnu().is_some()); + assert!(h.as_gnu_mut().is_some()); + assert!(h.as_ustar().is_none()); + assert!(h.as_ustar_mut().is_none()); +} + +#[test] +fn goto_old() { + let mut h = Header::new_old(); + assert!(h.as_gnu().is_none()); + assert!(h.as_gnu_mut().is_none()); + assert!(h.as_ustar().is_none()); + assert!(h.as_ustar_mut().is_none()); +} + +#[test] +fn goto_ustar() { + let mut h = Header::new_ustar(); + assert!(h.as_gnu().is_none()); + assert!(h.as_gnu_mut().is_none()); + assert!(h.as_ustar().is_some()); + assert!(h.as_ustar_mut().is_some()); +} + +#[test] +fn link_name() { + let mut h = Header::new_gnu(); + t!(h.set_link_name("foo")); + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo")); + t!(h.set_link_name("../foo")); + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("../foo")); + t!(h.set_link_name("foo/bar")); + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo/bar")); + t!(h.set_link_name("foo\\ba")); + if cfg!(windows) { + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo/ba")); + } else { + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo\\ba")); + } + + let name = "foo\\bar\0"; + for (slot, val) in h.as_old_mut().linkname.iter_mut().zip(name.as_bytes()) { + *slot = *val; + } + assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo\\bar")); + + assert!(h.set_link_name("\0").is_err()); +} + +#[test] +fn mtime() { + let h = Header::new_gnu(); + assert_eq!(t!(h.mtime()), 0); + + let h = Header::new_ustar(); + assert_eq!(t!(h.mtime()), 0); + + let h = Header::new_old(); + assert_eq!(t!(h.mtime()), 0); +} + +#[test] +fn user_and_group_name() { + let mut h = Header::new_gnu(); + t!(h.set_username("foo")); + t!(h.set_groupname("bar")); + assert_eq!(t!(h.username()), Some("foo")); + assert_eq!(t!(h.groupname()), Some("bar")); + + h = Header::new_ustar(); + t!(h.set_username("foo")); + t!(h.set_groupname("bar")); + assert_eq!(t!(h.username()), Some("foo")); + assert_eq!(t!(h.groupname()), Some("bar")); + + h = Header::new_old(); + assert_eq!(t!(h.username()), None); + assert_eq!(t!(h.groupname()), None); + assert!(h.set_username("foo").is_err()); + assert!(h.set_groupname("foo").is_err()); +} + +#[test] +fn dev_major_minor() { + let mut h = Header::new_gnu(); + t!(h.set_device_major(1)); + t!(h.set_device_minor(2)); + assert_eq!(t!(h.device_major()), Some(1)); + assert_eq!(t!(h.device_minor()), Some(2)); + + h = Header::new_ustar(); + t!(h.set_device_major(1)); + t!(h.set_device_minor(2)); + assert_eq!(t!(h.device_major()), Some(1)); + assert_eq!(t!(h.device_minor()), Some(2)); + + h.as_ustar_mut().unwrap().dev_minor[0] = 0x7f; + h.as_ustar_mut().unwrap().dev_major[0] = 0x7f; + assert!(h.device_major().is_err()); + assert!(h.device_minor().is_err()); + + h.as_ustar_mut().unwrap().dev_minor[0] = b'g'; + h.as_ustar_mut().unwrap().dev_major[0] = b'h'; + assert!(h.device_major().is_err()); + assert!(h.device_minor().is_err()); + + h = Header::new_old(); + assert_eq!(t!(h.device_major()), None); + assert_eq!(t!(h.device_minor()), None); + assert!(h.set_device_major(1).is_err()); + assert!(h.set_device_minor(1).is_err()); +} + +#[test] +fn set_path() { + let mut h = Header::new_gnu(); + t!(h.set_path("foo")); + assert_eq!(t!(h.path()).to_str(), Some("foo")); + t!(h.set_path("foo/")); + assert_eq!(t!(h.path()).to_str(), Some("foo/")); + t!(h.set_path("foo/bar")); + assert_eq!(t!(h.path()).to_str(), Some("foo/bar")); + t!(h.set_path("foo\\bar")); + if cfg!(windows) { + assert_eq!(t!(h.path()).to_str(), Some("foo/bar")); + } else { + assert_eq!(t!(h.path()).to_str(), Some("foo\\bar")); + } + + let long_name = iter::repeat("foo").take(100).collect::<String>(); + let medium1 = iter::repeat("foo").take(52).collect::<String>(); + let medium2 = iter::repeat("fo/").take(52).collect::<String>(); + + assert!(h.set_path(&long_name).is_err()); + assert!(h.set_path(&medium1).is_err()); + assert!(h.set_path(&medium2).is_err()); + assert!(h.set_path("\0").is_err()); + + h = Header::new_ustar(); + t!(h.set_path("foo")); + assert_eq!(t!(h.path()).to_str(), Some("foo")); + + assert!(h.set_path(&long_name).is_err()); + assert!(h.set_path(&medium1).is_err()); + t!(h.set_path(&medium2)); + assert_eq!(t!(h.path()).to_str(), Some(&medium2[..])); +} + +#[test] +fn set_ustar_path_hard() { + let mut h = Header::new_ustar(); + let p = Path::new("a").join(&vec!["a"; 100].join("")); + t!(h.set_path(&p)); + assert_eq!(t!(h.path()), p); +} + +#[test] +fn set_metadata_deterministic() { + let td = t!(TempDir::new("tar-rs")); + let tmppath = td.path().join("tmpfile"); + + fn mk_header(path: &Path, readonly: bool) -> Result<Header, io::Error> { + let mut file = t!(File::create(path)); + t!(file.write_all(b"c")); + let mut perms = t!(file.metadata()).permissions(); + perms.set_readonly(readonly); + t!(fs::set_permissions(path, perms)); + let mut h = Header::new_ustar(); + h.set_metadata_in_mode(&t!(path.metadata()), HeaderMode::Deterministic); + Ok(h) + } + + // Create "the same" File twice in a row, one second apart, with differing readonly values. + let one = t!(mk_header(tmppath.as_path(), false)); + thread::sleep(time::Duration::from_millis(1050)); + let two = t!(mk_header(tmppath.as_path(), true)); + + // Always expected to match. + assert_eq!(t!(one.size()), t!(two.size())); + assert_eq!(t!(one.path()), t!(two.path())); + assert_eq!(t!(one.mode()), t!(two.mode())); + + // Would not match without `Deterministic`. + assert_eq!(t!(one.mtime()), t!(two.mtime())); + // TODO: No great way to validate that these would not be filled, but + // check them anyway. + assert_eq!(t!(one.uid()), t!(two.uid())); + assert_eq!(t!(one.gid()), t!(two.gid())); +} + +#[test] +fn extended_numeric_format() { + let mut h: GnuHeader = unsafe { mem::zeroed() }; + h.as_header_mut().set_size(42); + assert_eq!(h.size, [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 50, 0]); + h.as_header_mut().set_size(8589934593); + assert_eq!(h.size, [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 1]); + h.size = [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 0]; + assert_eq!(h.as_header().entry_size().unwrap(), 0x0200000000); + h.size = [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 51, 0]; + assert_eq!(h.as_header().entry_size().unwrap(), 43); + + h.as_header_mut().set_gid(42); + assert_eq!(h.gid, [48, 48, 48, 48, 48, 53, 50, 0]); + assert_eq!(h.as_header().gid().unwrap(), 42); + h.as_header_mut().set_gid(0x7fffffffffffffff); + assert_eq!(h.gid, [0xff; 8]); + assert_eq!(h.as_header().gid().unwrap(), 0x7fffffffffffffff); + h.uid = [0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78]; + assert_eq!(h.as_header().uid().unwrap(), 0x12345678); + + h.mtime = [ + 0x80, 0, 0, 0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + ]; + assert_eq!(h.as_header().mtime().unwrap(), 0x0123456789abcdef); +} + +#[test] +fn byte_slice_conversion() { + let h = Header::new_gnu(); + let b: &[u8] = h.as_bytes(); + let b_conv: &[u8] = Header::from_byte_slice(h.as_bytes()).as_bytes(); + assert_eq!(b, b_conv); +} diff --git a/tempfile/.cargo-checksum.json b/tempfile/.cargo-checksum.json new file mode 100644 index 000000000..937c57a79 --- /dev/null +++ b/tempfile/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7dc4738f2e68ed2855de5ac9cdbe05c9216773ecde4739b2f095002ab03a13ef"} \ No newline at end of file diff --git a/tempfile/Cargo.toml b/tempfile/Cargo.toml new file mode 100644 index 000000000..ff4c9d3e5 --- /dev/null +++ b/tempfile/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "tempfile" +version = "3.0.8" +authors = ["Steven Allen <steven@stebalien.com>", "The Rust Project Developers", "Ashley Mannix <ashleymannix@live.com.au>", "Jason White <jasonaw0@gmail.com>"] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A library for managing temporary files and directories.\n" +homepage = "http://stebalien.com/projects/tempfile-rs" +documentation = "https://docs.rs/tempfile" +keywords = ["tempfile", "tmpfile", "filesystem"] +license = "MIT/Apache-2.0" +repository = "https://github.com/Stebalien/tempfile" +[dependencies.cfg-if] +version = "0.1" + +[dependencies.rand] +version = "0.6" + +[dependencies.remove_dir_all] +version = "0.5" +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" +[target."cfg(unix)".dependencies.libc] +version = "0.2.27" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["fileapi", "winbase", "handleapi"] diff --git a/tempfile/LICENSE-APACHE b/tempfile/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/tempfile/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/tempfile/LICENSE-MIT b/tempfile/LICENSE-MIT new file mode 100644 index 000000000..0c3270fdd --- /dev/null +++ b/tempfile/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 Steven Allen + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/tempfile/NEWS b/tempfile/NEWS new file mode 100644 index 000000000..d274bc9b9 --- /dev/null +++ b/tempfile/NEWS @@ -0,0 +1,153 @@ +3.0.8 +===== + +This is a bugfix release. + +Fixes: + +* Export `PathPersistError`. +* Fix a bug where flushing a `SpooledTempFile` to disk could fail to write part + of the file in some rare, yet-to-reproduced cases. + +3.0.7 +===== + +Breaking: + +* `Builder::prefix` and `Builder::suffix` now accept a generic `&AsRef<OsStr>`. + This could affect type inference. +* Temporary files (except unnamed temporary files on Windows and Linux >= 3.11) + now use absolute path names. This will break programs that create temporary + files relative to their current working directory when they don't have the + search permission (x) on some ancestor directory. This is only likely to + affect programs with strange chroot-less filesystem sandboxes. If you believe + you're affected by this issue, please comment on #40. + +Features: + +* Accept anything implementing `&AsRef<OsStr>` in the builder: &OsStr, &OsString, &Path, etc. + +Fixes: + +* Fix LFS support. +* Use absolute paths for named temporary files to guard against changes in the + current directory. +* Use absolute paths when creating unnamed temporary files on platforms that + can't create unlinked or auto-deleted temporary files. This fixes a very + unlikely race where the current directory could change while the temporary + file is being created. + +Misc: + +* Use modern stdlib features to avoid custom unsafe code. This reduces the + number of unsafe blocks from 12 to 4. + +3.0.6 +===== + +* Don't hide temporary files on windows, fixing #66 and #69. + +3.0.5 +===== + +Features: + +* Added a spooled temporary file implementation. This temporary file variant + starts out as an in-memory temporary file but "rolls-over" onto disk when it + grows over a specified size (#68). +* Errors are now annotated with paths to make debugging easier (#73). + +Misc: + +* The rand version has been bumped to 0.6 (#74). + +Bugs: + +* Tempfile compiles again on Redox (#75). + +3.0.4 +===== + +* Now compiles on unsupported platforms. + +3.0.3 +===== + +* update rand to 0.5 + +3.0.2 +===== + +* Actually *delete* temporary files on non-Linux unix systems (thanks to +@oliverhenshaw for the fix and a test case). + +3.0.1 +===== + +* Restore NamedTempFile::new_in + +3.0.0 +===== + +* Adds temporary directory support (@KodrAus) +* Allow closing named temporary files without deleting them (@jasonwhite) + +2.2.0 +===== + +* Redox Support + +2.1.6 +===== + +* Remove build script and bump minimum rustc version to 1.9.0 + +2.1.5 +===== + +* Don't build platform-specific dependencies on all platforms. +* Cleanup some documentation. + +2.1.4 +===== + +* Fix crates.io tags. No interesting changes. + +2.1.3 +===== + +Export `PersistError`. + +2.1.2 +===== + +Add `Read`/`Write`/`Seek` impls on `&NamedTempFile`. This mirrors the +implementations on `&File`. One can currently just deref to a `&File` but these +implementations are more discoverable. + +2.1.1 +===== + +Add LFS Support. + +2.1.0 +===== + +* Implement `AsRef<File>` for `NamedTempFile` allowing named temporary files to + be borrowed as `File`s. +* Add a method to convert a `NamedTempFile` to an unnamed temporary `File`. + +2.0.1 +===== + +* Arm bugfix + +2.0.0 +===== + +This release replaces `TempFile` with a `tempfile()` function that returnes +`std::fs::File` objects. These are significantly more useful because most rust +libraries expect normal `File` objects. + +To continue supporting shared temporary files, this new version adds a +`reopen()` method to `NamedTempFile`. diff --git a/tempfile/README.md b/tempfile/README.md new file mode 100644 index 000000000..81f6258ec --- /dev/null +++ b/tempfile/README.md @@ -0,0 +1,52 @@ +tempfile +======== + +[![Crate](https://img.shields.io/crates/v/tempfile.svg)](https://crates.io/crates/tempfile) +[![Build Status](https://travis-ci.org/Stebalien/tempfile.svg?branch=master)](https://travis-ci.org/Stebalien/tempfile) +[![Build status](https://ci.appveyor.com/api/projects/status/5q00b8rvvg46i5tf/branch/master?svg=true)](https://ci.appveyor.com/project/Stebalien/tempfile/branch/master) + +A secure, cross-platform, temporary file library for Rust. In addition to creating +temporary files, this library also allows users to securely open multiple +independent references to the same temporary file (useful for consumer/producer +patterns and surprisingly difficult to implement securely). + +[Documentation](https://docs.rs/tempfile/) + +Usage +----- + +Minimum required Rust version: 1.24.0 + +Add this to your `Cargo.toml`: +```toml +[dependencies] +tempfile = "3" +``` + +...and this to your crate root: +```rust +extern crate tempfile; +``` + +Example +------- + +```rust +extern crate tempfile; +use std::fs::File; +use std::io::{Write, Read, Seek, SeekFrom}; + +fn main() { + // Write + let mut tmpfile: File = tempfile::tempfile().unwrap(); + write!(tmpfile, "Hello World!").unwrap(); + + // Seek to start + tmpfile.seek(SeekFrom::Start(0)).unwrap(); + + // Read + let mut buf = String::new(); + tmpfile.read_to_string(&mut buf).unwrap(); + assert_eq!("Hello World!", buf); +} +``` diff --git a/tempfile/src/dir.rs b/tempfile/src/dir.rs new file mode 100644 index 000000000..90507a70b --- /dev/null +++ b/tempfile/src/dir.rs @@ -0,0 +1,408 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use remove_dir_all::remove_dir_all; +use std::path::{self, Path, PathBuf}; +use std::{fmt, fs, io}; + +use error::IoResultExt; +use Builder; + +/// Create a new temporary directory. +/// +/// The `tempdir` function creates a directory in the file system +/// and returns a [`TempDir`]. +/// The directory will be automatically deleted when the `TempDir`s +/// desctructor is run. +/// +/// # Resource Leaking +/// +/// See [the resource leaking][resource-leaking] docs on `TempDir`. +/// +/// # Errors +/// +/// If the directory can not be created, `Err` is returned. +/// +/// # Examples +/// +/// ``` +/// # extern crate tempfile; +/// use tempfile::tempdir; +/// use std::fs::File; +/// use std::io::{self, Write}; +/// +/// # fn main() { +/// # if let Err(_) = run() { +/// # ::std::process::exit(1); +/// # } +/// # } +/// # fn run() -> Result<(), io::Error> { +/// // Create a directory inside of `std::env::temp_dir()` +/// let dir = tempdir()?; +/// +/// let file_path = dir.path().join("my-temporary-note.txt"); +/// let mut file = File::create(file_path)?; +/// writeln!(file, "Brian was here. Briefly.")?; +/// +/// // `tmp_dir` goes out of scope, the directory as well as +/// // `tmp_file` will be deleted here. +/// drop(file); +/// dir.close()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`TempDir`]: struct.TempDir.html +/// [resource-leaking]: struct.TempDir.html#resource-leaking +pub fn tempdir() -> io::Result<TempDir> { + TempDir::new() +} + +/// Create a new temporary directory. +/// +/// The `tempdir` function creates a directory in the file system +/// and returns a [`TempDir`]. +/// The directory will be automatically deleted when the `TempDir`s +/// desctructor is run. +/// +/// # Resource Leaking +/// +/// See [the resource leaking][resource-leaking] docs on `TempDir`. +/// +/// # Errors +/// +/// If the directory can not be created, `Err` is returned. +/// +/// # Examples +/// +/// ``` +/// # extern crate tempfile; +/// use tempfile::tempdir; +/// use std::fs::File; +/// use std::io::{self, Write}; +/// +/// # fn main() { +/// # if let Err(_) = run() { +/// # ::std::process::exit(1); +/// # } +/// # } +/// # fn run() -> Result<(), io::Error> { +/// // Create a directory inside of `std::env::temp_dir()`, +/// let dir = tempdir()?; +/// +/// let file_path = dir.path().join("my-temporary-note.txt"); +/// let mut file = File::create(file_path)?; +/// writeln!(file, "Brian was here. Briefly.")?; +/// +/// // `tmp_dir` goes out of scope, the directory as well as +/// // `tmp_file` will be deleted here. +/// drop(file); +/// dir.close()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`TempDir`]: struct.TempDir.html +/// [resource-leaking]: struct.TempDir.html#resource-leaking +pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> { + TempDir::new_in(dir) +} + +/// A directory in the filesystem that is automatically deleted when +/// it goes out of scope. +/// +/// The [`TempDir`] type creates a directory on the file system that +/// is deleted once it goes out of scope. At construction, the +/// `TempDir` creates a new directory with a randomly generated name. +/// +/// The default constructor, [`TempDir::new()`], creates directories in +/// the location returned by [`std::env::temp_dir()`], but `TempDir` +/// can be configured to manage a temporary directory in any location +/// by constructing with a [`Builder`]. +/// +/// After creating a `TempDir`, work with the file system by doing +/// standard [`std::fs`] file system operations on its [`Path`], +/// which can be retrieved with [`TempDir::path()`]. Once the `TempDir` +/// value is dropped, the directory at the path will be deleted, along +/// with any files and directories it contains. It is your responsibility +/// to ensure that no further file system operations are attempted +/// inside the temporary directory once it has been deleted. +/// +/// # Resource Leaking +/// +/// Various platform-specific conditions may cause `TempDir` to fail +/// to delete the underlying directory. It's important to ensure that +/// handles (like [`File`] and [`ReadDir`]) to files inside the +/// directory are dropped before the `TempDir` goes out of scope. The +/// `TempDir` destructor will silently ignore any errors in deleting +/// the directory; to instead handle errors call [`TempDir::close()`]. +/// +/// Note that if the program exits before the `TempDir` destructor is +/// run, such as via [`std::process::exit()`], by segfaulting, or by +/// receiving a signal like `SIGINT`, then the temporary directory +/// will not be deleted. +/// +/// # Examples +/// +/// Create a temporary directory with a generated name: +/// +/// ``` +/// use std::fs::File; +/// use std::io::Write; +/// use tempfile::TempDir; +/// +/// # use std::io; +/// # fn run() -> Result<(), io::Error> { +/// // Create a directory inside of `std::env::temp_dir()` +/// let tmp_dir = TempDir::new()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// Create a temporary directory with a prefix in its name: +/// +/// ``` +/// use std::fs::File; +/// use std::io::Write; +/// use tempfile::Builder; +/// +/// # use std::io; +/// # fn run() -> Result<(), io::Error> { +/// // Create a directory inside of `std::env::temp_dir()`, +/// // whose name will begin with 'example'. +/// let tmp_dir = Builder::new().prefix("example").tempdir()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`File`]: http://doc.rust-lang.org/std/fs/struct.File.html +/// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html +/// [`ReadDir`]: http://doc.rust-lang.org/std/fs/struct.ReadDir.html +/// [`Builder`]: struct.Builder.html +/// [`TempDir::close()`]: struct.TempDir.html#method.close +/// [`TempDir::new()`]: struct.TempDir.html#method.new +/// [`TempDir::path()`]: struct.TempDir.html#method.path +/// [`TempDir`]: struct.TempDir.html +/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html +/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html +/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html +pub struct TempDir { + path: Option<PathBuf>, +} + +impl TempDir { + /// Attempts to make a temporary directory inside of `env::temp_dir()`. + /// + /// See [`Builder`] for more configuration. + /// + /// The directory and everything inside it will be automatically deleted + /// once the returned `TempDir` is destroyed. + /// + /// # Errors + /// + /// If the directory can not be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::Write; + /// use tempfile::TempDir; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// // Create a directory inside of `std::env::temp_dir()` + /// let tmp_dir = TempDir::new()?; + /// + /// let file_path = tmp_dir.path().join("my-temporary-note.txt"); + /// let mut tmp_file = File::create(file_path)?; + /// writeln!(tmp_file, "Brian was here. Briefly.")?; + /// + /// // `tmp_dir` goes out of scope, the directory as well as + /// // `tmp_file` will be deleted here. + /// # Ok(()) + /// # } + /// ``` + /// + /// [`Builder`]: struct.Builder.html + pub fn new() -> io::Result<TempDir> { + Builder::new().tempdir() + } + + /// Attempts to make a temporary directory inside of `dir`. + /// The directory and everything inside it will be automatically + /// deleted once the returned `TempDir` is destroyed. + /// + /// # Errors + /// + /// If the directory can not be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// use std::fs::{self, File}; + /// use std::io::Write; + /// use tempfile::TempDir; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// // Create a directory inside of the current directory + /// let tmp_dir = TempDir::new_in(".")?; + /// let file_path = tmp_dir.path().join("my-temporary-note.txt"); + /// let mut tmp_file = File::create(file_path)?; + /// writeln!(tmp_file, "Brian was here. Briefly.")?; + /// # Ok(()) + /// # } + /// ``` + pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> { + Builder::new().tempdir_in(dir) + } + + /// Accesses the [`Path`] to the temporary directory. + /// + /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html + /// + /// # Examples + /// + /// ``` + /// use tempfile::TempDir; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// let tmp_path; + /// + /// { + /// let tmp_dir = TempDir::new()?; + /// tmp_path = tmp_dir.path().to_owned(); + /// + /// // Check that the temp directory actually exists. + /// assert!(tmp_path.exists()); + /// + /// // End of `tmp_dir` scope, directory will be deleted + /// } + /// + /// // Temp directory should be deleted by now + /// assert_eq!(tmp_path.exists(), false); + /// # Ok(()) + /// # } + /// ``` + pub fn path(&self) -> &path::Path { + self.path.as_ref().unwrap() + } + + /// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located. + /// + /// This consumes the [`TempDir`] without deleting directory on the filesystem, meaning that + /// the directory will no longer be automatically deleted. + /// + /// [`TempDir`]: struct.TempDir.html + /// [`PathBuf`]: http://doc.rust-lang.org/std/path/struct.PathBuf.html + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use tempfile::TempDir; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// let tmp_dir = TempDir::new()?; + /// + /// // Persist the temporary directory to disk, + /// // getting the path where it is. + /// let tmp_path = tmp_dir.into_path(); + /// + /// // Delete the temporary directory ourselves. + /// fs::remove_dir_all(tmp_path)?; + /// # Ok(()) + /// # } + /// ``` + pub fn into_path(mut self) -> PathBuf { + self.path.take().unwrap() + } + + /// Closes and removes the temporary directory, returing a `Result`. + /// + /// Although `TempDir` removes the directory on drop, in the destructor + /// any errors are ignored. To detect errors cleaning up the temporary + /// directory, call `close` instead. + /// + /// # Errors + /// + /// This function may return a variety of [`std::io::Error`]s that result from deleting + /// the files and directories contained with the temporary directory, + /// as well as from deleting the temporary directory itself. These errors + /// may be platform specific. + /// + /// [`std::io::Error`]: http://doc.rust-lang.org/std/io/struct.Error.html + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::Write; + /// use tempfile::TempDir; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// // Create a directory inside of `std::env::temp_dir()`. + /// let tmp_dir = TempDir::new()?; + /// let file_path = tmp_dir.path().join("my-temporary-note.txt"); + /// let mut tmp_file = File::create(file_path)?; + /// writeln!(tmp_file, "Brian was here. Briefly.")?; + /// + /// // By closing the `TempDir` explicitly we can check that it has + /// // been deleted successfully. If we don't close it explicitly, + /// // the directory will still be deleted when `tmp_dir` goes out + /// // of scope, but we won't know whether deleting the directory + /// // succeeded. + /// drop(tmp_file); + /// tmp_dir.close()?; + /// # Ok(()) + /// # } + /// ``` + pub fn close(mut self) -> io::Result<()> { + let result = remove_dir_all(self.path()).with_err_path(|| self.path()); + + // Prevent the Drop impl from removing the dir a second time. + self.path = None; + + result + } +} + +impl AsRef<Path> for TempDir { + fn as_ref(&self) -> &Path { + self.path() + } +} + +impl fmt::Debug for TempDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TempDir") + .field("path", &self.path()) + .finish() + } +} + +impl Drop for TempDir { + fn drop(&mut self) { + // Path is `None` if `close()` or `into_path()` has been called. + if let Some(ref p) = self.path { + let _ = remove_dir_all(p); + } + } +} + +pub(crate) fn create(path: PathBuf) -> io::Result<TempDir> { + fs::create_dir(&path) + .with_err_path(|| &path) + .map(|_| TempDir { path: Some(path) }) +} diff --git a/tempfile/src/error.rs b/tempfile/src/error.rs new file mode 100644 index 000000000..a5805568a --- /dev/null +++ b/tempfile/src/error.rs @@ -0,0 +1,50 @@ +use std::path::PathBuf; +use std::{error, fmt, io}; + +#[derive(Debug)] +struct PathError { + path: PathBuf, + err: io::Error, +} + +impl fmt::Display for PathError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} at path {:?}", self.err, self.path) + } +} + +impl error::Error for PathError { + fn description(&self) -> &str { + self.err.description() + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&error::Error> { + self.err.cause() + } +} + +pub(crate) trait IoResultExt<T> { + fn with_err_path<F, P>(self, path: F) -> Self + where + F: FnOnce() -> P, + P: Into<PathBuf>; +} + +impl<T> IoResultExt<T> for Result<T, io::Error> { + fn with_err_path<F, P>(self, path: F) -> Self + where + F: FnOnce() -> P, + P: Into<PathBuf>, + { + self.map_err(|e| { + io::Error::new( + e.kind(), + PathError { + path: path().into(), + err: e, + }, + ) + }) + } +} diff --git a/tempfile/src/file/imp/mod.rs b/tempfile/src/file/imp/mod.rs new file mode 100644 index 000000000..31e872886 --- /dev/null +++ b/tempfile/src/file/imp/mod.rs @@ -0,0 +1,12 @@ +cfg_if! { + if #[cfg(any(unix, target_os = "redox"))] { + mod unix; + pub use self::unix::*; + } else if #[cfg(windows)] { + mod windows; + pub use self::windows::*; + } else { + mod other; + pub use self::other::*; + } +} diff --git a/tempfile/src/file/imp/other.rs b/tempfile/src/file/imp/other.rs new file mode 100644 index 000000000..095ff40d9 --- /dev/null +++ b/tempfile/src/file/imp/other.rs @@ -0,0 +1,30 @@ +use std::fs::File; +use std::io; +use std::path::Path; + +fn not_supported<T>() -> io::Result<T> { + Err(io::Error::new( + io::ErrorKind::Other, + "operation not supported on this platform", + )) +} + +pub fn create_named(_path: &Path) -> io::Result<File> { + not_supported() +} + +pub fn create(_dir: &Path) -> io::Result<File> { + not_supported() +} + +pub fn reopen(_file: &File, _path: &Path) -> io::Result<File> { + not_supported() +} + +pub fn persist(_old_path: &Path, _new_path: &Path, _overwrite: bool) -> io::Result<()> { + not_supported() +} + +pub fn keep(path: &Path) -> io::Result<()> { + not_supported() +} diff --git a/tempfile/src/file/imp/unix.rs b/tempfile/src/file/imp/unix.rs new file mode 100644 index 000000000..eb76e612c --- /dev/null +++ b/tempfile/src/file/imp/unix.rs @@ -0,0 +1,137 @@ +use std::env; +use std::ffi::{CString, OsStr}; +use std::fs::{self, File, OpenOptions}; +use std::io; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; +use std::path::Path; +use util; + +#[cfg(not(target_os = "redox"))] +use libc::{c_char, c_int, link, rename, unlink}; + +#[cfg(not(target_os = "redox"))] +#[inline(always)] +pub fn cvt_err(result: c_int) -> io::Result<c_int> { + if result == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(result) + } +} + +#[cfg(target_os = "redox")] +#[inline(always)] +pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> { + result.map_err(|err| io::Error::from_raw_os_error(err.errno)) +} + +// Stolen from std. +pub fn cstr(path: &Path) -> io::Result<CString> { + CString::new(path.as_os_str().as_bytes()) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null")) +} + +pub fn create_named(path: &Path) -> io::Result<File> { + OpenOptions::new() + .read(true) + .write(true) + .create_new(true) + .mode(0o600) + .open(path) +} + +fn create_unlinked(path: &Path) -> io::Result<File> { + let tmp; + // shadow this to decrease the lifetime. It can't live longer than `tmp`. + let mut path = path; + if !path.is_absolute() { + let cur_dir = env::current_dir()?; + tmp = cur_dir.join(path); + path = &tmp; + } + + let f = create_named(path)?; + // don't care whether the path has already been unlinked, + // but perhaps there are some IO error conditions we should send up? + let _ = fs::remove_file(path); + Ok(f) +} + +#[cfg(target_os = "linux")] +pub fn create(dir: &Path) -> io::Result<File> { + use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE}; + OpenOptions::new() + .read(true) + .write(true) + .custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)` + .open(dir) + .or_else(|e| { + match e.raw_os_error() { + // These are the three "not supported" error codes for O_TMPFILE. + Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir), + _ => Err(e), + } + }) +} + +#[cfg(not(target_os = "linux"))] +pub fn create(dir: &Path) -> io::Result<File> { + create_unix(dir) +} + +fn create_unix(dir: &Path) -> io::Result<File> { + util::create_helper( + dir, + OsStr::new(".tmp"), + OsStr::new(""), + ::NUM_RAND_CHARS, + |path| create_unlinked(&path), + ) +} + +pub fn reopen(file: &File, path: &Path) -> io::Result<File> { + let new_file = OpenOptions::new().read(true).write(true).open(path)?; + let old_meta = file.metadata()?; + let new_meta = new_file.metadata()?; + if old_meta.dev() != new_meta.dev() || old_meta.ino() != new_meta.ino() { + return Err(io::Error::new( + io::ErrorKind::NotFound, + "original tempfile has been replaced", + )); + } + Ok(new_file) +} + +#[cfg(not(target_os = "redox"))] +pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> { + unsafe { + let old_path = cstr(old_path)?; + let new_path = cstr(new_path)?; + if overwrite { + cvt_err(rename( + old_path.as_ptr() as *const c_char, + new_path.as_ptr() as *const c_char, + ))?; + } else { + cvt_err(link( + old_path.as_ptr() as *const c_char, + new_path.as_ptr() as *const c_char, + ))?; + // Ignore unlink errors. Can we do better? + // On recent linux, we can use renameat2 to do this atomically. + let _ = unlink(old_path.as_ptr() as *const c_char); + } + Ok(()) + } +} + +#[cfg(target_os = "redox")] +pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> { + // XXX implement when possible + Err(io::Error::from_raw_os_error(syscall::ENOSYS)) +} + +pub fn keep(_: &Path) -> io::Result<()> { + Ok(()) +} diff --git a/tempfile/src/file/imp/windows.rs b/tempfile/src/file/imp/windows.rs new file mode 100644 index 000000000..3b35f5c72 --- /dev/null +++ b/tempfile/src/file/imp/windows.rs @@ -0,0 +1,108 @@ +use std::ffi::OsStr; +use std::fs::{File, OpenOptions}; +use std::os::windows::ffi::OsStrExt; +use std::os::windows::fs::OpenOptionsExt; +use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle}; +use std::path::Path; +use std::{io, iter}; + +use winapi::um::fileapi::SetFileAttributesW; +use winapi::um::handleapi::INVALID_HANDLE_VALUE; +use winapi::um::winbase::{MoveFileExW, ReOpenFile}; +use winapi::um::winbase::{FILE_FLAG_DELETE_ON_CLOSE, MOVEFILE_REPLACE_EXISTING}; +use winapi::um::winnt::{FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY}; +use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, HANDLE}; +use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; + +use util; + +fn to_utf16(s: &Path) -> Vec<u16> { + s.as_os_str().encode_wide().chain(iter::once(0)).collect() +} + +pub fn create_named(path: &Path) -> io::Result<File> { + OpenOptions::new() + .create_new(true) + .read(true) + .write(true) + .custom_flags(FILE_ATTRIBUTE_TEMPORARY) + .open(path) +} + +pub fn create(dir: &Path) -> io::Result<File> { + util::create_helper( + dir, + OsStr::new(".tmp"), + OsStr::new(""), + ::NUM_RAND_CHARS, + |path| { + OpenOptions::new() + .create_new(true) + .read(true) + .write(true) + .share_mode(0) + .custom_flags(FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE) + .open(path) + }, + ) +} + +pub fn reopen(file: &File, _path: &Path) -> io::Result<File> { + let handle = file.as_raw_handle(); + unsafe { + let handle = ReOpenFile( + handle as HANDLE, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + ); + if handle == INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) + } else { + Ok(FromRawHandle::from_raw_handle(handle as RawHandle)) + } + } +} + +pub fn keep(path: &Path) -> io::Result<()> { + unsafe { + let path_w = to_utf16(path); + if SetFileAttributesW(path_w.as_ptr(), FILE_ATTRIBUTE_NORMAL) == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } +} + +pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> { + // TODO: We should probably do this in one-shot using SetFileInformationByHandle but the API is + // really painful. + + unsafe { + let old_path_w = to_utf16(old_path); + let new_path_w = to_utf16(new_path); + + // Don't succeed if this fails. We don't want to claim to have successfully persisted a file + // still marked as temporary because this file won't have the same consistency guarantees. + if SetFileAttributesW(old_path_w.as_ptr(), FILE_ATTRIBUTE_NORMAL) == 0 { + return Err(io::Error::last_os_error()); + } + + let mut flags = 0; + + if overwrite { + flags |= MOVEFILE_REPLACE_EXISTING; + } + + if MoveFileExW(old_path_w.as_ptr(), new_path_w.as_ptr(), flags) == 0 { + let e = io::Error::last_os_error(); + // If this fails, the temporary file is now un-hidden and no longer marked temporary + // (slightly less efficient) but it will still work. + let _ = SetFileAttributesW(old_path_w.as_ptr(), FILE_ATTRIBUTE_TEMPORARY); + Err(e) + } else { + Ok(()) + } + } +} diff --git a/tempfile/src/file/mod.rs b/tempfile/src/file/mod.rs new file mode 100644 index 000000000..ee1c4f211 --- /dev/null +++ b/tempfile/src/file/mod.rs @@ -0,0 +1,910 @@ +use std; +use std::env; +use std::error; +use std::ffi::OsStr; +use std::fmt; +use std::fs::{self, File}; +use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::mem; +use std::ops::Deref; +use std::path::{Path, PathBuf}; + +use error::IoResultExt; +use Builder; + +mod imp; + +/// Create a new temporary file. +/// +/// The file will be created in the location returned by [`std::env::temp_dir()`]. +/// +/// # Security +/// +/// This variant is secure/reliable in the presence of a pathological temporary file cleaner. +/// +/// # Resource Leaking +/// +/// The temporary file will be automatically removed by the OS when the last handle to it is closed. +/// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file. +/// +/// # Errors +/// +/// If the file can not be created, `Err` is returned. +/// +/// # Examples +/// +/// ``` +/// # extern crate tempfile; +/// use tempfile::tempfile; +/// use std::io::{self, Write}; +/// +/// # fn main() { +/// # if let Err(_) = run() { +/// # ::std::process::exit(1); +/// # } +/// # } +/// # fn run() -> Result<(), io::Error> { +/// // Create a file inside of `std::env::temp_dir()`. +/// let mut file = tempfile()?; +/// +/// writeln!(file, "Brian was here. Briefly.")?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html +pub fn tempfile() -> io::Result<File> { + tempfile_in(&env::temp_dir()) +} + +/// Create a new temporary file in the specified directory. +/// +/// # Security +/// +/// This variant is secure/reliable in the presence of a pathological temporary file cleaner. +/// If the temporary file isn't created in [`std::env::temp_dir()`] then temporary file cleaners aren't an issue. +/// +/// # Resource Leaking +/// +/// The temporary file will be automatically removed by the OS when the last handle to it is closed. +/// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file. +/// +/// # Errors +/// +/// If the file can not be created, `Err` is returned. +/// +/// # Examples +/// +/// ``` +/// # extern crate tempfile; +/// use tempfile::tempfile_in; +/// use std::io::{self, Write}; +/// +/// # fn main() { +/// # if let Err(_) = run() { +/// # ::std::process::exit(1); +/// # } +/// # } +/// # fn run() -> Result<(), io::Error> { +/// // Create a file inside of the current working directory +/// let mut file = tempfile_in("./")?; +/// +/// writeln!(file, "Brian was here. Briefly.")?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html +pub fn tempfile_in<P: AsRef<Path>>(dir: P) -> io::Result<File> { + imp::create(dir.as_ref()) +} + +/// Error returned when persisting a temporary file path fails. +#[derive(Debug)] +pub struct PathPersistError { + /// The underlying IO error. + pub error: io::Error, + /// The temporary file path that couldn't be persisted. + pub path: TempPath, +} + +impl From<PathPersistError> for io::Error { + #[inline] + fn from(error: PathPersistError) -> io::Error { + error.error + } +} + +impl From<PathPersistError> for TempPath { + #[inline] + fn from(error: PathPersistError) -> TempPath { + error.path + } +} + +impl fmt::Display for PathPersistError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to persist temporary file path: {}", self.error) + } +} + +impl error::Error for PathPersistError { + fn description(&self) -> &str { + "failed to persist temporary file path" + } + + fn cause(&self) -> Option<&error::Error> { + Some(&self.error) + } +} + +/// A path to a named temporary file without an open file handle. +/// +/// This is useful when the temporary file needs to be used by a child process, +/// for example. +/// +/// When dropped, the temporary file is deleted. +pub struct TempPath { + path: PathBuf, +} + +impl TempPath { + /// Close and remove the temporary file. + /// + /// Use this if you want to detect errors in deleting the file. + /// + /// # Errors + /// + /// If the file cannot be deleted, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # extern crate tempfile; + /// # use std::io; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// // Close the file, but keep the path to it around. + /// let path = file.into_temp_path(); + /// + /// // By closing the `TempPath` explicitly, we can check that it has + /// // been deleted successfully. If we don't close it explicitly, the + /// // file will still be deleted when `file` goes out of scope, but we + /// // won't know whether deleting the file succeeded. + /// path.close()?; + /// # Ok(()) + /// # } + /// ``` + pub fn close(mut self) -> io::Result<()> { + let result = fs::remove_file(&self.path).with_err_path(|| &self.path); + mem::replace(&mut self.path, PathBuf::new()); + mem::forget(self); + result + } + + /// Persist the temporary file at the target path. + /// + /// If a file exists at the target path, persist will atomically replace it. + /// If this method fails, it will return `self` in the resulting + /// [`PathPersistError`]. + /// + /// Note: Temporary files cannot be persisted across filesystems. + /// + /// # Security + /// + /// Only use this method if you're positive that a temporary file cleaner + /// won't have deleted your file. Otherwise, you might end up persisting an + /// attacker controlled file. + /// + /// # Errors + /// + /// If the file cannot be moved to the new location, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let mut file = NamedTempFile::new()?; + /// writeln!(file, "Brian was here. Briefly.")?; + /// + /// let path = file.into_temp_path(); + /// path.persist("./saved_file.txt")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`PathPersistError`]: struct.PathPersistError.html + pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<(), PathPersistError> { + match imp::persist(&self.path, new_path.as_ref(), true) { + Ok(_) => { + // Don't drop `self`. We don't want to try deleting the old + // temporary file path. (It'll fail, but the failure is never + // seen.) + mem::replace(&mut self.path, PathBuf::new()); + mem::forget(self); + Ok(()) + } + Err(e) => Err(PathPersistError { + error: e, + path: self, + }), + } + } + + /// Persist the temporary file at the target path iff no file exists there. + /// + /// If a file exists at the target path, fail. If this method fails, it will + /// return `self` in the resulting [`PathPersistError`]. + /// + /// Note: Temporary files cannot be persisted across filesystems. Also Note: + /// This method is not atomic. It can leave the original link to the + /// temporary file behind. + /// + /// # Security + /// + /// Only use this method if you're positive that a temporary file cleaner + /// won't have deleted your file. Otherwise, you might end up persisting an + /// attacker controlled file. + /// + /// # Errors + /// + /// If the file cannot be moved to the new location or a file already exists + /// there, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let mut file = NamedTempFile::new()?; + /// writeln!(file, "Brian was here. Briefly.")?; + /// + /// let path = file.into_temp_path(); + /// path.persist_noclobber("./saved_file.txt")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`PathPersistError`]: struct.PathPersistError.html + pub fn persist_noclobber<P: AsRef<Path>>( + mut self, + new_path: P, + ) -> Result<(), PathPersistError> { + match imp::persist(&self.path, new_path.as_ref(), false) { + Ok(_) => { + // Don't drop `self`. We don't want to try deleting the old + // temporary file path. (It'll fail, but the failure is never + // seen.) + mem::replace(&mut self.path, PathBuf::new()); + mem::forget(self); + Ok(()) + } + Err(e) => Err(PathPersistError { + error: e, + path: self, + }), + } + } + + /// Keep the temporary file from being deleted. This function will turn the + /// temporary file into a non-temporary file without moving it. + /// + /// + /// # Errors + /// + /// On some platforms (e.g., Windows), we need to mark the file as + /// non-temporary. This operation could fail. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let mut file = NamedTempFile::new()?; + /// writeln!(file, "Brian was here. Briefly.")?; + /// + /// let path = file.into_temp_path(); + /// let path = path.keep()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`PathPersistError`]: struct.PathPersistError.html + pub fn keep(mut self) -> Result<PathBuf, PathPersistError> { + match imp::keep(&self.path) { + Ok(_) => { + // Don't drop `self`. We don't want to try deleting the old + // temporary file path. (It'll fail, but the failure is never + // seen.) + let mut path = PathBuf::new(); + mem::swap(&mut self.path, &mut path); + mem::forget(self); + Ok(path) + } + Err(e) => Err(PathPersistError { + error: e, + path: self, + }), + } + } +} + +impl fmt::Debug for TempPath { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.path.fmt(f) + } +} + +impl Drop for TempPath { + fn drop(&mut self) { + let _ = fs::remove_file(&self.path); + } +} + +impl Deref for TempPath { + type Target = Path; + + fn deref(&self) -> &Path { + &self.path + } +} + +impl AsRef<Path> for TempPath { + fn as_ref(&self) -> &Path { + &self.path + } +} + +impl AsRef<OsStr> for TempPath { + fn as_ref(&self) -> &OsStr { + self.path.as_os_str() + } +} + +/// A named temporary file. +/// +/// The default constructor, [`NamedTempFile::new()`], creates files in +/// the location returned by [`std::env::temp_dir()`], but `NamedTempFile` +/// can be configured to manage a temporary file in any location +/// by constructing with [`NamedTempFile::new_in()`]. +/// +/// # Security +/// +/// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner. +/// +/// # Resource Leaking +/// +/// If the program exits before the `NamedTempFile` destructor is +/// run, such as via [`std::process::exit()`], by segfaulting, or by +/// receiving a signal like `SIGINT`, then the temporary file +/// will not be deleted. +/// +/// Use the [`tempfile()`] function unless you absolutely need a named file. +/// +/// [`tempfile()`]: fn.tempfile.html +/// [`NamedTempFile::new()`]: #method.new +/// [`NamedTempFile::new_in()`]: #method.new_in +/// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html +/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html +pub struct NamedTempFile { + path: TempPath, + file: File, +} + +impl fmt::Debug for NamedTempFile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NamedTempFile({:?})", self.path) + } +} + +impl AsRef<Path> for NamedTempFile { + #[inline] + fn as_ref(&self) -> &Path { + self.path() + } +} + +/// Error returned when persisting a temporary file fails. +#[derive(Debug)] +pub struct PersistError { + /// The underlying IO error. + pub error: io::Error, + /// The temporary file that couldn't be persisted. + pub file: NamedTempFile, +} + +impl From<PersistError> for io::Error { + #[inline] + fn from(error: PersistError) -> io::Error { + error.error + } +} + +impl From<PersistError> for NamedTempFile { + #[inline] + fn from(error: PersistError) -> NamedTempFile { + error.file + } +} + +impl fmt::Display for PersistError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to persist temporary file: {}", self.error) + } +} + +impl error::Error for PersistError { + fn description(&self) -> &str { + "failed to persist temporary file" + } + fn cause(&self) -> Option<&error::Error> { + Some(&self.error) + } +} + +impl NamedTempFile { + /// Create a new named temporary file. + /// + /// See [`Builder`] for more configuration. + /// + /// # Security + /// + /// This will create a temporary file in the default temporary file + /// directory (platform dependent). These directories are often patrolled by temporary file + /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't + /// delete your file. + /// + /// Reasons to use this method: + /// + /// 1. The file has a short lifetime and your temporary file cleaner is + /// sane (doesn't delete recently accessed files). + /// + /// 2. You trust every user on your system (i.e. you are the only user). + /// + /// 3. You have disabled your system's temporary file cleaner or verified + /// that your system doesn't have a temporary file cleaner. + /// + /// Reasons not to use this method: + /// + /// 1. You'll fix it later. No you won't. + /// + /// 2. You don't care about the security of the temporary file. If none of + /// the "reasons to use this method" apply, referring to a temporary + /// file by name may allow an attacker to create/overwrite your + /// non-temporary files. There are exceptions but if you don't already + /// know them, don't use this method. + /// + /// # Errors + /// + /// If the file can not be created, `Err` is returned. + /// + /// # Examples + /// + /// Create a named temporary file and write some data to it: + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), ::std::io::Error> { + /// let mut file = NamedTempFile::new()?; + /// + /// writeln!(file, "Brian was here. Briefly.")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`Builder`]: struct.Builder.html + pub fn new() -> io::Result<NamedTempFile> { + Builder::new().tempfile() + } + + /// Create a new named temporary file in the specified directory. + /// + /// See [`NamedTempFile::new()`] for details. + /// + /// [`NamedTempFile::new()`]: #method.new_in + pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> { + Builder::new().tempfile_in(dir) + } + + /// Get the temporary file's path. + /// + /// # Security + /// + /// Only use this method if you're positive that a + /// temporary file cleaner won't have deleted your file. Otherwise, the path + /// returned by this method may refer to an attacker controlled file. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), ::std::io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// println!("{:?}", file.path()); + /// # Ok(()) + /// # } + /// ``` + #[inline] + pub fn path(&self) -> &Path { + &self.path + } + + /// Close and remove the temporary file. + /// + /// Use this if you want to detect errors in deleting the file. + /// + /// # Errors + /// + /// If the file cannot be deleted, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # extern crate tempfile; + /// # use std::io; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// // By closing the `NamedTempFile` explicitly, we can check that it has + /// // been deleted successfully. If we don't close it explicitly, + /// // the file will still be deleted when `file` goes out + /// // of scope, but we won't know whether deleting the file + /// // succeeded. + /// file.close()?; + /// # Ok(()) + /// # } + /// ``` + pub fn close(self) -> io::Result<()> { + let NamedTempFile { path, .. } = self; + path.close() + } + + /// Persist the temporary file at the target path. + /// + /// If a file exists at the target path, persist will atomically replace it. + /// If this method fails, it will return `self` in the resulting + /// [`PersistError`]. + /// + /// Note: Temporary files cannot be persisted across filesystems. + /// + /// # Security + /// + /// Only use this method if you're positive that a + /// temporary file cleaner won't have deleted your file. Otherwise, you + /// might end up persisting an attacker controlled file. + /// + /// # Errors + /// + /// If the file cannot be moved to the new location, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// let mut persisted_file = file.persist("./saved_file.txt")?; + /// writeln!(persisted_file, "Brian was here. Briefly.")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`PersistError`]: struct.PersistError.html + pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> { + let NamedTempFile { path, file } = self; + match path.persist(new_path) { + Ok(_) => Ok(file), + Err(err) => { + let PathPersistError { error, path } = err; + Err(PersistError { + file: NamedTempFile { path, file }, + error, + }) + } + } + } + + /// Persist the temporary file at the target path iff no file exists there. + /// + /// If a file exists at the target path, fail. If this method fails, it will + /// return `self` in the resulting PersistError. + /// + /// Note: Temporary files cannot be persisted across filesystems. Also Note: + /// This method is not atomic. It can leave the original link to the + /// temporary file behind. + /// + /// # Security + /// + /// Only use this method if you're positive that a + /// temporary file cleaner won't have deleted your file. Otherwise, you + /// might end up persisting an attacker controlled file. + /// + /// # Errors + /// + /// If the file cannot be moved to the new location or a file already exists there, + /// `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// let mut persisted_file = file.persist_noclobber("./saved_file.txt")?; + /// writeln!(persisted_file, "Brian was here. Briefly.")?; + /// # Ok(()) + /// # } + /// ``` + pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> { + let NamedTempFile { path, file } = self; + match path.persist_noclobber(new_path) { + Ok(_) => Ok(file), + Err(err) => { + let PathPersistError { error, path } = err; + Err(PersistError { + file: NamedTempFile { path, file }, + error, + }) + } + } + } + + /// Keep the temporary file from being deleted. This function will turn the + /// temporary file into a non-temporary file without moving it. + /// + /// + /// # Errors + /// + /// On some platforms (e.g., Windows), we need to mark the file as + /// non-temporary. This operation could fail. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io::{self, Write}; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let mut file = NamedTempFile::new()?; + /// writeln!(file, "Brian was here. Briefly.")?; + /// + /// let (file, path) = file.keep()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [`PathPersistError`]: struct.PathPersistError.html + pub fn keep(self) -> Result<(File, PathBuf), PersistError> { + let (file, path) = (self.file, self.path); + match path.keep() { + Ok(path) => Ok((file, path)), + Err(PathPersistError { error, path }) => Err(PersistError { + file: NamedTempFile { path, file }, + error, + }), + } + } + + /// Reopen the temporary file. + /// + /// This function is useful when you need multiple independent handles to + /// the same file. It's perfectly fine to drop the original `NamedTempFile` + /// while holding on to `File`s returned by this function; the `File`s will + /// remain usable. However, they may not be nameable. + /// + /// # Errors + /// + /// If the file cannot be reopened, `Err` is returned. + /// + /// # Examples + /// + /// ```no_run + /// # use std::io; + /// # extern crate tempfile; + /// use tempfile::NamedTempFile; + /// + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// let file = NamedTempFile::new()?; + /// + /// let another_handle = file.reopen()?; + /// # Ok(()) + /// # } + /// ``` + pub fn reopen(&self) -> io::Result<File> { + imp::reopen(self.as_file(), NamedTempFile::path(self)) + .with_err_path(|| NamedTempFile::path(self)) + } + + /// Get a reference to the underlying file. + pub fn as_file(&self) -> &File { + &self.file + } + + /// Get a mutable reference to the underlying file. + pub fn as_file_mut(&mut self) -> &mut File { + &mut self.file + } + + /// Convert the temporary file into a `std::fs::File`. + /// + /// The inner file will be deleted. + pub fn into_file(self) -> File { + self.file + } + + /// Closes the file, leaving only the temporary file path. + /// + /// This is useful when another process must be able to open the temporary + /// file. + pub fn into_temp_path(self) -> TempPath { + self.path + } + + /// Converts the named temporary file into its constituent parts. + /// + /// Note: When the path is dropped, the file is deleted but the file handle + /// is still usable. + pub fn into_parts(self) -> (File, TempPath) { + (self.file, self.path) + } +} + +impl Read for NamedTempFile { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.as_file_mut().read(buf).with_err_path(|| self.path()) + } +} + +impl<'a> Read for &'a NamedTempFile { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.as_file().read(buf).with_err_path(|| self.path()) + } +} + +impl Write for NamedTempFile { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.as_file_mut().write(buf).with_err_path(|| self.path()) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + self.as_file_mut().flush().with_err_path(|| self.path()) + } +} + +impl<'a> Write for &'a NamedTempFile { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.as_file().write(buf).with_err_path(|| self.path()) + } + #[inline] + fn flush(&mut self) -> io::Result<()> { + self.as_file().flush().with_err_path(|| self.path()) + } +} + +impl Seek for NamedTempFile { + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + self.as_file_mut().seek(pos).with_err_path(|| self.path()) + } +} + +impl<'a> Seek for &'a NamedTempFile { + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + self.as_file().seek(pos).with_err_path(|| self.path()) + } +} + +#[cfg(unix)] +impl std::os::unix::io::AsRawFd for NamedTempFile { + #[inline] + fn as_raw_fd(&self) -> std::os::unix::io::RawFd { + self.as_file().as_raw_fd() + } +} + +#[cfg(windows)] +impl std::os::windows::io::AsRawHandle for NamedTempFile { + #[inline] + fn as_raw_handle(&self) -> std::os::windows::io::RawHandle { + self.as_file().as_raw_handle() + } +} + +pub(crate) fn create_named(mut path: PathBuf) -> io::Result<NamedTempFile> { + // Make the path absolute. Otherwise, changing directories could cause us to + // delete the wrong file. + if !path.is_absolute() { + path = env::current_dir()?.join(path) + } + imp::create_named(&path) + .with_err_path(|| path.clone()) + .map(|file| NamedTempFile { + path: TempPath { path }, + file, + }) +} diff --git a/tempfile/src/lib.rs b/tempfile/src/lib.rs new file mode 100644 index 000000000..df04d0798 --- /dev/null +++ b/tempfile/src/lib.rs @@ -0,0 +1,455 @@ +//! Temporary files and directories. +//! +//! - Use the [`tempfile()`] function for temporary files +//! - Use the [`tempdir()`] function for temporary directories. +//! +//! # Design +//! +//! This crate provides several approaches to creating temporary files and directories. +//! [`tempfile()`] relies on the OS to remove the temporary file once the last handle is closed. +//! [`TempDir`] and [`NamedTempFile`] both rely on Rust destructors for cleanup. +//! +//! When choosing between the temporary file variants, prefer `tempfile` +//! unless you either need to know the file's path or to be able to persist it. +//! +//! ## Resource Leaking +//! +//! `tempfile` will (almost) never fail to cleanup temporary resources, but `TempDir` and `NamedTempFile` will if +//! their destructors don't run. This is because `tempfile` relies on the OS to cleanup the +//! underlying file, while `TempDir` and `NamedTempFile` rely on their destructors to do so. +//! +//! ## Security +//! +//! In the presence of pathological temporary file cleaner, relying on file paths is unsafe because +//! a temporary file cleaner could delete the temporary file which an attacker could then replace. +//! +//! `tempfile` doesn't rely on file paths so this isn't an issue. However, `NamedTempFile` does +//! rely on file paths. +//! +//! ## Examples +//! +//! Create a temporary file and write some data into it: +//! +//! ``` +//! # extern crate tempfile; +//! use tempfile::tempfile; +//! use std::io::{self, Write}; +//! +//! # fn main() { +//! # if let Err(_) = run() { +//! # ::std::process::exit(1); +//! # } +//! # } +//! # fn run() -> Result<(), io::Error> { +//! // Create a file inside of `std::env::temp_dir()`. +//! let mut file = tempfile()?; +//! +//! writeln!(file, "Brian was here. Briefly.")?; +//! # Ok(()) +//! # } +//! ``` +//! +//! Create a temporary directory and add a file to it: +//! +//! ``` +//! # extern crate tempfile; +//! use tempfile::tempdir; +//! use std::fs::File; +//! use std::io::{self, Write}; +//! +//! # fn main() { +//! # if let Err(_) = run() { +//! # ::std::process::exit(1); +//! # } +//! # } +//! # fn run() -> Result<(), io::Error> { +//! // Create a directory inside of `std::env::temp_dir()`. +//! let dir = tempdir()?; +//! +//! let file_path = dir.path().join("my-temporary-note.txt"); +//! let mut file = File::create(file_path)?; +//! writeln!(file, "Brian was here. Briefly.")?; +//! +//! // By closing the `TempDir` explicitly, we can check that it has +//! // been deleted successfully. If we don't close it explicitly, +//! // the directory will still be deleted when `dir` goes out +//! // of scope, but we won't know whether deleting the directory +//! // succeeded. +//! drop(file); +//! dir.close()?; +//! # Ok(()) +//! # } +//! ``` +//! +//! [`tempfile()`]: fn.tempfile.html +//! [`tempdir()`]: fn.tempdir.html +//! [`TempDir`]: struct.TempDir.html +//! [`NamedTempFile`]: struct.NamedTempFile.html +//! [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html + +#![doc( + html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://docs.rs/tempfile/2.2.0" +)] +#![cfg_attr(test, deny(warnings))] + +#[macro_use] +extern crate cfg_if; +extern crate rand; +extern crate remove_dir_all; + +#[cfg(unix)] +extern crate libc; + +#[cfg(windows)] +extern crate winapi; + +#[cfg(target_os = "redox")] +extern crate syscall; + +const NUM_RETRIES: u32 = 1 << 31; +const NUM_RAND_CHARS: usize = 6; + +use std::ffi::OsStr; +use std::path::Path; +use std::{env, io}; + +mod dir; +mod error; +mod file; +mod spooled; +mod util; + +pub use dir::{tempdir, tempdir_in, TempDir}; +pub use file::{tempfile, tempfile_in, NamedTempFile, PathPersistError, PersistError, TempPath}; +pub use spooled::{spooled_tempfile, SpooledTempFile}; + +/// Create a new temporary file or directory with custom parameters. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Builder<'a, 'b> { + random_len: usize, + prefix: &'a OsStr, + suffix: &'b OsStr, +} + +impl<'a, 'b> Default for Builder<'a, 'b> { + fn default() -> Self { + Builder { + random_len: ::NUM_RAND_CHARS, + prefix: OsStr::new(".tmp"), + suffix: OsStr::new(""), + } + } +} + +impl<'a, 'b> Builder<'a, 'b> { + /// Create a new `Builder`. + /// + /// # Examples + /// + /// Create a named temporary file and write some data into it: + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # use std::ffi::OsStr; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// use tempfile::Builder; + /// + /// let named_tempfile = Builder::new() + /// .prefix("my-temporary-note") + /// .suffix(".txt") + /// .rand_bytes(5) + /// .tempfile()?; + /// + /// let name = named_tempfile + /// .path() + /// .file_name().and_then(OsStr::to_str); + /// + /// if let Some(name) = name { + /// assert!(name.starts_with("my-temporary-note")); + /// assert!(name.ends_with(".txt")); + /// assert_eq!(name.len(), "my-temporary-note.txt".len() + 5); + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// Create a temporary directory and add a file to it: + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io::{self, Write}; + /// # use std::fs::File; + /// # use std::ffi::OsStr; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// use tempfile::Builder; + /// + /// let dir = Builder::new() + /// .prefix("my-temporary-dir") + /// .rand_bytes(5) + /// .tempdir()?; + /// + /// let file_path = dir.path().join("my-temporary-note.txt"); + /// let mut file = File::create(file_path)?; + /// writeln!(file, "Brian was here. Briefly.")?; + /// + /// // By closing the `TempDir` explicitly, we can check that it has + /// // been deleted successfully. If we don't close it explicitly, + /// // the directory will still be deleted when `dir` goes out + /// // of scope, but we won't know whether deleting the directory + /// // succeeded. + /// drop(file); + /// dir.close()?; + /// # Ok(()) + /// # } + /// ``` + pub fn new() -> Self { + Self::default() + } + + /// Set a custom filename prefix. + /// + /// Path separators are legal but not advisable. + /// Default: `.tmp`. + /// + /// # Examples + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// # use tempfile::Builder; + /// let named_tempfile = Builder::new() + /// .prefix("my-temporary-note") + /// .tempfile()?; + /// # Ok(()) + /// # } + /// ``` + pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self { + self.prefix = prefix.as_ref(); + self + } + + /// Set a custom filename suffix. + /// + /// Path separators are legal but not advisable. + /// Default: empty. + /// + /// # Examples + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// # use tempfile::Builder; + /// let named_tempfile = Builder::new() + /// .suffix(".txt") + /// .tempfile()?; + /// # Ok(()) + /// # } + /// ``` + pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self { + self.suffix = suffix.as_ref(); + self + } + + /// Set the number of random bytes. + /// + /// Default: `6`. + /// + /// # Examples + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// # use tempfile::Builder; + /// let named_tempfile = Builder::new() + /// .rand_bytes(5) + /// .tempfile()?; + /// # Ok(()) + /// # } + /// ``` + pub fn rand_bytes(&mut self, rand: usize) -> &mut Self { + self.random_len = rand; + self + } + + /// Create the named temporary file. + /// + /// # Security + /// + /// See [the security][security] docs on `NamedTempFile`. + /// + /// # Resource leaking + /// + /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`. + /// + /// # Errors + /// + /// If the file cannot be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// # use tempfile::Builder; + /// let tempfile = Builder::new().tempfile()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [security]: struct.NamedTempFile.html#security + /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking + pub fn tempfile(&self) -> io::Result<NamedTempFile> { + self.tempfile_in(&env::temp_dir()) + } + + /// Create the named temporary file in the specified directory. + /// + /// # Security + /// + /// See [the security][security] docs on `NamedTempFile`. + /// + /// # Resource leaking + /// + /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`. + /// + /// # Errors + /// + /// If the file cannot be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// # extern crate tempfile; + /// # use std::io; + /// # fn main() { + /// # if let Err(_) = run() { + /// # ::std::process::exit(1); + /// # } + /// # } + /// # fn run() -> Result<(), io::Error> { + /// # use tempfile::Builder; + /// let tempfile = Builder::new().tempfile_in("./")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [security]: struct.NamedTempFile.html#security + /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking + pub fn tempfile_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<NamedTempFile> { + util::create_helper( + dir.as_ref(), + self.prefix, + self.suffix, + self.random_len, + file::create_named, + ) + } + + /// Attempts to make a temporary directory inside of `env::temp_dir()` whose + /// name will have the prefix, `prefix`. The directory and + /// everything inside it will be automatically deleted once the + /// returned `TempDir` is destroyed. + /// + /// # Resource leaking + /// + /// See [the resource leaking][resource-leaking] docs on `TempDir`. + /// + /// # Errors + /// + /// If the directory can not be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::Write; + /// use tempfile::Builder; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// let tmp_dir = Builder::new().tempdir()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [resource-leaking]: struct.TempDir.html#resource-leaking + pub fn tempdir(&self) -> io::Result<TempDir> { + self.tempdir_in(&env::temp_dir()) + } + + /// Attempts to make a temporary directory inside of `dir`. + /// The directory and everything inside it will be automatically + /// deleted once the returned `TempDir` is destroyed. + /// + /// # Resource leaking + /// + /// See [the resource leaking][resource-leaking] docs on `TempDir`. + /// + /// # Errors + /// + /// If the directory can not be created, `Err` is returned. + /// + /// # Examples + /// + /// ``` + /// use std::fs::{self, File}; + /// use std::io::Write; + /// use tempfile::Builder; + /// + /// # use std::io; + /// # fn run() -> Result<(), io::Error> { + /// let tmp_dir = Builder::new().tempdir_in("./")?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [resource-leaking]: struct.TempDir.html#resource-leaking + pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> { + let storage; + let mut dir = dir.as_ref(); + if !dir.is_absolute() { + let cur_dir = env::current_dir()?; + storage = cur_dir.join(dir); + dir = &storage; + } + + util::create_helper(dir, self.prefix, self.suffix, self.random_len, dir::create) + } +} diff --git a/tempfile/src/spooled.rs b/tempfile/src/spooled.rs new file mode 100644 index 000000000..093477b8c --- /dev/null +++ b/tempfile/src/spooled.rs @@ -0,0 +1,153 @@ +use file::tempfile; +use std::fs::File; +use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; + +#[derive(Debug)] +enum SpooledInner { + InMemory(Cursor<Vec<u8>>), + OnDisk(File), +} + +/// An object that behaves like a regular temporary file, but keeps data in +/// memory until it reaches a configured size, at which point the data is +/// written to a temporary file on disk, and further operations use the file +/// on disk. +#[derive(Debug)] +pub struct SpooledTempFile { + max_size: usize, + inner: SpooledInner, +} + +/// Create a new spooled temporary file. +/// +/// # Security +/// +/// This variant is secure/reliable in the presence of a pathological temporary +/// file cleaner. +/// +/// # Resource Leaking +/// +/// The temporary file will be automatically removed by the OS when the last +/// handle to it is closed. This doesn't rely on Rust destructors being run, so +/// will (almost) never fail to clean up the temporary file. +/// +/// # Examples +/// +/// ``` +/// # extern crate tempfile; +/// use tempfile::spooled_tempfile; +/// use std::io::{self, Write}; +/// +/// # fn main() { +/// # if let Err(_) = run() { +/// # ::std::process::exit(1); +/// # } +/// # } +/// # fn run() -> Result<(), io::Error> { +/// let mut file = spooled_tempfile(15); +/// +/// writeln!(file, "short line")?; +/// assert!(!file.is_rolled()); +/// +/// // as a result of this write call, the size of the data will exceed +/// // `max_size` (15), so it will be written to a temporary file on disk, +/// // and the in-memory buffer will be dropped +/// writeln!(file, "marvin gardens")?; +/// assert!(file.is_rolled()); +/// +/// # Ok(()) +/// # } +/// ``` +#[inline] +pub fn spooled_tempfile(max_size: usize) -> SpooledTempFile { + SpooledTempFile::new(max_size) +} + +impl SpooledTempFile { + pub fn new(max_size: usize) -> SpooledTempFile { + SpooledTempFile { + max_size: max_size, + inner: SpooledInner::InMemory(Cursor::new(Vec::new())), + } + } + + /// Returns true if the file has been rolled over to disk. + pub fn is_rolled(&self) -> bool { + match self.inner { + SpooledInner::InMemory(_) => false, + SpooledInner::OnDisk(_) => true, + } + } + + /// Rolls over to a file on disk, regardless of current size. Does nothing + /// if already rolled over. + pub fn roll(&mut self) -> io::Result<()> { + if !self.is_rolled() { + let mut file = tempfile()?; + if let SpooledInner::InMemory(ref mut cursor) = self.inner { + file.write_all(cursor.get_ref())?; + file.seek(SeekFrom::Start(cursor.position()))?; + } + self.inner = SpooledInner::OnDisk(file); + } + Ok(()) + } + + pub fn set_len(&mut self, size: u64) -> Result<(), io::Error> { + if size as usize > self.max_size { + self.roll()?; // does nothing if already rolled over + } + match self.inner { + SpooledInner::InMemory(ref mut cursor) => { + cursor.get_mut().resize(size as usize, 0); + Ok(()) + } + SpooledInner::OnDisk(ref mut file) => file.set_len(size), + } + } +} + +impl Read for SpooledTempFile { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + match self.inner { + SpooledInner::InMemory(ref mut cursor) => cursor.read(buf), + SpooledInner::OnDisk(ref mut file) => file.read(buf), + } + } +} + +impl Write for SpooledTempFile { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + // roll over to file if necessary + let mut rolling = false; + if let SpooledInner::InMemory(ref mut cursor) = self.inner { + rolling = cursor.position() as usize + buf.len() > self.max_size; + } + if rolling { + self.roll()?; + } + + // write the bytes + match self.inner { + SpooledInner::InMemory(ref mut cursor) => cursor.write(buf), + SpooledInner::OnDisk(ref mut file) => file.write(buf), + } + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + match self.inner { + SpooledInner::InMemory(ref mut cursor) => cursor.flush(), + SpooledInner::OnDisk(ref mut file) => file.flush(), + } + } +} + +impl Seek for SpooledTempFile { + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + match self.inner { + SpooledInner::InMemory(ref mut cursor) => cursor.seek(pos), + SpooledInner::OnDisk(ref mut file) => file.seek(pos), + } + } +} diff --git a/tempfile/src/util.rs b/tempfile/src/util.rs new file mode 100644 index 000000000..42d1eeded --- /dev/null +++ b/tempfile/src/util.rs @@ -0,0 +1,51 @@ +use rand::distributions::Alphanumeric; +use rand::{self, Rng}; +use std::ffi::{OsStr, OsString}; +use std::path::{Path, PathBuf}; +use std::{io, str}; + +use error::IoResultExt; + +fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString { + let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len); + buf.push(prefix); + + // Push each character in one-by-one. Unfortunately, this is the only + // safe(ish) simple way to do this without allocating a temporary + // String/Vec. + unsafe { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(rand_len) + .for_each(|b| buf.push(str::from_utf8_unchecked(&[b as u8]))) + } + buf.push(suffix); + buf +} + +pub fn create_helper<F, R>( + base: &Path, + prefix: &OsStr, + suffix: &OsStr, + random_len: usize, + f: F, +) -> io::Result<R> +where + F: Fn(PathBuf) -> io::Result<R>, +{ + let num_retries = if random_len != 0 { ::NUM_RETRIES } else { 1 }; + + for _ in 0..num_retries { + let path = base.join(tmpname(prefix, suffix, random_len)); + return match f(path) { + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => continue, + res => res, + }; + } + + Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "too many temporary files exist", + )) + .with_err_path(|| base) +} diff --git a/tempfile/tests/namedtempfile.rs b/tempfile/tests/namedtempfile.rs new file mode 100644 index 000000000..2294285a5 --- /dev/null +++ b/tempfile/tests/namedtempfile.rs @@ -0,0 +1,269 @@ +extern crate tempfile; +use std::env; +use std::fs::File; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::path::Path; +use tempfile::{Builder, NamedTempFile}; + +fn exists<P: AsRef<Path>>(path: P) -> bool { + std::fs::metadata(path.as_ref()).is_ok() +} + +#[test] +fn test_basic() { + let mut tmpfile = NamedTempFile::new().unwrap(); + write!(tmpfile, "abcde").unwrap(); + tmpfile.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + tmpfile.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); +} + +#[test] +fn test_deleted() { + let tmpfile = NamedTempFile::new().unwrap(); + let path = tmpfile.path().to_path_buf(); + assert!(exists(&path)); + drop(tmpfile); + assert!(!exists(&path)); +} + +#[test] +fn test_persist() { + let mut tmpfile = NamedTempFile::new().unwrap(); + let old_path = tmpfile.path().to_path_buf(); + let persist_path = env::temp_dir().join("persisted_temporary_file"); + write!(tmpfile, "abcde").unwrap(); + { + assert!(exists(&old_path)); + let mut f = tmpfile.persist(&persist_path).unwrap(); + assert!(!exists(&old_path)); + + // Check original file + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + + { + // Try opening it at the new path. + let mut f = File::open(&persist_path).unwrap(); + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + std::fs::remove_file(&persist_path).unwrap(); +} + +#[test] +fn test_persist_noclobber() { + let mut tmpfile = NamedTempFile::new().unwrap(); + let old_path = tmpfile.path().to_path_buf(); + let persist_target = NamedTempFile::new().unwrap(); + let persist_path = persist_target.path().to_path_buf(); + write!(tmpfile, "abcde").unwrap(); + assert!(exists(&old_path)); + { + tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into(); + assert!(exists(&old_path)); + std::fs::remove_file(&persist_path).unwrap(); + drop(persist_target); + } + tmpfile.persist_noclobber(&persist_path).unwrap(); + // Try opening it at the new path. + let mut f = File::open(&persist_path).unwrap(); + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + std::fs::remove_file(&persist_path).unwrap(); +} + +#[test] +fn test_customnamed() { + let tmpfile = Builder::new() + .prefix("tmp") + .suffix(&".rs".to_string()) + .rand_bytes(12) + .tempfile() + .unwrap(); + let name = tmpfile.path().file_name().unwrap().to_str().unwrap(); + assert!(name.starts_with("tmp")); + assert!(name.ends_with(".rs")); + assert_eq!(name.len(), 18); +} + +#[test] +fn test_reopen() { + let source = NamedTempFile::new().unwrap(); + let mut first = source.reopen().unwrap(); + let mut second = source.reopen().unwrap(); + drop(source); + + write!(first, "abcde").expect("write failed"); + let mut buf = String::new(); + second.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); +} + +#[test] +fn test_into_file() { + let mut file = NamedTempFile::new().unwrap(); + let path = file.path().to_owned(); + write!(file, "abcde").expect("write failed"); + + assert!(path.exists()); + let mut file = file.into_file(); + assert!(!path.exists()); + + file.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); +} + +#[test] +fn test_immut() { + let tmpfile = NamedTempFile::new().unwrap(); + (&tmpfile).write_all(b"abcde").unwrap(); + (&tmpfile).seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + (&tmpfile).read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); +} + +#[test] +fn test_temppath() { + let mut tmpfile = NamedTempFile::new().unwrap(); + write!(tmpfile, "abcde").unwrap(); + + let path = tmpfile.into_temp_path(); + assert!(path.is_file()); +} + +#[test] +fn test_temppath_persist() { + let mut tmpfile = NamedTempFile::new().unwrap(); + write!(tmpfile, "abcde").unwrap(); + + let tmppath = tmpfile.into_temp_path(); + + let old_path = tmppath.to_path_buf(); + let persist_path = env::temp_dir().join("persisted_temppath_file"); + + { + assert!(exists(&old_path)); + tmppath.persist(&persist_path).unwrap(); + assert!(!exists(&old_path)); + } + + { + // Try opening it at the new path. + let mut f = File::open(&persist_path).unwrap(); + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + + std::fs::remove_file(&persist_path).unwrap(); +} + +#[test] +fn test_temppath_persist_noclobber() { + let mut tmpfile = NamedTempFile::new().unwrap(); + write!(tmpfile, "abcde").unwrap(); + + let mut tmppath = tmpfile.into_temp_path(); + + let old_path = tmppath.to_path_buf(); + let persist_target = NamedTempFile::new().unwrap(); + let persist_path = persist_target.path().to_path_buf(); + + assert!(exists(&old_path)); + + { + tmppath = tmppath.persist_noclobber(&persist_path).unwrap_err().into(); + assert!(exists(&old_path)); + std::fs::remove_file(&persist_path).unwrap(); + drop(persist_target); + } + + tmppath.persist_noclobber(&persist_path).unwrap(); + + // Try opening it at the new path. + let mut f = File::open(&persist_path).unwrap(); + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + std::fs::remove_file(&persist_path).unwrap(); +} + +#[test] +fn test_write_after_close() { + let path = NamedTempFile::new().unwrap().into_temp_path(); + File::create(path).unwrap().write_all(b"test").unwrap(); +} + +#[test] +fn test_change_dir() { + env::set_current_dir(env::temp_dir()).unwrap(); + let tmpfile = NamedTempFile::new_in(".").unwrap(); + let path = env::current_dir().unwrap().join(tmpfile.path()); + env::set_current_dir("/").unwrap(); + drop(tmpfile); + assert!(!exists(path)) +} + +#[test] +fn test_into_parts() { + let mut file = NamedTempFile::new().unwrap(); + write!(file, "abcd").expect("write failed"); + + let (mut file, temp_path) = file.into_parts(); + + let path = temp_path.to_path_buf(); + + assert!(path.exists()); + drop(temp_path); + assert!(!path.exists()); + + write!(file, "efgh").expect("write failed"); + + file.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + assert_eq!("abcdefgh", buf); +} + +#[test] +fn test_keep() { + let mut tmpfile = NamedTempFile::new().unwrap(); + write!(tmpfile, "abcde").unwrap(); + let (mut f, temp_path) = tmpfile.into_parts(); + let path; + { + assert!(exists(&temp_path)); + path = temp_path.keep().unwrap(); + assert!(exists(&path)); + + // Check original file + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + + { + // Try opening it again. + let mut f = File::open(&path).unwrap(); + f.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + f.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + std::fs::remove_file(&path).unwrap(); +} diff --git a/tempfile/tests/spooled.rs b/tempfile/tests/spooled.rs new file mode 100644 index 000000000..8481936bd --- /dev/null +++ b/tempfile/tests/spooled.rs @@ -0,0 +1,307 @@ +extern crate tempfile; + +use std::io::{Read, Seek, SeekFrom, Write}; + +use tempfile::{spooled_tempfile, SpooledTempFile}; + +#[test] +fn test_automatic_rollover() { + let mut t = spooled_tempfile(10); + let mut buf = Vec::new(); + + assert!(!t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf.as_slice(), b""); + buf.clear(); + + assert_eq!(t.write(b"abcde").unwrap(), 5); + + assert!(!t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 5); + assert_eq!(buf.as_slice(), b"abcde"); + + assert_eq!(t.write(b"fghijklmno").unwrap(), 10); + + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 15); + assert!(t.is_rolled()); +} + +#[test] +fn test_explicit_rollover() { + let mut t = SpooledTempFile::new(100); + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); + assert!(!t.is_rolled()); + + // roll over explicitly + assert!(t.roll().is_ok()); + assert!(t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); + + let mut buf = Vec::new(); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf.as_slice(), b""); + buf.clear(); + + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 26); + assert_eq!(buf.as_slice(), b"abcdefghijklmnopqrstuvwxyz"); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); +} + +// called by test_seek_{buffer, file} +// assumes t is empty and offset is 0 to start +fn test_seek(t: &mut SpooledTempFile) { + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell() + assert_eq!(t.seek(SeekFrom::Current(-1)).unwrap(), 25); + assert_eq!(t.seek(SeekFrom::Current(1)).unwrap(), 26); + assert_eq!(t.seek(SeekFrom::Current(1)).unwrap(), 27); + assert_eq!(t.seek(SeekFrom::Current(-27)).unwrap(), 0); + assert!(t.seek(SeekFrom::Current(-1)).is_err()); + assert!(t.seek(SeekFrom::Current(-1245)).is_err()); + + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.seek(SeekFrom::Start(1)).unwrap(), 1); + assert_eq!(t.seek(SeekFrom::Start(26)).unwrap(), 26); + assert_eq!(t.seek(SeekFrom::Start(27)).unwrap(), 27); + // // these are build errors + // assert!(t.seek(SeekFrom::Start(-1)).is_err()); + // assert!(t.seek(SeekFrom::Start(-1000)).is_err()); + + assert_eq!(t.seek(SeekFrom::End(0)).unwrap(), 26); + assert_eq!(t.seek(SeekFrom::End(-1)).unwrap(), 25); + assert_eq!(t.seek(SeekFrom::End(-26)).unwrap(), 0); + assert!(t.seek(SeekFrom::End(-27)).is_err()); + assert!(t.seek(SeekFrom::End(-99)).is_err()); + assert_eq!(t.seek(SeekFrom::End(1)).unwrap(), 27); + assert_eq!(t.seek(SeekFrom::End(1)).unwrap(), 27); +} + +#[test] +fn test_seek_buffer() { + let mut t = spooled_tempfile(100); + test_seek(&mut t); +} + +#[test] +fn test_seek_file() { + let mut t = SpooledTempFile::new(10); + test_seek(&mut t); +} + +fn test_seek_read(t: &mut SpooledTempFile) { + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + + let mut buf = Vec::new(); + + // we're at the end + assert_eq!(t.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf.as_slice(), b""); + buf.clear(); + + // seek to start, read whole thing + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 26); + assert_eq!(buf.as_slice(), b"abcdefghijklmnopqrstuvwxyz"); + buf.clear(); + + // now we're at the end again + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell() + assert_eq!(t.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf.as_slice(), b""); + buf.clear(); + + // seek to somewhere in the middle, read a bit + assert_eq!(t.seek(SeekFrom::Start(5)).unwrap(), 5); + let mut buf = [0; 5]; + assert!(t.read_exact(&mut buf).is_ok()); + assert_eq!(buf, *b"fghij"); + + // read again from current spot + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell() + assert!(t.read_exact(&mut buf).is_ok()); + assert_eq!(buf, *b"klmno"); + + let mut buf = [0; 15]; + // partial read + assert_eq!(t.read(&mut buf).unwrap(), 11); + assert_eq!(buf[0..11], *b"pqrstuvwxyz"); + + // try to read off the end: UnexpectedEof + assert!(t.read_exact(&mut buf).is_err()); +} + +#[test] +fn test_seek_read_buffer() { + let mut t = spooled_tempfile(100); + test_seek_read(&mut t); +} + +#[test] +fn test_seek_read_file() { + let mut t = SpooledTempFile::new(10); + test_seek_read(&mut t); +} + +fn test_overwrite_middle(t: &mut SpooledTempFile) { + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + + assert_eq!(t.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(t.write(b"0123456789").unwrap(), 10); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + + let mut buf = Vec::new(); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 26); + assert_eq!(buf.as_slice(), b"abcdefghij0123456789uvwxyz"); +} + +#[test] +fn test_overwrite_middle_of_buffer() { + let mut t = spooled_tempfile(100); + test_overwrite_middle(&mut t); +} + +#[test] +fn test_overwrite_middle_of_file() { + let mut t = SpooledTempFile::new(10); + test_overwrite_middle(&mut t); +} + +#[test] +fn test_overwrite_and_extend_buffer() { + let mut t = spooled_tempfile(100); + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + assert_eq!(t.seek(SeekFrom::End(-5)).unwrap(), 21); + assert_eq!(t.write(b"0123456789").unwrap(), 10); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + let mut buf = Vec::new(); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 31); + assert_eq!(buf.as_slice(), b"abcdefghijklmnopqrstu0123456789"); + assert!(!t.is_rolled()); +} + +#[test] +fn test_overwrite_and_extend_rollover() { + let mut t = SpooledTempFile::new(20); + assert_eq!(t.write(b"abcdefghijklmno").unwrap(), 15); + assert!(!t.is_rolled()); + assert_eq!(t.seek(SeekFrom::End(-5)).unwrap(), 10); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell() + assert!(!t.is_rolled()); + assert_eq!(t.write(b"0123456789)!@#$%^&*(").unwrap(), 20); + assert!(t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 30); // tell() + let mut buf = Vec::new(); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 30); + assert_eq!(buf.as_slice(), b"abcdefghij0123456789)!@#$%^&*("); +} + +fn test_sparse(t: &mut SpooledTempFile) { + assert_eq!(t.write(b"abcde").unwrap(), 5); + assert_eq!(t.seek(SeekFrom::Current(5)).unwrap(), 10); + assert_eq!(t.write(b"klmno").unwrap(), 5); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + let mut buf = Vec::new(); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 15); + assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0klmno"); +} + +#[test] +fn test_sparse_buffer() { + let mut t = spooled_tempfile(100); + test_sparse(&mut t); +} + +#[test] +fn test_sparse_file() { + let mut t = SpooledTempFile::new(1); + test_sparse(&mut t); +} + +#[test] +fn test_sparse_write_rollover() { + let mut t = spooled_tempfile(10); + assert_eq!(t.write(b"abcde").unwrap(), 5); + assert!(!t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(5)).unwrap(), 10); + assert!(!t.is_rolled()); + assert_eq!(t.write(b"klmno").unwrap(), 5); + assert!(t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + let mut buf = Vec::new(); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 15); + assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0klmno"); +} + +fn test_set_len(t: &mut SpooledTempFile) { + let mut buf: Vec<u8> = Vec::new(); + + assert_eq!(t.write(b"abcdefghijklmnopqrstuvwxyz").unwrap(), 26); + + // truncate to 10 bytes + assert!(t.set_len(10).is_ok()); + + // position should not have moved + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell() + + assert_eq!(t.read_to_end(&mut buf).unwrap(), 0); + assert_eq!(buf.as_slice(), b""); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 26); // tell() + buf.clear(); + + // read whole thing + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 10); + assert_eq!(buf.as_slice(), b"abcdefghij"); + buf.clear(); + + // set_len to expand beyond the end + assert!(t.set_len(40).is_ok()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 10); // tell() + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 40); + assert_eq!( + buf.as_slice(), + &b"abcdefghij\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"[..] + ); +} + +#[test] +fn test_set_len_buffer() { + let mut t = spooled_tempfile(100); + test_set_len(&mut t); +} + +#[test] +fn test_set_len_file() { + let mut t = spooled_tempfile(100); + test_set_len(&mut t); +} + +#[test] +fn test_set_len_rollover() { + let mut buf: Vec<u8> = Vec::new(); + + let mut t = spooled_tempfile(10); + assert_eq!(t.write(b"abcde").unwrap(), 5); + assert!(!t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell() + + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 5); + assert_eq!(buf.as_slice(), b"abcde"); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell() + buf.clear(); + + assert!(t.set_len(20).is_ok()); + assert!(t.is_rolled()); + assert_eq!(t.seek(SeekFrom::Current(0)).unwrap(), 5); // tell() + assert_eq!(t.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(t.read_to_end(&mut buf).unwrap(), 20); + assert_eq!(buf.as_slice(), b"abcde\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} diff --git a/tempfile/tests/tempdir.rs b/tempfile/tests/tempdir.rs new file mode 100644 index 000000000..9baccdccb --- /dev/null +++ b/tempfile/tests/tempdir.rs @@ -0,0 +1,261 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate tempfile; + +use std::env; +use std::fs; +use std::path::Path; +use std::sync::mpsc::channel; +use std::thread; + +use tempfile::{Builder, TempDir}; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(n) => n, + Err(e) => panic!("error: {}", e), + } + }; +} + +trait PathExt { + fn exists(&self) -> bool; + fn is_dir(&self) -> bool; +} + +impl PathExt for Path { + fn exists(&self) -> bool { + fs::metadata(self).is_ok() + } + fn is_dir(&self) -> bool { + fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) + } +} + +fn test_tempdir() { + let path = { + let p = t!(Builder::new().prefix("foobar").tempdir_in(&Path::new("."))); + let p = p.path(); + assert!(p.to_str().unwrap().contains("foobar")); + p.to_path_buf() + }; + assert!(!path.exists()); +} + +#[test] +fn test_customnamed() { + let tmpfile = Builder::new() + .prefix("prefix") + .suffix("suffix") + .rand_bytes(12) + .tempdir() + .unwrap(); + let name = tmpfile.path().file_name().unwrap().to_str().unwrap(); + assert!(name.starts_with("prefix")); + assert!(name.ends_with("suffix")); + assert_eq!(name.len(), 24); +} + +fn test_rm_tempdir() { + let (tx, rx) = channel(); + let f = move || -> () { + let tmp = t!(TempDir::new()); + tx.send(tmp.path().to_path_buf()).unwrap(); + panic!("panic to unwind past `tmp`"); + }; + let _ = thread::spawn(f).join(); + let path = rx.recv().unwrap(); + assert!(!path.exists()); + + let tmp = t!(TempDir::new()); + let path = tmp.path().to_path_buf(); + let f = move || -> () { + let _tmp = tmp; + panic!("panic to unwind past `tmp`"); + }; + let _ = thread::spawn(f).join(); + assert!(!path.exists()); + + let path; + { + let f = move || t!(TempDir::new()); + + let tmp = thread::spawn(f).join().unwrap(); + path = tmp.path().to_path_buf(); + assert!(path.exists()); + } + assert!(!path.exists()); + + let path; + { + let tmp = t!(TempDir::new()); + path = tmp.into_path(); + } + assert!(path.exists()); + t!(fs::remove_dir_all(&path)); + assert!(!path.exists()); +} + +fn test_rm_tempdir_close() { + let (tx, rx) = channel(); + let f = move || -> () { + let tmp = t!(TempDir::new()); + tx.send(tmp.path().to_path_buf()).unwrap(); + t!(tmp.close()); + panic!("panic when unwinding past `tmp`"); + }; + let _ = thread::spawn(f).join(); + let path = rx.recv().unwrap(); + assert!(!path.exists()); + + let tmp = t!(TempDir::new()); + let path = tmp.path().to_path_buf(); + let f = move || -> () { + let tmp = tmp; + t!(tmp.close()); + panic!("panic when unwinding past `tmp`"); + }; + let _ = thread::spawn(f).join(); + assert!(!path.exists()); + + let path; + { + let f = move || t!(TempDir::new()); + + let tmp = thread::spawn(f).join().unwrap(); + path = tmp.path().to_path_buf(); + assert!(path.exists()); + t!(tmp.close()); + } + assert!(!path.exists()); + + let path; + { + let tmp = t!(TempDir::new()); + path = tmp.into_path(); + } + assert!(path.exists()); + t!(fs::remove_dir_all(&path)); + assert!(!path.exists()); +} + +// Ideally these would be in std::os but then core would need +// to depend on std +fn recursive_mkdir_rel() { + let path = Path::new("frob"); + let cwd = env::current_dir().unwrap(); + println!( + "recursive_mkdir_rel: Making: {} in cwd {} [{}]", + path.display(), + cwd.display(), + path.exists() + ); + t!(fs::create_dir(&path)); + assert!(path.is_dir()); + t!(fs::create_dir_all(&path)); + assert!(path.is_dir()); +} + +fn recursive_mkdir_dot() { + let dot = Path::new("."); + t!(fs::create_dir_all(&dot)); + let dotdot = Path::new(".."); + t!(fs::create_dir_all(&dotdot)); +} + +fn recursive_mkdir_rel_2() { + let path = Path::new("./frob/baz"); + let cwd = env::current_dir().unwrap(); + println!( + "recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", + path.display(), + cwd.display(), + path.exists() + ); + t!(fs::create_dir_all(&path)); + assert!(path.is_dir()); + assert!(path.parent().unwrap().is_dir()); + let path2 = Path::new("quux/blat"); + println!( + "recursive_mkdir_rel_2: Making: {} in cwd {}", + path2.display(), + cwd.display() + ); + t!(fs::create_dir("quux")); + t!(fs::create_dir_all(&path2)); + assert!(path2.is_dir()); + assert!(path2.parent().unwrap().is_dir()); +} + +// Ideally this would be in core, but needs TempFile +pub fn test_remove_dir_all_ok() { + let tmpdir = t!(TempDir::new()); + let tmpdir = tmpdir.path(); + let root = tmpdir.join("foo"); + + println!("making {}", root.display()); + t!(fs::create_dir(&root)); + t!(fs::create_dir(&root.join("foo"))); + t!(fs::create_dir(&root.join("foo").join("bar"))); + t!(fs::create_dir(&root.join("foo").join("bar").join("blat"))); + t!(fs::remove_dir_all(&root)); + assert!(!root.exists()); + assert!(!root.join("bar").exists()); + assert!(!root.join("bar").join("blat").exists()); +} + +pub fn dont_double_panic() { + let r: Result<(), _> = thread::spawn(move || { + let tmpdir = TempDir::new().unwrap(); + // Remove the temporary directory so that TempDir sees + // an error on drop + t!(fs::remove_dir(tmpdir.path())); + // Panic. If TempDir panics *again* due to the rmdir + // error then the process will abort. + panic!(); + }) + .join(); + assert!(r.is_err()); +} + +fn in_tmpdir<F>(f: F) +where + F: FnOnce(), +{ + let tmpdir = t!(TempDir::new()); + assert!(env::set_current_dir(tmpdir.path()).is_ok()); + + f(); +} + +pub fn pass_as_asref_path() { + let tempdir = t!(TempDir::new()); + takes_asref_path(&tempdir); + + fn takes_asref_path<T: AsRef<Path>>(path: T) { + let path = path.as_ref(); + assert!(path.exists()); + } +} + +#[test] +fn main() { + in_tmpdir(test_tempdir); + in_tmpdir(test_rm_tempdir); + in_tmpdir(test_rm_tempdir_close); + in_tmpdir(recursive_mkdir_rel); + in_tmpdir(recursive_mkdir_dot); + in_tmpdir(recursive_mkdir_rel_2); + in_tmpdir(test_remove_dir_all_ok); + in_tmpdir(dont_double_panic); + in_tmpdir(pass_as_asref_path); +} diff --git a/tempfile/tests/tempfile.rs b/tempfile/tests/tempfile.rs new file mode 100644 index 000000000..4a19b29c6 --- /dev/null +++ b/tempfile/tests/tempfile.rs @@ -0,0 +1,62 @@ +extern crate tempfile; +use std::fs; +use std::io::{Read, Seek, SeekFrom, Write}; +use std::sync::mpsc::{sync_channel, TryRecvError}; +use std::thread; + +#[test] +fn test_basic() { + let mut tmpfile = tempfile::tempfile().unwrap(); + write!(tmpfile, "abcde").unwrap(); + tmpfile.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + tmpfile.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); +} + +#[test] +fn test_cleanup() { + let tmpdir = tempfile::tempdir().unwrap(); + { + let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap(); + write!(tmpfile, "abcde").unwrap(); + } + let num_files = fs::read_dir(&tmpdir).unwrap().count(); + assert!(num_files == 0); +} + +#[test] +fn test_pathological_cleaner() { + let tmpdir = tempfile::tempdir().unwrap(); + let (tx, rx) = sync_channel(0); + let cleaner_thread = thread::spawn(move || { + let tmp_path = rx.recv().unwrap(); + while rx.try_recv() == Err(TryRecvError::Empty) { + let files = fs::read_dir(&tmp_path).unwrap(); + for f in files { + // skip errors + if f.is_err() { + continue; + } + let f = f.unwrap(); + let _ = fs::remove_file(f.path()); + } + } + }); + + // block until cleaner_thread makes progress + tx.send(tmpdir.path().to_owned()).unwrap(); + // need 40-400 iterations to encounter race with cleaner on original system + for _ in 0..10000 { + let mut tmpfile = tempfile::tempfile_in(&tmpdir).unwrap(); + write!(tmpfile, "abcde").unwrap(); + tmpfile.seek(SeekFrom::Start(0)).unwrap(); + let mut buf = String::new(); + tmpfile.read_to_string(&mut buf).unwrap(); + assert_eq!("abcde", buf); + } + + // close the channel to make cleaner_thread exit + drop(tx); + cleaner_thread.join().expect("The cleaner thread failed"); +} diff --git a/termcolor/.cargo-checksum.json b/termcolor/.cargo-checksum.json new file mode 100644 index 000000000..6a6f2ca78 --- /dev/null +++ b/termcolor/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"} \ No newline at end of file diff --git a/termcolor/COPYING b/termcolor/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/termcolor/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/termcolor/Cargo.toml b/termcolor/Cargo.toml new file mode 100644 index 000000000..812cab133 --- /dev/null +++ b/termcolor/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "termcolor" +version = "1.0.4" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +exclude = ["/.travis.yml", "/appveyor.yml", "/ci/**"] +description = "A simple cross platform library for writing colored text to a terminal.\n" +homepage = "https://github.com/BurntSushi/termcolor" +documentation = "https://docs.rs/termcolor" +readme = "README.md" +keywords = ["windows", "win", "color", "ansi", "console"] +license = "Unlicense OR MIT" +repository = "https://github.com/BurntSushi/termcolor" + +[lib] +name = "termcolor" +bench = false +[target."cfg(windows)".dependencies.wincolor] +version = "1" diff --git a/termcolor/LICENSE-MIT b/termcolor/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/termcolor/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/termcolor/README.md b/termcolor/README.md new file mode 100644 index 000000000..faf3edb2d --- /dev/null +++ b/termcolor/README.md @@ -0,0 +1,86 @@ +termcolor +========= +A simple cross platform library for writing colored text to a terminal. This +library writes colored text either using standard ANSI escape sequences or +by interacting with the Windows console. Several convenient abstractions +are provided for use in single-threaded or multi-threaded command line +applications. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/termcolor.png)](https://travis-ci.org/BurntSushi/termcolor) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/termcolor?svg=true)](https://ci.appveyor.com/project/BurntSushi/termcolor) +[![](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +[https://docs.rs/termcolor](https://docs.rs/termcolor) + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +termcolor = "1" +``` + +and this to your crate root: + +```rust +extern crate termcolor; +``` + +### Organization + +The `WriteColor` trait extends the `io::Write` trait with methods for setting +colors or resetting them. + +`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are +analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr` +and `std::io::StderrLock`. + +`Buffer` is an in memory buffer that supports colored text. In a parallel +program, each thread might write to its own buffer. A buffer can be printed to +stdout or stderr using a `BufferWriter`. The advantage of this design is that +each thread can work in parallel on a buffer without having to synchronize +access to global resources such as the Windows console. Moreover, this design +also prevents interleaving of buffer output. + +`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of +`io::Write`. These types are useful when you know exactly what you need. An +analogous type for the Windows console is not provided since it cannot exist. + +### Example: using `StandardStream` + +The `StandardStream` type in this crate works similarly to `std::io::Stdout`, +except it is augmented with methods for coloring by the `WriteColor` trait. +For example, to write some green text: + +```rust +use std::io::Write; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +let mut stdout = StandardStream::stdout(ColorChoice::Always); +stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut stdout, "green text!")?; +``` + +### Example: using `BufferWriter` + +A `BufferWriter` can create buffers and write buffers to stdout or stderr. It +does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer` +implements `io::Write` and `termcolor::WriteColor`. + +This example shows how to print some green text to stderr. + +```rust +use std::io::Write; +use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; + +let mut bufwtr = BufferWriter::stderr(ColorChoice::Always); +let mut buffer = bufwtr.buffer(); +buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut buffer, "green text!")?; +bufwtr.print(&buffer)?; +``` diff --git a/termcolor/UNLICENSE b/termcolor/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/termcolor/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/termcolor/src/lib.rs b/termcolor/src/lib.rs new file mode 100644 index 000000000..1e9cef0d1 --- /dev/null +++ b/termcolor/src/lib.rs @@ -0,0 +1,1895 @@ +/*! +This crate provides a cross platform abstraction for writing colored text to +a terminal. Colors are written using either ANSI escape sequences or by +communicating with a Windows console. Much of this API was motivated by use +inside command line applications, where colors or styles can be configured +by the end user and/or the environment. + +This crate also provides platform independent support for writing colored text +to an in memory buffer. While this is easy to do with ANSI escape sequences +(because they are in the buffer themselves), it is trickier to do with the +Windows console API, which requires synchronous communication. + +# Organization + +The `WriteColor` trait extends the `io::Write` trait with methods for setting +colors or resetting them. + +`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are +analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr` +and `std::io::StderrLock`. + +`Buffer` is an in memory buffer that supports colored text. In a parallel +program, each thread might write to its own buffer. A buffer can be printed to +using a `BufferWriter`. The advantage of this design is that each thread can +work in parallel on a buffer without having to synchronize access to global +resources such as the Windows console. Moreover, this design also prevents +interleaving of buffer output. + +`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of +`io::Write`. These types are useful when you know exactly what you need. An +analogous type for the Windows console is not provided since it cannot exist. + +# Example: using `StandardStream` + +The `StandardStream` type in this crate works similarly to `std::io::Stdout`, +except it is augmented with methods for coloring by the `WriteColor` trait. +For example, to write some green text: + +```rust,no_run +# fn test() -> Result<(), Box<::std::error::Error>> { +use std::io::Write; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +let mut stdout = StandardStream::stdout(ColorChoice::Always); +stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut stdout, "green text!")?; +# Ok(()) } +``` + +# Example: using `BufferWriter` + +A `BufferWriter` can create buffers and write buffers to stdout or stderr. It +does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer` +implements `io::Write` and `io::WriteColor`. + +This example shows how to print some green text to stderr. + +```rust,no_run +# fn test() -> Result<(), Box<::std::error::Error>> { +use std::io::Write; +use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; + +let mut bufwtr = BufferWriter::stderr(ColorChoice::Always); +let mut buffer = bufwtr.buffer(); +buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut buffer, "green text!")?; +bufwtr.print(&buffer)?; +# Ok(()) } +``` +*/ + +#![deny(missing_docs)] + +#[cfg(windows)] +extern crate wincolor; + +use std::env; +use std::error; +use std::fmt; +use std::io::{self, Write}; +use std::str::FromStr; +#[cfg(windows)] +use std::sync::{Mutex, MutexGuard}; +use std::sync::atomic::{AtomicBool, Ordering}; + +/// This trait describes the behavior of writers that support colored output. +pub trait WriteColor: io::Write { + /// Returns true if and only if the underlying writer supports colors. + fn supports_color(&self) -> bool; + + /// Set the color settings of the writer. + /// + /// Subsequent writes to this writer will use these settings until either + /// `reset` is called or new color settings are set. + /// + /// If there was a problem setting the color settings, then an error is + /// returned. + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()>; + + /// Reset the current color settings to their original settings. + /// + /// If there was a problem resetting the color settings, then an error is + /// returned. + fn reset(&mut self) -> io::Result<()>; + + /// Returns true if and only if the underlying writer must synchronously + /// interact with an end user's device in order to control colors. By + /// default, this always returns `false`. + /// + /// In practice, this should return `true` if the underlying writer is + /// manipulating colors using the Windows console APIs. + /// + /// This is useful for writing generic code (such as a buffered writer) + /// that can perform certain optimizations when the underlying writer + /// doesn't rely on synchronous APIs. For example, ANSI escape sequences + /// can be passed through to the end user's device as is. + fn is_synchronous(&self) -> bool { + false + } +} + +impl<'a, T: ?Sized + WriteColor> WriteColor for &'a mut T { + fn supports_color(&self) -> bool { (&**self).supports_color() } + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + (&mut **self).set_color(spec) + } + fn reset(&mut self) -> io::Result<()> { (&mut **self).reset() } + fn is_synchronous(&self) -> bool { (&**self).is_synchronous() } +} + +impl<T: ?Sized + WriteColor> WriteColor for Box<T> { + fn supports_color(&self) -> bool { (&**self).supports_color() } + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + (&mut **self).set_color(spec) + } + fn reset(&mut self) -> io::Result<()> { (&mut **self).reset() } + fn is_synchronous(&self) -> bool { (&**self).is_synchronous() } +} + +/// ColorChoice represents the color preferences of an end user. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ColorChoice { + /// Try very hard to emit colors. This includes emitting ANSI colors + /// on Windows if the console API is unavailable. + Always, + /// AlwaysAnsi is like Always, except it never tries to use anything other + /// than emitting ANSI color codes. + AlwaysAnsi, + /// Try to use colors, but don't force the issue. If the console isn't + /// available on Windows, or if TERM=dumb, for example, then don't use + /// colors. + Auto, + /// Never emit colors. + Never, +} + +impl ColorChoice { + /// Returns true if we should attempt to write colored output. + #[cfg(not(windows))] + fn should_attempt_color(&self) -> bool { + match *self { + ColorChoice::Always => true, + ColorChoice::AlwaysAnsi => true, + ColorChoice::Never => false, + ColorChoice::Auto => { + match env::var("TERM") { + Err(_) => false, + Ok(k) => k != "dumb", + } + } + } + } + + /// Returns true if we should attempt to write colored output. + #[cfg(windows)] + fn should_attempt_color(&self) -> bool { + match *self { + ColorChoice::Always => true, + ColorChoice::AlwaysAnsi => true, + ColorChoice::Never => false, + ColorChoice::Auto => { + match env::var("TERM") { + Err(_) => true, + Ok(k) => k != "dumb", + } + } + } + } + + /// Returns true if this choice should forcefully use ANSI color codes. + /// + /// It's possible that ANSI is still the correct choice even if this + /// returns false. + #[cfg(windows)] + fn should_ansi(&self) -> bool { + match *self { + ColorChoice::Always => false, + ColorChoice::AlwaysAnsi => true, + ColorChoice::Never => false, + ColorChoice::Auto => { + match env::var("TERM") { + Err(_) => false, + // cygwin doesn't seem to support ANSI escape sequences + // and instead has its own variety. However, the Windows + // console API may be available. + Ok(k) => k != "dumb" && k != "cygwin", + } + } + } + } +} + +/// `std::io` implements `Stdout` and `Stderr` (and their `Lock` variants) as +/// separate types, which makes it difficult to abstract over them. We use +/// some simple internal enum types to work around this. + +enum StandardStreamType { + Stdout, + Stderr, + StdoutBuffered, + StderrBuffered, +} + +enum IoStandardStream { + Stdout(io::Stdout), + Stderr(io::Stderr), + StdoutBuffered(io::BufWriter<io::Stdout>), + StderrBuffered(io::BufWriter<io::Stderr>), +} + +impl IoStandardStream { + fn new(sty: StandardStreamType) -> IoStandardStream { + match sty { + StandardStreamType::Stdout => { + IoStandardStream::Stdout(io::stdout()) + } + StandardStreamType::Stderr => { + IoStandardStream::Stderr(io::stderr()) + } + StandardStreamType::StdoutBuffered => { + let wtr = io::BufWriter::new(io::stdout()); + IoStandardStream::StdoutBuffered(wtr) + } + StandardStreamType::StderrBuffered => { + let wtr = io::BufWriter::new(io::stderr()); + IoStandardStream::StderrBuffered(wtr) + } + } + } + + fn lock(&self) -> IoStandardStreamLock { + match *self { + IoStandardStream::Stdout(ref s) => { + IoStandardStreamLock::StdoutLock(s.lock()) + } + IoStandardStream::Stderr(ref s) => { + IoStandardStreamLock::StderrLock(s.lock()) + } + IoStandardStream::StdoutBuffered(_) + | IoStandardStream::StderrBuffered(_) => { + // We don't permit this case to ever occur in the public API, + // so it's OK to panic. + panic!("cannot lock a buffered standard stream") + } + } + } +} + +impl io::Write for IoStandardStream { + #[inline(always)] + fn write(&mut self, b: &[u8]) -> io::Result<usize> { + match *self { + IoStandardStream::Stdout(ref mut s) => s.write(b), + IoStandardStream::Stderr(ref mut s) => s.write(b), + IoStandardStream::StdoutBuffered(ref mut s) => s.write(b), + IoStandardStream::StderrBuffered(ref mut s) => s.write(b), + } + } + + #[inline(always)] + fn flush(&mut self) -> io::Result<()> { + match *self { + IoStandardStream::Stdout(ref mut s) => s.flush(), + IoStandardStream::Stderr(ref mut s) => s.flush(), + IoStandardStream::StdoutBuffered(ref mut s) => s.flush(), + IoStandardStream::StderrBuffered(ref mut s) => s.flush(), + } + } +} + +// Same rigmarole for the locked variants of the standard streams. + +enum IoStandardStreamLock<'a> { + StdoutLock(io::StdoutLock<'a>), + StderrLock(io::StderrLock<'a>), +} + +impl<'a> io::Write for IoStandardStreamLock<'a> { + #[inline(always)] + fn write(&mut self, b: &[u8]) -> io::Result<usize> { + match *self { + IoStandardStreamLock::StdoutLock(ref mut s) => s.write(b), + IoStandardStreamLock::StderrLock(ref mut s) => s.write(b), + } + } + + #[inline(always)] + fn flush(&mut self) -> io::Result<()> { + match *self { + IoStandardStreamLock::StdoutLock(ref mut s) => s.flush(), + IoStandardStreamLock::StderrLock(ref mut s) => s.flush(), + } + } +} + +/// Satisfies `io::Write` and `WriteColor`, and supports optional coloring +/// to either of the standard output streams, stdout and stderr. +pub struct StandardStream { + wtr: LossyStandardStream<WriterInner<IoStandardStream>>, +} + +/// `StandardStreamLock` is a locked reference to a `StandardStream`. +/// +/// This implements the `io::Write` and `WriteColor` traits, and is constructed +/// via the `Write::lock` method. +/// +/// The lifetime `'a` refers to the lifetime of the corresponding +/// `StandardStream`. +pub struct StandardStreamLock<'a> { + wtr: LossyStandardStream<WriterInnerLock<'a, IoStandardStreamLock<'a>>>, +} + +/// Like `StandardStream`, but does buffered writing. +pub struct BufferedStandardStream { + wtr: LossyStandardStream<WriterInner<IoStandardStream>>, +} + +/// WriterInner is a (limited) generic representation of a writer. It is +/// limited because W should only ever be stdout/stderr on Windows. +enum WriterInner<W> { + NoColor(NoColor<W>), + Ansi(Ansi<W>), + #[cfg(windows)] + Windows { wtr: W, console: Mutex<wincolor::Console> }, +} + +/// WriterInnerLock is a (limited) generic representation of a writer. It is +/// limited because W should only ever be stdout/stderr on Windows. +enum WriterInnerLock<'a, W> { + NoColor(NoColor<W>), + Ansi(Ansi<W>), + /// What a gross hack. On Windows, we need to specify a lifetime for the + /// console when in a locked state, but obviously don't need to do that + /// on Unix, which makes the `'a` unused. To satisfy the compiler, we need + /// a PhantomData. + #[allow(dead_code)] + Unreachable(::std::marker::PhantomData<&'a ()>), + #[cfg(windows)] + Windows { wtr: W, console: MutexGuard<'a, wincolor::Console> }, +} + +impl StandardStream { + /// Create a new `StandardStream` with the given color preferences that + /// writes to standard output. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing via + /// the `WriteColor` trait. + pub fn stdout(choice: ColorChoice) -> StandardStream { + let wtr = WriterInner::create(StandardStreamType::Stdout, choice); + StandardStream { wtr: LossyStandardStream::new(wtr) } + } + + /// Create a new `StandardStream` with the given color preferences that + /// writes to standard error. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing via + /// the `WriteColor` trait. + pub fn stderr(choice: ColorChoice) -> StandardStream { + let wtr = WriterInner::create(StandardStreamType::Stderr, choice); + StandardStream { wtr: LossyStandardStream::new(wtr) } + } + + /// Lock the underlying writer. + /// + /// The lock guard returned also satisfies `io::Write` and + /// `WriteColor`. + /// + /// This method is **not reentrant**. It may panic if `lock` is called + /// while a `StandardStreamLock` is still alive. + pub fn lock(&self) -> StandardStreamLock { + StandardStreamLock::from_stream(self) + } +} + +impl<'a> StandardStreamLock<'a> { + #[cfg(not(windows))] + fn from_stream(stream: &StandardStream) -> StandardStreamLock { + let locked = match *stream.wtr.get_ref() { + WriterInner::NoColor(ref w) => { + WriterInnerLock::NoColor(NoColor(w.0.lock())) + } + WriterInner::Ansi(ref w) => { + WriterInnerLock::Ansi(Ansi(w.0.lock())) + } + }; + StandardStreamLock { wtr: stream.wtr.wrap(locked) } + } + + #[cfg(windows)] + fn from_stream(stream: &StandardStream) -> StandardStreamLock { + let locked = match *stream.wtr.get_ref() { + WriterInner::NoColor(ref w) => { + WriterInnerLock::NoColor(NoColor(w.0.lock())) + } + WriterInner::Ansi(ref w) => { + WriterInnerLock::Ansi(Ansi(w.0.lock())) + } + #[cfg(windows)] + WriterInner::Windows { ref wtr, ref console } => { + WriterInnerLock::Windows { + wtr: wtr.lock(), + console: console.lock().unwrap(), + } + } + }; + StandardStreamLock { wtr: stream.wtr.wrap(locked) } + } +} + +impl BufferedStandardStream { + /// Create a new `BufferedStandardStream` with the given color preferences + /// that writes to standard output via a buffered writer. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing via + /// the `WriteColor` trait. + pub fn stdout(choice: ColorChoice) -> BufferedStandardStream { + let wtr = WriterInner::create( + StandardStreamType::StdoutBuffered, + choice, + ); + BufferedStandardStream { wtr: LossyStandardStream::new(wtr) } + } + + /// Create a new `BufferedStandardStream` with the given color preferences + /// that writes to standard error via a buffered writer. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing via + /// the `WriteColor` trait. + pub fn stderr(choice: ColorChoice) -> BufferedStandardStream { + let wtr = WriterInner::create( + StandardStreamType::StderrBuffered, + choice, + ); + BufferedStandardStream { wtr: LossyStandardStream::new(wtr) } + } +} + +impl WriterInner<IoStandardStream> { + /// Create a new inner writer for a standard stream with the given color + /// preferences. + #[cfg(not(windows))] + fn create( + sty: StandardStreamType, + choice: ColorChoice, + ) -> WriterInner<IoStandardStream> { + if choice.should_attempt_color() { + WriterInner::Ansi(Ansi(IoStandardStream::new(sty))) + } else { + WriterInner::NoColor(NoColor(IoStandardStream::new(sty))) + } + } + + /// Create a new inner writer for a standard stream with the given color + /// preferences. + /// + /// If coloring is desired and a Windows console could not be found, then + /// ANSI escape sequences are used instead. + #[cfg(windows)] + fn create( + sty: StandardStreamType, + choice: ColorChoice, + ) -> WriterInner<IoStandardStream> { + let mut con = match sty { + StandardStreamType::Stdout => wincolor::Console::stdout(), + StandardStreamType::Stderr => wincolor::Console::stderr(), + StandardStreamType::StdoutBuffered => wincolor::Console::stdout(), + StandardStreamType::StderrBuffered => wincolor::Console::stderr(), + }; + let is_console_virtual = con.as_mut().map(|con| { + con.set_virtual_terminal_processing(true).is_ok() + }).unwrap_or(false); + if choice.should_attempt_color() { + if choice.should_ansi() || is_console_virtual { + WriterInner::Ansi(Ansi(IoStandardStream::new(sty))) + } else if let Ok(console) = con { + WriterInner::Windows { + wtr: IoStandardStream::new(sty), + console: Mutex::new(console), + } + } else { + WriterInner::Ansi(Ansi(IoStandardStream::new(sty))) + } + } else { + WriterInner::NoColor(NoColor(IoStandardStream::new(sty))) + } + } +} + +impl io::Write for StandardStream { + #[inline] + fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) } + + #[inline] + fn flush(&mut self) -> io::Result<()> { self.wtr.flush() } +} + +impl WriteColor for StandardStream { + #[inline] + fn supports_color(&self) -> bool { self.wtr.supports_color() } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.wtr.set_color(spec) + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } + + #[inline] + fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() } +} + +impl<'a> io::Write for StandardStreamLock<'a> { + #[inline] + fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) } + + #[inline] + fn flush(&mut self) -> io::Result<()> { self.wtr.flush() } +} + +impl<'a> WriteColor for StandardStreamLock<'a> { + #[inline] + fn supports_color(&self) -> bool { self.wtr.supports_color() } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.wtr.set_color(spec) + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } + + #[inline] + fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() } +} + +impl io::Write for BufferedStandardStream { + #[inline] + fn write(&mut self, b: &[u8]) -> io::Result<usize> { self.wtr.write(b) } + + #[inline] + fn flush(&mut self) -> io::Result<()> { self.wtr.flush() } +} + +impl WriteColor for BufferedStandardStream { + #[inline] + fn supports_color(&self) -> bool { self.wtr.supports_color() } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + if self.is_synchronous() { + self.wtr.flush()?; + } + self.wtr.set_color(spec) + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } + + #[inline] + fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() } +} + +impl<W: io::Write> io::Write for WriterInner<W> { + #[inline(always)] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + match *self { + WriterInner::NoColor(ref mut wtr) => wtr.write(buf), + WriterInner::Ansi(ref mut wtr) => wtr.write(buf), + #[cfg(windows)] + WriterInner::Windows { ref mut wtr, .. } => wtr.write(buf), + } + } + + #[inline(always)] + fn flush(&mut self) -> io::Result<()> { + match *self { + WriterInner::NoColor(ref mut wtr) => wtr.flush(), + WriterInner::Ansi(ref mut wtr) => wtr.flush(), + #[cfg(windows)] + WriterInner::Windows { ref mut wtr, .. } => wtr.flush(), + } + } +} + +impl<W: io::Write> WriteColor for WriterInner<W> { + fn supports_color(&self) -> bool { + match *self { + WriterInner::NoColor(_) => false, + WriterInner::Ansi(_) => true, + #[cfg(windows)] + WriterInner::Windows { .. } => true, + } + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + match *self { + WriterInner::NoColor(ref mut wtr) => wtr.set_color(spec), + WriterInner::Ansi(ref mut wtr) => wtr.set_color(spec), + #[cfg(windows)] + WriterInner::Windows { ref mut wtr, ref console } => { + wtr.flush()?; + let mut console = console.lock().unwrap(); + spec.write_console(&mut *console) + } + } + } + + fn reset(&mut self) -> io::Result<()> { + match *self { + WriterInner::NoColor(ref mut wtr) => wtr.reset(), + WriterInner::Ansi(ref mut wtr) => wtr.reset(), + #[cfg(windows)] + WriterInner::Windows { ref mut wtr, ref mut console } => { + wtr.flush()?; + console.lock().unwrap().reset()?; + Ok(()) + } + } + } + + fn is_synchronous(&self) -> bool { + match *self { + WriterInner::NoColor(_) => false, + WriterInner::Ansi(_) => false, + #[cfg(windows)] + WriterInner::Windows {..} => true, + } + } +} + +impl<'a, W: io::Write> io::Write for WriterInnerLock<'a, W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(ref mut wtr) => wtr.write(buf), + WriterInnerLock::Ansi(ref mut wtr) => wtr.write(buf), + #[cfg(windows)] + WriterInnerLock::Windows { ref mut wtr, .. } => wtr.write(buf), + } + } + + fn flush(&mut self) -> io::Result<()> { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(ref mut wtr) => wtr.flush(), + WriterInnerLock::Ansi(ref mut wtr) => wtr.flush(), + #[cfg(windows)] + WriterInnerLock::Windows { ref mut wtr, .. } => wtr.flush(), + } + } +} + +impl<'a, W: io::Write> WriteColor for WriterInnerLock<'a, W> { + fn supports_color(&self) -> bool { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(_) => false, + WriterInnerLock::Ansi(_) => true, + #[cfg(windows)] + WriterInnerLock::Windows { .. } => true, + } + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(ref mut wtr) => wtr.set_color(spec), + WriterInnerLock::Ansi(ref mut wtr) => wtr.set_color(spec), + #[cfg(windows)] + WriterInnerLock::Windows { ref mut wtr, ref mut console } => { + wtr.flush()?; + spec.write_console(console) + } + } + } + + fn reset(&mut self) -> io::Result<()> { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(ref mut wtr) => wtr.reset(), + WriterInnerLock::Ansi(ref mut wtr) => wtr.reset(), + #[cfg(windows)] + WriterInnerLock::Windows { ref mut wtr, ref mut console } => { + wtr.flush()?; + console.reset()?; + Ok(()) + } + } + } + + fn is_synchronous(&self) -> bool { + match *self { + WriterInnerLock::Unreachable(_) => unreachable!(), + WriterInnerLock::NoColor(_) => false, + WriterInnerLock::Ansi(_) => false, + #[cfg(windows)] + WriterInnerLock::Windows {..} => true, + } + } +} + +/// Writes colored buffers to stdout or stderr. +/// +/// Writable buffers can be obtained by calling `buffer` on a `BufferWriter`. +/// +/// This writer works with terminals that support ANSI escape sequences or +/// with a Windows console. +/// +/// It is intended for a `BufferWriter` to be put in an `Arc` and written to +/// from multiple threads simultaneously. +pub struct BufferWriter { + stream: LossyStandardStream<IoStandardStream>, + printed: AtomicBool, + separator: Option<Vec<u8>>, + color_choice: ColorChoice, + #[cfg(windows)] + console: Option<Mutex<wincolor::Console>>, +} + +impl BufferWriter { + /// Create a new `BufferWriter` that writes to a standard stream with the + /// given color preferences. + /// + /// The specific color/style settings can be configured when writing to + /// the buffers themselves. + #[cfg(not(windows))] + fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter { + BufferWriter { + stream: LossyStandardStream::new(IoStandardStream::new(sty)), + printed: AtomicBool::new(false), + separator: None, + color_choice: choice, + } + } + + /// Create a new `BufferWriter` that writes to a standard stream with the + /// given color preferences. + /// + /// If coloring is desired and a Windows console could not be found, then + /// ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing to + /// the buffers themselves. + #[cfg(windows)] + fn create(sty: StandardStreamType, choice: ColorChoice) -> BufferWriter { + let mut con = match sty { + StandardStreamType::Stdout => wincolor::Console::stdout(), + StandardStreamType::Stderr => wincolor::Console::stderr(), + StandardStreamType::StdoutBuffered => wincolor::Console::stdout(), + StandardStreamType::StderrBuffered => wincolor::Console::stderr(), + }.ok(); + let is_console_virtual = con.as_mut().map(|con| { + con.set_virtual_terminal_processing(true).is_ok() + }).unwrap_or(false); + // If we can enable ANSI on Windows, then we don't need the console + // anymore. + if is_console_virtual { + con = None; + } + let stream = LossyStandardStream::new(IoStandardStream::new(sty)); + BufferWriter { + stream: stream, + printed: AtomicBool::new(false), + separator: None, + color_choice: choice, + console: con.map(Mutex::new), + } + } + + /// Create a new `BufferWriter` that writes to stdout with the given + /// color preferences. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing to + /// the buffers themselves. + pub fn stdout(choice: ColorChoice) -> BufferWriter { + BufferWriter::create(StandardStreamType::Stdout, choice) + } + + /// Create a new `BufferWriter` that writes to stderr with the given + /// color preferences. + /// + /// On Windows, if coloring is desired and a Windows console could not be + /// found, then ANSI escape sequences are used instead. + /// + /// The specific color/style settings can be configured when writing to + /// the buffers themselves. + pub fn stderr(choice: ColorChoice) -> BufferWriter { + BufferWriter::create(StandardStreamType::Stderr, choice) + } + + /// If set, the separator given is printed between buffers. By default, no + /// separator is printed. + /// + /// The default value is `None`. + pub fn separator(&mut self, sep: Option<Vec<u8>>) { + self.separator = sep; + } + + /// Creates a new `Buffer` with the current color preferences. + /// + /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can + /// be printed using the `print` method. + #[cfg(not(windows))] + pub fn buffer(&self) -> Buffer { + Buffer::new(self.color_choice) + } + + /// Creates a new `Buffer` with the current color preferences. + /// + /// A `Buffer` satisfies both `io::Write` and `WriteColor`. A `Buffer` can + /// be printed using the `print` method. + #[cfg(windows)] + pub fn buffer(&self) -> Buffer { + Buffer::new(self.color_choice, self.console.is_some()) + } + + /// Prints the contents of the given buffer. + /// + /// It is safe to call this from multiple threads simultaneously. In + /// particular, all buffers are written atomically. No interleaving will + /// occur. + pub fn print(&self, buf: &Buffer) -> io::Result<()> { + if buf.is_empty() { + return Ok(()); + } + let mut stream = self.stream.wrap(self.stream.get_ref().lock()); + if let Some(ref sep) = self.separator { + if self.printed.load(Ordering::SeqCst) { + stream.write_all(sep)?; + stream.write_all(b"\n")?; + } + } + match buf.0 { + BufferInner::NoColor(ref b) => stream.write_all(&b.0)?, + BufferInner::Ansi(ref b) => stream.write_all(&b.0)?, + #[cfg(windows)] + BufferInner::Windows(ref b) => { + // We guarantee by construction that we have a console here. + // Namely, a BufferWriter is the only way to produce a Buffer. + let console_mutex = self.console.as_ref() + .expect("got Windows buffer but have no Console"); + let mut console = console_mutex.lock().unwrap(); + b.print(&mut *console, &mut stream)?; + } + } + self.printed.store(true, Ordering::SeqCst); + Ok(()) + } +} + +/// Write colored text to memory. +/// +/// `Buffer` is a platform independent abstraction for printing colored text to +/// an in memory buffer. When the buffer is printed using a `BufferWriter`, the +/// color information will be applied to the output device (a tty on Unix and a +/// console on Windows). +/// +/// A `Buffer` is typically created by calling the `BufferWriter.buffer` +/// method, which will take color preferences and the environment into +/// account. However, buffers can also be manually created using `no_color`, +/// `ansi` or `console` (on Windows). +pub struct Buffer(BufferInner); + +/// BufferInner is an enumeration of different buffer types. +enum BufferInner { + /// No coloring information should be applied. This ignores all coloring + /// directives. + NoColor(NoColor<Vec<u8>>), + /// Apply coloring using ANSI escape sequences embedded into the buffer. + Ansi(Ansi<Vec<u8>>), + /// Apply coloring using the Windows console APIs. This buffer saves + /// color information in memory and only interacts with the console when + /// the buffer is printed. + #[cfg(windows)] + Windows(WindowsBuffer), +} + +impl Buffer { + /// Create a new buffer with the given color settings. + #[cfg(not(windows))] + fn new(choice: ColorChoice) -> Buffer { + if choice.should_attempt_color() { + Buffer::ansi() + } else { + Buffer::no_color() + } + } + + /// Create a new buffer with the given color settings. + /// + /// On Windows, one can elect to create a buffer capable of being written + /// to a console. Only enable it if a console is available. + /// + /// If coloring is desired and `console` is false, then ANSI escape + /// sequences are used instead. + #[cfg(windows)] + fn new(choice: ColorChoice, console: bool) -> Buffer { + if choice.should_attempt_color() { + if !console || choice.should_ansi() { + Buffer::ansi() + } else { + Buffer::console() + } + } else { + Buffer::no_color() + } + } + + /// Create a buffer that drops all color information. + pub fn no_color() -> Buffer { + Buffer(BufferInner::NoColor(NoColor(vec![]))) + } + + /// Create a buffer that uses ANSI escape sequences. + pub fn ansi() -> Buffer { + Buffer(BufferInner::Ansi(Ansi(vec![]))) + } + + /// Create a buffer that can be written to a Windows console. + #[cfg(windows)] + pub fn console() -> Buffer { + Buffer(BufferInner::Windows(WindowsBuffer::new())) + } + + /// Returns true if and only if this buffer is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the length of this buffer in bytes. + pub fn len(&self) -> usize { + match self.0 { + BufferInner::NoColor(ref b) => b.0.len(), + BufferInner::Ansi(ref b) => b.0.len(), + #[cfg(windows)] + BufferInner::Windows(ref b) => b.buf.len(), + } + } + + /// Clears this buffer. + pub fn clear(&mut self) { + match self.0 { + BufferInner::NoColor(ref mut b) => b.0.clear(), + BufferInner::Ansi(ref mut b) => b.0.clear(), + #[cfg(windows)] + BufferInner::Windows(ref mut b) => b.clear(), + } + } + + /// Consume this buffer and return the underlying raw data. + /// + /// On Windows, this unrecoverably drops all color information associated + /// with the buffer. + pub fn into_inner(self) -> Vec<u8> { + match self.0 { + BufferInner::NoColor(b) => b.0, + BufferInner::Ansi(b) => b.0, + #[cfg(windows)] + BufferInner::Windows(b) => b.buf, + } + } + + /// Return the underlying data of the buffer. + pub fn as_slice(&self) -> &[u8] { + match self.0 { + BufferInner::NoColor(ref b) => &b.0, + BufferInner::Ansi(ref b) => &b.0, + #[cfg(windows)] + BufferInner::Windows(ref b) => &b.buf, + } + } + + /// Return the underlying data of the buffer as a mutable slice. + pub fn as_mut_slice(&mut self) -> &mut [u8] { + match self.0 { + BufferInner::NoColor(ref mut b) => &mut b.0, + BufferInner::Ansi(ref mut b) => &mut b.0, + #[cfg(windows)] + BufferInner::Windows(ref mut b) => &mut b.buf, + } + } +} + +impl io::Write for Buffer { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + match self.0 { + BufferInner::NoColor(ref mut w) => w.write(buf), + BufferInner::Ansi(ref mut w) => w.write(buf), + #[cfg(windows)] + BufferInner::Windows(ref mut w) => w.write(buf), + } + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + match self.0 { + BufferInner::NoColor(ref mut w) => w.flush(), + BufferInner::Ansi(ref mut w) => w.flush(), + #[cfg(windows)] + BufferInner::Windows(ref mut w) => w.flush(), + } + } +} + +impl WriteColor for Buffer { + #[inline] + fn supports_color(&self) -> bool { + match self.0 { + BufferInner::NoColor(_) => false, + BufferInner::Ansi(_) => true, + #[cfg(windows)] + BufferInner::Windows(_) => true, + } + } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + match self.0 { + BufferInner::NoColor(ref mut w) => w.set_color(spec), + BufferInner::Ansi(ref mut w) => w.set_color(spec), + #[cfg(windows)] + BufferInner::Windows(ref mut w) => w.set_color(spec), + } + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { + match self.0 { + BufferInner::NoColor(ref mut w) => w.reset(), + BufferInner::Ansi(ref mut w) => w.reset(), + #[cfg(windows)] + BufferInner::Windows(ref mut w) => w.reset(), + } + } + + #[inline] + fn is_synchronous(&self) -> bool { + false + } +} + +/// Satisfies `WriteColor` but ignores all color options. +pub struct NoColor<W>(W); + +impl<W: Write> NoColor<W> { + /// Create a new writer that satisfies `WriteColor` but drops all color + /// information. + pub fn new(wtr: W) -> NoColor<W> { NoColor(wtr) } + + /// Consume this `NoColor` value and return the inner writer. + pub fn into_inner(self) -> W { self.0 } + + /// Return a reference to the inner writer. + pub fn get_ref(&self) -> &W { &self.0 } + + /// Return a mutable reference to the inner writer. + pub fn get_mut(&mut self) -> &mut W { &mut self.0 } +} + +impl<W: io::Write> io::Write for NoColor<W> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.0.write(buf) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } +} + +impl<W: io::Write> WriteColor for NoColor<W> { + #[inline] + fn supports_color(&self) -> bool { false } + + #[inline] + fn set_color(&mut self, _: &ColorSpec) -> io::Result<()> { Ok(()) } + + #[inline] + fn reset(&mut self) -> io::Result<()> { Ok(()) } + + #[inline] + fn is_synchronous(&self) -> bool { false } +} + +/// Satisfies `WriteColor` using standard ANSI escape sequences. +pub struct Ansi<W>(W); + +impl<W: Write> Ansi<W> { + /// Create a new writer that satisfies `WriteColor` using standard ANSI + /// escape sequences. + pub fn new(wtr: W) -> Ansi<W> { Ansi(wtr) } + + /// Consume this `Ansi` value and return the inner writer. + pub fn into_inner(self) -> W { self.0 } + + /// Return a reference to the inner writer. + pub fn get_ref(&self) -> &W { &self.0 } + + /// Return a mutable reference to the inner writer. + pub fn get_mut(&mut self) -> &mut W { &mut self.0 } +} + +impl<W: io::Write> io::Write for Ansi<W> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.0.write(buf) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } +} + +impl<W: io::Write> WriteColor for Ansi<W> { + #[inline] + fn supports_color(&self) -> bool { true } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.reset()?; + if spec.bold { + self.write_str("\x1B[1m")?; + } + if spec.underline { + self.write_str("\x1B[4m")?; + } + if let Some(ref c) = spec.fg_color { + self.write_color(true, c, spec.intense)?; + } + if let Some(ref c) = spec.bg_color { + self.write_color(false, c, spec.intense)?; + } + Ok(()) + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { + self.write_str("\x1B[0m") + } + + #[inline] + fn is_synchronous(&self) -> bool { false } +} + +impl<W: io::Write> Ansi<W> { + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.write_all(s.as_bytes()) + } + + fn write_color( + &mut self, + fg: bool, + c: &Color, + intense: bool, + ) -> io::Result<()> { + macro_rules! write_intense { + ($clr:expr) => { + if fg { + self.write_str(concat!("\x1B[38;5;", $clr, "m")) + } else { + self.write_str(concat!("\x1B[48;5;", $clr, "m")) + } + } + } + macro_rules! write_normal { + ($clr:expr) => { + if fg { + self.write_str(concat!("\x1B[3", $clr, "m")) + } else { + self.write_str(concat!("\x1B[4", $clr, "m")) + } + } + } + macro_rules! write_var_ansi_code { + ($pre:expr, $($code:expr),+) => {{ + // The loop generates at worst a literal of the form + // '255,255,255m' which is 12-bytes. + // The largest `pre` expression we currently use is 7 bytes. + // This gives us the maximum of 19-bytes for our work buffer. + let pre_len = $pre.len(); + assert!(pre_len <= 7); + let mut fmt = [0u8; 19]; + fmt[..pre_len].copy_from_slice($pre); + let mut i = pre_len - 1; + $( + let c1: u8 = ($code / 100) % 10; + let c2: u8 = ($code / 10) % 10; + let c3: u8 = $code % 10; + let mut printed = false; + + if c1 != 0 { + printed = true; + i += 1; + fmt[i] = b'0' + c1; + } + if c2 != 0 || printed { + i += 1; + fmt[i] = b'0' + c2; + } + // If we received a zero value we must still print a value. + i += 1; + fmt[i] = b'0' + c3; + i += 1; + fmt[i] = b';'; + )+ + + fmt[i] = b'm'; + self.write_all(&fmt[0..i+1]) + }} + } + macro_rules! write_custom { + ($ansi256:expr) => { + if fg { + write_var_ansi_code!(b"\x1B[38;5;", $ansi256) + } else { + write_var_ansi_code!(b"\x1B[48;5;", $ansi256) + } + }; + + ($r:expr, $g:expr, $b:expr) => {{ + if fg { + write_var_ansi_code!(b"\x1B[38;2;", $r, $g, $b) + } else { + write_var_ansi_code!(b"\x1B[48;2;", $r, $g, $b) + } + }}; + } + if intense { + match *c { + Color::Black => write_intense!("8"), + Color::Blue => write_intense!("12"), + Color::Green => write_intense!("10"), + Color::Red => write_intense!("9"), + Color::Cyan => write_intense!("14"), + Color::Magenta => write_intense!("13"), + Color::Yellow => write_intense!("11"), + Color::White => write_intense!("15"), + Color::Ansi256(c) => write_custom!(c), + Color::Rgb(r, g, b) => write_custom!(r, g, b), + Color::__Nonexhaustive => unreachable!(), + } + } else { + match *c { + Color::Black => write_normal!("0"), + Color::Blue => write_normal!("4"), + Color::Green => write_normal!("2"), + Color::Red => write_normal!("1"), + Color::Cyan => write_normal!("6"), + Color::Magenta => write_normal!("5"), + Color::Yellow => write_normal!("3"), + Color::White => write_normal!("7"), + Color::Ansi256(c) => write_custom!(c), + Color::Rgb(r, g, b) => write_custom!(r, g, b), + Color::__Nonexhaustive => unreachable!(), + } + } + } +} + +/// An in-memory buffer that provides Windows console coloring. +/// +/// This doesn't actually communicate with the Windows console. Instead, it +/// acts like a normal buffer but also saves the color information associated +/// with positions in the buffer. It is only when the buffer is written to the +/// console that coloring is actually applied. +/// +/// This is roughly isomorphic to the ANSI based approach (i.e., +/// `Ansi<Vec<u8>>`), except with ANSI, the color information is embedded +/// directly into the buffer. +/// +/// Note that there is no way to write something generic like +/// `WindowsConsole<W: io::Write>` since coloring on Windows is tied +/// specifically to the console APIs, and therefore can't work on arbitrary +/// writers. +#[cfg(windows)] +#[derive(Clone, Debug)] +struct WindowsBuffer { + /// The actual content that should be printed. + buf: Vec<u8>, + /// A sequence of position oriented color specifications. Namely, each + /// element is a position and a color spec, where the color spec should + /// be applied at the position inside of `buf`. + /// + /// A missing color spec implies the underlying console should be reset. + colors: Vec<(usize, Option<ColorSpec>)>, +} + +#[cfg(windows)] +impl WindowsBuffer { + /// Create a new empty buffer for Windows console coloring. + fn new() -> WindowsBuffer { + WindowsBuffer { + buf: vec![], + colors: vec![], + } + } + + /// Push the given color specification into this buffer. + /// + /// This has the effect of setting the given color information at the + /// current position in the buffer. + fn push(&mut self, spec: Option<ColorSpec>) { + let pos = self.buf.len(); + self.colors.push((pos, spec)); + } + + /// Print the contents to the given stream handle, and use the console + /// for coloring. + fn print( + &self, + console: &mut wincolor::Console, + stream: &mut LossyStandardStream<IoStandardStreamLock>, + ) -> io::Result<()> { + let mut last = 0; + for &(pos, ref spec) in &self.colors { + stream.write_all(&self.buf[last..pos])?; + stream.flush()?; + last = pos; + match *spec { + None => console.reset()?, + Some(ref spec) => spec.write_console(console)?, + } + } + stream.write_all(&self.buf[last..])?; + stream.flush() + } + + /// Clear the buffer. + fn clear(&mut self) { + self.buf.clear(); + self.colors.clear(); + } +} + +#[cfg(windows)] +impl io::Write for WindowsBuffer { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(windows)] +impl WriteColor for WindowsBuffer { + #[inline] + fn supports_color(&self) -> bool { true } + + #[inline] + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.push(Some(spec.clone())); + Ok(()) + } + + #[inline] + fn reset(&mut self) -> io::Result<()> { + self.push(None); + Ok(()) + } + + #[inline] + fn is_synchronous(&self) -> bool { + false + } +} + +/// A color specification. +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct ColorSpec { + fg_color: Option<Color>, + bg_color: Option<Color>, + bold: bool, + intense: bool, + underline: bool, +} + +impl ColorSpec { + /// Create a new color specification that has no colors or styles. + pub fn new() -> ColorSpec { + ColorSpec::default() + } + + /// Get the foreground color. + pub fn fg(&self) -> Option<&Color> { self.fg_color.as_ref() } + + /// Set the foreground color. + pub fn set_fg(&mut self, color: Option<Color>) -> &mut ColorSpec { + self.fg_color = color; + self + } + + /// Get the background color. + pub fn bg(&self) -> Option<&Color> { self.bg_color.as_ref() } + + /// Set the background color. + pub fn set_bg(&mut self, color: Option<Color>) -> &mut ColorSpec { + self.bg_color = color; + self + } + + /// Get whether this is bold or not. + /// + /// Note that the bold setting has no effect in a Windows console. + pub fn bold(&self) -> bool { self.bold } + + /// Set whether the text is bolded or not. + /// + /// Note that the bold setting has no effect in a Windows console. + pub fn set_bold(&mut self, yes: bool) -> &mut ColorSpec { + self.bold = yes; + self + } + + /// Get whether this is underline or not. + /// + /// Note that the underline setting has no effect in a Windows console. + pub fn underline(&self) -> bool { self.underline } + + /// Set whether the text is underlined or not. + /// + /// Note that the underline setting has no effect in a Windows console. + pub fn set_underline(&mut self, yes: bool) -> &mut ColorSpec { + self.underline = yes; + self + } + + /// Get whether this is intense or not. + /// + /// On Unix-like systems, this will output the ANSI escape sequence + /// that will print a high-intensity version of the color + /// specified. + /// + /// On Windows systems, this will output the ANSI escape sequence + /// that will print a brighter version of the color specified. + pub fn intense(&self) -> bool { self.intense } + + /// Set whether the text is intense or not. + /// + /// On Unix-like systems, this will output the ANSI escape sequence + /// that will print a high-intensity version of the color + /// specified. + /// + /// On Windows systems, this will output the ANSI escape sequence + /// that will print a brighter version of the color specified. + pub fn set_intense(&mut self, yes: bool) -> &mut ColorSpec { + self.intense = yes; + self + } + + /// Returns true if this color specification has no colors or styles. + pub fn is_none(&self) -> bool { + self.fg_color.is_none() && self.bg_color.is_none() + && !self.bold && !self.underline + } + + /// Clears this color specification so that it has no color/style settings. + pub fn clear(&mut self) { + self.fg_color = None; + self.bg_color = None; + self.bold = false; + self.underline = false; + } + + /// Writes this color spec to the given Windows console. + #[cfg(windows)] + fn write_console( + &self, + console: &mut wincolor::Console, + ) -> io::Result<()> { + use wincolor::Intense; + + let intense = if self.intense { Intense::Yes } else { Intense::No }; + + let fg_color = self.fg_color.as_ref().and_then(|c| c.to_windows()); + if let Some(color) = fg_color { + console.fg(intense, color)?; + } + + let bg_color = self.bg_color.as_ref().and_then(|c| c.to_windows()); + if let Some(color) = bg_color { + console.bg(intense, color)?; + } + Ok(()) + } +} + +/// The set of available colors for the terminal foreground/background. +/// +/// The `Ansi256` and `Rgb` colors will only output the correct codes when +/// paired with the `Ansi` `WriteColor` implementation. +/// +/// The `Ansi256` and `Rgb` color types are not supported when writing colors +/// on Windows using the console. If they are used on Windows, then they are +/// silently ignored and no colors will be emitted. +/// +/// This set may expand over time. +/// +/// This type has a `FromStr` impl that can parse colors from their human +/// readable form. The format is as follows: +/// +/// 1. Any of the explicitly listed colors in English. They are matched +/// case insensitively. +/// 2. A single 8-bit integer, in either decimal or hexadecimal format. +/// 3. A triple of 8-bit integers separated by a comma, where each integer is +/// in decimal or hexadecimal format. +/// +/// Hexadecimal numbers are written with a `0x` prefix. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Color { + Black, + Blue, + Green, + Red, + Cyan, + Magenta, + Yellow, + White, + Ansi256(u8), + Rgb(u8, u8, u8), + #[doc(hidden)] + __Nonexhaustive, +} + +impl Color { + /// Translate this color to a wincolor::Color. + #[cfg(windows)] + fn to_windows(&self) -> Option<wincolor::Color> { + match *self { + Color::Black => Some(wincolor::Color::Black), + Color::Blue => Some(wincolor::Color::Blue), + Color::Green => Some(wincolor::Color::Green), + Color::Red => Some(wincolor::Color::Red), + Color::Cyan => Some(wincolor::Color::Cyan), + Color::Magenta => Some(wincolor::Color::Magenta), + Color::Yellow => Some(wincolor::Color::Yellow), + Color::White => Some(wincolor::Color::White), + Color::Ansi256(_) => None, + Color::Rgb(_, _, _) => None, + Color::__Nonexhaustive => unreachable!(), + } + } + + /// Parses a numeric color string, either ANSI or RGB. + fn from_str_numeric(s: &str) -> Result<Color, ParseColorError> { + // The "ansi256" format is a single number (decimal or hex) + // corresponding to one of 256 colors. + // + // The "rgb" format is a triple of numbers (decimal or hex) delimited + // by a comma corresponding to one of 256^3 colors. + + fn parse_number(s: &str) -> Option<u8> { + use std::u8; + + if s.starts_with("0x") { + u8::from_str_radix(&s[2..], 16).ok() + } else { + u8::from_str_radix(s, 10).ok() + } + } + + let codes: Vec<&str> = s.split(',').collect(); + if codes.len() == 1 { + if let Some(n) = parse_number(&codes[0]) { + Ok(Color::Ansi256(n)) + } else { + if s.chars().all(|c| c.is_digit(16)) { + Err(ParseColorError { + kind: ParseColorErrorKind::InvalidAnsi256, + given: s.to_string(), + }) + } else { + Err(ParseColorError { + kind: ParseColorErrorKind::InvalidName, + given: s.to_string(), + }) + } + } + } else if codes.len() == 3 { + let mut v = vec![]; + for code in codes { + let n = parse_number(code).ok_or_else(|| { + ParseColorError { + kind: ParseColorErrorKind::InvalidRgb, + given: s.to_string(), + } + })?; + v.push(n); + } + Ok(Color::Rgb(v[0], v[1], v[2])) + } else { + Err(if s.contains(",") { + ParseColorError { + kind: ParseColorErrorKind::InvalidRgb, + given: s.to_string(), + } + } else { + ParseColorError { + kind: ParseColorErrorKind::InvalidName, + given: s.to_string(), + } + }) + } + } +} + +/// An error from parsing an invalid color specification. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParseColorError { + kind: ParseColorErrorKind, + given: String, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +enum ParseColorErrorKind { + InvalidName, + InvalidAnsi256, + InvalidRgb, +} + +impl ParseColorError { + /// Return the string that couldn't be parsed as a valid color. + pub fn invalid(&self) -> &str { &self.given } +} + +impl error::Error for ParseColorError { + fn description(&self) -> &str { + use self::ParseColorErrorKind::*; + match self.kind { + InvalidName => "unrecognized color name", + InvalidAnsi256 => "invalid ansi256 color number", + InvalidRgb => "invalid RGB color triple", + } + } +} + +impl fmt::Display for ParseColorError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::ParseColorErrorKind::*; + match self.kind { + InvalidName => { + write!(f, "unrecognized color name '{}'. Choose from: \ + black, blue, green, red, cyan, magenta, yellow, \ + white", + self.given) + } + InvalidAnsi256 => { + write!(f, "unrecognized ansi256 color number, \ + should be '[0-255]' (or a hex number), but is '{}'", + self.given) + } + InvalidRgb => { + write!(f, "unrecognized RGB color triple, \ + should be '[0-255],[0-255],[0-255]' (or a hex \ + triple), but is '{}'", self.given) + } + } + } +} + +impl FromStr for Color { + type Err = ParseColorError; + + fn from_str(s: &str) -> Result<Color, ParseColorError> { + match &*s.to_lowercase() { + "black" => Ok(Color::Black), + "blue" => Ok(Color::Blue), + "green" => Ok(Color::Green), + "red" => Ok(Color::Red), + "cyan" => Ok(Color::Cyan), + "magenta" => Ok(Color::Magenta), + "yellow" => Ok(Color::Yellow), + "white" => Ok(Color::White), + _ => Color::from_str_numeric(s), + } + } +} + +struct LossyStandardStream<W> { + wtr: W, + #[cfg(windows)] + is_console: bool, +} + +impl<W: io::Write> LossyStandardStream<W> { + #[cfg(not(windows))] + fn new(wtr: W) -> LossyStandardStream<W> { + LossyStandardStream { wtr: wtr } + } + + #[cfg(windows)] + fn new(wtr: W) -> LossyStandardStream<W> { + let is_console = + wincolor::Console::stdout().is_ok() + || wincolor::Console::stderr().is_ok(); + LossyStandardStream { wtr: wtr, is_console: is_console } + } + + #[cfg(not(windows))] + fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> { + LossyStandardStream::new(wtr) + } + + #[cfg(windows)] + fn wrap<Q: io::Write>(&self, wtr: Q) -> LossyStandardStream<Q> { + LossyStandardStream { wtr: wtr, is_console: self.is_console } + } + + fn get_ref(&self) -> &W { + &self.wtr + } +} + +impl<W: WriteColor> WriteColor for LossyStandardStream<W> { + fn supports_color(&self) -> bool { self.wtr.supports_color() } + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.wtr.set_color(spec) + } + fn reset(&mut self) -> io::Result<()> { self.wtr.reset() } + fn is_synchronous(&self) -> bool { self.wtr.is_synchronous() } +} + +impl<W: io::Write> io::Write for LossyStandardStream<W> { + #[cfg(not(windows))] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.wtr.write(buf) + } + + #[cfg(windows)] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + if self.is_console { + write_lossy_utf8(&mut self.wtr, buf) + } else { + self.wtr.write(buf) + } + } + + fn flush(&mut self) -> io::Result<()> { + self.wtr.flush() + } +} + +#[cfg(windows)] +fn write_lossy_utf8<W: io::Write>(mut w: W, buf: &[u8]) -> io::Result<usize> { + match ::std::str::from_utf8(buf) { + Ok(s) => w.write(s.as_bytes()), + Err(ref e) if e.valid_up_to() == 0 => { + w.write(b"\xEF\xBF\xBD")?; + Ok(1) + } + Err(e) => w.write(&buf[..e.valid_up_to()]), + } +} + +#[cfg(test)] +mod tests { + use super::{ + Ansi, Color, ParseColorError, ParseColorErrorKind, StandardStream, + }; + + fn assert_is_send<T: Send>() {} + + #[test] + fn standard_stream_is_send() { + assert_is_send::<StandardStream>(); + } + + #[test] + fn test_simple_parse_ok() { + let color = "green".parse::<Color>(); + assert_eq!(color, Ok(Color::Green)); + } + + #[test] + fn test_256_parse_ok() { + let color = "7".parse::<Color>(); + assert_eq!(color, Ok(Color::Ansi256(7))); + + let color = "32".parse::<Color>(); + assert_eq!(color, Ok(Color::Ansi256(32))); + + let color = "0xFF".parse::<Color>(); + assert_eq!(color, Ok(Color::Ansi256(0xFF))); + } + + #[test] + fn test_256_parse_err_out_of_range() { + let color = "256".parse::<Color>(); + assert_eq!(color, Err(ParseColorError { + kind: ParseColorErrorKind::InvalidAnsi256, + given: "256".to_string(), + })); + } + + #[test] + fn test_rgb_parse_ok() { + let color = "0,0,0".parse::<Color>(); + assert_eq!(color, Ok(Color::Rgb(0, 0, 0))); + + let color = "0,128,255".parse::<Color>(); + assert_eq!(color, Ok(Color::Rgb(0, 128, 255))); + + let color = "0x0,0x0,0x0".parse::<Color>(); + assert_eq!(color, Ok(Color::Rgb(0, 0, 0))); + + let color = "0x33,0x66,0xFF".parse::<Color>(); + assert_eq!(color, Ok(Color::Rgb(0x33, 0x66, 0xFF))); + } + + #[test] + fn test_rgb_parse_err_out_of_range() { + let color = "0,0,256".parse::<Color>(); + assert_eq!(color, Err(ParseColorError { + kind: ParseColorErrorKind::InvalidRgb, + given: "0,0,256".to_string(), + })); + } + + #[test] + fn test_rgb_parse_err_bad_format() { + let color = "0,0".parse::<Color>(); + assert_eq!(color, Err(ParseColorError { + kind: ParseColorErrorKind::InvalidRgb, + given: "0,0".to_string(), + })); + + let color = "not_a_color".parse::<Color>(); + assert_eq!(color, Err(ParseColorError { + kind: ParseColorErrorKind::InvalidName, + given: "not_a_color".to_string(), + })); + } + + #[test] + fn test_var_ansi_write_rgb() { + let mut buf = Ansi::new(vec![]); + let _ = buf.write_color(true, &Color::Rgb(254, 253, 255), false); + assert_eq!(buf.0, b"\x1B[38;2;254;253;255m"); + } + + #[test] + fn test_var_ansi_write_256() { + let mut buf = Ansi::new(vec![]); + let _ = buf.write_color(false, &Color::Ansi256(7), false); + assert_eq!(buf.0, b"\x1B[48;5;7m"); + + let mut buf = Ansi::new(vec![]); + let _ = buf.write_color(false, &Color::Ansi256(208), false); + assert_eq!(buf.0, b"\x1B[48;5;208m"); + } +} diff --git a/termion/.cargo-checksum.json b/termion/.cargo-checksum.json new file mode 100644 index 000000000..28a1b4d8d --- /dev/null +++ b/termion/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"} \ No newline at end of file diff --git a/termion/Cargo.toml b/termion/Cargo.toml new file mode 100644 index 000000000..da11aad14 --- /dev/null +++ b/termion/Cargo.toml @@ -0,0 +1,32 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "termion" +version = "1.5.2" +authors = ["ticki <Ticki@users.noreply.github.com>", "gycos <alexandre.bury@gmail.com>", "IGI-111 <igi-111@protonmail.com>"] +exclude = ["target", "CHANGELOG.md", "image.png", "Cargo.lock"] +description = "A bindless library for manipulating terminals." +documentation = "https://docs.rs/termion" +keywords = ["tty", "color", "terminal", "password", "tui"] +license = "MIT" +repository = "https://gitlab.redox-os.org/redox-os/termion" +[dependencies.numtoa] +version = "0.1.0" +features = ["std"] +[target."cfg(not(target_os = \"redox\"))".dependencies.libc] +version = "0.2.8" +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" + +[target."cfg(target_os = \"redox\")".dependencies.redox_termios] +version = "0.1" diff --git a/termion/LICENSE b/termion/LICENSE new file mode 100644 index 000000000..3903091a1 --- /dev/null +++ b/termion/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Ticki + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/termion/README.md b/termion/README.md new file mode 100644 index 000000000..25346d94c --- /dev/null +++ b/termion/README.md @@ -0,0 +1,181 @@ +<p align="center"> +<img alt="Termion logo" src="https://rawgit.com/redox-os/termion/master/logo.svg" /> +</p> + +[![Build Status](https://travis-ci.org/redox-os/termion.svg?branch=master)](https://travis-ci.org/redox-os/termion) [![Latest Version](https://img.shields.io/crates/v/termion.svg)](https://crates.io/crates/termion) | [Documentation](https://docs.rs/termion) | [Examples](https://github.com/redox-os/termion/tree/master/examples) | [Changelog](https://github.com/redox-os/termion/tree/master/CHANGELOG.md) | [Tutorial](http://ticki.github.io/blog/making-terminal-applications-in-rust-with-termion/) +|----|----|----|----|---- + + +**Termion** is a pure Rust, bindless library for low-level handling, manipulating +and reading information about terminals. This provides a full-featured +alternative to Termbox. + +Termion aims to be simple and yet expressive. It is bindless, meaning that it +is not a front-end to some other library (e.g., ncurses or termbox), but a +standalone library directly talking to the TTY. + +Termion is quite convenient, due to its complete coverage of essential TTY +features, providing one consistent API. Termion is rather low-level containing +only abstraction aligned with what actually happens behind the scenes. For +something more high-level, refer to inquirer-rs, which uses Termion as backend. + +Termion generates escapes and API calls for the user. This makes it a whole lot +cleaner to use escapes. + +Supports Redox, Mac OS X, BSD, and Linux (or, in general, ANSI terminals). + +## A note on stability + +This crate is stable. + +## Cargo.toml + +```toml +[dependencies] +termion = "*" +``` + +## 0.1.0 to 1.0.0 guide + +This sample table gives an idea of how to go about converting to the new major +version of Termion. + +| 0.1.0 | 1.0.0 +|--------------------------------|--------------------------- +| `use termion::IntoRawMode` | `use termion::raw::IntoRawMode` +| `use termion::TermRead` | `use termion::input::TermRead` +| `stdout.color(color::Red);` | `write!(stdout, "{}", color::Fg(color::Red));` +| `stdout.color_bg(color::Red);` | `write!(stdout, "{}", color::Bg(color::Red));` +| `stdout.goto(x, y);` | `write!(stdout, "{}", cursor::Goto(x, y));` +| `color::rgb(r, g, b);` | `color::Rgb(r, g, b)` (truecolor) +| `x.with_mouse()` | `MouseTerminal::from(x)` + +## Features + +- Raw mode. +- TrueColor. +- 256-color mode. +- Cursor movement. +- Text formatting. +- Console size. +- TTY-only stream. +- Control sequences. +- Termios control. +- Password input. +- Redox support. +- Safe `isatty` wrapper. +- Panic-free error handling. +- Special keys events (modifiers, special keys, etc.). +- Allocation-free. +- Asynchronous key events. +- Mouse input. +- Carefully tested. +- Detailed documentation on every item. + +and much more. + +## Examples + +### Style and colors. + +```rust +extern crate termion; + +use termion::{color, style}; + +use std::io; + +fn main() { + println!("{}Red", color::Fg(color::Red)); + println!("{}Blue", color::Fg(color::Blue)); + println!("{}Blue'n'Bold{}", style::Bold, style::Reset); + println!("{}Just plain italic", style::Italic); +} +``` + +### Moving the cursor + +```rust +extern crate termion; + +fn main() { + print!("{}{}Stuff", termion::clear::All, termion::cursor::Goto(1, 1)); +} + +``` + +### Mouse + +```rust +extern crate termion; + +use termion::event::{Key, Event, MouseEvent}; +use termion::input::{TermRead, MouseTerminal}; +use termion::raw::IntoRawMode; +use std::io::{Write, stdout, stdin}; + +fn main() { + let stdin = stdin(); + let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); + + write!(stdout, "{}{}q to exit. Click, click, click!", termion::clear::All, termion::cursor::Goto(1, 1)).unwrap(); + stdout.flush().unwrap(); + + for c in stdin.events() { + let evt = c.unwrap(); + match evt { + Event::Key(Key::Char('q')) => break, + Event::Mouse(me) => { + match me { + MouseEvent::Press(_, x, y) => { + write!(stdout, "{}x", termion::cursor::Goto(x, y)).unwrap(); + }, + _ => (), + } + } + _ => {} + } + stdout.flush().unwrap(); + } +} +``` + +### Read a password + +```rust +extern crate termion; + +use termion::input::TermRead; +use std::io::{Write, stdout, stdin}; + +fn main() { + let stdout = stdout(); + let mut stdout = stdout.lock(); + let stdin = stdin(); + let mut stdin = stdin.lock(); + + stdout.write_all(b"password: ").unwrap(); + stdout.flush().unwrap(); + + let pass = stdin.read_passwd(&mut stdout); + + if let Ok(Some(pass)) = pass { + stdout.write_all(pass.as_bytes()).unwrap(); + stdout.write_all(b"\n").unwrap(); + } else { + stdout.write_all(b"Error\n").unwrap(); + } +} +``` + +## Usage + +See `examples/`, and the documentation, which can be rendered using `cargo doc`. + +For a more complete example, see [a minesweeper implementation](https://github.com/redox-os/games-for-redox/blob/master/src/minesweeper/main.rs), that I made for Redox using termion. + +<img src="image.png" width="200"> + +## License + +MIT/X11. diff --git a/termion/examples/alternate_screen.rs b/termion/examples/alternate_screen.rs new file mode 100644 index 000000000..91d28b170 --- /dev/null +++ b/termion/examples/alternate_screen.rs @@ -0,0 +1,17 @@ +extern crate termion; + +use termion::screen::*; +use std::io::{Write, stdout}; +use std::{time, thread}; + +fn main() { + { + let mut screen = AlternateScreen::from(stdout()); + write!(screen, "Welcome to the alternate screen.\n\nPlease wait patiently until we arrive back at the main screen in a about three seconds.").unwrap(); + screen.flush().unwrap(); + + thread::sleep(time::Duration::from_secs(3)); + } + + println!("Phew! We are back."); +} diff --git a/termion/examples/alternate_screen_raw.rs b/termion/examples/alternate_screen_raw.rs new file mode 100644 index 000000000..7ba788880 --- /dev/null +++ b/termion/examples/alternate_screen_raw.rs @@ -0,0 +1,40 @@ +extern crate termion; + +use termion::event::Key; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use termion::screen::*; +use std::io::{Write, stdout, stdin}; + +fn write_alt_screen_msg<W: Write>(screen: &mut W) { + write!(screen, "{}{}Welcome to the alternate screen.{}Press '1' to switch to the main screen or '2' to switch to the alternate screen.{}Press 'q' to exit (and switch back to the main screen).", + termion::clear::All, + termion::cursor::Goto(1, 1), + termion::cursor::Goto(1, 3), + termion::cursor::Goto(1, 4)).unwrap(); +} + +fn main() { + let stdin = stdin(); + let mut screen = AlternateScreen::from(stdout().into_raw_mode().unwrap()); + write!(screen, "{}", termion::cursor::Hide).unwrap(); + write_alt_screen_msg(&mut screen); + + screen.flush().unwrap(); + + for c in stdin.keys() { + match c.unwrap() { + Key::Char('q') => break, + Key::Char('1') => { + write!(screen, "{}", ToMainScreen).unwrap(); + } + Key::Char('2') => { + write!(screen, "{}", ToAlternateScreen).unwrap(); + write_alt_screen_msg(&mut screen); + } + _ => {} + } + screen.flush().unwrap(); + } + write!(screen, "{}", termion::cursor::Show).unwrap(); +} diff --git a/termion/examples/async.rs b/termion/examples/async.rs new file mode 100644 index 000000000..b16bb7861 --- /dev/null +++ b/termion/examples/async.rs @@ -0,0 +1,39 @@ +extern crate termion; + +use termion::raw::IntoRawMode; +use termion::async_stdin; +use std::io::{Read, Write, stdout}; +use std::thread; +use std::time::Duration; + +fn main() { + let stdout = stdout(); + let mut stdout = stdout.lock().into_raw_mode().unwrap(); + let mut stdin = async_stdin().bytes(); + + write!(stdout, + "{}{}", + termion::clear::All, + termion::cursor::Goto(1, 1)) + .unwrap(); + + loop { + write!(stdout, "{}", termion::clear::CurrentLine).unwrap(); + + let b = stdin.next(); + write!(stdout, "\r{:?} <- This demonstrates the async read input char. Between each update a 100 ms. is waited, simply to demonstrate the async fashion. \n\r", b).unwrap(); + if let Some(Ok(b'q')) = b { + break; + } + + stdout.flush().unwrap(); + + thread::sleep(Duration::from_millis(50)); + stdout.write_all(b"# ").unwrap(); + stdout.flush().unwrap(); + thread::sleep(Duration::from_millis(50)); + stdout.write_all(b"\r #").unwrap(); + write!(stdout, "{}", termion::cursor::Goto(1, 1)).unwrap(); + stdout.flush().unwrap(); + } +} diff --git a/termion/examples/click.rs b/termion/examples/click.rs new file mode 100644 index 000000000..fe903d837 --- /dev/null +++ b/termion/examples/click.rs @@ -0,0 +1,35 @@ +extern crate termion; + +use termion::event::{Key, Event, MouseEvent}; +use termion::input::{TermRead, MouseTerminal}; +use termion::raw::IntoRawMode; +use std::io::{Write, stdout, stdin}; + +fn main() { + let stdin = stdin(); + let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap()); + + write!(stdout, + "{}{}q to exit. Click, click, click!", + termion::clear::All, + termion::cursor::Goto(1, 1)) + .unwrap(); + stdout.flush().unwrap(); + + for c in stdin.events() { + let evt = c.unwrap(); + match evt { + Event::Key(Key::Char('q')) => break, + Event::Mouse(me) => { + match me { + MouseEvent::Press(_, x, y) => { + write!(stdout, "{}x", termion::cursor::Goto(x, y)).unwrap(); + } + _ => (), + } + } + _ => {} + } + stdout.flush().unwrap(); + } +} diff --git a/termion/examples/color.rs b/termion/examples/color.rs new file mode 100644 index 000000000..72c521d70 --- /dev/null +++ b/termion/examples/color.rs @@ -0,0 +1,10 @@ +extern crate termion; + +use termion::{color, style}; + +fn main() { + println!("{}Red", color::Fg(color::Red)); + println!("{}Blue", color::Fg(color::Blue)); + println!("{}Blue'n'Bold{}", style::Bold, style::Reset); + println!("{}Just plain italic{}", style::Italic, style::Reset); +} diff --git a/termion/examples/commie.rs b/termion/examples/commie.rs new file mode 100644 index 000000000..32f8820e5 --- /dev/null +++ b/termion/examples/commie.rs @@ -0,0 +1,51 @@ +extern crate termion; + +use termion::{clear, color, cursor}; + +use std::{time, thread}; + +const COMMUNISM: &'static str = r#" + !######### # + !########! ##! + !########! ### + !########## #### + ######### ##### ###### + !###! !####! ###### + ! ##### ######! + !####! ####### + ##### ####### + !####! #######! + ####!######## + ## ########## + ,######! !############# + ,#### ########################!####! + ,####' ##################!' ##### + ,####' ####### !####! + ####' ##### + ~## ##~ +"#; + +fn main() { + let mut state = 0; + + println!("\n{}{}{}{}{}{}", + cursor::Hide, + clear::All, + cursor::Goto(1, 1), + color::Fg(color::Black), + color::Bg(color::Red), + COMMUNISM); + loop { + println!("{}{} ☭ GAY ☭ SPACE ☭ COMMUNISM ☭ ", + cursor::Goto(1, 1), + color::Bg(color::AnsiValue(state))); + println!("{}{} WILL PREVAIL, COMRADES! ", + cursor::Goto(1, 20), + color::Bg(color::AnsiValue(state))); + + state += 1; + state %= 8; + + thread::sleep(time::Duration::from_millis(90)); + } +} diff --git a/termion/examples/detect_color.rs b/termion/examples/detect_color.rs new file mode 100644 index 000000000..ecfdd5b45 --- /dev/null +++ b/termion/examples/detect_color.rs @@ -0,0 +1,19 @@ +extern crate termion; + +use termion::color::{DetectColors, AnsiValue, Bg}; +use termion::raw::IntoRawMode; +use std::io::stdout; + +fn main() { + let count; + { + let mut term = stdout().into_raw_mode().unwrap(); + count = term.available_colors().unwrap(); + } + + println!("This terminal supports {} colors.", count); + for i in 0..count { + print!("{} {}", Bg(AnsiValue(i as u8)), Bg(AnsiValue(0))); + } + println!(); +} diff --git a/termion/examples/is_tty.rs b/termion/examples/is_tty.rs new file mode 100644 index 000000000..52d1bc1d2 --- /dev/null +++ b/termion/examples/is_tty.rs @@ -0,0 +1,11 @@ +extern crate termion; + +use std::fs; + +fn main() { + if termion::is_tty(&fs::File::create("/dev/stdout").unwrap()) { + println!("This is a TTY!"); + } else { + println!("This is not a TTY :("); + } +} diff --git a/termion/examples/keys.rs b/termion/examples/keys.rs new file mode 100644 index 000000000..272ffd1b9 --- /dev/null +++ b/termion/examples/keys.rs @@ -0,0 +1,44 @@ +extern crate termion; + +use termion::event::Key; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use std::io::{Write, stdout, stdin}; + +fn main() { + let stdin = stdin(); + let mut stdout = stdout().into_raw_mode().unwrap(); + + write!(stdout, + "{}{}q to exit. Type stuff, use alt, and so on.{}", + termion::clear::All, + termion::cursor::Goto(1, 1), + termion::cursor::Hide) + .unwrap(); + stdout.flush().unwrap(); + + for c in stdin.keys() { + write!(stdout, + "{}{}", + termion::cursor::Goto(1, 1), + termion::clear::CurrentLine) + .unwrap(); + + match c.unwrap() { + Key::Char('q') => break, + Key::Char(c) => println!("{}", c), + Key::Alt(c) => println!("^{}", c), + Key::Ctrl(c) => println!("*{}", c), + Key::Esc => println!("ESC"), + Key::Left => println!("←"), + Key::Right => println!("→"), + Key::Up => println!("↑"), + Key::Down => println!("↓"), + Key::Backspace => println!("×"), + _ => {} + } + stdout.flush().unwrap(); + } + + write!(stdout, "{}", termion::cursor::Show).unwrap(); +} diff --git a/termion/examples/mouse.rs b/termion/examples/mouse.rs new file mode 100644 index 000000000..cbe8baf46 --- /dev/null +++ b/termion/examples/mouse.rs @@ -0,0 +1,46 @@ +extern crate termion; + +use termion::event::*; +use termion::cursor::{self, DetectCursorPos}; +use termion::input::{TermRead, MouseTerminal}; +use termion::raw::IntoRawMode; +use std::io::{self, Write}; + +fn main() { + let stdin = io::stdin(); + let mut stdout = MouseTerminal::from(io::stdout().into_raw_mode().unwrap()); + + writeln!(stdout, + "{}{}q to exit. Type stuff, use alt, click around...", + termion::clear::All, + termion::cursor::Goto(1, 1)) + .unwrap(); + + for c in stdin.events() { + let evt = c.unwrap(); + match evt { + Event::Key(Key::Char('q')) => break, + Event::Mouse(me) => { + match me { + MouseEvent::Press(_, a, b) | + MouseEvent::Release(a, b) | + MouseEvent::Hold(a, b) => { + write!(stdout, "{}", cursor::Goto(a, b)).unwrap(); + let (x, y) = stdout.cursor_pos().unwrap(); + write!(stdout, + "{}{}Cursor is at: ({},{}){}", + cursor::Goto(5, 5), + termion::clear::UntilNewline, + x, + y, + cursor::Goto(a, b)) + .unwrap(); + } + } + } + _ => {} + } + + stdout.flush().unwrap(); + } +} diff --git a/termion/examples/rainbow.rs b/termion/examples/rainbow.rs new file mode 100644 index 000000000..4ee4000d0 --- /dev/null +++ b/termion/examples/rainbow.rs @@ -0,0 +1,60 @@ +extern crate termion; + +use termion::event::Key; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use std::io::{Write, stdout, stdin}; + +fn rainbow<W: Write>(stdout: &mut W, blue: u8) { + write!(stdout, + "{}{}", + termion::cursor::Goto(1, 1), + termion::clear::All) + .unwrap(); + + for red in 0..32 { + let red = red * 8; + for green in 0..64 { + let green = green * 4; + write!(stdout, + "{} ", + termion::color::Bg(termion::color::Rgb(red, green, blue))) + .unwrap(); + } + write!(stdout, "\n\r").unwrap(); + } + + writeln!(stdout, "{}b = {}", termion::style::Reset, blue).unwrap(); +} + +fn main() { + let stdin = stdin(); + let mut stdout = stdout().into_raw_mode().unwrap(); + + writeln!(stdout, + "{}{}{}Use the up/down arrow keys to change the blue in the rainbow.", + termion::clear::All, + termion::cursor::Goto(1, 1), + termion::cursor::Hide) + .unwrap(); + + let mut blue = 172u8; + + for c in stdin.keys() { + match c.unwrap() { + Key::Up => { + blue = blue.saturating_add(4); + rainbow(&mut stdout, blue); + } + Key::Down => { + blue = blue.saturating_sub(4); + rainbow(&mut stdout, blue); + } + Key::Char('q') => break, + _ => {} + } + stdout.flush().unwrap(); + } + + write!(stdout, "{}", termion::cursor::Show).unwrap(); +} diff --git a/termion/examples/read.rs b/termion/examples/read.rs new file mode 100644 index 000000000..8d53e1bf7 --- /dev/null +++ b/termion/examples/read.rs @@ -0,0 +1,23 @@ +extern crate termion; + +use termion::input::TermRead; +use std::io::{Write, stdout, stdin}; + +fn main() { + let stdout = stdout(); + let mut stdout = stdout.lock(); + let stdin = stdin(); + let mut stdin = stdin.lock(); + + stdout.write_all(b"password: ").unwrap(); + stdout.flush().unwrap(); + + let pass = stdin.read_passwd(&mut stdout); + + if let Ok(Some(pass)) = pass { + stdout.write_all(pass.as_bytes()).unwrap(); + stdout.write_all(b"\n").unwrap(); + } else { + stdout.write_all(b"Error\n").unwrap(); + } +} diff --git a/termion/examples/rustc_fun.rs b/termion/examples/rustc_fun.rs new file mode 100644 index 000000000..734e89f42 --- /dev/null +++ b/termion/examples/rustc_fun.rs @@ -0,0 +1,24 @@ +extern crate termion; + +use termion::{color, style}; + +fn main() { + println!("{lighgreen}-- src/test/ui/borrow-errors.rs at 82:18 --\n\ + {red}error: {reset}{bold}two closures require unique access to `vec` at the same time {reset}{bold}{magenta}[E0524]{reset}\n\ + {line_num_fg}{line_num_bg}79 {reset} let append = |e| {{\n\ + {line_num_fg}{line_num_bg}{info_line}{reset} {red}^^^{reset} {error_fg}first closure is constructed here\n\ + {line_num_fg}{line_num_bg}80 {reset} vec.push(e)\n\ + {line_num_fg}{line_num_bg}{info_line}{reset} {red}^^^{reset} {error_fg}previous borrow occurs due to use of `vec` in closure\n\ + {line_num_fg}{line_num_bg}84 {reset} }};\n\ + {line_num_fg}{line_num_bg}85 {reset} }}\n\ + {line_num_fg}{line_num_bg}{info_line}{reset} {red}^{reset} {error_fg}borrow from first closure ends here", + lighgreen = color::Fg(color::LightGreen), + red = color::Fg(color::Red), + bold = style::Bold, + reset = style::Reset, + magenta = color::Fg(color::Magenta), + line_num_bg = color::Bg(color::AnsiValue::grayscale(3)), + line_num_fg = color::Fg(color::AnsiValue::grayscale(18)), + info_line = "| ", + error_fg = color::Fg(color::AnsiValue::grayscale(17))) +} diff --git a/termion/examples/simple.rs b/termion/examples/simple.rs new file mode 100644 index 000000000..93ef1df3a --- /dev/null +++ b/termion/examples/simple.rs @@ -0,0 +1,42 @@ +extern crate termion; + +use termion::color; +use termion::raw::IntoRawMode; +use std::io::{Read, Write, stdout, stdin}; + +fn main() { + // Initialize 'em all. + let stdout = stdout(); + let mut stdout = stdout.lock().into_raw_mode().unwrap(); + let stdin = stdin(); + let stdin = stdin.lock(); + + write!(stdout, + "{}{}{}yo, 'q' will exit.{}{}", + termion::clear::All, + termion::cursor::Goto(5, 5), + termion::style::Bold, + termion::style::Reset, + termion::cursor::Goto(20, 10)) + .unwrap(); + stdout.flush().unwrap(); + + let mut bytes = stdin.bytes(); + loop { + let b = bytes.next().unwrap().unwrap(); + + match b { + // Quit + b'q' => return, + // Clear the screen + b'c' => write!(stdout, "{}", termion::clear::All), + // Set red color + b'r' => write!(stdout, "{}", color::Fg(color::Rgb(5, 0, 0))), + // Write it to stdout. + a => write!(stdout, "{}", a), + } + .unwrap(); + + stdout.flush().unwrap(); + } +} diff --git a/termion/examples/size.rs b/termion/examples/size.rs new file mode 100644 index 000000000..e91fa5430 --- /dev/null +++ b/termion/examples/size.rs @@ -0,0 +1,7 @@ +extern crate termion; + +use termion::terminal_size; + +fn main() { + println!("Size is {:?}", terminal_size().unwrap()) +} diff --git a/termion/examples/truecolor.rs b/termion/examples/truecolor.rs new file mode 100644 index 000000000..ba5c8685b --- /dev/null +++ b/termion/examples/truecolor.rs @@ -0,0 +1,12 @@ +extern crate termion; + +use termion::{color, cursor, clear}; +use std::{thread, time}; + +fn main() { + for r in 0..255 { + let c = color::Rgb(r, !r, 2 * ((r % 128) as i8 - 64).abs() as u8); + println!("{}{}{}wow", cursor::Goto(1, 1), color::Bg(c), clear::All); + thread::sleep(time::Duration::from_millis(100)); + } +} diff --git a/termion/logo.svg b/termion/logo.svg new file mode 100644 index 000000000..39bc574b6 --- /dev/null +++ b/termion/logo.svg @@ -0,0 +1,9 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="60.099598mm" height="18.291185mm" viewBox="0 0 212.95 64.81"> + <style> + .blink { animation: blinker 3s linear infinite; } @keyframes blinker { 50% { opacity: 0; } } + </style> + + <path d="M0 0h212.95v64.82H0z" opacity=".71"/> + <path fill="#f9f9f9" d="M12.24 17.8H34.5v3.33h-9.13v25.84H21.4V21.13h-9.16V17.8zm27 0h17.3v3.33H43.2v8.63h12.77v3.32h-12.8v10.57H56.9v3.32H39.24V17.8zM74.3 33.2q1.5.4 2.6 1.48 1.06 1.08 2.66 4.32l3.97 7.97H79.3l-3.5-7.37q-1.5-3.14-2.7-4.04-1.2-.92-3.13-.92H66.2v12.33h-3.96V17.8h8.13q4.8 0 7.36 2.17 2.56 2.17 2.56 6.27 0 2.9-1.6 4.73-1.6 1.82-4.4 2.23zm-8.1-12.15V31.4h4.32q2.83 0 4.22-1.27 1.4-1.27 1.4-3.9 0-2.5-1.5-3.83-1.46-1.35-4.27-1.35H66.2zm19-3.25h5.26l5.04 14.85 5.08-14.84h5.3V47h-3.66V21.2l-5.2 15.38h-2.98L88.82 21.2v25.77H85.2V17.8zm26.3 0h16.2v3.33h-6.12v22.52h6.1v3.32H111.5v-3.32h6.1V21.13h-6.1V17.8zm37.8 14.62q0-6.43-1.32-9.18-1.3-2.76-4.3-2.76t-4.33 2.76q-1.3 2.75-1.3 9.18 0 6.4 1.3 9.16 1.33 2.75 4.32 2.75 3 0 4.3-2.73 1.34-2.76 1.34-9.18zm4.13 0q0 7.6-2.42 11.36-2.4 3.75-7.3 3.75t-7.3-3.73q-2.4-3.73-2.4-11.38 0-7.64 2.4-11.4 2.4-3.74 7.35-3.74t7.34 3.75q2.42 3.75 2.42 11.4zm4.97-14.62h5l9.86 24v-24h3.8v29.17h-5l-9.84-24v24h-3.8V17.8z"/> + <path fill="#f9f9f9" d="M192.7 8.66v47.5h-3.93V8.66h3.94z" class="blink"/> +</svg> diff --git a/termion/src/async.rs b/termion/src/async.rs new file mode 100644 index 000000000..ea0248916 --- /dev/null +++ b/termion/src/async.rs @@ -0,0 +1,101 @@ +use std::io::{self, Read}; +use std::sync::mpsc; +use std::thread; + +use sys::tty::get_tty; + +/// Construct an asynchronous handle to the TTY standard input, with a delimiter byte. +/// +/// This has the same advantages as async_stdin(), but also allows specifying a delimiter byte. The +/// reader will stop reading after consuming the delimiter byte. +pub fn async_stdin_until(delimiter: u8) -> AsyncReader { + let (send, recv) = mpsc::channel(); + + thread::spawn(move || for i in get_tty().unwrap().bytes() { + + match i { + Ok(byte) => { + let end_of_stream = &byte == &delimiter; + let send_error = send.send(Ok(byte)).is_err(); + + if end_of_stream || send_error { return; } + }, + Err(_) => { return; } + } + }); + + AsyncReader { recv: recv } +} + +/// Construct an asynchronous handle to the TTY standard input. +/// +/// This allows you to read from standard input _without blocking_ the current thread. +/// Specifically, it works by firing up another thread to handle the event stream, which will then +/// be buffered in a mpsc queue, which will eventually be read by the current thread. +/// +/// This will not read the piped standard input, but rather read from the TTY device, since reading +/// asyncronized from piped input would rarely make sense. In other words, if you pipe standard +/// output from another process, it won't be reflected in the stream returned by this function, as +/// this represents the TTY device, and not the piped standard input. +pub fn async_stdin() -> AsyncReader { + let (send, recv) = mpsc::channel(); + + thread::spawn(move || for i in get_tty().unwrap().bytes() { + if send.send(i).is_err() { + return; + } + }); + + AsyncReader { recv: recv } +} + +/// An asynchronous reader. +/// +/// This acts as any other stream, with the exception that reading from it won't block. Instead, +/// the buffer will only be partially updated based on how much the internal buffer holds. +pub struct AsyncReader { + /// The underlying mpsc receiver. + recv: mpsc::Receiver<io::Result<u8>>, +} + +// FIXME: Allow constructing an async reader from an arbitrary stream. + +impl Read for AsyncReader { + /// Read from the byte stream. + /// + /// This will never block, but try to drain the event queue until empty. If the total number of + /// bytes written is lower than the buffer's length, the event queue is empty or that the event + /// stream halted. + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let mut total = 0; + + loop { + if total >= buf.len() { + break; + } + + match self.recv.try_recv() { + Ok(Ok(b)) => { + buf[total] = b; + total += 1; + } + Ok(Err(e)) => return Err(e), + Err(_) => break, + } + } + + Ok(total) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::Read; + + #[test] + fn test_async_stdin() { + let stdin = async_stdin(); + stdin.bytes().next(); + } +} diff --git a/termion/src/clear.rs b/termion/src/clear.rs new file mode 100644 index 000000000..d37f2c6b9 --- /dev/null +++ b/termion/src/clear.rs @@ -0,0 +1,9 @@ +//! Clearing the screen. + +use std::fmt; + +derive_csi_sequence!("Clear the entire screen.", All, "2J"); +derive_csi_sequence!("Clear everything after the cursor.", AfterCursor, "J"); +derive_csi_sequence!("Clear everything before the cursor.", BeforeCursor, "1J"); +derive_csi_sequence!("Clear the current line.", CurrentLine, "2K"); +derive_csi_sequence!("Clear from cursor to newline.", UntilNewline, "K"); diff --git a/termion/src/color.rs b/termion/src/color.rs new file mode 100644 index 000000000..6c543b695 --- /dev/null +++ b/termion/src/color.rs @@ -0,0 +1,306 @@ +//! Color managemement. +//! +//! # Example +//! +//! ```rust +//! use termion::color; +//! +//! fn main() { +//! println!("{}Red", color::Fg(color::Red)); +//! println!("{}Blue", color::Fg(color::Blue)); +//! println!("{}Back again", color::Fg(color::Reset)); +//! } +//! ``` + +use std::fmt; +use raw::CONTROL_SEQUENCE_TIMEOUT; +use std::io::{self, Write, Read}; +use std::time::{SystemTime, Duration}; +use async::async_stdin; +use std::env; +use std::fmt::Debug; +use numtoa::NumToA; + +/// A terminal color. +pub trait Color: Debug { + /// Write the foreground version of this color. + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result; + /// Write the background version of this color. + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result; +} + +macro_rules! derive_color { + ($doc:expr, $name:ident, $value:expr) => { + #[doc = $doc] + #[derive(Copy, Clone, Debug)] + pub struct $name; + + impl Color for $name { + #[inline] + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.fg_str()) + } + + #[inline] + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.bg_str()) + } + } + + impl $name { + #[inline] + /// Returns the ANSI escape sequence as a string. + pub fn fg_str(&self) -> &'static str { csi!("38;5;", $value, "m") } + + #[inline] + /// Returns the ANSI escape sequences as a string. + pub fn bg_str(&self) -> &'static str { csi!("48;5;", $value, "m") } + } + }; +} + +derive_color!("Black.", Black, "0"); +derive_color!("Red.", Red, "1"); +derive_color!("Green.", Green, "2"); +derive_color!("Yellow.", Yellow, "3"); +derive_color!("Blue.", Blue, "4"); +derive_color!("Magenta.", Magenta, "5"); +derive_color!("Cyan.", Cyan, "6"); +derive_color!("White.", White, "7"); +derive_color!("High-intensity light black.", LightBlack, "8"); +derive_color!("High-intensity light red.", LightRed, "9"); +derive_color!("High-intensity light green.", LightGreen, "10"); +derive_color!("High-intensity light yellow.", LightYellow, "11"); +derive_color!("High-intensity light blue.", LightBlue, "12"); +derive_color!("High-intensity light magenta.", LightMagenta, "13"); +derive_color!("High-intensity light cyan.", LightCyan, "14"); +derive_color!("High-intensity light white.", LightWhite, "15"); + +impl<'a> Color for &'a Color { + #[inline] + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + (*self).write_fg(f) + } + + #[inline] + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + (*self).write_bg(f) + } +} + +/// An arbitrary ANSI color value. +#[derive(Clone, Copy, Debug)] +pub struct AnsiValue(pub u8); + +impl AnsiValue { + /// 216-color (r, g, b ≤ 5) RGB. + pub fn rgb(r: u8, g: u8, b: u8) -> AnsiValue { + debug_assert!(r <= 5, + "Red color fragment (r = {}) is out of bound. Make sure r ≤ 5.", + r); + debug_assert!(g <= 5, + "Green color fragment (g = {}) is out of bound. Make sure g ≤ 5.", + g); + debug_assert!(b <= 5, + "Blue color fragment (b = {}) is out of bound. Make sure b ≤ 5.", + b); + + AnsiValue(16 + 36 * r + 6 * g + b) + } + + /// Grayscale color. + /// + /// There are 24 shades of gray. + pub fn grayscale(shade: u8) -> AnsiValue { + // Unfortunately, there are a little less than fifty shades. + debug_assert!(shade < 24, + "Grayscale out of bound (shade = {}). There are only 24 shades of \ + gray.", + shade); + + AnsiValue(0xE8 + shade) + } +} + +impl AnsiValue { + /// Returns the ANSI sequence as a string. + pub fn fg_string(self) -> String { + let mut x = [0u8; 20]; + let x = self.0.numtoa_str(10, &mut x); + [csi!("38;5;"), x, "m"].concat() + } + + /// Returns the ANSI sequence as a string. + pub fn bg_string(self) -> String { + let mut x = [0u8; 20]; + let x = self.0.numtoa_str(10, &mut x); + [csi!("48;5;"), x, "m"].concat() + } +} + +impl Color for AnsiValue { + #[inline] + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.fg_string()) + } + + #[inline] + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.bg_string()) + } +} + +/// A truecolor RGB. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Rgb(pub u8, pub u8, pub u8); + +impl Rgb { + /// Returns the ANSI sequence as a string. + pub fn fg_string(self) -> String { + let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]); + let (x, y, z) = ( + self.0.numtoa_str(10, &mut x), + self.1.numtoa_str(10, &mut y), + self.2.numtoa_str(10, &mut z), + ); + + [csi!("38;2;"), x, ";", y, ";", z, "m"].concat() + } + + /// Returns the ANSI sequence as a string. + pub fn bg_string(self) -> String { + let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]); + let (x, y, z) = ( + self.0.numtoa_str(10, &mut x), + self.1.numtoa_str(10, &mut y), + self.2.numtoa_str(10, &mut z), + ); + + [csi!("48;2;"), x, ";", y, ";", z, "m"].concat() + } +} + +impl Color for Rgb { + #[inline] + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.fg_string()) + } + + #[inline] + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&self.bg_string()) + } +} + +/// Reset colors to defaults. +#[derive(Debug, Clone, Copy)] +pub struct Reset; + +const RESET_FG: &str = csi!("39m"); +const RESET_BG: &str = csi!("49m"); + +impl Reset { + /// Returns the ANSI sequence as a string. + pub fn fg_str(self) -> &'static str { RESET_FG } + /// Returns the ANSI sequence as a string. + pub fn bg_str(self) -> &'static str { RESET_BG } +} + +impl Color for Reset { + #[inline] + fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(RESET_FG) + } + + #[inline] + fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(RESET_BG) + } +} + +/// A foreground color. +#[derive(Debug, Clone, Copy)] +pub struct Fg<C: Color>(pub C); + +impl<C: Color> fmt::Display for Fg<C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_fg(f) + } +} + +/// A background color. +#[derive(Debug, Clone, Copy)] +pub struct Bg<C: Color>(pub C); + +impl<C: Color> fmt::Display for Bg<C> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.write_bg(f) + } +} + +/// Types that allow detection of the colors they support. +pub trait DetectColors { + /// How many ANSI colors are supported (from 8 to 256)? + /// + /// Beware: the information given isn't authoritative, it's infered through escape codes or the + /// value of `TERM`, more colors may be available. + fn available_colors(&mut self) -> io::Result<u16>; +} + +impl<W: Write> DetectColors for W { + fn available_colors(&mut self) -> io::Result<u16> { + let mut stdin = async_stdin(); + + if detect_color(self, &mut stdin, 0)? { + // OSC 4 is supported, detect how many colors there are. + // Do a binary search of the last supported color. + let mut min = 8; + let mut max = 256; + let mut i; + while min + 1 < max { + i = (min + max) / 2; + if detect_color(self, &mut stdin, i)? { + min = i + } else { + max = i + } + } + Ok(max) + } else { + // OSC 4 is not supported, trust TERM contents. + Ok(match env::var_os("TERM") { + Some(val) => { + if val.to_str().unwrap_or("").contains("256color") { + 256 + } else { + 8 + } + } + None => 8, + }) + } + } +} + +/// Detect a color using OSC 4. +fn detect_color(stdout: &mut Write, stdin: &mut Read, color: u16) -> io::Result<bool> { + // Is the color available? + // Use `ESC ] 4 ; color ; ? BEL`. + write!(stdout, "\x1B]4;{};?\x07", color)?; + stdout.flush()?; + + let mut buf: [u8; 1] = [0]; + let mut total_read = 0; + + let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT); + let now = SystemTime::now(); + let bell = 7u8; + + // Either consume all data up to bell or wait for a timeout. + while buf[0] != bell && now.elapsed().unwrap() < timeout { + total_read += stdin.read(&mut buf)?; + } + + // If there was a response, the color is supported. + Ok(total_read > 0) +} diff --git a/termion/src/cursor.rs b/termion/src/cursor.rs new file mode 100644 index 000000000..bbc039406 --- /dev/null +++ b/termion/src/cursor.rs @@ -0,0 +1,222 @@ +//! Cursor movement. + +use std::fmt; +use std::ops; +use std::io::{self, Write, Error, ErrorKind, Read}; +use async::async_stdin_until; +use std::time::{SystemTime, Duration}; +use raw::CONTROL_SEQUENCE_TIMEOUT; +use numtoa::NumToA; + +derive_csi_sequence!("Hide the cursor.", Hide, "?25l"); +derive_csi_sequence!("Show the cursor.", Show, "?25h"); + +derive_csi_sequence!("Restore the cursor.", Restore, "u"); +derive_csi_sequence!("Save the cursor.", Save, "s"); + +/// Goto some position ((1,1)-based). +/// +/// # Why one-based? +/// +/// ANSI escapes are very poorly designed, and one of the many odd aspects is being one-based. This +/// can be quite strange at first, but it is not that big of an obstruction once you get used to +/// it. +/// +/// # Example +/// +/// ```rust +/// extern crate termion; +/// +/// fn main() { +/// print!("{}{}Stuff", termion::clear::All, termion::cursor::Goto(5, 3)); +/// } +/// ``` +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Goto(pub u16, pub u16); + +impl From<Goto> for String { + fn from(this: Goto) -> String { + let (mut x, mut y) = ([0u8; 20], [0u8; 20]); + ["\x1B[", this.1.numtoa_str(10, &mut x), ";", this.0.numtoa_str(10, &mut y), "H"].concat() + } +} + +impl Default for Goto { + fn default() -> Goto { + Goto(1, 1) + } +} + +impl fmt::Display for Goto { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + debug_assert!(self != &Goto(0, 0), "Goto is one-based."); + f.write_str(&String::from(*self)) + } +} + +/// Move cursor left. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Left(pub u16); + +impl From<Left> for String { + fn from(this: Left) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "D"].concat() + } +} + +impl fmt::Display for Left { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&String::from(*self)) + } +} + +/// Move cursor right. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Right(pub u16); + +impl From<Right> for String { + fn from(this: Right) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "C"].concat() + } +} + +impl fmt::Display for Right { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&String::from(*self)) + } +} + +/// Move cursor up. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Up(pub u16); + +impl From<Up> for String { + fn from(this: Up) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "A"].concat() + } +} + +impl fmt::Display for Up { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&String::from(*self)) + } +} + +/// Move cursor down. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Down(pub u16); + +impl From<Down> for String { + fn from(this: Down) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "B"].concat() + } +} + +impl fmt::Display for Down { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&String::from(*self)) + } +} + +/// Types that allow detection of the cursor position. +pub trait DetectCursorPos { + /// Get the (1,1)-based cursor position from the terminal. + fn cursor_pos(&mut self) -> io::Result<(u16, u16)>; +} + +impl<W: Write> DetectCursorPos for W { + fn cursor_pos(&mut self) -> io::Result<(u16, u16)> { + let delimiter = b'R'; + let mut stdin = async_stdin_until(delimiter); + + // Where is the cursor? + // Use `ESC [ 6 n`. + write!(self, "\x1B[6n")?; + self.flush()?; + + let mut buf: [u8; 1] = [0]; + let mut read_chars = Vec::new(); + + let timeout = Duration::from_millis(CONTROL_SEQUENCE_TIMEOUT); + let now = SystemTime::now(); + + // Either consume all data up to R or wait for a timeout. + while buf[0] != delimiter && now.elapsed().unwrap() < timeout { + if stdin.read(&mut buf)? > 0 { + read_chars.push(buf[0]); + } + } + + if read_chars.is_empty() { + return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out.")); + } + + // The answer will look like `ESC [ Cy ; Cx R`. + + read_chars.pop(); // remove trailing R. + let read_str = String::from_utf8(read_chars).unwrap(); + let beg = read_str.rfind('[').unwrap(); + let coords: String = read_str.chars().skip(beg + 1).collect(); + let mut nums = coords.split(';'); + + let cy = nums.next() + .unwrap() + .parse::<u16>() + .unwrap(); + let cx = nums.next() + .unwrap() + .parse::<u16>() + .unwrap(); + + Ok((cx, cy)) + } +} + +/// Hide the cursor for the lifetime of this struct. +/// It will hide the cursor on creation with from() and show it back on drop(). +pub struct HideCursor<W: Write> { + /// The output target. + output: W, +} + +impl<W: Write> HideCursor<W> { + /// Create a hide cursor wrapper struct for the provided output and hides the cursor. + pub fn from(mut output: W) -> Self { + write!(output, "{}", Hide).expect("hide the cursor"); + HideCursor { output: output } + } +} + +impl<W: Write> Drop for HideCursor<W> { + fn drop(&mut self) { + write!(self, "{}", Show).expect("show the cursor"); + } +} + +impl<W: Write> ops::Deref for HideCursor<W> { + type Target = W; + + fn deref(&self) -> &W { + &self.output + } +} + +impl<W: Write> ops::DerefMut for HideCursor<W> { + fn deref_mut(&mut self) -> &mut W { + &mut self.output + } +} + +impl<W: Write> Write for HideCursor<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.output.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.output.flush() + } +} diff --git a/termion/src/event.rs b/termion/src/event.rs new file mode 100644 index 000000000..6e383a1cd --- /dev/null +++ b/termion/src/event.rs @@ -0,0 +1,350 @@ +//! Mouse and key events. + +use std::io::{Error, ErrorKind}; +use std::str; + +/// An event reported by the terminal. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Event { + /// A key press. + Key(Key), + /// A mouse button press, release or wheel use at specific coordinates. + Mouse(MouseEvent), + /// An event that cannot currently be evaluated. + Unsupported(Vec<u8>), +} + +/// A mouse related event. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum MouseEvent { + /// A mouse button was pressed. + /// + /// The coordinates are one-based. + Press(MouseButton, u16, u16), + /// A mouse button was released. + /// + /// The coordinates are one-based. + Release(u16, u16), + /// A mouse button is held over the given coordinates. + /// + /// The coordinates are one-based. + Hold(u16, u16), +} + +/// A mouse button. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum MouseButton { + /// The left mouse button. + Left, + /// The right mouse button. + Right, + /// The middle mouse button. + Middle, + /// Mouse wheel is going up. + /// + /// This event is typically only used with Mouse::Press. + WheelUp, + /// Mouse wheel is going down. + /// + /// This event is typically only used with Mouse::Press. + WheelDown, +} + +/// A key. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Key { + /// Backspace. + Backspace, + /// Left arrow. + Left, + /// Right arrow. + Right, + /// Up arrow. + Up, + /// Down arrow. + Down, + /// Home key. + Home, + /// End key. + End, + /// Page Up key. + PageUp, + /// Page Down key. + PageDown, + /// Delete key. + Delete, + /// Insert key. + Insert, + /// Function keys. + /// + /// Only function keys 1 through 12 are supported. + F(u8), + /// Normal character. + Char(char), + /// Alt modified character. + Alt(char), + /// Ctrl modified character. + /// + /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals. + Ctrl(char), + /// Null byte. + Null, + /// Esc key. + Esc, + + #[doc(hidden)] + __IsNotComplete, +} + +/// Parse an Event from `item` and possibly subsequent bytes through `iter`. +pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, Error> + where I: Iterator<Item = Result<u8, Error>> +{ + let error = Error::new(ErrorKind::Other, "Could not parse an event"); + match item { + b'\x1B' => { + // This is an escape character, leading a control sequence. + Ok(match iter.next() { + Some(Ok(b'O')) => { + match iter.next() { + // F1-F4 + Some(Ok(val @ b'P'...b'S')) => Event::Key(Key::F(1 + val - b'P')), + _ => return Err(error), + } + } + Some(Ok(b'[')) => { + // This is a CSI sequence. + parse_csi(iter).ok_or(error)? + } + Some(Ok(c)) => { + let ch = parse_utf8_char(c, iter); + Event::Key(Key::Alt(try!(ch))) + } + Some(Err(_)) | None => return Err(error), + }) + } + b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))), + b'\t' => Ok(Event::Key(Key::Char('\t'))), + b'\x7F' => Ok(Event::Key(Key::Backspace)), + c @ b'\x01'...b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))), + c @ b'\x1C'...b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))), + b'\0' => Ok(Event::Key(Key::Null)), + c => { + Ok({ + let ch = parse_utf8_char(c, iter); + Event::Key(Key::Char(try!(ch))) + }) + } + } +} + +/// Parses a CSI sequence, just after reading ^[ +/// +/// Returns None if an unrecognized sequence is found. +fn parse_csi<I>(iter: &mut I) -> Option<Event> + where I: Iterator<Item = Result<u8, Error>> +{ + Some(match iter.next() { + Some(Ok(b'[')) => match iter.next() { + Some(Ok(val @ b'A'...b'E')) => Event::Key(Key::F(1 + val - b'A')), + _ => return None, + }, + Some(Ok(b'D')) => Event::Key(Key::Left), + Some(Ok(b'C')) => Event::Key(Key::Right), + Some(Ok(b'A')) => Event::Key(Key::Up), + Some(Ok(b'B')) => Event::Key(Key::Down), + Some(Ok(b'H')) => Event::Key(Key::Home), + Some(Ok(b'F')) => Event::Key(Key::End), + Some(Ok(b'M')) => { + // X10 emulation mouse encoding: ESC [ CB Cx Cy (6 characters only). + let mut next = || iter.next().unwrap().unwrap(); + + let cb = next() as i8 - 32; + // (1, 1) are the coords for upper left. + let cx = next().saturating_sub(32) as u16; + let cy = next().saturating_sub(32) as u16; + Event::Mouse(match cb & 0b11 { + 0 => { + if cb & 0x40 != 0 { + MouseEvent::Press(MouseButton::WheelUp, cx, cy) + } else { + MouseEvent::Press(MouseButton::Left, cx, cy) + } + } + 1 => { + if cb & 0x40 != 0 { + MouseEvent::Press(MouseButton::WheelDown, cx, cy) + } else { + MouseEvent::Press(MouseButton::Middle, cx, cy) + } + } + 2 => MouseEvent::Press(MouseButton::Right, cx, cy), + 3 => MouseEvent::Release(cx, cy), + _ => return None, + }) + } + Some(Ok(b'<')) => { + // xterm mouse encoding: + // ESC [ < Cb ; Cx ; Cy (;) (M or m) + let mut buf = Vec::new(); + let mut c = iter.next().unwrap().unwrap(); + while match c { + b'm' | b'M' => false, + _ => true, + } { + buf.push(c); + c = iter.next().unwrap().unwrap(); + } + let str_buf = String::from_utf8(buf).unwrap(); + let nums = &mut str_buf.split(';'); + + let cb = nums.next() + .unwrap() + .parse::<u16>() + .unwrap(); + let cx = nums.next() + .unwrap() + .parse::<u16>() + .unwrap(); + let cy = nums.next() + .unwrap() + .parse::<u16>() + .unwrap(); + + let event = match cb { + 0...2 | 64...65 => { + let button = match cb { + 0 => MouseButton::Left, + 1 => MouseButton::Middle, + 2 => MouseButton::Right, + 64 => MouseButton::WheelUp, + 65 => MouseButton::WheelDown, + _ => unreachable!(), + }; + match c { + b'M' => MouseEvent::Press(button, cx, cy), + b'm' => MouseEvent::Release(cx, cy), + _ => return None, + } + } + 32 => MouseEvent::Hold(cx, cy), + 3 => MouseEvent::Release(cx, cy), + _ => return None, + }; + + Event::Mouse(event) + } + Some(Ok(c @ b'0'...b'9')) => { + // Numbered escape code. + let mut buf = Vec::new(); + buf.push(c); + let mut c = iter.next().unwrap().unwrap(); + // The final byte of a CSI sequence can be in the range 64-126, so + // let's keep reading anything else. + while c < 64 || c > 126 { + buf.push(c); + c = iter.next().unwrap().unwrap(); + } + + match c { + // rxvt mouse encoding: + // ESC [ Cb ; Cx ; Cy ; M + b'M' => { + let str_buf = String::from_utf8(buf).unwrap(); + + let nums: Vec<u16> = str_buf.split(';').map(|n| n.parse().unwrap()).collect(); + + let cb = nums[0]; + let cx = nums[1]; + let cy = nums[2]; + + let event = match cb { + 32 => MouseEvent::Press(MouseButton::Left, cx, cy), + 33 => MouseEvent::Press(MouseButton::Middle, cx, cy), + 34 => MouseEvent::Press(MouseButton::Right, cx, cy), + 35 => MouseEvent::Release(cx, cy), + 64 => MouseEvent::Hold(cx, cy), + 96 | 97 => MouseEvent::Press(MouseButton::WheelUp, cx, cy), + _ => return None, + }; + + Event::Mouse(event) + } + // Special key code. + b'~' => { + let str_buf = String::from_utf8(buf).unwrap(); + + // This CSI sequence can be a list of semicolon-separated + // numbers. + let nums: Vec<u8> = str_buf.split(';').map(|n| n.parse().unwrap()).collect(); + + if nums.is_empty() { + return None; + } + + // TODO: handle multiple values for key modififiers (ex: values + // [3, 2] means Shift+Delete) + if nums.len() > 1 { + return None; + } + + match nums[0] { + 1 | 7 => Event::Key(Key::Home), + 2 => Event::Key(Key::Insert), + 3 => Event::Key(Key::Delete), + 4 | 8 => Event::Key(Key::End), + 5 => Event::Key(Key::PageUp), + 6 => Event::Key(Key::PageDown), + v @ 11...15 => Event::Key(Key::F(v - 10)), + v @ 17...21 => Event::Key(Key::F(v - 11)), + v @ 23...24 => Event::Key(Key::F(v - 12)), + _ => return None, + } + } + _ => return None, + } + } + _ => return None, + }) + +} + +/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char. +fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char, Error> + where I: Iterator<Item = Result<u8, Error>> +{ + let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8")); + if c.is_ascii() { + Ok(c as char) + } else { + let bytes = &mut Vec::new(); + bytes.push(c); + + loop { + match iter.next() { + Some(Ok(next)) => { + bytes.push(next); + if let Ok(st) = str::from_utf8(bytes) { + return Ok(st.chars().next().unwrap()); + } + if bytes.len() >= 4 { + return error; + } + } + _ => return error, + } + } + } +} + +#[cfg(test)] +#[test] +fn test_parse_utf8() { + let st = "abcéŷ¤£€ù%323"; + let ref mut bytes = st.bytes().map(|x| Ok(x)); + let chars = st.chars(); + for c in chars { + let b = bytes.next().unwrap().unwrap(); + assert!(c == parse_utf8_char(b, bytes).unwrap()); + } +} diff --git a/termion/src/input.rs b/termion/src/input.rs new file mode 100644 index 000000000..5c8ecf466 --- /dev/null +++ b/termion/src/input.rs @@ -0,0 +1,388 @@ +//! User input. + +use std::io::{self, Read, Write}; +use std::ops; + +use event::{self, Event, Key}; +use raw::IntoRawMode; + +/// An iterator over input keys. +pub struct Keys<R> { + iter: Events<R>, +} + +impl<R: Read> Iterator for Keys<R> { + type Item = Result<Key, io::Error>; + + fn next(&mut self) -> Option<Result<Key, io::Error>> { + loop { + match self.iter.next() { + Some(Ok(Event::Key(k))) => return Some(Ok(k)), + Some(Ok(_)) => continue, + e @ Some(Err(_)) => e, + None => return None, + }; + } + } +} + +/// An iterator over input events. +pub struct Events<R> { + inner: EventsAndRaw<R> +} + +impl<R: Read> Iterator for Events<R> { + type Item = Result<Event, io::Error>; + + fn next(&mut self) -> Option<Result<Event, io::Error>> { + self.inner.next().map(|tuple| tuple.map(|(event, _raw)| event)) + } +} + +/// An iterator over input events and the bytes that define them. +pub struct EventsAndRaw<R> { + source: R, + leftover: Option<u8>, +} + +impl<R: Read> Iterator for EventsAndRaw<R> { + type Item = Result<(Event, Vec<u8>), io::Error>; + + fn next(&mut self) -> Option<Result<(Event, Vec<u8>), io::Error>> { + let source = &mut self.source; + + if let Some(c) = self.leftover { + // we have a leftover byte, use it + self.leftover = None; + return Some(parse_event(c, &mut source.bytes())); + } + + // Here we read two bytes at a time. We need to distinguish between single ESC key presses, + // and escape sequences (which start with ESC or a x1B byte). The idea is that if this is + // an escape sequence, we will read multiple bytes (the first byte being ESC) but if this + // is a single ESC keypress, we will only read a single byte. + let mut buf = [0u8; 2]; + let res = match source.read(&mut buf) { + Ok(0) => return None, + Ok(1) => { + match buf[0] { + b'\x1B' => Ok((Event::Key(Key::Esc), vec![b'\x1B'])), + c => parse_event(c, &mut source.bytes()), + } + } + Ok(2) => { + let mut option_iter = &mut Some(buf[1]).into_iter(); + let result = { + let mut iter = option_iter.map(|c| Ok(c)).chain(source.bytes()); + parse_event(buf[0], &mut iter) + }; + // If the option_iter wasn't consumed, keep the byte for later. + self.leftover = option_iter.next(); + result + } + Ok(_) => unreachable!(), + Err(e) => Err(e), + }; + + Some(res) + } +} + +fn parse_event<I>(item: u8, iter: &mut I) -> Result<(Event, Vec<u8>), io::Error> + where I: Iterator<Item = Result<u8, io::Error>> +{ + let mut buf = vec![item]; + let result = { + let mut iter = iter.inspect(|byte| if let &Ok(byte) = byte { + buf.push(byte); + }); + event::parse_event(item, &mut iter) + }; + result.or(Ok(Event::Unsupported(buf.clone()))).map(|e| (e, buf)) +} + + +/// Extension to `Read` trait. +pub trait TermRead { + /// An iterator over input events. + fn events(self) -> Events<Self> where Self: Sized; + + /// An iterator over key inputs. + fn keys(self) -> Keys<Self> where Self: Sized; + + /// Read a line. + /// + /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will + /// complete the input. + fn read_line(&mut self) -> io::Result<Option<String>>; + + /// Read a password. + /// + /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will + /// complete the input. + fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> { + let _raw = try!(writer.into_raw_mode()); + self.read_line() + } +} + + +impl<R: Read + TermReadEventsAndRaw> TermRead for R { + fn events(self) -> Events<Self> { + Events { + inner: self.events_and_raw() + } + } + fn keys(self) -> Keys<Self> { + Keys { iter: self.events() } + } + + fn read_line(&mut self) -> io::Result<Option<String>> { + let mut buf = Vec::with_capacity(30); + + for c in self.bytes() { + match c { + Err(e) => return Err(e), + Ok(0) | Ok(3) | Ok(4) => return Ok(None), + Ok(0x7f) => { + buf.pop(); + } + Ok(b'\n') | Ok(b'\r') => break, + Ok(c) => buf.push(c), + } + } + + let string = try!(String::from_utf8(buf) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))); + Ok(Some(string)) + } +} + +/// Extension to `TermRead` trait. A separate trait in order to maintain backwards compatibility. +pub trait TermReadEventsAndRaw { + /// An iterator over input events and the bytes that define them. + fn events_and_raw(self) -> EventsAndRaw<Self> where Self: Sized; +} + +impl<R: Read> TermReadEventsAndRaw for R { + fn events_and_raw(self) -> EventsAndRaw<Self> { + EventsAndRaw { + source: self, + leftover: None, + } + } +} + +/// A sequence of escape codes to enable terminal mouse support. +const ENTER_MOUSE_SEQUENCE: &'static str = csi!("?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"); + +/// A sequence of escape codes to disable terminal mouse support. +const EXIT_MOUSE_SEQUENCE: &'static str = csi!("?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"); + +/// A terminal with added mouse support. +/// +/// This can be obtained through the `From` implementations. +pub struct MouseTerminal<W: Write> { + term: W, +} + +impl<W: Write> From<W> for MouseTerminal<W> { + fn from(mut from: W) -> MouseTerminal<W> { + from.write_all(ENTER_MOUSE_SEQUENCE.as_bytes()).unwrap(); + + MouseTerminal { term: from } + } +} + +impl<W: Write> Drop for MouseTerminal<W> { + fn drop(&mut self) { + self.term.write_all(EXIT_MOUSE_SEQUENCE.as_bytes()).unwrap(); + } +} + +impl<W: Write> ops::Deref for MouseTerminal<W> { + type Target = W; + + fn deref(&self) -> &W { + &self.term + } +} + +impl<W: Write> ops::DerefMut for MouseTerminal<W> { + fn deref_mut(&mut self) -> &mut W { + &mut self.term + } +} + +impl<W: Write> Write for MouseTerminal<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.term.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.term.flush() + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io; + use event::{Key, Event, MouseEvent, MouseButton}; + + #[test] + fn test_keys() { + let mut i = b"\x1Bayo\x7F\x1B[D".keys(); + + assert_eq!(i.next().unwrap().unwrap(), Key::Alt('a')); + assert_eq!(i.next().unwrap().unwrap(), Key::Char('y')); + assert_eq!(i.next().unwrap().unwrap(), Key::Char('o')); + assert_eq!(i.next().unwrap().unwrap(), Key::Backspace); + assert_eq!(i.next().unwrap().unwrap(), Key::Left); + assert!(i.next().is_none()); + } + + #[test] + fn test_events() { + let mut i = + b"\x1B[\x00bc\x7F\x1B[D\ + \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb" + .events(); + + assert_eq!(i.next().unwrap().unwrap(), + Event::Unsupported(vec![0x1B, b'[', 0x00])); + assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b'))); + assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('c'))); + assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Backspace)); + assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Left)); + assert_eq!(i.next().unwrap().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, 2, 4))); + assert_eq!(i.next().unwrap().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4))); + assert_eq!(i.next().unwrap().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4))); + assert_eq!(i.next().unwrap().unwrap(), + Event::Mouse(MouseEvent::Release(2, 4))); + assert_eq!(i.next().unwrap().unwrap(), + Event::Mouse(MouseEvent::Release(2, 4))); + assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b'))); + assert!(i.next().is_none()); + } + + #[test] + fn test_events_and_raw() { + let input = b"\x1B[\x00bc\x7F\x1B[D\ + \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb"; + let mut output = Vec::<u8>::new(); + { + let mut i = input.events_and_raw().map(|res| res.unwrap()) + .inspect(|&(_, ref raw)| { output.extend(raw); }).map(|(event, _)| event); + + assert_eq!(i.next().unwrap(), + Event::Unsupported(vec![0x1B, b'[', 0x00])); + assert_eq!(i.next().unwrap(), Event::Key(Key::Char('b'))); + assert_eq!(i.next().unwrap(), Event::Key(Key::Char('c'))); + assert_eq!(i.next().unwrap(), Event::Key(Key::Backspace)); + assert_eq!(i.next().unwrap(), Event::Key(Key::Left)); + assert_eq!(i.next().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, 2, 4))); + assert_eq!(i.next().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4))); + assert_eq!(i.next().unwrap(), + Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4))); + assert_eq!(i.next().unwrap(), + Event::Mouse(MouseEvent::Release(2, 4))); + assert_eq!(i.next().unwrap(), + Event::Mouse(MouseEvent::Release(2, 4))); + assert_eq!(i.next().unwrap(), Event::Key(Key::Char('b'))); + assert!(i.next().is_none()); + } + + assert_eq!(input.iter().map(|b| *b).collect::<Vec<u8>>(), output) + } + + #[test] + fn test_function_keys() { + let mut st = b"\x1BOP\x1BOQ\x1BOR\x1BOS".keys(); + for i in 1..5 { + assert_eq!(st.next().unwrap().unwrap(), Key::F(i)); + } + + let mut st = b"\x1B[11~\x1B[12~\x1B[13~\x1B[14~\x1B[15~\ + \x1B[17~\x1B[18~\x1B[19~\x1B[20~\x1B[21~\x1B[23~\x1B[24~" + .keys(); + for i in 1..13 { + assert_eq!(st.next().unwrap().unwrap(), Key::F(i)); + } + } + + #[test] + fn test_special_keys() { + let mut st = b"\x1B[2~\x1B[H\x1B[7~\x1B[5~\x1B[3~\x1B[F\x1B[8~\x1B[6~".keys(); + assert_eq!(st.next().unwrap().unwrap(), Key::Insert); + assert_eq!(st.next().unwrap().unwrap(), Key::Home); + assert_eq!(st.next().unwrap().unwrap(), Key::Home); + assert_eq!(st.next().unwrap().unwrap(), Key::PageUp); + assert_eq!(st.next().unwrap().unwrap(), Key::Delete); + assert_eq!(st.next().unwrap().unwrap(), Key::End); + assert_eq!(st.next().unwrap().unwrap(), Key::End); + assert_eq!(st.next().unwrap().unwrap(), Key::PageDown); + assert!(st.next().is_none()); + } + + #[test] + fn test_esc_key() { + let mut st = b"\x1B".keys(); + assert_eq!(st.next().unwrap().unwrap(), Key::Esc); + assert!(st.next().is_none()); + } + + fn line_match(a: &str, b: Option<&str>) { + let mut sink = io::sink(); + + let line = a.as_bytes().read_line().unwrap(); + let pass = a.as_bytes().read_passwd(&mut sink).unwrap(); + + // godammit rustc + + assert_eq!(line, pass); + + if let Some(l) = line { + assert_eq!(Some(l.as_str()), b); + } else { + assert!(b.is_none()); + } + } + + #[test] + fn test_read() { + let test1 = "this is the first test"; + let test2 = "this is the second test"; + + line_match(test1, Some(test1)); + line_match(test2, Some(test2)); + } + + #[test] + fn test_backspace() { + line_match("this is the\x7f first\x7f\x7f test", + Some("this is th fir test")); + line_match("this is the seco\x7fnd test\x7f", + Some("this is the secnd tes")); + } + + #[test] + fn test_end() { + line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ", + Some("abc")); + line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA", + Some("hello")); + } + + #[test] + fn test_abort() { + line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None); + line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None); + } + +} diff --git a/termion/src/lib.rs b/termion/src/lib.rs new file mode 100644 index 000000000..24917ad76 --- /dev/null +++ b/termion/src/lib.rs @@ -0,0 +1,63 @@ +//! Termion is a pure Rust, bindless library for low-level handling, manipulating +//! and reading information about terminals. This provides a full-featured +//! alternative to Termbox. +//! +//! Termion aims to be simple and yet expressive. It is bindless, meaning that it +//! is not a front-end to some other library (e.g., ncurses or termbox), but a +//! standalone library directly talking to the TTY. +//! +//! Supports Redox, Mac OS X, and Linux (or, in general, ANSI terminals). +//! +//! For more information refer to the [README](https://github.com/redox-os/termion). +#![warn(missing_docs)] + +extern crate numtoa; + +#[cfg(target_os = "redox")] +#[path="sys/redox/mod.rs"] +mod sys; + +#[cfg(all(unix, not(target_os = "redox")))] +#[path="sys/unix/mod.rs"] +mod sys; + +pub use sys::size::terminal_size; +pub use sys::tty::{is_tty, get_tty}; + +mod async; +pub use async::{AsyncReader, async_stdin}; + +#[macro_use] +mod macros; +pub mod clear; +pub mod color; +pub mod cursor; +pub mod event; +pub mod input; +pub mod raw; +pub mod screen; +pub mod scroll; +pub mod style; + +#[cfg(test)] +mod test { + use super::sys; + + #[test] + fn test_get_terminal_attr() { + sys::attr::get_terminal_attr().unwrap(); + sys::attr::get_terminal_attr().unwrap(); + sys::attr::get_terminal_attr().unwrap(); + } + + #[test] + fn test_set_terminal_attr() { + let ios = sys::attr::get_terminal_attr().unwrap(); + sys::attr::set_terminal_attr(&ios).unwrap(); + } + + #[test] + fn test_size() { + sys::size::terminal_size().unwrap(); + } +} diff --git a/termion/src/macros.rs b/termion/src/macros.rs new file mode 100644 index 000000000..5fd70b933 --- /dev/null +++ b/termion/src/macros.rs @@ -0,0 +1,27 @@ +/// Create a CSI-introduced sequence. +macro_rules! csi { + ($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) }; +} + +/// Derive a CSI sequence struct. +macro_rules! derive_csi_sequence { + ($doc:expr, $name:ident, $value:expr) => { + #[doc = $doc] + #[derive(Copy, Clone)] + pub struct $name; + + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, csi!($value)) + } + } + + impl AsRef<[u8]> for $name { + fn as_ref(&self) -> &'static [u8] { csi!($value).as_bytes() } + } + + impl AsRef<str> for $name { + fn as_ref(&self) -> &'static str { csi!($value) } + } + }; +} diff --git a/termion/src/raw.rs b/termion/src/raw.rs new file mode 100644 index 000000000..0dbfb569e --- /dev/null +++ b/termion/src/raw.rs @@ -0,0 +1,131 @@ +//! Managing raw mode. +//! +//! Raw mode is a particular state a TTY can have. It signifies that: +//! +//! 1. No line buffering (the input is given byte-by-byte). +//! 2. The input is not written out, instead it has to be done manually by the programmer. +//! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line +//! break"). +//! +//! It is essential to design terminal programs. +//! +//! # Example +//! +//! ```rust,no_run +//! use termion::raw::IntoRawMode; +//! use std::io::{Write, stdout}; +//! +//! fn main() { +//! let mut stdout = stdout().into_raw_mode().unwrap(); +//! +//! write!(stdout, "Hey there.").unwrap(); +//! } +//! ``` + +use std::io::{self, Write}; +use std::ops; + +use sys::Termios; +use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr}; + +/// The timeout of an escape code control sequence, in milliseconds. +pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100; + +/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when +/// dropped. +/// +/// Restoring will entirely bring back the old TTY state. +pub struct RawTerminal<W: Write> { + prev_ios: Termios, + output: W, +} + +impl<W: Write> Drop for RawTerminal<W> { + fn drop(&mut self) { + set_terminal_attr(&self.prev_ios).unwrap(); + } +} + +impl<W: Write> ops::Deref for RawTerminal<W> { + type Target = W; + + fn deref(&self) -> &W { + &self.output + } +} + +impl<W: Write> ops::DerefMut for RawTerminal<W> { + fn deref_mut(&mut self) -> &mut W { + &mut self.output + } +} + +impl<W: Write> Write for RawTerminal<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.output.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.output.flush() + } +} + +/// Types which can be converted into "raw mode". +/// +/// # Why is this type defined on writers and not readers? +/// +/// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the +/// screen, move the cursor and so on, so naturally you use the writer to change the mode as well. +pub trait IntoRawMode: Write + Sized { + /// Switch to raw mode. + /// + /// Raw mode means that stdin won't be printed (it will instead have to be written manually by + /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can + /// read from stdin one byte of a time). The output is neither modified in any way. + fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>; +} + +impl<W: Write> IntoRawMode for W { + fn into_raw_mode(self) -> io::Result<RawTerminal<W>> { + let mut ios = get_terminal_attr()?; + let prev_ios = ios; + + raw_terminal_attr(&mut ios); + + set_terminal_attr(&ios)?; + + Ok(RawTerminal { + prev_ios: prev_ios, + output: self, + }) + } +} + +impl<W: Write> RawTerminal<W> { + pub fn suspend_raw_mode(&self) -> io::Result<()> { + set_terminal_attr(&self.prev_ios)?; + Ok(()) + } + + pub fn activate_raw_mode(&self) -> io::Result<()> { + let mut ios = get_terminal_attr()?; + raw_terminal_attr(&mut ios); + set_terminal_attr(&ios)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::{Write, stdout}; + + #[test] + fn test_into_raw_mode() { + let mut out = stdout().into_raw_mode().unwrap(); + + out.write_all(b"this is a test, muahhahahah\r\n").unwrap(); + + drop(out); + } +} diff --git a/termion/src/screen.rs b/termion/src/screen.rs new file mode 100644 index 000000000..822399e27 --- /dev/null +++ b/termion/src/screen.rs @@ -0,0 +1,91 @@ +//! Managing switching between main and alternate screen buffers. +//! +//! Note that this implementation uses xterm's new escape sequences for screen switching and thus +//! only works for xterm compatible terminals (which should be most terminals nowadays). +//! +//! # Example +//! +//! ```rust +//! use termion::screen::AlternateScreen; +//! use std::io::{Write, stdout}; +//! +//! fn main() { +//! { +//! let mut screen = AlternateScreen::from(stdout()); +//! write!(screen, "Writing to alternate screen!").unwrap(); +//! screen.flush().unwrap(); +//! } +//! println!("Writing to main screen."); +//! } +//! ``` + +use std::io::{self, Write}; +use std::ops; +use std::fmt; + +/// Switch to the main screen buffer of the terminal. +pub struct ToMainScreen; + +impl fmt::Display for ToMainScreen { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, csi!("?1049l")) + } +} + +/// Switch to the alternate screen buffer of the terminal. +pub struct ToAlternateScreen; + +impl fmt::Display for ToAlternateScreen { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, csi!("?1049h")) + } +} + +/// A terminal restorer, which wraps a type implementing Write, and causes all writes to be written +/// to an alternate screen. +/// +/// This is achieved by switching the terminal to the alternate screen on creation and +/// automatically switching it back to the original screen on drop. +pub struct AlternateScreen<W: Write> { + /// The output target. + output: W, +} + +impl<W: Write> AlternateScreen<W> { + /// Create an alternate screen wrapper struct for the provided output and switch the terminal + /// to the alternate screen. + pub fn from(mut output: W) -> Self { + write!(output, "{}", ToAlternateScreen).expect("switch to alternate screen"); + AlternateScreen { output: output } + } +} + +impl<W: Write> Drop for AlternateScreen<W> { + fn drop(&mut self) { + write!(self, "{}", ToMainScreen).expect("switch to main screen"); + } +} + +impl<W: Write> ops::Deref for AlternateScreen<W> { + type Target = W; + + fn deref(&self) -> &W { + &self.output + } +} + +impl<W: Write> ops::DerefMut for AlternateScreen<W> { + fn deref_mut(&mut self) -> &mut W { + &mut self.output + } +} + +impl<W: Write> Write for AlternateScreen<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.output.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.output.flush() + } +} diff --git a/termion/src/scroll.rs b/termion/src/scroll.rs new file mode 100644 index 000000000..2744507f3 --- /dev/null +++ b/termion/src/scroll.rs @@ -0,0 +1,23 @@ +//! Scrolling. + +use std::fmt; + +/// Scroll up. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Up(pub u16); + +impl fmt::Display for Up { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, csi!("{}S"), self.0) + } +} + +/// Scroll down. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Down(pub u16); + +impl fmt::Display for Down { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, csi!("{}T"), self.0) + } +} diff --git a/termion/src/style.rs b/termion/src/style.rs new file mode 100644 index 000000000..58e9a78b8 --- /dev/null +++ b/termion/src/style.rs @@ -0,0 +1,22 @@ +//! Text styling management. + +use std::fmt; + +derive_csi_sequence!("Reset SGR parameters.", Reset, "m"); +derive_csi_sequence!("Bold text.", Bold, "1m"); +derive_csi_sequence!("Fainted text (not widely supported).", Faint, "2m"); +derive_csi_sequence!("Italic text.", Italic, "3m"); +derive_csi_sequence!("Underlined text.", Underline, "4m"); +derive_csi_sequence!("Blinking text (not widely supported).", Blink, "5m"); +derive_csi_sequence!("Inverted colors (negative mode).", Invert, "7m"); +derive_csi_sequence!("Crossed out text (not widely supported).", CrossedOut, "9m"); +derive_csi_sequence!("Undo bold text.", NoBold, "21m"); +derive_csi_sequence!("Undo fainted text (not widely supported).", NoFaint, "22m"); +derive_csi_sequence!("Undo italic text.", NoItalic, "23m"); +derive_csi_sequence!("Undo underlined text.", NoUnderline, "24m"); +derive_csi_sequence!("Undo blinking text (not widely supported).", NoBlink, "25m"); +derive_csi_sequence!("Undo inverted colors (negative mode).", NoInvert, "27m"); +derive_csi_sequence!("Undo crossed out text (not widely supported).", + NoCrossedOut, + "29m"); +derive_csi_sequence!("Framed text (not widely supported).", Framed, "51m"); diff --git a/termion/src/sys/redox/attr.rs b/termion/src/sys/redox/attr.rs new file mode 100644 index 000000000..c6489a510 --- /dev/null +++ b/termion/src/sys/redox/attr.rs @@ -0,0 +1,33 @@ +use std::io; + +use super::{cvt, syscall, Termios}; + +pub fn get_terminal_attr() -> io::Result<Termios> { + let mut termios = Termios::default(); + + let fd = cvt(syscall::dup(0, b"termios"))?; + let res = cvt(syscall::read(fd, &mut termios)); + let _ = syscall::close(fd); + + if res? == termios.len() { + Ok(termios) + } else { + Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal attributes.")) + } +} + +pub fn set_terminal_attr(termios: &Termios) -> io::Result<()> { + let fd = cvt(syscall::dup(0, b"termios"))?; + let res = cvt(syscall::write(fd, termios)); + let _ = syscall::close(fd); + + if res? == termios.len() { + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::Other, "Unable to set the terminal attributes.")) + } +} + +pub fn raw_terminal_attr(ios: &mut Termios) { + ios.make_raw() +} diff --git a/termion/src/sys/redox/mod.rs b/termion/src/sys/redox/mod.rs new file mode 100644 index 000000000..2a9b875e3 --- /dev/null +++ b/termion/src/sys/redox/mod.rs @@ -0,0 +1,15 @@ +extern crate redox_termios; +extern crate syscall; + +use std::io; + +pub use self::redox_termios::Termios; + +pub mod attr; +pub mod size; +pub mod tty; + +// Support function for converting syscall error to io error +fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> { + result.map_err(|err| io::Error::from_raw_os_error(err.errno)) +} diff --git a/termion/src/sys/redox/size.rs b/termion/src/sys/redox/size.rs new file mode 100644 index 000000000..07f64a243 --- /dev/null +++ b/termion/src/sys/redox/size.rs @@ -0,0 +1,18 @@ +use std::io; + +use super::{cvt, redox_termios, syscall}; + +/// Get the size of the terminal. +pub fn terminal_size() -> io::Result<(u16, u16)> { + let mut winsize = redox_termios::Winsize::default(); + + let fd = cvt(syscall::dup(1, b"winsize"))?; + let res = cvt(syscall::read(fd, &mut winsize)); + let _ = syscall::close(fd); + + if res? == winsize.len() { + Ok((winsize.ws_col, winsize.ws_row)) + } else { + Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal size.")) + } +} diff --git a/termion/src/sys/redox/tty.rs b/termion/src/sys/redox/tty.rs new file mode 100644 index 000000000..8e21ff8e5 --- /dev/null +++ b/termion/src/sys/redox/tty.rs @@ -0,0 +1,22 @@ +use std::{env, fs, io}; +use std::os::unix::io::AsRawFd; + +use super::syscall; + +/// Is this stream a TTY? +pub fn is_tty<T: AsRawFd>(stream: &T) -> bool { + if let Ok(fd) = syscall::dup(stream.as_raw_fd() as _, b"termios") { + let _ = syscall::close(fd); + true + } else { + false + } +} + +/// Get the TTY device. +/// +/// This allows for getting stdio representing _only_ the TTY, and not other streams. +pub fn get_tty() -> io::Result<fs::File> { + let tty = try!(env::var("TTY").map_err(|x| io::Error::new(io::ErrorKind::NotFound, x))); + fs::OpenOptions::new().read(true).write(true).open(tty) +} diff --git a/termion/src/sys/unix/attr.rs b/termion/src/sys/unix/attr.rs new file mode 100644 index 000000000..5e21fbac8 --- /dev/null +++ b/termion/src/sys/unix/attr.rs @@ -0,0 +1,29 @@ +use std::{io, mem}; + +use super::{cvt, Termios}; +use super::libc::c_int; + +pub fn get_terminal_attr() -> io::Result<Termios> { + extern "C" { + pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int; + } + unsafe { + let mut termios = mem::zeroed(); + cvt(tcgetattr(0, &mut termios))?; + Ok(termios) + } +} + +pub fn set_terminal_attr(termios: &Termios) -> io::Result<()> { + extern "C" { + pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *const Termios) -> c_int; + } + cvt(unsafe { tcsetattr(0, 0, termios) }).and(Ok(())) +} + +pub fn raw_terminal_attr(termios: &mut Termios) { + extern "C" { + pub fn cfmakeraw(termptr: *mut Termios); + } + unsafe { cfmakeraw(termios) } +} diff --git a/termion/src/sys/unix/mod.rs b/termion/src/sys/unix/mod.rs new file mode 100644 index 000000000..08d73feb1 --- /dev/null +++ b/termion/src/sys/unix/mod.rs @@ -0,0 +1,33 @@ +extern crate libc; + +use std::io; + +pub use self::libc::termios as Termios; + +pub mod attr; +pub mod size; +pub mod tty; + +// Support functions for converting libc return values to io errors { +trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) + } + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { + if t.is_minus_one() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} +// } End of support functions diff --git a/termion/src/sys/unix/size.rs b/termion/src/sys/unix/size.rs new file mode 100644 index 000000000..17f2515ae --- /dev/null +++ b/termion/src/sys/unix/size.rs @@ -0,0 +1,20 @@ +use std::{io, mem}; + +use super::cvt; +use super::libc::{c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ}; + +#[repr(C)] +struct TermSize { + row: c_ushort, + col: c_ushort, + _x: c_ushort, + _y: c_ushort, +} +/// Get the size of the terminal. +pub fn terminal_size() -> io::Result<(u16, u16)> { + unsafe { + let mut size: TermSize = mem::zeroed(); + cvt(ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &mut size as *mut _))?; + Ok((size.col as u16, size.row as u16)) + } +} diff --git a/termion/src/sys/unix/tty.rs b/termion/src/sys/unix/tty.rs new file mode 100644 index 000000000..2be936347 --- /dev/null +++ b/termion/src/sys/unix/tty.rs @@ -0,0 +1,17 @@ +use std::{fs, io}; +use std::os::unix::io::AsRawFd; + +use super::libc; + + +/// Is this stream a TTY? +pub fn is_tty<T: AsRawFd>(stream: &T) -> bool { + unsafe { libc::isatty(stream.as_raw_fd()) == 1 } +} + +/// Get the TTY device. +/// +/// This allows for getting stdio representing _only_ the TTY, and not other streams. +pub fn get_tty() -> io::Result<fs::File> { + fs::OpenOptions::new().read(true).write(true).open("/dev/tty") +} diff --git a/textwrap/.cargo-checksum.json b/textwrap/.cargo-checksum.json new file mode 100644 index 000000000..361de24b7 --- /dev/null +++ b/textwrap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"} \ No newline at end of file diff --git a/textwrap/Cargo.toml b/textwrap/Cargo.toml new file mode 100644 index 000000000..4ec570f10 --- /dev/null +++ b/textwrap/Cargo.toml @@ -0,0 +1,56 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "textwrap" +version = "0.11.0" +authors = ["Martin Geisler <martin@geisler.net>"] +exclude = [".dir-locals.el"] +description = "Textwrap is a small library for word wrapping, indenting, and\ndedenting strings.\n\nYou can use it to format strings (such as help and error messages) for\ndisplay in commandline applications. It is designed to be efficient\nand handle Unicode characters correctly.\n" +documentation = "https://docs.rs/textwrap/" +readme = "README.md" +keywords = ["text", "formatting", "wrap", "typesetting", "hyphenation"] +categories = ["text-processing", "command-line-interface"] +license = "MIT" +repository = "https://github.com/mgeisler/textwrap" +[package.metadata.docs.rs] +all-features = true +[dependencies.hyphenation] +version = "0.7.1" +features = ["embed_all"] +optional = true + +[dependencies.term_size] +version = "0.3.0" +optional = true + +[dependencies.unicode-width] +version = "0.1.3" +[dev-dependencies.lipsum] +version = "0.6" + +[dev-dependencies.rand] +version = "0.6" + +[dev-dependencies.rand_xorshift] +version = "0.1" + +[dev-dependencies.version-sync] +version = "0.6" +[badges.appveyor] +repository = "mgeisler/textwrap" + +[badges.codecov] +repository = "mgeisler/textwrap" + +[badges.travis-ci] +repository = "mgeisler/textwrap" diff --git a/textwrap/LICENSE b/textwrap/LICENSE new file mode 100644 index 000000000..0d37ec389 --- /dev/null +++ b/textwrap/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Martin Geisler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/textwrap/README.md b/textwrap/README.md new file mode 100644 index 000000000..23a543904 --- /dev/null +++ b/textwrap/README.md @@ -0,0 +1,337 @@ +# Textwrap + +[![](https://img.shields.io/crates/v/textwrap.svg)][crates-io] +[![](https://docs.rs/textwrap/badge.svg)][api-docs] +[![](https://travis-ci.org/mgeisler/textwrap.svg?branch=master)][travis-ci] +[![](https://ci.appveyor.com/api/projects/status/github/mgeisler/textwrap?branch=master&svg=true)][appveyor] +[![](https://codecov.io/gh/mgeisler/textwrap/branch/master/graph/badge.svg)][codecov] + +Textwrap is a small Rust crate for word wrapping text. You can use it +to format strings for display in commandline applications. The crate +name and interface is inspired by +the [Python textwrap module][py-textwrap]. + +## Usage + +Add this to your `Cargo.toml`: +```toml +[dependencies] +textwrap = "0.11" +``` + +and this to your crate root: +```rust +extern crate textwrap; +``` + +If you would like to have automatic hyphenation, specify the +dependency as: +```toml +[dependencies] +textwrap = { version = "0.11", features = ["hyphenation"] } +``` + +To conveniently wrap text at the current terminal width, enable the +`term_size` feature: + +```toml +[dependencies] +textwrap = { version = "0.11", features = ["term_size"] } +``` + +## Documentation + +**[API documentation][api-docs]** + +## Getting Started + +Word wrapping single strings is easy using the `fill` function: +```rust +extern crate textwrap; +use textwrap::fill; + +fn main() { + let text = "textwrap: a small library for wrapping text."; + println!("{}", fill(text, 18)); +} +``` +The output is +``` +textwrap: a small +library for +wrapping text. +``` + +With the `hyphenation` feature, you can get automatic hyphenation +for [about 70 languages][patterns]. Your program must load and +configure the hyphenation patterns to use: +```rust +extern crate hyphenation; +extern crate textwrap; + +use hyphenation::{Language, Load, Standard}; +use textwrap::Wrapper; + +fn main() { + let hyphenator = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(18, hyphenator); + let text = "textwrap: a small library for wrapping text."; + println!("{}", wrapper.fill(text)) +} +``` + +The output now looks like this: +``` +textwrap: a small +library for wrap- +ping text. +``` + +The hyphenation uses high-quality TeX hyphenation patterns. + +## Examples + +The library comes with some small example programs that shows various +features. + +### Layout Example + +The `layout` example shows how a fixed example string is wrapped at +different widths. Run the example with: + +```shell +$ cargo run --features hyphenation --example layout +``` + +The program will use the following string: + +> Memory safety without garbage collection. Concurrency without data +> races. Zero-cost abstractions. + +The string is wrapped at all widths between 15 and 60 columns. With +narrow columns the output looks like this: + +``` +.--- Width: 15 ---. +| Memory safety | +| without garbage | +| collection. | +| Concurrency | +| without data | +| races. Zero- | +| cost abstrac- | +| tions. | +.--- Width: 16 ----. +| Memory safety | +| without garbage | +| collection. Con- | +| currency without | +| data races. Ze- | +| ro-cost abstrac- | +| tions. | +``` + +Later, longer lines are used and the output now looks like this: + +``` +.-------------------- Width: 49 --------------------. +| Memory safety without garbage collection. Concur- | +| rency without data races. Zero-cost abstractions. | +.---------------------- Width: 53 ----------------------. +| Memory safety without garbage collection. Concurrency | +| without data races. Zero-cost abstractions. | +.------------------------- Width: 59 -------------------------. +| Memory safety without garbage collection. Concurrency with- | +| out data races. Zero-cost abstractions. | +``` + +Notice how words are split at hyphens (such as "zero-cost") but also +how words are hyphenated using automatic/machine hyphenation. + +### Terminal Width Example + +The `termwidth` example simply shows how the width can be set +automatically to the current terminal width. Run it with this command: + +``` +$ cargo run --example termwidth +``` + +If you run it in a narrow terminal, you'll see output like this: +``` +Formatted in within 60 columns: +---- +Memory safety without garbage collection. Concurrency +without data races. Zero-cost abstractions. +---- +``` + +If `stdout` is not connected to the terminal, the program will use a +default of 80 columns for the width: + +``` +$ cargo run --example termwidth | cat +Formatted in within 80 columns: +---- +Memory safety without garbage collection. Concurrency without data races. Zero- +cost abstractions. +---- +``` + +## Release History + +This section lists the largest changes per release. + +### Version 0.11.0 — December 9th, 2018 + +Due to our dependencies bumping their minimum supported version of +Rust, the minimum version of Rust we test against is now 1.22.0. + +* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and + trailing newlines. Thanks @bbqsrc! +* Fixed [#151][issue-151]: Release of version with hyphenation 0.7. + +### Version 0.10.0 — April 28th, 2018 + +Due to our dependencies bumping their minimum supported version of +Rust, the minimum version of Rust we test against is now 1.17.0. + +* Fixed [#99][issue-99]: Word broken even though it would fit on line. +* Fixed [#107][issue-107]: Automatic hyphenation is off by one. +* Fixed [#122][issue-122]: Take newlines into account when wrapping. +* Fixed [#129][issue-129]: Panic on string with em-dash. + +### Version 0.9.0 — October 5th, 2017 + +The dependency on `term_size` is now optional, and by default this +feature is not enabled. This is a *breaking change* for users of +`Wrapper::with_termwidth`. Enable the `term_size` feature to restore +the old functionality. + +Added a regression test for the case where `width` is set to +`usize::MAX`, thanks @Fraser999! All public structs now implement +`Debug`, thanks @hcpl! + +* Fixed [#101][issue-101]: Make `term_size` an optional dependency. + +### Version 0.8.0 — September 4th, 2017 + +The `Wrapper` stuct is now generic over the type of word splitter +being used. This means less boxing and a nicer API. The +`Wrapper::word_splitter` method has been removed. This is a *breaking +API change* if you used the method to change the word splitter. + +The `Wrapper` struct has two new methods that will wrap the input text +lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those +if you will be iterating over the wrapped lines one by one. + +* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks + @hcpl! +* Fixed [#81][issue-81]: Set `html_root_url`. + +### Version 0.7.0 — July 20th, 2017 + +Version 0.7.0 changes the return type of `Wrapper::wrap` from +`Vec<String>` to `Vec<Cow<'a, str>>`. This means that the output lines +borrow data from the input string. This is a *breaking API change* if +you relied on the exact return type of `Wrapper::wrap`. Callers of the +`textwrap::fill` convenience function will see no breakage. + +The above change and other optimizations makes version 0.7.0 roughly +15-30% faster than version 0.6.0. + +The `squeeze_whitespace` option has been removed since it was +complicating the above optimization. Let us know if this option is +important for you so we can provide a work around. + +* Fixed [#58][issue-58]: Add a "fast_wrap" function. +* Fixed [#61][issue-61]: Documentation errors. + +### Version 0.6.0 — May 22nd, 2017 + +Version 0.6.0 adds builder methods to `Wrapper` for easy one-line +initialization and configuration: + +```rust +let wrapper = Wrapper::new(60).break_words(false); +``` + +It also add a new `NoHyphenation` word splitter that will never split +words, not even at existing hyphens. + +* Fixed [#28][issue-28]: Support not squeezing whitespace. + +### Version 0.5.0 — May 15th, 2017 + +Version 0.5.0 has *breaking API changes*. However, this only affects +code using the hyphenation feature. The feature is now optional, so +you will first need to enable the `hyphenation` feature as described +above. Afterwards, please change your code from +```rust +wrapper.corpus = Some(&corpus); +``` +to +```rust +wrapper.splitter = Box::new(corpus); +``` + +Other changes include optimizations, so version 0.5.0 is roughly +10-15% faster than version 0.4.0. + +* Fixed [#19][issue-19]: Add support for finding terminal size. +* Fixed [#25][issue-25]: Handle words longer than `self.width`. +* Fixed [#26][issue-26]: Support custom indentation. +* Fixed [#36][issue-36]: Support building without `hyphenation`. +* Fixed [#39][issue-39]: Respect non-breaking spaces. + +### Version 0.4.0 — January 24th, 2017 + +Documented complexities and tested these via `cargo bench`. + +* Fixed [#13][issue-13]: Immediatedly add word if it fits. +* Fixed [#14][issue-14]: Avoid splitting on initial hyphens. + +### Version 0.3.0 — January 7th, 2017 + +Added support for automatic hyphenation. + +### Version 0.2.0 — December 28th, 2016 + +Introduced `Wrapper` struct. Added support for wrapping on hyphens. + +### Version 0.1.0 — December 17th, 2016 + +First public release with support for wrapping strings on whitespace. + +## License + +Textwrap can be distributed according to the [MIT license][mit]. +Contributions will be accepted under the same license. + +[crates-io]: https://crates.io/crates/textwrap +[travis-ci]: https://travis-ci.org/mgeisler/textwrap +[appveyor]: https://ci.appveyor.com/project/mgeisler/textwrap +[codecov]: https://codecov.io/gh/mgeisler/textwrap +[py-textwrap]: https://docs.python.org/library/textwrap +[patterns]: https://github.com/tapeinosyne/hyphenation/tree/master/patterns-tex +[api-docs]: https://docs.rs/textwrap/ +[issue-13]: https://github.com/mgeisler/textwrap/issues/13 +[issue-14]: https://github.com/mgeisler/textwrap/issues/14 +[issue-19]: https://github.com/mgeisler/textwrap/issues/19 +[issue-25]: https://github.com/mgeisler/textwrap/issues/25 +[issue-26]: https://github.com/mgeisler/textwrap/issues/26 +[issue-28]: https://github.com/mgeisler/textwrap/issues/28 +[issue-36]: https://github.com/mgeisler/textwrap/issues/36 +[issue-39]: https://github.com/mgeisler/textwrap/issues/39 +[issue-58]: https://github.com/mgeisler/textwrap/issues/58 +[issue-59]: https://github.com/mgeisler/textwrap/issues/59 +[issue-61]: https://github.com/mgeisler/textwrap/issues/61 +[issue-81]: https://github.com/mgeisler/textwrap/issues/81 +[issue-99]: https://github.com/mgeisler/textwrap/issues/99 +[issue-101]: https://github.com/mgeisler/textwrap/issues/101 +[issue-107]: https://github.com/mgeisler/textwrap/issues/107 +[issue-122]: https://github.com/mgeisler/textwrap/issues/122 +[issue-129]: https://github.com/mgeisler/textwrap/issues/129 +[issue-141]: https://github.com/mgeisler/textwrap/issues/141 +[issue-151]: https://github.com/mgeisler/textwrap/issues/151 +[mit]: LICENSE diff --git a/textwrap/benches/linear.rs b/textwrap/benches/linear.rs new file mode 100644 index 000000000..104398a1b --- /dev/null +++ b/textwrap/benches/linear.rs @@ -0,0 +1,122 @@ +#![feature(test)] + +// The benchmarks here verify that the complexity grows as O(*n*) +// where *n* is the number of characters in the text to be wrapped. + +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate lipsum; +extern crate rand; +extern crate rand_xorshift; +extern crate test; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load, Standard}; +use lipsum::MarkovChain; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; +use test::Bencher; +#[cfg(feature = "hyphenation")] +use textwrap::Wrapper; + +const LINE_LENGTH: usize = 60; + +/// Generate a lorem ipsum text with the given number of characters. +fn lorem_ipsum(length: usize) -> String { + // The average word length in the lorem ipsum text is somewhere + // between 6 and 7. So we conservatively divide by 5 to have a + // long enough text that we can truncate below. + let rng = XorShiftRng::seed_from_u64(0); + let mut chain = MarkovChain::new_with_rng(rng); + chain.learn(lipsum::LOREM_IPSUM); + chain.learn(lipsum::LIBER_PRIMUS); + + let mut text = chain.generate_from(length / 5, ("Lorem", "ipsum")); + text.truncate(length); + text +} + +#[bench] +fn fill_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn fill_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + b.iter(|| textwrap::fill(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +fn wrap_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + b.iter(|| textwrap::wrap(text, LINE_LENGTH)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_100(b: &mut Bencher) { + let text = &lorem_ipsum(100); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_200(b: &mut Bencher) { + let text = &lorem_ipsum(200); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_400(b: &mut Bencher) { + let text = &lorem_ipsum(400); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} + +#[bench] +#[cfg(feature = "hyphenation")] +fn hyphenation_fill_800(b: &mut Bencher) { + let text = &lorem_ipsum(800); + let dictionary = Standard::from_embedded(Language::Latin).unwrap(); + let wrapper = Wrapper::with_splitter(LINE_LENGTH, dictionary); + b.iter(|| wrapper.fill(text)) +} diff --git a/textwrap/examples/layout.rs b/textwrap/examples/layout.rs new file mode 100644 index 000000000..d36cb3ab9 --- /dev/null +++ b/textwrap/examples/layout.rs @@ -0,0 +1,38 @@ +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load}; +use textwrap::Wrapper; + +#[cfg(not(feature = "hyphenation"))] +fn new_wrapper<'a>() -> Wrapper<'a, textwrap::HyphenSplitter> { + Wrapper::new(0) +} + +#[cfg(feature = "hyphenation")] +fn new_wrapper<'a>() -> Wrapper<'a, hyphenation::Standard> { + let dictionary = hyphenation::Standard::from_embedded(Language::EnglishUS).unwrap(); + Wrapper::with_splitter(0, dictionary) +} + +fn main() { + let example = "Memory safety without garbage collection. \ + Concurrency without data races. \ + Zero-cost abstractions."; + let mut prev_lines = vec![]; + let mut wrapper = new_wrapper(); + for width in 15..60 { + wrapper.width = width; + let lines = wrapper.wrap(example); + if lines != prev_lines { + let title = format!(" Width: {} ", width); + println!(".{:-^1$}.", title, width + 2); + for line in &lines { + println!("| {:1$} |", line, width); + } + prev_lines = lines; + } + } +} diff --git a/textwrap/examples/termwidth.rs b/textwrap/examples/termwidth.rs new file mode 100644 index 000000000..75db3aa7e --- /dev/null +++ b/textwrap/examples/termwidth.rs @@ -0,0 +1,41 @@ +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +extern crate textwrap; + +#[cfg(feature = "hyphenation")] +use hyphenation::{Language, Load, Standard}; +#[cfg(feature = "term_size")] +use textwrap::Wrapper; + +#[cfg(not(feature = "term_size"))] +fn main() { + println!("Please enable the term_size feature to run this example."); +} + +#[cfg(feature = "term_size")] +fn main() { + #[cfg(not(feature = "hyphenation"))] + fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, textwrap::HyphenSplitter>) { + ("without hyphenation", Wrapper::with_termwidth()) + } + + #[cfg(feature = "hyphenation")] + fn new_wrapper<'a>() -> (&'static str, Wrapper<'a, Standard>) { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + ( + "with hyphenation", + Wrapper::with_splitter(textwrap::termwidth(), dictionary), + ) + } + + let example = "Memory safety without garbage collection. \ + Concurrency without data races. \ + Zero-cost abstractions."; + // Create a new Wrapper -- automatically set the width to the + // current terminal width. + let (msg, wrapper) = new_wrapper(); + println!("Formatted {} in {} columns:", msg, wrapper.width); + println!("----"); + println!("{}", wrapper.fill(example)); + println!("----"); +} diff --git a/textwrap/src/indentation.rs b/textwrap/src/indentation.rs new file mode 100644 index 000000000..276ba1055 --- /dev/null +++ b/textwrap/src/indentation.rs @@ -0,0 +1,294 @@ +//! Functions related to adding and removing indentation from lines of +//! text. +//! +//! The functions here can be used to uniformly indent or dedent +//! (unindent) word wrapped lines of text. + +/// Add prefix to each non-empty line. +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" +/// Foo +/// Bar +/// ", " "), " +/// Foo +/// Bar +/// "); +/// ``` +/// +/// Empty lines (lines consisting only of whitespace) are not indented +/// and the whitespace is replaced by a single newline (`\n`): +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" +/// Foo +/// +/// Bar +/// \t +/// Baz +/// ", "->"), " +/// ->Foo +/// +/// ->Bar +/// +/// ->Baz +/// "); +/// ``` +/// +/// Leading and trailing whitespace on non-empty lines is kept +/// unchanged: +/// +/// ``` +/// use textwrap::indent; +/// +/// assert_eq!(indent(" \t Foo ", "->"), "-> \t Foo \n"); +/// ``` +pub fn indent(s: &str, prefix: &str) -> String { + let mut result = String::new(); + for line in s.lines() { + if line.chars().any(|c| !c.is_whitespace()) { + result.push_str(prefix); + result.push_str(line); + } + result.push('\n'); + } + result +} + +/// Removes common leading whitespace from each line. +/// +/// This function will look at each non-empty line and determine the +/// maximum amount of whitespace that can be removed from all lines: +/// +/// ``` +/// use textwrap::dedent; +/// +/// assert_eq!(dedent(" +/// 1st line +/// 2nd line +/// 3rd line +/// "), " +/// 1st line +/// 2nd line +/// 3rd line +/// "); +/// ``` +pub fn dedent(s: &str) -> String { + let mut prefix = ""; + let mut lines = s.lines(); + + // We first search for a non-empty line to find a prefix. + for line in &mut lines { + let mut whitespace_idx = line.len(); + for (idx, ch) in line.char_indices() { + if !ch.is_whitespace() { + whitespace_idx = idx; + break; + } + } + + // Check if the line had anything but whitespace + if whitespace_idx < line.len() { + prefix = &line[..whitespace_idx]; + break; + } + } + + // We then continue looking through the remaining lines to + // possibly shorten the prefix. + for line in &mut lines { + let mut whitespace_idx = line.len(); + for ((idx, a), b) in line.char_indices().zip(prefix.chars()) { + if a != b { + whitespace_idx = idx; + break; + } + } + + // Check if the line had anything but whitespace and if we + // have found a shorter prefix + if whitespace_idx < line.len() && whitespace_idx < prefix.len() { + prefix = &line[..whitespace_idx]; + } + } + + // We now go over the lines a second time to build the result. + let mut result = String::new(); + for line in s.lines() { + if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) { + let (_, tail) = line.split_at(prefix.len()); + result.push_str(tail); + } + result.push('\n'); + } + + if result.ends_with('\n') && !s.ends_with('\n') { + let new_len = result.len() - 1; + result.truncate(new_len); + } + + result +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Add newlines. Ensures that the final line in the vector also + /// has a newline. + fn add_nl(lines: &[&str]) -> String { + lines.join("\n") + "\n" + } + + #[test] + fn indent_empty() { + assert_eq!(indent("\n", " "), "\n"); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn indent_nonempty() { + let x = vec![" foo", + "bar", + " baz"]; + let y = vec!["// foo", + "//bar", + "// baz"]; + assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn indent_empty_line() { + let x = vec![" foo", + "bar", + "", + " baz"]; + let y = vec!["// foo", + "//bar", + "", + "// baz"]; + assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y)); + } + + #[test] + fn dedent_empty() { + assert_eq!(dedent(""), ""); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_multi_line() { + let x = vec![" foo", + " bar", + " baz"]; + let y = vec![" foo", + "bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_empty_line() { + let x = vec![" foo", + " bar", + " ", + " baz"]; + let y = vec![" foo", + "bar", + "", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_blank_line() { + let x = vec![" foo", + "", + " bar", + " foo", + " bar", + " baz"]; + let y = vec!["foo", + "", + " bar", + " foo", + " bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_whitespace_line() { + let x = vec![" foo", + " ", + " bar", + " foo", + " bar", + " baz"]; + let y = vec!["foo", + "", + " bar", + " foo", + " bar", + " baz"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_whitespace() { + let x = vec!["\tfoo", + " bar"]; + let y = vec!["\tfoo", + " bar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_tabbed_whitespace() { + let x = vec!["\t\tfoo", + "\t\t\tbar"]; + let y = vec!["foo", + "\tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_tabbed_whitespace() { + let x = vec!["\t \tfoo", + "\t \t\tbar"]; + let y = vec!["foo", + "\tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_mixed_tabbed_whitespace2() { + let x = vec!["\t \tfoo", + "\t \tbar"]; + let y = vec!["\tfoo", + " \tbar"]; + assert_eq!(dedent(&add_nl(&x)), add_nl(&y)); + } + + #[test] + #[cfg_attr(rustfmt, rustfmt_skip)] + fn dedent_preserve_no_terminating_newline() { + let x = vec![" foo", + " bar"].join("\n"); + let y = vec!["foo", + " bar"].join("\n"); + assert_eq!(dedent(&x), y); + } +} diff --git a/textwrap/src/lib.rs b/textwrap/src/lib.rs new file mode 100644 index 000000000..2f82325fb --- /dev/null +++ b/textwrap/src/lib.rs @@ -0,0 +1,987 @@ +//! `textwrap` provides functions for word wrapping and filling text. +//! +//! Wrapping text can be very useful in commandline programs where you +//! want to format dynamic output nicely so it looks good in a +//! terminal. A quick example: +//! +//! ```no_run +//! extern crate textwrap; +//! use textwrap::fill; +//! +//! fn main() { +//! let text = "textwrap: a small library for wrapping text."; +//! println!("{}", fill(text, 18)); +//! } +//! ``` +//! +//! This will display the following output: +//! +//! ```text +//! textwrap: a small +//! library for +//! wrapping text. +//! ``` +//! +//! # Displayed Width vs Byte Size +//! +//! To word wrap text, one must know the width of each word so one can +//! know when to break lines. This library measures the width of text +//! using the [displayed width][unicode-width], not the size in bytes. +//! +//! This is important for non-ASCII text. ASCII characters such as `a` +//! and `!` are simple and take up one column each. This means that +//! the displayed width is equal to the string length in bytes. +//! However, non-ASCII characters and symbols take up more than one +//! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `⚙` is +//! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively. +//! +//! This is why we take care to use the displayed width instead of the +//! byte count when computing line lengths. All functions in this +//! library handle Unicode characters like this. +//! +//! [unicode-width]: https://docs.rs/unicode-width/ + +#![doc(html_root_url = "https://docs.rs/textwrap/0.11.0")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] + +#[cfg(feature = "hyphenation")] +extern crate hyphenation; +#[cfg(feature = "term_size")] +extern crate term_size; +extern crate unicode_width; + +use std::borrow::Cow; +use std::str::CharIndices; + +use unicode_width::UnicodeWidthChar; +use unicode_width::UnicodeWidthStr; + +/// A non-breaking space. +const NBSP: char = '\u{a0}'; + +mod indentation; +pub use indentation::dedent; +pub use indentation::indent; + +mod splitting; +pub use splitting::{HyphenSplitter, NoHyphenation, WordSplitter}; + +/// A Wrapper holds settings for wrapping and filling text. Use it +/// when the convenience [`wrap_iter`], [`wrap`] and [`fill`] functions +/// are not flexible enough. +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`wrap`]: fn.wrap.html +/// [`fill`]: fn.fill.html +/// +/// The algorithm used by the `WrapIter` iterator (returned from the +/// `wrap_iter` method) works by doing successive partial scans over +/// words in the input string (where each single scan yields a single +/// line) so that the overall time and memory complexity is O(*n*) where +/// *n* is the length of the input string. +#[derive(Clone, Debug)] +pub struct Wrapper<'a, S: WordSplitter> { + /// The width in columns at which the text will be wrapped. + pub width: usize, + /// Indentation used for the first line of output. + pub initial_indent: &'a str, + /// Indentation used for subsequent lines of output. + pub subsequent_indent: &'a str, + /// Allow long words to be broken if they cannot fit on a line. + /// When set to `false`, some lines may be longer than + /// `self.width`. + pub break_words: bool, + /// The method for splitting words. If the `hyphenation` feature + /// is enabled, you can use a `hyphenation::Standard` dictionary + /// here to get language-aware hyphenation. + pub splitter: S, +} + +impl<'a> Wrapper<'a, HyphenSplitter> { + /// Create a new Wrapper for wrapping at the specified width. By + /// default, we allow words longer than `width` to be broken. A + /// [`HyphenSplitter`] will be used by default for splitting + /// words. See the [`WordSplitter`] trait for other options. + /// + /// [`HyphenSplitter`]: struct.HyphenSplitter.html + /// [`WordSplitter`]: trait.WordSplitter.html + pub fn new(width: usize) -> Wrapper<'a, HyphenSplitter> { + Wrapper::with_splitter(width, HyphenSplitter) + } + + /// Create a new Wrapper for wrapping text at the current terminal + /// width. If the terminal width cannot be determined (typically + /// because the standard input and output is not connected to a + /// terminal), a width of 80 characters will be used. Other + /// settings use the same defaults as `Wrapper::new`. + /// + /// Equivalent to: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::{Wrapper, termwidth}; + /// + /// let wrapper = Wrapper::new(termwidth()); + /// ``` + #[cfg(feature = "term_size")] + pub fn with_termwidth() -> Wrapper<'a, HyphenSplitter> { + Wrapper::new(termwidth()) + } +} + +impl<'a, S: WordSplitter> Wrapper<'a, S> { + /// Use the given [`WordSplitter`] to create a new Wrapper for + /// wrapping at the specified width. By default, we allow words + /// longer than `width` to be broken. + /// + /// [`WordSplitter`]: trait.WordSplitter.html + pub fn with_splitter(width: usize, splitter: S) -> Wrapper<'a, S> { + Wrapper { + width: width, + initial_indent: "", + subsequent_indent: "", + break_words: true, + splitter: splitter, + } + } + + /// Change [`self.initial_indent`]. The initial indentation is + /// used on the very first line of output. + /// + /// # Examples + /// + /// Classic paragraph indentation can be achieved by specifying an + /// initial indentation and wrapping each paragraph by itself: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15).initial_indent(" "); + /// ``` + /// + /// [`self.initial_indent`]: #structfield.initial_indent + pub fn initial_indent(self, indent: &'a str) -> Wrapper<'a, S> { + Wrapper { + initial_indent: indent, + ..self + } + } + + /// Change [`self.subsequent_indent`]. The subsequent indentation + /// is used on lines following the first line of output. + /// + /// # Examples + /// + /// Combining initial and subsequent indentation lets you format a + /// single paragraph as a bullet list: + /// + /// ```no_run + /// # #![allow(unused_variables)] + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15) + /// .initial_indent("* ") + /// .subsequent_indent(" "); + /// ``` + /// + /// [`self.subsequent_indent`]: #structfield.subsequent_indent + pub fn subsequent_indent(self, indent: &'a str) -> Wrapper<'a, S> { + Wrapper { + subsequent_indent: indent, + ..self + } + } + + /// Change [`self.break_words`]. This controls if words longer + /// than `self.width` can be broken, or if they will be left + /// sticking out into the right margin. + /// + /// [`self.break_words`]: #structfield.break_words + pub fn break_words(self, setting: bool) -> Wrapper<'a, S> { + Wrapper { + break_words: setting, + ..self + } + } + + /// Fill a line of text at `self.width` characters. Strings are + /// wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The result is a string with newlines between each line. Use + /// the `wrap` method if you need access to the individual lines. + /// + /// # Complexities + /// + /// This method simply joins the lines produced by `wrap_iter`. As + /// such, it inherits the O(*n*) time and memory complexity where + /// *n* is the input string length. + /// + /// # Examples + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(15); + /// assert_eq!(wrapper.fill("Memory safety without garbage collection."), + /// "Memory safety\nwithout garbage\ncollection."); + /// ``` + pub fn fill(&self, s: &str) -> String { + // This will avoid reallocation in simple cases (no + // indentation, no hyphenation). + let mut result = String::with_capacity(s.len()); + + for (i, line) in self.wrap_iter(s).enumerate() { + if i > 0 { + result.push('\n'); + } + result.push_str(&line); + } + + result + } + + /// Wrap a line of text at `self.width` characters. Strings are + /// wrapped based on their displayed width, not their size in + /// bytes. + /// + /// # Complexities + /// + /// This method simply collects the lines produced by `wrap_iter`. + /// As such, it inherits the O(*n*) overall time and memory + /// complexity where *n* is the input string length. + /// + /// # Examples + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrap15 = Wrapper::new(15); + /// assert_eq!(wrap15.wrap("Concurrency without data races."), + /// vec!["Concurrency", + /// "without data", + /// "races."]); + /// + /// let wrap20 = Wrapper::new(20); + /// assert_eq!(wrap20.wrap("Concurrency without data races."), + /// vec!["Concurrency without", + /// "data races."]); + /// ``` + /// + /// Notice that newlines in the input are preserved. This means + /// that they force a line break, regardless of how long the + /// current line is: + /// + /// ``` + /// use textwrap::Wrapper; + /// + /// let wrapper = Wrapper::new(40); + /// assert_eq!(wrapper.wrap("First line.\nSecond line."), + /// vec!["First line.", "Second line."]); + /// ``` + /// + pub fn wrap(&self, s: &'a str) -> Vec<Cow<'a, str>> { + self.wrap_iter(s).collect::<Vec<_>>() + } + + /// Lazily wrap a line of text at `self.width` characters. Strings + /// are wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The [`WordSplitter`] stored in [`self.splitter`] is used + /// whenever when a word is too large to fit on the current line. + /// By changing the field, different hyphenation strategies can be + /// implemented. + /// + /// # Complexities + /// + /// This method returns a [`WrapIter`] iterator which borrows this + /// `Wrapper`. The algorithm used has a linear complexity, so + /// getting the next line from the iterator will take O(*w*) time, + /// where *w* is the wrapping width. Fully processing the iterator + /// will take O(*n*) time for an input string of length *n*. + /// + /// When no indentation is used, each line returned is a slice of + /// the input string and the memory overhead is thus constant. + /// Otherwise new memory is allocated for each line returned. + /// + /// # Examples + /// + /// ``` + /// use std::borrow::Cow; + /// use textwrap::Wrapper; + /// + /// let wrap20 = Wrapper::new(20); + /// let mut wrap20_iter = wrap20.wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); + /// assert_eq!(wrap20_iter.next(), None); + /// + /// let wrap25 = Wrapper::new(25); + /// let mut wrap25_iter = wrap25.wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions."))); + /// assert_eq!(wrap25_iter.next(), None); + /// ``` + /// + /// [`self.splitter`]: #structfield.splitter + /// [`WordSplitter`]: trait.WordSplitter.html + /// [`WrapIter`]: struct.WrapIter.html + pub fn wrap_iter<'w>(&'w self, s: &'a str) -> WrapIter<'w, 'a, S> { + WrapIter { + wrapper: self, + inner: WrapIterImpl::new(self, s), + } + } + + /// Lazily wrap a line of text at `self.width` characters. Strings + /// are wrapped based on their displayed width, not their size in + /// bytes. + /// + /// The [`WordSplitter`] stored in [`self.splitter`] is used + /// whenever when a word is too large to fit on the current line. + /// By changing the field, different hyphenation strategies can be + /// implemented. + /// + /// # Complexities + /// + /// This method consumes the `Wrapper` and returns a + /// [`IntoWrapIter`] iterator. Fully processing the iterator has + /// the same O(*n*) time complexity as [`wrap_iter`], where *n* is + /// the length of the input string. + /// + /// # Examples + /// + /// ``` + /// use std::borrow::Cow; + /// use textwrap::Wrapper; + /// + /// let wrap20 = Wrapper::new(20); + /// let mut wrap20_iter = wrap20.into_wrap_iter("Zero-cost abstractions."); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); + /// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); + /// assert_eq!(wrap20_iter.next(), None); + /// ``` + /// + /// [`self.splitter`]: #structfield.splitter + /// [`WordSplitter`]: trait.WordSplitter.html + /// [`IntoWrapIter`]: struct.IntoWrapIter.html + /// [`wrap_iter`]: #method.wrap_iter + pub fn into_wrap_iter(self, s: &'a str) -> IntoWrapIter<'a, S> { + let inner = WrapIterImpl::new(&self, s); + + IntoWrapIter { + wrapper: self, + inner: inner, + } + } +} + +/// An iterator over the lines of the input string which owns a +/// `Wrapper`. An instance of `IntoWrapIter` is typically obtained +/// through either [`wrap_iter`] or [`Wrapper::into_wrap_iter`]. +/// +/// Each call of `.next()` method yields a line wrapped in `Some` if the +/// input hasn't been fully processed yet. Otherwise it returns `None`. +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`Wrapper::into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter +#[derive(Debug)] +pub struct IntoWrapIter<'a, S: WordSplitter> { + wrapper: Wrapper<'a, S>, + inner: WrapIterImpl<'a>, +} + +impl<'a, S: WordSplitter> Iterator for IntoWrapIter<'a, S> { + type Item = Cow<'a, str>; + + fn next(&mut self) -> Option<Cow<'a, str>> { + self.inner.next(&self.wrapper) + } +} + +/// An iterator over the lines of the input string which borrows a +/// `Wrapper`. An instance of `WrapIter` is typically obtained +/// through the [`Wrapper::wrap_iter`] method. +/// +/// Each call of `.next()` method yields a line wrapped in `Some` if the +/// input hasn't been fully processed yet. Otherwise it returns `None`. +/// +/// [`Wrapper::wrap_iter`]: struct.Wrapper.html#method.wrap_iter +#[derive(Debug)] +pub struct WrapIter<'w, 'a: 'w, S: WordSplitter + 'w> { + wrapper: &'w Wrapper<'a, S>, + inner: WrapIterImpl<'a>, +} + +impl<'w, 'a: 'w, S: WordSplitter> Iterator for WrapIter<'w, 'a, S> { + type Item = Cow<'a, str>; + + fn next(&mut self) -> Option<Cow<'a, str>> { + self.inner.next(self.wrapper) + } +} + +/// Like `char::is_whitespace`, but non-breaking spaces don't count. +#[inline] +fn is_whitespace(ch: char) -> bool { + ch.is_whitespace() && ch != NBSP +} + +/// Common implementation details for `WrapIter` and `IntoWrapIter`. +#[derive(Debug)] +struct WrapIterImpl<'a> { + // String to wrap. + source: &'a str, + // CharIndices iterator over self.source. + char_indices: CharIndices<'a>, + // Byte index where the current line starts. + start: usize, + // Byte index of the last place where the string can be split. + split: usize, + // Size in bytes of the character at self.source[self.split]. + split_len: usize, + // Width of self.source[self.start..idx]. + line_width: usize, + // Width of self.source[self.start..self.split]. + line_width_at_split: usize, + // Tracking runs of whitespace characters. + in_whitespace: bool, + // Has iterator finished producing elements? + finished: bool, +} + +impl<'a> WrapIterImpl<'a> { + fn new<S: WordSplitter>(wrapper: &Wrapper<'a, S>, s: &'a str) -> WrapIterImpl<'a> { + WrapIterImpl { + source: s, + char_indices: s.char_indices(), + start: 0, + split: 0, + split_len: 0, + line_width: wrapper.initial_indent.width(), + line_width_at_split: wrapper.initial_indent.width(), + in_whitespace: false, + finished: false, + } + } + + fn create_result_line<S: WordSplitter>(&self, wrapper: &Wrapper<'a, S>) -> Cow<'a, str> { + if self.start == 0 { + Cow::from(wrapper.initial_indent) + } else { + Cow::from(wrapper.subsequent_indent) + } + } + + fn next<S: WordSplitter>(&mut self, wrapper: &Wrapper<'a, S>) -> Option<Cow<'a, str>> { + if self.finished { + return None; + } + + while let Some((idx, ch)) = self.char_indices.next() { + let char_width = ch.width().unwrap_or(0); + let char_len = ch.len_utf8(); + + if ch == '\n' { + self.split = idx; + self.split_len = char_len; + self.line_width_at_split = self.line_width; + self.in_whitespace = false; + + // If this is not the final line, return the current line. Otherwise, + // we will return the line with its line break after exiting the loop + if self.split + self.split_len < self.source.len() { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..self.split]; + + self.start = self.split + self.split_len; + self.line_width = wrapper.subsequent_indent.width(); + + return Some(line); + } + } else if is_whitespace(ch) { + // Extend the previous split or create a new one. + if self.in_whitespace { + self.split_len += char_len; + } else { + self.split = idx; + self.split_len = char_len; + } + self.line_width_at_split = self.line_width + char_width; + self.in_whitespace = true; + } else if self.line_width + char_width > wrapper.width { + // There is no room for this character on the current + // line. Try to split the final word. + self.in_whitespace = false; + let remaining_text = &self.source[self.split + self.split_len..]; + let final_word = match remaining_text.find(is_whitespace) { + Some(i) => &remaining_text[..i], + None => remaining_text, + }; + + let mut hyphen = ""; + let splits = wrapper.splitter.split(final_word); + for &(head, hyp, _) in splits.iter().rev() { + if self.line_width_at_split + head.width() + hyp.width() <= wrapper.width { + // We can fit head into the current line. + // Advance the split point by the width of the + // whitespace and the head length. + self.split += self.split_len + head.len(); + self.split_len = 0; + hyphen = hyp; + break; + } + } + + if self.start >= self.split { + // The word is too big to fit on a single line, so we + // need to split it at the current index. + if wrapper.break_words { + // Break work at current index. + self.split = idx; + self.split_len = 0; + self.line_width_at_split = self.line_width; + } else { + // Add smallest split. + self.split = self.start + splits[0].0.len(); + self.split_len = 0; + self.line_width_at_split = self.line_width; + } + } + + if self.start < self.split { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..self.split]; + line += hyphen; + + self.start = self.split + self.split_len; + self.line_width += wrapper.subsequent_indent.width(); + self.line_width -= self.line_width_at_split; + self.line_width += char_width; + + return Some(line); + } + } else { + self.in_whitespace = false; + } + self.line_width += char_width; + } + + self.finished = true; + + // Add final line. + if self.start < self.source.len() { + let mut line = self.create_result_line(wrapper); + line += &self.source[self.start..]; + return Some(line); + } + + None + } +} + +/// Return the current terminal width. If the terminal width cannot be +/// determined (typically because the standard output is not connected +/// to a terminal), a default width of 80 characters will be used. +/// +/// # Examples +/// +/// Create a `Wrapper` for the current terminal with a two column +/// margin: +/// +/// ```no_run +/// # #![allow(unused_variables)] +/// use textwrap::{Wrapper, NoHyphenation, termwidth}; +/// +/// let width = termwidth() - 4; // Two columns on each side. +/// let wrapper = Wrapper::with_splitter(width, NoHyphenation) +/// .initial_indent(" ") +/// .subsequent_indent(" "); +/// ``` +#[cfg(feature = "term_size")] +pub fn termwidth() -> usize { + term_size::dimensions_stdout().map_or(80, |(w, _)| w) +} + +/// Fill a line of text at `width` characters. Strings are wrapped +/// based on their displayed width, not their size in bytes. +/// +/// The result is a string with newlines between each line. Use +/// [`wrap`] if you need access to the individual lines or +/// [`wrap_iter`] for its iterator counterpart. +/// +/// ``` +/// use textwrap::fill; +/// +/// assert_eq!(fill("Memory safety without garbage collection.", 15), +/// "Memory safety\nwithout garbage\ncollection."); +/// ``` +/// +/// This function creates a Wrapper on the fly with default settings. +/// If you need to set a language corpus for automatic hyphenation, or +/// need to fill many strings, then it is suggested to create a Wrapper +/// and call its [`fill` method]. +/// +/// [`wrap`]: fn.wrap.html +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`fill` method]: struct.Wrapper.html#method.fill +pub fn fill(s: &str, width: usize) -> String { + Wrapper::new(width).fill(s) +} + +/// Wrap a line of text at `width` characters. Strings are wrapped +/// based on their displayed width, not their size in bytes. +/// +/// This function creates a Wrapper on the fly with default settings. +/// If you need to set a language corpus for automatic hyphenation, or +/// need to wrap many strings, then it is suggested to create a Wrapper +/// and call its [`wrap` method]. +/// +/// The result is a vector of strings. Use [`wrap_iter`] if you need an +/// iterator version. +/// +/// # Examples +/// +/// ``` +/// use textwrap::wrap; +/// +/// assert_eq!(wrap("Concurrency without data races.", 15), +/// vec!["Concurrency", +/// "without data", +/// "races."]); +/// +/// assert_eq!(wrap("Concurrency without data races.", 20), +/// vec!["Concurrency without", +/// "data races."]); +/// ``` +/// +/// [`wrap_iter`]: fn.wrap_iter.html +/// [`wrap` method]: struct.Wrapper.html#method.wrap +pub fn wrap(s: &str, width: usize) -> Vec<Cow<str>> { + Wrapper::new(width).wrap(s) +} + +/// Lazily wrap a line of text at `width` characters. Strings are +/// wrapped based on their displayed width, not their size in bytes. +/// +/// This function creates a Wrapper on the fly with default settings. +/// It then calls the [`into_wrap_iter`] method. Hence, the return +/// value is an [`IntoWrapIter`], not a [`WrapIter`] as the function +/// name would otherwise suggest. +/// +/// If you need to set a language corpus for automatic hyphenation, or +/// need to wrap many strings, then it is suggested to create a Wrapper +/// and call its [`wrap_iter`] or [`into_wrap_iter`] methods. +/// +/// # Examples +/// +/// ``` +/// use std::borrow::Cow; +/// use textwrap::wrap_iter; +/// +/// let mut wrap20_iter = wrap_iter("Zero-cost abstractions.", 20); +/// assert_eq!(wrap20_iter.next(), Some(Cow::from("Zero-cost"))); +/// assert_eq!(wrap20_iter.next(), Some(Cow::from("abstractions."))); +/// assert_eq!(wrap20_iter.next(), None); +/// +/// let mut wrap25_iter = wrap_iter("Zero-cost abstractions.", 25); +/// assert_eq!(wrap25_iter.next(), Some(Cow::from("Zero-cost abstractions."))); +/// assert_eq!(wrap25_iter.next(), None); +/// ``` +/// +/// [`wrap_iter`]: struct.Wrapper.html#method.wrap_iter +/// [`into_wrap_iter`]: struct.Wrapper.html#method.into_wrap_iter +/// [`IntoWrapIter`]: struct.IntoWrapIter.html +/// [`WrapIter`]: struct.WrapIter.html +pub fn wrap_iter(s: &str, width: usize) -> IntoWrapIter<HyphenSplitter> { + Wrapper::new(width).into_wrap_iter(s) +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "hyphenation")] + extern crate hyphenation; + + use super::*; + #[cfg(feature = "hyphenation")] + use hyphenation::{Language, Load, Standard}; + + #[test] + fn no_wrap() { + assert_eq!(wrap("foo", 10), vec!["foo"]); + } + + #[test] + fn simple() { + assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]); + } + + #[test] + fn multi_word_on_line() { + assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]); + } + + #[test] + fn long_word() { + assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]); + } + + #[test] + fn long_words() { + assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]); + } + + #[test] + fn max_width() { + assert_eq!(wrap("foo bar", usize::max_value()), vec!["foo bar"]); + } + + #[test] + fn leading_whitespace() { + assert_eq!(wrap(" foo bar", 6), vec![" foo", "bar"]); + } + + #[test] + fn trailing_whitespace() { + assert_eq!(wrap("foo bar ", 6), vec!["foo", "bar "]); + } + + #[test] + fn interior_whitespace() { + assert_eq!(wrap("foo: bar baz", 10), vec!["foo: bar", "baz"]); + } + + #[test] + fn extra_whitespace_start_of_line() { + // Whitespace is only significant inside a line. After a line + // gets too long and is broken, the first word starts in + // column zero and is not indented. The line before might end + // up with trailing whitespace. + assert_eq!(wrap("foo bar", 5), vec!["foo", "bar"]); + } + + #[test] + fn issue_99() { + // We did not reset the in_whitespace flag correctly and did + // not handle single-character words after a line break. + assert_eq!( + wrap("aaabbbccc x yyyzzzwww", 9), + vec!["aaabbbccc", "x", "yyyzzzwww"] + ); + } + + #[test] + fn issue_129() { + // The dash is an em-dash which takes up four bytes. We used + // to panic since we tried to index into the character. + assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]); + } + + #[test] + fn wide_character_handling() { + assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]); + assert_eq!( + wrap("Hello, World!", 15), + vec!["Hello,", "World!"] + ); + } + + #[test] + fn empty_input_not_indented() { + let wrapper = Wrapper::new(10).initial_indent("!!!"); + assert_eq!(wrapper.fill(""), ""); + } + + #[test] + fn indent_single_line() { + let wrapper = Wrapper::new(10).initial_indent(">>>"); // No trailing space + assert_eq!(wrapper.fill("foo"), ">>>foo"); + } + + #[test] + fn indent_multiple_lines() { + let wrapper = Wrapper::new(6).initial_indent("* ").subsequent_indent(" "); + assert_eq!(wrapper.wrap("foo bar baz"), vec!["* foo", " bar", " baz"]); + } + + #[test] + fn indent_break_words() { + let wrapper = Wrapper::new(5).initial_indent("* ").subsequent_indent(" "); + assert_eq!(wrapper.wrap("foobarbaz"), vec!["* foo", " bar", " baz"]); + } + + #[test] + fn hyphens() { + assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]); + } + + #[test] + fn trailing_hyphen() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foobar-"), vec!["foobar-"]); + } + + #[test] + fn multiple_hyphens() { + assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]); + } + + #[test] + fn hyphens_flag() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!( + wrapper.wrap("The --foo-bar flag."), + vec!["The", "--foo-", "bar", "flag."] + ); + } + + #[test] + fn repeated_hyphens() { + let wrapper = Wrapper::new(4).break_words(false); + assert_eq!(wrapper.wrap("foo--bar"), vec!["foo--bar"]); + } + + #[test] + fn hyphens_alphanumeric() { + assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]); + } + + #[test] + fn hyphens_non_alphanumeric() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foo(-)bar"), vec!["foo(-)bar"]); + } + + #[test] + fn multiple_splits() { + assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]); + } + + #[test] + fn forced_split() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.wrap("foobar-baz"), vec!["foobar-", "baz"]); + } + + #[test] + fn no_hyphenation() { + let wrapper = Wrapper::with_splitter(8, NoHyphenation); + assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn auto_hyphenation() { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::new(10); + assert_eq!( + wrapper.wrap("Internationalization"), + vec!["Internatio", "nalization"] + ); + + let wrapper = Wrapper::with_splitter(10, dictionary); + assert_eq!( + wrapper.wrap("Internationalization"), + vec!["Interna-", "tionaliza-", "tion"] + ); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn split_len_hyphenation() { + // Test that hyphenation takes the width of the wihtespace + // into account. + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(15, dictionary); + assert_eq!( + wrapper.wrap("garbage collection"), + vec!["garbage col-", "lection"] + ); + } + + #[test] + #[cfg(feature = "hyphenation")] + fn borrowed_lines() { + // Lines that end with an extra hyphen are owned, the final + // line is borrowed. + use std::borrow::Cow::{Borrowed, Owned}; + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::with_splitter(10, dictionary); + let lines = wrapper.wrap("Internationalization"); + if let Borrowed(s) = lines[0] { + assert!(false, "should not have been borrowed: {:?}", s); + } + if let Borrowed(s) = lines[1] { + assert!(false, "should not have been borrowed: {:?}", s); + } + if let Owned(ref s) = lines[2] { + assert!(false, "should not have been owned: {:?}", s); + } + } + + #[test] + #[cfg(feature = "hyphenation")] + fn auto_hyphenation_with_hyphen() { + let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); + let wrapper = Wrapper::new(8).break_words(false); + assert_eq!(wrapper.wrap("over-caffinated"), vec!["over-", "caffinated"]); + + let wrapper = Wrapper::with_splitter(8, dictionary).break_words(false); + assert_eq!( + wrapper.wrap("over-caffinated"), + vec!["over-", "caffi-", "nated"] + ); + } + + #[test] + fn break_words() { + assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]); + } + + #[test] + fn break_words_wide_characters() { + assert_eq!(wrap("Hello", 5), vec!["He", "ll", "o"]); + } + + #[test] + fn break_words_zero_width() { + assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]); + } + + #[test] + fn break_words_line_breaks() { + assert_eq!(fill("ab\ncdefghijkl", 5), "ab\ncdefg\nhijkl"); + assert_eq!(fill("abcdefgh\nijkl", 5), "abcde\nfgh\nijkl"); + } + + #[test] + fn preserve_line_breaks() { + assert_eq!(fill("test\n", 11), "test\n"); + assert_eq!(fill("test\n\na\n\n", 11), "test\n\na\n\n"); + assert_eq!(fill("1 3 5 7\n1 3 5 7", 7), "1 3 5 7\n1 3 5 7"); + } + + #[test] + fn wrap_preserve_line_breaks() { + assert_eq!(fill("1 3 5 7\n1 3 5 7", 5), "1 3 5\n7\n1 3 5\n7"); + } + + #[test] + fn non_breaking_space() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.fill("foo bar baz"), "foo bar baz"); + } + + #[test] + fn non_breaking_hyphen() { + let wrapper = Wrapper::new(5).break_words(false); + assert_eq!(wrapper.fill("foo‑bar‑baz"), "foo‑bar‑baz"); + } + + #[test] + fn fill_simple() { + assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz"); + } +} diff --git a/textwrap/src/splitting.rs b/textwrap/src/splitting.rs new file mode 100644 index 000000000..f6b65afda --- /dev/null +++ b/textwrap/src/splitting.rs @@ -0,0 +1,139 @@ +//! Word splitting functionality. +//! +//! To wrap text into lines, long words sometimes need to be split +//! across lines. The [`WordSplitter`] trait defines this +//! functionality. [`HyphenSplitter`] is the default implementation of +//! this treat: it will simply split words on existing hyphens. + +#[cfg(feature = "hyphenation")] +use hyphenation::{Hyphenator, Standard}; + +/// An interface for splitting words. +/// +/// When the [`wrap_iter`] method will try to fit text into a line, it +/// will eventually find a word that it too large the current text +/// width. It will then call the currently configured `WordSplitter` to +/// have it attempt to split the word into smaller parts. This trait +/// describes that functionality via the [`split`] method. +/// +/// If the `textwrap` crate has been compiled with the `hyphenation` +/// feature enabled, you will find an implementation of `WordSplitter` +/// by the `hyphenation::language::Corpus` struct. Use this struct for +/// language-aware hyphenation. See the [`hyphenation` documentation] +/// for details. +/// +/// [`wrap_iter`]: ../struct.Wrapper.html#method.wrap_iter +/// [`split`]: #tymethod.split +/// [`hyphenation` documentation]: https://docs.rs/hyphenation/ +pub trait WordSplitter { + /// Return all possible splits of word. Each split is a triple + /// with a head, a hyphen, and a tail where `head + &hyphen + + /// &tail == word`. The hyphen can be empty if there is already a + /// hyphen in the head. + /// + /// The splits should go from smallest to longest and should + /// include no split at all. So the word "technology" could be + /// split into + /// + /// ```no_run + /// vec![("tech", "-", "nology"), + /// ("technol", "-", "ogy"), + /// ("technolo", "-", "gy"), + /// ("technology", "", "")]; + /// ``` + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)>; +} + +/// Use this as a [`Wrapper.splitter`] to avoid any kind of +/// hyphenation: +/// +/// ``` +/// use textwrap::{Wrapper, NoHyphenation}; +/// +/// let wrapper = Wrapper::with_splitter(8, NoHyphenation); +/// assert_eq!(wrapper.wrap("foo bar-baz"), vec!["foo", "bar-baz"]); +/// ``` +/// +/// [`Wrapper.splitter`]: ../struct.Wrapper.html#structfield.splitter +#[derive(Clone, Debug)] +pub struct NoHyphenation; + +/// `NoHyphenation` implements `WordSplitter` by not splitting the +/// word at all. +impl WordSplitter for NoHyphenation { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + vec![(word, "", "")] + } +} + +/// Simple and default way to split words: splitting on existing +/// hyphens only. +/// +/// You probably don't need to use this type since it's already used +/// by default by `Wrapper::new`. +#[derive(Clone, Debug)] +pub struct HyphenSplitter; + +/// `HyphenSplitter` is the default `WordSplitter` used by +/// `Wrapper::new`. It will split words on any existing hyphens in the +/// word. +/// +/// It will only use hyphens that are surrounded by alphanumeric +/// characters, which prevents a word like "--foo-bar" from being +/// split on the first or second hyphen. +impl WordSplitter for HyphenSplitter { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + let mut triples = Vec::new(); + // Split on hyphens, smallest split first. We only use hyphens + // that are surrounded by alphanumeric characters. This is to + // avoid splitting on repeated hyphens, such as those found in + // --foo-bar. + let mut char_indices = word.char_indices(); + // Early return if the word is empty. + let mut prev = match char_indices.next() { + None => return vec![(word, "", "")], + Some((_, ch)) => ch, + }; + + // Find current word, or return early if the word only has a + // single character. + let (mut idx, mut cur) = match char_indices.next() { + None => return vec![(word, "", "")], + Some((idx, cur)) => (idx, cur), + }; + + for (i, next) in char_indices { + if prev.is_alphanumeric() && cur == '-' && next.is_alphanumeric() { + let (head, tail) = word.split_at(idx + 1); + triples.push((head, "", tail)); + } + prev = cur; + idx = i; + cur = next; + } + + // Finally option is no split at all. + triples.push((word, "", "")); + + triples + } +} + +/// A hyphenation dictionary can be used to do language-specific +/// hyphenation using patterns from the hyphenation crate. +#[cfg(feature = "hyphenation")] +impl WordSplitter for Standard { + fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> { + // Find splits based on language dictionary. + let mut triples = Vec::new(); + for n in self.hyphenate(word).breaks { + let (head, tail) = word.split_at(n); + let hyphen = if head.ends_with('-') { "" } else { "-" }; + triples.push((head, hyphen, tail)); + } + // Finally option is no split at all. + triples.push((word, "", "")); + + triples + } +} diff --git a/textwrap/tests/version-numbers.rs b/textwrap/tests/version-numbers.rs new file mode 100644 index 000000000..85c52e372 --- /dev/null +++ b/textwrap/tests/version-numbers.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate version_sync; + +#[test] +fn test_readme_deps() { + assert_markdown_deps_updated!("README.md"); +} + +#[test] +fn test_readme_changelog() { + assert_contains_regex!("README.md", r"^### Version {version} — .* \d\d?.., 20\d\d$"); +} + +#[test] +fn test_html_root_url() { + assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/thread_local/.cargo-checksum.json b/thread_local/.cargo-checksum.json new file mode 100644 index 000000000..b9c6a5bed --- /dev/null +++ b/thread_local/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"} \ No newline at end of file diff --git a/thread_local/Cargo.toml b/thread_local/Cargo.toml new file mode 100644 index 000000000..fc7b3c82d --- /dev/null +++ b/thread_local/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "thread_local" +version = "0.3.6" +authors = ["Amanieu d'Antras <amanieu@gmail.com>"] +description = "Per-object thread-local storage" +documentation = "https://amanieu.github.io/thread_local-rs/thread_local/index.html" +readme = "README.md" +keywords = ["thread_local", "concurrent", "thread"] +license = "Apache-2.0/MIT" +repository = "https://github.com/Amanieu/thread_local-rs" +[dependencies.lazy_static] +version = "1.0" +[badges.travis-ci] +repository = "Amanieu/thread_local-rs" diff --git a/thread_local/LICENSE-APACHE b/thread_local/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/thread_local/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/thread_local/LICENSE-MIT b/thread_local/LICENSE-MIT new file mode 100644 index 000000000..40b8817a4 --- /dev/null +++ b/thread_local/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/thread_local/README.md b/thread_local/README.md new file mode 100644 index 000000000..1472ed1c6 --- /dev/null +++ b/thread_local/README.md @@ -0,0 +1,41 @@ +thread_local +============ + +[![Build Status](https://travis-ci.org/Amanieu/thread_local-rs.svg?branch=master)](https://travis-ci.org/Amanieu/thread_local-rs) [![Crates.io](https://img.shields.io/crates/v/thread_local.svg)](https://crates.io/crates/thread_local) + +This library provides the `ThreadLocal` and `CachedThreadLocal` types which +allow a separate copy of an object to be used for each thread. This allows for +per-object thread-local storage, unlike the standard library's `thread_local!` +macro which only allows static thread-local storage. + +[Documentation](https://amanieu.github.io/thread_local-rs/thread_local/index.html) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +thread_local = "0.3" +``` + +and this to your crate root: + +```rust +extern crate thread_local; +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/thread_local/benches/thread_local.rs b/thread_local/benches/thread_local.rs new file mode 100644 index 000000000..4cfaacdc4 --- /dev/null +++ b/thread_local/benches/thread_local.rs @@ -0,0 +1,18 @@ +#![feature(test)] + +extern crate thread_local; +extern crate test; + +use thread_local::{ThreadLocal, CachedThreadLocal}; + +#[bench] +fn thread_local(b: &mut test::Bencher) { + let local = ThreadLocal::new(); + b.iter(|| { let _: &i32 = local.get_or(|| Box::new(0)); }); +} + +#[bench] +fn cached_thread_local(b: &mut test::Bencher) { + let local = CachedThreadLocal::new(); + b.iter(|| { let _: &i32 = local.get_or(|| Box::new(0)); }); +} diff --git a/thread_local/src/lib.rs b/thread_local/src/lib.rs new file mode 100644 index 000000000..2f8e579b5 --- /dev/null +++ b/thread_local/src/lib.rs @@ -0,0 +1,757 @@ +// Copyright 2017 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! Per-object thread-local storage +//! +//! This library provides the `ThreadLocal` type which allows a separate copy of +//! an object to be used for each thread. This allows for per-object +//! thread-local storage, unlike the standard library's `thread_local!` macro +//! which only allows static thread-local storage. +//! +//! Per-thread objects are not destroyed when a thread exits. Instead, objects +//! are only destroyed when the `ThreadLocal` containing them is destroyed. +//! +//! You can also iterate over the thread-local values of all thread in a +//! `ThreadLocal` object using the `iter_mut` and `into_iter` methods. This can +//! only be done if you have mutable access to the `ThreadLocal` object, which +//! guarantees that you are the only thread currently accessing it. +//! +//! A `CachedThreadLocal` type is also provided which wraps a `ThreadLocal` but +//! also uses a special fast path for the first thread that writes into it. The +//! fast path has very low overhead (<1ns per access) while keeping the same +//! performance as `ThreadLocal` for other threads. +//! +//! Note that since thread IDs are recycled when a thread exits, it is possible +//! for one thread to retrieve the object of another thread. Since this can only +//! occur after a thread has exited this does not lead to any race conditions. +//! +//! # Examples +//! +//! Basic usage of `ThreadLocal`: +//! +//! ```rust +//! use thread_local::ThreadLocal; +//! let tls: ThreadLocal<u32> = ThreadLocal::new(); +//! assert_eq!(tls.get(), None); +//! assert_eq!(tls.get_or(|| Box::new(5)), &5); +//! assert_eq!(tls.get(), Some(&5)); +//! ``` +//! +//! Combining thread-local values into a single result: +//! +//! ```rust +//! use thread_local::ThreadLocal; +//! use std::sync::Arc; +//! use std::cell::Cell; +//! use std::thread; +//! +//! let tls = Arc::new(ThreadLocal::new()); +//! +//! // Create a bunch of threads to do stuff +//! for _ in 0..5 { +//! let tls2 = tls.clone(); +//! thread::spawn(move || { +//! // Increment a counter to count some event... +//! let cell = tls2.get_or(|| Box::new(Cell::new(0))); +//! cell.set(cell.get() + 1); +//! }).join().unwrap(); +//! } +//! +//! // Once all threads are done, collect the counter values and return the +//! // sum of all thread-local counter values. +//! let tls = Arc::try_unwrap(tls).unwrap(); +//! let total = tls.into_iter().fold(0, |x, y| x + y.get()); +//! assert_eq!(total, 5); +//! ``` + +#![warn(missing_docs)] + +#[macro_use] +extern crate lazy_static; + +mod thread_id; +mod unreachable; + +use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; +use std::sync::Mutex; +use std::marker::PhantomData; +use std::cell::UnsafeCell; +use std::fmt; +use std::iter::Chain; +use std::option::IntoIter as OptionIter; +use std::panic::UnwindSafe; +use unreachable::{UncheckedOptionExt, UncheckedResultExt}; + +/// Thread-local variable wrapper +/// +/// See the [module-level documentation](index.html) for more. +pub struct ThreadLocal<T: ?Sized + Send> { + // Pointer to the current top-level hash table + table: AtomicPtr<Table<T>>, + + // Lock used to guard against concurrent modifications. This is only taken + // while writing to the table, not when reading from it. This also guards + // the counter for the total number of values in the hash table. + lock: Mutex<usize>, + + // PhantomData to indicate that we logically own T + marker: PhantomData<T>, +} + +struct Table<T: ?Sized + Send> { + // Hash entries for the table + entries: Box<[TableEntry<T>]>, + + // Number of bits used for the hash function + hash_bits: usize, + + // Previous table, half the size of the current one + prev: Option<Box<Table<T>>>, +} + +struct TableEntry<T: ?Sized + Send> { + // Current owner of this entry, or 0 if this is an empty entry + owner: AtomicUsize, + + // The object associated with this entry. This is only ever accessed by the + // owner of the entry. + data: UnsafeCell<Option<Box<T>>>, +} + +// ThreadLocal is always Sync, even if T isn't +unsafe impl<T: ?Sized + Send> Sync for ThreadLocal<T> {} + +impl<T: ?Sized + Send> Default for ThreadLocal<T> { + fn default() -> ThreadLocal<T> { + ThreadLocal::new() + } +} + +impl<T: ?Sized + Send> Drop for ThreadLocal<T> { + fn drop(&mut self) { + unsafe { + Box::from_raw(self.table.load(Ordering::Relaxed)); + } + } +} + +// Implementation of Clone for TableEntry, needed to make vec![] work +impl<T: ?Sized + Send> Clone for TableEntry<T> { + fn clone(&self) -> TableEntry<T> { + TableEntry { + owner: AtomicUsize::new(0), + data: UnsafeCell::new(None), + } + } +} + +// Hash function for the thread id +#[cfg(target_pointer_width = "32")] +#[inline] +fn hash(id: usize, bits: usize) -> usize { + id.wrapping_mul(0x9E3779B9) >> (32 - bits) +} +#[cfg(target_pointer_width = "64")] +#[inline] +fn hash(id: usize, bits: usize) -> usize { + id.wrapping_mul(0x9E37_79B9_7F4A_7C15) >> (64 - bits) +} + +impl<T: ?Sized + Send> ThreadLocal<T> { + /// Creates a new empty `ThreadLocal`. + pub fn new() -> ThreadLocal<T> { + let entry = TableEntry { + owner: AtomicUsize::new(0), + data: UnsafeCell::new(None), + }; + let table = Table { + entries: vec![entry; 2].into_boxed_slice(), + hash_bits: 1, + prev: None, + }; + ThreadLocal { + table: AtomicPtr::new(Box::into_raw(Box::new(table))), + lock: Mutex::new(0), + marker: PhantomData, + } + } + + /// Returns the element for the current thread, if it exists. + pub fn get(&self) -> Option<&T> { + let id = thread_id::get(); + self.get_fast(id) + } + + /// Returns the element for the current thread, or creates it if it doesn't + /// exist. + pub fn get_or<F>(&self, create: F) -> &T + where + F: FnOnce() -> Box<T>, + { + unsafe { + self.get_or_try(|| Ok::<Box<T>, ()>(create())) + .unchecked_unwrap_ok() + } + } + + /// Returns the element for the current thread, or creates it if it doesn't + /// exist. If `create` fails, that error is returned and no element is + /// added. + pub fn get_or_try<F, E>(&self, create: F) -> Result<&T, E> + where + F: FnOnce() -> Result<Box<T>, E>, + { + let id = thread_id::get(); + match self.get_fast(id) { + Some(x) => Ok(x), + None => Ok(self.insert(id, try!(create()), true)), + } + } + + // Simple hash table lookup function + fn lookup(id: usize, table: &Table<T>) -> Option<&UnsafeCell<Option<Box<T>>>> { + // Because we use a Mutex to prevent concurrent modifications (but not + // reads) of the hash table, we can avoid any memory barriers here. No + // elements between our hash bucket and our value can have been modified + // since we inserted our thread-local value into the table. + for entry in table.entries.iter().cycle().skip(hash(id, table.hash_bits)) { + let owner = entry.owner.load(Ordering::Relaxed); + if owner == id { + return Some(&entry.data); + } + if owner == 0 { + return None; + } + } + unreachable!(); + } + + // Fast path: try to find our thread in the top-level hash table + fn get_fast(&self, id: usize) -> Option<&T> { + let table = unsafe { &*self.table.load(Ordering::Relaxed) }; + match Self::lookup(id, table) { + Some(x) => unsafe { Some((*x.get()).as_ref().unchecked_unwrap()) }, + None => self.get_slow(id, table), + } + } + + // Slow path: try to find our thread in the other hash tables, and then + // move it to the top-level hash table. + #[cold] + fn get_slow(&self, id: usize, table_top: &Table<T>) -> Option<&T> { + let mut current = &table_top.prev; + while let Some(ref table) = *current { + if let Some(x) = Self::lookup(id, table) { + let data = unsafe { (*x.get()).take().unchecked_unwrap() }; + return Some(self.insert(id, data, false)); + } + current = &table.prev; + } + None + } + + #[cold] + fn insert(&self, id: usize, data: Box<T>, new: bool) -> &T { + // Lock the Mutex to ensure only a single thread is modify the hash + // table at once. + let mut count = self.lock.lock().unwrap(); + if new { + *count += 1; + } + let table_raw = self.table.load(Ordering::Relaxed); + let table = unsafe { &*table_raw }; + + // If the current top-level hash table is more than 75% full, add a new + // level with 2x the capacity. Elements will be moved up to the new top + // level table as they are accessed. + let table = if *count > table.entries.len() * 3 / 4 { + let entry = TableEntry { + owner: AtomicUsize::new(0), + data: UnsafeCell::new(None), + }; + let new_table = Box::into_raw(Box::new(Table { + entries: vec![entry; table.entries.len() * 2].into_boxed_slice(), + hash_bits: table.hash_bits + 1, + prev: unsafe { Some(Box::from_raw(table_raw)) }, + })); + self.table.store(new_table, Ordering::Release); + unsafe { &*new_table } + } else { + table + }; + + // Insert the new element into the top-level hash table + for entry in table.entries.iter().cycle().skip(hash(id, table.hash_bits)) { + let owner = entry.owner.load(Ordering::Relaxed); + if owner == 0 { + unsafe { + entry.owner.store(id, Ordering::Relaxed); + *entry.data.get() = Some(data); + return (*entry.data.get()).as_ref().unchecked_unwrap(); + } + } + if owner == id { + // This can happen if create() inserted a value into this + // ThreadLocal between our calls to get_fast() and insert(). We + // just return the existing value and drop the newly-allocated + // Box. + unsafe { + return (*entry.data.get()).as_ref().unchecked_unwrap(); + } + } + } + unreachable!(); + } + + /// Returns a mutable iterator over the local values of all threads. + /// + /// Since this call borrows the `ThreadLocal` mutably, this operation can + /// be done safely---the mutable borrow statically guarantees no other + /// threads are currently accessing their associated values. + pub fn iter_mut(&mut self) -> IterMut<T> { + let raw = RawIter { + remaining: *self.lock.lock().unwrap(), + index: 0, + table: self.table.load(Ordering::Relaxed), + }; + IterMut { + raw: raw, + marker: PhantomData, + } + } + + /// Removes all thread-specific values from the `ThreadLocal`, effectively + /// reseting it to its original state. + /// + /// Since this call borrows the `ThreadLocal` mutably, this operation can + /// be done safely---the mutable borrow statically guarantees no other + /// threads are currently accessing their associated values. + pub fn clear(&mut self) { + *self = ThreadLocal::new(); + } +} + +impl<T: ?Sized + Send> IntoIterator for ThreadLocal<T> { + type Item = Box<T>; + type IntoIter = IntoIter<T>; + + fn into_iter(self) -> IntoIter<T> { + let raw = RawIter { + remaining: *self.lock.lock().unwrap(), + index: 0, + table: self.table.load(Ordering::Relaxed), + }; + IntoIter { + raw: raw, + _thread_local: self, + } + } +} + +impl<'a, T: ?Sized + Send + 'a> IntoIterator for &'a mut ThreadLocal<T> { + type Item = &'a mut Box<T>; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl<T: Send + Default> ThreadLocal<T> { + /// Returns the element for the current thread, or creates a default one if + /// it doesn't exist. + pub fn get_default(&self) -> &T { + self.get_or(|| Box::new(T::default())) + } +} + +impl<T: ?Sized + Send + fmt::Debug> fmt::Debug for ThreadLocal<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ThreadLocal {{ local_data: {:?} }}", self.get()) + } +} + +impl<T: ?Sized + Send + UnwindSafe> UnwindSafe for ThreadLocal<T> {} + +struct RawIter<T: ?Sized + Send> { + remaining: usize, + index: usize, + table: *const Table<T>, +} + +impl<T: ?Sized + Send> RawIter<T> { + fn next(&mut self) -> Option<*mut Option<Box<T>>> { + if self.remaining == 0 { + return None; + } + + loop { + let entries = unsafe { &(*self.table).entries[..] }; + while self.index < entries.len() { + let val = entries[self.index].data.get(); + self.index += 1; + if unsafe { (*val).is_some() } { + self.remaining -= 1; + return Some(val); + } + } + self.index = 0; + self.table = unsafe { &**(*self.table).prev.as_ref().unchecked_unwrap() }; + } + } +} + +/// Mutable iterator over the contents of a `ThreadLocal`. +pub struct IterMut<'a, T: ?Sized + Send + 'a> { + raw: RawIter<T>, + marker: PhantomData<&'a mut ThreadLocal<T>>, +} + +impl<'a, T: ?Sized + Send + 'a> Iterator for IterMut<'a, T> { + type Item = &'a mut Box<T>; + + fn next(&mut self) -> Option<&'a mut Box<T>> { + self.raw.next().map(|x| unsafe { + (*x).as_mut().unchecked_unwrap() + }) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.raw.remaining, Some(self.raw.remaining)) + } +} + +impl<'a, T: ?Sized + Send + 'a> ExactSizeIterator for IterMut<'a, T> {} + +/// An iterator that moves out of a `ThreadLocal`. +pub struct IntoIter<T: ?Sized + Send> { + raw: RawIter<T>, + _thread_local: ThreadLocal<T>, +} + +impl<T: ?Sized + Send> Iterator for IntoIter<T> { + type Item = Box<T>; + + fn next(&mut self) -> Option<Box<T>> { + self.raw.next().map( + |x| unsafe { (*x).take().unchecked_unwrap() }, + ) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.raw.remaining, Some(self.raw.remaining)) + } +} + +impl<T: ?Sized + Send> ExactSizeIterator for IntoIter<T> {} + +/// Wrapper around `ThreadLocal` which adds a fast path for a single thread. +/// +/// This has the same API as `ThreadLocal`, but will register the first thread +/// that sets a value as its owner. All accesses by the owner will go through +/// a special fast path which is much faster than the normal `ThreadLocal` path. +pub struct CachedThreadLocal<T: ?Sized + Send> { + owner: AtomicUsize, + local: UnsafeCell<Option<Box<T>>>, + global: ThreadLocal<T>, +} + +// CachedThreadLocal is always Sync, even if T isn't +unsafe impl<T: ?Sized + Send> Sync for CachedThreadLocal<T> {} + +impl<T: ?Sized + Send> Default for CachedThreadLocal<T> { + fn default() -> CachedThreadLocal<T> { + CachedThreadLocal::new() + } +} + +impl<T: ?Sized + Send> CachedThreadLocal<T> { + /// Creates a new empty `CachedThreadLocal`. + pub fn new() -> CachedThreadLocal<T> { + CachedThreadLocal { + owner: AtomicUsize::new(0), + local: UnsafeCell::new(None), + global: ThreadLocal::new(), + } + } + + /// Returns the element for the current thread, if it exists. + pub fn get(&self) -> Option<&T> { + let id = thread_id::get(); + let owner = self.owner.load(Ordering::Relaxed); + if owner == id { + return unsafe { Some((*self.local.get()).as_ref().unchecked_unwrap()) }; + } + if owner == 0 { + return None; + } + self.global.get_fast(id) + } + + /// Returns the element for the current thread, or creates it if it doesn't + /// exist. + #[inline(always)] + pub fn get_or<F>(&self, create: F) -> &T + where + F: FnOnce() -> Box<T>, + { + unsafe { + self.get_or_try(|| Ok::<Box<T>, ()>(create())) + .unchecked_unwrap_ok() + } + } + + /// Returns the element for the current thread, or creates it if it doesn't + /// exist. If `create` fails, that error is returned and no element is + /// added. + pub fn get_or_try<F, E>(&self, create: F) -> Result<&T, E> + where + F: FnOnce() -> Result<Box<T>, E>, + { + let id = thread_id::get(); + let owner = self.owner.load(Ordering::Relaxed); + if owner == id { + return Ok(unsafe { (*self.local.get()).as_ref().unchecked_unwrap() }); + } + self.get_or_try_slow(id, owner, create) + } + + #[cold] + #[inline(never)] + fn get_or_try_slow<F, E>(&self, id: usize, owner: usize, create: F) -> Result<&T, E> + where + F: FnOnce() -> Result<Box<T>, E>, + { + if owner == 0 && self.owner.compare_and_swap(0, id, Ordering::Relaxed) == 0 { + unsafe { + (*self.local.get()) = Some(try!(create())); + return Ok((*self.local.get()).as_ref().unchecked_unwrap()); + } + } + match self.global.get_fast(id) { + Some(x) => Ok(x), + None => Ok(self.global.insert(id, try!(create()), true)), + } + } + + /// Returns a mutable iterator over the local values of all threads. + /// + /// Since this call borrows the `ThreadLocal` mutably, this operation can + /// be done safely---the mutable borrow statically guarantees no other + /// threads are currently accessing their associated values. + pub fn iter_mut(&mut self) -> CachedIterMut<T> { + unsafe { + (*self.local.get()).as_mut().into_iter().chain( + self.global + .iter_mut(), + ) + } + } + + /// Removes all thread-specific values from the `ThreadLocal`, effectively + /// reseting it to its original state. + /// + /// Since this call borrows the `ThreadLocal` mutably, this operation can + /// be done safely---the mutable borrow statically guarantees no other + /// threads are currently accessing their associated values. + pub fn clear(&mut self) { + *self = CachedThreadLocal::new(); + } +} + +impl<T: ?Sized + Send> IntoIterator for CachedThreadLocal<T> { + type Item = Box<T>; + type IntoIter = CachedIntoIter<T>; + + fn into_iter(self) -> CachedIntoIter<T> { + unsafe { + (*self.local.get()).take().into_iter().chain( + self.global + .into_iter(), + ) + } + } +} + +impl<'a, T: ?Sized + Send + 'a> IntoIterator for &'a mut CachedThreadLocal<T> { + type Item = &'a mut Box<T>; + type IntoIter = CachedIterMut<'a, T>; + + fn into_iter(self) -> CachedIterMut<'a, T> { + self.iter_mut() + } +} + +impl<T: Send + Default> CachedThreadLocal<T> { + /// Returns the element for the current thread, or creates a default one if + /// it doesn't exist. + pub fn get_default(&self) -> &T { + self.get_or(|| Box::new(T::default())) + } +} + +impl<T: ?Sized + Send + fmt::Debug> fmt::Debug for CachedThreadLocal<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ThreadLocal {{ local_data: {:?} }}", self.get()) + } +} + +/// Mutable iterator over the contents of a `CachedThreadLocal`. +pub type CachedIterMut<'a, T> = Chain<OptionIter<&'a mut Box<T>>, IterMut<'a, T>>; + +/// An iterator that moves out of a `CachedThreadLocal`. +pub type CachedIntoIter<T> = Chain<OptionIter<Box<T>>, IntoIter<T>>; + +impl<T: ?Sized + Send + UnwindSafe> UnwindSafe for CachedThreadLocal<T> {} + +#[cfg(test)] +mod tests { + use std::cell::RefCell; + use std::sync::Arc; + use std::sync::atomic::AtomicUsize; + use std::sync::atomic::Ordering::Relaxed; + use std::thread; + use super::{ThreadLocal, CachedThreadLocal}; + + fn make_create() -> Arc<Fn() -> Box<usize> + Send + Sync> { + let count = AtomicUsize::new(0); + Arc::new(move || Box::new(count.fetch_add(1, Relaxed))) + } + + #[test] + fn same_thread() { + let create = make_create(); + let mut tls = ThreadLocal::new(); + assert_eq!(None, tls.get()); + assert_eq!("ThreadLocal { local_data: None }", format!("{:?}", &tls)); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!("ThreadLocal { local_data: Some(0) }", format!("{:?}", &tls)); + tls.clear(); + assert_eq!(None, tls.get()); + } + + #[test] + fn same_thread_cached() { + let create = make_create(); + let mut tls = CachedThreadLocal::new(); + assert_eq!(None, tls.get()); + assert_eq!("ThreadLocal { local_data: None }", format!("{:?}", &tls)); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + assert_eq!("ThreadLocal { local_data: Some(0) }", format!("{:?}", &tls)); + tls.clear(); + assert_eq!(None, tls.get()); + } + + #[test] + fn different_thread() { + let create = make_create(); + let tls = Arc::new(ThreadLocal::new()); + assert_eq!(None, tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + + let tls2 = tls.clone(); + let create2 = create.clone(); + thread::spawn(move || { + assert_eq!(None, tls2.get()); + assert_eq!(1, *tls2.get_or(|| create2())); + assert_eq!(Some(&1), tls2.get()); + }).join() + .unwrap(); + + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + } + + #[test] + fn different_thread_cached() { + let create = make_create(); + let tls = Arc::new(CachedThreadLocal::new()); + assert_eq!(None, tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + assert_eq!(Some(&0), tls.get()); + + let tls2 = tls.clone(); + let create2 = create.clone(); + thread::spawn(move || { + assert_eq!(None, tls2.get()); + assert_eq!(1, *tls2.get_or(|| create2())); + assert_eq!(Some(&1), tls2.get()); + }).join() + .unwrap(); + + assert_eq!(Some(&0), tls.get()); + assert_eq!(0, *tls.get_or(|| create())); + } + + #[test] + fn iter() { + let tls = Arc::new(ThreadLocal::new()); + tls.get_or(|| Box::new(1)); + + let tls2 = tls.clone(); + thread::spawn(move || { + tls2.get_or(|| Box::new(2)); + let tls3 = tls2.clone(); + thread::spawn(move || { tls3.get_or(|| Box::new(3)); }) + .join() + .unwrap(); + }).join() + .unwrap(); + + let mut tls = Arc::try_unwrap(tls).unwrap(); + let mut v = tls.iter_mut().map(|x| **x).collect::<Vec<i32>>(); + v.sort(); + assert_eq!(vec![1, 2, 3], v); + let mut v = tls.into_iter().map(|x| *x).collect::<Vec<i32>>(); + v.sort(); + assert_eq!(vec![1, 2, 3], v); + } + + #[test] + fn iter_cached() { + let tls = Arc::new(CachedThreadLocal::new()); + tls.get_or(|| Box::new(1)); + + let tls2 = tls.clone(); + thread::spawn(move || { + tls2.get_or(|| Box::new(2)); + let tls3 = tls2.clone(); + thread::spawn(move || { tls3.get_or(|| Box::new(3)); }) + .join() + .unwrap(); + }).join() + .unwrap(); + + let mut tls = Arc::try_unwrap(tls).unwrap(); + let mut v = tls.iter_mut().map(|x| **x).collect::<Vec<i32>>(); + v.sort(); + assert_eq!(vec![1, 2, 3], v); + let mut v = tls.into_iter().map(|x| *x).collect::<Vec<i32>>(); + v.sort(); + assert_eq!(vec![1, 2, 3], v); + } + + #[test] + fn is_sync() { + fn foo<T: Sync>() {} + foo::<ThreadLocal<String>>(); + foo::<ThreadLocal<RefCell<String>>>(); + foo::<CachedThreadLocal<String>>(); + foo::<CachedThreadLocal<RefCell<String>>>(); + } +} diff --git a/thread_local/src/thread_id.rs b/thread_local/src/thread_id.rs new file mode 100644 index 000000000..e7579483a --- /dev/null +++ b/thread_local/src/thread_id.rs @@ -0,0 +1,61 @@ +// Copyright 2017 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::collections::BinaryHeap; +use std::sync::Mutex; +use std::usize; + +// Thread ID manager which allocates thread IDs. It attempts to aggressively +// reuse thread IDs where possible to avoid cases where a ThreadLocal grows +// indefinitely when it is used by many short-lived threads. +struct ThreadIdManager { + limit: usize, + free_list: BinaryHeap<usize>, +} +impl ThreadIdManager { + fn new() -> ThreadIdManager { + ThreadIdManager { + limit: usize::MAX, + free_list: BinaryHeap::new(), + } + } + fn alloc(&mut self) -> usize { + if let Some(id) = self.free_list.pop() { + id + } else { + let id = self.limit; + self.limit = self.limit.checked_sub(1).expect("Ran out of thread IDs"); + id + } + } + fn free(&mut self, id: usize) { + self.free_list.push(id); + } +} +lazy_static! { + static ref THREAD_ID_MANAGER: Mutex<ThreadIdManager> = Mutex::new(ThreadIdManager::new()); +} + +// Non-zero integer which is unique to the current thread while it is running. +// A thread ID may be reused after a thread exits. +struct ThreadId(usize); +impl ThreadId { + fn new() -> ThreadId { + ThreadId(THREAD_ID_MANAGER.lock().unwrap().alloc()) + } +} +impl Drop for ThreadId { + fn drop(&mut self) { + THREAD_ID_MANAGER.lock().unwrap().free(self.0); + } +} +thread_local!(static THREAD_ID: ThreadId = ThreadId::new()); + +/// Returns a non-zero ID for the current thread +pub fn get() -> usize { + THREAD_ID.with(|x| x.0) +} diff --git a/thread_local/src/unreachable.rs b/thread_local/src/unreachable.rs new file mode 100644 index 000000000..baff76600 --- /dev/null +++ b/thread_local/src/unreachable.rs @@ -0,0 +1,74 @@ +// Copyright 2017 Amanieu d'Antras +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! # unreachable +//! inlined from https://github.com/reem/rust-unreachable/ +//! +//! An unreachable code optimization hint in stable rust, and some useful +//! extension traits for `Option` and `Result`. +//! + +/// Hint to the optimizer that any code path which calls this function is +/// statically unreachable and can be removed. +/// +/// Calling this function in reachable code invokes undefined behavior. Be +/// very, very sure this is what you want; often, a simple `panic!` is more +/// suitable. +#[inline] +pub unsafe fn unreachable() -> ! { + /// The empty type for cases which can't occur. + enum Void { } + let x: &Void = ::std::mem::transmute(1usize); + match *x {} +} + +/// An extension trait for `Option<T>` providing unchecked unwrapping methods. +pub trait UncheckedOptionExt<T> { + /// Get the value out of this Option without checking for None. + unsafe fn unchecked_unwrap(self) -> T; + + /// Assert that this Option is a None to the optimizer. + unsafe fn unchecked_unwrap_none(self); +} + +/// An extension trait for `Result<T, E>` providing unchecked unwrapping methods. +pub trait UncheckedResultExt<T, E> { + /// Get the value out of this Result without checking for Err. + unsafe fn unchecked_unwrap_ok(self) -> T; + + /// Get the error out of this Result without checking for Ok. + unsafe fn unchecked_unwrap_err(self) -> E; +} + +impl<T> UncheckedOptionExt<T> for Option<T> { + unsafe fn unchecked_unwrap(self) -> T { + match self { + Some(x) => x, + None => unreachable() + } + } + + unsafe fn unchecked_unwrap_none(self) { + if self.is_some() { unreachable() } + } +} + +impl<T, E> UncheckedResultExt<T, E> for Result<T, E> { + unsafe fn unchecked_unwrap_ok(self) -> T { + match self { + Ok(x) => x, + Err(_) => unreachable() + } + } + + unsafe fn unchecked_unwrap_err(self) -> E { + match self { + Ok(_) => unreachable(), + Err(e) => e + } + } +} \ No newline at end of file diff --git a/time/.cargo-checksum.json b/time/.cargo-checksum.json new file mode 100644 index 000000000..549fb6202 --- /dev/null +++ b/time/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"} \ No newline at end of file diff --git a/time/Cargo.toml b/time/Cargo.toml new file mode 100644 index 000000000..6618d9f52 --- /dev/null +++ b/time/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "time" +version = "0.1.42" +authors = ["The Rust Project Developers"] +description = "Utilities for working with time-related functions in Rust.\n" +homepage = "https://github.com/rust-lang/time" +documentation = "https://doc.rust-lang.org/time" +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/time" +[dependencies.libc] +version = "0.2.1" + +[dependencies.rustc-serialize] +version = "0.3" +optional = true +[dev-dependencies.log] +version = "0.4" + +[dev-dependencies.winapi] +version = "0.3.0" +features = ["std", "processthreadsapi", "winbase"] +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" +[target."cfg(windows)".dependencies.winapi] +version = "0.3.0" +features = ["std", "minwinbase", "minwindef", "ntdef", "profileapi", "sysinfoapi", "timezoneapi"] +[badges.appveyor] +repository = "alexcrichton/time" + +[badges.travis-ci] +repository = "rust-lang-deprecated/time" diff --git a/time/LICENSE-APACHE b/time/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/time/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/time/LICENSE-MIT b/time/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/time/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/time/README.md b/time/README.md new file mode 100644 index 000000000..9762f5ed8 --- /dev/null +++ b/time/README.md @@ -0,0 +1,30 @@ +time +==== + +Utilities for working with time-related functions in Rust + +[![Build Status](https://travis-ci.org/rust-lang-deprecated/time.svg?branch=master)](https://travis-ci.org/rust-lang-deprecated/time) +[![Build status](https://ci.appveyor.com/api/projects/status/55m7rbaj9a5v3ad7?svg=true)](https://ci.appveyor.com/project/alexcrichton/time) + +[Documentation](https://doc.rust-lang.org/time) + +## Notes + +This library is no longer actively maintained, but bugfixes will be added ([details](https://github.com/rust-lang-deprecated/time/issues/136)). + +In case you're looking for something a little fresher and more actively maintained have a look at the [`chrono`](https://github.com/lifthrasiir/rust-chrono) crate. + +## Usage + +Put this in your `Cargo.toml`: + +```toml +[dependencies] +time = "0.1" +``` + +And this in your crate root: + +```rust +extern crate time; +``` diff --git a/time/appveyor.yml b/time/appveyor.yml new file mode 100644 index 000000000..6a1b8dc19 --- /dev/null +++ b/time/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose diff --git a/time/benches/precise_time_ns.rs b/time/benches/precise_time_ns.rs new file mode 100644 index 000000000..2f92226f8 --- /dev/null +++ b/time/benches/precise_time_ns.rs @@ -0,0 +1,14 @@ +#![feature(test)] + +extern crate test; +extern crate time; + +use test::Bencher; + +#[bench] +fn bench_precise_time_ns(b: &mut Bencher) { + b.iter(|| { + time::precise_time_ns(); + time::precise_time_ns(); + }); +} diff --git a/time/src/display.rs b/time/src/display.rs new file mode 100644 index 000000000..27372d22e --- /dev/null +++ b/time/src/display.rs @@ -0,0 +1,260 @@ +use std::fmt::{self, Write}; + +use super::{TmFmt, Tm, Fmt}; + +impl<'a> fmt::Display for TmFmt<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.format { + Fmt::Str(ref s) => { + let mut chars = s.chars(); + while let Some(ch) = chars.next() { + if ch == '%' { + // we've already validated that % always precedes + // another char + try!(parse_type(fmt, chars.next().unwrap(), self.tm)); + } else { + try!(fmt.write_char(ch)); + } + } + + Ok(()) + } + Fmt::Ctime => self.tm.to_local().asctime().fmt(fmt), + Fmt::Rfc3339 => { + if self.tm.tm_utcoff == 0 { + TmFmt { + tm: self.tm, + format: Fmt::Str("%Y-%m-%dT%H:%M:%SZ"), + }.fmt(fmt) + } else { + let s = TmFmt { + tm: self.tm, + format: Fmt::Str("%Y-%m-%dT%H:%M:%S"), + }; + let sign = if self.tm.tm_utcoff > 0 { '+' } else { '-' }; + let mut m = abs(self.tm.tm_utcoff) / 60; + let h = m / 60; + m -= h * 60; + write!(fmt, "{}{}{:02}:{:02}", s, sign, h, m) + } + } + } + } +} + +fn is_leap_year(year: i32) -> bool { + (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) +} + +fn days_in_year(year: i32) -> i32 { + if is_leap_year(year) { 366 } + else { 365 } +} + +fn iso_week_days(yday: i32, wday: i32) -> i32 { + /* The number of days from the first day of the first ISO week of this + * year to the year day YDAY with week day WDAY. + * ISO weeks start on Monday. The first ISO week has the year's first + * Thursday. + * YDAY may be as small as yday_minimum. + */ + let iso_week_start_wday: i32 = 1; /* Monday */ + let iso_week1_wday: i32 = 4; /* Thursday */ + let yday_minimum: i32 = 366; + /* Add enough to the first operand of % to make it nonnegative. */ + let big_enough_multiple_of_7: i32 = (yday_minimum / 7 + 2) * 7; + + yday - (yday - wday + iso_week1_wday + big_enough_multiple_of_7) % 7 + + iso_week1_wday - iso_week_start_wday +} + +fn iso_week(fmt: &mut fmt::Formatter, ch:char, tm: &Tm) -> fmt::Result { + let mut year = tm.tm_year + 1900; + let mut days = iso_week_days(tm.tm_yday, tm.tm_wday); + + if days < 0 { + /* This ISO week belongs to the previous year. */ + year -= 1; + days = iso_week_days(tm.tm_yday + (days_in_year(year)), tm.tm_wday); + } else { + let d = iso_week_days(tm.tm_yday - (days_in_year(year)), + tm.tm_wday); + if 0 <= d { + /* This ISO week belongs to the next year. */ + year += 1; + days = d; + } + } + + match ch { + 'G' => write!(fmt, "{}", year), + 'g' => write!(fmt, "{:02}", (year % 100 + 100) % 100), + 'V' => write!(fmt, "{:02}", days / 7 + 1), + _ => Ok(()) + } +} + +fn parse_type(fmt: &mut fmt::Formatter, ch: char, tm: &Tm) -> fmt::Result { + match ch { + 'A' => fmt.write_str(match tm.tm_wday { + 0 => "Sunday", + 1 => "Monday", + 2 => "Tuesday", + 3 => "Wednesday", + 4 => "Thursday", + 5 => "Friday", + 6 => "Saturday", + _ => unreachable!(), + }), + 'a' => fmt.write_str(match tm.tm_wday { + 0 => "Sun", + 1 => "Mon", + 2 => "Tue", + 3 => "Wed", + 4 => "Thu", + 5 => "Fri", + 6 => "Sat", + _ => unreachable!(), + }), + 'B' => fmt.write_str(match tm.tm_mon { + 0 => "January", + 1 => "February", + 2 => "March", + 3 => "April", + 4 => "May", + 5 => "June", + 6 => "July", + 7 => "August", + 8 => "September", + 9 => "October", + 10 => "November", + 11 => "December", + _ => unreachable!(), + }), + 'b' | 'h' => fmt.write_str(match tm.tm_mon { + 0 => "Jan", + 1 => "Feb", + 2 => "Mar", + 3 => "Apr", + 4 => "May", + 5 => "Jun", + 6 => "Jul", + 7 => "Aug", + 8 => "Sep", + 9 => "Oct", + 10 => "Nov", + 11 => "Dec", + _ => unreachable!(), + }), + 'C' => write!(fmt, "{:02}", (tm.tm_year + 1900) / 100), + 'c' => { + try!(parse_type(fmt, 'a', tm)); + try!(fmt.write_str(" ")); + try!(parse_type(fmt, 'b', tm)); + try!(fmt.write_str(" ")); + try!(parse_type(fmt, 'e', tm)); + try!(fmt.write_str(" ")); + try!(parse_type(fmt, 'T', tm)); + try!(fmt.write_str(" ")); + parse_type(fmt, 'Y', tm) + } + 'D' | 'x' => { + try!(parse_type(fmt, 'm', tm)); + try!(fmt.write_str("/")); + try!(parse_type(fmt, 'd', tm)); + try!(fmt.write_str("/")); + parse_type(fmt, 'y', tm) + } + 'd' => write!(fmt, "{:02}", tm.tm_mday), + 'e' => write!(fmt, "{:2}", tm.tm_mday), + 'f' => write!(fmt, "{:09}", tm.tm_nsec), + 'F' => { + try!(parse_type(fmt, 'Y', tm)); + try!(fmt.write_str("-")); + try!(parse_type(fmt, 'm', tm)); + try!(fmt.write_str("-")); + parse_type(fmt, 'd', tm) + } + 'G' => iso_week(fmt, 'G', tm), + 'g' => iso_week(fmt, 'g', tm), + 'H' => write!(fmt, "{:02}", tm.tm_hour), + 'I' => { + let mut h = tm.tm_hour; + if h == 0 { h = 12 } + if h > 12 { h -= 12 } + write!(fmt, "{:02}", h) + } + 'j' => write!(fmt, "{:03}", tm.tm_yday + 1), + 'k' => write!(fmt, "{:2}", tm.tm_hour), + 'l' => { + let mut h = tm.tm_hour; + if h == 0 { h = 12 } + if h > 12 { h -= 12 } + write!(fmt, "{:2}", h) + } + 'M' => write!(fmt, "{:02}", tm.tm_min), + 'm' => write!(fmt, "{:02}", tm.tm_mon + 1), + 'n' => fmt.write_str("\n"), + 'P' => fmt.write_str(if tm.tm_hour < 12 { "am" } else { "pm" }), + 'p' => fmt.write_str(if (tm.tm_hour) < 12 { "AM" } else { "PM" }), + 'R' => { + try!(parse_type(fmt, 'H', tm)); + try!(fmt.write_str(":")); + parse_type(fmt, 'M', tm) + } + 'r' => { + try!(parse_type(fmt, 'I', tm)); + try!(fmt.write_str(":")); + try!(parse_type(fmt, 'M', tm)); + try!(fmt.write_str(":")); + try!(parse_type(fmt, 'S', tm)); + try!(fmt.write_str(" ")); + parse_type(fmt, 'p', tm) + } + 'S' => write!(fmt, "{:02}", tm.tm_sec), + 's' => write!(fmt, "{}", tm.to_timespec().sec), + 'T' | 'X' => { + try!(parse_type(fmt, 'H', tm)); + try!(fmt.write_str(":")); + try!(parse_type(fmt, 'M', tm)); + try!(fmt.write_str(":")); + parse_type(fmt, 'S', tm) + } + 't' => fmt.write_str("\t"), + 'U' => write!(fmt, "{:02}", (tm.tm_yday - tm.tm_wday + 7) / 7), + 'u' => { + let i = tm.tm_wday; + write!(fmt, "{}", (if i == 0 { 7 } else { i })) + } + 'V' => iso_week(fmt, 'V', tm), + 'v' => { + try!(parse_type(fmt, 'e', tm)); + try!(fmt.write_str("-")); + try!(parse_type(fmt, 'b', tm)); + try!(fmt.write_str("-")); + parse_type(fmt, 'Y', tm) + } + 'W' => { + write!(fmt, "{:02}", (tm.tm_yday - (tm.tm_wday - 1 + 7) % 7 + 7) / 7) + } + 'w' => write!(fmt, "{}", tm.tm_wday), + 'Y' => write!(fmt, "{}", tm.tm_year + 1900), + 'y' => write!(fmt, "{:02}", (tm.tm_year + 1900) % 100), + // FIXME (#2350): support locale + 'Z' => fmt.write_str(if tm.tm_utcoff == 0 { "UTC"} else { "" }), + 'z' => { + let sign = if tm.tm_utcoff > 0 { '+' } else { '-' }; + let mut m = abs(tm.tm_utcoff) / 60; + let h = m / 60; + m -= h * 60; + write!(fmt, "{}{:02}{:02}", sign, h, m) + } + '+' => write!(fmt, "{}", tm.rfc3339()), + '%' => fmt.write_str("%"), + _ => unreachable!(), + } +} + +fn abs(i: i32) -> i32 { + if i < 0 {-i} else {i} +} diff --git a/time/src/duration.rs b/time/src/duration.rs new file mode 100644 index 000000000..d211280f9 --- /dev/null +++ b/time/src/duration.rs @@ -0,0 +1,654 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification + +use std::{fmt, i64}; +use std::error::Error; +use std::ops::{Add, Sub, Mul, Div, Neg, FnOnce}; +use std::time::Duration as StdDuration; + +/// The number of nanoseconds in a microsecond. +const NANOS_PER_MICRO: i32 = 1000; +/// The number of nanoseconds in a millisecond. +const NANOS_PER_MILLI: i32 = 1000_000; +/// The number of nanoseconds in seconds. +const NANOS_PER_SEC: i32 = 1_000_000_000; +/// The number of microseconds per second. +const MICROS_PER_SEC: i64 = 1000_000; +/// The number of milliseconds per second. +const MILLIS_PER_SEC: i64 = 1000; +/// The number of seconds in a minute. +const SECS_PER_MINUTE: i64 = 60; +/// The number of seconds in an hour. +const SECS_PER_HOUR: i64 = 3600; +/// The number of (non-leap) seconds in days. +const SECS_PER_DAY: i64 = 86400; +/// The number of (non-leap) seconds in a week. +const SECS_PER_WEEK: i64 = 604800; + +macro_rules! try_opt { + ($e:expr) => (match $e { Some(v) => v, None => return None }) +} + + +/// ISO 8601 time duration with nanosecond precision. +/// This also allows for the negative duration; see individual methods for details. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Duration { + secs: i64, + nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC +} + +/// The minimum possible `Duration`: `i64::MIN` milliseconds. +pub const MIN: Duration = Duration { + secs: i64::MIN / MILLIS_PER_SEC - 1, + nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +/// The maximum possible `Duration`: `i64::MAX` milliseconds. +pub const MAX: Duration = Duration { + secs: i64::MAX / MILLIS_PER_SEC, + nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +impl Duration { + /// Makes a new `Duration` with given number of weeks. + /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn weeks(weeks: i64) -> Duration { + let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn days(days: i64) -> Duration { + let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn hours(hours: i64) -> Duration { + let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn minutes(minutes: i64) -> Duration { + let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of seconds. + /// Panics when the duration is more than `i64::MAX` milliseconds + /// or less than `i64::MIN` milliseconds. + #[inline] + pub fn seconds(seconds: i64) -> Duration { + let d = Duration { secs: seconds, nanos: 0 }; + if d < MIN || d > MAX { + panic!("Duration::seconds out of bounds"); + } + d + } + + /// Makes a new `Duration` with given number of milliseconds. + #[inline] + pub fn milliseconds(milliseconds: i64) -> Duration { + let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); + let nanos = millis as i32 * NANOS_PER_MILLI; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of microseconds. + #[inline] + pub fn microseconds(microseconds: i64) -> Duration { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + let nanos = micros as i32 * NANOS_PER_MICRO; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of nanoseconds. + #[inline] + pub fn nanoseconds(nanos: i64) -> Duration { + let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); + Duration { secs: secs, nanos: nanos as i32 } + } + + /// Runs a closure, returning the duration of time it took to run the + /// closure. + pub fn span<F>(f: F) -> Duration where F: FnOnce() { + let before = super::precise_time_ns(); + f(); + Duration::nanoseconds((super::precise_time_ns() - before) as i64) + } + + /// Returns the total number of whole weeks in the duration. + #[inline] + pub fn num_weeks(&self) -> i64 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the duration. + pub fn num_days(&self) -> i64 { + self.num_seconds() / SECS_PER_DAY + } + + /// Returns the total number of whole hours in the duration. + #[inline] + pub fn num_hours(&self) -> i64 { + self.num_seconds() / SECS_PER_HOUR + } + + /// Returns the total number of whole minutes in the duration. + #[inline] + pub fn num_minutes(&self) -> i64 { + self.num_seconds() / SECS_PER_MINUTE + } + + /// Returns the total number of whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + // If secs is negative, nanos should be subtracted from the duration. + if self.secs < 0 && self.nanos > 0 { + self.secs + 1 + } else { + self.secs + } + } + + /// Returns the number of nanoseconds such that + /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of + /// nanoseconds in the duration. + fn nanos_mod_sec(&self) -> i32 { + if self.secs < 0 && self.nanos > 0 { + self.nanos - NANOS_PER_SEC + } else { + self.nanos + } + } + + /// Returns the total number of whole milliseconds in the duration, + pub fn num_milliseconds(&self) -> i64 { + // A proper Duration will not overflow, because MIN and MAX are defined + // such that the range is exactly i64 milliseconds. + let secs_part = self.num_seconds() * MILLIS_PER_SEC; + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI; + secs_part + nanos_part as i64 + } + + /// Returns the total number of whole microseconds in the duration, + /// or `None` on overflow (exceeding 2<sup>63</sup> microseconds in either direction). + pub fn num_microseconds(&self) -> Option<i64> { + let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; + secs_part.checked_add(nanos_part as i64) + } + + /// Returns the total number of whole nanoseconds in the duration, + /// or `None` on overflow (exceeding 2<sup>63</sup> nanoseconds in either direction). + pub fn num_nanoseconds(&self) -> Option<i64> { + let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); + let nanos_part = self.nanos_mod_sec(); + secs_part.checked_add(nanos_part as i64) + } + + /// Add two durations, returning `None` if overflow occurred. + pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> { + let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs = try_opt!(secs.checked_add(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// Subtract two durations, returning `None` if overflow occurred. + pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> { + let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs = try_opt!(secs.checked_sub(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// The minimum possible `Duration`: `i64::MIN` milliseconds. + #[inline] + pub fn min_value() -> Duration { MIN } + + /// The maximum possible `Duration`: `i64::MAX` milliseconds. + #[inline] + pub fn max_value() -> Duration { MAX } + + /// A duration where the stored seconds and nanoseconds are equal to zero. + #[inline] + pub fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + + /// Returns `true` if the duration equals `Duration::zero()`. + #[inline] + pub fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } + + /// Creates a `time::Duration` object from `std::time::Duration` + /// + /// This function errors when original duration is larger than the maximum + /// value supported for this type. + pub fn from_std(duration: StdDuration) -> Result<Duration, OutOfRangeError> { + // We need to check secs as u64 before coercing to i64 + if duration.as_secs() > MAX.secs as u64 { + return Err(OutOfRangeError(())); + } + let d = Duration { + secs: duration.as_secs() as i64, + nanos: duration.subsec_nanos() as i32, + }; + if d > MAX { + return Err(OutOfRangeError(())); + } + Ok(d) + } + + /// Creates a `std::time::Duration` object from `time::Duration` + /// + /// This function errors when duration is less than zero. As standard + /// library implementation is limited to non-negative values. + pub fn to_std(&self) -> Result<StdDuration, OutOfRangeError> { + if self.secs < 0 { + return Err(OutOfRangeError(())); + } + Ok(StdDuration::new(self.secs as u64, self.nanos as u32)) + } + + /// Returns the raw value of duration. + #[cfg(target_env = "sgx")] + pub(crate) fn raw(&self) -> (i64, i32) { + (self.secs, self.nanos) + } +} + +impl Neg for Duration { + type Output = Duration; + + #[inline] + fn neg(self) -> Duration { + if self.nanos == 0 { + Duration { secs: -self.secs, nanos: 0 } + } else { + Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } + } + } +} + +impl Add for Duration { + type Output = Duration; + + fn add(self, rhs: Duration) -> Duration { + let mut secs = self.secs + rhs.secs; + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Sub for Duration { + type Output = Duration; + + fn sub(self, rhs: Duration) -> Duration { + let mut secs = self.secs - rhs.secs; + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Mul<i32> for Duration { + type Output = Duration; + + fn mul(self, rhs: i32) -> Duration { + // Multiply nanoseconds as i64, because it cannot overflow that way. + let total_nanos = self.nanos as i64 * rhs as i64; + let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); + let secs = self.secs * rhs as i64 + extra_secs; + Duration { secs: secs, nanos: nanos as i32 } + } +} + +impl Div<i32> for Duration { + type Output = Duration; + + fn div(self, rhs: i32) -> Duration { + let mut secs = self.secs / rhs as i64; + let carry = self.secs - secs * rhs as i64; + let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64; + let mut nanos = self.nanos / rhs + extra_nanos as i32; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl fmt::Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // technically speaking, negative duration is not valid ISO 8601, + // but we need to print it anyway. + let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; + + let days = abs.secs / SECS_PER_DAY; + let secs = abs.secs - days * SECS_PER_DAY; + let hasdate = days != 0; + let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; + + try!(write!(f, "{}P", sign)); + + if hasdate { + try!(write!(f, "{}D", days)); + } + if hastime { + if abs.nanos == 0 { + try!(write!(f, "T{}S", secs)); + } else if abs.nanos % NANOS_PER_MILLI == 0 { + try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)); + } else if abs.nanos % NANOS_PER_MICRO == 0 { + try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)); + } else { + try!(write!(f, "T{}.{:09}S", secs, abs.nanos)); + } + } + Ok(()) + } +} + +/// Represents error when converting `Duration` to/from a standard library +/// implementation +/// +/// The `std::time::Duration` supports a range from zero to `u64::MAX` +/// *seconds*, while this module supports signed range of up to +/// `i64::MAX` of *milliseconds*. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OutOfRangeError(()); + +impl fmt::Display for OutOfRangeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + +impl Error for OutOfRangeError { + fn description(&self) -> &str { + "Source duration value is out of range for the target type" + } +} + +// Copied from libnum +#[inline] +fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { + (div_floor_64(this, other), mod_floor_64(this, other)) +} + +#[inline] +fn div_floor_64(this: i64, other: i64) -> i64 { + match div_rem_64(this, other) { + (d, r) if (r > 0 && other < 0) + || (r < 0 && other > 0) => d - 1, + (d, _) => d, + } +} + +#[inline] +fn mod_floor_64(this: i64, other: i64) -> i64 { + match this % other { + r if (r > 0 && other < 0) + || (r < 0 && other > 0) => r + other, + r => r, + } +} + +#[inline] +fn div_rem_64(this: i64, other: i64) -> (i64, i64) { + (this / other, this % other) +} + +#[cfg(test)] +mod tests { + use super::{Duration, MIN, MAX, OutOfRangeError}; + use std::{i32, i64}; + use std::time::Duration as StdDuration; + + #[test] + fn test_duration() { + assert!(Duration::seconds(1) != Duration::zero()); + assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); + assert_eq!(Duration::seconds(86399) + Duration::seconds(4), + Duration::days(1) + Duration::seconds(3)); + assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); + assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); + assert_eq!(Duration::days(2) + Duration::seconds(86399) + + Duration::nanoseconds(1234567890), + Duration::days(3) + Duration::nanoseconds(234567890)); + assert_eq!(-Duration::days(3), Duration::days(-3)); + assert_eq!(-(Duration::days(3) + Duration::seconds(70)), + Duration::days(-4) + Duration::seconds(86400-70)); + } + + #[test] + fn test_duration_num_days() { + assert_eq!(Duration::zero().num_days(), 0); + assert_eq!(Duration::days(1).num_days(), 1); + assert_eq!(Duration::days(-1).num_days(), -1); + assert_eq!(Duration::seconds(86399).num_days(), 0); + assert_eq!(Duration::seconds(86401).num_days(), 1); + assert_eq!(Duration::seconds(-86399).num_days(), 0); + assert_eq!(Duration::seconds(-86401).num_days(), -1); + assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); + assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); + } + + #[test] + fn test_duration_num_seconds() { + assert_eq!(Duration::zero().num_seconds(), 0); + assert_eq!(Duration::seconds(1).num_seconds(), 1); + assert_eq!(Duration::seconds(-1).num_seconds(), -1); + assert_eq!(Duration::milliseconds(999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); + assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); + } + + #[test] + fn test_duration_num_milliseconds() { + assert_eq!(Duration::zero().num_milliseconds(), 0); + assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); + assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); + assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); + assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); + assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); + assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); + assert_eq!(MAX.num_milliseconds(), i64::MAX); + assert_eq!(MIN.num_milliseconds(), i64::MIN); + } + + #[test] + fn test_duration_num_microseconds() { + assert_eq!(Duration::zero().num_microseconds(), Some(0)); + assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); + assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); + assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); + assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MIN.num_microseconds(), None); + + // overflow checks + const MICROS_PER_DAY: i64 = 86400_000_000; + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), + Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(), + Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None); + } + + #[test] + fn test_duration_num_nanoseconds() { + assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); + assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_nanoseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); + + // overflow checks + const NANOS_PER_DAY: i64 = 86400_000_000_000; + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); + } + + #[test] + fn test_duration_checked_ops() { + assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), + Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999))); + assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000)) + .is_none()); + + assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), + Some(Duration::milliseconds(i64::MIN))); + assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)) + .is_none()); + } + + #[test] + fn test_duration_mul() { + assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); + assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); + assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(30) * 333_333_333, + Duration::seconds(10) - Duration::nanoseconds(10)); + assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, + Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3)); + assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); + assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); + } + + #[test] + fn test_duration_div() { + assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); + assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); + assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); + assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); + assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); + } + + #[test] + fn test_duration_fmt() { + assert_eq!(Duration::zero().to_string(), "PT0S"); + assert_eq!(Duration::days(42).to_string(), "P42D"); + assert_eq!(Duration::days(-42).to_string(), "-P42D"); + assert_eq!(Duration::seconds(42).to_string(), "PT42S"); + assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S"); + assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S"); + assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S"); + assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), + "P7DT6.543S"); + assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S"); + assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S"); + + // the format specifier should have no effect on `Duration` + assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), + "P1DT2.345S"); + } + + #[test] + fn test_to_std() { + assert_eq!(Duration::seconds(1).to_std(), Ok(StdDuration::new(1, 0))); + assert_eq!(Duration::seconds(86401).to_std(), Ok(StdDuration::new(86401, 0))); + assert_eq!(Duration::milliseconds(123).to_std(), Ok(StdDuration::new(0, 123000000))); + assert_eq!(Duration::milliseconds(123765).to_std(), Ok(StdDuration::new(123, 765000000))); + assert_eq!(Duration::nanoseconds(777).to_std(), Ok(StdDuration::new(0, 777))); + assert_eq!(MAX.to_std(), Ok(StdDuration::new(9223372036854775, 807000000))); + assert_eq!(Duration::seconds(-1).to_std(), + Err(OutOfRangeError(()))); + assert_eq!(Duration::milliseconds(-1).to_std(), + Err(OutOfRangeError(()))); + } + + #[test] + fn test_from_std() { + assert_eq!(Ok(Duration::seconds(1)), + Duration::from_std(StdDuration::new(1, 0))); + assert_eq!(Ok(Duration::seconds(86401)), + Duration::from_std(StdDuration::new(86401, 0))); + assert_eq!(Ok(Duration::milliseconds(123)), + Duration::from_std(StdDuration::new(0, 123000000))); + assert_eq!(Ok(Duration::milliseconds(123765)), + Duration::from_std(StdDuration::new(123, 765000000))); + assert_eq!(Ok(Duration::nanoseconds(777)), + Duration::from_std(StdDuration::new(0, 777))); + assert_eq!(Ok(MAX), + Duration::from_std(StdDuration::new(9223372036854775, 807000000))); + assert_eq!(Duration::from_std(StdDuration::new(9223372036854776, 0)), + Err(OutOfRangeError(()))); + assert_eq!(Duration::from_std(StdDuration::new(9223372036854775, 807000001)), + Err(OutOfRangeError(()))); + } +} diff --git a/time/src/lib.rs b/time/src/lib.rs new file mode 100644 index 000000000..ef44f3a12 --- /dev/null +++ b/time/src/lib.rs @@ -0,0 +1,1276 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Simple time handling. +//! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/time) and can be +//! used by adding `time` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! time = "0.1" +//! ``` +//! +//! And this in your crate root: +//! +//! ```rust +//! extern crate time; +//! ``` +//! +//! This crate uses the same syntax for format strings as the +//! [`strftime()`](http://man7.org/linux/man-pages/man3/strftime.3.html) +//! function from the C standard library. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://www.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/time/")] +#![allow(trivial_numeric_casts)] +#![cfg_attr(test, deny(warnings))] + +#[cfg(target_os = "redox")] extern crate syscall; +#[cfg(unix)] extern crate libc; +#[cfg(windows)] extern crate winapi; +#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; + +#[cfg(test)] #[macro_use] extern crate log; + +use std::cmp::Ordering; +use std::error::Error; +use std::fmt; +use std::ops::{Add, Sub}; + +pub use duration::{Duration, OutOfRangeError}; + +use self::ParseError::{InvalidDay, InvalidDayOfMonth, InvalidDayOfWeek, + InvalidDayOfYear, InvalidFormatSpecifier, InvalidHour, + InvalidMinute, InvalidMonth, InvalidSecond, InvalidTime, + InvalidYear, InvalidZoneOffset, InvalidSecondsSinceEpoch, + MissingFormatConverter, UnexpectedCharacter}; + +pub use parse::strptime; + +mod display; +mod duration; +mod parse; +mod sys; + +static NSEC_PER_SEC: i32 = 1_000_000_000; + +/// A record specifying a time value in seconds and nanoseconds, where +/// nanoseconds represent the offset from the given second. +/// +/// For example a timespec of 1.2 seconds after the beginning of the epoch would +/// be represented as {sec: 1, nsec: 200000000}. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +pub struct Timespec { pub sec: i64, pub nsec: i32 } +/* + * Timespec assumes that pre-epoch Timespecs have negative sec and positive + * nsec fields. Darwin's and Linux's struct timespec functions handle pre- + * epoch timestamps using a "two steps back, one step forward" representation, + * though the man pages do not actually document this. For example, the time + * -1.2 seconds before the epoch is represented by `Timespec { sec: -2_i64, + * nsec: 800_000_000 }`. + */ +impl Timespec { + pub fn new(sec: i64, nsec: i32) -> Timespec { + assert!(nsec >= 0 && nsec < NSEC_PER_SEC); + Timespec { sec: sec, nsec: nsec } + } +} + +impl Add<Duration> for Timespec { + type Output = Timespec; + + fn add(self, other: Duration) -> Timespec { + let d_sec = other.num_seconds(); + // It is safe to unwrap the nanoseconds, because there cannot be + // more than one second left, which fits in i64 and in i32. + let d_nsec = (other - Duration::seconds(d_sec)) + .num_nanoseconds().unwrap() as i32; + let mut sec = self.sec + d_sec; + let mut nsec = self.nsec + d_nsec; + if nsec >= NSEC_PER_SEC { + nsec -= NSEC_PER_SEC; + sec += 1; + } else if nsec < 0 { + nsec += NSEC_PER_SEC; + sec -= 1; + } + Timespec::new(sec, nsec) + } +} + +impl Sub<Duration> for Timespec { + type Output = Timespec; + + fn sub(self, other: Duration) -> Timespec { + let d_sec = other.num_seconds(); + // It is safe to unwrap the nanoseconds, because there cannot be + // more than one second left, which fits in i64 and in i32. + let d_nsec = (other - Duration::seconds(d_sec)) + .num_nanoseconds().unwrap() as i32; + let mut sec = self.sec - d_sec; + let mut nsec = self.nsec - d_nsec; + if nsec >= NSEC_PER_SEC { + nsec -= NSEC_PER_SEC; + sec += 1; + } else if nsec < 0 { + nsec += NSEC_PER_SEC; + sec -= 1; + } + Timespec::new(sec, nsec) + } +} + +impl Sub<Timespec> for Timespec { + type Output = Duration; + + fn sub(self, other: Timespec) -> Duration { + let sec = self.sec - other.sec; + let nsec = self.nsec - other.nsec; + Duration::seconds(sec) + Duration::nanoseconds(nsec as i64) + } +} + +/** + * Returns the current time as a `timespec` containing the seconds and + * nanoseconds since 1970-01-01T00:00:00Z. + */ +pub fn get_time() -> Timespec { + let (sec, nsec) = sys::get_time(); + Timespec::new(sec, nsec) +} + + +/** + * Returns the current value of a high-resolution performance counter + * in nanoseconds since an unspecified epoch. + */ +#[inline] +pub fn precise_time_ns() -> u64 { + sys::get_precise_ns() +} + + +/** + * Returns the current value of a high-resolution performance counter + * in seconds since an unspecified epoch. + */ +pub fn precise_time_s() -> f64 { + return (precise_time_ns() as f64) / 1000000000.; +} + +/// An opaque structure representing a moment in time. +/// +/// The only operation that can be performed on a `PreciseTime` is the +/// calculation of the `Duration` of time that lies between them. +/// +/// # Examples +/// +/// Repeatedly call a function for 1 second: +/// +/// ```rust +/// use time::{Duration, PreciseTime}; +/// # fn do_some_work() {} +/// +/// let start = PreciseTime::now(); +/// +/// while start.to(PreciseTime::now()) < Duration::seconds(1) { +/// do_some_work(); +/// } +/// ``` +#[derive(Copy, Clone)] +pub struct PreciseTime(u64); + +impl PreciseTime { + /// Returns a `PreciseTime` representing the current moment in time. + pub fn now() -> PreciseTime { + PreciseTime(precise_time_ns()) + } + + /// Returns a `Duration` representing the span of time from the value of + /// `self` to the value of `later`. + /// + /// # Notes + /// + /// If `later` represents a time before `self`, the result of this method + /// is unspecified. + /// + /// If `later` represents a time more than 293 years after `self`, the + /// result of this method is unspecified. + #[inline] + pub fn to(&self, later: PreciseTime) -> Duration { + // NB: even if later is less than self due to overflow, this will work + // since the subtraction will underflow properly as well. + // + // We could deal with the overflow when casting to an i64, but all that + // gets us is the ability to handle intervals of up to 584 years, which + // seems not very useful :) + Duration::nanoseconds((later.0 - self.0) as i64) + } +} + +/// A structure representing a moment in time. +/// +/// `SteadyTime`s are generated by a "steady" clock, that is, a clock which +/// never experiences discontinuous jumps and for which time always flows at +/// the same rate. +/// +/// # Examples +/// +/// Repeatedly call a function for 1 second: +/// +/// ```rust +/// # use time::{Duration, SteadyTime}; +/// # fn do_some_work() {} +/// let start = SteadyTime::now(); +/// +/// while SteadyTime::now() - start < Duration::seconds(1) { +/// do_some_work(); +/// } +/// ``` +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] +pub struct SteadyTime(sys::SteadyTime); + +impl SteadyTime { + /// Returns a `SteadyTime` representing the current moment in time. + pub fn now() -> SteadyTime { + SteadyTime(sys::SteadyTime::now()) + } +} + +impl fmt::Display for SteadyTime { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + // TODO: needs a display customization + fmt::Debug::fmt(self, fmt) + } +} + +impl Sub for SteadyTime { + type Output = Duration; + + fn sub(self, other: SteadyTime) -> Duration { + self.0 - other.0 + } +} + +impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + + fn sub(self, other: Duration) -> SteadyTime { + SteadyTime(self.0 - other) + } +} + +impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + + fn add(self, other: Duration) -> SteadyTime { + SteadyTime(self.0 + other) + } +} + +#[cfg(not(any(windows, target_env = "sgx")))] +pub fn tzset() { + extern { fn tzset(); } + unsafe { tzset() } +} + + +#[cfg(any(windows, target_env = "sgx"))] +pub fn tzset() {} + +/// Holds a calendar date and time broken down into its components (year, month, +/// day, and so on), also called a broken-down time value. +// FIXME: use c_int instead of i32? +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +pub struct Tm { + /// Seconds after the minute - [0, 60] + pub tm_sec: i32, + + /// Minutes after the hour - [0, 59] + pub tm_min: i32, + + /// Hours after midnight - [0, 23] + pub tm_hour: i32, + + /// Day of the month - [1, 31] + pub tm_mday: i32, + + /// Months since January - [0, 11] + pub tm_mon: i32, + + /// Years since 1900 + pub tm_year: i32, + + /// Days since Sunday - [0, 6]. 0 = Sunday, 1 = Monday, ..., 6 = Saturday. + pub tm_wday: i32, + + /// Days since January 1 - [0, 365] + pub tm_yday: i32, + + /// Daylight Saving Time flag. + /// + /// This value is positive if Daylight Saving Time is in effect, zero if + /// Daylight Saving Time is not in effect, and negative if this information + /// is not available. + pub tm_isdst: i32, + + /// Identifies the time zone that was used to compute this broken-down time + /// value, including any adjustment for Daylight Saving Time. This is the + /// number of seconds east of UTC. For example, for U.S. Pacific Daylight + /// Time, the value is `-7*60*60 = -25200`. + pub tm_utcoff: i32, + + /// Nanoseconds after the second - [0, 10<sup>9</sup> - 1] + pub tm_nsec: i32, +} + +impl Add<Duration> for Tm { + type Output = Tm; + + /// The resulting Tm is in UTC. + // FIXME: The resulting Tm should have the same timezone as `self`; + // however, we need a function such as `at_tm(clock: Timespec, offset: i32)` + // for this. + fn add(self, other: Duration) -> Tm { + at_utc(self.to_timespec() + other) + } +} + +impl Sub<Duration> for Tm { + type Output = Tm; + + /// The resulting Tm is in UTC. + // FIXME: The resulting Tm should have the same timezone as `self`; + // however, we need a function such as `at_tm(clock: Timespec, offset: i32)` + // for this. + fn sub(self, other: Duration) -> Tm { + at_utc(self.to_timespec() - other) + } +} + +impl Sub<Tm> for Tm { + type Output = Duration; + + fn sub(self, other: Tm) -> Duration { + self.to_timespec() - other.to_timespec() + } +} + +impl PartialOrd for Tm { + fn partial_cmp(&self, other: &Tm) -> Option<Ordering> { + self.to_timespec().partial_cmp(&other.to_timespec()) + } +} + +impl Ord for Tm { + fn cmp(&self, other: &Tm) -> Ordering { + self.to_timespec().cmp(&other.to_timespec()) + } +} + +pub fn empty_tm() -> Tm { + Tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_utcoff: 0, + tm_nsec: 0, + } +} + +/// Returns the specified time in UTC +pub fn at_utc(clock: Timespec) -> Tm { + let Timespec { sec, nsec } = clock; + let mut tm = empty_tm(); + sys::time_to_utc_tm(sec, &mut tm); + tm.tm_nsec = nsec; + tm +} + +/// Returns the current time in UTC +pub fn now_utc() -> Tm { + at_utc(get_time()) +} + +/// Returns the specified time in the local timezone +pub fn at(clock: Timespec) -> Tm { + let Timespec { sec, nsec } = clock; + let mut tm = empty_tm(); + sys::time_to_local_tm(sec, &mut tm); + tm.tm_nsec = nsec; + tm +} + +/// Returns the current time in the local timezone +pub fn now() -> Tm { + at(get_time()) +} + +impl Tm { + /// Convert time to the seconds from January 1, 1970 + pub fn to_timespec(&self) -> Timespec { + let sec = match self.tm_utcoff { + 0 => sys::utc_tm_to_time(self), + _ => sys::local_tm_to_time(self) + }; + + Timespec::new(sec, self.tm_nsec) + } + + /// Convert time to the local timezone + pub fn to_local(&self) -> Tm { + at(self.to_timespec()) + } + + /// Convert time to the UTC + pub fn to_utc(&self) -> Tm { + match self.tm_utcoff { + 0 => *self, + _ => at_utc(self.to_timespec()) + } + } + + /** + * Returns a TmFmt that outputs according to the `asctime` format in ISO + * C, in the local timezone. + * + * Example: "Thu Jan 1 00:00:00 1970" + */ + pub fn ctime(&self) -> TmFmt { + TmFmt { + tm: self, + format: Fmt::Ctime, + } + } + + /** + * Returns a TmFmt that outputs according to the `asctime` format in ISO + * C. + * + * Example: "Thu Jan 1 00:00:00 1970" + */ + pub fn asctime(&self) -> TmFmt { + TmFmt { + tm: self, + format: Fmt::Str("%c"), + } + } + + /// Formats the time according to the format string. + pub fn strftime<'a>(&'a self, format: &'a str) -> Result<TmFmt<'a>, ParseError> { + validate_format(TmFmt { + tm: self, + format: Fmt::Str(format), + }) + } + + /** + * Returns a TmFmt that outputs according to RFC 822. + * + * local: "Thu, 22 Mar 2012 07:53:18 PST" + * utc: "Thu, 22 Mar 2012 14:53:18 GMT" + */ + pub fn rfc822(&self) -> TmFmt { + let fmt = if self.tm_utcoff == 0 { + "%a, %d %b %Y %T GMT" + } else { + "%a, %d %b %Y %T %Z" + }; + TmFmt { + tm: self, + format: Fmt::Str(fmt), + } + } + + /** + * Returns a TmFmt that outputs according to RFC 822 with Zulu time. + * + * local: "Thu, 22 Mar 2012 07:53:18 -0700" + * utc: "Thu, 22 Mar 2012 14:53:18 -0000" + */ + pub fn rfc822z(&self) -> TmFmt { + TmFmt { + tm: self, + format: Fmt::Str("%a, %d %b %Y %T %z"), + } + } + + /** + * Returns a TmFmt that outputs according to RFC 3339. RFC 3339 is + * compatible with ISO 8601. + * + * local: "2012-02-22T07:53:18-07:00" + * utc: "2012-02-22T14:53:18Z" + */ + pub fn rfc3339<'a>(&'a self) -> TmFmt { + TmFmt { + tm: self, + format: Fmt::Rfc3339, + } + } +} + +#[derive(Copy, PartialEq, Debug, Clone)] +pub enum ParseError { + InvalidSecond, + InvalidMinute, + InvalidHour, + InvalidDay, + InvalidMonth, + InvalidYear, + InvalidDayOfWeek, + InvalidDayOfMonth, + InvalidDayOfYear, + InvalidZoneOffset, + InvalidTime, + InvalidSecondsSinceEpoch, + MissingFormatConverter, + InvalidFormatSpecifier(char), + UnexpectedCharacter(char, char), +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InvalidFormatSpecifier(ch) => { + write!(f, "{}: %{}", self.description(), ch) + } + UnexpectedCharacter(a, b) => { + write!(f, "expected: `{}`, found: `{}`", a, b) + } + _ => write!(f, "{}", self.description()) + } + } +} + +impl Error for ParseError { + fn description(&self) -> &str { + match *self { + InvalidSecond => "Invalid second.", + InvalidMinute => "Invalid minute.", + InvalidHour => "Invalid hour.", + InvalidDay => "Invalid day.", + InvalidMonth => "Invalid month.", + InvalidYear => "Invalid year.", + InvalidDayOfWeek => "Invalid day of the week.", + InvalidDayOfMonth => "Invalid day of the month.", + InvalidDayOfYear => "Invalid day of the year.", + InvalidZoneOffset => "Invalid zone offset.", + InvalidTime => "Invalid time.", + InvalidSecondsSinceEpoch => "Invalid seconds since epoch.", + MissingFormatConverter => "missing format converter after `%`", + InvalidFormatSpecifier(..) => "invalid format specifier", + UnexpectedCharacter(..) => "Unexpected character.", + } + } +} + +/// A wrapper around a `Tm` and format string that implements Display. +#[derive(Debug)] +pub struct TmFmt<'a> { + tm: &'a Tm, + format: Fmt<'a> +} + +#[derive(Debug)] +enum Fmt<'a> { + Str(&'a str), + Rfc3339, + Ctime, +} + +fn validate_format<'a>(fmt: TmFmt<'a>) -> Result<TmFmt<'a>, ParseError> { + + match (fmt.tm.tm_wday, fmt.tm.tm_mon) { + (0...6, 0...11) => (), + (_wday, 0...11) => return Err(InvalidDayOfWeek), + (0...6, _mon) => return Err(InvalidMonth), + _ => return Err(InvalidDay) + } + match fmt.format { + Fmt::Str(ref s) => { + let mut chars = s.chars(); + loop { + match chars.next() { + Some('%') => { + match chars.next() { + Some('A') | Some('a') | Some('B') | Some('b') | + Some('C') | Some('c') | Some('D') | Some('d') | + Some('e') | Some('F') | Some('f') | Some('G') | + Some('g') | Some('H') | Some('h') | Some('I') | + Some('j') | Some('k') | Some('l') | Some('M') | + Some('m') | Some('n') | Some('P') | Some('p') | + Some('R') | Some('r') | Some('S') | Some('s') | + Some('T') | Some('t') | Some('U') | Some('u') | + Some('V') | Some('v') | Some('W') | Some('w') | + Some('X') | Some('x') | Some('Y') | Some('y') | + Some('Z') | Some('z') | Some('+') | Some('%') => (), + + Some(c) => return Err(InvalidFormatSpecifier(c)), + None => return Err(MissingFormatConverter), + } + }, + None => break, + _ => () + } + } + }, + _ => () + } + Ok(fmt) +} + +/// Formats the time according to the format string. +pub fn strftime(format: &str, tm: &Tm) -> Result<String, ParseError> { + tm.strftime(format).map(|fmt| fmt.to_string()) +} + +#[cfg(test)] +mod tests { + use super::{Timespec, get_time, precise_time_ns, precise_time_s, + at_utc, at, strptime, PreciseTime, SteadyTime, ParseError, Duration}; + use super::ParseError::{InvalidTime, InvalidYear, MissingFormatConverter, + InvalidFormatSpecifier}; + + use std::sync::{Once, ONCE_INIT, Mutex, MutexGuard, LockResult}; + use std::mem; + + struct TzReset { + _tzreset: ::sys::TzReset, + _lock: LockResult<MutexGuard<'static, ()>>, + } + + fn set_time_zone_la_or_london(london: bool) -> TzReset { + // Lock manages current timezone because some tests require LA some + // London + static mut LOCK: *mut Mutex<()> = 0 as *mut _; + static INIT: Once = ONCE_INIT; + + unsafe { + INIT.call_once(|| { + LOCK = mem::transmute(Box::new(Mutex::new(()))); + }); + + let timezone_lock = (*LOCK).lock(); + let reset_func = if london { + ::sys::set_london_with_dst_time_zone() + } else { + ::sys::set_los_angeles_time_zone() + }; + TzReset { + _lock: timezone_lock, + _tzreset: reset_func, + } + } + } + + fn set_time_zone() -> TzReset { + set_time_zone_la_or_london(false) + } + + fn set_time_zone_london_dst() -> TzReset { + set_time_zone_la_or_london(true) + } + + #[test] + fn test_get_time() { + static SOME_RECENT_DATE: i64 = 1325376000i64; // 2012-01-01T00:00:00Z + static SOME_FUTURE_DATE: i64 = 1577836800i64; // 2020-01-01T00:00:00Z + + let tv1 = get_time(); + debug!("tv1={} sec + {} nsec", tv1.sec, tv1.nsec); + + assert!(tv1.sec > SOME_RECENT_DATE); + assert!(tv1.nsec < 1000000000i32); + + let tv2 = get_time(); + debug!("tv2={} sec + {} nsec", tv2.sec, tv2.nsec); + + assert!(tv2.sec >= tv1.sec); + assert!(tv2.sec < SOME_FUTURE_DATE); + assert!(tv2.nsec < 1000000000i32); + if tv2.sec == tv1.sec { + assert!(tv2.nsec >= tv1.nsec); + } + } + + #[test] + fn test_precise_time() { + let s0 = precise_time_s(); + debug!("s0={} sec", s0); + assert!(s0 > 0.); + + let ns0 = precise_time_ns(); + let ns1 = precise_time_ns(); + debug!("ns0={} ns", ns0); + debug!("ns1={} ns", ns1); + assert!(ns1 >= ns0); + + let ns2 = precise_time_ns(); + debug!("ns2={} ns", ns2); + assert!(ns2 >= ns1); + } + + #[test] + fn test_precise_time_to() { + let t0 = PreciseTime(1000); + let t1 = PreciseTime(1023); + assert_eq!(Duration::nanoseconds(23), t0.to(t1)); + } + + #[test] + fn test_at_utc() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + + assert_eq!(utc.tm_sec, 30); + assert_eq!(utc.tm_min, 31); + assert_eq!(utc.tm_hour, 23); + assert_eq!(utc.tm_mday, 13); + assert_eq!(utc.tm_mon, 1); + assert_eq!(utc.tm_year, 109); + assert_eq!(utc.tm_wday, 5); + assert_eq!(utc.tm_yday, 43); + assert_eq!(utc.tm_isdst, 0); + assert_eq!(utc.tm_utcoff, 0); + assert_eq!(utc.tm_nsec, 54321); + } + + #[test] + fn test_at() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let local = at(time); + + debug!("time_at: {:?}", local); + + assert_eq!(local.tm_sec, 30); + assert_eq!(local.tm_min, 31); + assert_eq!(local.tm_hour, 15); + assert_eq!(local.tm_mday, 13); + assert_eq!(local.tm_mon, 1); + assert_eq!(local.tm_year, 109); + assert_eq!(local.tm_wday, 5); + assert_eq!(local.tm_yday, 43); + assert_eq!(local.tm_isdst, 0); + assert_eq!(local.tm_utcoff, -28800); + assert_eq!(local.tm_nsec, 54321); + } + + #[test] + fn test_to_timespec() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + + assert_eq!(utc.to_timespec(), time); + assert_eq!(utc.to_local().to_timespec(), time); + } + + #[test] + fn test_conversions() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + let local = at(time); + + assert!(local.to_local() == local); + assert!(local.to_utc() == utc); + assert!(local.to_utc().to_local() == local); + assert!(utc.to_utc() == utc); + assert!(utc.to_local() == local); + assert!(utc.to_local().to_utc() == utc); + } + + #[test] + fn test_strptime() { + let _reset = set_time_zone(); + + match strptime("", "") { + Ok(ref tm) => { + assert!(tm.tm_sec == 0); + assert!(tm.tm_min == 0); + assert!(tm.tm_hour == 0); + assert!(tm.tm_mday == 0); + assert!(tm.tm_mon == 0); + assert!(tm.tm_year == 0); + assert!(tm.tm_wday == 0); + assert!(tm.tm_isdst == 0); + assert!(tm.tm_utcoff == 0); + assert!(tm.tm_nsec == 0); + } + Err(_) => () + } + + let format = "%a %b %e %T.%f %Y"; + assert_eq!(strptime("", format), Err(ParseError::InvalidDay)); + assert_eq!(strptime("Fri Feb 13 15:31:30", format), + Err(InvalidTime)); + + match strptime("Fri Feb 13 15:31:30.01234 2009", format) { + Err(e) => panic!("{}", e), + Ok(ref tm) => { + assert_eq!(tm.tm_sec, 30); + assert_eq!(tm.tm_min, 31); + assert_eq!(tm.tm_hour, 15); + assert_eq!(tm.tm_mday, 13); + assert_eq!(tm.tm_mon, 1); + assert_eq!(tm.tm_year, 109); + assert_eq!(tm.tm_wday, 5); + assert_eq!(tm.tm_yday, 0); + assert_eq!(tm.tm_isdst, 0); + assert_eq!(tm.tm_utcoff, 0); + assert_eq!(tm.tm_nsec, 12340000); + } + } + + fn test(s: &str, format: &str) -> bool { + match strptime(s, format) { + Ok(tm) => { + tm.strftime(format).unwrap().to_string() == s.to_string() + }, + Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format) + } + } + + fn test_oneway(s : &str, format : &str) -> bool { + match strptime(s, format) { + Ok(_) => { + // oneway tests are used when reformatting the parsed Tm + // back into a string can generate a different string + // from the original (i.e. leading zeroes) + true + }, + Err(e) => panic!("{:?}, s={:?}, format={:?}", e, s, format) + } + } + + let days = [ + "Sunday".to_string(), + "Monday".to_string(), + "Tuesday".to_string(), + "Wednesday".to_string(), + "Thursday".to_string(), + "Friday".to_string(), + "Saturday".to_string() + ]; + for day in days.iter() { + assert!(test(&day, "%A")); + } + + let days = [ + "Sun".to_string(), + "Mon".to_string(), + "Tue".to_string(), + "Wed".to_string(), + "Thu".to_string(), + "Fri".to_string(), + "Sat".to_string() + ]; + for day in days.iter() { + assert!(test(&day, "%a")); + } + + let months = [ + "January".to_string(), + "February".to_string(), + "March".to_string(), + "April".to_string(), + "May".to_string(), + "June".to_string(), + "July".to_string(), + "August".to_string(), + "September".to_string(), + "October".to_string(), + "November".to_string(), + "December".to_string() + ]; + for day in months.iter() { + assert!(test(&day, "%B")); + } + + let months = [ + "Jan".to_string(), + "Feb".to_string(), + "Mar".to_string(), + "Apr".to_string(), + "May".to_string(), + "Jun".to_string(), + "Jul".to_string(), + "Aug".to_string(), + "Sep".to_string(), + "Oct".to_string(), + "Nov".to_string(), + "Dec".to_string() + ]; + for day in months.iter() { + assert!(test(&day, "%b")); + } + + assert!(test("19", "%C")); + assert!(test("Fri Feb 3 23:31:30 2009", "%c")); + assert!(test("Fri Feb 13 23:31:30 2009", "%c")); + assert!(test("02/13/09", "%D")); + assert!(test("03", "%d")); + assert!(test("13", "%d")); + assert!(test(" 3", "%e")); + assert!(test("13", "%e")); + assert!(test("2009-02-13", "%F")); + assert!(test("03", "%H")); + assert!(test("13", "%H")); + assert!(test("03", "%I")); // FIXME (#2350): flesh out + assert!(test("11", "%I")); // FIXME (#2350): flesh out + assert!(test("044", "%j")); + assert!(test(" 3", "%k")); + assert!(test("13", "%k")); + assert!(test(" 1", "%l")); + assert!(test("11", "%l")); + assert!(test("03", "%M")); + assert!(test("13", "%M")); + assert!(test("\n", "%n")); + assert!(test("am", "%P")); + assert!(test("pm", "%P")); + assert!(test("AM", "%p")); + assert!(test("PM", "%p")); + assert!(test("23:31", "%R")); + assert!(test("11:31:30 AM", "%r")); + assert!(test("11:31:30 PM", "%r")); + assert!(test("03", "%S")); + assert!(test("13", "%S")); + assert!(test("15:31:30", "%T")); + assert!(test("\t", "%t")); + assert!(test("1", "%u")); + assert!(test("7", "%u")); + assert!(test("13-Feb-2009", "%v")); + assert!(test("0", "%w")); + assert!(test("6", "%w")); + assert!(test("2009", "%Y")); + assert!(test("09", "%y")); + + assert!(test_oneway("3", "%d")); + assert!(test_oneway("3", "%H")); + assert!(test_oneway("3", "%e")); + assert!(test_oneway("3", "%M")); + assert!(test_oneway("3", "%S")); + + assert!(strptime("-0000", "%z").unwrap().tm_utcoff == 0); + assert!(strptime("-00:00", "%z").unwrap().tm_utcoff == 0); + assert!(strptime("Z", "%z").unwrap().tm_utcoff == 0); + assert_eq!(-28800, strptime("-0800", "%z").unwrap().tm_utcoff); + assert_eq!(-28800, strptime("-08:00", "%z").unwrap().tm_utcoff); + assert_eq!(28800, strptime("+0800", "%z").unwrap().tm_utcoff); + assert_eq!(28800, strptime("+08:00", "%z").unwrap().tm_utcoff); + assert_eq!(5400, strptime("+0130", "%z").unwrap().tm_utcoff); + assert_eq!(5400, strptime("+01:30", "%z").unwrap().tm_utcoff); + assert!(test("%", "%%")); + + // Test for #7256 + assert_eq!(strptime("360", "%Y-%m-%d"), Err(InvalidYear)); + + // Test for epoch seconds parsing + { + assert!(test("1428035610", "%s")); + let tm = strptime("1428035610", "%s").unwrap(); + assert_eq!(tm.tm_utcoff, 0); + assert_eq!(tm.tm_isdst, 0); + assert_eq!(tm.tm_yday, 92); + assert_eq!(tm.tm_wday, 5); + assert_eq!(tm.tm_year, 115); + assert_eq!(tm.tm_mon, 3); + assert_eq!(tm.tm_mday, 3); + assert_eq!(tm.tm_hour, 4); + } + } + + #[test] + fn test_asctime() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + let local = at(time); + + debug!("test_ctime: {} {}", utc.asctime(), local.asctime()); + + assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string()); + assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + } + + #[test] + fn test_ctime() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + let local = at(time); + + debug!("test_ctime: {} {}", utc.ctime(), local.ctime()); + + assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + } + + #[test] + fn test_strftime() { + let _reset = set_time_zone(); + + let time = Timespec::new(1234567890, 54321); + let utc = at_utc(time); + let local = at(time); + + assert_eq!(local.strftime("").unwrap().to_string(), "".to_string()); + assert_eq!(local.strftime("%A").unwrap().to_string(), "Friday".to_string()); + assert_eq!(local.strftime("%a").unwrap().to_string(), "Fri".to_string()); + assert_eq!(local.strftime("%B").unwrap().to_string(), "February".to_string()); + assert_eq!(local.strftime("%b").unwrap().to_string(), "Feb".to_string()); + assert_eq!(local.strftime("%C").unwrap().to_string(), "20".to_string()); + assert_eq!(local.strftime("%c").unwrap().to_string(), + "Fri Feb 13 15:31:30 2009".to_string()); + assert_eq!(local.strftime("%D").unwrap().to_string(), "02/13/09".to_string()); + assert_eq!(local.strftime("%d").unwrap().to_string(), "13".to_string()); + assert_eq!(local.strftime("%e").unwrap().to_string(), "13".to_string()); + assert_eq!(local.strftime("%F").unwrap().to_string(), "2009-02-13".to_string()); + assert_eq!(local.strftime("%f").unwrap().to_string(), "000054321".to_string()); + assert_eq!(local.strftime("%G").unwrap().to_string(), "2009".to_string()); + assert_eq!(local.strftime("%g").unwrap().to_string(), "09".to_string()); + assert_eq!(local.strftime("%H").unwrap().to_string(), "15".to_string()); + assert_eq!(local.strftime("%h").unwrap().to_string(), "Feb".to_string()); + assert_eq!(local.strftime("%I").unwrap().to_string(), "03".to_string()); + assert_eq!(local.strftime("%j").unwrap().to_string(), "044".to_string()); + assert_eq!(local.strftime("%k").unwrap().to_string(), "15".to_string()); + assert_eq!(local.strftime("%l").unwrap().to_string(), " 3".to_string()); + assert_eq!(local.strftime("%M").unwrap().to_string(), "31".to_string()); + assert_eq!(local.strftime("%m").unwrap().to_string(), "02".to_string()); + assert_eq!(local.strftime("%n").unwrap().to_string(), "\n".to_string()); + assert_eq!(local.strftime("%P").unwrap().to_string(), "pm".to_string()); + assert_eq!(local.strftime("%p").unwrap().to_string(), "PM".to_string()); + assert_eq!(local.strftime("%R").unwrap().to_string(), "15:31".to_string()); + assert_eq!(local.strftime("%r").unwrap().to_string(), "03:31:30 PM".to_string()); + assert_eq!(local.strftime("%S").unwrap().to_string(), "30".to_string()); + assert_eq!(local.strftime("%s").unwrap().to_string(), "1234567890".to_string()); + assert_eq!(local.strftime("%T").unwrap().to_string(), "15:31:30".to_string()); + assert_eq!(local.strftime("%t").unwrap().to_string(), "\t".to_string()); + assert_eq!(local.strftime("%U").unwrap().to_string(), "06".to_string()); + assert_eq!(local.strftime("%u").unwrap().to_string(), "5".to_string()); + assert_eq!(local.strftime("%V").unwrap().to_string(), "07".to_string()); + assert_eq!(local.strftime("%v").unwrap().to_string(), "13-Feb-2009".to_string()); + assert_eq!(local.strftime("%W").unwrap().to_string(), "06".to_string()); + assert_eq!(local.strftime("%w").unwrap().to_string(), "5".to_string()); + // FIXME (#2350): support locale + assert_eq!(local.strftime("%X").unwrap().to_string(), "15:31:30".to_string()); + // FIXME (#2350): support locale + assert_eq!(local.strftime("%x").unwrap().to_string(), "02/13/09".to_string()); + assert_eq!(local.strftime("%Y").unwrap().to_string(), "2009".to_string()); + assert_eq!(local.strftime("%y").unwrap().to_string(), "09".to_string()); + // FIXME (#2350): support locale + assert_eq!(local.strftime("%Z").unwrap().to_string(), "".to_string()); + assert_eq!(local.strftime("%z").unwrap().to_string(), "-0800".to_string()); + assert_eq!(local.strftime("%+").unwrap().to_string(), + "2009-02-13T15:31:30-08:00".to_string()); + assert_eq!(local.strftime("%%").unwrap().to_string(), "%".to_string()); + + let invalid_specifiers = ["%E", "%J", "%K", "%L", "%N", "%O", "%o", "%Q", "%q"]; + for &sp in invalid_specifiers.iter() { + assert_eq!(local.strftime(sp).unwrap_err(), + InvalidFormatSpecifier(sp[1..].chars().next().unwrap())); + } + assert_eq!(local.strftime("%").unwrap_err(), MissingFormatConverter); + assert_eq!(local.strftime("%A %").unwrap_err(), MissingFormatConverter); + + assert_eq!(local.asctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + assert_eq!(local.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + assert_eq!(local.rfc822z().to_string(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string()); + assert_eq!(local.rfc3339().to_string(), "2009-02-13T15:31:30-08:00".to_string()); + + assert_eq!(utc.asctime().to_string(), "Fri Feb 13 23:31:30 2009".to_string()); + assert_eq!(utc.ctime().to_string(), "Fri Feb 13 15:31:30 2009".to_string()); + assert_eq!(utc.rfc822().to_string(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string()); + assert_eq!(utc.rfc822z().to_string(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string()); + assert_eq!(utc.rfc3339().to_string(), "2009-02-13T23:31:30Z".to_string()); + } + + #[test] + fn test_timespec_eq_ord() { + let a = &Timespec::new(-2, 1); + let b = &Timespec::new(-1, 2); + let c = &Timespec::new(1, 2); + let d = &Timespec::new(2, 1); + let e = &Timespec::new(2, 1); + + assert!(d.eq(e)); + assert!(c.ne(e)); + + assert!(a.lt(b)); + assert!(b.lt(c)); + assert!(c.lt(d)); + + assert!(a.le(b)); + assert!(b.le(c)); + assert!(c.le(d)); + assert!(d.le(e)); + assert!(e.le(d)); + + assert!(b.ge(a)); + assert!(c.ge(b)); + assert!(d.ge(c)); + assert!(e.ge(d)); + assert!(d.ge(e)); + + assert!(b.gt(a)); + assert!(c.gt(b)); + assert!(d.gt(c)); + } + + #[test] + #[allow(deprecated)] + fn test_timespec_hash() { + use std::hash::{Hash, Hasher}; + + let c = &Timespec::new(3, 2); + let d = &Timespec::new(2, 1); + let e = &Timespec::new(2, 1); + + let mut hasher = ::std::hash::SipHasher::new(); + + let d_hash:u64 = { + d.hash(&mut hasher); + hasher.finish() + }; + + hasher = ::std::hash::SipHasher::new(); + + let e_hash:u64 = { + e.hash(&mut hasher); + hasher.finish() + }; + + hasher = ::std::hash::SipHasher::new(); + + let c_hash:u64 = { + c.hash(&mut hasher); + hasher.finish() + }; + + assert_eq!(d_hash, e_hash); + assert!(c_hash != e_hash); + } + + #[test] + fn test_timespec_add() { + let a = Timespec::new(1, 2); + let b = Duration::seconds(2) + Duration::nanoseconds(3); + let c = a + b; + assert_eq!(c.sec, 3); + assert_eq!(c.nsec, 5); + + let p = Timespec::new(1, super::NSEC_PER_SEC - 2); + let q = Duration::seconds(2) + Duration::nanoseconds(2); + let r = p + q; + assert_eq!(r.sec, 4); + assert_eq!(r.nsec, 0); + + let u = Timespec::new(1, super::NSEC_PER_SEC - 2); + let v = Duration::seconds(2) + Duration::nanoseconds(3); + let w = u + v; + assert_eq!(w.sec, 4); + assert_eq!(w.nsec, 1); + + let k = Timespec::new(1, 0); + let l = Duration::nanoseconds(-1); + let m = k + l; + assert_eq!(m.sec, 0); + assert_eq!(m.nsec, 999_999_999); + } + + #[test] + fn test_timespec_sub() { + let a = Timespec::new(2, 3); + let b = Timespec::new(1, 2); + let c = a - b; + assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 + 1)); + + let p = Timespec::new(2, 0); + let q = Timespec::new(1, 2); + let r = p - q; + assert_eq!(r.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 - 2)); + + let u = Timespec::new(1, 2); + let v = Timespec::new(2, 3); + let w = u - v; + assert_eq!(w.num_nanoseconds(), Some(-super::NSEC_PER_SEC as i64 - 1)); + } + + #[test] + fn test_time_sub() { + let a = ::now(); + let b = at(a.to_timespec() + Duration::seconds(5)); + let c = b - a; + assert_eq!(c.num_nanoseconds(), Some(super::NSEC_PER_SEC as i64 * 5)); + } + + #[test] + fn test_steadytime_sub() { + let a = SteadyTime::now(); + let b = a + Duration::seconds(1); + assert_eq!(b - a, Duration::seconds(1)); + assert_eq!(a - b, Duration::seconds(-1)); + } + + #[test] + fn test_date_before_1970() { + let early = strptime("1901-01-06", "%F").unwrap(); + let late = strptime("2000-01-01", "%F").unwrap(); + assert!(early < late); + } + + #[test] + fn test_dst() { + let _reset = set_time_zone_london_dst(); + let utc_in_feb = strptime("2015-02-01Z", "%F%z").unwrap(); + let utc_in_jun = strptime("2015-06-01Z", "%F%z").unwrap(); + let utc_in_nov = strptime("2015-11-01Z", "%F%z").unwrap(); + let local_in_feb = utc_in_feb.to_local(); + let local_in_jun = utc_in_jun.to_local(); + let local_in_nov = utc_in_nov.to_local(); + + assert_eq!(local_in_feb.tm_mon, 1); + assert_eq!(local_in_feb.tm_hour, 0); + assert_eq!(local_in_feb.tm_utcoff, 0); + assert_eq!(local_in_feb.tm_isdst, 0); + + assert_eq!(local_in_jun.tm_mon, 5); + assert_eq!(local_in_jun.tm_hour, 1); + assert_eq!(local_in_jun.tm_utcoff, 3600); + assert_eq!(local_in_jun.tm_isdst, 1); + + assert_eq!(local_in_nov.tm_mon, 10); + assert_eq!(local_in_nov.tm_hour, 0); + assert_eq!(local_in_nov.tm_utcoff, 0); + assert_eq!(local_in_nov.tm_isdst, 0) + } +} diff --git a/time/src/parse.rs b/time/src/parse.rs new file mode 100644 index 000000000..467c9be22 --- /dev/null +++ b/time/src/parse.rs @@ -0,0 +1,394 @@ +use super::{Timespec, Tm, at_utc, ParseError, NSEC_PER_SEC}; + +/// Parses the time from the string according to the format string. +pub fn strptime(mut s: &str, format: &str) -> Result<Tm, ParseError> { + let mut tm = Tm { + tm_sec: 0, + tm_min: 0, + tm_hour: 0, + tm_mday: 0, + tm_mon: 0, + tm_year: 0, + tm_wday: 0, + tm_yday: 0, + tm_isdst: 0, + tm_utcoff: 0, + tm_nsec: 0, + }; + let mut chars = format.chars(); + + while let Some(ch) = chars.next() { + if ch == '%' { + if let Some(ch) = chars.next() { + try!(parse_type(&mut s, ch, &mut tm)); + } + } else { + try!(parse_char(&mut s, ch)); + } + } + + Ok(tm) +} + +fn parse_type(s: &mut &str, ch: char, tm: &mut Tm) -> Result<(), ParseError> { + match ch { + 'A' => match match_strs(s, &[("Sunday", 0), + ("Monday", 1), + ("Tuesday", 2), + ("Wednesday", 3), + ("Thursday", 4), + ("Friday", 5), + ("Saturday", 6)]) { + Some(v) => { tm.tm_wday = v; Ok(()) } + None => Err(ParseError::InvalidDay) + }, + 'a' => match match_strs(s, &[("Sun", 0), + ("Mon", 1), + ("Tue", 2), + ("Wed", 3), + ("Thu", 4), + ("Fri", 5), + ("Sat", 6)]) { + Some(v) => { tm.tm_wday = v; Ok(()) } + None => Err(ParseError::InvalidDay) + }, + 'B' => match match_strs(s, &[("January", 0), + ("February", 1), + ("March", 2), + ("April", 3), + ("May", 4), + ("June", 5), + ("July", 6), + ("August", 7), + ("September", 8), + ("October", 9), + ("November", 10), + ("December", 11)]) { + Some(v) => { tm.tm_mon = v; Ok(()) } + None => Err(ParseError::InvalidMonth) + }, + 'b' | 'h' => match match_strs(s, &[("Jan", 0), + ("Feb", 1), + ("Mar", 2), + ("Apr", 3), + ("May", 4), + ("Jun", 5), + ("Jul", 6), + ("Aug", 7), + ("Sep", 8), + ("Oct", 9), + ("Nov", 10), + ("Dec", 11)]) { + Some(v) => { tm.tm_mon = v; Ok(()) } + None => Err(ParseError::InvalidMonth) + }, + 'C' => match match_digits_in_range(s, 1, 2, false, 0, 99) { + Some(v) => { tm.tm_year += (v * 100) - 1900; Ok(()) } + None => Err(ParseError::InvalidYear) + }, + 'c' => { + parse_type(s, 'a', tm) + .and_then(|()| parse_char(s, ' ')) + .and_then(|()| parse_type(s, 'b', tm)) + .and_then(|()| parse_char(s, ' ')) + .and_then(|()| parse_type(s, 'e', tm)) + .and_then(|()| parse_char(s, ' ')) + .and_then(|()| parse_type(s, 'T', tm)) + .and_then(|()| parse_char(s, ' ')) + .and_then(|()| parse_type(s, 'Y', tm)) + } + 'D' | 'x' => { + parse_type(s, 'm', tm) + .and_then(|()| parse_char(s, '/')) + .and_then(|()| parse_type(s, 'd', tm)) + .and_then(|()| parse_char(s, '/')) + .and_then(|()| parse_type(s, 'y', tm)) + } + 'd' => match match_digits_in_range(s, 1, 2, false, 1, 31) { + Some(v) => { tm.tm_mday = v; Ok(()) } + None => Err(ParseError::InvalidDayOfMonth) + }, + 'e' => match match_digits_in_range(s, 1, 2, true, 1, 31) { + Some(v) => { tm.tm_mday = v; Ok(()) } + None => Err(ParseError::InvalidDayOfMonth) + }, + 'f' => { + tm.tm_nsec = match_fractional_seconds(s); + Ok(()) + } + 'F' => { + parse_type(s, 'Y', tm) + .and_then(|()| parse_char(s, '-')) + .and_then(|()| parse_type(s, 'm', tm)) + .and_then(|()| parse_char(s, '-')) + .and_then(|()| parse_type(s, 'd', tm)) + } + 'H' => { + match match_digits_in_range(s, 1, 2, false, 0, 23) { + Some(v) => { tm.tm_hour = v; Ok(()) } + None => Err(ParseError::InvalidHour) + } + } + 'I' => { + match match_digits_in_range(s, 1, 2, false, 1, 12) { + Some(v) => { tm.tm_hour = if v == 12 { 0 } else { v }; Ok(()) } + None => Err(ParseError::InvalidHour) + } + } + 'j' => { + match match_digits_in_range(s, 1, 3, false, 1, 366) { + Some(v) => { tm.tm_yday = v - 1; Ok(()) } + None => Err(ParseError::InvalidDayOfYear) + } + } + 'k' => { + match match_digits_in_range(s, 1, 2, true, 0, 23) { + Some(v) => { tm.tm_hour = v; Ok(()) } + None => Err(ParseError::InvalidHour) + } + } + 'l' => { + match match_digits_in_range(s, 1, 2, true, 1, 12) { + Some(v) => { tm.tm_hour = if v == 12 { 0 } else { v }; Ok(()) } + None => Err(ParseError::InvalidHour) + } + } + 'M' => { + match match_digits_in_range(s, 1, 2, false, 0, 59) { + Some(v) => { tm.tm_min = v; Ok(()) } + None => Err(ParseError::InvalidMinute) + } + } + 'm' => { + match match_digits_in_range(s, 1, 2, false, 1, 12) { + Some(v) => { tm.tm_mon = v - 1; Ok(()) } + None => Err(ParseError::InvalidMonth) + } + } + 'n' => parse_char(s, '\n'), + 'P' => match match_strs(s, &[("am", 0), ("pm", 12)]) { + Some(v) => { tm.tm_hour += v; Ok(()) } + None => Err(ParseError::InvalidHour) + }, + 'p' => match match_strs(s, &[("AM", 0), ("PM", 12)]) { + Some(v) => { tm.tm_hour += v; Ok(()) } + None => Err(ParseError::InvalidHour) + }, + 'R' => { + parse_type(s, 'H', tm) + .and_then(|()| parse_char(s, ':')) + .and_then(|()| parse_type(s, 'M', tm)) + } + 'r' => { + parse_type(s, 'I', tm) + .and_then(|()| parse_char(s, ':')) + .and_then(|()| parse_type(s, 'M', tm)) + .and_then(|()| parse_char(s, ':')) + .and_then(|()| parse_type(s, 'S', tm)) + .and_then(|()| parse_char(s, ' ')) + .and_then(|()| parse_type(s, 'p', tm)) + } + 's' => { + match match_digits_i64(s, 1, 18, false) { + Some(v) => { + *tm = at_utc(Timespec::new(v, 0)); + Ok(()) + }, + None => Err(ParseError::InvalidSecondsSinceEpoch) + } + } + 'S' => { + match match_digits_in_range(s, 1, 2, false, 0, 60) { + Some(v) => { tm.tm_sec = v; Ok(()) } + None => Err(ParseError::InvalidSecond) + } + } + //'s' {} + 'T' | 'X' => { + parse_type(s, 'H', tm) + .and_then(|()| parse_char(s, ':')) + .and_then(|()| parse_type(s, 'M', tm)) + .and_then(|()| parse_char(s, ':')) + .and_then(|()| parse_type(s, 'S', tm)) + } + 't' => parse_char(s, '\t'), + 'u' => { + match match_digits_in_range(s, 1, 1, false, 1, 7) { + Some(v) => { tm.tm_wday = if v == 7 { 0 } else { v }; Ok(()) } + None => Err(ParseError::InvalidDayOfWeek) + } + } + 'v' => { + parse_type(s, 'e', tm) + .and_then(|()| parse_char(s, '-')) + .and_then(|()| parse_type(s, 'b', tm)) + .and_then(|()| parse_char(s, '-')) + .and_then(|()| parse_type(s, 'Y', tm)) + } + //'W' {} + 'w' => { + match match_digits_in_range(s, 1, 1, false, 0, 6) { + Some(v) => { tm.tm_wday = v; Ok(()) } + None => Err(ParseError::InvalidDayOfWeek) + } + } + 'Y' => { + match match_digits(s, 4, 4, false) { + Some(v) => { tm.tm_year = v - 1900; Ok(()) } + None => Err(ParseError::InvalidYear) + } + } + 'y' => { + match match_digits_in_range(s, 1, 2, false, 0, 99) { + Some(v) => { tm.tm_year = v; Ok(()) } + None => Err(ParseError::InvalidYear) + } + } + 'Z' => { + if match_str(s, "UTC") || match_str(s, "GMT") { + tm.tm_utcoff = 0; + Ok(()) + } else { + // It's odd, but to maintain compatibility with c's + // strptime we ignore the timezone. + for (i, ch) in s.char_indices() { + if ch == ' ' { + *s = &s[i..]; + return Ok(()) + } + } + *s = ""; + Ok(()) + } + } + 'z' => { + if parse_char(s, 'Z').is_ok() { + tm.tm_utcoff = 0; + Ok(()) + } else { + let sign = if parse_char(s, '+').is_ok() {1} + else if parse_char(s, '-').is_ok() {-1} + else { return Err(ParseError::InvalidZoneOffset) }; + + let hours; + let minutes; + + match match_digits(s, 2, 2, false) { + Some(h) => hours = h, + None => return Err(ParseError::InvalidZoneOffset) + } + + // consume the colon if its present, + // just ignore it otherwise + let _ = parse_char(s, ':'); + + match match_digits(s, 2, 2, false) { + Some(m) => minutes = m, + None => return Err(ParseError::InvalidZoneOffset) + } + + tm.tm_utcoff = sign * (hours * 60 * 60 + minutes * 60); + Ok(()) + } + } + '%' => parse_char(s, '%'), + ch => Err(ParseError::InvalidFormatSpecifier(ch)) + } +} + + +fn match_str(s: &mut &str, needle: &str) -> bool { + if s.starts_with(needle) { + *s = &s[needle.len()..]; + true + } else { + false + } +} + +fn match_strs(ss: &mut &str, strs: &[(&str, i32)]) -> Option<i32> { + for &(needle, value) in strs.iter() { + if match_str(ss, needle) { + return Some(value) + } + } + None +} + +fn match_digits(ss: &mut &str, min_digits : usize, max_digits: usize, ws: bool) -> Option<i32> { + match match_digits_i64(ss, min_digits, max_digits, ws) { + Some(v) => Some(v as i32), + None => None + } +} + +fn match_digits_i64(ss: &mut &str, min_digits : usize, max_digits: usize, ws: bool) -> Option<i64> { + let mut value : i64 = 0; + let mut n = 0; + if ws { + let s2 = ss.trim_left_matches(" "); + n = ss.len() - s2.len(); + if n > max_digits { return None } + } + let chars = ss[n..].char_indices(); + for (_, ch) in chars.take(max_digits - n) { + match ch { + '0' ... '9' => value = value * 10 + (ch as i64 - '0' as i64), + _ => break, + } + n += 1; + } + + if n >= min_digits && n <= max_digits { + *ss = &ss[n..]; + Some(value) + } else { + None + } +} + +fn match_fractional_seconds(ss: &mut &str) -> i32 { + let mut value = 0; + let mut multiplier = NSEC_PER_SEC / 10; + + let mut chars = ss.char_indices(); + let orig = *ss; + for (i, ch) in &mut chars { + *ss = &orig[i..]; + match ch { + '0' ... '9' => { + // This will drop digits after the nanoseconds place + let digit = ch as i32 - '0' as i32; + value += digit * multiplier; + multiplier /= 10; + } + _ => break + } + } + + value +} + +fn match_digits_in_range(ss: &mut &str, + min_digits : usize, max_digits : usize, + ws: bool, min: i32, max: i32) -> Option<i32> { + let before = *ss; + match match_digits(ss, min_digits, max_digits, ws) { + Some(val) if val >= min && val <= max => Some(val), + _ => { *ss = before; None } + } +} + +fn parse_char(s: &mut &str, c: char) -> Result<(), ParseError> { + match s.char_indices().next() { + Some((i, c2)) => { + if c == c2 { + *s = &s[i + c2.len_utf8()..]; + Ok(()) + } else { + Err(ParseError::UnexpectedCharacter(c, c2)) + } + } + None => Err(ParseError::InvalidTime), + } +} diff --git a/time/src/sys.rs b/time/src/sys.rs new file mode 100644 index 000000000..56df9cc32 --- /dev/null +++ b/time/src/sys.rs @@ -0,0 +1,1048 @@ +#![allow(bad_style)] + +pub use self::inner::*; + +#[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "redox", + target_env = "sgx" +))] +mod common { + use Tm; + + pub fn time_to_tm(ts: i64, tm: &mut Tm) { + let leapyear = |year| -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) + }; + + static _ytab: [[i64; 12]; 2] = [ + [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], + [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] + ]; + + let mut year = 1970; + + let dayclock = ts % 86400; + let mut dayno = ts / 86400; + + tm.tm_sec = (dayclock % 60) as i32; + tm.tm_min = ((dayclock % 3600) / 60) as i32; + tm.tm_hour = (dayclock / 3600) as i32; + tm.tm_wday = ((dayno + 4) % 7) as i32; + loop { + let yearsize = if leapyear(year) { + 366 + } else { + 365 + }; + if dayno >= yearsize { + dayno -= yearsize; + year += 1; + } else { + break; + } + } + tm.tm_year = (year - 1900) as i32; + tm.tm_yday = dayno as i32; + let mut mon = 0; + while dayno >= _ytab[if leapyear(year) { 1 } else { 0 }][mon] { + dayno -= _ytab[if leapyear(year) { 1 } else { 0 }][mon]; + mon += 1; + } + tm.tm_mon = mon as i32; + tm.tm_mday = dayno as i32 + 1; + tm.tm_isdst = 0; + } + + pub fn tm_to_time(tm: &Tm) -> i64 { + let mut y = tm.tm_year as i64 + 1900; + let mut m = tm.tm_mon as i64 + 1; + if m <= 2 { + y -= 1; + m += 12; + } + let d = tm.tm_mday as i64; + let h = tm.tm_hour as i64; + let mi = tm.tm_min as i64; + let s = tm.tm_sec as i64; + (365*y + y/4 - y/100 + y/400 + 3*(m+1)/5 + 30*m + d - 719561) + * 86400 + 3600 * h + 60 * mi + s + } +} + +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +mod inner { + use std::ops::{Add, Sub}; + use Tm; + use Duration; + use super::common::{time_to_tm, tm_to_time}; + + #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] + pub struct SteadyTime; + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + time_to_tm(sec, tm); + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + // FIXME: Add timezone logic + time_to_tm(sec, tm); + } + + pub fn utc_tm_to_time(tm: &Tm) -> i64 { + tm_to_time(tm) + } + + pub fn local_tm_to_time(tm: &Tm) -> i64 { + // FIXME: Add timezone logic + tm_to_time(tm) + } + + pub fn get_time() -> (i64, i32) { + unimplemented!() + } + + pub fn get_precise_ns() -> u64 { + unimplemented!() + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + unimplemented!() + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, _other: SteadyTime) -> Duration { + unimplemented!() + } + } + + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, _other: Duration) -> SteadyTime { + unimplemented!() + } + } + + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(self, _other: Duration) -> SteadyTime { + unimplemented!() + } + } +} + +#[cfg(target_os = "redox")] +mod inner { + use std::fmt; + use std::cmp::Ordering; + use std::ops::{Add, Sub}; + use syscall; + use super::common::{time_to_tm, tm_to_time}; + + use Duration; + use Tm; + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + time_to_tm(sec, tm); + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + // FIXME: Add timezone logic + time_to_tm(sec, tm); + } + + pub fn utc_tm_to_time(tm: &Tm) -> i64 { + tm_to_time(tm) + } + + pub fn local_tm_to_time(tm: &Tm) -> i64 { + // FIXME: Add timezone logic + tm_to_time(tm) + } + + pub fn get_time() -> (i64, i32) { + let mut tv = syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 }; + syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut tv).unwrap(); + (tv.tv_sec as i64, tv.tv_nsec as i32) + } + + pub fn get_precise_ns() -> u64 { + let mut ts = syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 }; + syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut ts).unwrap(); + (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) + } + + #[derive(Copy)] + pub struct SteadyTime { + t: syscall::TimeSpec, + } + + impl fmt::Debug for SteadyTime { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", + self.t.tv_sec, self.t.tv_nsec) + } + } + + impl Clone for SteadyTime { + fn clone(&self) -> SteadyTime { + SteadyTime { t: self.t } + } + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + let mut t = SteadyTime { + t: syscall::TimeSpec { + tv_sec: 0, + tv_nsec: 0, + } + }; + syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut t.t).unwrap(); + t + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + if self.t.tv_nsec >= other.t.tv_nsec { + Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + + Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) + } else { + Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + + Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - + other.t.tv_nsec as i64) + } + } + } + + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + self + -other + } + } + + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(mut self, other: Duration) -> SteadyTime { + let seconds = other.num_seconds(); + let nanoseconds = other - Duration::seconds(seconds); + let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); + self.t.tv_sec += seconds; + self.t.tv_nsec += nanoseconds as i32; + if self.t.tv_nsec >= ::NSEC_PER_SEC { + self.t.tv_nsec -= ::NSEC_PER_SEC; + self.t.tv_sec += 1; + } else if self.t.tv_nsec < 0 { + self.t.tv_sec -= 1; + self.t.tv_nsec += ::NSEC_PER_SEC; + } + self + } + } + + impl PartialOrd for SteadyTime { + fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { + Some(self.cmp(other)) + } + } + + impl Ord for SteadyTime { + fn cmp(&self, other: &SteadyTime) -> Ordering { + match self.t.tv_sec.cmp(&other.t.tv_sec) { + Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), + ord => ord + } + } + } + + impl PartialEq for SteadyTime { + fn eq(&self, other: &SteadyTime) -> bool { + self.t.tv_sec == other.t.tv_sec && + self.t.tv_nsec == other.t.tv_nsec + } + } + + impl Eq for SteadyTime {} +} + +#[cfg(target_env = "sgx")] +mod inner { + use std::ops::{Add, Sub}; + use Tm; + use Duration; + use super::common::{time_to_tm, tm_to_time}; + use std::time::SystemTime; + + /// The number of nanoseconds in seconds. + const NANOS_PER_SEC: u64 = 1_000_000_000; + + #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] + pub struct SteadyTime { + t: Duration + } + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + time_to_tm(sec, tm); + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + // FIXME: Add timezone logic + time_to_tm(sec, tm); + } + + pub fn utc_tm_to_time(tm: &Tm) -> i64 { + tm_to_time(tm) + } + + pub fn local_tm_to_time(tm: &Tm) -> i64 { + // FIXME: Add timezone logic + tm_to_time(tm) + } + + pub fn get_time() -> (i64, i32) { + SteadyTime::now().t.raw() + } + + pub fn get_precise_ns() -> u64 { + // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system clock is adjusted backward. + let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + std_duration.as_secs() * NANOS_PER_SEC + std_duration.subsec_nanos() as u64 + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system clock is adjusted backward. + let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); + // This unwrap is safe because duration is well within the limits of i64. + let duration = Duration::from_std(std_duration).unwrap(); + SteadyTime { t: duration } + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + self.t - other.t + } + } + + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + SteadyTime { t: self.t - other } + } + } + + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(self, other: Duration) -> SteadyTime { + SteadyTime { t: self.t + other } + } + } +} + +#[cfg(unix)] +mod inner { + use libc::{self, time_t}; + use std::mem; + use std::io; + use Tm; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub use self::mac::*; + #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] + pub use self::unix::*; + + #[cfg(target_os = "solaris")] + extern { + static timezone: time_t; + static altzone: time_t; + } + + fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) { + tm.tm_sec = rust_tm.tm_sec; + tm.tm_min = rust_tm.tm_min; + tm.tm_hour = rust_tm.tm_hour; + tm.tm_mday = rust_tm.tm_mday; + tm.tm_mon = rust_tm.tm_mon; + tm.tm_year = rust_tm.tm_year; + tm.tm_wday = rust_tm.tm_wday; + tm.tm_yday = rust_tm.tm_yday; + tm.tm_isdst = rust_tm.tm_isdst; + } + + fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) { + rust_tm.tm_sec = tm.tm_sec; + rust_tm.tm_min = tm.tm_min; + rust_tm.tm_hour = tm.tm_hour; + rust_tm.tm_mday = tm.tm_mday; + rust_tm.tm_mon = tm.tm_mon; + rust_tm.tm_year = tm.tm_year; + rust_tm.tm_wday = tm.tm_wday; + rust_tm.tm_yday = tm.tm_yday; + rust_tm.tm_isdst = tm.tm_isdst; + rust_tm.tm_utcoff = utcoff; + } + + #[cfg(any(target_os = "nacl", target_os = "solaris"))] + unsafe fn timegm(tm: *mut libc::tm) -> time_t { + use std::env::{set_var, var_os, remove_var}; + extern { + fn tzset(); + } + + let ret; + + let current_tz = var_os("TZ"); + set_var("TZ", "UTC"); + tzset(); + + ret = libc::mktime(tm); + + if let Some(tz) = current_tz { + set_var("TZ", tz); + } else { + remove_var("TZ"); + } + tzset(); + + ret + } + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + unsafe { + let sec = sec as time_t; + let mut out = mem::zeroed(); + if libc::gmtime_r(&sec, &mut out).is_null() { + panic!("gmtime_r failed: {}", io::Error::last_os_error()); + } + tm_to_rust_tm(&out, 0, tm); + } + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + unsafe { + let sec = sec as time_t; + let mut out = mem::zeroed(); + if libc::localtime_r(&sec, &mut out).is_null() { + panic!("localtime_r failed: {}", io::Error::last_os_error()); + } + #[cfg(target_os = "solaris")] + let gmtoff = { + ::tzset(); + // < 0 means we don't know; assume we're not in DST. + if out.tm_isdst == 0 { + // timezone is seconds west of UTC, tm_gmtoff is seconds east + -timezone + } else if out.tm_isdst > 0 { + -altzone + } else { + -timezone + } + }; + #[cfg(not(target_os = "solaris"))] + let gmtoff = out.tm_gmtoff; + tm_to_rust_tm(&out, gmtoff as i32, tm); + } + } + + pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 { + #[cfg(all(target_os = "android", target_pointer_width = "32"))] + use libc::timegm64 as timegm; + #[cfg(not(any(all(target_os = "android", target_pointer_width = "32"), target_os = "nacl", target_os = "solaris")))] + use libc::timegm; + + let mut tm = unsafe { mem::zeroed() }; + rust_tm_to_tm(rust_tm, &mut tm); + unsafe { timegm(&mut tm) as i64 } + } + + pub fn local_tm_to_time(rust_tm: &Tm) -> i64 { + let mut tm = unsafe { mem::zeroed() }; + rust_tm_to_tm(rust_tm, &mut tm); + unsafe { libc::mktime(&mut tm) as i64 } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + mod mac { + use libc::{self, timeval, mach_timebase_info}; + use std::sync::{Once, ONCE_INIT}; + use std::ops::{Add, Sub}; + use Duration; + + fn info() -> &'static mach_timebase_info { + static mut INFO: mach_timebase_info = mach_timebase_info { + numer: 0, + denom: 0, + }; + static ONCE: Once = ONCE_INIT; + + unsafe { + ONCE.call_once(|| { + mach_timebase_info(&mut INFO); + }); + &INFO + } + } + + pub fn get_time() -> (i64, i32) { + use std::ptr; + let mut tv = timeval { tv_sec: 0, tv_usec: 0 }; + unsafe { libc::gettimeofday(&mut tv, ptr::null_mut()); } + (tv.tv_sec as i64, tv.tv_usec * 1000) + } + + #[inline] + pub fn get_precise_ns() -> u64 { + unsafe { + let time = libc::mach_absolute_time(); + let info = info(); + time * info.numer as u64 / info.denom as u64 + } + } + + #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] + pub struct SteadyTime { t: u64 } + + impl SteadyTime { + pub fn now() -> SteadyTime { + SteadyTime { t: get_precise_ns() } + } + } + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + Duration::nanoseconds(self.t as i64 - other.t as i64) + } + } + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + self + -other + } + } + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(self, other: Duration) -> SteadyTime { + let delta = other.num_nanoseconds().unwrap(); + SteadyTime { + t: (self.t as i64 + delta) as u64 + } + } + } + } + + #[cfg(test)] + pub struct TzReset; + + #[cfg(test)] + pub fn set_los_angeles_time_zone() -> TzReset { + use std::env; + env::set_var("TZ", "America/Los_Angeles"); + ::tzset(); + TzReset + } + + #[cfg(test)] + pub fn set_london_with_dst_time_zone() -> TzReset { + use std::env; + env::set_var("TZ", "Europe/London"); + ::tzset(); + TzReset + } + + #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] + mod unix { + use std::fmt; + use std::cmp::Ordering; + use std::ops::{Add, Sub}; + use libc; + + use Duration; + + pub fn get_time() -> (i64, i32) { + let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); } + (tv.tv_sec as i64, tv.tv_nsec as i32) + } + + pub fn get_precise_ns() -> u64 { + let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); + } + (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) + } + + #[derive(Copy)] + pub struct SteadyTime { + t: libc::timespec, + } + + impl fmt::Debug for SteadyTime { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", + self.t.tv_sec, self.t.tv_nsec) + } + } + + impl Clone for SteadyTime { + fn clone(&self) -> SteadyTime { + SteadyTime { t: self.t } + } + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + let mut t = SteadyTime { + t: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + } + }; + unsafe { + assert_eq!(0, libc::clock_gettime(libc::CLOCK_MONOTONIC, + &mut t.t)); + } + t + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + if self.t.tv_nsec >= other.t.tv_nsec { + Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + + Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) + } else { + Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + + Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - + other.t.tv_nsec as i64) + } + } + } + + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + self + -other + } + } + + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(mut self, other: Duration) -> SteadyTime { + let seconds = other.num_seconds(); + let nanoseconds = other - Duration::seconds(seconds); + let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); + + #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] + type nsec = i64; + #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] + type nsec = libc::c_long; + + self.t.tv_sec += seconds as libc::time_t; + self.t.tv_nsec += nanoseconds as nsec; + if self.t.tv_nsec >= ::NSEC_PER_SEC as nsec { + self.t.tv_nsec -= ::NSEC_PER_SEC as nsec; + self.t.tv_sec += 1; + } else if self.t.tv_nsec < 0 { + self.t.tv_sec -= 1; + self.t.tv_nsec += ::NSEC_PER_SEC as nsec; + } + self + } + } + + impl PartialOrd for SteadyTime { + fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { + Some(self.cmp(other)) + } + } + + impl Ord for SteadyTime { + fn cmp(&self, other: &SteadyTime) -> Ordering { + match self.t.tv_sec.cmp(&other.t.tv_sec) { + Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), + ord => ord + } + } + } + + impl PartialEq for SteadyTime { + fn eq(&self, other: &SteadyTime) -> bool { + self.t.tv_sec == other.t.tv_sec && + self.t.tv_nsec == other.t.tv_nsec + } + } + + impl Eq for SteadyTime {} + + } +} + +#[cfg(windows)] +#[allow(non_snake_case)] +mod inner { + use std::io; + use std::mem; + use std::sync::{Once, ONCE_INIT}; + use std::ops::{Add, Sub}; + use {Tm, Duration}; + + use winapi::um::winnt::*; + use winapi::shared::minwindef::*; + use winapi::um::minwinbase::SYSTEMTIME; + use winapi::um::profileapi::*; + use winapi::um::timezoneapi::*; + use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; + + fn frequency() -> i64 { + static mut FREQUENCY: i64 = 0; + static ONCE: Once = ONCE_INIT; + + unsafe { + ONCE.call_once(|| { + let mut l = i64_to_large_integer(0); + QueryPerformanceFrequency(&mut l); + FREQUENCY = large_integer_to_i64(l); + }); + FREQUENCY + } + } + + fn i64_to_large_integer(i: i64) -> LARGE_INTEGER { + unsafe { + let mut large_integer: LARGE_INTEGER = mem::zeroed(); + *large_integer.QuadPart_mut() = i; + large_integer + } + } + + fn large_integer_to_i64(l: LARGE_INTEGER) -> i64 { + unsafe { + *l.QuadPart() + } + } + + const HECTONANOSECS_IN_SEC: i64 = 10_000_000; + const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; + + fn time_to_file_time(sec: i64) -> FILETIME { + let t = (((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH)) as u64; + FILETIME { + dwLowDateTime: t as DWORD, + dwHighDateTime: (t >> 32) as DWORD + } + } + + fn file_time_as_u64(ft: &FILETIME) -> u64 { + ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) + } + + fn file_time_to_nsec(ft: &FILETIME) -> i32 { + let t = file_time_as_u64(ft) as i64; + ((t % HECTONANOSECS_IN_SEC) * 100) as i32 + } + + fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { + let t = file_time_as_u64(ft) as i64; + ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 + } + + fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { + unsafe { + let mut ft = mem::zeroed(); + SystemTimeToFileTime(sys, &mut ft); + ft + } + } + + fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { + let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; + sys.wSecond = tm.tm_sec as WORD; + sys.wMinute = tm.tm_min as WORD; + sys.wHour = tm.tm_hour as WORD; + sys.wDay = tm.tm_mday as WORD; + sys.wDayOfWeek = tm.tm_wday as WORD; + sys.wMonth = (tm.tm_mon + 1) as WORD; + sys.wYear = (tm.tm_year + 1900) as WORD; + sys + } + + fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { + tm.tm_sec = sys.wSecond as i32; + tm.tm_min = sys.wMinute as i32; + tm.tm_hour = sys.wHour as i32; + tm.tm_mday = sys.wDay as i32; + tm.tm_wday = sys.wDayOfWeek as i32; + tm.tm_mon = (sys.wMonth - 1) as i32; + tm.tm_year = (sys.wYear - 1900) as i32; + tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); + + fn yday(year: i32, month: i32, day: i32) -> i32 { + let leap = if month > 2 { + if year % 4 == 0 { 1 } else { 2 } + } else { + 0 + }; + let july = if month > 7 { 1 } else { 0 }; + + (month - 1) * 30 + month / 2 + (day - 1) - leap + july + } + } + + macro_rules! call { + ($name:ident($($arg:expr),*)) => { + if $name($($arg),*) == 0 { + panic!(concat!(stringify!($name), " failed with: {}"), + io::Error::last_os_error()); + } + } + } + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + let mut out = unsafe { mem::zeroed() }; + let ft = time_to_file_time(sec); + unsafe { + call!(FileTimeToSystemTime(&ft, &mut out)); + } + system_time_to_tm(&out, tm); + tm.tm_utcoff = 0; + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + let ft = time_to_file_time(sec); + unsafe { + let mut utc = mem::zeroed(); + let mut local = mem::zeroed(); + call!(FileTimeToSystemTime(&ft, &mut utc)); + call!(SystemTimeToTzSpecificLocalTime(0 as *const _, + &mut utc, &mut local)); + system_time_to_tm(&local, tm); + + let local = system_time_to_file_time(&local); + let local_sec = file_time_to_unix_seconds(&local); + + let mut tz = mem::zeroed(); + GetTimeZoneInformation(&mut tz); + + // SystemTimeToTzSpecificLocalTime already applied the biases so + // check if it non standard + tm.tm_utcoff = (local_sec - sec) as i32; + tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { + 0 + } else { + 1 + }; + } + } + + pub fn utc_tm_to_time(tm: &Tm) -> i64 { + unsafe { + let mut ft = mem::zeroed(); + let sys_time = tm_to_system_time(tm); + call!(SystemTimeToFileTime(&sys_time, &mut ft)); + file_time_to_unix_seconds(&ft) + } + } + + pub fn local_tm_to_time(tm: &Tm) -> i64 { + unsafe { + let mut ft = mem::zeroed(); + let mut utc = mem::zeroed(); + let mut sys_time = tm_to_system_time(tm); + call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, + &mut sys_time, &mut utc)); + call!(SystemTimeToFileTime(&utc, &mut ft)); + file_time_to_unix_seconds(&ft) + } + } + + pub fn get_time() -> (i64, i32) { + unsafe { + let mut ft = mem::zeroed(); + GetSystemTimeAsFileTime(&mut ft); + (file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft)) + } + } + + pub fn get_precise_ns() -> u64 { + let mut ticks = i64_to_large_integer(0); + unsafe { + assert!(QueryPerformanceCounter(&mut ticks) == 1); + } + mul_div_i64(large_integer_to_i64(ticks), 1000000000, frequency()) as u64 + + } + + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct SteadyTime { + t: i64, + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + let mut l = i64_to_large_integer(0); + unsafe { QueryPerformanceCounter(&mut l); } + SteadyTime { t : large_integer_to_i64(l) } + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + let diff = self.t as i64 - other.t as i64; + Duration::nanoseconds(mul_div_i64(diff, 1000000000, + frequency())) + } + } + + impl Sub<Duration> for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + self + -other + } + } + + impl Add<Duration> for SteadyTime { + type Output = SteadyTime; + fn add(mut self, other: Duration) -> SteadyTime { + self.t += (other.num_microseconds().unwrap() * frequency() / + 1_000_000) as i64; + self + } + } + + #[cfg(test)] + pub struct TzReset { + old: TIME_ZONE_INFORMATION, + } + + #[cfg(test)] + impl Drop for TzReset { + fn drop(&mut self) { + unsafe { + call!(SetTimeZoneInformation(&self.old)); + } + } + } + + #[cfg(test)] + pub fn set_los_angeles_time_zone() -> TzReset { + acquire_privileges(); + + unsafe { + let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); + GetTimeZoneInformation(&mut tz); + let ret = TzReset { old: tz }; + tz.Bias = 60 * 8; + call!(SetTimeZoneInformation(&tz)); + return ret + } + } + + #[cfg(test)] + pub fn set_london_with_dst_time_zone() -> TzReset { + acquire_privileges(); + + unsafe { + let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); + GetTimeZoneInformation(&mut tz); + let ret = TzReset { old: tz }; + // Since date set precisely this is 2015's dates + tz.Bias = 0; + tz.DaylightBias = -60; + tz.DaylightDate.wYear = 0; + tz.DaylightDate.wMonth = 3; + tz.DaylightDate.wDayOfWeek = 0; + tz.DaylightDate.wDay = 5; + tz.DaylightDate.wHour = 2; + tz.StandardBias = 0; + tz.StandardDate.wYear = 0; + tz.StandardDate.wMonth = 10; + tz.StandardDate.wDayOfWeek = 0; + tz.StandardDate.wDay = 5; + tz.StandardDate.wHour = 2; + call!(SetTimeZoneInformation(&tz)); + return ret + } + } + + // Ensures that this process has the necessary privileges to set a new time + // zone, and this is all transcribed from: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724944%28v=vs.85%29.aspx + #[cfg(test)] + fn acquire_privileges() { + use std::sync::{ONCE_INIT, Once}; + use winapi::um::processthreadsapi::*; + use winapi::um::winbase::LookupPrivilegeValueA; + const SE_PRIVILEGE_ENABLED: DWORD = 2; + static INIT: Once = ONCE_INIT; + + // TODO: FIXME + extern "system" { + fn AdjustTokenPrivileges( + TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES, + BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD, + ) -> BOOL; + } + + #[repr(C)] + struct TKP { + tkp: TOKEN_PRIVILEGES, + laa: LUID_AND_ATTRIBUTES, + } + + INIT.call_once(|| unsafe { + let mut hToken = 0 as *mut _; + call!(OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &mut hToken)); + + let mut tkp = mem::zeroed::<TKP>(); + assert_eq!(tkp.tkp.Privileges.len(), 0); + let c = ::std::ffi::CString::new("SeTimeZonePrivilege").unwrap(); + call!(LookupPrivilegeValueA(0 as *const _, c.as_ptr(), + &mut tkp.laa.Luid)); + tkp.tkp.PrivilegeCount = 1; + tkp.laa.Attributes = SE_PRIVILEGE_ENABLED; + call!(AdjustTokenPrivileges(hToken, FALSE, &mut tkp.tkp, 0, + 0 as *mut _, 0 as *mut _)); + }); + } + + + + // Computes (value*numer)/denom without overflow, as long as both + // (numer*denom) and the overall result fit into i64 (which is the case + // for our time conversions). + fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numer)/denom and simplify. + // r < denom, so (denom*numer) is the upper bound of (r*numer) + q * numer + r * numer / denom + } + + #[test] + fn test_muldiv() { + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), + 1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), + -1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), + 1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), + -1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), + 1_000_000_000_001_000); + } +} diff --git a/toml/.cargo-checksum.json b/toml/.cargo-checksum.json new file mode 100644 index 000000000..120672e39 --- /dev/null +++ b/toml/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"} \ No newline at end of file diff --git a/toml/Cargo.toml b/toml/Cargo.toml new file mode 100644 index 000000000..6e5462128 --- /dev/null +++ b/toml/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "toml" +version = "0.4.10" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +description = "A native Rust encoder and decoder of TOML-formatted files and streams. Provides\nimplementations of the standard Serialize/Deserialize traits for TOML data to\nfacilitate deserializing and serializing Rust structures.\n" +homepage = "https://github.com/alexcrichton/toml-rs" +documentation = "https://docs.rs/toml" +readme = "README.md" +keywords = ["encoding"] +categories = ["config", "encoding", "parser-implementations"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/toml-rs" +[dependencies.serde] +version = "1.0" +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" +[badges.travis-ci] +repository = "alexcrichton/toml-rs" diff --git a/toml/LICENSE-APACHE b/toml/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/toml/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/toml/LICENSE-MIT b/toml/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/toml/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/toml/README.md b/toml/README.md new file mode 100644 index 000000000..6424c1fe6 --- /dev/null +++ b/toml/README.md @@ -0,0 +1,40 @@ +# toml-rs + +[![Build Status](https://travis-ci.org/alexcrichton/toml-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/toml-rs) +[![Coverage Status](https://coveralls.io/repos/alexcrichton/toml-rs/badge.svg?branch=master&service=github)](https://coveralls.io/github/alexcrichton/toml-rs?branch=master) +[![Latest Version](https://img.shields.io/crates/v/toml.svg)](https://crates.io/crates/toml) +[![Documentation](https://docs.rs/toml/badge.svg)](https://docs.rs/toml) + +A [TOML][toml] decoder and encoder for Rust. This library is currently compliant +with the v0.5.0 version of TOML. This library will also likely continue to stay +up to date with the TOML specification as changes happen. + +[toml]: https://github.com/toml-lang/toml + +```toml +# Cargo.toml +[dependencies] +toml = "0.4" +``` + +This crate also supports serialization/deserialization through the +[serde](https://serde.rs) crate on crates.io. Currently the older `rustc-serialize` +crate is not supported in the 0.3+ series of the `toml` crate, but 0.2 can be +used for that support. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in toml-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/toml/examples/decode.rs b/toml/examples/decode.rs new file mode 100644 index 000000000..e8ce58611 --- /dev/null +++ b/toml/examples/decode.rs @@ -0,0 +1,55 @@ +//! An example showing off the usage of `Deserialize` to automatically decode +//! TOML into a Rust `struct` + +#![deny(warnings)] + +extern crate toml; +#[macro_use] +extern crate serde_derive; + +/// This is what we're going to decode into. Each field is optional, meaning +/// that it doesn't have to be present in TOML. +#[derive(Debug, Deserialize)] +struct Config { + global_string: Option<String>, + global_integer: Option<u64>, + server: Option<ServerConfig>, + peers: Option<Vec<PeerConfig>>, +} + +/// Sub-structs are decoded from tables, so this will decode from the `[server]` +/// table. +/// +/// Again, each field is optional, meaning they don't have to be present. +#[derive(Debug, Deserialize)] +struct ServerConfig { + ip: Option<String>, + port: Option<u64>, +} + +#[derive(Debug, Deserialize)] +struct PeerConfig { + ip: Option<String>, + port: Option<u64>, +} + +fn main() { + let toml_str = r#" + global_string = "test" + global_integer = 5 + + [server] + ip = "127.0.0.1" + port = 80 + + [[peers]] + ip = "127.0.0.1" + port = 8080 + + [[peers]] + ip = "127.0.0.1" + "#; + + let decoded: Config = toml::from_str(toml_str).unwrap(); + println!("{:#?}", decoded); +} diff --git a/toml/examples/enum_external.rs b/toml/examples/enum_external.rs new file mode 100644 index 000000000..e2ac4f8e7 --- /dev/null +++ b/toml/examples/enum_external.rs @@ -0,0 +1,46 @@ +//! An example showing off the usage of `Deserialize` to automatically decode +//! TOML into a Rust `struct`, with enums. + +#![deny(warnings)] + +extern crate toml; +#[macro_use] +extern crate serde_derive; + +/// This is what we're going to decode into. +#[derive(Debug, Deserialize)] +struct Config { + plain: MyEnum, + plain_table: MyEnum, + tuple: MyEnum, + #[serde(rename = "struct")] + structv: MyEnum, + newtype: MyEnum, + my_enum: Vec<MyEnum>, +} + +#[derive(Debug, Deserialize)] +enum MyEnum { + Plain, + Tuple(i64, bool), + NewType(String), + Struct { value: i64 }, +} + +fn main() { + let toml_str = r#" + plain = "Plain" + plain_table = { Plain = {} } + tuple = { Tuple = { 0 = 123, 1 = true } } + struct = { Struct = { value = 123 } } + newtype = { NewType = "value" } + my_enum = [ + { Plain = {} }, + { Tuple = { 0 = 123, 1 = true } }, + { NewType = "value" }, + { Struct = { value = 123 } } + ]"#; + + let decoded: Config = toml::from_str(toml_str).unwrap(); + println!("{:#?}", decoded); +} diff --git a/toml/examples/toml2json.rs b/toml/examples/toml2json.rs new file mode 100644 index 000000000..1ed441a93 --- /dev/null +++ b/toml/examples/toml2json.rs @@ -0,0 +1,51 @@ +#![deny(warnings)] + +extern crate toml; +extern crate serde_json; + +use std::fs::File; +use std::env; +use std::io; +use std::io::prelude::*; + +use toml::Value as Toml; +use serde_json::Value as Json; + +fn main() { + let mut args = env::args(); + let mut input = String::new(); + if args.len() > 1 { + let name = args.nth(1).unwrap(); + File::open(&name).and_then(|mut f| { + f.read_to_string(&mut input) + }).unwrap(); + } else { + io::stdin().read_to_string(&mut input).unwrap(); + } + + match input.parse() { + Ok(toml) => { + let json = convert(toml); + println!("{}", serde_json::to_string_pretty(&json).unwrap()); + } + Err(error) => println!("failed to parse TOML: {}", error), + } +} + +fn convert(toml: Toml) -> Json { + match toml { + Toml::String(s) => Json::String(s), + Toml::Integer(i) => Json::Number(i.into()), + Toml::Float(f) => { + let n = serde_json::Number::from_f64(f) + .expect("float infinite and nan not allowed"); + Json::Number(n) + } + Toml::Boolean(b) => Json::Bool(b), + Toml::Array(arr) => Json::Array(arr.into_iter().map(convert).collect()), + Toml::Table(table) => Json::Object(table.into_iter().map(|(k, v)| { + (k, convert(v)) + }).collect()), + Toml::Datetime(dt) => Json::String(dt.to_string()), + } +} diff --git a/toml/src/datetime.rs b/toml/src/datetime.rs new file mode 100644 index 000000000..3678f582a --- /dev/null +++ b/toml/src/datetime.rs @@ -0,0 +1,424 @@ +use std::fmt; +use std::str::{self, FromStr}; +use std::error; + +use serde::{de, ser}; + +/// A parsed TOML datetime value +/// +/// This structure is intended to represent the datetime primitive type that can +/// be encoded into TOML documents. This type is a parsed version that contains +/// all metadata internally. +/// +/// Currently this type is intentionally conservative and only supports +/// `to_string` as an accessor. Over time though it's intended that it'll grow +/// more support! +/// +/// Note that if you're using `Deserialize` to deserialize a TOML document, you +/// can use this as a placeholder for where you're expecting a datetime to be +/// specified. +/// +/// Also note though that while this type implements `Serialize` and +/// `Deserialize` it's only recommended to use this type with the TOML format, +/// otherwise encoded in other formats it may look a little odd. +#[derive(PartialEq, Clone)] +pub struct Datetime { + date: Option<Date>, + time: Option<Time>, + offset: Option<Offset>, +} + +/// Error returned from parsing a `Datetime` in the `FromStr` implementation. +#[derive(Debug, Clone)] +pub struct DatetimeParseError { + _private: (), +} + +// Currently serde itself doesn't have a datetime type, so we map our `Datetime` +// to a special valid in the serde data model. Namely one with thiese special +// fields/struct names. +// +// In general the TOML encoder/decoder will catch this and not literally emit +// these strings but rather emit datetimes as they're intended. +pub const FIELD: &'static str = "$__toml_private_datetime"; +pub const NAME: &'static str = "$__toml_private_Datetime"; + +#[derive(PartialEq, Clone)] +struct Date { + year: u16, + month: u8, + day: u8, +} + +#[derive(PartialEq, Clone)] +struct Time { + hour: u8, + minute: u8, + second: u8, + nanosecond: u32, +} + +#[derive(PartialEq, Clone)] +enum Offset { + Z, + Custom { hours: i8, minutes: u8 }, +} + +impl fmt::Debug for Datetime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for Datetime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref date) = self.date { + write!(f, "{}", date)?; + } + if let Some(ref time) = self.time { + if self.date.is_some() { + write!(f, "T")?; + } + write!(f, "{}", time)?; + } + if let Some(ref offset) = self.offset { + write!(f, "{}", offset)?; + } + Ok(()) + } +} + +impl fmt::Display for Date { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day) + } +} + +impl fmt::Display for Time { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)?; + if self.nanosecond != 0 { + let s = format!("{:09}", self.nanosecond); + write!(f, ".{}", s.trim_right_matches('0'))?; + } + Ok(()) + } +} + +impl fmt::Display for Offset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Offset::Z => write!(f, "Z"), + Offset::Custom { hours, minutes } => { + write!(f, "{:+03}:{:02}", hours, minutes) + } + } + } +} + +impl FromStr for Datetime { + type Err = DatetimeParseError; + + fn from_str(date: &str) -> Result<Datetime, DatetimeParseError> { + // Accepted formats: + // + // 0000-00-00T00:00:00.00Z + // 0000-00-00T00:00:00.00 + // 0000-00-00 + // 00:00:00.00 + if date.len() < 3 { + return Err(DatetimeParseError { _private: () }) + } + let mut offset_allowed = true; + let mut chars = date.chars(); + + // First up, parse the full date if we can + let full_date = if chars.clone().nth(2) == Some(':') { + offset_allowed = false; + None + } else { + let y1 = digit(&mut chars)? as u16; + let y2 = digit(&mut chars)? as u16; + let y3 = digit(&mut chars)? as u16; + let y4 = digit(&mut chars)? as u16; + + match chars.next() { + Some('-') => {} + _ => return Err(DatetimeParseError { _private: () }), + } + + let m1 = digit(&mut chars)?; + let m2 = digit(&mut chars)?; + + match chars.next() { + Some('-') => {} + _ => return Err(DatetimeParseError { _private: () }), + } + + let d1 = digit(&mut chars)?; + let d2 = digit(&mut chars)?; + + let date = Date { + year: y1 * 1000 + y2 * 100 + y3 * 10 + y4, + month: m1 * 10 + m2, + day: d1 * 10 + d2, + }; + + if date.month < 1 || date.month > 12 { + return Err(DatetimeParseError { _private: () }) + } + if date.day < 1 || date.day > 31 { + return Err(DatetimeParseError { _private: () }) + } + + Some(date) + }; + + // Next parse the "partial-time" if available + let partial_time = if full_date.is_some() && + (chars.clone().next() == Some('T') + || chars.clone().next() == Some(' ')) { + chars.next(); + true + } else { + full_date.is_none() + }; + + let time = if partial_time { + let h1 = digit(&mut chars)?; + let h2 = digit(&mut chars)?; + match chars.next() { + Some(':') => {} + _ => return Err(DatetimeParseError { _private: () }), + } + let m1 = digit(&mut chars)?; + let m2 = digit(&mut chars)?; + match chars.next() { + Some(':') => {} + _ => return Err(DatetimeParseError { _private: () }), + } + let s1 = digit(&mut chars)?; + let s2 = digit(&mut chars)?; + + let mut nanosecond = 0; + if chars.clone().next() == Some('.') { + chars.next(); + let whole = chars.as_str(); + + let mut end = whole.len(); + for (i, byte) in whole.bytes().enumerate() { + match byte { + b'0' ... b'9' => { + if i < 9 { + let p = 10_u32.pow(8 - i as u32); + nanosecond += p * (byte - b'0') as u32; + } + } + _ => { + end = i; + break; + } + } + } + if end == 0 { + return Err(DatetimeParseError { _private: () }) + } + chars = whole[end..].chars(); + } + + let time = Time { + hour: h1 * 10 + h2, + minute: m1 * 10 + m2, + second: s1 * 10 + s2, + nanosecond: nanosecond, + }; + + if time.hour > 24 { + return Err(DatetimeParseError { _private: () }) + } + if time.minute > 59 { + return Err(DatetimeParseError { _private: () }) + } + if time.second > 59 { + return Err(DatetimeParseError { _private: () }) + } + if time.nanosecond > 999_999_999 { + return Err(DatetimeParseError { _private: () }) + } + + Some(time) + } else { + offset_allowed = false; + None + }; + + // And finally, parse the offset + let offset = if offset_allowed { + let next = chars.clone().next(); + if next == Some('Z') { + chars.next(); + Some(Offset::Z) + } else if next.is_none() { + None + } else { + let sign = match next { + Some('+') => 1, + Some('-') => -1, + _ => return Err(DatetimeParseError { _private: () }), + }; + chars.next(); + let h1 = digit(&mut chars)? as i8; + let h2 = digit(&mut chars)? as i8; + match chars.next() { + Some(':') => {} + _ => return Err(DatetimeParseError { _private: () }), + } + let m1 = digit(&mut chars)?; + let m2 = digit(&mut chars)?; + + Some(Offset::Custom { + hours: sign * (h1 * 10 + h2), + minutes: m1 * 10 + m2, + }) + } + } else { + None + }; + + // Return an error if we didn't hit eof, otherwise return our parsed + // date + if chars.next().is_some() { + return Err(DatetimeParseError { _private: () }) + } + + Ok(Datetime { + date: full_date, + time: time, + offset: offset, + }) + } +} + +fn digit(chars: &mut str::Chars) -> Result<u8, DatetimeParseError> { + match chars.next() { + Some(c) if '0' <= c && c <= '9' => Ok(c as u8 - b'0'), + _ => Err(DatetimeParseError { _private: () }), + } +} + +impl ser::Serialize for Datetime { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: ser::Serializer + { + use serde::ser::SerializeStruct; + + let mut s = serializer.serialize_struct(NAME, 1)?; + s.serialize_field(FIELD, &self.to_string())?; + s.end() + } +} + +impl<'de> de::Deserialize<'de> for Datetime { + fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error> + where D: de::Deserializer<'de> + { + struct DatetimeVisitor; + + impl<'de> de::Visitor<'de> for DatetimeVisitor { + type Value = Datetime; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a TOML datetime") + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error> + where V: de::MapAccess<'de> + { + let value = visitor.next_key::<DatetimeKey>()?; + if value.is_none() { + return Err(de::Error::custom("datetime key not found")) + } + let v: DatetimeFromString = visitor.next_value()?; + Ok(v.value) + + } + } + + static FIELDS: [&'static str; 1] = [FIELD]; + deserializer.deserialize_struct(NAME, &FIELDS, DatetimeVisitor) + } +} + +struct DatetimeKey; + +impl<'de> de::Deserialize<'de> for DatetimeKey { + fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error> + where D: de::Deserializer<'de> + { + struct FieldVisitor; + + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid datetime field") + } + + fn visit_str<E>(self, s: &str) -> Result<(), E> + where E: de::Error + { + if s == FIELD { + Ok(()) + } else { + Err(de::Error::custom("expected field with custom name")) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok(DatetimeKey) + } +} + +pub struct DatetimeFromString { + pub value: Datetime, +} + +impl<'de> de::Deserialize<'de> for DatetimeFromString { + fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error> + where D: de::Deserializer<'de> + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = DatetimeFromString; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("string containing a datetime") + } + + fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E> + where E: de::Error, + { + match s.parse() { + Ok(date) => Ok(DatetimeFromString { value: date }), + Err(e) => Err(de::Error::custom(e)), + } + } + } + + deserializer.deserialize_str(Visitor) + } +} + +impl fmt::Display for DatetimeParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "failed to parse datetime".fmt(f) + } +} + +impl error::Error for DatetimeParseError { + fn description(&self) -> &str { + "failed to parse datetime" + } +} diff --git a/toml/src/de.rs b/toml/src/de.rs new file mode 100644 index 000000000..9334cd38f --- /dev/null +++ b/toml/src/de.rs @@ -0,0 +1,1861 @@ +//! Deserializing TOML into Rust structures. +//! +//! This module contains all the Serde support for deserializing TOML documents +//! into Rust structures. Note that some top-level functions here are also +//! provided at the top of the crate. + +use std::borrow::Cow; +use std::error; +use std::f64; +use std::fmt; +use std::str; +use std::vec; + +use serde::de; +use serde::de::IntoDeserializer; +use serde::de::value::BorrowedStrDeserializer; + +use tokens::{Tokenizer, Token, Error as TokenError, Span}; +use datetime; +use spanned; + +/// Deserializes a byte slice into a type. +/// +/// This function will attempt to interpret `bytes` as UTF-8 data and then +/// deserialize `T` from the TOML document provided. +pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T, Error> + where T: de::Deserialize<'de>, +{ + match str::from_utf8(bytes) { + Ok(s) => from_str(s), + Err(e) => Err(Error::custom(e.to_string())), + } +} + +/// Deserializes a string into a type. +/// +/// This function will attempt to interpret `s` as a TOML document and +/// deserialize `T` from the document. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate serde_derive; +/// extern crate toml; +/// +/// #[derive(Deserialize)] +/// struct Config { +/// title: String, +/// owner: Owner, +/// } +/// +/// #[derive(Deserialize)] +/// struct Owner { +/// name: String, +/// } +/// +/// fn main() { +/// let config: Config = toml::from_str(r#" +/// title = 'TOML Example' +/// +/// [owner] +/// name = 'Lisa' +/// "#).unwrap(); +/// +/// assert_eq!(config.title, "TOML Example"); +/// assert_eq!(config.owner.name, "Lisa"); +/// } +/// ``` +pub fn from_str<'de, T>(s: &'de str) -> Result<T, Error> + where T: de::Deserialize<'de>, +{ + let mut d = Deserializer::new(s); + let ret = T::deserialize(&mut d)?; + d.end()?; + Ok(ret) +} + +/// Errors that can occur when deserializing a type. +#[derive(Debug, Clone)] +pub struct Error { + inner: Box<ErrorInner>, +} + +#[derive(Debug, Clone)] +struct ErrorInner { + kind: ErrorKind, + line: Option<usize>, + col: usize, + message: String, + key: Vec<String>, +} + +/// Errors that can occur when deserializing a type. +#[derive(Debug, Clone)] +enum ErrorKind { + /// EOF was reached when looking for a value + UnexpectedEof, + + /// An invalid character not allowed in a string was found + InvalidCharInString(char), + + /// An invalid character was found as an escape + InvalidEscape(char), + + /// An invalid character was found in a hex escape + InvalidHexEscape(char), + + /// An invalid escape value was specified in a hex escape in a string. + /// + /// Valid values are in the plane of unicode codepoints. + InvalidEscapeValue(u32), + + /// A newline in a string was encountered when one was not allowed. + NewlineInString, + + /// An unexpected character was encountered, typically when looking for a + /// value. + Unexpected(char), + + /// An unterminated string was found where EOF was found before the ending + /// EOF mark. + UnterminatedString, + + /// A newline was found in a table key. + NewlineInTableKey, + + /// A number failed to parse + NumberInvalid, + + /// A date or datetime was invalid + DateInvalid, + + /// Wanted one sort of token, but found another. + Wanted { + /// Expected token type + expected: &'static str, + /// Actually found token type + found: &'static str, + }, + + /// An array was decoded but the types inside of it were mixed, which is + /// disallowed by TOML. + MixedArrayType, + + /// A duplicate table definition was found. + DuplicateTable(String), + + /// A previously defined table was redefined as an array. + RedefineAsArray, + + /// An empty table key was found. + EmptyTableKey, + + /// Multiline strings are not allowed for key + MultilineStringKey, + + /// A custom error which could be generated when deserializing a particular + /// type. + Custom, + + /// A tuple with a certain number of elements was expected but something + /// else was found. + ExpectedTuple(usize), + + /// Expected table keys to be in increasing tuple index order, but something + /// else was found. + ExpectedTupleIndex { + /// Expected index. + expected: usize, + /// Key that was specified. + found: String, + }, + + /// An empty table was expected but entries were found + ExpectedEmptyTable, + + /// Dotted key attempted to extend something that is not a table. + DottedKeyInvalidType, + + /// An unexpected key was encountered. + /// + /// Used when deserializing a struct with a limited set of fields. + UnexpectedKeys { + /// The unexpected keys. + keys: Vec<String>, + /// Keys that may be specified. + available: &'static [&'static str], + }, + + #[doc(hidden)] + __Nonexhaustive, +} + +/// Deserialization implementation for TOML. +pub struct Deserializer<'a> { + require_newline_after_table: bool, + input: &'a str, + tokens: Tokenizer<'a>, +} + +impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + + let mut tables = self.tables()?; + + visitor.visit_map(MapVisitor { + values: Vec::new().into_iter(), + next_value: None, + depth: 0, + cur: 0, + cur_parent: 0, + max: tables.len(), + tables: &mut tables, + array: false, + de: self, + }) + } + + // Called when the type to deserialize is an enum, as opposed to a field in the type. + fn deserialize_enum<V>( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V + ) -> Result<V::Value, Error> + where V: de::Visitor<'de> + { + let (value, name) = self.string_or_table()?; + match value.e { + E::String(val) => visitor.visit_enum(val.into_deserializer()), + E::InlineTable(values) => { + if values.len() != 1 { + Err(Error::from_kind(ErrorKind::Wanted { + expected: "exactly 1 element", + found: if values.is_empty() { + "zero elements" + } else { + "more than 1 element" + }, + })) + } else { + visitor.visit_enum(InlineTableDeserializer { + values: values.into_iter(), + next_value: None, + }) + } + } + E::DottedTable(_) => visitor.visit_enum(DottedTableDeserializer { + name: name.expect("Expected table header to be passed."), + value: value, + }), + e @ _ => Err(Error::from_kind(ErrorKind::Wanted { + expected: "string or table", + found: e.type_name(), + })), + } + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map struct unit newtype_struct + ignored_any unit_struct tuple_struct tuple option identifier + } +} + +struct Table<'a> { + at: usize, + header: Vec<Cow<'a, str>>, + values: Option<Vec<(Cow<'a, str>, Value<'a>)>>, + array: bool, +} + +#[doc(hidden)] +pub struct MapVisitor<'de: 'b, 'b> { + values: vec::IntoIter<(Cow<'de, str>, Value<'de>)>, + next_value: Option<(Cow<'de, str>, Value<'de>)>, + depth: usize, + cur: usize, + cur_parent: usize, + max: usize, + tables: &'b mut [Table<'de>], + array: bool, + de: &'b mut Deserializer<'de>, +} + +impl<'de, 'b> de::MapAccess<'de> for MapVisitor<'de, 'b> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where K: de::DeserializeSeed<'de>, + { + if self.cur_parent == self.max || self.cur == self.max { + return Ok(None) + } + + loop { + assert!(self.next_value.is_none()); + if let Some((key, value)) = self.values.next() { + let ret = seed.deserialize(StrDeserializer::new(key.clone()))?; + self.next_value = Some((key, value)); + return Ok(Some(ret)) + } + + let next_table = { + let prefix = &self.tables[self.cur_parent].header[..self.depth]; + self.tables[self.cur..self.max].iter().enumerate().find(|&(_, t)| { + if t.values.is_none() { + return false + } + match t.header.get(..self.depth) { + Some(header) => header == prefix, + None => false, + } + }).map(|(i, _)| i + self.cur) + }; + + let pos = match next_table { + Some(pos) => pos, + None => return Ok(None), + }; + self.cur = pos; + + // Test to see if we're duplicating our parent's table, and if so + // then this is an error in the toml format + if self.cur_parent != pos && + self.tables[self.cur_parent].header == self.tables[pos].header { + let at = self.tables[pos].at; + let name = self.tables[pos].header.join("."); + return Err(self.de.error(at, ErrorKind::DuplicateTable(name))) + } + + let table = &mut self.tables[pos]; + + // If we're not yet at the appropriate depth for this table then we + // just next the next portion of its header and then continue + // decoding. + if self.depth != table.header.len() { + let key = &table.header[self.depth]; + let key = seed.deserialize(StrDeserializer::new(key.clone()))?; + return Ok(Some(key)) + } + + // Rule out cases like: + // + // [[foo.bar]] + // [[foo]] + if table.array { + let kind = ErrorKind::RedefineAsArray; + return Err(self.de.error(table.at, kind)) + } + + self.values = table.values.take().expect("Unable to read table values").into_iter(); + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where V: de::DeserializeSeed<'de>, + { + if let Some((k, v)) = self.next_value.take() { + match seed.deserialize(ValueDeserializer::new(v)) { + Ok(v) => return Ok(v), + Err(mut e) => { + e.add_key_context(&k); + return Err(e) + } + } + } + + let array = self.tables[self.cur].array && + self.depth == self.tables[self.cur].header.len() - 1; + self.cur += 1; + let res = seed.deserialize(MapVisitor { + values: Vec::new().into_iter(), + next_value: None, + depth: self.depth + if array {0} else {1}, + cur_parent: self.cur - 1, + cur: 0, + max: self.max, + array: array, + tables: &mut *self.tables, + de: &mut *self.de, + }); + res.map_err(|mut e| { + e.add_key_context(&self.tables[self.cur - 1].header[self.depth]); + e + }) + } +} + +impl<'de, 'b> de::SeqAccess<'de> for MapVisitor<'de, 'b> { + type Error = Error; + + fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where K: de::DeserializeSeed<'de>, + { + assert!(self.next_value.is_none()); + assert!(self.values.next().is_none()); + + if self.cur_parent == self.max { + return Ok(None) + } + + let next = self.tables[..self.max] + .iter() + .enumerate() + .skip(self.cur_parent + 1) + .find(|&(_, table)| { + table.array && table.header == self.tables[self.cur_parent].header + }).map(|p| p.0) + .unwrap_or(self.max); + + let ret = seed.deserialize(MapVisitor { + values: self.tables[self.cur_parent].values.take().expect("Unable to read table values").into_iter(), + next_value: None, + depth: self.depth + 1, + cur_parent: self.cur_parent, + max: next, + cur: 0, + array: false, + tables: &mut self.tables, + de: &mut self.de, + })?; + self.cur_parent = next; + Ok(Some(ret)) + } +} + +impl<'de, 'b> de::Deserializer<'de> for MapVisitor<'de, 'b> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + if self.array { + visitor.visit_seq(self) + } else { + visitor.visit_map(self) + } + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + visitor.visit_some(self) + } + + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V + ) -> Result<V::Value, Error> + where V: de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map struct unit identifier + ignored_any unit_struct tuple_struct tuple enum + } +} + +struct StrDeserializer<'a> { + key: Cow<'a, str>, +} + +impl<'a> StrDeserializer<'a> { + fn new(key: Cow<'a, str>) -> StrDeserializer<'a> { + StrDeserializer { + key: key, + } + } +} + +impl<'de> de::Deserializer<'de> for StrDeserializer<'de> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + match self.key { + Cow::Borrowed(s) => visitor.visit_borrowed_str(s), + Cow::Owned(s) => visitor.visit_string(s), + } + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct + ignored_any unit_struct tuple_struct tuple enum identifier + } +} + +struct ValueDeserializer<'a> { + value: Value<'a>, + validate_struct_keys: bool, +} + +impl<'a> ValueDeserializer<'a> { + fn new(value: Value<'a>) -> ValueDeserializer<'a> { + ValueDeserializer { + value: value, + validate_struct_keys: false, + } + } + + fn with_struct_key_validation(mut self) -> Self { + self.validate_struct_keys = true; + self + } +} + +impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + match self.value.e { + E::Integer(i) => visitor.visit_i64(i), + E::Boolean(b) => visitor.visit_bool(b), + E::Float(f) => visitor.visit_f64(f), + E::String(Cow::Borrowed(s)) => visitor.visit_borrowed_str(s), + E::String(Cow::Owned(s)) => visitor.visit_string(s), + E::Datetime(s) => visitor.visit_map(DatetimeDeserializer { + date: s, + visited: false, + }), + E::Array(values) => { + let mut s = de::value::SeqDeserializer::new(values.into_iter()); + let ret = visitor.visit_seq(&mut s)?; + s.end()?; + Ok(ret) + } + E::InlineTable(values) | E::DottedTable(values) => { + visitor.visit_map(InlineTableDeserializer { + values: values.into_iter(), + next_value: None, + }) + } + } + } + + fn deserialize_struct<V>(self, + name: &'static str, + fields: &'static [&'static str], + visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + if name == datetime::NAME && fields == &[datetime::FIELD] { + if let E::Datetime(s) = self.value.e { + return visitor.visit_map(DatetimeDeserializer { + date: s, + visited: false, + }) + } + } + + if self.validate_struct_keys { + match &self.value.e { + &E::InlineTable(ref values) | &E::DottedTable(ref values) => { + let extra_fields = values.iter() + .filter_map(|key_value| { + let (ref key, ref _val) = *key_value; + if !fields.contains(&&(**key)) { + Some(key.clone()) + } else { + None + } + }) + .collect::<Vec<Cow<'de, str>>>(); + + if !extra_fields.is_empty() { + return Err(Error::from_kind(ErrorKind::UnexpectedKeys { + keys: extra_fields.iter().map(|k| k.to_string()).collect::<Vec<_>>(), + available: fields, + })); + } + } + _ => {} + } + } + + if name == spanned::NAME && fields == &[spanned::START, spanned::END, spanned::VALUE] { + let start = self.value.start; + let end = self.value.end; + + return visitor.visit_map(SpannedDeserializer { + start: Some(start), + value: Some(self.value), + end: Some(end), + }); + } + + self.deserialize_any(visitor) + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + visitor.visit_some(self) + } + + fn deserialize_enum<V>( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V + ) -> Result<V::Value, Error> + where V: de::Visitor<'de> + { + match self.value.e { + E::String(val) => visitor.visit_enum(val.into_deserializer()), + E::InlineTable(values) => { + if values.len() != 1 { + Err(Error::from_kind(ErrorKind::Wanted { + expected: "exactly 1 element", + found: if values.is_empty() { + "zero elements" + } else { + "more than 1 element" + }, + })) + } else { + visitor.visit_enum(InlineTableDeserializer { + values: values.into_iter(), + next_value: None, + }) + } + } + e @ _ => Err(Error::from_kind(ErrorKind::Wanted { + expected: "string or inline table", + found: e.type_name(), + })), + } + } + + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V + ) -> Result<V::Value, Error> + where V: de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map unit identifier + ignored_any unit_struct tuple_struct tuple + } +} + +impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> { + type Deserializer = ValueDeserializer<'de>; + + fn into_deserializer(self) -> Self::Deserializer { + ValueDeserializer::new(self) + } +} + +struct SpannedDeserializer<'a> { + start: Option<usize>, + end: Option<usize>, + value: Option<Value<'a>>, +} + +impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: de::DeserializeSeed<'de>, + { + if self.start.is_some() { + seed.deserialize(BorrowedStrDeserializer::new(spanned::START)).map(Some) + } else if self.end.is_some() { + seed.deserialize(BorrowedStrDeserializer::new(spanned::END)).map(Some) + } else if self.value.is_some() { + seed.deserialize(BorrowedStrDeserializer::new(spanned::VALUE)).map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: de::DeserializeSeed<'de>, + { + if let Some(start) = self.start.take() { + seed.deserialize(start.into_deserializer()) + } else if let Some(end) = self.end.take() { + seed.deserialize(end.into_deserializer()) + } else if let Some(value) = self.value.take() { + seed.deserialize(value.into_deserializer()) + } else { + panic!("next_value_seed called before next_key_seed") + } + } +} + +struct DatetimeDeserializer<'a> { + visited: bool, + date: &'a str, +} + +impl<'de> de::MapAccess<'de> for DatetimeDeserializer<'de> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where K: de::DeserializeSeed<'de>, + { + if self.visited { + return Ok(None) + } + self.visited = true; + seed.deserialize(DatetimeFieldDeserializer).map(Some) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where V: de::DeserializeSeed<'de>, + { + seed.deserialize(StrDeserializer::new(self.date.into())) + } +} + +struct DatetimeFieldDeserializer; + +impl<'de> de::Deserializer<'de> for DatetimeFieldDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where V: de::Visitor<'de>, + { + visitor.visit_borrowed_str(datetime::FIELD) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq + bytes byte_buf map struct option unit newtype_struct + ignored_any unit_struct tuple_struct tuple enum identifier + } +} + +struct DottedTableDeserializer<'a> { + name: Cow<'a, str>, + value: Value<'a>, +} + +impl<'de> de::EnumAccess<'de> for DottedTableDeserializer<'de> { + type Error = Error; + type Variant = TableEnumDeserializer<'de>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let (name, value) = (self.name, self.value); + seed.deserialize(StrDeserializer::new(name)) + .map(|val| (val, TableEnumDeserializer { value: value })) + } +} + +struct InlineTableDeserializer<'a> { + values: vec::IntoIter<(Cow<'a, str>, Value<'a>)>, + next_value: Option<Value<'a>>, +} + +impl<'de> de::MapAccess<'de> for InlineTableDeserializer<'de> { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where K: de::DeserializeSeed<'de>, + { + let (key, value) = match self.values.next() { + Some(pair) => pair, + None => return Ok(None), + }; + self.next_value = Some(value); + seed.deserialize(StrDeserializer::new(key)).map(Some) + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where V: de::DeserializeSeed<'de>, + { + let value = self.next_value.take().expect("Unable to read table values"); + seed.deserialize(ValueDeserializer::new(value)) + } +} + +impl<'de> de::EnumAccess<'de> for InlineTableDeserializer<'de> { + type Error = Error; + type Variant = TableEnumDeserializer<'de>; + + fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let (key, value) = match self.values.next() { + Some(pair) => pair, + None => { + return Err(Error::from_kind(ErrorKind::Wanted { + expected: "table with exactly 1 entry", + found: "empty table", + })) + } + }; + + seed.deserialize(StrDeserializer::new(key)) + .map(|val| (val, TableEnumDeserializer { value: value })) + } +} + +/// Deserializes table values into enum variants. +struct TableEnumDeserializer<'a> { + value: Value<'a>, +} + +impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + match self.value.e { + E::InlineTable(values) | E::DottedTable(values) => { + if values.len() == 0 { + Ok(()) + } else { + Err(Error::from_kind(ErrorKind::ExpectedEmptyTable)) + } + } + e @ _ => Err(Error::from_kind(ErrorKind::Wanted { + expected: "table", + found: e.type_name(), + })), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + seed.deserialize(ValueDeserializer::new(self.value)) + } + + fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + match self.value.e { + E::InlineTable(values) | E::DottedTable(values) => { + let tuple_values = values + .into_iter() + .enumerate() + .map(|(index, (key, value))| match key.parse::<usize>() { + Ok(key_index) if key_index == index => Ok(value), + Ok(_) | Err(_) => Err(Error::from_kind(ErrorKind::ExpectedTupleIndex { + expected: index, + found: key.to_string(), + })), + }) + // Fold all values into a `Vec`, or return the first error. + .fold(Ok(Vec::with_capacity(len)), |result, value_result| { + result.and_then(move |mut tuple_values| match value_result { + Ok(value) => { + tuple_values.push(value); + Ok(tuple_values) + } + // `Result<de::Value, Self::Error>` to `Result<Vec<_>, Self::Error>` + Err(e) => Err(e), + }) + })?; + + if tuple_values.len() == len { + de::Deserializer::deserialize_seq( + ValueDeserializer::new(Value { + e: E::Array(tuple_values), + start: self.value.start, + end: self.value.end, + }), + visitor, + ) + } else { + Err(Error::from_kind(ErrorKind::ExpectedTuple(len))) + } + } + e @ _ => Err(Error::from_kind(ErrorKind::Wanted { + expected: "table", + found: e.type_name(), + })), + } + } + + fn struct_variant<V>( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: de::Visitor<'de>, + { + de::Deserializer::deserialize_struct( + ValueDeserializer::new(self.value).with_struct_key_validation(), + "", // TODO: this should be the variant name + fields, + visitor, + ) + } +} + +impl<'a> Deserializer<'a> { + /// Creates a new deserializer which will be deserializing the string + /// provided. + pub fn new(input: &'a str) -> Deserializer<'a> { + Deserializer { + tokens: Tokenizer::new(input), + input: input, + require_newline_after_table: true, + } + } + + /// The `Deserializer::end` method should be called after a value has been + /// fully deserialized. This allows the `Deserializer` to validate that the + /// input stream is at the end or that it only has trailing + /// whitespace/comments. + pub fn end(&mut self) -> Result<(), Error> { + Ok(()) + } + + /// Historical versions of toml-rs accidentally allowed a newline after a + /// table definition, but the TOML spec requires a newline after a table + /// definition header. + /// + /// This option can be set to `false` (the default is `true`) to emulate + /// this behavior for backwards compatibility with older toml-rs versions. + pub fn set_require_newline_after_table(&mut self, require: bool) { + self.require_newline_after_table = require; + } + + fn tables(&mut self) -> Result<Vec<Table<'a>>, Error> { + let mut tables = Vec::new(); + let mut cur_table = Table { + at: 0, + header: Vec::new(), + values: None, + array: false, + }; + + while let Some(line) = self.line()? { + match line { + Line::Table { + at, + mut header, + array, + } => { + if !cur_table.header.is_empty() || cur_table.values.is_some() { + tables.push(cur_table); + } + cur_table = Table { + at: at, + header: Vec::new(), + values: Some(Vec::new()), + array: array, + }; + loop { + let part = header.next().map_err(|e| self.token_error(e)); + match part? { + Some(part) => cur_table.header.push(part), + None => break, + } + } + } + Line::KeyValue(key, value) => { + if cur_table.values.is_none() { + cur_table.values = Some(Vec::new()); + } + self.add_dotted_key(key, value, cur_table.values.as_mut().unwrap())?; + } + } + } + if !cur_table.header.is_empty() || cur_table.values.is_some() { + tables.push(cur_table); + } + Ok(tables) + } + + fn line(&mut self) -> Result<Option<Line<'a>>, Error> { + loop { + self.eat_whitespace()?; + if self.eat_comment()? { + continue + } + if self.eat(Token::Newline)? { + continue + } + break + } + + match self.peek()? { + Some((_, Token::LeftBracket)) => self.table_header().map(Some), + Some(_) => self.key_value().map(Some), + None => Ok(None), + } + } + + fn table_header(&mut self) -> Result<Line<'a>, Error> { + let start = self.tokens.current(); + self.expect(Token::LeftBracket)?; + let array = self.eat(Token::LeftBracket)?; + let ret = Header::new(self.tokens.clone(), + array, + self.require_newline_after_table); + if self.require_newline_after_table { + self.tokens.skip_to_newline(); + } else { + loop { + match self.next()? { + Some((_, Token::RightBracket)) => { + if array { + self.eat(Token::RightBracket)?; + } + break + } + Some((_, Token::Newline)) | + None => break, + _ => {} + } + } + self.eat_whitespace()?; + } + Ok(Line::Table { at: start, header: ret, array: array }) + } + + fn key_value(&mut self) -> Result<Line<'a>, Error> { + let key = self.dotted_key()?; + self.eat_whitespace()?; + self.expect(Token::Equals)?; + self.eat_whitespace()?; + + let value = self.value()?; + self.eat_whitespace()?; + if !self.eat_comment()? { + self.eat_newline_or_eof()?; + } + + Ok(Line::KeyValue(key, value)) + } + + fn value(&mut self) -> Result<Value<'a>, Error> { + let at = self.tokens.current(); + let value = match self.next()? { + Some((Span { start, end }, Token::String { val, .. })) => { + Value { e: E::String(val), start: start, end: end } + } + Some((Span { start, end }, Token::Keylike("true"))) => { + Value { e: E::Boolean(true), start: start, end: end } + } + Some((Span { start, end }, Token::Keylike("false"))) => { + Value { e: E::Boolean(false), start: start, end: end } + } + Some((span, Token::Keylike(key))) => self.number_or_date(span, key)?, + Some((span, Token::Plus)) => self.number_leading_plus(span)?, + Some((Span { start, .. }, Token::LeftBrace)) => { + self.inline_table().map(|(Span { end, .. }, table)| Value { + e: E::InlineTable(table), + start: start, + end: end + })? + } + Some((Span { start, .. }, Token::LeftBracket)) => { + self.array().map(|(Span { end, .. }, array)| Value { + e: E::Array(array), + start: start, + end: end + })? + } + Some(token) => { + return Err(self.error(at, ErrorKind::Wanted { + expected: "a value", + found: token.1.describe(), + })) + } + None => return Err(self.eof()), + }; + Ok(value) + } + + fn number_or_date(&mut self, span: Span, s: &'a str) + -> Result<Value<'a>, Error> + { + if s.contains('T') || (s.len() > 1 && s[1..].contains('-')) && + !s.contains("e-") { + self.datetime(span, s, false).map(|(Span { start, end }, d)| Value { + e: E::Datetime(d), + start: start, + end: end + }) + } else if self.eat(Token::Colon)? { + self.datetime(span, s, true).map(|(Span { start, end }, d)| Value { + e: E::Datetime(d), + start: start, + end: end + }) + } else { + self.number(span, s) + } + } + + /// Returns a string or table value type. + /// + /// Used to deserialize enums. Unit enums may be represented as a string or a table, all other + /// structures (tuple, newtype, struct) must be represented as a table. + fn string_or_table(&mut self) -> Result<(Value<'a>, Option<Cow<'a, str>>), Error> { + match self.peek()? { + Some((_, Token::LeftBracket)) => { + let tables = self.tables()?; + if tables.len() != 1 { + return Err(Error::from_kind(ErrorKind::Wanted { + expected: "exactly 1 table", + found: if tables.is_empty() { + "zero tables" + } else { + "more than 1 table" + }, + })); + } + + let table = tables + .into_iter() + .next() + .expect("Expected exactly one table"); + let header = table + .header + .last() + .expect("Expected at least one header value for table."); + + let start = table.at; + let end = table + .values + .as_ref() + .and_then(|values| values.last()) + .map(|&(_, ref val)| val.end) + .unwrap_or_else(|| header.len()); + Ok(( + Value { + e: E::DottedTable(table.values.unwrap_or_else(Vec::new)), + start: start, + end: end, + }, + Some(header.clone()), + )) + } + Some(_) => self.value().map(|val| (val, None)), + None => Err(self.eof()), + } + } + + fn number(&mut self, Span { start, end }: Span, s: &'a str) -> Result<Value<'a>, Error> { + let to_integer = |f| Value { e: E::Integer(f), start: start, end: end }; + if s.starts_with("0x") { + self.integer(&s[2..], 16).map(to_integer) + } else if s.starts_with("0o") { + self.integer(&s[2..], 8).map(to_integer) + } else if s.starts_with("0b") { + self.integer(&s[2..], 2).map(to_integer) + } else if s.contains('e') || s.contains('E') { + self.float(s, None).map(|f| Value { e: E::Float(f), start: start, end: end }) + } else if self.eat(Token::Period)? { + let at = self.tokens.current(); + match self.next()? { + Some((Span { start, end }, Token::Keylike(after))) => { + self.float(s, Some(after)).map(|f| Value { + e: E::Float(f), start: start, end: end + }) + } + _ => Err(self.error(at, ErrorKind::NumberInvalid)), + } + } else if s == "inf" { + Ok(Value { e: E::Float(f64::INFINITY), start: start, end: end }) + } else if s == "-inf" { + Ok(Value { e: E::Float(f64::NEG_INFINITY), start: start, end: end }) + } else if s == "nan" { + Ok(Value { e: E::Float(f64::NAN), start: start, end: end }) + } else if s == "-nan" { + Ok(Value { e: E::Float(-f64::NAN), start: start, end: end }) + } else { + self.integer(s, 10).map(to_integer) + } + } + + fn number_leading_plus(&mut self, Span { start, .. }: Span) -> Result<Value<'a>, Error> { + let start_token = self.tokens.current(); + match self.next()? { + Some((Span { end, .. }, Token::Keylike(s))) => { + self.number(Span { start: start, end: end }, s) + }, + _ => Err(self.error(start_token, ErrorKind::NumberInvalid)), + } + } + + fn integer(&self, s: &'a str, radix: u32) -> Result<i64, Error> { + let allow_sign = radix == 10; + let allow_leading_zeros = radix != 10; + let (prefix, suffix) = self.parse_integer(s, allow_sign, allow_leading_zeros, radix)?; + let start = self.tokens.substr_offset(s); + if suffix != "" { + return Err(self.error(start, ErrorKind::NumberInvalid)) + } + i64::from_str_radix(&prefix.replace("_", "").trim_left_matches('+'), radix) + .map_err(|_e| self.error(start, ErrorKind::NumberInvalid)) + } + + fn parse_integer( + &self, + s: &'a str, + allow_sign: bool, + allow_leading_zeros: bool, + radix: u32, + ) -> Result<(&'a str, &'a str), Error> { + let start = self.tokens.substr_offset(s); + + let mut first = true; + let mut first_zero = false; + let mut underscore = false; + let mut end = s.len(); + for (i, c) in s.char_indices() { + let at = i + start; + if i == 0 && (c == '+' || c == '-') && allow_sign { + continue + } + + if c == '0' && first { + first_zero = true; + } else if c.to_digit(radix).is_some() { + if !first && first_zero && !allow_leading_zeros { + return Err(self.error(at, ErrorKind::NumberInvalid)); + } + underscore = false; + } else if c == '_' && first { + return Err(self.error(at, ErrorKind::NumberInvalid)); + } else if c == '_' && !underscore { + underscore = true; + } else { + end = i; + break; + } + first = false; + } + if first || underscore { + return Err(self.error(start, ErrorKind::NumberInvalid)) + } + Ok((&s[..end], &s[end..])) + } + + fn float(&mut self, s: &'a str, after_decimal: Option<&'a str>) + -> Result<f64, Error> { + let (integral, mut suffix) = self.parse_integer(s, true, false, 10)?; + let start = self.tokens.substr_offset(integral); + + let mut fraction = None; + if let Some(after) = after_decimal { + if suffix != "" { + return Err(self.error(start, ErrorKind::NumberInvalid)) + } + let (a, b) = self.parse_integer(after, false, true, 10)?; + fraction = Some(a); + suffix = b; + } + + let mut exponent = None; + if suffix.starts_with('e') || suffix.starts_with('E') { + let (a, b) = if suffix.len() == 1 { + self.eat(Token::Plus)?; + match self.next()? { + Some((_, Token::Keylike(s))) => { + self.parse_integer(s, false, false, 10)? + } + _ => return Err(self.error(start, ErrorKind::NumberInvalid)), + } + } else { + self.parse_integer(&suffix[1..], true, false, 10)? + }; + if b != "" { + return Err(self.error(start, ErrorKind::NumberInvalid)) + } + exponent = Some(a); + } + + let mut number = integral.trim_left_matches('+') + .chars() + .filter(|c| *c != '_') + .collect::<String>(); + if let Some(fraction) = fraction { + number.push_str("."); + number.extend(fraction.chars().filter(|c| *c != '_')); + } + if let Some(exponent) = exponent { + number.push_str("E"); + number.extend(exponent.chars().filter(|c| *c != '_')); + } + number.parse().map_err(|_e| { + self.error(start, ErrorKind::NumberInvalid) + }).and_then(|n: f64| { + if n.is_finite() { + Ok(n) + } else { + Err(self.error(start, ErrorKind::NumberInvalid)) + } + }) + } + + fn datetime(&mut self, mut span: Span, date: &'a str, colon_eaten: bool) + -> Result<(Span, &'a str), Error> { + let start = self.tokens.substr_offset(date); + + // Check for space separated date and time. + let mut lookahead = self.tokens.clone(); + if let Ok(Some((_, Token::Whitespace(" ")))) = lookahead.next() { + // Check if hour follows. + if let Ok(Some((_, Token::Keylike(_)))) = lookahead.next() { + self.next()?; // skip space + self.next()?; // skip keylike hour + } + } + + if colon_eaten || self.eat(Token::Colon)? { + // minutes + match self.next()? { + Some((_, Token::Keylike(_))) => {} + _ => return Err(self.error(start, ErrorKind::DateInvalid)), + } + // Seconds + self.expect(Token::Colon)?; + match self.next()? { + Some((Span { end, .. }, Token::Keylike(_))) => { + span.end = end; + }, + _ => return Err(self.error(start, ErrorKind::DateInvalid)), + } + // Fractional seconds + if self.eat(Token::Period)? { + match self.next()? { + Some((Span { end, .. }, Token::Keylike(_))) => { + span.end = end; + }, + _ => return Err(self.error(start, ErrorKind::DateInvalid)), + } + } + + // offset + if self.eat(Token::Plus)? { + match self.next()? { + Some((Span { end, .. }, Token::Keylike(_))) => { + span.end = end; + }, + _ => return Err(self.error(start, ErrorKind::DateInvalid)), + } + } + if self.eat(Token::Colon)? { + match self.next()? { + Some((Span { end, .. }, Token::Keylike(_))) => { + span.end = end; + }, + _ => return Err(self.error(start, ErrorKind::DateInvalid)), + } + } + } + + let end = self.tokens.current(); + Ok((span, &self.tokens.input()[start..end])) + } + + // TODO(#140): shouldn't buffer up this entire table in memory, it'd be + // great to defer parsing everything until later. + fn inline_table(&mut self) -> Result<(Span, Vec<(Cow<'a, str>, Value<'a>)>), Error> { + let mut ret = Vec::new(); + self.eat_whitespace()?; + if let Some(span) = self.eat_spanned(Token::RightBrace)? { + return Ok((span, ret)) + } + loop { + let key = self.dotted_key()?; + self.eat_whitespace()?; + self.expect(Token::Equals)?; + self.eat_whitespace()?; + let value = self.value()?; + self.add_dotted_key(key, value, &mut ret)?; + + self.eat_whitespace()?; + if let Some(span) = self.eat_spanned(Token::RightBrace)? { + return Ok((span, ret)) + } + self.expect(Token::Comma)?; + self.eat_whitespace()?; + } + } + + // TODO(#140): shouldn't buffer up this entire array in memory, it'd be + // great to defer parsing everything until later. + fn array(&mut self) -> Result<(Span, Vec<Value<'a>>), Error> { + let mut ret = Vec::new(); + + let intermediate = |me: &mut Deserializer| { + loop { + me.eat_whitespace()?; + if !me.eat(Token::Newline)? && !me.eat_comment()? { + break + } + } + Ok(()) + }; + + loop { + intermediate(self)?; + if let Some(span) = self.eat_spanned(Token::RightBracket)? { + return Ok((span, ret)) + } + let at = self.tokens.current(); + let value = self.value()?; + if let Some(last) = ret.last() { + if !value.same_type(last) { + return Err(self.error(at, ErrorKind::MixedArrayType)) + } + } + ret.push(value); + intermediate(self)?; + if !self.eat(Token::Comma)? { + break + } + } + intermediate(self)?; + let span = self.expect_spanned(Token::RightBracket)?; + Ok((span, ret)) + } + + fn table_key(&mut self) -> Result<Cow<'a, str>, Error> { + self.tokens.table_key().map(|t| t.1).map_err(|e| self.token_error(e)) + } + + fn dotted_key(&mut self) -> Result<Vec<Cow<'a, str>>, Error> { + let mut result = Vec::new(); + result.push(self.table_key()?); + self.eat_whitespace()?; + while self.eat(Token::Period)? { + self.eat_whitespace()?; + result.push(self.table_key()?); + self.eat_whitespace()?; + } + Ok(result) + } + + /// Stores a value in the appropriate hierachical structure positioned based on the dotted key. + /// + /// Given the following definition: `multi.part.key = "value"`, `multi` and `part` are + /// intermediate parts which are mapped to the relevant fields in the deserialized type's data + /// hierarchy. + /// + /// # Parameters + /// + /// * `key_parts`: Each segment of the dotted key, e.g. `part.one` maps to + /// `vec![Cow::Borrowed("part"), Cow::Borrowed("one")].` + /// * `value`: The parsed value. + /// * `values`: The `Vec` to store the value in. + fn add_dotted_key( + &self, + mut key_parts: Vec<Cow<'a, str>>, + value: Value<'a>, + values: &mut Vec<(Cow<'a, str>, Value<'a>)>, + ) -> Result<(), Error> { + let key = key_parts.remove(0); + if key_parts.is_empty() { + values.push((key, value)); + return Ok(()); + } + match values.iter_mut().find(|&&mut (ref k, _)| *k == key) { + Some(&mut (_, Value { e: E::DottedTable(ref mut v), .. })) => { + return self.add_dotted_key(key_parts, value, v); + } + Some(&mut (_, Value { start, .. })) => { + return Err(self.error(start, ErrorKind::DottedKeyInvalidType)); + } + None => {} + } + // The start/end value is somewhat misleading here. + let table_values = Value { + e: E::DottedTable(Vec::new()), + start: value.start, + end: value.end, + }; + values.push((key, table_values)); + let last_i = values.len() - 1; + if let (_, Value { e: E::DottedTable(ref mut v), .. }) = values[last_i] { + self.add_dotted_key(key_parts, value, v)?; + } + Ok(()) + } + + fn eat_whitespace(&mut self) -> Result<(), Error> { + self.tokens.eat_whitespace().map_err(|e| self.token_error(e)) + } + + fn eat_comment(&mut self) -> Result<bool, Error> { + self.tokens.eat_comment().map_err(|e| self.token_error(e)) + } + + fn eat_newline_or_eof(&mut self) -> Result<(), Error> { + self.tokens.eat_newline_or_eof().map_err(|e| self.token_error(e)) + } + + fn eat(&mut self, expected: Token<'a>) -> Result<bool, Error> { + self.tokens.eat(expected).map_err(|e| self.token_error(e)) + } + + fn eat_spanned(&mut self, expected: Token<'a>) -> Result<Option<Span>, Error> { + self.tokens.eat_spanned(expected).map_err(|e| self.token_error(e)) + } + + fn expect(&mut self, expected: Token<'a>) -> Result<(), Error> { + self.tokens.expect(expected).map_err(|e| self.token_error(e)) + } + + fn expect_spanned(&mut self, expected: Token<'a>) -> Result<Span, Error> { + self.tokens.expect_spanned(expected).map_err(|e| self.token_error(e)) + } + + fn next(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> { + self.tokens.next().map_err(|e| self.token_error(e)) + } + + fn peek(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> { + self.tokens.peek().map_err(|e| self.token_error(e)) + } + + fn eof(&self) -> Error { + self.error(self.input.len(), ErrorKind::UnexpectedEof) + } + + fn token_error(&self, error: TokenError) -> Error { + match error { + TokenError::InvalidCharInString(at, ch) => { + self.error(at, ErrorKind::InvalidCharInString(ch)) + } + TokenError::InvalidEscape(at, ch) => { + self.error(at, ErrorKind::InvalidEscape(ch)) + } + TokenError::InvalidEscapeValue(at, v) => { + self.error(at, ErrorKind::InvalidEscapeValue(v)) + } + TokenError::InvalidHexEscape(at, ch) => { + self.error(at, ErrorKind::InvalidHexEscape(ch)) + } + TokenError::NewlineInString(at) => { + self.error(at, ErrorKind::NewlineInString) + } + TokenError::Unexpected(at, ch) => { + self.error(at, ErrorKind::Unexpected(ch)) + } + TokenError::UnterminatedString(at) => { + self.error(at, ErrorKind::UnterminatedString) + } + TokenError::NewlineInTableKey(at) => { + self.error(at, ErrorKind::NewlineInTableKey) + } + TokenError::Wanted { at, expected, found } => { + self.error(at, ErrorKind::Wanted { expected: expected, found: found }) + } + TokenError::EmptyTableKey(at) => { + self.error(at, ErrorKind::EmptyTableKey) + } + TokenError::MultilineStringKey(at) => { + self.error(at, ErrorKind::MultilineStringKey) + } + } + } + + fn error(&self, at: usize, kind: ErrorKind) -> Error { + let mut err = Error::from_kind(kind); + let (line, col) = self.to_linecol(at); + err.inner.line = Some(line); + err.inner.col = col; + err + } + + /// Converts a byte offset from an error message to a (line, column) pair + /// + /// All indexes are 0-based. + fn to_linecol(&self, offset: usize) -> (usize, usize) { + let mut cur = 0; + for (i, line) in self.input.lines().enumerate() { + if cur + line.len() + 1 > offset { + return (i, offset - cur) + } + cur += line.len() + 1; + } + (self.input.lines().count(), 0) + } +} + +impl Error { + /// Produces a (line, column) pair of the position of the error if available + /// + /// All indexes are 0-based. + pub fn line_col(&self) -> Option<(usize, usize)> { + self.inner.line.map(|line| (line, self.inner.col)) + } + + fn from_kind(kind: ErrorKind) -> Error { + Error { + inner: Box::new(ErrorInner { + kind: kind, + line: None, + col: 0, + message: String::new(), + key: Vec::new(), + }), + } + } + + fn custom(s: String) -> Error { + Error { + inner: Box::new(ErrorInner { + kind: ErrorKind::Custom, + line: None, + col: 0, + message: s, + key: Vec::new(), + }), + } + } + + /// Do not call this method, it may be removed at any time, it's just an + /// internal implementation detail. + #[doc(hidden)] + pub fn add_key_context(&mut self, key: &str) { + self.inner.key.insert(0, key.to_string()); + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.inner.kind { + ErrorKind::UnexpectedEof => "unexpected eof encountered".fmt(f)?, + ErrorKind::InvalidCharInString(c) => { + write!(f, "invalid character in string: `{}`", + c.escape_default().collect::<String>())? + } + ErrorKind::InvalidEscape(c) => { + write!(f, "invalid escape character in string: `{}`", + c.escape_default().collect::<String>())? + } + ErrorKind::InvalidHexEscape(c) => { + write!(f, "invalid hex escape character in string: `{}`", + c.escape_default().collect::<String>())? + } + ErrorKind::InvalidEscapeValue(c) => { + write!(f, "invalid escape value: `{}`", c)? + } + ErrorKind::NewlineInString => "newline in string found".fmt(f)?, + ErrorKind::Unexpected(ch) => { + write!(f, "unexpected character found: `{}`", + ch.escape_default().collect::<String>())? + } + ErrorKind::UnterminatedString => "unterminated string".fmt(f)?, + ErrorKind::NewlineInTableKey => "found newline in table key".fmt(f)?, + ErrorKind::Wanted { expected, found } => { + write!(f, "expected {}, found {}", expected, found)? + } + ErrorKind::NumberInvalid => "invalid number".fmt(f)?, + ErrorKind::DateInvalid => "invalid date".fmt(f)?, + ErrorKind::MixedArrayType => "mixed types in an array".fmt(f)?, + ErrorKind::DuplicateTable(ref s) => { + write!(f, "redefinition of table `{}`", s)?; + } + ErrorKind::RedefineAsArray => "table redefined as array".fmt(f)?, + ErrorKind::EmptyTableKey => "empty table key found".fmt(f)?, + ErrorKind::MultilineStringKey => "multiline strings are not allowed for key".fmt(f)?, + ErrorKind::Custom => self.inner.message.fmt(f)?, + ErrorKind::ExpectedTuple(l) => write!(f, "expected table with length {}", l)?, + ErrorKind::ExpectedTupleIndex { + expected, + ref found, + } => write!(f, "expected table key `{}`, but was `{}`", expected, found)?, + ErrorKind::ExpectedEmptyTable => "expected empty table".fmt(f)?, + ErrorKind::DottedKeyInvalidType => { + "dotted key attempted to extend non-table type".fmt(f)? + } + ErrorKind::UnexpectedKeys { ref keys, available } => { + write!( + f, + "unexpected keys in table: `{:?}`, available keys: `{:?}`", + keys, + available + )? + } + ErrorKind::__Nonexhaustive => panic!(), + } + + if !self.inner.key.is_empty() { + write!(f, " for key `")?; + for (i, k) in self.inner.key.iter().enumerate() { + if i > 0 { + write!(f, ".")?; + } + write!(f, "{}", k)?; + } + write!(f, "`")?; + } + + if let Some(line) = self.inner.line { + write!(f, " at line {}", line + 1)?; + } + + Ok(()) + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match self.inner.kind { + ErrorKind::UnexpectedEof => "unexpected eof encountered", + ErrorKind::InvalidCharInString(_) => "invalid char in string", + ErrorKind::InvalidEscape(_) => "invalid escape in string", + ErrorKind::InvalidHexEscape(_) => "invalid hex escape in string", + ErrorKind::InvalidEscapeValue(_) => "invalid escape value in string", + ErrorKind::NewlineInString => "newline in string found", + ErrorKind::Unexpected(_) => "unexpected or invalid character", + ErrorKind::UnterminatedString => "unterminated string", + ErrorKind::NewlineInTableKey => "found newline in table key", + ErrorKind::Wanted { .. } => "expected a token but found another", + ErrorKind::NumberInvalid => "invalid number", + ErrorKind::DateInvalid => "invalid date", + ErrorKind::MixedArrayType => "mixed types in an array", + ErrorKind::DuplicateTable(_) => "duplicate table", + ErrorKind::RedefineAsArray => "table redefined as array", + ErrorKind::EmptyTableKey => "empty table key found", + ErrorKind::MultilineStringKey => "invalid multiline string for key", + ErrorKind::Custom => "a custom error", + ErrorKind::ExpectedTuple(_) => "expected table length", + ErrorKind::ExpectedTupleIndex { .. } => "expected table key", + ErrorKind::ExpectedEmptyTable => "expected empty table", + ErrorKind::DottedKeyInvalidType => "dotted key invalid type", + ErrorKind::UnexpectedKeys { .. } => "unexpected keys in table", + ErrorKind::__Nonexhaustive => panic!(), + } + } +} + +impl de::Error for Error { + fn custom<T: fmt::Display>(msg: T) -> Error { + Error::custom(msg.to_string()) + } +} + +enum Line<'a> { + Table { at: usize, header: Header<'a>, array: bool }, + KeyValue(Vec<Cow<'a, str>>, Value<'a>), +} + +struct Header<'a> { + first: bool, + array: bool, + require_newline_after_table: bool, + tokens: Tokenizer<'a>, +} + +impl<'a> Header<'a> { + fn new(tokens: Tokenizer<'a>, + array: bool, + require_newline_after_table: bool) -> Header<'a> { + Header { + first: true, + array: array, + tokens: tokens, + require_newline_after_table: require_newline_after_table, + } + } + + fn next(&mut self) -> Result<Option<Cow<'a, str>>, TokenError> { + self.tokens.eat_whitespace()?; + + if self.first || self.tokens.eat(Token::Period)? { + self.first = false; + self.tokens.eat_whitespace()?; + self.tokens.table_key().map(|t| t.1).map(Some) + } else { + self.tokens.expect(Token::RightBracket)?; + if self.array { + self.tokens.expect(Token::RightBracket)?; + } + + self.tokens.eat_whitespace()?; + if self.require_newline_after_table { + if !self.tokens.eat_comment()? { + self.tokens.eat_newline_or_eof()?; + } + } + Ok(None) + } + } +} + +#[derive(Debug)] +struct Value<'a> { + e: E<'a>, + start: usize, + end: usize, +} + +#[derive(Debug)] +enum E<'a> { + Integer(i64), + Float(f64), + Boolean(bool), + String(Cow<'a, str>), + Datetime(&'a str), + Array(Vec<Value<'a>>), + InlineTable(Vec<(Cow<'a, str>, Value<'a>)>), + DottedTable(Vec<(Cow<'a, str>, Value<'a>)>), +} + +impl<'a> E<'a> { + fn type_name(&self) -> &'static str { + match *self { + E::String(..) => "string", + E::Integer(..) => "integer", + E::Float(..) => "float", + E::Boolean(..) => "boolean", + E::Datetime(..) => "datetime", + E::Array(..) => "array", + E::InlineTable(..) => "inline table", + E::DottedTable(..) => "dotted table", + } + } +} + +impl<'a> Value<'a> { + fn same_type(&self, other: &Value<'a>) -> bool { + match (&self.e, &other.e) { + (&E::String(..), &E::String(..)) | + (&E::Integer(..), &E::Integer(..)) | + (&E::Float(..), &E::Float(..)) | + (&E::Boolean(..), &E::Boolean(..)) | + (&E::Datetime(..), &E::Datetime(..)) | + (&E::Array(..), &E::Array(..)) | + (&E::InlineTable(..), &E::InlineTable(..)) => true, + (&E::DottedTable(..), &E::DottedTable(..)) => true, + + _ => false, + } + } +} diff --git a/toml/src/lib.rs b/toml/src/lib.rs new file mode 100644 index 000000000..e36ff5221 --- /dev/null +++ b/toml/src/lib.rs @@ -0,0 +1,175 @@ +//! A [TOML]-parsing library +//! +//! This library implements a [TOML] v0.5.0 compatible parser, +//! primarily supporting the [`serde`] library for encoding/decoding +//! various types in Rust. +//! +//! TOML itself is a simple, ergonomic, and readable configuration format: +//! +//! ```toml +//! [package] +//! name = "toml" +//! version = "0.4.2" +//! authors = ["Alex Crichton <alex@alexcrichton.com>"] +//! +//! [dependencies] +//! serde = "1.0" +//! ``` +//! +//! The TOML format tends to be relatively common throughout the Rust community +//! for configuration, notably being used by [Cargo], Rust's package manager. +//! +//! ## TOML values +//! +//! A value in TOML is represented with the `Value` enum in this crate: +//! +//! ```rust,ignore +//! pub enum Value { +//! String(String), +//! Integer(i64), +//! Float(f64), +//! Boolean(bool), +//! Datetime(Datetime), +//! Array(Array), +//! Table(Table), +//! } +//! ``` +//! +//! TOML is similar to JSON with the notable addition of a `Datetime` +//! type. In general, TOML and JSON are interchangeable in terms of +//! formats. +//! +//! ## Parsing TOML +//! +//! The easiest way to parse a TOML document is via the `Value` type: +//! +//! ```rust +//! use toml::Value; +//! +//! let value = "foo = 'bar'".parse::<Value>().unwrap(); +//! +//! assert_eq!(value["foo"].as_str(), Some("bar")); +//! ``` +//! +//! The `Value` type implements a number of convenience methods and +//! traits; the example above uses `FromStr` to parse a `str` into a +//! `Value`. +//! +//! ## Deserialization and Serialization +//! +//! This crate supports [`serde`] 1.0 with a number of +//! implementations of the `Deserialize`, `Serialize`, `Deserializer`, and +//! `Serializer` traits. Namely, you'll find: +//! +//! * `Deserialize for Value` +//! * `Serialize for Value` +//! * `Deserialize for Datetime` +//! * `Serialize for Datetime` +//! * `Deserializer for de::Deserializer` +//! * `Serializer for ser::Serializer` +//! * `Deserializer for Value` +//! +//! This means that you can use Serde to deserialize/serialize the +//! `Value` type as well as the `Datetime` type in this crate. You can also +//! use the `Deserializer`, `Serializer`, or `Value` type itself to act as +//! a deserializer/serializer for arbitrary types. +//! +//! An example of deserializing with TOML is: +//! +//! ```rust +//! #[macro_use] +//! extern crate serde_derive; +//! extern crate toml; +//! +//! #[derive(Deserialize)] +//! struct Config { +//! ip: String, +//! port: Option<u16>, +//! keys: Keys, +//! } +//! +//! #[derive(Deserialize)] +//! struct Keys { +//! github: String, +//! travis: Option<String>, +//! } +//! +//! fn main() { +//! let config: Config = toml::from_str(r#" +//! ip = '127.0.0.1' +//! +//! [keys] +//! github = 'xxxxxxxxxxxxxxxxx' +//! travis = 'yyyyyyyyyyyyyyyyy' +//! "#).unwrap(); +//! +//! assert_eq!(config.ip, "127.0.0.1"); +//! assert_eq!(config.port, None); +//! assert_eq!(config.keys.github, "xxxxxxxxxxxxxxxxx"); +//! assert_eq!(config.keys.travis.as_ref().unwrap(), "yyyyyyyyyyyyyyyyy"); +//! } +//! ``` +//! +//! You can serialize types in a similar fashion: +//! +//! ```rust +//! #[macro_use] +//! extern crate serde_derive; +//! extern crate toml; +//! +//! #[derive(Serialize)] +//! struct Config { +//! ip: String, +//! port: Option<u16>, +//! keys: Keys, +//! } +//! +//! #[derive(Serialize)] +//! struct Keys { +//! github: String, +//! travis: Option<String>, +//! } +//! +//! fn main() { +//! let config = Config { +//! ip: "127.0.0.1".to_string(), +//! port: None, +//! keys: Keys { +//! github: "xxxxxxxxxxxxxxxxx".to_string(), +//! travis: Some("yyyyyyyyyyyyyyyyy".to_string()), +//! }, +//! }; +//! +//! let toml = toml::to_string(&config).unwrap(); +//! } +//! ``` +//! +//! [TOML]: https://github.com/toml-lang/toml +//! [Cargo]: https://crates.io/ +//! [`serde`]: https://serde.rs/ + +#![doc(html_root_url = "https://docs.rs/toml/0.4")] +#![deny(missing_docs)] + +#[macro_use] +extern crate serde; + +pub mod value; +#[doc(no_inline)] +pub use value::Value; +mod datetime; + +pub mod ser; +#[doc(no_inline)] +pub use ser::{to_string, to_string_pretty, to_vec, Serializer}; +pub mod de; +#[doc(no_inline)] +pub use de::{from_slice, from_str, Deserializer}; +mod tokens; + +#[doc(hidden)] +pub mod macros; + +mod spanned; +#[doc(no_inline)] +pub use spanned::Spanned; diff --git a/toml/src/macros.rs b/toml/src/macros.rs new file mode 100644 index 000000000..b4c7b22da --- /dev/null +++ b/toml/src/macros.rs @@ -0,0 +1,462 @@ +pub use serde::de::{Deserialize, IntoDeserializer}; + +use value::{Value, Table, Array}; + +/// Construct a [`toml::Value`] from TOML syntax. +/// +/// [`toml::Value`]: value/enum.Value.html +/// +/// ```rust +/// #[macro_use] +/// extern crate toml; +/// +/// fn main() { +/// let cargo_toml = toml! { +/// [package] +/// name = "toml" +/// version = "0.4.5" +/// authors = ["Alex Crichton <alex@alexcrichton.com>"] +/// +/// [badges] +/// travis-ci = { repository = "alexcrichton/toml-rs" } +/// +/// [dependencies] +/// serde = "1.0" +/// +/// [dev-dependencies] +/// serde_derive = "1.0" +/// serde_json = "1.0" +/// }; +/// +/// println!("{:#?}", cargo_toml); +/// } +/// ``` +#[macro_export] +macro_rules! toml { + ($($toml:tt)+) => {{ + let table = $crate::value::Table::new(); + let mut root = $crate::Value::Table(table); + toml_internal!(@toplevel root [] $($toml)+); + root + }}; +} + +// TT-muncher to parse TOML syntax into a toml::Value. +// +// @toplevel -- Parse tokens outside of an inline table or inline array. In +// this state, `[table headers]` and `[[array headers]]` are +// allowed and `key = value` pairs are not separated by commas. +// +// @topleveldatetime -- Helper to parse a Datetime from string and insert it +// into a table, continuing in the @toplevel state. +// +// @path -- Turn a path segment into a string. Segments that look like idents +// are stringified, while quoted segments like `"cfg(windows)"` +// are not. +// +// @value -- Parse the value part of a `key = value` pair, which may be a +// primitive or inline table or inline array. +// +// @table -- Parse the contents of an inline table, returning them as a +// toml::Value::Table. +// +// @tabledatetime -- Helper to parse a Datetime from string and insert it +// into a table, continuing in the @table state. +// +// @array -- Parse the contents of an inline array, returning them as a +// toml::Value::Array. +// +// @arraydatetime -- Helper to parse a Datetime from string and push it into +// an array, continuing in the @array state. +// +// @trailingcomma -- Helper to append a comma to a sequence of tokens if the +// sequence is non-empty and does not already end in a trailing +// comma. +// +#[macro_export] +#[doc(hidden)] +macro_rules! toml_internal { + // Base case, no elements remaining. + (@toplevel $root:ident [$($path:tt)*]) => {}; + + // Parse negative number `key = -value`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = - $v:tt $($rest:tt)*) => { + toml_internal!(@toplevel $root [$($path)*] $($($k)-+).+ = (-$v) $($rest)*); + }; + + // Parse positive number `key = +value`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = + $v:tt $($rest:tt)*) => { + toml_internal!(@toplevel $root [$($path)*] $($($k)-+).+ = ($v) $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T00:32:00-07:00`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + + // Parse local datetime `key = 1979-05-27T00:32:00.999999`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*); + }; + // Space instead of T. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*); + }; + // Space instead of T. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec) $($rest)*); + }; + + // Parse local date `key = 1979-05-27`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day) $($rest)*); + }; + + // Parse local time `key = 00:32:00.999999`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse local time `key = 07:32:00`. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt $($rest:tt)*) => { + toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($hr : $min : $sec) $($rest)*); + }; + + // Parse any other `key = value` including string, inline array, inline + // table, number, and boolean. + (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $v:tt $($rest:tt)*) => {{ + $crate::macros::insert_toml( + &mut $root, + &[$($path)* $(&concat!($("-", toml_internal!(@path $k),)+)[1..], )+], + toml_internal!(@value $v)); + toml_internal!(@toplevel $root [$($path)*] $($rest)*); + }}; + + // Parse array header `[[bin]]`. + (@toplevel $root:ident $oldpath:tt [[$($($path:tt)-+).+]] $($rest:tt)*) => { + $crate::macros::push_toml( + &mut $root, + &[$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+]); + toml_internal!(@toplevel $root [$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+] $($rest)*); + }; + + // Parse table header `[patch.crates-io]`. + (@toplevel $root:ident $oldpath:tt [$($($path:tt)-+).+] $($rest:tt)*) => { + $crate::macros::insert_toml( + &mut $root, + &[$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+], + $crate::Value::Table($crate::value::Table::new())); + toml_internal!(@toplevel $root [$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+] $($rest)*); + }; + + // Parse datetime from string and insert into table. + (@topleveldatetime $root:ident [$($path:tt)*] $($($k:tt)-+).+ = ($($datetime:tt)+) $($rest:tt)*) => { + $crate::macros::insert_toml( + &mut $root, + &[$($path)* $(&concat!($("-", toml_internal!(@path $k),)+)[1..], )+], + $crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap())); + toml_internal!(@toplevel $root [$($path)*] $($rest)*); + }; + + // Turn a path segment into a string. + (@path $ident:ident) => { + stringify!($ident) + }; + + // For a path segment that is not an ident, expect that it is already a + // quoted string, like in `[target."cfg(windows)".dependencies]`. + (@path $quoted:tt) => { + $quoted + }; + + // Construct a Value from an inline table. + (@value { $($inline:tt)* }) => {{ + let mut table = $crate::Value::Table($crate::value::Table::new()); + toml_internal!(@trailingcomma (@table table) $($inline)*); + table + }}; + + // Construct a Value from an inline array. + (@value [ $($inline:tt)* ]) => {{ + let mut array = $crate::value::Array::new(); + toml_internal!(@trailingcomma (@array array) $($inline)*); + $crate::Value::Array(array) + }}; + + (@value (-nan)) => { + $crate::Value::Float(-::std::f64::NAN) + }; + + (@value (nan)) => { + $crate::Value::Float(::std::f64::NAN) + }; + + (@value nan) => { + $crate::Value::Float(::std::f64::NAN) + }; + + (@value (-inf)) => { + $crate::Value::Float(::std::f64::NEG_INFINITY) + }; + + (@value (inf)) => { + $crate::Value::Float(::std::f64::INFINITY) + }; + + (@value inf) => { + $crate::Value::Float(::std::f64::INFINITY) + }; + + // Construct a Value from any other type, probably string or boolean or number. + (@value $v:tt) => {{ + // TODO: Implement this with something like serde_json::to_value instead. + let de = $crate::macros::IntoDeserializer::<$crate::de::Error>::into_deserializer($v); + <$crate::Value as $crate::macros::Deserialize>::deserialize(de).unwrap() + }}; + + // Base case of inline table. + (@table $root:ident) => {}; + + // Parse negative number `key = -value`. + (@table $root:ident $($($k:tt)-+).+ = - $v:tt , $($rest:tt)*) => { + toml_internal!(@table $root $($($k)-+).+ = (-$v) , $($rest)*); + }; + + // Parse positive number `key = +value`. + (@table $root:ident $($($k:tt)-+).+ = + $v:tt , $($rest:tt)*) => { + toml_internal!(@table $root $($($k)-+).+ = ($v) , $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T00:32:00-07:00`. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + + // Parse local datetime `key = 1979-05-27T00:32:00.999999`. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*); + }; + // Space instead of T. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*); + }; + // Space instead of T. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec) $($rest)*); + }; + + // Parse local date `key = 1979-05-27`. + (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day) $($rest)*); + }; + + // Parse local time `key = 00:32:00.999999`. + (@table $root:ident $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse local time `key = 07:32:00`. + (@table $root:ident $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@tabledatetime $root $($($k)-+).+ = ($hr : $min : $sec) $($rest)*); + }; + + // Parse any other type, probably string or boolean or number. + (@table $root:ident $($($k:tt)-+).+ = $v:tt , $($rest:tt)*) => { + $crate::macros::insert_toml( + &mut $root, + &[$(&concat!($("-", toml_internal!(@path $k),)+)[1..], )+], + toml_internal!(@value $v)); + toml_internal!(@table $root $($rest)*); + }; + + // Parse a Datetime from string and continue in @table state. + (@tabledatetime $root:ident $($($k:tt)-+).+ = ($($datetime:tt)*) $($rest:tt)*) => { + $crate::macros::insert_toml( + &mut $root, + &[$(&concat!($("-", toml_internal!(@path $k),)+)[1..], )+], + $crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap())); + toml_internal!(@table $root $($rest)*); + }; + + // Base case of inline array. + (@array $root:ident) => {}; + + // Parse negative number `-value`. + (@array $root:ident - $v:tt , $($rest:tt)*) => { + toml_internal!(@array $root (-$v) , $($rest)*); + }; + + // Parse positive number `+value`. + (@array $root:ident + $v:tt , $($rest:tt)*) => { + toml_internal!(@array $root ($v) , $($rest)*); + }; + + // Parse offset datetime `1979-05-27T00:32:00.999999-07:00`. + (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*); + }; + + // Parse offset datetime `1979-05-27T00:32:00-07:00`. + (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + // Space instead of T. + (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*); + }; + + // Parse local datetime `1979-05-27T00:32:00.999999`. + (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*); + }; + // Space instead of T. + (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse offset datetime `1979-05-27T07:32:00Z` and local datetime `1979-05-27T07:32:00`. + (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec) $($rest)*); + }; + // Space instead of T. + (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec) $($rest)*); + }; + + // Parse local date `1979-05-27`. + (@array $root:ident $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($yr - $mo - $day) $($rest)*); + }; + + // Parse local time `00:32:00.999999`. + (@array $root:ident $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($hr : $min : $sec . $frac) $($rest)*); + }; + + // Parse local time `07:32:00`. + (@array $root:ident $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => { + toml_internal!(@arraydatetime $root ($hr : $min : $sec) $($rest)*); + }; + + // Parse any other type, probably string or boolean or number. + (@array $root:ident $v:tt , $($rest:tt)*) => { + $root.push(toml_internal!(@value $v)); + toml_internal!(@array $root $($rest)*); + }; + + // Parse a Datetime from string and continue in @array state. + (@arraydatetime $root:ident ($($datetime:tt)*) $($rest:tt)*) => { + $root.push($crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap())); + toml_internal!(@array $root $($rest)*); + }; + + // No trailing comma required if the tokens are empty. + (@trailingcomma ($($args:tt)*)) => { + toml_internal!($($args)*); + }; + + // Tokens end with a trailing comma, do not append another one. + (@trailingcomma ($($args:tt)*) ,) => { + toml_internal!($($args)* ,); + }; + + // Tokens end with something other than comma, append a trailing comma. + (@trailingcomma ($($args:tt)*) $last:tt) => { + toml_internal!($($args)* $last ,); + }; + + // Not yet at the last token. + (@trailingcomma ($($args:tt)*) $first:tt $($rest:tt)+) => { + toml_internal!(@trailingcomma ($($args)* $first) $($rest)+); + }; +} + +// Called when parsing a `key = value` pair. +// Inserts an entry into the table at the given path. +pub fn insert_toml(root: &mut Value, path: &[&str], value: Value) { + *traverse(root, path) = value; +} + +// Called when parsing an `[[array header]]`. +// Pushes an empty table onto the array at the given path. +pub fn push_toml(root: &mut Value, path: &[&str]) { + let target = traverse(root, path); + if !target.is_array() { + *target = Value::Array(Array::new()); + } + target.as_array_mut().unwrap().push(Value::Table(Table::new())); +} + +fn traverse<'a>(root: &'a mut Value, path: &[&str]) -> &'a mut Value { + let mut cur = root; + for &key in path { + // Lexical lifetimes :D + let cur1 = cur; + let cur2; + + // From the TOML spec: + // + // > Each double-bracketed sub-table will belong to the most recently + // > defined table element above it. + if cur1.is_array() { + cur2 = cur1.as_array_mut().unwrap().last_mut().unwrap(); + } else { + cur2 = cur1; + }; + + // We are about to index into this value, so it better be a table. + if !cur2.is_table() { + *cur2 = Value::Table(Table::new()); + } + + if !cur2.as_table().unwrap().contains_key(key) { + // Insert an empty table for the next loop iteration to point to. + let empty = Value::Table(Table::new()); + cur2.as_table_mut().unwrap().insert(key.to_owned(), empty); + } + + // Step into the current table. + cur = cur2.as_table_mut().unwrap().get_mut(key).unwrap(); + } + cur +} diff --git a/toml/src/ser.rs b/toml/src/ser.rs new file mode 100644 index 000000000..e1fe1a2d6 --- /dev/null +++ b/toml/src/ser.rs @@ -0,0 +1,1802 @@ +//! Serializing Rust structures into TOML. +//! +//! This module contains all the Serde support for serializing Rust structures +//! into TOML documents (as strings). Note that some top-level functions here +//! are also provided at the top of the crate. +//! +//! Note that the TOML format has a restriction that if a table itself contains +//! tables, all keys with non-table values must be emitted first. This is +//! typically easy to ensure happens when you're defining a `struct` as you can +//! reorder the fields manually, but when working with maps (such as `BTreeMap` +//! or `HashMap`) this can lead to serialization errors. In those situations you +//! may use the `tables_last` function in this module like so: +//! +//! ```rust +//! # #[macro_use] extern crate serde_derive; +//! # extern crate toml; +//! # use std::collections::HashMap; +//! #[derive(Serialize)] +//! struct Manifest { +//! package: Package, +//! #[serde(serialize_with = "toml::ser::tables_last")] +//! dependencies: HashMap<String, Dependency>, +//! } +//! # type Package = String; +//! # type Dependency = String; +//! # fn main() {} +//! ``` + +use std::cell::Cell; +use std::error; +use std::fmt::{self, Write}; +use std::marker; +use std::rc::Rc; + +use serde::ser; +use datetime; + +/// Serialize the given data structure as a TOML byte vector. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error> + where T: ser::Serialize, +{ + to_string(value).map(|e| e.into_bytes()) +} + +/// Serialize the given data structure as a String of TOML. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate serde_derive; +/// extern crate toml; +/// +/// #[derive(Serialize)] +/// struct Config { +/// database: Database, +/// } +/// +/// #[derive(Serialize)] +/// struct Database { +/// ip: String, +/// port: Vec<u16>, +/// connection_max: u32, +/// enabled: bool, +/// } +/// +/// fn main() { +/// let config = Config { +/// database: Database { +/// ip: "192.168.1.1".to_string(), +/// port: vec![8001, 8002, 8003], +/// connection_max: 5000, +/// enabled: false, +/// }, +/// }; +/// +/// let toml = toml::to_string(&config).unwrap(); +/// println!("{}", toml) +/// } +/// ``` +pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error> + where T: ser::Serialize, +{ + let mut dst = String::with_capacity(128); + value.serialize(&mut Serializer::new(&mut dst))?; + Ok(dst) +} + +/// Serialize the given data structure as a "pretty" String of TOML. +/// +/// This is identical to `to_string` except the output string has a more +/// "pretty" output. See `Serializer::pretty` for more details. +pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error> + where T: ser::Serialize, +{ + let mut dst = String::with_capacity(128); + value.serialize(&mut Serializer::pretty(&mut dst))?; + Ok(dst) +} + +/// Errors that can occur when serializing a type. +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Error { + /// Indicates that a Rust type was requested to be serialized but it was not + /// supported. + /// + /// Currently the TOML format does not support serializing types such as + /// enums, tuples and tuple structs. + UnsupportedType, + + /// The key of all TOML maps must be strings, but serialization was + /// attempted where the key of a map was not a string. + KeyNotString, + + /// An error that we never omit but keep for backwards compatibility + #[doc(hidden)] + KeyNewline, + + /// Arrays in TOML must have a homogenous type, but a heterogeneous array + /// was emitted. + ArrayMixedType, + + /// All values in a TOML table must be emitted before further tables are + /// emitted. If a value is emitted *after* a table then this error is + /// generated. + ValueAfterTable, + + /// A serialized date was invalid. + DateInvalid, + + /// A serialized number was invalid. + NumberInvalid, + + /// None was attempted to be serialized, but it's not supported. + UnsupportedNone, + + /// A custom error which could be generated when serializing a particular + /// type. + Custom(String), + + #[doc(hidden)] + __Nonexhaustive, +} + +#[derive(Debug, Default, Clone)] +#[doc(hidden)] +/// Internal place for holding array setings +struct ArraySettings { + indent: usize, + trailing_comma: bool, +} + +impl ArraySettings { + fn pretty() -> ArraySettings { + ArraySettings { + indent: 4, + trailing_comma: true, + } + } +} + +#[doc(hidden)] +#[derive(Debug, Default, Clone)] +/// String settings +struct StringSettings { + /// Whether to use literal strings when possible + literal: bool, +} + +impl StringSettings { + fn pretty() -> StringSettings { + StringSettings { + literal: true, + } + } +} + +#[derive(Debug, Default, Clone)] +#[doc(hidden)] +/// Internal struct for holding serialization settings +struct Settings { + array: Option<ArraySettings>, + string: Option<StringSettings>, +} + +/// Serialization implementation for TOML. +/// +/// This structure implements serialization support for TOML to serialize an +/// arbitrary type to TOML. Note that the TOML format does not support all +/// datatypes in Rust, such as enums, tuples, and tuple structs. These types +/// will generate an error when serialized. +/// +/// Currently a serializer always writes its output to an in-memory `String`, +/// which is passed in when creating the serializer itself. +pub struct Serializer<'a> { + dst: &'a mut String, + state: State<'a>, + settings: Rc<Settings>, +} + +#[derive(Debug, Clone)] +enum State<'a> { + Table { + key: &'a str, + parent: &'a State<'a>, + first: &'a Cell<bool>, + table_emitted: &'a Cell<bool>, + }, + Array { + parent: &'a State<'a>, + first: &'a Cell<bool>, + type_: &'a Cell<Option<&'static str>>, + len: Option<usize>, + }, + End, +} + +#[doc(hidden)] +pub struct SerializeSeq<'a: 'b, 'b> { + ser: &'b mut Serializer<'a>, + first: Cell<bool>, + type_: Cell<Option<&'static str>>, + len: Option<usize>, +} + +#[doc(hidden)] +pub enum SerializeTable<'a: 'b, 'b> { + Datetime(&'b mut Serializer<'a>), + Table { + ser: &'b mut Serializer<'a>, + key: String, + first: Cell<bool>, + table_emitted: Cell<bool>, + } +} + +impl<'a> Serializer<'a> { + /// Creates a new serializer which will emit TOML into the buffer provided. + /// + /// The serializer can then be used to serialize a type after which the data + /// will be present in `dst`. + pub fn new(dst: &'a mut String) -> Serializer<'a> { + Serializer { + dst: dst, + state: State::End, + settings: Rc::new(Settings::default()), + } + } + + /// Instantiate a "pretty" formatter + /// + /// By default this will use: + /// + /// - pretty strings: strings with newlines will use the `'''` syntax. See + /// `Serializer::pretty_string` + /// - pretty arrays: each item in arrays will be on a newline, have an indentation of 4 and + /// have a trailing comma. See `Serializer::pretty_array` + pub fn pretty(dst: &'a mut String) -> Serializer<'a> { + Serializer { + dst: dst, + state: State::End, + settings: Rc::new(Settings { + array: Some(ArraySettings::pretty()), + string: Some(StringSettings::pretty()), + }), + } + } + + /// Enable or Disable pretty strings + /// + /// If enabled, literal strings will be used when possible and strings with + /// one or more newlines will use triple quotes (i.e.: `'''` or `"""`) + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = "\nfoo\nbar\n" + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// single = 'no newlines' + /// text = ''' + /// foo + /// bar + /// ''' + /// ``` + pub fn pretty_string(&mut self, value: bool) -> &mut Self { + Rc::get_mut(&mut self.settings).unwrap().string = if value { + Some(StringSettings::pretty()) + } else { + None + }; + self + } + + /// Enable or Disable Literal strings for pretty strings + /// + /// If enabled, literal strings will be used when possible and strings with + /// one or more newlines will use triple quotes (i.e.: `'''` or `"""`) + /// + /// If disabled, literal strings will NEVER be used and strings with one or + /// more newlines will use `"""` + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = "\nfoo\nbar\n" + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = """ + /// foo + /// bar + /// """ + /// ``` + pub fn pretty_string_literal(&mut self, value: bool) -> &mut Self { + let use_default = if let &mut Some(ref mut s) = &mut Rc::get_mut(&mut self.settings) + .unwrap().string { + s.literal = value; + false + } else { + true + }; + + if use_default { + let mut string = StringSettings::pretty(); + string.literal = value; + Rc::get_mut(&mut self.settings).unwrap().string = Some(string); + } + self + } + + /// Enable or Disable pretty arrays + /// + /// If enabled, arrays will always have each item on their own line. + /// + /// Some specific features can be controlled via other builder methods: + /// + /// - `Serializer::pretty_array_indent`: set the indent to a value other + /// than 4. + /// - `Serializer::pretty_array_trailing_comma`: enable/disable the trailing + /// comma on the last item. + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// array = ["foo", "bar"] + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// array = [ + /// "foo", + /// "bar", + /// ] + /// ``` + pub fn pretty_array(&mut self, value: bool) -> &mut Self { + Rc::get_mut(&mut self.settings).unwrap().array = if value { + Some(ArraySettings::pretty()) + } else { + None + }; + self + } + + /// Set the indent for pretty arrays + /// + /// See `Serializer::pretty_array` for more details. + pub fn pretty_array_indent(&mut self, value: usize) -> &mut Self { + let use_default = if let &mut Some(ref mut a) = &mut Rc::get_mut(&mut self.settings) + .unwrap().array { + a.indent = value; + false + } else { + true + }; + + if use_default { + let mut array = ArraySettings::pretty(); + array.indent = value; + Rc::get_mut(&mut self.settings).unwrap().array = Some(array); + } + self + } + + /// Specify whether to use a trailing comma when serializing pretty arrays + /// + /// See `Serializer::pretty_array` for more details. + pub fn pretty_array_trailing_comma(&mut self, value: bool) -> &mut Self { + let use_default = if let &mut Some(ref mut a) = &mut Rc::get_mut(&mut self.settings) + .unwrap().array { + a.trailing_comma = value; + false + } else { + true + }; + + if use_default { + let mut array = ArraySettings::pretty(); + array.trailing_comma = value; + Rc::get_mut(&mut self.settings).unwrap().array = Some(array); + } + self + } + + fn display<T: fmt::Display>(&mut self, + t: T, + type_: &'static str) -> Result<(), Error> { + self.emit_key(type_)?; + drop(write!(self.dst, "{}", t)); + if let State::Table { .. } = self.state { + self.dst.push_str("\n"); + } + Ok(()) + } + + fn emit_key(&mut self, type_: &'static str) -> Result<(), Error> { + self.array_type(type_)?; + let state = self.state.clone(); + self._emit_key(&state) + } + + // recursive implementation of `emit_key` above + fn _emit_key(&mut self, state: &State) -> Result<(), Error> { + match *state { + State::End => Ok(()), + State::Array { parent, first, type_, len } => { + assert!(type_.get().is_some()); + if first.get() { + self._emit_key(parent)?; + } + self.emit_array(first, len) + } + State::Table { parent, first, table_emitted, key } => { + if table_emitted.get() { + return Err(Error::ValueAfterTable) + } + if first.get() { + self.emit_table_header(parent)?; + first.set(false); + } + self.escape_key(key)?; + self.dst.push_str(" = "); + Ok(()) + } + } + } + + fn emit_array(&mut self, first: &Cell<bool>, len: Option<usize>) -> Result<(), Error> { + match (len, &self.settings.array) { + (Some(0...1), _) | (_, &None) => { + if first.get() { + self.dst.push_str("[") + } else { + self.dst.push_str(", ") + } + }, + (_, &Some(ref a)) => { + if first.get() { + self.dst.push_str("[\n") + } else { + self.dst.push_str(",\n") + } + for _ in 0..a.indent { + self.dst.push_str(" "); + } + }, + } + Ok(()) + } + + fn array_type(&mut self, type_: &'static str) -> Result<(), Error> { + let prev = match self.state { + State::Array { type_, .. } => type_, + _ => return Ok(()), + }; + if let Some(prev) = prev.get() { + if prev != type_ { + return Err(Error::ArrayMixedType) + } + } else { + prev.set(Some(type_)); + } + Ok(()) + } + + fn escape_key(&mut self, key: &str) -> Result<(), Error> { + let ok = key.chars().all(|c| { + match c { + 'a' ... 'z' | + 'A' ... 'Z' | + '0' ... '9' | + '-' | '_' => true, + _ => false, + } + }); + if ok { + drop(write!(self.dst, "{}", key)); + } else { + self.emit_str(key, true)?; + } + Ok(()) + } + + fn emit_str(&mut self, value: &str, is_key: bool) -> Result<(), Error> { + #[derive(PartialEq)] + enum Type { + NewlineTripple, + OnelineTripple, + OnelineSingle, + } + + enum Repr { + /// represent as a literal string (using '') + Literal(String, Type), + /// represent the std way (using "") + Std(Type), + } + + fn do_pretty(value: &str) -> Repr { + // For doing pretty prints we store in a new String + // because there are too many cases where pretty cannot + // work. We need to determine: + // - if we are a "multi-line" pretty (if there are \n) + // - if ['''] appears if multi or ['] if single + // - if there are any invalid control characters + // + // Doing it any other way would require multiple passes + // to determine if a pretty string works or not. + let mut out = String::with_capacity(value.len() * 2); + let mut ty = Type::OnelineSingle; + // found consecutive single quotes + let mut max_found_singles = 0; + let mut found_singles = 0; + let mut can_be_pretty = true; + + for ch in value.chars() { + if can_be_pretty { + if ch == '\'' { + found_singles += 1; + if found_singles >= 3 { + can_be_pretty = false; + } + } else { + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + found_singles = 0 + } + match ch { + '\t' => {}, + '\n' => ty = Type::NewlineTripple, + // note that the following are invalid: \b \f \r + c if c < '\u{1f}' => can_be_pretty = false, // Invalid control character + _ => {} + } + out.push(ch); + } else { + // the string cannot be represented as pretty, + // still check if it should be multiline + if ch == '\n' { + ty = Type::NewlineTripple; + } + } + } + if can_be_pretty && found_singles > 0 && value.ends_with('\'') { + // We cannot escape the ending quote so we must use """ + can_be_pretty = false; + } + if !can_be_pretty { + debug_assert!(ty != Type::OnelineTripple); + return Repr::Std(ty); + } + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + debug_assert!(max_found_singles < 3); + if ty == Type::OnelineSingle && max_found_singles >= 1 { + // no newlines, but must use ''' because it has ' in it + ty = Type::OnelineTripple; + } + Repr::Literal(out, ty) + } + + let repr = if !is_key && self.settings.string.is_some() { + match (&self.settings.string, do_pretty(value)) { + (&Some(StringSettings { literal: false, .. }), Repr::Literal(_, ty)) => + Repr::Std(ty), + (_, r @ _) => r, + } + } else { + Repr::Std(Type::OnelineSingle) + }; + match repr { + Repr::Literal(literal, ty) => { + // A pretty string + match ty { + Type::NewlineTripple => self.dst.push_str("'''\n"), + Type::OnelineTripple => self.dst.push_str("'''"), + Type::OnelineSingle => self.dst.push('\''), + } + self.dst.push_str(&literal); + match ty { + Type::OnelineSingle => self.dst.push('\''), + _ => self.dst.push_str("'''"), + } + }, + Repr::Std(ty) => { + match ty { + Type::NewlineTripple => self.dst.push_str("\"\"\"\n"), + // note: OnelineTripple can happen if do_pretty wants to do + // '''it's one line''' + // but settings.string.literal == false + Type::OnelineSingle | + Type::OnelineTripple => self.dst.push('"'), + } + for ch in value.chars() { + match ch { + '\u{8}' => self.dst.push_str("\\b"), + '\u{9}' => self.dst.push_str("\\t"), + '\u{a}' => { + match ty { + Type::NewlineTripple => self.dst.push('\n'), + Type::OnelineSingle => self.dst.push_str("\\n"), + _ => unreachable!(), + } + }, + '\u{c}' => self.dst.push_str("\\f"), + '\u{d}' => self.dst.push_str("\\r"), + '\u{22}' => self.dst.push_str("\\\""), + '\u{5c}' => self.dst.push_str("\\\\"), + c if c < '\u{1f}' => drop(write!(self.dst, "\\u{:04X}", ch as u32)), + ch => self.dst.push(ch), + } + } + match ty { + Type::NewlineTripple => self.dst.push_str("\"\"\""), + Type::OnelineSingle | Type::OnelineTripple => self.dst.push('"'), + } + }, + } + Ok(()) + } + + fn emit_table_header(&mut self, state: &State) -> Result<(), Error> { + let array_of_tables = match *state { + State::End => return Ok(()), + State::Array { .. } => true, + _ => false, + }; + + // Unlike [..]s, we can't omit [[..]] ancestors, so be sure to emit table + // headers for them. + let mut p = state; + if let State::Array { first, parent, .. } = *state { + if first.get() { + p = parent; + } + } + while let State::Table { first, parent, .. } = *p { + p = parent; + if !first.get() { + break; + } + if let State::Array { parent: &State::Table {..}, ..} = *parent { + self.emit_table_header(parent)?; + break; + } + } + + match *state { + State::Table { first, .. } => { + if !first.get() { + // Newline if we are a table that is not the first + // table in the document. + self.dst.push('\n'); + } + }, + State::Array { parent, first, .. } => { + if !first.get() { + // Always newline if we are not the first item in the + // table-array + self.dst.push('\n'); + } else if let State::Table { first, .. } = *parent { + if !first.get() { + // Newline if we are not the first item in the document + self.dst.push('\n'); + } + } + }, + _ => {} + } + self.dst.push_str("["); + if array_of_tables { + self.dst.push_str("["); + } + self.emit_key_part(state)?; + if array_of_tables { + self.dst.push_str("]"); + } + self.dst.push_str("]\n"); + Ok(()) + } + + fn emit_key_part(&mut self, key: &State) -> Result<bool, Error> { + match *key { + State::Array { parent, .. } => self.emit_key_part(parent), + State::End => Ok(true), + State::Table { key, parent, table_emitted, .. } => { + table_emitted.set(true); + let first = self.emit_key_part(parent)?; + if !first { + self.dst.push_str("."); + } + self.escape_key(key)?; + Ok(false) + } + } + } +} + +macro_rules! serialize_float { + ($this:expr, $v:expr) => {{ + $this.emit_key("float")?; + if ($v.is_nan() || $v == 0.0) && $v.is_sign_negative() { + drop(write!($this.dst, "-")); + } + if $v.is_nan() { + drop(write!($this.dst, "nan")); + } else { + drop(write!($this.dst, "{}", $v)); + } + if $v % 1.0 == 0.0 { + drop(write!($this.dst, ".0")); + } + if let State::Table { .. } = $this.state { + $this.dst.push_str("\n"); + } + return Ok(()); + }}; +} + +impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> { + type Ok = (); + type Error = Error; + type SerializeSeq = SerializeSeq<'a, 'b>; + type SerializeTuple = SerializeSeq<'a, 'b>; + type SerializeTupleStruct = SerializeSeq<'a, 'b>; + type SerializeTupleVariant = SerializeSeq<'a, 'b>; + type SerializeMap = SerializeTable<'a, 'b>; + type SerializeStruct = SerializeTable<'a, 'b>; + type SerializeStructVariant = ser::Impossible<(), Error>; + + fn serialize_bool(self, v: bool) -> Result<(), Self::Error> { + self.display(v, "bool") + } + + fn serialize_i8(self, v: i8) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_i16(self, v: i16) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_i32(self, v: i32) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_i64(self, v: i64) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_u8(self, v: u8) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_u16(self, v: u16) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_u32(self, v: u32) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_u64(self, v: u64) -> Result<(), Self::Error> { + self.display(v, "integer") + } + + fn serialize_f32(self, v: f32) -> Result<(), Self::Error> { + serialize_float!(self, v) + } + + fn serialize_f64(self, v: f64) -> Result<(), Self::Error> { + serialize_float!(self, v) + } + + fn serialize_char(self, v: char) -> Result<(), Self::Error> { + let mut buf = [0; 4]; + self.serialize_str(v.encode_utf8(&mut buf)) + } + + fn serialize_str(self, value: &str) -> Result<(), Self::Error> { + self.emit_key("string")?; + self.emit_str(value, false)?; + if let State::Table { .. } = self.state { + self.dst.push_str("\n"); + } + Ok(()) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<(), Self::Error> { + use serde::ser::Serialize; + value.serialize(self) + } + + fn serialize_none(self) -> Result<(), Self::Error> { + Err(Error::UnsupportedNone) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<(), Self::Error> + where T: ser::Serialize + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result<(), Self::Error> { + Err(Error::UnsupportedType) + } + + fn serialize_unit_struct(self, + _name: &'static str) + -> Result<(), Self::Error> { + Err(Error::UnsupportedType) + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: u32, + variant: &'static str) + -> Result<(), Self::Error> { + self.serialize_str(variant) + } + + fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) + -> Result<(), Self::Error> + where T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T) + -> Result<(), Self::Error> + where T: ser::Serialize, + { + Err(Error::UnsupportedType) + } + + fn serialize_seq(self, len: Option<usize>) + -> Result<Self::SerializeSeq, Self::Error> { + self.array_type("array")?; + Ok(SerializeSeq { + ser: self, + first: Cell::new(true), + type_: Cell::new(None), + len: len, + }) + } + + fn serialize_tuple(self, len: usize) + -> Result<Self::SerializeTuple, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct(self, _name: &'static str, len: usize) + -> Result<Self::SerializeTupleStruct, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize) + -> Result<Self::SerializeTupleVariant, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_map(self, _len: Option<usize>) + -> Result<Self::SerializeMap, Self::Error> { + self.array_type("table")?; + Ok(SerializeTable::Table { + ser: self, + key: String::new(), + first: Cell::new(true), + table_emitted: Cell::new(false), + }) + } + + fn serialize_struct(self, name: &'static str, _len: usize) + -> Result<Self::SerializeStruct, Self::Error> { + if name == datetime::NAME { + self.array_type("datetime")?; + Ok(SerializeTable::Datetime(self)) + } else { + self.array_type("table")?; + Ok(SerializeTable::Table { + ser: self, + key: String::new(), + first: Cell::new(true), + table_emitted: Cell::new(false), + }) + } + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::UnsupportedType) + } +} + +impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where T: ser::Serialize, + { + value.serialize(&mut Serializer { + dst: &mut *self.ser.dst, + state: State::Array { + parent: &self.ser.state, + first: &self.first, + type_: &self.type_, + len: self.len, + }, + settings: self.ser.settings.clone(), + })?; + self.first.set(false); + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self.type_.get() { + Some("table") => return Ok(()), + Some(_) => { + match (self.len, &self.ser.settings.array) { + (Some(0...1), _) | (_, &None) => { + self.ser.dst.push_str("]"); + }, + (_, &Some(ref a)) => { + if a.trailing_comma { + self.ser.dst.push_str(","); + } + self.ser.dst.push_str("\n]"); + }, + } + } + None => { + assert!(self.first.get()); + self.ser.emit_key("array")?; + self.ser.dst.push_str("[]") + } + } + if let State::Table { .. } = self.ser.state { + self.ser.dst.push_str("\n"); + } + Ok(()) + } +} + +impl<'a, 'b> ser::SerializeTuple for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeTupleVariant for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeTupleStruct for SerializeSeq<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<(), Error> { + ser::SerializeSeq::end(self) + } +} + +impl<'a, 'b> ser::SerializeMap for SerializeTable<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, input: &T) -> Result<(), Error> + where T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { ref mut key, .. } => { + key.truncate(0); + *key = input.serialize(StringExtractor)?; + } + } + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { + ref mut ser, + ref key, + ref first, + ref table_emitted, + .. + } => { + let res = value.serialize(&mut Serializer { + dst: &mut *ser.dst, + state: State::Table { + key: key, + parent: &ser.state, + first: first, + table_emitted: table_emitted, + }, + settings: ser.settings.clone(), + }); + match res { + Ok(()) => first.set(false), + Err(Error::UnsupportedNone) => {}, + Err(e) => return Err(e), + } + } + } + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self { + SerializeTable::Datetime(_) => panic!(), // shouldn't be possible + SerializeTable::Table { ser, first, .. } => { + if first.get() { + let state = ser.state.clone(); + ser.emit_table_header(&state)?; + } + } + } + Ok(()) + } +} + +impl<'a, 'b> ser::SerializeStruct for SerializeTable<'a, 'b> { + type Ok = (); + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) + -> Result<(), Error> + where T: ser::Serialize, + { + match *self { + SerializeTable::Datetime(ref mut ser) => { + if key == datetime::FIELD { + value.serialize(DateStrEmitter(&mut *ser))?; + } else { + return Err(Error::DateInvalid) + } + } + SerializeTable::Table { + ref mut ser, + ref first, + ref table_emitted, + .. + } => { + let res = value.serialize(&mut Serializer { + dst: &mut *ser.dst, + state: State::Table { + key: key, + parent: &ser.state, + first: first, + table_emitted: table_emitted, + }, + settings: ser.settings.clone(), + }); + match res { + Ok(()) => first.set(false), + Err(Error::UnsupportedNone) => {}, + Err(e) => return Err(e), + } + } + } + Ok(()) + } + + fn end(self) -> Result<(), Error> { + match self { + SerializeTable::Datetime(_) => {}, + SerializeTable::Table { ser, first, .. } => { + if first.get() { + let state = ser.state.clone(); + ser.emit_table_header(&state)?; + } + } + } + Ok(()) + } +} + +struct DateStrEmitter<'a: 'b, 'b>(&'b mut Serializer<'a>); + +impl<'a, 'b> ser::Serializer for DateStrEmitter<'a, 'b> { + type Ok = (); + type Error = Error; + type SerializeSeq = ser::Impossible<(), Error>; + type SerializeTuple = ser::Impossible<(), Error>; + type SerializeTupleStruct = ser::Impossible<(), Error>; + type SerializeTupleVariant = ser::Impossible<(), Error>; + type SerializeMap = ser::Impossible<(), Error>; + type SerializeStruct = ser::Impossible<(), Error>; + type SerializeStructVariant = ser::Impossible<(), Error>; + + fn serialize_bool(self, _v: bool) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i8(self, _v: i8) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i16(self, _v: i16) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i32(self, _v: i32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i64(self, _v: i64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u8(self, _v: u8) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u16(self, _v: u16) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u32(self, _v: u32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u64(self, _v: u64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f32(self, _v: f32) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f64(self, _v: f64) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_char(self, _v: char) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_str(self, value: &str) -> Result<(), Self::Error> { + self.0.display(value, "datetime")?; + Ok(()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_none(self) -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<(), Self::Error> + where T: ser::Serialize + { + Err(Error::KeyNotString) + } + + fn serialize_unit(self) -> Result<(), Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_struct(self, + _name: &'static str) + -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str) + -> Result<(), Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, _value: &T) + -> Result<(), Self::Error> + where T: ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_newtype_variant<T: ?Sized>(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T) + -> Result<(), Self::Error> + where T: ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_seq(self, _len: Option<usize>) + -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple(self, _len: usize) + -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_struct(self, _name: &'static str, _len: usize) + -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_map(self, _len: Option<usize>) + -> Result<Self::SerializeMap, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) + -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::DateInvalid) + } +} + +struct StringExtractor; + +impl ser::Serializer for StringExtractor { + type Ok = String; + type Error = Error; + type SerializeSeq = ser::Impossible<String, Error>; + type SerializeTuple = ser::Impossible<String, Error>; + type SerializeTupleStruct = ser::Impossible<String, Error>; + type SerializeTupleVariant = ser::Impossible<String, Error>; + type SerializeMap = ser::Impossible<String, Error>; + type SerializeStruct = ser::Impossible<String, Error>; + type SerializeStructVariant = ser::Impossible<String, Error>; + + fn serialize_bool(self, _v: bool) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i8(self, _v: i8) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i16(self, _v: i16) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i32(self, _v: i32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i64(self, _v: i64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u8(self, _v: u8) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u16(self, _v: u16) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u32(self, _v: u32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u64(self, _v: u64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f32(self, _v: f32) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f64(self, _v: f64) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_char(self, _v: char) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_str(self, value: &str) -> Result<String, Self::Error> { + Ok(value.to_string()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_none(self) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<String, Self::Error> + where T: ser::Serialize + { + Err(Error::KeyNotString) + } + + fn serialize_unit(self) -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_struct(self, + _name: &'static str) + -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str) + -> Result<String, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_newtype_struct<T: ?Sized>(self, _name: &'static str, value: &T) + -> Result<String, Self::Error> + where T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T) + -> Result<String, Self::Error> + where T: ser::Serialize, + { + Err(Error::KeyNotString) + } + + fn serialize_seq(self, _len: Option<usize>) + -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple(self, _len: usize) + -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_struct(self, _name: &'static str, _len: usize) + -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_map(self, _len: Option<usize>) + -> Result<Self::SerializeMap, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) + -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::KeyNotString) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::UnsupportedType => "unsupported Rust type".fmt(f), + Error::KeyNotString => "map key was not a string".fmt(f), + Error::ArrayMixedType => "arrays cannot have mixed types".fmt(f), + Error::ValueAfterTable => "values must be emitted before tables".fmt(f), + Error::DateInvalid => "a serialized date was invalid".fmt(f), + Error::NumberInvalid => "a serialized number was invalid".fmt(f), + Error::UnsupportedNone => "unsupported None value".fmt(f), + Error::Custom(ref s) => s.fmt(f), + Error::KeyNewline => unreachable!(), + Error::__Nonexhaustive => panic!(), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::UnsupportedType => "unsupported Rust type", + Error::KeyNotString => "map key was not a string", + Error::ArrayMixedType => "arrays cannot have mixed types", + Error::ValueAfterTable => "values must be emitted before tables", + Error::DateInvalid => "a serialized date was invalid", + Error::NumberInvalid => "a serialized number was invalid", + Error::UnsupportedNone => "unsupported None value", + Error::Custom(_) => "custom error", + Error::KeyNewline => unreachable!(), + Error::__Nonexhaustive => panic!(), + } + } +} + +impl ser::Error for Error { + fn custom<T: fmt::Display>(msg: T) -> Error { + Error::Custom(msg.to_string()) + } +} + +enum Category { + Primitive, + Array, + Table, +} + +/// Convenience function to serialize items in a map in an order valid with +/// TOML. +/// +/// TOML carries the restriction that keys in a table must be serialized last if +/// their value is a table itself. This isn't always easy to guarantee, so this +/// helper can be used like so: +/// +/// ```rust +/// # #[macro_use] extern crate serde_derive; +/// # extern crate toml; +/// # use std::collections::HashMap; +/// #[derive(Serialize)] +/// struct Manifest { +/// package: Package, +/// #[serde(serialize_with = "toml::ser::tables_last")] +/// dependencies: HashMap<String, Dependency>, +/// } +/// # type Package = String; +/// # type Dependency = String; +/// # fn main() {} +/// ``` +pub fn tables_last<'a, I, K, V, S>(data: &'a I, serializer: S) + -> Result<S::Ok, S::Error> + where &'a I: IntoIterator<Item = (K, V)>, + K: ser::Serialize, + V: ser::Serialize, + S: ser::Serializer +{ + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + for (k, v) in data { + if let Category::Primitive = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + for (k, v) in data { + if let Category::Array = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + for (k, v) in data { + if let Category::Table = v.serialize(Categorize::new())? { + map.serialize_entry(&k, &v)?; + } + } + map.end() +} + +struct Categorize<E>(marker::PhantomData<E>); + +impl<E> Categorize<E> { + fn new() -> Self { + Categorize(marker::PhantomData) + } +} + +impl<E: ser::Error> ser::Serializer for Categorize<E> { + type Ok = Category; + type Error = E; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = ser::Impossible<Category, E>; + + fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> { + Ok(Category::Primitive) + } + + fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_some<T: ?Sized + ser::Serialize>(self, v: &T) -> Result<Self::Ok, Self::Error> { + v.serialize(self) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_unit_variant(self, _: &'static str, _: u32, _: &'static str) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_newtype_struct<T: ?Sized + ser::Serialize>(self, _: &'static str, v: &T) -> Result<Self::Ok, Self::Error> { + v.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized + ser::Serialize>(self, _: &'static str, _: u32, _: &'static str, _: &T) -> Result<Self::Ok, Self::Error> { + Err(ser::Error::custom("unsupported")) + } + + fn serialize_seq(self, _: Option<usize>) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> { + Ok(self) + } + + fn serialize_tuple_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeTupleStruct, Self::Error> { + Ok(self) + } + + fn serialize_tuple_variant(self, _: &'static str, _: u32, _: &'static str, _: usize) -> Result<Self::SerializeTupleVariant, Self::Error> { + Ok(self) + } + + fn serialize_map(self, _: Option<usize>) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self, Self::Error> { + Ok(self) + } + + fn serialize_struct_variant(self, _: &'static str, _: u32, _: &'static str, _: usize) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(ser::Error::custom("unsupported")) + } +} + +impl<E: ser::Error> ser::SerializeSeq for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_element<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTuple for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_element<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTupleVariant for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeTupleStruct for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Array) + } +} + +impl<E: ser::Error> ser::SerializeMap for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_key<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn serialize_value<T: ?Sized + ser::Serialize>(&mut self, _: &T) + -> Result<(), Self::Error> { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Table) + } +} + +impl<E: ser::Error> ser::SerializeStruct for Categorize<E> { + type Ok = Category; + type Error = E; + + fn serialize_field<T: ?Sized>(&mut self, + _: &'static str, + _: &T) -> Result<(), Self::Error> + where T: ser::Serialize, + { + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(Category::Table) + } +} diff --git a/toml/src/spanned.rs b/toml/src/spanned.rs new file mode 100644 index 000000000..abbbd491e --- /dev/null +++ b/toml/src/spanned.rs @@ -0,0 +1,140 @@ +//! ``` +//! #[macro_use] +//! extern crate serde_derive; +//! +//! extern crate toml; +//! use toml::Spanned; +//! +//! #[derive(Deserialize)] +//! struct Value { +//! s: Spanned<String>, +//! } +//! +//! fn main() { +//! let t = "s = \"value\"\n"; +//! +//! let u: Value = toml::from_str(t).unwrap(); +//! +//! assert_eq!(u.s.start(), 4); +//! assert_eq!(u.s.end(), 11); +//! assert_eq!(u.s.get_ref(), "value"); +//! assert_eq!(u.s.into_inner(), String::from("value")); +//! } +//! ``` + +use serde::{de, ser}; +use std::fmt; + +#[doc(hidden)] +pub const NAME: &'static str = "$__toml_private_Spanned"; +#[doc(hidden)] +pub const START: &'static str = "$__toml_private_start"; +#[doc(hidden)] +pub const END: &'static str = "$__toml_private_end"; +#[doc(hidden)] +pub const VALUE: &'static str = "$__toml_private_value"; + +/// A spanned value, indicating the range at which it is defined in the source. +#[derive(Debug)] +pub struct Spanned<T> { + /// The start range. + start: usize, + /// The end range (exclusive). + end: usize, + /// The spanned value. + value: T, +} + +impl<T> Spanned<T> { + /// Access the start of the span of the contained value. + pub fn start(&self) -> usize { + self.start + } + + /// Access the end of the span of the contained value. + pub fn end(&self) -> usize { + self.end + } + + /// Get the span of the contained value. + pub fn span(&self) -> (usize, usize) { + (self.start, self.end) + } + + /// Consumes the spanned value and returns the contained value. + pub fn into_inner(self) -> T { + self.value + } + + /// Returns a reference to the contained value. + pub fn get_ref(&self) -> &T { + &self.value + } + + /// Returns a mutable reference to the contained value. + pub fn get_mut(&self) -> &T { + &self.value + } +} + +impl<'de, T> de::Deserialize<'de> for Spanned<T> + where T: de::Deserialize<'de> +{ + fn deserialize<D>(deserializer: D) -> Result<Spanned<T>, D::Error> + where D: de::Deserializer<'de> + { + struct SpannedVisitor<T>(::std::marker::PhantomData<T>); + + impl<'de, T> de::Visitor<'de> for SpannedVisitor<T> + where T: de::Deserialize<'de> + { + type Value = Spanned<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a TOML spanned") + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Spanned<T>, V::Error> + where V: de::MapAccess<'de> + { + if visitor.next_key()? != Some(START) { + return Err(de::Error::custom("spanned start key not found")) + } + + let start: usize = visitor.next_value()?; + + if visitor.next_key()? != Some(END) { + return Err(de::Error::custom("spanned end key not found")) + } + + let end: usize = visitor.next_value()?; + + if visitor.next_key()? != Some(VALUE) { + return Err(de::Error::custom("spanned value key not found")) + } + + let value: T = visitor.next_value()?; + + Ok(Spanned { + start: start, + end: end, + value: value + }) + } + } + + let visitor = SpannedVisitor(::std::marker::PhantomData); + + static FIELDS: [&'static str; 3] = [START, END, VALUE]; + deserializer.deserialize_struct(NAME, &FIELDS, visitor) + } +} + +impl<T: ser::Serialize> ser::Serialize for Spanned<T> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: ser::Serializer, + { + self.value.serialize(serializer) + } +} diff --git a/toml/src/tokens.rs b/toml/src/tokens.rs new file mode 100644 index 000000000..382c1ecb2 --- /dev/null +++ b/toml/src/tokens.rs @@ -0,0 +1,690 @@ +use std::borrow::Cow; +use std::char; +use std::str; +use std::string; +use std::string::String as StdString; + +use self::Token::*; + +/// A span, designating a range of bytes where a token is located. +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub struct Span { + /// The start of the range. + pub start: usize, + /// The end of the range (exclusive). + pub end: usize, +} + +impl From<Span> for (usize, usize) { + fn from(Span { start, end }: Span) -> (usize, usize) { + (start, end) + } +} + +#[derive(Eq, PartialEq, Debug)] +pub enum Token<'a> { + Whitespace(&'a str), + Newline, + Comment(&'a str), + + Equals, + Period, + Comma, + Colon, + Plus, + LeftBrace, + RightBrace, + LeftBracket, + RightBracket, + + Keylike(&'a str), + String { src: &'a str, val: Cow<'a, str>, multiline: bool }, +} + +#[derive(Eq, PartialEq, Debug)] +pub enum Error { + InvalidCharInString(usize, char), + InvalidEscape(usize, char), + InvalidHexEscape(usize, char), + InvalidEscapeValue(usize, u32), + NewlineInString(usize), + Unexpected(usize, char), + UnterminatedString(usize), + NewlineInTableKey(usize), + MultilineStringKey(usize), + EmptyTableKey(usize), + Wanted { at: usize, expected: &'static str, found: &'static str }, +} + +#[derive(Clone)] +pub struct Tokenizer<'a> { + input: &'a str, + chars: CrlfFold<'a>, +} + +#[derive(Clone)] +struct CrlfFold<'a> { + chars: str::CharIndices<'a>, +} + +#[derive(Debug)] +enum MaybeString { + NotEscaped(usize), + Owned(string::String), +} + +impl<'a> Tokenizer<'a> { + pub fn new(input: &'a str) -> Tokenizer<'a> { + let mut t = Tokenizer { + input: input, + chars: CrlfFold { + chars: input.char_indices(), + }, + }; + // Eat utf-8 BOM + t.eatc('\u{feff}'); + t + } + + pub fn next(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> { + let (start, token) = match self.one() { + Some((start, '\n')) => (start, Newline), + Some((start, ' ')) => (start, self.whitespace_token(start)), + Some((start, '\t')) => (start, self.whitespace_token(start)), + Some((start, '#')) => (start, self.comment_token(start)), + Some((start, '=')) => (start, Equals), + Some((start, '.')) => (start, Period), + Some((start, ',')) => (start, Comma), + Some((start, ':')) => (start, Colon), + Some((start, '+')) => (start, Plus), + Some((start, '{')) => (start, LeftBrace), + Some((start, '}')) => (start, RightBrace), + Some((start, '[')) => (start, LeftBracket), + Some((start, ']')) => (start, RightBracket), + Some((start, '\'')) => return self.literal_string(start) + .map(|t| Some((self.step_span(start), t))), + Some((start, '"')) => return self.basic_string(start) + .map(|t| Some((self.step_span(start), t))), + Some((start, ch)) if is_keylike(ch) => (start, self.keylike(start)), + + Some((start, ch)) => return Err(Error::Unexpected(start, ch)), + None => return Ok(None), + }; + + let span = self.step_span(start); + Ok(Some((span, token))) + } + + pub fn peek(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> { + self.clone().next() + } + + pub fn eat(&mut self, expected: Token<'a>) -> Result<bool, Error> { + self.eat_spanned(expected).map(|s| s.is_some()) + } + + /// Eat a value, returning it's span if it was consumed. + pub fn eat_spanned(&mut self, expected: Token<'a>) -> Result<Option<Span>, Error> { + let span = match self.peek()? { + Some((span, ref found)) if expected == *found => span, + Some(_) => return Ok(None), + None => return Ok(None), + }; + + drop(self.next()); + Ok(Some(span)) + } + + pub fn expect(&mut self, expected: Token<'a>) -> Result<(), Error> { + // ignore span + let _ = self.expect_spanned(expected)?; + Ok(()) + } + + /// Expect the given token returning its span. + pub fn expect_spanned(&mut self, expected: Token<'a>) -> Result<Span, Error> { + let current = self.current(); + match self.next()? { + Some((span, found)) => { + if expected == found { + Ok(span) + } else { + Err(Error::Wanted { + at: current, + expected: expected.describe(), + found: found.describe(), + }) + } + } + None => { + Err(Error::Wanted { + at: self.input.len(), + expected: expected.describe(), + found: "eof", + }) + } + } + } + + pub fn table_key(&mut self) -> Result<(Span, Cow<'a, str>), Error> { + let current = self.current(); + match self.next()? { + Some((span, Token::Keylike(k))) => Ok((span, k.into())), + Some((span, Token::String { src, val, multiline })) => { + let offset = self.substr_offset(src); + if multiline { + return Err(Error::MultilineStringKey(offset)) + } + if val == "" { + return Err(Error::EmptyTableKey(offset)) + } + match src.find('\n') { + None => Ok((span, val)), + Some(i) => Err(Error::NewlineInTableKey(offset + i)), + } + } + Some((_, other)) => { + Err(Error::Wanted { + at: current, + expected: "a table key", + found: other.describe(), + }) + } + None => { + Err(Error::Wanted { + at: self.input.len(), + expected: "a table key", + found: "eof", + }) + } + } + } + + pub fn eat_whitespace(&mut self) -> Result<(), Error> { + while self.eatc(' ') || self.eatc('\t') { + // ... + } + Ok(()) + } + + pub fn eat_comment(&mut self) -> Result<bool, Error> { + if !self.eatc('#') { + return Ok(false) + } + drop(self.comment_token(0)); + self.eat_newline_or_eof().map(|()| true) + } + + pub fn eat_newline_or_eof(&mut self) -> Result<(), Error> { + let current = self.current(); + match self.next()? { + None | + Some((_, Token::Newline)) => Ok(()), + Some((_, other)) => { + Err(Error::Wanted { + at: current, + expected: "newline", + found: other.describe(), + }) + } + } + } + + pub fn skip_to_newline(&mut self) { + loop { + match self.one() { + Some((_, '\n')) | + None => break, + _ => {} + } + } + } + + fn eatc(&mut self, ch: char) -> bool { + match self.chars.clone().next() { + Some((_, ch2)) if ch == ch2 => { + self.one(); + true + } + _ => false, + } + } + + pub fn current(&mut self) -> usize { + self.chars.clone().next().map(|i| i.0).unwrap_or(self.input.len()) + } + + pub fn input(&self) -> &'a str { + self.input + } + + fn whitespace_token(&mut self, start: usize) -> Token<'a> { + while self.eatc(' ') || self.eatc('\t') { + // ... + } + Whitespace(&self.input[start..self.current()]) + } + + fn comment_token(&mut self, start: usize) -> Token<'a> { + while let Some((_, ch)) = self.chars.clone().next() { + if ch != '\t' && (ch < '\u{20}' || ch > '\u{10ffff}') { + break + } + self.one(); + } + Comment(&self.input[start..self.current()]) + } + + fn read_string(&mut self, + delim: char, + start: usize, + new_ch: &mut FnMut(&mut Tokenizer, &mut MaybeString, + bool, usize, char) + -> Result<(), Error>) + -> Result<Token<'a>, Error> { + let mut multiline = false; + if self.eatc(delim) { + if self.eatc(delim) { + multiline = true; + } else { + return Ok(String { + src: &self.input[start..start+2], + val: Cow::Borrowed(""), + multiline: false, + }) + } + } + let mut val = MaybeString::NotEscaped(self.current()); + let mut n = 0; + 'outer: loop { + n += 1; + match self.one() { + Some((i, '\n')) => { + if multiline { + if self.input.as_bytes()[i] == b'\r' { + val.to_owned(&self.input[..i]); + } + if n == 1 { + val = MaybeString::NotEscaped(self.current()); + } else { + val.push('\n'); + } + continue + } else { + return Err(Error::NewlineInString(i)) + } + } + Some((i, ch)) if ch == delim => { + if multiline { + for _ in 0..2 { + if !self.eatc(delim) { + val.push(delim); + continue 'outer + } + } + } + return Ok(String { + src: &self.input[start..self.current()], + val: val.into_cow(&self.input[..i]), + multiline: multiline, + }) + } + Some((i, c)) => new_ch(self, &mut val, multiline, i, c)?, + None => return Err(Error::UnterminatedString(start)) + } + } + } + + fn literal_string(&mut self, start: usize) -> Result<Token<'a>, Error> { + self.read_string('\'', start, &mut |_me, val, _multi, i, ch| { + if ch == '\u{09}' || ('\u{20}' <= ch && ch <= '\u{10ffff}' && ch != '\u{7f}') { + val.push(ch); + Ok(()) + } else { + Err(Error::InvalidCharInString(i, ch)) + } + }) + } + + fn basic_string(&mut self, start: usize) -> Result<Token<'a>, Error> { + self.read_string('"', start, &mut |me, val, multi, i, ch| { + match ch { + '\\' => { + val.to_owned(&me.input[..i]); + match me.chars.next() { + Some((_, '"')) => val.push('"'), + Some((_, '\\')) => val.push('\\'), + Some((_, 'b')) => val.push('\u{8}'), + Some((_, 'f')) => val.push('\u{c}'), + Some((_, 'n')) => val.push('\n'), + Some((_, 'r')) => val.push('\r'), + Some((_, 't')) => val.push('\t'), + Some((i, c @ 'u')) | + Some((i, c @ 'U')) => { + let len = if c == 'u' {4} else {8}; + val.push(me.hex(start, i, len)?); + } + Some((i, c @ ' ')) | + Some((i, c @ '\t')) | + Some((i, c @ '\n')) if multi => { + if c != '\n' { + while let Some((_, ch)) = me.chars.clone().next() { + match ch { + ' ' | '\t' => { + me.chars.next(); + continue + }, + '\n' => { + me.chars.next(); + break + }, + _ => return Err(Error::InvalidEscape(i, c)), + } + } + } + while let Some((_, ch)) = me.chars.clone().next() { + match ch { + ' ' | '\t' | '\n' => { + me.chars.next(); + } + _ => break, + } + } + } + Some((i, c)) => return Err(Error::InvalidEscape(i, c)), + None => return Err(Error::UnterminatedString(start)), + } + Ok(()) + } + ch if '\u{20}' <= ch && ch <= '\u{10ffff}' && ch != '\u{7f}' => { + val.push(ch); + Ok(()) + } + _ => Err(Error::InvalidCharInString(i, ch)) + } + }) + } + + fn hex(&mut self, start: usize, i: usize, len: usize) -> Result<char, Error> { + let mut buf = StdString::with_capacity(len); + for _ in 0..len { + match self.one() { + Some((_, ch)) if ch as u32 <= 0x7F && ch.is_digit(16) => buf.push(ch), + Some((i, ch)) => return Err(Error::InvalidHexEscape(i, ch)), + None => return Err(Error::UnterminatedString(start)), + } + } + let val = u32::from_str_radix(&buf, 16).unwrap(); + match char::from_u32(val) { + Some(ch) => Ok(ch), + None => Err(Error::InvalidEscapeValue(i, val)), + } + } + + fn keylike(&mut self, start: usize) -> Token<'a> { + while let Some((_, ch)) = self.peek_one() { + if !is_keylike(ch) { + break + } + self.one(); + } + Keylike(&self.input[start..self.current()]) + } + + pub fn substr_offset(&self, s: &'a str) -> usize { + assert!(s.len() <= self.input.len()); + let a = self.input.as_ptr() as usize; + let b = s.as_ptr() as usize; + assert!(a <= b); + b - a + } + + /// Calculate the span of a single character. + fn step_span(&mut self, start: usize) -> Span { + let end = self.peek_one().map(|t| t.0).unwrap_or_else(|| self.input.len()); + Span { start: start, end: end } + } + + /// Peek one char without consuming it. + fn peek_one(&mut self) -> Option<(usize, char)> { + self.chars.clone().next() + } + + /// Take one char. + pub fn one(&mut self) -> Option<(usize, char)> { + self.chars.next() + } +} + +impl<'a> Iterator for CrlfFold<'a> { + type Item = (usize, char); + + fn next(&mut self) -> Option<(usize, char)> { + self.chars.next().map(|(i, c)| { + if c == '\r' { + let mut attempt = self.chars.clone(); + if let Some((_, '\n')) = attempt.next() { + self.chars = attempt; + return (i, '\n') + } + } + (i, c) + }) + } +} + +impl MaybeString { + fn push(&mut self, ch: char) { + match *self { + MaybeString::NotEscaped(..) => {} + MaybeString::Owned(ref mut s) => s.push(ch), + } + } + + fn to_owned(&mut self, input: &str) { + match *self { + MaybeString::NotEscaped(start) => { + *self = MaybeString::Owned(input[start..].to_owned()); + } + MaybeString::Owned(..) => {} + } + } + + fn into_cow(self, input: &str) -> Cow<str> { + match self { + MaybeString::NotEscaped(start) => Cow::Borrowed(&input[start..]), + MaybeString::Owned(s) => Cow::Owned(s), + } + } +} + +fn is_keylike(ch: char) -> bool { + ('A' <= ch && ch <= 'Z') || + ('a' <= ch && ch <= 'z') || + ('0' <= ch && ch <= '9') || + ch == '-' || + ch == '_' +} + +impl<'a> Token<'a> { + pub fn describe(&self) -> &'static str { + match *self { + Token::Keylike(_) => "an identifier", + Token::Equals => "an equals", + Token::Period => "a period", + Token::Comment(_) => "a comment", + Token::Newline => "a newline", + Token::Whitespace(_) => "whitespace", + Token::Comma => "a comma", + Token::RightBrace => "a right brace", + Token::LeftBrace => "a left brace", + Token::RightBracket => "a right bracket", + Token::LeftBracket => "a left bracket", + Token::String { multiline, .. } => if multiline { "a multiline string" } else { "a string" }, + Token::Colon => "a colon", + Token::Plus => "a plus", + } + } +} + +#[cfg(test)] +mod tests { + use std::borrow::Cow; + use super::{Tokenizer, Token, Error}; + + fn err(input: &str, err: Error) { + let mut t = Tokenizer::new(input); + let token = t.next().unwrap_err(); + assert_eq!(token, err); + assert!(t.next().unwrap().is_none()); + } + + #[test] + fn literal_strings() { + fn t(input: &str, val: &str, multiline: bool) { + let mut t = Tokenizer::new(input); + let (_, token) = t.next().unwrap().unwrap(); + assert_eq!(token, Token::String { + src: input, + val: Cow::Borrowed(val), + multiline: multiline, + }); + assert!(t.next().unwrap().is_none()); + } + + t("''", "", false); + t("''''''", "", true); + t("'''\n'''", "", true); + t("'a'", "a", false); + t("'\"a'", "\"a", false); + t("''''a'''", "'a", true); + t("'''\n'a\n'''", "'a\n", true); + t("'''a\n'a\r\n'''", "a\n'a\n", true); + } + + #[test] + fn basic_strings() { + fn t(input: &str, val: &str, multiline: bool) { + let mut t = Tokenizer::new(input); + let (_, token) = t.next().unwrap().unwrap(); + assert_eq!(token, Token::String { + src: input, + val: Cow::Borrowed(val), + multiline: multiline, + }); + assert!(t.next().unwrap().is_none()); + } + + t(r#""""#, "", false); + t(r#""""""""#, "", true); + t(r#""a""#, "a", false); + t(r#""""a""""#, "a", true); + t(r#""\t""#, "\t", false); + t(r#""\u0000""#, "\0", false); + t(r#""\U00000000""#, "\0", false); + t(r#""\U000A0000""#, "\u{A0000}", false); + t(r#""\\t""#, "\\t", false); + t("\"\"\"\\\n\"\"\"", "", true); + t("\"\"\"\\\n \t \t \\\r\n \t \n \t \r\n\"\"\"", "", true); + t(r#""\r""#, "\r", false); + t(r#""\n""#, "\n", false); + t(r#""\b""#, "\u{8}", false); + t(r#""a\fa""#, "a\u{c}a", false); + t(r#""\"a""#, "\"a", false); + t("\"\"\"\na\"\"\"", "a", true); + t("\"\"\"\n\"\"\"", "", true); + err(r#""\a"#, Error::InvalidEscape(2, 'a')); + err("\"\\\n", Error::InvalidEscape(2, '\n')); + err("\"\\\r\n", Error::InvalidEscape(2, '\n')); + err("\"\\", Error::UnterminatedString(0)); + err("\"\u{0}", Error::InvalidCharInString(1, '\u{0}')); + err(r#""\U00""#, Error::InvalidHexEscape(5, '"')); + err(r#""\U00"#, Error::UnterminatedString(0)); + err(r#""\uD800"#, Error::InvalidEscapeValue(2, 0xd800)); + err(r#""\UFFFFFFFF"#, Error::InvalidEscapeValue(2, 0xffffffff)); + } + + #[test] + fn keylike() { + fn t(input: &str) { + let mut t = Tokenizer::new(input); + let (_, token) = t.next().unwrap().unwrap(); + assert_eq!(token, Token::Keylike(input)); + assert!(t.next().unwrap().is_none()); + } + t("foo"); + t("0bar"); + t("bar0"); + t("1234"); + t("a-b"); + t("a_B"); + t("-_-"); + t("___"); + } + + #[test] + fn all() { + fn t(input: &str, expected: &[((usize, usize), Token, &str)]) { + let mut tokens = Tokenizer::new(input); + let mut actual: Vec<((usize, usize), Token, &str)> = Vec::new(); + while let Some((span, token)) = tokens.next().unwrap() { + actual.push((span.into(), token, &input[span.start..span.end])); + } + for (a, b) in actual.iter().zip(expected) { + assert_eq!(a, b); + } + assert_eq!(actual.len(), expected.len()); + } + + t(" a ", &[ + ((0, 1), Token::Whitespace(" "), " "), + ((1, 2), Token::Keylike("a"), "a"), + ((2, 3), Token::Whitespace(" "), " "), + ]); + + t(" a\t [[]] \t [] {} , . =\n# foo \r\n#foo \n ", &[ + ((0, 1), Token::Whitespace(" "), " "), + ((1, 2), Token::Keylike("a"), "a"), + ((2, 4), Token::Whitespace("\t "), "\t "), + ((4, 5), Token::LeftBracket, "["), + ((5, 6), Token::LeftBracket, "["), + ((6, 7), Token::RightBracket, "]"), + ((7, 8), Token::RightBracket, "]"), + ((8, 11), Token::Whitespace(" \t "), " \t "), + ((11, 12), Token::LeftBracket, "["), + ((12, 13), Token::RightBracket, "]"), + ((13, 14), Token::Whitespace(" "), " "), + ((14, 15), Token::LeftBrace, "{"), + ((15, 16), Token::RightBrace, "}"), + ((16, 17), Token::Whitespace(" "), " "), + ((17, 18), Token::Comma, ","), + ((18, 19), Token::Whitespace(" "), " "), + ((19, 20), Token::Period, "."), + ((20, 21), Token::Whitespace(" "), " "), + ((21, 22), Token::Equals, "="), + ((22, 23), Token::Newline, "\n"), + ((23, 29), Token::Comment("# foo "), "# foo "), + ((29, 31), Token::Newline, "\r\n"), + ((31, 36), Token::Comment("#foo "), "#foo "), + ((36, 37), Token::Newline, "\n"), + ((37, 38), Token::Whitespace(" "), " "), + ]); + } + + #[test] + fn bare_cr_bad() { + err("\r", Error::Unexpected(0, '\r')); + err("'\n", Error::NewlineInString(1)); + err("'\u{0}", Error::InvalidCharInString(1, '\u{0}')); + err("'", Error::UnterminatedString(0)); + err("\u{0}", Error::Unexpected(0, '\u{0}')); + } + + #[test] + fn bad_comment() { + let mut t = Tokenizer::new("#\u{0}"); + t.next().unwrap().unwrap(); + assert_eq!(t.next(), Err(Error::Unexpected(1, '\u{0}'))); + assert!(t.next().unwrap().is_none()); + } +} diff --git a/toml/src/value.rs b/toml/src/value.rs new file mode 100644 index 000000000..2e42dc3e7 --- /dev/null +++ b/toml/src/value.rs @@ -0,0 +1,1007 @@ +//! Definition of a TOML value + +use std::collections::{BTreeMap, HashMap}; +use std::hash::Hash; +use std::fmt; +use std::ops; +use std::str::FromStr; +use std::vec; + +use serde::ser; +use serde::de; +use serde::de::IntoDeserializer; + +pub use datetime::{Datetime, DatetimeParseError}; +use datetime::{self, DatetimeFromString}; + +/// Representation of a TOML value. +#[derive(PartialEq, Clone, Debug)] +pub enum Value { + /// Represents a TOML string + String(String), + /// Represents a TOML integer + Integer(i64), + /// Represents a TOML float + Float(f64), + /// Represents a TOML boolean + Boolean(bool), + /// Represents a TOML datetime + Datetime(Datetime), + /// Represents a TOML array + Array(Array), + /// Represents a TOML table + Table(Table), +} + +/// Type representing a TOML array, payload of the `Value::Array` variant +pub type Array = Vec<Value>; + +/// Type representing a TOML table, payload of the `Value::Table` variant +pub type Table = BTreeMap<String, Value>; + +impl Value { + /// Convert a `T` into `toml::Value` which is an enum that can represent + /// any valid TOML data. + /// + /// This conversion can fail if `T`'s implementation of `Serialize` decides to + /// fail, or if `T` contains a map with non-string keys. + pub fn try_from<T>(value: T) -> Result<Value, ::ser::Error> + where T: ser::Serialize, + { + value.serialize(Serializer) + } + + /// Interpret a `toml::Value` as an instance of type `T`. + /// + /// This conversion can fail if the structure of the `Value` does not match the + /// structure expected by `T`, for example if `T` is a struct type but the + /// `Value` contains something other than a TOML table. It can also fail if the + /// structure is correct but `T`'s implementation of `Deserialize` decides that + /// something is wrong with the data, for example required struct fields are + /// missing from the TOML map or some number is too big to fit in the expected + /// primitive type. + pub fn try_into<'de, T>(self) -> Result<T, ::de::Error> + where T: de::Deserialize<'de>, + { + de::Deserialize::deserialize(self) + } + + /// Index into a TOML array or map. A string index can be used to access a + /// value in a map, and a usize index can be used to access an element of an + /// array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get<I: Index>(&self, index: I) -> Option<&Value> { + index.index(self) + } + + /// Mutably index into a TOML array or map. A string index can be used to + /// access a value in a map, and a usize index can be used to access an + /// element of an array. + /// + /// Returns `None` if the type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. Also returns `None` if the given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> { + index.index_mut(self) + } + + /// Extracts the integer value if it is an integer. + pub fn as_integer(&self) -> Option<i64> { + match *self { Value::Integer(i) => Some(i), _ => None } + } + + /// Tests whether this value is an integer. + pub fn is_integer(&self) -> bool { + self.as_integer().is_some() + } + + /// Extracts the float value if it is a float. + pub fn as_float(&self) -> Option<f64> { + match *self { Value::Float(f) => Some(f), _ => None } + } + + /// Tests whether this value is a float. + pub fn is_float(&self) -> bool { + self.as_float().is_some() + } + + /// Extracts the boolean value if it is a boolean. + pub fn as_bool(&self) -> Option<bool> { + match *self { Value::Boolean(b) => Some(b), _ => None } + } + + /// Tests whether this value is a boolean. + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// Extracts the string of this value if it is a string. + pub fn as_str(&self) -> Option<&str> { + match *self { Value::String(ref s) => Some(&**s), _ => None } + } + + /// Tests if this value is a string. + pub fn is_str(&self) -> bool { + self.as_str().is_some() + } + + /// Extracts the datetime value if it is a datetime. + /// + /// Note that a parsed TOML value will only contain ISO 8601 dates. An + /// example date is: + /// + /// ```notrust + /// 1979-05-27T07:32:00Z + /// ``` + pub fn as_datetime(&self) -> Option<&Datetime> { + match *self { Value::Datetime(ref s) => Some(s), _ => None } + } + + /// Tests whether this value is a datetime. + pub fn is_datetime(&self) -> bool { + self.as_datetime().is_some() + } + + /// Extracts the array value if it is an array. + pub fn as_array(&self) -> Option<&Vec<Value>> { + match *self { Value::Array(ref s) => Some(s), _ => None } + } + + /// Extracts the array value if it is an array. + pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> { + match *self { Value::Array(ref mut s) => Some(s), _ => None } + } + + /// Tests whether this value is an array. + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// Extracts the table value if it is a table. + pub fn as_table(&self) -> Option<&Table> { + match *self { Value::Table(ref s) => Some(s), _ => None } + } + + /// Extracts the table value if it is a table. + pub fn as_table_mut(&mut self) -> Option<&mut Table> { + match *self { Value::Table(ref mut s) => Some(s), _ => None } + } + + /// Tests whether this value is a table. + pub fn is_table(&self) -> bool { + self.as_table().is_some() + } + + /// Tests whether this and another value have the same type. + pub fn same_type(&self, other: &Value) -> bool { + match (self, other) { + (&Value::String(..), &Value::String(..)) | + (&Value::Integer(..), &Value::Integer(..)) | + (&Value::Float(..), &Value::Float(..)) | + (&Value::Boolean(..), &Value::Boolean(..)) | + (&Value::Datetime(..), &Value::Datetime(..)) | + (&Value::Array(..), &Value::Array(..)) | + (&Value::Table(..), &Value::Table(..)) => true, + + _ => false, + } + } + + /// Returns a human-readable representation of the type of this value. + pub fn type_str(&self) -> &'static str { + match *self { + Value::String(..) => "string", + Value::Integer(..) => "integer", + Value::Float(..) => "float", + Value::Boolean(..) => "boolean", + Value::Datetime(..) => "datetime", + Value::Array(..) => "array", + Value::Table(..) => "table", + } + } +} + +impl<I> ops::Index<I> for Value where I: Index { + type Output = Value; + + fn index(&self, index: I) -> &Value { + self.get(index).expect("index not found") + } +} + +impl<I> ops::IndexMut<I> for Value where I: Index { + fn index_mut(&mut self, index: I) -> &mut Value { + self.get_mut(index).expect("index not found") + } +} + +impl<'a> From<&'a str> for Value { + #[inline] + fn from(val: &'a str) -> Value { + Value::String(val.to_string()) + } +} + +impl<V: Into<Value>> From<Vec<V>> for Value { + fn from(val: Vec<V>) -> Value { + Value::Array(val.into_iter().map(|v| v.into()).collect()) + } +} + +impl<S: Into<String>, V: Into<Value>> From<BTreeMap<S, V>> for Value { + fn from(val: BTreeMap<S, V>) -> Value { + let table = val.into_iter() + .map(|(s, v)| (s.into(), v.into())) + .collect(); + + Value::Table(table) + } +} + +impl<S: Into<String> + Hash + Eq, V: Into<Value>> From<HashMap<S, V>> for Value { + fn from(val: HashMap<S, V>) -> Value { + let table = val.into_iter() + .map(|(s, v)| (s.into(), v.into())) + .collect(); + + Value::Table(table) + } +} + +macro_rules! impl_into_value { + ($variant:ident : $T:ty) => { + impl From<$T> for Value { + #[inline] + fn from(val: $T) -> Value { + Value::$variant(val.into()) + } + } + } +} + +impl_into_value!(String: String); +impl_into_value!(Integer: i64); +impl_into_value!(Integer: i32); +impl_into_value!(Integer: i8); +impl_into_value!(Integer: u8); +impl_into_value!(Integer: u32); +impl_into_value!(Float: f64); +impl_into_value!(Float: f32); +impl_into_value!(Boolean: bool); +impl_into_value!(Datetime: Datetime); + +/// Types that can be used to index a `toml::Value` +/// +/// Currently this is implemented for `usize` to index arrays and `str` to index +/// tables. +/// +/// This trait is sealed and not intended for implementation outside of the +/// `toml` crate. +pub trait Index: Sealed { + #[doc(hidden)] + fn index<'a>(&self, val: &'a Value) -> Option<&'a Value>; + #[doc(hidden)] + fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value>; +} + +/// An implementation detail that should not be implemented, this will change in +/// the future and break code otherwise. +#[doc(hidden)] +pub trait Sealed {} +impl Sealed for usize {} +impl Sealed for str {} +impl Sealed for String {} +impl<'a, T: Sealed + ?Sized> Sealed for &'a T {} + +impl Index for usize { + fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> { + match *val { + Value::Array(ref a) => a.get(*self), + _ => None, + } + } + + fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> { + match *val { + Value::Array(ref mut a) => a.get_mut(*self), + _ => None, + } + } +} + +impl Index for str { + fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> { + match *val { + Value::Table(ref a) => a.get(self), + _ => None, + } + } + + fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> { + match *val { + Value::Table(ref mut a) => a.get_mut(self), + _ => None, + } + } +} + +impl Index for String { + fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> { + self[..].index(val) + } + + fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> { + self[..].index_mut(val) + } +} + +impl<'s, T: ?Sized> Index for &'s T where T: Index { + fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> { + (**self).index(val) + } + + fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> { + (**self).index_mut(val) + } +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ::ser::to_string(self).expect("Unable to represent value as string").fmt(f) + } +} + +impl FromStr for Value { + type Err = ::de::Error; + fn from_str(s: &str) -> Result<Value, Self::Err> { + ::from_str(s) + } +} + +impl ser::Serialize for Value { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: ser::Serializer + { + use serde::ser::SerializeMap; + + match *self { + Value::String(ref s) => serializer.serialize_str(s), + Value::Integer(i) => serializer.serialize_i64(i), + Value::Float(f) => serializer.serialize_f64(f), + Value::Boolean(b) => serializer.serialize_bool(b), + Value::Datetime(ref s) => s.serialize(serializer), + Value::Array(ref a) => a.serialize(serializer), + Value::Table(ref t) => { + let mut map = serializer.serialize_map(Some(t.len()))?; + // Be sure to visit non-tables first (and also non + // array-of-tables) as all keys must be emitted first. + for (k, v) in t { + if !v.is_table() && !v.is_array() || + (v.as_array().map(|a| !a.iter().any(|v| v.is_table())).unwrap_or(false)) { + map.serialize_entry(k, v)?; + } + } + for (k, v) in t { + if v.as_array().map(|a| a.iter().any(|v| v.is_table())).unwrap_or(false) { + map.serialize_entry(k, v)?; + } + } + for (k, v) in t { + if v.is_table() { + map.serialize_entry(k, v)?; + } + } + map.end() + } + } + } +} + +impl<'de> de::Deserialize<'de> for Value { + fn deserialize<D>(deserializer: D) -> Result<Value, D::Error> + where D: de::Deserializer<'de>, + { + struct ValueVisitor; + + impl<'de> de::Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("any valid TOML value") + } + + fn visit_bool<E>(self, value: bool) -> Result<Value, E> { + Ok(Value::Boolean(value)) + } + + fn visit_i64<E>(self, value: i64) -> Result<Value, E> { + Ok(Value::Integer(value)) + } + + fn visit_u64<E: de::Error>(self, value: u64) -> Result<Value, E> { + if value <= i64::max_value() as u64 { + Ok(Value::Integer(value as i64)) + } else { + Err(de::Error::custom("u64 value was too large")) + } + } + + fn visit_u32<E>(self, value: u32) -> Result<Value, E> { + Ok(Value::Integer(value.into())) + } + + fn visit_i32<E>(self, value: i32) -> Result<Value, E> { + Ok(Value::Integer(value.into())) + } + + fn visit_f64<E>(self, value: f64) -> Result<Value, E> { + Ok(Value::Float(value)) + } + + fn visit_str<E>(self, value: &str) -> Result<Value, E> { + Ok(Value::String(value.into())) + } + + fn visit_string<E>(self, value: String) -> Result<Value, E> { + Ok(Value::String(value)) + } + + fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error> + where D: de::Deserializer<'de>, + { + de::Deserialize::deserialize(deserializer) + } + + fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error> + where V: de::SeqAccess<'de>, + { + let mut vec = Vec::new(); + while let Some(elem) = visitor.next_element()? { + vec.push(elem); + } + Ok(Value::Array(vec)) + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error> + where V: de::MapAccess<'de>, + { + let mut key = String::new(); + let datetime = visitor.next_key_seed(DatetimeOrTable { + key: &mut key, + })?; + match datetime { + Some(true) => { + let date: DatetimeFromString = visitor.next_value()?; + return Ok(Value::Datetime(date.value)) + } + None => return Ok(Value::Table(BTreeMap::new())), + Some(false) => {} + } + let mut map = BTreeMap::new(); + map.insert(key, visitor.next_value()?); + while let Some(key) = visitor.next_key()? { + if map.contains_key(&key) { + let msg = format!("duplicate key: `{}`", key); + return Err(de::Error::custom(msg)) + } + map.insert(key, visitor.next_value()?); + } + Ok(Value::Table(map)) + } + } + + deserializer.deserialize_any(ValueVisitor) + } +} + +impl<'de> de::Deserializer<'de> for Value { + type Error = ::de::Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, ::de::Error> + where V: de::Visitor<'de>, + { + match self { + Value::Boolean(v) => visitor.visit_bool(v), + Value::Integer(n) => visitor.visit_i64(n), + Value::Float(n) => visitor.visit_f64(n), + Value::String(v) => visitor.visit_string(v), + Value::Datetime(v) => visitor.visit_string(v.to_string()), + Value::Array(v) => { + let len = v.len(); + let mut deserializer = SeqDeserializer::new(v); + let seq = visitor.visit_seq(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(seq) + } else { + Err(de::Error::invalid_length(len, &"fewer elements in array")) + } + } + Value::Table(v) => { + let len = v.len(); + let mut deserializer = MapDeserializer::new(v); + let map = visitor.visit_map(&mut deserializer)?; + let remaining = deserializer.iter.len(); + if remaining == 0 { + Ok(map) + } else { + Err(de::Error::invalid_length(len, &"fewer elements in map")) + } + } + } + } + + #[inline] + fn deserialize_enum<V>( + self, + _name: &str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, ::de::Error> + where + V: de::Visitor<'de>, + { + match self { + Value::String(variant) => visitor.visit_enum(variant.into_deserializer()), + _ => Err(de::Error::invalid_type(de::Unexpected::UnitVariant, &"string only")), + } + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, ::de::Error> + where V: de::Visitor<'de>, + { + visitor.visit_some(self) + } + + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V + ) -> Result<V::Value, ::de::Error> + where V: de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + + forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq + bytes byte_buf map unit_struct tuple_struct struct + tuple ignored_any identifier + } +} + +struct SeqDeserializer { + iter: vec::IntoIter<Value>, +} + +impl SeqDeserializer { + fn new(vec: Vec<Value>) -> Self { + SeqDeserializer { + iter: vec.into_iter(), + } + } +} + +impl<'de> de::SeqAccess<'de> for SeqDeserializer { + type Error = ::de::Error; + + fn next_element_seed<T>(&mut self, seed: T) + -> Result<Option<T::Value>, ::de::Error> + where T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +struct MapDeserializer { + iter: <BTreeMap<String, Value> as IntoIterator>::IntoIter, + value: Option<(String, Value)>, +} + +impl MapDeserializer { + fn new(map: BTreeMap<String, Value>) -> Self { + MapDeserializer { + iter: map.into_iter(), + value: None, + } + } +} + +impl<'de> de::MapAccess<'de> for MapDeserializer { + type Error = ::de::Error; + + fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, ::de::Error> + where T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some((key, value)) => { + self.value = Some((key.clone(), value)); + seed.deserialize(Value::String(key)).map(Some) + } + None => Ok(None), + } + } + + fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, ::de::Error> + where T: de::DeserializeSeed<'de>, + { + let (key, res) = match self.value.take() { + Some((key, value)) => (key, seed.deserialize(value)), + None => return Err(de::Error::custom("value is missing")), + }; + res.map_err(|mut error| { + error.add_key_context(&key); + error + }) + } + + fn size_hint(&self) -> Option<usize> { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } +} + +impl<'de> de::IntoDeserializer<'de, ::de::Error> for Value { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + +struct Serializer; + +impl ser::Serializer for Serializer { + type Ok = Value; + type Error = ::ser::Error; + + type SerializeSeq = SerializeVec; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeVec; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = ser::Impossible<Value, ::ser::Error>; + + fn serialize_bool(self, value: bool) -> Result<Value, ::ser::Error> { + Ok(Value::Boolean(value)) + } + + fn serialize_i8(self, value: i8) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_i16(self, value: i16) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_i32(self, value: i32) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_i64(self, value: i64) -> Result<Value, ::ser::Error> { + Ok(Value::Integer(value.into())) + } + + fn serialize_u8(self, value: u8) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_u16(self, value: u16) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_u32(self, value: u32) -> Result<Value, ::ser::Error> { + self.serialize_i64(value.into()) + } + + fn serialize_u64(self, value: u64) -> Result<Value, ::ser::Error> { + if value <= i64::max_value() as u64 { + self.serialize_i64(value as i64) + } else { + Err(ser::Error::custom("u64 value was too large")) + } + } + + fn serialize_f32(self, value: f32) -> Result<Value, ::ser::Error> { + self.serialize_f64(value.into()) + } + + fn serialize_f64(self, value: f64) -> Result<Value, ::ser::Error> { + Ok(Value::Float(value)) + } + + fn serialize_char(self, value: char) -> Result<Value, ::ser::Error> { + let mut s = String::new(); + s.push(value); + self.serialize_str(&s) + } + + fn serialize_str(self, value: &str) -> Result<Value, ::ser::Error> { + Ok(Value::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<Value, ::ser::Error> { + let vec = value.iter().map(|&b| Value::Integer(b.into())).collect(); + Ok(Value::Array(vec)) + } + + fn serialize_unit(self) -> Result<Value, ::ser::Error> { + Err(::ser::Error::UnsupportedType) + } + + fn serialize_unit_struct(self, _name: &'static str) + -> Result<Value, ::ser::Error> { + Err(::ser::Error::UnsupportedType) + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str) + -> Result<Value, ::ser::Error> { + self.serialize_str(_variant) + } + + fn serialize_newtype_struct<T: ?Sized>(self, + _name: &'static str, + value: &T) + -> Result<Value, ::ser::Error> + where T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T) + -> Result<Value, ::ser::Error> + where T: ser::Serialize, + { + Err(::ser::Error::UnsupportedType) + } + + fn serialize_none(self) -> Result<Value, ::ser::Error> { + Err(::ser::Error::UnsupportedNone) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Value, ::ser::Error> + where T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, len: Option<usize>) + -> Result<Self::SerializeSeq, ::ser::Error> + { + Ok(SerializeVec { + vec: Vec::with_capacity(len.unwrap_or(0)) + }) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, ::ser::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct(self, _name: &'static str, len: usize) + -> Result<Self::SerializeTupleStruct, ::ser::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize) + -> Result<Self::SerializeTupleVariant, ::ser::Error> + { + self.serialize_seq(Some(len)) + } + + fn serialize_map(self, _len: Option<usize>) + -> Result<Self::SerializeMap, ::ser::Error> + { + Ok(SerializeMap { + map: BTreeMap::new(), + next_key: None, + }) + } + + fn serialize_struct(self, _name: &'static str, len: usize) + -> Result<Self::SerializeStruct, ::ser::Error> { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize) + -> Result<Self::SerializeStructVariant, ::ser::Error> + { + Err(::ser::Error::UnsupportedType) + } +} + +struct SerializeVec { + vec: Vec<Value>, +} + +struct SerializeMap { + map: BTreeMap<String, Value>, + next_key: Option<String>, +} + +impl ser::SerializeSeq for SerializeVec { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + self.vec.push(Value::try_from(value)?); + Ok(()) + } + + fn end(self) -> Result<Value, ::ser::Error> { + Ok(Value::Array(self.vec)) + } +} + +impl ser::SerializeTuple for SerializeVec { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, ::ser::Error> { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleStruct for SerializeVec { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, ::ser::Error> { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeTupleVariant for SerializeVec { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Value, ::ser::Error> { + ser::SerializeSeq::end(self) + } +} + +impl ser::SerializeMap for SerializeMap { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + match Value::try_from(key)? { + Value::String(s) => self.next_key = Some(s), + _ => return Err(::ser::Error::KeyNotString), + }; + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + let key = self.next_key.take(); + let key = key.expect("serialize_value called before serialize_key"); + match Value::try_from(value) { + Ok(value) => { self.map.insert(key, value); } + Err(::ser::Error::UnsupportedNone) => {} + Err(e) => return Err(e), + } + Ok(()) + } + + fn end(self) -> Result<Value, ::ser::Error> { + Ok(Value::Table(self.map)) + } +} + +impl ser::SerializeStruct for SerializeMap { + type Ok = Value; + type Error = ::ser::Error; + + fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), ::ser::Error> + where T: ser::Serialize + { + ser::SerializeMap::serialize_key(self, key)?; + ser::SerializeMap::serialize_value(self, value) + } + + fn end(self) -> Result<Value, ::ser::Error> { + ser::SerializeMap::end(self) + } +} + +struct DatetimeOrTable<'a> { + key: &'a mut String, +} + +impl<'a, 'de> de::DeserializeSeed<'de> for DatetimeOrTable<'a> { + type Value = bool; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where D: de::Deserializer<'de> + { + deserializer.deserialize_any(self) + } +} + +impl<'a, 'de> de::Visitor<'de> for DatetimeOrTable<'a> { + type Value = bool; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string key") + } + + fn visit_str<E>(self, s: &str) -> Result<bool, E> + where E: de::Error, + { + if s == datetime::FIELD { + Ok(true) + } else { + self.key.push_str(s); + Ok(false) + } + } + + fn visit_string<E>(self, s: String) -> Result<bool, E> + where E: de::Error, + { + if s == datetime::FIELD { + Ok(true) + } else { + *self.key = s; + Ok(false) + } + } +} diff --git a/toml/tests/enum_external_deserialize.rs b/toml/tests/enum_external_deserialize.rs new file mode 100644 index 000000000..3c3858014 --- /dev/null +++ b/toml/tests/enum_external_deserialize.rs @@ -0,0 +1,238 @@ +#[macro_use] +extern crate serde_derive; +extern crate toml; + +#[derive(Debug, Deserialize, PartialEq)] +enum TheEnum { + Plain, + Tuple(i64, bool), + NewType(String), + Struct { value: i64 }, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Val { + val: TheEnum, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Multi { + enums: Vec<TheEnum>, +} + +#[test] +fn invalid_variant_returns_error_with_good_message_string() { + let error = toml::from_str::<TheEnum>("\"NonExistent\"").unwrap_err(); + + assert_eq!( + error.to_string(), + "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`" + ); +} + +#[test] +fn invalid_variant_returns_error_with_good_message_inline_table() { + let error = toml::from_str::<TheEnum>("{ NonExistent = {} }").unwrap_err(); + assert_eq!( + error.to_string(), + "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`" + ); +} + +#[test] +fn extra_field_returns_expected_empty_table_error() { + let error = toml::from_str::<TheEnum>("{ Plain = { extra_field = 404 } }").unwrap_err(); + + assert_eq!(error.to_string(), "expected empty table"); +} + +#[test] +fn extra_field_returns_expected_empty_table_error_struct_variant() { + let error = toml::from_str::<TheEnum>("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }") + .unwrap_err(); + + assert_eq!( + error.to_string(), + r#"unexpected keys in table: `["extra_0", "extra_1"]`, available keys: `["value"]`"# + ); +} + +mod enum_unit { + use super::*; + + #[test] + fn from_str() { + assert_eq!(TheEnum::Plain, toml::from_str("\"Plain\"").unwrap()); + } + + #[test] + fn from_inline_table() { + assert_eq!(TheEnum::Plain, toml::from_str("{ Plain = {} }").unwrap()); + assert_eq!( + Val { + val: TheEnum::Plain + }, + toml::from_str("val = { Plain = {} }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap()); + } +} + +mod enum_tuple { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + toml::from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Tuple(-123, true) + }, + toml::from_str("val = { Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + toml::from_str( + r#"[Tuple] + 0 = -123 + 1 = true + "# + ) + .unwrap() + ); + } +} + +mod enum_newtype { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + toml::from_str(r#"{ NewType = "value" }"#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str(r#"val = { NewType = "value" }"#).unwrap() + ); + } + + #[test] + #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"] + fn from_dotted_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + toml::from_str(r#"NewType = "value""#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str( + r#"[val] + NewType = "value" + "# + ) + .unwrap() + ); + } +} + +mod enum_struct { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + toml::from_str("{ Struct = { value = -123 } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Struct { value: -123 } + }, + toml::from_str("val = { Struct = { value = -123 } }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + toml::from_str( + r#"[Struct] + value = -123 + "# + ) + .unwrap() + ); + } +} + +mod enum_array { + use super::*; + + #[test] + fn from_inline_tables() { + let toml_str = r#" + enums = [ + { Plain = {} }, + { Tuple = { 0 = -123, 1 = true } }, + { NewType = "value" }, + { Struct = { value = -123 } } + ]"#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } + + #[test] + #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"] + fn from_dotted_table() { + let toml_str = r#"[[enums]] + Plain = {} + + [[enums]] + Tuple = { 0 = -123, 1 = true } + + [[enums]] + NewType = "value" + + [[enums]] + Struct = { value = -123 } + "#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } +} diff --git a/typenum/.cargo-checksum.json b/typenum/.cargo-checksum.json new file mode 100644 index 000000000..284de3860 --- /dev/null +++ b/typenum/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"} \ No newline at end of file diff --git a/typenum/.pc/.quilt_patches b/typenum/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/typenum/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/typenum/.pc/.quilt_series b/typenum/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/typenum/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/typenum/.pc/.version b/typenum/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/typenum/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/typenum/.pc/applied-patches b/typenum/.pc/applied-patches new file mode 100644 index 000000000..2f259e3eb --- /dev/null +++ b/typenum/.pc/applied-patches @@ -0,0 +1 @@ +pr115.patch diff --git a/typenum/.pc/pr115.patch/.timestamp b/typenum/.pc/pr115.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/typenum/.pc/pr115.patch/build/main.rs b/typenum/.pc/pr115.patch/build/main.rs new file mode 100644 index 000000000..9c9f237cd --- /dev/null +++ b/typenum/.pc/pr115.patch/build/main.rs @@ -0,0 +1,179 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::fmt; + +#[cfg(tests)] +mod tests; +mod op; + +pub enum UIntCode { + Term, + Zero(Box<UIntCode>), + One(Box<UIntCode>), +} + +pub enum IntCode { + Zero, + Pos(Box<UIntCode>), + Neg(Box<UIntCode>), +} + +impl fmt::Display for UIntCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + UIntCode::Term => write!(f, "UTerm"), + UIntCode::Zero(ref inner) => write!(f, "UInt<{}, B0>", inner), + UIntCode::One(ref inner) => write!(f, "UInt<{}, B1>", inner), + } + } +} + +impl fmt::Display for IntCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + IntCode::Zero => write!(f, "Z0"), + IntCode::Pos(ref inner) => write!(f, "PInt<{}>", inner), + IntCode::Neg(ref inner) => write!(f, "NInt<{}>", inner), + } + } +} + +pub fn gen_uint(u: u64) -> UIntCode { + let mut result = UIntCode::Term; + let mut x = 1u64 << 63; + while x > u { + x >>= 1 + } + while x > 0 { + result = if x & u > 0 { + UIntCode::One(Box::new(result)) + } else { + UIntCode::Zero(Box::new(result)) + }; + x >>= 1; + } + result +} + +pub fn gen_int(i: i64) -> IntCode { + if i > 0 { + IntCode::Pos(Box::new(gen_uint(i as u64))) + } else if i < 0 { + IntCode::Neg(Box::new(gen_uint(i.abs() as u64))) + } else { + IntCode::Zero + } +} + +#[cfg_attr(feature="no_std", deprecated( + since="1.3.0", + note="the `no_std` flag is no longer necessary and will be removed in the future"))] +pub fn no_std() {} + +// fixme: get a warning when testing without this +#[allow(dead_code)] +fn main() { + let highest: u64 = 1024; + + let first2: u32 = (highest as f64).log(2.0) as u32 + 1; + let first10: u32 = (highest as f64).log(10.0) as u32 + 1; + let uints = (0..(highest + 1)) + .chain((first2..64).map(|i| 2u64.pow(i))) + .chain((first10..20).map(|i| 10u64.pow(i))); + + let out_dir = env::var("OUT_DIR").unwrap(); + let dest = Path::new(&out_dir).join("consts.rs"); + + let mut f = File::create(&dest).unwrap(); + + no_std(); + + // Header stuff here! + write!( + f, + " +/** +Type aliases for many constants. + +This file is generated by typenum's build script. + +For unsigned integers, the format is `U` followed by the number. We define aliases for + +- Numbers 0 through {highest} +- Powers of 2 below `u64::MAX` +- Powers of 10 below `u64::MAX` + +These alias definitions look like this: + +```rust +use typenum::{{B0, B1, UInt, UTerm}}; + +# #[allow(dead_code)] +type U6 = UInt<UInt<UInt<UTerm, B1>, B1>, B0>; +``` + +For positive signed integers, the format is `P` followed by the number and for negative +signed integers it is `N` followed by the number. For the signed integer zero, we use +`Z0`. We define aliases for + +- Numbers -{highest} through {highest} +- Powers of 2 between `i64::MIN` and `i64::MAX` +- Powers of 10 between `i64::MIN` and `i64::MAX` + +These alias definitions look like this: + +```rust +use typenum::{{B0, B1, UInt, UTerm, PInt, NInt}}; + +# #[allow(dead_code)] +type P6 = PInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>; +# #[allow(dead_code)] +type N6 = NInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>; +``` + +# Example +```rust +# #[allow(unused_imports)] +use typenum::{{U0, U1, U2, U3, U4, U5, U6}}; +# #[allow(unused_imports)] +use typenum::{{N3, N2, N1, Z0, P1, P2, P3}}; +# #[allow(unused_imports)] +use typenum::{{U774, N17, N10000, P1024, P4096}}; +``` + +We also define the aliases `False` and `True` for `B0` and `B1`, respectively. +*/ +#[allow(missing_docs)] +pub mod consts {{ + use uint::{{UInt, UTerm}}; + use int::{{PInt, NInt}}; + + pub use bit::{{B0, B1}}; + pub use int::Z0; + + pub type True = B1; + pub type False = B0; +", + highest = highest + ).unwrap(); + + for u in uints { + write!(f, " pub type U{} = {};\n", u, gen_uint(u)).unwrap(); + if u <= ::std::i64::MAX as u64 && u != 0 { + let i = u as i64; + write!( + f, + " pub type P{i} = PInt<U{i}>; pub type N{i} = NInt<U{i}>;\n", + i = i + ).unwrap(); + } + } + write!(f, "}}").unwrap(); + + #[cfg(tests)] + tests::build_tests().unwrap(); + + op::write_op_macro().unwrap(); +} diff --git a/typenum/CHANGELOG.md b/typenum/CHANGELOG.md new file mode 100644 index 000000000..abb8e5527 --- /dev/null +++ b/typenum/CHANGELOG.md @@ -0,0 +1,56 @@ +# Changelog + +This project follows semantic versioning. + +### 1.10.0 (2018-03-11) +- [added] The `PowerOfTwo` marker trait. +- [added] Associated constants for `Bit`, `Unsigned`, and `Integer`. + +### 1.9.0 (2017-05-14) +- [added] The `Abs` type operater and corresponding `AbsVal` alias. +- [added] The feature `i128` that enables creating 128-bit integers from typenums. +- [added] The `assert_type!` and `assert_type_eq!` macros. +- [added] Operators to the `op!` macro, including those performed by `cmp!`. +- [fixed] Bug in `op!` macro involving functions and convoluted expressions. +- [deprecated] The `cmp!` macro. + +### 1.8.0 (2017-04-12) +- [added] The `op!` macro for conveniently performing type-level operations. +- [added] The `cmp!` macro for conveniently performing type-level comparisons. +- [added] Some comparison type-operators that are used by the `cmp!` macro. + +### 1.7.0 (2017-03-24) +- [added] Type operators `Min` and `Max` with accompanying aliases `Minimum` and `Maximum` + +### 1.6.0 (2017-02-24) +- [fixed] Bug in `Array` division. +- [fixed] Bug where `Rem` would sometimes exit early with the wrong answer. +- [added] `PartialDiv` operator that performs division as a partial function -- it's defined only + when there is no remainder. + +### 1.5.2 (2017-02-04) +- [fixed] Bug between `Div` implementation and type system. + +### 1.5.1 (2016-11-08) +- [fixed] Expanded implementation of `Pow` for primitives. + +### 1.5.0 (2016-11-03) +- [added] Functions to the `Pow` and `Len` traits. This is *technically* a breaking change, but it + would only break someone's code if they have a custom impl for `Pow`. I would be very surprised + if that is anyone other than me. + +### 1.4.0 (2016-10-29) +- [added] Type-level arrays of type-level integers. (PR #66) +- [added] The types in this crate are now instantiable. (Issue #67, PR #68) + +### 1.3.1 (2016-03-31) +- [fixed] Bug with recent nightlies. + +### 1.3.0 (2016-02-07) +- [changed] Removed dependency on libstd. (Issue #53, PR #55) +- [changed] Reorganized module structure. (PR #57) + +### 1.2.0 (2016-01-03) +- [added] This change log! +- [added] Convenience type aliases for operators. (Issue #48, PR #50) +- [added] Types in this crate now derive all possible traits. (Issue #42, PR #51) diff --git a/typenum/Cargo.toml b/typenum/Cargo.toml new file mode 100644 index 000000000..aceb434fc --- /dev/null +++ b/typenum/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "typenum" +version = "1.10.0" +authors = ["Paho Lurie-Gregg <paho@paholg.com>", "Andre Bogus <bogusandre@gmail.com>"] +build = "build/main.rs" +description = "Typenum is a Rust library for type-level numbers evaluated at compile time. It currently supports bits, unsigned integers, and signed integers. It also provides a type-level array of type-level numbers, but its implementation is incomplete." +documentation = "https://docs.rs/typenum" +readme = "README.md" +categories = ["no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/paholg/typenum" + +[lib] +name = "typenum" + +[features] +i128 = [] +no_std = [] +strict = [] diff --git a/typenum/LICENSE b/typenum/LICENSE new file mode 100644 index 000000000..e567a4d28 --- /dev/null +++ b/typenum/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Paho Lurie-Gregg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/typenum/README.md b/typenum/README.md new file mode 100644 index 000000000..e9d6ea24f --- /dev/null +++ b/typenum/README.md @@ -0,0 +1,42 @@ +[![crates.io](https://img.shields.io/crates/v/typenum.svg)](https://crates.io/crates/typenum) +[![Build Status](https://travis-ci.org/paholg/typenum.svg?branch=master)](https://travis-ci.org/paholg/typenum) + +Typenum +===== + +Typenum is a Rust library for type-level numbers evaluated at compile time. It currently +supports bits, unsigned integers, and signed integers. + +Typenum depends only on libcore, and so is suitable for use on any platform! + +For the full documentation, go [here](https://docs.rs/typenum). + +### Importing + +While `typenum` is divided into several modules, they are all re-exported through the crate root, +so you can import anything contained herein with `use typenum::whatever;`, ignoring the +crate structure. + +You may also find it useful to treat the `consts` module as a prelude, perfoming a glob import. + +### Example + +Here is a trivial example of `typenum`'s use: + +```rust +use typenum::{Sum, Exp, Integer, N2, P3, P4}; + +type X = Sum<P3, P4>; +assert_eq!(<X as Integer>::to_i32(), 7); + +type Y = Exp<N2, P3>; +assert_eq!(<Y as Integer>::to_i32(), -8); +``` + +For a non-trivial example of its use, see one of the crates that depends on it. The full +list is [here](https://crates.io/crates/typenum/reverse_dependencies). Of note are +[dimensioned](https://crates.io/crates/dimensioned/) which does compile-time type +checking for arbitrary unit systems and +[generic-array](https://crates.io/crates/generic-array/) which provides arrays whose +length you can generically refer to. + diff --git a/typenum/build/main.rs b/typenum/build/main.rs new file mode 100644 index 000000000..153031a2f --- /dev/null +++ b/typenum/build/main.rs @@ -0,0 +1,179 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::fmt; + +#[cfg(tests)] +mod tests; +mod op; + +pub enum UIntCode { + Term, + Zero(Box<UIntCode>), + One(Box<UIntCode>), +} + +pub enum IntCode { + Zero, + Pos(Box<UIntCode>), + Neg(Box<UIntCode>), +} + +impl fmt::Display for UIntCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + UIntCode::Term => write!(f, "UTerm"), + UIntCode::Zero(ref inner) => write!(f, "UInt<{}, B0>", inner), + UIntCode::One(ref inner) => write!(f, "UInt<{}, B1>", inner), + } + } +} + +impl fmt::Display for IntCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + IntCode::Zero => write!(f, "Z0"), + IntCode::Pos(ref inner) => write!(f, "PInt<{}>", inner), + IntCode::Neg(ref inner) => write!(f, "NInt<{}>", inner), + } + } +} + +pub fn gen_uint(u: u64) -> UIntCode { + let mut result = UIntCode::Term; + let mut x = 1u64 << 63; + while x > u { + x >>= 1 + } + while x > 0 { + result = if x & u > 0 { + UIntCode::One(Box::new(result)) + } else { + UIntCode::Zero(Box::new(result)) + }; + x >>= 1; + } + result +} + +pub fn gen_int(i: i64) -> IntCode { + if i > 0 { + IntCode::Pos(Box::new(gen_uint(i as u64))) + } else if i < 0 { + IntCode::Neg(Box::new(gen_uint(i.abs() as u64))) + } else { + IntCode::Zero + } +} + +#[cfg_attr(feature="no_std", deprecated( + since="1.3.0", + note="the `no_std` flag is no longer necessary and will be removed in the future"))] +pub fn no_std() {} + +// fixme: get a warning when testing without this +#[allow(dead_code)] +fn main() { + let highest: u64 = 1024; + + let first2: u32 = (highest as f64).log(2.0).round() as u32 + 1; + let first10: u32 = (highest as f64).log(10.0) as u32 + 1; + let uints = (0..(highest + 1)) + .chain((first2..64).map(|i| 2u64.pow(i))) + .chain((first10..20).map(|i| 10u64.pow(i))); + + let out_dir = env::var("OUT_DIR").unwrap(); + let dest = Path::new(&out_dir).join("consts.rs"); + + let mut f = File::create(&dest).unwrap(); + + no_std(); + + // Header stuff here! + write!( + f, + " +/** +Type aliases for many constants. + +This file is generated by typenum's build script. + +For unsigned integers, the format is `U` followed by the number. We define aliases for + +- Numbers 0 through {highest} +- Powers of 2 below `u64::MAX` +- Powers of 10 below `u64::MAX` + +These alias definitions look like this: + +```rust +use typenum::{{B0, B1, UInt, UTerm}}; + +# #[allow(dead_code)] +type U6 = UInt<UInt<UInt<UTerm, B1>, B1>, B0>; +``` + +For positive signed integers, the format is `P` followed by the number and for negative +signed integers it is `N` followed by the number. For the signed integer zero, we use +`Z0`. We define aliases for + +- Numbers -{highest} through {highest} +- Powers of 2 between `i64::MIN` and `i64::MAX` +- Powers of 10 between `i64::MIN` and `i64::MAX` + +These alias definitions look like this: + +```rust +use typenum::{{B0, B1, UInt, UTerm, PInt, NInt}}; + +# #[allow(dead_code)] +type P6 = PInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>; +# #[allow(dead_code)] +type N6 = NInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>>; +``` + +# Example +```rust +# #[allow(unused_imports)] +use typenum::{{U0, U1, U2, U3, U4, U5, U6}}; +# #[allow(unused_imports)] +use typenum::{{N3, N2, N1, Z0, P1, P2, P3}}; +# #[allow(unused_imports)] +use typenum::{{U774, N17, N10000, P1024, P4096}}; +``` + +We also define the aliases `False` and `True` for `B0` and `B1`, respectively. +*/ +#[allow(missing_docs)] +pub mod consts {{ + use uint::{{UInt, UTerm}}; + use int::{{PInt, NInt}}; + + pub use bit::{{B0, B1}}; + pub use int::Z0; + + pub type True = B1; + pub type False = B0; +", + highest = highest + ).unwrap(); + + for u in uints { + write!(f, " pub type U{} = {};\n", u, gen_uint(u)).unwrap(); + if u <= ::std::i64::MAX as u64 && u != 0 { + let i = u as i64; + write!( + f, + " pub type P{i} = PInt<U{i}>; pub type N{i} = NInt<U{i}>;\n", + i = i + ).unwrap(); + } + } + write!(f, "}}").unwrap(); + + #[cfg(tests)] + tests::build_tests().unwrap(); + + op::write_op_macro().unwrap(); +} diff --git a/typenum/build/op.rs b/typenum/build/op.rs new file mode 100644 index 000000000..d85e73b31 --- /dev/null +++ b/typenum/build/op.rs @@ -0,0 +1,533 @@ +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum OpType { + Operator, + Function, +} + +use self::OpType::*; + +struct Op { + token: &'static str, + operator: &'static str, + example: (&'static str, &'static str), + precedence: u8, + n_args: u8, + op_type: OpType, +} + +pub fn write_op_macro() -> ::std::io::Result<()> { + let out_dir = ::std::env::var("OUT_DIR").unwrap(); + let dest = ::std::path::Path::new(&out_dir).join("op.rs"); + let mut f = ::std::fs::File::create(&dest).unwrap(); + + // Operator precedence is taken from + // https://doc.rust-lang.org/reference.html#operator-precedence + // + // We choose 16 as the highest precedence (functions are set to 255 but it doesn't matter + // for them). We also only use operators that are left associative so we don't have to worry + // about that. + let ops = &[ + Op { + token: "*", + operator: "Prod", + example: ("P2 * P3", "P6"), + precedence: 16, + n_args: 2, + op_type: Operator, + }, + Op { + token: "/", + operator: "Quot", + example: ("P6 / P2", "P3"), + precedence: 16, + n_args: 2, + op_type: Operator, + }, + Op { + token: "%", + operator: "Mod", + example: ("P5 % P3", "P2"), + precedence: 16, + n_args: 2, + op_type: Operator, + }, + Op { + token: "+", + operator: "Sum", + example: ("P2 + P3", "P5"), + precedence: 15, + n_args: 2, + op_type: Operator, + }, + Op { + token: "-", + operator: "Diff", + example: ("P2 - P3", "N1"), + precedence: 15, + n_args: 2, + op_type: Operator, + }, + Op { + token: "<<", + operator: "Shleft", + example: ("U1 << U5", "U32"), + precedence: 14, + n_args: 2, + op_type: Operator, + }, + Op { + token: ">>", + operator: "Shright", + example: ("U32 >> U5", "U1"), + precedence: 14, + n_args: 2, + op_type: Operator, + }, + Op { + token: "&", + operator: "And", + example: ("U5 & U3", "U1"), + precedence: 13, + n_args: 2, + op_type: Operator, + }, + Op { + token: "^", + operator: "Xor", + example: ("U5 ^ U3", "U6"), + precedence: 12, + n_args: 2, + op_type: Operator, + }, + Op { + token: "|", + operator: "Or", + example: ("U5 | U3", "U7"), + precedence: 11, + n_args: 2, + op_type: Operator, + }, + Op { + token: "==", + operator: "Eq", + example: ("P5 == P3 + P2", "True"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: "!=", + operator: "NotEq", + example: ("P5 != P3 + P2", "False"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: "<=", + operator: "LeEq", + example: ("P6 <= P3 + P2", "False"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: ">=", + operator: "GrEq", + example: ("P6 >= P3 + P2", "True"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: "<", + operator: "Le", + example: ("P4 < P3 + P2", "True"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: ">", + operator: "Gr", + example: ("P5 < P3 + P2", "False"), + precedence: 10, + n_args: 2, + op_type: Operator, + }, + Op { + token: "cmp", + operator: "Compare", + example: ("cmp(P2, P3)", "Less"), + precedence: !0, + n_args: 2, + op_type: Function, + }, + Op { + token: "sqr", + operator: "Square", + example: ("sqr(P2)", "P4"), + precedence: !0, + n_args: 1, + op_type: Function, + }, + Op { + token: "abs", + operator: "AbsVal", + example: ("abs(N2)", "P2"), + precedence: !0, + n_args: 1, + op_type: Function, + }, + Op { + token: "cube", + operator: "Cube", + example: ("cube(P2)", "P8"), + precedence: !0, + n_args: 1, + op_type: Function, + }, + Op { + token: "pow", + operator: "Exp", + example: ("pow(P2, P3)", "P8"), + precedence: !0, + n_args: 2, + op_type: Function, + }, + Op { + token: "min", + operator: "Minimum", + example: ("min(P2, P3)", "P2"), + precedence: !0, + n_args: 2, + op_type: Function, + }, + Op { + token: "max", + operator: "Maximum", + example: ("max(P2, P3)", "P3"), + precedence: !0, + n_args: 2, + op_type: Function, + }, + ]; + + use std::io::Write; + write!( + f, + " +/** +Convenient type operations. + +Any types representing values must be able to be expressed as `ident`s. That means they need to be +in scope. + +For example, `P5` is okay, but `typenum::P5` is not. + +You may combine operators arbitrarily, although doing so excessively may require raising the +recursion limit. + +# Example +```rust +#![recursion_limit=\"128\"] +#[macro_use] extern crate typenum; +use typenum::consts::*; + +fn main() {{ + assert_type!( + op!(min((P1 - P2) * (N3 + N7), P5 * (P3 + P4)) == P10) + ); +}} +``` +Operators are evaluated based on the operator precedence outlined +[here](https://doc.rust-lang.org/reference.html#operator-precedence). + +The full list of supported operators and functions is as follows: + +{} + +They all expand to type aliases defined in the `operator_aliases` module. Here is an expanded list, +including examples: + +", + ops.iter() + .map(|op| format!("`{}`", op.token)) + .collect::<Vec<_>>() + .join(", ") + )?; + + //write!(f, "Token | Alias | Example\n ===|===|===\n")?; + + for op in ops.iter() { + write!( + f, + "---\nOperator `{token}`. Expands to `{operator}`. + +```rust +# #[macro_use] extern crate typenum; +# use typenum::*; +# fn main() {{ +assert_type_eq!(op!({ex0}), {ex1}); +# }} +```\n +", + token = op.token, + operator = op.operator, + ex0 = op.example.0, + ex1 = op.example.1 + )?; + } + + write!( + f, + "*/ +#[macro_export] +macro_rules! op {{ + ($($tail:tt)*) => ( __op_internal__!($($tail)*) ); +}} + + #[doc(hidden)] + #[macro_export] + macro_rules! __op_internal__ {{ +" + )?; + + // We first us the shunting-yard algorithm to produce our tokens in Polish notation. + // See: https://en.wikipedia.org/wiki/Shunting-yard_algorithm + + // Note: Due to macro asymmetry, "the top of the stack" refers to the first element, not the + // last + + // ----------------------------------------------------------------------------------------- + // Stage 1: There are tokens to be read: + + // ------- + // Case 1: Token is a function => Push it onto the stack: + for fun in ops.iter().filter(|f| f.op_type == Function) { + write!( + f, + " +(@stack[$($stack:ident,)*] @queue[$($queue:ident,)*] @tail: {f_token} $($tail:tt)*) => ( + __op_internal__!(@stack[{f_op}, $($stack,)*] @queue[$($queue,)*] @tail: $($tail)*) +);", + f_token = fun.token, + f_op = fun.operator + )?; + } + + // ------- + // Case 2: Token is a comma => Until the top of the stack is a LParen, + // Pop operators from stack to queue + + // Base case: Top of stack is LParen, ditch comma and continue + write!( + f, + " +(@stack[LParen, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: , $($tail:tt)*) => ( + __op_internal__!(@stack[LParen, $($stack,)*] @queue[$($queue,)*] @tail: $($tail)*) +);" + )?; + // Recursive case: Not LParen, pop from stack to queue + write!( + f, + " +(@stack[$stack_top:ident, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: , $($tail:tt)*) => ( + __op_internal__!(@stack[$($stack,)*] @queue[$stack_top, $($queue,)*] @tail: , $($tail)*) +);" + )?; + + // ------- + // Case 3: Token is an operator, o1: + for o1 in ops.iter().filter(|op| op.op_type == Operator) { + // If top of stack is operator o2 with o1.precedence <= o2.precedence, + // Then pop o2 off stack onto queue: + for o2 in ops.iter() + .filter(|op| op.op_type == Operator) + .filter(|o2| o1.precedence <= o2.precedence) + { + write!( + f, + " +(@stack[{o2_op}, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: {o1_token} $($tail:tt)*) => ( + __op_internal__!(@stack[$($stack,)*] @queue[{o2_op}, $($queue,)*] @tail: {o1_token} $($tail)*) +);", + o2_op = o2.operator, + o1_token = o1.token + )?; + } + // Base case: push o1 onto stack + write!( + f, + " +(@stack[$($stack:ident,)*] @queue[$($queue:ident,)*] @tail: {o1_token} $($tail:tt)*) => ( + __op_internal__!(@stack[{o1_op}, $($stack,)*] @queue[$($queue,)*] @tail: $($tail)*) +);", + o1_op = o1.operator, + o1_token = o1.token + )?; + } + + // ------- + // Case 4: Token is "(": push it onto stack as "LParen". Also convert the ")" to "RParen" to + // appease the macro gods: + write!( + f, + " +(@stack[$($stack:ident,)*] @queue[$($queue:ident,)*] @tail: ( $($stuff:tt)* ) $($tail:tt)* ) + => ( + __op_internal__!(@stack[LParen, $($stack,)*] @queue[$($queue,)*] + @tail: $($stuff)* RParen $($tail)*) +);" + )?; + + // ------- + // Case 5: Token is "RParen": + // 1. Pop from stack to queue until we see an "LParen", + // 2. Kill the "LParen", + // 3. If the top of the stack is a function, pop it onto the queue + // 2. Base case: + write!( + f, + " +(@stack[LParen, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: RParen $($tail:tt)*) => ( + __op_internal__!(@rp3 @stack[$($stack,)*] @queue[$($queue,)*] @tail: $($tail)*) +);" + )?; + // 1. Recursive case: + write!( + f, + " +(@stack[$stack_top:ident, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: RParen $($tail:tt)*) + => ( + __op_internal__!(@stack[$($stack,)*] @queue[$stack_top, $($queue,)*] @tail: RParen $($tail)*) +);" + )?; + // 3. Check for function: + for fun in ops.iter().filter(|f| f.op_type == Function) { + write!( + f, + " +(@rp3 @stack[{fun_op}, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail: $($tail:tt)*) => ( + __op_internal__!(@stack[$($stack,)*] @queue[{fun_op}, $($queue,)*] @tail: $($tail)*) +);", + fun_op = fun.operator + )?; + } + // 3. If no function found: + write!( + f, + " +(@rp3 @stack[$($stack:ident,)*] @queue[$($queue:ident,)*] @tail: $($tail:tt)*) => ( + __op_internal__!(@stack[$($stack,)*] @queue[$($queue,)*] @tail: $($tail)*) +);" + )?; + + // ------- + // Case 6: Token is a number: Push it onto the queue + write!( + f, + " +(@stack[$($stack:ident,)*] @queue[$($queue:ident,)*] @tail: $num:ident $($tail:tt)*) => ( + __op_internal__!(@stack[$($stack,)*] @queue[$num, $($queue,)*] @tail: $($tail)*) +);" + )?; + + // ------- + // Case 7: Out of tokens: + // Base case: Stack empty: Start evaluating + write!( + f, + " +(@stack[] @queue[$($queue:ident,)*] @tail: ) => ( + __op_internal__!(@reverse[] @input: $($queue,)*) +);" + )?; + // Recursive case: Pop stack to queue + write!( + f, + " +(@stack[$stack_top:ident, $($stack:ident,)*] @queue[$($queue:ident,)*] @tail:) => ( + __op_internal__!(@stack[$($stack,)*] @queue[$stack_top, $($queue,)*] @tail: ) +);" + )?; + + // ----------------------------------------------------------------------------------------- + // Stage 2: Reverse so we have RPN + write!( + f, + " +(@reverse[$($revved:ident,)*] @input: $head:ident, $($tail:ident,)* ) => ( + __op_internal__!(@reverse[$head, $($revved,)*] @input: $($tail,)*) +);" + )?; + write!( + f, + " +(@reverse[$($revved:ident,)*] @input: ) => ( + __op_internal__!(@eval @stack[] @input[$($revved,)*]) +);" + )?; + + // ----------------------------------------------------------------------------------------- + // Stage 3: Evaluate in Reverse Polish Notation + // Operators / Operators with 2 args: + for op in ops.iter().filter(|op| op.n_args == 2) { + // Note: We have to switch $a and $b here, otherwise non-commutative functions are backwards + write!( + f, + " +(@eval @stack[$a:ty, $b:ty, $($stack:ty,)*] @input[{op}, $($tail:ident,)*]) => ( + __op_internal__!(@eval @stack[$crate::{op}<$b, $a>, $($stack,)*] @input[$($tail,)*]) +);", + op = op.operator + )?; + } + // Operators with 1 arg: + for op in ops.iter().filter(|op| op.n_args == 1) { + write!( + f, + " +(@eval @stack[$a:ty, $($stack:ty,)*] @input[{op}, $($tail:ident,)*]) => ( + __op_internal__!(@eval @stack[$crate::{op}<$a>, $($stack,)*] @input[$($tail,)*]) +);", + op = op.operator + )?; + } + + // Wasn't a function or operator, so must be a value => push onto stack + write!( + f, + " +(@eval @stack[$($stack:ty,)*] @input[$head:ident, $($tail:ident,)*]) => ( + __op_internal__!(@eval @stack[$head, $($stack,)*] @input[$($tail,)*]) +);" + )?; + + // No input left: + write!( + f, + " +(@eval @stack[$stack:ty,] @input[]) => ( + $stack +);" + )?; + + // ----------------------------------------------------------------------------------------- + // Stage 0: Get it started + write!( + f, + " +($($tail:tt)* ) => ( + __op_internal__!(@stack[] @queue[] @tail: $($tail)*) +);" + )?; + + write!( + f, + " +}}" + )?; + + Ok(()) +} diff --git a/typenum/build/tests.rs b/typenum/build/tests.rs new file mode 100644 index 000000000..3ae74e67d --- /dev/null +++ b/typenum/build/tests.rs @@ -0,0 +1,301 @@ +use std::{env, fmt, fs, io, path}; + +use super::{gen_int, gen_uint}; + +fn sign(i: i64) -> char { + if i > 0 { + 'P' + } else if i < 0 { + 'N' + } else { + '_' + } +} + +struct UIntTest { + a: u64, + op: &'static str, + b: Option<u64>, + r: u64, +} + +impl fmt::Display for UIntTest { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.b { + Some(b) => write!( + f, + " +#[test] +#[allow(non_snake_case)] +fn test_{a}_{op}_{b}() {{ + type A = {gen_a}; + type B = {gen_b}; + type U{r} = {result}; + + #[allow(non_camel_case_types)] + type U{a}{op}U{b} = <<A as {op}<B>>::Output as Same<U{r}>>::Output; + + assert_eq!(<U{a}{op}U{b} as Unsigned>::to_u64(), <U{r} as Unsigned>::to_u64()); +}}", + gen_a = gen_uint(self.a), + gen_b = gen_uint(b), + r = self.r, + result = gen_uint(self.r), + a = self.a, + b = b, + op = self.op + ), + None => write!( + f, + " +#[test] +#[allow(non_snake_case)] +fn test_{a}_{op}() {{ + type A = {gen_a}; + type U{r} = {result}; + + #[allow(non_camel_case_types)] + type {op}U{a} = <<A as {op}>::Output as Same<U{r}>>::Output; + assert_eq!(<{op}U{a} as Unsigned>::to_u64(), <U{r} as Unsigned>::to_u64()); +}}", + gen_a = gen_uint(self.a), + r = self.r, + result = gen_uint(self.r), + a = self.a, + op = self.op + ), + } + } +} + +fn uint_binary_test(a: u64, op: &'static str, b: u64, result: u64) -> UIntTest { + UIntTest { + a: a, + op: op, + b: Option::Some(b), + r: result, + } +} + +// fn uint_unary_test(op: &'static str, a: u64, result: u64) -> UIntTest { +// UIntTest { a: a, op: op, b: Option::None, r: result } +// } + +struct IntBinaryTest { + a: i64, + op: &'static str, + b: i64, + r: i64, +} + +impl fmt::Display for IntBinaryTest { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + " +#[test] +#[allow(non_snake_case)] +fn test_{sa}{a}_{op}_{sb}{b}() {{ + type A = {gen_a}; + type B = {gen_b}; + type {sr}{r} = {result}; + + #[allow(non_camel_case_types)] + type {sa}{a}{op}{sb}{b} = <<A as {op}<B>>::Output as Same<{sr}{r}>>::Output; + + assert_eq!(<{sa}{a}{op}{sb}{b} as Integer>::to_i64(), <{sr}{r} as Integer>::to_i64()); +}}", + gen_a = gen_int(self.a), + gen_b = gen_int(self.b), + r = self.r.abs(), + sr = sign(self.r), + result = gen_int(self.r), + a = self.a.abs(), + b = self.b.abs(), + sa = sign(self.a), + sb = sign(self.b), + op = self.op + ) + } +} + +fn int_binary_test(a: i64, op: &'static str, b: i64, result: i64) -> IntBinaryTest { + IntBinaryTest { + a: a, + op: op, + b: b, + r: result, + } +} + +struct IntUnaryTest { + op: &'static str, + a: i64, + r: i64, +} + +impl fmt::Display for IntUnaryTest { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + " +#[test] +#[allow(non_snake_case)] +fn test_{sa}{a}_{op}() {{ + type A = {gen_a}; + type {sr}{r} = {result}; + + #[allow(non_camel_case_types)] + type {op}{sa}{a} = <<A as {op}>::Output as Same<{sr}{r}>>::Output; + assert_eq!(<{op}{sa}{a} as Integer>::to_i64(), <{sr}{r} as Integer>::to_i64()); +}}", + gen_a = gen_int(self.a), + r = self.r.abs(), + sr = sign(self.r), + result = gen_int(self.r), + a = self.a.abs(), + sa = sign(self.a), + op = self.op + ) + } +} + +fn int_unary_test(op: &'static str, a: i64, result: i64) -> IntUnaryTest { + IntUnaryTest { + op: op, + a: a, + r: result, + } +} + +fn uint_cmp_test(a: u64, b: u64) -> String { + format!( + " +#[test] +#[allow(non_snake_case)] +fn test_{a}_cmp_{b}() {{ + type A = {gen_a}; + type B = {gen_b}; + + #[allow(non_camel_case_types)] + type U{a}CmpU{b} = <A as Cmp<B>>::Output; + assert_eq!(<U{a}CmpU{b} as Ord>::to_ordering(), Ordering::{result:?}); +}}", + a = a, + b = b, + gen_a = gen_uint(a), + gen_b = gen_uint(b), + result = a.cmp(&b) + ) +} + +fn int_cmp_test(a: i64, b: i64) -> String { + format!( + " +#[test] +#[allow(non_snake_case)] +fn test_{sa}{a}_cmp_{sb}{b}() {{ + type A = {gen_a}; + type B = {gen_b}; + + #[allow(non_camel_case_types)] + type {sa}{a}Cmp{sb}{b} = <A as Cmp<B>>::Output; + assert_eq!(<{sa}{a}Cmp{sb}{b} as Ord>::to_ordering(), Ordering::{result:?}); +}}", + a = a.abs(), + b = b.abs(), + sa = sign(a), + sb = sign(b), + gen_a = gen_int(a), + gen_b = gen_int(b), + result = a.cmp(&b) + ) +} + +pub fn build_tests() -> Result<(), Box<::std::error::Error>> { + // will test all permutations of number pairs up to this (and down to its opposite for ints) + let high: i64 = 5; + + let uints = (0u64..high as u64 + 1).flat_map(|a| (a..a + 1).cycle().zip(0..high as u64 + 1)); + let ints = (-high..high + 1).flat_map(|a| (a..a + 1).cycle().zip(-high..high + 1)); + + let out_dir = env::var("OUT_DIR")?; + let dest = path::Path::new(&out_dir).join("tests.rs"); + let f = fs::File::create(&dest)?; + let mut writer = io::BufWriter::new(&f); + use std::io::Write; + writer.write( + b" +extern crate typenum; + +use std::ops::*; +use std::cmp::Ordering; +use typenum::*; +", + )?; + use std::cmp; + // uint operators: + for (a, b) in uints { + write!(writer, "{}", uint_binary_test(a, "BitAnd", b, a & b))?; + write!(writer, "{}", uint_binary_test(a, "BitOr", b, a | b))?; + write!(writer, "{}", uint_binary_test(a, "BitXor", b, a ^ b))?; + write!(writer, "{}", uint_binary_test(a, "Shl", b, a << b))?; + write!(writer, "{}", uint_binary_test(a, "Shr", b, a >> b))?; + write!(writer, "{}", uint_binary_test(a, "Add", b, a + b))?; + write!(writer, "{}", uint_binary_test(a, "Min", b, cmp::min(a, b)))?; + write!(writer, "{}", uint_binary_test(a, "Max", b, cmp::max(a, b)))?; + if a >= b { + write!(writer, "{}", uint_binary_test(a, "Sub", b, a - b))?; + } + write!(writer, "{}", uint_binary_test(a, "Mul", b, a * b))?; + if b != 0 { + write!(writer, "{}", uint_binary_test(a, "Div", b, a / b))?; + write!(writer, "{}", uint_binary_test(a, "Rem", b, a % b))?; + if a % b == 0 { + write!(writer, "{}", uint_binary_test(a, "PartialDiv", b, a / b))?; + } + } + write!(writer, "{}", uint_binary_test(a, "Pow", b, a.pow(b as u32)))?; + write!(writer, "{}", uint_cmp_test(a, b))?; + } + // int operators: + for (a, b) in ints { + write!(writer, "{}", int_binary_test(a, "Add", b, a + b))?; + write!(writer, "{}", int_binary_test(a, "Sub", b, a - b))?; + write!(writer, "{}", int_binary_test(a, "Mul", b, a * b))?; + write!(writer, "{}", int_binary_test(a, "Min", b, cmp::min(a, b)))?; + write!(writer, "{}", int_binary_test(a, "Max", b, cmp::max(a, b)))?; + if b != 0 { + write!(writer, "{}", int_binary_test(a, "Div", b, a / b))?; + write!(writer, "{}", int_binary_test(a, "Rem", b, a % b))?; + if a % b == 0 { + write!(writer, "{}", int_binary_test(a, "PartialDiv", b, a / b))?; + } + } + if b >= 0 || a.abs() == 1 { + let result = if b < 0 { + if a == 1 { + a + } else if a == -1 { + a.pow((-b) as u32) + } else { + unreachable!() + } + } else { + a.pow(b as u32) + }; + write!(writer, "{}", int_binary_test(a, "Pow", b, result))?; + } + write!(writer, "{}", int_cmp_test(a, b))?; + } + + // int unary operators: + for n in -high..high + 1 { + write!(writer, "{}", int_unary_test("Neg", n, -n))?; + write!(writer, "{}", int_unary_test("Abs", n, n.abs()))?; + } + + writer.flush()?; + + Ok(()) +} diff --git a/typenum/debian/patches/pr115.patch b/typenum/debian/patches/pr115.patch new file mode 100644 index 000000000..d0b4517b9 --- /dev/null +++ b/typenum/debian/patches/pr115.patch @@ -0,0 +1,23 @@ +From 0d5196feadafa77c727f517d747ffcf3fd0e8ba9 Mon Sep 17 00:00:00 2001 +From: Michael Hudson-Doyle <michael.hudson@canonical.com> +Date: Wed, 13 Mar 2019 15:55:30 +1300 +Subject: [PATCH] round result of (highest as f64).log(2.0) + +Even though (1024f64).log(2.0) has an exact, representable, value, with rustc 1.32 on i386 it comes out as +9.999999999999999985 with optimization enabled. And the rustc doesn't like having two defintions for U1024 etc. +--- + build/main.rs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/build/main.rs b/build/main.rs +index 16b0ffe2f..b7939f993 100644 +--- a/build/main.rs ++++ b/build/main.rs +@@ -81,7 +81,7 @@ pub fn no_std() {} + fn main() { + let highest: u64 = 1024; + +- let first2: u32 = (highest as f64).log(2.0) as u32 + 1; ++ let first2: u32 = (highest as f64).log(2.0).round() as u32 + 1; + let first10: u32 = (highest as f64).log(10.0) as u32 + 1; + let uints = (0..(highest + 1)) + .chain((first2..64).map(|i| 2u64.pow(i))) diff --git a/typenum/debian/patches/series b/typenum/debian/patches/series new file mode 100644 index 000000000..2f259e3eb --- /dev/null +++ b/typenum/debian/patches/series @@ -0,0 +1 @@ +pr115.patch diff --git a/typenum/src/array.rs b/typenum/src/array.rs new file mode 100644 index 000000000..22873a3ea --- /dev/null +++ b/typenum/src/array.rs @@ -0,0 +1,282 @@ +//! A type-level array of type-level numbers. +//! +//! It is not very featureful right now, and should be considered a work in progress. + +use core::marker::PhantomData; +use core::ops::{Add, Div, Mul, Sub}; + +use super::*; + +/// The terminating type for type arrays. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug)] +pub struct ATerm; + +impl TypeArray for ATerm {} + +/// `TArr` is a type that acts as an array of types. It is defined similarly to `UInt`, only its +/// values can be more than bits, and it is designed to act as an array. So you can only add two if +/// they have the same number of elements, for example. +/// +/// This array is only really designed to contain `Integer` types. If you use it with others, you +/// may find it lacking functionality. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug)] +pub struct TArr<V, A> { + _marker: PhantomData<(V, A)>, +} + +impl<V, A> TypeArray for TArr<V, A> {} + +/// Create a new type-level arrray. Only usable on Rust 1.13.0 or newer. +/// +/// There's not a whole lot you can do with it right now. +/// +/// # Example +/// ```rust +/// #[macro_use] +/// extern crate typenum; +/// use typenum::consts::*; +/// +/// type Array = tarr![P3, N4, Z0, P38]; +/// # fn main() { let _: Array; } +#[macro_export] +macro_rules! tarr { + () => ( $crate::ATerm ); + ($n:ty) => ( $crate::TArr<$n, $crate::ATerm> ); + ($n:ty,) => ( $crate::TArr<$n, $crate::ATerm> ); + ($n:ty, $($tail:ty),+) => ( $crate::TArr<$n, tarr![$($tail),+]> ); + ($n:ty, $($tail:ty),+,) => ( $crate::TArr<$n, tarr![$($tail),+]> ); +} + +// --------------------------------------------------------------------------------------- +// Length + +/// Length of `ATerm` by itself is 0 +impl Len for ATerm { + type Output = U0; + fn len(&self) -> Self::Output { + UTerm + } +} + +/// Size of a `TypeArray` +impl<V, A> Len for TArr<V, A> +where + A: Len, + Length<A>: Add<B1>, + Sum<Length<A>, B1>: Unsigned, +{ + type Output = Add1<Length<A>>; + fn len(&self) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Add arrays +// Note that two arrays are only addable if they are the same length. + +impl Add<ATerm> for ATerm { + type Output = ATerm; + fn add(self, _: ATerm) -> Self::Output { + ATerm + } +} + +impl<Al, Vl, Ar, Vr> Add<TArr<Vr, Ar>> for TArr<Vl, Al> +where + Al: Add<Ar>, + Vl: Add<Vr>, +{ + type Output = TArr<Sum<Vl, Vr>, Sum<Al, Ar>>; + fn add(self, _: TArr<Vr, Ar>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Subtract arrays +// Note that two arrays are only subtractable if they are the same length. + +impl Sub<ATerm> for ATerm { + type Output = ATerm; + fn sub(self, _: ATerm) -> Self::Output { + ATerm + } +} + +impl<Vl, Al, Vr, Ar> Sub<TArr<Vr, Ar>> for TArr<Vl, Al> +where + Vl: Sub<Vr>, + Al: Sub<Ar>, +{ + type Output = TArr<Diff<Vl, Vr>, Diff<Al, Ar>>; + fn sub(self, _: TArr<Vr, Ar>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Multiply an array by a scalar + +impl<Rhs> Mul<Rhs> for ATerm { + type Output = ATerm; + fn mul(self, _: Rhs) -> Self::Output { + ATerm + } +} + +impl<V, A, Rhs> Mul<Rhs> for TArr<V, A> +where + V: Mul<Rhs>, + A: Mul<Rhs>, +{ + type Output = TArr<Prod<V, Rhs>, Prod<A, Rhs>>; + fn mul(self, _: Rhs) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl Mul<ATerm> for Z0 { + type Output = ATerm; + fn mul(self, _: ATerm) -> Self::Output { + ATerm + } +} + +impl<U> Mul<ATerm> for PInt<U> +where + U: Unsigned + NonZero, +{ + type Output = ATerm; + fn mul(self, _: ATerm) -> Self::Output { + ATerm + } +} + +impl<U> Mul<ATerm> for NInt<U> +where + U: Unsigned + NonZero, +{ + type Output = ATerm; + fn mul(self, _: ATerm) -> Self::Output { + ATerm + } +} + +impl<V, A> Mul<TArr<V, A>> for Z0 +where + Z0: Mul<A>, +{ + type Output = TArr<Z0, Prod<Z0, A>>; + fn mul(self, _: TArr<V, A>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl<V, A, U> Mul<TArr<V, A>> for PInt<U> +where + U: Unsigned + NonZero, + PInt<U>: Mul<A> + Mul<V>, +{ + type Output = TArr<Prod<PInt<U>, V>, Prod<PInt<U>, A>>; + fn mul(self, _: TArr<V, A>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl<V, A, U> Mul<TArr<V, A>> for NInt<U> +where + U: Unsigned + NonZero, + NInt<U>: Mul<A> + Mul<V>, +{ + type Output = TArr<Prod<NInt<U>, V>, Prod<NInt<U>, A>>; + fn mul(self, _: TArr<V, A>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Divide an array by a scalar + +impl<Rhs> Div<Rhs> for ATerm { + type Output = ATerm; + fn div(self, _: Rhs) -> Self::Output { + ATerm + } +} + +impl<V, A, Rhs> Div<Rhs> for TArr<V, A> +where + V: Div<Rhs>, + A: Div<Rhs>, +{ + type Output = TArr<Quot<V, Rhs>, Quot<A, Rhs>>; + fn div(self, _: Rhs) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Partial Divide an array by a scalar + +impl<Rhs> PartialDiv<Rhs> for ATerm { + type Output = ATerm; + fn partial_div(self, _: Rhs) -> Self::Output { + ATerm + } +} + +impl<V, A, Rhs> PartialDiv<Rhs> for TArr<V, A> +where + V: PartialDiv<Rhs>, + A: PartialDiv<Rhs>, +{ + type Output = TArr<PartialQuot<V, Rhs>, PartialQuot<A, Rhs>>; + fn partial_div(self, _: Rhs) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Modulo an array by a scalar +use core::ops::Rem; + +impl<Rhs> Rem<Rhs> for ATerm { + type Output = ATerm; + fn rem(self, _: Rhs) -> Self::Output { + ATerm + } +} + +impl<V, A, Rhs> Rem<Rhs> for TArr<V, A> +where + V: Rem<Rhs>, + A: Rem<Rhs>, +{ + type Output = TArr<Mod<V, Rhs>, Mod<A, Rhs>>; + fn rem(self, _: Rhs) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Negate an array +use core::ops::Neg; + +impl Neg for ATerm { + type Output = ATerm; + fn neg(self) -> Self::Output { + ATerm + } +} + +impl<V, A> Neg for TArr<V, A> +where + V: Neg, + A: Neg, +{ + type Output = TArr<Negate<V>, Negate<A>>; + fn neg(self) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} diff --git a/typenum/src/bit.rs b/typenum/src/bit.rs new file mode 100644 index 000000000..f7c7dacab --- /dev/null +++ b/typenum/src/bit.rs @@ -0,0 +1,272 @@ +//! Type-level bits. +//! +//! These are rather simple and are used as the building blocks of the +//! other number types in this crate. +//! +//! +//! **Type operators** implemented: +//! +//! - From `core::ops`: `BitAnd`, `BitOr`, `BitXor`, and `Not`. +//! - From `typenum`: `Same` and `Cmp`. +//! + +use core::ops::{BitAnd, BitOr, BitXor, Not}; +use {Cmp, Equal, Greater, Less, NonZero, PowerOfTwo}; + +pub use marker_traits::Bit; + +/// The type-level bit 0. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct B0; + +impl B0 { + /// Instantiates a singleton representing this bit. + #[inline] + pub fn new() -> B0 { + B0 + } +} + +/// The type-level bit 1. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct B1; + +impl B1 { + /// Instantiates a singleton representing this bit. + #[inline] + pub fn new() -> B1 { + B1 + } +} + +impl Bit for B0 { + const U8: u8 = 0; + const BOOL: bool = false; + + #[inline] + fn to_u8() -> u8 { + 0 + } + #[inline] + fn to_bool() -> bool { + false + } +} + +impl Bit for B1 { + const U8: u8 = 1; + const BOOL: bool = true; + + #[inline] + fn to_u8() -> u8 { + 1 + } + #[inline] + fn to_bool() -> bool { + true + } +} + +impl NonZero for B1 {} +impl PowerOfTwo for B1 {} + +/// Not of 0 (!0 = 1) +impl Not for B0 { + type Output = B1; + fn not(self) -> Self::Output { + B1 + } +} +/// Not of 1 (!1 = 0) +impl Not for B1 { + type Output = B0; + fn not(self) -> Self::Output { + B0 + } +} + +/// And with 0 ( 0 & B = 0) +impl<Rhs: Bit> BitAnd<Rhs> for B0 { + type Output = B0; + fn bitand(self, _: Rhs) -> Self::Output { + B0 + } +} + +/// And with 1 ( 1 & 0 = 0) +impl BitAnd<B0> for B1 { + type Output = B0; + fn bitand(self, _: B0) -> Self::Output { + B0 + } +} + +/// And with 1 ( 1 & 1 = 1) +impl BitAnd<B1> for B1 { + type Output = B1; + fn bitand(self, _: B1) -> Self::Output { + B1 + } +} + +/// Or with 0 ( 0 | 0 = 0) +impl BitOr<B0> for B0 { + type Output = B0; + fn bitor(self, _: B0) -> Self::Output { + B0 + } +} + +/// Or with 0 ( 0 | 1 = 1) +impl BitOr<B1> for B0 { + type Output = B1; + fn bitor(self, _: B1) -> Self::Output { + B1 + } +} + +/// Or with 1 ( 1 | B = 1) +impl<Rhs: Bit> BitOr<Rhs> for B1 { + type Output = B1; + fn bitor(self, _: Rhs) -> Self::Output { + B1 + } +} + +/// Xor between 0 and 0 ( 0 ^ 0 = 0) +impl BitXor<B0> for B0 { + type Output = B0; + fn bitxor(self, _: B0) -> Self::Output { + B0 + } +} +/// Xor between 1 and 0 ( 1 ^ 0 = 1) +impl BitXor<B0> for B1 { + type Output = B1; + fn bitxor(self, _: B0) -> Self::Output { + B1 + } +} +/// Xor between 0 and 1 ( 0 ^ 1 = 1) +impl BitXor<B1> for B0 { + type Output = B1; + fn bitxor(self, _: B1) -> Self::Output { + B1 + } +} +/// Xor between 1 and 1 ( 1 ^ 1 = 0) +impl BitXor<B1> for B1 { + type Output = B0; + fn bitxor(self, _: B1) -> Self::Output { + B0 + } +} + +#[cfg(tests)] +mod tests { + // macro for testing operation results. Uses `Same` to ensure the types are equal and + // not just the values they evaluate to. + macro_rules! test_bit_op { + ($op:ident $Lhs:ident = $Answer:ident) => ( + { + type Test = <<$Lhs as $op>::Output as ::Same<$Answer>>::Output; + assert_eq!(<$Answer as Bit>::to_u8(), <Test as Bit>::to_u8()); + } + ); + ($Lhs:ident $op:ident $Rhs:ident = $Answer:ident) => ( + { + type Test = <<$Lhs as $op<$Rhs>>::Output as ::Same<$Answer>>::Output; + assert_eq!(<$Answer as Bit>::to_u8(), <Test as Bit>::to_u8()); + } + ); + } + + #[test] + fn bit_operations() { + test_bit_op!(Not B0 = B1); + test_bit_op!(Not B1 = B0); + + test_bit_op!(B0 BitAnd B0 = B0); + test_bit_op!(B0 BitAnd B1 = B0); + test_bit_op!(B1 BitAnd B0 = B0); + test_bit_op!(B1 BitAnd B1 = B1); + + test_bit_op!(B0 BitOr B0 = B0); + test_bit_op!(B0 BitOr B1 = B1); + test_bit_op!(B1 BitOr B0 = B1); + test_bit_op!(B1 BitOr B1 = B1); + + test_bit_op!(B0 BitXor B0 = B0); + test_bit_op!(B0 BitXor B1 = B1); + test_bit_op!(B1 BitXor B0 = B1); + test_bit_op!(B1 BitXor B1 = B0); + } +} + +impl Cmp<B0> for B0 { + type Output = Equal; +} + +impl Cmp<B1> for B0 { + type Output = Less; +} + +impl Cmp<B0> for B1 { + type Output = Greater; +} + +impl Cmp<B1> for B1 { + type Output = Equal; +} + +use Min; +impl Min<B0> for B0 { + type Output = B0; + fn min(self, _: B0) -> B0 { + self + } +} +impl Min<B1> for B0 { + type Output = B0; + fn min(self, _: B1) -> B0 { + self + } +} +impl Min<B0> for B1 { + type Output = B0; + fn min(self, rhs: B0) -> B0 { + rhs + } +} +impl Min<B1> for B1 { + type Output = B1; + fn min(self, _: B1) -> B1 { + self + } +} + +use Max; +impl Max<B0> for B0 { + type Output = B0; + fn max(self, _: B0) -> B0 { + self + } +} +impl Max<B1> for B0 { + type Output = B1; + fn max(self, rhs: B1) -> B1 { + rhs + } +} +impl Max<B0> for B1 { + type Output = B1; + fn max(self, _: B0) -> B1 { + self + } +} +impl Max<B1> for B1 { + type Output = B1; + fn max(self, _: B1) -> B1 { + self + } +} diff --git a/typenum/src/int.rs b/typenum/src/int.rs new file mode 100644 index 000000000..2554a4052 --- /dev/null +++ b/typenum/src/int.rs @@ -0,0 +1,935 @@ +//! Type-level signed integers. +//! +//! +//! Type **operators** implemented: +//! +//! From `core::ops`: `Add`, `Sub`, `Mul`, `Div`, and `Rem`. +//! From `typenum`: `Same`, `Cmp`, and `Pow`. +//! +//! Rather than directly using the structs defined in this module, it is recommended that +//! you import and use the relevant aliases from the [consts](../consts/index.html) module. +//! +//! Note that operators that work on the underlying structure of the number are +//! intentionally not implemented. This is because this implementation of signed integers +//! does *not* use twos-complement, and implementing them would require making arbitrary +//! choices, causing the results of such operators to be difficult to reason about. +//! +//! # Example +//! ```rust +//! use std::ops::{Add, Sub, Mul, Div, Rem}; +//! use typenum::{Integer, N3, P2}; +//! +//! assert_eq!(<N3 as Add<P2>>::Output::to_i32(), -1); +//! assert_eq!(<N3 as Sub<P2>>::Output::to_i32(), -5); +//! assert_eq!(<N3 as Mul<P2>>::Output::to_i32(), -6); +//! assert_eq!(<N3 as Div<P2>>::Output::to_i32(), -1); +//! assert_eq!(<N3 as Rem<P2>>::Output::to_i32(), -1); +//! ``` +//! + +use core::ops::{Add, Div, Mul, Neg, Rem, Sub}; +use core::marker::PhantomData; + +use {Cmp, Equal, Greater, Less, NonZero, Pow, PowerOfTwo}; +use uint::{UInt, Unsigned}; +use bit::{B0, B1, Bit}; +use private::{PrivateDivInt, PrivateIntegerAdd, PrivateRem}; +use consts::{N1, P1, U0, U1}; + +pub use marker_traits::Integer; + +/// Type-level signed integers with positive sign. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct PInt<U: Unsigned + NonZero> { + _marker: PhantomData<U>, +} + +/// Type-level signed integers with negative sign. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct NInt<U: Unsigned + NonZero> { + _marker: PhantomData<U>, +} + +impl<U: Unsigned + NonZero> PInt<U> { + /// Instantiates a singleton representing this strictly positive integer. + #[inline] + pub fn new() -> PInt<U> { + PInt { + _marker: PhantomData, + } + } +} + +impl<U: Unsigned + NonZero> NInt<U> { + /// Instantiates a singleton representing this strictly negative integer. + #[inline] + pub fn new() -> NInt<U> { + NInt { + _marker: PhantomData, + } + } +} + +/// The type-level signed integer 0. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct Z0; + +impl Z0 { + /// Instantiates a singleton representing the integer 0. + #[inline] + pub fn new() -> Z0 { + Z0 + } +} + +impl<U: Unsigned + NonZero> NonZero for PInt<U> {} +impl<U: Unsigned + NonZero> NonZero for NInt<U> {} + +impl<U: Unsigned + NonZero + PowerOfTwo> PowerOfTwo for PInt<U> {} + +impl Integer for Z0 { + const I8: i8 = 0; + const I16: i16 = 0; + const I32: i32 = 0; + const I64: i64 = 0; + #[cfg(feature = "i128")] + const I128: i128 = 0; + const ISIZE: isize = 0; + + #[inline] + fn to_i8() -> i8 { + 0 + } + #[inline] + fn to_i16() -> i16 { + 0 + } + #[inline] + fn to_i32() -> i32 { + 0 + } + #[inline] + fn to_i64() -> i64 { + 0 + } + #[cfg(feature = "i128")] + #[inline] + fn to_i128() -> i128 { + 0 + } + #[inline] + fn to_isize() -> isize { + 0 + } +} + +impl<U: Unsigned + NonZero> Integer for PInt<U> { + const I8: i8 = U::I8; + const I16: i16 = U::I16; + const I32: i32 = U::I32; + const I64: i64 = U::I64; + #[cfg(feature = "i128")] + const I128: i128 = U::I128; + const ISIZE: isize = U::ISIZE; + + #[inline] + fn to_i8() -> i8 { + <U as Unsigned>::to_i8() + } + #[inline] + fn to_i16() -> i16 { + <U as Unsigned>::to_i16() + } + #[inline] + fn to_i32() -> i32 { + <U as Unsigned>::to_i32() + } + #[inline] + fn to_i64() -> i64 { + <U as Unsigned>::to_i64() + } + #[cfg(feature = "i128")] + #[inline] + fn to_i128() -> i128 { + <U as Unsigned>::to_i128() + } + #[inline] + fn to_isize() -> isize { + <U as Unsigned>::to_isize() + } +} + +impl<U: Unsigned + NonZero> Integer for NInt<U> { + const I8: i8 = -U::I8; + const I16: i16 = -U::I16; + const I32: i32 = -U::I32; + const I64: i64 = -U::I64; + #[cfg(feature = "i128")] + const I128: i128 = -U::I128; + const ISIZE: isize = -U::ISIZE; + + #[inline] + fn to_i8() -> i8 { + -<U as Unsigned>::to_i8() + } + #[inline] + fn to_i16() -> i16 { + -<U as Unsigned>::to_i16() + } + #[inline] + fn to_i32() -> i32 { + -<U as Unsigned>::to_i32() + } + #[inline] + fn to_i64() -> i64 { + -<U as Unsigned>::to_i64() + } + #[cfg(feature = "i128")] + #[inline] + fn to_i128() -> i128 { + -<U as Unsigned>::to_i128() + } + #[inline] + fn to_isize() -> isize { + -<U as Unsigned>::to_isize() + } +} + +// --------------------------------------------------------------------------------------- +// Neg + +/// `-Z0 = Z0` +impl Neg for Z0 { + type Output = Z0; + fn neg(self) -> Self::Output { + Z0 + } +} + +/// `-PInt = NInt` +impl<U: Unsigned + NonZero> Neg for PInt<U> { + type Output = NInt<U>; + fn neg(self) -> Self::Output { + NInt::new() + } +} + +/// `-NInt = PInt` +impl<U: Unsigned + NonZero> Neg for NInt<U> { + type Output = PInt<U>; + fn neg(self) -> Self::Output { + PInt::new() + } +} + +// --------------------------------------------------------------------------------------- +// Add + +/// `Z0 + I = I` +impl<I: Integer> Add<I> for Z0 { + type Output = I; + fn add(self, _: I) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `PInt + Z0 = PInt` +impl<U: Unsigned + NonZero> Add<Z0> for PInt<U> { + type Output = PInt<U>; + fn add(self, _: Z0) -> Self::Output { + PInt::new() + } +} + +/// `NInt + Z0 = NInt` +impl<U: Unsigned + NonZero> Add<Z0> for NInt<U> { + type Output = NInt<U>; + fn add(self, _: Z0) -> Self::Output { + NInt::new() + } +} + +/// `P(Ul) + P(Ur) = P(Ul + Ur)` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Add<PInt<Ur>> for PInt<Ul> +where + Ul: Add<Ur>, + <Ul as Add<Ur>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Add<Ur>>::Output>; + fn add(self, _: PInt<Ur>) -> Self::Output { + PInt::new() + } +} + +/// `N(Ul) + N(Ur) = N(Ul + Ur)` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Add<NInt<Ur>> for NInt<Ul> +where + Ul: Add<Ur>, + <Ul as Add<Ur>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<Ul as Add<Ur>>::Output>; + fn add(self, _: NInt<Ur>) -> Self::Output { + NInt::new() + } +} + +/// `P(Ul) + N(Ur)`: We resolve this with our `PrivateAdd` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Add<NInt<Ur>> for PInt<Ul> +where + Ul: Cmp<Ur> + PrivateIntegerAdd<<Ul as Cmp<Ur>>::Output, Ur>, +{ + type Output = <Ul as PrivateIntegerAdd<<Ul as Cmp<Ur>>::Output, Ur>>::Output; + fn add(self, _: NInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `N(Ul) + P(Ur)`: We resolve this with our `PrivateAdd` +// We just do the same thing as above, swapping Lhs and Rhs +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Add<PInt<Ur>> for NInt<Ul> +where + Ur: Cmp<Ul> + PrivateIntegerAdd<<Ur as Cmp<Ul>>::Output, Ul>, +{ + type Output = <Ur as PrivateIntegerAdd<<Ur as Cmp<Ul>>::Output, Ul>>::Output; + fn add(self, _: PInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `P + N = 0` where `P == N` +impl<N: Unsigned, P: Unsigned> PrivateIntegerAdd<Equal, N> for P { + type Output = Z0; +} + +/// `P + N = Positive` where `P > N` +impl<N: Unsigned, P: Unsigned> PrivateIntegerAdd<Greater, N> for P +where + P: Sub<N>, + <P as Sub<N>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<P as Sub<N>>::Output>; +} + +/// `P + N = Negative` where `P < N` +impl<N: Unsigned, P: Unsigned> PrivateIntegerAdd<Less, N> for P +where + N: Sub<P>, + <N as Sub<P>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<N as Sub<P>>::Output>; +} + +// --------------------------------------------------------------------------------------- +// Sub + +/// `Z0 - Z0 = Z0` +impl Sub<Z0> for Z0 { + type Output = Z0; + fn sub(self, _: Z0) -> Self::Output { + Z0 + } +} + +/// `Z0 - P = N` +impl<U: Unsigned + NonZero> Sub<PInt<U>> for Z0 { + type Output = NInt<U>; + fn sub(self, _: PInt<U>) -> Self::Output { + NInt::new() + } +} + +/// `Z0 - N = P` +impl<U: Unsigned + NonZero> Sub<NInt<U>> for Z0 { + type Output = PInt<U>; + fn sub(self, _: NInt<U>) -> Self::Output { + PInt::new() + } +} + +/// `PInt - Z0 = PInt` +impl<U: Unsigned + NonZero> Sub<Z0> for PInt<U> { + type Output = PInt<U>; + fn sub(self, _: Z0) -> Self::Output { + PInt::new() + } +} + +/// `NInt - Z0 = NInt` +impl<U: Unsigned + NonZero> Sub<Z0> for NInt<U> { + type Output = NInt<U>; + fn sub(self, _: Z0) -> Self::Output { + NInt::new() + } +} + +/// `P(Ul) - N(Ur) = P(Ul + Ur)` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Sub<NInt<Ur>> for PInt<Ul> +where + Ul: Add<Ur>, + <Ul as Add<Ur>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Add<Ur>>::Output>; + fn sub(self, _: NInt<Ur>) -> Self::Output { + PInt::new() + } +} + +/// `N(Ul) - P(Ur) = N(Ul + Ur)` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Sub<PInt<Ur>> for NInt<Ul> +where + Ul: Add<Ur>, + <Ul as Add<Ur>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<Ul as Add<Ur>>::Output>; + fn sub(self, _: PInt<Ur>) -> Self::Output { + NInt::new() + } +} + +/// `P(Ul) - P(Ur)`: We resolve this with our `PrivateAdd` +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Sub<PInt<Ur>> for PInt<Ul> +where + Ul: Cmp<Ur> + PrivateIntegerAdd<<Ul as Cmp<Ur>>::Output, Ur>, +{ + type Output = <Ul as PrivateIntegerAdd<<Ul as Cmp<Ur>>::Output, Ur>>::Output; + fn sub(self, _: PInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `N(Ul) - N(Ur)`: We resolve this with our `PrivateAdd` +// We just do the same thing as above, swapping Lhs and Rhs +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Sub<NInt<Ur>> for NInt<Ul> +where + Ur: Cmp<Ul> + PrivateIntegerAdd<<Ur as Cmp<Ul>>::Output, Ul>, +{ + type Output = <Ur as PrivateIntegerAdd<<Ur as Cmp<Ul>>::Output, Ul>>::Output; + fn sub(self, _: NInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Mul + +/// `Z0 * I = Z0` +impl<I: Integer> Mul<I> for Z0 { + type Output = Z0; + fn mul(self, _: I) -> Self::Output { + Z0 + } +} + +/// `P * Z0 = Z0` +impl<U: Unsigned + NonZero> Mul<Z0> for PInt<U> { + type Output = Z0; + fn mul(self, _: Z0) -> Self::Output { + Z0 + } +} + +/// `N * Z0 = Z0` +impl<U: Unsigned + NonZero> Mul<Z0> for NInt<U> { + type Output = Z0; + fn mul(self, _: Z0) -> Self::Output { + Z0 + } +} + +/// P(Ul) * P(Ur) = P(Ul * Ur) +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Mul<PInt<Ur>> for PInt<Ul> +where + Ul: Mul<Ur>, + <Ul as Mul<Ur>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Mul<Ur>>::Output>; + fn mul(self, _: PInt<Ur>) -> Self::Output { + PInt::new() + } +} + +/// N(Ul) * N(Ur) = P(Ul * Ur) +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Mul<NInt<Ur>> for NInt<Ul> +where + Ul: Mul<Ur>, + <Ul as Mul<Ur>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Mul<Ur>>::Output>; + fn mul(self, _: NInt<Ur>) -> Self::Output { + PInt::new() + } +} + +/// P(Ul) * N(Ur) = N(Ul * Ur) +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Mul<NInt<Ur>> for PInt<Ul> +where + Ul: Mul<Ur>, + <Ul as Mul<Ur>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<Ul as Mul<Ur>>::Output>; + fn mul(self, _: NInt<Ur>) -> Self::Output { + NInt::new() + } +} + +/// N(Ul) * P(Ur) = N(Ul * Ur) +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Mul<PInt<Ur>> for NInt<Ul> +where + Ul: Mul<Ur>, + <Ul as Mul<Ur>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<Ul as Mul<Ur>>::Output>; + fn mul(self, _: PInt<Ur>) -> Self::Output { + NInt::new() + } +} + +// --------------------------------------------------------------------------------------- +// Div + +/// `Z0 / I = Z0` where `I != 0` +impl<I: Integer + NonZero> Div<I> for Z0 { + type Output = Z0; + fn div(self, _: I) -> Self::Output { + Z0 + } +} + +macro_rules! impl_int_div { + ($A:ident, $B:ident, $R:ident) => ( + /// `$A<Ul> / $B<Ur> = $R<Ul / Ur>` + impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Div<$B<Ur>> for $A<Ul> + where Ul: Cmp<Ur>, + $A<Ul>: PrivateDivInt<<Ul as Cmp<Ur>>::Output, $B<Ur>> + { + type Output = <$A<Ul> as PrivateDivInt< + <Ul as Cmp<Ur>>::Output, + $B<Ur>>>::Output; + fn div(self, _: $B<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } + } + impl<Ul, Ur> PrivateDivInt<Less, $B<Ur>> for $A<Ul> + where Ul: Unsigned + NonZero, Ur: Unsigned + NonZero, + { + type Output = Z0; + } + impl<Ul, Ur> PrivateDivInt<Equal, $B<Ur>> for $A<Ul> + where Ul: Unsigned + NonZero, Ur: Unsigned + NonZero, + { + type Output = $R<U1>; + } + impl<Ul, Ur> PrivateDivInt<Greater, $B<Ur>> for $A<Ul> + where Ul: Unsigned + NonZero + Div<Ur>, + Ur: Unsigned + NonZero, + <Ul as Div<Ur>>::Output: Unsigned + NonZero, + { + type Output = $R<<Ul as Div<Ur>>::Output>; + } + ); +} + +impl_int_div!(PInt, PInt, PInt); +impl_int_div!(PInt, NInt, NInt); +impl_int_div!(NInt, PInt, NInt); +impl_int_div!(NInt, NInt, PInt); + +// --------------------------------------------------------------------------------------- +// PartialDiv + +use {PartialDiv, Quot}; + +impl<M, N> PartialDiv<N> for M +where + M: Integer + Div<N> + Rem<N, Output = Z0>, +{ + type Output = Quot<M, N>; + fn partial_div(self, _: N) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Cmp + +/// 0 == 0 +impl Cmp<Z0> for Z0 { + type Output = Equal; +} + +/// 0 > -X +impl<U: Unsigned + NonZero> Cmp<NInt<U>> for Z0 { + type Output = Greater; +} + +/// 0 < X +impl<U: Unsigned + NonZero> Cmp<PInt<U>> for Z0 { + type Output = Less; +} + +/// X > 0 +impl<U: Unsigned + NonZero> Cmp<Z0> for PInt<U> { + type Output = Greater; +} + +/// -X < 0 +impl<U: Unsigned + NonZero> Cmp<Z0> for NInt<U> { + type Output = Less; +} + +/// -X < Y +impl<P: Unsigned + NonZero, N: Unsigned + NonZero> Cmp<PInt<P>> for NInt<N> { + type Output = Less; +} + +/// X > - Y +impl<P: Unsigned + NonZero, N: Unsigned + NonZero> Cmp<NInt<N>> for PInt<P> { + type Output = Greater; +} + +/// X <==> Y +impl<Pl: Cmp<Pr> + Unsigned + NonZero, Pr: Unsigned + NonZero> Cmp<PInt<Pr>> for PInt<Pl> { + type Output = <Pl as Cmp<Pr>>::Output; +} + +/// -X <==> -Y +impl<Nl: Unsigned + NonZero, Nr: Cmp<Nl> + Unsigned + NonZero> Cmp<NInt<Nr>> for NInt<Nl> { + type Output = <Nr as Cmp<Nl>>::Output; +} + +// --------------------------------------------------------------------------------------- +// Rem + +/// `Z0 % I = Z0` where `I != 0` +impl<I: Integer + NonZero> Rem<I> for Z0 { + type Output = Z0; + fn rem(self, _: I) -> Self::Output { + Z0 + } +} + +macro_rules! impl_int_rem { + ($A:ident, $B:ident, $R:ident) => ( + /// `$A<Ul> % $B<Ur> = $R<Ul % Ur>` + impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Rem<$B<Ur>> for $A<Ul> + where Ul: Rem<Ur>, + $A<Ul>: PrivateRem<<Ul as Rem<Ur>>::Output, $B<Ur>> + { + type Output = <$A<Ul> as PrivateRem< + <Ul as Rem<Ur>>::Output, + $B<Ur>>>::Output; + fn rem(self, _: $B<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } + } + impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> PrivateRem<U0, $B<Ur>> for $A<Ul> { + type Output = Z0; + } + impl<Ul, Ur, U, B> PrivateRem<UInt<U, B>, $B<Ur>> for $A<Ul> + where Ul: Unsigned + NonZero, Ur: Unsigned + NonZero, U: Unsigned, B: Bit, + { + type Output = $R<UInt<U, B>>; + } + ); +} + +impl_int_rem!(PInt, PInt, PInt); +impl_int_rem!(PInt, NInt, PInt); +impl_int_rem!(NInt, PInt, NInt); +impl_int_rem!(NInt, NInt, NInt); + +// --------------------------------------------------------------------------------------- +// Pow + +/// 0^0 = 1 +impl Pow<Z0> for Z0 { + type Output = P1; + fn powi(self, _: Z0) -> Self::Output { + P1::new() + } +} + +/// 0^P = 0 +impl<U: Unsigned + NonZero> Pow<PInt<U>> for Z0 { + type Output = Z0; + fn powi(self, _: PInt<U>) -> Self::Output { + Z0 + } +} + +/// 0^N = 0 +impl<U: Unsigned + NonZero> Pow<NInt<U>> for Z0 { + type Output = Z0; + fn powi(self, _: NInt<U>) -> Self::Output { + Z0 + } +} + +/// 1^N = 1 +impl<U: Unsigned + NonZero> Pow<NInt<U>> for P1 { + type Output = P1; + fn powi(self, _: NInt<U>) -> Self::Output { + P1::new() + } +} + +/// (-1)^N = 1 if N is even +impl<U: Unsigned> Pow<NInt<UInt<U, B0>>> for N1 { + type Output = P1; + fn powi(self, _: NInt<UInt<U, B0>>) -> Self::Output { + P1::new() + } +} + +/// (-1)^N = -1 if N is odd +impl<U: Unsigned> Pow<NInt<UInt<U, B1>>> for N1 { + type Output = N1; + fn powi(self, _: NInt<UInt<U, B1>>) -> Self::Output { + N1::new() + } +} + +/// P^0 = 1 +impl<U: Unsigned + NonZero> Pow<Z0> for PInt<U> { + type Output = P1; + fn powi(self, _: Z0) -> Self::Output { + P1::new() + } +} + +/// N^0 = 1 +impl<U: Unsigned + NonZero> Pow<Z0> for NInt<U> { + type Output = P1; + fn powi(self, _: Z0) -> Self::Output { + P1::new() + } +} + +/// P(Ul)^P(Ur) = P(Ul^Ur) +impl<Ul: Unsigned + NonZero, Ur: Unsigned + NonZero> Pow<PInt<Ur>> for PInt<Ul> +where + Ul: Pow<Ur>, + <Ul as Pow<Ur>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Pow<Ur>>::Output>; + fn powi(self, _: PInt<Ur>) -> Self::Output { + PInt::new() + } +} + +/// N(Ul)^P(Ur) = P(Ul^Ur) if Ur is even +impl<Ul: Unsigned + NonZero, Ur: Unsigned> Pow<PInt<UInt<Ur, B0>>> for NInt<Ul> +where + Ul: Pow<UInt<Ur, B0>>, + <Ul as Pow<UInt<Ur, B0>>>::Output: Unsigned + NonZero, +{ + type Output = PInt<<Ul as Pow<UInt<Ur, B0>>>::Output>; + fn powi(self, _: PInt<UInt<Ur, B0>>) -> Self::Output { + PInt::new() + } +} + +/// N(Ul)^P(Ur) = N(Ul^Ur) if Ur is odd +impl<Ul: Unsigned + NonZero, Ur: Unsigned> Pow<PInt<UInt<Ur, B1>>> for NInt<Ul> +where + Ul: Pow<UInt<Ur, B1>>, + <Ul as Pow<UInt<Ur, B1>>>::Output: Unsigned + NonZero, +{ + type Output = NInt<<Ul as Pow<UInt<Ur, B1>>>::Output>; + fn powi(self, _: PInt<UInt<Ur, B1>>) -> Self::Output { + NInt::new() + } +} + +// --------------------------------------------------------------------------------------- +// Min +use {Max, Maximum, Min, Minimum}; + +impl Min<Z0> for Z0 { + type Output = Z0; + fn min(self, _: Z0) -> Self::Output { + self + } +} + +impl<U> Min<PInt<U>> for Z0 +where + U: Unsigned + NonZero, +{ + type Output = Z0; + fn min(self, _: PInt<U>) -> Self::Output { + self + } +} + +impl<U> Min<NInt<U>> for Z0 +where + U: Unsigned + NonZero, +{ + type Output = NInt<U>; + fn min(self, rhs: NInt<U>) -> Self::Output { + rhs + } +} + +impl<U> Min<Z0> for PInt<U> +where + U: Unsigned + NonZero, +{ + type Output = Z0; + fn min(self, rhs: Z0) -> Self::Output { + rhs + } +} + +impl<U> Min<Z0> for NInt<U> +where + U: Unsigned + NonZero, +{ + type Output = NInt<U>; + fn min(self, _: Z0) -> Self::Output { + self + } +} + +impl<Ul, Ur> Min<PInt<Ur>> for PInt<Ul> +where + Ul: Unsigned + NonZero + Min<Ur>, + Ur: Unsigned + NonZero, + Minimum<Ul, Ur>: Unsigned + NonZero, +{ + type Output = PInt<Minimum<Ul, Ur>>; + fn min(self, _: PInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl<Ul, Ur> Min<PInt<Ur>> for NInt<Ul> +where + Ul: Unsigned + NonZero, + Ur: Unsigned + NonZero, +{ + type Output = NInt<Ul>; + fn min(self, _: PInt<Ur>) -> Self::Output { + self + } +} + +impl<Ul, Ur> Min<NInt<Ur>> for PInt<Ul> +where + Ul: Unsigned + NonZero, + Ur: Unsigned + NonZero, +{ + type Output = NInt<Ur>; + fn min(self, rhs: NInt<Ur>) -> Self::Output { + rhs + } +} + +impl<Ul, Ur> Min<NInt<Ur>> for NInt<Ul> +where + Ul: Unsigned + NonZero + Max<Ur>, + Ur: Unsigned + NonZero, + Maximum<Ul, Ur>: Unsigned + NonZero, +{ + type Output = NInt<Maximum<Ul, Ur>>; + fn min(self, _: NInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Max + +impl Max<Z0> for Z0 { + type Output = Z0; + fn max(self, _: Z0) -> Self::Output { + self + } +} + +impl<U> Max<PInt<U>> for Z0 +where + U: Unsigned + NonZero, +{ + type Output = PInt<U>; + fn max(self, rhs: PInt<U>) -> Self::Output { + rhs + } +} + +impl<U> Max<NInt<U>> for Z0 +where + U: Unsigned + NonZero, +{ + type Output = Z0; + fn max(self, _: NInt<U>) -> Self::Output { + self + } +} + +impl<U> Max<Z0> for PInt<U> +where + U: Unsigned + NonZero, +{ + type Output = PInt<U>; + fn max(self, _: Z0) -> Self::Output { + self + } +} + +impl<U> Max<Z0> for NInt<U> +where + U: Unsigned + NonZero, +{ + type Output = Z0; + fn max(self, rhs: Z0) -> Self::Output { + rhs + } +} + +impl<Ul, Ur> Max<PInt<Ur>> for PInt<Ul> +where + Ul: Unsigned + NonZero + Max<Ur>, + Ur: Unsigned + NonZero, + Maximum<Ul, Ur>: Unsigned + NonZero, +{ + type Output = PInt<Maximum<Ul, Ur>>; + fn max(self, _: PInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl<Ul, Ur> Max<PInt<Ur>> for NInt<Ul> +where + Ul: Unsigned + NonZero, + Ur: Unsigned + NonZero, +{ + type Output = PInt<Ur>; + fn max(self, rhs: PInt<Ur>) -> Self::Output { + rhs + } +} + +impl<Ul, Ur> Max<NInt<Ur>> for PInt<Ul> +where + Ul: Unsigned + NonZero, + Ur: Unsigned + NonZero, +{ + type Output = PInt<Ul>; + fn max(self, _: NInt<Ur>) -> Self::Output { + self + } +} + +impl<Ul, Ur> Max<NInt<Ur>> for NInt<Ul> +where + Ul: Unsigned + NonZero + Min<Ur>, + Ur: Unsigned + NonZero, + Minimum<Ul, Ur>: Unsigned + NonZero, +{ + type Output = NInt<Minimum<Ul, Ur>>; + fn max(self, _: NInt<Ur>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} diff --git a/typenum/src/lib.rs b/typenum/src/lib.rs new file mode 100644 index 000000000..bca4ddb5e --- /dev/null +++ b/typenum/src/lib.rs @@ -0,0 +1,135 @@ +//! This crate provides type-level numbers evaluated at compile time. It depends only on libcore. +//! +//! The traits defined or used in this crate are used in a typical manner. They can be divided into +//! two categories: **marker traits** and **type operators**. +//! +//! Many of the marker traits have functions defined, but they all do essentially the same thing: +//! convert a type into its runtime counterpart, and are really just there for debugging. For +//! example, +//! +//! ```rust +//! use typenum::{N4, Integer}; +//! +//! assert_eq!(N4::to_i32(), -4); +//! ``` +//! +//! **Type operators** are traits that behave as functions at the type level. These are the meat of +//! this library. Where possible, traits defined in libcore have been used, but their attached +//! functions have not been implemented. +//! +//! For example, the `Add` trait is implemented for both unsigned and signed integers, but the +//! `add` function is not. As there are never any objects of the types defined here, it wouldn't +//! make sense to implement it. What is important is its associated type `Output`, which is where +//! the addition happens. +//! +//! ```rust +//! use std::ops::Add; +//! use typenum::{Integer, P3, P4}; +//! +//! type X = <P3 as Add<P4>>::Output; +//! assert_eq!(<X as Integer>::to_i32(), 7); +//! ``` +//! +//! In addition, helper aliases are defined for type operators. For example, the above snippet +//! could be replaced with +//! +//! ```rust +//! use typenum::{Sum, Integer, P3, P4}; +//! +//! type X = Sum<P3, P4>; +//! assert_eq!(<X as Integer>::to_i32(), 7); +//! ``` +//! +//! Documented in each module is the full list of type operators implemented. +//! + +#![no_std] +#![warn(missing_docs)] +#![cfg_attr(feature = "i128", feature(i128_type))] +#![cfg_attr(feature = "strict", deny(missing_docs))] +#![cfg_attr(feature = "strict", deny(warnings))] +#![cfg_attr(feature = "cargo-clippy", deny(clippy))] +#![cfg_attr(feature = "cargo-clippy", + allow(type_complexity, len_without_is_empty, new_without_default_derive))] + +// For debugging macros: +// #![feature(trace_macros)] +// trace_macros!(true); + +use core::cmp::Ordering; + +include!(concat!(env!("OUT_DIR"), "/consts.rs")); +include!(concat!(env!("OUT_DIR"), "/op.rs")); +pub mod bit; +pub mod uint; +pub mod int; +pub mod private; +pub mod marker_traits; +pub mod type_operators; +pub mod operator_aliases; + +pub mod array; + +pub use consts::*; +pub use marker_traits::*; +pub use type_operators::*; +pub use operator_aliases::*; + +pub use uint::{UInt, UTerm}; +pub use int::{NInt, PInt}; +pub use array::{ATerm, TArr}; + +/// A potential output from `Cmp`, this is the type equivalent to the enum variant +/// `core::cmp::Ordering::Greater`. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct Greater; + +/// A potential output from `Cmp`, this is the type equivalent to the enum variant +/// `core::cmp::Ordering::Less`. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct Less; + +/// A potential output from `Cmp`, this is the type equivalent to the enum variant +/// `core::cmp::Ordering::Equal`. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct Equal; + +/// Returns `core::cmp::Ordering::Greater` +impl Ord for Greater { + #[inline] + fn to_ordering() -> Ordering { + Ordering::Greater + } +} + +/// Returns `core::cmp::Ordering::Less` +impl Ord for Less { + #[inline] + fn to_ordering() -> Ordering { + Ordering::Less + } +} + +/// Returns `core::cmp::Ordering::Equal` +impl Ord for Equal { + #[inline] + fn to_ordering() -> Ordering { + Ordering::Equal + } +} + +/// Asserts that two types are the same. +#[macro_export] +macro_rules! assert_type_eq { + ($a:ty, $b:ty) => ( + let _: <$a as $crate::Same<$b>>::Output; + ); +} + +/// Asserts that a type is `True`, aka `B1`. +#[macro_export] +macro_rules! assert_type { + ($a:ty) => ( + let _: <$a as $crate::Same<True>>::Output; + ); +} diff --git a/typenum/src/marker_traits.rs b/typenum/src/marker_traits.rs new file mode 100644 index 000000000..85c8ff02a --- /dev/null +++ b/typenum/src/marker_traits.rs @@ -0,0 +1,194 @@ +//! All of the **marker traits** used in typenum. +//! +//! Note that the definition here for marker traits is slightly different than +//! the conventional one -- we include traits with functions that convert a type +//! to the corresponding value, as well as associated constants that do the +//! same. +//! +//! For example, the `Integer` trait includes the function (among others) `fn +//! to_i32() -> i32` and the associated constant `I32` so that one can do this: +//! +//! ``` +//! use typenum::{N42, Integer}; +//! +//! assert_eq!(-42, N42::to_i32()); +//! assert_eq!(-42, N42::I32); +//! ``` +//! + +/// A **marker trait** to designate that a type is not zero. All number types in this +/// crate implement `NonZero` except `B0`, `U0`, and `Z0`. +pub trait NonZero {} + +/// A **Marker trait** for the types `Greater`, `Equal`, and `Less`. +/// +/// This trait should not be implemented for anything outside this crate. +pub trait Ord { + #[allow(missing_docs)] + fn to_ordering() -> ::core::cmp::Ordering; +} + +/// The **marker trait** for compile time bits. +/// +/// This trait should not be implemented for anything outside this crate. +pub trait Bit { + #[allow(missing_docs)] + const U8: u8; + #[allow(missing_docs)] + const BOOL: bool; + + #[allow(missing_docs)] + fn to_u8() -> u8; + #[allow(missing_docs)] + fn to_bool() -> bool; +} + +/// The **marker trait** for compile time unsigned integers. +/// +/// This trait should not be implemented for anything outside this crate. +/// +/// # Example +/// ```rust +/// use typenum::{U3, Unsigned}; +/// +/// assert_eq!(U3::to_u32(), 3); +/// assert_eq!(U3::I32, 3); +/// ``` +pub trait Unsigned { + #[allow(missing_docs)] + const U8: u8; + #[allow(missing_docs)] + const U16: u16; + #[allow(missing_docs)] + const U32: u32; + #[allow(missing_docs)] + const U64: u64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + const U128: u128; + #[allow(missing_docs)] + const USIZE: usize; + + #[allow(missing_docs)] + const I8: i8; + #[allow(missing_docs)] + const I16: i16; + #[allow(missing_docs)] + const I32: i32; + #[allow(missing_docs)] + const I64: i64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + const I128: i128; + #[allow(missing_docs)] + const ISIZE: isize; + + #[allow(missing_docs)] + fn to_u8() -> u8; + #[allow(missing_docs)] + fn to_u16() -> u16; + #[allow(missing_docs)] + fn to_u32() -> u32; + #[allow(missing_docs)] + fn to_u64() -> u64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + fn to_u128() -> u128; + #[allow(missing_docs)] + fn to_usize() -> usize; + + #[allow(missing_docs)] + fn to_i8() -> i8; + #[allow(missing_docs)] + fn to_i16() -> i16; + #[allow(missing_docs)] + fn to_i32() -> i32; + #[allow(missing_docs)] + fn to_i64() -> i64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + fn to_i128() -> i128; + #[allow(missing_docs)] + fn to_isize() -> isize; +} + +/// The **marker trait** for compile time signed integers. +/// +/// This trait should not be implemented for anything outside this crate. +/// +/// # Example +/// ```rust +/// use typenum::{P3, Integer}; +/// +/// assert_eq!(P3::to_i32(), 3); +/// assert_eq!(P3::I32, 3); +/// ``` +pub trait Integer { + #[allow(missing_docs)] + const I8: i8; + #[allow(missing_docs)] + const I16: i16; + #[allow(missing_docs)] + const I32: i32; + #[allow(missing_docs)] + const I64: i64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + const I128: i128; + #[allow(missing_docs)] + const ISIZE: isize; + + #[allow(missing_docs)] + fn to_i8() -> i8; + #[allow(missing_docs)] + fn to_i16() -> i16; + #[allow(missing_docs)] + fn to_i32() -> i32; + #[allow(missing_docs)] + fn to_i64() -> i64; + #[cfg(feature = "i128")] + #[allow(missing_docs)] + fn to_i128() -> i128; + #[allow(missing_docs)] + fn to_isize() -> isize; +} + +/// The **marker trait** for type-level arrays of type-level numbers. +/// +/// This trait should not be implemented for anything outside this crate. +/// +/// Someday, it may contain an associated constant to produce a runtime array, +/// like the other marker traits here. However, that is blocked by [this +/// issue](https://github.com/rust-lang/rust/issues/44168). +pub trait TypeArray {} + +/// The **marker trait** for type-level numbers which are a power of two. +/// +/// This trait should not be implemented for anything outside this crate. +/// +/// # Examples +/// +/// Here's a working example: +/// +/// ```rust +/// use typenum::{P4, P8, PowerOfTwo}; +/// +/// fn only_p2<P: PowerOfTwo>() { } +/// +/// only_p2::<P4>(); +/// only_p2::<P8>(); +/// ``` +/// +/// Numbers which are not a power of two will fail to compile in this example: +/// +/// ```rust,compile_fail +/// use typenum::{P9, P511, P1023, PowerOfTwo}; +/// +/// fn only_p2<P: PowerOfTwo>() { } +/// +/// only_p2::<P9>(); +/// only_p2::<P511>(); +/// only_p2::<P1023>(); +/// ``` + +pub trait PowerOfTwo {} diff --git a/typenum/src/operator_aliases.rs b/typenum/src/operator_aliases.rs new file mode 100644 index 000000000..5b24c8f37 --- /dev/null +++ b/typenum/src/operator_aliases.rs @@ -0,0 +1,98 @@ +//! Aliases for the type operators used in this crate. + +//! Their purpose is to increase the ergonomics of performing operations on the types defined +//! here. For even more ergonomics, consider using the `op!` macro instead. +//! +//! For example, type `X` and type `Y` are the same here: +//! +//! ```rust +//! # #[macro_use] extern crate typenum; +//! # fn main() { +//! use std::ops::Mul; +//! use typenum::{Prod, P5, P7}; +//! +//! type X = <P7 as Mul<P5>>::Output; +//! type Y = Prod<P7, P5>; +//! +//! assert_type_eq!(X, Y); +//! # } +//! ``` +//! +//! + +// Aliases!!! +use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; +use type_operators::{Abs, Cmp, Len, Max, Min, PartialDiv, Pow}; + +/// Alias for the associated type of `BitAnd`: `And<A, B> = <A as BitAnd<B>>::Output` +pub type And<A, B> = <A as BitAnd<B>>::Output; +/// Alias for the associated type of `BitOr`: `Or<A, B> = <A as BitOr<B>>::Output` +pub type Or<A, B> = <A as BitOr<B>>::Output; +/// Alias for the associated type of `BitXor`: `Xor<A, B> = <A as BitXor<B>>::Output` +pub type Xor<A, B> = <A as BitXor<B>>::Output; + +/// Alias for the associated type of `Shl`: `Shleft<A, B> = <A as Shl<B>>::Output` +pub type Shleft<A, B> = <A as Shl<B>>::Output; +/// Alias for the associated type of `Shr`: `Shright<A, B> = <A as Shr<B>>::Output` +pub type Shright<A, B> = <A as Shr<B>>::Output; + +/// Alias for the associated type of `Add`: `Sum<A, B> = <A as Add<B>>::Output` +pub type Sum<A, B> = <A as Add<B>>::Output; +/// Alias for the associated type of `Sub`: `Diff<A, B> = <A as Sub<B>>::Output` +pub type Diff<A, B> = <A as Sub<B>>::Output; +/// Alias for the associated type of `Mul`: `Prod<A, B> = <A as Mul<B>>::Output` +pub type Prod<A, B> = <A as Mul<B>>::Output; +/// Alias for the associated type of `Div`: `Quot<A, B> = <A as Div<B>>::Output` +pub type Quot<A, B> = <A as Div<B>>::Output; +/// Alias for the associated type of `Rem`: `Mod<A, B> = <A as Rem<B>>::Output` +pub type Mod<A, B> = <A as Rem<B>>::Output; + +/// Alias for the associated type of +/// `PartialDiv`: `PartialQuot<A, B> = <A as PartialDiv<B>>::Output` +pub type PartialQuot<A, B> = <A as PartialDiv<B>>::Output; + +/// Alias for the associated type of `Neg`: `Negate<A> = <A as Neg>::Output` +pub type Negate<A> = <A as Neg>::Output; + +/// Alias for the associated type of `Abs`: `AbsVal<A> = <A as Abs>::Output` +pub type AbsVal<A> = <A as Abs>::Output; + +/// Alias for the associated type of `Pow`: `Exp<A, B> = <A as Pow<B>>::Output` +pub type Exp<A, B> = <A as Pow<B>>::Output; + +/// Alias to make it easy to add 1: `Add1<A> = <A as Add<B1>>::Output` +pub type Add1<A> = <A as Add<::bit::B1>>::Output; +/// Alias to make it easy to subtract 1: `Sub1<A> = <A as Sub<B1>>::Output` +pub type Sub1<A> = <A as Sub<::bit::B1>>::Output; + +/// Alias to make it easy to square. `Square<A> = <A as Mul<A>>::Output` +pub type Square<A> = <A as Mul>::Output; +/// Alias to make it easy to cube. `Cube<A> = <Square<A> as Mul<A>>::Output` +pub type Cube<A> = <Square<A> as Mul<A>>::Output; + +/// Alias for the associated type of `Cmp`: `Compare<A, B> = <A as Cmp<B>>::Output` +pub type Compare<A, B> = <A as Cmp<B>>::Output; + +/// Alias for the associated type of `Len`: `Length<A> = <A as Len>::Output` +pub type Length<T> = <T as Len>::Output; + +/// Alias for the associated type of `Min`: `Minimum<A, B> = <A as Min<B>>::Output` +pub type Minimum<A, B> = <A as Min<B>>::Output; + +/// Alias for the associated type of `Max`: `Maximum<A, B> = <A as Max<B>>::Output` +pub type Maximum<A, B> = <A as Max<B>>::Output; + +use type_operators::{IsEqual, IsGreater, IsGreaterOrEqual, IsLess, IsLessOrEqual, IsNotEqual}; +/// Alias for the associated type of `IsLess`: `Le<A, B> = <A as IsLess<B>>::Output` +pub type Le<A, B> = <A as IsLess<B>>::Output; +/// Alias for the associated type of `IsEqual`: `Eq<A, B> = <A as IsEqual<B>>::Output` +pub type Eq<A, B> = <A as IsEqual<B>>::Output; +/// Alias for the associated type of `IsGreater`: `Gr<A, B> = <A as IsGreater<B>>::Output` +pub type Gr<A, B> = <A as IsGreater<B>>::Output; +/// Alias for the associated type of `IsGreaterOrEqual`: +/// `GrEq<A, B> = <A as IsGreaterOrEqual<B>>::Output` +pub type GrEq<A, B> = <A as IsGreaterOrEqual<B>>::Output; +/// Alias for the associated type of `IsLessOrEqual`: `LeEq<A, B> = <A as IsLessOrEqual<B>>::Output` +pub type LeEq<A, B> = <A as IsLessOrEqual<B>>::Output; +/// Alias for the associated type of `IsNotEqual`: `NotEq<A, B> = <A as IsNotEqual<B>>::Output` +pub type NotEq<A, B> = <A as IsNotEqual<B>>::Output; diff --git a/typenum/src/private.rs b/typenum/src/private.rs new file mode 100644 index 000000000..ea264838b --- /dev/null +++ b/typenum/src/private.rs @@ -0,0 +1,361 @@ +//! **Ignore me!** This module is for things that are conceptually private but that must +//! be made public for typenum to work correctly. +//! +//! Unless you are working on typenum itself, **there is no need to view anything here**. +//! +//! Certainly don't implement any of the traits here for anything. +//! +//! +//! Just look away. +//! +//! +//! Loooooooooooooooooooooooooooooooooook awaaaaaaaaaaaayyyyyyyyyyyyyyyyyyyyyyyyyyyyy... +//! +//! +//! If you do manage to find something of use in here, please let me know. If you can make a +//! compelling case, it may be moved out of __private. +//! +//! Note: Aliases for private type operators will all be named simply that operator followed +//! by an abbreviated name of its associated type. +//! + +#![doc(hidden)] + +// use ::{Sub}; +use bit::{B0, B1, Bit}; +use uint::{UInt, UTerm, Unsigned}; + +/// Convenience trait. Calls `Invert` -> `TrimTrailingZeros` -> `Invert` +pub trait Trim { + type Output; +} +pub type TrimOut<A> = <A as Trim>::Output; + +/// Gets rid of all zeros until it hits a one. + +// ONLY IMPLEMENT FOR INVERTED NUMBERS! +pub trait TrimTrailingZeros { + type Output; +} +pub type TrimTrailingZerosOut<A> = <A as TrimTrailingZeros>::Output; + +/// Converts between standard numbers and inverted ones that have the most significant +/// digit on the outside. +pub trait Invert { + type Output; +} +pub type InvertOut<A> = <A as Invert>::Output; + +/// Doubly private! Called by invert to make the magic happen once its done the first step. +/// The Rhs is what we've got so far. +pub trait PrivateInvert<Rhs> { + type Output; +} +pub type PrivateInvertOut<A, Rhs> = <A as PrivateInvert<Rhs>>::Output; + +/// Terminating character for `InvertedUInt`s +pub enum InvertedUTerm {} + +/// Inverted `UInt` (has most significant digit on the outside) +pub struct InvertedUInt<IU: InvertedUnsigned, B: Bit> { + _marker: (IU, B), +} + +/// Does the real anding for `UInt`s; `And` just calls this and then `Trim`. +pub trait PrivateAnd<Rhs = Self> { + type Output; +} +pub type PrivateAndOut<A, Rhs> = <A as PrivateAnd<Rhs>>::Output; + +/// Does the real xoring for `UInt`s; `Xor` just calls this and then `Trim`. +pub trait PrivateXor<Rhs = Self> { + type Output; +} +pub type PrivateXorOut<A, Rhs> = <A as PrivateXor<Rhs>>::Output; + +/// Does the real subtraction for `UInt`s; `Sub` just calls this and then `Trim`. +pub trait PrivateSub<Rhs = Self> { + type Output; +} +pub type PrivateSubOut<A, Rhs> = <A as PrivateSub<Rhs>>::Output; + +/// Used for addition of signed integers; `C = P.cmp(N)` +/// Assumes `P = Self` is positive and `N` is negative +/// where `P` and `N` are both passed as unsigned integers +pub trait PrivateIntegerAdd<C, N> { + type Output; +} +pub type PrivateIntegerAddOut<P, C, N> = <P as PrivateIntegerAdd<C, N>>::Output; + +pub trait PrivatePow<Y, N> { + type Output; +} +pub type PrivatePowOut<A, Y, N> = <A as PrivatePow<Y, N>>::Output; + +/// Performs `Shl` on `Lhs` so that `SizeOf(Lhs) = SizeOf(Rhs)` +/// Fails if `SizeOf(Lhs) > SizeOf(Rhs)` +pub trait ShiftDiff<Rhs> { + type Output; +} +pub type ShiftDiffOut<A, Rhs> = <A as ShiftDiff<Rhs>>::Output; + +/// Gives `SizeOf(Lhs) - SizeOf(Rhs)` +pub trait BitDiff<Rhs> { + type Output; +} +pub type BitDiffOut<A, Rhs> = <A as BitDiff<Rhs>>::Output; + +/// Inverted unsigned numbers +pub trait InvertedUnsigned { + fn to_u64() -> u64; +} + +impl InvertedUnsigned for InvertedUTerm { + fn to_u64() -> u64 { + 0 + } +} + +impl<IU: InvertedUnsigned, B: Bit> InvertedUnsigned for InvertedUInt<IU, B> { + fn to_u64() -> u64 { + u64::from(B::to_u8()) | IU::to_u64() << 1 + } +} + +impl Invert for UTerm { + type Output = InvertedUTerm; +} + +impl<U: Unsigned, B: Bit> Invert for UInt<U, B> +where + U: PrivateInvert<InvertedUInt<InvertedUTerm, B>>, +{ + type Output = PrivateInvertOut<U, InvertedUInt<InvertedUTerm, B>>; +} + +impl<IU: InvertedUnsigned> PrivateInvert<IU> for UTerm { + type Output = IU; +} + +impl<IU: InvertedUnsigned, U: Unsigned, B: Bit> PrivateInvert<IU> for UInt<U, B> +where + U: PrivateInvert<InvertedUInt<IU, B>>, +{ + type Output = PrivateInvertOut<U, InvertedUInt<IU, B>>; +} + +#[test] +fn test_inversion() { + type Test4 = <::consts::U4 as Invert>::Output; + type Test5 = <::consts::U5 as Invert>::Output; + type Test12 = <::consts::U12 as Invert>::Output; + type Test16 = <::consts::U16 as Invert>::Output; + + assert_eq!(1, <Test4 as InvertedUnsigned>::to_u64()); + assert_eq!(5, <Test5 as InvertedUnsigned>::to_u64()); + assert_eq!(3, <Test12 as InvertedUnsigned>::to_u64()); + assert_eq!(1, <Test16 as InvertedUnsigned>::to_u64()); +} + +impl Invert for InvertedUTerm { + type Output = UTerm; +} + +impl<IU: InvertedUnsigned, B: Bit> Invert for InvertedUInt<IU, B> +where + IU: PrivateInvert<UInt<UTerm, B>>, +{ + type Output = <IU as PrivateInvert<UInt<UTerm, B>>>::Output; +} + +impl<U: Unsigned> PrivateInvert<U> for InvertedUTerm { + type Output = U; +} + +impl<U: Unsigned, IU: InvertedUnsigned, B: Bit> PrivateInvert<U> for InvertedUInt<IU, B> +where + IU: PrivateInvert<UInt<U, B>>, +{ + type Output = <IU as PrivateInvert<UInt<U, B>>>::Output; +} + +#[test] +fn test_double_inversion() { + type Test4 = <<::consts::U4 as Invert>::Output as Invert>::Output; + type Test5 = <<::consts::U5 as Invert>::Output as Invert>::Output; + type Test12 = <<::consts::U12 as Invert>::Output as Invert>::Output; + type Test16 = <<::consts::U16 as Invert>::Output as Invert>::Output; + + assert_eq!(4, <Test4 as Unsigned>::to_u64()); + assert_eq!(5, <Test5 as Unsigned>::to_u64()); + assert_eq!(12, <Test12 as Unsigned>::to_u64()); + assert_eq!(16, <Test16 as Unsigned>::to_u64()); +} + +impl TrimTrailingZeros for InvertedUTerm { + type Output = InvertedUTerm; +} + +impl<IU: InvertedUnsigned> TrimTrailingZeros for InvertedUInt<IU, B1> { + type Output = Self; +} + +impl<IU: InvertedUnsigned> TrimTrailingZeros for InvertedUInt<IU, B0> +where + IU: TrimTrailingZeros, +{ + type Output = <IU as TrimTrailingZeros>::Output; +} + +impl<U: Unsigned> Trim for U +where + U: Invert, + <U as Invert>::Output: TrimTrailingZeros, + <<U as Invert>::Output as TrimTrailingZeros>::Output: Invert, +{ + type Output = <<<U as Invert>::Output as TrimTrailingZeros>::Output as Invert>::Output; +} + +// Note: Trimming is tested when we do subtraction. + +pub trait PrivateCmp<Rhs, SoFar> { + type Output; +} +pub type PrivateCmpOut<A, Rhs, SoFar> = <A as PrivateCmp<Rhs, SoFar>>::Output; + +// Set Bit +pub trait PrivateSetBit<I, B> { + type Output; +} +pub type PrivateSetBitOut<N, I, B> = <N as PrivateSetBit<I, B>>::Output; + +// Div +pub trait PrivateDiv<N, D, Q, R, I> { + type Quotient; + type Remainder; +} + +pub type PrivateDivQuot<N, D, Q, R, I> = <() as PrivateDiv<N, D, Q, R, I>>::Quotient; +pub type PrivateDivRem<N, D, Q, R, I> = <() as PrivateDiv<N, D, Q, R, I>>::Remainder; + +pub trait PrivateDivIf<N, D, Q, R, I, RcmpD> { + type Quotient; + type Remainder; +} + +pub type PrivateDivIfQuot<N, D, Q, R, I, RcmpD> = + <() as PrivateDivIf<N, D, Q, R, I, RcmpD>>::Quotient; +pub type PrivateDivIfRem<N, D, Q, R, I, RcmpD> = + <() as PrivateDivIf<N, D, Q, R, I, RcmpD>>::Remainder; + +// Div for signed ints +pub trait PrivateDivInt<C, Divisor> { + type Output; +} +pub type PrivateDivIntOut<A, C, Divisor> = <A as PrivateDivInt<C, Divisor>>::Output; + +pub trait PrivateRem<URem, Divisor> { + type Output; +} +pub type PrivateRemOut<A, URem, Divisor> = <A as PrivateRem<URem, Divisor>>::Output; + +// min max +pub trait PrivateMin<Rhs, CmpResult> { + type Output; + fn private_min(self, rhs: Rhs) -> Self::Output; +} +pub type PrivateMinOut<A, B, CmpResult> = <A as PrivateMin<B, CmpResult>>::Output; + +pub trait PrivateMax<Rhs, CmpResult> { + type Output; + fn private_max(self, rhs: Rhs) -> Self::Output; +} +pub type PrivateMaxOut<A, B, CmpResult> = <A as PrivateMax<B, CmpResult>>::Output; + +// Comparisons + +use {Equal, False, Greater, Less, True}; + +pub trait IsLessPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsLessPrivate<B, Less> for A { + type Output = True; +} +impl<A, B> IsLessPrivate<B, Equal> for A { + type Output = False; +} +impl<A, B> IsLessPrivate<B, Greater> for A { + type Output = False; +} + +pub trait IsEqualPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsEqualPrivate<B, Less> for A { + type Output = False; +} +impl<A, B> IsEqualPrivate<B, Equal> for A { + type Output = True; +} +impl<A, B> IsEqualPrivate<B, Greater> for A { + type Output = False; +} + +pub trait IsGreaterPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsGreaterPrivate<B, Less> for A { + type Output = False; +} +impl<A, B> IsGreaterPrivate<B, Equal> for A { + type Output = False; +} +impl<A, B> IsGreaterPrivate<B, Greater> for A { + type Output = True; +} + +pub trait IsLessOrEqualPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsLessOrEqualPrivate<B, Less> for A { + type Output = True; +} +impl<A, B> IsLessOrEqualPrivate<B, Equal> for A { + type Output = True; +} +impl<A, B> IsLessOrEqualPrivate<B, Greater> for A { + type Output = False; +} + +pub trait IsNotEqualPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsNotEqualPrivate<B, Less> for A { + type Output = True; +} +impl<A, B> IsNotEqualPrivate<B, Equal> for A { + type Output = False; +} +impl<A, B> IsNotEqualPrivate<B, Greater> for A { + type Output = True; +} + +pub trait IsGreaterOrEqualPrivate<Rhs, Cmp> { + type Output: Bit; +} + +impl<A, B> IsGreaterOrEqualPrivate<B, Less> for A { + type Output = False; +} +impl<A, B> IsGreaterOrEqualPrivate<B, Equal> for A { + type Output = True; +} +impl<A, B> IsGreaterOrEqualPrivate<B, Greater> for A { + type Output = True; +} diff --git a/typenum/src/type_operators.rs b/typenum/src/type_operators.rs new file mode 100644 index 000000000..e3e5e361e --- /dev/null +++ b/typenum/src/type_operators.rs @@ -0,0 +1,500 @@ +//! Useful **type operators** that are not defined in `core::ops`. +//! + +use {Bit, NInt, NonZero, PInt, UInt, UTerm, Unsigned, Z0}; + +/// A **type operator** that ensures that `Rhs` is the same as `Self`, it is mainly useful +/// for writing macros that can take arbitrary binary or unary operators. +/// +/// `Same` is implemented generically for all types; it should never need to be implemented +/// for anything else. +/// +/// Note that Rust lazily evaluates types, so this will only fail for two different types if +/// the `Output` is used. +/// +/// # Example +/// ```rust +/// use typenum::{Same, U4, U5, Unsigned}; +/// +/// assert_eq!(<U5 as Same<U5>>::Output::to_u32(), 5); +/// +/// // Only an error if we use it: +/// # #[allow(dead_code)] +/// type Undefined = <U5 as Same<U4>>::Output; +/// // Compiler error: +/// // Undefined::to_u32(); +/// ``` +pub trait Same<Rhs = Self> { + /// Should always be `Self` + type Output; +} + +impl<T> Same<T> for T { + type Output = T; +} + +/// A **type operator** that returns the absolute value. +/// +/// # Example +/// ```rust +/// use typenum::{Abs, N5, Integer}; +/// +/// assert_eq!(<N5 as Abs>::Output::to_i32(), 5); +/// ``` +pub trait Abs { + /// The absolute value. + type Output; +} + +impl Abs for Z0 { + type Output = Z0; +} + +impl<U: Unsigned + NonZero> Abs for PInt<U> { + type Output = Self; +} + +impl<U: Unsigned + NonZero> Abs for NInt<U> { + type Output = PInt<U>; +} + +/// A **type operator** that provides exponentiation by repeated squaring. +/// +/// # Example +/// ```rust +/// use typenum::{Pow, N3, P3, Integer}; +/// +/// assert_eq!(<N3 as Pow<P3>>::Output::to_i32(), -27); +/// ``` +pub trait Pow<Exp> { + /// The result of the exponentiation. + type Output; + /// This function isn't used in this crate, but may be useful for others. + /// It is implemented for primitives. + /// + /// # Example + /// ```rust + /// use typenum::{Pow, U3}; + /// + /// let a = 7u32.powi(U3::new()); + /// let b = 7u32.pow(3); + /// assert_eq!(a, b); + /// + /// let x = 3.0.powi(U3::new()); + /// let y = 27.0; + /// assert_eq!(x, y); + /// ``` + fn powi(self, exp: Exp) -> Self::Output; +} + +macro_rules! impl_pow_f { + ($t: ty) => ( + impl Pow<UTerm> for $t { + type Output = $t; + #[inline] + fn powi(self, _: UTerm) -> Self::Output { + 1.0 + } + } + + impl<U: Unsigned, B: Bit> Pow<UInt<U, B>> for $t { + type Output = $t; + // powi is unstable in core, so we have to write this function ourselves. + // copied from num::pow::pow + #[inline] + fn powi(self, _: UInt<U, B>) -> Self::Output { + let mut exp = <UInt<U, B> as Unsigned>::to_u32(); + let mut base = self; + + if exp == 0 { return 1.0 } + + while exp & 1 == 0 { + base *= base; + exp >>= 1; + } + if exp == 1 { return base } + + let mut acc = base.clone(); + while exp > 1 { + exp >>= 1; + base *= base; + if exp & 1 == 1 { + acc *= base.clone(); + } + } + acc + } + } + + impl Pow<Z0> for $t { + type Output = $t; + #[inline] + fn powi(self, _: Z0) -> Self::Output { + 1.0 + } + } + + impl<U: Unsigned + NonZero> Pow<PInt<U>> for $t { + type Output = $t; + // powi is unstable in core, so we have to write this function ourselves. + // copied from num::pow::pow + #[inline] + fn powi(self, _: PInt<U>) -> Self::Output { + let mut exp = U::to_u32(); + let mut base = self; + + if exp == 0 { return 1.0 } + + while exp & 1 == 0 { + base *= base; + exp >>= 1; + } + if exp == 1 { return base } + + let mut acc = base.clone(); + while exp > 1 { + exp >>= 1; + base *= base; + if exp & 1 == 1 { + acc *= base.clone(); + } + } + acc + } + } + ); +} + +impl_pow_f!(f32); +impl_pow_f!(f64); + +macro_rules! impl_pow_i { + () => (); + ($t: ty $(, $tail:tt)*) => ( + impl Pow<UTerm> for $t { + type Output = $t; + #[inline] + fn powi(self, _: UTerm) -> Self::Output { + 1 + } + } + + impl<U: Unsigned, B: Bit> Pow<UInt<U, B>> for $t { + type Output = $t; + #[inline] + fn powi(self, _: UInt<U, B>) -> Self::Output { + self.pow(<UInt<U, B> as Unsigned>::to_u32()) + } + } + + impl Pow<Z0> for $t { + type Output = $t; + #[inline] + fn powi(self, _: Z0) -> Self::Output { + 1 + } + } + + impl<U: Unsigned + NonZero> Pow<PInt<U>> for $t { + type Output = $t; + #[inline] + fn powi(self, _: PInt<U>) -> Self::Output { + self.pow(U::to_u32()) + } + } + + impl_pow_i!($($tail),*); + ); +} + +impl_pow_i!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize); +#[cfg(feature = "i128")] +impl_pow_i!(u128, i128); + +#[test] +fn pow_test() { + use consts::*; + let z0 = Z0::new(); + let p3 = P3::new(); + + let u0 = U0::new(); + let u3 = U3::new(); + + macro_rules! check { + ($x:ident) => ( + assert_eq!($x.powi(z0), 1); + assert_eq!($x.powi(u0), 1); + + assert_eq!($x.powi(p3), $x*$x*$x); + assert_eq!($x.powi(u3), $x*$x*$x); + ); + ($x:ident, $f:ident) => ( + assert!((<$f as Pow<Z0>>::powi(*$x, z0) - 1.0).abs() < ::core::$f::EPSILON); + assert!((<$f as Pow<U0>>::powi(*$x, u0) - 1.0).abs() < ::core::$f::EPSILON); + + assert!((<$f as Pow<P3>>::powi(*$x, p3) - $x*$x*$x).abs() < ::core::$f::EPSILON); + assert!((<$f as Pow<U3>>::powi(*$x, u3) - $x*$x*$x).abs() < ::core::$f::EPSILON); + ); + } + + for x in &[0i8, -3, 2] { + check!(x); + } + for x in &[0u8, 1, 5] { + check!(x); + } + for x in &[0usize, 1, 5, 40] { + check!(x); + } + for x in &[0isize, 1, 2, -30, -22, 48] { + check!(x); + } + for x in &[0.0f32, 2.2, -3.5, 378.223] { + check!(x, f32); + } + for x in &[0.0f64, 2.2, -3.5, -2387.2, 234.22] { + check!(x, f64); + } +} + +/// A **type operator** for comparing `Self` and `Rhs`. It provides a similar functionality to +/// the function +/// [`core::cmp::Ord::cmp`](https://doc.rust-lang.org/nightly/core/cmp/trait.Ord.html#tymethod.cmp) +/// but for types. +/// +/// # Example +/// ```rust +/// use typenum::{Cmp, Ord, N3, P2, P5}; +/// use std::cmp::Ordering; +/// +/// assert_eq!(<P2 as Cmp<N3>>::Output::to_ordering(), Ordering::Greater); +/// assert_eq!(<P2 as Cmp<P2>>::Output::to_ordering(), Ordering::Equal); +/// assert_eq!(<P2 as Cmp<P5>>::Output::to_ordering(), Ordering::Less); +pub trait Cmp<Rhs = Self> { + /// The result of the comparison. It should only ever be one of `Greater`, `Less`, or `Equal`. + type Output; +} + +/// A **type operator** that gives the length of an `Array` or the number of bits in a `UInt`. +pub trait Len { + /// The length as a type-level unsigned integer. + type Output: ::Unsigned; + /// This function isn't used in this crate, but may be useful for others. + fn len(&self) -> Self::Output; +} + +/// Division as a partial function. This **type operator** performs division just as `Div`, but is +/// only defined when the result is an integer (i.e. there is no remainder). +pub trait PartialDiv<Rhs = Self> { + /// The type of the result of the division + type Output; + /// Method for performing the division + fn partial_div(self, _: Rhs) -> Self::Output; +} + +/// A **type operator** that returns the minimum of `Self` and `Rhs`. +pub trait Min<Rhs = Self> { + /// The type of the minimum of `Self` and `Rhs` + type Output; + /// Method returning the minimum + fn min(self, rhs: Rhs) -> Self::Output; +} + +/// A **type operator** that returns the maximum of `Self` and `Rhs`. +pub trait Max<Rhs = Self> { + /// The type of the maximum of `Self` and `Rhs` + type Output; + /// Method returning the maximum + fn max(self, rhs: Rhs) -> Self::Output; +} + +use Compare; + +/// A **type operator** that returns `True` if `Self < Rhs`, otherwise returns `False`. +pub trait IsLess<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_less(self, rhs: Rhs) -> Self::Output; +} + +use private::IsLessPrivate; +impl<A, B> IsLess<B> for A +where + A: Cmp<B> + IsLessPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsLessPrivate<B, Compare<A, B>>>::Output; + + fn is_less(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// A **type operator** that returns `True` if `Self == Rhs`, otherwise returns `False`. +pub trait IsEqual<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_equal(self, rhs: Rhs) -> Self::Output; +} + +use private::IsEqualPrivate; +impl<A, B> IsEqual<B> for A +where + A: Cmp<B> + IsEqualPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsEqualPrivate<B, Compare<A, B>>>::Output; + + fn is_equal(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// A **type operator** that returns `True` if `Self > Rhs`, otherwise returns `False`. +pub trait IsGreater<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_greater(self, rhs: Rhs) -> Self::Output; +} + +use private::IsGreaterPrivate; +impl<A, B> IsGreater<B> for A +where + A: Cmp<B> + IsGreaterPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsGreaterPrivate<B, Compare<A, B>>>::Output; + + fn is_greater(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// A **type operator** that returns `True` if `Self <= Rhs`, otherwise returns `False`. +pub trait IsLessOrEqual<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_less_or_equal(self, rhs: Rhs) -> Self::Output; +} + +use private::IsLessOrEqualPrivate; +impl<A, B> IsLessOrEqual<B> for A +where + A: Cmp<B> + IsLessOrEqualPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsLessOrEqualPrivate<B, Compare<A, B>>>::Output; + + fn is_less_or_equal(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// A **type operator** that returns `True` if `Self != Rhs`, otherwise returns `False`. +pub trait IsNotEqual<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_not_equal(self, rhs: Rhs) -> Self::Output; +} + +use private::IsNotEqualPrivate; +impl<A, B> IsNotEqual<B> for A +where + A: Cmp<B> + IsNotEqualPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsNotEqualPrivate<B, Compare<A, B>>>::Output; + + fn is_not_equal(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// A **type operator** that returns `True` if `Self >= Rhs`, otherwise returns `False`. +pub trait IsGreaterOrEqual<Rhs = Self> { + /// The type representing either `True` or `False` + type Output: Bit; + /// Method returning `True` or `False`. + fn is_greater_or_equal(self, rhs: Rhs) -> Self::Output; +} + +use private::IsGreaterOrEqualPrivate; +impl<A, B> IsGreaterOrEqual<B> for A +where + A: Cmp<B> + IsGreaterOrEqualPrivate<B, Compare<A, B>>, +{ + type Output = <A as IsGreaterOrEqualPrivate<B, Compare<A, B>>>::Output; + + fn is_greater_or_equal(self, _: B) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/** +A convenience macro for comparing type numbers. Use `op!` instead. + +Due to the intricacies of the macro system, if the left-hand operand is more complex than a simple +`ident`, you must place a comma between it and the comparison sign. + +For example, you can do `cmp!(P5 > P3)` or `cmp!(typenum::P5, > typenum::P3)` but not +`cmp!(typenum::P5 > typenum::P3)`. + +The result of this comparison will always be one of `True` (aka `B1`) or `False` (aka `B0`). + +# Example +```rust +#[macro_use] extern crate typenum; +use typenum::consts::*; +use typenum::Bit; + +fn main() { +type Result = cmp!(P9 == op!(P1 + P2 * (P2 - N2))); +assert_eq!(Result::to_bool(), true); +} +``` + */ +#[deprecated(since = "1.9.0", note = "use the `op!` macro instead")] +#[macro_export] +macro_rules! cmp { + ($a:ident < $b:ty) => ( + <$a as $crate::IsLess<$b>>::Output + ); + ($a:ty, < $b:ty) => ( + <$a as $crate::IsLess<$b>>::Output + ); + + ($a:ident == $b:ty) => ( + <$a as $crate::IsEqual<$b>>::Output + ); + ($a:ty, == $b:ty) => ( + <$a as $crate::IsEqual<$b>>::Output + ); + + ($a:ident > $b:ty) => ( + <$a as $crate::IsGreater<$b>>::Output + ); + ($a:ty, > $b:ty) => ( + <$a as $crate::IsGreater<$b>>::Output + ); + + ($a:ident <= $b:ty) => ( + <$a as $crate::IsLessOrEqual<$b>>::Output + ); + ($a:ty, <= $b:ty) => ( + <$a as $crate::IsLessOrEqual<$b>>::Output + ); + + ($a:ident != $b:ty) => ( + <$a as $crate::IsNotEqual<$b>>::Output + ); + ($a:ty, != $b:ty) => ( + <$a as $crate::IsNotEqual<$b>>::Output + ); + + ($a:ident >= $b:ty) => ( + <$a as $crate::IsGreaterOrEqual<$b>>::Output + ); + ($a:ty, >= $b:ty) => ( + <$a as $crate::IsGreaterOrEqual<$b>>::Output + ); +} diff --git a/typenum/src/uint.rs b/typenum/src/uint.rs new file mode 100644 index 000000000..a8607eedc --- /dev/null +++ b/typenum/src/uint.rs @@ -0,0 +1,1572 @@ +//! Type-level unsigned integers. +//! +//! +//! **Type operators** implemented: +//! +//! From `core::ops`: `BitAnd`, `BitOr`, `BitXor`, `Shl`, `Shr`, `Add`, `Sub`, +//! `Mul`, `Div`, and `Rem`. +//! From `typenum`: `Same`, `Cmp`, and `Pow`. +//! +//! Rather than directly using the structs defined in this module, it is recommended that +//! you import and use the relevant aliases from the [consts](../consts/index.html) module. +//! +//! # Example +//! ```rust +//! use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr, Add, Sub, Mul, Div, Rem}; +//! use typenum::{Unsigned, U1, U2, U3, U4}; +//! +//! assert_eq!(<U3 as BitAnd<U2>>::Output::to_u32(), 2); +//! assert_eq!(<U3 as BitOr<U4>>::Output::to_u32(), 7); +//! assert_eq!(<U3 as BitXor<U2>>::Output::to_u32(), 1); +//! assert_eq!(<U3 as Shl<U1>>::Output::to_u32(), 6); +//! assert_eq!(<U3 as Shr<U1>>::Output::to_u32(), 1); +//! assert_eq!(<U3 as Add<U2>>::Output::to_u32(), 5); +//! assert_eq!(<U3 as Sub<U2>>::Output::to_u32(), 1); +//! assert_eq!(<U3 as Mul<U2>>::Output::to_u32(), 6); +//! assert_eq!(<U3 as Div<U2>>::Output::to_u32(), 1); +//! assert_eq!(<U3 as Rem<U2>>::Output::to_u32(), 1); +//! ``` +//! + +use core::ops::{Add, BitAnd, BitOr, BitXor, Mul, Shl, Shr, Sub}; +use core::marker::PhantomData; +use {Cmp, Equal, Greater, Len, Less, NonZero, Ord, Pow}; + +use bit::{B0, B1, Bit}; + +use private::{BitDiff, PrivateAnd, PrivateCmp, PrivatePow, PrivateSub, PrivateXor, Trim}; + +use private::{BitDiffOut, PrivateAndOut, PrivateCmpOut, PrivatePowOut, PrivateSubOut, + PrivateXorOut, TrimOut}; + +use consts::{U0, U1}; +use {Add1, Length, Or, Prod, Shleft, Shright, Square, Sub1, Sum}; + +pub use marker_traits::{PowerOfTwo, Unsigned}; + +/// The terminating type for `UInt`; it always comes after the most significant +/// bit. `UTerm` by itself represents zero, which is aliased to `U0`. +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct UTerm; + +impl UTerm { + /// Instantiates a singleton representing this unsigned integer. + #[inline] + pub fn new() -> UTerm { + UTerm + } +} + +impl Unsigned for UTerm { + const U8: u8 = 0; + const U16: u16 = 0; + const U32: u32 = 0; + const U64: u64 = 0; + #[cfg(feature = "i128")] + const U128: u128 = 0; + const USIZE: usize = 0; + + const I8: i8 = 0; + const I16: i16 = 0; + const I32: i32 = 0; + const I64: i64 = 0; + #[cfg(feature = "i128")] + const I128: i128 = 0; + const ISIZE: isize = 0; + + #[inline] + fn to_u8() -> u8 { + 0 + } + #[inline] + fn to_u16() -> u16 { + 0 + } + #[inline] + fn to_u32() -> u32 { + 0 + } + #[inline] + fn to_u64() -> u64 { + 0 + } + #[cfg(feature = "i128")] + #[inline] + fn to_u128() -> u128 { + 0 + } + #[inline] + fn to_usize() -> usize { + 0 + } + + #[inline] + fn to_i8() -> i8 { + 0 + } + #[inline] + fn to_i16() -> i16 { + 0 + } + #[inline] + fn to_i32() -> i32 { + 0 + } + #[inline] + fn to_i64() -> i64 { + 0 + } + #[cfg(feature = "i128")] + #[inline] + fn to_i128() -> i128 { + 0 + } + #[inline] + fn to_isize() -> isize { + 0 + } +} + +/// `UInt` is defined recursively, where `B` is the least significant bit and `U` is the rest +/// of the number. Conceptually, `U` should be bound by the trait `Unsigned` and `B` should +/// be bound by the trait `Bit`, but enforcing these bounds causes linear instead of +/// logrithmic scaling in some places, so they are left off for now. They may be enforced in +/// future. +/// +/// In order to keep numbers unique, leading zeros are not allowed, so `UInt<UTerm, B0>` is +/// forbidden. +/// +/// # Example +/// ```rust +/// use typenum::{B0, B1, UInt, UTerm}; +/// +/// # #[allow(dead_code)] +/// type U6 = UInt<UInt<UInt<UTerm, B1>, B1>, B0>; +/// ``` +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] +pub struct UInt<U, B> { + _marker: PhantomData<(U, B)>, +} + +impl<U: Unsigned, B: Bit> UInt<U, B> { + /// Instantiates a singleton representing this unsigned integer. + #[inline] + pub fn new() -> UInt<U, B> { + UInt { + _marker: PhantomData, + } + } +} + +impl<U: Unsigned, B: Bit> Unsigned for UInt<U, B> { + const U8: u8 = B::U8 | U::U8 << 1; + const U16: u16 = B::U8 as u16 | U::U16 << 1; + const U32: u32 = B::U8 as u32 | U::U32 << 1; + const U64: u64 = B::U8 as u64 | U::U64 << 1; + #[cfg(feature = "i128")] + const U128: u128 = B::U8 as u128 | U::U128 << 1; + const USIZE: usize = B::U8 as usize | U::USIZE << 1; + + const I8: i8 = B::U8 as i8 | U::I8 << 1; + const I16: i16 = B::U8 as i16 | U::I16 << 1; + const I32: i32 = B::U8 as i32 | U::I32 << 1; + const I64: i64 = B::U8 as i64 | U::I64 << 1; + #[cfg(feature = "i128")] + const I128: i128 = B::U8 as i128 | U::I128 << 1; + const ISIZE: isize = B::U8 as isize | U::ISIZE << 1; + + #[inline] + fn to_u8() -> u8 { + B::to_u8() | U::to_u8() << 1 + } + #[inline] + fn to_u16() -> u16 { + u16::from(B::to_u8()) | U::to_u16() << 1 + } + #[inline] + fn to_u32() -> u32 { + u32::from(B::to_u8()) | U::to_u32() << 1 + } + #[inline] + fn to_u64() -> u64 { + u64::from(B::to_u8()) | U::to_u64() << 1 + } + #[cfg(feature = "i128")] + #[inline] + fn to_u128() -> u128 { + u128::from(B::to_u8()) | U::to_u128() << 1 + } + #[inline] + fn to_usize() -> usize { + usize::from(B::to_u8()) | U::to_usize() << 1 + } + + #[inline] + fn to_i8() -> i8 { + B::to_u8() as i8 | U::to_i8() << 1 + } + #[inline] + fn to_i16() -> i16 { + i16::from(B::to_u8()) | U::to_i16() << 1 + } + #[inline] + fn to_i32() -> i32 { + i32::from(B::to_u8()) | U::to_i32() << 1 + } + #[inline] + fn to_i64() -> i64 { + i64::from(B::to_u8()) | U::to_i64() << 1 + } + #[cfg(feature = "i128")] + #[inline] + fn to_i128() -> i128 { + i128::from(B::to_u8()) | U::to_i128() << 1 + } + #[inline] + fn to_isize() -> isize { + B::to_u8() as isize | U::to_isize() << 1 + } +} + +impl<U: Unsigned, B: Bit> NonZero for UInt<U, B> {} + +impl PowerOfTwo for UInt<UTerm, B1> {} +impl<U: Unsigned + PowerOfTwo> PowerOfTwo for UInt<U, B0> {} + +// --------------------------------------------------------------------------------------- +// Getting length of unsigned integers, which is defined as the number of bits before `UTerm` + +/// Length of `UTerm` by itself is 0 +impl Len for UTerm { + type Output = U0; + fn len(&self) -> Self::Output { + UTerm + } +} + +/// Length of a bit is 1 +impl<U: Unsigned, B: Bit> Len for UInt<U, B> +where + U: Len, + Length<U>: Add<B1>, + Add1<Length<U>>: Unsigned, +{ + type Output = Add1<Length<U>>; + fn len(&self) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Adding bits to unsigned integers + +/// `UTerm + B0 = UTerm` +impl Add<B0> for UTerm { + type Output = UTerm; + fn add(self, _: B0) -> Self::Output { + UTerm + } +} + +/// `U + B0 = U` +impl<U: Unsigned, B: Bit> Add<B0> for UInt<U, B> { + type Output = UInt<U, B>; + fn add(self, _: B0) -> Self::Output { + UInt::new() + } +} + +/// `UTerm + B1 = UInt<UTerm, B1>` +impl Add<B1> for UTerm { + type Output = UInt<UTerm, B1>; + fn add(self, _: B1) -> Self::Output { + UInt::new() + } +} + +/// `UInt<U, B0> + B1 = UInt<U + B1>` +impl<U: Unsigned> Add<B1> for UInt<U, B0> { + type Output = UInt<U, B1>; + fn add(self, _: B1) -> Self::Output { + UInt::new() + } +} + +/// `UInt<U, B1> + B1 = UInt<U + B1, B0>` +impl<U: Unsigned> Add<B1> for UInt<U, B1> +where + U: Add<B1>, + Add1<U>: Unsigned, +{ + type Output = UInt<Add1<U>, B0>; + fn add(self, _: B1) -> Self::Output { + UInt::new() + } +} + +// --------------------------------------------------------------------------------------- +// Adding unsigned integers + +/// `UTerm + U = U` +impl<U: Unsigned> Add<U> for UTerm { + type Output = U; + fn add(self, _: U) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<U, B> + UTerm = UInt<U, B>` +impl<U: Unsigned, B: Bit> Add<UTerm> for UInt<U, B> { + type Output = UInt<U, B>; + fn add(self, _: UTerm) -> Self::Output { + UInt::new() + } +} + +/// `UInt<Ul, B0> + UInt<Ur, B0> = UInt<Ul + Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> Add<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: Add<Ur>, +{ + type Output = UInt<Sum<Ul, Ur>, B0>; + fn add(self, _: UInt<Ur, B0>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B0> + UInt<Ur, B1> = UInt<Ul + Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> Add<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: Add<Ur>, +{ + type Output = UInt<Sum<Ul, Ur>, B1>; + fn add(self, _: UInt<Ur, B1>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B1> + UInt<Ur, B0> = UInt<Ul + Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> Add<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: Add<Ur>, +{ + type Output = UInt<Sum<Ul, Ur>, B1>; + fn add(self, _: UInt<Ur, B0>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B1> + UInt<Ur, B1> = UInt<(Ul + Ur) + B1, B0>` +impl<Ul: Unsigned, Ur: Unsigned> Add<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: Add<Ur>, + Sum<Ul, Ur>: Add<B1>, +{ + type Output = UInt<Add1<Sum<Ul, Ur>>, B0>; + fn add(self, _: UInt<Ur, B1>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Subtracting bits from unsigned integers + +/// `UTerm - B0 = Term` +impl Sub<B0> for UTerm { + type Output = UTerm; + fn sub(self, _: B0) -> Self::Output { + UTerm + } +} + +/// `UInt - B0 = UInt` +impl<U: Unsigned, B: Bit> Sub<B0> for UInt<U, B> { + type Output = UInt<U, B>; + fn sub(self, _: B0) -> Self::Output { + UInt::new() + } +} + +/// `UInt<U, B1> - B1 = UInt<U, B0>` +impl<U: Unsigned, B: Bit> Sub<B1> for UInt<UInt<U, B>, B1> { + type Output = UInt<UInt<U, B>, B0>; + fn sub(self, _: B1) -> Self::Output { + UInt::new() + } +} + +/// `UInt<UTerm, B1> - B1 = UTerm` +impl Sub<B1> for UInt<UTerm, B1> { + type Output = UTerm; + fn sub(self, _: B1) -> Self::Output { + UTerm + } +} + +/// `UInt<U, B0> - B1 = UInt<U - B1, B1>` +impl<U: Unsigned> Sub<B1> for UInt<U, B0> +where + U: Sub<B1>, + Sub1<U>: Unsigned, +{ + type Output = UInt<Sub1<U>, B1>; + fn sub(self, _: B1) -> Self::Output { + UInt::new() + } +} + +// --------------------------------------------------------------------------------------- +// Subtracting unsigned integers + +/// `UTerm - UTerm = UTerm` +impl Sub<UTerm> for UTerm { + type Output = UTerm; + fn sub(self, _: UTerm) -> Self::Output { + UTerm + } +} + +/// Subtracting unsigned integers. We just do our `PrivateSub` and then `Trim` the output. +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned> Sub<Ur> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: PrivateSub<Ur>, + PrivateSubOut<UInt<Ul, Bl>, Ur>: Trim, +{ + type Output = TrimOut<PrivateSubOut<UInt<Ul, Bl>, Ur>>; + fn sub(self, _: Ur) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `U - UTerm = U` +impl<U: Unsigned> PrivateSub<UTerm> for U { + type Output = U; +} + +/// `UInt<Ul, B0> - UInt<Ur, B0> = UInt<Ul - Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateSub<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: PrivateSub<Ur>, +{ + type Output = UInt<PrivateSubOut<Ul, Ur>, B0>; +} + +/// `UInt<Ul, B0> - UInt<Ur, B1> = UInt<(Ul - Ur) - B1, B1>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateSub<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: PrivateSub<Ur>, + PrivateSubOut<Ul, Ur>: Sub<B1>, +{ + type Output = UInt<Sub1<PrivateSubOut<Ul, Ur>>, B1>; +} + +/// `UInt<Ul, B1> - UInt<Ur, B0> = UInt<Ul - Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateSub<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: PrivateSub<Ur>, +{ + type Output = UInt<PrivateSubOut<Ul, Ur>, B1>; +} + +/// `UInt<Ul, B1> - UInt<Ur, B1> = UInt<Ul - Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateSub<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: PrivateSub<Ur>, +{ + type Output = UInt<PrivateSubOut<Ul, Ur>, B0>; +} + +// --------------------------------------------------------------------------------------- +// And unsigned integers + +/// 0 & X = 0 +impl<Ur: Unsigned> BitAnd<Ur> for UTerm { + type Output = UTerm; + fn bitand(self, _: Ur) -> Self::Output { + UTerm + } +} + +/// Anding unsigned integers. +/// We use our `PrivateAnd` operator and then `Trim` the output. +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned> BitAnd<Ur> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: PrivateAnd<Ur>, + PrivateAndOut<UInt<Ul, Bl>, Ur>: Trim, +{ + type Output = TrimOut<PrivateAndOut<UInt<Ul, Bl>, Ur>>; + fn bitand(self, _: Ur) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UTerm & X = UTerm` +impl<U: Unsigned> PrivateAnd<U> for UTerm { + type Output = UTerm; +} + +/// `X & UTerm = UTerm` +impl<B: Bit, U: Unsigned> PrivateAnd<UTerm> for UInt<U, B> { + type Output = UTerm; +} + +/// `UInt<Ul, B0> & UInt<Ur, B0> = UInt<Ul & Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateAnd<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: PrivateAnd<Ur>, +{ + type Output = UInt<PrivateAndOut<Ul, Ur>, B0>; +} + +/// `UInt<Ul, B0> & UInt<Ur, B1> = UInt<Ul & Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateAnd<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: PrivateAnd<Ur>, +{ + type Output = UInt<PrivateAndOut<Ul, Ur>, B0>; +} + +/// `UInt<Ul, B1> & UInt<Ur, B0> = UInt<Ul & Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateAnd<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: PrivateAnd<Ur>, +{ + type Output = UInt<PrivateAndOut<Ul, Ur>, B0>; +} + +/// `UInt<Ul, B1> & UInt<Ur, B1> = UInt<Ul & Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateAnd<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: PrivateAnd<Ur>, +{ + type Output = UInt<PrivateAndOut<Ul, Ur>, B1>; +} + +// --------------------------------------------------------------------------------------- +// Or unsigned integers + +/// `UTerm | X = X` +impl<U: Unsigned> BitOr<U> for UTerm { + type Output = U; + fn bitor(self, _: U) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `X | UTerm = X` +impl<B: Bit, U: Unsigned> BitOr<UTerm> for UInt<U, B> { + type Output = Self; + fn bitor(self, _: UTerm) -> Self::Output { + UInt::new() + } +} + +/// `UInt<Ul, B0> | UInt<Ur, B0> = UInt<Ul | Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> BitOr<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: BitOr<Ur>, +{ + type Output = UInt<<Ul as BitOr<Ur>>::Output, B0>; + fn bitor(self, _: UInt<Ur, B0>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B0> | UInt<Ur, B1> = UInt<Ul | Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> BitOr<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: BitOr<Ur>, +{ + type Output = UInt<Or<Ul, Ur>, B1>; + fn bitor(self, _: UInt<Ur, B1>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B1> | UInt<Ur, B0> = UInt<Ul | Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> BitOr<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: BitOr<Ur>, +{ + type Output = UInt<Or<Ul, Ur>, B1>; + fn bitor(self, _: UInt<Ur, B0>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B1> | UInt<Ur, B1> = UInt<Ul | Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> BitOr<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: BitOr<Ur>, +{ + type Output = UInt<Or<Ul, Ur>, B1>; + fn bitor(self, _: UInt<Ur, B1>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Xor unsigned integers + +/// 0 ^ X = X +impl<Ur: Unsigned> BitXor<Ur> for UTerm { + type Output = Ur; + fn bitxor(self, _: Ur) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// Xoring unsigned integers. +/// We use our `PrivateXor` operator and then `Trim` the output. +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned> BitXor<Ur> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: PrivateXor<Ur>, + PrivateXorOut<UInt<Ul, Bl>, Ur>: Trim, +{ + type Output = TrimOut<PrivateXorOut<UInt<Ul, Bl>, Ur>>; + fn bitxor(self, _: Ur) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UTerm ^ X = X` +impl<U: Unsigned> PrivateXor<U> for UTerm { + type Output = U; +} + +/// `X ^ UTerm = X` +impl<B: Bit, U: Unsigned> PrivateXor<UTerm> for UInt<U, B> { + type Output = Self; +} + +/// `UInt<Ul, B0> ^ UInt<Ur, B0> = UInt<Ul ^ Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateXor<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: PrivateXor<Ur>, +{ + type Output = UInt<PrivateXorOut<Ul, Ur>, B0>; +} + +/// `UInt<Ul, B0> ^ UInt<Ur, B1> = UInt<Ul ^ Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateXor<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: PrivateXor<Ur>, +{ + type Output = UInt<PrivateXorOut<Ul, Ur>, B1>; +} + +/// `UInt<Ul, B1> ^ UInt<Ur, B0> = UInt<Ul ^ Ur, B1>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateXor<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: PrivateXor<Ur>, +{ + type Output = UInt<PrivateXorOut<Ul, Ur>, B1>; +} + +/// `UInt<Ul, B1> ^ UInt<Ur, B1> = UInt<Ul ^ Ur, B0>` +impl<Ul: Unsigned, Ur: Unsigned> PrivateXor<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: PrivateXor<Ur>, +{ + type Output = UInt<PrivateXorOut<Ul, Ur>, B0>; +} + +// --------------------------------------------------------------------------------------- +// Shl unsigned integers + +/// Shifting `UTerm` by a 0 bit: `UTerm << B0 = UTerm` +impl Shl<B0> for UTerm { + type Output = UTerm; + fn shl(self, _: B0) -> Self::Output { + UTerm + } +} + +/// Shifting `UTerm` by a 1 bit: `UTerm << B1 = UTerm` +impl Shl<B1> for UTerm { + type Output = UTerm; + fn shl(self, _: B1) -> Self::Output { + UTerm + } +} + +/// Shifting left any unsigned by a zero bit: `U << B0 = U` +impl<U: Unsigned, B: Bit> Shl<B0> for UInt<U, B> { + type Output = UInt<U, B>; + fn shl(self, _: B0) -> Self::Output { + UInt::new() + } +} + +/// Shifting left a `UInt` by a one bit: `UInt<U, B> << B1 = UInt<UInt<U, B>, B0>` +impl<U: Unsigned, B: Bit> Shl<B1> for UInt<U, B> { + type Output = UInt<UInt<U, B>, B0>; + fn shl(self, _: B1) -> Self::Output { + UInt::new() + } +} + +/// Shifting left `UInt` by `UTerm`: `UInt<U, B> << UTerm = UInt<U, B>` +impl<U: Unsigned, B: Bit> Shl<UTerm> for UInt<U, B> { + type Output = UInt<U, B>; + fn shl(self, _: UTerm) -> Self::Output { + UInt::new() + } +} + +/// Shifting left `UTerm` by an unsigned integer: `UTerm << U = UTerm` +impl<U: Unsigned> Shl<U> for UTerm { + type Output = UTerm; + fn shl(self, _: U) -> Self::Output { + UTerm + } +} + +/// Shifting left `UInt` by `UInt`: `X << Y` = `UInt(X, B0) << (Y - 1)` +impl<U: Unsigned, B: Bit, Ur: Unsigned, Br: Bit> Shl<UInt<Ur, Br>> for UInt<U, B> +where + UInt<Ur, Br>: Sub<B1>, + UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>, +{ + type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>; + fn shl(self, _: UInt<Ur, Br>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Shr unsigned integers + +/// Shifting right a `UTerm` by an unsigned integer: `UTerm >> U = UTerm` +impl<U: Unsigned> Shr<U> for UTerm { + type Output = UTerm; + fn shr(self, _: U) -> Self::Output { + UTerm + } +} + +/// Shifting right `UInt` by `UTerm`: `UInt<U, B> >> UTerm = UInt<U, B>` +impl<U: Unsigned, B: Bit> Shr<UTerm> for UInt<U, B> { + type Output = UInt<U, B>; + fn shr(self, _: UTerm) -> Self::Output { + UInt::new() + } +} + +/// Shifting right `UTerm` by a 0 bit: `UTerm >> B0 = UTerm` +impl Shr<B0> for UTerm { + type Output = UTerm; + fn shr(self, _: B0) -> Self::Output { + UTerm + } +} + +/// Shifting right `UTerm` by a 1 bit: `UTerm >> B1 = UTerm` +impl Shr<B1> for UTerm { + type Output = UTerm; + fn shr(self, _: B1) -> Self::Output { + UTerm + } +} + +/// Shifting right any unsigned by a zero bit: `U >> B0 = U` +impl<U: Unsigned, B: Bit> Shr<B0> for UInt<U, B> { + type Output = UInt<U, B>; + fn shr(self, _: B0) -> Self::Output { + UInt::new() + } +} + +/// Shifting right a `UInt` by a 1 bit: `UInt<U, B> >> B1 = U` +impl<U: Unsigned, B: Bit> Shr<B1> for UInt<U, B> { + type Output = U; + fn shr(self, _: B1) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// Shifting right `UInt` by `UInt`: `UInt(U, B) >> Y` = `U >> (Y - 1)` +impl<U: Unsigned, B: Bit, Ur: Unsigned, Br: Bit> Shr<UInt<Ur, Br>> for UInt<U, B> +where + UInt<Ur, Br>: Sub<B1>, + U: Shr<Sub1<UInt<Ur, Br>>>, +{ + type Output = Shright<U, Sub1<UInt<Ur, Br>>>; + fn shr(self, _: UInt<Ur, Br>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Multiply unsigned integers + +/// `UInt * B0 = UTerm` +impl<U: Unsigned, B: Bit> Mul<B0> for UInt<U, B> { + type Output = UTerm; + fn mul(self, _: B0) -> Self::Output { + UTerm + } +} + +/// `UTerm * B0 = UTerm` +impl Mul<B0> for UTerm { + type Output = UTerm; + fn mul(self, _: B0) -> Self::Output { + UTerm + } +} + +/// `UTerm * B1 = UTerm` +impl Mul<B1> for UTerm { + type Output = UTerm; + fn mul(self, _: B1) -> Self::Output { + UTerm + } +} + +/// `UInt * B1 = UInt` +impl<U: Unsigned, B: Bit> Mul<B1> for UInt<U, B> { + type Output = UInt<U, B>; + fn mul(self, _: B1) -> Self::Output { + UInt::new() + } +} + +/// `UInt<U, B> * UTerm = UTerm` +impl<U: Unsigned, B: Bit> Mul<UTerm> for UInt<U, B> { + type Output = UTerm; + fn mul(self, _: UTerm) -> Self::Output { + UTerm + } +} + +/// `UTerm * U = UTerm` +impl<U: Unsigned> Mul<U> for UTerm { + type Output = UTerm; + fn mul(self, _: U) -> Self::Output { + UTerm + } +} + +/// `UInt<Ul, B0> * UInt<Ur, B> = UInt<(Ul * UInt<Ur, B>), B0>` +impl<Ul: Unsigned, B: Bit, Ur: Unsigned> Mul<UInt<Ur, B>> for UInt<Ul, B0> +where + Ul: Mul<UInt<Ur, B>>, +{ + type Output = UInt<Prod<Ul, UInt<Ur, B>>, B0>; + fn mul(self, _: UInt<Ur, B>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +/// `UInt<Ul, B1> * UInt<Ur, B> = UInt<(Ul * UInt<Ur, B>), B0> + UInt<Ur, B>` +impl<Ul: Unsigned, B: Bit, Ur: Unsigned> Mul<UInt<Ur, B>> for UInt<Ul, B1> +where + Ul: Mul<UInt<Ur, B>>, + UInt<Prod<Ul, UInt<Ur, B>>, B0>: Add<UInt<Ur, B>>, +{ + type Output = Sum<UInt<Prod<Ul, UInt<Ur, B>>, B0>, UInt<Ur, B>>; + fn mul(self, _: UInt<Ur, B>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// --------------------------------------------------------------------------------------- +// Compare unsigned integers + +/// Zero == Zero +impl Cmp<UTerm> for UTerm { + type Output = Equal; +} + +/// Nonzero > Zero +impl<U: Unsigned, B: Bit> Cmp<UTerm> for UInt<U, B> { + type Output = Greater; +} + +/// Zero < Nonzero +impl<U: Unsigned, B: Bit> Cmp<UInt<U, B>> for UTerm { + type Output = Less; +} + +/// `UInt<Ul, B0>` cmp with `UInt<Ur, B0>`: `SoFar` is `Equal` +impl<Ul: Unsigned, Ur: Unsigned> Cmp<UInt<Ur, B0>> for UInt<Ul, B0> +where + Ul: PrivateCmp<Ur, Equal>, +{ + type Output = PrivateCmpOut<Ul, Ur, Equal>; +} + +/// `UInt<Ul, B1>` cmp with `UInt<Ur, B1>`: `SoFar` is `Equal` +impl<Ul: Unsigned, Ur: Unsigned> Cmp<UInt<Ur, B1>> for UInt<Ul, B1> +where + Ul: PrivateCmp<Ur, Equal>, +{ + type Output = PrivateCmpOut<Ul, Ur, Equal>; +} + +/// `UInt<Ul, B0>` cmp with `UInt<Ur, B1>`: `SoFar` is `Less` +impl<Ul: Unsigned, Ur: Unsigned> Cmp<UInt<Ur, B1>> for UInt<Ul, B0> +where + Ul: PrivateCmp<Ur, Less>, +{ + type Output = PrivateCmpOut<Ul, Ur, Less>; +} + +/// `UInt<Ul, B1>` cmp with `UInt<Ur, B0>`: `SoFar` is `Greater` +impl<Ul: Unsigned, Ur: Unsigned> Cmp<UInt<Ur, B0>> for UInt<Ul, B1> +where + Ul: PrivateCmp<Ur, Greater>, +{ + type Output = PrivateCmpOut<Ul, Ur, Greater>; +} + +/// Comparing non-terimal bits, with both having bit `B0`. +/// These are `Equal`, so we propogate `SoFar`. +impl<Ul, Ur, SoFar> PrivateCmp<UInt<Ur, B0>, SoFar> for UInt<Ul, B0> +where + Ul: Unsigned, + Ur: Unsigned, + SoFar: Ord, + Ul: PrivateCmp<Ur, SoFar>, +{ + type Output = PrivateCmpOut<Ul, Ur, SoFar>; +} + +/// Comparing non-terimal bits, with both having bit `B1`. +/// These are `Equal`, so we propogate `SoFar`. +impl<Ul, Ur, SoFar> PrivateCmp<UInt<Ur, B1>, SoFar> for UInt<Ul, B1> +where + Ul: Unsigned, + Ur: Unsigned, + SoFar: Ord, + Ul: PrivateCmp<Ur, SoFar>, +{ + type Output = PrivateCmpOut<Ul, Ur, SoFar>; +} + +/// Comparing non-terimal bits, with `Lhs` having bit `B0` and `Rhs` having bit `B1`. +/// `SoFar`, Lhs is `Less`. +impl<Ul, Ur, SoFar> PrivateCmp<UInt<Ur, B1>, SoFar> for UInt<Ul, B0> +where + Ul: Unsigned, + Ur: Unsigned, + SoFar: Ord, + Ul: PrivateCmp<Ur, Less>, +{ + type Output = PrivateCmpOut<Ul, Ur, Less>; +} + +/// Comparing non-terimal bits, with `Lhs` having bit `B1` and `Rhs` having bit `B0`. +/// `SoFar`, Lhs is `Greater`. +impl<Ul, Ur, SoFar> PrivateCmp<UInt<Ur, B0>, SoFar> for UInt<Ul, B1> +where + Ul: Unsigned, + Ur: Unsigned, + SoFar: Ord, + Ul: PrivateCmp<Ur, Greater>, +{ + type Output = PrivateCmpOut<Ul, Ur, Greater>; +} + +/// Got to the end of just the `Lhs`. It's `Less`. +impl<U: Unsigned, B: Bit, SoFar: Ord> PrivateCmp<UInt<U, B>, SoFar> for UTerm { + type Output = Less; +} + +/// Got to the end of just the `Rhs`. `Lhs` is `Greater`. +impl<U: Unsigned, B: Bit, SoFar: Ord> PrivateCmp<UTerm, SoFar> for UInt<U, B> { + type Output = Greater; +} + +/// Got to the end of both! Return `SoFar` +impl<SoFar: Ord> PrivateCmp<UTerm, SoFar> for UTerm { + type Output = SoFar; +} + +// --------------------------------------------------------------------------------------- +// Getting difference in number of bits + +impl<Ul, Bl, Ur, Br> BitDiff<UInt<Ur, Br>> for UInt<Ul, Bl> +where + Ul: Unsigned, + Bl: Bit, + Ur: Unsigned, + Br: Bit, + Ul: BitDiff<Ur>, +{ + type Output = BitDiffOut<Ul, Ur>; +} + +impl<Ul> BitDiff<UTerm> for Ul +where + Ul: Unsigned + Len, +{ + type Output = Length<Ul>; +} + +// --------------------------------------------------------------------------------------- +// Shifting one number until it's the size of another +use private::ShiftDiff; +impl<Ul: Unsigned, Ur: Unsigned> ShiftDiff<Ur> for Ul +where + Ur: BitDiff<Ul>, + Ul: Shl<BitDiffOut<Ur, Ul>>, +{ + type Output = Shleft<Ul, BitDiffOut<Ur, Ul>>; +} + +// --------------------------------------------------------------------------------------- +// Powers of unsigned integers + +/// X^N +impl<X: Unsigned, N: Unsigned> Pow<N> for X +where + X: PrivatePow<U1, N>, +{ + type Output = PrivatePowOut<X, U1, N>; + fn powi(self, _: N) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U0> for X { + type Output = Y; +} + +impl<Y: Unsigned, X: Unsigned> PrivatePow<Y, U1> for X +where + X: Mul<Y>, +{ + type Output = Prod<X, Y>; +} + +/// N is even +impl<Y: Unsigned, U: Unsigned, B: Bit, X: Unsigned> PrivatePow<Y, UInt<UInt<U, B>, B0>> for X +where + X: Mul, + Square<X>: PrivatePow<Y, UInt<U, B>>, +{ + type Output = PrivatePowOut<Square<X>, Y, UInt<U, B>>; +} + +/// N is odd +impl<Y: Unsigned, U: Unsigned, B: Bit, X: Unsigned> PrivatePow<Y, UInt<UInt<U, B>, B1>> for X +where + X: Mul + Mul<Y>, + Square<X>: PrivatePow<Prod<X, Y>, UInt<U, B>>, +{ + type Output = PrivatePowOut<Square<X>, Prod<X, Y>, UInt<U, B>>; +} + +// ----------------------------------------- +// GetBit + +#[allow(missing_docs)] +pub trait GetBit<I> { + #[allow(missing_docs)] + type Output; +} + +#[allow(missing_docs)] +pub type GetBitOut<N, I> = <N as GetBit<I>>::Output; + +// Base case +impl<Un, Bn> GetBit<U0> for UInt<Un, Bn> { + type Output = Bn; +} + +// Recursion case +impl<Un, Bn, Ui, Bi> GetBit<UInt<Ui, Bi>> for UInt<Un, Bn> +where + UInt<Ui, Bi>: Sub<B1>, + Un: GetBit<Sub1<UInt<Ui, Bi>>>, +{ + type Output = GetBitOut<Un, Sub1<UInt<Ui, Bi>>>; +} + +// Ran out of bits +impl<I> GetBit<I> for UTerm { + type Output = B0; +} + +#[test] +fn test_get_bit() { + use consts::*; + use Same; + type T1 = <GetBitOut<U2, U0> as Same<B0>>::Output; + type T2 = <GetBitOut<U2, U1> as Same<B1>>::Output; + type T3 = <GetBitOut<U2, U2> as Same<B0>>::Output; + + <T1 as Bit>::to_bool(); + <T2 as Bit>::to_bool(); + <T3 as Bit>::to_bool(); +} + +// ----------------------------------------- +// SetBit + +/// A **type operator** that, when implemented for unsigned integer `N`, sets the bit at position +/// `I` to `B`. +pub trait SetBit<I, B> { + #[allow(missing_docs)] + type Output; +} +/// Alias for the result of calling `SetBit`: `SetBitOut<N, I, B> = <N as SetBit<I, B>>::Output`. +pub type SetBitOut<N, I, B> = <N as SetBit<I, B>>::Output; + +use private::{PrivateSetBit, PrivateSetBitOut}; + +// Call private one then trim it +impl<N, I, B> SetBit<I, B> for N +where + N: PrivateSetBit<I, B>, + PrivateSetBitOut<N, I, B>: Trim, +{ + type Output = TrimOut<PrivateSetBitOut<N, I, B>>; +} + +// Base case +impl<Un, Bn, B> PrivateSetBit<U0, B> for UInt<Un, Bn> { + type Output = UInt<Un, B>; +} + +// Recursion case +impl<Un, Bn, Ui, Bi, B> PrivateSetBit<UInt<Ui, Bi>, B> for UInt<Un, Bn> +where + UInt<Ui, Bi>: Sub<B1>, + Un: PrivateSetBit<Sub1<UInt<Ui, Bi>>, B>, +{ + type Output = UInt<PrivateSetBitOut<Un, Sub1<UInt<Ui, Bi>>, B>, Bn>; +} + +// Ran out of bits, setting B0 +impl<I> PrivateSetBit<I, B0> for UTerm { + type Output = UTerm; +} + +// Ran out of bits, setting B1 +impl<I> PrivateSetBit<I, B1> for UTerm +where + U1: Shl<I>, +{ + type Output = Shleft<U1, I>; +} + +#[test] +fn test_set_bit() { + use consts::*; + use Same; + type T1 = <SetBitOut<U2, U0, B0> as Same<U2>>::Output; + type T2 = <SetBitOut<U2, U0, B1> as Same<U3>>::Output; + type T3 = <SetBitOut<U2, U1, B0> as Same<U0>>::Output; + type T4 = <SetBitOut<U2, U1, B1> as Same<U2>>::Output; + type T5 = <SetBitOut<U2, U2, B0> as Same<U2>>::Output; + type T6 = <SetBitOut<U2, U2, B1> as Same<U6>>::Output; + type T7 = <SetBitOut<U2, U3, B0> as Same<U2>>::Output; + type T8 = <SetBitOut<U2, U3, B1> as Same<U10>>::Output; + type T9 = <SetBitOut<U2, U4, B0> as Same<U2>>::Output; + type T10 = <SetBitOut<U2, U4, B1> as Same<U18>>::Output; + + type T11 = <SetBitOut<U3, U0, B0> as Same<U2>>::Output; + + <T1 as Unsigned>::to_u32(); + <T2 as Unsigned>::to_u32(); + <T3 as Unsigned>::to_u32(); + <T4 as Unsigned>::to_u32(); + <T5 as Unsigned>::to_u32(); + <T6 as Unsigned>::to_u32(); + <T7 as Unsigned>::to_u32(); + <T8 as Unsigned>::to_u32(); + <T9 as Unsigned>::to_u32(); + <T10 as Unsigned>::to_u32(); + <T11 as Unsigned>::to_u32(); +} + +// ----------------------------------------- + +// Division algorithm: +// We have N / D: +// let Q = 0, R = 0 +// NBits = len(N) +// for I in NBits-1..0: +// R <<=1 +// R[0] = N[i] +// let C = R.cmp(D) +// if C == Equal or Greater: +// R -= D +// Q[i] = 1 + +#[cfg(tests)] +mod tests { + macro_rules! test_div { + ($a:ident / $b:ident = $c:ident) => ( + { + type R = Quot<$a, $b>; + assert_eq!(<R as Unsigned>::to_usize(), $c::to_usize()); + } + ); + } + #[test] + fn test_div() { + use consts::*; + use {Quot, Same}; + + test_div!(U0 / U1 = U0); + test_div!(U1 / U1 = U1); + test_div!(U2 / U1 = U2); + test_div!(U3 / U1 = U3); + test_div!(U4 / U1 = U4); + + test_div!(U0 / U2 = U0); + test_div!(U1 / U2 = U0); + test_div!(U2 / U2 = U1); + test_div!(U3 / U2 = U1); + test_div!(U4 / U2 = U2); + test_div!(U6 / U2 = U3); + test_div!(U7 / U2 = U3); + + type T = <SetBitOut<U0, U1, B1> as Same<U2>>::Output; + <T as Unsigned>::to_u32(); + } +} +// ----------------------------------------- +// Div +use core::ops::Div; + +// 0 // N +impl<Ur: Unsigned, Br: Bit> Div<UInt<Ur, Br>> for UTerm { + type Output = UTerm; + fn div(self, _: UInt<Ur, Br>) -> Self::Output { + UTerm + } +} + +// M // N +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned, Br: Bit> Div<UInt<Ur, Br>> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: Len, + Length<UInt<Ul, Bl>>: Sub<B1>, + (): PrivateDiv<UInt<Ul, Bl>, UInt<Ur, Br>, U0, U0, Sub1<Length<UInt<Ul, Bl>>>>, +{ + type Output = PrivateDivQuot<UInt<Ul, Bl>, UInt<Ur, Br>, U0, U0, Sub1<Length<UInt<Ul, Bl>>>>; + fn div(self, _: UInt<Ur, Br>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// ----------------------------------------- +// Rem +use core::ops::Rem; + +// 0 % N +impl<Ur: Unsigned, Br: Bit> Rem<UInt<Ur, Br>> for UTerm { + type Output = UTerm; + fn rem(self, _: UInt<Ur, Br>) -> Self::Output { + UTerm + } +} + +// M % N +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned, Br: Bit> Rem<UInt<Ur, Br>> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: Len, + Length<UInt<Ul, Bl>>: Sub<B1>, + (): PrivateDiv<UInt<Ul, Bl>, UInt<Ur, Br>, U0, U0, Sub1<Length<UInt<Ul, Bl>>>>, +{ + type Output = PrivateDivRem<UInt<Ul, Bl>, UInt<Ur, Br>, U0, U0, Sub1<Length<UInt<Ul, Bl>>>>; + fn rem(self, _: UInt<Ur, Br>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// ----------------------------------------- +// PrivateDiv +use private::{PrivateDiv, PrivateDivQuot, PrivateDivRem}; + +use Compare; +// R == 0: We set R = UInt<UTerm, N[i]>, then call out to PrivateDivIf for the if statement +impl<N, D, Q, I> PrivateDiv<N, D, Q, U0, I> for () +where + N: GetBit<I>, + UInt<UTerm, GetBitOut<N, I>>: Trim, + TrimOut<UInt<UTerm, GetBitOut<N, I>>>: Cmp<D>, + (): PrivateDivIf< + N, + D, + Q, + TrimOut<UInt<UTerm, GetBitOut<N, I>>>, + I, + Compare<TrimOut<UInt<UTerm, GetBitOut<N, I>>>, D>, + >, +{ + type Quotient = PrivateDivIfQuot< + N, + D, + Q, + TrimOut<UInt<UTerm, GetBitOut<N, I>>>, + I, + Compare<TrimOut<UInt<UTerm, GetBitOut<N, I>>>, D>, + >; + type Remainder = PrivateDivIfRem< + N, + D, + Q, + TrimOut<UInt<UTerm, GetBitOut<N, I>>>, + I, + Compare<TrimOut<UInt<UTerm, GetBitOut<N, I>>>, D>, + >; +} + +// R > 0: We perform R <<= 1 and R[0] = N[i], then call out to PrivateDivIf for the if statement +impl<N, D, Q, Ur, Br, I> PrivateDiv<N, D, Q, UInt<Ur, Br>, I> for () +where + N: GetBit<I>, + UInt<UInt<Ur, Br>, GetBitOut<N, I>>: Cmp<D>, + (): PrivateDivIf< + N, + D, + Q, + UInt<UInt<Ur, Br>, GetBitOut<N, I>>, + I, + Compare<UInt<UInt<Ur, Br>, GetBitOut<N, I>>, D>, + >, +{ + type Quotient = PrivateDivIfQuot< + N, + D, + Q, + UInt<UInt<Ur, Br>, GetBitOut<N, I>>, + I, + Compare<UInt<UInt<Ur, Br>, GetBitOut<N, I>>, D>, + >; + type Remainder = PrivateDivIfRem< + N, + D, + Q, + UInt<UInt<Ur, Br>, GetBitOut<N, I>>, + I, + Compare<UInt<UInt<Ur, Br>, GetBitOut<N, I>>, D>, + >; +} + +// ----------------------------------------- +// PrivateDivIf + +use private::{PrivateDivIf, PrivateDivIfQuot, PrivateDivIfRem}; + +// R < D, I > 0, we do nothing and recurse +impl<N, D, Q, R, Ui, Bi> PrivateDivIf<N, D, Q, R, UInt<Ui, Bi>, Less> for () +where + UInt<Ui, Bi>: Sub<B1>, + (): PrivateDiv<N, D, Q, R, Sub1<UInt<Ui, Bi>>>, +{ + type Quotient = PrivateDivQuot<N, D, Q, R, Sub1<UInt<Ui, Bi>>>; + type Remainder = PrivateDivRem<N, D, Q, R, Sub1<UInt<Ui, Bi>>>; +} + +// R == D, I > 0, we set R = 0, Q[I] = 1 and recurse +impl<N, D, Q, R, Ui, Bi> PrivateDivIf<N, D, Q, R, UInt<Ui, Bi>, Equal> for () +where + UInt<Ui, Bi>: Sub<B1>, + Q: SetBit<UInt<Ui, Bi>, B1>, + (): PrivateDiv<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, U0, Sub1<UInt<Ui, Bi>>>, +{ + type Quotient = PrivateDivQuot<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, U0, Sub1<UInt<Ui, Bi>>>; + type Remainder = PrivateDivRem<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, U0, Sub1<UInt<Ui, Bi>>>; +} + +use Diff; +// R > D, I > 0, we set R -= D, Q[I] = 1 and recurse +impl<N, D, Q, R, Ui, Bi> PrivateDivIf<N, D, Q, R, UInt<Ui, Bi>, Greater> for () +where + UInt<Ui, Bi>: Sub<B1>, + R: Sub<D>, + Q: SetBit<UInt<Ui, Bi>, B1>, + (): PrivateDiv<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, Diff<R, D>, Sub1<UInt<Ui, Bi>>>, +{ + type Quotient = + PrivateDivQuot<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, Diff<R, D>, Sub1<UInt<Ui, Bi>>>; + type Remainder = + PrivateDivRem<N, D, SetBitOut<Q, UInt<Ui, Bi>, B1>, Diff<R, D>, Sub1<UInt<Ui, Bi>>>; +} + +// R < D, I == 0: we do nothing, and return +impl<N, D, Q, R> PrivateDivIf<N, D, Q, R, U0, Less> for () { + type Quotient = Q; + type Remainder = R; +} + +// R == D, I == 0: we set R = 0, Q[I] = 1, and return +impl<N, D, Q, R> PrivateDivIf<N, D, Q, R, U0, Equal> for () +where + Q: SetBit<U0, B1>, +{ + type Quotient = SetBitOut<Q, U0, B1>; + type Remainder = U0; +} + +// R > D, I == 0: We set R -= D, Q[I] = 1, and return +impl<N, D, Q, R> PrivateDivIf<N, D, Q, R, U0, Greater> for () +where + R: Sub<D>, + Q: SetBit<U0, B1>, +{ + type Quotient = SetBitOut<Q, U0, B1>; + type Remainder = Diff<R, D>; +} + +// ----------------------------------------- +// PartialDiv +use {PartialDiv, Quot}; +impl<Ur: Unsigned, Br: Bit> PartialDiv<UInt<Ur, Br>> for UTerm { + type Output = UTerm; + fn partial_div(self, _: UInt<Ur, Br>) -> Self::Output { + UTerm + } +} + +// M / N +impl<Ul: Unsigned, Bl: Bit, Ur: Unsigned, Br: Bit> PartialDiv<UInt<Ur, Br>> for UInt<Ul, Bl> +where + UInt<Ul, Bl>: Div<UInt<Ur, Br>> + Rem<UInt<Ur, Br>, Output = U0>, +{ + type Output = Quot<UInt<Ul, Bl>, UInt<Ur, Br>>; + fn partial_div(self, _: UInt<Ur, Br>) -> Self::Output { + unsafe { ::core::mem::uninitialized() } + } +} + +// ----------------------------------------- +// PrivateMin +use private::{PrivateMin, PrivateMinOut}; + +impl<U, B, Ur> PrivateMin<Ur, Equal> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = UInt<U, B>; + fn private_min(self, _: Ur) -> Self::Output { + self + } +} + +impl<U, B, Ur> PrivateMin<Ur, Less> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = UInt<U, B>; + fn private_min(self, _: Ur) -> Self::Output { + self + } +} + +impl<U, B, Ur> PrivateMin<Ur, Greater> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = Ur; + fn private_min(self, rhs: Ur) -> Self::Output { + rhs + } +} + +// ----------------------------------------- +// Min +use Min; + +impl<U> Min<U> for UTerm +where + U: Unsigned, +{ + type Output = UTerm; + fn min(self, _: U) -> Self::Output { + self + } +} + +impl<U, B, Ur> Min<Ur> for UInt<U, B> +where + U: Unsigned, + B: Bit, + Ur: Unsigned, + UInt<U, B>: Cmp<Ur> + PrivateMin<Ur, Compare<UInt<U, B>, Ur>>, +{ + type Output = PrivateMinOut<UInt<U, B>, Ur, Compare<UInt<U, B>, Ur>>; + fn min(self, rhs: Ur) -> Self::Output { + self.private_min(rhs) + } +} + +// ----------------------------------------- +// PrivateMax +use private::{PrivateMax, PrivateMaxOut}; + +impl<U, B, Ur> PrivateMax<Ur, Equal> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = UInt<U, B>; + fn private_max(self, _: Ur) -> Self::Output { + self + } +} + +impl<U, B, Ur> PrivateMax<Ur, Less> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = Ur; + fn private_max(self, rhs: Ur) -> Self::Output { + rhs + } +} + +impl<U, B, Ur> PrivateMax<Ur, Greater> for UInt<U, B> +where + Ur: Unsigned, + U: Unsigned, + B: Bit, +{ + type Output = UInt<U, B>; + fn private_max(self, _: Ur) -> Self::Output { + self + } +} + +// ----------------------------------------- +// Max +use Max; + +impl<U> Max<U> for UTerm +where + U: Unsigned, +{ + type Output = U; + fn max(self, rhs: U) -> Self::Output { + rhs + } +} + +impl<U, B, Ur> Max<Ur> for UInt<U, B> +where + U: Unsigned, + B: Bit, + Ur: Unsigned, + UInt<U, B>: Cmp<Ur> + PrivateMax<Ur, Compare<UInt<U, B>, Ur>>, +{ + type Output = PrivateMaxOut<UInt<U, B>, Ur, Compare<UInt<U, B>, Ur>>; + fn max(self, rhs: Ur) -> Self::Output { + self.private_max(rhs) + } +} diff --git a/typenum/tests/test.rs b/typenum/tests/test.rs new file mode 100644 index 000000000..0cd9d98a8 --- /dev/null +++ b/typenum/tests/test.rs @@ -0,0 +1,2 @@ +#[cfg(tests)] +include!(concat!(env!("OUT_DIR"), "/tests.rs")); diff --git a/ucd-util/.cargo-checksum.json b/ucd-util/.cargo-checksum.json new file mode 100644 index 000000000..eca4e826f --- /dev/null +++ b/ucd-util/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"} \ No newline at end of file diff --git a/ucd-util/Cargo.toml b/ucd-util/Cargo.toml new file mode 100644 index 000000000..38d7bd3e0 --- /dev/null +++ b/ucd-util/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "ucd-util" +version = "0.1.3" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +description = "A small utility library for working with the Unicode character database.\n" +homepage = "https://github.com/BurntSushi/ucd-generate" +documentation = "https://docs.rs/ucd-util" +readme = "README.md" +keywords = ["unicode", "database", "character", "property"] +license = "MIT/Apache-2.0" +repository = "https://github.com/BurntSushi/ucd-generate" diff --git a/ucd-util/LICENSE-APACHE b/ucd-util/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/ucd-util/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/ucd-util/LICENSE-MIT b/ucd-util/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/ucd-util/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ucd-util/LICENSE-UNICODE b/ucd-util/LICENSE-UNICODE new file mode 100644 index 000000000..176d5ec11 --- /dev/null +++ b/ucd-util/LICENSE-UNICODE @@ -0,0 +1,57 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +Unicode Data Files include all data files under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +Unicode Data Files do not include PDF online code charts under the +directory http://www.unicode.org/Public/. + +Software includes any source code published in the Unicode Standard +or under the directories +http://www.unicode.org/Public/, http://www.unicode.org/reports/, +http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and +http://www.unicode.org/utility/trac/browser/. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2018 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. \ No newline at end of file diff --git a/ucd-util/README.md b/ucd-util/README.md new file mode 100644 index 000000000..0c4f9bc60 --- /dev/null +++ b/ucd-util/README.md @@ -0,0 +1,27 @@ +ucd-util +======== +A library for small auxiliary Unicode functions. This includes things like +symbol or character name canonicalization, ideograph name generation and helper +functions for searching property name and value tables. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/ucd-generate.png)](https://travis-ci.org/BurntSushi/ucd-generate) +[![](http://meritbadge.herokuapp.com/ucd-generate)](https://crates.io/crates/ucd-util) + + +### Documentation + +https://docs.rs/ucd-util + + +### License + +This project is licensed under either of + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) +at your option. + +The data in [`src/unicode_tables/`](src/unicode_tables) is licensed inder the Unicode License +Agreement ([LICENSE-UNICODE](LICENSE-UNICODE) or +http://www.unicode.org/copyright.html#License). diff --git a/ucd-util/src/hangul.rs b/ucd-util/src/hangul.rs new file mode 100644 index 000000000..dd3bbc8f5 --- /dev/null +++ b/ucd-util/src/hangul.rs @@ -0,0 +1,105 @@ +use unicode_tables::jamo_short_name::JAMO_SHORT_NAME; + +// This implementation should correspond to the algorithms described in +// Unicode 3.12. + +/// A set of ranges that corresponds to the set of all Hangul syllable +/// codepoints. +/// +/// These ranges are defined in Unicode 4.8 Table 4-13. +pub const RANGE_HANGUL_SYLLABLE: &'static [(u32, u32)] = &[ + (0xAC00, 0xD7A3), +]; + +const S_BASE: u32 = 0xAC00; +const L_BASE: u32 = 0x1100; +const V_BASE: u32 = 0x1161; +const T_BASE: u32 = 0x11A7; +const T_COUNT: u32 = 28; +const N_COUNT: u32 = 588; + +/// Return the character name of the given precomposed Hangul codepoint. +/// +/// If the given codepoint does not correspond to a precomposed Hangul +/// codepoint in the inclusive range `AC00..D7A3`, then this returns `None`. +/// +/// This implements the algorithms described in Unicode 3.12 and Unicode 4.8. +pub fn hangul_name(cp: u32) -> Option<String> { + let mut name = "HANGUL SYLLABLE ".to_string(); + let (lpart, vpart, tpart) = match hangul_full_canonical_decomposition(cp) { + None => return None, + Some(triple) => triple, + }; + + name.push_str(jamo_short_name(lpart)); + name.push_str(jamo_short_name(vpart)); + name.push_str(tpart.map_or("", jamo_short_name)); + Some(name) +} + +/// Return the full canonical decomposition of the given precomposed Hangul +/// codepoint. +/// +/// If the decomposition does not have any trailing consonant, then the third +/// part of the tuple returned is `None`. +/// +/// If the given codepoint does not correspond to a precomposed Hangul +/// codepoint in the inclusive range `AC00..D7A3`, then this returns `None`. +/// +/// This implements the algorithms described in Unicode 3.12 and Unicode 4.8. +pub fn hangul_full_canonical_decomposition( + cp: u32, +) -> Option<(u32, u32, Option<u32>)> { + if !(0xAC00 <= cp && cp <= 0xD7A3) { + return None; + } + + let s_index = cp - S_BASE; + let l_index = s_index / N_COUNT; + let v_index = (s_index % N_COUNT) / T_COUNT; + let t_index = s_index % T_COUNT; + + let l_part = L_BASE + l_index; + let v_part = V_BASE + v_index; + let t_part = + if t_index == 0 { + None + } else { + Some(T_BASE + t_index) + }; + Some((l_part, v_part, t_part)) +} + +fn jamo_short_name(cp: u32) -> &'static str { + let i = JAMO_SHORT_NAME.binary_search_by_key(&cp, |p| p.0).unwrap(); + JAMO_SHORT_NAME[i].1 +} + +#[cfg(test)] +mod tests { + use super::{hangul_name, hangul_full_canonical_decomposition}; + + #[test] + fn canon_decomp() { + assert_eq!( + hangul_full_canonical_decomposition(0xD4DB), + Some((0x1111, 0x1171, Some(0x11B6)))); + } + + #[test] + fn name() { + assert_eq!(hangul_name(0xD4DB).unwrap(), "HANGUL SYLLABLE PWILH"); + } + + #[test] + fn all() { + for cp in 0xAC00..(0xD7A3 + 1) { + hangul_name(cp).unwrap(); + } + } + + #[test] + fn invalid() { + assert!(hangul_name(0).is_none()); + } +} diff --git a/ucd-util/src/ideograph.rs b/ucd-util/src/ideograph.rs new file mode 100644 index 000000000..0502c6ecf --- /dev/null +++ b/ucd-util/src/ideograph.rs @@ -0,0 +1,83 @@ +/// A set of ranges that corresponds to the set of all ideograph codepoints. +/// +/// These ranges are defined in Unicode 4.8 Table 4-13. +pub const RANGE_IDEOGRAPH: &'static [(u32, u32)] = &[ + (0x3400, 0x4DB5), + (0x4E00, 0x9FD5), + (0x4E00, 0x9FD5), + (0x20000, 0x2A6D6), + (0x2A700, 0x2B734), + (0x2B740, 0x2B81D), + (0x2B820, 0x2CEA1), + (0x17000, 0x187EC), + (0xF900, 0xFA6D), + (0xFA70, 0xFAD9), + (0x2F800, 0x2FA1D), +]; + +/// Return the character name of the given ideograph codepoint. +/// +/// This operation is only defined on ideographic codepoints. This includes +/// precisely the following inclusive ranges: +/// +/// * `3400..4DB5` +/// * `4E00..9FD5` +/// * `20000..2A6D6` +/// * `2A700..2B734` +/// * `2B740..2B81D` +/// * `2B820..2CEA1` +/// * `17000..187EC` +/// * `F900..FA6D` +/// * `FA70..FAD9` +/// * `2F800..2FA1D` +/// +/// If the given codepoint is not in any of the above ranges, then `None` is +/// returned. +/// +/// This implements the algorithm described in Unicode 4.8. +pub fn ideograph_name(cp: u32) -> Option<String> { + // This match should be in sync with the `RANGE_IDEOGRAPH` constant. + match cp { + 0x3400...0x4DB5 + | 0x4E00...0x9FD5 + | 0x20000...0x2A6D6 + | 0x2A700...0x2B734 + | 0x2B740...0x2B81D + | 0x2B820...0x2CEA1 => { + Some(format!("CJK UNIFIED IDEOGRAPH-{:04X}", cp)) + } + 0x17000...0x187EC => { + Some(format!("TANGUT IDEOGRAPH-{:04X}", cp)) + } + 0xF900...0xFA6D | 0xFA70...0xFAD9 | 0x2F800...0x2FA1D => { + Some(format!("CJK COMPATIBILITY IDEOGRAPH-{:04X}", cp)) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::ideograph_name; + + #[test] + fn name() { + assert_eq!( + ideograph_name(0x4E00).unwrap(), + "CJK UNIFIED IDEOGRAPH-4E00"); + assert_eq!( + ideograph_name(0x9FD5).unwrap(), + "CJK UNIFIED IDEOGRAPH-9FD5"); + assert_eq!( + ideograph_name(0x17000).unwrap(), + "TANGUT IDEOGRAPH-17000"); + assert_eq!( + ideograph_name(0xF900).unwrap(), + "CJK COMPATIBILITY IDEOGRAPH-F900"); + } + + #[test] + fn invalid() { + assert!(ideograph_name(0).is_none()); + } +} diff --git a/ucd-util/src/lib.rs b/ucd-util/src/lib.rs new file mode 100644 index 000000000..4dc560637 --- /dev/null +++ b/ucd-util/src/lib.rs @@ -0,0 +1,28 @@ +/*! +The `ucd-util` crate contains a smattering of utility functions that implement +various algorithms specified by Unicode. There is no specific goal for +exhaustiveness. Instead, implementations should be added on an as-needed basis. + +A *current* design constraint of this crate is that it should not bring in any +large Unicode tables. For example, to use the various property name and value +canonicalization functions, you'll need to supply your own table, which can +be generated using `ucd-generate`. +*/ + +#![deny(missing_docs)] + +mod hangul; +mod ideograph; +mod name; +mod property; +mod unicode_tables; + +pub use hangul::{ + RANGE_HANGUL_SYLLABLE, hangul_name, hangul_full_canonical_decomposition, +}; +pub use ideograph::{RANGE_IDEOGRAPH, ideograph_name}; +pub use name::{character_name_normalize, symbolic_name_normalize}; +pub use property::{ + PropertyTable, PropertyValueTable, PropertyValues, + canonical_property_name, property_values, canonical_property_value, +}; diff --git a/ucd-util/src/name.rs b/ucd-util/src/name.rs new file mode 100644 index 000000000..20c2f4b58 --- /dev/null +++ b/ucd-util/src/name.rs @@ -0,0 +1,194 @@ +/// Normalize the given character name in place according to UAX44-LM2. +/// +/// See: http://unicode.org/reports/tr44/#UAX44-LM2 +pub fn character_name_normalize(string: &mut String) { + let bytes = unsafe { + // SAFETY: `character_name_normalize_bytes` guarantees that + // `bytes[..len]` is valid UTF-8. + string.as_mut_vec() + }; + let len = character_name_normalize_bytes(bytes).len(); + bytes.truncate(len); +} + +/// Normalize the given character name in place according to UAX44-LM2. +/// +/// The slice returned is guaranteed to be valid UTF-8 for all possible values +/// of `slice`. +/// +/// See: http://unicode.org/reports/tr44/#UAX44-LM2 +fn character_name_normalize_bytes(slice: &mut [u8]) -> &mut [u8] { + // According to Unicode 4.8, character names consist only of Latin + // capital letters A to Z, ASCII digits, ASCII space or ASCII hypen. + // Therefore, we can do very simplistic case folding and operate on the + // raw bytes, since everything is ASCII. Note that we don't actually know + // whether `slice` is all ASCII or not, so we drop all non-ASCII bytes. + let mut next_write = 0; + let mut prev_space = true; + for i in 0..slice.len() { + // SAFETY ARGUMENT: To guarantee that the resulting slice is valid + // UTF-8, we ensure that the slice contains only ASCII bytes. In + // particular, we drop every non-ASCII byte from the normalized string. + let b = slice[i]; + if b == b' ' { + prev_space = true; + continue; + } else if b == b'_' { + // Drop the underscore. + } else if b == b'-' { + let mut keep_hyphen = prev_space || slice.get(i+1) == Some(&b' '); + // We want to keep the hypen only if it isn't medial, which means + // it has at least one adjacent space character. However, there + // is one exception. We need to keep the hypen in the character + // (U+1180) named `HANGUL JUNGSEONG O-E`. So we check for that + // here. + let rest_e = slice[i+1..] == b"E"[..] || slice[i+1..] == b"e"[..]; + if !keep_hyphen && rest_e { + keep_hyphen = slice[..next_write] == b"hanguljungseongo"[..]; + } + if keep_hyphen { + slice[next_write] = b; + next_write += 1; + } + } else if b'A' <= b && b <= b'Z' { + slice[next_write] = b + (b'a' - b'A'); + next_write += 1; + } else if b <= 0x7F { + slice[next_write] = b; + next_write += 1; + } + prev_space = false; + } + &mut slice[..next_write] +} + +/// Normalize the given symbolic name in place according to UAX44-LM3. +/// +/// A "symbolic name" typically corresponds to property names and property +/// value aliases. Note, though, that it should not be applied to property +/// string values. +/// +/// See: http://unicode.org/reports/tr44/#UAX44-LM2 +pub fn symbolic_name_normalize(string: &mut String) { + let bytes = unsafe { + // SAFETY: `symbolic_name_normalize_bytes` guarantees that + // `bytes[..len]` is valid UTF-8. + string.as_mut_vec() + }; + let len = symbolic_name_normalize_bytes(bytes).len(); + bytes.truncate(len); +} + +/// Normalize the given symbolic name in place according to UAX44-LM3. +/// +/// A "symbolic name" typically corresponds to property names and property +/// value aliases. Note, though, that it should not be applied to property +/// string values. +/// +/// The slice returned is guaranteed to be valid UTF-8 for all possible values +/// of `slice`. +/// +/// See: http://unicode.org/reports/tr44/#UAX44-LM3 +fn symbolic_name_normalize_bytes(slice: &mut [u8]) -> &mut [u8] { + // I couldn't find a place in the standard that specified that property + // names/aliases had a particular structure (unlike character names), but + // we assume that it's ASCII only and drop anything that isn't ASCII. + let mut start = 0; + let mut starts_with_is = false; + if slice.len() >= 2 { + // Ignore any "is" prefix. + starts_with_is = + slice[0..2] == b"is"[..] + || slice[0..2] == b"IS"[..] + || slice[0..2] == b"iS"[..] + || slice[0..2] == b"Is"[..]; + if starts_with_is { + start = 2; + } + } + let mut next_write = 0; + for i in start..slice.len() { + // SAFETY ARGUMENT: To guarantee that the resulting slice is valid + // UTF-8, we ensure that the slice contains only ASCII bytes. In + // particular, we drop every non-ASCII byte from the normalized string. + let b = slice[i]; + if b == b' ' || b == b'_' || b == b'-' { + continue; + } else if b'A' <= b && b <= b'Z' { + slice[next_write] = b + (b'a' - b'A'); + next_write += 1; + } else if b <= 0x7F { + slice[next_write] = b; + next_write += 1; + } + } + // Special case: ISO_Comment has a 'isc' abbreviation. Since we generally + // ignore 'is' prefixes, the 'isc' abbreviation gets caught in the cross + // fire and ends up creating an alias for 'c' to 'ISO_Comment', but it + // is actually an alias for the 'Other' general category. + if starts_with_is && next_write == 1 && slice[0] == b'c' { + slice[0] = b'i'; + slice[1] = b's'; + slice[2] = b'c'; + next_write = 3; + } + &mut slice[..next_write] +} + +#[cfg(test)] +mod tests { + use super::{ + character_name_normalize, character_name_normalize_bytes, + symbolic_name_normalize, symbolic_name_normalize_bytes, + }; + + fn char_norm(s: &str) -> String { + let mut s = s.to_string(); + character_name_normalize(&mut s); + s + } + + fn sym_norm(s: &str) -> String { + let mut s = s.to_string(); + symbolic_name_normalize(&mut s); + s + } + + #[test] + fn char_normalize() { + assert_eq!(char_norm("HANGUL JUNGSEONG O-E"), "hanguljungseongo-e"); + assert_eq!(char_norm("zero-width space"), "zerowidthspace"); + assert_eq!(char_norm("zerowidthspace"), "zerowidthspace"); + assert_eq!(char_norm("ZERO WIDTH SPACE"), "zerowidthspace"); + assert_eq!(char_norm("TIBETAN MARK TSA -PHRU"), "tibetanmarktsa-phru"); + } + + #[test] + fn sym_normalize() { + assert_eq!(sym_norm("Line_Break"), "linebreak"); + assert_eq!(sym_norm("Line-break"), "linebreak"); + assert_eq!(sym_norm("linebreak"), "linebreak"); + assert_eq!(sym_norm("BA"), "ba"); + assert_eq!(sym_norm("ba"), "ba"); + assert_eq!(sym_norm("Greek"), "greek"); + assert_eq!(sym_norm("isGreek"), "greek"); + assert_eq!(sym_norm("IS_Greek"), "greek"); + assert_eq!(sym_norm("isc"), "isc"); + assert_eq!(sym_norm("is c"), "isc"); + assert_eq!(sym_norm("is_c"), "isc"); + } + + #[test] + fn valid_utf8_character() { + let mut x = b"abc\xFFxyz".to_vec(); + let y = character_name_normalize_bytes(&mut x); + assert_eq!(y, b"abcxyz"); + } + + #[test] + fn valid_utf8_symbolic() { + let mut x = b"abc\xFFxyz".to_vec(); + let y = symbolic_name_normalize_bytes(&mut x); + assert_eq!(y, b"abcxyz"); + } +} diff --git a/ucd-util/src/property.rs b/ucd-util/src/property.rs new file mode 100644 index 000000000..7bbe56e96 --- /dev/null +++ b/ucd-util/src/property.rs @@ -0,0 +1,124 @@ +/// The type of a property name table. +/// +/// A property name table is a sequence of sorted tuples, where the first +/// value in each tuple is a normalized property name and the second value of +/// each tuple is the corresponding canonical property name. +pub type PropertyTable = &'static [(&'static str, &'static str)]; + +/// Find the canonical property name for the given normalized property name. +/// +/// If no such property exists, then `None` is returned. +/// +/// The normalized property name must have been normalized according to +/// UAX44 LM3, which can be done using `symbolic_name_normalize`. +pub fn canonical_property_name( + property_table: PropertyTable, + normalized_property_name: &str, +) -> Option<&'static str> { + property_table + .binary_search_by_key(&normalized_property_name, |&(n, _)| n) + .ok() + .map(|i| property_table[i].1) +} + +/// Type of a property value table. +/// +/// A property value table maps property names to a mapping of property values, +/// where the mapping of property values is represented by a sequence of +/// tuples. The first element of each tuple is a normalized property value +/// while the second element of each tuple is the corresponding canonical +/// property value. +/// +/// Note that a property value table only includes values for properties that +/// are catalogs, enumerations or binary properties. Properties that have +/// string values (such as case or decomposition mappings), numeric values +/// or are miscellaneous are not represented in this table. +pub type PropertyValueTable = &'static [(&'static str, PropertyValues)]; + +/// A mapping of property values for a specific property. +/// +/// The first element of each tuple is a normalized property value while the +/// second element of each tuple is the corresponding canonical property +/// value. +pub type PropertyValues = &'static [(&'static str, &'static str)]; + +/// Find the set of possible property values for a given property. +/// +/// The set returned is a mapping expressed as a sorted list of tuples. +/// The first element of each tuple is a normalized property value while the +/// second element of each tuple is the corresponding canonical property +/// value. +/// +/// If no such property exists, then `None` is returned. +/// +/// The given property name must be in its canonical form, which can be +/// found using `canonical_property_name`. +pub fn property_values( + property_value_table: PropertyValueTable, + canonical_property_name: &str, +) -> Option<PropertyValues> { + property_value_table + .binary_search_by_key(&canonical_property_name, |&(n, _)| n) + .ok() + .map(|i| property_value_table[i].1) +} + +/// Find the canonical property value for the given normalized property +/// value. +/// +/// The given property values should correspond to the values for the property +/// under question, which can be found using `property_values`. +/// +/// If no such property value exists, then `None` is returned. +/// +/// The normalized property value must have been normalized according to +/// UAX44 LM3, which can be done using `symbolic_name_normalize`. +pub fn canonical_property_value( + property_values: PropertyValues, + normalized_property_value: &str, +) -> Option<&'static str> { + // This is cute. The types line up, so why not? + canonical_property_name(property_values, normalized_property_value) +} + + +#[cfg(test)] +mod tests { + use unicode_tables::property_names::PROPERTY_NAMES; + use unicode_tables::property_values::PROPERTY_VALUES; + + use super::{ + canonical_property_name, property_values, canonical_property_value, + }; + + #[test] + fn canonical_property_name_1() { + assert_eq!( + canonical_property_name(PROPERTY_NAMES, "gc"), + Some("General_Category")); + assert_eq!( + canonical_property_name(PROPERTY_NAMES, "generalcategory"), + Some("General_Category")); + assert_eq!( + canonical_property_name(PROPERTY_NAMES, "g c"), + None); + } + + #[test] + fn property_values_1() { + assert_eq!( + property_values(PROPERTY_VALUES, "White_Space"), + Some(&[ + ("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ][..])); + } + + #[test] + fn canonical_property_value_1() { + let values = property_values(PROPERTY_VALUES, "White_Space").unwrap(); + assert_eq!(canonical_property_value(values, "false"), Some("No")); + assert_eq!(canonical_property_value(values, "t"), Some("Yes")); + assert_eq!(canonical_property_value(values, "F"), None); + } +} diff --git a/ucd-util/src/unicode_tables/jamo_short_name.rs b/ucd-util/src/unicode_tables/jamo_short_name.rs new file mode 100644 index 000000000..4d48063cc --- /dev/null +++ b/ucd-util/src/unicode_tables/jamo_short_name.rs @@ -0,0 +1,22 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate jamo-short-name tmp/ucd-11.0.0/ +// +// ucd-generate is available on crates.io. + +pub const JAMO_SHORT_NAME: &'static [(u32, &'static str)] = &[ + (4352, "G"), (4353, "GG"), (4354, "N"), (4355, "D"), (4356, "DD"), + (4357, "R"), (4358, "M"), (4359, "B"), (4360, "BB"), (4361, "S"), + (4362, "SS"), (4363, ""), (4364, "J"), (4365, "JJ"), (4366, "C"), + (4367, "K"), (4368, "T"), (4369, "P"), (4370, "H"), (4449, "A"), + (4450, "AE"), (4451, "YA"), (4452, "YAE"), (4453, "EO"), (4454, "E"), + (4455, "YEO"), (4456, "YE"), (4457, "O"), (4458, "WA"), (4459, "WAE"), + (4460, "OE"), (4461, "YO"), (4462, "U"), (4463, "WEO"), (4464, "WE"), + (4465, "WI"), (4466, "YU"), (4467, "EU"), (4468, "YI"), (4469, "I"), + (4520, "G"), (4521, "GG"), (4522, "GS"), (4523, "N"), (4524, "NJ"), + (4525, "NH"), (4526, "D"), (4527, "L"), (4528, "LG"), (4529, "LM"), + (4530, "LB"), (4531, "LS"), (4532, "LT"), (4533, "LP"), (4534, "LH"), + (4535, "M"), (4536, "B"), (4537, "BS"), (4538, "S"), (4539, "SS"), + (4540, "NG"), (4541, "J"), (4542, "C"), (4543, "K"), (4544, "T"), + (4545, "P"), (4546, "H"), +]; diff --git a/ucd-util/src/unicode_tables/mod.rs b/ucd-util/src/unicode_tables/mod.rs new file mode 100644 index 000000000..558177da9 --- /dev/null +++ b/ucd-util/src/unicode_tables/mod.rs @@ -0,0 +1,5 @@ +pub mod jamo_short_name; +#[cfg(test)] +pub mod property_names; +#[cfg(test)] +pub mod property_values; diff --git a/ucd-util/src/unicode_tables/property_names.rs b/ucd-util/src/unicode_tables/property_names.rs new file mode 100644 index 000000000..aa1d684a7 --- /dev/null +++ b/ucd-util/src/unicode_tables/property_names.rs @@ -0,0 +1,147 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-names tmp/ucd-11.0.0/ +// +// ucd-generate is available on crates.io. + +pub const PROPERTY_NAMES: &'static [(&'static str, &'static str)] = &[ + ("age", "Age"), ("ahex", "ASCII_Hex_Digit"), ("alpha", "Alphabetic"), + ("alphabetic", "Alphabetic"), ("asciihexdigit", "ASCII_Hex_Digit"), + ("bc", "Bidi_Class"), ("bidic", "Bidi_Control"), + ("bidiclass", "Bidi_Class"), ("bidicontrol", "Bidi_Control"), + ("bidim", "Bidi_Mirrored"), ("bidimirrored", "Bidi_Mirrored"), + ("bidimirroringglyph", "Bidi_Mirroring_Glyph"), + ("bidipairedbracket", "Bidi_Paired_Bracket"), + ("bidipairedbrackettype", "Bidi_Paired_Bracket_Type"), ("blk", "Block"), + ("block", "Block"), ("bmg", "Bidi_Mirroring_Glyph"), + ("bpb", "Bidi_Paired_Bracket"), ("bpt", "Bidi_Paired_Bracket_Type"), + ("canonicalcombiningclass", "Canonical_Combining_Class"), + ("cased", "Cased"), ("casefolding", "Case_Folding"), + ("caseignorable", "Case_Ignorable"), ("ccc", "Canonical_Combining_Class"), + ("ce", "Composition_Exclusion"), ("cf", "Case_Folding"), + ("changeswhencasefolded", "Changes_When_Casefolded"), + ("changeswhencasemapped", "Changes_When_Casemapped"), + ("changeswhenlowercased", "Changes_When_Lowercased"), + ("changeswhennfkccasefolded", "Changes_When_NFKC_Casefolded"), + ("changeswhentitlecased", "Changes_When_Titlecased"), + ("changeswhenuppercased", "Changes_When_Uppercased"), + ("ci", "Case_Ignorable"), ("cjkaccountingnumeric", "kAccountingNumeric"), + ("cjkcompatibilityvariant", "kCompatibilityVariant"), + ("cjkiicore", "kIICore"), ("cjkirggsource", "kIRG_GSource"), + ("cjkirghsource", "kIRG_HSource"), ("cjkirgjsource", "kIRG_JSource"), + ("cjkirgkpsource", "kIRG_KPSource"), ("cjkirgksource", "kIRG_KSource"), + ("cjkirgmsource", "kIRG_MSource"), ("cjkirgtsource", "kIRG_TSource"), + ("cjkirgusource", "kIRG_USource"), ("cjkirgvsource", "kIRG_VSource"), + ("cjkothernumeric", "kOtherNumeric"), + ("cjkprimarynumeric", "kPrimaryNumeric"), ("cjkrsunicode", "kRSUnicode"), + ("compex", "Full_Composition_Exclusion"), + ("compositionexclusion", "Composition_Exclusion"), + ("cwcf", "Changes_When_Casefolded"), ("cwcm", "Changes_When_Casemapped"), + ("cwkcf", "Changes_When_NFKC_Casefolded"), + ("cwl", "Changes_When_Lowercased"), ("cwt", "Changes_When_Titlecased"), + ("cwu", "Changes_When_Uppercased"), ("dash", "Dash"), + ("decompositionmapping", "Decomposition_Mapping"), + ("decompositiontype", "Decomposition_Type"), + ("defaultignorablecodepoint", "Default_Ignorable_Code_Point"), + ("dep", "Deprecated"), ("deprecated", "Deprecated"), + ("di", "Default_Ignorable_Code_Point"), ("dia", "Diacritic"), + ("diacritic", "Diacritic"), ("dm", "Decomposition_Mapping"), + ("dt", "Decomposition_Type"), ("ea", "East_Asian_Width"), + ("eastasianwidth", "East_Asian_Width"), + ("equideo", "Equivalent_Unified_Ideograph"), + ("equivalentunifiedideograph", "Equivalent_Unified_Ideograph"), + ("expandsonnfc", "Expands_On_NFC"), ("expandsonnfd", "Expands_On_NFD"), + ("expandsonnfkc", "Expands_On_NFKC"), ("expandsonnfkd", "Expands_On_NFKD"), + ("ext", "Extender"), ("extender", "Extender"), + ("fcnfkc", "FC_NFKC_Closure"), ("fcnfkcclosure", "FC_NFKC_Closure"), + ("fullcompositionexclusion", "Full_Composition_Exclusion"), + ("gc", "General_Category"), ("gcb", "Grapheme_Cluster_Break"), + ("generalcategory", "General_Category"), ("graphemebase", "Grapheme_Base"), + ("graphemeclusterbreak", "Grapheme_Cluster_Break"), + ("graphemeextend", "Grapheme_Extend"), ("graphemelink", "Grapheme_Link"), + ("grbase", "Grapheme_Base"), ("grext", "Grapheme_Extend"), + ("grlink", "Grapheme_Link"), ("hangulsyllabletype", "Hangul_Syllable_Type"), + ("hex", "Hex_Digit"), ("hexdigit", "Hex_Digit"), + ("hst", "Hangul_Syllable_Type"), ("hyphen", "Hyphen"), + ("idc", "ID_Continue"), ("idcontinue", "ID_Continue"), + ("ideo", "Ideographic"), ("ideographic", "Ideographic"), + ("ids", "ID_Start"), ("idsb", "IDS_Binary_Operator"), + ("idsbinaryoperator", "IDS_Binary_Operator"), + ("idst", "IDS_Trinary_Operator"), ("idstart", "ID_Start"), + ("idstrinaryoperator", "IDS_Trinary_Operator"), + ("indicpositionalcategory", "Indic_Positional_Category"), + ("indicsyllabiccategory", "Indic_Syllabic_Category"), + ("inpc", "Indic_Positional_Category"), ("insc", "Indic_Syllabic_Category"), + ("isc", "ISO_Comment"), ("jamoshortname", "Jamo_Short_Name"), + ("jg", "Joining_Group"), ("joinc", "Join_Control"), + ("joincontrol", "Join_Control"), ("joininggroup", "Joining_Group"), + ("joiningtype", "Joining_Type"), ("jsn", "Jamo_Short_Name"), + ("jt", "Joining_Type"), ("kaccountingnumeric", "kAccountingNumeric"), + ("kcompatibilityvariant", "kCompatibilityVariant"), ("kiicore", "kIICore"), + ("kirggsource", "kIRG_GSource"), ("kirghsource", "kIRG_HSource"), + ("kirgjsource", "kIRG_JSource"), ("kirgkpsource", "kIRG_KPSource"), + ("kirgksource", "kIRG_KSource"), ("kirgmsource", "kIRG_MSource"), + ("kirgtsource", "kIRG_TSource"), ("kirgusource", "kIRG_USource"), + ("kirgvsource", "kIRG_VSource"), ("kothernumeric", "kOtherNumeric"), + ("kprimarynumeric", "kPrimaryNumeric"), ("krsunicode", "kRSUnicode"), + ("lb", "Line_Break"), ("lc", "Lowercase_Mapping"), + ("linebreak", "Line_Break"), ("loe", "Logical_Order_Exception"), + ("logicalorderexception", "Logical_Order_Exception"), + ("lower", "Lowercase"), ("lowercase", "Lowercase"), + ("lowercasemapping", "Lowercase_Mapping"), ("math", "Math"), ("na", "Name"), + ("na1", "Unicode_1_Name"), ("name", "Name"), ("namealias", "Name_Alias"), + ("nchar", "Noncharacter_Code_Point"), ("nfcqc", "NFC_Quick_Check"), + ("nfcquickcheck", "NFC_Quick_Check"), ("nfdqc", "NFD_Quick_Check"), + ("nfdquickcheck", "NFD_Quick_Check"), ("nfkccasefold", "NFKC_Casefold"), + ("nfkccf", "NFKC_Casefold"), ("nfkcqc", "NFKC_Quick_Check"), + ("nfkcquickcheck", "NFKC_Quick_Check"), ("nfkdqc", "NFKD_Quick_Check"), + ("nfkdquickcheck", "NFKD_Quick_Check"), + ("noncharactercodepoint", "Noncharacter_Code_Point"), + ("nt", "Numeric_Type"), ("numerictype", "Numeric_Type"), + ("numericvalue", "Numeric_Value"), ("nv", "Numeric_Value"), + ("oalpha", "Other_Alphabetic"), ("ocomment", "ISO_Comment"), + ("odi", "Other_Default_Ignorable_Code_Point"), + ("ogrext", "Other_Grapheme_Extend"), ("oidc", "Other_ID_Continue"), + ("oids", "Other_ID_Start"), ("olower", "Other_Lowercase"), + ("omath", "Other_Math"), ("otheralphabetic", "Other_Alphabetic"), + ("otherdefaultignorablecodepoint", "Other_Default_Ignorable_Code_Point"), + ("othergraphemeextend", "Other_Grapheme_Extend"), + ("otheridcontinue", "Other_ID_Continue"), + ("otheridstart", "Other_ID_Start"), ("otherlowercase", "Other_Lowercase"), + ("othermath", "Other_Math"), ("otheruppercase", "Other_Uppercase"), + ("oupper", "Other_Uppercase"), ("patsyn", "Pattern_Syntax"), + ("patternsyntax", "Pattern_Syntax"), + ("patternwhitespace", "Pattern_White_Space"), + ("patws", "Pattern_White_Space"), ("pcm", "Prepended_Concatenation_Mark"), + ("prependedconcatenationmark", "Prepended_Concatenation_Mark"), + ("qmark", "Quotation_Mark"), ("quotationmark", "Quotation_Mark"), + ("radical", "Radical"), ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), ("sb", "Sentence_Break"), ("sc", "Script"), + ("scf", "Simple_Case_Folding"), ("script", "Script"), + ("scriptextensions", "Script_Extensions"), ("scx", "Script_Extensions"), + ("sd", "Soft_Dotted"), ("sentencebreak", "Sentence_Break"), + ("sentenceterminal", "Sentence_Terminal"), ("sfc", "Simple_Case_Folding"), + ("simplecasefolding", "Simple_Case_Folding"), + ("simplelowercasemapping", "Simple_Lowercase_Mapping"), + ("simpletitlecasemapping", "Simple_Titlecase_Mapping"), + ("simpleuppercasemapping", "Simple_Uppercase_Mapping"), + ("slc", "Simple_Lowercase_Mapping"), ("softdotted", "Soft_Dotted"), + ("space", "White_Space"), ("stc", "Simple_Titlecase_Mapping"), + ("sterm", "Sentence_Terminal"), ("suc", "Simple_Uppercase_Mapping"), + ("tc", "Titlecase_Mapping"), ("term", "Terminal_Punctuation"), + ("terminalpunctuation", "Terminal_Punctuation"), + ("titlecasemapping", "Titlecase_Mapping"), ("uc", "Uppercase_Mapping"), + ("uideo", "Unified_Ideograph"), ("unicode1name", "Unicode_1_Name"), + ("unicoderadicalstroke", "kRSUnicode"), + ("unifiedideograph", "Unified_Ideograph"), ("upper", "Uppercase"), + ("uppercase", "Uppercase"), ("uppercasemapping", "Uppercase_Mapping"), + ("urs", "kRSUnicode"), ("variationselector", "Variation_Selector"), + ("verticalorientation", "Vertical_Orientation"), + ("vo", "Vertical_Orientation"), ("vs", "Variation_Selector"), + ("wb", "Word_Break"), ("whitespace", "White_Space"), + ("wordbreak", "Word_Break"), ("wspace", "White_Space"), + ("xidc", "XID_Continue"), ("xidcontinue", "XID_Continue"), + ("xids", "XID_Start"), ("xidstart", "XID_Start"), + ("xonfc", "Expands_On_NFC"), ("xonfd", "Expands_On_NFD"), + ("xonfkc", "Expands_On_NFKC"), ("xonfkd", "Expands_On_NFKD"), +]; diff --git a/ucd-util/src/unicode_tables/property_values.rs b/ucd-util/src/unicode_tables/property_values.rs new file mode 100644 index 000000000..83286d5b4 --- /dev/null +++ b/ucd-util/src/unicode_tables/property_values.rs @@ -0,0 +1,1122 @@ +// DO NOT EDIT THIS FILE. IT WAS AUTOMATICALLY GENERATED BY: +// +// ucd-generate property-values tmp/ucd-11.0.0/ +// +// ucd-generate is available on crates.io. + +pub const PROPERTY_VALUES: &'static [(&'static str, &'static [(&'static str, &'static str)])] = &[ + ("ASCII_Hex_Digit", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Age", &[("1.1", "V1_1"), ("10.0", "V10_0"), ("11.0", "V11_0"), + ("2.0", "V2_0"), ("2.1", "V2_1"), ("3.0", "V3_0"), ("3.1", "V3_1"), + ("3.2", "V3_2"), ("4.0", "V4_0"), ("4.1", "V4_1"), ("5.0", "V5_0"), + ("5.1", "V5_1"), ("5.2", "V5_2"), ("6.0", "V6_0"), ("6.1", "V6_1"), + ("6.2", "V6_2"), ("6.3", "V6_3"), ("7.0", "V7_0"), ("8.0", "V8_0"), + ("9.0", "V9_0"), ("na", "Unassigned"), ("unassigned", "Unassigned"), + ("v100", "V10_0"), ("v11", "V1_1"), ("v110", "V11_0"), ("v20", "V2_0"), + ("v21", "V2_1"), ("v30", "V3_0"), ("v31", "V3_1"), ("v32", "V3_2"), + ("v40", "V4_0"), ("v41", "V4_1"), ("v50", "V5_0"), ("v51", "V5_1"), + ("v52", "V5_2"), ("v60", "V6_0"), ("v61", "V6_1"), ("v62", "V6_2"), + ("v63", "V6_3"), ("v70", "V7_0"), ("v80", "V8_0"), ("v90", "V9_0"), ]), + + ("Alphabetic", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Bidi_Class", &[("al", "Arabic_Letter"), ("an", "Arabic_Number"), + ("arabicletter", "Arabic_Letter"), ("arabicnumber", "Arabic_Number"), + ("b", "Paragraph_Separator"), ("bn", "Boundary_Neutral"), + ("boundaryneutral", "Boundary_Neutral"), + ("commonseparator", "Common_Separator"), ("cs", "Common_Separator"), + ("en", "European_Number"), ("es", "European_Separator"), + ("et", "European_Terminator"), ("europeannumber", "European_Number"), + ("europeanseparator", "European_Separator"), + ("europeanterminator", "European_Terminator"), + ("firststrongisolate", "First_Strong_Isolate"), + ("fsi", "First_Strong_Isolate"), ("l", "Left_To_Right"), + ("lefttoright", "Left_To_Right"), + ("lefttorightembedding", "Left_To_Right_Embedding"), + ("lefttorightisolate", "Left_To_Right_Isolate"), + ("lefttorightoverride", "Left_To_Right_Override"), + ("lre", "Left_To_Right_Embedding"), ("lri", "Left_To_Right_Isolate"), + ("lro", "Left_To_Right_Override"), ("nonspacingmark", "Nonspacing_Mark"), + ("nsm", "Nonspacing_Mark"), ("on", "Other_Neutral"), + ("otherneutral", "Other_Neutral"), + ("paragraphseparator", "Paragraph_Separator"), + ("pdf", "Pop_Directional_Format"), ("pdi", "Pop_Directional_Isolate"), + ("popdirectionalformat", "Pop_Directional_Format"), + ("popdirectionalisolate", "Pop_Directional_Isolate"), + ("r", "Right_To_Left"), ("righttoleft", "Right_To_Left"), + ("righttoleftembedding", "Right_To_Left_Embedding"), + ("righttoleftisolate", "Right_To_Left_Isolate"), + ("righttoleftoverride", "Right_To_Left_Override"), + ("rle", "Right_To_Left_Embedding"), ("rli", "Right_To_Left_Isolate"), + ("rlo", "Right_To_Left_Override"), ("s", "Segment_Separator"), + ("segmentseparator", "Segment_Separator"), ("whitespace", "White_Space"), + ("ws", "White_Space"), ]), + + ("Bidi_Control", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Bidi_Mirrored", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Bidi_Paired_Bracket_Type", &[("c", "Close"), ("close", "Close"), + ("n", "None"), ("none", "None"), ("o", "Open"), ("open", "Open"), ]), + + ("Block", &[("adlam", "Adlam"), ("aegeannumbers", "Aegean_Numbers"), + ("ahom", "Ahom"), ("alchemical", "Alchemical_Symbols"), + ("alchemicalsymbols", "Alchemical_Symbols"), + ("alphabeticpf", "Alphabetic_Presentation_Forms"), + ("alphabeticpresentationforms", "Alphabetic_Presentation_Forms"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), + ("ancientgreekmusic", "Ancient_Greek_Musical_Notation"), + ("ancientgreekmusicalnotation", "Ancient_Greek_Musical_Notation"), + ("ancientgreeknumbers", "Ancient_Greek_Numbers"), + ("ancientsymbols", "Ancient_Symbols"), ("arabic", "Arabic"), + ("arabicexta", "Arabic_Extended_A"), + ("arabicextendeda", "Arabic_Extended_A"), + ("arabicmath", "Arabic_Mathematical_Alphabetic_Symbols"), + ("arabicmathematicalalphabeticsymbols", "Arabic_Mathematical_Alphabetic_Symbols"), + ("arabicpfa", "Arabic_Presentation_Forms_A"), + ("arabicpfb", "Arabic_Presentation_Forms_B"), + ("arabicpresentationformsa", "Arabic_Presentation_Forms_A"), + ("arabicpresentationformsb", "Arabic_Presentation_Forms_B"), + ("arabicsup", "Arabic_Supplement"), + ("arabicsupplement", "Arabic_Supplement"), ("armenian", "Armenian"), + ("arrows", "Arrows"), ("ascii", "Basic_Latin"), ("avestan", "Avestan"), + ("balinese", "Balinese"), ("bamum", "Bamum"), + ("bamumsup", "Bamum_Supplement"), ("bamumsupplement", "Bamum_Supplement"), + ("basiclatin", "Basic_Latin"), ("bassavah", "Bassa_Vah"), + ("batak", "Batak"), ("bengali", "Bengali"), ("bhaiksuki", "Bhaiksuki"), + ("blockelements", "Block_Elements"), ("bopomofo", "Bopomofo"), + ("bopomofoext", "Bopomofo_Extended"), + ("bopomofoextended", "Bopomofo_Extended"), ("boxdrawing", "Box_Drawing"), + ("brahmi", "Brahmi"), ("braille", "Braille_Patterns"), + ("braillepatterns", "Braille_Patterns"), ("buginese", "Buginese"), + ("buhid", "Buhid"), ("byzantinemusic", "Byzantine_Musical_Symbols"), + ("byzantinemusicalsymbols", "Byzantine_Musical_Symbols"), + ("canadiansyllabics", "Unified_Canadian_Aboriginal_Syllabics"), + ("carian", "Carian"), ("caucasianalbanian", "Caucasian_Albanian"), + ("chakma", "Chakma"), ("cham", "Cham"), ("cherokee", "Cherokee"), + ("cherokeesup", "Cherokee_Supplement"), + ("cherokeesupplement", "Cherokee_Supplement"), + ("chesssymbols", "Chess_Symbols"), ("cjk", "CJK_Unified_Ideographs"), + ("cjkcompat", "CJK_Compatibility"), + ("cjkcompatforms", "CJK_Compatibility_Forms"), + ("cjkcompatibility", "CJK_Compatibility"), + ("cjkcompatibilityforms", "CJK_Compatibility_Forms"), + ("cjkcompatibilityideographs", "CJK_Compatibility_Ideographs"), + ("cjkcompatibilityideographssupplement", "CJK_Compatibility_Ideographs_Supplement"), + ("cjkcompatideographs", "CJK_Compatibility_Ideographs"), + ("cjkcompatideographssup", "CJK_Compatibility_Ideographs_Supplement"), + ("cjkexta", "CJK_Unified_Ideographs_Extension_A"), + ("cjkextb", "CJK_Unified_Ideographs_Extension_B"), + ("cjkextc", "CJK_Unified_Ideographs_Extension_C"), + ("cjkextd", "CJK_Unified_Ideographs_Extension_D"), + ("cjkexte", "CJK_Unified_Ideographs_Extension_E"), + ("cjkextf", "CJK_Unified_Ideographs_Extension_F"), + ("cjkradicalssup", "CJK_Radicals_Supplement"), + ("cjkradicalssupplement", "CJK_Radicals_Supplement"), + ("cjkstrokes", "CJK_Strokes"), + ("cjksymbols", "CJK_Symbols_And_Punctuation"), + ("cjksymbolsandpunctuation", "CJK_Symbols_And_Punctuation"), + ("cjkunifiedideographs", "CJK_Unified_Ideographs"), + ("cjkunifiedideographsextensiona", "CJK_Unified_Ideographs_Extension_A"), + ("cjkunifiedideographsextensionb", "CJK_Unified_Ideographs_Extension_B"), + ("cjkunifiedideographsextensionc", "CJK_Unified_Ideographs_Extension_C"), + ("cjkunifiedideographsextensiond", "CJK_Unified_Ideographs_Extension_D"), + ("cjkunifiedideographsextensione", "CJK_Unified_Ideographs_Extension_E"), + ("cjkunifiedideographsextensionf", "CJK_Unified_Ideographs_Extension_F"), + ("combiningdiacriticalmarks", "Combining_Diacritical_Marks"), + ("combiningdiacriticalmarksextended", "Combining_Diacritical_Marks_Extended"), + ("combiningdiacriticalmarksforsymbols", "Combining_Diacritical_Marks_For_Symbols"), + ("combiningdiacriticalmarkssupplement", "Combining_Diacritical_Marks_Supplement"), + ("combininghalfmarks", "Combining_Half_Marks"), + ("combiningmarksforsymbols", "Combining_Diacritical_Marks_For_Symbols"), + ("commonindicnumberforms", "Common_Indic_Number_Forms"), + ("compatjamo", "Hangul_Compatibility_Jamo"), + ("controlpictures", "Control_Pictures"), ("coptic", "Coptic"), + ("copticepactnumbers", "Coptic_Epact_Numbers"), + ("countingrod", "Counting_Rod_Numerals"), + ("countingrodnumerals", "Counting_Rod_Numerals"), + ("cuneiform", "Cuneiform"), + ("cuneiformnumbers", "Cuneiform_Numbers_And_Punctuation"), + ("cuneiformnumbersandpunctuation", "Cuneiform_Numbers_And_Punctuation"), + ("currencysymbols", "Currency_Symbols"), + ("cypriotsyllabary", "Cypriot_Syllabary"), ("cyrillic", "Cyrillic"), + ("cyrillicexta", "Cyrillic_Extended_A"), + ("cyrillicextb", "Cyrillic_Extended_B"), + ("cyrillicextc", "Cyrillic_Extended_C"), + ("cyrillicextendeda", "Cyrillic_Extended_A"), + ("cyrillicextendedb", "Cyrillic_Extended_B"), + ("cyrillicextendedc", "Cyrillic_Extended_C"), + ("cyrillicsup", "Cyrillic_Supplement"), + ("cyrillicsupplement", "Cyrillic_Supplement"), + ("cyrillicsupplementary", "Cyrillic_Supplement"), ("deseret", "Deseret"), + ("devanagari", "Devanagari"), ("devanagariext", "Devanagari_Extended"), + ("devanagariextended", "Devanagari_Extended"), + ("diacriticals", "Combining_Diacritical_Marks"), + ("diacriticalsext", "Combining_Diacritical_Marks_Extended"), + ("diacriticalsforsymbols", "Combining_Diacritical_Marks_For_Symbols"), + ("diacriticalssup", "Combining_Diacritical_Marks_Supplement"), + ("dingbats", "Dingbats"), ("dogra", "Dogra"), ("domino", "Domino_Tiles"), + ("dominotiles", "Domino_Tiles"), ("duployan", "Duployan"), + ("earlydynasticcuneiform", "Early_Dynastic_Cuneiform"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), ("elbasan", "Elbasan"), + ("emoticons", "Emoticons"), ("enclosedalphanum", "Enclosed_Alphanumerics"), + ("enclosedalphanumerics", "Enclosed_Alphanumerics"), + ("enclosedalphanumericsupplement", "Enclosed_Alphanumeric_Supplement"), + ("enclosedalphanumsup", "Enclosed_Alphanumeric_Supplement"), + ("enclosedcjk", "Enclosed_CJK_Letters_And_Months"), + ("enclosedcjklettersandmonths", "Enclosed_CJK_Letters_And_Months"), + ("enclosedideographicsup", "Enclosed_Ideographic_Supplement"), + ("enclosedideographicsupplement", "Enclosed_Ideographic_Supplement"), + ("ethiopic", "Ethiopic"), ("ethiopicext", "Ethiopic_Extended"), + ("ethiopicexta", "Ethiopic_Extended_A"), + ("ethiopicextended", "Ethiopic_Extended"), + ("ethiopicextendeda", "Ethiopic_Extended_A"), + ("ethiopicsup", "Ethiopic_Supplement"), + ("ethiopicsupplement", "Ethiopic_Supplement"), + ("generalpunctuation", "General_Punctuation"), + ("geometricshapes", "Geometric_Shapes"), + ("geometricshapesext", "Geometric_Shapes_Extended"), + ("geometricshapesextended", "Geometric_Shapes_Extended"), + ("georgian", "Georgian"), ("georgianext", "Georgian_Extended"), + ("georgianextended", "Georgian_Extended"), + ("georgiansup", "Georgian_Supplement"), + ("georgiansupplement", "Georgian_Supplement"), ("glagolitic", "Glagolitic"), + ("glagoliticsup", "Glagolitic_Supplement"), + ("glagoliticsupplement", "Glagolitic_Supplement"), ("gothic", "Gothic"), + ("grantha", "Grantha"), ("greek", "Greek_And_Coptic"), + ("greekandcoptic", "Greek_And_Coptic"), ("greekext", "Greek_Extended"), + ("greekextended", "Greek_Extended"), ("gujarati", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), ("gurmukhi", "Gurmukhi"), + ("halfandfullforms", "Halfwidth_And_Fullwidth_Forms"), + ("halfmarks", "Combining_Half_Marks"), + ("halfwidthandfullwidthforms", "Halfwidth_And_Fullwidth_Forms"), + ("hangul", "Hangul_Syllables"), + ("hangulcompatibilityjamo", "Hangul_Compatibility_Jamo"), + ("hanguljamo", "Hangul_Jamo"), + ("hanguljamoextendeda", "Hangul_Jamo_Extended_A"), + ("hanguljamoextendedb", "Hangul_Jamo_Extended_B"), + ("hangulsyllables", "Hangul_Syllables"), + ("hanifirohingya", "Hanifi_Rohingya"), ("hanunoo", "Hanunoo"), + ("hatran", "Hatran"), ("hebrew", "Hebrew"), + ("highprivateusesurrogates", "High_Private_Use_Surrogates"), + ("highpusurrogates", "High_Private_Use_Surrogates"), + ("highsurrogates", "High_Surrogates"), ("hiragana", "Hiragana"), + ("idc", "Ideographic_Description_Characters"), + ("ideographicdescriptioncharacters", "Ideographic_Description_Characters"), + ("ideographicsymbols", "Ideographic_Symbols_And_Punctuation"), + ("ideographicsymbolsandpunctuation", "Ideographic_Symbols_And_Punctuation"), + ("imperialaramaic", "Imperial_Aramaic"), + ("indicnumberforms", "Common_Indic_Number_Forms"), + ("indicsiyaqnumbers", "Indic_Siyaq_Numbers"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), + ("ipaext", "IPA_Extensions"), ("ipaextensions", "IPA_Extensions"), + ("jamo", "Hangul_Jamo"), ("jamoexta", "Hangul_Jamo_Extended_A"), + ("jamoextb", "Hangul_Jamo_Extended_B"), ("javanese", "Javanese"), + ("kaithi", "Kaithi"), ("kanaexta", "Kana_Extended_A"), + ("kanaextendeda", "Kana_Extended_A"), ("kanasup", "Kana_Supplement"), + ("kanasupplement", "Kana_Supplement"), ("kanbun", "Kanbun"), + ("kangxi", "Kangxi_Radicals"), ("kangxiradicals", "Kangxi_Radicals"), + ("kannada", "Kannada"), ("katakana", "Katakana"), + ("katakanaext", "Katakana_Phonetic_Extensions"), + ("katakanaphoneticextensions", "Katakana_Phonetic_Extensions"), + ("kayahli", "Kayah_Li"), ("kharoshthi", "Kharoshthi"), ("khmer", "Khmer"), + ("khmersymbols", "Khmer_Symbols"), ("khojki", "Khojki"), + ("khudawadi", "Khudawadi"), ("lao", "Lao"), + ("latin1", "Latin_1_Supplement"), ("latin1sup", "Latin_1_Supplement"), + ("latin1supplement", "Latin_1_Supplement"), + ("latinexta", "Latin_Extended_A"), + ("latinextadditional", "Latin_Extended_Additional"), + ("latinextb", "Latin_Extended_B"), ("latinextc", "Latin_Extended_C"), + ("latinextd", "Latin_Extended_D"), ("latinexte", "Latin_Extended_E"), + ("latinextendeda", "Latin_Extended_A"), + ("latinextendedadditional", "Latin_Extended_Additional"), + ("latinextendedb", "Latin_Extended_B"), + ("latinextendedc", "Latin_Extended_C"), + ("latinextendedd", "Latin_Extended_D"), + ("latinextendede", "Latin_Extended_E"), ("lepcha", "Lepcha"), + ("letterlikesymbols", "Letterlike_Symbols"), ("limbu", "Limbu"), + ("lineara", "Linear_A"), ("linearbideograms", "Linear_B_Ideograms"), + ("linearbsyllabary", "Linear_B_Syllabary"), ("lisu", "Lisu"), + ("lowsurrogates", "Low_Surrogates"), ("lycian", "Lycian"), + ("lydian", "Lydian"), ("mahajani", "Mahajani"), + ("mahjong", "Mahjong_Tiles"), ("mahjongtiles", "Mahjong_Tiles"), + ("makasar", "Makasar"), ("malayalam", "Malayalam"), ("mandaic", "Mandaic"), + ("manichaean", "Manichaean"), ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), + ("mathalphanum", "Mathematical_Alphanumeric_Symbols"), + ("mathematicalalphanumericsymbols", "Mathematical_Alphanumeric_Symbols"), + ("mathematicaloperators", "Mathematical_Operators"), + ("mathoperators", "Mathematical_Operators"), + ("mayannumerals", "Mayan_Numerals"), ("medefaidrin", "Medefaidrin"), + ("meeteimayek", "Meetei_Mayek"), + ("meeteimayekext", "Meetei_Mayek_Extensions"), + ("meeteimayekextensions", "Meetei_Mayek_Extensions"), + ("mendekikakui", "Mende_Kikakui"), ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), ("miao", "Miao"), + ("miscarrows", "Miscellaneous_Symbols_And_Arrows"), + ("miscellaneousmathematicalsymbolsa", "Miscellaneous_Mathematical_Symbols_A"), + ("miscellaneousmathematicalsymbolsb", "Miscellaneous_Mathematical_Symbols_B"), + ("miscellaneoussymbols", "Miscellaneous_Symbols"), + ("miscellaneoussymbolsandarrows", "Miscellaneous_Symbols_And_Arrows"), + ("miscellaneoussymbolsandpictographs", "Miscellaneous_Symbols_And_Pictographs"), + ("miscellaneoustechnical", "Miscellaneous_Technical"), + ("miscmathsymbolsa", "Miscellaneous_Mathematical_Symbols_A"), + ("miscmathsymbolsb", "Miscellaneous_Mathematical_Symbols_B"), + ("miscpictographs", "Miscellaneous_Symbols_And_Pictographs"), + ("miscsymbols", "Miscellaneous_Symbols"), + ("misctechnical", "Miscellaneous_Technical"), ("modi", "Modi"), + ("modifierletters", "Spacing_Modifier_Letters"), + ("modifiertoneletters", "Modifier_Tone_Letters"), + ("mongolian", "Mongolian"), ("mongoliansup", "Mongolian_Supplement"), + ("mongoliansupplement", "Mongolian_Supplement"), ("mro", "Mro"), + ("multani", "Multani"), ("music", "Musical_Symbols"), + ("musicalsymbols", "Musical_Symbols"), ("myanmar", "Myanmar"), + ("myanmarexta", "Myanmar_Extended_A"), + ("myanmarextb", "Myanmar_Extended_B"), + ("myanmarextendeda", "Myanmar_Extended_A"), + ("myanmarextendedb", "Myanmar_Extended_B"), ("nabataean", "Nabataean"), + ("nb", "No_Block"), ("newa", "Newa"), ("newtailue", "New_Tai_Lue"), + ("nko", "NKo"), ("noblock", "No_Block"), ("numberforms", "Number_Forms"), + ("nushu", "Nushu"), ("ocr", "Optical_Character_Recognition"), + ("ogham", "Ogham"), ("olchiki", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), ("oldturkic", "Old_Turkic"), + ("opticalcharacterrecognition", "Optical_Character_Recognition"), + ("oriya", "Oriya"), ("ornamentaldingbats", "Ornamental_Dingbats"), + ("osage", "Osage"), ("osmanya", "Osmanya"), ("pahawhhmong", "Pahawh_Hmong"), + ("palmyrene", "Palmyrene"), ("paucinhau", "Pau_Cin_Hau"), + ("phagspa", "Phags_Pa"), ("phaistos", "Phaistos_Disc"), + ("phaistosdisc", "Phaistos_Disc"), ("phoenician", "Phoenician"), + ("phoneticext", "Phonetic_Extensions"), + ("phoneticextensions", "Phonetic_Extensions"), + ("phoneticextensionssupplement", "Phonetic_Extensions_Supplement"), + ("phoneticextsup", "Phonetic_Extensions_Supplement"), + ("playingcards", "Playing_Cards"), ("privateuse", "Private_Use_Area"), + ("privateusearea", "Private_Use_Area"), + ("psalterpahlavi", "Psalter_Pahlavi"), ("pua", "Private_Use_Area"), + ("punctuation", "General_Punctuation"), ("rejang", "Rejang"), + ("rumi", "Rumi_Numeral_Symbols"), + ("ruminumeralsymbols", "Rumi_Numeral_Symbols"), ("runic", "Runic"), + ("samaritan", "Samaritan"), ("saurashtra", "Saurashtra"), + ("sharada", "Sharada"), ("shavian", "Shavian"), + ("shorthandformatcontrols", "Shorthand_Format_Controls"), + ("siddham", "Siddham"), ("sinhala", "Sinhala"), + ("sinhalaarchaicnumbers", "Sinhala_Archaic_Numbers"), + ("smallforms", "Small_Form_Variants"), + ("smallformvariants", "Small_Form_Variants"), ("sogdian", "Sogdian"), + ("sorasompeng", "Sora_Sompeng"), ("soyombo", "Soyombo"), + ("spacingmodifierletters", "Spacing_Modifier_Letters"), + ("specials", "Specials"), ("sundanese", "Sundanese"), + ("sundanesesup", "Sundanese_Supplement"), + ("sundanesesupplement", "Sundanese_Supplement"), + ("suparrowsa", "Supplemental_Arrows_A"), + ("suparrowsb", "Supplemental_Arrows_B"), + ("suparrowsc", "Supplemental_Arrows_C"), + ("superandsub", "Superscripts_And_Subscripts"), + ("superscriptsandsubscripts", "Superscripts_And_Subscripts"), + ("supmathoperators", "Supplemental_Mathematical_Operators"), + ("supplementalarrowsa", "Supplemental_Arrows_A"), + ("supplementalarrowsb", "Supplemental_Arrows_B"), + ("supplementalarrowsc", "Supplemental_Arrows_C"), + ("supplementalmathematicaloperators", "Supplemental_Mathematical_Operators"), + ("supplementalpunctuation", "Supplemental_Punctuation"), + ("supplementalsymbolsandpictographs", "Supplemental_Symbols_And_Pictographs"), + ("supplementaryprivateuseareaa", "Supplementary_Private_Use_Area_A"), + ("supplementaryprivateuseareab", "Supplementary_Private_Use_Area_B"), + ("suppuaa", "Supplementary_Private_Use_Area_A"), + ("suppuab", "Supplementary_Private_Use_Area_B"), + ("suppunctuation", "Supplemental_Punctuation"), + ("supsymbolsandpictographs", "Supplemental_Symbols_And_Pictographs"), + ("suttonsignwriting", "Sutton_SignWriting"), + ("sylotinagri", "Syloti_Nagri"), ("syriac", "Syriac"), + ("syriacsup", "Syriac_Supplement"), + ("syriacsupplement", "Syriac_Supplement"), ("tagalog", "Tagalog"), + ("tagbanwa", "Tagbanwa"), ("tags", "Tags"), ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), ("taiviet", "Tai_Viet"), + ("taixuanjing", "Tai_Xuan_Jing_Symbols"), + ("taixuanjingsymbols", "Tai_Xuan_Jing_Symbols"), ("takri", "Takri"), + ("tamil", "Tamil"), ("tangut", "Tangut"), + ("tangutcomponents", "Tangut_Components"), ("telugu", "Telugu"), + ("thaana", "Thaana"), ("thai", "Thai"), ("tibetan", "Tibetan"), + ("tifinagh", "Tifinagh"), ("tirhuta", "Tirhuta"), + ("transportandmap", "Transport_And_Map_Symbols"), + ("transportandmapsymbols", "Transport_And_Map_Symbols"), + ("ucas", "Unified_Canadian_Aboriginal_Syllabics"), + ("ucasext", "Unified_Canadian_Aboriginal_Syllabics_Extended"), + ("ugaritic", "Ugaritic"), + ("unifiedcanadianaboriginalsyllabics", "Unified_Canadian_Aboriginal_Syllabics"), + ("unifiedcanadianaboriginalsyllabicsextended", "Unified_Canadian_Aboriginal_Syllabics_Extended"), + ("vai", "Vai"), ("variationselectors", "Variation_Selectors"), + ("variationselectorssupplement", "Variation_Selectors_Supplement"), + ("vedicext", "Vedic_Extensions"), ("vedicextensions", "Vedic_Extensions"), + ("verticalforms", "Vertical_Forms"), ("vs", "Variation_Selectors"), + ("vssup", "Variation_Selectors_Supplement"), ("warangciti", "Warang_Citi"), + ("yijing", "Yijing_Hexagram_Symbols"), + ("yijinghexagramsymbols", "Yijing_Hexagram_Symbols"), + ("yiradicals", "Yi_Radicals"), ("yisyllables", "Yi_Syllables"), + ("zanabazarsquare", "Zanabazar_Square"), ]), + + ("Canonical_Combining_Class", &[("", "Iota_Subscript"), + ("0", "Not_Reordered"), ("1", "Overlay"), ("10", "CCC10"), + ("103", "CCC103"), ("107", "CCC107"), ("11", "CCC11"), ("118", "CCC118"), + ("12", "CCC12"), ("122", "CCC122"), ("129", "CCC129"), ("13", "CCC13"), + ("130", "CCC130"), ("132", "CCC132"), ("133", "CCC133"), ("14", "CCC14"), + ("15", "CCC15"), ("16", "CCC16"), ("17", "CCC17"), ("18", "CCC18"), + ("19", "CCC19"), ("20", "CCC20"), ("200", "Attached_Below_Left"), + ("202", "Attached_Below"), ("21", "CCC21"), ("214", "Attached_Above"), + ("216", "Attached_Above_Right"), ("218", "Below_Left"), ("22", "CCC22"), + ("220", "Below"), ("222", "Below_Right"), ("224", "Left"), ("226", "Right"), + ("228", "Above_Left"), ("23", "CCC23"), ("230", "Above"), + ("232", "Above_Right"), ("233", "Double_Below"), ("234", "Double_Above"), + ("24", "CCC24"), ("240", "Iota_Subscript"), ("25", "CCC25"), + ("26", "CCC26"), ("27", "CCC27"), ("28", "CCC28"), ("29", "CCC29"), + ("30", "CCC30"), ("31", "CCC31"), ("32", "CCC32"), ("33", "CCC33"), + ("34", "CCC34"), ("35", "CCC35"), ("36", "CCC36"), ("7", "Nukta"), + ("8", "Kana_Voicing"), ("84", "CCC84"), ("9", "Virama"), ("91", "CCC91"), + ("a", "Above"), ("above", "Above"), ("aboveleft", "Above_Left"), + ("aboveright", "Above_Right"), ("al", "Above_Left"), ("ar", "Above_Right"), + ("ata", "Attached_Above"), ("atar", "Attached_Above_Right"), + ("atb", "Attached_Below"), ("atbl", "Attached_Below_Left"), + ("attachedabove", "Attached_Above"), + ("attachedaboveright", "Attached_Above_Right"), + ("attachedbelow", "Attached_Below"), + ("attachedbelowleft", "Attached_Below_Left"), ("b", "Below"), + ("below", "Below"), ("belowleft", "Below_Left"), + ("belowright", "Below_Right"), ("bl", "Below_Left"), ("br", "Below_Right"), + ("ccc10", "CCC10"), ("ccc103", "CCC103"), ("ccc107", "CCC107"), + ("ccc11", "CCC11"), ("ccc118", "CCC118"), ("ccc12", "CCC12"), + ("ccc122", "CCC122"), ("ccc129", "CCC129"), ("ccc13", "CCC13"), + ("ccc130", "CCC130"), ("ccc132", "CCC132"), ("ccc133", "CCC133"), + ("ccc14", "CCC14"), ("ccc15", "CCC15"), ("ccc16", "CCC16"), + ("ccc17", "CCC17"), ("ccc18", "CCC18"), ("ccc19", "CCC19"), + ("ccc20", "CCC20"), ("ccc21", "CCC21"), ("ccc22", "CCC22"), + ("ccc23", "CCC23"), ("ccc24", "CCC24"), ("ccc25", "CCC25"), + ("ccc26", "CCC26"), ("ccc27", "CCC27"), ("ccc28", "CCC28"), + ("ccc29", "CCC29"), ("ccc30", "CCC30"), ("ccc31", "CCC31"), + ("ccc32", "CCC32"), ("ccc33", "CCC33"), ("ccc34", "CCC34"), + ("ccc35", "CCC35"), ("ccc36", "CCC36"), ("ccc84", "CCC84"), + ("ccc91", "CCC91"), ("da", "Double_Above"), ("db", "Double_Below"), + ("doubleabove", "Double_Above"), ("doublebelow", "Double_Below"), + ("iotasubscript", "Iota_Subscript"), ("kanavoicing", "Kana_Voicing"), + ("kv", "Kana_Voicing"), ("l", "Left"), ("left", "Left"), ("nk", "Nukta"), + ("notreordered", "Not_Reordered"), ("nr", "Not_Reordered"), + ("nukta", "Nukta"), ("ov", "Overlay"), ("overlay", "Overlay"), + ("r", "Right"), ("right", "Right"), ("virama", "Virama"), ("vr", "Virama"), + ]), + + ("Case_Ignorable", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Cased", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Changes_When_Casefolded", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Changes_When_Casemapped", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Changes_When_Lowercased", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Changes_When_NFKC_Casefolded", &[("f", "No"), ("false", "No"), + ("n", "No"), ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("Changes_When_Titlecased", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Changes_When_Uppercased", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Composition_Exclusion", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Dash", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Decomposition_Type", &[("can", "Canonical"), ("canonical", "Canonical"), + ("circle", "Circle"), ("com", "Compat"), ("compat", "Compat"), + ("enc", "Circle"), ("fin", "Final"), ("final", "Final"), ("font", "Font"), + ("fra", "Fraction"), ("fraction", "Fraction"), ("init", "Initial"), + ("initial", "Initial"), ("med", "Medial"), ("medial", "Medial"), + ("nar", "Narrow"), ("narrow", "Narrow"), ("nb", "Nobreak"), + ("nobreak", "Nobreak"), ("none", "None"), ("o", "Isolated"), + ("olated", "Isolated"), ("small", "Small"), ("sml", "Small"), + ("sqr", "Square"), ("square", "Square"), ("sub", "Sub"), ("sup", "Super"), + ("super", "Super"), ("vert", "Vertical"), ("vertical", "Vertical"), + ("wide", "Wide"), ]), + + ("Default_Ignorable_Code_Point", &[("f", "No"), ("false", "No"), + ("n", "No"), ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("Deprecated", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Diacritic", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("East_Asian_Width", &[("a", "Ambiguous"), ("ambiguous", "Ambiguous"), + ("f", "Fullwidth"), ("fullwidth", "Fullwidth"), ("h", "Halfwidth"), + ("halfwidth", "Halfwidth"), ("n", "Neutral"), ("na", "Narrow"), + ("narrow", "Narrow"), ("neutral", "Neutral"), ("w", "Wide"), + ("wide", "Wide"), ]), + + ("Expands_On_NFC", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Expands_On_NFD", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Expands_On_NFKC", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Expands_On_NFKD", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Extender", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Full_Composition_Exclusion", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("General_Category", &[("c", "Other"), ("casedletter", "Cased_Letter"), + ("cc", "Control"), ("cf", "Format"), + ("closepunctuation", "Close_Punctuation"), ("cn", "Unassigned"), + ("cntrl", "Control"), ("co", "Private_Use"), ("combiningmark", "Mark"), + ("connectorpunctuation", "Connector_Punctuation"), ("control", "Control"), + ("cs", "Surrogate"), ("currencysymbol", "Currency_Symbol"), + ("dashpunctuation", "Dash_Punctuation"), + ("decimalnumber", "Decimal_Number"), ("digit", "Decimal_Number"), + ("enclosingmark", "Enclosing_Mark"), + ("finalpunctuation", "Final_Punctuation"), ("format", "Format"), + ("initialpunctuation", "Initial_Punctuation"), ("l", "Letter"), + ("lc", "Cased_Letter"), ("letter", "Letter"), + ("letternumber", "Letter_Number"), ("lineseparator", "Line_Separator"), + ("ll", "Lowercase_Letter"), ("lm", "Modifier_Letter"), + ("lo", "Other_Letter"), ("lowercaseletter", "Lowercase_Letter"), + ("lt", "Titlecase_Letter"), ("lu", "Uppercase_Letter"), ("m", "Mark"), + ("mark", "Mark"), ("mathsymbol", "Math_Symbol"), ("mc", "Spacing_Mark"), + ("me", "Enclosing_Mark"), ("mn", "Nonspacing_Mark"), + ("modifierletter", "Modifier_Letter"), + ("modifiersymbol", "Modifier_Symbol"), ("n", "Number"), + ("nd", "Decimal_Number"), ("nl", "Letter_Number"), ("no", "Other_Number"), + ("nonspacingmark", "Nonspacing_Mark"), ("number", "Number"), + ("openpunctuation", "Open_Punctuation"), ("other", "Other"), + ("otherletter", "Other_Letter"), ("othernumber", "Other_Number"), + ("otherpunctuation", "Other_Punctuation"), ("othersymbol", "Other_Symbol"), + ("p", "Punctuation"), ("paragraphseparator", "Paragraph_Separator"), + ("pc", "Connector_Punctuation"), ("pd", "Dash_Punctuation"), + ("pe", "Close_Punctuation"), ("pf", "Final_Punctuation"), + ("pi", "Initial_Punctuation"), ("po", "Other_Punctuation"), + ("privateuse", "Private_Use"), ("ps", "Open_Punctuation"), + ("punct", "Punctuation"), ("punctuation", "Punctuation"), ("s", "Symbol"), + ("sc", "Currency_Symbol"), ("separator", "Separator"), + ("sk", "Modifier_Symbol"), ("sm", "Math_Symbol"), ("so", "Other_Symbol"), + ("spaceseparator", "Space_Separator"), ("spacingmark", "Spacing_Mark"), + ("surrogate", "Surrogate"), ("symbol", "Symbol"), + ("titlecaseletter", "Titlecase_Letter"), ("unassigned", "Unassigned"), + ("uppercaseletter", "Uppercase_Letter"), ("z", "Separator"), + ("zl", "Line_Separator"), ("zp", "Paragraph_Separator"), + ("zs", "Space_Separator"), ]), + + ("Grapheme_Base", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Grapheme_Cluster_Break", &[("cn", "Control"), ("control", "Control"), + ("cr", "CR"), ("eb", "E_Base"), ("ebase", "E_Base"), + ("ebasegaz", "E_Base_GAZ"), ("ebg", "E_Base_GAZ"), ("em", "E_Modifier"), + ("emodifier", "E_Modifier"), ("ex", "Extend"), ("extend", "Extend"), + ("gaz", "Glue_After_Zwj"), ("glueafterzwj", "Glue_After_Zwj"), ("l", "L"), + ("lf", "LF"), ("lv", "LV"), ("lvt", "LVT"), ("other", "Other"), + ("pp", "Prepend"), ("prepend", "Prepend"), + ("regionalindicator", "Regional_Indicator"), ("ri", "Regional_Indicator"), + ("sm", "SpacingMark"), ("spacingmark", "SpacingMark"), ("t", "T"), + ("v", "V"), ("xx", "Other"), ("zwj", "ZWJ"), ]), + + ("Grapheme_Extend", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Grapheme_Link", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Hangul_Syllable_Type", &[("l", "Leading_Jamo"), + ("leadingjamo", "Leading_Jamo"), ("lv", "LV_Syllable"), + ("lvsyllable", "LV_Syllable"), ("lvt", "LVT_Syllable"), + ("lvtsyllable", "LVT_Syllable"), ("na", "Not_Applicable"), + ("notapplicable", "Not_Applicable"), ("t", "Trailing_Jamo"), + ("trailingjamo", "Trailing_Jamo"), ("v", "Vowel_Jamo"), + ("voweljamo", "Vowel_Jamo"), ]), + + ("Hex_Digit", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Hyphen", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("IDS_Binary_Operator", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("IDS_Trinary_Operator", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("ID_Continue", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("ID_Start", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Ideographic", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Indic_Positional_Category", &[("bottom", "Bottom"), + ("bottomandleft", "Bottom_And_Left"), + ("bottomandright", "Bottom_And_Right"), ("left", "Left"), + ("leftandright", "Left_And_Right"), ("na", "NA"), + ("overstruck", "Overstruck"), ("right", "Right"), ("top", "Top"), + ("topandbottom", "Top_And_Bottom"), + ("topandbottomandright", "Top_And_Bottom_And_Right"), + ("topandleft", "Top_And_Left"), + ("topandleftandright", "Top_And_Left_And_Right"), + ("topandright", "Top_And_Right"), ("visualorderleft", "Visual_Order_Left"), + ]), + + ("Indic_Syllabic_Category", &[("avagraha", "Avagraha"), ("bindu", "Bindu"), + ("brahmijoiningnumber", "Brahmi_Joining_Number"), + ("cantillationmark", "Cantillation_Mark"), ("consonant", "Consonant"), + ("consonantdead", "Consonant_Dead"), ("consonantfinal", "Consonant_Final"), + ("consonantheadletter", "Consonant_Head_Letter"), + ("consonantinitialpostfixed", "Consonant_Initial_Postfixed"), + ("consonantkiller", "Consonant_Killer"), + ("consonantmedial", "Consonant_Medial"), + ("consonantplaceholder", "Consonant_Placeholder"), + ("consonantprecedingrepha", "Consonant_Preceding_Repha"), + ("consonantprefixed", "Consonant_Prefixed"), + ("consonantsubjoined", "Consonant_Subjoined"), + ("consonantsucceedingrepha", "Consonant_Succeeding_Repha"), + ("consonantwithstacker", "Consonant_With_Stacker"), + ("geminationmark", "Gemination_Mark"), + ("invisiblestacker", "Invisible_Stacker"), ("joiner", "Joiner"), + ("modifyingletter", "Modifying_Letter"), ("nonjoiner", "Non_Joiner"), + ("nukta", "Nukta"), ("number", "Number"), ("numberjoiner", "Number_Joiner"), + ("other", "Other"), ("purekiller", "Pure_Killer"), + ("registershifter", "Register_Shifter"), + ("syllablemodifier", "Syllable_Modifier"), ("toneletter", "Tone_Letter"), + ("tonemark", "Tone_Mark"), ("virama", "Virama"), ("visarga", "Visarga"), + ("vowel", "Vowel"), ("voweldependent", "Vowel_Dependent"), + ("vowelindependent", "Vowel_Independent"), ]), + + ("Jamo_Short_Name", &[("a", "A"), ("ae", "AE"), ("b", "B"), ("bb", "BB"), + ("bs", "BS"), ("c", "C"), ("d", "D"), ("dd", "DD"), ("e", "E"), + ("eo", "EO"), ("eu", "EU"), ("g", "G"), ("gg", "GG"), ("gs", "GS"), + ("h", "H"), ("i", "I"), ("j", "J"), ("jj", "JJ"), ("k", "K"), ("l", "L"), + ("lb", "LB"), ("lg", "LG"), ("lh", "LH"), ("lm", "LM"), ("lp", "LP"), + ("ls", "LS"), ("lt", "LT"), ("m", "M"), ("n", "N"), ("ng", "NG"), + ("nh", "NH"), ("nj", "NJ"), ("o", "O"), ("oe", "OE"), ("p", "P"), + ("r", "R"), ("s", "S"), ("ss", "SS"), ("t", "T"), ("u", "U"), ("wa", "WA"), + ("wae", "WAE"), ("we", "WE"), ("weo", "WEO"), ("wi", "WI"), ("ya", "YA"), + ("yae", "YAE"), ("ye", "YE"), ("yeo", "YEO"), ("yi", "YI"), ("yo", "YO"), + ("yu", "YU"), ]), + + ("Join_Control", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Joining_Group", &[("africanfeh", "African_Feh"), + ("africannoon", "African_Noon"), ("africanqaf", "African_Qaf"), + ("ain", "Ain"), ("alaph", "Alaph"), ("alef", "Alef"), ("beh", "Beh"), + ("beth", "Beth"), ("burushaskiyehbarree", "Burushaski_Yeh_Barree"), + ("dal", "Dal"), ("dalathrish", "Dalath_Rish"), ("e", "E"), + ("farsiyeh", "Farsi_Yeh"), ("fe", "Fe"), ("feh", "Feh"), + ("finalsemkath", "Final_Semkath"), ("gaf", "Gaf"), ("gamal", "Gamal"), + ("hah", "Hah"), ("hamzaonhehgoal", "Hamza_On_Heh_Goal"), + ("hanifirohingyakinnaya", "Hanifi_Rohingya_Kinna_Ya"), + ("hanifirohingyapa", "Hanifi_Rohingya_Pa"), ("he", "He"), ("heh", "Heh"), + ("hehgoal", "Heh_Goal"), ("heth", "Heth"), ("kaf", "Kaf"), ("kaph", "Kaph"), + ("khaph", "Khaph"), ("knottedheh", "Knotted_Heh"), ("lam", "Lam"), + ("lamadh", "Lamadh"), ("malayalambha", "Malayalam_Bha"), + ("malayalamja", "Malayalam_Ja"), ("malayalamlla", "Malayalam_Lla"), + ("malayalamllla", "Malayalam_Llla"), ("malayalamnga", "Malayalam_Nga"), + ("malayalamnna", "Malayalam_Nna"), ("malayalamnnna", "Malayalam_Nnna"), + ("malayalamnya", "Malayalam_Nya"), ("malayalamra", "Malayalam_Ra"), + ("malayalamssa", "Malayalam_Ssa"), ("malayalamtta", "Malayalam_Tta"), + ("manichaeanaleph", "Manichaean_Aleph"), + ("manichaeanayin", "Manichaean_Ayin"), + ("manichaeanbeth", "Manichaean_Beth"), + ("manichaeandaleth", "Manichaean_Daleth"), + ("manichaeandhamedh", "Manichaean_Dhamedh"), + ("manichaeanfive", "Manichaean_Five"), + ("manichaeangimel", "Manichaean_Gimel"), + ("manichaeanheth", "Manichaean_Heth"), + ("manichaeanhundred", "Manichaean_Hundred"), + ("manichaeankaph", "Manichaean_Kaph"), + ("manichaeanlamedh", "Manichaean_Lamedh"), + ("manichaeanmem", "Manichaean_Mem"), ("manichaeannun", "Manichaean_Nun"), + ("manichaeanone", "Manichaean_One"), ("manichaeanpe", "Manichaean_Pe"), + ("manichaeanqoph", "Manichaean_Qoph"), + ("manichaeanresh", "Manichaean_Resh"), + ("manichaeansadhe", "Manichaean_Sadhe"), + ("manichaeansamekh", "Manichaean_Samekh"), + ("manichaeantaw", "Manichaean_Taw"), ("manichaeanten", "Manichaean_Ten"), + ("manichaeanteth", "Manichaean_Teth"), + ("manichaeanthamedh", "Manichaean_Thamedh"), + ("manichaeantwenty", "Manichaean_Twenty"), + ("manichaeanwaw", "Manichaean_Waw"), ("manichaeanyodh", "Manichaean_Yodh"), + ("manichaeanzayin", "Manichaean_Zayin"), ("meem", "Meem"), ("mim", "Mim"), + ("nojoininggroup", "No_Joining_Group"), ("noon", "Noon"), ("nun", "Nun"), + ("nya", "Nya"), ("pe", "Pe"), ("qaf", "Qaf"), ("qaph", "Qaph"), + ("reh", "Reh"), ("reversedpe", "Reversed_Pe"), + ("rohingyayeh", "Rohingya_Yeh"), ("sad", "Sad"), ("sadhe", "Sadhe"), + ("seen", "Seen"), ("semkath", "Semkath"), ("shin", "Shin"), + ("straightwaw", "Straight_Waw"), ("swashkaf", "Swash_Kaf"), + ("syriacwaw", "Syriac_Waw"), ("tah", "Tah"), ("taw", "Taw"), + ("tehmarbuta", "Teh_Marbuta"), ("tehmarbutagoal", "Hamza_On_Heh_Goal"), + ("teth", "Teth"), ("waw", "Waw"), ("yeh", "Yeh"), + ("yehbarree", "Yeh_Barree"), ("yehwithtail", "Yeh_With_Tail"), + ("yudh", "Yudh"), ("yudhhe", "Yudh_He"), ("zain", "Zain"), + ("zhain", "Zhain"), ]), + + ("Joining_Type", &[("c", "Join_Causing"), ("d", "Dual_Joining"), + ("dualjoining", "Dual_Joining"), ("joincausing", "Join_Causing"), + ("l", "Left_Joining"), ("leftjoining", "Left_Joining"), + ("nonjoining", "Non_Joining"), ("r", "Right_Joining"), + ("rightjoining", "Right_Joining"), ("t", "Transparent"), + ("transparent", "Transparent"), ("u", "Non_Joining"), ]), + + ("Line_Break", &[("", "Infix_Numeric"), ("ai", "Ambiguous"), + ("al", "Alphabetic"), ("alphabetic", "Alphabetic"), + ("ambiguous", "Ambiguous"), ("b2", "Break_Both"), ("ba", "Break_After"), + ("bb", "Break_Before"), ("bk", "Mandatory_Break"), + ("breakafter", "Break_After"), ("breakbefore", "Break_Before"), + ("breakboth", "Break_Both"), ("breaksymbols", "Break_Symbols"), + ("carriagereturn", "Carriage_Return"), ("cb", "Contingent_Break"), + ("cj", "Conditional_Japanese_Starter"), ("cl", "Close_Punctuation"), + ("closeparenthesis", "Close_Parenthesis"), + ("closepunctuation", "Close_Punctuation"), ("cm", "Combining_Mark"), + ("combiningmark", "Combining_Mark"), ("complexcontext", "Complex_Context"), + ("conditionaljapanesestarter", "Conditional_Japanese_Starter"), + ("contingentbreak", "Contingent_Break"), ("cp", "Close_Parenthesis"), + ("cr", "Carriage_Return"), ("eb", "E_Base"), ("ebase", "E_Base"), + ("em", "E_Modifier"), ("emodifier", "E_Modifier"), ("ex", "Exclamation"), + ("exclamation", "Exclamation"), ("gl", "Glue"), ("glue", "Glue"), + ("h2", "H2"), ("h3", "H3"), ("hebrewletter", "Hebrew_Letter"), + ("hl", "Hebrew_Letter"), ("hy", "Hyphen"), ("hyphen", "Hyphen"), + ("id", "Ideographic"), ("ideographic", "Ideographic"), + ("in", "Inseparable"), ("infixnumeric", "Infix_Numeric"), + ("inseparable", "Inseparable"), ("inseperable", "Inseparable"), + ("jl", "JL"), ("jt", "JT"), ("jv", "JV"), ("lf", "Line_Feed"), + ("linefeed", "Line_Feed"), ("mandatorybreak", "Mandatory_Break"), + ("nextline", "Next_Line"), ("nl", "Next_Line"), + ("nonstarter", "Nonstarter"), ("ns", "Nonstarter"), ("nu", "Numeric"), + ("numeric", "Numeric"), ("op", "Open_Punctuation"), + ("openpunctuation", "Open_Punctuation"), ("po", "Postfix_Numeric"), + ("postfixnumeric", "Postfix_Numeric"), ("pr", "Prefix_Numeric"), + ("prefixnumeric", "Prefix_Numeric"), ("qu", "Quotation"), + ("quotation", "Quotation"), ("regionalindicator", "Regional_Indicator"), + ("ri", "Regional_Indicator"), ("sa", "Complex_Context"), + ("sg", "Surrogate"), ("sp", "Space"), ("space", "Space"), + ("surrogate", "Surrogate"), ("sy", "Break_Symbols"), ("unknown", "Unknown"), + ("wj", "Word_Joiner"), ("wordjoiner", "Word_Joiner"), ("xx", "Unknown"), + ("zw", "ZWSpace"), ("zwj", "ZWJ"), ("zwspace", "ZWSpace"), ]), + + ("Logical_Order_Exception", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Lowercase", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Math", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("NFC_Quick_Check", &[("m", "Maybe"), ("maybe", "Maybe"), ("n", "No"), + ("no", "No"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("NFD_Quick_Check", &[("n", "No"), ("no", "No"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("NFKC_Quick_Check", &[("m", "Maybe"), ("maybe", "Maybe"), ("n", "No"), + ("no", "No"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("NFKD_Quick_Check", &[("n", "No"), ("no", "No"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("Noncharacter_Code_Point", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Numeric_Type", &[("de", "Decimal"), ("decimal", "Decimal"), + ("di", "Digit"), ("digit", "Digit"), ("none", "None"), ("nu", "Numeric"), + ("numeric", "Numeric"), ]), + + ("Other_Alphabetic", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Other_Default_Ignorable_Code_Point", &[("f", "No"), ("false", "No"), + ("n", "No"), ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("Other_Grapheme_Extend", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Other_ID_Continue", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Other_ID_Start", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Other_Lowercase", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Other_Math", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Other_Uppercase", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Pattern_Syntax", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Pattern_White_Space", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Prepended_Concatenation_Mark", &[("f", "No"), ("false", "No"), + ("n", "No"), ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), + ("yes", "Yes"), ]), + + ("Quotation_Mark", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Radical", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Regional_Indicator", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Script", &[("adlam", "Adlam"), ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), ("arab", "Arabic"), + ("arabic", "Arabic"), ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), ("armn", "Armenian"), ("avestan", "Avestan"), + ("avst", "Avestan"), ("bali", "Balinese"), ("balinese", "Balinese"), + ("bamu", "Bamum"), ("bamum", "Bamum"), ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), ("batak", "Batak"), ("batk", "Batak"), + ("beng", "Bengali"), ("bengali", "Bengali"), ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), ("bopo", "Bopomofo"), ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), ("brahmi", "Brahmi"), ("brai", "Braille"), + ("braille", "Braille"), ("bugi", "Buginese"), ("buginese", "Buginese"), + ("buhd", "Buhid"), ("buhid", "Buhid"), ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), ("cari", "Carian"), ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), ("chakma", "Chakma"), + ("cham", "Cham"), ("cher", "Cherokee"), ("cherokee", "Cherokee"), + ("common", "Common"), ("copt", "Coptic"), ("coptic", "Coptic"), + ("cprt", "Cypriot"), ("cuneiform", "Cuneiform"), ("cypriot", "Cypriot"), + ("cyrillic", "Cyrillic"), ("cyrl", "Cyrillic"), ("deseret", "Deseret"), + ("deva", "Devanagari"), ("devanagari", "Devanagari"), ("dogr", "Dogra"), + ("dogra", "Dogra"), ("dsrt", "Deseret"), ("dupl", "Duployan"), + ("duployan", "Duployan"), ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), ("elba", "Elbasan"), + ("elbasan", "Elbasan"), ("ethi", "Ethiopic"), ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), ("georgian", "Georgian"), ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), ("goth", "Gothic"), ("gothic", "Gothic"), + ("gran", "Grantha"), ("grantha", "Grantha"), ("greek", "Greek"), + ("grek", "Greek"), ("gujarati", "Gujarati"), ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), ("han", "Han"), ("hang", "Hangul"), + ("hangul", "Hangul"), ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), ("hatr", "Hatran"), ("hatran", "Hatran"), + ("hebr", "Hebrew"), ("hebrew", "Hebrew"), ("hira", "Hiragana"), + ("hiragana", "Hiragana"), ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), ("ital", "Old_Italic"), + ("java", "Javanese"), ("javanese", "Javanese"), ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), ("kana", "Katakana"), ("kannada", "Kannada"), + ("katakana", "Katakana"), ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kayahli", "Kayah_Li"), ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), ("khmer", "Khmer"), ("khmr", "Khmer"), + ("khoj", "Khojki"), ("khojki", "Khojki"), ("khudawadi", "Khudawadi"), + ("knda", "Kannada"), ("kthi", "Kaithi"), ("lana", "Tai_Tham"), + ("lao", "Lao"), ("laoo", "Lao"), ("latin", "Latin"), ("latn", "Latin"), + ("lepc", "Lepcha"), ("lepcha", "Lepcha"), ("limb", "Limbu"), + ("limbu", "Limbu"), ("lina", "Linear_A"), ("linb", "Linear_B"), + ("lineara", "Linear_A"), ("linearb", "Linear_B"), ("lisu", "Lisu"), + ("lyci", "Lycian"), ("lycian", "Lycian"), ("lydi", "Lydian"), + ("lydian", "Lydian"), ("mahajani", "Mahajani"), ("mahj", "Mahajani"), + ("maka", "Makasar"), ("makasar", "Makasar"), ("malayalam", "Malayalam"), + ("mand", "Mandaic"), ("mandaic", "Mandaic"), ("mani", "Manichaean"), + ("manichaean", "Manichaean"), ("marc", "Marchen"), ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), ("miao", "Miao"), + ("mlym", "Malayalam"), ("modi", "Modi"), ("mong", "Mongolian"), + ("mongolian", "Mongolian"), ("mro", "Mro"), ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), ("mult", "Multani"), ("multani", "Multani"), + ("myanmar", "Myanmar"), ("mymr", "Myanmar"), ("nabataean", "Nabataean"), + ("narb", "Old_North_Arabian"), ("nbat", "Nabataean"), ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), ("nko", "Nko"), ("nkoo", "Nko"), + ("nshu", "Nushu"), ("nushu", "Nushu"), ("ogam", "Ogham"), + ("ogham", "Ogham"), ("olchiki", "Ol_Chiki"), ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), ("oldturkic", "Old_Turkic"), + ("oriya", "Oriya"), ("orkh", "Old_Turkic"), ("orya", "Oriya"), + ("osage", "Osage"), ("osge", "Osage"), ("osma", "Osmanya"), + ("osmanya", "Osmanya"), ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), ("palmyrene", "Palmyrene"), ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), ("perm", "Old_Permic"), ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), ("qaai", "Inherited"), ("rejang", "Rejang"), + ("rjng", "Rejang"), ("rohg", "Hanifi_Rohingya"), ("runic", "Runic"), + ("runr", "Runic"), ("samaritan", "Samaritan"), ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), ("sgnw", "SignWriting"), + ("sharada", "Sharada"), ("shavian", "Shavian"), ("shaw", "Shavian"), + ("shrd", "Sharada"), ("sidd", "Siddham"), ("siddham", "Siddham"), + ("signwriting", "SignWriting"), ("sind", "Khudawadi"), ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), ("sogd", "Sogdian"), ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), ("sund", "Sundanese"), ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), ("syriac", "Syriac"), ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), ("tagbanwa", "Tagbanwa"), ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), ("taiviet", "Tai_Viet"), ("takr", "Takri"), + ("takri", "Takri"), ("tale", "Tai_Le"), ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), ("taml", "Tamil"), ("tang", "Tangut"), + ("tangut", "Tangut"), ("tavt", "Tai_Viet"), ("telu", "Telugu"), + ("telugu", "Telugu"), ("tfng", "Tifinagh"), ("tglg", "Tagalog"), + ("thaa", "Thaana"), ("thaana", "Thaana"), ("thai", "Thai"), + ("tibetan", "Tibetan"), ("tibt", "Tibetan"), ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), ("tirhuta", "Tirhuta"), ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), ("unknown", "Unknown"), ("vai", "Vai"), + ("vaii", "Vai"), ("wara", "Warang_Citi"), ("warangciti", "Warang_Citi"), + ("xpeo", "Old_Persian"), ("xsux", "Cuneiform"), ("yi", "Yi"), + ("yiii", "Yi"), ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), ("zinh", "Inherited"), ("zyyy", "Common"), + ("zzzz", "Unknown"), ]), + + ("Script_Extensions", &[("adlam", "Adlam"), ("adlm", "Adlam"), + ("aghb", "Caucasian_Albanian"), ("ahom", "Ahom"), + ("anatolianhieroglyphs", "Anatolian_Hieroglyphs"), ("arab", "Arabic"), + ("arabic", "Arabic"), ("armenian", "Armenian"), + ("armi", "Imperial_Aramaic"), ("armn", "Armenian"), ("avestan", "Avestan"), + ("avst", "Avestan"), ("bali", "Balinese"), ("balinese", "Balinese"), + ("bamu", "Bamum"), ("bamum", "Bamum"), ("bass", "Bassa_Vah"), + ("bassavah", "Bassa_Vah"), ("batak", "Batak"), ("batk", "Batak"), + ("beng", "Bengali"), ("bengali", "Bengali"), ("bhaiksuki", "Bhaiksuki"), + ("bhks", "Bhaiksuki"), ("bopo", "Bopomofo"), ("bopomofo", "Bopomofo"), + ("brah", "Brahmi"), ("brahmi", "Brahmi"), ("brai", "Braille"), + ("braille", "Braille"), ("bugi", "Buginese"), ("buginese", "Buginese"), + ("buhd", "Buhid"), ("buhid", "Buhid"), ("cakm", "Chakma"), + ("canadianaboriginal", "Canadian_Aboriginal"), + ("cans", "Canadian_Aboriginal"), ("cari", "Carian"), ("carian", "Carian"), + ("caucasianalbanian", "Caucasian_Albanian"), ("chakma", "Chakma"), + ("cham", "Cham"), ("cher", "Cherokee"), ("cherokee", "Cherokee"), + ("common", "Common"), ("copt", "Coptic"), ("coptic", "Coptic"), + ("cprt", "Cypriot"), ("cuneiform", "Cuneiform"), ("cypriot", "Cypriot"), + ("cyrillic", "Cyrillic"), ("cyrl", "Cyrillic"), ("deseret", "Deseret"), + ("deva", "Devanagari"), ("devanagari", "Devanagari"), ("dogr", "Dogra"), + ("dogra", "Dogra"), ("dsrt", "Deseret"), ("dupl", "Duployan"), + ("duployan", "Duployan"), ("egyp", "Egyptian_Hieroglyphs"), + ("egyptianhieroglyphs", "Egyptian_Hieroglyphs"), ("elba", "Elbasan"), + ("elbasan", "Elbasan"), ("ethi", "Ethiopic"), ("ethiopic", "Ethiopic"), + ("geor", "Georgian"), ("georgian", "Georgian"), ("glag", "Glagolitic"), + ("glagolitic", "Glagolitic"), ("gong", "Gunjala_Gondi"), + ("gonm", "Masaram_Gondi"), ("goth", "Gothic"), ("gothic", "Gothic"), + ("gran", "Grantha"), ("grantha", "Grantha"), ("greek", "Greek"), + ("grek", "Greek"), ("gujarati", "Gujarati"), ("gujr", "Gujarati"), + ("gunjalagondi", "Gunjala_Gondi"), ("gurmukhi", "Gurmukhi"), + ("guru", "Gurmukhi"), ("han", "Han"), ("hang", "Hangul"), + ("hangul", "Hangul"), ("hani", "Han"), + ("hanifirohingya", "Hanifi_Rohingya"), ("hano", "Hanunoo"), + ("hanunoo", "Hanunoo"), ("hatr", "Hatran"), ("hatran", "Hatran"), + ("hebr", "Hebrew"), ("hebrew", "Hebrew"), ("hira", "Hiragana"), + ("hiragana", "Hiragana"), ("hluw", "Anatolian_Hieroglyphs"), + ("hmng", "Pahawh_Hmong"), ("hrkt", "Katakana_Or_Hiragana"), + ("hung", "Old_Hungarian"), ("imperialaramaic", "Imperial_Aramaic"), + ("inherited", "Inherited"), + ("inscriptionalpahlavi", "Inscriptional_Pahlavi"), + ("inscriptionalparthian", "Inscriptional_Parthian"), ("ital", "Old_Italic"), + ("java", "Javanese"), ("javanese", "Javanese"), ("kaithi", "Kaithi"), + ("kali", "Kayah_Li"), ("kana", "Katakana"), ("kannada", "Kannada"), + ("katakana", "Katakana"), ("katakanaorhiragana", "Katakana_Or_Hiragana"), + ("kayahli", "Kayah_Li"), ("khar", "Kharoshthi"), + ("kharoshthi", "Kharoshthi"), ("khmer", "Khmer"), ("khmr", "Khmer"), + ("khoj", "Khojki"), ("khojki", "Khojki"), ("khudawadi", "Khudawadi"), + ("knda", "Kannada"), ("kthi", "Kaithi"), ("lana", "Tai_Tham"), + ("lao", "Lao"), ("laoo", "Lao"), ("latin", "Latin"), ("latn", "Latin"), + ("lepc", "Lepcha"), ("lepcha", "Lepcha"), ("limb", "Limbu"), + ("limbu", "Limbu"), ("lina", "Linear_A"), ("linb", "Linear_B"), + ("lineara", "Linear_A"), ("linearb", "Linear_B"), ("lisu", "Lisu"), + ("lyci", "Lycian"), ("lycian", "Lycian"), ("lydi", "Lydian"), + ("lydian", "Lydian"), ("mahajani", "Mahajani"), ("mahj", "Mahajani"), + ("maka", "Makasar"), ("makasar", "Makasar"), ("malayalam", "Malayalam"), + ("mand", "Mandaic"), ("mandaic", "Mandaic"), ("mani", "Manichaean"), + ("manichaean", "Manichaean"), ("marc", "Marchen"), ("marchen", "Marchen"), + ("masaramgondi", "Masaram_Gondi"), ("medefaidrin", "Medefaidrin"), + ("medf", "Medefaidrin"), ("meeteimayek", "Meetei_Mayek"), + ("mend", "Mende_Kikakui"), ("mendekikakui", "Mende_Kikakui"), + ("merc", "Meroitic_Cursive"), ("mero", "Meroitic_Hieroglyphs"), + ("meroiticcursive", "Meroitic_Cursive"), + ("meroitichieroglyphs", "Meroitic_Hieroglyphs"), ("miao", "Miao"), + ("mlym", "Malayalam"), ("modi", "Modi"), ("mong", "Mongolian"), + ("mongolian", "Mongolian"), ("mro", "Mro"), ("mroo", "Mro"), + ("mtei", "Meetei_Mayek"), ("mult", "Multani"), ("multani", "Multani"), + ("myanmar", "Myanmar"), ("mymr", "Myanmar"), ("nabataean", "Nabataean"), + ("narb", "Old_North_Arabian"), ("nbat", "Nabataean"), ("newa", "Newa"), + ("newtailue", "New_Tai_Lue"), ("nko", "Nko"), ("nkoo", "Nko"), + ("nshu", "Nushu"), ("nushu", "Nushu"), ("ogam", "Ogham"), + ("ogham", "Ogham"), ("olchiki", "Ol_Chiki"), ("olck", "Ol_Chiki"), + ("oldhungarian", "Old_Hungarian"), ("olditalic", "Old_Italic"), + ("oldnortharabian", "Old_North_Arabian"), ("oldpermic", "Old_Permic"), + ("oldpersian", "Old_Persian"), ("oldsogdian", "Old_Sogdian"), + ("oldsoutharabian", "Old_South_Arabian"), ("oldturkic", "Old_Turkic"), + ("oriya", "Oriya"), ("orkh", "Old_Turkic"), ("orya", "Oriya"), + ("osage", "Osage"), ("osge", "Osage"), ("osma", "Osmanya"), + ("osmanya", "Osmanya"), ("pahawhhmong", "Pahawh_Hmong"), + ("palm", "Palmyrene"), ("palmyrene", "Palmyrene"), ("pauc", "Pau_Cin_Hau"), + ("paucinhau", "Pau_Cin_Hau"), ("perm", "Old_Permic"), ("phag", "Phags_Pa"), + ("phagspa", "Phags_Pa"), ("phli", "Inscriptional_Pahlavi"), + ("phlp", "Psalter_Pahlavi"), ("phnx", "Phoenician"), + ("phoenician", "Phoenician"), ("plrd", "Miao"), + ("prti", "Inscriptional_Parthian"), ("psalterpahlavi", "Psalter_Pahlavi"), + ("qaac", "Coptic"), ("qaai", "Inherited"), ("rejang", "Rejang"), + ("rjng", "Rejang"), ("rohg", "Hanifi_Rohingya"), ("runic", "Runic"), + ("runr", "Runic"), ("samaritan", "Samaritan"), ("samr", "Samaritan"), + ("sarb", "Old_South_Arabian"), ("saur", "Saurashtra"), + ("saurashtra", "Saurashtra"), ("sgnw", "SignWriting"), + ("sharada", "Sharada"), ("shavian", "Shavian"), ("shaw", "Shavian"), + ("shrd", "Sharada"), ("sidd", "Siddham"), ("siddham", "Siddham"), + ("signwriting", "SignWriting"), ("sind", "Khudawadi"), ("sinh", "Sinhala"), + ("sinhala", "Sinhala"), ("sogd", "Sogdian"), ("sogdian", "Sogdian"), + ("sogo", "Old_Sogdian"), ("sora", "Sora_Sompeng"), + ("sorasompeng", "Sora_Sompeng"), ("soyo", "Soyombo"), + ("soyombo", "Soyombo"), ("sund", "Sundanese"), ("sundanese", "Sundanese"), + ("sylo", "Syloti_Nagri"), ("sylotinagri", "Syloti_Nagri"), + ("syrc", "Syriac"), ("syriac", "Syriac"), ("tagalog", "Tagalog"), + ("tagb", "Tagbanwa"), ("tagbanwa", "Tagbanwa"), ("taile", "Tai_Le"), + ("taitham", "Tai_Tham"), ("taiviet", "Tai_Viet"), ("takr", "Takri"), + ("takri", "Takri"), ("tale", "Tai_Le"), ("talu", "New_Tai_Lue"), + ("tamil", "Tamil"), ("taml", "Tamil"), ("tang", "Tangut"), + ("tangut", "Tangut"), ("tavt", "Tai_Viet"), ("telu", "Telugu"), + ("telugu", "Telugu"), ("tfng", "Tifinagh"), ("tglg", "Tagalog"), + ("thaa", "Thaana"), ("thaana", "Thaana"), ("thai", "Thai"), + ("tibetan", "Tibetan"), ("tibt", "Tibetan"), ("tifinagh", "Tifinagh"), + ("tirh", "Tirhuta"), ("tirhuta", "Tirhuta"), ("ugar", "Ugaritic"), + ("ugaritic", "Ugaritic"), ("unknown", "Unknown"), ("vai", "Vai"), + ("vaii", "Vai"), ("wara", "Warang_Citi"), ("warangciti", "Warang_Citi"), + ("xpeo", "Old_Persian"), ("xsux", "Cuneiform"), ("yi", "Yi"), + ("yiii", "Yi"), ("zanabazarsquare", "Zanabazar_Square"), + ("zanb", "Zanabazar_Square"), ("zinh", "Inherited"), ("zyyy", "Common"), + ("zzzz", "Unknown"), ]), + + ("Sentence_Break", &[("at", "ATerm"), ("aterm", "ATerm"), ("cl", "Close"), + ("close", "Close"), ("cr", "CR"), ("ex", "Extend"), ("extend", "Extend"), + ("fo", "Format"), ("format", "Format"), ("le", "OLetter"), ("lf", "LF"), + ("lo", "Lower"), ("lower", "Lower"), ("nu", "Numeric"), + ("numeric", "Numeric"), ("oletter", "OLetter"), ("other", "Other"), + ("sc", "SContinue"), ("scontinue", "SContinue"), ("se", "Sep"), + ("sep", "Sep"), ("sp", "Sp"), ("st", "STerm"), ("sterm", "STerm"), + ("up", "Upper"), ("upper", "Upper"), ("xx", "Other"), ]), + + ("Sentence_Terminal", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Soft_Dotted", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Terminal_Punctuation", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Unified_Ideograph", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Uppercase", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Variation_Selector", &[("f", "No"), ("false", "No"), ("n", "No"), + ("no", "No"), ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), + ]), + + ("Vertical_Orientation", &[("r", "Rotated"), ("rotated", "Rotated"), + ("tr", "Transformed_Rotated"), + ("transformedrotated", "Transformed_Rotated"), + ("transformedupright", "Transformed_Upright"), + ("tu", "Transformed_Upright"), ("u", "Upright"), ("upright", "Upright"), ]), + + ("White_Space", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("Word_Break", &[("aletter", "ALetter"), ("cr", "CR"), + ("doublequote", "Double_Quote"), ("dq", "Double_Quote"), ("eb", "E_Base"), + ("ebase", "E_Base"), ("ebasegaz", "E_Base_GAZ"), ("ebg", "E_Base_GAZ"), + ("em", "E_Modifier"), ("emodifier", "E_Modifier"), ("ex", "ExtendNumLet"), + ("extend", "Extend"), ("extendnumlet", "ExtendNumLet"), ("fo", "Format"), + ("format", "Format"), ("gaz", "Glue_After_Zwj"), + ("glueafterzwj", "Glue_After_Zwj"), ("hebrewletter", "Hebrew_Letter"), + ("hl", "Hebrew_Letter"), ("ka", "Katakana"), ("katakana", "Katakana"), + ("le", "ALetter"), ("lf", "LF"), ("mb", "MidNumLet"), + ("midletter", "MidLetter"), ("midnum", "MidNum"), + ("midnumlet", "MidNumLet"), ("ml", "MidLetter"), ("mn", "MidNum"), + ("newline", "Newline"), ("nl", "Newline"), ("nu", "Numeric"), + ("numeric", "Numeric"), ("other", "Other"), + ("regionalindicator", "Regional_Indicator"), ("ri", "Regional_Indicator"), + ("singlequote", "Single_Quote"), ("sq", "Single_Quote"), + ("wsegspace", "WSegSpace"), ("xx", "Other"), ("zwj", "ZWJ"), ]), + + ("XID_Continue", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), + + ("XID_Start", &[("f", "No"), ("false", "No"), ("n", "No"), ("no", "No"), + ("t", "Yes"), ("true", "Yes"), ("y", "Yes"), ("yes", "Yes"), ]), +]; diff --git a/unicode-bidi/.cargo-checksum.json b/unicode-bidi/.cargo-checksum.json new file mode 100644 index 000000000..3b027f11f --- /dev/null +++ b/unicode-bidi/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"} \ No newline at end of file diff --git a/unicode-bidi/.pc/.quilt_patches b/unicode-bidi/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/unicode-bidi/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/unicode-bidi/.pc/.quilt_series b/unicode-bidi/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/unicode-bidi/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/unicode-bidi/.pc/.version b/unicode-bidi/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/unicode-bidi/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/unicode-bidi/.pc/applied-patches b/unicode-bidi/.pc/applied-patches new file mode 100644 index 000000000..142adb0f9 --- /dev/null +++ b/unicode-bidi/.pc/applied-patches @@ -0,0 +1 @@ +no-flamegraphs.patch diff --git a/unicode-bidi/.pc/no-flamegraphs.patch/.timestamp b/unicode-bidi/.pc/no-flamegraphs.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/unicode-bidi/.pc/no-flamegraphs.patch/Cargo.toml b/unicode-bidi/.pc/no-flamegraphs.patch/Cargo.toml new file mode 100644 index 000000000..f12ebcd60 --- /dev/null +++ b/unicode-bidi/.pc/no-flamegraphs.patch/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "unicode-bidi" +version = "0.3.4" +authors = ["The Servo Project Developers"] +exclude = ["benches/**", "data/**", "examples/**", "tests/**", "tools/**"] +description = "Implementation of the Unicode Bidirectional Algorithm" +documentation = "http://doc.servo.org/unicode_bidi/" +keywords = ["rtl", "unicode", "text", "layout", "bidi"] +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/unicode-bidi" + +[lib] +name = "unicode_bidi" +[dependencies.flame] +version = "0.1" +optional = true + +[dependencies.flamer] +version = "0.1" +optional = true + +[dependencies.serde] +version = ">=0.8, <2.0" +features = ["derive"] +optional = true + +[dependencies.matches] +version = "0.1" +[dev-dependencies.serde_test] +version = ">=0.8, <2.0" + +[features] +with_serde = ["serde"] +flame_it = ["flame", "flamer"] +unstable = [] +default = [] +bench_it = [] diff --git a/unicode-bidi/AUTHORS b/unicode-bidi/AUTHORS new file mode 100644 index 000000000..81b0362e0 --- /dev/null +++ b/unicode-bidi/AUTHORS @@ -0,0 +1,4 @@ +This software was written by the following people: + +Matt Brubeck <mbrubeck@limpet.net> +Behnam Esfahbod <behnam@zwnj.org> diff --git a/unicode-bidi/COPYRIGHT b/unicode-bidi/COPYRIGHT new file mode 100644 index 000000000..d84c46588 --- /dev/null +++ b/unicode-bidi/COPYRIGHT @@ -0,0 +1,8 @@ +This project is copyright 2015, The Servo Project Developers (given in the +file AUTHORS). + +Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +http://opensource.org/licenses/MIT>, at your option. All files in the project +carrying such notice may not be copied, modified, or distributed except +according to those terms. diff --git a/unicode-bidi/Cargo.toml b/unicode-bidi/Cargo.toml new file mode 100644 index 000000000..555c5d162 --- /dev/null +++ b/unicode-bidi/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "unicode-bidi" +version = "0.3.4" +authors = ["The Servo Project Developers"] +exclude = ["benches/**", "data/**", "examples/**", "tests/**", "tools/**"] +description = "Implementation of the Unicode Bidirectional Algorithm" +documentation = "http://doc.servo.org/unicode_bidi/" +keywords = ["rtl", "unicode", "text", "layout", "bidi"] +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/unicode-bidi" + +[lib] +name = "unicode_bidi" + +[dependencies.serde] +version = ">=0.8, <2.0" +features = ["derive"] +optional = true + +[dependencies.matches] +version = "0.1" +[dev-dependencies.serde_test] +version = ">=0.8, <2.0" + +[features] +with_serde = ["serde"] +unstable = [] +default = [] +bench_it = [] diff --git a/unicode-bidi/LICENSE-APACHE b/unicode-bidi/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/unicode-bidi/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/unicode-bidi/LICENSE-MIT b/unicode-bidi/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/unicode-bidi/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/unicode-bidi/README.md b/unicode-bidi/README.md new file mode 100644 index 000000000..d2888a1da --- /dev/null +++ b/unicode-bidi/README.md @@ -0,0 +1,12 @@ +# unicode-bidi + +This crate implements the [Unicode Bidirectional Algorithm][tr9] for display +of mixed right-to-left and left-to-right text. It is written in safe Rust, +compatible with the current stable release. + +[Documentation](http://doc.servo.org/unicode_bidi/) + +[![Travis-CI](https://travis-ci.org/servo/unicode-bidi.svg?branch=master)](https://travis-ci.org/servo/unicode-bidi) +[![AppVeyor](https://img.shields.io/appveyor/ci/servo/unicode-bidi/master.svg)](https://ci.appveyor.com/project/servo/unicode-bidi) + +[tr9]: http://www.unicode.org/reports/tr9/ diff --git a/unicode-bidi/debian/patches/no-flamegraphs.patch b/unicode-bidi/debian/patches/no-flamegraphs.patch new file mode 100644 index 000000000..9acab8637 --- /dev/null +++ b/unicode-bidi/debian/patches/no-flamegraphs.patch @@ -0,0 +1,24 @@ +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -23,13 +23,6 @@ + + [lib] + name = "unicode_bidi" +-[dependencies.flame] +-version = "0.1" +-optional = true +- +-[dependencies.flamer] +-version = "0.1" +-optional = true + + [dependencies.serde] + version = ">=0.8, <2.0" +@@ -43,7 +36,6 @@ + + [features] + with_serde = ["serde"] +-flame_it = ["flame", "flamer"] + unstable = [] + default = [] + bench_it = [] diff --git a/unicode-bidi/debian/patches/series b/unicode-bidi/debian/patches/series new file mode 100644 index 000000000..142adb0f9 --- /dev/null +++ b/unicode-bidi/debian/patches/series @@ -0,0 +1 @@ +no-flamegraphs.patch diff --git a/unicode-bidi/src/char_data/mod.rs b/unicode-bidi/src/char_data/mod.rs new file mode 100644 index 000000000..4899a715f --- /dev/null +++ b/unicode-bidi/src/char_data/mod.rs @@ -0,0 +1,136 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Accessor for `Bidi_Class` property from Unicode Character Database (UCD) + +mod tables; + +pub use self::tables::{BidiClass, UNICODE_VERSION}; + +use std::cmp::Ordering::{Equal, Less, Greater}; +use std::char; + +use self::tables::bidi_class_table; +use BidiClass::*; + +/// Find the `BidiClass` of a single char. +pub fn bidi_class(c: char) -> BidiClass { + bsearch_range_value_table(c, bidi_class_table) +} + +pub fn is_rtl(bidi_class: BidiClass) -> bool { + match bidi_class { + RLE | RLO | RLI => true, + _ => false, + } +} + +fn bsearch_range_value_table(c: char, r: &'static [(char, char, BidiClass)]) -> BidiClass { + match r.binary_search_by(|&(lo, hi, _)| if lo <= c && c <= hi { + Equal + } else if hi < c { + Less + } else { + Greater + }) { + Ok(idx) => { + let (_, _, cat) = r[idx]; + cat + } + // UCD/extracted/DerivedBidiClass.txt: "All code points not explicitly listed + // for Bidi_Class have the value Left_To_Right (L)." + Err(_) => L, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ascii() { + assert_eq!(bidi_class('\u{0000}'), BN); + assert_eq!(bidi_class('\u{0040}'), ON); + assert_eq!(bidi_class('\u{0041}'), L); + assert_eq!(bidi_class('\u{0062}'), L); + assert_eq!(bidi_class('\u{007F}'), BN); + } + + #[test] + fn test_bmp() { + // Hebrew + assert_eq!(bidi_class('\u{0590}'), R); + assert_eq!(bidi_class('\u{05D0}'), R); + assert_eq!(bidi_class('\u{05D1}'), R); + assert_eq!(bidi_class('\u{05FF}'), R); + + // Arabic + assert_eq!(bidi_class('\u{0600}'), AN); + assert_eq!(bidi_class('\u{0627}'), AL); + assert_eq!(bidi_class('\u{07BF}'), AL); + + // Default R + Arabic Extras + assert_eq!(bidi_class('\u{07C0}'), R); + assert_eq!(bidi_class('\u{085F}'), R); + assert_eq!(bidi_class('\u{0860}'), AL); + assert_eq!(bidi_class('\u{0870}'), R); + assert_eq!(bidi_class('\u{089F}'), R); + assert_eq!(bidi_class('\u{08A0}'), AL); + assert_eq!(bidi_class('\u{089F}'), R); + assert_eq!(bidi_class('\u{08FF}'), NSM); + + // Default ET + assert_eq!(bidi_class('\u{20A0}'), ET); + assert_eq!(bidi_class('\u{20CF}'), ET); + + // Arabic Presentation Forms + assert_eq!(bidi_class('\u{FB1D}'), R); + assert_eq!(bidi_class('\u{FB4F}'), R); + assert_eq!(bidi_class('\u{FB50}'), AL); + assert_eq!(bidi_class('\u{FDCF}'), AL); + assert_eq!(bidi_class('\u{FDF0}'), AL); + assert_eq!(bidi_class('\u{FDFF}'), AL); + assert_eq!(bidi_class('\u{FE70}'), AL); + assert_eq!(bidi_class('\u{FEFE}'), AL); + assert_eq!(bidi_class('\u{FEFF}'), BN); + + // noncharacters + assert_eq!(bidi_class('\u{FDD0}'), L); + assert_eq!(bidi_class('\u{FDD1}'), L); + assert_eq!(bidi_class('\u{FDEE}'), L); + assert_eq!(bidi_class('\u{FDEF}'), L); + assert_eq!(bidi_class('\u{FFFE}'), L); + assert_eq!(bidi_class('\u{FFFF}'), L); + } + + #[test] + fn test_smp() { + // Default AL + R + assert_eq!(bidi_class('\u{10800}'), R); + assert_eq!(bidi_class('\u{10FFF}'), R); + assert_eq!(bidi_class('\u{1E800}'), R); + assert_eq!(bidi_class('\u{1EDFF}'), R); + assert_eq!(bidi_class('\u{1EE00}'), AL); + assert_eq!(bidi_class('\u{1EEFF}'), AL); + assert_eq!(bidi_class('\u{1EF00}'), R); + assert_eq!(bidi_class('\u{1EFFF}'), R); + } + + #[test] + fn test_unassigned_planes() { + assert_eq!(bidi_class('\u{30000}'), L); + assert_eq!(bidi_class('\u{40000}'), L); + assert_eq!(bidi_class('\u{50000}'), L); + assert_eq!(bidi_class('\u{60000}'), L); + assert_eq!(bidi_class('\u{70000}'), L); + assert_eq!(bidi_class('\u{80000}'), L); + assert_eq!(bidi_class('\u{90000}'), L); + assert_eq!(bidi_class('\u{a0000}'), L); + } +} diff --git a/unicode-bidi/src/char_data/tables.rs b/unicode-bidi/src/char_data/tables.rs new file mode 100644 index 000000000..acc62e71a --- /dev/null +++ b/unicode-bidi/src/char_data/tables.rs @@ -0,0 +1,464 @@ +// NOTE: +// The following code was generated by "tools/generate.py". do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] +#![cfg_attr(rustfmt, rustfmt_skip)] + +/// The [Unicode version](http://www.unicode.org/versions/) of data +pub const UNICODE_VERSION: (u64, u64, u64) = (10, 0, 0); + +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// Represents values of the Unicode character property +/// [`Bidi_Class`](http://www.unicode.org/reports/tr44/#Bidi_Class), also +/// known as the *bidirectional character type*. +/// +/// * <http://www.unicode.org/reports/tr9/#Bidirectional_Character_Types> +/// * <http://www.unicode.org/reports/tr44/#Bidi_Class_Values> +pub enum BidiClass { + AL, + AN, + B, + BN, + CS, + EN, + ES, + ET, + FSI, + L, + LRE, + LRI, + LRO, + NSM, + ON, + PDF, + PDI, + R, + RLE, + RLI, + RLO, + S, + WS, +} + +use self::BidiClass::*; +pub const bidi_class_table: &'static [(char, char, BidiClass)] = &[ + ('\u{0}', '\u{8}', BN), ('\u{9}', '\u{9}', S), ('\u{a}', '\u{a}', B), ('\u{b}', '\u{b}', S), + ('\u{c}', '\u{c}', WS), ('\u{d}', '\u{d}', B), ('\u{e}', '\u{1b}', BN), ('\u{1c}', '\u{1e}', B), + ('\u{1f}', '\u{1f}', S), ('\u{20}', '\u{20}', WS), ('\u{21}', '\u{22}', ON), ('\u{23}', + '\u{25}', ET), ('\u{26}', '\u{2a}', ON), ('\u{2b}', '\u{2b}', ES), ('\u{2c}', '\u{2c}', CS), + ('\u{2d}', '\u{2d}', ES), ('\u{2e}', '\u{2f}', CS), ('\u{30}', '\u{39}', EN), ('\u{3a}', + '\u{3a}', CS), ('\u{3b}', '\u{40}', ON), ('\u{41}', '\u{5a}', L), ('\u{5b}', '\u{60}', ON), + ('\u{61}', '\u{7a}', L), ('\u{7b}', '\u{7e}', ON), ('\u{7f}', '\u{84}', BN), ('\u{85}', + '\u{85}', B), ('\u{86}', '\u{9f}', BN), ('\u{a0}', '\u{a0}', CS), ('\u{a1}', '\u{a1}', ON), + ('\u{a2}', '\u{a5}', ET), ('\u{a6}', '\u{a9}', ON), ('\u{aa}', '\u{aa}', L), ('\u{ab}', + '\u{ac}', ON), ('\u{ad}', '\u{ad}', BN), ('\u{ae}', '\u{af}', ON), ('\u{b0}', '\u{b1}', ET), + ('\u{b2}', '\u{b3}', EN), ('\u{b4}', '\u{b4}', ON), ('\u{b5}', '\u{b5}', L), ('\u{b6}', + '\u{b8}', ON), ('\u{b9}', '\u{b9}', EN), ('\u{ba}', '\u{ba}', L), ('\u{bb}', '\u{bf}', ON), + ('\u{c0}', '\u{d6}', L), ('\u{d7}', '\u{d7}', ON), ('\u{d8}', '\u{f6}', L), ('\u{f7}', '\u{f7}', + ON), ('\u{f8}', '\u{2b8}', L), ('\u{2b9}', '\u{2ba}', ON), ('\u{2bb}', '\u{2c1}', L), + ('\u{2c2}', '\u{2cf}', ON), ('\u{2d0}', '\u{2d1}', L), ('\u{2d2}', '\u{2df}', ON), ('\u{2e0}', + '\u{2e4}', L), ('\u{2e5}', '\u{2ed}', ON), ('\u{2ee}', '\u{2ee}', L), ('\u{2ef}', '\u{2ff}', + ON), ('\u{300}', '\u{36f}', NSM), ('\u{370}', '\u{373}', L), ('\u{374}', '\u{375}', ON), + ('\u{376}', '\u{377}', L), ('\u{37a}', '\u{37d}', L), ('\u{37e}', '\u{37e}', ON), ('\u{37f}', + '\u{37f}', L), ('\u{384}', '\u{385}', ON), ('\u{386}', '\u{386}', L), ('\u{387}', '\u{387}', + ON), ('\u{388}', '\u{38a}', L), ('\u{38c}', '\u{38c}', L), ('\u{38e}', '\u{3a1}', L), + ('\u{3a3}', '\u{3f5}', L), ('\u{3f6}', '\u{3f6}', ON), ('\u{3f7}', '\u{482}', L), ('\u{483}', + '\u{489}', NSM), ('\u{48a}', '\u{52f}', L), ('\u{531}', '\u{556}', L), ('\u{559}', '\u{55f}', + L), ('\u{561}', '\u{587}', L), ('\u{589}', '\u{589}', L), ('\u{58a}', '\u{58a}', ON), + ('\u{58d}', '\u{58e}', ON), ('\u{58f}', '\u{58f}', ET), ('\u{590}', '\u{590}', R), ('\u{591}', + '\u{5bd}', NSM), ('\u{5be}', '\u{5be}', R), ('\u{5bf}', '\u{5bf}', NSM), ('\u{5c0}', '\u{5c0}', + R), ('\u{5c1}', '\u{5c2}', NSM), ('\u{5c3}', '\u{5c3}', R), ('\u{5c4}', '\u{5c5}', NSM), + ('\u{5c6}', '\u{5c6}', R), ('\u{5c7}', '\u{5c7}', NSM), ('\u{5c8}', '\u{5ff}', R), ('\u{600}', + '\u{605}', AN), ('\u{606}', '\u{607}', ON), ('\u{608}', '\u{608}', AL), ('\u{609}', '\u{60a}', + ET), ('\u{60b}', '\u{60b}', AL), ('\u{60c}', '\u{60c}', CS), ('\u{60d}', '\u{60d}', AL), + ('\u{60e}', '\u{60f}', ON), ('\u{610}', '\u{61a}', NSM), ('\u{61b}', '\u{64a}', AL), ('\u{64b}', + '\u{65f}', NSM), ('\u{660}', '\u{669}', AN), ('\u{66a}', '\u{66a}', ET), ('\u{66b}', '\u{66c}', + AN), ('\u{66d}', '\u{66f}', AL), ('\u{670}', '\u{670}', NSM), ('\u{671}', '\u{6d5}', AL), + ('\u{6d6}', '\u{6dc}', NSM), ('\u{6dd}', '\u{6dd}', AN), ('\u{6de}', '\u{6de}', ON), ('\u{6df}', + '\u{6e4}', NSM), ('\u{6e5}', '\u{6e6}', AL), ('\u{6e7}', '\u{6e8}', NSM), ('\u{6e9}', '\u{6e9}', + ON), ('\u{6ea}', '\u{6ed}', NSM), ('\u{6ee}', '\u{6ef}', AL), ('\u{6f0}', '\u{6f9}', EN), + ('\u{6fa}', '\u{710}', AL), ('\u{711}', '\u{711}', NSM), ('\u{712}', '\u{72f}', AL), ('\u{730}', + '\u{74a}', NSM), ('\u{74b}', '\u{7a5}', AL), ('\u{7a6}', '\u{7b0}', NSM), ('\u{7b1}', '\u{7bf}', + AL), ('\u{7c0}', '\u{7ea}', R), ('\u{7eb}', '\u{7f3}', NSM), ('\u{7f4}', '\u{7f5}', R), + ('\u{7f6}', '\u{7f9}', ON), ('\u{7fa}', '\u{815}', R), ('\u{816}', '\u{819}', NSM), ('\u{81a}', + '\u{81a}', R), ('\u{81b}', '\u{823}', NSM), ('\u{824}', '\u{824}', R), ('\u{825}', '\u{827}', + NSM), ('\u{828}', '\u{828}', R), ('\u{829}', '\u{82d}', NSM), ('\u{82e}', '\u{858}', R), + ('\u{859}', '\u{85b}', NSM), ('\u{85c}', '\u{85f}', R), ('\u{860}', '\u{86a}', AL), ('\u{86b}', + '\u{89f}', R), ('\u{8a0}', '\u{8d3}', AL), ('\u{8d4}', '\u{8e1}', NSM), ('\u{8e2}', '\u{8e2}', + AN), ('\u{8e3}', '\u{902}', NSM), ('\u{903}', '\u{939}', L), ('\u{93a}', '\u{93a}', NSM), + ('\u{93b}', '\u{93b}', L), ('\u{93c}', '\u{93c}', NSM), ('\u{93d}', '\u{940}', L), ('\u{941}', + '\u{948}', NSM), ('\u{949}', '\u{94c}', L), ('\u{94d}', '\u{94d}', NSM), ('\u{94e}', '\u{950}', + L), ('\u{951}', '\u{957}', NSM), ('\u{958}', '\u{961}', L), ('\u{962}', '\u{963}', NSM), + ('\u{964}', '\u{980}', L), ('\u{981}', '\u{981}', NSM), ('\u{982}', '\u{983}', L), ('\u{985}', + '\u{98c}', L), ('\u{98f}', '\u{990}', L), ('\u{993}', '\u{9a8}', L), ('\u{9aa}', '\u{9b0}', L), + ('\u{9b2}', '\u{9b2}', L), ('\u{9b6}', '\u{9b9}', L), ('\u{9bc}', '\u{9bc}', NSM), ('\u{9bd}', + '\u{9c0}', L), ('\u{9c1}', '\u{9c4}', NSM), ('\u{9c7}', '\u{9c8}', L), ('\u{9cb}', '\u{9cc}', + L), ('\u{9cd}', '\u{9cd}', NSM), ('\u{9ce}', '\u{9ce}', L), ('\u{9d7}', '\u{9d7}', L), + ('\u{9dc}', '\u{9dd}', L), ('\u{9df}', '\u{9e1}', L), ('\u{9e2}', '\u{9e3}', NSM), ('\u{9e6}', + '\u{9f1}', L), ('\u{9f2}', '\u{9f3}', ET), ('\u{9f4}', '\u{9fa}', L), ('\u{9fb}', '\u{9fb}', + ET), ('\u{9fc}', '\u{9fd}', L), ('\u{a01}', '\u{a02}', NSM), ('\u{a03}', '\u{a03}', L), + ('\u{a05}', '\u{a0a}', L), ('\u{a0f}', '\u{a10}', L), ('\u{a13}', '\u{a28}', L), ('\u{a2a}', + '\u{a30}', L), ('\u{a32}', '\u{a33}', L), ('\u{a35}', '\u{a36}', L), ('\u{a38}', '\u{a39}', L), + ('\u{a3c}', '\u{a3c}', NSM), ('\u{a3e}', '\u{a40}', L), ('\u{a41}', '\u{a42}', NSM), ('\u{a47}', + '\u{a48}', NSM), ('\u{a4b}', '\u{a4d}', NSM), ('\u{a51}', '\u{a51}', NSM), ('\u{a59}', + '\u{a5c}', L), ('\u{a5e}', '\u{a5e}', L), ('\u{a66}', '\u{a6f}', L), ('\u{a70}', '\u{a71}', + NSM), ('\u{a72}', '\u{a74}', L), ('\u{a75}', '\u{a75}', NSM), ('\u{a81}', '\u{a82}', NSM), + ('\u{a83}', '\u{a83}', L), ('\u{a85}', '\u{a8d}', L), ('\u{a8f}', '\u{a91}', L), ('\u{a93}', + '\u{aa8}', L), ('\u{aaa}', '\u{ab0}', L), ('\u{ab2}', '\u{ab3}', L), ('\u{ab5}', '\u{ab9}', L), + ('\u{abc}', '\u{abc}', NSM), ('\u{abd}', '\u{ac0}', L), ('\u{ac1}', '\u{ac5}', NSM), ('\u{ac7}', + '\u{ac8}', NSM), ('\u{ac9}', '\u{ac9}', L), ('\u{acb}', '\u{acc}', L), ('\u{acd}', '\u{acd}', + NSM), ('\u{ad0}', '\u{ad0}', L), ('\u{ae0}', '\u{ae1}', L), ('\u{ae2}', '\u{ae3}', NSM), + ('\u{ae6}', '\u{af0}', L), ('\u{af1}', '\u{af1}', ET), ('\u{af9}', '\u{af9}', L), ('\u{afa}', + '\u{aff}', NSM), ('\u{b01}', '\u{b01}', NSM), ('\u{b02}', '\u{b03}', L), ('\u{b05}', '\u{b0c}', + L), ('\u{b0f}', '\u{b10}', L), ('\u{b13}', '\u{b28}', L), ('\u{b2a}', '\u{b30}', L), ('\u{b32}', + '\u{b33}', L), ('\u{b35}', '\u{b39}', L), ('\u{b3c}', '\u{b3c}', NSM), ('\u{b3d}', '\u{b3e}', + L), ('\u{b3f}', '\u{b3f}', NSM), ('\u{b40}', '\u{b40}', L), ('\u{b41}', '\u{b44}', NSM), + ('\u{b47}', '\u{b48}', L), ('\u{b4b}', '\u{b4c}', L), ('\u{b4d}', '\u{b4d}', NSM), ('\u{b56}', + '\u{b56}', NSM), ('\u{b57}', '\u{b57}', L), ('\u{b5c}', '\u{b5d}', L), ('\u{b5f}', '\u{b61}', + L), ('\u{b62}', '\u{b63}', NSM), ('\u{b66}', '\u{b77}', L), ('\u{b82}', '\u{b82}', NSM), + ('\u{b83}', '\u{b83}', L), ('\u{b85}', '\u{b8a}', L), ('\u{b8e}', '\u{b90}', L), ('\u{b92}', + '\u{b95}', L), ('\u{b99}', '\u{b9a}', L), ('\u{b9c}', '\u{b9c}', L), ('\u{b9e}', '\u{b9f}', L), + ('\u{ba3}', '\u{ba4}', L), ('\u{ba8}', '\u{baa}', L), ('\u{bae}', '\u{bb9}', L), ('\u{bbe}', + '\u{bbf}', L), ('\u{bc0}', '\u{bc0}', NSM), ('\u{bc1}', '\u{bc2}', L), ('\u{bc6}', '\u{bc8}', + L), ('\u{bca}', '\u{bcc}', L), ('\u{bcd}', '\u{bcd}', NSM), ('\u{bd0}', '\u{bd0}', L), + ('\u{bd7}', '\u{bd7}', L), ('\u{be6}', '\u{bf2}', L), ('\u{bf3}', '\u{bf8}', ON), ('\u{bf9}', + '\u{bf9}', ET), ('\u{bfa}', '\u{bfa}', ON), ('\u{c00}', '\u{c00}', NSM), ('\u{c01}', '\u{c03}', + L), ('\u{c05}', '\u{c0c}', L), ('\u{c0e}', '\u{c10}', L), ('\u{c12}', '\u{c28}', L), ('\u{c2a}', + '\u{c39}', L), ('\u{c3d}', '\u{c3d}', L), ('\u{c3e}', '\u{c40}', NSM), ('\u{c41}', '\u{c44}', + L), ('\u{c46}', '\u{c48}', NSM), ('\u{c4a}', '\u{c4d}', NSM), ('\u{c55}', '\u{c56}', NSM), + ('\u{c58}', '\u{c5a}', L), ('\u{c60}', '\u{c61}', L), ('\u{c62}', '\u{c63}', NSM), ('\u{c66}', + '\u{c6f}', L), ('\u{c78}', '\u{c7e}', ON), ('\u{c7f}', '\u{c80}', L), ('\u{c81}', '\u{c81}', + NSM), ('\u{c82}', '\u{c83}', L), ('\u{c85}', '\u{c8c}', L), ('\u{c8e}', '\u{c90}', L), + ('\u{c92}', '\u{ca8}', L), ('\u{caa}', '\u{cb3}', L), ('\u{cb5}', '\u{cb9}', L), ('\u{cbc}', + '\u{cbc}', NSM), ('\u{cbd}', '\u{cc4}', L), ('\u{cc6}', '\u{cc8}', L), ('\u{cca}', '\u{ccb}', + L), ('\u{ccc}', '\u{ccd}', NSM), ('\u{cd5}', '\u{cd6}', L), ('\u{cde}', '\u{cde}', L), + ('\u{ce0}', '\u{ce1}', L), ('\u{ce2}', '\u{ce3}', NSM), ('\u{ce6}', '\u{cef}', L), ('\u{cf1}', + '\u{cf2}', L), ('\u{d00}', '\u{d01}', NSM), ('\u{d02}', '\u{d03}', L), ('\u{d05}', '\u{d0c}', + L), ('\u{d0e}', '\u{d10}', L), ('\u{d12}', '\u{d3a}', L), ('\u{d3b}', '\u{d3c}', NSM), + ('\u{d3d}', '\u{d40}', L), ('\u{d41}', '\u{d44}', NSM), ('\u{d46}', '\u{d48}', L), ('\u{d4a}', + '\u{d4c}', L), ('\u{d4d}', '\u{d4d}', NSM), ('\u{d4e}', '\u{d4f}', L), ('\u{d54}', '\u{d61}', + L), ('\u{d62}', '\u{d63}', NSM), ('\u{d66}', '\u{d7f}', L), ('\u{d82}', '\u{d83}', L), + ('\u{d85}', '\u{d96}', L), ('\u{d9a}', '\u{db1}', L), ('\u{db3}', '\u{dbb}', L), ('\u{dbd}', + '\u{dbd}', L), ('\u{dc0}', '\u{dc6}', L), ('\u{dca}', '\u{dca}', NSM), ('\u{dcf}', '\u{dd1}', + L), ('\u{dd2}', '\u{dd4}', NSM), ('\u{dd6}', '\u{dd6}', NSM), ('\u{dd8}', '\u{ddf}', L), + ('\u{de6}', '\u{def}', L), ('\u{df2}', '\u{df4}', L), ('\u{e01}', '\u{e30}', L), ('\u{e31}', + '\u{e31}', NSM), ('\u{e32}', '\u{e33}', L), ('\u{e34}', '\u{e3a}', NSM), ('\u{e3f}', '\u{e3f}', + ET), ('\u{e40}', '\u{e46}', L), ('\u{e47}', '\u{e4e}', NSM), ('\u{e4f}', '\u{e5b}', L), + ('\u{e81}', '\u{e82}', L), ('\u{e84}', '\u{e84}', L), ('\u{e87}', '\u{e88}', L), ('\u{e8a}', + '\u{e8a}', L), ('\u{e8d}', '\u{e8d}', L), ('\u{e94}', '\u{e97}', L), ('\u{e99}', '\u{e9f}', L), + ('\u{ea1}', '\u{ea3}', L), ('\u{ea5}', '\u{ea5}', L), ('\u{ea7}', '\u{ea7}', L), ('\u{eaa}', + '\u{eab}', L), ('\u{ead}', '\u{eb0}', L), ('\u{eb1}', '\u{eb1}', NSM), ('\u{eb2}', '\u{eb3}', + L), ('\u{eb4}', '\u{eb9}', NSM), ('\u{ebb}', '\u{ebc}', NSM), ('\u{ebd}', '\u{ebd}', L), + ('\u{ec0}', '\u{ec4}', L), ('\u{ec6}', '\u{ec6}', L), ('\u{ec8}', '\u{ecd}', NSM), ('\u{ed0}', + '\u{ed9}', L), ('\u{edc}', '\u{edf}', L), ('\u{f00}', '\u{f17}', L), ('\u{f18}', '\u{f19}', + NSM), ('\u{f1a}', '\u{f34}', L), ('\u{f35}', '\u{f35}', NSM), ('\u{f36}', '\u{f36}', L), + ('\u{f37}', '\u{f37}', NSM), ('\u{f38}', '\u{f38}', L), ('\u{f39}', '\u{f39}', NSM), ('\u{f3a}', + '\u{f3d}', ON), ('\u{f3e}', '\u{f47}', L), ('\u{f49}', '\u{f6c}', L), ('\u{f71}', '\u{f7e}', + NSM), ('\u{f7f}', '\u{f7f}', L), ('\u{f80}', '\u{f84}', NSM), ('\u{f85}', '\u{f85}', L), + ('\u{f86}', '\u{f87}', NSM), ('\u{f88}', '\u{f8c}', L), ('\u{f8d}', '\u{f97}', NSM), ('\u{f99}', + '\u{fbc}', NSM), ('\u{fbe}', '\u{fc5}', L), ('\u{fc6}', '\u{fc6}', NSM), ('\u{fc7}', '\u{fcc}', + L), ('\u{fce}', '\u{fda}', L), ('\u{1000}', '\u{102c}', L), ('\u{102d}', '\u{1030}', NSM), + ('\u{1031}', '\u{1031}', L), ('\u{1032}', '\u{1037}', NSM), ('\u{1038}', '\u{1038}', L), + ('\u{1039}', '\u{103a}', NSM), ('\u{103b}', '\u{103c}', L), ('\u{103d}', '\u{103e}', NSM), + ('\u{103f}', '\u{1057}', L), ('\u{1058}', '\u{1059}', NSM), ('\u{105a}', '\u{105d}', L), + ('\u{105e}', '\u{1060}', NSM), ('\u{1061}', '\u{1070}', L), ('\u{1071}', '\u{1074}', NSM), + ('\u{1075}', '\u{1081}', L), ('\u{1082}', '\u{1082}', NSM), ('\u{1083}', '\u{1084}', L), + ('\u{1085}', '\u{1086}', NSM), ('\u{1087}', '\u{108c}', L), ('\u{108d}', '\u{108d}', NSM), + ('\u{108e}', '\u{109c}', L), ('\u{109d}', '\u{109d}', NSM), ('\u{109e}', '\u{10c5}', L), + ('\u{10c7}', '\u{10c7}', L), ('\u{10cd}', '\u{10cd}', L), ('\u{10d0}', '\u{1248}', L), + ('\u{124a}', '\u{124d}', L), ('\u{1250}', '\u{1256}', L), ('\u{1258}', '\u{1258}', L), + ('\u{125a}', '\u{125d}', L), ('\u{1260}', '\u{1288}', L), ('\u{128a}', '\u{128d}', L), + ('\u{1290}', '\u{12b0}', L), ('\u{12b2}', '\u{12b5}', L), ('\u{12b8}', '\u{12be}', L), + ('\u{12c0}', '\u{12c0}', L), ('\u{12c2}', '\u{12c5}', L), ('\u{12c8}', '\u{12d6}', L), + ('\u{12d8}', '\u{1310}', L), ('\u{1312}', '\u{1315}', L), ('\u{1318}', '\u{135a}', L), + ('\u{135d}', '\u{135f}', NSM), ('\u{1360}', '\u{137c}', L), ('\u{1380}', '\u{138f}', L), + ('\u{1390}', '\u{1399}', ON), ('\u{13a0}', '\u{13f5}', L), ('\u{13f8}', '\u{13fd}', L), + ('\u{1400}', '\u{1400}', ON), ('\u{1401}', '\u{167f}', L), ('\u{1680}', '\u{1680}', WS), + ('\u{1681}', '\u{169a}', L), ('\u{169b}', '\u{169c}', ON), ('\u{16a0}', '\u{16f8}', L), + ('\u{1700}', '\u{170c}', L), ('\u{170e}', '\u{1711}', L), ('\u{1712}', '\u{1714}', NSM), + ('\u{1720}', '\u{1731}', L), ('\u{1732}', '\u{1734}', NSM), ('\u{1735}', '\u{1736}', L), + ('\u{1740}', '\u{1751}', L), ('\u{1752}', '\u{1753}', NSM), ('\u{1760}', '\u{176c}', L), + ('\u{176e}', '\u{1770}', L), ('\u{1772}', '\u{1773}', NSM), ('\u{1780}', '\u{17b3}', L), + ('\u{17b4}', '\u{17b5}', NSM), ('\u{17b6}', '\u{17b6}', L), ('\u{17b7}', '\u{17bd}', NSM), + ('\u{17be}', '\u{17c5}', L), ('\u{17c6}', '\u{17c6}', NSM), ('\u{17c7}', '\u{17c8}', L), + ('\u{17c9}', '\u{17d3}', NSM), ('\u{17d4}', '\u{17da}', L), ('\u{17db}', '\u{17db}', ET), + ('\u{17dc}', '\u{17dc}', L), ('\u{17dd}', '\u{17dd}', NSM), ('\u{17e0}', '\u{17e9}', L), + ('\u{17f0}', '\u{17f9}', ON), ('\u{1800}', '\u{180a}', ON), ('\u{180b}', '\u{180d}', NSM), + ('\u{180e}', '\u{180e}', BN), ('\u{1810}', '\u{1819}', L), ('\u{1820}', '\u{1877}', L), + ('\u{1880}', '\u{1884}', L), ('\u{1885}', '\u{1886}', NSM), ('\u{1887}', '\u{18a8}', L), + ('\u{18a9}', '\u{18a9}', NSM), ('\u{18aa}', '\u{18aa}', L), ('\u{18b0}', '\u{18f5}', L), + ('\u{1900}', '\u{191e}', L), ('\u{1920}', '\u{1922}', NSM), ('\u{1923}', '\u{1926}', L), + ('\u{1927}', '\u{1928}', NSM), ('\u{1929}', '\u{192b}', L), ('\u{1930}', '\u{1931}', L), + ('\u{1932}', '\u{1932}', NSM), ('\u{1933}', '\u{1938}', L), ('\u{1939}', '\u{193b}', NSM), + ('\u{1940}', '\u{1940}', ON), ('\u{1944}', '\u{1945}', ON), ('\u{1946}', '\u{196d}', L), + ('\u{1970}', '\u{1974}', L), ('\u{1980}', '\u{19ab}', L), ('\u{19b0}', '\u{19c9}', L), + ('\u{19d0}', '\u{19da}', L), ('\u{19de}', '\u{19ff}', ON), ('\u{1a00}', '\u{1a16}', L), + ('\u{1a17}', '\u{1a18}', NSM), ('\u{1a19}', '\u{1a1a}', L), ('\u{1a1b}', '\u{1a1b}', NSM), + ('\u{1a1e}', '\u{1a55}', L), ('\u{1a56}', '\u{1a56}', NSM), ('\u{1a57}', '\u{1a57}', L), + ('\u{1a58}', '\u{1a5e}', NSM), ('\u{1a60}', '\u{1a60}', NSM), ('\u{1a61}', '\u{1a61}', L), + ('\u{1a62}', '\u{1a62}', NSM), ('\u{1a63}', '\u{1a64}', L), ('\u{1a65}', '\u{1a6c}', NSM), + ('\u{1a6d}', '\u{1a72}', L), ('\u{1a73}', '\u{1a7c}', NSM), ('\u{1a7f}', '\u{1a7f}', NSM), + ('\u{1a80}', '\u{1a89}', L), ('\u{1a90}', '\u{1a99}', L), ('\u{1aa0}', '\u{1aad}', L), + ('\u{1ab0}', '\u{1abe}', NSM), ('\u{1b00}', '\u{1b03}', NSM), ('\u{1b04}', '\u{1b33}', L), + ('\u{1b34}', '\u{1b34}', NSM), ('\u{1b35}', '\u{1b35}', L), ('\u{1b36}', '\u{1b3a}', NSM), + ('\u{1b3b}', '\u{1b3b}', L), ('\u{1b3c}', '\u{1b3c}', NSM), ('\u{1b3d}', '\u{1b41}', L), + ('\u{1b42}', '\u{1b42}', NSM), ('\u{1b43}', '\u{1b4b}', L), ('\u{1b50}', '\u{1b6a}', L), + ('\u{1b6b}', '\u{1b73}', NSM), ('\u{1b74}', '\u{1b7c}', L), ('\u{1b80}', '\u{1b81}', NSM), + ('\u{1b82}', '\u{1ba1}', L), ('\u{1ba2}', '\u{1ba5}', NSM), ('\u{1ba6}', '\u{1ba7}', L), + ('\u{1ba8}', '\u{1ba9}', NSM), ('\u{1baa}', '\u{1baa}', L), ('\u{1bab}', '\u{1bad}', NSM), + ('\u{1bae}', '\u{1be5}', L), ('\u{1be6}', '\u{1be6}', NSM), ('\u{1be7}', '\u{1be7}', L), + ('\u{1be8}', '\u{1be9}', NSM), ('\u{1bea}', '\u{1bec}', L), ('\u{1bed}', '\u{1bed}', NSM), + ('\u{1bee}', '\u{1bee}', L), ('\u{1bef}', '\u{1bf1}', NSM), ('\u{1bf2}', '\u{1bf3}', L), + ('\u{1bfc}', '\u{1c2b}', L), ('\u{1c2c}', '\u{1c33}', NSM), ('\u{1c34}', '\u{1c35}', L), + ('\u{1c36}', '\u{1c37}', NSM), ('\u{1c3b}', '\u{1c49}', L), ('\u{1c4d}', '\u{1c88}', L), + ('\u{1cc0}', '\u{1cc7}', L), ('\u{1cd0}', '\u{1cd2}', NSM), ('\u{1cd3}', '\u{1cd3}', L), + ('\u{1cd4}', '\u{1ce0}', NSM), ('\u{1ce1}', '\u{1ce1}', L), ('\u{1ce2}', '\u{1ce8}', NSM), + ('\u{1ce9}', '\u{1cec}', L), ('\u{1ced}', '\u{1ced}', NSM), ('\u{1cee}', '\u{1cf3}', L), + ('\u{1cf4}', '\u{1cf4}', NSM), ('\u{1cf5}', '\u{1cf7}', L), ('\u{1cf8}', '\u{1cf9}', NSM), + ('\u{1d00}', '\u{1dbf}', L), ('\u{1dc0}', '\u{1df9}', NSM), ('\u{1dfb}', '\u{1dff}', NSM), + ('\u{1e00}', '\u{1f15}', L), ('\u{1f18}', '\u{1f1d}', L), ('\u{1f20}', '\u{1f45}', L), + ('\u{1f48}', '\u{1f4d}', L), ('\u{1f50}', '\u{1f57}', L), ('\u{1f59}', '\u{1f59}', L), + ('\u{1f5b}', '\u{1f5b}', L), ('\u{1f5d}', '\u{1f5d}', L), ('\u{1f5f}', '\u{1f7d}', L), + ('\u{1f80}', '\u{1fb4}', L), ('\u{1fb6}', '\u{1fbc}', L), ('\u{1fbd}', '\u{1fbd}', ON), + ('\u{1fbe}', '\u{1fbe}', L), ('\u{1fbf}', '\u{1fc1}', ON), ('\u{1fc2}', '\u{1fc4}', L), + ('\u{1fc6}', '\u{1fcc}', L), ('\u{1fcd}', '\u{1fcf}', ON), ('\u{1fd0}', '\u{1fd3}', L), + ('\u{1fd6}', '\u{1fdb}', L), ('\u{1fdd}', '\u{1fdf}', ON), ('\u{1fe0}', '\u{1fec}', L), + ('\u{1fed}', '\u{1fef}', ON), ('\u{1ff2}', '\u{1ff4}', L), ('\u{1ff6}', '\u{1ffc}', L), + ('\u{1ffd}', '\u{1ffe}', ON), ('\u{2000}', '\u{200a}', WS), ('\u{200b}', '\u{200d}', BN), + ('\u{200e}', '\u{200e}', L), ('\u{200f}', '\u{200f}', R), ('\u{2010}', '\u{2027}', ON), + ('\u{2028}', '\u{2028}', WS), ('\u{2029}', '\u{2029}', B), ('\u{202a}', '\u{202a}', LRE), + ('\u{202b}', '\u{202b}', RLE), ('\u{202c}', '\u{202c}', PDF), ('\u{202d}', '\u{202d}', LRO), + ('\u{202e}', '\u{202e}', RLO), ('\u{202f}', '\u{202f}', CS), ('\u{2030}', '\u{2034}', ET), + ('\u{2035}', '\u{2043}', ON), ('\u{2044}', '\u{2044}', CS), ('\u{2045}', '\u{205e}', ON), + ('\u{205f}', '\u{205f}', WS), ('\u{2060}', '\u{2064}', BN), ('\u{2066}', '\u{2066}', LRI), + ('\u{2067}', '\u{2067}', RLI), ('\u{2068}', '\u{2068}', FSI), ('\u{2069}', '\u{2069}', PDI), + ('\u{206a}', '\u{206f}', BN), ('\u{2070}', '\u{2070}', EN), ('\u{2071}', '\u{2071}', L), + ('\u{2074}', '\u{2079}', EN), ('\u{207a}', '\u{207b}', ES), ('\u{207c}', '\u{207e}', ON), + ('\u{207f}', '\u{207f}', L), ('\u{2080}', '\u{2089}', EN), ('\u{208a}', '\u{208b}', ES), + ('\u{208c}', '\u{208e}', ON), ('\u{2090}', '\u{209c}', L), ('\u{20a0}', '\u{20cf}', ET), + ('\u{20d0}', '\u{20f0}', NSM), ('\u{2100}', '\u{2101}', ON), ('\u{2102}', '\u{2102}', L), + ('\u{2103}', '\u{2106}', ON), ('\u{2107}', '\u{2107}', L), ('\u{2108}', '\u{2109}', ON), + ('\u{210a}', '\u{2113}', L), ('\u{2114}', '\u{2114}', ON), ('\u{2115}', '\u{2115}', L), + ('\u{2116}', '\u{2118}', ON), ('\u{2119}', '\u{211d}', L), ('\u{211e}', '\u{2123}', ON), + ('\u{2124}', '\u{2124}', L), ('\u{2125}', '\u{2125}', ON), ('\u{2126}', '\u{2126}', L), + ('\u{2127}', '\u{2127}', ON), ('\u{2128}', '\u{2128}', L), ('\u{2129}', '\u{2129}', ON), + ('\u{212a}', '\u{212d}', L), ('\u{212e}', '\u{212e}', ET), ('\u{212f}', '\u{2139}', L), + ('\u{213a}', '\u{213b}', ON), ('\u{213c}', '\u{213f}', L), ('\u{2140}', '\u{2144}', ON), + ('\u{2145}', '\u{2149}', L), ('\u{214a}', '\u{214d}', ON), ('\u{214e}', '\u{214f}', L), + ('\u{2150}', '\u{215f}', ON), ('\u{2160}', '\u{2188}', L), ('\u{2189}', '\u{218b}', ON), + ('\u{2190}', '\u{2211}', ON), ('\u{2212}', '\u{2212}', ES), ('\u{2213}', '\u{2213}', ET), + ('\u{2214}', '\u{2335}', ON), ('\u{2336}', '\u{237a}', L), ('\u{237b}', '\u{2394}', ON), + ('\u{2395}', '\u{2395}', L), ('\u{2396}', '\u{2426}', ON), ('\u{2440}', '\u{244a}', ON), + ('\u{2460}', '\u{2487}', ON), ('\u{2488}', '\u{249b}', EN), ('\u{249c}', '\u{24e9}', L), + ('\u{24ea}', '\u{26ab}', ON), ('\u{26ac}', '\u{26ac}', L), ('\u{26ad}', '\u{27ff}', ON), + ('\u{2800}', '\u{28ff}', L), ('\u{2900}', '\u{2b73}', ON), ('\u{2b76}', '\u{2b95}', ON), + ('\u{2b98}', '\u{2bb9}', ON), ('\u{2bbd}', '\u{2bc8}', ON), ('\u{2bca}', '\u{2bd2}', ON), + ('\u{2bec}', '\u{2bef}', ON), ('\u{2c00}', '\u{2c2e}', L), ('\u{2c30}', '\u{2c5e}', L), + ('\u{2c60}', '\u{2ce4}', L), ('\u{2ce5}', '\u{2cea}', ON), ('\u{2ceb}', '\u{2cee}', L), + ('\u{2cef}', '\u{2cf1}', NSM), ('\u{2cf2}', '\u{2cf3}', L), ('\u{2cf9}', '\u{2cff}', ON), + ('\u{2d00}', '\u{2d25}', L), ('\u{2d27}', '\u{2d27}', L), ('\u{2d2d}', '\u{2d2d}', L), + ('\u{2d30}', '\u{2d67}', L), ('\u{2d6f}', '\u{2d70}', L), ('\u{2d7f}', '\u{2d7f}', NSM), + ('\u{2d80}', '\u{2d96}', L), ('\u{2da0}', '\u{2da6}', L), ('\u{2da8}', '\u{2dae}', L), + ('\u{2db0}', '\u{2db6}', L), ('\u{2db8}', '\u{2dbe}', L), ('\u{2dc0}', '\u{2dc6}', L), + ('\u{2dc8}', '\u{2dce}', L), ('\u{2dd0}', '\u{2dd6}', L), ('\u{2dd8}', '\u{2dde}', L), + ('\u{2de0}', '\u{2dff}', NSM), ('\u{2e00}', '\u{2e49}', ON), ('\u{2e80}', '\u{2e99}', ON), + ('\u{2e9b}', '\u{2ef3}', ON), ('\u{2f00}', '\u{2fd5}', ON), ('\u{2ff0}', '\u{2ffb}', ON), + ('\u{3000}', '\u{3000}', WS), ('\u{3001}', '\u{3004}', ON), ('\u{3005}', '\u{3007}', L), + ('\u{3008}', '\u{3020}', ON), ('\u{3021}', '\u{3029}', L), ('\u{302a}', '\u{302d}', NSM), + ('\u{302e}', '\u{302f}', L), ('\u{3030}', '\u{3030}', ON), ('\u{3031}', '\u{3035}', L), + ('\u{3036}', '\u{3037}', ON), ('\u{3038}', '\u{303c}', L), ('\u{303d}', '\u{303f}', ON), + ('\u{3041}', '\u{3096}', L), ('\u{3099}', '\u{309a}', NSM), ('\u{309b}', '\u{309c}', ON), + ('\u{309d}', '\u{309f}', L), ('\u{30a0}', '\u{30a0}', ON), ('\u{30a1}', '\u{30fa}', L), + ('\u{30fb}', '\u{30fb}', ON), ('\u{30fc}', '\u{30ff}', L), ('\u{3105}', '\u{312e}', L), + ('\u{3131}', '\u{318e}', L), ('\u{3190}', '\u{31ba}', L), ('\u{31c0}', '\u{31e3}', ON), + ('\u{31f0}', '\u{321c}', L), ('\u{321d}', '\u{321e}', ON), ('\u{3220}', '\u{324f}', L), + ('\u{3250}', '\u{325f}', ON), ('\u{3260}', '\u{327b}', L), ('\u{327c}', '\u{327e}', ON), + ('\u{327f}', '\u{32b0}', L), ('\u{32b1}', '\u{32bf}', ON), ('\u{32c0}', '\u{32cb}', L), + ('\u{32cc}', '\u{32cf}', ON), ('\u{32d0}', '\u{32fe}', L), ('\u{3300}', '\u{3376}', L), + ('\u{3377}', '\u{337a}', ON), ('\u{337b}', '\u{33dd}', L), ('\u{33de}', '\u{33df}', ON), + ('\u{33e0}', '\u{33fe}', L), ('\u{33ff}', '\u{33ff}', ON), ('\u{3400}', '\u{4db5}', L), + ('\u{4dc0}', '\u{4dff}', ON), ('\u{4e00}', '\u{9fea}', L), ('\u{a000}', '\u{a48c}', L), + ('\u{a490}', '\u{a4c6}', ON), ('\u{a4d0}', '\u{a60c}', L), ('\u{a60d}', '\u{a60f}', ON), + ('\u{a610}', '\u{a62b}', L), ('\u{a640}', '\u{a66e}', L), ('\u{a66f}', '\u{a672}', NSM), + ('\u{a673}', '\u{a673}', ON), ('\u{a674}', '\u{a67d}', NSM), ('\u{a67e}', '\u{a67f}', ON), + ('\u{a680}', '\u{a69d}', L), ('\u{a69e}', '\u{a69f}', NSM), ('\u{a6a0}', '\u{a6ef}', L), + ('\u{a6f0}', '\u{a6f1}', NSM), ('\u{a6f2}', '\u{a6f7}', L), ('\u{a700}', '\u{a721}', ON), + ('\u{a722}', '\u{a787}', L), ('\u{a788}', '\u{a788}', ON), ('\u{a789}', '\u{a7ae}', L), + ('\u{a7b0}', '\u{a7b7}', L), ('\u{a7f7}', '\u{a801}', L), ('\u{a802}', '\u{a802}', NSM), + ('\u{a803}', '\u{a805}', L), ('\u{a806}', '\u{a806}', NSM), ('\u{a807}', '\u{a80a}', L), + ('\u{a80b}', '\u{a80b}', NSM), ('\u{a80c}', '\u{a824}', L), ('\u{a825}', '\u{a826}', NSM), + ('\u{a827}', '\u{a827}', L), ('\u{a828}', '\u{a82b}', ON), ('\u{a830}', '\u{a837}', L), + ('\u{a838}', '\u{a839}', ET), ('\u{a840}', '\u{a873}', L), ('\u{a874}', '\u{a877}', ON), + ('\u{a880}', '\u{a8c3}', L), ('\u{a8c4}', '\u{a8c5}', NSM), ('\u{a8ce}', '\u{a8d9}', L), + ('\u{a8e0}', '\u{a8f1}', NSM), ('\u{a8f2}', '\u{a8fd}', L), ('\u{a900}', '\u{a925}', L), + ('\u{a926}', '\u{a92d}', NSM), ('\u{a92e}', '\u{a946}', L), ('\u{a947}', '\u{a951}', NSM), + ('\u{a952}', '\u{a953}', L), ('\u{a95f}', '\u{a97c}', L), ('\u{a980}', '\u{a982}', NSM), + ('\u{a983}', '\u{a9b2}', L), ('\u{a9b3}', '\u{a9b3}', NSM), ('\u{a9b4}', '\u{a9b5}', L), + ('\u{a9b6}', '\u{a9b9}', NSM), ('\u{a9ba}', '\u{a9bb}', L), ('\u{a9bc}', '\u{a9bc}', NSM), + ('\u{a9bd}', '\u{a9cd}', L), ('\u{a9cf}', '\u{a9d9}', L), ('\u{a9de}', '\u{a9e4}', L), + ('\u{a9e5}', '\u{a9e5}', NSM), ('\u{a9e6}', '\u{a9fe}', L), ('\u{aa00}', '\u{aa28}', L), + ('\u{aa29}', '\u{aa2e}', NSM), ('\u{aa2f}', '\u{aa30}', L), ('\u{aa31}', '\u{aa32}', NSM), + ('\u{aa33}', '\u{aa34}', L), ('\u{aa35}', '\u{aa36}', NSM), ('\u{aa40}', '\u{aa42}', L), + ('\u{aa43}', '\u{aa43}', NSM), ('\u{aa44}', '\u{aa4b}', L), ('\u{aa4c}', '\u{aa4c}', NSM), + ('\u{aa4d}', '\u{aa4d}', L), ('\u{aa50}', '\u{aa59}', L), ('\u{aa5c}', '\u{aa7b}', L), + ('\u{aa7c}', '\u{aa7c}', NSM), ('\u{aa7d}', '\u{aaaf}', L), ('\u{aab0}', '\u{aab0}', NSM), + ('\u{aab1}', '\u{aab1}', L), ('\u{aab2}', '\u{aab4}', NSM), ('\u{aab5}', '\u{aab6}', L), + ('\u{aab7}', '\u{aab8}', NSM), ('\u{aab9}', '\u{aabd}', L), ('\u{aabe}', '\u{aabf}', NSM), + ('\u{aac0}', '\u{aac0}', L), ('\u{aac1}', '\u{aac1}', NSM), ('\u{aac2}', '\u{aac2}', L), + ('\u{aadb}', '\u{aaeb}', L), ('\u{aaec}', '\u{aaed}', NSM), ('\u{aaee}', '\u{aaf5}', L), + ('\u{aaf6}', '\u{aaf6}', NSM), ('\u{ab01}', '\u{ab06}', L), ('\u{ab09}', '\u{ab0e}', L), + ('\u{ab11}', '\u{ab16}', L), ('\u{ab20}', '\u{ab26}', L), ('\u{ab28}', '\u{ab2e}', L), + ('\u{ab30}', '\u{ab65}', L), ('\u{ab70}', '\u{abe4}', L), ('\u{abe5}', '\u{abe5}', NSM), + ('\u{abe6}', '\u{abe7}', L), ('\u{abe8}', '\u{abe8}', NSM), ('\u{abe9}', '\u{abec}', L), + ('\u{abed}', '\u{abed}', NSM), ('\u{abf0}', '\u{abf9}', L), ('\u{ac00}', '\u{d7a3}', L), + ('\u{d7b0}', '\u{d7c6}', L), ('\u{d7cb}', '\u{d7fb}', L), ('\u{e000}', '\u{fa6d}', L), + ('\u{fa70}', '\u{fad9}', L), ('\u{fb00}', '\u{fb06}', L), ('\u{fb13}', '\u{fb17}', L), + ('\u{fb1d}', '\u{fb1d}', R), ('\u{fb1e}', '\u{fb1e}', NSM), ('\u{fb1f}', '\u{fb28}', R), + ('\u{fb29}', '\u{fb29}', ES), ('\u{fb2a}', '\u{fb4f}', R), ('\u{fb50}', '\u{fd3d}', AL), + ('\u{fd3e}', '\u{fd3f}', ON), ('\u{fd40}', '\u{fdcf}', AL), ('\u{fdf0}', '\u{fdfc}', AL), + ('\u{fdfd}', '\u{fdfd}', ON), ('\u{fdfe}', '\u{fdff}', AL), ('\u{fe00}', '\u{fe0f}', NSM), + ('\u{fe10}', '\u{fe19}', ON), ('\u{fe20}', '\u{fe2f}', NSM), ('\u{fe30}', '\u{fe4f}', ON), + ('\u{fe50}', '\u{fe50}', CS), ('\u{fe51}', '\u{fe51}', ON), ('\u{fe52}', '\u{fe52}', CS), + ('\u{fe54}', '\u{fe54}', ON), ('\u{fe55}', '\u{fe55}', CS), ('\u{fe56}', '\u{fe5e}', ON), + ('\u{fe5f}', '\u{fe5f}', ET), ('\u{fe60}', '\u{fe61}', ON), ('\u{fe62}', '\u{fe63}', ES), + ('\u{fe64}', '\u{fe66}', ON), ('\u{fe68}', '\u{fe68}', ON), ('\u{fe69}', '\u{fe6a}', ET), + ('\u{fe6b}', '\u{fe6b}', ON), ('\u{fe70}', '\u{fefe}', AL), ('\u{feff}', '\u{feff}', BN), + ('\u{ff01}', '\u{ff02}', ON), ('\u{ff03}', '\u{ff05}', ET), ('\u{ff06}', '\u{ff0a}', ON), + ('\u{ff0b}', '\u{ff0b}', ES), ('\u{ff0c}', '\u{ff0c}', CS), ('\u{ff0d}', '\u{ff0d}', ES), + ('\u{ff0e}', '\u{ff0f}', CS), ('\u{ff10}', '\u{ff19}', EN), ('\u{ff1a}', '\u{ff1a}', CS), + ('\u{ff1b}', '\u{ff20}', ON), ('\u{ff21}', '\u{ff3a}', L), ('\u{ff3b}', '\u{ff40}', ON), + ('\u{ff41}', '\u{ff5a}', L), ('\u{ff5b}', '\u{ff65}', ON), ('\u{ff66}', '\u{ffbe}', L), + ('\u{ffc2}', '\u{ffc7}', L), ('\u{ffca}', '\u{ffcf}', L), ('\u{ffd2}', '\u{ffd7}', L), + ('\u{ffda}', '\u{ffdc}', L), ('\u{ffe0}', '\u{ffe1}', ET), ('\u{ffe2}', '\u{ffe4}', ON), + ('\u{ffe5}', '\u{ffe6}', ET), ('\u{ffe8}', '\u{ffee}', ON), ('\u{fff9}', '\u{fffd}', ON), + ('\u{10000}', '\u{1000b}', L), ('\u{1000d}', '\u{10026}', L), ('\u{10028}', '\u{1003a}', L), + ('\u{1003c}', '\u{1003d}', L), ('\u{1003f}', '\u{1004d}', L), ('\u{10050}', '\u{1005d}', L), + ('\u{10080}', '\u{100fa}', L), ('\u{10100}', '\u{10100}', L), ('\u{10101}', '\u{10101}', ON), + ('\u{10102}', '\u{10102}', L), ('\u{10107}', '\u{10133}', L), ('\u{10137}', '\u{1013f}', L), + ('\u{10140}', '\u{1018c}', ON), ('\u{1018d}', '\u{1018e}', L), ('\u{10190}', '\u{1019b}', ON), + ('\u{101a0}', '\u{101a0}', ON), ('\u{101d0}', '\u{101fc}', L), ('\u{101fd}', '\u{101fd}', NSM), + ('\u{10280}', '\u{1029c}', L), ('\u{102a0}', '\u{102d0}', L), ('\u{102e0}', '\u{102e0}', NSM), + ('\u{102e1}', '\u{102fb}', EN), ('\u{10300}', '\u{10323}', L), ('\u{1032d}', '\u{1034a}', L), + ('\u{10350}', '\u{10375}', L), ('\u{10376}', '\u{1037a}', NSM), ('\u{10380}', '\u{1039d}', L), + ('\u{1039f}', '\u{103c3}', L), ('\u{103c8}', '\u{103d5}', L), ('\u{10400}', '\u{1049d}', L), + ('\u{104a0}', '\u{104a9}', L), ('\u{104b0}', '\u{104d3}', L), ('\u{104d8}', '\u{104fb}', L), + ('\u{10500}', '\u{10527}', L), ('\u{10530}', '\u{10563}', L), ('\u{1056f}', '\u{1056f}', L), + ('\u{10600}', '\u{10736}', L), ('\u{10740}', '\u{10755}', L), ('\u{10760}', '\u{10767}', L), + ('\u{10800}', '\u{1091e}', R), ('\u{1091f}', '\u{1091f}', ON), ('\u{10920}', '\u{10a00}', R), + ('\u{10a01}', '\u{10a03}', NSM), ('\u{10a04}', '\u{10a04}', R), ('\u{10a05}', '\u{10a06}', NSM), + ('\u{10a07}', '\u{10a0b}', R), ('\u{10a0c}', '\u{10a0f}', NSM), ('\u{10a10}', '\u{10a37}', R), + ('\u{10a38}', '\u{10a3a}', NSM), ('\u{10a3b}', '\u{10a3e}', R), ('\u{10a3f}', '\u{10a3f}', NSM), + ('\u{10a40}', '\u{10ae4}', R), ('\u{10ae5}', '\u{10ae6}', NSM), ('\u{10ae7}', '\u{10b38}', R), + ('\u{10b39}', '\u{10b3f}', ON), ('\u{10b40}', '\u{10e5f}', R), ('\u{10e60}', '\u{10e7e}', AN), + ('\u{10e7f}', '\u{10fff}', R), ('\u{11000}', '\u{11000}', L), ('\u{11001}', '\u{11001}', NSM), + ('\u{11002}', '\u{11037}', L), ('\u{11038}', '\u{11046}', NSM), ('\u{11047}', '\u{1104d}', L), + ('\u{11052}', '\u{11065}', ON), ('\u{11066}', '\u{1106f}', L), ('\u{1107f}', '\u{11081}', NSM), + ('\u{11082}', '\u{110b2}', L), ('\u{110b3}', '\u{110b6}', NSM), ('\u{110b7}', '\u{110b8}', L), + ('\u{110b9}', '\u{110ba}', NSM), ('\u{110bb}', '\u{110c1}', L), ('\u{110d0}', '\u{110e8}', L), + ('\u{110f0}', '\u{110f9}', L), ('\u{11100}', '\u{11102}', NSM), ('\u{11103}', '\u{11126}', L), + ('\u{11127}', '\u{1112b}', NSM), ('\u{1112c}', '\u{1112c}', L), ('\u{1112d}', '\u{11134}', NSM), + ('\u{11136}', '\u{11143}', L), ('\u{11150}', '\u{11172}', L), ('\u{11173}', '\u{11173}', NSM), + ('\u{11174}', '\u{11176}', L), ('\u{11180}', '\u{11181}', NSM), ('\u{11182}', '\u{111b5}', L), + ('\u{111b6}', '\u{111be}', NSM), ('\u{111bf}', '\u{111c9}', L), ('\u{111ca}', '\u{111cc}', NSM), + ('\u{111cd}', '\u{111cd}', L), ('\u{111d0}', '\u{111df}', L), ('\u{111e1}', '\u{111f4}', L), + ('\u{11200}', '\u{11211}', L), ('\u{11213}', '\u{1122e}', L), ('\u{1122f}', '\u{11231}', NSM), + ('\u{11232}', '\u{11233}', L), ('\u{11234}', '\u{11234}', NSM), ('\u{11235}', '\u{11235}', L), + ('\u{11236}', '\u{11237}', NSM), ('\u{11238}', '\u{1123d}', L), ('\u{1123e}', '\u{1123e}', NSM), + ('\u{11280}', '\u{11286}', L), ('\u{11288}', '\u{11288}', L), ('\u{1128a}', '\u{1128d}', L), + ('\u{1128f}', '\u{1129d}', L), ('\u{1129f}', '\u{112a9}', L), ('\u{112b0}', '\u{112de}', L), + ('\u{112df}', '\u{112df}', NSM), ('\u{112e0}', '\u{112e2}', L), ('\u{112e3}', '\u{112ea}', NSM), + ('\u{112f0}', '\u{112f9}', L), ('\u{11300}', '\u{11301}', NSM), ('\u{11302}', '\u{11303}', L), + ('\u{11305}', '\u{1130c}', L), ('\u{1130f}', '\u{11310}', L), ('\u{11313}', '\u{11328}', L), + ('\u{1132a}', '\u{11330}', L), ('\u{11332}', '\u{11333}', L), ('\u{11335}', '\u{11339}', L), + ('\u{1133c}', '\u{1133c}', NSM), ('\u{1133d}', '\u{1133f}', L), ('\u{11340}', '\u{11340}', NSM), + ('\u{11341}', '\u{11344}', L), ('\u{11347}', '\u{11348}', L), ('\u{1134b}', '\u{1134d}', L), + ('\u{11350}', '\u{11350}', L), ('\u{11357}', '\u{11357}', L), ('\u{1135d}', '\u{11363}', L), + ('\u{11366}', '\u{1136c}', NSM), ('\u{11370}', '\u{11374}', NSM), ('\u{11400}', '\u{11437}', L), + ('\u{11438}', '\u{1143f}', NSM), ('\u{11440}', '\u{11441}', L), ('\u{11442}', '\u{11444}', NSM), + ('\u{11445}', '\u{11445}', L), ('\u{11446}', '\u{11446}', NSM), ('\u{11447}', '\u{11459}', L), + ('\u{1145b}', '\u{1145b}', L), ('\u{1145d}', '\u{1145d}', L), ('\u{11480}', '\u{114b2}', L), + ('\u{114b3}', '\u{114b8}', NSM), ('\u{114b9}', '\u{114b9}', L), ('\u{114ba}', '\u{114ba}', NSM), + ('\u{114bb}', '\u{114be}', L), ('\u{114bf}', '\u{114c0}', NSM), ('\u{114c1}', '\u{114c1}', L), + ('\u{114c2}', '\u{114c3}', NSM), ('\u{114c4}', '\u{114c7}', L), ('\u{114d0}', '\u{114d9}', L), + ('\u{11580}', '\u{115b1}', L), ('\u{115b2}', '\u{115b5}', NSM), ('\u{115b8}', '\u{115bb}', L), + ('\u{115bc}', '\u{115bd}', NSM), ('\u{115be}', '\u{115be}', L), ('\u{115bf}', '\u{115c0}', NSM), + ('\u{115c1}', '\u{115db}', L), ('\u{115dc}', '\u{115dd}', NSM), ('\u{11600}', '\u{11632}', L), + ('\u{11633}', '\u{1163a}', NSM), ('\u{1163b}', '\u{1163c}', L), ('\u{1163d}', '\u{1163d}', NSM), + ('\u{1163e}', '\u{1163e}', L), ('\u{1163f}', '\u{11640}', NSM), ('\u{11641}', '\u{11644}', L), + ('\u{11650}', '\u{11659}', L), ('\u{11660}', '\u{1166c}', ON), ('\u{11680}', '\u{116aa}', L), + ('\u{116ab}', '\u{116ab}', NSM), ('\u{116ac}', '\u{116ac}', L), ('\u{116ad}', '\u{116ad}', NSM), + ('\u{116ae}', '\u{116af}', L), ('\u{116b0}', '\u{116b5}', NSM), ('\u{116b6}', '\u{116b6}', L), + ('\u{116b7}', '\u{116b7}', NSM), ('\u{116c0}', '\u{116c9}', L), ('\u{11700}', '\u{11719}', L), + ('\u{1171d}', '\u{1171f}', NSM), ('\u{11720}', '\u{11721}', L), ('\u{11722}', '\u{11725}', NSM), + ('\u{11726}', '\u{11726}', L), ('\u{11727}', '\u{1172b}', NSM), ('\u{11730}', '\u{1173f}', L), + ('\u{118a0}', '\u{118f2}', L), ('\u{118ff}', '\u{118ff}', L), ('\u{11a00}', '\u{11a00}', L), + ('\u{11a01}', '\u{11a06}', NSM), ('\u{11a07}', '\u{11a08}', L), ('\u{11a09}', '\u{11a0a}', NSM), + ('\u{11a0b}', '\u{11a32}', L), ('\u{11a33}', '\u{11a38}', NSM), ('\u{11a39}', '\u{11a3a}', L), + ('\u{11a3b}', '\u{11a3e}', NSM), ('\u{11a3f}', '\u{11a46}', L), ('\u{11a47}', '\u{11a47}', NSM), + ('\u{11a50}', '\u{11a50}', L), ('\u{11a51}', '\u{11a56}', NSM), ('\u{11a57}', '\u{11a58}', L), + ('\u{11a59}', '\u{11a5b}', NSM), ('\u{11a5c}', '\u{11a83}', L), ('\u{11a86}', '\u{11a89}', L), + ('\u{11a8a}', '\u{11a96}', NSM), ('\u{11a97}', '\u{11a97}', L), ('\u{11a98}', '\u{11a99}', NSM), + ('\u{11a9a}', '\u{11a9c}', L), ('\u{11a9e}', '\u{11aa2}', L), ('\u{11ac0}', '\u{11af8}', L), + ('\u{11c00}', '\u{11c08}', L), ('\u{11c0a}', '\u{11c2f}', L), ('\u{11c30}', '\u{11c36}', NSM), + ('\u{11c38}', '\u{11c3d}', NSM), ('\u{11c3e}', '\u{11c45}', L), ('\u{11c50}', '\u{11c6c}', L), + ('\u{11c70}', '\u{11c8f}', L), ('\u{11c92}', '\u{11ca7}', NSM), ('\u{11ca9}', '\u{11ca9}', L), + ('\u{11caa}', '\u{11cb0}', NSM), ('\u{11cb1}', '\u{11cb1}', L), ('\u{11cb2}', '\u{11cb3}', NSM), + ('\u{11cb4}', '\u{11cb4}', L), ('\u{11cb5}', '\u{11cb6}', NSM), ('\u{11d00}', '\u{11d06}', L), + ('\u{11d08}', '\u{11d09}', L), ('\u{11d0b}', '\u{11d30}', L), ('\u{11d31}', '\u{11d36}', NSM), + ('\u{11d3a}', '\u{11d3a}', NSM), ('\u{11d3c}', '\u{11d3d}', NSM), ('\u{11d3f}', '\u{11d45}', + NSM), ('\u{11d46}', '\u{11d46}', L), ('\u{11d47}', '\u{11d47}', NSM), ('\u{11d50}', '\u{11d59}', + L), ('\u{12000}', '\u{12399}', L), ('\u{12400}', '\u{1246e}', L), ('\u{12470}', '\u{12474}', L), + ('\u{12480}', '\u{12543}', L), ('\u{13000}', '\u{1342e}', L), ('\u{14400}', '\u{14646}', L), + ('\u{16800}', '\u{16a38}', L), ('\u{16a40}', '\u{16a5e}', L), ('\u{16a60}', '\u{16a69}', L), + ('\u{16a6e}', '\u{16a6f}', L), ('\u{16ad0}', '\u{16aed}', L), ('\u{16af0}', '\u{16af4}', NSM), + ('\u{16af5}', '\u{16af5}', L), ('\u{16b00}', '\u{16b2f}', L), ('\u{16b30}', '\u{16b36}', NSM), + ('\u{16b37}', '\u{16b45}', L), ('\u{16b50}', '\u{16b59}', L), ('\u{16b5b}', '\u{16b61}', L), + ('\u{16b63}', '\u{16b77}', L), ('\u{16b7d}', '\u{16b8f}', L), ('\u{16f00}', '\u{16f44}', L), + ('\u{16f50}', '\u{16f7e}', L), ('\u{16f8f}', '\u{16f92}', NSM), ('\u{16f93}', '\u{16f9f}', L), + ('\u{16fe0}', '\u{16fe1}', L), ('\u{17000}', '\u{187ec}', L), ('\u{18800}', '\u{18af2}', L), + ('\u{1b000}', '\u{1b11e}', L), ('\u{1b170}', '\u{1b2fb}', L), ('\u{1bc00}', '\u{1bc6a}', L), + ('\u{1bc70}', '\u{1bc7c}', L), ('\u{1bc80}', '\u{1bc88}', L), ('\u{1bc90}', '\u{1bc99}', L), + ('\u{1bc9c}', '\u{1bc9c}', L), ('\u{1bc9d}', '\u{1bc9e}', NSM), ('\u{1bc9f}', '\u{1bc9f}', L), + ('\u{1bca0}', '\u{1bca3}', BN), ('\u{1d000}', '\u{1d0f5}', L), ('\u{1d100}', '\u{1d126}', L), + ('\u{1d129}', '\u{1d166}', L), ('\u{1d167}', '\u{1d169}', NSM), ('\u{1d16a}', '\u{1d172}', L), + ('\u{1d173}', '\u{1d17a}', BN), ('\u{1d17b}', '\u{1d182}', NSM), ('\u{1d183}', '\u{1d184}', L), + ('\u{1d185}', '\u{1d18b}', NSM), ('\u{1d18c}', '\u{1d1a9}', L), ('\u{1d1aa}', '\u{1d1ad}', NSM), + ('\u{1d1ae}', '\u{1d1e8}', L), ('\u{1d200}', '\u{1d241}', ON), ('\u{1d242}', '\u{1d244}', NSM), + ('\u{1d245}', '\u{1d245}', ON), ('\u{1d300}', '\u{1d356}', ON), ('\u{1d360}', '\u{1d371}', L), + ('\u{1d400}', '\u{1d454}', L), ('\u{1d456}', '\u{1d49c}', L), ('\u{1d49e}', '\u{1d49f}', L), + ('\u{1d4a2}', '\u{1d4a2}', L), ('\u{1d4a5}', '\u{1d4a6}', L), ('\u{1d4a9}', '\u{1d4ac}', L), + ('\u{1d4ae}', '\u{1d4b9}', L), ('\u{1d4bb}', '\u{1d4bb}', L), ('\u{1d4bd}', '\u{1d4c3}', L), + ('\u{1d4c5}', '\u{1d505}', L), ('\u{1d507}', '\u{1d50a}', L), ('\u{1d50d}', '\u{1d514}', L), + ('\u{1d516}', '\u{1d51c}', L), ('\u{1d51e}', '\u{1d539}', L), ('\u{1d53b}', '\u{1d53e}', L), + ('\u{1d540}', '\u{1d544}', L), ('\u{1d546}', '\u{1d546}', L), ('\u{1d54a}', '\u{1d550}', L), + ('\u{1d552}', '\u{1d6a5}', L), ('\u{1d6a8}', '\u{1d6da}', L), ('\u{1d6db}', '\u{1d6db}', ON), + ('\u{1d6dc}', '\u{1d714}', L), ('\u{1d715}', '\u{1d715}', ON), ('\u{1d716}', '\u{1d74e}', L), + ('\u{1d74f}', '\u{1d74f}', ON), ('\u{1d750}', '\u{1d788}', L), ('\u{1d789}', '\u{1d789}', ON), + ('\u{1d78a}', '\u{1d7c2}', L), ('\u{1d7c3}', '\u{1d7c3}', ON), ('\u{1d7c4}', '\u{1d7cb}', L), + ('\u{1d7ce}', '\u{1d7ff}', EN), ('\u{1d800}', '\u{1d9ff}', L), ('\u{1da00}', '\u{1da36}', NSM), + ('\u{1da37}', '\u{1da3a}', L), ('\u{1da3b}', '\u{1da6c}', NSM), ('\u{1da6d}', '\u{1da74}', L), + ('\u{1da75}', '\u{1da75}', NSM), ('\u{1da76}', '\u{1da83}', L), ('\u{1da84}', '\u{1da84}', NSM), + ('\u{1da85}', '\u{1da8b}', L), ('\u{1da9b}', '\u{1da9f}', NSM), ('\u{1daa1}', '\u{1daaf}', NSM), + ('\u{1e000}', '\u{1e006}', NSM), ('\u{1e008}', '\u{1e018}', NSM), ('\u{1e01b}', '\u{1e021}', + NSM), ('\u{1e023}', '\u{1e024}', NSM), ('\u{1e026}', '\u{1e02a}', NSM), ('\u{1e800}', + '\u{1e8cf}', R), ('\u{1e8d0}', '\u{1e8d6}', NSM), ('\u{1e8d7}', '\u{1e943}', R), ('\u{1e944}', + '\u{1e94a}', NSM), ('\u{1e94b}', '\u{1edff}', R), ('\u{1ee00}', '\u{1eeef}', AL), ('\u{1eef0}', + '\u{1eef1}', ON), ('\u{1eef2}', '\u{1eeff}', AL), ('\u{1ef00}', '\u{1efff}', R), ('\u{1f000}', + '\u{1f02b}', ON), ('\u{1f030}', '\u{1f093}', ON), ('\u{1f0a0}', '\u{1f0ae}', ON), ('\u{1f0b1}', + '\u{1f0bf}', ON), ('\u{1f0c1}', '\u{1f0cf}', ON), ('\u{1f0d1}', '\u{1f0f5}', ON), ('\u{1f100}', + '\u{1f10a}', EN), ('\u{1f10b}', '\u{1f10c}', ON), ('\u{1f110}', '\u{1f12e}', L), ('\u{1f130}', + '\u{1f169}', L), ('\u{1f16a}', '\u{1f16b}', ON), ('\u{1f170}', '\u{1f1ac}', L), ('\u{1f1e6}', + '\u{1f202}', L), ('\u{1f210}', '\u{1f23b}', L), ('\u{1f240}', '\u{1f248}', L), ('\u{1f250}', + '\u{1f251}', L), ('\u{1f260}', '\u{1f265}', ON), ('\u{1f300}', '\u{1f6d4}', ON), ('\u{1f6e0}', + '\u{1f6ec}', ON), ('\u{1f6f0}', '\u{1f6f8}', ON), ('\u{1f700}', '\u{1f773}', ON), ('\u{1f780}', + '\u{1f7d4}', ON), ('\u{1f800}', '\u{1f80b}', ON), ('\u{1f810}', '\u{1f847}', ON), ('\u{1f850}', + '\u{1f859}', ON), ('\u{1f860}', '\u{1f887}', ON), ('\u{1f890}', '\u{1f8ad}', ON), ('\u{1f900}', + '\u{1f90b}', ON), ('\u{1f910}', '\u{1f93e}', ON), ('\u{1f940}', '\u{1f94c}', ON), ('\u{1f950}', + '\u{1f96b}', ON), ('\u{1f980}', '\u{1f997}', ON), ('\u{1f9c0}', '\u{1f9c0}', ON), ('\u{1f9d0}', + '\u{1f9e6}', ON), ('\u{20000}', '\u{2a6d6}', L), ('\u{2a700}', '\u{2b734}', L), ('\u{2b740}', + '\u{2b81d}', L), ('\u{2b820}', '\u{2cea1}', L), ('\u{2ceb0}', '\u{2ebe0}', L), ('\u{2f800}', + '\u{2fa1d}', L), ('\u{e0001}', '\u{e0001}', BN), ('\u{e0020}', '\u{e007f}', BN), ('\u{e0100}', + '\u{e01ef}', NSM), ('\u{f0000}', '\u{ffffd}', L), ('\u{100000}', '\u{10fffd}', L) +]; + diff --git a/unicode-bidi/src/deprecated.rs b/unicode-bidi/src/deprecated.rs new file mode 100644 index 000000000..4d4b76e35 --- /dev/null +++ b/unicode-bidi/src/deprecated.rs @@ -0,0 +1,90 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module holds deprecated assets only. + +// Doesn't worth updating API here +#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))] + +use super::*; + +/// Find the level runs within a line and return them in visual order. +/// +/// NOTE: This implementation is incomplete. The algorithm needs information about the text, +/// including original `BidiClass` property of each character, to be able to perform correctly. +/// Please see [`BidiInfo::visual_runs()`](../struct.BidiInfo.html#method.visual_runs) for the +/// improved implementation. +/// +/// `line` is a range of bytes indices within `levels`. +/// +/// <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels> +#[deprecated(since = "0.3.0", note = "please use `BidiInfo::visual_runs()` instead.")] +pub fn visual_runs(line: Range<usize>, levels: &[Level]) -> Vec<LevelRun> { + assert!(line.start <= levels.len()); + assert!(line.end <= levels.len()); + + let mut runs = Vec::new(); + + // Find consecutive level runs. + let mut start = line.start; + let mut run_level = levels[start]; + let mut min_level = run_level; + let mut max_level = run_level; + + for (i, &new_level) in levels.iter().enumerate().take(line.end).skip(start + 1) { + if new_level != run_level { + // End of the previous run, start of a new one. + runs.push(start..i); + start = i; + run_level = new_level; + + min_level = min(run_level, min_level); + max_level = max(run_level, max_level); + } + } + runs.push(start..line.end); + + let run_count = runs.len(); + + // Re-order the odd runs. + // <http://www.unicode.org/reports/tr9/#L2> + + // Stop at the lowest *odd* level. + min_level = min_level.new_lowest_ge_rtl().expect("Level error"); + + while max_level >= min_level { + // Look for the start of a sequence of consecutive runs of max_level or higher. + let mut seq_start = 0; + while seq_start < run_count { + if levels[runs[seq_start].start] < max_level { + seq_start += 1; + continue; + } + + // Found the start of a sequence. Now find the end. + let mut seq_end = seq_start + 1; + while seq_end < run_count { + if levels[runs[seq_end].start] < max_level { + break; + } + seq_end += 1; + } + + // Reverse the runs within this sequence. + runs[seq_start..seq_end].reverse(); + + seq_start = seq_end; + } + max_level.lower(1).expect( + "Lowering embedding level below zero", + ); + } + + runs +} diff --git a/unicode-bidi/src/explicit.rs b/unicode-bidi/src/explicit.rs new file mode 100644 index 000000000..4f6f22f6c --- /dev/null +++ b/unicode-bidi/src/explicit.rs @@ -0,0 +1,186 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 3.3.2 Explicit Levels and Directions +//! +//! <http://www.unicode.org/reports/tr9/#Explicit_Levels_and_Directions> + +use super::char_data::{BidiClass, is_rtl}; +use super::level::Level; + +use BidiClass::*; + +/// Compute explicit embedding levels for one paragraph of text (X1-X8). +/// +/// `processing_classes[i]` must contain the `BidiClass` of the char at byte index `i`, +/// for each char in `text`. +#[cfg_attr(feature = "flame_it", flame)] +pub fn compute( + text: &str, + para_level: Level, + original_classes: &[BidiClass], + levels: &mut [Level], + processing_classes: &mut [BidiClass], +) { + assert_eq!(text.len(), original_classes.len()); + + // <http://www.unicode.org/reports/tr9/#X1> + let mut stack = DirectionalStatusStack::new(); + stack.push(para_level, OverrideStatus::Neutral); + + let mut overflow_isolate_count = 0u32; + let mut overflow_embedding_count = 0u32; + let mut valid_isolate_count = 0u32; + + for (i, c) in text.char_indices() { + match original_classes[i] { + + // Rules X2-X5c + RLE | LRE | RLO | LRO | RLI | LRI | FSI => { + let last_level = stack.last().level; + + // X5a-X5c: Isolate initiators get the level of the last entry on the stack. + let is_isolate = matches!(original_classes[i], RLI | LRI | FSI); + if is_isolate { + levels[i] = last_level; + match stack.last().status { + OverrideStatus::RTL => processing_classes[i] = R, + OverrideStatus::LTR => processing_classes[i] = L, + _ => {} + } + } + + let new_level = if is_rtl(original_classes[i]) { + last_level.new_explicit_next_rtl() + } else { + last_level.new_explicit_next_ltr() + }; + if new_level.is_ok() && overflow_isolate_count == 0 && + overflow_embedding_count == 0 + { + let new_level = new_level.unwrap(); + stack.push( + new_level, + match original_classes[i] { + RLO => OverrideStatus::RTL, + LRO => OverrideStatus::LTR, + RLI | LRI | FSI => OverrideStatus::Isolate, + _ => OverrideStatus::Neutral, + }, + ); + if is_isolate { + valid_isolate_count += 1; + } else { + // The spec doesn't explicitly mention this step, but it is necessary. + // See the reference implementations for comparison. + levels[i] = new_level; + } + } else if is_isolate { + overflow_isolate_count += 1; + } else if overflow_isolate_count == 0 { + overflow_embedding_count += 1; + } + } + + // <http://www.unicode.org/reports/tr9/#X6a> + PDI => { + if overflow_isolate_count > 0 { + overflow_isolate_count -= 1; + } else if valid_isolate_count > 0 { + overflow_embedding_count = 0; + loop { + // Pop everything up to and including the last Isolate status. + match stack.vec.pop() { + None | + Some(Status { status: OverrideStatus::Isolate, .. }) => break, + _ => continue, + } + } + valid_isolate_count -= 1; + } + let last = stack.last(); + levels[i] = last.level; + match last.status { + OverrideStatus::RTL => processing_classes[i] = R, + OverrideStatus::LTR => processing_classes[i] = L, + _ => {} + } + } + + // <http://www.unicode.org/reports/tr9/#X7> + PDF => { + if overflow_isolate_count > 0 { + continue; + } + if overflow_embedding_count > 0 { + overflow_embedding_count -= 1; + continue; + } + if stack.last().status != OverrideStatus::Isolate && stack.vec.len() >= 2 { + stack.vec.pop(); + } + // The spec doesn't explicitly mention this step, but it is necessary. + // See the reference implementations for comparison. + levels[i] = stack.last().level; + } + + // Nothing + B | BN => {} + + // <http://www.unicode.org/reports/tr9/#X6> + _ => { + let last = stack.last(); + levels[i] = last.level; + match last.status { + OverrideStatus::RTL => processing_classes[i] = R, + OverrideStatus::LTR => processing_classes[i] = L, + _ => {} + } + } + } + + // Handle multi-byte characters. + for j in 1..c.len_utf8() { + levels[i + j] = levels[i]; + processing_classes[i + j] = processing_classes[i]; + } + } +} + +/// Entries in the directional status stack: +struct Status { + level: Level, + status: OverrideStatus, +} + +#[derive(PartialEq)] +enum OverrideStatus { + Neutral, + RTL, + LTR, + Isolate, +} + +struct DirectionalStatusStack { + vec: Vec<Status>, +} + +impl DirectionalStatusStack { + fn new() -> Self { + DirectionalStatusStack { vec: Vec::with_capacity(Level::max_explicit_depth() as usize + 2) } + } + + fn push(&mut self, level: Level, status: OverrideStatus) { + self.vec.push(Status { level, status }); + } + + fn last(&self) -> &Status { + self.vec.last().unwrap() + } +} diff --git a/unicode-bidi/src/format_chars.rs b/unicode-bidi/src/format_chars.rs new file mode 100644 index 000000000..5b19b5e76 --- /dev/null +++ b/unicode-bidi/src/format_chars.rs @@ -0,0 +1,42 @@ +// Copyright 2017 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Directional Formatting Characters +//! +//! <http://www.unicode.org/reports/tr9/#Directional_Formatting_Characters> + +// == Implicit == +/// ARABIC LETTER MARK +pub const ALM: char = '\u{061C}'; +/// LEFT-TO-RIGHT MARK +pub const LRM: char = '\u{200E}'; +/// RIGHT-TO-LEFT MARK +pub const RLM: char = '\u{200F}'; + +// == Explicit Isolates == +/// LEFT‑TO‑RIGHT ISOLATE +pub const LRI: char = '\u{2066}'; +/// RIGHT‑TO‑LEFT ISOLATE +pub const RLI: char = '\u{2067}'; +/// FIRST STRONG ISOLATE +pub const FSI: char = '\u{2068}'; +/// POP DIRECTIONAL ISOLATE +pub const PDI: char = '\u{2069}'; + +// == Explicit Embeddings and Overrides == +/// LEFT-TO-RIGHT EMBEDDING +pub const LRE: char = '\u{202A}'; +/// RIGHT-TO-LEFT EMBEDDING +pub const RLE: char = '\u{202B}'; +/// POP DIRECTIONAL FORMATTING +pub const PDF: char = '\u{202C}'; +/// LEFT-TO-RIGHT OVERRIDE +pub const LRO: char = '\u{202D}'; +/// RIGHT-TO-LEFT OVERRIDE +pub const RLO: char = '\u{202E}'; diff --git a/unicode-bidi/src/implicit.rs b/unicode-bidi/src/implicit.rs new file mode 100644 index 000000000..4344ea3d6 --- /dev/null +++ b/unicode-bidi/src/implicit.rs @@ -0,0 +1,228 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 3.3.4 - 3.3.6. Resolve implicit levels and types. + +use std::cmp::max; + +use super::char_data::BidiClass; +use super::prepare::{IsolatingRunSequence, LevelRun, not_removed_by_x9, removed_by_x9}; +use super::level::Level; + +use BidiClass::*; + +/// 3.3.4 Resolving Weak Types +/// +/// <http://www.unicode.org/reports/tr9/#Resolving_Weak_Types> +#[cfg_attr(feature = "flame_it", flame)] +pub fn resolve_weak(sequence: &IsolatingRunSequence, processing_classes: &mut [BidiClass]) { + // FIXME (#8): This function applies steps W1-W6 in a single pass. This can produce + // incorrect results in cases where a "later" rule changes the value of `prev_class` seen + // by an "earlier" rule. We should either split this into separate passes, or preserve + // extra state so each rule can see the correct previous class. + + // FIXME: Also, this could be the cause of increased failure for using longer-UTF-8 chars in + // conformance tests, like BidiTest:69635 (AL ET EN) + + let mut prev_class = sequence.sos; + let mut last_strong_is_al = false; + let mut et_run_indices = Vec::new(); // for W5 + + // Like sequence.runs.iter().flat_map(Clone::clone), but make indices itself clonable. + fn id(x: LevelRun) -> LevelRun { + x + } + let mut indices = sequence.runs.iter().cloned().flat_map( + id as fn(LevelRun) -> LevelRun, + ); + + while let Some(i) = indices.next() { + match processing_classes[i] { + // <http://www.unicode.org/reports/tr9/#W1> + NSM => { + processing_classes[i] = match prev_class { + RLI | LRI | FSI | PDI => ON, + _ => prev_class, + }; + } + EN => { + if last_strong_is_al { + // W2. If previous strong char was AL, change EN to AN. + processing_classes[i] = AN; + } else { + // W5. If a run of ETs is adjacent to an EN, change the ETs to EN. + for j in &et_run_indices { + processing_classes[*j] = EN; + } + et_run_indices.clear(); + } + } + // <http://www.unicode.org/reports/tr9/#W3> + AL => processing_classes[i] = R, + + // <http://www.unicode.org/reports/tr9/#W4> + ES | CS => { + let next_class = indices + .clone() + .map(|j| processing_classes[j]) + .find(not_removed_by_x9) + .unwrap_or(sequence.eos); + processing_classes[i] = match (prev_class, processing_classes[i], next_class) { + (EN, ES, EN) | (EN, CS, EN) => EN, + (AN, CS, AN) => AN, + (_, _, _) => ON, + } + } + // <http://www.unicode.org/reports/tr9/#W5> + ET => { + match prev_class { + EN => processing_classes[i] = EN, + _ => et_run_indices.push(i), // In case this is followed by an EN. + } + } + class => { + if removed_by_x9(class) { + continue; + } + } + } + + prev_class = processing_classes[i]; + match prev_class { + L | R => { + last_strong_is_al = false; + } + AL => { + last_strong_is_al = true; + } + _ => {} + } + if prev_class != ET { + // W6. If we didn't find an adjacent EN, turn any ETs into ON instead. + for j in &et_run_indices { + processing_classes[*j] = ON; + } + et_run_indices.clear(); + } + } + + // W7. If the previous strong char was L, change EN to L. + let mut last_strong_is_l = sequence.sos == L; + for run in &sequence.runs { + for i in run.clone() { + match processing_classes[i] { + EN if last_strong_is_l => { + processing_classes[i] = L; + } + L => { + last_strong_is_l = true; + } + R | AL => { + last_strong_is_l = false; + } + _ => {} + } + } + } +} + +/// 3.3.5 Resolving Neutral Types +/// +/// <http://www.unicode.org/reports/tr9/#Resolving_Neutral_Types> +#[cfg_attr(feature = "flame_it", flame)] +pub fn resolve_neutral( + sequence: &IsolatingRunSequence, + levels: &[Level], + processing_classes: &mut [BidiClass], +) { + let e: BidiClass = levels[sequence.runs[0].start].bidi_class(); + let mut indices = sequence.runs.iter().flat_map(Clone::clone); + let mut prev_class = sequence.sos; + + while let Some(mut i) = indices.next() { + // N0. Process bracket pairs. + // TODO + + // Process sequences of NI characters. + let mut ni_run = Vec::new(); + if is_NI(processing_classes[i]) { + // Consume a run of consecutive NI characters. + ni_run.push(i); + let mut next_class; + loop { + match indices.next() { + Some(j) => { + i = j; + if removed_by_x9(processing_classes[i]) { + continue; + } + next_class = processing_classes[j]; + if is_NI(next_class) { + ni_run.push(i); + } else { + break; + } + } + None => { + next_class = sequence.eos; + break; + } + }; + } + + // N1-N2. + // + // <http://www.unicode.org/reports/tr9/#N1> + // <http://www.unicode.org/reports/tr9/#N2> + let new_class = match (prev_class, next_class) { + (L, L) => L, + (R, R) | (R, AN) | (R, EN) | (AN, R) | (AN, AN) | (AN, EN) | (EN, R) | + (EN, AN) | (EN, EN) => R, + (_, _) => e, + }; + for j in &ni_run { + processing_classes[*j] = new_class; + } + ni_run.clear(); + } + prev_class = processing_classes[i]; + } +} + +/// 3.3.6 Resolving Implicit Levels +/// +/// Returns the maximum embedding level in the paragraph. +/// +/// <http://www.unicode.org/reports/tr9/#Resolving_Implicit_Levels> +#[cfg_attr(feature = "flame_it", flame)] +pub fn resolve_levels(original_classes: &[BidiClass], levels: &mut [Level]) -> Level { + let mut max_level = Level::ltr(); + + assert_eq!(original_classes.len(), levels.len()); + for i in 0..levels.len() { + match (levels[i].is_rtl(), original_classes[i]) { + (false, AN) | (false, EN) => levels[i].raise(2).expect("Level number error"), + (false, R) | (true, L) | (true, EN) | (true, AN) => { + levels[i].raise(1).expect("Level number error") + } + (_, _) => {} + } + max_level = max(max_level, levels[i]); + } + + max_level +} + +/// Neutral or Isolate formatting character (B, S, WS, ON, FSI, LRI, RLI, PDI) +/// +/// <http://www.unicode.org/reports/tr9/#NI> +#[allow(non_snake_case)] +fn is_NI(class: BidiClass) -> bool { + matches!(class, B | S | WS | ON | FSI | LRI | RLI | PDI) +} diff --git a/unicode-bidi/src/level.rs b/unicode-bidi/src/level.rs new file mode 100644 index 000000000..1c195a9c5 --- /dev/null +++ b/unicode-bidi/src/level.rs @@ -0,0 +1,382 @@ +// Copyright 2017 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Bidi Embedding Level +//! +//! See [`Level`](struct.Level.html) for more details. +//! +//! <http://www.unicode.org/reports/tr9/#BD2> + +use std::convert::{From, Into}; + +use super::char_data::BidiClass; + +/// Embedding Level +/// +/// Embedding Levels are numbers between 0 and 126 (inclusive), where even values denote a +/// left-to-right (LTR) direction and odd values a right-to-left (RTL) direction. +/// +/// This struct maintains a *valid* status for level numbers, meaning that creating a new level, or +/// mutating an existing level, with the value smaller than `0` (before conversion to `u8`) or +/// larger than 125 results in an `Error`. +/// +/// <http://www.unicode.org/reports/tr9/#BD2> +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Level(u8); + +pub const LTR_LEVEL: Level = Level(0); +pub const RTL_LEVEL: Level = Level(1); + +const MAX_DEPTH: u8 = 125; +/// During explicit level resolution, embedding level can go as high as `max_depth`. +pub const MAX_EXPLICIT_DEPTH: u8 = MAX_DEPTH; +/// During implicit level resolution, embedding level can go as high as `max_depth + 1`. +pub const MAX_IMPLICIT_DEPTH: u8 = MAX_DEPTH + 1; + +/// Errors that can occur on Level creation or mutation +#[derive(Debug, PartialEq)] +pub enum Error { + /// Out-of-range (invalid) embedding level number. + OutOfRangeNumber, +} + +impl Level { + /// New LTR level with smallest number value (0). + #[inline] + pub fn ltr() -> Level { + LTR_LEVEL + } + + /// New RTL level with smallest number value (1). + #[inline] + pub fn rtl() -> Level { + RTL_LEVEL + } + + /// Maximum depth of the directional status stack during implicit resolutions. + pub fn max_implicit_depth() -> u8 { + MAX_IMPLICIT_DEPTH + } + + /// Maximum depth of the directional status stack during explicit resolutions. + pub fn max_explicit_depth() -> u8 { + MAX_EXPLICIT_DEPTH + } + + // == Inquiries == + + /// Create new level, fail if number is larger than `max_depth + 1`. + #[inline] + pub fn new(number: u8) -> Result<Level, Error> { + if number <= MAX_IMPLICIT_DEPTH { + Ok(Level(number)) + } else { + Err(Error::OutOfRangeNumber) + } + } + + /// Create new level, fail if number is larger than `max_depth`. + #[inline] + pub fn new_explicit(number: u8) -> Result<Level, Error> { + if number <= MAX_EXPLICIT_DEPTH { + Ok(Level(number)) + } else { + Err(Error::OutOfRangeNumber) + } + } + + // == Inquiries == + + /// The level number. + #[inline] + pub fn number(&self) -> u8 { + self.0 + } + + /// If this level is left-to-right. + #[inline] + pub fn is_ltr(&self) -> bool { + self.0 % 2 == 0 + } + + /// If this level is right-to-left. + #[inline] + pub fn is_rtl(&self) -> bool { + self.0 % 2 == 1 + } + + // == Mutators == + + /// Raise level by `amount`, fail if number is larger than `max_depth + 1`. + #[inline] + pub fn raise(&mut self, amount: u8) -> Result<(), Error> { + match self.0.checked_add(amount) { + Some(number) => { + if number <= MAX_IMPLICIT_DEPTH { + self.0 = number; + Ok(()) + } else { + Err(Error::OutOfRangeNumber) + } + } + None => Err(Error::OutOfRangeNumber), + } + } + + /// Raise level by `amount`, fail if number is larger than `max_depth`. + #[inline] + pub fn raise_explicit(&mut self, amount: u8) -> Result<(), Error> { + match self.0.checked_add(amount) { + Some(number) => { + if number <= MAX_EXPLICIT_DEPTH { + self.0 = number; + Ok(()) + } else { + Err(Error::OutOfRangeNumber) + } + } + None => Err(Error::OutOfRangeNumber), + } + } + + /// Lower level by `amount`, fail if number goes below zero. + #[inline] + pub fn lower(&mut self, amount: u8) -> Result<(), Error> { + match self.0.checked_sub(amount) { + Some(number) => { + self.0 = number; + Ok(()) + } + None => Err(Error::OutOfRangeNumber), + } + } + + // == Helpers == + + /// The next LTR (even) level greater than this, or fail if number is larger than `max_depth`. + #[inline] + pub fn new_explicit_next_ltr(&self) -> Result<Level, Error> { + Level::new_explicit((self.0 + 2) & !1) + } + + /// The next RTL (odd) level greater than this, or fail if number is larger than `max_depth`. + #[inline] + pub fn new_explicit_next_rtl(&self) -> Result<Level, Error> { + Level::new_explicit((self.0 + 1) | 1) + } + + /// The lowest RTL (odd) level greater than or equal to this, or fail if number is larger than + /// `max_depth + 1`. + #[inline] + pub fn new_lowest_ge_rtl(&self) -> Result<Level, Error> { + Level::new(self.0 | 1) + } + + /// Generate a character type based on a level (as specified in steps X10 and N2). + #[inline] + pub fn bidi_class(&self) -> BidiClass { + if self.is_rtl() { + BidiClass::R + } else { + BidiClass::L + } + } + + pub fn vec(v: &[u8]) -> Vec<Level> { + v.iter().map(|&x| x.into()).collect() + } +} + +/// If levels has any RTL (odd) level +/// +/// This information is usually used to skip re-ordering of text when no RTL level is present +#[inline] +pub fn has_rtl(levels: &[Level]) -> bool { + levels.iter().any(|&lvl| lvl.is_rtl()) +} + +impl Into<u8> for Level { + /// Convert to the level number + #[inline] + fn into(self) -> u8 { + self.number() + } +} + +impl From<u8> for Level { + /// Create level by number + #[inline] + fn from(number: u8) -> Level { + Level::new(number).expect("Level number error") + } +} + +/// Used for matching levels in conformance tests +impl<'a> PartialEq<&'a str> for Level { + #[inline] + fn eq(&self, s: &&'a str) -> bool { + *s == "x" || *s == self.0.to_string() + } +} + +/// Used for matching levels in conformance tests +impl<'a> PartialEq<String> for Level { + #[inline] + fn eq(&self, s: &String) -> bool { + self == &s.as_str() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new() { + assert_eq!(Level::new(0), Ok(Level(0))); + assert_eq!(Level::new(1), Ok(Level(1))); + assert_eq!(Level::new(10), Ok(Level(10))); + assert_eq!(Level::new(125), Ok(Level(125))); + assert_eq!(Level::new(126), Ok(Level(126))); + assert_eq!(Level::new(127), Err(Error::OutOfRangeNumber)); + assert_eq!(Level::new(255), Err(Error::OutOfRangeNumber)); + } + + #[test] + fn test_new_explicit() { + assert_eq!(Level::new_explicit(0), Ok(Level(0))); + assert_eq!(Level::new_explicit(1), Ok(Level(1))); + assert_eq!(Level::new_explicit(10), Ok(Level(10))); + assert_eq!(Level::new_explicit(125), Ok(Level(125))); + assert_eq!(Level::new_explicit(126), Err(Error::OutOfRangeNumber)); + assert_eq!(Level::new_explicit(255), Err(Error::OutOfRangeNumber)); + } + + #[test] + fn test_is_ltr() { + assert_eq!(Level(0).is_ltr(), true); + assert_eq!(Level(1).is_ltr(), false); + assert_eq!(Level(10).is_ltr(), true); + assert_eq!(Level(11).is_ltr(), false); + assert_eq!(Level(124).is_ltr(), true); + assert_eq!(Level(125).is_ltr(), false); + } + + #[test] + fn test_is_rtl() { + assert_eq!(Level(0).is_rtl(), false); + assert_eq!(Level(1).is_rtl(), true); + assert_eq!(Level(10).is_rtl(), false); + assert_eq!(Level(11).is_rtl(), true); + assert_eq!(Level(124).is_rtl(), false); + assert_eq!(Level(125).is_rtl(), true); + } + + #[test] + fn test_raise() { + let mut level = Level::ltr(); + assert_eq!(level.number(), 0); + assert!(level.raise(100).is_ok()); + assert_eq!(level.number(), 100); + assert!(level.raise(26).is_ok()); + assert_eq!(level.number(), 126); + assert!(level.raise(1).is_err()); // invalid! + assert!(level.raise(250).is_err()); // overflow! + assert_eq!(level.number(), 126); + } + + #[test] + fn test_raise_explicit() { + let mut level = Level::ltr(); + assert_eq!(level.number(), 0); + assert!(level.raise_explicit(100).is_ok()); + assert_eq!(level.number(), 100); + assert!(level.raise_explicit(25).is_ok()); + assert_eq!(level.number(), 125); + assert!(level.raise_explicit(1).is_err()); // invalid! + assert!(level.raise_explicit(250).is_err()); // overflow! + assert_eq!(level.number(), 125); + } + + #[test] + fn test_lower() { + let mut level = Level::rtl(); + assert_eq!(level.number(), 1); + assert!(level.lower(1).is_ok()); + assert_eq!(level.number(), 0); + assert!(level.lower(1).is_err()); // underflow! + assert!(level.lower(250).is_err()); // underflow! + assert_eq!(level.number(), 0); + } + + #[test] + fn test_has_rtl() { + assert_eq!(has_rtl(&Level::vec(&[0, 0, 0])), false); + assert_eq!(has_rtl(&Level::vec(&[0, 1, 0])), true); + assert_eq!(has_rtl(&Level::vec(&[0, 2, 0])), false); + assert_eq!(has_rtl(&Level::vec(&[0, 125, 0])), true); + assert_eq!(has_rtl(&Level::vec(&[0, 126, 0])), false); + } + + #[test] + fn test_into() { + let level = Level::rtl(); + assert_eq!(1u8, level.into()); + } + + #[test] + fn test_vec() { + assert_eq!( + Level::vec(&[0, 1, 125]), + vec![Level(0), Level(1), Level(125)] + ); + } + + #[test] + fn test_str_eq() { + assert_eq!(Level::vec(&[0, 1, 4, 125]), vec!["0", "1", "x", "125"]); + assert_ne!(Level::vec(&[0, 1, 4, 125]), vec!["0", "1", "5", "125"]); + } + + #[test] + fn test_string_eq() { + assert_eq!( + Level::vec(&[0, 1, 4, 125]), + vec!["0".to_string(), "1".to_string(), "x".to_string(), "125".to_string()] + ); + } +} + +#[cfg(all(feature = "serde", test))] +mod serde_tests { + use serde_test::{Token, assert_tokens}; + use super::*; + + #[test] + fn test_statics() { + assert_tokens( + &Level::ltr(), + &[Token::NewtypeStruct { name: "Level" }, Token::U8(0)], + ); + assert_tokens( + &Level::rtl(), + &[Token::NewtypeStruct { name: "Level" }, Token::U8(1)], + ); + } + + #[test] + fn test_new() { + let level = Level::new(42).unwrap(); + assert_tokens( + &level, + &[Token::NewtypeStruct { name: "Level" }, Token::U8(42)], + ); + } +} diff --git a/unicode-bidi/src/lib.rs b/unicode-bidi/src/lib.rs new file mode 100644 index 000000000..5e1d3e204 --- /dev/null +++ b/unicode-bidi/src/lib.rs @@ -0,0 +1,890 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This crate implements the [Unicode Bidirectional Algorithm][tr9] for display of mixed +//! right-to-left and left-to-right text. It is written in safe Rust, compatible with the +//! current stable release. +//! +//! ## Example +//! +//! ```rust +//! use unicode_bidi::BidiInfo; +//! +//! // This example text is defined using `concat!` because some browsers +//! // and text editors have trouble displaying bidi strings. +//! let text = concat![ +//! "א", +//! "ב", +//! "ג", +//! "a", +//! "b", +//! "c", +//! ]; +//! +//! // Resolve embedding levels within the text. Pass `None` to detect the +//! // paragraph level automatically. +//! let bidi_info = BidiInfo::new(&text, None); +//! +//! // This paragraph has embedding level 1 because its first strong character is RTL. +//! assert_eq!(bidi_info.paragraphs.len(), 1); +//! let para = &bidi_info.paragraphs[0]; +//! assert_eq!(para.level.number(), 1); +//! assert_eq!(para.level.is_rtl(), true); +//! +//! // Re-ordering is done after wrapping each paragraph into a sequence of +//! // lines. For this example, I'll just use a single line that spans the +//! // entire paragraph. +//! let line = para.range.clone(); +//! +//! let display = bidi_info.reorder_line(para, line); +//! assert_eq!(display, concat![ +//! "a", +//! "b", +//! "c", +//! "ג", +//! "ב", +//! "א", +//! ]); +//! ``` +//! +//! [tr9]: <http://www.unicode.org/reports/tr9/> + +#![forbid(unsafe_code)] + +#![cfg_attr(feature="flame_it", feature(plugin, custom_attribute))] +#![cfg_attr(feature="flame_it", plugin(flamer))] + + +#[macro_use] +extern crate matches; + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +#[cfg(all(feature = "serde", test))] +extern crate serde_test; + +#[cfg(feature = "flame_it")] +extern crate flame; + + +pub mod deprecated; +pub mod format_chars; +pub mod level; + +mod char_data; +mod explicit; +mod implicit; +mod prepare; + +pub use char_data::{BidiClass, bidi_class, UNICODE_VERSION}; +pub use level::{Level, LTR_LEVEL, RTL_LEVEL}; +pub use prepare::LevelRun; + +use std::borrow::Cow; +use std::cmp::{max, min}; +use std::iter::repeat; +use std::ops::Range; + +use BidiClass::*; +use format_chars as chars; + + +/// Bidi information about a single paragraph +#[derive(Debug, PartialEq)] +pub struct ParagraphInfo { + /// The paragraphs boundaries within the text, as byte indices. + /// + /// TODO: Shrink this to only include the starting index? + pub range: Range<usize>, + + /// The paragraph embedding level. + /// + /// <http://www.unicode.org/reports/tr9/#BD4> + pub level: Level, +} + +/// Initial bidi information of the text. +/// +/// Contains the text paragraphs and `BidiClass` of its characters. +#[derive(PartialEq, Debug)] +pub struct InitialInfo<'text> { + /// The text + pub text: &'text str, + + /// The BidiClass of the character at each byte in the text. + /// If a character is multiple bytes, its class will appear multiple times in the vector. + pub original_classes: Vec<BidiClass>, + + /// The boundaries and level of each paragraph within the text. + pub paragraphs: Vec<ParagraphInfo>, +} + +impl<'text> InitialInfo<'text> { + /// Find the paragraphs and BidiClasses in a string of text. + /// + /// <http://www.unicode.org/reports/tr9/#The_Paragraph_Level> + /// + /// Also sets the class for each First Strong Isolate initiator (FSI) to LRI or RLI if a strong + /// character is found before the matching PDI. If no strong character is found, the class will + /// remain FSI, and it's up to later stages to treat these as LRI when needed. + #[cfg_attr(feature = "flame_it", flame)] + pub fn new(text: &str, default_para_level: Option<Level>) -> InitialInfo { + let mut original_classes = Vec::with_capacity(text.len()); + + // The stack contains the starting byte index for each nested isolate we're inside. + let mut isolate_stack = Vec::new(); + let mut paragraphs = Vec::new(); + + let mut para_start = 0; + let mut para_level = default_para_level; + + #[cfg(feature = "flame_it")] flame::start("InitialInfo::new(): iter text.char_indices()"); + + for (i, c) in text.char_indices() { + let class = bidi_class(c); + + #[cfg(feature = "flame_it")] flame::start("original_classes.extend()"); + + original_classes.extend(repeat(class).take(c.len_utf8())); + + #[cfg(feature = "flame_it")] flame::end("original_classes.extend()"); + + match class { + + B => { + // P1. Split the text into separate paragraphs. The paragraph separator is kept + // with the previous paragraph. + let para_end = i + c.len_utf8(); + paragraphs.push(ParagraphInfo { + range: para_start..para_end, + // P3. If no character is found in p2, set the paragraph level to zero. + level: para_level.unwrap_or(LTR_LEVEL), + }); + // Reset state for the start of the next paragraph. + para_start = para_end; + // TODO: Support defaulting to direction of previous paragraph + // + // <http://www.unicode.org/reports/tr9/#HL1> + para_level = default_para_level; + isolate_stack.clear(); + } + + L | R | AL => { + match isolate_stack.last() { + Some(&start) => { + if original_classes[start] == FSI { + // X5c. If the first strong character between FSI and its matching + // PDI is R or AL, treat it as RLI. Otherwise, treat it as LRI. + for j in 0..chars::FSI.len_utf8() { + original_classes[start + j] = + if class == L { LRI } else { RLI }; + } + } + } + + None => { + if para_level.is_none() { + // P2. Find the first character of type L, AL, or R, while skipping + // any characters between an isolate initiator and its matching + // PDI. + para_level = Some(if class != L { RTL_LEVEL } else { LTR_LEVEL }); + } + } + } + } + + RLI | LRI | FSI => { + isolate_stack.push(i); + } + + PDI => { + isolate_stack.pop(); + } + + _ => {} + } + } + if para_start < text.len() { + paragraphs.push(ParagraphInfo { + range: para_start..text.len(), + level: para_level.unwrap_or(LTR_LEVEL), + }); + } + assert_eq!(original_classes.len(), text.len()); + + #[cfg(feature = "flame_it")] flame::end("InitialInfo::new(): iter text.char_indices()"); + + InitialInfo { + text, + original_classes, + paragraphs, + } + } +} + +/// Bidi information of the text. +/// +/// The `original_classes` and `levels` vectors are indexed by byte offsets into the text. If a +/// character is multiple bytes wide, then its class and level will appear multiple times in these +/// vectors. +// TODO: Impl `struct StringProperty<T> { values: Vec<T> }` and use instead of Vec<T> +#[derive(Debug, PartialEq)] +pub struct BidiInfo<'text> { + /// The text + pub text: &'text str, + + /// The BidiClass of the character at each byte in the text. + pub original_classes: Vec<BidiClass>, + + /// The directional embedding level of each byte in the text. + pub levels: Vec<Level>, + + /// The boundaries and paragraph embedding level of each paragraph within the text. + /// + /// TODO: Use SmallVec or similar to avoid overhead when there are only one or two paragraphs? + /// Or just don't include the first paragraph, which always starts at 0? + pub paragraphs: Vec<ParagraphInfo>, +} + +impl<'text> BidiInfo<'text> { + /// Split the text into paragraphs and determine the bidi embedding levels for each paragraph. + /// + /// TODO: In early steps, check for special cases that allow later steps to be skipped. like + /// text that is entirely LTR. See the `nsBidi` class from Gecko for comparison. + /// + /// TODO: Support auto-RTL base direction + #[cfg_attr(feature = "flame_it", flame)] + pub fn new(text: &str, default_para_level: Option<Level>) -> BidiInfo { + let InitialInfo { + original_classes, + paragraphs, + .. + } = InitialInfo::new(text, default_para_level); + + let mut levels = Vec::<Level>::with_capacity(text.len()); + let mut processing_classes = original_classes.clone(); + + for para in ¶graphs { + let text = &text[para.range.clone()]; + let original_classes = &original_classes[para.range.clone()]; + let processing_classes = &mut processing_classes[para.range.clone()]; + + let new_len = levels.len() + para.range.len(); + levels.resize(new_len, para.level); + let levels = &mut levels[para.range.clone()]; + + explicit::compute( + text, + para.level, + original_classes, + levels, + processing_classes, + ); + + let sequences = prepare::isolating_run_sequences(para.level, original_classes, levels); + for sequence in &sequences { + implicit::resolve_weak(sequence, processing_classes); + implicit::resolve_neutral(sequence, levels, processing_classes); + } + implicit::resolve_levels(processing_classes, levels); + + assign_levels_to_removed_chars(para.level, original_classes, levels); + } + + BidiInfo { + text, + original_classes, + paragraphs, + levels, + } + } + + /// Re-order a line based on resolved levels and return only the embedding levels, one `Level` + /// per *byte*. + #[cfg_attr(feature = "flame_it", flame)] + pub fn reordered_levels(&self, para: &ParagraphInfo, line: Range<usize>) -> Vec<Level> { + let (levels, _) = self.visual_runs(para, line.clone()); + levels + } + + /// Re-order a line based on resolved levels and return only the embedding levels, one `Level` + /// per *character*. + #[cfg_attr(feature = "flame_it", flame)] + pub fn reordered_levels_per_char( + &self, + para: &ParagraphInfo, + line: Range<usize>, + ) -> Vec<Level> { + let levels = self.reordered_levels(para, line); + self.text.char_indices().map(|(i, _)| levels[i]).collect() + } + + + /// Re-order a line based on resolved levels and return the line in display order. + #[cfg_attr(feature = "flame_it", flame)] + pub fn reorder_line(&self, para: &ParagraphInfo, line: Range<usize>) -> Cow<'text, str> { + let (levels, runs) = self.visual_runs(para, line.clone()); + + // If all isolating run sequences are LTR, no reordering is needed + if runs.iter().all(|run| levels[run.start].is_ltr()) { + return self.text[line.clone()].into(); + } + + let mut result = String::with_capacity(line.len()); + for run in runs { + if levels[run.start].is_rtl() { + result.extend(self.text[run].chars().rev()); + } else { + result.push_str(&self.text[run]); + } + } + result.into() + } + + /// Find the level runs within a line and return them in visual order. + /// + /// `line` is a range of bytes indices within `levels`. + /// + /// <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels> + #[cfg_attr(feature = "flame_it", flame)] + pub fn visual_runs( + &self, + para: &ParagraphInfo, + line: Range<usize>, + ) -> (Vec<Level>, Vec<LevelRun>) { + assert!(line.start <= self.levels.len()); + assert!(line.end <= self.levels.len()); + + let mut levels = self.levels.clone(); + + // Reset some whitespace chars to paragraph level. + // <http://www.unicode.org/reports/tr9/#L1> + let line_str: &str = &self.text[line.clone()]; + let mut reset_from: Option<usize> = Some(0); + let mut reset_to: Option<usize> = None; + for (i, c) in line_str.char_indices() { + match self.original_classes[i] { + // Ignored by X9 + RLE | LRE | RLO | LRO | PDF | BN => {} + // Segment separator, Paragraph separator + B | S => { + assert_eq!(reset_to, None); + reset_to = Some(i + c.len_utf8()); + if reset_from == None { + reset_from = Some(i); + } + } + // Whitespace, isolate formatting + WS | FSI | LRI | RLI | PDI => { + if reset_from == None { + reset_from = Some(i); + } + } + _ => { + reset_from = None; + } + } + if let (Some(from), Some(to)) = (reset_from, reset_to) { + #[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))] + for j in from..to { + levels[j] = para.level; + } + reset_from = None; + reset_to = None; + } + } + if let Some(from) = reset_from { + #[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))] + for j in from..line_str.len() { + levels[j] = para.level; + } + } + + // Find consecutive level runs. + let mut runs = Vec::new(); + let mut start = line.start; + let mut run_level = levels[start]; + let mut min_level = run_level; + let mut max_level = run_level; + + for (i, &new_level) in levels.iter().enumerate().take(line.end).skip(start + 1) { + if new_level != run_level { + // End of the previous run, start of a new one. + runs.push(start..i); + start = i; + run_level = new_level; + min_level = min(run_level, min_level); + max_level = max(run_level, max_level); + } + } + runs.push(start..line.end); + + let run_count = runs.len(); + + // Re-order the odd runs. + // <http://www.unicode.org/reports/tr9/#L2> + + // Stop at the lowest *odd* level. + min_level = min_level.new_lowest_ge_rtl().expect("Level error"); + + while max_level >= min_level { + // Look for the start of a sequence of consecutive runs of max_level or higher. + let mut seq_start = 0; + while seq_start < run_count { + if self.levels[runs[seq_start].start] < max_level { + seq_start += 1; + continue; + } + + // Found the start of a sequence. Now find the end. + let mut seq_end = seq_start + 1; + while seq_end < run_count { + if self.levels[runs[seq_end].start] < max_level { + break; + } + seq_end += 1; + } + + // Reverse the runs within this sequence. + runs[seq_start..seq_end].reverse(); + + seq_start = seq_end; + } + max_level.lower(1).expect( + "Lowering embedding level below zero", + ); + } + + (levels, runs) + } + + /// If processed text has any computed RTL levels + /// + /// This information is usually used to skip re-ordering of text when no RTL level is present + #[inline] + pub fn has_rtl(&self) -> bool { + level::has_rtl(&self.levels) + } +} + +/// Assign levels to characters removed by rule X9. +/// +/// The levels assigned to these characters are not specified by the algorithm. This function +/// assigns each one the level of the previous character, to avoid breaking level runs. +#[cfg_attr(feature = "flame_it", flame)] +fn assign_levels_to_removed_chars(para_level: Level, classes: &[BidiClass], levels: &mut [Level]) { + for i in 0..levels.len() { + if prepare::removed_by_x9(classes[i]) { + levels[i] = if i > 0 { levels[i - 1] } else { para_level }; + } + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_initial_text_info() { + let text = "a1"; + assert_eq!( + InitialInfo::new(text, None), + InitialInfo { + text, + original_classes: vec![L, EN], + paragraphs: vec![ + ParagraphInfo { + range: 0..2, + level: LTR_LEVEL, + }, + ], + } + ); + + let text = "غ א"; + assert_eq!( + InitialInfo::new(text, None), + InitialInfo { + text, + original_classes: vec![AL, AL, WS, R, R], + paragraphs: vec![ + ParagraphInfo { + range: 0..5, + level: RTL_LEVEL, + }, + ], + } + ); + + let text = "a\u{2029}b"; + assert_eq!( + InitialInfo::new(text, None), + InitialInfo { + text, + original_classes: vec![L, B, B, B, L], + paragraphs: vec![ + ParagraphInfo { + range: 0..4, + level: LTR_LEVEL, + }, + ParagraphInfo { + range: 4..5, + level: LTR_LEVEL, + }, + ], + } + ); + + let text = format!("{}א{}a", chars::FSI, chars::PDI); + assert_eq!( + InitialInfo::new(&text, None), + InitialInfo { + text: &text, + original_classes: vec![RLI, RLI, RLI, R, R, PDI, PDI, PDI, L], + paragraphs: vec![ + ParagraphInfo { + range: 0..9, + level: LTR_LEVEL, + }, + ], + } + ); + } + + #[test] + fn test_process_text() { + let text = "abc123"; + assert_eq!( + BidiInfo::new(text, Some(LTR_LEVEL)), + BidiInfo { + text, + levels: Level::vec(&[0, 0, 0, 0, 0, 0]), + original_classes: vec![L, L, L, EN, EN, EN], + paragraphs: vec![ + ParagraphInfo { + range: 0..6, + level: LTR_LEVEL, + }, + ], + } + ); + + let text = "abc אבג"; + assert_eq!( + BidiInfo::new(text, Some(LTR_LEVEL)), + BidiInfo { + text, + levels: Level::vec(&[0, 0, 0, 0, 1, 1, 1, 1, 1, 1]), + original_classes: vec![L, L, L, WS, R, R, R, R, R, R], + paragraphs: vec![ + ParagraphInfo { + range: 0..10, + level: LTR_LEVEL, + }, + ], + } + ); + assert_eq!( + BidiInfo::new(text, Some(RTL_LEVEL)), + BidiInfo { + text, + levels: Level::vec(&[2, 2, 2, 1, 1, 1, 1, 1, 1, 1]), + original_classes: vec![L, L, L, WS, R, R, R, R, R, R], + paragraphs: vec![ + ParagraphInfo { + range: 0..10, + level: RTL_LEVEL, + }, + ], + } + ); + + let text = "אבג abc"; + assert_eq!( + BidiInfo::new(text, Some(LTR_LEVEL)), + BidiInfo { + text, + levels: Level::vec(&[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]), + original_classes: vec![R, R, R, R, R, R, WS, L, L, L], + paragraphs: vec![ + ParagraphInfo { + range: 0..10, + level: LTR_LEVEL, + }, + ], + } + ); + assert_eq!( + BidiInfo::new(text, None), + BidiInfo { + text, + levels: Level::vec(&[1, 1, 1, 1, 1, 1, 1, 2, 2, 2]), + original_classes: vec![R, R, R, R, R, R, WS, L, L, L], + paragraphs: vec![ + ParagraphInfo { + range: 0..10, + level: RTL_LEVEL, + }, + ], + } + ); + + let text = "غ2ظ א2ג"; + assert_eq!( + BidiInfo::new(text, Some(LTR_LEVEL)), + BidiInfo { + text, + levels: Level::vec(&[1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1]), + original_classes: vec![AL, AL, EN, AL, AL, WS, R, R, EN, R, R], + paragraphs: vec![ + ParagraphInfo { + range: 0..11, + level: LTR_LEVEL, + }, + ], + } + ); + + let text = "a א.\nג"; + assert_eq!( + BidiInfo::new(text, None), + BidiInfo { + text, + original_classes: vec![L, WS, R, R, CS, B, R, R], + levels: Level::vec(&[0, 0, 1, 1, 0, 0, 1, 1]), + paragraphs: vec![ + ParagraphInfo { + range: 0..6, + level: LTR_LEVEL, + }, + ParagraphInfo { + range: 6..8, + level: RTL_LEVEL, + }, + ], + } + ); + + /// BidiTest:69635 (AL ET EN) + let bidi_info = BidiInfo::new("\u{060B}\u{20CF}\u{06F9}", None); + assert_eq!(bidi_info.original_classes, vec![AL, AL, ET, ET, ET, EN, EN]); + } + + #[test] + fn test_bidi_info_has_rtl() { + // ASCII only + assert_eq!(BidiInfo::new("123", None).has_rtl(), false); + assert_eq!(BidiInfo::new("123", Some(LTR_LEVEL)).has_rtl(), false); + assert_eq!(BidiInfo::new("123", Some(RTL_LEVEL)).has_rtl(), false); + assert_eq!(BidiInfo::new("abc", None).has_rtl(), false); + assert_eq!(BidiInfo::new("abc", Some(LTR_LEVEL)).has_rtl(), false); + assert_eq!(BidiInfo::new("abc", Some(RTL_LEVEL)).has_rtl(), false); + assert_eq!(BidiInfo::new("abc 123", None).has_rtl(), false); + assert_eq!(BidiInfo::new("abc\n123", None).has_rtl(), false); + + // With Hebrew + assert_eq!(BidiInfo::new("אבּג", None).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג", Some(LTR_LEVEL)).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג", Some(RTL_LEVEL)).has_rtl(), true); + assert_eq!(BidiInfo::new("abc אבּג", None).has_rtl(), true); + assert_eq!(BidiInfo::new("abc\nאבּג", None).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג abc", None).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג\nabc", None).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג 123", None).has_rtl(), true); + assert_eq!(BidiInfo::new("אבּג\n123", None).has_rtl(), true); + } + + fn reorder_paras(text: &str) -> Vec<Cow<str>> { + let bidi_info = BidiInfo::new(text, None); + bidi_info + .paragraphs + .iter() + .map(|para| bidi_info.reorder_line(para, para.range.clone())) + .collect() + } + + #[test] + fn test_reorder_line() { + /// Bidi_Class: L L L B L L L B L L L + assert_eq!( + reorder_paras("abc\ndef\nghi"), + vec!["abc\n", "def\n", "ghi"] + ); + + /// Bidi_Class: L L EN B L L EN B L L EN + assert_eq!( + reorder_paras("ab1\nde2\ngh3"), + vec!["ab1\n", "de2\n", "gh3"] + ); + + /// Bidi_Class: L L L B AL AL AL + assert_eq!(reorder_paras("abc\nابج"), vec!["abc\n", "جبا"]); + + /// Bidi_Class: AL AL AL B L L L + assert_eq!(reorder_paras("ابج\nabc"), vec!["\nجبا", "abc"]); + + assert_eq!(reorder_paras("1.-2"), vec!["1.-2"]); + assert_eq!(reorder_paras("1-.2"), vec!["1-.2"]); + assert_eq!(reorder_paras("abc אבג"), vec!["abc גבא"]); + + // Numbers being weak LTR characters, cannot reorder strong RTL + assert_eq!(reorder_paras("123 אבג"), vec!["גבא 123"]); + + assert_eq!(reorder_paras("abc\u{202A}def"), vec!["abc\u{202A}def"]); + + assert_eq!( + reorder_paras("abc\u{202A}def\u{202C}ghi"), + vec!["abc\u{202A}def\u{202C}ghi"] + ); + + assert_eq!( + reorder_paras("abc\u{2066}def\u{2069}ghi"), + vec!["abc\u{2066}def\u{2069}ghi"] + ); + + // Testing for RLE Character + assert_eq!( + reorder_paras("\u{202B}abc אבג\u{202C}"), + vec!["\u{202B}\u{202C}גבא abc"] + ); + + // Testing neutral characters + assert_eq!(reorder_paras("אבג? אבג"), vec!["גבא ?גבא"]); + + // Testing neutral characters with special case + assert_eq!(reorder_paras("A אבג?"), vec!["A גבא?"]); + + // Testing neutral characters with Implicit RTL Marker + assert_eq!( + reorder_paras("A אבג?\u{200F}"), + vec!["A \u{200F}?גבא"] + ); + assert_eq!(reorder_paras("אבג abc"), vec!["abc גבא"]); + assert_eq!( + reorder_paras("abc\u{2067}.-\u{2069}ghi"), + vec!["abc\u{2067}-.\u{2069}ghi"] + ); + + assert_eq!( + reorder_paras("Hello, \u{2068}\u{202E}world\u{202C}\u{2069}!"), + vec!["Hello, \u{2068}\u{202E}\u{202C}dlrow\u{2069}!"] + ); + + // With mirrorable characters in RTL run + assert_eq!(reorder_paras("א(ב)ג."), vec![".ג)ב(א"]); + + // With mirrorable characters on level boundry + assert_eq!( + reorder_paras("אב(גד[&ef].)gh"), + vec!["ef].)gh&[דג(בא"] + ); + } + + fn reordered_levels_for_paras(text: &str) -> Vec<Vec<Level>> { + let bidi_info = BidiInfo::new(text, None); + bidi_info + .paragraphs + .iter() + .map(|para| bidi_info.reordered_levels(para, para.range.clone())) + .collect() + } + + fn reordered_levels_per_char_for_paras(text: &str) -> Vec<Vec<Level>> { + let bidi_info = BidiInfo::new(text, None); + bidi_info + .paragraphs + .iter() + .map(|para| { + bidi_info.reordered_levels_per_char(para, para.range.clone()) + }) + .collect() + } + + #[test] + fn test_reordered_levels() { + + /// BidiTest:946 (LRI PDI) + let text = "\u{2067}\u{2069}"; + assert_eq!( + reordered_levels_for_paras(text), + vec![Level::vec(&[0, 0, 0, 0, 0, 0])] + ); + assert_eq!( + reordered_levels_per_char_for_paras(text), + vec![Level::vec(&[0, 0])] + ); + + /* TODO + /// BidiTest:69635 (AL ET EN) + let text = "\u{060B}\u{20CF}\u{06F9}"; + assert_eq!( + reordered_levels_for_paras(text), + vec![Level::vec(&[1, 1, 1, 1, 1, 2, 2])] + ); + assert_eq!( + reordered_levels_per_char_for_paras(text), + vec![Level::vec(&[1, 1, 2])] + ); + */ + + /* TODO + // BidiTest:291284 (AN RLI PDF R) + assert_eq!( + reordered_levels_per_char_for_paras("\u{0605}\u{2067}\u{202C}\u{0590}"), + vec![&["2", "0", "x", "1"]] + ); + */ + } +} + + +#[cfg(all(feature = "serde", test))] +mod serde_tests { + use serde_test::{Token, assert_tokens}; + use super::*; + + #[test] + fn test_levels() { + let text = "abc אבג"; + let bidi_info = BidiInfo::new(text, None); + let levels = bidi_info.levels; + assert_eq!(text.as_bytes().len(), 10); + assert_eq!(levels.len(), 10); + assert_tokens( + &levels, + &[ + Token::Seq { len: Some(10) }, + Token::NewtypeStruct { name: "Level" }, + Token::U8(0), + Token::NewtypeStruct { name: "Level" }, + Token::U8(0), + Token::NewtypeStruct { name: "Level" }, + Token::U8(0), + Token::NewtypeStruct { name: "Level" }, + Token::U8(0), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::NewtypeStruct { name: "Level" }, + Token::U8(1), + Token::SeqEnd, + ], + ); + } +} diff --git a/unicode-bidi/src/prepare.rs b/unicode-bidi/src/prepare.rs new file mode 100644 index 000000000..79839624a --- /dev/null +++ b/unicode-bidi/src/prepare.rs @@ -0,0 +1,366 @@ +// Copyright 2015 The Servo Project Developers. See the +// COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 3.3.3 Preparations for Implicit Processing +//! +//! <http://www.unicode.org/reports/tr9/#Preparations_for_Implicit_Processing> + +use std::cmp::max; +use std::ops::Range; + +use super::char_data::BidiClass; +use super::level::Level; + +use BidiClass::*; + +/// A maximal substring of characters with the same embedding level. +/// +/// Represented as a range of byte indices. +pub type LevelRun = Range<usize>; + + +/// Output of `isolating_run_sequences` (steps X9-X10) +#[derive(Debug, PartialEq)] +pub struct IsolatingRunSequence { + pub runs: Vec<LevelRun>, + pub sos: BidiClass, // Start-of-sequence type. + pub eos: BidiClass, // End-of-sequence type. +} + + +/// Compute the set of isolating run sequences. +/// +/// An isolating run sequence is a maximal sequence of level runs such that for all level runs +/// except the last one in the sequence, the last character of the run is an isolate initiator +/// whose matching PDI is the first character of the next level run in the sequence. +/// +/// Note: This function does *not* return the sequences in order by their first characters. +#[cfg_attr(feature = "flame_it", flame)] +pub fn isolating_run_sequences( + para_level: Level, + original_classes: &[BidiClass], + levels: &[Level], +) -> Vec<IsolatingRunSequence> { + let runs = level_runs(levels, original_classes); + + // Compute the set of isolating run sequences. + // <http://www.unicode.org/reports/tr9/#BD13> + let mut sequences = Vec::with_capacity(runs.len()); + + // When we encounter an isolate initiator, we push the current sequence onto the + // stack so we can resume it after the matching PDI. + let mut stack = vec![Vec::new()]; + + for run in runs { + assert!(run.len() > 0); + assert!(!stack.is_empty()); + + let start_class = original_classes[run.start]; + let end_class = original_classes[run.end - 1]; + + let mut sequence = if start_class == PDI && stack.len() > 1 { + // Continue a previous sequence interrupted by an isolate. + stack.pop().unwrap() + } else { + // Start a new sequence. + Vec::new() + }; + + sequence.push(run); + + if matches!(end_class, RLI | LRI | FSI) { + // Resume this sequence after the isolate. + stack.push(sequence); + } else { + // This sequence is finished. + sequences.push(sequence); + } + } + // Pop any remaning sequences off the stack. + sequences.extend(stack.into_iter().rev().filter(|seq| !seq.is_empty())); + + // Determine the `sos` and `eos` class for each sequence. + // <http://www.unicode.org/reports/tr9/#X10> + sequences + .into_iter() + .map(|sequence: Vec<LevelRun>| { + assert!(!sequence.is_empty()); + + let start_of_seq = sequence[0].start; + let end_of_seq = sequence[sequence.len() - 1].end; + let seq_level = levels[start_of_seq]; + + #[cfg(test)] + for run in sequence.clone() { + for idx in run { + if not_removed_by_x9(&original_classes[idx]) { + assert_eq!(seq_level, levels[idx]); + } + } + } + + // Get the level of the last non-removed char before the runs. + let pred_level = match original_classes[..start_of_seq].iter().rposition( + not_removed_by_x9, + ) { + Some(idx) => levels[idx], + None => para_level, + }; + + // Get the level of the next non-removed char after the runs. + let succ_level = if matches!(original_classes[end_of_seq - 1], RLI | LRI | FSI) { + para_level + } else { + match original_classes[end_of_seq..].iter().position( + not_removed_by_x9, + ) { + Some(idx) => levels[end_of_seq + idx], + None => para_level, + } + }; + + IsolatingRunSequence { + runs: sequence, + sos: max(seq_level, pred_level).bidi_class(), + eos: max(seq_level, succ_level).bidi_class(), + } + }) + .collect() +} + +/// Finds the level runs in a paragraph. +/// +/// <http://www.unicode.org/reports/tr9/#BD7> +fn level_runs(levels: &[Level], original_classes: &[BidiClass]) -> Vec<LevelRun> { + assert_eq!(levels.len(), original_classes.len()); + + let mut runs = Vec::new(); + if levels.is_empty() { + return runs; + } + + let mut current_run_level = levels[0]; + let mut current_run_start = 0; + for i in 1..levels.len() { + if !removed_by_x9(original_classes[i]) && levels[i] != current_run_level { + // End the last run and start a new one. + runs.push(current_run_start..i); + current_run_level = levels[i]; + current_run_start = i; + } + } + runs.push(current_run_start..levels.len()); + + runs +} + +/// Should this character be ignored in steps after X9? +/// +/// <http://www.unicode.org/reports/tr9/#X9> +pub fn removed_by_x9(class: BidiClass) -> bool { + matches!(class, RLE | LRE | RLO | LRO | PDF | BN) +} + +// For use as a predicate for `position` / `rposition` +pub fn not_removed_by_x9(class: &BidiClass) -> bool { + !removed_by_x9(*class) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_level_runs() { + assert_eq!(level_runs(&Level::vec(&[]), &[]), &[]); + assert_eq!( + level_runs(&Level::vec(&[0, 0, 0, 1, 1, 2, 0, 0]), &[L; 8]), + &[0..3, 3..5, 5..6, 6..8] + ); + } + + // From <http://www.unicode.org/reports/tr9/#BD13> + #[cfg_attr(rustfmt, rustfmt_skip)] + #[test] + fn test_isolating_run_sequences() { + + // == Example 1 == + // text1·RLE·text2·PDF·RLE·text3·PDF·text4 + // index 0 1 2 3 4 5 6 7 + let classes = &[L, RLE, L, PDF, RLE, L, PDF, L]; + let levels = &[0, 1, 1, 1, 1, 1, 1, 0]; + let para_level = Level::ltr(); + let mut sequences = isolating_run_sequences(para_level, classes, &Level::vec(levels)); + sequences.sort_by(|a, b| a.runs[0].clone().cmp(b.runs[0].clone())); + assert_eq!( + sequences.iter().map(|s| s.runs.clone()).collect::<Vec<_>>(), + vec![vec![0..2], vec![2..7], vec![7..8]] + ); + + // == Example 2 == + // text1·RLI·text2·PDI·RLI·text3·PDI·text4 + // index 0 1 2 3 4 5 6 7 + let classes = &[L, RLI, L, PDI, RLI, L, PDI, L]; + let levels = &[0, 0, 1, 0, 0, 1, 0, 0]; + let para_level = Level::ltr(); + let mut sequences = isolating_run_sequences(para_level, classes, &Level::vec(levels)); + sequences.sort_by(|a, b| a.runs[0].clone().cmp(b.runs[0].clone())); + assert_eq!( + sequences.iter().map(|s| s.runs.clone()).collect::<Vec<_>>(), + vec![vec![0..2, 3..5, 6..8], vec![2..3], vec![5..6]] + ); + + // == Example 3 == + // text1·RLI·text2·LRI·text3·RLE·text4·PDF·text5·PDI·text6·PDI·text7 + // index 0 1 2 3 4 5 6 7 8 9 10 11 12 + let classes = &[L, RLI, L, LRI, L, RLE, L, PDF, L, PDI, L, PDI, L]; + let levels = &[0, 0, 1, 1, 2, 3, 3, 3, 2, 1, 1, 0, 0]; + let para_level = Level::ltr(); + let mut sequences = isolating_run_sequences(para_level, classes, &Level::vec(levels)); + sequences.sort_by(|a, b| a.runs[0].clone().cmp(b.runs[0].clone())); + assert_eq!( + sequences.iter().map(|s| s.runs.clone()).collect::<Vec<_>>(), + vec![vec![0..2, 11..13], vec![2..4, 9..11], vec![4..6], vec![6..8], vec![8..9]] + ); + } + + // From <http://www.unicode.org/reports/tr9/#X10> + #[cfg_attr(rustfmt, rustfmt_skip)] + #[test] + fn test_isolating_run_sequences_sos_and_eos() { + + // == Example 1 == + // text1·RLE·text2·LRE·text3·PDF·text4·PDF·RLE·text5·PDF·text6 + // index 0 1 2 3 4 5 6 7 8 9 10 11 + let classes = &[L, RLE, L, LRE, L, PDF, L, PDF, RLE, L, PDF, L]; + let levels = &[0, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 0]; + let para_level = Level::ltr(); + let mut sequences = isolating_run_sequences(para_level, classes, &Level::vec(levels)); + sequences.sort_by(|a, b| a.runs[0].clone().cmp(b.runs[0].clone())); + + // text1 + assert_eq!( + &sequences[0], + &IsolatingRunSequence { + runs: vec![0..2], + sos: L, + eos: R, + } + ); + + // text2 + assert_eq!( + &sequences[1], + &IsolatingRunSequence { + runs: vec![2..4], + sos: R, + eos: L, + } + ); + + // text3 + assert_eq!( + &sequences[2], + &IsolatingRunSequence { + runs: vec![4..6], + sos: L, + eos: L, + } + ); + + // text4 text5 + assert_eq!( + &sequences[3], + &IsolatingRunSequence { + runs: vec![6..11], + sos: L, + eos: R, + } + ); + + // text6 + assert_eq!( + &sequences[4], + &IsolatingRunSequence { + runs: vec![11..12], + sos: R, + eos: L, + } + ); + + // == Example 2 == + // text1·RLI·text2·LRI·text3·PDI·text4·PDI·RLI·text5·PDI·text6 + // index 0 1 2 3 4 5 6 7 8 9 10 11 + let classes = &[L, RLI, L, LRI, L, PDI, L, PDI, RLI, L, PDI, L]; + let levels = &[0, 0, 1, 1, 2, 1, 1, 0, 0, 1, 0, 0]; + let para_level = Level::ltr(); + let mut sequences = isolating_run_sequences(para_level, classes, &Level::vec(levels)); + sequences.sort_by(|a, b| a.runs[0].clone().cmp(b.runs[0].clone())); + + // text1·RLI·PDI·RLI·PDI·text6 + assert_eq!( + &sequences[0], + &IsolatingRunSequence { + runs: vec![0..2, 7..9, 10..12], + sos: L, + eos: L, + } + ); + + // text2·LRI·PDI·text4 + assert_eq!( + &sequences[1], + &IsolatingRunSequence { + runs: vec![2..4, 5..7], + sos: R, + eos: R, + } + ); + + // text3 + assert_eq!( + &sequences[2], + &IsolatingRunSequence { + runs: vec![4..5], + sos: L, + eos: L, + } + ); + + // text5 + assert_eq!( + &sequences[3], + &IsolatingRunSequence { + runs: vec![9..10], + sos: R, + eos: R, + } + ); + } + + #[test] + fn test_removed_by_x9() { + let rem_classes = &[RLE, LRE, RLO, LRO, PDF, BN]; + let not_classes = &[L, RLI, AL, LRI, PDI]; + for x in rem_classes { + assert_eq!(removed_by_x9(*x), true); + } + for x in not_classes { + assert_eq!(removed_by_x9(*x), false); + } + } + + #[test] + fn test_not_removed_by_x9() { + let non_x9_classes = &[L, R, AL, EN, ES, ET, AN, CS, NSM, B, S, WS, ON, LRI, RLI, FSI, PDI]; + for x in non_x9_classes { + assert_eq!(not_removed_by_x9(&x), true); + } + } +} diff --git a/unicode-normalization/.cargo-checksum.json b/unicode-normalization/.cargo-checksum.json new file mode 100644 index 000000000..ac7557926 --- /dev/null +++ b/unicode-normalization/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"} \ No newline at end of file diff --git a/unicode-normalization/COPYRIGHT b/unicode-normalization/COPYRIGHT new file mode 100644 index 000000000..b286ec16a --- /dev/null +++ b/unicode-normalization/COPYRIGHT @@ -0,0 +1,7 @@ +Licensed under the Apache License, Version 2.0 +<LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT +license <LICENSE-MIT or http://opensource.org/licenses/MIT>, +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. diff --git a/unicode-normalization/Cargo.toml b/unicode-normalization/Cargo.toml new file mode 100644 index 000000000..29bce95f1 --- /dev/null +++ b/unicode-normalization/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "unicode-normalization" +version = "0.1.8" +authors = ["kwantam <kwantam@gmail.com>"] +exclude = ["target/*", "Cargo.lock", "scripts/tmp", "*.txt", "src/normalization_tests.rs", "src/test.rs"] +description = "This crate provides functions for normalization of\nUnicode strings, including Canonical and Compatible\nDecomposition and Recomposition, as described in\nUnicode Standard Annex #15.\n" +homepage = "https://github.com/unicode-rs/unicode-normalization" +documentation = "https://docs.rs/unicode-normalization/" +readme = "README.md" +keywords = ["text", "unicode", "normalization", "decomposition", "recomposition"] +license = "MIT/Apache-2.0" +repository = "https://github.com/unicode-rs/unicode-normalization" +[dependencies.smallvec] +version = "0.6" diff --git a/unicode-normalization/LICENSE-APACHE b/unicode-normalization/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/unicode-normalization/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/unicode-normalization/LICENSE-MIT b/unicode-normalization/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/unicode-normalization/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/unicode-normalization/README.md b/unicode-normalization/README.md new file mode 100644 index 000000000..591849dcc --- /dev/null +++ b/unicode-normalization/README.md @@ -0,0 +1,35 @@ +# unicode-normalization + +[![Build Status](https://travis-ci.org/unicode-rs/unicode-normalization.svg)](https://travis-ci.org/unicode-rs/unicode-normalization) +[![Docs](https://docs.rs/unicode-normalization/badge.svg)](https://docs.rs/unicode-normalization/) + +Unicode character composition and decomposition utilities +as described in +[Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/). + +This crate requires Rust 1.21+. + +```rust +extern crate unicode_normalization; + +use unicode_normalization::char::compose; +use unicode_normalization::UnicodeNormalization; + +fn main() { + assert_eq!(compose('A','\u{30a}'), Some('Å')); + + let s = "ÅΩ"; + let c = s.nfc().collect::<String>(); + assert_eq!(c, "ÅΩ"); +} +``` + +## crates.io + +You can use this package in your project by adding the following +to your `Cargo.toml`: + +```toml +[dependencies] +unicode-normalization = "0.1.8" +``` diff --git a/unicode-normalization/benches/bench.rs b/unicode-normalization/benches/bench.rs new file mode 100644 index 000000000..b3ea83660 --- /dev/null +++ b/unicode-normalization/benches/bench.rs @@ -0,0 +1,127 @@ +#![feature(test)] +#![feature(iterator_step_by)] +extern crate unicode_normalization; +extern crate test; + +use std::fs; +use test::Bencher; +use unicode_normalization::UnicodeNormalization; + +const ASCII: &'static str = "all types of normalized"; +const NFC: &'static str = "Introducci\u{00f3}n a Unicode.pdf"; +const NFD: &'static str = "Introduccio\u{0301}n a Unicode.pdf"; + +#[bench] +fn bench_is_nfc_ascii(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc(ASCII)); +} + +#[bench] +fn bench_is_nfc_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc(NFC)); +} + +#[bench] +fn bench_is_nfc_not_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc(NFD)); +} + +#[bench] +fn bench_is_nfd_ascii(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd(ASCII)); +} + +#[bench] +fn bench_is_nfd_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd(NFD)); +} + +#[bench] +fn bench_is_nfd_not_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd(NFC)); +} + +#[bench] +fn bench_is_nfc_stream_safe_ascii(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc_stream_safe(ASCII)); +} + +#[bench] +fn bench_is_nfc_stream_safe_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc_stream_safe(NFC)); +} + +#[bench] +fn bench_is_nfc_stream_safe_not_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfc_stream_safe(NFD)); +} + +#[bench] +fn bench_is_nfd_stream_safe_ascii(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd_stream_safe(ASCII)); +} + +#[bench] +fn bench_is_nfd_stream_safe_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd_stream_safe(NFD)); +} + +#[bench] +fn bench_is_nfd_stream_safe_not_normalized(b: &mut Bencher) { + b.iter(|| unicode_normalization::is_nfd_stream_safe(NFC)); +} + +#[bench] +fn bench_nfc_ascii(b: &mut Bencher) { + b.iter(|| ASCII.nfc().count()); +} + +#[bench] +fn bench_nfd_ascii(b: &mut Bencher) { + b.iter(|| ASCII.nfd().count()); +} + +#[bench] +fn bench_nfc_long(b: &mut Bencher) { + let long = fs::read_to_string("benches/long.txt").unwrap(); + b.iter(|| long.nfc().count()); +} + +#[bench] +fn bench_nfd_long(b: &mut Bencher) { + let long = fs::read_to_string("benches/long.txt").unwrap(); + b.iter(|| long.nfd().count()); +} + +#[bench] +fn bench_nfkc_ascii(b: &mut Bencher) { + b.iter(|| ASCII.nfkc().count()); +} + +#[bench] +fn bench_nfkd_ascii(b: &mut Bencher) { + b.iter(|| ASCII.nfkd().count()); +} + +#[bench] +fn bench_nfkc_long(b: &mut Bencher) { + let long = fs::read_to_string("benches/long.txt").unwrap(); + b.iter(|| long.nfkc().count()); +} + +#[bench] +fn bench_nfkd_long(b: &mut Bencher) { + let long = fs::read_to_string("benches/long.txt").unwrap(); + b.iter(|| long.nfkd().count()); +} + +#[bench] +fn bench_streamsafe_ascii(b: &mut Bencher) { + b.iter(|| ASCII.stream_safe().count()); +} + +#[bench] +fn bench_streamsafe_adversarial(b: &mut Bencher) { + let s = "bo\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{0316}\u{0317}\u{0318}\u{0319}\u{031a}\u{031b}\u{031c}\u{031d}\u{032e}oom"; + b.iter(|| s.stream_safe().count()); +} diff --git a/unicode-normalization/scripts/unicode.py b/unicode-normalization/scripts/unicode.py new file mode 100644 index 000000000..8cd0ede69 --- /dev/null +++ b/unicode-normalization/scripts/unicode.py @@ -0,0 +1,475 @@ +#!/usr/bin/env python +# +# Copyright 2011-2018 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - DerivedNormalizationProps.txt +# - NormalizationTest.txt +# - UnicodeData.txt +# +# Since this should not require frequent updates, we just store this +# out-of-line and check the unicode.rs file into git. +import collections +import requests + +UNICODE_VERSION = "9.0.0" +UCD_URL = "https://www.unicode.org/Public/%s/ucd/" % UNICODE_VERSION + +PREAMBLE = """// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs)] +""" + +NormalizationTest = collections.namedtuple( + "NormalizationTest", + ["source", "nfc", "nfd", "nfkc", "nfkd"], +) + +# Mapping taken from Table 12 from: +# http://www.unicode.org/reports/tr44/#General_Category_Values +expanded_categories = { + 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'], + 'Lm': ['L'], 'Lo': ['L'], + 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'], + 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'], + 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'], + 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'], + 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'], + 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'], + 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'], +} + +class UnicodeData(object): + def __init__(self): + self._load_unicode_data() + self.norm_props = self._load_norm_props() + self.norm_tests = self._load_norm_tests() + + self.canon_comp = self._compute_canonical_comp() + self.canon_fully_decomp, self.compat_fully_decomp = self._compute_fully_decomposed() + + def stats(name, table): + count = sum(len(v) for v in table.values()) + print "%s: %d chars => %d decomposed chars" % (name, len(table), count) + + print "Decomposition table stats:" + stats("Canonical decomp", self.canon_decomp) + stats("Compatible decomp", self.compat_decomp) + stats("Canonical fully decomp", self.canon_fully_decomp) + stats("Compatible fully decomp", self.compat_fully_decomp) + + self.ss_leading, self.ss_trailing = self._compute_stream_safe_tables() + + def _fetch(self, filename): + resp = requests.get(UCD_URL + filename) + return resp.text + + def _load_unicode_data(self): + self.combining_classes = {} + self.compat_decomp = {} + self.canon_decomp = {} + self.general_category_mark = [] + + for line in self._fetch("UnicodeData.txt").splitlines(): + # See ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html + pieces = line.split(';') + assert len(pieces) == 15 + char, category, cc, decomp = pieces[0], pieces[2], pieces[3], pieces[5] + char_int = int(char, 16) + + if cc != '0': + self.combining_classes[char_int] = cc + + if decomp.startswith('<'): + self.compat_decomp[char_int] = [int(c, 16) for c in decomp.split()[1:]] + elif decomp != '': + self.canon_decomp[char_int] = [int(c, 16) for c in decomp.split()] + + if category == 'M' or 'M' in expanded_categories.get(category, []): + self.general_category_mark.append(char_int) + + def _load_norm_props(self): + props = collections.defaultdict(list) + + for line in self._fetch("DerivedNormalizationProps.txt").splitlines(): + (prop_data, _, _) = line.partition("#") + prop_pieces = prop_data.split(";") + + if len(prop_pieces) < 2: + continue + + assert len(prop_pieces) <= 3 + (low, _, high) = prop_pieces[0].strip().partition("..") + + prop = prop_pieces[1].strip() + + data = None + if len(prop_pieces) == 3: + data = prop_pieces[2].strip() + + props[prop].append((low, high, data)) + + return props + + def _load_norm_tests(self): + tests = [] + for line in self._fetch("NormalizationTest.txt").splitlines(): + (test_data, _, _) = line.partition("#") + test_pieces = test_data.split(";") + + if len(test_pieces) < 5: + continue + + source, nfc, nfd, nfkc, nfkd = [[c.strip() for c in p.split()] for p in test_pieces[:5]] + tests.append(NormalizationTest(source, nfc, nfd, nfkc, nfkd)) + + return tests + + def _compute_canonical_comp(self): + canon_comp = {} + comp_exclusions = [ + (int(low, 16), int(high or low, 16)) + for low, high, _ in self.norm_props["Full_Composition_Exclusion"] + ] + for char_int, decomp in self.canon_decomp.items(): + if any(lo <= char_int <= hi for lo, hi in comp_exclusions): + continue + + assert len(decomp) == 2 + assert (decomp[0], decomp[1]) not in canon_comp + canon_comp[(decomp[0], decomp[1])] = char_int + + return canon_comp + + def _compute_fully_decomposed(self): + """ + Even though the decomposition algorithm is recursive, it is possible + to precompute the recursion at table generation time with modest + increase to the table size. Then, for these precomputed tables, we + note that 1) compatible decomposition is a subset of canonical + decomposition and 2) they mostly agree on their intersection. + Therefore, we don't store entries in the compatible table for + characters that decompose the same way under canonical decomposition. + + Decomposition table stats: + Canonical decomp: 2060 chars => 3085 decomposed chars + Compatible decomp: 3662 chars => 5440 decomposed chars + Canonical fully decomp: 2060 chars => 3404 decomposed chars + Compatible fully decomp: 3678 chars => 5599 decomposed chars + + The upshot is that decomposition code is very simple and easy to inline + at mild code size cost. + """ + # Constants from Unicode 9.0.0 Section 3.12 Conjoining Jamo Behavior + # http://www.unicode.org/versions/Unicode9.0.0/ch03.pdf#M9.32468.Heading.310.Combining.Jamo.Behavior + S_BASE, L_COUNT, V_COUNT, T_COUNT = 0xAC00, 19, 21, 28 + S_COUNT = L_COUNT * V_COUNT * T_COUNT + + def _decompose(char_int, compatible): + # 7-bit ASCII never decomposes + if char_int <= 0x7f: + yield char_int + return + + # Assert that we're handling Hangul separately. + assert not (S_BASE <= char_int < S_BASE + S_COUNT) + + decomp = self.canon_decomp.get(char_int) + if decomp is not None: + for decomposed_ch in decomp: + for fully_decomposed_ch in _decompose(decomposed_ch, compatible): + yield fully_decomposed_ch + return + + if compatible and char_int in self.compat_decomp: + for decomposed_ch in self.compat_decomp[char_int]: + for fully_decomposed_ch in _decompose(decomposed_ch, compatible): + yield fully_decomposed_ch + return + + yield char_int + return + + end_codepoint = max( + max(self.canon_decomp.keys()), + max(self.compat_decomp.keys()), + ) + + canon_fully_decomp = {} + compat_fully_decomp = {} + + for char_int in range(0, end_codepoint + 1): + # Always skip Hangul, since it's more efficient to represent its + # decomposition programmatically. + if S_BASE <= char_int < S_BASE + S_COUNT: + continue + + canon = list(_decompose(char_int, False)) + if not (len(canon) == 1 and canon[0] == char_int): + canon_fully_decomp[char_int] = canon + + compat = list(_decompose(char_int, True)) + if not (len(compat) == 1 and compat[0] == char_int): + compat_fully_decomp[char_int] = compat + + # Since canon_fully_decomp is a subset of compat_fully_decomp, we don't + # need to store their overlap when they agree. When they don't agree, + # store the decomposition in the compatibility table since we'll check + # that first when normalizing to NFKD. + assert canon_fully_decomp <= compat_fully_decomp + + for ch in set(canon_fully_decomp) & set(compat_fully_decomp): + if canon_fully_decomp[ch] == compat_fully_decomp[ch]: + del compat_fully_decomp[ch] + + return canon_fully_decomp, compat_fully_decomp + + def _compute_stream_safe_tables(self): + """ + To make a text stream-safe with the Stream-Safe Text Process (UAX15-D4), + we need to be able to know the number of contiguous non-starters *after* + applying compatibility decomposition to each character. + + We can do this incrementally by computing the number of leading and + trailing non-starters for each character's compatibility decomposition + with the following rules: + + 1) If a character is not affected by compatibility decomposition, look + up its canonical combining class to find out if it's a non-starter. + 2) All Hangul characters are starters, even under decomposition. + 3) Otherwise, very few decomposing characters have a nonzero count + of leading or trailing non-starters, so store these characters + with their associated counts in a separate table. + """ + leading_nonstarters = {} + trailing_nonstarters = {} + + for c in set(self.canon_fully_decomp) | set(self.compat_fully_decomp): + decomposed = self.compat_fully_decomp.get(c) or self.canon_fully_decomp[c] + + num_leading = 0 + for d in decomposed: + if d not in self.combining_classes: + break + num_leading += 1 + + num_trailing = 0 + for d in reversed(decomposed): + if d not in self.combining_classes: + break + num_trailing += 1 + + if num_leading > 0: + leading_nonstarters[c] = num_leading + if num_trailing > 0: + trailing_nonstarters[c] = num_trailing + + return leading_nonstarters, trailing_nonstarters + +hexify = lambda c: hex(c)[2:].upper().rjust(4, '0') + +def gen_combining_class(combining_classes, out): + out.write("#[inline]\n") + out.write("pub fn canonical_combining_class(c: char) -> u8 {\n") + out.write(" match c {\n") + + for char, combining_class in sorted(combining_classes.items()): + out.write(" '\u{%s}' => %s,\n" % (hexify(char), combining_class)) + + out.write(" _ => 0,\n") + out.write(" }\n") + out.write("}\n") + +def gen_composition_table(canon_comp, out): + out.write("#[inline]\n") + out.write("pub fn composition_table(c1: char, c2: char) -> Option<char> {\n") + out.write(" match (c1, c2) {\n") + + for (c1, c2), c3 in sorted(canon_comp.items()): + out.write(" ('\u{%s}', '\u{%s}') => Some('\u{%s}'),\n" % (hexify(c1), hexify(c2), hexify(c3))) + + out.write(" _ => None,\n") + out.write(" }\n") + out.write("}\n") + +def gen_decomposition_tables(canon_decomp, compat_decomp, out): + tables = [(canon_decomp, 'canonical'), (compat_decomp, 'compatibility')] + for table, name in tables: + out.write("#[inline]\n") + out.write("pub fn %s_fully_decomposed(c: char) -> Option<&'static [char]> {\n" % name) + # The "Some" constructor is around the match statement here, because + # putting it into the individual arms would make the item_bodies + # checking of rustc takes almost twice as long, and it's already pretty + # slow because of the huge number of match arms and the fact that there + # is a borrow inside each arm + out.write(" Some(match c {\n") + + for char, chars in sorted(table.items()): + d = ", ".join("'\u{%s}'" % hexify(c) for c in chars) + out.write(" '\u{%s}' => &[%s],\n" % (hexify(char), d)) + + out.write(" _ => return None,\n") + out.write(" })\n") + out.write("}\n") + out.write("\n") + +def gen_qc_match(prop_table, out): + out.write(" match c {\n") + + for low, high, data in prop_table: + assert data in ('N', 'M') + result = "No" if data == 'N' else "Maybe" + if high: + out.write(r" '\u{%s}'...'\u{%s}' => %s," % (low, high, result)) + else: + out.write(r" '\u{%s}' => %s," % (low, result)) + out.write("\n") + + out.write(" _ => Yes,\n") + out.write(" }\n") + +def gen_nfc_qc(prop_tables, out): + out.write("#[inline]\n") + out.write("pub fn qc_nfc(c: char) -> IsNormalized {\n") + gen_qc_match(prop_tables['NFC_QC'], out) + out.write("}\n") + +def gen_nfkc_qc(prop_tables, out): + out.write("#[inline]\n") + out.write("pub fn qc_nfkc(c: char) -> IsNormalized {\n") + gen_qc_match(prop_tables['NFKC_QC'], out) + out.write("}\n") + +def gen_nfd_qc(prop_tables, out): + out.write("#[inline]\n") + out.write("pub fn qc_nfd(c: char) -> IsNormalized {\n") + gen_qc_match(prop_tables['NFD_QC'], out) + out.write("}\n") + +def gen_nfkd_qc(prop_tables, out): + out.write("#[inline]\n") + out.write("pub fn qc_nfkd(c: char) -> IsNormalized {\n") + gen_qc_match(prop_tables['NFKD_QC'], out) + out.write("}\n") + +def gen_combining_mark(general_category_mark, out): + out.write("#[inline]\n") + out.write("pub fn is_combining_mark(c: char) -> bool {\n") + out.write(" match c {\n") + + for char in general_category_mark: + out.write(" '\u{%s}' => true,\n" % hexify(char)) + + out.write(" _ => false,\n") + out.write(" }\n") + out.write("}\n") + +def gen_stream_safe(leading, trailing, out): + out.write("#[inline]\n") + out.write("pub fn stream_safe_leading_nonstarters(c: char) -> usize {\n") + out.write(" match c {\n") + + for char, num_leading in leading.items(): + out.write(" '\u{%s}' => %d,\n" % (hexify(char), num_leading)) + + out.write(" _ => 0,\n") + out.write(" }\n") + out.write("}\n") + out.write("\n") + + out.write("#[inline]\n") + out.write("pub fn stream_safe_trailing_nonstarters(c: char) -> usize {\n") + out.write(" match c {\n") + + for char, num_trailing in trailing.items(): + out.write(" '\u{%s}' => %d,\n" % (hexify(char), num_trailing)) + + out.write(" _ => 0,\n") + out.write(" }\n") + out.write("}\n") + +def gen_tests(tests, out): + out.write("""#[derive(Debug)] +pub struct NormalizationTest { + pub source: &'static str, + pub nfc: &'static str, + pub nfd: &'static str, + pub nfkc: &'static str, + pub nfkd: &'static str, +} + +""") + + out.write("pub const NORMALIZATION_TESTS: &[NormalizationTest] = &[\n") + str_literal = lambda s: '"%s"' % "".join("\u{%s}" % c for c in s) + + for test in tests: + out.write(" NormalizationTest {\n") + out.write(" source: %s,\n" % str_literal(test.source)) + out.write(" nfc: %s,\n" % str_literal(test.nfc)) + out.write(" nfd: %s,\n" % str_literal(test.nfd)) + out.write(" nfkc: %s,\n" % str_literal(test.nfkc)) + out.write(" nfkd: %s,\n" % str_literal(test.nfkd)) + out.write(" },\n") + + out.write("];\n") + +if __name__ == '__main__': + data = UnicodeData() + with open("tables.rs", "w") as out: + out.write(PREAMBLE) + out.write("use quick_check::IsNormalized;\n") + out.write("use quick_check::IsNormalized::*;\n") + out.write("\n") + + version = "(%s, %s, %s)" % tuple(UNICODE_VERSION.split(".")) + out.write("#[allow(unused)]\n") + out.write("pub const UNICODE_VERSION: (u64, u64, u64) = %s;\n\n" % version) + + gen_combining_class(data.combining_classes, out) + out.write("\n") + + gen_composition_table(data.canon_comp, out) + out.write("\n") + + gen_decomposition_tables(data.canon_fully_decomp, data.compat_fully_decomp, out) + + gen_combining_mark(data.general_category_mark, out) + out.write("\n") + + gen_nfc_qc(data.norm_props, out) + out.write("\n") + + gen_nfkc_qc(data.norm_props, out) + out.write("\n") + + gen_nfd_qc(data.norm_props, out) + out.write("\n") + + gen_nfkd_qc(data.norm_props, out) + out.write("\n") + + gen_stream_safe(data.ss_leading, data.ss_trailing, out) + out.write("\n") + + with open("normalization_tests.rs", "w") as out: + out.write(PREAMBLE) + gen_tests(data.norm_tests, out) diff --git a/unicode-normalization/src/decompose.rs b/unicode-normalization/src/decompose.rs new file mode 100644 index 000000000..b4ef386b1 --- /dev/null +++ b/unicode-normalization/src/decompose.rs @@ -0,0 +1,159 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use smallvec::SmallVec; +use std::fmt::{self, Write}; +use std::iter::Fuse; +use std::ops::Range; + +#[derive(Clone)] +enum DecompositionType { + Canonical, + Compatible, +} + +/// External iterator for a string decomposition's characters. +#[derive(Clone)] +pub struct Decompositions<I> { + kind: DecompositionType, + iter: Fuse<I>, + + // This buffer stores pairs of (canonical combining class, character), + // pushed onto the end in text order. + // + // It's divided into up to three sections: + // 1) A prefix that is free space; + // 2) "Ready" characters which are sorted and ready to emit on demand; + // 3) A "pending" block which stills needs more characters for us to be able + // to sort in canonical order and is not safe to emit. + buffer: SmallVec<[(u8, char); 4]>, + ready: Range<usize>, +} + +#[inline] +pub fn new_canonical<I: Iterator<Item=char>>(iter: I) -> Decompositions<I> { + Decompositions { + kind: self::DecompositionType::Canonical, + iter: iter.fuse(), + buffer: SmallVec::new(), + ready: 0..0, + } +} + +#[inline] +pub fn new_compatible<I: Iterator<Item=char>>(iter: I) -> Decompositions<I> { + Decompositions { + kind: self::DecompositionType::Compatible, + iter: iter.fuse(), + buffer: SmallVec::new(), + ready: 0..0, + } +} + +impl<I> Decompositions<I> { + #[inline] + fn push_back(&mut self, ch: char) { + let class = super::char::canonical_combining_class(ch); + + if class == 0 { + self.sort_pending(); + } + + self.buffer.push((class, ch)); + } + + #[inline] + fn sort_pending(&mut self) { + // NB: `sort_by_key` is stable, so it will preserve the original text's + // order within a combining class. + self.buffer[self.ready.end..].sort_by_key(|k| k.0); + self.ready.end = self.buffer.len(); + } + + #[inline] + fn reset_buffer(&mut self) { + // Equivalent to `self.buffer.drain(0..self.ready.end)` (if SmallVec + // supported this API) + let pending = self.buffer.len() - self.ready.end; + for i in 0..pending { + self.buffer[i] = self.buffer[i + self.ready.end]; + } + self.buffer.truncate(pending); + self.ready = 0..0; + } + + #[inline] + fn increment_next_ready(&mut self) { + let next = self.ready.start + 1; + if next == self.ready.end { + self.reset_buffer(); + } else { + self.ready.start = next; + } + } +} + +impl<I: Iterator<Item=char>> Iterator for Decompositions<I> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option<char> { + while self.ready.end == 0 { + match (self.iter.next(), &self.kind) { + (Some(ch), &DecompositionType::Canonical) => { + super::char::decompose_canonical(ch, |d| self.push_back(d)); + } + (Some(ch), &DecompositionType::Compatible) => { + super::char::decompose_compatible(ch, |d| self.push_back(d)); + } + (None, _) => { + if self.buffer.is_empty() { + return None; + } else { + self.sort_pending(); + + // This implementation means that we can call `next` + // on an exhausted iterator; the last outer `next` call + // will result in an inner `next` call. To make this + // safe, we use `fuse`. + break; + } + } + } + } + + // We can assume here that, if `self.ready.end` is greater than zero, + // it's also greater than `self.ready.start`. That's because we only + // increment `self.ready.start` inside `increment_next_ready`, and + // whenever it reaches equality with `self.ready.end`, we reset both + // to zero, maintaining the invariant that: + // self.ready.start < self.ready.end || self.ready.end == self.ready.start == 0 + // + // This less-than-obviously-safe implementation is chosen for performance, + // minimizing the number & complexity of branches in `next` in the common + // case of buffering then unbuffering a single character with each call. + let (_, ch) = self.buffer[self.ready.start]; + self.increment_next_ready(); + Some(ch) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + let (lower, _) = self.iter.size_hint(); + (lower, None) + } +} + +impl<I: Iterator<Item=char> + Clone> fmt::Display for Decompositions<I> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} diff --git a/unicode-normalization/src/lib.rs b/unicode-normalization/src/lib.rs new file mode 100644 index 000000000..8a1d986d9 --- /dev/null +++ b/unicode-normalization/src/lib.rs @@ -0,0 +1,173 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unicode character composition and decomposition utilities +//! as described in +//! [Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/). +//! +//! ```rust +//! extern crate unicode_normalization; +//! +//! use unicode_normalization::char::compose; +//! use unicode_normalization::UnicodeNormalization; +//! +//! fn main() { +//! assert_eq!(compose('A','\u{30a}'), Some('Å')); +//! +//! let s = "ÅΩ"; +//! let c = s.nfc().collect::<String>(); +//! assert_eq!(c, "ÅΩ"); +//! } +//! ``` +//! +//! # crates.io +//! +//! You can use this package in your project by adding the following +//! to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! unicode-normalization = "0.1.8" +//! ``` + +#![deny(missing_docs, unsafe_code)] +#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png", + html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")] + +extern crate smallvec; + +pub use tables::UNICODE_VERSION; +pub use decompose::Decompositions; +pub use quick_check::{ + IsNormalized, + is_nfc, + is_nfc_quick, + is_nfkc, + is_nfkc_quick, + is_nfc_stream_safe, + is_nfc_stream_safe_quick, + is_nfd, + is_nfd_quick, + is_nfkd, + is_nfkd_quick, + is_nfd_stream_safe, + is_nfd_stream_safe_quick, +}; +pub use recompose::Recompositions; +pub use stream_safe::StreamSafe; +use std::str::Chars; + +mod decompose; +mod normalize; +mod recompose; +mod quick_check; +mod stream_safe; +mod tables; + +#[cfg(test)] +mod test; +#[cfg(test)] +mod normalization_tests; + +/// Methods for composing and decomposing characters. +pub mod char { + pub use normalize::{decompose_canonical, decompose_compatible, compose}; + + /// Look up the canonical combining class of a character. + pub use tables::canonical_combining_class; + + /// Return whether the given character is a combining mark (`General_Category=Mark`) + pub use tables::is_combining_mark; +} + + +/// Methods for iterating over strings while applying Unicode normalizations +/// as described in +/// [Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/). +pub trait UnicodeNormalization<I: Iterator<Item=char>> { + /// Returns an iterator over the string in Unicode Normalization Form D + /// (canonical decomposition). + #[inline] + fn nfd(self) -> Decompositions<I>; + + /// Returns an iterator over the string in Unicode Normalization Form KD + /// (compatibility decomposition). + #[inline] + fn nfkd(self) -> Decompositions<I>; + + /// An Iterator over the string in Unicode Normalization Form C + /// (canonical decomposition followed by canonical composition). + #[inline] + fn nfc(self) -> Recompositions<I>; + + /// An Iterator over the string in Unicode Normalization Form KC + /// (compatibility decomposition followed by canonical composition). + #[inline] + fn nfkc(self) -> Recompositions<I>; + + /// An Iterator over the string with Conjoining Grapheme Joiner characters + /// inserted according to the Stream-Safe Text Process (UAX15-D4) + #[inline] + fn stream_safe(self) -> StreamSafe<I>; +} + +impl<'a> UnicodeNormalization<Chars<'a>> for &'a str { + #[inline] + fn nfd(self) -> Decompositions<Chars<'a>> { + decompose::new_canonical(self.chars()) + } + + #[inline] + fn nfkd(self) -> Decompositions<Chars<'a>> { + decompose::new_compatible(self.chars()) + } + + #[inline] + fn nfc(self) -> Recompositions<Chars<'a>> { + recompose::new_canonical(self.chars()) + } + + #[inline] + fn nfkc(self) -> Recompositions<Chars<'a>> { + recompose::new_compatible(self.chars()) + } + + #[inline] + fn stream_safe(self) -> StreamSafe<Chars<'a>> { + StreamSafe::new(self.chars()) + } +} + +impl<I: Iterator<Item=char>> UnicodeNormalization<I> for I { + #[inline] + fn nfd(self) -> Decompositions<I> { + decompose::new_canonical(self) + } + + #[inline] + fn nfkd(self) -> Decompositions<I> { + decompose::new_compatible(self) + } + + #[inline] + fn nfc(self) -> Recompositions<I> { + recompose::new_canonical(self) + } + + #[inline] + fn nfkc(self) -> Recompositions<I> { + recompose::new_compatible(self) + } + + #[inline] + fn stream_safe(self) -> StreamSafe<I> { + StreamSafe::new(self) + } +} diff --git a/unicode-normalization/src/normalize.rs b/unicode-normalization/src/normalize.rs new file mode 100644 index 000000000..b7f44345d --- /dev/null +++ b/unicode-normalization/src/normalize.rs @@ -0,0 +1,152 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Functions for computing canonical and compatible decompositions for Unicode characters. +use std::char; +use std::ops::FnMut; +use tables; + +/// Compute canonical Unicode decomposition for character. +/// See [Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/) +/// for more information. +#[inline] +pub fn decompose_canonical<F>(c: char, emit_char: F) where F: FnMut(char) { + decompose(c, tables::canonical_fully_decomposed, emit_char) +} + +/// Compute canonical or compatible Unicode decomposition for character. +/// See [Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/) +/// for more information. +#[inline] +pub fn decompose_compatible<F: FnMut(char)>(c: char, emit_char: F) { + let decompose_char = |c| tables::compatibility_fully_decomposed(c) + .or_else(|| tables::canonical_fully_decomposed(c)); + decompose(c, decompose_char, emit_char) +} + +#[inline] +fn decompose<D, F>(c: char, decompose_char: D, mut emit_char: F) + where D: Fn(char) -> Option<&'static [char]>, F: FnMut(char) +{ + // 7-bit ASCII never decomposes + if c <= '\x7f' { + emit_char(c); + return; + } + + // Perform decomposition for Hangul + if is_hangul_syllable(c) { + decompose_hangul(c, emit_char); + return; + } + + if let Some(decomposed) = decompose_char(c) { + for &d in decomposed { + emit_char(d); + } + return; + } + + // Finally bottom out. + emit_char(c); +} + +/// Compose two characters into a single character, if possible. +/// See [Unicode Standard Annex #15](http://www.unicode.org/reports/tr15/) +/// for more information. +pub fn compose(a: char, b: char) -> Option<char> { + compose_hangul(a, b).or_else(|| tables::composition_table(a, b)) +} + +// Constants from Unicode 9.0.0 Section 3.12 Conjoining Jamo Behavior +// http://www.unicode.org/versions/Unicode9.0.0/ch03.pdf#M9.32468.Heading.310.Combining.Jamo.Behavior +const S_BASE: u32 = 0xAC00; +const L_BASE: u32 = 0x1100; +const V_BASE: u32 = 0x1161; +const T_BASE: u32 = 0x11A7; +const L_COUNT: u32 = 19; +const V_COUNT: u32 = 21; +const T_COUNT: u32 = 28; +const N_COUNT: u32 = (V_COUNT * T_COUNT); +const S_COUNT: u32 = (L_COUNT * N_COUNT); + +const S_LAST: u32 = S_BASE + S_COUNT - 1; +const L_LAST: u32 = L_BASE + L_COUNT - 1; +const V_LAST: u32 = V_BASE + V_COUNT - 1; +const T_LAST: u32 = T_BASE + T_COUNT - 1; + +// Composition only occurs for `TPart`s in `U+11A8 ... U+11C2`, +// i.e. `T_BASE + 1 ... T_LAST`. +const T_FIRST: u32 = T_BASE + 1; + +pub(crate) fn is_hangul_syllable(c: char) -> bool { + (c as u32) >= S_BASE && (c as u32) < (S_BASE + S_COUNT) +} + +// Decompose a precomposed Hangul syllable +#[allow(unsafe_code)] +#[inline(always)] +fn decompose_hangul<F>(s: char, mut emit_char: F) where F: FnMut(char) { + let s_index = s as u32 - S_BASE; + let l_index = s_index / N_COUNT; + unsafe { + emit_char(char::from_u32_unchecked(L_BASE + l_index)); + + let v_index = (s_index % N_COUNT) / T_COUNT; + emit_char(char::from_u32_unchecked(V_BASE + v_index)); + + let t_index = s_index % T_COUNT; + if t_index > 0 { + emit_char(char::from_u32_unchecked(T_BASE + t_index)); + } + } +} + +#[inline] +pub(crate) fn hangul_decomposition_length(s: char) -> usize { + let si = s as u32 - S_BASE; + let ti = si % T_COUNT; + if ti > 0 { 3 } else { 2 } +} + +// Compose a pair of Hangul Jamo +#[allow(unsafe_code)] +#[inline(always)] +fn compose_hangul(a: char, b: char) -> Option<char> { + let (a, b) = (a as u32, b as u32); + match (a, b) { + // Compose a leading consonant and a vowel together into an LV_Syllable + (L_BASE ... L_LAST, V_BASE ... V_LAST) => { + let l_index = a - L_BASE; + let v_index = b - V_BASE; + let lv_index = l_index * N_COUNT + v_index * T_COUNT; + let s = S_BASE + lv_index; + Some(unsafe {char::from_u32_unchecked(s)}) + }, + // Compose an LV_Syllable and a trailing consonant into an LVT_Syllable + (S_BASE ... S_LAST, T_FIRST ... T_LAST) if (a - S_BASE) % T_COUNT == 0 => { + Some(unsafe {char::from_u32_unchecked(a + (b - T_BASE))}) + }, + _ => None, + } +} + +#[cfg(test)] +mod tests { + use super::compose_hangul; + + // Regression test from a bugfix where we were composing an LV_Syllable with + // T_BASE directly. (We should only compose an LV_Syllable with a character + // in the range `T_BASE + 1 ... T_LAST`.) + #[test] + fn test_hangul_composition() { + assert_eq!(compose_hangul('\u{c8e0}', '\u{11a7}'), None); + } +} diff --git a/unicode-normalization/src/quick_check.rs b/unicode-normalization/src/quick_check.rs new file mode 100644 index 000000000..e8bd49595 --- /dev/null +++ b/unicode-normalization/src/quick_check.rs @@ -0,0 +1,189 @@ +use UnicodeNormalization; +use stream_safe; +use tables; + +/// The QuickCheck algorithm can quickly determine if a text is or isn't +/// normalized without any allocations in many cases, but it has to be able to +/// return `Maybe` when a full decomposition and recomposition is necessary. +#[derive(Debug, Eq, PartialEq)] +pub enum IsNormalized { + /// The text is definitely normalized. + Yes, + /// The text is definitely not normalized. + No, + /// The text may be normalized. + Maybe, +} + +// https://unicode.org/reports/tr15/#Detecting_Normalization_Forms +#[inline] +fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized + where I: Iterator<Item=char>, F: Fn(char) -> IsNormalized +{ + let mut last_cc = 0u8; + let mut nonstarter_count = 0; + let mut result = IsNormalized::Yes; + for ch in s { + // For ASCII we know it's always allowed and a starter + if ch <= '\x7f' { + last_cc = 0; + nonstarter_count = 0; + continue; + } + + // Otherwise, lookup the combining class and QC property + let cc = tables::canonical_combining_class(ch); + if last_cc > cc && cc != 0 { + return IsNormalized::No; + } + match is_allowed(ch) { + IsNormalized::Yes => (), + IsNormalized::No => return IsNormalized::No, + IsNormalized::Maybe => { + result = IsNormalized::Maybe; + }, + } + if stream_safe { + let decomp = stream_safe::classify_nonstarters(ch); + + // If we're above `MAX_NONSTARTERS`, we're definitely *not* + // stream-safe normalized. + if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { + return IsNormalized::No; + } + if decomp.leading_nonstarters == decomp.decomposition_len { + nonstarter_count += decomp.decomposition_len; + } else { + nonstarter_count = decomp.trailing_nonstarters; + } + } + last_cc = cc; + } + result +} + +/// Quickly check if a string is in NFC, potentially returning +/// `IsNormalized::Maybe` if further checks are necessary. In this case a check +/// like `s.chars().nfc().eq(s.chars())` should suffice. +#[inline] +pub fn is_nfc_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfc, false) +} + + +/// Quickly check if a string is in NFKC. +#[inline] +pub fn is_nfkc_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfkc, false) +} + +/// Quickly check if a string is in NFD. +#[inline] +pub fn is_nfd_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfd, false) +} + +/// Quickly check if a string is in NFKD. +#[inline] +pub fn is_nfkd_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfkd, false) +} + +/// Quickly check if a string is Stream-Safe NFC. +#[inline] +pub fn is_nfc_stream_safe_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfc, true) +} + +/// Quickly check if a string is Stream-Safe NFD. +#[inline] +pub fn is_nfd_stream_safe_quick<I: Iterator<Item=char>>(s: I) -> IsNormalized { + quick_check(s, tables::qc_nfd, true) +} + +/// Authoritatively check if a string is in NFC. +#[inline] +pub fn is_nfc(s: &str) -> bool { + match is_nfc_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().nfc()), + } +} + +/// Authoritatively check if a string is in NFKC. +#[inline] +pub fn is_nfkc(s: &str) -> bool { + match is_nfkc_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().nfkc()), + } +} + +/// Authoritatively check if a string is in NFD. +#[inline] +pub fn is_nfd(s: &str) -> bool { + match is_nfd_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().nfd()), + } +} + +/// Authoritatively check if a string is in NFKD. +#[inline] +pub fn is_nfkd(s: &str) -> bool { + match is_nfkd_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().nfkd()), + } +} + +/// Authoritatively check if a string is Stream-Safe NFC. +#[inline] +pub fn is_nfc_stream_safe(s: &str) -> bool { + match is_nfc_stream_safe_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfc()), + } +} + +/// Authoritatively check if a string is Stream-Safe NFD. +#[inline] +pub fn is_nfd_stream_safe(s: &str) -> bool { + match is_nfd_stream_safe_quick(s.chars()) { + IsNormalized::Yes => true, + IsNormalized::No => false, + IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfd()), + } +} + +#[cfg(test)] +mod tests { + use super::{ + IsNormalized, + is_nfc_stream_safe_quick, + is_nfd_stream_safe_quick, + }; + + #[test] + fn test_stream_safe_nfd() { + let okay = "Da\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}ngerzone"; + assert_eq!(is_nfd_stream_safe_quick(okay.chars()), IsNormalized::Yes); + + let too_much = "Da\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{031e}\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}ngerzone"; + assert_eq!(is_nfd_stream_safe_quick(too_much.chars()), IsNormalized::No); + } + + #[test] + fn test_stream_safe_nfc() { + let okay = "ok\u{e0}\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}y"; + assert_eq!(is_nfc_stream_safe_quick(okay.chars()), IsNormalized::Maybe); + + let too_much = "not ok\u{e0}\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{031e}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}y"; + assert_eq!(is_nfc_stream_safe_quick(too_much.chars()), IsNormalized::No); + } +} diff --git a/unicode-normalization/src/recompose.rs b/unicode-normalization/src/recompose.rs new file mode 100644 index 000000000..4c2bf9793 --- /dev/null +++ b/unicode-normalization/src/recompose.rs @@ -0,0 +1,160 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use decompose::Decompositions; +use smallvec::SmallVec; +use std::fmt::{self, Write}; + +#[derive(Clone)] +enum RecompositionState { + Composing, + Purging(usize), + Finished(usize), +} + +/// External iterator for a string recomposition's characters. +#[derive(Clone)] +pub struct Recompositions<I> { + iter: Decompositions<I>, + state: RecompositionState, + buffer: SmallVec<[char; 4]>, + composee: Option<char>, + last_ccc: Option<u8>, +} + +#[inline] +pub fn new_canonical<I: Iterator<Item=char>>(iter: I) -> Recompositions<I> { + Recompositions { + iter: super::decompose::new_canonical(iter), + state: self::RecompositionState::Composing, + buffer: SmallVec::new(), + composee: None, + last_ccc: None, + } +} + +#[inline] +pub fn new_compatible<I: Iterator<Item=char>>(iter: I) -> Recompositions<I> { + Recompositions { + iter: super::decompose::new_compatible(iter), + state: self::RecompositionState::Composing, + buffer: SmallVec::new(), + composee: None, + last_ccc: None, + } +} + +impl<I: Iterator<Item=char>> Iterator for Recompositions<I> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option<char> { + use self::RecompositionState::*; + + loop { + match self.state { + Composing => { + for ch in self.iter.by_ref() { + let ch_class = super::char::canonical_combining_class(ch); + let k = match self.composee { + None => { + if ch_class != 0 { + return Some(ch); + } + self.composee = Some(ch); + continue; + }, + Some(k) => k, + }; + match self.last_ccc { + None => { + match super::char::compose(k, ch) { + Some(r) => { + self.composee = Some(r); + continue; + } + None => { + if ch_class == 0 { + self.composee = Some(ch); + return Some(k); + } + self.buffer.push(ch); + self.last_ccc = Some(ch_class); + } + } + } + Some(l_class) => { + if l_class >= ch_class { + // `ch` is blocked from `composee` + if ch_class == 0 { + self.composee = Some(ch); + self.last_ccc = None; + self.state = Purging(0); + return Some(k); + } + self.buffer.push(ch); + self.last_ccc = Some(ch_class); + continue; + } + match super::char::compose(k, ch) { + Some(r) => { + self.composee = Some(r); + continue; + } + None => { + self.buffer.push(ch); + self.last_ccc = Some(ch_class); + } + } + } + } + } + self.state = Finished(0); + if self.composee.is_some() { + return self.composee.take(); + } + } + Purging(next) => { + match self.buffer.get(next).cloned() { + None => { + self.buffer.clear(); + self.state = Composing; + } + s => { + self.state = Purging(next + 1); + return s + } + } + } + Finished(next) => { + match self.buffer.get(next).cloned() { + None => { + self.buffer.clear(); + return self.composee.take() + } + s => { + self.state = Finished(next + 1); + return s + } + } + } + } + } + } +} + +impl<I: Iterator<Item=char> + Clone> fmt::Display for Recompositions<I> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} diff --git a/unicode-normalization/src/stream_safe.rs b/unicode-normalization/src/stream_safe.rs new file mode 100644 index 000000000..8bc48f636 --- /dev/null +++ b/unicode-normalization/src/stream_safe.rs @@ -0,0 +1,164 @@ +use normalize::{ + hangul_decomposition_length, + is_hangul_syllable, +}; +use tables; + +pub(crate) const MAX_NONSTARTERS: usize = 30; +const COMBINING_GRAPHEME_JOINER: char = '\u{034F}'; + +/// UAX15-D4: This iterator keeps track of how many non-starters there have been +/// since the last starter in *NFKD* and will emit a Combining Grapheme Joiner +/// (U+034F) if the count exceeds 30. +pub struct StreamSafe<I> { + iter: I, + nonstarter_count: usize, + buffer: Option<char>, +} + +impl<I> StreamSafe<I> { + pub(crate) fn new(iter: I) -> Self { + Self { iter, nonstarter_count: 0, buffer: None } + } +} + +impl<I: Iterator<Item=char>> Iterator for StreamSafe<I> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option<char> { + if let Some(ch) = self.buffer.take() { + return Some(ch); + } + let next_ch = match self.iter.next() { + None => return None, + Some(c) => c, + }; + let d = classify_nonstarters(next_ch); + if self.nonstarter_count + d.leading_nonstarters > MAX_NONSTARTERS { + self.buffer = Some(next_ch); + self.nonstarter_count = 0; + return Some(COMBINING_GRAPHEME_JOINER); + } + + // No starters in the decomposition, so keep accumulating + if d.leading_nonstarters == d.decomposition_len { + self.nonstarter_count += d.decomposition_len; + } + // Otherwise, restart the nonstarter counter. + else { + self.nonstarter_count = d.trailing_nonstarters; + } + Some(next_ch) + } +} + +#[derive(Debug)] +pub(crate) struct Decomposition { + pub(crate) leading_nonstarters: usize, + pub(crate) trailing_nonstarters: usize, + pub(crate) decomposition_len: usize, +} + +#[inline] +pub(crate) fn classify_nonstarters(c: char) -> Decomposition { + // As usual, fast path for ASCII (which is always a starter) + if c <= '\x7f' { + return Decomposition { + leading_nonstarters: 0, + trailing_nonstarters: 0, + decomposition_len: 1, + } + } + // Next, special case Hangul, since it's not handled by our tables. + if is_hangul_syllable(c) { + return Decomposition { + leading_nonstarters: 0, + trailing_nonstarters: 0, + decomposition_len: hangul_decomposition_length(c), + }; + } + let decomp = tables::compatibility_fully_decomposed(c) + .or_else(|| tables::canonical_fully_decomposed(c)); + match decomp { + Some(decomp) => { + Decomposition { + leading_nonstarters: tables::stream_safe_leading_nonstarters(c), + trailing_nonstarters: tables::stream_safe_trailing_nonstarters(c), + decomposition_len: decomp.len(), + } + }, + None => { + let is_nonstarter = tables::canonical_combining_class(c) != 0; + let nonstarter = if is_nonstarter { 1 } else { 0 }; + Decomposition { + leading_nonstarters: nonstarter, + trailing_nonstarters: nonstarter, + decomposition_len: 1, + } + } + } +} + +#[cfg(test)] +mod tests { + use super::{ + StreamSafe, + classify_nonstarters, + }; + use std::char; + use normalization_tests::NORMALIZATION_TESTS; + use normalize::decompose_compatible; + use tables; + + fn stream_safe(s: &str) -> String { + StreamSafe::new(s.chars()).collect() + } + + #[test] + fn test_normalization_tests_unaffected() { + for test in NORMALIZATION_TESTS { + for &s in &[test.source, test.nfc, test.nfd, test.nfkc, test.nfkd] { + assert_eq!(stream_safe(s), s); + } + } + } + + #[test] + fn test_simple() { + let technically_okay = "Da\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{0316}\u{0317}\u{0318}\u{0319}\u{031a}\u{031b}\u{031c}\u{031d}ngerzone"; + assert_eq!(stream_safe(technically_okay), technically_okay); + + let too_much = "Da\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{0316}\u{0317}\u{0318}\u{0319}\u{031a}\u{031b}\u{031c}\u{031d}\u{032e}ngerzone"; + assert_ne!(stream_safe(too_much), too_much); + } + + #[test] + fn test_classify_nonstarters() { + // Highest character in the `compat_fully_decomp` table is 2FA1D + for ch in 0..0x2FA1E { + let ch = match char::from_u32(ch) { + Some(c) => c, + None => continue, + }; + let c = classify_nonstarters(ch); + let mut s = vec![]; + decompose_compatible(ch, |c| s.push(c)); + + assert_eq!(s.len(), c.decomposition_len); + + let num_leading = s + .iter() + .take_while(|&c| tables::canonical_combining_class(*c) != 0) + .count(); + let num_trailing = s + .iter() + .rev() + .take_while(|&c| tables::canonical_combining_class(*c) != 0) + .count(); + + assert_eq!(num_leading, c.leading_nonstarters); + assert_eq!(num_trailing, c.trailing_nonstarters); + } + } +} diff --git a/unicode-normalization/src/tables.rs b/unicode-normalization/src/tables.rs new file mode 100644 index 000000000..5e488e70e --- /dev/null +++ b/unicode-normalization/src/tables.rs @@ -0,0 +1,12112 @@ +// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs)] +use quick_check::IsNormalized; +use quick_check::IsNormalized::*; + +#[allow(unused)] +pub const UNICODE_VERSION: (u64, u64, u64) = (9, 0, 0); + +#[inline] +pub fn canonical_combining_class(c: char) -> u8 { + match c { + '\u{0300}' => 230, + '\u{0301}' => 230, + '\u{0302}' => 230, + '\u{0303}' => 230, + '\u{0304}' => 230, + '\u{0305}' => 230, + '\u{0306}' => 230, + '\u{0307}' => 230, + '\u{0308}' => 230, + '\u{0309}' => 230, + '\u{030A}' => 230, + '\u{030B}' => 230, + '\u{030C}' => 230, + '\u{030D}' => 230, + '\u{030E}' => 230, + '\u{030F}' => 230, + '\u{0310}' => 230, + '\u{0311}' => 230, + '\u{0312}' => 230, + '\u{0313}' => 230, + '\u{0314}' => 230, + '\u{0315}' => 232, + '\u{0316}' => 220, + '\u{0317}' => 220, + '\u{0318}' => 220, + '\u{0319}' => 220, + '\u{031A}' => 232, + '\u{031B}' => 216, + '\u{031C}' => 220, + '\u{031D}' => 220, + '\u{031E}' => 220, + '\u{031F}' => 220, + '\u{0320}' => 220, + '\u{0321}' => 202, + '\u{0322}' => 202, + '\u{0323}' => 220, + '\u{0324}' => 220, + '\u{0325}' => 220, + '\u{0326}' => 220, + '\u{0327}' => 202, + '\u{0328}' => 202, + '\u{0329}' => 220, + '\u{032A}' => 220, + '\u{032B}' => 220, + '\u{032C}' => 220, + '\u{032D}' => 220, + '\u{032E}' => 220, + '\u{032F}' => 220, + '\u{0330}' => 220, + '\u{0331}' => 220, + '\u{0332}' => 220, + '\u{0333}' => 220, + '\u{0334}' => 1, + '\u{0335}' => 1, + '\u{0336}' => 1, + '\u{0337}' => 1, + '\u{0338}' => 1, + '\u{0339}' => 220, + '\u{033A}' => 220, + '\u{033B}' => 220, + '\u{033C}' => 220, + '\u{033D}' => 230, + '\u{033E}' => 230, + '\u{033F}' => 230, + '\u{0340}' => 230, + '\u{0341}' => 230, + '\u{0342}' => 230, + '\u{0343}' => 230, + '\u{0344}' => 230, + '\u{0345}' => 240, + '\u{0346}' => 230, + '\u{0347}' => 220, + '\u{0348}' => 220, + '\u{0349}' => 220, + '\u{034A}' => 230, + '\u{034B}' => 230, + '\u{034C}' => 230, + '\u{034D}' => 220, + '\u{034E}' => 220, + '\u{0350}' => 230, + '\u{0351}' => 230, + '\u{0352}' => 230, + '\u{0353}' => 220, + '\u{0354}' => 220, + '\u{0355}' => 220, + '\u{0356}' => 220, + '\u{0357}' => 230, + '\u{0358}' => 232, + '\u{0359}' => 220, + '\u{035A}' => 220, + '\u{035B}' => 230, + '\u{035C}' => 233, + '\u{035D}' => 234, + '\u{035E}' => 234, + '\u{035F}' => 233, + '\u{0360}' => 234, + '\u{0361}' => 234, + '\u{0362}' => 233, + '\u{0363}' => 230, + '\u{0364}' => 230, + '\u{0365}' => 230, + '\u{0366}' => 230, + '\u{0367}' => 230, + '\u{0368}' => 230, + '\u{0369}' => 230, + '\u{036A}' => 230, + '\u{036B}' => 230, + '\u{036C}' => 230, + '\u{036D}' => 230, + '\u{036E}' => 230, + '\u{036F}' => 230, + '\u{0483}' => 230, + '\u{0484}' => 230, + '\u{0485}' => 230, + '\u{0486}' => 230, + '\u{0487}' => 230, + '\u{0591}' => 220, + '\u{0592}' => 230, + '\u{0593}' => 230, + '\u{0594}' => 230, + '\u{0595}' => 230, + '\u{0596}' => 220, + '\u{0597}' => 230, + '\u{0598}' => 230, + '\u{0599}' => 230, + '\u{059A}' => 222, + '\u{059B}' => 220, + '\u{059C}' => 230, + '\u{059D}' => 230, + '\u{059E}' => 230, + '\u{059F}' => 230, + '\u{05A0}' => 230, + '\u{05A1}' => 230, + '\u{05A2}' => 220, + '\u{05A3}' => 220, + '\u{05A4}' => 220, + '\u{05A5}' => 220, + '\u{05A6}' => 220, + '\u{05A7}' => 220, + '\u{05A8}' => 230, + '\u{05A9}' => 230, + '\u{05AA}' => 220, + '\u{05AB}' => 230, + '\u{05AC}' => 230, + '\u{05AD}' => 222, + '\u{05AE}' => 228, + '\u{05AF}' => 230, + '\u{05B0}' => 10, + '\u{05B1}' => 11, + '\u{05B2}' => 12, + '\u{05B3}' => 13, + '\u{05B4}' => 14, + '\u{05B5}' => 15, + '\u{05B6}' => 16, + '\u{05B7}' => 17, + '\u{05B8}' => 18, + '\u{05B9}' => 19, + '\u{05BA}' => 19, + '\u{05BB}' => 20, + '\u{05BC}' => 21, + '\u{05BD}' => 22, + '\u{05BF}' => 23, + '\u{05C1}' => 24, + '\u{05C2}' => 25, + '\u{05C4}' => 230, + '\u{05C5}' => 220, + '\u{05C7}' => 18, + '\u{0610}' => 230, + '\u{0611}' => 230, + '\u{0612}' => 230, + '\u{0613}' => 230, + '\u{0614}' => 230, + '\u{0615}' => 230, + '\u{0616}' => 230, + '\u{0617}' => 230, + '\u{0618}' => 30, + '\u{0619}' => 31, + '\u{061A}' => 32, + '\u{064B}' => 27, + '\u{064C}' => 28, + '\u{064D}' => 29, + '\u{064E}' => 30, + '\u{064F}' => 31, + '\u{0650}' => 32, + '\u{0651}' => 33, + '\u{0652}' => 34, + '\u{0653}' => 230, + '\u{0654}' => 230, + '\u{0655}' => 220, + '\u{0656}' => 220, + '\u{0657}' => 230, + '\u{0658}' => 230, + '\u{0659}' => 230, + '\u{065A}' => 230, + '\u{065B}' => 230, + '\u{065C}' => 220, + '\u{065D}' => 230, + '\u{065E}' => 230, + '\u{065F}' => 220, + '\u{0670}' => 35, + '\u{06D6}' => 230, + '\u{06D7}' => 230, + '\u{06D8}' => 230, + '\u{06D9}' => 230, + '\u{06DA}' => 230, + '\u{06DB}' => 230, + '\u{06DC}' => 230, + '\u{06DF}' => 230, + '\u{06E0}' => 230, + '\u{06E1}' => 230, + '\u{06E2}' => 230, + '\u{06E3}' => 220, + '\u{06E4}' => 230, + '\u{06E7}' => 230, + '\u{06E8}' => 230, + '\u{06EA}' => 220, + '\u{06EB}' => 230, + '\u{06EC}' => 230, + '\u{06ED}' => 220, + '\u{0711}' => 36, + '\u{0730}' => 230, + '\u{0731}' => 220, + '\u{0732}' => 230, + '\u{0733}' => 230, + '\u{0734}' => 220, + '\u{0735}' => 230, + '\u{0736}' => 230, + '\u{0737}' => 220, + '\u{0738}' => 220, + '\u{0739}' => 220, + '\u{073A}' => 230, + '\u{073B}' => 220, + '\u{073C}' => 220, + '\u{073D}' => 230, + '\u{073E}' => 220, + '\u{073F}' => 230, + '\u{0740}' => 230, + '\u{0741}' => 230, + '\u{0742}' => 220, + '\u{0743}' => 230, + '\u{0744}' => 220, + '\u{0745}' => 230, + '\u{0746}' => 220, + '\u{0747}' => 230, + '\u{0748}' => 220, + '\u{0749}' => 230, + '\u{074A}' => 230, + '\u{07EB}' => 230, + '\u{07EC}' => 230, + '\u{07ED}' => 230, + '\u{07EE}' => 230, + '\u{07EF}' => 230, + '\u{07F0}' => 230, + '\u{07F1}' => 230, + '\u{07F2}' => 220, + '\u{07F3}' => 230, + '\u{0816}' => 230, + '\u{0817}' => 230, + '\u{0818}' => 230, + '\u{0819}' => 230, + '\u{081B}' => 230, + '\u{081C}' => 230, + '\u{081D}' => 230, + '\u{081E}' => 230, + '\u{081F}' => 230, + '\u{0820}' => 230, + '\u{0821}' => 230, + '\u{0822}' => 230, + '\u{0823}' => 230, + '\u{0825}' => 230, + '\u{0826}' => 230, + '\u{0827}' => 230, + '\u{0829}' => 230, + '\u{082A}' => 230, + '\u{082B}' => 230, + '\u{082C}' => 230, + '\u{082D}' => 230, + '\u{0859}' => 220, + '\u{085A}' => 220, + '\u{085B}' => 220, + '\u{08D4}' => 230, + '\u{08D5}' => 230, + '\u{08D6}' => 230, + '\u{08D7}' => 230, + '\u{08D8}' => 230, + '\u{08D9}' => 230, + '\u{08DA}' => 230, + '\u{08DB}' => 230, + '\u{08DC}' => 230, + '\u{08DD}' => 230, + '\u{08DE}' => 230, + '\u{08DF}' => 230, + '\u{08E0}' => 230, + '\u{08E1}' => 230, + '\u{08E3}' => 220, + '\u{08E4}' => 230, + '\u{08E5}' => 230, + '\u{08E6}' => 220, + '\u{08E7}' => 230, + '\u{08E8}' => 230, + '\u{08E9}' => 220, + '\u{08EA}' => 230, + '\u{08EB}' => 230, + '\u{08EC}' => 230, + '\u{08ED}' => 220, + '\u{08EE}' => 220, + '\u{08EF}' => 220, + '\u{08F0}' => 27, + '\u{08F1}' => 28, + '\u{08F2}' => 29, + '\u{08F3}' => 230, + '\u{08F4}' => 230, + '\u{08F5}' => 230, + '\u{08F6}' => 220, + '\u{08F7}' => 230, + '\u{08F8}' => 230, + '\u{08F9}' => 220, + '\u{08FA}' => 220, + '\u{08FB}' => 230, + '\u{08FC}' => 230, + '\u{08FD}' => 230, + '\u{08FE}' => 230, + '\u{08FF}' => 230, + '\u{093C}' => 7, + '\u{094D}' => 9, + '\u{0951}' => 230, + '\u{0952}' => 220, + '\u{0953}' => 230, + '\u{0954}' => 230, + '\u{09BC}' => 7, + '\u{09CD}' => 9, + '\u{0A3C}' => 7, + '\u{0A4D}' => 9, + '\u{0ABC}' => 7, + '\u{0ACD}' => 9, + '\u{0B3C}' => 7, + '\u{0B4D}' => 9, + '\u{0BCD}' => 9, + '\u{0C4D}' => 9, + '\u{0C55}' => 84, + '\u{0C56}' => 91, + '\u{0CBC}' => 7, + '\u{0CCD}' => 9, + '\u{0D4D}' => 9, + '\u{0DCA}' => 9, + '\u{0E38}' => 103, + '\u{0E39}' => 103, + '\u{0E3A}' => 9, + '\u{0E48}' => 107, + '\u{0E49}' => 107, + '\u{0E4A}' => 107, + '\u{0E4B}' => 107, + '\u{0EB8}' => 118, + '\u{0EB9}' => 118, + '\u{0EC8}' => 122, + '\u{0EC9}' => 122, + '\u{0ECA}' => 122, + '\u{0ECB}' => 122, + '\u{0F18}' => 220, + '\u{0F19}' => 220, + '\u{0F35}' => 220, + '\u{0F37}' => 220, + '\u{0F39}' => 216, + '\u{0F71}' => 129, + '\u{0F72}' => 130, + '\u{0F74}' => 132, + '\u{0F7A}' => 130, + '\u{0F7B}' => 130, + '\u{0F7C}' => 130, + '\u{0F7D}' => 130, + '\u{0F80}' => 130, + '\u{0F82}' => 230, + '\u{0F83}' => 230, + '\u{0F84}' => 9, + '\u{0F86}' => 230, + '\u{0F87}' => 230, + '\u{0FC6}' => 220, + '\u{1037}' => 7, + '\u{1039}' => 9, + '\u{103A}' => 9, + '\u{108D}' => 220, + '\u{135D}' => 230, + '\u{135E}' => 230, + '\u{135F}' => 230, + '\u{1714}' => 9, + '\u{1734}' => 9, + '\u{17D2}' => 9, + '\u{17DD}' => 230, + '\u{18A9}' => 228, + '\u{1939}' => 222, + '\u{193A}' => 230, + '\u{193B}' => 220, + '\u{1A17}' => 230, + '\u{1A18}' => 220, + '\u{1A60}' => 9, + '\u{1A75}' => 230, + '\u{1A76}' => 230, + '\u{1A77}' => 230, + '\u{1A78}' => 230, + '\u{1A79}' => 230, + '\u{1A7A}' => 230, + '\u{1A7B}' => 230, + '\u{1A7C}' => 230, + '\u{1A7F}' => 220, + '\u{1AB0}' => 230, + '\u{1AB1}' => 230, + '\u{1AB2}' => 230, + '\u{1AB3}' => 230, + '\u{1AB4}' => 230, + '\u{1AB5}' => 220, + '\u{1AB6}' => 220, + '\u{1AB7}' => 220, + '\u{1AB8}' => 220, + '\u{1AB9}' => 220, + '\u{1ABA}' => 220, + '\u{1ABB}' => 230, + '\u{1ABC}' => 230, + '\u{1ABD}' => 220, + '\u{1B34}' => 7, + '\u{1B44}' => 9, + '\u{1B6B}' => 230, + '\u{1B6C}' => 220, + '\u{1B6D}' => 230, + '\u{1B6E}' => 230, + '\u{1B6F}' => 230, + '\u{1B70}' => 230, + '\u{1B71}' => 230, + '\u{1B72}' => 230, + '\u{1B73}' => 230, + '\u{1BAA}' => 9, + '\u{1BAB}' => 9, + '\u{1BE6}' => 7, + '\u{1BF2}' => 9, + '\u{1BF3}' => 9, + '\u{1C37}' => 7, + '\u{1CD0}' => 230, + '\u{1CD1}' => 230, + '\u{1CD2}' => 230, + '\u{1CD4}' => 1, + '\u{1CD5}' => 220, + '\u{1CD6}' => 220, + '\u{1CD7}' => 220, + '\u{1CD8}' => 220, + '\u{1CD9}' => 220, + '\u{1CDA}' => 230, + '\u{1CDB}' => 230, + '\u{1CDC}' => 220, + '\u{1CDD}' => 220, + '\u{1CDE}' => 220, + '\u{1CDF}' => 220, + '\u{1CE0}' => 230, + '\u{1CE2}' => 1, + '\u{1CE3}' => 1, + '\u{1CE4}' => 1, + '\u{1CE5}' => 1, + '\u{1CE6}' => 1, + '\u{1CE7}' => 1, + '\u{1CE8}' => 1, + '\u{1CED}' => 220, + '\u{1CF4}' => 230, + '\u{1CF8}' => 230, + '\u{1CF9}' => 230, + '\u{1DC0}' => 230, + '\u{1DC1}' => 230, + '\u{1DC2}' => 220, + '\u{1DC3}' => 230, + '\u{1DC4}' => 230, + '\u{1DC5}' => 230, + '\u{1DC6}' => 230, + '\u{1DC7}' => 230, + '\u{1DC8}' => 230, + '\u{1DC9}' => 230, + '\u{1DCA}' => 220, + '\u{1DCB}' => 230, + '\u{1DCC}' => 230, + '\u{1DCD}' => 234, + '\u{1DCE}' => 214, + '\u{1DCF}' => 220, + '\u{1DD0}' => 202, + '\u{1DD1}' => 230, + '\u{1DD2}' => 230, + '\u{1DD3}' => 230, + '\u{1DD4}' => 230, + '\u{1DD5}' => 230, + '\u{1DD6}' => 230, + '\u{1DD7}' => 230, + '\u{1DD8}' => 230, + '\u{1DD9}' => 230, + '\u{1DDA}' => 230, + '\u{1DDB}' => 230, + '\u{1DDC}' => 230, + '\u{1DDD}' => 230, + '\u{1DDE}' => 230, + '\u{1DDF}' => 230, + '\u{1DE0}' => 230, + '\u{1DE1}' => 230, + '\u{1DE2}' => 230, + '\u{1DE3}' => 230, + '\u{1DE4}' => 230, + '\u{1DE5}' => 230, + '\u{1DE6}' => 230, + '\u{1DE7}' => 230, + '\u{1DE8}' => 230, + '\u{1DE9}' => 230, + '\u{1DEA}' => 230, + '\u{1DEB}' => 230, + '\u{1DEC}' => 230, + '\u{1DED}' => 230, + '\u{1DEE}' => 230, + '\u{1DEF}' => 230, + '\u{1DF0}' => 230, + '\u{1DF1}' => 230, + '\u{1DF2}' => 230, + '\u{1DF3}' => 230, + '\u{1DF4}' => 230, + '\u{1DF5}' => 230, + '\u{1DFB}' => 230, + '\u{1DFC}' => 233, + '\u{1DFD}' => 220, + '\u{1DFE}' => 230, + '\u{1DFF}' => 220, + '\u{20D0}' => 230, + '\u{20D1}' => 230, + '\u{20D2}' => 1, + '\u{20D3}' => 1, + '\u{20D4}' => 230, + '\u{20D5}' => 230, + '\u{20D6}' => 230, + '\u{20D7}' => 230, + '\u{20D8}' => 1, + '\u{20D9}' => 1, + '\u{20DA}' => 1, + '\u{20DB}' => 230, + '\u{20DC}' => 230, + '\u{20E1}' => 230, + '\u{20E5}' => 1, + '\u{20E6}' => 1, + '\u{20E7}' => 230, + '\u{20E8}' => 220, + '\u{20E9}' => 230, + '\u{20EA}' => 1, + '\u{20EB}' => 1, + '\u{20EC}' => 220, + '\u{20ED}' => 220, + '\u{20EE}' => 220, + '\u{20EF}' => 220, + '\u{20F0}' => 230, + '\u{2CEF}' => 230, + '\u{2CF0}' => 230, + '\u{2CF1}' => 230, + '\u{2D7F}' => 9, + '\u{2DE0}' => 230, + '\u{2DE1}' => 230, + '\u{2DE2}' => 230, + '\u{2DE3}' => 230, + '\u{2DE4}' => 230, + '\u{2DE5}' => 230, + '\u{2DE6}' => 230, + '\u{2DE7}' => 230, + '\u{2DE8}' => 230, + '\u{2DE9}' => 230, + '\u{2DEA}' => 230, + '\u{2DEB}' => 230, + '\u{2DEC}' => 230, + '\u{2DED}' => 230, + '\u{2DEE}' => 230, + '\u{2DEF}' => 230, + '\u{2DF0}' => 230, + '\u{2DF1}' => 230, + '\u{2DF2}' => 230, + '\u{2DF3}' => 230, + '\u{2DF4}' => 230, + '\u{2DF5}' => 230, + '\u{2DF6}' => 230, + '\u{2DF7}' => 230, + '\u{2DF8}' => 230, + '\u{2DF9}' => 230, + '\u{2DFA}' => 230, + '\u{2DFB}' => 230, + '\u{2DFC}' => 230, + '\u{2DFD}' => 230, + '\u{2DFE}' => 230, + '\u{2DFF}' => 230, + '\u{302A}' => 218, + '\u{302B}' => 228, + '\u{302C}' => 232, + '\u{302D}' => 222, + '\u{302E}' => 224, + '\u{302F}' => 224, + '\u{3099}' => 8, + '\u{309A}' => 8, + '\u{A66F}' => 230, + '\u{A674}' => 230, + '\u{A675}' => 230, + '\u{A676}' => 230, + '\u{A677}' => 230, + '\u{A678}' => 230, + '\u{A679}' => 230, + '\u{A67A}' => 230, + '\u{A67B}' => 230, + '\u{A67C}' => 230, + '\u{A67D}' => 230, + '\u{A69E}' => 230, + '\u{A69F}' => 230, + '\u{A6F0}' => 230, + '\u{A6F1}' => 230, + '\u{A806}' => 9, + '\u{A8C4}' => 9, + '\u{A8E0}' => 230, + '\u{A8E1}' => 230, + '\u{A8E2}' => 230, + '\u{A8E3}' => 230, + '\u{A8E4}' => 230, + '\u{A8E5}' => 230, + '\u{A8E6}' => 230, + '\u{A8E7}' => 230, + '\u{A8E8}' => 230, + '\u{A8E9}' => 230, + '\u{A8EA}' => 230, + '\u{A8EB}' => 230, + '\u{A8EC}' => 230, + '\u{A8ED}' => 230, + '\u{A8EE}' => 230, + '\u{A8EF}' => 230, + '\u{A8F0}' => 230, + '\u{A8F1}' => 230, + '\u{A92B}' => 220, + '\u{A92C}' => 220, + '\u{A92D}' => 220, + '\u{A953}' => 9, + '\u{A9B3}' => 7, + '\u{A9C0}' => 9, + '\u{AAB0}' => 230, + '\u{AAB2}' => 230, + '\u{AAB3}' => 230, + '\u{AAB4}' => 220, + '\u{AAB7}' => 230, + '\u{AAB8}' => 230, + '\u{AABE}' => 230, + '\u{AABF}' => 230, + '\u{AAC1}' => 230, + '\u{AAF6}' => 9, + '\u{ABED}' => 9, + '\u{FB1E}' => 26, + '\u{FE20}' => 230, + '\u{FE21}' => 230, + '\u{FE22}' => 230, + '\u{FE23}' => 230, + '\u{FE24}' => 230, + '\u{FE25}' => 230, + '\u{FE26}' => 230, + '\u{FE27}' => 220, + '\u{FE28}' => 220, + '\u{FE29}' => 220, + '\u{FE2A}' => 220, + '\u{FE2B}' => 220, + '\u{FE2C}' => 220, + '\u{FE2D}' => 220, + '\u{FE2E}' => 230, + '\u{FE2F}' => 230, + '\u{101FD}' => 220, + '\u{102E0}' => 220, + '\u{10376}' => 230, + '\u{10377}' => 230, + '\u{10378}' => 230, + '\u{10379}' => 230, + '\u{1037A}' => 230, + '\u{10A0D}' => 220, + '\u{10A0F}' => 230, + '\u{10A38}' => 230, + '\u{10A39}' => 1, + '\u{10A3A}' => 220, + '\u{10A3F}' => 9, + '\u{10AE5}' => 230, + '\u{10AE6}' => 220, + '\u{11046}' => 9, + '\u{1107F}' => 9, + '\u{110B9}' => 9, + '\u{110BA}' => 7, + '\u{11100}' => 230, + '\u{11101}' => 230, + '\u{11102}' => 230, + '\u{11133}' => 9, + '\u{11134}' => 9, + '\u{11173}' => 7, + '\u{111C0}' => 9, + '\u{111CA}' => 7, + '\u{11235}' => 9, + '\u{11236}' => 7, + '\u{112E9}' => 7, + '\u{112EA}' => 9, + '\u{1133C}' => 7, + '\u{1134D}' => 9, + '\u{11366}' => 230, + '\u{11367}' => 230, + '\u{11368}' => 230, + '\u{11369}' => 230, + '\u{1136A}' => 230, + '\u{1136B}' => 230, + '\u{1136C}' => 230, + '\u{11370}' => 230, + '\u{11371}' => 230, + '\u{11372}' => 230, + '\u{11373}' => 230, + '\u{11374}' => 230, + '\u{11442}' => 9, + '\u{11446}' => 7, + '\u{114C2}' => 9, + '\u{114C3}' => 7, + '\u{115BF}' => 9, + '\u{115C0}' => 7, + '\u{1163F}' => 9, + '\u{116B6}' => 9, + '\u{116B7}' => 7, + '\u{1172B}' => 9, + '\u{11C3F}' => 9, + '\u{16AF0}' => 1, + '\u{16AF1}' => 1, + '\u{16AF2}' => 1, + '\u{16AF3}' => 1, + '\u{16AF4}' => 1, + '\u{16B30}' => 230, + '\u{16B31}' => 230, + '\u{16B32}' => 230, + '\u{16B33}' => 230, + '\u{16B34}' => 230, + '\u{16B35}' => 230, + '\u{16B36}' => 230, + '\u{1BC9E}' => 1, + '\u{1D165}' => 216, + '\u{1D166}' => 216, + '\u{1D167}' => 1, + '\u{1D168}' => 1, + '\u{1D169}' => 1, + '\u{1D16D}' => 226, + '\u{1D16E}' => 216, + '\u{1D16F}' => 216, + '\u{1D170}' => 216, + '\u{1D171}' => 216, + '\u{1D172}' => 216, + '\u{1D17B}' => 220, + '\u{1D17C}' => 220, + '\u{1D17D}' => 220, + '\u{1D17E}' => 220, + '\u{1D17F}' => 220, + '\u{1D180}' => 220, + '\u{1D181}' => 220, + '\u{1D182}' => 220, + '\u{1D185}' => 230, + '\u{1D186}' => 230, + '\u{1D187}' => 230, + '\u{1D188}' => 230, + '\u{1D189}' => 230, + '\u{1D18A}' => 220, + '\u{1D18B}' => 220, + '\u{1D1AA}' => 230, + '\u{1D1AB}' => 230, + '\u{1D1AC}' => 230, + '\u{1D1AD}' => 230, + '\u{1D242}' => 230, + '\u{1D243}' => 230, + '\u{1D244}' => 230, + '\u{1E000}' => 230, + '\u{1E001}' => 230, + '\u{1E002}' => 230, + '\u{1E003}' => 230, + '\u{1E004}' => 230, + '\u{1E005}' => 230, + '\u{1E006}' => 230, + '\u{1E008}' => 230, + '\u{1E009}' => 230, + '\u{1E00A}' => 230, + '\u{1E00B}' => 230, + '\u{1E00C}' => 230, + '\u{1E00D}' => 230, + '\u{1E00E}' => 230, + '\u{1E00F}' => 230, + '\u{1E010}' => 230, + '\u{1E011}' => 230, + '\u{1E012}' => 230, + '\u{1E013}' => 230, + '\u{1E014}' => 230, + '\u{1E015}' => 230, + '\u{1E016}' => 230, + '\u{1E017}' => 230, + '\u{1E018}' => 230, + '\u{1E01B}' => 230, + '\u{1E01C}' => 230, + '\u{1E01D}' => 230, + '\u{1E01E}' => 230, + '\u{1E01F}' => 230, + '\u{1E020}' => 230, + '\u{1E021}' => 230, + '\u{1E023}' => 230, + '\u{1E024}' => 230, + '\u{1E026}' => 230, + '\u{1E027}' => 230, + '\u{1E028}' => 230, + '\u{1E029}' => 230, + '\u{1E02A}' => 230, + '\u{1E8D0}' => 220, + '\u{1E8D1}' => 220, + '\u{1E8D2}' => 220, + '\u{1E8D3}' => 220, + '\u{1E8D4}' => 220, + '\u{1E8D5}' => 220, + '\u{1E8D6}' => 220, + '\u{1E944}' => 230, + '\u{1E945}' => 230, + '\u{1E946}' => 230, + '\u{1E947}' => 230, + '\u{1E948}' => 230, + '\u{1E949}' => 230, + '\u{1E94A}' => 7, + _ => 0, + } +} + +#[inline] +pub fn composition_table(c1: char, c2: char) -> Option<char> { + match (c1, c2) { + ('\u{003C}', '\u{0338}') => Some('\u{226E}'), + ('\u{003D}', '\u{0338}') => Some('\u{2260}'), + ('\u{003E}', '\u{0338}') => Some('\u{226F}'), + ('\u{0041}', '\u{0300}') => Some('\u{00C0}'), + ('\u{0041}', '\u{0301}') => Some('\u{00C1}'), + ('\u{0041}', '\u{0302}') => Some('\u{00C2}'), + ('\u{0041}', '\u{0303}') => Some('\u{00C3}'), + ('\u{0041}', '\u{0304}') => Some('\u{0100}'), + ('\u{0041}', '\u{0306}') => Some('\u{0102}'), + ('\u{0041}', '\u{0307}') => Some('\u{0226}'), + ('\u{0041}', '\u{0308}') => Some('\u{00C4}'), + ('\u{0041}', '\u{0309}') => Some('\u{1EA2}'), + ('\u{0041}', '\u{030A}') => Some('\u{00C5}'), + ('\u{0041}', '\u{030C}') => Some('\u{01CD}'), + ('\u{0041}', '\u{030F}') => Some('\u{0200}'), + ('\u{0041}', '\u{0311}') => Some('\u{0202}'), + ('\u{0041}', '\u{0323}') => Some('\u{1EA0}'), + ('\u{0041}', '\u{0325}') => Some('\u{1E00}'), + ('\u{0041}', '\u{0328}') => Some('\u{0104}'), + ('\u{0042}', '\u{0307}') => Some('\u{1E02}'), + ('\u{0042}', '\u{0323}') => Some('\u{1E04}'), + ('\u{0042}', '\u{0331}') => Some('\u{1E06}'), + ('\u{0043}', '\u{0301}') => Some('\u{0106}'), + ('\u{0043}', '\u{0302}') => Some('\u{0108}'), + ('\u{0043}', '\u{0307}') => Some('\u{010A}'), + ('\u{0043}', '\u{030C}') => Some('\u{010C}'), + ('\u{0043}', '\u{0327}') => Some('\u{00C7}'), + ('\u{0044}', '\u{0307}') => Some('\u{1E0A}'), + ('\u{0044}', '\u{030C}') => Some('\u{010E}'), + ('\u{0044}', '\u{0323}') => Some('\u{1E0C}'), + ('\u{0044}', '\u{0327}') => Some('\u{1E10}'), + ('\u{0044}', '\u{032D}') => Some('\u{1E12}'), + ('\u{0044}', '\u{0331}') => Some('\u{1E0E}'), + ('\u{0045}', '\u{0300}') => Some('\u{00C8}'), + ('\u{0045}', '\u{0301}') => Some('\u{00C9}'), + ('\u{0045}', '\u{0302}') => Some('\u{00CA}'), + ('\u{0045}', '\u{0303}') => Some('\u{1EBC}'), + ('\u{0045}', '\u{0304}') => Some('\u{0112}'), + ('\u{0045}', '\u{0306}') => Some('\u{0114}'), + ('\u{0045}', '\u{0307}') => Some('\u{0116}'), + ('\u{0045}', '\u{0308}') => Some('\u{00CB}'), + ('\u{0045}', '\u{0309}') => Some('\u{1EBA}'), + ('\u{0045}', '\u{030C}') => Some('\u{011A}'), + ('\u{0045}', '\u{030F}') => Some('\u{0204}'), + ('\u{0045}', '\u{0311}') => Some('\u{0206}'), + ('\u{0045}', '\u{0323}') => Some('\u{1EB8}'), + ('\u{0045}', '\u{0327}') => Some('\u{0228}'), + ('\u{0045}', '\u{0328}') => Some('\u{0118}'), + ('\u{0045}', '\u{032D}') => Some('\u{1E18}'), + ('\u{0045}', '\u{0330}') => Some('\u{1E1A}'), + ('\u{0046}', '\u{0307}') => Some('\u{1E1E}'), + ('\u{0047}', '\u{0301}') => Some('\u{01F4}'), + ('\u{0047}', '\u{0302}') => Some('\u{011C}'), + ('\u{0047}', '\u{0304}') => Some('\u{1E20}'), + ('\u{0047}', '\u{0306}') => Some('\u{011E}'), + ('\u{0047}', '\u{0307}') => Some('\u{0120}'), + ('\u{0047}', '\u{030C}') => Some('\u{01E6}'), + ('\u{0047}', '\u{0327}') => Some('\u{0122}'), + ('\u{0048}', '\u{0302}') => Some('\u{0124}'), + ('\u{0048}', '\u{0307}') => Some('\u{1E22}'), + ('\u{0048}', '\u{0308}') => Some('\u{1E26}'), + ('\u{0048}', '\u{030C}') => Some('\u{021E}'), + ('\u{0048}', '\u{0323}') => Some('\u{1E24}'), + ('\u{0048}', '\u{0327}') => Some('\u{1E28}'), + ('\u{0048}', '\u{032E}') => Some('\u{1E2A}'), + ('\u{0049}', '\u{0300}') => Some('\u{00CC}'), + ('\u{0049}', '\u{0301}') => Some('\u{00CD}'), + ('\u{0049}', '\u{0302}') => Some('\u{00CE}'), + ('\u{0049}', '\u{0303}') => Some('\u{0128}'), + ('\u{0049}', '\u{0304}') => Some('\u{012A}'), + ('\u{0049}', '\u{0306}') => Some('\u{012C}'), + ('\u{0049}', '\u{0307}') => Some('\u{0130}'), + ('\u{0049}', '\u{0308}') => Some('\u{00CF}'), + ('\u{0049}', '\u{0309}') => Some('\u{1EC8}'), + ('\u{0049}', '\u{030C}') => Some('\u{01CF}'), + ('\u{0049}', '\u{030F}') => Some('\u{0208}'), + ('\u{0049}', '\u{0311}') => Some('\u{020A}'), + ('\u{0049}', '\u{0323}') => Some('\u{1ECA}'), + ('\u{0049}', '\u{0328}') => Some('\u{012E}'), + ('\u{0049}', '\u{0330}') => Some('\u{1E2C}'), + ('\u{004A}', '\u{0302}') => Some('\u{0134}'), + ('\u{004B}', '\u{0301}') => Some('\u{1E30}'), + ('\u{004B}', '\u{030C}') => Some('\u{01E8}'), + ('\u{004B}', '\u{0323}') => Some('\u{1E32}'), + ('\u{004B}', '\u{0327}') => Some('\u{0136}'), + ('\u{004B}', '\u{0331}') => Some('\u{1E34}'), + ('\u{004C}', '\u{0301}') => Some('\u{0139}'), + ('\u{004C}', '\u{030C}') => Some('\u{013D}'), + ('\u{004C}', '\u{0323}') => Some('\u{1E36}'), + ('\u{004C}', '\u{0327}') => Some('\u{013B}'), + ('\u{004C}', '\u{032D}') => Some('\u{1E3C}'), + ('\u{004C}', '\u{0331}') => Some('\u{1E3A}'), + ('\u{004D}', '\u{0301}') => Some('\u{1E3E}'), + ('\u{004D}', '\u{0307}') => Some('\u{1E40}'), + ('\u{004D}', '\u{0323}') => Some('\u{1E42}'), + ('\u{004E}', '\u{0300}') => Some('\u{01F8}'), + ('\u{004E}', '\u{0301}') => Some('\u{0143}'), + ('\u{004E}', '\u{0303}') => Some('\u{00D1}'), + ('\u{004E}', '\u{0307}') => Some('\u{1E44}'), + ('\u{004E}', '\u{030C}') => Some('\u{0147}'), + ('\u{004E}', '\u{0323}') => Some('\u{1E46}'), + ('\u{004E}', '\u{0327}') => Some('\u{0145}'), + ('\u{004E}', '\u{032D}') => Some('\u{1E4A}'), + ('\u{004E}', '\u{0331}') => Some('\u{1E48}'), + ('\u{004F}', '\u{0300}') => Some('\u{00D2}'), + ('\u{004F}', '\u{0301}') => Some('\u{00D3}'), + ('\u{004F}', '\u{0302}') => Some('\u{00D4}'), + ('\u{004F}', '\u{0303}') => Some('\u{00D5}'), + ('\u{004F}', '\u{0304}') => Some('\u{014C}'), + ('\u{004F}', '\u{0306}') => Some('\u{014E}'), + ('\u{004F}', '\u{0307}') => Some('\u{022E}'), + ('\u{004F}', '\u{0308}') => Some('\u{00D6}'), + ('\u{004F}', '\u{0309}') => Some('\u{1ECE}'), + ('\u{004F}', '\u{030B}') => Some('\u{0150}'), + ('\u{004F}', '\u{030C}') => Some('\u{01D1}'), + ('\u{004F}', '\u{030F}') => Some('\u{020C}'), + ('\u{004F}', '\u{0311}') => Some('\u{020E}'), + ('\u{004F}', '\u{031B}') => Some('\u{01A0}'), + ('\u{004F}', '\u{0323}') => Some('\u{1ECC}'), + ('\u{004F}', '\u{0328}') => Some('\u{01EA}'), + ('\u{0050}', '\u{0301}') => Some('\u{1E54}'), + ('\u{0050}', '\u{0307}') => Some('\u{1E56}'), + ('\u{0052}', '\u{0301}') => Some('\u{0154}'), + ('\u{0052}', '\u{0307}') => Some('\u{1E58}'), + ('\u{0052}', '\u{030C}') => Some('\u{0158}'), + ('\u{0052}', '\u{030F}') => Some('\u{0210}'), + ('\u{0052}', '\u{0311}') => Some('\u{0212}'), + ('\u{0052}', '\u{0323}') => Some('\u{1E5A}'), + ('\u{0052}', '\u{0327}') => Some('\u{0156}'), + ('\u{0052}', '\u{0331}') => Some('\u{1E5E}'), + ('\u{0053}', '\u{0301}') => Some('\u{015A}'), + ('\u{0053}', '\u{0302}') => Some('\u{015C}'), + ('\u{0053}', '\u{0307}') => Some('\u{1E60}'), + ('\u{0053}', '\u{030C}') => Some('\u{0160}'), + ('\u{0053}', '\u{0323}') => Some('\u{1E62}'), + ('\u{0053}', '\u{0326}') => Some('\u{0218}'), + ('\u{0053}', '\u{0327}') => Some('\u{015E}'), + ('\u{0054}', '\u{0307}') => Some('\u{1E6A}'), + ('\u{0054}', '\u{030C}') => Some('\u{0164}'), + ('\u{0054}', '\u{0323}') => Some('\u{1E6C}'), + ('\u{0054}', '\u{0326}') => Some('\u{021A}'), + ('\u{0054}', '\u{0327}') => Some('\u{0162}'), + ('\u{0054}', '\u{032D}') => Some('\u{1E70}'), + ('\u{0054}', '\u{0331}') => Some('\u{1E6E}'), + ('\u{0055}', '\u{0300}') => Some('\u{00D9}'), + ('\u{0055}', '\u{0301}') => Some('\u{00DA}'), + ('\u{0055}', '\u{0302}') => Some('\u{00DB}'), + ('\u{0055}', '\u{0303}') => Some('\u{0168}'), + ('\u{0055}', '\u{0304}') => Some('\u{016A}'), + ('\u{0055}', '\u{0306}') => Some('\u{016C}'), + ('\u{0055}', '\u{0308}') => Some('\u{00DC}'), + ('\u{0055}', '\u{0309}') => Some('\u{1EE6}'), + ('\u{0055}', '\u{030A}') => Some('\u{016E}'), + ('\u{0055}', '\u{030B}') => Some('\u{0170}'), + ('\u{0055}', '\u{030C}') => Some('\u{01D3}'), + ('\u{0055}', '\u{030F}') => Some('\u{0214}'), + ('\u{0055}', '\u{0311}') => Some('\u{0216}'), + ('\u{0055}', '\u{031B}') => Some('\u{01AF}'), + ('\u{0055}', '\u{0323}') => Some('\u{1EE4}'), + ('\u{0055}', '\u{0324}') => Some('\u{1E72}'), + ('\u{0055}', '\u{0328}') => Some('\u{0172}'), + ('\u{0055}', '\u{032D}') => Some('\u{1E76}'), + ('\u{0055}', '\u{0330}') => Some('\u{1E74}'), + ('\u{0056}', '\u{0303}') => Some('\u{1E7C}'), + ('\u{0056}', '\u{0323}') => Some('\u{1E7E}'), + ('\u{0057}', '\u{0300}') => Some('\u{1E80}'), + ('\u{0057}', '\u{0301}') => Some('\u{1E82}'), + ('\u{0057}', '\u{0302}') => Some('\u{0174}'), + ('\u{0057}', '\u{0307}') => Some('\u{1E86}'), + ('\u{0057}', '\u{0308}') => Some('\u{1E84}'), + ('\u{0057}', '\u{0323}') => Some('\u{1E88}'), + ('\u{0058}', '\u{0307}') => Some('\u{1E8A}'), + ('\u{0058}', '\u{0308}') => Some('\u{1E8C}'), + ('\u{0059}', '\u{0300}') => Some('\u{1EF2}'), + ('\u{0059}', '\u{0301}') => Some('\u{00DD}'), + ('\u{0059}', '\u{0302}') => Some('\u{0176}'), + ('\u{0059}', '\u{0303}') => Some('\u{1EF8}'), + ('\u{0059}', '\u{0304}') => Some('\u{0232}'), + ('\u{0059}', '\u{0307}') => Some('\u{1E8E}'), + ('\u{0059}', '\u{0308}') => Some('\u{0178}'), + ('\u{0059}', '\u{0309}') => Some('\u{1EF6}'), + ('\u{0059}', '\u{0323}') => Some('\u{1EF4}'), + ('\u{005A}', '\u{0301}') => Some('\u{0179}'), + ('\u{005A}', '\u{0302}') => Some('\u{1E90}'), + ('\u{005A}', '\u{0307}') => Some('\u{017B}'), + ('\u{005A}', '\u{030C}') => Some('\u{017D}'), + ('\u{005A}', '\u{0323}') => Some('\u{1E92}'), + ('\u{005A}', '\u{0331}') => Some('\u{1E94}'), + ('\u{0061}', '\u{0300}') => Some('\u{00E0}'), + ('\u{0061}', '\u{0301}') => Some('\u{00E1}'), + ('\u{0061}', '\u{0302}') => Some('\u{00E2}'), + ('\u{0061}', '\u{0303}') => Some('\u{00E3}'), + ('\u{0061}', '\u{0304}') => Some('\u{0101}'), + ('\u{0061}', '\u{0306}') => Some('\u{0103}'), + ('\u{0061}', '\u{0307}') => Some('\u{0227}'), + ('\u{0061}', '\u{0308}') => Some('\u{00E4}'), + ('\u{0061}', '\u{0309}') => Some('\u{1EA3}'), + ('\u{0061}', '\u{030A}') => Some('\u{00E5}'), + ('\u{0061}', '\u{030C}') => Some('\u{01CE}'), + ('\u{0061}', '\u{030F}') => Some('\u{0201}'), + ('\u{0061}', '\u{0311}') => Some('\u{0203}'), + ('\u{0061}', '\u{0323}') => Some('\u{1EA1}'), + ('\u{0061}', '\u{0325}') => Some('\u{1E01}'), + ('\u{0061}', '\u{0328}') => Some('\u{0105}'), + ('\u{0062}', '\u{0307}') => Some('\u{1E03}'), + ('\u{0062}', '\u{0323}') => Some('\u{1E05}'), + ('\u{0062}', '\u{0331}') => Some('\u{1E07}'), + ('\u{0063}', '\u{0301}') => Some('\u{0107}'), + ('\u{0063}', '\u{0302}') => Some('\u{0109}'), + ('\u{0063}', '\u{0307}') => Some('\u{010B}'), + ('\u{0063}', '\u{030C}') => Some('\u{010D}'), + ('\u{0063}', '\u{0327}') => Some('\u{00E7}'), + ('\u{0064}', '\u{0307}') => Some('\u{1E0B}'), + ('\u{0064}', '\u{030C}') => Some('\u{010F}'), + ('\u{0064}', '\u{0323}') => Some('\u{1E0D}'), + ('\u{0064}', '\u{0327}') => Some('\u{1E11}'), + ('\u{0064}', '\u{032D}') => Some('\u{1E13}'), + ('\u{0064}', '\u{0331}') => Some('\u{1E0F}'), + ('\u{0065}', '\u{0300}') => Some('\u{00E8}'), + ('\u{0065}', '\u{0301}') => Some('\u{00E9}'), + ('\u{0065}', '\u{0302}') => Some('\u{00EA}'), + ('\u{0065}', '\u{0303}') => Some('\u{1EBD}'), + ('\u{0065}', '\u{0304}') => Some('\u{0113}'), + ('\u{0065}', '\u{0306}') => Some('\u{0115}'), + ('\u{0065}', '\u{0307}') => Some('\u{0117}'), + ('\u{0065}', '\u{0308}') => Some('\u{00EB}'), + ('\u{0065}', '\u{0309}') => Some('\u{1EBB}'), + ('\u{0065}', '\u{030C}') => Some('\u{011B}'), + ('\u{0065}', '\u{030F}') => Some('\u{0205}'), + ('\u{0065}', '\u{0311}') => Some('\u{0207}'), + ('\u{0065}', '\u{0323}') => Some('\u{1EB9}'), + ('\u{0065}', '\u{0327}') => Some('\u{0229}'), + ('\u{0065}', '\u{0328}') => Some('\u{0119}'), + ('\u{0065}', '\u{032D}') => Some('\u{1E19}'), + ('\u{0065}', '\u{0330}') => Some('\u{1E1B}'), + ('\u{0066}', '\u{0307}') => Some('\u{1E1F}'), + ('\u{0067}', '\u{0301}') => Some('\u{01F5}'), + ('\u{0067}', '\u{0302}') => Some('\u{011D}'), + ('\u{0067}', '\u{0304}') => Some('\u{1E21}'), + ('\u{0067}', '\u{0306}') => Some('\u{011F}'), + ('\u{0067}', '\u{0307}') => Some('\u{0121}'), + ('\u{0067}', '\u{030C}') => Some('\u{01E7}'), + ('\u{0067}', '\u{0327}') => Some('\u{0123}'), + ('\u{0068}', '\u{0302}') => Some('\u{0125}'), + ('\u{0068}', '\u{0307}') => Some('\u{1E23}'), + ('\u{0068}', '\u{0308}') => Some('\u{1E27}'), + ('\u{0068}', '\u{030C}') => Some('\u{021F}'), + ('\u{0068}', '\u{0323}') => Some('\u{1E25}'), + ('\u{0068}', '\u{0327}') => Some('\u{1E29}'), + ('\u{0068}', '\u{032E}') => Some('\u{1E2B}'), + ('\u{0068}', '\u{0331}') => Some('\u{1E96}'), + ('\u{0069}', '\u{0300}') => Some('\u{00EC}'), + ('\u{0069}', '\u{0301}') => Some('\u{00ED}'), + ('\u{0069}', '\u{0302}') => Some('\u{00EE}'), + ('\u{0069}', '\u{0303}') => Some('\u{0129}'), + ('\u{0069}', '\u{0304}') => Some('\u{012B}'), + ('\u{0069}', '\u{0306}') => Some('\u{012D}'), + ('\u{0069}', '\u{0308}') => Some('\u{00EF}'), + ('\u{0069}', '\u{0309}') => Some('\u{1EC9}'), + ('\u{0069}', '\u{030C}') => Some('\u{01D0}'), + ('\u{0069}', '\u{030F}') => Some('\u{0209}'), + ('\u{0069}', '\u{0311}') => Some('\u{020B}'), + ('\u{0069}', '\u{0323}') => Some('\u{1ECB}'), + ('\u{0069}', '\u{0328}') => Some('\u{012F}'), + ('\u{0069}', '\u{0330}') => Some('\u{1E2D}'), + ('\u{006A}', '\u{0302}') => Some('\u{0135}'), + ('\u{006A}', '\u{030C}') => Some('\u{01F0}'), + ('\u{006B}', '\u{0301}') => Some('\u{1E31}'), + ('\u{006B}', '\u{030C}') => Some('\u{01E9}'), + ('\u{006B}', '\u{0323}') => Some('\u{1E33}'), + ('\u{006B}', '\u{0327}') => Some('\u{0137}'), + ('\u{006B}', '\u{0331}') => Some('\u{1E35}'), + ('\u{006C}', '\u{0301}') => Some('\u{013A}'), + ('\u{006C}', '\u{030C}') => Some('\u{013E}'), + ('\u{006C}', '\u{0323}') => Some('\u{1E37}'), + ('\u{006C}', '\u{0327}') => Some('\u{013C}'), + ('\u{006C}', '\u{032D}') => Some('\u{1E3D}'), + ('\u{006C}', '\u{0331}') => Some('\u{1E3B}'), + ('\u{006D}', '\u{0301}') => Some('\u{1E3F}'), + ('\u{006D}', '\u{0307}') => Some('\u{1E41}'), + ('\u{006D}', '\u{0323}') => Some('\u{1E43}'), + ('\u{006E}', '\u{0300}') => Some('\u{01F9}'), + ('\u{006E}', '\u{0301}') => Some('\u{0144}'), + ('\u{006E}', '\u{0303}') => Some('\u{00F1}'), + ('\u{006E}', '\u{0307}') => Some('\u{1E45}'), + ('\u{006E}', '\u{030C}') => Some('\u{0148}'), + ('\u{006E}', '\u{0323}') => Some('\u{1E47}'), + ('\u{006E}', '\u{0327}') => Some('\u{0146}'), + ('\u{006E}', '\u{032D}') => Some('\u{1E4B}'), + ('\u{006E}', '\u{0331}') => Some('\u{1E49}'), + ('\u{006F}', '\u{0300}') => Some('\u{00F2}'), + ('\u{006F}', '\u{0301}') => Some('\u{00F3}'), + ('\u{006F}', '\u{0302}') => Some('\u{00F4}'), + ('\u{006F}', '\u{0303}') => Some('\u{00F5}'), + ('\u{006F}', '\u{0304}') => Some('\u{014D}'), + ('\u{006F}', '\u{0306}') => Some('\u{014F}'), + ('\u{006F}', '\u{0307}') => Some('\u{022F}'), + ('\u{006F}', '\u{0308}') => Some('\u{00F6}'), + ('\u{006F}', '\u{0309}') => Some('\u{1ECF}'), + ('\u{006F}', '\u{030B}') => Some('\u{0151}'), + ('\u{006F}', '\u{030C}') => Some('\u{01D2}'), + ('\u{006F}', '\u{030F}') => Some('\u{020D}'), + ('\u{006F}', '\u{0311}') => Some('\u{020F}'), + ('\u{006F}', '\u{031B}') => Some('\u{01A1}'), + ('\u{006F}', '\u{0323}') => Some('\u{1ECD}'), + ('\u{006F}', '\u{0328}') => Some('\u{01EB}'), + ('\u{0070}', '\u{0301}') => Some('\u{1E55}'), + ('\u{0070}', '\u{0307}') => Some('\u{1E57}'), + ('\u{0072}', '\u{0301}') => Some('\u{0155}'), + ('\u{0072}', '\u{0307}') => Some('\u{1E59}'), + ('\u{0072}', '\u{030C}') => Some('\u{0159}'), + ('\u{0072}', '\u{030F}') => Some('\u{0211}'), + ('\u{0072}', '\u{0311}') => Some('\u{0213}'), + ('\u{0072}', '\u{0323}') => Some('\u{1E5B}'), + ('\u{0072}', '\u{0327}') => Some('\u{0157}'), + ('\u{0072}', '\u{0331}') => Some('\u{1E5F}'), + ('\u{0073}', '\u{0301}') => Some('\u{015B}'), + ('\u{0073}', '\u{0302}') => Some('\u{015D}'), + ('\u{0073}', '\u{0307}') => Some('\u{1E61}'), + ('\u{0073}', '\u{030C}') => Some('\u{0161}'), + ('\u{0073}', '\u{0323}') => Some('\u{1E63}'), + ('\u{0073}', '\u{0326}') => Some('\u{0219}'), + ('\u{0073}', '\u{0327}') => Some('\u{015F}'), + ('\u{0074}', '\u{0307}') => Some('\u{1E6B}'), + ('\u{0074}', '\u{0308}') => Some('\u{1E97}'), + ('\u{0074}', '\u{030C}') => Some('\u{0165}'), + ('\u{0074}', '\u{0323}') => Some('\u{1E6D}'), + ('\u{0074}', '\u{0326}') => Some('\u{021B}'), + ('\u{0074}', '\u{0327}') => Some('\u{0163}'), + ('\u{0074}', '\u{032D}') => Some('\u{1E71}'), + ('\u{0074}', '\u{0331}') => Some('\u{1E6F}'), + ('\u{0075}', '\u{0300}') => Some('\u{00F9}'), + ('\u{0075}', '\u{0301}') => Some('\u{00FA}'), + ('\u{0075}', '\u{0302}') => Some('\u{00FB}'), + ('\u{0075}', '\u{0303}') => Some('\u{0169}'), + ('\u{0075}', '\u{0304}') => Some('\u{016B}'), + ('\u{0075}', '\u{0306}') => Some('\u{016D}'), + ('\u{0075}', '\u{0308}') => Some('\u{00FC}'), + ('\u{0075}', '\u{0309}') => Some('\u{1EE7}'), + ('\u{0075}', '\u{030A}') => Some('\u{016F}'), + ('\u{0075}', '\u{030B}') => Some('\u{0171}'), + ('\u{0075}', '\u{030C}') => Some('\u{01D4}'), + ('\u{0075}', '\u{030F}') => Some('\u{0215}'), + ('\u{0075}', '\u{0311}') => Some('\u{0217}'), + ('\u{0075}', '\u{031B}') => Some('\u{01B0}'), + ('\u{0075}', '\u{0323}') => Some('\u{1EE5}'), + ('\u{0075}', '\u{0324}') => Some('\u{1E73}'), + ('\u{0075}', '\u{0328}') => Some('\u{0173}'), + ('\u{0075}', '\u{032D}') => Some('\u{1E77}'), + ('\u{0075}', '\u{0330}') => Some('\u{1E75}'), + ('\u{0076}', '\u{0303}') => Some('\u{1E7D}'), + ('\u{0076}', '\u{0323}') => Some('\u{1E7F}'), + ('\u{0077}', '\u{0300}') => Some('\u{1E81}'), + ('\u{0077}', '\u{0301}') => Some('\u{1E83}'), + ('\u{0077}', '\u{0302}') => Some('\u{0175}'), + ('\u{0077}', '\u{0307}') => Some('\u{1E87}'), + ('\u{0077}', '\u{0308}') => Some('\u{1E85}'), + ('\u{0077}', '\u{030A}') => Some('\u{1E98}'), + ('\u{0077}', '\u{0323}') => Some('\u{1E89}'), + ('\u{0078}', '\u{0307}') => Some('\u{1E8B}'), + ('\u{0078}', '\u{0308}') => Some('\u{1E8D}'), + ('\u{0079}', '\u{0300}') => Some('\u{1EF3}'), + ('\u{0079}', '\u{0301}') => Some('\u{00FD}'), + ('\u{0079}', '\u{0302}') => Some('\u{0177}'), + ('\u{0079}', '\u{0303}') => Some('\u{1EF9}'), + ('\u{0079}', '\u{0304}') => Some('\u{0233}'), + ('\u{0079}', '\u{0307}') => Some('\u{1E8F}'), + ('\u{0079}', '\u{0308}') => Some('\u{00FF}'), + ('\u{0079}', '\u{0309}') => Some('\u{1EF7}'), + ('\u{0079}', '\u{030A}') => Some('\u{1E99}'), + ('\u{0079}', '\u{0323}') => Some('\u{1EF5}'), + ('\u{007A}', '\u{0301}') => Some('\u{017A}'), + ('\u{007A}', '\u{0302}') => Some('\u{1E91}'), + ('\u{007A}', '\u{0307}') => Some('\u{017C}'), + ('\u{007A}', '\u{030C}') => Some('\u{017E}'), + ('\u{007A}', '\u{0323}') => Some('\u{1E93}'), + ('\u{007A}', '\u{0331}') => Some('\u{1E95}'), + ('\u{00A8}', '\u{0300}') => Some('\u{1FED}'), + ('\u{00A8}', '\u{0301}') => Some('\u{0385}'), + ('\u{00A8}', '\u{0342}') => Some('\u{1FC1}'), + ('\u{00C2}', '\u{0300}') => Some('\u{1EA6}'), + ('\u{00C2}', '\u{0301}') => Some('\u{1EA4}'), + ('\u{00C2}', '\u{0303}') => Some('\u{1EAA}'), + ('\u{00C2}', '\u{0309}') => Some('\u{1EA8}'), + ('\u{00C4}', '\u{0304}') => Some('\u{01DE}'), + ('\u{00C5}', '\u{0301}') => Some('\u{01FA}'), + ('\u{00C6}', '\u{0301}') => Some('\u{01FC}'), + ('\u{00C6}', '\u{0304}') => Some('\u{01E2}'), + ('\u{00C7}', '\u{0301}') => Some('\u{1E08}'), + ('\u{00CA}', '\u{0300}') => Some('\u{1EC0}'), + ('\u{00CA}', '\u{0301}') => Some('\u{1EBE}'), + ('\u{00CA}', '\u{0303}') => Some('\u{1EC4}'), + ('\u{00CA}', '\u{0309}') => Some('\u{1EC2}'), + ('\u{00CF}', '\u{0301}') => Some('\u{1E2E}'), + ('\u{00D4}', '\u{0300}') => Some('\u{1ED2}'), + ('\u{00D4}', '\u{0301}') => Some('\u{1ED0}'), + ('\u{00D4}', '\u{0303}') => Some('\u{1ED6}'), + ('\u{00D4}', '\u{0309}') => Some('\u{1ED4}'), + ('\u{00D5}', '\u{0301}') => Some('\u{1E4C}'), + ('\u{00D5}', '\u{0304}') => Some('\u{022C}'), + ('\u{00D5}', '\u{0308}') => Some('\u{1E4E}'), + ('\u{00D6}', '\u{0304}') => Some('\u{022A}'), + ('\u{00D8}', '\u{0301}') => Some('\u{01FE}'), + ('\u{00DC}', '\u{0300}') => Some('\u{01DB}'), + ('\u{00DC}', '\u{0301}') => Some('\u{01D7}'), + ('\u{00DC}', '\u{0304}') => Some('\u{01D5}'), + ('\u{00DC}', '\u{030C}') => Some('\u{01D9}'), + ('\u{00E2}', '\u{0300}') => Some('\u{1EA7}'), + ('\u{00E2}', '\u{0301}') => Some('\u{1EA5}'), + ('\u{00E2}', '\u{0303}') => Some('\u{1EAB}'), + ('\u{00E2}', '\u{0309}') => Some('\u{1EA9}'), + ('\u{00E4}', '\u{0304}') => Some('\u{01DF}'), + ('\u{00E5}', '\u{0301}') => Some('\u{01FB}'), + ('\u{00E6}', '\u{0301}') => Some('\u{01FD}'), + ('\u{00E6}', '\u{0304}') => Some('\u{01E3}'), + ('\u{00E7}', '\u{0301}') => Some('\u{1E09}'), + ('\u{00EA}', '\u{0300}') => Some('\u{1EC1}'), + ('\u{00EA}', '\u{0301}') => Some('\u{1EBF}'), + ('\u{00EA}', '\u{0303}') => Some('\u{1EC5}'), + ('\u{00EA}', '\u{0309}') => Some('\u{1EC3}'), + ('\u{00EF}', '\u{0301}') => Some('\u{1E2F}'), + ('\u{00F4}', '\u{0300}') => Some('\u{1ED3}'), + ('\u{00F4}', '\u{0301}') => Some('\u{1ED1}'), + ('\u{00F4}', '\u{0303}') => Some('\u{1ED7}'), + ('\u{00F4}', '\u{0309}') => Some('\u{1ED5}'), + ('\u{00F5}', '\u{0301}') => Some('\u{1E4D}'), + ('\u{00F5}', '\u{0304}') => Some('\u{022D}'), + ('\u{00F5}', '\u{0308}') => Some('\u{1E4F}'), + ('\u{00F6}', '\u{0304}') => Some('\u{022B}'), + ('\u{00F8}', '\u{0301}') => Some('\u{01FF}'), + ('\u{00FC}', '\u{0300}') => Some('\u{01DC}'), + ('\u{00FC}', '\u{0301}') => Some('\u{01D8}'), + ('\u{00FC}', '\u{0304}') => Some('\u{01D6}'), + ('\u{00FC}', '\u{030C}') => Some('\u{01DA}'), + ('\u{0102}', '\u{0300}') => Some('\u{1EB0}'), + ('\u{0102}', '\u{0301}') => Some('\u{1EAE}'), + ('\u{0102}', '\u{0303}') => Some('\u{1EB4}'), + ('\u{0102}', '\u{0309}') => Some('\u{1EB2}'), + ('\u{0103}', '\u{0300}') => Some('\u{1EB1}'), + ('\u{0103}', '\u{0301}') => Some('\u{1EAF}'), + ('\u{0103}', '\u{0303}') => Some('\u{1EB5}'), + ('\u{0103}', '\u{0309}') => Some('\u{1EB3}'), + ('\u{0112}', '\u{0300}') => Some('\u{1E14}'), + ('\u{0112}', '\u{0301}') => Some('\u{1E16}'), + ('\u{0113}', '\u{0300}') => Some('\u{1E15}'), + ('\u{0113}', '\u{0301}') => Some('\u{1E17}'), + ('\u{014C}', '\u{0300}') => Some('\u{1E50}'), + ('\u{014C}', '\u{0301}') => Some('\u{1E52}'), + ('\u{014D}', '\u{0300}') => Some('\u{1E51}'), + ('\u{014D}', '\u{0301}') => Some('\u{1E53}'), + ('\u{015A}', '\u{0307}') => Some('\u{1E64}'), + ('\u{015B}', '\u{0307}') => Some('\u{1E65}'), + ('\u{0160}', '\u{0307}') => Some('\u{1E66}'), + ('\u{0161}', '\u{0307}') => Some('\u{1E67}'), + ('\u{0168}', '\u{0301}') => Some('\u{1E78}'), + ('\u{0169}', '\u{0301}') => Some('\u{1E79}'), + ('\u{016A}', '\u{0308}') => Some('\u{1E7A}'), + ('\u{016B}', '\u{0308}') => Some('\u{1E7B}'), + ('\u{017F}', '\u{0307}') => Some('\u{1E9B}'), + ('\u{01A0}', '\u{0300}') => Some('\u{1EDC}'), + ('\u{01A0}', '\u{0301}') => Some('\u{1EDA}'), + ('\u{01A0}', '\u{0303}') => Some('\u{1EE0}'), + ('\u{01A0}', '\u{0309}') => Some('\u{1EDE}'), + ('\u{01A0}', '\u{0323}') => Some('\u{1EE2}'), + ('\u{01A1}', '\u{0300}') => Some('\u{1EDD}'), + ('\u{01A1}', '\u{0301}') => Some('\u{1EDB}'), + ('\u{01A1}', '\u{0303}') => Some('\u{1EE1}'), + ('\u{01A1}', '\u{0309}') => Some('\u{1EDF}'), + ('\u{01A1}', '\u{0323}') => Some('\u{1EE3}'), + ('\u{01AF}', '\u{0300}') => Some('\u{1EEA}'), + ('\u{01AF}', '\u{0301}') => Some('\u{1EE8}'), + ('\u{01AF}', '\u{0303}') => Some('\u{1EEE}'), + ('\u{01AF}', '\u{0309}') => Some('\u{1EEC}'), + ('\u{01AF}', '\u{0323}') => Some('\u{1EF0}'), + ('\u{01B0}', '\u{0300}') => Some('\u{1EEB}'), + ('\u{01B0}', '\u{0301}') => Some('\u{1EE9}'), + ('\u{01B0}', '\u{0303}') => Some('\u{1EEF}'), + ('\u{01B0}', '\u{0309}') => Some('\u{1EED}'), + ('\u{01B0}', '\u{0323}') => Some('\u{1EF1}'), + ('\u{01B7}', '\u{030C}') => Some('\u{01EE}'), + ('\u{01EA}', '\u{0304}') => Some('\u{01EC}'), + ('\u{01EB}', '\u{0304}') => Some('\u{01ED}'), + ('\u{0226}', '\u{0304}') => Some('\u{01E0}'), + ('\u{0227}', '\u{0304}') => Some('\u{01E1}'), + ('\u{0228}', '\u{0306}') => Some('\u{1E1C}'), + ('\u{0229}', '\u{0306}') => Some('\u{1E1D}'), + ('\u{022E}', '\u{0304}') => Some('\u{0230}'), + ('\u{022F}', '\u{0304}') => Some('\u{0231}'), + ('\u{0292}', '\u{030C}') => Some('\u{01EF}'), + ('\u{0391}', '\u{0300}') => Some('\u{1FBA}'), + ('\u{0391}', '\u{0301}') => Some('\u{0386}'), + ('\u{0391}', '\u{0304}') => Some('\u{1FB9}'), + ('\u{0391}', '\u{0306}') => Some('\u{1FB8}'), + ('\u{0391}', '\u{0313}') => Some('\u{1F08}'), + ('\u{0391}', '\u{0314}') => Some('\u{1F09}'), + ('\u{0391}', '\u{0345}') => Some('\u{1FBC}'), + ('\u{0395}', '\u{0300}') => Some('\u{1FC8}'), + ('\u{0395}', '\u{0301}') => Some('\u{0388}'), + ('\u{0395}', '\u{0313}') => Some('\u{1F18}'), + ('\u{0395}', '\u{0314}') => Some('\u{1F19}'), + ('\u{0397}', '\u{0300}') => Some('\u{1FCA}'), + ('\u{0397}', '\u{0301}') => Some('\u{0389}'), + ('\u{0397}', '\u{0313}') => Some('\u{1F28}'), + ('\u{0397}', '\u{0314}') => Some('\u{1F29}'), + ('\u{0397}', '\u{0345}') => Some('\u{1FCC}'), + ('\u{0399}', '\u{0300}') => Some('\u{1FDA}'), + ('\u{0399}', '\u{0301}') => Some('\u{038A}'), + ('\u{0399}', '\u{0304}') => Some('\u{1FD9}'), + ('\u{0399}', '\u{0306}') => Some('\u{1FD8}'), + ('\u{0399}', '\u{0308}') => Some('\u{03AA}'), + ('\u{0399}', '\u{0313}') => Some('\u{1F38}'), + ('\u{0399}', '\u{0314}') => Some('\u{1F39}'), + ('\u{039F}', '\u{0300}') => Some('\u{1FF8}'), + ('\u{039F}', '\u{0301}') => Some('\u{038C}'), + ('\u{039F}', '\u{0313}') => Some('\u{1F48}'), + ('\u{039F}', '\u{0314}') => Some('\u{1F49}'), + ('\u{03A1}', '\u{0314}') => Some('\u{1FEC}'), + ('\u{03A5}', '\u{0300}') => Some('\u{1FEA}'), + ('\u{03A5}', '\u{0301}') => Some('\u{038E}'), + ('\u{03A5}', '\u{0304}') => Some('\u{1FE9}'), + ('\u{03A5}', '\u{0306}') => Some('\u{1FE8}'), + ('\u{03A5}', '\u{0308}') => Some('\u{03AB}'), + ('\u{03A5}', '\u{0314}') => Some('\u{1F59}'), + ('\u{03A9}', '\u{0300}') => Some('\u{1FFA}'), + ('\u{03A9}', '\u{0301}') => Some('\u{038F}'), + ('\u{03A9}', '\u{0313}') => Some('\u{1F68}'), + ('\u{03A9}', '\u{0314}') => Some('\u{1F69}'), + ('\u{03A9}', '\u{0345}') => Some('\u{1FFC}'), + ('\u{03AC}', '\u{0345}') => Some('\u{1FB4}'), + ('\u{03AE}', '\u{0345}') => Some('\u{1FC4}'), + ('\u{03B1}', '\u{0300}') => Some('\u{1F70}'), + ('\u{03B1}', '\u{0301}') => Some('\u{03AC}'), + ('\u{03B1}', '\u{0304}') => Some('\u{1FB1}'), + ('\u{03B1}', '\u{0306}') => Some('\u{1FB0}'), + ('\u{03B1}', '\u{0313}') => Some('\u{1F00}'), + ('\u{03B1}', '\u{0314}') => Some('\u{1F01}'), + ('\u{03B1}', '\u{0342}') => Some('\u{1FB6}'), + ('\u{03B1}', '\u{0345}') => Some('\u{1FB3}'), + ('\u{03B5}', '\u{0300}') => Some('\u{1F72}'), + ('\u{03B5}', '\u{0301}') => Some('\u{03AD}'), + ('\u{03B5}', '\u{0313}') => Some('\u{1F10}'), + ('\u{03B5}', '\u{0314}') => Some('\u{1F11}'), + ('\u{03B7}', '\u{0300}') => Some('\u{1F74}'), + ('\u{03B7}', '\u{0301}') => Some('\u{03AE}'), + ('\u{03B7}', '\u{0313}') => Some('\u{1F20}'), + ('\u{03B7}', '\u{0314}') => Some('\u{1F21}'), + ('\u{03B7}', '\u{0342}') => Some('\u{1FC6}'), + ('\u{03B7}', '\u{0345}') => Some('\u{1FC3}'), + ('\u{03B9}', '\u{0300}') => Some('\u{1F76}'), + ('\u{03B9}', '\u{0301}') => Some('\u{03AF}'), + ('\u{03B9}', '\u{0304}') => Some('\u{1FD1}'), + ('\u{03B9}', '\u{0306}') => Some('\u{1FD0}'), + ('\u{03B9}', '\u{0308}') => Some('\u{03CA}'), + ('\u{03B9}', '\u{0313}') => Some('\u{1F30}'), + ('\u{03B9}', '\u{0314}') => Some('\u{1F31}'), + ('\u{03B9}', '\u{0342}') => Some('\u{1FD6}'), + ('\u{03BF}', '\u{0300}') => Some('\u{1F78}'), + ('\u{03BF}', '\u{0301}') => Some('\u{03CC}'), + ('\u{03BF}', '\u{0313}') => Some('\u{1F40}'), + ('\u{03BF}', '\u{0314}') => Some('\u{1F41}'), + ('\u{03C1}', '\u{0313}') => Some('\u{1FE4}'), + ('\u{03C1}', '\u{0314}') => Some('\u{1FE5}'), + ('\u{03C5}', '\u{0300}') => Some('\u{1F7A}'), + ('\u{03C5}', '\u{0301}') => Some('\u{03CD}'), + ('\u{03C5}', '\u{0304}') => Some('\u{1FE1}'), + ('\u{03C5}', '\u{0306}') => Some('\u{1FE0}'), + ('\u{03C5}', '\u{0308}') => Some('\u{03CB}'), + ('\u{03C5}', '\u{0313}') => Some('\u{1F50}'), + ('\u{03C5}', '\u{0314}') => Some('\u{1F51}'), + ('\u{03C5}', '\u{0342}') => Some('\u{1FE6}'), + ('\u{03C9}', '\u{0300}') => Some('\u{1F7C}'), + ('\u{03C9}', '\u{0301}') => Some('\u{03CE}'), + ('\u{03C9}', '\u{0313}') => Some('\u{1F60}'), + ('\u{03C9}', '\u{0314}') => Some('\u{1F61}'), + ('\u{03C9}', '\u{0342}') => Some('\u{1FF6}'), + ('\u{03C9}', '\u{0345}') => Some('\u{1FF3}'), + ('\u{03CA}', '\u{0300}') => Some('\u{1FD2}'), + ('\u{03CA}', '\u{0301}') => Some('\u{0390}'), + ('\u{03CA}', '\u{0342}') => Some('\u{1FD7}'), + ('\u{03CB}', '\u{0300}') => Some('\u{1FE2}'), + ('\u{03CB}', '\u{0301}') => Some('\u{03B0}'), + ('\u{03CB}', '\u{0342}') => Some('\u{1FE7}'), + ('\u{03CE}', '\u{0345}') => Some('\u{1FF4}'), + ('\u{03D2}', '\u{0301}') => Some('\u{03D3}'), + ('\u{03D2}', '\u{0308}') => Some('\u{03D4}'), + ('\u{0406}', '\u{0308}') => Some('\u{0407}'), + ('\u{0410}', '\u{0306}') => Some('\u{04D0}'), + ('\u{0410}', '\u{0308}') => Some('\u{04D2}'), + ('\u{0413}', '\u{0301}') => Some('\u{0403}'), + ('\u{0415}', '\u{0300}') => Some('\u{0400}'), + ('\u{0415}', '\u{0306}') => Some('\u{04D6}'), + ('\u{0415}', '\u{0308}') => Some('\u{0401}'), + ('\u{0416}', '\u{0306}') => Some('\u{04C1}'), + ('\u{0416}', '\u{0308}') => Some('\u{04DC}'), + ('\u{0417}', '\u{0308}') => Some('\u{04DE}'), + ('\u{0418}', '\u{0300}') => Some('\u{040D}'), + ('\u{0418}', '\u{0304}') => Some('\u{04E2}'), + ('\u{0418}', '\u{0306}') => Some('\u{0419}'), + ('\u{0418}', '\u{0308}') => Some('\u{04E4}'), + ('\u{041A}', '\u{0301}') => Some('\u{040C}'), + ('\u{041E}', '\u{0308}') => Some('\u{04E6}'), + ('\u{0423}', '\u{0304}') => Some('\u{04EE}'), + ('\u{0423}', '\u{0306}') => Some('\u{040E}'), + ('\u{0423}', '\u{0308}') => Some('\u{04F0}'), + ('\u{0423}', '\u{030B}') => Some('\u{04F2}'), + ('\u{0427}', '\u{0308}') => Some('\u{04F4}'), + ('\u{042B}', '\u{0308}') => Some('\u{04F8}'), + ('\u{042D}', '\u{0308}') => Some('\u{04EC}'), + ('\u{0430}', '\u{0306}') => Some('\u{04D1}'), + ('\u{0430}', '\u{0308}') => Some('\u{04D3}'), + ('\u{0433}', '\u{0301}') => Some('\u{0453}'), + ('\u{0435}', '\u{0300}') => Some('\u{0450}'), + ('\u{0435}', '\u{0306}') => Some('\u{04D7}'), + ('\u{0435}', '\u{0308}') => Some('\u{0451}'), + ('\u{0436}', '\u{0306}') => Some('\u{04C2}'), + ('\u{0436}', '\u{0308}') => Some('\u{04DD}'), + ('\u{0437}', '\u{0308}') => Some('\u{04DF}'), + ('\u{0438}', '\u{0300}') => Some('\u{045D}'), + ('\u{0438}', '\u{0304}') => Some('\u{04E3}'), + ('\u{0438}', '\u{0306}') => Some('\u{0439}'), + ('\u{0438}', '\u{0308}') => Some('\u{04E5}'), + ('\u{043A}', '\u{0301}') => Some('\u{045C}'), + ('\u{043E}', '\u{0308}') => Some('\u{04E7}'), + ('\u{0443}', '\u{0304}') => Some('\u{04EF}'), + ('\u{0443}', '\u{0306}') => Some('\u{045E}'), + ('\u{0443}', '\u{0308}') => Some('\u{04F1}'), + ('\u{0443}', '\u{030B}') => Some('\u{04F3}'), + ('\u{0447}', '\u{0308}') => Some('\u{04F5}'), + ('\u{044B}', '\u{0308}') => Some('\u{04F9}'), + ('\u{044D}', '\u{0308}') => Some('\u{04ED}'), + ('\u{0456}', '\u{0308}') => Some('\u{0457}'), + ('\u{0474}', '\u{030F}') => Some('\u{0476}'), + ('\u{0475}', '\u{030F}') => Some('\u{0477}'), + ('\u{04D8}', '\u{0308}') => Some('\u{04DA}'), + ('\u{04D9}', '\u{0308}') => Some('\u{04DB}'), + ('\u{04E8}', '\u{0308}') => Some('\u{04EA}'), + ('\u{04E9}', '\u{0308}') => Some('\u{04EB}'), + ('\u{0627}', '\u{0653}') => Some('\u{0622}'), + ('\u{0627}', '\u{0654}') => Some('\u{0623}'), + ('\u{0627}', '\u{0655}') => Some('\u{0625}'), + ('\u{0648}', '\u{0654}') => Some('\u{0624}'), + ('\u{064A}', '\u{0654}') => Some('\u{0626}'), + ('\u{06C1}', '\u{0654}') => Some('\u{06C2}'), + ('\u{06D2}', '\u{0654}') => Some('\u{06D3}'), + ('\u{06D5}', '\u{0654}') => Some('\u{06C0}'), + ('\u{0928}', '\u{093C}') => Some('\u{0929}'), + ('\u{0930}', '\u{093C}') => Some('\u{0931}'), + ('\u{0933}', '\u{093C}') => Some('\u{0934}'), + ('\u{09C7}', '\u{09BE}') => Some('\u{09CB}'), + ('\u{09C7}', '\u{09D7}') => Some('\u{09CC}'), + ('\u{0B47}', '\u{0B3E}') => Some('\u{0B4B}'), + ('\u{0B47}', '\u{0B56}') => Some('\u{0B48}'), + ('\u{0B47}', '\u{0B57}') => Some('\u{0B4C}'), + ('\u{0B92}', '\u{0BD7}') => Some('\u{0B94}'), + ('\u{0BC6}', '\u{0BBE}') => Some('\u{0BCA}'), + ('\u{0BC6}', '\u{0BD7}') => Some('\u{0BCC}'), + ('\u{0BC7}', '\u{0BBE}') => Some('\u{0BCB}'), + ('\u{0C46}', '\u{0C56}') => Some('\u{0C48}'), + ('\u{0CBF}', '\u{0CD5}') => Some('\u{0CC0}'), + ('\u{0CC6}', '\u{0CC2}') => Some('\u{0CCA}'), + ('\u{0CC6}', '\u{0CD5}') => Some('\u{0CC7}'), + ('\u{0CC6}', '\u{0CD6}') => Some('\u{0CC8}'), + ('\u{0CCA}', '\u{0CD5}') => Some('\u{0CCB}'), + ('\u{0D46}', '\u{0D3E}') => Some('\u{0D4A}'), + ('\u{0D46}', '\u{0D57}') => Some('\u{0D4C}'), + ('\u{0D47}', '\u{0D3E}') => Some('\u{0D4B}'), + ('\u{0DD9}', '\u{0DCA}') => Some('\u{0DDA}'), + ('\u{0DD9}', '\u{0DCF}') => Some('\u{0DDC}'), + ('\u{0DD9}', '\u{0DDF}') => Some('\u{0DDE}'), + ('\u{0DDC}', '\u{0DCA}') => Some('\u{0DDD}'), + ('\u{1025}', '\u{102E}') => Some('\u{1026}'), + ('\u{1B05}', '\u{1B35}') => Some('\u{1B06}'), + ('\u{1B07}', '\u{1B35}') => Some('\u{1B08}'), + ('\u{1B09}', '\u{1B35}') => Some('\u{1B0A}'), + ('\u{1B0B}', '\u{1B35}') => Some('\u{1B0C}'), + ('\u{1B0D}', '\u{1B35}') => Some('\u{1B0E}'), + ('\u{1B11}', '\u{1B35}') => Some('\u{1B12}'), + ('\u{1B3A}', '\u{1B35}') => Some('\u{1B3B}'), + ('\u{1B3C}', '\u{1B35}') => Some('\u{1B3D}'), + ('\u{1B3E}', '\u{1B35}') => Some('\u{1B40}'), + ('\u{1B3F}', '\u{1B35}') => Some('\u{1B41}'), + ('\u{1B42}', '\u{1B35}') => Some('\u{1B43}'), + ('\u{1E36}', '\u{0304}') => Some('\u{1E38}'), + ('\u{1E37}', '\u{0304}') => Some('\u{1E39}'), + ('\u{1E5A}', '\u{0304}') => Some('\u{1E5C}'), + ('\u{1E5B}', '\u{0304}') => Some('\u{1E5D}'), + ('\u{1E62}', '\u{0307}') => Some('\u{1E68}'), + ('\u{1E63}', '\u{0307}') => Some('\u{1E69}'), + ('\u{1EA0}', '\u{0302}') => Some('\u{1EAC}'), + ('\u{1EA0}', '\u{0306}') => Some('\u{1EB6}'), + ('\u{1EA1}', '\u{0302}') => Some('\u{1EAD}'), + ('\u{1EA1}', '\u{0306}') => Some('\u{1EB7}'), + ('\u{1EB8}', '\u{0302}') => Some('\u{1EC6}'), + ('\u{1EB9}', '\u{0302}') => Some('\u{1EC7}'), + ('\u{1ECC}', '\u{0302}') => Some('\u{1ED8}'), + ('\u{1ECD}', '\u{0302}') => Some('\u{1ED9}'), + ('\u{1F00}', '\u{0300}') => Some('\u{1F02}'), + ('\u{1F00}', '\u{0301}') => Some('\u{1F04}'), + ('\u{1F00}', '\u{0342}') => Some('\u{1F06}'), + ('\u{1F00}', '\u{0345}') => Some('\u{1F80}'), + ('\u{1F01}', '\u{0300}') => Some('\u{1F03}'), + ('\u{1F01}', '\u{0301}') => Some('\u{1F05}'), + ('\u{1F01}', '\u{0342}') => Some('\u{1F07}'), + ('\u{1F01}', '\u{0345}') => Some('\u{1F81}'), + ('\u{1F02}', '\u{0345}') => Some('\u{1F82}'), + ('\u{1F03}', '\u{0345}') => Some('\u{1F83}'), + ('\u{1F04}', '\u{0345}') => Some('\u{1F84}'), + ('\u{1F05}', '\u{0345}') => Some('\u{1F85}'), + ('\u{1F06}', '\u{0345}') => Some('\u{1F86}'), + ('\u{1F07}', '\u{0345}') => Some('\u{1F87}'), + ('\u{1F08}', '\u{0300}') => Some('\u{1F0A}'), + ('\u{1F08}', '\u{0301}') => Some('\u{1F0C}'), + ('\u{1F08}', '\u{0342}') => Some('\u{1F0E}'), + ('\u{1F08}', '\u{0345}') => Some('\u{1F88}'), + ('\u{1F09}', '\u{0300}') => Some('\u{1F0B}'), + ('\u{1F09}', '\u{0301}') => Some('\u{1F0D}'), + ('\u{1F09}', '\u{0342}') => Some('\u{1F0F}'), + ('\u{1F09}', '\u{0345}') => Some('\u{1F89}'), + ('\u{1F0A}', '\u{0345}') => Some('\u{1F8A}'), + ('\u{1F0B}', '\u{0345}') => Some('\u{1F8B}'), + ('\u{1F0C}', '\u{0345}') => Some('\u{1F8C}'), + ('\u{1F0D}', '\u{0345}') => Some('\u{1F8D}'), + ('\u{1F0E}', '\u{0345}') => Some('\u{1F8E}'), + ('\u{1F0F}', '\u{0345}') => Some('\u{1F8F}'), + ('\u{1F10}', '\u{0300}') => Some('\u{1F12}'), + ('\u{1F10}', '\u{0301}') => Some('\u{1F14}'), + ('\u{1F11}', '\u{0300}') => Some('\u{1F13}'), + ('\u{1F11}', '\u{0301}') => Some('\u{1F15}'), + ('\u{1F18}', '\u{0300}') => Some('\u{1F1A}'), + ('\u{1F18}', '\u{0301}') => Some('\u{1F1C}'), + ('\u{1F19}', '\u{0300}') => Some('\u{1F1B}'), + ('\u{1F19}', '\u{0301}') => Some('\u{1F1D}'), + ('\u{1F20}', '\u{0300}') => Some('\u{1F22}'), + ('\u{1F20}', '\u{0301}') => Some('\u{1F24}'), + ('\u{1F20}', '\u{0342}') => Some('\u{1F26}'), + ('\u{1F20}', '\u{0345}') => Some('\u{1F90}'), + ('\u{1F21}', '\u{0300}') => Some('\u{1F23}'), + ('\u{1F21}', '\u{0301}') => Some('\u{1F25}'), + ('\u{1F21}', '\u{0342}') => Some('\u{1F27}'), + ('\u{1F21}', '\u{0345}') => Some('\u{1F91}'), + ('\u{1F22}', '\u{0345}') => Some('\u{1F92}'), + ('\u{1F23}', '\u{0345}') => Some('\u{1F93}'), + ('\u{1F24}', '\u{0345}') => Some('\u{1F94}'), + ('\u{1F25}', '\u{0345}') => Some('\u{1F95}'), + ('\u{1F26}', '\u{0345}') => Some('\u{1F96}'), + ('\u{1F27}', '\u{0345}') => Some('\u{1F97}'), + ('\u{1F28}', '\u{0300}') => Some('\u{1F2A}'), + ('\u{1F28}', '\u{0301}') => Some('\u{1F2C}'), + ('\u{1F28}', '\u{0342}') => Some('\u{1F2E}'), + ('\u{1F28}', '\u{0345}') => Some('\u{1F98}'), + ('\u{1F29}', '\u{0300}') => Some('\u{1F2B}'), + ('\u{1F29}', '\u{0301}') => Some('\u{1F2D}'), + ('\u{1F29}', '\u{0342}') => Some('\u{1F2F}'), + ('\u{1F29}', '\u{0345}') => Some('\u{1F99}'), + ('\u{1F2A}', '\u{0345}') => Some('\u{1F9A}'), + ('\u{1F2B}', '\u{0345}') => Some('\u{1F9B}'), + ('\u{1F2C}', '\u{0345}') => Some('\u{1F9C}'), + ('\u{1F2D}', '\u{0345}') => Some('\u{1F9D}'), + ('\u{1F2E}', '\u{0345}') => Some('\u{1F9E}'), + ('\u{1F2F}', '\u{0345}') => Some('\u{1F9F}'), + ('\u{1F30}', '\u{0300}') => Some('\u{1F32}'), + ('\u{1F30}', '\u{0301}') => Some('\u{1F34}'), + ('\u{1F30}', '\u{0342}') => Some('\u{1F36}'), + ('\u{1F31}', '\u{0300}') => Some('\u{1F33}'), + ('\u{1F31}', '\u{0301}') => Some('\u{1F35}'), + ('\u{1F31}', '\u{0342}') => Some('\u{1F37}'), + ('\u{1F38}', '\u{0300}') => Some('\u{1F3A}'), + ('\u{1F38}', '\u{0301}') => Some('\u{1F3C}'), + ('\u{1F38}', '\u{0342}') => Some('\u{1F3E}'), + ('\u{1F39}', '\u{0300}') => Some('\u{1F3B}'), + ('\u{1F39}', '\u{0301}') => Some('\u{1F3D}'), + ('\u{1F39}', '\u{0342}') => Some('\u{1F3F}'), + ('\u{1F40}', '\u{0300}') => Some('\u{1F42}'), + ('\u{1F40}', '\u{0301}') => Some('\u{1F44}'), + ('\u{1F41}', '\u{0300}') => Some('\u{1F43}'), + ('\u{1F41}', '\u{0301}') => Some('\u{1F45}'), + ('\u{1F48}', '\u{0300}') => Some('\u{1F4A}'), + ('\u{1F48}', '\u{0301}') => Some('\u{1F4C}'), + ('\u{1F49}', '\u{0300}') => Some('\u{1F4B}'), + ('\u{1F49}', '\u{0301}') => Some('\u{1F4D}'), + ('\u{1F50}', '\u{0300}') => Some('\u{1F52}'), + ('\u{1F50}', '\u{0301}') => Some('\u{1F54}'), + ('\u{1F50}', '\u{0342}') => Some('\u{1F56}'), + ('\u{1F51}', '\u{0300}') => Some('\u{1F53}'), + ('\u{1F51}', '\u{0301}') => Some('\u{1F55}'), + ('\u{1F51}', '\u{0342}') => Some('\u{1F57}'), + ('\u{1F59}', '\u{0300}') => Some('\u{1F5B}'), + ('\u{1F59}', '\u{0301}') => Some('\u{1F5D}'), + ('\u{1F59}', '\u{0342}') => Some('\u{1F5F}'), + ('\u{1F60}', '\u{0300}') => Some('\u{1F62}'), + ('\u{1F60}', '\u{0301}') => Some('\u{1F64}'), + ('\u{1F60}', '\u{0342}') => Some('\u{1F66}'), + ('\u{1F60}', '\u{0345}') => Some('\u{1FA0}'), + ('\u{1F61}', '\u{0300}') => Some('\u{1F63}'), + ('\u{1F61}', '\u{0301}') => Some('\u{1F65}'), + ('\u{1F61}', '\u{0342}') => Some('\u{1F67}'), + ('\u{1F61}', '\u{0345}') => Some('\u{1FA1}'), + ('\u{1F62}', '\u{0345}') => Some('\u{1FA2}'), + ('\u{1F63}', '\u{0345}') => Some('\u{1FA3}'), + ('\u{1F64}', '\u{0345}') => Some('\u{1FA4}'), + ('\u{1F65}', '\u{0345}') => Some('\u{1FA5}'), + ('\u{1F66}', '\u{0345}') => Some('\u{1FA6}'), + ('\u{1F67}', '\u{0345}') => Some('\u{1FA7}'), + ('\u{1F68}', '\u{0300}') => Some('\u{1F6A}'), + ('\u{1F68}', '\u{0301}') => Some('\u{1F6C}'), + ('\u{1F68}', '\u{0342}') => Some('\u{1F6E}'), + ('\u{1F68}', '\u{0345}') => Some('\u{1FA8}'), + ('\u{1F69}', '\u{0300}') => Some('\u{1F6B}'), + ('\u{1F69}', '\u{0301}') => Some('\u{1F6D}'), + ('\u{1F69}', '\u{0342}') => Some('\u{1F6F}'), + ('\u{1F69}', '\u{0345}') => Some('\u{1FA9}'), + ('\u{1F6A}', '\u{0345}') => Some('\u{1FAA}'), + ('\u{1F6B}', '\u{0345}') => Some('\u{1FAB}'), + ('\u{1F6C}', '\u{0345}') => Some('\u{1FAC}'), + ('\u{1F6D}', '\u{0345}') => Some('\u{1FAD}'), + ('\u{1F6E}', '\u{0345}') => Some('\u{1FAE}'), + ('\u{1F6F}', '\u{0345}') => Some('\u{1FAF}'), + ('\u{1F70}', '\u{0345}') => Some('\u{1FB2}'), + ('\u{1F74}', '\u{0345}') => Some('\u{1FC2}'), + ('\u{1F7C}', '\u{0345}') => Some('\u{1FF2}'), + ('\u{1FB6}', '\u{0345}') => Some('\u{1FB7}'), + ('\u{1FBF}', '\u{0300}') => Some('\u{1FCD}'), + ('\u{1FBF}', '\u{0301}') => Some('\u{1FCE}'), + ('\u{1FBF}', '\u{0342}') => Some('\u{1FCF}'), + ('\u{1FC6}', '\u{0345}') => Some('\u{1FC7}'), + ('\u{1FF6}', '\u{0345}') => Some('\u{1FF7}'), + ('\u{1FFE}', '\u{0300}') => Some('\u{1FDD}'), + ('\u{1FFE}', '\u{0301}') => Some('\u{1FDE}'), + ('\u{1FFE}', '\u{0342}') => Some('\u{1FDF}'), + ('\u{2190}', '\u{0338}') => Some('\u{219A}'), + ('\u{2192}', '\u{0338}') => Some('\u{219B}'), + ('\u{2194}', '\u{0338}') => Some('\u{21AE}'), + ('\u{21D0}', '\u{0338}') => Some('\u{21CD}'), + ('\u{21D2}', '\u{0338}') => Some('\u{21CF}'), + ('\u{21D4}', '\u{0338}') => Some('\u{21CE}'), + ('\u{2203}', '\u{0338}') => Some('\u{2204}'), + ('\u{2208}', '\u{0338}') => Some('\u{2209}'), + ('\u{220B}', '\u{0338}') => Some('\u{220C}'), + ('\u{2223}', '\u{0338}') => Some('\u{2224}'), + ('\u{2225}', '\u{0338}') => Some('\u{2226}'), + ('\u{223C}', '\u{0338}') => Some('\u{2241}'), + ('\u{2243}', '\u{0338}') => Some('\u{2244}'), + ('\u{2245}', '\u{0338}') => Some('\u{2247}'), + ('\u{2248}', '\u{0338}') => Some('\u{2249}'), + ('\u{224D}', '\u{0338}') => Some('\u{226D}'), + ('\u{2261}', '\u{0338}') => Some('\u{2262}'), + ('\u{2264}', '\u{0338}') => Some('\u{2270}'), + ('\u{2265}', '\u{0338}') => Some('\u{2271}'), + ('\u{2272}', '\u{0338}') => Some('\u{2274}'), + ('\u{2273}', '\u{0338}') => Some('\u{2275}'), + ('\u{2276}', '\u{0338}') => Some('\u{2278}'), + ('\u{2277}', '\u{0338}') => Some('\u{2279}'), + ('\u{227A}', '\u{0338}') => Some('\u{2280}'), + ('\u{227B}', '\u{0338}') => Some('\u{2281}'), + ('\u{227C}', '\u{0338}') => Some('\u{22E0}'), + ('\u{227D}', '\u{0338}') => Some('\u{22E1}'), + ('\u{2282}', '\u{0338}') => Some('\u{2284}'), + ('\u{2283}', '\u{0338}') => Some('\u{2285}'), + ('\u{2286}', '\u{0338}') => Some('\u{2288}'), + ('\u{2287}', '\u{0338}') => Some('\u{2289}'), + ('\u{2291}', '\u{0338}') => Some('\u{22E2}'), + ('\u{2292}', '\u{0338}') => Some('\u{22E3}'), + ('\u{22A2}', '\u{0338}') => Some('\u{22AC}'), + ('\u{22A8}', '\u{0338}') => Some('\u{22AD}'), + ('\u{22A9}', '\u{0338}') => Some('\u{22AE}'), + ('\u{22AB}', '\u{0338}') => Some('\u{22AF}'), + ('\u{22B2}', '\u{0338}') => Some('\u{22EA}'), + ('\u{22B3}', '\u{0338}') => Some('\u{22EB}'), + ('\u{22B4}', '\u{0338}') => Some('\u{22EC}'), + ('\u{22B5}', '\u{0338}') => Some('\u{22ED}'), + ('\u{3046}', '\u{3099}') => Some('\u{3094}'), + ('\u{304B}', '\u{3099}') => Some('\u{304C}'), + ('\u{304D}', '\u{3099}') => Some('\u{304E}'), + ('\u{304F}', '\u{3099}') => Some('\u{3050}'), + ('\u{3051}', '\u{3099}') => Some('\u{3052}'), + ('\u{3053}', '\u{3099}') => Some('\u{3054}'), + ('\u{3055}', '\u{3099}') => Some('\u{3056}'), + ('\u{3057}', '\u{3099}') => Some('\u{3058}'), + ('\u{3059}', '\u{3099}') => Some('\u{305A}'), + ('\u{305B}', '\u{3099}') => Some('\u{305C}'), + ('\u{305D}', '\u{3099}') => Some('\u{305E}'), + ('\u{305F}', '\u{3099}') => Some('\u{3060}'), + ('\u{3061}', '\u{3099}') => Some('\u{3062}'), + ('\u{3064}', '\u{3099}') => Some('\u{3065}'), + ('\u{3066}', '\u{3099}') => Some('\u{3067}'), + ('\u{3068}', '\u{3099}') => Some('\u{3069}'), + ('\u{306F}', '\u{3099}') => Some('\u{3070}'), + ('\u{306F}', '\u{309A}') => Some('\u{3071}'), + ('\u{3072}', '\u{3099}') => Some('\u{3073}'), + ('\u{3072}', '\u{309A}') => Some('\u{3074}'), + ('\u{3075}', '\u{3099}') => Some('\u{3076}'), + ('\u{3075}', '\u{309A}') => Some('\u{3077}'), + ('\u{3078}', '\u{3099}') => Some('\u{3079}'), + ('\u{3078}', '\u{309A}') => Some('\u{307A}'), + ('\u{307B}', '\u{3099}') => Some('\u{307C}'), + ('\u{307B}', '\u{309A}') => Some('\u{307D}'), + ('\u{309D}', '\u{3099}') => Some('\u{309E}'), + ('\u{30A6}', '\u{3099}') => Some('\u{30F4}'), + ('\u{30AB}', '\u{3099}') => Some('\u{30AC}'), + ('\u{30AD}', '\u{3099}') => Some('\u{30AE}'), + ('\u{30AF}', '\u{3099}') => Some('\u{30B0}'), + ('\u{30B1}', '\u{3099}') => Some('\u{30B2}'), + ('\u{30B3}', '\u{3099}') => Some('\u{30B4}'), + ('\u{30B5}', '\u{3099}') => Some('\u{30B6}'), + ('\u{30B7}', '\u{3099}') => Some('\u{30B8}'), + ('\u{30B9}', '\u{3099}') => Some('\u{30BA}'), + ('\u{30BB}', '\u{3099}') => Some('\u{30BC}'), + ('\u{30BD}', '\u{3099}') => Some('\u{30BE}'), + ('\u{30BF}', '\u{3099}') => Some('\u{30C0}'), + ('\u{30C1}', '\u{3099}') => Some('\u{30C2}'), + ('\u{30C4}', '\u{3099}') => Some('\u{30C5}'), + ('\u{30C6}', '\u{3099}') => Some('\u{30C7}'), + ('\u{30C8}', '\u{3099}') => Some('\u{30C9}'), + ('\u{30CF}', '\u{3099}') => Some('\u{30D0}'), + ('\u{30CF}', '\u{309A}') => Some('\u{30D1}'), + ('\u{30D2}', '\u{3099}') => Some('\u{30D3}'), + ('\u{30D2}', '\u{309A}') => Some('\u{30D4}'), + ('\u{30D5}', '\u{3099}') => Some('\u{30D6}'), + ('\u{30D5}', '\u{309A}') => Some('\u{30D7}'), + ('\u{30D8}', '\u{3099}') => Some('\u{30D9}'), + ('\u{30D8}', '\u{309A}') => Some('\u{30DA}'), + ('\u{30DB}', '\u{3099}') => Some('\u{30DC}'), + ('\u{30DB}', '\u{309A}') => Some('\u{30DD}'), + ('\u{30EF}', '\u{3099}') => Some('\u{30F7}'), + ('\u{30F0}', '\u{3099}') => Some('\u{30F8}'), + ('\u{30F1}', '\u{3099}') => Some('\u{30F9}'), + ('\u{30F2}', '\u{3099}') => Some('\u{30FA}'), + ('\u{30FD}', '\u{3099}') => Some('\u{30FE}'), + ('\u{11099}', '\u{110BA}') => Some('\u{1109A}'), + ('\u{1109B}', '\u{110BA}') => Some('\u{1109C}'), + ('\u{110A5}', '\u{110BA}') => Some('\u{110AB}'), + ('\u{11131}', '\u{11127}') => Some('\u{1112E}'), + ('\u{11132}', '\u{11127}') => Some('\u{1112F}'), + ('\u{11347}', '\u{1133E}') => Some('\u{1134B}'), + ('\u{11347}', '\u{11357}') => Some('\u{1134C}'), + ('\u{114B9}', '\u{114B0}') => Some('\u{114BC}'), + ('\u{114B9}', '\u{114BA}') => Some('\u{114BB}'), + ('\u{114B9}', '\u{114BD}') => Some('\u{114BE}'), + ('\u{115B8}', '\u{115AF}') => Some('\u{115BA}'), + ('\u{115B9}', '\u{115AF}') => Some('\u{115BB}'), + _ => None, + } +} + +#[inline] +pub fn canonical_fully_decomposed(c: char) -> Option<&'static [char]> { + Some(match c { + '\u{00C0}' => &['\u{0041}', '\u{0300}'], + '\u{00C1}' => &['\u{0041}', '\u{0301}'], + '\u{00C2}' => &['\u{0041}', '\u{0302}'], + '\u{00C3}' => &['\u{0041}', '\u{0303}'], + '\u{00C4}' => &['\u{0041}', '\u{0308}'], + '\u{00C5}' => &['\u{0041}', '\u{030A}'], + '\u{00C7}' => &['\u{0043}', '\u{0327}'], + '\u{00C8}' => &['\u{0045}', '\u{0300}'], + '\u{00C9}' => &['\u{0045}', '\u{0301}'], + '\u{00CA}' => &['\u{0045}', '\u{0302}'], + '\u{00CB}' => &['\u{0045}', '\u{0308}'], + '\u{00CC}' => &['\u{0049}', '\u{0300}'], + '\u{00CD}' => &['\u{0049}', '\u{0301}'], + '\u{00CE}' => &['\u{0049}', '\u{0302}'], + '\u{00CF}' => &['\u{0049}', '\u{0308}'], + '\u{00D1}' => &['\u{004E}', '\u{0303}'], + '\u{00D2}' => &['\u{004F}', '\u{0300}'], + '\u{00D3}' => &['\u{004F}', '\u{0301}'], + '\u{00D4}' => &['\u{004F}', '\u{0302}'], + '\u{00D5}' => &['\u{004F}', '\u{0303}'], + '\u{00D6}' => &['\u{004F}', '\u{0308}'], + '\u{00D9}' => &['\u{0055}', '\u{0300}'], + '\u{00DA}' => &['\u{0055}', '\u{0301}'], + '\u{00DB}' => &['\u{0055}', '\u{0302}'], + '\u{00DC}' => &['\u{0055}', '\u{0308}'], + '\u{00DD}' => &['\u{0059}', '\u{0301}'], + '\u{00E0}' => &['\u{0061}', '\u{0300}'], + '\u{00E1}' => &['\u{0061}', '\u{0301}'], + '\u{00E2}' => &['\u{0061}', '\u{0302}'], + '\u{00E3}' => &['\u{0061}', '\u{0303}'], + '\u{00E4}' => &['\u{0061}', '\u{0308}'], + '\u{00E5}' => &['\u{0061}', '\u{030A}'], + '\u{00E7}' => &['\u{0063}', '\u{0327}'], + '\u{00E8}' => &['\u{0065}', '\u{0300}'], + '\u{00E9}' => &['\u{0065}', '\u{0301}'], + '\u{00EA}' => &['\u{0065}', '\u{0302}'], + '\u{00EB}' => &['\u{0065}', '\u{0308}'], + '\u{00EC}' => &['\u{0069}', '\u{0300}'], + '\u{00ED}' => &['\u{0069}', '\u{0301}'], + '\u{00EE}' => &['\u{0069}', '\u{0302}'], + '\u{00EF}' => &['\u{0069}', '\u{0308}'], + '\u{00F1}' => &['\u{006E}', '\u{0303}'], + '\u{00F2}' => &['\u{006F}', '\u{0300}'], + '\u{00F3}' => &['\u{006F}', '\u{0301}'], + '\u{00F4}' => &['\u{006F}', '\u{0302}'], + '\u{00F5}' => &['\u{006F}', '\u{0303}'], + '\u{00F6}' => &['\u{006F}', '\u{0308}'], + '\u{00F9}' => &['\u{0075}', '\u{0300}'], + '\u{00FA}' => &['\u{0075}', '\u{0301}'], + '\u{00FB}' => &['\u{0075}', '\u{0302}'], + '\u{00FC}' => &['\u{0075}', '\u{0308}'], + '\u{00FD}' => &['\u{0079}', '\u{0301}'], + '\u{00FF}' => &['\u{0079}', '\u{0308}'], + '\u{0100}' => &['\u{0041}', '\u{0304}'], + '\u{0101}' => &['\u{0061}', '\u{0304}'], + '\u{0102}' => &['\u{0041}', '\u{0306}'], + '\u{0103}' => &['\u{0061}', '\u{0306}'], + '\u{0104}' => &['\u{0041}', '\u{0328}'], + '\u{0105}' => &['\u{0061}', '\u{0328}'], + '\u{0106}' => &['\u{0043}', '\u{0301}'], + '\u{0107}' => &['\u{0063}', '\u{0301}'], + '\u{0108}' => &['\u{0043}', '\u{0302}'], + '\u{0109}' => &['\u{0063}', '\u{0302}'], + '\u{010A}' => &['\u{0043}', '\u{0307}'], + '\u{010B}' => &['\u{0063}', '\u{0307}'], + '\u{010C}' => &['\u{0043}', '\u{030C}'], + '\u{010D}' => &['\u{0063}', '\u{030C}'], + '\u{010E}' => &['\u{0044}', '\u{030C}'], + '\u{010F}' => &['\u{0064}', '\u{030C}'], + '\u{0112}' => &['\u{0045}', '\u{0304}'], + '\u{0113}' => &['\u{0065}', '\u{0304}'], + '\u{0114}' => &['\u{0045}', '\u{0306}'], + '\u{0115}' => &['\u{0065}', '\u{0306}'], + '\u{0116}' => &['\u{0045}', '\u{0307}'], + '\u{0117}' => &['\u{0065}', '\u{0307}'], + '\u{0118}' => &['\u{0045}', '\u{0328}'], + '\u{0119}' => &['\u{0065}', '\u{0328}'], + '\u{011A}' => &['\u{0045}', '\u{030C}'], + '\u{011B}' => &['\u{0065}', '\u{030C}'], + '\u{011C}' => &['\u{0047}', '\u{0302}'], + '\u{011D}' => &['\u{0067}', '\u{0302}'], + '\u{011E}' => &['\u{0047}', '\u{0306}'], + '\u{011F}' => &['\u{0067}', '\u{0306}'], + '\u{0120}' => &['\u{0047}', '\u{0307}'], + '\u{0121}' => &['\u{0067}', '\u{0307}'], + '\u{0122}' => &['\u{0047}', '\u{0327}'], + '\u{0123}' => &['\u{0067}', '\u{0327}'], + '\u{0124}' => &['\u{0048}', '\u{0302}'], + '\u{0125}' => &['\u{0068}', '\u{0302}'], + '\u{0128}' => &['\u{0049}', '\u{0303}'], + '\u{0129}' => &['\u{0069}', '\u{0303}'], + '\u{012A}' => &['\u{0049}', '\u{0304}'], + '\u{012B}' => &['\u{0069}', '\u{0304}'], + '\u{012C}' => &['\u{0049}', '\u{0306}'], + '\u{012D}' => &['\u{0069}', '\u{0306}'], + '\u{012E}' => &['\u{0049}', '\u{0328}'], + '\u{012F}' => &['\u{0069}', '\u{0328}'], + '\u{0130}' => &['\u{0049}', '\u{0307}'], + '\u{0134}' => &['\u{004A}', '\u{0302}'], + '\u{0135}' => &['\u{006A}', '\u{0302}'], + '\u{0136}' => &['\u{004B}', '\u{0327}'], + '\u{0137}' => &['\u{006B}', '\u{0327}'], + '\u{0139}' => &['\u{004C}', '\u{0301}'], + '\u{013A}' => &['\u{006C}', '\u{0301}'], + '\u{013B}' => &['\u{004C}', '\u{0327}'], + '\u{013C}' => &['\u{006C}', '\u{0327}'], + '\u{013D}' => &['\u{004C}', '\u{030C}'], + '\u{013E}' => &['\u{006C}', '\u{030C}'], + '\u{0143}' => &['\u{004E}', '\u{0301}'], + '\u{0144}' => &['\u{006E}', '\u{0301}'], + '\u{0145}' => &['\u{004E}', '\u{0327}'], + '\u{0146}' => &['\u{006E}', '\u{0327}'], + '\u{0147}' => &['\u{004E}', '\u{030C}'], + '\u{0148}' => &['\u{006E}', '\u{030C}'], + '\u{014C}' => &['\u{004F}', '\u{0304}'], + '\u{014D}' => &['\u{006F}', '\u{0304}'], + '\u{014E}' => &['\u{004F}', '\u{0306}'], + '\u{014F}' => &['\u{006F}', '\u{0306}'], + '\u{0150}' => &['\u{004F}', '\u{030B}'], + '\u{0151}' => &['\u{006F}', '\u{030B}'], + '\u{0154}' => &['\u{0052}', '\u{0301}'], + '\u{0155}' => &['\u{0072}', '\u{0301}'], + '\u{0156}' => &['\u{0052}', '\u{0327}'], + '\u{0157}' => &['\u{0072}', '\u{0327}'], + '\u{0158}' => &['\u{0052}', '\u{030C}'], + '\u{0159}' => &['\u{0072}', '\u{030C}'], + '\u{015A}' => &['\u{0053}', '\u{0301}'], + '\u{015B}' => &['\u{0073}', '\u{0301}'], + '\u{015C}' => &['\u{0053}', '\u{0302}'], + '\u{015D}' => &['\u{0073}', '\u{0302}'], + '\u{015E}' => &['\u{0053}', '\u{0327}'], + '\u{015F}' => &['\u{0073}', '\u{0327}'], + '\u{0160}' => &['\u{0053}', '\u{030C}'], + '\u{0161}' => &['\u{0073}', '\u{030C}'], + '\u{0162}' => &['\u{0054}', '\u{0327}'], + '\u{0163}' => &['\u{0074}', '\u{0327}'], + '\u{0164}' => &['\u{0054}', '\u{030C}'], + '\u{0165}' => &['\u{0074}', '\u{030C}'], + '\u{0168}' => &['\u{0055}', '\u{0303}'], + '\u{0169}' => &['\u{0075}', '\u{0303}'], + '\u{016A}' => &['\u{0055}', '\u{0304}'], + '\u{016B}' => &['\u{0075}', '\u{0304}'], + '\u{016C}' => &['\u{0055}', '\u{0306}'], + '\u{016D}' => &['\u{0075}', '\u{0306}'], + '\u{016E}' => &['\u{0055}', '\u{030A}'], + '\u{016F}' => &['\u{0075}', '\u{030A}'], + '\u{0170}' => &['\u{0055}', '\u{030B}'], + '\u{0171}' => &['\u{0075}', '\u{030B}'], + '\u{0172}' => &['\u{0055}', '\u{0328}'], + '\u{0173}' => &['\u{0075}', '\u{0328}'], + '\u{0174}' => &['\u{0057}', '\u{0302}'], + '\u{0175}' => &['\u{0077}', '\u{0302}'], + '\u{0176}' => &['\u{0059}', '\u{0302}'], + '\u{0177}' => &['\u{0079}', '\u{0302}'], + '\u{0178}' => &['\u{0059}', '\u{0308}'], + '\u{0179}' => &['\u{005A}', '\u{0301}'], + '\u{017A}' => &['\u{007A}', '\u{0301}'], + '\u{017B}' => &['\u{005A}', '\u{0307}'], + '\u{017C}' => &['\u{007A}', '\u{0307}'], + '\u{017D}' => &['\u{005A}', '\u{030C}'], + '\u{017E}' => &['\u{007A}', '\u{030C}'], + '\u{01A0}' => &['\u{004F}', '\u{031B}'], + '\u{01A1}' => &['\u{006F}', '\u{031B}'], + '\u{01AF}' => &['\u{0055}', '\u{031B}'], + '\u{01B0}' => &['\u{0075}', '\u{031B}'], + '\u{01CD}' => &['\u{0041}', '\u{030C}'], + '\u{01CE}' => &['\u{0061}', '\u{030C}'], + '\u{01CF}' => &['\u{0049}', '\u{030C}'], + '\u{01D0}' => &['\u{0069}', '\u{030C}'], + '\u{01D1}' => &['\u{004F}', '\u{030C}'], + '\u{01D2}' => &['\u{006F}', '\u{030C}'], + '\u{01D3}' => &['\u{0055}', '\u{030C}'], + '\u{01D4}' => &['\u{0075}', '\u{030C}'], + '\u{01D5}' => &['\u{0055}', '\u{0308}', '\u{0304}'], + '\u{01D6}' => &['\u{0075}', '\u{0308}', '\u{0304}'], + '\u{01D7}' => &['\u{0055}', '\u{0308}', '\u{0301}'], + '\u{01D8}' => &['\u{0075}', '\u{0308}', '\u{0301}'], + '\u{01D9}' => &['\u{0055}', '\u{0308}', '\u{030C}'], + '\u{01DA}' => &['\u{0075}', '\u{0308}', '\u{030C}'], + '\u{01DB}' => &['\u{0055}', '\u{0308}', '\u{0300}'], + '\u{01DC}' => &['\u{0075}', '\u{0308}', '\u{0300}'], + '\u{01DE}' => &['\u{0041}', '\u{0308}', '\u{0304}'], + '\u{01DF}' => &['\u{0061}', '\u{0308}', '\u{0304}'], + '\u{01E0}' => &['\u{0041}', '\u{0307}', '\u{0304}'], + '\u{01E1}' => &['\u{0061}', '\u{0307}', '\u{0304}'], + '\u{01E2}' => &['\u{00C6}', '\u{0304}'], + '\u{01E3}' => &['\u{00E6}', '\u{0304}'], + '\u{01E6}' => &['\u{0047}', '\u{030C}'], + '\u{01E7}' => &['\u{0067}', '\u{030C}'], + '\u{01E8}' => &['\u{004B}', '\u{030C}'], + '\u{01E9}' => &['\u{006B}', '\u{030C}'], + '\u{01EA}' => &['\u{004F}', '\u{0328}'], + '\u{01EB}' => &['\u{006F}', '\u{0328}'], + '\u{01EC}' => &['\u{004F}', '\u{0328}', '\u{0304}'], + '\u{01ED}' => &['\u{006F}', '\u{0328}', '\u{0304}'], + '\u{01EE}' => &['\u{01B7}', '\u{030C}'], + '\u{01EF}' => &['\u{0292}', '\u{030C}'], + '\u{01F0}' => &['\u{006A}', '\u{030C}'], + '\u{01F4}' => &['\u{0047}', '\u{0301}'], + '\u{01F5}' => &['\u{0067}', '\u{0301}'], + '\u{01F8}' => &['\u{004E}', '\u{0300}'], + '\u{01F9}' => &['\u{006E}', '\u{0300}'], + '\u{01FA}' => &['\u{0041}', '\u{030A}', '\u{0301}'], + '\u{01FB}' => &['\u{0061}', '\u{030A}', '\u{0301}'], + '\u{01FC}' => &['\u{00C6}', '\u{0301}'], + '\u{01FD}' => &['\u{00E6}', '\u{0301}'], + '\u{01FE}' => &['\u{00D8}', '\u{0301}'], + '\u{01FF}' => &['\u{00F8}', '\u{0301}'], + '\u{0200}' => &['\u{0041}', '\u{030F}'], + '\u{0201}' => &['\u{0061}', '\u{030F}'], + '\u{0202}' => &['\u{0041}', '\u{0311}'], + '\u{0203}' => &['\u{0061}', '\u{0311}'], + '\u{0204}' => &['\u{0045}', '\u{030F}'], + '\u{0205}' => &['\u{0065}', '\u{030F}'], + '\u{0206}' => &['\u{0045}', '\u{0311}'], + '\u{0207}' => &['\u{0065}', '\u{0311}'], + '\u{0208}' => &['\u{0049}', '\u{030F}'], + '\u{0209}' => &['\u{0069}', '\u{030F}'], + '\u{020A}' => &['\u{0049}', '\u{0311}'], + '\u{020B}' => &['\u{0069}', '\u{0311}'], + '\u{020C}' => &['\u{004F}', '\u{030F}'], + '\u{020D}' => &['\u{006F}', '\u{030F}'], + '\u{020E}' => &['\u{004F}', '\u{0311}'], + '\u{020F}' => &['\u{006F}', '\u{0311}'], + '\u{0210}' => &['\u{0052}', '\u{030F}'], + '\u{0211}' => &['\u{0072}', '\u{030F}'], + '\u{0212}' => &['\u{0052}', '\u{0311}'], + '\u{0213}' => &['\u{0072}', '\u{0311}'], + '\u{0214}' => &['\u{0055}', '\u{030F}'], + '\u{0215}' => &['\u{0075}', '\u{030F}'], + '\u{0216}' => &['\u{0055}', '\u{0311}'], + '\u{0217}' => &['\u{0075}', '\u{0311}'], + '\u{0218}' => &['\u{0053}', '\u{0326}'], + '\u{0219}' => &['\u{0073}', '\u{0326}'], + '\u{021A}' => &['\u{0054}', '\u{0326}'], + '\u{021B}' => &['\u{0074}', '\u{0326}'], + '\u{021E}' => &['\u{0048}', '\u{030C}'], + '\u{021F}' => &['\u{0068}', '\u{030C}'], + '\u{0226}' => &['\u{0041}', '\u{0307}'], + '\u{0227}' => &['\u{0061}', '\u{0307}'], + '\u{0228}' => &['\u{0045}', '\u{0327}'], + '\u{0229}' => &['\u{0065}', '\u{0327}'], + '\u{022A}' => &['\u{004F}', '\u{0308}', '\u{0304}'], + '\u{022B}' => &['\u{006F}', '\u{0308}', '\u{0304}'], + '\u{022C}' => &['\u{004F}', '\u{0303}', '\u{0304}'], + '\u{022D}' => &['\u{006F}', '\u{0303}', '\u{0304}'], + '\u{022E}' => &['\u{004F}', '\u{0307}'], + '\u{022F}' => &['\u{006F}', '\u{0307}'], + '\u{0230}' => &['\u{004F}', '\u{0307}', '\u{0304}'], + '\u{0231}' => &['\u{006F}', '\u{0307}', '\u{0304}'], + '\u{0232}' => &['\u{0059}', '\u{0304}'], + '\u{0233}' => &['\u{0079}', '\u{0304}'], + '\u{0340}' => &['\u{0300}'], + '\u{0341}' => &['\u{0301}'], + '\u{0343}' => &['\u{0313}'], + '\u{0344}' => &['\u{0308}', '\u{0301}'], + '\u{0374}' => &['\u{02B9}'], + '\u{037E}' => &['\u{003B}'], + '\u{0385}' => &['\u{00A8}', '\u{0301}'], + '\u{0386}' => &['\u{0391}', '\u{0301}'], + '\u{0387}' => &['\u{00B7}'], + '\u{0388}' => &['\u{0395}', '\u{0301}'], + '\u{0389}' => &['\u{0397}', '\u{0301}'], + '\u{038A}' => &['\u{0399}', '\u{0301}'], + '\u{038C}' => &['\u{039F}', '\u{0301}'], + '\u{038E}' => &['\u{03A5}', '\u{0301}'], + '\u{038F}' => &['\u{03A9}', '\u{0301}'], + '\u{0390}' => &['\u{03B9}', '\u{0308}', '\u{0301}'], + '\u{03AA}' => &['\u{0399}', '\u{0308}'], + '\u{03AB}' => &['\u{03A5}', '\u{0308}'], + '\u{03AC}' => &['\u{03B1}', '\u{0301}'], + '\u{03AD}' => &['\u{03B5}', '\u{0301}'], + '\u{03AE}' => &['\u{03B7}', '\u{0301}'], + '\u{03AF}' => &['\u{03B9}', '\u{0301}'], + '\u{03B0}' => &['\u{03C5}', '\u{0308}', '\u{0301}'], + '\u{03CA}' => &['\u{03B9}', '\u{0308}'], + '\u{03CB}' => &['\u{03C5}', '\u{0308}'], + '\u{03CC}' => &['\u{03BF}', '\u{0301}'], + '\u{03CD}' => &['\u{03C5}', '\u{0301}'], + '\u{03CE}' => &['\u{03C9}', '\u{0301}'], + '\u{03D3}' => &['\u{03D2}', '\u{0301}'], + '\u{03D4}' => &['\u{03D2}', '\u{0308}'], + '\u{0400}' => &['\u{0415}', '\u{0300}'], + '\u{0401}' => &['\u{0415}', '\u{0308}'], + '\u{0403}' => &['\u{0413}', '\u{0301}'], + '\u{0407}' => &['\u{0406}', '\u{0308}'], + '\u{040C}' => &['\u{041A}', '\u{0301}'], + '\u{040D}' => &['\u{0418}', '\u{0300}'], + '\u{040E}' => &['\u{0423}', '\u{0306}'], + '\u{0419}' => &['\u{0418}', '\u{0306}'], + '\u{0439}' => &['\u{0438}', '\u{0306}'], + '\u{0450}' => &['\u{0435}', '\u{0300}'], + '\u{0451}' => &['\u{0435}', '\u{0308}'], + '\u{0453}' => &['\u{0433}', '\u{0301}'], + '\u{0457}' => &['\u{0456}', '\u{0308}'], + '\u{045C}' => &['\u{043A}', '\u{0301}'], + '\u{045D}' => &['\u{0438}', '\u{0300}'], + '\u{045E}' => &['\u{0443}', '\u{0306}'], + '\u{0476}' => &['\u{0474}', '\u{030F}'], + '\u{0477}' => &['\u{0475}', '\u{030F}'], + '\u{04C1}' => &['\u{0416}', '\u{0306}'], + '\u{04C2}' => &['\u{0436}', '\u{0306}'], + '\u{04D0}' => &['\u{0410}', '\u{0306}'], + '\u{04D1}' => &['\u{0430}', '\u{0306}'], + '\u{04D2}' => &['\u{0410}', '\u{0308}'], + '\u{04D3}' => &['\u{0430}', '\u{0308}'], + '\u{04D6}' => &['\u{0415}', '\u{0306}'], + '\u{04D7}' => &['\u{0435}', '\u{0306}'], + '\u{04DA}' => &['\u{04D8}', '\u{0308}'], + '\u{04DB}' => &['\u{04D9}', '\u{0308}'], + '\u{04DC}' => &['\u{0416}', '\u{0308}'], + '\u{04DD}' => &['\u{0436}', '\u{0308}'], + '\u{04DE}' => &['\u{0417}', '\u{0308}'], + '\u{04DF}' => &['\u{0437}', '\u{0308}'], + '\u{04E2}' => &['\u{0418}', '\u{0304}'], + '\u{04E3}' => &['\u{0438}', '\u{0304}'], + '\u{04E4}' => &['\u{0418}', '\u{0308}'], + '\u{04E5}' => &['\u{0438}', '\u{0308}'], + '\u{04E6}' => &['\u{041E}', '\u{0308}'], + '\u{04E7}' => &['\u{043E}', '\u{0308}'], + '\u{04EA}' => &['\u{04E8}', '\u{0308}'], + '\u{04EB}' => &['\u{04E9}', '\u{0308}'], + '\u{04EC}' => &['\u{042D}', '\u{0308}'], + '\u{04ED}' => &['\u{044D}', '\u{0308}'], + '\u{04EE}' => &['\u{0423}', '\u{0304}'], + '\u{04EF}' => &['\u{0443}', '\u{0304}'], + '\u{04F0}' => &['\u{0423}', '\u{0308}'], + '\u{04F1}' => &['\u{0443}', '\u{0308}'], + '\u{04F2}' => &['\u{0423}', '\u{030B}'], + '\u{04F3}' => &['\u{0443}', '\u{030B}'], + '\u{04F4}' => &['\u{0427}', '\u{0308}'], + '\u{04F5}' => &['\u{0447}', '\u{0308}'], + '\u{04F8}' => &['\u{042B}', '\u{0308}'], + '\u{04F9}' => &['\u{044B}', '\u{0308}'], + '\u{0622}' => &['\u{0627}', '\u{0653}'], + '\u{0623}' => &['\u{0627}', '\u{0654}'], + '\u{0624}' => &['\u{0648}', '\u{0654}'], + '\u{0625}' => &['\u{0627}', '\u{0655}'], + '\u{0626}' => &['\u{064A}', '\u{0654}'], + '\u{06C0}' => &['\u{06D5}', '\u{0654}'], + '\u{06C2}' => &['\u{06C1}', '\u{0654}'], + '\u{06D3}' => &['\u{06D2}', '\u{0654}'], + '\u{0929}' => &['\u{0928}', '\u{093C}'], + '\u{0931}' => &['\u{0930}', '\u{093C}'], + '\u{0934}' => &['\u{0933}', '\u{093C}'], + '\u{0958}' => &['\u{0915}', '\u{093C}'], + '\u{0959}' => &['\u{0916}', '\u{093C}'], + '\u{095A}' => &['\u{0917}', '\u{093C}'], + '\u{095B}' => &['\u{091C}', '\u{093C}'], + '\u{095C}' => &['\u{0921}', '\u{093C}'], + '\u{095D}' => &['\u{0922}', '\u{093C}'], + '\u{095E}' => &['\u{092B}', '\u{093C}'], + '\u{095F}' => &['\u{092F}', '\u{093C}'], + '\u{09CB}' => &['\u{09C7}', '\u{09BE}'], + '\u{09CC}' => &['\u{09C7}', '\u{09D7}'], + '\u{09DC}' => &['\u{09A1}', '\u{09BC}'], + '\u{09DD}' => &['\u{09A2}', '\u{09BC}'], + '\u{09DF}' => &['\u{09AF}', '\u{09BC}'], + '\u{0A33}' => &['\u{0A32}', '\u{0A3C}'], + '\u{0A36}' => &['\u{0A38}', '\u{0A3C}'], + '\u{0A59}' => &['\u{0A16}', '\u{0A3C}'], + '\u{0A5A}' => &['\u{0A17}', '\u{0A3C}'], + '\u{0A5B}' => &['\u{0A1C}', '\u{0A3C}'], + '\u{0A5E}' => &['\u{0A2B}', '\u{0A3C}'], + '\u{0B48}' => &['\u{0B47}', '\u{0B56}'], + '\u{0B4B}' => &['\u{0B47}', '\u{0B3E}'], + '\u{0B4C}' => &['\u{0B47}', '\u{0B57}'], + '\u{0B5C}' => &['\u{0B21}', '\u{0B3C}'], + '\u{0B5D}' => &['\u{0B22}', '\u{0B3C}'], + '\u{0B94}' => &['\u{0B92}', '\u{0BD7}'], + '\u{0BCA}' => &['\u{0BC6}', '\u{0BBE}'], + '\u{0BCB}' => &['\u{0BC7}', '\u{0BBE}'], + '\u{0BCC}' => &['\u{0BC6}', '\u{0BD7}'], + '\u{0C48}' => &['\u{0C46}', '\u{0C56}'], + '\u{0CC0}' => &['\u{0CBF}', '\u{0CD5}'], + '\u{0CC7}' => &['\u{0CC6}', '\u{0CD5}'], + '\u{0CC8}' => &['\u{0CC6}', '\u{0CD6}'], + '\u{0CCA}' => &['\u{0CC6}', '\u{0CC2}'], + '\u{0CCB}' => &['\u{0CC6}', '\u{0CC2}', '\u{0CD5}'], + '\u{0D4A}' => &['\u{0D46}', '\u{0D3E}'], + '\u{0D4B}' => &['\u{0D47}', '\u{0D3E}'], + '\u{0D4C}' => &['\u{0D46}', '\u{0D57}'], + '\u{0DDA}' => &['\u{0DD9}', '\u{0DCA}'], + '\u{0DDC}' => &['\u{0DD9}', '\u{0DCF}'], + '\u{0DDD}' => &['\u{0DD9}', '\u{0DCF}', '\u{0DCA}'], + '\u{0DDE}' => &['\u{0DD9}', '\u{0DDF}'], + '\u{0F43}' => &['\u{0F42}', '\u{0FB7}'], + '\u{0F4D}' => &['\u{0F4C}', '\u{0FB7}'], + '\u{0F52}' => &['\u{0F51}', '\u{0FB7}'], + '\u{0F57}' => &['\u{0F56}', '\u{0FB7}'], + '\u{0F5C}' => &['\u{0F5B}', '\u{0FB7}'], + '\u{0F69}' => &['\u{0F40}', '\u{0FB5}'], + '\u{0F73}' => &['\u{0F71}', '\u{0F72}'], + '\u{0F75}' => &['\u{0F71}', '\u{0F74}'], + '\u{0F76}' => &['\u{0FB2}', '\u{0F80}'], + '\u{0F78}' => &['\u{0FB3}', '\u{0F80}'], + '\u{0F81}' => &['\u{0F71}', '\u{0F80}'], + '\u{0F93}' => &['\u{0F92}', '\u{0FB7}'], + '\u{0F9D}' => &['\u{0F9C}', '\u{0FB7}'], + '\u{0FA2}' => &['\u{0FA1}', '\u{0FB7}'], + '\u{0FA7}' => &['\u{0FA6}', '\u{0FB7}'], + '\u{0FAC}' => &['\u{0FAB}', '\u{0FB7}'], + '\u{0FB9}' => &['\u{0F90}', '\u{0FB5}'], + '\u{1026}' => &['\u{1025}', '\u{102E}'], + '\u{1B06}' => &['\u{1B05}', '\u{1B35}'], + '\u{1B08}' => &['\u{1B07}', '\u{1B35}'], + '\u{1B0A}' => &['\u{1B09}', '\u{1B35}'], + '\u{1B0C}' => &['\u{1B0B}', '\u{1B35}'], + '\u{1B0E}' => &['\u{1B0D}', '\u{1B35}'], + '\u{1B12}' => &['\u{1B11}', '\u{1B35}'], + '\u{1B3B}' => &['\u{1B3A}', '\u{1B35}'], + '\u{1B3D}' => &['\u{1B3C}', '\u{1B35}'], + '\u{1B40}' => &['\u{1B3E}', '\u{1B35}'], + '\u{1B41}' => &['\u{1B3F}', '\u{1B35}'], + '\u{1B43}' => &['\u{1B42}', '\u{1B35}'], + '\u{1E00}' => &['\u{0041}', '\u{0325}'], + '\u{1E01}' => &['\u{0061}', '\u{0325}'], + '\u{1E02}' => &['\u{0042}', '\u{0307}'], + '\u{1E03}' => &['\u{0062}', '\u{0307}'], + '\u{1E04}' => &['\u{0042}', '\u{0323}'], + '\u{1E05}' => &['\u{0062}', '\u{0323}'], + '\u{1E06}' => &['\u{0042}', '\u{0331}'], + '\u{1E07}' => &['\u{0062}', '\u{0331}'], + '\u{1E08}' => &['\u{0043}', '\u{0327}', '\u{0301}'], + '\u{1E09}' => &['\u{0063}', '\u{0327}', '\u{0301}'], + '\u{1E0A}' => &['\u{0044}', '\u{0307}'], + '\u{1E0B}' => &['\u{0064}', '\u{0307}'], + '\u{1E0C}' => &['\u{0044}', '\u{0323}'], + '\u{1E0D}' => &['\u{0064}', '\u{0323}'], + '\u{1E0E}' => &['\u{0044}', '\u{0331}'], + '\u{1E0F}' => &['\u{0064}', '\u{0331}'], + '\u{1E10}' => &['\u{0044}', '\u{0327}'], + '\u{1E11}' => &['\u{0064}', '\u{0327}'], + '\u{1E12}' => &['\u{0044}', '\u{032D}'], + '\u{1E13}' => &['\u{0064}', '\u{032D}'], + '\u{1E14}' => &['\u{0045}', '\u{0304}', '\u{0300}'], + '\u{1E15}' => &['\u{0065}', '\u{0304}', '\u{0300}'], + '\u{1E16}' => &['\u{0045}', '\u{0304}', '\u{0301}'], + '\u{1E17}' => &['\u{0065}', '\u{0304}', '\u{0301}'], + '\u{1E18}' => &['\u{0045}', '\u{032D}'], + '\u{1E19}' => &['\u{0065}', '\u{032D}'], + '\u{1E1A}' => &['\u{0045}', '\u{0330}'], + '\u{1E1B}' => &['\u{0065}', '\u{0330}'], + '\u{1E1C}' => &['\u{0045}', '\u{0327}', '\u{0306}'], + '\u{1E1D}' => &['\u{0065}', '\u{0327}', '\u{0306}'], + '\u{1E1E}' => &['\u{0046}', '\u{0307}'], + '\u{1E1F}' => &['\u{0066}', '\u{0307}'], + '\u{1E20}' => &['\u{0047}', '\u{0304}'], + '\u{1E21}' => &['\u{0067}', '\u{0304}'], + '\u{1E22}' => &['\u{0048}', '\u{0307}'], + '\u{1E23}' => &['\u{0068}', '\u{0307}'], + '\u{1E24}' => &['\u{0048}', '\u{0323}'], + '\u{1E25}' => &['\u{0068}', '\u{0323}'], + '\u{1E26}' => &['\u{0048}', '\u{0308}'], + '\u{1E27}' => &['\u{0068}', '\u{0308}'], + '\u{1E28}' => &['\u{0048}', '\u{0327}'], + '\u{1E29}' => &['\u{0068}', '\u{0327}'], + '\u{1E2A}' => &['\u{0048}', '\u{032E}'], + '\u{1E2B}' => &['\u{0068}', '\u{032E}'], + '\u{1E2C}' => &['\u{0049}', '\u{0330}'], + '\u{1E2D}' => &['\u{0069}', '\u{0330}'], + '\u{1E2E}' => &['\u{0049}', '\u{0308}', '\u{0301}'], + '\u{1E2F}' => &['\u{0069}', '\u{0308}', '\u{0301}'], + '\u{1E30}' => &['\u{004B}', '\u{0301}'], + '\u{1E31}' => &['\u{006B}', '\u{0301}'], + '\u{1E32}' => &['\u{004B}', '\u{0323}'], + '\u{1E33}' => &['\u{006B}', '\u{0323}'], + '\u{1E34}' => &['\u{004B}', '\u{0331}'], + '\u{1E35}' => &['\u{006B}', '\u{0331}'], + '\u{1E36}' => &['\u{004C}', '\u{0323}'], + '\u{1E37}' => &['\u{006C}', '\u{0323}'], + '\u{1E38}' => &['\u{004C}', '\u{0323}', '\u{0304}'], + '\u{1E39}' => &['\u{006C}', '\u{0323}', '\u{0304}'], + '\u{1E3A}' => &['\u{004C}', '\u{0331}'], + '\u{1E3B}' => &['\u{006C}', '\u{0331}'], + '\u{1E3C}' => &['\u{004C}', '\u{032D}'], + '\u{1E3D}' => &['\u{006C}', '\u{032D}'], + '\u{1E3E}' => &['\u{004D}', '\u{0301}'], + '\u{1E3F}' => &['\u{006D}', '\u{0301}'], + '\u{1E40}' => &['\u{004D}', '\u{0307}'], + '\u{1E41}' => &['\u{006D}', '\u{0307}'], + '\u{1E42}' => &['\u{004D}', '\u{0323}'], + '\u{1E43}' => &['\u{006D}', '\u{0323}'], + '\u{1E44}' => &['\u{004E}', '\u{0307}'], + '\u{1E45}' => &['\u{006E}', '\u{0307}'], + '\u{1E46}' => &['\u{004E}', '\u{0323}'], + '\u{1E47}' => &['\u{006E}', '\u{0323}'], + '\u{1E48}' => &['\u{004E}', '\u{0331}'], + '\u{1E49}' => &['\u{006E}', '\u{0331}'], + '\u{1E4A}' => &['\u{004E}', '\u{032D}'], + '\u{1E4B}' => &['\u{006E}', '\u{032D}'], + '\u{1E4C}' => &['\u{004F}', '\u{0303}', '\u{0301}'], + '\u{1E4D}' => &['\u{006F}', '\u{0303}', '\u{0301}'], + '\u{1E4E}' => &['\u{004F}', '\u{0303}', '\u{0308}'], + '\u{1E4F}' => &['\u{006F}', '\u{0303}', '\u{0308}'], + '\u{1E50}' => &['\u{004F}', '\u{0304}', '\u{0300}'], + '\u{1E51}' => &['\u{006F}', '\u{0304}', '\u{0300}'], + '\u{1E52}' => &['\u{004F}', '\u{0304}', '\u{0301}'], + '\u{1E53}' => &['\u{006F}', '\u{0304}', '\u{0301}'], + '\u{1E54}' => &['\u{0050}', '\u{0301}'], + '\u{1E55}' => &['\u{0070}', '\u{0301}'], + '\u{1E56}' => &['\u{0050}', '\u{0307}'], + '\u{1E57}' => &['\u{0070}', '\u{0307}'], + '\u{1E58}' => &['\u{0052}', '\u{0307}'], + '\u{1E59}' => &['\u{0072}', '\u{0307}'], + '\u{1E5A}' => &['\u{0052}', '\u{0323}'], + '\u{1E5B}' => &['\u{0072}', '\u{0323}'], + '\u{1E5C}' => &['\u{0052}', '\u{0323}', '\u{0304}'], + '\u{1E5D}' => &['\u{0072}', '\u{0323}', '\u{0304}'], + '\u{1E5E}' => &['\u{0052}', '\u{0331}'], + '\u{1E5F}' => &['\u{0072}', '\u{0331}'], + '\u{1E60}' => &['\u{0053}', '\u{0307}'], + '\u{1E61}' => &['\u{0073}', '\u{0307}'], + '\u{1E62}' => &['\u{0053}', '\u{0323}'], + '\u{1E63}' => &['\u{0073}', '\u{0323}'], + '\u{1E64}' => &['\u{0053}', '\u{0301}', '\u{0307}'], + '\u{1E65}' => &['\u{0073}', '\u{0301}', '\u{0307}'], + '\u{1E66}' => &['\u{0053}', '\u{030C}', '\u{0307}'], + '\u{1E67}' => &['\u{0073}', '\u{030C}', '\u{0307}'], + '\u{1E68}' => &['\u{0053}', '\u{0323}', '\u{0307}'], + '\u{1E69}' => &['\u{0073}', '\u{0323}', '\u{0307}'], + '\u{1E6A}' => &['\u{0054}', '\u{0307}'], + '\u{1E6B}' => &['\u{0074}', '\u{0307}'], + '\u{1E6C}' => &['\u{0054}', '\u{0323}'], + '\u{1E6D}' => &['\u{0074}', '\u{0323}'], + '\u{1E6E}' => &['\u{0054}', '\u{0331}'], + '\u{1E6F}' => &['\u{0074}', '\u{0331}'], + '\u{1E70}' => &['\u{0054}', '\u{032D}'], + '\u{1E71}' => &['\u{0074}', '\u{032D}'], + '\u{1E72}' => &['\u{0055}', '\u{0324}'], + '\u{1E73}' => &['\u{0075}', '\u{0324}'], + '\u{1E74}' => &['\u{0055}', '\u{0330}'], + '\u{1E75}' => &['\u{0075}', '\u{0330}'], + '\u{1E76}' => &['\u{0055}', '\u{032D}'], + '\u{1E77}' => &['\u{0075}', '\u{032D}'], + '\u{1E78}' => &['\u{0055}', '\u{0303}', '\u{0301}'], + '\u{1E79}' => &['\u{0075}', '\u{0303}', '\u{0301}'], + '\u{1E7A}' => &['\u{0055}', '\u{0304}', '\u{0308}'], + '\u{1E7B}' => &['\u{0075}', '\u{0304}', '\u{0308}'], + '\u{1E7C}' => &['\u{0056}', '\u{0303}'], + '\u{1E7D}' => &['\u{0076}', '\u{0303}'], + '\u{1E7E}' => &['\u{0056}', '\u{0323}'], + '\u{1E7F}' => &['\u{0076}', '\u{0323}'], + '\u{1E80}' => &['\u{0057}', '\u{0300}'], + '\u{1E81}' => &['\u{0077}', '\u{0300}'], + '\u{1E82}' => &['\u{0057}', '\u{0301}'], + '\u{1E83}' => &['\u{0077}', '\u{0301}'], + '\u{1E84}' => &['\u{0057}', '\u{0308}'], + '\u{1E85}' => &['\u{0077}', '\u{0308}'], + '\u{1E86}' => &['\u{0057}', '\u{0307}'], + '\u{1E87}' => &['\u{0077}', '\u{0307}'], + '\u{1E88}' => &['\u{0057}', '\u{0323}'], + '\u{1E89}' => &['\u{0077}', '\u{0323}'], + '\u{1E8A}' => &['\u{0058}', '\u{0307}'], + '\u{1E8B}' => &['\u{0078}', '\u{0307}'], + '\u{1E8C}' => &['\u{0058}', '\u{0308}'], + '\u{1E8D}' => &['\u{0078}', '\u{0308}'], + '\u{1E8E}' => &['\u{0059}', '\u{0307}'], + '\u{1E8F}' => &['\u{0079}', '\u{0307}'], + '\u{1E90}' => &['\u{005A}', '\u{0302}'], + '\u{1E91}' => &['\u{007A}', '\u{0302}'], + '\u{1E92}' => &['\u{005A}', '\u{0323}'], + '\u{1E93}' => &['\u{007A}', '\u{0323}'], + '\u{1E94}' => &['\u{005A}', '\u{0331}'], + '\u{1E95}' => &['\u{007A}', '\u{0331}'], + '\u{1E96}' => &['\u{0068}', '\u{0331}'], + '\u{1E97}' => &['\u{0074}', '\u{0308}'], + '\u{1E98}' => &['\u{0077}', '\u{030A}'], + '\u{1E99}' => &['\u{0079}', '\u{030A}'], + '\u{1E9B}' => &['\u{017F}', '\u{0307}'], + '\u{1EA0}' => &['\u{0041}', '\u{0323}'], + '\u{1EA1}' => &['\u{0061}', '\u{0323}'], + '\u{1EA2}' => &['\u{0041}', '\u{0309}'], + '\u{1EA3}' => &['\u{0061}', '\u{0309}'], + '\u{1EA4}' => &['\u{0041}', '\u{0302}', '\u{0301}'], + '\u{1EA5}' => &['\u{0061}', '\u{0302}', '\u{0301}'], + '\u{1EA6}' => &['\u{0041}', '\u{0302}', '\u{0300}'], + '\u{1EA7}' => &['\u{0061}', '\u{0302}', '\u{0300}'], + '\u{1EA8}' => &['\u{0041}', '\u{0302}', '\u{0309}'], + '\u{1EA9}' => &['\u{0061}', '\u{0302}', '\u{0309}'], + '\u{1EAA}' => &['\u{0041}', '\u{0302}', '\u{0303}'], + '\u{1EAB}' => &['\u{0061}', '\u{0302}', '\u{0303}'], + '\u{1EAC}' => &['\u{0041}', '\u{0323}', '\u{0302}'], + '\u{1EAD}' => &['\u{0061}', '\u{0323}', '\u{0302}'], + '\u{1EAE}' => &['\u{0041}', '\u{0306}', '\u{0301}'], + '\u{1EAF}' => &['\u{0061}', '\u{0306}', '\u{0301}'], + '\u{1EB0}' => &['\u{0041}', '\u{0306}', '\u{0300}'], + '\u{1EB1}' => &['\u{0061}', '\u{0306}', '\u{0300}'], + '\u{1EB2}' => &['\u{0041}', '\u{0306}', '\u{0309}'], + '\u{1EB3}' => &['\u{0061}', '\u{0306}', '\u{0309}'], + '\u{1EB4}' => &['\u{0041}', '\u{0306}', '\u{0303}'], + '\u{1EB5}' => &['\u{0061}', '\u{0306}', '\u{0303}'], + '\u{1EB6}' => &['\u{0041}', '\u{0323}', '\u{0306}'], + '\u{1EB7}' => &['\u{0061}', '\u{0323}', '\u{0306}'], + '\u{1EB8}' => &['\u{0045}', '\u{0323}'], + '\u{1EB9}' => &['\u{0065}', '\u{0323}'], + '\u{1EBA}' => &['\u{0045}', '\u{0309}'], + '\u{1EBB}' => &['\u{0065}', '\u{0309}'], + '\u{1EBC}' => &['\u{0045}', '\u{0303}'], + '\u{1EBD}' => &['\u{0065}', '\u{0303}'], + '\u{1EBE}' => &['\u{0045}', '\u{0302}', '\u{0301}'], + '\u{1EBF}' => &['\u{0065}', '\u{0302}', '\u{0301}'], + '\u{1EC0}' => &['\u{0045}', '\u{0302}', '\u{0300}'], + '\u{1EC1}' => &['\u{0065}', '\u{0302}', '\u{0300}'], + '\u{1EC2}' => &['\u{0045}', '\u{0302}', '\u{0309}'], + '\u{1EC3}' => &['\u{0065}', '\u{0302}', '\u{0309}'], + '\u{1EC4}' => &['\u{0045}', '\u{0302}', '\u{0303}'], + '\u{1EC5}' => &['\u{0065}', '\u{0302}', '\u{0303}'], + '\u{1EC6}' => &['\u{0045}', '\u{0323}', '\u{0302}'], + '\u{1EC7}' => &['\u{0065}', '\u{0323}', '\u{0302}'], + '\u{1EC8}' => &['\u{0049}', '\u{0309}'], + '\u{1EC9}' => &['\u{0069}', '\u{0309}'], + '\u{1ECA}' => &['\u{0049}', '\u{0323}'], + '\u{1ECB}' => &['\u{0069}', '\u{0323}'], + '\u{1ECC}' => &['\u{004F}', '\u{0323}'], + '\u{1ECD}' => &['\u{006F}', '\u{0323}'], + '\u{1ECE}' => &['\u{004F}', '\u{0309}'], + '\u{1ECF}' => &['\u{006F}', '\u{0309}'], + '\u{1ED0}' => &['\u{004F}', '\u{0302}', '\u{0301}'], + '\u{1ED1}' => &['\u{006F}', '\u{0302}', '\u{0301}'], + '\u{1ED2}' => &['\u{004F}', '\u{0302}', '\u{0300}'], + '\u{1ED3}' => &['\u{006F}', '\u{0302}', '\u{0300}'], + '\u{1ED4}' => &['\u{004F}', '\u{0302}', '\u{0309}'], + '\u{1ED5}' => &['\u{006F}', '\u{0302}', '\u{0309}'], + '\u{1ED6}' => &['\u{004F}', '\u{0302}', '\u{0303}'], + '\u{1ED7}' => &['\u{006F}', '\u{0302}', '\u{0303}'], + '\u{1ED8}' => &['\u{004F}', '\u{0323}', '\u{0302}'], + '\u{1ED9}' => &['\u{006F}', '\u{0323}', '\u{0302}'], + '\u{1EDA}' => &['\u{004F}', '\u{031B}', '\u{0301}'], + '\u{1EDB}' => &['\u{006F}', '\u{031B}', '\u{0301}'], + '\u{1EDC}' => &['\u{004F}', '\u{031B}', '\u{0300}'], + '\u{1EDD}' => &['\u{006F}', '\u{031B}', '\u{0300}'], + '\u{1EDE}' => &['\u{004F}', '\u{031B}', '\u{0309}'], + '\u{1EDF}' => &['\u{006F}', '\u{031B}', '\u{0309}'], + '\u{1EE0}' => &['\u{004F}', '\u{031B}', '\u{0303}'], + '\u{1EE1}' => &['\u{006F}', '\u{031B}', '\u{0303}'], + '\u{1EE2}' => &['\u{004F}', '\u{031B}', '\u{0323}'], + '\u{1EE3}' => &['\u{006F}', '\u{031B}', '\u{0323}'], + '\u{1EE4}' => &['\u{0055}', '\u{0323}'], + '\u{1EE5}' => &['\u{0075}', '\u{0323}'], + '\u{1EE6}' => &['\u{0055}', '\u{0309}'], + '\u{1EE7}' => &['\u{0075}', '\u{0309}'], + '\u{1EE8}' => &['\u{0055}', '\u{031B}', '\u{0301}'], + '\u{1EE9}' => &['\u{0075}', '\u{031B}', '\u{0301}'], + '\u{1EEA}' => &['\u{0055}', '\u{031B}', '\u{0300}'], + '\u{1EEB}' => &['\u{0075}', '\u{031B}', '\u{0300}'], + '\u{1EEC}' => &['\u{0055}', '\u{031B}', '\u{0309}'], + '\u{1EED}' => &['\u{0075}', '\u{031B}', '\u{0309}'], + '\u{1EEE}' => &['\u{0055}', '\u{031B}', '\u{0303}'], + '\u{1EEF}' => &['\u{0075}', '\u{031B}', '\u{0303}'], + '\u{1EF0}' => &['\u{0055}', '\u{031B}', '\u{0323}'], + '\u{1EF1}' => &['\u{0075}', '\u{031B}', '\u{0323}'], + '\u{1EF2}' => &['\u{0059}', '\u{0300}'], + '\u{1EF3}' => &['\u{0079}', '\u{0300}'], + '\u{1EF4}' => &['\u{0059}', '\u{0323}'], + '\u{1EF5}' => &['\u{0079}', '\u{0323}'], + '\u{1EF6}' => &['\u{0059}', '\u{0309}'], + '\u{1EF7}' => &['\u{0079}', '\u{0309}'], + '\u{1EF8}' => &['\u{0059}', '\u{0303}'], + '\u{1EF9}' => &['\u{0079}', '\u{0303}'], + '\u{1F00}' => &['\u{03B1}', '\u{0313}'], + '\u{1F01}' => &['\u{03B1}', '\u{0314}'], + '\u{1F02}' => &['\u{03B1}', '\u{0313}', '\u{0300}'], + '\u{1F03}' => &['\u{03B1}', '\u{0314}', '\u{0300}'], + '\u{1F04}' => &['\u{03B1}', '\u{0313}', '\u{0301}'], + '\u{1F05}' => &['\u{03B1}', '\u{0314}', '\u{0301}'], + '\u{1F06}' => &['\u{03B1}', '\u{0313}', '\u{0342}'], + '\u{1F07}' => &['\u{03B1}', '\u{0314}', '\u{0342}'], + '\u{1F08}' => &['\u{0391}', '\u{0313}'], + '\u{1F09}' => &['\u{0391}', '\u{0314}'], + '\u{1F0A}' => &['\u{0391}', '\u{0313}', '\u{0300}'], + '\u{1F0B}' => &['\u{0391}', '\u{0314}', '\u{0300}'], + '\u{1F0C}' => &['\u{0391}', '\u{0313}', '\u{0301}'], + '\u{1F0D}' => &['\u{0391}', '\u{0314}', '\u{0301}'], + '\u{1F0E}' => &['\u{0391}', '\u{0313}', '\u{0342}'], + '\u{1F0F}' => &['\u{0391}', '\u{0314}', '\u{0342}'], + '\u{1F10}' => &['\u{03B5}', '\u{0313}'], + '\u{1F11}' => &['\u{03B5}', '\u{0314}'], + '\u{1F12}' => &['\u{03B5}', '\u{0313}', '\u{0300}'], + '\u{1F13}' => &['\u{03B5}', '\u{0314}', '\u{0300}'], + '\u{1F14}' => &['\u{03B5}', '\u{0313}', '\u{0301}'], + '\u{1F15}' => &['\u{03B5}', '\u{0314}', '\u{0301}'], + '\u{1F18}' => &['\u{0395}', '\u{0313}'], + '\u{1F19}' => &['\u{0395}', '\u{0314}'], + '\u{1F1A}' => &['\u{0395}', '\u{0313}', '\u{0300}'], + '\u{1F1B}' => &['\u{0395}', '\u{0314}', '\u{0300}'], + '\u{1F1C}' => &['\u{0395}', '\u{0313}', '\u{0301}'], + '\u{1F1D}' => &['\u{0395}', '\u{0314}', '\u{0301}'], + '\u{1F20}' => &['\u{03B7}', '\u{0313}'], + '\u{1F21}' => &['\u{03B7}', '\u{0314}'], + '\u{1F22}' => &['\u{03B7}', '\u{0313}', '\u{0300}'], + '\u{1F23}' => &['\u{03B7}', '\u{0314}', '\u{0300}'], + '\u{1F24}' => &['\u{03B7}', '\u{0313}', '\u{0301}'], + '\u{1F25}' => &['\u{03B7}', '\u{0314}', '\u{0301}'], + '\u{1F26}' => &['\u{03B7}', '\u{0313}', '\u{0342}'], + '\u{1F27}' => &['\u{03B7}', '\u{0314}', '\u{0342}'], + '\u{1F28}' => &['\u{0397}', '\u{0313}'], + '\u{1F29}' => &['\u{0397}', '\u{0314}'], + '\u{1F2A}' => &['\u{0397}', '\u{0313}', '\u{0300}'], + '\u{1F2B}' => &['\u{0397}', '\u{0314}', '\u{0300}'], + '\u{1F2C}' => &['\u{0397}', '\u{0313}', '\u{0301}'], + '\u{1F2D}' => &['\u{0397}', '\u{0314}', '\u{0301}'], + '\u{1F2E}' => &['\u{0397}', '\u{0313}', '\u{0342}'], + '\u{1F2F}' => &['\u{0397}', '\u{0314}', '\u{0342}'], + '\u{1F30}' => &['\u{03B9}', '\u{0313}'], + '\u{1F31}' => &['\u{03B9}', '\u{0314}'], + '\u{1F32}' => &['\u{03B9}', '\u{0313}', '\u{0300}'], + '\u{1F33}' => &['\u{03B9}', '\u{0314}', '\u{0300}'], + '\u{1F34}' => &['\u{03B9}', '\u{0313}', '\u{0301}'], + '\u{1F35}' => &['\u{03B9}', '\u{0314}', '\u{0301}'], + '\u{1F36}' => &['\u{03B9}', '\u{0313}', '\u{0342}'], + '\u{1F37}' => &['\u{03B9}', '\u{0314}', '\u{0342}'], + '\u{1F38}' => &['\u{0399}', '\u{0313}'], + '\u{1F39}' => &['\u{0399}', '\u{0314}'], + '\u{1F3A}' => &['\u{0399}', '\u{0313}', '\u{0300}'], + '\u{1F3B}' => &['\u{0399}', '\u{0314}', '\u{0300}'], + '\u{1F3C}' => &['\u{0399}', '\u{0313}', '\u{0301}'], + '\u{1F3D}' => &['\u{0399}', '\u{0314}', '\u{0301}'], + '\u{1F3E}' => &['\u{0399}', '\u{0313}', '\u{0342}'], + '\u{1F3F}' => &['\u{0399}', '\u{0314}', '\u{0342}'], + '\u{1F40}' => &['\u{03BF}', '\u{0313}'], + '\u{1F41}' => &['\u{03BF}', '\u{0314}'], + '\u{1F42}' => &['\u{03BF}', '\u{0313}', '\u{0300}'], + '\u{1F43}' => &['\u{03BF}', '\u{0314}', '\u{0300}'], + '\u{1F44}' => &['\u{03BF}', '\u{0313}', '\u{0301}'], + '\u{1F45}' => &['\u{03BF}', '\u{0314}', '\u{0301}'], + '\u{1F48}' => &['\u{039F}', '\u{0313}'], + '\u{1F49}' => &['\u{039F}', '\u{0314}'], + '\u{1F4A}' => &['\u{039F}', '\u{0313}', '\u{0300}'], + '\u{1F4B}' => &['\u{039F}', '\u{0314}', '\u{0300}'], + '\u{1F4C}' => &['\u{039F}', '\u{0313}', '\u{0301}'], + '\u{1F4D}' => &['\u{039F}', '\u{0314}', '\u{0301}'], + '\u{1F50}' => &['\u{03C5}', '\u{0313}'], + '\u{1F51}' => &['\u{03C5}', '\u{0314}'], + '\u{1F52}' => &['\u{03C5}', '\u{0313}', '\u{0300}'], + '\u{1F53}' => &['\u{03C5}', '\u{0314}', '\u{0300}'], + '\u{1F54}' => &['\u{03C5}', '\u{0313}', '\u{0301}'], + '\u{1F55}' => &['\u{03C5}', '\u{0314}', '\u{0301}'], + '\u{1F56}' => &['\u{03C5}', '\u{0313}', '\u{0342}'], + '\u{1F57}' => &['\u{03C5}', '\u{0314}', '\u{0342}'], + '\u{1F59}' => &['\u{03A5}', '\u{0314}'], + '\u{1F5B}' => &['\u{03A5}', '\u{0314}', '\u{0300}'], + '\u{1F5D}' => &['\u{03A5}', '\u{0314}', '\u{0301}'], + '\u{1F5F}' => &['\u{03A5}', '\u{0314}', '\u{0342}'], + '\u{1F60}' => &['\u{03C9}', '\u{0313}'], + '\u{1F61}' => &['\u{03C9}', '\u{0314}'], + '\u{1F62}' => &['\u{03C9}', '\u{0313}', '\u{0300}'], + '\u{1F63}' => &['\u{03C9}', '\u{0314}', '\u{0300}'], + '\u{1F64}' => &['\u{03C9}', '\u{0313}', '\u{0301}'], + '\u{1F65}' => &['\u{03C9}', '\u{0314}', '\u{0301}'], + '\u{1F66}' => &['\u{03C9}', '\u{0313}', '\u{0342}'], + '\u{1F67}' => &['\u{03C9}', '\u{0314}', '\u{0342}'], + '\u{1F68}' => &['\u{03A9}', '\u{0313}'], + '\u{1F69}' => &['\u{03A9}', '\u{0314}'], + '\u{1F6A}' => &['\u{03A9}', '\u{0313}', '\u{0300}'], + '\u{1F6B}' => &['\u{03A9}', '\u{0314}', '\u{0300}'], + '\u{1F6C}' => &['\u{03A9}', '\u{0313}', '\u{0301}'], + '\u{1F6D}' => &['\u{03A9}', '\u{0314}', '\u{0301}'], + '\u{1F6E}' => &['\u{03A9}', '\u{0313}', '\u{0342}'], + '\u{1F6F}' => &['\u{03A9}', '\u{0314}', '\u{0342}'], + '\u{1F70}' => &['\u{03B1}', '\u{0300}'], + '\u{1F71}' => &['\u{03B1}', '\u{0301}'], + '\u{1F72}' => &['\u{03B5}', '\u{0300}'], + '\u{1F73}' => &['\u{03B5}', '\u{0301}'], + '\u{1F74}' => &['\u{03B7}', '\u{0300}'], + '\u{1F75}' => &['\u{03B7}', '\u{0301}'], + '\u{1F76}' => &['\u{03B9}', '\u{0300}'], + '\u{1F77}' => &['\u{03B9}', '\u{0301}'], + '\u{1F78}' => &['\u{03BF}', '\u{0300}'], + '\u{1F79}' => &['\u{03BF}', '\u{0301}'], + '\u{1F7A}' => &['\u{03C5}', '\u{0300}'], + '\u{1F7B}' => &['\u{03C5}', '\u{0301}'], + '\u{1F7C}' => &['\u{03C9}', '\u{0300}'], + '\u{1F7D}' => &['\u{03C9}', '\u{0301}'], + '\u{1F80}' => &['\u{03B1}', '\u{0313}', '\u{0345}'], + '\u{1F81}' => &['\u{03B1}', '\u{0314}', '\u{0345}'], + '\u{1F82}' => &['\u{03B1}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1F83}' => &['\u{03B1}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1F84}' => &['\u{03B1}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1F85}' => &['\u{03B1}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1F86}' => &['\u{03B1}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1F87}' => &['\u{03B1}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1F88}' => &['\u{0391}', '\u{0313}', '\u{0345}'], + '\u{1F89}' => &['\u{0391}', '\u{0314}', '\u{0345}'], + '\u{1F8A}' => &['\u{0391}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1F8B}' => &['\u{0391}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1F8C}' => &['\u{0391}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1F8D}' => &['\u{0391}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1F8E}' => &['\u{0391}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1F8F}' => &['\u{0391}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1F90}' => &['\u{03B7}', '\u{0313}', '\u{0345}'], + '\u{1F91}' => &['\u{03B7}', '\u{0314}', '\u{0345}'], + '\u{1F92}' => &['\u{03B7}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1F93}' => &['\u{03B7}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1F94}' => &['\u{03B7}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1F95}' => &['\u{03B7}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1F96}' => &['\u{03B7}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1F97}' => &['\u{03B7}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1F98}' => &['\u{0397}', '\u{0313}', '\u{0345}'], + '\u{1F99}' => &['\u{0397}', '\u{0314}', '\u{0345}'], + '\u{1F9A}' => &['\u{0397}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1F9B}' => &['\u{0397}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1F9C}' => &['\u{0397}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1F9D}' => &['\u{0397}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1F9E}' => &['\u{0397}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1F9F}' => &['\u{0397}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1FA0}' => &['\u{03C9}', '\u{0313}', '\u{0345}'], + '\u{1FA1}' => &['\u{03C9}', '\u{0314}', '\u{0345}'], + '\u{1FA2}' => &['\u{03C9}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1FA3}' => &['\u{03C9}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1FA4}' => &['\u{03C9}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1FA5}' => &['\u{03C9}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1FA6}' => &['\u{03C9}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1FA7}' => &['\u{03C9}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1FA8}' => &['\u{03A9}', '\u{0313}', '\u{0345}'], + '\u{1FA9}' => &['\u{03A9}', '\u{0314}', '\u{0345}'], + '\u{1FAA}' => &['\u{03A9}', '\u{0313}', '\u{0300}', '\u{0345}'], + '\u{1FAB}' => &['\u{03A9}', '\u{0314}', '\u{0300}', '\u{0345}'], + '\u{1FAC}' => &['\u{03A9}', '\u{0313}', '\u{0301}', '\u{0345}'], + '\u{1FAD}' => &['\u{03A9}', '\u{0314}', '\u{0301}', '\u{0345}'], + '\u{1FAE}' => &['\u{03A9}', '\u{0313}', '\u{0342}', '\u{0345}'], + '\u{1FAF}' => &['\u{03A9}', '\u{0314}', '\u{0342}', '\u{0345}'], + '\u{1FB0}' => &['\u{03B1}', '\u{0306}'], + '\u{1FB1}' => &['\u{03B1}', '\u{0304}'], + '\u{1FB2}' => &['\u{03B1}', '\u{0300}', '\u{0345}'], + '\u{1FB3}' => &['\u{03B1}', '\u{0345}'], + '\u{1FB4}' => &['\u{03B1}', '\u{0301}', '\u{0345}'], + '\u{1FB6}' => &['\u{03B1}', '\u{0342}'], + '\u{1FB7}' => &['\u{03B1}', '\u{0342}', '\u{0345}'], + '\u{1FB8}' => &['\u{0391}', '\u{0306}'], + '\u{1FB9}' => &['\u{0391}', '\u{0304}'], + '\u{1FBA}' => &['\u{0391}', '\u{0300}'], + '\u{1FBB}' => &['\u{0391}', '\u{0301}'], + '\u{1FBC}' => &['\u{0391}', '\u{0345}'], + '\u{1FBE}' => &['\u{03B9}'], + '\u{1FC1}' => &['\u{00A8}', '\u{0342}'], + '\u{1FC2}' => &['\u{03B7}', '\u{0300}', '\u{0345}'], + '\u{1FC3}' => &['\u{03B7}', '\u{0345}'], + '\u{1FC4}' => &['\u{03B7}', '\u{0301}', '\u{0345}'], + '\u{1FC6}' => &['\u{03B7}', '\u{0342}'], + '\u{1FC7}' => &['\u{03B7}', '\u{0342}', '\u{0345}'], + '\u{1FC8}' => &['\u{0395}', '\u{0300}'], + '\u{1FC9}' => &['\u{0395}', '\u{0301}'], + '\u{1FCA}' => &['\u{0397}', '\u{0300}'], + '\u{1FCB}' => &['\u{0397}', '\u{0301}'], + '\u{1FCC}' => &['\u{0397}', '\u{0345}'], + '\u{1FCD}' => &['\u{1FBF}', '\u{0300}'], + '\u{1FCE}' => &['\u{1FBF}', '\u{0301}'], + '\u{1FCF}' => &['\u{1FBF}', '\u{0342}'], + '\u{1FD0}' => &['\u{03B9}', '\u{0306}'], + '\u{1FD1}' => &['\u{03B9}', '\u{0304}'], + '\u{1FD2}' => &['\u{03B9}', '\u{0308}', '\u{0300}'], + '\u{1FD3}' => &['\u{03B9}', '\u{0308}', '\u{0301}'], + '\u{1FD6}' => &['\u{03B9}', '\u{0342}'], + '\u{1FD7}' => &['\u{03B9}', '\u{0308}', '\u{0342}'], + '\u{1FD8}' => &['\u{0399}', '\u{0306}'], + '\u{1FD9}' => &['\u{0399}', '\u{0304}'], + '\u{1FDA}' => &['\u{0399}', '\u{0300}'], + '\u{1FDB}' => &['\u{0399}', '\u{0301}'], + '\u{1FDD}' => &['\u{1FFE}', '\u{0300}'], + '\u{1FDE}' => &['\u{1FFE}', '\u{0301}'], + '\u{1FDF}' => &['\u{1FFE}', '\u{0342}'], + '\u{1FE0}' => &['\u{03C5}', '\u{0306}'], + '\u{1FE1}' => &['\u{03C5}', '\u{0304}'], + '\u{1FE2}' => &['\u{03C5}', '\u{0308}', '\u{0300}'], + '\u{1FE3}' => &['\u{03C5}', '\u{0308}', '\u{0301}'], + '\u{1FE4}' => &['\u{03C1}', '\u{0313}'], + '\u{1FE5}' => &['\u{03C1}', '\u{0314}'], + '\u{1FE6}' => &['\u{03C5}', '\u{0342}'], + '\u{1FE7}' => &['\u{03C5}', '\u{0308}', '\u{0342}'], + '\u{1FE8}' => &['\u{03A5}', '\u{0306}'], + '\u{1FE9}' => &['\u{03A5}', '\u{0304}'], + '\u{1FEA}' => &['\u{03A5}', '\u{0300}'], + '\u{1FEB}' => &['\u{03A5}', '\u{0301}'], + '\u{1FEC}' => &['\u{03A1}', '\u{0314}'], + '\u{1FED}' => &['\u{00A8}', '\u{0300}'], + '\u{1FEE}' => &['\u{00A8}', '\u{0301}'], + '\u{1FEF}' => &['\u{0060}'], + '\u{1FF2}' => &['\u{03C9}', '\u{0300}', '\u{0345}'], + '\u{1FF3}' => &['\u{03C9}', '\u{0345}'], + '\u{1FF4}' => &['\u{03C9}', '\u{0301}', '\u{0345}'], + '\u{1FF6}' => &['\u{03C9}', '\u{0342}'], + '\u{1FF7}' => &['\u{03C9}', '\u{0342}', '\u{0345}'], + '\u{1FF8}' => &['\u{039F}', '\u{0300}'], + '\u{1FF9}' => &['\u{039F}', '\u{0301}'], + '\u{1FFA}' => &['\u{03A9}', '\u{0300}'], + '\u{1FFB}' => &['\u{03A9}', '\u{0301}'], + '\u{1FFC}' => &['\u{03A9}', '\u{0345}'], + '\u{1FFD}' => &['\u{00B4}'], + '\u{2000}' => &['\u{2002}'], + '\u{2001}' => &['\u{2003}'], + '\u{2126}' => &['\u{03A9}'], + '\u{212A}' => &['\u{004B}'], + '\u{212B}' => &['\u{0041}', '\u{030A}'], + '\u{219A}' => &['\u{2190}', '\u{0338}'], + '\u{219B}' => &['\u{2192}', '\u{0338}'], + '\u{21AE}' => &['\u{2194}', '\u{0338}'], + '\u{21CD}' => &['\u{21D0}', '\u{0338}'], + '\u{21CE}' => &['\u{21D4}', '\u{0338}'], + '\u{21CF}' => &['\u{21D2}', '\u{0338}'], + '\u{2204}' => &['\u{2203}', '\u{0338}'], + '\u{2209}' => &['\u{2208}', '\u{0338}'], + '\u{220C}' => &['\u{220B}', '\u{0338}'], + '\u{2224}' => &['\u{2223}', '\u{0338}'], + '\u{2226}' => &['\u{2225}', '\u{0338}'], + '\u{2241}' => &['\u{223C}', '\u{0338}'], + '\u{2244}' => &['\u{2243}', '\u{0338}'], + '\u{2247}' => &['\u{2245}', '\u{0338}'], + '\u{2249}' => &['\u{2248}', '\u{0338}'], + '\u{2260}' => &['\u{003D}', '\u{0338}'], + '\u{2262}' => &['\u{2261}', '\u{0338}'], + '\u{226D}' => &['\u{224D}', '\u{0338}'], + '\u{226E}' => &['\u{003C}', '\u{0338}'], + '\u{226F}' => &['\u{003E}', '\u{0338}'], + '\u{2270}' => &['\u{2264}', '\u{0338}'], + '\u{2271}' => &['\u{2265}', '\u{0338}'], + '\u{2274}' => &['\u{2272}', '\u{0338}'], + '\u{2275}' => &['\u{2273}', '\u{0338}'], + '\u{2278}' => &['\u{2276}', '\u{0338}'], + '\u{2279}' => &['\u{2277}', '\u{0338}'], + '\u{2280}' => &['\u{227A}', '\u{0338}'], + '\u{2281}' => &['\u{227B}', '\u{0338}'], + '\u{2284}' => &['\u{2282}', '\u{0338}'], + '\u{2285}' => &['\u{2283}', '\u{0338}'], + '\u{2288}' => &['\u{2286}', '\u{0338}'], + '\u{2289}' => &['\u{2287}', '\u{0338}'], + '\u{22AC}' => &['\u{22A2}', '\u{0338}'], + '\u{22AD}' => &['\u{22A8}', '\u{0338}'], + '\u{22AE}' => &['\u{22A9}', '\u{0338}'], + '\u{22AF}' => &['\u{22AB}', '\u{0338}'], + '\u{22E0}' => &['\u{227C}', '\u{0338}'], + '\u{22E1}' => &['\u{227D}', '\u{0338}'], + '\u{22E2}' => &['\u{2291}', '\u{0338}'], + '\u{22E3}' => &['\u{2292}', '\u{0338}'], + '\u{22EA}' => &['\u{22B2}', '\u{0338}'], + '\u{22EB}' => &['\u{22B3}', '\u{0338}'], + '\u{22EC}' => &['\u{22B4}', '\u{0338}'], + '\u{22ED}' => &['\u{22B5}', '\u{0338}'], + '\u{2329}' => &['\u{3008}'], + '\u{232A}' => &['\u{3009}'], + '\u{2ADC}' => &['\u{2ADD}', '\u{0338}'], + '\u{304C}' => &['\u{304B}', '\u{3099}'], + '\u{304E}' => &['\u{304D}', '\u{3099}'], + '\u{3050}' => &['\u{304F}', '\u{3099}'], + '\u{3052}' => &['\u{3051}', '\u{3099}'], + '\u{3054}' => &['\u{3053}', '\u{3099}'], + '\u{3056}' => &['\u{3055}', '\u{3099}'], + '\u{3058}' => &['\u{3057}', '\u{3099}'], + '\u{305A}' => &['\u{3059}', '\u{3099}'], + '\u{305C}' => &['\u{305B}', '\u{3099}'], + '\u{305E}' => &['\u{305D}', '\u{3099}'], + '\u{3060}' => &['\u{305F}', '\u{3099}'], + '\u{3062}' => &['\u{3061}', '\u{3099}'], + '\u{3065}' => &['\u{3064}', '\u{3099}'], + '\u{3067}' => &['\u{3066}', '\u{3099}'], + '\u{3069}' => &['\u{3068}', '\u{3099}'], + '\u{3070}' => &['\u{306F}', '\u{3099}'], + '\u{3071}' => &['\u{306F}', '\u{309A}'], + '\u{3073}' => &['\u{3072}', '\u{3099}'], + '\u{3074}' => &['\u{3072}', '\u{309A}'], + '\u{3076}' => &['\u{3075}', '\u{3099}'], + '\u{3077}' => &['\u{3075}', '\u{309A}'], + '\u{3079}' => &['\u{3078}', '\u{3099}'], + '\u{307A}' => &['\u{3078}', '\u{309A}'], + '\u{307C}' => &['\u{307B}', '\u{3099}'], + '\u{307D}' => &['\u{307B}', '\u{309A}'], + '\u{3094}' => &['\u{3046}', '\u{3099}'], + '\u{309E}' => &['\u{309D}', '\u{3099}'], + '\u{30AC}' => &['\u{30AB}', '\u{3099}'], + '\u{30AE}' => &['\u{30AD}', '\u{3099}'], + '\u{30B0}' => &['\u{30AF}', '\u{3099}'], + '\u{30B2}' => &['\u{30B1}', '\u{3099}'], + '\u{30B4}' => &['\u{30B3}', '\u{3099}'], + '\u{30B6}' => &['\u{30B5}', '\u{3099}'], + '\u{30B8}' => &['\u{30B7}', '\u{3099}'], + '\u{30BA}' => &['\u{30B9}', '\u{3099}'], + '\u{30BC}' => &['\u{30BB}', '\u{3099}'], + '\u{30BE}' => &['\u{30BD}', '\u{3099}'], + '\u{30C0}' => &['\u{30BF}', '\u{3099}'], + '\u{30C2}' => &['\u{30C1}', '\u{3099}'], + '\u{30C5}' => &['\u{30C4}', '\u{3099}'], + '\u{30C7}' => &['\u{30C6}', '\u{3099}'], + '\u{30C9}' => &['\u{30C8}', '\u{3099}'], + '\u{30D0}' => &['\u{30CF}', '\u{3099}'], + '\u{30D1}' => &['\u{30CF}', '\u{309A}'], + '\u{30D3}' => &['\u{30D2}', '\u{3099}'], + '\u{30D4}' => &['\u{30D2}', '\u{309A}'], + '\u{30D6}' => &['\u{30D5}', '\u{3099}'], + '\u{30D7}' => &['\u{30D5}', '\u{309A}'], + '\u{30D9}' => &['\u{30D8}', '\u{3099}'], + '\u{30DA}' => &['\u{30D8}', '\u{309A}'], + '\u{30DC}' => &['\u{30DB}', '\u{3099}'], + '\u{30DD}' => &['\u{30DB}', '\u{309A}'], + '\u{30F4}' => &['\u{30A6}', '\u{3099}'], + '\u{30F7}' => &['\u{30EF}', '\u{3099}'], + '\u{30F8}' => &['\u{30F0}', '\u{3099}'], + '\u{30F9}' => &['\u{30F1}', '\u{3099}'], + '\u{30FA}' => &['\u{30F2}', '\u{3099}'], + '\u{30FE}' => &['\u{30FD}', '\u{3099}'], + '\u{F900}' => &['\u{8C48}'], + '\u{F901}' => &['\u{66F4}'], + '\u{F902}' => &['\u{8ECA}'], + '\u{F903}' => &['\u{8CC8}'], + '\u{F904}' => &['\u{6ED1}'], + '\u{F905}' => &['\u{4E32}'], + '\u{F906}' => &['\u{53E5}'], + '\u{F907}' => &['\u{9F9C}'], + '\u{F908}' => &['\u{9F9C}'], + '\u{F909}' => &['\u{5951}'], + '\u{F90A}' => &['\u{91D1}'], + '\u{F90B}' => &['\u{5587}'], + '\u{F90C}' => &['\u{5948}'], + '\u{F90D}' => &['\u{61F6}'], + '\u{F90E}' => &['\u{7669}'], + '\u{F90F}' => &['\u{7F85}'], + '\u{F910}' => &['\u{863F}'], + '\u{F911}' => &['\u{87BA}'], + '\u{F912}' => &['\u{88F8}'], + '\u{F913}' => &['\u{908F}'], + '\u{F914}' => &['\u{6A02}'], + '\u{F915}' => &['\u{6D1B}'], + '\u{F916}' => &['\u{70D9}'], + '\u{F917}' => &['\u{73DE}'], + '\u{F918}' => &['\u{843D}'], + '\u{F919}' => &['\u{916A}'], + '\u{F91A}' => &['\u{99F1}'], + '\u{F91B}' => &['\u{4E82}'], + '\u{F91C}' => &['\u{5375}'], + '\u{F91D}' => &['\u{6B04}'], + '\u{F91E}' => &['\u{721B}'], + '\u{F91F}' => &['\u{862D}'], + '\u{F920}' => &['\u{9E1E}'], + '\u{F921}' => &['\u{5D50}'], + '\u{F922}' => &['\u{6FEB}'], + '\u{F923}' => &['\u{85CD}'], + '\u{F924}' => &['\u{8964}'], + '\u{F925}' => &['\u{62C9}'], + '\u{F926}' => &['\u{81D8}'], + '\u{F927}' => &['\u{881F}'], + '\u{F928}' => &['\u{5ECA}'], + '\u{F929}' => &['\u{6717}'], + '\u{F92A}' => &['\u{6D6A}'], + '\u{F92B}' => &['\u{72FC}'], + '\u{F92C}' => &['\u{90CE}'], + '\u{F92D}' => &['\u{4F86}'], + '\u{F92E}' => &['\u{51B7}'], + '\u{F92F}' => &['\u{52DE}'], + '\u{F930}' => &['\u{64C4}'], + '\u{F931}' => &['\u{6AD3}'], + '\u{F932}' => &['\u{7210}'], + '\u{F933}' => &['\u{76E7}'], + '\u{F934}' => &['\u{8001}'], + '\u{F935}' => &['\u{8606}'], + '\u{F936}' => &['\u{865C}'], + '\u{F937}' => &['\u{8DEF}'], + '\u{F938}' => &['\u{9732}'], + '\u{F939}' => &['\u{9B6F}'], + '\u{F93A}' => &['\u{9DFA}'], + '\u{F93B}' => &['\u{788C}'], + '\u{F93C}' => &['\u{797F}'], + '\u{F93D}' => &['\u{7DA0}'], + '\u{F93E}' => &['\u{83C9}'], + '\u{F93F}' => &['\u{9304}'], + '\u{F940}' => &['\u{9E7F}'], + '\u{F941}' => &['\u{8AD6}'], + '\u{F942}' => &['\u{58DF}'], + '\u{F943}' => &['\u{5F04}'], + '\u{F944}' => &['\u{7C60}'], + '\u{F945}' => &['\u{807E}'], + '\u{F946}' => &['\u{7262}'], + '\u{F947}' => &['\u{78CA}'], + '\u{F948}' => &['\u{8CC2}'], + '\u{F949}' => &['\u{96F7}'], + '\u{F94A}' => &['\u{58D8}'], + '\u{F94B}' => &['\u{5C62}'], + '\u{F94C}' => &['\u{6A13}'], + '\u{F94D}' => &['\u{6DDA}'], + '\u{F94E}' => &['\u{6F0F}'], + '\u{F94F}' => &['\u{7D2F}'], + '\u{F950}' => &['\u{7E37}'], + '\u{F951}' => &['\u{964B}'], + '\u{F952}' => &['\u{52D2}'], + '\u{F953}' => &['\u{808B}'], + '\u{F954}' => &['\u{51DC}'], + '\u{F955}' => &['\u{51CC}'], + '\u{F956}' => &['\u{7A1C}'], + '\u{F957}' => &['\u{7DBE}'], + '\u{F958}' => &['\u{83F1}'], + '\u{F959}' => &['\u{9675}'], + '\u{F95A}' => &['\u{8B80}'], + '\u{F95B}' => &['\u{62CF}'], + '\u{F95C}' => &['\u{6A02}'], + '\u{F95D}' => &['\u{8AFE}'], + '\u{F95E}' => &['\u{4E39}'], + '\u{F95F}' => &['\u{5BE7}'], + '\u{F960}' => &['\u{6012}'], + '\u{F961}' => &['\u{7387}'], + '\u{F962}' => &['\u{7570}'], + '\u{F963}' => &['\u{5317}'], + '\u{F964}' => &['\u{78FB}'], + '\u{F965}' => &['\u{4FBF}'], + '\u{F966}' => &['\u{5FA9}'], + '\u{F967}' => &['\u{4E0D}'], + '\u{F968}' => &['\u{6CCC}'], + '\u{F969}' => &['\u{6578}'], + '\u{F96A}' => &['\u{7D22}'], + '\u{F96B}' => &['\u{53C3}'], + '\u{F96C}' => &['\u{585E}'], + '\u{F96D}' => &['\u{7701}'], + '\u{F96E}' => &['\u{8449}'], + '\u{F96F}' => &['\u{8AAA}'], + '\u{F970}' => &['\u{6BBA}'], + '\u{F971}' => &['\u{8FB0}'], + '\u{F972}' => &['\u{6C88}'], + '\u{F973}' => &['\u{62FE}'], + '\u{F974}' => &['\u{82E5}'], + '\u{F975}' => &['\u{63A0}'], + '\u{F976}' => &['\u{7565}'], + '\u{F977}' => &['\u{4EAE}'], + '\u{F978}' => &['\u{5169}'], + '\u{F979}' => &['\u{51C9}'], + '\u{F97A}' => &['\u{6881}'], + '\u{F97B}' => &['\u{7CE7}'], + '\u{F97C}' => &['\u{826F}'], + '\u{F97D}' => &['\u{8AD2}'], + '\u{F97E}' => &['\u{91CF}'], + '\u{F97F}' => &['\u{52F5}'], + '\u{F980}' => &['\u{5442}'], + '\u{F981}' => &['\u{5973}'], + '\u{F982}' => &['\u{5EEC}'], + '\u{F983}' => &['\u{65C5}'], + '\u{F984}' => &['\u{6FFE}'], + '\u{F985}' => &['\u{792A}'], + '\u{F986}' => &['\u{95AD}'], + '\u{F987}' => &['\u{9A6A}'], + '\u{F988}' => &['\u{9E97}'], + '\u{F989}' => &['\u{9ECE}'], + '\u{F98A}' => &['\u{529B}'], + '\u{F98B}' => &['\u{66C6}'], + '\u{F98C}' => &['\u{6B77}'], + '\u{F98D}' => &['\u{8F62}'], + '\u{F98E}' => &['\u{5E74}'], + '\u{F98F}' => &['\u{6190}'], + '\u{F990}' => &['\u{6200}'], + '\u{F991}' => &['\u{649A}'], + '\u{F992}' => &['\u{6F23}'], + '\u{F993}' => &['\u{7149}'], + '\u{F994}' => &['\u{7489}'], + '\u{F995}' => &['\u{79CA}'], + '\u{F996}' => &['\u{7DF4}'], + '\u{F997}' => &['\u{806F}'], + '\u{F998}' => &['\u{8F26}'], + '\u{F999}' => &['\u{84EE}'], + '\u{F99A}' => &['\u{9023}'], + '\u{F99B}' => &['\u{934A}'], + '\u{F99C}' => &['\u{5217}'], + '\u{F99D}' => &['\u{52A3}'], + '\u{F99E}' => &['\u{54BD}'], + '\u{F99F}' => &['\u{70C8}'], + '\u{F9A0}' => &['\u{88C2}'], + '\u{F9A1}' => &['\u{8AAA}'], + '\u{F9A2}' => &['\u{5EC9}'], + '\u{F9A3}' => &['\u{5FF5}'], + '\u{F9A4}' => &['\u{637B}'], + '\u{F9A5}' => &['\u{6BAE}'], + '\u{F9A6}' => &['\u{7C3E}'], + '\u{F9A7}' => &['\u{7375}'], + '\u{F9A8}' => &['\u{4EE4}'], + '\u{F9A9}' => &['\u{56F9}'], + '\u{F9AA}' => &['\u{5BE7}'], + '\u{F9AB}' => &['\u{5DBA}'], + '\u{F9AC}' => &['\u{601C}'], + '\u{F9AD}' => &['\u{73B2}'], + '\u{F9AE}' => &['\u{7469}'], + '\u{F9AF}' => &['\u{7F9A}'], + '\u{F9B0}' => &['\u{8046}'], + '\u{F9B1}' => &['\u{9234}'], + '\u{F9B2}' => &['\u{96F6}'], + '\u{F9B3}' => &['\u{9748}'], + '\u{F9B4}' => &['\u{9818}'], + '\u{F9B5}' => &['\u{4F8B}'], + '\u{F9B6}' => &['\u{79AE}'], + '\u{F9B7}' => &['\u{91B4}'], + '\u{F9B8}' => &['\u{96B8}'], + '\u{F9B9}' => &['\u{60E1}'], + '\u{F9BA}' => &['\u{4E86}'], + '\u{F9BB}' => &['\u{50DA}'], + '\u{F9BC}' => &['\u{5BEE}'], + '\u{F9BD}' => &['\u{5C3F}'], + '\u{F9BE}' => &['\u{6599}'], + '\u{F9BF}' => &['\u{6A02}'], + '\u{F9C0}' => &['\u{71CE}'], + '\u{F9C1}' => &['\u{7642}'], + '\u{F9C2}' => &['\u{84FC}'], + '\u{F9C3}' => &['\u{907C}'], + '\u{F9C4}' => &['\u{9F8D}'], + '\u{F9C5}' => &['\u{6688}'], + '\u{F9C6}' => &['\u{962E}'], + '\u{F9C7}' => &['\u{5289}'], + '\u{F9C8}' => &['\u{677B}'], + '\u{F9C9}' => &['\u{67F3}'], + '\u{F9CA}' => &['\u{6D41}'], + '\u{F9CB}' => &['\u{6E9C}'], + '\u{F9CC}' => &['\u{7409}'], + '\u{F9CD}' => &['\u{7559}'], + '\u{F9CE}' => &['\u{786B}'], + '\u{F9CF}' => &['\u{7D10}'], + '\u{F9D0}' => &['\u{985E}'], + '\u{F9D1}' => &['\u{516D}'], + '\u{F9D2}' => &['\u{622E}'], + '\u{F9D3}' => &['\u{9678}'], + '\u{F9D4}' => &['\u{502B}'], + '\u{F9D5}' => &['\u{5D19}'], + '\u{F9D6}' => &['\u{6DEA}'], + '\u{F9D7}' => &['\u{8F2A}'], + '\u{F9D8}' => &['\u{5F8B}'], + '\u{F9D9}' => &['\u{6144}'], + '\u{F9DA}' => &['\u{6817}'], + '\u{F9DB}' => &['\u{7387}'], + '\u{F9DC}' => &['\u{9686}'], + '\u{F9DD}' => &['\u{5229}'], + '\u{F9DE}' => &['\u{540F}'], + '\u{F9DF}' => &['\u{5C65}'], + '\u{F9E0}' => &['\u{6613}'], + '\u{F9E1}' => &['\u{674E}'], + '\u{F9E2}' => &['\u{68A8}'], + '\u{F9E3}' => &['\u{6CE5}'], + '\u{F9E4}' => &['\u{7406}'], + '\u{F9E5}' => &['\u{75E2}'], + '\u{F9E6}' => &['\u{7F79}'], + '\u{F9E7}' => &['\u{88CF}'], + '\u{F9E8}' => &['\u{88E1}'], + '\u{F9E9}' => &['\u{91CC}'], + '\u{F9EA}' => &['\u{96E2}'], + '\u{F9EB}' => &['\u{533F}'], + '\u{F9EC}' => &['\u{6EBA}'], + '\u{F9ED}' => &['\u{541D}'], + '\u{F9EE}' => &['\u{71D0}'], + '\u{F9EF}' => &['\u{7498}'], + '\u{F9F0}' => &['\u{85FA}'], + '\u{F9F1}' => &['\u{96A3}'], + '\u{F9F2}' => &['\u{9C57}'], + '\u{F9F3}' => &['\u{9E9F}'], + '\u{F9F4}' => &['\u{6797}'], + '\u{F9F5}' => &['\u{6DCB}'], + '\u{F9F6}' => &['\u{81E8}'], + '\u{F9F7}' => &['\u{7ACB}'], + '\u{F9F8}' => &['\u{7B20}'], + '\u{F9F9}' => &['\u{7C92}'], + '\u{F9FA}' => &['\u{72C0}'], + '\u{F9FB}' => &['\u{7099}'], + '\u{F9FC}' => &['\u{8B58}'], + '\u{F9FD}' => &['\u{4EC0}'], + '\u{F9FE}' => &['\u{8336}'], + '\u{F9FF}' => &['\u{523A}'], + '\u{FA00}' => &['\u{5207}'], + '\u{FA01}' => &['\u{5EA6}'], + '\u{FA02}' => &['\u{62D3}'], + '\u{FA03}' => &['\u{7CD6}'], + '\u{FA04}' => &['\u{5B85}'], + '\u{FA05}' => &['\u{6D1E}'], + '\u{FA06}' => &['\u{66B4}'], + '\u{FA07}' => &['\u{8F3B}'], + '\u{FA08}' => &['\u{884C}'], + '\u{FA09}' => &['\u{964D}'], + '\u{FA0A}' => &['\u{898B}'], + '\u{FA0B}' => &['\u{5ED3}'], + '\u{FA0C}' => &['\u{5140}'], + '\u{FA0D}' => &['\u{55C0}'], + '\u{FA10}' => &['\u{585A}'], + '\u{FA12}' => &['\u{6674}'], + '\u{FA15}' => &['\u{51DE}'], + '\u{FA16}' => &['\u{732A}'], + '\u{FA17}' => &['\u{76CA}'], + '\u{FA18}' => &['\u{793C}'], + '\u{FA19}' => &['\u{795E}'], + '\u{FA1A}' => &['\u{7965}'], + '\u{FA1B}' => &['\u{798F}'], + '\u{FA1C}' => &['\u{9756}'], + '\u{FA1D}' => &['\u{7CBE}'], + '\u{FA1E}' => &['\u{7FBD}'], + '\u{FA20}' => &['\u{8612}'], + '\u{FA22}' => &['\u{8AF8}'], + '\u{FA25}' => &['\u{9038}'], + '\u{FA26}' => &['\u{90FD}'], + '\u{FA2A}' => &['\u{98EF}'], + '\u{FA2B}' => &['\u{98FC}'], + '\u{FA2C}' => &['\u{9928}'], + '\u{FA2D}' => &['\u{9DB4}'], + '\u{FA2E}' => &['\u{90DE}'], + '\u{FA2F}' => &['\u{96B7}'], + '\u{FA30}' => &['\u{4FAE}'], + '\u{FA31}' => &['\u{50E7}'], + '\u{FA32}' => &['\u{514D}'], + '\u{FA33}' => &['\u{52C9}'], + '\u{FA34}' => &['\u{52E4}'], + '\u{FA35}' => &['\u{5351}'], + '\u{FA36}' => &['\u{559D}'], + '\u{FA37}' => &['\u{5606}'], + '\u{FA38}' => &['\u{5668}'], + '\u{FA39}' => &['\u{5840}'], + '\u{FA3A}' => &['\u{58A8}'], + '\u{FA3B}' => &['\u{5C64}'], + '\u{FA3C}' => &['\u{5C6E}'], + '\u{FA3D}' => &['\u{6094}'], + '\u{FA3E}' => &['\u{6168}'], + '\u{FA3F}' => &['\u{618E}'], + '\u{FA40}' => &['\u{61F2}'], + '\u{FA41}' => &['\u{654F}'], + '\u{FA42}' => &['\u{65E2}'], + '\u{FA43}' => &['\u{6691}'], + '\u{FA44}' => &['\u{6885}'], + '\u{FA45}' => &['\u{6D77}'], + '\u{FA46}' => &['\u{6E1A}'], + '\u{FA47}' => &['\u{6F22}'], + '\u{FA48}' => &['\u{716E}'], + '\u{FA49}' => &['\u{722B}'], + '\u{FA4A}' => &['\u{7422}'], + '\u{FA4B}' => &['\u{7891}'], + '\u{FA4C}' => &['\u{793E}'], + '\u{FA4D}' => &['\u{7949}'], + '\u{FA4E}' => &['\u{7948}'], + '\u{FA4F}' => &['\u{7950}'], + '\u{FA50}' => &['\u{7956}'], + '\u{FA51}' => &['\u{795D}'], + '\u{FA52}' => &['\u{798D}'], + '\u{FA53}' => &['\u{798E}'], + '\u{FA54}' => &['\u{7A40}'], + '\u{FA55}' => &['\u{7A81}'], + '\u{FA56}' => &['\u{7BC0}'], + '\u{FA57}' => &['\u{7DF4}'], + '\u{FA58}' => &['\u{7E09}'], + '\u{FA59}' => &['\u{7E41}'], + '\u{FA5A}' => &['\u{7F72}'], + '\u{FA5B}' => &['\u{8005}'], + '\u{FA5C}' => &['\u{81ED}'], + '\u{FA5D}' => &['\u{8279}'], + '\u{FA5E}' => &['\u{8279}'], + '\u{FA5F}' => &['\u{8457}'], + '\u{FA60}' => &['\u{8910}'], + '\u{FA61}' => &['\u{8996}'], + '\u{FA62}' => &['\u{8B01}'], + '\u{FA63}' => &['\u{8B39}'], + '\u{FA64}' => &['\u{8CD3}'], + '\u{FA65}' => &['\u{8D08}'], + '\u{FA66}' => &['\u{8FB6}'], + '\u{FA67}' => &['\u{9038}'], + '\u{FA68}' => &['\u{96E3}'], + '\u{FA69}' => &['\u{97FF}'], + '\u{FA6A}' => &['\u{983B}'], + '\u{FA6B}' => &['\u{6075}'], + '\u{FA6C}' => &['\u{242EE}'], + '\u{FA6D}' => &['\u{8218}'], + '\u{FA70}' => &['\u{4E26}'], + '\u{FA71}' => &['\u{51B5}'], + '\u{FA72}' => &['\u{5168}'], + '\u{FA73}' => &['\u{4F80}'], + '\u{FA74}' => &['\u{5145}'], + '\u{FA75}' => &['\u{5180}'], + '\u{FA76}' => &['\u{52C7}'], + '\u{FA77}' => &['\u{52FA}'], + '\u{FA78}' => &['\u{559D}'], + '\u{FA79}' => &['\u{5555}'], + '\u{FA7A}' => &['\u{5599}'], + '\u{FA7B}' => &['\u{55E2}'], + '\u{FA7C}' => &['\u{585A}'], + '\u{FA7D}' => &['\u{58B3}'], + '\u{FA7E}' => &['\u{5944}'], + '\u{FA7F}' => &['\u{5954}'], + '\u{FA80}' => &['\u{5A62}'], + '\u{FA81}' => &['\u{5B28}'], + '\u{FA82}' => &['\u{5ED2}'], + '\u{FA83}' => &['\u{5ED9}'], + '\u{FA84}' => &['\u{5F69}'], + '\u{FA85}' => &['\u{5FAD}'], + '\u{FA86}' => &['\u{60D8}'], + '\u{FA87}' => &['\u{614E}'], + '\u{FA88}' => &['\u{6108}'], + '\u{FA89}' => &['\u{618E}'], + '\u{FA8A}' => &['\u{6160}'], + '\u{FA8B}' => &['\u{61F2}'], + '\u{FA8C}' => &['\u{6234}'], + '\u{FA8D}' => &['\u{63C4}'], + '\u{FA8E}' => &['\u{641C}'], + '\u{FA8F}' => &['\u{6452}'], + '\u{FA90}' => &['\u{6556}'], + '\u{FA91}' => &['\u{6674}'], + '\u{FA92}' => &['\u{6717}'], + '\u{FA93}' => &['\u{671B}'], + '\u{FA94}' => &['\u{6756}'], + '\u{FA95}' => &['\u{6B79}'], + '\u{FA96}' => &['\u{6BBA}'], + '\u{FA97}' => &['\u{6D41}'], + '\u{FA98}' => &['\u{6EDB}'], + '\u{FA99}' => &['\u{6ECB}'], + '\u{FA9A}' => &['\u{6F22}'], + '\u{FA9B}' => &['\u{701E}'], + '\u{FA9C}' => &['\u{716E}'], + '\u{FA9D}' => &['\u{77A7}'], + '\u{FA9E}' => &['\u{7235}'], + '\u{FA9F}' => &['\u{72AF}'], + '\u{FAA0}' => &['\u{732A}'], + '\u{FAA1}' => &['\u{7471}'], + '\u{FAA2}' => &['\u{7506}'], + '\u{FAA3}' => &['\u{753B}'], + '\u{FAA4}' => &['\u{761D}'], + '\u{FAA5}' => &['\u{761F}'], + '\u{FAA6}' => &['\u{76CA}'], + '\u{FAA7}' => &['\u{76DB}'], + '\u{FAA8}' => &['\u{76F4}'], + '\u{FAA9}' => &['\u{774A}'], + '\u{FAAA}' => &['\u{7740}'], + '\u{FAAB}' => &['\u{78CC}'], + '\u{FAAC}' => &['\u{7AB1}'], + '\u{FAAD}' => &['\u{7BC0}'], + '\u{FAAE}' => &['\u{7C7B}'], + '\u{FAAF}' => &['\u{7D5B}'], + '\u{FAB0}' => &['\u{7DF4}'], + '\u{FAB1}' => &['\u{7F3E}'], + '\u{FAB2}' => &['\u{8005}'], + '\u{FAB3}' => &['\u{8352}'], + '\u{FAB4}' => &['\u{83EF}'], + '\u{FAB5}' => &['\u{8779}'], + '\u{FAB6}' => &['\u{8941}'], + '\u{FAB7}' => &['\u{8986}'], + '\u{FAB8}' => &['\u{8996}'], + '\u{FAB9}' => &['\u{8ABF}'], + '\u{FABA}' => &['\u{8AF8}'], + '\u{FABB}' => &['\u{8ACB}'], + '\u{FABC}' => &['\u{8B01}'], + '\u{FABD}' => &['\u{8AFE}'], + '\u{FABE}' => &['\u{8AED}'], + '\u{FABF}' => &['\u{8B39}'], + '\u{FAC0}' => &['\u{8B8A}'], + '\u{FAC1}' => &['\u{8D08}'], + '\u{FAC2}' => &['\u{8F38}'], + '\u{FAC3}' => &['\u{9072}'], + '\u{FAC4}' => &['\u{9199}'], + '\u{FAC5}' => &['\u{9276}'], + '\u{FAC6}' => &['\u{967C}'], + '\u{FAC7}' => &['\u{96E3}'], + '\u{FAC8}' => &['\u{9756}'], + '\u{FAC9}' => &['\u{97DB}'], + '\u{FACA}' => &['\u{97FF}'], + '\u{FACB}' => &['\u{980B}'], + '\u{FACC}' => &['\u{983B}'], + '\u{FACD}' => &['\u{9B12}'], + '\u{FACE}' => &['\u{9F9C}'], + '\u{FACF}' => &['\u{2284A}'], + '\u{FAD0}' => &['\u{22844}'], + '\u{FAD1}' => &['\u{233D5}'], + '\u{FAD2}' => &['\u{3B9D}'], + '\u{FAD3}' => &['\u{4018}'], + '\u{FAD4}' => &['\u{4039}'], + '\u{FAD5}' => &['\u{25249}'], + '\u{FAD6}' => &['\u{25CD0}'], + '\u{FAD7}' => &['\u{27ED3}'], + '\u{FAD8}' => &['\u{9F43}'], + '\u{FAD9}' => &['\u{9F8E}'], + '\u{FB1D}' => &['\u{05D9}', '\u{05B4}'], + '\u{FB1F}' => &['\u{05F2}', '\u{05B7}'], + '\u{FB2A}' => &['\u{05E9}', '\u{05C1}'], + '\u{FB2B}' => &['\u{05E9}', '\u{05C2}'], + '\u{FB2C}' => &['\u{05E9}', '\u{05BC}', '\u{05C1}'], + '\u{FB2D}' => &['\u{05E9}', '\u{05BC}', '\u{05C2}'], + '\u{FB2E}' => &['\u{05D0}', '\u{05B7}'], + '\u{FB2F}' => &['\u{05D0}', '\u{05B8}'], + '\u{FB30}' => &['\u{05D0}', '\u{05BC}'], + '\u{FB31}' => &['\u{05D1}', '\u{05BC}'], + '\u{FB32}' => &['\u{05D2}', '\u{05BC}'], + '\u{FB33}' => &['\u{05D3}', '\u{05BC}'], + '\u{FB34}' => &['\u{05D4}', '\u{05BC}'], + '\u{FB35}' => &['\u{05D5}', '\u{05BC}'], + '\u{FB36}' => &['\u{05D6}', '\u{05BC}'], + '\u{FB38}' => &['\u{05D8}', '\u{05BC}'], + '\u{FB39}' => &['\u{05D9}', '\u{05BC}'], + '\u{FB3A}' => &['\u{05DA}', '\u{05BC}'], + '\u{FB3B}' => &['\u{05DB}', '\u{05BC}'], + '\u{FB3C}' => &['\u{05DC}', '\u{05BC}'], + '\u{FB3E}' => &['\u{05DE}', '\u{05BC}'], + '\u{FB40}' => &['\u{05E0}', '\u{05BC}'], + '\u{FB41}' => &['\u{05E1}', '\u{05BC}'], + '\u{FB43}' => &['\u{05E3}', '\u{05BC}'], + '\u{FB44}' => &['\u{05E4}', '\u{05BC}'], + '\u{FB46}' => &['\u{05E6}', '\u{05BC}'], + '\u{FB47}' => &['\u{05E7}', '\u{05BC}'], + '\u{FB48}' => &['\u{05E8}', '\u{05BC}'], + '\u{FB49}' => &['\u{05E9}', '\u{05BC}'], + '\u{FB4A}' => &['\u{05EA}', '\u{05BC}'], + '\u{FB4B}' => &['\u{05D5}', '\u{05B9}'], + '\u{FB4C}' => &['\u{05D1}', '\u{05BF}'], + '\u{FB4D}' => &['\u{05DB}', '\u{05BF}'], + '\u{FB4E}' => &['\u{05E4}', '\u{05BF}'], + '\u{1109A}' => &['\u{11099}', '\u{110BA}'], + '\u{1109C}' => &['\u{1109B}', '\u{110BA}'], + '\u{110AB}' => &['\u{110A5}', '\u{110BA}'], + '\u{1112E}' => &['\u{11131}', '\u{11127}'], + '\u{1112F}' => &['\u{11132}', '\u{11127}'], + '\u{1134B}' => &['\u{11347}', '\u{1133E}'], + '\u{1134C}' => &['\u{11347}', '\u{11357}'], + '\u{114BB}' => &['\u{114B9}', '\u{114BA}'], + '\u{114BC}' => &['\u{114B9}', '\u{114B0}'], + '\u{114BE}' => &['\u{114B9}', '\u{114BD}'], + '\u{115BA}' => &['\u{115B8}', '\u{115AF}'], + '\u{115BB}' => &['\u{115B9}', '\u{115AF}'], + '\u{1D15E}' => &['\u{1D157}', '\u{1D165}'], + '\u{1D15F}' => &['\u{1D158}', '\u{1D165}'], + '\u{1D160}' => &['\u{1D158}', '\u{1D165}', '\u{1D16E}'], + '\u{1D161}' => &['\u{1D158}', '\u{1D165}', '\u{1D16F}'], + '\u{1D162}' => &['\u{1D158}', '\u{1D165}', '\u{1D170}'], + '\u{1D163}' => &['\u{1D158}', '\u{1D165}', '\u{1D171}'], + '\u{1D164}' => &['\u{1D158}', '\u{1D165}', '\u{1D172}'], + '\u{1D1BB}' => &['\u{1D1B9}', '\u{1D165}'], + '\u{1D1BC}' => &['\u{1D1BA}', '\u{1D165}'], + '\u{1D1BD}' => &['\u{1D1B9}', '\u{1D165}', '\u{1D16E}'], + '\u{1D1BE}' => &['\u{1D1BA}', '\u{1D165}', '\u{1D16E}'], + '\u{1D1BF}' => &['\u{1D1B9}', '\u{1D165}', '\u{1D16F}'], + '\u{1D1C0}' => &['\u{1D1BA}', '\u{1D165}', '\u{1D16F}'], + '\u{2F800}' => &['\u{4E3D}'], + '\u{2F801}' => &['\u{4E38}'], + '\u{2F802}' => &['\u{4E41}'], + '\u{2F803}' => &['\u{20122}'], + '\u{2F804}' => &['\u{4F60}'], + '\u{2F805}' => &['\u{4FAE}'], + '\u{2F806}' => &['\u{4FBB}'], + '\u{2F807}' => &['\u{5002}'], + '\u{2F808}' => &['\u{507A}'], + '\u{2F809}' => &['\u{5099}'], + '\u{2F80A}' => &['\u{50E7}'], + '\u{2F80B}' => &['\u{50CF}'], + '\u{2F80C}' => &['\u{349E}'], + '\u{2F80D}' => &['\u{2063A}'], + '\u{2F80E}' => &['\u{514D}'], + '\u{2F80F}' => &['\u{5154}'], + '\u{2F810}' => &['\u{5164}'], + '\u{2F811}' => &['\u{5177}'], + '\u{2F812}' => &['\u{2051C}'], + '\u{2F813}' => &['\u{34B9}'], + '\u{2F814}' => &['\u{5167}'], + '\u{2F815}' => &['\u{518D}'], + '\u{2F816}' => &['\u{2054B}'], + '\u{2F817}' => &['\u{5197}'], + '\u{2F818}' => &['\u{51A4}'], + '\u{2F819}' => &['\u{4ECC}'], + '\u{2F81A}' => &['\u{51AC}'], + '\u{2F81B}' => &['\u{51B5}'], + '\u{2F81C}' => &['\u{291DF}'], + '\u{2F81D}' => &['\u{51F5}'], + '\u{2F81E}' => &['\u{5203}'], + '\u{2F81F}' => &['\u{34DF}'], + '\u{2F820}' => &['\u{523B}'], + '\u{2F821}' => &['\u{5246}'], + '\u{2F822}' => &['\u{5272}'], + '\u{2F823}' => &['\u{5277}'], + '\u{2F824}' => &['\u{3515}'], + '\u{2F825}' => &['\u{52C7}'], + '\u{2F826}' => &['\u{52C9}'], + '\u{2F827}' => &['\u{52E4}'], + '\u{2F828}' => &['\u{52FA}'], + '\u{2F829}' => &['\u{5305}'], + '\u{2F82A}' => &['\u{5306}'], + '\u{2F82B}' => &['\u{5317}'], + '\u{2F82C}' => &['\u{5349}'], + '\u{2F82D}' => &['\u{5351}'], + '\u{2F82E}' => &['\u{535A}'], + '\u{2F82F}' => &['\u{5373}'], + '\u{2F830}' => &['\u{537D}'], + '\u{2F831}' => &['\u{537F}'], + '\u{2F832}' => &['\u{537F}'], + '\u{2F833}' => &['\u{537F}'], + '\u{2F834}' => &['\u{20A2C}'], + '\u{2F835}' => &['\u{7070}'], + '\u{2F836}' => &['\u{53CA}'], + '\u{2F837}' => &['\u{53DF}'], + '\u{2F838}' => &['\u{20B63}'], + '\u{2F839}' => &['\u{53EB}'], + '\u{2F83A}' => &['\u{53F1}'], + '\u{2F83B}' => &['\u{5406}'], + '\u{2F83C}' => &['\u{549E}'], + '\u{2F83D}' => &['\u{5438}'], + '\u{2F83E}' => &['\u{5448}'], + '\u{2F83F}' => &['\u{5468}'], + '\u{2F840}' => &['\u{54A2}'], + '\u{2F841}' => &['\u{54F6}'], + '\u{2F842}' => &['\u{5510}'], + '\u{2F843}' => &['\u{5553}'], + '\u{2F844}' => &['\u{5563}'], + '\u{2F845}' => &['\u{5584}'], + '\u{2F846}' => &['\u{5584}'], + '\u{2F847}' => &['\u{5599}'], + '\u{2F848}' => &['\u{55AB}'], + '\u{2F849}' => &['\u{55B3}'], + '\u{2F84A}' => &['\u{55C2}'], + '\u{2F84B}' => &['\u{5716}'], + '\u{2F84C}' => &['\u{5606}'], + '\u{2F84D}' => &['\u{5717}'], + '\u{2F84E}' => &['\u{5651}'], + '\u{2F84F}' => &['\u{5674}'], + '\u{2F850}' => &['\u{5207}'], + '\u{2F851}' => &['\u{58EE}'], + '\u{2F852}' => &['\u{57CE}'], + '\u{2F853}' => &['\u{57F4}'], + '\u{2F854}' => &['\u{580D}'], + '\u{2F855}' => &['\u{578B}'], + '\u{2F856}' => &['\u{5832}'], + '\u{2F857}' => &['\u{5831}'], + '\u{2F858}' => &['\u{58AC}'], + '\u{2F859}' => &['\u{214E4}'], + '\u{2F85A}' => &['\u{58F2}'], + '\u{2F85B}' => &['\u{58F7}'], + '\u{2F85C}' => &['\u{5906}'], + '\u{2F85D}' => &['\u{591A}'], + '\u{2F85E}' => &['\u{5922}'], + '\u{2F85F}' => &['\u{5962}'], + '\u{2F860}' => &['\u{216A8}'], + '\u{2F861}' => &['\u{216EA}'], + '\u{2F862}' => &['\u{59EC}'], + '\u{2F863}' => &['\u{5A1B}'], + '\u{2F864}' => &['\u{5A27}'], + '\u{2F865}' => &['\u{59D8}'], + '\u{2F866}' => &['\u{5A66}'], + '\u{2F867}' => &['\u{36EE}'], + '\u{2F868}' => &['\u{36FC}'], + '\u{2F869}' => &['\u{5B08}'], + '\u{2F86A}' => &['\u{5B3E}'], + '\u{2F86B}' => &['\u{5B3E}'], + '\u{2F86C}' => &['\u{219C8}'], + '\u{2F86D}' => &['\u{5BC3}'], + '\u{2F86E}' => &['\u{5BD8}'], + '\u{2F86F}' => &['\u{5BE7}'], + '\u{2F870}' => &['\u{5BF3}'], + '\u{2F871}' => &['\u{21B18}'], + '\u{2F872}' => &['\u{5BFF}'], + '\u{2F873}' => &['\u{5C06}'], + '\u{2F874}' => &['\u{5F53}'], + '\u{2F875}' => &['\u{5C22}'], + '\u{2F876}' => &['\u{3781}'], + '\u{2F877}' => &['\u{5C60}'], + '\u{2F878}' => &['\u{5C6E}'], + '\u{2F879}' => &['\u{5CC0}'], + '\u{2F87A}' => &['\u{5C8D}'], + '\u{2F87B}' => &['\u{21DE4}'], + '\u{2F87C}' => &['\u{5D43}'], + '\u{2F87D}' => &['\u{21DE6}'], + '\u{2F87E}' => &['\u{5D6E}'], + '\u{2F87F}' => &['\u{5D6B}'], + '\u{2F880}' => &['\u{5D7C}'], + '\u{2F881}' => &['\u{5DE1}'], + '\u{2F882}' => &['\u{5DE2}'], + '\u{2F883}' => &['\u{382F}'], + '\u{2F884}' => &['\u{5DFD}'], + '\u{2F885}' => &['\u{5E28}'], + '\u{2F886}' => &['\u{5E3D}'], + '\u{2F887}' => &['\u{5E69}'], + '\u{2F888}' => &['\u{3862}'], + '\u{2F889}' => &['\u{22183}'], + '\u{2F88A}' => &['\u{387C}'], + '\u{2F88B}' => &['\u{5EB0}'], + '\u{2F88C}' => &['\u{5EB3}'], + '\u{2F88D}' => &['\u{5EB6}'], + '\u{2F88E}' => &['\u{5ECA}'], + '\u{2F88F}' => &['\u{2A392}'], + '\u{2F890}' => &['\u{5EFE}'], + '\u{2F891}' => &['\u{22331}'], + '\u{2F892}' => &['\u{22331}'], + '\u{2F893}' => &['\u{8201}'], + '\u{2F894}' => &['\u{5F22}'], + '\u{2F895}' => &['\u{5F22}'], + '\u{2F896}' => &['\u{38C7}'], + '\u{2F897}' => &['\u{232B8}'], + '\u{2F898}' => &['\u{261DA}'], + '\u{2F899}' => &['\u{5F62}'], + '\u{2F89A}' => &['\u{5F6B}'], + '\u{2F89B}' => &['\u{38E3}'], + '\u{2F89C}' => &['\u{5F9A}'], + '\u{2F89D}' => &['\u{5FCD}'], + '\u{2F89E}' => &['\u{5FD7}'], + '\u{2F89F}' => &['\u{5FF9}'], + '\u{2F8A0}' => &['\u{6081}'], + '\u{2F8A1}' => &['\u{393A}'], + '\u{2F8A2}' => &['\u{391C}'], + '\u{2F8A3}' => &['\u{6094}'], + '\u{2F8A4}' => &['\u{226D4}'], + '\u{2F8A5}' => &['\u{60C7}'], + '\u{2F8A6}' => &['\u{6148}'], + '\u{2F8A7}' => &['\u{614C}'], + '\u{2F8A8}' => &['\u{614E}'], + '\u{2F8A9}' => &['\u{614C}'], + '\u{2F8AA}' => &['\u{617A}'], + '\u{2F8AB}' => &['\u{618E}'], + '\u{2F8AC}' => &['\u{61B2}'], + '\u{2F8AD}' => &['\u{61A4}'], + '\u{2F8AE}' => &['\u{61AF}'], + '\u{2F8AF}' => &['\u{61DE}'], + '\u{2F8B0}' => &['\u{61F2}'], + '\u{2F8B1}' => &['\u{61F6}'], + '\u{2F8B2}' => &['\u{6210}'], + '\u{2F8B3}' => &['\u{621B}'], + '\u{2F8B4}' => &['\u{625D}'], + '\u{2F8B5}' => &['\u{62B1}'], + '\u{2F8B6}' => &['\u{62D4}'], + '\u{2F8B7}' => &['\u{6350}'], + '\u{2F8B8}' => &['\u{22B0C}'], + '\u{2F8B9}' => &['\u{633D}'], + '\u{2F8BA}' => &['\u{62FC}'], + '\u{2F8BB}' => &['\u{6368}'], + '\u{2F8BC}' => &['\u{6383}'], + '\u{2F8BD}' => &['\u{63E4}'], + '\u{2F8BE}' => &['\u{22BF1}'], + '\u{2F8BF}' => &['\u{6422}'], + '\u{2F8C0}' => &['\u{63C5}'], + '\u{2F8C1}' => &['\u{63A9}'], + '\u{2F8C2}' => &['\u{3A2E}'], + '\u{2F8C3}' => &['\u{6469}'], + '\u{2F8C4}' => &['\u{647E}'], + '\u{2F8C5}' => &['\u{649D}'], + '\u{2F8C6}' => &['\u{6477}'], + '\u{2F8C7}' => &['\u{3A6C}'], + '\u{2F8C8}' => &['\u{654F}'], + '\u{2F8C9}' => &['\u{656C}'], + '\u{2F8CA}' => &['\u{2300A}'], + '\u{2F8CB}' => &['\u{65E3}'], + '\u{2F8CC}' => &['\u{66F8}'], + '\u{2F8CD}' => &['\u{6649}'], + '\u{2F8CE}' => &['\u{3B19}'], + '\u{2F8CF}' => &['\u{6691}'], + '\u{2F8D0}' => &['\u{3B08}'], + '\u{2F8D1}' => &['\u{3AE4}'], + '\u{2F8D2}' => &['\u{5192}'], + '\u{2F8D3}' => &['\u{5195}'], + '\u{2F8D4}' => &['\u{6700}'], + '\u{2F8D5}' => &['\u{669C}'], + '\u{2F8D6}' => &['\u{80AD}'], + '\u{2F8D7}' => &['\u{43D9}'], + '\u{2F8D8}' => &['\u{6717}'], + '\u{2F8D9}' => &['\u{671B}'], + '\u{2F8DA}' => &['\u{6721}'], + '\u{2F8DB}' => &['\u{675E}'], + '\u{2F8DC}' => &['\u{6753}'], + '\u{2F8DD}' => &['\u{233C3}'], + '\u{2F8DE}' => &['\u{3B49}'], + '\u{2F8DF}' => &['\u{67FA}'], + '\u{2F8E0}' => &['\u{6785}'], + '\u{2F8E1}' => &['\u{6852}'], + '\u{2F8E2}' => &['\u{6885}'], + '\u{2F8E3}' => &['\u{2346D}'], + '\u{2F8E4}' => &['\u{688E}'], + '\u{2F8E5}' => &['\u{681F}'], + '\u{2F8E6}' => &['\u{6914}'], + '\u{2F8E7}' => &['\u{3B9D}'], + '\u{2F8E8}' => &['\u{6942}'], + '\u{2F8E9}' => &['\u{69A3}'], + '\u{2F8EA}' => &['\u{69EA}'], + '\u{2F8EB}' => &['\u{6AA8}'], + '\u{2F8EC}' => &['\u{236A3}'], + '\u{2F8ED}' => &['\u{6ADB}'], + '\u{2F8EE}' => &['\u{3C18}'], + '\u{2F8EF}' => &['\u{6B21}'], + '\u{2F8F0}' => &['\u{238A7}'], + '\u{2F8F1}' => &['\u{6B54}'], + '\u{2F8F2}' => &['\u{3C4E}'], + '\u{2F8F3}' => &['\u{6B72}'], + '\u{2F8F4}' => &['\u{6B9F}'], + '\u{2F8F5}' => &['\u{6BBA}'], + '\u{2F8F6}' => &['\u{6BBB}'], + '\u{2F8F7}' => &['\u{23A8D}'], + '\u{2F8F8}' => &['\u{21D0B}'], + '\u{2F8F9}' => &['\u{23AFA}'], + '\u{2F8FA}' => &['\u{6C4E}'], + '\u{2F8FB}' => &['\u{23CBC}'], + '\u{2F8FC}' => &['\u{6CBF}'], + '\u{2F8FD}' => &['\u{6CCD}'], + '\u{2F8FE}' => &['\u{6C67}'], + '\u{2F8FF}' => &['\u{6D16}'], + '\u{2F900}' => &['\u{6D3E}'], + '\u{2F901}' => &['\u{6D77}'], + '\u{2F902}' => &['\u{6D41}'], + '\u{2F903}' => &['\u{6D69}'], + '\u{2F904}' => &['\u{6D78}'], + '\u{2F905}' => &['\u{6D85}'], + '\u{2F906}' => &['\u{23D1E}'], + '\u{2F907}' => &['\u{6D34}'], + '\u{2F908}' => &['\u{6E2F}'], + '\u{2F909}' => &['\u{6E6E}'], + '\u{2F90A}' => &['\u{3D33}'], + '\u{2F90B}' => &['\u{6ECB}'], + '\u{2F90C}' => &['\u{6EC7}'], + '\u{2F90D}' => &['\u{23ED1}'], + '\u{2F90E}' => &['\u{6DF9}'], + '\u{2F90F}' => &['\u{6F6E}'], + '\u{2F910}' => &['\u{23F5E}'], + '\u{2F911}' => &['\u{23F8E}'], + '\u{2F912}' => &['\u{6FC6}'], + '\u{2F913}' => &['\u{7039}'], + '\u{2F914}' => &['\u{701E}'], + '\u{2F915}' => &['\u{701B}'], + '\u{2F916}' => &['\u{3D96}'], + '\u{2F917}' => &['\u{704A}'], + '\u{2F918}' => &['\u{707D}'], + '\u{2F919}' => &['\u{7077}'], + '\u{2F91A}' => &['\u{70AD}'], + '\u{2F91B}' => &['\u{20525}'], + '\u{2F91C}' => &['\u{7145}'], + '\u{2F91D}' => &['\u{24263}'], + '\u{2F91E}' => &['\u{719C}'], + '\u{2F91F}' => &['\u{243AB}'], + '\u{2F920}' => &['\u{7228}'], + '\u{2F921}' => &['\u{7235}'], + '\u{2F922}' => &['\u{7250}'], + '\u{2F923}' => &['\u{24608}'], + '\u{2F924}' => &['\u{7280}'], + '\u{2F925}' => &['\u{7295}'], + '\u{2F926}' => &['\u{24735}'], + '\u{2F927}' => &['\u{24814}'], + '\u{2F928}' => &['\u{737A}'], + '\u{2F929}' => &['\u{738B}'], + '\u{2F92A}' => &['\u{3EAC}'], + '\u{2F92B}' => &['\u{73A5}'], + '\u{2F92C}' => &['\u{3EB8}'], + '\u{2F92D}' => &['\u{3EB8}'], + '\u{2F92E}' => &['\u{7447}'], + '\u{2F92F}' => &['\u{745C}'], + '\u{2F930}' => &['\u{7471}'], + '\u{2F931}' => &['\u{7485}'], + '\u{2F932}' => &['\u{74CA}'], + '\u{2F933}' => &['\u{3F1B}'], + '\u{2F934}' => &['\u{7524}'], + '\u{2F935}' => &['\u{24C36}'], + '\u{2F936}' => &['\u{753E}'], + '\u{2F937}' => &['\u{24C92}'], + '\u{2F938}' => &['\u{7570}'], + '\u{2F939}' => &['\u{2219F}'], + '\u{2F93A}' => &['\u{7610}'], + '\u{2F93B}' => &['\u{24FA1}'], + '\u{2F93C}' => &['\u{24FB8}'], + '\u{2F93D}' => &['\u{25044}'], + '\u{2F93E}' => &['\u{3FFC}'], + '\u{2F93F}' => &['\u{4008}'], + '\u{2F940}' => &['\u{76F4}'], + '\u{2F941}' => &['\u{250F3}'], + '\u{2F942}' => &['\u{250F2}'], + '\u{2F943}' => &['\u{25119}'], + '\u{2F944}' => &['\u{25133}'], + '\u{2F945}' => &['\u{771E}'], + '\u{2F946}' => &['\u{771F}'], + '\u{2F947}' => &['\u{771F}'], + '\u{2F948}' => &['\u{774A}'], + '\u{2F949}' => &['\u{4039}'], + '\u{2F94A}' => &['\u{778B}'], + '\u{2F94B}' => &['\u{4046}'], + '\u{2F94C}' => &['\u{4096}'], + '\u{2F94D}' => &['\u{2541D}'], + '\u{2F94E}' => &['\u{784E}'], + '\u{2F94F}' => &['\u{788C}'], + '\u{2F950}' => &['\u{78CC}'], + '\u{2F951}' => &['\u{40E3}'], + '\u{2F952}' => &['\u{25626}'], + '\u{2F953}' => &['\u{7956}'], + '\u{2F954}' => &['\u{2569A}'], + '\u{2F955}' => &['\u{256C5}'], + '\u{2F956}' => &['\u{798F}'], + '\u{2F957}' => &['\u{79EB}'], + '\u{2F958}' => &['\u{412F}'], + '\u{2F959}' => &['\u{7A40}'], + '\u{2F95A}' => &['\u{7A4A}'], + '\u{2F95B}' => &['\u{7A4F}'], + '\u{2F95C}' => &['\u{2597C}'], + '\u{2F95D}' => &['\u{25AA7}'], + '\u{2F95E}' => &['\u{25AA7}'], + '\u{2F95F}' => &['\u{7AEE}'], + '\u{2F960}' => &['\u{4202}'], + '\u{2F961}' => &['\u{25BAB}'], + '\u{2F962}' => &['\u{7BC6}'], + '\u{2F963}' => &['\u{7BC9}'], + '\u{2F964}' => &['\u{4227}'], + '\u{2F965}' => &['\u{25C80}'], + '\u{2F966}' => &['\u{7CD2}'], + '\u{2F967}' => &['\u{42A0}'], + '\u{2F968}' => &['\u{7CE8}'], + '\u{2F969}' => &['\u{7CE3}'], + '\u{2F96A}' => &['\u{7D00}'], + '\u{2F96B}' => &['\u{25F86}'], + '\u{2F96C}' => &['\u{7D63}'], + '\u{2F96D}' => &['\u{4301}'], + '\u{2F96E}' => &['\u{7DC7}'], + '\u{2F96F}' => &['\u{7E02}'], + '\u{2F970}' => &['\u{7E45}'], + '\u{2F971}' => &['\u{4334}'], + '\u{2F972}' => &['\u{26228}'], + '\u{2F973}' => &['\u{26247}'], + '\u{2F974}' => &['\u{4359}'], + '\u{2F975}' => &['\u{262D9}'], + '\u{2F976}' => &['\u{7F7A}'], + '\u{2F977}' => &['\u{2633E}'], + '\u{2F978}' => &['\u{7F95}'], + '\u{2F979}' => &['\u{7FFA}'], + '\u{2F97A}' => &['\u{8005}'], + '\u{2F97B}' => &['\u{264DA}'], + '\u{2F97C}' => &['\u{26523}'], + '\u{2F97D}' => &['\u{8060}'], + '\u{2F97E}' => &['\u{265A8}'], + '\u{2F97F}' => &['\u{8070}'], + '\u{2F980}' => &['\u{2335F}'], + '\u{2F981}' => &['\u{43D5}'], + '\u{2F982}' => &['\u{80B2}'], + '\u{2F983}' => &['\u{8103}'], + '\u{2F984}' => &['\u{440B}'], + '\u{2F985}' => &['\u{813E}'], + '\u{2F986}' => &['\u{5AB5}'], + '\u{2F987}' => &['\u{267A7}'], + '\u{2F988}' => &['\u{267B5}'], + '\u{2F989}' => &['\u{23393}'], + '\u{2F98A}' => &['\u{2339C}'], + '\u{2F98B}' => &['\u{8201}'], + '\u{2F98C}' => &['\u{8204}'], + '\u{2F98D}' => &['\u{8F9E}'], + '\u{2F98E}' => &['\u{446B}'], + '\u{2F98F}' => &['\u{8291}'], + '\u{2F990}' => &['\u{828B}'], + '\u{2F991}' => &['\u{829D}'], + '\u{2F992}' => &['\u{52B3}'], + '\u{2F993}' => &['\u{82B1}'], + '\u{2F994}' => &['\u{82B3}'], + '\u{2F995}' => &['\u{82BD}'], + '\u{2F996}' => &['\u{82E6}'], + '\u{2F997}' => &['\u{26B3C}'], + '\u{2F998}' => &['\u{82E5}'], + '\u{2F999}' => &['\u{831D}'], + '\u{2F99A}' => &['\u{8363}'], + '\u{2F99B}' => &['\u{83AD}'], + '\u{2F99C}' => &['\u{8323}'], + '\u{2F99D}' => &['\u{83BD}'], + '\u{2F99E}' => &['\u{83E7}'], + '\u{2F99F}' => &['\u{8457}'], + '\u{2F9A0}' => &['\u{8353}'], + '\u{2F9A1}' => &['\u{83CA}'], + '\u{2F9A2}' => &['\u{83CC}'], + '\u{2F9A3}' => &['\u{83DC}'], + '\u{2F9A4}' => &['\u{26C36}'], + '\u{2F9A5}' => &['\u{26D6B}'], + '\u{2F9A6}' => &['\u{26CD5}'], + '\u{2F9A7}' => &['\u{452B}'], + '\u{2F9A8}' => &['\u{84F1}'], + '\u{2F9A9}' => &['\u{84F3}'], + '\u{2F9AA}' => &['\u{8516}'], + '\u{2F9AB}' => &['\u{273CA}'], + '\u{2F9AC}' => &['\u{8564}'], + '\u{2F9AD}' => &['\u{26F2C}'], + '\u{2F9AE}' => &['\u{455D}'], + '\u{2F9AF}' => &['\u{4561}'], + '\u{2F9B0}' => &['\u{26FB1}'], + '\u{2F9B1}' => &['\u{270D2}'], + '\u{2F9B2}' => &['\u{456B}'], + '\u{2F9B3}' => &['\u{8650}'], + '\u{2F9B4}' => &['\u{865C}'], + '\u{2F9B5}' => &['\u{8667}'], + '\u{2F9B6}' => &['\u{8669}'], + '\u{2F9B7}' => &['\u{86A9}'], + '\u{2F9B8}' => &['\u{8688}'], + '\u{2F9B9}' => &['\u{870E}'], + '\u{2F9BA}' => &['\u{86E2}'], + '\u{2F9BB}' => &['\u{8779}'], + '\u{2F9BC}' => &['\u{8728}'], + '\u{2F9BD}' => &['\u{876B}'], + '\u{2F9BE}' => &['\u{8786}'], + '\u{2F9BF}' => &['\u{45D7}'], + '\u{2F9C0}' => &['\u{87E1}'], + '\u{2F9C1}' => &['\u{8801}'], + '\u{2F9C2}' => &['\u{45F9}'], + '\u{2F9C3}' => &['\u{8860}'], + '\u{2F9C4}' => &['\u{8863}'], + '\u{2F9C5}' => &['\u{27667}'], + '\u{2F9C6}' => &['\u{88D7}'], + '\u{2F9C7}' => &['\u{88DE}'], + '\u{2F9C8}' => &['\u{4635}'], + '\u{2F9C9}' => &['\u{88FA}'], + '\u{2F9CA}' => &['\u{34BB}'], + '\u{2F9CB}' => &['\u{278AE}'], + '\u{2F9CC}' => &['\u{27966}'], + '\u{2F9CD}' => &['\u{46BE}'], + '\u{2F9CE}' => &['\u{46C7}'], + '\u{2F9CF}' => &['\u{8AA0}'], + '\u{2F9D0}' => &['\u{8AED}'], + '\u{2F9D1}' => &['\u{8B8A}'], + '\u{2F9D2}' => &['\u{8C55}'], + '\u{2F9D3}' => &['\u{27CA8}'], + '\u{2F9D4}' => &['\u{8CAB}'], + '\u{2F9D5}' => &['\u{8CC1}'], + '\u{2F9D6}' => &['\u{8D1B}'], + '\u{2F9D7}' => &['\u{8D77}'], + '\u{2F9D8}' => &['\u{27F2F}'], + '\u{2F9D9}' => &['\u{20804}'], + '\u{2F9DA}' => &['\u{8DCB}'], + '\u{2F9DB}' => &['\u{8DBC}'], + '\u{2F9DC}' => &['\u{8DF0}'], + '\u{2F9DD}' => &['\u{208DE}'], + '\u{2F9DE}' => &['\u{8ED4}'], + '\u{2F9DF}' => &['\u{8F38}'], + '\u{2F9E0}' => &['\u{285D2}'], + '\u{2F9E1}' => &['\u{285ED}'], + '\u{2F9E2}' => &['\u{9094}'], + '\u{2F9E3}' => &['\u{90F1}'], + '\u{2F9E4}' => &['\u{9111}'], + '\u{2F9E5}' => &['\u{2872E}'], + '\u{2F9E6}' => &['\u{911B}'], + '\u{2F9E7}' => &['\u{9238}'], + '\u{2F9E8}' => &['\u{92D7}'], + '\u{2F9E9}' => &['\u{92D8}'], + '\u{2F9EA}' => &['\u{927C}'], + '\u{2F9EB}' => &['\u{93F9}'], + '\u{2F9EC}' => &['\u{9415}'], + '\u{2F9ED}' => &['\u{28BFA}'], + '\u{2F9EE}' => &['\u{958B}'], + '\u{2F9EF}' => &['\u{4995}'], + '\u{2F9F0}' => &['\u{95B7}'], + '\u{2F9F1}' => &['\u{28D77}'], + '\u{2F9F2}' => &['\u{49E6}'], + '\u{2F9F3}' => &['\u{96C3}'], + '\u{2F9F4}' => &['\u{5DB2}'], + '\u{2F9F5}' => &['\u{9723}'], + '\u{2F9F6}' => &['\u{29145}'], + '\u{2F9F7}' => &['\u{2921A}'], + '\u{2F9F8}' => &['\u{4A6E}'], + '\u{2F9F9}' => &['\u{4A76}'], + '\u{2F9FA}' => &['\u{97E0}'], + '\u{2F9FB}' => &['\u{2940A}'], + '\u{2F9FC}' => &['\u{4AB2}'], + '\u{2F9FD}' => &['\u{29496}'], + '\u{2F9FE}' => &['\u{980B}'], + '\u{2F9FF}' => &['\u{980B}'], + '\u{2FA00}' => &['\u{9829}'], + '\u{2FA01}' => &['\u{295B6}'], + '\u{2FA02}' => &['\u{98E2}'], + '\u{2FA03}' => &['\u{4B33}'], + '\u{2FA04}' => &['\u{9929}'], + '\u{2FA05}' => &['\u{99A7}'], + '\u{2FA06}' => &['\u{99C2}'], + '\u{2FA07}' => &['\u{99FE}'], + '\u{2FA08}' => &['\u{4BCE}'], + '\u{2FA09}' => &['\u{29B30}'], + '\u{2FA0A}' => &['\u{9B12}'], + '\u{2FA0B}' => &['\u{9C40}'], + '\u{2FA0C}' => &['\u{9CFD}'], + '\u{2FA0D}' => &['\u{4CCE}'], + '\u{2FA0E}' => &['\u{4CED}'], + '\u{2FA0F}' => &['\u{9D67}'], + '\u{2FA10}' => &['\u{2A0CE}'], + '\u{2FA11}' => &['\u{4CF8}'], + '\u{2FA12}' => &['\u{2A105}'], + '\u{2FA13}' => &['\u{2A20E}'], + '\u{2FA14}' => &['\u{2A291}'], + '\u{2FA15}' => &['\u{9EBB}'], + '\u{2FA16}' => &['\u{4D56}'], + '\u{2FA17}' => &['\u{9EF9}'], + '\u{2FA18}' => &['\u{9EFE}'], + '\u{2FA19}' => &['\u{9F05}'], + '\u{2FA1A}' => &['\u{9F0F}'], + '\u{2FA1B}' => &['\u{9F16}'], + '\u{2FA1C}' => &['\u{9F3B}'], + '\u{2FA1D}' => &['\u{2A600}'], + _ => return None, + }) +} + +#[inline] +pub fn compatibility_fully_decomposed(c: char) -> Option<&'static [char]> { + Some(match c { + '\u{00A0}' => &['\u{0020}'], + '\u{00A8}' => &['\u{0020}', '\u{0308}'], + '\u{00AA}' => &['\u{0061}'], + '\u{00AF}' => &['\u{0020}', '\u{0304}'], + '\u{00B2}' => &['\u{0032}'], + '\u{00B3}' => &['\u{0033}'], + '\u{00B4}' => &['\u{0020}', '\u{0301}'], + '\u{00B5}' => &['\u{03BC}'], + '\u{00B8}' => &['\u{0020}', '\u{0327}'], + '\u{00B9}' => &['\u{0031}'], + '\u{00BA}' => &['\u{006F}'], + '\u{00BC}' => &['\u{0031}', '\u{2044}', '\u{0034}'], + '\u{00BD}' => &['\u{0031}', '\u{2044}', '\u{0032}'], + '\u{00BE}' => &['\u{0033}', '\u{2044}', '\u{0034}'], + '\u{0132}' => &['\u{0049}', '\u{004A}'], + '\u{0133}' => &['\u{0069}', '\u{006A}'], + '\u{013F}' => &['\u{004C}', '\u{00B7}'], + '\u{0140}' => &['\u{006C}', '\u{00B7}'], + '\u{0149}' => &['\u{02BC}', '\u{006E}'], + '\u{017F}' => &['\u{0073}'], + '\u{01C4}' => &['\u{0044}', '\u{005A}', '\u{030C}'], + '\u{01C5}' => &['\u{0044}', '\u{007A}', '\u{030C}'], + '\u{01C6}' => &['\u{0064}', '\u{007A}', '\u{030C}'], + '\u{01C7}' => &['\u{004C}', '\u{004A}'], + '\u{01C8}' => &['\u{004C}', '\u{006A}'], + '\u{01C9}' => &['\u{006C}', '\u{006A}'], + '\u{01CA}' => &['\u{004E}', '\u{004A}'], + '\u{01CB}' => &['\u{004E}', '\u{006A}'], + '\u{01CC}' => &['\u{006E}', '\u{006A}'], + '\u{01F1}' => &['\u{0044}', '\u{005A}'], + '\u{01F2}' => &['\u{0044}', '\u{007A}'], + '\u{01F3}' => &['\u{0064}', '\u{007A}'], + '\u{02B0}' => &['\u{0068}'], + '\u{02B1}' => &['\u{0266}'], + '\u{02B2}' => &['\u{006A}'], + '\u{02B3}' => &['\u{0072}'], + '\u{02B4}' => &['\u{0279}'], + '\u{02B5}' => &['\u{027B}'], + '\u{02B6}' => &['\u{0281}'], + '\u{02B7}' => &['\u{0077}'], + '\u{02B8}' => &['\u{0079}'], + '\u{02D8}' => &['\u{0020}', '\u{0306}'], + '\u{02D9}' => &['\u{0020}', '\u{0307}'], + '\u{02DA}' => &['\u{0020}', '\u{030A}'], + '\u{02DB}' => &['\u{0020}', '\u{0328}'], + '\u{02DC}' => &['\u{0020}', '\u{0303}'], + '\u{02DD}' => &['\u{0020}', '\u{030B}'], + '\u{02E0}' => &['\u{0263}'], + '\u{02E1}' => &['\u{006C}'], + '\u{02E2}' => &['\u{0073}'], + '\u{02E3}' => &['\u{0078}'], + '\u{02E4}' => &['\u{0295}'], + '\u{037A}' => &['\u{0020}', '\u{0345}'], + '\u{0384}' => &['\u{0020}', '\u{0301}'], + '\u{0385}' => &['\u{0020}', '\u{0308}', '\u{0301}'], + '\u{03D0}' => &['\u{03B2}'], + '\u{03D1}' => &['\u{03B8}'], + '\u{03D2}' => &['\u{03A5}'], + '\u{03D3}' => &['\u{03A5}', '\u{0301}'], + '\u{03D4}' => &['\u{03A5}', '\u{0308}'], + '\u{03D5}' => &['\u{03C6}'], + '\u{03D6}' => &['\u{03C0}'], + '\u{03F0}' => &['\u{03BA}'], + '\u{03F1}' => &['\u{03C1}'], + '\u{03F2}' => &['\u{03C2}'], + '\u{03F4}' => &['\u{0398}'], + '\u{03F5}' => &['\u{03B5}'], + '\u{03F9}' => &['\u{03A3}'], + '\u{0587}' => &['\u{0565}', '\u{0582}'], + '\u{0675}' => &['\u{0627}', '\u{0674}'], + '\u{0676}' => &['\u{0648}', '\u{0674}'], + '\u{0677}' => &['\u{06C7}', '\u{0674}'], + '\u{0678}' => &['\u{064A}', '\u{0674}'], + '\u{0E33}' => &['\u{0E4D}', '\u{0E32}'], + '\u{0EB3}' => &['\u{0ECD}', '\u{0EB2}'], + '\u{0EDC}' => &['\u{0EAB}', '\u{0E99}'], + '\u{0EDD}' => &['\u{0EAB}', '\u{0EA1}'], + '\u{0F0C}' => &['\u{0F0B}'], + '\u{0F77}' => &['\u{0FB2}', '\u{0F71}', '\u{0F80}'], + '\u{0F79}' => &['\u{0FB3}', '\u{0F71}', '\u{0F80}'], + '\u{10FC}' => &['\u{10DC}'], + '\u{1D2C}' => &['\u{0041}'], + '\u{1D2D}' => &['\u{00C6}'], + '\u{1D2E}' => &['\u{0042}'], + '\u{1D30}' => &['\u{0044}'], + '\u{1D31}' => &['\u{0045}'], + '\u{1D32}' => &['\u{018E}'], + '\u{1D33}' => &['\u{0047}'], + '\u{1D34}' => &['\u{0048}'], + '\u{1D35}' => &['\u{0049}'], + '\u{1D36}' => &['\u{004A}'], + '\u{1D37}' => &['\u{004B}'], + '\u{1D38}' => &['\u{004C}'], + '\u{1D39}' => &['\u{004D}'], + '\u{1D3A}' => &['\u{004E}'], + '\u{1D3C}' => &['\u{004F}'], + '\u{1D3D}' => &['\u{0222}'], + '\u{1D3E}' => &['\u{0050}'], + '\u{1D3F}' => &['\u{0052}'], + '\u{1D40}' => &['\u{0054}'], + '\u{1D41}' => &['\u{0055}'], + '\u{1D42}' => &['\u{0057}'], + '\u{1D43}' => &['\u{0061}'], + '\u{1D44}' => &['\u{0250}'], + '\u{1D45}' => &['\u{0251}'], + '\u{1D46}' => &['\u{1D02}'], + '\u{1D47}' => &['\u{0062}'], + '\u{1D48}' => &['\u{0064}'], + '\u{1D49}' => &['\u{0065}'], + '\u{1D4A}' => &['\u{0259}'], + '\u{1D4B}' => &['\u{025B}'], + '\u{1D4C}' => &['\u{025C}'], + '\u{1D4D}' => &['\u{0067}'], + '\u{1D4F}' => &['\u{006B}'], + '\u{1D50}' => &['\u{006D}'], + '\u{1D51}' => &['\u{014B}'], + '\u{1D52}' => &['\u{006F}'], + '\u{1D53}' => &['\u{0254}'], + '\u{1D54}' => &['\u{1D16}'], + '\u{1D55}' => &['\u{1D17}'], + '\u{1D56}' => &['\u{0070}'], + '\u{1D57}' => &['\u{0074}'], + '\u{1D58}' => &['\u{0075}'], + '\u{1D59}' => &['\u{1D1D}'], + '\u{1D5A}' => &['\u{026F}'], + '\u{1D5B}' => &['\u{0076}'], + '\u{1D5C}' => &['\u{1D25}'], + '\u{1D5D}' => &['\u{03B2}'], + '\u{1D5E}' => &['\u{03B3}'], + '\u{1D5F}' => &['\u{03B4}'], + '\u{1D60}' => &['\u{03C6}'], + '\u{1D61}' => &['\u{03C7}'], + '\u{1D62}' => &['\u{0069}'], + '\u{1D63}' => &['\u{0072}'], + '\u{1D64}' => &['\u{0075}'], + '\u{1D65}' => &['\u{0076}'], + '\u{1D66}' => &['\u{03B2}'], + '\u{1D67}' => &['\u{03B3}'], + '\u{1D68}' => &['\u{03C1}'], + '\u{1D69}' => &['\u{03C6}'], + '\u{1D6A}' => &['\u{03C7}'], + '\u{1D78}' => &['\u{043D}'], + '\u{1D9B}' => &['\u{0252}'], + '\u{1D9C}' => &['\u{0063}'], + '\u{1D9D}' => &['\u{0255}'], + '\u{1D9E}' => &['\u{00F0}'], + '\u{1D9F}' => &['\u{025C}'], + '\u{1DA0}' => &['\u{0066}'], + '\u{1DA1}' => &['\u{025F}'], + '\u{1DA2}' => &['\u{0261}'], + '\u{1DA3}' => &['\u{0265}'], + '\u{1DA4}' => &['\u{0268}'], + '\u{1DA5}' => &['\u{0269}'], + '\u{1DA6}' => &['\u{026A}'], + '\u{1DA7}' => &['\u{1D7B}'], + '\u{1DA8}' => &['\u{029D}'], + '\u{1DA9}' => &['\u{026D}'], + '\u{1DAA}' => &['\u{1D85}'], + '\u{1DAB}' => &['\u{029F}'], + '\u{1DAC}' => &['\u{0271}'], + '\u{1DAD}' => &['\u{0270}'], + '\u{1DAE}' => &['\u{0272}'], + '\u{1DAF}' => &['\u{0273}'], + '\u{1DB0}' => &['\u{0274}'], + '\u{1DB1}' => &['\u{0275}'], + '\u{1DB2}' => &['\u{0278}'], + '\u{1DB3}' => &['\u{0282}'], + '\u{1DB4}' => &['\u{0283}'], + '\u{1DB5}' => &['\u{01AB}'], + '\u{1DB6}' => &['\u{0289}'], + '\u{1DB7}' => &['\u{028A}'], + '\u{1DB8}' => &['\u{1D1C}'], + '\u{1DB9}' => &['\u{028B}'], + '\u{1DBA}' => &['\u{028C}'], + '\u{1DBB}' => &['\u{007A}'], + '\u{1DBC}' => &['\u{0290}'], + '\u{1DBD}' => &['\u{0291}'], + '\u{1DBE}' => &['\u{0292}'], + '\u{1DBF}' => &['\u{03B8}'], + '\u{1E9A}' => &['\u{0061}', '\u{02BE}'], + '\u{1E9B}' => &['\u{0073}', '\u{0307}'], + '\u{1FBD}' => &['\u{0020}', '\u{0313}'], + '\u{1FBF}' => &['\u{0020}', '\u{0313}'], + '\u{1FC0}' => &['\u{0020}', '\u{0342}'], + '\u{1FC1}' => &['\u{0020}', '\u{0308}', '\u{0342}'], + '\u{1FCD}' => &['\u{0020}', '\u{0313}', '\u{0300}'], + '\u{1FCE}' => &['\u{0020}', '\u{0313}', '\u{0301}'], + '\u{1FCF}' => &['\u{0020}', '\u{0313}', '\u{0342}'], + '\u{1FDD}' => &['\u{0020}', '\u{0314}', '\u{0300}'], + '\u{1FDE}' => &['\u{0020}', '\u{0314}', '\u{0301}'], + '\u{1FDF}' => &['\u{0020}', '\u{0314}', '\u{0342}'], + '\u{1FED}' => &['\u{0020}', '\u{0308}', '\u{0300}'], + '\u{1FEE}' => &['\u{0020}', '\u{0308}', '\u{0301}'], + '\u{1FFD}' => &['\u{0020}', '\u{0301}'], + '\u{1FFE}' => &['\u{0020}', '\u{0314}'], + '\u{2000}' => &['\u{0020}'], + '\u{2001}' => &['\u{0020}'], + '\u{2002}' => &['\u{0020}'], + '\u{2003}' => &['\u{0020}'], + '\u{2004}' => &['\u{0020}'], + '\u{2005}' => &['\u{0020}'], + '\u{2006}' => &['\u{0020}'], + '\u{2007}' => &['\u{0020}'], + '\u{2008}' => &['\u{0020}'], + '\u{2009}' => &['\u{0020}'], + '\u{200A}' => &['\u{0020}'], + '\u{2011}' => &['\u{2010}'], + '\u{2017}' => &['\u{0020}', '\u{0333}'], + '\u{2024}' => &['\u{002E}'], + '\u{2025}' => &['\u{002E}', '\u{002E}'], + '\u{2026}' => &['\u{002E}', '\u{002E}', '\u{002E}'], + '\u{202F}' => &['\u{0020}'], + '\u{2033}' => &['\u{2032}', '\u{2032}'], + '\u{2034}' => &['\u{2032}', '\u{2032}', '\u{2032}'], + '\u{2036}' => &['\u{2035}', '\u{2035}'], + '\u{2037}' => &['\u{2035}', '\u{2035}', '\u{2035}'], + '\u{203C}' => &['\u{0021}', '\u{0021}'], + '\u{203E}' => &['\u{0020}', '\u{0305}'], + '\u{2047}' => &['\u{003F}', '\u{003F}'], + '\u{2048}' => &['\u{003F}', '\u{0021}'], + '\u{2049}' => &['\u{0021}', '\u{003F}'], + '\u{2057}' => &['\u{2032}', '\u{2032}', '\u{2032}', '\u{2032}'], + '\u{205F}' => &['\u{0020}'], + '\u{2070}' => &['\u{0030}'], + '\u{2071}' => &['\u{0069}'], + '\u{2074}' => &['\u{0034}'], + '\u{2075}' => &['\u{0035}'], + '\u{2076}' => &['\u{0036}'], + '\u{2077}' => &['\u{0037}'], + '\u{2078}' => &['\u{0038}'], + '\u{2079}' => &['\u{0039}'], + '\u{207A}' => &['\u{002B}'], + '\u{207B}' => &['\u{2212}'], + '\u{207C}' => &['\u{003D}'], + '\u{207D}' => &['\u{0028}'], + '\u{207E}' => &['\u{0029}'], + '\u{207F}' => &['\u{006E}'], + '\u{2080}' => &['\u{0030}'], + '\u{2081}' => &['\u{0031}'], + '\u{2082}' => &['\u{0032}'], + '\u{2083}' => &['\u{0033}'], + '\u{2084}' => &['\u{0034}'], + '\u{2085}' => &['\u{0035}'], + '\u{2086}' => &['\u{0036}'], + '\u{2087}' => &['\u{0037}'], + '\u{2088}' => &['\u{0038}'], + '\u{2089}' => &['\u{0039}'], + '\u{208A}' => &['\u{002B}'], + '\u{208B}' => &['\u{2212}'], + '\u{208C}' => &['\u{003D}'], + '\u{208D}' => &['\u{0028}'], + '\u{208E}' => &['\u{0029}'], + '\u{2090}' => &['\u{0061}'], + '\u{2091}' => &['\u{0065}'], + '\u{2092}' => &['\u{006F}'], + '\u{2093}' => &['\u{0078}'], + '\u{2094}' => &['\u{0259}'], + '\u{2095}' => &['\u{0068}'], + '\u{2096}' => &['\u{006B}'], + '\u{2097}' => &['\u{006C}'], + '\u{2098}' => &['\u{006D}'], + '\u{2099}' => &['\u{006E}'], + '\u{209A}' => &['\u{0070}'], + '\u{209B}' => &['\u{0073}'], + '\u{209C}' => &['\u{0074}'], + '\u{20A8}' => &['\u{0052}', '\u{0073}'], + '\u{2100}' => &['\u{0061}', '\u{002F}', '\u{0063}'], + '\u{2101}' => &['\u{0061}', '\u{002F}', '\u{0073}'], + '\u{2102}' => &['\u{0043}'], + '\u{2103}' => &['\u{00B0}', '\u{0043}'], + '\u{2105}' => &['\u{0063}', '\u{002F}', '\u{006F}'], + '\u{2106}' => &['\u{0063}', '\u{002F}', '\u{0075}'], + '\u{2107}' => &['\u{0190}'], + '\u{2109}' => &['\u{00B0}', '\u{0046}'], + '\u{210A}' => &['\u{0067}'], + '\u{210B}' => &['\u{0048}'], + '\u{210C}' => &['\u{0048}'], + '\u{210D}' => &['\u{0048}'], + '\u{210E}' => &['\u{0068}'], + '\u{210F}' => &['\u{0127}'], + '\u{2110}' => &['\u{0049}'], + '\u{2111}' => &['\u{0049}'], + '\u{2112}' => &['\u{004C}'], + '\u{2113}' => &['\u{006C}'], + '\u{2115}' => &['\u{004E}'], + '\u{2116}' => &['\u{004E}', '\u{006F}'], + '\u{2119}' => &['\u{0050}'], + '\u{211A}' => &['\u{0051}'], + '\u{211B}' => &['\u{0052}'], + '\u{211C}' => &['\u{0052}'], + '\u{211D}' => &['\u{0052}'], + '\u{2120}' => &['\u{0053}', '\u{004D}'], + '\u{2121}' => &['\u{0054}', '\u{0045}', '\u{004C}'], + '\u{2122}' => &['\u{0054}', '\u{004D}'], + '\u{2124}' => &['\u{005A}'], + '\u{2128}' => &['\u{005A}'], + '\u{212C}' => &['\u{0042}'], + '\u{212D}' => &['\u{0043}'], + '\u{212F}' => &['\u{0065}'], + '\u{2130}' => &['\u{0045}'], + '\u{2131}' => &['\u{0046}'], + '\u{2133}' => &['\u{004D}'], + '\u{2134}' => &['\u{006F}'], + '\u{2135}' => &['\u{05D0}'], + '\u{2136}' => &['\u{05D1}'], + '\u{2137}' => &['\u{05D2}'], + '\u{2138}' => &['\u{05D3}'], + '\u{2139}' => &['\u{0069}'], + '\u{213B}' => &['\u{0046}', '\u{0041}', '\u{0058}'], + '\u{213C}' => &['\u{03C0}'], + '\u{213D}' => &['\u{03B3}'], + '\u{213E}' => &['\u{0393}'], + '\u{213F}' => &['\u{03A0}'], + '\u{2140}' => &['\u{2211}'], + '\u{2145}' => &['\u{0044}'], + '\u{2146}' => &['\u{0064}'], + '\u{2147}' => &['\u{0065}'], + '\u{2148}' => &['\u{0069}'], + '\u{2149}' => &['\u{006A}'], + '\u{2150}' => &['\u{0031}', '\u{2044}', '\u{0037}'], + '\u{2151}' => &['\u{0031}', '\u{2044}', '\u{0039}'], + '\u{2152}' => &['\u{0031}', '\u{2044}', '\u{0031}', '\u{0030}'], + '\u{2153}' => &['\u{0031}', '\u{2044}', '\u{0033}'], + '\u{2154}' => &['\u{0032}', '\u{2044}', '\u{0033}'], + '\u{2155}' => &['\u{0031}', '\u{2044}', '\u{0035}'], + '\u{2156}' => &['\u{0032}', '\u{2044}', '\u{0035}'], + '\u{2157}' => &['\u{0033}', '\u{2044}', '\u{0035}'], + '\u{2158}' => &['\u{0034}', '\u{2044}', '\u{0035}'], + '\u{2159}' => &['\u{0031}', '\u{2044}', '\u{0036}'], + '\u{215A}' => &['\u{0035}', '\u{2044}', '\u{0036}'], + '\u{215B}' => &['\u{0031}', '\u{2044}', '\u{0038}'], + '\u{215C}' => &['\u{0033}', '\u{2044}', '\u{0038}'], + '\u{215D}' => &['\u{0035}', '\u{2044}', '\u{0038}'], + '\u{215E}' => &['\u{0037}', '\u{2044}', '\u{0038}'], + '\u{215F}' => &['\u{0031}', '\u{2044}'], + '\u{2160}' => &['\u{0049}'], + '\u{2161}' => &['\u{0049}', '\u{0049}'], + '\u{2162}' => &['\u{0049}', '\u{0049}', '\u{0049}'], + '\u{2163}' => &['\u{0049}', '\u{0056}'], + '\u{2164}' => &['\u{0056}'], + '\u{2165}' => &['\u{0056}', '\u{0049}'], + '\u{2166}' => &['\u{0056}', '\u{0049}', '\u{0049}'], + '\u{2167}' => &['\u{0056}', '\u{0049}', '\u{0049}', '\u{0049}'], + '\u{2168}' => &['\u{0049}', '\u{0058}'], + '\u{2169}' => &['\u{0058}'], + '\u{216A}' => &['\u{0058}', '\u{0049}'], + '\u{216B}' => &['\u{0058}', '\u{0049}', '\u{0049}'], + '\u{216C}' => &['\u{004C}'], + '\u{216D}' => &['\u{0043}'], + '\u{216E}' => &['\u{0044}'], + '\u{216F}' => &['\u{004D}'], + '\u{2170}' => &['\u{0069}'], + '\u{2171}' => &['\u{0069}', '\u{0069}'], + '\u{2172}' => &['\u{0069}', '\u{0069}', '\u{0069}'], + '\u{2173}' => &['\u{0069}', '\u{0076}'], + '\u{2174}' => &['\u{0076}'], + '\u{2175}' => &['\u{0076}', '\u{0069}'], + '\u{2176}' => &['\u{0076}', '\u{0069}', '\u{0069}'], + '\u{2177}' => &['\u{0076}', '\u{0069}', '\u{0069}', '\u{0069}'], + '\u{2178}' => &['\u{0069}', '\u{0078}'], + '\u{2179}' => &['\u{0078}'], + '\u{217A}' => &['\u{0078}', '\u{0069}'], + '\u{217B}' => &['\u{0078}', '\u{0069}', '\u{0069}'], + '\u{217C}' => &['\u{006C}'], + '\u{217D}' => &['\u{0063}'], + '\u{217E}' => &['\u{0064}'], + '\u{217F}' => &['\u{006D}'], + '\u{2189}' => &['\u{0030}', '\u{2044}', '\u{0033}'], + '\u{222C}' => &['\u{222B}', '\u{222B}'], + '\u{222D}' => &['\u{222B}', '\u{222B}', '\u{222B}'], + '\u{222F}' => &['\u{222E}', '\u{222E}'], + '\u{2230}' => &['\u{222E}', '\u{222E}', '\u{222E}'], + '\u{2460}' => &['\u{0031}'], + '\u{2461}' => &['\u{0032}'], + '\u{2462}' => &['\u{0033}'], + '\u{2463}' => &['\u{0034}'], + '\u{2464}' => &['\u{0035}'], + '\u{2465}' => &['\u{0036}'], + '\u{2466}' => &['\u{0037}'], + '\u{2467}' => &['\u{0038}'], + '\u{2468}' => &['\u{0039}'], + '\u{2469}' => &['\u{0031}', '\u{0030}'], + '\u{246A}' => &['\u{0031}', '\u{0031}'], + '\u{246B}' => &['\u{0031}', '\u{0032}'], + '\u{246C}' => &['\u{0031}', '\u{0033}'], + '\u{246D}' => &['\u{0031}', '\u{0034}'], + '\u{246E}' => &['\u{0031}', '\u{0035}'], + '\u{246F}' => &['\u{0031}', '\u{0036}'], + '\u{2470}' => &['\u{0031}', '\u{0037}'], + '\u{2471}' => &['\u{0031}', '\u{0038}'], + '\u{2472}' => &['\u{0031}', '\u{0039}'], + '\u{2473}' => &['\u{0032}', '\u{0030}'], + '\u{2474}' => &['\u{0028}', '\u{0031}', '\u{0029}'], + '\u{2475}' => &['\u{0028}', '\u{0032}', '\u{0029}'], + '\u{2476}' => &['\u{0028}', '\u{0033}', '\u{0029}'], + '\u{2477}' => &['\u{0028}', '\u{0034}', '\u{0029}'], + '\u{2478}' => &['\u{0028}', '\u{0035}', '\u{0029}'], + '\u{2479}' => &['\u{0028}', '\u{0036}', '\u{0029}'], + '\u{247A}' => &['\u{0028}', '\u{0037}', '\u{0029}'], + '\u{247B}' => &['\u{0028}', '\u{0038}', '\u{0029}'], + '\u{247C}' => &['\u{0028}', '\u{0039}', '\u{0029}'], + '\u{247D}' => &['\u{0028}', '\u{0031}', '\u{0030}', '\u{0029}'], + '\u{247E}' => &['\u{0028}', '\u{0031}', '\u{0031}', '\u{0029}'], + '\u{247F}' => &['\u{0028}', '\u{0031}', '\u{0032}', '\u{0029}'], + '\u{2480}' => &['\u{0028}', '\u{0031}', '\u{0033}', '\u{0029}'], + '\u{2481}' => &['\u{0028}', '\u{0031}', '\u{0034}', '\u{0029}'], + '\u{2482}' => &['\u{0028}', '\u{0031}', '\u{0035}', '\u{0029}'], + '\u{2483}' => &['\u{0028}', '\u{0031}', '\u{0036}', '\u{0029}'], + '\u{2484}' => &['\u{0028}', '\u{0031}', '\u{0037}', '\u{0029}'], + '\u{2485}' => &['\u{0028}', '\u{0031}', '\u{0038}', '\u{0029}'], + '\u{2486}' => &['\u{0028}', '\u{0031}', '\u{0039}', '\u{0029}'], + '\u{2487}' => &['\u{0028}', '\u{0032}', '\u{0030}', '\u{0029}'], + '\u{2488}' => &['\u{0031}', '\u{002E}'], + '\u{2489}' => &['\u{0032}', '\u{002E}'], + '\u{248A}' => &['\u{0033}', '\u{002E}'], + '\u{248B}' => &['\u{0034}', '\u{002E}'], + '\u{248C}' => &['\u{0035}', '\u{002E}'], + '\u{248D}' => &['\u{0036}', '\u{002E}'], + '\u{248E}' => &['\u{0037}', '\u{002E}'], + '\u{248F}' => &['\u{0038}', '\u{002E}'], + '\u{2490}' => &['\u{0039}', '\u{002E}'], + '\u{2491}' => &['\u{0031}', '\u{0030}', '\u{002E}'], + '\u{2492}' => &['\u{0031}', '\u{0031}', '\u{002E}'], + '\u{2493}' => &['\u{0031}', '\u{0032}', '\u{002E}'], + '\u{2494}' => &['\u{0031}', '\u{0033}', '\u{002E}'], + '\u{2495}' => &['\u{0031}', '\u{0034}', '\u{002E}'], + '\u{2496}' => &['\u{0031}', '\u{0035}', '\u{002E}'], + '\u{2497}' => &['\u{0031}', '\u{0036}', '\u{002E}'], + '\u{2498}' => &['\u{0031}', '\u{0037}', '\u{002E}'], + '\u{2499}' => &['\u{0031}', '\u{0038}', '\u{002E}'], + '\u{249A}' => &['\u{0031}', '\u{0039}', '\u{002E}'], + '\u{249B}' => &['\u{0032}', '\u{0030}', '\u{002E}'], + '\u{249C}' => &['\u{0028}', '\u{0061}', '\u{0029}'], + '\u{249D}' => &['\u{0028}', '\u{0062}', '\u{0029}'], + '\u{249E}' => &['\u{0028}', '\u{0063}', '\u{0029}'], + '\u{249F}' => &['\u{0028}', '\u{0064}', '\u{0029}'], + '\u{24A0}' => &['\u{0028}', '\u{0065}', '\u{0029}'], + '\u{24A1}' => &['\u{0028}', '\u{0066}', '\u{0029}'], + '\u{24A2}' => &['\u{0028}', '\u{0067}', '\u{0029}'], + '\u{24A3}' => &['\u{0028}', '\u{0068}', '\u{0029}'], + '\u{24A4}' => &['\u{0028}', '\u{0069}', '\u{0029}'], + '\u{24A5}' => &['\u{0028}', '\u{006A}', '\u{0029}'], + '\u{24A6}' => &['\u{0028}', '\u{006B}', '\u{0029}'], + '\u{24A7}' => &['\u{0028}', '\u{006C}', '\u{0029}'], + '\u{24A8}' => &['\u{0028}', '\u{006D}', '\u{0029}'], + '\u{24A9}' => &['\u{0028}', '\u{006E}', '\u{0029}'], + '\u{24AA}' => &['\u{0028}', '\u{006F}', '\u{0029}'], + '\u{24AB}' => &['\u{0028}', '\u{0070}', '\u{0029}'], + '\u{24AC}' => &['\u{0028}', '\u{0071}', '\u{0029}'], + '\u{24AD}' => &['\u{0028}', '\u{0072}', '\u{0029}'], + '\u{24AE}' => &['\u{0028}', '\u{0073}', '\u{0029}'], + '\u{24AF}' => &['\u{0028}', '\u{0074}', '\u{0029}'], + '\u{24B0}' => &['\u{0028}', '\u{0075}', '\u{0029}'], + '\u{24B1}' => &['\u{0028}', '\u{0076}', '\u{0029}'], + '\u{24B2}' => &['\u{0028}', '\u{0077}', '\u{0029}'], + '\u{24B3}' => &['\u{0028}', '\u{0078}', '\u{0029}'], + '\u{24B4}' => &['\u{0028}', '\u{0079}', '\u{0029}'], + '\u{24B5}' => &['\u{0028}', '\u{007A}', '\u{0029}'], + '\u{24B6}' => &['\u{0041}'], + '\u{24B7}' => &['\u{0042}'], + '\u{24B8}' => &['\u{0043}'], + '\u{24B9}' => &['\u{0044}'], + '\u{24BA}' => &['\u{0045}'], + '\u{24BB}' => &['\u{0046}'], + '\u{24BC}' => &['\u{0047}'], + '\u{24BD}' => &['\u{0048}'], + '\u{24BE}' => &['\u{0049}'], + '\u{24BF}' => &['\u{004A}'], + '\u{24C0}' => &['\u{004B}'], + '\u{24C1}' => &['\u{004C}'], + '\u{24C2}' => &['\u{004D}'], + '\u{24C3}' => &['\u{004E}'], + '\u{24C4}' => &['\u{004F}'], + '\u{24C5}' => &['\u{0050}'], + '\u{24C6}' => &['\u{0051}'], + '\u{24C7}' => &['\u{0052}'], + '\u{24C8}' => &['\u{0053}'], + '\u{24C9}' => &['\u{0054}'], + '\u{24CA}' => &['\u{0055}'], + '\u{24CB}' => &['\u{0056}'], + '\u{24CC}' => &['\u{0057}'], + '\u{24CD}' => &['\u{0058}'], + '\u{24CE}' => &['\u{0059}'], + '\u{24CF}' => &['\u{005A}'], + '\u{24D0}' => &['\u{0061}'], + '\u{24D1}' => &['\u{0062}'], + '\u{24D2}' => &['\u{0063}'], + '\u{24D3}' => &['\u{0064}'], + '\u{24D4}' => &['\u{0065}'], + '\u{24D5}' => &['\u{0066}'], + '\u{24D6}' => &['\u{0067}'], + '\u{24D7}' => &['\u{0068}'], + '\u{24D8}' => &['\u{0069}'], + '\u{24D9}' => &['\u{006A}'], + '\u{24DA}' => &['\u{006B}'], + '\u{24DB}' => &['\u{006C}'], + '\u{24DC}' => &['\u{006D}'], + '\u{24DD}' => &['\u{006E}'], + '\u{24DE}' => &['\u{006F}'], + '\u{24DF}' => &['\u{0070}'], + '\u{24E0}' => &['\u{0071}'], + '\u{24E1}' => &['\u{0072}'], + '\u{24E2}' => &['\u{0073}'], + '\u{24E3}' => &['\u{0074}'], + '\u{24E4}' => &['\u{0075}'], + '\u{24E5}' => &['\u{0076}'], + '\u{24E6}' => &['\u{0077}'], + '\u{24E7}' => &['\u{0078}'], + '\u{24E8}' => &['\u{0079}'], + '\u{24E9}' => &['\u{007A}'], + '\u{24EA}' => &['\u{0030}'], + '\u{2A0C}' => &['\u{222B}', '\u{222B}', '\u{222B}', '\u{222B}'], + '\u{2A74}' => &['\u{003A}', '\u{003A}', '\u{003D}'], + '\u{2A75}' => &['\u{003D}', '\u{003D}'], + '\u{2A76}' => &['\u{003D}', '\u{003D}', '\u{003D}'], + '\u{2C7C}' => &['\u{006A}'], + '\u{2C7D}' => &['\u{0056}'], + '\u{2D6F}' => &['\u{2D61}'], + '\u{2E9F}' => &['\u{6BCD}'], + '\u{2EF3}' => &['\u{9F9F}'], + '\u{2F00}' => &['\u{4E00}'], + '\u{2F01}' => &['\u{4E28}'], + '\u{2F02}' => &['\u{4E36}'], + '\u{2F03}' => &['\u{4E3F}'], + '\u{2F04}' => &['\u{4E59}'], + '\u{2F05}' => &['\u{4E85}'], + '\u{2F06}' => &['\u{4E8C}'], + '\u{2F07}' => &['\u{4EA0}'], + '\u{2F08}' => &['\u{4EBA}'], + '\u{2F09}' => &['\u{513F}'], + '\u{2F0A}' => &['\u{5165}'], + '\u{2F0B}' => &['\u{516B}'], + '\u{2F0C}' => &['\u{5182}'], + '\u{2F0D}' => &['\u{5196}'], + '\u{2F0E}' => &['\u{51AB}'], + '\u{2F0F}' => &['\u{51E0}'], + '\u{2F10}' => &['\u{51F5}'], + '\u{2F11}' => &['\u{5200}'], + '\u{2F12}' => &['\u{529B}'], + '\u{2F13}' => &['\u{52F9}'], + '\u{2F14}' => &['\u{5315}'], + '\u{2F15}' => &['\u{531A}'], + '\u{2F16}' => &['\u{5338}'], + '\u{2F17}' => &['\u{5341}'], + '\u{2F18}' => &['\u{535C}'], + '\u{2F19}' => &['\u{5369}'], + '\u{2F1A}' => &['\u{5382}'], + '\u{2F1B}' => &['\u{53B6}'], + '\u{2F1C}' => &['\u{53C8}'], + '\u{2F1D}' => &['\u{53E3}'], + '\u{2F1E}' => &['\u{56D7}'], + '\u{2F1F}' => &['\u{571F}'], + '\u{2F20}' => &['\u{58EB}'], + '\u{2F21}' => &['\u{5902}'], + '\u{2F22}' => &['\u{590A}'], + '\u{2F23}' => &['\u{5915}'], + '\u{2F24}' => &['\u{5927}'], + '\u{2F25}' => &['\u{5973}'], + '\u{2F26}' => &['\u{5B50}'], + '\u{2F27}' => &['\u{5B80}'], + '\u{2F28}' => &['\u{5BF8}'], + '\u{2F29}' => &['\u{5C0F}'], + '\u{2F2A}' => &['\u{5C22}'], + '\u{2F2B}' => &['\u{5C38}'], + '\u{2F2C}' => &['\u{5C6E}'], + '\u{2F2D}' => &['\u{5C71}'], + '\u{2F2E}' => &['\u{5DDB}'], + '\u{2F2F}' => &['\u{5DE5}'], + '\u{2F30}' => &['\u{5DF1}'], + '\u{2F31}' => &['\u{5DFE}'], + '\u{2F32}' => &['\u{5E72}'], + '\u{2F33}' => &['\u{5E7A}'], + '\u{2F34}' => &['\u{5E7F}'], + '\u{2F35}' => &['\u{5EF4}'], + '\u{2F36}' => &['\u{5EFE}'], + '\u{2F37}' => &['\u{5F0B}'], + '\u{2F38}' => &['\u{5F13}'], + '\u{2F39}' => &['\u{5F50}'], + '\u{2F3A}' => &['\u{5F61}'], + '\u{2F3B}' => &['\u{5F73}'], + '\u{2F3C}' => &['\u{5FC3}'], + '\u{2F3D}' => &['\u{6208}'], + '\u{2F3E}' => &['\u{6236}'], + '\u{2F3F}' => &['\u{624B}'], + '\u{2F40}' => &['\u{652F}'], + '\u{2F41}' => &['\u{6534}'], + '\u{2F42}' => &['\u{6587}'], + '\u{2F43}' => &['\u{6597}'], + '\u{2F44}' => &['\u{65A4}'], + '\u{2F45}' => &['\u{65B9}'], + '\u{2F46}' => &['\u{65E0}'], + '\u{2F47}' => &['\u{65E5}'], + '\u{2F48}' => &['\u{66F0}'], + '\u{2F49}' => &['\u{6708}'], + '\u{2F4A}' => &['\u{6728}'], + '\u{2F4B}' => &['\u{6B20}'], + '\u{2F4C}' => &['\u{6B62}'], + '\u{2F4D}' => &['\u{6B79}'], + '\u{2F4E}' => &['\u{6BB3}'], + '\u{2F4F}' => &['\u{6BCB}'], + '\u{2F50}' => &['\u{6BD4}'], + '\u{2F51}' => &['\u{6BDB}'], + '\u{2F52}' => &['\u{6C0F}'], + '\u{2F53}' => &['\u{6C14}'], + '\u{2F54}' => &['\u{6C34}'], + '\u{2F55}' => &['\u{706B}'], + '\u{2F56}' => &['\u{722A}'], + '\u{2F57}' => &['\u{7236}'], + '\u{2F58}' => &['\u{723B}'], + '\u{2F59}' => &['\u{723F}'], + '\u{2F5A}' => &['\u{7247}'], + '\u{2F5B}' => &['\u{7259}'], + '\u{2F5C}' => &['\u{725B}'], + '\u{2F5D}' => &['\u{72AC}'], + '\u{2F5E}' => &['\u{7384}'], + '\u{2F5F}' => &['\u{7389}'], + '\u{2F60}' => &['\u{74DC}'], + '\u{2F61}' => &['\u{74E6}'], + '\u{2F62}' => &['\u{7518}'], + '\u{2F63}' => &['\u{751F}'], + '\u{2F64}' => &['\u{7528}'], + '\u{2F65}' => &['\u{7530}'], + '\u{2F66}' => &['\u{758B}'], + '\u{2F67}' => &['\u{7592}'], + '\u{2F68}' => &['\u{7676}'], + '\u{2F69}' => &['\u{767D}'], + '\u{2F6A}' => &['\u{76AE}'], + '\u{2F6B}' => &['\u{76BF}'], + '\u{2F6C}' => &['\u{76EE}'], + '\u{2F6D}' => &['\u{77DB}'], + '\u{2F6E}' => &['\u{77E2}'], + '\u{2F6F}' => &['\u{77F3}'], + '\u{2F70}' => &['\u{793A}'], + '\u{2F71}' => &['\u{79B8}'], + '\u{2F72}' => &['\u{79BE}'], + '\u{2F73}' => &['\u{7A74}'], + '\u{2F74}' => &['\u{7ACB}'], + '\u{2F75}' => &['\u{7AF9}'], + '\u{2F76}' => &['\u{7C73}'], + '\u{2F77}' => &['\u{7CF8}'], + '\u{2F78}' => &['\u{7F36}'], + '\u{2F79}' => &['\u{7F51}'], + '\u{2F7A}' => &['\u{7F8A}'], + '\u{2F7B}' => &['\u{7FBD}'], + '\u{2F7C}' => &['\u{8001}'], + '\u{2F7D}' => &['\u{800C}'], + '\u{2F7E}' => &['\u{8012}'], + '\u{2F7F}' => &['\u{8033}'], + '\u{2F80}' => &['\u{807F}'], + '\u{2F81}' => &['\u{8089}'], + '\u{2F82}' => &['\u{81E3}'], + '\u{2F83}' => &['\u{81EA}'], + '\u{2F84}' => &['\u{81F3}'], + '\u{2F85}' => &['\u{81FC}'], + '\u{2F86}' => &['\u{820C}'], + '\u{2F87}' => &['\u{821B}'], + '\u{2F88}' => &['\u{821F}'], + '\u{2F89}' => &['\u{826E}'], + '\u{2F8A}' => &['\u{8272}'], + '\u{2F8B}' => &['\u{8278}'], + '\u{2F8C}' => &['\u{864D}'], + '\u{2F8D}' => &['\u{866B}'], + '\u{2F8E}' => &['\u{8840}'], + '\u{2F8F}' => &['\u{884C}'], + '\u{2F90}' => &['\u{8863}'], + '\u{2F91}' => &['\u{897E}'], + '\u{2F92}' => &['\u{898B}'], + '\u{2F93}' => &['\u{89D2}'], + '\u{2F94}' => &['\u{8A00}'], + '\u{2F95}' => &['\u{8C37}'], + '\u{2F96}' => &['\u{8C46}'], + '\u{2F97}' => &['\u{8C55}'], + '\u{2F98}' => &['\u{8C78}'], + '\u{2F99}' => &['\u{8C9D}'], + '\u{2F9A}' => &['\u{8D64}'], + '\u{2F9B}' => &['\u{8D70}'], + '\u{2F9C}' => &['\u{8DB3}'], + '\u{2F9D}' => &['\u{8EAB}'], + '\u{2F9E}' => &['\u{8ECA}'], + '\u{2F9F}' => &['\u{8F9B}'], + '\u{2FA0}' => &['\u{8FB0}'], + '\u{2FA1}' => &['\u{8FB5}'], + '\u{2FA2}' => &['\u{9091}'], + '\u{2FA3}' => &['\u{9149}'], + '\u{2FA4}' => &['\u{91C6}'], + '\u{2FA5}' => &['\u{91CC}'], + '\u{2FA6}' => &['\u{91D1}'], + '\u{2FA7}' => &['\u{9577}'], + '\u{2FA8}' => &['\u{9580}'], + '\u{2FA9}' => &['\u{961C}'], + '\u{2FAA}' => &['\u{96B6}'], + '\u{2FAB}' => &['\u{96B9}'], + '\u{2FAC}' => &['\u{96E8}'], + '\u{2FAD}' => &['\u{9751}'], + '\u{2FAE}' => &['\u{975E}'], + '\u{2FAF}' => &['\u{9762}'], + '\u{2FB0}' => &['\u{9769}'], + '\u{2FB1}' => &['\u{97CB}'], + '\u{2FB2}' => &['\u{97ED}'], + '\u{2FB3}' => &['\u{97F3}'], + '\u{2FB4}' => &['\u{9801}'], + '\u{2FB5}' => &['\u{98A8}'], + '\u{2FB6}' => &['\u{98DB}'], + '\u{2FB7}' => &['\u{98DF}'], + '\u{2FB8}' => &['\u{9996}'], + '\u{2FB9}' => &['\u{9999}'], + '\u{2FBA}' => &['\u{99AC}'], + '\u{2FBB}' => &['\u{9AA8}'], + '\u{2FBC}' => &['\u{9AD8}'], + '\u{2FBD}' => &['\u{9ADF}'], + '\u{2FBE}' => &['\u{9B25}'], + '\u{2FBF}' => &['\u{9B2F}'], + '\u{2FC0}' => &['\u{9B32}'], + '\u{2FC1}' => &['\u{9B3C}'], + '\u{2FC2}' => &['\u{9B5A}'], + '\u{2FC3}' => &['\u{9CE5}'], + '\u{2FC4}' => &['\u{9E75}'], + '\u{2FC5}' => &['\u{9E7F}'], + '\u{2FC6}' => &['\u{9EA5}'], + '\u{2FC7}' => &['\u{9EBB}'], + '\u{2FC8}' => &['\u{9EC3}'], + '\u{2FC9}' => &['\u{9ECD}'], + '\u{2FCA}' => &['\u{9ED1}'], + '\u{2FCB}' => &['\u{9EF9}'], + '\u{2FCC}' => &['\u{9EFD}'], + '\u{2FCD}' => &['\u{9F0E}'], + '\u{2FCE}' => &['\u{9F13}'], + '\u{2FCF}' => &['\u{9F20}'], + '\u{2FD0}' => &['\u{9F3B}'], + '\u{2FD1}' => &['\u{9F4A}'], + '\u{2FD2}' => &['\u{9F52}'], + '\u{2FD3}' => &['\u{9F8D}'], + '\u{2FD4}' => &['\u{9F9C}'], + '\u{2FD5}' => &['\u{9FA0}'], + '\u{3000}' => &['\u{0020}'], + '\u{3036}' => &['\u{3012}'], + '\u{3038}' => &['\u{5341}'], + '\u{3039}' => &['\u{5344}'], + '\u{303A}' => &['\u{5345}'], + '\u{309B}' => &['\u{0020}', '\u{3099}'], + '\u{309C}' => &['\u{0020}', '\u{309A}'], + '\u{309F}' => &['\u{3088}', '\u{308A}'], + '\u{30FF}' => &['\u{30B3}', '\u{30C8}'], + '\u{3131}' => &['\u{1100}'], + '\u{3132}' => &['\u{1101}'], + '\u{3133}' => &['\u{11AA}'], + '\u{3134}' => &['\u{1102}'], + '\u{3135}' => &['\u{11AC}'], + '\u{3136}' => &['\u{11AD}'], + '\u{3137}' => &['\u{1103}'], + '\u{3138}' => &['\u{1104}'], + '\u{3139}' => &['\u{1105}'], + '\u{313A}' => &['\u{11B0}'], + '\u{313B}' => &['\u{11B1}'], + '\u{313C}' => &['\u{11B2}'], + '\u{313D}' => &['\u{11B3}'], + '\u{313E}' => &['\u{11B4}'], + '\u{313F}' => &['\u{11B5}'], + '\u{3140}' => &['\u{111A}'], + '\u{3141}' => &['\u{1106}'], + '\u{3142}' => &['\u{1107}'], + '\u{3143}' => &['\u{1108}'], + '\u{3144}' => &['\u{1121}'], + '\u{3145}' => &['\u{1109}'], + '\u{3146}' => &['\u{110A}'], + '\u{3147}' => &['\u{110B}'], + '\u{3148}' => &['\u{110C}'], + '\u{3149}' => &['\u{110D}'], + '\u{314A}' => &['\u{110E}'], + '\u{314B}' => &['\u{110F}'], + '\u{314C}' => &['\u{1110}'], + '\u{314D}' => &['\u{1111}'], + '\u{314E}' => &['\u{1112}'], + '\u{314F}' => &['\u{1161}'], + '\u{3150}' => &['\u{1162}'], + '\u{3151}' => &['\u{1163}'], + '\u{3152}' => &['\u{1164}'], + '\u{3153}' => &['\u{1165}'], + '\u{3154}' => &['\u{1166}'], + '\u{3155}' => &['\u{1167}'], + '\u{3156}' => &['\u{1168}'], + '\u{3157}' => &['\u{1169}'], + '\u{3158}' => &['\u{116A}'], + '\u{3159}' => &['\u{116B}'], + '\u{315A}' => &['\u{116C}'], + '\u{315B}' => &['\u{116D}'], + '\u{315C}' => &['\u{116E}'], + '\u{315D}' => &['\u{116F}'], + '\u{315E}' => &['\u{1170}'], + '\u{315F}' => &['\u{1171}'], + '\u{3160}' => &['\u{1172}'], + '\u{3161}' => &['\u{1173}'], + '\u{3162}' => &['\u{1174}'], + '\u{3163}' => &['\u{1175}'], + '\u{3164}' => &['\u{1160}'], + '\u{3165}' => &['\u{1114}'], + '\u{3166}' => &['\u{1115}'], + '\u{3167}' => &['\u{11C7}'], + '\u{3168}' => &['\u{11C8}'], + '\u{3169}' => &['\u{11CC}'], + '\u{316A}' => &['\u{11CE}'], + '\u{316B}' => &['\u{11D3}'], + '\u{316C}' => &['\u{11D7}'], + '\u{316D}' => &['\u{11D9}'], + '\u{316E}' => &['\u{111C}'], + '\u{316F}' => &['\u{11DD}'], + '\u{3170}' => &['\u{11DF}'], + '\u{3171}' => &['\u{111D}'], + '\u{3172}' => &['\u{111E}'], + '\u{3173}' => &['\u{1120}'], + '\u{3174}' => &['\u{1122}'], + '\u{3175}' => &['\u{1123}'], + '\u{3176}' => &['\u{1127}'], + '\u{3177}' => &['\u{1129}'], + '\u{3178}' => &['\u{112B}'], + '\u{3179}' => &['\u{112C}'], + '\u{317A}' => &['\u{112D}'], + '\u{317B}' => &['\u{112E}'], + '\u{317C}' => &['\u{112F}'], + '\u{317D}' => &['\u{1132}'], + '\u{317E}' => &['\u{1136}'], + '\u{317F}' => &['\u{1140}'], + '\u{3180}' => &['\u{1147}'], + '\u{3181}' => &['\u{114C}'], + '\u{3182}' => &['\u{11F1}'], + '\u{3183}' => &['\u{11F2}'], + '\u{3184}' => &['\u{1157}'], + '\u{3185}' => &['\u{1158}'], + '\u{3186}' => &['\u{1159}'], + '\u{3187}' => &['\u{1184}'], + '\u{3188}' => &['\u{1185}'], + '\u{3189}' => &['\u{1188}'], + '\u{318A}' => &['\u{1191}'], + '\u{318B}' => &['\u{1192}'], + '\u{318C}' => &['\u{1194}'], + '\u{318D}' => &['\u{119E}'], + '\u{318E}' => &['\u{11A1}'], + '\u{3192}' => &['\u{4E00}'], + '\u{3193}' => &['\u{4E8C}'], + '\u{3194}' => &['\u{4E09}'], + '\u{3195}' => &['\u{56DB}'], + '\u{3196}' => &['\u{4E0A}'], + '\u{3197}' => &['\u{4E2D}'], + '\u{3198}' => &['\u{4E0B}'], + '\u{3199}' => &['\u{7532}'], + '\u{319A}' => &['\u{4E59}'], + '\u{319B}' => &['\u{4E19}'], + '\u{319C}' => &['\u{4E01}'], + '\u{319D}' => &['\u{5929}'], + '\u{319E}' => &['\u{5730}'], + '\u{319F}' => &['\u{4EBA}'], + '\u{3200}' => &['\u{0028}', '\u{1100}', '\u{0029}'], + '\u{3201}' => &['\u{0028}', '\u{1102}', '\u{0029}'], + '\u{3202}' => &['\u{0028}', '\u{1103}', '\u{0029}'], + '\u{3203}' => &['\u{0028}', '\u{1105}', '\u{0029}'], + '\u{3204}' => &['\u{0028}', '\u{1106}', '\u{0029}'], + '\u{3205}' => &['\u{0028}', '\u{1107}', '\u{0029}'], + '\u{3206}' => &['\u{0028}', '\u{1109}', '\u{0029}'], + '\u{3207}' => &['\u{0028}', '\u{110B}', '\u{0029}'], + '\u{3208}' => &['\u{0028}', '\u{110C}', '\u{0029}'], + '\u{3209}' => &['\u{0028}', '\u{110E}', '\u{0029}'], + '\u{320A}' => &['\u{0028}', '\u{110F}', '\u{0029}'], + '\u{320B}' => &['\u{0028}', '\u{1110}', '\u{0029}'], + '\u{320C}' => &['\u{0028}', '\u{1111}', '\u{0029}'], + '\u{320D}' => &['\u{0028}', '\u{1112}', '\u{0029}'], + '\u{320E}' => &['\u{0028}', '\u{1100}', '\u{1161}', '\u{0029}'], + '\u{320F}' => &['\u{0028}', '\u{1102}', '\u{1161}', '\u{0029}'], + '\u{3210}' => &['\u{0028}', '\u{1103}', '\u{1161}', '\u{0029}'], + '\u{3211}' => &['\u{0028}', '\u{1105}', '\u{1161}', '\u{0029}'], + '\u{3212}' => &['\u{0028}', '\u{1106}', '\u{1161}', '\u{0029}'], + '\u{3213}' => &['\u{0028}', '\u{1107}', '\u{1161}', '\u{0029}'], + '\u{3214}' => &['\u{0028}', '\u{1109}', '\u{1161}', '\u{0029}'], + '\u{3215}' => &['\u{0028}', '\u{110B}', '\u{1161}', '\u{0029}'], + '\u{3216}' => &['\u{0028}', '\u{110C}', '\u{1161}', '\u{0029}'], + '\u{3217}' => &['\u{0028}', '\u{110E}', '\u{1161}', '\u{0029}'], + '\u{3218}' => &['\u{0028}', '\u{110F}', '\u{1161}', '\u{0029}'], + '\u{3219}' => &['\u{0028}', '\u{1110}', '\u{1161}', '\u{0029}'], + '\u{321A}' => &['\u{0028}', '\u{1111}', '\u{1161}', '\u{0029}'], + '\u{321B}' => &['\u{0028}', '\u{1112}', '\u{1161}', '\u{0029}'], + '\u{321C}' => &['\u{0028}', '\u{110C}', '\u{116E}', '\u{0029}'], + '\u{321D}' => &['\u{0028}', '\u{110B}', '\u{1169}', '\u{110C}', '\u{1165}', '\u{11AB}', '\u{0029}'], + '\u{321E}' => &['\u{0028}', '\u{110B}', '\u{1169}', '\u{1112}', '\u{116E}', '\u{0029}'], + '\u{3220}' => &['\u{0028}', '\u{4E00}', '\u{0029}'], + '\u{3221}' => &['\u{0028}', '\u{4E8C}', '\u{0029}'], + '\u{3222}' => &['\u{0028}', '\u{4E09}', '\u{0029}'], + '\u{3223}' => &['\u{0028}', '\u{56DB}', '\u{0029}'], + '\u{3224}' => &['\u{0028}', '\u{4E94}', '\u{0029}'], + '\u{3225}' => &['\u{0028}', '\u{516D}', '\u{0029}'], + '\u{3226}' => &['\u{0028}', '\u{4E03}', '\u{0029}'], + '\u{3227}' => &['\u{0028}', '\u{516B}', '\u{0029}'], + '\u{3228}' => &['\u{0028}', '\u{4E5D}', '\u{0029}'], + '\u{3229}' => &['\u{0028}', '\u{5341}', '\u{0029}'], + '\u{322A}' => &['\u{0028}', '\u{6708}', '\u{0029}'], + '\u{322B}' => &['\u{0028}', '\u{706B}', '\u{0029}'], + '\u{322C}' => &['\u{0028}', '\u{6C34}', '\u{0029}'], + '\u{322D}' => &['\u{0028}', '\u{6728}', '\u{0029}'], + '\u{322E}' => &['\u{0028}', '\u{91D1}', '\u{0029}'], + '\u{322F}' => &['\u{0028}', '\u{571F}', '\u{0029}'], + '\u{3230}' => &['\u{0028}', '\u{65E5}', '\u{0029}'], + '\u{3231}' => &['\u{0028}', '\u{682A}', '\u{0029}'], + '\u{3232}' => &['\u{0028}', '\u{6709}', '\u{0029}'], + '\u{3233}' => &['\u{0028}', '\u{793E}', '\u{0029}'], + '\u{3234}' => &['\u{0028}', '\u{540D}', '\u{0029}'], + '\u{3235}' => &['\u{0028}', '\u{7279}', '\u{0029}'], + '\u{3236}' => &['\u{0028}', '\u{8CA1}', '\u{0029}'], + '\u{3237}' => &['\u{0028}', '\u{795D}', '\u{0029}'], + '\u{3238}' => &['\u{0028}', '\u{52B4}', '\u{0029}'], + '\u{3239}' => &['\u{0028}', '\u{4EE3}', '\u{0029}'], + '\u{323A}' => &['\u{0028}', '\u{547C}', '\u{0029}'], + '\u{323B}' => &['\u{0028}', '\u{5B66}', '\u{0029}'], + '\u{323C}' => &['\u{0028}', '\u{76E3}', '\u{0029}'], + '\u{323D}' => &['\u{0028}', '\u{4F01}', '\u{0029}'], + '\u{323E}' => &['\u{0028}', '\u{8CC7}', '\u{0029}'], + '\u{323F}' => &['\u{0028}', '\u{5354}', '\u{0029}'], + '\u{3240}' => &['\u{0028}', '\u{796D}', '\u{0029}'], + '\u{3241}' => &['\u{0028}', '\u{4F11}', '\u{0029}'], + '\u{3242}' => &['\u{0028}', '\u{81EA}', '\u{0029}'], + '\u{3243}' => &['\u{0028}', '\u{81F3}', '\u{0029}'], + '\u{3244}' => &['\u{554F}'], + '\u{3245}' => &['\u{5E7C}'], + '\u{3246}' => &['\u{6587}'], + '\u{3247}' => &['\u{7B8F}'], + '\u{3250}' => &['\u{0050}', '\u{0054}', '\u{0045}'], + '\u{3251}' => &['\u{0032}', '\u{0031}'], + '\u{3252}' => &['\u{0032}', '\u{0032}'], + '\u{3253}' => &['\u{0032}', '\u{0033}'], + '\u{3254}' => &['\u{0032}', '\u{0034}'], + '\u{3255}' => &['\u{0032}', '\u{0035}'], + '\u{3256}' => &['\u{0032}', '\u{0036}'], + '\u{3257}' => &['\u{0032}', '\u{0037}'], + '\u{3258}' => &['\u{0032}', '\u{0038}'], + '\u{3259}' => &['\u{0032}', '\u{0039}'], + '\u{325A}' => &['\u{0033}', '\u{0030}'], + '\u{325B}' => &['\u{0033}', '\u{0031}'], + '\u{325C}' => &['\u{0033}', '\u{0032}'], + '\u{325D}' => &['\u{0033}', '\u{0033}'], + '\u{325E}' => &['\u{0033}', '\u{0034}'], + '\u{325F}' => &['\u{0033}', '\u{0035}'], + '\u{3260}' => &['\u{1100}'], + '\u{3261}' => &['\u{1102}'], + '\u{3262}' => &['\u{1103}'], + '\u{3263}' => &['\u{1105}'], + '\u{3264}' => &['\u{1106}'], + '\u{3265}' => &['\u{1107}'], + '\u{3266}' => &['\u{1109}'], + '\u{3267}' => &['\u{110B}'], + '\u{3268}' => &['\u{110C}'], + '\u{3269}' => &['\u{110E}'], + '\u{326A}' => &['\u{110F}'], + '\u{326B}' => &['\u{1110}'], + '\u{326C}' => &['\u{1111}'], + '\u{326D}' => &['\u{1112}'], + '\u{326E}' => &['\u{1100}', '\u{1161}'], + '\u{326F}' => &['\u{1102}', '\u{1161}'], + '\u{3270}' => &['\u{1103}', '\u{1161}'], + '\u{3271}' => &['\u{1105}', '\u{1161}'], + '\u{3272}' => &['\u{1106}', '\u{1161}'], + '\u{3273}' => &['\u{1107}', '\u{1161}'], + '\u{3274}' => &['\u{1109}', '\u{1161}'], + '\u{3275}' => &['\u{110B}', '\u{1161}'], + '\u{3276}' => &['\u{110C}', '\u{1161}'], + '\u{3277}' => &['\u{110E}', '\u{1161}'], + '\u{3278}' => &['\u{110F}', '\u{1161}'], + '\u{3279}' => &['\u{1110}', '\u{1161}'], + '\u{327A}' => &['\u{1111}', '\u{1161}'], + '\u{327B}' => &['\u{1112}', '\u{1161}'], + '\u{327C}' => &['\u{110E}', '\u{1161}', '\u{11B7}', '\u{1100}', '\u{1169}'], + '\u{327D}' => &['\u{110C}', '\u{116E}', '\u{110B}', '\u{1174}'], + '\u{327E}' => &['\u{110B}', '\u{116E}'], + '\u{3280}' => &['\u{4E00}'], + '\u{3281}' => &['\u{4E8C}'], + '\u{3282}' => &['\u{4E09}'], + '\u{3283}' => &['\u{56DB}'], + '\u{3284}' => &['\u{4E94}'], + '\u{3285}' => &['\u{516D}'], + '\u{3286}' => &['\u{4E03}'], + '\u{3287}' => &['\u{516B}'], + '\u{3288}' => &['\u{4E5D}'], + '\u{3289}' => &['\u{5341}'], + '\u{328A}' => &['\u{6708}'], + '\u{328B}' => &['\u{706B}'], + '\u{328C}' => &['\u{6C34}'], + '\u{328D}' => &['\u{6728}'], + '\u{328E}' => &['\u{91D1}'], + '\u{328F}' => &['\u{571F}'], + '\u{3290}' => &['\u{65E5}'], + '\u{3291}' => &['\u{682A}'], + '\u{3292}' => &['\u{6709}'], + '\u{3293}' => &['\u{793E}'], + '\u{3294}' => &['\u{540D}'], + '\u{3295}' => &['\u{7279}'], + '\u{3296}' => &['\u{8CA1}'], + '\u{3297}' => &['\u{795D}'], + '\u{3298}' => &['\u{52B4}'], + '\u{3299}' => &['\u{79D8}'], + '\u{329A}' => &['\u{7537}'], + '\u{329B}' => &['\u{5973}'], + '\u{329C}' => &['\u{9069}'], + '\u{329D}' => &['\u{512A}'], + '\u{329E}' => &['\u{5370}'], + '\u{329F}' => &['\u{6CE8}'], + '\u{32A0}' => &['\u{9805}'], + '\u{32A1}' => &['\u{4F11}'], + '\u{32A2}' => &['\u{5199}'], + '\u{32A3}' => &['\u{6B63}'], + '\u{32A4}' => &['\u{4E0A}'], + '\u{32A5}' => &['\u{4E2D}'], + '\u{32A6}' => &['\u{4E0B}'], + '\u{32A7}' => &['\u{5DE6}'], + '\u{32A8}' => &['\u{53F3}'], + '\u{32A9}' => &['\u{533B}'], + '\u{32AA}' => &['\u{5B97}'], + '\u{32AB}' => &['\u{5B66}'], + '\u{32AC}' => &['\u{76E3}'], + '\u{32AD}' => &['\u{4F01}'], + '\u{32AE}' => &['\u{8CC7}'], + '\u{32AF}' => &['\u{5354}'], + '\u{32B0}' => &['\u{591C}'], + '\u{32B1}' => &['\u{0033}', '\u{0036}'], + '\u{32B2}' => &['\u{0033}', '\u{0037}'], + '\u{32B3}' => &['\u{0033}', '\u{0038}'], + '\u{32B4}' => &['\u{0033}', '\u{0039}'], + '\u{32B5}' => &['\u{0034}', '\u{0030}'], + '\u{32B6}' => &['\u{0034}', '\u{0031}'], + '\u{32B7}' => &['\u{0034}', '\u{0032}'], + '\u{32B8}' => &['\u{0034}', '\u{0033}'], + '\u{32B9}' => &['\u{0034}', '\u{0034}'], + '\u{32BA}' => &['\u{0034}', '\u{0035}'], + '\u{32BB}' => &['\u{0034}', '\u{0036}'], + '\u{32BC}' => &['\u{0034}', '\u{0037}'], + '\u{32BD}' => &['\u{0034}', '\u{0038}'], + '\u{32BE}' => &['\u{0034}', '\u{0039}'], + '\u{32BF}' => &['\u{0035}', '\u{0030}'], + '\u{32C0}' => &['\u{0031}', '\u{6708}'], + '\u{32C1}' => &['\u{0032}', '\u{6708}'], + '\u{32C2}' => &['\u{0033}', '\u{6708}'], + '\u{32C3}' => &['\u{0034}', '\u{6708}'], + '\u{32C4}' => &['\u{0035}', '\u{6708}'], + '\u{32C5}' => &['\u{0036}', '\u{6708}'], + '\u{32C6}' => &['\u{0037}', '\u{6708}'], + '\u{32C7}' => &['\u{0038}', '\u{6708}'], + '\u{32C8}' => &['\u{0039}', '\u{6708}'], + '\u{32C9}' => &['\u{0031}', '\u{0030}', '\u{6708}'], + '\u{32CA}' => &['\u{0031}', '\u{0031}', '\u{6708}'], + '\u{32CB}' => &['\u{0031}', '\u{0032}', '\u{6708}'], + '\u{32CC}' => &['\u{0048}', '\u{0067}'], + '\u{32CD}' => &['\u{0065}', '\u{0072}', '\u{0067}'], + '\u{32CE}' => &['\u{0065}', '\u{0056}'], + '\u{32CF}' => &['\u{004C}', '\u{0054}', '\u{0044}'], + '\u{32D0}' => &['\u{30A2}'], + '\u{32D1}' => &['\u{30A4}'], + '\u{32D2}' => &['\u{30A6}'], + '\u{32D3}' => &['\u{30A8}'], + '\u{32D4}' => &['\u{30AA}'], + '\u{32D5}' => &['\u{30AB}'], + '\u{32D6}' => &['\u{30AD}'], + '\u{32D7}' => &['\u{30AF}'], + '\u{32D8}' => &['\u{30B1}'], + '\u{32D9}' => &['\u{30B3}'], + '\u{32DA}' => &['\u{30B5}'], + '\u{32DB}' => &['\u{30B7}'], + '\u{32DC}' => &['\u{30B9}'], + '\u{32DD}' => &['\u{30BB}'], + '\u{32DE}' => &['\u{30BD}'], + '\u{32DF}' => &['\u{30BF}'], + '\u{32E0}' => &['\u{30C1}'], + '\u{32E1}' => &['\u{30C4}'], + '\u{32E2}' => &['\u{30C6}'], + '\u{32E3}' => &['\u{30C8}'], + '\u{32E4}' => &['\u{30CA}'], + '\u{32E5}' => &['\u{30CB}'], + '\u{32E6}' => &['\u{30CC}'], + '\u{32E7}' => &['\u{30CD}'], + '\u{32E8}' => &['\u{30CE}'], + '\u{32E9}' => &['\u{30CF}'], + '\u{32EA}' => &['\u{30D2}'], + '\u{32EB}' => &['\u{30D5}'], + '\u{32EC}' => &['\u{30D8}'], + '\u{32ED}' => &['\u{30DB}'], + '\u{32EE}' => &['\u{30DE}'], + '\u{32EF}' => &['\u{30DF}'], + '\u{32F0}' => &['\u{30E0}'], + '\u{32F1}' => &['\u{30E1}'], + '\u{32F2}' => &['\u{30E2}'], + '\u{32F3}' => &['\u{30E4}'], + '\u{32F4}' => &['\u{30E6}'], + '\u{32F5}' => &['\u{30E8}'], + '\u{32F6}' => &['\u{30E9}'], + '\u{32F7}' => &['\u{30EA}'], + '\u{32F8}' => &['\u{30EB}'], + '\u{32F9}' => &['\u{30EC}'], + '\u{32FA}' => &['\u{30ED}'], + '\u{32FB}' => &['\u{30EF}'], + '\u{32FC}' => &['\u{30F0}'], + '\u{32FD}' => &['\u{30F1}'], + '\u{32FE}' => &['\u{30F2}'], + '\u{3300}' => &['\u{30A2}', '\u{30CF}', '\u{309A}', '\u{30FC}', '\u{30C8}'], + '\u{3301}' => &['\u{30A2}', '\u{30EB}', '\u{30D5}', '\u{30A1}'], + '\u{3302}' => &['\u{30A2}', '\u{30F3}', '\u{30D8}', '\u{309A}', '\u{30A2}'], + '\u{3303}' => &['\u{30A2}', '\u{30FC}', '\u{30EB}'], + '\u{3304}' => &['\u{30A4}', '\u{30CB}', '\u{30F3}', '\u{30AF}', '\u{3099}'], + '\u{3305}' => &['\u{30A4}', '\u{30F3}', '\u{30C1}'], + '\u{3306}' => &['\u{30A6}', '\u{30A9}', '\u{30F3}'], + '\u{3307}' => &['\u{30A8}', '\u{30B9}', '\u{30AF}', '\u{30FC}', '\u{30C8}', '\u{3099}'], + '\u{3308}' => &['\u{30A8}', '\u{30FC}', '\u{30AB}', '\u{30FC}'], + '\u{3309}' => &['\u{30AA}', '\u{30F3}', '\u{30B9}'], + '\u{330A}' => &['\u{30AA}', '\u{30FC}', '\u{30E0}'], + '\u{330B}' => &['\u{30AB}', '\u{30A4}', '\u{30EA}'], + '\u{330C}' => &['\u{30AB}', '\u{30E9}', '\u{30C3}', '\u{30C8}'], + '\u{330D}' => &['\u{30AB}', '\u{30ED}', '\u{30EA}', '\u{30FC}'], + '\u{330E}' => &['\u{30AB}', '\u{3099}', '\u{30ED}', '\u{30F3}'], + '\u{330F}' => &['\u{30AB}', '\u{3099}', '\u{30F3}', '\u{30DE}'], + '\u{3310}' => &['\u{30AD}', '\u{3099}', '\u{30AB}', '\u{3099}'], + '\u{3311}' => &['\u{30AD}', '\u{3099}', '\u{30CB}', '\u{30FC}'], + '\u{3312}' => &['\u{30AD}', '\u{30E5}', '\u{30EA}', '\u{30FC}'], + '\u{3313}' => &['\u{30AD}', '\u{3099}', '\u{30EB}', '\u{30BF}', '\u{3099}', '\u{30FC}'], + '\u{3314}' => &['\u{30AD}', '\u{30ED}'], + '\u{3315}' => &['\u{30AD}', '\u{30ED}', '\u{30AF}', '\u{3099}', '\u{30E9}', '\u{30E0}'], + '\u{3316}' => &['\u{30AD}', '\u{30ED}', '\u{30E1}', '\u{30FC}', '\u{30C8}', '\u{30EB}'], + '\u{3317}' => &['\u{30AD}', '\u{30ED}', '\u{30EF}', '\u{30C3}', '\u{30C8}'], + '\u{3318}' => &['\u{30AF}', '\u{3099}', '\u{30E9}', '\u{30E0}'], + '\u{3319}' => &['\u{30AF}', '\u{3099}', '\u{30E9}', '\u{30E0}', '\u{30C8}', '\u{30F3}'], + '\u{331A}' => &['\u{30AF}', '\u{30EB}', '\u{30BB}', '\u{3099}', '\u{30A4}', '\u{30ED}'], + '\u{331B}' => &['\u{30AF}', '\u{30ED}', '\u{30FC}', '\u{30CD}'], + '\u{331C}' => &['\u{30B1}', '\u{30FC}', '\u{30B9}'], + '\u{331D}' => &['\u{30B3}', '\u{30EB}', '\u{30CA}'], + '\u{331E}' => &['\u{30B3}', '\u{30FC}', '\u{30DB}', '\u{309A}'], + '\u{331F}' => &['\u{30B5}', '\u{30A4}', '\u{30AF}', '\u{30EB}'], + '\u{3320}' => &['\u{30B5}', '\u{30F3}', '\u{30C1}', '\u{30FC}', '\u{30E0}'], + '\u{3321}' => &['\u{30B7}', '\u{30EA}', '\u{30F3}', '\u{30AF}', '\u{3099}'], + '\u{3322}' => &['\u{30BB}', '\u{30F3}', '\u{30C1}'], + '\u{3323}' => &['\u{30BB}', '\u{30F3}', '\u{30C8}'], + '\u{3324}' => &['\u{30BF}', '\u{3099}', '\u{30FC}', '\u{30B9}'], + '\u{3325}' => &['\u{30C6}', '\u{3099}', '\u{30B7}'], + '\u{3326}' => &['\u{30C8}', '\u{3099}', '\u{30EB}'], + '\u{3327}' => &['\u{30C8}', '\u{30F3}'], + '\u{3328}' => &['\u{30CA}', '\u{30CE}'], + '\u{3329}' => &['\u{30CE}', '\u{30C3}', '\u{30C8}'], + '\u{332A}' => &['\u{30CF}', '\u{30A4}', '\u{30C4}'], + '\u{332B}' => &['\u{30CF}', '\u{309A}', '\u{30FC}', '\u{30BB}', '\u{30F3}', '\u{30C8}'], + '\u{332C}' => &['\u{30CF}', '\u{309A}', '\u{30FC}', '\u{30C4}'], + '\u{332D}' => &['\u{30CF}', '\u{3099}', '\u{30FC}', '\u{30EC}', '\u{30EB}'], + '\u{332E}' => &['\u{30D2}', '\u{309A}', '\u{30A2}', '\u{30B9}', '\u{30C8}', '\u{30EB}'], + '\u{332F}' => &['\u{30D2}', '\u{309A}', '\u{30AF}', '\u{30EB}'], + '\u{3330}' => &['\u{30D2}', '\u{309A}', '\u{30B3}'], + '\u{3331}' => &['\u{30D2}', '\u{3099}', '\u{30EB}'], + '\u{3332}' => &['\u{30D5}', '\u{30A1}', '\u{30E9}', '\u{30C3}', '\u{30C8}', '\u{3099}'], + '\u{3333}' => &['\u{30D5}', '\u{30A3}', '\u{30FC}', '\u{30C8}'], + '\u{3334}' => &['\u{30D5}', '\u{3099}', '\u{30C3}', '\u{30B7}', '\u{30A7}', '\u{30EB}'], + '\u{3335}' => &['\u{30D5}', '\u{30E9}', '\u{30F3}'], + '\u{3336}' => &['\u{30D8}', '\u{30AF}', '\u{30BF}', '\u{30FC}', '\u{30EB}'], + '\u{3337}' => &['\u{30D8}', '\u{309A}', '\u{30BD}'], + '\u{3338}' => &['\u{30D8}', '\u{309A}', '\u{30CB}', '\u{30D2}'], + '\u{3339}' => &['\u{30D8}', '\u{30EB}', '\u{30C4}'], + '\u{333A}' => &['\u{30D8}', '\u{309A}', '\u{30F3}', '\u{30B9}'], + '\u{333B}' => &['\u{30D8}', '\u{309A}', '\u{30FC}', '\u{30B7}', '\u{3099}'], + '\u{333C}' => &['\u{30D8}', '\u{3099}', '\u{30FC}', '\u{30BF}'], + '\u{333D}' => &['\u{30DB}', '\u{309A}', '\u{30A4}', '\u{30F3}', '\u{30C8}'], + '\u{333E}' => &['\u{30DB}', '\u{3099}', '\u{30EB}', '\u{30C8}'], + '\u{333F}' => &['\u{30DB}', '\u{30F3}'], + '\u{3340}' => &['\u{30DB}', '\u{309A}', '\u{30F3}', '\u{30C8}', '\u{3099}'], + '\u{3341}' => &['\u{30DB}', '\u{30FC}', '\u{30EB}'], + '\u{3342}' => &['\u{30DB}', '\u{30FC}', '\u{30F3}'], + '\u{3343}' => &['\u{30DE}', '\u{30A4}', '\u{30AF}', '\u{30ED}'], + '\u{3344}' => &['\u{30DE}', '\u{30A4}', '\u{30EB}'], + '\u{3345}' => &['\u{30DE}', '\u{30C3}', '\u{30CF}'], + '\u{3346}' => &['\u{30DE}', '\u{30EB}', '\u{30AF}'], + '\u{3347}' => &['\u{30DE}', '\u{30F3}', '\u{30B7}', '\u{30E7}', '\u{30F3}'], + '\u{3348}' => &['\u{30DF}', '\u{30AF}', '\u{30ED}', '\u{30F3}'], + '\u{3349}' => &['\u{30DF}', '\u{30EA}'], + '\u{334A}' => &['\u{30DF}', '\u{30EA}', '\u{30CF}', '\u{3099}', '\u{30FC}', '\u{30EB}'], + '\u{334B}' => &['\u{30E1}', '\u{30AB}', '\u{3099}'], + '\u{334C}' => &['\u{30E1}', '\u{30AB}', '\u{3099}', '\u{30C8}', '\u{30F3}'], + '\u{334D}' => &['\u{30E1}', '\u{30FC}', '\u{30C8}', '\u{30EB}'], + '\u{334E}' => &['\u{30E4}', '\u{30FC}', '\u{30C8}', '\u{3099}'], + '\u{334F}' => &['\u{30E4}', '\u{30FC}', '\u{30EB}'], + '\u{3350}' => &['\u{30E6}', '\u{30A2}', '\u{30F3}'], + '\u{3351}' => &['\u{30EA}', '\u{30C3}', '\u{30C8}', '\u{30EB}'], + '\u{3352}' => &['\u{30EA}', '\u{30E9}'], + '\u{3353}' => &['\u{30EB}', '\u{30D2}', '\u{309A}', '\u{30FC}'], + '\u{3354}' => &['\u{30EB}', '\u{30FC}', '\u{30D5}', '\u{3099}', '\u{30EB}'], + '\u{3355}' => &['\u{30EC}', '\u{30E0}'], + '\u{3356}' => &['\u{30EC}', '\u{30F3}', '\u{30C8}', '\u{30B1}', '\u{3099}', '\u{30F3}'], + '\u{3357}' => &['\u{30EF}', '\u{30C3}', '\u{30C8}'], + '\u{3358}' => &['\u{0030}', '\u{70B9}'], + '\u{3359}' => &['\u{0031}', '\u{70B9}'], + '\u{335A}' => &['\u{0032}', '\u{70B9}'], + '\u{335B}' => &['\u{0033}', '\u{70B9}'], + '\u{335C}' => &['\u{0034}', '\u{70B9}'], + '\u{335D}' => &['\u{0035}', '\u{70B9}'], + '\u{335E}' => &['\u{0036}', '\u{70B9}'], + '\u{335F}' => &['\u{0037}', '\u{70B9}'], + '\u{3360}' => &['\u{0038}', '\u{70B9}'], + '\u{3361}' => &['\u{0039}', '\u{70B9}'], + '\u{3362}' => &['\u{0031}', '\u{0030}', '\u{70B9}'], + '\u{3363}' => &['\u{0031}', '\u{0031}', '\u{70B9}'], + '\u{3364}' => &['\u{0031}', '\u{0032}', '\u{70B9}'], + '\u{3365}' => &['\u{0031}', '\u{0033}', '\u{70B9}'], + '\u{3366}' => &['\u{0031}', '\u{0034}', '\u{70B9}'], + '\u{3367}' => &['\u{0031}', '\u{0035}', '\u{70B9}'], + '\u{3368}' => &['\u{0031}', '\u{0036}', '\u{70B9}'], + '\u{3369}' => &['\u{0031}', '\u{0037}', '\u{70B9}'], + '\u{336A}' => &['\u{0031}', '\u{0038}', '\u{70B9}'], + '\u{336B}' => &['\u{0031}', '\u{0039}', '\u{70B9}'], + '\u{336C}' => &['\u{0032}', '\u{0030}', '\u{70B9}'], + '\u{336D}' => &['\u{0032}', '\u{0031}', '\u{70B9}'], + '\u{336E}' => &['\u{0032}', '\u{0032}', '\u{70B9}'], + '\u{336F}' => &['\u{0032}', '\u{0033}', '\u{70B9}'], + '\u{3370}' => &['\u{0032}', '\u{0034}', '\u{70B9}'], + '\u{3371}' => &['\u{0068}', '\u{0050}', '\u{0061}'], + '\u{3372}' => &['\u{0064}', '\u{0061}'], + '\u{3373}' => &['\u{0041}', '\u{0055}'], + '\u{3374}' => &['\u{0062}', '\u{0061}', '\u{0072}'], + '\u{3375}' => &['\u{006F}', '\u{0056}'], + '\u{3376}' => &['\u{0070}', '\u{0063}'], + '\u{3377}' => &['\u{0064}', '\u{006D}'], + '\u{3378}' => &['\u{0064}', '\u{006D}', '\u{0032}'], + '\u{3379}' => &['\u{0064}', '\u{006D}', '\u{0033}'], + '\u{337A}' => &['\u{0049}', '\u{0055}'], + '\u{337B}' => &['\u{5E73}', '\u{6210}'], + '\u{337C}' => &['\u{662D}', '\u{548C}'], + '\u{337D}' => &['\u{5927}', '\u{6B63}'], + '\u{337E}' => &['\u{660E}', '\u{6CBB}'], + '\u{337F}' => &['\u{682A}', '\u{5F0F}', '\u{4F1A}', '\u{793E}'], + '\u{3380}' => &['\u{0070}', '\u{0041}'], + '\u{3381}' => &['\u{006E}', '\u{0041}'], + '\u{3382}' => &['\u{03BC}', '\u{0041}'], + '\u{3383}' => &['\u{006D}', '\u{0041}'], + '\u{3384}' => &['\u{006B}', '\u{0041}'], + '\u{3385}' => &['\u{004B}', '\u{0042}'], + '\u{3386}' => &['\u{004D}', '\u{0042}'], + '\u{3387}' => &['\u{0047}', '\u{0042}'], + '\u{3388}' => &['\u{0063}', '\u{0061}', '\u{006C}'], + '\u{3389}' => &['\u{006B}', '\u{0063}', '\u{0061}', '\u{006C}'], + '\u{338A}' => &['\u{0070}', '\u{0046}'], + '\u{338B}' => &['\u{006E}', '\u{0046}'], + '\u{338C}' => &['\u{03BC}', '\u{0046}'], + '\u{338D}' => &['\u{03BC}', '\u{0067}'], + '\u{338E}' => &['\u{006D}', '\u{0067}'], + '\u{338F}' => &['\u{006B}', '\u{0067}'], + '\u{3390}' => &['\u{0048}', '\u{007A}'], + '\u{3391}' => &['\u{006B}', '\u{0048}', '\u{007A}'], + '\u{3392}' => &['\u{004D}', '\u{0048}', '\u{007A}'], + '\u{3393}' => &['\u{0047}', '\u{0048}', '\u{007A}'], + '\u{3394}' => &['\u{0054}', '\u{0048}', '\u{007A}'], + '\u{3395}' => &['\u{03BC}', '\u{006C}'], + '\u{3396}' => &['\u{006D}', '\u{006C}'], + '\u{3397}' => &['\u{0064}', '\u{006C}'], + '\u{3398}' => &['\u{006B}', '\u{006C}'], + '\u{3399}' => &['\u{0066}', '\u{006D}'], + '\u{339A}' => &['\u{006E}', '\u{006D}'], + '\u{339B}' => &['\u{03BC}', '\u{006D}'], + '\u{339C}' => &['\u{006D}', '\u{006D}'], + '\u{339D}' => &['\u{0063}', '\u{006D}'], + '\u{339E}' => &['\u{006B}', '\u{006D}'], + '\u{339F}' => &['\u{006D}', '\u{006D}', '\u{0032}'], + '\u{33A0}' => &['\u{0063}', '\u{006D}', '\u{0032}'], + '\u{33A1}' => &['\u{006D}', '\u{0032}'], + '\u{33A2}' => &['\u{006B}', '\u{006D}', '\u{0032}'], + '\u{33A3}' => &['\u{006D}', '\u{006D}', '\u{0033}'], + '\u{33A4}' => &['\u{0063}', '\u{006D}', '\u{0033}'], + '\u{33A5}' => &['\u{006D}', '\u{0033}'], + '\u{33A6}' => &['\u{006B}', '\u{006D}', '\u{0033}'], + '\u{33A7}' => &['\u{006D}', '\u{2215}', '\u{0073}'], + '\u{33A8}' => &['\u{006D}', '\u{2215}', '\u{0073}', '\u{0032}'], + '\u{33A9}' => &['\u{0050}', '\u{0061}'], + '\u{33AA}' => &['\u{006B}', '\u{0050}', '\u{0061}'], + '\u{33AB}' => &['\u{004D}', '\u{0050}', '\u{0061}'], + '\u{33AC}' => &['\u{0047}', '\u{0050}', '\u{0061}'], + '\u{33AD}' => &['\u{0072}', '\u{0061}', '\u{0064}'], + '\u{33AE}' => &['\u{0072}', '\u{0061}', '\u{0064}', '\u{2215}', '\u{0073}'], + '\u{33AF}' => &['\u{0072}', '\u{0061}', '\u{0064}', '\u{2215}', '\u{0073}', '\u{0032}'], + '\u{33B0}' => &['\u{0070}', '\u{0073}'], + '\u{33B1}' => &['\u{006E}', '\u{0073}'], + '\u{33B2}' => &['\u{03BC}', '\u{0073}'], + '\u{33B3}' => &['\u{006D}', '\u{0073}'], + '\u{33B4}' => &['\u{0070}', '\u{0056}'], + '\u{33B5}' => &['\u{006E}', '\u{0056}'], + '\u{33B6}' => &['\u{03BC}', '\u{0056}'], + '\u{33B7}' => &['\u{006D}', '\u{0056}'], + '\u{33B8}' => &['\u{006B}', '\u{0056}'], + '\u{33B9}' => &['\u{004D}', '\u{0056}'], + '\u{33BA}' => &['\u{0070}', '\u{0057}'], + '\u{33BB}' => &['\u{006E}', '\u{0057}'], + '\u{33BC}' => &['\u{03BC}', '\u{0057}'], + '\u{33BD}' => &['\u{006D}', '\u{0057}'], + '\u{33BE}' => &['\u{006B}', '\u{0057}'], + '\u{33BF}' => &['\u{004D}', '\u{0057}'], + '\u{33C0}' => &['\u{006B}', '\u{03A9}'], + '\u{33C1}' => &['\u{004D}', '\u{03A9}'], + '\u{33C2}' => &['\u{0061}', '\u{002E}', '\u{006D}', '\u{002E}'], + '\u{33C3}' => &['\u{0042}', '\u{0071}'], + '\u{33C4}' => &['\u{0063}', '\u{0063}'], + '\u{33C5}' => &['\u{0063}', '\u{0064}'], + '\u{33C6}' => &['\u{0043}', '\u{2215}', '\u{006B}', '\u{0067}'], + '\u{33C7}' => &['\u{0043}', '\u{006F}', '\u{002E}'], + '\u{33C8}' => &['\u{0064}', '\u{0042}'], + '\u{33C9}' => &['\u{0047}', '\u{0079}'], + '\u{33CA}' => &['\u{0068}', '\u{0061}'], + '\u{33CB}' => &['\u{0048}', '\u{0050}'], + '\u{33CC}' => &['\u{0069}', '\u{006E}'], + '\u{33CD}' => &['\u{004B}', '\u{004B}'], + '\u{33CE}' => &['\u{004B}', '\u{004D}'], + '\u{33CF}' => &['\u{006B}', '\u{0074}'], + '\u{33D0}' => &['\u{006C}', '\u{006D}'], + '\u{33D1}' => &['\u{006C}', '\u{006E}'], + '\u{33D2}' => &['\u{006C}', '\u{006F}', '\u{0067}'], + '\u{33D3}' => &['\u{006C}', '\u{0078}'], + '\u{33D4}' => &['\u{006D}', '\u{0062}'], + '\u{33D5}' => &['\u{006D}', '\u{0069}', '\u{006C}'], + '\u{33D6}' => &['\u{006D}', '\u{006F}', '\u{006C}'], + '\u{33D7}' => &['\u{0050}', '\u{0048}'], + '\u{33D8}' => &['\u{0070}', '\u{002E}', '\u{006D}', '\u{002E}'], + '\u{33D9}' => &['\u{0050}', '\u{0050}', '\u{004D}'], + '\u{33DA}' => &['\u{0050}', '\u{0052}'], + '\u{33DB}' => &['\u{0073}', '\u{0072}'], + '\u{33DC}' => &['\u{0053}', '\u{0076}'], + '\u{33DD}' => &['\u{0057}', '\u{0062}'], + '\u{33DE}' => &['\u{0056}', '\u{2215}', '\u{006D}'], + '\u{33DF}' => &['\u{0041}', '\u{2215}', '\u{006D}'], + '\u{33E0}' => &['\u{0031}', '\u{65E5}'], + '\u{33E1}' => &['\u{0032}', '\u{65E5}'], + '\u{33E2}' => &['\u{0033}', '\u{65E5}'], + '\u{33E3}' => &['\u{0034}', '\u{65E5}'], + '\u{33E4}' => &['\u{0035}', '\u{65E5}'], + '\u{33E5}' => &['\u{0036}', '\u{65E5}'], + '\u{33E6}' => &['\u{0037}', '\u{65E5}'], + '\u{33E7}' => &['\u{0038}', '\u{65E5}'], + '\u{33E8}' => &['\u{0039}', '\u{65E5}'], + '\u{33E9}' => &['\u{0031}', '\u{0030}', '\u{65E5}'], + '\u{33EA}' => &['\u{0031}', '\u{0031}', '\u{65E5}'], + '\u{33EB}' => &['\u{0031}', '\u{0032}', '\u{65E5}'], + '\u{33EC}' => &['\u{0031}', '\u{0033}', '\u{65E5}'], + '\u{33ED}' => &['\u{0031}', '\u{0034}', '\u{65E5}'], + '\u{33EE}' => &['\u{0031}', '\u{0035}', '\u{65E5}'], + '\u{33EF}' => &['\u{0031}', '\u{0036}', '\u{65E5}'], + '\u{33F0}' => &['\u{0031}', '\u{0037}', '\u{65E5}'], + '\u{33F1}' => &['\u{0031}', '\u{0038}', '\u{65E5}'], + '\u{33F2}' => &['\u{0031}', '\u{0039}', '\u{65E5}'], + '\u{33F3}' => &['\u{0032}', '\u{0030}', '\u{65E5}'], + '\u{33F4}' => &['\u{0032}', '\u{0031}', '\u{65E5}'], + '\u{33F5}' => &['\u{0032}', '\u{0032}', '\u{65E5}'], + '\u{33F6}' => &['\u{0032}', '\u{0033}', '\u{65E5}'], + '\u{33F7}' => &['\u{0032}', '\u{0034}', '\u{65E5}'], + '\u{33F8}' => &['\u{0032}', '\u{0035}', '\u{65E5}'], + '\u{33F9}' => &['\u{0032}', '\u{0036}', '\u{65E5}'], + '\u{33FA}' => &['\u{0032}', '\u{0037}', '\u{65E5}'], + '\u{33FB}' => &['\u{0032}', '\u{0038}', '\u{65E5}'], + '\u{33FC}' => &['\u{0032}', '\u{0039}', '\u{65E5}'], + '\u{33FD}' => &['\u{0033}', '\u{0030}', '\u{65E5}'], + '\u{33FE}' => &['\u{0033}', '\u{0031}', '\u{65E5}'], + '\u{33FF}' => &['\u{0067}', '\u{0061}', '\u{006C}'], + '\u{A69C}' => &['\u{044A}'], + '\u{A69D}' => &['\u{044C}'], + '\u{A770}' => &['\u{A76F}'], + '\u{A7F8}' => &['\u{0126}'], + '\u{A7F9}' => &['\u{0153}'], + '\u{AB5C}' => &['\u{A727}'], + '\u{AB5D}' => &['\u{AB37}'], + '\u{AB5E}' => &['\u{026B}'], + '\u{AB5F}' => &['\u{AB52}'], + '\u{FB00}' => &['\u{0066}', '\u{0066}'], + '\u{FB01}' => &['\u{0066}', '\u{0069}'], + '\u{FB02}' => &['\u{0066}', '\u{006C}'], + '\u{FB03}' => &['\u{0066}', '\u{0066}', '\u{0069}'], + '\u{FB04}' => &['\u{0066}', '\u{0066}', '\u{006C}'], + '\u{FB05}' => &['\u{0073}', '\u{0074}'], + '\u{FB06}' => &['\u{0073}', '\u{0074}'], + '\u{FB13}' => &['\u{0574}', '\u{0576}'], + '\u{FB14}' => &['\u{0574}', '\u{0565}'], + '\u{FB15}' => &['\u{0574}', '\u{056B}'], + '\u{FB16}' => &['\u{057E}', '\u{0576}'], + '\u{FB17}' => &['\u{0574}', '\u{056D}'], + '\u{FB20}' => &['\u{05E2}'], + '\u{FB21}' => &['\u{05D0}'], + '\u{FB22}' => &['\u{05D3}'], + '\u{FB23}' => &['\u{05D4}'], + '\u{FB24}' => &['\u{05DB}'], + '\u{FB25}' => &['\u{05DC}'], + '\u{FB26}' => &['\u{05DD}'], + '\u{FB27}' => &['\u{05E8}'], + '\u{FB28}' => &['\u{05EA}'], + '\u{FB29}' => &['\u{002B}'], + '\u{FB4F}' => &['\u{05D0}', '\u{05DC}'], + '\u{FB50}' => &['\u{0671}'], + '\u{FB51}' => &['\u{0671}'], + '\u{FB52}' => &['\u{067B}'], + '\u{FB53}' => &['\u{067B}'], + '\u{FB54}' => &['\u{067B}'], + '\u{FB55}' => &['\u{067B}'], + '\u{FB56}' => &['\u{067E}'], + '\u{FB57}' => &['\u{067E}'], + '\u{FB58}' => &['\u{067E}'], + '\u{FB59}' => &['\u{067E}'], + '\u{FB5A}' => &['\u{0680}'], + '\u{FB5B}' => &['\u{0680}'], + '\u{FB5C}' => &['\u{0680}'], + '\u{FB5D}' => &['\u{0680}'], + '\u{FB5E}' => &['\u{067A}'], + '\u{FB5F}' => &['\u{067A}'], + '\u{FB60}' => &['\u{067A}'], + '\u{FB61}' => &['\u{067A}'], + '\u{FB62}' => &['\u{067F}'], + '\u{FB63}' => &['\u{067F}'], + '\u{FB64}' => &['\u{067F}'], + '\u{FB65}' => &['\u{067F}'], + '\u{FB66}' => &['\u{0679}'], + '\u{FB67}' => &['\u{0679}'], + '\u{FB68}' => &['\u{0679}'], + '\u{FB69}' => &['\u{0679}'], + '\u{FB6A}' => &['\u{06A4}'], + '\u{FB6B}' => &['\u{06A4}'], + '\u{FB6C}' => &['\u{06A4}'], + '\u{FB6D}' => &['\u{06A4}'], + '\u{FB6E}' => &['\u{06A6}'], + '\u{FB6F}' => &['\u{06A6}'], + '\u{FB70}' => &['\u{06A6}'], + '\u{FB71}' => &['\u{06A6}'], + '\u{FB72}' => &['\u{0684}'], + '\u{FB73}' => &['\u{0684}'], + '\u{FB74}' => &['\u{0684}'], + '\u{FB75}' => &['\u{0684}'], + '\u{FB76}' => &['\u{0683}'], + '\u{FB77}' => &['\u{0683}'], + '\u{FB78}' => &['\u{0683}'], + '\u{FB79}' => &['\u{0683}'], + '\u{FB7A}' => &['\u{0686}'], + '\u{FB7B}' => &['\u{0686}'], + '\u{FB7C}' => &['\u{0686}'], + '\u{FB7D}' => &['\u{0686}'], + '\u{FB7E}' => &['\u{0687}'], + '\u{FB7F}' => &['\u{0687}'], + '\u{FB80}' => &['\u{0687}'], + '\u{FB81}' => &['\u{0687}'], + '\u{FB82}' => &['\u{068D}'], + '\u{FB83}' => &['\u{068D}'], + '\u{FB84}' => &['\u{068C}'], + '\u{FB85}' => &['\u{068C}'], + '\u{FB86}' => &['\u{068E}'], + '\u{FB87}' => &['\u{068E}'], + '\u{FB88}' => &['\u{0688}'], + '\u{FB89}' => &['\u{0688}'], + '\u{FB8A}' => &['\u{0698}'], + '\u{FB8B}' => &['\u{0698}'], + '\u{FB8C}' => &['\u{0691}'], + '\u{FB8D}' => &['\u{0691}'], + '\u{FB8E}' => &['\u{06A9}'], + '\u{FB8F}' => &['\u{06A9}'], + '\u{FB90}' => &['\u{06A9}'], + '\u{FB91}' => &['\u{06A9}'], + '\u{FB92}' => &['\u{06AF}'], + '\u{FB93}' => &['\u{06AF}'], + '\u{FB94}' => &['\u{06AF}'], + '\u{FB95}' => &['\u{06AF}'], + '\u{FB96}' => &['\u{06B3}'], + '\u{FB97}' => &['\u{06B3}'], + '\u{FB98}' => &['\u{06B3}'], + '\u{FB99}' => &['\u{06B3}'], + '\u{FB9A}' => &['\u{06B1}'], + '\u{FB9B}' => &['\u{06B1}'], + '\u{FB9C}' => &['\u{06B1}'], + '\u{FB9D}' => &['\u{06B1}'], + '\u{FB9E}' => &['\u{06BA}'], + '\u{FB9F}' => &['\u{06BA}'], + '\u{FBA0}' => &['\u{06BB}'], + '\u{FBA1}' => &['\u{06BB}'], + '\u{FBA2}' => &['\u{06BB}'], + '\u{FBA3}' => &['\u{06BB}'], + '\u{FBA4}' => &['\u{06D5}', '\u{0654}'], + '\u{FBA5}' => &['\u{06D5}', '\u{0654}'], + '\u{FBA6}' => &['\u{06C1}'], + '\u{FBA7}' => &['\u{06C1}'], + '\u{FBA8}' => &['\u{06C1}'], + '\u{FBA9}' => &['\u{06C1}'], + '\u{FBAA}' => &['\u{06BE}'], + '\u{FBAB}' => &['\u{06BE}'], + '\u{FBAC}' => &['\u{06BE}'], + '\u{FBAD}' => &['\u{06BE}'], + '\u{FBAE}' => &['\u{06D2}'], + '\u{FBAF}' => &['\u{06D2}'], + '\u{FBB0}' => &['\u{06D2}', '\u{0654}'], + '\u{FBB1}' => &['\u{06D2}', '\u{0654}'], + '\u{FBD3}' => &['\u{06AD}'], + '\u{FBD4}' => &['\u{06AD}'], + '\u{FBD5}' => &['\u{06AD}'], + '\u{FBD6}' => &['\u{06AD}'], + '\u{FBD7}' => &['\u{06C7}'], + '\u{FBD8}' => &['\u{06C7}'], + '\u{FBD9}' => &['\u{06C6}'], + '\u{FBDA}' => &['\u{06C6}'], + '\u{FBDB}' => &['\u{06C8}'], + '\u{FBDC}' => &['\u{06C8}'], + '\u{FBDD}' => &['\u{06C7}', '\u{0674}'], + '\u{FBDE}' => &['\u{06CB}'], + '\u{FBDF}' => &['\u{06CB}'], + '\u{FBE0}' => &['\u{06C5}'], + '\u{FBE1}' => &['\u{06C5}'], + '\u{FBE2}' => &['\u{06C9}'], + '\u{FBE3}' => &['\u{06C9}'], + '\u{FBE4}' => &['\u{06D0}'], + '\u{FBE5}' => &['\u{06D0}'], + '\u{FBE6}' => &['\u{06D0}'], + '\u{FBE7}' => &['\u{06D0}'], + '\u{FBE8}' => &['\u{0649}'], + '\u{FBE9}' => &['\u{0649}'], + '\u{FBEA}' => &['\u{064A}', '\u{0654}', '\u{0627}'], + '\u{FBEB}' => &['\u{064A}', '\u{0654}', '\u{0627}'], + '\u{FBEC}' => &['\u{064A}', '\u{0654}', '\u{06D5}'], + '\u{FBED}' => &['\u{064A}', '\u{0654}', '\u{06D5}'], + '\u{FBEE}' => &['\u{064A}', '\u{0654}', '\u{0648}'], + '\u{FBEF}' => &['\u{064A}', '\u{0654}', '\u{0648}'], + '\u{FBF0}' => &['\u{064A}', '\u{0654}', '\u{06C7}'], + '\u{FBF1}' => &['\u{064A}', '\u{0654}', '\u{06C7}'], + '\u{FBF2}' => &['\u{064A}', '\u{0654}', '\u{06C6}'], + '\u{FBF3}' => &['\u{064A}', '\u{0654}', '\u{06C6}'], + '\u{FBF4}' => &['\u{064A}', '\u{0654}', '\u{06C8}'], + '\u{FBF5}' => &['\u{064A}', '\u{0654}', '\u{06C8}'], + '\u{FBF6}' => &['\u{064A}', '\u{0654}', '\u{06D0}'], + '\u{FBF7}' => &['\u{064A}', '\u{0654}', '\u{06D0}'], + '\u{FBF8}' => &['\u{064A}', '\u{0654}', '\u{06D0}'], + '\u{FBF9}' => &['\u{064A}', '\u{0654}', '\u{0649}'], + '\u{FBFA}' => &['\u{064A}', '\u{0654}', '\u{0649}'], + '\u{FBFB}' => &['\u{064A}', '\u{0654}', '\u{0649}'], + '\u{FBFC}' => &['\u{06CC}'], + '\u{FBFD}' => &['\u{06CC}'], + '\u{FBFE}' => &['\u{06CC}'], + '\u{FBFF}' => &['\u{06CC}'], + '\u{FC00}' => &['\u{064A}', '\u{0654}', '\u{062C}'], + '\u{FC01}' => &['\u{064A}', '\u{0654}', '\u{062D}'], + '\u{FC02}' => &['\u{064A}', '\u{0654}', '\u{0645}'], + '\u{FC03}' => &['\u{064A}', '\u{0654}', '\u{0649}'], + '\u{FC04}' => &['\u{064A}', '\u{0654}', '\u{064A}'], + '\u{FC05}' => &['\u{0628}', '\u{062C}'], + '\u{FC06}' => &['\u{0628}', '\u{062D}'], + '\u{FC07}' => &['\u{0628}', '\u{062E}'], + '\u{FC08}' => &['\u{0628}', '\u{0645}'], + '\u{FC09}' => &['\u{0628}', '\u{0649}'], + '\u{FC0A}' => &['\u{0628}', '\u{064A}'], + '\u{FC0B}' => &['\u{062A}', '\u{062C}'], + '\u{FC0C}' => &['\u{062A}', '\u{062D}'], + '\u{FC0D}' => &['\u{062A}', '\u{062E}'], + '\u{FC0E}' => &['\u{062A}', '\u{0645}'], + '\u{FC0F}' => &['\u{062A}', '\u{0649}'], + '\u{FC10}' => &['\u{062A}', '\u{064A}'], + '\u{FC11}' => &['\u{062B}', '\u{062C}'], + '\u{FC12}' => &['\u{062B}', '\u{0645}'], + '\u{FC13}' => &['\u{062B}', '\u{0649}'], + '\u{FC14}' => &['\u{062B}', '\u{064A}'], + '\u{FC15}' => &['\u{062C}', '\u{062D}'], + '\u{FC16}' => &['\u{062C}', '\u{0645}'], + '\u{FC17}' => &['\u{062D}', '\u{062C}'], + '\u{FC18}' => &['\u{062D}', '\u{0645}'], + '\u{FC19}' => &['\u{062E}', '\u{062C}'], + '\u{FC1A}' => &['\u{062E}', '\u{062D}'], + '\u{FC1B}' => &['\u{062E}', '\u{0645}'], + '\u{FC1C}' => &['\u{0633}', '\u{062C}'], + '\u{FC1D}' => &['\u{0633}', '\u{062D}'], + '\u{FC1E}' => &['\u{0633}', '\u{062E}'], + '\u{FC1F}' => &['\u{0633}', '\u{0645}'], + '\u{FC20}' => &['\u{0635}', '\u{062D}'], + '\u{FC21}' => &['\u{0635}', '\u{0645}'], + '\u{FC22}' => &['\u{0636}', '\u{062C}'], + '\u{FC23}' => &['\u{0636}', '\u{062D}'], + '\u{FC24}' => &['\u{0636}', '\u{062E}'], + '\u{FC25}' => &['\u{0636}', '\u{0645}'], + '\u{FC26}' => &['\u{0637}', '\u{062D}'], + '\u{FC27}' => &['\u{0637}', '\u{0645}'], + '\u{FC28}' => &['\u{0638}', '\u{0645}'], + '\u{FC29}' => &['\u{0639}', '\u{062C}'], + '\u{FC2A}' => &['\u{0639}', '\u{0645}'], + '\u{FC2B}' => &['\u{063A}', '\u{062C}'], + '\u{FC2C}' => &['\u{063A}', '\u{0645}'], + '\u{FC2D}' => &['\u{0641}', '\u{062C}'], + '\u{FC2E}' => &['\u{0641}', '\u{062D}'], + '\u{FC2F}' => &['\u{0641}', '\u{062E}'], + '\u{FC30}' => &['\u{0641}', '\u{0645}'], + '\u{FC31}' => &['\u{0641}', '\u{0649}'], + '\u{FC32}' => &['\u{0641}', '\u{064A}'], + '\u{FC33}' => &['\u{0642}', '\u{062D}'], + '\u{FC34}' => &['\u{0642}', '\u{0645}'], + '\u{FC35}' => &['\u{0642}', '\u{0649}'], + '\u{FC36}' => &['\u{0642}', '\u{064A}'], + '\u{FC37}' => &['\u{0643}', '\u{0627}'], + '\u{FC38}' => &['\u{0643}', '\u{062C}'], + '\u{FC39}' => &['\u{0643}', '\u{062D}'], + '\u{FC3A}' => &['\u{0643}', '\u{062E}'], + '\u{FC3B}' => &['\u{0643}', '\u{0644}'], + '\u{FC3C}' => &['\u{0643}', '\u{0645}'], + '\u{FC3D}' => &['\u{0643}', '\u{0649}'], + '\u{FC3E}' => &['\u{0643}', '\u{064A}'], + '\u{FC3F}' => &['\u{0644}', '\u{062C}'], + '\u{FC40}' => &['\u{0644}', '\u{062D}'], + '\u{FC41}' => &['\u{0644}', '\u{062E}'], + '\u{FC42}' => &['\u{0644}', '\u{0645}'], + '\u{FC43}' => &['\u{0644}', '\u{0649}'], + '\u{FC44}' => &['\u{0644}', '\u{064A}'], + '\u{FC45}' => &['\u{0645}', '\u{062C}'], + '\u{FC46}' => &['\u{0645}', '\u{062D}'], + '\u{FC47}' => &['\u{0645}', '\u{062E}'], + '\u{FC48}' => &['\u{0645}', '\u{0645}'], + '\u{FC49}' => &['\u{0645}', '\u{0649}'], + '\u{FC4A}' => &['\u{0645}', '\u{064A}'], + '\u{FC4B}' => &['\u{0646}', '\u{062C}'], + '\u{FC4C}' => &['\u{0646}', '\u{062D}'], + '\u{FC4D}' => &['\u{0646}', '\u{062E}'], + '\u{FC4E}' => &['\u{0646}', '\u{0645}'], + '\u{FC4F}' => &['\u{0646}', '\u{0649}'], + '\u{FC50}' => &['\u{0646}', '\u{064A}'], + '\u{FC51}' => &['\u{0647}', '\u{062C}'], + '\u{FC52}' => &['\u{0647}', '\u{0645}'], + '\u{FC53}' => &['\u{0647}', '\u{0649}'], + '\u{FC54}' => &['\u{0647}', '\u{064A}'], + '\u{FC55}' => &['\u{064A}', '\u{062C}'], + '\u{FC56}' => &['\u{064A}', '\u{062D}'], + '\u{FC57}' => &['\u{064A}', '\u{062E}'], + '\u{FC58}' => &['\u{064A}', '\u{0645}'], + '\u{FC59}' => &['\u{064A}', '\u{0649}'], + '\u{FC5A}' => &['\u{064A}', '\u{064A}'], + '\u{FC5B}' => &['\u{0630}', '\u{0670}'], + '\u{FC5C}' => &['\u{0631}', '\u{0670}'], + '\u{FC5D}' => &['\u{0649}', '\u{0670}'], + '\u{FC5E}' => &['\u{0020}', '\u{064C}', '\u{0651}'], + '\u{FC5F}' => &['\u{0020}', '\u{064D}', '\u{0651}'], + '\u{FC60}' => &['\u{0020}', '\u{064E}', '\u{0651}'], + '\u{FC61}' => &['\u{0020}', '\u{064F}', '\u{0651}'], + '\u{FC62}' => &['\u{0020}', '\u{0650}', '\u{0651}'], + '\u{FC63}' => &['\u{0020}', '\u{0651}', '\u{0670}'], + '\u{FC64}' => &['\u{064A}', '\u{0654}', '\u{0631}'], + '\u{FC65}' => &['\u{064A}', '\u{0654}', '\u{0632}'], + '\u{FC66}' => &['\u{064A}', '\u{0654}', '\u{0645}'], + '\u{FC67}' => &['\u{064A}', '\u{0654}', '\u{0646}'], + '\u{FC68}' => &['\u{064A}', '\u{0654}', '\u{0649}'], + '\u{FC69}' => &['\u{064A}', '\u{0654}', '\u{064A}'], + '\u{FC6A}' => &['\u{0628}', '\u{0631}'], + '\u{FC6B}' => &['\u{0628}', '\u{0632}'], + '\u{FC6C}' => &['\u{0628}', '\u{0645}'], + '\u{FC6D}' => &['\u{0628}', '\u{0646}'], + '\u{FC6E}' => &['\u{0628}', '\u{0649}'], + '\u{FC6F}' => &['\u{0628}', '\u{064A}'], + '\u{FC70}' => &['\u{062A}', '\u{0631}'], + '\u{FC71}' => &['\u{062A}', '\u{0632}'], + '\u{FC72}' => &['\u{062A}', '\u{0645}'], + '\u{FC73}' => &['\u{062A}', '\u{0646}'], + '\u{FC74}' => &['\u{062A}', '\u{0649}'], + '\u{FC75}' => &['\u{062A}', '\u{064A}'], + '\u{FC76}' => &['\u{062B}', '\u{0631}'], + '\u{FC77}' => &['\u{062B}', '\u{0632}'], + '\u{FC78}' => &['\u{062B}', '\u{0645}'], + '\u{FC79}' => &['\u{062B}', '\u{0646}'], + '\u{FC7A}' => &['\u{062B}', '\u{0649}'], + '\u{FC7B}' => &['\u{062B}', '\u{064A}'], + '\u{FC7C}' => &['\u{0641}', '\u{0649}'], + '\u{FC7D}' => &['\u{0641}', '\u{064A}'], + '\u{FC7E}' => &['\u{0642}', '\u{0649}'], + '\u{FC7F}' => &['\u{0642}', '\u{064A}'], + '\u{FC80}' => &['\u{0643}', '\u{0627}'], + '\u{FC81}' => &['\u{0643}', '\u{0644}'], + '\u{FC82}' => &['\u{0643}', '\u{0645}'], + '\u{FC83}' => &['\u{0643}', '\u{0649}'], + '\u{FC84}' => &['\u{0643}', '\u{064A}'], + '\u{FC85}' => &['\u{0644}', '\u{0645}'], + '\u{FC86}' => &['\u{0644}', '\u{0649}'], + '\u{FC87}' => &['\u{0644}', '\u{064A}'], + '\u{FC88}' => &['\u{0645}', '\u{0627}'], + '\u{FC89}' => &['\u{0645}', '\u{0645}'], + '\u{FC8A}' => &['\u{0646}', '\u{0631}'], + '\u{FC8B}' => &['\u{0646}', '\u{0632}'], + '\u{FC8C}' => &['\u{0646}', '\u{0645}'], + '\u{FC8D}' => &['\u{0646}', '\u{0646}'], + '\u{FC8E}' => &['\u{0646}', '\u{0649}'], + '\u{FC8F}' => &['\u{0646}', '\u{064A}'], + '\u{FC90}' => &['\u{0649}', '\u{0670}'], + '\u{FC91}' => &['\u{064A}', '\u{0631}'], + '\u{FC92}' => &['\u{064A}', '\u{0632}'], + '\u{FC93}' => &['\u{064A}', '\u{0645}'], + '\u{FC94}' => &['\u{064A}', '\u{0646}'], + '\u{FC95}' => &['\u{064A}', '\u{0649}'], + '\u{FC96}' => &['\u{064A}', '\u{064A}'], + '\u{FC97}' => &['\u{064A}', '\u{0654}', '\u{062C}'], + '\u{FC98}' => &['\u{064A}', '\u{0654}', '\u{062D}'], + '\u{FC99}' => &['\u{064A}', '\u{0654}', '\u{062E}'], + '\u{FC9A}' => &['\u{064A}', '\u{0654}', '\u{0645}'], + '\u{FC9B}' => &['\u{064A}', '\u{0654}', '\u{0647}'], + '\u{FC9C}' => &['\u{0628}', '\u{062C}'], + '\u{FC9D}' => &['\u{0628}', '\u{062D}'], + '\u{FC9E}' => &['\u{0628}', '\u{062E}'], + '\u{FC9F}' => &['\u{0628}', '\u{0645}'], + '\u{FCA0}' => &['\u{0628}', '\u{0647}'], + '\u{FCA1}' => &['\u{062A}', '\u{062C}'], + '\u{FCA2}' => &['\u{062A}', '\u{062D}'], + '\u{FCA3}' => &['\u{062A}', '\u{062E}'], + '\u{FCA4}' => &['\u{062A}', '\u{0645}'], + '\u{FCA5}' => &['\u{062A}', '\u{0647}'], + '\u{FCA6}' => &['\u{062B}', '\u{0645}'], + '\u{FCA7}' => &['\u{062C}', '\u{062D}'], + '\u{FCA8}' => &['\u{062C}', '\u{0645}'], + '\u{FCA9}' => &['\u{062D}', '\u{062C}'], + '\u{FCAA}' => &['\u{062D}', '\u{0645}'], + '\u{FCAB}' => &['\u{062E}', '\u{062C}'], + '\u{FCAC}' => &['\u{062E}', '\u{0645}'], + '\u{FCAD}' => &['\u{0633}', '\u{062C}'], + '\u{FCAE}' => &['\u{0633}', '\u{062D}'], + '\u{FCAF}' => &['\u{0633}', '\u{062E}'], + '\u{FCB0}' => &['\u{0633}', '\u{0645}'], + '\u{FCB1}' => &['\u{0635}', '\u{062D}'], + '\u{FCB2}' => &['\u{0635}', '\u{062E}'], + '\u{FCB3}' => &['\u{0635}', '\u{0645}'], + '\u{FCB4}' => &['\u{0636}', '\u{062C}'], + '\u{FCB5}' => &['\u{0636}', '\u{062D}'], + '\u{FCB6}' => &['\u{0636}', '\u{062E}'], + '\u{FCB7}' => &['\u{0636}', '\u{0645}'], + '\u{FCB8}' => &['\u{0637}', '\u{062D}'], + '\u{FCB9}' => &['\u{0638}', '\u{0645}'], + '\u{FCBA}' => &['\u{0639}', '\u{062C}'], + '\u{FCBB}' => &['\u{0639}', '\u{0645}'], + '\u{FCBC}' => &['\u{063A}', '\u{062C}'], + '\u{FCBD}' => &['\u{063A}', '\u{0645}'], + '\u{FCBE}' => &['\u{0641}', '\u{062C}'], + '\u{FCBF}' => &['\u{0641}', '\u{062D}'], + '\u{FCC0}' => &['\u{0641}', '\u{062E}'], + '\u{FCC1}' => &['\u{0641}', '\u{0645}'], + '\u{FCC2}' => &['\u{0642}', '\u{062D}'], + '\u{FCC3}' => &['\u{0642}', '\u{0645}'], + '\u{FCC4}' => &['\u{0643}', '\u{062C}'], + '\u{FCC5}' => &['\u{0643}', '\u{062D}'], + '\u{FCC6}' => &['\u{0643}', '\u{062E}'], + '\u{FCC7}' => &['\u{0643}', '\u{0644}'], + '\u{FCC8}' => &['\u{0643}', '\u{0645}'], + '\u{FCC9}' => &['\u{0644}', '\u{062C}'], + '\u{FCCA}' => &['\u{0644}', '\u{062D}'], + '\u{FCCB}' => &['\u{0644}', '\u{062E}'], + '\u{FCCC}' => &['\u{0644}', '\u{0645}'], + '\u{FCCD}' => &['\u{0644}', '\u{0647}'], + '\u{FCCE}' => &['\u{0645}', '\u{062C}'], + '\u{FCCF}' => &['\u{0645}', '\u{062D}'], + '\u{FCD0}' => &['\u{0645}', '\u{062E}'], + '\u{FCD1}' => &['\u{0645}', '\u{0645}'], + '\u{FCD2}' => &['\u{0646}', '\u{062C}'], + '\u{FCD3}' => &['\u{0646}', '\u{062D}'], + '\u{FCD4}' => &['\u{0646}', '\u{062E}'], + '\u{FCD5}' => &['\u{0646}', '\u{0645}'], + '\u{FCD6}' => &['\u{0646}', '\u{0647}'], + '\u{FCD7}' => &['\u{0647}', '\u{062C}'], + '\u{FCD8}' => &['\u{0647}', '\u{0645}'], + '\u{FCD9}' => &['\u{0647}', '\u{0670}'], + '\u{FCDA}' => &['\u{064A}', '\u{062C}'], + '\u{FCDB}' => &['\u{064A}', '\u{062D}'], + '\u{FCDC}' => &['\u{064A}', '\u{062E}'], + '\u{FCDD}' => &['\u{064A}', '\u{0645}'], + '\u{FCDE}' => &['\u{064A}', '\u{0647}'], + '\u{FCDF}' => &['\u{064A}', '\u{0654}', '\u{0645}'], + '\u{FCE0}' => &['\u{064A}', '\u{0654}', '\u{0647}'], + '\u{FCE1}' => &['\u{0628}', '\u{0645}'], + '\u{FCE2}' => &['\u{0628}', '\u{0647}'], + '\u{FCE3}' => &['\u{062A}', '\u{0645}'], + '\u{FCE4}' => &['\u{062A}', '\u{0647}'], + '\u{FCE5}' => &['\u{062B}', '\u{0645}'], + '\u{FCE6}' => &['\u{062B}', '\u{0647}'], + '\u{FCE7}' => &['\u{0633}', '\u{0645}'], + '\u{FCE8}' => &['\u{0633}', '\u{0647}'], + '\u{FCE9}' => &['\u{0634}', '\u{0645}'], + '\u{FCEA}' => &['\u{0634}', '\u{0647}'], + '\u{FCEB}' => &['\u{0643}', '\u{0644}'], + '\u{FCEC}' => &['\u{0643}', '\u{0645}'], + '\u{FCED}' => &['\u{0644}', '\u{0645}'], + '\u{FCEE}' => &['\u{0646}', '\u{0645}'], + '\u{FCEF}' => &['\u{0646}', '\u{0647}'], + '\u{FCF0}' => &['\u{064A}', '\u{0645}'], + '\u{FCF1}' => &['\u{064A}', '\u{0647}'], + '\u{FCF2}' => &['\u{0640}', '\u{064E}', '\u{0651}'], + '\u{FCF3}' => &['\u{0640}', '\u{064F}', '\u{0651}'], + '\u{FCF4}' => &['\u{0640}', '\u{0650}', '\u{0651}'], + '\u{FCF5}' => &['\u{0637}', '\u{0649}'], + '\u{FCF6}' => &['\u{0637}', '\u{064A}'], + '\u{FCF7}' => &['\u{0639}', '\u{0649}'], + '\u{FCF8}' => &['\u{0639}', '\u{064A}'], + '\u{FCF9}' => &['\u{063A}', '\u{0649}'], + '\u{FCFA}' => &['\u{063A}', '\u{064A}'], + '\u{FCFB}' => &['\u{0633}', '\u{0649}'], + '\u{FCFC}' => &['\u{0633}', '\u{064A}'], + '\u{FCFD}' => &['\u{0634}', '\u{0649}'], + '\u{FCFE}' => &['\u{0634}', '\u{064A}'], + '\u{FCFF}' => &['\u{062D}', '\u{0649}'], + '\u{FD00}' => &['\u{062D}', '\u{064A}'], + '\u{FD01}' => &['\u{062C}', '\u{0649}'], + '\u{FD02}' => &['\u{062C}', '\u{064A}'], + '\u{FD03}' => &['\u{062E}', '\u{0649}'], + '\u{FD04}' => &['\u{062E}', '\u{064A}'], + '\u{FD05}' => &['\u{0635}', '\u{0649}'], + '\u{FD06}' => &['\u{0635}', '\u{064A}'], + '\u{FD07}' => &['\u{0636}', '\u{0649}'], + '\u{FD08}' => &['\u{0636}', '\u{064A}'], + '\u{FD09}' => &['\u{0634}', '\u{062C}'], + '\u{FD0A}' => &['\u{0634}', '\u{062D}'], + '\u{FD0B}' => &['\u{0634}', '\u{062E}'], + '\u{FD0C}' => &['\u{0634}', '\u{0645}'], + '\u{FD0D}' => &['\u{0634}', '\u{0631}'], + '\u{FD0E}' => &['\u{0633}', '\u{0631}'], + '\u{FD0F}' => &['\u{0635}', '\u{0631}'], + '\u{FD10}' => &['\u{0636}', '\u{0631}'], + '\u{FD11}' => &['\u{0637}', '\u{0649}'], + '\u{FD12}' => &['\u{0637}', '\u{064A}'], + '\u{FD13}' => &['\u{0639}', '\u{0649}'], + '\u{FD14}' => &['\u{0639}', '\u{064A}'], + '\u{FD15}' => &['\u{063A}', '\u{0649}'], + '\u{FD16}' => &['\u{063A}', '\u{064A}'], + '\u{FD17}' => &['\u{0633}', '\u{0649}'], + '\u{FD18}' => &['\u{0633}', '\u{064A}'], + '\u{FD19}' => &['\u{0634}', '\u{0649}'], + '\u{FD1A}' => &['\u{0634}', '\u{064A}'], + '\u{FD1B}' => &['\u{062D}', '\u{0649}'], + '\u{FD1C}' => &['\u{062D}', '\u{064A}'], + '\u{FD1D}' => &['\u{062C}', '\u{0649}'], + '\u{FD1E}' => &['\u{062C}', '\u{064A}'], + '\u{FD1F}' => &['\u{062E}', '\u{0649}'], + '\u{FD20}' => &['\u{062E}', '\u{064A}'], + '\u{FD21}' => &['\u{0635}', '\u{0649}'], + '\u{FD22}' => &['\u{0635}', '\u{064A}'], + '\u{FD23}' => &['\u{0636}', '\u{0649}'], + '\u{FD24}' => &['\u{0636}', '\u{064A}'], + '\u{FD25}' => &['\u{0634}', '\u{062C}'], + '\u{FD26}' => &['\u{0634}', '\u{062D}'], + '\u{FD27}' => &['\u{0634}', '\u{062E}'], + '\u{FD28}' => &['\u{0634}', '\u{0645}'], + '\u{FD29}' => &['\u{0634}', '\u{0631}'], + '\u{FD2A}' => &['\u{0633}', '\u{0631}'], + '\u{FD2B}' => &['\u{0635}', '\u{0631}'], + '\u{FD2C}' => &['\u{0636}', '\u{0631}'], + '\u{FD2D}' => &['\u{0634}', '\u{062C}'], + '\u{FD2E}' => &['\u{0634}', '\u{062D}'], + '\u{FD2F}' => &['\u{0634}', '\u{062E}'], + '\u{FD30}' => &['\u{0634}', '\u{0645}'], + '\u{FD31}' => &['\u{0633}', '\u{0647}'], + '\u{FD32}' => &['\u{0634}', '\u{0647}'], + '\u{FD33}' => &['\u{0637}', '\u{0645}'], + '\u{FD34}' => &['\u{0633}', '\u{062C}'], + '\u{FD35}' => &['\u{0633}', '\u{062D}'], + '\u{FD36}' => &['\u{0633}', '\u{062E}'], + '\u{FD37}' => &['\u{0634}', '\u{062C}'], + '\u{FD38}' => &['\u{0634}', '\u{062D}'], + '\u{FD39}' => &['\u{0634}', '\u{062E}'], + '\u{FD3A}' => &['\u{0637}', '\u{0645}'], + '\u{FD3B}' => &['\u{0638}', '\u{0645}'], + '\u{FD3C}' => &['\u{0627}', '\u{064B}'], + '\u{FD3D}' => &['\u{0627}', '\u{064B}'], + '\u{FD50}' => &['\u{062A}', '\u{062C}', '\u{0645}'], + '\u{FD51}' => &['\u{062A}', '\u{062D}', '\u{062C}'], + '\u{FD52}' => &['\u{062A}', '\u{062D}', '\u{062C}'], + '\u{FD53}' => &['\u{062A}', '\u{062D}', '\u{0645}'], + '\u{FD54}' => &['\u{062A}', '\u{062E}', '\u{0645}'], + '\u{FD55}' => &['\u{062A}', '\u{0645}', '\u{062C}'], + '\u{FD56}' => &['\u{062A}', '\u{0645}', '\u{062D}'], + '\u{FD57}' => &['\u{062A}', '\u{0645}', '\u{062E}'], + '\u{FD58}' => &['\u{062C}', '\u{0645}', '\u{062D}'], + '\u{FD59}' => &['\u{062C}', '\u{0645}', '\u{062D}'], + '\u{FD5A}' => &['\u{062D}', '\u{0645}', '\u{064A}'], + '\u{FD5B}' => &['\u{062D}', '\u{0645}', '\u{0649}'], + '\u{FD5C}' => &['\u{0633}', '\u{062D}', '\u{062C}'], + '\u{FD5D}' => &['\u{0633}', '\u{062C}', '\u{062D}'], + '\u{FD5E}' => &['\u{0633}', '\u{062C}', '\u{0649}'], + '\u{FD5F}' => &['\u{0633}', '\u{0645}', '\u{062D}'], + '\u{FD60}' => &['\u{0633}', '\u{0645}', '\u{062D}'], + '\u{FD61}' => &['\u{0633}', '\u{0645}', '\u{062C}'], + '\u{FD62}' => &['\u{0633}', '\u{0645}', '\u{0645}'], + '\u{FD63}' => &['\u{0633}', '\u{0645}', '\u{0645}'], + '\u{FD64}' => &['\u{0635}', '\u{062D}', '\u{062D}'], + '\u{FD65}' => &['\u{0635}', '\u{062D}', '\u{062D}'], + '\u{FD66}' => &['\u{0635}', '\u{0645}', '\u{0645}'], + '\u{FD67}' => &['\u{0634}', '\u{062D}', '\u{0645}'], + '\u{FD68}' => &['\u{0634}', '\u{062D}', '\u{0645}'], + '\u{FD69}' => &['\u{0634}', '\u{062C}', '\u{064A}'], + '\u{FD6A}' => &['\u{0634}', '\u{0645}', '\u{062E}'], + '\u{FD6B}' => &['\u{0634}', '\u{0645}', '\u{062E}'], + '\u{FD6C}' => &['\u{0634}', '\u{0645}', '\u{0645}'], + '\u{FD6D}' => &['\u{0634}', '\u{0645}', '\u{0645}'], + '\u{FD6E}' => &['\u{0636}', '\u{062D}', '\u{0649}'], + '\u{FD6F}' => &['\u{0636}', '\u{062E}', '\u{0645}'], + '\u{FD70}' => &['\u{0636}', '\u{062E}', '\u{0645}'], + '\u{FD71}' => &['\u{0637}', '\u{0645}', '\u{062D}'], + '\u{FD72}' => &['\u{0637}', '\u{0645}', '\u{062D}'], + '\u{FD73}' => &['\u{0637}', '\u{0645}', '\u{0645}'], + '\u{FD74}' => &['\u{0637}', '\u{0645}', '\u{064A}'], + '\u{FD75}' => &['\u{0639}', '\u{062C}', '\u{0645}'], + '\u{FD76}' => &['\u{0639}', '\u{0645}', '\u{0645}'], + '\u{FD77}' => &['\u{0639}', '\u{0645}', '\u{0645}'], + '\u{FD78}' => &['\u{0639}', '\u{0645}', '\u{0649}'], + '\u{FD79}' => &['\u{063A}', '\u{0645}', '\u{0645}'], + '\u{FD7A}' => &['\u{063A}', '\u{0645}', '\u{064A}'], + '\u{FD7B}' => &['\u{063A}', '\u{0645}', '\u{0649}'], + '\u{FD7C}' => &['\u{0641}', '\u{062E}', '\u{0645}'], + '\u{FD7D}' => &['\u{0641}', '\u{062E}', '\u{0645}'], + '\u{FD7E}' => &['\u{0642}', '\u{0645}', '\u{062D}'], + '\u{FD7F}' => &['\u{0642}', '\u{0645}', '\u{0645}'], + '\u{FD80}' => &['\u{0644}', '\u{062D}', '\u{0645}'], + '\u{FD81}' => &['\u{0644}', '\u{062D}', '\u{064A}'], + '\u{FD82}' => &['\u{0644}', '\u{062D}', '\u{0649}'], + '\u{FD83}' => &['\u{0644}', '\u{062C}', '\u{062C}'], + '\u{FD84}' => &['\u{0644}', '\u{062C}', '\u{062C}'], + '\u{FD85}' => &['\u{0644}', '\u{062E}', '\u{0645}'], + '\u{FD86}' => &['\u{0644}', '\u{062E}', '\u{0645}'], + '\u{FD87}' => &['\u{0644}', '\u{0645}', '\u{062D}'], + '\u{FD88}' => &['\u{0644}', '\u{0645}', '\u{062D}'], + '\u{FD89}' => &['\u{0645}', '\u{062D}', '\u{062C}'], + '\u{FD8A}' => &['\u{0645}', '\u{062D}', '\u{0645}'], + '\u{FD8B}' => &['\u{0645}', '\u{062D}', '\u{064A}'], + '\u{FD8C}' => &['\u{0645}', '\u{062C}', '\u{062D}'], + '\u{FD8D}' => &['\u{0645}', '\u{062C}', '\u{0645}'], + '\u{FD8E}' => &['\u{0645}', '\u{062E}', '\u{062C}'], + '\u{FD8F}' => &['\u{0645}', '\u{062E}', '\u{0645}'], + '\u{FD92}' => &['\u{0645}', '\u{062C}', '\u{062E}'], + '\u{FD93}' => &['\u{0647}', '\u{0645}', '\u{062C}'], + '\u{FD94}' => &['\u{0647}', '\u{0645}', '\u{0645}'], + '\u{FD95}' => &['\u{0646}', '\u{062D}', '\u{0645}'], + '\u{FD96}' => &['\u{0646}', '\u{062D}', '\u{0649}'], + '\u{FD97}' => &['\u{0646}', '\u{062C}', '\u{0645}'], + '\u{FD98}' => &['\u{0646}', '\u{062C}', '\u{0645}'], + '\u{FD99}' => &['\u{0646}', '\u{062C}', '\u{0649}'], + '\u{FD9A}' => &['\u{0646}', '\u{0645}', '\u{064A}'], + '\u{FD9B}' => &['\u{0646}', '\u{0645}', '\u{0649}'], + '\u{FD9C}' => &['\u{064A}', '\u{0645}', '\u{0645}'], + '\u{FD9D}' => &['\u{064A}', '\u{0645}', '\u{0645}'], + '\u{FD9E}' => &['\u{0628}', '\u{062E}', '\u{064A}'], + '\u{FD9F}' => &['\u{062A}', '\u{062C}', '\u{064A}'], + '\u{FDA0}' => &['\u{062A}', '\u{062C}', '\u{0649}'], + '\u{FDA1}' => &['\u{062A}', '\u{062E}', '\u{064A}'], + '\u{FDA2}' => &['\u{062A}', '\u{062E}', '\u{0649}'], + '\u{FDA3}' => &['\u{062A}', '\u{0645}', '\u{064A}'], + '\u{FDA4}' => &['\u{062A}', '\u{0645}', '\u{0649}'], + '\u{FDA5}' => &['\u{062C}', '\u{0645}', '\u{064A}'], + '\u{FDA6}' => &['\u{062C}', '\u{062D}', '\u{0649}'], + '\u{FDA7}' => &['\u{062C}', '\u{0645}', '\u{0649}'], + '\u{FDA8}' => &['\u{0633}', '\u{062E}', '\u{0649}'], + '\u{FDA9}' => &['\u{0635}', '\u{062D}', '\u{064A}'], + '\u{FDAA}' => &['\u{0634}', '\u{062D}', '\u{064A}'], + '\u{FDAB}' => &['\u{0636}', '\u{062D}', '\u{064A}'], + '\u{FDAC}' => &['\u{0644}', '\u{062C}', '\u{064A}'], + '\u{FDAD}' => &['\u{0644}', '\u{0645}', '\u{064A}'], + '\u{FDAE}' => &['\u{064A}', '\u{062D}', '\u{064A}'], + '\u{FDAF}' => &['\u{064A}', '\u{062C}', '\u{064A}'], + '\u{FDB0}' => &['\u{064A}', '\u{0645}', '\u{064A}'], + '\u{FDB1}' => &['\u{0645}', '\u{0645}', '\u{064A}'], + '\u{FDB2}' => &['\u{0642}', '\u{0645}', '\u{064A}'], + '\u{FDB3}' => &['\u{0646}', '\u{062D}', '\u{064A}'], + '\u{FDB4}' => &['\u{0642}', '\u{0645}', '\u{062D}'], + '\u{FDB5}' => &['\u{0644}', '\u{062D}', '\u{0645}'], + '\u{FDB6}' => &['\u{0639}', '\u{0645}', '\u{064A}'], + '\u{FDB7}' => &['\u{0643}', '\u{0645}', '\u{064A}'], + '\u{FDB8}' => &['\u{0646}', '\u{062C}', '\u{062D}'], + '\u{FDB9}' => &['\u{0645}', '\u{062E}', '\u{064A}'], + '\u{FDBA}' => &['\u{0644}', '\u{062C}', '\u{0645}'], + '\u{FDBB}' => &['\u{0643}', '\u{0645}', '\u{0645}'], + '\u{FDBC}' => &['\u{0644}', '\u{062C}', '\u{0645}'], + '\u{FDBD}' => &['\u{0646}', '\u{062C}', '\u{062D}'], + '\u{FDBE}' => &['\u{062C}', '\u{062D}', '\u{064A}'], + '\u{FDBF}' => &['\u{062D}', '\u{062C}', '\u{064A}'], + '\u{FDC0}' => &['\u{0645}', '\u{062C}', '\u{064A}'], + '\u{FDC1}' => &['\u{0641}', '\u{0645}', '\u{064A}'], + '\u{FDC2}' => &['\u{0628}', '\u{062D}', '\u{064A}'], + '\u{FDC3}' => &['\u{0643}', '\u{0645}', '\u{0645}'], + '\u{FDC4}' => &['\u{0639}', '\u{062C}', '\u{0645}'], + '\u{FDC5}' => &['\u{0635}', '\u{0645}', '\u{0645}'], + '\u{FDC6}' => &['\u{0633}', '\u{062E}', '\u{064A}'], + '\u{FDC7}' => &['\u{0646}', '\u{062C}', '\u{064A}'], + '\u{FDF0}' => &['\u{0635}', '\u{0644}', '\u{06D2}'], + '\u{FDF1}' => &['\u{0642}', '\u{0644}', '\u{06D2}'], + '\u{FDF2}' => &['\u{0627}', '\u{0644}', '\u{0644}', '\u{0647}'], + '\u{FDF3}' => &['\u{0627}', '\u{0643}', '\u{0628}', '\u{0631}'], + '\u{FDF4}' => &['\u{0645}', '\u{062D}', '\u{0645}', '\u{062F}'], + '\u{FDF5}' => &['\u{0635}', '\u{0644}', '\u{0639}', '\u{0645}'], + '\u{FDF6}' => &['\u{0631}', '\u{0633}', '\u{0648}', '\u{0644}'], + '\u{FDF7}' => &['\u{0639}', '\u{0644}', '\u{064A}', '\u{0647}'], + '\u{FDF8}' => &['\u{0648}', '\u{0633}', '\u{0644}', '\u{0645}'], + '\u{FDF9}' => &['\u{0635}', '\u{0644}', '\u{0649}'], + '\u{FDFA}' => &['\u{0635}', '\u{0644}', '\u{0649}', '\u{0020}', '\u{0627}', '\u{0644}', '\u{0644}', '\u{0647}', '\u{0020}', '\u{0639}', '\u{0644}', '\u{064A}', '\u{0647}', '\u{0020}', '\u{0648}', '\u{0633}', '\u{0644}', '\u{0645}'], + '\u{FDFB}' => &['\u{062C}', '\u{0644}', '\u{0020}', '\u{062C}', '\u{0644}', '\u{0627}', '\u{0644}', '\u{0647}'], + '\u{FDFC}' => &['\u{0631}', '\u{06CC}', '\u{0627}', '\u{0644}'], + '\u{FE10}' => &['\u{002C}'], + '\u{FE11}' => &['\u{3001}'], + '\u{FE12}' => &['\u{3002}'], + '\u{FE13}' => &['\u{003A}'], + '\u{FE14}' => &['\u{003B}'], + '\u{FE15}' => &['\u{0021}'], + '\u{FE16}' => &['\u{003F}'], + '\u{FE17}' => &['\u{3016}'], + '\u{FE18}' => &['\u{3017}'], + '\u{FE19}' => &['\u{002E}', '\u{002E}', '\u{002E}'], + '\u{FE30}' => &['\u{002E}', '\u{002E}'], + '\u{FE31}' => &['\u{2014}'], + '\u{FE32}' => &['\u{2013}'], + '\u{FE33}' => &['\u{005F}'], + '\u{FE34}' => &['\u{005F}'], + '\u{FE35}' => &['\u{0028}'], + '\u{FE36}' => &['\u{0029}'], + '\u{FE37}' => &['\u{007B}'], + '\u{FE38}' => &['\u{007D}'], + '\u{FE39}' => &['\u{3014}'], + '\u{FE3A}' => &['\u{3015}'], + '\u{FE3B}' => &['\u{3010}'], + '\u{FE3C}' => &['\u{3011}'], + '\u{FE3D}' => &['\u{300A}'], + '\u{FE3E}' => &['\u{300B}'], + '\u{FE3F}' => &['\u{3008}'], + '\u{FE40}' => &['\u{3009}'], + '\u{FE41}' => &['\u{300C}'], + '\u{FE42}' => &['\u{300D}'], + '\u{FE43}' => &['\u{300E}'], + '\u{FE44}' => &['\u{300F}'], + '\u{FE47}' => &['\u{005B}'], + '\u{FE48}' => &['\u{005D}'], + '\u{FE49}' => &['\u{0020}', '\u{0305}'], + '\u{FE4A}' => &['\u{0020}', '\u{0305}'], + '\u{FE4B}' => &['\u{0020}', '\u{0305}'], + '\u{FE4C}' => &['\u{0020}', '\u{0305}'], + '\u{FE4D}' => &['\u{005F}'], + '\u{FE4E}' => &['\u{005F}'], + '\u{FE4F}' => &['\u{005F}'], + '\u{FE50}' => &['\u{002C}'], + '\u{FE51}' => &['\u{3001}'], + '\u{FE52}' => &['\u{002E}'], + '\u{FE54}' => &['\u{003B}'], + '\u{FE55}' => &['\u{003A}'], + '\u{FE56}' => &['\u{003F}'], + '\u{FE57}' => &['\u{0021}'], + '\u{FE58}' => &['\u{2014}'], + '\u{FE59}' => &['\u{0028}'], + '\u{FE5A}' => &['\u{0029}'], + '\u{FE5B}' => &['\u{007B}'], + '\u{FE5C}' => &['\u{007D}'], + '\u{FE5D}' => &['\u{3014}'], + '\u{FE5E}' => &['\u{3015}'], + '\u{FE5F}' => &['\u{0023}'], + '\u{FE60}' => &['\u{0026}'], + '\u{FE61}' => &['\u{002A}'], + '\u{FE62}' => &['\u{002B}'], + '\u{FE63}' => &['\u{002D}'], + '\u{FE64}' => &['\u{003C}'], + '\u{FE65}' => &['\u{003E}'], + '\u{FE66}' => &['\u{003D}'], + '\u{FE68}' => &['\u{005C}'], + '\u{FE69}' => &['\u{0024}'], + '\u{FE6A}' => &['\u{0025}'], + '\u{FE6B}' => &['\u{0040}'], + '\u{FE70}' => &['\u{0020}', '\u{064B}'], + '\u{FE71}' => &['\u{0640}', '\u{064B}'], + '\u{FE72}' => &['\u{0020}', '\u{064C}'], + '\u{FE74}' => &['\u{0020}', '\u{064D}'], + '\u{FE76}' => &['\u{0020}', '\u{064E}'], + '\u{FE77}' => &['\u{0640}', '\u{064E}'], + '\u{FE78}' => &['\u{0020}', '\u{064F}'], + '\u{FE79}' => &['\u{0640}', '\u{064F}'], + '\u{FE7A}' => &['\u{0020}', '\u{0650}'], + '\u{FE7B}' => &['\u{0640}', '\u{0650}'], + '\u{FE7C}' => &['\u{0020}', '\u{0651}'], + '\u{FE7D}' => &['\u{0640}', '\u{0651}'], + '\u{FE7E}' => &['\u{0020}', '\u{0652}'], + '\u{FE7F}' => &['\u{0640}', '\u{0652}'], + '\u{FE80}' => &['\u{0621}'], + '\u{FE81}' => &['\u{0627}', '\u{0653}'], + '\u{FE82}' => &['\u{0627}', '\u{0653}'], + '\u{FE83}' => &['\u{0627}', '\u{0654}'], + '\u{FE84}' => &['\u{0627}', '\u{0654}'], + '\u{FE85}' => &['\u{0648}', '\u{0654}'], + '\u{FE86}' => &['\u{0648}', '\u{0654}'], + '\u{FE87}' => &['\u{0627}', '\u{0655}'], + '\u{FE88}' => &['\u{0627}', '\u{0655}'], + '\u{FE89}' => &['\u{064A}', '\u{0654}'], + '\u{FE8A}' => &['\u{064A}', '\u{0654}'], + '\u{FE8B}' => &['\u{064A}', '\u{0654}'], + '\u{FE8C}' => &['\u{064A}', '\u{0654}'], + '\u{FE8D}' => &['\u{0627}'], + '\u{FE8E}' => &['\u{0627}'], + '\u{FE8F}' => &['\u{0628}'], + '\u{FE90}' => &['\u{0628}'], + '\u{FE91}' => &['\u{0628}'], + '\u{FE92}' => &['\u{0628}'], + '\u{FE93}' => &['\u{0629}'], + '\u{FE94}' => &['\u{0629}'], + '\u{FE95}' => &['\u{062A}'], + '\u{FE96}' => &['\u{062A}'], + '\u{FE97}' => &['\u{062A}'], + '\u{FE98}' => &['\u{062A}'], + '\u{FE99}' => &['\u{062B}'], + '\u{FE9A}' => &['\u{062B}'], + '\u{FE9B}' => &['\u{062B}'], + '\u{FE9C}' => &['\u{062B}'], + '\u{FE9D}' => &['\u{062C}'], + '\u{FE9E}' => &['\u{062C}'], + '\u{FE9F}' => &['\u{062C}'], + '\u{FEA0}' => &['\u{062C}'], + '\u{FEA1}' => &['\u{062D}'], + '\u{FEA2}' => &['\u{062D}'], + '\u{FEA3}' => &['\u{062D}'], + '\u{FEA4}' => &['\u{062D}'], + '\u{FEA5}' => &['\u{062E}'], + '\u{FEA6}' => &['\u{062E}'], + '\u{FEA7}' => &['\u{062E}'], + '\u{FEA8}' => &['\u{062E}'], + '\u{FEA9}' => &['\u{062F}'], + '\u{FEAA}' => &['\u{062F}'], + '\u{FEAB}' => &['\u{0630}'], + '\u{FEAC}' => &['\u{0630}'], + '\u{FEAD}' => &['\u{0631}'], + '\u{FEAE}' => &['\u{0631}'], + '\u{FEAF}' => &['\u{0632}'], + '\u{FEB0}' => &['\u{0632}'], + '\u{FEB1}' => &['\u{0633}'], + '\u{FEB2}' => &['\u{0633}'], + '\u{FEB3}' => &['\u{0633}'], + '\u{FEB4}' => &['\u{0633}'], + '\u{FEB5}' => &['\u{0634}'], + '\u{FEB6}' => &['\u{0634}'], + '\u{FEB7}' => &['\u{0634}'], + '\u{FEB8}' => &['\u{0634}'], + '\u{FEB9}' => &['\u{0635}'], + '\u{FEBA}' => &['\u{0635}'], + '\u{FEBB}' => &['\u{0635}'], + '\u{FEBC}' => &['\u{0635}'], + '\u{FEBD}' => &['\u{0636}'], + '\u{FEBE}' => &['\u{0636}'], + '\u{FEBF}' => &['\u{0636}'], + '\u{FEC0}' => &['\u{0636}'], + '\u{FEC1}' => &['\u{0637}'], + '\u{FEC2}' => &['\u{0637}'], + '\u{FEC3}' => &['\u{0637}'], + '\u{FEC4}' => &['\u{0637}'], + '\u{FEC5}' => &['\u{0638}'], + '\u{FEC6}' => &['\u{0638}'], + '\u{FEC7}' => &['\u{0638}'], + '\u{FEC8}' => &['\u{0638}'], + '\u{FEC9}' => &['\u{0639}'], + '\u{FECA}' => &['\u{0639}'], + '\u{FECB}' => &['\u{0639}'], + '\u{FECC}' => &['\u{0639}'], + '\u{FECD}' => &['\u{063A}'], + '\u{FECE}' => &['\u{063A}'], + '\u{FECF}' => &['\u{063A}'], + '\u{FED0}' => &['\u{063A}'], + '\u{FED1}' => &['\u{0641}'], + '\u{FED2}' => &['\u{0641}'], + '\u{FED3}' => &['\u{0641}'], + '\u{FED4}' => &['\u{0641}'], + '\u{FED5}' => &['\u{0642}'], + '\u{FED6}' => &['\u{0642}'], + '\u{FED7}' => &['\u{0642}'], + '\u{FED8}' => &['\u{0642}'], + '\u{FED9}' => &['\u{0643}'], + '\u{FEDA}' => &['\u{0643}'], + '\u{FEDB}' => &['\u{0643}'], + '\u{FEDC}' => &['\u{0643}'], + '\u{FEDD}' => &['\u{0644}'], + '\u{FEDE}' => &['\u{0644}'], + '\u{FEDF}' => &['\u{0644}'], + '\u{FEE0}' => &['\u{0644}'], + '\u{FEE1}' => &['\u{0645}'], + '\u{FEE2}' => &['\u{0645}'], + '\u{FEE3}' => &['\u{0645}'], + '\u{FEE4}' => &['\u{0645}'], + '\u{FEE5}' => &['\u{0646}'], + '\u{FEE6}' => &['\u{0646}'], + '\u{FEE7}' => &['\u{0646}'], + '\u{FEE8}' => &['\u{0646}'], + '\u{FEE9}' => &['\u{0647}'], + '\u{FEEA}' => &['\u{0647}'], + '\u{FEEB}' => &['\u{0647}'], + '\u{FEEC}' => &['\u{0647}'], + '\u{FEED}' => &['\u{0648}'], + '\u{FEEE}' => &['\u{0648}'], + '\u{FEEF}' => &['\u{0649}'], + '\u{FEF0}' => &['\u{0649}'], + '\u{FEF1}' => &['\u{064A}'], + '\u{FEF2}' => &['\u{064A}'], + '\u{FEF3}' => &['\u{064A}'], + '\u{FEF4}' => &['\u{064A}'], + '\u{FEF5}' => &['\u{0644}', '\u{0627}', '\u{0653}'], + '\u{FEF6}' => &['\u{0644}', '\u{0627}', '\u{0653}'], + '\u{FEF7}' => &['\u{0644}', '\u{0627}', '\u{0654}'], + '\u{FEF8}' => &['\u{0644}', '\u{0627}', '\u{0654}'], + '\u{FEF9}' => &['\u{0644}', '\u{0627}', '\u{0655}'], + '\u{FEFA}' => &['\u{0644}', '\u{0627}', '\u{0655}'], + '\u{FEFB}' => &['\u{0644}', '\u{0627}'], + '\u{FEFC}' => &['\u{0644}', '\u{0627}'], + '\u{FF01}' => &['\u{0021}'], + '\u{FF02}' => &['\u{0022}'], + '\u{FF03}' => &['\u{0023}'], + '\u{FF04}' => &['\u{0024}'], + '\u{FF05}' => &['\u{0025}'], + '\u{FF06}' => &['\u{0026}'], + '\u{FF07}' => &['\u{0027}'], + '\u{FF08}' => &['\u{0028}'], + '\u{FF09}' => &['\u{0029}'], + '\u{FF0A}' => &['\u{002A}'], + '\u{FF0B}' => &['\u{002B}'], + '\u{FF0C}' => &['\u{002C}'], + '\u{FF0D}' => &['\u{002D}'], + '\u{FF0E}' => &['\u{002E}'], + '\u{FF0F}' => &['\u{002F}'], + '\u{FF10}' => &['\u{0030}'], + '\u{FF11}' => &['\u{0031}'], + '\u{FF12}' => &['\u{0032}'], + '\u{FF13}' => &['\u{0033}'], + '\u{FF14}' => &['\u{0034}'], + '\u{FF15}' => &['\u{0035}'], + '\u{FF16}' => &['\u{0036}'], + '\u{FF17}' => &['\u{0037}'], + '\u{FF18}' => &['\u{0038}'], + '\u{FF19}' => &['\u{0039}'], + '\u{FF1A}' => &['\u{003A}'], + '\u{FF1B}' => &['\u{003B}'], + '\u{FF1C}' => &['\u{003C}'], + '\u{FF1D}' => &['\u{003D}'], + '\u{FF1E}' => &['\u{003E}'], + '\u{FF1F}' => &['\u{003F}'], + '\u{FF20}' => &['\u{0040}'], + '\u{FF21}' => &['\u{0041}'], + '\u{FF22}' => &['\u{0042}'], + '\u{FF23}' => &['\u{0043}'], + '\u{FF24}' => &['\u{0044}'], + '\u{FF25}' => &['\u{0045}'], + '\u{FF26}' => &['\u{0046}'], + '\u{FF27}' => &['\u{0047}'], + '\u{FF28}' => &['\u{0048}'], + '\u{FF29}' => &['\u{0049}'], + '\u{FF2A}' => &['\u{004A}'], + '\u{FF2B}' => &['\u{004B}'], + '\u{FF2C}' => &['\u{004C}'], + '\u{FF2D}' => &['\u{004D}'], + '\u{FF2E}' => &['\u{004E}'], + '\u{FF2F}' => &['\u{004F}'], + '\u{FF30}' => &['\u{0050}'], + '\u{FF31}' => &['\u{0051}'], + '\u{FF32}' => &['\u{0052}'], + '\u{FF33}' => &['\u{0053}'], + '\u{FF34}' => &['\u{0054}'], + '\u{FF35}' => &['\u{0055}'], + '\u{FF36}' => &['\u{0056}'], + '\u{FF37}' => &['\u{0057}'], + '\u{FF38}' => &['\u{0058}'], + '\u{FF39}' => &['\u{0059}'], + '\u{FF3A}' => &['\u{005A}'], + '\u{FF3B}' => &['\u{005B}'], + '\u{FF3C}' => &['\u{005C}'], + '\u{FF3D}' => &['\u{005D}'], + '\u{FF3E}' => &['\u{005E}'], + '\u{FF3F}' => &['\u{005F}'], + '\u{FF40}' => &['\u{0060}'], + '\u{FF41}' => &['\u{0061}'], + '\u{FF42}' => &['\u{0062}'], + '\u{FF43}' => &['\u{0063}'], + '\u{FF44}' => &['\u{0064}'], + '\u{FF45}' => &['\u{0065}'], + '\u{FF46}' => &['\u{0066}'], + '\u{FF47}' => &['\u{0067}'], + '\u{FF48}' => &['\u{0068}'], + '\u{FF49}' => &['\u{0069}'], + '\u{FF4A}' => &['\u{006A}'], + '\u{FF4B}' => &['\u{006B}'], + '\u{FF4C}' => &['\u{006C}'], + '\u{FF4D}' => &['\u{006D}'], + '\u{FF4E}' => &['\u{006E}'], + '\u{FF4F}' => &['\u{006F}'], + '\u{FF50}' => &['\u{0070}'], + '\u{FF51}' => &['\u{0071}'], + '\u{FF52}' => &['\u{0072}'], + '\u{FF53}' => &['\u{0073}'], + '\u{FF54}' => &['\u{0074}'], + '\u{FF55}' => &['\u{0075}'], + '\u{FF56}' => &['\u{0076}'], + '\u{FF57}' => &['\u{0077}'], + '\u{FF58}' => &['\u{0078}'], + '\u{FF59}' => &['\u{0079}'], + '\u{FF5A}' => &['\u{007A}'], + '\u{FF5B}' => &['\u{007B}'], + '\u{FF5C}' => &['\u{007C}'], + '\u{FF5D}' => &['\u{007D}'], + '\u{FF5E}' => &['\u{007E}'], + '\u{FF5F}' => &['\u{2985}'], + '\u{FF60}' => &['\u{2986}'], + '\u{FF61}' => &['\u{3002}'], + '\u{FF62}' => &['\u{300C}'], + '\u{FF63}' => &['\u{300D}'], + '\u{FF64}' => &['\u{3001}'], + '\u{FF65}' => &['\u{30FB}'], + '\u{FF66}' => &['\u{30F2}'], + '\u{FF67}' => &['\u{30A1}'], + '\u{FF68}' => &['\u{30A3}'], + '\u{FF69}' => &['\u{30A5}'], + '\u{FF6A}' => &['\u{30A7}'], + '\u{FF6B}' => &['\u{30A9}'], + '\u{FF6C}' => &['\u{30E3}'], + '\u{FF6D}' => &['\u{30E5}'], + '\u{FF6E}' => &['\u{30E7}'], + '\u{FF6F}' => &['\u{30C3}'], + '\u{FF70}' => &['\u{30FC}'], + '\u{FF71}' => &['\u{30A2}'], + '\u{FF72}' => &['\u{30A4}'], + '\u{FF73}' => &['\u{30A6}'], + '\u{FF74}' => &['\u{30A8}'], + '\u{FF75}' => &['\u{30AA}'], + '\u{FF76}' => &['\u{30AB}'], + '\u{FF77}' => &['\u{30AD}'], + '\u{FF78}' => &['\u{30AF}'], + '\u{FF79}' => &['\u{30B1}'], + '\u{FF7A}' => &['\u{30B3}'], + '\u{FF7B}' => &['\u{30B5}'], + '\u{FF7C}' => &['\u{30B7}'], + '\u{FF7D}' => &['\u{30B9}'], + '\u{FF7E}' => &['\u{30BB}'], + '\u{FF7F}' => &['\u{30BD}'], + '\u{FF80}' => &['\u{30BF}'], + '\u{FF81}' => &['\u{30C1}'], + '\u{FF82}' => &['\u{30C4}'], + '\u{FF83}' => &['\u{30C6}'], + '\u{FF84}' => &['\u{30C8}'], + '\u{FF85}' => &['\u{30CA}'], + '\u{FF86}' => &['\u{30CB}'], + '\u{FF87}' => &['\u{30CC}'], + '\u{FF88}' => &['\u{30CD}'], + '\u{FF89}' => &['\u{30CE}'], + '\u{FF8A}' => &['\u{30CF}'], + '\u{FF8B}' => &['\u{30D2}'], + '\u{FF8C}' => &['\u{30D5}'], + '\u{FF8D}' => &['\u{30D8}'], + '\u{FF8E}' => &['\u{30DB}'], + '\u{FF8F}' => &['\u{30DE}'], + '\u{FF90}' => &['\u{30DF}'], + '\u{FF91}' => &['\u{30E0}'], + '\u{FF92}' => &['\u{30E1}'], + '\u{FF93}' => &['\u{30E2}'], + '\u{FF94}' => &['\u{30E4}'], + '\u{FF95}' => &['\u{30E6}'], + '\u{FF96}' => &['\u{30E8}'], + '\u{FF97}' => &['\u{30E9}'], + '\u{FF98}' => &['\u{30EA}'], + '\u{FF99}' => &['\u{30EB}'], + '\u{FF9A}' => &['\u{30EC}'], + '\u{FF9B}' => &['\u{30ED}'], + '\u{FF9C}' => &['\u{30EF}'], + '\u{FF9D}' => &['\u{30F3}'], + '\u{FF9E}' => &['\u{3099}'], + '\u{FF9F}' => &['\u{309A}'], + '\u{FFA0}' => &['\u{1160}'], + '\u{FFA1}' => &['\u{1100}'], + '\u{FFA2}' => &['\u{1101}'], + '\u{FFA3}' => &['\u{11AA}'], + '\u{FFA4}' => &['\u{1102}'], + '\u{FFA5}' => &['\u{11AC}'], + '\u{FFA6}' => &['\u{11AD}'], + '\u{FFA7}' => &['\u{1103}'], + '\u{FFA8}' => &['\u{1104}'], + '\u{FFA9}' => &['\u{1105}'], + '\u{FFAA}' => &['\u{11B0}'], + '\u{FFAB}' => &['\u{11B1}'], + '\u{FFAC}' => &['\u{11B2}'], + '\u{FFAD}' => &['\u{11B3}'], + '\u{FFAE}' => &['\u{11B4}'], + '\u{FFAF}' => &['\u{11B5}'], + '\u{FFB0}' => &['\u{111A}'], + '\u{FFB1}' => &['\u{1106}'], + '\u{FFB2}' => &['\u{1107}'], + '\u{FFB3}' => &['\u{1108}'], + '\u{FFB4}' => &['\u{1121}'], + '\u{FFB5}' => &['\u{1109}'], + '\u{FFB6}' => &['\u{110A}'], + '\u{FFB7}' => &['\u{110B}'], + '\u{FFB8}' => &['\u{110C}'], + '\u{FFB9}' => &['\u{110D}'], + '\u{FFBA}' => &['\u{110E}'], + '\u{FFBB}' => &['\u{110F}'], + '\u{FFBC}' => &['\u{1110}'], + '\u{FFBD}' => &['\u{1111}'], + '\u{FFBE}' => &['\u{1112}'], + '\u{FFC2}' => &['\u{1161}'], + '\u{FFC3}' => &['\u{1162}'], + '\u{FFC4}' => &['\u{1163}'], + '\u{FFC5}' => &['\u{1164}'], + '\u{FFC6}' => &['\u{1165}'], + '\u{FFC7}' => &['\u{1166}'], + '\u{FFCA}' => &['\u{1167}'], + '\u{FFCB}' => &['\u{1168}'], + '\u{FFCC}' => &['\u{1169}'], + '\u{FFCD}' => &['\u{116A}'], + '\u{FFCE}' => &['\u{116B}'], + '\u{FFCF}' => &['\u{116C}'], + '\u{FFD2}' => &['\u{116D}'], + '\u{FFD3}' => &['\u{116E}'], + '\u{FFD4}' => &['\u{116F}'], + '\u{FFD5}' => &['\u{1170}'], + '\u{FFD6}' => &['\u{1171}'], + '\u{FFD7}' => &['\u{1172}'], + '\u{FFDA}' => &['\u{1173}'], + '\u{FFDB}' => &['\u{1174}'], + '\u{FFDC}' => &['\u{1175}'], + '\u{FFE0}' => &['\u{00A2}'], + '\u{FFE1}' => &['\u{00A3}'], + '\u{FFE2}' => &['\u{00AC}'], + '\u{FFE3}' => &['\u{0020}', '\u{0304}'], + '\u{FFE4}' => &['\u{00A6}'], + '\u{FFE5}' => &['\u{00A5}'], + '\u{FFE6}' => &['\u{20A9}'], + '\u{FFE8}' => &['\u{2502}'], + '\u{FFE9}' => &['\u{2190}'], + '\u{FFEA}' => &['\u{2191}'], + '\u{FFEB}' => &['\u{2192}'], + '\u{FFEC}' => &['\u{2193}'], + '\u{FFED}' => &['\u{25A0}'], + '\u{FFEE}' => &['\u{25CB}'], + '\u{1D400}' => &['\u{0041}'], + '\u{1D401}' => &['\u{0042}'], + '\u{1D402}' => &['\u{0043}'], + '\u{1D403}' => &['\u{0044}'], + '\u{1D404}' => &['\u{0045}'], + '\u{1D405}' => &['\u{0046}'], + '\u{1D406}' => &['\u{0047}'], + '\u{1D407}' => &['\u{0048}'], + '\u{1D408}' => &['\u{0049}'], + '\u{1D409}' => &['\u{004A}'], + '\u{1D40A}' => &['\u{004B}'], + '\u{1D40B}' => &['\u{004C}'], + '\u{1D40C}' => &['\u{004D}'], + '\u{1D40D}' => &['\u{004E}'], + '\u{1D40E}' => &['\u{004F}'], + '\u{1D40F}' => &['\u{0050}'], + '\u{1D410}' => &['\u{0051}'], + '\u{1D411}' => &['\u{0052}'], + '\u{1D412}' => &['\u{0053}'], + '\u{1D413}' => &['\u{0054}'], + '\u{1D414}' => &['\u{0055}'], + '\u{1D415}' => &['\u{0056}'], + '\u{1D416}' => &['\u{0057}'], + '\u{1D417}' => &['\u{0058}'], + '\u{1D418}' => &['\u{0059}'], + '\u{1D419}' => &['\u{005A}'], + '\u{1D41A}' => &['\u{0061}'], + '\u{1D41B}' => &['\u{0062}'], + '\u{1D41C}' => &['\u{0063}'], + '\u{1D41D}' => &['\u{0064}'], + '\u{1D41E}' => &['\u{0065}'], + '\u{1D41F}' => &['\u{0066}'], + '\u{1D420}' => &['\u{0067}'], + '\u{1D421}' => &['\u{0068}'], + '\u{1D422}' => &['\u{0069}'], + '\u{1D423}' => &['\u{006A}'], + '\u{1D424}' => &['\u{006B}'], + '\u{1D425}' => &['\u{006C}'], + '\u{1D426}' => &['\u{006D}'], + '\u{1D427}' => &['\u{006E}'], + '\u{1D428}' => &['\u{006F}'], + '\u{1D429}' => &['\u{0070}'], + '\u{1D42A}' => &['\u{0071}'], + '\u{1D42B}' => &['\u{0072}'], + '\u{1D42C}' => &['\u{0073}'], + '\u{1D42D}' => &['\u{0074}'], + '\u{1D42E}' => &['\u{0075}'], + '\u{1D42F}' => &['\u{0076}'], + '\u{1D430}' => &['\u{0077}'], + '\u{1D431}' => &['\u{0078}'], + '\u{1D432}' => &['\u{0079}'], + '\u{1D433}' => &['\u{007A}'], + '\u{1D434}' => &['\u{0041}'], + '\u{1D435}' => &['\u{0042}'], + '\u{1D436}' => &['\u{0043}'], + '\u{1D437}' => &['\u{0044}'], + '\u{1D438}' => &['\u{0045}'], + '\u{1D439}' => &['\u{0046}'], + '\u{1D43A}' => &['\u{0047}'], + '\u{1D43B}' => &['\u{0048}'], + '\u{1D43C}' => &['\u{0049}'], + '\u{1D43D}' => &['\u{004A}'], + '\u{1D43E}' => &['\u{004B}'], + '\u{1D43F}' => &['\u{004C}'], + '\u{1D440}' => &['\u{004D}'], + '\u{1D441}' => &['\u{004E}'], + '\u{1D442}' => &['\u{004F}'], + '\u{1D443}' => &['\u{0050}'], + '\u{1D444}' => &['\u{0051}'], + '\u{1D445}' => &['\u{0052}'], + '\u{1D446}' => &['\u{0053}'], + '\u{1D447}' => &['\u{0054}'], + '\u{1D448}' => &['\u{0055}'], + '\u{1D449}' => &['\u{0056}'], + '\u{1D44A}' => &['\u{0057}'], + '\u{1D44B}' => &['\u{0058}'], + '\u{1D44C}' => &['\u{0059}'], + '\u{1D44D}' => &['\u{005A}'], + '\u{1D44E}' => &['\u{0061}'], + '\u{1D44F}' => &['\u{0062}'], + '\u{1D450}' => &['\u{0063}'], + '\u{1D451}' => &['\u{0064}'], + '\u{1D452}' => &['\u{0065}'], + '\u{1D453}' => &['\u{0066}'], + '\u{1D454}' => &['\u{0067}'], + '\u{1D456}' => &['\u{0069}'], + '\u{1D457}' => &['\u{006A}'], + '\u{1D458}' => &['\u{006B}'], + '\u{1D459}' => &['\u{006C}'], + '\u{1D45A}' => &['\u{006D}'], + '\u{1D45B}' => &['\u{006E}'], + '\u{1D45C}' => &['\u{006F}'], + '\u{1D45D}' => &['\u{0070}'], + '\u{1D45E}' => &['\u{0071}'], + '\u{1D45F}' => &['\u{0072}'], + '\u{1D460}' => &['\u{0073}'], + '\u{1D461}' => &['\u{0074}'], + '\u{1D462}' => &['\u{0075}'], + '\u{1D463}' => &['\u{0076}'], + '\u{1D464}' => &['\u{0077}'], + '\u{1D465}' => &['\u{0078}'], + '\u{1D466}' => &['\u{0079}'], + '\u{1D467}' => &['\u{007A}'], + '\u{1D468}' => &['\u{0041}'], + '\u{1D469}' => &['\u{0042}'], + '\u{1D46A}' => &['\u{0043}'], + '\u{1D46B}' => &['\u{0044}'], + '\u{1D46C}' => &['\u{0045}'], + '\u{1D46D}' => &['\u{0046}'], + '\u{1D46E}' => &['\u{0047}'], + '\u{1D46F}' => &['\u{0048}'], + '\u{1D470}' => &['\u{0049}'], + '\u{1D471}' => &['\u{004A}'], + '\u{1D472}' => &['\u{004B}'], + '\u{1D473}' => &['\u{004C}'], + '\u{1D474}' => &['\u{004D}'], + '\u{1D475}' => &['\u{004E}'], + '\u{1D476}' => &['\u{004F}'], + '\u{1D477}' => &['\u{0050}'], + '\u{1D478}' => &['\u{0051}'], + '\u{1D479}' => &['\u{0052}'], + '\u{1D47A}' => &['\u{0053}'], + '\u{1D47B}' => &['\u{0054}'], + '\u{1D47C}' => &['\u{0055}'], + '\u{1D47D}' => &['\u{0056}'], + '\u{1D47E}' => &['\u{0057}'], + '\u{1D47F}' => &['\u{0058}'], + '\u{1D480}' => &['\u{0059}'], + '\u{1D481}' => &['\u{005A}'], + '\u{1D482}' => &['\u{0061}'], + '\u{1D483}' => &['\u{0062}'], + '\u{1D484}' => &['\u{0063}'], + '\u{1D485}' => &['\u{0064}'], + '\u{1D486}' => &['\u{0065}'], + '\u{1D487}' => &['\u{0066}'], + '\u{1D488}' => &['\u{0067}'], + '\u{1D489}' => &['\u{0068}'], + '\u{1D48A}' => &['\u{0069}'], + '\u{1D48B}' => &['\u{006A}'], + '\u{1D48C}' => &['\u{006B}'], + '\u{1D48D}' => &['\u{006C}'], + '\u{1D48E}' => &['\u{006D}'], + '\u{1D48F}' => &['\u{006E}'], + '\u{1D490}' => &['\u{006F}'], + '\u{1D491}' => &['\u{0070}'], + '\u{1D492}' => &['\u{0071}'], + '\u{1D493}' => &['\u{0072}'], + '\u{1D494}' => &['\u{0073}'], + '\u{1D495}' => &['\u{0074}'], + '\u{1D496}' => &['\u{0075}'], + '\u{1D497}' => &['\u{0076}'], + '\u{1D498}' => &['\u{0077}'], + '\u{1D499}' => &['\u{0078}'], + '\u{1D49A}' => &['\u{0079}'], + '\u{1D49B}' => &['\u{007A}'], + '\u{1D49C}' => &['\u{0041}'], + '\u{1D49E}' => &['\u{0043}'], + '\u{1D49F}' => &['\u{0044}'], + '\u{1D4A2}' => &['\u{0047}'], + '\u{1D4A5}' => &['\u{004A}'], + '\u{1D4A6}' => &['\u{004B}'], + '\u{1D4A9}' => &['\u{004E}'], + '\u{1D4AA}' => &['\u{004F}'], + '\u{1D4AB}' => &['\u{0050}'], + '\u{1D4AC}' => &['\u{0051}'], + '\u{1D4AE}' => &['\u{0053}'], + '\u{1D4AF}' => &['\u{0054}'], + '\u{1D4B0}' => &['\u{0055}'], + '\u{1D4B1}' => &['\u{0056}'], + '\u{1D4B2}' => &['\u{0057}'], + '\u{1D4B3}' => &['\u{0058}'], + '\u{1D4B4}' => &['\u{0059}'], + '\u{1D4B5}' => &['\u{005A}'], + '\u{1D4B6}' => &['\u{0061}'], + '\u{1D4B7}' => &['\u{0062}'], + '\u{1D4B8}' => &['\u{0063}'], + '\u{1D4B9}' => &['\u{0064}'], + '\u{1D4BB}' => &['\u{0066}'], + '\u{1D4BD}' => &['\u{0068}'], + '\u{1D4BE}' => &['\u{0069}'], + '\u{1D4BF}' => &['\u{006A}'], + '\u{1D4C0}' => &['\u{006B}'], + '\u{1D4C1}' => &['\u{006C}'], + '\u{1D4C2}' => &['\u{006D}'], + '\u{1D4C3}' => &['\u{006E}'], + '\u{1D4C5}' => &['\u{0070}'], + '\u{1D4C6}' => &['\u{0071}'], + '\u{1D4C7}' => &['\u{0072}'], + '\u{1D4C8}' => &['\u{0073}'], + '\u{1D4C9}' => &['\u{0074}'], + '\u{1D4CA}' => &['\u{0075}'], + '\u{1D4CB}' => &['\u{0076}'], + '\u{1D4CC}' => &['\u{0077}'], + '\u{1D4CD}' => &['\u{0078}'], + '\u{1D4CE}' => &['\u{0079}'], + '\u{1D4CF}' => &['\u{007A}'], + '\u{1D4D0}' => &['\u{0041}'], + '\u{1D4D1}' => &['\u{0042}'], + '\u{1D4D2}' => &['\u{0043}'], + '\u{1D4D3}' => &['\u{0044}'], + '\u{1D4D4}' => &['\u{0045}'], + '\u{1D4D5}' => &['\u{0046}'], + '\u{1D4D6}' => &['\u{0047}'], + '\u{1D4D7}' => &['\u{0048}'], + '\u{1D4D8}' => &['\u{0049}'], + '\u{1D4D9}' => &['\u{004A}'], + '\u{1D4DA}' => &['\u{004B}'], + '\u{1D4DB}' => &['\u{004C}'], + '\u{1D4DC}' => &['\u{004D}'], + '\u{1D4DD}' => &['\u{004E}'], + '\u{1D4DE}' => &['\u{004F}'], + '\u{1D4DF}' => &['\u{0050}'], + '\u{1D4E0}' => &['\u{0051}'], + '\u{1D4E1}' => &['\u{0052}'], + '\u{1D4E2}' => &['\u{0053}'], + '\u{1D4E3}' => &['\u{0054}'], + '\u{1D4E4}' => &['\u{0055}'], + '\u{1D4E5}' => &['\u{0056}'], + '\u{1D4E6}' => &['\u{0057}'], + '\u{1D4E7}' => &['\u{0058}'], + '\u{1D4E8}' => &['\u{0059}'], + '\u{1D4E9}' => &['\u{005A}'], + '\u{1D4EA}' => &['\u{0061}'], + '\u{1D4EB}' => &['\u{0062}'], + '\u{1D4EC}' => &['\u{0063}'], + '\u{1D4ED}' => &['\u{0064}'], + '\u{1D4EE}' => &['\u{0065}'], + '\u{1D4EF}' => &['\u{0066}'], + '\u{1D4F0}' => &['\u{0067}'], + '\u{1D4F1}' => &['\u{0068}'], + '\u{1D4F2}' => &['\u{0069}'], + '\u{1D4F3}' => &['\u{006A}'], + '\u{1D4F4}' => &['\u{006B}'], + '\u{1D4F5}' => &['\u{006C}'], + '\u{1D4F6}' => &['\u{006D}'], + '\u{1D4F7}' => &['\u{006E}'], + '\u{1D4F8}' => &['\u{006F}'], + '\u{1D4F9}' => &['\u{0070}'], + '\u{1D4FA}' => &['\u{0071}'], + '\u{1D4FB}' => &['\u{0072}'], + '\u{1D4FC}' => &['\u{0073}'], + '\u{1D4FD}' => &['\u{0074}'], + '\u{1D4FE}' => &['\u{0075}'], + '\u{1D4FF}' => &['\u{0076}'], + '\u{1D500}' => &['\u{0077}'], + '\u{1D501}' => &['\u{0078}'], + '\u{1D502}' => &['\u{0079}'], + '\u{1D503}' => &['\u{007A}'], + '\u{1D504}' => &['\u{0041}'], + '\u{1D505}' => &['\u{0042}'], + '\u{1D507}' => &['\u{0044}'], + '\u{1D508}' => &['\u{0045}'], + '\u{1D509}' => &['\u{0046}'], + '\u{1D50A}' => &['\u{0047}'], + '\u{1D50D}' => &['\u{004A}'], + '\u{1D50E}' => &['\u{004B}'], + '\u{1D50F}' => &['\u{004C}'], + '\u{1D510}' => &['\u{004D}'], + '\u{1D511}' => &['\u{004E}'], + '\u{1D512}' => &['\u{004F}'], + '\u{1D513}' => &['\u{0050}'], + '\u{1D514}' => &['\u{0051}'], + '\u{1D516}' => &['\u{0053}'], + '\u{1D517}' => &['\u{0054}'], + '\u{1D518}' => &['\u{0055}'], + '\u{1D519}' => &['\u{0056}'], + '\u{1D51A}' => &['\u{0057}'], + '\u{1D51B}' => &['\u{0058}'], + '\u{1D51C}' => &['\u{0059}'], + '\u{1D51E}' => &['\u{0061}'], + '\u{1D51F}' => &['\u{0062}'], + '\u{1D520}' => &['\u{0063}'], + '\u{1D521}' => &['\u{0064}'], + '\u{1D522}' => &['\u{0065}'], + '\u{1D523}' => &['\u{0066}'], + '\u{1D524}' => &['\u{0067}'], + '\u{1D525}' => &['\u{0068}'], + '\u{1D526}' => &['\u{0069}'], + '\u{1D527}' => &['\u{006A}'], + '\u{1D528}' => &['\u{006B}'], + '\u{1D529}' => &['\u{006C}'], + '\u{1D52A}' => &['\u{006D}'], + '\u{1D52B}' => &['\u{006E}'], + '\u{1D52C}' => &['\u{006F}'], + '\u{1D52D}' => &['\u{0070}'], + '\u{1D52E}' => &['\u{0071}'], + '\u{1D52F}' => &['\u{0072}'], + '\u{1D530}' => &['\u{0073}'], + '\u{1D531}' => &['\u{0074}'], + '\u{1D532}' => &['\u{0075}'], + '\u{1D533}' => &['\u{0076}'], + '\u{1D534}' => &['\u{0077}'], + '\u{1D535}' => &['\u{0078}'], + '\u{1D536}' => &['\u{0079}'], + '\u{1D537}' => &['\u{007A}'], + '\u{1D538}' => &['\u{0041}'], + '\u{1D539}' => &['\u{0042}'], + '\u{1D53B}' => &['\u{0044}'], + '\u{1D53C}' => &['\u{0045}'], + '\u{1D53D}' => &['\u{0046}'], + '\u{1D53E}' => &['\u{0047}'], + '\u{1D540}' => &['\u{0049}'], + '\u{1D541}' => &['\u{004A}'], + '\u{1D542}' => &['\u{004B}'], + '\u{1D543}' => &['\u{004C}'], + '\u{1D544}' => &['\u{004D}'], + '\u{1D546}' => &['\u{004F}'], + '\u{1D54A}' => &['\u{0053}'], + '\u{1D54B}' => &['\u{0054}'], + '\u{1D54C}' => &['\u{0055}'], + '\u{1D54D}' => &['\u{0056}'], + '\u{1D54E}' => &['\u{0057}'], + '\u{1D54F}' => &['\u{0058}'], + '\u{1D550}' => &['\u{0059}'], + '\u{1D552}' => &['\u{0061}'], + '\u{1D553}' => &['\u{0062}'], + '\u{1D554}' => &['\u{0063}'], + '\u{1D555}' => &['\u{0064}'], + '\u{1D556}' => &['\u{0065}'], + '\u{1D557}' => &['\u{0066}'], + '\u{1D558}' => &['\u{0067}'], + '\u{1D559}' => &['\u{0068}'], + '\u{1D55A}' => &['\u{0069}'], + '\u{1D55B}' => &['\u{006A}'], + '\u{1D55C}' => &['\u{006B}'], + '\u{1D55D}' => &['\u{006C}'], + '\u{1D55E}' => &['\u{006D}'], + '\u{1D55F}' => &['\u{006E}'], + '\u{1D560}' => &['\u{006F}'], + '\u{1D561}' => &['\u{0070}'], + '\u{1D562}' => &['\u{0071}'], + '\u{1D563}' => &['\u{0072}'], + '\u{1D564}' => &['\u{0073}'], + '\u{1D565}' => &['\u{0074}'], + '\u{1D566}' => &['\u{0075}'], + '\u{1D567}' => &['\u{0076}'], + '\u{1D568}' => &['\u{0077}'], + '\u{1D569}' => &['\u{0078}'], + '\u{1D56A}' => &['\u{0079}'], + '\u{1D56B}' => &['\u{007A}'], + '\u{1D56C}' => &['\u{0041}'], + '\u{1D56D}' => &['\u{0042}'], + '\u{1D56E}' => &['\u{0043}'], + '\u{1D56F}' => &['\u{0044}'], + '\u{1D570}' => &['\u{0045}'], + '\u{1D571}' => &['\u{0046}'], + '\u{1D572}' => &['\u{0047}'], + '\u{1D573}' => &['\u{0048}'], + '\u{1D574}' => &['\u{0049}'], + '\u{1D575}' => &['\u{004A}'], + '\u{1D576}' => &['\u{004B}'], + '\u{1D577}' => &['\u{004C}'], + '\u{1D578}' => &['\u{004D}'], + '\u{1D579}' => &['\u{004E}'], + '\u{1D57A}' => &['\u{004F}'], + '\u{1D57B}' => &['\u{0050}'], + '\u{1D57C}' => &['\u{0051}'], + '\u{1D57D}' => &['\u{0052}'], + '\u{1D57E}' => &['\u{0053}'], + '\u{1D57F}' => &['\u{0054}'], + '\u{1D580}' => &['\u{0055}'], + '\u{1D581}' => &['\u{0056}'], + '\u{1D582}' => &['\u{0057}'], + '\u{1D583}' => &['\u{0058}'], + '\u{1D584}' => &['\u{0059}'], + '\u{1D585}' => &['\u{005A}'], + '\u{1D586}' => &['\u{0061}'], + '\u{1D587}' => &['\u{0062}'], + '\u{1D588}' => &['\u{0063}'], + '\u{1D589}' => &['\u{0064}'], + '\u{1D58A}' => &['\u{0065}'], + '\u{1D58B}' => &['\u{0066}'], + '\u{1D58C}' => &['\u{0067}'], + '\u{1D58D}' => &['\u{0068}'], + '\u{1D58E}' => &['\u{0069}'], + '\u{1D58F}' => &['\u{006A}'], + '\u{1D590}' => &['\u{006B}'], + '\u{1D591}' => &['\u{006C}'], + '\u{1D592}' => &['\u{006D}'], + '\u{1D593}' => &['\u{006E}'], + '\u{1D594}' => &['\u{006F}'], + '\u{1D595}' => &['\u{0070}'], + '\u{1D596}' => &['\u{0071}'], + '\u{1D597}' => &['\u{0072}'], + '\u{1D598}' => &['\u{0073}'], + '\u{1D599}' => &['\u{0074}'], + '\u{1D59A}' => &['\u{0075}'], + '\u{1D59B}' => &['\u{0076}'], + '\u{1D59C}' => &['\u{0077}'], + '\u{1D59D}' => &['\u{0078}'], + '\u{1D59E}' => &['\u{0079}'], + '\u{1D59F}' => &['\u{007A}'], + '\u{1D5A0}' => &['\u{0041}'], + '\u{1D5A1}' => &['\u{0042}'], + '\u{1D5A2}' => &['\u{0043}'], + '\u{1D5A3}' => &['\u{0044}'], + '\u{1D5A4}' => &['\u{0045}'], + '\u{1D5A5}' => &['\u{0046}'], + '\u{1D5A6}' => &['\u{0047}'], + '\u{1D5A7}' => &['\u{0048}'], + '\u{1D5A8}' => &['\u{0049}'], + '\u{1D5A9}' => &['\u{004A}'], + '\u{1D5AA}' => &['\u{004B}'], + '\u{1D5AB}' => &['\u{004C}'], + '\u{1D5AC}' => &['\u{004D}'], + '\u{1D5AD}' => &['\u{004E}'], + '\u{1D5AE}' => &['\u{004F}'], + '\u{1D5AF}' => &['\u{0050}'], + '\u{1D5B0}' => &['\u{0051}'], + '\u{1D5B1}' => &['\u{0052}'], + '\u{1D5B2}' => &['\u{0053}'], + '\u{1D5B3}' => &['\u{0054}'], + '\u{1D5B4}' => &['\u{0055}'], + '\u{1D5B5}' => &['\u{0056}'], + '\u{1D5B6}' => &['\u{0057}'], + '\u{1D5B7}' => &['\u{0058}'], + '\u{1D5B8}' => &['\u{0059}'], + '\u{1D5B9}' => &['\u{005A}'], + '\u{1D5BA}' => &['\u{0061}'], + '\u{1D5BB}' => &['\u{0062}'], + '\u{1D5BC}' => &['\u{0063}'], + '\u{1D5BD}' => &['\u{0064}'], + '\u{1D5BE}' => &['\u{0065}'], + '\u{1D5BF}' => &['\u{0066}'], + '\u{1D5C0}' => &['\u{0067}'], + '\u{1D5C1}' => &['\u{0068}'], + '\u{1D5C2}' => &['\u{0069}'], + '\u{1D5C3}' => &['\u{006A}'], + '\u{1D5C4}' => &['\u{006B}'], + '\u{1D5C5}' => &['\u{006C}'], + '\u{1D5C6}' => &['\u{006D}'], + '\u{1D5C7}' => &['\u{006E}'], + '\u{1D5C8}' => &['\u{006F}'], + '\u{1D5C9}' => &['\u{0070}'], + '\u{1D5CA}' => &['\u{0071}'], + '\u{1D5CB}' => &['\u{0072}'], + '\u{1D5CC}' => &['\u{0073}'], + '\u{1D5CD}' => &['\u{0074}'], + '\u{1D5CE}' => &['\u{0075}'], + '\u{1D5CF}' => &['\u{0076}'], + '\u{1D5D0}' => &['\u{0077}'], + '\u{1D5D1}' => &['\u{0078}'], + '\u{1D5D2}' => &['\u{0079}'], + '\u{1D5D3}' => &['\u{007A}'], + '\u{1D5D4}' => &['\u{0041}'], + '\u{1D5D5}' => &['\u{0042}'], + '\u{1D5D6}' => &['\u{0043}'], + '\u{1D5D7}' => &['\u{0044}'], + '\u{1D5D8}' => &['\u{0045}'], + '\u{1D5D9}' => &['\u{0046}'], + '\u{1D5DA}' => &['\u{0047}'], + '\u{1D5DB}' => &['\u{0048}'], + '\u{1D5DC}' => &['\u{0049}'], + '\u{1D5DD}' => &['\u{004A}'], + '\u{1D5DE}' => &['\u{004B}'], + '\u{1D5DF}' => &['\u{004C}'], + '\u{1D5E0}' => &['\u{004D}'], + '\u{1D5E1}' => &['\u{004E}'], + '\u{1D5E2}' => &['\u{004F}'], + '\u{1D5E3}' => &['\u{0050}'], + '\u{1D5E4}' => &['\u{0051}'], + '\u{1D5E5}' => &['\u{0052}'], + '\u{1D5E6}' => &['\u{0053}'], + '\u{1D5E7}' => &['\u{0054}'], + '\u{1D5E8}' => &['\u{0055}'], + '\u{1D5E9}' => &['\u{0056}'], + '\u{1D5EA}' => &['\u{0057}'], + '\u{1D5EB}' => &['\u{0058}'], + '\u{1D5EC}' => &['\u{0059}'], + '\u{1D5ED}' => &['\u{005A}'], + '\u{1D5EE}' => &['\u{0061}'], + '\u{1D5EF}' => &['\u{0062}'], + '\u{1D5F0}' => &['\u{0063}'], + '\u{1D5F1}' => &['\u{0064}'], + '\u{1D5F2}' => &['\u{0065}'], + '\u{1D5F3}' => &['\u{0066}'], + '\u{1D5F4}' => &['\u{0067}'], + '\u{1D5F5}' => &['\u{0068}'], + '\u{1D5F6}' => &['\u{0069}'], + '\u{1D5F7}' => &['\u{006A}'], + '\u{1D5F8}' => &['\u{006B}'], + '\u{1D5F9}' => &['\u{006C}'], + '\u{1D5FA}' => &['\u{006D}'], + '\u{1D5FB}' => &['\u{006E}'], + '\u{1D5FC}' => &['\u{006F}'], + '\u{1D5FD}' => &['\u{0070}'], + '\u{1D5FE}' => &['\u{0071}'], + '\u{1D5FF}' => &['\u{0072}'], + '\u{1D600}' => &['\u{0073}'], + '\u{1D601}' => &['\u{0074}'], + '\u{1D602}' => &['\u{0075}'], + '\u{1D603}' => &['\u{0076}'], + '\u{1D604}' => &['\u{0077}'], + '\u{1D605}' => &['\u{0078}'], + '\u{1D606}' => &['\u{0079}'], + '\u{1D607}' => &['\u{007A}'], + '\u{1D608}' => &['\u{0041}'], + '\u{1D609}' => &['\u{0042}'], + '\u{1D60A}' => &['\u{0043}'], + '\u{1D60B}' => &['\u{0044}'], + '\u{1D60C}' => &['\u{0045}'], + '\u{1D60D}' => &['\u{0046}'], + '\u{1D60E}' => &['\u{0047}'], + '\u{1D60F}' => &['\u{0048}'], + '\u{1D610}' => &['\u{0049}'], + '\u{1D611}' => &['\u{004A}'], + '\u{1D612}' => &['\u{004B}'], + '\u{1D613}' => &['\u{004C}'], + '\u{1D614}' => &['\u{004D}'], + '\u{1D615}' => &['\u{004E}'], + '\u{1D616}' => &['\u{004F}'], + '\u{1D617}' => &['\u{0050}'], + '\u{1D618}' => &['\u{0051}'], + '\u{1D619}' => &['\u{0052}'], + '\u{1D61A}' => &['\u{0053}'], + '\u{1D61B}' => &['\u{0054}'], + '\u{1D61C}' => &['\u{0055}'], + '\u{1D61D}' => &['\u{0056}'], + '\u{1D61E}' => &['\u{0057}'], + '\u{1D61F}' => &['\u{0058}'], + '\u{1D620}' => &['\u{0059}'], + '\u{1D621}' => &['\u{005A}'], + '\u{1D622}' => &['\u{0061}'], + '\u{1D623}' => &['\u{0062}'], + '\u{1D624}' => &['\u{0063}'], + '\u{1D625}' => &['\u{0064}'], + '\u{1D626}' => &['\u{0065}'], + '\u{1D627}' => &['\u{0066}'], + '\u{1D628}' => &['\u{0067}'], + '\u{1D629}' => &['\u{0068}'], + '\u{1D62A}' => &['\u{0069}'], + '\u{1D62B}' => &['\u{006A}'], + '\u{1D62C}' => &['\u{006B}'], + '\u{1D62D}' => &['\u{006C}'], + '\u{1D62E}' => &['\u{006D}'], + '\u{1D62F}' => &['\u{006E}'], + '\u{1D630}' => &['\u{006F}'], + '\u{1D631}' => &['\u{0070}'], + '\u{1D632}' => &['\u{0071}'], + '\u{1D633}' => &['\u{0072}'], + '\u{1D634}' => &['\u{0073}'], + '\u{1D635}' => &['\u{0074}'], + '\u{1D636}' => &['\u{0075}'], + '\u{1D637}' => &['\u{0076}'], + '\u{1D638}' => &['\u{0077}'], + '\u{1D639}' => &['\u{0078}'], + '\u{1D63A}' => &['\u{0079}'], + '\u{1D63B}' => &['\u{007A}'], + '\u{1D63C}' => &['\u{0041}'], + '\u{1D63D}' => &['\u{0042}'], + '\u{1D63E}' => &['\u{0043}'], + '\u{1D63F}' => &['\u{0044}'], + '\u{1D640}' => &['\u{0045}'], + '\u{1D641}' => &['\u{0046}'], + '\u{1D642}' => &['\u{0047}'], + '\u{1D643}' => &['\u{0048}'], + '\u{1D644}' => &['\u{0049}'], + '\u{1D645}' => &['\u{004A}'], + '\u{1D646}' => &['\u{004B}'], + '\u{1D647}' => &['\u{004C}'], + '\u{1D648}' => &['\u{004D}'], + '\u{1D649}' => &['\u{004E}'], + '\u{1D64A}' => &['\u{004F}'], + '\u{1D64B}' => &['\u{0050}'], + '\u{1D64C}' => &['\u{0051}'], + '\u{1D64D}' => &['\u{0052}'], + '\u{1D64E}' => &['\u{0053}'], + '\u{1D64F}' => &['\u{0054}'], + '\u{1D650}' => &['\u{0055}'], + '\u{1D651}' => &['\u{0056}'], + '\u{1D652}' => &['\u{0057}'], + '\u{1D653}' => &['\u{0058}'], + '\u{1D654}' => &['\u{0059}'], + '\u{1D655}' => &['\u{005A}'], + '\u{1D656}' => &['\u{0061}'], + '\u{1D657}' => &['\u{0062}'], + '\u{1D658}' => &['\u{0063}'], + '\u{1D659}' => &['\u{0064}'], + '\u{1D65A}' => &['\u{0065}'], + '\u{1D65B}' => &['\u{0066}'], + '\u{1D65C}' => &['\u{0067}'], + '\u{1D65D}' => &['\u{0068}'], + '\u{1D65E}' => &['\u{0069}'], + '\u{1D65F}' => &['\u{006A}'], + '\u{1D660}' => &['\u{006B}'], + '\u{1D661}' => &['\u{006C}'], + '\u{1D662}' => &['\u{006D}'], + '\u{1D663}' => &['\u{006E}'], + '\u{1D664}' => &['\u{006F}'], + '\u{1D665}' => &['\u{0070}'], + '\u{1D666}' => &['\u{0071}'], + '\u{1D667}' => &['\u{0072}'], + '\u{1D668}' => &['\u{0073}'], + '\u{1D669}' => &['\u{0074}'], + '\u{1D66A}' => &['\u{0075}'], + '\u{1D66B}' => &['\u{0076}'], + '\u{1D66C}' => &['\u{0077}'], + '\u{1D66D}' => &['\u{0078}'], + '\u{1D66E}' => &['\u{0079}'], + '\u{1D66F}' => &['\u{007A}'], + '\u{1D670}' => &['\u{0041}'], + '\u{1D671}' => &['\u{0042}'], + '\u{1D672}' => &['\u{0043}'], + '\u{1D673}' => &['\u{0044}'], + '\u{1D674}' => &['\u{0045}'], + '\u{1D675}' => &['\u{0046}'], + '\u{1D676}' => &['\u{0047}'], + '\u{1D677}' => &['\u{0048}'], + '\u{1D678}' => &['\u{0049}'], + '\u{1D679}' => &['\u{004A}'], + '\u{1D67A}' => &['\u{004B}'], + '\u{1D67B}' => &['\u{004C}'], + '\u{1D67C}' => &['\u{004D}'], + '\u{1D67D}' => &['\u{004E}'], + '\u{1D67E}' => &['\u{004F}'], + '\u{1D67F}' => &['\u{0050}'], + '\u{1D680}' => &['\u{0051}'], + '\u{1D681}' => &['\u{0052}'], + '\u{1D682}' => &['\u{0053}'], + '\u{1D683}' => &['\u{0054}'], + '\u{1D684}' => &['\u{0055}'], + '\u{1D685}' => &['\u{0056}'], + '\u{1D686}' => &['\u{0057}'], + '\u{1D687}' => &['\u{0058}'], + '\u{1D688}' => &['\u{0059}'], + '\u{1D689}' => &['\u{005A}'], + '\u{1D68A}' => &['\u{0061}'], + '\u{1D68B}' => &['\u{0062}'], + '\u{1D68C}' => &['\u{0063}'], + '\u{1D68D}' => &['\u{0064}'], + '\u{1D68E}' => &['\u{0065}'], + '\u{1D68F}' => &['\u{0066}'], + '\u{1D690}' => &['\u{0067}'], + '\u{1D691}' => &['\u{0068}'], + '\u{1D692}' => &['\u{0069}'], + '\u{1D693}' => &['\u{006A}'], + '\u{1D694}' => &['\u{006B}'], + '\u{1D695}' => &['\u{006C}'], + '\u{1D696}' => &['\u{006D}'], + '\u{1D697}' => &['\u{006E}'], + '\u{1D698}' => &['\u{006F}'], + '\u{1D699}' => &['\u{0070}'], + '\u{1D69A}' => &['\u{0071}'], + '\u{1D69B}' => &['\u{0072}'], + '\u{1D69C}' => &['\u{0073}'], + '\u{1D69D}' => &['\u{0074}'], + '\u{1D69E}' => &['\u{0075}'], + '\u{1D69F}' => &['\u{0076}'], + '\u{1D6A0}' => &['\u{0077}'], + '\u{1D6A1}' => &['\u{0078}'], + '\u{1D6A2}' => &['\u{0079}'], + '\u{1D6A3}' => &['\u{007A}'], + '\u{1D6A4}' => &['\u{0131}'], + '\u{1D6A5}' => &['\u{0237}'], + '\u{1D6A8}' => &['\u{0391}'], + '\u{1D6A9}' => &['\u{0392}'], + '\u{1D6AA}' => &['\u{0393}'], + '\u{1D6AB}' => &['\u{0394}'], + '\u{1D6AC}' => &['\u{0395}'], + '\u{1D6AD}' => &['\u{0396}'], + '\u{1D6AE}' => &['\u{0397}'], + '\u{1D6AF}' => &['\u{0398}'], + '\u{1D6B0}' => &['\u{0399}'], + '\u{1D6B1}' => &['\u{039A}'], + '\u{1D6B2}' => &['\u{039B}'], + '\u{1D6B3}' => &['\u{039C}'], + '\u{1D6B4}' => &['\u{039D}'], + '\u{1D6B5}' => &['\u{039E}'], + '\u{1D6B6}' => &['\u{039F}'], + '\u{1D6B7}' => &['\u{03A0}'], + '\u{1D6B8}' => &['\u{03A1}'], + '\u{1D6B9}' => &['\u{0398}'], + '\u{1D6BA}' => &['\u{03A3}'], + '\u{1D6BB}' => &['\u{03A4}'], + '\u{1D6BC}' => &['\u{03A5}'], + '\u{1D6BD}' => &['\u{03A6}'], + '\u{1D6BE}' => &['\u{03A7}'], + '\u{1D6BF}' => &['\u{03A8}'], + '\u{1D6C0}' => &['\u{03A9}'], + '\u{1D6C1}' => &['\u{2207}'], + '\u{1D6C2}' => &['\u{03B1}'], + '\u{1D6C3}' => &['\u{03B2}'], + '\u{1D6C4}' => &['\u{03B3}'], + '\u{1D6C5}' => &['\u{03B4}'], + '\u{1D6C6}' => &['\u{03B5}'], + '\u{1D6C7}' => &['\u{03B6}'], + '\u{1D6C8}' => &['\u{03B7}'], + '\u{1D6C9}' => &['\u{03B8}'], + '\u{1D6CA}' => &['\u{03B9}'], + '\u{1D6CB}' => &['\u{03BA}'], + '\u{1D6CC}' => &['\u{03BB}'], + '\u{1D6CD}' => &['\u{03BC}'], + '\u{1D6CE}' => &['\u{03BD}'], + '\u{1D6CF}' => &['\u{03BE}'], + '\u{1D6D0}' => &['\u{03BF}'], + '\u{1D6D1}' => &['\u{03C0}'], + '\u{1D6D2}' => &['\u{03C1}'], + '\u{1D6D3}' => &['\u{03C2}'], + '\u{1D6D4}' => &['\u{03C3}'], + '\u{1D6D5}' => &['\u{03C4}'], + '\u{1D6D6}' => &['\u{03C5}'], + '\u{1D6D7}' => &['\u{03C6}'], + '\u{1D6D8}' => &['\u{03C7}'], + '\u{1D6D9}' => &['\u{03C8}'], + '\u{1D6DA}' => &['\u{03C9}'], + '\u{1D6DB}' => &['\u{2202}'], + '\u{1D6DC}' => &['\u{03B5}'], + '\u{1D6DD}' => &['\u{03B8}'], + '\u{1D6DE}' => &['\u{03BA}'], + '\u{1D6DF}' => &['\u{03C6}'], + '\u{1D6E0}' => &['\u{03C1}'], + '\u{1D6E1}' => &['\u{03C0}'], + '\u{1D6E2}' => &['\u{0391}'], + '\u{1D6E3}' => &['\u{0392}'], + '\u{1D6E4}' => &['\u{0393}'], + '\u{1D6E5}' => &['\u{0394}'], + '\u{1D6E6}' => &['\u{0395}'], + '\u{1D6E7}' => &['\u{0396}'], + '\u{1D6E8}' => &['\u{0397}'], + '\u{1D6E9}' => &['\u{0398}'], + '\u{1D6EA}' => &['\u{0399}'], + '\u{1D6EB}' => &['\u{039A}'], + '\u{1D6EC}' => &['\u{039B}'], + '\u{1D6ED}' => &['\u{039C}'], + '\u{1D6EE}' => &['\u{039D}'], + '\u{1D6EF}' => &['\u{039E}'], + '\u{1D6F0}' => &['\u{039F}'], + '\u{1D6F1}' => &['\u{03A0}'], + '\u{1D6F2}' => &['\u{03A1}'], + '\u{1D6F3}' => &['\u{0398}'], + '\u{1D6F4}' => &['\u{03A3}'], + '\u{1D6F5}' => &['\u{03A4}'], + '\u{1D6F6}' => &['\u{03A5}'], + '\u{1D6F7}' => &['\u{03A6}'], + '\u{1D6F8}' => &['\u{03A7}'], + '\u{1D6F9}' => &['\u{03A8}'], + '\u{1D6FA}' => &['\u{03A9}'], + '\u{1D6FB}' => &['\u{2207}'], + '\u{1D6FC}' => &['\u{03B1}'], + '\u{1D6FD}' => &['\u{03B2}'], + '\u{1D6FE}' => &['\u{03B3}'], + '\u{1D6FF}' => &['\u{03B4}'], + '\u{1D700}' => &['\u{03B5}'], + '\u{1D701}' => &['\u{03B6}'], + '\u{1D702}' => &['\u{03B7}'], + '\u{1D703}' => &['\u{03B8}'], + '\u{1D704}' => &['\u{03B9}'], + '\u{1D705}' => &['\u{03BA}'], + '\u{1D706}' => &['\u{03BB}'], + '\u{1D707}' => &['\u{03BC}'], + '\u{1D708}' => &['\u{03BD}'], + '\u{1D709}' => &['\u{03BE}'], + '\u{1D70A}' => &['\u{03BF}'], + '\u{1D70B}' => &['\u{03C0}'], + '\u{1D70C}' => &['\u{03C1}'], + '\u{1D70D}' => &['\u{03C2}'], + '\u{1D70E}' => &['\u{03C3}'], + '\u{1D70F}' => &['\u{03C4}'], + '\u{1D710}' => &['\u{03C5}'], + '\u{1D711}' => &['\u{03C6}'], + '\u{1D712}' => &['\u{03C7}'], + '\u{1D713}' => &['\u{03C8}'], + '\u{1D714}' => &['\u{03C9}'], + '\u{1D715}' => &['\u{2202}'], + '\u{1D716}' => &['\u{03B5}'], + '\u{1D717}' => &['\u{03B8}'], + '\u{1D718}' => &['\u{03BA}'], + '\u{1D719}' => &['\u{03C6}'], + '\u{1D71A}' => &['\u{03C1}'], + '\u{1D71B}' => &['\u{03C0}'], + '\u{1D71C}' => &['\u{0391}'], + '\u{1D71D}' => &['\u{0392}'], + '\u{1D71E}' => &['\u{0393}'], + '\u{1D71F}' => &['\u{0394}'], + '\u{1D720}' => &['\u{0395}'], + '\u{1D721}' => &['\u{0396}'], + '\u{1D722}' => &['\u{0397}'], + '\u{1D723}' => &['\u{0398}'], + '\u{1D724}' => &['\u{0399}'], + '\u{1D725}' => &['\u{039A}'], + '\u{1D726}' => &['\u{039B}'], + '\u{1D727}' => &['\u{039C}'], + '\u{1D728}' => &['\u{039D}'], + '\u{1D729}' => &['\u{039E}'], + '\u{1D72A}' => &['\u{039F}'], + '\u{1D72B}' => &['\u{03A0}'], + '\u{1D72C}' => &['\u{03A1}'], + '\u{1D72D}' => &['\u{0398}'], + '\u{1D72E}' => &['\u{03A3}'], + '\u{1D72F}' => &['\u{03A4}'], + '\u{1D730}' => &['\u{03A5}'], + '\u{1D731}' => &['\u{03A6}'], + '\u{1D732}' => &['\u{03A7}'], + '\u{1D733}' => &['\u{03A8}'], + '\u{1D734}' => &['\u{03A9}'], + '\u{1D735}' => &['\u{2207}'], + '\u{1D736}' => &['\u{03B1}'], + '\u{1D737}' => &['\u{03B2}'], + '\u{1D738}' => &['\u{03B3}'], + '\u{1D739}' => &['\u{03B4}'], + '\u{1D73A}' => &['\u{03B5}'], + '\u{1D73B}' => &['\u{03B6}'], + '\u{1D73C}' => &['\u{03B7}'], + '\u{1D73D}' => &['\u{03B8}'], + '\u{1D73E}' => &['\u{03B9}'], + '\u{1D73F}' => &['\u{03BA}'], + '\u{1D740}' => &['\u{03BB}'], + '\u{1D741}' => &['\u{03BC}'], + '\u{1D742}' => &['\u{03BD}'], + '\u{1D743}' => &['\u{03BE}'], + '\u{1D744}' => &['\u{03BF}'], + '\u{1D745}' => &['\u{03C0}'], + '\u{1D746}' => &['\u{03C1}'], + '\u{1D747}' => &['\u{03C2}'], + '\u{1D748}' => &['\u{03C3}'], + '\u{1D749}' => &['\u{03C4}'], + '\u{1D74A}' => &['\u{03C5}'], + '\u{1D74B}' => &['\u{03C6}'], + '\u{1D74C}' => &['\u{03C7}'], + '\u{1D74D}' => &['\u{03C8}'], + '\u{1D74E}' => &['\u{03C9}'], + '\u{1D74F}' => &['\u{2202}'], + '\u{1D750}' => &['\u{03B5}'], + '\u{1D751}' => &['\u{03B8}'], + '\u{1D752}' => &['\u{03BA}'], + '\u{1D753}' => &['\u{03C6}'], + '\u{1D754}' => &['\u{03C1}'], + '\u{1D755}' => &['\u{03C0}'], + '\u{1D756}' => &['\u{0391}'], + '\u{1D757}' => &['\u{0392}'], + '\u{1D758}' => &['\u{0393}'], + '\u{1D759}' => &['\u{0394}'], + '\u{1D75A}' => &['\u{0395}'], + '\u{1D75B}' => &['\u{0396}'], + '\u{1D75C}' => &['\u{0397}'], + '\u{1D75D}' => &['\u{0398}'], + '\u{1D75E}' => &['\u{0399}'], + '\u{1D75F}' => &['\u{039A}'], + '\u{1D760}' => &['\u{039B}'], + '\u{1D761}' => &['\u{039C}'], + '\u{1D762}' => &['\u{039D}'], + '\u{1D763}' => &['\u{039E}'], + '\u{1D764}' => &['\u{039F}'], + '\u{1D765}' => &['\u{03A0}'], + '\u{1D766}' => &['\u{03A1}'], + '\u{1D767}' => &['\u{0398}'], + '\u{1D768}' => &['\u{03A3}'], + '\u{1D769}' => &['\u{03A4}'], + '\u{1D76A}' => &['\u{03A5}'], + '\u{1D76B}' => &['\u{03A6}'], + '\u{1D76C}' => &['\u{03A7}'], + '\u{1D76D}' => &['\u{03A8}'], + '\u{1D76E}' => &['\u{03A9}'], + '\u{1D76F}' => &['\u{2207}'], + '\u{1D770}' => &['\u{03B1}'], + '\u{1D771}' => &['\u{03B2}'], + '\u{1D772}' => &['\u{03B3}'], + '\u{1D773}' => &['\u{03B4}'], + '\u{1D774}' => &['\u{03B5}'], + '\u{1D775}' => &['\u{03B6}'], + '\u{1D776}' => &['\u{03B7}'], + '\u{1D777}' => &['\u{03B8}'], + '\u{1D778}' => &['\u{03B9}'], + '\u{1D779}' => &['\u{03BA}'], + '\u{1D77A}' => &['\u{03BB}'], + '\u{1D77B}' => &['\u{03BC}'], + '\u{1D77C}' => &['\u{03BD}'], + '\u{1D77D}' => &['\u{03BE}'], + '\u{1D77E}' => &['\u{03BF}'], + '\u{1D77F}' => &['\u{03C0}'], + '\u{1D780}' => &['\u{03C1}'], + '\u{1D781}' => &['\u{03C2}'], + '\u{1D782}' => &['\u{03C3}'], + '\u{1D783}' => &['\u{03C4}'], + '\u{1D784}' => &['\u{03C5}'], + '\u{1D785}' => &['\u{03C6}'], + '\u{1D786}' => &['\u{03C7}'], + '\u{1D787}' => &['\u{03C8}'], + '\u{1D788}' => &['\u{03C9}'], + '\u{1D789}' => &['\u{2202}'], + '\u{1D78A}' => &['\u{03B5}'], + '\u{1D78B}' => &['\u{03B8}'], + '\u{1D78C}' => &['\u{03BA}'], + '\u{1D78D}' => &['\u{03C6}'], + '\u{1D78E}' => &['\u{03C1}'], + '\u{1D78F}' => &['\u{03C0}'], + '\u{1D790}' => &['\u{0391}'], + '\u{1D791}' => &['\u{0392}'], + '\u{1D792}' => &['\u{0393}'], + '\u{1D793}' => &['\u{0394}'], + '\u{1D794}' => &['\u{0395}'], + '\u{1D795}' => &['\u{0396}'], + '\u{1D796}' => &['\u{0397}'], + '\u{1D797}' => &['\u{0398}'], + '\u{1D798}' => &['\u{0399}'], + '\u{1D799}' => &['\u{039A}'], + '\u{1D79A}' => &['\u{039B}'], + '\u{1D79B}' => &['\u{039C}'], + '\u{1D79C}' => &['\u{039D}'], + '\u{1D79D}' => &['\u{039E}'], + '\u{1D79E}' => &['\u{039F}'], + '\u{1D79F}' => &['\u{03A0}'], + '\u{1D7A0}' => &['\u{03A1}'], + '\u{1D7A1}' => &['\u{0398}'], + '\u{1D7A2}' => &['\u{03A3}'], + '\u{1D7A3}' => &['\u{03A4}'], + '\u{1D7A4}' => &['\u{03A5}'], + '\u{1D7A5}' => &['\u{03A6}'], + '\u{1D7A6}' => &['\u{03A7}'], + '\u{1D7A7}' => &['\u{03A8}'], + '\u{1D7A8}' => &['\u{03A9}'], + '\u{1D7A9}' => &['\u{2207}'], + '\u{1D7AA}' => &['\u{03B1}'], + '\u{1D7AB}' => &['\u{03B2}'], + '\u{1D7AC}' => &['\u{03B3}'], + '\u{1D7AD}' => &['\u{03B4}'], + '\u{1D7AE}' => &['\u{03B5}'], + '\u{1D7AF}' => &['\u{03B6}'], + '\u{1D7B0}' => &['\u{03B7}'], + '\u{1D7B1}' => &['\u{03B8}'], + '\u{1D7B2}' => &['\u{03B9}'], + '\u{1D7B3}' => &['\u{03BA}'], + '\u{1D7B4}' => &['\u{03BB}'], + '\u{1D7B5}' => &['\u{03BC}'], + '\u{1D7B6}' => &['\u{03BD}'], + '\u{1D7B7}' => &['\u{03BE}'], + '\u{1D7B8}' => &['\u{03BF}'], + '\u{1D7B9}' => &['\u{03C0}'], + '\u{1D7BA}' => &['\u{03C1}'], + '\u{1D7BB}' => &['\u{03C2}'], + '\u{1D7BC}' => &['\u{03C3}'], + '\u{1D7BD}' => &['\u{03C4}'], + '\u{1D7BE}' => &['\u{03C5}'], + '\u{1D7BF}' => &['\u{03C6}'], + '\u{1D7C0}' => &['\u{03C7}'], + '\u{1D7C1}' => &['\u{03C8}'], + '\u{1D7C2}' => &['\u{03C9}'], + '\u{1D7C3}' => &['\u{2202}'], + '\u{1D7C4}' => &['\u{03B5}'], + '\u{1D7C5}' => &['\u{03B8}'], + '\u{1D7C6}' => &['\u{03BA}'], + '\u{1D7C7}' => &['\u{03C6}'], + '\u{1D7C8}' => &['\u{03C1}'], + '\u{1D7C9}' => &['\u{03C0}'], + '\u{1D7CA}' => &['\u{03DC}'], + '\u{1D7CB}' => &['\u{03DD}'], + '\u{1D7CE}' => &['\u{0030}'], + '\u{1D7CF}' => &['\u{0031}'], + '\u{1D7D0}' => &['\u{0032}'], + '\u{1D7D1}' => &['\u{0033}'], + '\u{1D7D2}' => &['\u{0034}'], + '\u{1D7D3}' => &['\u{0035}'], + '\u{1D7D4}' => &['\u{0036}'], + '\u{1D7D5}' => &['\u{0037}'], + '\u{1D7D6}' => &['\u{0038}'], + '\u{1D7D7}' => &['\u{0039}'], + '\u{1D7D8}' => &['\u{0030}'], + '\u{1D7D9}' => &['\u{0031}'], + '\u{1D7DA}' => &['\u{0032}'], + '\u{1D7DB}' => &['\u{0033}'], + '\u{1D7DC}' => &['\u{0034}'], + '\u{1D7DD}' => &['\u{0035}'], + '\u{1D7DE}' => &['\u{0036}'], + '\u{1D7DF}' => &['\u{0037}'], + '\u{1D7E0}' => &['\u{0038}'], + '\u{1D7E1}' => &['\u{0039}'], + '\u{1D7E2}' => &['\u{0030}'], + '\u{1D7E3}' => &['\u{0031}'], + '\u{1D7E4}' => &['\u{0032}'], + '\u{1D7E5}' => &['\u{0033}'], + '\u{1D7E6}' => &['\u{0034}'], + '\u{1D7E7}' => &['\u{0035}'], + '\u{1D7E8}' => &['\u{0036}'], + '\u{1D7E9}' => &['\u{0037}'], + '\u{1D7EA}' => &['\u{0038}'], + '\u{1D7EB}' => &['\u{0039}'], + '\u{1D7EC}' => &['\u{0030}'], + '\u{1D7ED}' => &['\u{0031}'], + '\u{1D7EE}' => &['\u{0032}'], + '\u{1D7EF}' => &['\u{0033}'], + '\u{1D7F0}' => &['\u{0034}'], + '\u{1D7F1}' => &['\u{0035}'], + '\u{1D7F2}' => &['\u{0036}'], + '\u{1D7F3}' => &['\u{0037}'], + '\u{1D7F4}' => &['\u{0038}'], + '\u{1D7F5}' => &['\u{0039}'], + '\u{1D7F6}' => &['\u{0030}'], + '\u{1D7F7}' => &['\u{0031}'], + '\u{1D7F8}' => &['\u{0032}'], + '\u{1D7F9}' => &['\u{0033}'], + '\u{1D7FA}' => &['\u{0034}'], + '\u{1D7FB}' => &['\u{0035}'], + '\u{1D7FC}' => &['\u{0036}'], + '\u{1D7FD}' => &['\u{0037}'], + '\u{1D7FE}' => &['\u{0038}'], + '\u{1D7FF}' => &['\u{0039}'], + '\u{1EE00}' => &['\u{0627}'], + '\u{1EE01}' => &['\u{0628}'], + '\u{1EE02}' => &['\u{062C}'], + '\u{1EE03}' => &['\u{062F}'], + '\u{1EE05}' => &['\u{0648}'], + '\u{1EE06}' => &['\u{0632}'], + '\u{1EE07}' => &['\u{062D}'], + '\u{1EE08}' => &['\u{0637}'], + '\u{1EE09}' => &['\u{064A}'], + '\u{1EE0A}' => &['\u{0643}'], + '\u{1EE0B}' => &['\u{0644}'], + '\u{1EE0C}' => &['\u{0645}'], + '\u{1EE0D}' => &['\u{0646}'], + '\u{1EE0E}' => &['\u{0633}'], + '\u{1EE0F}' => &['\u{0639}'], + '\u{1EE10}' => &['\u{0641}'], + '\u{1EE11}' => &['\u{0635}'], + '\u{1EE12}' => &['\u{0642}'], + '\u{1EE13}' => &['\u{0631}'], + '\u{1EE14}' => &['\u{0634}'], + '\u{1EE15}' => &['\u{062A}'], + '\u{1EE16}' => &['\u{062B}'], + '\u{1EE17}' => &['\u{062E}'], + '\u{1EE18}' => &['\u{0630}'], + '\u{1EE19}' => &['\u{0636}'], + '\u{1EE1A}' => &['\u{0638}'], + '\u{1EE1B}' => &['\u{063A}'], + '\u{1EE1C}' => &['\u{066E}'], + '\u{1EE1D}' => &['\u{06BA}'], + '\u{1EE1E}' => &['\u{06A1}'], + '\u{1EE1F}' => &['\u{066F}'], + '\u{1EE21}' => &['\u{0628}'], + '\u{1EE22}' => &['\u{062C}'], + '\u{1EE24}' => &['\u{0647}'], + '\u{1EE27}' => &['\u{062D}'], + '\u{1EE29}' => &['\u{064A}'], + '\u{1EE2A}' => &['\u{0643}'], + '\u{1EE2B}' => &['\u{0644}'], + '\u{1EE2C}' => &['\u{0645}'], + '\u{1EE2D}' => &['\u{0646}'], + '\u{1EE2E}' => &['\u{0633}'], + '\u{1EE2F}' => &['\u{0639}'], + '\u{1EE30}' => &['\u{0641}'], + '\u{1EE31}' => &['\u{0635}'], + '\u{1EE32}' => &['\u{0642}'], + '\u{1EE34}' => &['\u{0634}'], + '\u{1EE35}' => &['\u{062A}'], + '\u{1EE36}' => &['\u{062B}'], + '\u{1EE37}' => &['\u{062E}'], + '\u{1EE39}' => &['\u{0636}'], + '\u{1EE3B}' => &['\u{063A}'], + '\u{1EE42}' => &['\u{062C}'], + '\u{1EE47}' => &['\u{062D}'], + '\u{1EE49}' => &['\u{064A}'], + '\u{1EE4B}' => &['\u{0644}'], + '\u{1EE4D}' => &['\u{0646}'], + '\u{1EE4E}' => &['\u{0633}'], + '\u{1EE4F}' => &['\u{0639}'], + '\u{1EE51}' => &['\u{0635}'], + '\u{1EE52}' => &['\u{0642}'], + '\u{1EE54}' => &['\u{0634}'], + '\u{1EE57}' => &['\u{062E}'], + '\u{1EE59}' => &['\u{0636}'], + '\u{1EE5B}' => &['\u{063A}'], + '\u{1EE5D}' => &['\u{06BA}'], + '\u{1EE5F}' => &['\u{066F}'], + '\u{1EE61}' => &['\u{0628}'], + '\u{1EE62}' => &['\u{062C}'], + '\u{1EE64}' => &['\u{0647}'], + '\u{1EE67}' => &['\u{062D}'], + '\u{1EE68}' => &['\u{0637}'], + '\u{1EE69}' => &['\u{064A}'], + '\u{1EE6A}' => &['\u{0643}'], + '\u{1EE6C}' => &['\u{0645}'], + '\u{1EE6D}' => &['\u{0646}'], + '\u{1EE6E}' => &['\u{0633}'], + '\u{1EE6F}' => &['\u{0639}'], + '\u{1EE70}' => &['\u{0641}'], + '\u{1EE71}' => &['\u{0635}'], + '\u{1EE72}' => &['\u{0642}'], + '\u{1EE74}' => &['\u{0634}'], + '\u{1EE75}' => &['\u{062A}'], + '\u{1EE76}' => &['\u{062B}'], + '\u{1EE77}' => &['\u{062E}'], + '\u{1EE79}' => &['\u{0636}'], + '\u{1EE7A}' => &['\u{0638}'], + '\u{1EE7B}' => &['\u{063A}'], + '\u{1EE7C}' => &['\u{066E}'], + '\u{1EE7E}' => &['\u{06A1}'], + '\u{1EE80}' => &['\u{0627}'], + '\u{1EE81}' => &['\u{0628}'], + '\u{1EE82}' => &['\u{062C}'], + '\u{1EE83}' => &['\u{062F}'], + '\u{1EE84}' => &['\u{0647}'], + '\u{1EE85}' => &['\u{0648}'], + '\u{1EE86}' => &['\u{0632}'], + '\u{1EE87}' => &['\u{062D}'], + '\u{1EE88}' => &['\u{0637}'], + '\u{1EE89}' => &['\u{064A}'], + '\u{1EE8B}' => &['\u{0644}'], + '\u{1EE8C}' => &['\u{0645}'], + '\u{1EE8D}' => &['\u{0646}'], + '\u{1EE8E}' => &['\u{0633}'], + '\u{1EE8F}' => &['\u{0639}'], + '\u{1EE90}' => &['\u{0641}'], + '\u{1EE91}' => &['\u{0635}'], + '\u{1EE92}' => &['\u{0642}'], + '\u{1EE93}' => &['\u{0631}'], + '\u{1EE94}' => &['\u{0634}'], + '\u{1EE95}' => &['\u{062A}'], + '\u{1EE96}' => &['\u{062B}'], + '\u{1EE97}' => &['\u{062E}'], + '\u{1EE98}' => &['\u{0630}'], + '\u{1EE99}' => &['\u{0636}'], + '\u{1EE9A}' => &['\u{0638}'], + '\u{1EE9B}' => &['\u{063A}'], + '\u{1EEA1}' => &['\u{0628}'], + '\u{1EEA2}' => &['\u{062C}'], + '\u{1EEA3}' => &['\u{062F}'], + '\u{1EEA5}' => &['\u{0648}'], + '\u{1EEA6}' => &['\u{0632}'], + '\u{1EEA7}' => &['\u{062D}'], + '\u{1EEA8}' => &['\u{0637}'], + '\u{1EEA9}' => &['\u{064A}'], + '\u{1EEAB}' => &['\u{0644}'], + '\u{1EEAC}' => &['\u{0645}'], + '\u{1EEAD}' => &['\u{0646}'], + '\u{1EEAE}' => &['\u{0633}'], + '\u{1EEAF}' => &['\u{0639}'], + '\u{1EEB0}' => &['\u{0641}'], + '\u{1EEB1}' => &['\u{0635}'], + '\u{1EEB2}' => &['\u{0642}'], + '\u{1EEB3}' => &['\u{0631}'], + '\u{1EEB4}' => &['\u{0634}'], + '\u{1EEB5}' => &['\u{062A}'], + '\u{1EEB6}' => &['\u{062B}'], + '\u{1EEB7}' => &['\u{062E}'], + '\u{1EEB8}' => &['\u{0630}'], + '\u{1EEB9}' => &['\u{0636}'], + '\u{1EEBA}' => &['\u{0638}'], + '\u{1EEBB}' => &['\u{063A}'], + '\u{1F100}' => &['\u{0030}', '\u{002E}'], + '\u{1F101}' => &['\u{0030}', '\u{002C}'], + '\u{1F102}' => &['\u{0031}', '\u{002C}'], + '\u{1F103}' => &['\u{0032}', '\u{002C}'], + '\u{1F104}' => &['\u{0033}', '\u{002C}'], + '\u{1F105}' => &['\u{0034}', '\u{002C}'], + '\u{1F106}' => &['\u{0035}', '\u{002C}'], + '\u{1F107}' => &['\u{0036}', '\u{002C}'], + '\u{1F108}' => &['\u{0037}', '\u{002C}'], + '\u{1F109}' => &['\u{0038}', '\u{002C}'], + '\u{1F10A}' => &['\u{0039}', '\u{002C}'], + '\u{1F110}' => &['\u{0028}', '\u{0041}', '\u{0029}'], + '\u{1F111}' => &['\u{0028}', '\u{0042}', '\u{0029}'], + '\u{1F112}' => &['\u{0028}', '\u{0043}', '\u{0029}'], + '\u{1F113}' => &['\u{0028}', '\u{0044}', '\u{0029}'], + '\u{1F114}' => &['\u{0028}', '\u{0045}', '\u{0029}'], + '\u{1F115}' => &['\u{0028}', '\u{0046}', '\u{0029}'], + '\u{1F116}' => &['\u{0028}', '\u{0047}', '\u{0029}'], + '\u{1F117}' => &['\u{0028}', '\u{0048}', '\u{0029}'], + '\u{1F118}' => &['\u{0028}', '\u{0049}', '\u{0029}'], + '\u{1F119}' => &['\u{0028}', '\u{004A}', '\u{0029}'], + '\u{1F11A}' => &['\u{0028}', '\u{004B}', '\u{0029}'], + '\u{1F11B}' => &['\u{0028}', '\u{004C}', '\u{0029}'], + '\u{1F11C}' => &['\u{0028}', '\u{004D}', '\u{0029}'], + '\u{1F11D}' => &['\u{0028}', '\u{004E}', '\u{0029}'], + '\u{1F11E}' => &['\u{0028}', '\u{004F}', '\u{0029}'], + '\u{1F11F}' => &['\u{0028}', '\u{0050}', '\u{0029}'], + '\u{1F120}' => &['\u{0028}', '\u{0051}', '\u{0029}'], + '\u{1F121}' => &['\u{0028}', '\u{0052}', '\u{0029}'], + '\u{1F122}' => &['\u{0028}', '\u{0053}', '\u{0029}'], + '\u{1F123}' => &['\u{0028}', '\u{0054}', '\u{0029}'], + '\u{1F124}' => &['\u{0028}', '\u{0055}', '\u{0029}'], + '\u{1F125}' => &['\u{0028}', '\u{0056}', '\u{0029}'], + '\u{1F126}' => &['\u{0028}', '\u{0057}', '\u{0029}'], + '\u{1F127}' => &['\u{0028}', '\u{0058}', '\u{0029}'], + '\u{1F128}' => &['\u{0028}', '\u{0059}', '\u{0029}'], + '\u{1F129}' => &['\u{0028}', '\u{005A}', '\u{0029}'], + '\u{1F12A}' => &['\u{3014}', '\u{0053}', '\u{3015}'], + '\u{1F12B}' => &['\u{0043}'], + '\u{1F12C}' => &['\u{0052}'], + '\u{1F12D}' => &['\u{0043}', '\u{0044}'], + '\u{1F12E}' => &['\u{0057}', '\u{005A}'], + '\u{1F130}' => &['\u{0041}'], + '\u{1F131}' => &['\u{0042}'], + '\u{1F132}' => &['\u{0043}'], + '\u{1F133}' => &['\u{0044}'], + '\u{1F134}' => &['\u{0045}'], + '\u{1F135}' => &['\u{0046}'], + '\u{1F136}' => &['\u{0047}'], + '\u{1F137}' => &['\u{0048}'], + '\u{1F138}' => &['\u{0049}'], + '\u{1F139}' => &['\u{004A}'], + '\u{1F13A}' => &['\u{004B}'], + '\u{1F13B}' => &['\u{004C}'], + '\u{1F13C}' => &['\u{004D}'], + '\u{1F13D}' => &['\u{004E}'], + '\u{1F13E}' => &['\u{004F}'], + '\u{1F13F}' => &['\u{0050}'], + '\u{1F140}' => &['\u{0051}'], + '\u{1F141}' => &['\u{0052}'], + '\u{1F142}' => &['\u{0053}'], + '\u{1F143}' => &['\u{0054}'], + '\u{1F144}' => &['\u{0055}'], + '\u{1F145}' => &['\u{0056}'], + '\u{1F146}' => &['\u{0057}'], + '\u{1F147}' => &['\u{0058}'], + '\u{1F148}' => &['\u{0059}'], + '\u{1F149}' => &['\u{005A}'], + '\u{1F14A}' => &['\u{0048}', '\u{0056}'], + '\u{1F14B}' => &['\u{004D}', '\u{0056}'], + '\u{1F14C}' => &['\u{0053}', '\u{0044}'], + '\u{1F14D}' => &['\u{0053}', '\u{0053}'], + '\u{1F14E}' => &['\u{0050}', '\u{0050}', '\u{0056}'], + '\u{1F14F}' => &['\u{0057}', '\u{0043}'], + '\u{1F16A}' => &['\u{004D}', '\u{0043}'], + '\u{1F16B}' => &['\u{004D}', '\u{0044}'], + '\u{1F190}' => &['\u{0044}', '\u{004A}'], + '\u{1F200}' => &['\u{307B}', '\u{304B}'], + '\u{1F201}' => &['\u{30B3}', '\u{30B3}'], + '\u{1F202}' => &['\u{30B5}'], + '\u{1F210}' => &['\u{624B}'], + '\u{1F211}' => &['\u{5B57}'], + '\u{1F212}' => &['\u{53CC}'], + '\u{1F213}' => &['\u{30C6}', '\u{3099}'], + '\u{1F214}' => &['\u{4E8C}'], + '\u{1F215}' => &['\u{591A}'], + '\u{1F216}' => &['\u{89E3}'], + '\u{1F217}' => &['\u{5929}'], + '\u{1F218}' => &['\u{4EA4}'], + '\u{1F219}' => &['\u{6620}'], + '\u{1F21A}' => &['\u{7121}'], + '\u{1F21B}' => &['\u{6599}'], + '\u{1F21C}' => &['\u{524D}'], + '\u{1F21D}' => &['\u{5F8C}'], + '\u{1F21E}' => &['\u{518D}'], + '\u{1F21F}' => &['\u{65B0}'], + '\u{1F220}' => &['\u{521D}'], + '\u{1F221}' => &['\u{7D42}'], + '\u{1F222}' => &['\u{751F}'], + '\u{1F223}' => &['\u{8CA9}'], + '\u{1F224}' => &['\u{58F0}'], + '\u{1F225}' => &['\u{5439}'], + '\u{1F226}' => &['\u{6F14}'], + '\u{1F227}' => &['\u{6295}'], + '\u{1F228}' => &['\u{6355}'], + '\u{1F229}' => &['\u{4E00}'], + '\u{1F22A}' => &['\u{4E09}'], + '\u{1F22B}' => &['\u{904A}'], + '\u{1F22C}' => &['\u{5DE6}'], + '\u{1F22D}' => &['\u{4E2D}'], + '\u{1F22E}' => &['\u{53F3}'], + '\u{1F22F}' => &['\u{6307}'], + '\u{1F230}' => &['\u{8D70}'], + '\u{1F231}' => &['\u{6253}'], + '\u{1F232}' => &['\u{7981}'], + '\u{1F233}' => &['\u{7A7A}'], + '\u{1F234}' => &['\u{5408}'], + '\u{1F235}' => &['\u{6E80}'], + '\u{1F236}' => &['\u{6709}'], + '\u{1F237}' => &['\u{6708}'], + '\u{1F238}' => &['\u{7533}'], + '\u{1F239}' => &['\u{5272}'], + '\u{1F23A}' => &['\u{55B6}'], + '\u{1F23B}' => &['\u{914D}'], + '\u{1F240}' => &['\u{3014}', '\u{672C}', '\u{3015}'], + '\u{1F241}' => &['\u{3014}', '\u{4E09}', '\u{3015}'], + '\u{1F242}' => &['\u{3014}', '\u{4E8C}', '\u{3015}'], + '\u{1F243}' => &['\u{3014}', '\u{5B89}', '\u{3015}'], + '\u{1F244}' => &['\u{3014}', '\u{70B9}', '\u{3015}'], + '\u{1F245}' => &['\u{3014}', '\u{6253}', '\u{3015}'], + '\u{1F246}' => &['\u{3014}', '\u{76D7}', '\u{3015}'], + '\u{1F247}' => &['\u{3014}', '\u{52DD}', '\u{3015}'], + '\u{1F248}' => &['\u{3014}', '\u{6557}', '\u{3015}'], + '\u{1F250}' => &['\u{5F97}'], + '\u{1F251}' => &['\u{53EF}'], + _ => return None, + }) +} + +#[inline] +pub fn is_combining_mark(c: char) -> bool { + match c { + '\u{0300}' => true, + '\u{0301}' => true, + '\u{0302}' => true, + '\u{0303}' => true, + '\u{0304}' => true, + '\u{0305}' => true, + '\u{0306}' => true, + '\u{0307}' => true, + '\u{0308}' => true, + '\u{0309}' => true, + '\u{030A}' => true, + '\u{030B}' => true, + '\u{030C}' => true, + '\u{030D}' => true, + '\u{030E}' => true, + '\u{030F}' => true, + '\u{0310}' => true, + '\u{0311}' => true, + '\u{0312}' => true, + '\u{0313}' => true, + '\u{0314}' => true, + '\u{0315}' => true, + '\u{0316}' => true, + '\u{0317}' => true, + '\u{0318}' => true, + '\u{0319}' => true, + '\u{031A}' => true, + '\u{031B}' => true, + '\u{031C}' => true, + '\u{031D}' => true, + '\u{031E}' => true, + '\u{031F}' => true, + '\u{0320}' => true, + '\u{0321}' => true, + '\u{0322}' => true, + '\u{0323}' => true, + '\u{0324}' => true, + '\u{0325}' => true, + '\u{0326}' => true, + '\u{0327}' => true, + '\u{0328}' => true, + '\u{0329}' => true, + '\u{032A}' => true, + '\u{032B}' => true, + '\u{032C}' => true, + '\u{032D}' => true, + '\u{032E}' => true, + '\u{032F}' => true, + '\u{0330}' => true, + '\u{0331}' => true, + '\u{0332}' => true, + '\u{0333}' => true, + '\u{0334}' => true, + '\u{0335}' => true, + '\u{0336}' => true, + '\u{0337}' => true, + '\u{0338}' => true, + '\u{0339}' => true, + '\u{033A}' => true, + '\u{033B}' => true, + '\u{033C}' => true, + '\u{033D}' => true, + '\u{033E}' => true, + '\u{033F}' => true, + '\u{0340}' => true, + '\u{0341}' => true, + '\u{0342}' => true, + '\u{0343}' => true, + '\u{0344}' => true, + '\u{0345}' => true, + '\u{0346}' => true, + '\u{0347}' => true, + '\u{0348}' => true, + '\u{0349}' => true, + '\u{034A}' => true, + '\u{034B}' => true, + '\u{034C}' => true, + '\u{034D}' => true, + '\u{034E}' => true, + '\u{034F}' => true, + '\u{0350}' => true, + '\u{0351}' => true, + '\u{0352}' => true, + '\u{0353}' => true, + '\u{0354}' => true, + '\u{0355}' => true, + '\u{0356}' => true, + '\u{0357}' => true, + '\u{0358}' => true, + '\u{0359}' => true, + '\u{035A}' => true, + '\u{035B}' => true, + '\u{035C}' => true, + '\u{035D}' => true, + '\u{035E}' => true, + '\u{035F}' => true, + '\u{0360}' => true, + '\u{0361}' => true, + '\u{0362}' => true, + '\u{0363}' => true, + '\u{0364}' => true, + '\u{0365}' => true, + '\u{0366}' => true, + '\u{0367}' => true, + '\u{0368}' => true, + '\u{0369}' => true, + '\u{036A}' => true, + '\u{036B}' => true, + '\u{036C}' => true, + '\u{036D}' => true, + '\u{036E}' => true, + '\u{036F}' => true, + '\u{0483}' => true, + '\u{0484}' => true, + '\u{0485}' => true, + '\u{0486}' => true, + '\u{0487}' => true, + '\u{0488}' => true, + '\u{0489}' => true, + '\u{0591}' => true, + '\u{0592}' => true, + '\u{0593}' => true, + '\u{0594}' => true, + '\u{0595}' => true, + '\u{0596}' => true, + '\u{0597}' => true, + '\u{0598}' => true, + '\u{0599}' => true, + '\u{059A}' => true, + '\u{059B}' => true, + '\u{059C}' => true, + '\u{059D}' => true, + '\u{059E}' => true, + '\u{059F}' => true, + '\u{05A0}' => true, + '\u{05A1}' => true, + '\u{05A2}' => true, + '\u{05A3}' => true, + '\u{05A4}' => true, + '\u{05A5}' => true, + '\u{05A6}' => true, + '\u{05A7}' => true, + '\u{05A8}' => true, + '\u{05A9}' => true, + '\u{05AA}' => true, + '\u{05AB}' => true, + '\u{05AC}' => true, + '\u{05AD}' => true, + '\u{05AE}' => true, + '\u{05AF}' => true, + '\u{05B0}' => true, + '\u{05B1}' => true, + '\u{05B2}' => true, + '\u{05B3}' => true, + '\u{05B4}' => true, + '\u{05B5}' => true, + '\u{05B6}' => true, + '\u{05B7}' => true, + '\u{05B8}' => true, + '\u{05B9}' => true, + '\u{05BA}' => true, + '\u{05BB}' => true, + '\u{05BC}' => true, + '\u{05BD}' => true, + '\u{05BF}' => true, + '\u{05C1}' => true, + '\u{05C2}' => true, + '\u{05C4}' => true, + '\u{05C5}' => true, + '\u{05C7}' => true, + '\u{0610}' => true, + '\u{0611}' => true, + '\u{0612}' => true, + '\u{0613}' => true, + '\u{0614}' => true, + '\u{0615}' => true, + '\u{0616}' => true, + '\u{0617}' => true, + '\u{0618}' => true, + '\u{0619}' => true, + '\u{061A}' => true, + '\u{064B}' => true, + '\u{064C}' => true, + '\u{064D}' => true, + '\u{064E}' => true, + '\u{064F}' => true, + '\u{0650}' => true, + '\u{0651}' => true, + '\u{0652}' => true, + '\u{0653}' => true, + '\u{0654}' => true, + '\u{0655}' => true, + '\u{0656}' => true, + '\u{0657}' => true, + '\u{0658}' => true, + '\u{0659}' => true, + '\u{065A}' => true, + '\u{065B}' => true, + '\u{065C}' => true, + '\u{065D}' => true, + '\u{065E}' => true, + '\u{065F}' => true, + '\u{0670}' => true, + '\u{06D6}' => true, + '\u{06D7}' => true, + '\u{06D8}' => true, + '\u{06D9}' => true, + '\u{06DA}' => true, + '\u{06DB}' => true, + '\u{06DC}' => true, + '\u{06DF}' => true, + '\u{06E0}' => true, + '\u{06E1}' => true, + '\u{06E2}' => true, + '\u{06E3}' => true, + '\u{06E4}' => true, + '\u{06E7}' => true, + '\u{06E8}' => true, + '\u{06EA}' => true, + '\u{06EB}' => true, + '\u{06EC}' => true, + '\u{06ED}' => true, + '\u{0711}' => true, + '\u{0730}' => true, + '\u{0731}' => true, + '\u{0732}' => true, + '\u{0733}' => true, + '\u{0734}' => true, + '\u{0735}' => true, + '\u{0736}' => true, + '\u{0737}' => true, + '\u{0738}' => true, + '\u{0739}' => true, + '\u{073A}' => true, + '\u{073B}' => true, + '\u{073C}' => true, + '\u{073D}' => true, + '\u{073E}' => true, + '\u{073F}' => true, + '\u{0740}' => true, + '\u{0741}' => true, + '\u{0742}' => true, + '\u{0743}' => true, + '\u{0744}' => true, + '\u{0745}' => true, + '\u{0746}' => true, + '\u{0747}' => true, + '\u{0748}' => true, + '\u{0749}' => true, + '\u{074A}' => true, + '\u{07A6}' => true, + '\u{07A7}' => true, + '\u{07A8}' => true, + '\u{07A9}' => true, + '\u{07AA}' => true, + '\u{07AB}' => true, + '\u{07AC}' => true, + '\u{07AD}' => true, + '\u{07AE}' => true, + '\u{07AF}' => true, + '\u{07B0}' => true, + '\u{07EB}' => true, + '\u{07EC}' => true, + '\u{07ED}' => true, + '\u{07EE}' => true, + '\u{07EF}' => true, + '\u{07F0}' => true, + '\u{07F1}' => true, + '\u{07F2}' => true, + '\u{07F3}' => true, + '\u{0816}' => true, + '\u{0817}' => true, + '\u{0818}' => true, + '\u{0819}' => true, + '\u{081B}' => true, + '\u{081C}' => true, + '\u{081D}' => true, + '\u{081E}' => true, + '\u{081F}' => true, + '\u{0820}' => true, + '\u{0821}' => true, + '\u{0822}' => true, + '\u{0823}' => true, + '\u{0825}' => true, + '\u{0826}' => true, + '\u{0827}' => true, + '\u{0829}' => true, + '\u{082A}' => true, + '\u{082B}' => true, + '\u{082C}' => true, + '\u{082D}' => true, + '\u{0859}' => true, + '\u{085A}' => true, + '\u{085B}' => true, + '\u{08D4}' => true, + '\u{08D5}' => true, + '\u{08D6}' => true, + '\u{08D7}' => true, + '\u{08D8}' => true, + '\u{08D9}' => true, + '\u{08DA}' => true, + '\u{08DB}' => true, + '\u{08DC}' => true, + '\u{08DD}' => true, + '\u{08DE}' => true, + '\u{08DF}' => true, + '\u{08E0}' => true, + '\u{08E1}' => true, + '\u{08E3}' => true, + '\u{08E4}' => true, + '\u{08E5}' => true, + '\u{08E6}' => true, + '\u{08E7}' => true, + '\u{08E8}' => true, + '\u{08E9}' => true, + '\u{08EA}' => true, + '\u{08EB}' => true, + '\u{08EC}' => true, + '\u{08ED}' => true, + '\u{08EE}' => true, + '\u{08EF}' => true, + '\u{08F0}' => true, + '\u{08F1}' => true, + '\u{08F2}' => true, + '\u{08F3}' => true, + '\u{08F4}' => true, + '\u{08F5}' => true, + '\u{08F6}' => true, + '\u{08F7}' => true, + '\u{08F8}' => true, + '\u{08F9}' => true, + '\u{08FA}' => true, + '\u{08FB}' => true, + '\u{08FC}' => true, + '\u{08FD}' => true, + '\u{08FE}' => true, + '\u{08FF}' => true, + '\u{0900}' => true, + '\u{0901}' => true, + '\u{0902}' => true, + '\u{0903}' => true, + '\u{093A}' => true, + '\u{093B}' => true, + '\u{093C}' => true, + '\u{093E}' => true, + '\u{093F}' => true, + '\u{0940}' => true, + '\u{0941}' => true, + '\u{0942}' => true, + '\u{0943}' => true, + '\u{0944}' => true, + '\u{0945}' => true, + '\u{0946}' => true, + '\u{0947}' => true, + '\u{0948}' => true, + '\u{0949}' => true, + '\u{094A}' => true, + '\u{094B}' => true, + '\u{094C}' => true, + '\u{094D}' => true, + '\u{094E}' => true, + '\u{094F}' => true, + '\u{0951}' => true, + '\u{0952}' => true, + '\u{0953}' => true, + '\u{0954}' => true, + '\u{0955}' => true, + '\u{0956}' => true, + '\u{0957}' => true, + '\u{0962}' => true, + '\u{0963}' => true, + '\u{0981}' => true, + '\u{0982}' => true, + '\u{0983}' => true, + '\u{09BC}' => true, + '\u{09BE}' => true, + '\u{09BF}' => true, + '\u{09C0}' => true, + '\u{09C1}' => true, + '\u{09C2}' => true, + '\u{09C3}' => true, + '\u{09C4}' => true, + '\u{09C7}' => true, + '\u{09C8}' => true, + '\u{09CB}' => true, + '\u{09CC}' => true, + '\u{09CD}' => true, + '\u{09D7}' => true, + '\u{09E2}' => true, + '\u{09E3}' => true, + '\u{0A01}' => true, + '\u{0A02}' => true, + '\u{0A03}' => true, + '\u{0A3C}' => true, + '\u{0A3E}' => true, + '\u{0A3F}' => true, + '\u{0A40}' => true, + '\u{0A41}' => true, + '\u{0A42}' => true, + '\u{0A47}' => true, + '\u{0A48}' => true, + '\u{0A4B}' => true, + '\u{0A4C}' => true, + '\u{0A4D}' => true, + '\u{0A51}' => true, + '\u{0A70}' => true, + '\u{0A71}' => true, + '\u{0A75}' => true, + '\u{0A81}' => true, + '\u{0A82}' => true, + '\u{0A83}' => true, + '\u{0ABC}' => true, + '\u{0ABE}' => true, + '\u{0ABF}' => true, + '\u{0AC0}' => true, + '\u{0AC1}' => true, + '\u{0AC2}' => true, + '\u{0AC3}' => true, + '\u{0AC4}' => true, + '\u{0AC5}' => true, + '\u{0AC7}' => true, + '\u{0AC8}' => true, + '\u{0AC9}' => true, + '\u{0ACB}' => true, + '\u{0ACC}' => true, + '\u{0ACD}' => true, + '\u{0AE2}' => true, + '\u{0AE3}' => true, + '\u{0B01}' => true, + '\u{0B02}' => true, + '\u{0B03}' => true, + '\u{0B3C}' => true, + '\u{0B3E}' => true, + '\u{0B3F}' => true, + '\u{0B40}' => true, + '\u{0B41}' => true, + '\u{0B42}' => true, + '\u{0B43}' => true, + '\u{0B44}' => true, + '\u{0B47}' => true, + '\u{0B48}' => true, + '\u{0B4B}' => true, + '\u{0B4C}' => true, + '\u{0B4D}' => true, + '\u{0B56}' => true, + '\u{0B57}' => true, + '\u{0B62}' => true, + '\u{0B63}' => true, + '\u{0B82}' => true, + '\u{0BBE}' => true, + '\u{0BBF}' => true, + '\u{0BC0}' => true, + '\u{0BC1}' => true, + '\u{0BC2}' => true, + '\u{0BC6}' => true, + '\u{0BC7}' => true, + '\u{0BC8}' => true, + '\u{0BCA}' => true, + '\u{0BCB}' => true, + '\u{0BCC}' => true, + '\u{0BCD}' => true, + '\u{0BD7}' => true, + '\u{0C00}' => true, + '\u{0C01}' => true, + '\u{0C02}' => true, + '\u{0C03}' => true, + '\u{0C3E}' => true, + '\u{0C3F}' => true, + '\u{0C40}' => true, + '\u{0C41}' => true, + '\u{0C42}' => true, + '\u{0C43}' => true, + '\u{0C44}' => true, + '\u{0C46}' => true, + '\u{0C47}' => true, + '\u{0C48}' => true, + '\u{0C4A}' => true, + '\u{0C4B}' => true, + '\u{0C4C}' => true, + '\u{0C4D}' => true, + '\u{0C55}' => true, + '\u{0C56}' => true, + '\u{0C62}' => true, + '\u{0C63}' => true, + '\u{0C81}' => true, + '\u{0C82}' => true, + '\u{0C83}' => true, + '\u{0CBC}' => true, + '\u{0CBE}' => true, + '\u{0CBF}' => true, + '\u{0CC0}' => true, + '\u{0CC1}' => true, + '\u{0CC2}' => true, + '\u{0CC3}' => true, + '\u{0CC4}' => true, + '\u{0CC6}' => true, + '\u{0CC7}' => true, + '\u{0CC8}' => true, + '\u{0CCA}' => true, + '\u{0CCB}' => true, + '\u{0CCC}' => true, + '\u{0CCD}' => true, + '\u{0CD5}' => true, + '\u{0CD6}' => true, + '\u{0CE2}' => true, + '\u{0CE3}' => true, + '\u{0D01}' => true, + '\u{0D02}' => true, + '\u{0D03}' => true, + '\u{0D3E}' => true, + '\u{0D3F}' => true, + '\u{0D40}' => true, + '\u{0D41}' => true, + '\u{0D42}' => true, + '\u{0D43}' => true, + '\u{0D44}' => true, + '\u{0D46}' => true, + '\u{0D47}' => true, + '\u{0D48}' => true, + '\u{0D4A}' => true, + '\u{0D4B}' => true, + '\u{0D4C}' => true, + '\u{0D4D}' => true, + '\u{0D57}' => true, + '\u{0D62}' => true, + '\u{0D63}' => true, + '\u{0D82}' => true, + '\u{0D83}' => true, + '\u{0DCA}' => true, + '\u{0DCF}' => true, + '\u{0DD0}' => true, + '\u{0DD1}' => true, + '\u{0DD2}' => true, + '\u{0DD3}' => true, + '\u{0DD4}' => true, + '\u{0DD6}' => true, + '\u{0DD8}' => true, + '\u{0DD9}' => true, + '\u{0DDA}' => true, + '\u{0DDB}' => true, + '\u{0DDC}' => true, + '\u{0DDD}' => true, + '\u{0DDE}' => true, + '\u{0DDF}' => true, + '\u{0DF2}' => true, + '\u{0DF3}' => true, + '\u{0E31}' => true, + '\u{0E34}' => true, + '\u{0E35}' => true, + '\u{0E36}' => true, + '\u{0E37}' => true, + '\u{0E38}' => true, + '\u{0E39}' => true, + '\u{0E3A}' => true, + '\u{0E47}' => true, + '\u{0E48}' => true, + '\u{0E49}' => true, + '\u{0E4A}' => true, + '\u{0E4B}' => true, + '\u{0E4C}' => true, + '\u{0E4D}' => true, + '\u{0E4E}' => true, + '\u{0EB1}' => true, + '\u{0EB4}' => true, + '\u{0EB5}' => true, + '\u{0EB6}' => true, + '\u{0EB7}' => true, + '\u{0EB8}' => true, + '\u{0EB9}' => true, + '\u{0EBB}' => true, + '\u{0EBC}' => true, + '\u{0EC8}' => true, + '\u{0EC9}' => true, + '\u{0ECA}' => true, + '\u{0ECB}' => true, + '\u{0ECC}' => true, + '\u{0ECD}' => true, + '\u{0F18}' => true, + '\u{0F19}' => true, + '\u{0F35}' => true, + '\u{0F37}' => true, + '\u{0F39}' => true, + '\u{0F3E}' => true, + '\u{0F3F}' => true, + '\u{0F71}' => true, + '\u{0F72}' => true, + '\u{0F73}' => true, + '\u{0F74}' => true, + '\u{0F75}' => true, + '\u{0F76}' => true, + '\u{0F77}' => true, + '\u{0F78}' => true, + '\u{0F79}' => true, + '\u{0F7A}' => true, + '\u{0F7B}' => true, + '\u{0F7C}' => true, + '\u{0F7D}' => true, + '\u{0F7E}' => true, + '\u{0F7F}' => true, + '\u{0F80}' => true, + '\u{0F81}' => true, + '\u{0F82}' => true, + '\u{0F83}' => true, + '\u{0F84}' => true, + '\u{0F86}' => true, + '\u{0F87}' => true, + '\u{0F8D}' => true, + '\u{0F8E}' => true, + '\u{0F8F}' => true, + '\u{0F90}' => true, + '\u{0F91}' => true, + '\u{0F92}' => true, + '\u{0F93}' => true, + '\u{0F94}' => true, + '\u{0F95}' => true, + '\u{0F96}' => true, + '\u{0F97}' => true, + '\u{0F99}' => true, + '\u{0F9A}' => true, + '\u{0F9B}' => true, + '\u{0F9C}' => true, + '\u{0F9D}' => true, + '\u{0F9E}' => true, + '\u{0F9F}' => true, + '\u{0FA0}' => true, + '\u{0FA1}' => true, + '\u{0FA2}' => true, + '\u{0FA3}' => true, + '\u{0FA4}' => true, + '\u{0FA5}' => true, + '\u{0FA6}' => true, + '\u{0FA7}' => true, + '\u{0FA8}' => true, + '\u{0FA9}' => true, + '\u{0FAA}' => true, + '\u{0FAB}' => true, + '\u{0FAC}' => true, + '\u{0FAD}' => true, + '\u{0FAE}' => true, + '\u{0FAF}' => true, + '\u{0FB0}' => true, + '\u{0FB1}' => true, + '\u{0FB2}' => true, + '\u{0FB3}' => true, + '\u{0FB4}' => true, + '\u{0FB5}' => true, + '\u{0FB6}' => true, + '\u{0FB7}' => true, + '\u{0FB8}' => true, + '\u{0FB9}' => true, + '\u{0FBA}' => true, + '\u{0FBB}' => true, + '\u{0FBC}' => true, + '\u{0FC6}' => true, + '\u{102B}' => true, + '\u{102C}' => true, + '\u{102D}' => true, + '\u{102E}' => true, + '\u{102F}' => true, + '\u{1030}' => true, + '\u{1031}' => true, + '\u{1032}' => true, + '\u{1033}' => true, + '\u{1034}' => true, + '\u{1035}' => true, + '\u{1036}' => true, + '\u{1037}' => true, + '\u{1038}' => true, + '\u{1039}' => true, + '\u{103A}' => true, + '\u{103B}' => true, + '\u{103C}' => true, + '\u{103D}' => true, + '\u{103E}' => true, + '\u{1056}' => true, + '\u{1057}' => true, + '\u{1058}' => true, + '\u{1059}' => true, + '\u{105E}' => true, + '\u{105F}' => true, + '\u{1060}' => true, + '\u{1062}' => true, + '\u{1063}' => true, + '\u{1064}' => true, + '\u{1067}' => true, + '\u{1068}' => true, + '\u{1069}' => true, + '\u{106A}' => true, + '\u{106B}' => true, + '\u{106C}' => true, + '\u{106D}' => true, + '\u{1071}' => true, + '\u{1072}' => true, + '\u{1073}' => true, + '\u{1074}' => true, + '\u{1082}' => true, + '\u{1083}' => true, + '\u{1084}' => true, + '\u{1085}' => true, + '\u{1086}' => true, + '\u{1087}' => true, + '\u{1088}' => true, + '\u{1089}' => true, + '\u{108A}' => true, + '\u{108B}' => true, + '\u{108C}' => true, + '\u{108D}' => true, + '\u{108F}' => true, + '\u{109A}' => true, + '\u{109B}' => true, + '\u{109C}' => true, + '\u{109D}' => true, + '\u{135D}' => true, + '\u{135E}' => true, + '\u{135F}' => true, + '\u{1712}' => true, + '\u{1713}' => true, + '\u{1714}' => true, + '\u{1732}' => true, + '\u{1733}' => true, + '\u{1734}' => true, + '\u{1752}' => true, + '\u{1753}' => true, + '\u{1772}' => true, + '\u{1773}' => true, + '\u{17B4}' => true, + '\u{17B5}' => true, + '\u{17B6}' => true, + '\u{17B7}' => true, + '\u{17B8}' => true, + '\u{17B9}' => true, + '\u{17BA}' => true, + '\u{17BB}' => true, + '\u{17BC}' => true, + '\u{17BD}' => true, + '\u{17BE}' => true, + '\u{17BF}' => true, + '\u{17C0}' => true, + '\u{17C1}' => true, + '\u{17C2}' => true, + '\u{17C3}' => true, + '\u{17C4}' => true, + '\u{17C5}' => true, + '\u{17C6}' => true, + '\u{17C7}' => true, + '\u{17C8}' => true, + '\u{17C9}' => true, + '\u{17CA}' => true, + '\u{17CB}' => true, + '\u{17CC}' => true, + '\u{17CD}' => true, + '\u{17CE}' => true, + '\u{17CF}' => true, + '\u{17D0}' => true, + '\u{17D1}' => true, + '\u{17D2}' => true, + '\u{17D3}' => true, + '\u{17DD}' => true, + '\u{180B}' => true, + '\u{180C}' => true, + '\u{180D}' => true, + '\u{1885}' => true, + '\u{1886}' => true, + '\u{18A9}' => true, + '\u{1920}' => true, + '\u{1921}' => true, + '\u{1922}' => true, + '\u{1923}' => true, + '\u{1924}' => true, + '\u{1925}' => true, + '\u{1926}' => true, + '\u{1927}' => true, + '\u{1928}' => true, + '\u{1929}' => true, + '\u{192A}' => true, + '\u{192B}' => true, + '\u{1930}' => true, + '\u{1931}' => true, + '\u{1932}' => true, + '\u{1933}' => true, + '\u{1934}' => true, + '\u{1935}' => true, + '\u{1936}' => true, + '\u{1937}' => true, + '\u{1938}' => true, + '\u{1939}' => true, + '\u{193A}' => true, + '\u{193B}' => true, + '\u{1A17}' => true, + '\u{1A18}' => true, + '\u{1A19}' => true, + '\u{1A1A}' => true, + '\u{1A1B}' => true, + '\u{1A55}' => true, + '\u{1A56}' => true, + '\u{1A57}' => true, + '\u{1A58}' => true, + '\u{1A59}' => true, + '\u{1A5A}' => true, + '\u{1A5B}' => true, + '\u{1A5C}' => true, + '\u{1A5D}' => true, + '\u{1A5E}' => true, + '\u{1A60}' => true, + '\u{1A61}' => true, + '\u{1A62}' => true, + '\u{1A63}' => true, + '\u{1A64}' => true, + '\u{1A65}' => true, + '\u{1A66}' => true, + '\u{1A67}' => true, + '\u{1A68}' => true, + '\u{1A69}' => true, + '\u{1A6A}' => true, + '\u{1A6B}' => true, + '\u{1A6C}' => true, + '\u{1A6D}' => true, + '\u{1A6E}' => true, + '\u{1A6F}' => true, + '\u{1A70}' => true, + '\u{1A71}' => true, + '\u{1A72}' => true, + '\u{1A73}' => true, + '\u{1A74}' => true, + '\u{1A75}' => true, + '\u{1A76}' => true, + '\u{1A77}' => true, + '\u{1A78}' => true, + '\u{1A79}' => true, + '\u{1A7A}' => true, + '\u{1A7B}' => true, + '\u{1A7C}' => true, + '\u{1A7F}' => true, + '\u{1AB0}' => true, + '\u{1AB1}' => true, + '\u{1AB2}' => true, + '\u{1AB3}' => true, + '\u{1AB4}' => true, + '\u{1AB5}' => true, + '\u{1AB6}' => true, + '\u{1AB7}' => true, + '\u{1AB8}' => true, + '\u{1AB9}' => true, + '\u{1ABA}' => true, + '\u{1ABB}' => true, + '\u{1ABC}' => true, + '\u{1ABD}' => true, + '\u{1ABE}' => true, + '\u{1B00}' => true, + '\u{1B01}' => true, + '\u{1B02}' => true, + '\u{1B03}' => true, + '\u{1B04}' => true, + '\u{1B34}' => true, + '\u{1B35}' => true, + '\u{1B36}' => true, + '\u{1B37}' => true, + '\u{1B38}' => true, + '\u{1B39}' => true, + '\u{1B3A}' => true, + '\u{1B3B}' => true, + '\u{1B3C}' => true, + '\u{1B3D}' => true, + '\u{1B3E}' => true, + '\u{1B3F}' => true, + '\u{1B40}' => true, + '\u{1B41}' => true, + '\u{1B42}' => true, + '\u{1B43}' => true, + '\u{1B44}' => true, + '\u{1B6B}' => true, + '\u{1B6C}' => true, + '\u{1B6D}' => true, + '\u{1B6E}' => true, + '\u{1B6F}' => true, + '\u{1B70}' => true, + '\u{1B71}' => true, + '\u{1B72}' => true, + '\u{1B73}' => true, + '\u{1B80}' => true, + '\u{1B81}' => true, + '\u{1B82}' => true, + '\u{1BA1}' => true, + '\u{1BA2}' => true, + '\u{1BA3}' => true, + '\u{1BA4}' => true, + '\u{1BA5}' => true, + '\u{1BA6}' => true, + '\u{1BA7}' => true, + '\u{1BA8}' => true, + '\u{1BA9}' => true, + '\u{1BAA}' => true, + '\u{1BAB}' => true, + '\u{1BAC}' => true, + '\u{1BAD}' => true, + '\u{1BE6}' => true, + '\u{1BE7}' => true, + '\u{1BE8}' => true, + '\u{1BE9}' => true, + '\u{1BEA}' => true, + '\u{1BEB}' => true, + '\u{1BEC}' => true, + '\u{1BED}' => true, + '\u{1BEE}' => true, + '\u{1BEF}' => true, + '\u{1BF0}' => true, + '\u{1BF1}' => true, + '\u{1BF2}' => true, + '\u{1BF3}' => true, + '\u{1C24}' => true, + '\u{1C25}' => true, + '\u{1C26}' => true, + '\u{1C27}' => true, + '\u{1C28}' => true, + '\u{1C29}' => true, + '\u{1C2A}' => true, + '\u{1C2B}' => true, + '\u{1C2C}' => true, + '\u{1C2D}' => true, + '\u{1C2E}' => true, + '\u{1C2F}' => true, + '\u{1C30}' => true, + '\u{1C31}' => true, + '\u{1C32}' => true, + '\u{1C33}' => true, + '\u{1C34}' => true, + '\u{1C35}' => true, + '\u{1C36}' => true, + '\u{1C37}' => true, + '\u{1CD0}' => true, + '\u{1CD1}' => true, + '\u{1CD2}' => true, + '\u{1CD4}' => true, + '\u{1CD5}' => true, + '\u{1CD6}' => true, + '\u{1CD7}' => true, + '\u{1CD8}' => true, + '\u{1CD9}' => true, + '\u{1CDA}' => true, + '\u{1CDB}' => true, + '\u{1CDC}' => true, + '\u{1CDD}' => true, + '\u{1CDE}' => true, + '\u{1CDF}' => true, + '\u{1CE0}' => true, + '\u{1CE1}' => true, + '\u{1CE2}' => true, + '\u{1CE3}' => true, + '\u{1CE4}' => true, + '\u{1CE5}' => true, + '\u{1CE6}' => true, + '\u{1CE7}' => true, + '\u{1CE8}' => true, + '\u{1CED}' => true, + '\u{1CF2}' => true, + '\u{1CF3}' => true, + '\u{1CF4}' => true, + '\u{1CF8}' => true, + '\u{1CF9}' => true, + '\u{1DC0}' => true, + '\u{1DC1}' => true, + '\u{1DC2}' => true, + '\u{1DC3}' => true, + '\u{1DC4}' => true, + '\u{1DC5}' => true, + '\u{1DC6}' => true, + '\u{1DC7}' => true, + '\u{1DC8}' => true, + '\u{1DC9}' => true, + '\u{1DCA}' => true, + '\u{1DCB}' => true, + '\u{1DCC}' => true, + '\u{1DCD}' => true, + '\u{1DCE}' => true, + '\u{1DCF}' => true, + '\u{1DD0}' => true, + '\u{1DD1}' => true, + '\u{1DD2}' => true, + '\u{1DD3}' => true, + '\u{1DD4}' => true, + '\u{1DD5}' => true, + '\u{1DD6}' => true, + '\u{1DD7}' => true, + '\u{1DD8}' => true, + '\u{1DD9}' => true, + '\u{1DDA}' => true, + '\u{1DDB}' => true, + '\u{1DDC}' => true, + '\u{1DDD}' => true, + '\u{1DDE}' => true, + '\u{1DDF}' => true, + '\u{1DE0}' => true, + '\u{1DE1}' => true, + '\u{1DE2}' => true, + '\u{1DE3}' => true, + '\u{1DE4}' => true, + '\u{1DE5}' => true, + '\u{1DE6}' => true, + '\u{1DE7}' => true, + '\u{1DE8}' => true, + '\u{1DE9}' => true, + '\u{1DEA}' => true, + '\u{1DEB}' => true, + '\u{1DEC}' => true, + '\u{1DED}' => true, + '\u{1DEE}' => true, + '\u{1DEF}' => true, + '\u{1DF0}' => true, + '\u{1DF1}' => true, + '\u{1DF2}' => true, + '\u{1DF3}' => true, + '\u{1DF4}' => true, + '\u{1DF5}' => true, + '\u{1DFB}' => true, + '\u{1DFC}' => true, + '\u{1DFD}' => true, + '\u{1DFE}' => true, + '\u{1DFF}' => true, + '\u{20D0}' => true, + '\u{20D1}' => true, + '\u{20D2}' => true, + '\u{20D3}' => true, + '\u{20D4}' => true, + '\u{20D5}' => true, + '\u{20D6}' => true, + '\u{20D7}' => true, + '\u{20D8}' => true, + '\u{20D9}' => true, + '\u{20DA}' => true, + '\u{20DB}' => true, + '\u{20DC}' => true, + '\u{20DD}' => true, + '\u{20DE}' => true, + '\u{20DF}' => true, + '\u{20E0}' => true, + '\u{20E1}' => true, + '\u{20E2}' => true, + '\u{20E3}' => true, + '\u{20E4}' => true, + '\u{20E5}' => true, + '\u{20E6}' => true, + '\u{20E7}' => true, + '\u{20E8}' => true, + '\u{20E9}' => true, + '\u{20EA}' => true, + '\u{20EB}' => true, + '\u{20EC}' => true, + '\u{20ED}' => true, + '\u{20EE}' => true, + '\u{20EF}' => true, + '\u{20F0}' => true, + '\u{2CEF}' => true, + '\u{2CF0}' => true, + '\u{2CF1}' => true, + '\u{2D7F}' => true, + '\u{2DE0}' => true, + '\u{2DE1}' => true, + '\u{2DE2}' => true, + '\u{2DE3}' => true, + '\u{2DE4}' => true, + '\u{2DE5}' => true, + '\u{2DE6}' => true, + '\u{2DE7}' => true, + '\u{2DE8}' => true, + '\u{2DE9}' => true, + '\u{2DEA}' => true, + '\u{2DEB}' => true, + '\u{2DEC}' => true, + '\u{2DED}' => true, + '\u{2DEE}' => true, + '\u{2DEF}' => true, + '\u{2DF0}' => true, + '\u{2DF1}' => true, + '\u{2DF2}' => true, + '\u{2DF3}' => true, + '\u{2DF4}' => true, + '\u{2DF5}' => true, + '\u{2DF6}' => true, + '\u{2DF7}' => true, + '\u{2DF8}' => true, + '\u{2DF9}' => true, + '\u{2DFA}' => true, + '\u{2DFB}' => true, + '\u{2DFC}' => true, + '\u{2DFD}' => true, + '\u{2DFE}' => true, + '\u{2DFF}' => true, + '\u{302A}' => true, + '\u{302B}' => true, + '\u{302C}' => true, + '\u{302D}' => true, + '\u{302E}' => true, + '\u{302F}' => true, + '\u{3099}' => true, + '\u{309A}' => true, + '\u{A66F}' => true, + '\u{A670}' => true, + '\u{A671}' => true, + '\u{A672}' => true, + '\u{A674}' => true, + '\u{A675}' => true, + '\u{A676}' => true, + '\u{A677}' => true, + '\u{A678}' => true, + '\u{A679}' => true, + '\u{A67A}' => true, + '\u{A67B}' => true, + '\u{A67C}' => true, + '\u{A67D}' => true, + '\u{A69E}' => true, + '\u{A69F}' => true, + '\u{A6F0}' => true, + '\u{A6F1}' => true, + '\u{A802}' => true, + '\u{A806}' => true, + '\u{A80B}' => true, + '\u{A823}' => true, + '\u{A824}' => true, + '\u{A825}' => true, + '\u{A826}' => true, + '\u{A827}' => true, + '\u{A880}' => true, + '\u{A881}' => true, + '\u{A8B4}' => true, + '\u{A8B5}' => true, + '\u{A8B6}' => true, + '\u{A8B7}' => true, + '\u{A8B8}' => true, + '\u{A8B9}' => true, + '\u{A8BA}' => true, + '\u{A8BB}' => true, + '\u{A8BC}' => true, + '\u{A8BD}' => true, + '\u{A8BE}' => true, + '\u{A8BF}' => true, + '\u{A8C0}' => true, + '\u{A8C1}' => true, + '\u{A8C2}' => true, + '\u{A8C3}' => true, + '\u{A8C4}' => true, + '\u{A8C5}' => true, + '\u{A8E0}' => true, + '\u{A8E1}' => true, + '\u{A8E2}' => true, + '\u{A8E3}' => true, + '\u{A8E4}' => true, + '\u{A8E5}' => true, + '\u{A8E6}' => true, + '\u{A8E7}' => true, + '\u{A8E8}' => true, + '\u{A8E9}' => true, + '\u{A8EA}' => true, + '\u{A8EB}' => true, + '\u{A8EC}' => true, + '\u{A8ED}' => true, + '\u{A8EE}' => true, + '\u{A8EF}' => true, + '\u{A8F0}' => true, + '\u{A8F1}' => true, + '\u{A926}' => true, + '\u{A927}' => true, + '\u{A928}' => true, + '\u{A929}' => true, + '\u{A92A}' => true, + '\u{A92B}' => true, + '\u{A92C}' => true, + '\u{A92D}' => true, + '\u{A947}' => true, + '\u{A948}' => true, + '\u{A949}' => true, + '\u{A94A}' => true, + '\u{A94B}' => true, + '\u{A94C}' => true, + '\u{A94D}' => true, + '\u{A94E}' => true, + '\u{A94F}' => true, + '\u{A950}' => true, + '\u{A951}' => true, + '\u{A952}' => true, + '\u{A953}' => true, + '\u{A980}' => true, + '\u{A981}' => true, + '\u{A982}' => true, + '\u{A983}' => true, + '\u{A9B3}' => true, + '\u{A9B4}' => true, + '\u{A9B5}' => true, + '\u{A9B6}' => true, + '\u{A9B7}' => true, + '\u{A9B8}' => true, + '\u{A9B9}' => true, + '\u{A9BA}' => true, + '\u{A9BB}' => true, + '\u{A9BC}' => true, + '\u{A9BD}' => true, + '\u{A9BE}' => true, + '\u{A9BF}' => true, + '\u{A9C0}' => true, + '\u{A9E5}' => true, + '\u{AA29}' => true, + '\u{AA2A}' => true, + '\u{AA2B}' => true, + '\u{AA2C}' => true, + '\u{AA2D}' => true, + '\u{AA2E}' => true, + '\u{AA2F}' => true, + '\u{AA30}' => true, + '\u{AA31}' => true, + '\u{AA32}' => true, + '\u{AA33}' => true, + '\u{AA34}' => true, + '\u{AA35}' => true, + '\u{AA36}' => true, + '\u{AA43}' => true, + '\u{AA4C}' => true, + '\u{AA4D}' => true, + '\u{AA7B}' => true, + '\u{AA7C}' => true, + '\u{AA7D}' => true, + '\u{AAB0}' => true, + '\u{AAB2}' => true, + '\u{AAB3}' => true, + '\u{AAB4}' => true, + '\u{AAB7}' => true, + '\u{AAB8}' => true, + '\u{AABE}' => true, + '\u{AABF}' => true, + '\u{AAC1}' => true, + '\u{AAEB}' => true, + '\u{AAEC}' => true, + '\u{AAED}' => true, + '\u{AAEE}' => true, + '\u{AAEF}' => true, + '\u{AAF5}' => true, + '\u{AAF6}' => true, + '\u{ABE3}' => true, + '\u{ABE4}' => true, + '\u{ABE5}' => true, + '\u{ABE6}' => true, + '\u{ABE7}' => true, + '\u{ABE8}' => true, + '\u{ABE9}' => true, + '\u{ABEA}' => true, + '\u{ABEC}' => true, + '\u{ABED}' => true, + '\u{FB1E}' => true, + '\u{FE00}' => true, + '\u{FE01}' => true, + '\u{FE02}' => true, + '\u{FE03}' => true, + '\u{FE04}' => true, + '\u{FE05}' => true, + '\u{FE06}' => true, + '\u{FE07}' => true, + '\u{FE08}' => true, + '\u{FE09}' => true, + '\u{FE0A}' => true, + '\u{FE0B}' => true, + '\u{FE0C}' => true, + '\u{FE0D}' => true, + '\u{FE0E}' => true, + '\u{FE0F}' => true, + '\u{FE20}' => true, + '\u{FE21}' => true, + '\u{FE22}' => true, + '\u{FE23}' => true, + '\u{FE24}' => true, + '\u{FE25}' => true, + '\u{FE26}' => true, + '\u{FE27}' => true, + '\u{FE28}' => true, + '\u{FE29}' => true, + '\u{FE2A}' => true, + '\u{FE2B}' => true, + '\u{FE2C}' => true, + '\u{FE2D}' => true, + '\u{FE2E}' => true, + '\u{FE2F}' => true, + '\u{101FD}' => true, + '\u{102E0}' => true, + '\u{10376}' => true, + '\u{10377}' => true, + '\u{10378}' => true, + '\u{10379}' => true, + '\u{1037A}' => true, + '\u{10A01}' => true, + '\u{10A02}' => true, + '\u{10A03}' => true, + '\u{10A05}' => true, + '\u{10A06}' => true, + '\u{10A0C}' => true, + '\u{10A0D}' => true, + '\u{10A0E}' => true, + '\u{10A0F}' => true, + '\u{10A38}' => true, + '\u{10A39}' => true, + '\u{10A3A}' => true, + '\u{10A3F}' => true, + '\u{10AE5}' => true, + '\u{10AE6}' => true, + '\u{11000}' => true, + '\u{11001}' => true, + '\u{11002}' => true, + '\u{11038}' => true, + '\u{11039}' => true, + '\u{1103A}' => true, + '\u{1103B}' => true, + '\u{1103C}' => true, + '\u{1103D}' => true, + '\u{1103E}' => true, + '\u{1103F}' => true, + '\u{11040}' => true, + '\u{11041}' => true, + '\u{11042}' => true, + '\u{11043}' => true, + '\u{11044}' => true, + '\u{11045}' => true, + '\u{11046}' => true, + '\u{1107F}' => true, + '\u{11080}' => true, + '\u{11081}' => true, + '\u{11082}' => true, + '\u{110B0}' => true, + '\u{110B1}' => true, + '\u{110B2}' => true, + '\u{110B3}' => true, + '\u{110B4}' => true, + '\u{110B5}' => true, + '\u{110B6}' => true, + '\u{110B7}' => true, + '\u{110B8}' => true, + '\u{110B9}' => true, + '\u{110BA}' => true, + '\u{11100}' => true, + '\u{11101}' => true, + '\u{11102}' => true, + '\u{11127}' => true, + '\u{11128}' => true, + '\u{11129}' => true, + '\u{1112A}' => true, + '\u{1112B}' => true, + '\u{1112C}' => true, + '\u{1112D}' => true, + '\u{1112E}' => true, + '\u{1112F}' => true, + '\u{11130}' => true, + '\u{11131}' => true, + '\u{11132}' => true, + '\u{11133}' => true, + '\u{11134}' => true, + '\u{11173}' => true, + '\u{11180}' => true, + '\u{11181}' => true, + '\u{11182}' => true, + '\u{111B3}' => true, + '\u{111B4}' => true, + '\u{111B5}' => true, + '\u{111B6}' => true, + '\u{111B7}' => true, + '\u{111B8}' => true, + '\u{111B9}' => true, + '\u{111BA}' => true, + '\u{111BB}' => true, + '\u{111BC}' => true, + '\u{111BD}' => true, + '\u{111BE}' => true, + '\u{111BF}' => true, + '\u{111C0}' => true, + '\u{111CA}' => true, + '\u{111CB}' => true, + '\u{111CC}' => true, + '\u{1122C}' => true, + '\u{1122D}' => true, + '\u{1122E}' => true, + '\u{1122F}' => true, + '\u{11230}' => true, + '\u{11231}' => true, + '\u{11232}' => true, + '\u{11233}' => true, + '\u{11234}' => true, + '\u{11235}' => true, + '\u{11236}' => true, + '\u{11237}' => true, + '\u{1123E}' => true, + '\u{112DF}' => true, + '\u{112E0}' => true, + '\u{112E1}' => true, + '\u{112E2}' => true, + '\u{112E3}' => true, + '\u{112E4}' => true, + '\u{112E5}' => true, + '\u{112E6}' => true, + '\u{112E7}' => true, + '\u{112E8}' => true, + '\u{112E9}' => true, + '\u{112EA}' => true, + '\u{11300}' => true, + '\u{11301}' => true, + '\u{11302}' => true, + '\u{11303}' => true, + '\u{1133C}' => true, + '\u{1133E}' => true, + '\u{1133F}' => true, + '\u{11340}' => true, + '\u{11341}' => true, + '\u{11342}' => true, + '\u{11343}' => true, + '\u{11344}' => true, + '\u{11347}' => true, + '\u{11348}' => true, + '\u{1134B}' => true, + '\u{1134C}' => true, + '\u{1134D}' => true, + '\u{11357}' => true, + '\u{11362}' => true, + '\u{11363}' => true, + '\u{11366}' => true, + '\u{11367}' => true, + '\u{11368}' => true, + '\u{11369}' => true, + '\u{1136A}' => true, + '\u{1136B}' => true, + '\u{1136C}' => true, + '\u{11370}' => true, + '\u{11371}' => true, + '\u{11372}' => true, + '\u{11373}' => true, + '\u{11374}' => true, + '\u{11435}' => true, + '\u{11436}' => true, + '\u{11437}' => true, + '\u{11438}' => true, + '\u{11439}' => true, + '\u{1143A}' => true, + '\u{1143B}' => true, + '\u{1143C}' => true, + '\u{1143D}' => true, + '\u{1143E}' => true, + '\u{1143F}' => true, + '\u{11440}' => true, + '\u{11441}' => true, + '\u{11442}' => true, + '\u{11443}' => true, + '\u{11444}' => true, + '\u{11445}' => true, + '\u{11446}' => true, + '\u{114B0}' => true, + '\u{114B1}' => true, + '\u{114B2}' => true, + '\u{114B3}' => true, + '\u{114B4}' => true, + '\u{114B5}' => true, + '\u{114B6}' => true, + '\u{114B7}' => true, + '\u{114B8}' => true, + '\u{114B9}' => true, + '\u{114BA}' => true, + '\u{114BB}' => true, + '\u{114BC}' => true, + '\u{114BD}' => true, + '\u{114BE}' => true, + '\u{114BF}' => true, + '\u{114C0}' => true, + '\u{114C1}' => true, + '\u{114C2}' => true, + '\u{114C3}' => true, + '\u{115AF}' => true, + '\u{115B0}' => true, + '\u{115B1}' => true, + '\u{115B2}' => true, + '\u{115B3}' => true, + '\u{115B4}' => true, + '\u{115B5}' => true, + '\u{115B8}' => true, + '\u{115B9}' => true, + '\u{115BA}' => true, + '\u{115BB}' => true, + '\u{115BC}' => true, + '\u{115BD}' => true, + '\u{115BE}' => true, + '\u{115BF}' => true, + '\u{115C0}' => true, + '\u{115DC}' => true, + '\u{115DD}' => true, + '\u{11630}' => true, + '\u{11631}' => true, + '\u{11632}' => true, + '\u{11633}' => true, + '\u{11634}' => true, + '\u{11635}' => true, + '\u{11636}' => true, + '\u{11637}' => true, + '\u{11638}' => true, + '\u{11639}' => true, + '\u{1163A}' => true, + '\u{1163B}' => true, + '\u{1163C}' => true, + '\u{1163D}' => true, + '\u{1163E}' => true, + '\u{1163F}' => true, + '\u{11640}' => true, + '\u{116AB}' => true, + '\u{116AC}' => true, + '\u{116AD}' => true, + '\u{116AE}' => true, + '\u{116AF}' => true, + '\u{116B0}' => true, + '\u{116B1}' => true, + '\u{116B2}' => true, + '\u{116B3}' => true, + '\u{116B4}' => true, + '\u{116B5}' => true, + '\u{116B6}' => true, + '\u{116B7}' => true, + '\u{1171D}' => true, + '\u{1171E}' => true, + '\u{1171F}' => true, + '\u{11720}' => true, + '\u{11721}' => true, + '\u{11722}' => true, + '\u{11723}' => true, + '\u{11724}' => true, + '\u{11725}' => true, + '\u{11726}' => true, + '\u{11727}' => true, + '\u{11728}' => true, + '\u{11729}' => true, + '\u{1172A}' => true, + '\u{1172B}' => true, + '\u{11C2F}' => true, + '\u{11C30}' => true, + '\u{11C31}' => true, + '\u{11C32}' => true, + '\u{11C33}' => true, + '\u{11C34}' => true, + '\u{11C35}' => true, + '\u{11C36}' => true, + '\u{11C38}' => true, + '\u{11C39}' => true, + '\u{11C3A}' => true, + '\u{11C3B}' => true, + '\u{11C3C}' => true, + '\u{11C3D}' => true, + '\u{11C3E}' => true, + '\u{11C3F}' => true, + '\u{11C92}' => true, + '\u{11C93}' => true, + '\u{11C94}' => true, + '\u{11C95}' => true, + '\u{11C96}' => true, + '\u{11C97}' => true, + '\u{11C98}' => true, + '\u{11C99}' => true, + '\u{11C9A}' => true, + '\u{11C9B}' => true, + '\u{11C9C}' => true, + '\u{11C9D}' => true, + '\u{11C9E}' => true, + '\u{11C9F}' => true, + '\u{11CA0}' => true, + '\u{11CA1}' => true, + '\u{11CA2}' => true, + '\u{11CA3}' => true, + '\u{11CA4}' => true, + '\u{11CA5}' => true, + '\u{11CA6}' => true, + '\u{11CA7}' => true, + '\u{11CA9}' => true, + '\u{11CAA}' => true, + '\u{11CAB}' => true, + '\u{11CAC}' => true, + '\u{11CAD}' => true, + '\u{11CAE}' => true, + '\u{11CAF}' => true, + '\u{11CB0}' => true, + '\u{11CB1}' => true, + '\u{11CB2}' => true, + '\u{11CB3}' => true, + '\u{11CB4}' => true, + '\u{11CB5}' => true, + '\u{11CB6}' => true, + '\u{16AF0}' => true, + '\u{16AF1}' => true, + '\u{16AF2}' => true, + '\u{16AF3}' => true, + '\u{16AF4}' => true, + '\u{16B30}' => true, + '\u{16B31}' => true, + '\u{16B32}' => true, + '\u{16B33}' => true, + '\u{16B34}' => true, + '\u{16B35}' => true, + '\u{16B36}' => true, + '\u{16F51}' => true, + '\u{16F52}' => true, + '\u{16F53}' => true, + '\u{16F54}' => true, + '\u{16F55}' => true, + '\u{16F56}' => true, + '\u{16F57}' => true, + '\u{16F58}' => true, + '\u{16F59}' => true, + '\u{16F5A}' => true, + '\u{16F5B}' => true, + '\u{16F5C}' => true, + '\u{16F5D}' => true, + '\u{16F5E}' => true, + '\u{16F5F}' => true, + '\u{16F60}' => true, + '\u{16F61}' => true, + '\u{16F62}' => true, + '\u{16F63}' => true, + '\u{16F64}' => true, + '\u{16F65}' => true, + '\u{16F66}' => true, + '\u{16F67}' => true, + '\u{16F68}' => true, + '\u{16F69}' => true, + '\u{16F6A}' => true, + '\u{16F6B}' => true, + '\u{16F6C}' => true, + '\u{16F6D}' => true, + '\u{16F6E}' => true, + '\u{16F6F}' => true, + '\u{16F70}' => true, + '\u{16F71}' => true, + '\u{16F72}' => true, + '\u{16F73}' => true, + '\u{16F74}' => true, + '\u{16F75}' => true, + '\u{16F76}' => true, + '\u{16F77}' => true, + '\u{16F78}' => true, + '\u{16F79}' => true, + '\u{16F7A}' => true, + '\u{16F7B}' => true, + '\u{16F7C}' => true, + '\u{16F7D}' => true, + '\u{16F7E}' => true, + '\u{16F8F}' => true, + '\u{16F90}' => true, + '\u{16F91}' => true, + '\u{16F92}' => true, + '\u{1BC9D}' => true, + '\u{1BC9E}' => true, + '\u{1D165}' => true, + '\u{1D166}' => true, + '\u{1D167}' => true, + '\u{1D168}' => true, + '\u{1D169}' => true, + '\u{1D16D}' => true, + '\u{1D16E}' => true, + '\u{1D16F}' => true, + '\u{1D170}' => true, + '\u{1D171}' => true, + '\u{1D172}' => true, + '\u{1D17B}' => true, + '\u{1D17C}' => true, + '\u{1D17D}' => true, + '\u{1D17E}' => true, + '\u{1D17F}' => true, + '\u{1D180}' => true, + '\u{1D181}' => true, + '\u{1D182}' => true, + '\u{1D185}' => true, + '\u{1D186}' => true, + '\u{1D187}' => true, + '\u{1D188}' => true, + '\u{1D189}' => true, + '\u{1D18A}' => true, + '\u{1D18B}' => true, + '\u{1D1AA}' => true, + '\u{1D1AB}' => true, + '\u{1D1AC}' => true, + '\u{1D1AD}' => true, + '\u{1D242}' => true, + '\u{1D243}' => true, + '\u{1D244}' => true, + '\u{1DA00}' => true, + '\u{1DA01}' => true, + '\u{1DA02}' => true, + '\u{1DA03}' => true, + '\u{1DA04}' => true, + '\u{1DA05}' => true, + '\u{1DA06}' => true, + '\u{1DA07}' => true, + '\u{1DA08}' => true, + '\u{1DA09}' => true, + '\u{1DA0A}' => true, + '\u{1DA0B}' => true, + '\u{1DA0C}' => true, + '\u{1DA0D}' => true, + '\u{1DA0E}' => true, + '\u{1DA0F}' => true, + '\u{1DA10}' => true, + '\u{1DA11}' => true, + '\u{1DA12}' => true, + '\u{1DA13}' => true, + '\u{1DA14}' => true, + '\u{1DA15}' => true, + '\u{1DA16}' => true, + '\u{1DA17}' => true, + '\u{1DA18}' => true, + '\u{1DA19}' => true, + '\u{1DA1A}' => true, + '\u{1DA1B}' => true, + '\u{1DA1C}' => true, + '\u{1DA1D}' => true, + '\u{1DA1E}' => true, + '\u{1DA1F}' => true, + '\u{1DA20}' => true, + '\u{1DA21}' => true, + '\u{1DA22}' => true, + '\u{1DA23}' => true, + '\u{1DA24}' => true, + '\u{1DA25}' => true, + '\u{1DA26}' => true, + '\u{1DA27}' => true, + '\u{1DA28}' => true, + '\u{1DA29}' => true, + '\u{1DA2A}' => true, + '\u{1DA2B}' => true, + '\u{1DA2C}' => true, + '\u{1DA2D}' => true, + '\u{1DA2E}' => true, + '\u{1DA2F}' => true, + '\u{1DA30}' => true, + '\u{1DA31}' => true, + '\u{1DA32}' => true, + '\u{1DA33}' => true, + '\u{1DA34}' => true, + '\u{1DA35}' => true, + '\u{1DA36}' => true, + '\u{1DA3B}' => true, + '\u{1DA3C}' => true, + '\u{1DA3D}' => true, + '\u{1DA3E}' => true, + '\u{1DA3F}' => true, + '\u{1DA40}' => true, + '\u{1DA41}' => true, + '\u{1DA42}' => true, + '\u{1DA43}' => true, + '\u{1DA44}' => true, + '\u{1DA45}' => true, + '\u{1DA46}' => true, + '\u{1DA47}' => true, + '\u{1DA48}' => true, + '\u{1DA49}' => true, + '\u{1DA4A}' => true, + '\u{1DA4B}' => true, + '\u{1DA4C}' => true, + '\u{1DA4D}' => true, + '\u{1DA4E}' => true, + '\u{1DA4F}' => true, + '\u{1DA50}' => true, + '\u{1DA51}' => true, + '\u{1DA52}' => true, + '\u{1DA53}' => true, + '\u{1DA54}' => true, + '\u{1DA55}' => true, + '\u{1DA56}' => true, + '\u{1DA57}' => true, + '\u{1DA58}' => true, + '\u{1DA59}' => true, + '\u{1DA5A}' => true, + '\u{1DA5B}' => true, + '\u{1DA5C}' => true, + '\u{1DA5D}' => true, + '\u{1DA5E}' => true, + '\u{1DA5F}' => true, + '\u{1DA60}' => true, + '\u{1DA61}' => true, + '\u{1DA62}' => true, + '\u{1DA63}' => true, + '\u{1DA64}' => true, + '\u{1DA65}' => true, + '\u{1DA66}' => true, + '\u{1DA67}' => true, + '\u{1DA68}' => true, + '\u{1DA69}' => true, + '\u{1DA6A}' => true, + '\u{1DA6B}' => true, + '\u{1DA6C}' => true, + '\u{1DA75}' => true, + '\u{1DA84}' => true, + '\u{1DA9B}' => true, + '\u{1DA9C}' => true, + '\u{1DA9D}' => true, + '\u{1DA9E}' => true, + '\u{1DA9F}' => true, + '\u{1DAA1}' => true, + '\u{1DAA2}' => true, + '\u{1DAA3}' => true, + '\u{1DAA4}' => true, + '\u{1DAA5}' => true, + '\u{1DAA6}' => true, + '\u{1DAA7}' => true, + '\u{1DAA8}' => true, + '\u{1DAA9}' => true, + '\u{1DAAA}' => true, + '\u{1DAAB}' => true, + '\u{1DAAC}' => true, + '\u{1DAAD}' => true, + '\u{1DAAE}' => true, + '\u{1DAAF}' => true, + '\u{1E000}' => true, + '\u{1E001}' => true, + '\u{1E002}' => true, + '\u{1E003}' => true, + '\u{1E004}' => true, + '\u{1E005}' => true, + '\u{1E006}' => true, + '\u{1E008}' => true, + '\u{1E009}' => true, + '\u{1E00A}' => true, + '\u{1E00B}' => true, + '\u{1E00C}' => true, + '\u{1E00D}' => true, + '\u{1E00E}' => true, + '\u{1E00F}' => true, + '\u{1E010}' => true, + '\u{1E011}' => true, + '\u{1E012}' => true, + '\u{1E013}' => true, + '\u{1E014}' => true, + '\u{1E015}' => true, + '\u{1E016}' => true, + '\u{1E017}' => true, + '\u{1E018}' => true, + '\u{1E01B}' => true, + '\u{1E01C}' => true, + '\u{1E01D}' => true, + '\u{1E01E}' => true, + '\u{1E01F}' => true, + '\u{1E020}' => true, + '\u{1E021}' => true, + '\u{1E023}' => true, + '\u{1E024}' => true, + '\u{1E026}' => true, + '\u{1E027}' => true, + '\u{1E028}' => true, + '\u{1E029}' => true, + '\u{1E02A}' => true, + '\u{1E8D0}' => true, + '\u{1E8D1}' => true, + '\u{1E8D2}' => true, + '\u{1E8D3}' => true, + '\u{1E8D4}' => true, + '\u{1E8D5}' => true, + '\u{1E8D6}' => true, + '\u{1E944}' => true, + '\u{1E945}' => true, + '\u{1E946}' => true, + '\u{1E947}' => true, + '\u{1E948}' => true, + '\u{1E949}' => true, + '\u{1E94A}' => true, + '\u{E0100}' => true, + '\u{E0101}' => true, + '\u{E0102}' => true, + '\u{E0103}' => true, + '\u{E0104}' => true, + '\u{E0105}' => true, + '\u{E0106}' => true, + '\u{E0107}' => true, + '\u{E0108}' => true, + '\u{E0109}' => true, + '\u{E010A}' => true, + '\u{E010B}' => true, + '\u{E010C}' => true, + '\u{E010D}' => true, + '\u{E010E}' => true, + '\u{E010F}' => true, + '\u{E0110}' => true, + '\u{E0111}' => true, + '\u{E0112}' => true, + '\u{E0113}' => true, + '\u{E0114}' => true, + '\u{E0115}' => true, + '\u{E0116}' => true, + '\u{E0117}' => true, + '\u{E0118}' => true, + '\u{E0119}' => true, + '\u{E011A}' => true, + '\u{E011B}' => true, + '\u{E011C}' => true, + '\u{E011D}' => true, + '\u{E011E}' => true, + '\u{E011F}' => true, + '\u{E0120}' => true, + '\u{E0121}' => true, + '\u{E0122}' => true, + '\u{E0123}' => true, + '\u{E0124}' => true, + '\u{E0125}' => true, + '\u{E0126}' => true, + '\u{E0127}' => true, + '\u{E0128}' => true, + '\u{E0129}' => true, + '\u{E012A}' => true, + '\u{E012B}' => true, + '\u{E012C}' => true, + '\u{E012D}' => true, + '\u{E012E}' => true, + '\u{E012F}' => true, + '\u{E0130}' => true, + '\u{E0131}' => true, + '\u{E0132}' => true, + '\u{E0133}' => true, + '\u{E0134}' => true, + '\u{E0135}' => true, + '\u{E0136}' => true, + '\u{E0137}' => true, + '\u{E0138}' => true, + '\u{E0139}' => true, + '\u{E013A}' => true, + '\u{E013B}' => true, + '\u{E013C}' => true, + '\u{E013D}' => true, + '\u{E013E}' => true, + '\u{E013F}' => true, + '\u{E0140}' => true, + '\u{E0141}' => true, + '\u{E0142}' => true, + '\u{E0143}' => true, + '\u{E0144}' => true, + '\u{E0145}' => true, + '\u{E0146}' => true, + '\u{E0147}' => true, + '\u{E0148}' => true, + '\u{E0149}' => true, + '\u{E014A}' => true, + '\u{E014B}' => true, + '\u{E014C}' => true, + '\u{E014D}' => true, + '\u{E014E}' => true, + '\u{E014F}' => true, + '\u{E0150}' => true, + '\u{E0151}' => true, + '\u{E0152}' => true, + '\u{E0153}' => true, + '\u{E0154}' => true, + '\u{E0155}' => true, + '\u{E0156}' => true, + '\u{E0157}' => true, + '\u{E0158}' => true, + '\u{E0159}' => true, + '\u{E015A}' => true, + '\u{E015B}' => true, + '\u{E015C}' => true, + '\u{E015D}' => true, + '\u{E015E}' => true, + '\u{E015F}' => true, + '\u{E0160}' => true, + '\u{E0161}' => true, + '\u{E0162}' => true, + '\u{E0163}' => true, + '\u{E0164}' => true, + '\u{E0165}' => true, + '\u{E0166}' => true, + '\u{E0167}' => true, + '\u{E0168}' => true, + '\u{E0169}' => true, + '\u{E016A}' => true, + '\u{E016B}' => true, + '\u{E016C}' => true, + '\u{E016D}' => true, + '\u{E016E}' => true, + '\u{E016F}' => true, + '\u{E0170}' => true, + '\u{E0171}' => true, + '\u{E0172}' => true, + '\u{E0173}' => true, + '\u{E0174}' => true, + '\u{E0175}' => true, + '\u{E0176}' => true, + '\u{E0177}' => true, + '\u{E0178}' => true, + '\u{E0179}' => true, + '\u{E017A}' => true, + '\u{E017B}' => true, + '\u{E017C}' => true, + '\u{E017D}' => true, + '\u{E017E}' => true, + '\u{E017F}' => true, + '\u{E0180}' => true, + '\u{E0181}' => true, + '\u{E0182}' => true, + '\u{E0183}' => true, + '\u{E0184}' => true, + '\u{E0185}' => true, + '\u{E0186}' => true, + '\u{E0187}' => true, + '\u{E0188}' => true, + '\u{E0189}' => true, + '\u{E018A}' => true, + '\u{E018B}' => true, + '\u{E018C}' => true, + '\u{E018D}' => true, + '\u{E018E}' => true, + '\u{E018F}' => true, + '\u{E0190}' => true, + '\u{E0191}' => true, + '\u{E0192}' => true, + '\u{E0193}' => true, + '\u{E0194}' => true, + '\u{E0195}' => true, + '\u{E0196}' => true, + '\u{E0197}' => true, + '\u{E0198}' => true, + '\u{E0199}' => true, + '\u{E019A}' => true, + '\u{E019B}' => true, + '\u{E019C}' => true, + '\u{E019D}' => true, + '\u{E019E}' => true, + '\u{E019F}' => true, + '\u{E01A0}' => true, + '\u{E01A1}' => true, + '\u{E01A2}' => true, + '\u{E01A3}' => true, + '\u{E01A4}' => true, + '\u{E01A5}' => true, + '\u{E01A6}' => true, + '\u{E01A7}' => true, + '\u{E01A8}' => true, + '\u{E01A9}' => true, + '\u{E01AA}' => true, + '\u{E01AB}' => true, + '\u{E01AC}' => true, + '\u{E01AD}' => true, + '\u{E01AE}' => true, + '\u{E01AF}' => true, + '\u{E01B0}' => true, + '\u{E01B1}' => true, + '\u{E01B2}' => true, + '\u{E01B3}' => true, + '\u{E01B4}' => true, + '\u{E01B5}' => true, + '\u{E01B6}' => true, + '\u{E01B7}' => true, + '\u{E01B8}' => true, + '\u{E01B9}' => true, + '\u{E01BA}' => true, + '\u{E01BB}' => true, + '\u{E01BC}' => true, + '\u{E01BD}' => true, + '\u{E01BE}' => true, + '\u{E01BF}' => true, + '\u{E01C0}' => true, + '\u{E01C1}' => true, + '\u{E01C2}' => true, + '\u{E01C3}' => true, + '\u{E01C4}' => true, + '\u{E01C5}' => true, + '\u{E01C6}' => true, + '\u{E01C7}' => true, + '\u{E01C8}' => true, + '\u{E01C9}' => true, + '\u{E01CA}' => true, + '\u{E01CB}' => true, + '\u{E01CC}' => true, + '\u{E01CD}' => true, + '\u{E01CE}' => true, + '\u{E01CF}' => true, + '\u{E01D0}' => true, + '\u{E01D1}' => true, + '\u{E01D2}' => true, + '\u{E01D3}' => true, + '\u{E01D4}' => true, + '\u{E01D5}' => true, + '\u{E01D6}' => true, + '\u{E01D7}' => true, + '\u{E01D8}' => true, + '\u{E01D9}' => true, + '\u{E01DA}' => true, + '\u{E01DB}' => true, + '\u{E01DC}' => true, + '\u{E01DD}' => true, + '\u{E01DE}' => true, + '\u{E01DF}' => true, + '\u{E01E0}' => true, + '\u{E01E1}' => true, + '\u{E01E2}' => true, + '\u{E01E3}' => true, + '\u{E01E4}' => true, + '\u{E01E5}' => true, + '\u{E01E6}' => true, + '\u{E01E7}' => true, + '\u{E01E8}' => true, + '\u{E01E9}' => true, + '\u{E01EA}' => true, + '\u{E01EB}' => true, + '\u{E01EC}' => true, + '\u{E01ED}' => true, + '\u{E01EE}' => true, + '\u{E01EF}' => true, + _ => false, + } +} + +#[inline] +pub fn qc_nfc(c: char) -> IsNormalized { + match c { + '\u{0340}'...'\u{0341}' => No, + '\u{0343}'...'\u{0344}' => No, + '\u{0374}' => No, + '\u{037E}' => No, + '\u{0387}' => No, + '\u{0958}'...'\u{095F}' => No, + '\u{09DC}'...'\u{09DD}' => No, + '\u{09DF}' => No, + '\u{0A33}' => No, + '\u{0A36}' => No, + '\u{0A59}'...'\u{0A5B}' => No, + '\u{0A5E}' => No, + '\u{0B5C}'...'\u{0B5D}' => No, + '\u{0F43}' => No, + '\u{0F4D}' => No, + '\u{0F52}' => No, + '\u{0F57}' => No, + '\u{0F5C}' => No, + '\u{0F69}' => No, + '\u{0F73}' => No, + '\u{0F75}'...'\u{0F76}' => No, + '\u{0F78}' => No, + '\u{0F81}' => No, + '\u{0F93}' => No, + '\u{0F9D}' => No, + '\u{0FA2}' => No, + '\u{0FA7}' => No, + '\u{0FAC}' => No, + '\u{0FB9}' => No, + '\u{1F71}' => No, + '\u{1F73}' => No, + '\u{1F75}' => No, + '\u{1F77}' => No, + '\u{1F79}' => No, + '\u{1F7B}' => No, + '\u{1F7D}' => No, + '\u{1FBB}' => No, + '\u{1FBE}' => No, + '\u{1FC9}' => No, + '\u{1FCB}' => No, + '\u{1FD3}' => No, + '\u{1FDB}' => No, + '\u{1FE3}' => No, + '\u{1FEB}' => No, + '\u{1FEE}'...'\u{1FEF}' => No, + '\u{1FF9}' => No, + '\u{1FFB}' => No, + '\u{1FFD}' => No, + '\u{2000}'...'\u{2001}' => No, + '\u{2126}' => No, + '\u{212A}'...'\u{212B}' => No, + '\u{2329}' => No, + '\u{232A}' => No, + '\u{2ADC}' => No, + '\u{F900}'...'\u{FA0D}' => No, + '\u{FA10}' => No, + '\u{FA12}' => No, + '\u{FA15}'...'\u{FA1E}' => No, + '\u{FA20}' => No, + '\u{FA22}' => No, + '\u{FA25}'...'\u{FA26}' => No, + '\u{FA2A}'...'\u{FA6D}' => No, + '\u{FA70}'...'\u{FAD9}' => No, + '\u{FB1D}' => No, + '\u{FB1F}' => No, + '\u{FB2A}'...'\u{FB36}' => No, + '\u{FB38}'...'\u{FB3C}' => No, + '\u{FB3E}' => No, + '\u{FB40}'...'\u{FB41}' => No, + '\u{FB43}'...'\u{FB44}' => No, + '\u{FB46}'...'\u{FB4E}' => No, + '\u{1D15E}'...'\u{1D164}' => No, + '\u{1D1BB}'...'\u{1D1C0}' => No, + '\u{2F800}'...'\u{2FA1D}' => No, + '\u{0300}'...'\u{0304}' => Maybe, + '\u{0306}'...'\u{030C}' => Maybe, + '\u{030F}' => Maybe, + '\u{0311}' => Maybe, + '\u{0313}'...'\u{0314}' => Maybe, + '\u{031B}' => Maybe, + '\u{0323}'...'\u{0328}' => Maybe, + '\u{032D}'...'\u{032E}' => Maybe, + '\u{0330}'...'\u{0331}' => Maybe, + '\u{0338}' => Maybe, + '\u{0342}' => Maybe, + '\u{0345}' => Maybe, + '\u{0653}'...'\u{0655}' => Maybe, + '\u{093C}' => Maybe, + '\u{09BE}' => Maybe, + '\u{09D7}' => Maybe, + '\u{0B3E}' => Maybe, + '\u{0B56}' => Maybe, + '\u{0B57}' => Maybe, + '\u{0BBE}' => Maybe, + '\u{0BD7}' => Maybe, + '\u{0C56}' => Maybe, + '\u{0CC2}' => Maybe, + '\u{0CD5}'...'\u{0CD6}' => Maybe, + '\u{0D3E}' => Maybe, + '\u{0D57}' => Maybe, + '\u{0DCA}' => Maybe, + '\u{0DCF}' => Maybe, + '\u{0DDF}' => Maybe, + '\u{102E}' => Maybe, + '\u{1161}'...'\u{1175}' => Maybe, + '\u{11A8}'...'\u{11C2}' => Maybe, + '\u{1B35}' => Maybe, + '\u{3099}'...'\u{309A}' => Maybe, + '\u{110BA}' => Maybe, + '\u{11127}' => Maybe, + '\u{1133E}' => Maybe, + '\u{11357}' => Maybe, + '\u{114B0}' => Maybe, + '\u{114BA}' => Maybe, + '\u{114BD}' => Maybe, + '\u{115AF}' => Maybe, + _ => Yes, + } +} + +#[inline] +pub fn qc_nfkc(c: char) -> IsNormalized { + match c { + '\u{00A0}' => No, + '\u{00A8}' => No, + '\u{00AA}' => No, + '\u{00AF}' => No, + '\u{00B2}'...'\u{00B3}' => No, + '\u{00B4}' => No, + '\u{00B5}' => No, + '\u{00B8}' => No, + '\u{00B9}' => No, + '\u{00BA}' => No, + '\u{00BC}'...'\u{00BE}' => No, + '\u{0132}'...'\u{0133}' => No, + '\u{013F}'...'\u{0140}' => No, + '\u{0149}' => No, + '\u{017F}' => No, + '\u{01C4}'...'\u{01CC}' => No, + '\u{01F1}'...'\u{01F3}' => No, + '\u{02B0}'...'\u{02B8}' => No, + '\u{02D8}'...'\u{02DD}' => No, + '\u{02E0}'...'\u{02E4}' => No, + '\u{0340}'...'\u{0341}' => No, + '\u{0343}'...'\u{0344}' => No, + '\u{0374}' => No, + '\u{037A}' => No, + '\u{037E}' => No, + '\u{0384}'...'\u{0385}' => No, + '\u{0387}' => No, + '\u{03D0}'...'\u{03D6}' => No, + '\u{03F0}'...'\u{03F2}' => No, + '\u{03F4}'...'\u{03F5}' => No, + '\u{03F9}' => No, + '\u{0587}' => No, + '\u{0675}'...'\u{0678}' => No, + '\u{0958}'...'\u{095F}' => No, + '\u{09DC}'...'\u{09DD}' => No, + '\u{09DF}' => No, + '\u{0A33}' => No, + '\u{0A36}' => No, + '\u{0A59}'...'\u{0A5B}' => No, + '\u{0A5E}' => No, + '\u{0B5C}'...'\u{0B5D}' => No, + '\u{0E33}' => No, + '\u{0EB3}' => No, + '\u{0EDC}'...'\u{0EDD}' => No, + '\u{0F0C}' => No, + '\u{0F43}' => No, + '\u{0F4D}' => No, + '\u{0F52}' => No, + '\u{0F57}' => No, + '\u{0F5C}' => No, + '\u{0F69}' => No, + '\u{0F73}' => No, + '\u{0F75}'...'\u{0F79}' => No, + '\u{0F81}' => No, + '\u{0F93}' => No, + '\u{0F9D}' => No, + '\u{0FA2}' => No, + '\u{0FA7}' => No, + '\u{0FAC}' => No, + '\u{0FB9}' => No, + '\u{10FC}' => No, + '\u{1D2C}'...'\u{1D2E}' => No, + '\u{1D30}'...'\u{1D3A}' => No, + '\u{1D3C}'...'\u{1D4D}' => No, + '\u{1D4F}'...'\u{1D6A}' => No, + '\u{1D78}' => No, + '\u{1D9B}'...'\u{1DBF}' => No, + '\u{1E9A}'...'\u{1E9B}' => No, + '\u{1F71}' => No, + '\u{1F73}' => No, + '\u{1F75}' => No, + '\u{1F77}' => No, + '\u{1F79}' => No, + '\u{1F7B}' => No, + '\u{1F7D}' => No, + '\u{1FBB}' => No, + '\u{1FBD}' => No, + '\u{1FBE}' => No, + '\u{1FBF}'...'\u{1FC1}' => No, + '\u{1FC9}' => No, + '\u{1FCB}' => No, + '\u{1FCD}'...'\u{1FCF}' => No, + '\u{1FD3}' => No, + '\u{1FDB}' => No, + '\u{1FDD}'...'\u{1FDF}' => No, + '\u{1FE3}' => No, + '\u{1FEB}' => No, + '\u{1FED}'...'\u{1FEF}' => No, + '\u{1FF9}' => No, + '\u{1FFB}' => No, + '\u{1FFD}'...'\u{1FFE}' => No, + '\u{2000}'...'\u{200A}' => No, + '\u{2011}' => No, + '\u{2017}' => No, + '\u{2024}'...'\u{2026}' => No, + '\u{202F}' => No, + '\u{2033}'...'\u{2034}' => No, + '\u{2036}'...'\u{2037}' => No, + '\u{203C}' => No, + '\u{203E}' => No, + '\u{2047}'...'\u{2049}' => No, + '\u{2057}' => No, + '\u{205F}' => No, + '\u{2070}' => No, + '\u{2071}' => No, + '\u{2074}'...'\u{2079}' => No, + '\u{207A}'...'\u{207C}' => No, + '\u{207D}' => No, + '\u{207E}' => No, + '\u{207F}' => No, + '\u{2080}'...'\u{2089}' => No, + '\u{208A}'...'\u{208C}' => No, + '\u{208D}' => No, + '\u{208E}' => No, + '\u{2090}'...'\u{209C}' => No, + '\u{20A8}' => No, + '\u{2100}'...'\u{2101}' => No, + '\u{2102}' => No, + '\u{2103}' => No, + '\u{2105}'...'\u{2106}' => No, + '\u{2107}' => No, + '\u{2109}' => No, + '\u{210A}'...'\u{2113}' => No, + '\u{2115}' => No, + '\u{2116}' => No, + '\u{2119}'...'\u{211D}' => No, + '\u{2120}'...'\u{2122}' => No, + '\u{2124}' => No, + '\u{2126}' => No, + '\u{2128}' => No, + '\u{212A}'...'\u{212D}' => No, + '\u{212F}'...'\u{2131}' => No, + '\u{2133}'...'\u{2134}' => No, + '\u{2135}'...'\u{2138}' => No, + '\u{2139}' => No, + '\u{213B}' => No, + '\u{213C}'...'\u{213F}' => No, + '\u{2140}' => No, + '\u{2145}'...'\u{2149}' => No, + '\u{2150}'...'\u{215F}' => No, + '\u{2160}'...'\u{217F}' => No, + '\u{2189}' => No, + '\u{222C}'...'\u{222D}' => No, + '\u{222F}'...'\u{2230}' => No, + '\u{2329}' => No, + '\u{232A}' => No, + '\u{2460}'...'\u{249B}' => No, + '\u{249C}'...'\u{24E9}' => No, + '\u{24EA}' => No, + '\u{2A0C}' => No, + '\u{2A74}'...'\u{2A76}' => No, + '\u{2ADC}' => No, + '\u{2C7C}'...'\u{2C7D}' => No, + '\u{2D6F}' => No, + '\u{2E9F}' => No, + '\u{2EF3}' => No, + '\u{2F00}'...'\u{2FD5}' => No, + '\u{3000}' => No, + '\u{3036}' => No, + '\u{3038}'...'\u{303A}' => No, + '\u{309B}'...'\u{309C}' => No, + '\u{309F}' => No, + '\u{30FF}' => No, + '\u{3131}'...'\u{318E}' => No, + '\u{3192}'...'\u{3195}' => No, + '\u{3196}'...'\u{319F}' => No, + '\u{3200}'...'\u{321E}' => No, + '\u{3220}'...'\u{3229}' => No, + '\u{322A}'...'\u{3247}' => No, + '\u{3250}' => No, + '\u{3251}'...'\u{325F}' => No, + '\u{3260}'...'\u{327E}' => No, + '\u{3280}'...'\u{3289}' => No, + '\u{328A}'...'\u{32B0}' => No, + '\u{32B1}'...'\u{32BF}' => No, + '\u{32C0}'...'\u{32FE}' => No, + '\u{3300}'...'\u{33FF}' => No, + '\u{A69C}'...'\u{A69D}' => No, + '\u{A770}' => No, + '\u{A7F8}'...'\u{A7F9}' => No, + '\u{AB5C}'...'\u{AB5F}' => No, + '\u{F900}'...'\u{FA0D}' => No, + '\u{FA10}' => No, + '\u{FA12}' => No, + '\u{FA15}'...'\u{FA1E}' => No, + '\u{FA20}' => No, + '\u{FA22}' => No, + '\u{FA25}'...'\u{FA26}' => No, + '\u{FA2A}'...'\u{FA6D}' => No, + '\u{FA70}'...'\u{FAD9}' => No, + '\u{FB00}'...'\u{FB06}' => No, + '\u{FB13}'...'\u{FB17}' => No, + '\u{FB1D}' => No, + '\u{FB1F}'...'\u{FB28}' => No, + '\u{FB29}' => No, + '\u{FB2A}'...'\u{FB36}' => No, + '\u{FB38}'...'\u{FB3C}' => No, + '\u{FB3E}' => No, + '\u{FB40}'...'\u{FB41}' => No, + '\u{FB43}'...'\u{FB44}' => No, + '\u{FB46}'...'\u{FBB1}' => No, + '\u{FBD3}'...'\u{FD3D}' => No, + '\u{FD50}'...'\u{FD8F}' => No, + '\u{FD92}'...'\u{FDC7}' => No, + '\u{FDF0}'...'\u{FDFB}' => No, + '\u{FDFC}' => No, + '\u{FE10}'...'\u{FE16}' => No, + '\u{FE17}' => No, + '\u{FE18}' => No, + '\u{FE19}' => No, + '\u{FE30}' => No, + '\u{FE31}'...'\u{FE32}' => No, + '\u{FE33}'...'\u{FE34}' => No, + '\u{FE35}' => No, + '\u{FE36}' => No, + '\u{FE37}' => No, + '\u{FE38}' => No, + '\u{FE39}' => No, + '\u{FE3A}' => No, + '\u{FE3B}' => No, + '\u{FE3C}' => No, + '\u{FE3D}' => No, + '\u{FE3E}' => No, + '\u{FE3F}' => No, + '\u{FE40}' => No, + '\u{FE41}' => No, + '\u{FE42}' => No, + '\u{FE43}' => No, + '\u{FE44}' => No, + '\u{FE47}' => No, + '\u{FE48}' => No, + '\u{FE49}'...'\u{FE4C}' => No, + '\u{FE4D}'...'\u{FE4F}' => No, + '\u{FE50}'...'\u{FE52}' => No, + '\u{FE54}'...'\u{FE57}' => No, + '\u{FE58}' => No, + '\u{FE59}' => No, + '\u{FE5A}' => No, + '\u{FE5B}' => No, + '\u{FE5C}' => No, + '\u{FE5D}' => No, + '\u{FE5E}' => No, + '\u{FE5F}'...'\u{FE61}' => No, + '\u{FE62}' => No, + '\u{FE63}' => No, + '\u{FE64}'...'\u{FE66}' => No, + '\u{FE68}' => No, + '\u{FE69}' => No, + '\u{FE6A}'...'\u{FE6B}' => No, + '\u{FE70}'...'\u{FE72}' => No, + '\u{FE74}' => No, + '\u{FE76}'...'\u{FEFC}' => No, + '\u{FF01}'...'\u{FF03}' => No, + '\u{FF04}' => No, + '\u{FF05}'...'\u{FF07}' => No, + '\u{FF08}' => No, + '\u{FF09}' => No, + '\u{FF0A}' => No, + '\u{FF0B}' => No, + '\u{FF0C}' => No, + '\u{FF0D}' => No, + '\u{FF0E}'...'\u{FF0F}' => No, + '\u{FF10}'...'\u{FF19}' => No, + '\u{FF1A}'...'\u{FF1B}' => No, + '\u{FF1C}'...'\u{FF1E}' => No, + '\u{FF1F}'...'\u{FF20}' => No, + '\u{FF21}'...'\u{FF3A}' => No, + '\u{FF3B}' => No, + '\u{FF3C}' => No, + '\u{FF3D}' => No, + '\u{FF3E}' => No, + '\u{FF3F}' => No, + '\u{FF40}' => No, + '\u{FF41}'...'\u{FF5A}' => No, + '\u{FF5B}' => No, + '\u{FF5C}' => No, + '\u{FF5D}' => No, + '\u{FF5E}' => No, + '\u{FF5F}' => No, + '\u{FF60}' => No, + '\u{FF61}' => No, + '\u{FF62}' => No, + '\u{FF63}' => No, + '\u{FF64}'...'\u{FF65}' => No, + '\u{FF66}'...'\u{FF6F}' => No, + '\u{FF70}' => No, + '\u{FF71}'...'\u{FF9D}' => No, + '\u{FF9E}'...'\u{FF9F}' => No, + '\u{FFA0}'...'\u{FFBE}' => No, + '\u{FFC2}'...'\u{FFC7}' => No, + '\u{FFCA}'...'\u{FFCF}' => No, + '\u{FFD2}'...'\u{FFD7}' => No, + '\u{FFDA}'...'\u{FFDC}' => No, + '\u{FFE0}'...'\u{FFE1}' => No, + '\u{FFE2}' => No, + '\u{FFE3}' => No, + '\u{FFE4}' => No, + '\u{FFE5}'...'\u{FFE6}' => No, + '\u{FFE8}' => No, + '\u{FFE9}'...'\u{FFEC}' => No, + '\u{FFED}'...'\u{FFEE}' => No, + '\u{1D15E}'...'\u{1D164}' => No, + '\u{1D1BB}'...'\u{1D1C0}' => No, + '\u{1D400}'...'\u{1D454}' => No, + '\u{1D456}'...'\u{1D49C}' => No, + '\u{1D49E}'...'\u{1D49F}' => No, + '\u{1D4A2}' => No, + '\u{1D4A5}'...'\u{1D4A6}' => No, + '\u{1D4A9}'...'\u{1D4AC}' => No, + '\u{1D4AE}'...'\u{1D4B9}' => No, + '\u{1D4BB}' => No, + '\u{1D4BD}'...'\u{1D4C3}' => No, + '\u{1D4C5}'...'\u{1D505}' => No, + '\u{1D507}'...'\u{1D50A}' => No, + '\u{1D50D}'...'\u{1D514}' => No, + '\u{1D516}'...'\u{1D51C}' => No, + '\u{1D51E}'...'\u{1D539}' => No, + '\u{1D53B}'...'\u{1D53E}' => No, + '\u{1D540}'...'\u{1D544}' => No, + '\u{1D546}' => No, + '\u{1D54A}'...'\u{1D550}' => No, + '\u{1D552}'...'\u{1D6A5}' => No, + '\u{1D6A8}'...'\u{1D6C0}' => No, + '\u{1D6C1}' => No, + '\u{1D6C2}'...'\u{1D6DA}' => No, + '\u{1D6DB}' => No, + '\u{1D6DC}'...'\u{1D6FA}' => No, + '\u{1D6FB}' => No, + '\u{1D6FC}'...'\u{1D714}' => No, + '\u{1D715}' => No, + '\u{1D716}'...'\u{1D734}' => No, + '\u{1D735}' => No, + '\u{1D736}'...'\u{1D74E}' => No, + '\u{1D74F}' => No, + '\u{1D750}'...'\u{1D76E}' => No, + '\u{1D76F}' => No, + '\u{1D770}'...'\u{1D788}' => No, + '\u{1D789}' => No, + '\u{1D78A}'...'\u{1D7A8}' => No, + '\u{1D7A9}' => No, + '\u{1D7AA}'...'\u{1D7C2}' => No, + '\u{1D7C3}' => No, + '\u{1D7C4}'...'\u{1D7CB}' => No, + '\u{1D7CE}'...'\u{1D7FF}' => No, + '\u{1EE00}'...'\u{1EE03}' => No, + '\u{1EE05}'...'\u{1EE1F}' => No, + '\u{1EE21}'...'\u{1EE22}' => No, + '\u{1EE24}' => No, + '\u{1EE27}' => No, + '\u{1EE29}'...'\u{1EE32}' => No, + '\u{1EE34}'...'\u{1EE37}' => No, + '\u{1EE39}' => No, + '\u{1EE3B}' => No, + '\u{1EE42}' => No, + '\u{1EE47}' => No, + '\u{1EE49}' => No, + '\u{1EE4B}' => No, + '\u{1EE4D}'...'\u{1EE4F}' => No, + '\u{1EE51}'...'\u{1EE52}' => No, + '\u{1EE54}' => No, + '\u{1EE57}' => No, + '\u{1EE59}' => No, + '\u{1EE5B}' => No, + '\u{1EE5D}' => No, + '\u{1EE5F}' => No, + '\u{1EE61}'...'\u{1EE62}' => No, + '\u{1EE64}' => No, + '\u{1EE67}'...'\u{1EE6A}' => No, + '\u{1EE6C}'...'\u{1EE72}' => No, + '\u{1EE74}'...'\u{1EE77}' => No, + '\u{1EE79}'...'\u{1EE7C}' => No, + '\u{1EE7E}' => No, + '\u{1EE80}'...'\u{1EE89}' => No, + '\u{1EE8B}'...'\u{1EE9B}' => No, + '\u{1EEA1}'...'\u{1EEA3}' => No, + '\u{1EEA5}'...'\u{1EEA9}' => No, + '\u{1EEAB}'...'\u{1EEBB}' => No, + '\u{1F100}'...'\u{1F10A}' => No, + '\u{1F110}'...'\u{1F12E}' => No, + '\u{1F130}'...'\u{1F14F}' => No, + '\u{1F16A}'...'\u{1F16B}' => No, + '\u{1F190}' => No, + '\u{1F200}'...'\u{1F202}' => No, + '\u{1F210}'...'\u{1F23B}' => No, + '\u{1F240}'...'\u{1F248}' => No, + '\u{1F250}'...'\u{1F251}' => No, + '\u{2F800}'...'\u{2FA1D}' => No, + '\u{0300}'...'\u{0304}' => Maybe, + '\u{0306}'...'\u{030C}' => Maybe, + '\u{030F}' => Maybe, + '\u{0311}' => Maybe, + '\u{0313}'...'\u{0314}' => Maybe, + '\u{031B}' => Maybe, + '\u{0323}'...'\u{0328}' => Maybe, + '\u{032D}'...'\u{032E}' => Maybe, + '\u{0330}'...'\u{0331}' => Maybe, + '\u{0338}' => Maybe, + '\u{0342}' => Maybe, + '\u{0345}' => Maybe, + '\u{0653}'...'\u{0655}' => Maybe, + '\u{093C}' => Maybe, + '\u{09BE}' => Maybe, + '\u{09D7}' => Maybe, + '\u{0B3E}' => Maybe, + '\u{0B56}' => Maybe, + '\u{0B57}' => Maybe, + '\u{0BBE}' => Maybe, + '\u{0BD7}' => Maybe, + '\u{0C56}' => Maybe, + '\u{0CC2}' => Maybe, + '\u{0CD5}'...'\u{0CD6}' => Maybe, + '\u{0D3E}' => Maybe, + '\u{0D57}' => Maybe, + '\u{0DCA}' => Maybe, + '\u{0DCF}' => Maybe, + '\u{0DDF}' => Maybe, + '\u{102E}' => Maybe, + '\u{1161}'...'\u{1175}' => Maybe, + '\u{11A8}'...'\u{11C2}' => Maybe, + '\u{1B35}' => Maybe, + '\u{3099}'...'\u{309A}' => Maybe, + '\u{110BA}' => Maybe, + '\u{11127}' => Maybe, + '\u{1133E}' => Maybe, + '\u{11357}' => Maybe, + '\u{114B0}' => Maybe, + '\u{114BA}' => Maybe, + '\u{114BD}' => Maybe, + '\u{115AF}' => Maybe, + _ => Yes, + } +} + +#[inline] +pub fn qc_nfd(c: char) -> IsNormalized { + match c { + '\u{00C0}'...'\u{00C5}' => No, + '\u{00C7}'...'\u{00CF}' => No, + '\u{00D1}'...'\u{00D6}' => No, + '\u{00D9}'...'\u{00DD}' => No, + '\u{00E0}'...'\u{00E5}' => No, + '\u{00E7}'...'\u{00EF}' => No, + '\u{00F1}'...'\u{00F6}' => No, + '\u{00F9}'...'\u{00FD}' => No, + '\u{00FF}'...'\u{010F}' => No, + '\u{0112}'...'\u{0125}' => No, + '\u{0128}'...'\u{0130}' => No, + '\u{0134}'...'\u{0137}' => No, + '\u{0139}'...'\u{013E}' => No, + '\u{0143}'...'\u{0148}' => No, + '\u{014C}'...'\u{0151}' => No, + '\u{0154}'...'\u{0165}' => No, + '\u{0168}'...'\u{017E}' => No, + '\u{01A0}'...'\u{01A1}' => No, + '\u{01AF}'...'\u{01B0}' => No, + '\u{01CD}'...'\u{01DC}' => No, + '\u{01DE}'...'\u{01E3}' => No, + '\u{01E6}'...'\u{01F0}' => No, + '\u{01F4}'...'\u{01F5}' => No, + '\u{01F8}'...'\u{021B}' => No, + '\u{021E}'...'\u{021F}' => No, + '\u{0226}'...'\u{0233}' => No, + '\u{0340}'...'\u{0341}' => No, + '\u{0343}'...'\u{0344}' => No, + '\u{0374}' => No, + '\u{037E}' => No, + '\u{0385}' => No, + '\u{0386}' => No, + '\u{0387}' => No, + '\u{0388}'...'\u{038A}' => No, + '\u{038C}' => No, + '\u{038E}'...'\u{0390}' => No, + '\u{03AA}'...'\u{03B0}' => No, + '\u{03CA}'...'\u{03CE}' => No, + '\u{03D3}'...'\u{03D4}' => No, + '\u{0400}'...'\u{0401}' => No, + '\u{0403}' => No, + '\u{0407}' => No, + '\u{040C}'...'\u{040E}' => No, + '\u{0419}' => No, + '\u{0439}' => No, + '\u{0450}'...'\u{0451}' => No, + '\u{0453}' => No, + '\u{0457}' => No, + '\u{045C}'...'\u{045E}' => No, + '\u{0476}'...'\u{0477}' => No, + '\u{04C1}'...'\u{04C2}' => No, + '\u{04D0}'...'\u{04D3}' => No, + '\u{04D6}'...'\u{04D7}' => No, + '\u{04DA}'...'\u{04DF}' => No, + '\u{04E2}'...'\u{04E7}' => No, + '\u{04EA}'...'\u{04F5}' => No, + '\u{04F8}'...'\u{04F9}' => No, + '\u{0622}'...'\u{0626}' => No, + '\u{06C0}' => No, + '\u{06C2}' => No, + '\u{06D3}' => No, + '\u{0929}' => No, + '\u{0931}' => No, + '\u{0934}' => No, + '\u{0958}'...'\u{095F}' => No, + '\u{09CB}'...'\u{09CC}' => No, + '\u{09DC}'...'\u{09DD}' => No, + '\u{09DF}' => No, + '\u{0A33}' => No, + '\u{0A36}' => No, + '\u{0A59}'...'\u{0A5B}' => No, + '\u{0A5E}' => No, + '\u{0B48}' => No, + '\u{0B4B}'...'\u{0B4C}' => No, + '\u{0B5C}'...'\u{0B5D}' => No, + '\u{0B94}' => No, + '\u{0BCA}'...'\u{0BCC}' => No, + '\u{0C48}' => No, + '\u{0CC0}' => No, + '\u{0CC7}'...'\u{0CC8}' => No, + '\u{0CCA}'...'\u{0CCB}' => No, + '\u{0D4A}'...'\u{0D4C}' => No, + '\u{0DDA}' => No, + '\u{0DDC}'...'\u{0DDE}' => No, + '\u{0F43}' => No, + '\u{0F4D}' => No, + '\u{0F52}' => No, + '\u{0F57}' => No, + '\u{0F5C}' => No, + '\u{0F69}' => No, + '\u{0F73}' => No, + '\u{0F75}'...'\u{0F76}' => No, + '\u{0F78}' => No, + '\u{0F81}' => No, + '\u{0F93}' => No, + '\u{0F9D}' => No, + '\u{0FA2}' => No, + '\u{0FA7}' => No, + '\u{0FAC}' => No, + '\u{0FB9}' => No, + '\u{1026}' => No, + '\u{1B06}' => No, + '\u{1B08}' => No, + '\u{1B0A}' => No, + '\u{1B0C}' => No, + '\u{1B0E}' => No, + '\u{1B12}' => No, + '\u{1B3B}' => No, + '\u{1B3D}' => No, + '\u{1B40}'...'\u{1B41}' => No, + '\u{1B43}' => No, + '\u{1E00}'...'\u{1E99}' => No, + '\u{1E9B}' => No, + '\u{1EA0}'...'\u{1EF9}' => No, + '\u{1F00}'...'\u{1F15}' => No, + '\u{1F18}'...'\u{1F1D}' => No, + '\u{1F20}'...'\u{1F45}' => No, + '\u{1F48}'...'\u{1F4D}' => No, + '\u{1F50}'...'\u{1F57}' => No, + '\u{1F59}' => No, + '\u{1F5B}' => No, + '\u{1F5D}' => No, + '\u{1F5F}'...'\u{1F7D}' => No, + '\u{1F80}'...'\u{1FB4}' => No, + '\u{1FB6}'...'\u{1FBC}' => No, + '\u{1FBE}' => No, + '\u{1FC1}' => No, + '\u{1FC2}'...'\u{1FC4}' => No, + '\u{1FC6}'...'\u{1FCC}' => No, + '\u{1FCD}'...'\u{1FCF}' => No, + '\u{1FD0}'...'\u{1FD3}' => No, + '\u{1FD6}'...'\u{1FDB}' => No, + '\u{1FDD}'...'\u{1FDF}' => No, + '\u{1FE0}'...'\u{1FEC}' => No, + '\u{1FED}'...'\u{1FEF}' => No, + '\u{1FF2}'...'\u{1FF4}' => No, + '\u{1FF6}'...'\u{1FFC}' => No, + '\u{1FFD}' => No, + '\u{2000}'...'\u{2001}' => No, + '\u{2126}' => No, + '\u{212A}'...'\u{212B}' => No, + '\u{219A}'...'\u{219B}' => No, + '\u{21AE}' => No, + '\u{21CD}' => No, + '\u{21CE}'...'\u{21CF}' => No, + '\u{2204}' => No, + '\u{2209}' => No, + '\u{220C}' => No, + '\u{2224}' => No, + '\u{2226}' => No, + '\u{2241}' => No, + '\u{2244}' => No, + '\u{2247}' => No, + '\u{2249}' => No, + '\u{2260}' => No, + '\u{2262}' => No, + '\u{226D}'...'\u{2271}' => No, + '\u{2274}'...'\u{2275}' => No, + '\u{2278}'...'\u{2279}' => No, + '\u{2280}'...'\u{2281}' => No, + '\u{2284}'...'\u{2285}' => No, + '\u{2288}'...'\u{2289}' => No, + '\u{22AC}'...'\u{22AF}' => No, + '\u{22E0}'...'\u{22E3}' => No, + '\u{22EA}'...'\u{22ED}' => No, + '\u{2329}' => No, + '\u{232A}' => No, + '\u{2ADC}' => No, + '\u{304C}' => No, + '\u{304E}' => No, + '\u{3050}' => No, + '\u{3052}' => No, + '\u{3054}' => No, + '\u{3056}' => No, + '\u{3058}' => No, + '\u{305A}' => No, + '\u{305C}' => No, + '\u{305E}' => No, + '\u{3060}' => No, + '\u{3062}' => No, + '\u{3065}' => No, + '\u{3067}' => No, + '\u{3069}' => No, + '\u{3070}'...'\u{3071}' => No, + '\u{3073}'...'\u{3074}' => No, + '\u{3076}'...'\u{3077}' => No, + '\u{3079}'...'\u{307A}' => No, + '\u{307C}'...'\u{307D}' => No, + '\u{3094}' => No, + '\u{309E}' => No, + '\u{30AC}' => No, + '\u{30AE}' => No, + '\u{30B0}' => No, + '\u{30B2}' => No, + '\u{30B4}' => No, + '\u{30B6}' => No, + '\u{30B8}' => No, + '\u{30BA}' => No, + '\u{30BC}' => No, + '\u{30BE}' => No, + '\u{30C0}' => No, + '\u{30C2}' => No, + '\u{30C5}' => No, + '\u{30C7}' => No, + '\u{30C9}' => No, + '\u{30D0}'...'\u{30D1}' => No, + '\u{30D3}'...'\u{30D4}' => No, + '\u{30D6}'...'\u{30D7}' => No, + '\u{30D9}'...'\u{30DA}' => No, + '\u{30DC}'...'\u{30DD}' => No, + '\u{30F4}' => No, + '\u{30F7}'...'\u{30FA}' => No, + '\u{30FE}' => No, + '\u{AC00}'...'\u{D7A3}' => No, + '\u{F900}'...'\u{FA0D}' => No, + '\u{FA10}' => No, + '\u{FA12}' => No, + '\u{FA15}'...'\u{FA1E}' => No, + '\u{FA20}' => No, + '\u{FA22}' => No, + '\u{FA25}'...'\u{FA26}' => No, + '\u{FA2A}'...'\u{FA6D}' => No, + '\u{FA70}'...'\u{FAD9}' => No, + '\u{FB1D}' => No, + '\u{FB1F}' => No, + '\u{FB2A}'...'\u{FB36}' => No, + '\u{FB38}'...'\u{FB3C}' => No, + '\u{FB3E}' => No, + '\u{FB40}'...'\u{FB41}' => No, + '\u{FB43}'...'\u{FB44}' => No, + '\u{FB46}'...'\u{FB4E}' => No, + '\u{1109A}' => No, + '\u{1109C}' => No, + '\u{110AB}' => No, + '\u{1112E}'...'\u{1112F}' => No, + '\u{1134B}'...'\u{1134C}' => No, + '\u{114BB}'...'\u{114BC}' => No, + '\u{114BE}' => No, + '\u{115BA}'...'\u{115BB}' => No, + '\u{1D15E}'...'\u{1D164}' => No, + '\u{1D1BB}'...'\u{1D1C0}' => No, + '\u{2F800}'...'\u{2FA1D}' => No, + _ => Yes, + } +} + +#[inline] +pub fn qc_nfkd(c: char) -> IsNormalized { + match c { + '\u{00A0}' => No, + '\u{00A8}' => No, + '\u{00AA}' => No, + '\u{00AF}' => No, + '\u{00B2}'...'\u{00B3}' => No, + '\u{00B4}' => No, + '\u{00B5}' => No, + '\u{00B8}' => No, + '\u{00B9}' => No, + '\u{00BA}' => No, + '\u{00BC}'...'\u{00BE}' => No, + '\u{00C0}'...'\u{00C5}' => No, + '\u{00C7}'...'\u{00CF}' => No, + '\u{00D1}'...'\u{00D6}' => No, + '\u{00D9}'...'\u{00DD}' => No, + '\u{00E0}'...'\u{00E5}' => No, + '\u{00E7}'...'\u{00EF}' => No, + '\u{00F1}'...'\u{00F6}' => No, + '\u{00F9}'...'\u{00FD}' => No, + '\u{00FF}'...'\u{010F}' => No, + '\u{0112}'...'\u{0125}' => No, + '\u{0128}'...'\u{0130}' => No, + '\u{0132}'...'\u{0137}' => No, + '\u{0139}'...'\u{0140}' => No, + '\u{0143}'...'\u{0149}' => No, + '\u{014C}'...'\u{0151}' => No, + '\u{0154}'...'\u{0165}' => No, + '\u{0168}'...'\u{017F}' => No, + '\u{01A0}'...'\u{01A1}' => No, + '\u{01AF}'...'\u{01B0}' => No, + '\u{01C4}'...'\u{01DC}' => No, + '\u{01DE}'...'\u{01E3}' => No, + '\u{01E6}'...'\u{01F5}' => No, + '\u{01F8}'...'\u{021B}' => No, + '\u{021E}'...'\u{021F}' => No, + '\u{0226}'...'\u{0233}' => No, + '\u{02B0}'...'\u{02B8}' => No, + '\u{02D8}'...'\u{02DD}' => No, + '\u{02E0}'...'\u{02E4}' => No, + '\u{0340}'...'\u{0341}' => No, + '\u{0343}'...'\u{0344}' => No, + '\u{0374}' => No, + '\u{037A}' => No, + '\u{037E}' => No, + '\u{0384}'...'\u{0385}' => No, + '\u{0386}' => No, + '\u{0387}' => No, + '\u{0388}'...'\u{038A}' => No, + '\u{038C}' => No, + '\u{038E}'...'\u{0390}' => No, + '\u{03AA}'...'\u{03B0}' => No, + '\u{03CA}'...'\u{03CE}' => No, + '\u{03D0}'...'\u{03D6}' => No, + '\u{03F0}'...'\u{03F2}' => No, + '\u{03F4}'...'\u{03F5}' => No, + '\u{03F9}' => No, + '\u{0400}'...'\u{0401}' => No, + '\u{0403}' => No, + '\u{0407}' => No, + '\u{040C}'...'\u{040E}' => No, + '\u{0419}' => No, + '\u{0439}' => No, + '\u{0450}'...'\u{0451}' => No, + '\u{0453}' => No, + '\u{0457}' => No, + '\u{045C}'...'\u{045E}' => No, + '\u{0476}'...'\u{0477}' => No, + '\u{04C1}'...'\u{04C2}' => No, + '\u{04D0}'...'\u{04D3}' => No, + '\u{04D6}'...'\u{04D7}' => No, + '\u{04DA}'...'\u{04DF}' => No, + '\u{04E2}'...'\u{04E7}' => No, + '\u{04EA}'...'\u{04F5}' => No, + '\u{04F8}'...'\u{04F9}' => No, + '\u{0587}' => No, + '\u{0622}'...'\u{0626}' => No, + '\u{0675}'...'\u{0678}' => No, + '\u{06C0}' => No, + '\u{06C2}' => No, + '\u{06D3}' => No, + '\u{0929}' => No, + '\u{0931}' => No, + '\u{0934}' => No, + '\u{0958}'...'\u{095F}' => No, + '\u{09CB}'...'\u{09CC}' => No, + '\u{09DC}'...'\u{09DD}' => No, + '\u{09DF}' => No, + '\u{0A33}' => No, + '\u{0A36}' => No, + '\u{0A59}'...'\u{0A5B}' => No, + '\u{0A5E}' => No, + '\u{0B48}' => No, + '\u{0B4B}'...'\u{0B4C}' => No, + '\u{0B5C}'...'\u{0B5D}' => No, + '\u{0B94}' => No, + '\u{0BCA}'...'\u{0BCC}' => No, + '\u{0C48}' => No, + '\u{0CC0}' => No, + '\u{0CC7}'...'\u{0CC8}' => No, + '\u{0CCA}'...'\u{0CCB}' => No, + '\u{0D4A}'...'\u{0D4C}' => No, + '\u{0DDA}' => No, + '\u{0DDC}'...'\u{0DDE}' => No, + '\u{0E33}' => No, + '\u{0EB3}' => No, + '\u{0EDC}'...'\u{0EDD}' => No, + '\u{0F0C}' => No, + '\u{0F43}' => No, + '\u{0F4D}' => No, + '\u{0F52}' => No, + '\u{0F57}' => No, + '\u{0F5C}' => No, + '\u{0F69}' => No, + '\u{0F73}' => No, + '\u{0F75}'...'\u{0F79}' => No, + '\u{0F81}' => No, + '\u{0F93}' => No, + '\u{0F9D}' => No, + '\u{0FA2}' => No, + '\u{0FA7}' => No, + '\u{0FAC}' => No, + '\u{0FB9}' => No, + '\u{1026}' => No, + '\u{10FC}' => No, + '\u{1B06}' => No, + '\u{1B08}' => No, + '\u{1B0A}' => No, + '\u{1B0C}' => No, + '\u{1B0E}' => No, + '\u{1B12}' => No, + '\u{1B3B}' => No, + '\u{1B3D}' => No, + '\u{1B40}'...'\u{1B41}' => No, + '\u{1B43}' => No, + '\u{1D2C}'...'\u{1D2E}' => No, + '\u{1D30}'...'\u{1D3A}' => No, + '\u{1D3C}'...'\u{1D4D}' => No, + '\u{1D4F}'...'\u{1D6A}' => No, + '\u{1D78}' => No, + '\u{1D9B}'...'\u{1DBF}' => No, + '\u{1E00}'...'\u{1E9B}' => No, + '\u{1EA0}'...'\u{1EF9}' => No, + '\u{1F00}'...'\u{1F15}' => No, + '\u{1F18}'...'\u{1F1D}' => No, + '\u{1F20}'...'\u{1F45}' => No, + '\u{1F48}'...'\u{1F4D}' => No, + '\u{1F50}'...'\u{1F57}' => No, + '\u{1F59}' => No, + '\u{1F5B}' => No, + '\u{1F5D}' => No, + '\u{1F5F}'...'\u{1F7D}' => No, + '\u{1F80}'...'\u{1FB4}' => No, + '\u{1FB6}'...'\u{1FBC}' => No, + '\u{1FBD}' => No, + '\u{1FBE}' => No, + '\u{1FBF}'...'\u{1FC1}' => No, + '\u{1FC2}'...'\u{1FC4}' => No, + '\u{1FC6}'...'\u{1FCC}' => No, + '\u{1FCD}'...'\u{1FCF}' => No, + '\u{1FD0}'...'\u{1FD3}' => No, + '\u{1FD6}'...'\u{1FDB}' => No, + '\u{1FDD}'...'\u{1FDF}' => No, + '\u{1FE0}'...'\u{1FEC}' => No, + '\u{1FED}'...'\u{1FEF}' => No, + '\u{1FF2}'...'\u{1FF4}' => No, + '\u{1FF6}'...'\u{1FFC}' => No, + '\u{1FFD}'...'\u{1FFE}' => No, + '\u{2000}'...'\u{200A}' => No, + '\u{2011}' => No, + '\u{2017}' => No, + '\u{2024}'...'\u{2026}' => No, + '\u{202F}' => No, + '\u{2033}'...'\u{2034}' => No, + '\u{2036}'...'\u{2037}' => No, + '\u{203C}' => No, + '\u{203E}' => No, + '\u{2047}'...'\u{2049}' => No, + '\u{2057}' => No, + '\u{205F}' => No, + '\u{2070}' => No, + '\u{2071}' => No, + '\u{2074}'...'\u{2079}' => No, + '\u{207A}'...'\u{207C}' => No, + '\u{207D}' => No, + '\u{207E}' => No, + '\u{207F}' => No, + '\u{2080}'...'\u{2089}' => No, + '\u{208A}'...'\u{208C}' => No, + '\u{208D}' => No, + '\u{208E}' => No, + '\u{2090}'...'\u{209C}' => No, + '\u{20A8}' => No, + '\u{2100}'...'\u{2101}' => No, + '\u{2102}' => No, + '\u{2103}' => No, + '\u{2105}'...'\u{2106}' => No, + '\u{2107}' => No, + '\u{2109}' => No, + '\u{210A}'...'\u{2113}' => No, + '\u{2115}' => No, + '\u{2116}' => No, + '\u{2119}'...'\u{211D}' => No, + '\u{2120}'...'\u{2122}' => No, + '\u{2124}' => No, + '\u{2126}' => No, + '\u{2128}' => No, + '\u{212A}'...'\u{212D}' => No, + '\u{212F}'...'\u{2131}' => No, + '\u{2133}'...'\u{2134}' => No, + '\u{2135}'...'\u{2138}' => No, + '\u{2139}' => No, + '\u{213B}' => No, + '\u{213C}'...'\u{213F}' => No, + '\u{2140}' => No, + '\u{2145}'...'\u{2149}' => No, + '\u{2150}'...'\u{215F}' => No, + '\u{2160}'...'\u{217F}' => No, + '\u{2189}' => No, + '\u{219A}'...'\u{219B}' => No, + '\u{21AE}' => No, + '\u{21CD}' => No, + '\u{21CE}'...'\u{21CF}' => No, + '\u{2204}' => No, + '\u{2209}' => No, + '\u{220C}' => No, + '\u{2224}' => No, + '\u{2226}' => No, + '\u{222C}'...'\u{222D}' => No, + '\u{222F}'...'\u{2230}' => No, + '\u{2241}' => No, + '\u{2244}' => No, + '\u{2247}' => No, + '\u{2249}' => No, + '\u{2260}' => No, + '\u{2262}' => No, + '\u{226D}'...'\u{2271}' => No, + '\u{2274}'...'\u{2275}' => No, + '\u{2278}'...'\u{2279}' => No, + '\u{2280}'...'\u{2281}' => No, + '\u{2284}'...'\u{2285}' => No, + '\u{2288}'...'\u{2289}' => No, + '\u{22AC}'...'\u{22AF}' => No, + '\u{22E0}'...'\u{22E3}' => No, + '\u{22EA}'...'\u{22ED}' => No, + '\u{2329}' => No, + '\u{232A}' => No, + '\u{2460}'...'\u{249B}' => No, + '\u{249C}'...'\u{24E9}' => No, + '\u{24EA}' => No, + '\u{2A0C}' => No, + '\u{2A74}'...'\u{2A76}' => No, + '\u{2ADC}' => No, + '\u{2C7C}'...'\u{2C7D}' => No, + '\u{2D6F}' => No, + '\u{2E9F}' => No, + '\u{2EF3}' => No, + '\u{2F00}'...'\u{2FD5}' => No, + '\u{3000}' => No, + '\u{3036}' => No, + '\u{3038}'...'\u{303A}' => No, + '\u{304C}' => No, + '\u{304E}' => No, + '\u{3050}' => No, + '\u{3052}' => No, + '\u{3054}' => No, + '\u{3056}' => No, + '\u{3058}' => No, + '\u{305A}' => No, + '\u{305C}' => No, + '\u{305E}' => No, + '\u{3060}' => No, + '\u{3062}' => No, + '\u{3065}' => No, + '\u{3067}' => No, + '\u{3069}' => No, + '\u{3070}'...'\u{3071}' => No, + '\u{3073}'...'\u{3074}' => No, + '\u{3076}'...'\u{3077}' => No, + '\u{3079}'...'\u{307A}' => No, + '\u{307C}'...'\u{307D}' => No, + '\u{3094}' => No, + '\u{309B}'...'\u{309C}' => No, + '\u{309E}' => No, + '\u{309F}' => No, + '\u{30AC}' => No, + '\u{30AE}' => No, + '\u{30B0}' => No, + '\u{30B2}' => No, + '\u{30B4}' => No, + '\u{30B6}' => No, + '\u{30B8}' => No, + '\u{30BA}' => No, + '\u{30BC}' => No, + '\u{30BE}' => No, + '\u{30C0}' => No, + '\u{30C2}' => No, + '\u{30C5}' => No, + '\u{30C7}' => No, + '\u{30C9}' => No, + '\u{30D0}'...'\u{30D1}' => No, + '\u{30D3}'...'\u{30D4}' => No, + '\u{30D6}'...'\u{30D7}' => No, + '\u{30D9}'...'\u{30DA}' => No, + '\u{30DC}'...'\u{30DD}' => No, + '\u{30F4}' => No, + '\u{30F7}'...'\u{30FA}' => No, + '\u{30FE}' => No, + '\u{30FF}' => No, + '\u{3131}'...'\u{318E}' => No, + '\u{3192}'...'\u{3195}' => No, + '\u{3196}'...'\u{319F}' => No, + '\u{3200}'...'\u{321E}' => No, + '\u{3220}'...'\u{3229}' => No, + '\u{322A}'...'\u{3247}' => No, + '\u{3250}' => No, + '\u{3251}'...'\u{325F}' => No, + '\u{3260}'...'\u{327E}' => No, + '\u{3280}'...'\u{3289}' => No, + '\u{328A}'...'\u{32B0}' => No, + '\u{32B1}'...'\u{32BF}' => No, + '\u{32C0}'...'\u{32FE}' => No, + '\u{3300}'...'\u{33FF}' => No, + '\u{A69C}'...'\u{A69D}' => No, + '\u{A770}' => No, + '\u{A7F8}'...'\u{A7F9}' => No, + '\u{AB5C}'...'\u{AB5F}' => No, + '\u{AC00}'...'\u{D7A3}' => No, + '\u{F900}'...'\u{FA0D}' => No, + '\u{FA10}' => No, + '\u{FA12}' => No, + '\u{FA15}'...'\u{FA1E}' => No, + '\u{FA20}' => No, + '\u{FA22}' => No, + '\u{FA25}'...'\u{FA26}' => No, + '\u{FA2A}'...'\u{FA6D}' => No, + '\u{FA70}'...'\u{FAD9}' => No, + '\u{FB00}'...'\u{FB06}' => No, + '\u{FB13}'...'\u{FB17}' => No, + '\u{FB1D}' => No, + '\u{FB1F}'...'\u{FB28}' => No, + '\u{FB29}' => No, + '\u{FB2A}'...'\u{FB36}' => No, + '\u{FB38}'...'\u{FB3C}' => No, + '\u{FB3E}' => No, + '\u{FB40}'...'\u{FB41}' => No, + '\u{FB43}'...'\u{FB44}' => No, + '\u{FB46}'...'\u{FBB1}' => No, + '\u{FBD3}'...'\u{FD3D}' => No, + '\u{FD50}'...'\u{FD8F}' => No, + '\u{FD92}'...'\u{FDC7}' => No, + '\u{FDF0}'...'\u{FDFB}' => No, + '\u{FDFC}' => No, + '\u{FE10}'...'\u{FE16}' => No, + '\u{FE17}' => No, + '\u{FE18}' => No, + '\u{FE19}' => No, + '\u{FE30}' => No, + '\u{FE31}'...'\u{FE32}' => No, + '\u{FE33}'...'\u{FE34}' => No, + '\u{FE35}' => No, + '\u{FE36}' => No, + '\u{FE37}' => No, + '\u{FE38}' => No, + '\u{FE39}' => No, + '\u{FE3A}' => No, + '\u{FE3B}' => No, + '\u{FE3C}' => No, + '\u{FE3D}' => No, + '\u{FE3E}' => No, + '\u{FE3F}' => No, + '\u{FE40}' => No, + '\u{FE41}' => No, + '\u{FE42}' => No, + '\u{FE43}' => No, + '\u{FE44}' => No, + '\u{FE47}' => No, + '\u{FE48}' => No, + '\u{FE49}'...'\u{FE4C}' => No, + '\u{FE4D}'...'\u{FE4F}' => No, + '\u{FE50}'...'\u{FE52}' => No, + '\u{FE54}'...'\u{FE57}' => No, + '\u{FE58}' => No, + '\u{FE59}' => No, + '\u{FE5A}' => No, + '\u{FE5B}' => No, + '\u{FE5C}' => No, + '\u{FE5D}' => No, + '\u{FE5E}' => No, + '\u{FE5F}'...'\u{FE61}' => No, + '\u{FE62}' => No, + '\u{FE63}' => No, + '\u{FE64}'...'\u{FE66}' => No, + '\u{FE68}' => No, + '\u{FE69}' => No, + '\u{FE6A}'...'\u{FE6B}' => No, + '\u{FE70}'...'\u{FE72}' => No, + '\u{FE74}' => No, + '\u{FE76}'...'\u{FEFC}' => No, + '\u{FF01}'...'\u{FF03}' => No, + '\u{FF04}' => No, + '\u{FF05}'...'\u{FF07}' => No, + '\u{FF08}' => No, + '\u{FF09}' => No, + '\u{FF0A}' => No, + '\u{FF0B}' => No, + '\u{FF0C}' => No, + '\u{FF0D}' => No, + '\u{FF0E}'...'\u{FF0F}' => No, + '\u{FF10}'...'\u{FF19}' => No, + '\u{FF1A}'...'\u{FF1B}' => No, + '\u{FF1C}'...'\u{FF1E}' => No, + '\u{FF1F}'...'\u{FF20}' => No, + '\u{FF21}'...'\u{FF3A}' => No, + '\u{FF3B}' => No, + '\u{FF3C}' => No, + '\u{FF3D}' => No, + '\u{FF3E}' => No, + '\u{FF3F}' => No, + '\u{FF40}' => No, + '\u{FF41}'...'\u{FF5A}' => No, + '\u{FF5B}' => No, + '\u{FF5C}' => No, + '\u{FF5D}' => No, + '\u{FF5E}' => No, + '\u{FF5F}' => No, + '\u{FF60}' => No, + '\u{FF61}' => No, + '\u{FF62}' => No, + '\u{FF63}' => No, + '\u{FF64}'...'\u{FF65}' => No, + '\u{FF66}'...'\u{FF6F}' => No, + '\u{FF70}' => No, + '\u{FF71}'...'\u{FF9D}' => No, + '\u{FF9E}'...'\u{FF9F}' => No, + '\u{FFA0}'...'\u{FFBE}' => No, + '\u{FFC2}'...'\u{FFC7}' => No, + '\u{FFCA}'...'\u{FFCF}' => No, + '\u{FFD2}'...'\u{FFD7}' => No, + '\u{FFDA}'...'\u{FFDC}' => No, + '\u{FFE0}'...'\u{FFE1}' => No, + '\u{FFE2}' => No, + '\u{FFE3}' => No, + '\u{FFE4}' => No, + '\u{FFE5}'...'\u{FFE6}' => No, + '\u{FFE8}' => No, + '\u{FFE9}'...'\u{FFEC}' => No, + '\u{FFED}'...'\u{FFEE}' => No, + '\u{1109A}' => No, + '\u{1109C}' => No, + '\u{110AB}' => No, + '\u{1112E}'...'\u{1112F}' => No, + '\u{1134B}'...'\u{1134C}' => No, + '\u{114BB}'...'\u{114BC}' => No, + '\u{114BE}' => No, + '\u{115BA}'...'\u{115BB}' => No, + '\u{1D15E}'...'\u{1D164}' => No, + '\u{1D1BB}'...'\u{1D1C0}' => No, + '\u{1D400}'...'\u{1D454}' => No, + '\u{1D456}'...'\u{1D49C}' => No, + '\u{1D49E}'...'\u{1D49F}' => No, + '\u{1D4A2}' => No, + '\u{1D4A5}'...'\u{1D4A6}' => No, + '\u{1D4A9}'...'\u{1D4AC}' => No, + '\u{1D4AE}'...'\u{1D4B9}' => No, + '\u{1D4BB}' => No, + '\u{1D4BD}'...'\u{1D4C3}' => No, + '\u{1D4C5}'...'\u{1D505}' => No, + '\u{1D507}'...'\u{1D50A}' => No, + '\u{1D50D}'...'\u{1D514}' => No, + '\u{1D516}'...'\u{1D51C}' => No, + '\u{1D51E}'...'\u{1D539}' => No, + '\u{1D53B}'...'\u{1D53E}' => No, + '\u{1D540}'...'\u{1D544}' => No, + '\u{1D546}' => No, + '\u{1D54A}'...'\u{1D550}' => No, + '\u{1D552}'...'\u{1D6A5}' => No, + '\u{1D6A8}'...'\u{1D6C0}' => No, + '\u{1D6C1}' => No, + '\u{1D6C2}'...'\u{1D6DA}' => No, + '\u{1D6DB}' => No, + '\u{1D6DC}'...'\u{1D6FA}' => No, + '\u{1D6FB}' => No, + '\u{1D6FC}'...'\u{1D714}' => No, + '\u{1D715}' => No, + '\u{1D716}'...'\u{1D734}' => No, + '\u{1D735}' => No, + '\u{1D736}'...'\u{1D74E}' => No, + '\u{1D74F}' => No, + '\u{1D750}'...'\u{1D76E}' => No, + '\u{1D76F}' => No, + '\u{1D770}'...'\u{1D788}' => No, + '\u{1D789}' => No, + '\u{1D78A}'...'\u{1D7A8}' => No, + '\u{1D7A9}' => No, + '\u{1D7AA}'...'\u{1D7C2}' => No, + '\u{1D7C3}' => No, + '\u{1D7C4}'...'\u{1D7CB}' => No, + '\u{1D7CE}'...'\u{1D7FF}' => No, + '\u{1EE00}'...'\u{1EE03}' => No, + '\u{1EE05}'...'\u{1EE1F}' => No, + '\u{1EE21}'...'\u{1EE22}' => No, + '\u{1EE24}' => No, + '\u{1EE27}' => No, + '\u{1EE29}'...'\u{1EE32}' => No, + '\u{1EE34}'...'\u{1EE37}' => No, + '\u{1EE39}' => No, + '\u{1EE3B}' => No, + '\u{1EE42}' => No, + '\u{1EE47}' => No, + '\u{1EE49}' => No, + '\u{1EE4B}' => No, + '\u{1EE4D}'...'\u{1EE4F}' => No, + '\u{1EE51}'...'\u{1EE52}' => No, + '\u{1EE54}' => No, + '\u{1EE57}' => No, + '\u{1EE59}' => No, + '\u{1EE5B}' => No, + '\u{1EE5D}' => No, + '\u{1EE5F}' => No, + '\u{1EE61}'...'\u{1EE62}' => No, + '\u{1EE64}' => No, + '\u{1EE67}'...'\u{1EE6A}' => No, + '\u{1EE6C}'...'\u{1EE72}' => No, + '\u{1EE74}'...'\u{1EE77}' => No, + '\u{1EE79}'...'\u{1EE7C}' => No, + '\u{1EE7E}' => No, + '\u{1EE80}'...'\u{1EE89}' => No, + '\u{1EE8B}'...'\u{1EE9B}' => No, + '\u{1EEA1}'...'\u{1EEA3}' => No, + '\u{1EEA5}'...'\u{1EEA9}' => No, + '\u{1EEAB}'...'\u{1EEBB}' => No, + '\u{1F100}'...'\u{1F10A}' => No, + '\u{1F110}'...'\u{1F12E}' => No, + '\u{1F130}'...'\u{1F14F}' => No, + '\u{1F16A}'...'\u{1F16B}' => No, + '\u{1F190}' => No, + '\u{1F200}'...'\u{1F202}' => No, + '\u{1F210}'...'\u{1F23B}' => No, + '\u{1F240}'...'\u{1F248}' => No, + '\u{1F250}'...'\u{1F251}' => No, + '\u{2F800}'...'\u{2FA1D}' => No, + _ => Yes, + } +} + +#[inline] +pub fn stream_safe_leading_nonstarters(c: char) -> usize { + match c { + '\u{0340}' => 1, + '\u{0341}' => 1, + '\u{0343}' => 1, + '\u{0344}' => 2, + '\u{0F81}' => 2, + '\u{0F73}' => 2, + '\u{0F75}' => 2, + '\u{FF9E}' => 1, + '\u{FF9F}' => 1, + _ => 0, + } +} + +#[inline] +pub fn stream_safe_trailing_nonstarters(c: char) -> usize { + match c { + '\u{0958}' => 1, + '\u{0959}' => 1, + '\u{095A}' => 1, + '\u{095B}' => 1, + '\u{095C}' => 1, + '\u{FE87}' => 1, + '\u{095D}' => 1, + '\u{095E}' => 1, + '\u{095F}' => 1, + '\u{203E}' => 1, + '\u{1D160}' => 2, + '\u{1D161}' => 2, + '\u{FEF9}' => 1, + '\u{304C}' => 1, + '\u{1D162}' => 2, + '\u{304E}' => 1, + '\u{3050}' => 1, + '\u{3052}' => 1, + '\u{1D163}' => 2, + '\u{3054}' => 1, + '\u{3056}' => 1, + '\u{3058}' => 1, + '\u{1D164}' => 2, + '\u{305A}' => 1, + '\u{305C}' => 1, + '\u{305E}' => 1, + '\u{3060}' => 1, + '\u{3062}' => 1, + '\u{3065}' => 1, + '\u{3067}' => 1, + '\u{3069}' => 1, + '\u{3070}' => 1, + '\u{3071}' => 1, + '\u{3073}' => 1, + '\u{3074}' => 1, + '\u{3076}' => 1, + '\u{3077}' => 1, + '\u{3079}' => 1, + '\u{307A}' => 1, + '\u{307C}' => 1, + '\u{307D}' => 1, + '\u{1EC0}' => 2, + '\u{2017}' => 1, + '\u{1EC2}' => 2, + '\u{3094}' => 1, + '\u{FEF7}' => 1, + '\u{1109A}' => 1, + '\u{309B}' => 1, + '\u{1109C}' => 1, + '\u{309E}' => 1, + '\u{FB32}' => 1, + '\u{00A8}' => 1, + '\u{110AB}' => 1, + '\u{30AC}' => 1, + '\u{FE71}' => 1, + '\u{30AE}' => 1, + '\u{00AF}' => 1, + '\u{30B0}' => 1, + '\u{30B2}' => 1, + '\u{FEF5}' => 1, + '\u{00B4}' => 1, + '\u{30B6}' => 1, + '\u{00B8}' => 1, + '\u{30BA}' => 1, + '\u{30BC}' => 1, + '\u{30BE}' => 1, + '\u{00C0}' => 1, + '\u{00C1}' => 1, + '\u{00C2}' => 1, + '\u{00C3}' => 1, + '\u{00C4}' => 1, + '\u{00C5}' => 1, + '\u{00C7}' => 1, + '\u{00C8}' => 1, + '\u{00C9}' => 1, + '\u{00CA}' => 1, + '\u{00CB}' => 1, + '\u{00CC}' => 1, + '\u{00CD}' => 1, + '\u{00CE}' => 1, + '\u{00CF}' => 1, + '\u{30D0}' => 1, + '\u{00D1}' => 1, + '\u{00D2}' => 1, + '\u{00D3}' => 1, + '\u{00D4}' => 1, + '\u{00D5}' => 1, + '\u{00D6}' => 1, + '\u{30D7}' => 1, + '\u{00D9}' => 1, + '\u{00DA}' => 1, + '\u{00DB}' => 1, + '\u{00DC}' => 1, + '\u{00DD}' => 1, + '\u{00E0}' => 1, + '\u{00E1}' => 1, + '\u{00E2}' => 1, + '\u{00E3}' => 1, + '\u{00E4}' => 1, + '\u{00E5}' => 1, + '\u{00E7}' => 1, + '\u{00E8}' => 1, + '\u{00E9}' => 1, + '\u{00EA}' => 1, + '\u{00EB}' => 1, + '\u{00EC}' => 1, + '\u{00ED}' => 1, + '\u{00EE}' => 1, + '\u{00EF}' => 1, + '\u{00F1}' => 1, + '\u{00F2}' => 1, + '\u{00F3}' => 1, + '\u{00F4}' => 1, + '\u{00F5}' => 1, + '\u{00F6}' => 1, + '\u{30F7}' => 1, + '\u{30F8}' => 1, + '\u{00F9}' => 1, + '\u{00FA}' => 1, + '\u{00FB}' => 1, + '\u{00FC}' => 1, + '\u{00FD}' => 1, + '\u{30FE}' => 1, + '\u{00FF}' => 1, + '\u{0100}' => 1, + '\u{0101}' => 1, + '\u{0102}' => 1, + '\u{0103}' => 1, + '\u{0104}' => 1, + '\u{0105}' => 1, + '\u{0106}' => 1, + '\u{0107}' => 1, + '\u{0108}' => 1, + '\u{0109}' => 1, + '\u{010A}' => 1, + '\u{010B}' => 1, + '\u{010C}' => 1, + '\u{010D}' => 1, + '\u{010E}' => 1, + '\u{010F}' => 1, + '\u{1E23}' => 1, + '\u{0112}' => 1, + '\u{0113}' => 1, + '\u{0114}' => 1, + '\u{0115}' => 1, + '\u{0116}' => 1, + '\u{0117}' => 1, + '\u{0118}' => 1, + '\u{0119}' => 1, + '\u{011A}' => 1, + '\u{011B}' => 1, + '\u{011C}' => 1, + '\u{011D}' => 1, + '\u{011E}' => 1, + '\u{011F}' => 1, + '\u{0120}' => 1, + '\u{0121}' => 1, + '\u{0122}' => 1, + '\u{0123}' => 1, + '\u{0124}' => 1, + '\u{0125}' => 1, + '\u{0128}' => 1, + '\u{0129}' => 1, + '\u{012A}' => 1, + '\u{012B}' => 1, + '\u{012C}' => 1, + '\u{012D}' => 1, + '\u{012E}' => 1, + '\u{012F}' => 1, + '\u{0130}' => 1, + '\u{0931}' => 1, + '\u{0134}' => 1, + '\u{0135}' => 1, + '\u{0136}' => 1, + '\u{0137}' => 1, + '\u{0139}' => 1, + '\u{013A}' => 1, + '\u{013B}' => 1, + '\u{013C}' => 1, + '\u{013D}' => 1, + '\u{013E}' => 1, + '\u{FE76}' => 1, + '\u{0143}' => 1, + '\u{0144}' => 1, + '\u{0145}' => 1, + '\u{0146}' => 1, + '\u{0147}' => 1, + '\u{0148}' => 1, + '\u{014C}' => 1, + '\u{014D}' => 1, + '\u{014E}' => 1, + '\u{014F}' => 1, + '\u{0150}' => 1, + '\u{0151}' => 1, + '\u{0154}' => 1, + '\u{0155}' => 1, + '\u{0156}' => 1, + '\u{0157}' => 1, + '\u{0158}' => 1, + '\u{0159}' => 1, + '\u{015A}' => 1, + '\u{015B}' => 1, + '\u{015C}' => 1, + '\u{015D}' => 1, + '\u{015E}' => 1, + '\u{015F}' => 1, + '\u{0160}' => 1, + '\u{0161}' => 1, + '\u{0162}' => 1, + '\u{0163}' => 1, + '\u{0164}' => 1, + '\u{0165}' => 1, + '\u{0168}' => 1, + '\u{0169}' => 1, + '\u{016A}' => 1, + '\u{016B}' => 1, + '\u{016C}' => 1, + '\u{016D}' => 1, + '\u{016E}' => 1, + '\u{016F}' => 1, + '\u{0170}' => 1, + '\u{0171}' => 1, + '\u{0172}' => 1, + '\u{0173}' => 1, + '\u{0174}' => 1, + '\u{0175}' => 1, + '\u{0176}' => 1, + '\u{0177}' => 1, + '\u{0178}' => 1, + '\u{0179}' => 1, + '\u{017A}' => 1, + '\u{017B}' => 1, + '\u{017C}' => 1, + '\u{017D}' => 1, + '\u{017E}' => 1, + '\u{FE82}' => 1, + '\u{2226}' => 1, + '\u{FE74}' => 1, + '\u{219A}' => 1, + '\u{219B}' => 1, + '\u{01A0}' => 1, + '\u{01A1}' => 1, + '\u{FEF8}' => 1, + '\u{21AE}' => 1, + '\u{01AF}' => 1, + '\u{01B0}' => 1, + '\u{1D1BB}' => 1, + '\u{1D1BC}' => 1, + '\u{1D1BD}' => 2, + '\u{1D1BE}' => 2, + '\u{1D1BF}' => 2, + '\u{1D1C0}' => 2, + '\u{01C4}' => 1, + '\u{01C5}' => 1, + '\u{01C6}' => 1, + '\u{1EF7}' => 1, + '\u{01CD}' => 1, + '\u{01CE}' => 1, + '\u{01CF}' => 1, + '\u{01D0}' => 1, + '\u{01D1}' => 1, + '\u{01D2}' => 1, + '\u{01D3}' => 1, + '\u{01D4}' => 1, + '\u{01D5}' => 2, + '\u{01D6}' => 2, + '\u{01D7}' => 2, + '\u{01D8}' => 2, + '\u{01D9}' => 2, + '\u{01DA}' => 2, + '\u{01DB}' => 2, + '\u{01DC}' => 2, + '\u{09DD}' => 1, + '\u{01DE}' => 2, + '\u{01DF}' => 2, + '\u{01E0}' => 2, + '\u{01E1}' => 2, + '\u{01E2}' => 1, + '\u{01E3}' => 1, + '\u{01E6}' => 1, + '\u{01E7}' => 1, + '\u{01E8}' => 1, + '\u{01E9}' => 1, + '\u{01EA}' => 1, + '\u{01EB}' => 1, + '\u{01EC}' => 2, + '\u{01ED}' => 2, + '\u{01EE}' => 1, + '\u{01EF}' => 1, + '\u{01F0}' => 1, + '\u{01F4}' => 1, + '\u{01F5}' => 1, + '\u{01F8}' => 1, + '\u{01F9}' => 1, + '\u{01FA}' => 2, + '\u{01FB}' => 2, + '\u{01FC}' => 1, + '\u{01FD}' => 1, + '\u{01FE}' => 1, + '\u{01FF}' => 1, + '\u{0200}' => 1, + '\u{0201}' => 1, + '\u{0202}' => 1, + '\u{0203}' => 1, + '\u{0204}' => 1, + '\u{0205}' => 1, + '\u{0206}' => 1, + '\u{0207}' => 1, + '\u{0208}' => 1, + '\u{0209}' => 1, + '\u{020A}' => 1, + '\u{020B}' => 1, + '\u{020C}' => 1, + '\u{020D}' => 1, + '\u{020E}' => 1, + '\u{020F}' => 1, + '\u{0210}' => 1, + '\u{0211}' => 1, + '\u{0212}' => 1, + '\u{0213}' => 1, + '\u{0214}' => 1, + '\u{0215}' => 1, + '\u{0216}' => 1, + '\u{0217}' => 1, + '\u{0218}' => 1, + '\u{0219}' => 1, + '\u{021A}' => 1, + '\u{021B}' => 1, + '\u{021E}' => 1, + '\u{021F}' => 1, + '\u{2224}' => 1, + '\u{FE8C}' => 1, + '\u{0226}' => 1, + '\u{0227}' => 1, + '\u{0228}' => 1, + '\u{0229}' => 1, + '\u{022A}' => 2, + '\u{022B}' => 2, + '\u{022C}' => 2, + '\u{022D}' => 2, + '\u{022E}' => 1, + '\u{022F}' => 1, + '\u{0230}' => 2, + '\u{0231}' => 2, + '\u{0232}' => 1, + '\u{0233}' => 1, + '\u{FC5E}' => 2, + '\u{0A36}' => 1, + '\u{30D1}' => 1, + '\u{2241}' => 1, + '\u{2244}' => 1, + '\u{FE7A}' => 1, + '\u{30D3}' => 1, + '\u{2247}' => 1, + '\u{2249}' => 1, + '\u{30FA}' => 1, + '\u{FE85}' => 1, + '\u{0A59}' => 1, + '\u{0A5A}' => 1, + '\u{0A5B}' => 1, + '\u{0A5E}' => 1, + '\u{2260}' => 1, + '\u{2262}' => 1, + '\u{FE7B}' => 1, + '\u{30D4}' => 1, + '\u{30B4}' => 1, + '\u{226D}' => 1, + '\u{226E}' => 1, + '\u{226F}' => 1, + '\u{2270}' => 1, + '\u{2271}' => 1, + '\u{2274}' => 1, + '\u{2275}' => 1, + '\u{2278}' => 1, + '\u{2279}' => 1, + '\u{2280}' => 1, + '\u{2281}' => 1, + '\u{2284}' => 1, + '\u{2285}' => 1, + '\u{2288}' => 1, + '\u{2289}' => 1, + '\u{FE72}' => 1, + '\u{FE7D}' => 1, + '\u{FE86}' => 1, + '\u{FB4B}' => 1, + '\u{22AC}' => 1, + '\u{22AD}' => 1, + '\u{22AE}' => 1, + '\u{22AF}' => 1, + '\u{FC5C}' => 1, + '\u{FE7E}' => 1, + '\u{FC5D}' => 1, + '\u{21CD}' => 1, + '\u{21CE}' => 1, + '\u{02D8}' => 1, + '\u{02D9}' => 1, + '\u{02DA}' => 1, + '\u{02DB}' => 1, + '\u{02DC}' => 1, + '\u{02DD}' => 1, + '\u{22E0}' => 1, + '\u{22E1}' => 1, + '\u{22E2}' => 1, + '\u{22E3}' => 1, + '\u{22EA}' => 1, + '\u{22EB}' => 1, + '\u{22EC}' => 1, + '\u{22ED}' => 1, + '\u{FE77}' => 1, + '\u{FE79}' => 1, + '\u{3304}' => 1, + '\u{3307}' => 1, + '\u{FCD9}' => 1, + '\u{3310}' => 1, + '\u{FE81}' => 1, + '\u{FB1D}' => 1, + '\u{331E}' => 1, + '\u{FB1F}' => 1, + '\u{3321}' => 1, + '\u{09DC}' => 1, + '\u{FB2A}' => 1, + '\u{FB2B}' => 1, + '\u{FB2C}' => 2, + '\u{FB2D}' => 2, + '\u{FB2E}' => 1, + '\u{FB2F}' => 1, + '\u{FB30}' => 1, + '\u{FB31}' => 1, + '\u{3332}' => 1, + '\u{FB33}' => 1, + '\u{FB34}' => 1, + '\u{FB35}' => 1, + '\u{FB36}' => 1, + '\u{FB38}' => 1, + '\u{FB39}' => 1, + '\u{FB3A}' => 1, + '\u{09DF}' => 1, + '\u{FB3C}' => 1, + '\u{FB3E}' => 1, + '\u{0340}' => 1, + '\u{0341}' => 1, + '\u{0343}' => 1, + '\u{0344}' => 2, + '\u{FB46}' => 1, + '\u{FB47}' => 1, + '\u{FB48}' => 1, + '\u{FB49}' => 1, + '\u{FB4A}' => 1, + '\u{1F37}' => 2, + '\u{FB4C}' => 1, + '\u{FB4D}' => 1, + '\u{334E}' => 1, + '\u{FE83}' => 1, + '\u{1F39}' => 1, + '\u{0B5C}' => 1, + '\u{0B5D}' => 1, + '\u{333B}' => 1, + '\u{FE84}' => 1, + '\u{037A}' => 1, + '\u{3340}' => 1, + '\u{0384}' => 1, + '\u{0385}' => 2, + '\u{0386}' => 1, + '\u{FB41}' => 1, + '\u{0388}' => 1, + '\u{0389}' => 1, + '\u{038A}' => 1, + '\u{038C}' => 1, + '\u{038E}' => 1, + '\u{038F}' => 1, + '\u{0390}' => 2, + '\u{FB43}' => 1, + '\u{30B8}' => 1, + '\u{FB44}' => 1, + '\u{FB40}' => 1, + '\u{FBA4}' => 1, + '\u{FBA5}' => 1, + '\u{309C}' => 1, + '\u{03AA}' => 1, + '\u{03AB}' => 1, + '\u{03AC}' => 1, + '\u{03AD}' => 1, + '\u{03AE}' => 1, + '\u{03AF}' => 1, + '\u{03B0}' => 2, + '\u{FBB1}' => 1, + '\u{2ADC}' => 1, + '\u{334B}' => 1, + '\u{03CA}' => 1, + '\u{03CB}' => 1, + '\u{03CC}' => 1, + '\u{03CD}' => 1, + '\u{03CE}' => 1, + '\u{03D3}' => 1, + '\u{03D4}' => 1, + '\u{FB4E}' => 1, + '\u{FE88}' => 1, + '\u{0400}' => 1, + '\u{0401}' => 1, + '\u{0403}' => 1, + '\u{0407}' => 1, + '\u{FBB0}' => 1, + '\u{040C}' => 1, + '\u{040D}' => 1, + '\u{040E}' => 1, + '\u{0419}' => 1, + '\u{FE78}' => 1, + '\u{FE8A}' => 1, + '\u{FB3B}' => 1, + '\u{2209}' => 1, + '\u{0439}' => 1, + '\u{FE8B}' => 1, + '\u{0C48}' => 1, + '\u{220C}' => 1, + '\u{0450}' => 1, + '\u{0451}' => 1, + '\u{0453}' => 1, + '\u{FEF6}' => 1, + '\u{0457}' => 1, + '\u{FC5B}' => 1, + '\u{045C}' => 1, + '\u{045D}' => 1, + '\u{045E}' => 1, + '\u{FC5F}' => 2, + '\u{FC60}' => 2, + '\u{FC61}' => 2, + '\u{FC62}' => 2, + '\u{FC63}' => 2, + '\u{FE89}' => 1, + '\u{FE7C}' => 1, + '\u{1F213}' => 1, + '\u{0476}' => 1, + '\u{0477}' => 1, + '\u{30C0}' => 1, + '\u{FCF4}' => 2, + '\u{212B}' => 1, + '\u{30C2}' => 1, + '\u{FC90}' => 1, + '\u{30C5}' => 1, + '\u{30C7}' => 1, + '\u{1F73}' => 1, + '\u{21CF}' => 1, + '\u{1F75}' => 1, + '\u{04C1}' => 1, + '\u{04C2}' => 1, + '\u{1F76}' => 1, + '\u{FFE3}' => 1, + '\u{1F77}' => 1, + '\u{1E22}' => 1, + '\u{04D0}' => 1, + '\u{04D1}' => 1, + '\u{04D2}' => 1, + '\u{04D3}' => 1, + '\u{04D6}' => 1, + '\u{04D7}' => 1, + '\u{1E24}' => 1, + '\u{04DA}' => 1, + '\u{04DB}' => 1, + '\u{04DC}' => 1, + '\u{04DD}' => 1, + '\u{04DE}' => 1, + '\u{04DF}' => 1, + '\u{04E2}' => 1, + '\u{04E3}' => 1, + '\u{04E4}' => 1, + '\u{04E5}' => 1, + '\u{04E6}' => 1, + '\u{04E7}' => 1, + '\u{04EA}' => 1, + '\u{04EB}' => 1, + '\u{04EC}' => 1, + '\u{04ED}' => 1, + '\u{04EE}' => 1, + '\u{04EF}' => 1, + '\u{04F0}' => 1, + '\u{04F1}' => 1, + '\u{04F2}' => 1, + '\u{04F3}' => 1, + '\u{04F4}' => 1, + '\u{04F5}' => 1, + '\u{04F8}' => 1, + '\u{04F9}' => 1, + '\u{30D6}' => 1, + '\u{1F81}' => 2, + '\u{30D9}' => 1, + '\u{30DA}' => 1, + '\u{1FDF}' => 2, + '\u{30DC}' => 1, + '\u{30DD}' => 1, + '\u{0A33}' => 1, + '\u{FD3C}' => 1, + '\u{FD3D}' => 1, + '\u{1F78}' => 1, + '\u{1F94}' => 3, + '\u{FE70}' => 1, + '\u{2204}' => 1, + '\u{30C9}' => 1, + '\u{FCF2}' => 2, + '\u{FCF3}' => 2, + '\u{FF9E}' => 1, + '\u{1ED3}' => 2, + '\u{FE49}' => 1, + '\u{30F4}' => 1, + '\u{FF9F}' => 1, + '\u{FE4A}' => 1, + '\u{FE4B}' => 1, + '\u{FE4C}' => 1, + '\u{30F9}' => 1, + '\u{0DDA}' => 1, + '\u{0DDD}' => 1, + '\u{1F79}' => 1, + '\u{1E00}' => 1, + '\u{1E01}' => 1, + '\u{1E02}' => 1, + '\u{1E03}' => 1, + '\u{1E04}' => 1, + '\u{1E05}' => 1, + '\u{1E06}' => 1, + '\u{1E07}' => 1, + '\u{1E08}' => 2, + '\u{1E09}' => 2, + '\u{1E0A}' => 1, + '\u{1E0B}' => 1, + '\u{1E0C}' => 1, + '\u{1E0D}' => 1, + '\u{1E0E}' => 1, + '\u{1E0F}' => 1, + '\u{1E10}' => 1, + '\u{1E11}' => 1, + '\u{1E12}' => 1, + '\u{1E13}' => 1, + '\u{1E14}' => 2, + '\u{1E15}' => 2, + '\u{1E16}' => 2, + '\u{1E17}' => 2, + '\u{1E18}' => 1, + '\u{1E19}' => 1, + '\u{1E1A}' => 1, + '\u{1E1B}' => 1, + '\u{1E1C}' => 2, + '\u{1E1D}' => 2, + '\u{1E1E}' => 1, + '\u{1E1F}' => 1, + '\u{1E20}' => 1, + '\u{1E21}' => 1, + '\u{0622}' => 1, + '\u{0623}' => 1, + '\u{0624}' => 1, + '\u{0625}' => 1, + '\u{0626}' => 1, + '\u{1E27}' => 1, + '\u{1E28}' => 1, + '\u{1E29}' => 1, + '\u{1E2A}' => 1, + '\u{1E2B}' => 1, + '\u{1E2C}' => 1, + '\u{1E2D}' => 1, + '\u{1E2E}' => 2, + '\u{1E2F}' => 2, + '\u{1E30}' => 1, + '\u{1E31}' => 1, + '\u{1E32}' => 1, + '\u{1E33}' => 1, + '\u{1E34}' => 1, + '\u{1E35}' => 1, + '\u{1E36}' => 1, + '\u{1E37}' => 1, + '\u{1E38}' => 2, + '\u{1E39}' => 2, + '\u{1E3A}' => 1, + '\u{1E3B}' => 1, + '\u{1E3C}' => 1, + '\u{1E3D}' => 1, + '\u{1E3E}' => 1, + '\u{1E3F}' => 1, + '\u{1E40}' => 1, + '\u{1E41}' => 1, + '\u{1E42}' => 1, + '\u{1E43}' => 1, + '\u{1E44}' => 1, + '\u{1E45}' => 1, + '\u{1E46}' => 1, + '\u{1E47}' => 1, + '\u{1E48}' => 1, + '\u{1E49}' => 1, + '\u{1E4A}' => 1, + '\u{1E4B}' => 1, + '\u{1E4C}' => 2, + '\u{1E4D}' => 2, + '\u{1E4E}' => 2, + '\u{1E4F}' => 2, + '\u{1E50}' => 2, + '\u{1E51}' => 2, + '\u{1E52}' => 2, + '\u{1E53}' => 2, + '\u{1E54}' => 1, + '\u{1E55}' => 1, + '\u{1E56}' => 1, + '\u{1E57}' => 1, + '\u{1E58}' => 1, + '\u{1E59}' => 1, + '\u{1E5A}' => 1, + '\u{1E5B}' => 1, + '\u{1E5C}' => 2, + '\u{1E5D}' => 2, + '\u{1E5E}' => 1, + '\u{1E5F}' => 1, + '\u{1E60}' => 1, + '\u{1E61}' => 1, + '\u{1E62}' => 1, + '\u{1E63}' => 1, + '\u{1E64}' => 2, + '\u{1E65}' => 2, + '\u{1E66}' => 2, + '\u{1E67}' => 2, + '\u{1E68}' => 2, + '\u{1E69}' => 2, + '\u{1E6A}' => 1, + '\u{1E6B}' => 1, + '\u{1E6C}' => 1, + '\u{1E6D}' => 1, + '\u{1E6E}' => 1, + '\u{1E6F}' => 1, + '\u{1E70}' => 1, + '\u{1E71}' => 1, + '\u{1E72}' => 1, + '\u{1E73}' => 1, + '\u{1E74}' => 1, + '\u{1E75}' => 1, + '\u{1E76}' => 1, + '\u{1E77}' => 1, + '\u{1E78}' => 2, + '\u{1E79}' => 2, + '\u{1E7A}' => 2, + '\u{1E7B}' => 2, + '\u{1E7C}' => 1, + '\u{1E7D}' => 1, + '\u{1E7E}' => 1, + '\u{1E7F}' => 1, + '\u{1E80}' => 1, + '\u{1E81}' => 1, + '\u{1E82}' => 1, + '\u{1E83}' => 1, + '\u{1E84}' => 1, + '\u{1E85}' => 1, + '\u{1E86}' => 1, + '\u{1E87}' => 1, + '\u{1E88}' => 1, + '\u{1E25}' => 1, + '\u{1E8A}' => 1, + '\u{1E8B}' => 1, + '\u{1E8C}' => 1, + '\u{1E8D}' => 1, + '\u{1E8E}' => 1, + '\u{1E8F}' => 1, + '\u{1E90}' => 1, + '\u{1E91}' => 1, + '\u{1E92}' => 1, + '\u{1E93}' => 1, + '\u{1E94}' => 1, + '\u{1E95}' => 1, + '\u{1E96}' => 1, + '\u{1E97}' => 1, + '\u{1E98}' => 1, + '\u{1E99}' => 1, + '\u{1E9B}' => 1, + '\u{1EA0}' => 1, + '\u{1EA1}' => 1, + '\u{1EA2}' => 1, + '\u{1EA3}' => 1, + '\u{1EA4}' => 2, + '\u{1EA5}' => 2, + '\u{1EA6}' => 2, + '\u{1EA7}' => 2, + '\u{1EA8}' => 2, + '\u{1EA9}' => 2, + '\u{1EAA}' => 2, + '\u{1EAB}' => 2, + '\u{1EAC}' => 2, + '\u{1EAD}' => 2, + '\u{1EAE}' => 2, + '\u{1EAF}' => 2, + '\u{1EB0}' => 2, + '\u{1EB1}' => 2, + '\u{1EB2}' => 2, + '\u{1EB3}' => 2, + '\u{1EB4}' => 2, + '\u{1EB5}' => 2, + '\u{1EB6}' => 2, + '\u{1EB7}' => 2, + '\u{1EB8}' => 1, + '\u{1EB9}' => 1, + '\u{1EBA}' => 1, + '\u{1EBB}' => 1, + '\u{1EBC}' => 1, + '\u{1EBD}' => 1, + '\u{1EBE}' => 2, + '\u{1EBF}' => 2, + '\u{06C0}' => 1, + '\u{1EC1}' => 2, + '\u{06C2}' => 1, + '\u{1EC3}' => 2, + '\u{1EC4}' => 2, + '\u{1EC5}' => 2, + '\u{1EC6}' => 2, + '\u{1EC7}' => 2, + '\u{1EC8}' => 1, + '\u{1EC9}' => 1, + '\u{1ECA}' => 1, + '\u{1ECB}' => 1, + '\u{1ECC}' => 1, + '\u{1ECD}' => 1, + '\u{1ECE}' => 1, + '\u{1ECF}' => 1, + '\u{1ED0}' => 2, + '\u{1ED1}' => 2, + '\u{1ED2}' => 2, + '\u{06D3}' => 1, + '\u{1ED4}' => 2, + '\u{1ED5}' => 2, + '\u{1ED6}' => 2, + '\u{1ED7}' => 2, + '\u{1ED8}' => 2, + '\u{1ED9}' => 2, + '\u{1EDA}' => 2, + '\u{1EDB}' => 2, + '\u{1EDC}' => 2, + '\u{1EDD}' => 2, + '\u{1EDE}' => 2, + '\u{1EDF}' => 2, + '\u{1EE0}' => 2, + '\u{1EE1}' => 2, + '\u{1EE2}' => 2, + '\u{1EE3}' => 2, + '\u{1EE4}' => 1, + '\u{1EE5}' => 1, + '\u{1EE6}' => 1, + '\u{1EE7}' => 1, + '\u{1EE8}' => 2, + '\u{1EE9}' => 2, + '\u{1EEA}' => 2, + '\u{1EEB}' => 2, + '\u{1EEC}' => 2, + '\u{1EED}' => 2, + '\u{1EEE}' => 2, + '\u{1EEF}' => 2, + '\u{1EF0}' => 2, + '\u{1EF1}' => 2, + '\u{1EF2}' => 1, + '\u{1EF3}' => 1, + '\u{1EF4}' => 1, + '\u{1EF5}' => 1, + '\u{1EF6}' => 1, + '\u{0929}' => 1, + '\u{1EF8}' => 1, + '\u{1EF9}' => 1, + '\u{FEFA}' => 1, + '\u{FE7F}' => 1, + '\u{1F00}' => 1, + '\u{1F01}' => 1, + '\u{1F02}' => 2, + '\u{1F03}' => 2, + '\u{1F04}' => 2, + '\u{1F05}' => 2, + '\u{1F06}' => 2, + '\u{1F07}' => 2, + '\u{1F08}' => 1, + '\u{1F09}' => 1, + '\u{1F0A}' => 2, + '\u{1F0B}' => 2, + '\u{1F0C}' => 2, + '\u{1F0D}' => 2, + '\u{1F0E}' => 2, + '\u{1F0F}' => 2, + '\u{1F10}' => 1, + '\u{1F11}' => 1, + '\u{1F12}' => 2, + '\u{1F13}' => 2, + '\u{1F14}' => 2, + '\u{1F15}' => 2, + '\u{1F18}' => 1, + '\u{1F19}' => 1, + '\u{1F1A}' => 2, + '\u{1F1B}' => 2, + '\u{1F1C}' => 2, + '\u{1F1D}' => 2, + '\u{1E26}' => 1, + '\u{1F20}' => 1, + '\u{1F21}' => 1, + '\u{1F22}' => 2, + '\u{1F23}' => 2, + '\u{1F24}' => 2, + '\u{1F25}' => 2, + '\u{1F26}' => 2, + '\u{1F27}' => 2, + '\u{1F28}' => 1, + '\u{1F29}' => 1, + '\u{1F2A}' => 2, + '\u{1F2B}' => 2, + '\u{1F2C}' => 2, + '\u{1F2D}' => 2, + '\u{1F2E}' => 2, + '\u{1F2F}' => 2, + '\u{1F30}' => 1, + '\u{1F31}' => 1, + '\u{1F32}' => 2, + '\u{1F33}' => 2, + '\u{1F34}' => 2, + '\u{1F35}' => 2, + '\u{1F36}' => 2, + '\u{1E89}' => 1, + '\u{1F38}' => 1, + '\u{0934}' => 1, + '\u{1F3A}' => 2, + '\u{1F3B}' => 2, + '\u{1F3C}' => 2, + '\u{1F3D}' => 2, + '\u{1F3E}' => 2, + '\u{1F3F}' => 2, + '\u{1F40}' => 1, + '\u{1F41}' => 1, + '\u{1F42}' => 2, + '\u{1F43}' => 2, + '\u{1F44}' => 2, + '\u{1F45}' => 2, + '\u{1F48}' => 1, + '\u{1F49}' => 1, + '\u{1F4A}' => 2, + '\u{1F4B}' => 2, + '\u{1F4C}' => 2, + '\u{1F4D}' => 2, + '\u{1F50}' => 1, + '\u{1F51}' => 1, + '\u{1F52}' => 2, + '\u{1F53}' => 2, + '\u{1F54}' => 2, + '\u{1F55}' => 2, + '\u{1F56}' => 2, + '\u{1F57}' => 2, + '\u{1F59}' => 1, + '\u{1F5B}' => 2, + '\u{1F5D}' => 2, + '\u{1F5F}' => 2, + '\u{1F60}' => 1, + '\u{1F61}' => 1, + '\u{1F62}' => 2, + '\u{1F63}' => 2, + '\u{1F64}' => 2, + '\u{1F65}' => 2, + '\u{1F66}' => 2, + '\u{1F67}' => 2, + '\u{1F68}' => 1, + '\u{1F69}' => 1, + '\u{1F6A}' => 2, + '\u{1F6B}' => 2, + '\u{1F6C}' => 2, + '\u{1F6D}' => 2, + '\u{1F6E}' => 2, + '\u{1F6F}' => 2, + '\u{1F70}' => 1, + '\u{1F71}' => 1, + '\u{1F72}' => 1, + '\u{0F73}' => 2, + '\u{1F74}' => 1, + '\u{0F75}' => 2, + '\u{0F76}' => 1, + '\u{0F77}' => 2, + '\u{0F78}' => 1, + '\u{0F79}' => 2, + '\u{1F7A}' => 1, + '\u{1F7B}' => 1, + '\u{1F7C}' => 1, + '\u{1F7D}' => 1, + '\u{1F80}' => 2, + '\u{0F81}' => 2, + '\u{1F82}' => 3, + '\u{1F83}' => 3, + '\u{1F84}' => 3, + '\u{1F85}' => 3, + '\u{1F86}' => 3, + '\u{1F87}' => 3, + '\u{1F88}' => 2, + '\u{1F89}' => 2, + '\u{1F8A}' => 3, + '\u{1F8B}' => 3, + '\u{1F8C}' => 3, + '\u{1F8D}' => 3, + '\u{1F8E}' => 3, + '\u{1F8F}' => 3, + '\u{1F90}' => 2, + '\u{1F91}' => 2, + '\u{1F92}' => 3, + '\u{1F93}' => 3, + '\u{1D15E}' => 1, + '\u{1F95}' => 3, + '\u{1F96}' => 3, + '\u{1F97}' => 3, + '\u{1F98}' => 2, + '\u{1F99}' => 2, + '\u{1F9A}' => 3, + '\u{1F9B}' => 3, + '\u{1F9C}' => 3, + '\u{1F9D}' => 3, + '\u{1F9E}' => 3, + '\u{1F9F}' => 3, + '\u{1FA0}' => 2, + '\u{1FA1}' => 2, + '\u{1FA2}' => 3, + '\u{1FA3}' => 3, + '\u{1FA4}' => 3, + '\u{1FA5}' => 3, + '\u{1FA6}' => 3, + '\u{1FA7}' => 3, + '\u{1FA8}' => 2, + '\u{1FA9}' => 2, + '\u{1FAA}' => 3, + '\u{1FAB}' => 3, + '\u{1FAC}' => 3, + '\u{1FAD}' => 3, + '\u{1FAE}' => 3, + '\u{1FAF}' => 3, + '\u{1FB0}' => 1, + '\u{1FB1}' => 1, + '\u{1D15F}' => 1, + '\u{1FB3}' => 1, + '\u{1FB4}' => 2, + '\u{1FB6}' => 1, + '\u{1FB7}' => 2, + '\u{1FB8}' => 1, + '\u{1FB9}' => 1, + '\u{1FBA}' => 1, + '\u{1FBB}' => 1, + '\u{1FBC}' => 1, + '\u{1FBD}' => 1, + '\u{1FBF}' => 1, + '\u{1FC0}' => 1, + '\u{1FC1}' => 2, + '\u{1FC2}' => 2, + '\u{1FC3}' => 1, + '\u{1FC4}' => 2, + '\u{1FC6}' => 1, + '\u{1FC7}' => 2, + '\u{1FC8}' => 1, + '\u{1FC9}' => 1, + '\u{1FCA}' => 1, + '\u{1FCB}' => 1, + '\u{1FCC}' => 1, + '\u{1FCD}' => 2, + '\u{1FCE}' => 2, + '\u{1FCF}' => 2, + '\u{1FD0}' => 1, + '\u{1FD1}' => 1, + '\u{1FD2}' => 2, + '\u{1FD3}' => 2, + '\u{1FD6}' => 1, + '\u{1FD7}' => 2, + '\u{1FD8}' => 1, + '\u{1FD9}' => 1, + '\u{1FDA}' => 1, + '\u{1FDB}' => 1, + '\u{1FDD}' => 2, + '\u{1FDE}' => 2, + '\u{1FB2}' => 2, + '\u{1FE0}' => 1, + '\u{1FE1}' => 1, + '\u{1FE2}' => 2, + '\u{1FE3}' => 2, + '\u{1FE4}' => 1, + '\u{1FE5}' => 1, + '\u{1FE6}' => 1, + '\u{1FE7}' => 2, + '\u{1FE8}' => 1, + '\u{1FE9}' => 1, + '\u{1FEA}' => 1, + '\u{1FEB}' => 1, + '\u{1FEC}' => 1, + '\u{1FED}' => 2, + '\u{1FEE}' => 2, + '\u{1FF2}' => 2, + '\u{1FF3}' => 1, + '\u{1FF4}' => 2, + '\u{1FF6}' => 1, + '\u{1FF7}' => 2, + '\u{1FF8}' => 1, + '\u{1FF9}' => 1, + '\u{1FFA}' => 1, + '\u{1FFB}' => 1, + '\u{1FFC}' => 1, + '\u{1FFD}' => 1, + '\u{1FFE}' => 1, + _ => 0, + } +} + diff --git a/unicode-width/.cargo-checksum.json b/unicode-width/.cargo-checksum.json new file mode 100644 index 000000000..26fd2a5fc --- /dev/null +++ b/unicode-width/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"} \ No newline at end of file diff --git a/unicode-width/COPYRIGHT b/unicode-width/COPYRIGHT new file mode 100644 index 000000000..b286ec16a --- /dev/null +++ b/unicode-width/COPYRIGHT @@ -0,0 +1,7 @@ +Licensed under the Apache License, Version 2.0 +<LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT +license <LICENSE-MIT or http://opensource.org/licenses/MIT>, +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. diff --git a/unicode-width/Cargo.toml b/unicode-width/Cargo.toml new file mode 100644 index 000000000..0b15c461c --- /dev/null +++ b/unicode-width/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "unicode-width" +version = "0.1.5" +authors = ["kwantam <kwantam@gmail.com>"] +exclude = ["target/*", "Cargo.lock"] +description = "Determine displayed width of `char` and `str` types\naccording to Unicode Standard Annex #11 rules.\n" +homepage = "https://github.com/unicode-rs/unicode-width" +documentation = "https://unicode-rs.github.io/unicode-width" +readme = "README.md" +keywords = ["text", "width", "unicode"] +license = "MIT/Apache-2.0" +repository = "https://github.com/unicode-rs/unicode-width" + +[features] +bench = [] +default = [] +no_std = [] diff --git a/unicode-width/LICENSE-APACHE b/unicode-width/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/unicode-width/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/unicode-width/LICENSE-MIT b/unicode-width/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/unicode-width/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/unicode-width/README.md b/unicode-width/README.md new file mode 100644 index 000000000..53a096d77 --- /dev/null +++ b/unicode-width/README.md @@ -0,0 +1,39 @@ +# unicode-width + +Determine displayed width of `char` and `str` types according to +[Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) +rules. + +[![Build Status](https://travis-ci.org/unicode-rs/unicode-width.svg)](https://travis-ci.org/unicode-rs/unicode-width) + +[Documentation](https://unicode-rs.github.io/unicode-width/unicode_width/index.html) + +```rust +extern crate unicode_width; + +use unicode_width::UnicodeWidthStr; + +fn main() { + let teststr = "Hello, world!"; + let width = UnicodeWidthStr::width(teststr); + println!("{}", teststr); + println!("The above string is {} columns wide.", width); + let width = teststr.width_cjk(); + println!("The above string is {} columns wide (CJK).", width); +} +``` + +## features + +unicode-width does not depend on libstd, so it can be used in crates +with the `#![no_std]` attribute. + +## crates.io + +You can use this package in your project by adding the following +to your `Cargo.toml`: + +```toml +[dependencies] +unicode-width = "0.1.5" +``` diff --git a/unicode-width/scripts/unicode.py b/unicode-width/scripts/unicode.py new file mode 100755 index 000000000..203e16afa --- /dev/null +++ b/unicode-width/scripts/unicode.py @@ -0,0 +1,321 @@ +#!/usr/bin/env python +# +# Copyright 2011-2015 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - EastAsianWidth.txt +# - ReadMe.txt +# - UnicodeData.txt +# +# Since this should not require frequent updates, we just store this +# out-of-line and check the unicode.rs file into git. + +import fileinput, re, os, sys, operator + +preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] +''' + +# Mapping taken from Table 12 from: +# http://www.unicode.org/reports/tr44/#General_Category_Values +expanded_categories = { + 'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'], + 'Lm': ['L'], 'Lo': ['L'], + 'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'], + 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'], + 'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'], + 'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'], + 'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'], + 'Zs': ['Z'], 'Zl': ['Z'], 'Zp': ['Z'], + 'Cc': ['C'], 'Cf': ['C'], 'Cs': ['C'], 'Co': ['C'], 'Cn': ['C'], +} + +# these are the surrogate codepoints, which are not valid rust characters +surrogate_codepoints = (0xd800, 0xdfff) + +def fetch(f): + if not os.path.exists(os.path.basename(f)): + os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" + % f) + + if not os.path.exists(os.path.basename(f)): + sys.stderr.write("cannot load %s" % f) + exit(1) + +def is_surrogate(n): + return surrogate_codepoints[0] <= n <= surrogate_codepoints[1] + +def load_unicode_data(f): + fetch(f) + gencats = {} + + udict = {}; + range_start = -1; + for line in fileinput.input(f): + data = line.split(';'); + if len(data) != 15: + continue + cp = int(data[0], 16); + if is_surrogate(cp): + continue + if range_start >= 0: + for i in xrange(range_start, cp): + udict[i] = data; + range_start = -1; + if data[1].endswith(", First>"): + range_start = cp; + continue; + udict[cp] = data; + + for code in udict: + [code_org, name, gencat, combine, bidi, + decomp, deci, digit, num, mirror, + old, iso, upcase, lowcase, titlecase ] = udict[code]; + + # place letter in categories as appropriate + for cat in [gencat, "Assigned"] + expanded_categories.get(gencat, []): + if cat not in gencats: + gencats[cat] = [] + gencats[cat].append(code) + + gencats = group_cats(gencats) + + return gencats + +def group_cats(cats): + cats_out = {} + for cat in cats: + cats_out[cat] = group_cat(cats[cat]) + return cats_out + +def group_cat(cat): + cat_out = [] + letters = sorted(set(cat)) + cur_start = letters.pop(0) + cur_end = cur_start + for letter in letters: + assert letter > cur_end, \ + "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter)) + if letter == cur_end + 1: + cur_end = letter + else: + cat_out.append((cur_start, cur_end)) + cur_start = cur_end = letter + cat_out.append((cur_start, cur_end)) + return cat_out + +def format_table_content(f, content, indent): + line = " "*indent + first = True + for chunk in content.split(","): + if len(line) + len(chunk) < 98: + if first: + line += chunk + else: + line += ", " + chunk + first = False + else: + f.write(line + ",\n") + line = " "*indent + chunk + f.write(line) + +# load all widths of want_widths, except those in except_cats +def load_east_asian_width(want_widths, except_cats): + f = "EastAsianWidth.txt" + fetch(f) + widths = {} + re1 = re.compile("^([0-9A-F]+);(\w+) +# (\w+)") + re2 = re.compile("^([0-9A-F]+)\.\.([0-9A-F]+);(\w+) +# (\w+)") + + for line in fileinput.input(f): + width = None + d_lo = 0 + d_hi = 0 + cat = None + m = re1.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(1) + width = m.group(2) + cat = m.group(3) + else: + m = re2.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(2) + width = m.group(3) + cat = m.group(4) + else: + continue + if cat in except_cats or width not in want_widths: + continue + d_lo = int(d_lo, 16) + d_hi = int(d_hi, 16) + if width not in widths: + widths[width] = [] + widths[width].append((d_lo, d_hi)) + return widths + +def escape_char(c): + return "'\\u{%x}'" % c + +def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True, + pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1])), is_const=True): + pub_string = "const" + if not is_const: + pub_string = "let" + if is_pub: + pub_string = "pub " + pub_string + f.write(" %s %s: %s = &[\n" % (pub_string, name, t_type)) + data = "" + first = True + for dat in t_data: + if not first: + data += "," + first = False + data += pfun(dat) + format_table_content(f, data, 8) + f.write("\n ];\n\n") + +def emit_charwidth_module(f, width_table): + f.write("pub mod charwidth {") + f.write(""" + use core::option::Option::{self, Some, None}; + use core::result::Result::{Ok, Err}; + + #[inline] + fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 { + use core::cmp::Ordering::{Equal, Less, Greater}; + match r.binary_search_by(|&(lo, hi, _, _)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }) { + Ok(idx) => { + let (_, _, r_ncjk, r_cjk) = r[idx]; + if is_cjk { r_cjk } else { r_ncjk } + } + Err(_) => 1 + } + } +""") + + f.write(""" + #[inline] + pub fn width(c: char, is_cjk: bool) -> Option<usize> { + match c as usize { + _c @ 0 => Some(0), // null is zero width + cu if cu < 0x20 => None, // control sequences have no width + cu if cu < 0x7F => Some(1), // ASCII + cu if cu < 0xA0 => None, // more control sequences + _ => Some(bsearch_range_value_table(c, is_cjk, charwidth_table) as usize) + } + } + +""") + + f.write(" // character width table. Based on Markus Kuhn's free wcwidth() implementation,\n") + f.write(" // http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c\n") + emit_table(f, "charwidth_table", width_table, "&'static [(char, char, u8, u8)]", is_pub=False, + pfun=lambda x: "(%s,%s,%s,%s)" % (escape_char(x[0]), escape_char(x[1]), x[2], x[3])) + f.write("}\n\n") + +def remove_from_wtable(wtable, val): + wtable_out = [] + while wtable: + if wtable[0][1] < val: + wtable_out.append(wtable.pop(0)) + elif wtable[0][0] > val: + break + else: + (wt_lo, wt_hi, width, width_cjk) = wtable.pop(0) + if wt_lo == wt_hi == val: + continue + elif wt_lo == val: + wtable_out.append((wt_lo+1, wt_hi, width, width_cjk)) + elif wt_hi == val: + wtable_out.append((wt_lo, wt_hi-1, width, width_cjk)) + else: + wtable_out.append((wt_lo, val-1, width, width_cjk)) + wtable_out.append((val+1, wt_hi, width, width_cjk)) + if wtable: + wtable_out.extend(wtable) + return wtable_out + + + +def optimize_width_table(wtable): + wtable_out = [] + w_this = wtable.pop(0) + while wtable: + if w_this[1] == wtable[0][0] - 1 and w_this[2:3] == wtable[0][2:3]: + w_tmp = wtable.pop(0) + w_this = (w_this[0], w_tmp[1], w_tmp[2], w_tmp[3]) + else: + wtable_out.append(w_this) + w_this = wtable.pop(0) + wtable_out.append(w_this) + return wtable_out + +if __name__ == "__main__": + r = "tables.rs" + if os.path.exists(r): + os.remove(r) + with open(r, "w") as rf: + # write the file's preamble + rf.write(preamble) + + # download and parse all the data + fetch("ReadMe.txt") + with open("ReadMe.txt") as readme: + pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" + unicode_version = re.search(pattern, readme.read()).groups() + rf.write(""" +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-width is based on. +pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); + +""" % unicode_version) + gencats = load_unicode_data("UnicodeData.txt") + + ### character width module + width_table = [] + for zwcat in ["Me", "Mn", "Cf"]: + width_table.extend(map(lambda (lo, hi): (lo, hi, 0, 0), gencats[zwcat])) + width_table.append((4448, 4607, 0, 0)) + + # get widths, except those that are explicitly marked zero-width above + ea_widths = load_east_asian_width(["W", "F", "A"], ["Me", "Mn", "Cf"]) + # these are doublewidth + for dwcat in ["W", "F"]: + width_table.extend(map(lambda (lo, hi): (lo, hi, 2, 2), ea_widths[dwcat])) + width_table.extend(map(lambda (lo, hi): (lo, hi, 1, 2), ea_widths["A"])) + + width_table.sort(key=lambda w: w[0]) + + # soft hyphen is not zero width in preformatted text; it's used to indicate + # a hyphen inserted to facilitate a linebreak. + width_table = remove_from_wtable(width_table, 173) + + # optimize the width table by collapsing adjacent entities when possible + width_table = optimize_width_table(width_table) + emit_charwidth_module(rf, width_table) diff --git a/unicode-width/src/lib.rs b/unicode-width/src/lib.rs new file mode 100644 index 000000000..1ee35c85d --- /dev/null +++ b/unicode-width/src/lib.rs @@ -0,0 +1,131 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Determine displayed width of `char` and `str` types according to +//! [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) +//! rules. +//! +//! ```rust +//! extern crate unicode_width; +//! +//! use unicode_width::UnicodeWidthStr; +//! +//! fn main() { +//! let teststr = "Hello, world!"; +//! let width = UnicodeWidthStr::width(teststr); +//! println!("{}", teststr); +//! println!("The above string is {} columns wide.", width); +//! let width = teststr.width_cjk(); +//! println!("The above string is {} columns wide (CJK).", width); +//! } +//! ``` +//! +//! # features +//! +//! unicode-width supports a `no_std` feature. This eliminates dependence +//! on std, and instead uses equivalent functions from core. +//! +//! # crates.io +//! +//! You can use this package in your project by adding the following +//! to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! unicode-width = "0.1.5" +//! ``` + +#![deny(missing_docs, unsafe_code)] +#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png", + html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")] + +#![cfg_attr(feature = "bench", feature(test))] +#![no_std] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "bench")] +extern crate test; + +use tables::charwidth as cw; +pub use tables::UNICODE_VERSION; + +use core::ops::Add; + +mod tables; + +#[cfg(test)] +mod tests; + +/// Methods for determining displayed width of Unicode characters. +pub trait UnicodeWidthChar { + /// Returns the character's displayed width in columns, or `None` if the + /// character is a control character other than `'\x00'`. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 1 column wide. This is consistent with the recommendations for non-CJK + /// contexts, or when the context cannot be reliably determined. + fn width(self) -> Option<usize>; + + /// Returns the character's displayed width in columns, or `None` if the + /// character is a control character other than `'\x00'`. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 2 columns wide. This is consistent with the recommendations for + /// CJK contexts. + fn width_cjk(self) -> Option<usize>; +} + +impl UnicodeWidthChar for char { + #[inline] + fn width(self) -> Option<usize> { cw::width(self, false) } + + #[inline] + fn width_cjk(self) -> Option<usize> { cw::width(self, true) } +} + +/// Methods for determining displayed width of Unicode strings. +pub trait UnicodeWidthStr { + /// Returns the string's displayed width in columns. + /// + /// Control characters are treated as having zero width. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 1 column wide. This is consistent with the recommendations for + /// non-CJK contexts, or when the context cannot be reliably determined. + fn width<'a>(&'a self) -> usize; + + /// Returns the string's displayed width in columns. + /// + /// Control characters are treated as having zero width. + /// + /// This function treats characters in the Ambiguous category according + /// to [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// as 2 column wide. This is consistent with the recommendations for + /// CJK contexts. + fn width_cjk<'a>(&'a self) -> usize; +} + +impl UnicodeWidthStr for str { + #[inline] + fn width(&self) -> usize { + self.chars().map(|c| cw::width(c, false).unwrap_or(0)).fold(0, Add::add) + } + + #[inline] + fn width_cjk(&self) -> usize { + self.chars().map(|c| cw::width(c, true).unwrap_or(0)).fold(0, Add::add) + } +} diff --git a/unicode-width/src/tables.rs b/unicode-width/src/tables.rs new file mode 100644 index 000000000..3acb93212 --- /dev/null +++ b/unicode-width/src/tables.rs @@ -0,0 +1,273 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] + +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-width is based on. +pub const UNICODE_VERSION: (u64, u64, u64) = (10, 0, 0); + +pub mod charwidth { + use core::option::Option::{self, Some, None}; + use core::result::Result::{Ok, Err}; + + #[inline] + fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 { + use core::cmp::Ordering::{Equal, Less, Greater}; + match r.binary_search_by(|&(lo, hi, _, _)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }) { + Ok(idx) => { + let (_, _, r_ncjk, r_cjk) = r[idx]; + if is_cjk { r_cjk } else { r_ncjk } + } + Err(_) => 1 + } + } + + #[inline] + pub fn width(c: char, is_cjk: bool) -> Option<usize> { + match c as usize { + _c @ 0 => Some(0), // null is zero width + cu if cu < 0x20 => None, // control sequences have no width + cu if cu < 0x7F => Some(1), // ASCII + cu if cu < 0xA0 => None, // more control sequences + _ => Some(bsearch_range_value_table(c, is_cjk, charwidth_table) as usize) + } + } + + // character width table. Based on Markus Kuhn's free wcwidth() implementation, + // http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c + const charwidth_table: &'static [(char, char, u8, u8)] = &[ + ('\u{a1}', '\u{a1}', 1, 2), ('\u{a4}', '\u{a4}', 1, 2), ('\u{a7}', '\u{a8}', 1, 2), + ('\u{aa}', '\u{aa}', 1, 2), ('\u{ae}', '\u{ae}', 1, 2), ('\u{b0}', '\u{b4}', 1, 2), + ('\u{b6}', '\u{ba}', 1, 2), ('\u{bc}', '\u{bf}', 1, 2), ('\u{c6}', '\u{c6}', 1, 2), + ('\u{d0}', '\u{d0}', 1, 2), ('\u{d7}', '\u{d8}', 1, 2), ('\u{de}', '\u{e1}', 1, 2), + ('\u{e6}', '\u{e6}', 1, 2), ('\u{e8}', '\u{ea}', 1, 2), ('\u{ec}', '\u{ed}', 1, 2), + ('\u{f0}', '\u{f0}', 1, 2), ('\u{f2}', '\u{f3}', 1, 2), ('\u{f7}', '\u{fa}', 1, 2), + ('\u{fc}', '\u{fc}', 1, 2), ('\u{fe}', '\u{fe}', 1, 2), ('\u{101}', '\u{101}', 1, 2), + ('\u{111}', '\u{111}', 1, 2), ('\u{113}', '\u{113}', 1, 2), ('\u{11b}', '\u{11b}', 1, 2), + ('\u{126}', '\u{127}', 1, 2), ('\u{12b}', '\u{12b}', 1, 2), ('\u{131}', '\u{133}', 1, 2), + ('\u{138}', '\u{138}', 1, 2), ('\u{13f}', '\u{142}', 1, 2), ('\u{144}', '\u{144}', 1, 2), + ('\u{148}', '\u{14b}', 1, 2), ('\u{14d}', '\u{14d}', 1, 2), ('\u{152}', '\u{153}', 1, 2), + ('\u{166}', '\u{167}', 1, 2), ('\u{16b}', '\u{16b}', 1, 2), ('\u{1ce}', '\u{1ce}', 1, 2), + ('\u{1d0}', '\u{1d0}', 1, 2), ('\u{1d2}', '\u{1d2}', 1, 2), ('\u{1d4}', '\u{1d4}', 1, 2), + ('\u{1d6}', '\u{1d6}', 1, 2), ('\u{1d8}', '\u{1d8}', 1, 2), ('\u{1da}', '\u{1da}', 1, 2), + ('\u{1dc}', '\u{1dc}', 1, 2), ('\u{251}', '\u{251}', 1, 2), ('\u{261}', '\u{261}', 1, 2), + ('\u{2c4}', '\u{2c4}', 1, 2), ('\u{2c7}', '\u{2c7}', 1, 2), ('\u{2c9}', '\u{2cb}', 1, 2), + ('\u{2cd}', '\u{2cd}', 1, 2), ('\u{2d0}', '\u{2d0}', 1, 2), ('\u{2d8}', '\u{2db}', 1, 2), + ('\u{2dd}', '\u{2dd}', 1, 2), ('\u{2df}', '\u{2df}', 1, 2), ('\u{300}', '\u{36f}', 0, 0), + ('\u{391}', '\u{3a1}', 1, 2), ('\u{3a3}', '\u{3a9}', 1, 2), ('\u{3b1}', '\u{3c1}', 1, 2), + ('\u{3c3}', '\u{3c9}', 1, 2), ('\u{401}', '\u{401}', 1, 2), ('\u{410}', '\u{44f}', 1, 2), + ('\u{451}', '\u{451}', 1, 2), ('\u{483}', '\u{489}', 0, 0), ('\u{591}', '\u{5bd}', 0, 0), + ('\u{5bf}', '\u{5bf}', 0, 0), ('\u{5c1}', '\u{5c2}', 0, 0), ('\u{5c4}', '\u{5c5}', 0, 0), + ('\u{5c7}', '\u{5c7}', 0, 0), ('\u{600}', '\u{605}', 0, 0), ('\u{610}', '\u{61a}', 0, 0), + ('\u{61c}', '\u{61c}', 0, 0), ('\u{64b}', '\u{65f}', 0, 0), ('\u{670}', '\u{670}', 0, 0), + ('\u{6d6}', '\u{6dd}', 0, 0), ('\u{6df}', '\u{6e4}', 0, 0), ('\u{6e7}', '\u{6e8}', 0, 0), + ('\u{6ea}', '\u{6ed}', 0, 0), ('\u{70f}', '\u{70f}', 0, 0), ('\u{711}', '\u{711}', 0, 0), + ('\u{730}', '\u{74a}', 0, 0), ('\u{7a6}', '\u{7b0}', 0, 0), ('\u{7eb}', '\u{7f3}', 0, 0), + ('\u{816}', '\u{819}', 0, 0), ('\u{81b}', '\u{823}', 0, 0), ('\u{825}', '\u{827}', 0, 0), + ('\u{829}', '\u{82d}', 0, 0), ('\u{859}', '\u{85b}', 0, 0), ('\u{8d4}', '\u{902}', 0, 0), + ('\u{93a}', '\u{93a}', 0, 0), ('\u{93c}', '\u{93c}', 0, 0), ('\u{941}', '\u{948}', 0, 0), + ('\u{94d}', '\u{94d}', 0, 0), ('\u{951}', '\u{957}', 0, 0), ('\u{962}', '\u{963}', 0, 0), + ('\u{981}', '\u{981}', 0, 0), ('\u{9bc}', '\u{9bc}', 0, 0), ('\u{9c1}', '\u{9c4}', 0, 0), + ('\u{9cd}', '\u{9cd}', 0, 0), ('\u{9e2}', '\u{9e3}', 0, 0), ('\u{a01}', '\u{a02}', 0, 0), + ('\u{a3c}', '\u{a3c}', 0, 0), ('\u{a41}', '\u{a42}', 0, 0), ('\u{a47}', '\u{a48}', 0, 0), + ('\u{a4b}', '\u{a4d}', 0, 0), ('\u{a51}', '\u{a51}', 0, 0), ('\u{a70}', '\u{a71}', 0, 0), + ('\u{a75}', '\u{a75}', 0, 0), ('\u{a81}', '\u{a82}', 0, 0), ('\u{abc}', '\u{abc}', 0, 0), + ('\u{ac1}', '\u{ac5}', 0, 0), ('\u{ac7}', '\u{ac8}', 0, 0), ('\u{acd}', '\u{acd}', 0, 0), + ('\u{ae2}', '\u{ae3}', 0, 0), ('\u{afa}', '\u{aff}', 0, 0), ('\u{b01}', '\u{b01}', 0, 0), + ('\u{b3c}', '\u{b3c}', 0, 0), ('\u{b3f}', '\u{b3f}', 0, 0), ('\u{b41}', '\u{b44}', 0, 0), + ('\u{b4d}', '\u{b4d}', 0, 0), ('\u{b56}', '\u{b56}', 0, 0), ('\u{b62}', '\u{b63}', 0, 0), + ('\u{b82}', '\u{b82}', 0, 0), ('\u{bc0}', '\u{bc0}', 0, 0), ('\u{bcd}', '\u{bcd}', 0, 0), + ('\u{c00}', '\u{c00}', 0, 0), ('\u{c3e}', '\u{c40}', 0, 0), ('\u{c46}', '\u{c48}', 0, 0), + ('\u{c4a}', '\u{c4d}', 0, 0), ('\u{c55}', '\u{c56}', 0, 0), ('\u{c62}', '\u{c63}', 0, 0), + ('\u{c81}', '\u{c81}', 0, 0), ('\u{cbc}', '\u{cbc}', 0, 0), ('\u{cbf}', '\u{cbf}', 0, 0), + ('\u{cc6}', '\u{cc6}', 0, 0), ('\u{ccc}', '\u{ccd}', 0, 0), ('\u{ce2}', '\u{ce3}', 0, 0), + ('\u{d00}', '\u{d01}', 0, 0), ('\u{d3b}', '\u{d3c}', 0, 0), ('\u{d41}', '\u{d44}', 0, 0), + ('\u{d4d}', '\u{d4d}', 0, 0), ('\u{d62}', '\u{d63}', 0, 0), ('\u{dca}', '\u{dca}', 0, 0), + ('\u{dd2}', '\u{dd4}', 0, 0), ('\u{dd6}', '\u{dd6}', 0, 0), ('\u{e31}', '\u{e31}', 0, 0), + ('\u{e34}', '\u{e3a}', 0, 0), ('\u{e47}', '\u{e4e}', 0, 0), ('\u{eb1}', '\u{eb1}', 0, 0), + ('\u{eb4}', '\u{eb9}', 0, 0), ('\u{ebb}', '\u{ebc}', 0, 0), ('\u{ec8}', '\u{ecd}', 0, 0), + ('\u{f18}', '\u{f19}', 0, 0), ('\u{f35}', '\u{f35}', 0, 0), ('\u{f37}', '\u{f37}', 0, 0), + ('\u{f39}', '\u{f39}', 0, 0), ('\u{f71}', '\u{f7e}', 0, 0), ('\u{f80}', '\u{f84}', 0, 0), + ('\u{f86}', '\u{f87}', 0, 0), ('\u{f8d}', '\u{f97}', 0, 0), ('\u{f99}', '\u{fbc}', 0, 0), + ('\u{fc6}', '\u{fc6}', 0, 0), ('\u{102d}', '\u{1030}', 0, 0), ('\u{1032}', '\u{1037}', 0, + 0), ('\u{1039}', '\u{103a}', 0, 0), ('\u{103d}', '\u{103e}', 0, 0), ('\u{1058}', '\u{1059}', + 0, 0), ('\u{105e}', '\u{1060}', 0, 0), ('\u{1071}', '\u{1074}', 0, 0), ('\u{1082}', + '\u{1082}', 0, 0), ('\u{1085}', '\u{1086}', 0, 0), ('\u{108d}', '\u{108d}', 0, 0), + ('\u{109d}', '\u{109d}', 0, 0), ('\u{1100}', '\u{115f}', 2, 2), ('\u{1160}', '\u{11ff}', 0, + 0), ('\u{135d}', '\u{135f}', 0, 0), ('\u{1712}', '\u{1714}', 0, 0), ('\u{1732}', '\u{1734}', + 0, 0), ('\u{1752}', '\u{1753}', 0, 0), ('\u{1772}', '\u{1773}', 0, 0), ('\u{17b4}', + '\u{17b5}', 0, 0), ('\u{17b7}', '\u{17bd}', 0, 0), ('\u{17c6}', '\u{17c6}', 0, 0), + ('\u{17c9}', '\u{17d3}', 0, 0), ('\u{17dd}', '\u{17dd}', 0, 0), ('\u{180b}', '\u{180e}', 0, + 0), ('\u{1885}', '\u{1886}', 0, 0), ('\u{18a9}', '\u{18a9}', 0, 0), ('\u{1920}', '\u{1922}', + 0, 0), ('\u{1927}', '\u{1928}', 0, 0), ('\u{1932}', '\u{1932}', 0, 0), ('\u{1939}', + '\u{193b}', 0, 0), ('\u{1a17}', '\u{1a18}', 0, 0), ('\u{1a1b}', '\u{1a1b}', 0, 0), + ('\u{1a56}', '\u{1a56}', 0, 0), ('\u{1a58}', '\u{1a5e}', 0, 0), ('\u{1a60}', '\u{1a60}', 0, + 0), ('\u{1a62}', '\u{1a62}', 0, 0), ('\u{1a65}', '\u{1a6c}', 0, 0), ('\u{1a73}', '\u{1a7c}', + 0, 0), ('\u{1a7f}', '\u{1a7f}', 0, 0), ('\u{1ab0}', '\u{1abe}', 0, 0), ('\u{1b00}', + '\u{1b03}', 0, 0), ('\u{1b34}', '\u{1b34}', 0, 0), ('\u{1b36}', '\u{1b3a}', 0, 0), + ('\u{1b3c}', '\u{1b3c}', 0, 0), ('\u{1b42}', '\u{1b42}', 0, 0), ('\u{1b6b}', '\u{1b73}', 0, + 0), ('\u{1b80}', '\u{1b81}', 0, 0), ('\u{1ba2}', '\u{1ba5}', 0, 0), ('\u{1ba8}', '\u{1ba9}', + 0, 0), ('\u{1bab}', '\u{1bad}', 0, 0), ('\u{1be6}', '\u{1be6}', 0, 0), ('\u{1be8}', + '\u{1be9}', 0, 0), ('\u{1bed}', '\u{1bed}', 0, 0), ('\u{1bef}', '\u{1bf1}', 0, 0), + ('\u{1c2c}', '\u{1c33}', 0, 0), ('\u{1c36}', '\u{1c37}', 0, 0), ('\u{1cd0}', '\u{1cd2}', 0, + 0), ('\u{1cd4}', '\u{1ce0}', 0, 0), ('\u{1ce2}', '\u{1ce8}', 0, 0), ('\u{1ced}', '\u{1ced}', + 0, 0), ('\u{1cf4}', '\u{1cf4}', 0, 0), ('\u{1cf8}', '\u{1cf9}', 0, 0), ('\u{1dc0}', + '\u{1df9}', 0, 0), ('\u{1dfb}', '\u{1dff}', 0, 0), ('\u{200b}', '\u{200f}', 0, 0), + ('\u{2010}', '\u{2010}', 1, 2), ('\u{2013}', '\u{2016}', 1, 2), ('\u{2018}', '\u{2019}', 1, + 2), ('\u{201c}', '\u{201d}', 1, 2), ('\u{2020}', '\u{2022}', 1, 2), ('\u{2024}', '\u{2027}', + 1, 2), ('\u{202a}', '\u{202e}', 0, 0), ('\u{2030}', '\u{2030}', 1, 2), ('\u{2032}', + '\u{2033}', 1, 2), ('\u{2035}', '\u{2035}', 1, 2), ('\u{203b}', '\u{203b}', 1, 2), + ('\u{203e}', '\u{203e}', 1, 2), ('\u{2060}', '\u{2064}', 0, 0), ('\u{2066}', '\u{206f}', 0, + 0), ('\u{2074}', '\u{2074}', 1, 2), ('\u{207f}', '\u{207f}', 1, 2), ('\u{2081}', '\u{2084}', + 1, 2), ('\u{20ac}', '\u{20ac}', 1, 2), ('\u{20d0}', '\u{20f0}', 0, 0), ('\u{2103}', + '\u{2103}', 1, 2), ('\u{2105}', '\u{2105}', 1, 2), ('\u{2109}', '\u{2109}', 1, 2), + ('\u{2113}', '\u{2113}', 1, 2), ('\u{2116}', '\u{2116}', 1, 2), ('\u{2121}', '\u{2122}', 1, + 2), ('\u{2126}', '\u{2126}', 1, 2), ('\u{212b}', '\u{212b}', 1, 2), ('\u{2153}', '\u{2154}', + 1, 2), ('\u{215b}', '\u{215e}', 1, 2), ('\u{2160}', '\u{216b}', 1, 2), ('\u{2170}', + '\u{2179}', 1, 2), ('\u{2189}', '\u{2189}', 1, 2), ('\u{2190}', '\u{2199}', 1, 2), + ('\u{21b8}', '\u{21b9}', 1, 2), ('\u{21d2}', '\u{21d2}', 1, 2), ('\u{21d4}', '\u{21d4}', 1, + 2), ('\u{21e7}', '\u{21e7}', 1, 2), ('\u{2200}', '\u{2200}', 1, 2), ('\u{2202}', '\u{2203}', + 1, 2), ('\u{2207}', '\u{2208}', 1, 2), ('\u{220b}', '\u{220b}', 1, 2), ('\u{220f}', + '\u{220f}', 1, 2), ('\u{2211}', '\u{2211}', 1, 2), ('\u{2215}', '\u{2215}', 1, 2), + ('\u{221a}', '\u{221a}', 1, 2), ('\u{221d}', '\u{2220}', 1, 2), ('\u{2223}', '\u{2223}', 1, + 2), ('\u{2225}', '\u{2225}', 1, 2), ('\u{2227}', '\u{222c}', 1, 2), ('\u{222e}', '\u{222e}', + 1, 2), ('\u{2234}', '\u{2237}', 1, 2), ('\u{223c}', '\u{223d}', 1, 2), ('\u{2248}', + '\u{2248}', 1, 2), ('\u{224c}', '\u{224c}', 1, 2), ('\u{2252}', '\u{2252}', 1, 2), + ('\u{2260}', '\u{2261}', 1, 2), ('\u{2264}', '\u{2267}', 1, 2), ('\u{226a}', '\u{226b}', 1, + 2), ('\u{226e}', '\u{226f}', 1, 2), ('\u{2282}', '\u{2283}', 1, 2), ('\u{2286}', '\u{2287}', + 1, 2), ('\u{2295}', '\u{2295}', 1, 2), ('\u{2299}', '\u{2299}', 1, 2), ('\u{22a5}', + '\u{22a5}', 1, 2), ('\u{22bf}', '\u{22bf}', 1, 2), ('\u{2312}', '\u{2312}', 1, 2), + ('\u{231a}', '\u{231b}', 2, 2), ('\u{2329}', '\u{232a}', 2, 2), ('\u{23e9}', '\u{23ec}', 2, + 2), ('\u{23f0}', '\u{23f0}', 2, 2), ('\u{23f3}', '\u{23f3}', 2, 2), ('\u{2460}', '\u{24e9}', + 1, 2), ('\u{24eb}', '\u{254b}', 1, 2), ('\u{2550}', '\u{2573}', 1, 2), ('\u{2580}', + '\u{258f}', 1, 2), ('\u{2592}', '\u{2595}', 1, 2), ('\u{25a0}', '\u{25a1}', 1, 2), + ('\u{25a3}', '\u{25a9}', 1, 2), ('\u{25b2}', '\u{25b3}', 1, 2), ('\u{25b6}', '\u{25b7}', 1, + 2), ('\u{25bc}', '\u{25bd}', 1, 2), ('\u{25c0}', '\u{25c1}', 1, 2), ('\u{25c6}', '\u{25c8}', + 1, 2), ('\u{25cb}', '\u{25cb}', 1, 2), ('\u{25ce}', '\u{25d1}', 1, 2), ('\u{25e2}', + '\u{25e5}', 1, 2), ('\u{25ef}', '\u{25ef}', 1, 2), ('\u{25fd}', '\u{25fe}', 2, 2), + ('\u{2605}', '\u{2606}', 1, 2), ('\u{2609}', '\u{2609}', 1, 2), ('\u{260e}', '\u{260f}', 1, + 2), ('\u{2614}', '\u{2615}', 2, 2), ('\u{261c}', '\u{261c}', 1, 2), ('\u{261e}', '\u{261e}', + 1, 2), ('\u{2640}', '\u{2640}', 1, 2), ('\u{2642}', '\u{2642}', 1, 2), ('\u{2648}', + '\u{2653}', 2, 2), ('\u{2660}', '\u{2661}', 1, 2), ('\u{2663}', '\u{2665}', 1, 2), + ('\u{2667}', '\u{266a}', 1, 2), ('\u{266c}', '\u{266d}', 1, 2), ('\u{266f}', '\u{266f}', 1, + 2), ('\u{267f}', '\u{267f}', 2, 2), ('\u{2693}', '\u{2693}', 2, 2), ('\u{269e}', '\u{269f}', + 1, 2), ('\u{26a1}', '\u{26a1}', 2, 2), ('\u{26aa}', '\u{26ab}', 2, 2), ('\u{26bd}', + '\u{26be}', 2, 2), ('\u{26bf}', '\u{26bf}', 1, 2), ('\u{26c4}', '\u{26c5}', 2, 2), + ('\u{26c6}', '\u{26cd}', 1, 2), ('\u{26ce}', '\u{26ce}', 2, 2), ('\u{26cf}', '\u{26d3}', 1, + 2), ('\u{26d4}', '\u{26d4}', 2, 2), ('\u{26d5}', '\u{26e1}', 1, 2), ('\u{26e3}', '\u{26e3}', + 1, 2), ('\u{26e8}', '\u{26e9}', 1, 2), ('\u{26ea}', '\u{26ea}', 2, 2), ('\u{26eb}', + '\u{26f1}', 1, 2), ('\u{26f2}', '\u{26f3}', 2, 2), ('\u{26f4}', '\u{26f4}', 1, 2), + ('\u{26f5}', '\u{26f5}', 2, 2), ('\u{26f6}', '\u{26f9}', 1, 2), ('\u{26fa}', '\u{26fa}', 2, + 2), ('\u{26fb}', '\u{26fc}', 1, 2), ('\u{26fd}', '\u{26fd}', 2, 2), ('\u{26fe}', '\u{26ff}', + 1, 2), ('\u{2705}', '\u{2705}', 2, 2), ('\u{270a}', '\u{270b}', 2, 2), ('\u{2728}', + '\u{2728}', 2, 2), ('\u{273d}', '\u{273d}', 1, 2), ('\u{274c}', '\u{274c}', 2, 2), + ('\u{274e}', '\u{274e}', 2, 2), ('\u{2753}', '\u{2755}', 2, 2), ('\u{2757}', '\u{2757}', 2, + 2), ('\u{2776}', '\u{277f}', 1, 2), ('\u{2795}', '\u{2797}', 2, 2), ('\u{27b0}', '\u{27b0}', + 2, 2), ('\u{27bf}', '\u{27bf}', 2, 2), ('\u{2b1b}', '\u{2b1c}', 2, 2), ('\u{2b50}', + '\u{2b50}', 2, 2), ('\u{2b55}', '\u{2b55}', 2, 2), ('\u{2b56}', '\u{2b59}', 1, 2), + ('\u{2cef}', '\u{2cf1}', 0, 0), ('\u{2d7f}', '\u{2d7f}', 0, 0), ('\u{2de0}', '\u{2dff}', 0, + 0), ('\u{2e80}', '\u{2e99}', 2, 2), ('\u{2e9b}', '\u{2ef3}', 2, 2), ('\u{2f00}', '\u{2fd5}', + 2, 2), ('\u{2ff0}', '\u{2ffb}', 2, 2), ('\u{3000}', '\u{3029}', 2, 2), ('\u{302a}', + '\u{302d}', 0, 0), ('\u{302e}', '\u{303e}', 2, 2), ('\u{3041}', '\u{3096}', 2, 2), + ('\u{3099}', '\u{309a}', 0, 0), ('\u{309b}', '\u{30ff}', 2, 2), ('\u{3105}', '\u{312e}', 2, + 2), ('\u{3131}', '\u{318e}', 2, 2), ('\u{3190}', '\u{31ba}', 2, 2), ('\u{31c0}', '\u{31e3}', + 2, 2), ('\u{31f0}', '\u{321e}', 2, 2), ('\u{3220}', '\u{3247}', 2, 2), ('\u{3248}', + '\u{324f}', 1, 2), ('\u{3250}', '\u{32fe}', 2, 2), ('\u{3300}', '\u{4dbf}', 2, 2), + ('\u{4e00}', '\u{a48c}', 2, 2), ('\u{a490}', '\u{a4c6}', 2, 2), ('\u{a66f}', '\u{a672}', 0, + 0), ('\u{a674}', '\u{a67d}', 0, 0), ('\u{a69e}', '\u{a69f}', 0, 0), ('\u{a6f0}', '\u{a6f1}', + 0, 0), ('\u{a802}', '\u{a802}', 0, 0), ('\u{a806}', '\u{a806}', 0, 0), ('\u{a80b}', + '\u{a80b}', 0, 0), ('\u{a825}', '\u{a826}', 0, 0), ('\u{a8c4}', '\u{a8c5}', 0, 0), + ('\u{a8e0}', '\u{a8f1}', 0, 0), ('\u{a926}', '\u{a92d}', 0, 0), ('\u{a947}', '\u{a951}', 0, + 0), ('\u{a960}', '\u{a97c}', 2, 2), ('\u{a980}', '\u{a982}', 0, 0), ('\u{a9b3}', '\u{a9b3}', + 0, 0), ('\u{a9b6}', '\u{a9b9}', 0, 0), ('\u{a9bc}', '\u{a9bc}', 0, 0), ('\u{a9e5}', + '\u{a9e5}', 0, 0), ('\u{aa29}', '\u{aa2e}', 0, 0), ('\u{aa31}', '\u{aa32}', 0, 0), + ('\u{aa35}', '\u{aa36}', 0, 0), ('\u{aa43}', '\u{aa43}', 0, 0), ('\u{aa4c}', '\u{aa4c}', 0, + 0), ('\u{aa7c}', '\u{aa7c}', 0, 0), ('\u{aab0}', '\u{aab0}', 0, 0), ('\u{aab2}', '\u{aab4}', + 0, 0), ('\u{aab7}', '\u{aab8}', 0, 0), ('\u{aabe}', '\u{aabf}', 0, 0), ('\u{aac1}', + '\u{aac1}', 0, 0), ('\u{aaec}', '\u{aaed}', 0, 0), ('\u{aaf6}', '\u{aaf6}', 0, 0), + ('\u{abe5}', '\u{abe5}', 0, 0), ('\u{abe8}', '\u{abe8}', 0, 0), ('\u{abed}', '\u{abed}', 0, + 0), ('\u{ac00}', '\u{d7a3}', 2, 2), ('\u{e000}', '\u{f8ff}', 1, 2), ('\u{f900}', '\u{faff}', + 2, 2), ('\u{fb1e}', '\u{fb1e}', 0, 0), ('\u{fe00}', '\u{fe0f}', 0, 0), ('\u{fe10}', + '\u{fe19}', 2, 2), ('\u{fe20}', '\u{fe2f}', 0, 0), ('\u{fe30}', '\u{fe52}', 2, 2), + ('\u{fe54}', '\u{fe66}', 2, 2), ('\u{fe68}', '\u{fe6b}', 2, 2), ('\u{feff}', '\u{feff}', 0, + 0), ('\u{ff01}', '\u{ff60}', 2, 2), ('\u{ffe0}', '\u{ffe6}', 2, 2), ('\u{fff9}', '\u{fffb}', + 0, 0), ('\u{fffd}', '\u{fffd}', 1, 2), ('\u{101fd}', '\u{101fd}', 0, 0), ('\u{102e0}', + '\u{102e0}', 0, 0), ('\u{10376}', '\u{1037a}', 0, 0), ('\u{10a01}', '\u{10a03}', 0, 0), + ('\u{10a05}', '\u{10a06}', 0, 0), ('\u{10a0c}', '\u{10a0f}', 0, 0), ('\u{10a38}', + '\u{10a3a}', 0, 0), ('\u{10a3f}', '\u{10a3f}', 0, 0), ('\u{10ae5}', '\u{10ae6}', 0, 0), + ('\u{11001}', '\u{11001}', 0, 0), ('\u{11038}', '\u{11046}', 0, 0), ('\u{1107f}', + '\u{11081}', 0, 0), ('\u{110b3}', '\u{110b6}', 0, 0), ('\u{110b9}', '\u{110ba}', 0, 0), + ('\u{110bd}', '\u{110bd}', 0, 0), ('\u{11100}', '\u{11102}', 0, 0), ('\u{11127}', + '\u{1112b}', 0, 0), ('\u{1112d}', '\u{11134}', 0, 0), ('\u{11173}', '\u{11173}', 0, 0), + ('\u{11180}', '\u{11181}', 0, 0), ('\u{111b6}', '\u{111be}', 0, 0), ('\u{111ca}', + '\u{111cc}', 0, 0), ('\u{1122f}', '\u{11231}', 0, 0), ('\u{11234}', '\u{11234}', 0, 0), + ('\u{11236}', '\u{11237}', 0, 0), ('\u{1123e}', '\u{1123e}', 0, 0), ('\u{112df}', + '\u{112df}', 0, 0), ('\u{112e3}', '\u{112ea}', 0, 0), ('\u{11300}', '\u{11301}', 0, 0), + ('\u{1133c}', '\u{1133c}', 0, 0), ('\u{11340}', '\u{11340}', 0, 0), ('\u{11366}', + '\u{1136c}', 0, 0), ('\u{11370}', '\u{11374}', 0, 0), ('\u{11438}', '\u{1143f}', 0, 0), + ('\u{11442}', '\u{11444}', 0, 0), ('\u{11446}', '\u{11446}', 0, 0), ('\u{114b3}', + '\u{114b8}', 0, 0), ('\u{114ba}', '\u{114ba}', 0, 0), ('\u{114bf}', '\u{114c0}', 0, 0), + ('\u{114c2}', '\u{114c3}', 0, 0), ('\u{115b2}', '\u{115b5}', 0, 0), ('\u{115bc}', + '\u{115bd}', 0, 0), ('\u{115bf}', '\u{115c0}', 0, 0), ('\u{115dc}', '\u{115dd}', 0, 0), + ('\u{11633}', '\u{1163a}', 0, 0), ('\u{1163d}', '\u{1163d}', 0, 0), ('\u{1163f}', + '\u{11640}', 0, 0), ('\u{116ab}', '\u{116ab}', 0, 0), ('\u{116ad}', '\u{116ad}', 0, 0), + ('\u{116b0}', '\u{116b5}', 0, 0), ('\u{116b7}', '\u{116b7}', 0, 0), ('\u{1171d}', + '\u{1171f}', 0, 0), ('\u{11722}', '\u{11725}', 0, 0), ('\u{11727}', '\u{1172b}', 0, 0), + ('\u{11a01}', '\u{11a06}', 0, 0), ('\u{11a09}', '\u{11a0a}', 0, 0), ('\u{11a33}', + '\u{11a38}', 0, 0), ('\u{11a3b}', '\u{11a3e}', 0, 0), ('\u{11a47}', '\u{11a47}', 0, 0), + ('\u{11a51}', '\u{11a56}', 0, 0), ('\u{11a59}', '\u{11a5b}', 0, 0), ('\u{11a8a}', + '\u{11a96}', 0, 0), ('\u{11a98}', '\u{11a99}', 0, 0), ('\u{11c30}', '\u{11c36}', 0, 0), + ('\u{11c38}', '\u{11c3d}', 0, 0), ('\u{11c3f}', '\u{11c3f}', 0, 0), ('\u{11c92}', + '\u{11ca7}', 0, 0), ('\u{11caa}', '\u{11cb0}', 0, 0), ('\u{11cb2}', '\u{11cb3}', 0, 0), + ('\u{11cb5}', '\u{11cb6}', 0, 0), ('\u{11d31}', '\u{11d36}', 0, 0), ('\u{11d3a}', + '\u{11d3a}', 0, 0), ('\u{11d3c}', '\u{11d3d}', 0, 0), ('\u{11d3f}', '\u{11d45}', 0, 0), + ('\u{11d47}', '\u{11d47}', 0, 0), ('\u{16af0}', '\u{16af4}', 0, 0), ('\u{16b30}', + '\u{16b36}', 0, 0), ('\u{16f8f}', '\u{16f92}', 0, 0), ('\u{16fe0}', '\u{16fe1}', 2, 2), + ('\u{17000}', '\u{187ec}', 2, 2), ('\u{18800}', '\u{18af2}', 2, 2), ('\u{1b000}', + '\u{1b11e}', 2, 2), ('\u{1b170}', '\u{1b2fb}', 2, 2), ('\u{1bc9d}', '\u{1bc9e}', 0, 0), + ('\u{1bca0}', '\u{1bca3}', 0, 0), ('\u{1d167}', '\u{1d169}', 0, 0), ('\u{1d173}', + '\u{1d182}', 0, 0), ('\u{1d185}', '\u{1d18b}', 0, 0), ('\u{1d1aa}', '\u{1d1ad}', 0, 0), + ('\u{1d242}', '\u{1d244}', 0, 0), ('\u{1da00}', '\u{1da36}', 0, 0), ('\u{1da3b}', + '\u{1da6c}', 0, 0), ('\u{1da75}', '\u{1da75}', 0, 0), ('\u{1da84}', '\u{1da84}', 0, 0), + ('\u{1da9b}', '\u{1da9f}', 0, 0), ('\u{1daa1}', '\u{1daaf}', 0, 0), ('\u{1e000}', + '\u{1e006}', 0, 0), ('\u{1e008}', '\u{1e018}', 0, 0), ('\u{1e01b}', '\u{1e021}', 0, 0), + ('\u{1e023}', '\u{1e024}', 0, 0), ('\u{1e026}', '\u{1e02a}', 0, 0), ('\u{1e8d0}', + '\u{1e8d6}', 0, 0), ('\u{1e944}', '\u{1e94a}', 0, 0), ('\u{1f004}', '\u{1f004}', 2, 2), + ('\u{1f0cf}', '\u{1f0cf}', 2, 2), ('\u{1f100}', '\u{1f10a}', 1, 2), ('\u{1f110}', + '\u{1f12d}', 1, 2), ('\u{1f130}', '\u{1f169}', 1, 2), ('\u{1f170}', '\u{1f18d}', 1, 2), + ('\u{1f18e}', '\u{1f18e}', 2, 2), ('\u{1f18f}', '\u{1f190}', 1, 2), ('\u{1f191}', + '\u{1f19a}', 2, 2), ('\u{1f19b}', '\u{1f1ac}', 1, 2), ('\u{1f200}', '\u{1f202}', 2, 2), + ('\u{1f210}', '\u{1f23b}', 2, 2), ('\u{1f240}', '\u{1f248}', 2, 2), ('\u{1f250}', + '\u{1f251}', 2, 2), ('\u{1f260}', '\u{1f265}', 2, 2), ('\u{1f300}', '\u{1f320}', 2, 2), + ('\u{1f32d}', '\u{1f335}', 2, 2), ('\u{1f337}', '\u{1f37c}', 2, 2), ('\u{1f37e}', + '\u{1f393}', 2, 2), ('\u{1f3a0}', '\u{1f3ca}', 2, 2), ('\u{1f3cf}', '\u{1f3d3}', 2, 2), + ('\u{1f3e0}', '\u{1f3f0}', 2, 2), ('\u{1f3f4}', '\u{1f3f4}', 2, 2), ('\u{1f3f8}', + '\u{1f43e}', 2, 2), ('\u{1f440}', '\u{1f440}', 2, 2), ('\u{1f442}', '\u{1f4fc}', 2, 2), + ('\u{1f4ff}', '\u{1f53d}', 2, 2), ('\u{1f54b}', '\u{1f54e}', 2, 2), ('\u{1f550}', + '\u{1f567}', 2, 2), ('\u{1f57a}', '\u{1f57a}', 2, 2), ('\u{1f595}', '\u{1f596}', 2, 2), + ('\u{1f5a4}', '\u{1f5a4}', 2, 2), ('\u{1f5fb}', '\u{1f64f}', 2, 2), ('\u{1f680}', + '\u{1f6c5}', 2, 2), ('\u{1f6cc}', '\u{1f6cc}', 2, 2), ('\u{1f6d0}', '\u{1f6d2}', 2, 2), + ('\u{1f6eb}', '\u{1f6ec}', 2, 2), ('\u{1f6f4}', '\u{1f6f8}', 2, 2), ('\u{1f910}', + '\u{1f93e}', 2, 2), ('\u{1f940}', '\u{1f94c}', 2, 2), ('\u{1f950}', '\u{1f96b}', 2, 2), + ('\u{1f980}', '\u{1f997}', 2, 2), ('\u{1f9c0}', '\u{1f9c0}', 2, 2), ('\u{1f9d0}', + '\u{1f9e6}', 2, 2), ('\u{20000}', '\u{2fffd}', 2, 2), ('\u{30000}', '\u{3fffd}', 2, 2), + ('\u{e0001}', '\u{e0001}', 0, 0), ('\u{e0020}', '\u{e007f}', 0, 0), ('\u{e0100}', + '\u{e01ef}', 0, 0), ('\u{f0000}', '\u{ffffd}', 1, 2), ('\u{100000}', '\u{10fffd}', 1, 2) + ]; + +} + diff --git a/unicode-width/src/tests.rs b/unicode-width/src/tests.rs new file mode 100644 index 000000000..2ba1e23d7 --- /dev/null +++ b/unicode-width/src/tests.rs @@ -0,0 +1,156 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(feature = "bench")] +use std::iter; +#[cfg(feature = "bench")] +use test::{self, Bencher}; +#[cfg(feature = "bench")] +use super::UnicodeWidthChar; + +use std::prelude::v1::*; + +#[cfg(feature = "bench")] +#[bench] +fn cargo(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.iter(|| { + for c in string.chars() { + test::black_box(UnicodeWidthChar::width(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +#[allow(deprecated)] +fn stdlib(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.iter(|| { + for c in string.chars() { + test::black_box(c.width()); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn simple_if(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.iter(|| { + for c in string.chars() { + test::black_box(simple_width_if(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn simple_match(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.iter(|| { + for c in string.chars() { + test::black_box(simple_width_match(c)); + } + }); +} + +#[cfg(feature = "bench")] +#[inline] +fn simple_width_if(c: char) -> Option<usize> { + let cu = c as u32; + if cu < 127 { + if cu > 31 { + Some(1) + } else if cu == 0 { + Some(0) + } else { + None + } + } else { + UnicodeWidthChar::width(c) + } +} + +#[cfg(feature = "bench")] +#[inline] +fn simple_width_match(c: char) -> Option<usize> { + match c as u32 { + cu if cu == 0 => Some(0), + cu if cu < 0x20 => None, + cu if cu < 0x7f => Some(1), + _ => UnicodeWidthChar::width(c) + } +} + +#[test] +fn test_str() { + use super::UnicodeWidthStr; + + assert_eq!(UnicodeWidthStr::width("hello"), 10); + assert_eq!("hello".width_cjk(), 10); + assert_eq!(UnicodeWidthStr::width("\0\0\0\x01\x01"), 0); + assert_eq!("\0\0\0\x01\x01".width_cjk(), 0); + assert_eq!(UnicodeWidthStr::width(""), 0); + assert_eq!("".width_cjk(), 0); + assert_eq!(UnicodeWidthStr::width("\u{2081}\u{2082}\u{2083}\u{2084}"), 4); + assert_eq!("\u{2081}\u{2082}\u{2083}\u{2084}".width_cjk(), 8); +} + +#[test] +fn test_char() { + use super::UnicodeWidthChar; + #[cfg(feature = "no_std")] + use core::option::Option::{Some, None}; + + assert_eq!(UnicodeWidthChar::width('h'), Some(2)); + assert_eq!('h'.width_cjk(), Some(2)); + assert_eq!(UnicodeWidthChar::width('\x00'), Some(0)); + assert_eq!('\x00'.width_cjk(), Some(0)); + assert_eq!(UnicodeWidthChar::width('\x01'), None); + assert_eq!('\x01'.width_cjk(), None); + assert_eq!(UnicodeWidthChar::width('\u{2081}'), Some(1)); + assert_eq!('\u{2081}'.width_cjk(), Some(2)); +} + +#[test] +fn test_char2() { + use super::UnicodeWidthChar; + #[cfg(feature = "no_std")] + use core::option::Option::{Some, None}; + + assert_eq!(UnicodeWidthChar::width('\x00'),Some(0)); + assert_eq!('\x00'.width_cjk(),Some(0)); + + assert_eq!(UnicodeWidthChar::width('\x0A'),None); + assert_eq!('\x0A'.width_cjk(),None); + + assert_eq!(UnicodeWidthChar::width('w'),Some(1)); + assert_eq!('w'.width_cjk(),Some(1)); + + assert_eq!(UnicodeWidthChar::width('h'),Some(2)); + assert_eq!('h'.width_cjk(),Some(2)); + + assert_eq!(UnicodeWidthChar::width('\u{AD}'),Some(1)); + assert_eq!('\u{AD}'.width_cjk(),Some(1)); + + assert_eq!(UnicodeWidthChar::width('\u{1160}'),Some(0)); + assert_eq!('\u{1160}'.width_cjk(),Some(0)); + + assert_eq!(UnicodeWidthChar::width('\u{a1}'),Some(1)); + assert_eq!('\u{a1}'.width_cjk(),Some(2)); + + assert_eq!(UnicodeWidthChar::width('\u{300}'),Some(0)); + assert_eq!('\u{300}'.width_cjk(),Some(0)); +} diff --git a/unicode-xid/.cargo-checksum.json b/unicode-xid/.cargo-checksum.json new file mode 100644 index 000000000..62f0b3e05 --- /dev/null +++ b/unicode-xid/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"} \ No newline at end of file diff --git a/unicode-xid/COPYRIGHT b/unicode-xid/COPYRIGHT new file mode 100644 index 000000000..b286ec16a --- /dev/null +++ b/unicode-xid/COPYRIGHT @@ -0,0 +1,7 @@ +Licensed under the Apache License, Version 2.0 +<LICENSE-APACHE or +http://www.apache.org/licenses/LICENSE-2.0> or the MIT +license <LICENSE-MIT or http://opensource.org/licenses/MIT>, +at your option. All files in the project carrying such +notice may not be copied, modified, or distributed except +according to those terms. diff --git a/unicode-xid/Cargo.toml b/unicode-xid/Cargo.toml new file mode 100644 index 000000000..b9b69b293 --- /dev/null +++ b/unicode-xid/Cargo.toml @@ -0,0 +1,26 @@ +[package] + +name = "unicode-xid" +version = "0.1.0" +authors = ["erick.tryzelaar <erick.tryzelaar@gmail.com>", + "kwantam <kwantam@gmail.com>", + ] + +homepage = "https://github.com/unicode-rs/unicode-xid" +repository = "https://github.com/unicode-rs/unicode-xid" +documentation = "https://unicode-rs.github.io/unicode-xid" +license = "MIT/Apache-2.0" +keywords = ["text", "unicode", "xid"] +readme = "README.md" +description = """ +Determine whether characters have the XID_Start +or XID_Continue properties according to +Unicode Standard Annex #31. +""" + +exclude = [ "target/*", "Cargo.lock" ] + +[features] +default = [] +no_std = [] +bench = [] diff --git a/unicode-xid/LICENSE-APACHE b/unicode-xid/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/unicode-xid/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/unicode-xid/LICENSE-MIT b/unicode-xid/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/unicode-xid/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/unicode-xid/README.md b/unicode-xid/README.md new file mode 100644 index 000000000..3a2be472d --- /dev/null +++ b/unicode-xid/README.md @@ -0,0 +1,34 @@ +# unicode-xid + +Determine if a `char` is a valid identifier for a parser and/or lexer according to +[Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) rules. + +[![Build Status](https://travis-ci.org/unicode-rs/unicode-xid.svg)](https://travis-ci.org/unicode-rs/unicode-xid) + +[Documentation](https://unicode-rs.github.io/unicode-xid/unicode_xid/index.html) + +```rust +extern crate unicode_xid; + +use unicode_xid::UnicodeXID; + +fn main() { + let ch = 'a'; + println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch)); +} +``` + +# features + +unicode-xid supports a `no_std` feature. This eliminates dependence +on std, and instead uses equivalent functions from core. + +# crates.io + +You can use this package in your project by adding the following +to your `Cargo.toml`: + +```toml +[dependencies] +unicode-xid = "0.0.4" +``` diff --git a/unicode-xid/scripts/unicode.py b/unicode-xid/scripts/unicode.py new file mode 100755 index 000000000..a30d2f2a7 --- /dev/null +++ b/unicode-xid/scripts/unicode.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python +# +# Copyright 2011-2015 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - DerivedCoreProperties.txt +# - ReadMe.txt +# +# Since this should not require frequent updates, we just store this +# out-of-line and check the unicode.rs file into git. + +import fileinput, re, os, sys + +preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] +''' + +def fetch(f): + if not os.path.exists(os.path.basename(f)): + os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" + % f) + + if not os.path.exists(os.path.basename(f)): + sys.stderr.write("cannot load %s" % f) + exit(1) + +def group_cat(cat): + cat_out = [] + letters = sorted(set(cat)) + cur_start = letters.pop(0) + cur_end = cur_start + for letter in letters: + assert letter > cur_end, \ + "cur_end: %s, letter: %s" % (hex(cur_end), hex(letter)) + if letter == cur_end + 1: + cur_end = letter + else: + cat_out.append((cur_start, cur_end)) + cur_start = cur_end = letter + cat_out.append((cur_start, cur_end)) + return cat_out + +def ungroup_cat(cat): + cat_out = [] + for (lo, hi) in cat: + while lo <= hi: + cat_out.append(lo) + lo += 1 + return cat_out + +def format_table_content(f, content, indent): + line = " "*indent + first = True + for chunk in content.split(","): + if len(line) + len(chunk) < 98: + if first: + line += chunk + else: + line += ", " + chunk + first = False + else: + f.write(line + ",\n") + line = " "*indent + chunk + f.write(line) + +def load_properties(f, interestingprops): + fetch(f) + props = {} + re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)") + re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)") + + for line in fileinput.input(os.path.basename(f)): + prop = None + d_lo = 0 + d_hi = 0 + m = re1.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(1) + prop = m.group(2) + else: + m = re2.match(line) + if m: + d_lo = m.group(1) + d_hi = m.group(2) + prop = m.group(3) + else: + continue + if interestingprops and prop not in interestingprops: + continue + d_lo = int(d_lo, 16) + d_hi = int(d_hi, 16) + if prop not in props: + props[prop] = [] + props[prop].append((d_lo, d_hi)) + + # optimize if possible + for prop in props: + props[prop] = group_cat(ungroup_cat(props[prop])) + + return props + +def escape_char(c): + return "'\\u{%x}'" % c + +def emit_bsearch_range_table(f): + f.write(""" +fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { + use core::cmp::Ordering::{Equal, Less, Greater}; + + r.binary_search_by(|&(lo,hi)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }).is_ok() +}\n +""") + +def emit_table(f, name, t_data, t_type = "&'static [(char, char)]", is_pub=True, + pfun=lambda x: "(%s,%s)" % (escape_char(x[0]), escape_char(x[1])), is_const=True): + pub_string = "const" + if not is_const: + pub_string = "let" + if is_pub: + pub_string = "pub " + pub_string + f.write(" %s %s: %s = &[\n" % (pub_string, name, t_type)) + data = "" + first = True + for dat in t_data: + if not first: + data += "," + first = False + data += pfun(dat) + format_table_content(f, data, 8) + f.write("\n ];\n\n") + +def emit_property_module(f, mod, tbl, emit): + f.write("pub mod %s {\n" % mod) + for cat in sorted(emit): + emit_table(f, "%s_table" % cat, tbl[cat]) + f.write(" pub fn %s(c: char) -> bool {\n" % cat) + f.write(" super::bsearch_range_table(c, %s_table)\n" % cat) + f.write(" }\n\n") + f.write("}\n\n") + +if __name__ == "__main__": + r = "tables.rs" + if os.path.exists(r): + os.remove(r) + with open(r, "w") as rf: + # write the file's preamble + rf.write(preamble) + + # download and parse all the data + fetch("ReadMe.txt") + with open("ReadMe.txt") as readme: + pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" + unicode_version = re.search(pattern, readme.read()).groups() + rf.write(""" +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-xid is based on. +pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); +""" % unicode_version) + emit_bsearch_range_table(rf) + + want_derived = ["XID_Start", "XID_Continue"] + derived = load_properties("DerivedCoreProperties.txt", want_derived) + emit_property_module(rf, "derived_property", derived, want_derived) diff --git a/unicode-xid/src/lib.rs b/unicode-xid/src/lib.rs new file mode 100644 index 000000000..09faf9726 --- /dev/null +++ b/unicode-xid/src/lib.rs @@ -0,0 +1,87 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Determine if a `char` is a valid identifier for a parser and/or lexer according to +//! [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) rules. +//! +//! ```rust +//! extern crate unicode_xid; +//! +//! use unicode_xid::UnicodeXID; +//! +//! fn main() { +//! let ch = 'a'; +//! println!("Is {} a valid start of an identifier? {}", ch, UnicodeXID::is_xid_start(ch)); +//! } +//! ``` +//! +//! # features +//! +//! unicode-xid supports a `no_std` feature. This eliminates dependence +//! on std, and instead uses equivalent functions from core. +//! +//! # crates.io +//! +//! You can use this package in your project by adding the following +//! to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! unicode-xid = "0.0.4" +//! ``` + +#![deny(missing_docs, unsafe_code)] +#![doc(html_logo_url = "https://unicode-rs.github.io/unicode-rs_sm.png", + html_favicon_url = "https://unicode-rs.github.io/unicode-rs_sm.png")] + +#![no_std] +#![cfg_attr(feature = "bench", feature(test, unicode))] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "bench")] +extern crate test; + +use tables::derived_property; +pub use tables::UNICODE_VERSION; + +mod tables; + +#[cfg(test)] +mod tests; + +/// Methods for determining if a character is a valid identifier character. +pub trait UnicodeXID { + /// Returns whether the specified character satisfies the 'XID_Start' + /// Unicode property. + /// + /// 'XID_Start' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to ID_Start but modified for closure under NFKx. + fn is_xid_start(self) -> bool; + + /// Returns whether the specified `char` satisfies the 'XID_Continue' + /// Unicode property. + /// + /// 'XID_Continue' is a Unicode Derived Property specified in + /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), + /// mostly similar to 'ID_Continue' but modified for closure under NFKx. + fn is_xid_continue(self) -> bool; +} + +impl UnicodeXID for char { + #[inline] + fn is_xid_start(self) -> bool { derived_property::XID_Start(self) } + + #[inline] + fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) } +} diff --git a/unicode-xid/src/tables.rs b/unicode-xid/src/tables.rs new file mode 100644 index 000000000..3fe0d3d11 --- /dev/null +++ b/unicode-xid/src/tables.rs @@ -0,0 +1,426 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "scripts/unicode.py", do not edit directly + +#![allow(missing_docs, non_upper_case_globals, non_snake_case)] + +/// The version of [Unicode](http://www.unicode.org/) +/// that this version of unicode-xid is based on. +pub const UNICODE_VERSION: (u64, u64, u64) = (9, 0, 0); + +fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { + use core::cmp::Ordering::{Equal, Less, Greater}; + + r.binary_search_by(|&(lo,hi)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }).is_ok() +} + +pub mod derived_property { + pub const XID_Continue_table: &'static [(char, char)] = &[ + ('\u{30}', '\u{39}'), ('\u{41}', '\u{5a}'), ('\u{5f}', '\u{5f}'), ('\u{61}', '\u{7a}'), + ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{b7}', '\u{b7}'), ('\u{ba}', '\u{ba}'), + ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), ('\u{2c6}', '\u{2d1}'), + ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', '\u{2ee}'), ('\u{300}', + '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'), + ('\u{386}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', + '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{483}', '\u{487}'), ('\u{48a}', '\u{52f}'), + ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{561}', '\u{587}'), ('\u{591}', + '\u{5bd}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), + ('\u{5c7}', '\u{5c7}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{610}', + '\u{61a}'), ('\u{620}', '\u{669}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'), + ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}', + '\u{74a}'), ('\u{74d}', '\u{7b1}'), ('\u{7c0}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), + ('\u{800}', '\u{82d}'), ('\u{840}', '\u{85b}'), ('\u{8a0}', '\u{8b4}'), ('\u{8b6}', + '\u{8bd}'), ('\u{8d4}', '\u{8e1}'), ('\u{8e3}', '\u{963}'), ('\u{966}', '\u{96f}'), + ('\u{971}', '\u{983}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', + '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), + ('\u{9bc}', '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), ('\u{9cb}', '\u{9ce}'), ('\u{9d7}', + '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e3}'), ('\u{9e6}', '\u{9f1}'), + ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), ('\u{a13}', + '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', '\u{a36}'), + ('\u{a38}', '\u{a39}'), ('\u{a3c}', '\u{a3c}'), ('\u{a3e}', '\u{a42}'), ('\u{a47}', + '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a59}', '\u{a5c}'), + ('\u{a5e}', '\u{a5e}'), ('\u{a66}', '\u{a75}'), ('\u{a81}', '\u{a83}'), ('\u{a85}', + '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), + ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abc}', '\u{ac5}'), ('\u{ac7}', + '\u{ac9}'), ('\u{acb}', '\u{acd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae3}'), + ('\u{ae6}', '\u{aef}'), ('\u{af9}', '\u{af9}'), ('\u{b01}', '\u{b03}'), ('\u{b05}', + '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), + ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3c}', '\u{b44}'), ('\u{b47}', + '\u{b48}'), ('\u{b4b}', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b5c}', '\u{b5d}'), + ('\u{b5f}', '\u{b63}'), ('\u{b66}', '\u{b6f}'), ('\u{b71}', '\u{b71}'), ('\u{b82}', + '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), + ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', + '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bbe}', '\u{bc2}'), + ('\u{bc6}', '\u{bc8}'), ('\u{bca}', '\u{bcd}'), ('\u{bd0}', '\u{bd0}'), ('\u{bd7}', + '\u{bd7}'), ('\u{be6}', '\u{bef}'), ('\u{c00}', '\u{c03}'), ('\u{c05}', '\u{c0c}'), + ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', + '\u{c44}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), + ('\u{c58}', '\u{c5a}'), ('\u{c60}', '\u{c63}'), ('\u{c66}', '\u{c6f}'), ('\u{c80}', + '\u{c83}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), + ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbc}', '\u{cc4}'), ('\u{cc6}', + '\u{cc8}'), ('\u{cca}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', '\u{cde}'), + ('\u{ce0}', '\u{ce3}'), ('\u{ce6}', '\u{cef}'), ('\u{cf1}', '\u{cf2}'), ('\u{d01}', + '\u{d03}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), + ('\u{d3d}', '\u{d44}'), ('\u{d46}', '\u{d48}'), ('\u{d4a}', '\u{d4e}'), ('\u{d54}', + '\u{d57}'), ('\u{d5f}', '\u{d63}'), ('\u{d66}', '\u{d6f}'), ('\u{d7a}', '\u{d7f}'), + ('\u{d82}', '\u{d83}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', + '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{dca}', '\u{dca}'), + ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('\u{dd8}', '\u{ddf}'), ('\u{de6}', + '\u{def}'), ('\u{df2}', '\u{df3}'), ('\u{e01}', '\u{e3a}'), ('\u{e40}', '\u{e4e}'), + ('\u{e50}', '\u{e59}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', + '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), + ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', + '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', '\u{eb9}'), ('\u{ebb}', '\u{ebd}'), + ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{ec8}', '\u{ecd}'), ('\u{ed0}', + '\u{ed9}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f18}', '\u{f19}'), + ('\u{f20}', '\u{f29}'), ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', + '\u{f39}'), ('\u{f3e}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f71}', '\u{f84}'), + ('\u{f86}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), ('\u{1000}', + '\u{1049}'), ('\u{1050}', '\u{109d}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), + ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', + '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), + ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', + '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), + ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', + '\u{135a}'), ('\u{135d}', '\u{135f}'), ('\u{1369}', '\u{1371}'), ('\u{1380}', '\u{138f}'), + ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', + '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f8}'), + ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1714}'), ('\u{1720}', '\u{1734}'), ('\u{1740}', + '\u{1753}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1772}', '\u{1773}'), + ('\u{1780}', '\u{17d3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dd}'), ('\u{17e0}', + '\u{17e9}'), ('\u{180b}', '\u{180d}'), ('\u{1810}', '\u{1819}'), ('\u{1820}', '\u{1877}'), + ('\u{1880}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1920}', + '\u{192b}'), ('\u{1930}', '\u{193b}'), ('\u{1946}', '\u{196d}'), ('\u{1970}', '\u{1974}'), + ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{19d0}', '\u{19da}'), ('\u{1a00}', + '\u{1a1b}'), ('\u{1a20}', '\u{1a5e}'), ('\u{1a60}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a89}'), + ('\u{1a90}', '\u{1a99}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', + '\u{1b4b}'), ('\u{1b50}', '\u{1b59}'), ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1bf3}'), + ('\u{1c00}', '\u{1c37}'), ('\u{1c40}', '\u{1c49}'), ('\u{1c4d}', '\u{1c7d}'), ('\u{1c80}', + '\u{1c88}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cf6}'), ('\u{1cf8}', '\u{1cf9}'), + ('\u{1d00}', '\u{1df5}'), ('\u{1dfb}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', + '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), + ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', + '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), + ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', + '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{203f}', '\u{2040}'), + ('\u{2054}', '\u{2054}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', + '\u{209c}'), ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', '\u{20e1}'), ('\u{20e5}', '\u{20f0}'), + ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', + '\u{2115}'), ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), + ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', + '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{2c00}', '\u{2c2e}'), + ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cf3}'), ('\u{2d00}', + '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), + ('\u{2d6f}', '\u{2d6f}'), ('\u{2d7f}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', + '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), + ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{2de0}', + '\u{2dff}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{302f}'), ('\u{3031}', '\u{3035}'), + ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{3099}', '\u{309a}'), ('\u{309d}', + '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), + ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', + '\u{4db5}'), ('\u{4e00}', '\u{9fd5}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), + ('\u{a500}', '\u{a60c}'), ('\u{a610}', '\u{a62b}'), ('\u{a640}', '\u{a66f}'), ('\u{a674}', + '\u{a67d}'), ('\u{a67f}', '\u{a6f1}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'), + ('\u{a78b}', '\u{a7ae}'), ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f7}', '\u{a827}'), ('\u{a840}', + '\u{a873}'), ('\u{a880}', '\u{a8c5}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a8e0}', '\u{a8f7}'), + ('\u{a8fb}', '\u{a8fb}'), ('\u{a8fd}', '\u{a8fd}'), ('\u{a900}', '\u{a92d}'), ('\u{a930}', + '\u{a953}'), ('\u{a960}', '\u{a97c}'), ('\u{a980}', '\u{a9c0}'), ('\u{a9cf}', '\u{a9d9}'), + ('\u{a9e0}', '\u{a9fe}'), ('\u{aa00}', '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), ('\u{aa50}', + '\u{aa59}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), + ('\u{aae0}', '\u{aaef}'), ('\u{aaf2}', '\u{aaf6}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', + '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), + ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', '\u{abea}'), ('\u{abec}', + '\u{abed}'), ('\u{abf0}', '\u{abf9}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), + ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', + '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), + ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', + '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), + ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), ('\u{fe00}', + '\u{fe0f}'), ('\u{fe20}', '\u{fe2f}'), ('\u{fe33}', '\u{fe34}'), ('\u{fe4d}', '\u{fe4f}'), + ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', '\u{fe73}'), ('\u{fe77}', '\u{fe77}'), ('\u{fe79}', + '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), ('\u{fe7d}', '\u{fe7d}'), ('\u{fe7f}', '\u{fefc}'), + ('\u{ff10}', '\u{ff19}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff3f}', '\u{ff3f}'), ('\u{ff41}', + '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), + ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), + ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), + ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', '\u{100fa}'), + ('\u{10140}', '\u{10174}'), ('\u{101fd}', '\u{101fd}'), ('\u{10280}', '\u{1029c}'), + ('\u{102a0}', '\u{102d0}'), ('\u{102e0}', '\u{102e0}'), ('\u{10300}', '\u{1031f}'), + ('\u{10330}', '\u{1034a}'), ('\u{10350}', '\u{1037a}'), ('\u{10380}', '\u{1039d}'), + ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), + ('\u{10400}', '\u{1049d}'), ('\u{104a0}', '\u{104a9}'), ('\u{104b0}', '\u{104d3}'), + ('\u{104d8}', '\u{104fb}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', '\u{10563}'), + ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', '\u{10767}'), + ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', '\u{10835}'), + ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', '\u{10855}'), + ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{108e0}', '\u{108f2}'), + ('\u{108f4}', '\u{108f5}'), ('\u{10900}', '\u{10915}'), ('\u{10920}', '\u{10939}'), + ('\u{10980}', '\u{109b7}'), ('\u{109be}', '\u{109bf}'), ('\u{10a00}', '\u{10a03}'), + ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), + ('\u{10a19}', '\u{10a33}'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), + ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), + ('\u{10ac9}', '\u{10ae6}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), + ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), + ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), ('\u{11000}', '\u{11046}'), + ('\u{11066}', '\u{1106f}'), ('\u{1107f}', '\u{110ba}'), ('\u{110d0}', '\u{110e8}'), + ('\u{110f0}', '\u{110f9}'), ('\u{11100}', '\u{11134}'), ('\u{11136}', '\u{1113f}'), + ('\u{11150}', '\u{11173}'), ('\u{11176}', '\u{11176}'), ('\u{11180}', '\u{111c4}'), + ('\u{111ca}', '\u{111cc}'), ('\u{111d0}', '\u{111da}'), ('\u{111dc}', '\u{111dc}'), + ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{11237}'), ('\u{1123e}', '\u{1123e}'), + ('\u{11280}', '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), + ('\u{1128f}', '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112ea}'), + ('\u{112f0}', '\u{112f9}'), ('\u{11300}', '\u{11303}'), ('\u{11305}', '\u{1130c}'), + ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), + ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133c}', '\u{11344}'), + ('\u{11347}', '\u{11348}'), ('\u{1134b}', '\u{1134d}'), ('\u{11350}', '\u{11350}'), + ('\u{11357}', '\u{11357}'), ('\u{1135d}', '\u{11363}'), ('\u{11366}', '\u{1136c}'), + ('\u{11370}', '\u{11374}'), ('\u{11400}', '\u{1144a}'), ('\u{11450}', '\u{11459}'), + ('\u{11480}', '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), ('\u{114d0}', '\u{114d9}'), + ('\u{11580}', '\u{115b5}'), ('\u{115b8}', '\u{115c0}'), ('\u{115d8}', '\u{115dd}'), + ('\u{11600}', '\u{11640}'), ('\u{11644}', '\u{11644}'), ('\u{11650}', '\u{11659}'), + ('\u{11680}', '\u{116b7}'), ('\u{116c0}', '\u{116c9}'), ('\u{11700}', '\u{11719}'), + ('\u{1171d}', '\u{1172b}'), ('\u{11730}', '\u{11739}'), ('\u{118a0}', '\u{118e9}'), + ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{11c00}', '\u{11c08}'), + ('\u{11c0a}', '\u{11c36}'), ('\u{11c38}', '\u{11c40}'), ('\u{11c50}', '\u{11c59}'), + ('\u{11c72}', '\u{11c8f}'), ('\u{11c92}', '\u{11ca7}'), ('\u{11ca9}', '\u{11cb6}'), + ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', '\u{12543}'), + ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', '\u{16a38}'), + ('\u{16a40}', '\u{16a5e}'), ('\u{16a60}', '\u{16a69}'), ('\u{16ad0}', '\u{16aed}'), + ('\u{16af0}', '\u{16af4}'), ('\u{16b00}', '\u{16b36}'), ('\u{16b40}', '\u{16b43}'), + ('\u{16b50}', '\u{16b59}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), + ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f7e}'), ('\u{16f8f}', '\u{16f9f}'), + ('\u{16fe0}', '\u{16fe0}'), ('\u{17000}', '\u{187ec}'), ('\u{18800}', '\u{18af2}'), + ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), + ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1bc9d}', '\u{1bc9e}'), + ('\u{1d165}', '\u{1d169}'), ('\u{1d16d}', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), + ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), + ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), + ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), + ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), + ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), + ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), + ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), + ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), + ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), + ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), + ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), + ('\u{1d7ce}', '\u{1d7ff}'), ('\u{1da00}', '\u{1da36}'), ('\u{1da3b}', '\u{1da6c}'), + ('\u{1da75}', '\u{1da75}'), ('\u{1da84}', '\u{1da84}'), ('\u{1da9b}', '\u{1da9f}'), + ('\u{1daa1}', '\u{1daaf}'), ('\u{1e000}', '\u{1e006}'), ('\u{1e008}', '\u{1e018}'), + ('\u{1e01b}', '\u{1e021}'), ('\u{1e023}', '\u{1e024}'), ('\u{1e026}', '\u{1e02a}'), + ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1e900}', '\u{1e94a}'), + ('\u{1e950}', '\u{1e959}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), + ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), + ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), + ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), + ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), + ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), + ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), + ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), + ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), + ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), + ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), + ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), + ('\u{2b740}', '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2f800}', '\u{2fa1d}'), + ('\u{e0100}', '\u{e01ef}') + ]; + + pub fn XID_Continue(c: char) -> bool { + super::bsearch_range_table(c, XID_Continue_table) + } + + pub const XID_Start_table: &'static [(char, char)] = &[ + ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), + ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), + ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', + '\u{2ee}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37b}', '\u{37d}'), + ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', + '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'), + ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{561}', + '\u{587}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{620}', '\u{64a}'), + ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}', + '\u{6e6}'), ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), + ('\u{710}', '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}', + '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), + ('\u{800}', '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}', + '\u{828}'), ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b4}'), ('\u{8b6}', '\u{8bd}'), + ('\u{904}', '\u{939}'), ('\u{93d}', '\u{93d}'), ('\u{950}', '\u{950}'), ('\u{958}', + '\u{961}'), ('\u{971}', '\u{980}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), + ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', + '\u{9b9}'), ('\u{9bd}', '\u{9bd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), + ('\u{9df}', '\u{9e1}'), ('\u{9f0}', '\u{9f1}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', + '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), + ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', + '\u{a5e}'), ('\u{a72}', '\u{a74}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), + ('\u{a93}', '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', + '\u{ab9}'), ('\u{abd}', '\u{abd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), + ('\u{af9}', '\u{af9}'), ('\u{b05}', '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', + '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), + ('\u{b3d}', '\u{b3d}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b61}'), ('\u{b71}', + '\u{b71}'), ('\u{b83}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), + ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', + '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), + ('\u{bd0}', '\u{bd0}'), ('\u{c05}', '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', + '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c3d}'), ('\u{c58}', '\u{c5a}'), + ('\u{c60}', '\u{c61}'), ('\u{c80}', '\u{c80}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', + '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), + ('\u{cbd}', '\u{cbd}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', '\u{ce1}'), ('\u{cf1}', + '\u{cf2}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), + ('\u{d3d}', '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d54}', '\u{d56}'), ('\u{d5f}', + '\u{d61}'), ('\u{d7a}', '\u{d7f}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), + ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', + '\u{e30}'), ('\u{e32}', '\u{e32}'), ('\u{e40}', '\u{e46}'), ('\u{e81}', '\u{e82}'), + ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', + '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), + ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', + '\u{eb0}'), ('\u{eb2}', '\u{eb2}'), ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), + ('\u{ec6}', '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f40}', + '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), ('\u{1000}', '\u{102a}'), + ('\u{103f}', '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', '\u{105d}'), ('\u{1061}', + '\u{1061}'), ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), ('\u{1075}', '\u{1081}'), + ('\u{108e}', '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', + '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), + ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', + '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), + ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', + '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), + ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f5}'), ('\u{13f8}', '\u{13fd}'), ('\u{1401}', + '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', '\u{16ea}'), + ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1720}', + '\u{1731}'), ('\u{1740}', '\u{1751}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), + ('\u{1780}', '\u{17b3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', + '\u{1877}'), ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), + ('\u{1900}', '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', + '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', '\u{1a54}'), + ('\u{1aa7}', '\u{1aa7}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b83}', + '\u{1ba0}'), ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', '\u{1c23}'), + ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', '\u{1c7d}'), ('\u{1c80}', '\u{1c88}'), ('\u{1ce9}', + '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), ('\u{1cf5}', '\u{1cf6}'), ('\u{1d00}', '\u{1dbf}'), + ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', + '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), + ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', + '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), + ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', + '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), + ('\u{2090}', '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', + '\u{2113}'), ('\u{2115}', '\u{2115}'), ('\u{2118}', '\u{211d}'), ('\u{2124}', '\u{2124}'), + ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{2139}'), ('\u{213c}', + '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), + ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', + '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), + ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', + '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), + ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', + '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{3005}', '\u{3007}'), ('\u{3021}', '\u{3029}'), + ('\u{3031}', '\u{3035}'), ('\u{3038}', '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{309d}', + '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), + ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', + '\u{4db5}'), ('\u{4e00}', '\u{9fd5}'), ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), + ('\u{a500}', '\u{a60c}'), ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', + '\u{a66e}'), ('\u{a67f}', '\u{a69d}'), ('\u{a6a0}', '\u{a6ef}'), ('\u{a717}', '\u{a71f}'), + ('\u{a722}', '\u{a788}'), ('\u{a78b}', '\u{a7ae}'), ('\u{a7b0}', '\u{a7b7}'), ('\u{a7f7}', + '\u{a801}'), ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a822}'), + ('\u{a840}', '\u{a873}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', + '\u{a8fb}'), ('\u{a8fd}', '\u{a8fd}'), ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), + ('\u{a960}', '\u{a97c}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', + '\u{a9e4}'), ('\u{a9e6}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', '\u{aa28}'), + ('\u{aa40}', '\u{aa42}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', + '\u{aa7a}'), ('\u{aa7e}', '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), + ('\u{aab9}', '\u{aabd}'), ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', + '\u{aadd}'), ('\u{aae0}', '\u{aaea}'), ('\u{aaf2}', '\u{aaf4}'), ('\u{ab01}', '\u{ab06}'), + ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', + '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab65}'), ('\u{ab70}', '\u{abe2}'), + ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', + '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), + ('\u{fb1d}', '\u{fb1d}'), ('\u{fb1f}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', + '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), + ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', + '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdf9}'), ('\u{fe71}', '\u{fe71}'), + ('\u{fe73}', '\u{fe73}'), ('\u{fe77}', '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', + '\u{fe7b}'), ('\u{fe7d}', '\u{fe7d}'), ('\u{fe7f}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), + ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), ('\u{ffc2}', + '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), + ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), + ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), + ('\u{10080}', '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{10280}', '\u{1029c}'), + ('\u{102a0}', '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', '\u{1034a}'), + ('\u{10350}', '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), + ('\u{103c8}', '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), + ('\u{104b0}', '\u{104d3}'), ('\u{104d8}', '\u{104fb}'), ('\u{10500}', '\u{10527}'), + ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), + ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), + ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), + ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), + ('\u{108e0}', '\u{108f2}'), ('\u{108f4}', '\u{108f5}'), ('\u{10900}', '\u{10915}'), + ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', '\u{109bf}'), + ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), + ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), + ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', '\u{10b35}'), + ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), + ('\u{10c00}', '\u{10c48}'), ('\u{10c80}', '\u{10cb2}'), ('\u{10cc0}', '\u{10cf2}'), + ('\u{11003}', '\u{11037}'), ('\u{11083}', '\u{110af}'), ('\u{110d0}', '\u{110e8}'), + ('\u{11103}', '\u{11126}'), ('\u{11150}', '\u{11172}'), ('\u{11176}', '\u{11176}'), + ('\u{11183}', '\u{111b2}'), ('\u{111c1}', '\u{111c4}'), ('\u{111da}', '\u{111da}'), + ('\u{111dc}', '\u{111dc}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{1122b}'), + ('\u{11280}', '\u{11286}'), ('\u{11288}', '\u{11288}'), ('\u{1128a}', '\u{1128d}'), + ('\u{1128f}', '\u{1129d}'), ('\u{1129f}', '\u{112a8}'), ('\u{112b0}', '\u{112de}'), + ('\u{11305}', '\u{1130c}'), ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), + ('\u{1132a}', '\u{11330}'), ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), + ('\u{1133d}', '\u{1133d}'), ('\u{11350}', '\u{11350}'), ('\u{1135d}', '\u{11361}'), + ('\u{11400}', '\u{11434}'), ('\u{11447}', '\u{1144a}'), ('\u{11480}', '\u{114af}'), + ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), ('\u{11580}', '\u{115ae}'), + ('\u{115d8}', '\u{115db}'), ('\u{11600}', '\u{1162f}'), ('\u{11644}', '\u{11644}'), + ('\u{11680}', '\u{116aa}'), ('\u{11700}', '\u{11719}'), ('\u{118a0}', '\u{118df}'), + ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{11c00}', '\u{11c08}'), + ('\u{11c0a}', '\u{11c2e}'), ('\u{11c40}', '\u{11c40}'), ('\u{11c72}', '\u{11c8f}'), + ('\u{12000}', '\u{12399}'), ('\u{12400}', '\u{1246e}'), ('\u{12480}', '\u{12543}'), + ('\u{13000}', '\u{1342e}'), ('\u{14400}', '\u{14646}'), ('\u{16800}', '\u{16a38}'), + ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'), + ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), + ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{16f93}', '\u{16f9f}'), + ('\u{16fe0}', '\u{16fe0}'), ('\u{17000}', '\u{187ec}'), ('\u{18800}', '\u{18af2}'), + ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), + ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1d400}', '\u{1d454}'), + ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), + ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), + ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), + ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), + ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), + ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), + ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), + ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), + ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), + ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e800}', '\u{1e8c4}'), + ('\u{1e900}', '\u{1e943}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), + ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), + ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), + ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), + ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), + ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), + ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), + ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), + ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), + ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), + ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), + ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), + ('\u{2b740}', '\u{2b81d}'), ('\u{2b820}', '\u{2cea1}'), ('\u{2f800}', '\u{2fa1d}') + ]; + + pub fn XID_Start(c: char) -> bool { + super::bsearch_range_table(c, XID_Start_table) + } + +} + diff --git a/unicode-xid/src/tests.rs b/unicode-xid/src/tests.rs new file mode 100644 index 000000000..f4333967f --- /dev/null +++ b/unicode-xid/src/tests.rs @@ -0,0 +1,113 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(feature = "bench")] +use std::iter; +#[cfg(feature = "bench")] +use test::Bencher; +#[cfg(feature = "bench")] +use std::prelude::v1::*; + +use super::UnicodeXID; + +#[cfg(feature = "bench")] +#[bench] +fn cargo_is_xid_start(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.bytes = string.len() as u64; + b.iter(|| { + string.chars().all(UnicodeXID::is_xid_start) + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn stdlib_is_xid_start(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.bytes = string.len() as u64; + b.iter(|| { + string.chars().all(char::is_xid_start) + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn cargo_xid_continue(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.bytes = string.len() as u64; + b.iter(|| { + string.chars().all(UnicodeXID::is_xid_continue) + }); +} + +#[cfg(feature = "bench")] +#[bench] +fn stdlib_xid_continue(b: &mut Bencher) { + let string = iter::repeat('a').take(4096).collect::<String>(); + + b.bytes = string.len() as u64; + b.iter(|| { + string.chars().all(char::is_xid_continue) + }); +} + +#[test] +fn test_is_xid_start() { + let chars = [ + 'A', 'Z', 'a', 'z', + '\u{1000d}', '\u{10026}', + ]; + + for ch in &chars { + assert!(UnicodeXID::is_xid_start(*ch), "{}", ch); + } +} + +#[test] +fn test_is_not_xid_start() { + let chars = [ + '\x00', '\x01', + '0', '9', + ' ', '[', '<', '{', '(', + '\u{02c2}', '\u{ffff}', + ]; + + for ch in &chars { + assert!(!UnicodeXID::is_xid_start(*ch), "{}", ch); + } +} + +#[test] +fn test_is_xid_continue() { + let chars = [ + '0', '9', 'A', 'Z', 'a', 'z', '_', + '\u{1000d}', '\u{10026}', + ]; + + for ch in &chars { + assert!(UnicodeXID::is_xid_continue(*ch), "{}", ch); + } +} + +#[test] +fn test_is_not_xid_continue() { + let chars = [ + '\x00', '\x01', + ' ', '[', '<', '{', '(', + '\u{02c2}', '\u{ffff}', + ]; + + for &ch in &chars { + assert!(!UnicodeXID::is_xid_continue(ch), "{}", ch); + } +} diff --git a/url/.cargo-checksum.json b/url/.cargo-checksum.json new file mode 100644 index 000000000..7f9db8de7 --- /dev/null +++ b/url/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"} \ No newline at end of file diff --git a/url/.pc/.quilt_patches b/url/.pc/.quilt_patches new file mode 100644 index 000000000..6857a8d44 --- /dev/null +++ b/url/.pc/.quilt_patches @@ -0,0 +1 @@ +debian/patches diff --git a/url/.pc/.quilt_series b/url/.pc/.quilt_series new file mode 100644 index 000000000..c2067066a --- /dev/null +++ b/url/.pc/.quilt_series @@ -0,0 +1 @@ +series diff --git a/url/.pc/.version b/url/.pc/.version new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/url/.pc/.version @@ -0,0 +1 @@ +2 diff --git a/url/.pc/0001-Remove-dependency-to-outdated-serde.patch/.timestamp b/url/.pc/0001-Remove-dependency-to-outdated-serde.patch/.timestamp new file mode 100644 index 000000000..e69de29bb diff --git a/url/.pc/0001-Remove-dependency-to-outdated-serde.patch/Cargo.toml b/url/.pc/0001-Remove-dependency-to-outdated-serde.patch/Cargo.toml new file mode 100644 index 000000000..ea661e0c6 --- /dev/null +++ b/url/.pc/0001-Remove-dependency-to-outdated-serde.patch/Cargo.toml @@ -0,0 +1,83 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "url" +version = "1.7.2" +authors = ["The rust-url developers"] +description = "URL library for Rust, based on the WHATWG URL Standard" +documentation = "https://docs.rs/url" +readme = "README.md" +keywords = ["url", "parser"] +categories = ["parser-implementations", "web-programming", "encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/servo/rust-url" +[package.metadata.docs.rs] +features = ["query_encoding"] + +[lib] +test = false + +[[test]] +name = "unit" + +[[test]] +name = "data" +harness = false + +[[bench]] +name = "parse_url" +harness = false +[dependencies.encoding] +version = "0.2" +optional = true + +[dependencies.heapsize] +version = ">=0.4.1, <0.5" +optional = true + +[dependencies.idna] +version = "0.1.0" + +[dependencies.matches] +version = "0.1" + +[dependencies.percent-encoding] +version = "1.0.0" + +[dependencies.rustc-serialize] +version = "0.3" +optional = true + +[dependencies.serde] +version = ">=0.6.1, <0.9" +optional = true +[dev-dependencies.bencher] +version = "0.1" + +[dev-dependencies.rustc-serialize] +version = "0.3" + +[dev-dependencies.rustc-test] +version = "0.3" + +[dev-dependencies.serde_json] +version = ">=0.6.1, <0.9" + +[features] +heap_size = ["heapsize"] +query_encoding = ["encoding"] +[badges.appveyor] +repository = "Manishearth/rust-url" + +[badges.travis-ci] +repository = "servo/rust-url" diff --git a/url/.pc/applied-patches b/url/.pc/applied-patches new file mode 100644 index 000000000..cfd194d9d --- /dev/null +++ b/url/.pc/applied-patches @@ -0,0 +1 @@ +0001-Remove-dependency-to-outdated-serde.patch diff --git a/url/Cargo.toml b/url/Cargo.toml new file mode 100644 index 000000000..077e30473 --- /dev/null +++ b/url/Cargo.toml @@ -0,0 +1,77 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "url" +version = "1.7.2" +authors = ["The rust-url developers"] +description = "URL library for Rust, based on the WHATWG URL Standard" +documentation = "https://docs.rs/url" +readme = "README.md" +keywords = ["url", "parser"] +categories = ["parser-implementations", "web-programming", "encoding"] +license = "MIT/Apache-2.0" +repository = "https://github.com/servo/rust-url" +[package.metadata.docs.rs] +features = ["query_encoding"] + +[lib] +test = false + +[[test]] +name = "unit" + +[[test]] +name = "data" +harness = false + +[[bench]] +name = "parse_url" +harness = false +[dependencies.encoding] +version = "0.2" +optional = true + +[dependencies.heapsize] +version = ">=0.4.1, <0.5" +optional = true + +[dependencies.idna] +version = "0.1.0" + +[dependencies.matches] +version = "0.1" + +[dependencies.percent-encoding] +version = "1.0.0" + +[dependencies.rustc-serialize] +version = "0.3" +optional = true + +[dev-dependencies.bencher] +version = "0.1" + +[dev-dependencies.rustc-serialize] +version = "0.3" + +[dev-dependencies.rustc-test] +version = "0.3" + +[features] +heap_size = ["heapsize"] +query_encoding = ["encoding"] +[badges.appveyor] +repository = "Manishearth/rust-url" + +[badges.travis-ci] +repository = "servo/rust-url" diff --git a/url/LICENSE-APACHE b/url/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/url/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/url/LICENSE-MIT b/url/LICENSE-MIT new file mode 100644 index 000000000..24de6b418 --- /dev/null +++ b/url/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2013-2016 The rust-url developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/url/README.md b/url/README.md new file mode 100644 index 000000000..0721254af --- /dev/null +++ b/url/README.md @@ -0,0 +1,10 @@ +rust-url +======== + +[![Travis build Status](https://travis-ci.org/servo/rust-url.svg?branch=master)](https://travis-ci.org/servo/rust-url) [![Appveyor build status](https://ci.appveyor.com/api/projects/status/ulkqx2xcemyod6xa?svg=true)](https://ci.appveyor.com/project/Manishearth/rust-url) + +URL library for Rust, based on the [URL Standard](https://url.spec.whatwg.org/). + +[Documentation](https://docs.rs/url/) + +Please see [UPGRADING.md](https://github.com/servo/rust-url/blob/master/UPGRADING.md) if you are upgrading from 0.x to 1.x. diff --git a/url/UPGRADING.md b/url/UPGRADING.md new file mode 100644 index 000000000..f156130f6 --- /dev/null +++ b/url/UPGRADING.md @@ -0,0 +1,263 @@ +# Guide to upgrading from url 0.x to 1.x + +* The fields of `Url` are now private because the `Url` constructor, parser, + and setters maintain invariants that could be violated if you were to set the fields directly. + Instead of accessing, for example, `url.scheme`, use the getter method, such as `url.scheme()`. + Instead of assigning directly to a field, for example `url.scheme = "https".to_string()`, + use the setter method, such as `url.set_scheme("https").unwrap()`. + (Some setters validate the new value and return a `Result` that must be used). + +* The methods of `Url` now return `&str` instead of `String`, + thus reducing allocations and making serialization cheap. + +* The `path()` method on `url::Url` instances used to return `Option<&[String]>`; + now it returns `&str`. + If you would like functionality more similar to the old behavior of `path()`, + use `path_segments()` that returns `Option<str::Split<char>>`. + + Before upgrading: + + ```rust + let issue_list_url = Url::parse( + "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" + ).unwrap(); + assert_eq!(issue_list_url.path(), Some(&["rust-lang".to_string(), + "rust".to_string(), + "issues".to_string()][..])); + ``` + + After upgrading: + + ```rust + let issue_list_url = Url::parse( + "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" + ).unwrap(); + assert_eq!(issue_list_url.path(), "/rust-lang/rust/issues"); + assert_eq!(issue_list_url.path_segments().map(|c| c.collect::<Vec<_>>()), + Some(vec!["rust-lang", "rust", "issues"])); + ``` + +* The `path_mut()` method on `url::Url` instances that allowed modification of a URL's path + has been replaced by `path_segments_mut()`. + + Before upgrading: + + ```rust + let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap(); + url.path_mut().unwrap().push("issues"); + ``` + + After upgrading: + + ```rust + let mut url = Url::parse("https://github.com/rust-lang/rust").unwrap(); + url.path_segments_mut().unwrap().push("issues"); + ``` + +* The `domain_mut()` method on `url::Url` instances that allowed modification of a URL's domain + has been replaced by `set_host()` and `set_ip_host()`. + +* The `host()` method on `url::Url` instances used to return `Option<&Host>`; + now it returns `Option<Host<&str>>`. + The `serialize_host()` method that returned `Option<String>` + has been replaced by the `host_str()` method that returns `Option<&str>`. + +* The `serialize()` method on `url::Url` instances that returned `String` + has been replaced by an `as_str()` method that returns `&str`. + + Before upgrading: + + ```rust + let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); + assert_eq!(this_document.serialize(), "http://servo.github.io/rust-url/url/index.html".to_string()); + ``` + + After upgrading: + + ```rust + let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); + assert_eq!(this_document.as_str(), "http://servo.github.io/rust-url/url/index.html"); + ``` + +* `url::UrlParser` has been replaced by `url::Url::parse()` and `url::Url::join()`. + + Before upgrading: + + ```rust + let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); + let css_url = UrlParser::new().base_url(&this_document).parse("../main.css").unwrap(); + assert_eq!(css_url.serialize(), "http://servo.github.io/rust-url/main.css".to_string()); + ``` + + After upgrading: + + ```rust + let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html").unwrap(); + let css_url = this_document.join("../main.css").unwrap(); + assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css"); + ``` + +* `url::parse_path()` and `url::UrlParser::parse_path()` have been removed without replacement. + As a workaround, you can give a base URL that you then ignore too `url::Url::parse()`. + + Before upgrading: + + ```rust + let (path, query, fragment) = url::parse_path("/foo/bar/../baz?q=42").unwrap(); + assert_eq!(path, vec!["foo".to_string(), "baz".to_string()]); + assert_eq!(query, Some("q=42".to_string())); + assert_eq!(fragment, None); + ``` + + After upgrading: + + ```rust + let base = Url::parse("http://example.com").unwrap(); + let with_path = base.join("/foo/bar/../baz?q=42").unwrap(); + assert_eq!(with_path.path(), "/foo/baz"); + assert_eq!(with_path.query(), Some("q=42")); + assert_eq!(with_path.fragment(), None); + ``` + +* The `url::form_urlencoded::serialize()` method + has been replaced with the `url::form_urlencoded::Serializer` struct. + Instead of calling `serialize()` with key/value pairs, + create a new `Serializer` with a new string, + call the `extend_pairs()` method on the `Serializer` instance with the key/value pairs as the argument, + then call `finish()`. + + Before upgrading: + + ```rust + let form = url::form_urlencoded::serialize(form.iter().map(|(k, v)| { + (&k[..], &v[..]) + })); + ``` + + After upgrading: + + ```rust + let form = url::form_urlencoded::Serializer::new(String::new()).extend_pairs( + form.iter().map(|(k, v)| { (&k[..], &v[..]) }) + ).finish(); + ``` + +* The `set_query_from_pairs()` method on `url::Url` instances that took key/value pairs + has been replaced with `query_pairs_mut()`, which allows you to modify the `url::Url`'s query pairs. + + Before upgrading: + + ```rust + let mut url = Url::parse("https://duckduckgo.com/").unwrap(); + let pairs = vec![ + ("q", "test"), + ("ia", "images"), + ]; + url.set_query_from_pairs(pairs.iter().map(|&(k, v)| { + (&k[..], &v[..]) + })); + ``` + + After upgrading: + + ```rust + let mut url = Url::parse("https://duckduckgo.com/").unwrap(); + let pairs = vec![ + ("q", "test"), + ("ia", "images"), + ]; + url.query_pairs_mut().clear().extend_pairs( + pairs.iter().map(|&(k, v)| { (&k[..], &v[..]) }) + ); + ``` + +* `url::SchemeData`, its variants `Relative` and `NonRelative`, + and the struct `url::RelativeSchemeData` have been removed. + Instead of matching on these variants + to determine if you have a URL in a relative scheme such as HTTP + versus a URL in a non-relative scheme as data, + use the `cannot_be_a_base()` method to determine which kind you have. + + Before upgrading: + + ```rust + match url.scheme_data { + url::SchemeData::Relative(..) => {} + url::SchemeData::NonRelative(..) => { + return Err(human(format!("`{}` must have relative scheme \ + data: {}", field, url))) + } + } + ``` + + After upgrading: + + ```rust + if url.cannot_be_a_base() { + return Err(human(format!("`{}` must have relative scheme \ + data: {}", field, url))) + } + ``` + +* The functions `url::whatwg_scheme_type_mapper()`, the `SchemeType` enum, + and the `scheme_type_mapper()` method on `url::UrlParser` instances have been removed. + `SchemeType` had a method for getting the `default_port()`; + to replicate this functionality, use the method `port_or_known_default()` on `url::Url` instances. + The `port_or_default()` method on `url::Url` instances has been removed; + use `port_or_known_default()` instead. + + Before upgrading: + + ```rust + let port = match whatwg_scheme_type_mapper(&url.scheme) { + SchemeType::Relative(port) => port, + _ => return Err(format!("Invalid special scheme: `{}`", + raw_url.scheme)), + }; + ``` + + After upgrading: + + ```rust + let port = match url.port_or_known_default() { + Some(port) => port, + _ => return Err(format!("Invalid special scheme: `{}`", + url.scheme())), + }; + ``` + +* The following formatting utilities have been removed without replacement; + look at their linked previous implementations + if you would like to replicate the functionality in your code: + * [`url::format::PathFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL24) + * [`url::format::UserInfoFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL50) + * [`url::format::UrlNoFragmentFormatter`](https://github.com/servo/rust-url/pull/176/commits/9e759f18726c8e1343162922b87163d4dd08fe3c#diff-0bb16ac13b75e9b568fa4aff61b0e71dL70) + +* `url::percent_encoding::percent_decode()` used to have a return type of `Vec<u8>`; + now it returns an iterator of decoded `u8` bytes that also implements `Into<Cow<u8>>`. + Use `.into().to_owned()` to obtain a `Vec<u8>`. + (`.collect()` also works but might not be as efficient.) + +* The `url::percent_encoding::EncodeSet` struct and constant instances + used with `url::percent_encoding::percent_encode()` + have been changed to structs that implement the trait `url::percent_encoding::EncodeSet`. + * `SIMPLE_ENCODE_SET`, `QUERY_ENCODE_SET`, `DEFAULT_ENCODE_SET`, + and `USERINFO_ENCODE_SET` have the same behavior. + * `USERNAME_ENCODE_SET` and `PASSWORD_ENCODE_SET` have been removed; + use `USERINFO_ENCODE_SET` instead. + * `HTTP_VALUE_ENCODE_SET` has been removed; + an implementation of it in the new types can be found [in hyper's source]( + https://github.com/hyperium/hyper/blob/67436c5bf615cf5a55a71e32b788afef5985570e/src/header/parsing.rs#L131-L138) + if you need to replicate this functionality in your code. + * `FORM_URLENCODED_ENCODE_SET` has been removed; + instead, use the functionality in `url::form_urlencoded`. + * `PATH_SEGMENT_ENCODE_SET` has been added for use on '/'-separated path segments. + +* `url::percent_encoding::percent_decode_to()` has been removed. + Use `url::percent_encoding::percent_decode()` which returns an iterator. + You can then use the iterator’s `collect()` method + or give it to some data structure’s `extend()` method. +* A number of `ParseError` variants have changed. + [See the documentation for the current set](http://servo.github.io/rust-url/url/enum.ParseError.html). +* `url::OpaqueOrigin::new()` and `url::Origin::UID(OpaqueOrigin)` + have been replaced by `url::Origin::new_opaque()` and `url::Origin::Opaque(OpaqueOrigin)`, respectively. diff --git a/url/appveyor.yml b/url/appveyor.yml new file mode 100644 index 000000000..5819d38b1 --- /dev/null +++ b/url/appveyor.yml @@ -0,0 +1,13 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe' + - rust-nightly-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + - git submodule update --init --recursive + +build: false + +test_script: + - cargo build + - cargo test --verbose diff --git a/url/benches/parse_url.rs b/url/benches/parse_url.rs new file mode 100644 index 000000000..d6ac3c402 --- /dev/null +++ b/url/benches/parse_url.rs @@ -0,0 +1,18 @@ +#[macro_use] +extern crate bencher; + +extern crate url; + +use bencher::{black_box, Bencher}; + +use url::Url; + +fn short(bench: &mut Bencher) { + let url = "https://example.com/bench"; + + bench.bytes = url.len() as u64; + bench.iter(|| black_box(url).parse::<Url>().unwrap()); +} + +benchmark_group!(benches, short); +benchmark_main!(benches); diff --git a/url/debian/patches/0001-Remove-dependency-to-outdated-serde.patch b/url/debian/patches/0001-Remove-dependency-to-outdated-serde.patch new file mode 100644 index 000000000..8fc722c3a --- /dev/null +++ b/url/debian/patches/0001-Remove-dependency-to-outdated-serde.patch @@ -0,0 +1,32 @@ +From: Wolfgang Silbermayr <ws@xell.at> +Date: Thu, 20 Sep 2018 10:53:53 +0200 +Subject: Remove dependency to outdated serde + +--- + Cargo.toml | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 804e4c3..e00d124 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -58,9 +58,6 @@ version = "1.0.0" + version = "0.3" + optional = true + +-[dependencies.serde] +-version = ">=0.6.1, <0.9" +-optional = true + [dev-dependencies.bencher] + version = "0.1" + +@@ -70,9 +67,6 @@ version = "0.3" + [dev-dependencies.rustc-test] + version = "0.3" + +-[dev-dependencies.serde_json] +-version = ">=0.6.1, <0.9" +- + [features] + heap_size = ["heapsize"] + query_encoding = ["encoding"] diff --git a/url/debian/patches/series b/url/debian/patches/series new file mode 100644 index 000000000..cfd194d9d --- /dev/null +++ b/url/debian/patches/series @@ -0,0 +1 @@ +0001-Remove-dependency-to-outdated-serde.patch diff --git a/url/docs/404.html b/url/docs/404.html new file mode 100644 index 000000000..b13eac0ee --- /dev/null +++ b/url/docs/404.html @@ -0,0 +1,3 @@ +<meta http-equiv="refresh" content="0; url=https://docs.rs/url/"> +<link rel="canonical" href="https://docs.rs/url/"> +<a href="https://docs.rs/url/">Moved to docs.rs</a> diff --git a/url/docs/index.html b/url/docs/index.html new file mode 100644 index 000000000..b13eac0ee --- /dev/null +++ b/url/docs/index.html @@ -0,0 +1,3 @@ +<meta http-equiv="refresh" content="0; url=https://docs.rs/url/"> +<link rel="canonical" href="https://docs.rs/url/"> +<a href="https://docs.rs/url/">Moved to docs.rs</a> diff --git a/url/src/encoding.rs b/url/src/encoding.rs new file mode 100644 index 000000000..920b30e11 --- /dev/null +++ b/url/src/encoding.rs @@ -0,0 +1,146 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//! Abstraction that conditionally compiles either to rust-encoding, +//! or to only support UTF-8. + +#[cfg(feature = "query_encoding")] extern crate encoding; + +use std::borrow::Cow; +#[cfg(feature = "query_encoding")] use std::fmt::{self, Debug, Formatter}; + +#[cfg(feature = "query_encoding")] use self::encoding::types::{DecoderTrap, EncoderTrap}; +#[cfg(feature = "query_encoding")] use self::encoding::label::encoding_from_whatwg_label; +#[cfg(feature = "query_encoding")] pub use self::encoding::types::EncodingRef; + +#[cfg(feature = "query_encoding")] +#[derive(Copy, Clone)] +pub struct EncodingOverride { + /// `None` means UTF-8. + encoding: Option<EncodingRef> +} + +#[cfg(feature = "query_encoding")] +impl EncodingOverride { + pub fn from_opt_encoding(encoding: Option<EncodingRef>) -> Self { + encoding.map(Self::from_encoding).unwrap_or_else(Self::utf8) + } + + pub fn from_encoding(encoding: EncodingRef) -> Self { + EncodingOverride { + encoding: if encoding.name() == "utf-8" { None } else { Some(encoding) } + } + } + + #[inline] + pub fn utf8() -> Self { + EncodingOverride { encoding: None } + } + + pub fn lookup(label: &[u8]) -> Option<Self> { + // Don't use String::from_utf8_lossy since no encoding label contains U+FFFD + // https://encoding.spec.whatwg.org/#names-and-labels + ::std::str::from_utf8(label) + .ok() + .and_then(encoding_from_whatwg_label) + .map(Self::from_encoding) + } + + /// https://encoding.spec.whatwg.org/#get-an-output-encoding + pub fn to_output_encoding(self) -> Self { + if let Some(encoding) = self.encoding { + if matches!(encoding.name(), "utf-16le" | "utf-16be") { + return Self::utf8() + } + } + self + } + + pub fn is_utf8(&self) -> bool { + self.encoding.is_none() + } + + pub fn name(&self) -> &'static str { + match self.encoding { + Some(encoding) => encoding.name(), + None => "utf-8", + } + } + + pub fn decode<'a>(&self, input: Cow<'a, [u8]>) -> Cow<'a, str> { + match self.encoding { + // `encoding.decode` never returns `Err` when called with `DecoderTrap::Replace` + Some(encoding) => encoding.decode(&input, DecoderTrap::Replace).unwrap().into(), + None => decode_utf8_lossy(input), + } + } + + pub fn encode<'a>(&self, input: Cow<'a, str>) -> Cow<'a, [u8]> { + match self.encoding { + // `encoding.encode` never returns `Err` when called with `EncoderTrap::NcrEscape` + Some(encoding) => Cow::Owned(encoding.encode(&input, EncoderTrap::NcrEscape).unwrap()), + None => encode_utf8(input) + } + } +} + +#[cfg(feature = "query_encoding")] +impl Debug for EncodingOverride { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "EncodingOverride {{ encoding: ")?; + match self.encoding { + Some(e) => write!(f, "{} }}", e.name()), + None => write!(f, "None }}") + } + } +} + +#[cfg(not(feature = "query_encoding"))] +#[derive(Copy, Clone, Debug)] +pub struct EncodingOverride; + +#[cfg(not(feature = "query_encoding"))] +impl EncodingOverride { + #[inline] + pub fn utf8() -> Self { + EncodingOverride + } + + pub fn decode<'a>(&self, input: Cow<'a, [u8]>) -> Cow<'a, str> { + decode_utf8_lossy(input) + } + + pub fn encode<'a>(&self, input: Cow<'a, str>) -> Cow<'a, [u8]> { + encode_utf8(input) + } +} + +pub fn decode_utf8_lossy(input: Cow<[u8]>) -> Cow<str> { + match input { + Cow::Borrowed(bytes) => String::from_utf8_lossy(bytes), + Cow::Owned(bytes) => { + let raw_utf8: *const [u8]; + match String::from_utf8_lossy(&bytes) { + Cow::Borrowed(utf8) => raw_utf8 = utf8.as_bytes(), + Cow::Owned(s) => return s.into(), + } + // from_utf8_lossy returned a borrow of `bytes` unchanged. + debug_assert!(raw_utf8 == &*bytes as *const [u8]); + // Reuse the existing `Vec` allocation. + unsafe { String::from_utf8_unchecked(bytes) }.into() + } + } +} + +pub fn encode_utf8(input: Cow<str>) -> Cow<[u8]> { + match input { + Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), + Cow::Owned(s) => Cow::Owned(s.into_bytes()) + } +} diff --git a/url/src/form_urlencoded.rs b/url/src/form_urlencoded.rs new file mode 100644 index 000000000..f378c9a6c --- /dev/null +++ b/url/src/form_urlencoded.rs @@ -0,0 +1,411 @@ +// Copyright 2013-2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Parser and serializer for the [`application/x-www-form-urlencoded` syntax]( +//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded), +//! as used by HTML forms. +//! +//! Converts between a string (such as an URL’s query string) +//! and a sequence of (name, value) pairs. + +use encoding::EncodingOverride; +use percent_encoding::{percent_encode_byte, percent_decode}; +use std::borrow::{Borrow, Cow}; +use std::fmt; +use std::str; + + +/// Convert a byte string in the `application/x-www-form-urlencoded` syntax +/// into a iterator of (name, value) pairs. +/// +/// Use `parse(input.as_bytes())` to parse a `&str` string. +/// +/// The names and values are percent-decoded. For instance, `%23first=%25try%25` will be +/// converted to `[("#first", "%try%")]`. +#[inline] +pub fn parse(input: &[u8]) -> Parse { + Parse { + input: input, + encoding: EncodingOverride::utf8(), + } +} + + +/// Convert a byte string in the `application/x-www-form-urlencoded` syntax +/// into a iterator of (name, value) pairs. +/// +/// Use `parse(input.as_bytes())` to parse a `&str` string. +/// +/// This function is only available if the `query_encoding` +/// [feature](http://doc.crates.io/manifest.html#the-features-section]) is enabled. +/// +/// Arguments: +/// +/// * `encoding_override`: The character encoding each name and values is decoded as +/// after percent-decoding. Defaults to UTF-8. +/// `EncodingRef` is defined in [rust-encoding](https://github.com/lifthrasiir/rust-encoding). +/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`. +#[cfg(feature = "query_encoding")] +pub fn parse_with_encoding<'a>(input: &'a [u8], + encoding_override: Option<::encoding::EncodingRef>, + use_charset: bool) + -> Result<Parse<'a>, ()> { + use std::ascii::AsciiExt; + + let mut encoding = EncodingOverride::from_opt_encoding(encoding_override); + if !(encoding.is_utf8() || input.is_ascii()) { + return Err(()) + } + if use_charset { + for sequence in input.split(|&b| b == b'&') { + // No '+' in "_charset_" to replace with ' '. + if sequence.starts_with(b"_charset_=") { + let value = &sequence[b"_charset_=".len()..]; + // Skip replacing '+' with ' ' in value since no encoding label contains either: + // https://encoding.spec.whatwg.org/#names-and-labels + if let Some(e) = EncodingOverride::lookup(value) { + encoding = e; + break + } + } + } + } + Ok(Parse { + input: input, + encoding: encoding, + }) +} + +/// The return type of `parse()`. +#[derive(Copy, Clone, Debug)] +pub struct Parse<'a> { + input: &'a [u8], + encoding: EncodingOverride, +} + +impl<'a> Iterator for Parse<'a> { + type Item = (Cow<'a, str>, Cow<'a, str>); + + fn next(&mut self) -> Option<Self::Item> { + loop { + if self.input.is_empty() { + return None + } + let mut split2 = self.input.splitn(2, |&b| b == b'&'); + let sequence = split2.next().unwrap(); + self.input = split2.next().unwrap_or(&[][..]); + if sequence.is_empty() { + continue + } + let mut split2 = sequence.splitn(2, |&b| b == b'='); + let name = split2.next().unwrap(); + let value = split2.next().unwrap_or(&[][..]); + return Some(( + decode(name, self.encoding), + decode(value, self.encoding), + )) + } + } +} + +fn decode(input: &[u8], encoding: EncodingOverride) -> Cow<str> { + let replaced = replace_plus(input); + encoding.decode(match percent_decode(&replaced).if_any() { + Some(vec) => Cow::Owned(vec), + None => replaced, + }) +} + +/// Replace b'+' with b' ' +fn replace_plus(input: &[u8]) -> Cow<[u8]> { + match input.iter().position(|&b| b == b'+') { + None => Cow::Borrowed(input), + Some(first_position) => { + let mut replaced = input.to_owned(); + replaced[first_position] = b' '; + for byte in &mut replaced[first_position + 1..] { + if *byte == b'+' { + *byte = b' '; + } + } + Cow::Owned(replaced) + } + } +} + +impl<'a> Parse<'a> { + /// Return a new iterator that yields pairs of `String` instead of pairs of `Cow<str>`. + pub fn into_owned(self) -> ParseIntoOwned<'a> { + ParseIntoOwned { inner: self } + } +} + +/// Like `Parse`, but yields pairs of `String` instead of pairs of `Cow<str>`. +#[derive(Debug)] +pub struct ParseIntoOwned<'a> { + inner: Parse<'a> +} + +impl<'a> Iterator for ParseIntoOwned<'a> { + type Item = (String, String); + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next().map(|(k, v)| (k.into_owned(), v.into_owned())) + } +} + +/// The [`application/x-www-form-urlencoded` byte serializer]( +/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer). +/// +/// Return an iterator of `&str` slices. +pub fn byte_serialize(input: &[u8]) -> ByteSerialize { + ByteSerialize { + bytes: input, + } +} + +/// Return value of `byte_serialize()`. +#[derive(Debug)] +pub struct ByteSerialize<'a> { + bytes: &'a [u8], +} + +fn byte_serialized_unchanged(byte: u8) -> bool { + matches!(byte, b'*' | b'-' | b'.' | b'0' ... b'9' | b'A' ... b'Z' | b'_' | b'a' ... b'z') +} + +impl<'a> Iterator for ByteSerialize<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + if let Some((&first, tail)) = self.bytes.split_first() { + if !byte_serialized_unchanged(first) { + self.bytes = tail; + return Some(if first == b' ' { "+" } else { percent_encode_byte(first) }) + } + let position = tail.iter().position(|&b| !byte_serialized_unchanged(b)); + let (unchanged_slice, remaining) = match position { + // 1 for first_byte + i unchanged in tail + Some(i) => self.bytes.split_at(1 + i), + None => (self.bytes, &[][..]), + }; + self.bytes = remaining; + Some(unsafe { str::from_utf8_unchecked(unchanged_slice) }) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + if self.bytes.is_empty() { + (0, Some(0)) + } else { + (1, Some(self.bytes.len())) + } + } +} + +/// The [`application/x-www-form-urlencoded` serializer]( +/// https://url.spec.whatwg.org/#concept-urlencoded-serializer). +#[derive(Debug)] +pub struct Serializer<T: Target> { + target: Option<T>, + start_position: usize, + encoding: EncodingOverride, + custom_encoding: Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>, +} + +struct SilentDebug<T>(T); + +impl<T> fmt::Debug for SilentDebug<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("…") + } +} + +pub trait Target { + fn as_mut_string(&mut self) -> &mut String; + fn finish(self) -> Self::Finished; + type Finished; +} + +impl Target for String { + fn as_mut_string(&mut self) -> &mut String { self } + fn finish(self) -> Self { self } + type Finished = Self; +} + +impl<'a> Target for &'a mut String { + fn as_mut_string(&mut self) -> &mut String { &mut **self } + fn finish(self) -> Self { self } + type Finished = Self; +} + +// `as_mut_string` string here exposes the internal serialization of an `Url`, +// which should not be exposed to users. +// We achieve that by not giving users direct access to `UrlQuery`: +// * Its fields are private +// (and so can not be constructed with struct literal syntax outside of this crate), +// * It has no constructor +// * It is only visible (on the type level) to users in the return type of +// `Url::query_pairs_mut` which is `Serializer<UrlQuery>` +// * `Serializer` keeps its target in a private field +// * Unlike in other `Target` impls, `UrlQuery::finished` does not return `Self`. +impl<'a> Target for ::UrlQuery<'a> { + fn as_mut_string(&mut self) -> &mut String { + &mut self.url.as_mut().unwrap().serialization + } + + fn finish(mut self) -> &'a mut ::Url { + let url = self.url.take().unwrap(); + url.restore_already_parsed_fragment(self.fragment.take()); + url + } + + type Finished = &'a mut ::Url; +} + +impl<T: Target> Serializer<T> { + /// Create a new `application/x-www-form-urlencoded` serializer for the given target. + /// + /// If the target is non-empty, + /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax. + pub fn new(target: T) -> Self { + Self::for_suffix(target, 0) + } + + /// Create a new `application/x-www-form-urlencoded` serializer + /// for a suffix of the given target. + /// + /// If that suffix is non-empty, + /// its content is assumed to already be in `application/x-www-form-urlencoded` syntax. + pub fn for_suffix(mut target: T, start_position: usize) -> Self { + &target.as_mut_string()[start_position..]; // Panic if out of bounds + Serializer { + target: Some(target), + start_position: start_position, + encoding: EncodingOverride::utf8(), + custom_encoding: None, + } + } + + /// Remove any existing name/value pair. + /// + /// Panics if called after `.finish()`. + pub fn clear(&mut self) -> &mut Self { + string(&mut self.target).truncate(self.start_position); + self + } + + /// Set the character encoding to be used for names and values before percent-encoding. + #[cfg(feature = "query_encoding")] + pub fn encoding_override(&mut self, new: Option<::encoding::EncodingRef>) -> &mut Self { + self.encoding = EncodingOverride::from_opt_encoding(new).to_output_encoding(); + self + } + + /// Set the character encoding to be used for names and values before percent-encoding. + pub fn custom_encoding_override<F>(&mut self, encode: F) -> &mut Self + where F: FnMut(&str) -> Cow<[u8]> + 'static + { + self.custom_encoding = Some(SilentDebug(Box::new(encode))); + self + } + + /// Serialize and append a name/value pair. + /// + /// Panics if called after `.finish()`. + pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self { + append_pair(string(&mut self.target), self.start_position, self.encoding, + &mut self.custom_encoding, name, value); + self + } + + /// Serialize and append a number of name/value pairs. + /// + /// This simply calls `append_pair` repeatedly. + /// This can be more convenient, so the user doesn’t need to introduce a block + /// to limit the scope of `Serializer`’s borrow of its string. + /// + /// Panics if called after `.finish()`. + pub fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self + where I: IntoIterator, I::Item: Borrow<(K, V)>, K: AsRef<str>, V: AsRef<str> { + { + let string = string(&mut self.target); + for pair in iter { + let &(ref k, ref v) = pair.borrow(); + append_pair(string, self.start_position, self.encoding, + &mut self.custom_encoding, k.as_ref(), v.as_ref()); + } + } + self + } + + /// Add a name/value pair whose name is `_charset_` + /// and whose value is the character encoding’s name. + /// (See the `encoding_override()` method.) + /// + /// Panics if called after `.finish()`. + #[cfg(feature = "query_encoding")] + pub fn append_charset(&mut self) -> &mut Self { + assert!(self.custom_encoding.is_none(), + "Cannot use both custom_encoding_override() and append_charset()"); + { + let string = string(&mut self.target); + append_separator_if_needed(string, self.start_position); + string.push_str("_charset_="); + string.push_str(self.encoding.name()); + } + self + } + + /// If this serializer was constructed with a string, take and return that string. + /// + /// ```rust + /// use url::form_urlencoded; + /// let encoded: String = form_urlencoded::Serializer::new(String::new()) + /// .append_pair("foo", "bar & baz") + /// .append_pair("saison", "Été+hiver") + /// .finish(); + /// assert_eq!(encoded, "foo=bar+%26+baz&saison=%C3%89t%C3%A9%2Bhiver"); + /// ``` + /// + /// Panics if called more than once. + pub fn finish(&mut self) -> T::Finished { + self.target.take().expect("url::form_urlencoded::Serializer double finish").finish() + } +} + +fn append_separator_if_needed(string: &mut String, start_position: usize) { + if string.len() > start_position { + string.push('&') + } +} + +fn string<T: Target>(target: &mut Option<T>) -> &mut String { + target.as_mut().expect("url::form_urlencoded::Serializer finished").as_mut_string() +} + +fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride, + custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>, + name: &str, value: &str) { + append_separator_if_needed(string, start_position); + append_encoded(name, string, encoding, custom_encoding); + string.push('='); + append_encoded(value, string, encoding, custom_encoding); +} + +fn append_encoded(s: &str, string: &mut String, encoding: EncodingOverride, + custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>) { + let bytes = if let Some(SilentDebug(ref mut custom)) = *custom_encoding { + custom(s) + } else { + encoding.encode(s.into()) + }; + string.extend(byte_serialize(&bytes)); +} diff --git a/url/src/host.rs b/url/src/host.rs new file mode 100644 index 000000000..38e88a3bb --- /dev/null +++ b/url/src/host.rs @@ -0,0 +1,556 @@ +// Copyright 2013-2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf; +use std::cmp; +use std::fmt::{self, Formatter}; +use std::io; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; +use std::vec; +use parser::{ParseResult, ParseError}; +use percent_encoding::{percent_decode, utf8_percent_encode, SIMPLE_ENCODE_SET}; +use idna; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum HostInternal { + None, + Domain, + Ipv4(Ipv4Addr), + Ipv6(Ipv6Addr), +} + +#[cfg(feature = "heapsize")] +known_heap_size!(0, HostInternal); + +#[cfg(feature="serde")] +impl ::serde::Serialize for HostInternal { + fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: ::serde::Serializer { + // This doesn’t use `derive` because that involves + // large dependencies (that take a long time to build), and + // either Macros 1.1 which are not stable yet or a cumbersome build script. + // + // Implementing `Serializer` correctly for an enum is tricky, + // so let’s use existing enums that already do. + use std::net::IpAddr; + match *self { + HostInternal::None => None, + HostInternal::Domain => Some(None), + HostInternal::Ipv4(addr) => Some(Some(IpAddr::V4(addr))), + HostInternal::Ipv6(addr) => Some(Some(IpAddr::V6(addr))), + }.serialize(serializer) + } +} + +#[cfg(feature="serde")] +impl ::serde::Deserialize for HostInternal { + fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: ::serde::Deserializer { + use std::net::IpAddr; + Ok(match ::serde::Deserialize::deserialize(deserializer)? { + None => HostInternal::None, + Some(None) => HostInternal::Domain, + Some(Some(IpAddr::V4(addr))) => HostInternal::Ipv4(addr), + Some(Some(IpAddr::V6(addr))) => HostInternal::Ipv6(addr), + }) + } +} + +impl<S> From<Host<S>> for HostInternal { + fn from(host: Host<S>) -> HostInternal { + match host { + Host::Domain(_) => HostInternal::Domain, + Host::Ipv4(address) => HostInternal::Ipv4(address), + Host::Ipv6(address) => HostInternal::Ipv6(address), + } + } +} + +/// The host name of an URL. +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Host<S=String> { + /// A DNS domain name, as '.' dot-separated labels. + /// Non-ASCII labels are encoded in punycode per IDNA if this is the host of + /// a special URL, or percent encoded for non-special URLs. Hosts for + /// non-special URLs are also called opaque hosts. + Domain(S), + + /// An IPv4 address. + /// `Url::host_str` returns the serialization of this address, + /// as four decimal integers separated by `.` dots. + Ipv4(Ipv4Addr), + + /// An IPv6 address. + /// `Url::host_str` returns the serialization of that address between `[` and `]` brackets, + /// in the format per [RFC 5952 *A Recommendation + /// for IPv6 Address Text Representation*](https://tools.ietf.org/html/rfc5952): + /// lowercase hexadecimal with maximal `::` compression. + Ipv6(Ipv6Addr), +} + +#[cfg(feature="serde")] +impl<S: ::serde::Serialize> ::serde::Serialize for Host<S> { + fn serialize<R>(&self, serializer: &mut R) -> Result<(), R::Error> where R: ::serde::Serializer { + use std::net::IpAddr; + match *self { + Host::Domain(ref s) => Ok(s), + Host::Ipv4(addr) => Err(IpAddr::V4(addr)), + Host::Ipv6(addr) => Err(IpAddr::V6(addr)), + }.serialize(serializer) + } +} + +#[cfg(feature="serde")] +impl<S: ::serde::Deserialize> ::serde::Deserialize for Host<S> { + fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: ::serde::Deserializer { + use std::net::IpAddr; + Ok(match ::serde::Deserialize::deserialize(deserializer)? { + Ok(s) => Host::Domain(s), + Err(IpAddr::V4(addr)) => Host::Ipv4(addr), + Err(IpAddr::V6(addr)) => Host::Ipv6(addr), + }) + } +} + +#[cfg(feature = "heapsize")] +impl<S: HeapSizeOf> HeapSizeOf for Host<S> { + fn heap_size_of_children(&self) -> usize { + match *self { + Host::Domain(ref s) => s.heap_size_of_children(), + _ => 0, + } + } +} + +impl<'a> Host<&'a str> { + /// Return a copy of `self` that owns an allocated `String` but does not borrow an `&Url`. + pub fn to_owned(&self) -> Host<String> { + match *self { + Host::Domain(domain) => Host::Domain(domain.to_owned()), + Host::Ipv4(address) => Host::Ipv4(address), + Host::Ipv6(address) => Host::Ipv6(address), + } + } +} + +impl Host<String> { + /// Parse a host: either an IPv6 address in [] square brackets, or a domain. + /// + /// <https://url.spec.whatwg.org/#host-parsing> + pub fn parse(input: &str) -> Result<Self, ParseError> { + if input.starts_with('[') { + if !input.ends_with(']') { + return Err(ParseError::InvalidIpv6Address) + } + return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6) + } + let domain = percent_decode(input.as_bytes()).decode_utf8_lossy(); + let domain = idna::domain_to_ascii(&domain)?; + if domain.find(|c| matches!(c, + '\0' | '\t' | '\n' | '\r' | ' ' | '#' | '%' | '/' | ':' | '?' | '@' | '[' | '\\' | ']' + )).is_some() { + return Err(ParseError::InvalidDomainCharacter) + } + if let Some(address) = parse_ipv4addr(&domain)? { + Ok(Host::Ipv4(address)) + } else { + Ok(Host::Domain(domain.into())) + } + } + + // <https://url.spec.whatwg.org/#concept-opaque-host-parser> + pub fn parse_opaque(input: &str) -> Result<Self, ParseError> { + if input.starts_with('[') { + if !input.ends_with(']') { + return Err(ParseError::InvalidIpv6Address) + } + return parse_ipv6addr(&input[1..input.len() - 1]).map(Host::Ipv6) + } + if input.find(|c| matches!(c, + '\0' | '\t' | '\n' | '\r' | ' ' | '#' | '/' | ':' | '?' | '@' | '[' | '\\' | ']' + )).is_some() { + return Err(ParseError::InvalidDomainCharacter) + } + let s = utf8_percent_encode(input, SIMPLE_ENCODE_SET).to_string(); + Ok(Host::Domain(s)) + } +} + +impl<S: AsRef<str>> fmt::Display for Host<S> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + Host::Domain(ref domain) => domain.as_ref().fmt(f), + Host::Ipv4(ref addr) => addr.fmt(f), + Host::Ipv6(ref addr) => { + f.write_str("[")?; + write_ipv6(addr, f)?; + f.write_str("]") + } + } + } +} + +/// This mostly exists because coherence rules don’t allow us to implement +/// `ToSocketAddrs for (Host<S>, u16)`. +#[derive(Clone, Debug)] +pub struct HostAndPort<S=String> { + pub host: Host<S>, + pub port: u16, +} + +impl<'a> HostAndPort<&'a str> { + /// Return a copy of `self` that owns an allocated `String` but does not borrow an `&Url`. + pub fn to_owned(&self) -> HostAndPort<String> { + HostAndPort { + host: self.host.to_owned(), + port: self.port + } + } +} + +impl<S: AsRef<str>> fmt::Display for HostAndPort<S> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.host.fmt(f)?; + f.write_str(":")?; + self.port.fmt(f) + } +} + + +impl<S: AsRef<str>> ToSocketAddrs for HostAndPort<S> { + type Iter = SocketAddrs; + + fn to_socket_addrs(&self) -> io::Result<Self::Iter> { + let port = self.port; + match self.host { + Host::Domain(ref domain) => Ok(SocketAddrs { + // FIXME: use std::net::lookup_host when it’s stable. + state: SocketAddrsState::Domain((domain.as_ref(), port).to_socket_addrs()?) + }), + Host::Ipv4(address) => Ok(SocketAddrs { + state: SocketAddrsState::One(SocketAddr::V4(SocketAddrV4::new(address, port))) + }), + Host::Ipv6(address) => Ok(SocketAddrs { + state: SocketAddrsState::One(SocketAddr::V6(SocketAddrV6::new(address, port, 0, 0))) + }), + } + } +} + +/// Socket addresses for an URL. +#[derive(Debug)] +pub struct SocketAddrs { + state: SocketAddrsState +} + +#[derive(Debug)] +enum SocketAddrsState { + Domain(vec::IntoIter<SocketAddr>), + One(SocketAddr), + Done, +} + +impl Iterator for SocketAddrs { + type Item = SocketAddr; + fn next(&mut self) -> Option<SocketAddr> { + match self.state { + SocketAddrsState::Domain(ref mut iter) => iter.next(), + SocketAddrsState::One(s) => { + self.state = SocketAddrsState::Done; + Some(s) + } + SocketAddrsState::Done => None + } + } +} + +fn write_ipv6(addr: &Ipv6Addr, f: &mut Formatter) -> fmt::Result { + let segments = addr.segments(); + let (compress_start, compress_end) = longest_zero_sequence(&segments); + let mut i = 0; + while i < 8 { + if i == compress_start { + f.write_str(":")?; + if i == 0 { + f.write_str(":")?; + } + if compress_end < 8 { + i = compress_end; + } else { + break; + } + } + write!(f, "{:x}", segments[i as usize])?; + if i < 7 { + f.write_str(":")?; + } + i += 1; + } + Ok(()) +} + +// https://url.spec.whatwg.org/#concept-ipv6-serializer step 2 and 3 +fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) { + let mut longest = -1; + let mut longest_length = -1; + let mut start = -1; + macro_rules! finish_sequence( + ($end: expr) => { + if start >= 0 { + let length = $end - start; + if length > longest_length { + longest = start; + longest_length = length; + } + } + }; + ); + for i in 0..8 { + if pieces[i as usize] == 0 { + if start < 0 { + start = i; + } + } else { + finish_sequence!(i); + start = -1; + } + } + finish_sequence!(8); + // https://url.spec.whatwg.org/#concept-ipv6-serializer + // step 3: ignore lone zeroes + if longest_length < 2 { + (-1, -2) + } else { + (longest, longest + longest_length) + } +} + +/// <https://url.spec.whatwg.org/#ipv4-number-parser> +fn parse_ipv4number(mut input: &str) -> Result<Option<u32>, ()> { + let mut r = 10; + if input.starts_with("0x") || input.starts_with("0X") { + input = &input[2..]; + r = 16; + } else if input.len() >= 2 && input.starts_with('0') { + input = &input[1..]; + r = 8; + } + + // At the moment we can't know the reason why from_str_radix fails + // https://github.com/rust-lang/rust/issues/22639 + // So instead we check if the input looks like a real number and only return + // an error when it's an overflow. + let valid_number = match r { + 8 => input.chars().all(|c| c >= '0' && c <='7'), + 10 => input.chars().all(|c| c >= '0' && c <='9'), + 16 => input.chars().all(|c| (c >= '0' && c <='9') || (c >='a' && c <= 'f') || (c >= 'A' && c <= 'F')), + _ => false + }; + + if !valid_number { + return Ok(None); + } + + if input.is_empty() { + return Ok(Some(0)); + } + if input.starts_with('+') { + return Ok(None); + } + match u32::from_str_radix(input, r) { + Ok(number) => Ok(Some(number)), + Err(_) => Err(()), + } +} + +/// <https://url.spec.whatwg.org/#concept-ipv4-parser> +fn parse_ipv4addr(input: &str) -> ParseResult<Option<Ipv4Addr>> { + if input.is_empty() { + return Ok(None) + } + let mut parts: Vec<&str> = input.split('.').collect(); + if parts.last() == Some(&"") { + parts.pop(); + } + if parts.len() > 4 { + return Ok(None); + } + let mut numbers: Vec<u32> = Vec::new(); + let mut overflow = false; + for part in parts { + if part == "" { + return Ok(None); + } + match parse_ipv4number(part) { + Ok(Some(n)) => numbers.push(n), + Ok(None) => return Ok(None), + Err(()) => overflow = true + }; + } + if overflow { + return Err(ParseError::InvalidIpv4Address); + } + let mut ipv4 = numbers.pop().expect("a non-empty list of numbers"); + // Equivalent to: ipv4 >= 256 ** (4 − numbers.len()) + if ipv4 > u32::max_value() >> (8 * numbers.len() as u32) { + return Err(ParseError::InvalidIpv4Address); + } + if numbers.iter().any(|x| *x > 255) { + return Err(ParseError::InvalidIpv4Address); + } + for (counter, n) in numbers.iter().enumerate() { + ipv4 += n << (8 * (3 - counter as u32)) + } + Ok(Some(Ipv4Addr::from(ipv4))) +} + +/// <https://url.spec.whatwg.org/#concept-ipv6-parser> +fn parse_ipv6addr(input: &str) -> ParseResult<Ipv6Addr> { + let input = input.as_bytes(); + let len = input.len(); + let mut is_ip_v4 = false; + let mut pieces = [0, 0, 0, 0, 0, 0, 0, 0]; + let mut piece_pointer = 0; + let mut compress_pointer = None; + let mut i = 0; + + if len < 2 { + return Err(ParseError::InvalidIpv6Address) + } + + if input[0] == b':' { + if input[1] != b':' { + return Err(ParseError::InvalidIpv6Address) + } + i = 2; + piece_pointer = 1; + compress_pointer = Some(1); + } + + while i < len { + if piece_pointer == 8 { + return Err(ParseError::InvalidIpv6Address) + } + if input[i] == b':' { + if compress_pointer.is_some() { + return Err(ParseError::InvalidIpv6Address) + } + i += 1; + piece_pointer += 1; + compress_pointer = Some(piece_pointer); + continue + } + let start = i; + let end = cmp::min(len, start + 4); + let mut value = 0u16; + while i < end { + match (input[i] as char).to_digit(16) { + Some(digit) => { + value = value * 0x10 + digit as u16; + i += 1; + }, + None => break + } + } + if i < len { + match input[i] { + b'.' => { + if i == start { + return Err(ParseError::InvalidIpv6Address) + } + i = start; + if piece_pointer > 6 { + return Err(ParseError::InvalidIpv6Address) + } + is_ip_v4 = true; + }, + b':' => { + i += 1; + if i == len { + return Err(ParseError::InvalidIpv6Address) + } + }, + _ => return Err(ParseError::InvalidIpv6Address) + } + } + if is_ip_v4 { + break + } + pieces[piece_pointer] = value; + piece_pointer += 1; + } + + if is_ip_v4 { + if piece_pointer > 6 { + return Err(ParseError::InvalidIpv6Address) + } + let mut numbers_seen = 0; + while i < len { + if numbers_seen > 0 { + if numbers_seen < 4 && (i < len && input[i] == b'.') { + i += 1 + } else { + return Err(ParseError::InvalidIpv6Address) + } + } + + let mut ipv4_piece = None; + while i < len { + let digit = match input[i] { + c @ b'0' ... b'9' => c - b'0', + _ => break + }; + match ipv4_piece { + None => ipv4_piece = Some(digit as u16), + Some(0) => return Err(ParseError::InvalidIpv6Address), // No leading zero + Some(ref mut v) => { + *v = *v * 10 + digit as u16; + if *v > 255 { + return Err(ParseError::InvalidIpv6Address) + } + } + } + i += 1; + } + + pieces[piece_pointer] = if let Some(v) = ipv4_piece { + pieces[piece_pointer] * 0x100 + v + } else { + return Err(ParseError::InvalidIpv6Address) + }; + numbers_seen += 1; + + if numbers_seen == 2 || numbers_seen == 4 { + piece_pointer += 1; + } + } + + if numbers_seen != 4 { + return Err(ParseError::InvalidIpv6Address) + } + } + + if i < len { + return Err(ParseError::InvalidIpv6Address) + } + + match compress_pointer { + Some(compress_pointer) => { + let mut swaps = piece_pointer - compress_pointer; + piece_pointer = 7; + while swaps > 0 { + pieces.swap(piece_pointer, compress_pointer + swaps - 1); + swaps -= 1; + piece_pointer -= 1; + } + } + _ => if piece_pointer != 8 { + return Err(ParseError::InvalidIpv6Address) + } + } + Ok(Ipv6Addr::new(pieces[0], pieces[1], pieces[2], pieces[3], + pieces[4], pieces[5], pieces[6], pieces[7])) +} diff --git a/url/src/lib.rs b/url/src/lib.rs new file mode 100644 index 000000000..dbcd06405 --- /dev/null +++ b/url/src/lib.rs @@ -0,0 +1,2482 @@ +// Copyright 2013-2015 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +rust-url is an implementation of the [URL Standard](http://url.spec.whatwg.org/) +for the [Rust](http://rust-lang.org/) programming language. + + +# URL parsing and data structures + +First, URL parsing may fail for various reasons and therefore returns a `Result`. + +``` +use url::{Url, ParseError}; + +assert!(Url::parse("http://[:::1]") == Err(ParseError::InvalidIpv6Address)) +``` + +Let’s parse a valid URL and look at its components. + +``` +use url::{Url, Host}; +# use url::ParseError; +# fn run() -> Result<(), ParseError> { +let issue_list_url = Url::parse( + "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open" +)?; + + +assert!(issue_list_url.scheme() == "https"); +assert!(issue_list_url.username() == ""); +assert!(issue_list_url.password() == None); +assert!(issue_list_url.host_str() == Some("github.com")); +assert!(issue_list_url.host() == Some(Host::Domain("github.com"))); +assert!(issue_list_url.port() == None); +assert!(issue_list_url.path() == "/rust-lang/rust/issues"); +assert!(issue_list_url.path_segments().map(|c| c.collect::<Vec<_>>()) == + Some(vec!["rust-lang", "rust", "issues"])); +assert!(issue_list_url.query() == Some("labels=E-easy&state=open")); +assert!(issue_list_url.fragment() == None); +assert!(!issue_list_url.cannot_be_a_base()); +# Ok(()) +# } +# run().unwrap(); +``` + +Some URLs are said to be *cannot-be-a-base*: +they don’t have a username, password, host, or port, +and their "path" is an arbitrary string rather than slash-separated segments: + +``` +use url::Url; +# use url::ParseError; + +# fn run() -> Result<(), ParseError> { +let data_url = Url::parse("data:text/plain,Hello?World#")?; + +assert!(data_url.cannot_be_a_base()); +assert!(data_url.scheme() == "data"); +assert!(data_url.path() == "text/plain,Hello"); +assert!(data_url.path_segments().is_none()); +assert!(data_url.query() == Some("World")); +assert!(data_url.fragment() == Some("")); +# Ok(()) +# } +# run().unwrap(); +``` + + +# Base URL + +Many contexts allow URL *references* that can be relative to a *base URL*: + +```html +<link rel="stylesheet" href="../main.css"> +``` + +Since parsed URL are absolute, giving a base is required for parsing relative URLs: + +``` +use url::{Url, ParseError}; + +assert!(Url::parse("../main.css") == Err(ParseError::RelativeUrlWithoutBase)) +``` + +Use the `join` method on an `Url` to use it as a base URL: + +``` +use url::Url; +# use url::ParseError; + +# fn run() -> Result<(), ParseError> { +let this_document = Url::parse("http://servo.github.io/rust-url/url/index.html")?; +let css_url = this_document.join("../main.css")?; +assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css"); +# Ok(()) +# } +# run().unwrap(); +*/ + +#![doc(html_root_url = "https://docs.rs/url/1.7.0")] + +#[cfg(feature="rustc-serialize")] extern crate rustc_serialize; +#[macro_use] extern crate matches; +#[cfg(feature="serde")] extern crate serde; +#[cfg(feature="heapsize")] #[macro_use] extern crate heapsize; + +pub extern crate idna; +#[macro_use] +pub extern crate percent_encoding; + +use encoding::EncodingOverride; +#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf; +use host::HostInternal; +use parser::{Parser, Context, SchemeType, to_u32, ViolationFn}; +use percent_encoding::{PATH_SEGMENT_ENCODE_SET, USERINFO_ENCODE_SET, + percent_encode, percent_decode, utf8_percent_encode}; +use std::borrow::Borrow; +use std::cmp; +#[cfg(feature = "serde")] use std::error::Error; +use std::fmt::{self, Write, Debug, Formatter}; +use std::hash; +use std::io; +use std::mem; +use std::net::{ToSocketAddrs, IpAddr}; +use std::ops::{Range, RangeFrom, RangeTo}; +use std::path::{Path, PathBuf}; +use std::str; + +pub use origin::{Origin, OpaqueOrigin}; +pub use host::{Host, HostAndPort, SocketAddrs}; +pub use path_segments::PathSegmentsMut; +pub use parser::{ParseError, SyntaxViolation}; +pub use slicing::Position; + +mod encoding; +mod host; +mod origin; +mod path_segments; +mod parser; +mod slicing; + +pub mod form_urlencoded; +#[doc(hidden)] pub mod quirks; + +/// A parsed URL record. +#[derive(Clone)] +pub struct Url { + /// Syntax in pseudo-BNF: + /// + /// url = scheme ":" [ hierarchical | non-hierarchical ] [ "?" query ]? [ "#" fragment ]? + /// non-hierarchical = non-hierarchical-path + /// non-hierarchical-path = /* Does not start with "/" */ + /// hierarchical = authority? hierarchical-path + /// authority = "//" userinfo? host [ ":" port ]? + /// userinfo = username [ ":" password ]? "@" + /// hierarchical-path = [ "/" path-segment ]+ + serialization: String, + + // Components + scheme_end: u32, // Before ':' + username_end: u32, // Before ':' (if a password is given) or '@' (if not) + host_start: u32, + host_end: u32, + host: HostInternal, + port: Option<u16>, + path_start: u32, // Before initial '/', if any + query_start: Option<u32>, // Before '?', unlike Position::QueryStart + fragment_start: Option<u32>, // Before '#', unlike Position::FragmentStart +} + +#[cfg(feature = "heapsize")] +impl HeapSizeOf for Url { + fn heap_size_of_children(&self) -> usize { + self.serialization.heap_size_of_children() + } +} + +/// Full configuration for the URL parser. +#[derive(Copy, Clone)] +pub struct ParseOptions<'a> { + base_url: Option<&'a Url>, + encoding_override: encoding::EncodingOverride, + violation_fn: ViolationFn<'a>, +} + +impl<'a> ParseOptions<'a> { + /// Change the base URL + pub fn base_url(mut self, new: Option<&'a Url>) -> Self { + self.base_url = new; + self + } + + /// Override the character encoding of query strings. + /// This is a legacy concept only relevant for HTML. + /// + /// `EncodingRef` is defined in [rust-encoding](https://github.com/lifthrasiir/rust-encoding). + /// + /// This method is only available if the `query_encoding` + /// [feature](http://doc.crates.io/manifest.html#the-features-section]) is enabled. + #[cfg(feature = "query_encoding")] + pub fn encoding_override(mut self, new: Option<encoding::EncodingRef>) -> Self { + self.encoding_override = EncodingOverride::from_opt_encoding(new).to_output_encoding(); + self + } + + /// Call the provided function or closure on non-fatal parse errors, passing + /// a static string description. This method is deprecated in favor of + /// `syntax_violation_callback` and is implemented as an adaptor for the + /// latter, passing the `SyntaxViolation` description. Only the last value + /// passed to either method will be used by a parser. + #[deprecated] + pub fn log_syntax_violation(mut self, new: Option<&'a Fn(&'static str)>) -> Self { + self.violation_fn = match new { + Some(f) => ViolationFn::OldFn(f), + None => ViolationFn::NoOp + }; + self + } + + /// Call the provided function or closure for a non-fatal `SyntaxViolation` + /// when it occurs during parsing. Note that since the provided function is + /// `Fn`, the caller might need to utilize _interior mutability_, such as with + /// a `RefCell`, to collect the violations. + /// + /// ## Example + /// ``` + /// use std::cell::RefCell; + /// use url::{Url, SyntaxViolation}; + /// # use url::ParseError; + /// # fn run() -> Result<(), url::ParseError> { + /// let violations = RefCell::new(Vec::new()); + /// let url = Url::options() + /// .syntax_violation_callback(Some(&|v| violations.borrow_mut().push(v))) + /// .parse("https:////example.com")?; + /// assert_eq!(url.as_str(), "https://example.com/"); + /// assert_eq!(violations.into_inner(), + /// vec!(SyntaxViolation::ExpectedDoubleSlash)); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn syntax_violation_callback(mut self, new: Option<&'a Fn(SyntaxViolation)>) -> Self { + self.violation_fn = match new { + Some(f) => ViolationFn::NewFn(f), + None => ViolationFn::NoOp + }; + self + } + + /// Parse an URL string with the configuration so far. + pub fn parse(self, input: &str) -> Result<Url, ::ParseError> { + Parser { + serialization: String::with_capacity(input.len()), + base_url: self.base_url, + query_encoding_override: self.encoding_override, + violation_fn: self.violation_fn, + context: Context::UrlParser, + }.parse_url(input) + } +} + +impl<'a> Debug for ParseOptions<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, + "ParseOptions {{ base_url: {:?}, encoding_override: {:?}, \ + violation_fn: {:?} }}", + self.base_url, + self.encoding_override, + self.violation_fn) + } +} + +impl Url { + /// Parse an absolute URL from a string. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.net")?; + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// # Errors + /// + /// If the function can not parse an absolute URL from the given string, + /// a [`ParseError`] variant will be returned. + /// + /// [`ParseError`]: enum.ParseError.html + #[inline] + pub fn parse(input: &str) -> Result<Url, ::ParseError> { + Url::options().parse(input) + } + + /// Parse an absolute URL from a string and add params to its query string. + /// + /// Existing params are not removed. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse_with_params("https://example.net?dont=clobberme", + /// &[("lang", "rust"), ("browser", "servo")])?; + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// # Errors + /// + /// If the function can not parse an absolute URL from the given string, + /// a [`ParseError`] variant will be returned. + /// + /// [`ParseError`]: enum.ParseError.html + #[inline] + pub fn parse_with_params<I, K, V>(input: &str, iter: I) -> Result<Url, ::ParseError> + where I: IntoIterator, + I::Item: Borrow<(K, V)>, + K: AsRef<str>, + V: AsRef<str> + { + let mut url = Url::options().parse(input); + + if let Ok(ref mut url) = url { + url.query_pairs_mut().extend_pairs(iter); + } + + url + } + + /// Parse a string as an URL, with this URL as the base URL. + /// + /// Note: a trailing slash is significant. + /// Without it, the last path component is considered to be a “file” name + /// to be removed to get at the “directory” that is used as the base: + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let base = Url::parse("https://example.net/a/b.html")?; + /// let url = base.join("c.png")?; + /// assert_eq!(url.as_str(), "https://example.net/a/c.png"); // Not /a/b.html/c.png + /// + /// let base = Url::parse("https://example.net/a/b/")?; + /// let url = base.join("c.png")?; + /// assert_eq!(url.as_str(), "https://example.net/a/b/c.png"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// # Errors + /// + /// If the function can not parse an URL from the given string + /// with this URL as the base URL, a [`ParseError`] variant will be returned. + /// + /// [`ParseError`]: enum.ParseError.html + #[inline] + pub fn join(&self, input: &str) -> Result<Url, ::ParseError> { + Url::options().base_url(Some(self)).parse(input) + } + + /// Return a default `ParseOptions` that can fully configure the URL parser. + /// + /// # Examples + /// + /// Get default `ParseOptions`, then change base url + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// # fn run() -> Result<(), ParseError> { + /// let options = Url::options(); + /// let api = Url::parse("https://api.example.com")?; + /// let base_url = options.base_url(Some(&api)); + /// let version_url = base_url.parse("version.json")?; + /// assert_eq!(version_url.as_str(), "https://api.example.com/version.json"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn options<'a>() -> ParseOptions<'a> { + ParseOptions { + base_url: None, + encoding_override: EncodingOverride::utf8(), + violation_fn: ViolationFn::NoOp, + } + } + + /// Return the serialization of this URL. + /// + /// This is fast since that serialization is already stored in the `Url` struct. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url_str = "https://example.net/"; + /// let url = Url::parse(url_str)?; + /// assert_eq!(url.as_str(), url_str); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn as_str(&self) -> &str { + &self.serialization + } + + /// Return the serialization of this URL. + /// + /// This consumes the `Url` and takes ownership of the `String` stored in it. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url_str = "https://example.net/"; + /// let url = Url::parse(url_str)?; + /// assert_eq!(url.into_string(), url_str); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn into_string(self) -> String { + self.serialization + } + + /// For internal testing, not part of the public API. + /// + /// Methods of the `Url` struct assume a number of invariants. + /// This checks each of these invariants and panic if one is not met. + /// This is for testing rust-url itself. + #[doc(hidden)] + pub fn check_invariants(&self) -> Result<(), String> { + macro_rules! assert { + ($x: expr) => { + if !$x { + return Err(format!("!( {} ) for URL {:?}", + stringify!($x), self.serialization)) + } + } + } + + macro_rules! assert_eq { + ($a: expr, $b: expr) => { + { + let a = $a; + let b = $b; + if a != b { + return Err(format!("{:?} != {:?} ({} != {}) for URL {:?}", + a, b, stringify!($a), stringify!($b), + self.serialization)) + } + } + } + } + + assert!(self.scheme_end >= 1); + assert!(matches!(self.byte_at(0), b'a'...b'z' | b'A'...b'Z')); + assert!(self.slice(1..self.scheme_end).chars() + .all(|c| matches!(c, 'a'...'z' | 'A'...'Z' | '0'...'9' | '+' | '-' | '.'))); + assert_eq!(self.byte_at(self.scheme_end), b':'); + + if self.slice(self.scheme_end + 1 ..).starts_with("//") { + // URL with authority + match self.byte_at(self.username_end) { + b':' => { + assert!(self.host_start >= self.username_end + 2); + assert_eq!(self.byte_at(self.host_start - 1), b'@'); + } + b'@' => assert!(self.host_start == self.username_end + 1), + _ => assert_eq!(self.username_end, self.scheme_end + 3), + } + assert!(self.host_start >= self.username_end); + assert!(self.host_end >= self.host_start); + let host_str = self.slice(self.host_start..self.host_end); + match self.host { + HostInternal::None => assert_eq!(host_str, ""), + HostInternal::Ipv4(address) => assert_eq!(host_str, address.to_string()), + HostInternal::Ipv6(address) => { + let h: Host<String> = Host::Ipv6(address); + assert_eq!(host_str, h.to_string()) + } + HostInternal::Domain => { + if SchemeType::from(self.scheme()).is_special() { + assert!(!host_str.is_empty()) + } + } + } + if self.path_start == self.host_end { + assert_eq!(self.port, None); + } else { + assert_eq!(self.byte_at(self.host_end), b':'); + let port_str = self.slice(self.host_end + 1..self.path_start); + assert_eq!(self.port, Some(port_str.parse::<u16>().expect("Couldn't parse port?"))); + } + assert_eq!(self.byte_at(self.path_start), b'/'); + } else { + // Anarchist URL (no authority) + assert_eq!(self.username_end, self.scheme_end + 1); + assert_eq!(self.host_start, self.scheme_end + 1); + assert_eq!(self.host_end, self.scheme_end + 1); + assert_eq!(self.host, HostInternal::None); + assert_eq!(self.port, None); + assert_eq!(self.path_start, self.scheme_end + 1); + } + if let Some(start) = self.query_start { + assert!(start > self.path_start); + assert_eq!(self.byte_at(start), b'?'); + } + if let Some(start) = self.fragment_start { + assert!(start > self.path_start); + assert_eq!(self.byte_at(start), b'#'); + } + if let (Some(query_start), Some(fragment_start)) = (self.query_start, self.fragment_start) { + assert!(fragment_start > query_start); + } + + let other = Url::parse(self.as_str()).expect("Failed to parse myself?"); + assert_eq!(&self.serialization, &other.serialization); + assert_eq!(self.scheme_end, other.scheme_end); + assert_eq!(self.username_end, other.username_end); + assert_eq!(self.host_start, other.host_start); + assert_eq!(self.host_end, other.host_end); + assert!(self.host == other.host || + // XXX No host round-trips to empty host. + // See https://github.com/whatwg/url/issues/79 + (self.host_str(), other.host_str()) == (None, Some(""))); + assert_eq!(self.port, other.port); + assert_eq!(self.path_start, other.path_start); + assert_eq!(self.query_start, other.query_start); + assert_eq!(self.fragment_start, other.fragment_start); + Ok(()) + } + + /// Return the origin of this URL (<https://url.spec.whatwg.org/#origin>) + /// + /// Note: this returns an opaque origin for `file:` URLs, which causes + /// `url.origin() != url.origin()`. + /// + /// # Examples + /// + /// URL with `ftp` scheme: + /// + /// ```rust + /// use url::{Host, Origin, Url}; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://example.com/foo")?; + /// assert_eq!(url.origin(), + /// Origin::Tuple("ftp".into(), + /// Host::Domain("example.com".into()), + /// 21)); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// URL with `blob` scheme: + /// + /// ```rust + /// use url::{Host, Origin, Url}; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("blob:https://example.com/foo")?; + /// assert_eq!(url.origin(), + /// Origin::Tuple("https".into(), + /// Host::Domain("example.com".into()), + /// 443)); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// URL with `file` scheme: + /// + /// ```rust + /// use url::{Host, Origin, Url}; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("file:///tmp/foo")?; + /// assert!(!url.origin().is_tuple()); + /// + /// let other_url = Url::parse("file:///tmp/foo")?; + /// assert!(url.origin() != other_url.origin()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// URL with other scheme: + /// + /// ```rust + /// use url::{Host, Origin, Url}; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("foo:bar")?; + /// assert!(!url.origin().is_tuple()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn origin(&self) -> Origin { + origin::url_origin(self) + } + + /// Return the scheme of this URL, lower-cased, as an ASCII string without the ':' delimiter. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("file:///tmp/foo")?; + /// assert_eq!(url.scheme(), "file"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn scheme(&self) -> &str { + self.slice(..self.scheme_end) + } + + /// Return whether the URL has an 'authority', + /// which can contain a username, password, host, and port number. + /// + /// URLs that do *not* are either path-only like `unix:/run/foo.socket` + /// or cannot-be-a-base like `data:text/plain,Stuff`. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert!(url.has_authority()); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert!(!url.has_authority()); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert!(!url.has_authority()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn has_authority(&self) -> bool { + debug_assert!(self.byte_at(self.scheme_end) == b':'); + self.slice(self.scheme_end..).starts_with("://") + } + + /// Return whether this URL is a cannot-be-a-base URL, + /// meaning that parsing a relative URL string with this URL as the base will return an error. + /// + /// This is the case if the scheme and `:` delimiter are not followed by a `/` slash, + /// as is typically the case of `data:` and `mailto:` URLs. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert!(!url.cannot_be_a_base()); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert!(!url.cannot_be_a_base()); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert!(url.cannot_be_a_base()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn cannot_be_a_base(&self) -> bool { + !self.slice(self.path_start..).starts_with('/') + } + + /// Return the username for this URL (typically the empty string) + /// as a percent-encoded ASCII string. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert_eq!(url.username(), "rms"); + /// + /// let url = Url::parse("ftp://:secret123@example.com")?; + /// assert_eq!(url.username(), ""); + /// + /// let url = Url::parse("https://example.com")?; + /// assert_eq!(url.username(), ""); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn username(&self) -> &str { + if self.has_authority() { + self.slice(self.scheme_end + ("://".len() as u32)..self.username_end) + } else { + "" + } + } + + /// Return the password for this URL, if any, as a percent-encoded ASCII string. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms:secret123@example.com")?; + /// assert_eq!(url.password(), Some("secret123")); + /// + /// let url = Url::parse("ftp://:secret123@example.com")?; + /// assert_eq!(url.password(), Some("secret123")); + /// + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert_eq!(url.password(), None); + /// + /// let url = Url::parse("https://example.com")?; + /// assert_eq!(url.password(), None); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn password(&self) -> Option<&str> { + // This ':' is not the one marking a port number since a host can not be empty. + // (Except for file: URLs, which do not have port numbers.) + if self.has_authority() && self.byte_at(self.username_end) == b':' { + debug_assert!(self.byte_at(self.host_start - 1) == b'@'); + Some(self.slice(self.username_end + 1..self.host_start - 1)) + } else { + None + } + } + + /// Equivalent to `url.host().is_some()`. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert!(url.has_host()); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert!(!url.has_host()); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert!(!url.has_host()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn has_host(&self) -> bool { + !matches!(self.host, HostInternal::None) + } + + /// Return the string representation of the host (domain or IP address) for this URL, if any. + /// + /// Non-ASCII domains are punycode-encoded per IDNA. + /// IPv6 addresses are given between `[` and `]` brackets. + /// + /// Cannot-be-a-base URLs (typical of `data:` and `mailto:`) and some `file:` URLs + /// don’t have a host. + /// + /// See also the `host` method. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://127.0.0.1/index.html")?; + /// assert_eq!(url.host_str(), Some("127.0.0.1")); + /// + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert_eq!(url.host_str(), Some("example.com")); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert_eq!(url.host_str(), None); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert_eq!(url.host_str(), None); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn host_str(&self) -> Option<&str> { + if self.has_host() { + Some(self.slice(self.host_start..self.host_end)) + } else { + None + } + } + + /// Return the parsed representation of the host for this URL. + /// Non-ASCII domain labels are punycode-encoded per IDNA. + /// + /// Cannot-be-a-base URLs (typical of `data:` and `mailto:`) and some `file:` URLs + /// don’t have a host. + /// + /// See also the `host_str` method. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://127.0.0.1/index.html")?; + /// assert!(url.host().is_some()); + /// + /// let url = Url::parse("ftp://rms@example.com")?; + /// assert!(url.host().is_some()); + /// + /// let url = Url::parse("unix:/run/foo.socket")?; + /// assert!(url.host().is_none()); + /// + /// let url = Url::parse("data:text/plain,Stuff")?; + /// assert!(url.host().is_none()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn host(&self) -> Option<Host<&str>> { + match self.host { + HostInternal::None => None, + HostInternal::Domain => Some(Host::Domain(self.slice(self.host_start..self.host_end))), + HostInternal::Ipv4(address) => Some(Host::Ipv4(address)), + HostInternal::Ipv6(address) => Some(Host::Ipv6(address)), + } + } + + /// If this URL has a host and it is a domain name (not an IP address), return it. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://127.0.0.1/")?; + /// assert_eq!(url.domain(), None); + /// + /// let url = Url::parse("mailto:rms@example.net")?; + /// assert_eq!(url.domain(), None); + /// + /// let url = Url::parse("https://example.com/")?; + /// assert_eq!(url.domain(), Some("example.com")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn domain(&self) -> Option<&str> { + match self.host { + HostInternal::Domain => Some(self.slice(self.host_start..self.host_end)), + _ => None, + } + } + + /// Return the port number for this URL, if any. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.com")?; + /// assert_eq!(url.port(), None); + /// + /// let url = Url::parse("ssh://example.com:22")?; + /// assert_eq!(url.port(), Some(22)); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn port(&self) -> Option<u16> { + self.port + } + + /// Return the port number for this URL, or the default port number if it is known. + /// + /// This method only knows the default port number + /// of the `http`, `https`, `ws`, `wss`, `ftp`, and `gopher` schemes. + /// + /// For URLs in these schemes, this method always returns `Some(_)`. + /// For other schemes, it is the same as `Url::port()`. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("foo://example.com")?; + /// assert_eq!(url.port_or_known_default(), None); + /// + /// let url = Url::parse("foo://example.com:1456")?; + /// assert_eq!(url.port_or_known_default(), Some(1456)); + /// + /// let url = Url::parse("https://example.com")?; + /// assert_eq!(url.port_or_known_default(), Some(443)); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + #[inline] + pub fn port_or_known_default(&self) -> Option<u16> { + self.port.or_else(|| parser::default_port(self.scheme())) + } + + /// If the URL has a host, return something that implements `ToSocketAddrs`. + /// + /// If the URL has no port number and the scheme’s default port number is not known + /// (see `Url::port_or_known_default`), + /// the closure is called to obtain a port number. + /// Typically, this closure can match on the result `Url::scheme` + /// to have per-scheme default port numbers, + /// and panic for schemes it’s not prepared to handle. + /// For example: + /// + /// ```rust + /// # use url::Url; + /// # use std::net::TcpStream; + /// # use std::io; + /// fn connect(url: &Url) -> io::Result<TcpStream> { + /// TcpStream::connect(url.with_default_port(default_port)?) + /// } + /// + /// fn default_port(url: &Url) -> Result<u16, ()> { + /// match url.scheme() { + /// "git" => Ok(9418), + /// "git+ssh" => Ok(22), + /// "git+https" => Ok(443), + /// "git+http" => Ok(80), + /// _ => Err(()), + /// } + /// } + /// ``` + pub fn with_default_port<F>(&self, f: F) -> io::Result<HostAndPort<&str>> + where F: FnOnce(&Url) -> Result<u16, ()> { + Ok(HostAndPort { + host: self.host() + .ok_or(()) + .or_else(|()| io_error("URL has no host"))?, + port: self.port_or_known_default() + .ok_or(()) + .or_else(|()| f(self)) + .or_else(|()| io_error("URL has no port number"))? + }) + } + + /// Return the path for this URL, as a percent-encoded ASCII string. + /// For cannot-be-a-base URLs, this is an arbitrary string that doesn’t start with '/'. + /// For other URLs, this starts with a '/' slash + /// and continues with slash-separated path segments. + /// + /// # Examples + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.com/api/versions?page=2")?; + /// assert_eq!(url.path(), "/api/versions"); + /// + /// let url = Url::parse("https://example.com")?; + /// assert_eq!(url.path(), "/"); + /// + /// let url = Url::parse("https://example.com/countries/việt nam")?; + /// assert_eq!(url.path(), "/countries/vi%E1%BB%87t%20nam"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn path(&self) -> &str { + match (self.query_start, self.fragment_start) { + (None, None) => self.slice(self.path_start..), + (Some(next_component_start), _) | + (None, Some(next_component_start)) => { + self.slice(self.path_start..next_component_start) + } + } + } + + /// Unless this URL is cannot-be-a-base, + /// return an iterator of '/' slash-separated path segments, + /// each as a percent-encoded ASCII string. + /// + /// Return `None` for cannot-be-a-base URLs. + /// + /// When `Some` is returned, the iterator always contains at least one string + /// (which may be empty). + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let url = Url::parse("https://example.com/foo/bar")?; + /// let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?; + /// assert_eq!(path_segments.next(), Some("foo")); + /// assert_eq!(path_segments.next(), Some("bar")); + /// assert_eq!(path_segments.next(), None); + /// + /// let url = Url::parse("https://example.com")?; + /// let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?; + /// assert_eq!(path_segments.next(), Some("")); + /// assert_eq!(path_segments.next(), None); + /// + /// let url = Url::parse("data:text/plain,HelloWorld")?; + /// assert!(url.path_segments().is_none()); + /// + /// let url = Url::parse("https://example.com/countries/việt nam")?; + /// let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?; + /// assert_eq!(path_segments.next(), Some("countries")); + /// assert_eq!(path_segments.next(), Some("vi%E1%BB%87t%20nam")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn path_segments(&self) -> Option<str::Split<char>> { + let path = self.path(); + if path.starts_with('/') { + Some(path[1..].split('/')) + } else { + None + } + } + + /// Return this URL’s query string, if any, as a percent-encoded ASCII string. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.com/products?page=2")?; + /// let query = url.query(); + /// assert_eq!(query, Some("page=2")); + /// + /// let url = Url::parse("https://example.com/products")?; + /// let query = url.query(); + /// assert!(query.is_none()); + /// + /// let url = Url::parse("https://example.com/?country=español")?; + /// let query = url.query(); + /// assert_eq!(query, Some("country=espa%C3%B1ol")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn query(&self) -> Option<&str> { + match (self.query_start, self.fragment_start) { + (None, _) => None, + (Some(query_start), None) => { + debug_assert!(self.byte_at(query_start) == b'?'); + Some(self.slice(query_start + 1..)) + } + (Some(query_start), Some(fragment_start)) => { + debug_assert!(self.byte_at(query_start) == b'?'); + Some(self.slice(query_start + 1..fragment_start)) + } + } + } + + /// Parse the URL’s query string, if any, as `application/x-www-form-urlencoded` + /// and return an iterator of (key, value) pairs. + /// + /// # Examples + /// + /// ```rust + /// use std::borrow::Cow; + /// + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.com/products?page=2&sort=desc")?; + /// let mut pairs = url.query_pairs(); + /// + /// assert_eq!(pairs.count(), 2); + /// + /// assert_eq!(pairs.next(), Some((Cow::Borrowed("page"), Cow::Borrowed("2")))); + /// assert_eq!(pairs.next(), Some((Cow::Borrowed("sort"), Cow::Borrowed("desc")))); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// + + #[inline] + pub fn query_pairs(&self) -> form_urlencoded::Parse { + form_urlencoded::parse(self.query().unwrap_or("").as_bytes()) + } + + /// Return this URL’s fragment identifier, if any. + /// + /// A fragment is the part of the URL after the `#` symbol. + /// The fragment is optional and, if present, contains a fragment identifier + /// that identifies a secondary resource, such as a section heading + /// of a document. + /// + /// In HTML, the fragment identifier is usually the id attribute of a an element + /// that is scrolled to on load. Browsers typically will not send the fragment portion + /// of a URL to the server. + /// + /// **Note:** the parser did *not* percent-encode this component, + /// but the input may have been percent-encoded already. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let url = Url::parse("https://example.com/data.csv#row=4")?; + /// + /// assert_eq!(url.fragment(), Some("row=4")); + /// + /// let url = Url::parse("https://example.com/data.csv#cell=4,1-6,2")?; + /// + /// assert_eq!(url.fragment(), Some("cell=4,1-6,2")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn fragment(&self) -> Option<&str> { + self.fragment_start.map(|start| { + debug_assert!(self.byte_at(start) == b'#'); + self.slice(start + 1..) + }) + } + + fn mutate<F: FnOnce(&mut Parser) -> R, R>(&mut self, f: F) -> R { + let mut parser = Parser::for_setter(mem::replace(&mut self.serialization, String::new())); + let result = f(&mut parser); + self.serialization = parser.serialization; + result + } + + /// Change this URL’s fragment identifier. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.com/data.csv")?; + /// assert_eq!(url.as_str(), "https://example.com/data.csv"); + + /// url.set_fragment(Some("cell=4,1-6,2")); + /// assert_eq!(url.as_str(), "https://example.com/data.csv#cell=4,1-6,2"); + /// assert_eq!(url.fragment(), Some("cell=4,1-6,2")); + /// + /// url.set_fragment(None); + /// assert_eq!(url.as_str(), "https://example.com/data.csv"); + /// assert!(url.fragment().is_none()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_fragment(&mut self, fragment: Option<&str>) { + // Remove any previous fragment + if let Some(start) = self.fragment_start { + debug_assert!(self.byte_at(start) == b'#'); + self.serialization.truncate(start as usize); + } + // Write the new one + if let Some(input) = fragment { + self.fragment_start = Some(to_u32(self.serialization.len()).unwrap()); + self.serialization.push('#'); + self.mutate(|parser| parser.parse_fragment(parser::Input::new(input))) + } else { + self.fragment_start = None + } + } + + fn take_fragment(&mut self) -> Option<String> { + self.fragment_start.take().map(|start| { + debug_assert!(self.byte_at(start) == b'#'); + let fragment = self.slice(start + 1..).to_owned(); + self.serialization.truncate(start as usize); + fragment + }) + } + + fn restore_already_parsed_fragment(&mut self, fragment: Option<String>) { + if let Some(ref fragment) = fragment { + assert!(self.fragment_start.is_none()); + self.fragment_start = Some(to_u32(self.serialization.len()).unwrap()); + self.serialization.push('#'); + self.serialization.push_str(fragment); + } + } + + /// Change this URL’s query string. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.com/products")?; + /// assert_eq!(url.as_str(), "https://example.com/products"); + /// + /// url.set_query(Some("page=2")); + /// assert_eq!(url.as_str(), "https://example.com/products?page=2"); + /// assert_eq!(url.query(), Some("page=2")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_query(&mut self, query: Option<&str>) { + let fragment = self.take_fragment(); + + // Remove any previous query + if let Some(start) = self.query_start.take() { + debug_assert!(self.byte_at(start) == b'?'); + self.serialization.truncate(start as usize); + } + // Write the new query, if any + if let Some(input) = query { + self.query_start = Some(to_u32(self.serialization.len()).unwrap()); + self.serialization.push('?'); + let scheme_end = self.scheme_end; + self.mutate(|parser| parser.parse_query(scheme_end, parser::Input::new(input))); + } + + self.restore_already_parsed_fragment(fragment); + } + + /// Manipulate this URL’s query string, viewed as a sequence of name/value pairs + /// in `application/x-www-form-urlencoded` syntax. + /// + /// The return value has a method-chaining API: + /// + /// ```rust + /// # use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.net?lang=fr#nav")?; + /// assert_eq!(url.query(), Some("lang=fr")); + /// + /// url.query_pairs_mut().append_pair("foo", "bar"); + /// assert_eq!(url.query(), Some("lang=fr&foo=bar")); + /// assert_eq!(url.as_str(), "https://example.net/?lang=fr&foo=bar#nav"); + /// + /// url.query_pairs_mut() + /// .clear() + /// .append_pair("foo", "bar & baz") + /// .append_pair("saisons", "\u{00C9}t\u{00E9}+hiver"); + /// assert_eq!(url.query(), Some("foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver")); + /// assert_eq!(url.as_str(), + /// "https://example.net/?foo=bar+%26+baz&saisons=%C3%89t%C3%A9%2Bhiver#nav"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Note: `url.query_pairs_mut().clear();` is equivalent to `url.set_query(Some(""))`, + /// not `url.set_query(None)`. + /// + /// The state of `Url` is unspecified if this return value is leaked without being dropped. + pub fn query_pairs_mut(&mut self) -> form_urlencoded::Serializer<UrlQuery> { + let fragment = self.take_fragment(); + + let query_start; + if let Some(start) = self.query_start { + debug_assert!(self.byte_at(start) == b'?'); + query_start = start as usize; + } else { + query_start = self.serialization.len(); + self.query_start = Some(to_u32(query_start).unwrap()); + self.serialization.push('?'); + } + + let query = UrlQuery { url: Some(self), fragment: fragment }; + form_urlencoded::Serializer::for_suffix(query, query_start + "?".len()) + } + + fn take_after_path(&mut self) -> String { + match (self.query_start, self.fragment_start) { + (Some(i), _) | (None, Some(i)) => { + let after_path = self.slice(i..).to_owned(); + self.serialization.truncate(i as usize); + after_path + }, + (None, None) => String::new(), + } + } + + /// Change this URL’s path. + /// + /// # Examples + /// + /// ```rust + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.com")?; + /// url.set_path("api/comments"); + /// assert_eq!(url.as_str(), "https://example.com/api/comments"); + /// assert_eq!(url.path(), "/api/comments"); + /// + /// let mut url = Url::parse("https://example.com/api")?; + /// url.set_path("data/report.csv"); + /// assert_eq!(url.as_str(), "https://example.com/data/report.csv"); + /// assert_eq!(url.path(), "/data/report.csv"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_path(&mut self, mut path: &str) { + let after_path = self.take_after_path(); + let old_after_path_pos = to_u32(self.serialization.len()).unwrap(); + let cannot_be_a_base = self.cannot_be_a_base(); + let scheme_type = SchemeType::from(self.scheme()); + self.serialization.truncate(self.path_start as usize); + self.mutate(|parser| { + if cannot_be_a_base { + if path.starts_with('/') { + parser.serialization.push_str("%2F"); + path = &path[1..]; + } + parser.parse_cannot_be_a_base_path(parser::Input::new(path)); + } else { + let mut has_host = true; // FIXME + parser.parse_path_start(scheme_type, &mut has_host, parser::Input::new(path)); + } + }); + self.restore_after_path(old_after_path_pos, &after_path); + } + + /// Return an object with methods to manipulate this URL’s path segments. + /// + /// Return `Err(())` if this URL is cannot-be-a-base. + pub fn path_segments_mut(&mut self) -> Result<PathSegmentsMut, ()> { + if self.cannot_be_a_base() { + Err(()) + } else { + Ok(path_segments::new(self)) + } + } + + fn restore_after_path(&mut self, old_after_path_position: u32, after_path: &str) { + let new_after_path_position = to_u32(self.serialization.len()).unwrap(); + let adjust = |index: &mut u32| { + *index -= old_after_path_position; + *index += new_after_path_position; + }; + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + self.serialization.push_str(after_path) + } + + /// Change this URL’s port number. + /// + /// If this URL is cannot-be-a-base, does not have a host, or has the `file` scheme; + /// do nothing and return `Err`. + /// + /// # Examples + /// + /// ``` + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let mut url = Url::parse("ssh://example.net:2048/")?; + /// + /// url.set_port(Some(4096)).map_err(|_| "cannot be base")?; + /// assert_eq!(url.as_str(), "ssh://example.net:4096/"); + /// + /// url.set_port(None).map_err(|_| "cannot be base")?; + /// assert_eq!(url.as_str(), "ssh://example.net/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Cannot set port for cannot-be-a-base URLs: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rms@example.net")?; + /// + /// let result = url.set_port(Some(80)); + /// assert!(result.is_err()); + /// + /// let result = url.set_port(None); + /// assert!(result.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_port(&mut self, mut port: Option<u16>) -> Result<(), ()> { + // has_host implies !cannot_be_a_base + if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + return Err(()) + } + if port.is_some() && port == parser::default_port(self.scheme()) { + port = None + } + self.set_port_internal(port); + Ok(()) + } + + fn set_port_internal(&mut self, port: Option<u16>) { + match (self.port, port) { + (None, None) => {} + (Some(_), None) => { + self.serialization.drain(self.host_end as usize .. self.path_start as usize); + let offset = self.path_start - self.host_end; + self.path_start = self.host_end; + if let Some(ref mut index) = self.query_start { *index -= offset } + if let Some(ref mut index) = self.fragment_start { *index -= offset } + } + (Some(old), Some(new)) if old == new => {} + (_, Some(new)) => { + let path_and_after = self.slice(self.path_start..).to_owned(); + self.serialization.truncate(self.host_end as usize); + write!(&mut self.serialization, ":{}", new).unwrap(); + let old_path_start = self.path_start; + let new_path_start = to_u32(self.serialization.len()).unwrap(); + self.path_start = new_path_start; + let adjust = |index: &mut u32| { + *index -= old_path_start; + *index += new_path_start; + }; + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + self.serialization.push_str(&path_and_after); + } + } + self.port = port; + } + + /// Change this URL’s host. + /// + /// Removing the host (calling this with `None`) + /// will also remove any username, password, and port number. + /// + /// # Examples + /// + /// Change host: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.net")?; + /// let result = url.set_host(Some("rust-lang.org")); + /// assert!(result.is_ok()); + /// assert_eq!(url.as_str(), "https://rust-lang.org/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Remove host: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("foo://example.net")?; + /// let result = url.set_host(None); + /// assert!(result.is_ok()); + /// assert_eq!(url.as_str(), "foo:/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Cannot remove host for 'special' schemes (e.g. `http`): + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.net")?; + /// let result = url.set_host(None); + /// assert!(result.is_err()); + /// assert_eq!(url.as_str(), "https://example.net/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Cannot change or remove host for cannot-be-a-base URLs: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rms@example.net")?; + /// + /// let result = url.set_host(Some("rust-lang.org")); + /// assert!(result.is_err()); + /// assert_eq!(url.as_str(), "mailto:rms@example.net"); + /// + /// let result = url.set_host(None); + /// assert!(result.is_err()); + /// assert_eq!(url.as_str(), "mailto:rms@example.net"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// # Errors + /// + /// If this URL is cannot-be-a-base or there is an error parsing the given `host`, + /// a [`ParseError`] variant will be returned. + /// + /// [`ParseError`]: enum.ParseError.html + pub fn set_host(&mut self, host: Option<&str>) -> Result<(), ParseError> { + if self.cannot_be_a_base() { + return Err(ParseError::SetHostOnCannotBeABaseUrl) + } + + if let Some(host) = host { + if host == "" && SchemeType::from(self.scheme()).is_special() { + return Err(ParseError::EmptyHost); + } + if SchemeType::from(self.scheme()).is_special() { + self.set_host_internal(Host::parse(host)?, None) + } else { + self.set_host_internal(Host::parse_opaque(host)?, None) + } + } else if self.has_host() { + if SchemeType::from(self.scheme()).is_special() { + return Err(ParseError::EmptyHost) + } + debug_assert!(self.byte_at(self.scheme_end) == b':'); + debug_assert!(self.byte_at(self.path_start) == b'/'); + let new_path_start = self.scheme_end + 1; + self.serialization.drain(new_path_start as usize..self.path_start as usize); + let offset = self.path_start - new_path_start; + self.path_start = new_path_start; + self.username_end = new_path_start; + self.host_start = new_path_start; + self.host_end = new_path_start; + self.port = None; + if let Some(ref mut index) = self.query_start { *index -= offset } + if let Some(ref mut index) = self.fragment_start { *index -= offset } + } + Ok(()) + } + + /// opt_new_port: None means leave unchanged, Some(None) means remove any port number. + fn set_host_internal(&mut self, host: Host<String>, opt_new_port: Option<Option<u16>>) { + let old_suffix_pos = if opt_new_port.is_some() { self.path_start } else { self.host_end }; + let suffix = self.slice(old_suffix_pos..).to_owned(); + self.serialization.truncate(self.host_start as usize); + if !self.has_authority() { + debug_assert!(self.slice(self.scheme_end..self.host_start) == ":"); + debug_assert!(self.username_end == self.host_start); + self.serialization.push('/'); + self.serialization.push('/'); + self.username_end += 2; + self.host_start += 2; + } + write!(&mut self.serialization, "{}", host).unwrap(); + self.host_end = to_u32(self.serialization.len()).unwrap(); + self.host = host.into(); + + if let Some(new_port) = opt_new_port { + self.port = new_port; + if let Some(port) = new_port { + write!(&mut self.serialization, ":{}", port).unwrap(); + } + } + let new_suffix_pos = to_u32(self.serialization.len()).unwrap(); + self.serialization.push_str(&suffix); + + let adjust = |index: &mut u32| { + *index -= old_suffix_pos; + *index += new_suffix_pos; + }; + adjust(&mut self.path_start); + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + } + + /// Change this URL’s host to the given IP address. + /// + /// If this URL is cannot-be-a-base, do nothing and return `Err`. + /// + /// Compared to `Url::set_host`, this skips the host parser. + /// + /// # Examples + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("http://example.com")?; + /// url.set_ip_host("127.0.0.1".parse().unwrap()); + /// assert_eq!(url.host_str(), Some("127.0.0.1")); + /// assert_eq!(url.as_str(), "http://127.0.0.1/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Cannot change URL's from mailto(cannot-be-base) to ip: + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rms@example.com")?; + /// let result = url.set_ip_host("127.0.0.1".parse().unwrap()); + /// + /// assert_eq!(url.as_str(), "mailto:rms@example.com"); + /// assert!(result.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + pub fn set_ip_host(&mut self, address: IpAddr) -> Result<(), ()> { + if self.cannot_be_a_base() { + return Err(()) + } + + let address = match address { + IpAddr::V4(address) => Host::Ipv4(address), + IpAddr::V6(address) => Host::Ipv6(address), + }; + self.set_host_internal(address, None); + Ok(()) + } + + /// Change this URL’s password. + /// + /// If this URL is cannot-be-a-base or does not have a host, do nothing and return `Err`. + /// + /// # Examples + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rmz@example.com")?; + /// let result = url.set_password(Some("secret_password")); + /// assert!(result.is_err()); + /// + /// let mut url = Url::parse("ftp://user1:secret1@example.com")?; + /// let result = url.set_password(Some("secret_password")); + /// assert_eq!(url.password(), Some("secret_password")); + /// + /// let mut url = Url::parse("ftp://user2:@example.com")?; + /// let result = url.set_password(Some("secret2")); + /// assert!(result.is_ok()); + /// assert_eq!(url.password(), Some("secret2")); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_password(&mut self, password: Option<&str>) -> Result<(), ()> { + // has_host implies !cannot_be_a_base + if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + return Err(()) + } + if let Some(password) = password { + let host_and_after = self.slice(self.host_start..).to_owned(); + self.serialization.truncate(self.username_end as usize); + self.serialization.push(':'); + self.serialization.extend(utf8_percent_encode(password, USERINFO_ENCODE_SET)); + self.serialization.push('@'); + + let old_host_start = self.host_start; + let new_host_start = to_u32(self.serialization.len()).unwrap(); + let adjust = |index: &mut u32| { + *index -= old_host_start; + *index += new_host_start; + }; + self.host_start = new_host_start; + adjust(&mut self.host_end); + adjust(&mut self.path_start); + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + + self.serialization.push_str(&host_and_after); + } else if self.byte_at(self.username_end) == b':' { // If there is a password to remove + let has_username_or_password = self.byte_at(self.host_start - 1) == b'@'; + debug_assert!(has_username_or_password); + let username_start = self.scheme_end + 3; + let empty_username = username_start == self.username_end; + let start = self.username_end; // Remove the ':' + let end = if empty_username { + self.host_start // Remove the '@' as well + } else { + self.host_start - 1 // Keep the '@' to separate the username from the host + }; + self.serialization.drain(start as usize .. end as usize); + let offset = end - start; + self.host_start -= offset; + self.host_end -= offset; + self.path_start -= offset; + if let Some(ref mut index) = self.query_start { *index -= offset } + if let Some(ref mut index) = self.fragment_start { *index -= offset } + } + Ok(()) + } + + /// Change this URL’s username. + /// + /// If this URL is cannot-be-a-base or does not have a host, do nothing and return `Err`. + /// # Examples + /// + /// Cannot setup username from mailto(cannot-be-base) + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rmz@example.com")?; + /// let result = url.set_username("user1"); + /// assert_eq!(url.as_str(), "mailto:rmz@example.com"); + /// assert!(result.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Setup username to user1 + /// + /// ```rust + /// use url::{Url, ParseError}; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("ftp://:secre1@example.com/")?; + /// let result = url.set_username("user1"); + /// assert!(result.is_ok()); + /// assert_eq!(url.username(), "user1"); + /// assert_eq!(url.as_str(), "ftp://user1:secre1@example.com/"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_username(&mut self, username: &str) -> Result<(), ()> { + // has_host implies !cannot_be_a_base + if !self.has_host() || self.host() == Some(Host::Domain("")) || self.scheme() == "file" { + return Err(()) + } + let username_start = self.scheme_end + 3; + debug_assert!(self.slice(self.scheme_end..username_start) == "://"); + if self.slice(username_start..self.username_end) == username { + return Ok(()) + } + let after_username = self.slice(self.username_end..).to_owned(); + self.serialization.truncate(username_start as usize); + self.serialization.extend(utf8_percent_encode(username, USERINFO_ENCODE_SET)); + + let mut removed_bytes = self.username_end; + self.username_end = to_u32(self.serialization.len()).unwrap(); + let mut added_bytes = self.username_end; + + let new_username_is_empty = self.username_end == username_start; + match (new_username_is_empty, after_username.chars().next()) { + (true, Some('@')) => { + removed_bytes += 1; + self.serialization.push_str(&after_username[1..]); + } + (false, Some('@')) | (_, Some(':')) | (true, _) => { + self.serialization.push_str(&after_username); + } + (false, _) => { + added_bytes += 1; + self.serialization.push('@'); + self.serialization.push_str(&after_username); + } + } + + let adjust = |index: &mut u32| { + *index -= removed_bytes; + *index += added_bytes; + }; + adjust(&mut self.host_start); + adjust(&mut self.host_end); + adjust(&mut self.path_start); + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + Ok(()) + } + + /// Change this URL’s scheme. + /// + /// Do nothing and return `Err` if: + /// + /// * The new scheme is not in `[a-zA-Z][a-zA-Z0-9+.-]+` + /// * This URL is cannot-be-a-base and the new scheme is one of + /// `http`, `https`, `ws`, `wss`, `ftp`, or `gopher` + /// + /// # Examples + /// + /// Change the URL’s scheme from `https` to `foo`: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.net")?; + /// let result = url.set_scheme("foo"); + /// assert_eq!(url.as_str(), "foo://example.net/"); + /// assert!(result.is_ok()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// + /// Cannot change URL’s scheme from `https` to `foõ`: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("https://example.net")?; + /// let result = url.set_scheme("foõ"); + /// assert_eq!(url.as_str(), "https://example.net/"); + /// assert!(result.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// Cannot change URL’s scheme from `mailto` (cannot-be-a-base) to `https`: + /// + /// ``` + /// use url::Url; + /// # use url::ParseError; + /// + /// # fn run() -> Result<(), ParseError> { + /// let mut url = Url::parse("mailto:rms@example.net")?; + /// let result = url.set_scheme("https"); + /// assert_eq!(url.as_str(), "mailto:rms@example.net"); + /// assert!(result.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn set_scheme(&mut self, scheme: &str) -> Result<(), ()> { + let mut parser = Parser::for_setter(String::new()); + let remaining = parser.parse_scheme(parser::Input::new(scheme))?; + if !remaining.is_empty() || + (!self.has_host() && SchemeType::from(&parser.serialization).is_special()) { + return Err(()) + } + let old_scheme_end = self.scheme_end; + let new_scheme_end = to_u32(parser.serialization.len()).unwrap(); + let adjust = |index: &mut u32| { + *index -= old_scheme_end; + *index += new_scheme_end; + }; + + self.scheme_end = new_scheme_end; + adjust(&mut self.username_end); + adjust(&mut self.host_start); + adjust(&mut self.host_end); + adjust(&mut self.path_start); + if let Some(ref mut index) = self.query_start { adjust(index) } + if let Some(ref mut index) = self.fragment_start { adjust(index) } + + parser.serialization.push_str(self.slice(old_scheme_end..)); + self.serialization = parser.serialization; + Ok(()) + } + + /// Convert a file name as `std::path::Path` into an URL in the `file` scheme. + /// + /// This returns `Err` if the given path is not absolute or, + /// on Windows, if the prefix is not a disk prefix (e.g. `C:`) or a UNC prefix (`\\`). + /// + /// # Examples + /// + /// On Unix-like platforms: + /// + /// ``` + /// # if cfg!(unix) { + /// use url::Url; + /// + /// # fn run() -> Result<(), ()> { + /// let url = Url::from_file_path("/tmp/foo.txt")?; + /// assert_eq!(url.as_str(), "file:///tmp/foo.txt"); + /// + /// let url = Url::from_file_path("../foo.txt"); + /// assert!(url.is_err()); + /// + /// let url = Url::from_file_path("https://google.com/"); + /// assert!(url.is_err()); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// # } + /// ``` + #[cfg(any(unix, windows, target_os="redox"))] + pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> { + let mut serialization = "file://".to_owned(); + let host_start = serialization.len() as u32; + let (host_end, host) = path_to_file_url_segments(path.as_ref(), &mut serialization)?; + Ok(Url { + serialization: serialization, + scheme_end: "file".len() as u32, + username_end: host_start, + host_start: host_start, + host_end: host_end, + host: host, + port: None, + path_start: host_end, + query_start: None, + fragment_start: None, + }) + } + + /// Convert a directory name as `std::path::Path` into an URL in the `file` scheme. + /// + /// This returns `Err` if the given path is not absolute or, + /// on Windows, if the prefix is not a disk prefix (e.g. `C:`) or a UNC prefix (`\\`). + /// + /// Compared to `from_file_path`, this ensure that URL’s the path has a trailing slash + /// so that the entire path is considered when using this URL as a base URL. + /// + /// For example: + /// + /// * `"index.html"` parsed with `Url::from_directory_path(Path::new("/var/www"))` + /// as the base URL is `file:///var/www/index.html` + /// * `"index.html"` parsed with `Url::from_file_path(Path::new("/var/www"))` + /// as the base URL is `file:///var/index.html`, which might not be what was intended. + /// + /// Note that `std::path` does not consider trailing slashes significant + /// and usually does not include them (e.g. in `Path::parent()`). + #[cfg(any(unix, windows, target_os="redox"))] + pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> { + let mut url = Url::from_file_path(path)?; + if !url.serialization.ends_with('/') { + url.serialization.push('/') + } + Ok(url) + } + + /// Serialize with Serde using the internal representation of the `Url` struct. + /// + /// The corresponding `deserialize_internal` method sacrifices some invariant-checking + /// for speed, compared to the `Deserialize` trait impl. + /// + /// This method is only available if the `serde` Cargo feature is enabled. + #[cfg(feature = "serde")] + #[deny(unused)] + pub fn serialize_internal<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { + use serde::Serialize; + // Destructuring first lets us ensure that adding or removing fields forces this method + // to be updated + let Url { ref serialization, ref scheme_end, + ref username_end, ref host_start, + ref host_end, ref host, ref port, + ref path_start, ref query_start, + ref fragment_start} = *self; + (serialization, scheme_end, username_end, + host_start, host_end, host, port, path_start, + query_start, fragment_start).serialize(serializer) + } + + /// Serialize with Serde using the internal representation of the `Url` struct. + /// + /// The corresponding `deserialize_internal` method sacrifices some invariant-checking + /// for speed, compared to the `Deserialize` trait impl. + /// + /// This method is only available if the `serde` Cargo feature is enabled. + #[cfg(feature = "serde")] + #[deny(unused)] + pub fn deserialize_internal<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: serde::Deserializer { + use serde::{Deserialize, Error}; + let (serialization, scheme_end, username_end, + host_start, host_end, host, port, path_start, + query_start, fragment_start) = Deserialize::deserialize(deserializer)?; + let url = Url { + serialization: serialization, + scheme_end: scheme_end, + username_end: username_end, + host_start: host_start, + host_end: host_end, + host: host, + port: port, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start + }; + if cfg!(debug_assertions) { + url.check_invariants().map_err(|ref reason| Error::invalid_value(&reason))? + } + Ok(url) + } + + + /// Assuming the URL is in the `file` scheme or similar, + /// convert its path to an absolute `std::path::Path`. + /// + /// **Note:** This does not actually check the URL’s `scheme`, + /// and may give nonsensical results for other schemes. + /// It is the user’s responsibility to check the URL’s scheme before calling this. + /// + /// ``` + /// # use url::Url; + /// # let url = Url::parse("file:///etc/passwd").unwrap(); + /// let path = url.to_file_path(); + /// ``` + /// + /// Returns `Err` if the host is neither empty nor `"localhost"` (except on Windows, where + /// `file:` URLs may have a non-local host), + /// or if `Path::new_opt()` returns `None`. + /// (That is, if the percent-decoded path contains a NUL byte or, + /// for a Windows path, is not UTF-8.) + #[inline] + #[cfg(any(unix, windows, target_os="redox"))] + pub fn to_file_path(&self) -> Result<PathBuf, ()> { + if let Some(segments) = self.path_segments() { + let host = match self.host() { + None | Some(Host::Domain("localhost")) => None, + Some(_) if cfg!(windows) && self.scheme() == "file" => { + Some(&self.serialization[self.host_start as usize .. self.host_end as usize]) + }, + _ => return Err(()) + }; + + return file_url_segments_to_pathbuf(host, segments); + } + Err(()) + } + + // Private helper methods: + + #[inline] + fn slice<R>(&self, range: R) -> &str where R: RangeArg { + range.slice_of(&self.serialization) + } + + #[inline] + fn byte_at(&self, i: u32) -> u8 { + self.serialization.as_bytes()[i as usize] + } +} + +/// Return an error if `Url::host` or `Url::port_or_known_default` return `None`. +impl ToSocketAddrs for Url { + type Iter = SocketAddrs; + + fn to_socket_addrs(&self) -> io::Result<Self::Iter> { + self.with_default_port(|_| Err(()))?.to_socket_addrs() + } +} + +/// Parse a string as an URL, without a base URL or encoding override. +impl str::FromStr for Url { + type Err = ParseError; + + #[inline] + fn from_str(input: &str) -> Result<Url, ::ParseError> { + Url::parse(input) + } +} + +/// Display the serialization of this URL. +impl fmt::Display for Url { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.serialization, formatter) + } +} + +/// Debug the serialization of this URL. +impl fmt::Debug for Url { + #[inline] + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.serialization, formatter) + } +} + +/// URLs compare like their serialization. +impl Eq for Url {} + +/// URLs compare like their serialization. +impl PartialEq for Url { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.serialization == other.serialization + } +} + +/// URLs compare like their serialization. +impl Ord for Url { + #[inline] + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.serialization.cmp(&other.serialization) + } +} + +/// URLs compare like their serialization. +impl PartialOrd for Url { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { + self.serialization.partial_cmp(&other.serialization) + } +} + +/// URLs hash like their serialization. +impl hash::Hash for Url { + #[inline] + fn hash<H>(&self, state: &mut H) where H: hash::Hasher { + hash::Hash::hash(&self.serialization, state) + } +} + +/// Return the serialization of this URL. +impl AsRef<str> for Url { + #[inline] + fn as_ref(&self) -> &str { + &self.serialization + } +} + +trait RangeArg { + fn slice_of<'a>(&self, s: &'a str) -> &'a str; +} + +impl RangeArg for Range<u32> { + #[inline] + fn slice_of<'a>(&self, s: &'a str) -> &'a str { + &s[self.start as usize .. self.end as usize] + } +} + +impl RangeArg for RangeFrom<u32> { + #[inline] + fn slice_of<'a>(&self, s: &'a str) -> &'a str { + &s[self.start as usize ..] + } +} + +impl RangeArg for RangeTo<u32> { + #[inline] + fn slice_of<'a>(&self, s: &'a str) -> &'a str { + &s[.. self.end as usize] + } +} + +#[cfg(feature="rustc-serialize")] +impl rustc_serialize::Encodable for Url { + fn encode<S: rustc_serialize::Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> { + encoder.emit_str(self.as_str()) + } +} + + +#[cfg(feature="rustc-serialize")] +impl rustc_serialize::Decodable for Url { + fn decode<D: rustc_serialize::Decoder>(decoder: &mut D) -> Result<Url, D::Error> { + Url::parse(&*decoder.read_str()?).map_err(|error| { + decoder.error(&format!("URL parsing error: {}", error)) + }) + } +} + +/// Serializes this URL into a `serde` stream. +/// +/// This implementation is only available if the `serde` Cargo feature is enabled. +#[cfg(feature="serde")] +impl serde::Serialize for Url { + fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { + serializer.serialize_str(self.as_str()) + } +} + +/// Deserializes this URL from a `serde` stream. +/// +/// This implementation is only available if the `serde` Cargo feature is enabled. +#[cfg(feature="serde")] +impl serde::Deserialize for Url { + fn deserialize<D>(deserializer: &mut D) -> Result<Url, D::Error> where D: serde::Deserializer { + let string_representation: String = serde::Deserialize::deserialize(deserializer)?; + Url::parse(&string_representation).map_err(|err| { + serde::Error::invalid_value(err.description()) + }) + } +} + +#[cfg(any(unix, target_os = "redox"))] +fn path_to_file_url_segments(path: &Path, serialization: &mut String) + -> Result<(u32, HostInternal), ()> { + use std::os::unix::prelude::OsStrExt; + if !path.is_absolute() { + return Err(()) + } + let host_end = to_u32(serialization.len()).unwrap(); + let mut empty = true; + // skip the root component + for component in path.components().skip(1) { + empty = false; + serialization.push('/'); + serialization.extend(percent_encode( + component.as_os_str().as_bytes(), PATH_SEGMENT_ENCODE_SET)); + } + if empty { + // An URL’s path must not be empty. + serialization.push('/'); + } + Ok((host_end, HostInternal::None)) +} + +#[cfg(windows)] +fn path_to_file_url_segments(path: &Path, serialization: &mut String) + -> Result<(u32, HostInternal), ()> { + path_to_file_url_segments_windows(path, serialization) +} + +// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102 +#[cfg_attr(not(windows), allow(dead_code))] +fn path_to_file_url_segments_windows(path: &Path, serialization: &mut String) + -> Result<(u32, HostInternal), ()> { + use std::path::{Prefix, Component}; + if !path.is_absolute() { + return Err(()) + } + let mut components = path.components(); + + let host_end; + let host_internal; + match components.next() { + Some(Component::Prefix(ref p)) => match p.kind() { + Prefix::Disk(letter) | Prefix::VerbatimDisk(letter) => { + host_end = to_u32(serialization.len()).unwrap(); + host_internal = HostInternal::None; + serialization.push('/'); + serialization.push(letter as char); + serialization.push(':'); + }, + Prefix::UNC(server, share) | Prefix::VerbatimUNC(server, share) => { + let host = Host::parse(server.to_str().ok_or(())?).map_err(|_| ())?; + write!(serialization, "{}", host).unwrap(); + host_end = to_u32(serialization.len()).unwrap(); + host_internal = host.into(); + serialization.push('/'); + let share = share.to_str().ok_or(())?; + serialization.extend(percent_encode(share.as_bytes(), PATH_SEGMENT_ENCODE_SET)); + }, + _ => return Err(()) + }, + + _ => return Err(()) + } + + for component in components { + if component == Component::RootDir { continue } + // FIXME: somehow work with non-unicode? + let component = component.as_os_str().to_str().ok_or(())?; + serialization.push('/'); + serialization.extend(percent_encode(component.as_bytes(), PATH_SEGMENT_ENCODE_SET)); + } + Ok((host_end, host_internal)) +} + + +#[cfg(any(unix, target_os = "redox"))] +fn file_url_segments_to_pathbuf(host: Option<&str>, segments: str::Split<char>) -> Result<PathBuf, ()> { + use std::ffi::OsStr; + use std::os::unix::prelude::OsStrExt; + use std::path::PathBuf; + + if host.is_some() { + return Err(()); + } + + let mut bytes = Vec::new(); + for segment in segments { + bytes.push(b'/'); + bytes.extend(percent_decode(segment.as_bytes())); + } + let os_str = OsStr::from_bytes(&bytes); + let path = PathBuf::from(os_str); + debug_assert!(path.is_absolute(), + "to_file_path() failed to produce an absolute Path"); + Ok(path) +} + +#[cfg(windows)] +fn file_url_segments_to_pathbuf(host: Option<&str>, segments: str::Split<char>) -> Result<PathBuf, ()> { + file_url_segments_to_pathbuf_windows(host, segments) +} + +// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102 +#[cfg_attr(not(windows), allow(dead_code))] +fn file_url_segments_to_pathbuf_windows(host: Option<&str>, mut segments: str::Split<char>) -> Result<PathBuf, ()> { + + let mut string = if let Some(host) = host { + r"\\".to_owned() + host + } else { + let first = segments.next().ok_or(())?; + + match first.len() { + 2 => { + if !first.starts_with(parser::ascii_alpha) || first.as_bytes()[1] != b':' { + return Err(()) + } + + first.to_owned() + }, + + 4 => { + if !first.starts_with(parser::ascii_alpha) { + return Err(()) + } + let bytes = first.as_bytes(); + if bytes[1] != b'%' || bytes[2] != b'3' || (bytes[3] != b'a' && bytes[3] != b'A') { + return Err(()) + } + + first[0..1].to_owned() + ":" + }, + + _ => return Err(()), + } + }; + + for segment in segments { + string.push('\\'); + + // Currently non-unicode windows paths cannot be represented + match String::from_utf8(percent_decode(segment.as_bytes()).collect()) { + Ok(s) => string.push_str(&s), + Err(..) => return Err(()), + } + } + let path = PathBuf::from(string); + debug_assert!(path.is_absolute(), + "to_file_path() failed to produce an absolute Path"); + Ok(path) +} + +fn io_error<T>(reason: &str) -> io::Result<T> { + Err(io::Error::new(io::ErrorKind::InvalidData, reason)) +} + +/// Implementation detail of `Url::query_pairs_mut`. Typically not used directly. +#[derive(Debug)] +pub struct UrlQuery<'a> { + url: Option<&'a mut Url>, + fragment: Option<String>, +} + +impl<'a> Drop for UrlQuery<'a> { + fn drop(&mut self) { + if let Some(url) = self.url.take() { + url.restore_already_parsed_fragment(self.fragment.take()) + } + } +} + + +/// Define a new struct +/// that implements the [`EncodeSet`](percent_encoding/trait.EncodeSet.html) trait, +/// for use in [`percent_decode()`](percent_encoding/fn.percent_encode.html) +/// and related functions. +/// +/// Parameters are characters to include in the set in addition to those of the base set. +/// See [encode sets specification](http://url.spec.whatwg.org/#simple-encode-set). +/// +/// Example +/// ======= +/// +/// ```rust +/// #[macro_use] extern crate url; +/// use url::percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET}; +/// define_encode_set! { +/// /// This encode set is used in the URL parser for query strings. +/// pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'} +/// } +/// # fn main() { +/// assert_eq!(utf8_percent_encode("foo bar", QUERY_ENCODE_SET).collect::<String>(), "foo%20bar"); +/// # } +/// ``` +#[macro_export] +macro_rules! define_encode_set { + ($(#[$attr: meta])* pub $name: ident = [$base_set: expr] | {$($ch: pat),*}) => { + $(#[$attr])* + #[derive(Copy, Clone)] + #[allow(non_camel_case_types)] + pub struct $name; + + impl $crate::percent_encoding::EncodeSet for $name { + #[inline] + fn contains(&self, byte: u8) -> bool { + match byte as char { + $( + $ch => true, + )* + _ => $base_set.contains(byte) + } + } + } + } +} diff --git a/url/src/origin.rs b/url/src/origin.rs new file mode 100644 index 000000000..ee0b83e50 --- /dev/null +++ b/url/src/origin.rs @@ -0,0 +1,130 @@ +// Copyright 2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(feature = "heapsize")] use heapsize::HeapSizeOf; +use host::Host; +use idna::domain_to_unicode; +use parser::default_port; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use Url; + +pub fn url_origin(url: &Url) -> Origin { + let scheme = url.scheme(); + match scheme { + "blob" => { + let result = Url::parse(url.path()); + match result { + Ok(ref url) => url_origin(url), + Err(_) => Origin::new_opaque() + } + }, + "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => { + Origin::Tuple(scheme.to_owned(), url.host().unwrap().to_owned(), + url.port_or_known_default().unwrap()) + }, + // TODO: Figure out what to do if the scheme is a file + "file" => Origin::new_opaque(), + _ => Origin::new_opaque() + } +} + +/// The origin of an URL +/// +/// Two URLs with the same origin are considered +/// to originate from the same entity and can therefore trust +/// each other. +/// +/// The origin is determined based on the scheme as follows: +/// +/// - If the scheme is "blob" the origin is the origin of the +/// URL contained in the path component. If parsing fails, +/// it is an opaque origin. +/// - If the scheme is "ftp", "gopher", "http", "https", "ws", or "wss", +/// then the origin is a tuple of the scheme, host, and port. +/// - If the scheme is anything else, the origin is opaque, meaning +/// the URL does not have the same origin as any other URL. +/// +/// For more information see <https://url.spec.whatwg.org/#origin> +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +pub enum Origin { + /// A globally unique identifier + Opaque(OpaqueOrigin), + + /// Consists of the URL's scheme, host and port + Tuple(String, Host<String>, u16) +} + +#[cfg(feature = "heapsize")] +impl HeapSizeOf for Origin { + fn heap_size_of_children(&self) -> usize { + match *self { + Origin::Tuple(ref scheme, ref host, _) => { + scheme.heap_size_of_children() + + host.heap_size_of_children() + }, + _ => 0, + } + } +} + + +impl Origin { + /// Creates a new opaque origin that is only equal to itself. + pub fn new_opaque() -> Origin { + static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + Origin::Opaque(OpaqueOrigin(COUNTER.fetch_add(1, Ordering::SeqCst))) + } + + /// Return whether this origin is a (scheme, host, port) tuple + /// (as opposed to an opaque origin). + pub fn is_tuple(&self) -> bool { + matches!(*self, Origin::Tuple(..)) + } + + /// <https://html.spec.whatwg.org/multipage/#ascii-serialisation-of-an-origin> + pub fn ascii_serialization(&self) -> String { + match *self { + Origin::Opaque(_) => "null".to_owned(), + Origin::Tuple(ref scheme, ref host, port) => { + if default_port(scheme) == Some(port) { + format!("{}://{}", scheme, host) + } else { + format!("{}://{}:{}", scheme, host, port) + } + } + } + } + + /// <https://html.spec.whatwg.org/multipage/#unicode-serialisation-of-an-origin> + pub fn unicode_serialization(&self) -> String { + match *self { + Origin::Opaque(_) => "null".to_owned(), + Origin::Tuple(ref scheme, ref host, port) => { + let host = match *host { + Host::Domain(ref domain) => { + let (domain, _errors) = domain_to_unicode(domain); + Host::Domain(domain) + } + _ => host.clone() + }; + if default_port(scheme) == Some(port) { + format!("{}://{}", scheme, host) + } else { + format!("{}://{}:{}", scheme, host, port) + } + } + } + } +} + +/// Opaque identifier for URLs that have file or other schemes +#[derive(Eq, PartialEq, Hash, Clone, Debug)] +pub struct OpaqueOrigin(usize); + +#[cfg(feature = "heapsize")] +known_heap_size!(0, OpaqueOrigin); diff --git a/url/src/parser.rs b/url/src/parser.rs new file mode 100644 index 000000000..4f9cc524b --- /dev/null +++ b/url/src/parser.rs @@ -0,0 +1,1290 @@ +// Copyright 2013-2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(unused_imports, deprecated)] +use std::ascii::AsciiExt; + +use std::error::Error; +use std::fmt::{self, Formatter, Write}; +use std::str; + +use Url; +use encoding::EncodingOverride; +use host::{Host, HostInternal}; +use percent_encoding::{ + utf8_percent_encode, percent_encode, + SIMPLE_ENCODE_SET, DEFAULT_ENCODE_SET, USERINFO_ENCODE_SET, QUERY_ENCODE_SET, + PATH_SEGMENT_ENCODE_SET +}; + +define_encode_set! { + // The backslash (\) character is treated as a path separator in special URLs + // so it needs to be additionally escaped in that case. + pub SPECIAL_PATH_SEGMENT_ENCODE_SET = [PATH_SEGMENT_ENCODE_SET] | {'\\'} +} + +pub type ParseResult<T> = Result<T, ParseError>; + +macro_rules! simple_enum_error { + ($($name: ident => $description: expr,)+) => { + /// Errors that can occur during parsing. + #[derive(PartialEq, Eq, Clone, Copy, Debug)] + pub enum ParseError { + $( + $name, + )+ + } + + impl Error for ParseError { + fn description(&self) -> &str { + match *self { + $( + ParseError::$name => $description, + )+ + } + } + } + } +} + +simple_enum_error! { + EmptyHost => "empty host", + IdnaError => "invalid international domain name", + InvalidPort => "invalid port number", + InvalidIpv4Address => "invalid IPv4 address", + InvalidIpv6Address => "invalid IPv6 address", + InvalidDomainCharacter => "invalid domain character", + RelativeUrlWithoutBase => "relative URL without a base", + RelativeUrlWithCannotBeABaseBase => "relative URL with a cannot-be-a-base base", + SetHostOnCannotBeABaseUrl => "a cannot-be-a-base URL doesn’t have a host to set", + Overflow => "URLs more than 4 GB are not supported", +} + +#[cfg(feature = "heapsize")] +known_heap_size!(0, ParseError); + +impl fmt::Display for ParseError { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.description().fmt(fmt) + } +} + +impl From<::idna::uts46::Errors> for ParseError { + fn from(_: ::idna::uts46::Errors) -> ParseError { ParseError::IdnaError } +} + +macro_rules! syntax_violation_enum { + ($($name: ident => $description: expr,)+) => { + /// Non-fatal syntax violations that can occur during parsing. + #[derive(PartialEq, Eq, Clone, Copy, Debug)] + pub enum SyntaxViolation { + $( + $name, + )+ + } + + impl SyntaxViolation { + pub fn description(&self) -> &'static str { + match *self { + $( + SyntaxViolation::$name => $description, + )+ + } + } + } + } +} + +syntax_violation_enum! { + Backslash => "backslash", + C0SpaceIgnored => + "leading or trailing control or space character are ignored in URLs", + EmbeddedCredentials => + "embedding authentication information (username or password) \ + in an URL is not recommended", + ExpectedDoubleSlash => "expected //", + ExpectedFileDoubleSlash => "expected // after file:", + FileWithHostAndWindowsDrive => "file: with host and Windows drive letter", + NonUrlCodePoint => "non-URL code point", + NullInFragment => "NULL characters are ignored in URL fragment identifiers", + PercentDecode => "expected 2 hex digits after %", + TabOrNewlineIgnored => "tabs or newlines are ignored in URLs", + UnencodedAtSign => "unencoded @ sign in username or password", +} + +#[cfg(feature = "heapsize")] +known_heap_size!(0, SyntaxViolation); + +impl fmt::Display for SyntaxViolation { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.description().fmt(fmt) + } +} + +#[derive(Copy, Clone)] +pub enum SchemeType { + File, + SpecialNotFile, + NotSpecial, +} + +impl SchemeType { + pub fn is_special(&self) -> bool { + !matches!(*self, SchemeType::NotSpecial) + } + + pub fn is_file(&self) -> bool { + matches!(*self, SchemeType::File) + } + + pub fn from(s: &str) -> Self { + match s { + "http" | "https" | "ws" | "wss" | "ftp" | "gopher" => SchemeType::SpecialNotFile, + "file" => SchemeType::File, + _ => SchemeType::NotSpecial, + } + } +} + +pub fn default_port(scheme: &str) -> Option<u16> { + match scheme { + "http" | "ws" => Some(80), + "https" | "wss" => Some(443), + "ftp" => Some(21), + "gopher" => Some(70), + _ => None, + } +} + +#[derive(Clone)] +pub struct Input<'i> { + chars: str::Chars<'i>, +} + +impl<'i> Input<'i> { + pub fn new(input: &'i str) -> Self { + Input::with_log(input, ViolationFn::NoOp) + } + + pub fn with_log(original_input: &'i str, vfn: ViolationFn) -> Self { + let input = original_input.trim_matches(c0_control_or_space); + if vfn.is_set() { + if input.len() < original_input.len() { + vfn.call(SyntaxViolation::C0SpaceIgnored) + } + if input.chars().any(|c| matches!(c, '\t' | '\n' | '\r')) { + vfn.call(SyntaxViolation::TabOrNewlineIgnored) + } + } + Input { chars: input.chars() } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.clone().next().is_none() + } + + #[inline] + fn starts_with<P: Pattern>(&self, p: P) -> bool { + p.split_prefix(&mut self.clone()) + } + + #[inline] + pub fn split_prefix<P: Pattern>(&self, p: P) -> Option<Self> { + let mut remaining = self.clone(); + if p.split_prefix(&mut remaining) { + Some(remaining) + } else { + None + } + } + + #[inline] + fn split_first(&self) -> (Option<char>, Self) { + let mut remaining = self.clone(); + (remaining.next(), remaining) + } + + #[inline] + fn count_matching<F: Fn(char) -> bool>(&self, f: F) -> (u32, Self) { + let mut count = 0; + let mut remaining = self.clone(); + loop { + let mut input = remaining.clone(); + if matches!(input.next(), Some(c) if f(c)) { + remaining = input; + count += 1; + } else { + return (count, remaining) + } + } + } + + #[inline] + fn next_utf8(&mut self) -> Option<(char, &'i str)> { + loop { + let utf8 = self.chars.as_str(); + match self.chars.next() { + Some(c) => { + if !matches!(c, '\t' | '\n' | '\r') { + return Some((c, &utf8[..c.len_utf8()])) + } + } + None => return None + } + } + } +} + +pub trait Pattern { + fn split_prefix<'i>(self, input: &mut Input<'i>) -> bool; +} + +impl Pattern for char { + fn split_prefix<'i>(self, input: &mut Input<'i>) -> bool { input.next() == Some(self) } +} + +impl<'a> Pattern for &'a str { + fn split_prefix<'i>(self, input: &mut Input<'i>) -> bool { + for c in self.chars() { + if input.next() != Some(c) { + return false + } + } + true + } +} + +impl<F: FnMut(char) -> bool> Pattern for F { + fn split_prefix<'i>(self, input: &mut Input<'i>) -> bool { input.next().map_or(false, self) } +} + +impl<'i> Iterator for Input<'i> { + type Item = char; + fn next(&mut self) -> Option<char> { + self.chars.by_ref().find(|&c| !matches!(c, '\t' | '\n' | '\r')) + } +} + +/// Wrapper for syntax violation callback functions. +#[derive(Copy, Clone)] +pub enum ViolationFn<'a> { + NewFn(&'a (Fn(SyntaxViolation) + 'a)), + OldFn(&'a (Fn(&'static str) + 'a)), + NoOp +} + +impl<'a> ViolationFn<'a> { + /// Call with a violation. + pub fn call(self, v: SyntaxViolation) { + match self { + ViolationFn::NewFn(f) => f(v), + ViolationFn::OldFn(f) => f(v.description()), + ViolationFn::NoOp => {} + } + } + + /// Call with a violation, if provided test returns true. Avoids + /// the test entirely if `NoOp`. + pub fn call_if<F>(self, v: SyntaxViolation, test: F) + where F: Fn() -> bool + { + match self { + ViolationFn::NewFn(f) => if test() { f(v) }, + ViolationFn::OldFn(f) => if test() { f(v.description()) }, + ViolationFn::NoOp => {} // avoid test + } + } + + /// True if not `NoOp` + pub fn is_set(self) -> bool { + match self { + ViolationFn::NoOp => false, + _ => true + } + } +} + +impl<'a> fmt::Debug for ViolationFn<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match *self { + ViolationFn::NewFn(_) => write!(f, "NewFn(Fn(SyntaxViolation))"), + ViolationFn::OldFn(_) => write!(f, "OldFn(Fn(&'static str))"), + ViolationFn::NoOp => write!(f, "NoOp") + } + } +} + +pub struct Parser<'a> { + pub serialization: String, + pub base_url: Option<&'a Url>, + pub query_encoding_override: EncodingOverride, + pub violation_fn: ViolationFn<'a>, + pub context: Context, +} + +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum Context { + UrlParser, + Setter, + PathSegmentSetter, +} + +impl<'a> Parser<'a> { + pub fn for_setter(serialization: String) -> Parser<'a> { + Parser { + serialization: serialization, + base_url: None, + query_encoding_override: EncodingOverride::utf8(), + violation_fn: ViolationFn::NoOp, + context: Context::Setter, + } + } + + /// https://url.spec.whatwg.org/#concept-basic-url-parser + pub fn parse_url(mut self, input: &str) -> ParseResult<Url> { + let input = Input::with_log(input, self.violation_fn); + if let Ok(remaining) = self.parse_scheme(input.clone()) { + return self.parse_with_scheme(remaining) + } + + // No-scheme state + if let Some(base_url) = self.base_url { + if input.starts_with('#') { + self.fragment_only(base_url, input) + } else if base_url.cannot_be_a_base() { + Err(ParseError::RelativeUrlWithCannotBeABaseBase) + } else { + let scheme_type = SchemeType::from(base_url.scheme()); + if scheme_type.is_file() { + self.parse_file(input, Some(base_url)) + } else { + self.parse_relative(input, scheme_type, base_url) + } + } + } else { + Err(ParseError::RelativeUrlWithoutBase) + } + } + + pub fn parse_scheme<'i>(&mut self, mut input: Input<'i>) -> Result<Input<'i>, ()> { + if input.is_empty() || !input.starts_with(ascii_alpha) { + return Err(()) + } + debug_assert!(self.serialization.is_empty()); + while let Some(c) = input.next() { + match c { + 'a'...'z' | 'A'...'Z' | '0'...'9' | '+' | '-' | '.' => { + self.serialization.push(c.to_ascii_lowercase()) + } + ':' => return Ok(input), + _ => { + self.serialization.clear(); + return Err(()) + } + } + } + // EOF before ':' + if self.context == Context::Setter { + Ok(input) + } else { + self.serialization.clear(); + Err(()) + } + } + + fn parse_with_scheme(mut self, input: Input) -> ParseResult<Url> { + use SyntaxViolation::{ExpectedFileDoubleSlash, ExpectedDoubleSlash}; + let scheme_end = to_u32(self.serialization.len())?; + let scheme_type = SchemeType::from(&self.serialization); + self.serialization.push(':'); + match scheme_type { + SchemeType::File => { + self.violation_fn.call_if(ExpectedFileDoubleSlash, || !input.starts_with("//")); + let base_file_url = self.base_url.and_then(|base| { + if base.scheme() == "file" { Some(base) } else { None } + }); + self.serialization.clear(); + self.parse_file(input, base_file_url) + } + SchemeType::SpecialNotFile => { + // special relative or authority state + let (slashes_count, remaining) = input.count_matching(|c| matches!(c, '/' | '\\')); + if let Some(base_url) = self.base_url { + if slashes_count < 2 && + base_url.scheme() == &self.serialization[..scheme_end as usize] { + // "Cannot-be-a-base" URLs only happen with "not special" schemes. + debug_assert!(!base_url.cannot_be_a_base()); + self.serialization.clear(); + return self.parse_relative(input, scheme_type, base_url) + } + } + // special authority slashes state + self.violation_fn.call_if(ExpectedDoubleSlash, || { + input.clone().take_while(|&c| matches!(c, '/' | '\\')) + .collect::<String>() != "//" + }); + self.after_double_slash(remaining, scheme_type, scheme_end) + } + SchemeType::NotSpecial => self.parse_non_special(input, scheme_type, scheme_end) + } + } + + /// Scheme other than file, http, https, ws, ws, ftp, gopher. + fn parse_non_special(mut self, input: Input, scheme_type: SchemeType, scheme_end: u32) + -> ParseResult<Url> { + // path or authority state ( + if let Some(input) = input.split_prefix("//") { + return self.after_double_slash(input, scheme_type, scheme_end) + } + // Anarchist URL (no authority) + let path_start = to_u32(self.serialization.len())?; + let username_end = path_start; + let host_start = path_start; + let host_end = path_start; + let host = HostInternal::None; + let port = None; + let remaining = if let Some(input) = input.split_prefix('/') { + let path_start = self.serialization.len(); + self.serialization.push('/'); + self.parse_path(scheme_type, &mut false, path_start, input) + } else { + self.parse_cannot_be_a_base_path(input) + }; + self.with_query_and_fragment(scheme_end, username_end, host_start, + host_end, host, port, path_start, remaining) + } + + fn parse_file(mut self, input: Input, mut base_file_url: Option<&Url>) -> ParseResult<Url> { + use SyntaxViolation::Backslash; + // file state + debug_assert!(self.serialization.is_empty()); + let (first_char, input_after_first_char) = input.split_first(); + match first_char { + None => { + if let Some(base_url) = base_file_url { + // Copy everything except the fragment + let before_fragment = match base_url.fragment_start { + Some(i) => &base_url.serialization[..i as usize], + None => &*base_url.serialization, + }; + self.serialization.push_str(before_fragment); + Ok(Url { + serialization: self.serialization, + fragment_start: None, + ..*base_url + }) + } else { + self.serialization.push_str("file:///"); + let scheme_end = "file".len() as u32; + let path_start = "file://".len() as u32; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: path_start, + host_start: path_start, + host_end: path_start, + host: HostInternal::None, + port: None, + path_start: path_start, + query_start: None, + fragment_start: None, + }) + } + }, + Some('?') => { + if let Some(base_url) = base_file_url { + // Copy everything up to the query string + let before_query = match (base_url.query_start, base_url.fragment_start) { + (None, None) => &*base_url.serialization, + (Some(i), _) | + (None, Some(i)) => base_url.slice(..i) + }; + self.serialization.push_str(before_query); + let (query_start, fragment_start) = + self.parse_query_and_fragment(base_url.scheme_end, input)?; + Ok(Url { + serialization: self.serialization, + query_start: query_start, + fragment_start: fragment_start, + ..*base_url + }) + } else { + self.serialization.push_str("file:///"); + let scheme_end = "file".len() as u32; + let path_start = "file://".len() as u32; + let (query_start, fragment_start) = + self.parse_query_and_fragment(scheme_end, input)?; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: path_start, + host_start: path_start, + host_end: path_start, + host: HostInternal::None, + port: None, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start, + }) + } + }, + Some('#') => { + if let Some(base_url) = base_file_url { + self.fragment_only(base_url, input) + } else { + self.serialization.push_str("file:///"); + let scheme_end = "file".len() as u32; + let path_start = "file://".len() as u32; + let fragment_start = "file:///".len() as u32; + self.serialization.push('#'); + self.parse_fragment(input_after_first_char); + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: path_start, + host_start: path_start, + host_end: path_start, + host: HostInternal::None, + port: None, + path_start: path_start, + query_start: None, + fragment_start: Some(fragment_start), + }) + } + } + Some('/') | Some('\\') => { + self.violation_fn.call_if(Backslash, || first_char == Some('\\')); + // file slash state + let (next_char, input_after_next_char) = input_after_first_char.split_first(); + self.violation_fn.call_if(Backslash, || next_char == Some('\\')); + if matches!(next_char, Some('/') | Some('\\')) { + // file host state + self.serialization.push_str("file://"); + let scheme_end = "file".len() as u32; + let host_start = "file://".len() as u32; + let (path_start, mut host, remaining) = + self.parse_file_host(input_after_next_char)?; + let mut host_end = to_u32(self.serialization.len())?; + let mut has_host = !matches!(host, HostInternal::None); + let remaining = if path_start { + self.parse_path_start(SchemeType::File, &mut has_host, remaining) + } else { + let path_start = self.serialization.len(); + self.serialization.push('/'); + self.parse_path(SchemeType::File, &mut has_host, path_start, remaining) + }; + // For file URLs that have a host and whose path starts + // with the windows drive letter we just remove the host. + if !has_host { + self.serialization.drain(host_start as usize..host_end as usize); + host_end = host_start; + host = HostInternal::None; + } + let (query_start, fragment_start) = + self.parse_query_and_fragment(scheme_end, remaining)?; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: host_start, + host_start: host_start, + host_end: host_end, + host: host, + port: None, + path_start: host_end, + query_start: query_start, + fragment_start: fragment_start, + }) + } else { + self.serialization.push_str("file:///"); + let scheme_end = "file".len() as u32; + let path_start = "file://".len(); + if let Some(base_url) = base_file_url { + let first_segment = base_url.path_segments().unwrap().next().unwrap(); + // FIXME: *normalized* drive letter + if is_windows_drive_letter(first_segment) { + self.serialization.push_str(first_segment); + self.serialization.push('/'); + } + } + let remaining = self.parse_path( + SchemeType::File, &mut false, path_start, input_after_first_char); + let (query_start, fragment_start) = + self.parse_query_and_fragment(scheme_end, remaining)?; + let path_start = path_start as u32; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: path_start, + host_start: path_start, + host_end: path_start, + host: HostInternal::None, + port: None, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start, + }) + } + } + _ => { + if starts_with_windows_drive_letter_segment(&input) { + base_file_url = None; + } + if let Some(base_url) = base_file_url { + let before_query = match (base_url.query_start, base_url.fragment_start) { + (None, None) => &*base_url.serialization, + (Some(i), _) | + (None, Some(i)) => base_url.slice(..i) + }; + self.serialization.push_str(before_query); + self.pop_path(SchemeType::File, base_url.path_start as usize); + let remaining = self.parse_path( + SchemeType::File, &mut true, base_url.path_start as usize, input); + self.with_query_and_fragment( + base_url.scheme_end, base_url.username_end, base_url.host_start, + base_url.host_end, base_url.host, base_url.port, base_url.path_start, remaining) + } else { + self.serialization.push_str("file:///"); + let scheme_end = "file".len() as u32; + let path_start = "file://".len(); + let remaining = self.parse_path( + SchemeType::File, &mut false, path_start, input); + let (query_start, fragment_start) = + self.parse_query_and_fragment(scheme_end, remaining)?; + let path_start = path_start as u32; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: path_start, + host_start: path_start, + host_end: path_start, + host: HostInternal::None, + port: None, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start, + }) + } + } + } + } + + fn parse_relative(mut self, input: Input, scheme_type: SchemeType, base_url: &Url) + -> ParseResult<Url> { + // relative state + debug_assert!(self.serialization.is_empty()); + let (first_char, input_after_first_char) = input.split_first(); + match first_char { + None => { + // Copy everything except the fragment + let before_fragment = match base_url.fragment_start { + Some(i) => &base_url.serialization[..i as usize], + None => &*base_url.serialization, + }; + self.serialization.push_str(before_fragment); + Ok(Url { + serialization: self.serialization, + fragment_start: None, + ..*base_url + }) + }, + Some('?') => { + // Copy everything up to the query string + let before_query = match (base_url.query_start, base_url.fragment_start) { + (None, None) => &*base_url.serialization, + (Some(i), _) | + (None, Some(i)) => base_url.slice(..i) + }; + self.serialization.push_str(before_query); + let (query_start, fragment_start) = + self.parse_query_and_fragment(base_url.scheme_end, input)?; + Ok(Url { + serialization: self.serialization, + query_start: query_start, + fragment_start: fragment_start, + ..*base_url + }) + }, + Some('#') => self.fragment_only(base_url, input), + Some('/') | Some('\\') => { + let (slashes_count, remaining) = input.count_matching(|c| matches!(c, '/' | '\\')); + if slashes_count >= 2 { + self.violation_fn.call_if(SyntaxViolation::ExpectedDoubleSlash, || { + input.clone().take_while(|&c| matches!(c, '/' | '\\')) + .collect::<String>() != "//" + }); + let scheme_end = base_url.scheme_end; + debug_assert!(base_url.byte_at(scheme_end) == b':'); + self.serialization.push_str(base_url.slice(..scheme_end + 1)); + return self.after_double_slash(remaining, scheme_type, scheme_end) + } + let path_start = base_url.path_start; + debug_assert!(base_url.byte_at(path_start) == b'/'); + self.serialization.push_str(base_url.slice(..path_start + 1)); + let remaining = self.parse_path( + scheme_type, &mut true, path_start as usize, input_after_first_char); + self.with_query_and_fragment( + base_url.scheme_end, base_url.username_end, base_url.host_start, + base_url.host_end, base_url.host, base_url.port, base_url.path_start, remaining) + } + _ => { + let before_query = match (base_url.query_start, base_url.fragment_start) { + (None, None) => &*base_url.serialization, + (Some(i), _) | + (None, Some(i)) => base_url.slice(..i) + }; + self.serialization.push_str(before_query); + // FIXME spec says just "remove last entry", not the "pop" algorithm + self.pop_path(scheme_type, base_url.path_start as usize); + let remaining = self.parse_path( + scheme_type, &mut true, base_url.path_start as usize, input); + self.with_query_and_fragment( + base_url.scheme_end, base_url.username_end, base_url.host_start, + base_url.host_end, base_url.host, base_url.port, base_url.path_start, remaining) + } + } + } + + fn after_double_slash(mut self, input: Input, scheme_type: SchemeType, scheme_end: u32) + -> ParseResult<Url> { + self.serialization.push('/'); + self.serialization.push('/'); + // authority state + let (username_end, remaining) = self.parse_userinfo(input, scheme_type)?; + // host state + let host_start = to_u32(self.serialization.len())?; + let (host_end, host, port, remaining) = + self.parse_host_and_port(remaining, scheme_end, scheme_type)?; + // path state + let path_start = to_u32(self.serialization.len())?; + let remaining = self.parse_path_start( + scheme_type, &mut true, remaining); + self.with_query_and_fragment(scheme_end, username_end, host_start, + host_end, host, port, path_start, remaining) + } + + /// Return (username_end, remaining) + fn parse_userinfo<'i>(&mut self, mut input: Input<'i>, scheme_type: SchemeType) + -> ParseResult<(u32, Input<'i>)> { + let mut last_at = None; + let mut remaining = input.clone(); + let mut char_count = 0; + while let Some(c) = remaining.next() { + match c { + '@' => { + if last_at.is_some() { + self.violation_fn.call(SyntaxViolation::UnencodedAtSign) + } else { + self.violation_fn.call(SyntaxViolation::EmbeddedCredentials) + } + last_at = Some((char_count, remaining.clone())) + }, + '/' | '?' | '#' => break, + '\\' if scheme_type.is_special() => break, + _ => (), + } + char_count += 1; + } + let (mut userinfo_char_count, remaining) = match last_at { + None => return Ok((to_u32(self.serialization.len())?, input)), + Some((0, remaining)) => return Ok((to_u32(self.serialization.len())?, remaining)), + Some(x) => x + }; + + let mut username_end = None; + let mut has_password = false; + let mut has_username = false; + while userinfo_char_count > 0 { + let (c, utf8_c) = input.next_utf8().unwrap(); + userinfo_char_count -= 1; + if c == ':' && username_end.is_none() { + // Start parsing password + username_end = Some(to_u32(self.serialization.len())?); + // We don't add a colon if the password is empty + if userinfo_char_count > 0 { + self.serialization.push(':'); + has_password = true; + } + } else { + if !has_password { + has_username = true; + } + self.check_url_code_point(c, &input); + self.serialization.extend(utf8_percent_encode(utf8_c, USERINFO_ENCODE_SET)); + } + } + let username_end = match username_end { + Some(i) => i, + None => to_u32(self.serialization.len())?, + }; + if has_username || has_password { + self.serialization.push('@'); + } + Ok((username_end, remaining)) + } + + fn parse_host_and_port<'i>(&mut self, input: Input<'i>, + scheme_end: u32, scheme_type: SchemeType) + -> ParseResult<(u32, HostInternal, Option<u16>, Input<'i>)> { + let (host, remaining) = Parser::parse_host(input, scheme_type)?; + write!(&mut self.serialization, "{}", host).unwrap(); + let host_end = to_u32(self.serialization.len())?; + let (port, remaining) = if let Some(remaining) = remaining.split_prefix(':') { + let scheme = || default_port(&self.serialization[..scheme_end as usize]); + Parser::parse_port(remaining, scheme, self.context)? + } else { + (None, remaining) + }; + if let Some(port) = port { + write!(&mut self.serialization, ":{}", port).unwrap() + } + Ok((host_end, host.into(), port, remaining)) + } + + pub fn parse_host(mut input: Input, scheme_type: SchemeType) + -> ParseResult<(Host<String>, Input)> { + // Undo the Input abstraction here to avoid allocating in the common case + // where the host part of the input does not contain any tab or newline + let input_str = input.chars.as_str(); + let mut inside_square_brackets = false; + let mut has_ignored_chars = false; + let mut non_ignored_chars = 0; + let mut bytes = 0; + for c in input_str.chars() { + match c { + ':' if !inside_square_brackets => break, + '\\' if scheme_type.is_special() => break, + '/' | '?' | '#' => break, + '\t' | '\n' | '\r' => { + has_ignored_chars = true; + } + '[' => { + inside_square_brackets = true; + non_ignored_chars += 1 + } + ']' => { + inside_square_brackets = false; + non_ignored_chars += 1 + } + _ => non_ignored_chars += 1 + } + bytes += c.len_utf8(); + } + let replaced: String; + let host_str; + { + let host_input = input.by_ref().take(non_ignored_chars); + if has_ignored_chars { + replaced = host_input.collect(); + host_str = &*replaced + } else { + for _ in host_input {} + host_str = &input_str[..bytes] + } + } + if scheme_type.is_special() && host_str.is_empty() { + return Err(ParseError::EmptyHost) + } + if !scheme_type.is_special() { + let host = Host::parse_opaque(host_str)?; + return Ok((host, input)); + } + let host = Host::parse(host_str)?; + Ok((host, input)) + } + + pub fn parse_file_host<'i>(&mut self, input: Input<'i>) + -> ParseResult<(bool, HostInternal, Input<'i>)> { + // Undo the Input abstraction here to avoid allocating in the common case + // where the host part of the input does not contain any tab or newline + let input_str = input.chars.as_str(); + let mut has_ignored_chars = false; + let mut non_ignored_chars = 0; + let mut bytes = 0; + for c in input_str.chars() { + match c { + '/' | '\\' | '?' | '#' => break, + '\t' | '\n' | '\r' => has_ignored_chars = true, + _ => non_ignored_chars += 1, + } + bytes += c.len_utf8(); + } + let replaced: String; + let host_str; + let mut remaining = input.clone(); + { + let host_input = remaining.by_ref().take(non_ignored_chars); + if has_ignored_chars { + replaced = host_input.collect(); + host_str = &*replaced + } else { + for _ in host_input {} + host_str = &input_str[..bytes] + } + } + if is_windows_drive_letter(host_str) { + return Ok((false, HostInternal::None, input)) + } + let host = if host_str.is_empty() { + HostInternal::None + } else { + match Host::parse(host_str)? { + Host::Domain(ref d) if d == "localhost" => HostInternal::None, + host => { + write!(&mut self.serialization, "{}", host).unwrap(); + host.into() + } + } + }; + Ok((true, host, remaining)) + } + + pub fn parse_port<P>(mut input: Input, default_port: P, + context: Context) + -> ParseResult<(Option<u16>, Input)> + where P: Fn() -> Option<u16> { + let mut port: u32 = 0; + let mut has_any_digit = false; + while let (Some(c), remaining) = input.split_first() { + if let Some(digit) = c.to_digit(10) { + port = port * 10 + digit; + if port > ::std::u16::MAX as u32 { + return Err(ParseError::InvalidPort) + } + has_any_digit = true; + } else if context == Context::UrlParser && !matches!(c, '/' | '\\' | '?' | '#') { + return Err(ParseError::InvalidPort) + } else { + break + } + input = remaining; + } + let mut opt_port = Some(port as u16); + if !has_any_digit || opt_port == default_port() { + opt_port = None; + } + Ok((opt_port, input)) + } + + pub fn parse_path_start<'i>(&mut self, scheme_type: SchemeType, has_host: &mut bool, + mut input: Input<'i>) + -> Input<'i> { + // Path start state + match input.split_first() { + (Some('/'), remaining) => input = remaining, + (Some('\\'), remaining) => if scheme_type.is_special() { + self.violation_fn.call(SyntaxViolation::Backslash); + input = remaining + }, + _ => {} + } + let path_start = self.serialization.len(); + self.serialization.push('/'); + self.parse_path(scheme_type, has_host, path_start, input) + } + + pub fn parse_path<'i>(&mut self, scheme_type: SchemeType, has_host: &mut bool, + path_start: usize, mut input: Input<'i>) + -> Input<'i> { + // Relative path state + debug_assert!(self.serialization.ends_with('/')); + loop { + let segment_start = self.serialization.len(); + let mut ends_with_slash = false; + loop { + let input_before_c = input.clone(); + let (c, utf8_c) = if let Some(x) = input.next_utf8() { x } else { break }; + match c { + '/' if self.context != Context::PathSegmentSetter => { + ends_with_slash = true; + break + }, + '\\' if self.context != Context::PathSegmentSetter && + scheme_type.is_special() => { + self.violation_fn.call(SyntaxViolation::Backslash); + ends_with_slash = true; + break + }, + '?' | '#' if self.context == Context::UrlParser => { + input = input_before_c; + break + }, + _ => { + self.check_url_code_point(c, &input); + if self.context == Context::PathSegmentSetter { + if scheme_type.is_special() { + self.serialization.extend(utf8_percent_encode( + utf8_c, SPECIAL_PATH_SEGMENT_ENCODE_SET)); + } else { + self.serialization.extend(utf8_percent_encode( + utf8_c, PATH_SEGMENT_ENCODE_SET)); + } + } else { + self.serialization.extend(utf8_percent_encode( + utf8_c, DEFAULT_ENCODE_SET)); + } + } + } + } + match &self.serialization[segment_start..] { + ".." | "%2e%2e" | "%2e%2E" | "%2E%2e" | "%2E%2E" | "%2e." | "%2E." | ".%2e" | ".%2E" => { + debug_assert!(self.serialization.as_bytes()[segment_start - 1] == b'/'); + self.serialization.truncate(segment_start - 1); // Truncate "/.." + self.pop_path(scheme_type, path_start); + if !self.serialization[path_start..].ends_with('/') { + self.serialization.push('/') + } + }, + "." | "%2e" | "%2E" => { + self.serialization.truncate(segment_start); + }, + _ => { + if scheme_type.is_file() && is_windows_drive_letter( + &self.serialization[path_start + 1..] + ) { + if self.serialization.ends_with('|') { + self.serialization.pop(); + self.serialization.push(':'); + } + if *has_host { + self.violation_fn.call(SyntaxViolation::FileWithHostAndWindowsDrive); + *has_host = false; // FIXME account for this in callers + } + } + if ends_with_slash { + self.serialization.push('/') + } + } + } + if !ends_with_slash { + break + } + } + input + } + + /// https://url.spec.whatwg.org/#pop-a-urls-path + fn pop_path(&mut self, scheme_type: SchemeType, path_start: usize) { + if self.serialization.len() > path_start { + let slash_position = self.serialization[path_start..].rfind('/').unwrap(); + // + 1 since rfind returns the position before the slash. + let segment_start = path_start + slash_position + 1; + // Don’t pop a Windows drive letter + // FIXME: *normalized* Windows drive letter + if !( + scheme_type.is_file() && + is_windows_drive_letter(&self.serialization[segment_start..]) + ) { + self.serialization.truncate(segment_start); + } + } + + } + + pub fn parse_cannot_be_a_base_path<'i>(&mut self, mut input: Input<'i>) -> Input<'i> { + loop { + let input_before_c = input.clone(); + match input.next_utf8() { + Some(('?', _)) | Some(('#', _)) if self.context == Context::UrlParser => { + return input_before_c + } + Some((c, utf8_c)) => { + self.check_url_code_point(c, &input); + self.serialization.extend(utf8_percent_encode( + utf8_c, SIMPLE_ENCODE_SET)); + } + None => return input + } + } + } + + fn with_query_and_fragment(mut self, scheme_end: u32, username_end: u32, + host_start: u32, host_end: u32, host: HostInternal, + port: Option<u16>, path_start: u32, remaining: Input) + -> ParseResult<Url> { + let (query_start, fragment_start) = + self.parse_query_and_fragment(scheme_end, remaining)?; + Ok(Url { + serialization: self.serialization, + scheme_end: scheme_end, + username_end: username_end, + host_start: host_start, + host_end: host_end, + host: host, + port: port, + path_start: path_start, + query_start: query_start, + fragment_start: fragment_start + }) + } + + /// Return (query_start, fragment_start) + fn parse_query_and_fragment(&mut self, scheme_end: u32, mut input: Input) + -> ParseResult<(Option<u32>, Option<u32>)> { + let mut query_start = None; + match input.next() { + Some('#') => {} + Some('?') => { + query_start = Some(to_u32(self.serialization.len())?); + self.serialization.push('?'); + let remaining = self.parse_query(scheme_end, input); + if let Some(remaining) = remaining { + input = remaining + } else { + return Ok((query_start, None)) + } + } + None => return Ok((None, None)), + _ => panic!("Programming error. parse_query_and_fragment() called without ? or #") + } + + let fragment_start = to_u32(self.serialization.len())?; + self.serialization.push('#'); + self.parse_fragment(input); + Ok((query_start, Some(fragment_start))) + } + + pub fn parse_query<'i>(&mut self, scheme_end: u32, mut input: Input<'i>) + -> Option<Input<'i>> { + let mut query = String::new(); // FIXME: use a streaming decoder instead + let mut remaining = None; + while let Some(c) = input.next() { + if c == '#' && self.context == Context::UrlParser { + remaining = Some(input); + break + } else { + self.check_url_code_point(c, &input); + query.push(c); + } + } + + let encoding = match &self.serialization[..scheme_end as usize] { + "http" | "https" | "file" | "ftp" | "gopher" => self.query_encoding_override, + _ => EncodingOverride::utf8(), + }; + let query_bytes = encoding.encode(query.into()); + self.serialization.extend(percent_encode(&query_bytes, QUERY_ENCODE_SET)); + remaining + } + + fn fragment_only(mut self, base_url: &Url, mut input: Input) -> ParseResult<Url> { + let before_fragment = match base_url.fragment_start { + Some(i) => base_url.slice(..i), + None => &*base_url.serialization, + }; + debug_assert!(self.serialization.is_empty()); + self.serialization.reserve(before_fragment.len() + input.chars.as_str().len()); + self.serialization.push_str(before_fragment); + self.serialization.push('#'); + let next = input.next(); + debug_assert!(next == Some('#')); + self.parse_fragment(input); + Ok(Url { + serialization: self.serialization, + fragment_start: Some(to_u32(before_fragment.len())?), + ..*base_url + }) + } + + pub fn parse_fragment(&mut self, mut input: Input) { + while let Some((c, utf8_c)) = input.next_utf8() { + if c == '\0' { + self.violation_fn.call(SyntaxViolation::NullInFragment) + } else { + self.check_url_code_point(c, &input); + self.serialization.extend(utf8_percent_encode(utf8_c, + SIMPLE_ENCODE_SET)); + } + } + } + + fn check_url_code_point(&self, c: char, input: &Input) { + let vfn = self.violation_fn; + if vfn.is_set() { + if c == '%' { + let mut input = input.clone(); + if !matches!((input.next(), input.next()), (Some(a), Some(b)) + if is_ascii_hex_digit(a) && is_ascii_hex_digit(b)) { + vfn.call(SyntaxViolation::PercentDecode) + } + } else if !is_url_code_point(c) { + vfn.call(SyntaxViolation::NonUrlCodePoint) + } + } + } +} + +#[inline] +fn is_ascii_hex_digit(c: char) -> bool { + matches!(c, 'a'...'f' | 'A'...'F' | '0'...'9') +} + +// Non URL code points: +// U+0000 to U+0020 (space) +// " # % < > [ \ ] ^ ` { | } +// U+007F to U+009F +// surrogates +// U+FDD0 to U+FDEF +// Last two of each plane: U+__FFFE to U+__FFFF for __ in 00 to 10 hex +#[inline] +fn is_url_code_point(c: char) -> bool { + matches!(c, + 'a'...'z' | + 'A'...'Z' | + '0'...'9' | + '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | + '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | + '\u{A0}'...'\u{D7FF}' | '\u{E000}'...'\u{FDCF}' | '\u{FDF0}'...'\u{FFFD}' | + '\u{10000}'...'\u{1FFFD}' | '\u{20000}'...'\u{2FFFD}' | + '\u{30000}'...'\u{3FFFD}' | '\u{40000}'...'\u{4FFFD}' | + '\u{50000}'...'\u{5FFFD}' | '\u{60000}'...'\u{6FFFD}' | + '\u{70000}'...'\u{7FFFD}' | '\u{80000}'...'\u{8FFFD}' | + '\u{90000}'...'\u{9FFFD}' | '\u{A0000}'...'\u{AFFFD}' | + '\u{B0000}'...'\u{BFFFD}' | '\u{C0000}'...'\u{CFFFD}' | + '\u{D0000}'...'\u{DFFFD}' | '\u{E1000}'...'\u{EFFFD}' | + '\u{F0000}'...'\u{FFFFD}' | '\u{100000}'...'\u{10FFFD}') +} + +/// https://url.spec.whatwg.org/#c0-controls-and-space +#[inline] +fn c0_control_or_space(ch: char) -> bool { + ch <= ' ' // U+0000 to U+0020 +} + +/// https://url.spec.whatwg.org/#ascii-alpha +#[inline] +pub fn ascii_alpha(ch: char) -> bool { + matches!(ch, 'a'...'z' | 'A'...'Z') +} + +#[inline] +pub fn to_u32(i: usize) -> ParseResult<u32> { + if i <= ::std::u32::MAX as usize { + Ok(i as u32) + } else { + Err(ParseError::Overflow) + } +} + +/// Wether the scheme is file:, the path has a single segment, and that segment +/// is a Windows drive letter +fn is_windows_drive_letter(segment: &str) -> bool { + segment.len() == 2 + && starts_with_windows_drive_letter(segment) +} + +fn starts_with_windows_drive_letter(s: &str) -> bool { + ascii_alpha(s.as_bytes()[0] as char) + && matches!(s.as_bytes()[1], b':' | b'|') +} + +fn starts_with_windows_drive_letter_segment(input: &Input) -> bool { + let mut input = input.clone(); + matches!((input.next(), input.next(), input.next()), (Some(a), Some(b), Some(c)) + if ascii_alpha(a) && matches!(b, ':' | '|') && matches!(c, '/' | '\\' | '?' | '#')) +} diff --git a/url/src/path_segments.rs b/url/src/path_segments.rs new file mode 100644 index 000000000..f5b7d51f9 --- /dev/null +++ b/url/src/path_segments.rs @@ -0,0 +1,217 @@ +// Copyright 2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use parser::{self, SchemeType, to_u32}; +use std::str; +use Url; + +/// Exposes methods to manipulate the path of an URL that is not cannot-be-base. +/// +/// The path always starts with a `/` slash, and is made of slash-separated segments. +/// There is always at least one segment (which may be the empty string). +/// +/// Examples: +/// +/// ```rust +/// use url::Url; +/// # use std::error::Error; +/// +/// # fn run() -> Result<(), Box<Error>> { +/// let mut url = Url::parse("mailto:me@example.com")?; +/// assert!(url.path_segments_mut().is_err()); +/// +/// let mut url = Url::parse("http://example.net/foo/index.html")?; +/// url.path_segments_mut().map_err(|_| "cannot be base")? +/// .pop().push("img").push("2/100%.png"); +/// assert_eq!(url.as_str(), "http://example.net/foo/img/2%2F100%25.png"); +/// # Ok(()) +/// # } +/// # run().unwrap(); +/// ``` +#[derive(Debug)] +pub struct PathSegmentsMut<'a> { + url: &'a mut Url, + after_first_slash: usize, + after_path: String, + old_after_path_position: u32, +} + +// Not re-exported outside the crate +pub fn new(url: &mut Url) -> PathSegmentsMut { + let after_path = url.take_after_path(); + let old_after_path_position = to_u32(url.serialization.len()).unwrap(); + debug_assert!(url.byte_at(url.path_start) == b'/'); + PathSegmentsMut { + after_first_slash: url.path_start as usize + "/".len(), + url: url, + old_after_path_position: old_after_path_position, + after_path: after_path, + } +} + +impl<'a> Drop for PathSegmentsMut<'a> { + fn drop(&mut self) { + self.url.restore_after_path(self.old_after_path_position, &self.after_path) + } +} + +impl<'a> PathSegmentsMut<'a> { + /// Remove all segments in the path, leaving the minimal `url.path() == "/"`. + /// + /// Returns `&mut Self` so that method calls can be chained. + /// + /// Example: + /// + /// ```rust + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let mut url = Url::parse("https://github.com/servo/rust-url/")?; + /// url.path_segments_mut().map_err(|_| "cannot be base")? + /// .clear().push("logout"); + /// assert_eq!(url.as_str(), "https://github.com/logout"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn clear(&mut self) -> &mut Self { + self.url.serialization.truncate(self.after_first_slash); + self + } + + /// Remove the last segment of this URL’s path if it is empty, + /// except if these was only one segment to begin with. + /// + /// In other words, remove one path trailing slash, if any, + /// unless it is also the initial slash (so this does nothing if `url.path() == "/")`. + /// + /// Returns `&mut Self` so that method calls can be chained. + /// + /// Example: + /// + /// ```rust + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let mut url = Url::parse("https://github.com/servo/rust-url/")?; + /// url.path_segments_mut().map_err(|_| "cannot be base")? + /// .push("pulls"); + /// assert_eq!(url.as_str(), "https://github.com/servo/rust-url//pulls"); + /// + /// let mut url = Url::parse("https://github.com/servo/rust-url/")?; + /// url.path_segments_mut().map_err(|_| "cannot be base")? + /// .pop_if_empty().push("pulls"); + /// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/pulls"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn pop_if_empty(&mut self) -> &mut Self { + if self.url.serialization[self.after_first_slash..].ends_with('/') { + self.url.serialization.pop(); + } + self + } + + /// Remove the last segment of this URL’s path. + /// + /// If the path only has one segment, make it empty such that `url.path() == "/"`. + /// + /// Returns `&mut Self` so that method calls can be chained. + pub fn pop(&mut self) -> &mut Self { + let last_slash = self.url.serialization[self.after_first_slash..].rfind('/').unwrap_or(0); + self.url.serialization.truncate(self.after_first_slash + last_slash); + self + } + + /// Append the given segment at the end of this URL’s path. + /// + /// See the documentation for `.extend()`. + /// + /// Returns `&mut Self` so that method calls can be chained. + pub fn push(&mut self, segment: &str) -> &mut Self { + self.extend(Some(segment)) + } + + /// Append each segment from the given iterator at the end of this URL’s path. + /// + /// Each segment is percent-encoded like in `Url::parse` or `Url::join`, + /// except that `%` and `/` characters are also encoded (to `%25` and `%2F`). + /// This is unlike `Url::parse` where `%` is left as-is in case some of the input + /// is already percent-encoded, and `/` denotes a path segment separator.) + /// + /// Note that, in addition to slashes between new segments, + /// this always adds a slash between the existing path and the new segments + /// *except* if the existing path is `"/"`. + /// If the previous last segment was empty (if the path had a trailing slash) + /// the path after `.extend()` will contain two consecutive slashes. + /// If that is undesired, call `.pop_if_empty()` first. + /// + /// To obtain a behavior similar to `Url::join`, call `.pop()` unconditionally first. + /// + /// Returns `&mut Self` so that method calls can be chained. + /// + /// Example: + /// + /// ```rust + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let mut url = Url::parse("https://github.com/")?; + /// let org = "servo"; + /// let repo = "rust-url"; + /// let issue_number = "188"; + /// url.path_segments_mut().map_err(|_| "cannot be base")? + /// .extend(&[org, repo, "issues", issue_number]); + /// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/issues/188"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + /// + /// In order to make sure that parsing the serialization of an URL gives the same URL, + /// a segment is ignored if it is `"."` or `".."`: + /// + /// ```rust + /// use url::Url; + /// # use std::error::Error; + /// + /// # fn run() -> Result<(), Box<Error>> { + /// let mut url = Url::parse("https://github.com/servo")?; + /// url.path_segments_mut().map_err(|_| "cannot be base")? + /// .extend(&["..", "rust-url", ".", "pulls"]); + /// assert_eq!(url.as_str(), "https://github.com/servo/rust-url/pulls"); + /// # Ok(()) + /// # } + /// # run().unwrap(); + /// ``` + pub fn extend<I>(&mut self, segments: I) -> &mut Self + where I: IntoIterator, I::Item: AsRef<str> { + let scheme_type = SchemeType::from(self.url.scheme()); + let path_start = self.url.path_start as usize; + self.url.mutate(|parser| { + parser.context = parser::Context::PathSegmentSetter; + for segment in segments { + let segment = segment.as_ref(); + if matches!(segment, "." | "..") { + continue + } + if parser.serialization.len() > path_start + 1 { + parser.serialization.push('/'); + } + let mut has_host = true; // FIXME account for this? + parser.parse_path(scheme_type, &mut has_host, path_start, + parser::Input::new(segment)); + } + }); + self + } +} diff --git a/url/src/quirks.rs b/url/src/quirks.rs new file mode 100644 index 000000000..0c7aaa894 --- /dev/null +++ b/url/src/quirks.rs @@ -0,0 +1,217 @@ +// Copyright 2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Getters and setters for URL components implemented per https://url.spec.whatwg.org/#api +//! +//! Unless you need to be interoperable with web browsers, +//! you probably want to use `Url` method instead. + +use {Url, Position, Host, ParseError, idna}; +use parser::{Parser, SchemeType, default_port, Context, Input}; + +/// https://url.spec.whatwg.org/#dom-url-domaintoascii +pub fn domain_to_ascii(domain: &str) -> String { + match Host::parse(domain) { + Ok(Host::Domain(domain)) => domain, + _ => String::new(), + } +} + +/// https://url.spec.whatwg.org/#dom-url-domaintounicode +pub fn domain_to_unicode(domain: &str) -> String { + match Host::parse(domain) { + Ok(Host::Domain(ref domain)) => { + let (unicode, _errors) = idna::domain_to_unicode(domain); + unicode + } + _ => String::new(), + } +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-href +pub fn href(url: &Url) -> &str { + url.as_str() +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-href +pub fn set_href(url: &mut Url, value: &str) -> Result<(), ParseError> { + *url = Url::parse(value)?; + Ok(()) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-origin +pub fn origin(url: &Url) -> String { + url.origin().ascii_serialization() +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-protocol +#[inline] +pub fn protocol(url: &Url) -> &str { + &url.as_str()[..url.scheme().len() + ":".len()] +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-protocol +pub fn set_protocol(url: &mut Url, mut new_protocol: &str) -> Result<(), ()> { + // The scheme state in the spec ignores everything after the first `:`, + // but `set_scheme` errors if there is more. + if let Some(position) = new_protocol.find(':') { + new_protocol = &new_protocol[..position]; + } + url.set_scheme(new_protocol) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-username +#[inline] +pub fn username(url: &Url) -> &str { + url.username() +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-username +pub fn set_username(url: &mut Url, new_username: &str) -> Result<(), ()> { + url.set_username(new_username) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-password +#[inline] +pub fn password(url: &Url) -> &str { + url.password().unwrap_or("") +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-password +pub fn set_password(url: &mut Url, new_password: &str) -> Result<(), ()> { + url.set_password(if new_password.is_empty() { None } else { Some(new_password) }) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-host +#[inline] +pub fn host(url: &Url) -> &str { + &url[Position::BeforeHost..Position::AfterPort] +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-host +pub fn set_host(url: &mut Url, new_host: &str) -> Result<(), ()> { + if url.cannot_be_a_base() { + return Err(()) + } + let host; + let opt_port; + { + let scheme = url.scheme(); + let result = Parser::parse_host(Input::new(new_host), SchemeType::from(scheme)); + match result { + Ok((h, remaining)) => { + host = h; + opt_port = if let Some(remaining) = remaining.split_prefix(':') { + Parser::parse_port(remaining, || default_port(scheme), Context::Setter) + .ok().map(|(port, _remaining)| port) + } else { + None + }; + } + Err(_) => return Err(()) + } + } + url.set_host_internal(host, opt_port); + Ok(()) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-hostname +#[inline] +pub fn hostname(url: &Url) -> &str { + url.host_str().unwrap_or("") +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-hostname +pub fn set_hostname(url: &mut Url, new_hostname: &str) -> Result<(), ()> { + if url.cannot_be_a_base() { + return Err(()) + } + let result = Parser::parse_host(Input::new(new_hostname), SchemeType::from(url.scheme())); + if let Ok((host, _remaining)) = result { + url.set_host_internal(host, None); + Ok(()) + } else { + Err(()) + } +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-port +#[inline] +pub fn port(url: &Url) -> &str { + &url[Position::BeforePort..Position::AfterPort] +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-port +pub fn set_port(url: &mut Url, new_port: &str) -> Result<(), ()> { + let result; + { + // has_host implies !cannot_be_a_base + let scheme = url.scheme(); + if !url.has_host() || url.host() == Some(Host::Domain("")) || scheme == "file" { + return Err(()) + } + result = Parser::parse_port(Input::new(new_port), || default_port(scheme), Context::Setter) + } + if let Ok((new_port, _remaining)) = result { + url.set_port_internal(new_port); + Ok(()) + } else { + Err(()) + } +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-pathname +#[inline] +pub fn pathname(url: &Url) -> &str { + url.path() +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-pathname +pub fn set_pathname(url: &mut Url, new_pathname: &str) { + if !url.cannot_be_a_base() { + url.set_path(new_pathname) + } +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-search +pub fn search(url: &Url) -> &str { + trim(&url[Position::AfterPath..Position::AfterQuery]) +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-search +pub fn set_search(url: &mut Url, new_search: &str) { + url.set_query(match new_search { + "" => None, + _ if new_search.starts_with('?') => Some(&new_search[1..]), + _ => Some(new_search), + }) +} + +/// Getter for https://url.spec.whatwg.org/#dom-url-hash +pub fn hash(url: &Url) -> &str { + trim(&url[Position::AfterQuery..]) +} + +/// Setter for https://url.spec.whatwg.org/#dom-url-hash +pub fn set_hash(url: &mut Url, new_hash: &str) { + if url.scheme() != "javascript" { + url.set_fragment(match new_hash { + "" => None, + _ if new_hash.starts_with('#') => Some(&new_hash[1..]), + _ => Some(new_hash), + }) + } +} + +fn trim(s: &str) -> &str { + if s.len() == 1 { + "" + } else { + s + } +} diff --git a/url/src/slicing.rs b/url/src/slicing.rs new file mode 100644 index 000000000..926f3c796 --- /dev/null +++ b/url/src/slicing.rs @@ -0,0 +1,182 @@ +// Copyright 2016 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Index}; +use Url; + +impl Index<RangeFull> for Url { + type Output = str; + fn index(&self, _: RangeFull) -> &str { + &self.serialization + } +} + +impl Index<RangeFrom<Position>> for Url { + type Output = str; + fn index(&self, range: RangeFrom<Position>) -> &str { + &self.serialization[self.index(range.start)..] + } +} + +impl Index<RangeTo<Position>> for Url { + type Output = str; + fn index(&self, range: RangeTo<Position>) -> &str { + &self.serialization[..self.index(range.end)] + } +} + +impl Index<Range<Position>> for Url { + type Output = str; + fn index(&self, range: Range<Position>) -> &str { + &self.serialization[self.index(range.start)..self.index(range.end)] + } +} + +/// Indicates a position within a URL based on its components. +/// +/// A range of positions can be used for slicing `Url`: +/// +/// ```rust +/// # use url::{Url, Position}; +/// # fn something(some_url: Url) { +/// let serialization: &str = &some_url[..]; +/// let serialization_without_fragment: &str = &some_url[..Position::AfterQuery]; +/// let authority: &str = &some_url[Position::BeforeUsername..Position::AfterPort]; +/// let data_url_payload: &str = &some_url[Position::BeforePath..Position::AfterQuery]; +/// let scheme_relative: &str = &some_url[Position::BeforeUsername..]; +/// # } +/// ``` +/// +/// In a pseudo-grammar (where `[`…`]?` makes a sub-sequence optional), +/// URL components and delimiters that separate them are: +/// +/// ```notrust +/// url = +/// scheme ":" +/// [ "//" [ username [ ":" password ]? "@" ]? host [ ":" port ]? ]? +/// path [ "?" query ]? [ "#" fragment ]? +/// ``` +/// +/// When a given component is not present, +/// its "before" and "after" position are the same +/// (so that `&some_url[BeforeFoo..AfterFoo]` is the empty string) +/// and component ordering is preserved +/// (so that a missing query "is between" a path and a fragment). +/// +/// The end of a component and the start of the next are either the same or separate +/// by a delimiter. +/// (Not that the initial `/` of a path is considered part of the path here, not a delimiter.) +/// For example, `&url[..BeforeFragment]` would include a `#` delimiter (if present in `url`), +/// so `&url[..AfterQuery]` might be desired instead. +/// +/// `BeforeScheme` and `AfterFragment` are always the start and end of the entire URL, +/// so `&url[BeforeScheme..X]` is the same as `&url[..X]` +/// and `&url[X..AfterFragment]` is the same as `&url[X..]`. +#[derive(Copy, Clone, Debug)] +pub enum Position { + BeforeScheme, + AfterScheme, + BeforeUsername, + AfterUsername, + BeforePassword, + AfterPassword, + BeforeHost, + AfterHost, + BeforePort, + AfterPort, + BeforePath, + AfterPath, + BeforeQuery, + AfterQuery, + BeforeFragment, + AfterFragment +} + +impl Url { + #[inline] + fn index(&self, position: Position) -> usize { + match position { + Position::BeforeScheme => 0, + + Position::AfterScheme => self.scheme_end as usize, + + Position::BeforeUsername => if self.has_authority() { + self.scheme_end as usize + "://".len() + } else { + debug_assert!(self.byte_at(self.scheme_end) == b':'); + debug_assert!(self.scheme_end + ":".len() as u32 == self.username_end); + self.scheme_end as usize + ":".len() + }, + + Position::AfterUsername => self.username_end as usize, + + Position::BeforePassword => if self.has_authority() && + self.byte_at(self.username_end) == b':' { + self.username_end as usize + ":".len() + } else { + debug_assert!(self.username_end == self.host_start); + self.username_end as usize + }, + + Position::AfterPassword => if self.has_authority() && + self.byte_at(self.username_end) == b':' { + debug_assert!(self.byte_at(self.host_start - "@".len() as u32) == b'@'); + self.host_start as usize - "@".len() + } else { + debug_assert!(self.username_end == self.host_start); + self.host_start as usize + }, + + Position::BeforeHost => self.host_start as usize, + + Position::AfterHost => self.host_end as usize, + + Position::BeforePort => if self.port.is_some() { + debug_assert!(self.byte_at(self.host_end) == b':'); + self.host_end as usize + ":".len() + } else { + self.host_end as usize + }, + + Position::AfterPort => self.path_start as usize, + + Position::BeforePath => self.path_start as usize, + + Position::AfterPath => match (self.query_start, self.fragment_start) { + (Some(q), _) => q as usize, + (None, Some(f)) => f as usize, + (None, None) => self.serialization.len(), + }, + + Position::BeforeQuery => match (self.query_start, self.fragment_start) { + (Some(q), _) => { + debug_assert!(self.byte_at(q) == b'?'); + q as usize + "?".len() + } + (None, Some(f)) => f as usize, + (None, None) => self.serialization.len(), + }, + + Position::AfterQuery => match self.fragment_start { + None => self.serialization.len(), + Some(f) => f as usize, + }, + + Position::BeforeFragment => match self.fragment_start { + Some(f) => { + debug_assert!(self.byte_at(f) == b'#'); + f as usize + "#".len() + } + None => self.serialization.len(), + }, + + Position::AfterFragment => self.serialization.len(), + } + } +} + diff --git a/url/tests/data.rs b/url/tests/data.rs new file mode 100644 index 000000000..e9203b1b0 --- /dev/null +++ b/url/tests/data.rs @@ -0,0 +1,200 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Data-driven tests + +extern crate rustc_serialize; +extern crate rustc_test as test; +extern crate url; + +use rustc_serialize::json::{self, Json}; +use url::{Url, quirks}; + +fn check_invariants(url: &Url) { + url.check_invariants().unwrap(); + #[cfg(feature="serde")] { + extern crate serde_json; + let bytes = serde_json::to_vec(url).unwrap(); + let new_url: Url = serde_json::from_slice(&bytes).unwrap(); + assert_eq!(url, &new_url); + } +} + + +fn run_parsing(input: &str, base: &str, expected: Result<ExpectedAttributes, ()>) { + let base = match Url::parse(&base) { + Ok(base) => base, + Err(_) if expected.is_err() => return, + Err(message) => panic!("Error parsing base {:?}: {}", base, message) + }; + let (url, expected) = match (base.join(&input), expected) { + (Ok(url), Ok(expected)) => (url, expected), + (Err(_), Err(())) => return, + (Err(message), Ok(_)) => panic!("Error parsing URL {:?}: {}", input, message), + (Ok(_), Err(())) => panic!("Expected a parse error for URL {:?}", input), + }; + + check_invariants(&url); + + macro_rules! assert_eq { + ($expected: expr, $got: expr) => { + { + let expected = $expected; + let got = $got; + assert!(expected == got, "{:?} != {} {:?} for URL {:?}", + got, stringify!($expected), expected, url); + } + } + } + + macro_rules! assert_attributes { + ($($attr: ident)+) => { + { + $( + assert_eq!(expected.$attr, quirks::$attr(&url)); + )+; + } + } + } + + assert_attributes!(href protocol username password host hostname port pathname search hash); + + if let Some(expected_origin) = expected.origin { + assert_eq!(expected_origin, quirks::origin(&url)); + } +} + +struct ExpectedAttributes { + href: String, + origin: Option<String>, + protocol: String, + username: String, + password: String, + host: String, + hostname: String, + port: String, + pathname: String, + search: String, + hash: String, +} + +trait JsonExt { + fn take(&mut self, key: &str) -> Option<Json>; + fn object(self) -> json::Object; + fn string(self) -> String; + fn take_string(&mut self, key: &str) -> String; +} + +impl JsonExt for Json { + fn take(&mut self, key: &str) -> Option<Json> { + self.as_object_mut().unwrap().remove(key) + } + + fn object(self) -> json::Object { + if let Json::Object(o) = self { o } else { panic!("Not a Json::Object") } + } + + fn string(self) -> String { + if let Json::String(s) = self { s } else { panic!("Not a Json::String") } + } + + fn take_string(&mut self, key: &str) -> String { + self.take(key).unwrap().string() + } +} + +fn collect_parsing<F: FnMut(String, test::TestFn)>(add_test: &mut F) { + // Copied form https://github.com/w3c/web-platform-tests/blob/master/url/ + let mut json = Json::from_str(include_str!("urltestdata.json")) + .expect("JSON parse error in urltestdata.json"); + for entry in json.as_array_mut().unwrap() { + if entry.is_string() { + continue // ignore comments + } + let base = entry.take_string("base"); + let input = entry.take_string("input"); + let expected = if entry.find("failure").is_some() { + Err(()) + } else { + Ok(ExpectedAttributes { + href: entry.take_string("href"), + origin: entry.take("origin").map(Json::string), + protocol: entry.take_string("protocol"), + username: entry.take_string("username"), + password: entry.take_string("password"), + host: entry.take_string("host"), + hostname: entry.take_string("hostname"), + port: entry.take_string("port"), + pathname: entry.take_string("pathname"), + search: entry.take_string("search"), + hash: entry.take_string("hash"), + }) + }; + add_test(format!("{:?} @ base {:?}", input, base), + test::TestFn::dyn_test_fn(move || run_parsing(&input, &base, expected))); + } +} + +fn collect_setters<F>(add_test: &mut F) where F: FnMut(String, test::TestFn) { + let mut json = Json::from_str(include_str!("setters_tests.json")) + .expect("JSON parse error in setters_tests.json"); + + macro_rules! setter { + ($attr: expr, $setter: ident) => {{ + let mut tests = json.take($attr).unwrap(); + for mut test in tests.as_array_mut().unwrap().drain(..) { + let comment = test.take("comment").map(Json::string).unwrap_or(String::new()); + let href = test.take_string("href"); + let new_value = test.take_string("new_value"); + let name = format!("{:?}.{} = {:?} {}", href, $attr, new_value, comment); + let mut expected = test.take("expected").unwrap(); + add_test(name, test::TestFn::dyn_test_fn(move || { + let mut url = Url::parse(&href).unwrap(); + check_invariants(&url); + let _ = quirks::$setter(&mut url, &new_value); + assert_attributes!(url, expected, + href protocol username password host hostname port pathname search hash); + check_invariants(&url); + })) + } + }} + } + macro_rules! assert_attributes { + ($url: expr, $expected: expr, $($attr: ident)+) => { + $( + if let Some(value) = $expected.take(stringify!($attr)) { + assert_eq!(quirks::$attr(&$url), value.string()) + } + )+ + } + } + setter!("protocol", set_protocol); + setter!("username", set_username); + setter!("password", set_password); + setter!("hostname", set_hostname); + setter!("host", set_host); + setter!("port", set_port); + setter!("pathname", set_pathname); + setter!("search", set_search); + setter!("hash", set_hash); +} + +fn main() { + let mut tests = Vec::new(); + { + let mut add_one = |name: String, run: test::TestFn| { + tests.push(test::TestDescAndFn { + desc: test::TestDesc::new(test::DynTestName(name)), + testfn: run, + }) + }; + collect_parsing(&mut add_one); + collect_setters(&mut add_one); + } + test::test_main(&std::env::args().collect::<Vec<_>>(), tests) +} diff --git a/url/tests/setters_tests.json b/url/tests/setters_tests.json new file mode 100644 index 000000000..a45171bf3 --- /dev/null +++ b/url/tests/setters_tests.json @@ -0,0 +1,1533 @@ +{ + "comment": [ + "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", + "", + "This file contains a JSON object.", + "Other than 'comment', each key is an attribute of the `URL` interface", + "defined in WHATWG’s URL Standard.", + "The values are arrays of test case objects for that attribute.", + "", + "To run a test case for the attribute `attr`:", + "", + "* Create a new `URL` object with the value for the 'href' key", + " the constructor single parameter. (Without a base URL.)", + " This must not throw.", + "* Set the attribute `attr` to (invoke its setter with)", + " with the value of for 'new_value' key.", + "* The value for the 'expected' key is another object.", + " For each `key` / `value` pair of that object,", + " get the attribute `key` (invoke its getter).", + " The returned string must be equal to `value`.", + "", + "Note: the 'href' setter is already covered by urltestdata.json." + ], + "protocol": [ + { + "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.", + "href": "a://example.net", + "new_value": "", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "href": "a://example.net", + "new_value": "b", + "expected": { + "href": "b://example.net/", + "protocol": "b:" + } + }, + { + "comment": "Upper-case ASCII is lower-cased", + "href": "a://example.net", + "new_value": "B", + "expected": { + "href": "b://example.net/", + "protocol": "b:" + } + }, + { + "comment": "Non-ASCII is rejected", + "href": "a://example.net", + "new_value": "é", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "comment": "No leading digit", + "href": "a://example.net", + "new_value": "0b", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "comment": "No leading punctuation", + "href": "a://example.net", + "new_value": "+b", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "href": "a://example.net", + "new_value": "bC0+-.", + "expected": { + "href": "bc0+-.://example.net/", + "protocol": "bc0+-.:" + } + }, + { + "comment": "Only some punctuation is acceptable", + "href": "a://example.net", + "new_value": "b,c", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "comment": "Non-ASCII is rejected", + "href": "a://example.net", + "new_value": "bé", + "expected": { + "href": "a://example.net/", + "protocol": "a:" + } + }, + { + "comment": "Can’t switch from file URL with no host", + "href": "file://localhost/", + "new_value": "http", + "expected": { + "href": "file:///", + "protocol": "file:" + } + }, + { + "href": "file:///test", + "new_value": "gopher", + "expected": { + "href": "file:///test", + "protocol": "file:" + } + }, + { + "href": "file:", + "new_value": "wss", + "expected": { + "href": "file:///", + "protocol": "file:" + } + }, + { + "comment": "Spec deviation: from special scheme to not is not problematic. https://github.com/whatwg/url/issues/104", + "href": "http://example.net", + "new_value": "b", + "expected": { + "href": "b://example.net/", + "protocol": "b:" + } + }, + { + "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", + "href": "mailto:me@example.net", + "new_value": "http", + "expected": { + "href": "mailto:me@example.net", + "protocol": "mailto:" + } + }, + { + "comment": "Spec deviation: from non-special scheme with a host to special is not problematic. https://github.com/whatwg/url/issues/104", + "href": "ssh://me@example.net", + "new_value": "http", + "expected": { + "href": "http://me@example.net/", + "protocol": "http:" + } + }, + { + "comment": "Stuff after the first ':' is ignored", + "href": "http://example.net", + "new_value": "https:foo : bar", + "expected": { + "href": "https://example.net/", + "protocol": "https:" + } + }, + { + "comment": "Stuff after the first ':' is ignored", + "href": "data:text/html,<p>Test", + "new_value": "view-source+data:foo : bar", + "expected": { + "href": "view-source+data:text/html,<p>Test", + "protocol": "view-source+data:" + } + } + ], + "username": [ + { + "comment": "No host means no username", + "href": "file:///home/you/index.html", + "new_value": "me", + "expected": { + "href": "file:///home/you/index.html", + "username": "" + } + }, + { + "comment": "No host means no username", + "href": "unix:/run/foo.socket", + "new_value": "me", + "expected": { + "href": "unix:/run/foo.socket", + "username": "" + } + }, + { + "comment": "Cannot-be-a-base means no username", + "href": "mailto:you@example.net", + "new_value": "me", + "expected": { + "href": "mailto:you@example.net", + "username": "" + } + }, + { + "href": "javascript:alert(1)", + "new_value": "wario", + "expected": { + "href": "javascript:alert(1)", + "username": "" + } + }, + { + "href": "http://example.net", + "new_value": "me", + "expected": { + "href": "http://me@example.net/", + "username": "me" + } + }, + { + "href": "http://:secret@example.net", + "new_value": "me", + "expected": { + "href": "http://me:secret@example.net/", + "username": "me" + } + }, + { + "href": "http://me@example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "username": "" + } + }, + { + "href": "http://me:secret@example.net", + "new_value": "", + "expected": { + "href": "http://:secret@example.net/", + "username": "" + } + }, + { + "comment": "UTF-8 percent encoding with the userinfo encode set.", + "href": "http://example.net", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is.", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://%c3%89t%C3%A9@example.net/", + "username": "%c3%89t%C3%A9" + } + }, + { + "href": "sc:///", + "new_value": "x", + "expected": { + "href": "sc:///", + "username": "" + } + }, + { + "href": "file://test/", + "new_value": "test", + "expected": { + "href": "file://test/", + "username": "" + } + }, + { + "href": "javascript://x/", + "new_value": "wario", + "expected": { + "href": "javascript://wario@x/", + "username": "wario" + } + } + ], + "password": [ + { + "comment": "No host means no password", + "href": "file:///home/me/index.html", + "new_value": "secret", + "expected": { + "href": "file:///home/me/index.html", + "password": "" + } + }, + { + "comment": "No host means no password", + "href": "unix:/run/foo.socket", + "new_value": "secret", + "expected": { + "href": "unix:/run/foo.socket", + "password": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "mailto:me@example.net", + "new_value": "secret", + "expected": { + "href": "mailto:me@example.net", + "password": "" + } + }, + { + "href": "http://example.net", + "new_value": "secret", + "expected": { + "href": "http://:secret@example.net/", + "password": "secret" + } + }, + { + "href": "http://me@example.net", + "new_value": "secret", + "expected": { + "href": "http://me:secret@example.net/", + "password": "secret" + } + }, + { + "href": "http://:secret@example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "password": "" + } + }, + { + "href": "http://me:secret@example.net", + "new_value": "", + "expected": { + "href": "http://me@example.net/", + "password": "" + } + }, + { + "comment": "UTF-8 percent encoding with the userinfo encode set.", + "href": "http://example.net", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is.", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://:%c3%89t%C3%A9@example.net/", + "password": "%c3%89t%C3%A9" + } + }, + { + "href": "sc:///", + "new_value": "x", + "expected": { + "href": "sc:///", + "password": "" + } + }, + { + "href": "file://test/", + "new_value": "test", + "expected": { + "href": "file://test/", + "password": "" + } + }, + { + "href": "javascript://x/", + "new_value": "bowser", + "expected": { + "href": "javascript://:bowser@x/", + "password": "bowser" + } + } + ], + "host": [ + { + "href": "sc://x/", + "new_value": "\u0009", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000A", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000D", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "#", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "/", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "?", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "@", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "ß", + "expected": { + "href": "sc://%C3%9F/", + "host": "%C3%9F", + "hostname": "%C3%9F" + } + }, + { + "comment": "Cannot-be-a-base means no host", + "href": "mailto:me@example.net", + "new_value": "example.com", + "expected": { + "href": "mailto:me@example.net", + "host": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "data:text/plain,Stuff", + "new_value": "example.net", + "expected": { + "href": "data:text/plain,Stuff", + "host": "" + } + }, + { + "href": "http://example.net", + "new_value": "example.com:8080", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port number is unchanged if not specified in the new value", + "href": "http://example.net:8080", + "new_value": "example.com", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port number is removed if empty in the new value: https://github.com/whatwg/url/pull/113", + "href": "http://example.net:8080", + "new_value": "example.com:", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "The empty host is not valid for special schemes", + "href": "http://example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net" + } + }, + { + "comment": "The empty host is OK for non-special schemes", + "href": "view-source+http://example.net/foo", + "new_value": "", + "expected": { + "href": "view-source+http:///foo", + "host": "" + } + }, + { + "comment": "Path-only URLs can gain a host", + "href": "a:/foo", + "new_value": "example.net", + "expected": { + "href": "a://example.net/foo", + "host": "example.net" + } + }, + { + "comment": "IPv4 address syntax is normalized", + "href": "http://example.net", + "new_value": "0x7F000001:8080", + "expected": { + "href": "http://127.0.0.1:8080/", + "host": "127.0.0.1:8080", + "hostname": "127.0.0.1", + "port": "8080" + } + }, + { + "comment": "IPv6 address syntax is normalized", + "href": "http://example.net", + "new_value": "[::0:01]:2", + "expected": { + "href": "http://[::1]:2/", + "host": "[::1]:2", + "hostname": "[::1]", + "port": "2" + } + }, + { + "comment": "Default port number is removed", + "href": "http://example.net", + "new_value": "example.com:80", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "https://example.net", + "new_value": "example.com:443", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Default port number is only removed for the relevant scheme", + "href": "https://example.net", + "new_value": "example.com:80", + "expected": { + "href": "https://example.com:80/", + "host": "example.com:80", + "hostname": "example.com", + "port": "80" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com/stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080/stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com?stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080?stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com#stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080#stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com:8080\\stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", + "href": "view-source+http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "view-source+http://example.net/path", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "view-source+http://example.net/path", + "new_value": "example.com:8080stuff2", + "expected": { + "href": "view-source+http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "example.com:8080stuff2", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "example.com:8080+2", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers", + "href": "http://example.net/path", + "new_value": "example.com:65535", + "expected": { + "href": "http://example.com:65535/path", + "host": "example.com:65535", + "hostname": "example.com", + "port": "65535" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", + "href": "http://example.net/path", + "new_value": "example.com:65536", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Broken IPv6", + "href": "http://example.net/", + "new_value": "[google.com]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.4x]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + } + ], + "hostname": [ + { + "href": "sc://x/", + "new_value": "\u0009", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000A", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000D", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "#", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "/", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "?", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "@", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "comment": "Cannot-be-a-base means no host", + "href": "mailto:me@example.net", + "new_value": "example.com", + "expected": { + "href": "mailto:me@example.net", + "host": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "data:text/plain,Stuff", + "new_value": "example.net", + "expected": { + "href": "data:text/plain,Stuff", + "host": "" + } + }, + { + "href": "http://example.net:8080", + "new_value": "example.com", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "The empty host is not valid for special schemes", + "href": "http://example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net" + } + }, + { + "comment": "The empty host is OK for non-special schemes", + "href": "view-source+http://example.net/foo", + "new_value": "", + "expected": { + "href": "view-source+http:///foo", + "host": "" + } + }, + { + "comment": "Path-only URLs can gain a host", + "href": "a:/foo", + "new_value": "example.net", + "expected": { + "href": "a://example.net/foo", + "host": "example.net" + } + }, + { + "comment": "IPv4 address syntax is normalized", + "href": "http://example.net:8080", + "new_value": "0x7F000001", + "expected": { + "href": "http://127.0.0.1:8080/", + "host": "127.0.0.1:8080", + "hostname": "127.0.0.1", + "port": "8080" + } + }, + { + "comment": "IPv6 address syntax is normalized", + "href": "http://example.net", + "new_value": "[::0:01]", + "expected": { + "href": "http://[::1]/", + "host": "[::1]", + "hostname": "[::1]", + "port": "" + } + }, + { + "comment": "Stuff after a : delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a : delimiter is ignored", + "href": "http://example.net:8080/path", + "new_value": "example.com:", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com/stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com?stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com#stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", + "href": "view-source+http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "view-source+http://example.net/path", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Broken IPv6", + "href": "http://example.net/", + "new_value": "[google.com]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.4x]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + } + ], + "port": [ + { + "href": "http://example.net", + "new_value": "8080", + "expected": { + "href": "http://example.net:8080/", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port number is removed if empty is the new value", + "href": "http://example.net:8080", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "http://example.net:8080", + "new_value": "80", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "https://example.net:4433", + "new_value": "443", + "expected": { + "href": "https://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is only removed for the relevant scheme", + "href": "https://example.net", + "new_value": "80", + "expected": { + "href": "https://example.net:80/", + "host": "example.net:80", + "hostname": "example.net", + "port": "80" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080/stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080?stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080#stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "8080\\stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "view-source+http://example.net/path", + "new_value": "8080stuff2", + "expected": { + "href": "view-source+http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "8080stuff2", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "8080+2", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers", + "href": "http://example.net/path", + "new_value": "65535", + "expected": { + "href": "http://example.net:65535/path", + "host": "example.net:65535", + "hostname": "example.net", + "port": "65535" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error", + "href": "http://example.net:8080/path", + "new_value": "65536", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error", + "href": "non-special://example.net:8080/path", + "new_value": "65536", + "expected": { + "href": "non-special://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "href": "file://test/", + "new_value": "12", + "expected": { + "href": "file://test/", + "port": "" + } + }, + { + "href": "file://localhost/", + "new_value": "12", + "expected": { + "href": "file:///", + "port": "" + } + }, + { + "href": "non-base:value", + "new_value": "12", + "expected": { + "href": "non-base:value", + "port": "" + } + }, + { + "href": "sc:///", + "new_value": "12", + "expected": { + "href": "sc:///", + "port": "" + } + }, + { + "href": "sc://x/", + "new_value": "12", + "expected": { + "href": "sc://x:12/", + "port": "12" + } + }, + { + "href": "javascript://x/", + "new_value": "12", + "expected": { + "href": "javascript://x:12/", + "port": "12" + } + } + ], + "pathname": [ + { + "comment": "Cannot-be-a-base don’t have a path", + "href": "mailto:me@example.net", + "new_value": "/foo", + "expected": { + "href": "mailto:me@example.net", + "pathname": "me@example.net" + } + }, + { + "href": "unix:/run/foo.socket?timeout=10", + "new_value": "/var/log/../run/bar.socket", + "expected": { + "href": "unix:/var/run/bar.socket?timeout=10", + "pathname": "/var/run/bar.socket" + } + }, + { + "href": "https://example.net#nav", + "new_value": "home", + "expected": { + "href": "https://example.net/home#nav", + "pathname": "/home" + } + }, + { + "href": "https://example.net#nav", + "new_value": "../home", + "expected": { + "href": "https://example.net/home#nav", + "pathname": "/home" + } + }, + { + "comment": "\\ is a segment delimiter for 'special' URLs", + "href": "http://example.net/home?lang=fr#nav", + "new_value": "\\a\\%2E\\b\\%2e.\\c", + "expected": { + "href": "http://example.net/a/c?lang=fr#nav", + "pathname": "/a/c" + } + }, + { + "comment": "\\ is *not* a segment delimiter for non-'special' URLs", + "href": "view-source+http://example.net/home?lang=fr#nav", + "new_value": "\\a\\%2E\\b\\%2e.\\c", + "expected": { + "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav", + "pathname": "/\\a\\%2E\\b\\%2e.\\c" + } + }, + { + "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed. Leading or training C0 controls and space are removed.", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + "pathname": "/!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.", + "href": "http://example.net", + "new_value": "%2e%2E%c3%89té", + "expected": { + "href": "http://example.net/%2e%2E%c3%89t%C3%A9", + "pathname": "/%2e%2E%c3%89t%C3%A9" + } + }, + { + "comment": "? needs to be encoded", + "href": "http://example.net", + "new_value": "?", + "expected": { + "href": "http://example.net/%3F", + "pathname": "/%3F" + } + }, + { + "comment": "# needs to be encoded", + "href": "http://example.net", + "new_value": "#", + "expected": { + "href": "http://example.net/%23", + "pathname": "/%23" + } + }, + { + "comment": "? needs to be encoded, non-special scheme", + "href": "sc://example.net", + "new_value": "?", + "expected": { + "href": "sc://example.net/%3F", + "pathname": "/%3F" + } + }, + { + "comment": "# needs to be encoded, non-special scheme", + "href": "sc://example.net", + "new_value": "#", + "expected": { + "href": "sc://example.net/%23", + "pathname": "/%23" + } + } + ], + "search": [ + { + "href": "https://example.net#nav", + "new_value": "lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "?lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "??lang=fr", + "expected": { + "href": "https://example.net/??lang=fr#nav", + "search": "??lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "?", + "expected": { + "href": "https://example.net/?#nav", + "search": "" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "", + "expected": { + "href": "https://example.net/#nav", + "search": "" + } + }, + { + "href": "https://example.net?lang=en-US", + "new_value": "", + "expected": { + "href": "https://example.net/", + "search": "" + } + }, + { + "href": "https://example.net", + "new_value": "", + "expected": { + "href": "https://example.net/", + "search": "" + } + }, + { + "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed. Leading or training C0 controls and space are removed.", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/?!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + "search": "?!%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://example.net/?%c3%89t%C3%A9", + "search": "?%c3%89t%C3%A9" + } + } + ], + "hash": [ + { + "href": "https://example.net", + "new_value": "main", + "expected": { + "href": "https://example.net/#main", + "hash": "#main" + } + }, + { + "href": "https://example.net#nav", + "new_value": "main", + "expected": { + "href": "https://example.net/#main", + "hash": "#main" + } + }, + { + "href": "https://example.net?lang=en-US", + "new_value": "##nav", + "expected": { + "href": "https://example.net/?lang=en-US##nav", + "hash": "##nav" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "#main", + "expected": { + "href": "https://example.net/?lang=en-US#main", + "hash": "#main" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "#", + "expected": { + "href": "https://example.net/?lang=en-US#", + "hash": "" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "", + "expected": { + "href": "https://example.net/?lang=en-US", + "hash": "" + } + }, + { + "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + "hash": "#!%01%1F !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://example.net/#%c3%89t%C3%A9", + "hash": "#%c3%89t%C3%A9" + } + } + ] +} diff --git a/url/tests/unit.rs b/url/tests/unit.rs new file mode 100644 index 000000000..62401c943 --- /dev/null +++ b/url/tests/unit.rs @@ -0,0 +1,556 @@ +// Copyright 2013-2014 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unit tests + +#[macro_use] +extern crate url; + +use std::ascii::AsciiExt; +use std::borrow::Cow; +use std::cell::{Cell, RefCell}; +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::path::{Path, PathBuf}; +use url::{Host, HostAndPort, Url, form_urlencoded}; + +#[test] +fn size() { + use std::mem::size_of; + assert_eq!(size_of::<Url>(), size_of::<Option<Url>>()); +} + +macro_rules! assert_from_file_path { + ($path: expr) => { assert_from_file_path!($path, $path) }; + ($path: expr, $url_path: expr) => {{ + let url = Url::from_file_path(Path::new($path)).unwrap(); + assert_eq!(url.host(), None); + assert_eq!(url.path(), $url_path); + assert_eq!(url.to_file_path(), Ok(PathBuf::from($path))); + }}; +} + + + +#[test] +fn new_file_paths() { + if cfg!(unix) { + assert_eq!(Url::from_file_path(Path::new("relative")), Err(())); + assert_eq!(Url::from_file_path(Path::new("../relative")), Err(())); + } + if cfg!(windows) { + assert_eq!(Url::from_file_path(Path::new("relative")), Err(())); + assert_eq!(Url::from_file_path(Path::new(r"..\relative")), Err(())); + assert_eq!(Url::from_file_path(Path::new(r"\drive-relative")), Err(())); + assert_eq!(Url::from_file_path(Path::new(r"\\ucn\")), Err(())); + } + + if cfg!(unix) { + assert_from_file_path!("/foo/bar"); + assert_from_file_path!("/foo/ba\0r", "/foo/ba%00r"); + assert_from_file_path!("/foo/ba%00r", "/foo/ba%2500r"); + } +} + +#[test] +#[cfg(unix)] +fn new_path_bad_utf8() { + use std::ffi::OsStr; + use std::os::unix::prelude::*; + + let url = Url::from_file_path(Path::new(OsStr::from_bytes(b"/foo/ba\x80r"))).unwrap(); + let os_str = OsStr::from_bytes(b"/foo/ba\x80r"); + assert_eq!(url.to_file_path(), Ok(PathBuf::from(os_str))); +} + +#[test] +fn new_path_windows_fun() { + if cfg!(windows) { + assert_from_file_path!(r"C:\foo\bar", "/C:/foo/bar"); + assert_from_file_path!("C:\\foo\\ba\0r", "/C:/foo/ba%00r"); + + // Invalid UTF-8 + assert!(Url::parse("file:///C:/foo/ba%80r").unwrap().to_file_path().is_err()); + + // test windows canonicalized path + let path = PathBuf::from(r"\\?\C:\foo\bar"); + assert!(Url::from_file_path(path).is_ok()); + + // Percent-encoded drive letter + let url = Url::parse("file:///C%3A/foo/bar").unwrap(); + assert_eq!(url.to_file_path(), Ok(PathBuf::from(r"C:\foo\bar"))); + } +} + + +#[test] +fn new_directory_paths() { + if cfg!(unix) { + assert_eq!(Url::from_directory_path(Path::new("relative")), Err(())); + assert_eq!(Url::from_directory_path(Path::new("../relative")), Err(())); + + let url = Url::from_directory_path(Path::new("/foo/bar")).unwrap(); + assert_eq!(url.host(), None); + assert_eq!(url.path(), "/foo/bar/"); + } + if cfg!(windows) { + assert_eq!(Url::from_directory_path(Path::new("relative")), Err(())); + assert_eq!(Url::from_directory_path(Path::new(r"..\relative")), Err(())); + assert_eq!(Url::from_directory_path(Path::new(r"\drive-relative")), Err(())); + assert_eq!(Url::from_directory_path(Path::new(r"\\ucn\")), Err(())); + + let url = Url::from_directory_path(Path::new(r"C:\foo\bar")).unwrap(); + assert_eq!(url.host(), None); + assert_eq!(url.path(), "/C:/foo/bar/"); + } +} + +#[test] +fn path_backslash_fun() { + let mut special_url = "http://foobar.com".parse::<Url>().unwrap(); + special_url.path_segments_mut().unwrap().push("foo\\bar"); + assert_eq!(special_url.as_str(), "http://foobar.com/foo%5Cbar"); + + let mut nonspecial_url = "thing://foobar.com".parse::<Url>().unwrap(); + nonspecial_url.path_segments_mut().unwrap().push("foo\\bar"); + assert_eq!(nonspecial_url.as_str(), "thing://foobar.com/foo\\bar"); +} + +#[test] +fn from_str() { + assert!("http://testing.com/this".parse::<Url>().is_ok()); +} + +#[test] +fn parse_with_params() { + let url = Url::parse_with_params("http://testing.com/this?dont=clobberme", + &[("lang", "rust")]).unwrap(); + + assert_eq!(url.as_str(), "http://testing.com/this?dont=clobberme&lang=rust"); +} + +#[test] +fn issue_124() { + let url: Url = "file:a".parse().unwrap(); + assert_eq!(url.path(), "/a"); + let url: Url = "file:...".parse().unwrap(); + assert_eq!(url.path(), "/..."); + let url: Url = "file:..".parse().unwrap(); + assert_eq!(url.path(), "/"); +} + +#[test] +fn test_equality() { + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + fn check_eq(a: &Url, b: &Url) { + assert_eq!(a, b); + + let mut h1 = DefaultHasher::new(); + a.hash(&mut h1); + let mut h2 = DefaultHasher::new(); + b.hash(&mut h2); + assert_eq!(h1.finish(), h2.finish()); + } + + fn url(s: &str) -> Url { + let rv = s.parse().unwrap(); + check_eq(&rv, &rv); + rv + } + + // Doesn't care if default port is given. + let a: Url = url("https://example.com/"); + let b: Url = url("https://example.com:443/"); + check_eq(&a, &b); + + // Different ports + let a: Url = url("http://example.com/"); + let b: Url = url("http://example.com:8080/"); + assert!(a != b, "{:?} != {:?}", a, b); + + // Different scheme + let a: Url = url("http://example.com/"); + let b: Url = url("https://example.com/"); + assert_ne!(a, b); + + // Different host + let a: Url = url("http://foo.com/"); + let b: Url = url("http://bar.com/"); + assert_ne!(a, b); + + // Missing path, automatically substituted. Semantically the same. + let a: Url = url("http://foo.com"); + let b: Url = url("http://foo.com/"); + check_eq(&a, &b); +} + +#[test] +fn host() { + fn assert_host(input: &str, host: Host<&str>) { + assert_eq!(Url::parse(input).unwrap().host(), Some(host)); + } + assert_host("http://www.mozilla.org", Host::Domain("www.mozilla.org")); + assert_host("http://1.35.33.49", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49))); + assert_host("http://[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]", Host::Ipv6(Ipv6Addr::new( + 0x2001, 0x0db8, 0x85a3, 0x08d3, 0x1319, 0x8a2e, 0x0370, 0x7344))); + assert_host("http://1.35.+33.49", Host::Domain("1.35.+33.49")); + assert_host("http://[::]", Host::Ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0))); + assert_host("http://[::1]", Host::Ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))); + assert_host("http://0x1.0X23.0x21.061", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49))); + assert_host("http://0x1232131", Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49))); + assert_host("http://111", Host::Ipv4(Ipv4Addr::new(0, 0, 0, 111))); + assert_host("http://2..2.3", Host::Domain("2..2.3")); + assert!(Url::parse("http://42.0x1232131").is_err()); + assert!(Url::parse("http://192.168.0.257").is_err()); +} + +#[test] +fn host_serialization() { + // libstd’s `Display for Ipv6Addr` serializes 0:0:0:0:0:0:_:_ and 0:0:0:0:0:ffff:_:_ + // using IPv4-like syntax, as suggested in https://tools.ietf.org/html/rfc5952#section-4 + // but https://url.spec.whatwg.org/#concept-ipv6-serializer specifies not to. + + // Not [::0.0.0.2] / [::ffff:0.0.0.2] + assert_eq!(Url::parse("http://[0::2]").unwrap().host_str(), Some("[::2]")); + assert_eq!(Url::parse("http://[0::ffff:0:2]").unwrap().host_str(), Some("[::ffff:0:2]")); +} + +#[test] +fn test_idna() { + assert!("http://goșu.ro".parse::<Url>().is_ok()); + assert_eq!(Url::parse("http://☃.net/").unwrap().host(), Some(Host::Domain("xn--n3h.net"))); + assert!("https://r2---sn-huoa-cvhl.googlevideo.com/crossdomain.xml".parse::<Url>().is_ok()); +} + +#[test] +fn test_serialization() { + let data = [ + ("http://example.com/", "http://example.com/"), + ("http://addslash.com", "http://addslash.com/"), + ("http://@emptyuser.com/", "http://emptyuser.com/"), + ("http://:@emptypass.com/", "http://emptypass.com/"), + ("http://user@user.com/", "http://user@user.com/"), + ("http://user:pass@userpass.com/", "http://user:pass@userpass.com/"), + ("http://slashquery.com/path/?q=something", "http://slashquery.com/path/?q=something"), + ("http://noslashquery.com/path?q=something", "http://noslashquery.com/path?q=something") + ]; + for &(input, result) in &data { + let url = Url::parse(input).unwrap(); + assert_eq!(url.as_str(), result); + } +} + +#[test] +fn test_form_urlencoded() { + let pairs: &[(Cow<str>, Cow<str>)] = &[ + ("foo".into(), "é&".into()), + ("bar".into(), "".into()), + ("foo".into(), "#".into()) + ]; + let encoded = form_urlencoded::Serializer::new(String::new()).extend_pairs(pairs).finish(); + assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23"); + assert_eq!(form_urlencoded::parse(encoded.as_bytes()).collect::<Vec<_>>(), pairs.to_vec()); +} + +#[test] +fn test_form_serialize() { + let encoded = form_urlencoded::Serializer::new(String::new()) + .append_pair("foo", "é&") + .append_pair("bar", "") + .append_pair("foo", "#") + .finish(); + assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23"); +} + +#[test] +fn form_urlencoded_custom_encoding_override() { + let encoded = form_urlencoded::Serializer::new(String::new()) + .custom_encoding_override(|s| s.as_bytes().to_ascii_uppercase().into()) + .append_pair("foo", "bar") + .finish(); + assert_eq!(encoded, "FOO=BAR"); +} + +#[test] +fn host_and_port_display() { + assert_eq!( + format!( + "{}", + HostAndPort{ host: Host::Domain("www.mozilla.org"), port: 80} + ), + "www.mozilla.org:80" + ); + assert_eq!( + format!( + "{}", + HostAndPort::<String>{ host: Host::Ipv4(Ipv4Addr::new(1, 35, 33, 49)), port: 65535 } + ), + "1.35.33.49:65535" + ); + assert_eq!( + format!( + "{}", + HostAndPort::<String>{ + host: Host::Ipv6(Ipv6Addr::new( + 0x2001, 0x0db8, 0x85a3, 0x08d3, 0x1319, 0x8a2e, 0x0370, 0x7344 + )), + port: 1337 + }) + , + "[2001:db8:85a3:8d3:1319:8a2e:370:7344]:1337" + ) +} + +#[test] +/// https://github.com/servo/rust-url/issues/61 +fn issue_61() { + let mut url = Url::parse("http://mozilla.org").unwrap(); + url.set_scheme("https").unwrap(); + assert_eq!(url.port(), None); + assert_eq!(url.port_or_known_default(), Some(443)); + url.check_invariants().unwrap(); +} + +#[test] +#[cfg(not(windows))] +/// https://github.com/servo/rust-url/issues/197 +fn issue_197() { + let mut url = Url::from_file_path("/").expect("Failed to parse path"); + url.check_invariants().unwrap(); + assert_eq!(url, Url::parse("file:///").expect("Failed to parse path + protocol")); + url.path_segments_mut().expect("path_segments_mut").pop_if_empty(); +} + +#[test] +fn issue_241() { + Url::parse("mailto:").unwrap().cannot_be_a_base(); +} + +#[test] +/// https://github.com/servo/rust-url/issues/222 +fn append_trailing_slash() { + let mut url: Url = "http://localhost:6767/foo/bar?a=b".parse().unwrap(); + url.check_invariants().unwrap(); + url.path_segments_mut().unwrap().push(""); + url.check_invariants().unwrap(); + assert_eq!(url.to_string(), "http://localhost:6767/foo/bar/?a=b"); +} + +#[test] +/// https://github.com/servo/rust-url/issues/227 +fn extend_query_pairs_then_mutate() { + let mut url: Url = "http://localhost:6767/foo/bar".parse().unwrap(); + url.query_pairs_mut().extend_pairs(vec![ ("auth", "my-token") ].into_iter()); + url.check_invariants().unwrap(); + assert_eq!(url.to_string(), "http://localhost:6767/foo/bar?auth=my-token"); + url.path_segments_mut().unwrap().push("some_other_path"); + url.check_invariants().unwrap(); + assert_eq!(url.to_string(), "http://localhost:6767/foo/bar/some_other_path?auth=my-token"); +} + +#[test] +/// https://github.com/servo/rust-url/issues/222 +fn append_empty_segment_then_mutate() { + let mut url: Url = "http://localhost:6767/foo/bar?a=b".parse().unwrap(); + url.check_invariants().unwrap(); + url.path_segments_mut().unwrap().push("").pop(); + url.check_invariants().unwrap(); + assert_eq!(url.to_string(), "http://localhost:6767/foo/bar?a=b"); +} + +#[test] +/// https://github.com/servo/rust-url/issues/243 +fn test_set_host() { + let mut url = Url::parse("https://example.net/hello").unwrap(); + url.set_host(Some("foo.com")).unwrap(); + assert_eq!(url.as_str(), "https://foo.com/hello"); + assert!(url.set_host(None).is_err()); + assert_eq!(url.as_str(), "https://foo.com/hello"); + assert!(url.set_host(Some("")).is_err()); + assert_eq!(url.as_str(), "https://foo.com/hello"); + + let mut url = Url::parse("foobar://example.net/hello").unwrap(); + url.set_host(None).unwrap(); + assert_eq!(url.as_str(), "foobar:/hello"); + + let mut url = Url::parse("foo://ș").unwrap(); + assert_eq!(url.as_str(), "foo://%C8%99/"); + url.set_host(Some("goșu.ro")).unwrap(); + assert_eq!(url.as_str(), "foo://go%C8%99u.ro/"); +} + +#[test] +// https://github.com/servo/rust-url/issues/166 +fn test_leading_dots() { + assert_eq!(Host::parse(".org").unwrap(), Host::Domain(".org".to_owned())); + assert_eq!(Url::parse("file://./foo").unwrap().domain(), Some(".")); +} + +// This is testing that the macro produces buildable code when invoked +// inside both a module and a function +#[test] +fn define_encode_set_scopes() { + use url::percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET}; + + define_encode_set! { + /// This encode set is used in the URL parser for query strings. + pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'} + } + + assert_eq!(utf8_percent_encode("foo bar", QUERY_ENCODE_SET).collect::<String>(), "foo%20bar"); + + mod m { + use url::percent_encoding::{utf8_percent_encode, SIMPLE_ENCODE_SET}; + + define_encode_set! { + /// This encode set is used in the URL parser for query strings. + pub QUERY_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '"', '#', '<', '>'} + } + + pub fn test() { + assert_eq!(utf8_percent_encode("foo bar", QUERY_ENCODE_SET).collect::<String>(), "foo%20bar"); + } + } + + m::test(); +} + +#[test] +/// https://github.com/servo/rust-url/issues/302 +fn test_origin_hash() { + use std::hash::{Hash,Hasher}; + use std::collections::hash_map::DefaultHasher; + + fn hash<T: Hash>(value: &T) -> u64 { + let mut hasher = DefaultHasher::new(); + value.hash(&mut hasher); + hasher.finish() + } + + let origin = &Url::parse("http://example.net/").unwrap().origin(); + + let origins_to_compare = [ + Url::parse("http://example.net:80/").unwrap().origin(), + Url::parse("http://example.net:81/").unwrap().origin(), + Url::parse("http://example.net").unwrap().origin(), + Url::parse("http://example.net/hello").unwrap().origin(), + Url::parse("https://example.net").unwrap().origin(), + Url::parse("ftp://example.net").unwrap().origin(), + Url::parse("file://example.net").unwrap().origin(), + Url::parse("http://user@example.net/").unwrap().origin(), + Url::parse("http://user:pass@example.net/").unwrap().origin(), + ]; + + for origin_to_compare in &origins_to_compare { + if origin == origin_to_compare { + assert_eq!(hash(origin), hash(origin_to_compare)); + } else { + assert_ne!(hash(origin), hash(origin_to_compare)); + } + } + + let opaque_origin = Url::parse("file://example.net").unwrap().origin(); + let same_opaque_origin = Url::parse("file://example.net").unwrap().origin(); + let other_opaque_origin = Url::parse("file://other").unwrap().origin(); + + assert_ne!(hash(&opaque_origin), hash(&same_opaque_origin)); + assert_ne!(hash(&opaque_origin), hash(&other_opaque_origin)); +} + +#[test] +fn test_windows_unc_path() { + if !cfg!(windows) { + return + } + + let url = Url::from_file_path(Path::new(r"\\host\share\path\file.txt")).unwrap(); + assert_eq!(url.as_str(), "file://host/share/path/file.txt"); + + let url = Url::from_file_path(Path::new(r"\\höst\share\path\file.txt")).unwrap(); + assert_eq!(url.as_str(), "file://xn--hst-sna/share/path/file.txt"); + + let url = Url::from_file_path(Path::new(r"\\192.168.0.1\share\path\file.txt")).unwrap(); + assert_eq!(url.host(), Some(Host::Ipv4(Ipv4Addr::new(192, 168, 0, 1)))); + + let path = url.to_file_path().unwrap(); + assert_eq!(path.to_str(), Some(r"\\192.168.0.1\share\path\file.txt")); + + // Another way to write these: + let url = Url::from_file_path(Path::new(r"\\?\UNC\host\share\path\file.txt")).unwrap(); + assert_eq!(url.as_str(), "file://host/share/path/file.txt"); + + // Paths starting with "\\.\" (Local Device Paths) are intentionally not supported. + let url = Url::from_file_path(Path::new(r"\\.\some\path\file.txt")); + assert!(url.is_err()); +} + +// Test the now deprecated log_syntax_violation method for backward +// compatibility +#[test] +#[allow(deprecated)] +fn test_old_log_violation_option() { + let violation = Cell::new(None); + let url = Url::options() + .log_syntax_violation(Some(&|s| violation.set(Some(s.to_owned())))) + .parse("http:////mozilla.org:42").unwrap(); + assert_eq!(url.port(), Some(42)); + + let violation = violation.take(); + assert_eq!(violation, Some("expected //".to_string())); +} + +#[test] +fn test_syntax_violation_callback() { + use url::SyntaxViolation::*; + let violation = Cell::new(None); + let url = Url::options() + .syntax_violation_callback(Some(&|v| violation.set(Some(v)))) + .parse("http:////mozilla.org:42").unwrap(); + assert_eq!(url.port(), Some(42)); + + let v = violation.take().unwrap(); + assert_eq!(v, ExpectedDoubleSlash); + assert_eq!(v.description(), "expected //"); +} + +#[test] +fn test_syntax_violation_callback_lifetimes() { + use url::SyntaxViolation::*; + let violation = Cell::new(None); + let vfn = |s| violation.set(Some(s)); + + let url = Url::options() + .syntax_violation_callback(Some(&vfn)) + .parse("http:////mozilla.org:42").unwrap(); + assert_eq!(url.port(), Some(42)); + assert_eq!(violation.take(), Some(ExpectedDoubleSlash)); + + let url = Url::options() + .syntax_violation_callback(Some(&vfn)) + .parse("http://mozilla.org\\path").unwrap(); + assert_eq!(url.path(), "/path"); + assert_eq!(violation.take(), Some(Backslash)); +} + +#[test] +fn test_options_reuse() { + use url::SyntaxViolation::*; + let violations = RefCell::new(Vec::new()); + let vfn = |v| violations.borrow_mut().push(v); + + let options = Url::options() + .syntax_violation_callback(Some(&vfn)); + let url = options.parse("http:////mozilla.org").unwrap(); + + let options = options.base_url(Some(&url)); + let url = options.parse("/sub\\path").unwrap(); + assert_eq!(url.as_str(), "http://mozilla.org/sub/path"); + assert_eq!(*violations.borrow(), + vec!(ExpectedDoubleSlash, Backslash)); +} diff --git a/url/tests/urltestdata.json b/url/tests/urltestdata.json new file mode 100644 index 000000000..5565c938f --- /dev/null +++ b/url/tests/urltestdata.json @@ -0,0 +1,6148 @@ +[ + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", + { + "input": "http://example\t.\norg", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@foo:21/bar;par?b#c", + "base": "http://example.org/foo/bar", + "href": "http://user:pass@foo:21/bar;par?b#c", + "origin": "http://foo:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "foo:21", + "hostname": "foo", + "port": "21", + "pathname": "/bar;par", + "search": "?b", + "hash": "#c" + }, + { + "input": "https://test:@test", + "base": "about:blank", + "href": "https://test@test/", + "origin": "https://test", + "protocol": "https:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://:@test", + "base": "about:blank", + "href": "https://test/", + "origin": "https://test", + "protocol": "https:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://test:@test/x", + "base": "about:blank", + "href": "non-special://test@test/x", + "origin": "null", + "protocol": "non-special:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "non-special://:@test/x", + "base": "about:blank", + "href": "non-special://test/x", + "origin": "null", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "http:foo.com", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "\t :foo.com \n", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com", + "search": "", + "hash": "" + }, + { + "input": " foo.com ", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "a:\t foo.com", + "base": "http://example.org/foo/bar", + "href": "a: foo.com", + "origin": "null", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": " foo.com", + "search": "", + "hash": "" + }, + { + "input": "http://f:21/ b ? d # e ", + "base": "http://example.org/foo/bar", + "href": "http://f:21/%20b%20?%20d%20# e", + "origin": "http://f:21", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:21", + "hostname": "f", + "port": "21", + "pathname": "/%20b%20", + "search": "?%20d%20", + "hash": "# e" + }, + { + "input": "lolscheme:x x#x x", + "base": "about:blank", + "href": "lolscheme:x x#x x", + "protocol": "lolscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x x", + "search": "", + "hash": "#x x" + }, + { + "input": "http://f:/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:0/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000000000080/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:b/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: /c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:\n/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:fifty-two/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "non-special://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: 21 / b ? d # e ", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": " \t", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": ":foo.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": ":a", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:a", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:a", + "search": "", + "hash": "" + }, + { + "input": ":/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": "#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "#/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#/" + }, + { + "input": "#\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#\\", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#\\" + }, + { + "input": "#;?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#;?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#;?" + }, + { + "input": "?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": ":23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:23", + "search": "", + "hash": "" + }, + { + "input": "/:23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/:23", + "search": "", + "hash": "" + }, + { + "input": "::", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::", + "search": "", + "hash": "" + }, + { + "input": "::23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::23", + "search": "", + "hash": "" + }, + { + "input": "foo://", + "base": "http://example.org/foo/bar", + "href": "foo:///", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@c:29/d", + "base": "http://example.org/foo/bar", + "href": "http://a:b@c:29/d", + "origin": "http://c:29", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "c:29", + "hostname": "c", + "port": "29", + "pathname": "/d", + "search": "", + "hash": "" + }, + { + "input": "http::@c:29", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:@c:29", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:@c:29", + "search": "", + "hash": "" + }, + { + "input": "http://&a:foo(b]c@d:2/", + "base": "http://example.org/foo/bar", + "href": "http://&a:foo(b%5Dc@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "&a", + "password": "foo(b%5Dc", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://::@c@d:2", + "base": "http://example.org/foo/bar", + "href": "http://:%3A%40c@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "", + "password": "%3A%40c", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com:b@d/", + "base": "http://example.org/foo/bar", + "href": "http://foo.com:b@d/", + "origin": "http://d", + "protocol": "http:", + "username": "foo.com", + "password": "b", + "host": "d", + "hostname": "d", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com/\\@", + "base": "http://example.org/foo/bar", + "href": "http://foo.com//@", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "//@", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://foo.com/", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\a\\b:c\\d@foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://a/b:c/d@foo.com/", + "origin": "http://a", + "protocol": "http:", + "username": "", + "password": "", + "host": "a", + "hostname": "a", + "port": "", + "pathname": "/b:c/d@foo.com/", + "search": "", + "hash": "" + }, + { + "input": "foo:/", + "base": "http://example.org/foo/bar", + "href": "foo:/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "foo:/bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo:/bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo://///////", + "base": "http://example.org/foo/bar", + "href": "foo://///////", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////", + "search": "", + "hash": "" + }, + { + "input": "foo://///////bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo://///////bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo:////://///", + "base": "http://example.org/foo/bar", + "href": "foo:////://///", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//://///", + "search": "", + "hash": "" + }, + { + "input": "c:/foo", + "base": "http://example.org/foo/bar", + "href": "c:/foo", + "origin": "null", + "protocol": "c:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "//foo/bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + { + "input": "http://foo/path;a??e#f#g", + "base": "http://example.org/foo/bar", + "href": "http://foo/path;a??e#f#g", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/path;a", + "search": "??e", + "hash": "#f#g" + }, + { + "input": "http://foo/abcd?efgh?ijkl", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd?efgh?ijkl", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "?efgh?ijkl", + "hash": "" + }, + { + "input": "http://foo/abcd#foo?bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd#foo?bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "", + "hash": "#foo?bar" + }, + { + "input": "[61:24:74]:98", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:24:74]:98", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:24:74]:98", + "search": "", + "hash": "" + }, + { + "input": "http:[61:27]/:foo", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:27]/:foo", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:27]/:foo", + "search": "", + "hash": "" + }, + { + "input": "http://[1::2]:3:4", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]:80", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://[2001::1]", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[::127.0.0.1]", + "base": "http://example.org/foo/bar", + "href": "http://[::7f00:1]/", + "origin": "http://[::7f00:1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::7f00:1]", + "hostname": "[::7f00:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[0:0:0:0:0:0:13.1.68.3]", + "base": "http://example.org/foo/bar", + "href": "http://[::d01:4403]/", + "origin": "http://[::d01:4403]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::d01:4403]", + "hostname": "[::d01:4403]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[2001::1]:80", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": "http://example.org/foo/bar", + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file://example:1/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://example:test/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://example%/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://[example]/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftps:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": "http://example.org/foo/bar", + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": "http://example.org/foo/bar", + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "/a/b/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/b/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/b/c", + "search": "", + "hash": "" + }, + { + "input": "/a/ /c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%20/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%20/c", + "search": "", + "hash": "" + }, + { + "input": "/a%2fc", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a%2fc", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a%2fc", + "search": "", + "hash": "" + }, + { + "input": "/a/%2f/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%2f/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%2f/c", + "search": "", + "hash": "" + }, + { + "input": "#β", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#%CE%B2", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#%CE%B2" + }, + { + "input": "data:text/html,test#test", + "base": "http://example.org/foo/bar", + "href": "data:text/html,test#test", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "text/html,test", + "search": "", + "hash": "#test" + }, + { + "input": "tel:1234567890", + "base": "http://example.org/foo/bar", + "href": "tel:1234567890", + "origin": "null", + "protocol": "tel:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "1234567890", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", + { + "input": "file:c:\\foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:/foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": " File:c|////foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:////foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:////foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": "C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/C|\\foo\\bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "\\\\server\\file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "/\\server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "file:///foo/bar.txt", + "base": "file:///tmp/mock/path", + "href": "file:///foo/bar.txt", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo/bar.txt", + "search": "", + "hash": "" + }, + { + "input": "file:///home/me", + "base": "file:///tmp/mock/path", + "href": "file:///home/me", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/home/me", + "search": "", + "hash": "" + }, + { + "input": "//", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "file://test", + "base": "file:///tmp/mock/path", + "href": "file://test/", + "protocol": "file:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + { + "input": "file:test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", + { + "input": "http://example.com/././foo", + "base": "about:blank", + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/./.foo", + "base": "about:blank", + "href": "http://example.com/.foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/.foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/.", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/./", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/..", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/..bar", + "base": "about:blank", + "href": "http://example.com/foo/..bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/..bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton", + "base": "about:blank", + "href": "http://example.com/foo/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton/../../a", + "base": "about:blank", + "href": "http://example.com/a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../..", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../../ton", + "base": "about:blank", + "href": "http://example.com/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e%2", + "base": "about:blank", + "href": "http://example.com/foo/%2e%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/%2e%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", + "base": "about:blank", + "href": "http://example.com/%2e.bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%2e.bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com////../..", + "base": "about:blank", + "href": "http://example.com//", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//../..", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//..", + "base": "about:blank", + "href": "http://example.com/foo/bar/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo", + "base": "about:blank", + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%20foo", + "base": "about:blank", + "href": "http://example.com/%20foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%20foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%", + "base": "about:blank", + "href": "http://example.com/foo%", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2", + "base": "about:blank", + "href": "http://example.com/foo%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2zbar", + "base": "about:blank", + "href": "http://example.com/foo%2zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2©zbar", + "base": "about:blank", + "href": "http://example.com/foo%2%C3%82%C2%A9zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2%C3%82%C2%A9zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%41%7a", + "base": "about:blank", + "href": "http://example.com/foo%41%7a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%41%7a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\t\u0091%91", + "base": "about:blank", + "href": "http://example.com/foo%C2%91%91", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%C2%91%91", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%00%51", + "base": "about:blank", + "href": "http://example.com/foo%00%51", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%00%51", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/(%28:%3A%29)", + "base": "about:blank", + "href": "http://example.com/(%28:%3A%29)", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/(%28:%3A%29)", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%3A%3a%3C%3c", + "base": "about:blank", + "href": "http://example.com/%3A%3a%3C%3c", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%3A%3a%3C%3c", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\tbar", + "base": "about:blank", + "href": "http://example.com/foobar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foobar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com\\\\foo\\\\bar", + "base": "about:blank", + "href": "http://example.com//foo//bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//foo//bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "base": "about:blank", + "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%7Ffp3%3Eju%3Dduvgw%3Dd", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/@asdf%40", + "base": "about:blank", + "href": "http://example.com/@asdf%40", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/@asdf%40", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/你好你好", + "base": "about:blank", + "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‥/foo", + "base": "about:blank", + "href": "http://example.com/%E2%80%A5/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%A5/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com//foo", + "base": "about:blank", + "href": "http://example.com/%EF%BB%BF/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%EF%BB%BF/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‮/foo/‭/bar", + "base": "about:blank", + "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%AE/foo/%E2%80%AD/bar", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", + { + "input": "http://www.google.com/foo?bar=baz#", + "base": "about:blank", + "href": "http://www.google.com/foo?bar=baz#", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "" + }, + { + "input": "http://www.google.com/foo?bar=baz# »", + "base": "about:blank", + "href": "http://www.google.com/foo?bar=baz# %C2%BB", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "# %C2%BB" + }, + { + "input": "data:test# »", + "base": "about:blank", + "href": "data:test# %C2%BB", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "# %C2%BB" + }, + { + "input": "http://www.google.com", + "base": "about:blank", + "href": "http://www.google.com/", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.0x00A80001", + "base": "about:blank", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo%2Ehtml", + "base": "about:blank", + "href": "http://www/foo%2Ehtml", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo%2Ehtml", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo/%2E/html", + "base": "about:blank", + "href": "http://www/foo/html", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo/html", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@/", + "base": "about:blank", + "failure": true + }, + { + "input": "http://%25DOMAIN:foobar@foodomain.com/", + "base": "about:blank", + "href": "http://%25DOMAIN:foobar@foodomain.com/", + "origin": "http://foodomain.com", + "protocol": "http:", + "username": "%25DOMAIN", + "password": "foobar", + "host": "foodomain.com", + "hostname": "foodomain.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\www.google.com\\foo", + "base": "about:blank", + "href": "http://www.google.com/foo", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://foo:80/", + "base": "about:blank", + "href": "http://foo/", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:81/", + "base": "about:blank", + "href": "http://foo:81/", + "origin": "http://foo:81", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "httpa://foo:80/", + "base": "about:blank", + "href": "httpa://foo:80/", + "origin": "null", + "protocol": "httpa:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:-80/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://foo:443/", + "base": "about:blank", + "href": "https://foo/", + "origin": "https://foo", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://foo:80/", + "base": "about:blank", + "href": "https://foo:80/", + "origin": "https://foo:80", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:21/", + "base": "about:blank", + "href": "ftp://foo/", + "origin": "ftp://foo", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:80/", + "base": "about:blank", + "href": "ftp://foo:80/", + "origin": "ftp://foo:80", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:70/", + "base": "about:blank", + "href": "gopher://foo/", + "origin": "gopher://foo", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:443/", + "base": "about:blank", + "href": "gopher://foo:443/", + "origin": "gopher://foo:443", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:80/", + "base": "about:blank", + "href": "ws://foo/", + "origin": "ws://foo", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:81/", + "base": "about:blank", + "href": "ws://foo:81/", + "origin": "ws://foo:81", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:443/", + "base": "about:blank", + "href": "ws://foo:443/", + "origin": "ws://foo:443", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:815/", + "base": "about:blank", + "href": "ws://foo:815/", + "origin": "ws://foo:815", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:80/", + "base": "about:blank", + "href": "wss://foo:80/", + "origin": "wss://foo:80", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:81/", + "base": "about:blank", + "href": "wss://foo:81/", + "origin": "wss://foo:81", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:443/", + "base": "about:blank", + "href": "wss://foo/", + "origin": "wss://foo", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:815/", + "base": "about:blank", + "href": "wss://foo:815/", + "origin": "wss://foo:815", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": "about:blank", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": "about:blank", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": "about:blank", + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": "about:blank", + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:/example.com/", + "base": "about:blank", + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": "about:blank", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": "about:blank", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": "about:blank", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": "about:blank", + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": "about:blank", + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": "about:blank", + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": "about:blank", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": "about:blank", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": "about:blank", + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": "about:blank", + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": "about:blank", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": "about:blank", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": "about:blank", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": "about:blank", + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": "about:blank", + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": "about:blank", + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", + { + "input": "http:@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@pple.com", + "base": "about:blank", + "href": "http://pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http::b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://:b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://user@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "https:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http::@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www.@pple.com", + "base": "about:blank", + "href": "http://www.@pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "www.", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://:@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Others", + { + "input": "/", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": ".", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "./test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../aaa/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/aaa/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/aaa/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "中/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/%E4%B8%AD/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/%E4%B8%AD/test.txt", + "search": "", + "hash": "" + }, + { + "input": "http://www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "//www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:...", + "base": "http://www.example.com/test", + "href": "file:///...", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/...", + "search": "", + "hash": "" + }, + { + "input": "file:..", + "base": "http://www.example.com/test", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:a", + "base": "http://www.example.com/test", + "href": "file:///a", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html", + "Basic canonicalization, uppercase should be converted to lowercase", + { + "input": "http://ExAmPlE.CoM", + "base": "http://other.com/", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example example.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://Goo%20 goo%7C|.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[:]", + "base": "http://other.com/", + "failure": true + }, + "U+3000 is mapped to U+0020 (space) which is disallowed", + { + "input": "http://GOO\u00a0\u3000goo.com", + "base": "http://other.com/", + "failure": true + }, + "Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored", + { + "input": "http://GOO\u200b\u2060\ufeffgoo.com", + "base": "http://other.com/", + "href": "http://googoo.com/", + "origin": "http://googoo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "googoo.com", + "hostname": "googoo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Leading and trailing C0 control or space", + { + "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", + { + "input": "http://www.foo。bar.com", + "base": "http://other.com/", + "href": "http://www.foo.bar.com/", + "origin": "http://www.foo.bar.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.foo.bar.com", + "hostname": "www.foo.bar.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0", + { + "input": "http://\ufdd0zyx.com", + "base": "http://other.com/", + "failure": true + }, + "This is the same as previous but escaped", + { + "input": "http://%ef%b7%90zyx.com", + "base": "http://other.com/", + "failure": true + }, + "U+FFFD", + { + "input": "https://\ufffd", + "base": "about:blank", + "failure": true + }, + { + "input": "https://%EF%BF%BD", + "base": "about:blank", + "failure": true + }, + { + "input": "https://x/\ufffd?\ufffd#\ufffd", + "base": "about:blank", + "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", + "origin": "https://x", + "protocol": "https:", + "username": "", + "password": "", + "host": "x", + "hostname": "x", + "port": "", + "pathname": "/%EF%BF%BD", + "search": "?%EF%BF%BD", + "hash": "#%EF%BF%BD" + }, + "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", + { + "input": "http://Go.com", + "base": "http://other.com/", + "href": "http://go.com/", + "origin": "http://go.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "go.com", + "hostname": "go.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257", + { + "input": "http://%41.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%94%ef%bc%91.com", + "base": "http://other.com/", + "failure": true + }, + "...%00 in fullwidth should fail (also as escaped UTF-8 input)", + { + "input": "http://%00.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%90%ef%bc%90.com", + "base": "http://other.com/", + "failure": true + }, + "Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN", + { + "input": "http://你好你好", + "base": "http://other.com/", + "href": "http://xn--6qqa088eba/", + "origin": "http://xn--6qqa088eba", + "protocol": "http:", + "username": "", + "password": "", + "host": "xn--6qqa088eba", + "hostname": "xn--6qqa088eba", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://faß.ExAmPlE/", + "base": "about:blank", + "href": "https://xn--fa-hia.example/", + "origin": "https://xn--fa-hia.example", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--fa-hia.example", + "hostname": "xn--fa-hia.example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://faß.ExAmPlE/", + "base": "about:blank", + "href": "sc://fa%C3%9F.ExAmPlE/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "fa%C3%9F.ExAmPlE", + "hostname": "fa%C3%9F.ExAmPlE", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", + { + "input": "http://%zz%66%a.com", + "base": "http://other.com/", + "failure": true + }, + "If we get an invalid character that has been escaped.", + { + "input": "http://%25", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://hello%00", + "base": "http://other.com/", + "failure": true + }, + "Escaped numbers should be treated like IP addresses if they are.", + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01%2e", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.0.257", + "base": "http://other.com/", + "failure": true + }, + "Invalid escaping in hosts causes failure", + { + "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01", + "base": "http://other.com/", + "failure": true + }, + "A space in a host causes failure", + { + "input": "http://192.168.0.1 hello", + "base": "http://other.com/", + "failure": true + }, + { + "input": "https://x x:12", + "base": "about:blank", + "failure": true + }, + "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", + { + "input": "http://0Xc0.0250.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Domains with empty labels", + { + "input": "http://./", + "base": "about:blank", + "href": "http://./", + "origin": "http://.", + "protocol": "http:", + "username": "", + "password": "", + "host": ".", + "hostname": ".", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://../", + "base": "about:blank", + "href": "http://../", + "origin": "http://..", + "protocol": "http:", + "username": "", + "password": "", + "host": "..", + "hostname": "..", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0..0x300/", + "base": "about:blank", + "href": "http://0..0x300/", + "origin": "http://0..0x300", + "protocol": "http:", + "username": "", + "password": "", + "host": "0..0x300", + "hostname": "0..0x300", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Broken IPv6", + { + "input": "http://[www.google.com]/", + "base": "about:blank", + "failure": true + }, + { + "input": "http://[google.com]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.4x]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.]", + "base": "http://other.com/", + "failure": true + }, + "Misc Unicode", + { + "input": "http://foo:💩@example.com/bar", + "base": "http://other.com/", + "href": "http://foo:%F0%9F%92%A9@example.com/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "foo", + "password": "%F0%9F%92%A9", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + "# resolving a fragment against any scheme succeeds", + { + "input": "#", + "base": "test:test", + "href": "test:test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "" + }, + { + "input": "#x", + "base": "mailto:x@x.com", + "href": "mailto:x@x.com#x", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x@x.com", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "data:,", + "href": "data:,#x", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ",", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "about:blank", + "href": "about:blank#x", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blank", + "search": "", + "hash": "#x" + }, + { + "input": "#", + "base": "test:test?test", + "href": "test:test?test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "?test", + "hash": "" + }, + "# multiple @ in authority state", + { + "input": "https://@test@test@example:800/", + "base": "http://doesnotmatter/", + "href": "https://%40test%40test@example:800/", + "origin": "https://example:800", + "protocol": "https:", + "username": "%40test%40test", + "password": "", + "host": "example:800", + "hostname": "example", + "port": "800", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://@@@example", + "base": "http://doesnotmatter/", + "href": "https://%40%40@example/", + "origin": "https://example", + "protocol": "https:", + "username": "%40%40", + "password": "", + "host": "example", + "hostname": "example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "non-az-09 characters", + { + "input": "http://`{}:`{}@h/`{}?`{}", + "base": "http://doesnotmatter/", + "href": "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}", + "origin": "http://h", + "protocol": "http:", + "username": "%60%7B%7D", + "password": "%60%7B%7D", + "host": "h", + "hostname": "h", + "port": "", + "pathname": "/%60%7B%7D", + "search": "?`{}", + "hash": "" + }, + "# Credentials in base", + { + "input": "/some/path", + "base": "http://user@example.org/smth", + "href": "http://user@example.org/some/path", + "origin": "http://example.org", + "protocol": "http:", + "username": "user", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/smth", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/smth", + "search": "", + "hash": "" + }, + { + "input": "/some/path", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/some/path", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + "# a set of tests designed by zcorpan for relative URLs with unknown schemes", + { + "input": "i", + "base": "sc:sd", + "failure": true + }, + { + "input": "i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "i", + "base": "sc:/pa/pa", + "href": "sc:/pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc:///pa/pa", + "href": "sc:///pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "?i", + "base": "sc:sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc://ho/pa", + "href": "sc://ho/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "#i", + "base": "sc:sd", + "href": "sc:sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:sd/sd", + "href": "sc:sd/sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd/sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc://ho/pa", + "href": "sc://ho/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + "# make sure that relative URL logic works on known typically non-relative schemes too", + { + "input": "about:/../", + "base": "about:blank", + "href": "about:/", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/../", + "base": "about:blank", + "href": "data:/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/../", + "base": "about:blank", + "href": "javascript:/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/../", + "base": "about:blank", + "href": "mailto:/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# unknown schemes and their hosts", + { + "input": "sc://ñ.test/", + "base": "about:blank", + "href": "sc://%C3%B1.test/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1.test", + "hostname": "%C3%B1.test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://\u001F!\"$&'()*+,-.;<=>^_`{|}~/", + "base": "about:blank", + "href": "sc://%1F!\"$&'()*+,-.;<=>^_`{|}~/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%1F!\"$&'()*+,-.;<=>^_`{|}~", + "hostname": "%1F!\"$&'()*+,-.;<=>^_`{|}~", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://\u0000/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc:// /", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://%/", + "base": "about:blank", + "href": "sc://%/", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%", + "hostname": "%", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://[/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://\\/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://]/", + "base": "about:blank", + "failure": true + }, + { + "input": "x", + "base": "sc://ñ", + "href": "sc://%C3%B1/x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + "# unknown schemes and backslashes", + { + "input": "sc:\\../", + "base": "about:blank", + "href": "sc:\\../", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "\\../", + "search": "", + "hash": "" + }, + "# unknown scheme with path looking like a password", + { + "input": "sc::a@example.net", + "base": "about:blank", + "href": "sc::a@example.net", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ":a@example.net", + "search": "", + "hash": "" + }, + "# unknown scheme with bogus percent-encoding", + { + "input": "wow:%NBD", + "base": "about:blank", + "href": "wow:%NBD", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%NBD", + "search": "", + "hash": "" + }, + { + "input": "wow:%1G", + "base": "about:blank", + "href": "wow:%1G", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%1G", + "search": "", + "hash": "" + }, + "# Hosts and percent-encoding", + { + "input": "ftp://example.com%80/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftp://example.com%A0/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://example.com%80/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://example.com%A0/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftp://%e2%98%83", + "base": "about:blank", + "href": "ftp://xn--n3h/", + "origin": "ftp://xn--n3h", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://%e2%98%83", + "base": "about:blank", + "href": "https://xn--n3h/", + "origin": "https://xn--n3h", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# tests from jsdom/whatwg-url designed for code coverage", + { + "input": "http://127.0.0.1:10100/relative_import.html", + "base": "about:blank", + "href": "http://127.0.0.1:10100/relative_import.html", + "origin": "http://127.0.0.1:10100", + "protocol": "http:", + "username": "", + "password": "", + "host": "127.0.0.1:10100", + "hostname": "127.0.0.1", + "port": "10100", + "pathname": "/relative_import.html", + "search": "", + "hash": "" + }, + { + "input": "http://facebook.com/?foo=%7B%22abc%22", + "base": "about:blank", + "href": "http://facebook.com/?foo=%7B%22abc%22", + "origin": "http://facebook.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "facebook.com", + "hostname": "facebook.com", + "port": "", + "pathname": "/", + "search": "?foo=%7B%22abc%22", + "hash": "" + }, + { + "input": "https://localhost:3000/jqueryui@1.2.3", + "base": "about:blank", + "href": "https://localhost:3000/jqueryui@1.2.3", + "origin": "https://localhost:3000", + "protocol": "https:", + "username": "", + "password": "", + "host": "localhost:3000", + "hostname": "localhost", + "port": "3000", + "pathname": "/jqueryui@1.2.3", + "search": "", + "hash": "" + }, + "# tab/LF/CR", + { + "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", + "base": "about:blank", + "href": "http://host:9000/path?query#frag", + "origin": "http://host:9000", + "protocol": "http:", + "username": "", + "password": "", + "host": "host:9000", + "hostname": "host", + "port": "9000", + "pathname": "/path", + "search": "?query", + "hash": "#frag" + }, + "# Stringification of URL.searchParams", + { + "input": "?a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "?a=b&c=d", + "searchParams": "a=b&c=d", + "hash": "" + }, + { + "input": "??a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar??a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "??a=b&c=d", + "searchParams": "%3Fa=b&c=d", + "hash": "" + }, + "# Scheme only", + { + "input": "http:", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "searchParams": "", + "hash": "" + }, + { + "input": "http:", + "base": "https://example.org/foo/bar", + "failure": true + }, + { + "input": "sc:", + "base": "https://example.org/foo/bar", + "href": "sc:", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "searchParams": "", + "hash": "" + }, + "# Percent encoding of fragments", + { + "input": "http://foo.bar/baz?qux#foo\bbar", + "base": "about:blank", + "href": "http://foo.bar/baz?qux#foo%08bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%08bar" + }, + "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)", + { + "input": "http://192.168.257", + "base": "http://other.com/", + "href": "http://192.168.1.1/", + "origin": "http://192.168.1.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.1.1", + "hostname": "192.168.1.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.257.com", + "base": "http://other.com/", + "href": "http://192.168.257.com/", + "origin": "http://192.168.257.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.257.com", + "hostname": "192.168.257.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256", + "base": "http://other.com/", + "href": "http://0.0.1.0/", + "origin": "http://0.0.1.0", + "protocol": "http:", + "username": "", + "password": "", + "host": "0.0.1.0", + "hostname": "0.0.1.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256.com", + "base": "http://other.com/", + "href": "http://256.com/", + "origin": "http://256.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "256.com", + "hostname": "256.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999", + "base": "http://other.com/", + "href": "http://59.154.201.255/", + "origin": "http://59.154.201.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "59.154.201.255", + "hostname": "59.154.201.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999.com", + "base": "http://other.com/", + "href": "http://999999999.com/", + "origin": "http://999999999.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "999999999.com", + "hostname": "999999999.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://10000000000", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://10000000000.com", + "base": "http://other.com/", + "href": "http://10000000000.com/", + "origin": "http://10000000000.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "10000000000.com", + "hostname": "10000000000.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967295", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967296", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://0xffffffff", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0xffffffff1", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256.256", + "base": "http://other.com/", + "href": "http://256.256.256.256.256/", + "origin": "http://256.256.256.256.256", + "protocol": "http:", + "username": "", + "password": "", + "host": "256.256.256.256.256", + "hostname": "256.256.256.256.256", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://0x.0x.0", + "base": "about:blank", + "href": "https://0.0.0.0/", + "origin": "https://0.0.0.0", + "protocol": "https:", + "username": "", + "password": "", + "host": "0.0.0.0", + "hostname": "0.0.0.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", + { + "input": "https://256.0.0.1/test", + "base": "about:blank", + "failure": true + }, + "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", + { + "input": "file:///C%3A/", + "base": "about:blank", + "href": "file:///C%3A/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%3A/", + "search": "", + "hash": "" + }, + { + "input": "file:///C%7C/", + "base": "about:blank", + "href": "file:///C%7C/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%7C/", + "search": "", + "hash": "" + }, + "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)", + { + "input": "pix/submit.gif", + "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html", + "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///C:/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# More file URL tests by zcorpan and annevk", + { + "input": "/", + "base": "file:///C:/a/b", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "//d:", + "base": "file:///C:/a/b", + "href": "file:///d:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:", + "search": "", + "hash": "" + }, + { + "input": "//d:/..", + "base": "file:///C:/a/b", + "href": "file:///d:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///ab:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///1:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "file:", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "file:?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + { + "input": "file:#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + "# File URLs and many (back)slashes", + { + "input": "file:///localhost//cat", + "base": "about:blank", + "href": "file:///localhost//cat", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/localhost//cat", + "search": "", + "hash": "" + }, + { + "input": "\\//pig", + "base": "file://lion/", + "href": "file:///pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pig", + "search": "", + "hash": "" + }, + { + "input": "file://", + "base": "file://ape/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Windows drive letter handling with the 'file:' base URL", + { + "input": "C|#", + "base": "file://host/dir/file", + "href": "file:///C:#", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|?", + "base": "file://host/dir/file", + "href": "file:///C:?", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\n/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\\", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C", + "base": "file://host/dir/file", + "href": "file://host/dir/C", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C", + "search": "", + "hash": "" + }, + { + "input": "C|a", + "base": "file://host/dir/file", + "href": "file://host/dir/C|a", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C|a", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk in the file slash state", + { + "input": "/c:/foo/bar", + "base": "file://host/path", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk (no host)", + { + "input": "file:/C|/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://C|/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk with not empty host", + { + "input": "file://example.net/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://1.2.3.4/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://[1::8]/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# file URLs without base URL by Rimas Misevičius", + { + "input": "file:", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:?q=v", + "base": "about:blank", + "href": "file:///?q=v", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "?q=v", + "hash": "" + }, + { + "input": "file:#frag", + "base": "about:blank", + "href": "file:///#frag", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "#frag" + }, + "# IPv6 tests", + { + "input": "http://[1:0::]", + "base": "http://example.net/", + "href": "http://[1::]/", + "origin": "http://[1::]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1::]", + "hostname": "[1::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[0:1:2:3:4:5:6:7:8]", + "base": "http://example.net/", + "failure": true + }, + { + "input": "https://[0::0::0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:0:]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.00.0.0.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.290.0.0.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.23.23]", + "base": "about:blank", + "failure": true + }, + "# Empty host", + { + "input": "http://?", + "base": "about:blank", + "failure": true + }, + { + "input": "http://#", + "base": "about:blank", + "failure": true + }, + "Port overflow (2^32 + 81)", + { + "input": "http://f:4294967377/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^64 + 81)", + { + "input": "http://f:18446744073709551697/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^128 + 81)", + { + "input": "http://f:340282366920938463463374607431768211537/c", + "base": "http://example.org/", + "failure": true + }, + "# Non-special-URL path tests", + { + "input": "///", + "base": "sc://x/", + "href": "sc:///", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "tftp://foobar.com/someconfig;mode=netascii", + "base": "about:blank", + "href": "tftp://foobar.com/someconfig;mode=netascii", + "origin": "null", + "protocol": "tftp:", + "username": "", + "password": "", + "host": "foobar.com", + "hostname": "foobar.com", + "port": "", + "pathname": "/someconfig;mode=netascii", + "search": "", + "hash": "" + }, + { + "input": "telnet://user:pass@foobar.com:23/", + "base": "about:blank", + "href": "telnet://user:pass@foobar.com:23/", + "origin": "null", + "protocol": "telnet:", + "username": "user", + "password": "pass", + "host": "foobar.com:23", + "hostname": "foobar.com", + "port": "23", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ut2004://10.10.10.10:7777/Index.ut2", + "base": "about:blank", + "href": "ut2004://10.10.10.10:7777/Index.ut2", + "origin": "null", + "protocol": "ut2004:", + "username": "", + "password": "", + "host": "10.10.10.10:7777", + "hostname": "10.10.10.10", + "port": "7777", + "pathname": "/Index.ut2", + "search": "", + "hash": "" + }, + { + "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "base": "about:blank", + "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "origin": "null", + "protocol": "redis:", + "username": "foo", + "password": "bar", + "host": "somehost:6379", + "hostname": "somehost", + "port": "6379", + "pathname": "/0", + "search": "?baz=bam&qux=baz", + "hash": "" + }, + { + "input": "rsync://foo@host:911/sup", + "base": "about:blank", + "href": "rsync://foo@host:911/sup", + "origin": "null", + "protocol": "rsync:", + "username": "foo", + "password": "", + "host": "host:911", + "hostname": "host", + "port": "911", + "pathname": "/sup", + "search": "", + "hash": "" + }, + { + "input": "git://github.com/foo/bar.git", + "base": "about:blank", + "href": "git://github.com/foo/bar.git", + "origin": "null", + "protocol": "git:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, + { + "input": "irc://myserver.com:6999/channel?passwd", + "base": "about:blank", + "href": "irc://myserver.com:6999/channel?passwd", + "origin": "null", + "protocol": "irc:", + "username": "", + "password": "", + "host": "myserver.com:6999", + "hostname": "myserver.com", + "port": "6999", + "pathname": "/channel", + "search": "?passwd", + "hash": "" + }, + { + "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "base": "about:blank", + "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "origin": "null", + "protocol": "dns:", + "username": "", + "password": "", + "host": "fw.example.org:9999", + "hostname": "fw.example.org", + "port": "9999", + "pathname": "/foo.bar.org", + "search": "?type=TXT", + "hash": "" + }, + { + "input": "ldap://localhost:389/ou=People,o=JNDITutorial", + "base": "about:blank", + "href": "ldap://localhost:389/ou=People,o=JNDITutorial", + "origin": "null", + "protocol": "ldap:", + "username": "", + "password": "", + "host": "localhost:389", + "hostname": "localhost", + "port": "389", + "pathname": "/ou=People,o=JNDITutorial", + "search": "", + "hash": "" + }, + { + "input": "git+https://github.com/foo/bar", + "base": "about:blank", + "href": "git+https://github.com/foo/bar", + "origin": "null", + "protocol": "git+https:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "urn:ietf:rfc:2648", + "base": "about:blank", + "href": "urn:ietf:rfc:2648", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ietf:rfc:2648", + "search": "", + "hash": "" + }, + { + "input": "tag:joe@example.org,2001:foo/bar", + "base": "about:blank", + "href": "tag:joe@example.org,2001:foo/bar", + "origin": "null", + "protocol": "tag:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "joe@example.org,2001:foo/bar", + "search": "", + "hash": "" + }, + "# percent encoded hosts in non-special-URLs", + { + "input": "non-special://%E2%80%A0/", + "base": "about:blank", + "href": "non-special://%E2%80%A0/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "%E2%80%A0", + "hostname": "%E2%80%A0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://H%4fSt/path", + "base": "about:blank", + "href": "non-special://H%4fSt/path", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "H%4fSt", + "hostname": "H%4fSt", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + "# IPv6 in non-special-URLs", + { + "input": "non-special://[1:2:0:0:5:0:0:0]/", + "base": "about:blank", + "href": "non-special://[1:2:0:0:5::]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2:0:0:5::]", + "hostname": "[1:2:0:0:5::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2:0:0:0:0:0:3]/", + "base": "about:blank", + "href": "non-special://[1:2::3]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]", + "hostname": "[1:2::3]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2::3]:80/", + "base": "about:blank", + "href": "non-special://[1:2::3]:80/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]:80", + "hostname": "[1:2::3]", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[:80/", + "base": "about:blank", + "failure": true + }, + { + "input": "blob:https://example.com:443/", + "base": "about:blank", + "href": "blob:https://example.com:443/", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "https://example.com:443/", + "search": "", + "hash": "" + }, + { + "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "base": "about:blank", + "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf", + "search": "", + "hash": "" + }, + "Invalid IPv4 radix digits", + { + "input": "http://0177.0.0.0189", + "base": "about:blank", + "href": "http://0177.0.0.0189/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0177.0.0.0189", + "hostname": "0177.0.0.0189", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0x7f.0.0.0x7g", + "base": "about:blank", + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0X7F.0.0.0X7G", + "base": "about:blank", + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid IPv4 portion of IPv6 address", + { + "input": "http://[::127.0.0.0.1]", + "base": "about:blank", + "failure": true + }, + "Uncompressed IPv6 addresses with 0", + { + "input": "http://[0:1:0:1:0:1:0:1]", + "base": "about:blank", + "href": "http://[0:1:0:1:0:1:0:1]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[0:1:0:1:0:1:0:1]", + "hostname": "[0:1:0:1:0:1:0:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[1:0:1:0:1:0:1:0]", + "base": "about:blank", + "href": "http://[1:0:1:0:1:0:1:0]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1:0:1:0:1:0:1:0]", + "hostname": "[1:0:1:0:1:0:1:0]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Percent-encoded query and fragment", + { + "input": "http://example.org/test?\u0022", + "base": "about:blank", + "href": "http://example.org/test?%22", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%22", + "hash": "" + }, + { + "input": "http://example.org/test?\u0023", + "base": "about:blank", + "href": "http://example.org/test?#", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "http://example.org/test?\u003C", + "base": "about:blank", + "href": "http://example.org/test?%3C", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3C", + "hash": "" + }, + { + "input": "http://example.org/test?\u003E", + "base": "about:blank", + "href": "http://example.org/test?%3E", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3E", + "hash": "" + }, + { + "input": "http://example.org/test?\u2323", + "base": "about:blank", + "href": "http://example.org/test?%E2%8C%A3", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%E2%8C%A3", + "hash": "" + }, + { + "input": "http://example.org/test?%23%23", + "base": "about:blank", + "href": "http://example.org/test?%23%23", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%23%23", + "hash": "" + }, + { + "input": "http://example.org/test?%GH", + "base": "about:blank", + "href": "http://example.org/test?%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%GH", + "hash": "" + }, + { + "input": "http://example.org/test?a#%EF", + "base": "about:blank", + "href": "http://example.org/test?a#%EF", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%EF" + }, + { + "input": "http://example.org/test?a#%GH", + "base": "about:blank", + "href": "http://example.org/test?a#%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%GH" + }, + "Bad bases", + { + "input": "test-a.html", + "base": "a", + "failure": true + }, + { + "input": "test-a-slash.html", + "base": "a/", + "failure": true + }, + { + "input": "test-a-slash-slash.html", + "base": "a//", + "failure": true + }, + { + "input": "test-a-colon.html", + "base": "a:", + "failure": true + }, + { + "input": "test-a-colon-slash.html", + "base": "a:/", + "href": "a:/test-a-colon-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash.html", + "base": "a://", + "href": "a:///test-a-colon-slash-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-b.html", + "base": "a:b", + "failure": true + }, + { + "input": "test-a-colon-slash-b.html", + "base": "a:/b", + "href": "a:/test-a-colon-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-b.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash-b.html", + "base": "a://b", + "href": "a://b/test-a-colon-slash-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "b", + "hostname": "b", + "port": "", + "pathname": "/test-a-colon-slash-slash-b.html", + "search": "", + "hash": "" + }, + "Null code point in fragment", + { + "input": "http://example.org/test?a#b\u0000c", + "base": "about:blank", + "href": "http://example.org/test?a#bc", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#bc" + } +] diff --git a/url_serde/.cargo-checksum.json b/url_serde/.cargo-checksum.json new file mode 100644 index 000000000..a573e197b --- /dev/null +++ b/url_serde/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea"} \ No newline at end of file diff --git a/url_serde/Cargo.toml b/url_serde/Cargo.toml new file mode 100644 index 000000000..935b5932c --- /dev/null +++ b/url_serde/Cargo.toml @@ -0,0 +1,23 @@ +[package] + +name = "url_serde" +version = "0.2.0" +authors = ["The rust-url developers"] + +description = "Serde support for URL types" +documentation = "https://docs.rs/url_serde/" +repository = "https://github.com/servo/rust-url" +readme = "README.md" +keywords = ["url", "serde"] +license = "MIT/Apache-2.0" + +[dependencies] +serde = "1.0" +url = "1.0.0" + +[dev-dependencies] +serde_json = "1.0" +serde_derive = "1.0" + +[lib] +doctest = false diff --git a/url_serde/README.md b/url_serde/README.md new file mode 100644 index 000000000..dea503946 --- /dev/null +++ b/url_serde/README.md @@ -0,0 +1,11 @@ +Serde support for rust-url types +================================ + +This crate provides wrappers and convenience functions to make `rust-url` and `serde` +work hand in hand. + +Version `0.2` or newer of this crate offer support for `serde 1.0`. +Version `0.1` of this crate offer support for `serde 0.9`. +Versions of `serde` older than `0.9` are natively supported by `rust-url` crate directly. + +For more details, see the crate [documentation](https://docs.rs/url_serde/). \ No newline at end of file diff --git a/url_serde/src/lib.rs b/url_serde/src/lib.rs new file mode 100644 index 000000000..ebb22a8d8 --- /dev/null +++ b/url_serde/src/lib.rs @@ -0,0 +1,410 @@ +// Copyright 2017 The rust-url developers. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +This crate provides wrappers and convenience functions to make rust-url +and Serde work hand in hand. + +The supported types are: + +* `url::Url` + +# How do I use a data type with a `Url` member with Serde? + +Use the serde attributes `deserialize_with` and `serialize_with`. + +``` +#[derive(serde::Serialize, serde::Deserialize)] +struct MyStruct { + #[serde(with = "url_serde")] + url: Url, +} +``` + +# How do I encode a `Url` value with `serde_json::to_string`? + +Use the `Ser` wrapper. + +``` +serde_json::to_string(&Ser::new(&url)) +``` + +# How do I decode a `Url` value with `serde_json::parse`? + +Use the `De` wrapper. + +``` +serde_json::from_str(r"http:://www.rust-lang.org").map(De::into_inner) +``` + +# How do I send `Url` values as part of an IPC channel? + +Use the `Serde` wrapper. It implements `Deref` and `DerefMut` for convenience. + +``` +ipc::channel::<Serde<Url>>() +``` +*/ + +#![deny(missing_docs)] +#![deny(unsafe_code)] + +extern crate serde; +#[cfg(test)] #[macro_use] extern crate serde_derive; +#[cfg(test)] extern crate serde_json; +extern crate url; + +use serde::{Deserialize, Serialize, Serializer, Deserializer}; +use std::cmp::PartialEq; +use std::error::Error; +use std::fmt; +use std::io::Write; +use std::ops::{Deref, DerefMut}; +use std::str; +use url::{Url, Host}; + +/// Serialises `value` with a given serializer. +/// +/// This is useful to serialize `rust-url` types used in structure fields or +/// tuple members with `#[serde(serialize_with = "url_serde::serialize")]`. +pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error> + where S: Serializer, for<'a> Ser<'a, T>: Serialize +{ + Ser::new(value).serialize(serializer) +} + +/// A wrapper to serialize `rust-url` types. +/// +/// This is useful with functions such as `serde_json::to_string`. +/// +/// Values of this type can only be passed to the `serde::Serialize` trait. +#[derive(Debug)] +pub struct Ser<'a, T: 'a>(&'a T); + +impl<'a, T> Ser<'a, T> where Ser<'a, T>: Serialize { + /// Returns a new `Ser` wrapper. + #[inline(always)] + pub fn new(value: &'a T) -> Self { + Ser(value) + } +} + +/// Serializes this URL into a `serde` stream. +impl<'a> Serialize for Ser<'a, Url> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer { + serializer.serialize_str(self.0.as_str()) + } +} + +/// Serializes this Option<URL> into a `serde` stream. +impl<'a> Serialize for Ser<'a, Option<Url>> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer { + if let Some(url) = self.0.as_ref() { + serializer.serialize_some(url.as_str()) + } else { + serializer.serialize_none() + } + } +} + +impl<'a, String> Serialize for Ser<'a, Host<String>> where String: AsRef<str> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer { + match *self.0 { + Host::Domain(ref s) => serializer.serialize_str(s.as_ref()), + Host::Ipv4(_) | Host::Ipv6(_) => { + // max("101.102.103.104".len(), + // "[1000:1002:1003:1004:1005:1006:101.102.103.104]".len()) + const MAX_LEN: usize = 47; + let mut buffer = [0; MAX_LEN]; + serializer.serialize_str(display_into_buffer(&self.0, &mut buffer)) + } + } + } +} + +/// Like .to_string(), but doesn’t allocate memory for a `String`. +/// +/// Panics if `buffer` is too small. +fn display_into_buffer<'a, T: fmt::Display>(value: &T, buffer: &'a mut [u8]) -> &'a str { + let remaining_len; + { + let mut remaining = &mut *buffer; + write!(remaining, "{}", value).unwrap(); + remaining_len = remaining.len() + } + let written_len = buffer.len() - remaining_len; + let written = &buffer[..written_len]; + + // write! only provides std::fmt::Formatter to Display implementations, + // which has methods write_str and write_char but no method to write arbitrary bytes. + // Therefore, `written` is well-formed in UTF-8. + #[allow(unsafe_code)] + unsafe { + str::from_utf8_unchecked(written) + } +} + +/// Deserialises a `T` value with a given deserializer. +/// +/// This is useful to deserialize Url types used in structure fields or +/// tuple members with `#[serde(deserialize_with = "url_serde::deserialize")]`. +pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error> + where D: Deserializer<'de>, De<T>: Deserialize<'de> +{ + De::deserialize(deserializer).map(De::into_inner) +} + +/// A wrapper to deserialize `rust-url` types. +/// +/// This is useful with functions such as `serde_json::from_str`. +/// +/// Values of this type can only be obtained through +/// the `serde::Deserialize` trait. +#[derive(Debug)] +pub struct De<T>(T); + +impl<'de, T> De<T> where De<T>: serde::Deserialize<'de> { + /// Consumes this wrapper, returning the deserialized value. + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } +} + +/// Deserializes this URL from a `serde` stream. +impl<'de> Deserialize<'de> for De<Url> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> { + let string_representation: String = Deserialize::deserialize(deserializer)?; + Url::parse(&string_representation).map(De).map_err(|err| { + serde::de::Error::custom(err.description()) + }) + } +} + +/// Deserializes this Option<URL> from a `serde` stream. +impl<'de> Deserialize<'de> for De<Option<Url>> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> { + let option_representation: Option<String> = Deserialize::deserialize(deserializer)?; + if let Some(s) = option_representation { + return Url::parse(&s) + .map(Some) + .map(De) + .map_err(|err| {serde::de::Error::custom(err.description())}); + } + Ok(De(None)) + + } +} + +impl<'de> Deserialize<'de> for De<Host> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> { + let string_representation: String = Deserialize::deserialize(deserializer)?; + Host::parse(&string_representation).map(De).map_err(|err| { + serde::de::Error::custom(err.description()) + }) + } +} + +/// A convenience wrapper to be used as a type parameter, for example when +/// a `Vec<T>` or an `HashMap<K, V>` need to be passed to serde. +#[derive(Clone, Eq, Hash, PartialEq)] +pub struct Serde<T>(pub T); + +/// A convenience type alias for Serde<Url>. +pub type SerdeUrl = Serde<Url>; + +impl<'de, T> Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + /// Consumes this wrapper, returning the inner value. + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } +} + +impl<'de, T> fmt::Debug for Serde<T> +where T: fmt::Debug, De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + self.0.fmt(formatter) + } +} + +impl<'de, T> Deref for Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<'de, T> DerefMut for Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl<'de, T: PartialEq> PartialEq<T> for Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + fn eq(&self, other: &T) -> bool { + self.0 == *other + } +} + +impl<'de, T> Deserialize<'de> for Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where D: Deserializer<'de> + { + De::deserialize(deserializer).map(De::into_inner).map(Serde) + } +} + +impl<'de, T> Serialize for Serde<T> +where De<T>: Deserialize<'de>, for<'a> Ser<'a, T>: Serialize +{ + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where S: Serializer + { + Ser(&self.0).serialize(serializer) + } +} + +#[test] +fn test_ser_de_url() { + let url = Url::parse("http://www.test.com/foo/bar?$param=bazz").unwrap(); + let s = serde_json::to_string(&Ser::new(&url)).unwrap(); + let new_url: Url = serde_json::from_str(&s).map(De::into_inner).unwrap(); + assert_eq!(url, new_url); +} + +#[test] +fn test_derive_deserialize_with_for_url() { + #[derive(Deserialize, Debug, Eq, PartialEq)] + struct Test { + #[serde(deserialize_with = "deserialize", rename = "_url_")] + url: Url + } + + let url_str = "http://www.test.com/foo/bar?$param=bazz"; + + let expected = Test { + url: Url::parse(url_str).unwrap() + }; + let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str); + let got: Test = serde_json::from_str(&json_string).unwrap(); + assert_eq!(expected, got); + +} + +#[test] +fn test_derive_deserialize_with_for_option_url() { + #[derive(Deserialize, Debug, Eq, PartialEq)] + struct Test { + #[serde(deserialize_with = "deserialize", rename = "_url_")] + url: Option<Url> + } + + let url_str = "http://www.test.com/foo/bar?$param=bazz"; + + let expected = Test { + url: Some(Url::parse(url_str).unwrap()) + }; + let json_string = format!(r#"{{"_url_": "{}"}}"#, url_str); + let got: Test = serde_json::from_str(&json_string).unwrap(); + assert_eq!(expected, got); + + let expected = Test { + url: None + }; + let json_string = r#"{"_url_": null}"#; + let got: Test = serde_json::from_str(&json_string).unwrap(); + assert_eq!(expected, got); +} + +#[test] +fn test_derive_serialize_with_for_url() { + #[derive(Serialize, Debug, Eq, PartialEq)] + struct Test { + #[serde(serialize_with = "serialize", rename = "_url_")] + url: Url + } + + let url_str = "http://www.test.com/foo/bar?$param=bazz"; + + let expected = format!(r#"{{"_url_":"{}"}}"#, url_str); + let input = Test {url: Url::parse(url_str).unwrap()}; + let got = serde_json::to_string(&input).unwrap(); + assert_eq!(expected, got); +} + +#[test] +fn test_derive_serialize_with_for_option_url() { + #[derive(Serialize, Debug, Eq, PartialEq)] + struct Test { + #[serde(serialize_with = "serialize", rename = "_url_")] + url: Option<Url> + } + + let url_str = "http://www.test.com/foo/bar?$param=bazz"; + + let expected = format!(r#"{{"_url_":"{}"}}"#, url_str); + let input = Test {url: Some(Url::parse(url_str).unwrap())}; + let got = serde_json::to_string(&input).unwrap(); + assert_eq!(expected, got); + + let expected = format!(r#"{{"_url_":null}}"#); + let input = Test {url: None}; + let got = serde_json::to_string(&input).unwrap(); + assert_eq!(expected, got); +} + +#[test] +fn test_derive_with_for_url() { + #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] + struct Test { + #[serde(with = "self", rename = "_url_")] + url: Url + } + + let url_str = "http://www.test.com/foo/bar?$param=bazz"; + let json_string = format!(r#"{{"_url_":"{}"}}"#, url_str); + + // test deserialization + let expected = Test { + url: Url::parse(url_str).unwrap() + }; + let got: Test = serde_json::from_str(&json_string).unwrap(); + assert_eq!(expected, got); + + // test serialization + let input = Test {url: Url::parse(url_str).unwrap()}; + let got = serde_json::to_string(&input).unwrap(); + assert_eq!(json_string, got); +} + +#[test] +fn test_host() { + for host in &[ + Host::Domain("foo.com".to_owned()), + Host::Ipv4("127.0.0.1".parse().unwrap()), + Host::Ipv6("::1".parse().unwrap()), + ] { + let json = serde_json::to_string(&Ser(host)).unwrap(); + let de: De<Host> = serde_json::from_str(&json).unwrap(); + assert_eq!(de.into_inner(), *host) + } +} diff --git a/utf8-ranges/.cargo-checksum.json b/utf8-ranges/.cargo-checksum.json new file mode 100644 index 000000000..1b299ffa4 --- /dev/null +++ b/utf8-ranges/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"} \ No newline at end of file diff --git a/utf8-ranges/COPYING b/utf8-ranges/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/utf8-ranges/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/utf8-ranges/Cargo.toml b/utf8-ranges/Cargo.toml new file mode 100644 index 000000000..67d9cf305 --- /dev/null +++ b/utf8-ranges/Cargo.toml @@ -0,0 +1,29 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "utf8-ranges" +version = "1.0.2" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +exclude = ["/ci/*", "/.travis.yml", "/Makefile", "/ctags.rust", "/session.vim"] +description = "Convert ranges of Unicode codepoints to UTF-8 byte ranges." +homepage = "https://github.com/BurntSushi/utf8-ranges" +documentation = "https://docs.rs/utf8-ranges" +readme = "README.md" +keywords = ["codepoint", "utf8", "automaton", "range"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/utf8-ranges" +[dev-dependencies.quickcheck] +version = "0.7" +default-features = false +[badges.travis-ci] +repository = "BurntSushi/utf8-ranges" diff --git a/utf8-ranges/LICENSE-MIT b/utf8-ranges/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/utf8-ranges/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/utf8-ranges/README.md b/utf8-ranges/README.md new file mode 100644 index 000000000..b30db24f3 --- /dev/null +++ b/utf8-ranges/README.md @@ -0,0 +1,54 @@ +utf8-ranges +=========== +This crate converts contiguous ranges of Unicode scalar values to UTF-8 byte +ranges. This is useful when constructing byte based automata from Unicode. +Stated differently, this lets one embed UTF-8 decoding as part of one's +automaton. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/utf8-ranges.png)](https://travis-ci.org/BurntSushi/utf8-ranges) +[![](http://meritbadge.herokuapp.com/utf8-ranges)](https://crates.io/crates/utf8-ranges) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/utf8-ranges + + +### Example + +This shows how to convert a scalar value range (e.g., the basic multilingual +plane) to a sequence of byte based character classes. + + +```rust +extern crate utf8_ranges; + +use utf8_ranges::Utf8Sequences; + +fn main() { + for range in Utf8Sequences::new('\u{0}', '\u{FFFF}') { + println!("{:?}", range); + } +} +``` + +The output: + +``` +[0-7F] +[C2-DF][80-BF] +[E0][A0-BF][80-BF] +[E1-EC][80-BF][80-BF] +[ED][80-9F][80-BF] +[EE-EF][80-BF][80-BF] +``` + +These ranges can then be used to build an automaton. Namely: + +1. Every arbitrary sequence of bytes matches exactly one of the sequences of + ranges or none of them. +2. Every match sequence of bytes is guaranteed to be valid UTF-8. (Erroneous + encodings of surrogate codepoints in UTF-8 cannot match any of the byte + ranges above.) diff --git a/utf8-ranges/UNLICENSE b/utf8-ranges/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/utf8-ranges/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/utf8-ranges/benches/bench.rs b/utf8-ranges/benches/bench.rs new file mode 100644 index 000000000..ccffa896f --- /dev/null +++ b/utf8-ranges/benches/bench.rs @@ -0,0 +1,25 @@ +#![feature(test)] + +extern crate test; +extern crate utf8_ranges; + +use test::Bencher; +use utf8_ranges::Utf8Sequences; + +#[bench] +fn no_reuse(b: &mut Bencher) { + b.iter(|| { + let count = Utf8Sequences::new('\u{0}', '\u{10FFFF}').count(); + assert_eq!(count, 9); + }) +} + +#[bench] +fn reuse(b: &mut Bencher) { + let mut seqs = Utf8Sequences::new('\u{0}', '\u{10FFFF}'); + b.iter(|| { + seqs.reset('\u{0}', '\u{10FFFF}'); + let count = (&mut seqs).count(); + assert_eq!(count, 9); + }) +} diff --git a/utf8-ranges/src/char_utf8.rs b/utf8-ranges/src/char_utf8.rs new file mode 100644 index 000000000..ac6be5490 --- /dev/null +++ b/utf8-ranges/src/char_utf8.rs @@ -0,0 +1,36 @@ +// Pulled from std::char until encode_utf8 stabilizes. ---AG + +// UTF-8 ranges and tags for encoding characters +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +#[inline] +pub fn encode_utf8(character: char, dst: &mut [u8]) -> Option<usize> { + let code = character as u32; + if code < MAX_ONE_B && !dst.is_empty() { + dst[0] = code as u8; + Some(1) + } else if code < MAX_TWO_B && dst.len() >= 2 { + dst[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + dst[1] = (code & 0x3F) as u8 | TAG_CONT; + Some(2) + } else if code < MAX_THREE_B && dst.len() >= 3 { + dst[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + dst[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + dst[2] = (code & 0x3F) as u8 | TAG_CONT; + Some(3) + } else if dst.len() >= 4 { + dst[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + dst[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; + dst[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; + dst[3] = (code & 0x3F) as u8 | TAG_CONT; + Some(4) + } else { + None + } +} diff --git a/utf8-ranges/src/lib.rs b/utf8-ranges/src/lib.rs new file mode 100644 index 000000000..962622a64 --- /dev/null +++ b/utf8-ranges/src/lib.rs @@ -0,0 +1,527 @@ +/*! +Crate `utf8-ranges` converts ranges of Unicode scalar values to equivalent +ranges of UTF-8 bytes. This is useful for constructing byte based automatons +that need to embed UTF-8 decoding. + +See the documentation on the `Utf8Sequences` iterator for more details and +an example. + +# Wait, what is this? + +This is simplest to explain with an example. Let's say you wanted to test +whether a particular byte sequence was a Cyrillic character. One possible +scalar value range is `[0400-04FF]`. The set of allowed bytes for this +range can be expressed as a sequence of byte ranges: + +```ignore +[D0-D3][80-BF] +``` + +This is simple enough: simply encode the boundaries, `0400` encodes to +`D0 80` and `04FF` encodes to `D3 BF`, and create ranges from each +corresponding pair of bytes: `D0` to `D3` and `80` to `BF`. + +However, what if you wanted to add the Cyrillic Supplementary characters to +your range? Your range might then become `[0400-052F]`. The same procedure +as above doesn't quite work because `052F` encodes to `D4 AF`. The byte ranges +you'd get from the previous transformation would be `[D0-D4][80-AF]`. However, +this isn't quite correct because this range doesn't capture many characters, +for example, `04FF` (because its last byte, `BF` isn't in the range `80-AF`). + +Instead, you need multiple sequences of byte ranges: + +```ignore +[D0-D3][80-BF] # matches codepoints 0400-04FF +[D4][80-AF] # matches codepoints 0500-052F +``` + +This gets even more complicated if you want bigger ranges, particularly if +they naively contain surrogate codepoints. For example, the sequence of byte +ranges for the basic multilingual plane (`[0000-FFFF]`) look like this: + +```ignore +[0-7F] +[C2-DF][80-BF] +[E0][A0-BF][80-BF] +[E1-EC][80-BF][80-BF] +[ED][80-9F][80-BF] +[EE-EF][80-BF][80-BF] +``` + +Note that the byte ranges above will *not* match any erroneous encoding of +UTF-8, including encodings of surrogate codepoints. + +And, of course, for all of Unicode (`[000000-10FFFF]`): + +```ignore +[0-7F] +[C2-DF][80-BF] +[E0][A0-BF][80-BF] +[E1-EC][80-BF][80-BF] +[ED][80-9F][80-BF] +[EE-EF][80-BF][80-BF] +[F0][90-BF][80-BF][80-BF] +[F1-F3][80-BF][80-BF][80-BF] +[F4][80-8F][80-BF][80-BF] +``` + +This crate automates the process of creating these byte ranges from ranges of +Unicode scalar values. + +# Why would I ever use this? + +You probably won't ever need this. In 99% of cases, you just decode the byte +sequence into a Unicode scalar value and compare scalar values directly. +However, this explicit decoding step isn't always possible. For example, the +construction of some finite state machines may benefit from converting ranges +of scalar values into UTF-8 decoder automata (e.g., for character classes in +regular expressions). + +# Lineage + +I got the idea and general implementation strategy from Russ Cox in his +[article on regexps](https://web.archive.org/web/20160404141123/https://swtch.com/~rsc/regexp/regexp3.html) and RE2. +Russ Cox got it from Ken Thompson's `grep` (no source, folk lore?). +I also got the idea from +[Lucene](https://github.com/apache/lucene-solr/blob/ae93f4e7ac6a3908046391de35d4f50a0d3c59ca/lucene/core/src/java/org/apache/lucene/util/automaton/UTF32ToUTF8.java), +which uses it for executing automata on their term index. +*/ + +#![deny(missing_docs)] + +#[cfg(test)] extern crate quickcheck; + +use std::char; +use std::fmt; +use std::slice; + +use char_utf8::encode_utf8; + +const MAX_UTF8_BYTES: usize = 4; + +mod char_utf8; + +/// Utf8Sequence represents a sequence of byte ranges. +/// +/// To match a Utf8Sequence, a candidate byte sequence must match each +/// successive range. +/// +/// For example, if there are two ranges, `[C2-DF][80-BF]`, then the byte +/// sequence `\xDD\x61` would not match because `0x61 < 0x80`. +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum Utf8Sequence { + /// One byte range. + One(Utf8Range), + /// Two successive byte ranges. + Two([Utf8Range; 2]), + /// Three successive byte ranges. + Three([Utf8Range; 3]), + /// Four successive byte ranges. + Four([Utf8Range; 4]), +} + +impl Utf8Sequence { + /// Creates a new UTF-8 sequence from the encoded bytes of a scalar value + /// range. + /// + /// This assumes that `start` and `end` have the same length. + fn from_encoded_range(start: &[u8], end: &[u8]) -> Self { + assert_eq!(start.len(), end.len()); + match start.len() { + 2 => Utf8Sequence::Two([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + ]), + 3 => Utf8Sequence::Three([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + Utf8Range::new(start[2], end[2]), + ]), + 4 => Utf8Sequence::Four([ + Utf8Range::new(start[0], end[0]), + Utf8Range::new(start[1], end[1]), + Utf8Range::new(start[2], end[2]), + Utf8Range::new(start[3], end[3]), + ]), + n => unreachable!("invalid encoded length: {}", n), + } + } + + /// Returns the underlying sequence of byte ranges as a slice. + pub fn as_slice(&self) -> &[Utf8Range] { + use self::Utf8Sequence::*; + match *self { + One(ref r) => unsafe { slice::from_raw_parts(r, 1) }, + Two(ref r) => &r[..], + Three(ref r) => &r[..], + Four(ref r) => &r[..], + } + } + + /// Returns the number of byte ranges in this sequence. + /// + /// The length is guaranteed to be in the closed interval `[1, 4]`. + pub fn len(&self) -> usize { + self.as_slice().len() + } + + /// Returns true if and only if a prefix of `bytes` matches this sequence + /// of byte ranges. + pub fn matches(&self, bytes: &[u8]) -> bool { + if bytes.len() < self.len() { + return false; + } + for (&b, r) in bytes.iter().zip(self) { + if !r.matches(b) { + return false; + } + } + true + } +} + +impl<'a> IntoIterator for &'a Utf8Sequence { + type IntoIter = slice::Iter<'a, Utf8Range>; + type Item = &'a Utf8Range; + + fn into_iter(self) -> Self::IntoIter { + self.as_slice().into_iter() + } +} + +impl fmt::Debug for Utf8Sequence { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Utf8Sequence::*; + match *self { + One(ref r) => write!(f, "{:?}", r), + Two(ref r) => write!(f, "{:?}{:?}", r[0], r[1]), + Three(ref r) => write!(f, "{:?}{:?}{:?}", r[0], r[1], r[2]), + Four(ref r) => write!(f, "{:?}{:?}{:?}{:?}", + r[0], r[1], r[2], r[3]), + } + } +} + +/// A single inclusive range of UTF-8 bytes. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct Utf8Range { + /// Start of byte range (inclusive). + pub start: u8, + /// End of byte range (inclusive). + pub end: u8, +} + +impl Utf8Range { + fn new(start: u8, end: u8) -> Self { + Utf8Range { start: start, end: end } + } + + /// Returns true if and only if the given byte is in this range. + pub fn matches(&self, b: u8) -> bool { + self.start <= b && b <= self.end + } +} + +impl fmt::Debug for Utf8Range { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.start == self.end { + write!(f, "[{:X}]", self.start) + } else { + write!(f, "[{:X}-{:X}]", self.start, self.end) + } + } +} + +/// An iterator over ranges of matching UTF-8 byte sequences. +/// +/// The iteration represents an alternation of comprehensive byte sequences +/// that match precisely the set of UTF-8 encoded scalar values. +/// +/// A byte sequence corresponds to one of the scalar values in the range given +/// if and only if it completely matches exactly one of the sequences of byte +/// ranges produced by this iterator. +/// +/// Each sequence of byte ranges matches a unique set of bytes. That is, no two +/// sequences will match the same bytes. +/// +/// # Example +/// +/// This shows how to match an arbitrary byte sequence against a range of +/// scalar values. +/// +/// ```rust +/// use utf8_ranges::{Utf8Sequences, Utf8Sequence}; +/// +/// fn matches(seqs: &[Utf8Sequence], bytes: &[u8]) -> bool { +/// for range in seqs { +/// if range.matches(bytes) { +/// return true; +/// } +/// } +/// false +/// } +/// +/// // Test the basic multilingual plane. +/// let seqs: Vec<_> = Utf8Sequences::new('\u{0}', '\u{FFFF}').collect(); +/// +/// // UTF-8 encoding of 'a'. +/// assert!(matches(&seqs, &[0x61])); +/// // UTF-8 encoding of '☃' (`\u{2603}`). +/// assert!(matches(&seqs, &[0xE2, 0x98, 0x83])); +/// // UTF-8 encoding of `\u{10348}` (outside the BMP). +/// assert!(!matches(&seqs, &[0xF0, 0x90, 0x8D, 0x88])); +/// // Tries to match against a UTF-8 encoding of a surrogate codepoint, +/// // which is invalid UTF-8, and therefore fails, despite the fact that +/// // the corresponding codepoint (0xD800) falls in the range given. +/// assert!(!matches(&seqs, &[0xED, 0xA0, 0x80])); +/// // And fails against plain old invalid UTF-8. +/// assert!(!matches(&seqs, &[0xFF, 0xFF])); +/// ``` +/// +/// If this example seems circuitous, that's because it is! It's meant to be +/// illustrative. In practice, you could just try to decode your byte sequence +/// and compare it with the scalar value range directly. However, this is not +/// always possible (for example, in a byte based automaton). +pub struct Utf8Sequences { + range_stack: Vec<ScalarRange>, +} + +impl Utf8Sequences { + /// Create a new iterator over UTF-8 byte ranges for the scalar value range + /// given. + pub fn new(start: char, end: char) -> Self { + let mut it = Utf8Sequences { range_stack: vec![] }; + it.push(start as u32, end as u32); + it + } + + /// reset resets the scalar value range. + /// Any existing state is cleared, but resources may be reused. + /// + /// N.B. Benchmarks say that this method is dubious. + #[doc(hidden)] + pub fn reset(&mut self, start: char, end: char) { + self.range_stack.clear(); + self.push(start as u32, end as u32); + } + + fn push(&mut self, start: u32, end: u32) { + self.range_stack.push(ScalarRange { start: start, end: end }); + } +} + +struct ScalarRange { + start: u32, + end: u32, +} + +impl fmt::Debug for ScalarRange { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ScalarRange({:X}, {:X})", self.start, self.end) + } +} + +impl Iterator for Utf8Sequences { + type Item = Utf8Sequence; + + fn next(&mut self) -> Option<Self::Item> { + 'TOP: + while let Some(mut r) = self.range_stack.pop() { + 'INNER: + loop { + if let Some((r1, r2)) = r.split() { + self.push(r2.start, r2.end); + r.start = r1.start; + r.end = r1.end; + continue 'INNER; + } + if !r.is_valid() { + continue 'TOP; + } + for i in 1..MAX_UTF8_BYTES { + let max = max_scalar_value(i); + if r.start <= max && max < r.end { + self.push(max + 1, r.end); + r.end = max; + continue 'INNER; + } + } + if let Some(ascii_range) = r.as_ascii() { + return Some(Utf8Sequence::One(ascii_range)); + } + for i in 1..MAX_UTF8_BYTES { + let m = (1 << (6 * i)) - 1; + if (r.start & !m) != (r.end & !m) { + if (r.start & m) != 0 { + self.push((r.start | m) + 1, r.end); + r.end = r.start | m; + continue 'INNER; + } + if (r.end & m) != m { + self.push(r.end & !m, r.end); + r.end = (r.end & !m) - 1; + continue 'INNER; + } + } + } + let mut start = [0; MAX_UTF8_BYTES]; + let mut end = [0; MAX_UTF8_BYTES]; + let n = r.encode(&mut start, &mut end); + return Some(Utf8Sequence::from_encoded_range( + &start[0..n], &end[0..n])); + } + } + None + } +} + +impl ScalarRange { + /// split splits this range if it overlaps with a surrogate codepoint. + /// + /// Either or both ranges may be invalid. + fn split(&self) -> Option<(ScalarRange, ScalarRange)> { + if self.start < 0xE000 && self.end > 0xD7FF { + Some((ScalarRange { + start: self.start, + end: 0xD7FF, + }, ScalarRange { + start: 0xE000, + end: self.end, + })) + } else { + None + } + } + + /// is_valid returns true if and only if start <= end. + fn is_valid(&self) -> bool { + self.start <= self.end + } + + /// as_ascii returns this range as a Utf8Range if and only if all scalar + /// values in this range can be encoded as a single byte. + fn as_ascii(&self) -> Option<Utf8Range> { + if self.is_ascii() { + Some(Utf8Range::new(self.start as u8, self.end as u8)) + } else { + None + } + } + + /// is_ascii returns true if the range is ASCII only (i.e., takes a single + /// byte to encode any scalar value). + fn is_ascii(&self) -> bool { + self.is_valid() && self.end <= 0x7f + } + + /// encode writes the UTF-8 encoding of the start and end of this range + /// to the corresponding destination slices. + /// + /// The slices should have room for at least `MAX_UTF8_BYTES`. + fn encode(&self, start: &mut [u8], end: &mut [u8]) -> usize { + let cs = char::from_u32(self.start).unwrap(); + let ce = char::from_u32(self.end).unwrap(); + let n = encode_utf8(cs, start).unwrap(); + let m = encode_utf8(ce, end).unwrap(); + assert_eq!(n, m); + n + } +} + +fn max_scalar_value(nbytes: usize) -> u32 { + match nbytes { + 1 => 0x007F, + 2 => 0x07FF, + 3 => 0xFFFF, + 4 => 0x10FFFF, + _ => unreachable!("invalid UTF-8 byte sequence size"), + } +} + +#[cfg(test)] +mod tests { + use std::char; + + use quickcheck::{TestResult, quickcheck}; + + use char_utf8::encode_utf8; + use {MAX_UTF8_BYTES, Utf8Range, Utf8Sequences}; + + fn rutf8(s: u8, e: u8) -> Utf8Range { + Utf8Range::new(s, e) + } + + fn never_accepts_surrogate_codepoints(start: char, end: char) { + let mut buf = [0; MAX_UTF8_BYTES]; + for cp in 0xD800..0xE000 { + let c = unsafe { ::std::mem::transmute(cp) }; + let n = encode_utf8(c, &mut buf).unwrap(); + for r in Utf8Sequences::new(start, end) { + if r.matches(&buf[0..n]) { + panic!("Sequence ({:X}, {:X}) contains range {:?}, \ + which matches surrogate code point {:X} \ + with encoded bytes {:?}", + start as u32, end as u32, r, cp, &buf[0..n]); + } + } + } + } + + #[test] + fn codepoints_no_surrogates() { + never_accepts_surrogate_codepoints('\u{0}', '\u{FFFF}'); + never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFF}'); + never_accepts_surrogate_codepoints('\u{0}', '\u{10FFFE}'); + never_accepts_surrogate_codepoints('\u{80}', '\u{10FFFF}'); + never_accepts_surrogate_codepoints('\u{D7FF}', '\u{E000}'); + } + + #[test] + fn single_codepoint_one_sequence() { + // Tests that every range of scalar values that contains a single + // scalar value is recognized by one sequence of byte ranges. + for i in 0x0..(0x10FFFF + 1) { + let c = match char::from_u32(i) { + None => continue, + Some(c) => c, + }; + let seqs: Vec<_> = Utf8Sequences::new(c, c).collect(); + assert_eq!(seqs.len(), 1); + } + } + + #[test] + fn qc_codepoints_no_surrogate() { + fn p(s: char, e: char) -> TestResult { + if s > e { + return TestResult::discard(); + } + never_accepts_surrogate_codepoints(s, e); + TestResult::passed() + } + quickcheck(p as fn(char, char) -> TestResult); + } + + #[test] + fn bmp() { + use Utf8Sequence::*; + + let seqs = Utf8Sequences::new('\u{0}', '\u{FFFF}') + .collect::<Vec<_>>(); + assert_eq!(seqs, vec![ + One(rutf8(0x0, 0x7F)), + Two([rutf8(0xC2, 0xDF), rutf8(0x80, 0xBF)]), + Three([rutf8(0xE0, 0xE0), rutf8(0xA0, 0xBF), rutf8(0x80, 0xBF)]), + Three([rutf8(0xE1, 0xEC), rutf8(0x80, 0xBF), rutf8(0x80, 0xBF)]), + Three([rutf8(0xED, 0xED), rutf8(0x80, 0x9F), rutf8(0x80, 0xBF)]), + Three([rutf8(0xEE, 0xEF), rutf8(0x80, 0xBF), rutf8(0x80, 0xBF)]), + ]); + } + + #[test] + fn scratch() { + for range in Utf8Sequences::new('\u{0}', '\u{FFFF}') { + println!("{:?}", range); + } + } +} diff --git a/vcpkg/.cargo-checksum.json b/vcpkg/.cargo-checksum.json new file mode 100644 index 000000000..1c37eea9d --- /dev/null +++ b/vcpkg/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"} \ No newline at end of file diff --git a/vcpkg/Cargo.toml b/vcpkg/Cargo.toml new file mode 100644 index 000000000..e1a9260ab --- /dev/null +++ b/vcpkg/Cargo.toml @@ -0,0 +1,38 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "vcpkg" +version = "0.2.6" +authors = ["Jim McGrath <jimmc2@gmail.com>"] +description = "A library to find native dependencies in a vcpkg tree at build\ntime in order to be used in Cargo build scripts.\n" +documentation = "https://docs.rs/vcpkg" +readme = "../README.md" +keywords = ["build-dependencies", "windows", "ffi", "win32"] +categories = ["os::windows-apis"] +license = "MIT/Apache-2.0" +repository = "https://github.com/mcgoo/vcpkg-rs" + +[dependencies] +[dev-dependencies.lazy_static] +version = "1" + +[dev-dependencies.tempdir] +version = "0.3.7" +[badges.appveyor] +branch = "master" +repository = "mcgoo/vcpkg-rs" +service = "github" + +[badges.travis-ci] +branch = "master" +repository = "mcgoo/vcpkg-rs" diff --git a/vcpkg/src/lib.rs b/vcpkg/src/lib.rs new file mode 100644 index 000000000..14ef0577c --- /dev/null +++ b/vcpkg/src/lib.rs @@ -0,0 +1,1154 @@ +//! A build dependency for Cargo libraries to find libraries in a +//! [Vcpkg](https://github.com/Microsoft/vcpkg) tree. From a Vcpkg package name +//! this build helper will emit cargo metadata to link it and it's dependencies +//! (excluding system libraries, which it cannot derive). +//! +//! **Note:** You must set one of `RUSTFLAGS=-Ctarget-feature=+crt-static` or +//! `VCPKGRS_DYNAMIC=1` in your environment or the vcpkg-rs helper +//! will not find any libraries. If `VCPKGRS_DYNAMIC` is set, `cargo install` will +//! generate dynamically linked binaries, in which case you will have to arrange for +//! dlls from your Vcpkg installation to be available in your path. +//! +//! The simplest possible usage looks like this :- +//! +//! ```rust,no_run +//! vcpkg::find_package("libssh2").unwrap(); +//! ``` +//! +//! The cargo metadata that is emitted can be changed like this :- +//! +//! ```rust,no_run +//! vcpkg::Config::new() +//! .emit_includes(true) +//! .find_package("zlib").unwrap(); +//! ``` +//! +//! If the search was successful all appropriate Cargo metadata will be printed +//! to stdout. +//! +//! The decision to choose static variants of libraries is driven by adding +//! `RUSTFLAGS=-Ctarget-feature=+crt-static` to the environment. This requires +//! at least Rust 1.19. +//! +//! A number of environment variables are available to globally configure which +//! libraries are selected. +//! +//! * `VCPKG_ROOT` - Set the directory to look in for a vcpkg installation. If +//! it is not set, vcpkg will use the user-wide installation if one has been +//! set up with `vcpkg integrate install` +//! +//! * `VCPKGRS_NO_FOO` - if set, vcpkg-rs will not attempt to find the +//! library named `foo`. +//! +//! * `VCPKGRS_DISABLE` - if set, vcpkg-rs will not attempt to find any libraries. +//! +//! * `VCPKGRS_DYNAMIC` - if set, vcpkg-rs will link to DLL builds of ports. +//! +//! There is a companion crate `vcpkg_cli` that allows testing of environment +//! and flag combinations. +//! +//! ```Batchfile +//! C:\src> vcpkg_cli probe -l static mysqlclient +//! Found library mysqlclient +//! Include paths: +//! C:\src\[..]\vcpkg\installed\x64-windows-static\include +//! Library paths: +//! C:\src\[..]\vcpkg\installed\x64-windows-static\lib +//! Cargo metadata: +//! cargo:rustc-link-search=native=C:\src\[..]\vcpkg\installed\x64-windows-static\lib +//! cargo:rustc-link-lib=static=mysqlclient +//! ``` + +#[cfg(test)] +#[macro_use] +extern crate lazy_static; + +#[allow(deprecated)] +#[allow(unused_imports)] +use std::ascii::AsciiExt; + +use std::collections::BTreeMap; +use std::env; +use std::error; +use std::ffi::OsStr; +use std::fmt; +use std::fs::{self, File}; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; + +#[derive(Default)] +pub struct Config { + /// should the cargo metadata actually be emitted + cargo_metadata: bool, + + /// should cargo:include= metadata be emitted (defaults to false) + emit_includes: bool, + + /// .libs that must be be found for probing to be considered successful + required_libs: Vec<String>, + + /// .dlls that must be be found for probing to be considered successful + required_dlls: Vec<String>, + + /// should DLLs be copies to OUT_DIR? + copy_dlls: bool, +} + +/// Details of a package that was found +#[derive(Debug)] +pub struct Library { + /// Paths for the linker to search for static or import libraries + pub link_paths: Vec<PathBuf>, + + /// Paths to search at runtme to find DLLs + pub dll_paths: Vec<PathBuf>, + + /// Paths to search for + pub include_paths: Vec<PathBuf>, + + /// cargo: metadata lines + pub cargo_metadata: Vec<String>, + + /// libraries found are static + pub is_static: bool, + + // DLLs found + pub found_dlls: Vec<PathBuf>, + + // static libs or import libs found + pub found_libs: Vec<PathBuf>, +} + +enum MSVCTarget { + X86, + X64, +} + +impl fmt::Display for MSVCTarget { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + MSVCTarget::X86 => write!(f, "x86-windows"), + MSVCTarget::X64 => write!(f, "x64-windows"), + } + } +} + +#[derive(Debug)] // need Display? +pub enum Error { + /// Aborted because of a `VCPKGRS_NO_*` environment variable. + /// + /// Contains the name of the responsible environment variable. + DisabledByEnv(String), + + /// Aborted because a required environment variable was not set. + RequiredEnvMissing(String), + + /// Only MSVC ABI is supported + NotMSVC, + + /// Can't find a vcpkg tree + VcpkgNotFound(String), + + /// Library not found in vcpkg tree + LibNotFound(String), + + /// Could not understand vcpkg installation + VcpkgInstallation(String), + + #[doc(hidden)] + __Nonexhaustive, +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::DisabledByEnv(_) => "vcpkg-rs requested to be aborted", + Error::RequiredEnvMissing(_) => "a required env setting is missing", + Error::NotMSVC => "vcpkg-rs only can only find libraries for MSVC ABI 64 bit builds", + Error::VcpkgNotFound(_) => "could not find Vcpkg tree", + Error::LibNotFound(_) => "could not find library in Vcpkg tree", + Error::VcpkgInstallation(_) => "could not look up details of packages in vcpkg tree", + Error::__Nonexhaustive => panic!(), + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + // Error::Command { ref cause, .. } => Some(cause), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::DisabledByEnv(ref name) => write!(f, "Aborted because {} is set", name), + Error::RequiredEnvMissing(ref name) => write!(f, "Aborted because {} is not set", name), + Error::NotMSVC => write!( + f, + "the vcpkg-rs Vcpkg build helper can only find libraries built for the MSVC ABI." + ), + Error::VcpkgNotFound(ref detail) => write!(f, "Could not find Vcpkg tree: {}", detail), + Error::LibNotFound(ref detail) => { + write!(f, "Could not find library in Vcpkg tree {}", detail) + } + Error::VcpkgInstallation(ref detail) => write!( + f, + "Could not look up details of packages in vcpkg tree {}", + detail + ), + Error::__Nonexhaustive => panic!(), + } + } +} + +/// Deprecated in favor of the find_package function +#[doc(hidden)] +pub fn probe_package(name: &str) -> Result<Library, Error> { + Config::new().probe(name) +} + +/// Find the package `package` in a Vcpkg tree. +/// +/// Emits cargo metadata to link to libraries provided by the Vcpkg package/port +/// named, and any (non-system) libraries that they depend on. +/// +/// This will select the architecture and linkage based on environment +/// variables and build flags as described in the module docs. +pub fn find_package(package: &str) -> Result<Library, Error> { + Config::new().find_package(package) +} + +fn find_vcpkg_root() -> Result<PathBuf, Error> { + // prefer the setting from the environment is there is one + if let Some(path) = env::var_os("VCPKG_ROOT") { + return Ok(PathBuf::from(path)); + } + + // see if there is a per-user vcpkg tree that has been integrated into msbuild + // using `vcpkg integrate install` + let local_app_data = try!(env::var("LOCALAPPDATA").map_err(|_| Error::VcpkgNotFound( + "Failed to read LOCALAPPDATA environment variable".to_string() + ))); // not present or can't utf8 + let vcpkg_user_targets_path = Path::new(local_app_data.as_str()) + .join("vcpkg") + .join("vcpkg.user.targets"); + + let file = try!(File::open(vcpkg_user_targets_path.clone()).map_err(|_| { + Error::VcpkgNotFound( + "No vcpkg.user.targets found. Set the VCPKG_ROOT environment \ + variable or run 'vcpkg integrate install'" + .to_string(), + ) + })); + let file = BufReader::new(&file); + + for line in file.lines() { + let line = try!(line.map_err(|_| Error::VcpkgNotFound(format!( + "Parsing of {} failed.", + vcpkg_user_targets_path.to_string_lossy().to_owned() + )))); + let mut split = line.split("Project=\""); + split.next(); // eat anything before Project=" + if let Some(found) = split.next() { + // " is illegal in a Windows pathname + if let Some(found) = found.split_terminator('"').next() { + let mut vcpkg_root = PathBuf::from(found); + if !(vcpkg_root.pop() && vcpkg_root.pop() && vcpkg_root.pop() && vcpkg_root.pop()) { + return Err(Error::VcpkgNotFound(format!( + "Could not find vcpkg root above {}", + found + ))); + } + return Ok(vcpkg_root); + } + } + } + + Err(Error::VcpkgNotFound(format!( + "Project location not found parsing {}.", + vcpkg_user_targets_path.to_string_lossy().to_owned() + ))) +} + +fn validate_vcpkg_root(path: &PathBuf) -> Result<(), Error> { + let mut vcpkg_root_path = path.clone(); + vcpkg_root_path.push(".vcpkg-root"); + + if vcpkg_root_path.exists() { + Ok(()) + } else { + Err(Error::VcpkgNotFound(format!( + "Could not find Vcpkg root at {}", + vcpkg_root_path.to_string_lossy() + ))) + } +} + +fn find_vcpkg_target(msvc_target: &MSVCTarget) -> Result<VcpkgTarget, Error> { + let vcpkg_root = try!(find_vcpkg_root()); + try!(validate_vcpkg_root(&vcpkg_root)); + + let static_lib = env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()) // rustc 1.10 + .contains("crt-static"); + + let mut base = vcpkg_root; + base.push("installed"); + let status_path = base.join("vcpkg"); + + let static_appendage = if static_lib { "-static" } else { "" }; + + let vcpkg_triple = format!("{}{}", msvc_target.to_string(), static_appendage); + base.push(&vcpkg_triple); + + let lib_path = base.join("lib"); + let bin_path = base.join("bin"); + let include_path = base.join("include"); + + Ok(VcpkgTarget { + vcpkg_triple: vcpkg_triple, + lib_path: lib_path, + bin_path: bin_path, + include_path: include_path, + is_static: static_lib, + status_path: status_path, + }) +} + +#[derive(Clone, Debug)] +struct Port { + // dlls if any + dlls: Vec<String>, + + // libs (static or import) + libs: Vec<String>, + + // ports that this port depends on + deps: Vec<String>, +} + +fn load_port_manifest( + path: &PathBuf, + port: &str, + version: &str, + vcpkg_triple: &str, +) -> Result<(Vec<String>, Vec<String>), Error> { + let manifest_file = path + .join("info") + .join(format!("{}_{}_{}.list", port, version, vcpkg_triple)); + + let mut dlls = Vec::new(); + let mut libs = Vec::new(); + + let f = try!( + File::open(&manifest_file).map_err(|_| Error::VcpkgInstallation(format!( + "Could not open port manifest file {}", + manifest_file.display() + ))) + ); + + let file = BufReader::new(&f); + + let dll_prefix = Path::new(vcpkg_triple).join("bin"); + let lib_prefix = Path::new(vcpkg_triple).join("lib"); + + for line in file.lines() { + let line = line.unwrap(); + + let file_path = Path::new(&line); + + if let Ok(dll) = file_path.strip_prefix(&dll_prefix) { + if dll.extension() == Some(OsStr::new("dll")) + && dll.components().collect::<Vec<_>>().len() == 1 + { + // match "mylib.dll" but not "debug/mylib.dll" or "manual_link/mylib.dll" + + dll.to_str().map(|s| dlls.push(s.to_owned())); + } + } else if let Ok(lib) = file_path.strip_prefix(&lib_prefix) { + if lib.extension() == Some(OsStr::new("lib")) + && lib.components().collect::<Vec<_>>().len() == 1 + { + lib.to_str().map(|s| libs.push(s.to_owned())); + } + } + } + + Ok((dlls, libs)) +} + +// load ports from the status file or one of the incremental updates +fn load_port_file( + filename: &PathBuf, + port_info: &mut Vec<BTreeMap<String, String>>, +) -> Result<(), Error> { + let f = try!( + File::open(&filename).map_err(|e| Error::VcpkgInstallation(format!( + "Could not open status file at {}: {}", + filename.display(), + e + ))) + ); + let file = BufReader::new(&f); + let mut current: BTreeMap<String, String> = BTreeMap::new(); + for line in file.lines() { + let line = line.unwrap(); + let parts = line.splitn(2, ": ").clone().collect::<Vec<_>>(); + if parts.len() == 2 { + // a key: value line + current.insert(parts[0].trim().into(), parts[1].trim().into()); + } else if line.len() == 0 { + // end of section + port_info.push(current.clone()); + current.clear(); + } else { + // ignore all extension lines of the form + // + // Description: a package with a + // very long description + // + // the description key is not used so this is harmless but + // this will eat extension lines for any multiline key which + // could become an issue in future + } + } + + if !current.is_empty() { + port_info.push(current); + } + + Ok(()) +} + +fn load_ports(target: &VcpkgTarget) -> Result<BTreeMap<String, Port>, Error> { + let mut ports = BTreeMap::new(); + + let mut port_info: Vec<BTreeMap<String, String>> = Vec::new(); + + // load the main status file. It is not an error if this file does not + // exist. If the only command that has been run in a Vcpkg installation + // is a single `vcpkg install package` then there will likely be no + // status file, only incremental updates. This is the typical case when + // running in a CI environment. + let status_filename = target.status_path.join("status"); + load_port_file(&status_filename, &mut port_info).ok(); + + // load updates to the status file that have yet to be normalized + let status_update_dir = target.status_path.join("updates"); + + let paths = try!( + fs::read_dir(status_update_dir).map_err(|e| Error::VcpkgInstallation(format!( + "could not read status file updates dir: {}", + e + ))) + ); + + // get all of the paths of the update files into a Vec<PathBuf> + let mut paths = try!( + paths + .map(|rde| rde.map(|de| de.path())) // Result<DirEntry, io::Error> -> Result<PathBuf, io::Error> + .collect::<Result<Vec<_>, _>>() // collect into Result<Vec<PathBuf>, io::Error> + .map_err(|e| { + Error::VcpkgInstallation(format!( + "could not read status file update filenames: {}", + e + )) + }) + ); + + // Sort the paths and read them. This could be done directly from the iterator if + // read_dir() guarantees that the files will be read in alpha order but that appears + // to be unspecified as the underlying operating system calls used are unspecified + // https://doc.rust-lang.org/nightly/std/fs/fn.read_dir.html#platform-specific-behavior + paths.sort(); + for path in paths { + // println!("Name: {}", path.display()); + try!(load_port_file(&path, &mut port_info)); + } + + for current in &port_info { + if let Some(name) = current.get("Package") { + if let Some(arch) = current.get("Architecture") { + if *arch == target.vcpkg_triple { + // println!("-++++++-"); + // println!("{:?}", current); + // println!("--------"); + + let mut deps = if let Some(deps) = current.get("Depends") { + deps.split(", ").map(|x| x.to_owned()).collect() + } else { + Vec::new() + }; + + if current + .get("Status") + .unwrap_or(&String::new()) + .ends_with(" installed") + { + match (current.get("Version"), current.get("Feature")) { + (Some(version), _) => { + let lib_info = try!(load_port_manifest( + &target.status_path, + name, + version, + &target.vcpkg_triple + )); + let port = Port { + dlls: lib_info.0, + libs: lib_info.1, + deps: deps, + }; + + ports.insert(name.clone(), port); + } + (_, Some(_feature)) => match ports.get_mut(name) { + Some(ref mut port) => { + port.deps.append(&mut deps); + } + _ => { + println!("found a feature that had no corresponding port :-"); + println!("current {:+?}", current); + continue; + } + }, + (_, _) => { + println!("didn't know how to deal with status file entry :-"); + println!("{:+?}", current); + continue; + } + } + } else { + // remove it? + //ports.remove(name); + //println!("would delete {} for arch {}", name, arch); + } + } + } + } + } + + Ok(ports) +} + +/// paths and triple for the chosen target +struct VcpkgTarget { + vcpkg_triple: String, + lib_path: PathBuf, + bin_path: PathBuf, + include_path: PathBuf, + + // directory containing the status file + status_path: PathBuf, + + is_static: bool, +} + +impl Config { + pub fn new() -> Config { + Config { + cargo_metadata: true, + copy_dlls: true, + ..Default::default() + // emit_includes: false, + // required_libs: Vec::new(), + } + } + + /// Override the name of the library to look for if it differs from the package name. + /// + /// This may be called more than once if multiple libs are required. + /// All libs must be found for the probe to succeed. `.probe()` must + /// be run with a different configuration to look for libraries under one of several names. + /// `.libname("ssleay32")` will look for ssleay32.lib and also ssleay32.dll if + /// dynamic linking is selected. + pub fn lib_name(&mut self, lib_stem: &str) -> &mut Config { + self.required_libs.push(lib_stem.to_owned()); + self.required_dlls.push(lib_stem.to_owned()); + self + } + + /// Override the name of the library to look for if it differs from the package name. + /// + /// This may be called more than once if multiple libs are required. + /// All libs must be found for the probe to succeed. `.probe()` must + /// be run with a different configuration to look for libraries under one of several names. + /// `.lib_names("libcurl_imp","curl")` will look for libcurl_imp.lib and also curl.dll if + /// dynamic linking is selected. + pub fn lib_names(&mut self, lib_stem: &str, dll_stem: &str) -> &mut Config { + self.required_libs.push(lib_stem.to_owned()); + self.required_dlls.push(dll_stem.to_owned()); + self + } + + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Config { + self.cargo_metadata = cargo_metadata; + self + } + + /// Define cargo:include= metadata should be emitted. Defaults to `false`. + pub fn emit_includes(&mut self, emit_includes: bool) -> &mut Config { + self.emit_includes = emit_includes; + self + } + + /// Should DLLs be copied to OUT_DIR? + /// Defaults to `true`. + pub fn copy_dlls(&mut self, copy_dlls: bool) -> &mut Config { + self.copy_dlls = copy_dlls; + self + } + + /// Find the library `port_name` in a Vcpkg tree. + /// + /// This will use all configuration previously set to select the + /// architecture and linkage. + /// Deprecated in favor of the find_package function + #[doc(hidden)] + pub fn probe(&mut self, port_name: &str) -> Result<Library, Error> { + // determine the target type, bailing out if it is not some + // kind of msvc + let msvc_target = try!(msvc_target()); + + // bail out if requested to not try at all + if env::var_os("VCPKGRS_DISABLE").is_some() { + return Err(Error::DisabledByEnv("VCPKGRS_DISABLE".to_owned())); + } + + // bail out if requested to not try at all (old) + if env::var_os("NO_VCPKG").is_some() { + return Err(Error::DisabledByEnv("NO_VCPKG".to_owned())); + } + + // bail out if requested to skip this package + let abort_var_name = format!("VCPKGRS_NO_{}", envify(port_name)); + if env::var_os(&abort_var_name).is_some() { + return Err(Error::DisabledByEnv(abort_var_name)); + } + + // bail out if requested to skip this package (old) + let abort_var_name = format!("{}_NO_VCPKG", envify(port_name)); + if env::var_os(&abort_var_name).is_some() { + return Err(Error::DisabledByEnv(abort_var_name)); + } + + // if no overrides have been selected, then the Vcpkg port name + // is the the .lib name and the .dll name + if self.required_libs.is_empty() { + self.required_libs.push(port_name.to_owned()); + self.required_dlls.push(port_name.to_owned()); + } + + let vcpkg_target = try!(find_vcpkg_target(&msvc_target)); + + // require explicit opt-in before using dynamically linked + // variants, otherwise cargo install of various things will + // stop working if Vcpkg is installed. + if !vcpkg_target.is_static && !env::var_os("VCPKGRS_DYNAMIC").is_some() { + return Err(Error::RequiredEnvMissing("VCPKGRS_DYNAMIC".to_owned())); + } + + let mut lib = Library::new(vcpkg_target.is_static); + + if self.emit_includes { + lib.cargo_metadata.push(format!( + "cargo:include={}", + vcpkg_target.include_path.display() + )); + } + lib.include_paths.push(vcpkg_target.include_path.clone()); + + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search=native={}", + vcpkg_target + .lib_path + .to_str() + .expect("failed to convert string type") + )); + lib.link_paths.push(vcpkg_target.lib_path.clone()); + if !vcpkg_target.is_static { + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search=native={}", + vcpkg_target + .bin_path + .to_str() + .expect("failed to convert string type") + )); + // this path is dropped by recent versions of cargo hence the copies to OUT_DIR below + lib.dll_paths.push(vcpkg_target.bin_path.clone()); + } + + try!(self.emit_libs(&mut lib, &vcpkg_target)); + + if self.copy_dlls { + try!(self.do_dll_copy(&mut lib)); + } + + if self.cargo_metadata { + for line in &lib.cargo_metadata { + println!("{}", line); + } + } + Ok(lib) + } + + fn emit_libs(&mut self, lib: &mut Library, vcpkg_target: &VcpkgTarget) -> Result<(), Error> { + for required_lib in &self.required_libs { + // this could use static-nobundle= for static libraries but it is apparently + // not necessary to make the distinction for windows-msvc. + lib.cargo_metadata + .push(format!("cargo:rustc-link-lib={}", required_lib)); + + // verify that the library exists + let mut lib_location = vcpkg_target.lib_path.clone(); + lib_location.push(required_lib.clone() + ".lib"); + + if !lib_location.exists() { + return Err(Error::LibNotFound(lib_location.display().to_string())); + } + lib.found_libs.push(lib_location); + } + + if !vcpkg_target.is_static { + for required_dll in &self.required_dlls { + let mut dll_location = vcpkg_target.bin_path.clone(); + dll_location.push(required_dll.clone() + ".dll"); + + // verify that the DLL exists + if !dll_location.exists() { + return Err(Error::LibNotFound(dll_location.display().to_string())); + } + lib.found_dlls.push(dll_location); + } + } + + Ok(()) + } + + fn do_dll_copy(&mut self, lib: &mut Library) -> Result<(), Error> { + if let Some(target_dir) = env::var_os("OUT_DIR") { + if !lib.found_dlls.is_empty() { + for file in &lib.found_dlls { + let mut dest_path = Path::new(target_dir.as_os_str()).to_path_buf(); + dest_path.push(Path::new(file.file_name().unwrap())); + try!( + fs::copy(file, &dest_path).map_err(|_| Error::LibNotFound(format!( + "Can't copy file {} to {}", + file.to_string_lossy(), + dest_path.to_string_lossy() + ))) + ); + println!( + "vcpkg build helper copied {} to {}", + file.to_string_lossy(), + dest_path.to_string_lossy() + ); + } + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search=native={}", + env::var("OUT_DIR").unwrap() + )); + // work around https://github.com/rust-lang/cargo/issues/3957 + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search={}", + env::var("OUT_DIR").unwrap() + )); + } + } else { + return Err(Error::LibNotFound("Unable to get OUT_DIR".to_owned())); + } + Ok(()) + } + + /// Find the package `port_name` in a Vcpkg tree. + /// + /// Emits cargo metadata to link to libraries provided by the Vcpkg package/port + /// named, and any (non-system) libraries that they depend on. + /// + /// This will select the architecture and linkage based on environment + /// variables and build flags as described in the module docs, and any configuration + /// set on the builder. + pub fn find_package(&mut self, port_name: &str) -> Result<Library, Error> { + // determine the target type, bailing out if it is not some + // kind of msvc + let msvc_target = try!(msvc_target()); + + // bail out if requested to not try at all + if env::var_os("VCPKGRS_DISABLE").is_some() { + return Err(Error::DisabledByEnv("VCPKGRS_DISABLE".to_owned())); + } + + // bail out if requested to not try at all (old) + if env::var_os("NO_VCPKG").is_some() { + return Err(Error::DisabledByEnv("NO_VCPKG".to_owned())); + } + + // bail out if requested to skip this package + let abort_var_name = format!("VCPKGRS_NO_{}", envify(port_name)); + if env::var_os(&abort_var_name).is_some() { + return Err(Error::DisabledByEnv(abort_var_name)); + } + + // bail out if requested to skip this package (old) + let abort_var_name = format!("{}_NO_VCPKG", envify(port_name)); + if env::var_os(&abort_var_name).is_some() { + return Err(Error::DisabledByEnv(abort_var_name)); + } + + let vcpkg_target = try!(find_vcpkg_target(&msvc_target)); + + // if no overrides have been selected, then the Vcpkg port name + // is the the .lib name and the .dll name + if self.required_libs.is_empty() { + let ports = try!(load_ports(&vcpkg_target)); + + if ports.get(&port_name.to_owned()).is_none() { + return Err(Error::LibNotFound(port_name.to_owned())); + } + + // the complete set of ports required + let mut required_ports: BTreeMap<String, Port> = BTreeMap::new(); + + // working of ports that we need to include + // let mut ports_to_scan: BTreeSet<String> = BTreeSet::new(); + // ports_to_scan.insert(port_name.to_owned()); + let mut ports_to_scan = vec![port_name.to_owned()]; //: Vec<String> = BTreeSet::new(); + + while !ports_to_scan.is_empty() { + let port_name = ports_to_scan.pop().unwrap(); + + if required_ports.contains_key(&port_name) { + continue; + } + + if let Some(port) = ports.get(&port_name) { + for dep in &port.deps { + ports_to_scan.push(dep.clone()); + } + required_ports.insert(port_name, (*port).clone()); + } else { + // what? + } + } + + // for port in ports { + // println!("port {:?}", port); + // } + // println!("============================="); + //for port in &required_ports { + // println!("required port {:?}", port); + //} + + // if no overrides have been selected, then the Vcpkg port name + // is the the .lib name and the .dll name + if self.required_libs.is_empty() { + for (_, port) in &required_ports { + self.required_libs.extend(port.libs.iter().map(|s| { + Path::new(&s) + .file_stem() + .unwrap() + .to_string_lossy() + .into_owned() + })); + self.required_dlls + .extend(port.dlls.iter().cloned().map(|s| { + Path::new(&s) + .file_stem() + .unwrap() + .to_string_lossy() + .into_owned() + })); + } + } + } + // require explicit opt-in before using dynamically linked + // variants, otherwise cargo install of various things will + // stop working if Vcpkg is installed. + if !vcpkg_target.is_static && !env::var_os("VCPKGRS_DYNAMIC").is_some() { + return Err(Error::RequiredEnvMissing("VCPKGRS_DYNAMIC".to_owned())); + } + + let mut lib = Library::new(vcpkg_target.is_static); + + if self.emit_includes { + lib.cargo_metadata.push(format!( + "cargo:include={}", + vcpkg_target.include_path.display() + )); + } + lib.include_paths.push(vcpkg_target.include_path.clone()); + + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search=native={}", + vcpkg_target + .lib_path + .to_str() + .expect("failed to convert string type") + )); + lib.link_paths.push(vcpkg_target.lib_path.clone()); + if !vcpkg_target.is_static { + lib.cargo_metadata.push(format!( + "cargo:rustc-link-search=native={}", + vcpkg_target + .bin_path + .to_str() + .expect("failed to convert string type") + )); + // this path is dropped by recent versions of cargo hence the copies to OUT_DIR below + lib.dll_paths.push(vcpkg_target.bin_path.clone()); + } + + try!(self.emit_libs(&mut lib, &vcpkg_target)); + + if self.copy_dlls { + try!(self.do_dll_copy(&mut lib)); + } + + if self.cargo_metadata { + for line in &lib.cargo_metadata { + println!("{}", line); + } + } + Ok(lib) + } +} + +impl Library { + fn new(is_static: bool) -> Library { + Library { + link_paths: Vec::new(), + dll_paths: Vec::new(), + include_paths: Vec::new(), + cargo_metadata: Vec::new(), + is_static: is_static, + found_dlls: Vec::new(), + found_libs: Vec::new(), + } + } +} + +fn envify(name: &str) -> String { + name.chars() + .map(|c| c.to_ascii_uppercase()) + .map(|c| if c == '-' { '_' } else { c }) + .collect() +} + +fn msvc_target() -> Result<MSVCTarget, Error> { + let target = env::var("TARGET").unwrap_or(String::new()); + if !target.contains("-pc-windows-msvc") { + Err(Error::NotMSVC) + } else if target.starts_with("x86_64-") { + Ok(MSVCTarget::X64) + } else { + // everything else is x86 + Ok(MSVCTarget::X86) + } +} + +#[cfg(test)] +mod tests { + + extern crate tempdir; + + use super::*; + use std::env; + use std::sync::Mutex; + + lazy_static! { + static ref LOCK: Mutex<()> = Mutex::new(()); + } + + #[test] + fn do_nothing_for_non_msvc_target() { + let _g = LOCK.lock(); + env::set_var("VCPKG_ROOT", "/"); + env::set_var("TARGET", "x86_64-unknown-linux-gnu"); + assert!(match ::probe_package("foo") { + Err(Error::NotMSVC) => true, + _ => false, + }); + + env::set_var("TARGET", "x86_64-pc-windows-gnu"); + assert_eq!(env::var("TARGET"), Ok("x86_64-pc-windows-gnu".to_string())); + assert!(match ::probe_package("foo") { + Err(Error::NotMSVC) => true, + _ => false, + }); + env::remove_var("TARGET"); + env::remove_var("VCPKG_ROOT"); + } + + #[test] + fn do_nothing_for_bailout_variables_set() { + let _g = LOCK.lock(); + env::set_var("VCPKG_ROOT", "/"); + env::set_var("TARGET", "x86_64-pc-windows-msvc"); + + for &var in &[ + "VCPKGRS_DISABLE", + "VCPKGRS_NO_FOO", + "FOO_NO_VCPKG", + "NO_VCPKG", + ] { + env::set_var(var, "1"); + assert!(match ::probe_package("foo") { + Err(Error::DisabledByEnv(ref v)) if v == var => true, + _ => false, + }); + env::remove_var(var); + } + env::remove_var("TARGET"); + env::remove_var("VCPKG_ROOT"); + } + + // these tests are good but are leaning on a real vcpkg installation + + #[test] + fn default_build_refuses_dynamic() { + let _g = LOCK.lock(); + clean_env(); + env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("no-status")); + env::set_var("TARGET", "x86_64-pc-windows-msvc"); + println!("Result is {:?}", ::find_package("libmysql")); + assert!(match ::find_package("libmysql") { + Err(Error::RequiredEnvMissing(ref v)) if v == "VCPKGRS_DYNAMIC" => true, + _ => false, + }); + clean_env(); + } + + #[test] + fn static_build_finds_lib() { + let _g = LOCK.lock(); + clean_env(); + env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("normalized")); + env::set_var("TARGET", "x86_64-pc-windows-msvc"); + let tmp_dir = tempdir::TempDir::new("vcpkg_tests").unwrap(); + env::set_var("OUT_DIR", tmp_dir.path()); + + // CARGO_CFG_TARGET_FEATURE is set in response to + // RUSTFLAGS=-Ctarget-feature=+crt-static. It would + // be nice to test that also. + env::set_var("CARGO_CFG_TARGET_FEATURE", "crt-static"); + println!("Result is {:?}", ::find_package("libmysql")); + assert!(match ::find_package("libmysql") { + Ok(_) => true, + _ => false, + }); + clean_env(); + } + + #[test] + fn dynamic_build_finds_lib() { + let _g = LOCK.lock(); + clean_env(); + env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("no-status")); + env::set_var("TARGET", "x86_64-pc-windows-msvc"); + env::set_var("VCPKGRS_DYNAMIC", "1"); + let tmp_dir = tempdir::TempDir::new("vcpkg_tests").unwrap(); + env::set_var("OUT_DIR", tmp_dir.path()); + + println!("Result is {:?}", ::find_package("libmysql")); + assert!(match ::find_package("libmysql") { + Ok(_) => true, + _ => false, + }); + clean_env(); + } + + #[test] + fn handle_multiline_description() { + let _g = LOCK.lock(); + clean_env(); + env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("multiline-description")); + env::set_var("TARGET", "i686-pc-windows-msvc"); + env::set_var("VCPKGRS_DYNAMIC", "1"); + let tmp_dir = tempdir::TempDir::new("vcpkg_tests").unwrap(); + env::set_var("OUT_DIR", tmp_dir.path()); + + println!("Result is {:?}", ::find_package("graphite2")); + assert!(match ::find_package("graphite2") { + Ok(_) => true, + _ => false, + }); + clean_env(); + } + + #[test] + fn link_libs_required_by_optional_features() { + let _g = LOCK.lock(); + clean_env(); + env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("normalized")); + env::set_var("TARGET", "i686-pc-windows-msvc"); + env::set_var("VCPKGRS_DYNAMIC", "1"); + let tmp_dir = tempdir::TempDir::new("vcpkg_tests").unwrap(); + env::set_var("OUT_DIR", tmp_dir.path()); + + println!("Result is {:?}", ::find_package("harfbuzz")); + assert!(match ::find_package("harfbuzz") { + Ok(lib) => lib + .cargo_metadata + .iter() + .find(|&x| x == "cargo:rustc-link-lib=icuuc") + .is_some(), + _ => false, + }); + clean_env(); + } + + // #[test] + // fn dynamic_build_package_specific_bailout() { + // clean_env(); + // env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("no-status")); + // env::set_var("TARGET", "x86_64-pc-windows-msvc"); + // env::set_var("VCPKGRS_DYNAMIC", "1"); + // env::set_var("VCPKGRS_NO_LIBMYSQL", "1"); + + // println!("Result is {:?}", ::find_package("libmysql")); + // assert!(match ::find_package("libmysql") { + // Err(Error::DisabledByEnv(ref v)) if v == "VCPKGRS_NO_LIBMYSQL" => true, + // _ => false, + // }); + // clean_env(); + // } + + // #[test] + // fn dynamic_build_global_bailout() { + // clean_env(); + // env::set_var("VCPKG_ROOT", vcpkg_test_tree_loc("no-status")); + // env::set_var("TARGET", "x86_64-pc-windows-msvc"); + // env::set_var("VCPKGRS_DYNAMIC", "1"); + // env::set_var("VCPKGRS_DISABLE", "1"); + + // println!("Result is {:?}", ::find_package("libmysql")); + // assert!(match ::find_package("libmysql") { + // Err(Error::DisabledByEnv(ref v)) if v == "VCPKGRS_DISABLE" => true, + // _ => false, + // }); + // clean_env(); + // } + + fn clean_env() { + env::remove_var("TARGET"); + env::remove_var("VCPKG_ROOT"); + env::remove_var("VCPKGRS_DYNAMIC"); + env::remove_var("RUSTFLAGS"); + env::remove_var("CARGO_CFG_TARGET_FEATURE"); + env::remove_var("VCPKGRS_DISABLE"); + env::remove_var("VCPKGRS_NO_LIBMYSQL"); + } + + // path to a to vcpkg installation to test against + fn vcpkg_test_tree_loc(name: &str) -> PathBuf { + let mut path = PathBuf::new(); + path.push(env::var("CARGO_MANIFEST_DIR").unwrap()); + path.pop(); + path.push("test-data"); + path.push(name); + path + } +} diff --git a/vec_map/.cargo-checksum.json b/vec_map/.cargo-checksum.json new file mode 100644 index 000000000..7b7431e6f --- /dev/null +++ b/vec_map/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"} \ No newline at end of file diff --git a/vec_map/Cargo.toml b/vec_map/Cargo.toml new file mode 100644 index 000000000..14691db92 --- /dev/null +++ b/vec_map/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "vec_map" +version = "0.8.1" +authors = ["Alex Crichton <alex@alexcrichton.com>", "Jorge Aparicio <japaricious@gmail.com>", "Alexis Beingessner <a.beingessner@gmail.com>", "Brian Anderson <>", "tbu- <>", "Manish Goregaokar <>", "Aaron Turon <aturon@mozilla.com>", "Adolfo Ochagavía <>", "Niko Matsakis <>", "Steven Fackler <>", "Chase Southwood <csouth3@illinois.edu>", "Eduard Burtescu <>", "Florian Wilkens <>", "Félix Raimundo <>", "Tibor Benke <>", "Markus Siemens <markus@m-siemens.de>", "Josh Branchaud <jbranchaud@gmail.com>", "Huon Wilson <dbau.pp@gmail.com>", "Corey Farwell <coref@rwell.org>", "Aaron Liblong <>", "Nick Cameron <nrc@ncameron.org>", "Patrick Walton <pcwalton@mimiga.net>", "Felix S Klock II <>", "Andrew Paseltiner <apaseltiner@gmail.com>", "Sean McArthur <sean.monstar@gmail.com>", "Vadim Petrochenkov <>"] +description = "A simple map based on a vector for small integer keys" +homepage = "https://github.com/contain-rs/vec-map" +documentation = "https://contain-rs.github.io/vec-map/vec_map" +readme = "README.md" +keywords = ["data-structures", "collections", "vecmap", "vec_map", "contain-rs"] +license = "MIT/Apache-2.0" +repository = "https://github.com/contain-rs/vec-map" +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true + +[features] +eders = ["serde"] diff --git a/vec_map/LICENSE-APACHE b/vec_map/LICENSE-APACHE new file mode 100644 index 000000000..583bd5a98 --- /dev/null +++ b/vec_map/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vec_map/LICENSE-MIT b/vec_map/LICENSE-MIT new file mode 100644 index 000000000..bf85e629c --- /dev/null +++ b/vec_map/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vec_map/README.md b/vec_map/README.md new file mode 100644 index 000000000..82394df8c --- /dev/null +++ b/vec_map/README.md @@ -0,0 +1,15 @@ +**WARNING: THIS PROJECT IS IN MAINTENANCE MODE, DUE TO INSUFFICIENT MAINTAINER RESOURCES** + +It works fine, but will generally no longer be improved. + +We are currently only accepting changes which: + +* keep this compiling with the latest versions of Rust or its dependencies. +* have minimal review requirements, such as documentation changes (so not totally new APIs). + +------ + + +A simple map based on a vector for small integer keys. + +Documentation is available at https://contain-rs.github.io/vec-map/vec_map. diff --git a/vec_map/deploy-docs.sh b/vec_map/deploy-docs.sh new file mode 100644 index 000000000..305be53e6 --- /dev/null +++ b/vec_map/deploy-docs.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -o errexit -o nounset + +rev=$(git rev-parse --short HEAD) + +cd target/doc + +git init +git config user.email 'FlashCat@users.noreply.github.com' +git config user.name 'FlashCat' +git remote add upstream "https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git" +git fetch upstream gh-pages +git reset upstream/gh-pages + +touch . + +git add -A . +git commit -m "rebuild pages at ${rev}" +git push -q upstream HEAD:gh-pages diff --git a/vec_map/src/lib.rs b/vec_map/src/lib.rs new file mode 100644 index 000000000..2bb7b3c96 --- /dev/null +++ b/vec_map/src/lib.rs @@ -0,0 +1,1623 @@ +// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(missing_docs)] + +//! A simple map based on a vector for small integer keys. Space requirements +//! are O(highest integer key). + +// optional serde support +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +use self::Entry::*; + +use std::cmp::{Ordering, max}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::iter::{Enumerate, FilterMap, FromIterator}; +use std::mem::{replace, swap}; +use std::ops::{Index, IndexMut}; +use std::slice; +use std::vec; + +/// A map optimized for small integer keys. +/// +/// # Examples +/// +/// ``` +/// use vec_map::VecMap; +/// +/// let mut months = VecMap::new(); +/// months.insert(1, "Jan"); +/// months.insert(2, "Feb"); +/// months.insert(3, "Mar"); +/// +/// if !months.contains_key(12) { +/// println!("The end is near!"); +/// } +/// +/// assert_eq!(months.get(1), Some(&"Jan")); +/// +/// if let Some(value) = months.get_mut(3) { +/// *value = "Venus"; +/// } +/// +/// assert_eq!(months.get(3), Some(&"Venus")); +/// +/// // Print out all months +/// for (key, value) in &months { +/// println!("month {} is {}", key, value); +/// } +/// +/// months.clear(); +/// assert!(months.is_empty()); +/// ``` +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct VecMap<V> { + n: usize, + v: Vec<Option<V>>, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +pub enum Entry<'a, V: 'a> { + /// A vacant Entry + Vacant(VacantEntry<'a, V>), + + /// An occupied Entry + Occupied(OccupiedEntry<'a, V>), +} + +/// A vacant Entry. +pub struct VacantEntry<'a, V: 'a> { + map: &'a mut VecMap<V>, + index: usize, +} + +/// An occupied Entry. +pub struct OccupiedEntry<'a, V: 'a> { + map: &'a mut VecMap<V>, + index: usize, +} + +impl<V> Default for VecMap<V> { + #[inline] + fn default() -> Self { Self::new() } +} + +impl<V: Hash> Hash for VecMap<V> { + fn hash<H: Hasher>(&self, state: &mut H) { + // In order to not traverse the `VecMap` twice, count the elements + // during iteration. + let mut count: usize = 0; + for elt in self { + elt.hash(state); + count += 1; + } + count.hash(state); + } +} + +impl<V> VecMap<V> { + /// Creates an empty `VecMap`. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let mut map: VecMap<&str> = VecMap::new(); + /// ``` + pub fn new() -> Self { VecMap { n: 0, v: vec![] } } + + /// Creates an empty `VecMap` with space for at least `capacity` + /// elements before resizing. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let mut map: VecMap<&str> = VecMap::with_capacity(10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + VecMap { n: 0, v: Vec::with_capacity(capacity) } + } + + /// Returns the number of elements the `VecMap` can hold without + /// reallocating. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let map: VecMap<String> = VecMap::with_capacity(10); + /// assert!(map.capacity() >= 10); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.v.capacity() + } + + /// Reserves capacity for the given `VecMap` to contain `len` distinct keys. + /// In the case of `VecMap` this means reallocations will not occur as long + /// as all inserted keys are less than `len`. + /// + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let mut map: VecMap<&str> = VecMap::new(); + /// map.reserve_len(10); + /// assert!(map.capacity() >= 10); + /// ``` + pub fn reserve_len(&mut self, len: usize) { + let cur_len = self.v.len(); + if len >= cur_len { + self.v.reserve(len - cur_len); + } + } + + /// Reserves the minimum capacity for the given `VecMap` to contain `len` distinct keys. + /// In the case of `VecMap` this means reallocations will not occur as long as all inserted + /// keys are less than `len`. + /// + /// Note that the allocator may give the collection more space than it requests. + /// Therefore capacity cannot be relied upon to be precisely minimal. Prefer + /// `reserve_len` if future insertions are expected. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let mut map: VecMap<&str> = VecMap::new(); + /// map.reserve_len_exact(10); + /// assert!(map.capacity() >= 10); + /// ``` + pub fn reserve_len_exact(&mut self, len: usize) { + let cur_len = self.v.len(); + if len >= cur_len { + self.v.reserve_exact(len - cur_len); + } + } + + /// Trims the `VecMap` of any excess capacity. + /// + /// The collection may reserve more space to avoid frequent reallocations. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// let mut map: VecMap<&str> = VecMap::with_capacity(10); + /// map.shrink_to_fit(); + /// assert_eq!(map.capacity(), 0); + /// ``` + pub fn shrink_to_fit(&mut self) { + // strip off trailing `None`s + if let Some(idx) = self.v.iter().rposition(Option::is_some) { + self.v.truncate(idx + 1); + } else { + self.v.clear(); + } + + self.v.shrink_to_fit() + } + + /// Returns an iterator visiting all keys in ascending order of the keys. + /// The iterator's element type is `usize`. + pub fn keys(&self) -> Keys<V> { + Keys { iter: self.iter() } + } + + /// Returns an iterator visiting all values in ascending order of the keys. + /// The iterator's element type is `&'r V`. + pub fn values(&self) -> Values<V> { + Values { iter: self.iter() } + } + + /// Returns an iterator visiting all values in ascending order of the keys. + /// The iterator's element type is `&'r mut V`. + pub fn values_mut(&mut self) -> ValuesMut<V> { + ValuesMut { iter_mut: self.iter_mut() } + } + + /// Returns an iterator visiting all key-value pairs in ascending order of the keys. + /// The iterator's element type is `(usize, &'r V)`. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// // Print `1: a` then `2: b` then `3: c` + /// for (key, value) in map.iter() { + /// println!("{}: {}", key, value); + /// } + /// ``` + pub fn iter(&self) -> Iter<V> { + Iter { + front: 0, + back: self.v.len(), + n: self.n, + yielded: 0, + iter: self.v.iter() + } + } + + /// Returns an iterator visiting all key-value pairs in ascending order of the keys, + /// with mutable references to the values. + /// The iterator's element type is `(usize, &'r mut V)`. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// map.insert(2, "b"); + /// map.insert(3, "c"); + /// + /// for (key, value) in map.iter_mut() { + /// *value = "x"; + /// } + /// + /// for (key, value) in &map { + /// assert_eq!(value, &"x"); + /// } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<V> { + IterMut { + front: 0, + back: self.v.len(), + n: self.n, + yielded: 0, + iter: self.v.iter_mut() + } + } + + /// Moves all elements from `other` into the map while overwriting existing keys. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut a = VecMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// let mut b = VecMap::new(); + /// b.insert(3, "c"); + /// b.insert(4, "d"); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a[1], "a"); + /// assert_eq!(a[2], "b"); + /// assert_eq!(a[3], "c"); + /// assert_eq!(a[4], "d"); + /// ``` + pub fn append(&mut self, other: &mut Self) { + self.extend(other.drain()); + } + + /// Splits the collection into two at the given key. + /// + /// Returns a newly allocated `Self`. `self` contains elements `[0, at)`, + /// and the returned `Self` contains elements `[at, max_key)`. + /// + /// Note that the capacity of `self` does not change. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut a = VecMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "d"); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a[1], "a"); + /// assert_eq!(a[2], "b"); + /// + /// assert_eq!(b[3], "c"); + /// assert_eq!(b[4], "d"); + /// ``` + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = VecMap::new(); + + if at == 0 { + // Move all elements to other + // The swap will also fix .n + swap(self, &mut other); + return other + } else if at >= self.v.len() { + // No elements to copy + return other; + } + + // Look up the index of the first non-None item + let first_index = self.v.iter().position(|el| el.is_some()); + let start_index = match first_index { + Some(index) => max(at, index), + None => { + // self has no elements + return other; + } + }; + + // Fill the new VecMap with `None`s until `start_index` + other.v.extend((0..start_index).map(|_| None)); + + // Move elements beginning with `start_index` from `self` into `other` + let mut taken = 0; + other.v.extend(self.v[start_index..].iter_mut().map(|el| { + let el = el.take(); + if el.is_some() { + taken += 1; + } + el + })); + other.n = taken; + self.n -= taken; + + other + } + + /// Returns an iterator visiting all key-value pairs in ascending order of + /// the keys, emptying (but not consuming) the original `VecMap`. + /// The iterator's element type is `(usize, &'r V)`. Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// let vec: Vec<(usize, &str)> = map.drain().collect(); + /// + /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]); + /// ``` + pub fn drain(&mut self) -> Drain<V> { + fn filter<A>((i, v): (usize, Option<A>)) -> Option<(usize, A)> { + v.map(|v| (i, v)) + } + let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr + + self.n = 0; + Drain { iter: self.v.drain(..).enumerate().filter_map(filter) } + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut a = VecMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + pub fn len(&self) -> usize { + self.n + } + + /// Returns true if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut a = VecMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.n == 0 + } + + /// Clears the map, removing all key-value pairs. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut a = VecMap::new(); + /// a.insert(1, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + pub fn clear(&mut self) { self.n = 0; self.v.clear() } + + /// Returns a reference to the value corresponding to the key. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(1), Some(&"a")); + /// assert_eq!(map.get(2), None); + /// ``` + pub fn get(&self, key: usize) -> Option<&V> { + if key < self.v.len() { + self.v[key].as_ref() + } else { + None + } + } + + /// Returns true if the map contains a value for the specified key. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(1), true); + /// assert_eq!(map.contains_key(2), false); + /// ``` + #[inline] + pub fn contains_key(&self, key: usize) -> bool { + self.get(key).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(1) { + /// *x = "b"; + /// } + /// assert_eq!(map[1], "b"); + /// ``` + pub fn get_mut(&mut self, key: usize) -> Option<&mut V> { + if key < self.v.len() { + self.v[key].as_mut() + } else { + None + } + } + + /// Inserts a key-value pair into the map. If the key already had a value + /// present in the map, that value is returned. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[37], "c"); + /// ``` + pub fn insert(&mut self, key: usize, value: V) -> Option<V> { + let len = self.v.len(); + if len <= key { + self.v.extend((0..key - len + 1).map(|_| None)); + } + let was = replace(&mut self.v[key], Some(value)); + if was.is_none() { + self.n += 1; + } + was + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.remove(1), Some("a")); + /// assert_eq!(map.remove(1), None); + /// ``` + pub fn remove(&mut self, key: usize) -> Option<V> { + if key >= self.v.len() { + return None; + } + let result = &mut self.v[key]; + let was = result.take(); + if was.is_some() { + self.n -= 1; + } + was + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut count: VecMap<u32> = VecMap::new(); + /// + /// // count the number of occurrences of numbers in the vec + /// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4] { + /// *count.entry(x).or_insert(0) += 1; + /// } + /// + /// assert_eq!(count[1], 3); + /// ``` + pub fn entry(&mut self, key: usize) -> Entry<V> { + // FIXME(Gankro): this is basically the dumbest implementation of + // entry possible, because weird non-lexical borrows issues make it + // completely insane to do any other way. That said, Entry is a border-line + // useless construct on VecMap, so it's hardly a big loss. + if self.contains_key(key) { + Occupied(OccupiedEntry { + map: self, + index: key, + }) + } else { + Vacant(VacantEntry { + map: self, + index: key, + }) + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map: VecMap<usize> = (0..8).map(|x|(x, x*10)).collect(); + /// map.retain(|k, _| k % 2 == 0); + /// assert_eq!(map.len(), 4); + /// ``` + pub fn retain<F>(&mut self, mut f: F) + where F: FnMut(usize, &mut V) -> bool + { + for (i, e) in self.v.iter_mut().enumerate() { + let remove = match *e { + Some(ref mut value) => !f(i, value), + None => false, + }; + if remove { + *e = None; + self.n -= 1; + } + } + } +} + +impl<'a, V> Entry<'a, V> { + /// Ensures a value is in the entry by inserting the default if empty, and + /// returns a mutable reference to the value in the entry. + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default + /// function if empty, and returns a mutable reference to the value in the + /// entry. + pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } +} + +impl<'a, V> VacantEntry<'a, V> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + pub fn insert(self, value: V) -> &'a mut V { + let index = self.index; + self.map.insert(index, value); + &mut self.map[index] + } +} + +impl<'a, V> OccupiedEntry<'a, V> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &V { + let index = self.index; + &self.map[index] + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut V { + let index = self.index; + &mut self.map[index] + } + + /// Converts the entry into a mutable reference to its value. + pub fn into_mut(self) -> &'a mut V { + let index = self.index; + &mut self.map[index] + } + + /// Sets the value of the entry with the OccupiedEntry's key, + /// and returns the entry's old value. + pub fn insert(&mut self, value: V) -> V { + let index = self.index; + self.map.insert(index, value).unwrap() + } + + /// Takes the value of the entry out of the map, and returns it. + pub fn remove(self) -> V { + let index = self.index; + self.map.remove(index).unwrap() + } +} + +impl<V: Clone> Clone for VecMap<V> { + #[inline] + fn clone(&self) -> Self { + VecMap { n: self.n, v: self.v.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.v.clone_from(&source.v); + self.n = source.n; + } +} + +impl<V: PartialEq> PartialEq for VecMap<V> { + fn eq(&self, other: &Self) -> bool { + self.n == other.n && self.iter().eq(other.iter()) + } +} + +impl<V: Eq> Eq for VecMap<V> {} + +impl<V: PartialOrd> PartialOrd for VecMap<V> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.iter().partial_cmp(other.iter()) + } +} + +impl<V: Ord> Ord for VecMap<V> { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other.iter()) + } +} + +impl<V: fmt::Debug> fmt::Debug for VecMap<V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_map().entries(self).finish() + } +} + +impl<V> FromIterator<(usize, V)> for VecMap<V> { + fn from_iter<I: IntoIterator<Item = (usize, V)>>(iter: I) -> Self { + let mut map = Self::new(); + map.extend(iter); + map + } +} + +impl<T> IntoIterator for VecMap<T> { + type Item = (usize, T); + type IntoIter = IntoIter<T>; + + /// Returns an iterator visiting all key-value pairs in ascending order of + /// the keys, consuming the original `VecMap`. + /// The iterator's element type is `(usize, &'r V)`. + /// + /// # Examples + /// + /// ``` + /// use vec_map::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// let vec: Vec<(usize, &str)> = map.into_iter().collect(); + /// + /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]); + /// ``` + fn into_iter(self) -> IntoIter<T> { + IntoIter { + n: self.n, + yielded: 0, + iter: self.v.into_iter().enumerate() + } + } +} + +impl<'a, T> IntoIterator for &'a VecMap<T> { + type Item = (usize, &'a T); + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut VecMap<T> { + type Item = (usize, &'a mut T); + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl<V> Extend<(usize, V)> for VecMap<V> { + fn extend<I: IntoIterator<Item = (usize, V)>>(&mut self, iter: I) { + for (k, v) in iter { + self.insert(k, v); + } + } +} + +impl<'a, V: Copy> Extend<(usize, &'a V)> for VecMap<V> { + fn extend<I: IntoIterator<Item = (usize, &'a V)>>(&mut self, iter: I) { + self.extend(iter.into_iter().map(|(key, &value)| (key, value))); + } +} + +impl<V> Index<usize> for VecMap<V> { + type Output = V; + + #[inline] + fn index(&self, i: usize) -> &V { + self.get(i).expect("key not present") + } +} + +impl<'a, V> Index<&'a usize> for VecMap<V> { + type Output = V; + + #[inline] + fn index(&self, i: &usize) -> &V { + self.get(*i).expect("key not present") + } +} + +impl<V> IndexMut<usize> for VecMap<V> { + #[inline] + fn index_mut(&mut self, i: usize) -> &mut V { + self.get_mut(i).expect("key not present") + } +} + +impl<'a, V> IndexMut<&'a usize> for VecMap<V> { + #[inline] + fn index_mut(&mut self, i: &usize) -> &mut V { + self.get_mut(*i).expect("key not present") + } +} + +macro_rules! iterator { + (impl $name:ident -> $elem:ty, $($getter:ident),+) => { + impl<'a, V> Iterator for $name<'a, V> { + type Item = $elem; + + #[inline] + fn next(&mut self) -> Option<$elem> { + while self.front < self.back { + if let Some(elem) = self.iter.next() { + if let Some(x) = elem$(. $getter ())+ { + let index = self.front; + self.front += 1; + self.yielded += 1; + return Some((index, x)); + } + } + self.front += 1; + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + (self.n - self.yielded, Some(self.n - self.yielded)) + } + } + } +} + +macro_rules! double_ended_iterator { + (impl $name:ident -> $elem:ty, $($getter:ident),+) => { + impl<'a, V> DoubleEndedIterator for $name<'a, V> { + #[inline] + fn next_back(&mut self) -> Option<$elem> { + while self.front < self.back { + if let Some(elem) = self.iter.next_back() { + if let Some(x) = elem$(. $getter ())+ { + self.back -= 1; + return Some((self.back, x)); + } + } + self.back -= 1; + } + None + } + } + } +} + +/// An iterator over the key-value pairs of a map. +pub struct Iter<'a, V: 'a> { + front: usize, + back: usize, + n: usize, + yielded: usize, + iter: slice::Iter<'a, Option<V>> +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, V> Clone for Iter<'a, V> { + fn clone(&self) -> Iter<'a, V> { + Iter { + front: self.front, + back: self.back, + n: self.n, + yielded: self.yielded, + iter: self.iter.clone() + } + } +} + +iterator! { impl Iter -> (usize, &'a V), as_ref } +impl<'a, V> ExactSizeIterator for Iter<'a, V> {} +double_ended_iterator! { impl Iter -> (usize, &'a V), as_ref } + +/// An iterator over the key-value pairs of a map, with the +/// values being mutable. +pub struct IterMut<'a, V: 'a> { + front: usize, + back: usize, + n: usize, + yielded: usize, + iter: slice::IterMut<'a, Option<V>> +} + +iterator! { impl IterMut -> (usize, &'a mut V), as_mut } +impl<'a, V> ExactSizeIterator for IterMut<'a, V> {} +double_ended_iterator! { impl IterMut -> (usize, &'a mut V), as_mut } + +/// An iterator over the keys of a map. +pub struct Keys<'a, V: 'a> { + iter: Iter<'a, V>, +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, V> Clone for Keys<'a, V> { + fn clone(&self) -> Keys<'a, V> { + Keys { + iter: self.iter.clone() + } + } +} + +/// An iterator over the values of a map. +pub struct Values<'a, V: 'a> { + iter: Iter<'a, V>, +} + +// FIXME(#19839) Remove in favor of `#[derive(Clone)]` +impl<'a, V> Clone for Values<'a, V> { + fn clone(&self) -> Values<'a, V> { + Values { + iter: self.iter.clone() + } + } +} + +/// An iterator over the values of a map. +pub struct ValuesMut<'a, V: 'a> { + iter_mut: IterMut<'a, V>, +} + +/// A consuming iterator over the key-value pairs of a map. +pub struct IntoIter<V> { + n: usize, + yielded: usize, + iter: Enumerate<vec::IntoIter<Option<V>>>, +} + +/// A draining iterator over the key-value pairs of a map. +pub struct Drain<'a, V: 'a> { + iter: FilterMap< + Enumerate<vec::Drain<'a, Option<V>>>, + fn((usize, Option<V>)) -> Option<(usize, V)>> +} + +impl<'a, V> Iterator for Drain<'a, V> { + type Item = (usize, V); + + fn next(&mut self) -> Option<(usize, V)> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +impl<'a, V> ExactSizeIterator for Drain<'a, V> {} + +impl<'a, V> DoubleEndedIterator for Drain<'a, V> { + fn next_back(&mut self) -> Option<(usize, V)> { self.iter.next_back() } +} + +impl<'a, V> Iterator for Keys<'a, V> { + type Item = usize; + + fn next(&mut self) -> Option<usize> { self.iter.next().map(|e| e.0) } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +impl<'a, V> ExactSizeIterator for Keys<'a, V> {} + +impl<'a, V> DoubleEndedIterator for Keys<'a, V> { + fn next_back(&mut self) -> Option<usize> { self.iter.next_back().map(|e| e.0) } +} + +impl<'a, V> Iterator for Values<'a, V> { + type Item = &'a V; + + fn next(&mut self) -> Option<(&'a V)> { self.iter.next().map(|e| e.1) } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +impl<'a, V> ExactSizeIterator for Values<'a, V> {} + +impl<'a, V> DoubleEndedIterator for Values<'a, V> { + fn next_back(&mut self) -> Option<(&'a V)> { self.iter.next_back().map(|e| e.1) } +} + +impl<'a, V> Iterator for ValuesMut<'a, V> { + type Item = &'a mut V; + + fn next(&mut self) -> Option<(&'a mut V)> { self.iter_mut.next().map(|e| e.1) } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter_mut.size_hint() } +} + +impl<'a, V> ExactSizeIterator for ValuesMut<'a, V> {} + +impl<'a, V> DoubleEndedIterator for ValuesMut<'a, V> { + fn next_back(&mut self) -> Option<&'a mut V> { self.iter_mut.next_back().map(|e| e.1) } +} + +impl<V> Iterator for IntoIter<V> { + type Item = (usize, V); + + fn next(&mut self) -> Option<(usize, V)> { + loop { + match self.iter.next() { + None => return None, + Some((i, Some(value))) => { + self.yielded += 1; + return Some((i, value)) + }, + _ => {} + } + } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.n - self.yielded, Some(self.n - self.yielded)) + } +} + +impl<V> ExactSizeIterator for IntoIter<V> {} + +impl<V> DoubleEndedIterator for IntoIter<V> { + fn next_back(&mut self) -> Option<(usize, V)> { + loop { + match self.iter.next_back() { + None => return None, + Some((i, Some(value))) => return Some((i, value)), + _ => {} + } + } + } +} + +#[allow(dead_code)] +fn assert_properties() { + fn vec_map_covariant<'a, T>(map: VecMap<&'static T>) -> VecMap<&'a T> { map } + + fn into_iter_covariant<'a, T>(iter: IntoIter<&'static T>) -> IntoIter<&'a T> { iter } + + fn iter_covariant<'i, 'a, T>(iter: Iter<'i, &'static T>) -> Iter<'i, &'a T> { iter } + + fn keys_covariant<'i, 'a, T>(iter: Keys<'i, &'static T>) -> Keys<'i, &'a T> { iter } + + fn values_covariant<'i, 'a, T>(iter: Values<'i, &'static T>) -> Values<'i, &'a T> { iter } +} + +#[cfg(test)] +mod test { + use super::VecMap; + use super::Entry::{Occupied, Vacant}; + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + #[test] + fn test_get_mut() { + let mut m = VecMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(5) { + None => panic!(), Some(x) => *x = new + } + assert_eq!(m.get(5), Some(&new)); + } + + #[test] + fn test_len() { + let mut map = VecMap::new(); + assert_eq!(map.len(), 0); + assert!(map.is_empty()); + assert!(map.insert(5, 20).is_none()); + assert_eq!(map.len(), 1); + assert!(!map.is_empty()); + assert!(map.insert(11, 12).is_none()); + assert_eq!(map.len(), 2); + assert!(!map.is_empty()); + assert!(map.insert(14, 22).is_none()); + assert_eq!(map.len(), 3); + assert!(!map.is_empty()); + } + + #[test] + fn test_clear() { + let mut map = VecMap::new(); + assert!(map.insert(5, 20).is_none()); + assert!(map.insert(11, 12).is_none()); + assert!(map.insert(14, 22).is_none()); + map.clear(); + assert!(map.is_empty()); + assert!(map.get(5).is_none()); + assert!(map.get(11).is_none()); + assert!(map.get(14).is_none()); + } + + #[test] + fn test_insert() { + let mut m = VecMap::new(); + assert_eq!(m.insert(1, 2), None); + assert_eq!(m.insert(1, 3), Some(2)); + assert_eq!(m.insert(1, 4), Some(3)); + } + + #[test] + fn test_remove() { + let mut m = VecMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(1), Some(2)); + assert_eq!(m.remove(1), None); + } + + #[test] + fn test_keys() { + let mut map = VecMap::new(); + map.insert(1, 'a'); + map.insert(2, 'b'); + map.insert(3, 'c'); + let keys: Vec<_> = map.keys().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let mut map = VecMap::new(); + map.insert(1, 'a'); + map.insert(2, 'b'); + map.insert(3, 'c'); + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_iterator() { + let mut m = VecMap::new(); + + assert!(m.insert(0, 1).is_none()); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(3, 5).is_none()); + assert!(m.insert(6, 10).is_none()); + assert!(m.insert(10, 11).is_none()); + + let mut it = m.iter(); + assert_eq!(it.size_hint(), (5, Some(5))); + assert_eq!(it.next().unwrap(), (0, &1)); + assert_eq!(it.size_hint(), (4, Some(4))); + assert_eq!(it.next().unwrap(), (1, &2)); + assert_eq!(it.size_hint(), (3, Some(3))); + assert_eq!(it.next().unwrap(), (3, &5)); + assert_eq!(it.size_hint(), (2, Some(2))); + assert_eq!(it.next().unwrap(), (6, &10)); + assert_eq!(it.size_hint(), (1, Some(1))); + assert_eq!(it.next().unwrap(), (10, &11)); + assert_eq!(it.size_hint(), (0, Some(0))); + assert!(it.next().is_none()); + } + + #[test] + fn test_iterator_size_hints() { + let mut m = VecMap::new(); + + assert!(m.insert(0, 1).is_none()); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(3, 5).is_none()); + assert!(m.insert(6, 10).is_none()); + assert!(m.insert(10, 11).is_none()); + + assert_eq!(m.iter().size_hint(), (5, Some(5))); + assert_eq!(m.iter().rev().size_hint(), (5, Some(5))); + assert_eq!(m.iter_mut().size_hint(), (5, Some(5))); + assert_eq!(m.iter_mut().rev().size_hint(), (5, Some(5))); + } + + #[test] + fn test_mut_iterator() { + let mut m = VecMap::new(); + + assert!(m.insert(0, 1).is_none()); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(3, 5).is_none()); + assert!(m.insert(6, 10).is_none()); + assert!(m.insert(10, 11).is_none()); + + for (k, v) in &mut m { + *v += k as isize; + } + + let mut it = m.iter(); + assert_eq!(it.next().unwrap(), (0, &1)); + assert_eq!(it.next().unwrap(), (1, &3)); + assert_eq!(it.next().unwrap(), (3, &8)); + assert_eq!(it.next().unwrap(), (6, &16)); + assert_eq!(it.next().unwrap(), (10, &21)); + assert!(it.next().is_none()); + } + + #[test] + fn test_rev_iterator() { + let mut m = VecMap::new(); + + assert!(m.insert(0, 1).is_none()); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(3, 5).is_none()); + assert!(m.insert(6, 10).is_none()); + assert!(m.insert(10, 11).is_none()); + + let mut it = m.iter().rev(); + assert_eq!(it.next().unwrap(), (10, &11)); + assert_eq!(it.next().unwrap(), (6, &10)); + assert_eq!(it.next().unwrap(), (3, &5)); + assert_eq!(it.next().unwrap(), (1, &2)); + assert_eq!(it.next().unwrap(), (0, &1)); + assert!(it.next().is_none()); + } + + #[test] + fn test_mut_rev_iterator() { + let mut m = VecMap::new(); + + assert!(m.insert(0, 1).is_none()); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(3, 5).is_none()); + assert!(m.insert(6, 10).is_none()); + assert!(m.insert(10, 11).is_none()); + + for (k, v) in m.iter_mut().rev() { + *v += k as isize; + } + + let mut it = m.iter(); + assert_eq!(it.next().unwrap(), (0, &1)); + assert_eq!(it.next().unwrap(), (1, &3)); + assert_eq!(it.next().unwrap(), (3, &8)); + assert_eq!(it.next().unwrap(), (6, &16)); + assert_eq!(it.next().unwrap(), (10, &21)); + assert!(it.next().is_none()); + } + + #[test] + fn test_move_iter() { + let mut m: VecMap<Box<_>> = VecMap::new(); + m.insert(1, Box::new(2)); + let mut called = false; + for (k, v) in m { + assert!(!called); + called = true; + assert_eq!(k, 1); + assert_eq!(v, Box::new(2)); + } + assert!(called); + } + + #[test] + fn test_drain_iterator() { + let mut map = VecMap::new(); + map.insert(1, "a"); + map.insert(3, "c"); + map.insert(2, "b"); + + let vec: Vec<_> = map.drain().collect(); + + assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]); + assert_eq!(map.len(), 0); + } + + #[test] + fn test_append() { + let mut a = VecMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + + let mut b = VecMap::new(); + b.insert(3, "d"); // Overwrite element from a + b.insert(4, "e"); + b.insert(5, "f"); + + a.append(&mut b); + + assert_eq!(a.len(), 5); + assert_eq!(b.len(), 0); + // Capacity shouldn't change for possible reuse + assert!(b.capacity() >= 4); + + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + assert_eq!(a[3], "d"); + assert_eq!(a[4], "e"); + assert_eq!(a[5], "f"); + } + + #[test] + fn test_split_off() { + // Split within the key range + let mut a = VecMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(3); + + assert_eq!(a.len(), 2); + assert_eq!(b.len(), 2); + + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + + assert_eq!(b[3], "c"); + assert_eq!(b[4], "d"); + + // Split at 0 + a.clear(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 4); + assert_eq!(b[1], "a"); + assert_eq!(b[2], "b"); + assert_eq!(b[3], "c"); + assert_eq!(b[4], "d"); + + // Split behind max_key + a.clear(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(5); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + assert_eq!(a[3], "c"); + assert_eq!(a[4], "d"); + } + + #[test] + fn test_show() { + let mut map = VecMap::new(); + let empty = VecMap::<i32>::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{:?}", map); + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{:?}", empty), "{}"); + } + + #[test] + fn test_clone() { + let mut a = VecMap::new(); + + a.insert(1, 'x'); + a.insert(4, 'y'); + a.insert(6, 'z'); + + assert_eq!(a.clone().iter().collect::<Vec<_>>(), [(1, &'x'), (4, &'y'), (6, &'z')]); + } + + #[test] + fn test_eq() { + let mut a = VecMap::new(); + let mut b = VecMap::new(); + + assert!(a == b); + assert!(a.insert(0, 5).is_none()); + assert!(a != b); + assert!(b.insert(0, 4).is_none()); + assert!(a != b); + assert!(a.insert(5, 19).is_none()); + assert!(a != b); + assert!(!b.insert(0, 5).is_none()); + assert!(a != b); + assert!(b.insert(5, 19).is_none()); + assert!(a == b); + + a = VecMap::new(); + b = VecMap::with_capacity(1); + assert!(a == b); + } + + #[test] + fn test_lt() { + let mut a = VecMap::new(); + let mut b = VecMap::new(); + + assert!(!(a < b) && !(b < a)); + assert!(b.insert(2, 5).is_none()); + assert!(a < b); + assert!(a.insert(2, 7).is_none()); + assert!(!(a < b) && b < a); + assert!(b.insert(1, 0).is_none()); + assert!(b < a); + assert!(a.insert(0, 6).is_none()); + assert!(a < b); + assert!(a.insert(6, 2).is_none()); + assert!(a < b && !(b < a)); + } + + #[test] + fn test_ord() { + let mut a = VecMap::new(); + let mut b = VecMap::new(); + + assert!(a <= b && a >= b); + assert!(a.insert(1, 1).is_none()); + assert!(a > b && a >= b); + assert!(b < a && b <= a); + assert!(b.insert(2, 2).is_none()); + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + #[test] + fn test_hash() { + fn hash<T: Hash>(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + let mut x = VecMap::new(); + let mut y = VecMap::new(); + + assert!(hash(&x) == hash(&y)); + x.insert(1, 'a'); + x.insert(2, 'b'); + x.insert(3, 'c'); + + y.insert(3, 'c'); + y.insert(2, 'b'); + y.insert(1, 'a'); + + assert!(hash(&x) == hash(&y)); + + x.insert(1000, 'd'); + x.remove(1000); + + assert!(hash(&x) == hash(&y)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]; + + let map: VecMap<_> = xs.iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(k), Some(&v)); + } + } + + #[test] + fn test_index() { + let mut map = VecMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[3], 4); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = VecMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + map[4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: VecMap<_> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + + assert_eq!(map.get(1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + *v *= 10; + } + } + + assert_eq!(map.get(2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + + assert_eq!(map.get(3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + + assert_eq!(map.get(10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_extend_ref() { + let mut a = VecMap::new(); + a.insert(1, "one"); + let mut b = VecMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde() { + use serde::{Serialize, Deserialize}; + fn impls_serde_traits<'de, S: Serialize + Deserialize<'de>>() {} + + impls_serde_traits::<VecMap<u32>>(); + } + + #[test] + fn test_retain() { + let mut map = VecMap::new(); + map.insert(1, "one"); + map.insert(2, "two"); + map.insert(3, "three"); + map.retain(|k, v| match k { + 1 => false, + 2 => { + *v = "two changed"; + true + }, + 3 => false, + _ => panic!(), + }); + + assert_eq!(map.len(), 1); + assert_eq!(map.get(1), None); + assert_eq!(map[2], "two changed"); + assert_eq!(map.get(3), None); + } +} diff --git a/wait-timeout/.cargo-checksum.json b/wait-timeout/.cargo-checksum.json new file mode 100644 index 000000000..6e6e1a3f4 --- /dev/null +++ b/wait-timeout/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"} \ No newline at end of file diff --git a/wait-timeout/Cargo.toml b/wait-timeout/Cargo.toml new file mode 100644 index 000000000..e62830113 --- /dev/null +++ b/wait-timeout/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "wait-timeout" +version = "0.2.0" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +description = "A crate to wait on a child process with a timeout specified across Unix and\nWindows platforms.\n" +homepage = "https://github.com/alexcrichton/wait-timeout" +documentation = "https://docs.rs/wait-timeout" +readme = "README.md" +categories = ["os"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/wait-timeout" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[badges.appveyor] +repository = "alexcrichton/wait-timeout" + +[badges.travis-ci] +repository = "alexcrichton/wait-timeout" diff --git a/wait-timeout/LICENSE-APACHE b/wait-timeout/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/wait-timeout/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/wait-timeout/LICENSE-MIT b/wait-timeout/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/wait-timeout/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/wait-timeout/README.md b/wait-timeout/README.md new file mode 100644 index 000000000..1c10e6f87 --- /dev/null +++ b/wait-timeout/README.md @@ -0,0 +1,14 @@ +# wait-timeout + +[![Build Status](https://travis-ci.org/alexcrichton/wait-timeout.svg?branch=master)](https://travis-ci.org/alexcrichton/wait-timeout) +[![Build status](https://ci.appveyor.com/api/projects/status/3t5mh1c8i4lnolma?svg=true)](https://ci.appveyor.com/project/alexcrichton/wait-timeout) + +[Documentation](https://docs.rs/wait-timeout) + +Rust crate for waiting on a `Child` process with a timeout specified. + +```toml +# Cargo.toml +[dependencies] +wait-timeout = "0.1.5" +``` diff --git a/wait-timeout/appveyor.yml b/wait-timeout/appveyor.yml new file mode 100644 index 000000000..4a6104291 --- /dev/null +++ b/wait-timeout/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose --target %TARGET% diff --git a/wait-timeout/src/bin/exit.rs b/wait-timeout/src/bin/exit.rs new file mode 100644 index 000000000..f33c49f34 --- /dev/null +++ b/wait-timeout/src/bin/exit.rs @@ -0,0 +1,4 @@ +fn main() { + let code = std::env::args().nth(1).unwrap().parse().unwrap(); + std::process::exit(code); +} diff --git a/wait-timeout/src/bin/reader.rs b/wait-timeout/src/bin/reader.rs new file mode 100644 index 000000000..94b017e64 --- /dev/null +++ b/wait-timeout/src/bin/reader.rs @@ -0,0 +1,7 @@ +use std::io::{Read, stdin}; + +#[allow(unused_must_use)] +fn main() { + let mut buffer: [u8; 32] = Default::default(); + stdin().read(&mut buffer); +} diff --git a/wait-timeout/src/bin/sleep.rs b/wait-timeout/src/bin/sleep.rs new file mode 100644 index 000000000..48dabdc02 --- /dev/null +++ b/wait-timeout/src/bin/sleep.rs @@ -0,0 +1,4 @@ +fn main() { + let amt = std::env::args().nth(1).unwrap().parse().unwrap(); + std::thread::sleep(std::time::Duration::from_millis(amt)); +} diff --git a/wait-timeout/src/lib.rs b/wait-timeout/src/lib.rs new file mode 100644 index 000000000..7c19bf30a --- /dev/null +++ b/wait-timeout/src/lib.rs @@ -0,0 +1,68 @@ +//! A crate to wait on a child process with a particular timeout. +//! +//! This crate is an implementation for Unix and Windows of the ability to wait +//! on a child process with a timeout specified. On Windows the implementation +//! is fairly trivial as it's just a call to `WaitForSingleObject` with a +//! timeout argument, but on Unix the implementation is much more involved. The +//! current implementation registers a `SIGCHLD` handler and initializes some +//! global state. This handler also works within multi-threaded environments. +//! If your application is otherwise handling `SIGCHLD` then bugs may arise. +//! +//! # Example +//! +//! ```no_run +//! use std::process::Command; +//! use wait_timeout::ChildExt; +//! use std::time::Duration; +//! +//! let mut child = Command::new("foo").spawn().unwrap(); +//! +//! let one_sec = Duration::from_secs(1); +//! let status_code = match child.wait_timeout(one_sec).unwrap() { +//! Some(status) => status.code(), +//! None => { +//! // child hasn't exited yet +//! child.kill().unwrap(); +//! child.wait().unwrap().code() +//! } +//! }; +//! ``` + +#![deny(missing_docs, warnings)] +#![doc(html_root_url = "https://docs.rs/wait-timeout/0.1")] + +#[cfg(unix)] +extern crate libc; + +use std::io; +use std::process::{Child, ExitStatus}; +use std::time::Duration; + +#[cfg(unix)] #[path = "unix.rs"] +mod imp; +#[cfg(windows)] #[path = "windows.rs"] +mod imp; + +/// Extension methods for the standard `std::process::Child` type. +pub trait ChildExt { + /// Deprecated, use `wait_timeout` instead. + #[doc(hidden)] + fn wait_timeout_ms(&mut self, ms: u32) -> io::Result<Option<ExitStatus>> { + self.wait_timeout(Duration::from_millis(ms as u64)) + } + + /// Wait for this child to exit, timing out after the duration `dur` has + /// elapsed. + /// + /// If `Ok(None)` is returned then the timeout period elapsed without the + /// child exiting, and if `Ok(Some(..))` is returned then the child exited + /// with the specified exit code. + fn wait_timeout(&mut self, dur: Duration) -> io::Result<Option<ExitStatus>>; +} + +impl ChildExt for Child { + fn wait_timeout(&mut self, dur: Duration) -> io::Result<Option<ExitStatus>> { + drop(self.stdin.take()); + imp::wait_timeout(self, dur) + } +} diff --git a/wait-timeout/src/unix.rs b/wait-timeout/src/unix.rs new file mode 100644 index 000000000..535855378 --- /dev/null +++ b/wait-timeout/src/unix.rs @@ -0,0 +1,305 @@ +//! Unix implementation of waiting for children with timeouts +//! +//! On unix, wait() and its friends have no timeout parameters, so there is +//! no way to time out a thread in wait(). From some googling and some +//! thinking, it appears that there are a few ways to handle timeouts in +//! wait(), but the only real reasonable one for a multi-threaded program is +//! to listen for SIGCHLD. +//! +//! With this in mind, the waiting mechanism with a timeout only uses +//! waitpid() with WNOHANG, but otherwise all the necessary blocking is done by +//! waiting for a SIGCHLD to arrive (and that blocking has a timeout). Note, +//! however, that waitpid() is still used to actually reap the child. +//! +//! Signal handling is super tricky in general, and this is no exception. Due +//! to the async nature of SIGCHLD, we use the self-pipe trick to transmit +//! data out of the signal handler to the rest of the application. + +#![allow(bad_style)] + +use std::cmp; +use std::collections::HashMap; +use std::io::{self, Write, Read}; +use std::os::unix::net::UnixStream; +use std::mem; +use std::os::unix::prelude::*; +use std::process::{Child, ExitStatus}; +use std::sync::{Once, ONCE_INIT, Mutex}; +use std::time::{Duration, Instant}; + +use libc::{self, c_int}; + +static INIT: Once = ONCE_INIT; +static mut STATE: *mut State = 0 as *mut _; + +struct State { + prev: libc::sigaction, + write: UnixStream, + read: UnixStream, + map: Mutex<StateMap>, +} + +type StateMap = HashMap<*mut Child, (UnixStream, Option<ExitStatus>)>; + +pub fn wait_timeout(child: &mut Child, dur: Duration) + -> io::Result<Option<ExitStatus>> { + INIT.call_once(State::init); + unsafe { + (*STATE).wait_timeout(child, dur) + } +} + +// Do $value as type_of($target) +macro_rules! _as { + ($value:expr, $target:expr) => ( + { + let mut x = $target; + x = $value as _; + x + } + ) +} + +impl State { + #[allow(unused_assignments)] + fn init() { + unsafe { + // Create our "self pipe" and then set both ends to nonblocking + // mode. + let (read, write) = UnixStream::pair().unwrap(); + read.set_nonblocking(true).unwrap(); + write.set_nonblocking(true).unwrap(); + + let mut state = Box::new(State { + prev: mem::zeroed(), + write: write, + read: read, + map: Mutex::new(HashMap::new()), + }); + + // Register our sigchld handler + let mut new: libc::sigaction = mem::zeroed(); + new.sa_sigaction = sigchld_handler as usize; + + // FIXME: remove this workaround when the PR to libc get merged and released + // + // This is a workaround for the type mismatch in the definition of SA_* + // constants for android. See https://github.com/rust-lang/libc/pull/511 + // + let sa_flags = new.sa_flags; + new.sa_flags = _as!(libc::SA_NOCLDSTOP, sa_flags) | + _as!(libc::SA_RESTART, sa_flags) | + _as!(libc::SA_SIGINFO, sa_flags); + + assert_eq!(libc::sigaction(libc::SIGCHLD, &new, &mut state.prev), 0); + + STATE = mem::transmute(state); + } + } + + fn wait_timeout(&self, child: &mut Child, dur: Duration) + -> io::Result<Option<ExitStatus>> { + // First up, prep our notification pipe which will tell us when our + // child has been reaped (other threads may signal this pipe). + let (read, write) = UnixStream::pair()?; + read.set_nonblocking(true)?; + write.set_nonblocking(true)?; + + // Next, take a lock on the map of children currently waiting. Right + // after this, **before** we add ourselves to the map, we check to see + // if our child has actually already exited via a `try_wait`. If the + // child has exited then we return immediately as we'll never otherwise + // receive a SIGCHLD notification. + // + // If the wait reports the child is still running, however, we add + // ourselves to the map and then block in `select` waiting for something + // to happen. + let mut map = self.map.lock().unwrap(); + if let Some(status) = child.try_wait()? { + return Ok(Some(status)) + } + assert!(map.insert(child, (write, None)).is_none()); + drop(map); + + // Make sure that no matter what when we exit our pointer is removed + // from the map. + struct Remove<'a> { + state: &'a State, + child: &'a mut Child, + } + impl<'a> Drop for Remove<'a> { + fn drop(&mut self) { + let mut map = self.state.map.lock().unwrap(); + drop(map.remove(&(self.child as *mut Child))); + } + } + let remove = Remove { state: self, child }; + + + // Alright, we're guaranteed that we'll eventually get a SIGCHLD due + // to our `try_wait` failing, and we're also guaranteed that we'll + // get notified about this because we're in the map. Next up wait + // for an event. + // + // Note that this happens in a loop for two reasons; we could + // receive EINTR or we could pick up a SIGCHLD for other threads but not + // actually be ready oureslves. + let start = Instant::now(); + let mut fds = [ + libc::pollfd { + fd: self.read.as_raw_fd(), + events: libc::POLLIN, + + revents: 0, + }, + libc::pollfd { + fd: read.as_raw_fd(), + events: libc::POLLIN, + revents: 0, + }, + ]; + loop { + let elapsed = start.elapsed(); + if elapsed >= dur { + break + } + let timeout = dur - elapsed; + let timeout = timeout.as_secs().checked_mul(1_000) + .and_then(|amt| { + amt.checked_add(timeout.subsec_nanos() as u64 / 1_000_000) + }) + .unwrap_or(u64::max_value()); + let timeout = cmp::min(<c_int>::max_value() as u64, timeout) as c_int; + let r = unsafe { + libc::poll(fds.as_mut_ptr(), 2, timeout) + }; + let timeout = match r { + 0 => true, + n if n > 0 => false, + n => { + let err = io::Error::last_os_error(); + if err.kind() == io::ErrorKind::Interrupted { + continue + } else { + panic!("error in select = {}: {}", n, err) + } + } + }; + + // Now that something has happened, we need to process what actually + // happened. There's are three reasons we could have woken up: + // + // 1. The file descriptor in our SIGCHLD handler was written to. + // This means that a SIGCHLD was received and we need to poll the + // entire list of waiting processes to figure out which ones + // actually exited. + // 2. Our file descriptor was written to. This means that another + // thread reaped our child and listed the exit status in the + // local map. + // 3. We timed out. This means we need to remove ourselves from the + // map and simply carry on. + // + // In the case that a SIGCHLD signal was received, we do that + // processing and keep going. If our fd was written to or a timeout + // was received then we break out of the loop and return from this + // call. + let mut map = self.map.lock().unwrap(); + if drain(&self.read) { + self.process_sigchlds(&mut map); + } + + if drain(&read) || timeout { + break + } + } + + let mut map = self.map.lock().unwrap(); + let (_write, ret) = map.remove(&(remove.child as *mut Child)).unwrap(); + drop(map); + Ok(ret) + } + + fn process_sigchlds(&self, map: &mut StateMap) { + for (&k, &mut (ref write, ref mut status)) in map { + // Already reaped, nothing to do here + if status.is_some() { + continue + } + + *status = unsafe { (*k).try_wait().unwrap() }; + if status.is_some() { + notify(write); + } + } + } +} + +fn drain(mut file: &UnixStream) -> bool { + let mut ret = false; + let mut buf = [0u8; 16]; + loop { + match file.read(&mut buf) { + Ok(0) => return true, // EOF == something happened + Ok(..) => ret = true, // data read, but keep draining + Err(e) => { + if e.kind() == io::ErrorKind::WouldBlock { + return ret + } else { + panic!("bad read: {}", e) + } + } + } + } +} + +fn notify(mut file: &UnixStream) { + match file.write(&[1]) { + Ok(..) => {} + Err(e) => { + if e.kind() != io::ErrorKind::WouldBlock { + panic!("bad error on write fd: {}", e) + } + } + } +} + +// Signal handler for SIGCHLD signals, must be async-signal-safe! +// +// This function will write to the writing half of the "self pipe" to wake +// up the helper thread if it's waiting. Note that this write must be +// nonblocking because if it blocks and the reader is the thread we +// interrupted, then we'll deadlock. +// +// When writing, if the write returns EWOULDBLOCK then we choose to ignore +// it. At that point we're guaranteed that there's something in the pipe +// which will wake up the other end at some point, so we just allow this +// signal to be coalesced with the pending signals on the pipe. +#[allow(unused_assignments)] +extern fn sigchld_handler(signum: c_int, + info: *mut libc::siginfo_t, + ptr: *mut libc::c_void) { + type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void); + type FnHandler = extern fn(c_int); + + unsafe { + let state = &*STATE; + notify(&state.write); + + let fnptr = state.prev.sa_sigaction; + if fnptr == 0 { + return + } + // FIXME: remove this workaround when the PR to libc get merged and released + // + // This is a workaround for the type mismatch in the definition of SA_* + // constants for android. See https://github.com/rust-lang/libc/pull/511 + // + if state.prev.sa_flags & _as!(libc::SA_SIGINFO, state.prev.sa_flags) == 0 { + let action = mem::transmute::<usize, FnHandler>(fnptr); + action(signum) + } else { + let action = mem::transmute::<usize, FnSigaction>(fnptr); + action(signum, info, ptr) + } + } +} diff --git a/wait-timeout/src/windows.rs b/wait-timeout/src/windows.rs new file mode 100644 index 000000000..a3aa10468 --- /dev/null +++ b/wait-timeout/src/windows.rs @@ -0,0 +1,34 @@ +use std::io; +use std::os::windows::prelude::*; +use std::process::{Child, ExitStatus}; +use std::time::Duration; + +type DWORD = u32; +type HANDLE = *mut u8; + +const WAIT_OBJECT_0: DWORD = 0x00000000; +const WAIT_TIMEOUT: DWORD = 258; + +extern "system" { + fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; +} + +pub fn wait_timeout(child: &mut Child, dur: Duration) + -> io::Result<Option<ExitStatus>> { + let ms = dur.as_secs().checked_mul(1000).and_then(|amt| { + amt.checked_add((dur.subsec_nanos() / 1_000_000) as u64) + }).expect("failed to convert duration to milliseconds"); + let ms = if ms > (DWORD::max_value() as u64) { + DWORD::max_value() + } else { + ms as DWORD + }; + unsafe { + match WaitForSingleObject(child.as_raw_handle() as *mut _, ms) { + WAIT_OBJECT_0 => {} + WAIT_TIMEOUT => return Ok(None), + _ => return Err(io::Error::last_os_error()), + } + } + child.try_wait() +} diff --git a/wait-timeout/tests/smoke.rs b/wait-timeout/tests/smoke.rs new file mode 100644 index 000000000..233259b71 --- /dev/null +++ b/wait-timeout/tests/smoke.rs @@ -0,0 +1,103 @@ +extern crate wait_timeout; + +use std::env; +use std::process::{Command, Child, Stdio}; +use std::time::{Duration, Instant}; + +use wait_timeout::ChildExt; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn sleeper(ms: u32) -> Child { + let mut me = env::current_exe().unwrap(); + me.pop(); + if me.ends_with("deps") { + me.pop(); + } + me.push("sleep"); + t!(Command::new(me).arg(ms.to_string()).spawn()) +} + +fn exit(code: u32) -> Child { + let mut me = env::current_exe().unwrap(); + me.pop(); + if me.ends_with("deps") { + me.pop(); + } + me.push("exit"); + t!(Command::new(me).arg(code.to_string()).spawn()) +} + +fn reader() -> Child { + let mut me = env::current_exe().unwrap(); + me.pop(); + if me.ends_with("deps") { + me.pop(); + } + me.push("reader"); + t!(Command::new(me).stdin(Stdio::piped()).spawn()) +} + +#[test] +fn smoke_insta_timeout() { + let mut child = sleeper(1_000); + assert_eq!(t!(child.wait_timeout_ms(0)), None); + + t!(child.kill()); + let status = t!(child.wait()); + assert!(!status.success()); +} + +#[test] +fn smoke_success() { + let start = Instant::now(); + let mut child = sleeper(0); + let status = t!(child.wait_timeout_ms(1_000)).expect("should have succeeded"); + assert!(status.success()); + + assert!(start.elapsed() < Duration::from_millis(500)); +} + +#[test] +fn smoke_timeout() { + let mut child = sleeper(1_000_000); + let start = Instant::now(); + assert_eq!(t!(child.wait_timeout_ms(100)), None); + assert!(start.elapsed() > Duration::from_millis(80)); + + t!(child.kill()); + let status = t!(child.wait()); + assert!(!status.success()); +} + +#[test] +fn smoke_reader() { + let mut child = reader(); + let dur = Duration::from_millis(100); + let status = t!(child.wait_timeout(dur)).unwrap(); + assert!(status.success()); +} + +#[test] +fn exit_codes() { + let mut child = exit(0); + let status = t!(child.wait_timeout_ms(1_000)).unwrap(); + assert_eq!(status.code(), Some(0)); + + let mut child = exit(1); + let status = t!(child.wait_timeout_ms(1_000)).unwrap(); + assert_eq!(status.code(), Some(1)); + + // check STILL_ACTIVE on windows, on unix this ends up just getting + // truncated so don't bother with it. + if cfg!(windows) { + let mut child = exit(259); + let status = t!(child.wait_timeout_ms(1_000)).unwrap(); + assert_eq!(status.code(), Some(259)); + } +} diff --git a/walkdir/.cargo-checksum.json b/walkdir/.cargo-checksum.json new file mode 100644 index 000000000..38a99da5e --- /dev/null +++ b/walkdir/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"} \ No newline at end of file diff --git a/walkdir/COPYING b/walkdir/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/walkdir/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/walkdir/Cargo.toml b/walkdir/Cargo.toml new file mode 100644 index 000000000..4810eac3f --- /dev/null +++ b/walkdir/Cargo.toml @@ -0,0 +1,53 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "walkdir" +version = "2.2.7" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +exclude = ["/ci/*", "/.travis.yml", "/Makefile", "/appveyor.yml", "/ctags.rust", "/session.vim"] +description = "Recursively walk a directory." +homepage = "https://github.com/BurntSushi/walkdir" +documentation = "https://docs.rs/walkdir/" +readme = "README.md" +keywords = ["directory", "recursive", "walk", "iterator"] +categories = ["filesystem"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/walkdir" +[dependencies.same-file] +version = "1.0.1" +[dev-dependencies.docopt] +version = "1.0.1" + +[dev-dependencies.quickcheck] +version = "0.7" +default-features = false + +[dev-dependencies.rand] +version = "0.5" + +[dev-dependencies.serde] +version = "1" + +[dev-dependencies.serde_derive] +version = "1" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["std", "winnt"] + +[target."cfg(windows)".dependencies.winapi-util] +version = "0.1.1" +[badges.appveyor] +repository = "BurntSushi/walkdir" + +[badges.travis-ci] +repository = "BurntSushi/walkdir" diff --git a/walkdir/LICENSE-MIT b/walkdir/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/walkdir/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/walkdir/README.md b/walkdir/README.md new file mode 100644 index 000000000..e15415fad --- /dev/null +++ b/walkdir/README.md @@ -0,0 +1,140 @@ +walkdir +======= +A cross platform Rust library for efficiently walking a directory recursively. +Comes with support for following symbolic links, controlling the number of +open file descriptors and efficient mechanisms for pruning the entries in the +directory tree. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/walkdir.svg)](https://travis-ci.org/BurntSushi/walkdir) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/walkdir?svg=true)](https://ci.appveyor.com/project/BurntSushi/walkdir) +[![](http://meritbadge.herokuapp.com/walkdir)](https://crates.io/crates/walkdir) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +[docs.rs/walkdir](https://docs.rs/walkdir/) + +### Usage + +To use this crate, add `walkdir` as a dependency to your project's +`Cargo.toml`: + +```toml +[dependencies] +walkdir = "2" +``` + +### Example + +The following code recursively iterates over the directory given and prints +the path for each entry: + +```rust,no_run +use walkdir::WalkDir; + +for entry in WalkDir::new("foo") { + let entry = entry.unwrap(); + println!("{}", entry.path().display()); +} +``` + +Or, if you'd like to iterate over all entries and ignore any errors that may +arise, use `filter_map`. (e.g., This code below will silently skip directories +that the owner of the running process does not have permission to access.) + +```rust,no_run +use walkdir::WalkDir; + +for entry in WalkDir::new("foo").into_iter().filter_map(|e| e.ok()) { + println!("{}", entry.path().display()); +} +``` + +### Example: follow symbolic links + +The same code as above, except `follow_links` is enabled: + +```rust,no_run +use walkdir::WalkDir; + +for entry in WalkDir::new("foo").follow_links(true) { + let entry = entry.unwrap(); + println!("{}", entry.path().display()); +} +``` + +### Example: skip hidden files and directories efficiently on unix + +This uses the `filter_entry` iterator adapter to avoid yielding hidden files +and directories efficiently: + +```rust,no_run +use walkdir::{DirEntry, WalkDir}; + +fn is_hidden(entry: &DirEntry) -> bool { + entry.file_name() + .to_str() + .map(|s| s.starts_with(".")) + .unwrap_or(false) +} + +let walker = WalkDir::new("foo").into_iter(); +for entry in walker.filter_entry(|e| !is_hidden(e)) { + let entry = entry.unwrap(); + println!("{}", entry.path().display()); +} +``` + +### Motivation + +`std::fs` has an unstable `walk_dir` implementation that needed some design +work. I started off on that task, but it quickly became apparent that walking +a directory recursively is quite complex and may not be a good fit for `std` +right away. + +This should at least resolve most or all of the issues reported here (and then +some): + +* https://github.com/rust-lang/rust/issues/27707 +* https://github.com/rust-lang/rust/issues/23715 + +### Performance + +The short story is that performance is comparable with `find` and glibc's +`nftw` on both a warm and cold file cache. In fact, I cannot observe any +performance difference after running `find /`, `walkdir /` and `nftw /` on my +local file system (SSD, ~3 million entries). More precisely, I am reasonably +confident that this crate makes as few system calls and close to as few +allocations as possible. + +I haven't recorded any benchmarks, but here are some things you can try with a +local checkout of `walkdir`: + +```sh +# The directory you want to recursively walk: +DIR=$HOME + +# If you want to observe perf on a cold file cache, run this before *each* +# command: +sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches' + +# To warm the caches +find $DIR + +# Test speed of `find` on warm cache: +time find $DIR + +# Compile and test speed of `walkdir` crate: +cargo build --release --example walkdir +time ./target/release/examples/walkdir $DIR + +# Compile and test speed of glibc's `nftw`: +gcc -O3 -o nftw ./compare/nftw.c +time ./nftw $DIR + +# For shits and giggles, test speed of Python's (2 or 3) os.walk: +time python ./compare/walk.py $DIR +``` + +On my system, the performance of `walkdir`, `find` and `nftw` is comparable. diff --git a/walkdir/UNLICENSE b/walkdir/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/walkdir/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/walkdir/compare/nftw.c b/walkdir/compare/nftw.c new file mode 100644 index 000000000..7d36e2fdf --- /dev/null +++ b/walkdir/compare/nftw.c @@ -0,0 +1,25 @@ +#define _XOPEN_SOURCE 500 +#include <ftw.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +static int +display_info(const char *fpath, const struct stat *sb, + int tflag, struct FTW *ftwbuf) +{ + printf("%s\n", fpath); + return 0; +} + +int +main(int argc, char *argv[]) +{ + int flags = FTW_PHYS; + if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags) == -1) { + perror("nftw"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); +} diff --git a/walkdir/compare/walk.py b/walkdir/compare/walk.py new file mode 100644 index 000000000..303d323e2 --- /dev/null +++ b/walkdir/compare/walk.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import, division, print_function + +import os +import sys + +for dirpath, dirnames, filenames in os.walk(sys.argv[1]): + for n in dirnames: + print(os.path.join(dirpath, n)) + for n in filenames: + print(os.path.join(dirpath, n)) diff --git a/walkdir/examples/walkdir.rs b/walkdir/examples/walkdir.rs new file mode 100644 index 000000000..658b31767 --- /dev/null +++ b/walkdir/examples/walkdir.rs @@ -0,0 +1,103 @@ +extern crate docopt; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate walkdir; + +use std::io::{self, Write}; + +use docopt::Docopt; +use walkdir::WalkDir; + +const USAGE: &'static str = " +Usage: + walkdir [options] [<dir> ...] + +Options: + -h, --help + -L, --follow-links Follow symlinks. + --min-depth NUM Minimum depth. + --max-depth NUM Maximum depth. + -n, --fd-max NUM Maximum open file descriptors. [default: 32] + --tree Show output as a tree. + --sort Sort the output. + -q, --ignore-errors Ignore errors. + -d, --depth Show directory's contents before the directory itself. + -x, --same-file-system Stay on the same file system. +"; + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +struct Args { + arg_dir: Option<Vec<String>>, + flag_follow_links: bool, + flag_min_depth: Option<usize>, + flag_max_depth: Option<usize>, + flag_fd_max: usize, + flag_tree: bool, + flag_ignore_errors: bool, + flag_sort: bool, + flag_depth: bool, + flag_same_file_system: bool, +} + +macro_rules! wout { ($($tt:tt)*) => { {writeln!($($tt)*)}.unwrap() } } + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + let mind = args.flag_min_depth.unwrap_or(0); + let maxd = args.flag_max_depth.unwrap_or(::std::usize::MAX); + for dir in args.arg_dir.unwrap_or(vec![".".to_string()]) { + let mut walkdir = WalkDir::new(dir) + .max_open(args.flag_fd_max) + .follow_links(args.flag_follow_links) + .min_depth(mind) + .max_depth(maxd) + .same_file_system(args.flag_same_file_system); + if args.flag_sort { + walkdir = walkdir.sort_by(|a,b| a.file_name().cmp(b.file_name())); + } + if args.flag_depth { + walkdir = walkdir.contents_first(true) + } + let it = walkdir.into_iter(); + let mut out = io::BufWriter::new(io::stdout()); + let mut eout = io::stderr(); + if args.flag_tree { + for dent in it { + match dent { + Err(err) => { + out.flush().unwrap(); + wout!(eout, "ERROR: {}", err); + } + Ok(dent) => { + let name = dent.file_name().to_string_lossy(); + wout!(out, "{}{}", indent(dent.depth()), name); + } + } + } + } else if args.flag_ignore_errors { + for dent in it.filter_map(|e| e.ok()) { + wout!(out, "{}", dent.path().display()); + } + } else { + for dent in it { + match dent { + Err(err) => { + out.flush().unwrap(); + wout!(eout, "ERROR: {}", err); + } + Ok(dent) => { + wout!(out, "{}", dent.path().display()); + } + } + } + } + } +} + +fn indent(depth: usize) -> String { + ::std::iter::repeat(' ').take(2 * depth).collect() +} diff --git a/walkdir/src/lib.rs b/walkdir/src/lib.rs new file mode 100644 index 000000000..1c38f73e6 --- /dev/null +++ b/walkdir/src/lib.rs @@ -0,0 +1,1718 @@ +/*! +Crate `walkdir` provides an efficient and cross platform implementation +of recursive directory traversal. Several options are exposed to control +iteration, such as whether to follow symbolic links (default off), limit the +maximum number of simultaneous open file descriptors and the ability to +efficiently skip descending into directories. + +To use this crate, add `walkdir` as a dependency to your project's +`Cargo.toml`: + +```toml +[dependencies] +walkdir = "2" +``` + +# From the top + +The [`WalkDir`] type builds iterators. The [`DirEntry`] type describes values +yielded by the iterator. Finally, the [`Error`] type is a small wrapper around +[`std::io::Error`] with additional information, such as if a loop was detected +while following symbolic links (not enabled by default). + +[`WalkDir`]: struct.WalkDir.html +[`DirEntry`]: struct.DirEntry.html +[`Error`]: struct.Error.html +[`std::io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html + +# Example + +The following code recursively iterates over the directory given and prints +the path for each entry: + +```no_run +use walkdir::WalkDir; +# use walkdir::Error; + +# fn try_main() -> Result<(), Error> { +for entry in WalkDir::new("foo") { + println!("{}", entry?.path().display()); +} +# Ok(()) +# } +``` + +Or, if you'd like to iterate over all entries and ignore any errors that +may arise, use [`filter_map`]. (e.g., This code below will silently skip +directories that the owner of the running process does not have permission to +access.) + +```no_run +use walkdir::WalkDir; + +for entry in WalkDir::new("foo").into_iter().filter_map(|e| e.ok()) { + println!("{}", entry.path().display()); +} +``` + +[`filter_map`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.filter_map + +# Example: follow symbolic links + +The same code as above, except [`follow_links`] is enabled: + +```no_run +use walkdir::WalkDir; +# use walkdir::Error; + +# fn try_main() -> Result<(), Error> { +for entry in WalkDir::new("foo").follow_links(true) { + println!("{}", entry?.path().display()); +} +# Ok(()) +# } +``` + +[`follow_links`]: struct.WalkDir.html#method.follow_links + +# Example: skip hidden files and directories on unix + +This uses the [`filter_entry`] iterator adapter to avoid yielding hidden files +and directories efficiently (i.e. without recursing into hidden directories): + +```no_run +use walkdir::{DirEntry, WalkDir}; +# use walkdir::Error; + +fn is_hidden(entry: &DirEntry) -> bool { + entry.file_name() + .to_str() + .map(|s| s.starts_with(".")) + .unwrap_or(false) +} + +# fn try_main() -> Result<(), Error> { +let walker = WalkDir::new("foo").into_iter(); +for entry in walker.filter_entry(|e| !is_hidden(e)) { + println!("{}", entry?.path().display()); +} +# Ok(()) +# } +``` + +[`filter_entry`]: struct.IntoIter.html#method.filter_entry +*/ + +#![deny(missing_docs)] + +#[cfg(test)] +extern crate quickcheck; +#[cfg(test)] +extern crate rand; +extern crate same_file; +#[cfg(windows)] +extern crate winapi; +#[cfg(windows)] +extern crate winapi_util; + +use std::cmp::{Ordering, min}; +use std::error; +use std::fmt; +use std::fs::{self, FileType, ReadDir}; +use std::io; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use std::result; +use std::vec; + +use same_file::Handle; + +#[cfg(unix)] +pub use unix::DirEntryExt; + +#[cfg(test)] +mod tests; +#[cfg(unix)] +mod unix; + +/// Like try, but for iterators that return [`Option<Result<_, _>>`]. +/// +/// [`Option<Result<_, _>>`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html +macro_rules! itry { + ($e:expr) => { + match $e { + Ok(v) => v, + Err(err) => return Some(Err(From::from(err))), + } + } +} + +/// A result type for walkdir operations. +/// +/// Note that this result type embeds the error type in this crate. This +/// is only useful if you care about the additional information provided by +/// the error (such as the path associated with the error or whether a loop +/// was dectected). If you want things to Just Work, then you can use +/// [`io::Result`] instead since the error type in this package will +/// automatically convert to an [`io::Result`] when using the [`try!`] macro. +/// +/// [`io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html +/// [`try!`]: https://doc.rust-lang.org/stable/std/macro.try.html +pub type Result<T> = ::std::result::Result<T, Error>; + +/// A builder to create an iterator for recursively walking a directory. +/// +/// Results are returned in depth first fashion, with directories yielded +/// before their contents. If [`contents_first`] is true, contents are yielded +/// before their directories. The order is unspecified but if [`sort_by`] is +/// given, directory entries are sorted according to this function. Directory +/// entries `.` and `..` are always omitted. +/// +/// If an error occurs at any point during iteration, then it is returned in +/// place of its corresponding directory entry and iteration continues as +/// normal. If an error occurs while opening a directory for reading, then it +/// is not descended into (but the error is still yielded by the iterator). +/// Iteration may be stopped at any time. When the iterator is destroyed, all +/// resources associated with it are freed. +/// +/// [`contents_first`]: struct.WalkDir.html#method.contents_first +/// [`sort_by`]: struct.WalkDir.html#method.sort_by +/// +/// # Usage +/// +/// This type implements [`IntoIterator`] so that it may be used as the subject +/// of a `for` loop. You may need to call [`into_iter`] explicitly if you want +/// to use iterator adapters such as [`filter_entry`]. +/// +/// Idiomatic use of this type should use method chaining to set desired +/// options. For example, this only shows entries with a depth of `1`, `2` or +/// `3` (relative to `foo`): +/// +/// ```no_run +/// use walkdir::WalkDir; +/// # use walkdir::Error; +/// +/// # fn try_main() -> Result<(), Error> { +/// for entry in WalkDir::new("foo").min_depth(1).max_depth(3) { +/// println!("{}", entry?.path().display()); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// [`IntoIterator`]: https://doc.rust-lang.org/stable/std/iter/trait.IntoIterator.html +/// [`into_iter`]: https://doc.rust-lang.org/nightly/core/iter/trait.IntoIterator.html#tymethod.into_iter +/// [`filter_entry`]: struct.IntoIter.html#method.filter_entry +/// +/// Note that the iterator by default includes the top-most directory. Since +/// this is the only directory yielded with depth `0`, it is easy to ignore it +/// with the [`min_depth`] setting: +/// +/// ```no_run +/// use walkdir::WalkDir; +/// # use walkdir::Error; +/// +/// # fn try_main() -> Result<(), Error> { +/// for entry in WalkDir::new("foo").min_depth(1) { +/// println!("{}", entry?.path().display()); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// [`min_depth`]: struct.WalkDir.html#method.min_depth +/// +/// This will only return descendents of the `foo` directory and not `foo` +/// itself. +/// +/// # Loops +/// +/// This iterator (like most/all recursive directory iterators) assumes that +/// no loops can be made with *hard* links on your file system. In particular, +/// this would require creating a hard link to a directory such that it creates +/// a loop. On most platforms, this operation is illegal. +/// +/// Note that when following symbolic/soft links, loops are detected and an +/// error is reported. +#[derive(Debug)] +pub struct WalkDir { + opts: WalkDirOptions, + root: PathBuf, +} + +struct WalkDirOptions { + follow_links: bool, + max_open: usize, + min_depth: usize, + max_depth: usize, + sorter: Option<Box< + FnMut(&DirEntry,&DirEntry) -> Ordering + Send + Sync + 'static + >>, + contents_first: bool, + same_file_system: bool, +} + +impl fmt::Debug for WalkDirOptions { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + let sorter_str = if self.sorter.is_some() { + // FnMut isn't `Debug` + "Some(...)" + } else { + "None" + }; + f.debug_struct("WalkDirOptions") + .field("follow_links", &self.follow_links) + .field("max_open", &self.max_open) + .field("min_depth", &self.min_depth) + .field("max_depth", &self.max_depth) + .field("sorter", &sorter_str) + .field("contents_first", &self.contents_first) + .field("same_file_system", &self.same_file_system) + .finish() + } +} + +impl WalkDir { + /// Create a builder for a recursive directory iterator starting at the + /// file path `root`. If `root` is a directory, then it is the first item + /// yielded by the iterator. If `root` is a file, then it is the first + /// and only item yielded by the iterator. If `root` is a symlink, then it + /// is always followed for the purposes of directory traversal. (A root + /// `DirEntry` still obeys its documentation with respect to symlinks and + /// the `follow_links` setting.) + pub fn new<P: AsRef<Path>>(root: P) -> Self { + WalkDir { + opts: WalkDirOptions { + follow_links: false, + max_open: 10, + min_depth: 0, + max_depth: ::std::usize::MAX, + sorter: None, + contents_first: false, + same_file_system: false, + }, + root: root.as_ref().to_path_buf(), + } + } + + /// Set the minimum depth of entries yielded by the iterator. + /// + /// The smallest depth is `0` and always corresponds to the path given + /// to the `new` function on this type. Its direct descendents have depth + /// `1`, and their descendents have depth `2`, and so on. + pub fn min_depth(mut self, depth: usize) -> Self { + self.opts.min_depth = depth; + if self.opts.min_depth > self.opts.max_depth { + self.opts.min_depth = self.opts.max_depth; + } + self + } + + /// Set the maximum depth of entries yield by the iterator. + /// + /// The smallest depth is `0` and always corresponds to the path given + /// to the `new` function on this type. Its direct descendents have depth + /// `1`, and their descendents have depth `2`, and so on. + /// + /// Note that this will not simply filter the entries of the iterator, but + /// it will actually avoid descending into directories when the depth is + /// exceeded. + pub fn max_depth(mut self, depth: usize) -> Self { + self.opts.max_depth = depth; + if self.opts.max_depth < self.opts.min_depth { + self.opts.max_depth = self.opts.min_depth; + } + self + } + + /// Follow symbolic links. By default, this is disabled. + /// + /// When `yes` is `true`, symbolic links are followed as if they were + /// normal directories and files. If a symbolic link is broken or is + /// involved in a loop, an error is yielded. + /// + /// When enabled, the yielded [`DirEntry`] values represent the target of + /// the link while the path corresponds to the link. See the [`DirEntry`] + /// type for more details. + /// + /// [`DirEntry`]: struct.DirEntry.html + pub fn follow_links(mut self, yes: bool) -> Self { + self.opts.follow_links = yes; + self + } + + /// Set the maximum number of simultaneously open file descriptors used + /// by the iterator. + /// + /// `n` must be greater than or equal to `1`. If `n` is `0`, then it is set + /// to `1` automatically. If this is not set, then it defaults to some + /// reasonably low number. + /// + /// This setting has no impact on the results yielded by the iterator + /// (even when `n` is `1`). Instead, this setting represents a trade off + /// between scarce resources (file descriptors) and memory. Namely, when + /// the maximum number of file descriptors is reached and a new directory + /// needs to be opened to continue iteration, then a previous directory + /// handle is closed and has its unyielded entries stored in memory. In + /// practice, this is a satisfying trade off because it scales with respect + /// to the *depth* of your file tree. Therefore, low values (even `1`) are + /// acceptable. + /// + /// Note that this value does not impact the number of system calls made by + /// an exhausted iterator. + /// + /// # Platform behavior + /// + /// On Windows, if `follow_links` is enabled, then this limit is not + /// respected. In particular, the maximum number of file descriptors opened + /// is proportional to the depth of the directory tree traversed. + pub fn max_open(mut self, mut n: usize) -> Self { + if n == 0 { + n = 1; + } + self.opts.max_open = n; + self + } + + /// Set a function for sorting directory entries. + /// + /// If a compare function is set, the resulting iterator will return all + /// paths in sorted order. The compare function will be called to compare + /// entries from the same directory. + /// + /// ```rust,no-run + /// use std::cmp; + /// use std::ffi::OsString; + /// use walkdir::WalkDir; + /// + /// WalkDir::new("foo").sort_by(|a,b| a.file_name().cmp(b.file_name())); + /// ``` + pub fn sort_by<F>(mut self, cmp: F) -> Self + where F: FnMut(&DirEntry, &DirEntry) -> Ordering + Send + Sync + 'static + { + self.opts.sorter = Some(Box::new(cmp)); + self + } + + /// Yield a directory's contents before the directory itself. By default, + /// this is disabled. + /// + /// When `yes` is `false` (as is the default), the directory is yielded + /// before its contents are read. This is useful when, e.g. you want to + /// skip processing of some directories. + /// + /// When `yes` is `true`, the iterator yields the contents of a directory + /// before yielding the directory itself. This is useful when, e.g. you + /// want to recursively delete a directory. + /// + /// # Example + /// + /// Assume the following directory tree: + /// + /// ```text + /// foo/ + /// abc/ + /// qrs + /// tuv + /// def/ + /// ``` + /// + /// With contents_first disabled (the default), the following code visits + /// the directory tree in depth-first order: + /// + /// ```no_run + /// use walkdir::WalkDir; + /// + /// for entry in WalkDir::new("foo") { + /// let entry = entry.unwrap(); + /// println!("{}", entry.path().display()); + /// } + /// + /// // foo + /// // foo/abc + /// // foo/abc/qrs + /// // foo/abc/tuv + /// // foo/def + /// ``` + /// + /// With contents_first enabled: + /// + /// ```no_run + /// use walkdir::WalkDir; + /// + /// for entry in WalkDir::new("foo").contents_first(true) { + /// let entry = entry.unwrap(); + /// println!("{}", entry.path().display()); + /// } + /// + /// // foo/abc/qrs + /// // foo/abc/tuv + /// // foo/abc + /// // foo/def + /// // foo + /// ``` + pub fn contents_first(mut self, yes: bool) -> Self { + self.opts.contents_first = yes; + self + } + + /// Do not cross file system boundaries. + /// + /// When this option is enabled, directory traversal will not descend into + /// directories that are on a different file system from the root path. + /// + /// Currently, this option is only supported on Unix and Windows. If this + /// option is used on an unsupported platform, then directory traversal + /// will immediately return an error and will not yield any entries. + pub fn same_file_system(mut self, yes: bool) -> Self { + self.opts.same_file_system = yes; + self + } +} + +impl IntoIterator for WalkDir { + type Item = Result<DirEntry>; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + opts: self.opts, + start: Some(self.root), + stack_list: vec![], + stack_path: vec![], + oldest_opened: 0, + depth: 0, + deferred_dirs: vec![], + root_device: None, + } + } +} + +/// An iterator for recursively descending into a directory. +/// +/// A value with this type must be constructed with the [`WalkDir`] type, which +/// uses a builder pattern to set options such as min/max depth, max open file +/// descriptors and whether the iterator should follow symbolic links. After +/// constructing a `WalkDir`, call [`.into_iter()`] at the end of the chain. +/// +/// The order of elements yielded by this iterator is unspecified. +/// +/// [`WalkDir`]: struct.WalkDir.html +/// [`.into_iter()`]: struct.WalkDir.html#into_iter.v +#[derive(Debug)] +pub struct IntoIter { + /// Options specified in the builder. Depths, max fds, etc. + opts: WalkDirOptions, + /// The start path. + /// + /// This is only `Some(...)` at the beginning. After the first iteration, + /// this is always `None`. + start: Option<PathBuf>, + /// A stack of open (up to max fd) or closed handles to directories. + /// An open handle is a plain [`fs::ReadDir`] while a closed handle is + /// a `Vec<fs::DirEntry>` corresponding to the as-of-yet consumed entries. + /// + /// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html + stack_list: Vec<DirList>, + /// A stack of file paths. + /// + /// This is *only* used when [`follow_links`] is enabled. In all other + /// cases this stack is empty. + /// + /// [`follow_links`]: struct.WalkDir.html#method.follow_links + stack_path: Vec<Ancestor>, + /// An index into `stack_list` that points to the oldest open directory + /// handle. If the maximum fd limit is reached and a new directory needs to + /// be read, the handle at this index is closed before the new directory is + /// opened. + oldest_opened: usize, + /// The current depth of iteration (the length of the stack at the + /// beginning of each iteration). + depth: usize, + /// A list of DirEntries corresponding to directories, that are + /// yielded after their contents has been fully yielded. This is only + /// used when `contents_first` is enabled. + deferred_dirs: Vec<DirEntry>, + /// The device of the root file path when the first call to `next` was + /// made. + /// + /// If the `same_file_system` option isn't enabled, then this is always + /// `None`. Conversely, if it is enabled, this is always `Some(...)` after + /// handling the root path. + root_device: Option<u64>, +} + +/// An ancestor is an item in the directory tree traversed by walkdir, and is +/// used to check for loops in the tree when traversing symlinks. +#[derive(Debug)] +struct Ancestor { + /// The path of this ancestor. + path: PathBuf, + /// An open file to this ancesor. This is only used on Windows where + /// opening a file handle appears to be quite expensive, so we choose to + /// cache it. This comes at the cost of not respecting the file descriptor + /// limit set by the user. + #[cfg(windows)] + handle: Handle, +} + +impl Ancestor { + /// Create a new ancestor from the given directory path. + #[cfg(windows)] + fn new(dent: &DirEntry) -> io::Result<Ancestor> { + let handle = Handle::from_path(dent.path())?; + Ok(Ancestor { + path: dent.path().to_path_buf(), + handle: handle, + }) + } + + /// Create a new ancestor from the given directory path. + #[cfg(not(windows))] + fn new(dent: &DirEntry) -> io::Result<Ancestor> { + Ok(Ancestor { path: dent.path().to_path_buf() }) + } + + /// Returns true if and only if the given open file handle corresponds to + /// the same directory as this ancestor. + #[cfg(windows)] + fn is_same(&self, child: &Handle) -> io::Result<bool> { + Ok(child == &self.handle) + } + + /// Returns true if and only if the given open file handle corresponds to + /// the same directory as this ancestor. + #[cfg(not(windows))] + fn is_same(&self, child: &Handle) -> io::Result<bool> { + Ok(child == &Handle::from_path(&self.path)?) + } +} + +/// A sequence of unconsumed directory entries. +/// +/// This represents the opened or closed state of a directory handle. When +/// open, future entries are read by iterating over the raw `fs::ReadDir`. +/// When closed, all future entries are read into memory. Iteration then +/// proceeds over a [`Vec<fs::DirEntry>`]. +/// +/// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html +/// [`Vec<fs::DirEntry>`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html +#[derive(Debug)] +enum DirList { + /// An opened handle. + /// + /// This includes the depth of the handle itself. + /// + /// If there was an error with the initial [`fs::read_dir`] call, then it + /// is stored here. (We use an [`Option<...>`] to make yielding the error + /// exactly once simpler.) + /// + /// [`fs::read_dir`]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html + /// [`Option<...>`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html + Opened { depth: usize, it: result::Result<ReadDir, Option<Error>> }, + /// A closed handle. + /// + /// All remaining directory entries are read into memory. + Closed(vec::IntoIter<Result<DirEntry>>), +} + +/// A directory entry. +/// +/// This is the type of value that is yielded from the iterators defined in +/// this crate. +/// +/// On Unix systems, this type implements the [`DirEntryExt`] trait, which +/// provides efficient access to the inode number of the directory entry. +/// +/// # Differences with `std::fs::DirEntry` +/// +/// This type mostly mirrors the type by the same name in [`std::fs`]. There +/// are some differences however: +/// +/// * All recursive directory iterators must inspect the entry's type. +/// Therefore, the value is stored and its access is guaranteed to be cheap and +/// successful. +/// * [`path`] and [`file_name`] return borrowed variants. +/// * If [`follow_links`] was enabled on the originating iterator, then all +/// operations except for [`path`] operate on the link target. Otherwise, all +/// operations operate on the symbolic link. +/// +/// [`std::fs`]: https://doc.rust-lang.org/stable/std/fs/index.html +/// [`path`]: #method.path +/// [`file_name`]: #method.file_name +/// [`follow_links`]: struct.WalkDir.html#method.follow_links +/// [`DirEntryExt`]: trait.DirEntryExt.html +pub struct DirEntry { + /// The path as reported by the [`fs::ReadDir`] iterator (even if it's a + /// symbolic link). + /// + /// [`fs::ReadDir`]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html + path: PathBuf, + /// The file type. Necessary for recursive iteration, so store it. + ty: FileType, + /// Is set when this entry was created from a symbolic link and the user + /// expects the iterator to follow symbolic links. + follow_link: bool, + /// The depth at which this entry was generated relative to the root. + depth: usize, + /// The underlying inode number (Unix only). + #[cfg(unix)] + ino: u64, + /// The underlying metadata (Windows only). We store this on Windows + /// because this comes for free while reading a directory. + /// + /// We use this to determine whether an entry is a directory or not, which + /// works around a bug in Rust's standard library: + /// https://github.com/rust-lang/rust/issues/46484 + #[cfg(windows)] + metadata: fs::Metadata, +} + +impl Iterator for IntoIter { + type Item = Result<DirEntry>; + /// Advances the iterator and returns the next value. + /// + /// # Errors + /// + /// If the iterator fails to retrieve the next value, this method returns + /// an error value. The error will be wrapped in an Option::Some. + fn next(&mut self) -> Option<Result<DirEntry>> { + if let Some(start) = self.start.take() { + if self.opts.same_file_system { + let result = device_num(&start) + .map_err(|e| Error::from_path(0, start.clone(), e)); + self.root_device = Some(itry!(result)); + } + let mut dent = itry!(DirEntry::from_path(0, start, false)); + if let Some(result) = self.handle_entry(dent) { + return Some(result); + } + } + while !self.stack_list.is_empty() { + self.depth = self.stack_list.len(); + if let Some(dentry) = self.get_deferred_dir() { + return Some(Ok(dentry)); + } + if self.depth > self.opts.max_depth { + // If we've exceeded the max depth, pop the current dir + // so that we don't descend. + self.pop(); + continue; + } + // Unwrap is safe here because we've verified above that + // `self.stack_list` is not empty + let next = self.stack_list + .last_mut() + .expect("BUG: stack should be non-empty") + .next(); + match next { + None => self.pop(), + Some(Err(err)) => return Some(Err(err)), + Some(Ok(dent)) => { + if let Some(result) = self.handle_entry(dent) { + return Some(result); + } + } + } + } + if self.opts.contents_first { + self.depth = self.stack_list.len(); + if let Some(dentry) = self.get_deferred_dir() { + return Some(Ok(dentry)); + } + } + None + } +} + +impl IntoIter { + /// Skips the current directory. + /// + /// This causes the iterator to stop traversing the contents of the least + /// recently yielded directory. This means any remaining entries in that + /// directory will be skipped (including sub-directories). + /// + /// Note that the ergonomics of this method are questionable since it + /// borrows the iterator mutably. Namely, you must write out the looping + /// condition manually. For example, to skip hidden entries efficiently on + /// unix systems: + /// + /// ```no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// let mut it = WalkDir::new("foo").into_iter(); + /// loop { + /// let entry = match it.next() { + /// None => break, + /// Some(Err(err)) => panic!("ERROR: {}", err), + /// Some(Ok(entry)) => entry, + /// }; + /// if is_hidden(&entry) { + /// if entry.file_type().is_dir() { + /// it.skip_current_dir(); + /// } + /// continue; + /// } + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// You may find it more convenient to use the [`filter_entry`] iterator + /// adapter. (See its documentation for the same example functionality as + /// above.) + /// + /// [`filter_entry`]: #method.filter_entry + pub fn skip_current_dir(&mut self) { + if !self.stack_list.is_empty() { + self.stack_list.pop(); + } + if !self.stack_path.is_empty() { + self.stack_path.pop(); + } + } + + /// Yields only entries which satisfy the given predicate and skips + /// descending into directories that do not satisfy the given predicate. + /// + /// The predicate is applied to all entries. If the predicate is + /// true, iteration carries on as normal. If the predicate is false, the + /// entry is ignored and if it is a directory, it is not descended into. + /// + /// This is often more convenient to use than [`skip_current_dir`]. For + /// example, to skip hidden files and directories efficiently on unix + /// systems: + /// + /// ```no_run + /// use walkdir::{DirEntry, WalkDir}; + /// # use walkdir::Error; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// # fn try_main() -> Result<(), Error> { + /// for entry in WalkDir::new("foo") + /// .into_iter() + /// .filter_entry(|e| !is_hidden(e)) { + /// println!("{}", entry?.path().display()); + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// Note that the iterator will still yield errors for reading entries that + /// may not satisfy the predicate. + /// + /// Note that entries skipped with [`min_depth`] and [`max_depth`] are not + /// passed to this predicate. + /// + /// Note that if the iterator has `contents_first` enabled, then this + /// method is no different than calling the standard `Iterator::filter` + /// method (because directory entries are yielded after they've been + /// descended into). + /// + /// [`skip_current_dir`]: #method.skip_current_dir + /// [`min_depth`]: struct.WalkDir.html#method.min_depth + /// [`max_depth`]: struct.WalkDir.html#method.max_depth + pub fn filter_entry<P>(self, predicate: P) -> FilterEntry<Self, P> + where P: FnMut(&DirEntry) -> bool + { + FilterEntry { it: self, predicate: predicate } + } + + fn handle_entry( + &mut self, + mut dent: DirEntry, + ) -> Option<Result<DirEntry>> { + if self.opts.follow_links && dent.file_type().is_symlink() { + dent = itry!(self.follow(dent)); + } + let is_normal_dir = !dent.file_type().is_symlink() && dent.is_dir(); + if is_normal_dir { + if self.opts.same_file_system && dent.depth > 0 { + if itry!(self.is_same_file_system(&dent)) { + itry!(self.push(&dent)); + } + } else { + itry!(self.push(&dent)); + } + } else if dent.depth() == 0 && dent.file_type().is_symlink() { + // As a special case, if we are processing a root entry, then we + // always follow it even if it's a symlink and follow_links is + // false. We are careful to not let this change the semantics of + // the DirEntry however. Namely, the DirEntry should still respect + // the follow_links setting. When it's disabled, it should report + // itself as a symlink. When it's enabled, it should always report + // itself as the target. + let md = itry!(fs::metadata(dent.path()).map_err(|err| { + Error::from_path(dent.depth(), dent.path().to_path_buf(), err) + })); + if md.file_type().is_dir() { + itry!(self.push(&dent)); + } + } + if is_normal_dir && self.opts.contents_first { + self.deferred_dirs.push(dent); + None + } else if self.skippable() { + None + } else { + Some(Ok(dent)) + } + } + + fn get_deferred_dir(&mut self) -> Option<DirEntry> { + if self.opts.contents_first { + if self.depth < self.deferred_dirs.len() { + // Unwrap is safe here because we've guaranteed that + // `self.deferred_dirs.len()` can never be less than 1 + let deferred: DirEntry = self.deferred_dirs.pop() + .expect("BUG: deferred_dirs should be non-empty"); + if !self.skippable() { + return Some(deferred); + } + } + } + None + } + + fn push(&mut self, dent: &DirEntry) -> Result<()> { + // Make room for another open file descriptor if we've hit the max. + let free = self.stack_list + .len() + .checked_sub(self.oldest_opened).unwrap(); + if free == self.opts.max_open { + self.stack_list[self.oldest_opened].close(); + // Unwrap is safe here because self.oldest_opened is guaranteed to + // never be greater than `self.stack_list.len()`, which implies + // that the subtraction won't underflow and that adding 1 will + // never overflow. + self.oldest_opened = self.oldest_opened.checked_add(1).unwrap(); + } + // Open a handle to reading the directory's entries. + let rd = fs::read_dir(dent.path()).map_err(|err| { + Some(Error::from_path(self.depth, dent.path().to_path_buf(), err)) + }); + let mut list = DirList::Opened { depth: self.depth, it: rd }; + if let Some(ref mut cmp) = self.opts.sorter { + let mut entries: Vec<_> = list.collect(); + entries.sort_by(|a, b| { + match (a, b) { + (&Ok(ref a), &Ok(ref b)) => { + cmp(a, b) + } + (&Err(_), &Err(_)) => Ordering::Equal, + (&Ok(_), &Err(_)) => Ordering::Greater, + (&Err(_), &Ok(_)) => Ordering::Less, + } + }); + list = DirList::Closed(entries.into_iter()); + } + if self.opts.follow_links { + let ancestor = Ancestor::new(&dent).map_err(|err| { + Error::from_io(self.depth, err) + })?; + self.stack_path.push(ancestor); + } + // We push this after stack_path since creating the Ancestor can fail. + // If it fails, then we return the error and won't descend. + self.stack_list.push(list); + Ok(()) + } + + fn pop(&mut self) { + self.stack_list.pop().expect("BUG: cannot pop from empty stack"); + if self.opts.follow_links { + self.stack_path.pop().expect("BUG: list/path stacks out of sync"); + } + // If everything in the stack is already closed, then there is + // room for at least one more open descriptor and it will + // always be at the top of the stack. + self.oldest_opened = min(self.oldest_opened, self.stack_list.len()); + } + + fn follow(&self, mut dent: DirEntry) -> Result<DirEntry> { + dent = DirEntry::from_path( + self.depth, + dent.path().to_path_buf(), + true, + )?; + // The only way a symlink can cause a loop is if it points + // to a directory. Otherwise, it always points to a leaf + // and we can omit any loop checks. + if dent.is_dir() { + self.check_loop(dent.path())?; + } + Ok(dent) + } + + fn check_loop<P: AsRef<Path>>(&self, child: P) -> Result<()> { + let hchild = Handle::from_path(&child).map_err(|err| { + Error::from_io(self.depth, err) + })?; + for ancestor in self.stack_path.iter().rev() { + let is_same = ancestor.is_same(&hchild).map_err(|err| { + Error::from_io(self.depth, err) + })?; + if is_same { + return Err(Error { + depth: self.depth, + inner: ErrorInner::Loop { + ancestor: ancestor.path.to_path_buf(), + child: child.as_ref().to_path_buf(), + }, + }); + } + } + Ok(()) + } + + fn is_same_file_system(&mut self, dent: &DirEntry) -> Result<bool> { + let dent_device = device_num(&dent.path) + .map_err(|err| Error::from_entry(dent, err))?; + Ok(self.root_device + .map(|d| d == dent_device) + .expect("BUG: called is_same_file_system without root device")) + } + + fn skippable(&self) -> bool { + self.depth < self.opts.min_depth || self.depth > self.opts.max_depth + } +} + +impl DirList { + fn close(&mut self) { + if let DirList::Opened { .. } = *self { + *self = DirList::Closed(self.collect::<Vec<_>>().into_iter()); + } + } +} + +impl Iterator for DirList { + type Item = Result<DirEntry>; + + #[inline(always)] + fn next(&mut self) -> Option<Result<DirEntry>> { + match *self { + DirList::Closed(ref mut it) => it.next(), + DirList::Opened { depth, ref mut it } => match *it { + Err(ref mut err) => err.take().map(Err), + Ok(ref mut rd) => rd.next().map(|r| match r { + Ok(r) => DirEntry::from_entry(depth + 1, &r), + Err(err) => Err(Error::from_io(depth + 1, err)) + }), + } + } + } +} + +impl DirEntry { + /// The full path that this entry represents. + /// + /// The full path is created by joining the parents of this entry up to the + /// root initially given to [`WalkDir::new`] with the file name of this + /// entry. + /// + /// Note that this *always* returns the path reported by the underlying + /// directory entry, even when symbolic links are followed. To get the + /// target path, use [`path_is_symlink`] to (cheaply) check if this entry + /// corresponds to a symbolic link, and [`std::fs::read_link`] to resolve + /// the target. + /// + /// [`WalkDir::new`]: struct.WalkDir.html#method.new + /// [`path_is_symlink`]: struct.DirEntry.html#method.path_is_symlink + /// [`std::fs::read_link`]: https://doc.rust-lang.org/stable/std/fs/fn.read_link.html + pub fn path(&self) -> &Path { + &self.path + } + + /// The full path that this entry represents. + /// + /// Analogous to [`path`], but moves ownership of the path. + /// + /// [`path`]: struct.DirEntry.html#method.path + pub fn into_path(self) -> PathBuf { + self.path + } + + /// Returns `true` if and only if this entry was created from a symbolic + /// link. This is unaffected by the [`follow_links`] setting. + /// + /// When `true`, the value returned by the [`path`] method is a + /// symbolic link name. To get the full target path, you must call + /// [`std::fs::read_link(entry.path())`]. + /// + /// [`path`]: struct.DirEntry.html#method.path + /// [`follow_links`]: struct.WalkDir.html#method.follow_links + /// [`std::fs::read_link(entry.path())`]: https://doc.rust-lang.org/stable/std/fs/fn.read_link.html + pub fn path_is_symlink(&self) -> bool { + self.ty.is_symlink() || self.follow_link + } + + /// Return the metadata for the file that this entry points to. + /// + /// This will follow symbolic links if and only if the [`WalkDir`] value + /// has [`follow_links`] enabled. + /// + /// # Platform behavior + /// + /// This always calls [`std::fs::symlink_metadata`]. + /// + /// If this entry is a symbolic link and [`follow_links`] is enabled, then + /// [`std::fs::metadata`] is called instead. + /// + /// # Errors + /// + /// Similar to [`std::fs::metadata`], returns errors for path values that + /// the program does not have permissions to access or if the path does not + /// exist. + /// + /// [`WalkDir`]: struct.WalkDir.html + /// [`follow_links`]: struct.WalkDir.html#method.follow_links + /// [`std::fs::metadata`]: https://doc.rust-lang.org/std/fs/fn.metadata.html + /// [`std::fs::symlink_metadata`]: https://doc.rust-lang.org/stable/std/fs/fn.symlink_metadata.html + pub fn metadata(&self) -> Result<fs::Metadata> { + self.metadata_internal() + } + + #[cfg(windows)] + fn metadata_internal(&self) -> Result<fs::Metadata> { + if self.follow_link { + fs::metadata(&self.path) + } else { + Ok(self.metadata.clone()) + }.map_err(|err| Error::from_entry(self, err)) + } + + #[cfg(not(windows))] + fn metadata_internal(&self) -> Result<fs::Metadata> { + if self.follow_link { + fs::metadata(&self.path) + } else { + fs::symlink_metadata(&self.path) + }.map_err(|err| Error::from_entry(self, err)) + } + + /// Return the file type for the file that this entry points to. + /// + /// If this is a symbolic link and [`follow_links`] is `true`, then this + /// returns the type of the target. + /// + /// This never makes any system calls. + /// + /// [`follow_links`]: struct.WalkDir.html#method.follow_links + pub fn file_type(&self) -> fs::FileType { + self.ty + } + + /// Return the file name of this entry. + /// + /// If this entry has no file name (e.g., `/`), then the full path is + /// returned. + pub fn file_name(&self) -> &OsStr { + self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) + } + + /// Returns the depth at which this entry was created relative to the root. + /// + /// The smallest depth is `0` and always corresponds to the path given + /// to the `new` function on `WalkDir`. Its direct descendents have depth + /// `1`, and their descendents have depth `2`, and so on. + pub fn depth(&self) -> usize { + self.depth + } + + /// Returns true if and only if this entry points to a directory. + /// + /// This works around a bug in Rust's standard library: + /// https://github.com/rust-lang/rust/issues/46484 + #[cfg(windows)] + fn is_dir(&self) -> bool { + use std::os::windows::fs::MetadataExt; + use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; + self.metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 + } + + /// Returns true if and only if this entry points to a directory. + #[cfg(not(windows))] + fn is_dir(&self) -> bool { + self.ty.is_dir() + } + + #[cfg(windows)] + fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { + let path = ent.path(); + let ty = ent.file_type().map_err(|err| { + Error::from_path(depth, path.clone(), err) + })?; + let md = ent.metadata().map_err(|err| { + Error::from_path(depth, path.clone(), err) + })?; + Ok(DirEntry { + path: path, + ty: ty, + follow_link: false, + depth: depth, + metadata: md, + }) + } + + #[cfg(unix)] + fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { + use std::os::unix::fs::DirEntryExt; + + let ty = ent.file_type().map_err(|err| { + Error::from_path(depth, ent.path(), err) + })?; + Ok(DirEntry { + path: ent.path(), + ty: ty, + follow_link: false, + depth: depth, + ino: ent.ino(), + }) + } + + #[cfg(not(any(unix, windows)))] + fn from_entry(depth: usize, ent: &fs::DirEntry) -> Result<DirEntry> { + let ty = ent.file_type().map_err(|err| { + Error::from_path(depth, ent.path(), err) + })?; + Ok(DirEntry { + path: ent.path(), + ty: ty, + follow_link: false, + depth: depth, + }) + } + + #[cfg(windows)] + fn from_path(depth: usize, pb: PathBuf, follow: bool) -> Result<DirEntry> { + let md = + if follow { + fs::metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + } else { + fs::symlink_metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + }; + Ok(DirEntry { + path: pb, + ty: md.file_type(), + follow_link: follow, + depth: depth, + metadata: md, + }) + } + + #[cfg(unix)] + fn from_path(depth: usize, pb: PathBuf, follow: bool) -> Result<DirEntry> { + use std::os::unix::fs::MetadataExt; + + let md = + if follow { + fs::metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + } else { + fs::symlink_metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + }; + Ok(DirEntry { + path: pb, + ty: md.file_type(), + follow_link: follow, + depth: depth, + ino: md.ino(), + }) + } + + #[cfg(not(any(unix, windows)))] + fn from_path(depth: usize, pb: PathBuf, follow: bool) -> Result<DirEntry> { + let md = + if follow { + fs::metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + } else { + fs::symlink_metadata(&pb).map_err(|err| { + Error::from_path(depth, pb.clone(), err) + })? + }; + Ok(DirEntry { + path: pb, + ty: md.file_type(), + follow_link: follow, + depth: depth, + }) + } +} + +impl Clone for DirEntry { + #[cfg(windows)] + fn clone(&self) -> DirEntry { + DirEntry { + path: self.path.clone(), + ty: self.ty, + follow_link: self.follow_link, + depth: self.depth, + metadata: self.metadata.clone(), + } + } + + #[cfg(unix)] + fn clone(&self) -> DirEntry { + DirEntry { + path: self.path.clone(), + ty: self.ty, + follow_link: self.follow_link, + depth: self.depth, + ino: self.ino, + } + } + + #[cfg(not(any(unix, windows)))] + fn clone(&self) -> DirEntry { + DirEntry { + path: self.path.clone(), + ty: self.ty, + follow_link: self.follow_link, + depth: self.depth, + } + } +} + +impl fmt::Debug for DirEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "DirEntry({:?})", self.path) + } +} + +/// A recursive directory iterator that skips entries. +/// +/// Values of this type are created by calling [`.filter_entry()`] on an +/// `IntoIter`, which is formed by calling [`.into_iter()`] on a `WalkDir`. +/// +/// Directories that fail the predicate `P` are skipped. Namely, they are +/// never yielded and never descended into. +/// +/// Entries that are skipped with the [`min_depth`] and [`max_depth`] options +/// are not passed through this filter. +/// +/// If opening a handle to a directory resulted in an error, then it is yielded +/// and no corresponding call to the predicate is made. +/// +/// Type parameter `I` refers to the underlying iterator and `P` refers to the +/// predicate, which is usually `FnMut(&DirEntry) -> bool`. +/// +/// [`.filter_entry()`]: struct.IntoIter.html#method.filter_entry +/// [`.into_iter()`]: struct.WalkDir.html#into_iter.v +/// [`min_depth`]: struct.WalkDir.html#method.min_depth +/// [`max_depth`]: struct.WalkDir.html#method.max_depth +#[derive(Debug)] +pub struct FilterEntry<I, P> { + it: I, + predicate: P, +} + +impl<P> Iterator for FilterEntry<IntoIter, P> +where P: FnMut(&DirEntry) -> bool +{ + type Item = Result<DirEntry>; + + /// Advances the iterator and returns the next value. + /// + /// # Errors + /// + /// If the iterator fails to retrieve the next value, this method returns + /// an error value. The error will be wrapped in an `Option::Some`. + fn next(&mut self) -> Option<Result<DirEntry>> { + loop { + let dent = match self.it.next() { + None => return None, + Some(result) => itry!(result), + }; + if !(self.predicate)(&dent) { + if dent.is_dir() { + self.it.skip_current_dir(); + } + continue; + } + return Some(Ok(dent)); + } + } +} + +impl<P> FilterEntry<IntoIter, P> where P: FnMut(&DirEntry) -> bool { + /// Yields only entries which satisfy the given predicate and skips + /// descending into directories that do not satisfy the given predicate. + /// + /// The predicate is applied to all entries. If the predicate is + /// true, iteration carries on as normal. If the predicate is false, the + /// entry is ignored and if it is a directory, it is not descended into. + /// + /// This is often more convenient to use than [`skip_current_dir`]. For + /// example, to skip hidden files and directories efficiently on unix + /// systems: + /// + /// ```no_run + /// use walkdir::{DirEntry, WalkDir}; + /// # use walkdir::Error; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// # fn try_main() -> Result<(), Error> { + /// for entry in WalkDir::new("foo") + /// .into_iter() + /// .filter_entry(|e| !is_hidden(e)) { + /// println!("{}", entry?.path().display()); + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// Note that the iterator will still yield errors for reading entries that + /// may not satisfy the predicate. + /// + /// Note that entries skipped with [`min_depth`] and [`max_depth`] are not + /// passed to this predicate. + /// + /// Note that if the iterator has `contents_first` enabled, then this + /// method is no different than calling the standard `Iterator::filter` + /// method (because directory entries are yielded after they've been + /// descended into). + /// + /// [`skip_current_dir`]: #method.skip_current_dir + /// [`min_depth`]: struct.WalkDir.html#method.min_depth + /// [`max_depth`]: struct.WalkDir.html#method.max_depth + pub fn filter_entry(self, predicate: P) -> FilterEntry<Self, P> { + FilterEntry { it: self, predicate: predicate } + } + + /// Skips the current directory. + /// + /// This causes the iterator to stop traversing the contents of the least + /// recently yielded directory. This means any remaining entries in that + /// directory will be skipped (including sub-directories). + /// + /// Note that the ergonomics of this method are questionable since it + /// borrows the iterator mutably. Namely, you must write out the looping + /// condition manually. For example, to skip hidden entries efficiently on + /// unix systems: + /// + /// ```no_run + /// use walkdir::{DirEntry, WalkDir}; + /// + /// fn is_hidden(entry: &DirEntry) -> bool { + /// entry.file_name() + /// .to_str() + /// .map(|s| s.starts_with(".")) + /// .unwrap_or(false) + /// } + /// + /// let mut it = WalkDir::new("foo").into_iter(); + /// loop { + /// let entry = match it.next() { + /// None => break, + /// Some(Err(err)) => panic!("ERROR: {}", err), + /// Some(Ok(entry)) => entry, + /// }; + /// if is_hidden(&entry) { + /// if entry.file_type().is_dir() { + /// it.skip_current_dir(); + /// } + /// continue; + /// } + /// println!("{}", entry.path().display()); + /// } + /// ``` + /// + /// You may find it more convenient to use the [`filter_entry`] iterator + /// adapter. (See its documentation for the same example functionality as + /// above.) + /// + /// [`filter_entry`]: #method.filter_entry + pub fn skip_current_dir(&mut self) { + self.it.skip_current_dir(); + } +} + +/// An error produced by recursively walking a directory. +/// +/// This error type is a light wrapper around [`std::io::Error`]. In +/// particular, it adds the following information: +/// +/// * The depth at which the error occurred in the file tree, relative to the +/// root. +/// * The path, if any, associated with the IO error. +/// * An indication that a loop occurred when following symbolic links. In this +/// case, there is no underlying IO error. +/// +/// To maintain good ergonomics, this type has a +/// [`impl From<Error> for std::io::Error`][impl] defined which preserves the original context. +/// This allows you to use an [`io::Result`] with methods in this crate if you don't care about +/// accessing the underlying error data in a structured form. +/// +/// [`std::io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html +/// [`io::Result`]: https://doc.rust-lang.org/stable/std/io/type.Result.html +/// [impl]: struct.Error.html#impl-From%3CError%3E +#[derive(Debug)] +pub struct Error { + depth: usize, + inner: ErrorInner, +} + +#[derive(Debug)] +enum ErrorInner { + Io { path: Option<PathBuf>, err: io::Error }, + Loop { ancestor: PathBuf, child: PathBuf }, +} + +impl Error { + /// Returns the path associated with this error if one exists. + /// + /// For example, if an error occurred while opening a directory handle, + /// the error will include the path passed to [`std::fs::read_dir`]. + /// + /// [`std::fs::read_dir`]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html + pub fn path(&self) -> Option<&Path> { + match self.inner { + ErrorInner::Io { path: None, .. } => None, + ErrorInner::Io { path: Some(ref path), .. } => Some(path), + ErrorInner::Loop { ref child, .. } => Some(child), + } + } + + /// Returns the path at which a cycle was detected. + /// + /// If no cycle was detected, [`None`] is returned. + /// + /// A cycle is detected when a directory entry is equivalent to one of + /// its ancestors. + /// + /// To get the path to the child directory entry in the cycle, use the + /// [`path`] method. + /// + /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None + /// [`path`]: struct.Error.html#path + pub fn loop_ancestor(&self) -> Option<&Path> { + match self.inner { + ErrorInner::Loop { ref ancestor, .. } => Some(ancestor), + _ => None, + } + } + + /// Returns the depth at which this error occurred relative to the root. + /// + /// The smallest depth is `0` and always corresponds to the path given to + /// the [`new`] function on [`WalkDir`]. Its direct descendents have depth + /// `1`, and their descendents have depth `2`, and so on. + /// + /// [`new`]: struct.WalkDir.html#method.new + /// [`WalkDir`]: struct.WalkDir.html + pub fn depth(&self) -> usize { + self.depth + } + + /// Inspect the original [`io::Error`] if there is one. + /// + /// [`None`] is returned if the [`Error`] doesn't correspond to an + /// [`io::Error`]. This might happen, for example, when the error was + /// produced because a cycle was found in the directory tree while + /// following symbolic links. + /// + /// This method returns a borrowed value that is bound to the lifetime of the [`Error`]. To + /// obtain an owned value, the [`into_io_error`] can be used instead. + /// + /// > This is the original [`io::Error`] and is _not_ the same as + /// > [`impl From<Error> for std::io::Error`][impl] which contains additional context about the + /// error. + /// + /// # Example + /// + /// ```rust,no-run + /// use std::io; + /// use std::path::Path; + /// + /// use walkdir::WalkDir; + /// + /// for entry in WalkDir::new("foo") { + /// match entry { + /// Ok(entry) => println!("{}", entry.path().display()), + /// Err(err) => { + /// let path = err.path().unwrap_or(Path::new("")).display(); + /// println!("failed to access entry {}", path); + /// if let Some(inner) = err.io_error() { + /// match inner.kind() { + /// io::ErrorKind::InvalidData => { + /// println!( + /// "entry contains invalid data: {}", + /// inner) + /// } + /// io::ErrorKind::PermissionDenied => { + /// println!( + /// "Missing permission to read entry: {}", + /// inner) + /// } + /// _ => { + /// println!( + /// "Unexpected error occurred: {}", + /// inner) + /// } + /// } + /// } + /// } + /// } + /// } + /// ``` + /// + /// [`None`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#variant.None + /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html + /// [`From`]: https://doc.rust-lang.org/stable/std/convert/trait.From.html + /// [`Error`]: struct.Error.html + /// [`into_io_error`]: struct.Error.html#method.into_io_error + /// [impl]: struct.Error.html#impl-From%3CError%3E + pub fn io_error(&self) -> Option<&io::Error> { + match self.inner { + ErrorInner::Io { ref err, .. } => Some(err), + ErrorInner::Loop { .. } => None, + } + } + + /// Similar to [`io_error`] except consumes self to convert to the original + /// [`io::Error`] if one exists. + /// + /// [`io_error`]: struct.Error.html#method.io_error + /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html + pub fn into_io_error(self) -> Option<io::Error> { + match self.inner { + ErrorInner::Io { err, .. } => Some(err), + ErrorInner::Loop { .. } => None, + } + } + + fn from_path(depth: usize, pb: PathBuf, err: io::Error) -> Self { + Error { + depth: depth, + inner: ErrorInner::Io { path: Some(pb), err: err }, + } + } + + fn from_entry(dent: &DirEntry, err: io::Error) -> Self { + Error { + depth: dent.depth, + inner: ErrorInner::Io { + path: Some(dent.path().to_path_buf()), + err: err, + }, + } + } + + fn from_io(depth: usize, err: io::Error) -> Self { + Error { + depth: depth, + inner: ErrorInner::Io { path: None, err: err }, + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match self.inner { + ErrorInner::Io { ref err, .. } => err.description(), + ErrorInner::Loop { .. } => "file system loop found", + } + } + + fn cause(&self) -> Option<&error::Error> { + match self.inner { + ErrorInner::Io { ref err, .. } => Some(err), + ErrorInner::Loop { .. } => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.inner { + ErrorInner::Io { path: None, ref err } => { + err.fmt(f) + } + ErrorInner::Io { path: Some(ref path), ref err } => { + write!(f, "IO error for operation on {}: {}", + path.display(), err) + } + ErrorInner::Loop { ref ancestor, ref child } => { + write!(f, "File system loop found: \ + {} points to an ancestor {}", + child.display(), ancestor.display()) + } + } + } +} + +impl From<Error> for io::Error { + /// Convert the [`Error`] to an [`io::Error`], preserving the original + /// [`Error`] as the ["inner error"]. Note that this also makes the display + /// of the error include the context. + /// + /// This is different from [`into_io_error`] which returns the original + /// [`io::Error`]. + /// + /// [`Error`]: struct.Error.html + /// [`io::Error`]: https://doc.rust-lang.org/stable/std/io/struct.Error.html + /// ["inner error"]: https://doc.rust-lang.org/std/io/struct.Error.html#method.into_inner + /// [`into_io_error`]: struct.WalkDir.html#method.into_io_error + fn from(walk_err: Error) -> io::Error { + let kind = match walk_err { + Error { inner: ErrorInner::Io { ref err, .. }, .. } => { + err.kind() + } + Error { inner: ErrorInner::Loop { .. }, .. } => { + io::ErrorKind::Other + } + }; + io::Error::new(kind, walk_err) + } +} + +#[cfg(unix)] +fn device_num<P: AsRef<Path>>(path: P)-> std::io::Result<u64> { + use std::os::unix::fs::MetadataExt; + + path.as_ref().metadata().map(|md| md.dev()) +} + + #[cfg(windows)] +fn device_num<P: AsRef<Path>>(path: P) -> std::io::Result<u64> { + use winapi_util::{Handle, file}; + + let h = Handle::from_path_any(path)?; + file::information(h).map(|info| info.volume_serial_number()) +} + +#[cfg(not(any(unix, windows)))] +fn device_num<P: AsRef<Path>>(_: P)-> std::io::Result<u64> { + Err(io::Error::new( + io::ErrorKind::Other, + "walkdir: same_file_system option not supported on this platform", + )) +} diff --git a/walkdir/src/tests.rs b/walkdir/src/tests.rs new file mode 100644 index 000000000..ddce7958e --- /dev/null +++ b/walkdir/src/tests.rs @@ -0,0 +1,912 @@ +#![cfg_attr(windows, allow(dead_code, unused_imports))] + +use std::cmp; +use std::env; +use std::fs::{self, File}; +use std::io; +use std::path::{Path, PathBuf}; +use std::collections::HashMap; + +use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen}; +use rand::{self, Rng, RngCore}; + +use super::{DirEntry, WalkDir, IntoIter, Error, ErrorInner}; + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +enum Tree { + Dir(PathBuf, Vec<Tree>), + File(PathBuf), + Symlink { + src: PathBuf, + dst: PathBuf, + dir: bool, + } +} + +impl Tree { + fn from_walk_with<P, F>( + p: P, + f: F, + ) -> io::Result<Tree> + where P: AsRef<Path>, F: FnOnce(WalkDir) -> WalkDir { + let mut stack = vec![Tree::Dir(p.as_ref().to_path_buf(), vec![])]; + let it: WalkEventIter = f(WalkDir::new(p)).into(); + for ev in it { + match try!(ev) { + WalkEvent::Exit => { + let tree = stack.pop().unwrap(); + if stack.is_empty() { + return Ok(tree); + } + stack.last_mut().unwrap().children_mut().push(tree); + } + WalkEvent::Dir(dent) => { + stack.push(Tree::Dir(pb(dent.file_name()), vec![])); + } + WalkEvent::File(dent) => { + let node = if dent.file_type().is_symlink() { + let src = try!(dent.path().read_link()); + let dst = pb(dent.file_name()); + let dir = dent.path().is_dir(); + Tree::Symlink { src: src, dst: dst, dir: dir } + } else { + Tree::File(pb(dent.file_name())) + }; + stack.last_mut().unwrap().children_mut().push(node); + } + } + } + assert_eq!(stack.len(), 1); + Ok(stack.pop().unwrap()) + } + + fn from_walk_with_contents_first<P, F>( + p: P, + f: F, + ) -> io::Result<Tree> + where P: AsRef<Path>, F: FnOnce(WalkDir) -> WalkDir { + let mut contents_of_dir_at_depth = HashMap::new(); + let mut min_depth = ::std::usize::MAX; + let top_level_path = p.as_ref().to_path_buf(); + for result in f(WalkDir::new(p).contents_first(true)) { + let dentry = try!(result); + + let tree = + if dentry.file_type().is_dir() { + let any_contents = contents_of_dir_at_depth.remove( + &(dentry.depth+1)); + Tree::Dir(pb(dentry.file_name()), any_contents.unwrap_or_default()) + } else { + if dentry.file_type().is_symlink() { + let src = try!(dentry.path().read_link()); + let dst = pb(dentry.file_name()); + let dir = dentry.path().is_dir(); + Tree::Symlink { src: src, dst: dst, dir: dir } + } else { + Tree::File(pb(dentry.file_name())) + } + }; + contents_of_dir_at_depth.entry( + dentry.depth).or_insert(vec!()).push(tree); + min_depth = cmp::min(min_depth, dentry.depth); + } + Ok(Tree::Dir(top_level_path, + contents_of_dir_at_depth.remove(&min_depth) + .unwrap_or_default())) + } + + fn name(&self) -> &Path { + match *self { + Tree::Dir(ref pb, _) => pb, + Tree::File(ref pb) => pb, + Tree::Symlink { ref dst, .. } => dst, + } + } + + fn unwrap_singleton(self) -> Tree { + match self { + Tree::File(_) | Tree::Symlink { .. } => { + panic!("cannot unwrap file or link as dir"); + } + Tree::Dir(_, mut childs) => { + assert_eq!(childs.len(), 1); + childs.pop().unwrap() + } + } + } + + fn unwrap_dir(self) -> Vec<Tree> { + match self { + Tree::File(_) | Tree::Symlink { .. } => { + panic!("cannot unwrap file as dir"); + } + Tree::Dir(_, childs) => childs, + } + } + + fn children_mut(&mut self) -> &mut Vec<Tree> { + match *self { + Tree::File(_) | Tree::Symlink { .. } => { + panic!("files do not have children"); + } + Tree::Dir(_, ref mut children) => children, + } + } + + fn create_in<P: AsRef<Path>>(&self, parent: P) -> io::Result<()> { + let parent = parent.as_ref(); + match *self { + Tree::Symlink { ref src, ref dst, dir } => { + if dir { + try!(soft_link_dir(src, parent.join(dst))); + } else { + try!(soft_link_file(src, parent.join(dst))); + } + } + Tree::File(ref p) => { try!(File::create(parent.join(p))); } + Tree::Dir(ref dir, ref children) => { + try!(fs::create_dir(parent.join(dir))); + for child in children { + try!(child.create_in(parent.join(dir))); + } + } + } + Ok(()) + } + + fn canonical(&self) -> Tree { + match *self { + Tree::Symlink { ref src, ref dst, dir } => { + Tree::Symlink { src: src.clone(), dst: dst.clone(), dir: dir } + } + Tree::File(ref p) => { + Tree::File(p.clone()) + } + Tree::Dir(ref p, ref cs) => { + let mut cs: Vec<Tree> = + cs.iter().map(|c| c.canonical()).collect(); + cs.sort(); + Tree::Dir(p.clone(), cs) + } + } + } + + fn dedup(&self) -> Tree { + match *self { + Tree::Symlink { ref src, ref dst, dir } => { + Tree::Symlink { src: src.clone(), dst: dst.clone(), dir: dir } + } + Tree::File(ref p) => { + Tree::File(p.clone()) + } + Tree::Dir(ref p, ref cs) => { + let mut nodupes: Vec<Tree> = vec![]; + for (i, c1) in cs.iter().enumerate() { + if !cs[i+1..].iter().any(|c2| c1.name() == c2.name()) + && !nodupes.iter().any(|c2| c1.name() == c2.name()) { + nodupes.push(c1.dedup()); + } + } + Tree::Dir(p.clone(), nodupes) + } + } + } + + fn gen<G: Gen>(g: &mut G, depth: usize) -> Tree { + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + struct NonEmptyAscii(String); + + impl Arbitrary for NonEmptyAscii { + fn arbitrary<G: Gen>(g: &mut G) -> NonEmptyAscii { + use std::char::from_u32; + let upper_bound = g.size(); + // We start with a lower bound of `4` to avoid + // generating the special file name `con` on Windows, + // because such files cannot exist... + let size = g.gen_range(4, upper_bound); + NonEmptyAscii((0..size) + .map(|_| from_u32(g.gen_range(97, 123)).unwrap()) + .collect()) + } + + fn shrink(&self) -> Box<Iterator<Item=NonEmptyAscii>> { + let mut smaller = vec![]; + for i in 1..self.0.len() { + let s: String = self.0.chars().skip(i).collect(); + smaller.push(NonEmptyAscii(s)); + } + Box::new(smaller.into_iter()) + } + } + + let name = pb(NonEmptyAscii::arbitrary(g).0); + if depth == 0 { + Tree::File(name) + } else { + let children: Vec<Tree> = + (0..g.gen_range(0, 5)) + .map(|_| Tree::gen(g, depth-1)) + .collect(); + Tree::Dir(name, children) + } + } +} + +impl Arbitrary for Tree { + fn arbitrary<G: Gen>(g: &mut G) -> Tree { + let depth = g.gen_range(0, 5); + Tree::gen(g, depth).dedup() + } + + fn shrink(&self) -> Box<Iterator<Item=Tree>> { + let trees: Box<Iterator<Item=Tree>> = match *self { + Tree::Symlink { .. } => unimplemented!(), + Tree::File(ref path) => { + let s = path.to_string_lossy().into_owned(); + Box::new(s.shrink().map(|s| Tree::File(pb(s)))) + } + Tree::Dir(ref path, ref children) => { + let s = path.to_string_lossy().into_owned(); + if children.is_empty() { + Box::new(s.shrink().map(|s| Tree::Dir(pb(s), vec![]))) + } else if children.len() == 1 { + let c = &children[0]; + Box::new(Some(c.clone()).into_iter().chain(c.shrink())) + } else { + Box::new(children + .shrink() + .map(move |cs| Tree::Dir(pb(s.clone()), cs))) + } + } + }; + Box::new(trees.map(|t| t.dedup())) + } +} + +#[derive(Debug)] +enum WalkEvent { + Dir(DirEntry), + File(DirEntry), + Exit, +} + +struct WalkEventIter { + depth: usize, + it: IntoIter, + next: Option<Result<DirEntry, Error>>, +} + +impl From<WalkDir> for WalkEventIter { + fn from(it: WalkDir) -> WalkEventIter { + WalkEventIter { depth: 0, it: it.into_iter(), next: None } + } +} + +impl Iterator for WalkEventIter { + type Item = io::Result<WalkEvent>; + + fn next(&mut self) -> Option<io::Result<WalkEvent>> { + let dent = self.next.take().or_else(|| self.it.next()); + let depth = match dent { + None => 0, + Some(Ok(ref dent)) => dent.depth(), + Some(Err(ref err)) => err.depth(), + }; + if depth < self.depth { + self.depth -= 1; + self.next = dent; + return Some(Ok(WalkEvent::Exit)); + } + self.depth = depth; + match dent { + None => None, + Some(Err(err)) => Some(Err(From::from(err))), + Some(Ok(dent)) => { + if dent.file_type().is_dir() { + self.depth += 1; + Some(Ok(WalkEvent::Dir(dent))) + } else { + Some(Ok(WalkEvent::File(dent))) + } + } + } + } +} + +struct TempDir(PathBuf); + +impl TempDir { + fn path<'a>(&'a self) -> &'a Path { + &self.0 + } +} + +impl Drop for TempDir { + fn drop(&mut self) { + fs::remove_dir_all(&self.0).unwrap(); + } +} + +fn tmpdir() -> TempDir { + let p = env::temp_dir(); + let mut r = rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); + fs::create_dir(&ret).unwrap(); + TempDir(ret) +} + +fn dir_setup_with<F>(t: &Tree, f: F) -> (TempDir, Tree) + where F: Fn(WalkDir) -> WalkDir { + let tmp = tmpdir(); + t.create_in(tmp.path()).unwrap(); + let got = Tree::from_walk_with(tmp.path(), &f).unwrap(); + let got_cf = Tree::from_walk_with_contents_first(tmp.path(), &f).unwrap(); + assert_eq!(got, got_cf); + + (tmp, got.unwrap_singleton().unwrap_singleton()) +} + +fn dir_setup(t: &Tree) -> (TempDir, Tree) { + dir_setup_with(t, |wd| wd) +} + +fn canon(unix: &str) -> String { + if cfg!(windows) { + unix.replace("/", "\\") + } else { + unix.to_string() + } +} + +fn pb<P: AsRef<Path>>(p: P) -> PathBuf { p.as_ref().to_path_buf() } +fn td<P: AsRef<Path>>(p: P, cs: Vec<Tree>) -> Tree { + Tree::Dir(pb(p), cs) +} +fn tf<P: AsRef<Path>>(p: P) -> Tree { + Tree::File(pb(p)) +} +fn tld<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Tree { + Tree::Symlink { src: pb(src), dst: pb(dst), dir: true } +} +fn tlf<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Tree { + Tree::Symlink { src: pb(src), dst: pb(dst), dir: false } +} + +#[cfg(unix)] +fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, +) -> io::Result<()> { + use std::os::unix::fs::symlink; + symlink(src, dst) +} + +#[cfg(unix)] +fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, +) -> io::Result<()> { + soft_link_dir(src, dst) +} + +#[cfg(windows)] +fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, +) -> io::Result<()> { + use std::os::windows::fs::symlink_dir; + symlink_dir(src, dst) +} + +#[cfg(windows)] +fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>( + src: P, + dst: Q, +) -> io::Result<()> { + use std::os::windows::fs::symlink_file; + symlink_file(src, dst) +} + +macro_rules! assert_tree_eq { + ($e1:expr, $e2:expr) => { + assert_eq!($e1.canonical(), $e2.canonical()); + } +} + +#[test] +fn walk_dir_1() { + let exp = td("foo", vec![]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_2() { + let exp = tf("foo"); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_3() { + let exp = td("foo", vec![tf("bar")]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_4() { + let exp = td("foo", vec![tf("foo"), tf("bar"), tf("baz")]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_5() { + let exp = td("foo", vec![td("bar", vec![])]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_6() { + let exp = td("foo", vec![ + td("bar", vec![ + tf("baz"), td("bat", vec![]), + ]), + ]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_7() { + let exp = td("foo", vec![ + td("bar", vec![ + tf("baz"), td("bat", vec![]), + ]), + td("a", vec![tf("b"), tf("c"), tf("d")]), + ]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_sym_1() { + let exp = td("foo", vec![tf("bar"), tlf("bar", "baz")]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_sym_2() { + let exp = td("foo", vec![ + td("a", vec![tf("a1"), tf("a2")]), + tld("a", "alink"), + ]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +fn walk_dir_sym_root() { + let exp = td("foo", vec![ + td("bar", vec![tf("a"), tf("b")]), + tld("bar", "alink"), + ]); + let tmp = tmpdir(); + let tmp_path = tmp.path(); + let tmp_len = tmp_path.to_str().unwrap().len(); + exp.create_in(tmp_path).unwrap(); + + let it = WalkDir::new(tmp_path.join("foo").join("alink")).into_iter(); + let mut got = it + .map(|d| d.unwrap().path().to_str().unwrap()[tmp_len+1..].into()) + .collect::<Vec<String>>(); + got.sort(); + assert_eq!(got, vec![ + canon("foo/alink"), canon("foo/alink/a"), canon("foo/alink/b"), + ]); + + let it = WalkDir::new(tmp_path.join("foo/alink/")).into_iter(); + let mut got = it + .map(|d| d.unwrap().path().to_str().unwrap()[tmp_len+1..].into()) + .collect::<Vec<String>>(); + got.sort(); + assert_eq!(got, vec!["foo/alink/", "foo/alink/a", "foo/alink/b"]); +} + +// See: https://github.com/BurntSushi/ripgrep/issues/984 +#[test] +#[cfg(unix)] +fn first_path_not_symlink() { + let exp = td("foo", vec![]); + let (tmp, _got) = dir_setup(&exp); + + let dents = WalkDir::new(tmp.path().join("foo")) + .into_iter() + .collect::<Result<Vec<_>, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); +} + +// Like first_path_not_symlink, but checks that the first path is not reported +// as a symlink even when we are supposed to be following them. +#[test] +#[cfg(unix)] +fn first_path_not_symlink_follow() { + let exp = td("foo", vec![]); + let (tmp, _got) = dir_setup(&exp); + + let dents = WalkDir::new(tmp.path().join("foo")) + .follow_links(true) + .into_iter() + .collect::<Result<Vec<_>, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].path_is_symlink()); +} + +// See: https://github.com/BurntSushi/walkdir/issues/115 +#[test] +#[cfg(unix)] +fn first_path_is_followed() { + let exp = td("foo", vec![ + td("a", vec![tf("a1"), tf("a2")]), + td("b", vec![tlf("../a/a1", "alink")]), + ]); + let (tmp, _got) = dir_setup(&exp); + + let dents = WalkDir::new(tmp.path().join("foo/b/alink")) + .into_iter() + .collect::<Result<Vec<_>, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(dents[0].file_type().is_symlink()); + assert!(dents[0].metadata().unwrap().file_type().is_symlink()); + + let dents = WalkDir::new(tmp.path().join("foo/b/alink")) + .follow_links(true) + .into_iter() + .collect::<Result<Vec<_>, _>>() + .unwrap(); + assert_eq!(1, dents.len()); + assert!(!dents[0].file_type().is_symlink()); + assert!(!dents[0].metadata().unwrap().file_type().is_symlink()); +} + +#[test] +#[cfg(unix)] +fn walk_dir_sym_detect_no_follow_no_loop() { + let exp = td("foo", vec![ + td("a", vec![tf("a1"), tf("a2")]), + td("b", vec![tld("../a", "alink")]), + ]); + let (_tmp, got) = dir_setup(&exp); + assert_tree_eq!(exp, got); +} + +#[test] +#[cfg(unix)] +fn walk_dir_sym_follow_dir() { + let actual = td("foo", vec![ + td("a", vec![tf("a1"), tf("a2")]), + td("b", vec![tld("../a", "alink")]), + ]); + let followed = td("foo", vec![ + td("a", vec![tf("a1"), tf("a2")]), + td("b", vec![td("alink", vec![tf("a1"), tf("a2")])]), + ]); + let (_tmp, got) = dir_setup_with(&actual, |wd| wd.follow_links(true)); + assert_tree_eq!(followed, got); +} + +#[test] +#[cfg(unix)] +fn walk_dir_sym_detect_loop() { + let actual = td("foo", vec![ + td("a", vec![tlf("../b", "blink"), tf("a1"), tf("a2")]), + td("b", vec![tlf("../a", "alink")]), + ]); + let tmp = tmpdir(); + actual.create_in(tmp.path()).unwrap(); + let got = WalkDir::new(tmp.path()) + .follow_links(true) + .into_iter() + .collect::<Result<Vec<_>, _>>(); + match got { + Ok(x) => panic!("expected loop error, got no error: {:?}", x), + Err(err @ Error { inner: ErrorInner::Io { .. }, .. }) => { + panic!("expected loop error, got generic IO error: {:?}", err); + } + Err(Error { inner: ErrorInner::Loop { .. }, .. }) => {} + } +} + +#[test] +fn walk_dir_sym_infinite() { + let actual = tlf("a", "a"); + let tmp = tmpdir(); + actual.create_in(tmp.path()).unwrap(); + let got = WalkDir::new(tmp.path()) + .follow_links(true) + .into_iter() + .collect::<Result<Vec<_>, _>>(); + match got { + Ok(x) => panic!("expected IO error, got no error: {:?}", x), + Err(Error { inner: ErrorInner::Loop { .. }, .. }) => { + panic!("expected IO error, but got loop error"); + } + Err(Error { inner: ErrorInner::Io { .. }, .. }) => {} + } +} + +#[test] +fn walk_dir_min_depth_1() { + let exp = td("foo", vec![tf("bar")]); + let (_tmp, got) = dir_setup_with(&exp, |wd| wd.min_depth(1)); + assert_tree_eq!(tf("bar"), got); +} + +#[test] +fn walk_dir_min_depth_2() { + let exp = td("foo", vec![tf("bar"), tf("baz")]); + let tmp = tmpdir(); + exp.create_in(tmp.path()).unwrap(); + let got = Tree::from_walk_with(tmp.path(), |wd| wd.min_depth(2)) + .unwrap().unwrap_dir(); + let got_cf = Tree::from_walk_with_contents_first( + tmp.path(), |wd| wd.min_depth(2)) + .unwrap().unwrap_dir(); + assert_eq!(got, got_cf); + assert_tree_eq!(exp, td("foo", got)); +} + +#[test] +fn walk_dir_min_depth_3() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("xyz")]), + tf("baz"), + ]); + let tmp = tmpdir(); + exp.create_in(tmp.path()).unwrap(); + let got = Tree::from_walk_with(tmp.path(), |wd| wd.min_depth(3)) + .unwrap().unwrap_dir(); + assert_eq!(vec![tf("xyz")], got); + let got_cf = Tree::from_walk_with_contents_first( + tmp.path(), |wd| wd.min_depth(3)) + .unwrap().unwrap_dir(); + assert_eq!(got, got_cf); +} + +#[test] +fn walk_dir_max_depth_1() { + let exp = td("foo", vec![tf("bar")]); + let (_tmp, got) = dir_setup_with(&exp, |wd| wd.max_depth(1)); + assert_tree_eq!(td("foo", vec![]), got); +} + +#[test] +fn walk_dir_max_depth_2() { + let exp = td("foo", vec![tf("bar"), tf("baz")]); + let (_tmp, got) = dir_setup_with(&exp, |wd| wd.max_depth(1)); + assert_tree_eq!(td("foo", vec![]), got); +} + +#[test] +fn walk_dir_max_depth_3() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("xyz")]), + tf("baz"), + ]); + let exp_trimmed = td("foo", vec![ + tf("bar"), + td("abc", vec![]), + tf("baz"), + ]); + let (_tmp, got) = dir_setup_with(&exp, |wd| wd.max_depth(2)); + assert_tree_eq!(exp_trimmed, got); +} + +#[test] +fn walk_dir_min_max_depth() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("xyz")]), + tf("baz"), + ]); + let tmp = tmpdir(); + exp.create_in(tmp.path()).unwrap(); + let got = Tree::from_walk_with(tmp.path(), + |wd| wd.min_depth(2).max_depth(2)) + .unwrap().unwrap_dir(); + let got_cf = Tree::from_walk_with_contents_first(tmp.path(), + |wd| wd.min_depth(2).max_depth(2)) + .unwrap().unwrap_dir(); + assert_eq!(got, got_cf); + assert_tree_eq!( + td("foo", vec![tf("bar"), td("abc", vec![]), tf("baz")]), + td("foo", got)); +} + +#[test] +fn walk_dir_skip() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("xyz")]), + tf("baz"), + ]); + let tmp = tmpdir(); + exp.create_in(tmp.path()).unwrap(); + let mut got = vec![]; + let mut it = WalkDir::new(tmp.path()).min_depth(1).into_iter(); + loop { + let dent = match it.next().map(|x| x.unwrap()) { + None => break, + Some(dent) => dent, + }; + let name = dent.file_name().to_str().unwrap().to_owned(); + if name == "abc" { + it.skip_current_dir(); + } + got.push(name); + } + got.sort(); + assert_eq!(got, vec!["abc", "bar", "baz", "foo"]); // missing xyz! +} + +#[test] +fn walk_dir_filter() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("fit")]), + tf("faz"), + ]); + let tmp = tmpdir(); + let tmp_path = tmp.path().to_path_buf(); + exp.create_in(tmp.path()).unwrap(); + let it = WalkDir::new(tmp.path()).min_depth(1) + .into_iter() + .filter_entry(move |d| { + let n = d.file_name().to_string_lossy().into_owned(); + !d.file_type().is_dir() + || n.starts_with("f") + || d.path() == &*tmp_path + }); + let mut got = it.map(|d| d.unwrap().file_name().to_str().unwrap().into()) + .collect::<Vec<String>>(); + got.sort(); + assert_eq!(got, vec!["bar", "faz", "foo"]); +} + +#[test] +fn qc_roundtrip() { + fn p(exp: Tree) -> bool { + let (_tmp, got) = dir_setup(&exp); + exp.canonical() == got.canonical() + } + QuickCheck::new() + .gen(StdGen::new(rand::thread_rng(), 15)) + .tests(1_000) + .max_tests(10_000) + .quickcheck(p as fn(Tree) -> bool); +} + +// Same as `qc_roundtrip`, but makes sure `follow_links` doesn't change +// the behavior of walking a directory *without* symlinks. +#[test] +fn qc_roundtrip_no_symlinks_with_follow() { + fn p(exp: Tree) -> bool { + let (_tmp, got) = dir_setup_with(&exp, |wd| wd.follow_links(true)); + exp.canonical() == got.canonical() + } + QuickCheck::new() + .gen(StdGen::new(rand::thread_rng(), 15)) + .tests(1_000) + .max_tests(10_000) + .quickcheck(p as fn(Tree) -> bool); +} + +#[test] +fn walk_dir_sort() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("fit")]), + tf("faz"), + ]); + let tmp = tmpdir(); + let tmp_path = tmp.path(); + let tmp_len = tmp_path.to_str().unwrap().len(); + exp.create_in(tmp_path).unwrap(); + let it = WalkDir::new(tmp_path) + .sort_by(|a,b| a.file_name().cmp(b.file_name())) + .into_iter(); + let got = it.map(|d| { + let path = d.unwrap(); + let path = &path.path().to_str().unwrap()[tmp_len..]; + path.replace("\\", "/") + }).collect::<Vec<String>>(); + assert_eq!( + got, + ["", "/foo", "/foo/abc", "/foo/abc/fit", "/foo/bar", "/foo/faz"]); +} + +#[test] +fn walk_dir_sort_small_fd_max() { + let exp = td("foo", vec![ + tf("bar"), + td("abc", vec![tf("fit")]), + tf("faz"), + ]); + let tmp = tmpdir(); + let tmp_path = tmp.path(); + let tmp_len = tmp_path.to_str().unwrap().len(); + exp.create_in(tmp_path).unwrap(); + let it = WalkDir::new(tmp_path) + .max_open(1) + .sort_by(|a,b| a.file_name().cmp(b.file_name())) + .into_iter(); + let got = it.map(|d| { + let path = d.unwrap(); + let path = &path.path().to_str().unwrap()[tmp_len..]; + path.replace("\\", "/") + }).collect::<Vec<String>>(); + assert_eq!( + got, + ["", "/foo", "/foo/abc", "/foo/abc/fit", "/foo/bar", "/foo/faz"]); +} + +#[test] +fn walk_dir_send_sync_traits() { + use FilterEntry; + + fn assert_send<T: Send>() {} + fn assert_sync<T: Sync>() {} + + assert_send::<WalkDir>(); + assert_sync::<WalkDir>(); + assert_send::<IntoIter>(); + assert_sync::<IntoIter>(); + assert_send::<FilterEntry<IntoIter, u8>>(); + assert_sync::<FilterEntry<IntoIter, u8>>(); +} + +// We cannot mount different volumes for the sake of the test, but +// on Linux systems we can assume that /sys is a mounted volume. +#[test] +#[cfg(target_os = "linux")] +fn walk_dir_stay_on_file_system() { + // If for some reason /sys doesn't exist or isn't a directory, just skip + // this test. + if !Path::new("/sys").is_dir() { + return; + } + + let actual = td("same_file", vec![ + td("a", vec![tld("/sys", "alink")]), + ]); + let unfollowed = td("same_file", vec![ + td("a", vec![tld("/sys", "alink")]), + ]); + let (_tmp, got) = dir_setup_with(&actual, |wd| wd); + assert_tree_eq!(unfollowed, got); + + // Create a symlink to sys and enable following symlinks. If the + // same_file_system option doesn't work, then this probably will hit a + // permission error. Otherwise, it should just skip over the symlink + // completely. + let actual = td("same_file", vec![ + td("a", vec![tld("/sys", "alink")]), + ]); + let followed = td("same_file", vec![ + td("a", vec![td("alink", vec![])]), + ]); + let (_tmp, got) = dir_setup_with(&actual, |wd| { + wd.follow_links(true).same_file_system(true) + }); + assert_tree_eq!(followed, got); +} + diff --git a/walkdir/src/unix.rs b/walkdir/src/unix.rs new file mode 100644 index 000000000..fb1842caf --- /dev/null +++ b/walkdir/src/unix.rs @@ -0,0 +1,16 @@ +use DirEntry; + +/// Unix-specific extension methods for `walkdir::DirEntry` +pub trait DirEntryExt { + /// Returns the underlying `d_ino` field in the contained `dirent` + /// structure. + fn ino(&self) -> u64; +} + +impl DirEntryExt for DirEntry { + /// Returns the underlying `d_ino` field in the contained `dirent` + /// structure. + fn ino(&self) -> u64 { + self.ino + } +} diff --git a/winapi-i686-pc-windows-gnu/.cargo-checksum.json b/winapi-i686-pc-windows-gnu/.cargo-checksum.json new file mode 100644 index 000000000..001dd9402 --- /dev/null +++ b/winapi-i686-pc-windows-gnu/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"} \ No newline at end of file diff --git a/winapi-i686-pc-windows-gnu/Cargo.toml b/winapi-i686-pc-windows-gnu/Cargo.toml new file mode 100644 index 000000000..e3bd0c6be --- /dev/null +++ b/winapi-i686-pc-windows-gnu/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +authors = ["Peter Atashian <retep998@gmail.com>"] +build = "build.rs" +include = ["src/*", "lib/*", "Cargo.toml", "build.rs"] +description = "Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead." +keywords = ["windows"] +license = "MIT/Apache-2.0" +repository = "https://github.com/retep998/winapi-rs" diff --git a/winapi-i686-pc-windows-gnu/build.rs b/winapi-i686-pc-windows-gnu/build.rs new file mode 100644 index 000000000..7130b307e --- /dev/null +++ b/winapi-i686-pc-windows-gnu/build.rs @@ -0,0 +1,18 @@ +// Copyright © 2016-2018 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +fn main() { + use std::env::var; + use std::path::Path; + println!("cargo:rerun-if-env-changed=WINAPI_NO_BUNDLED_LIBRARIES"); + if var("WINAPI_NO_BUNDLED_LIBRARIES").is_ok() { + return; + } + if var("TARGET").map(|target| target == "i686-pc-windows-gnu").unwrap_or(false) { + let dir = var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo:rustc-link-search=native={}", Path::new(&dir).join("lib").display()); + } +} diff --git a/winapi-i686-pc-windows-gnu/src/lib.rs b/winapi-i686-pc-windows-gnu/src/lib.rs new file mode 100644 index 000000000..3b7f827d8 --- /dev/null +++ b/winapi-i686-pc-windows-gnu/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright © 2016 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +#![no_std] diff --git a/winapi-util/.cargo-checksum.json b/winapi-util/.cargo-checksum.json new file mode 100644 index 000000000..7b1fe1d23 --- /dev/null +++ b/winapi-util/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"} \ No newline at end of file diff --git a/winapi-util/COPYING b/winapi-util/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/winapi-util/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/winapi-util/Cargo.toml b/winapi-util/Cargo.toml new file mode 100644 index 000000000..d6a7b7494 --- /dev/null +++ b/winapi-util/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "winapi-util" +version = "0.1.2" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +description = "A dumping ground for high level safe wrappers over winapi." +homepage = "https://github.com/BurntSushi/winapi-util" +documentation = "https://docs.rs/winapi-util" +readme = "README.md" +keywords = ["windows", "winapi", "util", "win"] +categories = ["os::windows-apis", "external-ffi-bindings"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/winapi-util" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["std", "consoleapi", "errhandlingapi", "fileapi", "minwindef", "processenv", "winbase", "wincon", "winerror", "winnt"] diff --git a/winapi-util/LICENSE-MIT b/winapi-util/LICENSE-MIT new file mode 100644 index 000000000..3303149e5 --- /dev/null +++ b/winapi-util/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/winapi-util/README.md b/winapi-util/README.md new file mode 100644 index 000000000..145eede1a --- /dev/null +++ b/winapi-util/README.md @@ -0,0 +1,51 @@ +winapi-util +=========== +This crate provides a smattering of safe wrappers around various parts of the +[winapi](https://crates.io/crates/winapi) crate. + +[![Linux build status](https://api.travis-ci.org/BurntSushi/winapi-util.png)](https://travis-ci.org/BurntSushi/winapi-util) +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/winapi-util?svg=true)](https://ci.appveyor.com/project/BurntSushi/winapi-util) +[![](http://meritbadge.herokuapp.com/winapi-util)](https://crates.io/crates/winapi-util) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/winapi-util + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +winapi-util = "0.1" +``` + +and this to your crate root: + +```rust +extern crate winapi_util; +``` + + +### Notes + +This crate was born out of frustration with having to write lots of little +ffi utility bindings in a variety of crates in order to get Windows support. +Eventually, I started needing to copy & paste a lot of those utility routines. +Since they are utility routines, they often don't make sense to expose directly +in the crate in which they are defined. Instead of continuing this process, +I decided to make a crate instead. + +Normally, I'm not a huge fan of "utility" crates like this that don't have a +well defined scope, but this is primarily a practical endeavor to make it +easier to isolate Windows specific ffi code. + +While I don't have a long term vision for this crate, I will welcome additional +PRs that add more high level routines/types on an as-needed basis. + +**WARNING:** I am not a Windows developer, so extra review to make sure I've +got things right is most appreciated. diff --git a/winapi-util/UNLICENSE b/winapi-util/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/winapi-util/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/winapi-util/appveyor.yml b/winapi-util/appveyor.yml new file mode 100644 index 000000000..9fdcaa8f1 --- /dev/null +++ b/winapi-util/appveyor.yml @@ -0,0 +1,26 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + BITS: 64 + MSYS2: 1 + - TARGET: x86_64-pc-windows-msvc + BITS: 64 + - TARGET: i686-pc-windows-gnu + BITS: 32 + MSYS2: 1 + - TARGET: i686-pc-windows-msvc + BITS: 32 +install: + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH% + - rustc -V + - cargo -V +build: false +test_script: + - cargo build --verbose --all + - cargo test --verbose --all +branches: + only: + - master diff --git a/winapi-util/ci/script.sh b/winapi-util/ci/script.sh new file mode 100755 index 000000000..90243df3d --- /dev/null +++ b/winapi-util/ci/script.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -ex + +cargo build --verbose --all +cargo doc --verbose --all +cargo test --verbose --all diff --git a/winapi-util/src/console.rs b/winapi-util/src/console.rs new file mode 100644 index 000000000..1f7dad8bd --- /dev/null +++ b/winapi-util/src/console.rs @@ -0,0 +1,121 @@ +use std::io; +use std::mem; + +use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; +use winapi::um::wincon::{ + CONSOLE_SCREEN_BUFFER_INFO, + GetConsoleScreenBufferInfo, SetConsoleTextAttribute, +}; + +use AsHandleRef; + +/// Query the given handle for information about the console's screen buffer. +/// +/// The given handle should represent a console. Otherwise, an error is +/// returned. +/// +/// This corresponds to calling [`GetConsoleScreenBufferInfo`]. +/// +/// [`GetConsoleScreenBufferInfo`]: https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo +pub fn screen_buffer_info<H: AsHandleRef>( + h: H, +) -> io::Result<ScreenBufferInfo> { + unsafe { + let mut info: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed(); + let rc = GetConsoleScreenBufferInfo(h.as_raw(), &mut info); + if rc == 0 { + return Err(io::Error::last_os_error()); + } + Ok(ScreenBufferInfo(info)) + } +} + +/// Set the text attributes of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleTextAttribute`]. +/// +/// [`SetConsoleTextAttribute`]: https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute +pub fn set_text_attributes<H: AsHandleRef>( + h: H, + attributes: u16, +) -> io::Result<()> { + if unsafe { SetConsoleTextAttribute(h.as_raw(), attributes) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Query the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`GetConsoleMode`], which describes the return +/// value. +/// +/// [`GetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/getconsolemode +pub fn mode<H: AsHandleRef>(h: H) -> io::Result<u32> { + let mut mode = 0; + if unsafe { GetConsoleMode(h.as_raw(), &mut mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(mode) + } +} + +/// Set the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleMode`], which describes the format +/// of the mode parameter. +/// +/// [`SetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/setconsolemode +pub fn set_mode<H: AsHandleRef>(h: H, mode: u32) -> io::Result<()> { + if unsafe { SetConsoleMode(h.as_raw(), mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Represents console screen buffer information such as size, cursor position +/// and styling attributes. +/// +/// This wraps a [`CONSOLE_SCREEN_BUFFER_INFO`]. +/// +/// [`CONSOLE_SCREEN_BUFFER_INFO`]: https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str +#[derive(Clone)] +pub struct ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO); + +impl ScreenBufferInfo { + /// Returns the size of the console screen buffer, in character columns and + /// rows. + /// + /// This corresponds to `dwSize`. + pub fn size(&self) -> (i16, i16) { + (self.0.dwSize.X, self.0.dwSize.Y) + } + + /// Returns the position of the cursor in terms of column and row + /// coordinates of the console screen buffer. + /// + /// This corresponds to `dwCursorPosition`. + pub fn cursor_position(&self) -> (i16, i16) { + (self.0.dwCursorPosition.X, self.0.dwCursorPosition.Y) + } + + /// Returns the character attributes associated with this console. + /// + /// This corresponds to `wAttributes`. + /// + /// See [`char info`] for more details. + /// + /// [`char info`]: https://docs.microsoft.com/en-us/windows/console/char-info-str + pub fn attributes(&self) -> u16 { + self.0.wAttributes + } + + /// Returns the maximum size of the console window, in character columns + /// and rows, given the current screen buffer size and font and the screen + /// size. + pub fn max_window_size(&self) -> (i16, i16) { + (self.0.dwMaximumWindowSize.X, self.0.dwMaximumWindowSize.Y) + } +} diff --git a/winapi-util/src/file.rs b/winapi-util/src/file.rs new file mode 100644 index 000000000..99f7981b5 --- /dev/null +++ b/winapi-util/src/file.rs @@ -0,0 +1,171 @@ +use std::io; +use std::mem; + +use winapi::shared::minwindef::FILETIME; +use winapi::shared::winerror::NO_ERROR; +use winapi::um::errhandlingapi::GetLastError; +use winapi::um::fileapi::{ + BY_HANDLE_FILE_INFORMATION, + GetFileInformationByHandle, GetFileType, +}; +use winapi::um::winnt; + +use AsHandleRef; + +/// Return various pieces of information about a file. +/// +/// This includes information such as a file's size, unique identifier and +/// time related fields. +/// +/// This corresponds to calling [`GetFileInformationByHandle`]. +/// +/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle +pub fn information<H: AsHandleRef>( + h: H, +) -> io::Result<Information> { + unsafe { + let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed(); + let rc = GetFileInformationByHandle(h.as_raw(), &mut info); + if rc == 0 { + return Err(io::Error::last_os_error()); + }; + Ok(Information(info)) + } +} + +/// Returns the file type of the given handle. +/// +/// If there was a problem querying the file type, then an error is returned. +/// +/// This corresponds to calling [`GetFileType`]. +/// +/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype +pub fn typ<H: AsHandleRef>(h: H) -> io::Result<Type> { + unsafe { + let rc = GetFileType(h.as_raw()); + if rc == 0 && GetLastError() != NO_ERROR { + return Err(io::Error::last_os_error()); + } + Ok(Type(rc)) + } +} + +/// Returns true if and only if the given file attributes contain the +/// `FILE_ATTRIBUTE_HIDDEN` attribute. +pub fn is_hidden(file_attributes: u64) -> bool { + file_attributes & (winnt::FILE_ATTRIBUTE_HIDDEN as u64) > 0 +} + +/// Represents file information such as creation time, file size, etc. +/// +/// This wraps a [`BY_HANDLE_FILE_INFORMATION`]. +/// +/// [`BY_HANDLE_FILE_INFORMATION`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information +#[derive(Clone)] +pub struct Information(BY_HANDLE_FILE_INFORMATION); + +impl Information { + /// Returns file attributes. + /// + /// This corresponds to `dwFileAttributes`. + pub fn file_attributes(&self) -> u64 { + self.0.dwFileAttributes as u64 + } + + /// Returns true if and only if this file information has the + /// `FILE_ATTRIBUTE_HIDDEN` attribute. + pub fn is_hidden(&self) -> bool { + is_hidden(self.file_attributes()) + } + + /// Return the creation time, if one exists. + /// + /// This corresponds to `ftCreationTime`. + pub fn creation_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftCreationTime) + } + + /// Return the last access time, if one exists. + /// + /// This corresponds to `ftLastAccessTime`. + pub fn last_access_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftLastAccessTime) + } + + /// Return the last write time, if one exists. + /// + /// This corresponds to `ftLastWriteTime`. + pub fn last_write_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftLastWriteTime) + } + + /// Return the serial number of the volume that the file is on. + /// + /// This corresponds to `dwVolumeSerialNumber`. + pub fn volume_serial_number(&self) -> u64 { + self.0.dwVolumeSerialNumber as u64 + } + + /// Return the file size, in bytes. + /// + /// This corresponds to `nFileSizeHigh` and `nFileSizeLow`. + pub fn file_size(&self) -> u64 { + ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64) + } + + /// Return the number of links to this file. + /// + /// This corresponds to `nNumberOfLinks`. + pub fn number_of_links(&self) -> u64 { + self.0.nNumberOfLinks as u64 + } + + /// Return the index of this file. The index of a file is a purpotedly + /// unique identifier for a file within a particular volume. + pub fn file_index(&self) -> u64 { + ((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64) + } +} + +/// Represents a Windows file type. +/// +/// This wraps the result of [`GetFileType`]. +/// +/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype +#[derive(Clone)] +pub struct Type(u32); + +impl Type { + /// Returns true if this type represents a character file, which is + /// typically an LPT device or a console. + pub fn is_char(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_CHAR + } + + /// Returns true if this type represents a disk file. + pub fn is_disk(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_DISK + } + + /// Returns true if this type represents a sock, named pipe or an + /// anonymous pipe. + pub fn is_pipe(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_PIPE + } + + /// Returns true if this type is not known. + /// + /// Note that this never corresponds to a failure. + pub fn is_unknown(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_UNKNOWN + } +} + +fn filetime_to_u64(t: FILETIME) -> Option<u64> { + let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64); + if v == 0 { + None + } else { + Some(v) + } +} diff --git a/winapi-util/src/lib.rs b/winapi-util/src/lib.rs new file mode 100644 index 000000000..a2864e1d0 --- /dev/null +++ b/winapi-util/src/lib.rs @@ -0,0 +1,35 @@ +/*! +This crate provides a smattering of safe routines for parts of winapi. The +primary purpose of this crate is to serve as a dumping ground for various +utility functions that make interactions with winapi safe. This permits the +centralization of `unsafe` when dealing with Windows APIs, and thus makes it +easier to audit. + +A key abstraction in this crate is the combination of the +[`Handle`](struct.Handle.html) +and +[`HandleRef`](struct.HandleRef.html) +types. Both represent a valid Windows handle to an I/O-like object, where +`Handle` is owned (the resource is closed when the handle is dropped) and +`HandleRef` is borrowed (the resource is not closed when the handle is +dropped). Many of the routines in this crate work on handles and accept +anything that can be safely converted into a `HandleRef`. This includes +standard library types such as `File`, `Stdin`, `Stdout` and `Stderr`. + +Note that this crate is completely empty on non-Windows platforms. +*/ + +#[cfg(windows)] +extern crate winapi; + +#[cfg(windows)] +pub use win::*; + +/// Safe routines for dealing with the Windows console. +#[cfg(windows)] +pub mod console; +/// Safe routines for dealing with files and handles on Windows. +#[cfg(windows)] +pub mod file; +#[cfg(windows)] +mod win; diff --git a/winapi-util/src/win.rs b/winapi-util/src/win.rs new file mode 100644 index 000000000..490534b99 --- /dev/null +++ b/winapi-util/src/win.rs @@ -0,0 +1,247 @@ +use std::fs::File; +use std::io; +use std::os::windows::io::{ + RawHandle, + AsRawHandle, FromRawHandle, IntoRawHandle, +}; +use std::path::Path; +use std::process; + +/// A handle represents an owned and valid Windows handle to a file-like +/// object. +/// +/// When an owned handle is dropped, then the underlying raw handle is closed. +/// To get a borrowed handle, use `HandleRef`. +#[derive(Debug)] +pub struct Handle(File); + +impl AsRawHandle for Handle { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() + } +} + +impl FromRawHandle for Handle { + unsafe fn from_raw_handle(handle: RawHandle) -> Handle { + Handle(File::from_raw_handle(handle)) + } +} + +impl IntoRawHandle for Handle { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} + +impl Handle { + /// Create an owned handle to the given file. + /// + /// When the returned handle is dropped, the file is closed. + /// + /// Note that if the given file represents a handle to a directory, then + /// it is generally required that it have been opened with the + /// [`FILE_FLAG_BACKUP_SEMANTICS`] flag in order to use it in various + /// calls such as `information` or `typ`. To have this done automatically + /// for you, use the `from_path_any` constructor. + /// + /// [`FILE_FLAG_BACKUP_SEMANTICS`]: https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-createfilea + pub fn from_file(file: File) -> Handle { + Handle(file) + } + + /// Open a file to the given file path, and return an owned handle to that + /// file. + /// + /// When the returned handle is dropped, the file is closed. + /// + /// If there was a problem opening the file, then the corresponding error + /// is returned. + pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Handle> { + Ok(Handle::from_file(File::open(path)?)) + } + + /// Like `from_path`, but supports opening directory handles as well. + /// + /// If you use `from_path` on a directory, then subsequent queries using + /// that handle will fail. + pub fn from_path_any<P: AsRef<Path>>(path: P) -> io::Result<Handle> { + use std::fs::OpenOptions; + use std::os::windows::fs::OpenOptionsExt; + use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; + + let file = OpenOptions::new() + .read(true) + .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) + .open(path)?; + Ok(Handle::from_file(file)) + } + + /// Return this handle as a standard `File` reference. + pub fn as_file(&self) -> &File { + &self.0 + } + + /// Return this handle as a standard `File` mutable reference. + pub fn as_file_mut(&mut self) -> &mut File { + &mut self.0 + } +} + +/// Represents a borrowed and valid Windows handle to a file-like object, such +/// as stdin/stdout/stderr or an actual file. +/// +/// When a borrowed handle is dropped, then the underlying raw handle is +/// **not** closed. To get an owned handle, use `Handle`. +#[derive(Debug)] +pub struct HandleRef(HandleRefInner); + +/// The representation of a HandleRef, on which we define a custom Drop impl +/// that avoids closing the underlying raw handle. +#[derive(Debug)] +struct HandleRefInner(Option<File>); + +impl Drop for HandleRefInner { + fn drop(&mut self) { + self.0.take().unwrap().into_raw_handle(); + } +} + +impl AsRawHandle for HandleRef { + fn as_raw_handle(&self) -> RawHandle { + self.as_file().as_raw_handle() + } +} + +impl Clone for HandleRef { + fn clone(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl HandleRef { + /// Create a borrowed handle to stdin. + /// + /// When the returned handle is dropped, stdin is not closed. + pub fn stdin() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stdin().as_raw_handle()) } + } + + /// Create a handle to stdout. + /// + /// When the returned handle is dropped, stdout is not closed. + pub fn stdout() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stdout().as_raw_handle()) } + } + + /// Create a handle to stderr. + /// + /// When the returned handle is dropped, stderr is not closed. + pub fn stderr() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stderr().as_raw_handle()) } + } + + /// Create a borrowed handle to the given file. + /// + /// When the returned handle is dropped, the file is not closed. + pub fn from_file(file: &File) -> HandleRef { + unsafe { HandleRef::from_raw_handle(file.as_raw_handle()) } + } + + /// Create a borrowed handle from the given raw handle. + /// + /// Note that unlike the `FromRawHandle` trait, this constructor does + /// **not** consume ownership of the given handle. That is, when the + /// borrowed handle created by this constructor is dropped, the underlying + /// handle will not be closed. + /// + /// # Safety + /// + /// This is unsafe because there is no guarantee that the given raw handle + /// is a valid handle. The caller must ensure this is true before invoking + /// this constructor. + pub unsafe fn from_raw_handle(handle: RawHandle) -> HandleRef { + HandleRef(HandleRefInner(Some(File::from_raw_handle(handle)))) + } + + /// Return this handle as a standard `File` reference. + pub fn as_file(&self) -> &File { + (self.0).0.as_ref().unwrap() + } + + /// Return this handle as a standard `File` mutable reference. + pub fn as_file_mut(&mut self) -> &mut File { + (self.0).0.as_mut().unwrap() + } +} + +/// Construct borrowed and valid Windows handles from file-like objects. +pub trait AsHandleRef { + /// A borrowed handle that wraps the raw handle of the `Self` object. + fn as_handle_ref(&self) -> HandleRef; + + /// A convenience routine for extracting a `HandleRef` from `Self`, and + /// then extracting a raw handle from the `HandleRef`. + fn as_raw(&self) -> RawHandle { + self.as_handle_ref().as_raw_handle() + } +} + +impl<'a, T: AsHandleRef> AsHandleRef for &'a T { + fn as_handle_ref(&self) -> HandleRef { + (**self).as_handle_ref() + } +} + +impl AsHandleRef for Handle { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for HandleRef { + fn as_handle_ref(&self) -> HandleRef { + self.clone() + } +} + +impl AsHandleRef for File { + fn as_handle_ref(&self) -> HandleRef { + HandleRef::from_file(self) + } +} + +impl AsHandleRef for io::Stdin { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for io::Stdout { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for io::Stderr { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStdin { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStdout { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStderr { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} diff --git a/winapi-x86_64-pc-windows-gnu/.cargo-checksum.json b/winapi-x86_64-pc-windows-gnu/.cargo-checksum.json new file mode 100644 index 000000000..030fa956a --- /dev/null +++ b/winapi-x86_64-pc-windows-gnu/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"} \ No newline at end of file diff --git a/winapi-x86_64-pc-windows-gnu/Cargo.toml b/winapi-x86_64-pc-windows-gnu/Cargo.toml new file mode 100644 index 000000000..7e1341b08 --- /dev/null +++ b/winapi-x86_64-pc-windows-gnu/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +authors = ["Peter Atashian <retep998@gmail.com>"] +build = "build.rs" +include = ["src/*", "lib/*", "Cargo.toml", "build.rs"] +description = "Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead." +keywords = ["windows"] +license = "MIT/Apache-2.0" +repository = "https://github.com/retep998/winapi-rs" diff --git a/winapi-x86_64-pc-windows-gnu/build.rs b/winapi-x86_64-pc-windows-gnu/build.rs new file mode 100644 index 000000000..a655b7c9e --- /dev/null +++ b/winapi-x86_64-pc-windows-gnu/build.rs @@ -0,0 +1,18 @@ +// Copyright © 2016-2018 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +fn main() { + use std::env::var; + use std::path::Path; + println!("cargo:rerun-if-env-changed=WINAPI_NO_BUNDLED_LIBRARIES"); + if var("WINAPI_NO_BUNDLED_LIBRARIES").is_ok() { + return; + } + if var("TARGET").map(|target| target == "x86_64-pc-windows-gnu").unwrap_or(false) { + let dir = var("CARGO_MANIFEST_DIR").unwrap(); + println!("cargo:rustc-link-search=native={}", Path::new(&dir).join("lib").display()); + } +} diff --git a/winapi-x86_64-pc-windows-gnu/src/lib.rs b/winapi-x86_64-pc-windows-gnu/src/lib.rs new file mode 100644 index 000000000..3b7f827d8 --- /dev/null +++ b/winapi-x86_64-pc-windows-gnu/src/lib.rs @@ -0,0 +1,7 @@ +// Copyright © 2016 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +#![no_std] diff --git a/winapi/.cargo-checksum.json b/winapi/.cargo-checksum.json new file mode 100644 index 000000000..2d08fc403 --- /dev/null +++ b/winapi/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"} \ No newline at end of file diff --git a/winapi/Cargo.toml b/winapi/Cargo.toml new file mode 100644 index 000000000..0404dada7 --- /dev/null +++ b/winapi/Cargo.toml @@ -0,0 +1,402 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "winapi" +version = "0.3.7" +authors = ["Peter Atashian <retep998@gmail.com>"] +build = "build.rs" +include = ["/src/**/*", "/Cargo.toml", "/LICENSE-MIT", "/LICENSE-APACHE", "/build.rs", "/README.md"] +description = "Raw FFI bindings for all of Windows API." +documentation = "https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/" +readme = "README.md" +keywords = ["windows", "ffi", "win32", "com", "directx"] +categories = ["external-ffi-bindings", "no-std", "os::windows-apis"] +license = "MIT/Apache-2.0" +repository = "https://github.com/retep998/winapi-rs" +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +features = ["everything", "impl-debug", "impl-default"] + +[features] +accctrl = [] +aclapi = [] +activation = [] +appmgmt = [] +audioclient = [] +audiosessiontypes = [] +avrt = [] +basetsd = [] +bcrypt = [] +bits = [] +bits10_1 = [] +bits1_5 = [] +bits2_0 = [] +bits2_5 = [] +bits3_0 = [] +bits4_0 = [] +bits5_0 = [] +bitscfg = [] +bitsmsg = [] +bugcodes = [] +cderr = [] +cfg = [] +cfgmgr32 = [] +cguid = [] +combaseapi = [] +coml2api = [] +commapi = [] +commctrl = [] +commdlg = [] +commoncontrols = [] +consoleapi = [] +corsym = [] +d2d1 = [] +d2d1_1 = [] +d2d1_2 = [] +d2d1_3 = [] +d2d1effectauthor = [] +d2d1effects = [] +d2d1effects_1 = [] +d2d1effects_2 = [] +d2d1svg = [] +d2dbasetypes = [] +d3d = [] +d3d10 = [] +d3d10_1 = [] +d3d10_1shader = [] +d3d10effect = [] +d3d10misc = [] +d3d10sdklayers = [] +d3d10shader = [] +d3d11 = [] +d3d11_1 = [] +d3d11_2 = [] +d3d11_3 = [] +d3d11_4 = [] +d3d11on12 = [] +d3d11sdklayers = [] +d3d11shader = [] +d3d11tokenizedprogramformat = [] +d3d12 = [] +d3d12sdklayers = [] +d3d12shader = [] +d3d9 = [] +d3d9caps = [] +d3d9types = [] +d3dcommon = [] +d3dcompiler = [] +d3dcsx = [] +d3dkmdt = [] +d3dkmthk = [] +d3dukmdt = [] +d3dx10core = [] +d3dx10math = [] +d3dx10mesh = [] +datetimeapi = [] +davclnt = [] +dbghelp = [] +dbt = [] +dcommon = [] +dcomp = [] +dcompanimation = [] +dcomptypes = [] +dde = [] +ddraw = [] +ddrawi = [] +ddrawint = [] +debug = ["impl-debug"] +debugapi = [] +devguid = [] +devicetopology = [] +devpkey = [] +devpropdef = [] +dinput = [] +dinputd = [] +dispex = [] +dmksctl = [] +dmusicc = [] +docobj = [] +documenttarget = [] +dpa_dsa = [] +dpapi = [] +dsgetdc = [] +dsound = [] +dsrole = [] +dvp = [] +dwmapi = [] +dwrite = [] +dwrite_1 = [] +dwrite_2 = [] +dwrite_3 = [] +dxdiag = [] +dxfile = [] +dxgi = [] +dxgi1_2 = [] +dxgi1_3 = [] +dxgi1_4 = [] +dxgi1_5 = [] +dxgi1_6 = [] +dxgidebug = [] +dxgiformat = [] +dxgitype = [] +dxva2api = [] +dxvahd = [] +enclaveapi = [] +endpointvolume = [] +errhandlingapi = [] +everything = [] +evntcons = [] +evntprov = [] +evntrace = [] +excpt = [] +exdisp = [] +fibersapi = [] +fileapi = [] +gl-gl = [] +guiddef = [] +handleapi = [] +heapapi = [] +hidclass = [] +hidpi = [] +hidsdi = [] +hidusage = [] +highlevelmonitorconfigurationapi = [] +hstring = [] +http = [] +ifdef = [] +imm = [] +impl-debug = [] +impl-default = [] +in6addr = [] +inaddr = [] +inspectable = [] +interlockedapi = [] +intsafe = [] +ioapiset = [] +jobapi = [] +jobapi2 = [] +knownfolders = [] +ks = [] +ksmedia = [] +ktmtypes = [] +ktmw32 = [] +libloaderapi = [] +limits = [] +lmaccess = [] +lmalert = [] +lmapibuf = [] +lmat = [] +lmcons = [] +lmdfs = [] +lmerrlog = [] +lmjoin = [] +lmmsg = [] +lmremutl = [] +lmrepl = [] +lmserver = [] +lmshare = [] +lmstats = [] +lmsvc = [] +lmuse = [] +lmwksta = [] +lowlevelmonitorconfigurationapi = [] +lsalookup = [] +memoryapi = [] +minschannel = [] +minwinbase = [] +minwindef = [] +mmdeviceapi = [] +mmeapi = [] +mmreg = [] +mmsystem = [] +msaatext = [] +mscat = [] +mschapp = [] +mssip = [] +mstcpip = [] +mswsock = [] +mswsockdef = [] +namedpipeapi = [] +namespaceapi = [] +nb30 = [] +ncrypt = [] +netioapi = [] +ntddscsi = [] +ntddser = [] +ntdef = [] +ntlsa = [] +ntsecapi = [] +ntstatus = [] +oaidl = [] +objbase = [] +objidl = [] +objidlbase = [] +ocidl = [] +ole2 = [] +oleauto = [] +olectl = [] +oleidl = [] +opmapi = [] +pdh = [] +perflib = [] +physicalmonitorenumerationapi = [] +playsoundapi = [] +portabledevice = [] +portabledeviceapi = [] +portabledevicetypes = [] +powerbase = [] +powersetting = [] +powrprof = [] +processenv = [] +processsnapshot = [] +processthreadsapi = [] +processtopologyapi = [] +profileapi = [] +propidl = [] +propkeydef = [] +propsys = [] +prsht = [] +psapi = [] +qos = [] +realtimeapiset = [] +reason = [] +restartmanager = [] +restrictederrorinfo = [] +rmxfguid = [] +roapi = [] +robuffer = [] +roerrorapi = [] +rpc = [] +rpcdce = [] +rpcndr = [] +sapi = [] +sapi51 = [] +sapi53 = [] +sapiddk = [] +sapiddk51 = [] +schannel = [] +sddl = [] +securityappcontainer = [] +securitybaseapi = [] +servprov = [] +setupapi = [] +shellapi = [] +shellscalingapi = [] +shlobj = [] +shobjidl = [] +shobjidl_core = [] +shtypes = [] +spapidef = [] +spellcheck = [] +sporder = [] +sql = [] +sqlext = [] +sqltypes = [] +sqlucode = [] +sspi = [] +std = [] +stralign = [] +stringapiset = [] +strmif = [] +subauth = [] +synchapi = [] +sysinfoapi = [] +systemtopologyapi = [] +taskschd = [] +textstor = [] +threadpoolapiset = [] +threadpoollegacyapiset = [] +timeapi = [] +timezoneapi = [] +tlhelp32 = [] +transportsettingcommon = [] +tvout = [] +unknwnbase = [] +urlhist = [] +urlmon = [] +usb = [] +usbiodef = [] +usbspec = [] +userenv = [] +usp10 = [] +utilapiset = [] +uxtheme = [] +vadefs = [] +vcruntime = [] +vsbackup = [] +vss = [] +vsserror = [] +vswriter = [] +wbemads = [] +wbemcli = [] +wbemdisp = [] +wbemprov = [] +wbemtran = [] +wct = [] +werapi = [] +winbase = [] +wincodec = [] +wincodecsdk = [] +wincon = [] +wincontypes = [] +wincred = [] +wincrypt = [] +windef = [] +windowsceip = [] +windowsx = [] +winefs = [] +winerror = [] +winevt = [] +wingdi = [] +winhttp = [] +wininet = [] +winineti = [] +winioctl = [] +winnetwk = [] +winnls = [] +winnt = [] +winreg = [] +winsafer = [] +winscard = [] +winsmcrd = [] +winsock2 = [] +winspool = [] +winstring = [] +winsvc = [] +winusb = [] +winusbio = [] +winuser = [] +winver = [] +wmistr = [] +wnnc = [] +wow64apiset = [] +wpdmtpextensions = [] +ws2def = [] +ws2ipdef = [] +ws2spi = [] +ws2tcpip = [] +wtypes = [] +wtypesbase = [] +xinput = [] +[target.i686-pc-windows-gnu.dependencies.winapi-i686-pc-windows-gnu] +version = "0.4" +[target.x86_64-pc-windows-gnu.dependencies.winapi-x86_64-pc-windows-gnu] +version = "0.4" +[badges.appveyor] +branch = "0.3" +repository = "retep998/winapi-rs" +service = "github" + +[badges.travis-ci] +branch = "0.3" +repository = "retep998/winapi-rs" diff --git a/winapi/LICENSE-APACHE b/winapi/LICENSE-APACHE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/winapi/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/winapi/LICENSE-MIT b/winapi/LICENSE-MIT new file mode 100644 index 000000000..6f1b4c850 --- /dev/null +++ b/winapi/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015-2018 The winapi-rs Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/winapi/README.md b/winapi/README.md new file mode 100644 index 000000000..0d8d39c61 --- /dev/null +++ b/winapi/README.md @@ -0,0 +1,89 @@ +# winapi-rs +[![Build status](https://ci.appveyor.com/api/projects/status/i47oonf5e7qm5utq/branch/0.3?svg=true)](https://ci.appveyor.com/project/retep998/winapi-rs/branch/0.3) +[![Build Status](https://travis-ci.org/retep998/winapi-rs.svg?branch=0.3)](https://travis-ci.org/retep998/winapi-rs) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/retep998/winapi-rs) +[![Crates.io](https://img.shields.io/crates/v/winapi.svg)](https://crates.io/crates/winapi) +![Lines of Code](https://tokei.rs/b1/github/retep998/winapi-rs) +![100% unsafe](https://img.shields.io/badge/unsafe-100%25-blue.svg) +[![Open issues](https://img.shields.io/github/issues-raw/retep998/winapi-rs.svg)](https://github.com/retep998/winapi-rs/issues) +[![License](https://img.shields.io/crates/l/winapi.svg)](https://github.com/retep998/winapi-rs) + + +[Documentation](https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/) + +Official IRC channel: #winapi on [Mozilla IRC](https://wiki.mozilla.org/IRC) + +This crate provides raw FFI bindings to all of Windows API. They are gathered by hand using the Windows 10 SDK from Microsoft. I aim to replace all existing Windows FFI in other crates with this crate through the "[Embrace, extend, and extinguish](http://en.wikipedia.org/wiki/Embrace,_extend_and_extinguish)" technique. + +If this crate is missing something you need, feel free to create an issue, open a pull request, or contact me via [other means](http://www.rustaceans.org/retep998). + +This crate depends on Rust 1.6 or newer on Windows. On other platforms this crate is a no-op and should compile with Rust 1.2 or newer. + +## Frequently asked questions ## + +### How do I create an instance of a union? + +Use `std::mem::zeroed()` to create an instance of the union, and then assign the value you want using one of the variant methods. + +### Why am I getting errors about unresolved imports? + +Each module is gated on a feature flag, so you must enable the appropriate feature to gain access to those items. For example, if you want to use something from `winapi::um::winuser` you must enable the `winuser` feature. + +### How do I know which module an item is defined in? + +You can use the search functionality in the [documentation](https://docs.rs/winapi/*/x86_64-pc-windows-msvc/winapi/) to find where items are defined. + +### Why is there no documentation on how to use anything? + +This crate is nothing more than raw bindings to Windows API. If you wish to know how to use the various functionality in Windows API, you can look up the various items on [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/aa906039) which is full of detailed documentation. + +### Can I use this library in `no_std` projects? + +Yes, absolutely! By default the `std` feature of `winapi` is disabled, allowing you to write Windows applications using nothing but `core` and `winapi`. + +### Why is `winapi`'s `HANDLE` incompatible with `std`'s `HANDLE`? + +Because `winapi` does not depend on `std` by default, it has to define `c_void` itself instead of using `std::os::raw::c_void`. However, if you enable the `std` feature of `winapi` then it will re-export `c_void` from `std` and cause `winapi`'s `HANDLE` to be the same type as `std`'s `HANDLE`. + +### Should I still use those `-sys` crates such as `kernel32-sys`? + +No. Those crates are a legacy of how `winapi` 0.2 was organized. Starting with `winapi` 0.3 all definitions are directly in `winapi` itself, and so there is no longer any need to use those `-sys` crates. + +## Example ## + +Cargo.toml: +```toml +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["winuser"] } +``` +main.rs: +```Rust +#[cfg(windows)] extern crate winapi; +use std::io::Error; + +#[cfg(windows)] +fn print_message(msg: &str) -> Result<i32, Error> { + use std::ffi::OsStr; + use std::iter::once; + use std::os::windows::ffi::OsStrExt; + use std::ptr::null_mut; + use winapi::um::winuser::{MB_OK, MessageBoxW}; + let wide: Vec<u16> = OsStr::new(msg).encode_wide().chain(once(0)).collect(); + let ret = unsafe { + MessageBoxW(null_mut(), wide.as_ptr(), wide.as_ptr(), MB_OK) + }; + if ret == 0 { Err(Error::last_os_error()) } + else { Ok(ret) } +} +#[cfg(not(windows))] +fn print_message(msg: &str) -> Result<(), Error> { + println!("{}", msg); + Ok(()) +} +fn main() { + print_message("Hello, world!").unwrap(); +} +``` + +## Financial Support +Do you use `winapi` in your projects? If so, you may be interested in financially supporting me on [Patreon](https://www.patreon.com/retep998). Companies in particular are especially encouraged to donate (I'm looking at you [Microsoft](https://github.com/Azure/iotedge/tree/master/edgelet)). diff --git a/winapi/build.rs b/winapi/build.rs new file mode 100644 index 000000000..036687d25 --- /dev/null +++ b/winapi/build.rs @@ -0,0 +1,488 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use std::cell::Cell; +use std::collections::HashMap; +use std::env::var; +// (header name, &[header dependencies], &[library dependencies]) +const DATA: &'static [(&'static str, &'static [&'static str], &'static [&'static str])] = &[ + // km + ("d3dkmthk", &["basetsd", "d3dukmdt", "minwindef", "ntdef", "windef"], &[]), + // mmos + // shared + ("basetsd", &[], &[]), + ("bcrypt", &["minwindef", "winnt"], &["bcrypt"]), + ("bugcodes", &["ntdef"], &[]), + ("cderr", &["minwindef"], &[]), + ("cfg", &["minwindef"], &[]), + ("d3d9", &["basetsd", "d3d9caps", "d3d9types", "guiddef", "minwindef", "unknwnbase", "windef", "wingdi", "winnt"], &["d3d9"]), + ("d3d9caps", &["d3d9types", "guiddef", "minwindef", "winnt"], &[]), + ("d3d9types", &["basetsd", "guiddef", "minwindef", "windef", "winnt"], &[]), + ("d3dkmdt", &["basetsd", "minwindef", "ntdef"], &[]), + ("d3dukmdt", &["basetsd", "guiddef", "minwindef", "ntdef"], &[]), + ("dcomptypes", &["dxgitype", "minwindef", "winnt"], &[]), + ("devguid", &[], &[]), + ("devpkey", &["devpropdef"], &[]), + ("devpropdef", &["guiddef", "minwindef", "winnt"], &[]), + ("dinputd", &[], &[]), + ("dxgi", &["basetsd", "dxgiformat", "dxgitype", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["dxgi"]), + ("dxgi1_2", &["basetsd", "dxgi", "dxgiformat", "dxgitype", "guiddef", "minwinbase", "minwindef", "unknwnbase", "windef", "winnt"], &[]), + ("dxgi1_3", &["dxgi", "dxgi1_2", "dxgiformat", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["dxgi"]), + ("dxgi1_4", &["basetsd", "dxgi1_2", "dxgi1_3", "dxgiformat", "dxgitype", "guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("dxgi1_5", &["basetsd", "dxgi", "dxgi1_2", "dxgi1_3", "dxgi1_4", "dxgiformat", "minwindef", "unknwnbase", "winnt"], &[]), + ("dxgi1_6", &["basetsd", "dxgi1_2", "dxgi1_4", "dxgi1_5", "dxgitype", "guiddef", "minwindef", "windef", "winnt"], &[]), + ("dxgiformat", &[], &[]), + ("dxgitype", &["d3d9types", "dxgiformat", "minwindef"], &[]), + ("enclaveapi", &["basetsd", "minwinbase", "minwindef", "ntdef", "winnt"], &["kernel32"]), + ("evntprov", &["basetsd", "guiddef", "minwindef", "winnt"], &["advapi32"]), + ("evntrace", &["basetsd", "evntcons", "evntprov", "guiddef", "handleapi", "minwindef", "timezoneapi", "vadefs", "winnt", "wmistr"], &["advapi32"]), + ("guiddef", &[], &[]), + ("hidclass", &["guiddef", "minwindef", "winioctl", "winnt"], &[]), + ("hidpi", &["hidusage", "minwindef", "ntdef", "ntstatus", "winnt"], &["hid"]), + ("hidsdi", &["guiddef", "hidpi", "minwindef", "winnt"], &["hid"]), + ("hidusage", &["minwindef"], &[]), + ("ifdef", &["basetsd", "minwindef"], &[]), + ("in6addr", &["minwindef"], &[]), + ("inaddr", &["minwindef"], &[]), + ("intsafe", &[], &[]), + ("ks", &[], &[]), + ("ksmedia", &[], &[]), + ("ktmtypes", &["guiddef", "minwindef", "winnt"], &[]), + ("lmcons", &["minwindef", "winnt"], &[]), + ("minwindef", &["basetsd", "ntdef"], &[]), + ("mmreg", &["guiddef", "minwindef"], &[]), + ("mstcpip", &["basetsd", "guiddef", "in6addr", "inaddr", "minwindef", "winnt", "ws2def"], &["ntdll"]), + ("mswsockdef", &["minwindef", "winnt", "ws2def"], &[]), + ("netioapi", &["basetsd", "guiddef", "ifdef", "minwindef", "ntdef"], &["iphlpapi"]), + ("ntddscsi", &["basetsd", "minwindef", "ntdef", "winioctl", "winnt"], &[]), + ("ntddser", &["devpropdef"], &[]), + ("ntdef", &["basetsd", "guiddef"], &[]), + ("ntstatus", &["ntdef"], &[]), + ("qos", &["minwindef"], &[]), + ("rpc", &[], &[]), + ("rpcdce", &["guiddef", "minwindef", "rpc"], &[]), + ("rpcndr", &[], &[]), + ("sddl", &["basetsd", "minwindef", "winnt"], &["advapi32"]), + ("sspi", &["basetsd", "guiddef", "minwindef", "subauth", "wincred", "winnt"], &["credui", "secur32"]), + ("stralign", &["vcruntime", "winnt"], &["kernel32"]), + ("transportsettingcommon", &["guiddef"], &[]), + ("tvout", &["guiddef", "minwindef"], &[]), + ("usb", &["minwindef", "usbspec", "winnt"], &[]), + ("usbiodef", &["guiddef", "minwindef", "winioctl", "winnt"], &[]), + ("usbspec", &["basetsd", "guiddef", "minwindef", "winnt"], &[]), + ("windef", &["minwindef", "winnt"], &[]), + ("windowsx", &["minwindef"], &[]), + ("winerror", &["minwindef", "wtypesbase"], &[]), + ("winusbio", &["minwindef", "usb"], &[]), + ("wmistr", &["basetsd", "guiddef", "minwindef", "winnt"], &[]), + ("wnnc", &["minwindef"], &[]), + ("ws2def", &["basetsd", "guiddef", "inaddr", "minwindef", "vcruntime", "winnt"], &[]), + ("ws2ipdef", &["in6addr", "inaddr", "minwindef", "ws2def"], &[]), + ("wtypes", &["guiddef", "minwindef", "ntdef", "rpcndr", "wingdi", "wtypesbase"], &[]), + ("wtypesbase", &["minwindef", "rpcndr", "winnt"], &[]), + // ucrt + // um + ("accctrl", &["guiddef", "minwindef", "winbase", "winnt"], &[]), + ("aclapi", &["accctrl", "guiddef", "minwindef", "winnt"], &["advapi32"]), + ("appmgmt", &["guiddef", "minwindef", "winnt"], &["advapi32"]), + ("audioclient", &["audiosessiontypes", "basetsd", "guiddef", "minwindef", "mmreg", "strmif", "unknwnbase", "winerror", "winnt", "wtypesbase"], &[]), + ("audiosessiontypes", &["minwindef"], &[]), + ("avrt", &["guiddef", "minwindef", "winnt"], &["avrt"]), + ("bits", &["basetsd", "guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("bits10_1", &["basetsd", "bits", "bits2_0", "bits3_0", "bits5_0", "minwindef", "winnt"], &[]), + ("bits1_5", &["basetsd", "bits", "rpcndr", "winnt"], &[]), + ("bits2_0", &["basetsd", "bits", "bits1_5", "minwindef", "winnt"], &[]), + ("bits2_5", &["minwindef", "rpcndr", "unknwnbase", "winnt"], &[]), + ("bits3_0", &["basetsd", "bits", "bits2_0", "guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("bits4_0", &["basetsd", "bits3_0", "minwindef", "unknwnbase", "winnt"], &[]), + ("bits5_0", &["basetsd", "bits1_5", "bits3_0", "bits4_0", "guiddef", "minwindef", "winnt"], &[]), + ("bitscfg", &["guiddef", "oaidl", "unknwnbase", "winnt", "wtypes"], &["oleaut32"]), + ("bitsmsg", &["minwindef"], &[]), + ("cfgmgr32", &["basetsd", "cfg", "devpropdef", "guiddef", "minwindef", "winnt", "winreg"], &["cfgmgr32"]), + ("cguid", &[], &[]), + ("combaseapi", &["basetsd", "guiddef", "minwindef", "objidl", "objidlbase", "propidl", "rpcdce", "unknwnbase", "winnt", "wtypesbase"], &["ole32"]), + ("coml2api", &["minwindef"], &[]), + ("commapi", &["minwinbase", "minwindef", "winbase", "winnt"], &["kernel32"]), + ("commctrl", &["basetsd", "commoncontrols", "guiddef", "minwinbase", "minwindef", "vcruntime", "windef", "winnt", "winuser"], &["comctl32"]), + ("commdlg", &["basetsd", "minwindef", "prsht", "unknwnbase", "windef", "wingdi", "winnt", "winuser"], &["comdlg32"]), + ("commoncontrols", &["commctrl", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["comctl32"]), + ("consoleapi", &["minwindef", "wincon", "wincontypes", "winnt"], &["kernel32"]), + ("corsym", &["basetsd", "objidlbase", "unknwnbase", "winnt"], &[]), + ("d2d1", &["basetsd", "d2dbasetypes", "d3dcommon", "dcommon", "dwrite", "dxgi", "guiddef", "minwindef", "unknwnbase", "wincodec", "windef", "winnt"], &["d2d1"]), + ("d2d1_1", &["basetsd", "d2d1", "d2d1effectauthor", "d2dbasetypes", "dcommon", "documenttarget", "dwrite", "dxgi", "dxgiformat", "guiddef", "minwindef", "objidlbase", "unknwnbase", "wincodec", "winnt"], &["d2d1"]), + ("d2d1_2", &["d2d1", "d2d1_1", "dxgi", "minwindef", "winnt"], &["d2d1"]), + ("d2d1_3", &["basetsd", "d2d1", "d2d1_1", "d2d1_2", "d2d1effects", "d2d1svg", "dcommon", "dwrite", "dxgi", "dxgitype", "minwindef", "ntdef", "objidlbase", "wincodec", "winerror"], &["d2d1"]), + ("d2d1effectauthor", &["basetsd", "d2d1", "d2d1_1", "d2dbasetypes", "d3dcommon", "dxgiformat", "guiddef", "minwindef", "ntdef", "unknwnbase", "wincodec"], &[]), + ("d2d1effects", &[], &[]), + ("d2d1effects_1", &[], &[]), + ("d2d1effects_2", &[], &[]), + ("d2d1svg", &["basetsd", "d2d1", "d2d1_1", "guiddef", "minwindef", "ntdef", "objidlbase", "winerror"], &[]), + ("d2dbasetypes", &["d3d9types", "dcommon"], &[]), + ("d3d", &[], &[]), + ("d3d10", &["d3dcommon"], &[]), + ("d3d10_1", &[], &[]), + ("d3d10_1shader", &[], &[]), + ("d3d10effect", &[], &[]), + ("d3d10misc", &[], &[]), + ("d3d10sdklayers", &[], &[]), + ("d3d10shader", &["d3d10", "d3dcommon", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3d11", &["basetsd", "d3dcommon", "dxgi", "dxgiformat", "dxgitype", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["d3d11"]), + ("d3d11_1", &["basetsd", "d3d11", "d3dcommon", "dxgiformat", "dxgitype", "guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3d11_2", &["basetsd", "d3d11", "d3d11_1", "dxgiformat", "minwindef", "winnt"], &[]), + ("d3d11_3", &[], &[]), + ("d3d11_4", &[], &[]), + ("d3d11on12", &["d3d11", "d3d12", "d3dcommon", "guiddef", "minwindef", "unknwnbase", "winnt"], &["d3d11"]), + ("d3d11sdklayers", &["basetsd", "d3d11", "dxgi", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3d11shader", &["basetsd", "d3dcommon", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3d11tokenizedprogramformat", &["minwindef"], &[]), + ("d3d12", &["basetsd", "d3dcommon", "dxgiformat", "dxgitype", "guiddef", "minwinbase", "minwindef", "unknwnbase", "windef", "winnt"], &["d3d12"]), + ("d3d12sdklayers", &["basetsd", "d3d12", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3d12shader", &["basetsd", "d3dcommon", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3dcommon", &["basetsd", "minwindef", "unknwnbase", "winnt"], &[]), + ("d3dcompiler", &["basetsd", "d3d11shader", "d3dcommon", "guiddef", "minwindef", "winnt"], &["d3dcompiler"]), + ("d3dcsx", &[], &[]), + ("d3dx10core", &[], &[]), + ("d3dx10math", &[], &[]), + ("d3dx10mesh", &[], &[]), + ("datetimeapi", &["minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("davclnt", &["minwindef", "winnt"], &["netapi32"]), + ("dbghelp", &["basetsd", "guiddef", "minwindef", "vcruntime", "winnt"], &["dbghelp"]), + ("dbt", &["basetsd", "guiddef", "minwindef", "winnt", "winuser"], &[]), + ("dcommon", &["basetsd", "dxgiformat", "minwindef", "windef"], &[]), + ("dcomp", &["d2d1", "d2d1_1", "d2d1effects", "d2dbasetypes", "d3d9types", "d3dcommon", "dcompanimation", "dcomptypes", "dxgi", "dxgi1_2", "dxgiformat", "guiddef", "minwinbase", "minwindef", "ntdef", "unknwnbase", "windef"], &["dcomp"]), + ("dcompanimation", &["ntdef", "unknwnbase"], &[]), + ("dde", &["basetsd", "minwindef"], &["user32"]), + ("ddraw", &[], &[]), + ("ddrawi", &[], &[]), + ("ddrawint", &[], &[]), + ("debugapi", &["minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("devicetopology", &["guiddef", "minwindef", "unknwnbase", "windef", "winnt", "wtypes"], &[]), + ("dinput", &[], &[]), + ("dispex", &["basetsd", "guiddef", "minwindef", "oaidl", "servprov", "unknwnbase", "winerror", "winnt", "wtypes"], &[]), + ("dmksctl", &[], &[]), + ("dmusicc", &[], &[]), + ("docobj", &["guiddef", "minwindef", "oaidl", "unknwnbase", "winnt"], &[]), + ("documenttarget", &["basetsd", "guiddef", "ntdef", "unknwnbase"], &[]), + ("dpa_dsa", &["basetsd", "minwindef", "winnt"], &["comctl32"]), + ("dpapi", &["minwindef", "wincrypt", "windef", "winnt"], &["crypt32"]), + ("dsgetdc", &["guiddef", "minwindef", "ntsecapi", "winnt", "ws2def"], &["netapi32"]), + ("dsound", &["guiddef", "minwindef", "mmsystem", "unknwnbase", "windef", "winerror", "winnt"], &["dsound"]), + ("dsrole", &["guiddef", "minwindef", "winnt"], &["netapi32"]), + ("dvp", &[], &[]), + ("dwmapi", &["basetsd", "minwindef", "uxtheme", "windef", "winnt"], &["dwmapi"]), + ("dwrite", &["basetsd", "d2d1", "dcommon", "guiddef", "minwindef", "unknwnbase", "windef", "winerror", "wingdi", "winnt"], &["dwrite"]), + ("dwrite_1", &["basetsd", "dcommon", "dwrite", "minwindef", "winnt"], &[]), + ("dwrite_2", &["basetsd", "d3d9types", "dcommon", "dwrite", "dwrite_1", "minwindef", "unknwnbase", "winnt"], &[]), + ("dwrite_3", &["basetsd", "dcommon", "dwrite", "dwrite_1", "dwrite_2", "minwindef", "unknwnbase", "wingdi", "winnt"], &[]), + ("dxdiag", &[], &[]), + ("dxfile", &[], &[]), + ("dxgidebug", &["basetsd", "guiddef", "minwindef", "unknwnbase", "winnt"], &["dxgi"]), + ("dxva2api", &["basetsd", "d3d9", "d3d9types", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["dxva2"]), + ("dxvahd", &["d3d9", "d3d9types", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["dxva2"]), + ("endpointvolume", &["basetsd", "guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("errhandlingapi", &["basetsd", "minwindef", "winnt"], &["kernel32"]), + ("evntcons", &["basetsd", "evntprov", "evntrace", "guiddef", "minwindef", "winnt"], &["advapi32"]), + ("exdisp", &["basetsd", "docobj", "oaidl", "ocidl", "winnt", "wtypes"], &[]), + ("fibersapi", &["minwindef", "winnt"], &["kernel32"]), + ("fileapi", &["minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("gl-gl", &[], &["opengl32"]), + ("handleapi", &["minwindef", "winnt"], &["kernel32"]), + ("heapapi", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("highlevelmonitorconfigurationapi", &["minwindef", "physicalmonitorenumerationapi", "winnt"], &["dxva2"]), + ("http", &["guiddef", "minwinbase", "minwindef", "sspi", "winnt", "ws2def"], &["winhttp"]), + ("imm", &["minwindef", "windef"], &["imm32"]), + ("interlockedapi", &["minwindef", "winnt"], &["kernel32"]), + ("ioapiset", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("jobapi", &["minwindef", "winnt"], &["kernel32"]), + ("jobapi2", &["basetsd", "minwinbase", "minwindef", "ntdef", "winnt"], &["kernel32"]), + ("knownfolders", &[], &[]), + ("ktmw32", &["guiddef", "minwinbase", "minwindef", "winnt"], &["ktmw32"]), + ("libloaderapi", &["basetsd", "minwindef", "winnt"], &["kernel32", "user32"]), + ("lmaccess", &["basetsd", "lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmalert", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmapibuf", &["lmcons", "minwindef"], &["netapi32"]), + ("lmat", &["basetsd", "lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmdfs", &["guiddef", "lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmerrlog", &["minwindef", "winnt"], &[]), + ("lmjoin", &["lmcons", "minwindef", "wincrypt", "winnt"], &["netapi32"]), + ("lmmsg", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmremutl", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmrepl", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmserver", &["guiddef", "lmcons", "minwindef", "winnt", "winsvc"], &["advapi32", "netapi32"]), + ("lmshare", &["basetsd", "guiddef", "lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmstats", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmsvc", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmuse", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lmwksta", &["lmcons", "minwindef", "winnt"], &["netapi32"]), + ("lowlevelmonitorconfigurationapi", &["minwindef", "physicalmonitorenumerationapi", "winnt"], &["dxva2"]), + ("lsalookup", &["guiddef", "minwindef", "ntdef", "winnt"], &["advapi32"]), + ("memoryapi", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("minschannel", &["guiddef", "minwindef", "wincrypt", "winnt"], &[]), + ("minwinbase", &["basetsd", "minwindef", "ntstatus", "winnt"], &[]), + ("mmdeviceapi", &["guiddef", "minwindef", "propidl", "propsys", "unknwnbase", "winnt", "wtypes"], &["mmdevapi"]), + ("mmeapi", &["basetsd", "imm", "minwindef", "mmsystem", "winnt"], &["winmm"]), + ("mmsystem", &["basetsd", "minwindef", "mmreg", "winnt"], &[]), + ("msaatext", &[], &[]), + ("mscat", &["guiddef", "minwindef", "mssip", "wincrypt", "winnt"], &[]), + ("mschapp", &["basetsd", "minwindef", "winnt"], &["advapi32"]), + ("mssip", &["guiddef", "minwindef", "mscat", "wincrypt", "winnt"], &["crypt32"]), + ("mswsock", &["minwinbase", "minwindef", "mswsockdef", "winnt", "winsock2", "ws2def"], &["mswsock"]), + ("namedpipeapi", &["minwinbase", "minwindef", "winnt"], &["advapi32", "kernel32"]), + ("namespaceapi", &["minwinbase", "minwindef", "ntdef", "winnt"], &["kernel32"]), + ("nb30", &["minwindef", "winnt"], &["netapi32"]), + ("ncrypt", &["basetsd", "bcrypt", "minwindef", "winnt"], &["ncrypt"]), + ("ntlsa", &["basetsd", "guiddef", "lsalookup", "minwindef", "ntdef", "ntsecapi", "subauth", "winnt"], &["advapi32"]), + ("ntsecapi", &["basetsd", "guiddef", "lsalookup", "minwindef", "ntdef", "sspi", "subauth", "winnt"], &["advapi32"]), + ("oaidl", &["basetsd", "guiddef", "minwindef", "rpcndr", "unknwnbase", "winnt", "wtypes", "wtypesbase"], &[]), + ("objbase", &["combaseapi", "minwindef", "winnt"], &["ole32"]), + ("objidl", &["basetsd", "guiddef", "minwindef", "ntdef", "objidlbase", "unknwnbase", "windef", "winnt", "wtypes", "wtypesbase"], &[]), + ("objidlbase", &["basetsd", "guiddef", "minwindef", "unknwnbase", "winnt", "wtypesbase"], &[]), + ("ocidl", &["guiddef", "minwindef", "ntdef", "oaidl", "unknwnbase", "wtypes", "wtypesbase"], &[]), + ("ole2", &["minwindef", "oleidl", "windef", "winnt"], &["ole32"]), + ("oleauto", &["basetsd", "minwinbase", "minwindef", "oaidl", "winnt", "wtypes", "wtypesbase"], &["oleaut32"]), + ("olectl", &["winerror", "winnt"], &[]), + ("oleidl", &["minwindef", "ntdef", "objidl", "unknwnbase", "windef"], &[]), + ("opmapi", &["basetsd", "d3d9", "d3d9types", "dxva2api", "guiddef", "minwindef", "unknwnbase", "windef", "winnt"], &["dxva2"]), + ("pdh", &["basetsd", "guiddef", "minwindef", "windef", "winnt"], &["pdh"]), + ("perflib", &["basetsd", "guiddef", "minwinbase", "minwindef", "winnt"], &["advapi32"]), + ("physicalmonitorenumerationapi", &["d3d9", "minwindef", "windef", "winnt"], &["dxva2"]), + ("playsoundapi", &["minwindef", "winnt"], &["winmm"]), + ("portabledevice", &["basetsd"], &[]), + ("portabledeviceapi", &["guiddef", "minwindef", "objidlbase", "portabledevicetypes", "propkeydef", "unknwnbase", "winnt"], &[]), + ("portabledevicetypes", &["guiddef", "minwindef", "propidl", "propkeydef", "propsys", "unknwnbase", "winnt", "wtypes"], &[]), + ("powerbase", &["minwindef", "winnt", "winuser"], &["powrprof"]), + ("powersetting", &["guiddef", "minwindef", "winnt", "winuser"], &["powrprof"]), + ("powrprof", &["guiddef", "minwindef", "winnt", "winreg"], &["powrprof"]), + ("processenv", &["minwindef", "winnt"], &["kernel32"]), + ("processsnapshot", &["basetsd", "minwindef", "winnt"], &["kernel32"]), + ("processthreadsapi", &["basetsd", "guiddef", "minwinbase", "minwindef", "winnt"], &["advapi32", "kernel32"]), + ("processtopologyapi", &["minwindef", "winnt"], &["kernel32"]), + ("profileapi", &["minwindef", "winnt"], &["kernel32"]), + ("propidl", &["minwindef", "wtypes"], &[]), + ("propkeydef", &["guiddef", "wtypes"], &[]), + ("propsys", &["minwindef", "propidl", "propkeydef", "unknwnbase", "winnt", "wtypes"], &[]), + ("prsht", &["basetsd", "minwindef", "windef", "winnt", "winuser"], &["comctl32"]), + ("psapi", &["basetsd", "minwindef", "winnt"], &["kernel32", "psapi"]), + ("realtimeapiset", &["basetsd", "minwindef", "winnt"], &["kernel32"]), + ("reason", &["minwindef"], &[]), + ("restartmanager", &["minwindef", "winnt"], &["rstrtmgr"]), + ("restrictederrorinfo", &["unknwnbase", "winnt", "wtypes"], &[]), + ("rmxfguid", &[], &[]), + ("sapi", &["guiddef", "minwindef", "sapi53", "unknwnbase", "winnt"], &[]), + ("sapi51", &["guiddef", "minwindef", "mmreg", "oaidl", "objidlbase", "rpcndr", "servprov", "unknwnbase", "windef", "winnt", "wtypes", "wtypesbase"], &[]), + ("sapi53", &["guiddef", "minwindef", "oaidl", "sapi51", "unknwnbase", "urlmon", "winnt", "wtypes"], &[]), + ("sapiddk", &["guiddef", "minwindef", "sapi", "sapiddk51", "unknwnbase", "winnt"], &[]), + ("sapiddk51", &["guiddef", "minwindef", "mmreg", "oaidl", "objidlbase", "sapi", "unknwnbase", "windef", "winnt"], &[]), + ("schannel", &["guiddef", "minwindef", "wincrypt", "windef", "winnt"], &[]), + ("securityappcontainer", &["minwindef", "winnt"], &["kernel32"]), + ("securitybaseapi", &["guiddef", "minwinbase", "minwindef", "winnt"], &["advapi32", "kernel32"]), + ("servprov", &["guiddef", "unknwnbase", "winnt"], &[]), + ("setupapi", &["basetsd", "commctrl", "devpropdef", "guiddef", "minwindef", "prsht", "spapidef", "windef", "winnt", "winreg"], &["setupapi"]), + ("shellapi", &["basetsd", "guiddef", "minwinbase", "minwindef", "processthreadsapi", "windef", "winnt", "winuser"], &["shell32", "shlwapi"]), + ("shellscalingapi", &["minwindef", "windef", "winnt"], &["shcore"]), + ("shlobj", &["guiddef", "minwinbase", "minwindef", "shtypes", "windef", "winnt"], &["shell32"]), + ("shobjidl", &["guiddef", "minwindef", "objidl", "propkeydef", "propsys", "shobjidl_core", "shtypes", "unknwnbase", "windef", "winnt"], &[]), + ("shobjidl_core", &["commctrl", "guiddef", "minwindef", "objidl", "unknwnbase", "windef", "winnt"], &[]), + ("shtypes", &["guiddef", "minwindef", "winnt"], &[]), + ("spapidef", &["minwindef", "winnt"], &[]), + ("spellcheck", &["minwindef", "ntdef", "objidlbase", "unknwnbase", "winerror"], &[]), + ("sporder", &["guiddef", "minwindef"], &["sporder"]), + ("sql", &["sqltypes"], &["odbc32"]), + ("sqlext", &["sql", "sqltypes"], &[]), + ("sqltypes", &["basetsd", "guiddef", "windef"], &[]), + ("sqlucode", &["sqltypes"], &["odbc32"]), + ("stringapiset", &["minwindef", "winnls", "winnt"], &["kernel32"]), + ("strmif", &["winnt"], &[]), + ("subauth", &["minwindef", "winnt"], &[]), + ("synchapi", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32", "synchronization"]), + ("sysinfoapi", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("systemtopologyapi", &["minwindef", "winnt"], &["kernel32"]), + ("taskschd", &["minwinbase", "minwindef", "oaidl", "unknwnbase", "winnt", "wtypes"], &[]), + ("textstor", &[], &[]), + ("threadpoolapiset", &["basetsd", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("threadpoollegacyapiset", &["minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("timeapi", &["minwindef", "mmsystem"], &["winmm"]), + ("timezoneapi", &["minwinbase", "minwindef", "winnt"], &["advapi32", "kernel32"]), + ("tlhelp32", &["basetsd", "minwindef", "winnt"], &["kernel32"]), + ("unknwnbase", &["guiddef", "minwindef", "winnt"], &[]), + ("urlhist", &["docobj", "guiddef", "minwindef", "unknwnbase", "winnt", "wtypesbase"], &[]), + ("urlmon", &["minwindef", "unknwnbase", "winnt"], &[]), + ("userenv", &["minwindef", "winnt", "winreg"], &["userenv"]), + ("usp10", &["minwindef", "ntdef", "windef", "winerror", "wingdi", "winnt"], &["usp10"]), + ("utilapiset", &["minwindef", "ntdef"], &["kernel32"]), + ("uxtheme", &["commctrl", "minwindef", "windef", "wingdi", "winnt"], &["uxtheme"]), + ("vsbackup", &["guiddef", "minwindef", "unknwnbase", "vss", "vswriter", "winnt", "wtypes"], &["vssapi"]), + ("vss", &["guiddef", "minwindef", "unknwnbase", "winnt"], &[]), + ("vsserror", &["winnt"], &[]), + ("vswriter", &["minwindef", "unknwnbase", "vss", "winnt", "wtypes"], &[]), + ("wbemads", &["oaidl", "wbemdisp", "winerror", "wtypes"], &[]), + ("wbemcli", &["minwindef", "oaidl", "rpcndr", "unknwnbase", "winerror", "winnt", "wtypes"], &[]), + ("wbemdisp", &["oaidl", "unknwnbase", "winerror", "wtypes"], &[]), + ("wbemprov", &["minwindef", "oaidl", "unknwnbase", "wbemcli", "winerror", "winnt", "wtypes"], &[]), + ("wbemtran", &["guiddef", "minwindef", "unknwnbase", "wbemcli", "winerror", "winnt", "wtypes"], &[]), + ("wct", &["basetsd", "guiddef", "minwindef", "winnt"], &["advapi32"]), + ("werapi", &["minwindef", "winnt"], &["kernel32", "wer"]), + ("winbase", &["basetsd", "cfgmgr32", "fileapi", "guiddef", "libloaderapi", "minwinbase", "minwindef", "processthreadsapi", "vadefs", "windef", "winnt"], &["kernel32"]), + ("wincodec", &["basetsd", "d2d1", "d2d1_1", "dcommon", "dxgiformat", "dxgitype", "guiddef", "minwindef", "ntdef", "objidlbase", "ocidl", "propidl", "unknwnbase", "windef", "winerror", "winnt"], &["windowscodecs"]), + ("wincodecsdk", &["guiddef", "minwindef", "oaidl", "objidl", "objidlbase", "ocidl", "propidl", "unknwnbase", "wincodec", "winnt", "wtypes"], &["ole32", "oleaut32", "windowscodecs"]), + ("wincon", &["minwinbase", "minwindef", "wincontypes", "windef", "wingdi", "winnt"], &["kernel32"]), + ("wincontypes", &["minwindef", "winnt"], &[]), + ("wincred", &["minwindef", "sspi", "windef", "winnt"], &["advapi32", "credui"]), + ("wincrypt", &["basetsd", "bcrypt", "guiddef", "minwinbase", "minwindef", "ncrypt", "vcruntime", "winnt"], &["advapi32", "crypt32", "cryptnet"]), + ("windowsceip", &["minwindef"], &["kernel32"]), + ("winefs", &["basetsd", "minwinbase", "minwindef", "wincrypt", "winnt"], &["advapi32"]), + ("winevt", &["basetsd", "guiddef", "minwinbase", "minwindef", "vcruntime", "winnt"], &["wevtapi"]), + ("wingdi", &["basetsd", "minwindef", "windef", "winnt"], &["gdi32", "msimg32", "opengl32", "winspool"]), + ("winhttp", &["basetsd", "minwinbase", "minwindef", "winnt"], &["winhttp"]), + ("wininet", &["basetsd", "minwinbase", "minwindef", "ntdef", "windef", "winineti", "winnt"], &["wininet"]), + ("winineti", &["minwindef"], &[]), + ("winioctl", &["basetsd", "devpropdef", "guiddef", "minwindef", "winnt"], &[]), + ("winnetwk", &["basetsd", "minwindef", "windef", "winerror", "winnt"], &["mpr"]), + ("winnls", &["basetsd", "guiddef", "minwinbase", "minwindef", "winnt"], &["kernel32"]), + ("winnt", &["basetsd", "excpt", "guiddef", "ktmtypes", "minwindef", "ntdef", "vcruntime"], &["kernel32"]), + ("winreg", &["basetsd", "minwinbase", "minwindef", "winnt"], &["advapi32"]), + ("winsafer", &["basetsd", "guiddef", "minwindef", "wincrypt", "windef", "winnt"], &["advapi32"]), + ("winscard", &["basetsd", "guiddef", "minwindef", "rpcdce", "windef", "winnt", "winsmcrd"], &["winscard"]), + ("winsmcrd", &["minwindef", "winioctl"], &[]), + ("winsock2", &["basetsd", "guiddef", "inaddr", "minwinbase", "minwindef", "qos", "winbase", "windef", "winerror", "winnt", "ws2def", "wtypesbase"], &["ws2_32"]), + ("winspool", &["guiddef", "minwinbase", "minwindef", "vcruntime", "windef", "winerror", "wingdi", "winnt"], &["winspool"]), + ("winsvc", &["minwindef", "winnt"], &["advapi32"]), + ("winusb", &["minwinbase", "minwindef", "usb", "usbspec", "winnt", "winusbio"], &["winusb"]), + ("winuser", &["basetsd", "guiddef", "limits", "minwinbase", "minwindef", "vadefs", "windef", "wingdi", "winnt"], &["user32"]), + ("winver", &["minwindef", "winnt"], &["kernel32", "version"]), + ("wow64apiset", &["minwindef", "winnt"], &["kernel32"]), + ("wpdmtpextensions", &[], &[]), + ("ws2spi", &["basetsd", "guiddef", "minwindef", "vcruntime", "windef", "winnt", "winsock2", "ws2def", "wtypesbase"], &["ws2_32"]), + ("ws2tcpip", &["guiddef", "minwinbase", "minwindef", "mstcpip", "vcruntime", "winerror", "winnt", "winsock2", "ws2def", "wtypesbase"], &["fwpuclnt", "ws2_32"]), + ("xinput", &["guiddef", "minwindef", "winnt"], &["xinput"]), + // vc + ("excpt", &[], &[]), + ("limits", &[], &[]), + ("vadefs", &[], &[]), + ("vcruntime", &[], &[]), + // winrt + ("activation", &["inspectable", "winnt"], &[]), + ("hstring", &["winnt"], &[]), + ("inspectable", &["guiddef", "hstring", "minwindef", "unknwnbase", "winnt"], &[]), + ("roapi", &["activation", "basetsd", "guiddef", "hstring", "inspectable", "objidl", "winnt"], &["runtimeobject"]), + ("robuffer", &["objidl", "winnt"], &["runtimeobject"]), + ("roerrorapi", &["basetsd", "hstring", "minwindef", "restrictederrorinfo", "unknwnbase", "winnt"], &["runtimeobject"]), + ("winstring", &["basetsd", "hstring", "minwindef", "winnt"], &["runtimeobject"]), +]; +struct Header { + required: bool, + included: Cell<bool>, + dependencies: &'static [&'static str], + libraries: &'static [&'static str], +} +struct Graph(HashMap<&'static str, Header>); +impl Graph { + fn generate() -> Graph { + Graph(DATA.iter().map(|&(name, dependencies, libraries)| { + let header = Header { + required: false, + included: Cell::new(false), + dependencies: dependencies, + libraries: libraries, + }; + (name, header) + }).collect()) + } + fn identify_required(&mut self) { + for (name, header) in &mut self.0 { + if let Ok(_) = var(&format!("CARGO_FEATURE_{}", name.to_uppercase())) { + header.required = true; + header.included.set(true); + } + } + } + fn check_everything(&self) { + if let Ok(_) = var("CARGO_FEATURE_EVERYTHING") { + for (_, header) in &self.0 { + header.included.set(true); + } + } + } + fn resolve_dependencies(&self) { + let mut done = false; + while !done { + done = true; + for (_, header) in &self.0 { + if header.included.get() { + for dep in header.dependencies { + let dep = &self.0.get(dep).expect(dep); + if !dep.included.get() { + done = false; + dep.included.set(true); + } + } + } + } + } + } + fn emit_features(&self) { + for (name, header) in &self.0 { + if header.included.get() && !header.required { + println!("cargo:rustc-cfg=feature=\"{}\"", name); + } + } + } + fn emit_libraries(&self) { + let mut libs = self.0.iter().filter(|&(_, header)| { + header.included.get() + }).flat_map(|(_, header)| { + header.libraries.iter() + }).collect::<Vec<_>>(); + libs.sort(); + libs.dedup(); + // FIXME Temporary hacks until build script is redesigned. + libs.retain(|&&lib| match &*var("TARGET").unwrap() { + "aarch64-pc-windows-msvc" => { + if lib == "opengl32" { false } + else { true } + }, + _ => true, + }); + let prefix = library_prefix(); + let kind = library_kind(); + for lib in libs { + println!("cargo:rustc-link-lib={}={}{}", kind, prefix, lib); + } + } +} +fn library_prefix() -> &'static str { + if var("TARGET").map(|target| + target == "i686-pc-windows-gnu" || target == "x86_64-pc-windows-gnu" + ).unwrap_or(false) && var("WINAPI_NO_BUNDLED_LIBRARIES").is_err() { + "winapi_" + } else { + "" + } +} +fn library_kind() -> &'static str { + if var("WINAPI_STATIC_NOBUNDLE").is_ok() { + "static-nobundle" + } else { + "dylib" + } +} +fn try_everything() { + let mut graph = Graph::generate(); + graph.identify_required(); + graph.check_everything(); + graph.resolve_dependencies(); + graph.emit_features(); + graph.emit_libraries(); +} +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=WINAPI_NO_BUNDLED_LIBRARIES"); + println!("cargo:rerun-if-env-changed=WINAPI_STATIC_NOBUNDLE"); + let target = var("TARGET").unwrap(); + let target: Vec<_> = target.split('-').collect(); + if target.get(2) == Some(&"windows") { + try_everything(); + } +} diff --git a/winapi/src/km/d3dkmthk.rs b/winapi/src/km/d3dkmthk.rs new file mode 100644 index 000000000..9ac551cee --- /dev/null +++ b/winapi/src/km/d3dkmthk.rs @@ -0,0 +1,312 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! longhorn display driver model kernel mode thunk interfaces +use shared::basetsd::{UINT32, UINT64}; +use shared::d3dukmdt::{ + D3DDDICB_SIGNALFLAGS, D3DDDI_ALLOCATIONLIST, D3DDDI_CREATECONTEXTFLAGS, + D3DDDI_MAX_BROADCAST_CONTEXT, D3DDDI_MAX_OBJECT_SIGNALED, D3DDDI_MAX_OBJECT_WAITED_ON, + D3DDDI_PATCHLOCATIONLIST, D3DDDI_SYNCHRONIZATIONOBJECTINFO, + D3DDDI_SYNCHRONIZATIONOBJECTINFO2, D3DDDI_VIDEO_PRESENT_SOURCE_ID, D3DGPU_VIRTUAL_ADDRESS, + D3DKMT_HANDLE, +}; +use shared::minwindef::{BOOL, UCHAR, UINT, ULONG}; +use shared::ntdef::{HANDLE, LUID, PCWSTR, ULONGLONG, VOID, WCHAR}; +use shared::windef::HDC; +STRUCT!{struct D3DKMT_CREATEDEVICEFLAGS { + bitfield: UINT, +}} +BITFIELD!{D3DKMT_CREATEDEVICEFLAGS bitfield: UINT [ + LegacyMode set_LegacyMode[0..1], + RequestVSync set_RequestVSync[1..2], + DisableGpuTimeout set_DisableGpuTimeout[2..3], + Reserved set_Reserved[3..32], +]} +UNION!{union D3DKMT_CREATEDEVICE_u { + [usize; 1], + hAdapter hAdapter_mut: D3DKMT_HANDLE, + pAdapter pAdapter_mut: *mut VOID, +}} +STRUCT!{struct D3DKMT_CREATEDEVICE { + u: D3DKMT_CREATEDEVICE_u, + Flags: D3DKMT_CREATEDEVICEFLAGS, + hDevice: D3DKMT_HANDLE, + pCommandBuffer: *mut VOID, + CommandBufferSize: UINT, + pAllocationList: *mut D3DDDI_ALLOCATIONLIST, + AllocationListSize: UINT, + pPatchLocationList: *mut D3DDDI_PATCHLOCATIONLIST, + PatchLocationListSize: UINT, +}} +STRUCT!{struct D3DKMT_DESTROYDEVICE { + hDevice: D3DKMT_HANDLE, +}} +ENUM!{enum D3DKMT_CLIENTHINT { + D3DKMT_CLIENTHINT_UNKNOWN = 0, + D3DKMT_CLIENTHINT_OPENGL = 1, + D3DKMT_CLIENTHINT_CDD = 2, + D3DKMT_CLIENTHINT_DX7 = 7, + D3DKMT_CLIENTHINT_DX8 = 8, + D3DKMT_CLIENTHINT_DX9 = 9, + D3DKMT_CLIENTHINT_DX10 = 10, +}} +STRUCT!{struct D3DKMT_CREATECONTEXT { + hDevice: D3DKMT_HANDLE, + NodeOrdinal: UINT, + EngineAffinity: UINT, + Flags: D3DDDI_CREATECONTEXTFLAGS, + pPrivateDriverData: *mut VOID, + PrivateDriverDataSize: UINT, + ClientHint: D3DKMT_CLIENTHINT, + hContext: D3DKMT_HANDLE, + pCommandBuffer: *mut VOID, + CommandBufferSize: UINT, + pAllocationList: *mut D3DDDI_ALLOCATIONLIST, + AllocationListSize: UINT, + pPatchLocationList: *mut D3DDDI_PATCHLOCATIONLIST, + PatchLocationListSize: UINT, + CommandBuffer: D3DGPU_VIRTUAL_ADDRESS, +}} +STRUCT!{struct D3DKMT_DESTROYCONTEXT { + hContext: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DKMT_CREATESYNCHRONIZATIONOBJECT { + hDevice: D3DKMT_HANDLE, + Info: D3DDDI_SYNCHRONIZATIONOBJECTINFO, + hSyncObject: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DKMT_CREATESYNCHRONIZATIONOBJECT2 { + hDevice: D3DKMT_HANDLE, + Info: D3DDDI_SYNCHRONIZATIONOBJECTINFO2, + hSyncObject: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DKMT_DESTROYSYNCHRONIZATIONOBJECT { + hSyncObject: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DKMT_OPENSYNCHRONIZATIONOBJECT { + hSharedHandle: D3DKMT_HANDLE, + hSyncObject: D3DKMT_HANDLE, + Reserved: [UINT64; 8], +}} +STRUCT!{struct D3DKMT_WAITFORSYNCHRONIZATIONOBJECT { + hContext: D3DKMT_HANDLE, + ObjectCount: UINT, + ObjectHandleArray: [D3DKMT_HANDLE; D3DDDI_MAX_OBJECT_WAITED_ON], +}} +STRUCT!{struct D3DKMT_WAITFORSYNCHRONIZATIONOBJECT2_Fence { + FenceValue: UINT64, +}} +UNION!{union D3DKMT_WAITFORSYNCHRONIZATIONOBJECT2_u { + [u64; 8], + Fence Fence_mut: D3DKMT_WAITFORSYNCHRONIZATIONOBJECT2_Fence, + Reserved Reserved_mut: [UINT64; 8], +}} +STRUCT!{struct D3DKMT_WAITFORSYNCHRONIZATIONOBJECT2 { + hContext: D3DKMT_HANDLE, + ObjectCount: UINT, + ObjectHandleArray: [D3DKMT_HANDLE; D3DDDI_MAX_OBJECT_WAITED_ON], + u: D3DKMT_WAITFORSYNCHRONIZATIONOBJECT2_u, +}} +STRUCT!{struct D3DKMT_SIGNALSYNCHRONIZATIONOBJECT { + hContext: D3DKMT_HANDLE, + ObjectCount: UINT, + ObjectHandleArray: [D3DKMT_HANDLE; D3DDDI_MAX_OBJECT_SIGNALED], + Flags: D3DDDICB_SIGNALFLAGS, +}} +STRUCT!{struct D3DKMT_SIGNALSYNCHRONIZATIONOBJECT2_Fence { + FenceValue: UINT64, +}} +UNION!{union D3DKMT_SIGNALSYNCHRONIZATIONOBJECT2_u { + [u64; 8], + Fence Fence_mut: D3DKMT_SIGNALSYNCHRONIZATIONOBJECT2_Fence, + CpuEventHandle CpuEventHandle_mut: HANDLE, + Reserved Reserved_mut: [UINT64; 8], +}} +STRUCT!{struct D3DKMT_SIGNALSYNCHRONIZATIONOBJECT2 { + hContext: D3DKMT_HANDLE, + ObjectCount: UINT, + ObjectHandleArray: [D3DKMT_HANDLE; D3DDDI_MAX_OBJECT_SIGNALED], + Flags: D3DDDICB_SIGNALFLAGS, + BroadcastContextCount: ULONG, + BroadcastContext: [D3DKMT_HANDLE; D3DDDI_MAX_BROADCAST_CONTEXT], + u: D3DKMT_SIGNALSYNCHRONIZATIONOBJECT2_u, +}} +//1512 +STRUCT!{struct D3DKMT_SEGMENTSIZEINFO { + DedicatedVideoMemorySize: ULONGLONG, + DedicatedSystemMemorySize: ULONGLONG, + SharedSystemMemorySize: ULONGLONG, +}} +//1617 +STRUCT!{struct D3DKMT_ADAPTERTYPE { + Value: UINT, +}} +BITFIELD!{D3DKMT_ADAPTERTYPE Value: UINT [ + RenderSupported set_RenderSupported[0..1], + DisplaySupported set_DisplaySupported[1..2], + SoftwareDevice set_SoftwareDevice[2..3], + PostDevice set_PostDevice[3..4], + HybridDiscrete set_HybridDiscrete[4..5], + HybridIntegrated set_HybridIntegrated[5..6], + IndirectDisplayDevice set_IndirectDisplayDevice[6..7], + Paravirtualized set_Paravirtualized[7..8], + ACGSupported set_ACGSupported[8..9], + SupportSetTimingsFromVidPn set_SupportSetTimingsFromVidPn[9..10], + Detachable set_Detachable[10..11], + Reserved set_Reserved[11..32], +]} +//1852 +STRUCT!{struct D3DKMT_NODE_PERFDATA { + NodeOrdinal: UINT32, + PhysicalAdapterIndex: UINT32, + Frequency: ULONGLONG, + MaxFrequency: ULONGLONG, + MaxFrequencyOC: ULONGLONG, + Voltage: ULONG, + VoltageMax: ULONG, + VoltageMaxOC: ULONG, + MaxTransitionLatency: ULONGLONG, +}} +STRUCT!{struct D3DKMT_ADAPTER_PERFDATA { + PhysicalAdapterIndex: UINT32, + MemoryFrequency: ULONGLONG, + MaxMemoryFrequency: ULONGLONG, + MaxMemoryFrequencyOC: ULONGLONG, + MemoryBandwidth: ULONGLONG, + PCIEBandwidth: ULONGLONG, + FanRPM: ULONG, + Power: ULONG, + Temperature: ULONG, + PowerStateOverride: UCHAR, +}} +STRUCT!{struct D3DKMT_ADAPTER_PERFDATACAPS { + PhysicalAdapterIndex: UINT32, + MaxMemoryBandwidth: ULONGLONG, + MaxPCIEBandwidth: ULONGLONG, + MaxFanRPM: ULONG, + TemperatureMax: ULONG, + TemperatureWarning: ULONG, +}} +pub const DXGK_MAX_GPUVERSION_NAME_LENGTH: usize = 32; +STRUCT!{struct D3DKMT_GPUVERSION { + PhysicalAdapterIndex: UINT32, + BiosVersion: [WCHAR; DXGK_MAX_GPUVERSION_NAME_LENGTH], + GpuArchitecture: [WCHAR; DXGK_MAX_GPUVERSION_NAME_LENGTH], +}} +ENUM!{enum KMTQUERYADAPTERINFOTYPE { + KMTQAITYPE_UMDRIVERPRIVATE = 0, + KMTQAITYPE_UMDRIVERNAME = 1, + KMTQAITYPE_UMOPENGLINFO = 2, + KMTQAITYPE_GETSEGMENTSIZE = 3, + KMTQAITYPE_ADAPTERGUID = 4, + KMTQAITYPE_FLIPQUEUEINFO = 5, + KMTQAITYPE_ADAPTERADDRESS = 6, + KMTQAITYPE_SETWORKINGSETINFO = 7, + KMTQAITYPE_ADAPTERREGISTRYINFO = 8, + KMTQAITYPE_CURRENTDISPLAYMODE = 9, + KMTQAITYPE_MODELIST = 10, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS = 11, + KMTQAITYPE_VIRTUALADDRESSINFO = 12, + KMTQAITYPE_DRIVERVERSION = 13, + KMTQAITYPE_ADAPTERTYPE = 15, + KMTQAITYPE_OUTPUTDUPLCONTEXTSCOUNT = 16, + KMTQAITYPE_WDDM_1_2_CAPS = 17, + KMTQAITYPE_UMD_DRIVER_VERSION = 18, + KMTQAITYPE_DIRECTFLIP_SUPPORT = 19, + KMTQAITYPE_MULTIPLANEOVERLAY_SUPPORT = 20, + KMTQAITYPE_DLIST_DRIVER_NAME = 21, + KMTQAITYPE_WDDM_1_3_CAPS = 22, + KMTQAITYPE_MULTIPLANEOVERLAY_HUD_SUPPORT = 23, + KMTQAITYPE_WDDM_2_0_CAPS = 24, + KMTQAITYPE_NODEMETADATA = 25, + KMTQAITYPE_CPDRIVERNAME = 26, + KMTQAITYPE_XBOX = 27, + KMTQAITYPE_INDEPENDENTFLIP_SUPPORT = 28, + KMTQAITYPE_MIRACASTCOMPANIONDRIVERNAME = 29, + KMTQAITYPE_PHYSICALADAPTERCOUNT = 30, + KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, + KMTQAITYPE_DRIVERCAPS_EXT = 32, + KMTQAITYPE_QUERY_MIRACAST_DRIVER_TYPE = 33, + KMTQAITYPE_QUERY_GPUMMU_CAPS = 34, + KMTQAITYPE_QUERY_MULTIPLANEOVERLAY_DECODE_SUPPORT = 35, + KMTQAITYPE_QUERY_HW_PROTECTION_TEARDOWN_COUNT = 36, + KMTQAITYPE_QUERY_ISBADDRIVERFORHWPROTECTIONDISABLED = 37, + KMTQAITYPE_MULTIPLANEOVERLAY_SECONDARY_SUPPORT = 38, + KMTQAITYPE_INDEPENDENTFLIP_SECONDARY_SUPPORT = 39, + KMTQAITYPE_PANELFITTER_SUPPORT = 40, + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, + KMTQAITYPE_GETSEGMENTGROUPSIZE = 42, + KMTQAITYPE_MPO3DDI_SUPPORT = 43, + KMTQAITYPE_HWDRM_SUPPORT = 44, + KMTQAITYPE_MPOKERNELCAPS_SUPPORT = 45, + KMTQAITYPE_MULTIPLANEOVERLAY_STRETCH_SUPPORT = 46, + KMTQAITYPE_GET_DEVICE_VIDPN_OWNERSHIP_INFO = 47, + KMTQAITYPE_QUERYREGISTRY = 48, + KMTQAITYPE_KMD_DRIVER_VERSION = 49, + KMTQAITYPE_BLOCKLIST_KERNEL = 50, + KMTQAITYPE_BLOCKLIST_RUNTIME = 51, + KMTQAITYPE_ADAPTERGUID_RENDER = 52, + KMTQAITYPE_ADAPTERADDRESS_RENDER = 53, + KMTQAITYPE_ADAPTERREGISTRYINFO_RENDER = 54, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS_RENDER = 55, + KMTQAITYPE_DRIVERVERSION_RENDER = 56, + KMTQAITYPE_ADAPTERTYPE_RENDER = 57, + KMTQAITYPE_WDDM_1_2_CAPS_RENDER = 58, + KMTQAITYPE_WDDM_1_3_CAPS_RENDER = 59, + KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, + KMTQAITYPE_NODEPERFDATA = 61, + KMTQAITYPE_ADAPTERPERFDATA = 62, + KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, + KMTQUITYPE_GPUVERSION = 64, +}} +STRUCT!{struct D3DKMT_QUERYADAPTERINFO { + hAdapter: D3DKMT_HANDLE, + Type: KMTQUERYADAPTERINFOTYPE, + pPrivateDriverData: *mut VOID, + PrivateDriverDataSize: UINT, +}} +STRUCT!{struct D3DKMT_OPENADAPTERFROMHDC { + hDc: HDC, + hAdapter: D3DKMT_HANDLE, + AdapterLuid: LUID, + VidPnSourceId: D3DDDI_VIDEO_PRESENT_SOURCE_ID, +}} +STRUCT!{struct D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME { + DeviceName: [WCHAR; 32], + hAdapter: D3DKMT_HANDLE, + AdapterLuid: LUID, + VidPnSourceId: D3DDDI_VIDEO_PRESENT_SOURCE_ID, +}} +STRUCT!{struct D3DKMT_OPENADAPTERFROMDEVICENAME { + pDeviceName: PCWSTR, + hAdapter: D3DKMT_HANDLE, + AdapterLuid: LUID, +}} +pub const MAX_ENUM_ADAPTERS: usize = 16; +STRUCT!{struct D3DKMT_ADAPTERINFO { + hAdapter: D3DKMT_HANDLE, + AdapterLuid: LUID, + NumOfSources: ULONG, + bPresentMoveRegionsPreferred: BOOL, +}} +STRUCT!{struct D3DKMT_ENUMADAPTERS { + NumAdapters: ULONG, + Adapters: [D3DKMT_ADAPTERINFO; MAX_ENUM_ADAPTERS], +}} +STRUCT!{struct D3DKMT_ENUMADAPTERS2 { + NumAdapters: ULONG, + pAdapters: *mut D3DKMT_ADAPTERINFO, +}} +STRUCT!{struct D3DKMT_OPENADAPTERFROMLUID { + AdapterLuid: LUID, + hAdapter: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DKMT_QUERYREMOTEVIDPNSOURCEFROMGDIDISPLAYNAME { + DeviceName: [WCHAR; 32], + VidPnSourceId: D3DDDI_VIDEO_PRESENT_SOURCE_ID, +}} +STRUCT!{struct D3DKMT_CLOSEADAPTER { + hAdapter: D3DKMT_HANDLE, +}} diff --git a/winapi/src/km/mod.rs b/winapi/src/km/mod.rs new file mode 100644 index 000000000..480f1950f --- /dev/null +++ b/winapi/src/km/mod.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Headers for kernel mode +#[cfg(feature = "d3dkmthk")] pub mod d3dkmthk; diff --git a/winapi/src/lib.rs b/winapi/src/lib.rs new file mode 100644 index 000000000..5dc8fb485 --- /dev/null +++ b/winapi/src/lib.rs @@ -0,0 +1,70 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +#![cfg(windows)] +#![deny(unused, unused_qualifications)] +#![warn(unused_attributes)] +#![allow(bad_style, overflowing_literals, unused_macros)] +#![recursion_limit = "2563"] +#![no_std] +//Uncomment as needed or once minimum Rust version is bumped to 1.18 +//#![cfg_attr(feature = "cargo-clippy", warn(clippy::pedantic))] +//#![cfg_attr(feature = "cargo-clippy", allow(clippy::absurd_extreme_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::const_static_lifetime, clippy::doc_markdown, clippy::empty_enum, clippy::erasing_op, clippy::excessive_precision, clippy::expl_impl_clone_on_copy, clippy::identity_op, clippy::if_not_else, clippy::many_single_char_names, clippy::module_inception, clippy::cast_possible_truncation, clippy::too_many_arguments, clippy::transmute_int_to_float, clippy::trivially_copy_pass_by_ref, clippy::unreadable_literal, clippy::unseparated_literal_suffix, clippy::used_underscore_binding))] + +#[cfg(feature = "std")] +extern crate std; + +/// Hack for exported macros +#[doc(hidden)] +pub extern crate core as _core; + +// Modules +#[macro_use] +mod macros; +pub mod km; +pub mod shared; +pub mod um; +pub mod vc; +pub mod winrt; + +/// Built in primitive types provided by the C language +pub mod ctypes { + #[cfg(feature = "std")] + pub use std::os::raw::c_void; + #[cfg(not(feature = "std"))] + pub enum c_void {} + pub type c_char = i8; + pub type c_schar = i8; + pub type c_uchar = u8; + pub type c_short = i16; + pub type c_ushort = u16; + pub type c_int = i32; + pub type c_uint = u32; + pub type c_long = i32; + pub type c_ulong = u32; + pub type c_longlong = i64; + pub type c_ulonglong = u64; + pub type c_float = f32; + pub type c_double = f64; + pub type __int8 = i8; + pub type __uint8 = u8; + pub type __int16 = i16; + pub type __uint16 = u16; + pub type __int32 = i32; + pub type __uint32 = u32; + pub type __int64 = i64; + pub type __uint64 = u64; + pub type wchar_t = u16; +} +// This trait should be implemented for all COM interfaces +pub trait Interface { + // Returns the IID of the Interface + fn uuidof() -> shared::guiddef::GUID; +} +// This trait should be implemented for all COM classes +pub trait Class { + // Returns the CLSID of the Class + fn uuidof() -> shared::guiddef::GUID; +} diff --git a/winapi/src/macros.rs b/winapi/src/macros.rs new file mode 100644 index 000000000..b209b48a8 --- /dev/null +++ b/winapi/src/macros.rs @@ -0,0 +1,424 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Macros to make things easier to define +macro_rules! DECLARE_HANDLE { + ($name:ident, $inner:ident) => { + pub enum $inner {} + pub type $name = *mut $inner; + }; +} +macro_rules! MAKE_HRESULT { + ($sev:expr, $fac:expr, $code:expr) => { + ($sev << 31) | ($fac << 16) | $code + } +} +macro_rules! MAKE_SCODE { + ($sev:expr, $fac:expr, $code:expr) => { + ($sev << 31) | ($fac << 16) | $code + } +} +macro_rules! HIDP_ERROR_CODES { + ($sev:expr, $code:expr) => { + ($sev << 28) | (FACILITY_HID_ERROR_CODE << 16) | $code + } +} +macro_rules! MAKEFOURCC { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + ($a as u32) | (($b as u32) << 8) | (($c as u32) << 16) | (($d as u32) << 24) + } +} +#[macro_export] +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::shared::guiddef::GUID = $crate::shared::guiddef::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + } +} +#[macro_export] +macro_rules! DEFINE_PROPERTYKEY { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr, + $pid:expr + ) => { + pub const $name: $crate::shared::wtypes::PROPERTYKEY + = $crate::shared::wtypes::PROPERTYKEY { + fmtid: $crate::shared::guiddef::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }, + pid: $pid, + }; + } +} +#[macro_export] +macro_rules! DEFINE_DEVPROPKEY { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr, + $pid:expr + ) => { + pub const $name: DEVPROPKEY = DEVPROPKEY { + fmtid: $crate::shared::guiddef::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }, + pid: $pid, + }; + } +} +macro_rules! CTL_CODE { + ($DeviceType:expr, $Function:expr, $Method:expr, $Access:expr) => { + ($DeviceType << 16) | ($Access << 14) | ($Function << 2) | $Method + } +} +macro_rules! HID_CTL_CODE { + ($id:expr) => { + CTL_CODE!(FILE_DEVICE_KEYBOARD, $id, METHOD_NEITHER, FILE_ANY_ACCESS) + } +} +macro_rules! HID_BUFFER_CTL_CODE { + ($id:expr) => { + CTL_CODE!(FILE_DEVICE_KEYBOARD, $id, METHOD_BUFFERED, FILE_ANY_ACCESS) + } +} +macro_rules! HID_IN_CTL_CODE { + ($id:expr) => { + CTL_CODE!(FILE_DEVICE_KEYBOARD, $id, METHOD_IN_DIRECT, FILE_ANY_ACCESS) + } +} +macro_rules! HID_OUT_CTL_CODE { + ($id:expr) => { + CTL_CODE!(FILE_DEVICE_KEYBOARD, $id, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + } +} +macro_rules! AUDCLNT_ERR { + ($n:expr) => { + MAKE_HRESULT!(SEVERITY_ERROR, FACILITY_AUDCLNT, $n) + }; +} +macro_rules! AUDCLNT_SUCCESS { + ($n:expr) => { + MAKE_SCODE!(SEVERITY_SUCCESS, FACILITY_AUDCLNT, $n) + }; +} +macro_rules! BCRYPT_MAKE_INTERFACE_VERSION { + ($major:expr, $minor:expr) => { + $crate::shared::bcrypt::BCRYPT_INTERFACE_VERSION { + MajorVersion: $major, MinorVersion: $minor, + } + } +} +macro_rules! MAKEINTRESOURCE { + ($i:expr) => { $i as u16 as usize as LPWSTR } +} +#[macro_export] +macro_rules! RIDL { + (#[uuid($l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr)] + class $class:ident;) => ( + pub enum $class {} + impl $crate::Class for $class { + #[inline] + fn uuidof() -> $crate::shared::guiddef::GUID { + $crate::shared::guiddef::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + $(#[$($attrs:tt)*])* fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + RIDL!{@vtbl $interface $vtbl () $( + $(#[$($attrs)*])* fn $method($($p: $t,)*) -> $rtr, + )+} + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + impl $interface { + $(RIDL!{@method $(#[$($attrs)*])* fn $method($($p: $t,)*) -> $rtr})+ + } + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {}) => ( + RIDL!{@vtbl $interface $vtbl (pub parent: $pvtbl,)} + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + $(#[$($attrs:tt)*])* fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + RIDL!{@vtbl $interface $vtbl (pub parent: $pvtbl,) $( + $(#[$($attrs)*])* fn $method($($p: $t,)*) -> $rtr, + )+} + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + impl $interface { + $(RIDL!{@method $(#[$($attrs)*])* fn $method($($p: $t,)*) -> $rtr})+ + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl $crate::_core::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@method fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty) => ( + #[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + } + ); + (@method #[fixme] fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty) => ( + #[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + let mut ret = $crate::_core::mem::uninitialized(); + ((*self.lpVtbl).$method)(self as *const _ as *mut _, &mut ret, $($p,)*); + ret + } + ); + (@vtbl $interface:ident $vtbl:ident ($($fields:tt)*) + $(fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty,)* + ) => ( + RIDL!{@item #[repr(C)] + pub struct $vtbl { + $($fields)* + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)* + }} + ); + (@vtbl $interface:ident $vtbl:ident ($($fields:tt)*) + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + $($tail:tt)*) => ( + RIDL!{@vtbl $interface $vtbl ( + $($fields)* + pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr, + ) $($tail)*} + ); + (@vtbl $interface:ident $vtbl:ident ($($fields:tt)*) + #[fixme] fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + $($tail:tt)*) => ( + RIDL!{@vtbl $interface $vtbl ( + $($fields)* + pub $method: unsafe extern "system" fn( + This: *mut $interface, + ret: *mut $rtr, + $($p: $t,)* + ) -> *mut $rtr, + ) $($tail)*} + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::Interface for $interface { + #[inline] + fn uuidof() -> $crate::shared::guiddef::GUID { + $crate::shared::guiddef::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); + (@item $thing:item) => ($thing); +} +macro_rules! UNION { + ($(#[$attrs:meta])* union $name:ident { + [$stype:ty; $ssize:expr], + $($variant:ident $variant_mut:ident: $ftype:ty,)+ + }) => ( + #[repr(C)] $(#[$attrs])* + pub struct $name([$stype; $ssize]); + impl Copy for $name {} + impl Clone for $name { + #[inline] + fn clone(&self) -> $name { *self } + } + #[cfg(feature = "impl-default")] + impl Default for $name { + #[inline] + fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } } + } + impl $name {$( + #[inline] + pub unsafe fn $variant(&self) -> &$ftype { + &*(self as *const _ as *const $ftype) + } + #[inline] + pub unsafe fn $variant_mut(&mut self) -> &mut $ftype { + &mut *(self as *mut _ as *mut $ftype) + } + )+} + ); + ($(#[$attrs:meta])* union $name:ident { + [$stype32:ty; $ssize32:expr] [$stype64:ty; $ssize64:expr], + $($variant:ident $variant_mut:ident: $ftype:ty,)+ + }) => ( + #[repr(C)] $(#[$attrs])* #[cfg(target_arch = "x86")] + pub struct $name([$stype32; $ssize32]); + #[repr(C)] $(#[$attrs])* #[cfg(target_pointer_width = "64")] + pub struct $name([$stype64; $ssize64]); + impl Copy for $name {} + impl Clone for $name { + #[inline] + fn clone(&self) -> $name { *self } + } + #[cfg(feature = "impl-default")] + impl Default for $name { + #[inline] + fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } } + } + impl $name {$( + #[inline] + pub unsafe fn $variant(&self) -> &$ftype { + &*(self as *const _ as *const $ftype) + } + #[inline] + pub unsafe fn $variant_mut(&mut self) -> &mut $ftype { + &mut *(self as *mut _ as *mut $ftype) + } + )+} + ); +} +macro_rules! BITFIELD { + ($base:ident $field:ident: $fieldtype:ty [ + $($thing:ident $set_thing:ident[$r:expr],)+ + ]) => { + impl $base {$( + #[inline] + pub fn $thing(&self) -> $fieldtype { + let size = $crate::core::mem::size_of::<$fieldtype>() * 8; + self.$field << (size - $r.end) >> (size - $r.end + $r.start) + } + #[inline] + pub fn $set_thing(&mut self, val: $fieldtype) { + let mask = ((1 << ($r.end - $r.start)) - 1) << $r.start; + self.$field &= !mask; + self.$field |= (val << $r.start) & mask; + } + )+} + } +} +#[macro_export] +macro_rules! ENUM { + {enum $name:ident { $($variant:ident = $value:expr,)+ }} => { + pub type $name = u32; + $(pub const $variant: $name = $value;)+ + }; + {enum $name:ident { $variant:ident = $value:expr, $($rest:tt)* }} => { + pub type $name = u32; + pub const $variant: $name = $value; + ENUM!{@gen $name $variant, $($rest)*} + }; + {enum $name:ident { $variant:ident, $($rest:tt)* }} => { + ENUM!{enum $name { $variant = 0, $($rest)* }} + }; + {@gen $name:ident $base:ident,} => {}; + {@gen $name:ident $base:ident, $variant:ident = $value:expr, $($rest:tt)*} => { + pub const $variant: $name = $value; + ENUM!{@gen $name $variant, $($rest)*} + }; + {@gen $name:ident $base:ident, $variant:ident, $($rest:tt)*} => { + pub const $variant: $name = $base + 1u32; + ENUM!{@gen $name $variant, $($rest)*} + }; +} +#[macro_export] +macro_rules! STRUCT { + (#[debug] $($rest:tt)*) => ( + STRUCT!{#[cfg_attr(feature = "impl-debug", derive(Debug))] $($rest)*} + ); + ($(#[$attrs:meta])* struct $name:ident { + $($field:ident: $ftype:ty,)+ + }) => ( + #[repr(C)] #[derive(Copy)] $(#[$attrs])* + pub struct $name { + $(pub $field: $ftype,)+ + } + impl Clone for $name { + #[inline] + fn clone(&self) -> $name { *self } + } + #[cfg(feature = "impl-default")] + impl Default for $name { + #[inline] + fn default() -> $name { unsafe { $crate::_core::mem::zeroed() } } + } + ); +} +macro_rules! IFDEF { + ($($thing:item)*) => ($($thing)*) +} +macro_rules! FN { + (stdcall $func:ident($($t:ty,)*) -> $ret:ty) => ( + pub type $func = Option<unsafe extern "system" fn($($t,)*) -> $ret>; + ); + (stdcall $func:ident($($p:ident: $t:ty,)*) -> $ret:ty) => ( + pub type $func = Option<unsafe extern "system" fn($($p: $t,)*) -> $ret>; + ); + (cdecl $func:ident($($t:ty,)*) -> $ret:ty) => ( + pub type $func = Option<unsafe extern "C" fn($($t,)*) -> $ret>; + ); + (cdecl $func:ident($($p:ident: $t:ty,)*) -> $ret:ty) => ( + pub type $func = Option<unsafe extern "C" fn($($p: $t,)*) -> $ret>; + ); +} +macro_rules! _WSAIO { + ($x:expr, $y:expr) => { + $crate::shared::ws2def::IOC_VOID | $x | $y + } +} +macro_rules! _WSAIOR { + ($x:expr, $y:expr) => { + $crate::shared::ws2def::IOC_OUT | $x | $y + } +} +macro_rules! _WSAIOW { + ($x:expr, $y:expr) => { + $crate::shared::ws2def::IOC_IN | $x | $y + } +} +macro_rules! _WSAIORW { + ($x:expr, $y:expr) => { + $crate::shared::ws2def::IOC_INOUT | $x | $y + } +} diff --git a/winapi/src/shared/basetsd.rs b/winapi/src/shared/basetsd.rs new file mode 100644 index 000000000..1870fd2d6 --- /dev/null +++ b/winapi/src/shared/basetsd.rs @@ -0,0 +1,70 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Type definitions for the basic sized types. +use ctypes::{__int64, __uint64, c_int, c_schar, c_short, c_uchar, c_uint, c_ushort}; +pub type POINTER_64_INT = usize; +pub type INT8 = c_schar; +pub type PINT8 = *mut c_schar; +pub type INT16 = c_short; +pub type PINT16 = *mut c_short; +pub type INT32 = c_int; +pub type PINT32 = *mut c_int; +pub type INT64 = __int64; +pub type PINT64 = *mut __int64; +pub type UINT8 = c_uchar; +pub type PUINT8 = *mut c_uchar; +pub type UINT16 = c_ushort; +pub type PUINT16 = *mut c_ushort; +pub type UINT32 = c_uint; +pub type PUINT32 = *mut c_uint; +pub type UINT64 = __uint64; +pub type PUINT64 = *mut __uint64; +pub type LONG32 = c_int; +pub type PLONG32 = *mut c_int; +pub type ULONG32 = c_uint; +pub type PULONG32 = *mut c_uint; +pub type DWORD32 = c_uint; +pub type PDWORD32 = *mut c_uint; +pub type INT_PTR = isize; +pub type PINT_PTR = *mut isize; +pub type UINT_PTR = usize; +pub type PUINT_PTR = *mut usize; +pub type LONG_PTR = isize; +pub type PLONG_PTR = *mut isize; +pub type ULONG_PTR = usize; +pub type PULONG_PTR = *mut usize; +pub type SHANDLE_PTR = isize; +pub type HANDLE_PTR = usize; +#[cfg(target_arch = "x86")] +pub type UHALF_PTR = c_ushort; +#[cfg(target_pointer_width = "64")] +pub type UHALF_PTR = c_uint; +#[cfg(target_arch = "x86")] +pub type PUHALF_PTR = *mut c_ushort; +#[cfg(target_pointer_width = "64")] +pub type PUHALF_PTR = *mut c_uint; +#[cfg(target_arch = "x86")] +pub type HALF_PTR = c_short; +#[cfg(target_pointer_width = "64")] +pub type HALF_PTR = c_int; +#[cfg(target_arch = "x86")] +pub type PHALF_PTR = *mut c_short; +#[cfg(target_pointer_width = "64")] +pub type PHALF_PTR = *mut c_int; +pub type SIZE_T = ULONG_PTR; +pub type PSIZE_T = *mut ULONG_PTR; +pub type SSIZE_T = LONG_PTR; +pub type PSSIZE_T = *mut LONG_PTR; +pub type DWORD_PTR = ULONG_PTR; +pub type PDWORD_PTR = *mut ULONG_PTR; +pub type LONG64 = __int64; +pub type PLONG64 = *mut __int64; +pub type ULONG64 = __uint64; +pub type PULONG64 = *mut __uint64; +pub type DWORD64 = __uint64; +pub type PDWORD64 = *mut __uint64; +pub type KAFFINITY = ULONG_PTR; +pub type PKAFFINITY = *mut KAFFINITY; diff --git a/winapi/src/shared/bcrypt.rs b/winapi/src/shared/bcrypt.rs new file mode 100644 index 000000000..4fa88ef8f --- /dev/null +++ b/winapi/src/shared/bcrypt.rs @@ -0,0 +1,1001 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Cryptographic Primitive API Prototypes and Definitions +use shared::minwindef::{PUCHAR, UCHAR, ULONG, USHORT}; +use um::winnt::{BOOLEAN, HANDLE, LONG, LPCWSTR, LPWSTR, PVOID, PWSTR, ULONGLONG, VOID}; +pub type NTSTATUS = LONG; +pub type PNTSTATUS = *mut NTSTATUS; +#[inline] +pub fn BCRYPT_SUCCESS(Status: NTSTATUS) -> bool { + Status >= 0 +} +pub const BCRYPT_OBJECT_ALIGNMENT: usize = 16; +pub const BCRYPT_KDF_HASH: &'static str = "HASH"; +pub const BCRYPT_KDF_HMAC: &'static str = "HMAC"; +pub const BCRYPT_KDF_TLS_PRF: &'static str = "TLS_PRF"; +pub const BCRYPT_KDF_SP80056A_CONCAT: &'static str = "SP800_56A_CONCAT"; +pub const BCRYPT_KDF_RAW_SECRET: &'static str = "TRUNCATE"; +pub const KDF_HASH_ALGORITHM: ULONG = 0x0; +pub const KDF_SECRET_PREPEND: ULONG = 0x1; +pub const KDF_SECRET_APPEND: ULONG = 0x2; +pub const KDF_HMAC_KEY: ULONG = 0x3; +pub const KDF_TLS_PRF_LABEL: ULONG = 0x4; +pub const KDF_TLS_PRF_SEED: ULONG = 0x5; +pub const KDF_SECRET_HANDLE: ULONG = 0x6; +pub const KDF_TLS_PRF_PROTOCOL: ULONG = 0x7; +pub const KDF_ALGORITHMID: ULONG = 0x8; +pub const KDF_PARTYUINFO: ULONG = 0x9; +pub const KDF_PARTYVINFO: ULONG = 0xA; +pub const KDF_SUPPPUBINFO: ULONG = 0xB; +pub const KDF_SUPPPRIVINFO: ULONG = 0xC; +pub const KDF_LABEL: ULONG = 0xD; +pub const KDF_CONTEXT: ULONG = 0xE; +pub const KDF_SALT: ULONG = 0xF; +pub const KDF_ITERATION_COUNT: ULONG = 0x10; +pub const KDF_GENERIC_PARAMETER: ULONG = 0x11; +pub const KDF_KEYBITLENGTH: ULONG = 0x12; +pub const KDF_USE_SECRET_AS_HMAC_KEY_FLAG: ULONG = 0x1; +STRUCT!{struct BCRYPT_KEY_LENGTHS_STRUCT { + dwMinLength: ULONG, + dwMaxLength: ULONG, + dwIncrement: ULONG, +}} +pub type BCRYPT_AUTH_TAG_LENGTHS_STRUCT = BCRYPT_KEY_LENGTHS_STRUCT; +STRUCT!{struct BCRYPT_OID { + cbOID: ULONG, + pbOID: PUCHAR, +}} +STRUCT!{struct BCRYPT_OID_LIST { + dwOIDCount: ULONG, + pOIDs: *mut BCRYPT_OID, +}} +STRUCT!{struct BCRYPT_PKCS1_PADDING_INFO { + pszAlgId: LPCWSTR, +}} +STRUCT!{struct BCRYPT_PSS_PADDING_INFO { + pszAlgId: LPCWSTR, + cbSalt: ULONG, +}} +STRUCT!{struct BCRYPT_OAEP_PADDING_INFO { + pszAlgId: LPCWSTR, + pbLabel: PUCHAR, + cbLabel: ULONG, +}} +pub const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION: ULONG = 1; +pub const BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG: ULONG = 0x00000001; +pub const BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG: ULONG = 0x00000002; +STRUCT!{struct BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO { + cbSize: ULONG, + dwInfoVersion: ULONG, + pbNonce: PUCHAR, + cbNonce: ULONG, + pbAuthData: PUCHAR, + cbAuthData: ULONG, + pbTag: PUCHAR, + cbTag: ULONG, + pbMacContext: PUCHAR, + cbMacContext: ULONG, + cbAAD: ULONG, + cbData: ULONGLONG, + dwFlags: ULONG, +}} +pub type PBCRYPT_AUTHENTICATED_CIPHER_MODE_INFO = *mut BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO; +pub const BCRYPT_OPAQUE_KEY_BLOB: &'static str = "OpaqueKeyBlob"; +pub const BCRYPT_KEY_DATA_BLOB: &'static str = "KeyDataBlob"; +pub const BCRYPT_AES_WRAP_KEY_BLOB: &'static str = "Rfc3565KeyWrapBlob"; +pub const BCRYPT_OBJECT_LENGTH: &'static str = "ObjectLength"; +pub const BCRYPT_ALGORITHM_NAME: &'static str = "AlgorithmName"; +pub const BCRYPT_PROVIDER_HANDLE: &'static str = "ProviderHandle"; +pub const BCRYPT_CHAINING_MODE: &'static str = "ChainingMode"; +pub const BCRYPT_BLOCK_LENGTH: &'static str = "BlockLength"; +pub const BCRYPT_KEY_LENGTH: &'static str = "KeyLength"; +pub const BCRYPT_KEY_OBJECT_LENGTH: &'static str = "KeyObjectLength"; +pub const BCRYPT_KEY_STRENGTH: &'static str = "KeyStrength"; +pub const BCRYPT_KEY_LENGTHS: &'static str = "KeyLengths"; +pub const BCRYPT_BLOCK_SIZE_LIST: &'static str = "BlockSizeList"; +pub const BCRYPT_EFFECTIVE_KEY_LENGTH: &'static str = "EffectiveKeyLength"; +pub const BCRYPT_HASH_LENGTH: &'static str = "HashDigestLength"; +pub const BCRYPT_HASH_OID_LIST: &'static str = "HashOIDList"; +pub const BCRYPT_PADDING_SCHEMES: &'static str = "PaddingSchemes"; +pub const BCRYPT_SIGNATURE_LENGTH: &'static str = "SignatureLength"; +pub const BCRYPT_HASH_BLOCK_LENGTH: &'static str = "HashBlockLength"; +pub const BCRYPT_AUTH_TAG_LENGTH: &'static str = "AuthTagLength"; +pub const BCRYPT_PRIMITIVE_TYPE: &'static str = "PrimitiveType"; +pub const BCRYPT_IS_KEYED_HASH: &'static str = "IsKeyedHash"; +pub const BCRYPT_IS_REUSABLE_HASH: &'static str = "IsReusableHash"; +pub const BCRYPT_MESSAGE_BLOCK_LENGTH: &'static str = "MessageBlockLength"; +pub const BCRYPT_PUBLIC_KEY_LENGTH: &'static str = "PublicKeyLength"; +pub const BCRYPT_PCP_PLATFORM_TYPE_PROPERTY: &'static str = "PCP_PLATFORM_TYPE"; +pub const BCRYPT_PCP_PROVIDER_VERSION_PROPERTY: &'static str = "PCP_PROVIDER_VERSION"; +pub const BCRYPT_MULTI_OBJECT_LENGTH: &'static str = "MultiObjectLength"; +pub const BCRYPT_INITIALIZATION_VECTOR: &'static str = "IV"; +pub const BCRYPT_CHAIN_MODE_NA: &'static str = "ChainingModeN/A"; +pub const BCRYPT_CHAIN_MODE_CBC: &'static str = "ChainingModeCBC"; +pub const BCRYPT_CHAIN_MODE_ECB: &'static str = "ChainingModeECB"; +pub const BCRYPT_CHAIN_MODE_CFB: &'static str = "ChainingModeCFB"; +pub const BCRYPT_CHAIN_MODE_CCM: &'static str = "ChainingModeCCM"; +pub const BCRYPT_CHAIN_MODE_GCM: &'static str = "ChainingModeGCM"; +pub const BCRYPT_PROV_DISPATCH: ULONG = 0x00000001; +pub const BCRYPT_BLOCK_PADDING: ULONG = 0x00000001; +pub const BCRYPT_PAD_NONE: ULONG = 0x00000001; +pub const BCRYPT_PAD_PKCS1: ULONG = 0x00000002; +pub const BCRYPT_PAD_OAEP: ULONG = 0x00000004; +pub const BCRYPT_PAD_PSS: ULONG = 0x00000008; +pub const BCRYPT_PAD_PKCS1_OPTIONAL_HASH_OID: ULONG = 0x00000010; +pub const BCRYPTBUFFER_VERSION: ULONG = 0; +STRUCT!{struct BCryptBuffer { + cbBuffer: ULONG, + BufferType: ULONG, + pvBuffer: PVOID, +}} +pub type PBCryptBuffer = *mut BCryptBuffer; +STRUCT!{struct BCryptBufferDesc { + ulVersion: ULONG, + cBuffers: ULONG, + pBuffers: PBCryptBuffer, +}} +pub type PBCryptBufferDesc = *mut BCryptBufferDesc; +pub type BCRYPT_HANDLE = PVOID; +pub type BCRYPT_ALG_HANDLE = PVOID; +pub type BCRYPT_KEY_HANDLE = PVOID; +pub type BCRYPT_HASH_HANDLE = PVOID; +pub type BCRYPT_SECRET_HANDLE = PVOID; +pub const BCRYPT_PUBLIC_KEY_BLOB: &'static str = "PUBLICBLOB"; +pub const BCRYPT_PRIVATE_KEY_BLOB: &'static str = "PRIVATEBLOB"; +STRUCT!{struct BCRYPT_KEY_BLOB { + Magic: ULONG, +}} +pub const BCRYPT_RSAPUBLIC_BLOB: &'static str = "RSAPUBLICBLOB"; +pub const BCRYPT_RSAPRIVATE_BLOB: &'static str = "RSAPRIVATEBLOB"; +pub const LEGACY_RSAPUBLIC_BLOB: &'static str = "CAPIPUBLICBLOB"; +pub const LEGACY_RSAPRIVATE_BLOB: &'static str = "CAPIPRIVATEBLOB"; +pub const BCRYPT_RSAPUBLIC_MAGIC: ULONG = 0x31415352; +pub const BCRYPT_RSAPRIVATE_MAGIC: ULONG = 0x32415352; +STRUCT!{struct BCRYPT_RSAKEY_BLOB { + Magic: ULONG, + BitLength: ULONG, + cbPublicExp: ULONG, + cbModulus: ULONG, + cbPrime1: ULONG, + cbPrime2: ULONG, +}} +pub const BCRYPT_RSAFULLPRIVATE_BLOB: &'static str = "RSAFULLPRIVATEBLOB"; +pub const BCRYPT_RSAFULLPRIVATE_MAGIC: ULONG = 0x33415352; +pub const BCRYPT_GLOBAL_PARAMETERS: &'static str = "SecretAgreementParam"; +pub const BCRYPT_PRIVATE_KEY: &'static str = "PrivKeyVal"; +pub const BCRYPT_ECCPUBLIC_BLOB: &'static str = "ECCPUBLICBLOB"; +pub const BCRYPT_ECCPRIVATE_BLOB: &'static str = "ECCPRIVATEBLOB"; +pub const BCRYPT_ECCFULLPUBLIC_BLOB: &'static str = "ECCFULLPUBLICBLOB"; +pub const BCRYPT_ECCFULLPRIVATE_BLOB: &'static str = "ECCFULLPRIVATEBLOB"; +pub const SSL_ECCPUBLIC_BLOB: &'static str = "SSLECCPUBLICBLOB"; +pub const BCRYPT_ECDH_PUBLIC_P256_MAGIC: ULONG = 0x314B4345; +pub const BCRYPT_ECDH_PRIVATE_P256_MAGIC: ULONG = 0x324B4345; +pub const BCRYPT_ECDH_PUBLIC_P384_MAGIC: ULONG = 0x334B4345; +pub const BCRYPT_ECDH_PRIVATE_P384_MAGIC: ULONG = 0x344B4345; +pub const BCRYPT_ECDH_PUBLIC_P521_MAGIC: ULONG = 0x354B4345; +pub const BCRYPT_ECDH_PRIVATE_P521_MAGIC: ULONG = 0x364B4345; +pub const BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC: ULONG = 0x504B4345; +pub const BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC: ULONG = 0x564B4345; +pub const BCRYPT_ECDSA_PUBLIC_P256_MAGIC: ULONG = 0x31534345; +pub const BCRYPT_ECDSA_PRIVATE_P256_MAGIC: ULONG = 0x32534345; +pub const BCRYPT_ECDSA_PUBLIC_P384_MAGIC: ULONG = 0x33534345; +pub const BCRYPT_ECDSA_PRIVATE_P384_MAGIC: ULONG = 0x34534345; +pub const BCRYPT_ECDSA_PUBLIC_P521_MAGIC: ULONG = 0x35534345; +pub const BCRYPT_ECDSA_PRIVATE_P521_MAGIC: ULONG = 0x36534345; +pub const BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC: ULONG = 0x50444345; +pub const BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC: ULONG = 0x56444345; +STRUCT!{struct BCRYPT_ECCKEY_BLOB { + dwMagic: ULONG, + cbKey: ULONG, +}} +pub type PBCRYPT_ECCKEY_BLOB = *mut BCRYPT_ECCKEY_BLOB; +STRUCT!{struct SSL_ECCKEY_BLOB { + dwCurveType: ULONG, + cbKey: ULONG, +}} +pub type PSSL_ECCKEY_BLOB = *mut SSL_ECCKEY_BLOB; +pub const BCRYPT_ECC_FULLKEY_BLOB_V1: ULONG = 0x1; +ENUM!{enum ECC_CURVE_TYPE_ENUM { + BCRYPT_ECC_PRIME_SHORT_WEIERSTRASS_CURVE = 0x1, + BCRYPT_ECC_PRIME_TWISTED_EDWARDS_CURVE = 0x2, + BCRYPT_ECC_PRIME_MONTGOMERY_CURVE = 0x3, +}} +ENUM!{enum ECC_CURVE_ALG_ID_ENUM { + BCRYPT_NO_CURVE_GENERATION_ALG_ID = 0x0, +}} +STRUCT!{struct BCRYPT_ECCFULLKEY_BLOB { + dwMagic: ULONG, + dwVersion: ULONG, + dwCurveType: ECC_CURVE_TYPE_ENUM, + dwCurveGenerationAlgId: ECC_CURVE_ALG_ID_ENUM, + cbFieldLength: ULONG, + cbSubgroupOrder: ULONG, + cbCofactor: ULONG, + cbSeed: ULONG, +}} +pub type PBCRYPT_ECCFULLKEY_BLOB = *mut BCRYPT_ECCFULLKEY_BLOB; +pub const BCRYPT_DH_PUBLIC_BLOB: &'static str = "DHPUBLICBLOB"; +pub const BCRYPT_DH_PRIVATE_BLOB: &'static str = "DHPRIVATEBLOB"; +pub const LEGACY_DH_PUBLIC_BLOB: &'static str = "CAPIDHPUBLICBLOB"; +pub const LEGACY_DH_PRIVATE_BLOB: &'static str = "CAPIDHPRIVATEBLOB"; +pub const BCRYPT_DH_PUBLIC_MAGIC: ULONG = 0x42504844; +pub const BCRYPT_DH_PRIVATE_MAGIC: ULONG = 0x56504844; +STRUCT!{struct BCRYPT_DH_KEY_BLOB { + dwMagic: ULONG, + cbKey: ULONG, +}} +pub type PBCRYPT_DH_KEY_BLOB = *mut BCRYPT_DH_KEY_BLOB; +pub const BCRYPT_DH_PARAMETERS: &'static str = "DHParameters"; +pub const BCRYPT_DH_PARAMETERS_MAGIC: ULONG = 0x4d504844; +STRUCT!{struct BCRYPT_DH_PARAMETER_HEADER { + cbLength: ULONG, + dwMagic: ULONG, + cbKeyLength: ULONG, +}} +pub const BCRYPT_DSA_PUBLIC_BLOB: &'static str = "DSAPUBLICBLOB"; +pub const BCRYPT_DSA_PRIVATE_BLOB: &'static str = "DSAPRIVATEBLOB"; +pub const LEGACY_DSA_PUBLIC_BLOB: &'static str = "CAPIDSAPUBLICBLOB"; +pub const LEGACY_DSA_PRIVATE_BLOB: &'static str = "CAPIDSAPRIVATEBLOB"; +pub const LEGACY_DSA_V2_PUBLIC_BLOB: &'static str = "V2CAPIDSAPUBLICBLOB"; +pub const LEGACY_DSA_V2_PRIVATE_BLOB: &'static str = "V2CAPIDSAPRIVATEBLOB"; +pub const BCRYPT_DSA_PUBLIC_MAGIC: ULONG = 0x42505344; +pub const BCRYPT_DSA_PRIVATE_MAGIC: ULONG = 0x56505344; +pub const BCRYPT_DSA_PUBLIC_MAGIC_V2: ULONG = 0x32425044; +pub const BCRYPT_DSA_PRIVATE_MAGIC_V2: ULONG = 0x32565044; +STRUCT!{struct BCRYPT_DSA_KEY_BLOB { + dwMagic: ULONG, + cbKey: ULONG, + Count: [UCHAR; 4], + Seed: [UCHAR; 20], + q: [UCHAR; 20], +}} +pub type PBCRYPT_DSA_KEY_BLOB = *mut BCRYPT_DSA_KEY_BLOB; +ENUM!{enum HASHALGORITHM_ENUM { + DSA_HASH_ALGORITHM_SHA1, + DSA_HASH_ALGORITHM_SHA256, + DSA_HASH_ALGORITHM_SHA512, +}} +ENUM!{enum DSAFIPSVERSION_ENUM { + DSA_FIPS186_2, + DSA_FIPS186_3, +}} +STRUCT!{struct BCRYPT_DSA_KEY_BLOB_V2 { + dwMagic: ULONG, + cbKey: ULONG, + hashAlgorithm: HASHALGORITHM_ENUM, + standardVersion: DSAFIPSVERSION_ENUM, + cbSeedLength: ULONG, + cbGroupSize: ULONG, + Count: [UCHAR; 4], +}} +pub type PBCRYPT_DSA_KEY_BLOB_V2 = *mut BCRYPT_DSA_KEY_BLOB_V2; +STRUCT!{struct BCRYPT_KEY_DATA_BLOB_HEADER { + dwMagic: ULONG, + dwVersion: ULONG, + cbKeyData: ULONG, +}} +pub type PBCRYPT_KEY_DATA_BLOB_HEADER = *mut BCRYPT_KEY_DATA_BLOB_HEADER; +pub const BCRYPT_KEY_DATA_BLOB_MAGIC: ULONG = 0x4d42444b; +pub const BCRYPT_KEY_DATA_BLOB_VERSION1: ULONG = 0x1; +pub const BCRYPT_DSA_PARAMETERS: &'static str = "DSAParameters"; +pub const BCRYPT_DSA_PARAMETERS_MAGIC: ULONG = 0x4d505344; +pub const BCRYPT_DSA_PARAMETERS_MAGIC_V2: ULONG = 0x324d5044; +STRUCT!{struct BCRYPT_DSA_PARAMETER_HEADER { + cbLength: ULONG, + dwMagic: ULONG, + cbKeyLength: ULONG, + Count: [UCHAR; 4], + Seed: [UCHAR; 20], + q: [UCHAR; 20], +}} +STRUCT!{struct BCRYPT_DSA_PARAMETER_HEADER_V2 { + cbLength: ULONG, + dwMagic: ULONG, + cbKeyLength: ULONG, + hashAlgorithm: HASHALGORITHM_ENUM, + standardVersion: DSAFIPSVERSION_ENUM, + cbSeedLength: ULONG, + cbGroupSize: ULONG, + Count: [UCHAR; 4], +}} +pub const BCRYPT_ECC_PARAMETERS: &'static str = "ECCParameters"; +pub const BCRYPT_ECC_CURVE_NAME: &'static str = "ECCCurveName"; +pub const BCRYPT_ECC_CURVE_NAME_LIST: &'static str = "ECCCurveNameList"; +pub const BCRYPT_ECC_PARAMETERS_MAGIC: ULONG = 0x50434345; +STRUCT!{struct BCRYPT_ECC_CURVE_NAMES { + dwEccCurveNames: ULONG, + pEccCurveNames: LPWSTR, +}} +pub const BCRYPT_ECC_CURVE_BRAINPOOLP160R1: &'static str = "brainpoolP160r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP160T1: &'static str = "brainpoolP160t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP192R1: &'static str = "brainpoolP192r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP192T1: &'static str = "brainpoolP192t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP224R1: &'static str = "brainpoolP224r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP224T1: &'static str = "brainpoolP224t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP256R1: &'static str = "brainpoolP256r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP256T1: &'static str = "brainpoolP256t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP320R1: &'static str = "brainpoolP320r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP320T1: &'static str = "brainpoolP320t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP384R1: &'static str = "brainpoolP384r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP384T1: &'static str = "brainpoolP384t1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP512R1: &'static str = "brainpoolP512r1"; +pub const BCRYPT_ECC_CURVE_BRAINPOOLP512T1: &'static str = "brainpoolP512t1"; +pub const BCRYPT_ECC_CURVE_25519: &'static str = "curve25519"; +pub const BCRYPT_ECC_CURVE_EC192WAPI: &'static str = "ec192wapi"; +pub const BCRYPT_ECC_CURVE_NISTP192: &'static str = "nistP192"; +pub const BCRYPT_ECC_CURVE_NISTP224: &'static str = "nistP224"; +pub const BCRYPT_ECC_CURVE_NISTP256: &'static str = "nistP256"; +pub const BCRYPT_ECC_CURVE_NISTP384: &'static str = "nistP384"; +pub const BCRYPT_ECC_CURVE_NISTP521: &'static str = "nistP521"; +pub const BCRYPT_ECC_CURVE_NUMSP256T1: &'static str = "numsP256t1"; +pub const BCRYPT_ECC_CURVE_NUMSP384T1: &'static str = "numsP384t1"; +pub const BCRYPT_ECC_CURVE_NUMSP512T1: &'static str = "numsP512t1"; +pub const BCRYPT_ECC_CURVE_SECP160K1: &'static str = "secP160k1"; +pub const BCRYPT_ECC_CURVE_SECP160R1: &'static str = "secP160r1"; +pub const BCRYPT_ECC_CURVE_SECP160R2: &'static str = "secP160r2"; +pub const BCRYPT_ECC_CURVE_SECP192K1: &'static str = "secP192k1"; +pub const BCRYPT_ECC_CURVE_SECP192R1: &'static str = "secP192r1"; +pub const BCRYPT_ECC_CURVE_SECP224K1: &'static str = "secP224k1"; +pub const BCRYPT_ECC_CURVE_SECP224R1: &'static str = "secP224r1"; +pub const BCRYPT_ECC_CURVE_SECP256K1: &'static str = "secP256k1"; +pub const BCRYPT_ECC_CURVE_SECP256R1: &'static str = "secP256r1"; +pub const BCRYPT_ECC_CURVE_SECP384R1: &'static str = "secP384r1"; +pub const BCRYPT_ECC_CURVE_SECP521R1: &'static str = "secP521r1"; +pub const BCRYPT_ECC_CURVE_WTLS7: &'static str = "wtls7"; +pub const BCRYPT_ECC_CURVE_WTLS9: &'static str = "wtls9"; +pub const BCRYPT_ECC_CURVE_WTLS12: &'static str = "wtls12"; +pub const BCRYPT_ECC_CURVE_X962P192V1: &'static str = "x962P192v1"; +pub const BCRYPT_ECC_CURVE_X962P192V2: &'static str = "x962P192v2"; +pub const BCRYPT_ECC_CURVE_X962P192V3: &'static str = "x962P192v3"; +pub const BCRYPT_ECC_CURVE_X962P239V1: &'static str = "x962P239v1"; +pub const BCRYPT_ECC_CURVE_X962P239V2: &'static str = "x962P239v2"; +pub const BCRYPT_ECC_CURVE_X962P239V3: &'static str = "x962P239v3"; +pub const BCRYPT_ECC_CURVE_X962P256V1: &'static str = "x962P256v1"; +ENUM!{enum BCRYPT_HASH_OPERATION_TYPE { + BCRYPT_HASH_OPERATION_HASH_DATA = 1, + BCRYPT_HASH_OPERATION_FINISH_HASH = 2, +}} +STRUCT!{struct BCRYPT_MULTI_HASH_OPERATION { + iHash: ULONG, + hashOperation: BCRYPT_HASH_OPERATION_TYPE, + pbBuffer: PUCHAR, + cbBuffer: ULONG, +}} +ENUM!{enum BCRYPT_MULTI_OPERATION_TYPE { + BCRYPT_OPERATION_TYPE_HASH = 1, +}} +STRUCT!{struct BCRYPT_MULTI_OBJECT_LENGTH_STRUCT { + cbPerObject: ULONG, + cbPerElement: ULONG, +}} +pub const MS_PRIMITIVE_PROVIDER: &'static str = "Microsoft Primitive Provider"; +pub const MS_PLATFORM_CRYPTO_PROVIDER: &'static str = "Microsoft Platform Crypto Provider"; +pub const BCRYPT_RSA_ALGORITHM: &'static str = "RSA"; +pub const BCRYPT_RSA_SIGN_ALGORITHM: &'static str = "RSA_SIGN"; +pub const BCRYPT_DH_ALGORITHM: &'static str = "DH"; +pub const BCRYPT_DSA_ALGORITHM: &'static str = "DSA"; +pub const BCRYPT_RC2_ALGORITHM: &'static str = "RC2"; +pub const BCRYPT_RC4_ALGORITHM: &'static str = "RC4"; +pub const BCRYPT_AES_ALGORITHM: &'static str = "AES"; +pub const BCRYPT_DES_ALGORITHM: &'static str = "DES"; +pub const BCRYPT_DESX_ALGORITHM: &'static str = "DESX"; +pub const BCRYPT_3DES_ALGORITHM: &'static str = "3DES"; +pub const BCRYPT_3DES_112_ALGORITHM: &'static str = "3DES_112"; +pub const BCRYPT_MD2_ALGORITHM: &'static str = "MD2"; +pub const BCRYPT_MD4_ALGORITHM: &'static str = "MD4"; +pub const BCRYPT_MD5_ALGORITHM: &'static str = "MD5"; +pub const BCRYPT_SHA1_ALGORITHM: &'static str = "SHA1"; +pub const BCRYPT_SHA256_ALGORITHM: &'static str = "SHA256"; +pub const BCRYPT_SHA384_ALGORITHM: &'static str = "SHA384"; +pub const BCRYPT_SHA512_ALGORITHM: &'static str = "SHA512"; +pub const BCRYPT_AES_GMAC_ALGORITHM: &'static str = "AES-GMAC"; +pub const BCRYPT_AES_CMAC_ALGORITHM: &'static str = "AES-CMAC"; +pub const BCRYPT_ECDSA_P256_ALGORITHM: &'static str = "ECDSA_P256"; +pub const BCRYPT_ECDSA_P384_ALGORITHM: &'static str = "ECDSA_P384"; +pub const BCRYPT_ECDSA_P521_ALGORITHM: &'static str = "ECDSA_P521"; +pub const BCRYPT_ECDH_P256_ALGORITHM: &'static str = "ECDH_P256"; +pub const BCRYPT_ECDH_P384_ALGORITHM: &'static str = "ECDH_P384"; +pub const BCRYPT_ECDH_P521_ALGORITHM: &'static str = "ECDH_P521"; +pub const BCRYPT_RNG_ALGORITHM: &'static str = "RNG"; +pub const BCRYPT_RNG_FIPS186_DSA_ALGORITHM: &'static str = "FIPS186DSARNG"; +pub const BCRYPT_RNG_DUAL_EC_ALGORITHM: &'static str = "DUALECRNG"; +pub const BCRYPT_SP800108_CTR_HMAC_ALGORITHM: &'static str = "SP800_108_CTR_HMAC"; +pub const BCRYPT_SP80056A_CONCAT_ALGORITHM: &'static str = "SP800_56A_CONCAT"; +pub const BCRYPT_PBKDF2_ALGORITHM: &'static str = "PBKDF2"; +pub const BCRYPT_CAPI_KDF_ALGORITHM: &'static str = "CAPI_KDF"; +pub const BCRYPT_TLS1_1_KDF_ALGORITHM: &'static str = "TLS1_1_KDF"; +pub const BCRYPT_TLS1_2_KDF_ALGORITHM: &'static str = "TLS1_2_KDF"; +pub const BCRYPT_ECDSA_ALGORITHM: &'static str = "ECDSA"; +pub const BCRYPT_ECDH_ALGORITHM: &'static str = "ECDH"; +pub const BCRYPT_XTS_AES_ALGORITHM: &'static str = "XTS-AES"; +pub const BCRYPT_CIPHER_INTERFACE: ULONG = 0x00000001; +pub const BCRYPT_HASH_INTERFACE: ULONG = 0x00000002; +pub const BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE: ULONG = 0x00000003; +pub const BCRYPT_SECRET_AGREEMENT_INTERFACE: ULONG = 0x00000004; +pub const BCRYPT_SIGNATURE_INTERFACE: ULONG = 0x00000005; +pub const BCRYPT_RNG_INTERFACE: ULONG = 0x00000006; +pub const BCRYPT_KEY_DERIVATION_INTERFACE: ULONG = 0x00000007; +pub const BCRYPT_MD2_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000001 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_MD4_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000011 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_MD5_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000021 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SHA1_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000031 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SHA256_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000041 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SHA384_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000051 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SHA512_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000061 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RC4_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000071 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RNG_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000081 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_MD5_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000091 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_SHA1_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000a1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_SHA256_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000b1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_SHA384_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000c1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_SHA512_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000d1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RSA_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000e1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDSA_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000000f1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_CMAC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000101 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_GMAC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000111 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_MD2_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000121 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_HMAC_MD4_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000131 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000141 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000151 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000161 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_112_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000171 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_112_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000181 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_3DES_112_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000191 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001a1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001b1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001c1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_CCM_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001d1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_AES_GCM_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001e1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DES_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000001f1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DES_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000201 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DES_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000211 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DESX_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000221 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DESX_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000231 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DESX_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000241 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RC2_CBC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000251 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RC2_ECB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000261 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RC2_CFB_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000271 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DH_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000281 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDH_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000291 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDH_P256_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002a1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDH_P384_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002b1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDH_P521_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002c1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_DSA_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002d1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDSA_P256_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002e1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDSA_P384_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x000002f1 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ECDSA_P521_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000301 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_RSA_SIGN_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000311 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_CAPI_KDF_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000321 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_PBKDF2_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000331 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SP800108_CTR_HMAC_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000341 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_SP80056A_CONCAT_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000351 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_TLS1_1_KDF_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000361 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_TLS1_2_KDF_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000371 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_XTS_AES_ALG_HANDLE: BCRYPT_ALG_HANDLE = 0x00000381 as BCRYPT_ALG_HANDLE; +pub const BCRYPT_ALG_HANDLE_HMAC_FLAG: ULONG = 0x00000008; +pub const BCRYPT_CAPI_AES_FLAG: ULONG = 0x00000010; +pub const BCRYPT_HASH_REUSABLE_FLAG: ULONG = 0x00000020; +pub const BCRYPT_BUFFERS_LOCKED_FLAG: ULONG = 0x00000040; +pub const BCRYPT_EXTENDED_KEYSIZE: ULONG = 0x00000080; +pub const BCRYPT_ENABLE_INCOMPATIBLE_FIPS_CHECKS: ULONG = 0x00000100; +extern "system" { + pub fn BCryptOpenAlgorithmProvider( + phAlgorithm: *mut BCRYPT_ALG_HANDLE, + pszAlgId: LPCWSTR, + pszImplementation: LPCWSTR, + dwFlags: ULONG, + ) -> NTSTATUS; +} +pub const BCRYPT_CIPHER_OPERATION: ULONG = 0x00000001; +pub const BCRYPT_HASH_OPERATION: ULONG = 0x00000002; +pub const BCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION: ULONG = 0x00000004; +pub const BCRYPT_SECRET_AGREEMENT_OPERATION: ULONG = 0x00000008; +pub const BCRYPT_SIGNATURE_OPERATION: ULONG = 0x00000010; +pub const BCRYPT_RNG_OPERATION: ULONG = 0x00000020; +pub const BCRYPT_KEY_DERIVATION_OPERATION: ULONG = 0x00000040; +STRUCT!{struct BCRYPT_ALGORITHM_IDENTIFIER { + pszName: LPWSTR, + dwClass: ULONG, + dwFlags: ULONG, +}} +extern "system" { + pub fn BCryptEnumAlgorithms( + dwAlgOperations: ULONG, + pAlgCount: *mut ULONG, + ppAlgList: *mut *mut BCRYPT_ALGORITHM_IDENTIFIER, + dwFlags: ULONG, + ) -> NTSTATUS; +} +STRUCT!{struct BCRYPT_PROVIDER_NAME { + pszProviderName: LPWSTR, +}} +extern "system" { + pub fn BCryptEnumProviders( + pszAlgId: LPCWSTR, + pImplCount: *mut ULONG, + ppImplList: *mut *mut BCRYPT_PROVIDER_NAME, + dwFlags: ULONG, + ) -> NTSTATUS; +} +pub const BCRYPT_PUBLIC_KEY_FLAG: ULONG = 0x00000001; +pub const BCRYPT_PRIVATE_KEY_FLAG: ULONG = 0x00000002; +extern "system" { + pub fn BCryptGetProperty( + hObject: BCRYPT_HANDLE, + pszProperty: LPCWSTR, + pbOutput: PUCHAR, + cbOutput: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptSetProperty( + hObject: BCRYPT_HANDLE, + pszProperty: LPCWSTR, + pbInput: PUCHAR, + cbInput: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptCloseAlgorithmProvider( + hAlgorithm: BCRYPT_ALG_HANDLE, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptFreeBuffer( + pvBuffer: PVOID, + ); + pub fn BCryptGenerateSymmetricKey( + hAlgorithm: BCRYPT_ALG_HANDLE, + phKey: *mut BCRYPT_KEY_HANDLE, + pbKeyObject: PUCHAR, + cbKeyObject: ULONG, + pbSecret: PUCHAR, + cbSecret: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptGenerateKeyPair( + hAlgorithm: BCRYPT_ALG_HANDLE, + phKey: *mut BCRYPT_KEY_HANDLE, + dwLength: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptEncrypt( + hKey: BCRYPT_KEY_HANDLE, + pbInput: PUCHAR, + cbInput: ULONG, + pPaddingInfo: *mut VOID, + pbIV: PUCHAR, + cbIV: ULONG, + pbOutput: PUCHAR, + cbOutput: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDecrypt( + hKey: BCRYPT_KEY_HANDLE, + pbInput: PUCHAR, + cbInput: ULONG, + pPaddingInfo: *mut VOID, + pbIV: PUCHAR, + cbIV: ULONG, + pbOutput: PUCHAR, + cbOutput: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptExportKey( + hKey: BCRYPT_KEY_HANDLE, + hExportKey: BCRYPT_KEY_HANDLE, + pszBlobType: LPCWSTR, + pbOutput: PUCHAR, + cbOutput: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptImportKey( + hAlgorithm: BCRYPT_ALG_HANDLE, + hImportKey: BCRYPT_KEY_HANDLE, + pszBlobType: LPCWSTR, + phKey: *mut BCRYPT_KEY_HANDLE, + pbKeyObject: PUCHAR, + cbKeyObject: ULONG, + pbInput: PUCHAR, + cbInput: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; +} +pub const BCRYPT_NO_KEY_VALIDATION: ULONG = 0x00000008; +extern "system" { + pub fn BCryptImportKeyPair( + hAlgorithm: BCRYPT_ALG_HANDLE, + hImportKey: BCRYPT_KEY_HANDLE, + pszBlobType: LPCWSTR, + phKey: *mut BCRYPT_KEY_HANDLE, + pbInput: PUCHAR, + cbInput: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDuplicateKey( + hKey: BCRYPT_KEY_HANDLE, + phNewKey: *mut BCRYPT_KEY_HANDLE, + pbKeyObject: PUCHAR, + cbKeyObject: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptFinalizeKeyPair( + hKey: BCRYPT_KEY_HANDLE, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDestroyKey( + hKey: BCRYPT_KEY_HANDLE, + ) -> NTSTATUS; + pub fn BCryptDestroySecret( + hSecret: BCRYPT_SECRET_HANDLE, + ) -> NTSTATUS; + pub fn BCryptSignHash( + hKey: BCRYPT_KEY_HANDLE, + pPaddingInfo: *mut VOID, + pbInput: PUCHAR, + cbInput: ULONG, + pbOutput: PUCHAR, + cbOutput: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptVerifySignature( + hKey: BCRYPT_KEY_HANDLE, + pPaddingInfo: *mut VOID, + pbHash: PUCHAR, + cbHash: ULONG, + pbSignature: PUCHAR, + cbSignature: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptSecretAgreement( + hPrivKey: BCRYPT_KEY_HANDLE, + hPubKey: BCRYPT_KEY_HANDLE, + phAgreedSecret: *mut BCRYPT_SECRET_HANDLE, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDeriveKey( + hSharedSecret: BCRYPT_SECRET_HANDLE, + pwszKDF: LPCWSTR, + pParameterList: *mut BCryptBufferDesc, + pbDerivedKey: PUCHAR, + cbDerivedKey: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptKeyDerivation( + hKey: BCRYPT_KEY_HANDLE, + pParameterList: *mut BCryptBufferDesc, + pbDerivedKey: PUCHAR, + cbDerivedKey: ULONG, + pcbResult: *mut ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptCreateHash( + hAlgorithm: BCRYPT_ALG_HANDLE, + phHash: *mut BCRYPT_HASH_HANDLE, + pbHashObject: PUCHAR, + cbHashObject: ULONG, + pbSecret: PUCHAR, + cbSecret: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptHashData( + hHash: BCRYPT_HASH_HANDLE, + pbInput: PUCHAR, + cbInput: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptFinishHash( + hHash: BCRYPT_HASH_HANDLE, + pbOutput: PUCHAR, + cbOutput: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptCreateMultiHash( + hAlgorithm: BCRYPT_ALG_HANDLE, + phHash: *mut BCRYPT_HASH_HANDLE, + nHashes: ULONG, + pbHashObject: PUCHAR, + cbHashObject: ULONG, + pbSecret: PUCHAR, + cbSecret: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptProcessMultiOperations( + hObject: BCRYPT_HANDLE, + operationType: BCRYPT_MULTI_OPERATION_TYPE, + pOperations: PVOID, + cbOperations: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDuplicateHash( + hHash: BCRYPT_HASH_HANDLE, + phNewHash: *mut BCRYPT_HASH_HANDLE, + pbHashObject: PUCHAR, + cbHashObject: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDestroyHash( + hHash: BCRYPT_HASH_HANDLE, + ) -> NTSTATUS; + pub fn BCryptHash( + hAlgorithm: BCRYPT_ALG_HANDLE, + pbSecret: PUCHAR, + cbSecret: ULONG, + pbInput: PUCHAR, + cbInput: ULONG, + pbOutput: PUCHAR, + cbOutput: ULONG, + ) -> NTSTATUS; +} +pub const BCRYPT_RNG_USE_ENTROPY_IN_BUFFER: ULONG = 0x00000001; +pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: ULONG = 0x00000002; +extern "system" { + pub fn BCryptGenRandom( + hAlgorithm: BCRYPT_ALG_HANDLE, + pbBuffer: PUCHAR, + cbBuffer: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDeriveKeyCapi( + hHash: BCRYPT_HASH_HANDLE, + hTargetAlg: BCRYPT_ALG_HANDLE, + pbDerivedKey: PUCHAR, + cbDerivedKey: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; + pub fn BCryptDeriveKeyPBKDF2( + hPrf: BCRYPT_ALG_HANDLE, + pbPassword: PUCHAR, + cbPassword: ULONG, + pbSalt: PUCHAR, + cbSalt: ULONG, + cIterations: ULONGLONG, + pbDerivedKey: PUCHAR, + cbDerivedKey: ULONG, + dwFlags: ULONG, + ) -> NTSTATUS; +} +STRUCT!{struct BCRYPT_INTERFACE_VERSION { + MajorVersion: USHORT, + MinorVersion: USHORT, +}} +pub type PBCRYPT_INTERFACE_VERSION = *mut BCRYPT_INTERFACE_VERSION; +#[inline] +pub fn BCRYPT_IS_INTERFACE_VERSION_COMPATIBLE( + loader: BCRYPT_INTERFACE_VERSION, + provider: BCRYPT_INTERFACE_VERSION, +) -> bool { + loader.MajorVersion <= provider.MajorVersion +} +pub const BCRYPT_CIPHER_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const BCRYPT_HASH_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const BCRYPT_HASH_INTERFACE_MAJORVERSION_2: USHORT = 2; +pub const BCRYPT_HASH_INTERFACE_VERSION_2: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(BCRYPT_HASH_INTERFACE_MAJORVERSION_2, 0); +pub const BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const BCRYPT_SECRET_AGREEMENT_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const BCRYPT_SIGNATURE_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const BCRYPT_RNG_INTERFACE_VERSION_1: BCRYPT_INTERFACE_VERSION = + BCRYPT_MAKE_INTERFACE_VERSION!(1, 0); +pub const CRYPT_MIN_DEPENDENCIES: ULONG = 0x00000001; +pub const CRYPT_PROCESS_ISOLATE: ULONG = 0x00010000; +pub const CRYPT_UM: ULONG = 0x00000001; +pub const CRYPT_KM: ULONG = 0x00000002; +pub const CRYPT_MM: ULONG = 0x00000003; +pub const CRYPT_ANY: ULONG = 0x00000004; +pub const CRYPT_OVERWRITE: ULONG = 0x00000001; +pub const CRYPT_LOCAL: ULONG = 0x00000001; +pub const CRYPT_DOMAIN: ULONG = 0x00000002; +pub const CRYPT_EXCLUSIVE: ULONG = 0x00000001; +pub const CRYPT_OVERRIDE: ULONG = 0x00010000; +pub const CRYPT_ALL_FUNCTIONS: ULONG = 0x00000001; +pub const CRYPT_ALL_PROVIDERS: ULONG = 0x00000002; +pub const CRYPT_PRIORITY_TOP: ULONG = 0x00000000; +pub const CRYPT_PRIORITY_BOTTOM: ULONG = 0xFFFFFFFF; +pub const CRYPT_DEFAULT_CONTEXT: &'static str = "Default"; +STRUCT!{struct CRYPT_INTERFACE_REG { + dwInterface: ULONG, + dwFlags: ULONG, + cFunctions: ULONG, + rgpszFunctions: *mut PWSTR, +}} +pub type PCRYPT_INTERFACE_REG = *mut CRYPT_INTERFACE_REG; +STRUCT!{struct CRYPT_IMAGE_REG { + pszImage: PWSTR, + cInterfaces: ULONG, + rgpInterfaces: *mut PCRYPT_INTERFACE_REG, +}} +pub type PCRYPT_IMAGE_REG = *mut CRYPT_IMAGE_REG; +STRUCT!{struct CRYPT_PROVIDER_REG { + cAliases: ULONG, + rgpszAliases: *mut PWSTR, + pUM: PCRYPT_IMAGE_REG, + pKM: PCRYPT_IMAGE_REG, +}} +pub type PCRYPT_PROVIDER_REG = *mut CRYPT_PROVIDER_REG; +STRUCT!{struct CRYPT_PROVIDERS { + cProviders: ULONG, + rgpszProviders: *mut PWSTR, +}} +pub type PCRYPT_PROVIDERS = *mut CRYPT_PROVIDERS; +STRUCT!{struct CRYPT_CONTEXT_CONFIG { + dwFlags: ULONG, + dwReserved: ULONG, +}} +pub type PCRYPT_CONTEXT_CONFIG = *mut CRYPT_CONTEXT_CONFIG; +STRUCT!{struct CRYPT_CONTEXT_FUNCTION_CONFIG { + dwFlags: ULONG, + dwReserved: ULONG, +}} +pub type PCRYPT_CONTEXT_FUNCTION_CONFIG = *mut CRYPT_CONTEXT_FUNCTION_CONFIG; +STRUCT!{struct CRYPT_CONTEXTS { + cContexts: ULONG, + rgpszContexts: *mut PWSTR, +}} +pub type PCRYPT_CONTEXTS = *mut CRYPT_CONTEXTS; +STRUCT!{struct CRYPT_CONTEXT_FUNCTIONS { + cFunctions: ULONG, + rgpszFunctions: *mut PWSTR, +}} +pub type PCRYPT_CONTEXT_FUNCTIONS = *mut CRYPT_CONTEXT_FUNCTIONS; +STRUCT!{struct CRYPT_CONTEXT_FUNCTION_PROVIDERS { + cProviders: ULONG, + rgpszProviders: *mut PWSTR, +}} +pub type PCRYPT_CONTEXT_FUNCTION_PROVIDERS = *mut CRYPT_CONTEXT_FUNCTION_PROVIDERS; +STRUCT!{struct CRYPT_PROPERTY_REF { + pszProperty: PWSTR, + cbValue: ULONG, + pbValue: PUCHAR, +}} +pub type PCRYPT_PROPERTY_REF = *mut CRYPT_PROPERTY_REF; +STRUCT!{struct CRYPT_IMAGE_REF { + pszImage: PWSTR, + dwFlags: ULONG, +}} +pub type PCRYPT_IMAGE_REF = *mut CRYPT_IMAGE_REF; +STRUCT!{struct CRYPT_PROVIDER_REF { + dwInterface: ULONG, + pszFunction: PWSTR, + pszProvider: PWSTR, + cProperties: ULONG, + rgpProperties: *mut PCRYPT_PROPERTY_REF, + pUM: PCRYPT_IMAGE_REF, + pKM: PCRYPT_IMAGE_REF, +}} +pub type PCRYPT_PROVIDER_REF = *mut CRYPT_PROVIDER_REF; +STRUCT!{struct CRYPT_PROVIDER_REFS { + cProviders: ULONG, + rgpProviders: *mut PCRYPT_PROVIDER_REF, +}} +pub type PCRYPT_PROVIDER_REFS = *mut CRYPT_PROVIDER_REFS; +extern "system" { + pub fn BCryptQueryProviderRegistration( + pszProvider: LPCWSTR, + dwMode: ULONG, + dwInterface: ULONG, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_PROVIDER_REG, + ) -> NTSTATUS; + pub fn BCryptEnumRegisteredProviders( + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_PROVIDERS, + ) -> NTSTATUS; + pub fn BCryptCreateContext( + dwTable: ULONG, + pszContext: LPCWSTR, + pConfig: PCRYPT_CONTEXT_CONFIG, + ) -> NTSTATUS; + pub fn BCryptDeleteContext( + dwTable: ULONG, + pszContext: LPCWSTR, + ) -> NTSTATUS; + pub fn BCryptEnumContexts( + dwTable: ULONG, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_CONTEXTS, + ) -> NTSTATUS; + pub fn BCryptConfigureContext( + dwTable: ULONG, + pszContext: LPCWSTR, + pConfig: PCRYPT_CONTEXT_CONFIG, + ) -> NTSTATUS; + pub fn BCryptQueryContextConfiguration( + dwTable: ULONG, + pszContext: LPCWSTR, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_CONTEXT_CONFIG, + ) -> NTSTATUS; + pub fn BCryptAddContextFunction( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + dwPosition: ULONG, + ) -> NTSTATUS; + pub fn BCryptRemoveContextFunction( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + ) -> NTSTATUS; + pub fn BCryptEnumContextFunctions( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_CONTEXT_FUNCTIONS, + ) -> NTSTATUS; + pub fn BCryptConfigureContextFunction( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pConfig: PCRYPT_CONTEXT_FUNCTION_CONFIG, + ) -> NTSTATUS; + pub fn BCryptQueryContextFunctionConfiguration( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_CONTEXT_FUNCTION_CONFIG, + ) -> NTSTATUS; + pub fn BCryptEnumContextFunctionProviders( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_CONTEXT_FUNCTION_PROVIDERS, + ) -> NTSTATUS; + pub fn BCryptSetContextFunctionProperty( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pszProperty: LPCWSTR, + cbValue: ULONG, + pbValue: PUCHAR, + ) -> NTSTATUS; + pub fn BCryptQueryContextFunctionProperty( + dwTable: ULONG, + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pszProperty: LPCWSTR, + pcbValue: *mut ULONG, + ppbValue: *mut PUCHAR, + ) -> NTSTATUS; + pub fn BCryptRegisterConfigChangeNotify( + phEvent: *mut HANDLE, + ) -> NTSTATUS; + pub fn BCryptUnregisterConfigChangeNotify( + hEvent: HANDLE, + ) -> NTSTATUS; + pub fn BCryptResolveProviders( + pszContext: LPCWSTR, + dwInterface: ULONG, + pszFunction: LPCWSTR, + pszProvider: LPCWSTR, + dwMode: ULONG, + dwFlags: ULONG, + pcbBuffer: *mut ULONG, + ppBuffer: *mut PCRYPT_PROVIDER_REFS, + ) -> NTSTATUS; + pub fn BCryptGetFipsAlgorithmMode( + pfEnabled: *mut BOOLEAN, + ) -> NTSTATUS; + pub fn CngGetFipsAlgorithmMode() -> BOOLEAN; +} diff --git a/winapi/src/shared/bugcodes.rs b/winapi/src/shared/bugcodes.rs new file mode 100644 index 000000000..3e2bd4954 --- /dev/null +++ b/winapi/src/shared/bugcodes.rs @@ -0,0 +1,456 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Definitions of system bug check codes +use shared::ntdef::ULONG; +pub const HARDWARE_PROFILE_UNDOCKED_STRING: ULONG = 0x40010001; +pub const HARDWARE_PROFILE_DOCKED_STRING: ULONG = 0x40010002; +pub const HARDWARE_PROFILE_UNKNOWN_STRING: ULONG = 0x40010003; +pub const WINDOWS_NT_BANNER: ULONG = 0x4000007E; +pub const WINDOWS_NT_CSD_STRING: ULONG = 0x40000087; +pub const WINDOWS_NT_INFO_STRING: ULONG = 0x40000088; +pub const WINDOWS_NT_MP_STRING: ULONG = 0x40000089; +pub const THREAD_TERMINATE_HELD_MUTEX: ULONG = 0x4000008A; +pub const WINDOWS_NT_INFO_STRING_PLURAL: ULONG = 0x4000009D; +pub const WINDOWS_NT_RC_STRING: ULONG = 0x4000009E; +pub const APC_INDEX_MISMATCH: ULONG = 0x00000001; +pub const DEVICE_QUEUE_NOT_BUSY: ULONG = 0x00000002; +pub const INVALID_AFFINITY_SET: ULONG = 0x00000003; +pub const INVALID_DATA_ACCESS_TRAP: ULONG = 0x00000004; +pub const INVALID_PROCESS_ATTACH_ATTEMPT: ULONG = 0x00000005; +pub const INVALID_PROCESS_DETACH_ATTEMPT: ULONG = 0x00000006; +pub const INVALID_SOFTWARE_INTERRUPT: ULONG = 0x00000007; +pub const IRQL_NOT_DISPATCH_LEVEL: ULONG = 0x00000008; +pub const IRQL_NOT_GREATER_OR_EQUAL: ULONG = 0x00000009; +pub const IRQL_NOT_LESS_OR_EQUAL: ULONG = 0x0000000A; +pub const NO_EXCEPTION_HANDLING_SUPPORT: ULONG = 0x0000000B; +pub const MAXIMUM_WAIT_OBJECTS_EXCEEDED: ULONG = 0x0000000C; +pub const MUTEX_LEVEL_NUMBER_VIOLATION: ULONG = 0x0000000D; +pub const NO_USER_MODE_CONTEXT: ULONG = 0x0000000E; +pub const SPIN_LOCK_ALREADY_OWNED: ULONG = 0x0000000F; +pub const SPIN_LOCK_NOT_OWNED: ULONG = 0x00000010; +pub const THREAD_NOT_MUTEX_OWNER: ULONG = 0x00000011; +pub const TRAP_CAUSE_UNKNOWN: ULONG = 0x00000012; +pub const EMPTY_THREAD_REAPER_LIST: ULONG = 0x00000013; +pub const CREATE_DELETE_LOCK_NOT_LOCKED: ULONG = 0x00000014; +pub const LAST_CHANCE_CALLED_FROM_KMODE: ULONG = 0x00000015; +pub const CID_HANDLE_CREATION: ULONG = 0x00000016; +pub const CID_HANDLE_DELETION: ULONG = 0x00000017; +pub const REFERENCE_BY_POINTER: ULONG = 0x00000018; +pub const BAD_POOL_HEADER: ULONG = 0x00000019; +pub const MEMORY_MANAGEMENT: ULONG = 0x0000001A; +pub const PFN_SHARE_COUNT: ULONG = 0x0000001B; +pub const PFN_REFERENCE_COUNT: ULONG = 0x0000001C; +pub const NO_SPIN_LOCK_AVAILABLE: ULONG = 0x0000001D; +pub const KMODE_EXCEPTION_NOT_HANDLED: ULONG = 0x0000001E; +pub const SHARED_RESOURCE_CONV_ERROR: ULONG = 0x0000001F; +pub const KERNEL_APC_PENDING_DURING_EXIT: ULONG = 0x00000020; +pub const QUOTA_UNDERFLOW: ULONG = 0x00000021; +pub const FILE_SYSTEM: ULONG = 0x00000022; +pub const FAT_FILE_SYSTEM: ULONG = 0x00000023; +pub const NTFS_FILE_SYSTEM: ULONG = 0x00000024; +pub const NPFS_FILE_SYSTEM: ULONG = 0x00000025; +pub const CDFS_FILE_SYSTEM: ULONG = 0x00000026; +pub const RDR_FILE_SYSTEM: ULONG = 0x00000027; +pub const CORRUPT_ACCESS_TOKEN: ULONG = 0x00000028; +pub const SECURITY_SYSTEM: ULONG = 0x00000029; +pub const INCONSISTENT_IRP: ULONG = 0x0000002A; +pub const PANIC_STACK_SWITCH: ULONG = 0x0000002B; +pub const PORT_DRIVER_INTERNAL: ULONG = 0x0000002C; +pub const SCSI_DISK_DRIVER_INTERNAL: ULONG = 0x0000002D; +pub const DATA_BUS_ERROR: ULONG = 0x0000002E; +pub const INSTRUCTION_BUS_ERROR: ULONG = 0x0000002F; +pub const SET_OF_INVALID_CONTEXT: ULONG = 0x00000030; +pub const PHASE0_INITIALIZATION_FAILED: ULONG = 0x00000031; +pub const PHASE1_INITIALIZATION_FAILED: ULONG = 0x00000032; +pub const UNEXPECTED_INITIALIZATION_CALL: ULONG = 0x00000033; +pub const CACHE_MANAGER: ULONG = 0x00000034; +pub const NO_MORE_IRP_STACK_LOCATIONS: ULONG = 0x00000035; +pub const DEVICE_REFERENCE_COUNT_NOT_ZERO: ULONG = 0x00000036; +pub const FLOPPY_INTERNAL_ERROR: ULONG = 0x00000037; +pub const SERIAL_DRIVER_INTERNAL: ULONG = 0x00000038; +pub const SYSTEM_EXIT_OWNED_MUTEX: ULONG = 0x00000039; +pub const SYSTEM_UNWIND_PREVIOUS_USER: ULONG = 0x0000003A; +pub const SYSTEM_SERVICE_EXCEPTION: ULONG = 0x0000003B; +pub const INTERRUPT_UNWIND_ATTEMPTED: ULONG = 0x0000003C; +pub const INTERRUPT_EXCEPTION_NOT_HANDLED: ULONG = 0x0000003D; +pub const MULTIPROCESSOR_CONFIGURATION_NOT_SUPPORTED: ULONG = 0x0000003E; +pub const NO_MORE_SYSTEM_PTES: ULONG = 0x0000003F; +pub const TARGET_MDL_TOO_SMALL: ULONG = 0x00000040; +pub const MUST_SUCCEED_POOL_EMPTY: ULONG = 0x00000041; +pub const ATDISK_DRIVER_INTERNAL: ULONG = 0x00000042; +pub const NO_SUCH_PARTITION: ULONG = 0x00000043; +pub const MULTIPLE_IRP_COMPLETE_REQUESTS: ULONG = 0x00000044; +pub const INSUFFICIENT_SYSTEM_MAP_REGS: ULONG = 0x00000045; +pub const DEREF_UNKNOWN_LOGON_SESSION: ULONG = 0x00000046; +pub const REF_UNKNOWN_LOGON_SESSION: ULONG = 0x00000047; +pub const CANCEL_STATE_IN_COMPLETED_IRP: ULONG = 0x00000048; +pub const PAGE_FAULT_WITH_INTERRUPTS_OFF: ULONG = 0x00000049; +pub const IRQL_GT_ZERO_AT_SYSTEM_SERVICE: ULONG = 0x0000004A; +pub const STREAMS_INTERNAL_ERROR: ULONG = 0x0000004B; +pub const FATAL_UNHANDLED_HARD_ERROR: ULONG = 0x0000004C; +pub const NO_PAGES_AVAILABLE: ULONG = 0x0000004D; +pub const PFN_LIST_CORRUPT: ULONG = 0x0000004E; +pub const NDIS_INTERNAL_ERROR: ULONG = 0x0000004F; +pub const PAGE_FAULT_IN_NONPAGED_AREA: ULONG = 0x00000050; +pub const PAGE_FAULT_IN_NONPAGED_AREA_M: ULONG = 0x10000050; +pub const REGISTRY_ERROR: ULONG = 0x00000051; +pub const MAILSLOT_FILE_SYSTEM: ULONG = 0x00000052; +pub const NO_BOOT_DEVICE: ULONG = 0x00000053; +pub const LM_SERVER_INTERNAL_ERROR: ULONG = 0x00000054; +pub const DATA_COHERENCY_EXCEPTION: ULONG = 0x00000055; +pub const INSTRUCTION_COHERENCY_EXCEPTION: ULONG = 0x00000056; +pub const XNS_INTERNAL_ERROR: ULONG = 0x00000057; +pub const VOLMGRX_INTERNAL_ERROR: ULONG = 0x00000058; +pub const PINBALL_FILE_SYSTEM: ULONG = 0x00000059; +pub const CRITICAL_SERVICE_FAILED: ULONG = 0x0000005A; +pub const SET_ENV_VAR_FAILED: ULONG = 0x0000005B; +pub const HAL_INITIALIZATION_FAILED: ULONG = 0x0000005C; +pub const UNSUPPORTED_PROCESSOR: ULONG = 0x0000005D; +pub const OBJECT_INITIALIZATION_FAILED: ULONG = 0x0000005E; +pub const SECURITY_INITIALIZATION_FAILED: ULONG = 0x0000005F; +pub const PROCESS_INITIALIZATION_FAILED: ULONG = 0x00000060; +pub const HAL1_INITIALIZATION_FAILED: ULONG = 0x00000061; +pub const OBJECT1_INITIALIZATION_FAILED: ULONG = 0x00000062; +pub const SECURITY1_INITIALIZATION_FAILED: ULONG = 0x00000063; +pub const SYMBOLIC_INITIALIZATION_FAILED: ULONG = 0x00000064; +pub const MEMORY1_INITIALIZATION_FAILED: ULONG = 0x00000065; +pub const CACHE_INITIALIZATION_FAILED: ULONG = 0x00000066; +pub const CONFIG_INITIALIZATION_FAILED: ULONG = 0x00000067; +pub const FILE_INITIALIZATION_FAILED: ULONG = 0x00000068; +pub const IO1_INITIALIZATION_FAILED: ULONG = 0x00000069; +pub const LPC_INITIALIZATION_FAILED: ULONG = 0x0000006A; +pub const PROCESS1_INITIALIZATION_FAILED: ULONG = 0x0000006B; +pub const REFMON_INITIALIZATION_FAILED: ULONG = 0x0000006C; +pub const SESSION1_INITIALIZATION_FAILED: ULONG = 0x0000006D; +pub const BOOTPROC_INITIALIZATION_FAILED: ULONG = 0x0000006E; +pub const VSL_INITIALIZATION_FAILED: ULONG = 0x0000006F; +pub const SOFT_RESTART_FATAL_ERROR: ULONG = 0x00000070; +pub const ASSIGN_DRIVE_LETTERS_FAILED: ULONG = 0x00000072; +pub const CONFIG_LIST_FAILED: ULONG = 0x00000073; +pub const BAD_SYSTEM_CONFIG_INFO: ULONG = 0x00000074; +pub const CANNOT_WRITE_CONFIGURATION: ULONG = 0x00000075; +pub const PROCESS_HAS_LOCKED_PAGES: ULONG = 0x00000076; +pub const KERNEL_STACK_INPAGE_ERROR: ULONG = 0x00000077; +pub const PHASE0_EXCEPTION: ULONG = 0x00000078; +pub const MISMATCHED_HAL: ULONG = 0x00000079; +pub const KERNEL_DATA_INPAGE_ERROR: ULONG = 0x0000007A; +pub const INACCESSIBLE_BOOT_DEVICE: ULONG = 0x0000007B; +pub const BUGCODE_NDIS_DRIVER: ULONG = 0x0000007C; +pub const INSTALL_MORE_MEMORY: ULONG = 0x0000007D; +pub const SYSTEM_THREAD_EXCEPTION_NOT_HANDLED: ULONG = 0x0000007E; +pub const SYSTEM_THREAD_EXCEPTION_NOT_HANDLED_M: ULONG = 0x1000007E; +pub const UNEXPECTED_KERNEL_MODE_TRAP: ULONG = 0x0000007F; +pub const UNEXPECTED_KERNEL_MODE_TRAP_M: ULONG = 0x1000007F; +pub const NMI_HARDWARE_FAILURE: ULONG = 0x00000080; +pub const SPIN_LOCK_INIT_FAILURE: ULONG = 0x00000081; +pub const DFS_FILE_SYSTEM: ULONG = 0x00000082; +pub const OFS_FILE_SYSTEM: ULONG = 0x00000083; +pub const RECOM_DRIVER: ULONG = 0x00000084; +pub const SETUP_FAILURE: ULONG = 0x00000085; +pub const AUDIT_FAILURE: ULONG = 0x00000086; +pub const MBR_CHECKSUM_MISMATCH: ULONG = 0x0000008B; +pub const KERNEL_MODE_EXCEPTION_NOT_HANDLED: ULONG = 0x0000008E; +pub const KERNEL_MODE_EXCEPTION_NOT_HANDLED_M: ULONG = 0x1000008E; +pub const PP0_INITIALIZATION_FAILED: ULONG = 0x0000008F; +pub const PP1_INITIALIZATION_FAILED: ULONG = 0x00000090; +pub const WIN32K_INIT_OR_RIT_FAILURE: ULONG = 0x00000091; +pub const UP_DRIVER_ON_MP_SYSTEM: ULONG = 0x00000092; +pub const INVALID_KERNEL_HANDLE: ULONG = 0x00000093; +pub const KERNEL_STACK_LOCKED_AT_EXIT: ULONG = 0x00000094; +pub const PNP_INTERNAL_ERROR: ULONG = 0x00000095; +pub const INVALID_WORK_QUEUE_ITEM: ULONG = 0x00000096; +pub const BOUND_IMAGE_UNSUPPORTED: ULONG = 0x00000097; +pub const END_OF_NT_EVALUATION_PERIOD: ULONG = 0x00000098; +pub const INVALID_REGION_OR_SEGMENT: ULONG = 0x00000099; +pub const SYSTEM_LICENSE_VIOLATION: ULONG = 0x0000009A; +pub const UDFS_FILE_SYSTEM: ULONG = 0x0000009B; +pub const MACHINE_CHECK_EXCEPTION: ULONG = 0x0000009C; +pub const USER_MODE_HEALTH_MONITOR: ULONG = 0x0000009E; +pub const DRIVER_POWER_STATE_FAILURE: ULONG = 0x0000009F; +pub const INTERNAL_POWER_ERROR: ULONG = 0x000000A0; +pub const PCI_BUS_DRIVER_INTERNAL: ULONG = 0x000000A1; +pub const MEMORY_IMAGE_CORRUPT: ULONG = 0x000000A2; +pub const ACPI_DRIVER_INTERNAL: ULONG = 0x000000A3; +pub const CNSS_FILE_SYSTEM_FILTER: ULONG = 0x000000A4; +pub const ACPI_BIOS_ERROR: ULONG = 0x000000A5; +pub const FP_EMULATION_ERROR: ULONG = 0x000000A6; +pub const BAD_EXHANDLE: ULONG = 0x000000A7; +pub const BOOTING_IN_SAFEMODE_MINIMAL: ULONG = 0x000000A8; +pub const BOOTING_IN_SAFEMODE_NETWORK: ULONG = 0x000000A9; +pub const BOOTING_IN_SAFEMODE_DSREPAIR: ULONG = 0x000000AA; +pub const SESSION_HAS_VALID_POOL_ON_EXIT: ULONG = 0x000000AB; +pub const HAL_MEMORY_ALLOCATION: ULONG = 0x000000AC; +pub const VIDEO_DRIVER_DEBUG_REPORT_REQUEST: ULONG = 0x400000AD; +pub const BGI_DETECTED_VIOLATION: ULONG = 0x000000B1; +pub const VIDEO_DRIVER_INIT_FAILURE: ULONG = 0x000000B4; +pub const BOOTLOG_LOADED: ULONG = 0x000000B5; +pub const BOOTLOG_NOT_LOADED: ULONG = 0x000000B6; +pub const BOOTLOG_ENABLED: ULONG = 0x000000B7; +pub const ATTEMPTED_SWITCH_FROM_DPC: ULONG = 0x000000B8; +pub const CHIPSET_DETECTED_ERROR: ULONG = 0x000000B9; +pub const SESSION_HAS_VALID_VIEWS_ON_EXIT: ULONG = 0x000000BA; +pub const NETWORK_BOOT_INITIALIZATION_FAILED: ULONG = 0x000000BB; +pub const NETWORK_BOOT_DUPLICATE_ADDRESS: ULONG = 0x000000BC; +pub const INVALID_HIBERNATED_STATE: ULONG = 0x000000BD; +pub const ATTEMPTED_WRITE_TO_READONLY_MEMORY: ULONG = 0x000000BE; +pub const MUTEX_ALREADY_OWNED: ULONG = 0x000000BF; +pub const PCI_CONFIG_SPACE_ACCESS_FAILURE: ULONG = 0x000000C0; +pub const SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION: ULONG = 0x000000C1; +pub const BAD_POOL_CALLER: ULONG = 0x000000C2; +pub const SYSTEM_IMAGE_BAD_SIGNATURE: ULONG = 0x000000C3; +pub const DRIVER_VERIFIER_DETECTED_VIOLATION: ULONG = 0x000000C4; +pub const DRIVER_CORRUPTED_EXPOOL: ULONG = 0x000000C5; +pub const DRIVER_CAUGHT_MODIFYING_FREED_POOL: ULONG = 0x000000C6; +pub const TIMER_OR_DPC_INVALID: ULONG = 0x000000C7; +pub const IRQL_UNEXPECTED_VALUE: ULONG = 0x000000C8; +pub const DRIVER_VERIFIER_IOMANAGER_VIOLATION: ULONG = 0x000000C9; +pub const PNP_DETECTED_FATAL_ERROR: ULONG = 0x000000CA; +pub const DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS: ULONG = 0x000000CB; +pub const PAGE_FAULT_IN_FREED_SPECIAL_POOL: ULONG = 0x000000CC; +pub const PAGE_FAULT_BEYOND_END_OF_ALLOCATION: ULONG = 0x000000CD; +pub const DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS: ULONG = 0x000000CE; +pub const TERMINAL_SERVER_DRIVER_MADE_INCORRECT_MEMORY_REFERENCE: ULONG = 0x000000CF; +pub const DRIVER_CORRUPTED_MMPOOL: ULONG = 0x000000D0; +pub const DRIVER_IRQL_NOT_LESS_OR_EQUAL: ULONG = 0x000000D1; +pub const BUGCODE_ID_DRIVER: ULONG = 0x000000D2; +pub const DRIVER_PORTION_MUST_BE_NONPAGED: ULONG = 0x000000D3; +pub const SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD: ULONG = 0x000000D4; +pub const DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL: ULONG = 0x000000D5; +pub const DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION: ULONG = 0x000000D6; +pub const DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION_M: ULONG = 0x100000D6; +pub const DRIVER_UNMAPPING_INVALID_VIEW: ULONG = 0x000000D7; +pub const DRIVER_USED_EXCESSIVE_PTES: ULONG = 0x000000D8; +pub const LOCKED_PAGES_TRACKER_CORRUPTION: ULONG = 0x000000D9; +pub const SYSTEM_PTE_MISUSE: ULONG = 0x000000DA; +pub const DRIVER_CORRUPTED_SYSPTES: ULONG = 0x000000DB; +pub const DRIVER_INVALID_STACK_ACCESS: ULONG = 0x000000DC; +pub const POOL_CORRUPTION_IN_FILE_AREA: ULONG = 0x000000DE; +pub const IMPERSONATING_WORKER_THREAD: ULONG = 0x000000DF; +pub const ACPI_BIOS_FATAL_ERROR: ULONG = 0x000000E0; +pub const WORKER_THREAD_RETURNED_AT_BAD_IRQL: ULONG = 0x000000E1; +pub const MANUALLY_INITIATED_CRASH: ULONG = 0x000000E2; +pub const RESOURCE_NOT_OWNED: ULONG = 0x000000E3; +pub const WORKER_INVALID: ULONG = 0x000000E4; +pub const POWER_FAILURE_SIMULATE: ULONG = 0x000000E5; +pub const DRIVER_VERIFIER_DMA_VIOLATION: ULONG = 0x000000E6; +pub const INVALID_FLOATING_POINT_STATE: ULONG = 0x000000E7; +pub const INVALID_CANCEL_OF_FILE_OPEN: ULONG = 0x000000E8; +pub const ACTIVE_EX_WORKER_THREAD_TERMINATION: ULONG = 0x000000E9; +pub const SAVER_UNSPECIFIED: ULONG = 0x0000F000; +pub const SAVER_BLANKSCREEN: ULONG = 0x0000F002; +pub const SAVER_INPUT: ULONG = 0x0000F003; +pub const SAVER_WATCHDOG: ULONG = 0x0000F004; +pub const SAVER_STARTNOTVISIBLE: ULONG = 0x0000F005; +pub const SAVER_NAVIGATIONMODEL: ULONG = 0x0000F006; +pub const SAVER_OUTOFMEMORY: ULONG = 0x0000F007; +pub const SAVER_GRAPHICS: ULONG = 0x0000F008; +pub const SAVER_NAVSERVERTIMEOUT: ULONG = 0x0000F009; +pub const SAVER_CHROMEPROCESSCRASH: ULONG = 0x0000F00A; +pub const SAVER_NOTIFICATIONDISMISSAL: ULONG = 0x0000F00B; +pub const SAVER_SPEECHDISMISSAL: ULONG = 0x0000F00C; +pub const SAVER_CALLDISMISSAL: ULONG = 0x0000F00D; +pub const SAVER_APPBARDISMISSAL: ULONG = 0x0000F00E; +pub const SAVER_RILADAPTATIONCRASH: ULONG = 0x0000F00F; +pub const SAVER_APPLISTUNREACHABLE: ULONG = 0x0000F010; +pub const SAVER_REPORTNOTIFICATIONFAILURE: ULONG = 0x0000F011; +pub const SAVER_UNEXPECTEDSHUTDOWN: ULONG = 0x0000F012; +pub const SAVER_RPCFAILURE: ULONG = 0x0000F013; +pub const SAVER_AUXILIARYFULLDUMP: ULONG = 0x0000F014; +pub const SAVER_ACCOUNTPROVSVCINITFAILURE: ULONG = 0x0000F015; +pub const SAVER_MTBFCOMMANDTIMEOUT: ULONG = 0x00000315; +pub const SAVER_MTBFCOMMANDHANG: ULONG = 0x0000F101; +pub const SAVER_MTBFPASSBUGCHECK: ULONG = 0x0000F102; +pub const SAVER_MTBFIOERROR: ULONG = 0x0000F103; +pub const SAVER_RENDERTHREADHANG: ULONG = 0x0000F200; +pub const SAVER_RENDERMOBILEUIOOM: ULONG = 0x0000F201; +pub const SAVER_DEVICEUPDATEUNSPECIFIED: ULONG = 0x0000F300; +pub const SAVER_AUDIODRIVERHANG: ULONG = 0x0000F400; +pub const SAVER_BATTERYPULLOUT: ULONG = 0x0000F500; +pub const SAVER_MEDIACORETESTHANG: ULONG = 0x0000F600; +pub const SAVER_RESOURCEMANAGEMENT: ULONG = 0x0000F700; +pub const SAVER_CAPTURESERVICE: ULONG = 0x0000F800; +pub const SAVER_WAITFORSHELLREADY: ULONG = 0x0000F900; +pub const SAVER_NONRESPONSIVEPROCESS: ULONG = 0x00000194; +pub const SAVER_SICKAPPLICATION: ULONG = 0x00008866; +pub const THREAD_STUCK_IN_DEVICE_DRIVER: ULONG = 0x000000EA; +pub const THREAD_STUCK_IN_DEVICE_DRIVER_M: ULONG = 0x100000EA; +pub const DIRTY_MAPPED_PAGES_CONGESTION: ULONG = 0x000000EB; +pub const SESSION_HAS_VALID_SPECIAL_POOL_ON_EXIT: ULONG = 0x000000EC; +pub const UNMOUNTABLE_BOOT_VOLUME: ULONG = 0x000000ED; +pub const CRITICAL_PROCESS_DIED: ULONG = 0x000000EF; +pub const STORAGE_MINIPORT_ERROR: ULONG = 0x000000F0; +pub const SCSI_VERIFIER_DETECTED_VIOLATION: ULONG = 0x000000F1; +pub const HARDWARE_INTERRUPT_STORM: ULONG = 0x000000F2; +pub const DISORDERLY_SHUTDOWN: ULONG = 0x000000F3; +pub const CRITICAL_OBJECT_TERMINATION: ULONG = 0x000000F4; +pub const FLTMGR_FILE_SYSTEM: ULONG = 0x000000F5; +pub const PCI_VERIFIER_DETECTED_VIOLATION: ULONG = 0x000000F6; +pub const DRIVER_OVERRAN_STACK_BUFFER: ULONG = 0x000000F7; +pub const RAMDISK_BOOT_INITIALIZATION_FAILED: ULONG = 0x000000F8; +pub const DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN: ULONG = 0x000000F9; +pub const HTTP_DRIVER_CORRUPTED: ULONG = 0x000000FA; +pub const RECURSIVE_MACHINE_CHECK: ULONG = 0x000000FB; +pub const ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY: ULONG = 0x000000FC; +pub const DIRTY_NOWRITE_PAGES_CONGESTION: ULONG = 0x000000FD; +pub const BUGCODE_USB_DRIVER: ULONG = 0x000000FE; +pub const BC_BLUETOOTH_VERIFIER_FAULT: ULONG = 0x00000BFE; +pub const BC_BTHMINI_VERIFIER_FAULT: ULONG = 0x00000BFF; +pub const RESERVE_QUEUE_OVERFLOW: ULONG = 0x000000FF; +pub const LOADER_BLOCK_MISMATCH: ULONG = 0x00000100; +pub const CLOCK_WATCHDOG_TIMEOUT: ULONG = 0x00000101; +pub const DPC_WATCHDOG_TIMEOUT: ULONG = 0x00000102; +pub const MUP_FILE_SYSTEM: ULONG = 0x00000103; +pub const AGP_INVALID_ACCESS: ULONG = 0x00000104; +pub const AGP_GART_CORRUPTION: ULONG = 0x00000105; +pub const AGP_ILLEGALLY_REPROGRAMMED: ULONG = 0x00000106; +pub const KERNEL_EXPAND_STACK_ACTIVE: ULONG = 0x00000107; +pub const THIRD_PARTY_FILE_SYSTEM_FAILURE: ULONG = 0x00000108; +pub const CRITICAL_STRUCTURE_CORRUPTION: ULONG = 0x00000109; +pub const APP_TAGGING_INITIALIZATION_FAILED: ULONG = 0x0000010A; +pub const DFSC_FILE_SYSTEM: ULONG = 0x0000010B; +pub const FSRTL_EXTRA_CREATE_PARAMETER_VIOLATION: ULONG = 0x0000010C; +pub const WDF_VIOLATION: ULONG = 0x0000010D; +pub const VIDEO_MEMORY_MANAGEMENT_INTERNAL: ULONG = 0x0000010E; +pub const DRIVER_INVALID_CRUNTIME_PARAMETER: ULONG = 0x00000110; +pub const RECURSIVE_NMI: ULONG = 0x00000111; +pub const MSRPC_STATE_VIOLATION: ULONG = 0x00000112; +pub const VIDEO_DXGKRNL_FATAL_ERROR: ULONG = 0x00000113; +pub const VIDEO_SHADOW_DRIVER_FATAL_ERROR: ULONG = 0x00000114; +pub const AGP_INTERNAL: ULONG = 0x00000115; +pub const VIDEO_TDR_FAILURE: ULONG = 0x00000116; +pub const VIDEO_TDR_TIMEOUT_DETECTED: ULONG = 0x00000117; +pub const NTHV_GUEST_ERROR: ULONG = 0x00000118; +pub const VIDEO_SCHEDULER_INTERNAL_ERROR: ULONG = 0x00000119; +pub const EM_INITIALIZATION_ERROR: ULONG = 0x0000011A; +pub const DRIVER_RETURNED_HOLDING_CANCEL_LOCK: ULONG = 0x0000011B; +pub const ATTEMPTED_WRITE_TO_CM_PROTECTED_STORAGE: ULONG = 0x0000011C; +pub const EVENT_TRACING_FATAL_ERROR: ULONG = 0x0000011D; +pub const TOO_MANY_RECURSIVE_FAULTS: ULONG = 0x0000011E; +pub const INVALID_DRIVER_HANDLE: ULONG = 0x0000011F; +pub const BITLOCKER_FATAL_ERROR: ULONG = 0x00000120; +pub const DRIVER_VIOLATION: ULONG = 0x00000121; +pub const WHEA_INTERNAL_ERROR: ULONG = 0x00000122; +pub const CRYPTO_SELF_TEST_FAILURE: ULONG = 0x00000123; +pub const WHEA_UNCORRECTABLE_ERROR: ULONG = 0x00000124; +pub const NMR_INVALID_STATE: ULONG = 0x00000125; +pub const NETIO_INVALID_POOL_CALLER: ULONG = 0x00000126; +pub const PAGE_NOT_ZERO: ULONG = 0x00000127; +pub const WORKER_THREAD_RETURNED_WITH_BAD_IO_PRIORITY: ULONG = 0x00000128; +pub const WORKER_THREAD_RETURNED_WITH_BAD_PAGING_IO_PRIORITY: ULONG = 0x00000129; +pub const MUI_NO_VALID_SYSTEM_LANGUAGE: ULONG = 0x0000012A; +pub const FAULTY_HARDWARE_CORRUPTED_PAGE: ULONG = 0x0000012B; +pub const EXFAT_FILE_SYSTEM: ULONG = 0x0000012C; +pub const VOLSNAP_OVERLAPPED_TABLE_ACCESS: ULONG = 0x0000012D; +pub const INVALID_MDL_RANGE: ULONG = 0x0000012E; +pub const VHD_BOOT_INITIALIZATION_FAILED: ULONG = 0x0000012F; +pub const DYNAMIC_ADD_PROCESSOR_MISMATCH: ULONG = 0x00000130; +pub const INVALID_EXTENDED_PROCESSOR_STATE: ULONG = 0x00000131; +pub const RESOURCE_OWNER_POINTER_INVALID: ULONG = 0x00000132; +pub const DPC_WATCHDOG_VIOLATION: ULONG = 0x00000133; +pub const DRIVE_EXTENDER: ULONG = 0x00000134; +pub const REGISTRY_FILTER_DRIVER_EXCEPTION: ULONG = 0x00000135; +pub const VHD_BOOT_HOST_VOLUME_NOT_ENOUGH_SPACE: ULONG = 0x00000136; +pub const WIN32K_HANDLE_MANAGER: ULONG = 0x00000137; +pub const GPIO_CONTROLLER_DRIVER_ERROR: ULONG = 0x00000138; +pub const KERNEL_SECURITY_CHECK_FAILURE: ULONG = 0x00000139; +pub const KERNEL_MODE_HEAP_CORRUPTION: ULONG = 0x0000013A; +pub const PASSIVE_INTERRUPT_ERROR: ULONG = 0x0000013B; +pub const INVALID_IO_BOOST_STATE: ULONG = 0x0000013C; +pub const CRITICAL_INITIALIZATION_FAILURE: ULONG = 0x0000013D; +pub const ERRATA_WORKAROUND_UNSUCCESSFUL: ULONG = 0x0000013E; +pub const STORAGE_DEVICE_ABNORMALITY_DETECTED: ULONG = 0x00000140; +pub const VIDEO_ENGINE_TIMEOUT_DETECTED: ULONG = 0x00000141; +pub const VIDEO_TDR_APPLICATION_BLOCKED: ULONG = 0x00000142; +pub const PROCESSOR_DRIVER_INTERNAL: ULONG = 0x00000143; +pub const BUGCODE_USB3_DRIVER: ULONG = 0x00000144; +pub const SECURE_BOOT_VIOLATION: ULONG = 0x00000145; +pub const NDIS_NET_BUFFER_LIST_INFO_ILLEGALLY_TRANSFERRED: ULONG = 0x00000146; +pub const ABNORMAL_RESET_DETECTED: ULONG = 0x00000147; +pub const IO_OBJECT_INVALID: ULONG = 0x00000148; +pub const REFS_FILE_SYSTEM: ULONG = 0x00000149; +pub const KERNEL_WMI_INTERNAL: ULONG = 0x0000014A; +pub const SOC_SUBSYSTEM_FAILURE: ULONG = 0x0000014B; +pub const FATAL_ABNORMAL_RESET_ERROR: ULONG = 0x0000014C; +pub const EXCEPTION_SCOPE_INVALID: ULONG = 0x0000014D; +pub const SOC_CRITICAL_DEVICE_REMOVED: ULONG = 0x0000014E; +pub const PDC_WATCHDOG_TIMEOUT: ULONG = 0x0000014F; +pub const TCPIP_AOAC_NIC_ACTIVE_REFERENCE_LEAK: ULONG = 0x00000150; +pub const UNSUPPORTED_INSTRUCTION_MODE: ULONG = 0x00000151; +pub const INVALID_PUSH_LOCK_FLAGS: ULONG = 0x00000152; +pub const KERNEL_LOCK_ENTRY_LEAKED_ON_THREAD_TERMINATION: ULONG = 0x00000153; +pub const UNEXPECTED_STORE_EXCEPTION: ULONG = 0x00000154; +pub const OS_DATA_TAMPERING: ULONG = 0x00000155; +pub const WINSOCK_DETECTED_HUNG_CLOSESOCKET_LIVEDUMP: ULONG = 0x00000156; +pub const KERNEL_THREAD_PRIORITY_FLOOR_VIOLATION: ULONG = 0x00000157; +pub const ILLEGAL_IOMMU_PAGE_FAULT: ULONG = 0x00000158; +pub const HAL_ILLEGAL_IOMMU_PAGE_FAULT: ULONG = 0x00000159; +pub const SDBUS_INTERNAL_ERROR: ULONG = 0x0000015A; +pub const WORKER_THREAD_RETURNED_WITH_SYSTEM_PAGE_PRIORITY_ACTIVE: ULONG = 0x0000015B; +pub const PDC_WATCHDOG_TIMEOUT_LIVEDUMP: ULONG = 0x0000015C; +pub const SOC_SUBSYSTEM_FAILURE_LIVEDUMP: ULONG = 0x0000015D; +pub const BUGCODE_NDIS_DRIVER_LIVE_DUMP: ULONG = 0x0000015E; +pub const CONNECTED_STANDBY_WATCHDOG_TIMEOUT_LIVEDUMP: ULONG = 0x0000015F; +pub const WIN32K_ATOMIC_CHECK_FAILURE: ULONG = 0x00000160; +pub const LIVE_SYSTEM_DUMP: ULONG = 0x00000161; +pub const KERNEL_AUTO_BOOST_INVALID_LOCK_RELEASE: ULONG = 0x00000162; +pub const WORKER_THREAD_TEST_CONDITION: ULONG = 0x00000163; +pub const WIN32K_CRITICAL_FAILURE: ULONG = 0x00000164; +pub const CLUSTER_CSV_STATUS_IO_TIMEOUT_LIVEDUMP: ULONG = 0x00000165; +pub const CLUSTER_RESOURCE_CALL_TIMEOUT_LIVEDUMP: ULONG = 0x00000166; +pub const CLUSTER_CSV_SNAPSHOT_DEVICE_INFO_TIMEOUT_LIVEDUMP: ULONG = 0x00000167; +pub const CLUSTER_CSV_STATE_TRANSITION_TIMEOUT_LIVEDUMP: ULONG = 0x00000168; +pub const CLUSTER_CSV_VOLUME_ARRIVAL_LIVEDUMP: ULONG = 0x00000169; +pub const CLUSTER_CSV_VOLUME_REMOVAL_LIVEDUMP: ULONG = 0x0000016A; +pub const CLUSTER_CSV_CLUSTER_WATCHDOG_LIVEDUMP: ULONG = 0x0000016B; +pub const INVALID_RUNDOWN_PROTECTION_FLAGS: ULONG = 0x0000016C; +pub const INVALID_SLOT_ALLOCATOR_FLAGS: ULONG = 0x0000016D; +pub const ERESOURCE_INVALID_RELEASE: ULONG = 0x0000016E; +pub const CLUSTER_CSV_STATE_TRANSITION_INTERVAL_TIMEOUT_LIVEDUMP: ULONG = 0x0000016F; +pub const CLUSTER_CSV_CLUSSVC_DISCONNECT_WATCHDOG: ULONG = 0x00000170; +pub const CRYPTO_LIBRARY_INTERNAL_ERROR: ULONG = 0x00000171; +pub const COREMSGCALL_INTERNAL_ERROR: ULONG = 0x00000173; +pub const COREMSG_INTERNAL_ERROR: ULONG = 0x00000174; +pub const PREVIOUS_FATAL_ABNORMAL_RESET_ERROR: ULONG = 0x00000175; +pub const ELAM_DRIVER_DETECTED_FATAL_ERROR: ULONG = 0x00000178; +pub const PDC_LOCK_WATCHDOG_LIVEDUMP: ULONG = 0x0000017C; +pub const PDC_UNEXPECTED_REVOCATION_LIVEDUMP: ULONG = 0x0000017D; +pub const WVR_LIVEDUMP_REPLICATION_IOCONTEXT_TIMEOUT: ULONG = 0x00000180; +pub const WVR_LIVEDUMP_STATE_TRANSITION_TIMEOUT: ULONG = 0x00000181; +pub const WVR_LIVEDUMP_RECOVERY_IOCONTEXT_TIMEOUT: ULONG = 0x00000182; +pub const WVR_LIVEDUMP_APP_IO_TIMEOUT: ULONG = 0x00000183; +pub const WVR_LIVEDUMP_MANUALLY_INITIATED: ULONG = 0x00000184; +pub const WVR_LIVEDUMP_STATE_FAILURE: ULONG = 0x00000185; +pub const WVR_LIVEDUMP_CRITICAL_ERROR: ULONG = 0x00000186; +pub const VIDEO_DWMINIT_TIMEOUT_FALLBACK_BDD: ULONG = 0x00000187; +pub const CLUSTER_CSVFS_LIVEDUMP: ULONG = 0x00000188; +pub const BAD_OBJECT_HEADER: ULONG = 0x00000189; +pub const SILO_CORRUPT: ULONG = 0x0000018A; +pub const SECURE_KERNEL_ERROR: ULONG = 0x0000018B; +pub const HYPERGUARD_VIOLATION: ULONG = 0x0000018C; +pub const WIN32K_CRITICAL_FAILURE_LIVEDUMP: ULONG = 0x00000190; +pub const PF_DETECTED_CORRUPTION: ULONG = 0x00000191; +pub const KERNEL_AUTO_BOOST_LOCK_ACQUISITION_WITH_RAISED_IRQL: ULONG = 0x00000192; +pub const VIDEO_DXGKRNL_LIVEDUMP: ULONG = 0x00000193; +pub const KERNEL_STORAGE_SLOT_IN_USE: ULONG = 0x00000199; +pub const SMB_SERVER_LIVEDUMP: ULONG = 0x00000195; +pub const LOADER_ROLLBACK_DETECTED: ULONG = 0x00000196; +pub const WIN32K_SECURITY_FAILURE: ULONG = 0x00000197; +pub const UFX_LIVEDUMP: ULONG = 0x00000198; +pub const WORKER_THREAD_RETURNED_WHILE_ATTACHED_TO_SILO: ULONG = 0x0000019A; +pub const TTM_FATAL_ERROR: ULONG = 0x0000019B; +pub const WIN32K_POWER_WATCHDOG_TIMEOUT: ULONG = 0x0000019C; +pub const CLUSTER_SVHDX_LIVEDUMP: ULONG = 0x0000019D; +pub const DRIVER_VERIFIER_DETECTED_VIOLATION_LIVEDUMP: ULONG = 0x000001C4; +pub const IO_THREADPOOL_DEADLOCK_LIVEDUMP: ULONG = 0x000001C5; +pub const XBOX_CORRUPTED_IMAGE: ULONG = 0x00000357; +pub const XBOX_INVERTED_FUNCTION_TABLE_OVERFLOW: ULONG = 0x00000358; +pub const XBOX_CORRUPTED_IMAGE_BASE: ULONG = 0x00000359; +pub const XBOX_360_SYSTEM_CRASH: ULONG = 0x00000360; +pub const XBOX_360_SYSTEM_CRASH_RESERVED: ULONG = 0x00000420; +pub const HYPERVISOR_ERROR: ULONG = 0x00020001; +pub const WINLOGON_FATAL_ERROR: ULONG = 0xC000021A; +pub const MANUALLY_INITIATED_CRASH1: ULONG = 0xDEADDEAD; +pub const BUGCHECK_CONTEXT_MODIFIER: ULONG = 0x80000000; diff --git a/winapi/src/shared/cderr.rs b/winapi/src/shared/cderr.rs new file mode 100644 index 000000000..07ea187ec --- /dev/null +++ b/winapi/src/shared/cderr.rs @@ -0,0 +1,44 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Common dialog error return codes +use shared::minwindef::DWORD; +pub const CDERR_DIALOGFAILURE: DWORD = 0xFFFF; +pub const CDERR_GENERALCODES: DWORD = 0x0000; +pub const CDERR_STRUCTSIZE: DWORD = 0x0001; +pub const CDERR_INITIALIZATION: DWORD = 0x0002; +pub const CDERR_NOTEMPLATE: DWORD = 0x0003; +pub const CDERR_NOHINSTANCE: DWORD = 0x0004; +pub const CDERR_LOADSTRFAILURE: DWORD = 0x0005; +pub const CDERR_FINDRESFAILURE: DWORD = 0x0006; +pub const CDERR_LOADRESFAILURE: DWORD = 0x0007; +pub const CDERR_LOCKRESFAILURE: DWORD = 0x0008; +pub const CDERR_MEMALLOCFAILURE: DWORD = 0x0009; +pub const CDERR_MEMLOCKFAILURE: DWORD = 0x000A; +pub const CDERR_NOHOOK: DWORD = 0x000B; +pub const CDERR_REGISTERMSGFAIL: DWORD = 0x000C; +pub const PDERR_PRINTERCODES: DWORD = 0x1000; +pub const PDERR_SETUPFAILURE: DWORD = 0x1001; +pub const PDERR_PARSEFAILURE: DWORD = 0x1002; +pub const PDERR_RETDEFFAILURE: DWORD = 0x1003; +pub const PDERR_LOADDRVFAILURE: DWORD = 0x1004; +pub const PDERR_GETDEVMODEFAIL: DWORD = 0x1005; +pub const PDERR_INITFAILURE: DWORD = 0x1006; +pub const PDERR_NODEVICES: DWORD = 0x1007; +pub const PDERR_NODEFAULTPRN: DWORD = 0x1008; +pub const PDERR_DNDMMISMATCH: DWORD = 0x1009; +pub const PDERR_CREATEICFAILURE: DWORD = 0x100A; +pub const PDERR_PRINTERNOTFOUND: DWORD = 0x100B; +pub const PDERR_DEFAULTDIFFERENT: DWORD = 0x100C; +pub const CFERR_CHOOSEFONTCODES: DWORD = 0x2000; +pub const CFERR_NOFONTS: DWORD = 0x2001; +pub const CFERR_MAXLESSTHANMIN: DWORD = 0x2002; +pub const FNERR_FILENAMECODES: DWORD = 0x3000; +pub const FNERR_SUBCLASSFAILURE: DWORD = 0x3001; +pub const FNERR_INVALIDFILENAME: DWORD = 0x3002; +pub const FNERR_BUFFERTOOSMALL: DWORD = 0x3003; +pub const FRERR_FINDREPLACECODES: DWORD = 0x4000; +pub const FRERR_BUFFERLENGTHZERO: DWORD = 0x4001; +pub const CCERR_CHOOSECOLORCODES: DWORD = 0x5000; diff --git a/winapi/src/shared/cfg.rs b/winapi/src/shared/cfg.rs new file mode 100644 index 000000000..4abe3838b --- /dev/null +++ b/winapi/src/shared/cfg.rs @@ -0,0 +1,138 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! common Configuration Manager definitions for both user mode and kernel mode code +use shared::minwindef::{DWORD, ULONG}; +ENUM!{enum PNP_VETO_TYPE { + PNP_VetoTypeUnknown, + PNP_VetoLegacyDevice, + PNP_VetoPendingClose, + PNP_VetoWindowsApp, + PNP_VetoWindowsService, + PNP_VetoOutstandingOpen, + PNP_VetoDevice, + PNP_VetoDriver, + PNP_VetoIllegalDeviceRequest, + PNP_VetoInsufficientPower, + PNP_VetoNonDisableable, + PNP_VetoLegacyDriver, + PNP_VetoInsufficientRights, +}} +pub type PPNP_VETO_TYPE = *mut PNP_VETO_TYPE; +pub const CM_PROB_NOT_CONFIGURED: DWORD = 0x00000001; +pub const CM_PROB_DEVLOADER_FAILED: DWORD = 0x00000002; +pub const CM_PROB_OUT_OF_MEMORY: DWORD = 0x00000003; +pub const CM_PROB_ENTRY_IS_WRONG_TYPE: DWORD = 0x00000004; +pub const CM_PROB_LACKED_ARBITRATOR: DWORD = 0x00000005; +pub const CM_PROB_BOOT_CONFIG_CONFLICT: DWORD = 0x00000006; +pub const CM_PROB_FAILED_FILTER: DWORD = 0x00000007; +pub const CM_PROB_DEVLOADER_NOT_FOUND: DWORD = 0x00000008; +pub const CM_PROB_INVALID_DATA: DWORD = 0x00000009; +pub const CM_PROB_FAILED_START: DWORD = 0x0000000A; +pub const CM_PROB_LIAR: DWORD = 0x0000000B; +pub const CM_PROB_NORMAL_CONFLICT: DWORD = 0x0000000C; +pub const CM_PROB_NOT_VERIFIED: DWORD = 0x0000000D; +pub const CM_PROB_NEED_RESTART: DWORD = 0x0000000E; +pub const CM_PROB_REENUMERATION: DWORD = 0x0000000F; +pub const CM_PROB_PARTIAL_LOG_CONF: DWORD = 0x00000010; +pub const CM_PROB_UNKNOWN_RESOURCE: DWORD = 0x00000011; +pub const CM_PROB_REINSTALL: DWORD = 0x00000012; +pub const CM_PROB_REGISTRY: DWORD = 0x00000013; +pub const CM_PROB_VXDLDR: DWORD = 0x00000014; +pub const CM_PROB_WILL_BE_REMOVED: DWORD = 0x00000015; +pub const CM_PROB_DISABLED: DWORD = 0x00000016; +pub const CM_PROB_DEVLOADER_NOT_READY: DWORD = 0x00000017; +pub const CM_PROB_DEVICE_NOT_THERE: DWORD = 0x00000018; +pub const CM_PROB_MOVED: DWORD = 0x00000019; +pub const CM_PROB_TOO_EARLY: DWORD = 0x0000001A; +pub const CM_PROB_NO_VALID_LOG_CONF: DWORD = 0x0000001B; +pub const CM_PROB_FAILED_INSTALL: DWORD = 0x0000001C; +pub const CM_PROB_HARDWARE_DISABLED: DWORD = 0x0000001D; +pub const CM_PROB_CANT_SHARE_IRQ: DWORD = 0x0000001E; +pub const CM_PROB_FAILED_ADD: DWORD = 0x0000001F; +pub const CM_PROB_DISABLED_SERVICE: DWORD = 0x00000020; +pub const CM_PROB_TRANSLATION_FAILED: DWORD = 0x00000021; +pub const CM_PROB_NO_SOFTCONFIG: DWORD = 0x00000022; +pub const CM_PROB_BIOS_TABLE: DWORD = 0x00000023; +pub const CM_PROB_IRQ_TRANSLATION_FAILED: DWORD = 0x00000024; +pub const CM_PROB_FAILED_DRIVER_ENTRY: DWORD = 0x00000025; +pub const CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD: DWORD = 0x00000026; +pub const CM_PROB_DRIVER_FAILED_LOAD: DWORD = 0x00000027; +pub const CM_PROB_DRIVER_SERVICE_KEY_INVALID: DWORD = 0x00000028; +pub const CM_PROB_LEGACY_SERVICE_NO_DEVICES: DWORD = 0x00000029; +pub const CM_PROB_DUPLICATE_DEVICE: DWORD = 0x0000002A; +pub const CM_PROB_FAILED_POST_START: DWORD = 0x0000002B; +pub const CM_PROB_HALTED: DWORD = 0x0000002C; +pub const CM_PROB_PHANTOM: DWORD = 0x0000002D; +pub const CM_PROB_SYSTEM_SHUTDOWN: DWORD = 0x0000002E; +pub const CM_PROB_HELD_FOR_EJECT: DWORD = 0x0000002F; +pub const CM_PROB_DRIVER_BLOCKED: DWORD = 0x00000030; +pub const CM_PROB_REGISTRY_TOO_LARGE: DWORD = 0x00000031; +pub const CM_PROB_SETPROPERTIES_FAILED: DWORD = 0x00000032; +pub const CM_PROB_WAITING_ON_DEPENDENCY: DWORD = 0x00000033; +pub const CM_PROB_UNSIGNED_DRIVER: DWORD = 0x00000034; +pub const CM_PROB_USED_BY_DEBUGGER: DWORD = 0x00000035; +pub const NUM_CM_PROB_V1: DWORD = 0x00000025; +pub const NUM_CM_PROB_V2: DWORD = 0x00000032; +pub const NUM_CM_PROB_V3: DWORD = 0x00000033; +pub const NUM_CM_PROB_V4: DWORD = 0x00000034; +pub const NUM_CM_PROB_V5: DWORD = 0x00000035; +pub const NUM_CM_PROB_V6: DWORD = 0x00000036; +pub const DN_ROOT_ENUMERATED: DWORD = 0x00000001; +pub const DN_DRIVER_LOADED: DWORD = 0x00000002; +pub const DN_ENUM_LOADED: DWORD = 0x00000004; +pub const DN_STARTED: DWORD = 0x00000008; +pub const DN_MANUAL: DWORD = 0x00000010; +pub const DN_NEED_TO_ENUM: DWORD = 0x00000020; +pub const DN_NOT_FIRST_TIME: DWORD = 0x00000040; +pub const DN_HARDWARE_ENUM: DWORD = 0x00000080; +pub const DN_LIAR: DWORD = 0x00000100; +pub const DN_HAS_MARK: DWORD = 0x00000200; +pub const DN_HAS_PROBLEM: DWORD = 0x00000400; +pub const DN_FILTERED: DWORD = 0x00000800; +pub const DN_MOVED: DWORD = 0x00001000; +pub const DN_DISABLEABLE: DWORD = 0x00002000; +pub const DN_REMOVABLE: DWORD = 0x00004000; +pub const DN_PRIVATE_PROBLEM: DWORD = 0x00008000; +pub const DN_MF_PARENT: DWORD = 0x00010000; +pub const DN_MF_CHILD: DWORD = 0x00020000; +pub const DN_WILL_BE_REMOVED: DWORD = 0x00040000; +pub const DN_NOT_FIRST_TIMEE: DWORD = 0x00080000; +pub const DN_STOP_FREE_RES: DWORD = 0x00100000; +pub const DN_REBAL_CANDIDATE: DWORD = 0x00200000; +pub const DN_BAD_PARTIAL: DWORD = 0x00400000; +pub const DN_NT_ENUMERATOR: DWORD = 0x00800000; +pub const DN_NT_DRIVER: DWORD = 0x01000000; +pub const DN_NEEDS_LOCKING: DWORD = 0x02000000; +pub const DN_ARM_WAKEUP: DWORD = 0x04000000; +pub const DN_APM_ENUMERATOR: DWORD = 0x08000000; +pub const DN_APM_DRIVER: DWORD = 0x10000000; +pub const DN_SILENT_INSTALL: DWORD = 0x20000000; +pub const DN_NO_SHOW_IN_DM: DWORD = 0x40000000; +pub const DN_BOOT_LOG_PROB: DWORD = 0x80000000; +pub const DN_NEED_RESTART: DWORD = DN_LIAR; +pub const DN_DRIVER_BLOCKED: DWORD = DN_NOT_FIRST_TIME; +pub const DN_LEGACY_DRIVER: DWORD = DN_MOVED; +pub const DN_CHILD_WITH_INVALID_ID: DWORD = DN_HAS_MARK; +pub const DN_DEVICE_DISCONNECTED: DWORD = DN_NEEDS_LOCKING; +pub const DN_CHANGEABLE_FLAGS: DWORD = DN_NOT_FIRST_TIME + DN_HARDWARE_ENUM + DN_HAS_MARK + + DN_DISABLEABLE + DN_REMOVABLE + DN_MF_CHILD + DN_MF_PARENT + DN_NOT_FIRST_TIMEE + + DN_STOP_FREE_RES + DN_REBAL_CANDIDATE + DN_NT_ENUMERATOR + DN_NT_DRIVER + DN_SILENT_INSTALL + + DN_NO_SHOW_IN_DM; +pub const LCPRI_FORCECONFIG: ULONG = 0x00000000; +pub const LCPRI_BOOTCONFIG: ULONG = 0x00000001; +pub const LCPRI_DESIRED: ULONG = 0x00002000; +pub const LCPRI_NORMAL: ULONG = 0x00003000; +pub const LCPRI_LASTBESTCONFIG: ULONG = 0x00003FFF; +pub const LCPRI_SUBOPTIMAL: ULONG = 0x00005000; +pub const LCPRI_LASTSOFTCONFIG: ULONG = 0x00007FFF; +pub const LCPRI_RESTART: ULONG = 0x00008000; +pub const LCPRI_REBOOT: ULONG = 0x00009000; +pub const LCPRI_POWEROFF: ULONG = 0x0000A000; +pub const LCPRI_HARDRECONFIG: ULONG = 0x0000C000; +pub const LCPRI_HARDWIRED: ULONG = 0x0000E000; +pub const LCPRI_IMPOSSIBLE: ULONG = 0x0000F000; +pub const LCPRI_DISABLED: ULONG = 0x0000FFFF; +pub const MAX_LCPRI: ULONG = 0x0000FFFF; diff --git a/winapi/src/shared/d3d9.rs b/winapi/src/shared/d3d9.rs new file mode 100644 index 000000000..437c81111 --- /dev/null +++ b/winapi/src/shared/d3d9.rs @@ -0,0 +1,1268 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Direct3D include file +use shared::basetsd::UINT32; +use shared::d3d9caps::{D3DCAPS9, D3DCONTENTPROTECTIONCAPS, D3DOVERLAYCAPS}; +use shared::d3d9types::{ + D3DADAPTER_IDENTIFIER9, D3DAUTHENTICATEDCHANNELTYPE, D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT, + D3DBACKBUFFER_TYPE, D3DBOX, D3DCLIPSTATUS9, D3DCOLOR, D3DCOMPOSERECTSOP, D3DCUBEMAP_FACES, + D3DDEVICE_CREATION_PARAMETERS, D3DDEVTYPE, D3DDISPLAYMODE, D3DDISPLAYMODEEX, + D3DDISPLAYMODEFILTER, D3DDISPLAYROTATION, D3DENCRYPTED_BLOCK_INFO, D3DFORMAT, D3DGAMMARAMP, + D3DINDEXBUFFER_DESC, D3DLIGHT9, D3DLOCKED_BOX, D3DLOCKED_RECT, D3DMATERIAL9, D3DMATRIX, + D3DMULTISAMPLE_TYPE, D3DPOOL, D3DPRESENTSTATS, D3DPRESENT_PARAMETERS, D3DPRIMITIVETYPE, + D3DQUERYTYPE, D3DRASTER_STATUS, D3DRECT, D3DRECTPATCH_INFO, D3DRENDERSTATETYPE, + D3DRESOURCETYPE, D3DSAMPLERSTATETYPE, D3DSTATEBLOCKTYPE, D3DSURFACE_DESC, D3DTEXTUREFILTERTYPE, + D3DTEXTURESTAGESTATETYPE, D3DTRANSFORMSTATETYPE, D3DTRIPATCH_INFO, D3DVERTEXBUFFER_DESC, + D3DVERTEXELEMENT9, D3DVIEWPORT9, D3DVOLUME_DESC, +}; +use shared::guiddef::{GUID, IID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, UINT}; +use shared::windef::{HDC, HMONITOR, HWND, POINT, RECT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wingdi::{PALETTEENTRY, RGNDATA}; +use um::winnt::{HANDLE, HRESULT, LPCWSTR, LUID, VOID}; +pub const D3D_SDK_VERSION: DWORD = 32; +pub const D3D9b_SDK_VERSION: DWORD = 31; +DEFINE_GUID!{IID_IDirect3D9, + 0x81bdcbca, 0x64d4, 0x426d, 0xae, 0x8d, 0xad, 0x01, 0x47, 0xf4, 0x27, 0x5c} +DEFINE_GUID!{IID_IDirect3DDevice9, + 0xd0223b96, 0xbf7a, 0x43fd, 0x92, 0xbd, 0xa4, 0x3b, 0x0d, 0x82, 0xb9, 0xeb} +DEFINE_GUID!{IID_IDirect3DResource9, + 0x05eec05d, 0x8f7d, 0x4362, 0xb9, 0x99, 0xd1, 0xba, 0xf3, 0x57, 0xc7, 0x04} +DEFINE_GUID!{IID_IDirect3DBaseTexture9, + 0x580ca87e, 0x1d3c, 0x4d54, 0x99, 0x1d, 0xb7, 0xd3, 0xe3, 0xc2, 0x98, 0xce} +DEFINE_GUID!{IID_IDirect3DTexture9, + 0x85c31227, 0x3de5, 0x4f00, 0x9b, 0x3a, 0xf1, 0x1a, 0xc3, 0x8c, 0x18, 0xb5} +DEFINE_GUID!{IID_IDirect3DCubeTexture9, + 0xfff32f81, 0xd953, 0x473a, 0x92, 0x23, 0x93, 0xd6, 0x52, 0xab, 0xa9, 0x3f} +DEFINE_GUID!{IID_IDirect3DVolumeTexture9, + 0x2518526c, 0xe789, 0x4111, 0xa7, 0xb9, 0x47, 0xef, 0x32, 0x8d, 0x13, 0xe6} +DEFINE_GUID!{IID_IDirect3DVertexBuffer9, + 0xb64bb1b5, 0xfd70, 0x4df6, 0xbf, 0x91, 0x19, 0xd0, 0xa1, 0x24, 0x55, 0xe3} +DEFINE_GUID!{IID_IDirect3DIndexBuffer9, + 0x7c9dd65e, 0xd3f7, 0x4529, 0xac, 0xee, 0x78, 0x58, 0x30, 0xac, 0xde, 0x35} +DEFINE_GUID!{IID_IDirect3DSurface9, + 0x0cfbaf3a, 0x9ff6, 0x429a, 0x99, 0xb3, 0xa2, 0x79, 0x6a, 0xf8, 0xb8, 0x9b} +DEFINE_GUID!{IID_IDirect3DVolume9, + 0x24f416e6, 0x1f67, 0x4aa7, 0xb8, 0x8e, 0xd3, 0x3f, 0x6f, 0x31, 0x28, 0xa1} +DEFINE_GUID!{IID_IDirect3DSwapChain9, + 0x794950f2, 0xadfc, 0x458a, 0x90, 0x5e, 0x10, 0xa1, 0x0b, 0x0b, 0x50, 0x3b} +DEFINE_GUID!{IID_IDirect3DVertexDeclaration9, + 0xdd13c59c, 0x36fa, 0x4098, 0xa8, 0xfb, 0xc7, 0xed, 0x39, 0xdc, 0x85, 0x46} +DEFINE_GUID!{IID_IDirect3DVertexShader9, + 0xefc5557e, 0x6265, 0x4613, 0x8a, 0x94, 0x43, 0x85, 0x78, 0x89, 0xeb, 0x36} +DEFINE_GUID!{IID_IDirect3DPixelShader9, + 0x6d3bdbdc, 0x5b02, 0x4415, 0xb8, 0x52, 0xce, 0x5e, 0x8b, 0xcc, 0xb2, 0x89} +DEFINE_GUID!{IID_IDirect3DStateBlock9, + 0xb07c4fe5, 0x310d, 0x4ba8, 0xa2, 0x3c, 0x4f, 0x0f, 0x20, 0x6f, 0x21, 0x8b} +DEFINE_GUID!{IID_IDirect3DQuery9, + 0xd9771460, 0xa695, 0x4f26, 0xbb, 0xd3, 0x27, 0xb8, 0x40, 0xb5, 0x41, 0xcc} +DEFINE_GUID!{IID_HelperName, + 0xe4a36723, 0xfdfe, 0x4b22, 0xb1, 0x46, 0x3c, 0x04, 0xc0, 0x7f, 0x4c, 0xc8} +DEFINE_GUID!{IID_IDirect3D9Ex, + 0x02177241, 0x69fc, 0x400c, 0x8f, 0xf1, 0x93, 0xa4, 0x4d, 0xf6, 0x86, 0x1d} +DEFINE_GUID!{IID_IDirect3DDevice9Ex, + 0xb18b10ce, 0x2649, 0x405a, 0x87, 0x0f, 0x95, 0xf7, 0x77, 0xd4, 0x31, 0x3a} +DEFINE_GUID!{IID_IDirect3DSwapChain9Ex, + 0x91886caf, 0x1c3d, 0x4d2e, 0xa0, 0xab, 0x3e, 0x4c, 0x7d, 0x8d, 0x33, 0x03} +DEFINE_GUID!{IID_IDirect3D9ExOverlayExtension, + 0x187aeb13, 0xaaf5, 0x4c59, 0x87, 0x6d, 0xe0, 0x59, 0x08, 0x8c, 0x0d, 0xf8} +DEFINE_GUID!{IID_IDirect3DDevice9Video, + 0x26dc4561, 0xa1ee, 0x4ae7, 0x96, 0xda, 0x11, 0x8a, 0x36, 0xc0, 0xec, 0x95} +DEFINE_GUID!{IID_IDirect3DAuthenticatedChannel9, + 0xff24beee, 0xda21, 0x4beb, 0x98, 0xb5, 0xd2, 0xf8, 0x99, 0xf9, 0x8a, 0xf9} +DEFINE_GUID!{IID_IDirect3DCryptoSession9, + 0xfa0ab799, 0x7a9c, 0x48ca, 0x8c, 0x5b, 0x23, 0x7e, 0x71, 0xa5, 0x44, 0x34} +extern "system" { + pub fn Direct3DCreate9( + SDKVersion: UINT, + ) -> *mut IDirect3D9; + pub fn D3DPERF_BeginEvent( + col: D3DCOLOR, + wszName: LPCWSTR, + ) -> INT; + pub fn D3DPERF_EndEvent() -> INT; + pub fn D3DPERF_SetMarker( + col: D3DCOLOR, + wszName: LPCWSTR, + ) -> (); + pub fn D3DPERF_SetRegion( + col: D3DCOLOR, + wszName: LPCWSTR, + ) -> (); + pub fn D3DPERF_QueryRepeatFrame() -> BOOL; + pub fn D3DPERF_SetOptions( + dwOptions: DWORD, + ) -> (); + pub fn D3DPERF_GetStatus() -> DWORD; +} +RIDL!{#[uuid(0x81bdcbca, 0x64d4, 0x426d, 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c)] +interface IDirect3D9(IDirect3D9Vtbl): IUnknown(IUnknownVtbl) { + fn RegisterSoftwareDevice( + pInitializeFunction: *mut VOID, + ) -> HRESULT, + fn GetAdapterCount() -> UINT, + fn GetAdapterIdentifier( + Adapter: UINT, + Flags: DWORD, + pIdentifier: *mut D3DADAPTER_IDENTIFIER9, + ) -> HRESULT, + fn GetAdapterModeCount( + Adapter: UINT, + Format: D3DFORMAT, + ) -> UINT, + fn EnumAdapterModes( + Adapter: UINT, + Format: D3DFORMAT, + Mode: UINT, + pMode: *mut D3DDISPLAYMODE, + ) -> HRESULT, + fn GetAdapterDisplayMode( + Adapter: UINT, + pMode: *mut D3DDISPLAYMODE, + ) -> HRESULT, + fn CheckDeviceType( + Adapter: UINT, + DevType: D3DDEVTYPE, + AdapterFormat: D3DFORMAT, + BackBufferFormat: D3DFORMAT, + bWindowed: BOOL, + ) -> HRESULT, + fn CheckDeviceFormat( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + AdapterFormat: D3DFORMAT, + Usage: DWORD, + RType: D3DRESOURCETYPE, + CheckFormat: D3DFORMAT, + ) -> HRESULT, + fn CheckDeviceMultiSampleType( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + SurfaceFormat: D3DFORMAT, + Windowed: BOOL, + MultiSampleType: D3DMULTISAMPLE_TYPE, + pQualityLevels: *mut DWORD, + ) -> HRESULT, + fn CheckDepthStencilMatch( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + AdapterFormat: D3DFORMAT, + RenderTargetFormat: D3DFORMAT, + DepthStencilFormat: D3DFORMAT, + ) -> HRESULT, + fn CheckDeviceFormatConversion( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + SourceFormat: D3DFORMAT, + TargetFormat: D3DFORMAT, + ) -> HRESULT, + fn GetDeviceCaps( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + pCaps: *mut D3DCAPS9, + ) -> HRESULT, + fn GetAdapterMonitor( + Adapter: UINT, + ) -> HMONITOR, + fn CreateDevice( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + hFocusWindow: HWND, + BehaviorFlags: DWORD, + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + ppReturnedDeviceInterface: *mut *mut IDirect3DDevice9, + ) -> HRESULT, +}} +pub type LPDIRECT3D9 = *mut IDirect3D9; +pub type PDIRECT3D9 = *mut IDirect3D9; +RIDL!{#[uuid(0xd0223b96, 0xbf7a, 0x43fd, 0x92, 0xbd, 0xa4, 0x3b, 0xd, 0x82, 0xb9, 0xeb)] +interface IDirect3DDevice9(IDirect3DDevice9Vtbl): IUnknown(IUnknownVtbl) { + fn TestCooperativeLevel() -> HRESULT, + fn GetAvailableTextureMem() -> UINT, + fn EvictManagedResources() -> HRESULT, + fn GetDirect3D( + ppD3D9: *mut *mut IDirect3D9, + ) -> HRESULT, + fn GetDeviceCaps( + pCaps: *mut D3DCAPS9, + ) -> HRESULT, + fn GetDisplayMode( + iSwapChain: UINT, + pMode: *mut D3DDISPLAYMODE, + ) -> HRESULT, + fn GetCreationParameters( + pParameters: *mut D3DDEVICE_CREATION_PARAMETERS, + ) -> HRESULT, + fn SetCursorProperties( + XHotSpot: UINT, + YHotSpot: UINT, + pCursorBitmap: *mut IDirect3DSurface9, + ) -> HRESULT, + fn SetCursorPosition( + X: INT, + Y: INT, + Flags: DWORD, + ) -> (), + fn ShowCursor( + bShow: BOOL, + ) -> BOOL, + fn CreateAdditionalSwapChain( + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + pSwapChain: *mut *mut IDirect3DSwapChain9, + ) -> HRESULT, + fn GetSwapChain( + iSwapChain: UINT, + pSwapChain: *mut *mut IDirect3DSwapChain9, + ) -> HRESULT, + fn GetNumberOfSwapChains() -> UINT, + fn Reset( + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + ) -> HRESULT, + fn Present( + pSourceRect: *const RECT, + pDestRect: *const RECT, + hDestWindowOverride: HWND, + pDirtyRegion: *const RGNDATA, + ) -> HRESULT, + fn GetBackBuffer( + iSwapChain: UINT, + iBackBuffer: UINT, + Type: D3DBACKBUFFER_TYPE, + ppBackBuffer: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetRasterStatus( + iSwapChain: UINT, + pRasterStatus: *mut D3DRASTER_STATUS, + ) -> HRESULT, + fn SetDialogBoxMode( + bEnableDialogs: BOOL, + ) -> HRESULT, + fn SetGammaRamp( + iSwapChain: UINT, + Flags: DWORD, + pRamp: *const D3DGAMMARAMP, + ) -> (), + fn GetGammaRamp( + iSwapChain: UINT, + pRamp: *mut D3DGAMMARAMP, + ) -> (), + fn CreateTexture( + Width: UINT, + Height: UINT, + Levels: UINT, + Usage: DWORD, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppTexture: *mut *mut IDirect3DTexture9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateVolumeTexture( + Width: UINT, + Height: UINT, + Depth: UINT, + Levels: UINT, + Usage: DWORD, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppVolumeTexture: *mut *mut IDirect3DVolumeTexture9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateCubeTexture( + EdgeLength: UINT, + Levels: UINT, + Usage: DWORD, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppCubeTexture: *mut *mut IDirect3DCubeTexture9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateVertexBuffer( + Length: UINT, + Usage: DWORD, + FVF: DWORD, + Pool: D3DPOOL, + ppVertexBuffer: *mut *mut IDirect3DVertexBuffer9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateIndexBuffer( + Length: UINT, + Usage: DWORD, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppIndexBuffer: *mut *mut IDirect3DIndexBuffer9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateRenderTarget( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + MultiSample: D3DMULTISAMPLE_TYPE, + MultisampleQuality: DWORD, + Lockable: BOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateDepthStencilSurface( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + MultiSample: D3DMULTISAMPLE_TYPE, + MultisampleQuality: DWORD, + Discard: BOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn UpdateSurface( + pSourceSurface: *mut IDirect3DSurface9, + pSourceRect: *const RECT, + pDestinationSurface: *mut IDirect3DSurface9, + pDestPoint: *const POINT, + ) -> HRESULT, + fn UpdateTexture( + pSourceTexture: *mut IDirect3DBaseTexture9, + pDestinationTexture: *mut IDirect3DBaseTexture9, + ) -> HRESULT, + fn GetRenderTargetData( + pRenderTarget: *mut IDirect3DSurface9, + pDestSurface: *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetFrontBufferData( + iSwapChain: UINT, + pDestSurface: *mut IDirect3DSurface9, + ) -> HRESULT, + fn StretchRect( + pSourceSurface: *mut IDirect3DSurface9, + pSourceRect: *const RECT, + pDestSurface: *mut IDirect3DSurface9, + pDestRect: *const RECT, + Filter: D3DTEXTUREFILTERTYPE, + ) -> HRESULT, + fn ColorFill( + pSurface: *mut IDirect3DSurface9, + pRect: *const RECT, + color: D3DCOLOR, + ) -> HRESULT, + fn CreateOffscreenPlainSurface( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn SetRenderTarget( + RenderTargetIndex: DWORD, + pRenderTarget: *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetRenderTarget( + RenderTargetIndex: DWORD, + ppRenderTarget: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn SetDepthStencilSurface( + pNewZStencil: *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetDepthStencilSurface( + ppZStencilSurface: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn BeginScene() -> HRESULT, + fn EndScene() -> HRESULT, + fn Clear( + Count: DWORD, + pRects: *const D3DRECT, + Flags: DWORD, + Color: D3DCOLOR, + Z: FLOAT, + Stencil: DWORD, + ) -> HRESULT, + fn SetTransform( + State: D3DTRANSFORMSTATETYPE, + pMatrix: *const D3DMATRIX, + ) -> HRESULT, + fn GetTransform( + State: D3DTRANSFORMSTATETYPE, + pMatrix: *mut D3DMATRIX, + ) -> HRESULT, + fn MultiplyTransform( + arg1: D3DTRANSFORMSTATETYPE, + arg2: *const D3DMATRIX, + ) -> HRESULT, + fn SetViewport( + pViewport: *const D3DVIEWPORT9, + ) -> HRESULT, + fn GetViewport( + pViewport: *mut D3DVIEWPORT9, + ) -> HRESULT, + fn SetMaterial( + pMaterial: *const D3DMATERIAL9, + ) -> HRESULT, + fn GetMaterial( + pMaterial: *mut D3DMATERIAL9, + ) -> HRESULT, + fn SetLight( + Index: DWORD, + arg1: *const D3DLIGHT9, + ) -> HRESULT, + fn GetLight( + Index: DWORD, + arg1: *mut D3DLIGHT9, + ) -> HRESULT, + fn LightEnable( + Index: DWORD, + Enable: BOOL, + ) -> HRESULT, + fn GetLightEnable( + Index: DWORD, + pEnable: *mut BOOL, + ) -> HRESULT, + fn SetClipPlane( + Index: DWORD, + pPlane: *const FLOAT, + ) -> HRESULT, + fn GetClipPlane( + Index: DWORD, + pPlane: *mut FLOAT, + ) -> HRESULT, + fn SetRenderState( + State: D3DRENDERSTATETYPE, + Value: DWORD, + ) -> HRESULT, + fn GetRenderState( + State: D3DRENDERSTATETYPE, + pValue: *mut DWORD, + ) -> HRESULT, + fn CreateStateBlock( + Type: D3DSTATEBLOCKTYPE, + ppSB: *mut *mut IDirect3DStateBlock9, + ) -> HRESULT, + fn BeginStateBlock() -> HRESULT, + fn EndStateBlock( + ppSB: *mut *mut IDirect3DStateBlock9, + ) -> HRESULT, + fn SetClipStatus( + pClipStatus: *const D3DCLIPSTATUS9, + ) -> HRESULT, + fn GetClipStatus( + pClipStatus: *mut D3DCLIPSTATUS9, + ) -> HRESULT, + fn GetTexture( + Stage: DWORD, + ppTexture: *mut *mut IDirect3DBaseTexture9, + ) -> HRESULT, + fn SetTexture( + Stage: DWORD, + pTexture: *mut IDirect3DBaseTexture9, + ) -> HRESULT, + fn GetTextureStageState( + Stage: DWORD, + Type: D3DTEXTURESTAGESTATETYPE, + pValue: *mut DWORD, + ) -> HRESULT, + fn SetTextureStageState( + Stage: DWORD, + Type: D3DTEXTURESTAGESTATETYPE, + Value: DWORD, + ) -> HRESULT, + fn GetSamplerState( + Sampler: DWORD, + Type: D3DSAMPLERSTATETYPE, + pValue: *mut DWORD, + ) -> HRESULT, + fn SetSamplerState( + Sampler: DWORD, + Type: D3DSAMPLERSTATETYPE, + Value: DWORD, + ) -> HRESULT, + fn ValidateDevice( + pNumPasses: *mut DWORD, + ) -> HRESULT, + fn SetPaletteEntries( + PaletteNumber: UINT, + pEntries: *const PALETTEENTRY, + ) -> HRESULT, + fn GetPaletteEntries( + PaletteNumber: UINT, + pEntries: *mut PALETTEENTRY, + ) -> HRESULT, + fn SetCurrentTexturePalette( + PaletteNumber: UINT, + ) -> HRESULT, + fn GetCurrentTexturePalette( + PaletteNumber: *mut UINT, + ) -> HRESULT, + fn SetScissorRect( + pRect: *const RECT, + ) -> HRESULT, + fn GetScissorRect( + pRect: *mut RECT, + ) -> HRESULT, + fn SetSoftwareVertexProcessing( + bSoftware: BOOL, + ) -> HRESULT, + fn GetSoftwareVertexProcessing() -> BOOL, + fn SetNPatchMode( + nSegments: FLOAT, + ) -> HRESULT, + fn GetNPatchMode() -> FLOAT, + fn DrawPrimitive( + PrimitiveType: D3DPRIMITIVETYPE, + StartVertex: UINT, + PrimitiveCount: UINT, + ) -> HRESULT, + fn DrawIndexedPrimitive( + arg1: D3DPRIMITIVETYPE, + BaseVertexIndex: INT, + MinVertexIndex: UINT, + NumVertices: UINT, + startIndex: UINT, + primCount: UINT, + ) -> HRESULT, + fn DrawPrimitiveUP( + PrimitiveType: D3DPRIMITIVETYPE, + PrimitiveCount: UINT, + pVertexStreamZeroData: *const VOID, + VertexStreamZeroStride: UINT, + ) -> HRESULT, + fn DrawIndexedPrimitiveUP( + PrimitiveType: D3DPRIMITIVETYPE, + MinVertexIndex: UINT, + NumVertices: UINT, + PrimitiveCount: UINT, + pIndexData: *const VOID, + IndexDataFormat: D3DFORMAT, + pVertexStreamZeroData: *const VOID, + VertexStreamZeroStride: UINT, + ) -> HRESULT, + fn ProcessVertices( + SrcStartIndex: UINT, + DestIndex: UINT, + VertexCount: UINT, + pDestBuffer: *mut IDirect3DVertexBuffer9, + pVertexDecl: *mut IDirect3DVertexDeclaration9, + Flags: DWORD, + ) -> HRESULT, + fn CreateVertexDeclaration( + pVertexElements: *const D3DVERTEXELEMENT9, + ppDecl: *mut *mut IDirect3DVertexDeclaration9, + ) -> HRESULT, + fn SetVertexDeclaration( + pDecl: *mut IDirect3DVertexDeclaration9, + ) -> HRESULT, + fn GetVertexDeclaration( + ppDecl: *mut *mut IDirect3DVertexDeclaration9, + ) -> HRESULT, + fn SetFVF( + FVF: DWORD, + ) -> HRESULT, + fn GetFVF( + pFVF: *mut DWORD, + ) -> HRESULT, + fn CreateVertexShader( + pFunction: *const DWORD, + ppShader: *mut *mut IDirect3DVertexShader9, + ) -> HRESULT, + fn SetVertexShader( + pShader: *mut IDirect3DVertexShader9, + ) -> HRESULT, + fn GetVertexShader( + ppShader: *mut *mut IDirect3DVertexShader9, + ) -> HRESULT, + fn SetVertexShaderConstantF( + StartRegister: UINT, + pConstantData: *const FLOAT, + Vector4fCount: UINT, + ) -> HRESULT, + fn GetVertexShaderConstantF( + StartRegister: UINT, + pConstantData: *mut FLOAT, + Vector4fCount: UINT, + ) -> HRESULT, + fn SetVertexShaderConstantI( + StartRegister: UINT, + pConstantData: *const INT, + Vector4iCount: UINT, + ) -> HRESULT, + fn GetVertexShaderConstantI( + StartRegister: UINT, + pConstantData: *mut INT, + Vector4iCount: UINT, + ) -> HRESULT, + fn SetVertexShaderConstantB( + StartRegister: UINT, + pConstantData: *const BOOL, + BoolCount: UINT, + ) -> HRESULT, + fn GetVertexShaderConstantB( + StartRegister: UINT, + pConstantData: *mut BOOL, + BoolCount: UINT, + ) -> HRESULT, + fn SetStreamSource( + StreamNumber: UINT, + pStreamData: *mut IDirect3DVertexBuffer9, + OffsetInBytes: UINT, + Stride: UINT, + ) -> HRESULT, + fn GetStreamSource( + StreamNumber: UINT, + ppStreamData: *mut *mut IDirect3DVertexBuffer9, + pOffsetInBytes: *mut UINT, + pStride: *mut UINT, + ) -> HRESULT, + fn SetStreamSourceFreq( + StreamNumber: UINT, + Setting: UINT, + ) -> HRESULT, + fn GetStreamSourceFreq( + StreamNumber: UINT, + pSetting: *mut UINT, + ) -> HRESULT, + fn SetIndices( + pIndexData: *mut IDirect3DIndexBuffer9, + ) -> HRESULT, + fn GetIndices( + ppIndexData: *mut *mut IDirect3DIndexBuffer9, + ) -> HRESULT, + fn CreatePixelShader( + pFunction: *const DWORD, + ppShader: *mut *mut IDirect3DPixelShader9, + ) -> HRESULT, + fn SetPixelShader( + pShader: *mut IDirect3DPixelShader9, + ) -> HRESULT, + fn GetPixelShader( + ppShader: *mut *mut IDirect3DPixelShader9, + ) -> HRESULT, + fn SetPixelShaderConstantF( + StartRegister: UINT, + pConstantData: *const FLOAT, + Vector4fCount: UINT, + ) -> HRESULT, + fn GetPixelShaderConstantF( + StartRegister: UINT, + pConstantData: *mut FLOAT, + Vector4fCount: UINT, + ) -> HRESULT, + fn SetPixelShaderConstantI( + StartRegister: UINT, + pConstantData: *const INT, + Vector4iCount: UINT, + ) -> HRESULT, + fn GetPixelShaderConstantI( + StartRegister: UINT, + pConstantData: *mut INT, + Vector4iCount: UINT, + ) -> HRESULT, + fn SetPixelShaderConstantB( + StartRegister: UINT, + pConstantData: *const BOOL, + BoolCount: UINT, + ) -> HRESULT, + fn GetPixelShaderConstantB( + StartRegister: UINT, + pConstantData: *mut BOOL, + BoolCount: UINT, + ) -> HRESULT, + fn DrawRectPatch( + Handle: UINT, + pNumSegs: *const FLOAT, + pRectPatchInfo: *const D3DRECTPATCH_INFO, + ) -> HRESULT, + fn DrawTriPatch( + Handle: UINT, + pNumSegs: *const FLOAT, + pTriPatchInfo: *const D3DTRIPATCH_INFO, + ) -> HRESULT, + fn DeletePatch( + Handle: UINT, + ) -> HRESULT, + fn CreateQuery( + Type: D3DQUERYTYPE, + ppQuery: *mut *mut IDirect3DQuery9, + ) -> HRESULT, +}} +pub type LPDIRECT3DDEVICE9 = *mut IDirect3DDevice9; +pub type PDIRECT3DDEVICE9 = *mut IDirect3DDevice9; +RIDL!{#[uuid(0xb07c4fe5, 0x310d, 0x4ba8, 0xa2, 0x3c, 0x4f, 0xf, 0x20, 0x6f, 0x21, 0x8b)] +interface IDirect3DStateBlock9(IDirect3DStateBlock9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn Capture() -> HRESULT, + fn Apply() -> HRESULT, +}} +pub type LPDIRECT3DSTATEBLOCK9 = *mut IDirect3DStateBlock9; +pub type PDIRECT3DSTATEBLOCK9 = *mut IDirect3DStateBlock9; +RIDL!{#[uuid(0x794950f2, 0xadfc, 0x458a, 0x90, 0x5e, 0x10, 0xa1, 0xb, 0xb, 0x50, 0x3b)] +interface IDirect3DSwapChain9(IDirect3DSwapChain9Vtbl): IUnknown(IUnknownVtbl) { + fn Present( + pSourceRect: *const RECT, + pDestRect: *const RECT, + hDestWindowOverride: HWND, + pDirtyRegion: *const RGNDATA, + dwFlags: DWORD, + ) -> HRESULT, + fn GetFrontBufferData( + pDestSurface: *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetBackBuffer( + iBackBuffer: UINT, + Type: D3DBACKBUFFER_TYPE, + ppBackBuffer: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn GetRasterStatus( + pRasterStatus: *mut D3DRASTER_STATUS, + ) -> HRESULT, + fn GetDisplayMode( + pMode: *mut D3DDISPLAYMODE, + ) -> HRESULT, + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn GetPresentParameters( + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + ) -> HRESULT, +}} +pub type LPDIRECT3DSWAPCHAIN9 = *mut IDirect3DSwapChain9; +pub type PDIRECT3DSWAPCHAIN9 = *mut IDirect3DSwapChain9; +RIDL!{#[uuid(0x5eec05d, 0x8f7d, 0x4362, 0xb9, 0x99, 0xd1, 0xba, 0xf3, 0x57, 0xc7, 0x4)] +interface IDirect3DResource9(IDirect3DResource9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn SetPrivateData( + refguid: *const GUID, + pData: *const VOID, + SizeOfData: DWORD, + Flags: DWORD, + ) -> HRESULT, + fn GetPrivateData( + refguid: *const GUID, + pData: *mut VOID, + pSizeOfData: *mut DWORD, + ) -> HRESULT, + fn FreePrivateData( + refguid: *const GUID, + ) -> HRESULT, + fn SetPriority( + PriorityNew: DWORD, + ) -> DWORD, + fn GetPriority() -> DWORD, + fn PreLoad() -> (), + fn GetType() -> D3DRESOURCETYPE, +}} +pub type LPDIRECT3DRESOURCE9 = *mut IDirect3DResource9; +pub type PDIRECT3DRESOURCE9 = *mut IDirect3DResource9; +RIDL!{#[uuid(0xdd13c59c, 0x36fa, 0x4098, 0xa8, 0xfb, 0xc7, 0xed, 0x39, 0xdc, 0x85, 0x46)] +interface IDirect3DVertexDeclaration9(IDirect3DVertexDeclaration9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn GetDeclaration( + pElement: *mut D3DVERTEXELEMENT9, + pNumElements: *mut UINT, + ) -> HRESULT, +}} +pub type LPDIRECT3DVERTEXDECLARATION9 = *mut IDirect3DVertexDeclaration9; +pub type PDIRECT3DVERTEXDECLARATION9 = *mut IDirect3DVertexDeclaration9; +RIDL!{#[uuid(0xefc5557e, 0x6265, 0x4613, 0x8a, 0x94, 0x43, 0x85, 0x78, 0x89, 0xeb, 0x36)] +interface IDirect3DVertexShader9(IDirect3DVertexShader9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn GetFunction( + arg1: *mut VOID, + pSizeOfData: *mut UINT, + ) -> HRESULT, +}} +pub type LPDIRECT3DVERTEXSHADER9 = *mut IDirect3DVertexShader9; +pub type PDIRECT3DVERTEXSHADER9 = *mut IDirect3DVertexShader9; +RIDL!{#[uuid(0x6d3bdbdc, 0x5b02, 0x4415, 0xb8, 0x52, 0xce, 0x5e, 0x8b, 0xcc, 0xb2, 0x89)] +interface IDirect3DPixelShader9(IDirect3DPixelShader9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn GetFunction( + arg1: *mut VOID, + pSizeOfData: *mut UINT, + ) -> HRESULT, +}} +pub type LPDIRECT3DPIXELSHADER9 = *mut IDirect3DPixelShader9; +pub type PDIRECT3DPIXELSHADER9 = *mut IDirect3DPixelShader9; +RIDL!{#[uuid(0x580ca87e, 0x1d3c, 0x4d54, 0x99, 0x1d, 0xb7, 0xd3, 0xe3, 0xc2, 0x98, 0xce)] +interface IDirect3DBaseTexture9(IDirect3DBaseTexture9Vtbl): + IDirect3DResource9(IDirect3DResource9Vtbl) { + fn SetLOD( + LODNew: DWORD, + ) -> DWORD, + fn GetLOD() -> DWORD, + fn GetLevelCount() -> DWORD, + fn SetAutoGenFilterType( + FilterType: D3DTEXTUREFILTERTYPE, + ) -> HRESULT, + fn GetAutoGenFilterType() -> D3DTEXTUREFILTERTYPE, + fn GenerateMipSubLevels() -> (), +}} +pub type LPDIRECT3DBASETEXTURE9 = *mut IDirect3DBaseTexture9; +pub type PDIRECT3DBASETEXTURE9 = *mut IDirect3DBaseTexture9; +RIDL!{#[uuid(0x85c31227, 0x3de5, 0x4f00, 0x9b, 0x3a, 0xf1, 0x1a, 0xc3, 0x8c, 0x18, 0xb5)] +interface IDirect3DTexture9(IDirect3DTexture9Vtbl): + IDirect3DBaseTexture9(IDirect3DBaseTexture9Vtbl) { + fn GetLevelDesc( + Level: UINT, + pDesc: *mut D3DSURFACE_DESC, + ) -> HRESULT, + fn GetSurfaceLevel( + Level: UINT, + ppSurfaceLevel: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn LockRect( + Level: UINT, + pLockedRect: *mut D3DLOCKED_RECT, + pRect: *const RECT, + Flags: DWORD, + ) -> HRESULT, + fn UnlockRect( + Level: UINT, + ) -> HRESULT, + fn AddDirtyRect( + pDirtyRect: *const RECT, + ) -> HRESULT, +}} +pub type LPDIRECT3DTEXTURE9 = *mut IDirect3DTexture9; +pub type PDIRECT3DTEXTURE9 = *mut IDirect3DTexture9; +RIDL!{#[uuid(0x2518526c, 0xe789, 0x4111, 0xa7, 0xb9, 0x47, 0xef, 0x32, 0x8d, 0x13, 0xe6)] +interface IDirect3DVolumeTexture9(IDirect3DVolumeTexture9Vtbl): + IDirect3DBaseTexture9(IDirect3DBaseTexture9Vtbl) { + fn GetLevelDesc( + Level: UINT, + pDesc: *mut D3DVOLUME_DESC, + ) -> HRESULT, + fn GetVolumeLevel( + Level: UINT, + ppVolumeLevel: *mut *mut IDirect3DVolume9, + ) -> HRESULT, + fn LockBox( + Level: UINT, + pLockedVolume: *mut D3DLOCKED_BOX, + pBox: *const D3DBOX, + Flags: DWORD, + ) -> HRESULT, + fn UnlockBox( + Level: UINT, + ) -> HRESULT, + fn AddDirtyBox( + pDirtyBox: *const D3DBOX, + ) -> HRESULT, +}} +pub type LPDIRECT3DVOLUMETEXTURE9 = *mut IDirect3DVolumeTexture9; +pub type PDIRECT3DVOLUMETEXTURE9 = *mut IDirect3DVolumeTexture9; +RIDL!{#[uuid(0xfff32f81, 0xd953, 0x473a, 0x92, 0x23, 0x93, 0xd6, 0x52, 0xab, 0xa9, 0x3f)] +interface IDirect3DCubeTexture9(IDirect3DCubeTexture9Vtbl): + IDirect3DBaseTexture9(IDirect3DBaseTexture9Vtbl) { + fn GetLevelDesc( + Level: UINT, + pDesc: *mut D3DSURFACE_DESC, + ) -> HRESULT, + fn GetCubeMapSurface( + FaceType: D3DCUBEMAP_FACES, + Level: UINT, + ppCubeMapSurface: *mut *mut IDirect3DSurface9, + ) -> HRESULT, + fn LockRect( + FaceType: D3DCUBEMAP_FACES, + Level: UINT, + pLockedRect: *mut D3DLOCKED_RECT, + pRect: *const RECT, + Flags: DWORD, + ) -> HRESULT, + fn UnlockRect( + FaceType: D3DCUBEMAP_FACES, + Level: UINT, + ) -> HRESULT, + fn AddDirtyRect( + FaceType: D3DCUBEMAP_FACES, + pDirtyRect: *const RECT, + ) -> HRESULT, +}} +pub type LPDIRECT3DCUBETEXTURE9 = *mut IDirect3DCubeTexture9; +pub type PDIRECT3DCUBETEXTURE9 = *mut IDirect3DCubeTexture9; +RIDL!{#[uuid(0xb64bb1b5, 0xfd70, 0x4df6, 0xbf, 0x91, 0x19, 0xd0, 0xa1, 0x24, 0x55, 0xe3)] +interface IDirect3DVertexBuffer9(IDirect3DVertexBuffer9Vtbl): + IDirect3DResource9(IDirect3DResource9Vtbl) { + fn Lock( + OffsetToLock: UINT, + SizeToLock: UINT, + ppbData: *mut *mut VOID, + Flags: DWORD, + ) -> HRESULT, + fn Unlock() -> HRESULT, + fn GetDesc( + pDesc: *mut D3DVERTEXBUFFER_DESC, + ) -> HRESULT, +}} +pub type LPDIRECT3DVERTEXBUFFER9 = *mut IDirect3DVertexBuffer9; +pub type PDIRECT3DVERTEXBUFFER9 = *mut IDirect3DVertexBuffer9; +RIDL!{#[uuid(0x7c9dd65e, 0xd3f7, 0x4529, 0xac, 0xee, 0x78, 0x58, 0x30, 0xac, 0xde, 0x35)] +interface IDirect3DIndexBuffer9(IDirect3DIndexBuffer9Vtbl): + IDirect3DResource9(IDirect3DResource9Vtbl) { + fn Lock( + OffsetToLock: UINT, + SizeToLock: UINT, + ppbData: *mut *mut VOID, + Flags: DWORD, + ) -> HRESULT, + fn Unlock() -> HRESULT, + fn GetDesc( + pDesc: *mut D3DINDEXBUFFER_DESC, + ) -> HRESULT, +}} +pub type LPDIRECT3DINDEXBUFFER9 = *mut IDirect3DIndexBuffer9; +pub type PDIRECT3DINDEXBUFFER9 = *mut IDirect3DIndexBuffer9; +RIDL!{#[uuid(0xcfbaf3a, 0x9ff6, 0x429a, 0x99, 0xb3, 0xa2, 0x79, 0x6a, 0xf8, 0xb8, 0x9b)] +interface IDirect3DSurface9(IDirect3DSurface9Vtbl): IDirect3DResource9(IDirect3DResource9Vtbl) { + fn GetContainer( + riid: *const IID, + ppContainer: *mut *mut VOID, + ) -> HRESULT, + fn GetDesc( + pDesc: *mut D3DSURFACE_DESC, + ) -> HRESULT, + fn LockRect( + pLockedRect: *mut D3DLOCKED_RECT, + pRect: *const RECT, + Flags: DWORD, + ) -> HRESULT, + fn UnlockRect() -> HRESULT, + fn GetDC( + phdc: *mut HDC, + ) -> HRESULT, + fn ReleaseDC( + hdc: HDC, + ) -> HRESULT, +}} +pub type LPDIRECT3DSURFACE9 = *mut IDirect3DSurface9; +pub type PDIRECT3DSURFACE9 = *mut IDirect3DSurface9; +RIDL!{#[uuid(0x24f416e6, 0x1f67, 0x4aa7, 0xb8, 0x8e, 0xd3, 0x3f, 0x6f, 0x31, 0x28, 0xa1)] +interface IDirect3DVolume9(IDirect3DVolume9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn SetPrivateData( + refguid: *const GUID, + pData: *const VOID, + SizeOfData: DWORD, + Flags: DWORD, + ) -> HRESULT, + fn GetPrivateData( + refguid: *const GUID, + pData: *mut VOID, + pSizeOfData: *mut DWORD, + ) -> HRESULT, + fn FreePrivateData( + refguid: *const GUID, + ) -> HRESULT, + fn GetContainer( + riid: *const IID, + ppContainer: *mut *mut VOID, + ) -> HRESULT, + fn GetDesc( + pDesc: *mut D3DVOLUME_DESC, + ) -> HRESULT, + fn LockBox( + pLockedVolume: *mut D3DLOCKED_BOX, + pBox: *const D3DBOX, + Flags: DWORD, + ) -> HRESULT, + fn UnlockBox() -> HRESULT, +}} +pub type LPDIRECT3DVOLUME9 = *mut IDirect3DVolume9; +pub type PDIRECT3DVOLUME9 = *mut IDirect3DVolume9; +RIDL!{#[uuid(0xd9771460, 0xa695, 0x4f26, 0xbb, 0xd3, 0x27, 0xb8, 0x40, 0xb5, 0x41, 0xcc)] +interface IDirect3DQuery9(IDirect3DQuery9Vtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut IDirect3DDevice9, + ) -> HRESULT, + fn GetType() -> D3DRESOURCETYPE, + fn GetDataSize() -> DWORD, + fn Issue( + dwIssueFlags: DWORD, + ) -> HRESULT, + fn GetData( + pData: *mut VOID, + dwSize: DWORD, + dwGetDataFlags: DWORD, + ) -> HRESULT, +}} +pub type LPDIRECT3DQUERY9 = *mut IDirect3DQuery9; +pub type PDIRECT3DQUERY9 = *mut IDirect3DQuery9; +pub const D3DCREATE_FPU_PRESERVE: DWORD = 0x2; +pub const D3DCREATE_MULTITHREADED: DWORD = 0x4; +pub const D3DCREATE_PUREDEVICE: DWORD = 0x10; +pub const D3DCREATE_SOFTWARE_VERTEXPROCESSING: DWORD = 0x20; +pub const D3DCREATE_HARDWARE_VERTEXPROCESSING: DWORD = 0x40; +pub const D3DCREATE_MIXED_VERTEXPROCESSING: DWORD = 0x80; +pub const D3DCREATE_DISABLE_DRIVER_MANAGEMENT: DWORD = 0x100; +pub const D3DCREATE_ADAPTERGROUP_DEVICE: DWORD = 0x200; +pub const D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX: DWORD = 0x400; +pub const D3DCREATE_NOWINDOWCHANGES: DWORD = 0x800; +pub const D3DCREATE_DISABLE_PSGP_THREADING: DWORD = 0x2000; +pub const D3DCREATE_ENABLE_PRESENTSTATS: DWORD = 0x4000; +pub const D3DCREATE_DISABLE_PRESENTSTATS: DWORD = 0x8000; +pub const D3DCREATE_SCREENSAVER: DWORD = 0x10000000; +pub const D3DADAPTER_DEFAULT: DWORD = 0; +extern "system" { + pub fn Direct3DCreate9Ex( + SDKVersion: UINT, + arg1: *mut *mut IDirect3D9Ex, + ) -> HRESULT; +} +RIDL!{#[uuid(0x02177241, 0x69fc, 0x400c, 0x8f, 0xf1, 0x93, 0xa4, 0x4d, 0xf6, 0x86, 0x1d)] +interface IDirect3D9Ex(IDirect3D9ExVtbl): IDirect3D9(IDirect3D9Vtbl) { + fn GetAdapterModeCountEx( + Adapter: UINT, + pFilter: *const D3DDISPLAYMODEFILTER, + ) -> UINT, + fn EnumAdapterModesEx( + Adapter: UINT, + pFilter: *const D3DDISPLAYMODEFILTER, + Mode: UINT, + pMode: *mut D3DDISPLAYMODEEX, + ) -> HRESULT, + fn GetAdapterDisplayModeEx( + Adapter: UINT, + pMode: *mut D3DDISPLAYMODEEX, + pRotation: *mut D3DDISPLAYROTATION, + ) -> HRESULT, + fn CreateDeviceEx( + Adapter: UINT, + DeviceType: D3DDEVTYPE, + hFocusWindow: HWND, + BehaviorFlags: DWORD, + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + pFullscreenDisplayMode: *mut D3DDISPLAYMODEEX, + ppReturnedDeviceInterface: *mut *mut IDirect3DDevice9Ex, + ) -> HRESULT, + fn GetAdapterLUID( + Adapter: UINT, + pLUID: *mut LUID, + ) -> HRESULT, +}} +pub type LPDIRECT3D9EX = *mut IDirect3D9Ex; +pub type PDIRECT3D9EX = *mut IDirect3D9Ex; +RIDL!{#[uuid(0xb18b10ce, 0x2649, 0x405a, 0x87, 0xf, 0x95, 0xf7, 0x77, 0xd4, 0x31, 0x3a)] +interface IDirect3DDevice9Ex(IDirect3DDevice9ExVtbl): IDirect3DDevice9(IDirect3DDevice9Vtbl) { + fn SetConvolutionMonoKernel( + width: UINT, + height: UINT, + rows: *mut FLOAT, + columns: *mut FLOAT, + ) -> HRESULT, + fn ComposeRects( + pSrc: *mut IDirect3DSurface9, + pDst: *mut IDirect3DSurface9, + pSrcRectDescs: *mut IDirect3DVertexBuffer9, + NumRects: UINT, + pDstRectDescs: *mut IDirect3DVertexBuffer9, + Operation: D3DCOMPOSERECTSOP, + Xoffset: INT, + Yoffset: INT, + ) -> HRESULT, + fn PresentEx( + pSourceRect: *const RECT, + pDestRect: *const RECT, + hDestWindowOverride: HWND, + pDirtyRegion: *const RGNDATA, + dwFlags: DWORD, + ) -> HRESULT, + fn GetGPUThreadPriority( + pPriority: *mut INT, + ) -> HRESULT, + fn SetGPUThreadPriority( + Priority: INT, + ) -> HRESULT, + fn WaitForVBlank( + iSwapChain: UINT, + ) -> HRESULT, + fn CheckResourceResidency( + pResourceArray: *mut *mut IDirect3DResource9, + NumResources: UINT32, + ) -> HRESULT, + fn SetMaximumFrameLatency( + MaxLatency: UINT, + ) -> HRESULT, + fn GetMaximumFrameLatency( + pMaxLatency: *mut UINT, + ) -> HRESULT, + fn CheckDeviceState( + hDestinationWindow: HWND, + ) -> HRESULT, + fn CreateRenderTargetEx( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + MultiSample: D3DMULTISAMPLE_TYPE, + MultisampleQuality: DWORD, + Lockable: BOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + Usage: DWORD, + ) -> HRESULT, + fn CreateOffscreenPlainSurfaceEx( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + Pool: D3DPOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + Usage: DWORD, + ) -> HRESULT, + fn CreateDepthStencilSurfaceEx( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + MultiSample: D3DMULTISAMPLE_TYPE, + MultisampleQuality: DWORD, + Discard: BOOL, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + Usage: DWORD, + ) -> HRESULT, + fn ResetEx( + pPresentationParameters: *mut D3DPRESENT_PARAMETERS, + pFullscreenDisplayMode: *mut D3DDISPLAYMODEEX, + ) -> HRESULT, + fn GetDisplayModeEx( + iSwapChain: UINT, + pMode: *mut D3DDISPLAYMODEEX, + pRotation: *mut D3DDISPLAYROTATION, + ) -> HRESULT, +}} +pub type LPDIRECT3DDEVICE9EX = *mut IDirect3DDevice9Ex; +pub type PDIRECT3DDEVICE9EX = *mut IDirect3DDevice9Ex; +RIDL!{#[uuid(0x91886caf, 0x1c3d, 0x4d2e, 0xa0, 0xab, 0x3e, 0x4c, 0x7d, 0x8d, 0x33, 0x3)] +interface IDirect3DSwapChain9Ex(IDirect3DSwapChain9ExVtbl): + IDirect3DSwapChain9(IDirect3DSwapChain9Vtbl) { + fn GetLastPresentCount( + pLastPresentCount: *mut UINT, + ) -> HRESULT, + fn GetPresentStats( + pPresentationStatistics: *mut D3DPRESENTSTATS, + ) -> HRESULT, + fn GetDisplayModeEx( + pMode: *mut D3DDISPLAYMODEEX, + pRotation: *mut D3DDISPLAYROTATION, + ) -> HRESULT, +}} +pub type LPDIRECT3DSWAPCHAIN9EX = *mut IDirect3DSwapChain9Ex; +pub type PDIRECT3DSWAPCHAIN9EX = *mut IDirect3DSwapChain9Ex; +RIDL!{#[uuid(0x187aeb13, 0xaaf5, 0x4c59, 0x87, 0x6d, 0xe0, 0x59, 0x8, 0x8c, 0xd, 0xf8)] +interface IDirect3D9ExOverlayExtension(IDirect3D9ExOverlayExtensionVtbl): IUnknown(IUnknownVtbl) { + fn CheckDeviceOverlayType( + Adapter: UINT, + DevType: D3DDEVTYPE, + OverlayWidth: UINT, + OverlayHeight: UINT, + OverlayFormat: D3DFORMAT, + pDisplayMode: *mut D3DDISPLAYMODEEX, + DisplayRotation: D3DDISPLAYROTATION, + pOverlayCaps: *mut D3DOVERLAYCAPS, + ) -> HRESULT, +}} +pub type LPDIRECT3D9EXOVERLAYEXTENSION = *mut IDirect3D9ExOverlayExtension; +pub type PDIRECT3D9EXOVERLAYEXTENSION = *mut IDirect3D9ExOverlayExtension; +RIDL!{#[uuid(0x26dc4561, 0xa1ee, 0x4ae7, 0x96, 0xda, 0x11, 0x8a, 0x36, 0xc0, 0xec, 0x95)] +interface IDirect3DDevice9Video(IDirect3DDevice9VideoVtbl): IUnknown(IUnknownVtbl) { + fn GetContentProtectionCaps( + pCryptoType: *const GUID, + pDecodeProfile: *const GUID, + pCaps: *mut D3DCONTENTPROTECTIONCAPS, + ) -> HRESULT, + fn CreateAuthenticatedChannel( + ChannelType: D3DAUTHENTICATEDCHANNELTYPE, + ppAuthenticatedChannel: *mut *mut IDirect3DAuthenticatedChannel9, + pChannelHandle: *mut HANDLE, + ) -> HRESULT, + fn CreateCryptoSession( + pCryptoType: *const GUID, + pDecodeProfile: *const GUID, + ppCryptoSession: *mut *mut IDirect3DCryptoSession9, + pCryptoHandle: *mut HANDLE, + ) -> HRESULT, +}} +pub type LPDIRECT3DDEVICE9VIDEO = *mut IDirect3DDevice9Video; +pub type PDIRECT3DDEVICE9VIDEO = *mut IDirect3DDevice9Video; +RIDL!{#[uuid(0xff24beee, 0xda21, 0x4beb, 0x98, 0xb5, 0xd2, 0xf8, 0x99, 0xf9, 0x8a, 0xf9)] +interface IDirect3DAuthenticatedChannel9(IDirect3DAuthenticatedChannel9Vtbl): + IUnknown(IUnknownVtbl) { + fn GetCertificateSize( + pCertificateSize: *mut UINT, + ) -> HRESULT, + fn GetCertificate( + CertifacteSize: UINT, + ppCertificate: *mut BYTE, + ) -> HRESULT, + fn NegotiateKeyExchange( + DataSize: UINT, + pData: *mut VOID, + ) -> HRESULT, + fn Query( + InputSize: UINT, + pInput: *const VOID, + OutputSize: UINT, + pOutput: *mut VOID, + ) -> HRESULT, + fn Configure( + InputSize: UINT, + pInput: *const VOID, + pOutput: *mut D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT, + ) -> HRESULT, +}} +pub type LPDIRECT3DAUTHENTICATEDCHANNEL9 = *mut IDirect3DAuthenticatedChannel9; +pub type PDIRECT3DAUTHENTICATEDCHANNEL9 = *mut IDirect3DAuthenticatedChannel9; +RIDL!{#[uuid(0xfa0ab799, 0x7a9c, 0x48ca, 0x8c, 0x5b, 0x23, 0x7e, 0x71, 0xa5, 0x44, 0x34)] +interface IDirect3DCryptoSession9(IDirect3DCryptoSession9Vtbl): IUnknown(IUnknownVtbl) { + fn GetCertificateSize( + pCertificateSize: *mut UINT, + ) -> HRESULT, + fn GetCertificate( + CertifacteSize: UINT, + ppCertificate: *mut BYTE, + ) -> HRESULT, + fn NegotiateKeyExchange( + DataSize: UINT, + pData: *mut VOID, + ) -> HRESULT, + fn EncryptionBlt( + pSrcSurface: *mut IDirect3DSurface9, + pDstSurface: *mut IDirect3DSurface9, + DstSurfaceSize: UINT, + pIV: *mut VOID, + ) -> HRESULT, + fn DecryptionBlt( + pSrcSurface: *mut IDirect3DSurface9, + pDstSurface: *mut IDirect3DSurface9, + SrcSurfaceSize: UINT, + pEncryptedBlockInfo: *mut D3DENCRYPTED_BLOCK_INFO, + pContentKey: *mut VOID, + pIV: *mut VOID, + ) -> HRESULT, + fn GetSurfacePitch( + pSrcSurface: *mut IDirect3DSurface9, + pSurfacePitch: *mut UINT, + ) -> HRESULT, + fn StartSessionKeyRefresh( + pRandomNumber: *mut VOID, + RandomNumberSize: UINT, + ) -> HRESULT, + fn FinishSessionKeyRefresh() -> HRESULT, + fn GetEncryptionBltKey( + pReadbackKey: *mut VOID, + KeySize: UINT, + ) -> HRESULT, +}} +pub type LPDIRECT3DCRYPTOSESSION9 = *mut IDirect3DCryptoSession9; +pub type PDIRECT3DCRYPTOSESSION9 = *mut IDirect3DCryptoSession9; diff --git a/winapi/src/shared/d3d9caps.rs b/winapi/src/shared/d3d9caps.rs new file mode 100644 index 000000000..e806e08b7 --- /dev/null +++ b/winapi/src/shared/d3d9caps.rs @@ -0,0 +1,366 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Direct3D capabilities include file +use ctypes::c_float; +use shared::d3d9types::D3DDEVTYPE; +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, INT, UINT}; +use um::winnt::ULONGLONG; +STRUCT!{struct D3DVSHADERCAPS2_0 { + Caps: DWORD, + DynamicFlowControlDepth: INT, + NumTemps: INT, + StaticFlowControlDepth: INT, +}} +pub const D3DVS20CAPS_PREDICATION: DWORD = 1 << 0; +pub const D3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH: DWORD = 24; +pub const D3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH: DWORD = 0; +pub const D3DVS20_MAX_NUMTEMPS: DWORD = 32; +pub const D3DVS20_MIN_NUMTEMPS: DWORD = 12; +pub const D3DVS20_MAX_STATICFLOWCONTROLDEPTH: DWORD = 4; +pub const D3DVS20_MIN_STATICFLOWCONTROLDEPTH: DWORD = 1; +STRUCT!{struct D3DPSHADERCAPS2_0 { + Caps: DWORD, + DynamicFlowControlDepth: INT, + NumTemps: INT, + StaticFlowControlDepth: INT, + NumInstructionSlots: INT, +}} +pub const D3DPS20CAPS_ARBITRARYSWIZZLE: DWORD = 1 << 0; +pub const D3DPS20CAPS_GRADIENTINSTRUCTIONS: DWORD = 1 << 1; +pub const D3DPS20CAPS_PREDICATION: DWORD = 1 << 2; +pub const D3DPS20CAPS_NODEPENDENTREADLIMIT: DWORD = 1 << 3; +pub const D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT: DWORD = 1 << 4; +pub const D3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH: DWORD = 24; +pub const D3DPS20_MIN_DYNAMICFLOWCONTROLDEPTH: DWORD = 0; +pub const D3DPS20_MAX_NUMTEMPS: DWORD = 32; +pub const D3DPS20_MIN_NUMTEMPS: DWORD = 12; +pub const D3DPS20_MAX_STATICFLOWCONTROLDEPTH: DWORD = 4; +pub const D3DPS20_MIN_STATICFLOWCONTROLDEPTH: DWORD = 0; +pub const D3DPS20_MAX_NUMINSTRUCTIONSLOTS: DWORD = 512; +pub const D3DPS20_MIN_NUMINSTRUCTIONSLOTS: DWORD = 96; +pub const D3DMIN30SHADERINSTRUCTIONS: DWORD = 512; +pub const D3DMAX30SHADERINSTRUCTIONS: DWORD = 32768; +STRUCT!{struct D3DOVERLAYCAPS { + Caps: UINT, + MaxOverlayDisplayWidth: UINT, + MaxOverlayDisplayHeight: UINT, +}} +pub const D3DOVERLAYCAPS_FULLRANGERGB: DWORD = 0x00000001; +pub const D3DOVERLAYCAPS_LIMITEDRANGERGB: DWORD = 0x00000002; +pub const D3DOVERLAYCAPS_YCbCr_BT601: DWORD = 0x00000004; +pub const D3DOVERLAYCAPS_YCbCr_BT709: DWORD = 0x00000008; +pub const D3DOVERLAYCAPS_YCbCr_BT601_xvYCC: DWORD = 0x00000010; +pub const D3DOVERLAYCAPS_YCbCr_BT709_xvYCC: DWORD = 0x00000020; +pub const D3DOVERLAYCAPS_STRETCHX: DWORD = 0x00000040; +pub const D3DOVERLAYCAPS_STRETCHY: DWORD = 0x00000080; +// FIXME packed(4) +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS { + Caps: DWORD, + KeyExchangeType: GUID, + BufferAlignmentStart: UINT, + BlockAlignmentSize: UINT, + ProtectedMemorySize: ULONGLONG, +}} +pub const D3DCPCAPS_SOFTWARE: DWORD = 0x00000001; +pub const D3DCPCAPS_HARDWARE: DWORD = 0x00000002; +pub const D3DCPCAPS_PROTECTIONALWAYSON: DWORD = 0x00000004; +pub const D3DCPCAPS_PARTIALDECRYPTION: DWORD = 0x00000008; +pub const D3DCPCAPS_CONTENTKEY: DWORD = 0x00000010; +pub const D3DCPCAPS_FRESHENSESSIONKEY: DWORD = 0x00000020; +pub const D3DCPCAPS_ENCRYPTEDREADBACK: DWORD = 0x00000040; +pub const D3DCPCAPS_ENCRYPTEDREADBACKKEY: DWORD = 0x00000080; +pub const D3DCPCAPS_SEQUENTIAL_CTR_IV: DWORD = 0x00000100; +pub const D3DCPCAPS_ENCRYPTSLICEDATAONLY: DWORD = 0x00000200; +DEFINE_GUID!{D3DCRYPTOTYPE_AES128_CTR, + 0x9b6bd711, 0x4f74, 0x41c9, 0x9e, 0x7b, 0x0b, 0xe2, 0xd7, 0xd9, 0x3b, 0x4f} +DEFINE_GUID!{D3DCRYPTOTYPE_PROPRIETARY, + 0xab4e9afd, 0x1d1c, 0x46e6, 0xa7, 0x2f, 0x08, 0x69, 0x91, 0x7b, 0x0d, 0xe8} +DEFINE_GUID!{D3DKEYEXCHANGE_RSAES_OAEP, + 0xc1949895, 0xd72a, 0x4a1d, 0x8e, 0x5d, 0xed, 0x85, 0x7d, 0x17, 0x15, 0x20} +DEFINE_GUID!{D3DKEYEXCHANGE_DXVA, + 0x43d3775c, 0x38e5, 0x4924, 0x8d, 0x86, 0xd3, 0xfc, 0xcf, 0x15, 0x3e, 0x9b} +STRUCT!{struct D3DCAPS9 { + DeviceType: D3DDEVTYPE, + AdapterOrdinal: UINT, + Caps: DWORD, + Caps2: DWORD, + Caps3: DWORD, + PresentationIntervals: DWORD, + CursorCaps: DWORD, + DevCaps: DWORD, + PrimitiveMiscCaps: DWORD, + RasterCaps: DWORD, + ZCmpCaps: DWORD, + SrcBlendCaps: DWORD, + DestBlendCaps: DWORD, + AlphaCmpCaps: DWORD, + ShadeCaps: DWORD, + TextureCaps: DWORD, + TextureFilterCaps: DWORD, + CubeTextureFilterCaps: DWORD, + VolumeTextureFilterCaps: DWORD, + TextureAddressCaps: DWORD, + VolumeTextureAddressCaps: DWORD, + LineCaps: DWORD, + MaxTextureWidth: DWORD, + MaxTextureHeight: DWORD, + MaxVolumeExtent: DWORD, + MaxTextureRepeat: DWORD, + MaxTextureAspectRatio: DWORD, + MaxAnisotropy: DWORD, + MaxVertexW: c_float, + GuardBandLeft: c_float, + GuardBandTop: c_float, + GuardBandRight: c_float, + GuardBandBottom: c_float, + ExtentsAdjust: c_float, + StencilCaps: DWORD, + FVFCaps: DWORD, + TextureOpCaps: DWORD, + MaxTextureBlendStages: DWORD, + MaxSimultaneousTextures: DWORD, + VertexProcessingCaps: DWORD, + MaxActiveLights: DWORD, + MaxUserClipPlanes: DWORD, + MaxVertexBlendMatrices: DWORD, + MaxVertexBlendMatrixIndex: DWORD, + MaxPointSize: c_float, + MaxPrimitiveCount: DWORD, + MaxVertexIndex: DWORD, + MaxStreams: DWORD, + MaxStreamStride: DWORD, + VertexShaderVersion: DWORD, + MaxVertexShaderConst: DWORD, + PixelShaderVersion: DWORD, + PixelShader1xMaxValue: c_float, + DevCaps2: DWORD, + MaxNpatchTessellationLevel: c_float, + Reserved5: DWORD, + MasterAdapterOrdinal: UINT, + AdapterOrdinalInGroup: UINT, + NumberOfAdaptersInGroup: UINT, + DeclTypes: DWORD, + NumSimultaneousRTs: DWORD, + StretchRectFilterCaps: DWORD, + VS20Caps: D3DVSHADERCAPS2_0, + PS20Caps: D3DPSHADERCAPS2_0, + VertexTextureFilterCaps: DWORD, + MaxVShaderInstructionsExecuted: DWORD, + MaxPShaderInstructionsExecuted: DWORD, + MaxVertexShader30InstructionSlots: DWORD, + MaxPixelShader30InstructionSlots: DWORD, +}} +pub const D3DCAPS_OVERLAY: DWORD = 0x00000800; +pub const D3DCAPS_READ_SCANLINE: DWORD = 0x00020000; +pub const D3DCAPS2_FULLSCREENGAMMA: DWORD = 0x00020000; +pub const D3DCAPS2_CANCALIBRATEGAMMA: DWORD = 0x00100000; +pub const D3DCAPS2_RESERVED: DWORD = 0x02000000; +pub const D3DCAPS2_CANMANAGERESOURCE: DWORD = 0x10000000; +pub const D3DCAPS2_DYNAMICTEXTURES: DWORD = 0x20000000; +pub const D3DCAPS2_CANAUTOGENMIPMAP: DWORD = 0x40000000; +pub const D3DCAPS2_CANSHARERESOURCE: DWORD = 0x80000000; +pub const D3DCAPS3_RESERVED: DWORD = 0x8000001f; +pub const D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD: DWORD = 0x00000020; +pub const D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION: DWORD = 0x00000080; +pub const D3DCAPS3_COPY_TO_VIDMEM: DWORD = 0x00000100; +pub const D3DCAPS3_COPY_TO_SYSTEMMEM: DWORD = 0x00000200; +pub const D3DCAPS3_DXVAHD: DWORD = 0x00000400; +pub const D3DCAPS3_DXVAHD_LIMITED: DWORD = 0x00000800; +pub const D3DPRESENT_INTERVAL_DEFAULT: DWORD = 0x00000000; +pub const D3DPRESENT_INTERVAL_ONE: DWORD = 0x00000001; +pub const D3DPRESENT_INTERVAL_TWO: DWORD = 0x00000002; +pub const D3DPRESENT_INTERVAL_THREE: DWORD = 0x00000004; +pub const D3DPRESENT_INTERVAL_FOUR: DWORD = 0x00000008; +pub const D3DPRESENT_INTERVAL_IMMEDIATE: DWORD = 0x80000000; +pub const D3DCURSORCAPS_COLOR: DWORD = 0x00000001; +pub const D3DCURSORCAPS_LOWRES: DWORD = 0x00000002; +pub const D3DDEVCAPS_EXECUTESYSTEMMEMORY: DWORD = 0x00000010; +pub const D3DDEVCAPS_EXECUTEVIDEOMEMORY: DWORD = 0x00000020; +pub const D3DDEVCAPS_TLVERTEXSYSTEMMEMORY: DWORD = 0x00000040; +pub const D3DDEVCAPS_TLVERTEXVIDEOMEMORY: DWORD = 0x00000080; +pub const D3DDEVCAPS_TEXTURESYSTEMMEMORY: DWORD = 0x00000100; +pub const D3DDEVCAPS_TEXTUREVIDEOMEMORY: DWORD = 0x00000200; +pub const D3DDEVCAPS_DRAWPRIMTLVERTEX: DWORD = 0x00000400; +pub const D3DDEVCAPS_CANRENDERAFTERFLIP: DWORD = 0x00000800; +pub const D3DDEVCAPS_TEXTURENONLOCALVIDMEM: DWORD = 0x00001000; +pub const D3DDEVCAPS_DRAWPRIMITIVES2: DWORD = 0x00002000; +pub const D3DDEVCAPS_SEPARATETEXTUREMEMORIES: DWORD = 0x00004000; +pub const D3DDEVCAPS_DRAWPRIMITIVES2EX: DWORD = 0x00008000; +pub const D3DDEVCAPS_HWTRANSFORMANDLIGHT: DWORD = 0x00010000; +pub const D3DDEVCAPS_CANBLTSYSTONONLOCAL: DWORD = 0x00020000; +pub const D3DDEVCAPS_HWRASTERIZATION: DWORD = 0x00080000; +pub const D3DDEVCAPS_PUREDEVICE: DWORD = 0x00100000; +pub const D3DDEVCAPS_QUINTICRTPATCHES: DWORD = 0x00200000; +pub const D3DDEVCAPS_RTPATCHES: DWORD = 0x00400000; +pub const D3DDEVCAPS_RTPATCHHANDLEZERO: DWORD = 0x00800000; +pub const D3DDEVCAPS_NPATCHES: DWORD = 0x01000000; +pub const D3DPMISCCAPS_MASKZ: DWORD = 0x00000002; +pub const D3DPMISCCAPS_CULLNONE: DWORD = 0x00000010; +pub const D3DPMISCCAPS_CULLCW: DWORD = 0x00000020; +pub const D3DPMISCCAPS_CULLCCW: DWORD = 0x00000040; +pub const D3DPMISCCAPS_COLORWRITEENABLE: DWORD = 0x00000080; +pub const D3DPMISCCAPS_CLIPPLANESCALEDPOINTS: DWORD = 0x00000100; +pub const D3DPMISCCAPS_CLIPTLVERTS: DWORD = 0x00000200; +pub const D3DPMISCCAPS_TSSARGTEMP: DWORD = 0x00000400; +pub const D3DPMISCCAPS_BLENDOP: DWORD = 0x00000800; +pub const D3DPMISCCAPS_NULLREFERENCE: DWORD = 0x00001000; +pub const D3DPMISCCAPS_INDEPENDENTWRITEMASKS: DWORD = 0x00004000; +pub const D3DPMISCCAPS_PERSTAGECONSTANT: DWORD = 0x00008000; +pub const D3DPMISCCAPS_FOGANDSPECULARALPHA: DWORD = 0x00010000; +pub const D3DPMISCCAPS_SEPARATEALPHABLEND: DWORD = 0x00020000; +pub const D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS: DWORD = 0x00040000; +pub const D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING: DWORD = 0x00080000; +pub const D3DPMISCCAPS_FOGVERTEXCLAMPED: DWORD = 0x00100000; +pub const D3DPMISCCAPS_POSTBLENDSRGBCONVERT: DWORD = 0x00200000; +pub const D3DLINECAPS_TEXTURE: DWORD = 0x00000001; +pub const D3DLINECAPS_ZTEST: DWORD = 0x00000002; +pub const D3DLINECAPS_BLEND: DWORD = 0x00000004; +pub const D3DLINECAPS_ALPHACMP: DWORD = 0x00000008; +pub const D3DLINECAPS_FOG: DWORD = 0x00000010; +pub const D3DLINECAPS_ANTIALIAS: DWORD = 0x00000020; +pub const D3DPRASTERCAPS_DITHER: DWORD = 0x00000001; +pub const D3DPRASTERCAPS_ZTEST: DWORD = 0x00000010; +pub const D3DPRASTERCAPS_FOGVERTEX: DWORD = 0x00000080; +pub const D3DPRASTERCAPS_FOGTABLE: DWORD = 0x00000100; +pub const D3DPRASTERCAPS_MIPMAPLODBIAS: DWORD = 0x00002000; +pub const D3DPRASTERCAPS_ZBUFFERLESSHSR: DWORD = 0x00008000; +pub const D3DPRASTERCAPS_FOGRANGE: DWORD = 0x00010000; +pub const D3DPRASTERCAPS_ANISOTROPY: DWORD = 0x00020000; +pub const D3DPRASTERCAPS_WBUFFER: DWORD = 0x00040000; +pub const D3DPRASTERCAPS_WFOG: DWORD = 0x00100000; +pub const D3DPRASTERCAPS_ZFOG: DWORD = 0x00200000; +pub const D3DPRASTERCAPS_COLORPERSPECTIVE: DWORD = 0x00400000; +pub const D3DPRASTERCAPS_SCISSORTEST: DWORD = 0x01000000; +pub const D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS: DWORD = 0x02000000; +pub const D3DPRASTERCAPS_DEPTHBIAS: DWORD = 0x04000000; +pub const D3DPRASTERCAPS_MULTISAMPLE_TOGGLE: DWORD = 0x08000000; +pub const D3DPCMPCAPS_NEVER: DWORD = 0x00000001; +pub const D3DPCMPCAPS_LESS: DWORD = 0x00000002; +pub const D3DPCMPCAPS_EQUAL: DWORD = 0x00000004; +pub const D3DPCMPCAPS_LESSEQUAL: DWORD = 0x00000008; +pub const D3DPCMPCAPS_GREATER: DWORD = 0x00000010; +pub const D3DPCMPCAPS_NOTEQUAL: DWORD = 0x00000020; +pub const D3DPCMPCAPS_GREATEREQUAL: DWORD = 0x00000040; +pub const D3DPCMPCAPS_ALWAYS: DWORD = 0x00000080; +pub const D3DPBLENDCAPS_ZERO: DWORD = 0x00000001; +pub const D3DPBLENDCAPS_ONE: DWORD = 0x00000002; +pub const D3DPBLENDCAPS_SRCCOLOR: DWORD = 0x00000004; +pub const D3DPBLENDCAPS_INVSRCCOLOR: DWORD = 0x00000008; +pub const D3DPBLENDCAPS_SRCALPHA: DWORD = 0x00000010; +pub const D3DPBLENDCAPS_INVSRCALPHA: DWORD = 0x00000020; +pub const D3DPBLENDCAPS_DESTALPHA: DWORD = 0x00000040; +pub const D3DPBLENDCAPS_INVDESTALPHA: DWORD = 0x00000080; +pub const D3DPBLENDCAPS_DESTCOLOR: DWORD = 0x00000100; +pub const D3DPBLENDCAPS_INVDESTCOLOR: DWORD = 0x00000200; +pub const D3DPBLENDCAPS_SRCALPHASAT: DWORD = 0x00000400; +pub const D3DPBLENDCAPS_BOTHSRCALPHA: DWORD = 0x00000800; +pub const D3DPBLENDCAPS_BOTHINVSRCALPHA: DWORD = 0x00001000; +pub const D3DPBLENDCAPS_BLENDFACTOR: DWORD = 0x00002000; +pub const D3DPBLENDCAPS_SRCCOLOR2: DWORD = 0x00004000; +pub const D3DPBLENDCAPS_INVSRCCOLOR2: DWORD = 0x00008000; +pub const D3DPSHADECAPS_COLORGOURAUDRGB: DWORD = 0x00000008; +pub const D3DPSHADECAPS_SPECULARGOURAUDRGB: DWORD = 0x00000200; +pub const D3DPSHADECAPS_ALPHAGOURAUDBLEND: DWORD = 0x00004000; +pub const D3DPSHADECAPS_FOGGOURAUD: DWORD = 0x00080000; +pub const D3DPTEXTURECAPS_PERSPECTIVE: DWORD = 0x00000001; +pub const D3DPTEXTURECAPS_POW2: DWORD = 0x00000002; +pub const D3DPTEXTURECAPS_ALPHA: DWORD = 0x00000004; +pub const D3DPTEXTURECAPS_SQUAREONLY: DWORD = 0x00000020; +pub const D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE: DWORD = 0x00000040; +pub const D3DPTEXTURECAPS_ALPHAPALETTE: DWORD = 0x00000080; +pub const D3DPTEXTURECAPS_NONPOW2CONDITIONAL: DWORD = 0x00000100; +pub const D3DPTEXTURECAPS_PROJECTED: DWORD = 0x00000400; +pub const D3DPTEXTURECAPS_CUBEMAP: DWORD = 0x00000800; +pub const D3DPTEXTURECAPS_VOLUMEMAP: DWORD = 0x00002000; +pub const D3DPTEXTURECAPS_MIPMAP: DWORD = 0x00004000; +pub const D3DPTEXTURECAPS_MIPVOLUMEMAP: DWORD = 0x00008000; +pub const D3DPTEXTURECAPS_MIPCUBEMAP: DWORD = 0x00010000; +pub const D3DPTEXTURECAPS_CUBEMAP_POW2: DWORD = 0x00020000; +pub const D3DPTEXTURECAPS_VOLUMEMAP_POW2: DWORD = 0x00040000; +pub const D3DPTEXTURECAPS_NOPROJECTEDBUMPENV: DWORD = 0x00200000; +pub const D3DPTFILTERCAPS_MINFPOINT: DWORD = 0x00000100; +pub const D3DPTFILTERCAPS_MINFLINEAR: DWORD = 0x00000200; +pub const D3DPTFILTERCAPS_MINFANISOTROPIC: DWORD = 0x00000400; +pub const D3DPTFILTERCAPS_MINFPYRAMIDALQUAD: DWORD = 0x00000800; +pub const D3DPTFILTERCAPS_MINFGAUSSIANQUAD: DWORD = 0x00001000; +pub const D3DPTFILTERCAPS_MIPFPOINT: DWORD = 0x00010000; +pub const D3DPTFILTERCAPS_MIPFLINEAR: DWORD = 0x00020000; +pub const D3DPTFILTERCAPS_CONVOLUTIONMONO: DWORD = 0x00040000; +pub const D3DPTFILTERCAPS_MAGFPOINT: DWORD = 0x01000000; +pub const D3DPTFILTERCAPS_MAGFLINEAR: DWORD = 0x02000000; +pub const D3DPTFILTERCAPS_MAGFANISOTROPIC: DWORD = 0x04000000; +pub const D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD: DWORD = 0x08000000; +pub const D3DPTFILTERCAPS_MAGFGAUSSIANQUAD: DWORD = 0x10000000; +pub const D3DPTADDRESSCAPS_WRAP: DWORD = 0x00000001; +pub const D3DPTADDRESSCAPS_MIRROR: DWORD = 0x00000002; +pub const D3DPTADDRESSCAPS_CLAMP: DWORD = 0x00000004; +pub const D3DPTADDRESSCAPS_BORDER: DWORD = 0x00000008; +pub const D3DPTADDRESSCAPS_INDEPENDENTUV: DWORD = 0x00000010; +pub const D3DPTADDRESSCAPS_MIRRORONCE: DWORD = 0x00000020; +pub const D3DSTENCILCAPS_KEEP: DWORD = 0x00000001; +pub const D3DSTENCILCAPS_ZERO: DWORD = 0x00000002; +pub const D3DSTENCILCAPS_REPLACE: DWORD = 0x00000004; +pub const D3DSTENCILCAPS_INCRSAT: DWORD = 0x00000008; +pub const D3DSTENCILCAPS_DECRSAT: DWORD = 0x00000010; +pub const D3DSTENCILCAPS_INVERT: DWORD = 0x00000020; +pub const D3DSTENCILCAPS_INCR: DWORD = 0x00000040; +pub const D3DSTENCILCAPS_DECR: DWORD = 0x00000080; +pub const D3DSTENCILCAPS_TWOSIDED: DWORD = 0x00000100; +pub const D3DTEXOPCAPS_DISABLE: DWORD = 0x00000001; +pub const D3DTEXOPCAPS_SELECTARG1: DWORD = 0x00000002; +pub const D3DTEXOPCAPS_SELECTARG2: DWORD = 0x00000004; +pub const D3DTEXOPCAPS_MODULATE: DWORD = 0x00000008; +pub const D3DTEXOPCAPS_MODULATE2X: DWORD = 0x00000010; +pub const D3DTEXOPCAPS_MODULATE4X: DWORD = 0x00000020; +pub const D3DTEXOPCAPS_ADD: DWORD = 0x00000040; +pub const D3DTEXOPCAPS_ADDSIGNED: DWORD = 0x00000080; +pub const D3DTEXOPCAPS_ADDSIGNED2X: DWORD = 0x00000100; +pub const D3DTEXOPCAPS_SUBTRACT: DWORD = 0x00000200; +pub const D3DTEXOPCAPS_ADDSMOOTH: DWORD = 0x00000400; +pub const D3DTEXOPCAPS_BLENDDIFFUSEALPHA: DWORD = 0x00000800; +pub const D3DTEXOPCAPS_BLENDTEXTUREALPHA: DWORD = 0x00001000; +pub const D3DTEXOPCAPS_BLENDFACTORALPHA: DWORD = 0x00002000; +pub const D3DTEXOPCAPS_BLENDTEXTUREALPHAPM: DWORD = 0x00004000; +pub const D3DTEXOPCAPS_BLENDCURRENTALPHA: DWORD = 0x00008000; +pub const D3DTEXOPCAPS_PREMODULATE: DWORD = 0x00010000; +pub const D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR: DWORD = 0x00020000; +pub const D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA: DWORD = 0x00040000; +pub const D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR: DWORD = 0x00080000; +pub const D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA: DWORD = 0x00100000; +pub const D3DTEXOPCAPS_BUMPENVMAP: DWORD = 0x00200000; +pub const D3DTEXOPCAPS_BUMPENVMAPLUMINANCE: DWORD = 0x00400000; +pub const D3DTEXOPCAPS_DOTPRODUCT3: DWORD = 0x00800000; +pub const D3DTEXOPCAPS_MULTIPLYADD: DWORD = 0x01000000; +pub const D3DTEXOPCAPS_LERP: DWORD = 0x02000000; +pub const D3DFVFCAPS_TEXCOORDCOUNTMASK: DWORD = 0x0000ffff; +pub const D3DFVFCAPS_DONOTSTRIPELEMENTS: DWORD = 0x00080000; +pub const D3DFVFCAPS_PSIZE: DWORD = 0x00100000; +pub const D3DVTXPCAPS_TEXGEN: DWORD = 0x00000001; +pub const D3DVTXPCAPS_MATERIALSOURCE7: DWORD = 0x00000002; +pub const D3DVTXPCAPS_DIRECTIONALLIGHTS: DWORD = 0x00000008; +pub const D3DVTXPCAPS_POSITIONALLIGHTS: DWORD = 0x00000010; +pub const D3DVTXPCAPS_LOCALVIEWER: DWORD = 0x00000020; +pub const D3DVTXPCAPS_TWEENING: DWORD = 0x00000040; +pub const D3DVTXPCAPS_TEXGEN_SPHEREMAP: DWORD = 0x00000100; +pub const D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER: DWORD = 0x00000200; +pub const D3DDEVCAPS2_STREAMOFFSET: DWORD = 0x00000001; +pub const D3DDEVCAPS2_DMAPNPATCH: DWORD = 0x00000002; +pub const D3DDEVCAPS2_ADAPTIVETESSRTPATCH: DWORD = 0x00000004; +pub const D3DDEVCAPS2_ADAPTIVETESSNPATCH: DWORD = 0x00000008; +pub const D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES: DWORD = 0x00000010; +pub const D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH: DWORD = 0x00000020; +pub const D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET: DWORD = 0x00000040; +pub const D3DDTCAPS_UBYTE4: DWORD = 0x00000001; +pub const D3DDTCAPS_UBYTE4N: DWORD = 0x00000002; +pub const D3DDTCAPS_SHORT2N: DWORD = 0x00000004; +pub const D3DDTCAPS_SHORT4N: DWORD = 0x00000008; +pub const D3DDTCAPS_USHORT2N: DWORD = 0x00000010; +pub const D3DDTCAPS_USHORT4N: DWORD = 0x00000020; +pub const D3DDTCAPS_UDEC3: DWORD = 0x00000040; +pub const D3DDTCAPS_DEC3N: DWORD = 0x00000080; +pub const D3DDTCAPS_FLOAT16_2: DWORD = 0x00000100; +pub const D3DDTCAPS_FLOAT16_4: DWORD = 0x00000200; diff --git a/winapi/src/shared/d3d9types.rs b/winapi/src/shared/d3d9types.rs new file mode 100644 index 000000000..e794d2731 --- /dev/null +++ b/winapi/src/shared/d3d9types.rs @@ -0,0 +1,1487 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Direct3D capabilities include file +use ctypes::{c_char, c_float, c_void}; +use shared::basetsd::UINT64; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, UINT, USHORT, WORD}; +use shared::windef::HWND; +use um::winnt::{HANDLE, HRESULT, LARGE_INTEGER, LONG, SHORT}; +pub type D3DCOLOR = DWORD; +#[inline] +pub fn D3DCOLOR_ARGB(a: DWORD, r: DWORD, g: DWORD, b: DWORD) -> D3DCOLOR { + (((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) as D3DCOLOR +} +#[inline] +pub fn D3DCOLOR_RGBA(r: DWORD, g: DWORD, b: DWORD, a: DWORD) -> D3DCOLOR { + D3DCOLOR_ARGB(a, r, g, b) +} +#[inline] +pub fn D3DCOLOR_XRGB(r: DWORD, g: DWORD, b: DWORD) -> D3DCOLOR { + D3DCOLOR_ARGB(0xff, r, g, b) +} +#[inline] +pub fn D3DCOLOR_XYUV(y: DWORD, u: DWORD, v: DWORD) -> D3DCOLOR { + D3DCOLOR_ARGB(0xff, y, u, v) +} +#[inline] +pub fn D3DCOLOR_AYUV(a: DWORD, y: DWORD, u: DWORD, v: DWORD) -> D3DCOLOR { + D3DCOLOR_ARGB(a, y, u, v) +} +#[inline] +pub fn D3DCOLOR_COLORVALUE(r: f32, g: f32, b: f32, a: f32) -> D3DCOLOR { + D3DCOLOR_ARGB( + (r * 255f32) as DWORD, + (g * 255f32) as DWORD, + (b * 255f32) as DWORD, + (a * 255f32) as DWORD, + ) +} +STRUCT!{struct D3DVECTOR { + x: c_float, + y: c_float, + z: c_float, +}} +STRUCT!{struct D3DCOLORVALUE { + r: c_float, + g: c_float, + b: c_float, + a: c_float, +}} +STRUCT!{struct D3DRECT { + x1: LONG, + y1: LONG, + x2: LONG, + y2: LONG, +}} +STRUCT!{struct D3DMATRIX { + m: [[c_float; 4]; 4], +}} +STRUCT!{struct D3DVIEWPORT9 { + X: DWORD, + Y: DWORD, + Width: DWORD, + Height: DWORD, + MinZ: c_float, + MaxZ: c_float, +}} +pub const D3DMAXUSERCLIPPLANES: DWORD = 32; +pub const D3DCLIPPLANE0: DWORD = 1 << 0; +pub const D3DCLIPPLANE1: DWORD = 1 << 1; +pub const D3DCLIPPLANE2: DWORD = 1 << 2; +pub const D3DCLIPPLANE3: DWORD = 1 << 3; +pub const D3DCLIPPLANE4: DWORD = 1 << 4; +pub const D3DCLIPPLANE5: DWORD = 1 << 5; +pub const D3DCS_LEFT: DWORD = 0x00000001; +pub const D3DCS_RIGHT: DWORD = 0x00000002; +pub const D3DCS_TOP: DWORD = 0x00000004; +pub const D3DCS_BOTTOM: DWORD = 0x00000008; +pub const D3DCS_FRONT: DWORD = 0x00000010; +pub const D3DCS_BACK: DWORD = 0x00000020; +pub const D3DCS_PLANE0: DWORD = 0x00000040; +pub const D3DCS_PLANE1: DWORD = 0x00000080; +pub const D3DCS_PLANE2: DWORD = 0x00000100; +pub const D3DCS_PLANE3: DWORD = 0x00000200; +pub const D3DCS_PLANE4: DWORD = 0x00000400; +pub const D3DCS_PLANE5: DWORD = 0x00000800; +pub const D3DCS_ALL: DWORD = D3DCS_LEFT | D3DCS_RIGHT | D3DCS_TOP | D3DCS_BOTTOM | D3DCS_FRONT + | D3DCS_BACK | D3DCS_PLANE0 | D3DCS_PLANE1 | D3DCS_PLANE2 | D3DCS_PLANE3 | D3DCS_PLANE4 + | D3DCS_PLANE5; +STRUCT!{struct D3DCLIPSTATUS9 { + ClipUnion: DWORD, + ClipIntersection: DWORD, +}} +STRUCT!{struct D3DMATERIAL9 { + Diffuse: D3DCOLORVALUE, + Ambient: D3DCOLORVALUE, + Specular: D3DCOLORVALUE, + Emissive: D3DCOLORVALUE, + Power: c_float, +}} +ENUM!{enum D3DLIGHTTYPE { + D3DLIGHT_POINT = 1, + D3DLIGHT_SPOT = 2, + D3DLIGHT_DIRECTIONAL = 3, +}} +STRUCT!{struct D3DLIGHT9 { + Type: D3DLIGHTTYPE, + Diffuse: D3DCOLORVALUE, + Specular: D3DCOLORVALUE, + Ambient: D3DCOLORVALUE, + Position: D3DVECTOR, + Direction: D3DVECTOR, + Range: c_float, + Falloff: c_float, + Attenuation0: c_float, + Attenuation1: c_float, + Attenuation2: c_float, + Theta: c_float, + Phi: c_float, +}} +pub const D3DCLEAR_TARGET: DWORD = 0x00000001; +pub const D3DCLEAR_ZBUFFER: DWORD = 0x00000002; +pub const D3DCLEAR_STENCIL: DWORD = 0x00000004; +ENUM!{enum D3DSHADEMODE { + D3DSHADE_FLAT = 1, + D3DSHADE_GOURAUD = 2, + D3DSHADE_PHONG = 3, +}} +ENUM!{enum D3DFILLMODE { + D3DFILL_POINT = 1, + D3DFILL_WIREFRAME = 2, + D3DFILL_SOLID = 3, +}} +ENUM!{enum D3DBLEND { + D3DBLEND_ZERO = 1, + D3DBLEND_ONE = 2, + D3DBLEND_SRCCOLOR = 3, + D3DBLEND_INVSRCCOLOR = 4, + D3DBLEND_SRCALPHA = 5, + D3DBLEND_INVSRCALPHA = 6, + D3DBLEND_DESTALPHA = 7, + D3DBLEND_INVDESTALPHA = 8, + D3DBLEND_DESTCOLOR = 9, + D3DBLEND_INVDESTCOLOR = 10, + D3DBLEND_SRCALPHASAT = 11, + D3DBLEND_BOTHSRCALPHA = 12, + D3DBLEND_BOTHINVSRCALPHA = 13, + D3DBLEND_BLENDFACTOR = 14, + D3DBLEND_INVBLENDFACTOR = 15, + D3DBLEND_SRCCOLOR2 = 16, + D3DBLEND_INVSRCCOLOR2 = 17, +}} +ENUM!{enum D3DBLENDOP { + D3DBLENDOP_ADD = 1, + D3DBLENDOP_SUBTRACT = 2, + D3DBLENDOP_REVSUBTRACT = 3, + D3DBLENDOP_MIN = 4, + D3DBLENDOP_MAX = 5, +}} +ENUM!{enum D3DTEXTUREADDRESS { + D3DTADDRESS_WRAP = 1, + D3DTADDRESS_MIRROR = 2, + D3DTADDRESS_CLAMP = 3, + D3DTADDRESS_BORDER = 4, + D3DTADDRESS_MIRRORONCE = 5, +}} +ENUM!{enum D3DCULL { + D3DCULL_NONE = 1, + D3DCULL_CW = 2, + D3DCULL_CCW = 3, +}} +ENUM!{enum D3DCMPFUNC { + D3DCMP_NEVER = 1, + D3DCMP_LESS = 2, + D3DCMP_EQUAL = 3, + D3DCMP_LESSEQUAL = 4, + D3DCMP_GREATER = 5, + D3DCMP_NOTEQUAL = 6, + D3DCMP_GREATEREQUAL = 7, + D3DCMP_ALWAYS = 8, +}} +ENUM!{enum D3DSTENCILOP { + D3DSTENCILOP_KEEP = 1, + D3DSTENCILOP_ZERO = 2, + D3DSTENCILOP_REPLACE = 3, + D3DSTENCILOP_INCRSAT = 4, + D3DSTENCILOP_DECRSAT = 5, + D3DSTENCILOP_INVERT = 6, + D3DSTENCILOP_INCR = 7, + D3DSTENCILOP_DECR = 8, +}} +ENUM!{enum D3DFOGMODE { + D3DFOG_NONE = 0, + D3DFOG_EXP = 1, + D3DFOG_EXP2 = 2, + D3DFOG_LINEAR = 3, +}} +ENUM!{enum D3DZBUFFERTYPE { + D3DZB_FALSE = 0, + D3DZB_TRUE = 1, + D3DZB_USEW = 2, +}} +ENUM!{enum D3DPRIMITIVETYPE { + D3DPT_POINTLIST = 1, + D3DPT_LINELIST = 2, + D3DPT_LINESTRIP = 3, + D3DPT_TRIANGLELIST = 4, + D3DPT_TRIANGLESTRIP = 5, + D3DPT_TRIANGLEFAN = 6, +}} +ENUM!{enum D3DTRANSFORMSTATETYPE { + D3DTS_VIEW = 2, + D3DTS_PROJECTION = 3, + D3DTS_TEXTURE0 = 16, + D3DTS_TEXTURE1 = 17, + D3DTS_TEXTURE2 = 18, + D3DTS_TEXTURE3 = 19, + D3DTS_TEXTURE4 = 20, + D3DTS_TEXTURE5 = 21, + D3DTS_TEXTURE6 = 22, + D3DTS_TEXTURE7 = 23, +}} +macro_rules! D3DTS_WORLDMATRIX { + ($index:expr) => ($index + 256) +} +pub const D3DTS_WORLD: D3DTRANSFORMSTATETYPE = D3DTS_WORLDMATRIX!(0); +pub const D3DTS_WORLD1: D3DTRANSFORMSTATETYPE = D3DTS_WORLDMATRIX!(1); +pub const D3DTS_WORLD2: D3DTRANSFORMSTATETYPE = D3DTS_WORLDMATRIX!(2); +pub const D3DTS_WORLD3: D3DTRANSFORMSTATETYPE = D3DTS_WORLDMATRIX!(3); +ENUM!{enum D3DRENDERSTATETYPE { + D3DRS_ZENABLE = 7, + D3DRS_FILLMODE = 8, + D3DRS_SHADEMODE = 9, + D3DRS_ZWRITEENABLE = 14, + D3DRS_ALPHATESTENABLE = 15, + D3DRS_LASTPIXEL = 16, + D3DRS_SRCBLEND = 19, + D3DRS_DESTBLEND = 20, + D3DRS_CULLMODE = 22, + D3DRS_ZFUNC = 23, + D3DRS_ALPHAREF = 24, + D3DRS_ALPHAFUNC = 25, + D3DRS_DITHERENABLE = 26, + D3DRS_ALPHABLENDENABLE = 27, + D3DRS_FOGENABLE = 28, + D3DRS_SPECULARENABLE = 29, + D3DRS_FOGCOLOR = 34, + D3DRS_FOGTABLEMODE = 35, + D3DRS_FOGSTART = 36, + D3DRS_FOGEND = 37, + D3DRS_FOGDENSITY = 38, + D3DRS_RANGEFOGENABLE = 48, + D3DRS_STENCILENABLE = 52, + D3DRS_STENCILFAIL = 53, + D3DRS_STENCILZFAIL = 54, + D3DRS_STENCILPASS = 55, + D3DRS_STENCILFUNC = 56, + D3DRS_STENCILREF = 57, + D3DRS_STENCILMASK = 58, + D3DRS_STENCILWRITEMASK = 59, + D3DRS_TEXTUREFACTOR = 60, + D3DRS_WRAP0 = 128, + D3DRS_WRAP1 = 129, + D3DRS_WRAP2 = 130, + D3DRS_WRAP3 = 131, + D3DRS_WRAP4 = 132, + D3DRS_WRAP5 = 133, + D3DRS_WRAP6 = 134, + D3DRS_WRAP7 = 135, + D3DRS_CLIPPING = 136, + D3DRS_LIGHTING = 137, + D3DRS_AMBIENT = 139, + D3DRS_FOGVERTEXMODE = 140, + D3DRS_COLORVERTEX = 141, + D3DRS_LOCALVIEWER = 142, + D3DRS_NORMALIZENORMALS = 143, + D3DRS_DIFFUSEMATERIALSOURCE = 145, + D3DRS_SPECULARMATERIALSOURCE = 146, + D3DRS_AMBIENTMATERIALSOURCE = 147, + D3DRS_EMISSIVEMATERIALSOURCE = 148, + D3DRS_VERTEXBLEND = 151, + D3DRS_CLIPPLANEENABLE = 152, + D3DRS_POINTSIZE = 154, + D3DRS_POINTSIZE_MIN = 155, + D3DRS_POINTSPRITEENABLE = 156, + D3DRS_POINTSCALEENABLE = 157, + D3DRS_POINTSCALE_A = 158, + D3DRS_POINTSCALE_B = 159, + D3DRS_POINTSCALE_C = 160, + D3DRS_MULTISAMPLEANTIALIAS = 161, + D3DRS_MULTISAMPLEMASK = 162, + D3DRS_PATCHEDGESTYLE = 163, + D3DRS_DEBUGMONITORTOKEN = 165, + D3DRS_POINTSIZE_MAX = 166, + D3DRS_INDEXEDVERTEXBLENDENABLE = 167, + D3DRS_COLORWRITEENABLE = 168, + D3DRS_TWEENFACTOR = 170, + D3DRS_BLENDOP = 171, + D3DRS_POSITIONDEGREE = 172, + D3DRS_NORMALDEGREE = 173, + D3DRS_SCISSORTESTENABLE = 174, + D3DRS_SLOPESCALEDEPTHBIAS = 175, + D3DRS_ANTIALIASEDLINEENABLE = 176, + D3DRS_MINTESSELLATIONLEVEL = 178, + D3DRS_MAXTESSELLATIONLEVEL = 179, + D3DRS_ADAPTIVETESS_X = 180, + D3DRS_ADAPTIVETESS_Y = 181, + D3DRS_ADAPTIVETESS_Z = 182, + D3DRS_ADAPTIVETESS_W = 183, + D3DRS_ENABLEADAPTIVETESSELLATION = 184, + D3DRS_TWOSIDEDSTENCILMODE = 185, + D3DRS_CCW_STENCILFAIL = 186, + D3DRS_CCW_STENCILZFAIL = 187, + D3DRS_CCW_STENCILPASS = 188, + D3DRS_CCW_STENCILFUNC = 189, + D3DRS_COLORWRITEENABLE1 = 190, + D3DRS_COLORWRITEENABLE2 = 191, + D3DRS_COLORWRITEENABLE3 = 192, + D3DRS_BLENDFACTOR = 193, + D3DRS_SRGBWRITEENABLE = 194, + D3DRS_DEPTHBIAS = 195, + D3DRS_WRAP8 = 198, + D3DRS_WRAP9 = 199, + D3DRS_WRAP10 = 200, + D3DRS_WRAP11 = 201, + D3DRS_WRAP12 = 202, + D3DRS_WRAP13 = 203, + D3DRS_WRAP14 = 204, + D3DRS_WRAP15 = 205, + D3DRS_SEPARATEALPHABLENDENABLE = 206, + D3DRS_SRCBLENDALPHA = 207, + D3DRS_DESTBLENDALPHA = 208, + D3DRS_BLENDOPALPHA = 209, +}} +pub const D3D_MAX_SIMULTANEOUS_RENDERTARGETS: DWORD = 4; +ENUM!{enum D3DMATERIALCOLORSOURCE { + D3DMCS_MATERIAL = 0, + D3DMCS_COLOR1 = 1, + D3DMCS_COLOR2 = 2, +}} +pub const D3DRENDERSTATE_WRAPBIAS: DWORD = 128; +pub const D3DWRAP_U: DWORD = 0x00000001; +pub const D3DWRAP_V: DWORD = 0x00000002; +pub const D3DWRAP_W: DWORD = 0x00000004; +pub const D3DWRAPCOORD_0: DWORD = 0x00000001; +pub const D3DWRAPCOORD_1: DWORD = 0x00000002; +pub const D3DWRAPCOORD_2: DWORD = 0x00000004; +pub const D3DWRAPCOORD_3: DWORD = 0x00000008; +pub const D3DCOLORWRITEENABLE_RED: DWORD = 1 << 0; +pub const D3DCOLORWRITEENABLE_GREEN: DWORD = 1 << 1; +pub const D3DCOLORWRITEENABLE_BLUE: DWORD = 1 << 2; +pub const D3DCOLORWRITEENABLE_ALPHA: DWORD = 1 << 3; +ENUM!{enum D3DTEXTURESTAGESTATETYPE { + D3DTSS_COLOROP = 1, + D3DTSS_COLORARG1 = 2, + D3DTSS_COLORARG2 = 3, + D3DTSS_ALPHAOP = 4, + D3DTSS_ALPHAARG1 = 5, + D3DTSS_ALPHAARG2 = 6, + D3DTSS_BUMPENVMAT00 = 7, + D3DTSS_BUMPENVMAT01 = 8, + D3DTSS_BUMPENVMAT10 = 9, + D3DTSS_BUMPENVMAT11 = 10, + D3DTSS_TEXCOORDINDEX = 11, + D3DTSS_BUMPENVLSCALE = 22, + D3DTSS_BUMPENVLOFFSET = 23, + D3DTSS_TEXTURETRANSFORMFLAGS = 24, + D3DTSS_COLORARG0 = 26, + D3DTSS_ALPHAARG0 = 27, + D3DTSS_RESULTARG = 28, + D3DTSS_CONSTANT = 32, +}} +ENUM!{enum D3DSAMPLERSTATETYPE { + D3DSAMP_ADDRESSU = 1, + D3DSAMP_ADDRESSV = 2, + D3DSAMP_ADDRESSW = 3, + D3DSAMP_BORDERCOLOR = 4, + D3DSAMP_MAGFILTER = 5, + D3DSAMP_MINFILTER = 6, + D3DSAMP_MIPFILTER = 7, + D3DSAMP_MIPMAPLODBIAS = 8, + D3DSAMP_MAXMIPLEVEL = 9, + D3DSAMP_MAXANISOTROPY = 10, + D3DSAMP_SRGBTEXTURE = 11, + D3DSAMP_ELEMENTINDEX = 12, + D3DSAMP_DMAPOFFSET = 13, +}} +pub const D3DDMAPSAMPLER: DWORD = 256; +pub const D3DVERTEXTEXTURESAMPLER0: DWORD = D3DDMAPSAMPLER + 1; +pub const D3DVERTEXTEXTURESAMPLER1: DWORD = D3DDMAPSAMPLER + 2; +pub const D3DVERTEXTEXTURESAMPLER2: DWORD = D3DDMAPSAMPLER + 3; +pub const D3DVERTEXTEXTURESAMPLER3: DWORD = D3DDMAPSAMPLER + 4; +pub const D3DTSS_TCI_PASSTHRU: DWORD = 0x00000000; +pub const D3DTSS_TCI_CAMERASPACENORMAL: DWORD = 0x00010000; +pub const D3DTSS_TCI_CAMERASPACEPOSITION: DWORD = 0x00020000; +pub const D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: DWORD = 0x00030000; +pub const D3DTSS_TCI_SPHEREMAP: DWORD = 0x00040000; +ENUM!{enum D3DTEXTUREOP { + D3DTOP_DISABLE = 1, + D3DTOP_SELECTARG1 = 2, + D3DTOP_SELECTARG2 = 3, + D3DTOP_MODULATE = 4, + D3DTOP_MODULATE2X = 5, + D3DTOP_MODULATE4X = 6, + D3DTOP_ADD = 7, + D3DTOP_ADDSIGNED = 8, + D3DTOP_ADDSIGNED2X = 9, + D3DTOP_SUBTRACT = 10, + D3DTOP_ADDSMOOTH = 11, + D3DTOP_BLENDDIFFUSEALPHA = 12, + D3DTOP_BLENDTEXTUREALPHA = 13, + D3DTOP_BLENDFACTORALPHA = 14, + D3DTOP_BLENDTEXTUREALPHAPM = 15, + D3DTOP_BLENDCURRENTALPHA = 16, + D3DTOP_PREMODULATE = 17, + D3DTOP_MODULATEALPHA_ADDCOLOR = 18, + D3DTOP_MODULATECOLOR_ADDALPHA = 19, + D3DTOP_MODULATEINVALPHA_ADDCOLOR = 20, + D3DTOP_MODULATEINVCOLOR_ADDALPHA = 21, + D3DTOP_BUMPENVMAP = 22, + D3DTOP_BUMPENVMAPLUMINANCE = 23, + D3DTOP_DOTPRODUCT3 = 24, + D3DTOP_MULTIPLYADD = 25, + D3DTOP_LERP = 26, +}} +pub const D3DTA_SELECTMASK: DWORD = 0x0000000f; +pub const D3DTA_DIFFUSE: DWORD = 0x00000000; +pub const D3DTA_CURRENT: DWORD = 0x00000001; +pub const D3DTA_TEXTURE: DWORD = 0x00000002; +pub const D3DTA_TFACTOR: DWORD = 0x00000003; +pub const D3DTA_SPECULAR: DWORD = 0x00000004; +pub const D3DTA_TEMP: DWORD = 0x00000005; +pub const D3DTA_CONSTANT: DWORD = 0x00000006; +pub const D3DTA_COMPLEMENT: DWORD = 0x00000010; +pub const D3DTA_ALPHAREPLICATE: DWORD = 0x00000020; +ENUM!{enum D3DTEXTUREFILTERTYPE { + D3DTEXF_NONE = 0, + D3DTEXF_POINT = 1, + D3DTEXF_LINEAR = 2, + D3DTEXF_ANISOTROPIC = 3, + D3DTEXF_PYRAMIDALQUAD = 6, + D3DTEXF_GAUSSIANQUAD = 7, + D3DTEXF_CONVOLUTIONMONO = 8, +}} +pub const D3DPV_DONOTCOPYDATA: DWORD = 1 << 0; +pub const D3DFVF_RESERVED0: DWORD = 0x001; +pub const D3DFVF_POSITION_MASK: DWORD = 0x400E; +pub const D3DFVF_XYZ: DWORD = 0x002; +pub const D3DFVF_XYZRHW: DWORD = 0x004; +pub const D3DFVF_XYZB1: DWORD = 0x006; +pub const D3DFVF_XYZB2: DWORD = 0x008; +pub const D3DFVF_XYZB3: DWORD = 0x00a; +pub const D3DFVF_XYZB4: DWORD = 0x00c; +pub const D3DFVF_XYZB5: DWORD = 0x00e; +pub const D3DFVF_XYZW: DWORD = 0x4002; +pub const D3DFVF_NORMAL: DWORD = 0x010; +pub const D3DFVF_PSIZE: DWORD = 0x020; +pub const D3DFVF_DIFFUSE: DWORD = 0x040; +pub const D3DFVF_SPECULAR: DWORD = 0x080; +pub const D3DFVF_TEXCOUNT_MASK: DWORD = 0xf00; +pub const D3DFVF_TEXCOUNT_SHIFT: DWORD = 8; +pub const D3DFVF_TEX0: DWORD = 0x000; +pub const D3DFVF_TEX1: DWORD = 0x100; +pub const D3DFVF_TEX2: DWORD = 0x200; +pub const D3DFVF_TEX3: DWORD = 0x300; +pub const D3DFVF_TEX4: DWORD = 0x400; +pub const D3DFVF_TEX5: DWORD = 0x500; +pub const D3DFVF_TEX6: DWORD = 0x600; +pub const D3DFVF_TEX7: DWORD = 0x700; +pub const D3DFVF_TEX8: DWORD = 0x800; +pub const D3DFVF_LASTBETA_UBYTE4: DWORD = 0x1000; +pub const D3DFVF_LASTBETA_D3DCOLOR: DWORD = 0x8000; +pub const D3DFVF_RESERVED2: DWORD = 0x6000; +ENUM!{enum D3DDECLUSAGE { + D3DDECLUSAGE_POSITION = 0, + D3DDECLUSAGE_BLENDWEIGHT, + D3DDECLUSAGE_BLENDINDICES, + D3DDECLUSAGE_NORMAL, + D3DDECLUSAGE_PSIZE, + D3DDECLUSAGE_TEXCOORD, + D3DDECLUSAGE_TANGENT, + D3DDECLUSAGE_BINORMAL, + D3DDECLUSAGE_TESSFACTOR, + D3DDECLUSAGE_POSITIONT, + D3DDECLUSAGE_COLOR, + D3DDECLUSAGE_FOG, + D3DDECLUSAGE_DEPTH, + D3DDECLUSAGE_SAMPLE, +}} +pub const MAXD3DDECLUSAGE: D3DDECLUSAGE = D3DDECLUSAGE_SAMPLE; +pub const MAXD3DDECLUSAGEINDEX: DWORD = 15; +pub const MAXD3DDECLLENGTH: DWORD = 64; +ENUM!{enum D3DDECLMETHOD { + D3DDECLMETHOD_DEFAULT = 0, + D3DDECLMETHOD_PARTIALU, + D3DDECLMETHOD_PARTIALV, + D3DDECLMETHOD_CROSSUV, + D3DDECLMETHOD_UV, + D3DDECLMETHOD_LOOKUP, + D3DDECLMETHOD_LOOKUPPRESAMPLED, +}} +pub const MAXD3DDECLMETHOD: D3DDECLMETHOD = D3DDECLMETHOD_LOOKUPPRESAMPLED; +ENUM!{enum D3DDECLTYPE { + D3DDECLTYPE_FLOAT1 = 0, + D3DDECLTYPE_FLOAT2 = 1, + D3DDECLTYPE_FLOAT3 = 2, + D3DDECLTYPE_FLOAT4 = 3, + D3DDECLTYPE_D3DCOLOR = 4, + D3DDECLTYPE_UBYTE4 = 5, + D3DDECLTYPE_SHORT2 = 6, + D3DDECLTYPE_SHORT4 = 7, + D3DDECLTYPE_UBYTE4N = 8, + D3DDECLTYPE_SHORT2N = 9, + D3DDECLTYPE_SHORT4N = 10, + D3DDECLTYPE_USHORT2N = 11, + D3DDECLTYPE_USHORT4N = 12, + D3DDECLTYPE_UDEC3 = 13, + D3DDECLTYPE_DEC3N = 14, + D3DDECLTYPE_FLOAT16_2 = 15, + D3DDECLTYPE_FLOAT16_4 = 16, + D3DDECLTYPE_UNUSED = 17, +}} +pub const MAXD3DDECLTYPE: D3DDECLTYPE = D3DDECLTYPE_UNUSED; +STRUCT!{struct D3DVERTEXELEMENT9 { + Stream: WORD, + Offset: WORD, + Type: BYTE, + Method: BYTE, + Usage: BYTE, + UsageIndex: BYTE, +}} +pub type LPD3DVERTEXELEMENT9 = *mut D3DVERTEXELEMENT9; +pub const D3DDECL_END: D3DVERTEXELEMENT9 = D3DVERTEXELEMENT9 { + Stream: 0xFF, + Offset: 0, + Type: D3DDECLTYPE_UNUSED as BYTE, + Method: 0, + Usage: 0, + UsageIndex: 0, +}; +pub const D3DDP_MAXTEXCOORD: DWORD = 8; +pub const D3DSTREAMSOURCE_INDEXEDDATA: DWORD = 1 << 30; +pub const D3DSTREAMSOURCE_INSTANCEDATA: DWORD = 2 << 30; +pub const D3DSI_OPCODE_MASK: DWORD = 0x0000FFFF; +pub const D3DSI_INSTLENGTH_MASK: DWORD = 0x0F000000; +pub const D3DSI_INSTLENGTH_SHIFT: DWORD = 24; +ENUM!{enum D3DSHADER_INSTRUCTION_OPCODE_TYPE { + D3DSIO_NOP = 0, + D3DSIO_MOV, + D3DSIO_ADD, + D3DSIO_SUB, + D3DSIO_MAD, + D3DSIO_MUL, + D3DSIO_RCP, + D3DSIO_RSQ, + D3DSIO_DP3, + D3DSIO_DP4, + D3DSIO_MIN, + D3DSIO_MAX, + D3DSIO_SLT, + D3DSIO_SGE, + D3DSIO_EXP, + D3DSIO_LOG, + D3DSIO_LIT, + D3DSIO_DST, + D3DSIO_LRP, + D3DSIO_FRC, + D3DSIO_M4x4, + D3DSIO_M4x3, + D3DSIO_M3x4, + D3DSIO_M3x3, + D3DSIO_M3x2, + D3DSIO_CALL, + D3DSIO_CALLNZ, + D3DSIO_LOOP, + D3DSIO_RET, + D3DSIO_ENDLOOP, + D3DSIO_LABEL, + D3DSIO_DCL, + D3DSIO_POW, + D3DSIO_CRS, + D3DSIO_SGN, + D3DSIO_ABS, + D3DSIO_NRM, + D3DSIO_SINCOS, + D3DSIO_REP, + D3DSIO_ENDREP, + D3DSIO_IF, + D3DSIO_IFC, + D3DSIO_ELSE, + D3DSIO_ENDIF, + D3DSIO_BREAK, + D3DSIO_BREAKC, + D3DSIO_MOVA, + D3DSIO_DEFB, + D3DSIO_DEFI, + D3DSIO_TEXCOORD = 64, + D3DSIO_TEXKILL, + D3DSIO_TEX, + D3DSIO_TEXBEM, + D3DSIO_TEXBEML, + D3DSIO_TEXREG2AR, + D3DSIO_TEXREG2GB, + D3DSIO_TEXM3x2PAD, + D3DSIO_TEXM3x2TEX, + D3DSIO_TEXM3x3PAD, + D3DSIO_TEXM3x3TEX, + D3DSIO_RESERVED0, + D3DSIO_TEXM3x3SPEC, + D3DSIO_TEXM3x3VSPEC, + D3DSIO_EXPP, + D3DSIO_LOGP, + D3DSIO_CND, + D3DSIO_DEF, + D3DSIO_TEXREG2RGB, + D3DSIO_TEXDP3TEX, + D3DSIO_TEXM3x2DEPTH, + D3DSIO_TEXDP3, + D3DSIO_TEXM3x3, + D3DSIO_TEXDEPTH, + D3DSIO_CMP, + D3DSIO_BEM, + D3DSIO_DP2ADD, + D3DSIO_DSX, + D3DSIO_DSY, + D3DSIO_TEXLDD, + D3DSIO_SETP, + D3DSIO_TEXLDL, + D3DSIO_BREAKP, + D3DSIO_PHASE = 0xFFFD, + D3DSIO_COMMENT = 0xFFFE, + D3DSIO_END = 0xFFFF, +}} +pub const D3DSI_COISSUE: DWORD = 0x40000000; +pub const D3DSP_OPCODESPECIFICCONTROL_MASK: DWORD = 0x00ff0000; +pub const D3DSP_OPCODESPECIFICCONTROL_SHIFT: DWORD = 16; +pub const D3DSI_TEXLD_PROJECT: DWORD = 0x01 << D3DSP_OPCODESPECIFICCONTROL_SHIFT; +pub const D3DSI_TEXLD_BIAS: DWORD = 0x02 << D3DSP_OPCODESPECIFICCONTROL_SHIFT; +ENUM!{enum D3DSHADER_COMPARISON { + D3DSPC_RESERVED0 = 0, + D3DSPC_GT = 1, + D3DSPC_EQ = 2, + D3DSPC_GE = 3, + D3DSPC_LT = 4, + D3DSPC_NE = 5, + D3DSPC_LE = 6, + D3DSPC_RESERVED1 = 7, +}} +pub const D3DSHADER_COMPARISON_SHIFT: DWORD = D3DSP_OPCODESPECIFICCONTROL_SHIFT; +pub const D3DSHADER_COMPARISON_MASK: DWORD = 0x7 << D3DSHADER_COMPARISON_SHIFT; +pub const D3DSHADER_INSTRUCTION_PREDICATED: DWORD = 0x1 << 28; +pub const D3DSP_DCL_USAGE_SHIFT: DWORD = 0; +pub const D3DSP_DCL_USAGE_MASK: DWORD = 0x0000000f; +pub const D3DSP_DCL_USAGEINDEX_SHIFT: DWORD = 16; +pub const D3DSP_DCL_USAGEINDEX_MASK: DWORD = 0x000f0000; +pub const D3DSP_TEXTURETYPE_SHIFT: DWORD = 27; +pub const D3DSP_TEXTURETYPE_MASK: DWORD = 0x78000000; +ENUM!{enum D3DSAMPLER_TEXTURE_TYPE { + D3DSTT_UNKNOWN = 0 << D3DSP_TEXTURETYPE_SHIFT, + D3DSTT_2D = 2 << D3DSP_TEXTURETYPE_SHIFT, + D3DSTT_CUBE = 3 << D3DSP_TEXTURETYPE_SHIFT, + D3DSTT_VOLUME = 4 << D3DSP_TEXTURETYPE_SHIFT, +}} +pub const D3DSP_REGNUM_MASK: DWORD = 0x000007FF; +pub const D3DSP_WRITEMASK_0: DWORD = 0x00010000; +pub const D3DSP_WRITEMASK_1: DWORD = 0x00020000; +pub const D3DSP_WRITEMASK_2: DWORD = 0x00040000; +pub const D3DSP_WRITEMASK_3: DWORD = 0x00080000; +pub const D3DSP_WRITEMASK_ALL: DWORD = 0x000F0000; +pub const D3DSP_DSTMOD_SHIFT: DWORD = 20; +pub const D3DSP_DSTMOD_MASK: DWORD = 0x00F00000; +pub const D3DSPDM_NONE: DWORD = 0 << D3DSP_DSTMOD_SHIFT; +pub const D3DSPDM_SATURATE: DWORD = 1 << D3DSP_DSTMOD_SHIFT; +pub const D3DSPDM_PARTIALPRECISION: DWORD = 2 << D3DSP_DSTMOD_SHIFT; +pub const D3DSPDM_MSAMPCENTROID: DWORD = 4 << D3DSP_DSTMOD_SHIFT; +pub const D3DSP_DSTSHIFT_SHIFT: DWORD = 24; +pub const D3DSP_DSTSHIFT_MASK: DWORD = 0x0F000000; +pub const D3DSP_REGTYPE_SHIFT: DWORD = 28; +pub const D3DSP_REGTYPE_SHIFT2: DWORD = 8; +pub const D3DSP_REGTYPE_MASK: DWORD = 0x70000000; +pub const D3DSP_REGTYPE_MASK2: DWORD = 0x00001800; +ENUM!{enum D3DSHADER_PARAM_REGISTER_TYPE { + D3DSPR_TEMP = 0, + D3DSPR_INPUT = 1, + D3DSPR_CONST = 2, + D3DSPR_ADDR = 3, + D3DSPR_TEXTURE = 3, + D3DSPR_RASTOUT = 4, + D3DSPR_ATTROUT = 5, + D3DSPR_TEXCRDOUT = 6, + D3DSPR_OUTPUT = 6, + D3DSPR_CONSTINT = 7, + D3DSPR_COLOROUT = 8, + D3DSPR_DEPTHOUT = 9, + D3DSPR_SAMPLER = 10, + D3DSPR_CONST2 = 11, + D3DSPR_CONST3 = 12, + D3DSPR_CONST4 = 13, + D3DSPR_CONSTBOOL = 14, + D3DSPR_LOOP = 15, + D3DSPR_TEMPFLOAT16 = 16, + D3DSPR_MISCTYPE = 17, + D3DSPR_LABEL = 18, + D3DSPR_PREDICATE = 19, +}} +ENUM!{enum D3DSHADER_MISCTYPE_OFFSETS { + D3DSMO_POSITION = 0, + D3DSMO_FACE = 1, +}} +ENUM!{enum D3DVS_RASTOUT_OFFSETS { + D3DSRO_POSITION = 0, + D3DSRO_FOG, + D3DSRO_POINT_SIZE, +}} +pub const D3DVS_ADDRESSMODE_SHIFT: DWORD = 13; +pub const D3DVS_ADDRESSMODE_MASK: DWORD = 1 << D3DVS_ADDRESSMODE_SHIFT; +ENUM!{enum D3DVS_ADDRESSMODE_TYPE { + D3DVS_ADDRMODE_ABSOLUTE = 0 << D3DVS_ADDRESSMODE_SHIFT, + D3DVS_ADDRMODE_RELATIVE = 1 << D3DVS_ADDRESSMODE_SHIFT, +}} +pub const D3DSHADER_ADDRESSMODE_SHIFT: DWORD = 13; +pub const D3DSHADER_ADDRESSMODE_MASK: DWORD = 1 << D3DSHADER_ADDRESSMODE_SHIFT; +ENUM!{enum D3DSHADER_ADDRESSMODE_TYPE { + D3DSHADER_ADDRMODE_ABSOLUTE = 0 << D3DSHADER_ADDRESSMODE_SHIFT, + D3DSHADER_ADDRMODE_RELATIVE = 1 << D3DSHADER_ADDRESSMODE_SHIFT, +}} +pub const D3DVS_SWIZZLE_SHIFT: DWORD = 16; +pub const D3DVS_SWIZZLE_MASK: DWORD = 0x00FF0000; +pub const D3DVS_X_X: DWORD = 0 << D3DVS_SWIZZLE_SHIFT; +pub const D3DVS_X_Y: DWORD = 1 << D3DVS_SWIZZLE_SHIFT; +pub const D3DVS_X_Z: DWORD = 2 << D3DVS_SWIZZLE_SHIFT; +pub const D3DVS_X_W: DWORD = 3 << D3DVS_SWIZZLE_SHIFT; +pub const D3DVS_Y_X: DWORD = 0 << (D3DVS_SWIZZLE_SHIFT + 2); +pub const D3DVS_Y_Y: DWORD = 1 << (D3DVS_SWIZZLE_SHIFT + 2); +pub const D3DVS_Y_Z: DWORD = 2 << (D3DVS_SWIZZLE_SHIFT + 2); +pub const D3DVS_Y_W: DWORD = 3 << (D3DVS_SWIZZLE_SHIFT + 2); +pub const D3DVS_Z_X: DWORD = 0 << (D3DVS_SWIZZLE_SHIFT + 4); +pub const D3DVS_Z_Y: DWORD = 1 << (D3DVS_SWIZZLE_SHIFT + 4); +pub const D3DVS_Z_Z: DWORD = 2 << (D3DVS_SWIZZLE_SHIFT + 4); +pub const D3DVS_Z_W: DWORD = 3 << (D3DVS_SWIZZLE_SHIFT + 4); +pub const D3DVS_W_X: DWORD = 0 << (D3DVS_SWIZZLE_SHIFT + 6); +pub const D3DVS_W_Y: DWORD = 1 << (D3DVS_SWIZZLE_SHIFT + 6); +pub const D3DVS_W_Z: DWORD = 2 << (D3DVS_SWIZZLE_SHIFT + 6); +pub const D3DVS_W_W: DWORD = 3 << (D3DVS_SWIZZLE_SHIFT + 6); +pub const D3DVS_NOSWIZZLE: DWORD = D3DVS_X_X | D3DVS_Y_Y | D3DVS_Z_Z | D3DVS_W_W; +pub const D3DSP_SWIZZLE_SHIFT: DWORD = 16; +pub const D3DSP_SWIZZLE_MASK: DWORD = 0x00FF0000; +pub const D3DSP_NOSWIZZLE: DWORD = (0 << (D3DSP_SWIZZLE_SHIFT + 0)) + | (1 << (D3DSP_SWIZZLE_SHIFT + 2)) | (2 << (D3DSP_SWIZZLE_SHIFT + 4)) + | (3 << (D3DSP_SWIZZLE_SHIFT + 6)); +pub const D3DSP_REPLICATERED: DWORD = (0 << (D3DSP_SWIZZLE_SHIFT + 0)) + | (0 << (D3DSP_SWIZZLE_SHIFT + 2)) | (0 << (D3DSP_SWIZZLE_SHIFT + 4)) + | (0 << (D3DSP_SWIZZLE_SHIFT + 6)); +pub const D3DSP_REPLICATEGREEN: DWORD = (1 << (D3DSP_SWIZZLE_SHIFT + 0)) + | (1 << (D3DSP_SWIZZLE_SHIFT + 2)) | (1 << (D3DSP_SWIZZLE_SHIFT + 4)) + | (1 << (D3DSP_SWIZZLE_SHIFT + 6)); +pub const D3DSP_REPLICATEBLUE: DWORD = (2 << (D3DSP_SWIZZLE_SHIFT + 0)) + | (2 << (D3DSP_SWIZZLE_SHIFT + 2)) | (2 << (D3DSP_SWIZZLE_SHIFT + 4)) + | (2 << (D3DSP_SWIZZLE_SHIFT + 6)); +pub const D3DSP_REPLICATEALPHA: DWORD = (3 << (D3DSP_SWIZZLE_SHIFT + 0)) + | (3 << (D3DSP_SWIZZLE_SHIFT + 2)) | (3 << (D3DSP_SWIZZLE_SHIFT + 4)) + | (3 << (D3DSP_SWIZZLE_SHIFT + 6)); +pub const D3DSP_SRCMOD_SHIFT: DWORD = 24; +pub const D3DSP_SRCMOD_MASK: DWORD = 0x0F000000; +ENUM!{enum D3DSHADER_PARAM_SRCMOD_TYPE { + D3DSPSM_NONE = 0 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_NEG = 1 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_BIAS = 2 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_BIASNEG = 3 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_SIGN = 4 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_SIGNNEG = 5 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_COMP = 6 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_X2 = 7 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_X2NEG = 8 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_DZ = 9 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_DW = 10 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_ABS = 11 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_ABSNEG = 12 << D3DSP_SRCMOD_SHIFT, + D3DSPSM_NOT = 13 << D3DSP_SRCMOD_SHIFT, +}} +pub const D3DSP_MIN_PRECISION_SHIFT: DWORD = 14; +pub const D3DSP_MIN_PRECISION_MASK: DWORD = 0x0000C000; +ENUM!{enum D3DSHADER_MIN_PRECISION { + D3DMP_DEFAULT = 0, + D3DMP_16 = 1, + D3DMP_2_8 = 2, +}} +pub const D3DSI_COMMENTSIZE_SHIFT: DWORD = 16; +pub const D3DSI_COMMENTSIZE_MASK: DWORD = 0x7FFF0000; +pub const D3DPS_END: DWORD = 0x0000FFFF; +pub const D3DVS_END: DWORD = 0x0000FFFF; +ENUM!{enum D3DBASISTYPE { + D3DBASIS_BEZIER = 0, + D3DBASIS_BSPLINE = 1, + D3DBASIS_CATMULL_ROM = 2, +}} +ENUM!{enum D3DDEGREETYPE { + D3DDEGREE_LINEAR = 1, + D3DDEGREE_QUADRATIC = 2, + D3DDEGREE_CUBIC = 3, + D3DDEGREE_QUINTIC = 5, +}} +ENUM!{enum D3DPATCHEDGESTYLE { + D3DPATCHEDGE_DISCRETE = 0, + D3DPATCHEDGE_CONTINUOUS = 1, +}} +ENUM!{enum D3DSTATEBLOCKTYPE { + D3DSBT_ALL = 1, + D3DSBT_PIXELSTATE = 2, + D3DSBT_VERTEXSTATE = 3, +}} +ENUM!{enum D3DVERTEXBLENDFLAGS { + D3DVBF_DISABLE = 0, + D3DVBF_1WEIGHTS = 1, + D3DVBF_2WEIGHTS = 2, + D3DVBF_3WEIGHTS = 3, + D3DVBF_TWEENING = 255, + D3DVBF_0WEIGHTS = 256, +}} +ENUM!{enum D3DTEXTURETRANSFORMFLAGS { + D3DTTFF_DISABLE = 0, + D3DTTFF_COUNT1 = 1, + D3DTTFF_COUNT2 = 2, + D3DTTFF_COUNT3 = 3, + D3DTTFF_COUNT4 = 4, + D3DTTFF_PROJECTED = 256, +}} +pub const D3DFVF_TEXTUREFORMAT2: DWORD = 0; +pub const D3DFVF_TEXTUREFORMAT1: DWORD = 3; +pub const D3DFVF_TEXTUREFORMAT3: DWORD = 1; +pub const D3DFVF_TEXTUREFORMAT4: DWORD = 2; +ENUM!{enum D3DDEVTYPE { + D3DDEVTYPE_HAL = 1, + D3DDEVTYPE_REF = 2, + D3DDEVTYPE_SW = 3, + D3DDEVTYPE_NULLREF = 4, +}} +ENUM!{enum D3DMULTISAMPLE_TYPE { + D3DMULTISAMPLE_NONE = 0, + D3DMULTISAMPLE_NONMASKABLE = 1, + D3DMULTISAMPLE_2_SAMPLES = 2, + D3DMULTISAMPLE_3_SAMPLES = 3, + D3DMULTISAMPLE_4_SAMPLES = 4, + D3DMULTISAMPLE_5_SAMPLES = 5, + D3DMULTISAMPLE_6_SAMPLES = 6, + D3DMULTISAMPLE_7_SAMPLES = 7, + D3DMULTISAMPLE_8_SAMPLES = 8, + D3DMULTISAMPLE_9_SAMPLES = 9, + D3DMULTISAMPLE_10_SAMPLES = 10, + D3DMULTISAMPLE_11_SAMPLES = 11, + D3DMULTISAMPLE_12_SAMPLES = 12, + D3DMULTISAMPLE_13_SAMPLES = 13, + D3DMULTISAMPLE_14_SAMPLES = 14, + D3DMULTISAMPLE_15_SAMPLES = 15, + D3DMULTISAMPLE_16_SAMPLES = 16, +}} +ENUM!{enum D3DFORMAT { + D3DFMT_UNKNOWN = 0, + D3DFMT_R8G8B8 = 20, + D3DFMT_A8R8G8B8 = 21, + D3DFMT_X8R8G8B8 = 22, + D3DFMT_R5G6B5 = 23, + D3DFMT_X1R5G5B5 = 24, + D3DFMT_A1R5G5B5 = 25, + D3DFMT_A4R4G4B4 = 26, + D3DFMT_R3G3B2 = 27, + D3DFMT_A8 = 28, + D3DFMT_A8R3G3B2 = 29, + D3DFMT_X4R4G4B4 = 30, + D3DFMT_A2B10G10R10 = 31, + D3DFMT_A8B8G8R8 = 32, + D3DFMT_X8B8G8R8 = 33, + D3DFMT_G16R16 = 34, + D3DFMT_A2R10G10B10 = 35, + D3DFMT_A16B16G16R16 = 36, + D3DFMT_A8P8 = 40, + D3DFMT_P8 = 41, + D3DFMT_L8 = 50, + D3DFMT_A8L8 = 51, + D3DFMT_A4L4 = 52, + D3DFMT_V8U8 = 60, + D3DFMT_L6V5U5 = 61, + D3DFMT_X8L8V8U8 = 62, + D3DFMT_Q8W8V8U8 = 63, + D3DFMT_V16U16 = 64, + D3DFMT_A2W10V10U10 = 67, + D3DFMT_UYVY = MAKEFOURCC!(b'U', b'Y', b'V', b'Y'), + D3DFMT_R8G8_B8G8 = MAKEFOURCC!(b'R', b'G', b'B', b'G'), + D3DFMT_YUY2 = MAKEFOURCC!(b'Y', b'U', b'Y', b'2'), + D3DFMT_G8R8_G8B8 = MAKEFOURCC!(b'G', b'R', b'G', b'B'), + D3DFMT_DXT1 = MAKEFOURCC!(b'D', b'X', b'T', b'1'), + D3DFMT_DXT2 = MAKEFOURCC!(b'D', b'X', b'T', b'2'), + D3DFMT_DXT3 = MAKEFOURCC!(b'D', b'X', b'T', b'3'), + D3DFMT_DXT4 = MAKEFOURCC!(b'D', b'X', b'T', b'4'), + D3DFMT_DXT5 = MAKEFOURCC!(b'D', b'X', b'T', b'5'), + D3DFMT_D16_LOCKABLE = 70, + D3DFMT_D32 = 71, + D3DFMT_D15S1 = 73, + D3DFMT_D24S8 = 75, + D3DFMT_D24X8 = 77, + D3DFMT_D24X4S4 = 79, + D3DFMT_D16 = 80, + D3DFMT_D32F_LOCKABLE = 82, + D3DFMT_D24FS8 = 83, + D3DFMT_D32_LOCKABLE = 84, + D3DFMT_S8_LOCKABLE = 85, + D3DFMT_L16 = 81, + D3DFMT_VERTEXDATA = 100, + D3DFMT_INDEX16 = 101, + D3DFMT_INDEX32 = 102, + D3DFMT_Q16W16V16U16 = 110, + D3DFMT_MULTI2_ARGB8 = MAKEFOURCC!(b'M', b'E', b'T', b'1'), + D3DFMT_R16F = 111, + D3DFMT_G16R16F = 112, + D3DFMT_A16B16G16R16F = 113, + D3DFMT_R32F = 114, + D3DFMT_G32R32F = 115, + D3DFMT_A32B32G32R32F = 116, + D3DFMT_CxV8U8 = 117, + D3DFMT_A1 = 118, + D3DFMT_A2B10G10R10_XR_BIAS = 119, + D3DFMT_BINARYBUFFER = 199, +}} +STRUCT!{struct D3DDISPLAYMODE { + Width: UINT, + Height: UINT, + RefreshRate: UINT, + Format: D3DFORMAT, +}} +STRUCT!{struct D3DDEVICE_CREATION_PARAMETERS { + AdapterOrdinal: UINT, + DeviceType: D3DDEVTYPE, + hFocusWindow: HWND, + BehaviorFlags: DWORD, +}} +ENUM!{enum D3DSWAPEFFECT { + D3DSWAPEFFECT_DISCARD = 1, + D3DSWAPEFFECT_FLIP = 2, + D3DSWAPEFFECT_COPY = 3, + D3DSWAPEFFECT_OVERLAY = 4, + D3DSWAPEFFECT_FLIPEX = 5, +}} +ENUM!{enum D3DPOOL { + D3DPOOL_DEFAULT = 0, + D3DPOOL_MANAGED = 1, + D3DPOOL_SYSTEMMEM = 2, + D3DPOOL_SCRATCH = 3, +}} +pub const D3DPRESENT_RATE_DEFAULT: DWORD = 0x00000000; +STRUCT!{struct D3DPRESENT_PARAMETERS { + BackBufferWidth: UINT, + BackBufferHeight: UINT, + BackBufferFormat: D3DFORMAT, + BackBufferCount: UINT, + MultiSampleType: D3DMULTISAMPLE_TYPE, + MultiSampleQuality: DWORD, + SwapEffect: D3DSWAPEFFECT, + hDeviceWindow: HWND, + Windowed: BOOL, + EnableAutoDepthStencil: BOOL, + AutoDepthStencilFormat: D3DFORMAT, + Flags: DWORD, + FullScreen_RefreshRateInHz: UINT, + PresentationInterval: UINT, +}} +pub const D3DPRESENTFLAG_LOCKABLE_BACKBUFFER: DWORD = 0x00000001; +pub const D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL: DWORD = 0x00000002; +pub const D3DPRESENTFLAG_DEVICECLIP: DWORD = 0x00000004; +pub const D3DPRESENTFLAG_VIDEO: DWORD = 0x00000010; +pub const D3DPRESENTFLAG_NOAUTOROTATE: DWORD = 0x00000020; +pub const D3DPRESENTFLAG_UNPRUNEDMODE: DWORD = 0x00000040; +pub const D3DPRESENTFLAG_OVERLAY_LIMITEDRGB: DWORD = 0x00000080; +pub const D3DPRESENTFLAG_OVERLAY_YCbCr_BT709: DWORD = 0x00000100; +pub const D3DPRESENTFLAG_OVERLAY_YCbCr_xvYCC: DWORD = 0x00000200; +pub const D3DPRESENTFLAG_RESTRICTED_CONTENT: DWORD = 0x00000400; +pub const D3DPRESENTFLAG_RESTRICT_SHARED_RESOURCE_DRIVER: DWORD = 0x00000800; +STRUCT!{struct D3DGAMMARAMP { + red: [WORD; 256], + green: [WORD; 256], + blue: [WORD; 256], +}} +ENUM!{enum D3DBACKBUFFER_TYPE { + D3DBACKBUFFER_TYPE_MONO = 0, + D3DBACKBUFFER_TYPE_LEFT = 1, + D3DBACKBUFFER_TYPE_RIGHT = 2, +}} +ENUM!{enum D3DRESOURCETYPE { + D3DRTYPE_SURFACE = 1, + D3DRTYPE_VOLUME = 2, + D3DRTYPE_TEXTURE = 3, + D3DRTYPE_VOLUMETEXTURE = 4, + D3DRTYPE_CUBETEXTURE = 5, + D3DRTYPE_VERTEXBUFFER = 6, + D3DRTYPE_INDEXBUFFER = 7, +}} +pub const D3DUSAGE_RENDERTARGET: DWORD = 0x00000001; +pub const D3DUSAGE_DEPTHSTENCIL: DWORD = 0x00000002; +pub const D3DUSAGE_DYNAMIC: DWORD = 0x00000200; +pub const D3DUSAGE_NONSECURE: DWORD = 0x00800000; +pub const D3DUSAGE_AUTOGENMIPMAP: DWORD = 0x00000400; +pub const D3DUSAGE_DMAP: DWORD = 0x00004000; +pub const D3DUSAGE_QUERY_LEGACYBUMPMAP: DWORD = 0x00008000; +pub const D3DUSAGE_QUERY_SRGBREAD: DWORD = 0x00010000; +pub const D3DUSAGE_QUERY_FILTER: DWORD = 0x00020000; +pub const D3DUSAGE_QUERY_SRGBWRITE: DWORD = 0x00040000; +pub const D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING: DWORD = 0x00080000; +pub const D3DUSAGE_QUERY_VERTEXTEXTURE: DWORD = 0x00100000; +pub const D3DUSAGE_QUERY_WRAPANDMIP: DWORD = 0x00200000; +pub const D3DUSAGE_WRITEONLY: DWORD = 0x00000008; +pub const D3DUSAGE_SOFTWAREPROCESSING: DWORD = 0x00000010; +pub const D3DUSAGE_DONOTCLIP: DWORD = 0x00000020; +pub const D3DUSAGE_POINTS: DWORD = 0x00000040; +pub const D3DUSAGE_RTPATCHES: DWORD = 0x00000080; +pub const D3DUSAGE_NPATCHES: DWORD = 0x00000100; +pub const D3DUSAGE_TEXTAPI: DWORD = 0x10000000; +pub const D3DUSAGE_RESTRICTED_CONTENT: DWORD = 0x00000800; +pub const D3DUSAGE_RESTRICT_SHARED_RESOURCE: DWORD = 0x00002000; +pub const D3DUSAGE_RESTRICT_SHARED_RESOURCE_DRIVER: DWORD = 0x00001000; +ENUM!{enum D3DCUBEMAP_FACES { + D3DCUBEMAP_FACE_POSITIVE_X = 0, + D3DCUBEMAP_FACE_NEGATIVE_X = 1, + D3DCUBEMAP_FACE_POSITIVE_Y = 2, + D3DCUBEMAP_FACE_NEGATIVE_Y = 3, + D3DCUBEMAP_FACE_POSITIVE_Z = 4, + D3DCUBEMAP_FACE_NEGATIVE_Z = 5, +}} +pub const D3DLOCK_READONLY: DWORD = 0x00000010; +pub const D3DLOCK_DISCARD: DWORD = 0x00002000; +pub const D3DLOCK_NOOVERWRITE: DWORD = 0x00001000; +pub const D3DLOCK_NOSYSLOCK: DWORD = 0x00000800; +pub const D3DLOCK_DONOTWAIT: DWORD = 0x00004000; +pub const D3DLOCK_NO_DIRTY_UPDATE: DWORD = 0x00008000; +STRUCT!{struct D3DVERTEXBUFFER_DESC { + Format: D3DFORMAT, + Type: D3DRESOURCETYPE, + Usage: DWORD, + Pool: D3DPOOL, + Size: UINT, + FVF: DWORD, +}} +STRUCT!{struct D3DINDEXBUFFER_DESC { + Format: D3DFORMAT, + Type: D3DRESOURCETYPE, + Usage: DWORD, + Pool: D3DPOOL, + Size: UINT, +}} +STRUCT!{struct D3DSURFACE_DESC { + Format: D3DFORMAT, + Type: D3DRESOURCETYPE, + Usage: DWORD, + Pool: D3DPOOL, + MultiSampleType: D3DMULTISAMPLE_TYPE, + MultiSampleQuality: DWORD, + Width: UINT, + Height: UINT, +}} +STRUCT!{struct D3DVOLUME_DESC { + Format: D3DFORMAT, + Type: D3DRESOURCETYPE, + Usage: DWORD, + Pool: D3DPOOL, + Width: UINT, + Height: UINT, + Depth: UINT, +}} +STRUCT!{struct D3DLOCKED_RECT { + Pitch: INT, + pBits: *mut c_void, +}} +STRUCT!{struct D3DBOX { + Left: UINT, + Top: UINT, + Right: UINT, + Bottom: UINT, + Front: UINT, + Back: UINT, +}} +STRUCT!{struct D3DLOCKED_BOX { + RowPitch: INT, + SlicePitch: INT, + pBits: *mut c_void, +}} +STRUCT!{struct D3DRANGE { + Offset: UINT, + Size: UINT, +}} +STRUCT!{struct D3DRECTPATCH_INFO { + StartVertexOffsetWidth: UINT, + StartVertexOffsetHeight: UINT, + Width: UINT, + Height: UINT, + Stride: UINT, + Basis: D3DBASISTYPE, + Degree: D3DDEGREETYPE, +}} +STRUCT!{struct D3DTRIPATCH_INFO { + StartVertexOffset: UINT, + NumVertices: UINT, + Basis: D3DBASISTYPE, + Degree: D3DDEGREETYPE, +}} +pub const MAX_DEVICE_IDENTIFIER_STRING: usize = 512; +// FIXME packed(4) +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DADAPTER_IDENTIFIER9 { + Driver: [c_char; MAX_DEVICE_IDENTIFIER_STRING], + Description: [c_char; MAX_DEVICE_IDENTIFIER_STRING], + DeviceName: [c_char; 32], + DriverVersion: LARGE_INTEGER, + VendorId: DWORD, + DeviceId: DWORD, + SubSysId: DWORD, + Revision: DWORD, + DeviceIdentifier: GUID, + WHQLLevel: DWORD, +}} +STRUCT!{struct D3DRASTER_STATUS { + InVBlank: BOOL, + ScanLine: UINT, +}} +ENUM!{enum D3DDEBUGMONITORTOKENS { + D3DDMT_ENABLE = 0, + D3DDMT_DISABLE = 1, +}} +ENUM!{enum D3DQUERYTYPE { + D3DQUERYTYPE_VCACHE = 4, + D3DQUERYTYPE_RESOURCEMANAGER = 5, + D3DQUERYTYPE_VERTEXSTATS = 6, + D3DQUERYTYPE_EVENT = 8, + D3DQUERYTYPE_OCCLUSION = 9, + D3DQUERYTYPE_TIMESTAMP = 10, + D3DQUERYTYPE_TIMESTAMPDISJOINT = 11, + D3DQUERYTYPE_TIMESTAMPFREQ = 12, + D3DQUERYTYPE_PIPELINETIMINGS = 13, + D3DQUERYTYPE_INTERFACETIMINGS = 14, + D3DQUERYTYPE_VERTEXTIMINGS = 15, + D3DQUERYTYPE_PIXELTIMINGS = 16, + D3DQUERYTYPE_BANDWIDTHTIMINGS = 17, + D3DQUERYTYPE_CACHEUTILIZATION = 18, + D3DQUERYTYPE_MEMORYPRESSURE = 19, +}} +pub const D3DISSUE_END: DWORD = 1 << 0; +pub const D3DISSUE_BEGIN: DWORD = 1 << 1; +pub const D3DGETDATA_FLUSH: DWORD = 1 << 0; +STRUCT!{struct D3DRESOURCESTATS { + bThrashing: BOOL, + ApproxBytesDownloaded: DWORD, + NumEvicts: DWORD, + NumVidCreates: DWORD, + LastPri: DWORD, + NumUsed: DWORD, + NumUsedInVidMem: DWORD, + WorkingSet: DWORD, + WorkingSetBytes: DWORD, + TotalManaged: DWORD, + TotalBytes: DWORD, +}} +pub const D3DRTYPECOUNT: usize = D3DRTYPE_INDEXBUFFER as usize + 1; +STRUCT!{struct D3DDEVINFO_RESOURCEMANAGER { + stats: [D3DRESOURCESTATS; D3DRTYPECOUNT], +}} +pub type LPD3DDEVINFO_RESOURCEMANAGER = *mut D3DDEVINFO_RESOURCEMANAGER; +STRUCT!{struct D3DDEVINFO_D3DVERTEXSTATS { + NumRenderedTriangles: DWORD, + NumExtraClippingTriangles: DWORD, +}} +pub type LPD3DDEVINFO_D3DVERTEXSTATS = *mut D3DDEVINFO_D3DVERTEXSTATS; +STRUCT!{struct D3DDEVINFO_VCACHE { + Pattern: DWORD, + OptMethod: DWORD, + CacheSize: DWORD, + MagicNumber: DWORD, +}} +pub type LPD3DDEVINFO_VCACHE = *mut D3DDEVINFO_VCACHE; +STRUCT!{struct D3DDEVINFO_D3D9PIPELINETIMINGS { + VertexProcessingTimePercent: FLOAT, + PixelProcessingTimePercent: FLOAT, + OtherGPUProcessingTimePercent: FLOAT, + GPUIdleTimePercent: FLOAT, +}} +STRUCT!{struct D3DDEVINFO_D3D9INTERFACETIMINGS { + WaitingForGPUToUseApplicationResourceTimePercent: FLOAT, + WaitingForGPUToAcceptMoreCommandsTimePercent: FLOAT, + WaitingForGPUToStayWithinLatencyTimePercent: FLOAT, + WaitingForGPUExclusiveResourceTimePercent: FLOAT, + WaitingForGPUOtherTimePercent: FLOAT, +}} +STRUCT!{struct D3DDEVINFO_D3D9STAGETIMINGS { + MemoryProcessingPercent: FLOAT, + ComputationProcessingPercent: FLOAT, +}} +STRUCT!{struct D3DDEVINFO_D3D9BANDWIDTHTIMINGS { + MaxBandwidthUtilized: FLOAT, + FrontEndUploadMemoryUtilizedPercent: FLOAT, + VertexRateUtilizedPercent: FLOAT, + TriangleSetupRateUtilizedPercent: FLOAT, + FillRateUtilizedPercent: FLOAT, +}} +STRUCT!{struct D3DDEVINFO_D3D9CACHEUTILIZATION { + TextureCacheHitRate: FLOAT, + PostTransformVertexCacheHitRate: FLOAT, +}} +// FIXME packed(4) +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DMEMORYPRESSURE { + BytesEvictedFromProcess: UINT64, + SizeOfInefficientAllocation: UINT64, + LevelOfEfficiency: DWORD, +}} +ENUM!{enum D3DCOMPOSERECTSOP { + D3DCOMPOSERECTS_COPY = 1, + D3DCOMPOSERECTS_OR = 2, + D3DCOMPOSERECTS_AND = 3, + D3DCOMPOSERECTS_NEG = 4, +}} +STRUCT!{struct D3DCOMPOSERECTDESC { + X: USHORT, + Y: USHORT, + Width: USHORT, + Height: USHORT, +}} +STRUCT!{struct D3DCOMPOSERECTDESTINATION { + SrcRectIndex: USHORT, + Reserved: USHORT, + X: SHORT, + Y: SHORT, +}} +pub const D3DCOMPOSERECTS_MAXNUMRECTS: DWORD = 0xFFFF; +pub const D3DCONVOLUTIONMONO_MAXWIDTH: DWORD = 7; +pub const D3DCONVOLUTIONMONO_MAXHEIGHT: DWORD = D3DCONVOLUTIONMONO_MAXWIDTH; +pub const D3DFMT_A1_SURFACE_MAXWIDTH: DWORD = 8192; +pub const D3DFMT_A1_SURFACE_MAXHEIGHT: DWORD = 2048; +// FIXME packed(4) +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DPRESENTSTATS { + PresentCount: UINT, + PresentRefreshCount: UINT, + SyncRefreshCount: UINT, + SyncQPCTime: LARGE_INTEGER, + SyncGPUTime: LARGE_INTEGER, +}} +ENUM!{enum D3DSCANLINEORDERING { + D3DSCANLINEORDERING_UNKNOWN = 0, + D3DSCANLINEORDERING_PROGRESSIVE = 1, + D3DSCANLINEORDERING_INTERLACED = 2, +}} +STRUCT!{struct D3DDISPLAYMODEEX { + Size: UINT, + Width: UINT, + Height: UINT, + RefreshRate: UINT, + Format: D3DFORMAT, + ScanLineOrdering: D3DSCANLINEORDERING, +}} +STRUCT!{struct D3DDISPLAYMODEFILTER { + Size: UINT, + Format: D3DFORMAT, + ScanLineOrdering: D3DSCANLINEORDERING, +}} +ENUM!{enum D3DDISPLAYROTATION { + D3DDISPLAYROTATION_IDENTITY = 1, + D3DDISPLAYROTATION_90 = 2, + D3DDISPLAYROTATION_180 = 3, + D3DDISPLAYROTATION_270 = 4, +}} +pub const D3D9_RESOURCE_PRIORITY_MINIMUM: DWORD = 0x28000000; +pub const D3D9_RESOURCE_PRIORITY_LOW: DWORD = 0x50000000; +pub const D3D9_RESOURCE_PRIORITY_NORMAL: DWORD = 0x78000000; +pub const D3D9_RESOURCE_PRIORITY_HIGH: DWORD = 0xa0000000; +pub const D3D9_RESOURCE_PRIORITY_MAXIMUM: DWORD = 0xc8000000; +pub const D3D_OMAC_SIZE: usize = 16; +STRUCT!{struct D3D_OMAC { + Omac: [BYTE; D3D_OMAC_SIZE], +}} +ENUM!{enum D3DAUTHENTICATEDCHANNELTYPE { + D3DAUTHENTICATEDCHANNEL_D3D9 = 1, + D3DAUTHENTICATEDCHANNEL_DRIVER_SOFTWARE = 2, + D3DAUTHENTICATEDCHANNEL_DRIVER_HARDWARE = 3, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERY_INPUT { + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT { + omac: D3D_OMAC, + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, + ReturnCode: HRESULT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_PROTECTION, + 0xa84eb584, 0xc495, 0x48aa, 0xb9, 0x4d, 0x8b, 0xd2, 0xd6, 0xfb, 0xce, 0x5} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS { + Value: UINT, +}} +BITFIELD!{D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS Value: UINT [ + ProtectionEnabled set_ProtectionEnabled[0..1], + OverlayOrFullscreenRequired set_OverlayOrFullscreenRequired[1..2], +]} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYPROTECTION_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + ProtectionFlags: D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_CHANNELTYPE, + 0xbc1b18a5, 0xb1fb, 0x42ab, 0xbd, 0x94, 0xb5, 0x82, 0x8b, 0x4b, 0xf7, 0xbe} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYCHANNELTYPE_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + ChannelType: D3DAUTHENTICATEDCHANNELTYPE, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_DEVICEHANDLE, + 0xec1c539d, 0x8cff, 0x4e2a, 0xbc, 0xc4, 0xf5, 0x69, 0x2f, 0x99, 0xf4, 0x80} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYDEVICEHANDLE_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + DeviceHandle: HANDLE, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_CRYPTOSESSION, + 0x2634499e, 0xd018, 0x4d74, 0xac, 0x17, 0x7f, 0x72, 0x40, 0x59, 0x52, 0x8d} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_INPUT { + Input: D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, + DXVA2DecodeHandle: HANDLE, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYCRYPTOSESSION_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + DXVA2DecodeHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_RESTRICTEDSHAREDRESOURCEPROCESSCOUNT, + 0xdb207b3, 0x9450, 0x46a6, 0x82, 0xde, 0x1b, 0x96, 0xd4, 0x4f, 0x9c, 0xf2} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESSCOUNT_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + NumRestrictedSharedResourceProcesses: UINT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_RESTRICTEDSHAREDRESOURCEPROCESS, + 0x649bbadb, 0xf0f4, 0x4639, 0xa1, 0x5b, 0x24, 0x39, 0x3f, 0xc3, 0xab, 0xac} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_INPUT { + Input: D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, + ProcessIndex: UINT, +}} +ENUM!{enum D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE { + PROCESSIDTYPE_UNKNOWN = 0, + PROCESSIDTYPE_DWM = 1, + PROCESSIDTYPE_HANDLE = 2, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYRESTRICTEDSHAREDRESOURCEPROCESS_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + ProcessIndex: UINT, + ProcessIdentifer: D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE, + ProcessHandle: HANDLE, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_UNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT, + 0x12f0bd6, 0xe662, 0x4474, 0xbe, 0xfd, 0xaa, 0x53, 0xe5, 0x14, 0x3c, 0x6d} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYUNRESTRICTEDPROTECTEDSHAREDRESOURCECOUNT_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + NumUnrestrictedProtectedSharedResources: UINT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_OUTPUTIDCOUNT, + 0x2c042b5e, 0x8c07, 0x46d5, 0xaa, 0xbe, 0x8f, 0x75, 0xcb, 0xad, 0x4c, 0x31} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_INPUT { + Input: D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTIDCOUNT_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + NumOutputIDs: UINT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_OUTPUTID, + 0x839ddca3, 0x9b4e, 0x41e4, 0xb0, 0x53, 0x89, 0x2b, 0xd2, 0xa1, 0x1e, 0xe7} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_INPUT { + Input: D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: UINT, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYOUTPUTID_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: UINT, + OutputID: UINT64, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_ACCESSIBILITYATTRIBUTES, + 0x6214d9d2, 0x432c, 0x4abb, 0x9f, 0xce, 0x21, 0x6e, 0xea, 0x26, 0x9e, 0x3b} +ENUM!{enum D3DBUSTYPE { + D3DBUSTYPE_OTHER = 0x00000000, + D3DBUSTYPE_PCI = 0x00000001, + D3DBUSTYPE_PCIX = 0x00000002, + D3DBUSTYPE_PCIEXPRESS = 0x00000003, + D3DBUSTYPE_AGP = 0x00000004, + D3DBUSIMPL_MODIFIER_INSIDE_OF_CHIPSET = 0x00010000, + MD3DBUSIMPL_ODIFIER_TRACKS_ON_MOTHER_BOARD_TO_CHIP = 0x00020000, + D3DBUSIMPL_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_SOCKET = 0x00030000, + D3DBUSIMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR = 0x00040000, + D3DBUSIMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR_INSIDE_OF_NUAE = 0x00050000, + D3DBUSIMPL_MODIFIER_NON_STANDARD = 0x80000000, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYINFOBUSTYPE_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + BusType: D3DBUSTYPE, + bAccessibleInContiguousBlocks: BOOL, + bAccessibleInNonContiguousBlocks: BOOL, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_ENCRYPTIONWHENACCESSIBLEGUIDCOUNT, + 0xb30f7066, 0x203c, 0x4b07, 0x93, 0xfc, 0xce, 0xaa, 0xfd, 0x61, 0x24, 0x1e} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUIDCOUNT_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + NumEncryptionGuids: UINT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_ENCRYPTIONWHENACCESSIBLEGUID, + 0xf83a5958, 0xe986, 0x4bda, 0xbe, 0xb0, 0x41, 0x1f, 0x6a, 0x7a, 0x1, 0xb7} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_INPUT { + Input: D3DAUTHENTICATEDCHANNEL_QUERY_INPUT, + EncryptionGuidIndex: UINT, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYEVICTIONENCRYPTIONGUID_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + EncryptionGuidIndex: UINT, + EncryptionGuid: GUID, +}} +DEFINE_GUID!{D3DAUTHENTICATEDQUERY_CURRENTENCRYPTIONWHENACCESSIBLE, + 0xec1791c7, 0xdad3, 0x4f15, 0x9e, 0xc3, 0xfa, 0xa9, 0x3d, 0x60, 0xd4, 0xf0} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_QUERYUNCOMPRESSEDENCRYPTIONLEVEL_OUTPUT { + Output: D3DAUTHENTICATEDCHANNEL_QUERY_OUTPUT, + EncryptionGuid: GUID, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT { + omac: D3D_OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, +}} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGURE_OUTPUT { + omac: D3D_OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, + ReturnCode: HRESULT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDCONFIGURE_INITIALIZE, + 0x6114bdb, 0x3523, 0x470a, 0x8d, 0xca, 0xfb, 0xc2, 0x84, 0x51, 0x54, 0xf0} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGUREINITIALIZE { + Parameters: D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, + StartSequenceQuery: UINT, + StartSequenceConfigure: UINT, +}} +DEFINE_GUID!{D3DAUTHENTICATEDCONFIGURE_PROTECTION, + 0x50455658, 0x3f47, 0x4362, 0xbf, 0x99, 0xbf, 0xdf, 0xcd, 0xe9, 0xed, 0x29} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGUREPROTECTION { + Parameters: D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, + Protections: D3DAUTHENTICATEDCHANNEL_PROTECTION_FLAGS, +}} +DEFINE_GUID!{D3DAUTHENTICATEDCONFIGURE_CRYPTOSESSION, + 0x6346cc54, 0x2cfc, 0x4ad4, 0x82, 0x24, 0xd1, 0x58, 0x37, 0xde, 0x77, 0x0} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGURECRYPTOSESSION { + Parameters: D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, + DXVA2DecodeHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +}} +DEFINE_GUID!{D3DAUTHENTICATEDCONFIGURE_SHAREDRESOURCE, + 0x772d047, 0x1b40, 0x48e8, 0x9c, 0xa6, 0xb5, 0xf5, 0x10, 0xde, 0x9f, 0x1} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGURESHAREDRESOURCE { + Parameters: D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, + ProcessIdentiferType: D3DAUTHENTICATEDCHANNEL_PROCESSIDENTIFIERTYPE, + ProcessHandle: HANDLE, + AllowAccess: BOOL, +}} +DEFINE_GUID!{D3DAUTHENTICATEDCONFIGURE_ENCRYPTIONWHENACCESSIBLE, + 0x41fff286, 0x6ae0, 0x4d43, 0x9d, 0x55, 0xa4, 0x6e, 0x9e, 0xfd, 0x15, 0x8a} +STRUCT!{struct D3DAUTHENTICATEDCHANNEL_CONFIGUREUNCOMPRESSEDENCRYPTION { + Parameters: D3DAUTHENTICATEDCHANNEL_CONFIGURE_INPUT, + EncryptionGuid: GUID, +}} +STRUCT!{struct D3DENCRYPTED_BLOCK_INFO { + NumEncryptedBytesAtBeginning: UINT, + NumBytesInSkipPattern: UINT, + NumBytesInEncryptPattern: UINT, +}} +STRUCT!{struct D3DAES_CTR_IV { + IV: UINT64, + Count: UINT64, +}} diff --git a/winapi/src/shared/d3dkmdt.rs b/winapi/src/shared/d3dkmdt.rs new file mode 100644 index 000000000..89d574f12 --- /dev/null +++ b/winapi/src/shared/d3dkmdt.rs @@ -0,0 +1,45 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Longhorn Display Driver Model (LDDM) kernel mode data type definitions +use shared::basetsd::UINT32; +use shared::minwindef::UINT; +use shared::ntdef::{BOOLEAN, WCHAR}; +//1932 +pub const DXGK_MAX_METADATA_NAME_LENGTH: usize = 32; +ENUM!{enum DXGK_ENGINE_TYPE { + DXGK_ENGINE_TYPE_OTHER, + DXGK_ENGINE_TYPE_3D, + DXGK_ENGINE_TYPE_VIDEO_DECODE, + DXGK_ENGINE_TYPE_VIDEO_ENCODE, + DXGK_ENGINE_TYPE_VIDEO_PROCESSING, + DXGK_ENGINE_TYPE_SCENE_ASSEMBLY, + DXGK_ENGINE_TYPE_COPY, + DXGK_ENGINE_TYPE_OVERLAY, + DXGK_ENGINE_TYPE_CRYPTO, + DXGK_ENGINE_TYPE_MAX, +}} +STRUCT!{#[repr(packed)] struct DXGK_NODEMETADATA_FLAGS { + Value: UINT32, +}} +BITFIELD!{DXGK_NODEMETADATA_FLAGS Value: UINT32 [ + ContextSchedulingSupported set_ContextSchedulingSupported[0..1], + RingBufferFenceRelease set_RingBufferFenceRelease[1..2], + SupportTrackedWorkload set_SupportTrackedWorkload[2..3], + Reserved set_Reserved[3..16], + MaxInFlightHwQueueBuffers set_MaxInFlightHwQueueBuffers[16..32], +]} +STRUCT!{#[repr(packed)] struct DXGK_NODEMETADATA { + EngineType: DXGK_ENGINE_TYPE, + FriendlyName: [WCHAR; DXGK_MAX_METADATA_NAME_LENGTH], + Flags: DXGK_NODEMETADATA_FLAGS, + GpuMmuSupported: BOOLEAN, + IoMmuSupported: BOOLEAN, +}} +//2100 +STRUCT!{#[repr(packed)] struct D3DKMT_NODEMETADATA { + NodeOrdinalAndAdapterIndex: UINT, + NodeData: DXGK_NODEMETADATA, +}} diff --git a/winapi/src/shared/d3dukmdt.rs b/winapi/src/shared/d3dukmdt.rs new file mode 100644 index 000000000..16a34d1a1 --- /dev/null +++ b/winapi/src/shared/d3dukmdt.rs @@ -0,0 +1,416 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Longhorn Display Driver Model (LDDM) user/kernel mode shared data type definitions. +use shared::basetsd::{UINT64, ULONG_PTR}; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, UINT, ULONG}; +use shared::ntdef::{HANDLE, LUID, ULONGLONG, VOID}; +pub const DXGKDDI_INTERFACE_VERSION_VISTA: ULONG = 0x1052; +pub const DXGKDDI_INTERFACE_VERSION_VISTA_SP1: ULONG = 0x1053; +pub const DXGKDDI_INTERFACE_VERSION_WIN7: ULONG = 0x2005; +pub const DXGKDDI_INTERFACE_VERSION_WIN8: ULONG = 0x300E; +pub const DXGKDDI_INTERFACE_VERSION_WDDM1_3: ULONG = 0x4002; +pub const DXGKDDI_INTERFACE_VERSION_WDDM1_3_PATH_INDEPENDENT_ROTATION: ULONG = 0x4003; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_0: ULONG = 0x5023; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_1: ULONG = 0x6003; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_1_5: ULONG = 0x6010; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_2: ULONG = 0x700A; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_3: ULONG = 0x8001; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_4: ULONG = 0x9006; +pub const DXGKDDI_INTERFACE_VERSION_WDDM2_5: ULONG = 0xA00B; +#[inline] +pub fn IS_OFFICIAL_DDI_INTERFACE_VERSION(version: ULONG) -> bool { + (version == DXGKDDI_INTERFACE_VERSION_VISTA) || + (version == DXGKDDI_INTERFACE_VERSION_VISTA_SP1) || + (version == DXGKDDI_INTERFACE_VERSION_WIN7) || + (version == DXGKDDI_INTERFACE_VERSION_WIN8) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM1_3) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM1_3_PATH_INDEPENDENT_ROTATION) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_0) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_1) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_1_5) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_2) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_3) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_4) || + (version == DXGKDDI_INTERFACE_VERSION_WDDM2_5) +} +pub const DXGKDDI_INTERFACE_VERSION: ULONG = DXGKDDI_INTERFACE_VERSION_WDDM2_5; +pub const D3D_UMD_INTERFACE_VERSION_VISTA: ULONG = 0x000C; +pub const D3D_UMD_INTERFACE_VERSION_WIN7: ULONG = 0x2003; +pub const D3D_UMD_INTERFACE_VERSION_WIN8_M3: ULONG = 0x3001; +pub const D3D_UMD_INTERFACE_VERSION_WIN8_CP: ULONG = 0x3002; +pub const D3D_UMD_INTERFACE_VERSION_WIN8_RC: ULONG = 0x3003; +pub const D3D_UMD_INTERFACE_VERSION_WIN8: ULONG = 0x3004; +pub const D3D_UMD_INTERFACE_VERSION_WDDM1_3: ULONG = 0x4002; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_0_M1: ULONG = 0x5000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_0_M1_3: ULONG = 0x5001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_0_M2_2: ULONG = 0x5002; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_0: ULONG = 0x5002; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_1_1: ULONG = 0x6000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_1_2: ULONG = 0x6001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_1_3: ULONG = 0x6002; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_1_4: ULONG = 0x6003; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_1: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_1_4; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_2_1: ULONG = 0x7000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_2_2: ULONG = 0x7001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_2: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_2_2; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_3_1: ULONG = 0x8000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_3_2: ULONG = 0x8001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_3: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_3_2; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_4_1: ULONG = 0x9000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_4_2: ULONG = 0x9001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_4: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_4_2; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_5_1: ULONG = 0xA000; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_5_2: ULONG = 0xA001; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_5_3: ULONG = 0xA002; +pub const D3D_UMD_INTERFACE_VERSION_WDDM2_5: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_5_3; +pub const D3D_UMD_INTERFACE_VERSION: ULONG = D3D_UMD_INTERFACE_VERSION_WDDM2_5; +pub type D3DGPU_VIRTUAL_ADDRESS = ULONGLONG; +pub type D3DGPU_SIZE_T = ULONGLONG; +pub const D3DGPU_UNIQUE_DRIVER_PROTECTION: ULONGLONG = 0x8000000000000000; +pub const DXGK_MAX_PAGE_TABLE_LEVEL_COUNT: UINT = 6; +pub const DXGK_MIN_PAGE_TABLE_LEVEL_COUNT: UINT = 2; +STRUCT!{struct GPUP_DRIVER_ESCAPE_INPUT { + vfLUID: LUID, +}} +pub type PGPUP_DRIVER_ESCAPE_INPUT = *mut GPUP_DRIVER_ESCAPE_INPUT; +ENUM!{enum DXGKVGPU_ESCAPE_TYPE { + DXGKVGPU_ESCAPE_TYPE_READ_PCI_CONFIG = 0, + DXGKVGPU_ESCAPE_TYPE_WRITE_PCI_CONFIG = 1, + DXGKVGPU_ESCAPE_TYPE_INITIALIZE = 2, + DXGKVGPU_ESCAPE_TYPE_RELEASE = 3, + DXGKVGPU_ESCAPE_TYPE_GET_VGPU_TYPE = 4, + DXGKVGPU_ESCAPE_TYPE_POWERTRANSITIONCOMPLETE = 5, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_HEAD { + Luid: GPUP_DRIVER_ESCAPE_INPUT, + Type: DXGKVGPU_ESCAPE_TYPE, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_READ_PCI_CONFIG { + Header: DXGKVGPU_ESCAPE_HEAD, + Offset: UINT, + Size: UINT, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_WRITE_PCI_CONFIG { + Header: DXGKVGPU_ESCAPE_HEAD, + Offset: UINT, + Size: UINT, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_READ_VGPU_TYPE { + Header: DXGKVGPU_ESCAPE_HEAD, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_POWERTRANSITIONCOMPLETE { + Header: DXGKVGPU_ESCAPE_HEAD, + PowerState: UINT, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_INITIALIZE { + Header: DXGKVGPU_ESCAPE_HEAD, + VmGuid: GUID, +}} +STRUCT!{struct DXGKVGPU_ESCAPE_RELEASE { + Header: DXGKVGPU_ESCAPE_HEAD, +}} +ENUM!{enum DXGK_PTE_PAGE_SIZE { + DXGK_PTE_PAGE_TABLE_PAGE_4KB = 0, + DXGK_PTE_PAGE_TABLE_PAGE_64KB = 1, +}} +UNION!{union DXGK_PTE_u { + [u64; 1], + PageAddress PageAddress_mut: ULONGLONG, + PageTableAddress PageTableAddress_mut: ULONGLONG, +}} +STRUCT!{struct DXGK_PTE { + Flags: ULONGLONG, + u: DXGK_PTE_u, +}} +BITFIELD!{DXGK_PTE Flags: ULONGLONG [ + Valid set_Valid[0..1], + Zero set_Zero[1..2], + CacheCoherent set_CacheCoherent[2..3], + ReadOnly set_ReadOnly[3..4], + NoExecute set_NoExecute[4..5], + Segment set_Segment[5..10], + LargePage set_LargePage[10..11], + PhysicalAdapterIndex set_PhysicalAdapterIndex[11..17], + PageTablePageSize set_PageTablePageSize[17..19], + SystemReserved0 set_SystemReserved0[19..20], + Reserved set_Reserved[20..64], +]} +pub const D3DGPU_NULL: D3DGPU_VIRTUAL_ADDRESS = 0; +pub const D3DDDI_MAX_WRITTEN_PRIMARIES: usize = 16; +pub const D3DDDI_MAX_MPO_PRESENT_DIRTY_RECTS: usize = 0xFFF; +STRUCT!{struct D3DGPU_PHYSICAL_ADDRESS { + SegmentId: UINT, + SegmentOffset: UINT64, +}} +pub type D3DDDI_VIDEO_PRESENT_SOURCE_ID = UINT; +pub type D3DDDI_VIDEO_PRESENT_TARGET_ID = UINT; +pub type D3DKMT_HANDLE = UINT; +STRUCT!{struct D3DDDI_RATIONAL { + Numerator: UINT, + Denominator: UINT, +}} +STRUCT!{struct D3DDDI_ALLOCATIONINFO { + hAllocation: D3DKMT_HANDLE, + pSystemMem: *const VOID, + pPrivateDriverData: *mut VOID, + PrivateDriverDataSize: UINT, + VidPnSourceId: D3DDDI_VIDEO_PRESENT_SOURCE_ID, + Flags: UINT, +}} +BITFIELD!{D3DDDI_ALLOCATIONINFO Flags: UINT [ + Primary set_Primary[0..1], + Stereo set_Stereo[1..2], + Reserved set_Reserved[2..32], +]} +UNION!{union D3DDDI_ALLOCATIONINFO2_u1 { + [usize; 1], + hSection hSection_mut: HANDLE, + pSystemMem pSystemMem_mut: *const VOID, +}} +UNION!{union D3DDDI_ALLOCATIONINFO2_u2 { + [usize; 1], + Priority Priority_mut: UINT, + Unused Unused_mut: ULONG_PTR, +}} +STRUCT!{struct D3DDDI_ALLOCATIONINFO2 { + hAllocation: D3DKMT_HANDLE, + u1: D3DDDI_ALLOCATIONINFO2_u1, + pPrivateDriverData: *mut VOID, + PrivateDriverDataSize: UINT, + VidPnSourceId: D3DDDI_VIDEO_PRESENT_SOURCE_ID, + Flags: UINT, + GpuVirtualAddress: D3DGPU_VIRTUAL_ADDRESS, + u2: D3DDDI_ALLOCATIONINFO2_u2, + Reserved: [ULONG_PTR; 5], +}} +BITFIELD!{D3DDDI_ALLOCATIONINFO2 Flags: UINT [ + Primary set_Primary[0..1], + Stereo set_Stereo[1..2], + OverridePriority set_OverridePriority[2..3], + Reserved set_Reserved[3..32], +]} +STRUCT!{struct D3DDDI_OPENALLOCATIONINFO { + hAllocation: D3DKMT_HANDLE, + pPrivateDriverData: *const VOID, + PrivateDriverDataSize: UINT, +}} +STRUCT!{struct D3DDDI_OPENALLOCATIONINFO2 { + hAllocation: D3DKMT_HANDLE, + pPrivateDriverData: *const VOID, + PrivateDriverDataSize: UINT, + GpuVirtualAddress: D3DGPU_VIRTUAL_ADDRESS, + Reserved: [ULONG_PTR; 6], +}} +ENUM!{enum D3DDDI_OFFER_PRIORITY { + D3DDDI_OFFER_PRIORITY_NONE = 0, + D3DDDI_OFFER_PRIORITY_LOW = 1, + D3DDDI_OFFER_PRIORITY_NORMAL, + D3DDDI_OFFER_PRIORITY_HIGH, + D3DDDI_OFFER_PRIORITY_AUTO, +}} +STRUCT!{struct D3DDDI_ALLOCATIONLIST { + hAllocation: D3DKMT_HANDLE, + Value: UINT, +}} +BITFIELD!{D3DDDI_ALLOCATIONLIST Value: UINT [ + WriteOperation set_WriteOperation[0..1], + DoNotRetireInstance set_DoNotRetireInstance[1..2], + OfferPriority set_OfferPriority[2..5], + Reserved set_Reserved[5..32], +]} +STRUCT!{struct D3DDDI_PATCHLOCATIONLIST { + AllocationIndex: UINT, + Value: UINT, + DriverId: UINT, + AllocationOffset: UINT, + PatchOffset: UINT, + SplitOffset: UINT, +}} +BITFIELD!{D3DDDI_PATCHLOCATIONLIST Value: UINT [ + SlotId set_SlotId[0..24], + Reserved set_Reserved[24..32], +]} +STRUCT!{struct D3DDDICB_LOCKFLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDICB_LOCKFLAGS Value: UINT [ + ReadOnly set_ReadOnly[0..1], + WriteOnly set_WriteOnly[1..2], + DonotWait set_DonotWait[2..3], + IgnoreSync set_IgnoreSync[3..4], + LockEntire set_LockEntire[4..5], + DonotEvict set_DonotEvict[5..6], + AcquireAperture set_AcquireAperture[6..7], + Discard set_Discard[7..8], + NoExistingReference set_NoExistingReference[8..9], + UseAlternateVA set_UseAlternateVA[9..10], + IgnoreReadSync set_IgnoreReadSync[10..11], + Reserved set_Reserved[11..32], +]} +STRUCT!{struct D3DDDICB_LOCK2FLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDICB_LOCK2FLAGS Value: UINT [ + Reserved set_Reserved[0..32], +]} +STRUCT!{struct D3DDDICB_DESTROYALLOCATION2FLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDICB_DESTROYALLOCATION2FLAGS Value: UINT [ + AssumeNotInUse set_AssumeNotInUse[0..1], + SynchronousDestroy set_SynchronousDestroy[1..2], + Reserved set_Reserved[2..31], + SystemUseOnly set_SystemUseOnly[31..32], +]} +STRUCT!{struct D3DDDI_ESCAPEFLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDI_ESCAPEFLAGS Value: UINT [ + HardwareAccess set_HardwareAccess[0..1], + DeviceStatusQuery set_DeviceStatusQuery[1..2], + ChangeFrameLatency set_ChangeFrameLatency[2..3], + NoAdapterSynchronization set_NoAdapterSynchronization[3..4], + Reserved set_Reserved[4..5], + VirtualMachineData set_VirtualMachineData[5..6], + DriverKnownEscape set_DriverKnownEscape[6..7], + DriverCommonEscape set_DriverCommonEscape[7..8], + Reserved2 set_Reserved2[8..24], +]} +ENUM!{enum D3DDDI_DRIVERESCAPETYPE { + D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE = 0, + D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE = 1, + D3DDDI_DRIVERESCAPETYPE_MAX, +}} +STRUCT!{struct D3DDDI_DRIVERESCAPE_TRANSLATEALLOCATIONEHANDLE { + EscapeType: D3DDDI_DRIVERESCAPETYPE, + hAllocation: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DDDI_DRIVERESCAPE_TRANSLATERESOURCEHANDLE { + EscapeType: D3DDDI_DRIVERESCAPETYPE, + hResource: D3DKMT_HANDLE, +}} +STRUCT!{struct D3DDDI_CREATECONTEXTFLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDI_CREATECONTEXTFLAGS Value: UINT [ + NullRendering set_NullRendering[0..1], + InitialData set_InitialData[1..2], + DisableGpuTimeout set_DisableGpuTimeout[2..3], + SynchronizationOnly set_SynchronizationOnly[3..4], + HwQueueSupported set_HwQueueSupported[4..5], + Reserved set_Reserved[5..32], +]} +//1188 +STRUCT!{struct D3DDDICB_SIGNALFLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDICB_SIGNALFLAGS Value: UINT [ + SignalAtSubmission set_SignalAtSubmission[0..1], + EnqueueCpuEvent set_EnqueueCpuEvent[1..2], + AllowFenceRewind set_AllowFenceRewind[2..3], + Reserved set_Reserved[3..31], + DXGK_SIGNAL_FLAG_INTERNAL0 set_DXGK_SIGNAL_FLAG_INTERNAL0[31..32], +]} +pub const D3DDDI_MAX_OBJECT_WAITED_ON: usize = 32; +pub const D3DDDI_MAX_OBJECT_SIGNALED: usize = 32; +ENUM!{enum D3DDDI_SYNCHRONIZATIONOBJECT_TYPE { + D3DDDI_SYNCHRONIZATION_MUTEX = 1, + D3DDDI_SEMAPHORE = 2, + D3DDDI_FENCE = 3, + D3DDDI_CPU_NOTIFICATION = 4, + D3DDDI_MONITORED_FENCE = 5, + D3DDDI_PERIODIC_MONITORED_FENCE = 6, + D3DDDI_SYNCHRONIZATION_TYPE_LIMIT, +}} +//1553 +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_SynchronizationMutex { + InitialState: BOOL, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_Semaphore { + MaxCount: UINT, + InitialCount: UINT, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_Reserved { + Reserved: [UINT; 16], +}} +UNION!{union D3DDDI_SYNCHRONIZATIONOBJECTINFO_u { + [u32; 16], + SynchronizationMutex SynchronizationMutex_mut: + D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_SynchronizationMutex, + Semaphore Semaphore_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_Semaphore, + Reserved Reserved_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO_u_Reserved, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO { + Type: D3DDDI_SYNCHRONIZATIONOBJECT_TYPE, + u: D3DDDI_SYNCHRONIZATIONOBJECTINFO_u, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS { + Value: UINT, +}} +BITFIELD!{D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS Value: UINT [ + Shared set_Shared[0..1], + NtSecuritySharing set_NtSecuritySharing[1..2], + CrossAdapter set_CrossAdapter[2..3], + TopOfPipeline set_TopOfPipeline[3..4], + NoSignal set_NoSignal[4..5], + NoWait set_NoWait[5..6], + NoSignalMaxValueOnTdr set_NoSignalMaxValueOnTdr[6..7], + NoGPUAccess set_NoGPUAccess[7..8], + Reserved set_Reserved[8..31], + D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0 + set_D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS_RESERVED0[31..32], +]} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_SynchronizationMutex { + InitialState: BOOL, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Semaphore { + MaxCount: UINT, + InitialCount: UINT, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Fence { + FenceValue: UINT64, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_CPUNotification { + Event: HANDLE, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_MonitoredFence { + InitialFenceValue: UINT64, + FenceValueCPUVirtualAddress: *mut VOID, + FenceValueGPUVirtualAddress: D3DGPU_VIRTUAL_ADDRESS, + EngineAffinity: UINT, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_PeriodicMonitoredFence { + hAdapter: D3DKMT_HANDLE, + VidPnTargetId: D3DDDI_VIDEO_PRESENT_TARGET_ID, + Time: UINT64, + FenceValueCPUVirtualAddress: *mut VOID, + FenceValueGPUVirtualAddress: D3DGPU_VIRTUAL_ADDRESS, + EngineAffinity: UINT, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Reserved { + Reserved: [UINT64; 8], +}} +UNION!{union D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u { + [u64; 8], + SynchronizationMutex SynchronizationMutex_mut: + D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_SynchronizationMutex, + Semaphore Semaphore_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Semaphore, + Fence Fence_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Fence, + CPUNotification CPUNotification_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_CPUNotification, + MonitoredFence MonitoredFence_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_MonitoredFence, + PeriodicMonitoredFence PeriodicMonitoredFence_mut: + D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_PeriodicMonitoredFence, + Reserved Reserved_mut: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u_Reserved, +}} +STRUCT!{struct D3DDDI_SYNCHRONIZATIONOBJECTINFO2 { + Type: D3DDDI_SYNCHRONIZATIONOBJECT_TYPE, + Flags: D3DDDI_SYNCHRONIZATIONOBJECT_FLAGS, + u: D3DDDI_SYNCHRONIZATIONOBJECTINFO2_u, + SharedHandle: D3DKMT_HANDLE, +}} +//1778 +pub const D3DDDI_MAX_BROADCAST_CONTEXT: usize = 64; diff --git a/winapi/src/shared/dcomptypes.rs b/winapi/src/shared/dcomptypes.rs new file mode 100644 index 000000000..4d45d3c90 --- /dev/null +++ b/winapi/src/shared/dcomptypes.rs @@ -0,0 +1,50 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dcomptypes.h +use shared::dxgitype::DXGI_RATIONAL; +use shared::minwindef::DWORD; +use um::winnt::LARGE_INTEGER; +ENUM!{enum DCOMPOSITION_BITMAP_INTERPOLATION_MODE { + DCOMPOSITION_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + DCOMPOSITION_BITMAP_INTERPOLATION_MODE_LINEAR = 1, + DCOMPOSITION_BITMAP_INTERPOLATION_MODE_INHERIT = 0xffffffff, +}} +ENUM!{enum DCOMPOSITION_BORDER_MODE { + DCOMPOSITION_BORDER_MODE_SOFT = 0, + DCOMPOSITION_BORDER_MODE_HARD = 1, + DCOMPOSITION_BORDER_MODE_INHERIT = 0xffffffff, +}} +ENUM!{enum DCOMPOSITION_COMPOSITE_MODE { + DCOMPOSITION_COMPOSITE_MODE_SOURCE_OVER = 0, + DCOMPOSITION_COMPOSITE_MODE_DESTINATION_INVERT = 1, + DCOMPOSITION_COMPOSITE_MODE_MIN_BLEND = 2, + DCOMPOSITION_COMPOSITE_MODE_INHERIT = 0xffffffff, +}} +ENUM!{enum DCOMPOSITION_BACKFACE_VISIBILITY { + DCOMPOSITION_BACKFACE_VISIBILITY_VISIBLE = 0, + DCOMPOSITION_BACKFACE_VISIBILITY_HIDDEN = 1, + DCOMPOSITION_BACKFACE_VISIBILITY_INHERIT = 0xffffffff, +}} +ENUM!{enum DCOMPOSITION_OPACITY_MODE { + DCOMPOSITION_OPACITY_MODE_LAYER = 0, + DCOMPOSITION_OPACITY_MODE_MULTIPLY = 1, + DCOMPOSITION_OPACITY_MODE_INHERIT = 0xffffffff, +}} +ENUM!{enum DCOMPOSITION_DEPTH_MODE { + DCOMPOSITION_DEPTH_MODE_TREE = 0, + DCOMPOSITION_DEPTH_MODE_SPATIAL = 1, + DCOMPOSITION_DEPTH_MODE_INHERIT = 0xffffffff, +}} +STRUCT!{struct DCOMPOSITION_FRAME_STATISTICS { + lastFrameTime: LARGE_INTEGER, + currentCompositionRate: DXGI_RATIONAL, + currentTime: LARGE_INTEGER, + timeFrequency: LARGE_INTEGER, + nextEstimatedFrameTime: LARGE_INTEGER, +}} +pub const COMPOSITIONOBJECT_READ: DWORD = 0x0001; +pub const COMPOSITIONOBJECT_WRITE: DWORD = 0x0002; +pub const COMPOSITIONOBJECT_ALL_ACCESS: DWORD = COMPOSITIONOBJECT_READ | COMPOSITIONOBJECT_WRITE; diff --git a/winapi/src/shared/devguid.rs b/winapi/src/shared/devguid.rs new file mode 100644 index 000000000..f163037b8 --- /dev/null +++ b/winapi/src/shared/devguid.rs @@ -0,0 +1,178 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Defines GUIDs for device classes used in Plug & Play. +DEFINE_GUID!{GUID_DEVCLASS_1394, + 0x6bdd1fc1, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_1394DEBUG, + 0x66f250d6, 0x7801, 0x4a64, 0xb1, 0x39, 0xee, 0xa8, 0x0a, 0x45, 0x0b, 0x24} +DEFINE_GUID!{GUID_DEVCLASS_61883, + 0x7ebefbc0, 0x3200, 0x11d2, 0xb4, 0xc2, 0x00, 0xa0, 0xc9, 0x69, 0x7d, 0x07} +DEFINE_GUID!{GUID_DEVCLASS_ADAPTER, + 0x4d36e964, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_APMSUPPORT, + 0xd45b1c18, 0xc8fa, 0x11d1, 0x9f, 0x77, 0x00, 0x00, 0xf8, 0x05, 0xf5, 0x30} +DEFINE_GUID!{GUID_DEVCLASS_AVC, + 0xc06ff265, 0xae09, 0x48f0, 0x81, 0x2c, 0x16, 0x75, 0x3d, 0x7c, 0xba, 0x83} +DEFINE_GUID!{GUID_DEVCLASS_BATTERY, + 0x72631e54, 0x78a4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a} +DEFINE_GUID!{GUID_DEVCLASS_BIOMETRIC, + 0x53d29ef7, 0x377c, 0x4d14, 0x86, 0x4b, 0xeb, 0x3a, 0x85, 0x76, 0x93, 0x59} +DEFINE_GUID!{GUID_DEVCLASS_BLUETOOTH, + 0xe0cbf06c, 0xcd8b, 0x4647, 0xbb, 0x8a, 0x26, 0x3b, 0x43, 0xf0, 0xf9, 0x74} +DEFINE_GUID!{GUID_DEVCLASS_CDROM, + 0x4d36e965, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_COMPUTER, + 0x4d36e966, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_DECODER, + 0x6bdd1fc2, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_DISKDRIVE, + 0x4d36e967, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_DISPLAY, + 0x4d36e968, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_DOT4, + 0x48721b56, 0x6795, 0x11d2, 0xb1, 0xa8, 0x00, 0x80, 0xc7, 0x2e, 0x74, 0xa2} +DEFINE_GUID!{GUID_DEVCLASS_DOT4PRINT, + 0x49ce6ac8, 0x6f86, 0x11d2, 0xb1, 0xe5, 0x00, 0x80, 0xc7, 0x2e, 0x74, 0xa2} +DEFINE_GUID!{GUID_DEVCLASS_ENUM1394, + 0xc459df55, 0xdb08, 0x11d1, 0xb0, 0x09, 0x00, 0xa0, 0xc9, 0x08, 0x1f, 0xf6} +DEFINE_GUID!{GUID_DEVCLASS_FDC, + 0x4d36e969, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_FLOPPYDISK, + 0x4d36e980, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_GPS, + 0x6bdd1fc3, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_HDC, + 0x4d36e96a, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_HIDCLASS, + 0x745a17a0, 0x74d3, 0x11d0, 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda} +DEFINE_GUID!{GUID_DEVCLASS_IMAGE, + 0x6bdd1fc6, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_INFINIBAND, + 0x30ef7132, 0xd858, 0x4a0c, 0xac, 0x24, 0xb9, 0x02, 0x8a, 0x5c, 0xca, 0x3f} +DEFINE_GUID!{GUID_DEVCLASS_INFRARED, + 0x6bdd1fc5, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_KEYBOARD, + 0x4d36e96b, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_LEGACYDRIVER, + 0x8ecc055d, 0x047f, 0x11d1, 0xa5, 0x37, 0x00, 0x00, 0xf8, 0x75, 0x3e, 0xd1} +DEFINE_GUID!{GUID_DEVCLASS_MEDIA, + 0x4d36e96c, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MEDIUM_CHANGER, + 0xce5939ae, 0xebde, 0x11d0, 0xb1, 0x81, 0x00, 0x00, 0xf8, 0x75, 0x3e, 0xc4} +DEFINE_GUID!{GUID_DEVCLASS_MODEM, + 0x4d36e96d, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MEMORY, + 0x5099944a, 0xf6b9, 0x4057, 0xa0, 0x56, 0x8c, 0x55, 0x02, 0x28, 0x54, 0x4c} +DEFINE_GUID!{GUID_DEVCLASS_MONITOR, + 0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MOUSE, + 0x4d36e96f, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MTD, + 0x4d36e970, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MULTIFUNCTION, + 0x4d36e971, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_MULTIPORTSERIAL, + 0x50906cb8, 0xba12, 0x11d1, 0xbf, 0x5d, 0x00, 0x00, 0xf8, 0x05, 0xf5, 0x30} +DEFINE_GUID!{GUID_DEVCLASS_NET, + 0x4d36e972, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_NETCLIENT, + 0x4d36e973, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_NETSERVICE, + 0x4d36e974, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_NETTRANS, + 0x4d36e975, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_NODRIVER, + 0x4d36e976, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_PCMCIA, + 0x4d36e977, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_PNPPRINTERS, + 0x4658ee7e, 0xf050, 0x11d1, 0xb6, 0xbd, 0x00, 0xc0, 0x4f, 0xa3, 0x72, 0xa7} +DEFINE_GUID!{GUID_DEVCLASS_PORTS, + 0x4d36e978, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_PRINTER, + 0x4d36e979, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_PRINTERUPGRADE, + 0x4d36e97a, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_PROCESSOR, + 0x50127dc3, 0x0f36, 0x415e, 0xa6, 0xcc, 0x4c, 0xb3, 0xbe, 0x91, 0x0B, 0x65} +DEFINE_GUID!{GUID_DEVCLASS_SBP2, + 0xd48179be, 0xec20, 0x11d1, 0xb6, 0xb8, 0x00, 0xc0, 0x4f, 0xa3, 0x72, 0xa7} +DEFINE_GUID!{GUID_DEVCLASS_SCSIADAPTER, + 0x4d36e97b, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_SECURITYACCELERATOR, + 0x268c95a1, 0xedfe, 0x11d3, 0x95, 0xc3, 0x00, 0x10, 0xdc, 0x40, 0x50, 0xa5} +DEFINE_GUID!{GUID_DEVCLASS_SENSOR, + 0x5175d334, 0xc371, 0x4806, 0xb3, 0xba, 0x71, 0xfd, 0x53, 0xc9, 0x25, 0x8d} +DEFINE_GUID!{GUID_DEVCLASS_SIDESHOW, + 0x997b5d8d, 0xc442, 0x4f2e, 0xba, 0xf3, 0x9c, 0x8e, 0x67, 0x1e, 0x9e, 0x21} +DEFINE_GUID!{GUID_DEVCLASS_SMARTCARDREADER, + 0x50dd5230, 0xba8a, 0x11d1, 0xbf, 0x5d, 0x00, 0x00, 0xf8, 0x05, 0xf5, 0x30} +DEFINE_GUID!{GUID_DEVCLASS_SOUND, + 0x4d36e97c, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_SYSTEM, + 0x4d36e97d, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_TAPEDRIVE, + 0x6d807884, 0x7d21, 0x11cf, 0x80, 0x1c, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_UNKNOWN, + 0x4d36e97e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_DEVCLASS_USB, + 0x36fc9e60, 0xc465, 0x11cf, 0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_DEVCLASS_VOLUME, + 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f} +DEFINE_GUID!{GUID_DEVCLASS_VOLUMESNAPSHOT, + 0x533c5b84, 0xec70, 0x11d2, 0x95, 0x05, 0x00, 0xc0, 0x4f, 0x79, 0xde, 0xaf} +DEFINE_GUID!{GUID_DEVCLASS_WCEUSBS, + 0x25dbce51, 0x6c8f, 0x4a72, 0x8a, 0x6d, 0xb5, 0x4c, 0x2b, 0x4f, 0xc8, 0x35} +DEFINE_GUID!{GUID_DEVCLASS_WPD, + 0xeec5ad98, 0x8080, 0x425f, 0x92, 0x2a, 0xda, 0xbf, 0x3d, 0xe3, 0xf6, 0x9a} +DEFINE_GUID!{GUID_DEVCLASS_EHSTORAGESILO, + 0x9da2b80f, 0xf89f, 0x4a49, 0xa5, 0xc2, 0x51, 0x1b, 0x08, 0x5b, 0x9e, 0x8a} +DEFINE_GUID!{GUID_DEVCLASS_FIRMWARE, + 0xf2e7dd72, 0x6468, 0x4e36, 0xb6, 0xf1, 0x64, 0x88, 0xf4, 0x2c, 0x1b, 0x52} +DEFINE_GUID!{GUID_DEVCLASS_EXTENSION, + 0xe2f84ce7, 0x8efa, 0x411c, 0xaa, 0x69, 0x97, 0x45, 0x4c, 0xa4, 0xcb, 0x57} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_TOP, + 0xb369baf4, 0x5568, 0x4e82, 0xa8, 0x7e, 0xa9, 0x3e, 0xb1, 0x6b, 0xca, 0x87} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_ACTIVITYMONITOR, + 0xb86dff51, 0xa31e, 0x4bac, 0xb3, 0xcf, 0xe8, 0xcf, 0xe7, 0x5c, 0x9f, 0xc2} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_UNDELETE, + 0xfe8f1572, 0xc67a, 0x48c0, 0xbb, 0xac, 0x0b, 0x5c, 0x6d, 0x66, 0xca, 0xfb} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_ANTIVIRUS, + 0xb1d1a169, 0xc54f, 0x4379, 0x81, 0xdb, 0xbe, 0xe7, 0xd8, 0x8d, 0x74, 0x54} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_REPLICATION, + 0x48d3ebc4, 0x4cf8, 0x48ff, 0xb8, 0x69, 0x9c, 0x68, 0xad, 0x42, 0xeb, 0x9f} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_CONTINUOUSBACKUP, + 0x71aa14f8, 0x6fad, 0x4622, 0xad, 0x77, 0x92, 0xbb, 0x9d, 0x7e, 0x69, 0x47} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_CONTENTSCREENER, + 0x3e3f0674, 0xc83c, 0x4558, 0xbb, 0x26, 0x98, 0x20, 0xe1, 0xeb, 0xa5, 0xc5} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_QUOTAMANAGEMENT, + 0x8503c911, 0xa6c7, 0x4919, 0x8f, 0x79, 0x50, 0x28, 0xf5, 0x86, 0x6b, 0x0c} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_SYSTEMRECOVERY, + 0x2db15374, 0x706e, 0x4131, 0xa0, 0xc7, 0xd7, 0xc7, 0x8e, 0xb0, 0x28, 0x9a} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_CFSMETADATASERVER, + 0xcdcf0939, 0xb75b, 0x4630, 0xbf, 0x76, 0x80, 0xf7, 0xba, 0x65, 0x58, 0x84} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_HSM, + 0xd546500a, 0x2aeb, 0x45f6, 0x94, 0x82, 0xf4, 0xb1, 0x79, 0x9c, 0x31, 0x77} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_COMPRESSION, + 0xf3586baf, 0xb5aa, 0x49b5, 0x8d, 0x6c, 0x05, 0x69, 0x28, 0x4c, 0x63, 0x9f} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_ENCRYPTION, + 0xa0a701c0, 0xa511, 0x42ff, 0xaa, 0x6c, 0x06, 0xdc, 0x03, 0x95, 0x57, 0x6f} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_VIRTUALIZATION, + 0xf75a86c0, 0x10d8, 0x4c3a, 0xb2, 0x33, 0xed, 0x60, 0xe4, 0xcd, 0xfa, 0xac} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_PHYSICALQUOTAMANAGEMENT, + 0x6a0a8e78, 0xbba6, 0x4fc4, 0xa7, 0x09, 0x1e, 0x33, 0xcd, 0x09, 0xd6, 0x7e} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_OPENFILEBACKUP, + 0xf8ecafa6, 0x66d1, 0x41a5, 0x89, 0x9b, 0x66, 0x58, 0x5d, 0x72, 0x16, 0xb7} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_SECURITYENHANCER, + 0xd02bc3da, 0x0c8e, 0x4945, 0x9b, 0xd5, 0xf1, 0x88, 0x3c, 0x22, 0x6c, 0x8c} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_COPYPROTECTION, + 0x89786ff1, 0x9c12, 0x402f, 0x9c, 0x9e, 0x17, 0x75, 0x3c, 0x7f, 0x43, 0x75} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_BOTTOM, + 0x37765ea0, 0x5958, 0x4fc9, 0xb0, 0x4b, 0x2f, 0xdf, 0xef, 0x97, 0xe5, 0x9e} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_SYSTEM, + 0x5d1b9aaa, 0x01e2, 0x46af, 0x84, 0x9f, 0x27, 0x2b, 0x3f, 0x32, 0x4c, 0x46} +DEFINE_GUID!{GUID_DEVCLASS_FSFILTER_INFRASTRUCTURE, + 0xe55fa6f9, 0x128c, 0x4d04, 0xab, 0xab, 0x63, 0x0c, 0x74, 0xb1, 0x45, 0x3a} diff --git a/winapi/src/shared/devpkey.rs b/winapi/src/shared/devpkey.rs new file mode 100644 index 000000000..db6855796 --- /dev/null +++ b/winapi/src/shared/devpkey.rs @@ -0,0 +1,401 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Defines property keys for the Plug and Play Device Property API. +use shared::devpropdef::DEVPROPKEY; +DEFINE_DEVPROPKEY!{DEVPKEY_NAME, + 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DeviceDesc, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_HardwareIds, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_CompatibleIds, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Service, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Class, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ClassGuid, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Driver, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ConfigFlags, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Manufacturer, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FriendlyName, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LocationInfo, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PDOName, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Capabilities, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_UINumber, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_UpperFilters, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LowerFilters, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BusTypeGuid, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LegacyBusType, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BusNumber, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_EnumeratorName, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Security, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SecuritySDS, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DevType, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Exclusive, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Characteristics, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Address, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_UINumberDescFormat, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PowerData, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_RemovalPolicy, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_RemovalPolicyDefault, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_RemovalPolicyOverride, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_InstallState, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LocationPaths, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BaseContainerId, + 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_InstanceId, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DevNodeStatus, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ProblemCode, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_EjectionRelations, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_RemovalRelations, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PowerRelations, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BusRelations, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Parent, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Children, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Siblings, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_TransportRelations, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ProblemStatus, + 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 12} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Reported, + 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Legacy, + 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ContainerId, + 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_InLocalMachineContainer, + 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Model, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 39} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ModelId, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FriendlyNameAttributes, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ManufacturerAttributes, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PresenceNotForDevice, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SignalStrength, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_IsAssociateableByUserAction, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ShowInUninstallUI, + 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 8} +pub const DEVPKEY_Numa_Proximity_Domain: DEVPROPKEY = DEVPKEY_Device_Numa_Proximity_Domain; +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Numa_Proximity_Domain, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DHP_Rebalance_Policy, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Numa_Node, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BusReportedDeviceDesc, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_IsPresent, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_HasProblem, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ConfigurationId, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ReportedDeviceIdsHash, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 8} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PhysicalDeviceLocation, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 9} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_BiosDeviceName, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverProblemDesc, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 11} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DebuggerSafe, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 12} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_PostInstallInProgress, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 13} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_Stack, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 14} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ExtendedConfigurationIds, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 15} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_IsRebootRequired, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 16} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FirmwareDate, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 17} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FirmwareVersion, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 18} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FirmwareRevision, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 19} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DependencyProviders, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 20} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DependencyDependents, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 21} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SoftRestartSupported, + 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 22} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SessionId, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_InstallDate, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 100} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_FirstInstallDate, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 101} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LastArrivalDate, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 102} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_LastRemovalDate, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 103} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverDate, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverVersion, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverDesc, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverInfPath, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverInfSection, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverInfSectionExt, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_MatchingDeviceId, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverProvider, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverPropPageProvider, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverCoInstallers, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ResourcePickerTags, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_ResourcePickerExceptions, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverRank, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_DriverLogoLevel, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_NoConnectSound, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_GenericDriverInstalled, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_AdditionalSoftwareRequested, + 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SafeRemovalRequired, + 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Device_SafeRemovalRequiredOverride, + 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_Model, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_VendorWebSite, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_DetailedDescription, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_DocumentationLink, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_Icon, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_DrvPkg_BrandingIcon, + 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_UpperFilters, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_LowerFilters, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_Security, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_SecuritySDS, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_DevType, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_Exclusive, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_Characteristics, + 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_Name, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_ClassName, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_Icon, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_ClassInstaller, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_PropPageProvider, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_NoInstallClass, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_NoDisplayClass, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_SilentInstall, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_NoUseClass, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_DefaultService, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_IconPath, + 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_DHPRebalanceOptOut, + 0xd14d3ef3, 0x66cf, 0x4ba2, 0x9d, 0x38, 0x0d, 0xdb, 0x37, 0xab, 0x47, 0x01, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceClass_ClassCoInstallers, + 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_FriendlyName, + 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_Enabled, + 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_ClassGuid, + 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_ReferenceString, + 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 5} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_Restricted, + 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 6} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterfaceClass_DefaultInterface, + 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterfaceClass_Name, + 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Address, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 51} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_DiscoveryMethod, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 52} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsEncrypted, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 53} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsAuthenticated, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 54} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsConnected, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 55} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsPaired, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 56} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Icon, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 57} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Version, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 65} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Last_Seen, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 66} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Last_Connected, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 67} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsShowInDisconnectedState, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 68} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsLocalMachine, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 70} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_MetadataPath, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 71} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsMetadataSearchInProgress, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 72} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_MetadataChecksum, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 73} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsNotInterestingForDisplay, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 74} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_LaunchDeviceStageOnDeviceConnect, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 76} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_LaunchDeviceStageFromExplorer, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 77} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_BaselineExperienceId, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 78} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsDeviceUniquelyIdentifiable, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 79} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_AssociationArray, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 80} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_DeviceDescription1, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 81} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_DeviceDescription2, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 82} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_HasProblem, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 83} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsSharedDevice, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 84} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsNetworkDevice, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 85} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsDefaultDevice, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 86} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_MetadataCabinet, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 87} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_RequiresPairingElevation, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 88} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_ExperienceId, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 89} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Category, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 90} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Category_Desc_Singular, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 91} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Category_Desc_Plural, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 92} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Category_Icon, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 93} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_CategoryGroup_Desc, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 94} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_CategoryGroup_Icon, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 95} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_PrimaryCategory, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 97} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_UnpairUninstall, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 98} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_RequiresUninstallElevation, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 99} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_DeviceFunctionSubRank, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 100} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_AlwaysShowDeviceAsConnected, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 101} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_ConfigFlags, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 105} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_PrivilegedPackageFamilyNames, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 106} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_CustomPrivilegedPackageFamilyNames, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 107} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_IsRebootRequired, + 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 108} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_FriendlyName, + 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 12288} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_Manufacturer, + 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 8192} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_ModelName, + 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 8194} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_ModelNumber, + 0x656A3BB3, 0xECC0, 0x43FD, 0x84, 0x77, 0x4A, 0xE0, 0x40, 0x4A, 0x96, 0xCD, 8195} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceContainer_InstallInProgress, + 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9} +pub const DEVPKEY_DeviceDisplay_DiscoveryMethod: DEVPROPKEY + = DEVPKEY_DeviceContainer_DiscoveryMethod; +pub const DEVPKEY_DeviceDisplay_IsShowInDisconnectedState: DEVPROPKEY + = DEVPKEY_DeviceContainer_IsShowInDisconnectedState; +pub const DEVPKEY_DeviceDisplay_IsNotInterestingForDisplay: DEVPROPKEY + = DEVPKEY_DeviceContainer_IsNotInterestingForDisplay; +pub const DEVPKEY_DeviceDisplay_IsNetworkDevice: DEVPROPKEY + = DEVPKEY_DeviceContainer_IsNetworkDevice; +pub const DEVPKEY_DeviceDisplay_Category: DEVPROPKEY = DEVPKEY_DeviceContainer_Category; +pub const DEVPKEY_DeviceDisplay_UnpairUninstall: DEVPROPKEY + = DEVPKEY_DeviceContainer_UnpairUninstall; +pub const DEVPKEY_DeviceDisplay_RequiresUninstallElevation: DEVPROPKEY + = DEVPKEY_DeviceContainer_RequiresUninstallElevation; +pub const DEVPKEY_DeviceDisplay_AlwaysShowDeviceAsConnected: DEVPROPKEY + = DEVPKEY_DeviceContainer_AlwaysShowDeviceAsConnected; +DEFINE_DEVPROPKEY!{DEVPKEY_DevQuery_ObjectType, + 0x13673f42, 0xa3d6, 0x49f6, 0xb4, 0xda, 0xae, 0x46, 0xe0, 0xc5, 0x23, 0x7c, 2} diff --git a/winapi/src/shared/devpropdef.rs b/winapi/src/shared/devpropdef.rs new file mode 100644 index 000000000..1e9388a44 --- /dev/null +++ b/winapi/src/shared/devpropdef.rs @@ -0,0 +1,83 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Defines property types and keys for the Plug and Play Device Property API +use shared::guiddef::{GUID, IsEqualGUID}; +use shared::minwindef::ULONG; +use um::winnt::{CHAR, PCWSTR, PVOID}; +pub type DEVPROPTYPE = ULONG; +pub type PDEVPROPTYPE = *mut ULONG; +pub const DEVPROP_TYPEMOD_ARRAY: DEVPROPTYPE = 0x00001000; +pub const DEVPROP_TYPEMOD_LIST: DEVPROPTYPE = 0x00002000; +pub const DEVPROP_TYPE_EMPTY: DEVPROPTYPE = 0x00000000; +pub const DEVPROP_TYPE_NULL: DEVPROPTYPE = 0x00000001; +pub const DEVPROP_TYPE_SBYTE: DEVPROPTYPE = 0x00000002; +pub const DEVPROP_TYPE_BYTE: DEVPROPTYPE = 0x00000003; +pub const DEVPROP_TYPE_INT16: DEVPROPTYPE = 0x00000004; +pub const DEVPROP_TYPE_UINT16: DEVPROPTYPE = 0x00000005; +pub const DEVPROP_TYPE_INT32: DEVPROPTYPE = 0x00000006; +pub const DEVPROP_TYPE_UINT32: DEVPROPTYPE = 0x00000007; +pub const DEVPROP_TYPE_INT64: DEVPROPTYPE = 0x00000008; +pub const DEVPROP_TYPE_UINT64: DEVPROPTYPE = 0x00000009; +pub const DEVPROP_TYPE_FLOAT: DEVPROPTYPE = 0x0000000A; +pub const DEVPROP_TYPE_DOUBLE: DEVPROPTYPE = 0x0000000B; +pub const DEVPROP_TYPE_DECIMAL: DEVPROPTYPE = 0x0000000C; +pub const DEVPROP_TYPE_GUID: DEVPROPTYPE = 0x0000000D; +pub const DEVPROP_TYPE_CURRENCY: DEVPROPTYPE = 0x0000000E; +pub const DEVPROP_TYPE_DATE: DEVPROPTYPE = 0x0000000F; +pub const DEVPROP_TYPE_FILETIME: DEVPROPTYPE = 0x00000010; +pub const DEVPROP_TYPE_BOOLEAN: DEVPROPTYPE = 0x00000011; +pub const DEVPROP_TYPE_STRING: DEVPROPTYPE = 0x00000012; +pub const DEVPROP_TYPE_STRING_LIST: DEVPROPTYPE = DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST; +pub const DEVPROP_TYPE_SECURITY_DESCRIPTOR: DEVPROPTYPE = 0x00000013; +pub const DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING: DEVPROPTYPE = 0x00000014; +pub const DEVPROP_TYPE_DEVPROPKEY: DEVPROPTYPE = 0x00000015; +pub const DEVPROP_TYPE_DEVPROPTYPE: DEVPROPTYPE = 0x00000016; +pub const DEVPROP_TYPE_BINARY: DEVPROPTYPE = DEVPROP_TYPE_BYTE | DEVPROP_TYPEMOD_ARRAY; +pub const DEVPROP_TYPE_ERROR: DEVPROPTYPE = 0x00000017; +pub const DEVPROP_TYPE_NTSTATUS: DEVPROPTYPE = 0x00000018; +pub const DEVPROP_TYPE_STRING_INDIRECT: DEVPROPTYPE = 0x00000019; +pub const MAX_DEVPROP_TYPE: DEVPROPTYPE = 0x00000019; +pub const MAX_DEVPROP_TYPEMOD: DEVPROPTYPE = 0x00002000; +pub const DEVPROP_MASK_TYPE: DEVPROPTYPE = 0x00000FFF; +pub const DEVPROP_MASK_TYPEMOD: DEVPROPTYPE = 0x0000F000; +pub type DEVPROP_BOOLEAN = CHAR; +pub type PDEVPROP_BOOLEAN = *mut CHAR; +pub const DEVPROP_TRUE: DEVPROP_BOOLEAN = -1; +pub const DEVPROP_FALSE: DEVPROP_BOOLEAN = 0; +pub type DEVPROPGUID = GUID; +pub type PDEVPROPGUID = *mut GUID; +pub type DEVPROPID = ULONG; +pub type PDEVPROPID = *mut ULONG; +STRUCT!{struct DEVPROPKEY { + fmtid: DEVPROPGUID, + pid: DEVPROPID, +}} +pub type PDEVPROPKEY = *mut DEVPROPKEY; +#[inline] +pub fn IsEqualDevPropKey(a: &DEVPROPKEY, b: &DEVPROPKEY) -> bool { + (a.pid == b.pid) && IsEqualGUID(&a.fmtid, &b.fmtid) +} +ENUM!{enum DEVPROPSTORE { + DEVPROP_STORE_SYSTEM, + DEVPROP_STORE_USER, +}} +pub type PDEVPROPSTORE = *mut DEVPROPSTORE; +STRUCT!{struct DEVPROPCOMPKEY { + Key: DEVPROPKEY, + Store: DEVPROPSTORE, + LocaleName: PCWSTR, +}} +pub type PDEVPROPCOMPKEY = *mut DEVPROPCOMPKEY; +// IsEqualLocaleName +// IsEqualDevPropCompKey +STRUCT!{struct DEVPROPERTY { + CompKey: DEVPROPCOMPKEY, + Type: DEVPROPTYPE, + BufferSize: ULONG, + Buffer: PVOID, +}} +pub type PDEVPROPERTY = *mut DEVPROPERTY; +pub const DEVPROPID_FIRST_USABLE: DEVPROPID = 2; diff --git a/winapi/src/shared/dinputd.rs b/winapi/src/shared/dinputd.rs new file mode 100644 index 000000000..ceb9ffd99 --- /dev/null +++ b/winapi/src/shared/dinputd.rs @@ -0,0 +1,21 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_IDirectInputEffectDriver, + 0x02538130, 0x898f, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{IID_IDirectInputJoyConfig, + 0x1de12ab1, 0xc9f5, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputPIDDriver, + 0xeec6993a, 0xb3fd, 0x11d2, 0xa9, 0x16, 0x00, 0xc0, 0x4f, 0xb9, 0x86, 0x38} +DEFINE_GUID!{IID_IDirectInputJoyConfig8, + 0xeb0d7dfa, 0x1990, 0x4f27, 0xb4, 0xd6, 0xed, 0xf2, 0xee, 0xc4, 0xa4, 0x4c} +DEFINE_GUID!{GUID_KeyboardClass, + 0x4d36e96b, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_MediaClass, + 0x4d36e96c, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_MouseClass, + 0x4d36e96f, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} +DEFINE_GUID!{GUID_HIDClass, + 0x745a17a0, 0x74d3, 0x11d0, 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda} diff --git a/winapi/src/shared/dxgi.rs b/winapi/src/shared/dxgi.rs new file mode 100644 index 000000000..0e878586e --- /dev/null +++ b/winapi/src/shared/dxgi.rs @@ -0,0 +1,411 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi.h +use ctypes::c_void; +use shared::basetsd::{SIZE_T, UINT64}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::{ + DXGI_GAMMA_CONTROL, DXGI_GAMMA_CONTROL_CAPABILITIES, DXGI_MODE_DESC, DXGI_MODE_ROTATION, + DXGI_SAMPLE_DESC, DXGI_USAGE, +}; +use shared::guiddef::{REFGUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, HMODULE, UINT}; +use shared::windef::{HDC, HMONITOR, HWND, RECT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, INT, LARGE_INTEGER, LUID, WCHAR}; +STRUCT!{struct DXGI_FRAME_STATISTICS { + PresentCount: UINT, + PresentRefreshCount: UINT, + SyncRefreshCount: UINT, + SyncQPCTime: LARGE_INTEGER, + SyncGPUTime: LARGE_INTEGER, +}} +STRUCT!{struct DXGI_MAPPED_RECT { + Pitch: INT, + pBits: *mut BYTE, +}} +STRUCT!{struct DXGI_ADAPTER_DESC { + Description: [WCHAR; 128], + VendorId: UINT, + DeviceId: UINT, + SubSysId: UINT, + Revision: UINT, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, +}} +STRUCT!{struct DXGI_OUTPUT_DESC { + DeviceName: [WCHAR; 32], + DesktopCoordinates: RECT, + AttachedToDesktop: BOOL, + Rotation: DXGI_MODE_ROTATION, + Monitor: HMONITOR, +}} +STRUCT!{struct DXGI_SHARED_RESOURCE { + Handle: HANDLE, +}} +pub const DXGI_RESOURCE_PRIORITY_MINIMUM: DWORD = 0x28000000; +pub const DXGI_RESOURCE_PRIORITY_LOW: DWORD = 0x50000000; +pub const DXGI_RESOURCE_PRIORITY_NORMAL: DWORD = 0x78000000; +pub const DXGI_RESOURCE_PRIORITY_HIGH: DWORD = 0xa0000000; +pub const DXGI_RESOURCE_PRIORITY_MAXIMUM: DWORD = 0xc8000000; +ENUM!{enum DXGI_RESIDENCY { + DXGI_RESIDENCY_FULLY_RESIDENT = 1, + DXGI_RESIDENCY_RESIDENT_IN_SHARED_MEMORY = 2, + DXGI_RESIDENCY_EVICTED_TO_DISK = 3, +}} +STRUCT!{struct DXGI_SURFACE_DESC { + Width: UINT, + Height: UINT, + Format: DXGI_FORMAT, + SampleDesc: DXGI_SAMPLE_DESC, +}} +ENUM!{enum DXGI_SWAP_EFFECT { + DXGI_SWAP_EFFECT_DISCARD = 0, + DXGI_SWAP_EFFECT_SEQUENTIAL = 1, + DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 3, + DXGI_SWAP_EFFECT_FLIP_DISCARD = 4, +}} +ENUM!{enum DXGI_SWAP_CHAIN_FLAG { + DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1, + DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2, + DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4, + DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT = 8, + DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 16, + DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY = 32, + DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT = 64, + DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER = 128, + DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO = 256, + DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO = 512, + DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED = 1024, + DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING = 2048, +}} +STRUCT!{struct DXGI_SWAP_CHAIN_DESC { + BufferDesc: DXGI_MODE_DESC, + SampleDesc: DXGI_SAMPLE_DESC, + BufferUsage: DXGI_USAGE, + BufferCount: UINT, + OutputWindow: HWND, + Windowed: BOOL, + SwapEffect: DXGI_SWAP_EFFECT, + Flags: UINT, +}} +RIDL!{#[uuid(0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a, 0x2e)] +interface IDXGIObject(IDXGIObjectVtbl): IUnknown(IUnknownVtbl) { + fn SetPrivateData( + Name: REFGUID, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn SetPrivateDataInterface( + Name: REFGUID, + pUnknown: *const IUnknown, + ) -> HRESULT, + fn GetPrivateData( + Name: REFGUID, + pDataSize: *mut UINT, + pData: *mut c_void, + ) -> HRESULT, + fn GetParent( + riid: REFIID, + ppParent: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29, 0x92, 0xf1, 0xa6)] +interface IDXGIDeviceSubObject(IDXGIDeviceSubObjectVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn GetDevice( + riid: REFIID, + ppDevice: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96, 0x0b)] +interface IDXGIResource(IDXGIResourceVtbl): IDXGIDeviceSubObject(IDXGIDeviceSubObjectVtbl) { + fn GetSharedHandle( + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn GetUsage( + pUsage: *mut DXGI_USAGE, + ) -> HRESULT, + fn SetEvictionPriority( + EvictionPriority: UINT, + ) -> HRESULT, + fn GetEvictionPriority( + pEvictionPriority: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a, 0xf8, 0x5d)] +interface IDXGIKeyedMutex(IDXGIKeyedMutexVtbl): IDXGIDeviceSubObject(IDXGIDeviceSubObjectVtbl) { + fn AcquireSync( + Key: UINT64, + dwMilliseconds: DWORD, + ) -> HRESULT, + fn ReleaseSync( + Key: UINT64, + ) -> HRESULT, +}} +pub const DXGI_MAP_READ: UINT = 1; +pub const DXGI_MAP_WRITE: UINT = 2; +pub const DXGI_MAP_DISCARD: UINT = 4; +RIDL!{#[uuid(0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60, 0xec)] +interface IDXGISurface(IDXGISurfaceVtbl): IDXGIDeviceSubObject(IDXGIDeviceSubObjectVtbl) { + fn GetDesc( + pDesc: *mut DXGI_SURFACE_DESC, + ) -> HRESULT, + fn Map( + pLockedRect: *mut DXGI_MAPPED_RECT, + MapFlags: UINT, + ) -> HRESULT, + fn Unmap() -> HRESULT, +}} +RIDL!{#[uuid(0x4ae63092, 0x6327, 0x4c1b, 0x80, 0xae, 0xbf, 0xe1, 0x2e, 0xa3, 0x2b, 0x86)] +interface IDXGISurface1(IDXGISurface1Vtbl): IDXGISurface(IDXGISurfaceVtbl) { + fn GetDC( + Discard: BOOL, + phdc: *mut HDC, + ) -> HRESULT, + fn ReleaseDC( + pDirtyRect: *mut RECT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d, 0xc0)] +interface IDXGIAdapter(IDXGIAdapterVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn EnumOutputs( + Output: UINT, + ppOutput: *mut *mut IDXGIOutput, + ) -> HRESULT, + fn GetDesc( + pDesc: *mut DXGI_ADAPTER_DESC, + ) -> HRESULT, + fn CheckInterfaceSupport( + InterfaceName: REFGUID, + pUMDVersion: *mut LARGE_INTEGER, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13, 0xaa)] +interface IDXGIOutput(IDXGIOutputVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn GetDesc( + pDesc: *mut DXGI_OUTPUT_DESC, + ) -> HRESULT, + fn GetDisplayModeList( + EnumFormat: DXGI_FORMAT, + Flags: UINT, + pNumModes: *mut UINT, + pDesc: *mut DXGI_MODE_DESC, + ) -> HRESULT, + fn FindClosestMatchingMode( + pModeToMatch: *const DXGI_MODE_DESC, + pClosestMatch: *mut DXGI_MODE_DESC, + pConcernedDevice: *mut IUnknown, + ) -> HRESULT, + fn WaitForVBlank() -> HRESULT, + fn TakeOwnership( + pDevice: *mut IUnknown, + Exclusive: BOOL, + ) -> HRESULT, + fn ReleaseOwnership() -> (), + fn GetGammaControlCapabilities( + pGammaCaps: *mut DXGI_GAMMA_CONTROL_CAPABILITIES, + ) -> HRESULT, + fn SetGammaControl( + pArray: *const DXGI_GAMMA_CONTROL, + ) -> HRESULT, + fn GetGammaControl( + pArray: *mut DXGI_GAMMA_CONTROL, + ) -> HRESULT, + fn SetDisplaySurface( + pScanoutSurface: *mut IDXGISurface, + ) -> HRESULT, + fn GetDisplaySurfaceData( + pDestination: *mut IDXGISurface, + ) -> HRESULT, + fn GetFrameStatistics( + pStats: *mut DXGI_FRAME_STATISTICS, + ) -> HRESULT, +}} +pub const DXGI_MAX_SWAP_CHAIN_BUFFERS: DWORD = 16; +pub const DXGI_PRESENT_TEST: DWORD = 0x00000001; +pub const DXGI_PRESENT_DO_NOT_SEQUENCE: DWORD = 0x00000002; +pub const DXGI_PRESENT_RESTART: DWORD = 0x00000004; +pub const DXGI_PRESENT_DO_NOT_WAIT: DWORD = 0x00000008; +pub const DXGI_PRESENT_STEREO_PREFER_RIGHT: DWORD = 0x00000010; +pub const DXGI_PRESENT_STEREO_TEMPORARY_MONO: DWORD = 0x00000020; +pub const DXGI_PRESENT_RESTRICT_TO_OUTPUT: DWORD = 0x00000040; +pub const DXGI_PRESENT_USE_DURATION: DWORD = 0x00000100; +pub const DXGI_PRESENT_ALLOW_TEARING: DWORD = 0x00000200; +pub const DXGI_ENUM_MODES_INTERLACED: UINT = 1; +pub const DXGI_ENUM_MODES_SCALING: UINT = 2; +RIDL!{#[uuid(0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8, 0x88, 0x6a)] +interface IDXGISwapChain(IDXGISwapChainVtbl): IDXGIDeviceSubObject(IDXGIDeviceSubObjectVtbl) { + fn Present( + SyncInterval: UINT, + Flags: UINT, + ) -> HRESULT, + fn GetBuffer( + Buffer: UINT, + riid: REFIID, + ppSurface: *mut *mut c_void, + ) -> HRESULT, + fn SetFullscreenState( + Fullscreen: BOOL, + pTarget: *mut IDXGIOutput, + ) -> HRESULT, + fn GetFullscreenState( + pFullscreen: *mut BOOL, + ppTarget: *mut *mut IDXGIOutput, + ) -> HRESULT, + fn GetDesc( + pDesc: *mut DXGI_SWAP_CHAIN_DESC, + ) -> HRESULT, + fn ResizeBuffers( + BufferCount: UINT, + Width: UINT, + Height: UINT, + NewFormat: DXGI_FORMAT, + SwapChainFlags: UINT, + ) -> HRESULT, + fn ResizeTarget( + pNewTargetParameters: *const DXGI_MODE_DESC, + ) -> HRESULT, + fn GetContainingOutput( + ppOutput: *mut *mut IDXGIOutput, + ) -> HRESULT, + fn GetFrameStatistics( + pStats: *mut DXGI_FRAME_STATISTICS, + ) -> HRESULT, + fn GetLastPresentCount( + pLastPresentCount: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69)] +interface IDXGIFactory(IDXGIFactoryVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn EnumAdapters( + Adapter: UINT, + ppAdapter: *mut *mut IDXGIAdapter, + ) -> HRESULT, + fn MakeWindowAssociation( + WindowHandle: HWND, + Flags: UINT, + ) -> HRESULT, + fn GetWindowAssociation( + pWindowHandle: *mut HWND, + ) -> HRESULT, + fn CreateSwapChain( + pDevice: *mut IUnknown, + pDesc: *mut DXGI_SWAP_CHAIN_DESC, + ppSwapChain: *mut *mut IDXGISwapChain, + ) -> HRESULT, + fn CreateSoftwareAdapter( + Module: HMODULE, + ppAdapter: *mut *mut IDXGIAdapter, + ) -> HRESULT, +}} +extern "system" { + pub fn CreateDXGIFactory( + riid: REFIID, + ppFactory: *mut *mut c_void, + ) -> HRESULT; + pub fn CreateDXGIFactory1( + riid: REFIID, + ppFactory: *mut *mut c_void, + ) -> HRESULT; +} +RIDL!{#[uuid(0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c)] +interface IDXGIDevice(IDXGIDeviceVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn GetAdapter( + pAdapter: *mut *mut IDXGIAdapter, + ) -> HRESULT, + fn CreateSurface( + pDesc: *const DXGI_SURFACE_DESC, + NumSurfaces: UINT, + Usage: DXGI_USAGE, + pSharedResource: *const DXGI_SHARED_RESOURCE, + ppSurface: *mut *mut IDXGISurface, + ) -> HRESULT, + fn QueryResourceResidency( + ppResources: *const *mut IUnknown, + pResidencyStatus: *mut DXGI_RESIDENCY, + NumResources: UINT, + ) -> HRESULT, + fn SetGPUThreadPriority( + Priority: INT, + ) -> HRESULT, + fn GetGPUThreadPriority( + pPriority: *mut INT, + ) -> HRESULT, +}} +ENUM!{enum DXGI_ADAPTER_FLAG { + DXGI_ADAPTER_FLAG_NONE, + DXGI_ADAPTER_FLAG_REMOTE, + DXGI_ADAPTER_FLAG_SOFTWARE, +}} +STRUCT!{struct DXGI_ADAPTER_DESC1 { + Description: [WCHAR; 128], + VendorId: UINT, + DeviceId: UINT, + SubSysId: UINT, + Revision: UINT, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, + Flags: UINT, +}} +STRUCT!{struct DXGI_DISPLAY_COLOR_SPACE { + PrimaryCoordinates: [[FLOAT; 2]; 8], + WhitePoints: [[FLOAT; 2]; 16], +}} +RIDL!{#[uuid(0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87)] +interface IDXGIFactory1(IDXGIFactory1Vtbl): IDXGIFactory(IDXGIFactoryVtbl) { + fn EnumAdapters1( + Adapter: UINT, + ppAdapter: *mut *mut IDXGIAdapter1, + ) -> HRESULT, + fn IsCurrent() -> BOOL, +}} +RIDL!{#[uuid(0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05)] +interface IDXGIAdapter1(IDXGIAdapter1Vtbl): IDXGIAdapter(IDXGIAdapterVtbl) { + fn GetDesc1( + pDesc: *mut DXGI_ADAPTER_DESC1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c)] +interface IDXGIDevice1(IDXGIDevice1Vtbl): IDXGIDevice(IDXGIDeviceVtbl) { + fn SetMaximumFrameLatency( + MaxLatency: UINT, + ) -> HRESULT, + fn GetMaximumFrameLatency( + pMaxLatency: *mut UINT, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_IDXGIObject, + 0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a, 0x2e} +DEFINE_GUID!{IID_IDXGIDeviceSubObject, + 0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29, 0x92, 0xf1, 0xa6} +DEFINE_GUID!{IID_IDXGIResource, + 0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96, 0x0b} +DEFINE_GUID!{IID_IDXGIKeyedMutex, + 0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a, 0xf8, 0x5d} +DEFINE_GUID!{IID_IDXGISurface, + 0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60, 0xec} +DEFINE_GUID!{IID_IDXGISurface1, + 0x4ae63092, 0x6327, 0x4c1b, 0x80, 0xae, 0xbf, 0xe1, 0x2e, 0xa3, 0x2b, 0x86} +DEFINE_GUID!{IID_IDXGIAdapter, + 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d, 0xc0} +DEFINE_GUID!{IID_IDXGIOutput, + 0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13, 0xaa} +DEFINE_GUID!{IID_IDXGISwapChain, + 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8, 0x88, 0x6a} +DEFINE_GUID!{IID_IDXGIFactory, + 0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69} +DEFINE_GUID!{IID_IDXGIDevice, + 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c} +DEFINE_GUID!{IID_IDXGIFactory1, + 0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87} +DEFINE_GUID!{IID_IDXGIAdapter1, + 0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05} +DEFINE_GUID!{IID_IDXGIDevice1, + 0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c} diff --git a/winapi/src/shared/dxgi1_2.rs b/winapi/src/shared/dxgi1_2.rs new file mode 100644 index 000000000..941f15e98 --- /dev/null +++ b/winapi/src/shared/dxgi1_2.rs @@ -0,0 +1,355 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi1_2.h +use ctypes::c_void; +use shared::basetsd::SIZE_T; +use shared::dxgi::{ + DXGI_MAPPED_RECT, DXGI_SWAP_EFFECT, IDXGIAdapter1, IDXGIAdapter1Vtbl, IDXGIDevice1, + IDXGIDevice1Vtbl, IDXGIFactory1, IDXGIFactory1Vtbl, IDXGIObject, IDXGIObjectVtbl, IDXGIOutput, + IDXGIOutputVtbl, IDXGIResource, IDXGIResourceVtbl, IDXGISurface1, IDXGISurface1Vtbl, + IDXGISwapChain, IDXGISwapChainVtbl, +}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::{ + DXGI_MODE_DESC, DXGI_MODE_ROTATION, DXGI_MODE_SCALING, DXGI_MODE_SCANLINE_ORDER, DXGI_RATIONAL, + DXGI_RGBA, DXGI_SAMPLE_DESC, DXGI_USAGE, +}; +use shared::guiddef::REFGUID; +use shared::minwindef::{BOOL, DWORD, UINT}; +use shared::windef::{HWND, POINT, RECT}; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LARGE_INTEGER, LPCWSTR, LUID, WCHAR}; +ENUM!{enum DXGI_ALPHA_MODE { + DXGI_ALPHA_MODE_UNSPECIFIED = 0, + DXGI_ALPHA_MODE_PREMULTIPLIED = 1, + DXGI_ALPHA_MODE_STRAIGHT = 2, + DXGI_ALPHA_MODE_IGNORE = 3, + DXGI_ALPHA_MODE_FORCE_DWORD = 0xFFFFFFFF, +}} +ENUM!{enum DXGI_COMPUTE_PREEMPTION_GRANULARITY { + DXGI_COMPUTE_PREEMPTION_DMA_BUFFER_BOUNDARY = 0, + DXGI_COMPUTE_PREEMPTION_DISPATCH_BOUNDARY = 1, + DXGI_COMPUTE_PREEMPTION_THREAD_GROUP_BOUNDARY = 2, + DXGI_COMPUTE_PREEMPTION_THREAD_BOUNDARY = 3, + DXGI_COMPUTE_PREEMPTION_INSTRUCTION_BOUNDARY = 4, +}} +ENUM!{enum DXGI_GRAPHICS_PREEMPTION_GRANULARITY { + DXGI_GRAPHICS_PREEMPTION_DMA_BUFFER_BOUNDARY = 0, + DXGI_GRAPHICS_PREEMPTION_PRIMITIVE_BOUNDARY = 1, + DXGI_GRAPHICS_PREEMPTION_TRIANGLE_BOUNDARY = 2, + DXGI_GRAPHICS_PREEMPTION_PIXEL_BOUNDARY = 3, + DXGI_GRAPHICS_PREEMPTION_INSTRUCTION_BOUNDARY = 4, +}} +ENUM!{enum DXGI_OUTDUPL_POINTER_SHAPE_TYPE { + DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME = 1, + DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR = 2, + DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR = 4, +}} +ENUM!{enum DXGI_SCALING { + DXGI_SCALING_STRETCH = 0, + DXGI_SCALING_NONE = 1, + DXGI_SCALING_ASPECT_RATIO_STRETCH = 2, +}} +ENUM!{enum _DXGI_OFFER_RESOURCE_PRIORITY { + DXGI_OFFER_RESOURCE_PRIORITY_LOW = 1, + DXGI_OFFER_RESOURCE_PRIORITY_NORMAL = 2, + DXGI_OFFER_RESOURCE_PRIORITY_HIGH = 3, +}} +STRUCT!{struct DXGI_ADAPTER_DESC2 { + Description: [WCHAR; 128], + VendorId: UINT, + DeviceId: UINT, + SubSysId: UINT, + Revision: UINT, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, + Flags: UINT, + GraphicsPreemptionGranularity: DXGI_GRAPHICS_PREEMPTION_GRANULARITY, + ComputePreemptionGranularity: DXGI_COMPUTE_PREEMPTION_GRANULARITY, +}} +STRUCT!{struct DXGI_MODE_DESC1 { + Width: UINT, + Height: UINT, + RefreshRate: DXGI_RATIONAL, + Format: DXGI_FORMAT, + ScanlineOrdering: DXGI_MODE_SCANLINE_ORDER, + Scaling: DXGI_MODE_SCALING, + Stereo: BOOL, +}} +STRUCT!{struct DXGI_OUTDUPL_DESC { + ModeDesc: DXGI_MODE_DESC, + Rotation: DXGI_MODE_ROTATION, + DesktopImageInSystemMemory: BOOL, +}} +STRUCT!{struct DXGI_OUTDUPL_FRAME_INFO { + LastPresentTime: LARGE_INTEGER, + LastMouseUpdateTime: LARGE_INTEGER, + AccumulatedFrames: UINT, + RectsCoalesced: BOOL, + ProtectedContentMaskedOut: BOOL, + PointerPosition: DXGI_OUTDUPL_POINTER_POSITION, + TotalMetadataBufferSize: UINT, + PointerShapeBufferSize: UINT, +}} +STRUCT!{struct DXGI_OUTDUPL_MOVE_RECT { + SourcePoint: POINT, + DestinationRect: RECT, +}} +STRUCT!{struct DXGI_OUTDUPL_POINTER_POSITION { + Position: POINT, + Visible: BOOL, +}} +STRUCT!{struct DXGI_OUTDUPL_POINTER_SHAPE_INFO { + Type: UINT, + Width: UINT, + Height: UINT, + Pitch: UINT, + HotSpot: POINT, +}} +STRUCT!{struct DXGI_PRESENT_PARAMETERS { + DirtyRectsCount: UINT, + pDirtyRects: *mut RECT, + pScrollRect: *mut RECT, + pScrollOffset: *mut POINT, +}} +STRUCT!{struct DXGI_SWAP_CHAIN_DESC1 { + Width: UINT, + Height: UINT, + Format: DXGI_FORMAT, + Stereo: BOOL, + SampleDesc: DXGI_SAMPLE_DESC, + BufferUsage: DXGI_USAGE, + BufferCount: UINT, + Scaling: DXGI_SCALING, + SwapEffect: DXGI_SWAP_EFFECT, + AlphaMode: DXGI_ALPHA_MODE, + Flags: UINT, +}} +STRUCT!{struct DXGI_SWAP_CHAIN_FULLSCREEN_DESC { + RefreshRate: DXGI_RATIONAL, + ScanlineOrdering: DXGI_MODE_SCANLINE_ORDER, + Scaling: DXGI_MODE_SCALING, + Windowed: BOOL, +}} +RIDL!{#[uuid(0x0aa1ae0a, 0xfa0e, 0x4b84, 0x86, 0x44, 0xe0, 0x5f, 0xf8, 0xe5, 0xac, 0xb5)] +interface IDXGIAdapter2(IDXGIAdapter2Vtbl): IDXGIAdapter1(IDXGIAdapter1Vtbl) { + fn GetDesc2( + pDesc: *mut DXGI_ADAPTER_DESC2, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6, 0xa9)] +interface IDXGIDevice2(IDXGIDevice2Vtbl): IDXGIDevice1(IDXGIDevice1Vtbl) { + fn OfferResources( + NumResources: UINT, + ppResources: *mut *mut IDXGIResource, + Priority: DXGI_OFFER_RESOURCE_PRIORITY, + ) -> HRESULT, + fn ReclaimResources( + NumResources: UINT, + ppResources: *mut *mut IDXGIResource, + pDiscarded: *mut BOOL, + ) -> HRESULT, + fn EnqueueSetEvent( + hEvent: HANDLE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38, 0xf3, 0x0c)] +interface IDXGIDisplayControl(IDXGIDisplayControlVtbl): IUnknown(IUnknownVtbl) { + fn IsStereoEnabled() -> BOOL, + fn SetStereoEnabled( + enabled: BOOL, + ) -> (), +}} +RIDL!{#[uuid(0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0)] +interface IDXGIFactory2(IDXGIFactory2Vtbl): IDXGIFactory1(IDXGIFactory1Vtbl) { + fn IsWindowedStereoEnabled() -> BOOL, + fn CreateSwapChainForHwnd( + pDevice: *mut IUnknown, + hWnd: HWND, + pDesc: *const DXGI_SWAP_CHAIN_DESC1, + pFullscreenDesc: *const DXGI_SWAP_CHAIN_FULLSCREEN_DESC, + pRestrictToOutput: *mut IDXGIOutput, + ppSwapChain: *mut *mut IDXGISwapChain1, + ) -> HRESULT, + fn CreateSwapChainForCoreWindow( + pDevice: *mut IUnknown, + pWindow: *mut IUnknown, + pDesc: *const DXGI_SWAP_CHAIN_DESC1, + pRestrictToOutput: *mut IDXGIOutput, + ppSwapChain: *mut *mut IDXGISwapChain1, + ) -> HRESULT, + fn GetSharedResourceAdapterLuid( + hResource: HANDLE, + pLuid: *mut LUID, + ) -> HRESULT, + fn RegisterStereoStatusWindow( + WindowHandle: HWND, + wMsg: UINT, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn RegisterStereoStatusEvent( + hEvent: HANDLE, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn UnregisterStereoStatus( + dwCookie: DWORD, + ) -> (), + fn RegisterOcclusionStatusWindow( + WindowHandle: HWND, + wMsg: UINT, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn RegisterOcclusionStatusEvent( + hEvent: HANDLE, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn UnregisterOcclusionStatus( + dwCookie: DWORD, + ) -> (), + fn CreateSwapChainForComposition( + pDevice: *mut IUnknown, + pDesc: *const DXGI_SWAP_CHAIN_DESC1, + pRestrictToOutput: *mut IDXGIOutput, + ppSwapChain: *mut *mut IDXGISwapChain1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66, 0xcc)] +interface IDXGIOutput1(IDXGIOutput1Vtbl): IDXGIOutput(IDXGIOutputVtbl) { + fn GetDisplayModeList1( + EnumFormat: DXGI_FORMAT, + Flags: UINT, + pNumModes: *mut UINT, + pDesc: *mut DXGI_MODE_DESC1, + ) -> HRESULT, + fn FindClosestMatchingMode1( + pModeToMatch: *const DXGI_MODE_DESC1, + pClosestMatch: *mut DXGI_MODE_DESC1, + pConcernedDevice: *mut IUnknown, + ) -> HRESULT, + fn GetDisplaySurfaceData1( + pDestination: *mut IDXGIResource, + ) -> HRESULT, + fn DuplicateOutput( + pDevice: *mut IUnknown, + ppOutputDuplication: *mut *mut IDXGIOutputDuplication, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4, 0x28, 0x31, 0x9c)] +interface IDXGIOutputDuplication(IDXGIOutputDuplicationVtbl): IDXGIObject(IDXGIObjectVtbl) { + fn GetDesc( + pDesc: *mut DXGI_OUTDUPL_DESC, + ) -> (), + fn AcquireNextFrame( + TimeoutInMilliseconds: UINT, + pFrameInfo: *mut DXGI_OUTDUPL_FRAME_INFO, + ppDesktopResource: *mut *mut IDXGIResource, + ) -> HRESULT, + fn GetFrameDirtyRects( + DirtyRectsBufferSize: UINT, + pDirtyRectsBuffer: *mut RECT, + pDirtyRectsBufferSizeRequired: *mut UINT, + ) -> HRESULT, + fn GetFrameMoveRects( + MoveRectsBufferSize: UINT, + pMoveRectBuffer: *mut DXGI_OUTDUPL_MOVE_RECT, + pMoveRectsBufferSizeRequired: *mut UINT, + ) -> HRESULT, + fn GetFramePointerShape( + PointerShapeBufferSize: UINT, + pPointerShapeBuffer: *mut c_void, + pPointerShapeBufferSizeRequired: *mut UINT, + pPointerShapeInfo: *mut DXGI_OUTDUPL_POINTER_SHAPE_INFO, + ) -> HRESULT, + fn MapDesktopSurface( + pLockedRect: *mut DXGI_MAPPED_RECT, + ) -> HRESULT, + fn UnMapDesktopSurface() -> HRESULT, + fn ReleaseFrame() -> HRESULT, +}} +RIDL!{#[uuid(0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e, 0xe0, 0xc1)] +interface IDXGIResource1(IDXGIResource1Vtbl): IDXGIResource(IDXGIResourceVtbl) { + fn CreateSubresourceSurface( + index: UINT, + ppSurface: *mut *mut IDXGISurface2, + ) -> HRESULT, + fn CreateSharedHandle( + pAttributes: *const SECURITY_ATTRIBUTES, + dwAccess: DWORD, + lpName: LPCWSTR, + pHandle: *mut HANDLE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f, 0xa2)] +interface IDXGISurface2(IDXGISurface2Vtbl): IDXGISurface1(IDXGISurface1Vtbl) { + fn GetResource( + riid: REFGUID, + ppParentResource: *mut *mut c_void, + pSubresourceIndex: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6, 0xf4, 0xaa)] +interface IDXGISwapChain1(IDXGISwapChain1Vtbl): IDXGISwapChain(IDXGISwapChainVtbl) { + fn GetDesc1( + pDesc: *mut DXGI_SWAP_CHAIN_DESC1, + ) -> HRESULT, + fn GetFullscreenDesc( + pDesc: *mut DXGI_SWAP_CHAIN_FULLSCREEN_DESC, + ) -> HRESULT, + fn GetHwnd( + pHwnd: *mut HWND, + ) -> HRESULT, + fn GetCoreWindow( + refiid: REFGUID, + ppUnk: *mut *mut c_void, + ) -> HRESULT, + fn Present1( + SyncInterval: UINT, + PresentFlags: UINT, + pPresentParameters: *const DXGI_PRESENT_PARAMETERS, + ) -> HRESULT, + fn IsTemporaryMonoSupported() -> BOOL, + fn GetRestrictToOutput( + ppRestrictToOutput: *mut *mut IDXGIOutput, + ) -> HRESULT, + fn SetBackgroundColor( + pColor: *const DXGI_RGBA, + ) -> HRESULT, + fn GetBackgroundColor( + pColor: *mut DXGI_RGBA, + ) -> HRESULT, + fn SetRotation( + Rotation: DXGI_MODE_ROTATION, + ) -> HRESULT, + fn GetRotation( + pRotation: *mut DXGI_MODE_ROTATION, + ) -> HRESULT, +}} +pub type DXGI_OFFER_RESOURCE_PRIORITY = _DXGI_OFFER_RESOURCE_PRIORITY; +pub const DXGI_ENUM_MODES_DISABLED_STEREO: UINT = 8; +pub const DXGI_ENUM_MODES_STEREO: UINT = 4; +pub const DXGI_SHARED_RESOURCE_READ: UINT = 0x80000000; +pub const DXGI_SHARED_RESOURCE_WRITE: UINT = 1; +DEFINE_GUID!{IID_IDXGIDisplayControl, + 0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38, 0xf3, 0x0c} +DEFINE_GUID!{IID_IDXGIOutputDuplication, + 0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4, 0x28, 0x31, 0x9c} +DEFINE_GUID!{IID_IDXGISurface2, + 0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f, 0xa2} +DEFINE_GUID!{IID_IDXGIResource1, + 0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e, 0xe0, 0xc1} +DEFINE_GUID!{IID_IDXGIDevice2, + 0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6, 0xa9} +DEFINE_GUID!{IID_IDXGISwapChain1, + 0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6, 0xf4, 0xaa} +DEFINE_GUID!{IID_IDXGIFactory2, + 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0} +DEFINE_GUID!{IID_IDXGIAdapter2, + 0x0aa1ae0a, 0xfa0e, 0x4b84, 0x86, 0x44, 0xe0, 0x5f, 0xf8, 0xe5, 0xac, 0xb5} +DEFINE_GUID!{IID_IDXGIOutput1, + 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66, 0xcc} diff --git a/winapi/src/shared/dxgi1_3.rs b/winapi/src/shared/dxgi1_3.rs new file mode 100644 index 000000000..caf346a61 --- /dev/null +++ b/winapi/src/shared/dxgi1_3.rs @@ -0,0 +1,190 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi1_3.h +use ctypes::c_void; +use shared::dxgi::{IDXGIOutput, IDXGIResource}; +use shared::dxgi1_2::{ + DXGI_SWAP_CHAIN_DESC1, IDXGIDevice2, IDXGIDevice2Vtbl, IDXGIFactory2, IDXGIFactory2Vtbl, + IDXGIOutput1, IDXGIOutput1Vtbl, IDXGISwapChain1, IDXGISwapChain1Vtbl, +}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, FLOAT, UINT}; +use shared::windef::RECT; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LARGE_INTEGER}; +ENUM!{enum DXGI_FRAME_PRESENTATION_MODE { + DXGI_FRAME_PRESENTATION_MODE_COMPOSED = 0, + DXGI_FRAME_PRESENTATION_MODE_OVERLAY = 1, + DXGI_FRAME_PRESENTATION_MODE_NONE = 2, + DXGI_FRAME_PRESENTATION_MODE_COMPOSITION_FAILURE = 3, +}} +ENUM!{enum DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAGS { + DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_NOMINAL_RANGE = 0x1, + DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_BT709 = 0x2, + DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAG_xvYCC = 0x4, +}} +ENUM!{enum DXGI_OVERLAY_SUPPORT_FLAG { + DXGI_OVERLAY_SUPPORT_FLAG_DIRECT = 0x1, + DXGI_OVERLAY_SUPPORT_FLAG_SCALING = 0x2, +}} +STRUCT!{struct DXGI_DECODE_SWAP_CHAIN_DESC { + Flags: UINT, +}} +STRUCT!{struct DXGI_FRAME_STATISTICS_MEDIA { + PresentCount: UINT, + PresentRefreshCount: UINT, + SyncRefreshCount: UINT, + SyncQPCTime: LARGE_INTEGER, + SyncGPUTime: LARGE_INTEGER, + CompositionMode: DXGI_FRAME_PRESENTATION_MODE, + ApprovedPresentDuration: UINT, +}} +STRUCT!{struct DXGI_MATRIX_3X2_F { + _11: FLOAT, + _12: FLOAT, + _21: FLOAT, + _22: FLOAT, + _31: FLOAT, + _32: FLOAT, +}} +RIDL!{#[uuid(0x2633066b, 0x4514, 0x4c7a, 0x8f, 0xd8, 0x12, 0xea, 0x98, 0x05, 0x9d, 0x18)] +interface IDXGIDecodeSwapChain(IDXGIDecodeSwapChainVtbl): IUnknown(IUnknownVtbl) { + fn PresentBuffer( + BufferToPresent: UINT, + SyncInterval: UINT, + Flags: UINT, + ) -> HRESULT, + fn SetSourceRect( + pRect: *const RECT, + ) -> HRESULT, + fn SetTargetRect( + pRect: *const RECT, + ) -> HRESULT, + fn SetDestSize( + Width: UINT, + Height: UINT, + ) -> HRESULT, + fn GetSourceRect( + pRect: *mut RECT, + ) -> HRESULT, + fn GetTargetRect( + pRect: *mut RECT, + ) -> HRESULT, + fn GetDestSize( + pWidth: *mut UINT, + pHeight: *mut UINT, + ) -> HRESULT, + fn SetColorSpace( + ColorSpace: DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAGS, + ) -> HRESULT, + fn GetColorSpace() -> DXGI_MULTIPLANE_OVERLAY_YCbCr_FLAGS, +}} +extern "system" { + pub fn CreateDXGIFactory2( + Flags: UINT, + riid: REFIID, + ppFactory: *mut *mut c_void, + ) -> HRESULT; + pub fn DXGIGetDebugInterface1( + Flags: UINT, + riid: REFIID, + pDebug: *mut *mut c_void, + ) -> HRESULT; +} +RIDL!{#[uuid(0x6007896c, 0x3244, 0x4afd, 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23)] +interface IDXGIDevice3(IDXGIDevice3Vtbl): IDXGIDevice2(IDXGIDevice2Vtbl) { + fn Trim() -> (), +}} +RIDL!{#[uuid(0x25483823, 0xcd46, 0x4c7d, 0x86, 0xca, 0x47, 0xaa, 0x95, 0xb8, 0x37, 0xbd)] +interface IDXGIFactory3(IDXGIFactory3Vtbl): IDXGIFactory2(IDXGIFactory2Vtbl) { + fn GetCreationFlags() -> UINT, +}} +RIDL!{#[uuid(0x41e7d1f2, 0xa591, 0x4f7b, 0xa2, 0xe5, 0xfa, 0x9c, 0x84, 0x3e, 0x1c, 0x12)] +interface IDXGIFactoryMedia(IDXGIFactoryMediaVtbl): IUnknown(IUnknownVtbl) { + fn CreateSwapChainForCompositionSurfaceHandle( + pDevice: *mut IUnknown, + hSurface: HANDLE, + pDesc: *const DXGI_SWAP_CHAIN_DESC1, + pRestrictToOutput: *mut IDXGIOutput, + ppSwapChain: *mut *mut IDXGISwapChain1, + ) -> HRESULT, + fn CreateDecodeSwapChainForCompositionSurfaceHandle( + pDevice: *mut IUnknown, + hSurface: HANDLE, + pDesc: *mut DXGI_DECODE_SWAP_CHAIN_DESC, + pYuvDecodeBuffers: *mut IDXGIResource, + pRestrictToOutput: *mut IDXGIOutput, + ppSwapChain: *mut *mut IDXGIDecodeSwapChain, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x595e39d1, 0x2724, 0x4663, 0x99, 0xb1, 0xda, 0x96, 0x9d, 0xe2, 0x83, 0x64)] +interface IDXGIOutput2(IDXGIOutput2Vtbl): IDXGIOutput1(IDXGIOutput1Vtbl) { + fn SupportsOverlays() -> BOOL, +}} +RIDL!{#[uuid(0x8a6bb301, 0x7e7e, 0x41f4, 0xa8, 0xe0, 0x5b, 0x32, 0xf7, 0xf9, 0x9b, 0x18)] +interface IDXGIOutput3(IDXGIOutput3Vtbl): IDXGIOutput2(IDXGIOutput2Vtbl) { + fn CheckOverlaySupport( + EnumFormat: DXGI_FORMAT, + pConcernedDevice: *mut IUnknown, + pFlags: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa8be2ac4, 0x199f, 0x4946, 0xb3, 0x31, 0x79, 0x59, 0x9f, 0xb9, 0x8d, 0xe7)] +interface IDXGISwapChain2(IDXGISwapChain2Vtbl): IDXGISwapChain1(IDXGISwapChain1Vtbl) { + fn SetSourceSize( + Width: UINT, + Height: UINT, + ) -> HRESULT, + fn GetSourceSize( + pWidth: *mut UINT, + pHeight: *mut UINT, + ) -> HRESULT, + fn SetMaximumFrameLatency( + MaxLatency: UINT, + ) -> HRESULT, + fn GetMaximumFrameLatency( + pMaxLatency: *mut UINT, + ) -> HRESULT, + fn GetFrameLatencyWaitableObject() -> HANDLE, + fn SetMatrixTransform( + pMatrix: *const DXGI_MATRIX_3X2_F, + ) -> HRESULT, + fn GetMatrixTransform( + pMatrix: *mut DXGI_MATRIX_3X2_F, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdd95b90b, 0xf05f, 0x4f6a, 0xbd, 0x65, 0x25, 0xbf, 0xb2, 0x64, 0xbd, 0x84)] +interface IDXGISwapChainMedia(IDXGISwapChainMediaVtbl): IUnknown(IUnknownVtbl) { + fn GetFrameStatisticsMedia( + pStats: *mut DXGI_FRAME_STATISTICS_MEDIA, + ) -> HRESULT, + fn SetPresentDuration( + Duration: UINT, + ) -> HRESULT, + fn CheckPresentDurationSupport( + DesiredPresentDuration: UINT, + pClosestSmallerPresentDuration: *mut UINT, + pClosestLargerPresentDuration: *mut UINT, + ) -> HRESULT, +}} +pub const DXGI_CREATE_FACTORY_DEBUG: UINT = 0x1; +DEFINE_GUID!{IID_IDXGIDevice3, + 0x6007896c, 0x3244, 0x4afd, 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23} +DEFINE_GUID!{IID_IDXGISwapChain2, + 0xa8be2ac4, 0x199f, 0x4946, 0xb3, 0x31, 0x79, 0x59, 0x9f, 0xb9, 0x8d, 0xe7} +DEFINE_GUID!{IID_IDXGIOutput2, + 0x595e39d1, 0x2724, 0x4663, 0x99, 0xb1, 0xda, 0x96, 0x9d, 0xe2, 0x83, 0x64} +DEFINE_GUID!{IID_IDXGIFactory3, + 0x25483823, 0xcd46, 0x4c7d, 0x86, 0xca, 0x47, 0xaa, 0x95, 0xb8, 0x37, 0xbd} +DEFINE_GUID!{IID_IDXGIDecodeSwapChain, + 0x2633066b, 0x4514, 0x4c7a, 0x8f, 0xd8, 0x12, 0xea, 0x98, 0x05, 0x9d, 0x18} +DEFINE_GUID!{IID_IDXGIFactoryMedia, + 0x41e7d1f2, 0xa591, 0x4f7b, 0xa2, 0xe5, 0xfa, 0x9c, 0x84, 0x3e, 0x1c, 0x12} +DEFINE_GUID!{IID_IDXGISwapChainMedia, + 0xdd95b90b, 0xf05f, 0x4f6a, 0xbd, 0x65, 0x25, 0xbf, 0xb2, 0x64, 0xbd, 0x84} +DEFINE_GUID!{IID_IDXGIOutput3, + 0x8a6bb301, 0x7e7e, 0x41f4, 0xa8, 0xe0, 0x5b, 0x32, 0xf7, 0xf9, 0x9b, 0x18} diff --git a/winapi/src/shared/dxgi1_4.rs b/winapi/src/shared/dxgi1_4.rs new file mode 100644 index 000000000..53269e88d --- /dev/null +++ b/winapi/src/shared/dxgi1_4.rs @@ -0,0 +1,112 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi1_4.h +use ctypes::c_void; +use shared::basetsd::UINT64; +use shared::dxgi1_2::{IDXGIAdapter2, IDXGIAdapter2Vtbl}; +use shared::dxgi1_3::{ + IDXGIFactory3, IDXGIFactory3Vtbl, IDXGIOutput3, IDXGIOutput3Vtbl, IDXGISwapChain2, + IDXGISwapChain2Vtbl, +}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::DXGI_COLOR_SPACE_TYPE; +use shared::guiddef::REFGUID; +use shared::minwindef::{DWORD, UINT}; +use um::unknwnbase::IUnknown; +use um::winnt::{HANDLE, HRESULT, LUID}; +ENUM!{enum DXGI_MEMORY_SEGMENT_GROUP { + DXGI_MEMORY_SEGMENT_GROUP_LOCAL = 0, + DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL = 1, +}} +ENUM!{enum DXGI_OVERLAY_COLOR_SPACE_SUPPORT_FLAG { + DXGI_OVERLAY_COLOR_SPACE_SUPPORT_FLAG_PRESENT = 0x1, +}} +ENUM!{enum DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG { + DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT = 0x1, + DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_OVERLAY_PRESENT = 0x2, +}} +STRUCT!{struct DXGI_QUERY_VIDEO_MEMORY_INFO { + Budget: UINT64, + CurrentUsage: UINT64, + AvailableForReservation: UINT64, + CurrentReservation: UINT64, +}} +RIDL!{#[uuid(0x645967a4, 0x1392, 0x4310, 0xa7, 0x98, 0x80, 0x53, 0xce, 0x3e, 0x93, 0xfd)] +interface IDXGIAdapter3(IDXGIAdapter3Vtbl): IDXGIAdapter2(IDXGIAdapter2Vtbl) { + fn RegisterHardwareContentProtectionTeardownStatusEvent( + hEvent: HANDLE, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn UnregisterHardwareContentProtectionTeardownStatus( + dwCookie: DWORD, + ) -> (), + fn QueryVideoMemoryInfo( + NodeIndex: UINT, + MemorySegmentGroup: DXGI_MEMORY_SEGMENT_GROUP, + pVideoMemoryInfo: *mut DXGI_QUERY_VIDEO_MEMORY_INFO, + ) -> HRESULT, + fn SetVideoMemoryReservation( + NodeIndex: UINT, + MemorySegmentGroup: DXGI_MEMORY_SEGMENT_GROUP, + Reservation: UINT64, + ) -> HRESULT, + fn RegisterVideoMemoryBudgetChangeNotificationEvent( + hEvent: HANDLE, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn UnregisterVideoMemoryBudgetChangeNotification( + dwCookie: DWORD, + ) -> (), +}} +RIDL!{#[uuid(0x1bc6ea02, 0xef36, 0x464f, 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a)] +interface IDXGIFactory4(IDXGIFactory4Vtbl): IDXGIFactory3(IDXGIFactory3Vtbl) { + fn EnumAdapterByLuid( + AdapterLuid: LUID, + riid: REFGUID, + ppvAdapter: *mut *mut c_void, + ) -> HRESULT, + fn EnumWarpAdapter( + riid: REFGUID, + ppvAdapter: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdc7dca35, 0x2196, 0x414d, 0x9f, 0x53, 0x61, 0x78, 0x84, 0x03, 0x2a, 0x60)] +interface IDXGIOutput4(IDXGIOutput4Vtbl): IDXGIOutput3(IDXGIOutput3Vtbl) { + fn CheckOverlayColorSpaceSupport( + Format: DXGI_FORMAT, + ColorSpace: DXGI_COLOR_SPACE_TYPE, + pConcernedDevice: *mut IUnknown, + pFlags: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1)] +interface IDXGISwapChain3(IDXGISwapChain3Vtbl): IDXGISwapChain2(IDXGISwapChain2Vtbl) { + fn GetCurrentBackBufferIndex() -> UINT, + fn CheckColorSpaceSupport( + ColorSpace: DXGI_COLOR_SPACE_TYPE, + pColorSpaceSupport: *mut UINT, + ) -> HRESULT, + fn SetColorSpace1( + ColorSpace: DXGI_COLOR_SPACE_TYPE, + ) -> HRESULT, + fn ResizeBuffers1( + BufferCount: UINT, + Width: UINT, + Height: UINT, + Format: DXGI_FORMAT, + SwapChainFlags: UINT, + pCreationNodeMask: *const UINT, + ppPresentQueue: *mut *mut IUnknown, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_IDXGISwapChain3, + 0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1} +DEFINE_GUID!{IID_IDXGIOutput4, + 0xdc7dca35, 0x2196, 0x414d, 0x9f, 0x53, 0x61, 0x78, 0x84, 0x03, 0x2a, 0x60} +DEFINE_GUID!{IID_IDXGIFactory4, + 0x1bc6ea02, 0xef36, 0x464f, 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a} +DEFINE_GUID!{IID_IDXGIAdapter3, + 0x645967a4, 0x1392, 0x4310, 0xa7, 0x98, 0x80, 0x53, 0xce, 0x3e, 0x93, 0xfd} diff --git a/winapi/src/shared/dxgi1_5.rs b/winapi/src/shared/dxgi1_5.rs new file mode 100644 index 000000000..a0500a247 --- /dev/null +++ b/winapi/src/shared/dxgi1_5.rs @@ -0,0 +1,92 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi1_5.h +use ctypes::c_void; +use shared::basetsd::UINT16; +use shared::dxgi::IDXGIResource; +use shared::dxgi1_2::{DXGI_OFFER_RESOURCE_PRIORITY, IDXGIOutputDuplication}; +use shared::dxgi1_3::{IDXGIDevice3, IDXGIDevice3Vtbl}; +use shared::dxgi1_4::{ + IDXGIFactory4, IDXGIFactory4Vtbl, IDXGIOutput4, IDXGIOutput4Vtbl, IDXGISwapChain3, + IDXGISwapChain3Vtbl, +}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::minwindef::UINT; +use um::unknwnbase::IUnknown; +use um::winnt::HRESULT; +RIDL!{#[uuid(0x80a07424, 0xab52, 0x42eb, 0x83, 0x3c, 0x0c, 0x42, 0xfd, 0x28, 0x2d, 0x98)] +interface IDXGIOutput5(IDXGIOutput5Vtbl): IDXGIOutput4(IDXGIOutput4Vtbl) { + fn DuplicateOutput1( + pDevice: *mut IUnknown, + Flags: UINT, + SupportedFormatsCount: UINT, + pSupportedFormats: *const DXGI_FORMAT, + ppOutputDuplication: *mut *mut IDXGIOutputDuplication, + )-> HRESULT, +}} +ENUM!{enum DXGI_HDR_METADATA_TYPE { + DXGI_HDR_METADATA_TYPE_NONE = 0, + DXGI_HDR_METADATA_TYPE_HDR10 = 1, +}} +STRUCT!{struct DXGI_HDR_METADATA_HDR10 { + RedPrimary: [UINT16; 2], + GreenPrimary: [UINT16; 2], + BluePrimary: [UINT16; 2], + WhitePoint: [UINT16; 2], + MaxMasteringLuminance: UINT, + MinMasteringLuminance: UINT, + MaxContentLightLevel: UINT16, + MaxFrameAverageLightLevel: UINT16, +}} +RIDL!{#[uuid(0x3d585d5a, 0xbd4a, 0x489e, 0xb1, 0xf4, 0x3d, 0xbc, 0xb6, 0x45, 0x2f, 0xfb)] +interface IDXGISwapChain4(IDXGISwapChain4Vtbl): IDXGISwapChain3(IDXGISwapChain3Vtbl) { + fn SetHDRMetaData( + Type: DXGI_HDR_METADATA_TYPE, + Size: UINT, + pMetaData: *mut c_void, + )-> HRESULT, +}} +ENUM!{enum DXGI_OFFER_RESOURCE_FLAGS { + DXGI_OFFER_RESOURCE_FLAG_ALLOW_DECOMMIT = 0x1, +}} +ENUM!{enum DXGI_RECLAIM_RESOURCE_RESULTS { + DXGI_RECLAIM_RESOURCE_RESULT_OK = 0, + DXGI_RECLAIM_RESOURCE_RESULT_DISCARDED = 1, + DXGI_RECLAIM_RESOURCE_RESULT_NOT_COMMITTED = 2, +}} +RIDL!{#[uuid(0x95b4f95f, 0xd8da, 0x4ca4, 0x9e, 0xe6, 0x3b, 0x76, 0xd5, 0x96, 0x8a, 0x10)] +interface IDXGIDevice4(IDXGIDevice4Vtbl): IDXGIDevice3(IDXGIDevice3Vtbl) { + fn OfferResources1( + NumResources: UINT, + ppResources: *mut *mut IDXGIResource, + Priority: DXGI_OFFER_RESOURCE_PRIORITY, + Flags: UINT, + ) -> HRESULT, + fn ReclaimResources1( + NumResources: UINT, + ppResources: *mut *mut IDXGIResource, + pResults: *mut DXGI_RECLAIM_RESOURCE_RESULTS, + ) -> HRESULT, +}} +ENUM!{enum DXGI_FEATURE { + DXGI_FEATURE_PRESENT_ALLOW_TEARING = 0, +}} +RIDL!{#[uuid(0x7632e1f5, 0xee65, 0x4dca, 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d)] +interface IDXGIFactory5(IDXGIFactory5Vtbl): IDXGIFactory4(IDXGIFactory4Vtbl) { + fn CheckFeatureSupport( + Feature: DXGI_FEATURE, + pFeatureSupportData: *mut c_void, + FeatureSupportDataSize: UINT, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_IDXGIOutput5, + 0x80A07424, 0xAB52, 0x42EB, 0x83, 0x3C, 0x0C, 0x42, 0xFD, 0x28, 0x2D, 0x98} +DEFINE_GUID!{IID_IDXGISwapChain4, + 0x3D585D5A, 0xBD4A, 0x489E, 0xB1, 0xF4, 0x3D, 0xBC, 0xB6, 0x45, 0x2F, 0xFB} +DEFINE_GUID!{IID_IDXGIDevice4, + 0x95B4F95F, 0xD8DA, 0x4CA4, 0x9E, 0xE6, 0x3B, 0x76, 0xD5, 0x96, 0x8A, 0x10} +DEFINE_GUID!{IID_IDXGIFactory5, + 0x7632e1f5, 0xee65, 0x4dca, 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d} diff --git a/winapi/src/shared/dxgi1_6.rs b/winapi/src/shared/dxgi1_6.rs new file mode 100644 index 000000000..30af20519 --- /dev/null +++ b/winapi/src/shared/dxgi1_6.rs @@ -0,0 +1,98 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgi1_6.h +use ctypes::c_void; +use shared::basetsd::SIZE_T; +use shared::dxgi1_2::{ + DXGI_COMPUTE_PREEMPTION_GRANULARITY, DXGI_GRAPHICS_PREEMPTION_GRANULARITY, +}; +use shared::dxgi1_4::{IDXGIAdapter3, IDXGIAdapter3Vtbl}; +use shared::dxgi1_5::{IDXGIFactory5, IDXGIFactory5Vtbl, IDXGIOutput5, IDXGIOutput5Vtbl}; +use shared::dxgitype::{DXGI_COLOR_SPACE_TYPE, DXGI_MODE_ROTATION}; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, FLOAT, UINT}; +use shared::windef::{HMONITOR, RECT}; +use um::winnt::{HRESULT, LUID, WCHAR}; +ENUM!{enum DXGI_ADAPTER_FLAG3 { + DXGI_ADAPTER_FLAG3_NONE = 0, + DXGI_ADAPTER_FLAG3_REMOTE = 1, + DXGI_ADAPTER_FLAG3_SOFTWARE = 2, + DXGI_ADAPTER_FLAG3_ACG_COMPATIBLE = 4, + DXGI_ADAPTER_FLAG3_SUPPORT_MONITORED_FENCES = 8, + DXGI_ADAPTER_FLAG3_SUPPORT_NON_MONITORED_FENCES = 0x10, + DXGI_ADAPTER_FLAG3_KEYED_MUTEX_CONFORMANCE = 0x20, + DXGI_ADAPTER_FLAG3_FORCE_DWORD = 0xFFFFFFFF, +}} +STRUCT!{struct DXGI_ADAPTER_DESC3 { + Description: [WCHAR; 128], + VendorID: UINT, + DeviceID: UINT, + SubSysID: UINT, + Revision: UINT, + DedicatedVideoMemory: SIZE_T, + DedicatedSystemMemory: SIZE_T, + SharedSystemMemory: SIZE_T, + AdapterLuid: LUID, + Flags: DXGI_ADAPTER_FLAG3, + GraphicsPreemptionGranularity: DXGI_GRAPHICS_PREEMPTION_GRANULARITY, + ComputePreemptionGranularity: DXGI_COMPUTE_PREEMPTION_GRANULARITY, +}} +RIDL!{#[uuid(0x3c8d99d1, 0x4fbf, 0x4181, 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e)] +interface IDXGIAdapter4(IDXGIAdapter4Vtbl): IDXGIAdapter3(IDXGIAdapter3Vtbl) { + fn GetDesc3( + pDesc: *mut DXGI_ADAPTER_DESC3, + ) -> HRESULT, +}} +STRUCT!{struct DXGI_OUTPUT_DESC1 { + DeviceName: [WCHAR; 32], + DesktopCoordinates: RECT, + AttachedToDesktop: BOOL, + Rotation: DXGI_MODE_ROTATION, + Monitor: HMONITOR, + BitsPerColor: UINT, + ColorSpace: DXGI_COLOR_SPACE_TYPE, + RedPrimary: [FLOAT; 2], + GreenPrimary: [FLOAT; 2], + BluePrimary: [FLOAT; 2], + WhitePoint: [FLOAT; 2], + MinLuminance: FLOAT, + MaxLuminance: FLOAT, + MaxFullFrameLuminance: FLOAT, +}} +ENUM!{enum DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAGS { + DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN = 1, + DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED = 2, + DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_CURSOR_STRETCHED = 4, +}} +RIDL!{#[uuid(0x068346e8, 0xaaec, 0x4b84, 0xad, 0xd7, 0x13, 0x7f, 0x51, 0x3f, 0x77, 0xa1)] +interface IDXGIOutput6(IDXGIOutput6Vtbl): IDXGIOutput5(IDXGIOutput5Vtbl) { + fn GetDesc1( + pDesc: *mut DXGI_OUTPUT_DESC1, + ) -> HRESULT, + fn CheckHardwareCompositionSupport( + pFlags: *mut UINT, + ) -> HRESULT, +}} +ENUM!{enum DXGI_GPU_PREFERENCE { + DXGI_GPU_PREFERENCE_UNSPECIFIED = 0, + DXGI_GPU_PREFERENCE_MINIMUM_POWER = 1, + DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE = 2, +}} +RIDL!{#[uuid(0xc1b6694f, 0xff09, 0x44a9, 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17)] +interface IDXGIFactory6(IDXGIFactory6Vtbl): IDXGIFactory5(IDXGIFactory5Vtbl) { + fn EnumAdapterByGpuPreference( + Adapter: UINT, + GpuPreference: DXGI_GPU_PREFERENCE, + riid: REFIID, + ppvAdapter: *mut *mut c_void, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_IDXGIAdapter4, + 0x3c8d99d1, 0x4fbf, 0x4181, 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e} +DEFINE_GUID!{IID_IDXGIOutput6, + 0x068346e8, 0xaaec, 0x4b84, 0xad, 0xd7, 0x13, 0x7f, 0x51, 0x3f, 0x77, 0xa1} +DEFINE_GUID!{IID_IDXGIFactory6, + 0xc1b6694f, 0xff09, 0x44a9, 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17} diff --git a/winapi/src/shared/dxgiformat.rs b/winapi/src/shared/dxgiformat.rs new file mode 100644 index 000000000..84cd23fa2 --- /dev/null +++ b/winapi/src/shared/dxgiformat.rs @@ -0,0 +1,127 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgiformat.h +ENUM!{enum DXGI_FORMAT { + DXGI_FORMAT_UNKNOWN = 0, + DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, + DXGI_FORMAT_R32G32B32A32_FLOAT = 2, + DXGI_FORMAT_R32G32B32A32_UINT = 3, + DXGI_FORMAT_R32G32B32A32_SINT = 4, + DXGI_FORMAT_R32G32B32_TYPELESS = 5, + DXGI_FORMAT_R32G32B32_FLOAT = 6, + DXGI_FORMAT_R32G32B32_UINT = 7, + DXGI_FORMAT_R32G32B32_SINT = 8, + DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, + DXGI_FORMAT_R16G16B16A16_FLOAT = 10, + DXGI_FORMAT_R16G16B16A16_UNORM = 11, + DXGI_FORMAT_R16G16B16A16_UINT = 12, + DXGI_FORMAT_R16G16B16A16_SNORM = 13, + DXGI_FORMAT_R16G16B16A16_SINT = 14, + DXGI_FORMAT_R32G32_TYPELESS = 15, + DXGI_FORMAT_R32G32_FLOAT = 16, + DXGI_FORMAT_R32G32_UINT = 17, + DXGI_FORMAT_R32G32_SINT = 18, + DXGI_FORMAT_R32G8X24_TYPELESS = 19, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, + DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, + DXGI_FORMAT_R10G10B10A2_UNORM = 24, + DXGI_FORMAT_R10G10B10A2_UINT = 25, + DXGI_FORMAT_R11G11B10_FLOAT = 26, + DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, + DXGI_FORMAT_R8G8B8A8_UNORM = 28, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, + DXGI_FORMAT_R8G8B8A8_UINT = 30, + DXGI_FORMAT_R8G8B8A8_SNORM = 31, + DXGI_FORMAT_R8G8B8A8_SINT = 32, + DXGI_FORMAT_R16G16_TYPELESS = 33, + DXGI_FORMAT_R16G16_FLOAT = 34, + DXGI_FORMAT_R16G16_UNORM = 35, + DXGI_FORMAT_R16G16_UINT = 36, + DXGI_FORMAT_R16G16_SNORM = 37, + DXGI_FORMAT_R16G16_SINT = 38, + DXGI_FORMAT_R32_TYPELESS = 39, + DXGI_FORMAT_D32_FLOAT = 40, + DXGI_FORMAT_R32_FLOAT = 41, + DXGI_FORMAT_R32_UINT = 42, + DXGI_FORMAT_R32_SINT = 43, + DXGI_FORMAT_R24G8_TYPELESS = 44, + DXGI_FORMAT_D24_UNORM_S8_UINT = 45, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, + DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, + DXGI_FORMAT_R8G8_TYPELESS = 48, + DXGI_FORMAT_R8G8_UNORM = 49, + DXGI_FORMAT_R8G8_UINT = 50, + DXGI_FORMAT_R8G8_SNORM = 51, + DXGI_FORMAT_R8G8_SINT = 52, + DXGI_FORMAT_R16_TYPELESS = 53, + DXGI_FORMAT_R16_FLOAT = 54, + DXGI_FORMAT_D16_UNORM = 55, + DXGI_FORMAT_R16_UNORM = 56, + DXGI_FORMAT_R16_UINT = 57, + DXGI_FORMAT_R16_SNORM = 58, + DXGI_FORMAT_R16_SINT = 59, + DXGI_FORMAT_R8_TYPELESS = 60, + DXGI_FORMAT_R8_UNORM = 61, + DXGI_FORMAT_R8_UINT = 62, + DXGI_FORMAT_R8_SNORM = 63, + DXGI_FORMAT_R8_SINT = 64, + DXGI_FORMAT_A8_UNORM = 65, + DXGI_FORMAT_R1_UNORM = 66, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, + DXGI_FORMAT_R8G8_B8G8_UNORM = 68, + DXGI_FORMAT_G8R8_G8B8_UNORM = 69, + DXGI_FORMAT_BC1_TYPELESS = 70, + DXGI_FORMAT_BC1_UNORM = 71, + DXGI_FORMAT_BC1_UNORM_SRGB = 72, + DXGI_FORMAT_BC2_TYPELESS = 73, + DXGI_FORMAT_BC2_UNORM = 74, + DXGI_FORMAT_BC2_UNORM_SRGB = 75, + DXGI_FORMAT_BC3_TYPELESS = 76, + DXGI_FORMAT_BC3_UNORM = 77, + DXGI_FORMAT_BC3_UNORM_SRGB = 78, + DXGI_FORMAT_BC4_TYPELESS = 79, + DXGI_FORMAT_BC4_UNORM = 80, + DXGI_FORMAT_BC4_SNORM = 81, + DXGI_FORMAT_BC5_TYPELESS = 82, + DXGI_FORMAT_BC5_UNORM = 83, + DXGI_FORMAT_BC5_SNORM = 84, + DXGI_FORMAT_B5G6R5_UNORM = 85, + DXGI_FORMAT_B5G5R5A1_UNORM = 86, + DXGI_FORMAT_B8G8R8A8_UNORM = 87, + DXGI_FORMAT_B8G8R8X8_UNORM = 88, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, + DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, + DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, + DXGI_FORMAT_BC6H_TYPELESS = 94, + DXGI_FORMAT_BC6H_UF16 = 95, + DXGI_FORMAT_BC6H_SF16 = 96, + DXGI_FORMAT_BC7_TYPELESS = 97, + DXGI_FORMAT_BC7_UNORM = 98, + DXGI_FORMAT_BC7_UNORM_SRGB = 99, + DXGI_FORMAT_AYUV = 100, + DXGI_FORMAT_Y410 = 101, + DXGI_FORMAT_Y416 = 102, + DXGI_FORMAT_NV12 = 103, + DXGI_FORMAT_P010 = 104, + DXGI_FORMAT_P016 = 105, + DXGI_FORMAT_420_OPAQUE = 106, + DXGI_FORMAT_YUY2 = 107, + DXGI_FORMAT_Y210 = 108, + DXGI_FORMAT_Y216 = 109, + DXGI_FORMAT_NV11 = 110, + DXGI_FORMAT_AI44 = 111, + DXGI_FORMAT_IA44 = 112, + DXGI_FORMAT_P8 = 113, + DXGI_FORMAT_A8P8 = 114, + DXGI_FORMAT_B4G4R4A4_UNORM = 115, + DXGI_FORMAT_P208 = 130, + DXGI_FORMAT_V208 = 131, + DXGI_FORMAT_V408 = 132, +}} diff --git a/winapi/src/shared/dxgitype.rs b/winapi/src/shared/dxgitype.rs new file mode 100644 index 000000000..d09dccde5 --- /dev/null +++ b/winapi/src/shared/dxgitype.rs @@ -0,0 +1,109 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dxgitype.h +use shared::d3d9types::D3DCOLORVALUE; +use shared::dxgiformat::DXGI_FORMAT; +use shared::minwindef::{BOOL, BYTE, DWORD, UINT}; +pub const DXGI_CPU_ACCESS_NONE: DWORD = 0; +pub const DXGI_CPU_ACCESS_DYNAMIC: DWORD = 1; +pub const DXGI_CPU_ACCESS_READ_WRITE: DWORD = 2; +pub const DXGI_CPU_ACCESS_SCRATCH: DWORD = 3; +pub const DXGI_CPU_ACCESS_FIELD: DWORD = 15; +ENUM!{enum DXGI_USAGE { + DXGI_USAGE_SHADER_INPUT = 1 << (0 + 4), + DXGI_USAGE_RENDER_TARGET_OUTPUT = 1 << (1 + 4), + DXGI_USAGE_BACK_BUFFER = 1 << (2 + 4), + DXGI_USAGE_SHARED = 1 << (3 + 4), + DXGI_USAGE_READ_ONLY = 1 << (4 + 4), + DXGI_USAGE_DISCARD_ON_PRESENT = 1 << (5 + 4), + DXGI_USAGE_UNORDERED_ACCESS = 1 << (6 + 4), +}} +STRUCT!{struct DXGI_RGB { + Red: f32, + Green: f32, + Blue: f32, +}} +pub type DXGI_RGBA = D3DCOLORVALUE; +STRUCT!{struct DXGI_GAMMA_CONTROL { + Scale: DXGI_RGB, + Offset: DXGI_RGB, + GammaCurve: [DXGI_RGB; 1025], +}} +STRUCT!{struct DXGI_GAMMA_CONTROL_CAPABILITIES { + ScaleAndOffsetSupported: BOOL, + MaxConvertedValue: f32, + MinConvertedValue: f32, + NumGammaControlPoints: UINT, + ControlPointPositions: [f32; 1025], +}} +STRUCT!{struct DXGI_RATIONAL { + Numerator: UINT, + Denominator: UINT, +}} +ENUM!{enum DXGI_MODE_SCANLINE_ORDER { + DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, + DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE, + DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST, + DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST, +}} +ENUM!{enum DXGI_MODE_SCALING { + DXGI_MODE_SCALING_UNSPECIFIED, + DXGI_MODE_SCALING_CENTERED, + DXGI_MODE_SCALING_STRETCHED, +}} +ENUM!{enum DXGI_MODE_ROTATION { + DXGI_MODE_ROTATION_UNSPECIFIED, + DXGI_MODE_ROTATION_IDENTITY, + DXGI_MODE_ROTATION_ROTATE90, + DXGI_MODE_ROTATION_ROTATE180, + DXGI_MODE_ROTATION_ROTATE270, +}} +STRUCT!{struct DXGI_MODE_DESC { + Width: UINT, + Height: UINT, + RefreshRate: DXGI_RATIONAL, + Format: DXGI_FORMAT, + ScanlineOrdering: DXGI_MODE_SCANLINE_ORDER, + Scaling: DXGI_MODE_SCALING, +}} +STRUCT!{struct DXGI_SAMPLE_DESC { + Count: UINT, + Quality: UINT, +}} +STRUCT!{struct DXGI_JPEG_DC_HUFFMAN_TABLE { + CodeCounts: [BYTE; 12], + CodeValues: [BYTE; 12], +}} +STRUCT!{struct DXGI_JPEG_AC_HUFFMAN_TABLE { + CodeCounts: [BYTE; 16], + CodeValues: [BYTE; 162], +}} +STRUCT!{struct DXGI_JPEG_QUANTIZATION_TABLE { + Elements: [BYTE; 64], +}} +ENUM!{enum DXGI_COLOR_SPACE_TYPE { + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0, + DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1, + DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2, + DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3, + DXGI_COLOR_SPACE_RESERVED = 4, + DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6, + DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8, + DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10, + DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13, + DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 14, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15, + DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16, + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17, + DXGI_COLOR_SPACE_CUSTOM = 0xFFFFFFFF, +}} +pub const DXGI_CENTER_MULTISAMPLE_QUALITY_PATTERN: UINT = 0xfffffffe; +pub const DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN: UINT = 0xffffffff; diff --git a/winapi/src/shared/evntprov.rs b/winapi/src/shared/evntprov.rs new file mode 100644 index 000000000..455ff5d29 --- /dev/null +++ b/winapi/src/shared/evntprov.rs @@ -0,0 +1,309 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{SIZE_T, ULONG64}; +use shared::guiddef::{LPCGUID, LPGUID}; +use shared::minwindef::{UCHAR, ULONG, USHORT}; +use um::winnt::{ANYSIZE_ARRAY, BOOLEAN, PCWSTR, PVOID, ULONGLONG, VOID}; +pub const EVENT_MIN_LEVEL: UCHAR = 0; +pub const EVENT_MAX_LEVEL: UCHAR = 0xff; +pub const EVENT_ACTIVITY_CTRL_GET_ID: ULONG = 1; +pub const EVENT_ACTIVITY_CTRL_SET_ID: ULONG = 2; +pub const EVENT_ACTIVITY_CTRL_CREATE_ID: ULONG = 3; +pub const EVENT_ACTIVITY_CTRL_GET_SET_ID: ULONG = 4; +pub const EVENT_ACTIVITY_CTRL_CREATE_SET_ID: ULONG = 5; +pub const MAX_EVENT_DATA_DESCRIPTORS: SIZE_T = 128; +pub const MAX_EVENT_FILTER_DATA_SIZE: SIZE_T = 1024; +pub const MAX_EVENT_FILTER_PAYLOAD_SIZE: SIZE_T = 4096; +pub const MAX_EVENT_FILTER_EVENT_NAME_SIZE: SIZE_T = 4096; +pub const MAX_EVENT_FILTERS_COUNT: SIZE_T = 8; +pub const MAX_EVENT_FILTER_PID_COUNT: SIZE_T = 8; +pub const MAX_EVENT_FILTER_EVENT_ID_COUNT: SIZE_T = 64; +pub const EVENT_FILTER_TYPE_NONE: ULONG = 0x00000000; +pub const EVENT_FILTER_TYPE_SCHEMATIZED: ULONG = 0x80000000; +pub const EVENT_FILTER_TYPE_SYSTEM_FLAGS: ULONG = 0x80000001; +pub const EVENT_FILTER_TYPE_TRACEHANDLE: ULONG = 0x80000002; +pub const EVENT_FILTER_TYPE_PID: ULONG = 0x80000004; +pub const EVENT_FILTER_TYPE_EXECUTABLE_NAME: ULONG = 0x80000008; +pub const EVENT_FILTER_TYPE_PACKAGE_ID: ULONG = 0x80000010; +pub const EVENT_FILTER_TYPE_PACKAGE_APP_ID: ULONG = 0x80000020; +pub const EVENT_FILTER_TYPE_PAYLOAD: ULONG = 0x80000100; +pub const EVENT_FILTER_TYPE_EVENT_ID: ULONG = 0x80000200; +pub const EVENT_FILTER_TYPE_EVENT_NAME: ULONG = 0x80000400; +pub const EVENT_FILTER_TYPE_STACKWALK: ULONG = 0x80001000; +pub const EVENT_FILTER_TYPE_STACKWALK_NAME: ULONG = 0x80001000; +pub const EVENT_FILTER_TYPE_STACKWALK_LEVEL_KW: ULONG = 0x80004000; +pub const EVENT_DATA_DESCRIPTOR_TYPE_NONE: UCHAR = 0; +pub const EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA: UCHAR = 1; +pub const EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA: UCHAR = 2; +pub const EVENT_DATA_DESCRIPTOR_TYPE_TIMESTAMP_OVERRIDE: UCHAR = 3; +pub const EVENT_WRITE_FLAG_NO_FAULTING: ULONG = 0x00000001; +pub const EVENT_WRITE_FLAG_INPRIVATE: ULONG = 0x00000002; +pub type REGHANDLE = ULONGLONG; +pub type PREGHANDLE = *mut REGHANDLE; +STRUCT!{struct EVENT_DATA_DESCRIPTOR_u_s { + Type: UCHAR, + Reserved1: UCHAR, + Reserved2: USHORT, +}} +UNION!{union EVENT_DATA_DESCRIPTOR_u { + [u32; 1], + Reserved Reserved_mut: ULONG, + s s_mut: EVENT_DATA_DESCRIPTOR_u_s, +}} +STRUCT!{struct EVENT_DATA_DESCRIPTOR { + Ptr: ULONGLONG, + Size: ULONG, + u: EVENT_DATA_DESCRIPTOR_u, +}} +pub type PEVENT_DATA_DESCRIPTOR = *mut EVENT_DATA_DESCRIPTOR; +STRUCT!{struct EVENT_DESCRIPTOR { + Id: USHORT, + Version: UCHAR, + Channel: UCHAR, + Level: UCHAR, + Opcode: UCHAR, + Task: USHORT, + Keyword: ULONGLONG, +}} +pub type PEVENT_DESCRIPTOR = *mut EVENT_DESCRIPTOR; +pub type PCEVENT_DESCRIPTOR = *const EVENT_DESCRIPTOR; +STRUCT!{struct EVENT_FILTER_DESCRIPTOR { + Ptr: ULONGLONG, + Size: ULONG, + Type: ULONG, +}} +pub type PEVENT_FILTER_DESCRIPTOR = *mut EVENT_FILTER_DESCRIPTOR; +STRUCT!{struct EVENT_FILTER_HEADER { + Id: USHORT, + Version: UCHAR, + Reserved: [UCHAR; 5], + InstanceId: ULONGLONG, + Size: ULONG, + NextOffset: ULONG, +}} +pub type PEVENT_FILTER_HEADER = *mut EVENT_FILTER_HEADER; +STRUCT!{struct EVENT_FILTER_EVENT_ID { + FilterIn: BOOLEAN, + Reserved: UCHAR, + Count: USHORT, + Events: [USHORT; ANYSIZE_ARRAY], +}} +pub type PEVENT_FILTER_EVENT_ID = *mut EVENT_FILTER_EVENT_ID; +STRUCT!{struct EVENT_FILTER_EVENT_NAME { + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, + Level: UCHAR, + FilterIn: BOOLEAN, + NameCount: USHORT, + Names: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PEVENT_FILTER_EVENT_NAME = *mut EVENT_FILTER_EVENT_NAME; +STRUCT!{struct EVENT_FILTER_LEVEL_KW { + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, + Level: UCHAR, + FilterIn: BOOLEAN, +}} +ENUM!{enum EVENT_INFO_CLASS { + EventProviderBinaryTrackInfo, + EventProviderSetReserved1, + EventProviderSetTraits, + EventProviderUseDescriptorType, + MaxEventInfo, +}} +FN!{stdcall PENABLECALLBACK( + SourceId: LPCGUID, + IsEnabled: ULONG, + Level: UCHAR, + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, + FilterData: PEVENT_FILTER_DESCRIPTOR, + CallbackContext: PVOID, +) -> ()} +extern "system" { + pub fn EventRegister( + ProviderId: LPCGUID, + EnableCallback: PENABLECALLBACK, + CallbackContext: PVOID, + RegHandle: PREGHANDLE, + ) -> ULONG; + pub fn EventUnregister( + RegHandle: REGHANDLE, + ) -> ULONG; + pub fn EventSetInformation( + RegHandle: REGHANDLE, + InformationClass: EVENT_INFO_CLASS, + EventInformation: PVOID, + InformationLength: ULONG, + ) -> ULONG; + pub fn EventEnabled( + RegHandle: REGHANDLE, + EventDescriptor: PCEVENT_DESCRIPTOR, + ) -> BOOLEAN; + pub fn EventProviderEnabled( + RegHandle: REGHANDLE, + Level: UCHAR, + Keyword: ULONGLONG, + ) -> BOOLEAN; + pub fn EventWrite( + RegHandle: REGHANDLE, + EventDescriptor: PCEVENT_DESCRIPTOR, + UserDataCount: ULONG, + UserData: PEVENT_DATA_DESCRIPTOR, + ) -> ULONG; + pub fn EventWriteTransfer( + RegHandle: REGHANDLE, + EventDescriptor: PCEVENT_DESCRIPTOR, + ActivityId: LPCGUID, + RelatedActivityId: LPCGUID, + UserDataCount: ULONG, + UserData: PEVENT_DATA_DESCRIPTOR, + ) -> ULONG; + pub fn EventWriteEx( + RegHandle: REGHANDLE, + EventDescriptor: PCEVENT_DESCRIPTOR, + Filter: ULONG64, + Flags: ULONG, + ActivityId: LPCGUID, + RelatedActivityId: LPCGUID, + UserDataCount: ULONG, + UserData: PEVENT_DATA_DESCRIPTOR, + ) -> ULONG; + pub fn EventWriteString( + RegHandle: REGHANDLE, + Level: UCHAR, + Keyword: ULONGLONG, + EventString: PCWSTR, + ) -> ULONG; + pub fn EventActivityIdControl( + ControlCode: ULONG, + ActivityId: LPGUID, + ) -> ULONG; +} +#[inline] +pub unsafe fn EventDataDescCreate( + EventDataDescriptor: PEVENT_DATA_DESCRIPTOR, + DataPtr: *const VOID, + DataSize: ULONG, +) { + (*EventDataDescriptor).Ptr = DataPtr as ULONGLONG; + (*EventDataDescriptor).Size = DataSize; + *(*EventDataDescriptor).u.Reserved_mut() = 0; +} +#[inline] +pub unsafe fn EventDescCreate( + EventDescriptor: PEVENT_DESCRIPTOR, + Id: USHORT, + Version: UCHAR, + Channel: UCHAR, + Level: UCHAR, + Task: USHORT, + Opcode: UCHAR, + Keyword: ULONGLONG, +) { + (*EventDescriptor).Id = Id; + (*EventDescriptor).Version = Version; + (*EventDescriptor).Channel = Channel; + (*EventDescriptor).Level = Level; + (*EventDescriptor).Task = Task; + (*EventDescriptor).Opcode = Opcode; + (*EventDescriptor).Keyword = Keyword; +} +#[inline] +pub unsafe fn EventDescZero(EventDescriptor: PEVENT_DESCRIPTOR) { + use core::ptr::write_bytes; + // FIXME: 16 = sizeof::<EVENT_DESCRIPTOR>() + write_bytes(EventDescriptor, 0, 16); +} +#[inline] +pub unsafe fn EventDescGetId(EventDescriptor: PCEVENT_DESCRIPTOR) -> USHORT { + (*EventDescriptor).Id +} +#[inline] +pub unsafe fn EventDescGetVersion(EventDescriptor: PCEVENT_DESCRIPTOR) -> UCHAR { + (*EventDescriptor).Version +} +#[inline] +pub unsafe fn EventDescGetTask(EventDescriptor: PCEVENT_DESCRIPTOR) -> USHORT { + (*EventDescriptor).Task +} +#[inline] +pub unsafe fn EventDescGetOpcode(EventDescriptor: PCEVENT_DESCRIPTOR) -> UCHAR { + (*EventDescriptor).Opcode +} +#[inline] +pub unsafe fn EventDescGetChannel(EventDescriptor: PCEVENT_DESCRIPTOR) -> UCHAR { + (*EventDescriptor).Channel +} +#[inline] +pub unsafe fn EventDescGetLevel(EventDescriptor: PCEVENT_DESCRIPTOR) -> UCHAR { + (*EventDescriptor).Level +} +#[inline] +pub unsafe fn EventDescGetKeyword(EventDescriptor: PCEVENT_DESCRIPTOR) -> ULONGLONG { + (*EventDescriptor).Keyword +} +#[inline] +pub unsafe fn EventDescSetId(EventDescriptor: PEVENT_DESCRIPTOR, Id: USHORT) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Id = Id; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetVersion( + EventDescriptor: PEVENT_DESCRIPTOR, + Version: UCHAR, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Version = Version; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetTask( + EventDescriptor: PEVENT_DESCRIPTOR, + Task: USHORT, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Task = Task; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetOpcode( + EventDescriptor: PEVENT_DESCRIPTOR, + Opcode: UCHAR, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Opcode = Opcode; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetLevel( + EventDescriptor: PEVENT_DESCRIPTOR, + Level: UCHAR, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Level = Level; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetChannel( + EventDescriptor: PEVENT_DESCRIPTOR, + Channel: UCHAR, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Channel = Channel; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescSetKeyword( + EventDescriptor: PEVENT_DESCRIPTOR, + Keyword: ULONGLONG, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Keyword = Keyword; + EventDescriptor +} +#[inline] +pub unsafe fn EventDescOrKeyword( + EventDescriptor: PEVENT_DESCRIPTOR, + Keyword: ULONGLONG, +) -> PEVENT_DESCRIPTOR { + (*EventDescriptor).Keyword |= Keyword; + EventDescriptor +} diff --git a/winapi/src/shared/evntrace.rs b/winapi/src/shared/evntrace.rs new file mode 100644 index 000000000..23a93eec3 --- /dev/null +++ b/winapi/src/shared/evntrace.rs @@ -0,0 +1,990 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{SIZE_T, ULONG32, ULONG64}; +use shared::evntprov::PEVENT_FILTER_DESCRIPTOR; +use shared::guiddef::{GUID, LPCGUID, LPGUID}; +use shared::minwindef::{DWORD, LPFILETIME, PULONG, UCHAR, UINT, ULONG, USHORT}; +use shared::wmistr::{WMIDPREQUESTCODE, WNODE_HEADER}; +use um::evntcons::PEVENT_RECORD; +use um::handleapi::INVALID_HANDLE_VALUE; +use um::timezoneapi::TIME_ZONE_INFORMATION; +use um::winnt::{ + ANYSIZE_ARRAY, BOOLEAN, HANDLE, LARGE_INTEGER, LONG, LONGLONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, + PVOID, ULONGLONG, WCHAR +}; +use vc::vadefs::va_list; +DEFINE_GUID!{EventTraceGuid, + 0x68fdd900, 0x4a3e, 0x11d1, 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3} +DEFINE_GUID!{SystemTraceControlGuid, + 0x9e814aad, 0x3204, 0x11d2, 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39} +DEFINE_GUID!{EventTraceConfigGuid, + 0x01853a65, 0x418f, 0x4f36, 0xae, 0xfc, 0xdc, 0x0f, 0x1d, 0x2f, 0xd2, 0x35} +DEFINE_GUID!{DefaultTraceSecurityGuid, + 0x0811c1af, 0x7a07, 0x4a06, 0x82, 0xed, 0x86, 0x94, 0x55, 0xcd, 0xf7, 0x13} +DEFINE_GUID!{PrivateLoggerNotificationGuid, + 0x3595ab5c, 0x042a, 0x4c8e, 0xb9, 0x42, 0x2d, 0x05, 0x9b, 0xfe, 0xb1, 0xb1} +pub const KERNEL_LOGGER_NAME: &'static str = "NT Kernel Logger"; +pub const GLOBAL_LOGGER_NAME: &'static str = "GlobalLogger"; +pub const EVENT_LOGGER_NAME: &'static str = "EventLog"; +pub const DIAG_LOGGER_NAME: &'static str = "DiagLog"; +pub const MAX_MOF_FIELDS: SIZE_T = 16; +DECLARE_HANDLE!{TRACEHANDLE, __TRACEHANDLE} +pub type PTRACEHANDLE = *mut TRACEHANDLE; +pub const EVENT_TRACE_TYPE_INFO: DWORD = 0x00; +pub const EVENT_TRACE_TYPE_START: DWORD = 0x01; +pub const EVENT_TRACE_TYPE_END: DWORD = 0x02; +pub const EVENT_TRACE_TYPE_STOP: DWORD = 0x02; +pub const EVENT_TRACE_TYPE_DC_START: DWORD = 0x03; +pub const EVENT_TRACE_TYPE_DC_END: DWORD = 0x04; +pub const EVENT_TRACE_TYPE_EXTENSION: DWORD = 0x05; +pub const EVENT_TRACE_TYPE_REPLY: DWORD = 0x06; +pub const EVENT_TRACE_TYPE_DEQUEUE: DWORD = 0x07; +pub const EVENT_TRACE_TYPE_RESUME: DWORD = 0x07; +pub const EVENT_TRACE_TYPE_CHECKPOINT: DWORD = 0x08; +pub const EVENT_TRACE_TYPE_SUSPEND: DWORD = 0x08; +pub const EVENT_TRACE_TYPE_WINEVT_SEND: DWORD = 0x09; +pub const EVENT_TRACE_TYPE_WINEVT_RECEIVE: DWORD = 0xF0; +pub const TRACE_LEVEL_CRITICAL: UCHAR = 1; +pub const TRACE_LEVEL_ERROR: UCHAR = 2; +pub const TRACE_LEVEL_WARNING: UCHAR = 3; +pub const TRACE_LEVEL_INFORMATION: UCHAR = 4; +pub const TRACE_LEVEL_VERBOSE: UCHAR = 5; +pub const TRACE_LEVEL_RESERVED6: UCHAR = 6; +pub const TRACE_LEVEL_RESERVED7: UCHAR = 7; +pub const TRACE_LEVEL_RESERVED8: UCHAR = 8; +pub const TRACE_LEVEL_RESERVED9: UCHAR = 9; +pub const EVENT_TRACE_TYPE_LOAD: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_TERMINATE: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_IO_READ: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_IO_WRITE: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_IO_READ_INIT: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_IO_WRITE_INIT: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_IO_FLUSH: DWORD = 0x0E; +pub const EVENT_TRACE_TYPE_IO_FLUSH_INIT: DWORD = 0x0F; +pub const EVENT_TRACE_TYPE_IO_REDIRECTED_INIT: DWORD = 0x10; +pub const EVENT_TRACE_TYPE_MM_TF: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_MM_DZF: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_MM_COW: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_MM_GPF: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_MM_HPF: DWORD = 0x0E; +pub const EVENT_TRACE_TYPE_MM_AV: DWORD = 0x0F; +pub const EVENT_TRACE_TYPE_SEND: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_RECEIVE: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_CONNECT: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_DISCONNECT: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_RETRANSMIT: DWORD = 0x0E; +pub const EVENT_TRACE_TYPE_ACCEPT: DWORD = 0x0F; +pub const EVENT_TRACE_TYPE_RECONNECT: DWORD = 0x10; +pub const EVENT_TRACE_TYPE_CONNFAIL: DWORD = 0x11; +pub const EVENT_TRACE_TYPE_COPY_TCP: DWORD = 0x12; +pub const EVENT_TRACE_TYPE_COPY_ARP: DWORD = 0x13; +pub const EVENT_TRACE_TYPE_ACKFULL: DWORD = 0x14; +pub const EVENT_TRACE_TYPE_ACKPART: DWORD = 0x15; +pub const EVENT_TRACE_TYPE_ACKDUP: DWORD = 0x16; +pub const EVENT_TRACE_TYPE_GUIDMAP: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_CONFIG: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_SIDINFO: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_SECURITY: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_DBGID_RSDS: DWORD = 0x40; +pub const EVENT_TRACE_TYPE_REGCREATE: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_REGOPEN: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_REGDELETE: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_REGQUERY: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_REGSETVALUE: DWORD = 0x0E; +pub const EVENT_TRACE_TYPE_REGDELETEVALUE: DWORD = 0x0F; +pub const EVENT_TRACE_TYPE_REGQUERYVALUE: DWORD = 0x10; +pub const EVENT_TRACE_TYPE_REGENUMERATEKEY: DWORD = 0x11; +pub const EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY: DWORD = 0x12; +pub const EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE: DWORD = 0x13; +pub const EVENT_TRACE_TYPE_REGSETINFORMATION: DWORD = 0x14; +pub const EVENT_TRACE_TYPE_REGFLUSH: DWORD = 0x15; +pub const EVENT_TRACE_TYPE_REGKCBCREATE: DWORD = 0x16; +pub const EVENT_TRACE_TYPE_REGKCBDELETE: DWORD = 0x17; +pub const EVENT_TRACE_TYPE_REGKCBRUNDOWNBEGIN: DWORD = 0x18; +pub const EVENT_TRACE_TYPE_REGKCBRUNDOWNEND: DWORD = 0x19; +pub const EVENT_TRACE_TYPE_REGVIRTUALIZE: DWORD = 0x1A; +pub const EVENT_TRACE_TYPE_REGCLOSE: DWORD = 0x1B; +pub const EVENT_TRACE_TYPE_REGSETSECURITY: DWORD = 0x1C; +pub const EVENT_TRACE_TYPE_REGQUERYSECURITY: DWORD = 0x1D; +pub const EVENT_TRACE_TYPE_REGCOMMIT: DWORD = 0x1E; +pub const EVENT_TRACE_TYPE_REGPREPARE: DWORD = 0x1F; +pub const EVENT_TRACE_TYPE_REGROLLBACK: DWORD = 0x20; +pub const EVENT_TRACE_TYPE_REGMOUNTHIVE: DWORD = 0x21; +pub const EVENT_TRACE_TYPE_CONFIG_CPU: DWORD = 0x0A; +pub const EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK: DWORD = 0x0B; +pub const EVENT_TRACE_TYPE_CONFIG_LOGICALDISK: DWORD = 0x0C; +pub const EVENT_TRACE_TYPE_CONFIG_NIC: DWORD = 0x0D; +pub const EVENT_TRACE_TYPE_CONFIG_VIDEO: DWORD = 0x0E; +pub const EVENT_TRACE_TYPE_CONFIG_SERVICES: DWORD = 0x0F; +pub const EVENT_TRACE_TYPE_CONFIG_POWER: DWORD = 0x10; +pub const EVENT_TRACE_TYPE_CONFIG_NETINFO: DWORD = 0x11; +pub const EVENT_TRACE_TYPE_CONFIG_OPTICALMEDIA: DWORD = 0x12; +pub const EVENT_TRACE_TYPE_CONFIG_IRQ: DWORD = 0x15; +pub const EVENT_TRACE_TYPE_CONFIG_PNP: DWORD = 0x16; +pub const EVENT_TRACE_TYPE_CONFIG_IDECHANNEL: DWORD = 0x17; +pub const EVENT_TRACE_TYPE_CONFIG_NUMANODE: DWORD = 0x18; +pub const EVENT_TRACE_TYPE_CONFIG_PLATFORM: DWORD = 0x19; +pub const EVENT_TRACE_TYPE_CONFIG_PROCESSORGROUP: DWORD = 0x1A; +pub const EVENT_TRACE_TYPE_CONFIG_PROCESSORNUMBER: DWORD = 0x1B; +pub const EVENT_TRACE_TYPE_CONFIG_DPI: DWORD = 0x1C; +pub const EVENT_TRACE_TYPE_CONFIG_CI_INFO: DWORD = 0x1D; +pub const EVENT_TRACE_TYPE_CONFIG_MACHINEID: DWORD = 0x1E; +pub const EVENT_TRACE_TYPE_CONFIG_DEFRAG: DWORD = 0x1F; +pub const EVENT_TRACE_TYPE_CONFIG_MOBILEPLATFORM: DWORD = 0x20; +pub const EVENT_TRACE_TYPE_CONFIG_DEVICEFAMILY: DWORD = 0x21; +pub const EVENT_TRACE_TYPE_CONFIG_FLIGHTID: DWORD = 0x22; +pub const EVENT_TRACE_TYPE_CONFIG_PROCESSOR: DWORD = 0x23; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_READ: DWORD = 0x37; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_WRITE: DWORD = 0x38; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_FLUSH: DWORD = 0x39; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_READ_INIT: DWORD = 0x3a; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_WRITE_INIT: DWORD = 0x3b; +pub const EVENT_TRACE_TYPE_OPTICAL_IO_FLUSH_INIT: DWORD = 0x3c; +pub const EVENT_TRACE_TYPE_FLT_PREOP_INIT: DWORD = 0x60; +pub const EVENT_TRACE_TYPE_FLT_POSTOP_INIT: DWORD = 0x61; +pub const EVENT_TRACE_TYPE_FLT_PREOP_COMPLETION: DWORD = 0x62; +pub const EVENT_TRACE_TYPE_FLT_POSTOP_COMPLETION: DWORD = 0x63; +pub const EVENT_TRACE_TYPE_FLT_PREOP_FAILURE: DWORD = 0x64; +pub const EVENT_TRACE_TYPE_FLT_POSTOP_FAILURE: DWORD = 0x65; +pub const EVENT_TRACE_FLAG_PROCESS: DWORD = 0x00000001; +pub const EVENT_TRACE_FLAG_THREAD: DWORD = 0x00000002; +pub const EVENT_TRACE_FLAG_IMAGE_LOAD: DWORD = 0x00000004; +pub const EVENT_TRACE_FLAG_DISK_IO: DWORD = 0x00000100; +pub const EVENT_TRACE_FLAG_DISK_FILE_IO: DWORD = 0x00000200; +pub const EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS: DWORD = 0x00001000; +pub const EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS: DWORD = 0x00002000; +pub const EVENT_TRACE_FLAG_NETWORK_TCPIP: DWORD = 0x00010000; +pub const EVENT_TRACE_FLAG_REGISTRY: DWORD = 0x00020000; +pub const EVENT_TRACE_FLAG_DBGPRINT: DWORD = 0x00040000; +pub const EVENT_TRACE_FLAG_PROCESS_COUNTERS: DWORD = 0x00000008; +pub const EVENT_TRACE_FLAG_CSWITCH: DWORD = 0x00000010; +pub const EVENT_TRACE_FLAG_DPC: DWORD = 0x00000020; +pub const EVENT_TRACE_FLAG_INTERRUPT: DWORD = 0x00000040; +pub const EVENT_TRACE_FLAG_SYSTEMCALL: DWORD = 0x00000080; +pub const EVENT_TRACE_FLAG_DISK_IO_INIT: DWORD = 0x00000400; +pub const EVENT_TRACE_FLAG_ALPC: DWORD = 0x00100000; +pub const EVENT_TRACE_FLAG_SPLIT_IO: DWORD = 0x00200000; +pub const EVENT_TRACE_FLAG_DRIVER: DWORD = 0x00800000; +pub const EVENT_TRACE_FLAG_PROFILE: DWORD = 0x01000000; +pub const EVENT_TRACE_FLAG_FILE_IO: DWORD = 0x02000000; +pub const EVENT_TRACE_FLAG_FILE_IO_INIT: DWORD = 0x04000000; +pub const EVENT_TRACE_FLAG_DISPATCHER: DWORD = 0x00000800; +pub const EVENT_TRACE_FLAG_VIRTUAL_ALLOC: DWORD = 0x00004000; +pub const EVENT_TRACE_FLAG_VAMAP: DWORD = 0x00008000; +pub const EVENT_TRACE_FLAG_NO_SYSCONFIG: DWORD = 0x10000000; +pub const EVENT_TRACE_FLAG_JOB: DWORD = 0x00080000; +pub const EVENT_TRACE_FLAG_DEBUG_EVENTS: DWORD = 0x00400000; +pub const EVENT_TRACE_FLAG_EXTENSION: DWORD = 0x80000000; +pub const EVENT_TRACE_FLAG_FORWARD_WMI: DWORD = 0x40000000; +pub const EVENT_TRACE_FLAG_ENABLE_RESERVE: DWORD = 0x20000000; +pub const EVENT_TRACE_FILE_MODE_NONE: DWORD = 0x00000000; +pub const EVENT_TRACE_FILE_MODE_SEQUENTIAL: DWORD = 0x00000001; +pub const EVENT_TRACE_FILE_MODE_CIRCULAR: DWORD = 0x00000002; +pub const EVENT_TRACE_FILE_MODE_APPEND: DWORD = 0x00000004; +pub const EVENT_TRACE_REAL_TIME_MODE: DWORD = 0x00000100; +pub const EVENT_TRACE_DELAY_OPEN_FILE_MODE: DWORD = 0x00000200; +pub const EVENT_TRACE_BUFFERING_MODE: DWORD = 0x00000400; +pub const EVENT_TRACE_PRIVATE_LOGGER_MODE: DWORD = 0x00000800; +pub const EVENT_TRACE_ADD_HEADER_MODE: DWORD = 0x00001000; +pub const EVENT_TRACE_USE_GLOBAL_SEQUENCE: DWORD = 0x00004000; +pub const EVENT_TRACE_USE_LOCAL_SEQUENCE: DWORD = 0x00008000; +pub const EVENT_TRACE_RELOG_MODE: DWORD = 0x00010000; +pub const EVENT_TRACE_USE_PAGED_MEMORY: DWORD = 0x01000000; +pub const EVENT_TRACE_FILE_MODE_NEWFILE: DWORD = 0x00000008; +pub const EVENT_TRACE_FILE_MODE_PREALLOCATE: DWORD = 0x00000020; +pub const EVENT_TRACE_NONSTOPPABLE_MODE: DWORD = 0x00000040; +pub const EVENT_TRACE_SECURE_MODE: DWORD = 0x00000080; +pub const EVENT_TRACE_USE_KBYTES_FOR_SIZE: DWORD = 0x00002000; +pub const EVENT_TRACE_PRIVATE_IN_PROC: DWORD = 0x00020000; +pub const EVENT_TRACE_MODE_RESERVED: DWORD = 0x00100000; +pub const EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING: DWORD = 0x10000000; +pub const EVENT_TRACE_SYSTEM_LOGGER_MODE: DWORD = 0x02000000; +pub const EVENT_TRACE_ADDTO_TRIAGE_DUMP: DWORD = 0x80000000; +pub const EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN: DWORD = 0x00400000; +pub const EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN: DWORD = 0x00800000; +pub const EVENT_TRACE_INDEPENDENT_SESSION_MODE: DWORD = 0x08000000; +pub const EVENT_TRACE_COMPRESSED_MODE: DWORD = 0x04000000; +pub const EVENT_TRACE_CONTROL_QUERY: DWORD = 0; +pub const EVENT_TRACE_CONTROL_STOP: DWORD = 1; +pub const EVENT_TRACE_CONTROL_UPDATE: DWORD = 2; +pub const EVENT_TRACE_CONTROL_FLUSH: DWORD = 3; +pub const TRACE_MESSAGE_SEQUENCE: DWORD = 1; +pub const TRACE_MESSAGE_GUID: DWORD = 2; +pub const TRACE_MESSAGE_COMPONENTID: DWORD = 4; +pub const TRACE_MESSAGE_TIMESTAMP: DWORD = 8; +pub const TRACE_MESSAGE_PERFORMANCE_TIMESTAMP: DWORD = 16; +pub const TRACE_MESSAGE_SYSTEMINFO: DWORD = 32; +pub const TRACE_MESSAGE_POINTER32: DWORD = 0x0040; +pub const TRACE_MESSAGE_POINTER64: DWORD = 0x0080; +pub const TRACE_MESSAGE_FLAG_MASK: DWORD = 0xFFFF; +pub const TRACE_MESSAGE_MAXIMUM_SIZE: SIZE_T = 64 * 1024; +pub const EVENT_TRACE_USE_PROCTIME: DWORD = 0x0001; +pub const EVENT_TRACE_USE_NOCPUTIME: DWORD = 0x0002; +pub const TRACE_HEADER_FLAG_USE_TIMESTAMP: DWORD = 0x00000200; +pub const TRACE_HEADER_FLAG_TRACED_GUID: DWORD = 0x00020000; +pub const TRACE_HEADER_FLAG_LOG_WNODE: DWORD = 0x00040000; +pub const TRACE_HEADER_FLAG_USE_GUID_PTR: DWORD = 0x00080000; +pub const TRACE_HEADER_FLAG_USE_MOF_PTR: DWORD = 0x00100000; +ENUM!{enum ETW_COMPRESSION_RESUMPTION_MODE { + EtwCompressionModeRestart = 0, + EtwCompressionModeNoDisable = 1, + EtwCompressionModeNoRestart = 2, +}} +STRUCT!{struct EVENT_TRACE_HEADER_u1_s { + HeaderType: UCHAR, + MarkerFlags: UCHAR, +}} +UNION!{union EVENT_TRACE_HEADER_u1 { + [u16; 1], + FieldTypeFlags FieldTypeFlags_mut: USHORT, + s s_mut: EVENT_TRACE_HEADER_u1_s, +}} +STRUCT!{struct EVENT_TRACE_HEADER_u2_CLASS { + Type: UCHAR, + Level: UCHAR, + Version: USHORT, +}} +UNION!{union EVENT_TRACE_HEADER_u2 { + [u32; 1], + Version Version_mut: ULONG, + Class Class_mut: EVENT_TRACE_HEADER_u2_CLASS, +}} +UNION!{union EVENT_TRACE_HEADER_u3 { + [u64; 2], + Guid Guid_mut: GUID, + GuidPtr GuidPtr_mut: ULONGLONG, +}} +STRUCT!{struct EVENT_TRACE_HEADER_u4_s1 { + ClientContext: ULONG, + Flags: ULONG, +}} +STRUCT!{struct EVENT_TRACE_HEADER_u4_s2 { + KernelTime: ULONG, + UserTime: ULONG, +}} +UNION!{union EVENT_TRACE_HEADER_u4 { + [u64; 1], + s1 s1_mut: EVENT_TRACE_HEADER_u4_s1, + s2 s2_mut: EVENT_TRACE_HEADER_u4_s2, + ProcessorTime ProcessorTime_mut: ULONG64, +}} +STRUCT!{struct EVENT_TRACE_HEADER { + Size: USHORT, + u1: EVENT_TRACE_HEADER_u1, + u2: EVENT_TRACE_HEADER_u2, + ThreadId: ULONG, + ProcessId: ULONG, + TimeStamp: LARGE_INTEGER, + u3: EVENT_TRACE_HEADER_u3, + u4: EVENT_TRACE_HEADER_u4, +}} +pub type PEVENT_TRACE_HEADER = *mut EVENT_TRACE_HEADER; +STRUCT!{struct EVENT_INSTANCE_HEADER_u1_s { + HeaderType: UCHAR, + MarkerFlags: UCHAR, +}} +UNION!{union EVENT_INSTANCE_HEADER_u1 { + [u16; 1], + FieldTypeFlags FieldTypeFlags_mut: USHORT, + s s_mut: EVENT_INSTANCE_HEADER_u1_s, +}} +STRUCT!{struct EVENT_INSTANCE_HEADER_u2_CLASS { + Type: UCHAR, + Level: UCHAR, + Version: USHORT, +}} +UNION!{union EVENT_INSTANCE_HEADER_u2 { + [u32; 1], + Version Version_mut: ULONG, + Class Class_mut: EVENT_INSTANCE_HEADER_u2_CLASS, +}} +STRUCT!{struct EVENT_INSTANCE_HEADER_u3_s1 { + KernelTime: ULONG, + UserTime: ULONG, +}} +STRUCT!{struct EVENT_INSTANCE_HEADER_u3_s2 { + EventId: ULONG, + Flags: ULONG, +}} +UNION!{union EVENT_INSTANCE_HEADER_u3 { + [u64; 1], + s1 s1_mut: EVENT_INSTANCE_HEADER_u3_s1, + ProcessorTime ProcessorTime_mut: ULONG64, + s2 s2_mut: EVENT_INSTANCE_HEADER_u3_s2, +}} +STRUCT!{struct EVENT_INSTANCE_HEADER { + Size: USHORT, + u1: EVENT_INSTANCE_HEADER_u1, + u2: EVENT_INSTANCE_HEADER_u2, + ThreadId: ULONG, + ProcessId: ULONG, + TimeStamp: LARGE_INTEGER, + RegHandle: ULONGLONG, + InstanceId: ULONG, + ParentInstanceId: ULONG, + u3: EVENT_INSTANCE_HEADER_u3, + ParentRegHandle: ULONGLONG, +}} +pub type PEVENT_INSTANCE_HEADER = *mut EVENT_INSTANCE_HEADER; +pub const ETW_NULL_TYPE_VALUE: ULONG = 0; +pub const ETW_OBJECT_TYPE_VALUE: ULONG = 1; +pub const ETW_STRING_TYPE_VALUE: ULONG = 2; +pub const ETW_SBYTE_TYPE_VALUE: ULONG = 3; +pub const ETW_BYTE_TYPE_VALUE: ULONG = 4; +pub const ETW_INT16_TYPE_VALUE: ULONG = 5; +pub const ETW_UINT16_TYPE_VALUE: ULONG = 6; +pub const ETW_INT32_TYPE_VALUE: ULONG = 7; +pub const ETW_UINT32_TYPE_VALUE: ULONG = 8; +pub const ETW_INT64_TYPE_VALUE: ULONG = 9; +pub const ETW_UINT64_TYPE_VALUE: ULONG = 10; +pub const ETW_CHAR_TYPE_VALUE: ULONG = 11; +pub const ETW_SINGLE_TYPE_VALUE: ULONG = 12; +pub const ETW_DOUBLE_TYPE_VALUE: ULONG = 13; +pub const ETW_BOOLEAN_TYPE_VALUE: ULONG = 14; +pub const ETW_DECIMAL_TYPE_VALUE: ULONG = 15; +pub const ETW_GUID_TYPE_VALUE: ULONG = 101; +pub const ETW_ASCIICHAR_TYPE_VALUE: ULONG = 102; +pub const ETW_ASCIISTRING_TYPE_VALUE: ULONG = 103; +pub const ETW_COUNTED_STRING_TYPE_VALUE: ULONG = 104; +pub const ETW_POINTER_TYPE_VALUE: ULONG = 105; +pub const ETW_SIZET_TYPE_VALUE: ULONG = 106; +pub const ETW_HIDDEN_TYPE_VALUE: ULONG = 107; +pub const ETW_BOOL_TYPE_VALUE: ULONG = 108; +pub const ETW_COUNTED_ANSISTRING_TYPE_VALUE: ULONG = 109; +pub const ETW_REVERSED_COUNTED_STRING_TYPE_VALUE: ULONG = 110; +pub const ETW_REVERSED_COUNTED_ANSISTRING_TYPE_VALUE: ULONG = 111; +pub const ETW_NON_NULL_TERMINATED_STRING_TYPE_VALUE: ULONG = 112; +pub const ETW_REDUCED_ANSISTRING_TYPE_VALUE: ULONG = 113; +pub const ETW_REDUCED_STRING_TYPE_VALUE: ULONG = 114; +pub const ETW_SID_TYPE_VALUE: ULONG = 115; +pub const ETW_VARIANT_TYPE_VALUE: ULONG = 116; +pub const ETW_PTVECTOR_TYPE_VALUE: ULONG = 117; +pub const ETW_WMITIME_TYPE_VALUE: ULONG = 118; +pub const ETW_DATETIME_TYPE_VALUE: ULONG = 119; +pub const ETW_REFRENCE_TYPE_VALUE: ULONG = 120; +// TODO: DEFINE_TRACE_MOF_FIELD +STRUCT!{struct MOF_FIELD { + DataPtr: ULONG64, + Length: ULONG, + DataType: ULONG, +}} +pub type PMOF_FIELD = *mut MOF_FIELD; +STRUCT!{struct TRACE_LOGFILE_HEADER_u1_VERSIONDETAIL { + MajorVersion: UCHAR, + MinorVersion: UCHAR, + SubVersion: UCHAR, + SubMinorVersion: UCHAR, +}} +UNION!{union TRACE_LOGFILE_HEADER_u1 { + [u32; 1], + Version Version_mut: ULONG, + VersionDetail VersionDetail_mut: TRACE_LOGFILE_HEADER_u1_VERSIONDETAIL, +}} +STRUCT!{struct TRACE_LOGFILE_HEADER_u2_s { + StartBuffers: ULONG, + PointerSize: ULONG, + EventsLost: ULONG, + CpuSpeedInMHz: ULONG, +}} +UNION!{union TRACE_LOGFILE_HEADER_u2 { + [u32; 4], + LogInstanceGuid LogInstanceGuid_mut: GUID, + s s_mut: TRACE_LOGFILE_HEADER_u2_s, +}} +STRUCT!{struct TRACE_LOGFILE_HEADER { + BufferSize: ULONG, + u1: TRACE_LOGFILE_HEADER_u1, + ProviderVersion: ULONG, + NumberOfProcessors: ULONG, + EndTime: LARGE_INTEGER, + TimerResolution: ULONG, + MaximumFileSize: ULONG, + LogFileMode: ULONG, + BuffersWritten: ULONG, + u2: TRACE_LOGFILE_HEADER_u2, + LoggerName: LPWSTR, + LogFileName: LPWSTR, + TimeZone: TIME_ZONE_INFORMATION, + BootTime: LARGE_INTEGER, + PrefFreq: LARGE_INTEGER, + StartTime: LARGE_INTEGER, + ReservedFlags: ULONG, + BuffersLost: ULONG, +}} +pub type PTRACE_LOGFILE_HEADER = *mut TRACE_LOGFILE_HEADER; +STRUCT!{struct TRACE_LOGFILE_HEADER32 { + BufferSize: ULONG, + u1: TRACE_LOGFILE_HEADER_u1, + ProviderVersion: ULONG, + NumberOfProcessors: ULONG, + EndTime: LARGE_INTEGER, + TimerResolution: ULONG, + MaximumFileSize: ULONG, + LogFileMode: ULONG, + BuffersWritten: ULONG, + u2: TRACE_LOGFILE_HEADER_u2, + LoggerName: ULONG32, + LogFileName: ULONG32, + TimeZone: TIME_ZONE_INFORMATION, + BootTime: LARGE_INTEGER, + PrefFreq: LARGE_INTEGER, + StartTime: LARGE_INTEGER, + ReservedFlags: ULONG, + BuffersLost: ULONG, +}} +pub type PTRACE_LOGFILE_HEADER32 = *mut TRACE_LOGFILE_HEADER32; +STRUCT!{struct TRACE_LOGFILE_HEADER64 { + BufferSize: ULONG, + u1: TRACE_LOGFILE_HEADER_u1, + ProviderVersion: ULONG, + NumberOfProcessors: ULONG, + EndTime: LARGE_INTEGER, + TimerResolution: ULONG, + MaximumFileSize: ULONG, + LogFileMode: ULONG, + BuffersWritten: ULONG, + u2: TRACE_LOGFILE_HEADER_u2, + LoggerName: ULONG64, + LogFileName: ULONG64, + TimeZone: TIME_ZONE_INFORMATION, + BootTime: LARGE_INTEGER, + PrefFreq: LARGE_INTEGER, + StartTime: LARGE_INTEGER, + ReservedFlags: ULONG, + BuffersLost: ULONG, +}} +pub type PTRACE_LOGFILE_HEADER64 = *mut TRACE_LOGFILE_HEADER64; +STRUCT!{struct EVENT_INSTANCE_INFO { + RegHandle: HANDLE, + InstanceId: ULONG, +}} +pub type PEVENT_INSTANCE_INFO = *mut EVENT_INSTANCE_INFO; +UNION!{union EVENT_TRACE_PROPERTIES_u { + [u32; 1], + AgeLimit AgeLimit_mut: LONG, + FlushThreshold FlushThreshold_mut: LONG, +}} +STRUCT!{struct EVENT_TRACE_PROPERTIES { + Wnode: WNODE_HEADER, + BufferSize: ULONG, + MinimumBuffers: ULONG, + MaximumBuffers: ULONG, + MaximumFileSize: ULONG, + LogFileMode: ULONG, + FlushTimer: ULONG, + EnableFlags: ULONG, + u: EVENT_TRACE_PROPERTIES_u, + NumberOfBuffers: ULONG, + FreeBuffers: ULONG, + EventsLost: ULONG, + BuffersWritten: ULONG, + LogBuffersLost: ULONG, + RealTimeBuffersLost: ULONG, + LoggerThreadId: HANDLE, + LogFileNameOffset: ULONG, + LoggerNameOffset: ULONG, +}} +pub type PEVENT_TRACE_PROPERTIES = *mut EVENT_TRACE_PROPERTIES; +UNION!{union EVENT_TRACE_PROPERTIES_V2_u1 { + [u32; 1], + AgeLimit AgeLimit_mut: LONG, + FlushThreshold FlushThreshold_mut: LONG, +}} +STRUCT!{struct EVENT_TRACE_PROPERTIES_V2_u2_s { + bitfield: ULONG, +}} +BITFIELD!{EVENT_TRACE_PROPERTIES_V2_u2_s bitfield: ULONG [ + VersionNumber set_VersionNumber[0..8], +]} +UNION!{union EVENT_TRACE_PROPERTIES_V2_u2 { + [u32; 1], + s s_mut: EVENT_TRACE_PROPERTIES_V2_u2_s, + V2Control V2Control_mut: ULONG, +}} +STRUCT!{struct EVENT_TRACE_PROPERTIES_V2_u3_s { + bitfield: ULONG, +}} +BITFIELD!{EVENT_TRACE_PROPERTIES_V2_u3_s bitfield: ULONG [ + Wow set_Wow[0..1], +]} +UNION!{union EVENT_TRACE_PROPERTIES_V2_u3 { + [u64; 1], + s s_mut: EVENT_TRACE_PROPERTIES_V2_u3_s, + V2Options V2Options_mut: ULONG64, +}} +STRUCT!{struct EVENT_TRACE_PROPERTIES_V2 { + Wnode: WNODE_HEADER, + BufferSize: ULONG, + MinimumBuffers: ULONG, + MaximumBuffers: ULONG, + MaximumFileSize: ULONG, + LogFileMode: ULONG, + FlushTimer: ULONG, + EnableFlags: ULONG, + u1: EVENT_TRACE_PROPERTIES_u, + NumberOfBuffers: ULONG, + FreeBuffers: ULONG, + EventsLost: ULONG, + BuffersWritten: ULONG, + LogBuffersLost: ULONG, + RealTimeBuffersLost: ULONG, + LoggerThreadId: HANDLE, + LogFileNameOffset: ULONG, + LoggerNameOffset: ULONG, + u2: EVENT_TRACE_PROPERTIES_V2_u2, + FilterDescCount: ULONG, + FilterDesc: PEVENT_FILTER_DESCRIPTOR, + u3: EVENT_TRACE_PROPERTIES_V2_u3, +}} +pub type PEVENT_TRACE_PROPERTIES_V2 = *mut EVENT_TRACE_PROPERTIES_V2; +STRUCT!{struct TRACE_GUID_REGISTRATION { + Guid: LPCGUID, + RegHandle: HANDLE, +}} +pub type PTRACE_GUID_REGISTRATION = *mut TRACE_GUID_REGISTRATION; +STRUCT!{struct TRACE_GUID_PROPERTIES { + Guid: GUID, + GuidType: ULONG, + LoggerId: ULONG, + EnableLevel: ULONG, + EnableFlags: ULONG, + IsEnable: BOOLEAN, +}} +pub type PTRACE_GUID_PROPERTIES = *mut TRACE_GUID_PROPERTIES; +STRUCT!{struct ETW_BUFFER_CONTEXT_u_s { + ProcessorNumber: UCHAR, + Alignment: UCHAR, +}} +UNION!{union ETW_BUFFER_CONTEXT_u { + [u16; 1], + s s_mut: ETW_BUFFER_CONTEXT_u_s, + ProcessorIndex ProcessorIndex_mut: USHORT, +}} +STRUCT!{struct ETW_BUFFER_CONTEXT { + u: ETW_BUFFER_CONTEXT_u, + LoggerId: USHORT, +}} +pub type PETW_BUFFER_CONTEXT = *mut ETW_BUFFER_CONTEXT; +pub const TRACE_PROVIDER_FLAG_LEGACY: ULONG = 0x00000001; +pub const TRACE_PROVIDER_FLAG_PRE_ENABLE: ULONG = 0x00000002; +STRUCT!{struct TRACE_ENABLE_INFO { + IsEnabled: ULONG, + Level: UCHAR, + Reserved1: UCHAR, + LoggerId: USHORT, + EnabledProperty: ULONG, + Reserved2: ULONG, + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, +}} +pub type PTRACE_ENABLE_INFO = *mut TRACE_ENABLE_INFO; +STRUCT!{struct TRACE_PROVIDER_INSTANCE_INFO { + NameOffset: ULONG, + EnableCount: ULONG, + Pid: ULONG, + Flags: ULONG, +}} +pub type PTRACE_PROVIDER_INSTANCE_INFO = *mut TRACE_PROVIDER_INSTANCE_INFO; +STRUCT!{struct TRACE_GUID_INFO { + InstanceCount: ULONG, + Reserved: ULONG, +}} +pub type PTRACE_GUID_INFO = *mut TRACE_GUID_INFO; +STRUCT!{struct PROFILE_SOURCE_INFO { + NextEntryOffset: ULONG, + Source: ULONG, + MinInterval: ULONG, + MaxInterval: ULONG, + Reserved: ULONG64, + Description: [WCHAR; ANYSIZE_ARRAY], +}} +pub type PPROFILE_SOURCE_INFO = *mut PROFILE_SOURCE_INFO; +UNION!{union EVENT_TRACE_u { + [u32; 1], + ClientContext ClientContext_mut: ULONG, + BufferContext BufferContext_mut: ETW_BUFFER_CONTEXT, +}} +STRUCT!{struct EVENT_TRACE { + Header: EVENT_TRACE_HEADER, + InstanceId: ULONG, + ParentInstanceId: ULONG, + ParentGuid: GUID, + MofData: PVOID, + MofLength: ULONG, + u: EVENT_TRACE_u, +}} +pub type PEVENT_TRACE = *mut EVENT_TRACE; +pub const EVENT_CONTROL_CODE_DISABLE_PROVIDER: ULONG = 0; +pub const EVENT_CONTROL_CODE_ENABLE_PROVIDER: ULONG = 1; +pub const EVENT_CONTROL_CODE_CAPTURE_STATE: ULONG = 2; +FN!{stdcall PEVENT_TRACE_BUFFER_CALLBACKW( + PEVENT_TRACE_LOGFILEW, +) -> ULONG} +FN!{stdcall PEVENT_TRACE_BUFFER_CALLBACKA( + PEVENT_TRACE_LOGFILEA, +) -> ULONG} +FN!{stdcall PEVENT_CALLBACK( + pEvent: PEVENT_TRACE, +) -> ()} +FN!{stdcall PEVENT_RECORD_CALLBACK( + EventRecord: PEVENT_RECORD, +) -> ()} +FN!{stdcall WMIDPREQUEST( + RequestCode: WMIDPREQUESTCODE, + RequestContext: PVOID, + BufferSize: *mut ULONG, + Buffer: PVOID, +) -> ULONG} +UNION!{union EVENT_TRACE_LOGFILE_u1 { + [u32; 1], + LogFileMode LogFileMode_mut: ULONG, + ProcessTraceMode ProcessTraceMode_mut: ULONG, +}} +UNION!{union EVENT_TRACE_LOGFILE_u2 { + [u32; 1] [u64; 1], + EventCallback EventCallback_mut: PEVENT_CALLBACK, + EventRecordCallback EventRecordCallback_mut: PEVENT_RECORD_CALLBACK, +}} +STRUCT!{struct EVENT_TRACE_LOGFILEW { + LogFileName: LPWSTR, + LoggerName: LPWSTR, + CurrentTime: LONGLONG, + BuffersRead: ULONG, + u1: EVENT_TRACE_LOGFILE_u1, + CurrentEvent: EVENT_TRACE, + LogfileHeader: TRACE_LOGFILE_HEADER, + BufferCallback: PEVENT_TRACE_BUFFER_CALLBACKW, + BufferSize: ULONG, + Filled: ULONG, + EventsLost: ULONG, + u2: EVENT_TRACE_LOGFILE_u2, + IsKernelTrace: ULONG, + Context: PVOID, +}} +pub type PEVENT_TRACE_LOGFILEW = *mut EVENT_TRACE_LOGFILEW; +STRUCT!{struct EVENT_TRACE_LOGFILEA { + LogFileName: LPSTR, + LoggerName: LPSTR, + CurrentTime: LONGLONG, + BuffersRead: ULONG, + u1: EVENT_TRACE_LOGFILE_u1, + CurrentEvent: EVENT_TRACE, + LogfileHeader: TRACE_LOGFILE_HEADER, + BufferCallback: PEVENT_TRACE_BUFFER_CALLBACKA, + BufferSize: ULONG, + Filled: ULONG, + EventsLost: ULONG, + u2: EVENT_TRACE_LOGFILE_u2, + IsKernelTrace: ULONG, + Context: PVOID, +}} +pub type PEVENT_TRACE_LOGFILEA = *mut EVENT_TRACE_LOGFILEA; +extern "system" { + pub fn StartTraceW( + SessionHandle: PTRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn StartTraceA( + SessionHandle: PTRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn StopTraceW( + SessionHandle: TRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn StopTraceA( + SessionHandle: TRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn QueryTraceW( + SessionHandle: TRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn QueryTraceA( + SessionHandle: TRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn UpdateTraceW( + SessionHandle: TRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn UpdateTraceA( + SessionHandle: TRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn FlushTraceW( + SessionHandle: TRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn FlushTraceA( + SessionHandle: TRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ) -> ULONG; + pub fn ControlTraceW( + SessionHandle: TRACEHANDLE, + SessionName: LPCWSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ControlCode: ULONG, + ) -> ULONG; + pub fn ControlTraceA( + SessionHandle: TRACEHANDLE, + SessionName: LPCSTR, + Properties: PEVENT_TRACE_PROPERTIES, + ControlCode: ULONG, + ) -> ULONG; + pub fn QueryAllTracesW( + PropertyArray: *mut PEVENT_TRACE_PROPERTIES, + PropertyArrayCount: ULONG, + SessionCount: PULONG, + ) -> ULONG; + pub fn QueryAllTracesA( + PropertyArray: *mut PEVENT_TRACE_PROPERTIES, + PropertyArrayCount: ULONG, + SessionCount: PULONG, + ) -> ULONG; + pub fn EnableTrace( + Enable: ULONG, + EnableFlag: ULONG, + EnableLevel: ULONG, + ControlGuid: LPCGUID, + SessionHandle: TRACEHANDLE, + ) -> ULONG; + pub fn EnableTraceEx( + ProviderId: LPCGUID, + SourceId: LPCGUID, + TraceHandle: TRACEHANDLE, + IsEnabled: ULONG, + Level: UCHAR, + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, + EnableProperty: ULONG, + EnableFilterDesc: PEVENT_FILTER_DESCRIPTOR, + ) -> ULONG; +} +pub const ENABLE_TRACE_PARAMETERS_VERSION: ULONG = 1; +pub const ENABLE_TRACE_PARAMETERS_VERSION_2: ULONG = 2; +STRUCT!{struct ENABLE_TRACE_PARAMETERS_V1 { + Version: ULONG, + EnableProperty: ULONG, + ControlFlags: ULONG, + SourceId: GUID, + EnableFilterDesc: PEVENT_FILTER_DESCRIPTOR, +}} +pub type PENABLE_TRACE_PARAMETERS_V1 = *mut ENABLE_TRACE_PARAMETERS_V1; +STRUCT!{struct ENABLE_TRACE_PARAMETERS { + Version: ULONG, + EnableProperty: ULONG, + ControlFlags: ULONG, + SourceId: GUID, + EnableFilterDesc: PEVENT_FILTER_DESCRIPTOR, + FilterDescCount: ULONG, +}} +pub type PENABLE_TRACE_PARAMETERS = *mut ENABLE_TRACE_PARAMETERS; +extern "system" { + pub fn EnableTraceEx2( + TraceHandle: TRACEHANDLE, + ProviderId: LPCGUID, + ControlCode: ULONG, + Level: UCHAR, + MatchAnyKeyword: ULONGLONG, + MatchAllKeyword: ULONGLONG, + Timeout: ULONG, + EnableParameters: PENABLE_TRACE_PARAMETERS, + ) -> ULONG; +} +ENUM!{enum TRACE_QUERY_INFO_CLASS { + TraceGuidQueryList, + TraceGuidQueryInfo, + TraceGuidQueryProcess, + TraceStackTracingInfo, + TraceSystemTraceEnableFlagsInfo, + TraceSampledProfileIntervalInfo, + TraceProfileSourceConfigInfo, + TraceProfileSourceListInfo, + TracePmcEventListInfo, + TracePmcCounterListInfo, + TraceSetDisallowList, + TraceVersionInfo, + TraceGroupQueryList, + TraceGroupQueryInfo, + TraceDisallowListQuery, + TraceCompressionInfo, + TracePeriodicCaptureStateListInfo, + TracePeriodicCaptureStateInfo, + TraceProviderBinaryTracking, + TraceMaxLoggersQuery, + MaxTraceSetInfoClass, +}} +pub type TRACE_INFO_CLASS = TRACE_QUERY_INFO_CLASS; +extern "system" { + pub fn EnumerateTraceGuidsEx( + TraceQueryInfoClass: TRACE_QUERY_INFO_CLASS, + InBuffer: PVOID, + InBufferSize: ULONG, + OutBuffer: PVOID, + OutBufferSize: ULONG, + ReturnLength: PULONG, + ) -> ULONG; +} +STRUCT!{struct CLASSIC_EVENT_ID { + EventGuid: GUID, + Type: UCHAR, + Reserved: [UCHAR; 7], +}} +pub type PCLASSIC_EVENT_ID = *mut CLASSIC_EVENT_ID; +STRUCT!{struct TRACE_PROFILE_INTERVAL { + Source: ULONG, + Interval: ULONG, +}} +pub type PTRACE_PROFILE_INTERVAL = *mut TRACE_PROFILE_INTERVAL; +STRUCT!{struct TRACE_VERSION_INFO { + EtwTraceProcessingVersion: UINT, + Reserved: UINT, +}} +pub type PTRACE_VERSION_INFO = *mut TRACE_VERSION_INFO; +STRUCT!{struct TRACE_PERIODIC_CAPTURE_STATE_INFO { + CaptureStateFrequencyInSeconds: ULONG, + ProviderCount: USHORT, + Reserved: USHORT, +}} +pub type PTRACE_PERIODIC_CAPTURE_STATE_INFO = *mut TRACE_PERIODIC_CAPTURE_STATE_INFO; +extern "system" { + pub fn TraceSetInformation( + SessionHandle: TRACEHANDLE, + InformationClass: TRACE_INFO_CLASS, + TraceInformation: PVOID, + InformationLength: ULONG, + ) -> ULONG; + pub fn TraceQueryInformation( + SessionHandle: TRACEHANDLE, + InformationClass: TRACE_QUERY_INFO_CLASS, + TraceInformation: PVOID, + InformationLength: ULONG, + ReturnLength: PULONG, + ) -> ULONG; + pub fn CreateTraceInstanceId( + RegHandle: HANDLE, + pInstInfo: PEVENT_INSTANCE_INFO, + ) -> ULONG; + pub fn TraceEvent( + SessionHandle: TRACEHANDLE, + EventTrace: PEVENT_TRACE_HEADER, + ) -> ULONG; + pub fn TraceEventInstance( + SessionHandle: TRACEHANDLE, + EventTrace: PEVENT_TRACE_HEADER, + pInstInfo: PEVENT_INSTANCE_INFO, + pParentInstInfo: PEVENT_INSTANCE_INFO, + ) -> ULONG; + pub fn RegisterTraceGuidsW( + RequestAddress: WMIDPREQUEST, + RequestContext: PVOID, + ControlGuid: LPCGUID, + GuidCount: ULONG, + TraceGuidReg: PTRACE_GUID_REGISTRATION, + MofImagePath: LPCWSTR, + MofResourceName: LPCWSTR, + RegistrationHandle: PTRACEHANDLE, + ) -> ULONG; + pub fn RegisterTraceGuidsA( + RequestAddress: WMIDPREQUEST, + RequestContext: PVOID, + ControlGuid: LPCGUID, + GuidCount: ULONG, + TraceGuidReg: PTRACE_GUID_REGISTRATION, + MofImagePath: LPCSTR, + MofResourceName: LPCSTR, + RegistrationHandle: PTRACEHANDLE, + ) -> ULONG; + pub fn EnumerateTraceGuids( + GuidPropertiesArray: *mut PTRACE_GUID_PROPERTIES, + PropertyArrayCount: ULONG, + GuidCount: PULONG, + ) -> ULONG; + pub fn UnregisterTraceGuids( + RegistrationHandle: TRACEHANDLE, + ) -> ULONG; + pub fn GetTraceLoggerHandle( + Buffer: PVOID, + ) -> TRACEHANDLE; + pub fn GetTraceEnableLevel( + SessionHandle: TRACEHANDLE, + ) -> UCHAR; + pub fn GetTraceEnableFlags( + SessionHandle: TRACEHANDLE, + ) -> ULONG; + pub fn OpenTraceW( + Logfile: PEVENT_TRACE_LOGFILEW, + ) -> TRACEHANDLE; + pub fn ProcessTrace( + HandleArray: PTRACEHANDLE, + HandleCount: ULONG, + StartTime: LPFILETIME, + EndTime: LPFILETIME, + ) -> ULONG; + pub fn CloseTrace( + TraceHandle: TRACEHANDLE, + ) -> ULONG; +} +ENUM!{enum ETW_PROCESS_HANDLE_INFO_TYPE { + EtwQueryPartitionInformation = 1, + EtwQueryProcessHandleInfoMax, +}} +STRUCT!{struct ETW_TRACE_PARTITION_INFORMATION { + PartitionId: GUID, + ParentId: GUID, + Reserved: ULONG64, + PartitionType: ULONG, +}} +pub type PETW_TRACE_PARTITION_INFORMATION = *mut ETW_TRACE_PARTITION_INFORMATION; +extern "system" { + pub fn QueryTraceProcessingHandle( + ProcessingHandle: TRACEHANDLE, + InformationClass: ETW_PROCESS_HANDLE_INFO_TYPE, + InBuffer: PVOID, + InBufferSize: ULONG, + OutBuffer: PVOID, + OutBufferSize: ULONG, + ReturnLength: PULONG, + ) -> ULONG; + pub fn OpenTraceA( + Logfile: PEVENT_TRACE_LOGFILEA, + ) -> TRACEHANDLE; + pub fn SetTraceCallback( + pGuid: LPCGUID, + EventCallback: PEVENT_CALLBACK, + ) -> ULONG; + pub fn RemoveTraceCallback( + pGuid: LPCGUID, + ) -> ULONG; +} +extern "C" { + pub fn TraceMessage( + SessionHandle: TRACEHANDLE, + MessageFlags: ULONG, + MessageGuid: LPGUID, + MessageNumber: USHORT, + ... + ) -> ULONG; + pub fn TraceMessageVa( + SessionHandle: TRACEHANDLE, + MessageFlags: ULONG, + MessageGuid: LPGUID, + MessageNumber: USHORT, + MessageArgList: va_list, + ); +} +pub const INVALID_PROCESSTRACE_HANDLE: TRACEHANDLE = INVALID_HANDLE_VALUE as TRACEHANDLE; diff --git a/winapi/src/shared/guiddef.rs b/winapi/src/shared/guiddef.rs new file mode 100644 index 000000000..dcd39dcc4 --- /dev/null +++ b/winapi/src/shared/guiddef.rs @@ -0,0 +1,36 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! GUID definition +use ctypes::{c_uchar, c_ulong, c_ushort}; +STRUCT!{#[debug] struct GUID { + Data1: c_ulong, + Data2: c_ushort, + Data3: c_ushort, + Data4: [c_uchar; 8], +}} +pub type LPGUID = *mut GUID; +pub type LPCGUID = *const GUID; +pub type IID = GUID; +pub type LPIID = *mut IID; +pub use self::IsEqualGUID as IsEqualIID; +pub type CLSID = GUID; +pub type LPCLSID = *mut CLSID; +pub use self::IsEqualGUID as IsEqualCLSID; +pub type FMTID = GUID; +pub type LPFMTID = *mut FMTID; +pub use self::IsEqualGUID as IsEqualFMTID; +pub type REFGUID = *const GUID; +pub type REFIID = *const IID; +pub type REFCLSID = *const IID; +pub type REFFMTID = *const IID; +DEFINE_GUID!{IID_NULL, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#[inline] +pub fn IsEqualGUID(g1: &GUID, g2: &GUID) -> bool { + let a = unsafe { &*(g1 as *const _ as *const [u32; 4]) }; + let b = unsafe { &*(g2 as *const _ as *const [u32; 4]) }; + a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3] +} diff --git a/winapi/src/shared/hidclass.rs b/winapi/src/shared/hidclass.rs new file mode 100644 index 000000000..c65c14faf --- /dev/null +++ b/winapi/src/shared/hidclass.rs @@ -0,0 +1,68 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, PUCHAR, UCHAR, ULONG, USHORT}; +use um::winioctl::{ + FILE_ANY_ACCESS, FILE_DEVICE_KEYBOARD, METHOD_BUFFERED, METHOD_IN_DIRECT, METHOD_NEITHER, + METHOD_OUT_DIRECT, +}; +use um::winnt::BOOLEAN; +DEFINE_GUID!{GUID_DEVINTERFACE_HID, + 0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} +pub const GUID_CLASS_INPUT: GUID = GUID_DEVINTERFACE_HID; +DEFINE_GUID!{GUID_HID_INTERFACE_NOTIFY, + 0x2c4e2e88, 0x25e6, 0x4c33, 0x88, 0x2f, 0x3d, 0x82, 0xe6, 0x07, 0x36, 0x81} +DEFINE_GUID!{GUID_HID_INTERFACE_HIDPARSE, + 0xf5c315a5, 0x69ac, 0x4bc2, 0x92, 0x79, 0xd0, 0xb6, 0x45, 0x76, 0xf4, 0x4b} +// FIXME devpropkey stuff +pub const HID_REVISION: DWORD = 0x00000001; +pub const IOCTL_HID_GET_DRIVER_CONFIG: DWORD = HID_BUFFER_CTL_CODE!(100); +pub const IOCTL_HID_SET_DRIVER_CONFIG: DWORD = HID_BUFFER_CTL_CODE!(101); +pub const IOCTL_HID_GET_POLL_FREQUENCY_MSEC: DWORD = HID_BUFFER_CTL_CODE!(102); +pub const IOCTL_HID_SET_POLL_FREQUENCY_MSEC: DWORD = HID_BUFFER_CTL_CODE!(103); +pub const IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS: DWORD = HID_BUFFER_CTL_CODE!(104); +pub const IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS: DWORD = HID_BUFFER_CTL_CODE!(105); +pub const IOCTL_HID_GET_COLLECTION_INFORMATION: DWORD = HID_BUFFER_CTL_CODE!(106); +pub const IOCTL_HID_ENABLE_WAKE_ON_SX: DWORD = HID_BUFFER_CTL_CODE!(107); +pub const IOCTL_HID_SET_S0_IDLE_TIMEOUT: DWORD = HID_BUFFER_CTL_CODE!(108); +pub const IOCTL_HID_GET_COLLECTION_DESCRIPTOR: DWORD = HID_CTL_CODE!(100); +pub const IOCTL_HID_FLUSH_QUEUE: DWORD = HID_CTL_CODE!(101); +pub const IOCTL_HID_SET_FEATURE: DWORD = HID_IN_CTL_CODE!(100); +pub const IOCTL_HID_SET_OUTPUT_REPORT: DWORD = HID_IN_CTL_CODE!(101); +pub const IOCTL_HID_GET_FEATURE: DWORD = HID_OUT_CTL_CODE!(100); +pub const IOCTL_GET_PHYSICAL_DESCRIPTOR: DWORD = HID_OUT_CTL_CODE!(102); +pub const IOCTL_HID_GET_HARDWARE_ID: DWORD = HID_OUT_CTL_CODE!(103); +pub const IOCTL_HID_GET_INPUT_REPORT: DWORD = HID_OUT_CTL_CODE!(104); +pub const IOCTL_HID_GET_OUTPUT_REPORT: DWORD = HID_OUT_CTL_CODE!(105); +pub const IOCTL_HID_GET_MANUFACTURER_STRING: DWORD = HID_OUT_CTL_CODE!(110); +pub const IOCTL_HID_GET_PRODUCT_STRING: DWORD = HID_OUT_CTL_CODE!(111); +pub const IOCTL_HID_GET_SERIALNUMBER_STRING: DWORD = HID_OUT_CTL_CODE!(112); +pub const IOCTL_HID_GET_INDEXED_STRING: DWORD = HID_OUT_CTL_CODE!(120); +pub const IOCTL_HID_GET_MS_GENRE_DESCRIPTOR: DWORD = HID_OUT_CTL_CODE!(121); +pub const IOCTL_HID_ENABLE_SECURE_READ: DWORD = HID_CTL_CODE!(130); +pub const IOCTL_HID_DISABLE_SECURE_READ: DWORD = HID_CTL_CODE!(131); +pub const IOCTL_HID_DEVICERESET_NOTIFICATION: DWORD = HID_CTL_CODE!(140); +STRUCT!{struct HID_XFER_PACKET { + reportBuffer: PUCHAR, + reportBufferLen: ULONG, + reportId: UCHAR, +}} +pub type PHID_XFER_PACKET = *mut HID_XFER_PACKET; +//FIXME Stuff for NT_INCLUDED +STRUCT!{struct HID_COLLECTION_INFORMATION { + DescriptorSize: ULONG, + Polled: BOOLEAN, + Reserved1: [UCHAR; 1], + VendorID: USHORT, + ProductID: USHORT, + VersionNumber: USHORT, +}} +pub type PHID_COLLECTION_INFORMATION = *mut HID_COLLECTION_INFORMATION; +STRUCT!{struct HID_DRIVER_CONFIG { + Size: ULONG, + RingBufferSize: ULONG, +}} +pub type PHID_DRIVER_CONFIG = *mut HID_DRIVER_CONFIG; diff --git a/winapi/src/shared/hidpi.rs b/winapi/src/shared/hidpi.rs new file mode 100644 index 000000000..ea0229253 --- /dev/null +++ b/winapi/src/shared/hidpi.rs @@ -0,0 +1,393 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::hidusage::{PUSAGE, USAGE}; +use shared::minwindef::{PUCHAR, PULONG, PUSHORT, UCHAR, ULONG, USHORT}; +use shared::ntdef::NTSTATUS; +use shared::ntstatus::FACILITY_HID_ERROR_CODE; +use um::winnt::{BOOLEAN, LONG, PCHAR, PLONG, PVOID}; +pub const HIDP_LINK_COLLECTION_ROOT: USHORT = -1i16 as u16; +pub const HIDP_LINK_COLLECTION_UNSPECIFIED: USHORT = 0; +ENUM!{enum HIDP_REPORT_TYPE { + HidP_Input, + HidP_Output, + HidP_Feature, +}} +STRUCT!{struct USAGE_AND_PAGE { + Usage: USAGE, + UsagePage: USAGE, +}} +pub type PUSAGE_AND_PAGE = *mut USAGE_AND_PAGE; +// HidP_IsSameUsageAndPage +STRUCT!{struct HIDP_CAPS_Range { + UsageMin: USAGE, + UsageMax: USAGE, + StringMin: USHORT, + StringMax: USHORT, + DesignatorMin: USHORT, + DesignatorMax: USHORT, + DataIndexMin: USHORT, + DataIndexMax: USHORT, +}} +STRUCT!{struct HIDP_CAPS_NotRange { + Usage: USAGE, + Reserved1: USAGE, + StringIndex: USHORT, + Reserved2: USHORT, + DesignatorIndex: USHORT, + Reserved3: USHORT, + DataIndex: USHORT, + Reserved4: USHORT, +}} +UNION!{union HIDP_CAPS_u { + [u16; 8], + Range Range_mut: HIDP_CAPS_Range, + NotRange NotRange_mut: HIDP_CAPS_NotRange, +}} +STRUCT!{struct HIDP_BUTTON_CAPS { + UsagePage: USAGE, + ReportID: UCHAR, + IsAlias: BOOLEAN, + BitField: USHORT, + LinkCollection: USHORT, + LinkUsage: USAGE, + LinkUsagePage: USAGE, + IsRange: BOOLEAN, + IsStringRange: BOOLEAN, + IsDesignatorRange: BOOLEAN, + IsAbsolute: BOOLEAN, + Reserved: [ULONG; 10], + u: HIDP_CAPS_u, +}} +pub type PHIDP_BUTTON_CAPS = *mut HIDP_BUTTON_CAPS; +STRUCT!{struct HIDP_VALUE_CAPS { + UsagePage: USAGE, + ReportID: UCHAR, + IsAlias: BOOLEAN, + BitField: USHORT, + LinkCollection: USHORT, + LinkUsage: USAGE, + LinkUsagePage: USAGE, + IsRange: BOOLEAN, + IsStringRange: BOOLEAN, + IsDesignatorRange: BOOLEAN, + IsAbsolute: BOOLEAN, + HasNull: BOOLEAN, + Reserved: UCHAR, + BitSize: USHORT, + ReportCount: USHORT, + Reserved2: [USHORT; 5], + UnitsExp: ULONG, + Units: ULONG, + LogicalMin: LONG, + LogicalMax: LONG, + PhysicalMin: LONG, + PhysicalMax: LONG, + u: HIDP_CAPS_u, +}} +pub type PHIDP_VALUE_CAPS = *mut HIDP_VALUE_CAPS; +STRUCT!{struct HIDP_LINK_COLLECTION_NODE { + LinkUsage: USAGE, + LinkUsagePage: USAGE, + Parent: USHORT, + NumberOfChildren: USHORT, + NextSibling: USHORT, + FirstChild: USHORT, + bit_fields: ULONG, + UserContext: PVOID, +}} +BITFIELD!{HIDP_LINK_COLLECTION_NODE bit_fields: ULONG [ + CollectionType set_CollectionType[0..8], + IsAlias set_IsAlias[8..9], +]} +pub type PHIDP_LINK_COLLECTION_NODE = *mut HIDP_LINK_COLLECTION_NODE; +pub type PHIDP_REPORT_DESCRIPTOR = PUCHAR; +pub enum HIDP_PREPARSED_DATA {} +pub type PHIDP_PREPARSED_DATA = *mut HIDP_PREPARSED_DATA; +STRUCT!{struct HIDP_CAPS { + Usage: USAGE, + UsagePage: USAGE, + InputReportByteLength: USHORT, + OutputReportByteLength: USHORT, + FeatureReportByteLength: USHORT, + Reserved: [USHORT; 17], + NumberLinkCollectionNodes: USHORT, + NumberInputButtonCaps: USHORT, + NumberInputValueCaps: USHORT, + NumberInputDataIndices: USHORT, + NumberOutputButtonCaps: USHORT, + NumberOutputValueCaps: USHORT, + NumberOutputDataIndices: USHORT, + NumberFeatureButtonCaps: USHORT, + NumberFeatureValueCaps: USHORT, + NumberFeatureDataIndices: USHORT, +}} +pub type PHIDP_CAPS = *mut HIDP_CAPS; +UNION!{union HIDP_DATA_u { + [u32; 1], + RawValue RawValue_mut: ULONG, + On On_mut: BOOLEAN, +}} +STRUCT!{struct HIDP_DATA { + DataIndex: USHORT, + Reserved: USHORT, + u: HIDP_DATA_u, +}} +pub type PHIDP_DATA = *mut HIDP_DATA; +STRUCT!{struct HIDP_UNKNOWN_TOKEN { + Token: UCHAR, + Reserved: [UCHAR; 3], + BitField: ULONG, +}} +pub type PHIDP_UNKNOWN_TOKEN = *mut HIDP_UNKNOWN_TOKEN; +STRUCT!{struct HIDP_EXTENDED_ATTRIBUTES { + NumGlobalUnknowns: UCHAR, + Reserved: [UCHAR; 3], + GlobalUnknowns: PHIDP_UNKNOWN_TOKEN, + Data: [ULONG; 1], +}} +pub type PHIDP_EXTENDED_ATTRIBUTES = *mut HIDP_EXTENDED_ATTRIBUTES; +extern "system" { + pub fn HidP_GetCaps( + PreparsedData: PHIDP_PREPARSED_DATA, + Capabilities: PHIDP_CAPS, + ) -> NTSTATUS; + pub fn HidP_GetLinkCollectionNodes( + LinkCollectionNodes: PHIDP_LINK_COLLECTION_NODE, + LinkCollectionNodesLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> NTSTATUS; + pub fn HidP_GetSpecificButtonCaps( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + ButtonCaps: PHIDP_BUTTON_CAPS, + ButtonCapsLength: PUSHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> NTSTATUS; + pub fn HidP_GetButtonCaps( + ReportType: HIDP_REPORT_TYPE, + ButtonCaps: PHIDP_BUTTON_CAPS, + ButtonCapsLength: PUSHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> NTSTATUS; + pub fn HidP_GetSpecificValueCaps( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + ValueCaps: PHIDP_VALUE_CAPS, + ValueCapsLength: PUSHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> NTSTATUS; + pub fn HidP_GetValueCaps( + ReportType: HIDP_REPORT_TYPE, + ValueCaps: PHIDP_VALUE_CAPS, + ValueCapsLength: PUSHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> NTSTATUS; + pub fn HidP_GetExtendedAttributes( + ReportType: HIDP_REPORT_TYPE, + DataIndex: USHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + Attributes: PHIDP_EXTENDED_ATTRIBUTES, + LengthAttributes: PULONG, + ) -> NTSTATUS; + pub fn HidP_InitializeReportForID( + ReportType: HIDP_REPORT_TYPE, + ReportID: UCHAR, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_SetData( + ReportType: HIDP_REPORT_TYPE, + DataList: PHIDP_DATA, + DataLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetData( + ReportType: HIDP_REPORT_TYPE, + DataList: PHIDP_DATA, + DataLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_MaxDataListLength( + ReportType: HIDP_REPORT_TYPE, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> ULONG; + pub fn HidP_SetUsages( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + UsageList: PUSAGE, + UsageLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_UnsetUsages( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + UsageList: PUSAGE, + UsageLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetUsages( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + UsageList: PUSAGE, + UsageLength: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetUsagesEx( + ReportType: HIDP_REPORT_TYPE, + LinkCollection: USHORT, + ButtonList: PUSAGE_AND_PAGE, + UsageLength: *mut ULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_MaxUsageListLength( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> ULONG; + pub fn HidP_SetUsageValue( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: ULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_SetScaledUsageValue( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: LONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_SetUsageValueArray( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: PCHAR, + UsageValueByteLength: USHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetUsageValue( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: PULONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetScaledUsageValue( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: PLONG, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_GetUsageValueArray( + ReportType: HIDP_REPORT_TYPE, + UsagePage: USAGE, + LinkCollection: USHORT, + Usage: USAGE, + UsageValue: PCHAR, + UsageValueByteLength: USHORT, + PreparsedData: PHIDP_PREPARSED_DATA, + Report: PCHAR, + ReportLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_UsageListDifference( + PreviousUsageList: PUSAGE, + CurrentUsageList: PUSAGE, + BreakUsageList: PUSAGE, + MakeUsageList: PUSAGE, + UsageListLength: ULONG, + ) -> NTSTATUS; + pub fn HidP_TranslateUsagesToI8042ScanCodes( + ChangedUsageList: PUSAGE, + UsageListLength: ULONG, + KeyAction: HIDP_KEYBOARD_DIRECTION, + ModifierState: PHIDP_KEYBOARD_MODIFIER_STATE, + InsertCodesProcedure: PHIDP_INSERT_SCANCODES, + InsertCodesContext: PVOID, + ) -> NTSTATUS; +} +ENUM!{enum HIDP_KEYBOARD_DIRECTION { + HidP_Keyboard_Break, + HidP_Keyboard_Make, +}} +STRUCT!{struct HIDP_KEYBOARD_MODIFIER_STATE { + ul: ULONG, +}} +BITFIELD!{HIDP_KEYBOARD_MODIFIER_STATE ul: ULONG [ + LeftControl set_LeftControl[0..1], + LeftShift set_LeftShift[1..2], + LeftAlt set_LeftAlt[2..3], + LeftGUI set_LeftGUI[3..4], + RightControl set_RightControl[4..5], + RightShift set_RightShift[5..6], + RightAlt set_RightAlt[6..7], + RigthGUI set_RigthGUI[7..8], + CapsLock set_CapsLock[8..9], + ScollLock set_ScollLock[9..10], + NumLock set_NumLock[10..11], +]} +pub type PHIDP_KEYBOARD_MODIFIER_STATE = *mut HIDP_KEYBOARD_MODIFIER_STATE; +FN!{stdcall PHIDP_INSERT_SCANCODES( + Context: PVOID, + NewScanCodes: PCHAR, + Length: ULONG, +) -> BOOLEAN} +pub const HIDP_STATUS_SUCCESS: NTSTATUS = HIDP_ERROR_CODES!(0x0, 0); +pub const HIDP_STATUS_NULL: NTSTATUS = HIDP_ERROR_CODES!(0x8, 1); +pub const HIDP_STATUS_INVALID_PREPARSED_DATA: NTSTATUS = HIDP_ERROR_CODES!(0xC, 1); +pub const HIDP_STATUS_INVALID_REPORT_TYPE: NTSTATUS = HIDP_ERROR_CODES!(0xC, 2); +pub const HIDP_STATUS_INVALID_REPORT_LENGTH: NTSTATUS = HIDP_ERROR_CODES!(0xC, 3); +pub const HIDP_STATUS_USAGE_NOT_FOUND: NTSTATUS = HIDP_ERROR_CODES!(0xC, 4); +pub const HIDP_STATUS_VALUE_OUT_OF_RANGE: NTSTATUS = HIDP_ERROR_CODES!(0xC, 5); +pub const HIDP_STATUS_BAD_LOG_PHY_VALUES: NTSTATUS = HIDP_ERROR_CODES!(0xC, 6); +pub const HIDP_STATUS_BUFFER_TOO_SMALL: NTSTATUS = HIDP_ERROR_CODES!(0xC, 7); +pub const HIDP_STATUS_INTERNAL_ERROR: NTSTATUS = HIDP_ERROR_CODES!(0xC, 8); +pub const HIDP_STATUS_I8042_TRANS_UNKNOWN: NTSTATUS = HIDP_ERROR_CODES!(0xC, 9); +pub const HIDP_STATUS_INCOMPATIBLE_REPORT_ID: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xA); +pub const HIDP_STATUS_NOT_VALUE_ARRAY: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xB); +pub const HIDP_STATUS_IS_VALUE_ARRAY: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xC); +pub const HIDP_STATUS_DATA_INDEX_NOT_FOUND: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xD); +pub const HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xE); +pub const HIDP_STATUS_BUTTON_NOT_PRESSED: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0xF); +pub const HIDP_STATUS_REPORT_DOES_NOT_EXIST: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0x10); +pub const HIDP_STATUS_NOT_IMPLEMENTED: NTSTATUS = HIDP_ERROR_CODES!(0xC, 0x20); +pub const HIDP_STATUS_I8242_TRANS_UNKNOWN: NTSTATUS = HIDP_STATUS_I8042_TRANS_UNKNOWN; diff --git a/winapi/src/shared/hidsdi.rs b/winapi/src/shared/hidsdi.rs new file mode 100644 index 000000000..ebdd3ed4f --- /dev/null +++ b/winapi/src/shared/hidsdi.rs @@ -0,0 +1,110 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::LPGUID; +use shared::hidpi::PHIDP_PREPARSED_DATA; +use shared::minwindef::{PULONG, ULONG, USHORT}; +use um::winnt::{BOOLEAN, HANDLE, PVOID}; +STRUCT!{struct HIDD_CONFIGURATION { + cookie: PVOID, + size: ULONG, + RingBufferSize: ULONG, +}} +pub type PHIDD_CONFIGURATION = *mut HIDD_CONFIGURATION; +STRUCT!{struct HIDD_ATTRIBUTES { + Size: ULONG, + VendorID: USHORT, + ProductID: USHORT, + VersionNumber: USHORT, +}} +pub type PHIDD_ATTRIBUTES = *mut HIDD_ATTRIBUTES; +extern "system" { + pub fn HidD_GetAttributes( + HidDeviceObject: HANDLE, + Attributes: PHIDD_ATTRIBUTES, + ) -> BOOLEAN; + pub fn HidD_GetHidGuid( + HidGuid: LPGUID, + ); + pub fn HidD_GetPreparsedData( + HidDeviceObject: HANDLE, + PreparsedData: *mut PHIDP_PREPARSED_DATA, + ) -> BOOLEAN; + pub fn HidD_FreePreparsedData( + PreparsedData: PHIDP_PREPARSED_DATA, + ) -> BOOLEAN; + pub fn HidD_FlushQueue( + HidDeviceObject: HANDLE, + ) -> BOOLEAN; + pub fn HidD_GetConfiguration( + HidDeviceObject: HANDLE, + Configuration: PHIDD_CONFIGURATION, + ConfigurationLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_SetConfiguration( + HidDeviceObject: HANDLE, + Configuration: PHIDD_CONFIGURATION, + ConfigurationLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetFeature( + HidDeviceObject: HANDLE, + ReportBuffer: PVOID, + ReportBufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_SetFeature( + HidDeviceObject: HANDLE, + ReportBuffer: PVOID, + ReportBufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetInputReport( + HidDeviceObject: HANDLE, + ReportBuffer: PVOID, + ReportBufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_SetOutputReport( + HidDeviceObject: HANDLE, + ReportBuffer: PVOID, + ReportBufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetNumInputBuffers( + HidDeviceObject: HANDLE, + NumberBuffers: PULONG, + ) -> BOOLEAN; + pub fn HidD_SetNumInputBuffers( + HidDeviceObject: HANDLE, + NumberBuffers: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetPhysicalDescriptor( + HidDeviceObject: HANDLE, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetManufacturerString( + HidDeviceObject: HANDLE, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetProductString( + HidDeviceObject: HANDLE, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetIndexedString( + HidDeviceObject: HANDLE, + StringIndex: ULONG, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetSerialNumberString( + HidDeviceObject: HANDLE, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; + pub fn HidD_GetMsGenreDescriptor( + HidDeviceObject: HANDLE, + Buffer: PVOID, + BufferLength: ULONG, + ) -> BOOLEAN; +} diff --git a/winapi/src/shared/hidusage.rs b/winapi/src/shared/hidusage.rs new file mode 100644 index 000000000..a483bf27d --- /dev/null +++ b/winapi/src/shared/hidusage.rs @@ -0,0 +1,274 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::USHORT; +pub type USAGE = USHORT; +pub type PUSAGE = *mut USAGE; +pub const HID_USAGE_PAGE_UNDEFINED: USAGE = 0x00; +pub const HID_USAGE_PAGE_GENERIC: USAGE = 0x01; +pub const HID_USAGE_PAGE_SIMULATION: USAGE = 0x02; +pub const HID_USAGE_PAGE_VR: USAGE = 0x03; +pub const HID_USAGE_PAGE_SPORT: USAGE = 0x04; +pub const HID_USAGE_PAGE_GAME: USAGE = 0x05; +pub const HID_USAGE_PAGE_KEYBOARD: USAGE = 0x07; +pub const HID_USAGE_PAGE_LED: USAGE = 0x08; +pub const HID_USAGE_PAGE_BUTTON: USAGE = 0x09; +pub const HID_USAGE_PAGE_ORDINAL: USAGE = 0x0A; +pub const HID_USAGE_PAGE_TELEPHONY: USAGE = 0x0B; +pub const HID_USAGE_PAGE_CONSUMER: USAGE = 0x0C; +pub const HID_USAGE_PAGE_DIGITIZER: USAGE = 0x0D; +pub const HID_USAGE_PAGE_UNICODE: USAGE = 0x10; +pub const HID_USAGE_PAGE_ALPHANUMERIC: USAGE = 0x14; +pub const HID_USAGE_PAGE_SENSOR: USAGE = 0x20; +pub const HID_USAGE_PAGE_BARCODE_SCANNER: USAGE = 0x8C; +pub const HID_USAGE_PAGE_WEIGHING_DEVICE: USAGE = 0x8D; +pub const HID_USAGE_PAGE_MAGNETIC_STRIPE_READER: USAGE = 0x8E; +pub const HID_USAGE_PAGE_CAMERA_CONTROL: USAGE = 0x90; +pub const HID_USAGE_PAGE_MICROSOFT_BLUETOOTH_HANDSFREE: USAGE = 0xFFF3; +pub const HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN: USAGE = 0xFF00; +pub const HID_USAGE_PAGE_VENDOR_DEFINED_END: USAGE = 0xFFFF; +pub const HID_USAGE_GENERIC_POINTER: USAGE = 0x01; +pub const HID_USAGE_GENERIC_MOUSE: USAGE = 0x02; +pub const HID_USAGE_GENERIC_JOYSTICK: USAGE = 0x04; +pub const HID_USAGE_GENERIC_GAMEPAD: USAGE = 0x05; +pub const HID_USAGE_GENERIC_KEYBOARD: USAGE = 0x06; +pub const HID_USAGE_GENERIC_KEYPAD: USAGE = 0x07; +pub const HID_USAGE_GENERIC_PORTABLE_DEVICE_CONTROL: USAGE = 0x0D; +pub const HID_USAGE_GENERIC_SYSTEM_CTL: USAGE = 0x80; +pub const HID_USAGE_GENERIC_X: USAGE = 0x30; +pub const HID_USAGE_GENERIC_Y: USAGE = 0x31; +pub const HID_USAGE_GENERIC_Z: USAGE = 0x32; +pub const HID_USAGE_GENERIC_RX: USAGE = 0x33; +pub const HID_USAGE_GENERIC_RY: USAGE = 0x34; +pub const HID_USAGE_GENERIC_RZ: USAGE = 0x35; +pub const HID_USAGE_GENERIC_SLIDER: USAGE = 0x36; +pub const HID_USAGE_GENERIC_DIAL: USAGE = 0x37; +pub const HID_USAGE_GENERIC_WHEEL: USAGE = 0x38; +pub const HID_USAGE_GENERIC_HATSWITCH: USAGE = 0x39; +pub const HID_USAGE_GENERIC_COUNTED_BUFFER: USAGE = 0x3A; +pub const HID_USAGE_GENERIC_BYTE_COUNT: USAGE = 0x3B; +pub const HID_USAGE_GENERIC_MOTION_WAKEUP: USAGE = 0x3C; +pub const HID_USAGE_GENERIC_VX: USAGE = 0x40; +pub const HID_USAGE_GENERIC_VY: USAGE = 0x41; +pub const HID_USAGE_GENERIC_VZ: USAGE = 0x42; +pub const HID_USAGE_GENERIC_VBRX: USAGE = 0x43; +pub const HID_USAGE_GENERIC_VBRY: USAGE = 0x44; +pub const HID_USAGE_GENERIC_VBRZ: USAGE = 0x45; +pub const HID_USAGE_GENERIC_VNO: USAGE = 0x46; +pub const HID_USAGE_GENERIC_RESOLUTION_MULTIPLIER: USAGE = 0x48; +pub const HID_USAGE_GENERIC_SYSCTL_POWER: USAGE = 0x81; +pub const HID_USAGE_GENERIC_SYSCTL_SLEEP: USAGE = 0x82; +pub const HID_USAGE_GENERIC_SYSCTL_WAKE: USAGE = 0x83; +pub const HID_USAGE_GENERIC_SYSCTL_CONTEXT_MENU: USAGE = 0x84; +pub const HID_USAGE_GENERIC_SYSCTL_MAIN_MENU: USAGE = 0x85; +pub const HID_USAGE_GENERIC_SYSCTL_APP_MENU: USAGE = 0x86; +pub const HID_USAGE_GENERIC_SYSCTL_HELP_MENU: USAGE = 0x87; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_EXIT: USAGE = 0x88; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_SELECT: USAGE = 0x89; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_RIGHT: USAGE = 0x8A; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_LEFT: USAGE = 0x8B; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_UP: USAGE = 0x8C; +pub const HID_USAGE_GENERIC_SYSCTL_MENU_DOWN: USAGE = 0x8D; +pub const HID_USAGE_GENERIC_SYSTEM_DISPLAY_ROTATION_LOCK_BUTTON: USAGE = 0xC9; +pub const HID_USAGE_GENERIC_SYSTEM_DISPLAY_ROTATION_LOCK_SLIDER_SWITCH: USAGE = 0xCA; +pub const HID_USAGE_GENERIC_CONTROL_ENABLE: USAGE = 0xCB; +pub const HID_USAGE_SIMULATION_RUDDER: USAGE = 0xBA; +pub const HID_USAGE_SIMULATION_THROTTLE: USAGE = 0xBB; +pub const HID_USAGE_KEYBOARD_NOEVENT: USAGE = 0x00; +pub const HID_USAGE_KEYBOARD_ROLLOVER: USAGE = 0x01; +pub const HID_USAGE_KEYBOARD_POSTFAIL: USAGE = 0x02; +pub const HID_USAGE_KEYBOARD_UNDEFINED: USAGE = 0x03; +pub const HID_USAGE_KEYBOARD_aA: USAGE = 0x04; +pub const HID_USAGE_KEYBOARD_zZ: USAGE = 0x1D; +pub const HID_USAGE_KEYBOARD_ONE: USAGE = 0x1E; +pub const HID_USAGE_KEYBOARD_ZERO: USAGE = 0x27; +pub const HID_USAGE_KEYBOARD_LCTRL: USAGE = 0xE0; +pub const HID_USAGE_KEYBOARD_LSHFT: USAGE = 0xE1; +pub const HID_USAGE_KEYBOARD_LALT: USAGE = 0xE2; +pub const HID_USAGE_KEYBOARD_LGUI: USAGE = 0xE3; +pub const HID_USAGE_KEYBOARD_RCTRL: USAGE = 0xE4; +pub const HID_USAGE_KEYBOARD_RSHFT: USAGE = 0xE5; +pub const HID_USAGE_KEYBOARD_RALT: USAGE = 0xE6; +pub const HID_USAGE_KEYBOARD_RGUI: USAGE = 0xE7; +pub const HID_USAGE_KEYBOARD_SCROLL_LOCK: USAGE = 0x47; +pub const HID_USAGE_KEYBOARD_NUM_LOCK: USAGE = 0x53; +pub const HID_USAGE_KEYBOARD_CAPS_LOCK: USAGE = 0x39; +pub const HID_USAGE_KEYBOARD_F1: USAGE = 0x3A; +pub const HID_USAGE_KEYBOARD_F2: USAGE = 0x3B; +pub const HID_USAGE_KEYBOARD_F3: USAGE = 0x3C; +pub const HID_USAGE_KEYBOARD_F4: USAGE = 0x3D; +pub const HID_USAGE_KEYBOARD_F5: USAGE = 0x3E; +pub const HID_USAGE_KEYBOARD_F6: USAGE = 0x3F; +pub const HID_USAGE_KEYBOARD_F7: USAGE = 0x40; +pub const HID_USAGE_KEYBOARD_F8: USAGE = 0x41; +pub const HID_USAGE_KEYBOARD_F9: USAGE = 0x42; +pub const HID_USAGE_KEYBOARD_F10: USAGE = 0x43; +pub const HID_USAGE_KEYBOARD_F11: USAGE = 0x44; +pub const HID_USAGE_KEYBOARD_F12: USAGE = 0x45; +pub const HID_USAGE_KEYBOARD_F13: USAGE = 0x68; +pub const HID_USAGE_KEYBOARD_F14: USAGE = 0x69; +pub const HID_USAGE_KEYBOARD_F15: USAGE = 0x6A; +pub const HID_USAGE_KEYBOARD_F16: USAGE = 0x6B; +pub const HID_USAGE_KEYBOARD_F17: USAGE = 0x6C; +pub const HID_USAGE_KEYBOARD_F18: USAGE = 0x6D; +pub const HID_USAGE_KEYBOARD_F19: USAGE = 0x6E; +pub const HID_USAGE_KEYBOARD_F20: USAGE = 0x6F; +pub const HID_USAGE_KEYBOARD_F21: USAGE = 0x70; +pub const HID_USAGE_KEYBOARD_F22: USAGE = 0x71; +pub const HID_USAGE_KEYBOARD_F23: USAGE = 0x72; +pub const HID_USAGE_KEYBOARD_F24: USAGE = 0x73; +pub const HID_USAGE_KEYBOARD_RETURN: USAGE = 0x28; +pub const HID_USAGE_KEYBOARD_ESCAPE: USAGE = 0x29; +pub const HID_USAGE_KEYBOARD_DELETE: USAGE = 0x2A; +pub const HID_USAGE_KEYBOARD_PRINT_SCREEN: USAGE = 0x46; +pub const HID_USAGE_KEYBOARD_DELETE_FORWARD: USAGE = 0x4C; +pub const HID_USAGE_LED_NUM_LOCK: USAGE = 0x01; +pub const HID_USAGE_LED_CAPS_LOCK: USAGE = 0x02; +pub const HID_USAGE_LED_SCROLL_LOCK: USAGE = 0x03; +pub const HID_USAGE_LED_COMPOSE: USAGE = 0x04; +pub const HID_USAGE_LED_KANA: USAGE = 0x05; +pub const HID_USAGE_LED_POWER: USAGE = 0x06; +pub const HID_USAGE_LED_SHIFT: USAGE = 0x07; +pub const HID_USAGE_LED_DO_NOT_DISTURB: USAGE = 0x08; +pub const HID_USAGE_LED_MUTE: USAGE = 0x09; +pub const HID_USAGE_LED_TONE_ENABLE: USAGE = 0x0A; +pub const HID_USAGE_LED_HIGH_CUT_FILTER: USAGE = 0x0B; +pub const HID_USAGE_LED_LOW_CUT_FILTER: USAGE = 0x0C; +pub const HID_USAGE_LED_EQUALIZER_ENABLE: USAGE = 0x0D; +pub const HID_USAGE_LED_SOUND_FIELD_ON: USAGE = 0x0E; +pub const HID_USAGE_LED_SURROUND_FIELD_ON: USAGE = 0x0F; +pub const HID_USAGE_LED_REPEAT: USAGE = 0x10; +pub const HID_USAGE_LED_STEREO: USAGE = 0x11; +pub const HID_USAGE_LED_SAMPLING_RATE_DETECT: USAGE = 0x12; +pub const HID_USAGE_LED_SPINNING: USAGE = 0x13; +pub const HID_USAGE_LED_CAV: USAGE = 0x14; +pub const HID_USAGE_LED_CLV: USAGE = 0x15; +pub const HID_USAGE_LED_RECORDING_FORMAT_DET: USAGE = 0x16; +pub const HID_USAGE_LED_OFF_HOOK: USAGE = 0x17; +pub const HID_USAGE_LED_RING: USAGE = 0x18; +pub const HID_USAGE_LED_MESSAGE_WAITING: USAGE = 0x19; +pub const HID_USAGE_LED_DATA_MODE: USAGE = 0x1A; +pub const HID_USAGE_LED_BATTERY_OPERATION: USAGE = 0x1B; +pub const HID_USAGE_LED_BATTERY_OK: USAGE = 0x1C; +pub const HID_USAGE_LED_BATTERY_LOW: USAGE = 0x1D; +pub const HID_USAGE_LED_SPEAKER: USAGE = 0x1E; +pub const HID_USAGE_LED_HEAD_SET: USAGE = 0x1F; +pub const HID_USAGE_LED_HOLD: USAGE = 0x20; +pub const HID_USAGE_LED_MICROPHONE: USAGE = 0x21; +pub const HID_USAGE_LED_COVERAGE: USAGE = 0x22; +pub const HID_USAGE_LED_NIGHT_MODE: USAGE = 0x23; +pub const HID_USAGE_LED_SEND_CALLS: USAGE = 0x24; +pub const HID_USAGE_LED_CALL_PICKUP: USAGE = 0x25; +pub const HID_USAGE_LED_CONFERENCE: USAGE = 0x26; +pub const HID_USAGE_LED_STAND_BY: USAGE = 0x27; +pub const HID_USAGE_LED_CAMERA_ON: USAGE = 0x28; +pub const HID_USAGE_LED_CAMERA_OFF: USAGE = 0x29; +pub const HID_USAGE_LED_ON_LINE: USAGE = 0x2A; +pub const HID_USAGE_LED_OFF_LINE: USAGE = 0x2B; +pub const HID_USAGE_LED_BUSY: USAGE = 0x2C; +pub const HID_USAGE_LED_READY: USAGE = 0x2D; +pub const HID_USAGE_LED_PAPER_OUT: USAGE = 0x2E; +pub const HID_USAGE_LED_PAPER_JAM: USAGE = 0x2F; +pub const HID_USAGE_LED_REMOTE: USAGE = 0x30; +pub const HID_USAGE_LED_FORWARD: USAGE = 0x31; +pub const HID_USAGE_LED_REVERSE: USAGE = 0x32; +pub const HID_USAGE_LED_STOP: USAGE = 0x33; +pub const HID_USAGE_LED_REWIND: USAGE = 0x34; +pub const HID_USAGE_LED_FAST_FORWARD: USAGE = 0x35; +pub const HID_USAGE_LED_PLAY: USAGE = 0x36; +pub const HID_USAGE_LED_PAUSE: USAGE = 0x37; +pub const HID_USAGE_LED_RECORD: USAGE = 0x38; +pub const HID_USAGE_LED_ERROR: USAGE = 0x39; +pub const HID_USAGE_LED_SELECTED_INDICATOR: USAGE = 0x3A; +pub const HID_USAGE_LED_IN_USE_INDICATOR: USAGE = 0x3B; +pub const HID_USAGE_LED_MULTI_MODE_INDICATOR: USAGE = 0x3C; +pub const HID_USAGE_LED_INDICATOR_ON: USAGE = 0x3D; +pub const HID_USAGE_LED_INDICATOR_FLASH: USAGE = 0x3E; +pub const HID_USAGE_LED_INDICATOR_SLOW_BLINK: USAGE = 0x3F; +pub const HID_USAGE_LED_INDICATOR_FAST_BLINK: USAGE = 0x40; +pub const HID_USAGE_LED_INDICATOR_OFF: USAGE = 0x41; +pub const HID_USAGE_LED_FLASH_ON_TIME: USAGE = 0x42; +pub const HID_USAGE_LED_SLOW_BLINK_ON_TIME: USAGE = 0x43; +pub const HID_USAGE_LED_SLOW_BLINK_OFF_TIME: USAGE = 0x44; +pub const HID_USAGE_LED_FAST_BLINK_ON_TIME: USAGE = 0x45; +pub const HID_USAGE_LED_FAST_BLINK_OFF_TIME: USAGE = 0x46; +pub const HID_USAGE_LED_INDICATOR_COLOR: USAGE = 0x47; +pub const HID_USAGE_LED_RED: USAGE = 0x48; +pub const HID_USAGE_LED_GREEN: USAGE = 0x49; +pub const HID_USAGE_LED_AMBER: USAGE = 0x4A; +pub const HID_USAGE_LED_GENERIC_INDICATOR: USAGE = 0x4B; +pub const HID_USAGE_TELEPHONY_PHONE: USAGE = 0x01; +pub const HID_USAGE_TELEPHONY_ANSWERING_MACHINE: USAGE = 0x02; +pub const HID_USAGE_TELEPHONY_MESSAGE_CONTROLS: USAGE = 0x03; +pub const HID_USAGE_TELEPHONY_HANDSET: USAGE = 0x04; +pub const HID_USAGE_TELEPHONY_HEADSET: USAGE = 0x05; +pub const HID_USAGE_TELEPHONY_KEYPAD: USAGE = 0x06; +pub const HID_USAGE_TELEPHONY_PROGRAMMABLE_BUTTON: USAGE = 0x07; +pub const HID_USAGE_TELEPHONY_REDIAL: USAGE = 0x24; +pub const HID_USAGE_TELEPHONY_TRANSFER: USAGE = 0x25; +pub const HID_USAGE_TELEPHONY_DROP: USAGE = 0x26; +pub const HID_USAGE_TELEPHONY_LINE: USAGE = 0x2A; +pub const HID_USAGE_TELEPHONY_RING_ENABLE: USAGE = 0x2D; +pub const HID_USAGE_TELEPHONY_SEND: USAGE = 0x31; +pub const HID_USAGE_TELEPHONY_KEYPAD_0: USAGE = 0xB0; +pub const HID_USAGE_TELEPHONY_KEYPAD_D: USAGE = 0xBF; +pub const HID_USAGE_TELEPHONY_HOST_AVAILABLE: USAGE = 0xF1; +pub const HID_USAGE_CONSUMERCTRL: USAGE = 0x01; +pub const HID_USAGE_CONSUMER_CHANNEL_INCREMENT: USAGE = 0x9C; +pub const HID_USAGE_CONSUMER_CHANNEL_DECREMENT: USAGE = 0x9D; +pub const HID_USAGE_CONSUMER_PLAY: USAGE = 0xB0; +pub const HID_USAGE_CONSUMER_PAUSE: USAGE = 0xB1; +pub const HID_USAGE_CONSUMER_RECORD: USAGE = 0xB2; +pub const HID_USAGE_CONSUMER_FAST_FORWARD: USAGE = 0xB3; +pub const HID_USAGE_CONSUMER_REWIND: USAGE = 0xB4; +pub const HID_USAGE_CONSUMER_SCAN_NEXT_TRACK: USAGE = 0xB5; +pub const HID_USAGE_CONSUMER_SCAN_PREV_TRACK: USAGE = 0xB6; +pub const HID_USAGE_CONSUMER_STOP: USAGE = 0xB7; +pub const HID_USAGE_CONSUMER_PLAY_PAUSE: USAGE = 0xCD; +pub const HID_USAGE_CONSUMER_VOLUME: USAGE = 0xE0; +pub const HID_USAGE_CONSUMER_BALANCE: USAGE = 0xE1; +pub const HID_USAGE_CONSUMER_MUTE: USAGE = 0xE2; +pub const HID_USAGE_CONSUMER_BASS: USAGE = 0xE3; +pub const HID_USAGE_CONSUMER_TREBLE: USAGE = 0xE4; +pub const HID_USAGE_CONSUMER_BASS_BOOST: USAGE = 0xE5; +pub const HID_USAGE_CONSUMER_SURROUND_MODE: USAGE = 0xE6; +pub const HID_USAGE_CONSUMER_LOUDNESS: USAGE = 0xE7; +pub const HID_USAGE_CONSUMER_MPX: USAGE = 0xE8; +pub const HID_USAGE_CONSUMER_VOLUME_INCREMENT: USAGE = 0xE9; +pub const HID_USAGE_CONSUMER_VOLUME_DECREMENT: USAGE = 0xEA; +pub const HID_USAGE_CONSUMER_BASS_INCREMENT: USAGE = 0x152; +pub const HID_USAGE_CONSUMER_BASS_DECREMENT: USAGE = 0x153; +pub const HID_USAGE_CONSUMER_TREBLE_INCREMENT: USAGE = 0x154; +pub const HID_USAGE_CONSUMER_TREBLE_DECREMENT: USAGE = 0x155; +pub const HID_USAGE_CONSUMER_AL_CONFIGURATION: USAGE = 0x183; +pub const HID_USAGE_CONSUMER_AL_EMAIL: USAGE = 0x18A; +pub const HID_USAGE_CONSUMER_AL_CALCULATOR: USAGE = 0x192; +pub const HID_USAGE_CONSUMER_AL_BROWSER: USAGE = 0x194; +pub const HID_USAGE_CONSUMER_AC_SEARCH: USAGE = 0x221; +pub const HID_USAGE_CONSUMER_AC_GOTO: USAGE = 0x222; +pub const HID_USAGE_CONSUMER_AC_HOME: USAGE = 0x223; +pub const HID_USAGE_CONSUMER_AC_BACK: USAGE = 0x224; +pub const HID_USAGE_CONSUMER_AC_FORWARD: USAGE = 0x225; +pub const HID_USAGE_CONSUMER_AC_STOP: USAGE = 0x226; +pub const HID_USAGE_CONSUMER_AC_REFRESH: USAGE = 0x227; +pub const HID_USAGE_CONSUMER_AC_PREVIOUS: USAGE = 0x228; +pub const HID_USAGE_CONSUMER_AC_NEXT: USAGE = 0x229; +pub const HID_USAGE_CONSUMER_AC_BOOKMARKS: USAGE = 0x22A; +pub const HID_USAGE_CONSUMER_AC_PAN: USAGE = 0x238; +pub const HID_USAGE_CONSUMER_EXTENDED_KEYBOARD_ATTRIBUTES_COLLECTION: USAGE = 0x2C0; +pub const HID_USAGE_CONSUMER_KEYBOARD_FORM_FACTOR: USAGE = 0x2C1; +pub const HID_USAGE_CONSUMER_KEYBOARD_KEY_TYPE: USAGE = 0x2C2; +pub const HID_USAGE_CONSUMER_KEYBOARD_PHYSICAL_LAYOUT: USAGE = 0x2C3; +pub const HID_USAGE_CONSUMER_VENDOR_SPECIFIC_KEYBOARD_PHYSICAL_LAYOUT: USAGE = 0x2C4; +pub const HID_USAGE_CONSUMER_KEYBOARD_IETF_LANGUAGE_TAG_INDEX: USAGE = 0x2C5; +pub const HID_USAGE_CONSUMER_IMPLEMENTED_KEYBOARD_INPUT_ASSIST_CONTROLS: USAGE = 0x2C6; +pub const HID_USAGE_DIGITIZER_PEN: USAGE = 0x02; +pub const HID_USAGE_DIGITIZER_IN_RANGE: USAGE = 0x32; +pub const HID_USAGE_DIGITIZER_TIP_SWITCH: USAGE = 0x42; +pub const HID_USAGE_DIGITIZER_BARREL_SWITCH: USAGE = 0x44; +pub const HID_USAGE_CAMERA_AUTO_FOCUS: USAGE = 0x20; +pub const HID_USAGE_CAMERA_SHUTTER: USAGE = 0x21; +pub const HID_USAGE_MS_BTH_HF_DIALNUMBER: USAGE = 0x21; +pub const HID_USAGE_MS_BTH_HF_DIALMEMORY: USAGE = 0x22; diff --git a/winapi/src/shared/ifdef.rs b/winapi/src/shared/ifdef.rs new file mode 100644 index 000000000..e64527a3f --- /dev/null +++ b/winapi/src/shared/ifdef.rs @@ -0,0 +1,22 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{UINT16, ULONG64}; +use shared::minwindef::ULONG; +STRUCT!{struct NET_LUID_LH { + Value: ULONG64, +}} +BITFIELD!{NET_LUID_LH Value: ULONG64 [ + Reserved set_Reserved[0..24], + NetLuidIndex set_NetLuidIndex[24..48], + IfType set_IfType[48..64], +]} +pub type PNET_LUID_LH = *mut NET_LUID_LH; +pub type NET_LUID = NET_LUID_LH; +pub type PNET_LUID = *mut NET_LUID; +pub type NET_IFINDEX = ULONG; +pub type PNET_IFINDEX = *mut ULONG; +pub type NET_IFTYPE = UINT16; +pub type PNET_IFTYPE = *mut UINT16; diff --git a/winapi/src/shared/in6addr.rs b/winapi/src/shared/in6addr.rs new file mode 100644 index 000000000..6ed9382e6 --- /dev/null +++ b/winapi/src/shared/in6addr.rs @@ -0,0 +1,17 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{UCHAR, USHORT}; +UNION!{union in6_addr_u { + [u16; 8], + Byte Byte_mut: [UCHAR; 16], + Word Word_mut: [USHORT; 8], +}} +STRUCT!{struct in6_addr { + u: in6_addr_u, +}} +pub type IN6_ADDR = in6_addr; +pub type PIN6_ADDR = *mut IN6_ADDR; +pub type LPIN6_ADDR = *mut IN6_ADDR; diff --git a/winapi/src/shared/inaddr.rs b/winapi/src/shared/inaddr.rs new file mode 100644 index 000000000..c56e1ea8b --- /dev/null +++ b/winapi/src/shared/inaddr.rs @@ -0,0 +1,29 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! IPv4 Internet address +use shared::minwindef::{UCHAR, ULONG, USHORT}; +STRUCT!{struct in_addr_S_un_b { + s_b1: UCHAR, + s_b2: UCHAR, + s_b3: UCHAR, + s_b4: UCHAR, +}} +STRUCT!{struct in_addr_S_un_w { + s_w1: USHORT, + s_w2: USHORT, +}} +UNION!{union in_addr_S_un { + [u32; 1], + S_un_b S_un_b_mut: in_addr_S_un_b, + S_un_w S_un_w_mut: in_addr_S_un_w, + S_addr S_addr_mut: ULONG, +}} +STRUCT!{struct in_addr { + S_un: in_addr_S_un, +}} +pub type IN_ADDR = in_addr; +pub type PIN_ADDR = *mut in_addr; +pub type LPIN_ADDR = *mut in_addr; diff --git a/winapi/src/shared/intsafe.rs b/winapi/src/shared/intsafe.rs new file mode 100644 index 000000000..916dc0e1a --- /dev/null +++ b/winapi/src/shared/intsafe.rs @@ -0,0 +1,5 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. diff --git a/winapi/src/shared/ks.rs b/winapi/src/shared/ks.rs new file mode 100644 index 000000000..3a2ab103c --- /dev/null +++ b/winapi/src/shared/ks.rs @@ -0,0 +1,63 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +// Licensed under the MIT License <LICENSE.md> +//! Mappings for the contents of ks.h +DEFINE_GUID!{KSCATEGORY_BRIDGE, + 0x085AFF00, 0x62CE, 0x11CF, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_CAPTURE, + 0x65E8773D, 0x8F56, 0x11D0, 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_VIDEO_CAMERA, + 0xe5323777, 0xf976, 0x4f5b, 0x9b, 0x55, 0xb9, 0x46, 0x99, 0xc4, 0x6e, 0x44} +DEFINE_GUID!{KSCATEGORY_SENSOR_CAMERA, + 0x24e552d7, 0x6523, 0x47f7, 0xa6, 0x47, 0xd3, 0x46, 0x5b, 0xf1, 0xf5, 0xca} +DEFINE_GUID!{KSCATEGORY_SENSOR_GROUP, + 0x669C7214, 0x0A88, 0x4311, 0xA7, 0xF3, 0x4E, 0x79, 0x82, 0x0E, 0x33, 0xBD} +DEFINE_GUID!{KSCATEGORY_RENDER, + 0x65E8773E, 0x8F56, 0x11D0, 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_MIXER, + 0xAD809C00, 0x7B88, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_SPLITTER, + 0x0A4252A0, 0x7E70, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_DATACOMPRESSOR, + 0x1E84C900, 0x7E70, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_DATADECOMPRESSOR, + 0x2721AE20, 0x7E70, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_DATATRANSFORM, + 0x2EB07EA0, 0x7E70, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSMFT_CATEGORY_VIDEO_DECODER, + 0xd6c02d4b, 0x6833, 0x45b4, 0x97, 0x1a, 0x05, 0xa4, 0xb0, 0x4b, 0xab, 0x91} +DEFINE_GUID!{KSMFT_CATEGORY_VIDEO_ENCODER, + 0xf79eac7d, 0xe545, 0x4387, 0xbd, 0xee, 0xd6, 0x47, 0xd7, 0xbd, 0xe4, 0x2a} +DEFINE_GUID!{KSMFT_CATEGORY_VIDEO_EFFECT, + 0x12e17c21, 0x532c, 0x4a6e, 0x8a, 0x1c, 0x40, 0x82, 0x5a, 0x73, 0x63, 0x97} +DEFINE_GUID!{KSMFT_CATEGORY_MULTIPLEXER, + 0x059c561e, 0x05ae, 0x4b61, 0xb6, 0x9d, 0x55, 0xb6, 0x1e, 0xe5, 0x4a, 0x7b} +DEFINE_GUID!{KSMFT_CATEGORY_DEMULTIPLEXER, + 0xa8700a7a, 0x939b, 0x44c5, 0x99, 0xd7, 0x76, 0x22, 0x6b, 0x23, 0xb3, 0xf1} +DEFINE_GUID!{KSMFT_CATEGORY_AUDIO_DECODER, + 0x9ea73fb4, 0xef7a, 0x4559, 0x8d, 0x5d, 0x71, 0x9d, 0x8f, 0x04, 0x26, 0xc7} +DEFINE_GUID!{KSMFT_CATEGORY_AUDIO_ENCODER, + 0x91c64bd0, 0xf91e, 0x4d8c, 0x92, 0x76, 0xdb, 0x24, 0x82, 0x79, 0xd9, 0x75} +DEFINE_GUID!{KSMFT_CATEGORY_AUDIO_EFFECT, + 0x11064c48, 0x3648, 0x4ed0, 0x93, 0x2e, 0x05, 0xce, 0x8a, 0xc8, 0x11, 0xb7} +DEFINE_GUID!{KSMFT_CATEGORY_VIDEO_PROCESSOR, + 0x302ea3fc, 0xaa5f, 0x47f9, 0x9f, 0x7a, 0xc2, 0x18, 0x8b, 0xb1, 0x63, 0x02} +DEFINE_GUID!{KSMFT_CATEGORY_OTHER, + 0x90175d57, 0xb7ea, 0x4901, 0xae, 0xb3, 0x93, 0x3a, 0x87, 0x47, 0x75, 0x6f} +DEFINE_GUID!{KSCATEGORY_COMMUNICATIONSTRANSFORM, + 0xCF1DDA2C, 0x9743, 0x11D0, 0xA3, 0xEE, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_INTERFACETRANSFORM, + 0xCF1DDA2D, 0x9743, 0x11D0, 0xA3, 0xEE, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_MEDIUMTRANSFORM, + 0xCF1DDA2E, 0x9743, 0x11D0, 0xA3, 0xEE, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_FILESYSTEM, + 0x760FED5E, 0x9357, 0x11D0, 0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_CLOCK, + 0x53172480, 0x4791, 0x11D0, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_PROXY, + 0x97EBAACA, 0x95BD, 0x11D0, 0xA3, 0xEA, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_QUALITY, + 0x97EBAACB, 0x95BD, 0x11D0, 0xA3, 0xEA, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} diff --git a/winapi/src/shared/ksmedia.rs b/winapi/src/shared/ksmedia.rs new file mode 100644 index 000000000..01d390d3c --- /dev/null +++ b/winapi/src/shared/ksmedia.rs @@ -0,0 +1,59 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +// Licensed under the MIT License <LICENSE.md> +//! Mappings for the contents of ksmedia.h +DEFINE_GUID!{KSCATEGORY_AUDIO, + 0x6994AD04, 0x93EF, 0x11D0, 0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_VIDEO, + 0x6994AD05, 0x93EF, 0x11D0, 0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_REALTIME, + 0xEB115FFC, 0x10C8, 0x4964, 0x83, 0x1D, 0x6D, 0xCB, 0x02, 0xE6, 0xF2, 0x3F} +DEFINE_GUID!{KSCATEGORY_TEXT, + 0x6994AD06, 0x93EF, 0x11D0, 0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_NETWORK, + 0x67C9CC3C, 0x69C4, 0x11D2, 0x87, 0x59, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_TOPOLOGY, + 0xDDA54A40, 0x1E4C, 0x11D1, 0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00} +DEFINE_GUID!{KSCATEGORY_VIRTUAL, + 0x3503EAC4, 0x1F26, 0x11D1, 0x8A, 0xB0, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSCATEGORY_ACOUSTIC_ECHO_CANCEL, + 0xBF963D80, 0xC559, 0x11D0, 0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1} +DEFINE_GUID!{KSCATEGORY_SYSAUDIO, + 0xA7C7A5B1, 0x5AF3, 0x11D1, 0x9C, 0xED, 0x00, 0xA0, 0x24, 0xBF, 0x04, 0x07} +DEFINE_GUID!{KSCATEGORY_WDMAUD, + 0x3E227E76, 0x690D, 0x11D2, 0x81, 0x61, 0x00, 0x00, 0xF8, 0x77, 0x5B, 0xF1} +DEFINE_GUID!{KSCATEGORY_AUDIO_GFX, + 0x9BAF9572, 0x340C, 0x11D3, 0xAB, 0xDC, 0x00, 0xA0, 0xC9, 0x0A, 0xB1, 0x6F} +DEFINE_GUID!{KSCATEGORY_AUDIO_SPLITTER, + 0x9EA331FA, 0xB91B, 0x45F8, 0x92, 0x85, 0xBD, 0x2B, 0xC7, 0x7A, 0xFC, 0xDE} +DEFINE_GUID!{KSCATEGORY_AUDIO_DEVICE, + 0xFBF6F530, 0x07B9, 0x11D2, 0xA7, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88} +DEFINE_GUID!{KSCATEGORY_PREFERRED_WAVEOUT_DEVICE, + 0xD6C5066E, 0x72C1, 0x11D2, 0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88} +DEFINE_GUID!{KSCATEGORY_PREFERRED_WAVEIN_DEVICE, + 0xD6C50671, 0x72C1, 0x11D2, 0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88} +DEFINE_GUID!{KSCATEGORY_PREFERRED_MIDIOUT_DEVICE, + 0xD6C50674, 0x72C1, 0x11D2, 0x97, 0x55, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88} +DEFINE_GUID!{KSCATEGORY_WDMAUD_USE_PIN_NAME, + 0x47A4FA20, 0xA251, 0x11D1, 0xA0, 0x50, 0x00, 0x00, 0xF8, 0x00, 0x47, 0x88} +DEFINE_GUID!{KSCATEGORY_ESCALANTE_PLATFORM_DRIVER, + 0x74F3AEA8, 0x9768, 0x11D1, 0x8E, 0x07, 0x00, 0xA0, 0xC9, 0x5E, 0xC2, 0x2E} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_ANALOG, + 0x6DBA3190, 0x67BD, 0x11CF, 0xA0, 0xF7, 0x00, 0x20, 0xAF, 0xD1, 0x56, 0xE4} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_PCM, + 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, + 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_DRM, + 0x00000009, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_ALAW, + 0x00000006, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_MULAW, + 0x00000007, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_ADPCM, + 0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_MPEG, + 0x00000050, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71} diff --git a/winapi/src/shared/ktmtypes.rs b/winapi/src/shared/ktmtypes.rs new file mode 100644 index 000000000..77394e2d5 --- /dev/null +++ b/winapi/src/shared/ktmtypes.rs @@ -0,0 +1,138 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Common types for KTM exposed at both the Nt- and Win32-layer +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, ULONG}; +use um::winnt::{LARGE_INTEGER, PVOID, WCHAR}; +pub type UOW = GUID; +pub type PUOW = *mut GUID; +pub type CRM_PROTOCOL_ID = GUID; +pub type PCRM_PROTOCOL_ID = *mut GUID; +pub const TRANSACTION_MANAGER_VOLATILE: ULONG = 0x00000001; +pub const TRANSACTION_MANAGER_COMMIT_DEFAULT: ULONG = 0x00000000; +pub const TRANSACTION_MANAGER_COMMIT_SYSTEM_VOLUME: ULONG = 0x00000002; +pub const TRANSACTION_MANAGER_COMMIT_SYSTEM_HIVES: ULONG = 0x00000004; +pub const TRANSACTION_MANAGER_COMMIT_LOWEST: ULONG = 0x00000008; +pub const TRANSACTION_MANAGER_CORRUPT_FOR_RECOVERY: ULONG = 0x00000010; +pub const TRANSACTION_MANAGER_CORRUPT_FOR_PROGRESS: ULONG = 0x00000020; +pub const TRANSACTION_MANAGER_MAXIMUM_OPTION: ULONG = 0x0000003F; +pub const TRANSACTION_DO_NOT_PROMOTE: DWORD = 0x00000001; +pub const TRANSACTION_MAXIMUM_OPTION: DWORD = 0x00000001; +pub const RESOURCE_MANAGER_VOLATILE: DWORD = 0x00000001; +pub const RESOURCE_MANAGER_COMMUNICATION: DWORD = 0x00000002; +pub const RESOURCE_MANAGER_MAXIMUM_OPTION: DWORD = 0x00000003; +pub const CRM_PROTOCOL_EXPLICIT_MARSHAL_ONLY: DWORD = 0x00000001; +pub const CRM_PROTOCOL_DYNAMIC_MARSHAL_INFO: DWORD = 0x00000002; +pub const CRM_PROTOCOL_MAXIMUM_OPTION: DWORD = 0x00000003; +pub const ENLISTMENT_SUPERIOR: ULONG = 0x00000001; +pub const ENLISTMENT_MAXIMUM_OPTION: ULONG = 0x00000001; +pub type NOTIFICATION_MASK = ULONG; +pub const TRANSACTION_NOTIFY_MASK: ULONG = 0x3FFFFFFF; +pub const TRANSACTION_NOTIFY_PREPREPARE: ULONG = 0x00000001; +pub const TRANSACTION_NOTIFY_PREPARE: ULONG = 0x00000002; +pub const TRANSACTION_NOTIFY_COMMIT: ULONG = 0x00000004; +pub const TRANSACTION_NOTIFY_ROLLBACK: ULONG = 0x00000008; +pub const TRANSACTION_NOTIFY_PREPREPARE_COMPLETE: ULONG = 0x00000010; +pub const TRANSACTION_NOTIFY_PREPARE_COMPLETE: ULONG = 0x00000020; +pub const TRANSACTION_NOTIFY_COMMIT_COMPLETE: ULONG = 0x00000040; +pub const TRANSACTION_NOTIFY_ROLLBACK_COMPLETE: ULONG = 0x00000080; +pub const TRANSACTION_NOTIFY_RECOVER: ULONG = 0x00000100; +pub const TRANSACTION_NOTIFY_SINGLE_PHASE_COMMIT: ULONG = 0x00000200; +pub const TRANSACTION_NOTIFY_DELEGATE_COMMIT: ULONG = 0x00000400; +pub const TRANSACTION_NOTIFY_RECOVER_QUERY: ULONG = 0x00000800; +pub const TRANSACTION_NOTIFY_ENLIST_PREPREPARE: ULONG = 0x00001000; +pub const TRANSACTION_NOTIFY_LAST_RECOVER: ULONG = 0x00002000; +pub const TRANSACTION_NOTIFY_INDOUBT: ULONG = 0x00004000; +pub const TRANSACTION_NOTIFY_PROPAGATE_PULL: ULONG = 0x00008000; +pub const TRANSACTION_NOTIFY_PROPAGATE_PUSH: ULONG = 0x00010000; +pub const TRANSACTION_NOTIFY_MARSHAL: ULONG = 0x00020000; +pub const TRANSACTION_NOTIFY_ENLIST_MASK: ULONG = 0x00040000; +pub const TRANSACTION_NOTIFY_RM_DISCONNECTED: ULONG = 0x01000000; +pub const TRANSACTION_NOTIFY_TM_ONLINE: ULONG = 0x02000000; +pub const TRANSACTION_NOTIFY_COMMIT_REQUEST: ULONG = 0x04000000; +pub const TRANSACTION_NOTIFY_PROMOTE: ULONG = 0x08000000; +pub const TRANSACTION_NOTIFY_PROMOTE_NEW: ULONG = 0x10000000; +pub const TRANSACTION_NOTIFY_REQUEST_OUTCOME: ULONG = 0x20000000; +pub const TRANSACTION_NOTIFY_COMMIT_FINALIZE: ULONG = 0x40000000; +pub const TRANSACTIONMANAGER_OBJECT_PATH: &'static str = "\\TransactionManager\\"; +pub const TRANSACTION_OBJECT_PATH: &'static str = "\\Transaction\\"; +pub const ENLISTMENT_OBJECT_PATH: &'static str = "\\Enlistment\\"; +pub const RESOURCE_MANAGER_OBJECT_PATH: &'static str = "\\ResourceManager\\"; +STRUCT!{struct TRANSACTION_NOTIFICATION { + TransactionKey: PVOID, + TransactionNotification: ULONG, + TmVirtualClock: LARGE_INTEGER, + ArgumentLength: ULONG, +}} +pub type PTRANSACTION_NOTIFICATION = *mut TRANSACTION_NOTIFICATION; +STRUCT!{struct TRANSACTION_NOTIFICATION_RECOVERY_ARGUMENT { + EnlistmentId: GUID, + UOW: UOW, +}} +pub type PTRANSACTION_NOTIFICATION_RECOVERY_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_RECOVERY_ARGUMENT; +pub const TRANSACTION_NOTIFICATION_TM_ONLINE_FLAG_IS_CLUSTERED: ULONG = 0x1; +STRUCT!{struct TRANSACTION_NOTIFICATION_TM_ONLINE_ARGUMENT { + TmIdentity: GUID, + Flags: ULONG, +}} +pub type PTRANSACTION_NOTIFICATION_TM_ONLINE_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_TM_ONLINE_ARGUMENT; +pub type SAVEPOINT_ID = ULONG; +pub type PSAVEPOINT_ID = *mut ULONG; +STRUCT!{struct TRANSACTION_NOTIFICATION_SAVEPOINT_ARGUMENT { + SavepointId: SAVEPOINT_ID, +}} +pub type PTRANSACTION_NOTIFICATION_SAVEPOINT_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_SAVEPOINT_ARGUMENT; +STRUCT!{struct TRANSACTION_NOTIFICATION_PROPAGATE_ARGUMENT { + PropagationCookie: ULONG, + UOW: GUID, + TmIdentity: GUID, + BufferLength: ULONG, +}} +pub type PTRANSACTION_NOTIFICATION_PROPAGATE_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_PROPAGATE_ARGUMENT; +STRUCT!{struct TRANSACTION_NOTIFICATION_MARSHAL_ARGUMENT { + MarshalCookie: ULONG, + UOW: GUID, +}} +pub type PTRANSACTION_NOTIFICATION_MARSHAL_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_MARSHAL_ARGUMENT; +pub type TRANSACTION_NOTIFICATION_PROMOTE_ARGUMENT = TRANSACTION_NOTIFICATION_PROPAGATE_ARGUMENT; +pub type PTRANSACTION_NOTIFICATION_PROMOTE_ARGUMENT + = *mut TRANSACTION_NOTIFICATION_PROPAGATE_ARGUMENT; +pub const KTM_MARSHAL_BLOB_VERSION_MAJOR: ULONG = 1; +pub const KTM_MARSHAL_BLOB_VERSION_MINOR: ULONG = 1; +pub const MAX_TRANSACTION_DESCRIPTION_LENGTH: usize = 64; +pub const MAX_RESOURCEMANAGER_DESCRIPTION_LENGTH: usize = 64; +STRUCT!{struct KCRM_MARSHAL_HEADER { + VersionMajor: ULONG, + VersionMinor: ULONG, + NumProtocols: ULONG, + Unused: ULONG, +}} +pub type PKCRM_MARSHAL_HEADER = *mut KCRM_MARSHAL_HEADER; +pub type PRKCRM_MARSHAL_HEADER = *mut KCRM_MARSHAL_HEADER; +STRUCT!{struct KCRM_TRANSACTION_BLOB { + UOW: UOW, + TmIdentity: GUID, + IsolationLevel: ULONG, + IsolationFlags: ULONG, + Timeout: ULONG, + Description: [WCHAR; MAX_TRANSACTION_DESCRIPTION_LENGTH], +}} +pub type PKCRM_TRANSACTION_BLOB = *mut KCRM_TRANSACTION_BLOB; +pub type PRKCRM_TRANSACTION_BLOB = *mut KCRM_TRANSACTION_BLOB; +STRUCT!{struct KCRM_PROTOCOL_BLOB { + ProtocolId: CRM_PROTOCOL_ID, + StaticInfoLength: ULONG, + TransactionIdInfoLength: ULONG, + Unused1: ULONG, + Unused2: ULONG, +}} +pub type PKCRM_PROTOCOL_BLOB = *mut KCRM_PROTOCOL_BLOB; +pub type PRKCRM_PROTOCOL_BLOB = *mut KCRM_PROTOCOL_BLOB; diff --git a/winapi/src/shared/lmcons.rs b/winapi/src/shared/lmcons.rs new file mode 100644 index 000000000..ca2819b4f --- /dev/null +++ b/winapi/src/shared/lmcons.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains constants used throughout the LAN Manager API header files. +use shared::minwindef::DWORD; +use um::winnt::{LPCWSTR, LPWSTR}; +pub const CNLEN: DWORD = 15; +pub const LM20_CNLEN: DWORD = 15; +pub const DNLEN: DWORD = CNLEN; +pub const LM20_DNLEN: DWORD = LM20_CNLEN; +pub const UNCLEN: DWORD = CNLEN + 2; +pub const LM20_UNCLEN: DWORD = LM20_CNLEN + 2; +pub const NNLEN: DWORD = 80; +pub const LM20_NNLEN: DWORD = 12; +pub const RMLEN: DWORD = UNCLEN + 1 + NNLEN; +pub const LM20_RMLEN: DWORD = LM20_UNCLEN + 1 + LM20_NNLEN; +pub const SNLEN: usize = 80; +pub const LM20_SNLEN: DWORD = 15; +pub const STXTLEN: DWORD = 256; +pub const LM20_STXTLEN: DWORD = 63; +pub const PATHLEN: DWORD = 256; +pub const LM20_PATHLEN: DWORD = 256; +pub const DEVLEN: DWORD = 80; +pub const LM20_DEVLEN: DWORD = 8; +pub const EVLEN: usize = 16; +pub const UNLEN: DWORD = 256; +pub const LM20_UNLEN: DWORD = 20; +pub const GNLEN: DWORD = UNLEN; +pub const LM20_GNLEN: DWORD = LM20_UNLEN; +pub const PWLEN: DWORD = 256; +pub const LM20_PWLEN: DWORD = 14; +pub const SHPWLEN: DWORD = 8; +pub const CLTYPE_LEN: DWORD = 12; +pub const MAXCOMMENTSZ: DWORD = 256; +pub const LM20_MAXCOMMENTSZ: DWORD = 48; +pub const QNLEN: DWORD = NNLEN; +pub const LM20_QNLEN: DWORD = LM20_NNLEN; +pub const ALERTSZ: DWORD = 128; +pub const MAXDEVENTRIES: DWORD = 4 * 8; // FIXME: sizeof(int) instead of 4 +pub const NETBIOS_NAME_LEN: DWORD = 16; +pub const MAX_PREFERRED_LENGTH: DWORD = -1i32 as u32; +pub const CRYPT_KEY_LEN: DWORD = 7; +pub const CRYPT_TXT_LEN: DWORD = 8; +pub const ENCRYPTED_PWLEN: usize = 16; +pub const SESSION_PWLEN: DWORD = 24; +pub const SESSION_CRYPT_KLEN: DWORD = 21; +pub const PARM_ERROR_UNKNOWN: DWORD = -1i32 as u32; +pub const PARM_ERROR_NONE: DWORD = 0; +pub const PARMNUM_BASE_INFOLEVEL: DWORD = 1000; +pub type LMSTR = LPWSTR; +pub type LMCSTR = LPCWSTR; +pub type NET_API_STATUS = DWORD; +pub type API_RET_TYPE = NET_API_STATUS; +pub const PLATFORM_ID_DOS: DWORD = 300; +pub const PLATFORM_ID_OS2: DWORD = 400; +pub const PLATFORM_ID_NT: DWORD = 500; +pub const PLATFORM_ID_OSF: DWORD = 600; +pub const PLATFORM_ID_VMS: DWORD = 700; diff --git a/winapi/src/shared/minwindef.rs b/winapi/src/shared/minwindef.rs new file mode 100644 index 000000000..6c2e38d2c --- /dev/null +++ b/winapi/src/shared/minwindef.rs @@ -0,0 +1,102 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Basic Windows Type Definitions for minwin partition +use ctypes::{c_char, c_float, c_int, c_long, c_uchar, c_uint, c_ulong, c_ushort, c_void}; +use shared::basetsd::{LONG_PTR, UINT_PTR}; +use shared::ntdef::{HANDLE, LONG}; +pub type ULONG = c_ulong; +pub type PULONG = *mut ULONG; +pub type USHORT = c_ushort; +pub type PUSHORT = *mut USHORT; +pub type UCHAR = c_uchar; +pub type PUCHAR = *mut UCHAR; +pub type PSZ = *mut c_char; +pub const MAX_PATH: usize = 260; +pub const FALSE: BOOL = 0; +pub const TRUE: BOOL = 1; +pub type DWORD = c_ulong; +pub type BOOL = c_int; +pub type BYTE = c_uchar; +pub type WORD = c_ushort; +pub type FLOAT = c_float; +pub type PFLOAT = *mut FLOAT; +pub type PBOOL = *mut BOOL; +pub type LPBOOL = *mut BOOL; +pub type PBYTE = *mut BYTE; +pub type LPBYTE = *mut BYTE; +pub type PINT = *mut c_int; +pub type LPINT = *mut c_int; +pub type PWORD = *mut WORD; +pub type LPWORD = *mut WORD; +pub type LPLONG = *mut c_long; +pub type PDWORD = *mut DWORD; +pub type LPDWORD = *mut DWORD; +pub type LPVOID = *mut c_void; +pub type LPCVOID = *const c_void; +pub type INT = c_int; +pub type UINT = c_uint; +pub type PUINT = *mut c_uint; +pub type WPARAM = UINT_PTR; +pub type LPARAM = LONG_PTR; +pub type LRESULT = LONG_PTR; +#[inline] +pub fn MAKEWORD(a: BYTE, b: BYTE) -> WORD { + (a as WORD) | ((b as WORD) << 8) +} +#[inline] +pub fn MAKELONG(a: WORD, b: WORD) -> LONG { + ((a as DWORD) | ((b as DWORD) << 16)) as LONG +} +#[inline] +pub fn LOWORD(l: DWORD) -> WORD { + (l & 0xffff) as WORD +} +#[inline] +pub fn HIWORD(l: DWORD) -> WORD { + ((l >> 16) & 0xffff) as WORD +} +#[inline] +pub fn LOBYTE(l: WORD) -> BYTE { + (l & 0xff) as BYTE +} +#[inline] +pub fn HIBYTE(l: WORD) -> BYTE { + ((l >> 8) & 0xff) as BYTE +} +pub type SPHANDLE = *mut HANDLE; +pub type LPHANDLE = *mut HANDLE; +pub type HGLOBAL = HANDLE; +pub type HLOCAL = HANDLE; +pub type GLOBALHANDLE = HANDLE; +pub type LOCALHANDLE = HANDLE; +pub enum __some_function {} +/// Pointer to a function with unknown type signature. +pub type FARPROC = *mut __some_function; +/// Pointer to a function with unknown type signature. +pub type NEARPROC = *mut __some_function; +/// Pointer to a function with unknown type signature. +pub type PROC = *mut __some_function; +pub type ATOM = WORD; +DECLARE_HANDLE!{HKEY, HKEY__} +pub type PHKEY = *mut HKEY; +DECLARE_HANDLE!{HMETAFILE, HMETAFILE__} +DECLARE_HANDLE!{HINSTANCE, HINSTANCE__} +pub type HMODULE = HINSTANCE; +DECLARE_HANDLE!{HRGN, HRGN__} +DECLARE_HANDLE!{HRSRC, HRSRC__} +DECLARE_HANDLE!{HSPRITE, HSPRITE__} +DECLARE_HANDLE!{HLSURF, HLSURF__} +DECLARE_HANDLE!{HSTR, HSTR__} +DECLARE_HANDLE!{HTASK, HTASK__} +DECLARE_HANDLE!{HWINSTA, HWINSTA__} +DECLARE_HANDLE!{HKL, HKL__} +pub type HFILE = c_int; +STRUCT!{#[debug] struct FILETIME { + dwLowDateTime: DWORD, + dwHighDateTime: DWORD, +}} +pub type PFILETIME = *mut FILETIME; +pub type LPFILETIME = *mut FILETIME; diff --git a/winapi/src/shared/mmreg.rs b/winapi/src/shared/mmreg.rs new file mode 100644 index 000000000..06ad900f2 --- /dev/null +++ b/winapi/src/shared/mmreg.rs @@ -0,0 +1,309 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, WORD}; +pub const WAVE_FORMAT_UNKNOWN: WORD = 0x0000; +pub const WAVE_FORMAT_PCM: WORD = 0x0001; +pub const WAVE_FORMAT_ADPCM: WORD = 0x0002; +pub const WAVE_FORMAT_IEEE_FLOAT: WORD = 0x0003; +pub const WAVE_FORMAT_VSELP: WORD = 0x0004; +pub const WAVE_FORMAT_IBM_CVSD: WORD = 0x0005; +pub const WAVE_FORMAT_ALAW: WORD = 0x0006; +pub const WAVE_FORMAT_MULAW: WORD = 0x0007; +pub const WAVE_FORMAT_DTS: WORD = 0x0008; +pub const WAVE_FORMAT_DRM: WORD = 0x0009; +pub const WAVE_FORMAT_WMAVOICE9: WORD = 0x000A; +pub const WAVE_FORMAT_WMAVOICE10: WORD = 0x000B; +pub const WAVE_FORMAT_OKI_ADPCM: WORD = 0x0010; +pub const WAVE_FORMAT_DVI_ADPCM: WORD = 0x0011; +pub const WAVE_FORMAT_IMA_ADPCM: WORD = WAVE_FORMAT_DVI_ADPCM; +pub const WAVE_FORMAT_MEDIASPACE_ADPCM: WORD = 0x0012; +pub const WAVE_FORMAT_SIERRA_ADPCM: WORD = 0x0013; +pub const WAVE_FORMAT_G723_ADPCM: WORD = 0x0014; +pub const WAVE_FORMAT_DIGISTD: WORD = 0x0015; +pub const WAVE_FORMAT_DIGIFIX: WORD = 0x0016; +pub const WAVE_FORMAT_DIALOGIC_OKI_ADPCM: WORD = 0x0017; +pub const WAVE_FORMAT_MEDIAVISION_ADPCM: WORD = 0x0018; +pub const WAVE_FORMAT_CU_CODEC: WORD = 0x0019; +pub const WAVE_FORMAT_HP_DYN_VOICE: WORD = 0x001A; +pub const WAVE_FORMAT_YAMAHA_ADPCM: WORD = 0x0020; +pub const WAVE_FORMAT_SONARC: WORD = 0x0021; +pub const WAVE_FORMAT_DSPGROUP_TRUESPEECH: WORD = 0x0022; +pub const WAVE_FORMAT_ECHOSC1: WORD = 0x0023; +pub const WAVE_FORMAT_AUDIOFILE_AF36: WORD = 0x0024; +pub const WAVE_FORMAT_APTX: WORD = 0x0025; +pub const WAVE_FORMAT_AUDIOFILE_AF10: WORD = 0x0026; +pub const WAVE_FORMAT_PROSODY_1612: WORD = 0x0027; +pub const WAVE_FORMAT_LRC: WORD = 0x0028; +pub const WAVE_FORMAT_DOLBY_AC2: WORD = 0x0030; +pub const WAVE_FORMAT_GSM610: WORD = 0x0031; +pub const WAVE_FORMAT_MSNAUDIO: WORD = 0x0032; +pub const WAVE_FORMAT_ANTEX_ADPCME: WORD = 0x0033; +pub const WAVE_FORMAT_CONTROL_RES_VQLPC: WORD = 0x0034; +pub const WAVE_FORMAT_DIGIREAL: WORD = 0x0035; +pub const WAVE_FORMAT_DIGIADPCM: WORD = 0x0036; +pub const WAVE_FORMAT_CONTROL_RES_CR10: WORD = 0x0037; +pub const WAVE_FORMAT_NMS_VBXADPCM: WORD = 0x0038; +pub const WAVE_FORMAT_CS_IMAADPCM: WORD = 0x0039; +pub const WAVE_FORMAT_ECHOSC3: WORD = 0x003A; +pub const WAVE_FORMAT_ROCKWELL_ADPCM: WORD = 0x003B; +pub const WAVE_FORMAT_ROCKWELL_DIGITALK: WORD = 0x003C; +pub const WAVE_FORMAT_XEBEC: WORD = 0x003D; +pub const WAVE_FORMAT_G721_ADPCM: WORD = 0x0040; +pub const WAVE_FORMAT_G728_CELP: WORD = 0x0041; +pub const WAVE_FORMAT_MSG723: WORD = 0x0042; +pub const WAVE_FORMAT_INTEL_G723_1: WORD = 0x0043; +pub const WAVE_FORMAT_INTEL_G729: WORD = 0x0044; +pub const WAVE_FORMAT_SHARP_G726: WORD = 0x0045; +pub const WAVE_FORMAT_MPEG: WORD = 0x0050; +pub const WAVE_FORMAT_RT24: WORD = 0x0052; +pub const WAVE_FORMAT_PAC: WORD = 0x0053; +pub const WAVE_FORMAT_MPEGLAYER3: WORD = 0x0055; +pub const WAVE_FORMAT_LUCENT_G723: WORD = 0x0059; +pub const WAVE_FORMAT_CIRRUS: WORD = 0x0060; +pub const WAVE_FORMAT_ESPCM: WORD = 0x0061; +pub const WAVE_FORMAT_VOXWARE: WORD = 0x0062; +pub const WAVE_FORMAT_CANOPUS_ATRAC: WORD = 0x0063; +pub const WAVE_FORMAT_G726_ADPCM: WORD = 0x0064; +pub const WAVE_FORMAT_G722_ADPCM: WORD = 0x0065; +pub const WAVE_FORMAT_DSAT: WORD = 0x0066; +pub const WAVE_FORMAT_DSAT_DISPLAY: WORD = 0x0067; +pub const WAVE_FORMAT_VOXWARE_BYTE_ALIGNED: WORD = 0x0069; +pub const WAVE_FORMAT_VOXWARE_AC8: WORD = 0x0070; +pub const WAVE_FORMAT_VOXWARE_AC10: WORD = 0x0071; +pub const WAVE_FORMAT_VOXWARE_AC16: WORD = 0x0072; +pub const WAVE_FORMAT_VOXWARE_AC20: WORD = 0x0073; +pub const WAVE_FORMAT_VOXWARE_RT24: WORD = 0x0074; +pub const WAVE_FORMAT_VOXWARE_RT29: WORD = 0x0075; +pub const WAVE_FORMAT_VOXWARE_RT29HW: WORD = 0x0076; +pub const WAVE_FORMAT_VOXWARE_VR12: WORD = 0x0077; +pub const WAVE_FORMAT_VOXWARE_VR18: WORD = 0x0078; +pub const WAVE_FORMAT_VOXWARE_TQ40: WORD = 0x0079; +pub const WAVE_FORMAT_VOXWARE_SC3: WORD = 0x007A; +pub const WAVE_FORMAT_VOXWARE_SC3_1: WORD = 0x007B; +pub const WAVE_FORMAT_SOFTSOUND: WORD = 0x0080; +pub const WAVE_FORMAT_VOXWARE_TQ60: WORD = 0x0081; +pub const WAVE_FORMAT_MSRT24: WORD = 0x0082; +pub const WAVE_FORMAT_G729A: WORD = 0x0083; +pub const WAVE_FORMAT_MVI_MVI2: WORD = 0x0084; +pub const WAVE_FORMAT_DF_G726: WORD = 0x0085; +pub const WAVE_FORMAT_DF_GSM610: WORD = 0x0086; +pub const WAVE_FORMAT_ISIAUDIO: WORD = 0x0088; +pub const WAVE_FORMAT_ONLIVE: WORD = 0x0089; +pub const WAVE_FORMAT_MULTITUDE_FT_SX20: WORD = 0x008A; +pub const WAVE_FORMAT_INFOCOM_ITS_G721_ADPCM: WORD = 0x008B; +pub const WAVE_FORMAT_CONVEDIA_G729: WORD = 0x008C; +pub const WAVE_FORMAT_CONGRUENCY: WORD = 0x008D; +pub const WAVE_FORMAT_SBC24: WORD = 0x0091; +pub const WAVE_FORMAT_DOLBY_AC3_SPDIF: WORD = 0x0092; +pub const WAVE_FORMAT_MEDIASONIC_G723: WORD = 0x0093; +pub const WAVE_FORMAT_PROSODY_8KBPS: WORD = 0x0094; +pub const WAVE_FORMAT_ZYXEL_ADPCM: WORD = 0x0097; +pub const WAVE_FORMAT_PHILIPS_LPCBB: WORD = 0x0098; +pub const WAVE_FORMAT_PACKED: WORD = 0x0099; +pub const WAVE_FORMAT_MALDEN_PHONYTALK: WORD = 0x00A0; +pub const WAVE_FORMAT_RACAL_RECORDER_GSM: WORD = 0x00A1; +pub const WAVE_FORMAT_RACAL_RECORDER_G720_A: WORD = 0x00A2; +pub const WAVE_FORMAT_RACAL_RECORDER_G723_1: WORD = 0x00A3; +pub const WAVE_FORMAT_RACAL_RECORDER_TETRA_ACELP: WORD = 0x00A4; +pub const WAVE_FORMAT_NEC_AAC: WORD = 0x00B0; +pub const WAVE_FORMAT_RAW_AAC1: WORD = 0x00FF; +pub const WAVE_FORMAT_RHETOREX_ADPCM: WORD = 0x0100; +pub const WAVE_FORMAT_IRAT: WORD = 0x0101; +pub const WAVE_FORMAT_VIVO_G723: WORD = 0x0111; +pub const WAVE_FORMAT_VIVO_SIREN: WORD = 0x0112; +pub const WAVE_FORMAT_PHILIPS_CELP: WORD = 0x0120; +pub const WAVE_FORMAT_PHILIPS_GRUNDIG: WORD = 0x0121; +pub const WAVE_FORMAT_DIGITAL_G723: WORD = 0x0123; +pub const WAVE_FORMAT_SANYO_LD_ADPCM: WORD = 0x0125; +pub const WAVE_FORMAT_SIPROLAB_ACEPLNET: WORD = 0x0130; +pub const WAVE_FORMAT_SIPROLAB_ACELP4800: WORD = 0x0131; +pub const WAVE_FORMAT_SIPROLAB_ACELP8V3: WORD = 0x0132; +pub const WAVE_FORMAT_SIPROLAB_G729: WORD = 0x0133; +pub const WAVE_FORMAT_SIPROLAB_G729A: WORD = 0x0134; +pub const WAVE_FORMAT_SIPROLAB_KELVIN: WORD = 0x0135; +pub const WAVE_FORMAT_VOICEAGE_AMR: WORD = 0x0136; +pub const WAVE_FORMAT_G726ADPCM: WORD = 0x0140; +pub const WAVE_FORMAT_DICTAPHONE_CELP68: WORD = 0x0141; +pub const WAVE_FORMAT_DICTAPHONE_CELP54: WORD = 0x0142; +pub const WAVE_FORMAT_QUALCOMM_PUREVOICE: WORD = 0x0150; +pub const WAVE_FORMAT_QUALCOMM_HALFRATE: WORD = 0x0151; +pub const WAVE_FORMAT_TUBGSM: WORD = 0x0155; +pub const WAVE_FORMAT_MSAUDIO1: WORD = 0x0160; +pub const WAVE_FORMAT_WMAUDIO2: WORD = 0x0161; +pub const WAVE_FORMAT_WMAUDIO3: WORD = 0x0162; +pub const WAVE_FORMAT_WMAUDIO_LOSSLESS: WORD = 0x0163; +pub const WAVE_FORMAT_WMASPDIF: WORD = 0x0164; +pub const WAVE_FORMAT_UNISYS_NAP_ADPCM: WORD = 0x0170; +pub const WAVE_FORMAT_UNISYS_NAP_ULAW: WORD = 0x0171; +pub const WAVE_FORMAT_UNISYS_NAP_ALAW: WORD = 0x0172; +pub const WAVE_FORMAT_UNISYS_NAP_16K: WORD = 0x0173; +pub const WAVE_FORMAT_SYCOM_ACM_SYC008: WORD = 0x0174; +pub const WAVE_FORMAT_SYCOM_ACM_SYC701_G726L: WORD = 0x0175; +pub const WAVE_FORMAT_SYCOM_ACM_SYC701_CELP54: WORD = 0x0176; +pub const WAVE_FORMAT_SYCOM_ACM_SYC701_CELP68: WORD = 0x0177; +pub const WAVE_FORMAT_KNOWLEDGE_ADVENTURE_ADPCM: WORD = 0x0178; +pub const WAVE_FORMAT_FRAUNHOFER_IIS_MPEG2_AAC: WORD = 0x0180; +pub const WAVE_FORMAT_DTS_DS: WORD = 0x0190; +pub const WAVE_FORMAT_CREATIVE_ADPCM: WORD = 0x0200; +pub const WAVE_FORMAT_CREATIVE_FASTSPEECH8: WORD = 0x0202; +pub const WAVE_FORMAT_CREATIVE_FASTSPEECH10: WORD = 0x0203; +pub const WAVE_FORMAT_UHER_ADPCM: WORD = 0x0210; +pub const WAVE_FORMAT_ULEAD_DV_AUDIO: WORD = 0x0215; +pub const WAVE_FORMAT_ULEAD_DV_AUDIO_1: WORD = 0x0216; +pub const WAVE_FORMAT_QUARTERDECK: WORD = 0x0220; +pub const WAVE_FORMAT_ILINK_VC: WORD = 0x0230; +pub const WAVE_FORMAT_RAW_SPORT: WORD = 0x0240; +pub const WAVE_FORMAT_ESST_AC3: WORD = 0x0241; +pub const WAVE_FORMAT_GENERIC_PASSTHRU: WORD = 0x0249; +pub const WAVE_FORMAT_IPI_HSX: WORD = 0x0250; +pub const WAVE_FORMAT_IPI_RPELP: WORD = 0x0251; +pub const WAVE_FORMAT_CS2: WORD = 0x0260; +pub const WAVE_FORMAT_SONY_SCX: WORD = 0x0270; +pub const WAVE_FORMAT_SONY_SCY: WORD = 0x0271; +pub const WAVE_FORMAT_SONY_ATRAC3: WORD = 0x0272; +pub const WAVE_FORMAT_SONY_SPC: WORD = 0x0273; +pub const WAVE_FORMAT_TELUM_AUDIO: WORD = 0x0280; +pub const WAVE_FORMAT_TELUM_IA_AUDIO: WORD = 0x0281; +pub const WAVE_FORMAT_NORCOM_VOICE_SYSTEMS_ADPCM: WORD = 0x0285; +pub const WAVE_FORMAT_FM_TOWNS_SND: WORD = 0x0300; +pub const WAVE_FORMAT_MICRONAS: WORD = 0x0350; +pub const WAVE_FORMAT_MICRONAS_CELP833: WORD = 0x0351; +pub const WAVE_FORMAT_BTV_DIGITAL: WORD = 0x0400; +pub const WAVE_FORMAT_INTEL_MUSIC_CODER: WORD = 0x0401; +pub const WAVE_FORMAT_INDEO_AUDIO: WORD = 0x0402; +pub const WAVE_FORMAT_QDESIGN_MUSIC: WORD = 0x0450; +pub const WAVE_FORMAT_ON2_VP7_AUDIO: WORD = 0x0500; +pub const WAVE_FORMAT_ON2_VP6_AUDIO: WORD = 0x0501; +pub const WAVE_FORMAT_VME_VMPCM: WORD = 0x0680; +pub const WAVE_FORMAT_TPC: WORD = 0x0681; +pub const WAVE_FORMAT_LIGHTWAVE_LOSSLESS: WORD = 0x08AE; +pub const WAVE_FORMAT_OLIGSM: WORD = 0x1000; +pub const WAVE_FORMAT_OLIADPCM: WORD = 0x1001; +pub const WAVE_FORMAT_OLICELP: WORD = 0x1002; +pub const WAVE_FORMAT_OLISBC: WORD = 0x1003; +pub const WAVE_FORMAT_OLIOPR: WORD = 0x1004; +pub const WAVE_FORMAT_LH_CODEC: WORD = 0x1100; +pub const WAVE_FORMAT_LH_CODEC_CELP: WORD = 0x1101; +pub const WAVE_FORMAT_LH_CODEC_SBC8: WORD = 0x1102; +pub const WAVE_FORMAT_LH_CODEC_SBC12: WORD = 0x1103; +pub const WAVE_FORMAT_LH_CODEC_SBC16: WORD = 0x1104; +pub const WAVE_FORMAT_NORRIS: WORD = 0x1400; +pub const WAVE_FORMAT_ISIAUDIO_2: WORD = 0x1401; +pub const WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS: WORD = 0x1500; +pub const WAVE_FORMAT_MPEG_ADTS_AAC: WORD = 0x1600; +pub const WAVE_FORMAT_MPEG_RAW_AAC: WORD = 0x1601; +pub const WAVE_FORMAT_MPEG_LOAS: WORD = 0x1602; +pub const WAVE_FORMAT_NOKIA_MPEG_ADTS_AAC: WORD = 0x1608; +pub const WAVE_FORMAT_NOKIA_MPEG_RAW_AAC: WORD = 0x1609; +pub const WAVE_FORMAT_VODAFONE_MPEG_ADTS_AAC: WORD = 0x160A; +pub const WAVE_FORMAT_VODAFONE_MPEG_RAW_AAC: WORD = 0x160B; +pub const WAVE_FORMAT_MPEG_HEAAC: WORD = 0x1610; +pub const WAVE_FORMAT_VOXWARE_RT24_SPEECH: WORD = 0x181C; +pub const WAVE_FORMAT_SONICFOUNDRY_LOSSLESS: WORD = 0x1971; +pub const WAVE_FORMAT_INNINGS_TELECOM_ADPCM: WORD = 0x1979; +pub const WAVE_FORMAT_LUCENT_SX8300P: WORD = 0x1C07; +pub const WAVE_FORMAT_LUCENT_SX5363S: WORD = 0x1C0C; +pub const WAVE_FORMAT_CUSEEME: WORD = 0x1F03; +pub const WAVE_FORMAT_NTCSOFT_ALF2CM_ACM: WORD = 0x1FC4; +pub const WAVE_FORMAT_DVM: WORD = 0x2000; +pub const WAVE_FORMAT_DTS2: WORD = 0x2001; +pub const WAVE_FORMAT_MAKEAVIS: WORD = 0x3313; +pub const WAVE_FORMAT_DIVIO_MPEG4_AAC: WORD = 0x4143; +pub const WAVE_FORMAT_NOKIA_ADAPTIVE_MULTIRATE: WORD = 0x4201; +pub const WAVE_FORMAT_DIVIO_G726: WORD = 0x4243; +pub const WAVE_FORMAT_LEAD_SPEECH: WORD = 0x434C; +pub const WAVE_FORMAT_LEAD_VORBIS: WORD = 0x564C; +pub const WAVE_FORMAT_WAVPACK_AUDIO: WORD = 0x5756; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_1: WORD = 0x674F; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_2: WORD = 0x6750; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_3: WORD = 0x6751; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_1_PLUS: WORD = 0x676F; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_2_PLUS: WORD = 0x6770; +pub const WAVE_FORMAT_OGG_VORBIS_MODE_3_PLUS: WORD = 0x6771; +pub const WAVE_FORMAT_3COM_NBX: WORD = 0x7000; +pub const WAVE_FORMAT_FAAD_AAC: WORD = 0x706D; +pub const WAVE_FORMAT_AMR_NB: WORD = 0x7361; +pub const WAVE_FORMAT_AMR_WB: WORD = 0x7362; +pub const WAVE_FORMAT_AMR_WP: WORD = 0x7363; +pub const WAVE_FORMAT_GSM_AMR_CBR: WORD = 0x7A21; +pub const WAVE_FORMAT_GSM_AMR_VBR_SID: WORD = 0x7A22; +pub const WAVE_FORMAT_COMVERSE_INFOSYS_G723_1: WORD = 0xA100; +pub const WAVE_FORMAT_COMVERSE_INFOSYS_AVQSBC: WORD = 0xA101; +pub const WAVE_FORMAT_COMVERSE_INFOSYS_SBC: WORD = 0xA102; +pub const WAVE_FORMAT_SYMBOL_G729_A: WORD = 0xA103; +pub const WAVE_FORMAT_VOICEAGE_AMR_WB: WORD = 0xA104; +pub const WAVE_FORMAT_INGENIENT_G726: WORD = 0xA105; +pub const WAVE_FORMAT_MPEG4_AAC: WORD = 0xA106; +pub const WAVE_FORMAT_ENCORE_G726: WORD = 0xA107; +pub const WAVE_FORMAT_ZOLL_ASAO: WORD = 0xA108; +pub const WAVE_FORMAT_SPEEX_VOICE: WORD = 0xA109; +pub const WAVE_FORMAT_VIANIX_MASC: WORD = 0xA10A; +pub const WAVE_FORMAT_WM9_SPECTRUM_ANALYZER: WORD = 0xA10B; +pub const WAVE_FORMAT_WMF_SPECTRUM_ANAYZER: WORD = 0xA10C; +pub const WAVE_FORMAT_GSM_610: WORD = 0xA10D; +pub const WAVE_FORMAT_GSM_620: WORD = 0xA10E; +pub const WAVE_FORMAT_GSM_660: WORD = 0xA10F; +pub const WAVE_FORMAT_GSM_690: WORD = 0xA110; +pub const WAVE_FORMAT_GSM_ADAPTIVE_MULTIRATE_WB: WORD = 0xA111; +pub const WAVE_FORMAT_POLYCOM_G722: WORD = 0xA112; +pub const WAVE_FORMAT_POLYCOM_G728: WORD = 0xA113; +pub const WAVE_FORMAT_POLYCOM_G729_A: WORD = 0xA114; +pub const WAVE_FORMAT_POLYCOM_SIREN: WORD = 0xA115; +pub const WAVE_FORMAT_GLOBAL_IP_ILBC: WORD = 0xA116; +pub const WAVE_FORMAT_RADIOTIME_TIME_SHIFT_RADIO: WORD = 0xA117; +pub const WAVE_FORMAT_NICE_ACA: WORD = 0xA118; +pub const WAVE_FORMAT_NICE_ADPCM: WORD = 0xA119; +pub const WAVE_FORMAT_VOCORD_G721: WORD = 0xA11A; +pub const WAVE_FORMAT_VOCORD_G726: WORD = 0xA11B; +pub const WAVE_FORMAT_VOCORD_G722_1: WORD = 0xA11C; +pub const WAVE_FORMAT_VOCORD_G728: WORD = 0xA11D; +pub const WAVE_FORMAT_VOCORD_G729: WORD = 0xA11E; +pub const WAVE_FORMAT_VOCORD_G729_A: WORD = 0xA11F; +pub const WAVE_FORMAT_VOCORD_G723_1: WORD = 0xA120; +pub const WAVE_FORMAT_VOCORD_LBC: WORD = 0xA121; +pub const WAVE_FORMAT_NICE_G728: WORD = 0xA122; +pub const WAVE_FORMAT_FRACE_TELECOM_G729: WORD = 0xA123; +pub const WAVE_FORMAT_CODIAN: WORD = 0xA124; +pub const WAVE_FORMAT_FLAC: WORD = 0xF1AC; +pub const WAVE_FORMAT_EXTENSIBLE: WORD = 0xFFFE; +pub const WAVE_FORMAT_DEVELOPMENT: WORD = 0xFFFF; +//2557 +pub const SPEAKER_FRONT_LEFT: DWORD = 0x1; +pub const SPEAKER_FRONT_RIGHT: DWORD = 0x2; +pub const SPEAKER_FRONT_CENTER: DWORD = 0x4; +pub const SPEAKER_LOW_FREQUENCY: DWORD = 0x8; +pub const SPEAKER_BACK_LEFT: DWORD = 0x10; +pub const SPEAKER_BACK_RIGHT: DWORD = 0x20; +pub const SPEAKER_FRONT_LEFT_OF_CENTER: DWORD = 0x40; +pub const SPEAKER_FRONT_RIGHT_OF_CENTER: DWORD = 0x80; +pub const SPEAKER_BACK_CENTER: DWORD = 0x100; +pub const SPEAKER_SIDE_LEFT: DWORD = 0x200; +pub const SPEAKER_SIDE_RIGHT: DWORD = 0x400; +pub const SPEAKER_TOP_CENTER: DWORD = 0x800; +pub const SPEAKER_TOP_FRONT_LEFT: DWORD = 0x1000; +pub const SPEAKER_TOP_FRONT_CENTER: DWORD = 0x2000; +pub const SPEAKER_TOP_FRONT_RIGHT: DWORD = 0x4000; +pub const SPEAKER_TOP_BACK_LEFT: DWORD = 0x8000; +pub const SPEAKER_TOP_BACK_CENTER: DWORD = 0x10000; +pub const SPEAKER_TOP_BACK_RIGHT: DWORD = 0x20000; +pub const SPEAKER_RESERVED: DWORD = 0x7FFC0000; +pub const SPEAKER_ALL: DWORD = 0x80000000; +STRUCT!{#[repr(packed)] struct WAVEFORMATEX { + wFormatTag: WORD, + nChannels: WORD, + nSamplesPerSec: DWORD, + nAvgBytesPerSec: DWORD, + nBlockAlign: WORD, + wBitsPerSample: WORD, + cbSize: WORD, +}} +STRUCT!{#[repr(packed)] struct WAVEFORMATEXTENSIBLE { + Format: WAVEFORMATEX, + Samples: WORD, + dwChannelMask: DWORD, + SubFormat: GUID, +}} diff --git a/winapi/src/shared/mod.rs b/winapi/src/shared/mod.rs new file mode 100644 index 000000000..cc14a5cec --- /dev/null +++ b/winapi/src/shared/mod.rs @@ -0,0 +1,75 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Headers shared between user mode and kernel mode +#[cfg(feature = "basetsd")] pub mod basetsd; +#[cfg(feature = "bcrypt")] pub mod bcrypt; +#[cfg(feature = "bugcodes")] pub mod bugcodes; +#[cfg(feature = "cderr")] pub mod cderr; +#[cfg(feature = "cfg")] pub mod cfg; +#[cfg(feature = "d3d9")] pub mod d3d9; +#[cfg(feature = "d3d9caps")] pub mod d3d9caps; +#[cfg(feature = "d3d9types")] pub mod d3d9types; +#[cfg(feature = "d3dkmdt")] pub mod d3dkmdt; +#[cfg(feature = "d3dukmdt")] pub mod d3dukmdt; +#[cfg(feature = "dcomptypes")] pub mod dcomptypes; +#[cfg(feature = "devguid")] pub mod devguid; +#[cfg(feature = "devpkey")] pub mod devpkey; +#[cfg(feature = "devpropdef")] pub mod devpropdef; +#[cfg(feature = "dinputd")] pub mod dinputd; +#[cfg(feature = "dxgi")] pub mod dxgi; +#[cfg(feature = "dxgi1_2")] pub mod dxgi1_2; +#[cfg(feature = "dxgi1_3")] pub mod dxgi1_3; +#[cfg(feature = "dxgi1_4")] pub mod dxgi1_4; +#[cfg(feature = "dxgi1_5")] pub mod dxgi1_5; +#[cfg(feature = "dxgi1_6")] pub mod dxgi1_6; +#[cfg(feature = "dxgiformat")] pub mod dxgiformat; +#[cfg(feature = "dxgitype")] pub mod dxgitype; +#[cfg(feature = "evntprov")] pub mod evntprov; +#[cfg(feature = "evntrace")] pub mod evntrace; +pub mod guiddef; +#[cfg(feature = "hidclass")] pub mod hidclass; +#[cfg(feature = "hidpi")] pub mod hidpi; +#[cfg(feature = "hidsdi")] pub mod hidsdi; +#[cfg(feature = "hidusage")] pub mod hidusage; +#[cfg(feature = "ifdef")] pub mod ifdef; +#[cfg(feature = "in6addr")] pub mod in6addr; +#[cfg(feature = "inaddr")] pub mod inaddr; +#[cfg(feature = "intsafe")] pub mod intsafe; +#[cfg(feature = "ks")] pub mod ks; +#[cfg(feature = "ksmedia")] pub mod ksmedia; +#[cfg(feature = "ktmtypes")] pub mod ktmtypes; +#[cfg(feature = "lmcons")] pub mod lmcons; +#[cfg(feature = "minwindef")] pub mod minwindef; +#[cfg(feature = "mmreg")] pub mod mmreg; +#[cfg(feature = "mstcpip")] pub mod mstcpip; +#[cfg(feature = "mswsockdef")] pub mod mswsockdef; +#[cfg(feature = "netioapi")] pub mod netioapi; +#[cfg(feature = "ntddscsi")] pub mod ntddscsi; +#[cfg(feature = "ntddser")] pub mod ntddser; +#[cfg(feature = "ntdef")] pub mod ntdef; +#[cfg(feature = "ntstatus")] pub mod ntstatus; +#[cfg(feature = "qos")] pub mod qos; +#[cfg(feature = "rpc")] pub mod rpc; +#[cfg(feature = "rpcdce")] pub mod rpcdce; +#[cfg(feature = "rpcndr")] pub mod rpcndr; +#[cfg(feature = "sddl")] pub mod sddl; +#[cfg(feature = "sspi")] pub mod sspi; +#[cfg(feature = "stralign")] pub mod stralign; +#[cfg(feature = "transportsettingcommon")] pub mod transportsettingcommon; +#[cfg(feature = "tvout")] pub mod tvout; +#[cfg(feature = "usb")] pub mod usb; +#[cfg(feature = "usbiodef")] pub mod usbiodef; +#[cfg(feature = "usbspec")] pub mod usbspec; +#[cfg(feature = "windef")] pub mod windef; +#[cfg(feature = "windowsx")] pub mod windowsx; +#[cfg(feature = "winerror")] pub mod winerror; +#[cfg(feature = "winusbio")] pub mod winusbio; +#[cfg(feature = "wmistr")] pub mod wmistr; +#[cfg(feature = "wnnc")] pub mod wnnc; +#[cfg(feature = "ws2def")] pub mod ws2def; +#[cfg(feature = "ws2ipdef")] pub mod ws2ipdef; +#[cfg(feature = "wtypes")] pub mod wtypes; +#[cfg(feature = "wtypesbase")] pub mod wtypesbase; diff --git a/winapi/src/shared/mstcpip.rs b/winapi/src/shared/mstcpip.rs new file mode 100644 index 000000000..fe2072544 --- /dev/null +++ b/winapi/src/shared/mstcpip.rs @@ -0,0 +1,492 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This module contains Microsoft-specific extensions to the core Winsock definitions. +use ctypes::wchar_t; +use shared::basetsd::{UINT32, UINT64, ULONG64}; +use shared::guiddef::GUID; +use shared::in6addr::IN6_ADDR; +use shared::inaddr::IN_ADDR; +use shared::minwindef::{DWORD, PULONG, PUSHORT, UCHAR, ULONG, USHORT}; +use shared::ws2def::{ + INADDR_ANY, INADDR_BROADCAST, INADDR_NONE, IOC_VENDOR, SOCKADDR_IN, + SOCKADDR_STORAGE, +}; +use um::winnt::{BOOLEAN, LONG, LPCWSTR, PCSTR, PCWSTR, PSTR, PWSTR}; +DEFINE_GUID!{SOCKET_DEFAULT2_QM_POLICY, + 0xaec2ef9c, 0x3a4d, 0x4d3e, 0x88, 0x42, 0x23, 0x99, 0x42, 0xe3, 0x9a, 0x47} +DEFINE_GUID!{REAL_TIME_NOTIFICATION_CAPABILITY, + 0x6b59819a, 0x5cae, 0x492d, 0xa9, 0x01, 0x2a, 0x3c, 0x2c, 0x50, 0x16, 0x4f} +DEFINE_GUID!{REAL_TIME_NOTIFICATION_CAPABILITY_EX, + 0x6843da03, 0x154a, 0x4616, 0xa5, 0x08, 0x44, 0x37, 0x12, 0x95, 0xf9, 0x6b} +DEFINE_GUID!{ASSOCIATE_NAMERES_CONTEXT, + 0x59a38b67, 0xd4fe, 0x46e1, 0xba, 0x3c, 0x87, 0xea, 0x74, 0xca, 0x30, 0x49} +ENUM!{enum TCPSTATE { + TCPSTATE_CLOSED, + TCPSTATE_LISTEN, + TCPSTATE_SYN_SENT, + TCPSTATE_SYN_RCVD, + TCPSTATE_ESTABLISHED, + TCPSTATE_FIN_WAIT_1, + TCPSTATE_FIN_WAIT_2, + TCPSTATE_CLOSE_WAIT, + TCPSTATE_CLOSING, + TCPSTATE_LAST_ACK, + TCPSTATE_TIME_WAIT, + TCPSTATE_MAX, +}} +STRUCT!{struct TRANSPORT_SETTING_ID { + Guid: GUID, +}} +pub type PTRANSPORT_SETTING_ID = *mut TRANSPORT_SETTING_ID; +STRUCT!{struct tcp_keepalive { + onoff: ULONG, + keepalivetime: ULONG, + keepaliveinterval: ULONG, +}} +ENUM!{enum CONTROL_CHANNEL_TRIGGER_STATUS { + CONTROL_CHANNEL_TRIGGER_STATUS_INVALID = 0, + CONTROL_CHANNEL_TRIGGER_STATUS_SOFTWARE_SLOT_ALLOCATED = 1, + CONTROL_CHANNEL_TRIGGER_STATUS_HARDWARE_SLOT_ALLOCATED = 2, + CONTROL_CHANNEL_TRIGGER_STATUS_POLICY_ERROR = 3, + CONTROL_CHANNEL_TRIGGER_STATUS_SYSTEM_ERROR = 4, + CONTROL_CHANNEL_TRIGGER_STATUS_TRANSPORT_DISCONNECTED = 5, + CONTROL_CHANNEL_TRIGGER_STATUS_SERVICE_UNAVAILABLE = 6, +}} +pub type PCONTROL_CHANNEL_TRIGGER_STATUS = *mut CONTROL_CHANNEL_TRIGGER_STATUS; +pub const CONTROL_CHANNEL_TRIGGER_STATUS_MAX: u32 = CONTROL_CHANNEL_TRIGGER_STATUS_SYSTEM_ERROR; +STRUCT!{struct REAL_TIME_NOTIFICATION_SETTING_INPUT { + TransportSettingId: TRANSPORT_SETTING_ID, + BrokerEventGuid: GUID, +}} +pub type PREAL_TIME_NOTIFICATION_SETTING_INPUT = *mut REAL_TIME_NOTIFICATION_SETTING_INPUT; +STRUCT!{struct REAL_TIME_NOTIFICATION_SETTING_INPUT_EX { + TransportSettingId: TRANSPORT_SETTING_ID, + BrokerEventGuid: GUID, + Unmark: BOOLEAN, +}} +pub type PREAL_TIME_NOTIFICATION_SETTING_INPUT_EX = *mut REAL_TIME_NOTIFICATION_SETTING_INPUT_EX; +STRUCT!{struct REAL_TIME_NOTIFICATION_SETTING_OUTPUT { + ChannelStatus: CONTROL_CHANNEL_TRIGGER_STATUS, +}} +pub type PREAL_TIME_NOTIFICATION_SETTING_OUTPUT = *mut REAL_TIME_NOTIFICATION_SETTING_OUTPUT; +STRUCT!{struct ASSOCIATE_NAMERES_CONTEXT_INPUT { + TransportSettingId: TRANSPORT_SETTING_ID, + Handle: UINT64, +}} +pub type PASSOCIATE_NAMERES_CONTEXT_INPUT = *mut ASSOCIATE_NAMERES_CONTEXT_INPUT; +pub const SIO_RCVALL: DWORD = _WSAIOW!(IOC_VENDOR,1); +pub const SIO_RCVALL_MCAST: DWORD = _WSAIOW!(IOC_VENDOR,2); +pub const SIO_RCVALL_IGMPMCAST: DWORD = _WSAIOW!(IOC_VENDOR,3); +pub const SIO_KEEPALIVE_VALS: DWORD = _WSAIOW!(IOC_VENDOR,4); +pub const SIO_ABSORB_RTRALERT: DWORD = _WSAIOW!(IOC_VENDOR,5); +pub const SIO_UCAST_IF: DWORD = _WSAIOW!(IOC_VENDOR,6); +pub const SIO_LIMIT_BROADCASTS: DWORD = _WSAIOW!(IOC_VENDOR,7); +pub const SIO_INDEX_BIND: DWORD = _WSAIOW!(IOC_VENDOR,8); +pub const SIO_INDEX_MCASTIF: DWORD = _WSAIOW!(IOC_VENDOR,9); +pub const SIO_INDEX_ADD_MCAST: DWORD = _WSAIOW!(IOC_VENDOR,10); +pub const SIO_INDEX_DEL_MCAST: DWORD = _WSAIOW!(IOC_VENDOR,11); +pub const SIO_RCVALL_MCAST_IF: DWORD = _WSAIOW!(IOC_VENDOR,13); +pub const SIO_RCVALL_IF: DWORD = _WSAIOW!(IOC_VENDOR,14); +pub const SIO_LOOPBACK_FAST_PATH: DWORD = _WSAIOW!(IOC_VENDOR,16); +pub const SIO_TCP_INITIAL_RTO: DWORD = _WSAIOW!(IOC_VENDOR,17); +pub const SIO_APPLY_TRANSPORT_SETTING: DWORD = _WSAIOW!(IOC_VENDOR,19); +pub const SIO_QUERY_TRANSPORT_SETTING: DWORD = _WSAIOW!(IOC_VENDOR,20); +pub const SIO_TCP_SET_ICW: DWORD = _WSAIOW!(IOC_VENDOR,22); +pub const SIO_TCP_SET_ACK_FREQUENCY: DWORD = _WSAIOW!(IOC_VENDOR,23); +pub const SIO_TCP_INFO: DWORD = _WSAIORW!(IOC_VENDOR,39); +ENUM!{enum RCVALL_VALUE { + RCVALL_OFF = 0, + RCVALL_ON = 1, + RCVALL_SOCKETLEVELONLY = 2, + RCVALL_IPLEVEL = 3, +}} +pub type PRCVALL_VALUE = *mut RCVALL_VALUE; +STRUCT!{struct RCVALL_IF { + Mode: RCVALL_VALUE, + Interface: ULONG, +}} +pub type PRCVALL_IF = *mut RCVALL_IF; +pub const TCP_INITIAL_RTO_UNSPECIFIED_RTT: USHORT = -1i16 as u16; +pub const TCP_INITIAL_RTO_UNSPECIFIED_MAX_SYN_RETRANSMISSIONS: UCHAR = -1i8 as u8; +pub const TCP_INITIAL_RTO_DEFAULT_RTT: USHORT = 0; +pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS: UCHAR = 0; +STRUCT!{struct TCP_INITIAL_RTO_PARAMETERS { + Rtt: USHORT, + MaxSynRetransmissions: UCHAR, +}} +pub type PTCP_INITIAL_RTO_PARAMETERS = *mut TCP_INITIAL_RTO_PARAMETERS; +ENUM!{enum TCP_ICW_LEVEL { + TCP_ICW_LEVEL_DEFAULT = 0, + TCP_ICW_LEVEL_HIGH = 1, + TCP_ICW_LEVEL_VERY_HIGH = 2, + TCP_ICW_LEVEL_AGGRESSIVE = 3, + TCP_ICW_LEVEL_EXPERIMENTAL = 4, + TCP_ICW_LEVEL_COMPAT = 254, + TCP_ICW_LEVEL_MAX = 255, +}} +pub type PTCP_ICW_LEVEL = *mut TCP_ICW_LEVEL; +STRUCT!{struct TCP_ICW_PARAMETERS { + Level: TCP_ICW_LEVEL, +}} +pub type PTCP_ICW_PARAMETERS = *mut TCP_ICW_PARAMETERS; +STRUCT!{struct TCP_ACK_FREQUENCY_PARAMETERS { + TcpDelayedAckFrequency: UCHAR, +}} +pub type PTCP_ACK_FREQUENCY_PARAMETERS = *mut TCP_ACK_FREQUENCY_PARAMETERS; +STRUCT!{struct TCP_INFO_v0 { + State: TCPSTATE, + Mss: ULONG, + ConnectionTimeMs: ULONG64, + TimestampsEnabled: BOOLEAN, + RttUs: ULONG, + MinRttUs: ULONG, + BytesInFlight: ULONG, + Cwnd: ULONG, + SndWnd: ULONG, + RcvWnd: ULONG, + RcvBuf: ULONG, + BytesOut: ULONG64, + BytesIn: ULONG64, + BytesReordered: ULONG, + BytesRetrans: ULONG, + FastRetrans: ULONG, + DupAcksIn: ULONG, + TimeoutEpisodes: ULONG, + SynRetrans: UCHAR, +}} +pub type PTCP_INFO_v0 = *mut TCP_INFO_v0; +pub const SIO_ACQUIRE_PORT_RESERVATION: DWORD = _WSAIOW!(IOC_VENDOR, 100); +pub const SIO_RELEASE_PORT_RESERVATION: DWORD = _WSAIOW!(IOC_VENDOR, 101); +pub const SIO_ASSOCIATE_PORT_RESERVATION: DWORD = _WSAIOW!(IOC_VENDOR, 102); +STRUCT!{struct INET_PORT_RANGE { + StartPort: USHORT, + NumberOfPorts: USHORT, +}} +pub type PINET_PORT_RANGE = *mut INET_PORT_RANGE; +pub type INET_PORT_RESERVATION = INET_PORT_RANGE; +pub type PINET_PORT_RESERVATION = *mut INET_PORT_RANGE; +STRUCT!{struct INET_PORT_RESERVATION_TOKEN { + Token: ULONG64, +}} +pub type PINET_PORT_RESERVATION_TOKEN = *mut INET_PORT_RESERVATION_TOKEN; +STRUCT!{struct INET_PORT_RESERVATION_INSTANCE { + Reservation: INET_PORT_RESERVATION, + Token: INET_PORT_RESERVATION_TOKEN, +}} +pub type PINET_PORT_RESERVATION_INSTANCE = *mut INET_PORT_RESERVATION_INSTANCE; +STRUCT!{struct INET_PORT_RESERVATION_INFORMATION { + OwningPid: ULONG, +}} +pub type PINET_PORT_RESERVATION_INFORMATION = *mut INET_PORT_RESERVATION_INFORMATION; +pub const SIO_SET_SECURITY: DWORD = _WSAIOW!(IOC_VENDOR, 200); +pub const SIO_QUERY_SECURITY: DWORD = _WSAIORW!(IOC_VENDOR, 201); +pub const SIO_SET_PEER_TARGET_NAME: DWORD = _WSAIOW!(IOC_VENDOR, 202); +pub const SIO_DELETE_PEER_TARGET_NAME: DWORD = _WSAIOW!(IOC_VENDOR, 203); +pub const SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS: DWORD = _WSAIOW!(IOC_VENDOR, 220); +pub const SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT: DWORD = _WSAIOW!(IOC_VENDOR, 221); +pub const SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS: DWORD = _WSAIOW!(IOC_VENDOR, 222); +pub const SIO_SOCKET_USAGE_NOTIFICATION: DWORD = _WSAIOW!(IOC_VENDOR, 204); +ENUM!{enum SOCKET_USAGE_TYPE { + SYSTEM_CRITICAL_SOCKET = 1, +}} +ENUM!{enum SOCKET_SECURITY_PROTOCOL { + SOCKET_SECURITY_PROTOCOL_DEFAULT, + SOCKET_SECURITY_PROTOCOL_IPSEC, + SOCKET_SECURITY_PROTOCOL_IPSEC2, + SOCKET_SECURITY_PROTOCOL_INVALID, +}} +STRUCT!{struct SOCKET_SECURITY_SETTINGS { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + SecurityFlags: ULONG, +}} +pub const SOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION: ULONG = 0x1; +pub const SOCKET_SETTINGS_IPSEC_OPTIONAL_PEER_NAME_VERIFICATION: ULONG = 0x2; +pub const SOCKET_SETTINGS_IPSEC_ALLOW_FIRST_INBOUND_PKT_UNENCRYPTED: ULONG = 0x4; +pub const SOCKET_SETTINGS_IPSEC_PEER_NAME_IS_RAW_FORMAT: ULONG = 0x8; +STRUCT!{struct SOCKET_SECURITY_SETTINGS_IPSEC { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + SecurityFlags: ULONG, + IpsecFlags: ULONG, + AuthipMMPolicyKey: GUID, + AuthipQMPolicyKey: GUID, + Reserved: GUID, + Reserved2: UINT64, + UserNameStringLen: ULONG, + DomainNameStringLen: ULONG, + PasswordStringLen: ULONG, + AllStrings: [wchar_t; 0], +}} +STRUCT!{struct SOCKET_PEER_TARGET_NAME { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + PeerAddress: SOCKADDR_STORAGE, + PeerTargetNameStringLen: ULONG, + AllStrings: [wchar_t; 0], +}} +STRUCT!{struct SOCKET_SECURITY_QUERY_TEMPLATE { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + PeerAddress: SOCKADDR_STORAGE, + PeerTokenAccessMask: ULONG, +}} +pub const SOCKET_QUERY_IPSEC2_ABORT_CONNECTION_ON_FIELD_CHANGE: ULONG = 0x1; +pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_MM_SA_ID: ULONG = 0x1; +pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_QM_SA_ID: ULONG = 0x2; +STRUCT!{struct SOCKET_SECURITY_QUERY_TEMPLATE_IPSEC2 { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + PeerAddress: SOCKADDR_STORAGE, + PeerTokenAccessMask: ULONG, + Flags: ULONG, + FieldMask: ULONG, +}} +pub const SOCKET_INFO_CONNECTION_SECURED: ULONG = 0x1; +pub const SOCKET_INFO_CONNECTION_ENCRYPTED: ULONG = 0x2; +pub const SOCKET_INFO_CONNECTION_IMPERSONATED: ULONG = 0x4; +STRUCT!{struct SOCKET_SECURITY_QUERY_INFO { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + Flags: ULONG, + PeerApplicationAccessTokenHandle: UINT64, + PeerMachineAccessTokenHandle: UINT64, +}} +STRUCT!{struct SOCKET_SECURITY_QUERY_INFO_IPSEC2 { + SecurityProtocol: SOCKET_SECURITY_PROTOCOL, + Flags: ULONG, + PeerApplicationAccessTokenHandle: UINT64, + PeerMachineAccessTokenHandle: UINT64, + MmSaId: UINT64, + QmSaId: UINT64, + NegotiationWinerr: UINT32, + SaLookupContext: GUID, +}} +pub const SIO_QUERY_WFP_ALE_ENDPOINT_HANDLE: DWORD = _WSAIOR!(IOC_VENDOR, 205); +pub const SIO_QUERY_RSS_SCALABILITY_INFO: DWORD = _WSAIOR!(IOC_VENDOR, 210); +STRUCT!{struct RSS_SCALABILITY_INFO { + RssEnabled: BOOLEAN, +}} +pub type PRSS_SCALABILITY_INFO = *mut RSS_SCALABILITY_INFO; +#[inline] +pub fn IN4_CLASSA(i: LONG) -> bool { + (i & 0x80) == 0 +} +#[inline] +pub fn IN4_CLASSB(i: LONG) -> bool { + (i & 0xc0) == 0x80 +} +#[inline] +pub fn IN4_CLASSC(i: LONG) -> bool { + (i & 0xe0) == 0xc0 +} +#[inline] +pub fn IN4_CLASSD(i: LONG) -> bool { + (i & 0xf0) == 0xe0 +} +#[inline] +pub fn IN4_MULTICAST(i: LONG) -> bool { + IN4_CLASSD(i) +} +pub const IN4ADDR_ANY: ULONG = INADDR_ANY; +pub const IN4ADDR_LOOPBACK: ULONG = 0x0100007f; +pub const IN4ADDR_BROADCAST: ULONG = INADDR_BROADCAST; +pub const IN4ADDR_NONE: ULONG = INADDR_NONE; +pub const IN4ADDR_LOOPBACKPREFIX_LENGTH: usize = 8; +pub const IN4ADDR_LINKLOCALPREFIX_LENGTH: usize = 16; +pub const IN4ADDR_MULTICASTPREFIX_LENGTH: usize = 4; +#[inline] +pub fn IN4_ADDR_EQUAL(a: &IN_ADDR, b: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == *b.S_un.S_addr() } +} +#[inline] +pub fn IN4_UNALIGNED_ADDR_EQUAL(a: &IN_ADDR, b: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == *b.S_un.S_addr() } +} +#[inline] +pub fn IN4_IS_ADDR_UNSPECIFIED(a: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == IN4ADDR_ANY } +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_UNSPECIFIED(a: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == IN4ADDR_ANY } +} +#[inline] +pub fn IN4_IS_ADDR_LOOPBACK(a: &IN_ADDR) -> bool { + unsafe { a.S_un.S_un_b().s_b1 == 0x7f } +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_LOOPBACK(a: &IN_ADDR) -> bool { + unsafe { a.S_un.S_un_b().s_b1 == 0x7f } +} +#[inline] +pub fn IN4_IS_ADDR_BROADCAST(a: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == IN4ADDR_BROADCAST } +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_BROADCAST(a: &IN_ADDR) -> bool { + unsafe { *a.S_un.S_addr() == IN4ADDR_BROADCAST } +} +#[inline] +pub fn IN4_IS_ADDR_MULTICAST(a: &IN_ADDR) -> bool { + IN4_MULTICAST(unsafe { *a.S_un.S_addr() as LONG }) +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_MULTICAST(a: &IN_ADDR) -> bool { + IN4_MULTICAST(unsafe { *a.S_un.S_addr() as LONG }) +} +#[inline] +pub fn IN4_IS_ADDR_LINKLOCAL(a: &IN_ADDR) -> bool { + unsafe { (*a.S_un.S_addr() & 0xffff) == 0xfea9 } +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_LINKLOCAL(a: &IN_ADDR) -> bool { + unsafe { (*a.S_un.S_addr() & 0xffff) == 0xfea9 } +} +#[inline] +pub fn IN4_IS_ADDR_SITELOCAL(_: &IN_ADDR) -> bool { + false +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_SITELOCAL(_: &IN_ADDR) -> bool { + false +} +#[inline] +pub fn IN4_IS_ADDR_RFC1918(a: &IN_ADDR) -> bool { + let s_addr = unsafe { *a.S_un.S_addr() }; + ((s_addr & 0x00ff) == 0x0a) || ((s_addr & 0xf0ff) == 0x10ac) || ((s_addr & 0xffff) == 0xa8c0) +} +#[inline] +pub fn IN4_IS_UNALIGNED_ADDR_RFC1918(a: &IN_ADDR) -> bool { + IN4_IS_ADDR_RFC1918(a) +} +#[inline] +pub fn IN4_IS_ADDR_MC_LINKLOCAL(a: &IN_ADDR) -> bool { + unsafe { (*a.S_un.S_addr() & 0xffffff) == 0xe0 } +} +#[inline] +pub fn IN4_IS_ADDR_MC_ADMINLOCAL(a: &IN_ADDR) -> bool { + unsafe { (*a.S_un.S_addr() & 0xffff) == 0xffef } +} +#[inline] +pub fn IN4_IS_ADDR_MC_SITELOCAL(a: &IN_ADDR) -> bool { + let first = unsafe { (*a.S_un.S_addr() & 0xff) == 0xef }; + first && !IN4_IS_ADDR_MC_ADMINLOCAL(a) +} +#[inline] +pub fn IN4ADDR_ISANY(a: &SOCKADDR_IN) -> bool { + IN4_IS_ADDR_UNSPECIFIED(&a.sin_addr) +} +#[inline] +pub fn IN4ADDR_ISLOOPBACK(a: &SOCKADDR_IN) -> bool { + IN4_IS_ADDR_LOOPBACK(&a.sin_addr) +} +extern "system" { + pub fn RtlIpv4AddressToStringA( + Addr: *const IN_ADDR, + S: PSTR, + ) -> PSTR; + pub fn RtlIpv4AddressToStringExA( + Address: *const IN_ADDR, + Port: USHORT, + AddressString: PSTR, + AddressStringLength: PULONG, + ) -> LONG; + pub fn RtlIpv4AddressToStringW( + Addr: *const IN_ADDR, + S: PWSTR, + ) -> PWSTR; + pub fn RtlIpv4AddressToStringExW( + Address: *const IN_ADDR, + Port: USHORT, + AddressString: PWSTR, + AddressStringLength: PULONG, + ) -> LONG; + pub fn RtlIpv4StringToAddressA( + S: PCSTR, + Strict: BOOLEAN, + Terminator: *mut PCSTR, + Addr: *mut IN_ADDR, + ) -> LONG; + pub fn RtlIpv4StringToAddressExA( + AddressString: PCSTR, + Strict: BOOLEAN, + Address: *mut IN_ADDR, + Port: PUSHORT, + ) -> LONG; + pub fn RtlIpv4StringToAddressW( + S: PCWSTR, + Strict: BOOLEAN, + Terminator: *mut LPCWSTR, + Addr: *mut IN_ADDR, + ) -> LONG; + pub fn RtlIpv4StringToAddressExW( + AddressString: PCWSTR, + Strict: BOOLEAN, + Address: *mut IN_ADDR, + Port: PUSHORT, + ) -> LONG; + pub fn RtlIpv6AddressToStringA( + Addr: *const IN6_ADDR, + S: PSTR, + ) -> PSTR; + pub fn RtlIpv6AddressToStringExA( + Address: *const IN6_ADDR, + ScopeId: ULONG, + Port: USHORT, + AddressString: PSTR, + AddressStringLength: PULONG, + ) -> LONG; + pub fn RtlIpv6AddressToStringW( + Addr: *const IN6_ADDR, + S: PWSTR, + ) -> PWSTR; + pub fn RtlIpv6AddressToStringExW( + Address: *const IN6_ADDR, + ScopeId: ULONG, + Port: USHORT, + AddressString: PWSTR, + AddressStringLength: PULONG, + ) -> LONG; + pub fn RtlIpv6StringToAddressA( + S: PCSTR, + Terminator: *mut PCSTR, + Addr: *mut IN6_ADDR, + ) -> LONG; + pub fn RtlIpv6StringToAddressExA( + AddressString: PCSTR, + Address: *mut IN6_ADDR, + ScopeId: PULONG, + Port: PUSHORT, + ) -> LONG; + pub fn RtlIpv6StringToAddressW( + S: PCWSTR, + Terminator: *mut PCWSTR, + Addr: *mut IN6_ADDR, + ) -> LONG; + pub fn RtlIpv6StringToAddressExW( + AddressString: PCWSTR, + Address: *mut IN6_ADDR, + ScopeId: PULONG, + Port: PUSHORT, + ) -> LONG; +} +DECLARE_HANDLE!{DL_EUI48, _DL_EUI48} +pub type PDL_EUI48 = *mut DL_EUI48; +extern "system" { + pub fn RtlEthernetAddressToStringA( + Addr: *const DL_EUI48, + S: PSTR, + ) -> PSTR; + pub fn RtlEthernetAddressToStringW( + Addr: *const DL_EUI48, + S: PWSTR, + ) -> PWSTR; + pub fn RtlEthernetStringToAddressA( + S: PCSTR, + Terminator: *mut PCSTR, + Addr: *mut DL_EUI48, + ) -> LONG; + pub fn RtlEthernetStringToAddressW( + S: PCWSTR, + Terminator: *mut LPCWSTR, + Addr: *mut DL_EUI48, + ) -> LONG; +} diff --git a/winapi/src/shared/mswsockdef.rs b/winapi/src/shared/mswsockdef.rs new file mode 100644 index 000000000..b62cf299d --- /dev/null +++ b/winapi/src/shared/mswsockdef.rs @@ -0,0 +1,48 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, ULONG}; +use shared::ws2def::IOC_VENDOR; +use um::winnt::{LONG, PVOID, ULONGLONG}; +pub const SIO_SET_COMPATIBILITY_MODE: DWORD = _WSAIOW!(IOC_VENDOR, 300); +ENUM!{enum WSA_COMPATIBILITY_BEHAVIOR_ID { + WsaBehaviorAll = 0, + WsaBehaviorReceiveBuffering, + WsaBehaviorAutoTuning, +}} +pub type PWSA_COMPATIBILITY_BEHAVIOR_ID = *mut WSA_COMPATIBILITY_BEHAVIOR_ID; +STRUCT!{struct WSA_COMPATIBILITY_MODE { + BehaviorId: WSA_COMPATIBILITY_BEHAVIOR_ID, + TargetOsVersion: ULONG, +}} +pub type PWSA_COMPATIBILITY_MODE = *mut WSA_COMPATIBILITY_MODE; +pub type RIO_BUFFERID = PVOID; +pub type PRIO_BUFFERID = *mut PVOID; +pub type RIO_CQ = PVOID; +pub type PRIO_CQ = *mut PVOID; +pub type RIO_RQ = PVOID; +pub type PRIO_RQ = *mut PVOID; +STRUCT!{struct RIORESULT { + Status: LONG, + BytesTransferred: ULONG, + SocketContext: ULONGLONG, + RequestContext: ULONGLONG, +}} +pub type PRIORESULT = *mut RIORESULT; +STRUCT!{struct RIO_BUF { + BufferId: RIO_BUFFERID, + Offset: ULONG, + Length: ULONG, +}} +pub type PRIO_BUF = *mut RIO_BUF; +pub const RIO_MSG_DONT_NOTIFY: DWORD = 0x00000001; +pub const RIO_MSG_DEFER: DWORD = 0x00000002; +pub const RIO_MSG_WAITALL: DWORD = 0x00000004; +pub const RIO_MSG_COMMIT_ONLY: DWORD = 0x00000008; +pub const RIO_INVALID_BUFFERID: RIO_BUFFERID = 0xFFFFFFFF as RIO_BUFFERID; +pub const RIO_INVALID_CQ: RIO_CQ = 0 as RIO_CQ; +pub const RIO_INVALID_RQ: RIO_RQ = 0 as RIO_RQ; +pub const RIO_MAX_CQ_SIZE: DWORD = 0x8000000; +pub const RIO_CORRUPT_CQ: ULONG = 0xFFFFFFFF; diff --git a/winapi/src/shared/netioapi.rs b/winapi/src/shared/netioapi.rs new file mode 100644 index 000000000..e8788e50b --- /dev/null +++ b/winapi/src/shared/netioapi.rs @@ -0,0 +1,57 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::SIZE_T; +use shared::guiddef::GUID; +use shared::ifdef::{NET_IFINDEX, NET_LUID, PNET_IFINDEX, PNET_LUID}; +use shared::minwindef::DWORD; +use shared::ntdef::{CHAR, PSTR, PWSTR, WCHAR}; +pub type NETIO_STATUS = DWORD; +pub type NETIOAPI_API = NETIO_STATUS; +extern "system" { + pub fn ConvertInterfaceNameToLuidA( + InterfaceName: *const CHAR, + InterfaceLuid: *mut NET_LUID, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceNameToLuidW( + InterfaceName: *const WCHAR, + InterfaceLuid: *mut NET_LUID, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceLuidToNameA( + InterfaceLuid: *const NET_LUID, + InterfaceName: PSTR, + Length: SIZE_T, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceLuidToNameW( + InterfaceLuid: *const NET_LUID, + InterfaceName: PWSTR, + Length: SIZE_T, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceLuidToIndex( + InterfaceLuid: *const NET_LUID, + InterfaceIndex: PNET_IFINDEX, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceIndexToLuid( + InterfaceIndex: NET_IFINDEX, + InterfaceLuid: PNET_LUID, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceLuidToAlias( + InterfaceLuid: *const NET_LUID, + InterfaceAlias: PWSTR, + Length: SIZE_T, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceAliasToLuid( + InterfaceAlias: *const WCHAR, + InterfaceLuid: PNET_LUID, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceLuidToGuid( + InterfaceLuid: *const NET_LUID, + InterfaceGuid: *mut GUID, + ) -> NETIOAPI_API; + pub fn ConvertInterfaceGuidToLuid( + InterfaceGuid: *const GUID, + InterfaceLuid: PNET_LUID, + ) -> NETIOAPI_API; +} diff --git a/winapi/src/shared/ntddscsi.rs b/winapi/src/shared/ntddscsi.rs new file mode 100644 index 000000000..ac47ec4e1 --- /dev/null +++ b/winapi/src/shared/ntddscsi.rs @@ -0,0 +1,834 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Constants and types for accessing SCSI port adapters. +use shared::basetsd::{ULONG32, ULONG_PTR}; +use shared::minwindef::{UCHAR, ULONG, USHORT}; +use shared::ntdef::{LARGE_INTEGER, LONG, LONGLONG, PVOID, ULONGLONG, VOID, WCHAR}; +use um::winioctl::{ + DEVICE_TYPE, FILE_ANY_ACCESS, FILE_DEVICE_CONTROLLER, FILE_READ_ACCESS, + FILE_WRITE_ACCESS, METHOD_BUFFERED +}; +use um::winnt::{ANYSIZE_ARRAY, BOOLEAN, PBOOLEAN}; +DEFINE_GUID!{ScsiRawInterfaceGuid, + 0x53f56309, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{WmiScsiAddressGuid, + 0x53f5630f, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +pub const IOCTL_SCSI_BASE: DEVICE_TYPE = FILE_DEVICE_CONTROLLER; +pub const FILE_DEVICE_SCSI: ULONG = 0x0000001; +pub const DD_SCSI_DEVICE_NAME: &'static str = "\\Device\\ScsiPort"; +pub const IOCTL_SCSI_PASS_THROUGH: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_MINIPORT: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_GET_INQUIRY_DATA: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SCSI_GET_CAPABILITIES: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SCSI_PASS_THROUGH_DIRECT: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_GET_ADDRESS: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SCSI_RESCAN_BUS: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SCSI_GET_DUMP_POINTERS: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SCSI_FREE_DUMP_POINTERS: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0409, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_IDE_PASS_THROUGH: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_ATA_PASS_THROUGH: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_ATA_PASS_THROUGH_DIRECT: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040c, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_ATA_MINIPORT: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040d, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_MINIPORT_PROCESS_SERVICE_IRP: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040e, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_MPIO_PASS_THROUGH_PATH: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x040f, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0410, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_PASS_THROUGH_EX: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0411, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0412, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_MPIO_PASS_THROUGH_PATH_EX: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0413, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_MPIO_PASS_THROUGH_PATH_DIRECT_EX: ULONG = + CTL_CODE!(IOCTL_SCSI_BASE, 0x0414, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SCSI_MINIPORT_NVCACHE: ULONG = ((FILE_DEVICE_SCSI << 16) + 0x0600); +pub const IOCTL_SCSI_MINIPORT_HYBRID: ULONG = ((FILE_DEVICE_SCSI << 16) + 0x0620); +pub const IOCTL_SCSI_MINIPORT_FIRMWARE: ULONG = ((FILE_DEVICE_SCSI << 16) + 0x0780); +STRUCT!{struct SCSI_PASS_THROUGH { + Length: USHORT, + ScsiStatus: UCHAR, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + CdbLength: UCHAR, + SenseInfoLength: UCHAR, + DataIn: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + DataBufferOffset: ULONG_PTR, + SenseInfoOffset: ULONG, + Cdb: [UCHAR; 16], +}} +pub type PSCSI_PASS_THROUGH = *mut SCSI_PASS_THROUGH; +STRUCT!{struct SCSI_PASS_THROUGH_DIRECT { + Length: USHORT, + ScsiStatus: UCHAR, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + CdbLength: UCHAR, + SenseInfoLength: UCHAR, + DataIn: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + DataBuffer: PVOID, + SenseInfoOffset: ULONG, + Cdb: [UCHAR; 16], +}} +pub type PSCSI_PASS_THROUGH_DIRECT = *mut SCSI_PASS_THROUGH_DIRECT; +STRUCT!{struct SCSI_PASS_THROUGH32 { + Length: USHORT, + ScsiStatus: UCHAR, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + CdbLength: UCHAR, + SenseInfoLength: UCHAR, + DataIn: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + DataBufferOffset: ULONG32, + SenseInfoOffset: ULONG, + Cdb: [UCHAR; 16], +}} +#[cfg(target_arch = "x86_64")] +IFDEF!{ +pub type PSCSI_PASS_THROUGH32 = *mut SCSI_PASS_THROUGH32; +STRUCT!{struct SCSI_PASS_THROUGH_DIRECT32 { + Length: USHORT, + ScsiStatus: UCHAR, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + CdbLength: UCHAR, + SenseInfoLength: UCHAR, + DataIn: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + DataBuffer: ULONG32, // Rust doesn't have anything like __ptr32 + SenseInfoOffset: ULONG, + Cdb: [UCHAR; 16], +}} +pub type PSCSI_PASS_THROUGH_DIRECT32 = *mut SCSI_PASS_THROUGH_DIRECT32; +} +STRUCT!{struct SCSI_PASS_THROUGH_EX { + Version: ULONG, + Length: ULONG, + CdbLength: ULONG, + StorAddressLength: ULONG, + ScsiStatus: UCHAR, + SenseInfolength: UCHAR, + DataDirection: UCHAR, + Reserved: UCHAR, + TimeOutValue: ULONG, + StorAddressOffset: ULONG, + SenseInfoOffset: ULONG, + DataOutTransferLength: ULONG, + DataInTransferLength: ULONG, + DataOutBufferOffset: ULONG_PTR, + DataInBufferOffset: ULONG_PTR, + Cdb: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PSCSI_PASS_THROUGH_EX = *mut SCSI_PASS_THROUGH_EX; +STRUCT!{struct SCSI_PASS_THROUGH_DIRECT_EX { + Version: ULONG, + Length: ULONG, + CdbLength: ULONG, + StorAddressLength: ULONG, + ScsiStatus: UCHAR, + SenseInfolength: UCHAR, + DataDirection: UCHAR, + Reserved: UCHAR, + TimeOutValue: ULONG, + StorAddressOffset: ULONG, + SenseInfoOffset: ULONG, + DataOutTransferLength: ULONG, + DataInTransferLength: ULONG, + DataOutBuffer: *mut VOID, + DataInBuffer: *mut VOID, + Cdb: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PSCSI_PASS_THROUGH_DIRECT_EX = *mut SCSI_PASS_THROUGH_DIRECT_EX; +#[cfg(target_arch = "x86_64")] +IFDEF!{ +STRUCT!{struct SCSI_PASS_THROUGH32_EX { + Version: ULONG, + Length: ULONG, + CdbLength: ULONG, + StorAddressLength: ULONG, + ScsiStatus: UCHAR, + SenseInfolength: UCHAR, + DataDirection: UCHAR, + Reserved: UCHAR, + TimeOutValue: ULONG, + StorAddressOffset: ULONG, + SenseInfoOffset: ULONG, + DataOutTransferLength: ULONG, + DataInTransferLength: ULONG, + DataOutBufferOffset: ULONG32, + DataInBufferOffset: ULONG32, + Cdb: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PSCSI_PASS_THROUGH32_EX = *mut SCSI_PASS_THROUGH32_EX; +STRUCT!{struct SCSI_PASS_THROUGH_DIRECT32_EX { + Version: ULONG, + Length: ULONG, + CdbLength: ULONG, + StorAddressLength: ULONG, + ScsiStatus: UCHAR, + SenseInfolength: UCHAR, + DataDirection: UCHAR, + Reserved: UCHAR, + TimeOutValue: ULONG, + StorAddressOffset: ULONG, + SenseInfoOffset: ULONG, + DataOutTransferLength: ULONG, + DataInTransferLength: ULONG, + DataOutBuffer: ULONG32, + DataInBuffer: ULONG32, + Cdb: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PSCSI_PASS_THROUGH_DIRECT32_EX = *mut SCSI_PASS_THROUGH_DIRECT32_EX; +} +STRUCT!{struct ATA_PASS_THROUGH_EX { + Length: USHORT, + AtaFlags: USHORT, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + ReservedAsUchar: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + ReservedAsUlong: ULONG, + DataBufferOffset: ULONG_PTR, + PreviousTaskFile: [UCHAR; 8], + CurrentTaskFile: [UCHAR; 8], +}} +pub type PATA_PASS_THROUGH_EX = *mut ATA_PASS_THROUGH_EX; +STRUCT!{struct ATA_PASS_THROUGH_DIRECT { + Length: USHORT, + AtaFlags: USHORT, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + ReservedAsUchar: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + ReservedAsUlong: ULONG, + DataBuffer: PVOID, + PreviousTaskFile: [UCHAR; 8], + CurrentTaskFile: [UCHAR; 8], +}} +pub type PATA_PASS_THROUGH_DIRECT = *mut ATA_PASS_THROUGH_DIRECT; +#[cfg(target_arch = "x86_64")] +IFDEF!{ +STRUCT!{struct ATA_PASS_THROUGH_EX32 { + Length: USHORT, + AtaFlags: USHORT, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + ReservedAsUchar: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + ReservedAsUlong: ULONG, + DataBufferOffset: ULONG32, + PreviousTaskFile: [UCHAR; 8], + CurrentTaskFile: [UCHAR; 8], +}} +pub type PATA_PASS_THROUGH_EX32 = *mut ATA_PASS_THROUGH_EX32; +STRUCT!{struct ATA_PASS_THROUGH_DIRECT32 { + Length: USHORT, + AtaFlags: USHORT, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + ReservedAsUchar: UCHAR, + DataTransferLength: ULONG, + TimeOutValue: ULONG, + ReservedAsUlong: ULONG, + DataBuffer: ULONG32, + PreviousTaskFile: [UCHAR; 8], + CurrentTaskFile: [UCHAR; 8], +}} +pub type PATA_PASS_THROUGH_DIRECT32 = *mut ATA_PASS_THROUGH_DIRECT32; +} +pub const ATA_FLAGS_DRDY_REQUIRED: USHORT = 1 << 0; +pub const ATA_FLAGS_DATA_IN: USHORT = 1 << 1; +pub const ATA_FLAGS_DATA_OUT: USHORT = 1 << 2; +pub const ATA_FLAGS_48BIT_COMMAND: USHORT = 1 << 3; +pub const ATA_FLAGS_USE_DMA: USHORT = 1 << 4; +pub const ATA_FLAGS_NO_MULTIPLE: USHORT = 1 << 5; +STRUCT!{struct IDE_IO_CONTROL { + HeaderLength: ULONG, + Signature: [UCHAR; 8], + Timeout: ULONG, + ControlCode: ULONG, + ReturnStatus: ULONG, + DataLength: ULONG, +}} +pub type PIDE_IO_CONTROL = *mut IDE_IO_CONTROL; +STRUCT!{struct MPIO_PASS_THROUGH_PATH { + PassThrough: SCSI_PASS_THROUGH, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH = *mut MPIO_PASS_THROUGH_PATH; +STRUCT!{struct MPIO_PASS_THROUGH_PATH_DIRECT { + PassThrough: SCSI_PASS_THROUGH_DIRECT, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH_DIRECT = *mut MPIO_PASS_THROUGH_PATH_DIRECT; +STRUCT!{struct MPIO_PASS_THROUGH_PATH_EX { + PassThroughOffset: ULONG, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH_EX = *mut MPIO_PASS_THROUGH_PATH_EX; +STRUCT!{struct MPIO_PASS_THROUGH_PATH_DIRECT_EX { + PassThroughOffset: ULONG, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH_DIRECT_EX = *mut MPIO_PASS_THROUGH_PATH_DIRECT_EX; +#[cfg(target_arch = "x86_64")] +IFDEF!{ +STRUCT!{struct MPIO_PASS_THROUGH_PATH32 { + PassThrough: SCSI_PASS_THROUGH32, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH32 = *mut MPIO_PASS_THROUGH_PATH32; +STRUCT!{struct MPIO_PASS_THROUGH_PATH_DIRECT32 { + PassThrough: SCSI_PASS_THROUGH_DIRECT32, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH_DIRECT32 = *mut MPIO_PASS_THROUGH_PATH_DIRECT32; +STRUCT!{struct MPIO_PASS_THROUGH_PATH32_EX { + PassThroughOffset: ULONG, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH32_EX = *mut MPIO_PASS_THROUGH_PATH32_EX; +STRUCT!{struct MPIO_PASS_THROUGH_PATH_DIRECT32_EX { + PassThroughOffset: ULONG, + Version: ULONG, + Length: USHORT, + Flags: UCHAR, + PortNumber: UCHAR, + MpioPathId: ULONGLONG, +}} +pub type PMPIO_PASS_THROUGH_PATH_DIRECT32_EX = *mut MPIO_PASS_THROUGH_PATH_DIRECT32_EX; +} +STRUCT!{struct SCSI_BUS_DATA { + NumberOfLogicalUnits: UCHAR, + InitiatorBusId: UCHAR, + InquiryDataOffset: ULONG, +}} +pub type PSCSI_BUS_DATA = *mut SCSI_BUS_DATA; +STRUCT!{struct SCSI_ADAPTER_BUS_INFO { + NumberOfBuses: UCHAR, + BusData: [SCSI_BUS_DATA; 1], +}} +pub type PSCSI_ADAPTER_BUS_INFO = *mut SCSI_ADAPTER_BUS_INFO; +STRUCT!{struct SCSI_INQUIRY_DATA { + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, + DeviceClaimed: BOOLEAN, + InquiryDataLength: ULONG, + NextInquiryDataOffset: ULONG, + InquiryData: [UCHAR; 1], +}} +pub type PSCSI_INQUIRY_DATA = *mut SCSI_INQUIRY_DATA; +pub const IOCTL_MINIPORT_SIGNATURE_SCSIDISK: &'static str = "SCSIDISK"; +pub const IOCTL_MINIPORT_SIGNATURE_HYBRDISK: &'static str = "HYBRDISK"; +pub const IOCTL_MINIPORT_SIGNATURE_DSM_NOTIFICATION: &'static str = "MPDSM "; +pub const IOCTL_MINIPORT_SIGNATURE_DSM_GENERAL: &'static str = "MPDSMGEN"; +pub const IOCTL_MINIPORT_SIGNATURE_FIRMWARE: &'static str = "FIRMWARE"; +pub const IOCTL_MINIPORT_SIGNATURE_QUERY_PROTOCOL: &'static str = "PROTOCOL"; +pub const IOCTL_MINIPORT_SIGNATURE_QUERY_TEMPERATURE: &'static str = "TEMPERAT"; +pub const IOCTL_MINIPORT_SIGNATURE_SET_TEMPERATURE_THRESHOLD: &'static str = "SETTEMPT"; +pub const IOCTL_MINIPORT_SIGNATURE_QUERY_PHYSICAL_TOPOLOGY: &'static str = "TOPOLOGY"; +STRUCT!{struct SRB_IO_CONTROL { + HeaderLength: ULONG, + Signature: [UCHAR; 8], + Timeout: ULONG, + ControlCode: ULONG, + ReturnCode: ULONG, + Length: ULONG, +}} +pub type PSRB_IO_CONTROL = *mut SRB_IO_CONTROL; +STRUCT!{struct NVCACHE_REQUEST_BLOCK { + NRBSize: ULONG, + Function: USHORT, + NRBFlags: ULONG, + NRBStatus: ULONG, + Count: ULONG, + LBA: ULONGLONG, + DataBufSize: ULONG, + NVCacheStatus: ULONG, + NVCacheSubStatus: ULONG, +}} +pub type PNVCACHE_REQUEST_BLOCK = *mut NVCACHE_REQUEST_BLOCK; +pub const NRB_FUNCTION_NVCACHE_INFO: USHORT = 0xEC; +pub const NRB_FUNCTION_SPINDLE_STATUS: USHORT = 0xE5; +pub const NRB_FUNCTION_NVCACHE_POWER_MODE_SET: USHORT = 0x00; +pub const NRB_FUNCTION_NVCACHE_POWER_MODE_RETURN: USHORT = 0x01; +pub const NRB_FUNCTION_FLUSH_NVCACHE: USHORT = 0x14; +pub const NRB_FUNCTION_QUERY_PINNED_SET: USHORT = 0x12; +pub const NRB_FUNCTION_QUERY_CACHE_MISS: USHORT = 0x13; +pub const NRB_FUNCTION_ADD_LBAS_PINNED_SET: USHORT = 0x10; +pub const NRB_FUNCTION_REMOVE_LBAS_PINNED_SET: USHORT = 0x11; +pub const NRB_FUNCTION_QUERY_ASCENDER_STATUS: USHORT = 0xD0; +pub const NRB_FUNCTION_QUERY_HYBRID_DISK_STATUS: USHORT = 0xD1; +pub const NRB_FUNCTION_PASS_HINT_PAYLOAD: USHORT = 0xE0; +pub const NRB_FUNCTION_NVSEPARATED_INFO: USHORT = 0xc0; +pub const NRB_FUNCTION_NVSEPARATED_FLUSH: USHORT = 0xc1; +pub const NRB_FUNCTION_NVSEPARATED_WB_DISABLE: USHORT = 0xc2; +pub const NRB_FUNCTION_NVSEPARATED_WB_REVERT_DEFAULT: USHORT = 0xc3; +pub const NRB_SUCCESS: ULONG = 0; +pub const NRB_ILLEGAL_REQUEST: ULONG = 1; +pub const NRB_INVALID_PARAMETER: ULONG = 2; +pub const NRB_INPUT_DATA_OVERRUN: ULONG = 3; +pub const NRB_INPUT_DATA_UNDERRUN: ULONG = 4; +pub const NRB_OUTPUT_DATA_OVERRUN: ULONG = 5; +pub const NRB_OUTPUT_DATA_UNDERRUN: ULONG = 6; +STRUCT!{struct NV_FEATURE_PARAMETER { + NVPowerModeEnabled: USHORT, + NVParameterReserv1: USHORT, + NVCmdEnabled: USHORT, + NVParameterReserv2: USHORT, + NVPowerModeVer: USHORT, + NVCmdVer: USHORT, + NVSize: ULONG, + NVReadSpeed: USHORT, + NVWrtSpeed: USHORT, + DeviceSpinUpTime: ULONG, +}} +pub type PNV_FEATURE_PARAMETER = *mut NV_FEATURE_PARAMETER; +STRUCT!{struct NVCACHE_HINT_PAYLOAD { + Command: UCHAR, + Feature7_0: UCHAR, + Feature15_8: UCHAR, + Count15_8: UCHAR, + LBA7_0: UCHAR, + LBA15_8: UCHAR, + LBA23_16: UCHAR, + LBA31_24: UCHAR, + LBA39_32: UCHAR, + LBA47_40: UCHAR, + Auxiliary7_0: UCHAR, + Auxiliary23_16: UCHAR, + Reserved: [UCHAR; 4], +}} +pub type PNVCACHE_HINT_PAYLOAD = *mut NVCACHE_HINT_PAYLOAD; +STRUCT!{struct NV_SEP_CACHE_PARAMETER { + Version: ULONG, + Size: ULONG, + Flags: NV_SEP_CACHE_PARAMETER_Flags, + WriteCacheType: UCHAR, + WriteCacheTypeEffective: UCHAR, + ParameterReserve1: [UCHAR; 3], +}} +pub type PNV_SEP_CACHE_PARAMETER = *mut NV_SEP_CACHE_PARAMETER; +UNION!{union NV_SEP_CACHE_PARAMETER_Flags { + [u8; 1], + CacheFlags CacheFlags_mut: NV_SEP_CACHE_PARAMETER_Flags_CacheFlags, + CacheFlagsSet CacheFlagsSet_mut: UCHAR, +}} +STRUCT!{struct NV_SEP_CACHE_PARAMETER_Flags_CacheFlags { + Bitfield: UCHAR, +}} +BITFIELD!{NV_SEP_CACHE_PARAMETER_Flags_CacheFlags Bitfield: UCHAR [ + WriteCacheEnabled set_WriteCacheEnabled[0..1], + WriteCacheChangeable set_WriteCacheChangeable[1..2], + WriteThroughIOSupported set_WriteThroughIOSupported[2..3], + FlushCacheSupported set_FlushCacheSupported[3..4], + ReservedBits set_ReservedBits[4..8], +]} +pub const NV_SEP_CACHE_PARAMETER_VERSION_1: ULONG = 1; +pub const NV_SEP_CACHE_PARAMETER_VERSION: ULONG = NV_SEP_CACHE_PARAMETER_VERSION_1; +ENUM!{enum NV_SEP_WRITE_CACHE_TYPE { + NVSEPWriteCacheTypeUnknown = 0, + NVSEPWriteCacheTypeNone = 1, + NVSEPWriteCacheTypeWriteBack = 2, + NVSEPWriteCacheTypeWriteThrough = 3, +}} +pub type PNV_SEP_WRITE_CACHE_TYPE = *mut NV_SEP_WRITE_CACHE_TYPE; +STRUCT!{struct MP_DEVICE_DATA_SET_RANGE { + StartingOffset: LONGLONG, + LengthInBytes: ULONGLONG, +}} +pub type PMP_DEVICE_DATA_SET_RANGE = *mut MP_DEVICE_DATA_SET_RANGE; +STRUCT!{struct DSM_NOTIFICATION_REQUEST_BLOCK { + Size: ULONG, + Version: ULONG, + NotifyFlags: ULONG, + DataSetProfile: ULONG, + Reserved: [ULONG; 3], + DataSetRangesCount: ULONG, + DataSetRanges: [MP_DEVICE_DATA_SET_RANGE; ANYSIZE_ARRAY], +}} +pub type PDSM_NOTIFICATION_REQUEST_BLOCK = *mut DSM_NOTIFICATION_REQUEST_BLOCK; +pub const MINIPORT_DSM_NOTIFICATION_VERSION_1: ULONG = 1; +pub const MINIPORT_DSM_NOTIFICATION_VERSION: ULONG = MINIPORT_DSM_NOTIFICATION_VERSION_1; +pub const MINIPORT_DSM_PROFILE_UNKNOWN: ULONG = 0; +pub const MINIPORT_DSM_PROFILE_PAGE_FILE: ULONG = 1; +pub const MINIPORT_DSM_PROFILE_HIBERNATION_FILE: ULONG = 2; +pub const MINIPORT_DSM_PROFILE_CRASHDUMP_FILE: ULONG = 3; +pub const MINIPORT_DSM_NOTIFY_FLAG_BEGIN: ULONG = 0x00000001; +pub const MINIPORT_DSM_NOTIFY_FLAG_END: ULONG = 0x00000002; +pub const HYBRID_FUNCTION_GET_INFO: ULONG = 0x01; +pub const HYBRID_FUNCTION_DISABLE_CACHING_MEDIUM: ULONG = 0x10; +pub const HYBRID_FUNCTION_ENABLE_CACHING_MEDIUM: ULONG = 0x11; +pub const HYBRID_FUNCTION_SET_DIRTY_THRESHOLD: ULONG = 0x12; +pub const HYBRID_FUNCTION_DEMOTE_BY_SIZE: ULONG = 0x13; +pub const HYBRID_STATUS_SUCCESS: ULONG = 0x0; +pub const HYBRID_STATUS_ILLEGAL_REQUEST: ULONG = 0x1; +pub const HYBRID_STATUS_INVALID_PARAMETER: ULONG = 0x2; +pub const HYBRID_STATUS_OUTPUT_BUFFER_TOO_SMALL: ULONG = 0x3; +pub const HYBRID_STATUS_ENABLE_REFCOUNT_HOLD: ULONG = 0x10; +pub const HYBRID_REQUEST_BLOCK_STRUCTURE_VERSION: ULONG = 0x1; +STRUCT!{struct HYBRID_REQUEST_BLOCK { + Version: ULONG, + Size: ULONG, + Function: ULONG, + Flags: ULONG, + DataBufferOffset: ULONG, + DataBufferLength: ULONG, +}} +pub type PHYBRID_REQUEST_BLOCK = *mut HYBRID_REQUEST_BLOCK; +ENUM!{enum NVCACHE_TYPE { + NvCacheTypeUnknown = 0, + NvCacheTypeNone = 1, + NvCacheTypeWriteBack = 2, + NvCacheTypeWriteThrough = 3, +}} +ENUM!{enum NVCACHE_STATUS { + NvCacheStatusUnknown = 0, + NvCacheStatusDisabling = 1, + NvCacheStatusDisabled = 2, + NvCacheStatusEnabled = 3, +}} +STRUCT!{struct NVCACHE_PRIORITY_LEVEL_DESCRIPTOR { + PriorityLevel: UCHAR, + Reserved0: [UCHAR; 3], + ConsumedNVMSizeFraction: ULONG, + ConsumedMappingResourcesFraction: ULONG, + ConsumedNVMSizeForDirtyDataFraction: ULONG, + ConsumedMappingResourcesForDirtyDataFraction: ULONG, + Reserved1: ULONG, +}} +pub type PNVCACHE_PRIORITY_LEVEL_DESCRIPTOR = *mut NVCACHE_PRIORITY_LEVEL_DESCRIPTOR; +pub const HYBRID_REQUEST_INFO_STRUCTURE_VERSION: ULONG = 1; +STRUCT!{struct HYBRID_INFORMATION { + Version: ULONG, + Size: ULONG, + HybridSupported: BOOLEAN, + Status: NVCACHE_STATUS, + CacheTypeEffective: NVCACHE_TYPE, + CacheTypeDefault: NVCACHE_TYPE, + FractionBase: ULONG, + CacheSize: ULONGLONG, + Attributes: HYBRID_INFORMATION_Attributes, + Priorities: HYBRID_INFORMATION_Priorities, +}} +pub type PHYBRID_INFORMATION = *mut HYBRID_INFORMATION; +STRUCT!{struct HYBRID_INFORMATION_Attributes { + Bitfield: ULONG, +}} +BITFIELD!{HYBRID_INFORMATION_Attributes Bitfield: ULONG [ + WriteCacheChangeable set_WriteCacheChangeable[0..1], + WriteThroughIoSupported set_WriteThroughIoSupported[1..2], + FlushCacheSupported set_FlushCacheSupported[2..3], + Removable set_Removable[3..4], + ReservedBits set_ReservedBits[4..32], +]} +STRUCT!{struct HYBRID_INFORMATION_Priorities { + PriorityLevelCount: UCHAR, + MaxPriorityBehavior: BOOLEAN, + OptimalWriteGranularity: UCHAR, + Reserved: UCHAR, + DirtyThresholdLow: ULONG, + DirtyThresholdHigh: ULONG, + SupportedCommands: HYBRID_INFORMATION_Priorities_SupportedCommands, + Priority: [NVCACHE_PRIORITY_LEVEL_DESCRIPTOR; 0], +}} +STRUCT!{struct HYBRID_INFORMATION_Priorities_SupportedCommands { + Bitfield: ULONG, + MaxEvictCommands: ULONG, + MaxLbaRangeCountForEvict: ULONG, + MaxLbaRangeCountForChangeLba: ULONG, +}} +BITFIELD!{HYBRID_INFORMATION_Priorities_SupportedCommands Bitfield: ULONG [ + CacheDisable set_CacheDisable[0..1], + SetDirtyThreshold set_SetDirtyThreshold[1..2], + PriorityDemoteBySize set_PriorityDemoteBySize[2..3], + PriorityChangeByLbaRange set_PriorityChangeByLbaRange[3..4], + Evict set_Evict[4..5], + ReservedBits set_ReservedBits[5..32], +]} +STRUCT!{struct HYBRID_DIRTY_THRESHOLDS { + Version: ULONG, + Size: ULONG, + DirtyLowThreshold: ULONG, + DirtyHighThreshold: ULONG, +}} +pub type PHYBRID_DIRTY_THRESHOLDS = *mut HYBRID_DIRTY_THRESHOLDS; +STRUCT!{struct HYBRID_DEMOTE_BY_SIZE { + Version: ULONG, + Size: ULONG, + SourcePriority: UCHAR, + TargetPriority: UCHAR, + Reserved0: USHORT, + Reserved1: ULONG, + LbaCount: ULONGLONG, +}} +pub type PHYBRID_DEMOTE_BY_SIZE = *mut HYBRID_DEMOTE_BY_SIZE; +pub const FIRMWARE_FUNCTION_GET_INFO: ULONG = 0x01; +pub const FIRMWARE_FUNCTION_DOWNLOAD: ULONG = 0x02; +pub const FIRMWARE_FUNCTION_ACTIVATE: ULONG = 0x03; +pub const FIRMWARE_STATUS_SUCCESS: ULONG = 0x0; +pub const FIRMWARE_STATUS_ERROR: ULONG = 0x1; +pub const FIRMWARE_STATUS_ILLEGAL_REQUEST: ULONG = 0x2; +pub const FIRMWARE_STATUS_INVALID_PARAMETER: ULONG = 0x3; +pub const FIRMWARE_STATUS_INPUT_BUFFER_TOO_BIG: ULONG = 0x4; +pub const FIRMWARE_STATUS_OUTPUT_BUFFER_TOO_SMALL: ULONG = 0x5; +pub const FIRMWARE_STATUS_INVALID_SLOT: ULONG = 0x6; +pub const FIRMWARE_STATUS_INVALID_IMAGE: ULONG = 0x7; +pub const FIRMWARE_STATUS_CONTROLLER_ERROR: ULONG = 0x10; +pub const FIRMWARE_STATUS_POWER_CYCLE_REQUIRED: ULONG = 0x20; +pub const FIRMWARE_STATUS_DEVICE_ERROR: ULONG = 0x40; +pub const FIRMWARE_STATUS_INTERFACE_CRC_ERROR: ULONG = 0x80; +pub const FIRMWARE_STATUS_UNCORRECTABLE_DATA_ERROR: ULONG = 0x81; +pub const FIRMWARE_STATUS_MEDIA_CHANGE: ULONG = 0x82; +pub const FIRMWARE_STATUS_ID_NOT_FOUND: ULONG = 0x83; +pub const FIRMWARE_STATUS_MEDIA_CHANGE_REQUEST: ULONG = 0x84; +pub const FIRMWARE_STATUS_COMMAND_ABORT: ULONG = 0x85; +pub const FIRMWARE_STATUS_END_OF_MEDIA: ULONG = 0x86; +pub const FIRMWARE_STATUS_ILLEGAL_LENGTH: ULONG = 0x87; +pub const FIRMWARE_REQUEST_BLOCK_STRUCTURE_VERSION: ULONG = 0x1; +STRUCT!{struct FIRMWARE_REQUEST_BLOCK { + Version: ULONG, + Size: ULONG, + Function: ULONG, + Flags: ULONG, + DataBufferOffset: ULONG, + DataBufferLength: ULONG, +}} +pub type PFIRMWARE_REQUEST_BLOCK = *mut FIRMWARE_REQUEST_BLOCK; +pub const FIRMWARE_REQUEST_FLAG_CONTROLLER: ULONG = 0x00000001; +pub const FIRMWARE_REQUEST_FLAG_LAST_SEGMENT: ULONG = 0x00000002; +pub const FIRMWARE_REQUEST_FLAG_SWITCH_TO_EXISTING_FIRMWARE: ULONG = 0x80000000; +pub const STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION: ULONG = 0x1; +pub const STORAGE_FIRMWARE_INFO_STRUCTURE_VERSION_V2: ULONG = 0x2; +pub const STORAGE_FIRMWARE_INFO_INVALID_SLOT: UCHAR = 0xFF; +STRUCT!{struct STORAGE_FIRMWARE_SLOT_INFO { + SlotNumber: UCHAR, + ReadOnly: BOOLEAN, + Reserved: [UCHAR; 6], + Revision: STORAGE_FIRMWARE_SLOT_INFO_Revision, +}} +pub type PSTORAGE_FIRMWARE_SLOT_INFO = *mut STORAGE_FIRMWARE_SLOT_INFO; +UNION!{union STORAGE_FIRMWARE_SLOT_INFO_Revision { + [u64; 1], + Info Info_mut: [UCHAR; 8], + AsUlonglong AsUlonglong_mut: ULONGLONG, +}} +pub const STORAGE_FIRMWARE_SLOT_INFO_V2_REVISION_LENGTH: usize = 16; +STRUCT!{struct STORAGE_FIRMWARE_SLOT_INFO_V2 { + SlotNumber: UCHAR, + ReadOnly: BOOLEAN, + Reserved: [UCHAR; 6], + Revision: [UCHAR; STORAGE_FIRMWARE_SLOT_INFO_V2_REVISION_LENGTH], +}} +pub type PSTORAGE_FIRMWARE_SLOT_INFO_V2 = *mut STORAGE_FIRMWARE_SLOT_INFO_V2; +STRUCT!{struct STORAGE_FIRMWARE_INFO { + Version: ULONG, + Size: ULONG, + UpgradeSupport: BOOLEAN, + SlotCount: UCHAR, + ActiveSlot: UCHAR, + PendingActivateSlot: UCHAR, + Reserved: ULONG, + Slot: [STORAGE_FIRMWARE_SLOT_INFO; 0], +}} +pub type PSTORAGE_FIRMWARE_INFO = *mut STORAGE_FIRMWARE_INFO; +STRUCT!{struct STORAGE_FIRMWARE_INFO_V2 { + Version: ULONG, + Size: ULONG, + UpgradeSupport: BOOLEAN, + SlotCount: UCHAR, + ActiveSlot: UCHAR, + PendingActivateSlot: UCHAR, + FirmwareShared: BOOLEAN, + Reserved: [UCHAR; 3], + ImagePayloadAlignment: ULONG, + ImagePayloadMaxSize: ULONG, + Slot: [STORAGE_FIRMWARE_SLOT_INFO_V2; 0], +}} +pub type PSTORAGE_FIRMWARE_INFO_V2 = *mut STORAGE_FIRMWARE_INFO_V2; +pub const STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION: ULONG = 0x1; +pub const STORAGE_FIRMWARE_DOWNLOAD_STRUCTURE_VERSION_V2: ULONG = 0x2; +STRUCT!{struct STORAGE_FIRMWARE_DOWNLOAD { + Version: ULONG, + Size: ULONG, + Offset: ULONGLONG, + BufferSize: ULONGLONG, + ImageBuffer: [UCHAR; 0], +}} +pub type PSTORAGE_FIRMWARE_DOWNLOAD = *mut STORAGE_FIRMWARE_DOWNLOAD; +STRUCT!{struct STORAGE_FIRMWARE_DOWNLOAD_V2 { + Version: ULONG, + Size: ULONG, + Offset: ULONGLONG, + BufferSize: ULONGLONG, + Slot: UCHAR, + Reserved: [UCHAR; 7], + ImageBuffer: [UCHAR; 0], +}} +pub type PSTORAGE_FIRMWARE_DOWNLOAD_V2 = *mut STORAGE_FIRMWARE_DOWNLOAD_V2; +pub const STORAGE_FIRMWARE_ACTIVATE_STRUCTURE_VERSION: ULONG = 0x1; +STRUCT!{struct STORAGE_FIRMWARE_ACTIVATE { + Version: ULONG, + Size: ULONG, + SlotToActivate: UCHAR, + Reserved0: [UCHAR; 3], +}} +pub type PSTORAGE_FIRMWARE_ACTIVATE = *mut STORAGE_FIRMWARE_ACTIVATE; +STRUCT!{struct IO_SCSI_CAPABILITIES { + Length: ULONG, + MaximumTransferLength: ULONG, + MaximumPhysicalPages: ULONG, + SupportedAsynchronousEvents: ULONG, + AlignmentMask: ULONG, + TaggedQueuing: BOOLEAN, + AdapterScansDown: BOOLEAN, + AdapterUsesPio: BOOLEAN, +}} +pub type PIO_SCSI_CAPABILITIES = *mut IO_SCSI_CAPABILITIES; +STRUCT!{struct SCSI_ADDRESS { + Length: ULONG, + PortNumber: UCHAR, + PathId: UCHAR, + TargetId: UCHAR, + Lun: UCHAR, +}} +pub type PSCSI_ADDRESS = *mut SCSI_ADDRESS; +pub const DUMP_POINTERS_VERSION_1: ULONG = 1; +pub const DUMP_POINTERS_VERSION_2: ULONG = 2; +pub const DUMP_POINTERS_VERSION_3: ULONG = 3; +pub const DUMP_POINTERS_VERSION_4: ULONG = 4; +pub const DUMP_DRIVER_NAME_LENGTH: usize = 15; +FN!{cdecl DUMP_DEVICE_POWERON_ROUTINE( + Context: PVOID, +) -> LONG} +pub type PDUMP_DEVICE_POWERON_ROUTINE = *mut DUMP_DEVICE_POWERON_ROUTINE; +STRUCT!{struct DUMP_POINTERS_VERSION { + Version: ULONG, + Size: ULONG, +}} +pub type PDUMP_POINTERS_VERSION = *mut DUMP_POINTERS_VERSION; +STRUCT!{struct DUMP_POINTERS { + AdapterObject: PVOID, // struct _ADAPTER_OBJECT * + MappedRegisterBase: PVOID, + DumpData: PVOID, + CommonBufferVa: PVOID, + CommonBufferPa: LARGE_INTEGER, + CommonBufferSize: ULONG, + AllocateCommonBuffers: BOOLEAN, + UseDiskDump: BOOLEAN, + Spare1: [UCHAR; 2], + DeviceObject: PVOID, +}} +pub type PDUMP_POINTERS = *mut DUMP_POINTERS; +STRUCT!{struct DUMP_POINTERS_EX { + Header: DUMP_POINTERS_VERSION, + DumpData: PVOID, + CommonBufferVa: PVOID, + CommonBufferSize: ULONG, + AllocateCommonBuffers: BOOLEAN, + DeviceObject: PVOID, + DriverList: PVOID, + dwPortFlags: ULONG, + MaxDeviceDumpSectionSize: ULONG, + MaxDeviceDumpLevel: ULONG, + MaxTransferSize: ULONG, + AdapterObject: PVOID, + MappedRegisterBase: PVOID, + DeviceReady: PBOOLEAN, + DumpDevicePowerOn: PDUMP_DEVICE_POWERON_ROUTINE, + DumpDevicePowerOnContext: PVOID, +}} +pub type PDUMP_POINTERS_EX = *mut DUMP_POINTERS_EX; +// TODO: Revisit these definitions when const size_of and offset_of! arrive. +#[cfg(target_pointer_width = "32")] +IFDEF!{ +pub const DUMP_POINTERS_EX_V2_SIZE: ULONG = 32; +pub const DUMP_POINTERS_EX_V3_SIZE: ULONG = 60; +pub const DUMP_POINTERS_EX_V4_SIZE: ULONG = 68; +} +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub const DUMP_POINTERS_EX_V2_SIZE: ULONG = 48; +pub const DUMP_POINTERS_EX_V3_SIZE: ULONG = 88; +pub const DUMP_POINTERS_EX_V4_SIZE: ULONG = 104; +} +pub const DUMP_EX_FLAG_SUPPORT_64BITMEMORY: ULONG = 0x00000001; +pub const DUMP_EX_FLAG_SUPPORT_DD_TELEMETRY: ULONG = 0x00000002; +pub const DUMP_EX_FLAG_RESUME_SUPPORT: ULONG = 0x00000004; +STRUCT!{struct DUMP_DRIVER { + DumpDriverList: PVOID, + DriverName: [WCHAR; DUMP_DRIVER_NAME_LENGTH], + BaseName: [WCHAR; DUMP_DRIVER_NAME_LENGTH], +}} +pub type PDUMP_DRIVER = *mut DUMP_DRIVER; +pub const SCSI_IOCTL_DATA_OUT: UCHAR = 0; +pub const SCSI_IOCTL_DATA_IN: UCHAR = 1; +pub const SCSI_IOCTL_DATA_UNSPECIFIED: UCHAR = 2; +pub const SCSI_IOCTL_DATA_BIDIRECTIONAL: UCHAR = 3; +pub const MPIO_IOCTL_FLAG_USE_PATHID: UCHAR = 1; +pub const MPIO_IOCTL_FLAG_USE_SCSIADDRESS: UCHAR = 2; +pub const MPIO_IOCTL_FLAG_INVOLVE_DSM: UCHAR = 4; diff --git a/winapi/src/shared/ntddser.rs b/winapi/src/shared/ntddser.rs new file mode 100644 index 000000000..d37b7f6ae --- /dev/null +++ b/winapi/src/shared/ntddser.rs @@ -0,0 +1,17 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This is the include file that defines all constants and types for accessing the Serial device. +use shared::devpropdef::DEVPROPKEY; +DEFINE_GUID!{GUID_DEVINTERFACE_COMPORT, + 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73} +DEFINE_GUID!{GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, + 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_Serial_UsbVendorId, + 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_Serial_UsbProductId, + 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_DeviceInterface_Serial_PortName, + 0x4C6BF15C, 0x4C03, 0x4AAC, 0x91, 0xF5, 0x64, 0xC0, 0xF8, 0x52, 0xBC, 0xF4, 4} diff --git a/winapi/src/shared/ntdef.rs b/winapi/src/shared/ntdef.rs new file mode 100644 index 000000000..2a4e1209a --- /dev/null +++ b/winapi/src/shared/ntdef.rs @@ -0,0 +1,1073 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Type definitions for the basic types. +use ctypes::{ + __int64, __uint64, c_char, c_double, c_int, c_long, c_schar, c_short, c_uchar, c_ulong, + c_ushort, c_void, wchar_t +}; +use shared::basetsd::{KAFFINITY, LONG_PTR, ULONG64, ULONG_PTR}; +use shared::guiddef::GUID; +#[cfg(target_arch = "x86_64")] +IFDEF!{ +pub const MAX_NATURAL_ALIGNMENT: usize = 8; +pub const MEMORY_ALLOCATION_ALIGNMENT: usize = 16; +} +#[cfg(not(target_arch = "x86_64"))] +IFDEF!{ +pub const MAX_NATURAL_ALIGNMENT: usize = 4; +pub const MEMORY_ALLOCATION_ALIGNMENT: usize = 8; +} +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +pub const SYSTEM_CACHE_ALIGNMENT_SIZE: usize = 64; +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] +pub const SYSTEM_CACHE_ALIGNMENT_SIZE: usize = 128; +pub type PVOID = *mut c_void; +pub type PVOID64 = u64; // This is a 64-bit pointer, even when in 32-bit +pub type VOID = c_void; +pub type CHAR = c_char; +pub type SHORT = c_short; +pub type LONG = c_long; +pub type INT = c_int; +pub type WCHAR = wchar_t; +pub type PWCHAR = *mut WCHAR; +pub type LPWCH = *mut WCHAR; +pub type PWCH = *mut WCHAR; +pub type LPCWCH = *const WCHAR; +pub type PCWCH = *const WCHAR; +pub type NWPSTR = *mut WCHAR; +pub type LPWSTR = *mut WCHAR; +pub type LPTSTR = LPSTR; +pub type PWSTR = *mut WCHAR; +pub type PZPWSTR = *mut PWSTR; +pub type PCZPWSTR = *const PWSTR; +pub type LPUWSTR = *mut WCHAR; // Unaligned pointer +pub type PUWSTR = *mut WCHAR; // Unaligned pointer +pub type LPCWSTR = *const WCHAR; +pub type PCWSTR = *const WCHAR; +pub type PZPCWSTR = *mut PCWSTR; +pub type PCZPCWSTR = *const PCWSTR; +pub type LPCUWSTR = *const WCHAR; // Unaligned pointer +pub type PCUWSTR = *const WCHAR; // Unaligned pointer +pub type PZZWSTR = *mut WCHAR; +pub type PCZZWSTR = *const WCHAR; +pub type PUZZWSTR = *mut WCHAR; // Unaligned pointer +pub type PCUZZWSTR = *const WCHAR; // Unaligned pointer +pub type PNZWCH = *mut WCHAR; +pub type PCNZWCH = *const WCHAR; +pub type PUNZWCH = *mut WCHAR; // Unaligned pointer +pub type PCUNZWCH = *const WCHAR; // Unaligned pointer +pub type LPCWCHAR = *const WCHAR; +pub type PCWCHAR = *const WCHAR; +pub type LPCUWCHAR = *const WCHAR; // Unaligned pointer +pub type PCUWCHAR = *const WCHAR; // Unaligned pointer +pub type UCSCHAR = c_ulong; +pub const UCSCHAR_INVALID_CHARACTER: UCSCHAR = 0xffffffff; +pub const MIN_UCSCHAR: UCSCHAR = 0; +pub const MAX_UCSCHAR: UCSCHAR = 0x0010FFFF; +pub type PUCSCHAR = *mut UCSCHAR; +pub type PCUCSCHAR = *const UCSCHAR; +pub type PUCSSTR = *mut UCSCHAR; +pub type PUUCSSTR = *mut UCSCHAR; // Unaligned pointer +pub type PCUCSSTR = *const UCSCHAR; +pub type PCUUCSSTR = *const UCSCHAR; // Unaligned pointer +pub type PUUCSCHAR = *mut UCSCHAR; // Unaligned pointer +pub type PCUUCSCHAR = *const UCSCHAR; // Unaligned pointer +pub type PCHAR = *mut CHAR; +pub type LPCH = *mut CHAR; +pub type PCH = *mut CHAR; +pub type LPCCH = *const CHAR; +pub type PCCH = *const CHAR; +pub type NPSTR = *mut CHAR; +pub type LPSTR = *mut CHAR; +pub type PSTR = *mut CHAR; +pub type PZPSTR = *mut PSTR; +pub type PCZPSTR = *const PSTR; +pub type LPCSTR = *const CHAR; +pub type PCSTR = *const CHAR; +pub type PZPCSTR = *mut PCSTR; +pub type PCZPCSTR = *const PCSTR; +pub type PZZSTR = *mut CHAR; +pub type PCZZSTR = *const CHAR; +pub type PNZCH = *mut CHAR; +pub type PCNZCH = *const CHAR; +// Skipping TCHAR things +pub type DOUBLE = c_double; +STRUCT!{struct QUAD { + UseThisFieldToCopy: __int64, +}} +pub type PSHORT = *mut SHORT; +pub type PLONG = *mut LONG; +pub type PQUAD = *mut QUAD; +pub type UCHAR = c_uchar; +pub type USHORT = c_ushort; +pub type ULONG = c_ulong; +pub type UQUAD = QUAD; +pub type PUCHAR = *mut UCHAR; +pub type PUSHORT = *mut USHORT; +pub type PULONG = *mut ULONG; +pub type PUQUAD = *mut UQUAD; +pub type PCUCHAR = *const UCHAR; +pub type PCUSHORT = *const USHORT; +pub type PCULONG = *const ULONG; +pub type PCUQUAD = *const UQUAD; +pub type SCHAR = c_schar; +pub type PSCHAR = *mut SCHAR; +pub type PCSCHAR = *const SCHAR; +pub const ALL_PROCESSOR_GROUPS: USHORT = 0xffff; +STRUCT!{struct PROCESSOR_NUMBER { + Group: USHORT, + Number: UCHAR, + Reserved: UCHAR, +}} +pub type PPROCESSOR_NUMBER = *mut PROCESSOR_NUMBER; +STRUCT!{struct GROUP_AFFINITY { + Mask: KAFFINITY, + Group: USHORT, + Reserved: [USHORT; 3], +}} +pub type PGROUP_AFFINITY = *mut GROUP_AFFINITY; +#[cfg(target_arch = "x86_64")] +pub const MAXIMUM_PROC_PER_GROUP: UCHAR = 64; +#[cfg(not(target_arch = "x86_64"))] +pub const MAXIMUM_PROC_PER_GROUP: UCHAR = 32; +pub const MAXIMUM_PROCESSORS: UCHAR = MAXIMUM_PROC_PER_GROUP; +pub type HANDLE = *mut c_void; +pub type PHANDLE = *mut HANDLE; +pub type FCHAR = UCHAR; +pub type FSHORT = USHORT; +pub type FLONG = ULONG; +pub type HRESULT = c_long; +pub const OBJ_HANDLE_TAGBITS: usize = 0x00000003; +pub type CCHAR = c_char; +pub type CSHORT = c_short; +pub type CLONG = ULONG; +pub type PCCHAR = *mut CCHAR; +pub type PCSHORT = *mut CSHORT; +pub type PCLONG = *mut CLONG; +pub type LCID = ULONG; +pub type PLCID = PULONG; +pub type LANGID = USHORT; +ENUM!{enum COMPARTMENT_ID { + UNSPECIFIED_COMPARTMENT_ID = 0, + DEFAULT_COMPARTMENT_ID, +}} +pub type PCOMPARTMENT_ID = *mut COMPARTMENT_ID; +pub type LOGICAL = ULONG; +pub type PLOGICAL = *mut ULONG; +pub type NTSTATUS = LONG; +pub type PNTSTATUS = *mut NTSTATUS; +pub type PCNTSTATUS = *const NTSTATUS; +#[inline] +pub fn NT_SUCCESS(Status: NTSTATUS) -> bool { + Status >= 0 +} +#[inline] +pub fn NT_INFORMATION(Status: NTSTATUS) -> bool { + ((Status as ULONG) >> 30) == 1 +} +#[inline] +pub fn NT_WARNING(Status: NTSTATUS) -> bool { + ((Status as ULONG) >> 30) == 2 +} +#[inline] +pub fn NT_ERROR(Status: NTSTATUS) -> bool { + ((Status as ULONG) >> 30) == 3 +} +pub const APPLICATION_ERROR_MASK: ULONG = 0x20000000; +pub const ERROR_SEVERITY_SUCCESS: ULONG = 0x00000000; +pub const ERROR_SEVERITY_INFORMATIONAL: ULONG = 0x40000000; +pub const ERROR_SEVERITY_WARNING: ULONG = 0x80000000; +pub const ERROR_SEVERITY_ERROR: ULONG = 0xC0000000; +pub type SECURITY_STATUS = c_long; +pub type TIME = LARGE_INTEGER; +pub type PTIME = *mut TIME; +STRUCT!{struct FLOAT128 { + LowPart: __int64, + HighPart: __int64, +}} +pub type PFLOAT128 = *mut FLOAT128; +pub type LONGLONG = __int64; +pub type ULONGLONG = __uint64; +pub const MAXLONGLONG: LONGLONG = 0x7fffffffffffffff; +pub type PLONGLONG = *mut LONGLONG; +pub type PULONGLONG = *mut ULONGLONG; +pub type USN = LONGLONG; +UNION!{union LARGE_INTEGER { + [i64; 1], + s s_mut: LARGE_INTEGER_s, + QuadPart QuadPart_mut: LONGLONG, +}} +STRUCT!{struct LARGE_INTEGER_s { + LowPart: ULONG, + HighPart: LONG, +}} +pub type PLARGE_INTEGER = *mut LARGE_INTEGER; +UNION!{union ULARGE_INTEGER { + [u64; 1], + s s_mut: ULARGE_INTEGER_s, + QuadPart QuadPart_mut: ULONGLONG, +}} +STRUCT!{struct ULARGE_INTEGER_s { + LowPart: ULONG, + HighPart: ULONG, +}} +pub type PULARGE_INTEGER = *mut ULARGE_INTEGER; +pub type RTL_REFERENCE_COUNT = LONG_PTR; +pub type PRTL_REFERENCE_COUNT = *mut RTL_REFERENCE_COUNT; +STRUCT!{struct LUID { + LowPart: ULONG, + HighPart: LONG, +}} +pub type PLUID = *mut LUID; +pub type DWORDLONG = ULONGLONG; +pub type PDWORDLONG = *mut DWORDLONG; +pub type PHYSICAL_ADDRESS = LARGE_INTEGER; +pub type PPHYSICAL_ADDRESS = *mut PHYSICAL_ADDRESS; +ENUM!{enum EVENT_TYPE { + NotificationEvent, + SynchronizationEvent, +}} +ENUM!{enum TIMER_TYPE { + NotificationTimer, + SynchronizationTimer, +}} +ENUM!{enum WAIT_TYPE { + WaitAll, + WaitAny, + WaitNotification, + WaitDequeue, +}} +pub type PSZ = *mut CHAR; +pub type PCSZ = *const c_char; +pub type RTL_STRING_LENGTH_TYPE = USHORT; +STRUCT!{struct STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PCHAR, +}} +pub type PSTRING = *mut STRING; +pub type ANSI_STRING = STRING; +pub type PANSI_STRING = PSTRING; +pub type OEM_STRING = STRING; +pub type POEM_STRING = PSTRING; +pub type PCOEM_STRING = *const STRING; +STRUCT!{struct CSTRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: *const c_char, +}} +pub type PCSTRING = *mut CSTRING; +pub const ANSI_NULL: CHAR = 0; +pub type CANSI_STRING = STRING; +pub type PCANSI_STRING = PSTRING; +STRUCT!{struct UNICODE_STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PWCH, +}} +pub type PUNICODE_STRING = *mut UNICODE_STRING; +pub type PCUNICODE_STRING = *const UNICODE_STRING; +pub const UNICODE_NULL: WCHAR = 0; +pub const UNICODE_STRING_MAX_BYTES: USHORT = 65534; +pub const UNICODE_STRING_MAX_CHARS: usize = 32767; +pub type BOOLEAN = UCHAR; +pub type PBOOLEAN = *mut BOOLEAN; +STRUCT!{struct LIST_ENTRY { + Flink: *mut LIST_ENTRY, + Blink: *mut LIST_ENTRY, +}} +pub type PLIST_ENTRY = *mut LIST_ENTRY; +pub type PRLIST_ENTRY = *mut LIST_ENTRY; // Restricted pointer +STRUCT!{struct SINGLE_LIST_ENTRY { + Next: *mut SINGLE_LIST_ENTRY, +}} +pub type PSINGLE_LIST_ENTRY = *mut SINGLE_LIST_ENTRY; +STRUCT!{struct RTL_BALANCED_NODE { + u: RTL_BALANCED_NODE_u, + ParentValue: ULONG_PTR, +}} +UNION!{union RTL_BALANCED_NODE_u { + [usize; 2], + Children Children_mut: [*mut RTL_BALANCED_NODE; 2], + s s_mut: RTL_BALANCED_NODE_s, +}} +STRUCT!{struct RTL_BALANCED_NODE_s { + Left: *mut RTL_BALANCED_NODE, + Right: *mut RTL_BALANCED_NODE, +}} +pub const RTL_BALANCED_NODE_RESERVED_PARENT_MASK: ULONG_PTR = 3; +pub type PRTL_BALANCED_NODE = *mut RTL_BALANCED_NODE; +#[inline] +pub unsafe fn RTL_BALANCED_NODE_GET_PARENT_POINTER( + Node: PRTL_BALANCED_NODE, +) -> PRTL_BALANCED_NODE { + ((*Node).ParentValue & !RTL_BALANCED_NODE_RESERVED_PARENT_MASK) as *mut RTL_BALANCED_NODE +} +STRUCT!{struct LIST_ENTRY32 { + Flink: ULONG, + Blink: ULONG, +}} +pub type PLIST_ENTRY32 = *mut LIST_ENTRY32; +STRUCT!{struct LIST_ENTRY64 { + Flink: ULONGLONG, + Blink: ULONGLONG, +}} +pub type PLIST_ENTRY64 = *mut LIST_ENTRY64; +STRUCT!{struct SINGLE_LIST_ENTRY32 { + Next: ULONG, +}} +pub type PSINGLE_LIST_ENTRY32 = *mut SINGLE_LIST_ENTRY32; +#[inline] +pub unsafe fn ListEntry32To64(l32: PLIST_ENTRY32, l64: PLIST_ENTRY64) { + (*l64).Flink = (*l32).Flink as ULONGLONG; + (*l64).Blink = (*l32).Blink as ULONGLONG; +} +#[inline] +pub unsafe fn ListEntry64To32(l64: PLIST_ENTRY64, l32: PLIST_ENTRY32) { + (*l32).Flink = (*l64).Flink as ULONG; + (*l32).Blink = (*l64).Blink as ULONG; +} +STRUCT!{struct WNF_STATE_NAME { + Data: [ULONG; 2], +}} +pub type PWNF_STATE_NAME = *mut WNF_STATE_NAME; +pub type PCWNF_STATE_NAME = *const WNF_STATE_NAME; +STRUCT!{struct STRING32 { + Length: USHORT, + MaximumLength: USHORT, + Buffer: ULONG, +}} +pub type PSTRING32 = *mut STRING32; +pub type UNICODE_STRING32 = STRING32; +pub type PUNICODE_STRING32 = *mut UNICODE_STRING32; +pub type ANSI_STRING32 = STRING32; +pub type PANSI_STRING32 = *mut ANSI_STRING32; +STRUCT!{struct STRING64 { + Length: USHORT, + MaximumLength: USHORT, + Buffer: ULONGLONG, +}} +pub type PSTRING64 = *mut STRING64; +pub type UNICODE_STRING64 = STRING64; +pub type PUNICODE_STRING64 = *mut UNICODE_STRING64; +pub type ANSI_STRING64 = STRING64; +pub type PANSI_STRING64 = *mut ANSI_STRING64; +pub const OBJ_INHERIT: ULONG = 0x00000002; +pub const OBJ_PERMANENT: ULONG = 0x00000010; +pub const OBJ_EXCLUSIVE: ULONG = 0x00000020; +pub const OBJ_CASE_INSENSITIVE: ULONG = 0x00000040; +pub const OBJ_OPENIF: ULONG = 0x00000080; +pub const OBJ_OPENLINK: ULONG = 0x00000100; +pub const OBJ_KERNEL_HANDLE: ULONG = 0x00000200; +pub const OBJ_FORCE_ACCESS_CHECK: ULONG = 0x00000400; +pub const OBJ_IGNORE_IMPERSONATED_DEVICEMAP: ULONG = 0x00000800; +pub const OBJ_DONT_REPARSE: ULONG = 0x00001000; +pub const OBJ_VALID_ATTRIBUTES: ULONG = 0x00001FF2; +STRUCT!{struct OBJECT_ATTRIBUTES64 { + Length: ULONG, + RootDirectory: ULONG64, + ObjectName: ULONG64, + Attributes: ULONG, + SecurityDescriptor: ULONG64, + SecurityQualityOfService: ULONG64, +}} +pub type POBJECT_ATTRIBUTES64 = *mut OBJECT_ATTRIBUTES64; +pub type PCOBJECT_ATTRIBUTES64 = *const OBJECT_ATTRIBUTES64; +STRUCT!{struct OBJECT_ATTRIBUTES32 { + Length: ULONG, + RootDirectory: ULONG, + ObjectName: ULONG, + Attributes: ULONG, + SecurityDescriptor: ULONG, + SecurityQualityOfService: ULONG, +}} +pub type POBJECT_ATTRIBUTES32 = *mut OBJECT_ATTRIBUTES32; +pub type PCOBJECT_ATTRIBUTES32 = *const OBJECT_ATTRIBUTES32; +STRUCT!{struct OBJECT_ATTRIBUTES { + Length: ULONG, + RootDirectory: HANDLE, + ObjectName: PUNICODE_STRING, + Attributes: ULONG, + SecurityDescriptor: PVOID, + SecurityQualityOfService: PVOID, +}} +pub type POBJECT_ATTRIBUTES = *mut OBJECT_ATTRIBUTES; +pub type PCOBJECT_ATTRIBUTES = *const OBJECT_ATTRIBUTES; +#[inline] +pub unsafe fn InitializeObjectAttributes( + p: POBJECT_ATTRIBUTES, + n: PUNICODE_STRING, + a: ULONG, + r: HANDLE, + s: PVOID, +) { + use core::mem::size_of; + (*p).Length = size_of::<OBJECT_ATTRIBUTES>() as ULONG; + (*p).RootDirectory = r; + (*p).Attributes = a; + (*p).ObjectName = n; + (*p).SecurityDescriptor = s; + (*p).SecurityQualityOfService = NULL; +} +pub const FALSE: BOOLEAN = 0; +pub const TRUE: BOOLEAN = 1; +pub const NULL: PVOID = 0 as PVOID; +pub const NULL64: PVOID64 = 0; +STRUCT!{struct OBJECTID { + Lineage: GUID, + Uniquifier: ULONG, +}} +pub const MINCHAR: CHAR = 0x80; +pub const MAXCHAR: CHAR = 0x7f; +pub const MINSHORT: SHORT = 0x8000; +pub const MAXSHORT: SHORT = 0x7fff; +pub const MINLONG: LONG = 0x80000000; +pub const MAXLONG: LONG = 0x7fffffff; +pub const MAXUCHAR: UCHAR = 0xff; +pub const MAXUSHORT: USHORT = 0xffff; +pub const MAXULONG: ULONG = 0xffffffff; +// PEXCEPTION_ROUTINE: Can't define here, because it needs EXCEPTION_RECORD and CONTEXT. +pub type KIRQL = UCHAR; +pub type PKIRQL = *mut KIRQL; +ENUM!{enum NT_PRODUCT_TYPE { + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer, +}} +pub type PNT_PRODUCT_TYPE = *mut NT_PRODUCT_TYPE; +ENUM!{enum SUITE_TYPE { + SmallBusiness, + Enterprise, + BackOffice, + CommunicationServer, + TerminalServer, + SmallBusinessRestricted, + EmbeddedNT, + DataCenter, + SingleUserTS, + Personal, + Blade, + EmbeddedRestricted, + SecurityAppliance, + StorageServer, + ComputeServer, + WHServer, + PhoneNT, + MaxSuiteType, +}} +pub const VER_SERVER_NT: ULONG = 0x80000000; +pub const VER_WORKSTATION_NT: ULONG = 0x40000000; +pub const VER_SUITE_SMALLBUSINESS: ULONG = 0x00000001; +pub const VER_SUITE_ENTERPRISE: ULONG = 0x00000002; +pub const VER_SUITE_BACKOFFICE: ULONG = 0x00000004; +pub const VER_SUITE_COMMUNICATIONS: ULONG = 0x00000008; +pub const VER_SUITE_TERMINAL: ULONG = 0x00000010; +pub const VER_SUITE_SMALLBUSINESS_RESTRICTED: ULONG = 0x00000020; +pub const VER_SUITE_EMBEDDEDNT: ULONG = 0x00000040; +pub const VER_SUITE_DATACENTER: ULONG = 0x00000080; +pub const VER_SUITE_SINGLEUSERTS: ULONG = 0x00000100; +pub const VER_SUITE_PERSONAL: ULONG = 0x00000200; +pub const VER_SUITE_BLADE: ULONG = 0x00000400; +pub const VER_SUITE_EMBEDDED_RESTRICTED: ULONG = 0x00000800; +pub const VER_SUITE_SECURITY_APPLIANCE: ULONG = 0x00001000; +pub const VER_SUITE_STORAGE_SERVER: ULONG = 0x00002000; +pub const VER_SUITE_COMPUTE_SERVER: ULONG = 0x00004000; +pub const VER_SUITE_WH_SERVER: ULONG = 0x00008000; +pub const PRODUCT_UNDEFINED: ULONG = 0x00000000; +pub const PRODUCT_ULTIMATE: ULONG = 0x00000001; +pub const PRODUCT_HOME_BASIC: ULONG = 0x00000002; +pub const PRODUCT_HOME_PREMIUM: ULONG = 0x00000003; +pub const PRODUCT_ENTERPRISE: ULONG = 0x00000004; +pub const PRODUCT_HOME_BASIC_N: ULONG = 0x00000005; +pub const PRODUCT_BUSINESS: ULONG = 0x00000006; +pub const PRODUCT_STANDARD_SERVER: ULONG = 0x00000007; +pub const PRODUCT_DATACENTER_SERVER: ULONG = 0x00000008; +pub const PRODUCT_SMALLBUSINESS_SERVER: ULONG = 0x00000009; +pub const PRODUCT_ENTERPRISE_SERVER: ULONG = 0x0000000A; +pub const PRODUCT_STARTER: ULONG = 0x0000000B; +pub const PRODUCT_DATACENTER_SERVER_CORE: ULONG = 0x0000000C; +pub const PRODUCT_STANDARD_SERVER_CORE: ULONG = 0x0000000D; +pub const PRODUCT_ENTERPRISE_SERVER_CORE: ULONG = 0x0000000E; +pub const PRODUCT_ENTERPRISE_SERVER_IA64: ULONG = 0x0000000F; +pub const PRODUCT_BUSINESS_N: ULONG = 0x00000010; +pub const PRODUCT_WEB_SERVER: ULONG = 0x00000011; +pub const PRODUCT_CLUSTER_SERVER: ULONG = 0x00000012; +pub const PRODUCT_HOME_SERVER: ULONG = 0x00000013; +pub const PRODUCT_STORAGE_EXPRESS_SERVER: ULONG = 0x00000014; +pub const PRODUCT_STORAGE_STANDARD_SERVER: ULONG = 0x00000015; +pub const PRODUCT_STORAGE_WORKGROUP_SERVER: ULONG = 0x00000016; +pub const PRODUCT_STORAGE_ENTERPRISE_SERVER: ULONG = 0x00000017; +pub const PRODUCT_SERVER_FOR_SMALLBUSINESS: ULONG = 0x00000018; +pub const PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: ULONG = 0x00000019; +pub const PRODUCT_HOME_PREMIUM_N: ULONG = 0x0000001A; +pub const PRODUCT_ENTERPRISE_N: ULONG = 0x0000001B; +pub const PRODUCT_ULTIMATE_N: ULONG = 0x0000001C; +pub const PRODUCT_WEB_SERVER_CORE: ULONG = 0x0000001D; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: ULONG = 0x0000001E; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: ULONG = 0x0000001F; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: ULONG = 0x00000020; +pub const PRODUCT_SERVER_FOUNDATION: ULONG = 0x00000021; +pub const PRODUCT_HOME_PREMIUM_SERVER: ULONG = 0x00000022; +pub const PRODUCT_SERVER_FOR_SMALLBUSINESS_V: ULONG = 0x00000023; +pub const PRODUCT_STANDARD_SERVER_V: ULONG = 0x00000024; +pub const PRODUCT_DATACENTER_SERVER_V: ULONG = 0x00000025; +pub const PRODUCT_ENTERPRISE_SERVER_V: ULONG = 0x00000026; +pub const PRODUCT_DATACENTER_SERVER_CORE_V: ULONG = 0x00000027; +pub const PRODUCT_STANDARD_SERVER_CORE_V: ULONG = 0x00000028; +pub const PRODUCT_ENTERPRISE_SERVER_CORE_V: ULONG = 0x00000029; +pub const PRODUCT_HYPERV: ULONG = 0x0000002A; +pub const PRODUCT_STORAGE_EXPRESS_SERVER_CORE: ULONG = 0x0000002B; +pub const PRODUCT_STORAGE_STANDARD_SERVER_CORE: ULONG = 0x0000002C; +pub const PRODUCT_STORAGE_WORKGROUP_SERVER_CORE: ULONG = 0x0000002D; +pub const PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE: ULONG = 0x0000002E; +pub const PRODUCT_STARTER_N: ULONG = 0x0000002F; +pub const PRODUCT_PROFESSIONAL: ULONG = 0x00000030; +pub const PRODUCT_PROFESSIONAL_N: ULONG = 0x00000031; +pub const PRODUCT_SB_SOLUTION_SERVER: ULONG = 0x00000032; +pub const PRODUCT_SERVER_FOR_SB_SOLUTIONS: ULONG = 0x00000033; +pub const PRODUCT_STANDARD_SERVER_SOLUTIONS: ULONG = 0x00000034; +pub const PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE: ULONG = 0x00000035; +pub const PRODUCT_SB_SOLUTION_SERVER_EM: ULONG = 0x00000036; +pub const PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM: ULONG = 0x00000037; +pub const PRODUCT_SOLUTION_EMBEDDEDSERVER: ULONG = 0x00000038; +pub const PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE: ULONG = 0x00000039; +pub const PRODUCT_PROFESSIONAL_EMBEDDED: ULONG = 0x0000003A; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT: ULONG = 0x0000003B; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL: ULONG = 0x0000003C; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC: ULONG = 0x0000003D; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC: ULONG = 0x0000003E; +pub const PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: ULONG = 0x0000003F; +pub const PRODUCT_CLUSTER_SERVER_V: ULONG = 0x00000040; +pub const PRODUCT_EMBEDDED: ULONG = 0x00000041; +pub const PRODUCT_STARTER_E: ULONG = 0x00000042; +pub const PRODUCT_HOME_BASIC_E: ULONG = 0x00000043; +pub const PRODUCT_HOME_PREMIUM_E: ULONG = 0x00000044; +pub const PRODUCT_PROFESSIONAL_E: ULONG = 0x00000045; +pub const PRODUCT_ENTERPRISE_E: ULONG = 0x00000046; +pub const PRODUCT_ULTIMATE_E: ULONG = 0x00000047; +pub const PRODUCT_ENTERPRISE_EVALUATION: ULONG = 0x00000048; +pub const PRODUCT_MULTIPOINT_STANDARD_SERVER: ULONG = 0x0000004C; +pub const PRODUCT_MULTIPOINT_PREMIUM_SERVER: ULONG = 0x0000004D; +pub const PRODUCT_STANDARD_EVALUATION_SERVER: ULONG = 0x0000004F; +pub const PRODUCT_DATACENTER_EVALUATION_SERVER: ULONG = 0x00000050; +pub const PRODUCT_ENTERPRISE_N_EVALUATION: ULONG = 0x00000054; +pub const PRODUCT_EMBEDDED_AUTOMOTIVE: ULONG = 0x00000055; +pub const PRODUCT_EMBEDDED_INDUSTRY_A: ULONG = 0x00000056; +pub const PRODUCT_THINPC: ULONG = 0x00000057; +pub const PRODUCT_EMBEDDED_A: ULONG = 0x00000058; +pub const PRODUCT_EMBEDDED_INDUSTRY: ULONG = 0x00000059; +pub const PRODUCT_EMBEDDED_E: ULONG = 0x0000005A; +pub const PRODUCT_EMBEDDED_INDUSTRY_E: ULONG = 0x0000005B; +pub const PRODUCT_EMBEDDED_INDUSTRY_A_E: ULONG = 0x0000005C; +pub const PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER: ULONG = 0x0000005F; +pub const PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER: ULONG = 0x00000060; +pub const PRODUCT_CORE_ARM: ULONG = 0x00000061; +pub const PRODUCT_CORE_N: ULONG = 0x00000062; +pub const PRODUCT_CORE_COUNTRYSPECIFIC: ULONG = 0x00000063; +pub const PRODUCT_CORE_SINGLELANGUAGE: ULONG = 0x00000064; +pub const PRODUCT_CORE: ULONG = 0x00000065; +pub const PRODUCT_PROFESSIONAL_WMC: ULONG = 0x00000067; +pub const PRODUCT_MOBILE_CORE: ULONG = 0x00000068; +pub const PRODUCT_EMBEDDED_INDUSTRY_EVAL: ULONG = 0x00000069; +pub const PRODUCT_EMBEDDED_INDUSTRY_E_EVAL: ULONG = 0x0000006A; +pub const PRODUCT_EMBEDDED_EVAL: ULONG = 0x0000006B; +pub const PRODUCT_EMBEDDED_E_EVAL: ULONG = 0x0000006C; +pub const PRODUCT_NANO_SERVER: ULONG = 0x0000006D; +pub const PRODUCT_CLOUD_STORAGE_SERVER: ULONG = 0x0000006E; +pub const PRODUCT_CORE_CONNECTED: ULONG = 0x0000006F; +pub const PRODUCT_PROFESSIONAL_STUDENT: ULONG = 0x00000070; +pub const PRODUCT_CORE_CONNECTED_N: ULONG = 0x00000071; +pub const PRODUCT_PROFESSIONAL_STUDENT_N: ULONG = 0x00000072; +pub const PRODUCT_CORE_CONNECTED_SINGLELANGUAGE: ULONG = 0x00000073; +pub const PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC: ULONG = 0x00000074; +pub const PRODUCT_CONNECTED_CAR: ULONG = 0x00000075; +pub const PRODUCT_INDUSTRY_HANDHELD: ULONG = 0x00000076; +pub const PRODUCT_PPI_PRO: ULONG = 0x00000077; +pub const PRODUCT_ARM64_SERVER: ULONG = 0x00000078; +pub const PRODUCT_EDUCATION: ULONG = 0x00000079; +pub const PRODUCT_EDUCATION_N: ULONG = 0x0000007A; +pub const PRODUCT_IOTUAP: ULONG = 0x0000007B; +pub const PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER: ULONG = 0x0000007C; +pub const PRODUCT_ENTERPRISE_S: ULONG = 0x0000007D; +pub const PRODUCT_ENTERPRISE_S_N: ULONG = 0x0000007E; +pub const PRODUCT_PROFESSIONAL_S: ULONG = 0x0000007F; +pub const PRODUCT_PROFESSIONAL_S_N: ULONG = 0x00000080; +pub const PRODUCT_ENTERPRISE_S_EVALUATION: ULONG = 0x00000081; +pub const PRODUCT_ENTERPRISE_S_N_EVALUATION: ULONG = 0x00000082; +pub const PRODUCT_HOLOGRAPHIC: ULONG = 0x00000087; +pub const PRODUCT_PRO_SINGLE_LANGUAGE: ULONG = 0x0000008A; +pub const PRODUCT_PRO_CHINA: ULONG = 0x0000008B; +pub const PRODUCT_ENTERPRISE_SUBSCRIPTION: ULONG = 0x0000008C; +pub const PRODUCT_ENTERPRISE_SUBSCRIPTION_N: ULONG = 0x0000008D; +pub const PRODUCT_DATACENTER_NANO_SERVER: ULONG = 0x0000008F; +pub const PRODUCT_STANDARD_NANO_SERVER: ULONG = 0x00000090; +pub const PRODUCT_DATACENTER_A_SERVER_CORE: ULONG = 0x00000091; +pub const PRODUCT_STANDARD_A_SERVER_CORE: ULONG = 0x00000092; +pub const PRODUCT_DATACENTER_WS_SERVER_CORE: ULONG = 0x00000093; +pub const PRODUCT_STANDARD_WS_SERVER_CORE: ULONG = 0x00000094; +pub const PRODUCT_UTILITY_VM: ULONG = 0x00000095; +pub const PRODUCT_DATACENTER_EVALUATION_SERVER_CORE: ULONG = 0x0000009F; +pub const PRODUCT_STANDARD_EVALUATION_SERVER_CORE: ULONG = 0x000000A0; +pub const PRODUCT_PRO_WORKSTATION: ULONG = 0x000000A1; +pub const PRODUCT_PRO_WORKSTATION_N: ULONG = 0x000000A2; +pub const PRODUCT_PRO_FOR_EDUCATION: ULONG = 0x000000A4; +pub const PRODUCT_PRO_FOR_EDUCATION_N: ULONG = 0x000000A5; +pub const PRODUCT_AZURE_SERVER_CORE: ULONG = 0x000000A8; +pub const PRODUCT_AZURE_NANO_SERVER: ULONG = 0x000000A9; +pub const PRODUCT_UNLICENSED: ULONG = 0xABCDABCD; +pub const LANG_NEUTRAL: USHORT = 0x00; +pub const LANG_INVARIANT: USHORT = 0x7f; +pub const LANG_AFRIKAANS: USHORT = 0x36; +pub const LANG_ALBANIAN: USHORT = 0x1c; +pub const LANG_ALSATIAN: USHORT = 0x84; +pub const LANG_AMHARIC: USHORT = 0x5e; +pub const LANG_ARABIC: USHORT = 0x01; +pub const LANG_ARMENIAN: USHORT = 0x2b; +pub const LANG_ASSAMESE: USHORT = 0x4d; +pub const LANG_AZERI: USHORT = 0x2c; +pub const LANG_AZERBAIJANI: USHORT = 0x2c; +pub const LANG_BANGLA: USHORT = 0x45; +pub const LANG_BASHKIR: USHORT = 0x6d; +pub const LANG_BASQUE: USHORT = 0x2d; +pub const LANG_BELARUSIAN: USHORT = 0x23; +pub const LANG_BENGALI: USHORT = 0x45; +pub const LANG_BRETON: USHORT = 0x7e; +pub const LANG_BOSNIAN: USHORT = 0x1a; +pub const LANG_BOSNIAN_NEUTRAL: USHORT = 0x781a; +pub const LANG_BULGARIAN: USHORT = 0x02; +pub const LANG_CATALAN: USHORT = 0x03; +pub const LANG_CENTRAL_KURDISH: USHORT = 0x92; +pub const LANG_CHEROKEE: USHORT = 0x5c; +pub const LANG_CHINESE: USHORT = 0x04; +pub const LANG_CHINESE_SIMPLIFIED: USHORT = 0x04; +pub const LANG_CHINESE_TRADITIONAL: USHORT = 0x7c04; +pub const LANG_CORSICAN: USHORT = 0x83; +pub const LANG_CROATIAN: USHORT = 0x1a; +pub const LANG_CZECH: USHORT = 0x05; +pub const LANG_DANISH: USHORT = 0x06; +pub const LANG_DARI: USHORT = 0x8c; +pub const LANG_DIVEHI: USHORT = 0x65; +pub const LANG_DUTCH: USHORT = 0x13; +pub const LANG_ENGLISH: USHORT = 0x09; +pub const LANG_ESTONIAN: USHORT = 0x25; +pub const LANG_FAEROESE: USHORT = 0x38; +pub const LANG_FARSI: USHORT = 0x29; +pub const LANG_FILIPINO: USHORT = 0x64; +pub const LANG_FINNISH: USHORT = 0x0b; +pub const LANG_FRENCH: USHORT = 0x0c; +pub const LANG_FRISIAN: USHORT = 0x62; +pub const LANG_FULAH: USHORT = 0x67; +pub const LANG_GALICIAN: USHORT = 0x56; +pub const LANG_GEORGIAN: USHORT = 0x37; +pub const LANG_GERMAN: USHORT = 0x07; +pub const LANG_GREEK: USHORT = 0x08; +pub const LANG_GREENLANDIC: USHORT = 0x6f; +pub const LANG_GUJARATI: USHORT = 0x47; +pub const LANG_HAUSA: USHORT = 0x68; +pub const LANG_HAWAIIAN: USHORT = 0x75; +pub const LANG_HEBREW: USHORT = 0x0d; +pub const LANG_HINDI: USHORT = 0x39; +pub const LANG_HUNGARIAN: USHORT = 0x0e; +pub const LANG_ICELANDIC: USHORT = 0x0f; +pub const LANG_IGBO: USHORT = 0x70; +pub const LANG_INDONESIAN: USHORT = 0x21; +pub const LANG_INUKTITUT: USHORT = 0x5d; +pub const LANG_IRISH: USHORT = 0x3c; +pub const LANG_ITALIAN: USHORT = 0x10; +pub const LANG_JAPANESE: USHORT = 0x11; +pub const LANG_KANNADA: USHORT = 0x4b; +pub const LANG_KASHMIRI: USHORT = 0x60; +pub const LANG_KAZAK: USHORT = 0x3f; +pub const LANG_KHMER: USHORT = 0x53; +pub const LANG_KICHE: USHORT = 0x86; +pub const LANG_KINYARWANDA: USHORT = 0x87; +pub const LANG_KONKANI: USHORT = 0x57; +pub const LANG_KOREAN: USHORT = 0x12; +pub const LANG_KYRGYZ: USHORT = 0x40; +pub const LANG_LAO: USHORT = 0x54; +pub const LANG_LATVIAN: USHORT = 0x26; +pub const LANG_LITHUANIAN: USHORT = 0x27; +pub const LANG_LOWER_SORBIAN: USHORT = 0x2e; +pub const LANG_LUXEMBOURGISH: USHORT = 0x6e; +pub const LANG_MACEDONIAN: USHORT = 0x2f; +pub const LANG_MALAY: USHORT = 0x3e; +pub const LANG_MALAYALAM: USHORT = 0x4c; +pub const LANG_MALTESE: USHORT = 0x3a; +pub const LANG_MANIPURI: USHORT = 0x58; +pub const LANG_MAORI: USHORT = 0x81; +pub const LANG_MAPUDUNGUN: USHORT = 0x7a; +pub const LANG_MARATHI: USHORT = 0x4e; +pub const LANG_MOHAWK: USHORT = 0x7c; +pub const LANG_MONGOLIAN: USHORT = 0x50; +pub const LANG_NEPALI: USHORT = 0x61; +pub const LANG_NORWEGIAN: USHORT = 0x14; +pub const LANG_OCCITAN: USHORT = 0x82; +pub const LANG_ODIA: USHORT = 0x48; +pub const LANG_ORIYA: USHORT = 0x48; +pub const LANG_PASHTO: USHORT = 0x63; +pub const LANG_PERSIAN: USHORT = 0x29; +pub const LANG_POLISH: USHORT = 0x15; +pub const LANG_PORTUGUESE: USHORT = 0x16; +pub const LANG_PULAR: USHORT = 0x67; +pub const LANG_PUNJABI: USHORT = 0x46; +pub const LANG_QUECHUA: USHORT = 0x6b; +pub const LANG_ROMANIAN: USHORT = 0x18; +pub const LANG_ROMANSH: USHORT = 0x17; +pub const LANG_RUSSIAN: USHORT = 0x19; +pub const LANG_SAKHA: USHORT = 0x85; +pub const LANG_SAMI: USHORT = 0x3b; +pub const LANG_SANSKRIT: USHORT = 0x4f; +pub const LANG_SCOTTISH_GAELIC: USHORT = 0x91; +pub const LANG_SERBIAN: USHORT = 0x1a; +pub const LANG_SERBIAN_NEUTRAL: USHORT = 0x7c1a; +pub const LANG_SINDHI: USHORT = 0x59; +pub const LANG_SINHALESE: USHORT = 0x5b; +pub const LANG_SLOVAK: USHORT = 0x1b; +pub const LANG_SLOVENIAN: USHORT = 0x24; +pub const LANG_SOTHO: USHORT = 0x6c; +pub const LANG_SPANISH: USHORT = 0x0a; +pub const LANG_SWAHILI: USHORT = 0x41; +pub const LANG_SWEDISH: USHORT = 0x1d; +pub const LANG_SYRIAC: USHORT = 0x5a; +pub const LANG_TAJIK: USHORT = 0x28; +pub const LANG_TAMAZIGHT: USHORT = 0x5f; +pub const LANG_TAMIL: USHORT = 0x49; +pub const LANG_TATAR: USHORT = 0x44; +pub const LANG_TELUGU: USHORT = 0x4a; +pub const LANG_THAI: USHORT = 0x1e; +pub const LANG_TIBETAN: USHORT = 0x51; +pub const LANG_TIGRIGNA: USHORT = 0x73; +pub const LANG_TIGRINYA: USHORT = 0x73; +pub const LANG_TSWANA: USHORT = 0x32; +pub const LANG_TURKISH: USHORT = 0x1f; +pub const LANG_TURKMEN: USHORT = 0x42; +pub const LANG_UIGHUR: USHORT = 0x80; +pub const LANG_UKRAINIAN: USHORT = 0x22; +pub const LANG_UPPER_SORBIAN: USHORT = 0x2e; +pub const LANG_URDU: USHORT = 0x20; +pub const LANG_UZBEK: USHORT = 0x43; +pub const LANG_VALENCIAN: USHORT = 0x03; +pub const LANG_VIETNAMESE: USHORT = 0x2a; +pub const LANG_WELSH: USHORT = 0x52; +pub const LANG_WOLOF: USHORT = 0x88; +pub const LANG_XHOSA: USHORT = 0x34; +pub const LANG_YAKUT: USHORT = 0x85; +pub const LANG_YI: USHORT = 0x78; +pub const LANG_YORUBA: USHORT = 0x6a; +pub const LANG_ZULU: USHORT = 0x35; +pub const SUBLANG_NEUTRAL: USHORT = 0x00; +pub const SUBLANG_DEFAULT: USHORT = 0x01; +pub const SUBLANG_SYS_DEFAULT: USHORT = 0x02; +pub const SUBLANG_CUSTOM_DEFAULT: USHORT = 0x03; +pub const SUBLANG_CUSTOM_UNSPECIFIED: USHORT = 0x04; +pub const SUBLANG_UI_CUSTOM_DEFAULT: USHORT = 0x05; +pub const SUBLANG_AFRIKAANS_SOUTH_AFRICA: USHORT = 0x01; +pub const SUBLANG_ALBANIAN_ALBANIA: USHORT = 0x01; +pub const SUBLANG_ALSATIAN_FRANCE: USHORT = 0x01; +pub const SUBLANG_AMHARIC_ETHIOPIA: USHORT = 0x01; +pub const SUBLANG_ARABIC_SAUDI_ARABIA: USHORT = 0x01; +pub const SUBLANG_ARABIC_IRAQ: USHORT = 0x02; +pub const SUBLANG_ARABIC_EGYPT: USHORT = 0x03; +pub const SUBLANG_ARABIC_LIBYA: USHORT = 0x04; +pub const SUBLANG_ARABIC_ALGERIA: USHORT = 0x05; +pub const SUBLANG_ARABIC_MOROCCO: USHORT = 0x06; +pub const SUBLANG_ARABIC_TUNISIA: USHORT = 0x07; +pub const SUBLANG_ARABIC_OMAN: USHORT = 0x08; +pub const SUBLANG_ARABIC_YEMEN: USHORT = 0x09; +pub const SUBLANG_ARABIC_SYRIA: USHORT = 0x0a; +pub const SUBLANG_ARABIC_JORDAN: USHORT = 0x0b; +pub const SUBLANG_ARABIC_LEBANON: USHORT = 0x0c; +pub const SUBLANG_ARABIC_KUWAIT: USHORT = 0x0d; +pub const SUBLANG_ARABIC_UAE: USHORT = 0x0e; +pub const SUBLANG_ARABIC_BAHRAIN: USHORT = 0x0f; +pub const SUBLANG_ARABIC_QATAR: USHORT = 0x10; +pub const SUBLANG_ARMENIAN_ARMENIA: USHORT = 0x01; +pub const SUBLANG_ASSAMESE_INDIA: USHORT = 0x01; +pub const SUBLANG_AZERI_LATIN: USHORT = 0x01; +pub const SUBLANG_AZERI_CYRILLIC: USHORT = 0x02; +pub const SUBLANG_AZERBAIJANI_AZERBAIJAN_LATIN: USHORT = 0x01; +pub const SUBLANG_AZERBAIJANI_AZERBAIJAN_CYRILLIC: USHORT = 0x02; +pub const SUBLANG_BANGLA_INDIA: USHORT = 0x01; +pub const SUBLANG_BANGLA_BANGLADESH: USHORT = 0x02; +pub const SUBLANG_BASHKIR_RUSSIA: USHORT = 0x01; +pub const SUBLANG_BASQUE_BASQUE: USHORT = 0x01; +pub const SUBLANG_BELARUSIAN_BELARUS: USHORT = 0x01; +pub const SUBLANG_BENGALI_INDIA: USHORT = 0x01; +pub const SUBLANG_BENGALI_BANGLADESH: USHORT = 0x02; +pub const SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN: USHORT = 0x05; +pub const SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC: USHORT = 0x08; +pub const SUBLANG_BRETON_FRANCE: USHORT = 0x01; +pub const SUBLANG_BULGARIAN_BULGARIA: USHORT = 0x01; +pub const SUBLANG_CATALAN_CATALAN: USHORT = 0x01; +pub const SUBLANG_CENTRAL_KURDISH_IRAQ: USHORT = 0x01; +pub const SUBLANG_CHEROKEE_CHEROKEE: USHORT = 0x01; +pub const SUBLANG_CHINESE_TRADITIONAL: USHORT = 0x01; +pub const SUBLANG_CHINESE_SIMPLIFIED: USHORT = 0x02; +pub const SUBLANG_CHINESE_HONGKONG: USHORT = 0x03; +pub const SUBLANG_CHINESE_SINGAPORE: USHORT = 0x04; +pub const SUBLANG_CHINESE_MACAU: USHORT = 0x05; +pub const SUBLANG_CORSICAN_FRANCE: USHORT = 0x01; +pub const SUBLANG_CZECH_CZECH_REPUBLIC: USHORT = 0x01; +pub const SUBLANG_CROATIAN_CROATIA: USHORT = 0x01; +pub const SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN: USHORT = 0x04; +pub const SUBLANG_DANISH_DENMARK: USHORT = 0x01; +pub const SUBLANG_DARI_AFGHANISTAN: USHORT = 0x01; +pub const SUBLANG_DIVEHI_MALDIVES: USHORT = 0x01; +pub const SUBLANG_DUTCH: USHORT = 0x01; +pub const SUBLANG_DUTCH_BELGIAN: USHORT = 0x02; +pub const SUBLANG_ENGLISH_US: USHORT = 0x01; +pub const SUBLANG_ENGLISH_UK: USHORT = 0x02; +pub const SUBLANG_ENGLISH_AUS: USHORT = 0x03; +pub const SUBLANG_ENGLISH_CAN: USHORT = 0x04; +pub const SUBLANG_ENGLISH_NZ: USHORT = 0x05; +pub const SUBLANG_ENGLISH_EIRE: USHORT = 0x06; +pub const SUBLANG_ENGLISH_SOUTH_AFRICA: USHORT = 0x07; +pub const SUBLANG_ENGLISH_JAMAICA: USHORT = 0x08; +pub const SUBLANG_ENGLISH_CARIBBEAN: USHORT = 0x09; +pub const SUBLANG_ENGLISH_BELIZE: USHORT = 0x0a; +pub const SUBLANG_ENGLISH_TRINIDAD: USHORT = 0x0b; +pub const SUBLANG_ENGLISH_ZIMBABWE: USHORT = 0x0c; +pub const SUBLANG_ENGLISH_PHILIPPINES: USHORT = 0x0d; +pub const SUBLANG_ENGLISH_INDIA: USHORT = 0x10; +pub const SUBLANG_ENGLISH_MALAYSIA: USHORT = 0x11; +pub const SUBLANG_ENGLISH_SINGAPORE: USHORT = 0x12; +pub const SUBLANG_ESTONIAN_ESTONIA: USHORT = 0x01; +pub const SUBLANG_FAEROESE_FAROE_ISLANDS: USHORT = 0x01; +pub const SUBLANG_FILIPINO_PHILIPPINES: USHORT = 0x01; +pub const SUBLANG_FINNISH_FINLAND: USHORT = 0x01; +pub const SUBLANG_FRENCH: USHORT = 0x01; +pub const SUBLANG_FRENCH_BELGIAN: USHORT = 0x02; +pub const SUBLANG_FRENCH_CANADIAN: USHORT = 0x03; +pub const SUBLANG_FRENCH_SWISS: USHORT = 0x04; +pub const SUBLANG_FRENCH_LUXEMBOURG: USHORT = 0x05; +pub const SUBLANG_FRENCH_MONACO: USHORT = 0x06; +pub const SUBLANG_FRISIAN_NETHERLANDS: USHORT = 0x01; +pub const SUBLANG_FULAH_SENEGAL: USHORT = 0x02; +pub const SUBLANG_GALICIAN_GALICIAN: USHORT = 0x01; +pub const SUBLANG_GEORGIAN_GEORGIA: USHORT = 0x01; +pub const SUBLANG_GERMAN: USHORT = 0x01; +pub const SUBLANG_GERMAN_SWISS: USHORT = 0x02; +pub const SUBLANG_GERMAN_AUSTRIAN: USHORT = 0x03; +pub const SUBLANG_GERMAN_LUXEMBOURG: USHORT = 0x04; +pub const SUBLANG_GERMAN_LIECHTENSTEIN: USHORT = 0x05; +pub const SUBLANG_GREEK_GREECE: USHORT = 0x01; +pub const SUBLANG_GREENLANDIC_GREENLAND: USHORT = 0x01; +pub const SUBLANG_GUJARATI_INDIA: USHORT = 0x01; +pub const SUBLANG_HAUSA_NIGERIA_LATIN: USHORT = 0x01; +pub const SUBLANG_HAWAIIAN_US: USHORT = 0x01; +pub const SUBLANG_HEBREW_ISRAEL: USHORT = 0x01; +pub const SUBLANG_HINDI_INDIA: USHORT = 0x01; +pub const SUBLANG_HUNGARIAN_HUNGARY: USHORT = 0x01; +pub const SUBLANG_ICELANDIC_ICELAND: USHORT = 0x01; +pub const SUBLANG_IGBO_NIGERIA: USHORT = 0x01; +pub const SUBLANG_INDONESIAN_INDONESIA: USHORT = 0x01; +pub const SUBLANG_INUKTITUT_CANADA: USHORT = 0x01; +pub const SUBLANG_INUKTITUT_CANADA_LATIN: USHORT = 0x02; +pub const SUBLANG_IRISH_IRELAND: USHORT = 0x02; +pub const SUBLANG_ITALIAN: USHORT = 0x01; +pub const SUBLANG_ITALIAN_SWISS: USHORT = 0x02; +pub const SUBLANG_JAPANESE_JAPAN: USHORT = 0x01; +pub const SUBLANG_KANNADA_INDIA: USHORT = 0x01; +pub const SUBLANG_KASHMIRI_SASIA: USHORT = 0x02; +pub const SUBLANG_KASHMIRI_INDIA: USHORT = 0x02; +pub const SUBLANG_KAZAK_KAZAKHSTAN: USHORT = 0x01; +pub const SUBLANG_KHMER_CAMBODIA: USHORT = 0x01; +pub const SUBLANG_KICHE_GUATEMALA: USHORT = 0x01; +pub const SUBLANG_KINYARWANDA_RWANDA: USHORT = 0x01; +pub const SUBLANG_KONKANI_INDIA: USHORT = 0x01; +pub const SUBLANG_KOREAN: USHORT = 0x01; +pub const SUBLANG_KYRGYZ_KYRGYZSTAN: USHORT = 0x01; +pub const SUBLANG_LAO_LAO: USHORT = 0x01; +pub const SUBLANG_LATVIAN_LATVIA: USHORT = 0x01; +pub const SUBLANG_LITHUANIAN: USHORT = 0x01; +pub const SUBLANG_LOWER_SORBIAN_GERMANY: USHORT = 0x02; +pub const SUBLANG_LUXEMBOURGISH_LUXEMBOURG: USHORT = 0x01; +pub const SUBLANG_MACEDONIAN_MACEDONIA: USHORT = 0x01; +pub const SUBLANG_MALAY_MALAYSIA: USHORT = 0x01; +pub const SUBLANG_MALAY_BRUNEI_DARUSSALAM: USHORT = 0x02; +pub const SUBLANG_MALAYALAM_INDIA: USHORT = 0x01; +pub const SUBLANG_MALTESE_MALTA: USHORT = 0x01; +pub const SUBLANG_MAORI_NEW_ZEALAND: USHORT = 0x01; +pub const SUBLANG_MAPUDUNGUN_CHILE: USHORT = 0x01; +pub const SUBLANG_MARATHI_INDIA: USHORT = 0x01; +pub const SUBLANG_MOHAWK_MOHAWK: USHORT = 0x01; +pub const SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA: USHORT = 0x01; +pub const SUBLANG_MONGOLIAN_PRC: USHORT = 0x02; +pub const SUBLANG_NEPALI_INDIA: USHORT = 0x02; +pub const SUBLANG_NEPALI_NEPAL: USHORT = 0x01; +pub const SUBLANG_NORWEGIAN_BOKMAL: USHORT = 0x01; +pub const SUBLANG_NORWEGIAN_NYNORSK: USHORT = 0x02; +pub const SUBLANG_OCCITAN_FRANCE: USHORT = 0x01; +pub const SUBLANG_ODIA_INDIA: USHORT = 0x01; +pub const SUBLANG_ORIYA_INDIA: USHORT = 0x01; +pub const SUBLANG_PASHTO_AFGHANISTAN: USHORT = 0x01; +pub const SUBLANG_PERSIAN_IRAN: USHORT = 0x01; +pub const SUBLANG_POLISH_POLAND: USHORT = 0x01; +pub const SUBLANG_PORTUGUESE: USHORT = 0x02; +pub const SUBLANG_PORTUGUESE_BRAZILIAN: USHORT = 0x01; +pub const SUBLANG_PULAR_SENEGAL: USHORT = 0x02; +pub const SUBLANG_PUNJABI_INDIA: USHORT = 0x01; +pub const SUBLANG_PUNJABI_PAKISTAN: USHORT = 0x02; +pub const SUBLANG_QUECHUA_BOLIVIA: USHORT = 0x01; +pub const SUBLANG_QUECHUA_ECUADOR: USHORT = 0x02; +pub const SUBLANG_QUECHUA_PERU: USHORT = 0x03; +pub const SUBLANG_ROMANIAN_ROMANIA: USHORT = 0x01; +pub const SUBLANG_ROMANSH_SWITZERLAND: USHORT = 0x01; +pub const SUBLANG_RUSSIAN_RUSSIA: USHORT = 0x01; +pub const SUBLANG_SAKHA_RUSSIA: USHORT = 0x01; +pub const SUBLANG_SAMI_NORTHERN_NORWAY: USHORT = 0x01; +pub const SUBLANG_SAMI_NORTHERN_SWEDEN: USHORT = 0x02; +pub const SUBLANG_SAMI_NORTHERN_FINLAND: USHORT = 0x03; +pub const SUBLANG_SAMI_LULE_NORWAY: USHORT = 0x04; +pub const SUBLANG_SAMI_LULE_SWEDEN: USHORT = 0x05; +pub const SUBLANG_SAMI_SOUTHERN_NORWAY: USHORT = 0x06; +pub const SUBLANG_SAMI_SOUTHERN_SWEDEN: USHORT = 0x07; +pub const SUBLANG_SAMI_SKOLT_FINLAND: USHORT = 0x08; +pub const SUBLANG_SAMI_INARI_FINLAND: USHORT = 0x09; +pub const SUBLANG_SANSKRIT_INDIA: USHORT = 0x01; +pub const SUBLANG_SCOTTISH_GAELIC: USHORT = 0x01; +pub const SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN: USHORT = 0x06; +pub const SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC: USHORT = 0x07; +pub const SUBLANG_SERBIAN_MONTENEGRO_LATIN: USHORT = 0x0b; +pub const SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC: USHORT = 0x0c; +pub const SUBLANG_SERBIAN_SERBIA_LATIN: USHORT = 0x09; +pub const SUBLANG_SERBIAN_SERBIA_CYRILLIC: USHORT = 0x0a; +pub const SUBLANG_SERBIAN_CROATIA: USHORT = 0x01; +pub const SUBLANG_SERBIAN_LATIN: USHORT = 0x02; +pub const SUBLANG_SERBIAN_CYRILLIC: USHORT = 0x03; +pub const SUBLANG_SINDHI_INDIA: USHORT = 0x01; +pub const SUBLANG_SINDHI_PAKISTAN: USHORT = 0x02; +pub const SUBLANG_SINDHI_AFGHANISTAN: USHORT = 0x02; +pub const SUBLANG_SINHALESE_SRI_LANKA: USHORT = 0x01; +pub const SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA: USHORT = 0x01; +pub const SUBLANG_SLOVAK_SLOVAKIA: USHORT = 0x01; +pub const SUBLANG_SLOVENIAN_SLOVENIA: USHORT = 0x01; +pub const SUBLANG_SPANISH: USHORT = 0x01; +pub const SUBLANG_SPANISH_MEXICAN: USHORT = 0x02; +pub const SUBLANG_SPANISH_MODERN: USHORT = 0x03; +pub const SUBLANG_SPANISH_GUATEMALA: USHORT = 0x04; +pub const SUBLANG_SPANISH_COSTA_RICA: USHORT = 0x05; +pub const SUBLANG_SPANISH_PANAMA: USHORT = 0x06; +pub const SUBLANG_SPANISH_DOMINICAN_REPUBLIC: USHORT = 0x07; +pub const SUBLANG_SPANISH_VENEZUELA: USHORT = 0x08; +pub const SUBLANG_SPANISH_COLOMBIA: USHORT = 0x09; +pub const SUBLANG_SPANISH_PERU: USHORT = 0x0a; +pub const SUBLANG_SPANISH_ARGENTINA: USHORT = 0x0b; +pub const SUBLANG_SPANISH_ECUADOR: USHORT = 0x0c; +pub const SUBLANG_SPANISH_CHILE: USHORT = 0x0d; +pub const SUBLANG_SPANISH_URUGUAY: USHORT = 0x0e; +pub const SUBLANG_SPANISH_PARAGUAY: USHORT = 0x0f; +pub const SUBLANG_SPANISH_BOLIVIA: USHORT = 0x10; +pub const SUBLANG_SPANISH_EL_SALVADOR: USHORT = 0x11; +pub const SUBLANG_SPANISH_HONDURAS: USHORT = 0x12; +pub const SUBLANG_SPANISH_NICARAGUA: USHORT = 0x13; +pub const SUBLANG_SPANISH_PUERTO_RICO: USHORT = 0x14; +pub const SUBLANG_SPANISH_US: USHORT = 0x15; +pub const SUBLANG_SWAHILI_KENYA: USHORT = 0x01; +pub const SUBLANG_SWEDISH: USHORT = 0x01; +pub const SUBLANG_SWEDISH_FINLAND: USHORT = 0x02; +pub const SUBLANG_SYRIAC_SYRIA: USHORT = 0x01; +pub const SUBLANG_TAJIK_TAJIKISTAN: USHORT = 0x01; +pub const SUBLANG_TAMAZIGHT_ALGERIA_LATIN: USHORT = 0x02; +pub const SUBLANG_TAMAZIGHT_MOROCCO_TIFINAGH: USHORT = 0x04; +pub const SUBLANG_TAMIL_INDIA: USHORT = 0x01; +pub const SUBLANG_TAMIL_SRI_LANKA: USHORT = 0x02; +pub const SUBLANG_TATAR_RUSSIA: USHORT = 0x01; +pub const SUBLANG_TELUGU_INDIA: USHORT = 0x01; +pub const SUBLANG_THAI_THAILAND: USHORT = 0x01; +pub const SUBLANG_TIBETAN_PRC: USHORT = 0x01; +pub const SUBLANG_TIGRIGNA_ERITREA: USHORT = 0x02; +pub const SUBLANG_TIGRINYA_ERITREA: USHORT = 0x02; +pub const SUBLANG_TIGRINYA_ETHIOPIA: USHORT = 0x01; +pub const SUBLANG_TSWANA_BOTSWANA: USHORT = 0x02; +pub const SUBLANG_TSWANA_SOUTH_AFRICA: USHORT = 0x01; +pub const SUBLANG_TURKISH_TURKEY: USHORT = 0x01; +pub const SUBLANG_TURKMEN_TURKMENISTAN: USHORT = 0x01; +pub const SUBLANG_UIGHUR_PRC: USHORT = 0x01; +pub const SUBLANG_UKRAINIAN_UKRAINE: USHORT = 0x01; +pub const SUBLANG_UPPER_SORBIAN_GERMANY: USHORT = 0x01; +pub const SUBLANG_URDU_PAKISTAN: USHORT = 0x01; +pub const SUBLANG_URDU_INDIA: USHORT = 0x02; +pub const SUBLANG_UZBEK_LATIN: USHORT = 0x01; +pub const SUBLANG_UZBEK_CYRILLIC: USHORT = 0x02; +pub const SUBLANG_VALENCIAN_VALENCIA: USHORT = 0x02; +pub const SUBLANG_VIETNAMESE_VIETNAM: USHORT = 0x01; +pub const SUBLANG_WELSH_UNITED_KINGDOM: USHORT = 0x01; +pub const SUBLANG_WOLOF_SENEGAL: USHORT = 0x01; +pub const SUBLANG_XHOSA_SOUTH_AFRICA: USHORT = 0x01; +pub const SUBLANG_YAKUT_RUSSIA: USHORT = 0x01; +pub const SUBLANG_YI_PRC: USHORT = 0x01; +pub const SUBLANG_YORUBA_NIGERIA: USHORT = 0x01; +pub const SUBLANG_ZULU_SOUTH_AFRICA: USHORT = 0x01; +pub const SORT_DEFAULT: USHORT = 0x0; +pub const SORT_INVARIANT_MATH: USHORT = 0x1; +pub const SORT_JAPANESE_XJIS: USHORT = 0x0; +pub const SORT_JAPANESE_UNICODE: USHORT = 0x1; +pub const SORT_JAPANESE_RADICALSTROKE: USHORT = 0x4; +pub const SORT_CHINESE_BIG5: USHORT = 0x0; +pub const SORT_CHINESE_PRCP: USHORT = 0x0; +pub const SORT_CHINESE_UNICODE: USHORT = 0x1; +pub const SORT_CHINESE_PRC: USHORT = 0x2; +pub const SORT_CHINESE_BOPOMOFO: USHORT = 0x3; +pub const SORT_CHINESE_RADICALSTROKE: USHORT = 0x4; +pub const SORT_KOREAN_KSC: USHORT = 0x0; +pub const SORT_KOREAN_UNICODE: USHORT = 0x1; +pub const SORT_GERMAN_PHONE_BOOK: USHORT = 0x1; +pub const SORT_HUNGARIAN_DEFAULT: USHORT = 0x0; +pub const SORT_HUNGARIAN_TECHNICAL: USHORT = 0x1; +pub const SORT_GEORGIAN_TRADITIONAL: USHORT = 0x0; +pub const SORT_GEORGIAN_MODERN: USHORT = 0x1; +macro_rules! MAKELANGID { + ($p:expr, $s:expr) => { + (($s as USHORT) << 10) | ($p as USHORT) + } +} +#[inline] +pub fn MAKELANGID(p: USHORT, s: USHORT) -> LANGID { (s << 10) | p } +#[inline] +pub fn PRIMARYLANGID(lgid: LANGID) -> USHORT { lgid & 0x3ff } +#[inline] +pub fn SUBLANGID(lgid: LANGID) -> USHORT { lgid >> 10 } +pub const NLS_VALID_LOCALE_MASK: ULONG = 0x000fffff; +macro_rules! MAKELCID { + ($lgid:expr, $srtid:expr) => { + (($srtid as ULONG) << 16) | ($lgid as ULONG) + } +} +#[inline] +pub fn MAKELCID(lgid: LANGID, srtid: USHORT) -> LCID { + ((srtid as ULONG) << 16) | (lgid as ULONG) +} +#[inline] +pub fn MAKESORTLCID(lgid: LANGID, srtid: USHORT, ver: USHORT) -> LCID { + MAKELCID(lgid, srtid) | ((ver as ULONG) << 20) +} +#[inline] +pub fn LANGIDFROMLCID(lcid: LCID) -> LANGID { lcid as LANGID } +#[inline] +pub fn SORTIDFROMLCID(lcid: LCID) -> USHORT { ((lcid >> 16) & 0xf) as USHORT } +#[inline] +pub fn SORTVERSIONFROMLCID(lcid: LCID) -> USHORT { ((lcid >> 16) & 0xf) as USHORT } +pub const LOCALE_NAME_MAX_LENGTH: usize = 85; +pub const LANG_SYSTEM_DEFAULT: LANGID = MAKELANGID!(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT); +pub const LANG_USER_DEFAULT: LANGID = MAKELANGID!(LANG_NEUTRAL, SUBLANG_DEFAULT); +pub const LOCALE_SYSTEM_DEFAULT: LCID = MAKELCID!(LANG_SYSTEM_DEFAULT, SORT_DEFAULT); +pub const LOCALE_USER_DEFAULT: LCID = MAKELCID!(LANG_USER_DEFAULT, SORT_DEFAULT); +pub const LOCALE_CUSTOM_DEFAULT: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT); +pub const LOCALE_CUSTOM_UNSPECIFIED: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT); +pub const LOCALE_CUSTOM_UI_DEFAULT: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT); +pub const LOCALE_NEUTRAL: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT); +pub const LOCALE_INVARIANT: LCID + = MAKELCID!(MAKELANGID!(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT); +pub const LOCALE_TRANSIENT_KEYBOARD1: LCID = 0x2000; +pub const LOCALE_TRANSIENT_KEYBOARD2: LCID = 0x2400; +pub const LOCALE_TRANSIENT_KEYBOARD3: LCID = 0x2800; +pub const LOCALE_TRANSIENT_KEYBOARD4: LCID = 0x2c00; +pub const LOCALE_UNASSIGNED_LCID: LCID = LOCALE_CUSTOM_UNSPECIFIED; diff --git a/winapi/src/shared/ntstatus.rs b/winapi/src/shared/ntstatus.rs new file mode 100644 index 000000000..c369c22fc --- /dev/null +++ b/winapi/src/shared/ntstatus.rs @@ -0,0 +1,2574 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Constant definitions for the NTSTATUS values. +use shared::ntdef::NTSTATUS; +pub const STATUS_WAIT_0: NTSTATUS = 0x00000000; +pub const FACILITY_VSM: NTSTATUS = 0x45; +pub const FACILITY_VOLSNAP: NTSTATUS = 0x50; +pub const FACILITY_VOLMGR: NTSTATUS = 0x38; +pub const FACILITY_VIRTUALIZATION: NTSTATUS = 0x37; +pub const FACILITY_VIDEO: NTSTATUS = 0x1B; +pub const FACILITY_USB_ERROR_CODE: NTSTATUS = 0x10; +pub const FACILITY_TRANSACTION: NTSTATUS = 0x19; +pub const FACILITY_TPM: NTSTATUS = 0x29; +pub const FACILITY_TERMINAL_SERVER: NTSTATUS = 0xA; +pub const FACILITY_SXS_ERROR_CODE: NTSTATUS = 0x15; +pub const FACILITY_NTSSPI: NTSTATUS = 0x9; +pub const FACILITY_SPACES: NTSTATUS = 0xE7; +pub const FACILITY_SMB: NTSTATUS = 0x5D; +pub const FACILITY_SYSTEM_INTEGRITY: NTSTATUS = 0xE9; +pub const FACILITY_SHARED_VHDX: NTSTATUS = 0x5C; +pub const FACILITY_SECUREBOOT: NTSTATUS = 0x43; +pub const FACILITY_SECURITY_CORE: NTSTATUS = 0xE8; +pub const FACILITY_SDBUS: NTSTATUS = 0x51; +pub const FACILITY_RTPM: NTSTATUS = 0x2A; +pub const FACILITY_RPC_STUBS: NTSTATUS = 0x3; +pub const FACILITY_RPC_RUNTIME: NTSTATUS = 0x2; +pub const FACILITY_RESUME_KEY_FILTER: NTSTATUS = 0x40; +pub const FACILITY_RDBSS: NTSTATUS = 0x41; +pub const FACILITY_PLATFORM_MANIFEST: NTSTATUS = 0xEB; +pub const FACILITY_NTWIN32: NTSTATUS = 0x7; +pub const FACILITY_WIN32K_NTUSER: NTSTATUS = 0x3E; +pub const FACILITY_WIN32K_NTGDI: NTSTATUS = 0x3F; +pub const FACILITY_NDIS_ERROR_CODE: NTSTATUS = 0x23; +pub const FACILTIY_MUI_ERROR_CODE: NTSTATUS = 0xB; +pub const FACILITY_MONITOR: NTSTATUS = 0x1D; +pub const FACILITY_MAXIMUM_VALUE: NTSTATUS = 0xEC; +pub const FACILITY_LICENSING: NTSTATUS = 0xEA; +pub const FACILITY_IPSEC: NTSTATUS = 0x36; +pub const FACILITY_IO_ERROR_CODE: NTSTATUS = 0x4; +pub const FACILITY_INTERIX: NTSTATUS = 0x99; +pub const FACILITY_HYPERVISOR: NTSTATUS = 0x35; +pub const FACILITY_HID_ERROR_CODE: NTSTATUS = 0x11; +pub const FACILITY_GRAPHICS_KERNEL: NTSTATUS = 0x1E; +pub const FACILITY_FWP_ERROR_CODE: NTSTATUS = 0x22; +pub const FACILITY_FVE_ERROR_CODE: NTSTATUS = 0x21; +pub const FACILITY_FIREWIRE_ERROR_CODE: NTSTATUS = 0x12; +pub const FACILITY_FILTER_MANAGER: NTSTATUS = 0x1C; +pub const FACILITY_DRIVER_FRAMEWORK: NTSTATUS = 0x20; +pub const FACILITY_DEBUGGER: NTSTATUS = 0x1; +pub const FACILITY_COMMONLOG: NTSTATUS = 0x1A; +pub const FACILITY_CODCLASS_ERROR_CODE: NTSTATUS = 0x6; +pub const FACILITY_CLUSTER_ERROR_CODE: NTSTATUS = 0x13; +pub const FACILITY_NTCERT: NTSTATUS = 0x8; +pub const FACILITY_BTH_ATT: NTSTATUS = 0x42; +pub const FACILITY_BCD_ERROR_CODE: NTSTATUS = 0x39; +pub const FACILITY_AUDIO_KERNEL: NTSTATUS = 0x44; +pub const FACILITY_ACPI_ERROR_CODE: NTSTATUS = 0x14; +pub const STATUS_SEVERITY_WARNING: NTSTATUS = 0x2; +pub const STATUS_SEVERITY_SUCCESS: NTSTATUS = 0x0; +pub const STATUS_SEVERITY_INFORMATIONAL: NTSTATUS = 0x1; +pub const STATUS_SEVERITY_ERROR: NTSTATUS = 0x3; +pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; +pub const STATUS_WAIT_1: NTSTATUS = 0x00000001; +pub const STATUS_WAIT_2: NTSTATUS = 0x00000002; +pub const STATUS_WAIT_3: NTSTATUS = 0x00000003; +pub const STATUS_WAIT_63: NTSTATUS = 0x0000003F; +pub const STATUS_ABANDONED: NTSTATUS = 0x00000080; +pub const STATUS_ABANDONED_WAIT_0: NTSTATUS = 0x00000080; +pub const STATUS_ABANDONED_WAIT_63: NTSTATUS = 0x000000BF; +pub const STATUS_USER_APC: NTSTATUS = 0x000000C0; +pub const STATUS_ALREADY_COMPLETE: NTSTATUS = 0x000000FF; +pub const STATUS_KERNEL_APC: NTSTATUS = 0x00000100; +pub const STATUS_ALERTED: NTSTATUS = 0x00000101; +pub const STATUS_TIMEOUT: NTSTATUS = 0x00000102; +pub const STATUS_PENDING: NTSTATUS = 0x00000103; +pub const STATUS_REPARSE: NTSTATUS = 0x00000104; +pub const STATUS_MORE_ENTRIES: NTSTATUS = 0x00000105; +pub const STATUS_NOT_ALL_ASSIGNED: NTSTATUS = 0x00000106; +pub const STATUS_SOME_NOT_MAPPED: NTSTATUS = 0x00000107; +pub const STATUS_OPLOCK_BREAK_IN_PROGRESS: NTSTATUS = 0x00000108; +pub const STATUS_VOLUME_MOUNTED: NTSTATUS = 0x00000109; +pub const STATUS_RXACT_COMMITTED: NTSTATUS = 0x0000010A; +pub const STATUS_NOTIFY_CLEANUP: NTSTATUS = 0x0000010B; +pub const STATUS_NOTIFY_ENUM_DIR: NTSTATUS = 0x0000010C; +pub const STATUS_NO_QUOTAS_FOR_ACCOUNT: NTSTATUS = 0x0000010D; +pub const STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED: NTSTATUS = 0x0000010E; +pub const STATUS_PAGE_FAULT_TRANSITION: NTSTATUS = 0x00000110; +pub const STATUS_PAGE_FAULT_DEMAND_ZERO: NTSTATUS = 0x00000111; +pub const STATUS_PAGE_FAULT_COPY_ON_WRITE: NTSTATUS = 0x00000112; +pub const STATUS_PAGE_FAULT_GUARD_PAGE: NTSTATUS = 0x00000113; +pub const STATUS_PAGE_FAULT_PAGING_FILE: NTSTATUS = 0x00000114; +pub const STATUS_CACHE_PAGE_LOCKED: NTSTATUS = 0x00000115; +pub const STATUS_CRASH_DUMP: NTSTATUS = 0x00000116; +pub const STATUS_BUFFER_ALL_ZEROS: NTSTATUS = 0x00000117; +pub const STATUS_REPARSE_OBJECT: NTSTATUS = 0x00000118; +pub const STATUS_RESOURCE_REQUIREMENTS_CHANGED: NTSTATUS = 0x00000119; +pub const STATUS_TRANSLATION_COMPLETE: NTSTATUS = 0x00000120; +pub const STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY: NTSTATUS = 0x00000121; +pub const STATUS_NOTHING_TO_TERMINATE: NTSTATUS = 0x00000122; +pub const STATUS_PROCESS_NOT_IN_JOB: NTSTATUS = 0x00000123; +pub const STATUS_PROCESS_IN_JOB: NTSTATUS = 0x00000124; +pub const STATUS_VOLSNAP_HIBERNATE_READY: NTSTATUS = 0x00000125; +pub const STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY: NTSTATUS = 0x00000126; +pub const STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: NTSTATUS = 0x00000127; +pub const STATUS_INTERRUPT_STILL_CONNECTED: NTSTATUS = 0x00000128; +pub const STATUS_PROCESS_CLONED: NTSTATUS = 0x00000129; +pub const STATUS_FILE_LOCKED_WITH_ONLY_READERS: NTSTATUS = 0x0000012A; +pub const STATUS_FILE_LOCKED_WITH_WRITERS: NTSTATUS = 0x0000012B; +pub const STATUS_VALID_IMAGE_HASH: NTSTATUS = 0x0000012C; +pub const STATUS_VALID_CATALOG_HASH: NTSTATUS = 0x0000012D; +pub const STATUS_VALID_STRONG_CODE_HASH: NTSTATUS = 0x0000012E; +pub const STATUS_GHOSTED: NTSTATUS = 0x0000012F; +pub const STATUS_RESOURCEMANAGER_READ_ONLY: NTSTATUS = 0x00000202; +pub const STATUS_RING_PREVIOUSLY_EMPTY: NTSTATUS = 0x00000210; +pub const STATUS_RING_PREVIOUSLY_FULL: NTSTATUS = 0x00000211; +pub const STATUS_RING_PREVIOUSLY_ABOVE_QUOTA: NTSTATUS = 0x00000212; +pub const STATUS_RING_NEWLY_EMPTY: NTSTATUS = 0x00000213; +pub const STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT: NTSTATUS = 0x00000214; +pub const STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE: NTSTATUS = 0x00000215; +pub const STATUS_OPLOCK_HANDLE_CLOSED: NTSTATUS = 0x00000216; +pub const STATUS_WAIT_FOR_OPLOCK: NTSTATUS = 0x00000367; +pub const STATUS_REPARSE_GLOBAL: NTSTATUS = 0x00000368; +pub const DBG_EXCEPTION_HANDLED: NTSTATUS = 0x00010001; +pub const DBG_CONTINUE: NTSTATUS = 0x00010002; +pub const STATUS_FLT_IO_COMPLETE: NTSTATUS = 0x001C0001; +pub const STATUS_OBJECT_NAME_EXISTS: NTSTATUS = 0x40000000; +pub const STATUS_THREAD_WAS_SUSPENDED: NTSTATUS = 0x40000001; +pub const STATUS_WORKING_SET_LIMIT_RANGE: NTSTATUS = 0x40000002; +pub const STATUS_IMAGE_NOT_AT_BASE: NTSTATUS = 0x40000003; +pub const STATUS_RXACT_STATE_CREATED: NTSTATUS = 0x40000004; +pub const STATUS_SEGMENT_NOTIFICATION: NTSTATUS = 0x40000005; +pub const STATUS_LOCAL_USER_SESSION_KEY: NTSTATUS = 0x40000006; +pub const STATUS_BAD_CURRENT_DIRECTORY: NTSTATUS = 0x40000007; +pub const STATUS_SERIAL_MORE_WRITES: NTSTATUS = 0x40000008; +pub const STATUS_REGISTRY_RECOVERED: NTSTATUS = 0x40000009; +pub const STATUS_FT_READ_RECOVERY_FROM_BACKUP: NTSTATUS = 0x4000000A; +pub const STATUS_FT_WRITE_RECOVERY: NTSTATUS = 0x4000000B; +pub const STATUS_SERIAL_COUNTER_TIMEOUT: NTSTATUS = 0x4000000C; +pub const STATUS_NULL_LM_PASSWORD: NTSTATUS = 0x4000000D; +pub const STATUS_IMAGE_MACHINE_TYPE_MISMATCH: NTSTATUS = 0x4000000E; +pub const STATUS_RECEIVE_PARTIAL: NTSTATUS = 0x4000000F; +pub const STATUS_RECEIVE_EXPEDITED: NTSTATUS = 0x40000010; +pub const STATUS_RECEIVE_PARTIAL_EXPEDITED: NTSTATUS = 0x40000011; +pub const STATUS_EVENT_DONE: NTSTATUS = 0x40000012; +pub const STATUS_EVENT_PENDING: NTSTATUS = 0x40000013; +pub const STATUS_CHECKING_FILE_SYSTEM: NTSTATUS = 0x40000014; +pub const STATUS_FATAL_APP_EXIT: NTSTATUS = 0x40000015; +pub const STATUS_PREDEFINED_HANDLE: NTSTATUS = 0x40000016; +pub const STATUS_WAS_UNLOCKED: NTSTATUS = 0x40000017; +pub const STATUS_SERVICE_NOTIFICATION: NTSTATUS = 0x40000018; +pub const STATUS_WAS_LOCKED: NTSTATUS = 0x40000019; +pub const STATUS_LOG_HARD_ERROR: NTSTATUS = 0x4000001A; +pub const STATUS_ALREADY_WIN32: NTSTATUS = 0x4000001B; +pub const STATUS_WX86_UNSIMULATE: NTSTATUS = 0x4000001C; +pub const STATUS_WX86_CONTINUE: NTSTATUS = 0x4000001D; +pub const STATUS_WX86_SINGLE_STEP: NTSTATUS = 0x4000001E; +pub const STATUS_WX86_BREAKPOINT: NTSTATUS = 0x4000001F; +pub const STATUS_WX86_EXCEPTION_CONTINUE: NTSTATUS = 0x40000020; +pub const STATUS_WX86_EXCEPTION_LASTCHANCE: NTSTATUS = 0x40000021; +pub const STATUS_WX86_EXCEPTION_CHAIN: NTSTATUS = 0x40000022; +pub const STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: NTSTATUS = 0x40000023; +pub const STATUS_NO_YIELD_PERFORMED: NTSTATUS = 0x40000024; +pub const STATUS_TIMER_RESUME_IGNORED: NTSTATUS = 0x40000025; +pub const STATUS_ARBITRATION_UNHANDLED: NTSTATUS = 0x40000026; +pub const STATUS_CARDBUS_NOT_SUPPORTED: NTSTATUS = 0x40000027; +pub const STATUS_WX86_CREATEWX86TIB: NTSTATUS = 0x40000028; +pub const STATUS_MP_PROCESSOR_MISMATCH: NTSTATUS = 0x40000029; +pub const STATUS_HIBERNATED: NTSTATUS = 0x4000002A; +pub const STATUS_RESUME_HIBERNATION: NTSTATUS = 0x4000002B; +pub const STATUS_FIRMWARE_UPDATED: NTSTATUS = 0x4000002C; +pub const STATUS_DRIVERS_LEAKING_LOCKED_PAGES: NTSTATUS = 0x4000002D; +pub const STATUS_MESSAGE_RETRIEVED: NTSTATUS = 0x4000002E; +pub const STATUS_SYSTEM_POWERSTATE_TRANSITION: NTSTATUS = 0x4000002F; +pub const STATUS_ALPC_CHECK_COMPLETION_LIST: NTSTATUS = 0x40000030; +pub const STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: NTSTATUS = 0x40000031; +pub const STATUS_ACCESS_AUDIT_BY_POLICY: NTSTATUS = 0x40000032; +pub const STATUS_ABANDON_HIBERFILE: NTSTATUS = 0x40000033; +pub const STATUS_BIZRULES_NOT_ENABLED: NTSTATUS = 0x40000034; +pub const STATUS_FT_READ_FROM_COPY: NTSTATUS = 0x40000035; +pub const STATUS_IMAGE_AT_DIFFERENT_BASE: NTSTATUS = 0x40000036; +pub const DBG_REPLY_LATER: NTSTATUS = 0x40010001; +pub const DBG_UNABLE_TO_PROVIDE_HANDLE: NTSTATUS = 0x40010002; +pub const DBG_TERMINATE_THREAD: NTSTATUS = 0x40010003; +pub const DBG_TERMINATE_PROCESS: NTSTATUS = 0x40010004; +pub const DBG_CONTROL_C: NTSTATUS = 0x40010005; +pub const DBG_PRINTEXCEPTION_C: NTSTATUS = 0x40010006; +pub const DBG_RIPEXCEPTION: NTSTATUS = 0x40010007; +pub const DBG_CONTROL_BREAK: NTSTATUS = 0x40010008; +pub const DBG_COMMAND_EXCEPTION: NTSTATUS = 0x40010009; +pub const DBG_PRINTEXCEPTION_WIDE_C: NTSTATUS = 0x4001000A; +pub const STATUS_HEURISTIC_DAMAGE_POSSIBLE: NTSTATUS = 0x40190001; +pub const STATUS_GUARD_PAGE_VIOLATION: NTSTATUS = 0x80000001; +pub const STATUS_DATATYPE_MISALIGNMENT: NTSTATUS = 0x80000002; +pub const STATUS_BREAKPOINT: NTSTATUS = 0x80000003; +pub const STATUS_SINGLE_STEP: NTSTATUS = 0x80000004; +pub const STATUS_BUFFER_OVERFLOW: NTSTATUS = 0x80000005; +pub const STATUS_NO_MORE_FILES: NTSTATUS = 0x80000006; +pub const STATUS_WAKE_SYSTEM_DEBUGGER: NTSTATUS = 0x80000007; +pub const STATUS_HANDLES_CLOSED: NTSTATUS = 0x8000000A; +pub const STATUS_NO_INHERITANCE: NTSTATUS = 0x8000000B; +pub const STATUS_GUID_SUBSTITUTION_MADE: NTSTATUS = 0x8000000C; +pub const STATUS_PARTIAL_COPY: NTSTATUS = 0x8000000D; +pub const STATUS_DEVICE_PAPER_EMPTY: NTSTATUS = 0x8000000E; +pub const STATUS_DEVICE_POWERED_OFF: NTSTATUS = 0x8000000F; +pub const STATUS_DEVICE_OFF_LINE: NTSTATUS = 0x80000010; +pub const STATUS_DEVICE_BUSY: NTSTATUS = 0x80000011; +pub const STATUS_NO_MORE_EAS: NTSTATUS = 0x80000012; +pub const STATUS_INVALID_EA_NAME: NTSTATUS = 0x80000013; +pub const STATUS_EA_LIST_INCONSISTENT: NTSTATUS = 0x80000014; +pub const STATUS_INVALID_EA_FLAG: NTSTATUS = 0x80000015; +pub const STATUS_VERIFY_REQUIRED: NTSTATUS = 0x80000016; +pub const STATUS_EXTRANEOUS_INFORMATION: NTSTATUS = 0x80000017; +pub const STATUS_RXACT_COMMIT_NECESSARY: NTSTATUS = 0x80000018; +pub const STATUS_NO_MORE_ENTRIES: NTSTATUS = 0x8000001A; +pub const STATUS_FILEMARK_DETECTED: NTSTATUS = 0x8000001B; +pub const STATUS_MEDIA_CHANGED: NTSTATUS = 0x8000001C; +pub const STATUS_BUS_RESET: NTSTATUS = 0x8000001D; +pub const STATUS_END_OF_MEDIA: NTSTATUS = 0x8000001E; +pub const STATUS_BEGINNING_OF_MEDIA: NTSTATUS = 0x8000001F; +pub const STATUS_MEDIA_CHECK: NTSTATUS = 0x80000020; +pub const STATUS_SETMARK_DETECTED: NTSTATUS = 0x80000021; +pub const STATUS_NO_DATA_DETECTED: NTSTATUS = 0x80000022; +pub const STATUS_REDIRECTOR_HAS_OPEN_HANDLES: NTSTATUS = 0x80000023; +pub const STATUS_SERVER_HAS_OPEN_HANDLES: NTSTATUS = 0x80000024; +pub const STATUS_ALREADY_DISCONNECTED: NTSTATUS = 0x80000025; +pub const STATUS_LONGJUMP: NTSTATUS = 0x80000026; +pub const STATUS_CLEANER_CARTRIDGE_INSTALLED: NTSTATUS = 0x80000027; +pub const STATUS_PLUGPLAY_QUERY_VETOED: NTSTATUS = 0x80000028; +pub const STATUS_UNWIND_CONSOLIDATE: NTSTATUS = 0x80000029; +pub const STATUS_REGISTRY_HIVE_RECOVERED: NTSTATUS = 0x8000002A; +pub const STATUS_DLL_MIGHT_BE_INSECURE: NTSTATUS = 0x8000002B; +pub const STATUS_DLL_MIGHT_BE_INCOMPATIBLE: NTSTATUS = 0x8000002C; +pub const STATUS_STOPPED_ON_SYMLINK: NTSTATUS = 0x8000002D; +pub const STATUS_CANNOT_GRANT_REQUESTED_OPLOCK: NTSTATUS = 0x8000002E; +pub const STATUS_NO_ACE_CONDITION: NTSTATUS = 0x8000002F; +pub const STATUS_DEVICE_SUPPORT_IN_PROGRESS: NTSTATUS = 0x80000030; +pub const STATUS_DEVICE_POWER_CYCLE_REQUIRED: NTSTATUS = 0x80000031; +pub const STATUS_NO_WORK_DONE: NTSTATUS = 0x80000032; +pub const DBG_EXCEPTION_NOT_HANDLED: NTSTATUS = 0x80010001; +pub const STATUS_CLUSTER_NODE_ALREADY_UP: NTSTATUS = 0x80130001; +pub const STATUS_CLUSTER_NODE_ALREADY_DOWN: NTSTATUS = 0x80130002; +pub const STATUS_CLUSTER_NETWORK_ALREADY_ONLINE: NTSTATUS = 0x80130003; +pub const STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE: NTSTATUS = 0x80130004; +pub const STATUS_CLUSTER_NODE_ALREADY_MEMBER: NTSTATUS = 0x80130005; +pub const STATUS_FLT_BUFFER_TOO_SMALL: NTSTATUS = 0x801C0001; +pub const STATUS_FVE_PARTIAL_METADATA: NTSTATUS = 0x80210001; +pub const STATUS_FVE_TRANSIENT_STATE: NTSTATUS = 0x80210002; +pub const STATUS_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH: NTSTATUS = 0x8000CF00; +pub const STATUS_UNSUCCESSFUL: NTSTATUS = 0xC0000001; +pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002; +pub const STATUS_INVALID_INFO_CLASS: NTSTATUS = 0xC0000003; +pub const STATUS_INFO_LENGTH_MISMATCH: NTSTATUS = 0xC0000004; +pub const STATUS_ACCESS_VIOLATION: NTSTATUS = 0xC0000005; +pub const STATUS_IN_PAGE_ERROR: NTSTATUS = 0xC0000006; +pub const STATUS_PAGEFILE_QUOTA: NTSTATUS = 0xC0000007; +pub const STATUS_INVALID_HANDLE: NTSTATUS = 0xC0000008; +pub const STATUS_BAD_INITIAL_STACK: NTSTATUS = 0xC0000009; +pub const STATUS_BAD_INITIAL_PC: NTSTATUS = 0xC000000A; +pub const STATUS_INVALID_CID: NTSTATUS = 0xC000000B; +pub const STATUS_TIMER_NOT_CANCELED: NTSTATUS = 0xC000000C; +pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xC000000D; +pub const STATUS_NO_SUCH_DEVICE: NTSTATUS = 0xC000000E; +pub const STATUS_NO_SUCH_FILE: NTSTATUS = 0xC000000F; +pub const STATUS_INVALID_DEVICE_REQUEST: NTSTATUS = 0xC0000010; +pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011; +pub const STATUS_WRONG_VOLUME: NTSTATUS = 0xC0000012; +pub const STATUS_NO_MEDIA_IN_DEVICE: NTSTATUS = 0xC0000013; +pub const STATUS_UNRECOGNIZED_MEDIA: NTSTATUS = 0xC0000014; +pub const STATUS_NONEXISTENT_SECTOR: NTSTATUS = 0xC0000015; +pub const STATUS_MORE_PROCESSING_REQUIRED: NTSTATUS = 0xC0000016; +pub const STATUS_NO_MEMORY: NTSTATUS = 0xC0000017; +pub const STATUS_CONFLICTING_ADDRESSES: NTSTATUS = 0xC0000018; +pub const STATUS_NOT_MAPPED_VIEW: NTSTATUS = 0xC0000019; +pub const STATUS_UNABLE_TO_FREE_VM: NTSTATUS = 0xC000001A; +pub const STATUS_UNABLE_TO_DELETE_SECTION: NTSTATUS = 0xC000001B; +pub const STATUS_INVALID_SYSTEM_SERVICE: NTSTATUS = 0xC000001C; +pub const STATUS_ILLEGAL_INSTRUCTION: NTSTATUS = 0xC000001D; +pub const STATUS_INVALID_LOCK_SEQUENCE: NTSTATUS = 0xC000001E; +pub const STATUS_INVALID_VIEW_SIZE: NTSTATUS = 0xC000001F; +pub const STATUS_INVALID_FILE_FOR_SECTION: NTSTATUS = 0xC0000020; +pub const STATUS_ALREADY_COMMITTED: NTSTATUS = 0xC0000021; +pub const STATUS_ACCESS_DENIED: NTSTATUS = 0xC0000022; +pub const STATUS_BUFFER_TOO_SMALL: NTSTATUS = 0xC0000023; +pub const STATUS_OBJECT_TYPE_MISMATCH: NTSTATUS = 0xC0000024; +pub const STATUS_NONCONTINUABLE_EXCEPTION: NTSTATUS = 0xC0000025; +pub const STATUS_INVALID_DISPOSITION: NTSTATUS = 0xC0000026; +pub const STATUS_UNWIND: NTSTATUS = 0xC0000027; +pub const STATUS_BAD_STACK: NTSTATUS = 0xC0000028; +pub const STATUS_INVALID_UNWIND_TARGET: NTSTATUS = 0xC0000029; +pub const STATUS_NOT_LOCKED: NTSTATUS = 0xC000002A; +pub const STATUS_PARITY_ERROR: NTSTATUS = 0xC000002B; +pub const STATUS_UNABLE_TO_DECOMMIT_VM: NTSTATUS = 0xC000002C; +pub const STATUS_NOT_COMMITTED: NTSTATUS = 0xC000002D; +pub const STATUS_INVALID_PORT_ATTRIBUTES: NTSTATUS = 0xC000002E; +pub const STATUS_PORT_MESSAGE_TOO_LONG: NTSTATUS = 0xC000002F; +pub const STATUS_INVALID_PARAMETER_MIX: NTSTATUS = 0xC0000030; +pub const STATUS_INVALID_QUOTA_LOWER: NTSTATUS = 0xC0000031; +pub const STATUS_DISK_CORRUPT_ERROR: NTSTATUS = 0xC0000032; +pub const STATUS_OBJECT_NAME_INVALID: NTSTATUS = 0xC0000033; +pub const STATUS_OBJECT_NAME_NOT_FOUND: NTSTATUS = 0xC0000034; +pub const STATUS_OBJECT_NAME_COLLISION: NTSTATUS = 0xC0000035; +pub const STATUS_PORT_DO_NOT_DISTURB: NTSTATUS = 0xC0000036; +pub const STATUS_PORT_DISCONNECTED: NTSTATUS = 0xC0000037; +pub const STATUS_DEVICE_ALREADY_ATTACHED: NTSTATUS = 0xC0000038; +pub const STATUS_OBJECT_PATH_INVALID: NTSTATUS = 0xC0000039; +pub const STATUS_OBJECT_PATH_NOT_FOUND: NTSTATUS = 0xC000003A; +pub const STATUS_OBJECT_PATH_SYNTAX_BAD: NTSTATUS = 0xC000003B; +pub const STATUS_DATA_OVERRUN: NTSTATUS = 0xC000003C; +pub const STATUS_DATA_LATE_ERROR: NTSTATUS = 0xC000003D; +pub const STATUS_DATA_ERROR: NTSTATUS = 0xC000003E; +pub const STATUS_CRC_ERROR: NTSTATUS = 0xC000003F; +pub const STATUS_SECTION_TOO_BIG: NTSTATUS = 0xC0000040; +pub const STATUS_PORT_CONNECTION_REFUSED: NTSTATUS = 0xC0000041; +pub const STATUS_INVALID_PORT_HANDLE: NTSTATUS = 0xC0000042; +pub const STATUS_SHARING_VIOLATION: NTSTATUS = 0xC0000043; +pub const STATUS_QUOTA_EXCEEDED: NTSTATUS = 0xC0000044; +pub const STATUS_INVALID_PAGE_PROTECTION: NTSTATUS = 0xC0000045; +pub const STATUS_MUTANT_NOT_OWNED: NTSTATUS = 0xC0000046; +pub const STATUS_SEMAPHORE_LIMIT_EXCEEDED: NTSTATUS = 0xC0000047; +pub const STATUS_PORT_ALREADY_SET: NTSTATUS = 0xC0000048; +pub const STATUS_SECTION_NOT_IMAGE: NTSTATUS = 0xC0000049; +pub const STATUS_SUSPEND_COUNT_EXCEEDED: NTSTATUS = 0xC000004A; +pub const STATUS_THREAD_IS_TERMINATING: NTSTATUS = 0xC000004B; +pub const STATUS_BAD_WORKING_SET_LIMIT: NTSTATUS = 0xC000004C; +pub const STATUS_INCOMPATIBLE_FILE_MAP: NTSTATUS = 0xC000004D; +pub const STATUS_SECTION_PROTECTION: NTSTATUS = 0xC000004E; +pub const STATUS_EAS_NOT_SUPPORTED: NTSTATUS = 0xC000004F; +pub const STATUS_EA_TOO_LARGE: NTSTATUS = 0xC0000050; +pub const STATUS_NONEXISTENT_EA_ENTRY: NTSTATUS = 0xC0000051; +pub const STATUS_NO_EAS_ON_FILE: NTSTATUS = 0xC0000052; +pub const STATUS_EA_CORRUPT_ERROR: NTSTATUS = 0xC0000053; +pub const STATUS_FILE_LOCK_CONFLICT: NTSTATUS = 0xC0000054; +pub const STATUS_LOCK_NOT_GRANTED: NTSTATUS = 0xC0000055; +pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056; +pub const STATUS_CTL_FILE_NOT_SUPPORTED: NTSTATUS = 0xC0000057; +pub const STATUS_UNKNOWN_REVISION: NTSTATUS = 0xC0000058; +pub const STATUS_REVISION_MISMATCH: NTSTATUS = 0xC0000059; +pub const STATUS_INVALID_OWNER: NTSTATUS = 0xC000005A; +pub const STATUS_INVALID_PRIMARY_GROUP: NTSTATUS = 0xC000005B; +pub const STATUS_NO_IMPERSONATION_TOKEN: NTSTATUS = 0xC000005C; +pub const STATUS_CANT_DISABLE_MANDATORY: NTSTATUS = 0xC000005D; +pub const STATUS_NO_LOGON_SERVERS: NTSTATUS = 0xC000005E; +pub const STATUS_NO_SUCH_LOGON_SESSION: NTSTATUS = 0xC000005F; +pub const STATUS_NO_SUCH_PRIVILEGE: NTSTATUS = 0xC0000060; +pub const STATUS_PRIVILEGE_NOT_HELD: NTSTATUS = 0xC0000061; +pub const STATUS_INVALID_ACCOUNT_NAME: NTSTATUS = 0xC0000062; +pub const STATUS_USER_EXISTS: NTSTATUS = 0xC0000063; +pub const STATUS_NO_SUCH_USER: NTSTATUS = 0xC0000064; +pub const STATUS_GROUP_EXISTS: NTSTATUS = 0xC0000065; +pub const STATUS_NO_SUCH_GROUP: NTSTATUS = 0xC0000066; +pub const STATUS_MEMBER_IN_GROUP: NTSTATUS = 0xC0000067; +pub const STATUS_MEMBER_NOT_IN_GROUP: NTSTATUS = 0xC0000068; +pub const STATUS_LAST_ADMIN: NTSTATUS = 0xC0000069; +pub const STATUS_WRONG_PASSWORD: NTSTATUS = 0xC000006A; +pub const STATUS_ILL_FORMED_PASSWORD: NTSTATUS = 0xC000006B; +pub const STATUS_PASSWORD_RESTRICTION: NTSTATUS = 0xC000006C; +pub const STATUS_LOGON_FAILURE: NTSTATUS = 0xC000006D; +pub const STATUS_ACCOUNT_RESTRICTION: NTSTATUS = 0xC000006E; +pub const STATUS_INVALID_LOGON_HOURS: NTSTATUS = 0xC000006F; +pub const STATUS_INVALID_WORKSTATION: NTSTATUS = 0xC0000070; +pub const STATUS_PASSWORD_EXPIRED: NTSTATUS = 0xC0000071; +pub const STATUS_ACCOUNT_DISABLED: NTSTATUS = 0xC0000072; +pub const STATUS_NONE_MAPPED: NTSTATUS = 0xC0000073; +pub const STATUS_TOO_MANY_LUIDS_REQUESTED: NTSTATUS = 0xC0000074; +pub const STATUS_LUIDS_EXHAUSTED: NTSTATUS = 0xC0000075; +pub const STATUS_INVALID_SUB_AUTHORITY: NTSTATUS = 0xC0000076; +pub const STATUS_INVALID_ACL: NTSTATUS = 0xC0000077; +pub const STATUS_INVALID_SID: NTSTATUS = 0xC0000078; +pub const STATUS_INVALID_SECURITY_DESCR: NTSTATUS = 0xC0000079; +pub const STATUS_PROCEDURE_NOT_FOUND: NTSTATUS = 0xC000007A; +pub const STATUS_INVALID_IMAGE_FORMAT: NTSTATUS = 0xC000007B; +pub const STATUS_NO_TOKEN: NTSTATUS = 0xC000007C; +pub const STATUS_BAD_INHERITANCE_ACL: NTSTATUS = 0xC000007D; +pub const STATUS_RANGE_NOT_LOCKED: NTSTATUS = 0xC000007E; +pub const STATUS_DISK_FULL: NTSTATUS = 0xC000007F; +pub const STATUS_SERVER_DISABLED: NTSTATUS = 0xC0000080; +pub const STATUS_SERVER_NOT_DISABLED: NTSTATUS = 0xC0000081; +pub const STATUS_TOO_MANY_GUIDS_REQUESTED: NTSTATUS = 0xC0000082; +pub const STATUS_GUIDS_EXHAUSTED: NTSTATUS = 0xC0000083; +pub const STATUS_INVALID_ID_AUTHORITY: NTSTATUS = 0xC0000084; +pub const STATUS_AGENTS_EXHAUSTED: NTSTATUS = 0xC0000085; +pub const STATUS_INVALID_VOLUME_LABEL: NTSTATUS = 0xC0000086; +pub const STATUS_SECTION_NOT_EXTENDED: NTSTATUS = 0xC0000087; +pub const STATUS_NOT_MAPPED_DATA: NTSTATUS = 0xC0000088; +pub const STATUS_RESOURCE_DATA_NOT_FOUND: NTSTATUS = 0xC0000089; +pub const STATUS_RESOURCE_TYPE_NOT_FOUND: NTSTATUS = 0xC000008A; +pub const STATUS_RESOURCE_NAME_NOT_FOUND: NTSTATUS = 0xC000008B; +pub const STATUS_ARRAY_BOUNDS_EXCEEDED: NTSTATUS = 0xC000008C; +pub const STATUS_FLOAT_DENORMAL_OPERAND: NTSTATUS = 0xC000008D; +pub const STATUS_FLOAT_DIVIDE_BY_ZERO: NTSTATUS = 0xC000008E; +pub const STATUS_FLOAT_INEXACT_RESULT: NTSTATUS = 0xC000008F; +pub const STATUS_FLOAT_INVALID_OPERATION: NTSTATUS = 0xC0000090; +pub const STATUS_FLOAT_OVERFLOW: NTSTATUS = 0xC0000091; +pub const STATUS_FLOAT_STACK_CHECK: NTSTATUS = 0xC0000092; +pub const STATUS_FLOAT_UNDERFLOW: NTSTATUS = 0xC0000093; +pub const STATUS_INTEGER_DIVIDE_BY_ZERO: NTSTATUS = 0xC0000094; +pub const STATUS_INTEGER_OVERFLOW: NTSTATUS = 0xC0000095; +pub const STATUS_PRIVILEGED_INSTRUCTION: NTSTATUS = 0xC0000096; +pub const STATUS_TOO_MANY_PAGING_FILES: NTSTATUS = 0xC0000097; +pub const STATUS_FILE_INVALID: NTSTATUS = 0xC0000098; +pub const STATUS_ALLOTTED_SPACE_EXCEEDED: NTSTATUS = 0xC0000099; +pub const STATUS_INSUFFICIENT_RESOURCES: NTSTATUS = 0xC000009A; +pub const STATUS_DFS_EXIT_PATH_FOUND: NTSTATUS = 0xC000009B; +pub const STATUS_DEVICE_DATA_ERROR: NTSTATUS = 0xC000009C; +pub const STATUS_DEVICE_NOT_CONNECTED: NTSTATUS = 0xC000009D; +pub const STATUS_DEVICE_POWER_FAILURE: NTSTATUS = 0xC000009E; +pub const STATUS_FREE_VM_NOT_AT_BASE: NTSTATUS = 0xC000009F; +pub const STATUS_MEMORY_NOT_ALLOCATED: NTSTATUS = 0xC00000A0; +pub const STATUS_WORKING_SET_QUOTA: NTSTATUS = 0xC00000A1; +pub const STATUS_MEDIA_WRITE_PROTECTED: NTSTATUS = 0xC00000A2; +pub const STATUS_DEVICE_NOT_READY: NTSTATUS = 0xC00000A3; +pub const STATUS_INVALID_GROUP_ATTRIBUTES: NTSTATUS = 0xC00000A4; +pub const STATUS_BAD_IMPERSONATION_LEVEL: NTSTATUS = 0xC00000A5; +pub const STATUS_CANT_OPEN_ANONYMOUS: NTSTATUS = 0xC00000A6; +pub const STATUS_BAD_VALIDATION_CLASS: NTSTATUS = 0xC00000A7; +pub const STATUS_BAD_TOKEN_TYPE: NTSTATUS = 0xC00000A8; +pub const STATUS_BAD_MASTER_BOOT_RECORD: NTSTATUS = 0xC00000A9; +pub const STATUS_INSTRUCTION_MISALIGNMENT: NTSTATUS = 0xC00000AA; +pub const STATUS_INSTANCE_NOT_AVAILABLE: NTSTATUS = 0xC00000AB; +pub const STATUS_PIPE_NOT_AVAILABLE: NTSTATUS = 0xC00000AC; +pub const STATUS_INVALID_PIPE_STATE: NTSTATUS = 0xC00000AD; +pub const STATUS_PIPE_BUSY: NTSTATUS = 0xC00000AE; +pub const STATUS_ILLEGAL_FUNCTION: NTSTATUS = 0xC00000AF; +pub const STATUS_PIPE_DISCONNECTED: NTSTATUS = 0xC00000B0; +pub const STATUS_PIPE_CLOSING: NTSTATUS = 0xC00000B1; +pub const STATUS_PIPE_CONNECTED: NTSTATUS = 0xC00000B2; +pub const STATUS_PIPE_LISTENING: NTSTATUS = 0xC00000B3; +pub const STATUS_INVALID_READ_MODE: NTSTATUS = 0xC00000B4; +pub const STATUS_IO_TIMEOUT: NTSTATUS = 0xC00000B5; +pub const STATUS_FILE_FORCED_CLOSED: NTSTATUS = 0xC00000B6; +pub const STATUS_PROFILING_NOT_STARTED: NTSTATUS = 0xC00000B7; +pub const STATUS_PROFILING_NOT_STOPPED: NTSTATUS = 0xC00000B8; +pub const STATUS_COULD_NOT_INTERPRET: NTSTATUS = 0xC00000B9; +pub const STATUS_FILE_IS_A_DIRECTORY: NTSTATUS = 0xC00000BA; +pub const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC00000BB; +pub const STATUS_REMOTE_NOT_LISTENING: NTSTATUS = 0xC00000BC; +pub const STATUS_DUPLICATE_NAME: NTSTATUS = 0xC00000BD; +pub const STATUS_BAD_NETWORK_PATH: NTSTATUS = 0xC00000BE; +pub const STATUS_NETWORK_BUSY: NTSTATUS = 0xC00000BF; +pub const STATUS_DEVICE_DOES_NOT_EXIST: NTSTATUS = 0xC00000C0; +pub const STATUS_TOO_MANY_COMMANDS: NTSTATUS = 0xC00000C1; +pub const STATUS_ADAPTER_HARDWARE_ERROR: NTSTATUS = 0xC00000C2; +pub const STATUS_INVALID_NETWORK_RESPONSE: NTSTATUS = 0xC00000C3; +pub const STATUS_UNEXPECTED_NETWORK_ERROR: NTSTATUS = 0xC00000C4; +pub const STATUS_BAD_REMOTE_ADAPTER: NTSTATUS = 0xC00000C5; +pub const STATUS_PRINT_QUEUE_FULL: NTSTATUS = 0xC00000C6; +pub const STATUS_NO_SPOOL_SPACE: NTSTATUS = 0xC00000C7; +pub const STATUS_PRINT_CANCELLED: NTSTATUS = 0xC00000C8; +pub const STATUS_NETWORK_NAME_DELETED: NTSTATUS = 0xC00000C9; +pub const STATUS_NETWORK_ACCESS_DENIED: NTSTATUS = 0xC00000CA; +pub const STATUS_BAD_DEVICE_TYPE: NTSTATUS = 0xC00000CB; +pub const STATUS_BAD_NETWORK_NAME: NTSTATUS = 0xC00000CC; +pub const STATUS_TOO_MANY_NAMES: NTSTATUS = 0xC00000CD; +pub const STATUS_TOO_MANY_SESSIONS: NTSTATUS = 0xC00000CE; +pub const STATUS_SHARING_PAUSED: NTSTATUS = 0xC00000CF; +pub const STATUS_REQUEST_NOT_ACCEPTED: NTSTATUS = 0xC00000D0; +pub const STATUS_REDIRECTOR_PAUSED: NTSTATUS = 0xC00000D1; +pub const STATUS_NET_WRITE_FAULT: NTSTATUS = 0xC00000D2; +pub const STATUS_PROFILING_AT_LIMIT: NTSTATUS = 0xC00000D3; +pub const STATUS_NOT_SAME_DEVICE: NTSTATUS = 0xC00000D4; +pub const STATUS_FILE_RENAMED: NTSTATUS = 0xC00000D5; +pub const STATUS_VIRTUAL_CIRCUIT_CLOSED: NTSTATUS = 0xC00000D6; +pub const STATUS_NO_SECURITY_ON_OBJECT: NTSTATUS = 0xC00000D7; +pub const STATUS_CANT_WAIT: NTSTATUS = 0xC00000D8; +pub const STATUS_PIPE_EMPTY: NTSTATUS = 0xC00000D9; +pub const STATUS_CANT_ACCESS_DOMAIN_INFO: NTSTATUS = 0xC00000DA; +pub const STATUS_CANT_TERMINATE_SELF: NTSTATUS = 0xC00000DB; +pub const STATUS_INVALID_SERVER_STATE: NTSTATUS = 0xC00000DC; +pub const STATUS_INVALID_DOMAIN_STATE: NTSTATUS = 0xC00000DD; +pub const STATUS_INVALID_DOMAIN_ROLE: NTSTATUS = 0xC00000DE; +pub const STATUS_NO_SUCH_DOMAIN: NTSTATUS = 0xC00000DF; +pub const STATUS_DOMAIN_EXISTS: NTSTATUS = 0xC00000E0; +pub const STATUS_DOMAIN_LIMIT_EXCEEDED: NTSTATUS = 0xC00000E1; +pub const STATUS_OPLOCK_NOT_GRANTED: NTSTATUS = 0xC00000E2; +pub const STATUS_INVALID_OPLOCK_PROTOCOL: NTSTATUS = 0xC00000E3; +pub const STATUS_INTERNAL_DB_CORRUPTION: NTSTATUS = 0xC00000E4; +pub const STATUS_INTERNAL_ERROR: NTSTATUS = 0xC00000E5; +pub const STATUS_GENERIC_NOT_MAPPED: NTSTATUS = 0xC00000E6; +pub const STATUS_BAD_DESCRIPTOR_FORMAT: NTSTATUS = 0xC00000E7; +pub const STATUS_INVALID_USER_BUFFER: NTSTATUS = 0xC00000E8; +pub const STATUS_UNEXPECTED_IO_ERROR: NTSTATUS = 0xC00000E9; +pub const STATUS_UNEXPECTED_MM_CREATE_ERR: NTSTATUS = 0xC00000EA; +pub const STATUS_UNEXPECTED_MM_MAP_ERROR: NTSTATUS = 0xC00000EB; +pub const STATUS_UNEXPECTED_MM_EXTEND_ERR: NTSTATUS = 0xC00000EC; +pub const STATUS_NOT_LOGON_PROCESS: NTSTATUS = 0xC00000ED; +pub const STATUS_LOGON_SESSION_EXISTS: NTSTATUS = 0xC00000EE; +pub const STATUS_INVALID_PARAMETER_1: NTSTATUS = 0xC00000EF; +pub const STATUS_INVALID_PARAMETER_2: NTSTATUS = 0xC00000F0; +pub const STATUS_INVALID_PARAMETER_3: NTSTATUS = 0xC00000F1; +pub const STATUS_INVALID_PARAMETER_4: NTSTATUS = 0xC00000F2; +pub const STATUS_INVALID_PARAMETER_5: NTSTATUS = 0xC00000F3; +pub const STATUS_INVALID_PARAMETER_6: NTSTATUS = 0xC00000F4; +pub const STATUS_INVALID_PARAMETER_7: NTSTATUS = 0xC00000F5; +pub const STATUS_INVALID_PARAMETER_8: NTSTATUS = 0xC00000F6; +pub const STATUS_INVALID_PARAMETER_9: NTSTATUS = 0xC00000F7; +pub const STATUS_INVALID_PARAMETER_10: NTSTATUS = 0xC00000F8; +pub const STATUS_INVALID_PARAMETER_11: NTSTATUS = 0xC00000F9; +pub const STATUS_INVALID_PARAMETER_12: NTSTATUS = 0xC00000FA; +pub const STATUS_REDIRECTOR_NOT_STARTED: NTSTATUS = 0xC00000FB; +pub const STATUS_REDIRECTOR_STARTED: NTSTATUS = 0xC00000FC; +pub const STATUS_STACK_OVERFLOW: NTSTATUS = 0xC00000FD; +pub const STATUS_NO_SUCH_PACKAGE: NTSTATUS = 0xC00000FE; +pub const STATUS_BAD_FUNCTION_TABLE: NTSTATUS = 0xC00000FF; +pub const STATUS_VARIABLE_NOT_FOUND: NTSTATUS = 0xC0000100; +pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101; +pub const STATUS_FILE_CORRUPT_ERROR: NTSTATUS = 0xC0000102; +pub const STATUS_NOT_A_DIRECTORY: NTSTATUS = 0xC0000103; +pub const STATUS_BAD_LOGON_SESSION_STATE: NTSTATUS = 0xC0000104; +pub const STATUS_LOGON_SESSION_COLLISION: NTSTATUS = 0xC0000105; +pub const STATUS_NAME_TOO_LONG: NTSTATUS = 0xC0000106; +pub const STATUS_FILES_OPEN: NTSTATUS = 0xC0000107; +pub const STATUS_CONNECTION_IN_USE: NTSTATUS = 0xC0000108; +pub const STATUS_MESSAGE_NOT_FOUND: NTSTATUS = 0xC0000109; +pub const STATUS_PROCESS_IS_TERMINATING: NTSTATUS = 0xC000010A; +pub const STATUS_INVALID_LOGON_TYPE: NTSTATUS = 0xC000010B; +pub const STATUS_NO_GUID_TRANSLATION: NTSTATUS = 0xC000010C; +pub const STATUS_CANNOT_IMPERSONATE: NTSTATUS = 0xC000010D; +pub const STATUS_IMAGE_ALREADY_LOADED: NTSTATUS = 0xC000010E; +pub const STATUS_ABIOS_NOT_PRESENT: NTSTATUS = 0xC000010F; +pub const STATUS_ABIOS_LID_NOT_EXIST: NTSTATUS = 0xC0000110; +pub const STATUS_ABIOS_LID_ALREADY_OWNED: NTSTATUS = 0xC0000111; +pub const STATUS_ABIOS_NOT_LID_OWNER: NTSTATUS = 0xC0000112; +pub const STATUS_ABIOS_INVALID_COMMAND: NTSTATUS = 0xC0000113; +pub const STATUS_ABIOS_INVALID_LID: NTSTATUS = 0xC0000114; +pub const STATUS_ABIOS_SELECTOR_NOT_AVAILABLE: NTSTATUS = 0xC0000115; +pub const STATUS_ABIOS_INVALID_SELECTOR: NTSTATUS = 0xC0000116; +pub const STATUS_NO_LDT: NTSTATUS = 0xC0000117; +pub const STATUS_INVALID_LDT_SIZE: NTSTATUS = 0xC0000118; +pub const STATUS_INVALID_LDT_OFFSET: NTSTATUS = 0xC0000119; +pub const STATUS_INVALID_LDT_DESCRIPTOR: NTSTATUS = 0xC000011A; +pub const STATUS_INVALID_IMAGE_NE_FORMAT: NTSTATUS = 0xC000011B; +pub const STATUS_RXACT_INVALID_STATE: NTSTATUS = 0xC000011C; +pub const STATUS_RXACT_COMMIT_FAILURE: NTSTATUS = 0xC000011D; +pub const STATUS_MAPPED_FILE_SIZE_ZERO: NTSTATUS = 0xC000011E; +pub const STATUS_TOO_MANY_OPENED_FILES: NTSTATUS = 0xC000011F; +pub const STATUS_CANCELLED: NTSTATUS = 0xC0000120; +pub const STATUS_CANNOT_DELETE: NTSTATUS = 0xC0000121; +pub const STATUS_INVALID_COMPUTER_NAME: NTSTATUS = 0xC0000122; +pub const STATUS_FILE_DELETED: NTSTATUS = 0xC0000123; +pub const STATUS_SPECIAL_ACCOUNT: NTSTATUS = 0xC0000124; +pub const STATUS_SPECIAL_GROUP: NTSTATUS = 0xC0000125; +pub const STATUS_SPECIAL_USER: NTSTATUS = 0xC0000126; +pub const STATUS_MEMBERS_PRIMARY_GROUP: NTSTATUS = 0xC0000127; +pub const STATUS_FILE_CLOSED: NTSTATUS = 0xC0000128; +pub const STATUS_TOO_MANY_THREADS: NTSTATUS = 0xC0000129; +pub const STATUS_THREAD_NOT_IN_PROCESS: NTSTATUS = 0xC000012A; +pub const STATUS_TOKEN_ALREADY_IN_USE: NTSTATUS = 0xC000012B; +pub const STATUS_PAGEFILE_QUOTA_EXCEEDED: NTSTATUS = 0xC000012C; +pub const STATUS_COMMITMENT_LIMIT: NTSTATUS = 0xC000012D; +pub const STATUS_INVALID_IMAGE_LE_FORMAT: NTSTATUS = 0xC000012E; +pub const STATUS_INVALID_IMAGE_NOT_MZ: NTSTATUS = 0xC000012F; +pub const STATUS_INVALID_IMAGE_PROTECT: NTSTATUS = 0xC0000130; +pub const STATUS_INVALID_IMAGE_WIN_16: NTSTATUS = 0xC0000131; +pub const STATUS_LOGON_SERVER_CONFLICT: NTSTATUS = 0xC0000132; +pub const STATUS_TIME_DIFFERENCE_AT_DC: NTSTATUS = 0xC0000133; +pub const STATUS_SYNCHRONIZATION_REQUIRED: NTSTATUS = 0xC0000134; +pub const STATUS_DLL_NOT_FOUND: NTSTATUS = 0xC0000135; +pub const STATUS_OPEN_FAILED: NTSTATUS = 0xC0000136; +pub const STATUS_IO_PRIVILEGE_FAILED: NTSTATUS = 0xC0000137; +pub const STATUS_ORDINAL_NOT_FOUND: NTSTATUS = 0xC0000138; +pub const STATUS_ENTRYPOINT_NOT_FOUND: NTSTATUS = 0xC0000139; +pub const STATUS_CONTROL_C_EXIT: NTSTATUS = 0xC000013A; +pub const STATUS_LOCAL_DISCONNECT: NTSTATUS = 0xC000013B; +pub const STATUS_REMOTE_DISCONNECT: NTSTATUS = 0xC000013C; +pub const STATUS_REMOTE_RESOURCES: NTSTATUS = 0xC000013D; +pub const STATUS_LINK_FAILED: NTSTATUS = 0xC000013E; +pub const STATUS_LINK_TIMEOUT: NTSTATUS = 0xC000013F; +pub const STATUS_INVALID_CONNECTION: NTSTATUS = 0xC0000140; +pub const STATUS_INVALID_ADDRESS: NTSTATUS = 0xC0000141; +pub const STATUS_DLL_INIT_FAILED: NTSTATUS = 0xC0000142; +pub const STATUS_MISSING_SYSTEMFILE: NTSTATUS = 0xC0000143; +pub const STATUS_UNHANDLED_EXCEPTION: NTSTATUS = 0xC0000144; +pub const STATUS_APP_INIT_FAILURE: NTSTATUS = 0xC0000145; +pub const STATUS_PAGEFILE_CREATE_FAILED: NTSTATUS = 0xC0000146; +pub const STATUS_NO_PAGEFILE: NTSTATUS = 0xC0000147; +pub const STATUS_INVALID_LEVEL: NTSTATUS = 0xC0000148; +pub const STATUS_WRONG_PASSWORD_CORE: NTSTATUS = 0xC0000149; +pub const STATUS_ILLEGAL_FLOAT_CONTEXT: NTSTATUS = 0xC000014A; +pub const STATUS_PIPE_BROKEN: NTSTATUS = 0xC000014B; +pub const STATUS_REGISTRY_CORRUPT: NTSTATUS = 0xC000014C; +pub const STATUS_REGISTRY_IO_FAILED: NTSTATUS = 0xC000014D; +pub const STATUS_NO_EVENT_PAIR: NTSTATUS = 0xC000014E; +pub const STATUS_UNRECOGNIZED_VOLUME: NTSTATUS = 0xC000014F; +pub const STATUS_SERIAL_NO_DEVICE_INITED: NTSTATUS = 0xC0000150; +pub const STATUS_NO_SUCH_ALIAS: NTSTATUS = 0xC0000151; +pub const STATUS_MEMBER_NOT_IN_ALIAS: NTSTATUS = 0xC0000152; +pub const STATUS_MEMBER_IN_ALIAS: NTSTATUS = 0xC0000153; +pub const STATUS_ALIAS_EXISTS: NTSTATUS = 0xC0000154; +pub const STATUS_LOGON_NOT_GRANTED: NTSTATUS = 0xC0000155; +pub const STATUS_TOO_MANY_SECRETS: NTSTATUS = 0xC0000156; +pub const STATUS_SECRET_TOO_LONG: NTSTATUS = 0xC0000157; +pub const STATUS_INTERNAL_DB_ERROR: NTSTATUS = 0xC0000158; +pub const STATUS_FULLSCREEN_MODE: NTSTATUS = 0xC0000159; +pub const STATUS_TOO_MANY_CONTEXT_IDS: NTSTATUS = 0xC000015A; +pub const STATUS_LOGON_TYPE_NOT_GRANTED: NTSTATUS = 0xC000015B; +pub const STATUS_NOT_REGISTRY_FILE: NTSTATUS = 0xC000015C; +pub const STATUS_NT_CROSS_ENCRYPTION_REQUIRED: NTSTATUS = 0xC000015D; +pub const STATUS_DOMAIN_CTRLR_CONFIG_ERROR: NTSTATUS = 0xC000015E; +pub const STATUS_FT_MISSING_MEMBER: NTSTATUS = 0xC000015F; +pub const STATUS_ILL_FORMED_SERVICE_ENTRY: NTSTATUS = 0xC0000160; +pub const STATUS_ILLEGAL_CHARACTER: NTSTATUS = 0xC0000161; +pub const STATUS_UNMAPPABLE_CHARACTER: NTSTATUS = 0xC0000162; +pub const STATUS_UNDEFINED_CHARACTER: NTSTATUS = 0xC0000163; +pub const STATUS_FLOPPY_VOLUME: NTSTATUS = 0xC0000164; +pub const STATUS_FLOPPY_ID_MARK_NOT_FOUND: NTSTATUS = 0xC0000165; +pub const STATUS_FLOPPY_WRONG_CYLINDER: NTSTATUS = 0xC0000166; +pub const STATUS_FLOPPY_UNKNOWN_ERROR: NTSTATUS = 0xC0000167; +pub const STATUS_FLOPPY_BAD_REGISTERS: NTSTATUS = 0xC0000168; +pub const STATUS_DISK_RECALIBRATE_FAILED: NTSTATUS = 0xC0000169; +pub const STATUS_DISK_OPERATION_FAILED: NTSTATUS = 0xC000016A; +pub const STATUS_DISK_RESET_FAILED: NTSTATUS = 0xC000016B; +pub const STATUS_SHARED_IRQ_BUSY: NTSTATUS = 0xC000016C; +pub const STATUS_FT_ORPHANING: NTSTATUS = 0xC000016D; +pub const STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT: NTSTATUS = 0xC000016E; +pub const STATUS_PARTITION_FAILURE: NTSTATUS = 0xC0000172; +pub const STATUS_INVALID_BLOCK_LENGTH: NTSTATUS = 0xC0000173; +pub const STATUS_DEVICE_NOT_PARTITIONED: NTSTATUS = 0xC0000174; +pub const STATUS_UNABLE_TO_LOCK_MEDIA: NTSTATUS = 0xC0000175; +pub const STATUS_UNABLE_TO_UNLOAD_MEDIA: NTSTATUS = 0xC0000176; +pub const STATUS_EOM_OVERFLOW: NTSTATUS = 0xC0000177; +pub const STATUS_NO_MEDIA: NTSTATUS = 0xC0000178; +pub const STATUS_NO_SUCH_MEMBER: NTSTATUS = 0xC000017A; +pub const STATUS_INVALID_MEMBER: NTSTATUS = 0xC000017B; +pub const STATUS_KEY_DELETED: NTSTATUS = 0xC000017C; +pub const STATUS_NO_LOG_SPACE: NTSTATUS = 0xC000017D; +pub const STATUS_TOO_MANY_SIDS: NTSTATUS = 0xC000017E; +pub const STATUS_LM_CROSS_ENCRYPTION_REQUIRED: NTSTATUS = 0xC000017F; +pub const STATUS_KEY_HAS_CHILDREN: NTSTATUS = 0xC0000180; +pub const STATUS_CHILD_MUST_BE_VOLATILE: NTSTATUS = 0xC0000181; +pub const STATUS_DEVICE_CONFIGURATION_ERROR: NTSTATUS = 0xC0000182; +pub const STATUS_DRIVER_INTERNAL_ERROR: NTSTATUS = 0xC0000183; +pub const STATUS_INVALID_DEVICE_STATE: NTSTATUS = 0xC0000184; +pub const STATUS_IO_DEVICE_ERROR: NTSTATUS = 0xC0000185; +pub const STATUS_DEVICE_PROTOCOL_ERROR: NTSTATUS = 0xC0000186; +pub const STATUS_BACKUP_CONTROLLER: NTSTATUS = 0xC0000187; +pub const STATUS_LOG_FILE_FULL: NTSTATUS = 0xC0000188; +pub const STATUS_TOO_LATE: NTSTATUS = 0xC0000189; +pub const STATUS_NO_TRUST_LSA_SECRET: NTSTATUS = 0xC000018A; +pub const STATUS_NO_TRUST_SAM_ACCOUNT: NTSTATUS = 0xC000018B; +pub const STATUS_TRUSTED_DOMAIN_FAILURE: NTSTATUS = 0xC000018C; +pub const STATUS_TRUSTED_RELATIONSHIP_FAILURE: NTSTATUS = 0xC000018D; +pub const STATUS_EVENTLOG_FILE_CORRUPT: NTSTATUS = 0xC000018E; +pub const STATUS_EVENTLOG_CANT_START: NTSTATUS = 0xC000018F; +pub const STATUS_TRUST_FAILURE: NTSTATUS = 0xC0000190; +pub const STATUS_MUTANT_LIMIT_EXCEEDED: NTSTATUS = 0xC0000191; +pub const STATUS_NETLOGON_NOT_STARTED: NTSTATUS = 0xC0000192; +pub const STATUS_ACCOUNT_EXPIRED: NTSTATUS = 0xC0000193; +pub const STATUS_POSSIBLE_DEADLOCK: NTSTATUS = 0xC0000194; +pub const STATUS_NETWORK_CREDENTIAL_CONFLICT: NTSTATUS = 0xC0000195; +pub const STATUS_REMOTE_SESSION_LIMIT: NTSTATUS = 0xC0000196; +pub const STATUS_EVENTLOG_FILE_CHANGED: NTSTATUS = 0xC0000197; +pub const STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: NTSTATUS = 0xC0000198; +pub const STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT: NTSTATUS = 0xC0000199; +pub const STATUS_NOLOGON_SERVER_TRUST_ACCOUNT: NTSTATUS = 0xC000019A; +pub const STATUS_DOMAIN_TRUST_INCONSISTENT: NTSTATUS = 0xC000019B; +pub const STATUS_FS_DRIVER_REQUIRED: NTSTATUS = 0xC000019C; +pub const STATUS_IMAGE_ALREADY_LOADED_AS_DLL: NTSTATUS = 0xC000019D; +pub const STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING: NTSTATUS + = 0xC000019E; +pub const STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME: NTSTATUS = 0xC000019F; +pub const STATUS_SECURITY_STREAM_IS_INCONSISTENT: NTSTATUS = 0xC00001A0; +pub const STATUS_INVALID_LOCK_RANGE: NTSTATUS = 0xC00001A1; +pub const STATUS_INVALID_ACE_CONDITION: NTSTATUS = 0xC00001A2; +pub const STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: NTSTATUS = 0xC00001A3; +pub const STATUS_NOTIFICATION_GUID_ALREADY_DEFINED: NTSTATUS = 0xC00001A4; +pub const STATUS_INVALID_EXCEPTION_HANDLER: NTSTATUS = 0xC00001A5; +pub const STATUS_DUPLICATE_PRIVILEGES: NTSTATUS = 0xC00001A6; +pub const STATUS_NOT_ALLOWED_ON_SYSTEM_FILE: NTSTATUS = 0xC00001A7; +pub const STATUS_REPAIR_NEEDED: NTSTATUS = 0xC00001A8; +pub const STATUS_QUOTA_NOT_ENABLED: NTSTATUS = 0xC00001A9; +pub const STATUS_NO_APPLICATION_PACKAGE: NTSTATUS = 0xC00001AA; +pub const STATUS_FILE_METADATA_OPTIMIZATION_IN_PROGRESS: NTSTATUS = 0xC00001AB; +pub const STATUS_NOT_SAME_OBJECT: NTSTATUS = 0xC00001AC; +pub const STATUS_FATAL_MEMORY_EXHAUSTION: NTSTATUS = 0xC00001AD; +pub const STATUS_ERROR_PROCESS_NOT_IN_JOB: NTSTATUS = 0xC00001AE; +pub const STATUS_CPU_SET_INVALID: NTSTATUS = 0xC00001AF; +pub const STATUS_NETWORK_OPEN_RESTRICTION: NTSTATUS = 0xC0000201; +pub const STATUS_NO_USER_SESSION_KEY: NTSTATUS = 0xC0000202; +pub const STATUS_USER_SESSION_DELETED: NTSTATUS = 0xC0000203; +pub const STATUS_RESOURCE_LANG_NOT_FOUND: NTSTATUS = 0xC0000204; +pub const STATUS_INSUFF_SERVER_RESOURCES: NTSTATUS = 0xC0000205; +pub const STATUS_INVALID_BUFFER_SIZE: NTSTATUS = 0xC0000206; +pub const STATUS_INVALID_ADDRESS_COMPONENT: NTSTATUS = 0xC0000207; +pub const STATUS_INVALID_ADDRESS_WILDCARD: NTSTATUS = 0xC0000208; +pub const STATUS_TOO_MANY_ADDRESSES: NTSTATUS = 0xC0000209; +pub const STATUS_ADDRESS_ALREADY_EXISTS: NTSTATUS = 0xC000020A; +pub const STATUS_ADDRESS_CLOSED: NTSTATUS = 0xC000020B; +pub const STATUS_CONNECTION_DISCONNECTED: NTSTATUS = 0xC000020C; +pub const STATUS_CONNECTION_RESET: NTSTATUS = 0xC000020D; +pub const STATUS_TOO_MANY_NODES: NTSTATUS = 0xC000020E; +pub const STATUS_TRANSACTION_ABORTED: NTSTATUS = 0xC000020F; +pub const STATUS_TRANSACTION_TIMED_OUT: NTSTATUS = 0xC0000210; +pub const STATUS_TRANSACTION_NO_RELEASE: NTSTATUS = 0xC0000211; +pub const STATUS_TRANSACTION_NO_MATCH: NTSTATUS = 0xC0000212; +pub const STATUS_TRANSACTION_RESPONDED: NTSTATUS = 0xC0000213; +pub const STATUS_TRANSACTION_INVALID_ID: NTSTATUS = 0xC0000214; +pub const STATUS_TRANSACTION_INVALID_TYPE: NTSTATUS = 0xC0000215; +pub const STATUS_NOT_SERVER_SESSION: NTSTATUS = 0xC0000216; +pub const STATUS_NOT_CLIENT_SESSION: NTSTATUS = 0xC0000217; +pub const STATUS_CANNOT_LOAD_REGISTRY_FILE: NTSTATUS = 0xC0000218; +pub const STATUS_DEBUG_ATTACH_FAILED: NTSTATUS = 0xC0000219; +pub const STATUS_SYSTEM_PROCESS_TERMINATED: NTSTATUS = 0xC000021A; +pub const STATUS_DATA_NOT_ACCEPTED: NTSTATUS = 0xC000021B; +pub const STATUS_NO_BROWSER_SERVERS_FOUND: NTSTATUS = 0xC000021C; +pub const STATUS_VDM_HARD_ERROR: NTSTATUS = 0xC000021D; +pub const STATUS_DRIVER_CANCEL_TIMEOUT: NTSTATUS = 0xC000021E; +pub const STATUS_REPLY_MESSAGE_MISMATCH: NTSTATUS = 0xC000021F; +pub const STATUS_MAPPED_ALIGNMENT: NTSTATUS = 0xC0000220; +pub const STATUS_IMAGE_CHECKSUM_MISMATCH: NTSTATUS = 0xC0000221; +pub const STATUS_LOST_WRITEBEHIND_DATA: NTSTATUS = 0xC0000222; +pub const STATUS_CLIENT_SERVER_PARAMETERS_INVALID: NTSTATUS = 0xC0000223; +pub const STATUS_PASSWORD_MUST_CHANGE: NTSTATUS = 0xC0000224; +pub const STATUS_NOT_FOUND: NTSTATUS = 0xC0000225; +pub const STATUS_NOT_TINY_STREAM: NTSTATUS = 0xC0000226; +pub const STATUS_RECOVERY_FAILURE: NTSTATUS = 0xC0000227; +pub const STATUS_STACK_OVERFLOW_READ: NTSTATUS = 0xC0000228; +pub const STATUS_FAIL_CHECK: NTSTATUS = 0xC0000229; +pub const STATUS_DUPLICATE_OBJECTID: NTSTATUS = 0xC000022A; +pub const STATUS_OBJECTID_EXISTS: NTSTATUS = 0xC000022B; +pub const STATUS_CONVERT_TO_LARGE: NTSTATUS = 0xC000022C; +pub const STATUS_RETRY: NTSTATUS = 0xC000022D; +pub const STATUS_FOUND_OUT_OF_SCOPE: NTSTATUS = 0xC000022E; +pub const STATUS_ALLOCATE_BUCKET: NTSTATUS = 0xC000022F; +pub const STATUS_PROPSET_NOT_FOUND: NTSTATUS = 0xC0000230; +pub const STATUS_MARSHALL_OVERFLOW: NTSTATUS = 0xC0000231; +pub const STATUS_INVALID_VARIANT: NTSTATUS = 0xC0000232; +pub const STATUS_DOMAIN_CONTROLLER_NOT_FOUND: NTSTATUS = 0xC0000233; +pub const STATUS_ACCOUNT_LOCKED_OUT: NTSTATUS = 0xC0000234; +pub const STATUS_HANDLE_NOT_CLOSABLE: NTSTATUS = 0xC0000235; +pub const STATUS_CONNECTION_REFUSED: NTSTATUS = 0xC0000236; +pub const STATUS_GRACEFUL_DISCONNECT: NTSTATUS = 0xC0000237; +pub const STATUS_ADDRESS_ALREADY_ASSOCIATED: NTSTATUS = 0xC0000238; +pub const STATUS_ADDRESS_NOT_ASSOCIATED: NTSTATUS = 0xC0000239; +pub const STATUS_CONNECTION_INVALID: NTSTATUS = 0xC000023A; +pub const STATUS_CONNECTION_ACTIVE: NTSTATUS = 0xC000023B; +pub const STATUS_NETWORK_UNREACHABLE: NTSTATUS = 0xC000023C; +pub const STATUS_HOST_UNREACHABLE: NTSTATUS = 0xC000023D; +pub const STATUS_PROTOCOL_UNREACHABLE: NTSTATUS = 0xC000023E; +pub const STATUS_PORT_UNREACHABLE: NTSTATUS = 0xC000023F; +pub const STATUS_REQUEST_ABORTED: NTSTATUS = 0xC0000240; +pub const STATUS_CONNECTION_ABORTED: NTSTATUS = 0xC0000241; +pub const STATUS_BAD_COMPRESSION_BUFFER: NTSTATUS = 0xC0000242; +pub const STATUS_USER_MAPPED_FILE: NTSTATUS = 0xC0000243; +pub const STATUS_AUDIT_FAILED: NTSTATUS = 0xC0000244; +pub const STATUS_TIMER_RESOLUTION_NOT_SET: NTSTATUS = 0xC0000245; +pub const STATUS_CONNECTION_COUNT_LIMIT: NTSTATUS = 0xC0000246; +pub const STATUS_LOGIN_TIME_RESTRICTION: NTSTATUS = 0xC0000247; +pub const STATUS_LOGIN_WKSTA_RESTRICTION: NTSTATUS = 0xC0000248; +pub const STATUS_IMAGE_MP_UP_MISMATCH: NTSTATUS = 0xC0000249; +pub const STATUS_INSUFFICIENT_LOGON_INFO: NTSTATUS = 0xC0000250; +pub const STATUS_BAD_DLL_ENTRYPOINT: NTSTATUS = 0xC0000251; +pub const STATUS_BAD_SERVICE_ENTRYPOINT: NTSTATUS = 0xC0000252; +pub const STATUS_LPC_REPLY_LOST: NTSTATUS = 0xC0000253; +pub const STATUS_IP_ADDRESS_CONFLICT1: NTSTATUS = 0xC0000254; +pub const STATUS_IP_ADDRESS_CONFLICT2: NTSTATUS = 0xC0000255; +pub const STATUS_REGISTRY_QUOTA_LIMIT: NTSTATUS = 0xC0000256; +pub const STATUS_PATH_NOT_COVERED: NTSTATUS = 0xC0000257; +pub const STATUS_NO_CALLBACK_ACTIVE: NTSTATUS = 0xC0000258; +pub const STATUS_LICENSE_QUOTA_EXCEEDED: NTSTATUS = 0xC0000259; +pub const STATUS_PWD_TOO_SHORT: NTSTATUS = 0xC000025A; +pub const STATUS_PWD_TOO_RECENT: NTSTATUS = 0xC000025B; +pub const STATUS_PWD_HISTORY_CONFLICT: NTSTATUS = 0xC000025C; +pub const STATUS_PLUGPLAY_NO_DEVICE: NTSTATUS = 0xC000025E; +pub const STATUS_UNSUPPORTED_COMPRESSION: NTSTATUS = 0xC000025F; +pub const STATUS_INVALID_HW_PROFILE: NTSTATUS = 0xC0000260; +pub const STATUS_INVALID_PLUGPLAY_DEVICE_PATH: NTSTATUS = 0xC0000261; +pub const STATUS_DRIVER_ORDINAL_NOT_FOUND: NTSTATUS = 0xC0000262; +pub const STATUS_DRIVER_ENTRYPOINT_NOT_FOUND: NTSTATUS = 0xC0000263; +pub const STATUS_RESOURCE_NOT_OWNED: NTSTATUS = 0xC0000264; +pub const STATUS_TOO_MANY_LINKS: NTSTATUS = 0xC0000265; +pub const STATUS_QUOTA_LIST_INCONSISTENT: NTSTATUS = 0xC0000266; +pub const STATUS_FILE_IS_OFFLINE: NTSTATUS = 0xC0000267; +pub const STATUS_EVALUATION_EXPIRATION: NTSTATUS = 0xC0000268; +pub const STATUS_ILLEGAL_DLL_RELOCATION: NTSTATUS = 0xC0000269; +pub const STATUS_LICENSE_VIOLATION: NTSTATUS = 0xC000026A; +pub const STATUS_DLL_INIT_FAILED_LOGOFF: NTSTATUS = 0xC000026B; +pub const STATUS_DRIVER_UNABLE_TO_LOAD: NTSTATUS = 0xC000026C; +pub const STATUS_DFS_UNAVAILABLE: NTSTATUS = 0xC000026D; +pub const STATUS_VOLUME_DISMOUNTED: NTSTATUS = 0xC000026E; +pub const STATUS_WX86_INTERNAL_ERROR: NTSTATUS = 0xC000026F; +pub const STATUS_WX86_FLOAT_STACK_CHECK: NTSTATUS = 0xC0000270; +pub const STATUS_VALIDATE_CONTINUE: NTSTATUS = 0xC0000271; +pub const STATUS_NO_MATCH: NTSTATUS = 0xC0000272; +pub const STATUS_NO_MORE_MATCHES: NTSTATUS = 0xC0000273; +pub const STATUS_NOT_A_REPARSE_POINT: NTSTATUS = 0xC0000275; +pub const STATUS_IO_REPARSE_TAG_INVALID: NTSTATUS = 0xC0000276; +pub const STATUS_IO_REPARSE_TAG_MISMATCH: NTSTATUS = 0xC0000277; +pub const STATUS_IO_REPARSE_DATA_INVALID: NTSTATUS = 0xC0000278; +pub const STATUS_IO_REPARSE_TAG_NOT_HANDLED: NTSTATUS = 0xC0000279; +pub const STATUS_PWD_TOO_LONG: NTSTATUS = 0xC000027A; +pub const STATUS_STOWED_EXCEPTION: NTSTATUS = 0xC000027B; +pub const STATUS_REPARSE_POINT_NOT_RESOLVED: NTSTATUS = 0xC0000280; +pub const STATUS_DIRECTORY_IS_A_REPARSE_POINT: NTSTATUS = 0xC0000281; +pub const STATUS_RANGE_LIST_CONFLICT: NTSTATUS = 0xC0000282; +pub const STATUS_SOURCE_ELEMENT_EMPTY: NTSTATUS = 0xC0000283; +pub const STATUS_DESTINATION_ELEMENT_FULL: NTSTATUS = 0xC0000284; +pub const STATUS_ILLEGAL_ELEMENT_ADDRESS: NTSTATUS = 0xC0000285; +pub const STATUS_MAGAZINE_NOT_PRESENT: NTSTATUS = 0xC0000286; +pub const STATUS_REINITIALIZATION_NEEDED: NTSTATUS = 0xC0000287; +pub const STATUS_DEVICE_REQUIRES_CLEANING: NTSTATUS = 0x80000288; +pub const STATUS_DEVICE_DOOR_OPEN: NTSTATUS = 0x80000289; +pub const STATUS_ENCRYPTION_FAILED: NTSTATUS = 0xC000028A; +pub const STATUS_DECRYPTION_FAILED: NTSTATUS = 0xC000028B; +pub const STATUS_RANGE_NOT_FOUND: NTSTATUS = 0xC000028C; +pub const STATUS_NO_RECOVERY_POLICY: NTSTATUS = 0xC000028D; +pub const STATUS_NO_EFS: NTSTATUS = 0xC000028E; +pub const STATUS_WRONG_EFS: NTSTATUS = 0xC000028F; +pub const STATUS_NO_USER_KEYS: NTSTATUS = 0xC0000290; +pub const STATUS_FILE_NOT_ENCRYPTED: NTSTATUS = 0xC0000291; +pub const STATUS_NOT_EXPORT_FORMAT: NTSTATUS = 0xC0000292; +pub const STATUS_FILE_ENCRYPTED: NTSTATUS = 0xC0000293; +pub const STATUS_WAKE_SYSTEM: NTSTATUS = 0x40000294; +pub const STATUS_WMI_GUID_NOT_FOUND: NTSTATUS = 0xC0000295; +pub const STATUS_WMI_INSTANCE_NOT_FOUND: NTSTATUS = 0xC0000296; +pub const STATUS_WMI_ITEMID_NOT_FOUND: NTSTATUS = 0xC0000297; +pub const STATUS_WMI_TRY_AGAIN: NTSTATUS = 0xC0000298; +pub const STATUS_SHARED_POLICY: NTSTATUS = 0xC0000299; +pub const STATUS_POLICY_OBJECT_NOT_FOUND: NTSTATUS = 0xC000029A; +pub const STATUS_POLICY_ONLY_IN_DS: NTSTATUS = 0xC000029B; +pub const STATUS_VOLUME_NOT_UPGRADED: NTSTATUS = 0xC000029C; +pub const STATUS_REMOTE_STORAGE_NOT_ACTIVE: NTSTATUS = 0xC000029D; +pub const STATUS_REMOTE_STORAGE_MEDIA_ERROR: NTSTATUS = 0xC000029E; +pub const STATUS_NO_TRACKING_SERVICE: NTSTATUS = 0xC000029F; +pub const STATUS_SERVER_SID_MISMATCH: NTSTATUS = 0xC00002A0; +pub const STATUS_DS_NO_ATTRIBUTE_OR_VALUE: NTSTATUS = 0xC00002A1; +pub const STATUS_DS_INVALID_ATTRIBUTE_SYNTAX: NTSTATUS = 0xC00002A2; +pub const STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED: NTSTATUS = 0xC00002A3; +pub const STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS: NTSTATUS = 0xC00002A4; +pub const STATUS_DS_BUSY: NTSTATUS = 0xC00002A5; +pub const STATUS_DS_UNAVAILABLE: NTSTATUS = 0xC00002A6; +pub const STATUS_DS_NO_RIDS_ALLOCATED: NTSTATUS = 0xC00002A7; +pub const STATUS_DS_NO_MORE_RIDS: NTSTATUS = 0xC00002A8; +pub const STATUS_DS_INCORRECT_ROLE_OWNER: NTSTATUS = 0xC00002A9; +pub const STATUS_DS_RIDMGR_INIT_ERROR: NTSTATUS = 0xC00002AA; +pub const STATUS_DS_OBJ_CLASS_VIOLATION: NTSTATUS = 0xC00002AB; +pub const STATUS_DS_CANT_ON_NON_LEAF: NTSTATUS = 0xC00002AC; +pub const STATUS_DS_CANT_ON_RDN: NTSTATUS = 0xC00002AD; +pub const STATUS_DS_CANT_MOD_OBJ_CLASS: NTSTATUS = 0xC00002AE; +pub const STATUS_DS_CROSS_DOM_MOVE_FAILED: NTSTATUS = 0xC00002AF; +pub const STATUS_DS_GC_NOT_AVAILABLE: NTSTATUS = 0xC00002B0; +pub const STATUS_DIRECTORY_SERVICE_REQUIRED: NTSTATUS = 0xC00002B1; +pub const STATUS_REPARSE_ATTRIBUTE_CONFLICT: NTSTATUS = 0xC00002B2; +pub const STATUS_CANT_ENABLE_DENY_ONLY: NTSTATUS = 0xC00002B3; +pub const STATUS_FLOAT_MULTIPLE_FAULTS: NTSTATUS = 0xC00002B4; +pub const STATUS_FLOAT_MULTIPLE_TRAPS: NTSTATUS = 0xC00002B5; +pub const STATUS_DEVICE_REMOVED: NTSTATUS = 0xC00002B6; +pub const STATUS_JOURNAL_DELETE_IN_PROGRESS: NTSTATUS = 0xC00002B7; +pub const STATUS_JOURNAL_NOT_ACTIVE: NTSTATUS = 0xC00002B8; +pub const STATUS_NOINTERFACE: NTSTATUS = 0xC00002B9; +pub const STATUS_DS_RIDMGR_DISABLED: NTSTATUS = 0xC00002BA; +pub const STATUS_DS_ADMIN_LIMIT_EXCEEDED: NTSTATUS = 0xC00002C1; +pub const STATUS_DRIVER_FAILED_SLEEP: NTSTATUS = 0xC00002C2; +pub const STATUS_MUTUAL_AUTHENTICATION_FAILED: NTSTATUS = 0xC00002C3; +pub const STATUS_CORRUPT_SYSTEM_FILE: NTSTATUS = 0xC00002C4; +pub const STATUS_DATATYPE_MISALIGNMENT_ERROR: NTSTATUS = 0xC00002C5; +pub const STATUS_WMI_READ_ONLY: NTSTATUS = 0xC00002C6; +pub const STATUS_WMI_SET_FAILURE: NTSTATUS = 0xC00002C7; +pub const STATUS_COMMITMENT_MINIMUM: NTSTATUS = 0xC00002C8; +pub const STATUS_REG_NAT_CONSUMPTION: NTSTATUS = 0xC00002C9; +pub const STATUS_TRANSPORT_FULL: NTSTATUS = 0xC00002CA; +pub const STATUS_DS_SAM_INIT_FAILURE: NTSTATUS = 0xC00002CB; +pub const STATUS_ONLY_IF_CONNECTED: NTSTATUS = 0xC00002CC; +pub const STATUS_DS_SENSITIVE_GROUP_VIOLATION: NTSTATUS = 0xC00002CD; +pub const STATUS_PNP_RESTART_ENUMERATION: NTSTATUS = 0xC00002CE; +pub const STATUS_JOURNAL_ENTRY_DELETED: NTSTATUS = 0xC00002CF; +pub const STATUS_DS_CANT_MOD_PRIMARYGROUPID: NTSTATUS = 0xC00002D0; +pub const STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: NTSTATUS = 0xC00002D1; +pub const STATUS_PNP_REBOOT_REQUIRED: NTSTATUS = 0xC00002D2; +pub const STATUS_POWER_STATE_INVALID: NTSTATUS = 0xC00002D3; +pub const STATUS_DS_INVALID_GROUP_TYPE: NTSTATUS = 0xC00002D4; +pub const STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: NTSTATUS = 0xC00002D5; +pub const STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: NTSTATUS = 0xC00002D6; +pub const STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: NTSTATUS = 0xC00002D7; +pub const STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: NTSTATUS = 0xC00002D8; +pub const STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: NTSTATUS = 0xC00002D9; +pub const STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: NTSTATUS = 0xC00002DA; +pub const STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: NTSTATUS = 0xC00002DB; +pub const STATUS_DS_HAVE_PRIMARY_MEMBERS: NTSTATUS = 0xC00002DC; +pub const STATUS_WMI_NOT_SUPPORTED: NTSTATUS = 0xC00002DD; +pub const STATUS_INSUFFICIENT_POWER: NTSTATUS = 0xC00002DE; +pub const STATUS_SAM_NEED_BOOTKEY_PASSWORD: NTSTATUS = 0xC00002DF; +pub const STATUS_SAM_NEED_BOOTKEY_FLOPPY: NTSTATUS = 0xC00002E0; +pub const STATUS_DS_CANT_START: NTSTATUS = 0xC00002E1; +pub const STATUS_DS_INIT_FAILURE: NTSTATUS = 0xC00002E2; +pub const STATUS_SAM_INIT_FAILURE: NTSTATUS = 0xC00002E3; +pub const STATUS_DS_GC_REQUIRED: NTSTATUS = 0xC00002E4; +pub const STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: NTSTATUS = 0xC00002E5; +pub const STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS: NTSTATUS = 0xC00002E6; +pub const STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: NTSTATUS = 0xC00002E7; +pub const STATUS_MULTIPLE_FAULT_VIOLATION: NTSTATUS = 0xC00002E8; +pub const STATUS_CURRENT_DOMAIN_NOT_ALLOWED: NTSTATUS = 0xC00002E9; +pub const STATUS_CANNOT_MAKE: NTSTATUS = 0xC00002EA; +pub const STATUS_SYSTEM_SHUTDOWN: NTSTATUS = 0xC00002EB; +pub const STATUS_DS_INIT_FAILURE_CONSOLE: NTSTATUS = 0xC00002EC; +pub const STATUS_DS_SAM_INIT_FAILURE_CONSOLE: NTSTATUS = 0xC00002ED; +pub const STATUS_UNFINISHED_CONTEXT_DELETED: NTSTATUS = 0xC00002EE; +pub const STATUS_NO_TGT_REPLY: NTSTATUS = 0xC00002EF; +pub const STATUS_OBJECTID_NOT_FOUND: NTSTATUS = 0xC00002F0; +pub const STATUS_NO_IP_ADDRESSES: NTSTATUS = 0xC00002F1; +pub const STATUS_WRONG_CREDENTIAL_HANDLE: NTSTATUS = 0xC00002F2; +pub const STATUS_CRYPTO_SYSTEM_INVALID: NTSTATUS = 0xC00002F3; +pub const STATUS_MAX_REFERRALS_EXCEEDED: NTSTATUS = 0xC00002F4; +pub const STATUS_MUST_BE_KDC: NTSTATUS = 0xC00002F5; +pub const STATUS_STRONG_CRYPTO_NOT_SUPPORTED: NTSTATUS = 0xC00002F6; +pub const STATUS_TOO_MANY_PRINCIPALS: NTSTATUS = 0xC00002F7; +pub const STATUS_NO_PA_DATA: NTSTATUS = 0xC00002F8; +pub const STATUS_PKINIT_NAME_MISMATCH: NTSTATUS = 0xC00002F9; +pub const STATUS_SMARTCARD_LOGON_REQUIRED: NTSTATUS = 0xC00002FA; +pub const STATUS_KDC_INVALID_REQUEST: NTSTATUS = 0xC00002FB; +pub const STATUS_KDC_UNABLE_TO_REFER: NTSTATUS = 0xC00002FC; +pub const STATUS_KDC_UNKNOWN_ETYPE: NTSTATUS = 0xC00002FD; +pub const STATUS_SHUTDOWN_IN_PROGRESS: NTSTATUS = 0xC00002FE; +pub const STATUS_SERVER_SHUTDOWN_IN_PROGRESS: NTSTATUS = 0xC00002FF; +pub const STATUS_NOT_SUPPORTED_ON_SBS: NTSTATUS = 0xC0000300; +pub const STATUS_WMI_GUID_DISCONNECTED: NTSTATUS = 0xC0000301; +pub const STATUS_WMI_ALREADY_DISABLED: NTSTATUS = 0xC0000302; +pub const STATUS_WMI_ALREADY_ENABLED: NTSTATUS = 0xC0000303; +pub const STATUS_MFT_TOO_FRAGMENTED: NTSTATUS = 0xC0000304; +pub const STATUS_COPY_PROTECTION_FAILURE: NTSTATUS = 0xC0000305; +pub const STATUS_CSS_AUTHENTICATION_FAILURE: NTSTATUS = 0xC0000306; +pub const STATUS_CSS_KEY_NOT_PRESENT: NTSTATUS = 0xC0000307; +pub const STATUS_CSS_KEY_NOT_ESTABLISHED: NTSTATUS = 0xC0000308; +pub const STATUS_CSS_SCRAMBLED_SECTOR: NTSTATUS = 0xC0000309; +pub const STATUS_CSS_REGION_MISMATCH: NTSTATUS = 0xC000030A; +pub const STATUS_CSS_RESETS_EXHAUSTED: NTSTATUS = 0xC000030B; +pub const STATUS_PASSWORD_CHANGE_REQUIRED: NTSTATUS = 0xC000030C; +pub const STATUS_PKINIT_FAILURE: NTSTATUS = 0xC0000320; +pub const STATUS_SMARTCARD_SUBSYSTEM_FAILURE: NTSTATUS = 0xC0000321; +pub const STATUS_NO_KERB_KEY: NTSTATUS = 0xC0000322; +pub const STATUS_HOST_DOWN: NTSTATUS = 0xC0000350; +pub const STATUS_UNSUPPORTED_PREAUTH: NTSTATUS = 0xC0000351; +pub const STATUS_EFS_ALG_BLOB_TOO_BIG: NTSTATUS = 0xC0000352; +pub const STATUS_PORT_NOT_SET: NTSTATUS = 0xC0000353; +pub const STATUS_DEBUGGER_INACTIVE: NTSTATUS = 0xC0000354; +pub const STATUS_DS_VERSION_CHECK_FAILURE: NTSTATUS = 0xC0000355; +pub const STATUS_AUDITING_DISABLED: NTSTATUS = 0xC0000356; +pub const STATUS_PRENT4_MACHINE_ACCOUNT: NTSTATUS = 0xC0000357; +pub const STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: NTSTATUS = 0xC0000358; +pub const STATUS_INVALID_IMAGE_WIN_32: NTSTATUS = 0xC0000359; +pub const STATUS_INVALID_IMAGE_WIN_64: NTSTATUS = 0xC000035A; +pub const STATUS_BAD_BINDINGS: NTSTATUS = 0xC000035B; +pub const STATUS_NETWORK_SESSION_EXPIRED: NTSTATUS = 0xC000035C; +pub const STATUS_APPHELP_BLOCK: NTSTATUS = 0xC000035D; +pub const STATUS_ALL_SIDS_FILTERED: NTSTATUS = 0xC000035E; +pub const STATUS_NOT_SAFE_MODE_DRIVER: NTSTATUS = 0xC000035F; +pub const STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT: NTSTATUS = 0xC0000361; +pub const STATUS_ACCESS_DISABLED_BY_POLICY_PATH: NTSTATUS = 0xC0000362; +pub const STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER: NTSTATUS = 0xC0000363; +pub const STATUS_ACCESS_DISABLED_BY_POLICY_OTHER: NTSTATUS = 0xC0000364; +pub const STATUS_FAILED_DRIVER_ENTRY: NTSTATUS = 0xC0000365; +pub const STATUS_DEVICE_ENUMERATION_ERROR: NTSTATUS = 0xC0000366; +pub const STATUS_MOUNT_POINT_NOT_RESOLVED: NTSTATUS = 0xC0000368; +pub const STATUS_INVALID_DEVICE_OBJECT_PARAMETER: NTSTATUS = 0xC0000369; +pub const STATUS_MCA_OCCURED: NTSTATUS = 0xC000036A; +pub const STATUS_DRIVER_BLOCKED_CRITICAL: NTSTATUS = 0xC000036B; +pub const STATUS_DRIVER_BLOCKED: NTSTATUS = 0xC000036C; +pub const STATUS_DRIVER_DATABASE_ERROR: NTSTATUS = 0xC000036D; +pub const STATUS_SYSTEM_HIVE_TOO_LARGE: NTSTATUS = 0xC000036E; +pub const STATUS_INVALID_IMPORT_OF_NON_DLL: NTSTATUS = 0xC000036F; +pub const STATUS_DS_SHUTTING_DOWN: NTSTATUS = 0x40000370; +pub const STATUS_NO_SECRETS: NTSTATUS = 0xC0000371; +pub const STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY: NTSTATUS = 0xC0000372; +pub const STATUS_FAILED_STACK_SWITCH: NTSTATUS = 0xC0000373; +pub const STATUS_HEAP_CORRUPTION: NTSTATUS = 0xC0000374; +pub const STATUS_SMARTCARD_WRONG_PIN: NTSTATUS = 0xC0000380; +pub const STATUS_SMARTCARD_CARD_BLOCKED: NTSTATUS = 0xC0000381; +pub const STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED: NTSTATUS = 0xC0000382; +pub const STATUS_SMARTCARD_NO_CARD: NTSTATUS = 0xC0000383; +pub const STATUS_SMARTCARD_NO_KEY_CONTAINER: NTSTATUS = 0xC0000384; +pub const STATUS_SMARTCARD_NO_CERTIFICATE: NTSTATUS = 0xC0000385; +pub const STATUS_SMARTCARD_NO_KEYSET: NTSTATUS = 0xC0000386; +pub const STATUS_SMARTCARD_IO_ERROR: NTSTATUS = 0xC0000387; +pub const STATUS_DOWNGRADE_DETECTED: NTSTATUS = 0xC0000388; +pub const STATUS_SMARTCARD_CERT_REVOKED: NTSTATUS = 0xC0000389; +pub const STATUS_ISSUING_CA_UNTRUSTED: NTSTATUS = 0xC000038A; +pub const STATUS_REVOCATION_OFFLINE_C: NTSTATUS = 0xC000038B; +pub const STATUS_PKINIT_CLIENT_FAILURE: NTSTATUS = 0xC000038C; +pub const STATUS_SMARTCARD_CERT_EXPIRED: NTSTATUS = 0xC000038D; +pub const STATUS_DRIVER_FAILED_PRIOR_UNLOAD: NTSTATUS = 0xC000038E; +pub const STATUS_SMARTCARD_SILENT_CONTEXT: NTSTATUS = 0xC000038F; +pub const STATUS_PER_USER_TRUST_QUOTA_EXCEEDED: NTSTATUS = 0xC0000401; +pub const STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED: NTSTATUS = 0xC0000402; +pub const STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED: NTSTATUS = 0xC0000403; +pub const STATUS_DS_NAME_NOT_UNIQUE: NTSTATUS = 0xC0000404; +pub const STATUS_DS_DUPLICATE_ID_FOUND: NTSTATUS = 0xC0000405; +pub const STATUS_DS_GROUP_CONVERSION_ERROR: NTSTATUS = 0xC0000406; +pub const STATUS_VOLSNAP_PREPARE_HIBERNATE: NTSTATUS = 0xC0000407; +pub const STATUS_USER2USER_REQUIRED: NTSTATUS = 0xC0000408; +pub const STATUS_STACK_BUFFER_OVERRUN: NTSTATUS = 0xC0000409; +pub const STATUS_NO_S4U_PROT_SUPPORT: NTSTATUS = 0xC000040A; +pub const STATUS_CROSSREALM_DELEGATION_FAILURE: NTSTATUS = 0xC000040B; +pub const STATUS_REVOCATION_OFFLINE_KDC: NTSTATUS = 0xC000040C; +pub const STATUS_ISSUING_CA_UNTRUSTED_KDC: NTSTATUS = 0xC000040D; +pub const STATUS_KDC_CERT_EXPIRED: NTSTATUS = 0xC000040E; +pub const STATUS_KDC_CERT_REVOKED: NTSTATUS = 0xC000040F; +pub const STATUS_PARAMETER_QUOTA_EXCEEDED: NTSTATUS = 0xC0000410; +pub const STATUS_HIBERNATION_FAILURE: NTSTATUS = 0xC0000411; +pub const STATUS_DELAY_LOAD_FAILED: NTSTATUS = 0xC0000412; +pub const STATUS_AUTHENTICATION_FIREWALL_FAILED: NTSTATUS = 0xC0000413; +pub const STATUS_VDM_DISALLOWED: NTSTATUS = 0xC0000414; +pub const STATUS_HUNG_DISPLAY_DRIVER_THREAD: NTSTATUS = 0xC0000415; +pub const STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE: NTSTATUS + = 0xC0000416; +pub const STATUS_INVALID_CRUNTIME_PARAMETER: NTSTATUS = 0xC0000417; +pub const STATUS_NTLM_BLOCKED: NTSTATUS = 0xC0000418; +pub const STATUS_DS_SRC_SID_EXISTS_IN_FOREST: NTSTATUS = 0xC0000419; +pub const STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST: NTSTATUS = 0xC000041A; +pub const STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST: NTSTATUS = 0xC000041B; +pub const STATUS_INVALID_USER_PRINCIPAL_NAME: NTSTATUS = 0xC000041C; +pub const STATUS_FATAL_USER_CALLBACK_EXCEPTION: NTSTATUS = 0xC000041D; +pub const STATUS_ASSERTION_FAILURE: NTSTATUS = 0xC0000420; +pub const STATUS_VERIFIER_STOP: NTSTATUS = 0xC0000421; +pub const STATUS_CALLBACK_POP_STACK: NTSTATUS = 0xC0000423; +pub const STATUS_INCOMPATIBLE_DRIVER_BLOCKED: NTSTATUS = 0xC0000424; +pub const STATUS_HIVE_UNLOADED: NTSTATUS = 0xC0000425; +pub const STATUS_COMPRESSION_DISABLED: NTSTATUS = 0xC0000426; +pub const STATUS_FILE_SYSTEM_LIMITATION: NTSTATUS = 0xC0000427; +pub const STATUS_INVALID_IMAGE_HASH: NTSTATUS = 0xC0000428; +pub const STATUS_NOT_CAPABLE: NTSTATUS = 0xC0000429; +pub const STATUS_REQUEST_OUT_OF_SEQUENCE: NTSTATUS = 0xC000042A; +pub const STATUS_IMPLEMENTATION_LIMIT: NTSTATUS = 0xC000042B; +pub const STATUS_ELEVATION_REQUIRED: NTSTATUS = 0xC000042C; +pub const STATUS_NO_SECURITY_CONTEXT: NTSTATUS = 0xC000042D; +pub const STATUS_PKU2U_CERT_FAILURE: NTSTATUS = 0xC000042F; +pub const STATUS_BEYOND_VDL: NTSTATUS = 0xC0000432; +pub const STATUS_ENCOUNTERED_WRITE_IN_PROGRESS: NTSTATUS = 0xC0000433; +pub const STATUS_PTE_CHANGED: NTSTATUS = 0xC0000434; +pub const STATUS_PURGE_FAILED: NTSTATUS = 0xC0000435; +pub const STATUS_CRED_REQUIRES_CONFIRMATION: NTSTATUS = 0xC0000440; +pub const STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE: NTSTATUS = 0xC0000441; +pub const STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER: NTSTATUS = 0xC0000442; +pub const STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE: NTSTATUS = 0xC0000443; +pub const STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE: NTSTATUS = 0xC0000444; +pub const STATUS_CS_ENCRYPTION_FILE_NOT_CSE: NTSTATUS = 0xC0000445; +pub const STATUS_INVALID_LABEL: NTSTATUS = 0xC0000446; +pub const STATUS_DRIVER_PROCESS_TERMINATED: NTSTATUS = 0xC0000450; +pub const STATUS_AMBIGUOUS_SYSTEM_DEVICE: NTSTATUS = 0xC0000451; +pub const STATUS_SYSTEM_DEVICE_NOT_FOUND: NTSTATUS = 0xC0000452; +pub const STATUS_RESTART_BOOT_APPLICATION: NTSTATUS = 0xC0000453; +pub const STATUS_INSUFFICIENT_NVRAM_RESOURCES: NTSTATUS = 0xC0000454; +pub const STATUS_INVALID_SESSION: NTSTATUS = 0xC0000455; +pub const STATUS_THREAD_ALREADY_IN_SESSION: NTSTATUS = 0xC0000456; +pub const STATUS_THREAD_NOT_IN_SESSION: NTSTATUS = 0xC0000457; +pub const STATUS_INVALID_WEIGHT: NTSTATUS = 0xC0000458; +pub const STATUS_REQUEST_PAUSED: NTSTATUS = 0xC0000459; +pub const STATUS_NO_RANGES_PROCESSED: NTSTATUS = 0xC0000460; +pub const STATUS_DISK_RESOURCES_EXHAUSTED: NTSTATUS = 0xC0000461; +pub const STATUS_NEEDS_REMEDIATION: NTSTATUS = 0xC0000462; +pub const STATUS_DEVICE_FEATURE_NOT_SUPPORTED: NTSTATUS = 0xC0000463; +pub const STATUS_DEVICE_UNREACHABLE: NTSTATUS = 0xC0000464; +pub const STATUS_INVALID_TOKEN: NTSTATUS = 0xC0000465; +pub const STATUS_SERVER_UNAVAILABLE: NTSTATUS = 0xC0000466; +pub const STATUS_FILE_NOT_AVAILABLE: NTSTATUS = 0xC0000467; +pub const STATUS_DEVICE_INSUFFICIENT_RESOURCES: NTSTATUS = 0xC0000468; +pub const STATUS_PACKAGE_UPDATING: NTSTATUS = 0xC0000469; +pub const STATUS_NOT_READ_FROM_COPY: NTSTATUS = 0xC000046A; +pub const STATUS_FT_WRITE_FAILURE: NTSTATUS = 0xC000046B; +pub const STATUS_FT_DI_SCAN_REQUIRED: NTSTATUS = 0xC000046C; +pub const STATUS_OBJECT_NOT_EXTERNALLY_BACKED: NTSTATUS = 0xC000046D; +pub const STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN: NTSTATUS = 0xC000046E; +pub const STATUS_COMPRESSION_NOT_BENEFICIAL: NTSTATUS = 0xC000046F; +pub const STATUS_DATA_CHECKSUM_ERROR: NTSTATUS = 0xC0000470; +pub const STATUS_INTERMIXED_KERNEL_EA_OPERATION: NTSTATUS = 0xC0000471; +pub const STATUS_TRIM_READ_ZERO_NOT_SUPPORTED: NTSTATUS = 0xC0000472; +pub const STATUS_TOO_MANY_SEGMENT_DESCRIPTORS: NTSTATUS = 0xC0000473; +pub const STATUS_INVALID_OFFSET_ALIGNMENT: NTSTATUS = 0xC0000474; +pub const STATUS_INVALID_FIELD_IN_PARAMETER_LIST: NTSTATUS = 0xC0000475; +pub const STATUS_OPERATION_IN_PROGRESS: NTSTATUS = 0xC0000476; +pub const STATUS_INVALID_INITIATOR_TARGET_PATH: NTSTATUS = 0xC0000477; +pub const STATUS_SCRUB_DATA_DISABLED: NTSTATUS = 0xC0000478; +pub const STATUS_NOT_REDUNDANT_STORAGE: NTSTATUS = 0xC0000479; +pub const STATUS_RESIDENT_FILE_NOT_SUPPORTED: NTSTATUS = 0xC000047A; +pub const STATUS_COMPRESSED_FILE_NOT_SUPPORTED: NTSTATUS = 0xC000047B; +pub const STATUS_DIRECTORY_NOT_SUPPORTED: NTSTATUS = 0xC000047C; +pub const STATUS_IO_OPERATION_TIMEOUT: NTSTATUS = 0xC000047D; +pub const STATUS_SYSTEM_NEEDS_REMEDIATION: NTSTATUS = 0xC000047E; +pub const STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN: NTSTATUS = 0xC000047F; +pub const STATUS_SHARE_UNAVAILABLE: NTSTATUS = 0xC0000480; +pub const STATUS_APISET_NOT_HOSTED: NTSTATUS = 0xC0000481; +pub const STATUS_APISET_NOT_PRESENT: NTSTATUS = 0xC0000482; +pub const STATUS_DEVICE_HARDWARE_ERROR: NTSTATUS = 0xC0000483; +pub const STATUS_FIRMWARE_SLOT_INVALID: NTSTATUS = 0xC0000484; +pub const STATUS_FIRMWARE_IMAGE_INVALID: NTSTATUS = 0xC0000485; +pub const STATUS_STORAGE_TOPOLOGY_ID_MISMATCH: NTSTATUS = 0xC0000486; +pub const STATUS_WIM_NOT_BOOTABLE: NTSTATUS = 0xC0000487; +pub const STATUS_BLOCKED_BY_PARENTAL_CONTROLS: NTSTATUS = 0xC0000488; +pub const STATUS_NEEDS_REGISTRATION: NTSTATUS = 0xC0000489; +pub const STATUS_QUOTA_ACTIVITY: NTSTATUS = 0xC000048A; +pub const STATUS_CALLBACK_INVOKE_INLINE: NTSTATUS = 0xC000048B; +pub const STATUS_BLOCK_TOO_MANY_REFERENCES: NTSTATUS = 0xC000048C; +pub const STATUS_MARKED_TO_DISALLOW_WRITES: NTSTATUS = 0xC000048D; +pub const STATUS_NETWORK_ACCESS_DENIED_EDP: NTSTATUS = 0xC000048E; +pub const STATUS_ENCLAVE_FAILURE: NTSTATUS = 0xC000048F; +pub const STATUS_PNP_NO_COMPAT_DRIVERS: NTSTATUS = 0xC0000490; +pub const STATUS_PNP_DRIVER_PACKAGE_NOT_FOUND: NTSTATUS = 0xC0000491; +pub const STATUS_PNP_DRIVER_CONFIGURATION_NOT_FOUND: NTSTATUS = 0xC0000492; +pub const STATUS_PNP_DRIVER_CONFIGURATION_INCOMPLETE: NTSTATUS = 0xC0000493; +pub const STATUS_PNP_FUNCTION_DRIVER_REQUIRED: NTSTATUS = 0xC0000494; +pub const STATUS_PNP_DEVICE_CONFIGURATION_PENDING: NTSTATUS = 0xC0000495; +pub const STATUS_DEVICE_HINT_NAME_BUFFER_TOO_SMALL: NTSTATUS = 0xC0000496; +pub const STATUS_PACKAGE_NOT_AVAILABLE: NTSTATUS = 0xC0000497; +pub const STATUS_DEVICE_IN_MAINTENANCE: NTSTATUS = 0xC0000499; +pub const STATUS_NOT_SUPPORTED_ON_DAX: NTSTATUS = 0xC000049A; +pub const STATUS_FREE_SPACE_TOO_FRAGMENTED: NTSTATUS = 0xC000049B; +pub const STATUS_DAX_MAPPING_EXISTS: NTSTATUS = 0xC000049C; +pub const STATUS_CHILD_PROCESS_BLOCKED: NTSTATUS = 0xC000049D; +pub const STATUS_STORAGE_LOST_DATA_PERSISTENCE: NTSTATUS = 0xC000049E; +pub const STATUS_INVALID_TASK_NAME: NTSTATUS = 0xC0000500; +pub const STATUS_INVALID_TASK_INDEX: NTSTATUS = 0xC0000501; +pub const STATUS_THREAD_ALREADY_IN_TASK: NTSTATUS = 0xC0000502; +pub const STATUS_CALLBACK_BYPASS: NTSTATUS = 0xC0000503; +pub const STATUS_UNDEFINED_SCOPE: NTSTATUS = 0xC0000504; +pub const STATUS_INVALID_CAP: NTSTATUS = 0xC0000505; +pub const STATUS_NOT_GUI_PROCESS: NTSTATUS = 0xC0000506; +pub const STATUS_DEVICE_HUNG: NTSTATUS = 0xC0000507; +pub const STATUS_CONTAINER_ASSIGNED: NTSTATUS = 0xC0000508; +pub const STATUS_JOB_NO_CONTAINER: NTSTATUS = 0xC0000509; +pub const STATUS_DEVICE_UNRESPONSIVE: NTSTATUS = 0xC000050A; +pub const STATUS_REPARSE_POINT_ENCOUNTERED: NTSTATUS = 0xC000050B; +pub const STATUS_FAIL_FAST_EXCEPTION: NTSTATUS = 0xC0000602; +pub const STATUS_IMAGE_CERT_REVOKED: NTSTATUS = 0xC0000603; +pub const STATUS_DYNAMIC_CODE_BLOCKED: NTSTATUS = 0xC0000604; +pub const STATUS_IMAGE_CERT_EXPIRED: NTSTATUS = 0xC0000605; +pub const STATUS_PORT_CLOSED: NTSTATUS = 0xC0000700; +pub const STATUS_MESSAGE_LOST: NTSTATUS = 0xC0000701; +pub const STATUS_INVALID_MESSAGE: NTSTATUS = 0xC0000702; +pub const STATUS_REQUEST_CANCELED: NTSTATUS = 0xC0000703; +pub const STATUS_RECURSIVE_DISPATCH: NTSTATUS = 0xC0000704; +pub const STATUS_LPC_RECEIVE_BUFFER_EXPECTED: NTSTATUS = 0xC0000705; +pub const STATUS_LPC_INVALID_CONNECTION_USAGE: NTSTATUS = 0xC0000706; +pub const STATUS_LPC_REQUESTS_NOT_ALLOWED: NTSTATUS = 0xC0000707; +pub const STATUS_RESOURCE_IN_USE: NTSTATUS = 0xC0000708; +pub const STATUS_HARDWARE_MEMORY_ERROR: NTSTATUS = 0xC0000709; +pub const STATUS_THREADPOOL_HANDLE_EXCEPTION: NTSTATUS = 0xC000070A; +pub const STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED: NTSTATUS = 0xC000070B; +pub const STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED: NTSTATUS + = 0xC000070C; +pub const STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED: NTSTATUS = 0xC000070D; +pub const STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED: NTSTATUS = 0xC000070E; +pub const STATUS_THREADPOOL_RELEASED_DURING_OPERATION: NTSTATUS = 0xC000070F; +pub const STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING: NTSTATUS = 0xC0000710; +pub const STATUS_APC_RETURNED_WHILE_IMPERSONATING: NTSTATUS = 0xC0000711; +pub const STATUS_PROCESS_IS_PROTECTED: NTSTATUS = 0xC0000712; +pub const STATUS_MCA_EXCEPTION: NTSTATUS = 0xC0000713; +pub const STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE: NTSTATUS = 0xC0000714; +pub const STATUS_SYMLINK_CLASS_DISABLED: NTSTATUS = 0xC0000715; +pub const STATUS_INVALID_IDN_NORMALIZATION: NTSTATUS = 0xC0000716; +pub const STATUS_NO_UNICODE_TRANSLATION: NTSTATUS = 0xC0000717; +pub const STATUS_ALREADY_REGISTERED: NTSTATUS = 0xC0000718; +pub const STATUS_CONTEXT_MISMATCH: NTSTATUS = 0xC0000719; +pub const STATUS_PORT_ALREADY_HAS_COMPLETION_LIST: NTSTATUS = 0xC000071A; +pub const STATUS_CALLBACK_RETURNED_THREAD_PRIORITY: NTSTATUS = 0xC000071B; +pub const STATUS_INVALID_THREAD: NTSTATUS = 0xC000071C; +pub const STATUS_CALLBACK_RETURNED_TRANSACTION: NTSTATUS = 0xC000071D; +pub const STATUS_CALLBACK_RETURNED_LDR_LOCK: NTSTATUS = 0xC000071E; +pub const STATUS_CALLBACK_RETURNED_LANG: NTSTATUS = 0xC000071F; +pub const STATUS_CALLBACK_RETURNED_PRI_BACK: NTSTATUS = 0xC0000720; +pub const STATUS_CALLBACK_RETURNED_THREAD_AFFINITY: NTSTATUS = 0xC0000721; +pub const STATUS_LPC_HANDLE_COUNT_EXCEEDED: NTSTATUS = 0xC0000722; +pub const STATUS_DISK_REPAIR_DISABLED: NTSTATUS = 0xC0000800; +pub const STATUS_DS_DOMAIN_RENAME_IN_PROGRESS: NTSTATUS = 0xC0000801; +pub const STATUS_DISK_QUOTA_EXCEEDED: NTSTATUS = 0xC0000802; +pub const STATUS_DATA_LOST_REPAIR: NTSTATUS = 0x80000803; +pub const STATUS_CONTENT_BLOCKED: NTSTATUS = 0xC0000804; +pub const STATUS_BAD_CLUSTERS: NTSTATUS = 0xC0000805; +pub const STATUS_VOLUME_DIRTY: NTSTATUS = 0xC0000806; +pub const STATUS_DISK_REPAIR_REDIRECTED: NTSTATUS = 0x40000807; +pub const STATUS_DISK_REPAIR_UNSUCCESSFUL: NTSTATUS = 0xC0000808; +pub const STATUS_CORRUPT_LOG_OVERFULL: NTSTATUS = 0xC0000809; +pub const STATUS_CORRUPT_LOG_CORRUPTED: NTSTATUS = 0xC000080A; +pub const STATUS_CORRUPT_LOG_UNAVAILABLE: NTSTATUS = 0xC000080B; +pub const STATUS_CORRUPT_LOG_DELETED_FULL: NTSTATUS = 0xC000080C; +pub const STATUS_CORRUPT_LOG_CLEARED: NTSTATUS = 0xC000080D; +pub const STATUS_ORPHAN_NAME_EXHAUSTED: NTSTATUS = 0xC000080E; +pub const STATUS_PROACTIVE_SCAN_IN_PROGRESS: NTSTATUS = 0xC000080F; +pub const STATUS_ENCRYPTED_IO_NOT_POSSIBLE: NTSTATUS = 0xC0000810; +pub const STATUS_CORRUPT_LOG_UPLEVEL_RECORDS: NTSTATUS = 0xC0000811; +pub const STATUS_FILE_CHECKED_OUT: NTSTATUS = 0xC0000901; +pub const STATUS_CHECKOUT_REQUIRED: NTSTATUS = 0xC0000902; +pub const STATUS_BAD_FILE_TYPE: NTSTATUS = 0xC0000903; +pub const STATUS_FILE_TOO_LARGE: NTSTATUS = 0xC0000904; +pub const STATUS_FORMS_AUTH_REQUIRED: NTSTATUS = 0xC0000905; +pub const STATUS_VIRUS_INFECTED: NTSTATUS = 0xC0000906; +pub const STATUS_VIRUS_DELETED: NTSTATUS = 0xC0000907; +pub const STATUS_BAD_MCFG_TABLE: NTSTATUS = 0xC0000908; +pub const STATUS_CANNOT_BREAK_OPLOCK: NTSTATUS = 0xC0000909; +pub const STATUS_BAD_KEY: NTSTATUS = 0xC000090A; +pub const STATUS_BAD_DATA: NTSTATUS = 0xC000090B; +pub const STATUS_NO_KEY: NTSTATUS = 0xC000090C; +pub const STATUS_FILE_HANDLE_REVOKED: NTSTATUS = 0xC0000910; +pub const STATUS_WOW_ASSERTION: NTSTATUS = 0xC0009898; +pub const STATUS_INVALID_SIGNATURE: NTSTATUS = 0xC000A000; +pub const STATUS_HMAC_NOT_SUPPORTED: NTSTATUS = 0xC000A001; +pub const STATUS_AUTH_TAG_MISMATCH: NTSTATUS = 0xC000A002; +pub const STATUS_INVALID_STATE_TRANSITION: NTSTATUS = 0xC000A003; +pub const STATUS_INVALID_KERNEL_INFO_VERSION: NTSTATUS = 0xC000A004; +pub const STATUS_INVALID_PEP_INFO_VERSION: NTSTATUS = 0xC000A005; +pub const STATUS_HANDLE_REVOKED: NTSTATUS = 0xC000A006; +pub const STATUS_EOF_ON_GHOSTED_RANGE: NTSTATUS = 0xC000A007; +pub const STATUS_IPSEC_QUEUE_OVERFLOW: NTSTATUS = 0xC000A010; +pub const STATUS_ND_QUEUE_OVERFLOW: NTSTATUS = 0xC000A011; +pub const STATUS_HOPLIMIT_EXCEEDED: NTSTATUS = 0xC000A012; +pub const STATUS_PROTOCOL_NOT_SUPPORTED: NTSTATUS = 0xC000A013; +pub const STATUS_FASTPATH_REJECTED: NTSTATUS = 0xC000A014; +pub const STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED: NTSTATUS = 0xC000A080; +pub const STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR: NTSTATUS = 0xC000A081; +pub const STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR: NTSTATUS = 0xC000A082; +pub const STATUS_XML_PARSE_ERROR: NTSTATUS = 0xC000A083; +pub const STATUS_XMLDSIG_ERROR: NTSTATUS = 0xC000A084; +pub const STATUS_WRONG_COMPARTMENT: NTSTATUS = 0xC000A085; +pub const STATUS_AUTHIP_FAILURE: NTSTATUS = 0xC000A086; +pub const STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS: NTSTATUS = 0xC000A087; +pub const STATUS_DS_OID_NOT_FOUND: NTSTATUS = 0xC000A088; +pub const STATUS_INCORRECT_ACCOUNT_TYPE: NTSTATUS = 0xC000A089; +pub const STATUS_HASH_NOT_SUPPORTED: NTSTATUS = 0xC000A100; +pub const STATUS_HASH_NOT_PRESENT: NTSTATUS = 0xC000A101; +pub const STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED: NTSTATUS = 0xC000A121; +pub const STATUS_GPIO_CLIENT_INFORMATION_INVALID: NTSTATUS = 0xC000A122; +pub const STATUS_GPIO_VERSION_NOT_SUPPORTED: NTSTATUS = 0xC000A123; +pub const STATUS_GPIO_INVALID_REGISTRATION_PACKET: NTSTATUS = 0xC000A124; +pub const STATUS_GPIO_OPERATION_DENIED: NTSTATUS = 0xC000A125; +pub const STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE: NTSTATUS = 0xC000A126; +pub const STATUS_GPIO_INTERRUPT_ALREADY_UNMASKED: NTSTATUS = 0x8000A127; +pub const STATUS_CANNOT_SWITCH_RUNLEVEL: NTSTATUS = 0xC000A141; +pub const STATUS_INVALID_RUNLEVEL_SETTING: NTSTATUS = 0xC000A142; +pub const STATUS_RUNLEVEL_SWITCH_TIMEOUT: NTSTATUS = 0xC000A143; +pub const STATUS_SERVICES_FAILED_AUTOSTART: NTSTATUS = 0x4000A144; +pub const STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT: NTSTATUS = 0xC000A145; +pub const STATUS_RUNLEVEL_SWITCH_IN_PROGRESS: NTSTATUS = 0xC000A146; +pub const STATUS_NOT_APPCONTAINER: NTSTATUS = 0xC000A200; +pub const STATUS_NOT_SUPPORTED_IN_APPCONTAINER: NTSTATUS = 0xC000A201; +pub const STATUS_INVALID_PACKAGE_SID_LENGTH: NTSTATUS = 0xC000A202; +pub const STATUS_APP_DATA_NOT_FOUND: NTSTATUS = 0xC000A281; +pub const STATUS_APP_DATA_EXPIRED: NTSTATUS = 0xC000A282; +pub const STATUS_APP_DATA_CORRUPT: NTSTATUS = 0xC000A283; +pub const STATUS_APP_DATA_LIMIT_EXCEEDED: NTSTATUS = 0xC000A284; +pub const STATUS_APP_DATA_REBOOT_REQUIRED: NTSTATUS = 0xC000A285; +pub const STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED: NTSTATUS = 0xC000A2A1; +pub const STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED: NTSTATUS = 0xC000A2A2; +pub const STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED: NTSTATUS = 0xC000A2A3; +pub const STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: NTSTATUS = 0xC000A2A4; +pub const STATUS_CLOUD_FILE_PROVIDER_UNKNOWN: NTSTATUS = 0xC000CF00; +pub const STATUS_CLOUD_FILE_PROVIDER_NOT_RUNNING: NTSTATUS = 0xC000CF01; +pub const STATUS_CLOUD_FILE_METADATA_CORRUPT: NTSTATUS = 0xC000CF02; +pub const STATUS_CLOUD_FILE_METADATA_TOO_LARGE: NTSTATUS = 0xC000CF03; +pub const STATUS_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE: NTSTATUS = 0x8000CF04; +pub const DBG_NO_STATE_CHANGE: NTSTATUS = 0xC0010001; +pub const DBG_APP_NOT_IDLE: NTSTATUS = 0xC0010002; +pub const RPC_NT_INVALID_STRING_BINDING: NTSTATUS = 0xC0020001; +pub const RPC_NT_WRONG_KIND_OF_BINDING: NTSTATUS = 0xC0020002; +pub const RPC_NT_INVALID_BINDING: NTSTATUS = 0xC0020003; +pub const RPC_NT_PROTSEQ_NOT_SUPPORTED: NTSTATUS = 0xC0020004; +pub const RPC_NT_INVALID_RPC_PROTSEQ: NTSTATUS = 0xC0020005; +pub const RPC_NT_INVALID_STRING_UUID: NTSTATUS = 0xC0020006; +pub const RPC_NT_INVALID_ENDPOINT_FORMAT: NTSTATUS = 0xC0020007; +pub const RPC_NT_INVALID_NET_ADDR: NTSTATUS = 0xC0020008; +pub const RPC_NT_NO_ENDPOINT_FOUND: NTSTATUS = 0xC0020009; +pub const RPC_NT_INVALID_TIMEOUT: NTSTATUS = 0xC002000A; +pub const RPC_NT_OBJECT_NOT_FOUND: NTSTATUS = 0xC002000B; +pub const RPC_NT_ALREADY_REGISTERED: NTSTATUS = 0xC002000C; +pub const RPC_NT_TYPE_ALREADY_REGISTERED: NTSTATUS = 0xC002000D; +pub const RPC_NT_ALREADY_LISTENING: NTSTATUS = 0xC002000E; +pub const RPC_NT_NO_PROTSEQS_REGISTERED: NTSTATUS = 0xC002000F; +pub const RPC_NT_NOT_LISTENING: NTSTATUS = 0xC0020010; +pub const RPC_NT_UNKNOWN_MGR_TYPE: NTSTATUS = 0xC0020011; +pub const RPC_NT_UNKNOWN_IF: NTSTATUS = 0xC0020012; +pub const RPC_NT_NO_BINDINGS: NTSTATUS = 0xC0020013; +pub const RPC_NT_NO_PROTSEQS: NTSTATUS = 0xC0020014; +pub const RPC_NT_CANT_CREATE_ENDPOINT: NTSTATUS = 0xC0020015; +pub const RPC_NT_OUT_OF_RESOURCES: NTSTATUS = 0xC0020016; +pub const RPC_NT_SERVER_UNAVAILABLE: NTSTATUS = 0xC0020017; +pub const RPC_NT_SERVER_TOO_BUSY: NTSTATUS = 0xC0020018; +pub const RPC_NT_INVALID_NETWORK_OPTIONS: NTSTATUS = 0xC0020019; +pub const RPC_NT_NO_CALL_ACTIVE: NTSTATUS = 0xC002001A; +pub const RPC_NT_CALL_FAILED: NTSTATUS = 0xC002001B; +pub const RPC_NT_CALL_FAILED_DNE: NTSTATUS = 0xC002001C; +pub const RPC_NT_PROTOCOL_ERROR: NTSTATUS = 0xC002001D; +pub const RPC_NT_UNSUPPORTED_TRANS_SYN: NTSTATUS = 0xC002001F; +pub const RPC_NT_UNSUPPORTED_TYPE: NTSTATUS = 0xC0020021; +pub const RPC_NT_INVALID_TAG: NTSTATUS = 0xC0020022; +pub const RPC_NT_INVALID_BOUND: NTSTATUS = 0xC0020023; +pub const RPC_NT_NO_ENTRY_NAME: NTSTATUS = 0xC0020024; +pub const RPC_NT_INVALID_NAME_SYNTAX: NTSTATUS = 0xC0020025; +pub const RPC_NT_UNSUPPORTED_NAME_SYNTAX: NTSTATUS = 0xC0020026; +pub const RPC_NT_UUID_NO_ADDRESS: NTSTATUS = 0xC0020028; +pub const RPC_NT_DUPLICATE_ENDPOINT: NTSTATUS = 0xC0020029; +pub const RPC_NT_UNKNOWN_AUTHN_TYPE: NTSTATUS = 0xC002002A; +pub const RPC_NT_MAX_CALLS_TOO_SMALL: NTSTATUS = 0xC002002B; +pub const RPC_NT_STRING_TOO_LONG: NTSTATUS = 0xC002002C; +pub const RPC_NT_PROTSEQ_NOT_FOUND: NTSTATUS = 0xC002002D; +pub const RPC_NT_PROCNUM_OUT_OF_RANGE: NTSTATUS = 0xC002002E; +pub const RPC_NT_BINDING_HAS_NO_AUTH: NTSTATUS = 0xC002002F; +pub const RPC_NT_UNKNOWN_AUTHN_SERVICE: NTSTATUS = 0xC0020030; +pub const RPC_NT_UNKNOWN_AUTHN_LEVEL: NTSTATUS = 0xC0020031; +pub const RPC_NT_INVALID_AUTH_IDENTITY: NTSTATUS = 0xC0020032; +pub const RPC_NT_UNKNOWN_AUTHZ_SERVICE: NTSTATUS = 0xC0020033; +pub const EPT_NT_INVALID_ENTRY: NTSTATUS = 0xC0020034; +pub const EPT_NT_CANT_PERFORM_OP: NTSTATUS = 0xC0020035; +pub const EPT_NT_NOT_REGISTERED: NTSTATUS = 0xC0020036; +pub const RPC_NT_NOTHING_TO_EXPORT: NTSTATUS = 0xC0020037; +pub const RPC_NT_INCOMPLETE_NAME: NTSTATUS = 0xC0020038; +pub const RPC_NT_INVALID_VERS_OPTION: NTSTATUS = 0xC0020039; +pub const RPC_NT_NO_MORE_MEMBERS: NTSTATUS = 0xC002003A; +pub const RPC_NT_NOT_ALL_OBJS_UNEXPORTED: NTSTATUS = 0xC002003B; +pub const RPC_NT_INTERFACE_NOT_FOUND: NTSTATUS = 0xC002003C; +pub const RPC_NT_ENTRY_ALREADY_EXISTS: NTSTATUS = 0xC002003D; +pub const RPC_NT_ENTRY_NOT_FOUND: NTSTATUS = 0xC002003E; +pub const RPC_NT_NAME_SERVICE_UNAVAILABLE: NTSTATUS = 0xC002003F; +pub const RPC_NT_INVALID_NAF_ID: NTSTATUS = 0xC0020040; +pub const RPC_NT_CANNOT_SUPPORT: NTSTATUS = 0xC0020041; +pub const RPC_NT_NO_CONTEXT_AVAILABLE: NTSTATUS = 0xC0020042; +pub const RPC_NT_INTERNAL_ERROR: NTSTATUS = 0xC0020043; +pub const RPC_NT_ZERO_DIVIDE: NTSTATUS = 0xC0020044; +pub const RPC_NT_ADDRESS_ERROR: NTSTATUS = 0xC0020045; +pub const RPC_NT_FP_DIV_ZERO: NTSTATUS = 0xC0020046; +pub const RPC_NT_FP_UNDERFLOW: NTSTATUS = 0xC0020047; +pub const RPC_NT_FP_OVERFLOW: NTSTATUS = 0xC0020048; +pub const RPC_NT_NO_MORE_ENTRIES: NTSTATUS = 0xC0030001; +pub const RPC_NT_SS_CHAR_TRANS_OPEN_FAIL: NTSTATUS = 0xC0030002; +pub const RPC_NT_SS_CHAR_TRANS_SHORT_FILE: NTSTATUS = 0xC0030003; +pub const RPC_NT_SS_IN_NULL_CONTEXT: NTSTATUS = 0xC0030004; +pub const RPC_NT_SS_CONTEXT_MISMATCH: NTSTATUS = 0xC0030005; +pub const RPC_NT_SS_CONTEXT_DAMAGED: NTSTATUS = 0xC0030006; +pub const RPC_NT_SS_HANDLES_MISMATCH: NTSTATUS = 0xC0030007; +pub const RPC_NT_SS_CANNOT_GET_CALL_HANDLE: NTSTATUS = 0xC0030008; +pub const RPC_NT_NULL_REF_POINTER: NTSTATUS = 0xC0030009; +pub const RPC_NT_ENUM_VALUE_OUT_OF_RANGE: NTSTATUS = 0xC003000A; +pub const RPC_NT_BYTE_COUNT_TOO_SMALL: NTSTATUS = 0xC003000B; +pub const RPC_NT_BAD_STUB_DATA: NTSTATUS = 0xC003000C; +pub const RPC_NT_CALL_IN_PROGRESS: NTSTATUS = 0xC0020049; +pub const RPC_NT_NO_MORE_BINDINGS: NTSTATUS = 0xC002004A; +pub const RPC_NT_GROUP_MEMBER_NOT_FOUND: NTSTATUS = 0xC002004B; +pub const EPT_NT_CANT_CREATE: NTSTATUS = 0xC002004C; +pub const RPC_NT_INVALID_OBJECT: NTSTATUS = 0xC002004D; +pub const RPC_NT_NO_INTERFACES: NTSTATUS = 0xC002004F; +pub const RPC_NT_CALL_CANCELLED: NTSTATUS = 0xC0020050; +pub const RPC_NT_BINDING_INCOMPLETE: NTSTATUS = 0xC0020051; +pub const RPC_NT_COMM_FAILURE: NTSTATUS = 0xC0020052; +pub const RPC_NT_UNSUPPORTED_AUTHN_LEVEL: NTSTATUS = 0xC0020053; +pub const RPC_NT_NO_PRINC_NAME: NTSTATUS = 0xC0020054; +pub const RPC_NT_NOT_RPC_ERROR: NTSTATUS = 0xC0020055; +pub const RPC_NT_UUID_LOCAL_ONLY: NTSTATUS = 0x40020056; +pub const RPC_NT_SEC_PKG_ERROR: NTSTATUS = 0xC0020057; +pub const RPC_NT_NOT_CANCELLED: NTSTATUS = 0xC0020058; +pub const RPC_NT_INVALID_ES_ACTION: NTSTATUS = 0xC0030059; +pub const RPC_NT_WRONG_ES_VERSION: NTSTATUS = 0xC003005A; +pub const RPC_NT_WRONG_STUB_VERSION: NTSTATUS = 0xC003005B; +pub const RPC_NT_INVALID_PIPE_OBJECT: NTSTATUS = 0xC003005C; +pub const RPC_NT_INVALID_PIPE_OPERATION: NTSTATUS = 0xC003005D; +pub const RPC_NT_WRONG_PIPE_VERSION: NTSTATUS = 0xC003005E; +pub const RPC_NT_PIPE_CLOSED: NTSTATUS = 0xC003005F; +pub const RPC_NT_PIPE_DISCIPLINE_ERROR: NTSTATUS = 0xC0030060; +pub const RPC_NT_PIPE_EMPTY: NTSTATUS = 0xC0030061; +pub const RPC_NT_INVALID_ASYNC_HANDLE: NTSTATUS = 0xC0020062; +pub const RPC_NT_INVALID_ASYNC_CALL: NTSTATUS = 0xC0020063; +pub const RPC_NT_PROXY_ACCESS_DENIED: NTSTATUS = 0xC0020064; +pub const RPC_NT_COOKIE_AUTH_FAILED: NTSTATUS = 0xC0020065; +pub const RPC_NT_SEND_INCOMPLETE: NTSTATUS = 0x400200AF; +pub const STATUS_ACPI_INVALID_OPCODE: NTSTATUS = 0xC0140001; +pub const STATUS_ACPI_STACK_OVERFLOW: NTSTATUS = 0xC0140002; +pub const STATUS_ACPI_ASSERT_FAILED: NTSTATUS = 0xC0140003; +pub const STATUS_ACPI_INVALID_INDEX: NTSTATUS = 0xC0140004; +pub const STATUS_ACPI_INVALID_ARGUMENT: NTSTATUS = 0xC0140005; +pub const STATUS_ACPI_FATAL: NTSTATUS = 0xC0140006; +pub const STATUS_ACPI_INVALID_SUPERNAME: NTSTATUS = 0xC0140007; +pub const STATUS_ACPI_INVALID_ARGTYPE: NTSTATUS = 0xC0140008; +pub const STATUS_ACPI_INVALID_OBJTYPE: NTSTATUS = 0xC0140009; +pub const STATUS_ACPI_INVALID_TARGETTYPE: NTSTATUS = 0xC014000A; +pub const STATUS_ACPI_INCORRECT_ARGUMENT_COUNT: NTSTATUS = 0xC014000B; +pub const STATUS_ACPI_ADDRESS_NOT_MAPPED: NTSTATUS = 0xC014000C; +pub const STATUS_ACPI_INVALID_EVENTTYPE: NTSTATUS = 0xC014000D; +pub const STATUS_ACPI_HANDLER_COLLISION: NTSTATUS = 0xC014000E; +pub const STATUS_ACPI_INVALID_DATA: NTSTATUS = 0xC014000F; +pub const STATUS_ACPI_INVALID_REGION: NTSTATUS = 0xC0140010; +pub const STATUS_ACPI_INVALID_ACCESS_SIZE: NTSTATUS = 0xC0140011; +pub const STATUS_ACPI_ACQUIRE_GLOBAL_LOCK: NTSTATUS = 0xC0140012; +pub const STATUS_ACPI_ALREADY_INITIALIZED: NTSTATUS = 0xC0140013; +pub const STATUS_ACPI_NOT_INITIALIZED: NTSTATUS = 0xC0140014; +pub const STATUS_ACPI_INVALID_MUTEX_LEVEL: NTSTATUS = 0xC0140015; +pub const STATUS_ACPI_MUTEX_NOT_OWNED: NTSTATUS = 0xC0140016; +pub const STATUS_ACPI_MUTEX_NOT_OWNER: NTSTATUS = 0xC0140017; +pub const STATUS_ACPI_RS_ACCESS: NTSTATUS = 0xC0140018; +pub const STATUS_ACPI_INVALID_TABLE: NTSTATUS = 0xC0140019; +pub const STATUS_ACPI_REG_HANDLER_FAILED: NTSTATUS = 0xC0140020; +pub const STATUS_ACPI_POWER_REQUEST_FAILED: NTSTATUS = 0xC0140021; +pub const STATUS_CTX_WINSTATION_NAME_INVALID: NTSTATUS = 0xC00A0001; +pub const STATUS_CTX_INVALID_PD: NTSTATUS = 0xC00A0002; +pub const STATUS_CTX_PD_NOT_FOUND: NTSTATUS = 0xC00A0003; +pub const STATUS_CTX_CDM_CONNECT: NTSTATUS = 0x400A0004; +pub const STATUS_CTX_CDM_DISCONNECT: NTSTATUS = 0x400A0005; +pub const STATUS_CTX_CLOSE_PENDING: NTSTATUS = 0xC00A0006; +pub const STATUS_CTX_NO_OUTBUF: NTSTATUS = 0xC00A0007; +pub const STATUS_CTX_MODEM_INF_NOT_FOUND: NTSTATUS = 0xC00A0008; +pub const STATUS_CTX_INVALID_MODEMNAME: NTSTATUS = 0xC00A0009; +pub const STATUS_CTX_RESPONSE_ERROR: NTSTATUS = 0xC00A000A; +pub const STATUS_CTX_MODEM_RESPONSE_TIMEOUT: NTSTATUS = 0xC00A000B; +pub const STATUS_CTX_MODEM_RESPONSE_NO_CARRIER: NTSTATUS = 0xC00A000C; +pub const STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE: NTSTATUS = 0xC00A000D; +pub const STATUS_CTX_MODEM_RESPONSE_BUSY: NTSTATUS = 0xC00A000E; +pub const STATUS_CTX_MODEM_RESPONSE_VOICE: NTSTATUS = 0xC00A000F; +pub const STATUS_CTX_TD_ERROR: NTSTATUS = 0xC00A0010; +pub const STATUS_CTX_LICENSE_CLIENT_INVALID: NTSTATUS = 0xC00A0012; +pub const STATUS_CTX_LICENSE_NOT_AVAILABLE: NTSTATUS = 0xC00A0013; +pub const STATUS_CTX_LICENSE_EXPIRED: NTSTATUS = 0xC00A0014; +pub const STATUS_CTX_WINSTATION_NOT_FOUND: NTSTATUS = 0xC00A0015; +pub const STATUS_CTX_WINSTATION_NAME_COLLISION: NTSTATUS = 0xC00A0016; +pub const STATUS_CTX_WINSTATION_BUSY: NTSTATUS = 0xC00A0017; +pub const STATUS_CTX_BAD_VIDEO_MODE: NTSTATUS = 0xC00A0018; +pub const STATUS_CTX_GRAPHICS_INVALID: NTSTATUS = 0xC00A0022; +pub const STATUS_CTX_NOT_CONSOLE: NTSTATUS = 0xC00A0024; +pub const STATUS_CTX_CLIENT_QUERY_TIMEOUT: NTSTATUS = 0xC00A0026; +pub const STATUS_CTX_CONSOLE_DISCONNECT: NTSTATUS = 0xC00A0027; +pub const STATUS_CTX_CONSOLE_CONNECT: NTSTATUS = 0xC00A0028; +pub const STATUS_CTX_SHADOW_DENIED: NTSTATUS = 0xC00A002A; +pub const STATUS_CTX_WINSTATION_ACCESS_DENIED: NTSTATUS = 0xC00A002B; +pub const STATUS_CTX_INVALID_WD: NTSTATUS = 0xC00A002E; +pub const STATUS_CTX_WD_NOT_FOUND: NTSTATUS = 0xC00A002F; +pub const STATUS_CTX_SHADOW_INVALID: NTSTATUS = 0xC00A0030; +pub const STATUS_CTX_SHADOW_DISABLED: NTSTATUS = 0xC00A0031; +pub const STATUS_RDP_PROTOCOL_ERROR: NTSTATUS = 0xC00A0032; +pub const STATUS_CTX_CLIENT_LICENSE_NOT_SET: NTSTATUS = 0xC00A0033; +pub const STATUS_CTX_CLIENT_LICENSE_IN_USE: NTSTATUS = 0xC00A0034; +pub const STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE: NTSTATUS = 0xC00A0035; +pub const STATUS_CTX_SHADOW_NOT_RUNNING: NTSTATUS = 0xC00A0036; +pub const STATUS_CTX_LOGON_DISABLED: NTSTATUS = 0xC00A0037; +pub const STATUS_CTX_SECURITY_LAYER_ERROR: NTSTATUS = 0xC00A0038; +pub const STATUS_TS_INCOMPATIBLE_SESSIONS: NTSTATUS = 0xC00A0039; +pub const STATUS_TS_VIDEO_SUBSYSTEM_ERROR: NTSTATUS = 0xC00A003A; +pub const STATUS_PNP_BAD_MPS_TABLE: NTSTATUS = 0xC0040035; +pub const STATUS_PNP_TRANSLATION_FAILED: NTSTATUS = 0xC0040036; +pub const STATUS_PNP_IRQ_TRANSLATION_FAILED: NTSTATUS = 0xC0040037; +pub const STATUS_PNP_INVALID_ID: NTSTATUS = 0xC0040038; +pub const STATUS_IO_REISSUE_AS_CACHED: NTSTATUS = 0xC0040039; +pub const STATUS_MUI_FILE_NOT_FOUND: NTSTATUS = 0xC00B0001; +pub const STATUS_MUI_INVALID_FILE: NTSTATUS = 0xC00B0002; +pub const STATUS_MUI_INVALID_RC_CONFIG: NTSTATUS = 0xC00B0003; +pub const STATUS_MUI_INVALID_LOCALE_NAME: NTSTATUS = 0xC00B0004; +pub const STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME: NTSTATUS = 0xC00B0005; +pub const STATUS_MUI_FILE_NOT_LOADED: NTSTATUS = 0xC00B0006; +pub const STATUS_RESOURCE_ENUM_USER_STOP: NTSTATUS = 0xC00B0007; +//FILTER_FLT_NTSTATUS_FROM_HRESULT +pub const STATUS_FLT_NO_HANDLER_DEFINED: NTSTATUS = 0xC01C0001; +pub const STATUS_FLT_CONTEXT_ALREADY_DEFINED: NTSTATUS = 0xC01C0002; +pub const STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST: NTSTATUS = 0xC01C0003; +pub const STATUS_FLT_DISALLOW_FAST_IO: NTSTATUS = 0xC01C0004; +pub const STATUS_FLT_INVALID_NAME_REQUEST: NTSTATUS = 0xC01C0005; +pub const STATUS_FLT_NOT_SAFE_TO_POST_OPERATION: NTSTATUS = 0xC01C0006; +pub const STATUS_FLT_NOT_INITIALIZED: NTSTATUS = 0xC01C0007; +pub const STATUS_FLT_FILTER_NOT_READY: NTSTATUS = 0xC01C0008; +pub const STATUS_FLT_POST_OPERATION_CLEANUP: NTSTATUS = 0xC01C0009; +pub const STATUS_FLT_INTERNAL_ERROR: NTSTATUS = 0xC01C000A; +pub const STATUS_FLT_DELETING_OBJECT: NTSTATUS = 0xC01C000B; +pub const STATUS_FLT_MUST_BE_NONPAGED_POOL: NTSTATUS = 0xC01C000C; +pub const STATUS_FLT_DUPLICATE_ENTRY: NTSTATUS = 0xC01C000D; +pub const STATUS_FLT_CBDQ_DISABLED: NTSTATUS = 0xC01C000E; +pub const STATUS_FLT_DO_NOT_ATTACH: NTSTATUS = 0xC01C000F; +pub const STATUS_FLT_DO_NOT_DETACH: NTSTATUS = 0xC01C0010; +pub const STATUS_FLT_INSTANCE_ALTITUDE_COLLISION: NTSTATUS = 0xC01C0011; +pub const STATUS_FLT_INSTANCE_NAME_COLLISION: NTSTATUS = 0xC01C0012; +pub const STATUS_FLT_FILTER_NOT_FOUND: NTSTATUS = 0xC01C0013; +pub const STATUS_FLT_VOLUME_NOT_FOUND: NTSTATUS = 0xC01C0014; +pub const STATUS_FLT_INSTANCE_NOT_FOUND: NTSTATUS = 0xC01C0015; +pub const STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND: NTSTATUS = 0xC01C0016; +pub const STATUS_FLT_INVALID_CONTEXT_REGISTRATION: NTSTATUS = 0xC01C0017; +pub const STATUS_FLT_NAME_CACHE_MISS: NTSTATUS = 0xC01C0018; +pub const STATUS_FLT_NO_DEVICE_OBJECT: NTSTATUS = 0xC01C0019; +pub const STATUS_FLT_VOLUME_ALREADY_MOUNTED: NTSTATUS = 0xC01C001A; +pub const STATUS_FLT_ALREADY_ENLISTED: NTSTATUS = 0xC01C001B; +pub const STATUS_FLT_CONTEXT_ALREADY_LINKED: NTSTATUS = 0xC01C001C; +pub const STATUS_FLT_NO_WAITER_FOR_REPLY: NTSTATUS = 0xC01C0020; +pub const STATUS_FLT_REGISTRATION_BUSY: NTSTATUS = 0xC01C0023; +pub const STATUS_SXS_SECTION_NOT_FOUND: NTSTATUS = 0xC0150001; +pub const STATUS_SXS_CANT_GEN_ACTCTX: NTSTATUS = 0xC0150002; +pub const STATUS_SXS_INVALID_ACTCTXDATA_FORMAT: NTSTATUS = 0xC0150003; +pub const STATUS_SXS_ASSEMBLY_NOT_FOUND: NTSTATUS = 0xC0150004; +pub const STATUS_SXS_MANIFEST_FORMAT_ERROR: NTSTATUS = 0xC0150005; +pub const STATUS_SXS_MANIFEST_PARSE_ERROR: NTSTATUS = 0xC0150006; +pub const STATUS_SXS_ACTIVATION_CONTEXT_DISABLED: NTSTATUS = 0xC0150007; +pub const STATUS_SXS_KEY_NOT_FOUND: NTSTATUS = 0xC0150008; +pub const STATUS_SXS_VERSION_CONFLICT: NTSTATUS = 0xC0150009; +pub const STATUS_SXS_WRONG_SECTION_TYPE: NTSTATUS = 0xC015000A; +pub const STATUS_SXS_THREAD_QUERIES_DISABLED: NTSTATUS = 0xC015000B; +pub const STATUS_SXS_ASSEMBLY_MISSING: NTSTATUS = 0xC015000C; +pub const STATUS_SXS_RELEASE_ACTIVATION_CONTEXT: NTSTATUS = 0x4015000D; +pub const STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET: NTSTATUS = 0xC015000E; +pub const STATUS_SXS_EARLY_DEACTIVATION: NTSTATUS = 0xC015000F; +pub const STATUS_SXS_INVALID_DEACTIVATION: NTSTATUS = 0xC0150010; +pub const STATUS_SXS_MULTIPLE_DEACTIVATION: NTSTATUS = 0xC0150011; +pub const STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: NTSTATUS = 0xC0150012; +pub const STATUS_SXS_PROCESS_TERMINATION_REQUESTED: NTSTATUS = 0xC0150013; +pub const STATUS_SXS_CORRUPT_ACTIVATION_STACK: NTSTATUS = 0xC0150014; +pub const STATUS_SXS_CORRUPTION: NTSTATUS = 0xC0150015; +pub const STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: NTSTATUS = 0xC0150016; +pub const STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: NTSTATUS = 0xC0150017; +pub const STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: NTSTATUS = 0xC0150018; +pub const STATUS_SXS_IDENTITY_PARSE_ERROR: NTSTATUS = 0xC0150019; +pub const STATUS_SXS_COMPONENT_STORE_CORRUPT: NTSTATUS = 0xC015001A; +pub const STATUS_SXS_FILE_HASH_MISMATCH: NTSTATUS = 0xC015001B; +pub const STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: NTSTATUS + = 0xC015001C; +pub const STATUS_SXS_IDENTITIES_DIFFERENT: NTSTATUS = 0xC015001D; +pub const STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: NTSTATUS = 0xC015001E; +pub const STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY: NTSTATUS = 0xC015001F; +pub const STATUS_ADVANCED_INSTALLER_FAILED: NTSTATUS = 0xC0150020; +pub const STATUS_XML_ENCODING_MISMATCH: NTSTATUS = 0xC0150021; +pub const STATUS_SXS_MANIFEST_TOO_BIG: NTSTATUS = 0xC0150022; +pub const STATUS_SXS_SETTING_NOT_REGISTERED: NTSTATUS = 0xC0150023; +pub const STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE: NTSTATUS = 0xC0150024; +pub const STATUS_SMI_PRIMITIVE_INSTALLER_FAILED: NTSTATUS = 0xC0150025; +pub const STATUS_GENERIC_COMMAND_FAILED: NTSTATUS = 0xC0150026; +pub const STATUS_SXS_FILE_HASH_MISSING: NTSTATUS = 0xC0150027; +pub const STATUS_CLUSTER_INVALID_NODE: NTSTATUS = 0xC0130001; +pub const STATUS_CLUSTER_NODE_EXISTS: NTSTATUS = 0xC0130002; +pub const STATUS_CLUSTER_JOIN_IN_PROGRESS: NTSTATUS = 0xC0130003; +pub const STATUS_CLUSTER_NODE_NOT_FOUND: NTSTATUS = 0xC0130004; +pub const STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND: NTSTATUS = 0xC0130005; +pub const STATUS_CLUSTER_NETWORK_EXISTS: NTSTATUS = 0xC0130006; +pub const STATUS_CLUSTER_NETWORK_NOT_FOUND: NTSTATUS = 0xC0130007; +pub const STATUS_CLUSTER_NETINTERFACE_EXISTS: NTSTATUS = 0xC0130008; +pub const STATUS_CLUSTER_NETINTERFACE_NOT_FOUND: NTSTATUS = 0xC0130009; +pub const STATUS_CLUSTER_INVALID_REQUEST: NTSTATUS = 0xC013000A; +pub const STATUS_CLUSTER_INVALID_NETWORK_PROVIDER: NTSTATUS = 0xC013000B; +pub const STATUS_CLUSTER_NODE_DOWN: NTSTATUS = 0xC013000C; +pub const STATUS_CLUSTER_NODE_UNREACHABLE: NTSTATUS = 0xC013000D; +pub const STATUS_CLUSTER_NODE_NOT_MEMBER: NTSTATUS = 0xC013000E; +pub const STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS: NTSTATUS = 0xC013000F; +pub const STATUS_CLUSTER_INVALID_NETWORK: NTSTATUS = 0xC0130010; +pub const STATUS_CLUSTER_NO_NET_ADAPTERS: NTSTATUS = 0xC0130011; +pub const STATUS_CLUSTER_NODE_UP: NTSTATUS = 0xC0130012; +pub const STATUS_CLUSTER_NODE_PAUSED: NTSTATUS = 0xC0130013; +pub const STATUS_CLUSTER_NODE_NOT_PAUSED: NTSTATUS = 0xC0130014; +pub const STATUS_CLUSTER_NO_SECURITY_CONTEXT: NTSTATUS = 0xC0130015; +pub const STATUS_CLUSTER_NETWORK_NOT_INTERNAL: NTSTATUS = 0xC0130016; +pub const STATUS_CLUSTER_POISONED: NTSTATUS = 0xC0130017; +pub const STATUS_CLUSTER_NON_CSV_PATH: NTSTATUS = 0xC0130018; +pub const STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL: NTSTATUS = 0xC0130019; +pub const STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS: NTSTATUS = 0xC0130020; +pub const STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR: NTSTATUS = 0xC0130021; +pub const STATUS_CLUSTER_CSV_REDIRECTED: NTSTATUS = 0xC0130022; +pub const STATUS_CLUSTER_CSV_NOT_REDIRECTED: NTSTATUS = 0xC0130023; +pub const STATUS_CLUSTER_CSV_VOLUME_DRAINING: NTSTATUS = 0xC0130024; +pub const STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS: NTSTATUS = 0xC0130025; +pub const STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL: NTSTATUS = 0xC0130026; +pub const STATUS_CLUSTER_CSV_NO_SNAPSHOTS: NTSTATUS = 0xC0130027; +pub const STATUS_CSV_IO_PAUSE_TIMEOUT: NTSTATUS = 0xC0130028; +pub const STATUS_CLUSTER_CSV_INVALID_HANDLE: NTSTATUS = 0xC0130029; +pub const STATUS_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR: NTSTATUS = 0xC0130030; +pub const STATUS_TRANSACTIONAL_CONFLICT: NTSTATUS = 0xC0190001; +pub const STATUS_INVALID_TRANSACTION: NTSTATUS = 0xC0190002; +pub const STATUS_TRANSACTION_NOT_ACTIVE: NTSTATUS = 0xC0190003; +pub const STATUS_TM_INITIALIZATION_FAILED: NTSTATUS = 0xC0190004; +pub const STATUS_RM_NOT_ACTIVE: NTSTATUS = 0xC0190005; +pub const STATUS_RM_METADATA_CORRUPT: NTSTATUS = 0xC0190006; +pub const STATUS_TRANSACTION_NOT_JOINED: NTSTATUS = 0xC0190007; +pub const STATUS_DIRECTORY_NOT_RM: NTSTATUS = 0xC0190008; +pub const STATUS_COULD_NOT_RESIZE_LOG: NTSTATUS = 0x80190009; +pub const STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE: NTSTATUS = 0xC019000A; +pub const STATUS_LOG_RESIZE_INVALID_SIZE: NTSTATUS = 0xC019000B; +pub const STATUS_REMOTE_FILE_VERSION_MISMATCH: NTSTATUS = 0xC019000C; +pub const STATUS_CRM_PROTOCOL_ALREADY_EXISTS: NTSTATUS = 0xC019000F; +pub const STATUS_TRANSACTION_PROPAGATION_FAILED: NTSTATUS = 0xC0190010; +pub const STATUS_CRM_PROTOCOL_NOT_FOUND: NTSTATUS = 0xC0190011; +pub const STATUS_TRANSACTION_SUPERIOR_EXISTS: NTSTATUS = 0xC0190012; +pub const STATUS_TRANSACTION_REQUEST_NOT_VALID: NTSTATUS = 0xC0190013; +pub const STATUS_TRANSACTION_NOT_REQUESTED: NTSTATUS = 0xC0190014; +pub const STATUS_TRANSACTION_ALREADY_ABORTED: NTSTATUS = 0xC0190015; +pub const STATUS_TRANSACTION_ALREADY_COMMITTED: NTSTATUS = 0xC0190016; +pub const STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER: NTSTATUS = 0xC0190017; +pub const STATUS_CURRENT_TRANSACTION_NOT_VALID: NTSTATUS = 0xC0190018; +pub const STATUS_LOG_GROWTH_FAILED: NTSTATUS = 0xC0190019; +pub const STATUS_OBJECT_NO_LONGER_EXISTS: NTSTATUS = 0xC0190021; +pub const STATUS_STREAM_MINIVERSION_NOT_FOUND: NTSTATUS = 0xC0190022; +pub const STATUS_STREAM_MINIVERSION_NOT_VALID: NTSTATUS = 0xC0190023; +pub const STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION: NTSTATUS + = 0xC0190024; +pub const STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT: NTSTATUS = 0xC0190025; +pub const STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS: NTSTATUS = 0xC0190026; +pub const STATUS_HANDLE_NO_LONGER_VALID: NTSTATUS = 0xC0190028; +pub const STATUS_NO_TXF_METADATA: NTSTATUS = 0x80190029; +pub const STATUS_LOG_CORRUPTION_DETECTED: NTSTATUS = 0xC0190030; +pub const STATUS_CANT_RECOVER_WITH_HANDLE_OPEN: NTSTATUS = 0x80190031; +pub const STATUS_RM_DISCONNECTED: NTSTATUS = 0xC0190032; +pub const STATUS_ENLISTMENT_NOT_SUPERIOR: NTSTATUS = 0xC0190033; +pub const STATUS_RECOVERY_NOT_NEEDED: NTSTATUS = 0x40190034; +pub const STATUS_RM_ALREADY_STARTED: NTSTATUS = 0x40190035; +pub const STATUS_FILE_IDENTITY_NOT_PERSISTENT: NTSTATUS = 0xC0190036; +pub const STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY: NTSTATUS = 0xC0190037; +pub const STATUS_CANT_CROSS_RM_BOUNDARY: NTSTATUS = 0xC0190038; +pub const STATUS_TXF_DIR_NOT_EMPTY: NTSTATUS = 0xC0190039; +pub const STATUS_INDOUBT_TRANSACTIONS_EXIST: NTSTATUS = 0xC019003A; +pub const STATUS_TM_VOLATILE: NTSTATUS = 0xC019003B; +pub const STATUS_ROLLBACK_TIMER_EXPIRED: NTSTATUS = 0xC019003C; +pub const STATUS_TXF_ATTRIBUTE_CORRUPT: NTSTATUS = 0xC019003D; +pub const STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION: NTSTATUS = 0xC019003E; +pub const STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED: NTSTATUS = 0xC019003F; +pub const STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE: NTSTATUS = 0xC0190040; +pub const STATUS_TXF_METADATA_ALREADY_PRESENT: NTSTATUS = 0x80190041; +pub const STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: NTSTATUS = 0x80190042; +pub const STATUS_TRANSACTION_REQUIRED_PROMOTION: NTSTATUS = 0xC0190043; +pub const STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION: NTSTATUS = 0xC0190044; +pub const STATUS_TRANSACTIONS_NOT_FROZEN: NTSTATUS = 0xC0190045; +pub const STATUS_TRANSACTION_FREEZE_IN_PROGRESS: NTSTATUS = 0xC0190046; +pub const STATUS_NOT_SNAPSHOT_VOLUME: NTSTATUS = 0xC0190047; +pub const STATUS_NO_SAVEPOINT_WITH_OPEN_FILES: NTSTATUS = 0xC0190048; +pub const STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION: NTSTATUS = 0xC0190049; +pub const STATUS_TM_IDENTITY_MISMATCH: NTSTATUS = 0xC019004A; +pub const STATUS_FLOATED_SECTION: NTSTATUS = 0xC019004B; +pub const STATUS_CANNOT_ACCEPT_TRANSACTED_WORK: NTSTATUS = 0xC019004C; +pub const STATUS_CANNOT_ABORT_TRANSACTIONS: NTSTATUS = 0xC019004D; +pub const STATUS_TRANSACTION_NOT_FOUND: NTSTATUS = 0xC019004E; +pub const STATUS_RESOURCEMANAGER_NOT_FOUND: NTSTATUS = 0xC019004F; +pub const STATUS_ENLISTMENT_NOT_FOUND: NTSTATUS = 0xC0190050; +pub const STATUS_TRANSACTIONMANAGER_NOT_FOUND: NTSTATUS = 0xC0190051; +pub const STATUS_TRANSACTIONMANAGER_NOT_ONLINE: NTSTATUS = 0xC0190052; +pub const STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION: NTSTATUS = 0xC0190053; +pub const STATUS_TRANSACTION_NOT_ROOT: NTSTATUS = 0xC0190054; +pub const STATUS_TRANSACTION_OBJECT_EXPIRED: NTSTATUS = 0xC0190055; +pub const STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION: NTSTATUS = 0xC0190056; +pub const STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED: NTSTATUS = 0xC0190057; +pub const STATUS_TRANSACTION_RECORD_TOO_LONG: NTSTATUS = 0xC0190058; +pub const STATUS_NO_LINK_TRACKING_IN_TRANSACTION: NTSTATUS = 0xC0190059; +pub const STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION: NTSTATUS = 0xC019005A; +pub const STATUS_TRANSACTION_INTEGRITY_VIOLATED: NTSTATUS = 0xC019005B; +pub const STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH: NTSTATUS = 0xC019005C; +pub const STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT: NTSTATUS = 0xC019005D; +pub const STATUS_TRANSACTION_MUST_WRITETHROUGH: NTSTATUS = 0xC019005E; +pub const STATUS_TRANSACTION_NO_SUPERIOR: NTSTATUS = 0xC019005F; +pub const STATUS_EXPIRED_HANDLE: NTSTATUS = 0xC0190060; +pub const STATUS_TRANSACTION_NOT_ENLISTED: NTSTATUS = 0xC0190061; +pub const STATUS_LOG_SECTOR_INVALID: NTSTATUS = 0xC01A0001; +pub const STATUS_LOG_SECTOR_PARITY_INVALID: NTSTATUS = 0xC01A0002; +pub const STATUS_LOG_SECTOR_REMAPPED: NTSTATUS = 0xC01A0003; +pub const STATUS_LOG_BLOCK_INCOMPLETE: NTSTATUS = 0xC01A0004; +pub const STATUS_LOG_INVALID_RANGE: NTSTATUS = 0xC01A0005; +pub const STATUS_LOG_BLOCKS_EXHAUSTED: NTSTATUS = 0xC01A0006; +pub const STATUS_LOG_READ_CONTEXT_INVALID: NTSTATUS = 0xC01A0007; +pub const STATUS_LOG_RESTART_INVALID: NTSTATUS = 0xC01A0008; +pub const STATUS_LOG_BLOCK_VERSION: NTSTATUS = 0xC01A0009; +pub const STATUS_LOG_BLOCK_INVALID: NTSTATUS = 0xC01A000A; +pub const STATUS_LOG_READ_MODE_INVALID: NTSTATUS = 0xC01A000B; +pub const STATUS_LOG_NO_RESTART: NTSTATUS = 0x401A000C; +pub const STATUS_LOG_METADATA_CORRUPT: NTSTATUS = 0xC01A000D; +pub const STATUS_LOG_METADATA_INVALID: NTSTATUS = 0xC01A000E; +pub const STATUS_LOG_METADATA_INCONSISTENT: NTSTATUS = 0xC01A000F; +pub const STATUS_LOG_RESERVATION_INVALID: NTSTATUS = 0xC01A0010; +pub const STATUS_LOG_CANT_DELETE: NTSTATUS = 0xC01A0011; +pub const STATUS_LOG_CONTAINER_LIMIT_EXCEEDED: NTSTATUS = 0xC01A0012; +pub const STATUS_LOG_START_OF_LOG: NTSTATUS = 0xC01A0013; +pub const STATUS_LOG_POLICY_ALREADY_INSTALLED: NTSTATUS = 0xC01A0014; +pub const STATUS_LOG_POLICY_NOT_INSTALLED: NTSTATUS = 0xC01A0015; +pub const STATUS_LOG_POLICY_INVALID: NTSTATUS = 0xC01A0016; +pub const STATUS_LOG_POLICY_CONFLICT: NTSTATUS = 0xC01A0017; +pub const STATUS_LOG_PINNED_ARCHIVE_TAIL: NTSTATUS = 0xC01A0018; +pub const STATUS_LOG_RECORD_NONEXISTENT: NTSTATUS = 0xC01A0019; +pub const STATUS_LOG_RECORDS_RESERVED_INVALID: NTSTATUS = 0xC01A001A; +pub const STATUS_LOG_SPACE_RESERVED_INVALID: NTSTATUS = 0xC01A001B; +pub const STATUS_LOG_TAIL_INVALID: NTSTATUS = 0xC01A001C; +pub const STATUS_LOG_FULL: NTSTATUS = 0xC01A001D; +pub const STATUS_LOG_MULTIPLEXED: NTSTATUS = 0xC01A001E; +pub const STATUS_LOG_DEDICATED: NTSTATUS = 0xC01A001F; +pub const STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS: NTSTATUS = 0xC01A0020; +pub const STATUS_LOG_ARCHIVE_IN_PROGRESS: NTSTATUS = 0xC01A0021; +pub const STATUS_LOG_EPHEMERAL: NTSTATUS = 0xC01A0022; +pub const STATUS_LOG_NOT_ENOUGH_CONTAINERS: NTSTATUS = 0xC01A0023; +pub const STATUS_LOG_CLIENT_ALREADY_REGISTERED: NTSTATUS = 0xC01A0024; +pub const STATUS_LOG_CLIENT_NOT_REGISTERED: NTSTATUS = 0xC01A0025; +pub const STATUS_LOG_FULL_HANDLER_IN_PROGRESS: NTSTATUS = 0xC01A0026; +pub const STATUS_LOG_CONTAINER_READ_FAILED: NTSTATUS = 0xC01A0027; +pub const STATUS_LOG_CONTAINER_WRITE_FAILED: NTSTATUS = 0xC01A0028; +pub const STATUS_LOG_CONTAINER_OPEN_FAILED: NTSTATUS = 0xC01A0029; +pub const STATUS_LOG_CONTAINER_STATE_INVALID: NTSTATUS = 0xC01A002A; +pub const STATUS_LOG_STATE_INVALID: NTSTATUS = 0xC01A002B; +pub const STATUS_LOG_PINNED: NTSTATUS = 0xC01A002C; +pub const STATUS_LOG_METADATA_FLUSH_FAILED: NTSTATUS = 0xC01A002D; +pub const STATUS_LOG_INCONSISTENT_SECURITY: NTSTATUS = 0xC01A002E; +pub const STATUS_LOG_APPENDED_FLUSH_FAILED: NTSTATUS = 0xC01A002F; +pub const STATUS_LOG_PINNED_RESERVATION: NTSTATUS = 0xC01A0030; +pub const STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD: NTSTATUS = 0xC01B00EA; +pub const STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED: NTSTATUS = 0x801B00EB; +pub const STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST: NTSTATUS = 0x401B00EC; +pub const STATUS_MONITOR_NO_DESCRIPTOR: NTSTATUS = 0xC01D0001; +pub const STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT: NTSTATUS = 0xC01D0002; +pub const STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM: NTSTATUS = 0xC01D0003; +pub const STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK: NTSTATUS = 0xC01D0004; +pub const STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED: NTSTATUS = 0xC01D0005; +pub const STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK: NTSTATUS = 0xC01D0006; +pub const STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK: NTSTATUS = 0xC01D0007; +pub const STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA: NTSTATUS = 0xC01D0008; +pub const STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK: NTSTATUS = 0xC01D0009; +pub const STATUS_MONITOR_INVALID_MANUFACTURE_DATE: NTSTATUS = 0xC01D000A; +pub const STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER: NTSTATUS = 0xC01E0000; +pub const STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER: NTSTATUS = 0xC01E0001; +pub const STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER: NTSTATUS = 0xC01E0002; +pub const STATUS_GRAPHICS_ADAPTER_WAS_RESET: NTSTATUS = 0xC01E0003; +pub const STATUS_GRAPHICS_INVALID_DRIVER_MODEL: NTSTATUS = 0xC01E0004; +pub const STATUS_GRAPHICS_PRESENT_MODE_CHANGED: NTSTATUS = 0xC01E0005; +pub const STATUS_GRAPHICS_PRESENT_OCCLUDED: NTSTATUS = 0xC01E0006; +pub const STATUS_GRAPHICS_PRESENT_DENIED: NTSTATUS = 0xC01E0007; +pub const STATUS_GRAPHICS_CANNOTCOLORCONVERT: NTSTATUS = 0xC01E0008; +pub const STATUS_GRAPHICS_DRIVER_MISMATCH: NTSTATUS = 0xC01E0009; +pub const STATUS_GRAPHICS_PARTIAL_DATA_POPULATED: NTSTATUS = 0x401E000A; +pub const STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED: NTSTATUS = 0xC01E000B; +pub const STATUS_GRAPHICS_PRESENT_UNOCCLUDED: NTSTATUS = 0xC01E000C; +pub const STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE: NTSTATUS = 0xC01E000D; +pub const STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED: NTSTATUS = 0xC01E000E; +pub const STATUS_GRAPHICS_NO_VIDEO_MEMORY: NTSTATUS = 0xC01E0100; +pub const STATUS_GRAPHICS_CANT_LOCK_MEMORY: NTSTATUS = 0xC01E0101; +pub const STATUS_GRAPHICS_ALLOCATION_BUSY: NTSTATUS = 0xC01E0102; +pub const STATUS_GRAPHICS_TOO_MANY_REFERENCES: NTSTATUS = 0xC01E0103; +pub const STATUS_GRAPHICS_TRY_AGAIN_LATER: NTSTATUS = 0xC01E0104; +pub const STATUS_GRAPHICS_TRY_AGAIN_NOW: NTSTATUS = 0xC01E0105; +pub const STATUS_GRAPHICS_ALLOCATION_INVALID: NTSTATUS = 0xC01E0106; +pub const STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE: NTSTATUS = 0xC01E0107; +pub const STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED: NTSTATUS = 0xC01E0108; +pub const STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION: NTSTATUS = 0xC01E0109; +pub const STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE: NTSTATUS = 0xC01E0110; +pub const STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION: NTSTATUS = 0xC01E0111; +pub const STATUS_GRAPHICS_ALLOCATION_CLOSED: NTSTATUS = 0xC01E0112; +pub const STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE: NTSTATUS = 0xC01E0113; +pub const STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE: NTSTATUS = 0xC01E0114; +pub const STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE: NTSTATUS = 0xC01E0115; +pub const STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST: NTSTATUS = 0xC01E0116; +pub const STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE: NTSTATUS = 0xC01E0200; +pub const STATUS_GRAPHICS_SKIP_ALLOCATION_PREPARATION: NTSTATUS = 0x401E0201; +pub const STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY: NTSTATUS = 0xC01E0300; +pub const STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED: NTSTATUS = 0xC01E0301; +pub const STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED: NTSTATUS = 0xC01E0302; +pub const STATUS_GRAPHICS_INVALID_VIDPN: NTSTATUS = 0xC01E0303; +pub const STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE: NTSTATUS = 0xC01E0304; +pub const STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET: NTSTATUS = 0xC01E0305; +pub const STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED: NTSTATUS = 0xC01E0306; +pub const STATUS_GRAPHICS_MODE_NOT_PINNED: NTSTATUS = 0x401E0307; +pub const STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET: NTSTATUS = 0xC01E0308; +pub const STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET: NTSTATUS = 0xC01E0309; +pub const STATUS_GRAPHICS_INVALID_FREQUENCY: NTSTATUS = 0xC01E030A; +pub const STATUS_GRAPHICS_INVALID_ACTIVE_REGION: NTSTATUS = 0xC01E030B; +pub const STATUS_GRAPHICS_INVALID_TOTAL_REGION: NTSTATUS = 0xC01E030C; +pub const STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE: NTSTATUS = 0xC01E0310; +pub const STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE: NTSTATUS = 0xC01E0311; +pub const STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET: NTSTATUS = 0xC01E0312; +pub const STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY: NTSTATUS = 0xC01E0313; +pub const STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET: NTSTATUS = 0xC01E0314; +pub const STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET: NTSTATUS = 0xC01E0315; +pub const STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET: NTSTATUS = 0xC01E0316; +pub const STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET: NTSTATUS = 0xC01E0317; +pub const STATUS_GRAPHICS_TARGET_ALREADY_IN_SET: NTSTATUS = 0xC01E0318; +pub const STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH: NTSTATUS = 0xC01E0319; +pub const STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY: NTSTATUS = 0xC01E031A; +pub const STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET: NTSTATUS = 0xC01E031B; +pub const STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE: NTSTATUS = 0xC01E031C; +pub const STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET: NTSTATUS = 0xC01E031D; +pub const STATUS_GRAPHICS_NO_PREFERRED_MODE: NTSTATUS = 0x401E031E; +pub const STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET: NTSTATUS = 0xC01E031F; +pub const STATUS_GRAPHICS_STALE_MODESET: NTSTATUS = 0xC01E0320; +pub const STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET: NTSTATUS = 0xC01E0321; +pub const STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE: NTSTATUS = 0xC01E0322; +pub const STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN: NTSTATUS = 0xC01E0323; +pub const STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE: NTSTATUS = 0xC01E0324; +pub const STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION: NTSTATUS + = 0xC01E0325; +pub const STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES: NTSTATUS = 0xC01E0326; +pub const STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY: NTSTATUS = 0xC01E0327; +pub const STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE: NTSTATUS = 0xC01E0328; +pub const STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET: NTSTATUS = 0xC01E0329; +pub const STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET: NTSTATUS = 0xC01E032A; +pub const STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR: NTSTATUS = 0xC01E032B; +pub const STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET: NTSTATUS = 0xC01E032C; +pub const STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET: NTSTATUS = 0xC01E032D; +pub const STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE: NTSTATUS = 0xC01E032E; +pub const STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE: NTSTATUS = 0xC01E032F; +pub const STATUS_GRAPHICS_RESOURCES_NOT_RELATED: NTSTATUS = 0xC01E0330; +pub const STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE: NTSTATUS = 0xC01E0331; +pub const STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE: NTSTATUS = 0xC01E0332; +pub const STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET: NTSTATUS = 0xC01E0333; +pub const STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER: NTSTATUS + = 0xC01E0334; +pub const STATUS_GRAPHICS_NO_VIDPNMGR: NTSTATUS = 0xC01E0335; +pub const STATUS_GRAPHICS_NO_ACTIVE_VIDPN: NTSTATUS = 0xC01E0336; +pub const STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY: NTSTATUS = 0xC01E0337; +pub const STATUS_GRAPHICS_MONITOR_NOT_CONNECTED: NTSTATUS = 0xC01E0338; +pub const STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY: NTSTATUS = 0xC01E0339; +pub const STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE: NTSTATUS = 0xC01E033A; +pub const STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE: NTSTATUS = 0xC01E033B; +pub const STATUS_GRAPHICS_INVALID_STRIDE: NTSTATUS = 0xC01E033C; +pub const STATUS_GRAPHICS_INVALID_PIXELFORMAT: NTSTATUS = 0xC01E033D; +pub const STATUS_GRAPHICS_INVALID_COLORBASIS: NTSTATUS = 0xC01E033E; +pub const STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE: NTSTATUS = 0xC01E033F; +pub const STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY: NTSTATUS = 0xC01E0340; +pub const STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT: NTSTATUS = 0xC01E0341; +pub const STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: NTSTATUS = 0xC01E0342; +pub const STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN: NTSTATUS = 0xC01E0343; +pub const STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL: NTSTATUS = 0xC01E0344; +pub const STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION: NTSTATUS + = 0xC01E0345; +pub const STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED: NTSTATUS + = 0xC01E0346; +pub const STATUS_GRAPHICS_INVALID_GAMMA_RAMP: NTSTATUS = 0xC01E0347; +pub const STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED: NTSTATUS = 0xC01E0348; +pub const STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED: NTSTATUS = 0xC01E0349; +pub const STATUS_GRAPHICS_MODE_NOT_IN_MODESET: NTSTATUS = 0xC01E034A; +pub const STATUS_GRAPHICS_DATASET_IS_EMPTY: NTSTATUS = 0x401E034B; +pub const STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: NTSTATUS = 0x401E034C; +pub const STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON: NTSTATUS + = 0xC01E034D; +pub const STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE: NTSTATUS = 0xC01E034E; +pub const STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE: NTSTATUS = 0xC01E034F; +pub const STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS: NTSTATUS = 0xC01E0350; +pub const STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: NTSTATUS = 0x401E0351; +pub const STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING: NTSTATUS = 0xC01E0352; +pub const STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED: NTSTATUS = 0xC01E0353; +pub const STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS: NTSTATUS = 0xC01E0354; +pub const STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT: NTSTATUS = 0xC01E0355; +pub const STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM: NTSTATUS = 0xC01E0356; +pub const STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN: NTSTATUS = 0xC01E0357; +pub const STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT: NTSTATUS + = 0xC01E0358; +pub const STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED: NTSTATUS = 0xC01E0359; +pub const STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION: NTSTATUS = 0xC01E035A; +pub const STATUS_GRAPHICS_INVALID_CLIENT_TYPE: NTSTATUS = 0xC01E035B; +pub const STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET: NTSTATUS = 0xC01E035C; +pub const STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED: NTSTATUS = 0xC01E0400; +pub const STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED: NTSTATUS = 0xC01E0401; +pub const STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS: NTSTATUS = 0x401E042F; +pub const STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER: NTSTATUS = 0xC01E0430; +pub const STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED: NTSTATUS = 0xC01E0431; +pub const STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED: NTSTATUS = 0xC01E0432; +pub const STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY: NTSTATUS = 0xC01E0433; +pub const STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED: NTSTATUS = 0xC01E0434; +pub const STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON: NTSTATUS = 0xC01E0435; +pub const STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE: NTSTATUS = 0xC01E0436; +pub const STATUS_GRAPHICS_LEADLINK_START_DEFERRED: NTSTATUS = 0x401E0437; +pub const STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER: NTSTATUS = 0xC01E0438; +pub const STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY: NTSTATUS = 0x401E0439; +pub const STATUS_GRAPHICS_START_DEFERRED: NTSTATUS = 0x401E043A; +pub const STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED: NTSTATUS = 0xC01E043B; +pub const STATUS_GRAPHICS_DEPENDABLE_CHILD_STATUS: NTSTATUS = 0x401E043C; +pub const STATUS_GRAPHICS_OPM_NOT_SUPPORTED: NTSTATUS = 0xC01E0500; +pub const STATUS_GRAPHICS_COPP_NOT_SUPPORTED: NTSTATUS = 0xC01E0501; +pub const STATUS_GRAPHICS_UAB_NOT_SUPPORTED: NTSTATUS = 0xC01E0502; +pub const STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS: NTSTATUS = 0xC01E0503; +pub const STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST: NTSTATUS = 0xC01E0505; +pub const STATUS_GRAPHICS_OPM_INTERNAL_ERROR: NTSTATUS = 0xC01E050B; +pub const STATUS_GRAPHICS_OPM_INVALID_HANDLE: NTSTATUS = 0xC01E050C; +pub const STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH: NTSTATUS = 0xC01E050E; +pub const STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED: NTSTATUS = 0xC01E050F; +pub const STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED: NTSTATUS = 0xC01E0510; +pub const STATUS_GRAPHICS_PVP_HFS_FAILED: NTSTATUS = 0xC01E0511; +pub const STATUS_GRAPHICS_OPM_INVALID_SRM: NTSTATUS = 0xC01E0512; +pub const STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP: NTSTATUS = 0xC01E0513; +pub const STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP: NTSTATUS = 0xC01E0514; +pub const STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA: NTSTATUS = 0xC01E0515; +pub const STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET: NTSTATUS = 0xC01E0516; +pub const STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH: NTSTATUS = 0xC01E0517; +pub const STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE: NTSTATUS = 0xC01E0518; +pub const STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS: NTSTATUS = 0xC01E051A; +pub const STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS: NTSTATUS + = 0xC01E051C; +pub const STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST: NTSTATUS = 0xC01E051D; +pub const STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR: NTSTATUS = 0xC01E051E; +pub const STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS: NTSTATUS + = 0xC01E051F; +pub const STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED: NTSTATUS = 0xC01E0520; +pub const STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST: NTSTATUS = 0xC01E0521; +pub const STATUS_GRAPHICS_I2C_NOT_SUPPORTED: NTSTATUS = 0xC01E0580; +pub const STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST: NTSTATUS = 0xC01E0581; +pub const STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA: NTSTATUS = 0xC01E0582; +pub const STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA: NTSTATUS = 0xC01E0583; +pub const STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED: NTSTATUS = 0xC01E0584; +pub const STATUS_GRAPHICS_DDCCI_INVALID_DATA: NTSTATUS = 0xC01E0585; +pub const STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE: NTSTATUS + = 0xC01E0586; +pub const STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING: NTSTATUS = 0xC01E0587; +pub const STATUS_GRAPHICS_MCA_INTERNAL_ERROR: NTSTATUS = 0xC01E0588; +pub const STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND: NTSTATUS = 0xC01E0589; +pub const STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH: NTSTATUS = 0xC01E058A; +pub const STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM: NTSTATUS = 0xC01E058B; +pub const STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE: NTSTATUS = 0xC01E058C; +pub const STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS: NTSTATUS = 0xC01E058D; +pub const STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED: NTSTATUS = 0xC01E05E0; +pub const STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: NTSTATUS = 0xC01E05E1; +pub const STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: NTSTATUS = 0xC01E05E2; +pub const STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED: NTSTATUS = 0xC01E05E3; +pub const STATUS_GRAPHICS_INVALID_POINTER: NTSTATUS = 0xC01E05E4; +pub const STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: NTSTATUS + = 0xC01E05E5; +pub const STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL: NTSTATUS = 0xC01E05E6; +pub const STATUS_GRAPHICS_INTERNAL_ERROR: NTSTATUS = 0xC01E05E7; +pub const STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS: NTSTATUS = 0xC01E05E8; +pub const STATUS_FVE_LOCKED_VOLUME: NTSTATUS = 0xC0210000; +pub const STATUS_FVE_NOT_ENCRYPTED: NTSTATUS = 0xC0210001; +pub const STATUS_FVE_BAD_INFORMATION: NTSTATUS = 0xC0210002; +pub const STATUS_FVE_TOO_SMALL: NTSTATUS = 0xC0210003; +pub const STATUS_FVE_FAILED_WRONG_FS: NTSTATUS = 0xC0210004; +pub const STATUS_FVE_BAD_PARTITION_SIZE: NTSTATUS = 0xC0210005; +pub const STATUS_FVE_FS_NOT_EXTENDED: NTSTATUS = 0xC0210006; +pub const STATUS_FVE_FS_MOUNTED: NTSTATUS = 0xC0210007; +pub const STATUS_FVE_NO_LICENSE: NTSTATUS = 0xC0210008; +pub const STATUS_FVE_ACTION_NOT_ALLOWED: NTSTATUS = 0xC0210009; +pub const STATUS_FVE_BAD_DATA: NTSTATUS = 0xC021000A; +pub const STATUS_FVE_VOLUME_NOT_BOUND: NTSTATUS = 0xC021000B; +pub const STATUS_FVE_NOT_DATA_VOLUME: NTSTATUS = 0xC021000C; +pub const STATUS_FVE_CONV_READ_ERROR: NTSTATUS = 0xC021000D; +pub const STATUS_FVE_CONV_WRITE_ERROR: NTSTATUS = 0xC021000E; +pub const STATUS_FVE_OVERLAPPED_UPDATE: NTSTATUS = 0xC021000F; +pub const STATUS_FVE_FAILED_SECTOR_SIZE: NTSTATUS = 0xC0210010; +pub const STATUS_FVE_FAILED_AUTHENTICATION: NTSTATUS = 0xC0210011; +pub const STATUS_FVE_NOT_OS_VOLUME: NTSTATUS = 0xC0210012; +pub const STATUS_FVE_KEYFILE_NOT_FOUND: NTSTATUS = 0xC0210013; +pub const STATUS_FVE_KEYFILE_INVALID: NTSTATUS = 0xC0210014; +pub const STATUS_FVE_KEYFILE_NO_VMK: NTSTATUS = 0xC0210015; +pub const STATUS_FVE_TPM_DISABLED: NTSTATUS = 0xC0210016; +pub const STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO: NTSTATUS = 0xC0210017; +pub const STATUS_FVE_TPM_INVALID_PCR: NTSTATUS = 0xC0210018; +pub const STATUS_FVE_TPM_NO_VMK: NTSTATUS = 0xC0210019; +pub const STATUS_FVE_PIN_INVALID: NTSTATUS = 0xC021001A; +pub const STATUS_FVE_AUTH_INVALID_APPLICATION: NTSTATUS = 0xC021001B; +pub const STATUS_FVE_AUTH_INVALID_CONFIG: NTSTATUS = 0xC021001C; +pub const STATUS_FVE_DEBUGGER_ENABLED: NTSTATUS = 0xC021001D; +pub const STATUS_FVE_DRY_RUN_FAILED: NTSTATUS = 0xC021001E; +pub const STATUS_FVE_BAD_METADATA_POINTER: NTSTATUS = 0xC021001F; +pub const STATUS_FVE_OLD_METADATA_COPY: NTSTATUS = 0xC0210020; +pub const STATUS_FVE_REBOOT_REQUIRED: NTSTATUS = 0xC0210021; +pub const STATUS_FVE_RAW_ACCESS: NTSTATUS = 0xC0210022; +pub const STATUS_FVE_RAW_BLOCKED: NTSTATUS = 0xC0210023; +pub const STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY: NTSTATUS = 0xC0210024; +pub const STATUS_FVE_MOR_FAILED: NTSTATUS = 0xC0210025; +pub const STATUS_FVE_NO_FEATURE_LICENSE: NTSTATUS = 0xC0210026; +pub const STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED: NTSTATUS = 0xC0210027; +pub const STATUS_FVE_CONV_RECOVERY_FAILED: NTSTATUS = 0xC0210028; +pub const STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG: NTSTATUS = 0xC0210029; +pub const STATUS_FVE_INVALID_DATUM_TYPE: NTSTATUS = 0xC021002A; +pub const STATUS_FVE_VOLUME_TOO_SMALL: NTSTATUS = 0xC0210030; +pub const STATUS_FVE_ENH_PIN_INVALID: NTSTATUS = 0xC0210031; +pub const STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE: NTSTATUS = 0xC0210032; +pub const STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE: NTSTATUS = 0xC0210033; +pub const STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK: NTSTATUS = 0xC0210034; +pub const STATUS_FVE_NOT_ALLOWED_ON_CLUSTER: NTSTATUS = 0xC0210035; +pub const STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING: NTSTATUS = 0xC0210036; +pub const STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE: NTSTATUS = 0xC0210037; +pub const STATUS_FVE_EDRIVE_DRY_RUN_FAILED: NTSTATUS = 0xC0210038; +pub const STATUS_FVE_SECUREBOOT_DISABLED: NTSTATUS = 0xC0210039; +pub const STATUS_FVE_SECUREBOOT_CONFIG_CHANGE: NTSTATUS = 0xC021003A; +pub const STATUS_FVE_DEVICE_LOCKEDOUT: NTSTATUS = 0xC021003B; +pub const STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT: NTSTATUS = 0xC021003C; +pub const STATUS_FVE_NOT_DE_VOLUME: NTSTATUS = 0xC021003D; +pub const STATUS_FVE_PROTECTION_DISABLED: NTSTATUS = 0xC021003E; +pub const STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED: NTSTATUS = 0xC021003F; +pub const STATUS_FWP_CALLOUT_NOT_FOUND: NTSTATUS = 0xC0220001; +pub const STATUS_FWP_CONDITION_NOT_FOUND: NTSTATUS = 0xC0220002; +pub const STATUS_FWP_FILTER_NOT_FOUND: NTSTATUS = 0xC0220003; +pub const STATUS_FWP_LAYER_NOT_FOUND: NTSTATUS = 0xC0220004; +pub const STATUS_FWP_PROVIDER_NOT_FOUND: NTSTATUS = 0xC0220005; +pub const STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND: NTSTATUS = 0xC0220006; +pub const STATUS_FWP_SUBLAYER_NOT_FOUND: NTSTATUS = 0xC0220007; +pub const STATUS_FWP_NOT_FOUND: NTSTATUS = 0xC0220008; +pub const STATUS_FWP_ALREADY_EXISTS: NTSTATUS = 0xC0220009; +pub const STATUS_FWP_IN_USE: NTSTATUS = 0xC022000A; +pub const STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS: NTSTATUS = 0xC022000B; +pub const STATUS_FWP_WRONG_SESSION: NTSTATUS = 0xC022000C; +pub const STATUS_FWP_NO_TXN_IN_PROGRESS: NTSTATUS = 0xC022000D; +pub const STATUS_FWP_TXN_IN_PROGRESS: NTSTATUS = 0xC022000E; +pub const STATUS_FWP_TXN_ABORTED: NTSTATUS = 0xC022000F; +pub const STATUS_FWP_SESSION_ABORTED: NTSTATUS = 0xC0220010; +pub const STATUS_FWP_INCOMPATIBLE_TXN: NTSTATUS = 0xC0220011; +pub const STATUS_FWP_TIMEOUT: NTSTATUS = 0xC0220012; +pub const STATUS_FWP_NET_EVENTS_DISABLED: NTSTATUS = 0xC0220013; +pub const STATUS_FWP_INCOMPATIBLE_LAYER: NTSTATUS = 0xC0220014; +pub const STATUS_FWP_KM_CLIENTS_ONLY: NTSTATUS = 0xC0220015; +pub const STATUS_FWP_LIFETIME_MISMATCH: NTSTATUS = 0xC0220016; +pub const STATUS_FWP_BUILTIN_OBJECT: NTSTATUS = 0xC0220017; +pub const STATUS_FWP_TOO_MANY_CALLOUTS: NTSTATUS = 0xC0220018; +pub const STATUS_FWP_NOTIFICATION_DROPPED: NTSTATUS = 0xC0220019; +pub const STATUS_FWP_TRAFFIC_MISMATCH: NTSTATUS = 0xC022001A; +pub const STATUS_FWP_INCOMPATIBLE_SA_STATE: NTSTATUS = 0xC022001B; +pub const STATUS_FWP_NULL_POINTER: NTSTATUS = 0xC022001C; +pub const STATUS_FWP_INVALID_ENUMERATOR: NTSTATUS = 0xC022001D; +pub const STATUS_FWP_INVALID_FLAGS: NTSTATUS = 0xC022001E; +pub const STATUS_FWP_INVALID_NET_MASK: NTSTATUS = 0xC022001F; +pub const STATUS_FWP_INVALID_RANGE: NTSTATUS = 0xC0220020; +pub const STATUS_FWP_INVALID_INTERVAL: NTSTATUS = 0xC0220021; +pub const STATUS_FWP_ZERO_LENGTH_ARRAY: NTSTATUS = 0xC0220022; +pub const STATUS_FWP_NULL_DISPLAY_NAME: NTSTATUS = 0xC0220023; +pub const STATUS_FWP_INVALID_ACTION_TYPE: NTSTATUS = 0xC0220024; +pub const STATUS_FWP_INVALID_WEIGHT: NTSTATUS = 0xC0220025; +pub const STATUS_FWP_MATCH_TYPE_MISMATCH: NTSTATUS = 0xC0220026; +pub const STATUS_FWP_TYPE_MISMATCH: NTSTATUS = 0xC0220027; +pub const STATUS_FWP_OUT_OF_BOUNDS: NTSTATUS = 0xC0220028; +pub const STATUS_FWP_RESERVED: NTSTATUS = 0xC0220029; +pub const STATUS_FWP_DUPLICATE_CONDITION: NTSTATUS = 0xC022002A; +pub const STATUS_FWP_DUPLICATE_KEYMOD: NTSTATUS = 0xC022002B; +pub const STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER: NTSTATUS = 0xC022002C; +pub const STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER: NTSTATUS = 0xC022002D; +pub const STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER: NTSTATUS = 0xC022002E; +pub const STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT: NTSTATUS = 0xC022002F; +pub const STATUS_FWP_INCOMPATIBLE_AUTH_METHOD: NTSTATUS = 0xC0220030; +pub const STATUS_FWP_INCOMPATIBLE_DH_GROUP: NTSTATUS = 0xC0220031; +pub const STATUS_FWP_EM_NOT_SUPPORTED: NTSTATUS = 0xC0220032; +pub const STATUS_FWP_NEVER_MATCH: NTSTATUS = 0xC0220033; +pub const STATUS_FWP_PROVIDER_CONTEXT_MISMATCH: NTSTATUS = 0xC0220034; +pub const STATUS_FWP_INVALID_PARAMETER: NTSTATUS = 0xC0220035; +pub const STATUS_FWP_TOO_MANY_SUBLAYERS: NTSTATUS = 0xC0220036; +pub const STATUS_FWP_CALLOUT_NOTIFICATION_FAILED: NTSTATUS = 0xC0220037; +pub const STATUS_FWP_INVALID_AUTH_TRANSFORM: NTSTATUS = 0xC0220038; +pub const STATUS_FWP_INVALID_CIPHER_TRANSFORM: NTSTATUS = 0xC0220039; +pub const STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM: NTSTATUS = 0xC022003A; +pub const STATUS_FWP_INVALID_TRANSFORM_COMBINATION: NTSTATUS = 0xC022003B; +pub const STATUS_FWP_DUPLICATE_AUTH_METHOD: NTSTATUS = 0xC022003C; +pub const STATUS_FWP_INVALID_TUNNEL_ENDPOINT: NTSTATUS = 0xC022003D; +pub const STATUS_FWP_L2_DRIVER_NOT_READY: NTSTATUS = 0xC022003E; +pub const STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED: NTSTATUS = 0xC022003F; +pub const STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL: NTSTATUS = 0xC0220040; +pub const STATUS_FWP_CONNECTIONS_DISABLED: NTSTATUS = 0xC0220041; +pub const STATUS_FWP_INVALID_DNS_NAME: NTSTATUS = 0xC0220042; +pub const STATUS_FWP_STILL_ON: NTSTATUS = 0xC0220043; +pub const STATUS_FWP_IKEEXT_NOT_RUNNING: NTSTATUS = 0xC0220044; +pub const STATUS_FWP_TCPIP_NOT_READY: NTSTATUS = 0xC0220100; +pub const STATUS_FWP_INJECT_HANDLE_CLOSING: NTSTATUS = 0xC0220101; +pub const STATUS_FWP_INJECT_HANDLE_STALE: NTSTATUS = 0xC0220102; +pub const STATUS_FWP_CANNOT_PEND: NTSTATUS = 0xC0220103; +pub const STATUS_FWP_DROP_NOICMP: NTSTATUS = 0xC0220104; +pub const STATUS_NDIS_CLOSING: NTSTATUS = 0xC0230002; +pub const STATUS_NDIS_BAD_VERSION: NTSTATUS = 0xC0230004; +pub const STATUS_NDIS_BAD_CHARACTERISTICS: NTSTATUS = 0xC0230005; +pub const STATUS_NDIS_ADAPTER_NOT_FOUND: NTSTATUS = 0xC0230006; +pub const STATUS_NDIS_OPEN_FAILED: NTSTATUS = 0xC0230007; +pub const STATUS_NDIS_DEVICE_FAILED: NTSTATUS = 0xC0230008; +pub const STATUS_NDIS_MULTICAST_FULL: NTSTATUS = 0xC0230009; +pub const STATUS_NDIS_MULTICAST_EXISTS: NTSTATUS = 0xC023000A; +pub const STATUS_NDIS_MULTICAST_NOT_FOUND: NTSTATUS = 0xC023000B; +pub const STATUS_NDIS_REQUEST_ABORTED: NTSTATUS = 0xC023000C; +pub const STATUS_NDIS_RESET_IN_PROGRESS: NTSTATUS = 0xC023000D; +pub const STATUS_NDIS_NOT_SUPPORTED: NTSTATUS = 0xC02300BB; +pub const STATUS_NDIS_INVALID_PACKET: NTSTATUS = 0xC023000F; +pub const STATUS_NDIS_ADAPTER_NOT_READY: NTSTATUS = 0xC0230011; +pub const STATUS_NDIS_INVALID_LENGTH: NTSTATUS = 0xC0230014; +pub const STATUS_NDIS_INVALID_DATA: NTSTATUS = 0xC0230015; +pub const STATUS_NDIS_BUFFER_TOO_SHORT: NTSTATUS = 0xC0230016; +pub const STATUS_NDIS_INVALID_OID: NTSTATUS = 0xC0230017; +pub const STATUS_NDIS_ADAPTER_REMOVED: NTSTATUS = 0xC0230018; +pub const STATUS_NDIS_UNSUPPORTED_MEDIA: NTSTATUS = 0xC0230019; +pub const STATUS_NDIS_GROUP_ADDRESS_IN_USE: NTSTATUS = 0xC023001A; +pub const STATUS_NDIS_FILE_NOT_FOUND: NTSTATUS = 0xC023001B; +pub const STATUS_NDIS_ERROR_READING_FILE: NTSTATUS = 0xC023001C; +pub const STATUS_NDIS_ALREADY_MAPPED: NTSTATUS = 0xC023001D; +pub const STATUS_NDIS_RESOURCE_CONFLICT: NTSTATUS = 0xC023001E; +pub const STATUS_NDIS_MEDIA_DISCONNECTED: NTSTATUS = 0xC023001F; +pub const STATUS_NDIS_INVALID_ADDRESS: NTSTATUS = 0xC0230022; +pub const STATUS_NDIS_INVALID_DEVICE_REQUEST: NTSTATUS = 0xC0230010; +pub const STATUS_NDIS_PAUSED: NTSTATUS = 0xC023002A; +pub const STATUS_NDIS_INTERFACE_NOT_FOUND: NTSTATUS = 0xC023002B; +pub const STATUS_NDIS_UNSUPPORTED_REVISION: NTSTATUS = 0xC023002C; +pub const STATUS_NDIS_INVALID_PORT: NTSTATUS = 0xC023002D; +pub const STATUS_NDIS_INVALID_PORT_STATE: NTSTATUS = 0xC023002E; +pub const STATUS_NDIS_LOW_POWER_STATE: NTSTATUS = 0xC023002F; +pub const STATUS_NDIS_REINIT_REQUIRED: NTSTATUS = 0xC0230030; +pub const STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED: NTSTATUS = 0xC0232000; +pub const STATUS_NDIS_DOT11_MEDIA_IN_USE: NTSTATUS = 0xC0232001; +pub const STATUS_NDIS_DOT11_POWER_STATE_INVALID: NTSTATUS = 0xC0232002; +pub const STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL: NTSTATUS = 0xC0232003; +pub const STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: NTSTATUS = 0xC0232004; +pub const STATUS_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE: NTSTATUS = 0xC0232005; +pub const STATUS_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE: NTSTATUS = 0xC0232006; +pub const STATUS_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED: NTSTATUS = 0xC0232007; +pub const STATUS_NDIS_DOT11_AP_BAND_NOT_ALLOWED: NTSTATUS = 0xC0232008; +pub const STATUS_NDIS_INDICATION_REQUIRED: NTSTATUS = 0x40230001; +pub const STATUS_NDIS_OFFLOAD_POLICY: NTSTATUS = 0xC023100F; +pub const STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED: NTSTATUS = 0xC0231012; +pub const STATUS_NDIS_OFFLOAD_PATH_REJECTED: NTSTATUS = 0xC0231013; +pub const STATUS_TPM_ERROR_MASK: NTSTATUS = 0xC0290000; +pub const STATUS_TPM_AUTHFAIL: NTSTATUS = 0xC0290001; +pub const STATUS_TPM_BADINDEX: NTSTATUS = 0xC0290002; +pub const STATUS_TPM_BAD_PARAMETER: NTSTATUS = 0xC0290003; +pub const STATUS_TPM_AUDITFAILURE: NTSTATUS = 0xC0290004; +pub const STATUS_TPM_CLEAR_DISABLED: NTSTATUS = 0xC0290005; +pub const STATUS_TPM_DEACTIVATED: NTSTATUS = 0xC0290006; +pub const STATUS_TPM_DISABLED: NTSTATUS = 0xC0290007; +pub const STATUS_TPM_DISABLED_CMD: NTSTATUS = 0xC0290008; +pub const STATUS_TPM_FAIL: NTSTATUS = 0xC0290009; +pub const STATUS_TPM_BAD_ORDINAL: NTSTATUS = 0xC029000A; +pub const STATUS_TPM_INSTALL_DISABLED: NTSTATUS = 0xC029000B; +pub const STATUS_TPM_INVALID_KEYHANDLE: NTSTATUS = 0xC029000C; +pub const STATUS_TPM_KEYNOTFOUND: NTSTATUS = 0xC029000D; +pub const STATUS_TPM_INAPPROPRIATE_ENC: NTSTATUS = 0xC029000E; +pub const STATUS_TPM_MIGRATEFAIL: NTSTATUS = 0xC029000F; +pub const STATUS_TPM_INVALID_PCR_INFO: NTSTATUS = 0xC0290010; +pub const STATUS_TPM_NOSPACE: NTSTATUS = 0xC0290011; +pub const STATUS_TPM_NOSRK: NTSTATUS = 0xC0290012; +pub const STATUS_TPM_NOTSEALED_BLOB: NTSTATUS = 0xC0290013; +pub const STATUS_TPM_OWNER_SET: NTSTATUS = 0xC0290014; +pub const STATUS_TPM_RESOURCES: NTSTATUS = 0xC0290015; +pub const STATUS_TPM_SHORTRANDOM: NTSTATUS = 0xC0290016; +pub const STATUS_TPM_SIZE: NTSTATUS = 0xC0290017; +pub const STATUS_TPM_WRONGPCRVAL: NTSTATUS = 0xC0290018; +pub const STATUS_TPM_BAD_PARAM_SIZE: NTSTATUS = 0xC0290019; +pub const STATUS_TPM_SHA_THREAD: NTSTATUS = 0xC029001A; +pub const STATUS_TPM_SHA_ERROR: NTSTATUS = 0xC029001B; +pub const STATUS_TPM_FAILEDSELFTEST: NTSTATUS = 0xC029001C; +pub const STATUS_TPM_AUTH2FAIL: NTSTATUS = 0xC029001D; +pub const STATUS_TPM_BADTAG: NTSTATUS = 0xC029001E; +pub const STATUS_TPM_IOERROR: NTSTATUS = 0xC029001F; +pub const STATUS_TPM_ENCRYPT_ERROR: NTSTATUS = 0xC0290020; +pub const STATUS_TPM_DECRYPT_ERROR: NTSTATUS = 0xC0290021; +pub const STATUS_TPM_INVALID_AUTHHANDLE: NTSTATUS = 0xC0290022; +pub const STATUS_TPM_NO_ENDORSEMENT: NTSTATUS = 0xC0290023; +pub const STATUS_TPM_INVALID_KEYUSAGE: NTSTATUS = 0xC0290024; +pub const STATUS_TPM_WRONG_ENTITYTYPE: NTSTATUS = 0xC0290025; +pub const STATUS_TPM_INVALID_POSTINIT: NTSTATUS = 0xC0290026; +pub const STATUS_TPM_INAPPROPRIATE_SIG: NTSTATUS = 0xC0290027; +pub const STATUS_TPM_BAD_KEY_PROPERTY: NTSTATUS = 0xC0290028; +pub const STATUS_TPM_BAD_MIGRATION: NTSTATUS = 0xC0290029; +pub const STATUS_TPM_BAD_SCHEME: NTSTATUS = 0xC029002A; +pub const STATUS_TPM_BAD_DATASIZE: NTSTATUS = 0xC029002B; +pub const STATUS_TPM_BAD_MODE: NTSTATUS = 0xC029002C; +pub const STATUS_TPM_BAD_PRESENCE: NTSTATUS = 0xC029002D; +pub const STATUS_TPM_BAD_VERSION: NTSTATUS = 0xC029002E; +pub const STATUS_TPM_NO_WRAP_TRANSPORT: NTSTATUS = 0xC029002F; +pub const STATUS_TPM_AUDITFAIL_UNSUCCESSFUL: NTSTATUS = 0xC0290030; +pub const STATUS_TPM_AUDITFAIL_SUCCESSFUL: NTSTATUS = 0xC0290031; +pub const STATUS_TPM_NOTRESETABLE: NTSTATUS = 0xC0290032; +pub const STATUS_TPM_NOTLOCAL: NTSTATUS = 0xC0290033; +pub const STATUS_TPM_BAD_TYPE: NTSTATUS = 0xC0290034; +pub const STATUS_TPM_INVALID_RESOURCE: NTSTATUS = 0xC0290035; +pub const STATUS_TPM_NOTFIPS: NTSTATUS = 0xC0290036; +pub const STATUS_TPM_INVALID_FAMILY: NTSTATUS = 0xC0290037; +pub const STATUS_TPM_NO_NV_PERMISSION: NTSTATUS = 0xC0290038; +pub const STATUS_TPM_REQUIRES_SIGN: NTSTATUS = 0xC0290039; +pub const STATUS_TPM_KEY_NOTSUPPORTED: NTSTATUS = 0xC029003A; +pub const STATUS_TPM_AUTH_CONFLICT: NTSTATUS = 0xC029003B; +pub const STATUS_TPM_AREA_LOCKED: NTSTATUS = 0xC029003C; +pub const STATUS_TPM_BAD_LOCALITY: NTSTATUS = 0xC029003D; +pub const STATUS_TPM_READ_ONLY: NTSTATUS = 0xC029003E; +pub const STATUS_TPM_PER_NOWRITE: NTSTATUS = 0xC029003F; +pub const STATUS_TPM_FAMILYCOUNT: NTSTATUS = 0xC0290040; +pub const STATUS_TPM_WRITE_LOCKED: NTSTATUS = 0xC0290041; +pub const STATUS_TPM_BAD_ATTRIBUTES: NTSTATUS = 0xC0290042; +pub const STATUS_TPM_INVALID_STRUCTURE: NTSTATUS = 0xC0290043; +pub const STATUS_TPM_KEY_OWNER_CONTROL: NTSTATUS = 0xC0290044; +pub const STATUS_TPM_BAD_COUNTER: NTSTATUS = 0xC0290045; +pub const STATUS_TPM_NOT_FULLWRITE: NTSTATUS = 0xC0290046; +pub const STATUS_TPM_CONTEXT_GAP: NTSTATUS = 0xC0290047; +pub const STATUS_TPM_MAXNVWRITES: NTSTATUS = 0xC0290048; +pub const STATUS_TPM_NOOPERATOR: NTSTATUS = 0xC0290049; +pub const STATUS_TPM_RESOURCEMISSING: NTSTATUS = 0xC029004A; +pub const STATUS_TPM_DELEGATE_LOCK: NTSTATUS = 0xC029004B; +pub const STATUS_TPM_DELEGATE_FAMILY: NTSTATUS = 0xC029004C; +pub const STATUS_TPM_DELEGATE_ADMIN: NTSTATUS = 0xC029004D; +pub const STATUS_TPM_TRANSPORT_NOTEXCLUSIVE: NTSTATUS = 0xC029004E; +pub const STATUS_TPM_OWNER_CONTROL: NTSTATUS = 0xC029004F; +pub const STATUS_TPM_DAA_RESOURCES: NTSTATUS = 0xC0290050; +pub const STATUS_TPM_DAA_INPUT_DATA0: NTSTATUS = 0xC0290051; +pub const STATUS_TPM_DAA_INPUT_DATA1: NTSTATUS = 0xC0290052; +pub const STATUS_TPM_DAA_ISSUER_SETTINGS: NTSTATUS = 0xC0290053; +pub const STATUS_TPM_DAA_TPM_SETTINGS: NTSTATUS = 0xC0290054; +pub const STATUS_TPM_DAA_STAGE: NTSTATUS = 0xC0290055; +pub const STATUS_TPM_DAA_ISSUER_VALIDITY: NTSTATUS = 0xC0290056; +pub const STATUS_TPM_DAA_WRONG_W: NTSTATUS = 0xC0290057; +pub const STATUS_TPM_BAD_HANDLE: NTSTATUS = 0xC0290058; +pub const STATUS_TPM_BAD_DELEGATE: NTSTATUS = 0xC0290059; +pub const STATUS_TPM_BADCONTEXT: NTSTATUS = 0xC029005A; +pub const STATUS_TPM_TOOMANYCONTEXTS: NTSTATUS = 0xC029005B; +pub const STATUS_TPM_MA_TICKET_SIGNATURE: NTSTATUS = 0xC029005C; +pub const STATUS_TPM_MA_DESTINATION: NTSTATUS = 0xC029005D; +pub const STATUS_TPM_MA_SOURCE: NTSTATUS = 0xC029005E; +pub const STATUS_TPM_MA_AUTHORITY: NTSTATUS = 0xC029005F; +pub const STATUS_TPM_PERMANENTEK: NTSTATUS = 0xC0290061; +pub const STATUS_TPM_BAD_SIGNATURE: NTSTATUS = 0xC0290062; +pub const STATUS_TPM_NOCONTEXTSPACE: NTSTATUS = 0xC0290063; +pub const STATUS_TPM_COMMAND_BLOCKED: NTSTATUS = 0xC0290400; +pub const STATUS_TPM_INVALID_HANDLE: NTSTATUS = 0xC0290401; +pub const STATUS_TPM_DUPLICATE_VHANDLE: NTSTATUS = 0xC0290402; +pub const STATUS_TPM_EMBEDDED_COMMAND_BLOCKED: NTSTATUS = 0xC0290403; +pub const STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED: NTSTATUS = 0xC0290404; +pub const STATUS_TPM_RETRY: NTSTATUS = 0xC0290800; +pub const STATUS_TPM_NEEDS_SELFTEST: NTSTATUS = 0xC0290801; +pub const STATUS_TPM_DOING_SELFTEST: NTSTATUS = 0xC0290802; +pub const STATUS_TPM_DEFEND_LOCK_RUNNING: NTSTATUS = 0xC0290803; +pub const STATUS_TPM_COMMAND_CANCELED: NTSTATUS = 0xC0291001; +pub const STATUS_TPM_TOO_MANY_CONTEXTS: NTSTATUS = 0xC0291002; +pub const STATUS_TPM_NOT_FOUND: NTSTATUS = 0xC0291003; +pub const STATUS_TPM_ACCESS_DENIED: NTSTATUS = 0xC0291004; +pub const STATUS_TPM_INSUFFICIENT_BUFFER: NTSTATUS = 0xC0291005; +pub const STATUS_TPM_PPI_FUNCTION_UNSUPPORTED: NTSTATUS = 0xC0291006; +pub const STATUS_PCP_ERROR_MASK: NTSTATUS = 0xC0292000; +pub const STATUS_PCP_DEVICE_NOT_READY: NTSTATUS = 0xC0292001; +pub const STATUS_PCP_INVALID_HANDLE: NTSTATUS = 0xC0292002; +pub const STATUS_PCP_INVALID_PARAMETER: NTSTATUS = 0xC0292003; +pub const STATUS_PCP_FLAG_NOT_SUPPORTED: NTSTATUS = 0xC0292004; +pub const STATUS_PCP_NOT_SUPPORTED: NTSTATUS = 0xC0292005; +pub const STATUS_PCP_BUFFER_TOO_SMALL: NTSTATUS = 0xC0292006; +pub const STATUS_PCP_INTERNAL_ERROR: NTSTATUS = 0xC0292007; +pub const STATUS_PCP_AUTHENTICATION_FAILED: NTSTATUS = 0xC0292008; +pub const STATUS_PCP_AUTHENTICATION_IGNORED: NTSTATUS = 0xC0292009; +pub const STATUS_PCP_POLICY_NOT_FOUND: NTSTATUS = 0xC029200A; +pub const STATUS_PCP_PROFILE_NOT_FOUND: NTSTATUS = 0xC029200B; +pub const STATUS_PCP_VALIDATION_FAILED: NTSTATUS = 0xC029200C; +pub const STATUS_PCP_DEVICE_NOT_FOUND: NTSTATUS = 0xC029200D; +pub const STATUS_RTPM_CONTEXT_CONTINUE: NTSTATUS = 0x00293000; +pub const STATUS_RTPM_CONTEXT_COMPLETE: NTSTATUS = 0x00293001; +pub const STATUS_RTPM_NO_RESULT: NTSTATUS = 0xC0293002; +pub const STATUS_RTPM_PCR_READ_INCOMPLETE: NTSTATUS = 0xC0293003; +pub const STATUS_RTPM_INVALID_CONTEXT: NTSTATUS = 0xC0293004; +pub const STATUS_RTPM_UNSUPPORTED_CMD: NTSTATUS = 0xC0293005; +pub const STATUS_HV_INVALID_HYPERCALL_CODE: NTSTATUS = 0xC0350002; +pub const STATUS_HV_INVALID_HYPERCALL_INPUT: NTSTATUS = 0xC0350003; +pub const STATUS_HV_INVALID_ALIGNMENT: NTSTATUS = 0xC0350004; +pub const STATUS_HV_INVALID_PARAMETER: NTSTATUS = 0xC0350005; +pub const STATUS_HV_ACCESS_DENIED: NTSTATUS = 0xC0350006; +pub const STATUS_HV_INVALID_PARTITION_STATE: NTSTATUS = 0xC0350007; +pub const STATUS_HV_OPERATION_DENIED: NTSTATUS = 0xC0350008; +pub const STATUS_HV_UNKNOWN_PROPERTY: NTSTATUS = 0xC0350009; +pub const STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE: NTSTATUS = 0xC035000A; +pub const STATUS_HV_INSUFFICIENT_MEMORY: NTSTATUS = 0xC035000B; +pub const STATUS_HV_PARTITION_TOO_DEEP: NTSTATUS = 0xC035000C; +pub const STATUS_HV_INVALID_PARTITION_ID: NTSTATUS = 0xC035000D; +pub const STATUS_HV_INVALID_VP_INDEX: NTSTATUS = 0xC035000E; +pub const STATUS_HV_INVALID_PORT_ID: NTSTATUS = 0xC0350011; +pub const STATUS_HV_INVALID_CONNECTION_ID: NTSTATUS = 0xC0350012; +pub const STATUS_HV_INSUFFICIENT_BUFFERS: NTSTATUS = 0xC0350013; +pub const STATUS_HV_NOT_ACKNOWLEDGED: NTSTATUS = 0xC0350014; +pub const STATUS_HV_INVALID_VP_STATE: NTSTATUS = 0xC0350015; +pub const STATUS_HV_ACKNOWLEDGED: NTSTATUS = 0xC0350016; +pub const STATUS_HV_INVALID_SAVE_RESTORE_STATE: NTSTATUS = 0xC0350017; +pub const STATUS_HV_INVALID_SYNIC_STATE: NTSTATUS = 0xC0350018; +pub const STATUS_HV_OBJECT_IN_USE: NTSTATUS = 0xC0350019; +pub const STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO: NTSTATUS = 0xC035001A; +pub const STATUS_HV_NO_DATA: NTSTATUS = 0xC035001B; +pub const STATUS_HV_INACTIVE: NTSTATUS = 0xC035001C; +pub const STATUS_HV_NO_RESOURCES: NTSTATUS = 0xC035001D; +pub const STATUS_HV_FEATURE_UNAVAILABLE: NTSTATUS = 0xC035001E; +pub const STATUS_HV_INSUFFICIENT_BUFFER: NTSTATUS = 0xC0350033; +pub const STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS: NTSTATUS = 0xC0350038; +pub const STATUS_HV_CPUID_FEATURE_VALIDATION_ERROR: NTSTATUS = 0xC035003C; +pub const STATUS_HV_CPUID_XSAVE_FEATURE_VALIDATION_ERROR: NTSTATUS = 0xC035003D; +pub const STATUS_HV_PROCESSOR_STARTUP_TIMEOUT: NTSTATUS = 0xC035003E; +pub const STATUS_HV_SMX_ENABLED: NTSTATUS = 0xC035003F; +pub const STATUS_HV_INVALID_LP_INDEX: NTSTATUS = 0xC0350041; +pub const STATUS_HV_INVALID_REGISTER_VALUE: NTSTATUS = 0xC0350050; +pub const STATUS_HV_INVALID_VTL_STATE: NTSTATUS = 0xC0350051; +pub const STATUS_HV_NX_NOT_DETECTED: NTSTATUS = 0xC0350055; +pub const STATUS_HV_INVALID_DEVICE_ID: NTSTATUS = 0xC0350057; +pub const STATUS_HV_INVALID_DEVICE_STATE: NTSTATUS = 0xC0350058; +pub const STATUS_HV_PENDING_PAGE_REQUESTS: NTSTATUS = 0x00350059; +pub const STATUS_HV_PAGE_REQUEST_INVALID: NTSTATUS = 0xC0350060; +pub const STATUS_HV_INVALID_CPU_GROUP_ID: NTSTATUS = 0xC035006F; +pub const STATUS_HV_INVALID_CPU_GROUP_STATE: NTSTATUS = 0xC0350070; +pub const STATUS_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE: NTSTATUS = 0xC0350071; +pub const STATUS_HV_NOT_PRESENT: NTSTATUS = 0xC0351000; +pub const STATUS_VID_DUPLICATE_HANDLER: NTSTATUS = 0xC0370001; +pub const STATUS_VID_TOO_MANY_HANDLERS: NTSTATUS = 0xC0370002; +pub const STATUS_VID_QUEUE_FULL: NTSTATUS = 0xC0370003; +pub const STATUS_VID_HANDLER_NOT_PRESENT: NTSTATUS = 0xC0370004; +pub const STATUS_VID_INVALID_OBJECT_NAME: NTSTATUS = 0xC0370005; +pub const STATUS_VID_PARTITION_NAME_TOO_LONG: NTSTATUS = 0xC0370006; +pub const STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG: NTSTATUS = 0xC0370007; +pub const STATUS_VID_PARTITION_ALREADY_EXISTS: NTSTATUS = 0xC0370008; +pub const STATUS_VID_PARTITION_DOES_NOT_EXIST: NTSTATUS = 0xC0370009; +pub const STATUS_VID_PARTITION_NAME_NOT_FOUND: NTSTATUS = 0xC037000A; +pub const STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS: NTSTATUS = 0xC037000B; +pub const STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT: NTSTATUS = 0xC037000C; +pub const STATUS_VID_MB_STILL_REFERENCED: NTSTATUS = 0xC037000D; +pub const STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED: NTSTATUS = 0xC037000E; +pub const STATUS_VID_INVALID_NUMA_SETTINGS: NTSTATUS = 0xC037000F; +pub const STATUS_VID_INVALID_NUMA_NODE_INDEX: NTSTATUS = 0xC0370010; +pub const STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED: NTSTATUS = 0xC0370011; +pub const STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE: NTSTATUS = 0xC0370012; +pub const STATUS_VID_PAGE_RANGE_OVERFLOW: NTSTATUS = 0xC0370013; +pub const STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE: NTSTATUS = 0xC0370014; +pub const STATUS_VID_INVALID_GPA_RANGE_HANDLE: NTSTATUS = 0xC0370015; +pub const STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE: NTSTATUS = 0xC0370016; +pub const STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED: NTSTATUS = 0xC0370017; +pub const STATUS_VID_INVALID_PPM_HANDLE: NTSTATUS = 0xC0370018; +pub const STATUS_VID_MBPS_ARE_LOCKED: NTSTATUS = 0xC0370019; +pub const STATUS_VID_MESSAGE_QUEUE_CLOSED: NTSTATUS = 0xC037001A; +pub const STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED: NTSTATUS = 0xC037001B; +pub const STATUS_VID_STOP_PENDING: NTSTATUS = 0xC037001C; +pub const STATUS_VID_INVALID_PROCESSOR_STATE: NTSTATUS = 0xC037001D; +pub const STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT: NTSTATUS = 0xC037001E; +pub const STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED: NTSTATUS = 0xC037001F; +pub const STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET: NTSTATUS = 0xC0370020; +pub const STATUS_VID_MMIO_RANGE_DESTROYED: NTSTATUS = 0xC0370021; +pub const STATUS_VID_INVALID_CHILD_GPA_PAGE_SET: NTSTATUS = 0xC0370022; +pub const STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED: NTSTATUS = 0xC0370023; +pub const STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL: NTSTATUS = 0xC0370024; +pub const STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE: NTSTATUS = 0xC0370025; +pub const STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT: NTSTATUS = 0xC0370026; +pub const STATUS_VID_SAVED_STATE_CORRUPT: NTSTATUS = 0xC0370027; +pub const STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM: NTSTATUS = 0xC0370028; +pub const STATUS_VID_SAVED_STATE_INCOMPATIBLE: NTSTATUS = 0xC0370029; +pub const STATUS_VID_VTL_ACCESS_DENIED: NTSTATUS = 0xC037002A; +pub const STATUS_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED: NTSTATUS = 0x80370001; +pub const STATUS_IPSEC_BAD_SPI: NTSTATUS = 0xC0360001; +pub const STATUS_IPSEC_SA_LIFETIME_EXPIRED: NTSTATUS = 0xC0360002; +pub const STATUS_IPSEC_WRONG_SA: NTSTATUS = 0xC0360003; +pub const STATUS_IPSEC_REPLAY_CHECK_FAILED: NTSTATUS = 0xC0360004; +pub const STATUS_IPSEC_INVALID_PACKET: NTSTATUS = 0xC0360005; +pub const STATUS_IPSEC_INTEGRITY_CHECK_FAILED: NTSTATUS = 0xC0360006; +pub const STATUS_IPSEC_CLEAR_TEXT_DROP: NTSTATUS = 0xC0360007; +pub const STATUS_IPSEC_AUTH_FIREWALL_DROP: NTSTATUS = 0xC0360008; +pub const STATUS_IPSEC_THROTTLE_DROP: NTSTATUS = 0xC0360009; +pub const STATUS_IPSEC_DOSP_BLOCK: NTSTATUS = 0xC0368000; +pub const STATUS_IPSEC_DOSP_RECEIVED_MULTICAST: NTSTATUS = 0xC0368001; +pub const STATUS_IPSEC_DOSP_INVALID_PACKET: NTSTATUS = 0xC0368002; +pub const STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED: NTSTATUS = 0xC0368003; +pub const STATUS_IPSEC_DOSP_MAX_ENTRIES: NTSTATUS = 0xC0368004; +pub const STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: NTSTATUS = 0xC0368005; +pub const STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: NTSTATUS = 0xC0368006; +pub const STATUS_VOLMGR_INCOMPLETE_REGENERATION: NTSTATUS = 0x80380001; +pub const STATUS_VOLMGR_INCOMPLETE_DISK_MIGRATION: NTSTATUS = 0x80380002; +pub const STATUS_VOLMGR_DATABASE_FULL: NTSTATUS = 0xC0380001; +pub const STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED: NTSTATUS = 0xC0380002; +pub const STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC: NTSTATUS = 0xC0380003; +pub const STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED: NTSTATUS = 0xC0380004; +pub const STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME: NTSTATUS = 0xC0380005; +pub const STATUS_VOLMGR_DISK_DUPLICATE: NTSTATUS = 0xC0380006; +pub const STATUS_VOLMGR_DISK_DYNAMIC: NTSTATUS = 0xC0380007; +pub const STATUS_VOLMGR_DISK_ID_INVALID: NTSTATUS = 0xC0380008; +pub const STATUS_VOLMGR_DISK_INVALID: NTSTATUS = 0xC0380009; +pub const STATUS_VOLMGR_DISK_LAST_VOTER: NTSTATUS = 0xC038000A; +pub const STATUS_VOLMGR_DISK_LAYOUT_INVALID: NTSTATUS = 0xC038000B; +pub const STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS: NTSTATUS + = 0xC038000C; +pub const STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED: NTSTATUS = 0xC038000D; +pub const STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL: NTSTATUS = 0xC038000E; +pub const STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS: NTSTATUS + = 0xC038000F; +pub const STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS: NTSTATUS = 0xC0380010; +pub const STATUS_VOLMGR_DISK_MISSING: NTSTATUS = 0xC0380011; +pub const STATUS_VOLMGR_DISK_NOT_EMPTY: NTSTATUS = 0xC0380012; +pub const STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE: NTSTATUS = 0xC0380013; +pub const STATUS_VOLMGR_DISK_REVECTORING_FAILED: NTSTATUS = 0xC0380014; +pub const STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID: NTSTATUS = 0xC0380015; +pub const STATUS_VOLMGR_DISK_SET_NOT_CONTAINED: NTSTATUS = 0xC0380016; +pub const STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS: NTSTATUS = 0xC0380017; +pub const STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES: NTSTATUS = 0xC0380018; +pub const STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED: NTSTATUS = 0xC0380019; +pub const STATUS_VOLMGR_EXTENT_ALREADY_USED: NTSTATUS = 0xC038001A; +pub const STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS: NTSTATUS = 0xC038001B; +pub const STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION: NTSTATUS = 0xC038001C; +pub const STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED: NTSTATUS = 0xC038001D; +pub const STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION: NTSTATUS = 0xC038001E; +pub const STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH: NTSTATUS = 0xC038001F; +pub const STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED: NTSTATUS = 0xC0380020; +pub const STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID: NTSTATUS = 0xC0380021; +pub const STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS: NTSTATUS = 0xC0380022; +pub const STATUS_VOLMGR_MEMBER_IN_SYNC: NTSTATUS = 0xC0380023; +pub const STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE: NTSTATUS = 0xC0380024; +pub const STATUS_VOLMGR_MEMBER_INDEX_INVALID: NTSTATUS = 0xC0380025; +pub const STATUS_VOLMGR_MEMBER_MISSING: NTSTATUS = 0xC0380026; +pub const STATUS_VOLMGR_MEMBER_NOT_DETACHED: NTSTATUS = 0xC0380027; +pub const STATUS_VOLMGR_MEMBER_REGENERATING: NTSTATUS = 0xC0380028; +pub const STATUS_VOLMGR_ALL_DISKS_FAILED: NTSTATUS = 0xC0380029; +pub const STATUS_VOLMGR_NO_REGISTERED_USERS: NTSTATUS = 0xC038002A; +pub const STATUS_VOLMGR_NO_SUCH_USER: NTSTATUS = 0xC038002B; +pub const STATUS_VOLMGR_NOTIFICATION_RESET: NTSTATUS = 0xC038002C; +pub const STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID: NTSTATUS = 0xC038002D; +pub const STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID: NTSTATUS = 0xC038002E; +pub const STATUS_VOLMGR_PACK_DUPLICATE: NTSTATUS = 0xC038002F; +pub const STATUS_VOLMGR_PACK_ID_INVALID: NTSTATUS = 0xC0380030; +pub const STATUS_VOLMGR_PACK_INVALID: NTSTATUS = 0xC0380031; +pub const STATUS_VOLMGR_PACK_NAME_INVALID: NTSTATUS = 0xC0380032; +pub const STATUS_VOLMGR_PACK_OFFLINE: NTSTATUS = 0xC0380033; +pub const STATUS_VOLMGR_PACK_HAS_QUORUM: NTSTATUS = 0xC0380034; +pub const STATUS_VOLMGR_PACK_WITHOUT_QUORUM: NTSTATUS = 0xC0380035; +pub const STATUS_VOLMGR_PARTITION_STYLE_INVALID: NTSTATUS = 0xC0380036; +pub const STATUS_VOLMGR_PARTITION_UPDATE_FAILED: NTSTATUS = 0xC0380037; +pub const STATUS_VOLMGR_PLEX_IN_SYNC: NTSTATUS = 0xC0380038; +pub const STATUS_VOLMGR_PLEX_INDEX_DUPLICATE: NTSTATUS = 0xC0380039; +pub const STATUS_VOLMGR_PLEX_INDEX_INVALID: NTSTATUS = 0xC038003A; +pub const STATUS_VOLMGR_PLEX_LAST_ACTIVE: NTSTATUS = 0xC038003B; +pub const STATUS_VOLMGR_PLEX_MISSING: NTSTATUS = 0xC038003C; +pub const STATUS_VOLMGR_PLEX_REGENERATING: NTSTATUS = 0xC038003D; +pub const STATUS_VOLMGR_PLEX_TYPE_INVALID: NTSTATUS = 0xC038003E; +pub const STATUS_VOLMGR_PLEX_NOT_RAID5: NTSTATUS = 0xC038003F; +pub const STATUS_VOLMGR_PLEX_NOT_SIMPLE: NTSTATUS = 0xC0380040; +pub const STATUS_VOLMGR_STRUCTURE_SIZE_INVALID: NTSTATUS = 0xC0380041; +pub const STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS: NTSTATUS = 0xC0380042; +pub const STATUS_VOLMGR_TRANSACTION_IN_PROGRESS: NTSTATUS = 0xC0380043; +pub const STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE: NTSTATUS = 0xC0380044; +pub const STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK: NTSTATUS = 0xC0380045; +pub const STATUS_VOLMGR_VOLUME_ID_INVALID: NTSTATUS = 0xC0380046; +pub const STATUS_VOLMGR_VOLUME_LENGTH_INVALID: NTSTATUS = 0xC0380047; +pub const STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE: NTSTATUS = 0xC0380048; +pub const STATUS_VOLMGR_VOLUME_NOT_MIRRORED: NTSTATUS = 0xC0380049; +pub const STATUS_VOLMGR_VOLUME_NOT_RETAINED: NTSTATUS = 0xC038004A; +pub const STATUS_VOLMGR_VOLUME_OFFLINE: NTSTATUS = 0xC038004B; +pub const STATUS_VOLMGR_VOLUME_RETAINED: NTSTATUS = 0xC038004C; +pub const STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID: NTSTATUS = 0xC038004D; +pub const STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE: NTSTATUS = 0xC038004E; +pub const STATUS_VOLMGR_BAD_BOOT_DISK: NTSTATUS = 0xC038004F; +pub const STATUS_VOLMGR_PACK_CONFIG_OFFLINE: NTSTATUS = 0xC0380050; +pub const STATUS_VOLMGR_PACK_CONFIG_ONLINE: NTSTATUS = 0xC0380051; +pub const STATUS_VOLMGR_NOT_PRIMARY_PACK: NTSTATUS = 0xC0380052; +pub const STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED: NTSTATUS = 0xC0380053; +pub const STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID: NTSTATUS = 0xC0380054; +pub const STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID: NTSTATUS = 0xC0380055; +pub const STATUS_VOLMGR_VOLUME_MIRRORED: NTSTATUS = 0xC0380056; +pub const STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED: NTSTATUS = 0xC0380057; +pub const STATUS_VOLMGR_NO_VALID_LOG_COPIES: NTSTATUS = 0xC0380058; +pub const STATUS_VOLMGR_PRIMARY_PACK_PRESENT: NTSTATUS = 0xC0380059; +pub const STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID: NTSTATUS = 0xC038005A; +pub const STATUS_VOLMGR_MIRROR_NOT_SUPPORTED: NTSTATUS = 0xC038005B; +pub const STATUS_VOLMGR_RAID5_NOT_SUPPORTED: NTSTATUS = 0xC038005C; +pub const STATUS_BCD_NOT_ALL_ENTRIES_IMPORTED: NTSTATUS = 0x80390001; +pub const STATUS_BCD_TOO_MANY_ELEMENTS: NTSTATUS = 0xC0390002; +pub const STATUS_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED: NTSTATUS = 0x80390003; +pub const STATUS_VHD_DRIVE_FOOTER_MISSING: NTSTATUS = 0xC03A0001; +pub const STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH: NTSTATUS = 0xC03A0002; +pub const STATUS_VHD_DRIVE_FOOTER_CORRUPT: NTSTATUS = 0xC03A0003; +pub const STATUS_VHD_FORMAT_UNKNOWN: NTSTATUS = 0xC03A0004; +pub const STATUS_VHD_FORMAT_UNSUPPORTED_VERSION: NTSTATUS = 0xC03A0005; +pub const STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH: NTSTATUS = 0xC03A0006; +pub const STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION: NTSTATUS = 0xC03A0007; +pub const STATUS_VHD_SPARSE_HEADER_CORRUPT: NTSTATUS = 0xC03A0008; +pub const STATUS_VHD_BLOCK_ALLOCATION_FAILURE: NTSTATUS = 0xC03A0009; +pub const STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT: NTSTATUS = 0xC03A000A; +pub const STATUS_VHD_INVALID_BLOCK_SIZE: NTSTATUS = 0xC03A000B; +pub const STATUS_VHD_BITMAP_MISMATCH: NTSTATUS = 0xC03A000C; +pub const STATUS_VHD_PARENT_VHD_NOT_FOUND: NTSTATUS = 0xC03A000D; +pub const STATUS_VHD_CHILD_PARENT_ID_MISMATCH: NTSTATUS = 0xC03A000E; +pub const STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH: NTSTATUS = 0xC03A000F; +pub const STATUS_VHD_METADATA_READ_FAILURE: NTSTATUS = 0xC03A0010; +pub const STATUS_VHD_METADATA_WRITE_FAILURE: NTSTATUS = 0xC03A0011; +pub const STATUS_VHD_INVALID_SIZE: NTSTATUS = 0xC03A0012; +pub const STATUS_VHD_INVALID_FILE_SIZE: NTSTATUS = 0xC03A0013; +pub const STATUS_VIRTDISK_PROVIDER_NOT_FOUND: NTSTATUS = 0xC03A0014; +pub const STATUS_VIRTDISK_NOT_VIRTUAL_DISK: NTSTATUS = 0xC03A0015; +pub const STATUS_VHD_PARENT_VHD_ACCESS_DENIED: NTSTATUS = 0xC03A0016; +pub const STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH: NTSTATUS = 0xC03A0017; +pub const STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED: NTSTATUS = 0xC03A0018; +pub const STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT: NTSTATUS = 0xC03A0019; +pub const STATUS_VIRTUAL_DISK_LIMITATION: NTSTATUS = 0xC03A001A; +pub const STATUS_VHD_INVALID_TYPE: NTSTATUS = 0xC03A001B; +pub const STATUS_VHD_INVALID_STATE: NTSTATUS = 0xC03A001C; +pub const STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE: NTSTATUS = 0xC03A001D; +pub const STATUS_VIRTDISK_DISK_ALREADY_OWNED: NTSTATUS = 0xC03A001E; +pub const STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE: NTSTATUS = 0xC03A001F; +pub const STATUS_CTLOG_TRACKING_NOT_INITIALIZED: NTSTATUS = 0xC03A0020; +pub const STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE: NTSTATUS = 0xC03A0021; +pub const STATUS_CTLOG_VHD_CHANGED_OFFLINE: NTSTATUS = 0xC03A0022; +pub const STATUS_CTLOG_INVALID_TRACKING_STATE: NTSTATUS = 0xC03A0023; +pub const STATUS_CTLOG_INCONSISTENT_TRACKING_FILE: NTSTATUS = 0xC03A0024; +pub const STATUS_VHD_METADATA_FULL: NTSTATUS = 0xC03A0028; +pub const STATUS_VHD_INVALID_CHANGE_TRACKING_ID: NTSTATUS = 0xC03A0029; +pub const STATUS_VHD_CHANGE_TRACKING_DISABLED: NTSTATUS = 0xC03A002A; +pub const STATUS_VHD_MISSING_CHANGE_TRACKING_INFORMATION: NTSTATUS = 0xC03A0030; +pub const STATUS_VHD_RESIZE_WOULD_TRUNCATE_DATA: NTSTATUS = 0xC03A0031; +pub const STATUS_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE: NTSTATUS = 0xC03A0032; +pub const STATUS_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE: NTSTATUS = 0xC03A0033; +pub const STATUS_QUERY_STORAGE_ERROR: NTSTATUS = 0x803A0001; +pub const STATUS_RKF_KEY_NOT_FOUND: NTSTATUS = 0xC0400001; +pub const STATUS_RKF_DUPLICATE_KEY: NTSTATUS = 0xC0400002; +pub const STATUS_RKF_BLOB_FULL: NTSTATUS = 0xC0400003; +pub const STATUS_RKF_STORE_FULL: NTSTATUS = 0xC0400004; +pub const STATUS_RKF_FILE_BLOCKED: NTSTATUS = 0xC0400005; +pub const STATUS_RKF_ACTIVE_KEY: NTSTATUS = 0xC0400006; +pub const STATUS_RDBSS_RESTART_OPERATION: NTSTATUS = 0xC0410001; +pub const STATUS_RDBSS_CONTINUE_OPERATION: NTSTATUS = 0xC0410002; +pub const STATUS_RDBSS_POST_OPERATION: NTSTATUS = 0xC0410003; +pub const STATUS_BTH_ATT_INVALID_HANDLE: NTSTATUS = 0xC0420001; +pub const STATUS_BTH_ATT_READ_NOT_PERMITTED: NTSTATUS = 0xC0420002; +pub const STATUS_BTH_ATT_WRITE_NOT_PERMITTED: NTSTATUS = 0xC0420003; +pub const STATUS_BTH_ATT_INVALID_PDU: NTSTATUS = 0xC0420004; +pub const STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION: NTSTATUS = 0xC0420005; +pub const STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED: NTSTATUS = 0xC0420006; +pub const STATUS_BTH_ATT_INVALID_OFFSET: NTSTATUS = 0xC0420007; +pub const STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION: NTSTATUS = 0xC0420008; +pub const STATUS_BTH_ATT_PREPARE_QUEUE_FULL: NTSTATUS = 0xC0420009; +pub const STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND: NTSTATUS = 0xC042000A; +pub const STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG: NTSTATUS = 0xC042000B; +pub const STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE: NTSTATUS = 0xC042000C; +pub const STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: NTSTATUS = 0xC042000D; +pub const STATUS_BTH_ATT_UNLIKELY: NTSTATUS = 0xC042000E; +pub const STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION: NTSTATUS = 0xC042000F; +pub const STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE: NTSTATUS = 0xC0420010; +pub const STATUS_BTH_ATT_INSUFFICIENT_RESOURCES: NTSTATUS = 0xC0420011; +pub const STATUS_BTH_ATT_UNKNOWN_ERROR: NTSTATUS = 0xC0421000; +pub const STATUS_SECUREBOOT_ROLLBACK_DETECTED: NTSTATUS = 0xC0430001; +pub const STATUS_SECUREBOOT_POLICY_VIOLATION: NTSTATUS = 0xC0430002; +pub const STATUS_SECUREBOOT_INVALID_POLICY: NTSTATUS = 0xC0430003; +pub const STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND: NTSTATUS = 0xC0430004; +pub const STATUS_SECUREBOOT_POLICY_NOT_SIGNED: NTSTATUS = 0xC0430005; +pub const STATUS_SECUREBOOT_NOT_ENABLED: NTSTATUS = 0x80430006; +pub const STATUS_SECUREBOOT_FILE_REPLACED: NTSTATUS = 0xC0430007; +pub const STATUS_SECUREBOOT_POLICY_NOT_AUTHORIZED: NTSTATUS = 0xC0430008; +pub const STATUS_SECUREBOOT_POLICY_UNKNOWN: NTSTATUS = 0xC0430009; +pub const STATUS_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION: NTSTATUS = 0xC043000A; +pub const STATUS_SECUREBOOT_PLATFORM_ID_MISMATCH: NTSTATUS = 0xC043000B; +pub const STATUS_SECUREBOOT_POLICY_ROLLBACK_DETECTED: NTSTATUS = 0xC043000C; +pub const STATUS_SECUREBOOT_POLICY_UPGRADE_MISMATCH: NTSTATUS = 0xC043000D; +pub const STATUS_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING: NTSTATUS = 0xC043000E; +pub const STATUS_SECUREBOOT_NOT_BASE_POLICY: NTSTATUS = 0xC043000F; +pub const STATUS_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY: NTSTATUS = 0xC0430010; +pub const STATUS_PLATFORM_MANIFEST_NOT_AUTHORIZED: NTSTATUS = 0xC0EB0001; +pub const STATUS_PLATFORM_MANIFEST_INVALID: NTSTATUS = 0xC0EB0002; +pub const STATUS_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED: NTSTATUS = 0xC0EB0003; +pub const STATUS_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED: NTSTATUS = 0xC0EB0004; +pub const STATUS_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND: NTSTATUS = 0xC0EB0005; +pub const STATUS_PLATFORM_MANIFEST_NOT_ACTIVE: NTSTATUS = 0xC0EB0006; +pub const STATUS_PLATFORM_MANIFEST_NOT_SIGNED: NTSTATUS = 0xC0EB0007; +pub const STATUS_SYSTEM_INTEGRITY_ROLLBACK_DETECTED: NTSTATUS = 0xC0E90001; +pub const STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION: NTSTATUS = 0xC0E90002; +pub const STATUS_SYSTEM_INTEGRITY_INVALID_POLICY: NTSTATUS = 0xC0E90003; +pub const STATUS_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED: NTSTATUS = 0xC0E90004; +pub const STATUS_NO_APPLICABLE_APP_LICENSES_FOUND: NTSTATUS = 0xC0EA0001; +pub const STATUS_CLIP_LICENSE_NOT_FOUND: NTSTATUS = 0xC0EA0002; +pub const STATUS_CLIP_DEVICE_LICENSE_MISSING: NTSTATUS = 0xC0EA0003; +pub const STATUS_CLIP_LICENSE_INVALID_SIGNATURE: NTSTATUS = 0xC0EA0004; +pub const STATUS_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID: NTSTATUS = 0xC0EA0005; +pub const STATUS_CLIP_LICENSE_EXPIRED: NTSTATUS = 0xC0EA0006; +pub const STATUS_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE: NTSTATUS = 0xC0EA0007; +pub const STATUS_CLIP_LICENSE_NOT_SIGNED: NTSTATUS = 0xC0EA0008; +pub const STATUS_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE: NTSTATUS = 0xC0EA0009; +pub const STATUS_CLIP_LICENSE_DEVICE_ID_MISMATCH: NTSTATUS = 0xC0EA000A; +pub const STATUS_AUDIO_ENGINE_NODE_NOT_FOUND: NTSTATUS = 0xC0440001; +pub const STATUS_HDAUDIO_EMPTY_CONNECTION_LIST: NTSTATUS = 0xC0440002; +pub const STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED: NTSTATUS = 0xC0440003; +pub const STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED: NTSTATUS = 0xC0440004; +pub const STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY: NTSTATUS = 0xC0440005; +pub const STATUS_SPACES_REPAIRED: NTSTATUS = 0x00E70000; +pub const STATUS_SPACES_PAUSE: NTSTATUS = 0x00E70001; +pub const STATUS_SPACES_COMPLETE: NTSTATUS = 0x00E70002; +pub const STATUS_SPACES_FAULT_DOMAIN_TYPE_INVALID: NTSTATUS = 0xC0E70001; +pub const STATUS_SPACES_RESILIENCY_TYPE_INVALID: NTSTATUS = 0xC0E70003; +pub const STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID: NTSTATUS = 0xC0E70004; +pub const STATUS_SPACES_DRIVE_REDUNDANCY_INVALID: NTSTATUS = 0xC0E70006; +pub const STATUS_SPACES_NUMBER_OF_DATA_COPIES_INVALID: NTSTATUS = 0xC0E70007; +pub const STATUS_SPACES_INTERLEAVE_LENGTH_INVALID: NTSTATUS = 0xC0E70009; +pub const STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID: NTSTATUS = 0xC0E7000A; +pub const STATUS_SPACES_NOT_ENOUGH_DRIVES: NTSTATUS = 0xC0E7000B; +pub const STATUS_SPACES_EXTENDED_ERROR: NTSTATUS = 0xC0E7000C; +pub const STATUS_SPACES_PROVISIONING_TYPE_INVALID: NTSTATUS = 0xC0E7000D; +pub const STATUS_SPACES_ALLOCATION_SIZE_INVALID: NTSTATUS = 0xC0E7000E; +pub const STATUS_SPACES_ENCLOSURE_AWARE_INVALID: NTSTATUS = 0xC0E7000F; +pub const STATUS_SPACES_WRITE_CACHE_SIZE_INVALID: NTSTATUS = 0xC0E70010; +pub const STATUS_SPACES_NUMBER_OF_GROUPS_INVALID: NTSTATUS = 0xC0E70011; +pub const STATUS_SPACES_DRIVE_OPERATIONAL_STATE_INVALID: NTSTATUS = 0xC0E70012; +pub const STATUS_SPACES_UPDATE_COLUMN_STATE: NTSTATUS = 0xC0E70013; +pub const STATUS_SPACES_MAP_REQUIRED: NTSTATUS = 0xC0E70014; +pub const STATUS_SPACES_UNSUPPORTED_VERSION: NTSTATUS = 0xC0E70015; +pub const STATUS_SPACES_CORRUPT_METADATA: NTSTATUS = 0xC0E70016; +pub const STATUS_SPACES_DRT_FULL: NTSTATUS = 0xC0E70017; +pub const STATUS_SPACES_INCONSISTENCY: NTSTATUS = 0xC0E70018; +pub const STATUS_SPACES_LOG_NOT_READY: NTSTATUS = 0xC0E70019; +pub const STATUS_SPACES_NO_REDUNDANCY: NTSTATUS = 0xC0E7001A; +pub const STATUS_SPACES_DRIVE_NOT_READY: NTSTATUS = 0xC0E7001B; +pub const STATUS_SPACES_DRIVE_SPLIT: NTSTATUS = 0xC0E7001C; +pub const STATUS_SPACES_DRIVE_LOST_DATA: NTSTATUS = 0xC0E7001D; +pub const STATUS_VOLSNAP_BOOTFILE_NOT_VALID: NTSTATUS = 0xC0500003; +pub const STATUS_VOLSNAP_ACTIVATION_TIMEOUT: NTSTATUS = 0xC0500004; +pub const STATUS_IO_PREEMPTED: NTSTATUS = 0xC0510001; +pub const STATUS_SVHDX_ERROR_STORED: NTSTATUS = 0xC05C0000; +pub const STATUS_SVHDX_ERROR_NOT_AVAILABLE: NTSTATUS = 0xC05CFF00; +pub const STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE: NTSTATUS = 0xC05CFF01; +pub const STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED: NTSTATUS = 0xC05CFF02; +pub const STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED: NTSTATUS = 0xC05CFF03; +pub const STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED: NTSTATUS = 0xC05CFF04; +pub const STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED: NTSTATUS = 0xC05CFF05; +pub const STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED: NTSTATUS + = 0xC05CFF06; +pub const STATUS_SVHDX_RESERVATION_CONFLICT: NTSTATUS = 0xC05CFF07; +pub const STATUS_SVHDX_WRONG_FILE_TYPE: NTSTATUS = 0xC05CFF08; +pub const STATUS_SVHDX_VERSION_MISMATCH: NTSTATUS = 0xC05CFF09; +pub const STATUS_VHD_SHARED: NTSTATUS = 0xC05CFF0A; +pub const STATUS_SVHDX_NO_INITIATOR: NTSTATUS = 0xC05CFF0B; +pub const STATUS_VHDSET_BACKING_STORAGE_NOT_FOUND: NTSTATUS = 0xC05CFF0C; +pub const STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP: NTSTATUS = 0xC05D0000; +pub const STATUS_SMB_BAD_CLUSTER_DIALECT: NTSTATUS = 0xC05D0001; +pub const STATUS_SMB_GUEST_LOGON_BLOCKED: NTSTATUS = 0xC05D0002; +pub const STATUS_SECCORE_INVALID_COMMAND: NTSTATUS = 0xC0E80000; +pub const STATUS_VSM_NOT_INITIALIZED: NTSTATUS = 0xC0450000; +pub const STATUS_VSM_DMA_PROTECTION_NOT_IN_USE: NTSTATUS = 0xC0450001; diff --git a/winapi/src/shared/qos.rs b/winapi/src/shared/qos.rs new file mode 100644 index 000000000..5117bd26a --- /dev/null +++ b/winapi/src/shared/qos.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! QoS definitions for NDIS components. +use shared::minwindef::ULONG; +pub type SERVICETYPE = ULONG; +STRUCT!{struct FLOWSPEC { + TokenRate: ULONG, + TokenBucketSize: ULONG, + PeakBandwidth: ULONG, + Latency: ULONG, + DelayVariation: ULONG, + ServiceType: SERVICETYPE, + MaxSduSize: ULONG, + MinimumPolicedSize: ULONG, +}} +pub type PFLOWSPEC = *mut FLOWSPEC; +pub type LPFLOWSPEC = *mut FLOWSPEC; diff --git a/winapi/src/shared/rpc.rs b/winapi/src/shared/rpc.rs new file mode 100644 index 000000000..5af7e095d --- /dev/null +++ b/winapi/src/shared/rpc.rs @@ -0,0 +1,9 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Master include file for RPC applications. +use ctypes::{c_long, c_void}; +pub type I_RPC_HANDLE = *mut c_void; +pub type RPC_STATUS = c_long; diff --git a/winapi/src/shared/rpcdce.rs b/winapi/src/shared/rpcdce.rs new file mode 100644 index 000000000..ab2879d92 --- /dev/null +++ b/winapi/src/shared/rpcdce.rs @@ -0,0 +1,563 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module contains the DCE RPC runtime APIs. +use ctypes::{c_int, c_uchar, c_uint, c_ulong, c_ushort, c_void, wchar_t}; +use shared::guiddef::GUID; +use shared::minwindef::DWORD; +use shared::rpc::{I_RPC_HANDLE, RPC_STATUS}; +pub type RPC_CSTR = *mut c_uchar; +pub type RPC_WSTR = *mut wchar_t; +pub type RPC_CWSTR = *const wchar_t; +pub type RPC_BINDING_HANDLE = I_RPC_HANDLE; +pub type handle_t = RPC_BINDING_HANDLE; +pub type rpc_binding_handle_t = RPC_BINDING_HANDLE; +pub type UUID = GUID; +pub type uuid_t = UUID; +STRUCT!{struct RPC_BINDING_VECTOR { + Count: c_ulong, + BindingH: [RPC_BINDING_HANDLE; 1], +}} +pub type rpc_binding_vector_t = RPC_BINDING_VECTOR; +STRUCT!{struct UUID_VECTOR { + Count: c_ulong, + Uuid: [*mut UUID; 1], +}} +pub type uuid_vector_t = UUID_VECTOR; +pub type RPC_IF_HANDLE = *mut c_void; +STRUCT!{struct RPC_IF_ID { + Uuid: UUID, + VersMajor: c_ushort, + VersMinor: c_ushort, +}} +pub const RPC_C_BINDING_INFINITE_TIMEOUT: DWORD = 10; +pub const RPC_C_BINDING_MIN_TIMEOUT: DWORD = 0; +pub const RPC_C_BINDING_DEFAULT_TIMEOUT: DWORD = 5; +pub const RPC_C_BINDING_MAX_TIMEOUT: DWORD = 9; +pub const RPC_C_CANCEL_INFINITE_TIMEOUT: c_int = -1; +pub const RPC_C_LISTEN_MAX_CALLS_DEFAULT: DWORD = 1234; +pub const RPC_C_PROTSEQ_MAX_REQS_DEFAULT: DWORD = 10; +pub const RPC_C_BIND_TO_ALL_NICS: DWORD = 1; +pub const RPC_C_USE_INTERNET_PORT: DWORD = 0x1; +pub const RPC_C_USE_INTRANET_PORT: DWORD = 0x2; +pub const RPC_C_DONT_FAIL: DWORD = 0x4; +pub const RPC_C_RPCHTTP_USE_LOAD_BALANCE: DWORD = 0x8; +pub const RPC_C_MQ_TEMPORARY: DWORD = 0x0000; +pub const RPC_C_MQ_PERMANENT: DWORD = 0x0001; +pub const RPC_C_MQ_CLEAR_ON_OPEN: DWORD = 0x0002; +pub const RPC_C_MQ_USE_EXISTING_SECURITY: DWORD = 0x0004; +pub const RPC_C_MQ_AUTHN_LEVEL_NONE: DWORD = 0x0000; +pub const RPC_C_MQ_AUTHN_LEVEL_PKT_INTEGRITY: DWORD = 0x0008; +pub const RPC_C_MQ_AUTHN_LEVEL_PKT_PRIVACY: DWORD = 0x0010; +pub const RPC_C_OPT_MQ_DELIVERY: DWORD = 1; +pub const RPC_C_OPT_MQ_PRIORITY: DWORD = 2; +pub const RPC_C_OPT_MQ_JOURNAL: DWORD = 3; +pub const RPC_C_OPT_MQ_ACKNOWLEDGE: DWORD = 4; +pub const RPC_C_OPT_MQ_AUTHN_SERVICE: DWORD = 5; +pub const RPC_C_OPT_MQ_AUTHN_LEVEL: DWORD = 6; +pub const RPC_C_OPT_MQ_TIME_TO_REACH_QUEUE: DWORD = 7; +pub const RPC_C_OPT_MQ_TIME_TO_BE_RECEIVED: DWORD = 8; +pub const RPC_C_OPT_BINDING_NONCAUSAL: DWORD = 9; +pub const RPC_C_OPT_SECURITY_CALLBACK: DWORD = 10; +pub const RPC_C_OPT_UNIQUE_BINDING: DWORD = 11; +pub const RPC_C_OPT_CALL_TIMEOUT: DWORD = 12; +pub const RPC_C_OPT_DONT_LINGER: DWORD = 13; +pub const RPC_C_OPT_TRUST_PEER: DWORD = 14; +pub const RPC_C_OPT_ASYNC_BLOCK: DWORD = 15; +pub const RPC_C_OPT_OPTIMIZE_TIME: DWORD = 16; +pub const RPC_C_OPT_MAX_OPTIONS: DWORD = 17; +pub const RPC_C_MQ_EXPRESS: DWORD = 0; +pub const RPC_C_MQ_RECOVERABLE: DWORD = 1; +pub const RPC_C_MQ_JOURNAL_NONE: DWORD = 0; +pub const RPC_C_MQ_JOURNAL_DEADLETTER: DWORD = 1; +pub const RPC_C_MQ_JOURNAL_ALWAYS: DWORD = 2; +pub const RPC_C_FULL_CERT_CHAIN: DWORD = 0x0001; +STRUCT!{struct RPC_PROTSEQ_VECTORA { + Count: c_uint, + Protseq: [*mut c_uchar; 1], +}} +STRUCT!{struct RPC_PROTSEQ_VECTORW { + Count: c_uint, + Protseq: [*mut c_ushort; 1], +}} +STRUCT!{struct RPC_POLICY { + Length: c_uint, + EndpointFlags: c_ulong, + NICFlags: c_ulong, +}} +pub type PRPC_POLICY = *mut RPC_POLICY; +FN!{stdcall RPC_OBJECT_INQ_FN( + ObjectUuid: *mut UUID, + TypeUuid: *mut UUID, + Status: *mut RPC_STATUS, +) -> ()} +FN!{stdcall RPC_IF_CALLBACK_FN( + InterfaceUuid: RPC_IF_HANDLE, + Context: *mut c_void, +) -> RPC_STATUS} +FN!{stdcall RPC_SECURITY_CALLBACK_FN( + Context: *mut c_void, +) -> ()} +pub type RPC_MGR_EPV = c_void; +STRUCT!{struct RPC_STATS_VECTOR { + Count: c_uint, + Stats: [c_ulong; 1], +}} +pub const RPC_C_STATS_CALLS_IN: c_ulong = 0; +pub const RPC_C_STATS_CALLS_OUT: c_ulong = 1; +pub const RPC_C_STATS_PKTS_IN: c_ulong = 2; +pub const RPC_C_STATS_PKTS_OUT: c_ulong = 3; +STRUCT!{struct RPC_IF_ID_VECTOR { + Count: c_ulong, + IfId: [*mut RPC_IF_ID; 1], +}} +pub type RPC_AUTH_IDENTITY_HANDLE = *mut c_void; +pub type RPC_AUTHZ_HANDLE = *mut c_void; +pub const RPC_C_AUTHN_LEVEL_DEFAULT: DWORD = 0; +pub const RPC_C_AUTHN_LEVEL_NONE: DWORD = 1; +pub const RPC_C_AUTHN_LEVEL_CONNECT: DWORD = 2; +pub const RPC_C_AUTHN_LEVEL_CALL: DWORD = 3; +pub const RPC_C_AUTHN_LEVEL_PKT: DWORD = 4; +pub const RPC_C_AUTHN_LEVEL_PKT_INTEGRITY: DWORD = 5; +pub const RPC_C_AUTHN_LEVEL_PKT_PRIVACY: DWORD = 6; +pub const RPC_C_IMP_LEVEL_DEFAULT: DWORD = 0; +pub const RPC_C_IMP_LEVEL_ANONYMOUS: DWORD = 1; +pub const RPC_C_IMP_LEVEL_IDENTIFY: DWORD = 2; +pub const RPC_C_IMP_LEVEL_IMPERSONATE: DWORD = 3; +pub const RPC_C_IMP_LEVEL_DELEGATE: DWORD = 4; +pub const RPC_C_QOS_IDENTITY_STATIC: DWORD = 0; +pub const RPC_C_QOS_IDENTITY_DYNAMIC: DWORD = 1; +pub const RPC_C_QOS_CAPABILITIES_DEFAULT: DWORD = 0x0; +pub const RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH: DWORD = 0x1; +pub const RPC_C_QOS_CAPABILITIES_MAKE_FULLSIC: DWORD = 0x2; +pub const RPC_C_QOS_CAPABILITIES_ANY_AUTHORITY: DWORD = 0x4; +pub const RPC_C_QOS_CAPABILITIES_IGNORE_DELEGATE_FAILURE: DWORD = 0x8; +pub const RPC_C_QOS_CAPABILITIES_LOCAL_MA_HINT: DWORD = 0x10; +pub const RPC_C_QOS_CAPABILITIES_SCHANNEL_FULL_AUTH_IDENTITY: DWORD = 0x20; +pub const RPC_C_PROTECT_LEVEL_DEFAULT: DWORD = RPC_C_AUTHN_LEVEL_DEFAULT; +pub const RPC_C_PROTECT_LEVEL_NONE: DWORD = RPC_C_AUTHN_LEVEL_NONE; +pub const RPC_C_PROTECT_LEVEL_CONNECT: DWORD = RPC_C_AUTHN_LEVEL_CONNECT; +pub const RPC_C_PROTECT_LEVEL_CALL: DWORD = RPC_C_AUTHN_LEVEL_CALL; +pub const RPC_C_PROTECT_LEVEL_PKT: DWORD = RPC_C_AUTHN_LEVEL_PKT; +pub const RPC_C_PROTECT_LEVEL_PKT_INTEGRITY: DWORD = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; +pub const RPC_C_PROTECT_LEVEL_PKT_PRIVACY: DWORD = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; +pub const RPC_C_AUTHN_NONE: DWORD = 0; +pub const RPC_C_AUTHN_DCE_PRIVATE: DWORD = 1; +pub const RPC_C_AUTHN_DCE_PUBLIC: DWORD = 2; +pub const RPC_C_AUTHN_DEC_PUBLIC: DWORD = 4; +pub const RPC_C_AUTHN_GSS_NEGOTIATE: DWORD = 9; +pub const RPC_C_AUTHN_WINNT: DWORD = 10; +pub const RPC_C_AUTHN_GSS_SCHANNEL: DWORD = 14; +pub const RPC_C_AUTHN_GSS_KERBEROS: DWORD = 16; +pub const RPC_C_AUTHN_DPA: DWORD = 17; +pub const RPC_C_AUTHN_MSN: DWORD = 18; +pub const RPC_C_AUTHN_DIGEST: DWORD = 21; +pub const RPC_C_AUTHN_KERNEL: DWORD = 20; +pub const RPC_C_AUTHN_NEGO_EXTENDER: DWORD = 30; +pub const RPC_C_AUTHN_PKU2U: DWORD = 31; +pub const RPC_C_AUTHN_LIVE_SSP: DWORD = 32; +pub const RPC_C_AUTHN_LIVEXP_SSP: DWORD = 35; +pub const RPC_C_AUTHN_MSONLINE: DWORD = 82; +pub const RPC_C_AUTHN_MQ: DWORD = 100; +pub const RPC_C_AUTHN_DEFAULT: DWORD = 0xFFFFFFFF; +pub const RPC_C_NO_CREDENTIALS: DWORD = 0xFFFFFFFF; +pub const RPC_C_SECURITY_QOS_VERSION: DWORD = 1; +pub const RPC_C_SECURITY_QOS_VERSION_1: DWORD = 1; +STRUCT!{struct RPC_SECURITY_QOS { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, +}} +pub type PRPC_SECURITY_QOS = *mut RPC_SECURITY_QOS; +STRUCT!{struct SEC_WINNT_AUTH_IDENTITY_W { + User: *mut c_ushort, + UserLength: c_ulong, + Domain: *mut c_ushort, + DomainLength: c_ulong, + Password: *mut c_ushort, + PasswordLength: c_ulong, + Flags: c_ulong, +}} +pub type PSEC_WINNT_AUTH_IDENTITY_W = *mut SEC_WINNT_AUTH_IDENTITY_W; +STRUCT!{struct SEC_WINNT_AUTH_IDENTITY_A { + User: *mut c_uchar, + UserLength: c_ulong, + Domain: *mut c_uchar, + DomainLength: c_ulong, + Password: *mut c_uchar, + PasswordLength: c_ulong, + Flags: c_ulong, +}} +pub type PSEC_WINNT_AUTH_IDENTITY_A = *mut SEC_WINNT_AUTH_IDENTITY_A; +pub const RPC_C_AUTHN_INFO_TYPE_HTTP: c_ulong = 1; +pub const RPC_C_HTTP_AUTHN_TARGET_SERVER: c_ulong = 1; +pub const RPC_C_HTTP_AUTHN_TARGET_PROXY: c_ulong = 2; +pub const RPC_C_HTTP_AUTHN_SCHEME_BASIC: c_ulong = 0x00000001; +pub const RPC_C_HTTP_AUTHN_SCHEME_NTLM: c_ulong = 0x00000002; +pub const RPC_C_HTTP_AUTHN_SCHEME_PASSPORT: c_ulong = 0x00000004; +pub const RPC_C_HTTP_AUTHN_SCHEME_DIGEST: c_ulong = 0x00000008; +pub const RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE: c_ulong = 0x00000010; +pub const RPC_C_HTTP_AUTHN_SCHEME_CERT: c_ulong = 0x00010000; +pub const RPC_C_HTTP_FLAG_USE_SSL: c_ulong = 1; +pub const RPC_C_HTTP_FLAG_USE_FIRST_AUTH_SCHEME: c_ulong = 2; +pub const RPC_C_HTTP_FLAG_IGNORE_CERT_CN_INVALID: c_ulong = 8; +pub const RPC_C_HTTP_FLAG_ENABLE_CERT_REVOCATION_CHECK: c_ulong = 16; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_W { + TransportCredentials: *mut SEC_WINNT_AUTH_IDENTITY_W, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_ushort, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_W = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_W; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_A { + TransportCredentials: *mut SEC_WINNT_AUTH_IDENTITY_A, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_uchar, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_A = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_A; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_V2_W { + TransportCredentials: *mut SEC_WINNT_AUTH_IDENTITY_W, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_ushort, + ProxyCredentials: *mut SEC_WINNT_AUTH_IDENTITY_W, + NumberOfProxyAuthnSchemes: c_ulong, + ProxyAuthnSchemes: *mut c_ulong, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_V2_W = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_V2_W; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_V2_A { + TransportCredentials: *mut SEC_WINNT_AUTH_IDENTITY_A, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_uchar, + ProxyCredentials: *mut SEC_WINNT_AUTH_IDENTITY_A, + NumberOfProxyAuthnSchemes: c_ulong, + ProxyAuthnSchemes: *mut c_ulong, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_V2_A = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_V2_A; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_V3_W { + TransportCredentials: RPC_AUTH_IDENTITY_HANDLE, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_ushort, + ProxyCredentials: *mut RPC_AUTH_IDENTITY_HANDLE, + NumberOfProxyAuthnSchemes: c_ulong, + ProxyAuthnSchemes: *mut c_ulong, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_V3_W = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_V3_W; +STRUCT!{struct RPC_HTTP_TRANSPORT_CREDENTIALS_V3_A { + TransportCredentials: RPC_AUTH_IDENTITY_HANDLE, + Flags: c_ulong, + AuthenticationTarget: c_ulong, + NumberOfAuthnSchemes: c_ulong, + AuthnSchemes: *mut c_ulong, + ServerCertificateSubject: *mut c_uchar, + ProxyCredentials: *mut RPC_AUTH_IDENTITY_HANDLE, + NumberOfProxyAuthnSchemes: c_ulong, + ProxyAuthnSchemes: *mut c_ulong, +}} +pub type PRPC_HTTP_TRANSPORT_CREDENTIALS_V3_A = *mut RPC_HTTP_TRANSPORT_CREDENTIALS_V3_A; +STRUCT!{struct RPC_SECURITY_QOS_V2_W_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_W, +}} +STRUCT!{struct RPC_SECURITY_QOS_V2_W { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V2_W_union, +}} +pub type PRPC_SECURITY_QOS_V2_W = *mut RPC_SECURITY_QOS_V2_W; +STRUCT!{struct RPC_SECURITY_QOS_V2_A_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_A, +}} +STRUCT!{struct RPC_SECURITY_QOS_V2_A { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V2_A_union, +}} +pub type PRPC_SECURITY_QOS_V2_A = *mut RPC_SECURITY_QOS_V2_A; +STRUCT!{struct RPC_SECURITY_QOS_V3_W_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_W, +}} +STRUCT!{struct RPC_SECURITY_QOS_V3_W { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V3_W_union, + Sid: *mut c_void, +}} +pub type PRPC_SECURITY_QOS_V3_W = *mut RPC_SECURITY_QOS_V3_W; +STRUCT!{struct RPC_SECURITY_QOS_V3_A_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_A, +}} +STRUCT!{struct RPC_SECURITY_QOS_V3_A { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V3_A_union, + Sid: *mut c_void, +}} +pub type PRPC_SECURITY_QOS_V3_A = *mut RPC_SECURITY_QOS_V3_A; +STRUCT!{struct RPC_SECURITY_QOS_V4_W_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_W, +}} +STRUCT!{struct RPC_SECURITY_QOS_V4_W { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V4_W_union, + Sid: *mut c_void, + EffectiveOnly: c_uint, +}} +pub type PRPC_SECURITY_QOS_V4_W = *mut RPC_SECURITY_QOS_V4_W; +STRUCT!{struct RPC_SECURITY_QOS_V4_A_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_A, +}} +STRUCT!{struct RPC_SECURITY_QOS_V4_A { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V4_A_union, + Sid: *mut c_void, + EffectiveOnly: c_uint, +}} +pub type PRPC_SECURITY_QOS_V4_A = *mut RPC_SECURITY_QOS_V4_A; +STRUCT!{struct RPC_SECURITY_QOS_V5_W_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_W, +}} +STRUCT!{struct RPC_SECURITY_QOS_V5_W { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V5_W_union, + Sid: *mut c_void, + EffectiveOnly: c_uint, + ServerSecurityDescriptor: *mut c_void, +}} +pub type PRPC_SECURITY_QOS_V5_W = *mut RPC_SECURITY_QOS_V5_W; +STRUCT!{struct RPC_SECURITY_QOS_V5_A_union { + HttpCredentials: *mut RPC_HTTP_TRANSPORT_CREDENTIALS_A, +}} +STRUCT!{struct RPC_SECURITY_QOS_V5_A { + Version: c_ulong, + Capabilities: c_ulong, + IdentityTracking: c_ulong, + ImpersonationType: c_ulong, + AdditionalSecurityInfoType: c_ulong, + u: RPC_SECURITY_QOS_V5_A_union, + Sid: *mut c_void, + EffectiveOnly: c_uint, + ServerSecurityDescriptor: *mut c_void, +}} +pub type PRPC_SECURITY_QOS_V5_A = *mut RPC_SECURITY_QOS_V5_A; +pub const RPC_PROTSEQ_TCP: c_ulong = 0x1; +pub const RPC_PROTSEQ_NMP: c_ulong = 0x2; +pub const RPC_PROTSEQ_LRPC: c_ulong = 0x3; +pub const RPC_PROTSEQ_HTTP: c_ulong = 0x4; +pub const RPC_BHT_OBJECT_UUID_VALID: c_ulong = 0x1; +pub const RPC_BHO_NONCAUSAL: c_ulong = 0x1; +pub const RPC_BHO_DONTLINGER: c_ulong = 0x2; +pub const RPC_BHO_EXCLUSIVE_AND_GUARANTEED: c_ulong = 0x4; +STRUCT!{struct RPC_BINDING_HANDLE_TEMPLATE_V1_W_union { + Reserved: *mut c_ushort, +}} +STRUCT!{struct RPC_BINDING_HANDLE_TEMPLATE_V1_W { + Version: c_ulong, + Flags: c_ulong, + ProtocolSequence: c_ulong, + NetworkAddress: *mut c_ushort, + StringEndpoint: *mut c_ushort, + u1: RPC_BINDING_HANDLE_TEMPLATE_V1_W_union, + ObjectUuid: UUID, +}} +pub type PRPC_BINDING_HANDLE_TEMPLATE_V1_W = *mut RPC_BINDING_HANDLE_TEMPLATE_V1_W; +STRUCT!{struct RPC_BINDING_HANDLE_TEMPLATE_V1_A_union { + Reserved: *mut c_uchar, +}} +STRUCT!{struct RPC_BINDING_HANDLE_TEMPLATE_V1_A { + Version: c_ulong, + Flags: c_ulong, + ProtocolSequence: c_ulong, + NetworkAddress: *mut c_uchar, + StringEndpoint: *mut c_uchar, + u1: RPC_BINDING_HANDLE_TEMPLATE_V1_A_union, + ObjectUuid: UUID, +}} +pub type PRPC_BINDING_HANDLE_TEMPLATE_V1_A = *mut RPC_BINDING_HANDLE_TEMPLATE_V1_A; +STRUCT!{struct RPC_BINDING_HANDLE_SECURITY_V1_W { + Version: c_ulong, + ServerPrincName: *mut c_ushort, + AuthnLevel: c_ulong, + AuthnSvc: c_ulong, + AuthIdentity: *mut SEC_WINNT_AUTH_IDENTITY_W, + SecurityQos: *mut RPC_SECURITY_QOS, +}} +pub type PRPC_BINDING_HANDLE_SECURITY_V1_W = *mut RPC_BINDING_HANDLE_SECURITY_V1_W; +STRUCT!{struct RPC_BINDING_HANDLE_SECURITY_V1_A { + Version: c_ulong, + ServerPrincName: *mut c_uchar, + AuthnLevel: c_ulong, + AuthnSvc: c_ulong, + AuthIdentity: *mut SEC_WINNT_AUTH_IDENTITY_A, + SecurityQos: *mut RPC_SECURITY_QOS, +}} +pub type PRPC_BINDING_HANDLE_SECURITY_V1_A = *mut RPC_BINDING_HANDLE_SECURITY_V1_A; +STRUCT!{struct RPC_BINDING_HANDLE_OPTIONS_V1 { + Version: c_ulong, + Flags: c_ulong, + ComTimeout: c_ulong, + CallTimeout: c_ulong, +}} +pub type PRPC_BINDING_HANDLE_OPTIONS_V1 = *mut RPC_BINDING_HANDLE_OPTIONS_V1; +ENUM!{enum RPC_HTTP_REDIRECTOR_STAGE { + RPCHTTP_RS_REDIRECT = 1, + RPCHTTP_RS_ACCESS_1, + RPCHTTP_RS_SESSION, + RPCHTTP_RS_ACCESS_2, + RPCHTTP_RS_INTERFACE, +}} +FN!{stdcall RPC_NEW_HTTP_PROXY_CHANNEL( + RedirectorStage: RPC_HTTP_REDIRECTOR_STAGE, + ServerName: RPC_WSTR, + ServerPort: RPC_WSTR, + RemoteUser: RPC_WSTR, + AuthType: RPC_WSTR, + ResourceUuid: *mut c_void, + SessionId: *mut c_void, + Interface: *mut c_void, + Reserved: *mut c_void, + Flags: c_ulong, + NewServerName: *mut RPC_WSTR, + NewServerPort: *mut RPC_WSTR, +) -> RPC_STATUS} +FN!{stdcall RPC_HTTP_PROXY_FREE_STRING( + String: RPC_WSTR, +) -> ()} +pub const RPC_C_AUTHZ_NONE: DWORD = 0; +pub const RPC_C_AUTHZ_NAME: DWORD = 1; +pub const RPC_C_AUTHZ_DCE: DWORD = 2; +pub const RPC_C_AUTHZ_DEFAULT: DWORD = 0xffffffff; +FN!{stdcall RPC_AUTH_KEY_RETRIEVAL_FN( + Arg: *mut c_void, + ServerPrincName: RPC_WSTR, + KeyVer: c_ulong, + Key: *mut *mut c_void, + Status: *mut RPC_STATUS, +) -> ()} +STRUCT!{struct RPC_CLIENT_INFORMATION1 { + UserName: *mut c_uchar, + ComputerName: *mut c_uchar, + Privilege: c_ushort, + AuthFlags: c_ulong, +}} +pub type PRPC_CLIENT_INFORMATION1 = *mut RPC_CLIENT_INFORMATION1; +pub type RPC_EP_INQ_HANDLE = *mut I_RPC_HANDLE; +pub const RPC_C_EP_ALL_ELTS: c_ulong = 0; +pub const RPC_C_EP_MATCH_BY_IF: c_ulong = 1; +pub const RPC_C_EP_MATCH_BY_OBJ: c_ulong = 2; +pub const RPC_C_EP_MATCH_BY_BOTH: c_ulong = 3; +pub const RPC_C_VERS_ALL: c_ulong = 1; +pub const RPC_C_VERS_COMPATIBLE: c_ulong = 2; +pub const RPC_C_VERS_EXACT: c_ulong = 3; +pub const RPC_C_VERS_MAJOR_ONLY: c_ulong = 4; +pub const RPC_C_VERS_UPTO: c_ulong = 5; +FN!{stdcall RPC_MGMT_AUTHORIZATION_FN( + ClientBinding: RPC_BINDING_HANDLE, + RequestedMgmtOperation: c_ulong, + Status: *mut RPC_STATUS, +) -> c_int} +pub const RPC_C_MGMT_INQ_IF_IDS: c_ulong = 0; +pub const RPC_C_MGMT_INQ_PRINC_NAME: c_ulong = 1; +pub const RPC_C_MGMT_INQ_STATS: c_ulong = 2; +pub const RPC_C_MGMT_IS_SERVER_LISTEN: c_ulong = 3; +pub const RPC_C_MGMT_STOP_SERVER_LISTEN: c_ulong = 4; +pub const RPC_IF_AUTOLISTEN: c_uint = 0x0001; +pub const RPC_IF_OLE: c_uint = 0x0002; +pub const RPC_IF_ALLOW_UNKNOWN_AUTHORITY: c_uint = 0x0004; +pub const RPC_IF_ALLOW_SECURE_ONLY: c_uint = 0x0008; +pub const RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH: c_uint = 0x0010; +pub const RPC_IF_ALLOW_LOCAL_ONLY: c_uint = 0x0020; +pub const RPC_IF_SEC_NO_CACHE: c_uint = 0x0040; +pub const RPC_IF_SEC_CACHE_PER_PROC: c_uint = 0x0080; +pub const RPC_IF_ASYNC_CALLBACK: c_uint = 0x0100; +pub const RPC_FW_IF_FLAG_DCOM: c_uint = 0x0001; +pub type RPC_INTERFACE_GROUP = *mut c_void; +pub type PRPC_INTERFACE_GROUP = *mut *mut c_void; +STRUCT!{struct RPC_ENDPOINT_TEMPLATEW { + Version: c_ulong, + ProtSeq: RPC_WSTR, + Endpoint: RPC_WSTR, + SecurityDescriptor: *mut c_void, + Backlog: c_ulong, +}} +pub type PRPC_ENDPOINT_TEMPLATEW = *mut RPC_ENDPOINT_TEMPLATEW; +STRUCT!{struct RPC_ENDPOINT_TEMPLATEA { + Version: c_ulong, + ProtSeq: RPC_CSTR, + Endpoint: RPC_CSTR, + SecurityDescriptor: *mut c_void, + Backlog: c_ulong, +}} +pub type PRPC_ENDPOINT_TEMPLATEA = *mut RPC_ENDPOINT_TEMPLATEA; +STRUCT!{struct RPC_INTERFACE_TEMPLATEA { + Version: c_ulong, + IfSpec: RPC_IF_HANDLE, + MgrTypeUuid: *mut UUID, + MgrEpv: *mut RPC_MGR_EPV, + Flags: c_uint, + MaxCalls: c_uint, + MaxRpcSize: c_uint, + IfCallback: *mut RPC_IF_CALLBACK_FN, + UuidVector: *mut UUID_VECTOR, + Annotation: RPC_CSTR, + SecurityDescriptor: *mut c_void, +}} +pub type PRPC_INTERFACE_TEMPLATEA = *mut RPC_INTERFACE_TEMPLATEA; +STRUCT!{struct RPC_INTERFACE_TEMPLATEW { + Version: c_ulong, + IfSpec: RPC_IF_HANDLE, + MgrTypeUuid: *mut UUID, + MgrEpv: *mut RPC_MGR_EPV, + Flags: c_uint, + MaxCalls: c_uint, + MaxRpcSize: c_uint, + IfCallback: *mut RPC_IF_CALLBACK_FN, + UuidVector: *mut UUID_VECTOR, + Annotation: RPC_WSTR, + SecurityDescriptor: *mut c_void, +}} +pub type PRPC_INTERFACE_TEMPLATEW = *mut RPC_INTERFACE_TEMPLATEW; +FN!{stdcall RPC_INTERFACE_GROUP_IDLE_CALLBACK_FN( + IfGroup: RPC_INTERFACE_GROUP, + IdleCallbackContext: *mut c_void, + IsGroupIdle: c_ulong, +) -> ()} diff --git a/winapi/src/shared/rpcndr.rs b/winapi/src/shared/rpcndr.rs new file mode 100644 index 000000000..b65a3da05 --- /dev/null +++ b/winapi/src/shared/rpcndr.rs @@ -0,0 +1,25 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{__int64, __uint64, c_char, c_uchar, c_ulong}; +pub const NDR_CHAR_REP_MASK: c_ulong = 0x0000000F; +pub const NDR_INT_REP_MASK: c_ulong = 0x000000F0; +pub const NDR_FLOAT_REP_MASK: c_ulong = 0x0000FF00; +pub const NDR_LITTLE_ENDIAN: c_ulong = 0x00000010; +pub const NDR_BIG_ENDIAN: c_ulong = 0x00000000; +pub const NDR_IEEE_FLOAT: c_ulong = 0x00000000; +pub const NDR_VAX_FLOAT: c_ulong = 0x00000100; +pub const NDR_IBM_FLOAT: c_ulong = 0x00000300; +pub const NDR_ASCII_CHAR: c_ulong = 0x00000000; +pub const NDR_EBCDIC_CHAR: c_ulong = 0x00000001; +pub const NDR_LOCAL_DATA_REPRESENTATION: c_ulong = 0x00000010; +pub const NDR_LOCAL_ENDIAN: c_ulong = NDR_LITTLE_ENDIAN; +pub type small = c_char; +pub type byte = c_uchar; +pub type cs_byte = byte; +pub type boolean = c_uchar; +pub type hyper = __int64; +pub type MIDL_uhyper = __uint64; +// TODO Finish the rest diff --git a/winapi/src/shared/sddl.rs b/winapi/src/shared/sddl.rs new file mode 100644 index 000000000..cf64387a4 --- /dev/null +++ b/winapi/src/shared/sddl.rs @@ -0,0 +1,217 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::SIZE_T; +use shared::minwindef::{BOOL, DWORD, PULONG, UCHAR}; +use um::winnt::{LPCSTR, LPCWSTR, LPSTR, LPWSTR, PSECURITY_DESCRIPTOR, PSID, SECURITY_INFORMATION}; +pub const SDDL_REVISION_1: UCHAR = 1; +pub const SDDL_REVISION: UCHAR = SDDL_REVISION_1; +pub const SDDL_OWNER: &'static str = "O"; +pub const SDDL_GROUP: &'static str = "G"; +pub const SDDL_DACL: &'static str = "D"; +pub const SDDL_SACL: &'static str = "S"; +pub const SDDL_PROTECTED: &'static str = "P"; +pub const SDDL_AUTO_INHERIT_REQ: &'static str = "AR"; +pub const SDDL_AUTO_INHERITED: &'static str = "AI"; +pub const SDDL_NULL_ACL: &'static str = "NO_ACCESS_CONTROL"; +pub const SDDL_ACCESS_ALLOWED: &'static str = "A"; +pub const SDDL_ACCESS_DENIED: &'static str = "D"; +pub const SDDL_OBJECT_ACCESS_ALLOWED: &'static str = "OA"; +pub const SDDL_OBJECT_ACCESS_DENIED: &'static str = "OD"; +pub const SDDL_AUDIT: &'static str = "AU"; +pub const SDDL_ALARM: &'static str = "AL"; +pub const SDDL_OBJECT_AUDIT: &'static str = "OU"; +pub const SDDL_OBJECT_ALARM: &'static str = "OL"; +pub const SDDL_MANDATORY_LABEL: &'static str = "ML"; +pub const SDDL_PROCESS_TRUST_LABEL: &'static str = "TL"; +pub const SDDL_CALLBACK_ACCESS_ALLOWED: &'static str = "XA"; +pub const SDDL_CALLBACK_ACCESS_DENIED: &'static str = "XD"; +pub const SDDL_RESOURCE_ATTRIBUTE: &'static str = "RA"; +pub const SDDL_SCOPED_POLICY_ID: &'static str = "SP"; +pub const SDDL_CALLBACK_AUDIT: &'static str = "XU"; +pub const SDDL_CALLBACK_OBJECT_ACCESS_ALLOWED: &'static str = "ZA"; +pub const SDDL_ACCESS_FILTER: &'static str = "FL"; +pub const SDDL_INT: &'static str = "TI"; +pub const SDDL_UINT: &'static str = "TU"; +pub const SDDL_WSTRING: &'static str = "TS"; +pub const SDDL_SID: &'static str = "TD"; +pub const SDDL_BLOB: &'static str = "TX"; +pub const SDDL_BOOLEAN: &'static str = "TB"; +pub const SDDL_CONTAINER_INHERIT: &'static str = "CI"; +pub const SDDL_OBJECT_INHERIT: &'static str = "OI"; +pub const SDDL_NO_PROPAGATE: &'static str = "NP"; +pub const SDDL_INHERIT_ONLY: &'static str = "IO"; +pub const SDDL_INHERITED: &'static str = "ID"; +pub const SDDL_TRUST_PROTECTED_FILTER: &'static str = "TP"; +pub const SDDL_AUDIT_SUCCESS: &'static str = "SA"; +pub const SDDL_AUDIT_FAILURE: &'static str = "FA"; +pub const SDDL_READ_PROPERTY: &'static str = "RP"; +pub const SDDL_WRITE_PROPERTY: &'static str = "WP"; +pub const SDDL_CREATE_CHILD: &'static str = "CC"; +pub const SDDL_DELETE_CHILD: &'static str = "DC"; +pub const SDDL_LIST_CHILDREN: &'static str = "LC"; +pub const SDDL_SELF_WRITE: &'static str = "SW"; +pub const SDDL_LIST_OBJECT: &'static str = "LO"; +pub const SDDL_DELETE_TREE: &'static str = "DT"; +pub const SDDL_CONTROL_ACCESS: &'static str = "CR"; +pub const SDDL_READ_CONTROL: &'static str = "RC"; +pub const SDDL_WRITE_DAC: &'static str = "WD"; +pub const SDDL_WRITE_OWNER: &'static str = "WO"; +pub const SDDL_STANDARD_DELETE: &'static str = "SD"; +pub const SDDL_GENERIC_ALL: &'static str = "GA"; +pub const SDDL_GENERIC_READ: &'static str = "GR"; +pub const SDDL_GENERIC_WRITE: &'static str = "GW"; +pub const SDDL_GENERIC_EXECUTE: &'static str = "GX"; +pub const SDDL_FILE_ALL: &'static str = "FA"; +pub const SDDL_FILE_READ: &'static str = "FR"; +pub const SDDL_FILE_WRITE: &'static str = "FW"; +pub const SDDL_FILE_EXECUTE: &'static str = "FX"; +pub const SDDL_KEY_ALL: &'static str = "KA"; +pub const SDDL_KEY_READ: &'static str = "KR"; +pub const SDDL_KEY_WRITE: &'static str = "KW"; +pub const SDDL_KEY_EXECUTE: &'static str = "KX"; +pub const SDDL_NO_WRITE_UP: &'static str = "NW"; +pub const SDDL_NO_READ_UP: &'static str = "NR"; +pub const SDDL_NO_EXECUTE_UP: &'static str = "NX"; +pub const SDDL_ALIAS_SIZE: SIZE_T = 2; +pub const SDDL_DOMAIN_ADMINISTRATORS: &'static str = "DA"; +pub const SDDL_DOMAIN_GUESTS: &'static str = "DG"; +pub const SDDL_DOMAIN_USERS: &'static str = "DU"; +pub const SDDL_ENTERPRISE_DOMAIN_CONTROLLERS: &'static str = "ED"; +pub const SDDL_DOMAIN_DOMAIN_CONTROLLERS: &'static str = "DD"; +pub const SDDL_DOMAIN_COMPUTERS: &'static str = "DC"; +pub const SDDL_BUILTIN_ADMINISTRATORS: &'static str = "BA"; +pub const SDDL_BUILTIN_GUESTS: &'static str = "BG"; +pub const SDDL_BUILTIN_USERS: &'static str = "BU"; +pub const SDDL_LOCAL_ADMIN: &'static str = "LA"; +pub const SDDL_LOCAL_GUEST: &'static str = "LG"; +pub const SDDL_ACCOUNT_OPERATORS: &'static str = "AO"; +pub const SDDL_BACKUP_OPERATORS: &'static str = "BO"; +pub const SDDL_PRINTER_OPERATORS: &'static str = "PO"; +pub const SDDL_SERVER_OPERATORS: &'static str = "SO"; +pub const SDDL_AUTHENTICATED_USERS: &'static str = "AU"; +pub const SDDL_PERSONAL_SELF: &'static str = "PS"; +pub const SDDL_CREATOR_OWNER: &'static str = "CO"; +pub const SDDL_CREATOR_GROUP: &'static str = "CG"; +pub const SDDL_LOCAL_SYSTEM: &'static str = "SY"; +pub const SDDL_POWER_USERS: &'static str = "PU"; +pub const SDDL_EVERYONE: &'static str = "WD"; +pub const SDDL_REPLICATOR: &'static str = "RE"; +pub const SDDL_INTERACTIVE: &'static str = "IU"; +pub const SDDL_NETWORK: &'static str = "NU"; +pub const SDDL_SERVICE: &'static str = "SU"; +pub const SDDL_RESTRICTED_CODE: &'static str = "RC"; +pub const SDDL_WRITE_RESTRICTED_CODE: &'static str = "WR"; +pub const SDDL_ANONYMOUS: &'static str = "AN"; +pub const SDDL_SCHEMA_ADMINISTRATORS: &'static str = "SA"; +pub const SDDL_CERT_SERV_ADMINISTRATORS: &'static str = "CA"; +pub const SDDL_RAS_SERVERS: &'static str = "RS"; +pub const SDDL_ENTERPRISE_ADMINS: &'static str = "EA"; +pub const SDDL_GROUP_POLICY_ADMINS: &'static str = "PA"; +pub const SDDL_ALIAS_PREW2KCOMPACC: &'static str = "RU"; +pub const SDDL_LOCAL_SERVICE: &'static str = "LS"; +pub const SDDL_NETWORK_SERVICE: &'static str = "NS"; +pub const SDDL_REMOTE_DESKTOP: &'static str = "RD"; +pub const SDDL_NETWORK_CONFIGURATION_OPS: &'static str = "NO"; +pub const SDDL_PERFMON_USERS: &'static str = "MU"; +pub const SDDL_PERFLOG_USERS: &'static str = "LU"; +pub const SDDL_IIS_USERS: &'static str = "IS"; +pub const SDDL_CRYPTO_OPERATORS: &'static str = "CY"; +pub const SDDL_OWNER_RIGHTS: &'static str = "OW"; +pub const SDDL_EVENT_LOG_READERS: &'static str = "ER"; +pub const SDDL_ENTERPRISE_RO_DCs: &'static str = "RO"; +pub const SDDL_CERTSVC_DCOM_ACCESS: &'static str = "CD"; +pub const SDDL_ALL_APP_PACKAGES: &'static str = "AC"; +pub const SDDL_RDS_REMOTE_ACCESS_SERVERS: &'static str = "RA"; +pub const SDDL_RDS_ENDPOINT_SERVERS: &'static str = "ES"; +pub const SDDL_RDS_MANAGEMENT_SERVERS: &'static str = "MS"; +pub const SDDL_USER_MODE_DRIVERS: &'static str = "UD"; +pub const SDDL_HYPER_V_ADMINS: &'static str = "HA"; +pub const SDDL_CLONEABLE_CONTROLLERS: &'static str = "CN"; +pub const SDDL_ACCESS_CONTROL_ASSISTANCE_OPS: &'static str = "AA"; +pub const SDDL_REMOTE_MANAGEMENT_USERS: &'static str = "RM"; +pub const SDDL_AUTHORITY_ASSERTED: &'static str = "AS"; +pub const SDDL_SERVICE_ASSERTED: &'static str = "SS"; +pub const SDDL_PROTECTED_USERS: &'static str = "AP"; +pub const SDDL_KEY_ADMINS: &'static str = "KA"; +pub const SDDL_ENTERPRISE_KEY_ADMINS: &'static str = "EK"; +pub const SDDL_ML_LOW: &'static str = "LW"; +pub const SDDL_ML_MEDIUM: &'static str = "ME"; +pub const SDDL_ML_MEDIUM_PLUS: &'static str = "MP"; +pub const SDDL_ML_HIGH: &'static str = "HI"; +pub const SDDL_ML_SYSTEM: &'static str = "SI"; +pub const SDDL_SEPERATORC: char = ';'; +pub const SDDL_DELIMINATORC: char = ':'; +pub const SDDL_ACE_BEGINC: char = '('; +pub const SDDL_ACE_ENDC: char = ')'; +pub const SDDL_SPACEC: char = ' '; +pub const SDDL_ACE_COND_BEGINC: char = '('; +pub const SDDL_ACE_COND_ENDC: char = ')'; +pub const SDDL_ACE_COND_STRING_BEGINC: char = '"'; +pub const SDDL_ACE_COND_STRING_ENDC: char = '"'; +pub const SDDL_ACE_COND_COMPOSITEVALUE_BEGINC: char = '{'; +pub const SDDL_ACE_COND_COMPOSITEVALUE_ENDC: char = '}'; +pub const SDDL_ACE_COND_COMPOSITEVALUE_SEPERATORC: char = ','; +pub const SDDL_ACE_COND_BLOB_PREFIXC: char = '#'; +pub const SDDL_ACE_COND_SID_BEGINC: char = '('; +pub const SDDL_ACE_COND_SID_ENDC: char = ')'; +pub const SDDL_SEPERATOR: &'static str = ";"; +pub const SDDL_DELIMINATOR: &'static str = ":"; +pub const SDDL_ACE_BEGIN: &'static str = "("; +pub const SDDL_ACE_END: &'static str = ")"; +pub const SDDL_ACE_COND_BEGIN: &'static str = "("; +pub const SDDL_ACE_COND_END: &'static str = ")"; +pub const SDDL_SPACE: &'static str = " "; +pub const SDDL_ACE_COND_BLOB_PREFIX: &'static str = "#"; +pub const SDDL_ACE_COND_SID_PREFIX: &'static str = "SID"; +pub const SDDL_ACE_COND_ATTRIBUTE_PREFIX: &'static str = "@"; +pub const SDDL_ACE_COND_USER_ATTRIBUTE_PREFIX: &'static str = "@USER."; +pub const SDDL_ACE_COND_RESOURCE_ATTRIBUTE_PREFIX: &'static str = "@RESOURCE."; +pub const SDDL_ACE_COND_DEVICE_ATTRIBUTE_PREFIX: &'static str = "@DEVICE."; +pub const SDDL_ACE_COND_TOKEN_ATTRIBUTE_PREFIX: &'static str = "@TOKEN."; +extern "system" { + pub fn ConvertSidToStringSidA( + Sid: PSID, + StringSid: *mut LPSTR, + ) -> BOOL; + pub fn ConvertSidToStringSidW( + Sid: PSID, + StringSid: *mut LPWSTR, + ) -> BOOL; + pub fn ConvertStringSidToSidA( + StringSid: LPCSTR, + Sid: *mut PSID, + ) -> BOOL; + pub fn ConvertStringSidToSidW( + StringSid: LPCWSTR, + Sid: *mut PSID, + ) -> BOOL; + pub fn ConvertStringSecurityDescriptorToSecurityDescriptorA( + StringSecurityDescriptor: LPCSTR, + StringSDRevision: DWORD, + SecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + SecurityDescriptorSize: PULONG, + ) -> BOOL; + pub fn ConvertStringSecurityDescriptorToSecurityDescriptorW( + StringSecurityDescriptor: LPCWSTR, + StringSDRevision: DWORD, + SecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + SecurityDescriptorSize: PULONG, + ) -> BOOL; + pub fn ConvertSecurityDescriptorToStringSecurityDescriptorA( + SecurityDescriptor: PSECURITY_DESCRIPTOR, + RequestedStringSDRevision: DWORD, + SecurityInformation: SECURITY_INFORMATION, + StringSecurityDescriptor: *mut LPSTR, + StringSecurityDescriptorLen: PULONG, + ) -> BOOL; + pub fn ConvertSecurityDescriptorToStringSecurityDescriptorW( + SecurityDescriptor: PSECURITY_DESCRIPTOR, + RequestedStringSDRevision: DWORD, + SecurityInformation: SECURITY_INFORMATION, + StringSecurityDescriptor: *mut LPWSTR, + StringSecurityDescriptorLen: PULONG, + ) -> BOOL; +} diff --git a/winapi/src/shared/sspi.rs b/winapi/src/shared/sspi.rs new file mode 100644 index 000000000..3b7c2d68a --- /dev/null +++ b/winapi/src/shared/sspi.rs @@ -0,0 +1,1074 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Security Support Provider Interface Prototypes and structure definitions +use ctypes::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}; +use shared::basetsd::ULONG_PTR; +use shared::guiddef::GUID; +use shared::minwindef::{PUCHAR, ULONG, USHORT}; +use um::subauth::PUNICODE_STRING; +use um::wincred::{PCREDUI_INFOA, PCREDUI_INFOW}; +use um::winnt::{ + ANYSIZE_ARRAY, BOOLEAN, CHAR, HANDLE, LARGE_INTEGER, LONG, LPSTR, LPWSTR, LUID, PCSTR, PCWSTR, + PVOID, WCHAR +}; +pub type SEC_WCHAR = WCHAR; +pub type SEC_CHAR = CHAR; +pub type SECURITY_STATUS = LONG; +STRUCT!{struct SecHandle { + dwLower: ULONG_PTR, + dwUpper: ULONG_PTR, +}} +pub type PSecHandle = *mut SecHandle; +pub const SEC_DELETED_HANDLE: ULONG_PTR = 2; +pub type CredHandle = SecHandle; +pub type PCredHandle = PSecHandle; +pub type CtxtHandle = SecHandle; +pub type PCtxtHandle = PSecHandle; +pub type SECURITY_INTEGER = LARGE_INTEGER; +pub type PSECURITY_INTEGER = *mut LARGE_INTEGER; +pub type TimeStamp = SECURITY_INTEGER; +pub type PTimeStamp = *mut SECURITY_INTEGER; +STRUCT!{struct SECURITY_STRING { + Length: c_ushort, + MaximumLength: c_ushort, + Buffer: *mut c_ushort, +}} +pub type PSECURITY_STRING = *mut SECURITY_STRING; +STRUCT!{struct SecPkgInfoW { + fCapabilities: c_ulong, + wVersion: c_ushort, + wRPCID: c_ushort, + cbMaxToken: c_ulong, + Name: *mut SEC_WCHAR, + Comment: *mut SEC_WCHAR, +}} +pub type PSecPkgInfoW = *mut SecPkgInfoW; +STRUCT!{struct SecPkgInfoA { + fCapabilities: c_ulong, + wVersion: c_ushort, + wRPCID: c_ushort, + cbMaxToken: c_ulong, + Name: *mut SEC_CHAR, + Comment: *mut SEC_CHAR, +}} +pub type PSecPkgInfoA = *mut SecPkgInfoA; +pub const SECPKG_FLAG_INTEGRITY: c_ulong = 0x00000001; +pub const SECPKG_FLAG_PRIVACY: c_ulong = 0x00000002; +pub const SECPKG_FLAG_TOKEN_ONLY: c_ulong = 0x00000004; +pub const SECPKG_FLAG_DATAGRAM: c_ulong = 0x00000008; +pub const SECPKG_FLAG_CONNECTION: c_ulong = 0x00000010; +pub const SECPKG_FLAG_MULTI_REQUIRED: c_ulong = 0x00000020; +pub const SECPKG_FLAG_CLIENT_ONLY: c_ulong = 0x00000040; +pub const SECPKG_FLAG_EXTENDED_ERROR: c_ulong = 0x00000080; +pub const SECPKG_FLAG_IMPERSONATION: c_ulong = 0x00000100; +pub const SECPKG_FLAG_ACCEPT_WIN32_NAME: c_ulong = 0x00000200; +pub const SECPKG_FLAG_STREAM: c_ulong = 0x00000400; +pub const SECPKG_FLAG_NEGOTIABLE: c_ulong = 0x00000800; +pub const SECPKG_FLAG_GSS_COMPATIBLE: c_ulong = 0x00001000; +pub const SECPKG_FLAG_LOGON: c_ulong = 0x00002000; +pub const SECPKG_FLAG_ASCII_BUFFERS: c_ulong = 0x00004000; +pub const SECPKG_FLAG_FRAGMENT: c_ulong = 0x00008000; +pub const SECPKG_FLAG_MUTUAL_AUTH: c_ulong = 0x00010000; +pub const SECPKG_FLAG_DELEGATION: c_ulong = 0x00020000; +pub const SECPKG_FLAG_READONLY_WITH_CHECKSUM: c_ulong = 0x00040000; +pub const SECPKG_FLAG_RESTRICTED_TOKENS: c_ulong = 0x00080000; +pub const SECPKG_FLAG_NEGO_EXTENDER: c_ulong = 0x00100000; +pub const SECPKG_FLAG_NEGOTIABLE2: c_ulong = 0x00200000; +pub const SECPKG_FLAG_APPCONTAINER_PASSTHROUGH: c_ulong = 0x00400000; +pub const SECPKG_FLAG_APPCONTAINER_CHECKS: c_ulong = 0x00800000; +pub const SECPKG_ID_NONE: c_ulong = 0xFFFF; +pub const SECPKG_CALLFLAGS_APPCONTAINER: c_ulong = 0x00000001; +pub const SECPKG_CALLFLAGS_APPCONTAINER_AUTHCAPABLE: c_ulong = 0x00000002; +pub const SECPKG_CALLFLAGS_FORCE_SUPPLIED: c_ulong = 0x00000004; +STRUCT!{struct SecBuffer { + cbBuffer: c_ulong, + BufferType: c_ulong, + pvBuffer: *mut c_void, +}} +pub type PSecBuffer = *mut SecBuffer; +STRUCT!{struct SecBufferDesc { + ulVersion: c_ulong, + cBuffers: c_ulong, + pBuffers: PSecBuffer, +}} +pub type PSecBufferDesc = *mut SecBufferDesc; +pub const SECBUFFER_VERSION: c_ulong = 0; +pub const SECBUFFER_EMPTY: c_ulong = 0; +pub const SECBUFFER_DATA: c_ulong = 1; +pub const SECBUFFER_TOKEN: c_ulong = 2; +pub const SECBUFFER_PKG_PARAMS: c_ulong = 3; +pub const SECBUFFER_MISSING: c_ulong = 4; +pub const SECBUFFER_EXTRA: c_ulong = 5; +pub const SECBUFFER_STREAM_TRAILER: c_ulong = 6; +pub const SECBUFFER_STREAM_HEADER: c_ulong = 7; +pub const SECBUFFER_NEGOTIATION_INFO: c_ulong = 8; +pub const SECBUFFER_PADDING: c_ulong = 9; +pub const SECBUFFER_STREAM: c_ulong = 10; +pub const SECBUFFER_MECHLIST: c_ulong = 11; +pub const SECBUFFER_MECHLIST_SIGNATURE: c_ulong = 12; +pub const SECBUFFER_TARGET: c_ulong = 13; +pub const SECBUFFER_CHANNEL_BINDINGS: c_ulong = 14; +pub const SECBUFFER_CHANGE_PASS_RESPONSE: c_ulong = 15; +pub const SECBUFFER_TARGET_HOST: c_ulong = 16; +pub const SECBUFFER_ALERT: c_ulong = 17; +pub const SECBUFFER_APPLICATION_PROTOCOLS: c_ulong = 18; +pub const SECBUFFER_ATTRMASK: c_ulong = 0xF0000000; +pub const SECBUFFER_READONLY: c_ulong = 0x80000000; +pub const SECBUFFER_READONLY_WITH_CHECKSUM: c_ulong = 0x10000000; +pub const SECBUFFER_RESERVED: c_ulong = 0x60000000; +STRUCT!{struct SEC_NEGOTIATION_INFO { + Size: c_ulong, + NameLength: c_ulong, + Name: *mut SEC_WCHAR, + Reserved: *mut c_void, +}} +pub type PSEC_NEGOTIATION_INFO = *mut SEC_NEGOTIATION_INFO; +STRUCT!{struct SEC_CHANNEL_BINDINGS { + dwInitiatorAddrType: c_ulong, + cbInitiatorLength: c_ulong, + dwInitiatorOffset: c_ulong, + dwAcceptorAddrType: c_ulong, + cbAcceptorLength: c_ulong, + dwAcceptorOffset: c_ulong, + cbApplicationDataLength: c_ulong, + dwApplicationDataOffset: c_ulong, +}} +pub type PSEC_CHANNEL_BINDINGS = *mut SEC_CHANNEL_BINDINGS; +ENUM!{enum SEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT { + SecApplicationProtocolNegotiationExt_None, + SecApplicationProtocolNegotiationExt_NPN, + SecApplicationProtocolNegotiationExt_ALPN, +}} +pub type PSEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT = *mut SEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT; +STRUCT!{struct SEC_APPLICATION_PROTOCOL_LIST { + ProtoNegoExt: SEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT, + ProtocolListSize: c_ushort, + ProtocolList: [c_uchar; 0], +}} +pub type PSEC_APPLICATION_PROTOCOL_LIST = *mut SEC_APPLICATION_PROTOCOL_LIST; +STRUCT!{struct SEC_APPLICATION_PROTOCOLS { + ProtocolListsSize: c_ulong, + ProtocolLists: [SEC_APPLICATION_PROTOCOL_LIST; ANYSIZE_ARRAY], +}} +pub type PSEC_APPLICATION_PROTOCOLS = *mut SEC_APPLICATION_PROTOCOLS; +pub const SECURITY_NATIVE_DREP: c_ulong = 0x00000010; +pub const SECURITY_NETWORK_DREP: c_ulong = 0x00000000; +pub const SECPKG_CRED_INBOUND: c_ulong = 0x00000001; +pub const SECPKG_CRED_OUTBOUND: c_ulong = 0x00000002; +pub const SECPKG_CRED_BOTH: c_ulong = 0x00000003; +pub const SECPKG_CRED_DEFAULT: c_ulong = 0x00000004; +pub const SECPKG_CRED_RESERVED: c_ulong = 0xF0000000; +pub const SECPKG_CRED_AUTOLOGON_RESTRICTED: c_ulong = 0x00000010; +pub const SECPKG_CRED_PROCESS_POLICY_ONLY: c_ulong = 0x00000020; +pub const ISC_REQ_DELEGATE: c_ulong = 0x00000001; +pub const ISC_REQ_MUTUAL_AUTH: c_ulong = 0x00000002; +pub const ISC_REQ_REPLAY_DETECT: c_ulong = 0x00000004; +pub const ISC_REQ_SEQUENCE_DETECT: c_ulong = 0x00000008; +pub const ISC_REQ_CONFIDENTIALITY: c_ulong = 0x00000010; +pub const ISC_REQ_USE_SESSION_KEY: c_ulong = 0x00000020; +pub const ISC_REQ_PROMPT_FOR_CREDS: c_ulong = 0x00000040; +pub const ISC_REQ_USE_SUPPLIED_CREDS: c_ulong = 0x00000080; +pub const ISC_REQ_ALLOCATE_MEMORY: c_ulong = 0x00000100; +pub const ISC_REQ_USE_DCE_STYLE: c_ulong = 0x00000200; +pub const ISC_REQ_DATAGRAM: c_ulong = 0x00000400; +pub const ISC_REQ_CONNECTION: c_ulong = 0x00000800; +pub const ISC_REQ_CALL_LEVEL: c_ulong = 0x00001000; +pub const ISC_REQ_FRAGMENT_SUPPLIED: c_ulong = 0x00002000; +pub const ISC_REQ_EXTENDED_ERROR: c_ulong = 0x00004000; +pub const ISC_REQ_STREAM: c_ulong = 0x00008000; +pub const ISC_REQ_INTEGRITY: c_ulong = 0x00010000; +pub const ISC_REQ_IDENTIFY: c_ulong = 0x00020000; +pub const ISC_REQ_NULL_SESSION: c_ulong = 0x00040000; +pub const ISC_REQ_MANUAL_CRED_VALIDATION: c_ulong = 0x00080000; +pub const ISC_REQ_RESERVED1: c_ulong = 0x00100000; +pub const ISC_REQ_FRAGMENT_TO_FIT: c_ulong = 0x00200000; +pub const ISC_REQ_FORWARD_CREDENTIALS: c_ulong = 0x00400000; +pub const ISC_REQ_NO_INTEGRITY: c_ulong = 0x00800000; +pub const ISC_REQ_USE_HTTP_STYLE: c_ulong = 0x01000000; +pub const ISC_REQ_UNVERIFIED_TARGET_NAME: c_ulong = 0x20000000; +pub const ISC_REQ_CONFIDENTIALITY_ONLY: c_ulong = 0x40000000; +pub const ISC_RET_DELEGATE: c_ulong = 0x00000001; +pub const ISC_RET_MUTUAL_AUTH: c_ulong = 0x00000002; +pub const ISC_RET_REPLAY_DETECT: c_ulong = 0x00000004; +pub const ISC_RET_SEQUENCE_DETECT: c_ulong = 0x00000008; +pub const ISC_RET_CONFIDENTIALITY: c_ulong = 0x00000010; +pub const ISC_RET_USE_SESSION_KEY: c_ulong = 0x00000020; +pub const ISC_RET_USED_COLLECTED_CREDS: c_ulong = 0x00000040; +pub const ISC_RET_USED_SUPPLIED_CREDS: c_ulong = 0x00000080; +pub const ISC_RET_ALLOCATED_MEMORY: c_ulong = 0x00000100; +pub const ISC_RET_USED_DCE_STYLE: c_ulong = 0x00000200; +pub const ISC_RET_DATAGRAM: c_ulong = 0x00000400; +pub const ISC_RET_CONNECTION: c_ulong = 0x00000800; +pub const ISC_RET_INTERMEDIATE_RETURN: c_ulong = 0x00001000; +pub const ISC_RET_CALL_LEVEL: c_ulong = 0x00002000; +pub const ISC_RET_EXTENDED_ERROR: c_ulong = 0x00004000; +pub const ISC_RET_STREAM: c_ulong = 0x00008000; +pub const ISC_RET_INTEGRITY: c_ulong = 0x00010000; +pub const ISC_RET_IDENTIFY: c_ulong = 0x00020000; +pub const ISC_RET_NULL_SESSION: c_ulong = 0x00040000; +pub const ISC_RET_MANUAL_CRED_VALIDATION: c_ulong = 0x00080000; +pub const ISC_RET_RESERVED1: c_ulong = 0x00100000; +pub const ISC_RET_FRAGMENT_ONLY: c_ulong = 0x00200000; +pub const ISC_RET_FORWARD_CREDENTIALS: c_ulong = 0x00400000; +pub const ISC_RET_USED_HTTP_STYLE: c_ulong = 0x01000000; +pub const ISC_RET_NO_ADDITIONAL_TOKEN: c_ulong = 0x02000000; +pub const ISC_RET_REAUTHENTICATION: c_ulong = 0x08000000; +pub const ISC_RET_CONFIDENTIALITY_ONLY: c_ulong = 0x40000000; +pub const ASC_REQ_DELEGATE: c_ulong = 0x00000001; +pub const ASC_REQ_MUTUAL_AUTH: c_ulong = 0x00000002; +pub const ASC_REQ_REPLAY_DETECT: c_ulong = 0x00000004; +pub const ASC_REQ_SEQUENCE_DETECT: c_ulong = 0x00000008; +pub const ASC_REQ_CONFIDENTIALITY: c_ulong = 0x00000010; +pub const ASC_REQ_USE_SESSION_KEY: c_ulong = 0x00000020; +pub const ASC_REQ_SESSION_TICKET: c_ulong = 0x00000040; +pub const ASC_REQ_ALLOCATE_MEMORY: c_ulong = 0x00000100; +pub const ASC_REQ_USE_DCE_STYLE: c_ulong = 0x00000200; +pub const ASC_REQ_DATAGRAM: c_ulong = 0x00000400; +pub const ASC_REQ_CONNECTION: c_ulong = 0x00000800; +pub const ASC_REQ_CALL_LEVEL: c_ulong = 0x00001000; +pub const ASC_REQ_EXTENDED_ERROR: c_ulong = 0x00008000; +pub const ASC_REQ_STREAM: c_ulong = 0x00010000; +pub const ASC_REQ_INTEGRITY: c_ulong = 0x00020000; +pub const ASC_REQ_LICENSING: c_ulong = 0x00040000; +pub const ASC_REQ_IDENTIFY: c_ulong = 0x00080000; +pub const ASC_REQ_ALLOW_NULL_SESSION: c_ulong = 0x00100000; +pub const ASC_REQ_ALLOW_NON_USER_LOGONS: c_ulong = 0x00200000; +pub const ASC_REQ_ALLOW_CONTEXT_REPLAY: c_ulong = 0x00400000; +pub const ASC_REQ_FRAGMENT_TO_FIT: c_ulong = 0x00800000; +pub const ASC_REQ_FRAGMENT_SUPPLIED: c_ulong = 0x00002000; +pub const ASC_REQ_NO_TOKEN: c_ulong = 0x01000000; +pub const ASC_REQ_PROXY_BINDINGS: c_ulong = 0x04000000; +pub const ASC_REQ_ALLOW_MISSING_BINDINGS: c_ulong = 0x10000000; +pub const ASC_RET_DELEGATE: c_ulong = 0x00000001; +pub const ASC_RET_MUTUAL_AUTH: c_ulong = 0x00000002; +pub const ASC_RET_REPLAY_DETECT: c_ulong = 0x00000004; +pub const ASC_RET_SEQUENCE_DETECT: c_ulong = 0x00000008; +pub const ASC_RET_CONFIDENTIALITY: c_ulong = 0x00000010; +pub const ASC_RET_USE_SESSION_KEY: c_ulong = 0x00000020; +pub const ASC_RET_SESSION_TICKET: c_ulong = 0x00000040; +pub const ASC_RET_ALLOCATED_MEMORY: c_ulong = 0x00000100; +pub const ASC_RET_USED_DCE_STYLE: c_ulong = 0x00000200; +pub const ASC_RET_DATAGRAM: c_ulong = 0x00000400; +pub const ASC_RET_CONNECTION: c_ulong = 0x00000800; +pub const ASC_RET_CALL_LEVEL: c_ulong = 0x00002000; +pub const ASC_RET_THIRD_LEG_FAILED: c_ulong = 0x00004000; +pub const ASC_RET_EXTENDED_ERROR: c_ulong = 0x00008000; +pub const ASC_RET_STREAM: c_ulong = 0x00010000; +pub const ASC_RET_INTEGRITY: c_ulong = 0x00020000; +pub const ASC_RET_LICENSING: c_ulong = 0x00040000; +pub const ASC_RET_IDENTIFY: c_ulong = 0x00080000; +pub const ASC_RET_NULL_SESSION: c_ulong = 0x00100000; +pub const ASC_RET_ALLOW_NON_USER_LOGONS: c_ulong = 0x00200000; +pub const ASC_RET_ALLOW_CONTEXT_REPLAY: c_ulong = 0x00400000; +pub const ASC_RET_FRAGMENT_ONLY: c_ulong = 0x00800000; +pub const ASC_RET_NO_TOKEN: c_ulong = 0x01000000; +pub const ASC_RET_NO_ADDITIONAL_TOKEN: c_ulong = 0x02000000; +pub const SECPKG_CRED_ATTR_NAMES: c_ulong = 1; +pub const SECPKG_CRED_ATTR_SSI_PROVIDER: c_ulong = 2; +pub const SECPKG_CRED_ATTR_KDC_PROXY_SETTINGS: c_ulong = 3; +pub const SECPKG_CRED_ATTR_CERT: c_ulong = 4; +STRUCT!{struct SecPkgCredentials_NamesW { + sUserName: *mut SEC_WCHAR, +}} +pub type PSecPkgCredentials_NamesW = *mut SecPkgCredentials_NamesW; +STRUCT!{struct SecPkgCredentials_NamesA { + sUserName: *mut SEC_CHAR, +}} +pub type PSecPkgCredentials_NamesA = *mut SecPkgCredentials_NamesA; +STRUCT!{struct SecPkgCredentials_SSIProviderW { + sProviderName: *mut SEC_WCHAR, + ProviderInfoLength: c_ulong, + ProviderInfo: *mut c_char, +}} +pub type PSecPkgCredentials_SSIProviderW = *mut SecPkgCredentials_SSIProviderW; +STRUCT!{struct SecPkgCredentials_SSIProviderA { + sProviderName: *mut SEC_CHAR, + ProviderInfoLength: c_ulong, + ProviderInfo: *mut c_char, +}} +pub type PSecPkgCredentials_SSIProviderA = *mut SecPkgCredentials_SSIProviderA; +pub const KDC_PROXY_SETTINGS_V1: ULONG = 1; +pub const KDC_PROXY_SETTINGS_FLAGS_FORCEPROXY: ULONG = 0x1; +STRUCT!{struct SecPkgCredentials_KdcProxySettingsW { + Version: ULONG, + Flags: ULONG, + ProxyServerOffset: USHORT, + ProxyServerLength: USHORT, + ClientTlsCredOffset: USHORT, + ClientTlsCredLength: USHORT, +}} +pub type PSecPkgCredentials_KdcProxySettingsW = *mut SecPkgCredentials_KdcProxySettingsW; +STRUCT!{struct SecPkgCredentials_Cert { + EncodedCertSize: c_ulong, + EncodedCert: *mut c_uchar, +}} +pub type PSecPkgCredentials_Cert = *mut SecPkgCredentials_Cert; +pub const SECPKG_ATTR_SIZES: c_ulong = 0; +pub const SECPKG_ATTR_NAMES: c_ulong = 1; +pub const SECPKG_ATTR_LIFESPAN: c_ulong = 2; +pub const SECPKG_ATTR_DCE_INFO: c_ulong = 3; +pub const SECPKG_ATTR_STREAM_SIZES: c_ulong = 4; +pub const SECPKG_ATTR_KEY_INFO: c_ulong = 5; +pub const SECPKG_ATTR_AUTHORITY: c_ulong = 6; +pub const SECPKG_ATTR_PROTO_INFO: c_ulong = 7; +pub const SECPKG_ATTR_PASSWORD_EXPIRY: c_ulong = 8; +pub const SECPKG_ATTR_SESSION_KEY: c_ulong = 9; +pub const SECPKG_ATTR_PACKAGE_INFO: c_ulong = 10; +pub const SECPKG_ATTR_USER_FLAGS: c_ulong = 11; +pub const SECPKG_ATTR_NEGOTIATION_INFO: c_ulong = 12; +pub const SECPKG_ATTR_NATIVE_NAMES: c_ulong = 13; +pub const SECPKG_ATTR_FLAGS: c_ulong = 14; +pub const SECPKG_ATTR_USE_VALIDATED: c_ulong = 15; +pub const SECPKG_ATTR_CREDENTIAL_NAME: c_ulong = 16; +pub const SECPKG_ATTR_TARGET_INFORMATION: c_ulong = 17; +pub const SECPKG_ATTR_ACCESS_TOKEN: c_ulong = 18; +pub const SECPKG_ATTR_TARGET: c_ulong = 19; +pub const SECPKG_ATTR_AUTHENTICATION_ID: c_ulong = 20; +pub const SECPKG_ATTR_LOGOFF_TIME: c_ulong = 21; +pub const SECPKG_ATTR_NEGO_KEYS: c_ulong = 22; +pub const SECPKG_ATTR_PROMPTING_NEEDED: c_ulong = 24; +pub const SECPKG_ATTR_UNIQUE_BINDINGS: c_ulong = 25; +pub const SECPKG_ATTR_ENDPOINT_BINDINGS: c_ulong = 26; +pub const SECPKG_ATTR_CLIENT_SPECIFIED_TARGET: c_ulong = 27; +pub const SECPKG_ATTR_LAST_CLIENT_TOKEN_STATUS: c_ulong = 30; +pub const SECPKG_ATTR_NEGO_PKG_INFO: c_ulong = 31; +pub const SECPKG_ATTR_NEGO_STATUS: c_ulong = 32; +pub const SECPKG_ATTR_CONTEXT_DELETED: c_ulong = 33; +pub const SECPKG_ATTR_DTLS_MTU: c_ulong = 34; +pub const SECPKG_ATTR_DATAGRAM_SIZES: c_ulong = SECPKG_ATTR_STREAM_SIZES; +pub const SECPKG_ATTR_SUBJECT_SECURITY_ATTRIBUTES: c_ulong = 128; +pub const SECPKG_ATTR_APPLICATION_PROTOCOL: c_ulong = 35; +STRUCT!{struct SecPkgContext_SubjectAttributes { + AttributeInfo: *mut c_void, +}} +pub type PSecPkgContext_SubjectAttributes = *mut SecPkgContext_SubjectAttributes; +pub const SECPKG_ATTR_NEGO_INFO_FLAG_NO_KERBEROS: c_ulong = 0x1; +pub const SECPKG_ATTR_NEGO_INFO_FLAG_NO_NTLM: c_ulong = 0x2; +ENUM!{enum SECPKG_CRED_CLASS { + SecPkgCredClass_None = 0, + SecPkgCredClass_Ephemeral = 10, + SecPkgCredClass_PersistedGeneric = 20, + SecPkgCredClass_PersistedSpecific = 30, + SecPkgCredClass_Explicit = 40, +}} +pub type PSECPKG_CRED_CLASS = *mut SECPKG_CRED_CLASS; +STRUCT!{struct SecPkgContext_CredInfo { + CredClass: SECPKG_CRED_CLASS, + IsPromptingNeeded: c_ulong, +}} +pub type PSecPkgContext_CredInfo = *mut SecPkgContext_CredInfo; +STRUCT!{struct SecPkgContext_NegoPackageInfo { + PackageMask: c_ulong, +}} +pub type PSecPkgContext_NegoPackageInfo = *mut SecPkgContext_NegoPackageInfo; +STRUCT!{struct SecPkgContext_NegoStatus { + LastStatus: c_ulong, +}} +pub type PSecPkgContext_NegoStatus = *mut SecPkgContext_NegoStatus; +STRUCT!{struct SecPkgContext_Sizes { + cbMaxToken: c_ulong, + cbMaxSignature: c_ulong, + cbBlockSize: c_ulong, + cbSecurityTrailer: c_ulong, +}} +pub type PSecPkgContext_Sizes = *mut SecPkgContext_Sizes; +STRUCT!{struct SecPkgContext_StreamSizes { + cbHeader: c_ulong, + cbTrailer: c_ulong, + cbMaximumMessage: c_ulong, + cBuffers: c_ulong, + cbBlockSize: c_ulong, +}} +pub type PSecPkgContext_StreamSizes = *mut SecPkgContext_StreamSizes; +pub type SecPkgContext_DatagramSizes = SecPkgContext_StreamSizes; +pub type PSecPkgContext_DatagramSizes = PSecPkgContext_StreamSizes; +STRUCT!{struct SecPkgContext_NamesW { + sUserName: *mut SEC_WCHAR, +}} +pub type PSecPkgContext_NamesW = *mut SecPkgContext_NamesW; +ENUM!{enum SECPKG_ATTR_LCT_STATUS { + SecPkgAttrLastClientTokenYes, + SecPkgAttrLastClientTokenNo, + SecPkgAttrLastClientTokenMaybe, +}} +pub type PSECPKG_ATTR_LCT_STATUS = *mut SECPKG_ATTR_LCT_STATUS; +STRUCT!{struct SecPkgContext_LastClientTokenStatus { + LastClientTokenStatus: SECPKG_ATTR_LCT_STATUS, +}} +pub type PSecPkgContext_LastClientTokenStatus = *mut SecPkgContext_LastClientTokenStatus; +STRUCT!{struct SecPkgContext_NamesA { + sUserName: *mut SEC_CHAR, +}} +pub type PSecPkgContext_NamesA = *mut SecPkgContext_NamesA; +STRUCT!{struct SecPkgContext_Lifespan { + tsStart: TimeStamp, + tsExpiry: TimeStamp, +}} +pub type PSecPkgContext_Lifespan = *mut SecPkgContext_Lifespan; +STRUCT!{struct SecPkgContext_DceInfo { + AuthzSvc: c_ulong, + pPac: *mut c_void, +}} +pub type PSecPkgContext_DceInfo = *mut SecPkgContext_DceInfo; +STRUCT!{struct SecPkgContext_KeyInfoA { + sSignatureAlgorithmName: *mut SEC_CHAR, + sEncryptAlgorithmName: *mut SEC_CHAR, + KeySize: c_ulong, + SignatureAlgorithm: c_ulong, + EncryptAlgorithm: c_ulong, +}} +pub type PSecPkgContext_KeyInfoA = *mut SecPkgContext_KeyInfoA; +STRUCT!{struct SecPkgContext_KeyInfoW { + sSignatureAlgorithmName: *mut SEC_WCHAR, + sEncryptAlgorithmName: *mut SEC_WCHAR, + KeySize: c_ulong, + SignatureAlgorithm: c_ulong, + EncryptAlgorithm: c_ulong, +}} +pub type PSecPkgContext_KeyInfoW = *mut SecPkgContext_KeyInfoW; +STRUCT!{struct SecPkgContext_AuthorityA { + sAuthorityName: *mut SEC_CHAR, +}} +pub type PSecPkgContext_AuthorityA = *mut SecPkgContext_AuthorityA; +STRUCT!{struct SecPkgContext_AuthorityW { + sAuthorityName: *mut SEC_WCHAR, +}} +pub type PSecPkgContext_AuthorityW = *mut SecPkgContext_AuthorityW; +STRUCT!{struct SecPkgContext_ProtoInfoA { + sProtocolName: *mut SEC_CHAR, + majorVersion: c_ulong, + minorVersion: c_ulong, +}} +pub type PSecPkgContext_ProtoInfoA = *mut SecPkgContext_ProtoInfoA; +STRUCT!{struct SecPkgContext_ProtoInfoW { + sProtocolName: *mut SEC_WCHAR, + majorVersion: c_ulong, + minorVersion: c_ulong, +}} +pub type PSecPkgContext_ProtoInfoW = *mut SecPkgContext_ProtoInfoW; +STRUCT!{struct SecPkgContext_PasswordExpiry { + tsPasswordExpires: TimeStamp, +}} +pub type PSecPkgContext_PasswordExpiry = *mut SecPkgContext_PasswordExpiry; +STRUCT!{struct SecPkgContext_LogoffTime { + tsLogoffTime: TimeStamp, +}} +pub type PSecPkgContext_LogoffTime = *mut SecPkgContext_LogoffTime; +STRUCT!{struct SecPkgContext_SessionKey { + SessionKeyLength: c_ulong, + SessionKey: *mut c_uchar, +}} +pub type PSecPkgContext_SessionKey = *mut SecPkgContext_SessionKey; +STRUCT!{struct SecPkgContext_NegoKeys { + KeyType: c_ulong, + KeyLength: c_ushort, + KeyValue: *mut c_uchar, + VerifyKeyType: c_ulong, + VerifyKeyLength: c_ushort, + VerifyKeyValue: *mut c_uchar, +}} +pub type PSecPkgContext_NegoKeys = *mut SecPkgContext_NegoKeys; +STRUCT!{struct SecPkgContext_PackageInfoW { + PackageInfo: PSecPkgInfoW, +}} +pub type PSecPkgContext_PackageInfoW = *mut SecPkgContext_PackageInfoW; +STRUCT!{struct SecPkgContext_PackageInfoA { + PackageInfo: PSecPkgInfoA, +}} +pub type PSecPkgContext_PackageInfoA = *mut SecPkgContext_PackageInfoA; +STRUCT!{struct SecPkgContext_UserFlags { + UserFlags: c_ulong, +}} +pub type PSecPkgContext_UserFlags = *mut SecPkgContext_UserFlags; +STRUCT!{struct SecPkgContext_Flags { + Flags: c_ulong, +}} +pub type PSecPkgContext_Flags = *mut SecPkgContext_Flags; +STRUCT!{struct SecPkgContext_NegotiationInfoA { + PackageInfo: PSecPkgInfoA, + NegotiationState: c_ulong, +}} +pub type PSecPkgContext_NegotiationInfoA = *mut SecPkgContext_NegotiationInfoA; +STRUCT!{struct SecPkgContext_NegotiationInfoW { + PackageInfo: PSecPkgInfoW, + NegotiationState: c_ulong, +}} +pub type PSecPkgContext_NegotiationInfoW = *mut SecPkgContext_NegotiationInfoW; +pub const SECPKG_NEGOTIATION_COMPLETE: c_ulong = 0; +pub const SECPKG_NEGOTIATION_OPTIMISTIC: c_ulong = 1; +pub const SECPKG_NEGOTIATION_IN_PROGRESS: c_ulong = 2; +pub const SECPKG_NEGOTIATION_DIRECT: c_ulong = 3; +pub const SECPKG_NEGOTIATION_TRY_MULTICRED: c_ulong = 4; +STRUCT!{struct SecPkgContext_NativeNamesW { + sClientName: *mut SEC_WCHAR, + sServerName: *mut SEC_WCHAR, +}} +pub type PSecPkgContext_NativeNamesW = *mut SecPkgContext_NativeNamesW; +STRUCT!{struct SecPkgContext_NativeNamesA { + sClientName: *mut SEC_CHAR, + sServerName: *mut SEC_CHAR, +}} +pub type PSecPkgContext_NativeNamesA = *mut SecPkgContext_NativeNamesA; +STRUCT!{struct SecPkgContext_CredentialNameW { + CredentialType: c_ulong, + sCredentialName: *mut SEC_WCHAR, +}} +pub type PSecPkgContext_CredentialNameW = *mut SecPkgContext_CredentialNameW; +STRUCT!{struct SecPkgContext_CredentialNameA { + CredentialType: c_ulong, + sCredentialName: *mut SEC_CHAR, +}} +pub type PSecPkgContext_CredentialNameA = *mut SecPkgContext_CredentialNameA; +STRUCT!{struct SecPkgContext_AccessToken { + AccessToken: *mut c_void, +}} +pub type PSecPkgContext_AccessToken = *mut SecPkgContext_AccessToken; +STRUCT!{struct SecPkgContext_TargetInformation { + MarshalledTargetInfoLength: c_ulong, + MarshalledTargetInfo: *mut c_uchar, +}} +pub type PSecPkgContext_TargetInformation = *mut SecPkgContext_TargetInformation; +STRUCT!{struct SecPkgContext_AuthzID { + AuthzIDLength: c_ulong, + AuthzID: *mut c_char, +}} +pub type PSecPkgContext_AuthzID = *mut SecPkgContext_AuthzID; +STRUCT!{struct SecPkgContext_Target { + TargetLength: c_ulong, + Target: *mut c_char, +}} +pub type PSecPkgContext_Target = *mut SecPkgContext_Target; +STRUCT!{struct SecPkgContext_ClientSpecifiedTarget { + sTargetName: *mut SEC_WCHAR, +}} +pub type PSecPkgContext_ClientSpecifiedTarget = *mut SecPkgContext_ClientSpecifiedTarget; +STRUCT!{struct SecPkgContext_Bindings { + BindingsLength: c_ulong, + Bindings: *mut SEC_CHANNEL_BINDINGS, +}} +pub type PSecPkgContext_Bindings = *mut SecPkgContext_Bindings; +ENUM!{enum SEC_APPLICATION_PROTOCOL_NEGOTIATION_STATUS { + SecApplicationProtocolNegotiationStatus_None, + SecApplicationProtocolNegotiationStatus_Success, + SecApplicationProtocolNegotiationStatus_SelectedClientOnly, +}} +pub type PSEC_APPLICATION_PROTOCOL_NEGOTIATION_STATUS = + *mut SEC_APPLICATION_PROTOCOL_NEGOTIATION_STATUS; +pub const MAX_PROTOCOL_ID_SIZE: usize = 0xff; +STRUCT!{struct SecPkgContext_ApplicationProtocol { + ProtoNegoStatus: SEC_APPLICATION_PROTOCOL_NEGOTIATION_STATUS, + ProtoNegoExt: SEC_APPLICATION_PROTOCOL_NEGOTIATION_EXT, + ProtocolIdSize: c_uchar, + ProtocolId: [c_uchar; MAX_PROTOCOL_ID_SIZE], +}} +pub type PSecPkgContext_ApplicationProtocol = *mut SecPkgContext_ApplicationProtocol; +FN!{stdcall SEC_GET_KEY_FN( + Arg: *mut c_void, + Principal: *mut c_void, + KeyVer: c_ulong, + Key: *mut *mut c_void, + Status: *mut SECURITY_STATUS, +) -> ()} +pub const SECPKG_CONTEXT_EXPORT_RESET_NEW: c_ulong = 0x00000001; +pub const SECPKG_CONTEXT_EXPORT_DELETE_OLD: c_ulong = 0x00000002; +pub const SECPKG_CONTEXT_EXPORT_TO_KERNEL: c_ulong = 0x00000004; +extern "system" { + pub fn AcquireCredentialsHandleW( + pszPrincipal: LPWSTR, + pszPackage: LPWSTR, + fCredentialUse: c_ulong, + pvLogonId: *mut c_void, + pAuthData: *mut c_void, + pGetKeyFn: SEC_GET_KEY_FN, + pvGetKeyArgument: *mut c_void, + phCredential: PCredHandle, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; +} +FN!{stdcall ACQUIRE_CREDENTIALS_HANDLE_FN_W( + *mut SEC_WCHAR, + *mut SEC_WCHAR, + c_ulong, + *mut c_void, + *mut c_void, + SEC_GET_KEY_FN, + *mut c_void, + PCredHandle, + PTimeStamp, +) -> SECURITY_STATUS} +extern "system" { + pub fn AcquireCredentialsHandleA( + pszPrincipal: LPSTR, + pszPackage: LPSTR, + fCredentialUse: c_ulong, + pvLogonId: *mut c_void, + pAuthData: *mut c_void, + pGetKeyFn: SEC_GET_KEY_FN, + pvGetKeyArgument: *mut c_void, + phCredential: PCredHandle, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; +} +FN!{stdcall ACQUIRE_CREDENTIALS_HANDLE_FN_A( + *mut SEC_CHAR, + *mut SEC_CHAR, + c_ulong, + *mut c_void, + *mut c_void, + SEC_GET_KEY_FN, + *mut c_void, + PCredHandle, + PTimeStamp, +) -> SECURITY_STATUS} +extern "system" { + pub fn FreeCredentialsHandle( + phCredential: PCredHandle, + ) -> SECURITY_STATUS; +} +FN!{stdcall FREE_CREDENTIALS_HANDLE_FN( + PCredHandle, +) -> SECURITY_STATUS} +extern "system" { + pub fn AddCredentialsW( + hCredentials: PCredHandle, + pszPrincipal: LPWSTR, + pszPackage: LPWSTR, + fCredentialUse: c_ulong, + pAuthData: *mut c_void, + pGetKeyFn: SEC_GET_KEY_FN, + pvGetKeyArgument: *mut c_void, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; +} +FN!{stdcall ADD_CREDENTIALS_FN_W( + PCredHandle, + *mut SEC_WCHAR, + *mut SEC_WCHAR, + c_ulong, + *mut c_void, + SEC_GET_KEY_FN, + *mut c_void, + PTimeStamp, +) -> SECURITY_STATUS} +extern "system" { + pub fn AddCredentialsA( + hCredentials: PCredHandle, + pszPrincipal: LPSTR, + pszPackage: LPSTR, + fCredentialUse: c_ulong, + pAuthData: *mut c_void, + pGetKeyFn: SEC_GET_KEY_FN, + pvGetKeyArgument: *mut c_void, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; +} +FN!{stdcall ADD_CREDENTIALS_FN_A( + PCredHandle, + *mut SEC_CHAR, + *mut SEC_CHAR, + c_ulong, + *mut c_void, + SEC_GET_KEY_FN, + *mut c_void, + PTimeStamp, +) -> SECURITY_STATUS} +extern "system" { + // pub fn spiCreateAsyncContext(); + // pub fn SspiFreeAsyncContext(); + // pub fn SspiReinitAsyncContext(); + // pub fn SspiSetAsyncNotifyCallback(); + // pub fn SspiAsyncContextRequiresNotify(); + // pub fn SspiGetAsyncCallStatus(); + // pub fn SspiAcquireCredentialsHandleAsyncW(); + // pub fn SspiAcquireCredentialsHandleAsyncA(); + // pub fn SspiInitializeSecurityContextAsyncW(); + // pub fn SspiInitializeSecurityContextAsyncA(); + // pub fn SspiAcceptSecurityContextAsync(); + // pub fn SspiFreeCredentialsHandleAsync(); + // pub fn SspiDeleteSecurityContextAsync(); + pub fn ChangeAccountPasswordW( + pszPackageName: *mut SEC_WCHAR, + pszDomainName: *mut SEC_WCHAR, + pszAccountName: *mut SEC_WCHAR, + pszOldPassword: *mut SEC_WCHAR, + pszNewPassword: *mut SEC_WCHAR, + bImpersonating: BOOLEAN, + dwReserved: c_ulong, + pOutput: PSecBufferDesc, + ) -> SECURITY_STATUS; +} +FN!{stdcall CHANGE_PASSWORD_FN_W( + *mut SEC_WCHAR, + *mut SEC_WCHAR, + *mut SEC_WCHAR, + *mut SEC_WCHAR, + *mut SEC_WCHAR, + BOOLEAN, + c_ulong, + PSecBufferDesc, +) -> SECURITY_STATUS} +extern "system" { + pub fn ChangeAccountPasswordA( + pszPackageName: *mut SEC_CHAR, + pszDomainName: *mut SEC_CHAR, + pszAccountName: *mut SEC_CHAR, + pszOldPassword: *mut SEC_CHAR, + pszNewPassword: *mut SEC_CHAR, + bImpersonating: BOOLEAN, + dwReserved: c_ulong, + pOutput: PSecBufferDesc, + ) -> SECURITY_STATUS; +} +FN!{stdcall CHANGE_PASSWORD_FN_A( + *mut SEC_CHAR, + *mut SEC_CHAR, + *mut SEC_CHAR, + *mut SEC_CHAR, + *mut SEC_CHAR, + BOOLEAN, + c_ulong, + PSecBufferDesc, +) -> SECURITY_STATUS} +extern "system" { + pub fn InitializeSecurityContextW( + phCredential: PCredHandle, + phContext: PCtxtHandle, + pszTargetName: *mut SEC_WCHAR, + fContextReq: c_ulong, + Reserved1: c_ulong, + TargetDataRep: c_ulong, + pInput: PSecBufferDesc, + Reserved2: c_ulong, + phNewContext: PCtxtHandle, + pOutput: PSecBufferDesc, + pfContextAttr: *mut c_ulong, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; +} +// INITIALIZE_SECURITY_CONTEXT_FN_W +extern "system" { + pub fn InitializeSecurityContextA( + phCredential: PCredHandle, + phContext: PCtxtHandle, + pszTargetName: *mut SEC_CHAR, + fContextReq: c_ulong, + Reserved1: c_ulong, + TargetDataRep: c_ulong, + pInput: PSecBufferDesc, + Reserved2: c_ulong, + phNewContext: PCtxtHandle, + pOutput: PSecBufferDesc, + pfContextAttr: *mut c_ulong, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; + pub fn AcceptSecurityContext( + phCredential: PCredHandle, + phContext: PCtxtHandle, + pInput: PSecBufferDesc, + fContextReq: c_ulong, + TargetDataRep: c_ulong, + phNewContext: PCtxtHandle, + pOutput: PSecBufferDesc, + pfContextAttr: *mut c_ulong, + ptsExpiry: PTimeStamp, + ) -> SECURITY_STATUS; + pub fn CompleteAuthToken( + phContext: PCtxtHandle, + pToken: PSecBufferDesc, + ) -> SECURITY_STATUS; + pub fn ImpersonateSecurityContext( + phContext: PCtxtHandle, + ) -> SECURITY_STATUS; + pub fn RevertSecurityContext( + phContext: PCtxtHandle, + ) -> SECURITY_STATUS; + pub fn QuerySecurityContextToken( + phContext: PCtxtHandle, + Token: *mut *mut c_void, + ) -> SECURITY_STATUS; + pub fn DeleteSecurityContext( + phContext: PCtxtHandle, + ) -> SECURITY_STATUS; + pub fn ApplyControlToken( + phContext: PCtxtHandle, + pInput: PSecBufferDesc, + ) -> SECURITY_STATUS; + pub fn QueryContextAttributesW( + phContext: PCtxtHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + ) -> SECURITY_STATUS; + // pub fn QueryContextAttributesExW(); + pub fn QueryContextAttributesA( + phContext: PCtxtHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + ) -> SECURITY_STATUS; + // pub fn QueryContextAttributesExA(); + pub fn SetContextAttributesW( + phContext: PCtxtHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + cbBuffer: c_ulong, + ) -> SECURITY_STATUS; + pub fn SetContextAttributesA( + phContext: PCtxtHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + cbBuffer: c_ulong, + ) -> SECURITY_STATUS; + pub fn QueryCredentialsAttributesW( + phCredential: PCredHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + ) -> SECURITY_STATUS; + // pub fn QueryCredentialsAttributesExW(); + pub fn QueryCredentialsAttributesA( + phCredential: PCredHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + ) -> SECURITY_STATUS; + // pub fn QueryCredentialsAttributesExA(); + pub fn SetCredentialsAttributesW( + phCredential: PCredHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + cbBuffer: c_ulong, + ) -> SECURITY_STATUS; + pub fn SetCredentialsAttributesA( + phCredential: PCredHandle, + ulAttribute: c_ulong, + pBuffer: *mut c_void, + cbBuffer: c_ulong, + ) -> SECURITY_STATUS; + pub fn FreeContextBuffer( + pvContextBuffer: PVOID, + ) -> SECURITY_STATUS; + pub fn MakeSignature( + phContext: PCtxtHandle, + fQOP: c_ulong, + pMessage: PSecBufferDesc, + MessageSeqNo: c_ulong, + ) -> SECURITY_STATUS; + pub fn VerifySignature( + phContext: PCtxtHandle, + pMessage: PSecBufferDesc, + MessageSeqNo: c_ulong, + pfQOP: *mut c_ulong, + ) -> SECURITY_STATUS; + pub fn EncryptMessage( + phContext: PCtxtHandle, + fQOP: c_ulong, + pMessage: PSecBufferDesc, + MessageSeqNo: c_ulong, + ) -> SECURITY_STATUS; + pub fn DecryptMessage( + phContext: PCtxtHandle, + pMessage: PSecBufferDesc, + MessageSeqNo: c_ulong, + pfQOP: *mut c_ulong, + ) -> SECURITY_STATUS; + pub fn EnumerateSecurityPackagesW( + pcPackages: *mut c_ulong, + ppPackageInfo: *mut PSecPkgInfoW, + ) -> SECURITY_STATUS; + pub fn EnumerateSecurityPackagesA( + pcPackages: *mut c_ulong, + ppPackageInfo: *mut PSecPkgInfoA, + ) -> SECURITY_STATUS; + pub fn QuerySecurityPackageInfoW( + pszPackageName: LPWSTR, + ppPackageInfo: *mut PSecPkgInfoW, + ) -> SECURITY_STATUS; + pub fn QuerySecurityPackageInfoA( + pszPackageName: LPSTR, + ppPackageInfo: *mut PSecPkgInfoA, + ) -> SECURITY_STATUS; +} +ENUM!{enum SecDelegationType { + SecFull, + SecService, + SecTree, + SecDirectory, + SecObject, +}} +pub type PSecDelegationType = *mut SecDelegationType; +extern "system" { + // pub fn DelegateSecurityContext(); + pub fn ExportSecurityContext( + phContext: PCtxtHandle, + fFlags: ULONG, + pPackedContext: PSecBuffer, + pToken: *mut *mut c_void, + ) -> SECURITY_STATUS; + pub fn ImportSecurityContextW( + pszPackage: LPWSTR, + pPackedContext: PSecBuffer, + Token: *mut c_void, + phContext: PCtxtHandle, + ) -> SECURITY_STATUS; + pub fn ImportSecurityContextA( + pszPackage: LPSTR, + pPackedContext: PSecBuffer, + Token: *mut c_void, + phContext: PCtxtHandle, + ) -> SECURITY_STATUS; +// pub fn SecMakeSPN(); +// pub fn SecMakeSPNEx(); +// pub fn SecMakeSPNEx2(); +// pub fn SecLookupAccountSid(); +// pub fn SecLookupAccountName(); +// pub fn SecLookupWellKnownSid(); +} +extern "system" { + // pub fn InitSecurityInterfaceA(); + // pub fn InitSecurityInterfaceW(); + // pub fn SaslEnumerateProfilesA(); + // pub fn SaslEnumerateProfilesW(); + // pub fn SaslGetProfilePackageA(); + // pub fn SaslGetProfilePackageW(); + // pub fn SaslIdentifyPackageA(); + // pub fn SaslIdentifyPackageW(); + // pub fn SaslInitializeSecurityContextW(); + // pub fn SaslInitializeSecurityContextA(); + // pub fn SaslAcceptSecurityContext(); + // pub fn SaslSetContextOption(); + // pub fn SaslGetContextOption(); +} +pub type PSEC_WINNT_AUTH_IDENTITY_OPAQUE = PVOID; +extern "system" { + pub fn SspiPromptForCredentialsW( + pszTargetName: PCWSTR, + pUiInfo: PCREDUI_INFOW, + dwAuthError: c_ulong, + pszPackage: PCWSTR, + pInputAuthIdentity: PSEC_WINNT_AUTH_IDENTITY_OPAQUE, + ppAuthIdentity: *mut PSEC_WINNT_AUTH_IDENTITY_OPAQUE, + pfSave: *mut c_int, + dwFlags: c_ulong, + ) -> c_ulong; + pub fn SspiPromptForCredentialsA( + pszTargetName: PCSTR, + pUiInfo: PCREDUI_INFOA, + dwAuthError: c_ulong, + pszPackage: PCSTR, + pInputAuthIdentity: PSEC_WINNT_AUTH_IDENTITY_OPAQUE, + ppAuthIdentity: *mut PSEC_WINNT_AUTH_IDENTITY_OPAQUE, + pfSave: *mut c_int, + dwFlags: c_ulong, + ) -> c_ulong; +} +STRUCT!{struct SEC_WINNT_AUTH_BYTE_VECTOR { + ByteArrayOffset: c_ulong, + ByteArrayLength: c_ushort, +}} +pub type PSEC_WINNT_AUTH_BYTE_VECTOR = *mut SEC_WINNT_AUTH_BYTE_VECTOR; +STRUCT!{struct SEC_WINNT_AUTH_DATA { + CredType: GUID, + CredData: SEC_WINNT_AUTH_BYTE_VECTOR, +}} +pub type PSEC_WINNT_AUTH_DATA = *mut SEC_WINNT_AUTH_DATA; +STRUCT!{struct SEC_WINNT_AUTH_PACKED_CREDENTIALS { + cbHeaderLength: c_ushort, + cbStructureLength: c_ushort, + AuthData: SEC_WINNT_AUTH_DATA, +}} +pub type PSEC_WINNT_AUTH_PACKED_CREDENTIALS = *mut SEC_WINNT_AUTH_PACKED_CREDENTIALS; +DEFINE_GUID!{SEC_WINNT_AUTH_DATA_TYPE_PASSWORD, + 0x28bfc32f, 0x10f6, 0x4738, 0x98, 0xd1, 0x1a, 0xc0, 0x61, 0xdf, 0x71, 0x6a} +DEFINE_GUID!{SEC_WINNT_AUTH_DATA_TYPE_CERT, + 0x235f69ad, 0x73fb, 0x4dbc, 0x82, 0x3, 0x6, 0x29, 0xe7, 0x39, 0x33, 0x9b} +STRUCT!{struct SEC_WINNT_AUTH_DATA_PASSWORD { + UnicodePassword: SEC_WINNT_AUTH_BYTE_VECTOR, +}} +pub type PSEC_WINNT_AUTH_DATA_PASSWORD = *mut SEC_WINNT_AUTH_DATA_PASSWORD; +DEFINE_GUID!{SEC_WINNT_AUTH_DATA_TYPE_CSP_DATA, + 0x68fd9879, 0x79c, 0x4dfe, 0x82, 0x81, 0x57, 0x8a, 0xad, 0xc1, 0xc1, 0x0} +// GUID SEC_WINNT_AUTH_DATA_TYPE_SMARTCARD_CONTEXTS +STRUCT!{struct SEC_WINNT_AUTH_CERTIFICATE_DATA { + cbHeaderLength: c_ushort, + cbStructureLength: c_ushort, + Certificate: SEC_WINNT_AUTH_BYTE_VECTOR, +}} +pub type PSEC_WINNT_AUTH_CERTIFICATE_DATA = *mut SEC_WINNT_AUTH_CERTIFICATE_DATA; +STRUCT!{struct SEC_WINNT_CREDUI_CONTEXT_VECTOR { + CredUIContextArrayOffset: ULONG, + CredUIContextCount: USHORT, +}} +pub type PSEC_WINNT_CREDUI_CONTEXT_VECTOR = *mut SEC_WINNT_CREDUI_CONTEXT_VECTOR; +STRUCT!{struct SEC_WINNT_AUTH_SHORT_VECTOR { + ShortArrayOffset: ULONG, + ShortArrayCount: USHORT, +}} +pub type PSEC_WINNT_AUTH_SHORT_VECTOR = *mut SEC_WINNT_AUTH_SHORT_VECTOR; +extern "system" { + pub fn SspiGetCredUIContext( + ContextHandle: HANDLE, + CredType: *mut GUID, + LogonId: *mut LUID, + CredUIContexts: *mut PSEC_WINNT_CREDUI_CONTEXT_VECTOR, + TokenHandle: *mut HANDLE, + ) -> SECURITY_STATUS; + pub fn SspiUpdateCredentials( + ContextHandle: HANDLE, + CredType: *mut GUID, + FlatCredUIContextLength: ULONG, + FlatCredUIContext: PUCHAR, + ) -> SECURITY_STATUS; +} +STRUCT!{struct CREDUIWIN_MARSHALED_CONTEXT { + StructureType: GUID, + cbHeaderLength: USHORT, + LogonId: LUID, + MarshaledDataType: GUID, + MarshaledDataOffset: ULONG, + MarshaledDataLength: USHORT, +}} +pub type PCREDUIWIN_MARSHALED_CONTEXT = *mut CREDUIWIN_MARSHALED_CONTEXT; +STRUCT!{struct SEC_WINNT_CREDUI_CONTEXT { + cbHeaderLength: USHORT, + CredUIContextHandle: HANDLE, + UIInfo: PCREDUI_INFOW, + dwAuthError: ULONG, + pInputAuthIdentity: PSEC_WINNT_AUTH_IDENTITY_OPAQUE, + TargetName: PUNICODE_STRING, +}} +pub type PSEC_WINNT_CREDUI_CONTEXT = *mut SEC_WINNT_CREDUI_CONTEXT; +// GUID CREDUIWIN_STRUCTURE_TYPE_SSPIPFC +// GUID SSPIPFC_STRUCTURE_TYPE_CREDUI_CONTEXT +extern "system" { + pub fn SspiUnmarshalCredUIContext( + MarshaledCredUIContext: PUCHAR, + MarshaledCredUIContextLength: ULONG, + CredUIContext: *mut PSEC_WINNT_CREDUI_CONTEXT, + ) -> SECURITY_STATUS; + // pub fn SspiPrepareForCredRead(); + // pub fn SspiPrepareForCredWrite(); + // pub fn SspiEncryptAuthIdentity(); + // pub fn SspiEncryptAuthIdentityEx(); + // pub fn SspiDecryptAuthIdentity(); + // pub fn SspiDecryptAuthIdentityEx(); + // pub fn SspiIsAuthIdentityEncrypted(); + // pub fn SspiEncodeAuthIdentityAsStrings(); + // pub fn SspiValidateAuthIdentity(); + // pub fn SspiCopyAuthIdentity(); + // pub fn SspiFreeAuthIdentity(); + // pub fn SspiZeroAuthIdentity(); + // pub fn SspiLocalFree(); + // pub fn SspiEncodeStringsAsAuthIdentity(); + // pub fn SspiCompareAuthIdentities(); + // pub fn SspiMarshalAuthIdentity(); + // pub fn SspiUnmarshalAuthIdentity(); + pub fn SspiIsPromptingNeeded( + ErrorOrNtStatus: c_ulong, + ) -> BOOLEAN; + // pub fn SspiGetTargetHostName(); + // pub fn SspiExcludePackage(); + // pub fn AddSecurityPackageA(); + // pub fn AddSecurityPackageW(); + // pub fn DeleteSecurityPackageA(); + // pub fn DeleteSecurityPackageW(); +} diff --git a/winapi/src/shared/stralign.rs b/winapi/src/shared/stralign.rs new file mode 100644 index 000000000..2e2a703fe --- /dev/null +++ b/winapi/src/shared/stralign.rs @@ -0,0 +1,40 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_int; +use um::winnt::{LPCUWSTR, PCUWSTR, PUWSTR, WCHAR}; +use vc::vcruntime::size_t; +extern "system" { + pub fn uaw_lstrcmpW( + String1: PCUWSTR, + String2: PCUWSTR, + ) -> c_int; + pub fn uaw_lstrcmpiW( + String1: PCUWSTR, + String2: PCUWSTR, + ) -> c_int; + pub fn uaw_lstrlenW( + String: LPCUWSTR, + ) -> c_int; + pub fn uaw_wcschr( + String: PCUWSTR, + Character: WCHAR, + ) -> PUWSTR; + pub fn uaw_wcscpy( + Destination: PUWSTR, + Source: PCUWSTR, + ) -> PUWSTR; + pub fn uaw_wcsicmp( + String1: PCUWSTR, + String2: PCUWSTR, + ) -> c_int; + pub fn uaw_wcslen( + String: PCUWSTR, + ) -> size_t; + pub fn uaw_wcsrchr( + String: PCUWSTR, + Character: WCHAR, + ) -> PUWSTR; +} diff --git a/winapi/src/shared/transportsettingcommon.rs b/winapi/src/shared/transportsettingcommon.rs new file mode 100644 index 000000000..2f5f6fb6c --- /dev/null +++ b/winapi/src/shared/transportsettingcommon.rs @@ -0,0 +1,10 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +STRUCT!{struct TRANSPORT_SETTING_ID { + Guid: GUID, +}} +pub type PTRANSPORT_SETTING_ID = *mut TRANSPORT_SETTING_ID; diff --git a/winapi/src/shared/tvout.rs b/winapi/src/shared/tvout.rs new file mode 100644 index 000000000..f691bdf32 --- /dev/null +++ b/winapi/src/shared/tvout.rs @@ -0,0 +1,72 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{UCHAR, ULONG}; +STRUCT!{struct VIDEOPARAMETERS { + Guid: GUID, + dwOffset: ULONG, + dwCommand: ULONG, + dwFlags: ULONG, + dwMode: ULONG, + dwTVStandard: ULONG, + dwAvailableModes: ULONG, + dwAvailableTVStandard: ULONG, + dwFlickerFilter: ULONG, + dwOverScanX: ULONG, + dwOverScanY: ULONG, + dwMaxUnscaledX: ULONG, + dwMaxUnscaledY: ULONG, + dwPositionX: ULONG, + dwPositionY: ULONG, + dwBrightness: ULONG, + dwContrast: ULONG, + dwCPType: ULONG, + dwCPCommand: ULONG, + dwCPStandard: ULONG, + dwCPKey: ULONG, + bCP_APSTriggerBits: ULONG, + bOEMCopyProtection: [UCHAR; 256], +}} +pub type PVIDEOPARAMETERS = *mut VIDEOPARAMETERS; +pub type LPVIDEOPARAMETERS = *mut VIDEOPARAMETERS; +pub const VP_COMMAND_GET: ULONG = 0x0001; +pub const VP_COMMAND_SET: ULONG = 0x0002; +pub const VP_FLAGS_TV_MODE: ULONG = 0x0001; +pub const VP_FLAGS_TV_STANDARD: ULONG = 0x0002; +pub const VP_FLAGS_FLICKER: ULONG = 0x0004; +pub const VP_FLAGS_OVERSCAN: ULONG = 0x0008; +pub const VP_FLAGS_MAX_UNSCALED: ULONG = 0x0010; +pub const VP_FLAGS_POSITION: ULONG = 0x0020; +pub const VP_FLAGS_BRIGHTNESS: ULONG = 0x0040; +pub const VP_FLAGS_CONTRAST: ULONG = 0x0080; +pub const VP_FLAGS_COPYPROTECT: ULONG = 0x0100; +pub const VP_MODE_WIN_GRAPHICS: ULONG = 0x0001; +pub const VP_MODE_TV_PLAYBACK: ULONG = 0x0002; +pub const VP_TV_STANDARD_NTSC_M: ULONG = 0x0001; +pub const VP_TV_STANDARD_NTSC_M_J: ULONG = 0x0002; +pub const VP_TV_STANDARD_PAL_B: ULONG = 0x0004; +pub const VP_TV_STANDARD_PAL_D: ULONG = 0x0008; +pub const VP_TV_STANDARD_PAL_H: ULONG = 0x0010; +pub const VP_TV_STANDARD_PAL_I: ULONG = 0x0020; +pub const VP_TV_STANDARD_PAL_M: ULONG = 0x0040; +pub const VP_TV_STANDARD_PAL_N: ULONG = 0x0080; +pub const VP_TV_STANDARD_SECAM_B: ULONG = 0x0100; +pub const VP_TV_STANDARD_SECAM_D: ULONG = 0x0200; +pub const VP_TV_STANDARD_SECAM_G: ULONG = 0x0400; +pub const VP_TV_STANDARD_SECAM_H: ULONG = 0x0800; +pub const VP_TV_STANDARD_SECAM_K: ULONG = 0x1000; +pub const VP_TV_STANDARD_SECAM_K1: ULONG = 0x2000; +pub const VP_TV_STANDARD_SECAM_L: ULONG = 0x4000; +pub const VP_TV_STANDARD_WIN_VGA: ULONG = 0x8000; +pub const VP_TV_STANDARD_NTSC_433: ULONG = 0x00010000; +pub const VP_TV_STANDARD_PAL_G: ULONG = 0x00020000; +pub const VP_TV_STANDARD_PAL_60: ULONG = 0x00040000; +pub const VP_TV_STANDARD_SECAM_L1: ULONG = 0x00080000; +pub const VP_CP_TYPE_APS_TRIGGER: ULONG = 0x0001; +pub const VP_CP_TYPE_MACROVISION: ULONG = 0x0002; +pub const VP_CP_CMD_ACTIVATE: ULONG = 0x0001; +pub const VP_CP_CMD_DEACTIVATE: ULONG = 0x0002; +pub const VP_CP_CMD_CHANGE: ULONG = 0x0004; diff --git a/winapi/src/shared/usb.rs b/winapi/src/shared/usb.rs new file mode 100644 index 000000000..7caae833c --- /dev/null +++ b/winapi/src/shared/usb.rs @@ -0,0 +1,523 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! USB Definitions. +use shared::minwindef::{UCHAR, ULONG, USHORT}; +use shared::usbspec::{ + PUSB_CONFIGURATION_DESCRIPTOR, USB_DEVICE_DESCRIPTOR, USB_ENDPOINT_DIRECTION_MASK, +}; +use um::winnt::{LONG, PVOID, WCHAR}; +pub type PRIP = PVOID; +pub type PMDL = PVOID; +pub const USBDI_VERSION: ULONG = 0x00000600; +pub const USB_PORTATTR_NO_CONNECTOR: ULONG = 0x00000001; +pub const USB_PORTATTR_SHARED_USB2: ULONG = 0x00000002; +pub const USB_PORTATTR_MINI_CONNECTOR: ULONG = 0x00000004; +pub const USB_PORTATTR_OEM_CONNECTOR: ULONG = 0x00000008; +pub const USB_PORTATTR_OWNED_BY_CC: ULONG = 0x01000000; +pub const USB_PORTATTR_NO_OVERCURRENT_UI: ULONG = 0x02000000; +ENUM!{enum USB_CONTROLLER_FLAVOR { + USB_HcGeneric = 0, + OHCI_Generic = 100, + OHCI_Hydra, + OHCI_NEC, + UHCI_Generic = 200, + UHCI_Piix4 = 201, + UHCI_Piix3 = 202, + UHCI_Ich2 = 203, + UHCI_Reserved204 = 204, + UHCI_Ich1 = 205, + UHCI_Ich3m = 206, + UHCI_Ich4 = 207, + UHCI_Ich5 = 208, + UHCI_Ich6 = 209, + UHCI_Intel = 249, + UHCI_VIA = 250, + UHCI_VIA_x01 = 251, + UHCI_VIA_x02 = 252, + UHCI_VIA_x03 = 253, + UHCI_VIA_x04 = 254, + UHCI_VIA_x0E_FIFO = 264, + EHCI_Generic = 1000, + EHCI_NEC = 2000, + EHCI_Lucent = 3000, + EHCI_NVIDIA_Tegra2 = 4000, + EHCI_NVIDIA_Tegra3 = 4001, + EHCI_Intel_Medfield = 5001, +}} +pub const USB_DEFAULT_DEVICE_ADDRESS: UCHAR = 0; +pub const USB_DEFAULT_ENDPOINT_ADDRESS: UCHAR = 0; +pub const USB_DEFAULT_MAX_PACKET: USHORT = 64; +pub const URB_FUNCTION_SELECT_CONFIGURATION: USHORT = 0x0000; +pub const URB_FUNCTION_SELECT_INTERFACE: USHORT = 0x0001; +pub const URB_FUNCTION_ABORT_PIPE: USHORT = 0x0002; +pub const URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: USHORT = 0x0003; +pub const URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL: USHORT = 0x0004; +pub const URB_FUNCTION_GET_FRAME_LENGTH: USHORT = 0x0005; +pub const URB_FUNCTION_SET_FRAME_LENGTH: USHORT = 0x0006; +pub const URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: USHORT = 0x0007; +pub const URB_FUNCTION_CONTROL_TRANSFER: USHORT = 0x0008; +pub const URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: USHORT = 0x0009; +pub const URB_FUNCTION_ISOCH_TRANSFER: USHORT = 0x000A; +pub const URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: USHORT = 0x000B; +pub const URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: USHORT = 0x000C; +pub const URB_FUNCTION_SET_FEATURE_TO_DEVICE: USHORT = 0x000D; +pub const URB_FUNCTION_SET_FEATURE_TO_INTERFACE: USHORT = 0x000E; +pub const URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: USHORT = 0x000F; +pub const URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: USHORT = 0x0010; +pub const URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: USHORT = 0x0011; +pub const URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: USHORT = 0x0012; +pub const URB_FUNCTION_GET_STATUS_FROM_DEVICE: USHORT = 0x0013; +pub const URB_FUNCTION_GET_STATUS_FROM_INTERFACE: USHORT = 0x0014; +pub const URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: USHORT = 0x0015; +pub const URB_FUNCTION_RESERVED_0X0016: USHORT = 0x0016; +pub const URB_FUNCTION_VENDOR_DEVICE: USHORT = 0x0017; +pub const URB_FUNCTION_VENDOR_INTERFACE: USHORT = 0x0018; +pub const URB_FUNCTION_VENDOR_ENDPOINT: USHORT = 0x0019; +pub const URB_FUNCTION_CLASS_DEVICE: USHORT = 0x001A; +pub const URB_FUNCTION_CLASS_INTERFACE: USHORT = 0x001B; +pub const URB_FUNCTION_CLASS_ENDPOINT: USHORT = 0x001C; +pub const URB_FUNCTION_RESERVE_0X001D: USHORT = 0x001D; +pub const URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: USHORT = 0x001E; +pub const URB_FUNCTION_CLASS_OTHER: USHORT = 0x001F; +pub const URB_FUNCTION_VENDOR_OTHER: USHORT = 0x0020; +pub const URB_FUNCTION_GET_STATUS_FROM_OTHER: USHORT = 0x0021; +pub const URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: USHORT = 0x0022; +pub const URB_FUNCTION_SET_FEATURE_TO_OTHER: USHORT = 0x0023; +pub const URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: USHORT = 0x0024; +pub const URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: USHORT = 0x0025; +pub const URB_FUNCTION_GET_CONFIGURATION: USHORT = 0x0026; +pub const URB_FUNCTION_GET_INTERFACE: USHORT = 0x0027; +pub const URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: USHORT = 0x0028; +pub const URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: USHORT = 0x0029; +pub const URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: USHORT = 0x002A; +pub const URB_FUNCTION_SYNC_RESET_PIPE: USHORT = 0x0030; +pub const URB_FUNCTION_SYNC_CLEAR_STALL: USHORT = 0x0031; +pub const URB_FUNCTION_CONTROL_TRANSFER_EX: USHORT = 0x0032; +pub const URB_FUNCTION_RESERVE_0X0033: USHORT = 0x0033; +pub const URB_FUNCTION_RESERVE_0X0034: USHORT = 0x0034; +pub const URB_FUNCTION_OPEN_STATIC_STREAMS: USHORT = 0x0035; +pub const URB_FUNCTION_CLOSE_STATIC_STREAMS: USHORT = 0x0036; +pub const URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER_USING_CHAINED_MDL: USHORT = 0x0037; +pub const URB_FUNCTION_ISOCH_TRANSFER_USING_CHAINED_MDL: USHORT = 0x0038; +pub const URB_FUNCTION_RESERVE_0X002B: USHORT = 0x002B; +pub const URB_FUNCTION_RESERVE_0X002C: USHORT = 0x002C; +pub const URB_FUNCTION_RESERVE_0X002D: USHORT = 0x002D; +pub const URB_FUNCTION_RESERVE_0X002E: USHORT = 0x002E; +pub const URB_FUNCTION_RESERVE_0X002F: USHORT = 0x002F; +pub const URB_FUNCTION_RESET_PIPE: USHORT = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL; +pub const USBD_SHORT_TRANSFER_OK: ULONG = 0x00000002; +pub const USBD_START_ISO_TRANSFER_ASAP: ULONG = 0x00000004; +pub const USBD_DEFAULT_PIPE_TRANSFER: ULONG = 0x00000008; +pub const USBD_TRANSFER_DIRECTION_OUT: ULONG = 0; +pub const USBD_TRANSFER_DIRECTION_IN: ULONG = 1; +pub const USBD_TRANSFER_DIRECTION: ULONG = USBD_TRANSFER_DIRECTION_IN; +#[inline] +pub fn USBD_TRANSFER_DIRECTION_FLAG(flags: ULONG) -> ULONG { + flags & USBD_TRANSFER_DIRECTION +} +pub const VALID_TRANSFER_FLAGS_MASK: ULONG = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION + | USBD_START_ISO_TRANSFER_ASAP | USBD_DEFAULT_PIPE_TRANSFER; +pub const USBD_ISO_START_FRAME_RANGE: ULONG = 1024; +pub type USBD_STATUS = LONG; +#[inline] +pub fn USBD_SUCCESS(Status: USBD_STATUS) -> bool { + Status >= 0 +} +#[inline] +pub fn USBD_PENDING(Status: ULONG) -> bool { + (Status >> 30) == 1 +} +pub const USBD_STATUS_SUCCESS: USBD_STATUS = 0x00000000; +pub const USBD_STATUS_PORT_OPERATION_PENDING: USBD_STATUS = 0x00000001; +pub const USBD_STATUS_PENDING: USBD_STATUS = 0x40000000; +pub const USBD_STATUS_CRC: USBD_STATUS = 0xC0000001; +pub const USBD_STATUS_BTSTUFF: USBD_STATUS = 0xC0000002; +pub const USBD_STATUS_DATA_TOGGLE_MISMATCH: USBD_STATUS = 0xC0000003; +pub const USBD_STATUS_STALL_PID: USBD_STATUS = 0xC0000004; +pub const USBD_STATUS_DEV_NOT_RESPONDING: USBD_STATUS = 0xC0000005; +pub const USBD_STATUS_PID_CHECK_FAILURE: USBD_STATUS = 0xC0000006; +pub const USBD_STATUS_UNEXPECTED_PID: USBD_STATUS = 0xC0000007; +pub const USBD_STATUS_DATA_OVERRUN: USBD_STATUS = 0xC0000008; +pub const USBD_STATUS_DATA_UNDERRUN: USBD_STATUS = 0xC0000009; +pub const USBD_STATUS_RESERVED1: USBD_STATUS = 0xC000000A; +pub const USBD_STATUS_RESERVED2: USBD_STATUS = 0xC000000B; +pub const USBD_STATUS_BUFFER_OVERRUN: USBD_STATUS = 0xC000000C; +pub const USBD_STATUS_BUFFER_UNDERRUN: USBD_STATUS = 0xC000000D; +pub const USBD_STATUS_NOT_ACCESSED: USBD_STATUS = 0xC000000F; +pub const USBD_STATUS_FIFO: USBD_STATUS = 0xC0000010; +pub const USBD_STATUS_XACT_ERROR: USBD_STATUS = 0xC0000011; +pub const USBD_STATUS_BABBLE_DETECTED: USBD_STATUS = 0xC0000012; +pub const USBD_STATUS_DATA_BUFFER_ERROR: USBD_STATUS = 0xC0000013; +pub const USBD_STATUS_NO_PING_RESPONSE: USBD_STATUS = 0xC0000014; +pub const USBD_STATUS_INVALID_STREAM_TYPE: USBD_STATUS = 0xC0000015; +pub const USBD_STATUS_INVALID_STREAM_ID: USBD_STATUS = 0xC0000016; +pub const USBD_STATUS_ENDPOINT_HALTED: USBD_STATUS = 0xC0000030; +pub const USBD_STATUS_INVALID_URB_FUNCTION: USBD_STATUS = 0x80000200; +pub const USBD_STATUS_INVALID_PARAMETER: USBD_STATUS = 0x80000300; +pub const USBD_STATUS_ERROR_BUSY: USBD_STATUS = 0x80000400; +pub const USBD_STATUS_INVALID_PIPE_HANDLE: USBD_STATUS = 0x80000600; +pub const USBD_STATUS_NO_BANDWIDTH: USBD_STATUS = 0x80000700; +pub const USBD_STATUS_INTERNAL_HC_ERROR: USBD_STATUS = 0x80000800; +pub const USBD_STATUS_ERROR_SHORT_TRANSFER: USBD_STATUS = 0x80000900; +pub const USBD_STATUS_BAD_START_FRAME: USBD_STATUS = 0xC0000A00; +pub const USBD_STATUS_ISOCH_REQUEST_FAILED: USBD_STATUS = 0xC0000B00; +pub const USBD_STATUS_FRAME_CONTROL_OWNED: USBD_STATUS = 0xC0000C00; +pub const USBD_STATUS_FRAME_CONTROL_NOT_OWNED: USBD_STATUS = 0xC0000D00; +pub const USBD_STATUS_NOT_SUPPORTED: USBD_STATUS = 0xC0000E00; +pub const USBD_STATUS_INAVLID_CONFIGURATION_DESCRIPTOR: USBD_STATUS = 0xC0000F00; +pub const USBD_STATUS_INVALID_CONFIGURATION_DESCRIPTOR: USBD_STATUS = 0xC0000F00; +pub const USBD_STATUS_INSUFFICIENT_RESOURCES: USBD_STATUS = 0xC0001000; +pub const USBD_STATUS_SET_CONFIG_FAILED: USBD_STATUS = 0xC0002000; +pub const USBD_STATUS_BUFFER_TOO_SMALL: USBD_STATUS = 0xC0003000; +pub const USBD_STATUS_INTERFACE_NOT_FOUND: USBD_STATUS = 0xC0004000; +pub const USBD_STATUS_INAVLID_PIPE_FLAGS: USBD_STATUS = 0xC0005000; +pub const USBD_STATUS_TIMEOUT: USBD_STATUS = 0xC0006000; +pub const USBD_STATUS_DEVICE_GONE: USBD_STATUS = 0xC0007000; +pub const USBD_STATUS_STATUS_NOT_MAPPED: USBD_STATUS = 0xC0008000; +pub const USBD_STATUS_HUB_INTERNAL_ERROR: USBD_STATUS = 0xC0009000; +pub const USBD_STATUS_CANCELED: USBD_STATUS = 0xC0010000; +pub const USBD_STATUS_ISO_NOT_ACCESSED_BY_HW: USBD_STATUS = 0xC0020000; +pub const USBD_STATUS_ISO_TD_ERROR: USBD_STATUS = 0xC0030000; +pub const USBD_STATUS_ISO_NA_LATE_USBPORT: USBD_STATUS = 0xC0040000; +pub const USBD_STATUS_ISO_NOT_ACCESSED_LATE: USBD_STATUS = 0xC0050000; +pub const USBD_STATUS_BAD_DESCRIPTOR: USBD_STATUS = 0xC0100000; +pub const USBD_STATUS_BAD_DESCRIPTOR_BLEN: USBD_STATUS = 0xC0100001; +pub const USBD_STATUS_BAD_DESCRIPTOR_TYPE: USBD_STATUS = 0xC0100002; +pub const USBD_STATUS_BAD_INTERFACE_DESCRIPTOR: USBD_STATUS = 0xC0100003; +pub const USBD_STATUS_BAD_ENDPOINT_DESCRIPTOR: USBD_STATUS = 0xC0100004; +pub const USBD_STATUS_BAD_INTERFACE_ASSOC_DESCRIPTOR: USBD_STATUS = 0xC0100005; +pub const USBD_STATUS_BAD_CONFIG_DESC_LENGTH: USBD_STATUS = 0xC0100006; +pub const USBD_STATUS_BAD_NUMBER_OF_INTERFACES: USBD_STATUS = 0xC0100007; +pub const USBD_STATUS_BAD_NUMBER_OF_ENDPOINTS: USBD_STATUS = 0xC0100008; +pub const USBD_STATUS_BAD_ENDPOINT_ADDRESS: USBD_STATUS = 0xC0100009; +pub type USBD_PIPE_HANDLE = PVOID; +pub type USBD_CONFIGURATION_HANDLE = PVOID; +pub type USBD_INTERFACE_HANDLE = PVOID; +pub const USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE: ULONG = 0xFFFFFFFF; +STRUCT!{struct USBD_VERSION_INFORMATION { + USBDI_Version: ULONG, + Supported_USB_Version: ULONG, +}} +pub type PUSBD_VERSION_INFORMATION = *mut USBD_VERSION_INFORMATION; +ENUM!{enum USBD_PIPE_TYPE { + UsbdPipeTypeControl, + UsbdPipeTypeIsochronous, + UsbdPipeTypeBulk, + UsbdPipeTypeInterrupt, +}} +#[inline] +pub fn USBD_PIPE_DIRECTION_IN(pipeInformation: &USBD_PIPE_INFORMATION) -> UCHAR { + pipeInformation.EndpointAddress & USB_ENDPOINT_DIRECTION_MASK +} +STRUCT!{struct USBD_DEVICE_INFORMATION { + OffsetNext: ULONG, + UsbdDeviceHandle: PVOID, + DeviceDescriptor: USB_DEVICE_DESCRIPTOR, +}} +pub type PUSBD_DEVICE_INFORMATION = *mut USBD_DEVICE_INFORMATION; +STRUCT!{struct USBD_PIPE_INFORMATION { + MaximumPacketSize: USHORT, + EndpointAddress: UCHAR, + Interval: UCHAR, + PipeType: USBD_PIPE_TYPE, + PipeHandle: USBD_PIPE_HANDLE, + MaximumTransferSize: ULONG, + PipeFlags: ULONG, +}} +pub type PUSBD_PIPE_INFORMATION = *mut USBD_PIPE_INFORMATION; +pub const USBD_PF_CHANGE_MAX_PACKET: ULONG = 0x00000001; +pub const USBD_PF_SHORT_PACKET_OPT: ULONG = 0x00000002; +pub const USBD_PF_ENABLE_RT_THREAD_ACCESS: ULONG = 0x00000004; +pub const USBD_PF_MAP_ADD_TRANSFERS: ULONG = 0x00000008; +pub const USBD_PF_VALID_MASK: ULONG = USBD_PF_CHANGE_MAX_PACKET | USBD_PF_SHORT_PACKET_OPT + | USBD_PF_ENABLE_RT_THREAD_ACCESS | USBD_PF_MAP_ADD_TRANSFERS; +STRUCT!{struct USBD_INTERFACE_INFORMATION { + Length: USHORT, + InterfaceNumber: UCHAR, + AlternateSetting: UCHAR, + Class: UCHAR, + SubClass: UCHAR, + Protocol: UCHAR, + Reserved: UCHAR, + InterfaceHandle: USBD_INTERFACE_HANDLE, + NumberOfPipes: ULONG, + Pipes: [USBD_PIPE_INFORMATION; 1], +}} +pub type PUSBD_INTERFACE_INFORMATION = *mut USBD_INTERFACE_INFORMATION; +STRUCT!{struct URB_HCD_AREA { + Reserved8: [PVOID; 8], +}} +STRUCT!{struct URB_HEADER { + Length: USHORT, + Function: USHORT, + Status: USBD_STATUS, + UsbdDeviceHandle: PVOID, + UsbdFlags: ULONG, +}} +STRUCT!{struct URB_SELECT_INTERFACE { + Hdr: URB_HEADER, + ConfigurationHandle: USBD_CONFIGURATION_HANDLE, + Interface: USBD_INTERFACE_INFORMATION, +}} +STRUCT!{struct URB_SELECT_CONFIGURATION { + Hdr: URB_HEADER, + ConfigurationDescriptor: PUSB_CONFIGURATION_DESCRIPTOR, + ConfigurationHandle: USBD_CONFIGURATION_HANDLE, + Interface: USBD_INTERFACE_INFORMATION, +}} +STRUCT!{struct URB_PIPE_REQUEST { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + Reserved: ULONG, +}} +STRUCT!{struct URB_FRAME_LENGTH_CONTROL { + Hdr: URB_HEADER, +}} +STRUCT!{struct URB_GET_FRAME_LENGTH { + Hdr: URB_HEADER, + FrameLength: ULONG, + FrameNumber: ULONG, +}} +STRUCT!{struct URB_SET_FRAME_LENGTH { + Hdr: URB_HEADER, + FrameLengthDelta: LONG, +}} +STRUCT!{struct URB_GET_CURRENT_FRAME_NUMBER { + Hdr: URB_HEADER, + FrameNumber: ULONG, +}} +STRUCT!{struct URB_CONTROL_DESCRIPTOR_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved0: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + Reserved1: USHORT, + Index: UCHAR, + DescriptorType: UCHAR, + LanguageId: USHORT, + Reserved2: USHORT, +}} +STRUCT!{struct URB_CONTROL_GET_STATUS_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved0: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + Reserved1: [UCHAR; 4], + Index: USHORT, + Reserved2: USHORT, +}} +STRUCT!{struct URB_CONTROL_FEATURE_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved2: ULONG, + Reserved3: ULONG, + Reserved4: PVOID, + Reserved5: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + Reserved0: USHORT, + FeatureSelector: USHORT, + Index: USHORT, + Reserved1: USHORT, +}} +STRUCT!{struct URB_CONTROL_VENDOR_OR_CLASS_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + RequestTypeReservedBits: UCHAR, + Request: UCHAR, + Value: USHORT, + Index: USHORT, + Reserved1: USHORT, +}} +STRUCT!{struct URB_CONTROL_GET_INTERFACE_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved0: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + Reserved1: [UCHAR; 4], + Interface: USHORT, + Reserved2: USHORT, +}} +STRUCT!{struct URB_CONTROL_GET_CONFIGURATION_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved0: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + Reserved1: [UCHAR; 8], +}} +pub const OS_STRING_DESCRIPTOR_INDEX: UCHAR = 0xEE; +pub const MS_GENRE_DESCRIPTOR_INDEX: USHORT = 0x0001; +pub const MS_POWER_DESCRIPTOR_INDEX: USHORT = 0x0002; +pub const MS_OS_STRING_SIGNATURE: &'static str = "MSFT100"; +pub const MS_OS_FLAGS_CONTAINERID: UCHAR = 0x02; +UNION!{union OS_STRING_u { + [u8; 1], + bPad bPad_mut: UCHAR, + bFlags bFlags_mut: UCHAR, +}} +STRUCT!{struct OS_STRING { + bLength: UCHAR, + bDescriptorType: UCHAR, + MicrosoftString: [WCHAR; 7], + bVendorCode: UCHAR, + u: OS_STRING_u, +}} +pub type POS_STRING = *mut OS_STRING; +STRUCT!{struct URB_OS_FEATURE_DESCRIPTOR_REQUEST { + Hdr: URB_HEADER, + Reserved: PVOID, + Reserved0: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + BitField: UCHAR, + Reserved2: UCHAR, + InterfaceNumber: UCHAR, + MS_PageIndex: UCHAR, + MS_FeatureDescriptorIndex: USHORT, + Reserved3: USHORT, +}} +BITFIELD!{URB_OS_FEATURE_DESCRIPTOR_REQUEST BitField: UCHAR [ + Recipient set_Recipient[0..5], + Reserved1 set_Reserved1[5..8], +]} +STRUCT!{struct URB_CONTROL_TRANSFER { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + SetupPacket: [UCHAR; 8], +}} +#[cfg(target_pointer_width = "64")] +STRUCT!{struct URB_CONTROL_TRANSFER_EX { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + Timeout: ULONG, + Pad: ULONG, + hca: URB_HCD_AREA, + SetupPacket: [UCHAR; 8], +}} +#[cfg(target_arch = "x86")] +STRUCT!{struct URB_CONTROL_TRANSFER_EX { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + Timeout: ULONG, + hca: URB_HCD_AREA, + SetupPacket: [UCHAR; 8], +}} +STRUCT!{struct URB_BULK_OR_INTERRUPT_TRANSFER { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, +}} +STRUCT!{struct USBD_ISO_PACKET_DESCRIPTOR { + Offset: ULONG, + Length: ULONG, + Status: USBD_STATUS, +}} +pub type PUSBD_ISO_PACKET_DESCRIPTOR = *mut USBD_ISO_PACKET_DESCRIPTOR; +STRUCT!{struct URB_ISOCH_TRANSFER { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + TransferFlags: ULONG, + TransferBufferLength: ULONG, + TransferBuffer: PVOID, + TransferBufferMDL: PMDL, + UrbLink: *mut URB, + hca: URB_HCD_AREA, + StartFrame: ULONG, + NumberOfPackets: ULONG, + ErrorCount: ULONG, + IsoPacket: [USBD_ISO_PACKET_DESCRIPTOR; 1], +}} +pub const URB_OPEN_STATIC_STREAMS_VERSION_100: USHORT = 0x100; +STRUCT!{struct USBD_STREAM_INFORMATION { + PipeHandle: USBD_PIPE_HANDLE, + StreamID: ULONG, + MaximumTransferSize: ULONG, + PipeFlags: ULONG, +}} +pub type PUSBD_STREAM_INFORMATION = *mut USBD_STREAM_INFORMATION; +STRUCT!{struct URB_OPEN_STATIC_STREAMS { + Hdr: URB_HEADER, + PipeHandle: USBD_PIPE_HANDLE, + NumberOfStreams: ULONG, + StreamInfoVersion: USHORT, + StreamInfoSize: USHORT, + Streams: PUSBD_STREAM_INFORMATION, +}} +UNION!{union URB_u { + [u32; 24] [u64; 19], + UrbHeader UrbHeader_mut: URB_HEADER, + UrbSelectInterface UrbSelectInterface_mut: URB_SELECT_INTERFACE, + UrbSelectConfiguration UrbSelectConfiguration_mut: URB_SELECT_CONFIGURATION, + UrbPipeRequest UrbPipeRequest_mut: URB_PIPE_REQUEST, + UrbFrameLengthControl UrbFrameLengthControl_mut: URB_FRAME_LENGTH_CONTROL, + UrbGetFrameLength UrbGetFrameLength_mut: URB_GET_FRAME_LENGTH, + UrbSetFrameLength UrbSetFrameLength_mut: URB_SET_FRAME_LENGTH, + UrbGetCurrentFrameNumber UrbGetCurrentFrameNumber_mut: URB_GET_CURRENT_FRAME_NUMBER, + UrbControlTransfer UrbControlTransfer_mut: URB_CONTROL_TRANSFER, + UrbControlTransferEx UrbControlTransferEx_mut: URB_CONTROL_TRANSFER_EX, + UrbBulkOrInterruptTransfer UrbBulkOrInterruptTransfer_mut: URB_BULK_OR_INTERRUPT_TRANSFER, + UrbIsochronousTransfer UrbIsochronousTransfer_mut: URB_ISOCH_TRANSFER, + UrbControlDescriptorRequest UrbControlDescriptorRequest_mut: URB_CONTROL_DESCRIPTOR_REQUEST, + UrbControlGetStatusRequest UrbControlGetStatusRequest_mut: URB_CONTROL_GET_STATUS_REQUEST, + UrbControlFeatureRequest UrbControlFeatureRequest_mut: URB_CONTROL_FEATURE_REQUEST, + UrbControlVendorClassRequest UrbControlVendorClassRequest_mut: + URB_CONTROL_VENDOR_OR_CLASS_REQUEST, + UrbControlGetInterfaceRequest UrbControlGetInterfaceRequest_mut: + URB_CONTROL_GET_INTERFACE_REQUEST, + UrbControlGetConfigurationRequest UrbControlGetConfigurationRequest_mut: + URB_CONTROL_GET_CONFIGURATION_REQUEST, + UrbOSFeatureDescriptorRequest UrbOSFeatureDescriptorRequest_mut: + URB_OS_FEATURE_DESCRIPTOR_REQUEST, + UrbOpenStaticStreams UrbOpenStaticStreams_mut: URB_OPEN_STATIC_STREAMS, +}} +STRUCT!{struct URB { + u: URB_u, +}} +pub type PURB = *mut URB; diff --git a/winapi/src/shared/usbiodef.rs b/winapi/src/shared/usbiodef.rs new file mode 100644 index 000000000..e9028c640 --- /dev/null +++ b/winapi/src/shared/usbiodef.rs @@ -0,0 +1,112 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Common header file for all USB IOCTLs defined for +//! the core stack. We define them in this single header file +//! so that we can maintain backward compatibilty with older +//! versions of the stack. +use shared::guiddef::GUID; +use shared::minwindef::ULONG; +use um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_UNKNOWN, METHOD_BUFFERED, METHOD_NEITHER}; +use um::winnt::PVOID; +pub const USB_SUBMIT_URB: ULONG = 0; +pub const USB_RESET_PORT: ULONG = 1; +pub const USB_GET_ROOTHUB_PDO: ULONG = 3; +pub const USB_GET_PORT_STATUS: ULONG = 4; +pub const USB_ENABLE_PORT: ULONG = 5; +pub const USB_GET_HUB_COUNT: ULONG = 6; +pub const USB_CYCLE_PORT: ULONG = 7; +pub const USB_GET_HUB_NAME: ULONG = 8; +pub const USB_IDLE_NOTIFICATION: ULONG = 9; +pub const USB_RECORD_FAILURE: ULONG = 10; +pub const USB_GET_BUS_INFO: ULONG = 264; +pub const USB_GET_CONTROLLER_NAME: ULONG = 265; +pub const USB_GET_BUSGUID_INFO: ULONG = 266; +pub const USB_GET_PARENT_HUB_INFO: ULONG = 267; +pub const USB_GET_DEVICE_HANDLE: ULONG = 268; +pub const USB_GET_DEVICE_HANDLE_EX: ULONG = 269; +pub const USB_GET_TT_DEVICE_HANDLE: ULONG = 270; +pub const USB_GET_TOPOLOGY_ADDRESS: ULONG = 271; +pub const USB_IDLE_NOTIFICATION_EX: ULONG = 272; +pub const USB_REQ_GLOBAL_SUSPEND: ULONG = 273; +pub const USB_REQ_GLOBAL_RESUME: ULONG = 274; +pub const USB_GET_HUB_CONFIG_INFO: ULONG = 275; +pub const USB_FAIL_GET_STATUS: ULONG = 280; +pub const USB_REGISTER_COMPOSITE_DEVICE: ULONG = 0; +pub const USB_UNREGISTER_COMPOSITE_DEVICE: ULONG = 1; +pub const USB_REQUEST_REMOTE_WAKE_NOTIFICATION: ULONG = 2; +pub const HCD_GET_STATS_1: ULONG = 255; +pub const HCD_DIAGNOSTIC_MODE_ON: ULONG = 256; +pub const HCD_DIAGNOSTIC_MODE_OFF: ULONG = 257; +pub const HCD_GET_ROOT_HUB_NAME: ULONG = 258; +pub const HCD_GET_DRIVERKEY_NAME: ULONG = 265; +pub const HCD_GET_STATS_2: ULONG = 266; +pub const HCD_DISABLE_PORT: ULONG = 268; +pub const HCD_ENABLE_PORT: ULONG = 269; +pub const HCD_USER_REQUEST: ULONG = 270; +pub const HCD_TRACE_READ_REQUEST: ULONG = 275; +pub const USB_GET_NODE_INFORMATION: ULONG = 258; +pub const USB_GET_NODE_CONNECTION_INFORMATION: ULONG = 259; +pub const USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION: ULONG = 260; +pub const USB_GET_NODE_CONNECTION_NAME: ULONG = 261; +pub const USB_DIAG_IGNORE_HUBS_ON: ULONG = 262; +pub const USB_DIAG_IGNORE_HUBS_OFF: ULONG = 263; +pub const USB_GET_NODE_CONNECTION_DRIVERKEY_NAME: ULONG = 264; +pub const USB_GET_HUB_CAPABILITIES: ULONG = 271; +pub const USB_GET_NODE_CONNECTION_ATTRIBUTES: ULONG = 272; +pub const USB_HUB_CYCLE_PORT: ULONG = 273; +pub const USB_GET_NODE_CONNECTION_INFORMATION_EX: ULONG = 274; +pub const USB_RESET_HUB: ULONG = 275; +pub const USB_GET_HUB_CAPABILITIES_EX: ULONG = 276; +pub const USB_GET_HUB_INFORMATION_EX: ULONG = 277; +pub const USB_GET_PORT_CONNECTOR_PROPERTIES: ULONG = 278; +pub const USB_GET_NODE_CONNECTION_INFORMATION_EX_V2: ULONG = 279; +DEFINE_GUID!{GUID_DEVINTERFACE_USB_HUB, + 0xf18a0e88, 0xc30c, 0x11d0, 0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8} +DEFINE_GUID!{GUID_DEVINTERFACE_USB_DEVICE, + 0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} +DEFINE_GUID!{GUID_DEVINTERFACE_USB_HOST_CONTROLLER, + 0x3abf6f2d, 0x71c4, 0x462a, 0x8a, 0x92, 0x1e, 0x68, 0x61, 0xe6, 0xaf, 0x27} +DEFINE_GUID!{GUID_USB_WMI_STD_DATA, + 0x4E623B20, 0xCB14, 0x11D1, 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2} +DEFINE_GUID!{GUID_USB_WMI_STD_NOTIFICATION, + 0x4E623B20, 0xCB14, 0x11D1, 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2} +DEFINE_GUID!{GUID_USB_WMI_DEVICE_PERF_INFO, + 0x66c1aa3c, 0x499f, 0x49a0, 0xa9, 0xa5, 0x61, 0xe2, 0x35, 0x9f, 0x64, 0x7} +DEFINE_GUID!{GUID_USB_WMI_NODE_INFO, + 0x9c179357, 0xdc7a, 0x4f41, 0xb6, 0x6b, 0x32, 0x3b, 0x9d, 0xdc, 0xb5, 0xb1} +DEFINE_GUID!{GUID_USB_WMI_TRACING, + 0x3a61881b, 0xb4e6, 0x4bf9, 0xae, 0xf, 0x3c, 0xd8, 0xf3, 0x94, 0xe5, 0x2f} +DEFINE_GUID!{GUID_USB_TRANSFER_TRACING, + 0x681eb8aa, 0x403d, 0x452c, 0x9f, 0x8a, 0xf0, 0x61, 0x6f, 0xac, 0x95, 0x40} +DEFINE_GUID!{GUID_USB_PERFORMANCE_TRACING, + 0xd5de77a6, 0x6ae9, 0x425c, 0xb1, 0xe2, 0xf5, 0x61, 0x5f, 0xd3, 0x48, 0xa9} +DEFINE_GUID!{GUID_USB_WMI_SURPRISE_REMOVAL_NOTIFICATION, + 0x9bbbf831, 0xa2f2, 0x43b4, 0x96, 0xd1, 0x86, 0x94, 0x4b, 0x59, 0x14, 0xb3} +pub const GUID_CLASS_USBHUB: GUID = GUID_DEVINTERFACE_USB_HUB; +pub const GUID_CLASS_USB_DEVICE: GUID = GUID_DEVINTERFACE_USB_DEVICE; +pub const GUID_CLASS_USB_HOST_CONTROLLER: GUID = GUID_DEVINTERFACE_USB_HOST_CONTROLLER; +pub const FILE_DEVICE_USB: ULONG = FILE_DEVICE_UNKNOWN; +#[inline] +pub fn USB_CTL(id: ULONG) -> ULONG { + CTL_CODE!(FILE_DEVICE_USB, id, METHOD_BUFFERED, FILE_ANY_ACCESS) +} +#[inline] +pub fn USB_KERNEL_CTL(id: ULONG) -> ULONG { + CTL_CODE!(FILE_DEVICE_USB, id, METHOD_NEITHER, FILE_ANY_ACCESS) +} +#[inline] +pub fn USB_KERNEL_CTL_BUFFERED(id: ULONG) -> ULONG { + CTL_CODE!(FILE_DEVICE_USB, id, METHOD_BUFFERED, FILE_ANY_ACCESS) +} +// No calling convention was specified in the code +FN!{stdcall USB_IDLE_CALLBACK( + Context: PVOID, +) -> ()} +STRUCT!{struct USB_IDLE_CALLBACK_INFO { + IdleCallback: USB_IDLE_CALLBACK, + IdleContext: PVOID, +}} +pub type PUSB_IDLE_CALLBACK_INFO = *mut USB_IDLE_CALLBACK_INFO; diff --git a/winapi/src/shared/usbspec.rs b/winapi/src/shared/usbspec.rs new file mode 100644 index 000000000..5fae43efd --- /dev/null +++ b/winapi/src/shared/usbspec.rs @@ -0,0 +1,860 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! USB Spec Definitions. +use shared::basetsd::ULONG64; +use shared::guiddef::GUID; +use shared::minwindef::{UCHAR, ULONG, USHORT}; +use um::winnt::WCHAR; +ENUM!{enum USB_DEVICE_SPEED { + UsbLowSpeed = 0, + UsbFullSpeed, + UsbHighSpeed, + UsbSuperSpeed, +}} +ENUM!{enum USB_DEVICE_TYPE { + Usb11Device = 0, + Usb20Device, +}} +STRUCT!{#[repr(packed)] struct BM_REQUEST_TYPE { + B: UCHAR, +}} +BITFIELD!{BM_REQUEST_TYPE B: UCHAR [ + Recipient set_Recipient[0..2], + Reserved set_Reserved[2..5], + Type set_Type[5..7], + Dir set_Dir[7..8], +]} +pub type PBM_REQUEST_TYPE = *mut BM_REQUEST_TYPE; +STRUCT!{#[repr(packed)] struct USB_DEFAULT_PIPE_SETUP_PACKET_wValue_s { + LowByte: UCHAR, + HiByte: UCHAR, +}} +UNION!{#[repr(packed)] union USB_DEFAULT_PIPE_SETUP_PACKET_wValue { + [u16; 1], + s s_mut: USB_DEFAULT_PIPE_SETUP_PACKET_wValue_s, + W W_mut: USHORT, +}} +STRUCT!{#[repr(packed)] struct USB_DEFAULT_PIPE_SETUP_PACKET_wIndex_s { + LowByte: UCHAR, + HiByte: UCHAR, +}} +UNION!{#[repr(packed)] union USB_DEFAULT_PIPE_SETUP_PACKET_wIndex { + [u16; 1], + s s_mut: USB_DEFAULT_PIPE_SETUP_PACKET_wIndex_s, + W W_mut: USHORT, +}} +STRUCT!{#[repr(packed)] struct USB_DEFAULT_PIPE_SETUP_PACKET { + bmRequestType: BM_REQUEST_TYPE, + bRequest: UCHAR, + wValue: USB_DEFAULT_PIPE_SETUP_PACKET_wValue, + wIndex: USB_DEFAULT_PIPE_SETUP_PACKET_wIndex, + wLength: USHORT, +}} +pub type PUSB_DEFAULT_PIPE_SETUP_PACKET = *mut USB_DEFAULT_PIPE_SETUP_PACKET; +pub const BMREQUEST_HOST_TO_DEVICE: UCHAR = 0; +pub const BMREQUEST_DEVICE_TO_HOST: UCHAR = 1; +pub const BMREQUEST_STANDARD: UCHAR = 0; +pub const BMREQUEST_CLASS: UCHAR = 1; +pub const BMREQUEST_VENDOR: UCHAR = 2; +pub const BMREQUEST_TO_DEVICE: UCHAR = 0; +pub const BMREQUEST_TO_INTERFACE: UCHAR = 1; +pub const BMREQUEST_TO_ENDPOINT: UCHAR = 2; +pub const BMREQUEST_TO_OTHER: UCHAR = 3; +#[inline] +pub fn USB_DESCRIPTOR_MAKE_TYPE_AND_INDEX(d: UCHAR, i: UCHAR) -> USHORT { + (d as USHORT) << 8 | (i as USHORT) +} +pub const USB_REQUEST_GET_STATUS: UCHAR = 0x00; +pub const USB_REQUEST_CLEAR_FEATURE: UCHAR = 0x01; +pub const USB_REQUEST_SET_FEATURE: UCHAR = 0x03; +pub const USB_REQUEST_SET_ADDRESS: UCHAR = 0x05; +pub const USB_REQUEST_GET_DESCRIPTOR: UCHAR = 0x06; +pub const USB_REQUEST_SET_DESCRIPTOR: UCHAR = 0x07; +pub const USB_REQUEST_GET_CONFIGURATION: UCHAR = 0x08; +pub const USB_REQUEST_SET_CONFIGURATION: UCHAR = 0x09; +pub const USB_REQUEST_GET_INTERFACE: UCHAR = 0x0A; +pub const USB_REQUEST_SET_INTERFACE: UCHAR = 0x0B; +pub const USB_REQUEST_SYNC_FRAME: UCHAR = 0x0C; +pub const USB_REQUEST_SET_SEL: UCHAR = 0x30; +pub const USB_REQUEST_ISOCH_DELAY: UCHAR = 0x31; +pub const USB_DEVICE_DESCRIPTOR_TYPE: UCHAR = 0x01; +pub const USB_CONFIGURATION_DESCRIPTOR_TYPE: UCHAR = 0x02; +pub const USB_STRING_DESCRIPTOR_TYPE: UCHAR = 0x03; +pub const USB_INTERFACE_DESCRIPTOR_TYPE: UCHAR = 0x04; +pub const USB_ENDPOINT_DESCRIPTOR_TYPE: UCHAR = 0x05; +pub const USB_DEVICE_QUALIFIER_DESCRIPTOR_TYPE: UCHAR = 0x06; +pub const USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR_TYPE: UCHAR = 0x07; +pub const USB_INTERFACE_POWER_DESCRIPTOR_TYPE: UCHAR = 0x08; +pub const USB_OTG_DESCRIPTOR_TYPE: UCHAR = 0x09; +pub const USB_DEBUG_DESCRIPTOR_TYPE: UCHAR = 0x0A; +pub const USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE: UCHAR = 0x0B; +pub const USB_BOS_DESCRIPTOR_TYPE: UCHAR = 0x0F; +pub const USB_DEVICE_CAPABILITY_DESCRIPTOR_TYPE: UCHAR = 0x10; +pub const USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_TYPE: UCHAR = 0x30; +pub const USB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR_TYPE: UCHAR = 0x31; +pub const USB_RESERVED_DESCRIPTOR_TYPE: UCHAR = 0x06; +pub const USB_CONFIG_POWER_DESCRIPTOR_TYPE: UCHAR = 0x07; +pub const USB_FEATURE_ENDPOINT_STALL: UCHAR = 0x00; +pub const USB_FEATURE_REMOTE_WAKEUP: UCHAR = 0x01; +pub const USB_FEATURE_TEST_MODE: UCHAR = 0x02; +pub const USB_FEATURE_FUNCTION_SUSPEND: UCHAR = 0x00; +pub const USB_FEATURE_U1_ENABLE: UCHAR = 0x30; +pub const USB_FEATURE_U2_ENABLE: UCHAR = 0x31; +pub const USB_FEATURE_LTM_ENABLE: UCHAR = 0x32; +pub const USB_FEATURE_LDM_ENABLE: UCHAR = 0x35; +pub const USB_FEATURE_BATTERY_WAKE_MASK: UCHAR = 0x28; +pub const USB_FEATURE_OS_IS_PD_AWARE: UCHAR = 0x29; +pub const USB_FEATURE_POLICY_MODE: UCHAR = 0x2A; +pub const USB_FEATURE_CHARGING_POLICY: UCHAR = 0x36; +pub const USB_CHARGING_POLICY_DEFAULT: UCHAR = 0x00; +pub const USB_CHARGING_POLICY_ICCHPF: UCHAR = 0x01; +pub const USB_CHARGING_POLICY_ICCLPF: UCHAR = 0x02; +pub const USB_CHARGING_POLICY_NO_POWER: UCHAR = 0x03; +pub const USB_STATUS_PORT_STATUS: UCHAR = 0x00; +pub const USB_STATUS_PD_STATUS: UCHAR = 0x01; +pub const USB_STATUS_EXT_PORT_STATUS: UCHAR = 0x02; +pub const USB_GETSTATUS_SELF_POWERED: UCHAR = 0x01; +pub const USB_GETSTATUS_REMOTE_WAKEUP_ENABLED: UCHAR = 0x02; +pub const USB_GETSTATUS_U1_ENABLE: UCHAR = 0x04; +pub const USB_GETSTATUS_U2_ENABLE: UCHAR = 0x08; +pub const USB_GETSTATUS_LTM_ENABLE: UCHAR = 0x10; +STRUCT!{#[repr(packed)] struct USB_DEVICE_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_DEVICE_STATUS AsUshort16: USHORT [ + SelfPowered set_SelfPowered[0..1], + RemoteWakeup set_RemoteWakeup[1..2], + U1Enable set_U1Enable[2..3], + U2Enable set_U2Enable[3..4], + LtmEnable set_LtmEnable[4..5], + Reserved set_Reserved[5..16], +]} +pub type PUSB_DEVICE_STATUS = *mut USB_DEVICE_STATUS; +STRUCT!{#[repr(packed)] struct USB_INTERFACE_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_INTERFACE_STATUS AsUshort16: USHORT [ + RemoteWakeupCapable set_RemoteWakeupCapable[0..1], + RemoteWakeupEnabled set_RemoteWakeupEnabled[1..2], + Reserved set_Reserved[2..16], +]} +pub type PUSB_INTERFACE_STATUS = *mut USB_INTERFACE_STATUS; +STRUCT!{#[repr(packed)] struct USB_ENDPOINT_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_ENDPOINT_STATUS AsUshort16: USHORT [ + Halt set_Halt[0..1], + Reserved set_Reserved[1..16], +]} +pub type PUSB_ENDPOINT_STATUS = *mut USB_ENDPOINT_STATUS; +STRUCT!{#[repr(packed)] struct USB_COMMON_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, +}} +pub type PUSB_COMMON_DESCRIPTOR = *mut USB_COMMON_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bcdUSB: USHORT, + bDeviceClass: UCHAR, + bDeviceSubClass: UCHAR, + bDeviceProtocol: UCHAR, + bMaxPacketSize0: UCHAR, + idVendor: USHORT, + idProduct: USHORT, + bcdDevice: USHORT, + iManufacturer: UCHAR, + iProduct: UCHAR, + iSerialNumber: UCHAR, + bNumConfigurations: UCHAR, +}} +pub type PUSB_DEVICE_DESCRIPTOR = *mut USB_DEVICE_DESCRIPTOR; +pub const USB_DEVICE_CLASS_RESERVED: UCHAR = 0x00; +pub const USB_DEVICE_CLASS_AUDIO: UCHAR = 0x01; +pub const USB_DEVICE_CLASS_COMMUNICATIONS: UCHAR = 0x02; +pub const USB_DEVICE_CLASS_HUMAN_INTERFACE: UCHAR = 0x03; +pub const USB_DEVICE_CLASS_MONITOR: UCHAR = 0x04; +pub const USB_DEVICE_CLASS_PHYSICAL_INTERFACE: UCHAR = 0x05; +pub const USB_DEVICE_CLASS_POWER: UCHAR = 0x06; +pub const USB_DEVICE_CLASS_IMAGE: UCHAR = 0x06; +pub const USB_DEVICE_CLASS_PRINTER: UCHAR = 0x07; +pub const USB_DEVICE_CLASS_STORAGE: UCHAR = 0x08; +pub const USB_DEVICE_CLASS_HUB: UCHAR = 0x09; +pub const USB_DEVICE_CLASS_CDC_DATA: UCHAR = 0x0A; +pub const USB_DEVICE_CLASS_SMART_CARD: UCHAR = 0x0B; +pub const USB_DEVICE_CLASS_CONTENT_SECURITY: UCHAR = 0x0D; +pub const USB_DEVICE_CLASS_VIDEO: UCHAR = 0x0E; +pub const USB_DEVICE_CLASS_PERSONAL_HEALTHCARE: UCHAR = 0x0F; +pub const USB_DEVICE_CLASS_AUDIO_VIDEO: UCHAR = 0x10; +pub const USB_DEVICE_CLASS_BILLBOARD: UCHAR = 0x11; +pub const USB_DEVICE_CLASS_DIAGNOSTIC_DEVICE: UCHAR = 0xDC; +pub const USB_DEVICE_CLASS_WIRELESS_CONTROLLER: UCHAR = 0xE0; +pub const USB_DEVICE_CLASS_MISCELLANEOUS: UCHAR = 0xEF; +pub const USB_DEVICE_CLASS_APPLICATION_SPECIFIC: UCHAR = 0xFE; +pub const USB_DEVICE_CLASS_VENDOR_SPECIFIC: UCHAR = 0xFF; +STRUCT!{#[repr(packed)] struct USB_DEVICE_QUALIFIER_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bcdUSB: USHORT, + bDeviceClass: UCHAR, + bDeviceSubClass: UCHAR, + bDeviceProtocol: UCHAR, + bMaxPacketSize0: UCHAR, + bNumConfigurations: UCHAR, + bReserved: UCHAR, +}} +pub type PUSB_DEVICE_QUALIFIER_DESCRIPTOR = *mut USB_DEVICE_QUALIFIER_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_BOS_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + wTotalLength: USHORT, + bNumDeviceCaps: UCHAR, +}} +pub type PUSB_BOS_DESCRIPTOR = *mut USB_BOS_DESCRIPTOR; +pub const USB_DEVICE_CAPABILITY_WIRELESS_USB: UCHAR = 0x01; +pub const USB_DEVICE_CAPABILITY_USB20_EXTENSION: UCHAR = 0x02; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_USB: UCHAR = 0x03; +pub const USB_DEVICE_CAPABILITY_CONTAINER_ID: UCHAR = 0x04; +pub const USB_DEVICE_CAPABILITY_PLATFORM: UCHAR = 0x05; +pub const USB_DEVICE_CAPABILITY_POWER_DELIVERY: UCHAR = 0x06; +pub const USB_DEVICE_CAPABILITY_BATTERY_INFO: UCHAR = 0x07; +pub const USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT: UCHAR = 0x08; +pub const USB_DEVICE_CAPABILITY_PD_PROVIDER_PORT: UCHAR = 0x09; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB: UCHAR = 0x0A; +pub const USB_DEVICE_CAPABILITY_PRECISION_TIME_MEASUREMENT: UCHAR = 0x0B; +pub const USB_DEVICE_CAPABILITY_BILLBOARD: UCHAR = 0x0D; +pub const USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY: UCHAR = 0x10; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR_bmAttributes { + AsUlong: ULONG, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR_bmAttributes AsUlong: ULONG [ + Reserved set_Reserved[0..1], + LPMCapable set_LPMCapable[1..2], + BESLAndAlternateHIRDSupported set_BESLAndAlternateHIRDSupported[2..3], + BaselineBESLValid set_BaselineBESLValid[3..4], + DeepBESLValid set_DeepBESLValid[4..5], + Reserved1 set_Reserved1[5..8], + BaselineBESL set_BaselineBESL[8..12], + DeepBESL set_DeepBESL[12..16], + Reserved2 set_Reserved2[16..32], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bmAttributes: USB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR_bmAttributes, +}} +pub type PUSB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_USB20_EXTENSION_DESCRIPTOR; +pub const USB_DEVICE_CAPABILITY_USB20_EXTENSION_BMATTRIBUTES_RESERVED_MASK: ULONG = 0xFFFF00E1; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR_bmAttributes { + AsUlong: ULONG, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR_bmAttributes AsUlong: ULONG [ + Reserved set_Reserved[0..1], + BatteryCharging set_BatteryCharging[1..2], + USBPowerDelivery set_USBPowerDelivery[2..3], + Provider set_Provider[3..4], + Consumer set_Consumer[4..5], + ChargingPolicy set_ChargingPolicy[5..6], + TypeCCurrent set_TypeCCurrent[6..7], + Reserved2 set_Reserved2[7..8], + ACSupply set_ACSupply[8..9], + Battery set_Battery[9..10], + Other set_Other[10..11], + NumBatteries set_NumBatteries[11..14], + UsesVbus set_UsesVbus[14..15], + Reserved3 set_Reserved3[15..32], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bReserved: UCHAR, + bmAttributes: USB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR_bmAttributes, + bmProviderPorts: USHORT, + bmConsumerPorts: USHORT, + bcdBCVersion: USHORT, + bcdPDVersion: USHORT, + bcdUSBTypeCVersion: USHORT, +}} +pub type PUSB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_POWER_DELIVERY_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR_bmCapabilities { + AsUshort: USHORT, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR_bmCapabilities AsUshort: USHORT [ + BatteryCharging set_BatteryCharging[0..1], + USBPowerDelivery set_USBPowerDelivery[1..2], + USBTypeCCurrent set_USBTypeCCurrent[2..3], + Reserved set_Reserved[3..16], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bReserved: UCHAR, + bmCapabilities: USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR_bmCapabilities, + wMinVoltage: USHORT, + wMaxVoltage: USHORT, + wReserved: USHORT, + dwMaxOperatingPower: ULONG, + dwMaxPeakPower: ULONG, + dwMaxPeakPowerTime: ULONG, +}} +pub type PUSB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_PD_CONSUMER_PORT_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bmAttributes: UCHAR, + wSpeedsSupported: USHORT, + bFunctionalitySupport: UCHAR, + bU1DevExitLat: UCHAR, + wU2DevExitLat: USHORT, +}} +pub type PUSB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_SUPERSPEED_USB_DESCRIPTOR; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_RESERVED_MASK: UCHAR = 0xFD; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_BMATTRIBUTES_LTM_CAPABLE: UCHAR = 0x02; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_RESERVED_MASK: USHORT = 0xFFF0; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_LOW: USHORT = 0x0001; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_FULL: USHORT = 0x0002; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_HIGH: USHORT = 0x0004; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_SPEEDS_SUPPORTED_SUPER: USHORT = 0x0008; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_U1_DEVICE_EXIT_MAX_VALUE: UCHAR = 0x0A; +pub const USB_DEVICE_CAPABILITY_SUPERSPEED_U2_DEVICE_EXIT_MAX_VALUE: USHORT = 0x07FF; +pub const USB_DEVICE_CAPABILITY_MAX_U1_LATENCY: UCHAR = 0x0A; +pub const USB_DEVICE_CAPABILITY_MAX_U2_LATENCY: USHORT = 0x07FF; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_LSE_BPS: ULONG = 0; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_LSE_KBPS: ULONG = 1; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_LSE_MBPS: ULONG = 2; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_LSE_GBPS: ULONG = 3; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_MODE_SYMMETRIC: ULONG = 0; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_MODE_ASYMMETRIC: ULONG = 1; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_DIR_RX: ULONG = 0; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_DIR_TX: ULONG = 1; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_PROTOCOL_SS: ULONG = 0; +pub const USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED_PROTOCOL_SSP: ULONG = 1; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED { + AsUlong32: ULONG, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED AsUlong32: ULONG [ + SublinkSpeedAttrID set_SublinkSpeedAttrID[0..4], + LaneSpeedExponent set_LaneSpeedExponent[4..6], + SublinkTypeMode set_SublinkTypeMode[6..7], + SublinkTypeDir set_SublinkTypeDir[7..8], + Reserved set_Reserved[8..14], + LinkProtocol set_LinkProtocol[14..16], + LaneSpeedMantissa set_LaneSpeedMantissa[16..32], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_bmAttributes { + AsUlong32: ULONG, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_bmAttributes AsUlong32: ULONG [ + SublinkSpeedAttrCount set_SublinkSpeedAttrCount[0..5], + SublinkSpeedIDCount set_SublinkSpeedIDCount[5..9], + Reserved set_Reserved[9..32], +]} +STRUCT!{#[repr(packed)] + struct USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_wFunctionalitySupport { + AsUshort: USHORT, +}} +BITFIELD!{ + USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_wFunctionalitySupport AsUshort: USHORT [ + SublinkSpeedAttrID set_SublinkSpeedAttrID[0..4], + Reserved set_Reserved[4..8], + MinRxLaneCount set_MinRxLaneCount[8..12], + MinTxLaneCount set_MinTxLaneCount[12..16], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bReserved: UCHAR, + bmAttributes: USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_bmAttributes, + wFunctionalitySupport: + USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR_wFunctionalitySupport, + wReserved: USHORT, + bmSublinkSpeedAttr: [USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_SPEED; 1], +}} +pub type PUSB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_SUPERSPEEDPLUS_USB_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bReserved: UCHAR, + ContainerID: [UCHAR; 16], +}} +pub type PUSB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_CONTAINER_ID_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR_Function { + bClass: UCHAR, + bSubClass: UCHAR, + bProtocol: UCHAR, +}} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bcdVersion: USHORT, + bConfigurationValue: UCHAR, + bMaxPower: UCHAR, + bNumFunctions: UCHAR, + Function: [USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR_Function; 1], +}} +pub type PUSB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_CONFIGURATION_SUMMARY_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + bReserved: UCHAR, + PlatformCapabilityUuid: GUID, + CapabililityData: [UCHAR; 1], +}} +pub type PUSB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_PLATFORM_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR_VconnPower { + AsUshort: USHORT, +}} +BITFIELD!{USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR_VconnPower AsUshort: USHORT [ + VConnPowerNeededForFullFunctionality set_VConnPowerNeededForFullFunctionality[0..3], + Reserved set_Reserved[3..15], + NoVconnPowerRequired set_NoVconnPowerRequired[15..16], +]} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR_AlternateMode { + wSVID: USHORT, + bAlternateMode: UCHAR, + iAlternateModeSetting: UCHAR, +}} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, + iAddtionalInfoURL: UCHAR, + bNumberOfAlternateModes: UCHAR, + bPreferredAlternateMode: UCHAR, + VconnPower: USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR_VconnPower, + bmConfigured: [UCHAR; 32], + bReserved: ULONG, + AlternateMode: [USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR_AlternateMode; 1], +}} +pub type PUSB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR + = *mut USB_DEVICE_CAPABILITY_BILLBOARD_DESCRIPTOR; +DEFINE_GUID!{GUID_USB_MSOS20_PLATFORM_CAPABILITY_ID, + 0xd8dd60df, 0x4589, 0x4cc7, 0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, 0x9f} +STRUCT!{#[repr(packed)] struct USB_DEVICE_CAPABILITY_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bDevCapabilityType: UCHAR, +}} +pub type PUSB_DEVICE_CAPABILITY_DESCRIPTOR = *mut USB_DEVICE_CAPABILITY_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_CONFIGURATION_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + wTotalLength: USHORT, + bNumInterfaces: UCHAR, + bConfigurationValue: UCHAR, + iConfiguration: UCHAR, + bmAttributes: UCHAR, + MaxPower: UCHAR, +}} +pub type PUSB_CONFIGURATION_DESCRIPTOR = *mut USB_CONFIGURATION_DESCRIPTOR; +pub const USB_CONFIG_POWERED_MASK: UCHAR = 0xC0; +pub const USB_CONFIG_BUS_POWERED: UCHAR = 0x80; +pub const USB_CONFIG_SELF_POWERED: UCHAR = 0x40; +pub const USB_CONFIG_REMOTE_WAKEUP: UCHAR = 0x20; +pub const USB_CONFIG_RESERVED: UCHAR = 0x1F; +STRUCT!{#[repr(packed)] struct USB_INTERFACE_ASSOCIATION_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bFirstInterface: UCHAR, + bInterfaceCount: UCHAR, + bFunctionClass: UCHAR, + bFunctionSubClass: UCHAR, + bFunctionProtocol: UCHAR, + iFunction: UCHAR, +}} +pub type PUSB_INTERFACE_ASSOCIATION_DESCRIPTOR = *mut USB_INTERFACE_ASSOCIATION_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_INTERFACE_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bInterfaceNumber: UCHAR, + bAlternateSetting: UCHAR, + bNumEndpoints: UCHAR, + bInterfaceClass: UCHAR, + bInterfaceSubClass: UCHAR, + bInterfaceProtocol: UCHAR, + iInterface: UCHAR, +}} +pub type PUSB_INTERFACE_DESCRIPTOR = *mut USB_INTERFACE_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_ENDPOINT_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bEndpointAddress: UCHAR, + bmAttributes: UCHAR, + wMaxPacketSize: USHORT, + bInterval: UCHAR, +}} +pub type PUSB_ENDPOINT_DESCRIPTOR = *mut USB_ENDPOINT_DESCRIPTOR; +pub const USB_ENDPOINT_DIRECTION_MASK: UCHAR = 0x80; +#[inline] +pub fn USB_ENDPOINT_DIRECTION_OUT(addr: UCHAR) -> UCHAR { + !(addr & USB_ENDPOINT_DIRECTION_MASK) +} +#[inline] +pub fn USB_ENDPOINT_DIRECTION_IN(addr: UCHAR) -> UCHAR { + addr & USB_ENDPOINT_DIRECTION_MASK +} +pub const USB_ENDPOINT_ADDRESS_MASK: UCHAR = 0x0F; +pub const USB_ENDPOINT_TYPE_MASK: UCHAR = 0x03; +pub const USB_ENDPOINT_TYPE_CONTROL: UCHAR = 0x00; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS: UCHAR = 0x01; +pub const USB_ENDPOINT_TYPE_BULK: UCHAR = 0x02; +pub const USB_ENDPOINT_TYPE_INTERRUPT: UCHAR = 0x03; +pub const USB_ENDPOINT_TYPE_BULK_RESERVED_MASK: UCHAR = 0xFC; +pub const USB_ENDPOINT_TYPE_CONTROL_RESERVED_MASK: UCHAR = 0xFC; +pub const USB_20_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK: UCHAR = 0xFC; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_RESERVED_MASK: UCHAR = 0xCC; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_RESERVED_MASK: UCHAR = 0xC0; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_MASK: UCHAR = 0x30; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_PERIODIC: UCHAR = 0x00; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_NOTIFICATION: UCHAR = 0x10; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED10: UCHAR = 0x20; +pub const USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_RESERVED11: UCHAR = 0x30; +#[inline] +pub fn USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE(bmAttr: UCHAR) -> UCHAR { + bmAttr & USB_30_ENDPOINT_TYPE_INTERRUPT_USAGE_MASK +} +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_MASK: UCHAR = 0x0C; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_NO_SYNCHRONIZATION: UCHAR = 0x00; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ASYNCHRONOUS: UCHAR = 0x04; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_ADAPTIVE: UCHAR = 0x08; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_SYNCHRONOUS: UCHAR = 0x0C; +#[inline] +pub fn USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION(bmAttr: UCHAR) -> UCHAR { + bmAttr & USB_ENDPOINT_TYPE_ISOCHRONOUS_SYNCHRONIZATION_MASK +} +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_MASK: UCHAR = 0x30; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_DATA_ENDOINT: UCHAR = 0x00; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_FEEDBACK_ENDPOINT: UCHAR = 0x10; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_IMPLICIT_FEEDBACK_DATA_ENDPOINT: UCHAR = 0x20; +pub const USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_RESERVED: UCHAR = 0x30; +#[inline] +pub fn USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE(bmAttr: UCHAR) -> UCHAR { + bmAttr & USB_ENDPOINT_TYPE_ISOCHRONOUS_USAGE_MASK +} +STRUCT!{#[repr(packed)] struct USB_HIGH_SPEED_MAXPACKET { + us: USHORT, +}} +BITFIELD!{USB_HIGH_SPEED_MAXPACKET us: USHORT [ + MaxPacket set_MaxPacket[0..11], + HSmux set_HSmux[11..13], + Reserved set_Reserved[13..16], +]} +pub type PUSB_HIGH_SPEED_MAXPACKET = *mut USB_HIGH_SPEED_MAXPACKET; +pub const USB_ENDPOINT_SUPERSPEED_BULK_MAX_PACKET_SIZE: USHORT = 1024; +pub const USB_ENDPOINT_SUPERSPEED_CONTROL_MAX_PACKET_SIZE: USHORT = 512; +pub const USB_ENDPOINT_SUPERSPEED_ISO_MAX_PACKET_SIZE: USHORT = 1024; +pub const USB_ENDPOINT_SUPERSPEED_INTERRUPT_MAX_PACKET_SIZE: USHORT = 1024; +STRUCT!{#[repr(packed)] struct USB_STRING_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bString: [WCHAR; 1], +}} +pub type PUSB_STRING_DESCRIPTOR = *mut USB_STRING_DESCRIPTOR; +pub const MAXIMUM_USB_STRING_LENGTH: UCHAR = 255; +STRUCT!{#[repr(packed)] struct USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Bulk { + BitField: UCHAR, +}} +BITFIELD!{USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Bulk BitField: UCHAR [ + MaxStreams set_MaxStreams[0..5], + Reserved1 set_Reserved1[5..8], +]} +STRUCT!{#[repr(packed)] + struct USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Isochronous { + BitField: UCHAR, +}} +BITFIELD!{USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Isochronous BitField: UCHAR [ + Mult set_Mult[0..2], + Reserved2 set_Reserved2[2..7], + SspCompanion set_SspCompanion[7..8], +]} +UNION!{#[repr(packed)] union USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes { + [u8; 1], + AsUchar AsUchar_mut: UCHAR, + Bulk Bulk_mut: USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Bulk, + Isochronous Isochronous_mut: + USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes_Isochronous, +}} +STRUCT!{#[repr(packed)] struct USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bMaxBurst: UCHAR, + bmAttributes: USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR_bmAttributes, + wBytesPerInterval: USHORT, +}} +pub type PUSB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR + = *mut USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR; +pub const USB_SUPERSPEED_ISOCHRONOUS_MAX_MULTIPLIER: UCHAR = 2; +STRUCT!{#[repr(packed)] struct USB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + wReserved: USHORT, + dwBytesPerInterval: ULONG, +}} +pub type PUSB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR + = *mut USB_SUPERSPEEDPLUS_ISOCH_ENDPOINT_COMPANION_DESCRIPTOR; +pub const USB_SUPERSPEEDPLUS_ISOCHRONOUS_MIN_BYTESPERINTERVAL: ULONG = 0xC001; +pub const USB_SUPERSPEEDPLUS_ISOCHRONOUS_MAX_BYTESPERINTERVAL: ULONG = 0xFFFFFF; +STRUCT!{#[repr(packed)] struct USB_HUB_DESCRIPTOR { + bDescriptorLength: UCHAR, + bDescriptorType: UCHAR, + bNumberOfPorts: UCHAR, + wHubCharacteristics: USHORT, + bPowerOnToPowerGood: UCHAR, + bHubControlCurrent: UCHAR, + bRemoveAndPowerMask: [UCHAR; 64], +}} +pub type PUSB_HUB_DESCRIPTOR = *mut USB_HUB_DESCRIPTOR; +pub const USB_20_HUB_DESCRIPTOR_TYPE: UCHAR = 0x29; +STRUCT!{#[repr(packed)] struct USB_30_HUB_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bNumberOfPorts: UCHAR, + wHubCharacteristics: USHORT, + bPowerOnToPowerGood: UCHAR, + bHubControlCurrent: UCHAR, + bHubHdrDecLat: UCHAR, + wHubDelay: USHORT, + DeviceRemovable: USHORT, +}} +pub type PUSB_30_HUB_DESCRIPTOR = *mut USB_30_HUB_DESCRIPTOR; +pub const USB_30_HUB_DESCRIPTOR_TYPE: UCHAR = 0x2A; +pub const USB_REQUEST_GET_STATE: UCHAR = 0x02; +pub const USB_REQUEST_CLEAR_TT_BUFFER: UCHAR = 0x08; +pub const USB_REQUEST_RESET_TT: UCHAR = 0x09; +pub const USB_REQUEST_GET_TT_STATE: UCHAR = 0x0A; +pub const USB_REQUEST_STOP_TT: UCHAR = 0x0B; +pub const USB_REQUEST_SET_HUB_DEPTH: UCHAR = 0x0C; +pub const USB_REQUEST_GET_PORT_ERR_COUNT: UCHAR = 0x0D; +STRUCT!{#[repr(packed)] struct USB_HUB_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_HUB_STATUS AsUshort16: USHORT [ + LocalPowerLost set_LocalPowerLost[0..1], + OverCurrent set_OverCurrent[1..2], + Reserved set_Reserved[2..16], +]} +pub type PUSB_HUB_STATUS = *mut USB_HUB_STATUS; +STRUCT!{#[repr(packed)] struct USB_HUB_CHANGE { + AsUshort16: USHORT, +}} +BITFIELD!{USB_HUB_CHANGE AsUshort16: USHORT [ + LocalPowerChange set_LocalPowerChange[0..1], + OverCurrentChange set_OverCurrentChange[1..2], + Reserved set_Reserved[2..16], +]} +pub type PUSB_HUB_CHANGE = *mut USB_HUB_CHANGE; +STRUCT!{#[repr(packed)] struct USB_HUB_STATUS_AND_CHANGE_s { + HubStatus: USB_HUB_STATUS, + HubChange: USB_HUB_CHANGE, +}} +UNION!{#[repr(packed)] union USB_HUB_STATUS_AND_CHANGE { + [u32; 1], + AsUlong32 AsUlong32_mut: ULONG, + s s_mut: USB_HUB_STATUS_AND_CHANGE_s, +}} +pub type PUSB_HUB_STATUS_AND_CHANGE = *mut USB_HUB_STATUS_AND_CHANGE; +STRUCT!{#[repr(packed)] struct USB_20_PORT_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_20_PORT_STATUS AsUshort16: USHORT [ + CurrentConnectStatus set_CurrentConnectStatus[0..1], + PortEnabledDisabled set_PortEnabledDisabled[1..2], + Suspend set_Suspend[2..3], + OverCurrent set_OverCurrent[3..4], + Reset set_Reset[4..5], + L1 set_L1[5..6], + Reserved0 set_Reserved0[6..8], + PortPower set_PortPower[8..9], + LowSpeedDeviceAttached set_LowSpeedDeviceAttached[9..10], + HighSpeedDeviceAttached set_HighSpeedDeviceAttached[10..11], + PortTestMode set_PortTestMode[11..12], + PortIndicatorControl set_PortIndicatorControl[12..13], + Reserved1 set_Reserved1[13..16], +]} +pub type PUSB_20_PORT_STATUS = *mut USB_20_PORT_STATUS; +pub const USB_PORT_STATUS_CONNECT: USHORT = 0x0001; +pub const USB_PORT_STATUS_ENABLE: USHORT = 0x0002; +pub const USB_PORT_STATUS_SUSPEND: USHORT = 0x0004; +pub const USB_PORT_STATUS_OVER_CURRENT: USHORT = 0x0008; +pub const USB_PORT_STATUS_RESET: USHORT = 0x0010; +pub const USB_PORT_STATUS_POWER: USHORT = 0x0100; +pub const USB_PORT_STATUS_LOW_SPEED: USHORT = 0x0200; +pub const USB_PORT_STATUS_HIGH_SPEED: USHORT = 0x0400; +STRUCT!{#[repr(packed)] struct USB_20_PORT_CHANGE { + AsUshort16: USHORT, +}} +BITFIELD!{USB_20_PORT_CHANGE AsUshort16: USHORT [ + ConnectStatusChange set_ConnectStatusChange[0..1], + PortEnableDisableChange set_PortEnableDisableChange[1..2], + SuspendChange set_SuspendChange[2..3], + OverCurrentIndicatorChange set_OverCurrentIndicatorChange[3..4], + ResetChange set_ResetChange[4..5], + Reserved2 set_Reserved2[5..16], +]} +pub type PUSB_20_PORT_CHANGE = *mut USB_20_PORT_CHANGE; +STRUCT!{#[repr(packed)] struct USB_30_PORT_STATUS { + AsUshort16: USHORT, +}} +BITFIELD!{USB_30_PORT_STATUS AsUshort16: USHORT [ + CurrentConnectStatus set_CurrentConnectStatus[0..1], + PortEnabledDisabled set_PortEnabledDisabled[1..2], + Reserved0 set_Reserved0[2..3], + OverCurrent set_OverCurrent[3..4], + Reset set_Reset[4..5], + PortLinkState set_PortLinkState[5..9], + PortPower set_PortPower[9..10], + NegotiatedDeviceSpeed set_NegotiatedDeviceSpeed[10..13], + Reserved1 set_Reserved1[13..16], +]} +pub type PUSB_30_PORT_STATUS = *mut USB_30_PORT_STATUS; +pub const PORT_LINK_STATE_U0: USHORT = 0; +pub const PORT_LINK_STATE_U1: USHORT = 1; +pub const PORT_LINK_STATE_U2: USHORT = 2; +pub const PORT_LINK_STATE_U3: USHORT = 3; +pub const PORT_LINK_STATE_DISABLED: USHORT = 4; +pub const PORT_LINK_STATE_RX_DETECT: USHORT = 5; +pub const PORT_LINK_STATE_INACTIVE: USHORT = 6; +pub const PORT_LINK_STATE_POLLING: USHORT = 7; +pub const PORT_LINK_STATE_RECOVERY: USHORT = 8; +pub const PORT_LINK_STATE_HOT_RESET: USHORT = 9; +pub const PORT_LINK_STATE_COMPLIANCE_MODE: USHORT = 10; +pub const PORT_LINK_STATE_LOOPBACK: USHORT = 11; +pub const PORT_LINK_STATE_TEST_MODE: USHORT = 11; +STRUCT!{#[repr(packed)] struct USB_30_PORT_CHANGE { + AsUshort16: USHORT, +}} +BITFIELD!{USB_30_PORT_CHANGE AsUshort16: USHORT [ + ConnectStatusChange set_ConnectStatusChange[0..1], + Reserved2 set_Reserved2[1..3], + OverCurrentIndicatorChange set_OverCurrentIndicatorChange[3..4], + ResetChange set_ResetChange[4..5], + BHResetChange set_BHResetChange[5..6], + PortLinkStateChange set_PortLinkStateChange[6..7], + PortConfigErrorChange set_PortConfigErrorChange[7..8], + Reserved3 set_Reserved3[8..16], +]} +pub type PUSB_30_PORT_CHANGE = *mut USB_30_PORT_CHANGE; +UNION!{#[repr(packed)] union USB_PORT_STATUS { + [u16; 1], + AsUshort16 AsUshort16_mut: USHORT, + Usb20PortStatus Usb20PortStatus_mut: USB_20_PORT_STATUS, + Usb30PortStatus Usb30PortStatus_mut: USB_30_PORT_STATUS, +}} +pub type PUSB_PORT_STATUS = *mut USB_PORT_STATUS; +UNION!{#[repr(packed)] union USB_PORT_CHANGE { + [u16; 1], + AsUshort16 AsUshort16_mut: USHORT, + Usb20PortChange Usb20PortChange_mut: USB_20_PORT_CHANGE, + Usb30PortChange Usb30PortChange_mut: USB_30_PORT_CHANGE, +}} +pub type PUSB_PORT_CHANGE = *mut USB_PORT_CHANGE; +STRUCT!{#[repr(packed)] struct USB_PORT_EXT_STATUS { + AsUlong32: ULONG, +}} +BITFIELD!{USB_PORT_EXT_STATUS AsUlong32: ULONG [ + RxSublinkSpeedID set_RxSublinkSpeedID[0..4], + TxSublinkSpeedID set_TxSublinkSpeedID[4..8], + RxLaneCount set_RxLaneCount[8..12], + TxLaneCount set_TxLaneCount[12..16], + Reserved set_Reserved[16..32], +]} +pub type PUSB_PORT_EXT_STATUS = *mut USB_PORT_EXT_STATUS; +STRUCT!{#[repr(packed)] struct USB_PORT_STATUS_AND_CHANGE_s { + PortStatus: USB_PORT_STATUS, + PortChange: USB_PORT_CHANGE, +}} +UNION!{#[repr(packed)] union USB_PORT_STATUS_AND_CHANGE { + [u32; 1], + AsUlong32 AsUlong32_mut: ULONG, + s s_mut: USB_PORT_STATUS_AND_CHANGE_s, +}} +pub type PUSB_PORT_STATUS_AND_CHANGE = *mut USB_PORT_STATUS_AND_CHANGE; +STRUCT!{#[repr(packed)] struct USB_PORT_EXT_STATUS_AND_CHANGE_s { + PortStatusChange: USB_PORT_STATUS_AND_CHANGE, + PortExtStatus: USB_PORT_EXT_STATUS, +}} +UNION!{#[repr(packed)] union USB_PORT_EXT_STATUS_AND_CHANGE { + [u64; 1], + AsUlong64 AsUlong64_mut: ULONG64, + s s_mut: USB_PORT_EXT_STATUS_AND_CHANGE_s, +}} +pub type PUSB_PORT_EXT_STATUS_AND_CHANGE = *mut USB_PORT_EXT_STATUS_AND_CHANGE; +STRUCT!{#[repr(packed)] struct USB_HUB_30_PORT_REMOTE_WAKE_MASK { + AsUchar8: UCHAR, +}} +BITFIELD!{USB_HUB_30_PORT_REMOTE_WAKE_MASK AsUchar8: UCHAR [ + ConnectRemoteWakeEnable set_ConnectRemoteWakeEnable[0..1], + DisconnectRemoteWakeEnable set_DisconnectRemoteWakeEnable[1..2], + OverCurrentRemoteWakeEnable set_OverCurrentRemoteWakeEnable[2..3], + Reserved0 set_Reserved0[3..8], +]} +pub type PUSB_HUB_30_PORT_REMOTE_WAKE_MASK = *mut USB_HUB_30_PORT_REMOTE_WAKE_MASK; +STRUCT!{#[repr(packed)] struct USB_FUNCTION_SUSPEND_OPTIONS { + AsUchar: UCHAR, +}} +BITFIELD!{USB_FUNCTION_SUSPEND_OPTIONS AsUchar: UCHAR [ + PowerState set_PowerState[0..1], + RemoteWakeEnabled set_RemoteWakeEnabled[1..2], + Reserved0 set_Reserved0[2..8], +]} +pub type PUSB_FUNCTION_SUSPEND_OPTIONS = *mut USB_FUNCTION_SUSPEND_OPTIONS; +pub const USB_FEATURE_INTERFACE_POWER_D0: USHORT = 0x0002; +pub const USB_FEATURE_INTERFACE_POWER_D1: USHORT = 0x0003; +pub const USB_FEATURE_INTERFACE_POWER_D2: USHORT = 0x0004; +pub const USB_FEATURE_INTERFACE_POWER_D3: USHORT = 0x0005; +pub const USB_SUPPORT_D0_COMMAND: UCHAR = 0x01; +pub const USB_SUPPORT_D1_COMMAND: UCHAR = 0x02; +pub const USB_SUPPORT_D2_COMMAND: UCHAR = 0x04; +pub const USB_SUPPORT_D3_COMMAND: UCHAR = 0x08; +pub const USB_SUPPORT_D1_WAKEUP: UCHAR = 0x10; +pub const USB_SUPPORT_D2_WAKEUP: UCHAR = 0x20; +STRUCT!{#[repr(packed)] struct USB_CONFIGURATION_POWER_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + SelfPowerConsumedD0: [UCHAR; 3], + bPowerSummaryId: UCHAR, + bBusPowerSavingD1: UCHAR, + bSelfPowerSavingD1: UCHAR, + bBusPowerSavingD2: UCHAR, + bSelfPowerSavingD2: UCHAR, + bBusPowerSavingD3: UCHAR, + bSelfPowerSavingD3: UCHAR, + TransitionTimeFromD1: USHORT, + TransitionTimeFromD2: USHORT, + TransitionTimeFromD3: USHORT, +}} +pub type PUSB_CONFIGURATION_POWER_DESCRIPTOR = *mut USB_CONFIGURATION_POWER_DESCRIPTOR; +STRUCT!{#[repr(packed)] struct USB_INTERFACE_POWER_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bmCapabilitiesFlags: UCHAR, + bBusPowerSavingD1: UCHAR, + bSelfPowerSavingD1: UCHAR, + bBusPowerSavingD2: UCHAR, + bSelfPowerSavingD2: UCHAR, + bBusPowerSavingD3: UCHAR, + bSelfPowerSavingD3: UCHAR, + TransitionTimeFromD1: USHORT, + TransitionTimeFromD2: USHORT, + TransitionTimeFromD3: USHORT, +}} +pub type PUSB_INTERFACE_POWER_DESCRIPTOR = *mut USB_INTERFACE_POWER_DESCRIPTOR; diff --git a/winapi/src/shared/windef.rs b/winapi/src/shared/windef.rs new file mode 100644 index 000000000..d2e5fe01c --- /dev/null +++ b/winapi/src/shared/windef.rs @@ -0,0 +1,125 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Basic Windows Type Definitions +use ctypes::c_void; +use shared::minwindef::{DWORD, HFILE, WORD}; +use um::winnt::{LONG, SHORT}; +DECLARE_HANDLE!{HWND, HWND__} +DECLARE_HANDLE!{HHOOK, HHOOK__} +pub type HGDIOBJ = *mut c_void; +DECLARE_HANDLE!{HACCEL, HACCEL__} +DECLARE_HANDLE!{HBITMAP, HBITMAP__} +DECLARE_HANDLE!{HBRUSH, HBRUSH__} +DECLARE_HANDLE!{HCOLORSPACE, HCOLORSPACE__} +DECLARE_HANDLE!{HDC, HDC__} +DECLARE_HANDLE!{HGLRC, HGLRC__} +DECLARE_HANDLE!{HDESK, HDESK__} +DECLARE_HANDLE!{HENHMETAFILE, HENHMETAFILE__} +DECLARE_HANDLE!{HFONT, HFONT__} +DECLARE_HANDLE!{HICON, HICON__} +DECLARE_HANDLE!{HMENU, HMENU__} +DECLARE_HANDLE!{HPALETTE, HPALETTE__} +DECLARE_HANDLE!{HPEN, HPEN__} +DECLARE_HANDLE!{HWINEVENTHOOK, HWINEVENTHOOK__} +DECLARE_HANDLE!{HMONITOR, HMONITOR__} +DECLARE_HANDLE!{HUMPD, HUMPD__} +pub type HCURSOR = HICON; +pub type COLORREF = DWORD; +pub type LPCOLORREF = *mut DWORD; +pub const HFILE_ERROR: HFILE = -1; +STRUCT!{#[debug] struct RECT { + left: LONG, + top: LONG, + right: LONG, + bottom: LONG, +}} +pub type PRECT = *mut RECT; +pub type NPRECT = *mut RECT; +pub type LPRECT = *mut RECT; +pub type LPCRECT = *const RECT; +STRUCT!{#[debug] struct RECTL { + left: LONG, + top: LONG, + right: LONG, + bottom: LONG, +}} +pub type PRECTL = *mut RECTL; +pub type LPRECTL = *mut RECTL; +pub type LPCRECTL = *const RECTL; +STRUCT!{struct POINT { + x: LONG, + y: LONG, +}} +pub type PPOINT = *mut POINT; +pub type NPPOINT = *mut POINT; +pub type LPPOINT = *mut POINT; +STRUCT!{struct POINTL { + x: LONG, + y: LONG, +}} +pub type PPOINTL = *mut POINTL; +STRUCT!{struct SIZE { + cx: LONG, + cy: LONG, +}} +pub type PSIZE = *mut SIZE; +pub type LPSIZE = *mut SIZE; +pub type SIZEL = SIZE; +pub type PSIZEL = *mut SIZE; +pub type LPSIZEL = *mut SIZE; +STRUCT!{struct POINTS { + x: SHORT, + y: SHORT, +}} +pub type PPOINTS = *mut POINTS; +pub type LPPOINTS = *mut POINTS; +pub const DM_UPDATE: WORD = 1; +pub const DM_COPY: WORD = 2; +pub const DM_PROMPT: WORD = 4; +pub const DM_MODIFY: WORD = 8; +pub const DM_IN_BUFFER: WORD = DM_MODIFY; +pub const DM_IN_PROMPT: WORD = DM_PROMPT; +pub const DM_OUT_BUFFER: WORD = DM_COPY; +pub const DM_OUT_DEFAULT: WORD = DM_UPDATE; +pub const DC_FIELDS: DWORD = 1; +pub const DC_PAPERS: DWORD = 2; +pub const DC_PAPERSIZE: DWORD = 3; +pub const DC_MINEXTENT: DWORD = 4; +pub const DC_MAXEXTENT: DWORD = 5; +pub const DC_BINS: DWORD = 6; +pub const DC_DUPLEX: DWORD = 7; +pub const DC_SIZE: DWORD = 8; +pub const DC_EXTRA: DWORD = 9; +pub const DC_VERSION: DWORD = 10; +pub const DC_DRIVER: DWORD = 11; +pub const DC_BINNAMES: DWORD = 12; +pub const DC_ENUMRESOLUTIONS: DWORD = 13; +pub const DC_FILEDEPENDENCIES: DWORD = 14; +pub const DC_TRUETYPE: DWORD = 15; +pub const DC_PAPERNAMES: DWORD = 16; +pub const DC_ORIENTATION: DWORD = 17; +pub const DC_COPIES: DWORD = 18; +DECLARE_HANDLE!{DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT__} +ENUM!{enum DPI_AWARENESS { + DPI_AWARENESS_INVALID = -1i32 as u32, + DPI_AWARENESS_UNAWARE = 0, + DPI_AWARENESS_SYSTEM_AWARE = 1, + DPI_AWARENESS_PER_MONITOR_AWARE = 2, +}} +pub const DPI_AWARENESS_CONTEXT_UNAWARE: DPI_AWARENESS_CONTEXT = -1isize as DPI_AWARENESS_CONTEXT; +pub const DPI_AWARENESS_CONTEXT_SYSTEM_AWARE: DPI_AWARENESS_CONTEXT + = -2isize as DPI_AWARENESS_CONTEXT; +pub const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE: DPI_AWARENESS_CONTEXT + = -3isize as DPI_AWARENESS_CONTEXT; +pub const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT + = -4isize as DPI_AWARENESS_CONTEXT; +pub const DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED: DPI_AWARENESS_CONTEXT + = -5isize as DPI_AWARENESS_CONTEXT; +ENUM!{enum DPI_HOSTING_BEHAVIOR { + DPI_HOSTING_BEHAVIOR_INVALID = -1i32 as u32, + DPI_HOSTING_BEHAVIOR_DEFAULT = 0, + DPI_HOSTING_BEHAVIOR_MIXED = 1, +}} diff --git a/winapi/src/shared/windowsx.rs b/winapi/src/shared/windowsx.rs new file mode 100644 index 000000000..4147aa353 --- /dev/null +++ b/winapi/src/shared/windowsx.rs @@ -0,0 +1,17 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Macro APIs, window message crackers, and control APIs +use ctypes::{c_int, c_short}; +use shared::minwindef::{DWORD, HIWORD, LOWORD, LPARAM}; +//1233 +#[inline] +pub fn GET_X_LPARAM(lp: LPARAM) -> c_int { + LOWORD(lp as DWORD) as c_short as c_int +} +#[inline] +pub fn GET_Y_LPARAM(lp: LPARAM) -> c_int { + HIWORD(lp as DWORD) as c_short as c_int +} diff --git a/winapi/src/shared/winerror.rs b/winapi/src/shared/winerror.rs new file mode 100644 index 000000000..378a31a4b --- /dev/null +++ b/winapi/src/shared/winerror.rs @@ -0,0 +1,6149 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! error code definitions for the Win32 API functions +use ctypes::{c_long, c_ulong}; +use shared::minwindef::DWORD; +use shared::wtypesbase::SCODE; +pub const FACILITY_XPS: HRESULT = 82; +pub const FACILITY_XAML: HRESULT = 43; +pub const FACILITY_USN: HRESULT = 129; +pub const FACILITY_BLBUI: HRESULT = 128; +pub const FACILITY_SPP: HRESULT = 256; +pub const FACILITY_WSB_ONLINE: HRESULT = 133; +pub const FACILITY_DLS: HRESULT = 153; +pub const FACILITY_BLB_CLI: HRESULT = 121; +pub const FACILITY_BLB: HRESULT = 120; +pub const FACILITY_WSBAPP: HRESULT = 122; +pub const FACILITY_WPN: HRESULT = 62; +pub const FACILITY_WMAAECMA: HRESULT = 1996; +pub const FACILITY_WINRM: HRESULT = 51; +pub const FACILITY_WINPE: HRESULT = 61; +pub const FACILITY_WINDOWSUPDATE: HRESULT = 36; +pub const FACILITY_WINDOWS_STORE: HRESULT = 63; +pub const FACILITY_WINDOWS_SETUP: HRESULT = 48; +pub const FACILITY_WINDOWS_DEFENDER: HRESULT = 80; +pub const FACILITY_WINDOWS_CE: HRESULT = 24; +pub const FACILITY_WINDOWS: HRESULT = 8; +pub const FACILITY_WINCODEC_DWRITE_DWM: HRESULT = 2200; +pub const FACILITY_WIA: HRESULT = 33; +pub const FACILITY_WER: HRESULT = 27; +pub const FACILITY_WEP: HRESULT = 2049; +pub const FACILITY_WEB_SOCKET: HRESULT = 886; +pub const FACILITY_WEB: HRESULT = 885; +pub const FACILITY_USERMODE_VOLSNAP: HRESULT = 130; +pub const FACILITY_USERMODE_VOLMGR: HRESULT = 56; +pub const FACILITY_VISUALCPP: HRESULT = 109; +pub const FACILITY_USERMODE_VIRTUALIZATION: HRESULT = 55; +pub const FACILITY_USERMODE_VHD: HRESULT = 58; +pub const FACILITY_URT: HRESULT = 19; +pub const FACILITY_UMI: HRESULT = 22; +pub const FACILITY_UI: HRESULT = 42; +pub const FACILITY_TPM_SOFTWARE: HRESULT = 41; +pub const FACILITY_TPM_SERVICES: HRESULT = 40; +pub const FACILITY_TIERING: HRESULT = 131; +pub const FACILITY_SYNCENGINE: HRESULT = 2050; +pub const FACILITY_SXS: HRESULT = 23; +pub const FACILITY_STORAGE: HRESULT = 3; +pub const FACILITY_STATE_MANAGEMENT: HRESULT = 34; +pub const FACILITY_SSPI: HRESULT = 9; +pub const FACILITY_USERMODE_SPACES: HRESULT = 231; +pub const FACILITY_SOS: HRESULT = 160; +pub const FACILITY_SCARD: HRESULT = 16; +pub const FACILITY_SHELL: HRESULT = 39; +pub const FACILITY_SETUPAPI: HRESULT = 15; +pub const FACILITY_SECURITY: HRESULT = 9; +pub const FACILITY_SDIAG: HRESULT = 60; +pub const FACILITY_USERMODE_SDBUS: HRESULT = 2305; +pub const FACILITY_RPC: HRESULT = 1; +pub const FACILITY_RESTORE: HRESULT = 256; +pub const FACILITY_SCRIPT: HRESULT = 112; +pub const FACILITY_PARSE: HRESULT = 113; +pub const FACILITY_RAS: HRESULT = 83; +pub const FACILITY_POWERSHELL: HRESULT = 84; +pub const FACILITY_PLA: HRESULT = 48; +pub const FACILITY_PIDGENX: HRESULT = 2561; +pub const FACILITY_P2P_INT: HRESULT = 98; +pub const FACILITY_P2P: HRESULT = 99; +pub const FACILITY_OPC: HRESULT = 81; +pub const FACILITY_ONLINE_ID: HRESULT = 134; +pub const FACILITY_WIN32: HRESULT = 7; +pub const FACILITY_CONTROL: HRESULT = 10; +pub const FACILITY_WEBSERVICES: HRESULT = 61; +pub const FACILITY_NULL: HRESULT = 0; +pub const FACILITY_NDIS: HRESULT = 52; +pub const FACILITY_NAP: HRESULT = 39; +pub const FACILITY_MOBILE: HRESULT = 1793; +pub const FACILITY_METADIRECTORY: HRESULT = 35; +pub const FACILITY_MSMQ: HRESULT = 14; +pub const FACILITY_MEDIASERVER: HRESULT = 13; +pub const FACILITY_MBN: HRESULT = 84; +pub const FACILITY_LINGUISTIC_SERVICES: HRESULT = 305; +pub const FACILITY_LEAP: HRESULT = 2184; +pub const FACILITY_JSCRIPT: HRESULT = 2306; +pub const FACILITY_INTERNET: HRESULT = 12; +pub const FACILITY_ITF: HRESULT = 4; +pub const FACILITY_INPUT: HRESULT = 64; +pub const FACILITY_USERMODE_HYPERVISOR: HRESULT = 53; +pub const FACILITY_ACCELERATOR: HRESULT = 1536; +pub const FACILITY_HTTP: HRESULT = 25; +pub const FACILITY_GRAPHICS: HRESULT = 38; +pub const FACILITY_FWP: HRESULT = 50; +pub const FACILITY_FVE: HRESULT = 49; +pub const FACILITY_USERMODE_FILTER_MANAGER: HRESULT = 31; +pub const FACILITY_EAS: HRESULT = 85; +pub const FACILITY_EAP: HRESULT = 66; +pub const FACILITY_DXGI_DDI: HRESULT = 2171; +pub const FACILITY_DXGI: HRESULT = 2170; +pub const FACILITY_DPLAY: HRESULT = 21; +pub const FACILITY_DMSERVER: HRESULT = 256; +pub const FACILITY_DISPATCH: HRESULT = 2; +pub const FACILITY_DIRECTORYSERVICE: HRESULT = 37; +pub const FACILITY_DIRECTMUSIC: HRESULT = 2168; +pub const FACILITY_DIRECT3D11: HRESULT = 2172; +pub const FACILITY_DIRECT3D10: HRESULT = 2169; +pub const FACILITY_DIRECT2D: HRESULT = 2201; +pub const FACILITY_DAF: HRESULT = 100; +pub const FACILITY_DEPLOYMENT_SERVICES_UTIL: HRESULT = 260; +pub const FACILITY_DEPLOYMENT_SERVICES_TRANSPORT_MANAGEMENT: HRESULT = 272; +pub const FACILITY_DEPLOYMENT_SERVICES_TFTP: HRESULT = 264; +pub const FACILITY_DEPLOYMENT_SERVICES_PXE: HRESULT = 263; +pub const FACILITY_DEPLOYMENT_SERVICES_MULTICAST_SERVER: HRESULT = 289; +pub const FACILITY_DEPLOYMENT_SERVICES_MULTICAST_CLIENT: HRESULT = 290; +pub const FACILITY_DEPLOYMENT_SERVICES_MANAGEMENT: HRESULT = 259; +pub const FACILITY_DEPLOYMENT_SERVICES_IMAGING: HRESULT = 258; +pub const FACILITY_DEPLOYMENT_SERVICES_DRIVER_PROVISIONING: HRESULT = 278; +pub const FACILITY_DEPLOYMENT_SERVICES_SERVER: HRESULT = 257; +pub const FACILITY_DEPLOYMENT_SERVICES_CONTENT_PROVIDER: HRESULT = 293; +pub const FACILITY_DEPLOYMENT_SERVICES_BINLSVC: HRESULT = 261; +pub const FACILITY_DEFRAG: HRESULT = 2304; +pub const FACILITY_DEBUGGERS: HRESULT = 176; +pub const FACILITY_CONFIGURATION: HRESULT = 33; +pub const FACILITY_COMPLUS: HRESULT = 17; +pub const FACILITY_USERMODE_COMMONLOG: HRESULT = 26; +pub const FACILITY_CMI: HRESULT = 54; +pub const FACILITY_CERT: HRESULT = 11; +pub const FACILITY_BLUETOOTH_ATT: HRESULT = 101; +pub const FACILITY_BCD: HRESULT = 57; +pub const FACILITY_BACKGROUNDCOPY: HRESULT = 32; +pub const FACILITY_AUDIOSTREAMING: HRESULT = 1094; +pub const FACILITY_AUDCLNT: HRESULT = 2185; +pub const FACILITY_AUDIO: HRESULT = 102; +pub const FACILITY_ACTION_QUEUE: HRESULT = 44; +pub const FACILITY_ACS: HRESULT = 20; +pub const FACILITY_AAF: HRESULT = 18; +pub const ERROR_SUCCESS: DWORD = 0; +pub const NO_ERROR: DWORD = 0; +pub const SEC_E_OK: HRESULT = 0; +pub const ERROR_INVALID_FUNCTION: DWORD = 1; +pub const ERROR_FILE_NOT_FOUND: DWORD = 2; +pub const ERROR_PATH_NOT_FOUND: DWORD = 3; +pub const ERROR_TOO_MANY_OPEN_FILES: DWORD = 4; +pub const ERROR_ACCESS_DENIED: DWORD = 5; +pub const ERROR_INVALID_HANDLE: DWORD = 6; +pub const ERROR_ARENA_TRASHED: DWORD = 7; +pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; +pub const ERROR_INVALID_BLOCK: DWORD = 9; +pub const ERROR_BAD_ENVIRONMENT: DWORD = 10; +pub const ERROR_BAD_FORMAT: DWORD = 11; +pub const ERROR_INVALID_ACCESS: DWORD = 12; +pub const ERROR_INVALID_DATA: DWORD = 13; +pub const ERROR_OUTOFMEMORY: DWORD = 14; +pub const ERROR_INVALID_DRIVE: DWORD = 15; +pub const ERROR_CURRENT_DIRECTORY: DWORD = 16; +pub const ERROR_NOT_SAME_DEVICE: DWORD = 17; +pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_WRITE_PROTECT: DWORD = 19; +pub const ERROR_BAD_UNIT: DWORD = 20; +pub const ERROR_NOT_READY: DWORD = 21; +pub const ERROR_BAD_COMMAND: DWORD = 22; +pub const ERROR_CRC: DWORD = 23; +pub const ERROR_BAD_LENGTH: DWORD = 24; +pub const ERROR_SEEK: DWORD = 25; +pub const ERROR_NOT_DOS_DISK: DWORD = 26; +pub const ERROR_SECTOR_NOT_FOUND: DWORD = 27; +pub const ERROR_OUT_OF_PAPER: DWORD = 28; +pub const ERROR_WRITE_FAULT: DWORD = 29; +pub const ERROR_READ_FAULT: DWORD = 30; +pub const ERROR_GEN_FAILURE: DWORD = 31; +pub const ERROR_SHARING_VIOLATION: DWORD = 32; +pub const ERROR_LOCK_VIOLATION: DWORD = 33; +pub const ERROR_WRONG_DISK: DWORD = 34; +pub const ERROR_SHARING_BUFFER_EXCEEDED: DWORD = 36; +pub const ERROR_HANDLE_EOF: DWORD = 38; +pub const ERROR_HANDLE_DISK_FULL: DWORD = 39; +pub const ERROR_NOT_SUPPORTED: DWORD = 50; +pub const ERROR_REM_NOT_LIST: DWORD = 51; +pub const ERROR_DUP_NAME: DWORD = 52; +pub const ERROR_BAD_NETPATH: DWORD = 53; +pub const ERROR_NETWORK_BUSY: DWORD = 54; +pub const ERROR_DEV_NOT_EXIST: DWORD = 55; +pub const ERROR_TOO_MANY_CMDS: DWORD = 56; +pub const ERROR_ADAP_HDW_ERR: DWORD = 57; +pub const ERROR_BAD_NET_RESP: DWORD = 58; +pub const ERROR_UNEXP_NET_ERR: DWORD = 59; +pub const ERROR_BAD_REM_ADAP: DWORD = 60; +pub const ERROR_PRINTQ_FULL: DWORD = 61; +pub const ERROR_NO_SPOOL_SPACE: DWORD = 62; +pub const ERROR_PRINT_CANCELLED: DWORD = 63; +pub const ERROR_NETNAME_DELETED: DWORD = 64; +pub const ERROR_NETWORK_ACCESS_DENIED: DWORD = 65; +pub const ERROR_BAD_DEV_TYPE: DWORD = 66; +pub const ERROR_BAD_NET_NAME: DWORD = 67; +pub const ERROR_TOO_MANY_NAMES: DWORD = 68; +pub const ERROR_TOO_MANY_SESS: DWORD = 69; +pub const ERROR_SHARING_PAUSED: DWORD = 70; +pub const ERROR_REQ_NOT_ACCEP: DWORD = 71; +pub const ERROR_REDIR_PAUSED: DWORD = 72; +pub const ERROR_FILE_EXISTS: DWORD = 80; +pub const ERROR_CANNOT_MAKE: DWORD = 82; +pub const ERROR_FAIL_I24: DWORD = 83; +pub const ERROR_OUT_OF_STRUCTURES: DWORD = 84; +pub const ERROR_ALREADY_ASSIGNED: DWORD = 85; +pub const ERROR_INVALID_PASSWORD: DWORD = 86; +pub const ERROR_INVALID_PARAMETER: DWORD = 87; +pub const ERROR_NET_WRITE_FAULT: DWORD = 88; +pub const ERROR_NO_PROC_SLOTS: DWORD = 89; +pub const ERROR_TOO_MANY_SEMAPHORES: DWORD = 100; +pub const ERROR_EXCL_SEM_ALREADY_OWNED: DWORD = 101; +pub const ERROR_SEM_IS_SET: DWORD = 102; +pub const ERROR_TOO_MANY_SEM_REQUESTS: DWORD = 103; +pub const ERROR_INVALID_AT_INTERRUPT_TIME: DWORD = 104; +pub const ERROR_SEM_OWNER_DIED: DWORD = 105; +pub const ERROR_SEM_USER_LIMIT: DWORD = 106; +pub const ERROR_DISK_CHANGE: DWORD = 107; +pub const ERROR_DRIVE_LOCKED: DWORD = 108; +pub const ERROR_BROKEN_PIPE: DWORD = 109; +pub const ERROR_OPEN_FAILED: DWORD = 110; +pub const ERROR_BUFFER_OVERFLOW: DWORD = 111; +pub const ERROR_DISK_FULL: DWORD = 112; +pub const ERROR_NO_MORE_SEARCH_HANDLES: DWORD = 113; +pub const ERROR_INVALID_TARGET_HANDLE: DWORD = 114; +pub const ERROR_INVALID_CATEGORY: DWORD = 117; +pub const ERROR_INVALID_VERIFY_SWITCH: DWORD = 118; +pub const ERROR_BAD_DRIVER_LEVEL: DWORD = 119; +pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; +pub const ERROR_SEM_TIMEOUT: DWORD = 121; +pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; +pub const ERROR_INVALID_NAME: DWORD = 123; +pub const ERROR_INVALID_LEVEL: DWORD = 124; +pub const ERROR_NO_VOLUME_LABEL: DWORD = 125; +pub const ERROR_MOD_NOT_FOUND: DWORD = 126; +pub const ERROR_PROC_NOT_FOUND: DWORD = 127; +pub const ERROR_WAIT_NO_CHILDREN: DWORD = 128; +pub const ERROR_CHILD_NOT_COMPLETE: DWORD = 129; +pub const ERROR_DIRECT_ACCESS_HANDLE: DWORD = 130; +pub const ERROR_NEGATIVE_SEEK: DWORD = 131; +pub const ERROR_SEEK_ON_DEVICE: DWORD = 132; +pub const ERROR_IS_JOIN_TARGET: DWORD = 133; +pub const ERROR_IS_JOINED: DWORD = 134; +pub const ERROR_IS_SUBSTED: DWORD = 135; +pub const ERROR_NOT_JOINED: DWORD = 136; +pub const ERROR_NOT_SUBSTED: DWORD = 137; +pub const ERROR_JOIN_TO_JOIN: DWORD = 138; +pub const ERROR_SUBST_TO_SUBST: DWORD = 139; +pub const ERROR_JOIN_TO_SUBST: DWORD = 140; +pub const ERROR_SUBST_TO_JOIN: DWORD = 141; +pub const ERROR_BUSY_DRIVE: DWORD = 142; +pub const ERROR_SAME_DRIVE: DWORD = 143; +pub const ERROR_DIR_NOT_ROOT: DWORD = 144; +pub const ERROR_DIR_NOT_EMPTY: DWORD = 145; +pub const ERROR_IS_SUBST_PATH: DWORD = 146; +pub const ERROR_IS_JOIN_PATH: DWORD = 147; +pub const ERROR_PATH_BUSY: DWORD = 148; +pub const ERROR_IS_SUBST_TARGET: DWORD = 149; +pub const ERROR_SYSTEM_TRACE: DWORD = 150; +pub const ERROR_INVALID_EVENT_COUNT: DWORD = 151; +pub const ERROR_TOO_MANY_MUXWAITERS: DWORD = 152; +pub const ERROR_INVALID_LIST_FORMAT: DWORD = 153; +pub const ERROR_LABEL_TOO_LONG: DWORD = 154; +pub const ERROR_TOO_MANY_TCBS: DWORD = 155; +pub const ERROR_SIGNAL_REFUSED: DWORD = 156; +pub const ERROR_DISCARDED: DWORD = 157; +pub const ERROR_NOT_LOCKED: DWORD = 158; +pub const ERROR_BAD_THREADID_ADDR: DWORD = 159; +pub const ERROR_BAD_ARGUMENTS: DWORD = 160; +pub const ERROR_BAD_PATHNAME: DWORD = 161; +pub const ERROR_SIGNAL_PENDING: DWORD = 162; +pub const ERROR_MAX_THRDS_REACHED: DWORD = 164; +pub const ERROR_LOCK_FAILED: DWORD = 167; +pub const ERROR_BUSY: DWORD = 170; +pub const ERROR_DEVICE_SUPPORT_IN_PROGRESS: DWORD = 171; +pub const ERROR_CANCEL_VIOLATION: DWORD = 173; +pub const ERROR_ATOMIC_LOCKS_NOT_SUPPORTED: DWORD = 174; +pub const ERROR_INVALID_SEGMENT_NUMBER: DWORD = 180; +pub const ERROR_INVALID_ORDINAL: DWORD = 182; +pub const ERROR_ALREADY_EXISTS: DWORD = 183; +pub const ERROR_INVALID_FLAG_NUMBER: DWORD = 186; +pub const ERROR_SEM_NOT_FOUND: DWORD = 187; +pub const ERROR_INVALID_STARTING_CODESEG: DWORD = 188; +pub const ERROR_INVALID_STACKSEG: DWORD = 189; +pub const ERROR_INVALID_MODULETYPE: DWORD = 190; +pub const ERROR_INVALID_EXE_SIGNATURE: DWORD = 191; +pub const ERROR_EXE_MARKED_INVALID: DWORD = 192; +pub const ERROR_BAD_EXE_FORMAT: DWORD = 193; +pub const ERROR_ITERATED_DATA_EXCEEDS_64k: DWORD = 194; +pub const ERROR_INVALID_MINALLOCSIZE: DWORD = 195; +pub const ERROR_DYNLINK_FROM_INVALID_RING: DWORD = 196; +pub const ERROR_IOPL_NOT_ENABLED: DWORD = 197; +pub const ERROR_INVALID_SEGDPL: DWORD = 198; +pub const ERROR_AUTODATASEG_EXCEEDS_64k: DWORD = 199; +pub const ERROR_RING2SEG_MUST_BE_MOVABLE: DWORD = 200; +pub const ERROR_RELOC_CHAIN_XEEDS_SEGLIM: DWORD = 201; +pub const ERROR_INFLOOP_IN_RELOC_CHAIN: DWORD = 202; +pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; +pub const ERROR_NO_SIGNAL_SENT: DWORD = 205; +pub const ERROR_FILENAME_EXCED_RANGE: DWORD = 206; +pub const ERROR_RING2_STACK_IN_USE: DWORD = 207; +pub const ERROR_META_EXPANSION_TOO_LONG: DWORD = 208; +pub const ERROR_INVALID_SIGNAL_NUMBER: DWORD = 209; +pub const ERROR_THREAD_1_INACTIVE: DWORD = 210; +pub const ERROR_LOCKED: DWORD = 212; +pub const ERROR_TOO_MANY_MODULES: DWORD = 214; +pub const ERROR_NESTING_NOT_ALLOWED: DWORD = 215; +pub const ERROR_EXE_MACHINE_TYPE_MISMATCH: DWORD = 216; +pub const ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY: DWORD = 217; +pub const ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY: DWORD = 218; +pub const ERROR_FILE_CHECKED_OUT: DWORD = 220; +pub const ERROR_CHECKOUT_REQUIRED: DWORD = 221; +pub const ERROR_BAD_FILE_TYPE: DWORD = 222; +pub const ERROR_FILE_TOO_LARGE: DWORD = 223; +pub const ERROR_FORMS_AUTH_REQUIRED: DWORD = 224; +pub const ERROR_VIRUS_INFECTED: DWORD = 225; +pub const ERROR_VIRUS_DELETED: DWORD = 226; +pub const ERROR_PIPE_LOCAL: DWORD = 229; +pub const ERROR_BAD_PIPE: DWORD = 230; +pub const ERROR_PIPE_BUSY: DWORD = 231; +pub const ERROR_NO_DATA: DWORD = 232; +pub const ERROR_PIPE_NOT_CONNECTED: DWORD = 233; +pub const ERROR_MORE_DATA: DWORD = 234; +pub const ERROR_VC_DISCONNECTED: DWORD = 240; +pub const ERROR_INVALID_EA_NAME: DWORD = 254; +pub const ERROR_EA_LIST_INCONSISTENT: DWORD = 255; +pub const WAIT_TIMEOUT: DWORD = 258; +pub const ERROR_NO_MORE_ITEMS: DWORD = 259; +pub const ERROR_CANNOT_COPY: DWORD = 266; +pub const ERROR_DIRECTORY: DWORD = 267; +pub const ERROR_EAS_DIDNT_FIT: DWORD = 275; +pub const ERROR_EA_FILE_CORRUPT: DWORD = 276; +pub const ERROR_EA_TABLE_FULL: DWORD = 277; +pub const ERROR_INVALID_EA_HANDLE: DWORD = 278; +pub const ERROR_EAS_NOT_SUPPORTED: DWORD = 282; +pub const ERROR_NOT_OWNER: DWORD = 288; +pub const ERROR_TOO_MANY_POSTS: DWORD = 298; +pub const ERROR_PARTIAL_COPY: DWORD = 299; +pub const ERROR_OPLOCK_NOT_GRANTED: DWORD = 300; +pub const ERROR_INVALID_OPLOCK_PROTOCOL: DWORD = 301; +pub const ERROR_DISK_TOO_FRAGMENTED: DWORD = 302; +pub const ERROR_DELETE_PENDING: DWORD = 303; +pub const ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING: DWORD = 304; +pub const ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME: DWORD = 305; +pub const ERROR_SECURITY_STREAM_IS_INCONSISTENT: DWORD = 306; +pub const ERROR_INVALID_LOCK_RANGE: DWORD = 307; +pub const ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT: DWORD = 308; +pub const ERROR_NOTIFICATION_GUID_ALREADY_DEFINED: DWORD = 309; +pub const ERROR_INVALID_EXCEPTION_HANDLER: DWORD = 310; +pub const ERROR_DUPLICATE_PRIVILEGES: DWORD = 311; +pub const ERROR_NO_RANGES_PROCESSED: DWORD = 312; +pub const ERROR_NOT_ALLOWED_ON_SYSTEM_FILE: DWORD = 313; +pub const ERROR_DISK_RESOURCES_EXHAUSTED: DWORD = 314; +pub const ERROR_INVALID_TOKEN: DWORD = 315; +pub const ERROR_DEVICE_FEATURE_NOT_SUPPORTED: DWORD = 316; +pub const ERROR_MR_MID_NOT_FOUND: DWORD = 317; +pub const ERROR_SCOPE_NOT_FOUND: DWORD = 318; +pub const ERROR_UNDEFINED_SCOPE: DWORD = 319; +pub const ERROR_INVALID_CAP: DWORD = 320; +pub const ERROR_DEVICE_UNREACHABLE: DWORD = 321; +pub const ERROR_DEVICE_NO_RESOURCES: DWORD = 322; +pub const ERROR_DATA_CHECKSUM_ERROR: DWORD = 323; +pub const ERROR_INTERMIXED_KERNEL_EA_OPERATION: DWORD = 324; +pub const ERROR_FILE_LEVEL_TRIM_NOT_SUPPORTED: DWORD = 326; +pub const ERROR_OFFSET_ALIGNMENT_VIOLATION: DWORD = 327; +pub const ERROR_INVALID_FIELD_IN_PARAMETER_LIST: DWORD = 328; +pub const ERROR_OPERATION_IN_PROGRESS: DWORD = 329; +pub const ERROR_BAD_DEVICE_PATH: DWORD = 330; +pub const ERROR_TOO_MANY_DESCRIPTORS: DWORD = 331; +pub const ERROR_SCRUB_DATA_DISABLED: DWORD = 332; +pub const ERROR_NOT_REDUNDANT_STORAGE: DWORD = 333; +pub const ERROR_RESIDENT_FILE_NOT_SUPPORTED: DWORD = 334; +pub const ERROR_COMPRESSED_FILE_NOT_SUPPORTED: DWORD = 335; +pub const ERROR_DIRECTORY_NOT_SUPPORTED: DWORD = 336; +pub const ERROR_NOT_READ_FROM_COPY: DWORD = 337; +pub const ERROR_FT_WRITE_FAILURE: DWORD = 338; +pub const ERROR_FT_DI_SCAN_REQUIRED: DWORD = 339; +pub const ERROR_INVALID_KERNEL_INFO_VERSION: DWORD = 340; +pub const ERROR_INVALID_PEP_INFO_VERSION: DWORD = 341; +pub const ERROR_OBJECT_NOT_EXTERNALLY_BACKED: DWORD = 342; +pub const ERROR_EXTERNAL_BACKING_PROVIDER_UNKNOWN: DWORD = 343; +pub const ERROR_FAIL_NOACTION_REBOOT: DWORD = 350; +pub const ERROR_FAIL_SHUTDOWN: DWORD = 351; +pub const ERROR_FAIL_RESTART: DWORD = 352; +pub const ERROR_MAX_SESSIONS_REACHED: DWORD = 353; +pub const ERROR_THREAD_MODE_ALREADY_BACKGROUND: DWORD = 400; +pub const ERROR_THREAD_MODE_NOT_BACKGROUND: DWORD = 401; +pub const ERROR_PROCESS_MODE_ALREADY_BACKGROUND: DWORD = 402; +pub const ERROR_PROCESS_MODE_NOT_BACKGROUND: DWORD = 403; +pub const ERROR_DEVICE_HARDWARE_ERROR: DWORD = 483; +pub const ERROR_INVALID_ADDRESS: DWORD = 487; +pub const ERROR_USER_PROFILE_LOAD: DWORD = 500; +pub const ERROR_ARITHMETIC_OVERFLOW: DWORD = 534; +pub const ERROR_PIPE_CONNECTED: DWORD = 535; +pub const ERROR_PIPE_LISTENING: DWORD = 536; +pub const ERROR_VERIFIER_STOP: DWORD = 537; +pub const ERROR_ABIOS_ERROR: DWORD = 538; +pub const ERROR_WX86_WARNING: DWORD = 539; +pub const ERROR_WX86_ERROR: DWORD = 540; +pub const ERROR_TIMER_NOT_CANCELED: DWORD = 541; +pub const ERROR_UNWIND: DWORD = 542; +pub const ERROR_BAD_STACK: DWORD = 543; +pub const ERROR_INVALID_UNWIND_TARGET: DWORD = 544; +pub const ERROR_INVALID_PORT_ATTRIBUTES: DWORD = 545; +pub const ERROR_PORT_MESSAGE_TOO_LONG: DWORD = 546; +pub const ERROR_INVALID_QUOTA_LOWER: DWORD = 547; +pub const ERROR_DEVICE_ALREADY_ATTACHED: DWORD = 548; +pub const ERROR_INSTRUCTION_MISALIGNMENT: DWORD = 549; +pub const ERROR_PROFILING_NOT_STARTED: DWORD = 550; +pub const ERROR_PROFILING_NOT_STOPPED: DWORD = 551; +pub const ERROR_COULD_NOT_INTERPRET: DWORD = 552; +pub const ERROR_PROFILING_AT_LIMIT: DWORD = 553; +pub const ERROR_CANT_WAIT: DWORD = 554; +pub const ERROR_CANT_TERMINATE_SELF: DWORD = 555; +pub const ERROR_UNEXPECTED_MM_CREATE_ERR: DWORD = 556; +pub const ERROR_UNEXPECTED_MM_MAP_ERROR: DWORD = 557; +pub const ERROR_UNEXPECTED_MM_EXTEND_ERR: DWORD = 558; +pub const ERROR_BAD_FUNCTION_TABLE: DWORD = 559; +pub const ERROR_NO_GUID_TRANSLATION: DWORD = 560; +pub const ERROR_INVALID_LDT_SIZE: DWORD = 561; +pub const ERROR_INVALID_LDT_OFFSET: DWORD = 563; +pub const ERROR_INVALID_LDT_DESCRIPTOR: DWORD = 564; +pub const ERROR_TOO_MANY_THREADS: DWORD = 565; +pub const ERROR_THREAD_NOT_IN_PROCESS: DWORD = 566; +pub const ERROR_PAGEFILE_QUOTA_EXCEEDED: DWORD = 567; +pub const ERROR_LOGON_SERVER_CONFLICT: DWORD = 568; +pub const ERROR_SYNCHRONIZATION_REQUIRED: DWORD = 569; +pub const ERROR_NET_OPEN_FAILED: DWORD = 570; +pub const ERROR_IO_PRIVILEGE_FAILED: DWORD = 571; +pub const ERROR_CONTROL_C_EXIT: DWORD = 572; +pub const ERROR_MISSING_SYSTEMFILE: DWORD = 573; +pub const ERROR_UNHANDLED_EXCEPTION: DWORD = 574; +pub const ERROR_APP_INIT_FAILURE: DWORD = 575; +pub const ERROR_PAGEFILE_CREATE_FAILED: DWORD = 576; +pub const ERROR_INVALID_IMAGE_HASH: DWORD = 577; +pub const ERROR_NO_PAGEFILE: DWORD = 578; +pub const ERROR_ILLEGAL_FLOAT_CONTEXT: DWORD = 579; +pub const ERROR_NO_EVENT_PAIR: DWORD = 580; +pub const ERROR_DOMAIN_CTRLR_CONFIG_ERROR: DWORD = 581; +pub const ERROR_ILLEGAL_CHARACTER: DWORD = 582; +pub const ERROR_UNDEFINED_CHARACTER: DWORD = 583; +pub const ERROR_FLOPPY_VOLUME: DWORD = 584; +pub const ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT: DWORD = 585; +pub const ERROR_BACKUP_CONTROLLER: DWORD = 586; +pub const ERROR_MUTANT_LIMIT_EXCEEDED: DWORD = 587; +pub const ERROR_FS_DRIVER_REQUIRED: DWORD = 588; +pub const ERROR_CANNOT_LOAD_REGISTRY_FILE: DWORD = 589; +pub const ERROR_DEBUG_ATTACH_FAILED: DWORD = 590; +pub const ERROR_SYSTEM_PROCESS_TERMINATED: DWORD = 591; +pub const ERROR_DATA_NOT_ACCEPTED: DWORD = 592; +pub const ERROR_VDM_HARD_ERROR: DWORD = 593; +pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; +pub const ERROR_REPLY_MESSAGE_MISMATCH: DWORD = 595; +pub const ERROR_LOST_WRITEBEHIND_DATA: DWORD = 596; +pub const ERROR_CLIENT_SERVER_PARAMETERS_INVALID: DWORD = 597; +pub const ERROR_NOT_TINY_STREAM: DWORD = 598; +pub const ERROR_STACK_OVERFLOW_READ: DWORD = 599; +pub const ERROR_CONVERT_TO_LARGE: DWORD = 600; +pub const ERROR_FOUND_OUT_OF_SCOPE: DWORD = 601; +pub const ERROR_ALLOCATE_BUCKET: DWORD = 602; +pub const ERROR_MARSHALL_OVERFLOW: DWORD = 603; +pub const ERROR_INVALID_VARIANT: DWORD = 604; +pub const ERROR_BAD_COMPRESSION_BUFFER: DWORD = 605; +pub const ERROR_AUDIT_FAILED: DWORD = 606; +pub const ERROR_TIMER_RESOLUTION_NOT_SET: DWORD = 607; +pub const ERROR_INSUFFICIENT_LOGON_INFO: DWORD = 608; +pub const ERROR_BAD_DLL_ENTRYPOINT: DWORD = 609; +pub const ERROR_BAD_SERVICE_ENTRYPOINT: DWORD = 610; +pub const ERROR_IP_ADDRESS_CONFLICT1: DWORD = 611; +pub const ERROR_IP_ADDRESS_CONFLICT2: DWORD = 612; +pub const ERROR_REGISTRY_QUOTA_LIMIT: DWORD = 613; +pub const ERROR_NO_CALLBACK_ACTIVE: DWORD = 614; +pub const ERROR_PWD_TOO_SHORT: DWORD = 615; +pub const ERROR_PWD_TOO_RECENT: DWORD = 616; +pub const ERROR_PWD_HISTORY_CONFLICT: DWORD = 617; +pub const ERROR_UNSUPPORTED_COMPRESSION: DWORD = 618; +pub const ERROR_INVALID_HW_PROFILE: DWORD = 619; +pub const ERROR_INVALID_PLUGPLAY_DEVICE_PATH: DWORD = 620; +pub const ERROR_QUOTA_LIST_INCONSISTENT: DWORD = 621; +pub const ERROR_EVALUATION_EXPIRATION: DWORD = 622; +pub const ERROR_ILLEGAL_DLL_RELOCATION: DWORD = 623; +pub const ERROR_DLL_INIT_FAILED_LOGOFF: DWORD = 624; +pub const ERROR_VALIDATE_CONTINUE: DWORD = 625; +pub const ERROR_NO_MORE_MATCHES: DWORD = 626; +pub const ERROR_RANGE_LIST_CONFLICT: DWORD = 627; +pub const ERROR_SERVER_SID_MISMATCH: DWORD = 628; +pub const ERROR_CANT_ENABLE_DENY_ONLY: DWORD = 629; +pub const ERROR_FLOAT_MULTIPLE_FAULTS: DWORD = 630; +pub const ERROR_FLOAT_MULTIPLE_TRAPS: DWORD = 631; +pub const ERROR_NOINTERFACE: DWORD = 632; +pub const ERROR_DRIVER_FAILED_SLEEP: DWORD = 633; +pub const ERROR_CORRUPT_SYSTEM_FILE: DWORD = 634; +pub const ERROR_COMMITMENT_MINIMUM: DWORD = 635; +pub const ERROR_PNP_RESTART_ENUMERATION: DWORD = 636; +pub const ERROR_SYSTEM_IMAGE_BAD_SIGNATURE: DWORD = 637; +pub const ERROR_PNP_REBOOT_REQUIRED: DWORD = 638; +pub const ERROR_INSUFFICIENT_POWER: DWORD = 639; +pub const ERROR_MULTIPLE_FAULT_VIOLATION: DWORD = 640; +pub const ERROR_SYSTEM_SHUTDOWN: DWORD = 641; +pub const ERROR_PORT_NOT_SET: DWORD = 642; +pub const ERROR_DS_VERSION_CHECK_FAILURE: DWORD = 643; +pub const ERROR_RANGE_NOT_FOUND: DWORD = 644; +pub const ERROR_NOT_SAFE_MODE_DRIVER: DWORD = 646; +pub const ERROR_FAILED_DRIVER_ENTRY: DWORD = 647; +pub const ERROR_DEVICE_ENUMERATION_ERROR: DWORD = 648; +pub const ERROR_MOUNT_POINT_NOT_RESOLVED: DWORD = 649; +pub const ERROR_INVALID_DEVICE_OBJECT_PARAMETER: DWORD = 650; +pub const ERROR_MCA_OCCURED: DWORD = 651; +pub const ERROR_DRIVER_DATABASE_ERROR: DWORD = 652; +pub const ERROR_SYSTEM_HIVE_TOO_LARGE: DWORD = 653; +pub const ERROR_DRIVER_FAILED_PRIOR_UNLOAD: DWORD = 654; +pub const ERROR_VOLSNAP_PREPARE_HIBERNATE: DWORD = 655; +pub const ERROR_HIBERNATION_FAILURE: DWORD = 656; +pub const ERROR_PWD_TOO_LONG: DWORD = 657; +pub const ERROR_FILE_SYSTEM_LIMITATION: DWORD = 665; +pub const ERROR_ASSERTION_FAILURE: DWORD = 668; +pub const ERROR_ACPI_ERROR: DWORD = 669; +pub const ERROR_WOW_ASSERTION: DWORD = 670; +pub const ERROR_PNP_BAD_MPS_TABLE: DWORD = 671; +pub const ERROR_PNP_TRANSLATION_FAILED: DWORD = 672; +pub const ERROR_PNP_IRQ_TRANSLATION_FAILED: DWORD = 673; +pub const ERROR_PNP_INVALID_ID: DWORD = 674; +pub const ERROR_WAKE_SYSTEM_DEBUGGER: DWORD = 675; +pub const ERROR_HANDLES_CLOSED: DWORD = 676; +pub const ERROR_EXTRANEOUS_INFORMATION: DWORD = 677; +pub const ERROR_RXACT_COMMIT_NECESSARY: DWORD = 678; +pub const ERROR_MEDIA_CHECK: DWORD = 679; +pub const ERROR_GUID_SUBSTITUTION_MADE: DWORD = 680; +pub const ERROR_STOPPED_ON_SYMLINK: DWORD = 681; +pub const ERROR_LONGJUMP: DWORD = 682; +pub const ERROR_PLUGPLAY_QUERY_VETOED: DWORD = 683; +pub const ERROR_UNWIND_CONSOLIDATE: DWORD = 684; +pub const ERROR_REGISTRY_HIVE_RECOVERED: DWORD = 685; +pub const ERROR_DLL_MIGHT_BE_INSECURE: DWORD = 686; +pub const ERROR_DLL_MIGHT_BE_INCOMPATIBLE: DWORD = 687; +pub const ERROR_DBG_EXCEPTION_NOT_HANDLED: DWORD = 688; +pub const ERROR_DBG_REPLY_LATER: DWORD = 689; +pub const ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE: DWORD = 690; +pub const ERROR_DBG_TERMINATE_THREAD: DWORD = 691; +pub const ERROR_DBG_TERMINATE_PROCESS: DWORD = 692; +pub const ERROR_DBG_CONTROL_C: DWORD = 693; +pub const ERROR_DBG_PRINTEXCEPTION_C: DWORD = 694; +pub const ERROR_DBG_RIPEXCEPTION: DWORD = 695; +pub const ERROR_DBG_CONTROL_BREAK: DWORD = 696; +pub const ERROR_DBG_COMMAND_EXCEPTION: DWORD = 697; +pub const ERROR_OBJECT_NAME_EXISTS: DWORD = 698; +pub const ERROR_THREAD_WAS_SUSPENDED: DWORD = 699; +pub const ERROR_IMAGE_NOT_AT_BASE: DWORD = 700; +pub const ERROR_RXACT_STATE_CREATED: DWORD = 701; +pub const ERROR_SEGMENT_NOTIFICATION: DWORD = 702; +pub const ERROR_BAD_CURRENT_DIRECTORY: DWORD = 703; +pub const ERROR_FT_READ_RECOVERY_FROM_BACKUP: DWORD = 704; +pub const ERROR_FT_WRITE_RECOVERY: DWORD = 705; +pub const ERROR_IMAGE_MACHINE_TYPE_MISMATCH: DWORD = 706; +pub const ERROR_RECEIVE_PARTIAL: DWORD = 707; +pub const ERROR_RECEIVE_EXPEDITED: DWORD = 708; +pub const ERROR_RECEIVE_PARTIAL_EXPEDITED: DWORD = 709; +pub const ERROR_EVENT_DONE: DWORD = 710; +pub const ERROR_EVENT_PENDING: DWORD = 711; +pub const ERROR_CHECKING_FILE_SYSTEM: DWORD = 712; +pub const ERROR_FATAL_APP_EXIT: DWORD = 713; +pub const ERROR_PREDEFINED_HANDLE: DWORD = 714; +pub const ERROR_WAS_UNLOCKED: DWORD = 715; +pub const ERROR_SERVICE_NOTIFICATION: DWORD = 716; +pub const ERROR_WAS_LOCKED: DWORD = 717; +pub const ERROR_LOG_HARD_ERROR: DWORD = 718; +pub const ERROR_ALREADY_WIN32: DWORD = 719; +pub const ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE: DWORD = 720; +pub const ERROR_NO_YIELD_PERFORMED: DWORD = 721; +pub const ERROR_TIMER_RESUME_IGNORED: DWORD = 722; +pub const ERROR_ARBITRATION_UNHANDLED: DWORD = 723; +pub const ERROR_CARDBUS_NOT_SUPPORTED: DWORD = 724; +pub const ERROR_MP_PROCESSOR_MISMATCH: DWORD = 725; +pub const ERROR_HIBERNATED: DWORD = 726; +pub const ERROR_RESUME_HIBERNATION: DWORD = 727; +pub const ERROR_FIRMWARE_UPDATED: DWORD = 728; +pub const ERROR_DRIVERS_LEAKING_LOCKED_PAGES: DWORD = 729; +pub const ERROR_WAKE_SYSTEM: DWORD = 730; +pub const ERROR_WAIT_1: DWORD = 731; +pub const ERROR_WAIT_2: DWORD = 732; +pub const ERROR_WAIT_3: DWORD = 733; +pub const ERROR_WAIT_63: DWORD = 734; +pub const ERROR_ABANDONED_WAIT_0: DWORD = 735; +pub const ERROR_ABANDONED_WAIT_63: DWORD = 736; +pub const ERROR_USER_APC: DWORD = 737; +pub const ERROR_KERNEL_APC: DWORD = 738; +pub const ERROR_ALERTED: DWORD = 739; +pub const ERROR_ELEVATION_REQUIRED: DWORD = 740; +pub const ERROR_REPARSE: DWORD = 741; +pub const ERROR_OPLOCK_BREAK_IN_PROGRESS: DWORD = 742; +pub const ERROR_VOLUME_MOUNTED: DWORD = 743; +pub const ERROR_RXACT_COMMITTED: DWORD = 744; +pub const ERROR_NOTIFY_CLEANUP: DWORD = 745; +pub const ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED: DWORD = 746; +pub const ERROR_PAGE_FAULT_TRANSITION: DWORD = 747; +pub const ERROR_PAGE_FAULT_DEMAND_ZERO: DWORD = 748; +pub const ERROR_PAGE_FAULT_COPY_ON_WRITE: DWORD = 749; +pub const ERROR_PAGE_FAULT_GUARD_PAGE: DWORD = 750; +pub const ERROR_PAGE_FAULT_PAGING_FILE: DWORD = 751; +pub const ERROR_CACHE_PAGE_LOCKED: DWORD = 752; +pub const ERROR_CRASH_DUMP: DWORD = 753; +pub const ERROR_BUFFER_ALL_ZEROS: DWORD = 754; +pub const ERROR_REPARSE_OBJECT: DWORD = 755; +pub const ERROR_RESOURCE_REQUIREMENTS_CHANGED: DWORD = 756; +pub const ERROR_TRANSLATION_COMPLETE: DWORD = 757; +pub const ERROR_NOTHING_TO_TERMINATE: DWORD = 758; +pub const ERROR_PROCESS_NOT_IN_JOB: DWORD = 759; +pub const ERROR_PROCESS_IN_JOB: DWORD = 760; +pub const ERROR_VOLSNAP_HIBERNATE_READY: DWORD = 761; +pub const ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY: DWORD = 762; +pub const ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED: DWORD = 763; +pub const ERROR_INTERRUPT_STILL_CONNECTED: DWORD = 764; +pub const ERROR_WAIT_FOR_OPLOCK: DWORD = 765; +pub const ERROR_DBG_EXCEPTION_HANDLED: DWORD = 766; +pub const ERROR_DBG_CONTINUE: DWORD = 767; +pub const ERROR_CALLBACK_POP_STACK: DWORD = 768; +pub const ERROR_COMPRESSION_DISABLED: DWORD = 769; +pub const ERROR_CANTFETCHBACKWARDS: DWORD = 770; +pub const ERROR_CANTSCROLLBACKWARDS: DWORD = 771; +pub const ERROR_ROWSNOTRELEASED: DWORD = 772; +pub const ERROR_BAD_ACCESSOR_FLAGS: DWORD = 773; +pub const ERROR_ERRORS_ENCOUNTERED: DWORD = 774; +pub const ERROR_NOT_CAPABLE: DWORD = 775; +pub const ERROR_REQUEST_OUT_OF_SEQUENCE: DWORD = 776; +pub const ERROR_VERSION_PARSE_ERROR: DWORD = 777; +pub const ERROR_BADSTARTPOSITION: DWORD = 778; +pub const ERROR_MEMORY_HARDWARE: DWORD = 779; +pub const ERROR_DISK_REPAIR_DISABLED: DWORD = 780; +pub const ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE: DWORD = 781; +pub const ERROR_SYSTEM_POWERSTATE_TRANSITION: DWORD = 782; +pub const ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION: DWORD = 783; +pub const ERROR_MCA_EXCEPTION: DWORD = 784; +pub const ERROR_ACCESS_AUDIT_BY_POLICY: DWORD = 785; +pub const ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY: DWORD = 786; +pub const ERROR_ABANDON_HIBERFILE: DWORD = 787; +pub const ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED: DWORD = 788; +pub const ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR: DWORD = 789; +pub const ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR: DWORD = 790; +pub const ERROR_BAD_MCFG_TABLE: DWORD = 791; +pub const ERROR_DISK_REPAIR_REDIRECTED: DWORD = 792; +pub const ERROR_DISK_REPAIR_UNSUCCESSFUL: DWORD = 793; +pub const ERROR_CORRUPT_LOG_OVERFULL: DWORD = 794; +pub const ERROR_CORRUPT_LOG_CORRUPTED: DWORD = 795; +pub const ERROR_CORRUPT_LOG_UNAVAILABLE: DWORD = 796; +pub const ERROR_CORRUPT_LOG_DELETED_FULL: DWORD = 797; +pub const ERROR_CORRUPT_LOG_CLEARED: DWORD = 798; +pub const ERROR_ORPHAN_NAME_EXHAUSTED: DWORD = 799; +pub const ERROR_OPLOCK_SWITCHED_TO_NEW_HANDLE: DWORD = 800; +pub const ERROR_CANNOT_GRANT_REQUESTED_OPLOCK: DWORD = 801; +pub const ERROR_CANNOT_BREAK_OPLOCK: DWORD = 802; +pub const ERROR_OPLOCK_HANDLE_CLOSED: DWORD = 803; +pub const ERROR_NO_ACE_CONDITION: DWORD = 804; +pub const ERROR_INVALID_ACE_CONDITION: DWORD = 805; +pub const ERROR_FILE_HANDLE_REVOKED: DWORD = 806; +pub const ERROR_IMAGE_AT_DIFFERENT_BASE: DWORD = 807; +pub const ERROR_ENCRYPTED_IO_NOT_POSSIBLE: DWORD = 808; +pub const ERROR_EA_ACCESS_DENIED: DWORD = 994; +pub const ERROR_OPERATION_ABORTED: DWORD = 995; +pub const ERROR_IO_INCOMPLETE: DWORD = 996; +pub const ERROR_IO_PENDING: DWORD = 997; +pub const ERROR_NOACCESS: DWORD = 998; +pub const ERROR_SWAPERROR: DWORD = 999; +pub const ERROR_STACK_OVERFLOW: DWORD = 1001; +pub const ERROR_INVALID_MESSAGE: DWORD = 1002; +pub const ERROR_CAN_NOT_COMPLETE: DWORD = 1003; +pub const ERROR_INVALID_FLAGS: DWORD = 1004; +pub const ERROR_UNRECOGNIZED_VOLUME: DWORD = 1005; +pub const ERROR_FILE_INVALID: DWORD = 1006; +pub const ERROR_FULLSCREEN_MODE: DWORD = 1007; +pub const ERROR_NO_TOKEN: DWORD = 1008; +pub const ERROR_BADDB: DWORD = 1009; +pub const ERROR_BADKEY: DWORD = 1010; +pub const ERROR_CANTOPEN: DWORD = 1011; +pub const ERROR_CANTREAD: DWORD = 1012; +pub const ERROR_CANTWRITE: DWORD = 1013; +pub const ERROR_REGISTRY_RECOVERED: DWORD = 1014; +pub const ERROR_REGISTRY_CORRUPT: DWORD = 1015; +pub const ERROR_REGISTRY_IO_FAILED: DWORD = 1016; +pub const ERROR_NOT_REGISTRY_FILE: DWORD = 1017; +pub const ERROR_KEY_DELETED: DWORD = 1018; +pub const ERROR_NO_LOG_SPACE: DWORD = 1019; +pub const ERROR_KEY_HAS_CHILDREN: DWORD = 1020; +pub const ERROR_CHILD_MUST_BE_VOLATILE: DWORD = 1021; +pub const ERROR_NOTIFY_ENUM_DIR: DWORD = 1022; +pub const ERROR_DEPENDENT_SERVICES_RUNNING: DWORD = 1051; +pub const ERROR_INVALID_SERVICE_CONTROL: DWORD = 1052; +pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; +pub const ERROR_SERVICE_NO_THREAD: DWORD = 1054; +pub const ERROR_SERVICE_DATABASE_LOCKED: DWORD = 1055; +pub const ERROR_SERVICE_ALREADY_RUNNING: DWORD = 1056; +pub const ERROR_INVALID_SERVICE_ACCOUNT: DWORD = 1057; +pub const ERROR_SERVICE_DISABLED: DWORD = 1058; +pub const ERROR_CIRCULAR_DEPENDENCY: DWORD = 1059; +pub const ERROR_SERVICE_DOES_NOT_EXIST: DWORD = 1060; +pub const ERROR_SERVICE_CANNOT_ACCEPT_CTRL: DWORD = 1061; +pub const ERROR_SERVICE_NOT_ACTIVE: DWORD = 1062; +pub const ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: DWORD = 1063; +pub const ERROR_EXCEPTION_IN_SERVICE: DWORD = 1064; +pub const ERROR_DATABASE_DOES_NOT_EXIST: DWORD = 1065; +pub const ERROR_SERVICE_SPECIFIC_ERROR: DWORD = 1066; +pub const ERROR_PROCESS_ABORTED: DWORD = 1067; +pub const ERROR_SERVICE_DEPENDENCY_FAIL: DWORD = 1068; +pub const ERROR_SERVICE_LOGON_FAILED: DWORD = 1069; +pub const ERROR_SERVICE_START_HANG: DWORD = 1070; +pub const ERROR_INVALID_SERVICE_LOCK: DWORD = 1071; +pub const ERROR_SERVICE_MARKED_FOR_DELETE: DWORD = 1072; +pub const ERROR_SERVICE_EXISTS: DWORD = 1073; +pub const ERROR_ALREADY_RUNNING_LKG: DWORD = 1074; +pub const ERROR_SERVICE_DEPENDENCY_DELETED: DWORD = 1075; +pub const ERROR_BOOT_ALREADY_ACCEPTED: DWORD = 1076; +pub const ERROR_SERVICE_NEVER_STARTED: DWORD = 1077; +pub const ERROR_DUPLICATE_SERVICE_NAME: DWORD = 1078; +pub const ERROR_DIFFERENT_SERVICE_ACCOUNT: DWORD = 1079; +pub const ERROR_CANNOT_DETECT_DRIVER_FAILURE: DWORD = 1080; +pub const ERROR_CANNOT_DETECT_PROCESS_ABORT: DWORD = 1081; +pub const ERROR_NO_RECOVERY_PROGRAM: DWORD = 1082; +pub const ERROR_SERVICE_NOT_IN_EXE: DWORD = 1083; +pub const ERROR_NOT_SAFEBOOT_SERVICE: DWORD = 1084; +pub const ERROR_END_OF_MEDIA: DWORD = 1100; +pub const ERROR_FILEMARK_DETECTED: DWORD = 1101; +pub const ERROR_BEGINNING_OF_MEDIA: DWORD = 1102; +pub const ERROR_SETMARK_DETECTED: DWORD = 1103; +pub const ERROR_NO_DATA_DETECTED: DWORD = 1104; +pub const ERROR_PARTITION_FAILURE: DWORD = 1105; +pub const ERROR_INVALID_BLOCK_LENGTH: DWORD = 1106; +pub const ERROR_DEVICE_NOT_PARTITIONED: DWORD = 1107; +pub const ERROR_UNABLE_TO_LOCK_MEDIA: DWORD = 1108; +pub const ERROR_UNABLE_TO_UNLOAD_MEDIA: DWORD = 1109; +pub const ERROR_MEDIA_CHANGED: DWORD = 1110; +pub const ERROR_BUS_RESET: DWORD = 1111; +pub const ERROR_NO_MEDIA_IN_DRIVE: DWORD = 1112; +pub const ERROR_NO_UNICODE_TRANSLATION: DWORD = 1113; +pub const ERROR_DLL_INIT_FAILED: DWORD = 1114; +pub const ERROR_SHUTDOWN_IN_PROGRESS: DWORD = 1115; +pub const ERROR_NO_SHUTDOWN_IN_PROGRESS: DWORD = 1116; +pub const ERROR_IO_DEVICE: DWORD = 1117; +pub const ERROR_SERIAL_NO_DEVICE: DWORD = 1118; +pub const ERROR_IRQ_BUSY: DWORD = 1119; +pub const ERROR_MORE_WRITES: DWORD = 1120; +pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; +pub const ERROR_FLOPPY_ID_MARK_NOT_FOUND: DWORD = 1122; +pub const ERROR_FLOPPY_WRONG_CYLINDER: DWORD = 1123; +pub const ERROR_FLOPPY_UNKNOWN_ERROR: DWORD = 1124; +pub const ERROR_FLOPPY_BAD_REGISTERS: DWORD = 1125; +pub const ERROR_DISK_RECALIBRATE_FAILED: DWORD = 1126; +pub const ERROR_DISK_OPERATION_FAILED: DWORD = 1127; +pub const ERROR_DISK_RESET_FAILED: DWORD = 1128; +pub const ERROR_EOM_OVERFLOW: DWORD = 1129; +pub const ERROR_NOT_ENOUGH_SERVER_MEMORY: DWORD = 1130; +pub const ERROR_POSSIBLE_DEADLOCK: DWORD = 1131; +pub const ERROR_MAPPED_ALIGNMENT: DWORD = 1132; +pub const ERROR_SET_POWER_STATE_VETOED: DWORD = 1140; +pub const ERROR_SET_POWER_STATE_FAILED: DWORD = 1141; +pub const ERROR_TOO_MANY_LINKS: DWORD = 1142; +pub const ERROR_OLD_WIN_VERSION: DWORD = 1150; +pub const ERROR_APP_WRONG_OS: DWORD = 1151; +pub const ERROR_SINGLE_INSTANCE_APP: DWORD = 1152; +pub const ERROR_RMODE_APP: DWORD = 1153; +pub const ERROR_INVALID_DLL: DWORD = 1154; +pub const ERROR_NO_ASSOCIATION: DWORD = 1155; +pub const ERROR_DDE_FAIL: DWORD = 1156; +pub const ERROR_DLL_NOT_FOUND: DWORD = 1157; +pub const ERROR_NO_MORE_USER_HANDLES: DWORD = 1158; +pub const ERROR_MESSAGE_SYNC_ONLY: DWORD = 1159; +pub const ERROR_SOURCE_ELEMENT_EMPTY: DWORD = 1160; +pub const ERROR_DESTINATION_ELEMENT_FULL: DWORD = 1161; +pub const ERROR_ILLEGAL_ELEMENT_ADDRESS: DWORD = 1162; +pub const ERROR_MAGAZINE_NOT_PRESENT: DWORD = 1163; +pub const ERROR_DEVICE_REINITIALIZATION_NEEDED: DWORD = 1164; +pub const ERROR_DEVICE_REQUIRES_CLEANING: DWORD = 1165; +pub const ERROR_DEVICE_DOOR_OPEN: DWORD = 1166; +pub const ERROR_DEVICE_NOT_CONNECTED: DWORD = 1167; +pub const ERROR_NOT_FOUND: DWORD = 1168; +pub const ERROR_NO_MATCH: DWORD = 1169; +pub const ERROR_SET_NOT_FOUND: DWORD = 1170; +pub const ERROR_POINT_NOT_FOUND: DWORD = 1171; +pub const ERROR_NO_TRACKING_SERVICE: DWORD = 1172; +pub const ERROR_NO_VOLUME_ID: DWORD = 1173; +pub const ERROR_UNABLE_TO_REMOVE_REPLACED: DWORD = 1175; +pub const ERROR_UNABLE_TO_MOVE_REPLACEMENT: DWORD = 1176; +pub const ERROR_UNABLE_TO_MOVE_REPLACEMENT_2: DWORD = 1177; +pub const ERROR_JOURNAL_DELETE_IN_PROGRESS: DWORD = 1178; +pub const ERROR_JOURNAL_NOT_ACTIVE: DWORD = 1179; +pub const ERROR_POTENTIAL_FILE_FOUND: DWORD = 1180; +pub const ERROR_JOURNAL_ENTRY_DELETED: DWORD = 1181; +pub const ERROR_SHUTDOWN_IS_SCHEDULED: DWORD = 1190; +pub const ERROR_SHUTDOWN_USERS_LOGGED_ON: DWORD = 1191; +pub const ERROR_BAD_DEVICE: DWORD = 1200; +pub const ERROR_CONNECTION_UNAVAIL: DWORD = 1201; +pub const ERROR_DEVICE_ALREADY_REMEMBERED: DWORD = 1202; +pub const ERROR_NO_NET_OR_BAD_PATH: DWORD = 1203; +pub const ERROR_BAD_PROVIDER: DWORD = 1204; +pub const ERROR_CANNOT_OPEN_PROFILE: DWORD = 1205; +pub const ERROR_BAD_PROFILE: DWORD = 1206; +pub const ERROR_NOT_CONTAINER: DWORD = 1207; +pub const ERROR_EXTENDED_ERROR: DWORD = 1208; +pub const ERROR_INVALID_GROUPNAME: DWORD = 1209; +pub const ERROR_INVALID_COMPUTERNAME: DWORD = 1210; +pub const ERROR_INVALID_EVENTNAME: DWORD = 1211; +pub const ERROR_INVALID_DOMAINNAME: DWORD = 1212; +pub const ERROR_INVALID_SERVICENAME: DWORD = 1213; +pub const ERROR_INVALID_NETNAME: DWORD = 1214; +pub const ERROR_INVALID_SHARENAME: DWORD = 1215; +pub const ERROR_INVALID_PASSWORDNAME: DWORD = 1216; +pub const ERROR_INVALID_MESSAGENAME: DWORD = 1217; +pub const ERROR_INVALID_MESSAGEDEST: DWORD = 1218; +pub const ERROR_SESSION_CREDENTIAL_CONFLICT: DWORD = 1219; +pub const ERROR_REMOTE_SESSION_LIMIT_EXCEEDED: DWORD = 1220; +pub const ERROR_DUP_DOMAINNAME: DWORD = 1221; +pub const ERROR_NO_NETWORK: DWORD = 1222; +pub const ERROR_CANCELLED: DWORD = 1223; +pub const ERROR_USER_MAPPED_FILE: DWORD = 1224; +pub const ERROR_CONNECTION_REFUSED: DWORD = 1225; +pub const ERROR_GRACEFUL_DISCONNECT: DWORD = 1226; +pub const ERROR_ADDRESS_ALREADY_ASSOCIATED: DWORD = 1227; +pub const ERROR_ADDRESS_NOT_ASSOCIATED: DWORD = 1228; +pub const ERROR_CONNECTION_INVALID: DWORD = 1229; +pub const ERROR_CONNECTION_ACTIVE: DWORD = 1230; +pub const ERROR_NETWORK_UNREACHABLE: DWORD = 1231; +pub const ERROR_HOST_UNREACHABLE: DWORD = 1232; +pub const ERROR_PROTOCOL_UNREACHABLE: DWORD = 1233; +pub const ERROR_PORT_UNREACHABLE: DWORD = 1234; +pub const ERROR_REQUEST_ABORTED: DWORD = 1235; +pub const ERROR_CONNECTION_ABORTED: DWORD = 1236; +pub const ERROR_RETRY: DWORD = 1237; +pub const ERROR_CONNECTION_COUNT_LIMIT: DWORD = 1238; +pub const ERROR_LOGIN_TIME_RESTRICTION: DWORD = 1239; +pub const ERROR_LOGIN_WKSTA_RESTRICTION: DWORD = 1240; +pub const ERROR_INCORRECT_ADDRESS: DWORD = 1241; +pub const ERROR_ALREADY_REGISTERED: DWORD = 1242; +pub const ERROR_SERVICE_NOT_FOUND: DWORD = 1243; +pub const ERROR_NOT_AUTHENTICATED: DWORD = 1244; +pub const ERROR_NOT_LOGGED_ON: DWORD = 1245; +pub const ERROR_CONTINUE: DWORD = 1246; +pub const ERROR_ALREADY_INITIALIZED: DWORD = 1247; +pub const ERROR_NO_MORE_DEVICES: DWORD = 1248; +pub const ERROR_NO_SUCH_SITE: DWORD = 1249; +pub const ERROR_DOMAIN_CONTROLLER_EXISTS: DWORD = 1250; +pub const ERROR_ONLY_IF_CONNECTED: DWORD = 1251; +pub const ERROR_OVERRIDE_NOCHANGES: DWORD = 1252; +pub const ERROR_BAD_USER_PROFILE: DWORD = 1253; +pub const ERROR_NOT_SUPPORTED_ON_SBS: DWORD = 1254; +pub const ERROR_SERVER_SHUTDOWN_IN_PROGRESS: DWORD = 1255; +pub const ERROR_HOST_DOWN: DWORD = 1256; +pub const ERROR_NON_ACCOUNT_SID: DWORD = 1257; +pub const ERROR_NON_DOMAIN_SID: DWORD = 1258; +pub const ERROR_APPHELP_BLOCK: DWORD = 1259; +pub const ERROR_ACCESS_DISABLED_BY_POLICY: DWORD = 1260; +pub const ERROR_REG_NAT_CONSUMPTION: DWORD = 1261; +pub const ERROR_CSCSHARE_OFFLINE: DWORD = 1262; +pub const ERROR_PKINIT_FAILURE: DWORD = 1263; +pub const ERROR_SMARTCARD_SUBSYSTEM_FAILURE: DWORD = 1264; +pub const ERROR_DOWNGRADE_DETECTED: DWORD = 1265; +pub const ERROR_MACHINE_LOCKED: DWORD = 1271; +pub const ERROR_CALLBACK_SUPPLIED_INVALID_DATA: DWORD = 1273; +pub const ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED: DWORD = 1274; +pub const ERROR_DRIVER_BLOCKED: DWORD = 1275; +pub const ERROR_INVALID_IMPORT_OF_NON_DLL: DWORD = 1276; +pub const ERROR_ACCESS_DISABLED_WEBBLADE: DWORD = 1277; +pub const ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER: DWORD = 1278; +pub const ERROR_RECOVERY_FAILURE: DWORD = 1279; +pub const ERROR_ALREADY_FIBER: DWORD = 1280; +pub const ERROR_ALREADY_THREAD: DWORD = 1281; +pub const ERROR_STACK_BUFFER_OVERRUN: DWORD = 1282; +pub const ERROR_PARAMETER_QUOTA_EXCEEDED: DWORD = 1283; +pub const ERROR_DEBUGGER_INACTIVE: DWORD = 1284; +pub const ERROR_DELAY_LOAD_FAILED: DWORD = 1285; +pub const ERROR_VDM_DISALLOWED: DWORD = 1286; +pub const ERROR_UNIDENTIFIED_ERROR: DWORD = 1287; +pub const ERROR_INVALID_CRUNTIME_PARAMETER: DWORD = 1288; +pub const ERROR_BEYOND_VDL: DWORD = 1289; +pub const ERROR_INCOMPATIBLE_SERVICE_SID_TYPE: DWORD = 1290; +pub const ERROR_DRIVER_PROCESS_TERMINATED: DWORD = 1291; +pub const ERROR_IMPLEMENTATION_LIMIT: DWORD = 1292; +pub const ERROR_PROCESS_IS_PROTECTED: DWORD = 1293; +pub const ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: DWORD = 1294; +pub const ERROR_DISK_QUOTA_EXCEEDED: DWORD = 1295; +pub const ERROR_CONTENT_BLOCKED: DWORD = 1296; +pub const ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE: DWORD = 1297; +pub const ERROR_APP_HANG: DWORD = 1298; +pub const ERROR_INVALID_LABEL: DWORD = 1299; +pub const ERROR_NOT_ALL_ASSIGNED: DWORD = 1300; +pub const ERROR_SOME_NOT_MAPPED: DWORD = 1301; +pub const ERROR_NO_QUOTAS_FOR_ACCOUNT: DWORD = 1302; +pub const ERROR_LOCAL_USER_SESSION_KEY: DWORD = 1303; +pub const ERROR_NULL_LM_PASSWORD: DWORD = 1304; +pub const ERROR_UNKNOWN_REVISION: DWORD = 1305; +pub const ERROR_REVISION_MISMATCH: DWORD = 1306; +pub const ERROR_INVALID_OWNER: DWORD = 1307; +pub const ERROR_INVALID_PRIMARY_GROUP: DWORD = 1308; +pub const ERROR_NO_IMPERSONATION_TOKEN: DWORD = 1309; +pub const ERROR_CANT_DISABLE_MANDATORY: DWORD = 1310; +pub const ERROR_NO_LOGON_SERVERS: DWORD = 1311; +pub const ERROR_NO_SUCH_LOGON_SESSION: DWORD = 1312; +pub const ERROR_NO_SUCH_PRIVILEGE: DWORD = 1313; +pub const ERROR_PRIVILEGE_NOT_HELD: DWORD = 1314; +pub const ERROR_INVALID_ACCOUNT_NAME: DWORD = 1315; +pub const ERROR_USER_EXISTS: DWORD = 1316; +pub const ERROR_NO_SUCH_USER: DWORD = 1317; +pub const ERROR_GROUP_EXISTS: DWORD = 1318; +pub const ERROR_NO_SUCH_GROUP: DWORD = 1319; +pub const ERROR_MEMBER_IN_GROUP: DWORD = 1320; +pub const ERROR_MEMBER_NOT_IN_GROUP: DWORD = 1321; +pub const ERROR_LAST_ADMIN: DWORD = 1322; +pub const ERROR_WRONG_PASSWORD: DWORD = 1323; +pub const ERROR_ILL_FORMED_PASSWORD: DWORD = 1324; +pub const ERROR_PASSWORD_RESTRICTION: DWORD = 1325; +pub const ERROR_LOGON_FAILURE: DWORD = 1326; +pub const ERROR_ACCOUNT_RESTRICTION: DWORD = 1327; +pub const ERROR_INVALID_LOGON_HOURS: DWORD = 1328; +pub const ERROR_INVALID_WORKSTATION: DWORD = 1329; +pub const ERROR_PASSWORD_EXPIRED: DWORD = 1330; +pub const ERROR_ACCOUNT_DISABLED: DWORD = 1331; +pub const ERROR_NONE_MAPPED: DWORD = 1332; +pub const ERROR_TOO_MANY_LUIDS_REQUESTED: DWORD = 1333; +pub const ERROR_LUIDS_EXHAUSTED: DWORD = 1334; +pub const ERROR_INVALID_SUB_AUTHORITY: DWORD = 1335; +pub const ERROR_INVALID_ACL: DWORD = 1336; +pub const ERROR_INVALID_SID: DWORD = 1337; +pub const ERROR_INVALID_SECURITY_DESCR: DWORD = 1338; +pub const ERROR_BAD_INHERITANCE_ACL: DWORD = 1340; +pub const ERROR_SERVER_DISABLED: DWORD = 1341; +pub const ERROR_SERVER_NOT_DISABLED: DWORD = 1342; +pub const ERROR_INVALID_ID_AUTHORITY: DWORD = 1343; +pub const ERROR_ALLOTTED_SPACE_EXCEEDED: DWORD = 1344; +pub const ERROR_INVALID_GROUP_ATTRIBUTES: DWORD = 1345; +pub const ERROR_BAD_IMPERSONATION_LEVEL: DWORD = 1346; +pub const ERROR_CANT_OPEN_ANONYMOUS: DWORD = 1347; +pub const ERROR_BAD_VALIDATION_CLASS: DWORD = 1348; +pub const ERROR_BAD_TOKEN_TYPE: DWORD = 1349; +pub const ERROR_NO_SECURITY_ON_OBJECT: DWORD = 1350; +pub const ERROR_CANT_ACCESS_DOMAIN_INFO: DWORD = 1351; +pub const ERROR_INVALID_SERVER_STATE: DWORD = 1352; +pub const ERROR_INVALID_DOMAIN_STATE: DWORD = 1353; +pub const ERROR_INVALID_DOMAIN_ROLE: DWORD = 1354; +pub const ERROR_NO_SUCH_DOMAIN: DWORD = 1355; +pub const ERROR_DOMAIN_EXISTS: DWORD = 1356; +pub const ERROR_DOMAIN_LIMIT_EXCEEDED: DWORD = 1357; +pub const ERROR_INTERNAL_DB_CORRUPTION: DWORD = 1358; +pub const ERROR_INTERNAL_ERROR: DWORD = 1359; +pub const ERROR_GENERIC_NOT_MAPPED: DWORD = 1360; +pub const ERROR_BAD_DESCRIPTOR_FORMAT: DWORD = 1361; +pub const ERROR_NOT_LOGON_PROCESS: DWORD = 1362; +pub const ERROR_LOGON_SESSION_EXISTS: DWORD = 1363; +pub const ERROR_NO_SUCH_PACKAGE: DWORD = 1364; +pub const ERROR_BAD_LOGON_SESSION_STATE: DWORD = 1365; +pub const ERROR_LOGON_SESSION_COLLISION: DWORD = 1366; +pub const ERROR_INVALID_LOGON_TYPE: DWORD = 1367; +pub const ERROR_CANNOT_IMPERSONATE: DWORD = 1368; +pub const ERROR_RXACT_INVALID_STATE: DWORD = 1369; +pub const ERROR_RXACT_COMMIT_FAILURE: DWORD = 1370; +pub const ERROR_SPECIAL_ACCOUNT: DWORD = 1371; +pub const ERROR_SPECIAL_GROUP: DWORD = 1372; +pub const ERROR_SPECIAL_USER: DWORD = 1373; +pub const ERROR_MEMBERS_PRIMARY_GROUP: DWORD = 1374; +pub const ERROR_TOKEN_ALREADY_IN_USE: DWORD = 1375; +pub const ERROR_NO_SUCH_ALIAS: DWORD = 1376; +pub const ERROR_MEMBER_NOT_IN_ALIAS: DWORD = 1377; +pub const ERROR_MEMBER_IN_ALIAS: DWORD = 1378; +pub const ERROR_ALIAS_EXISTS: DWORD = 1379; +pub const ERROR_LOGON_NOT_GRANTED: DWORD = 1380; +pub const ERROR_TOO_MANY_SECRETS: DWORD = 1381; +pub const ERROR_SECRET_TOO_LONG: DWORD = 1382; +pub const ERROR_INTERNAL_DB_ERROR: DWORD = 1383; +pub const ERROR_TOO_MANY_CONTEXT_IDS: DWORD = 1384; +pub const ERROR_LOGON_TYPE_NOT_GRANTED: DWORD = 1385; +pub const ERROR_NT_CROSS_ENCRYPTION_REQUIRED: DWORD = 1386; +pub const ERROR_NO_SUCH_MEMBER: DWORD = 1387; +pub const ERROR_INVALID_MEMBER: DWORD = 1388; +pub const ERROR_TOO_MANY_SIDS: DWORD = 1389; +pub const ERROR_LM_CROSS_ENCRYPTION_REQUIRED: DWORD = 1390; +pub const ERROR_NO_INHERITANCE: DWORD = 1391; +pub const ERROR_FILE_CORRUPT: DWORD = 1392; +pub const ERROR_DISK_CORRUPT: DWORD = 1393; +pub const ERROR_NO_USER_SESSION_KEY: DWORD = 1394; +pub const ERROR_LICENSE_QUOTA_EXCEEDED: DWORD = 1395; +pub const ERROR_WRONG_TARGET_NAME: DWORD = 1396; +pub const ERROR_MUTUAL_AUTH_FAILED: DWORD = 1397; +pub const ERROR_TIME_SKEW: DWORD = 1398; +pub const ERROR_CURRENT_DOMAIN_NOT_ALLOWED: DWORD = 1399; +pub const ERROR_INVALID_WINDOW_HANDLE: DWORD = 1400; +pub const ERROR_INVALID_MENU_HANDLE: DWORD = 1401; +pub const ERROR_INVALID_CURSOR_HANDLE: DWORD = 1402; +pub const ERROR_INVALID_ACCEL_HANDLE: DWORD = 1403; +pub const ERROR_INVALID_HOOK_HANDLE: DWORD = 1404; +pub const ERROR_INVALID_DWP_HANDLE: DWORD = 1405; +pub const ERROR_TLW_WITH_WSCHILD: DWORD = 1406; +pub const ERROR_CANNOT_FIND_WND_CLASS: DWORD = 1407; +pub const ERROR_WINDOW_OF_OTHER_THREAD: DWORD = 1408; +pub const ERROR_HOTKEY_ALREADY_REGISTERED: DWORD = 1409; +pub const ERROR_CLASS_ALREADY_EXISTS: DWORD = 1410; +pub const ERROR_CLASS_DOES_NOT_EXIST: DWORD = 1411; +pub const ERROR_CLASS_HAS_WINDOWS: DWORD = 1412; +pub const ERROR_INVALID_INDEX: DWORD = 1413; +pub const ERROR_INVALID_ICON_HANDLE: DWORD = 1414; +pub const ERROR_PRIVATE_DIALOG_INDEX: DWORD = 1415; +pub const ERROR_LISTBOX_ID_NOT_FOUND: DWORD = 1416; +pub const ERROR_NO_WILDCARD_CHARACTERS: DWORD = 1417; +pub const ERROR_CLIPBOARD_NOT_OPEN: DWORD = 1418; +pub const ERROR_HOTKEY_NOT_REGISTERED: DWORD = 1419; +pub const ERROR_WINDOW_NOT_DIALOG: DWORD = 1420; +pub const ERROR_CONTROL_ID_NOT_FOUND: DWORD = 1421; +pub const ERROR_INVALID_COMBOBOX_MESSAGE: DWORD = 1422; +pub const ERROR_WINDOW_NOT_COMBOBOX: DWORD = 1423; +pub const ERROR_INVALID_EDIT_HEIGHT: DWORD = 1424; +pub const ERROR_DC_NOT_FOUND: DWORD = 1425; +pub const ERROR_INVALID_HOOK_FILTER: DWORD = 1426; +pub const ERROR_INVALID_FILTER_PROC: DWORD = 1427; +pub const ERROR_HOOK_NEEDS_HMOD: DWORD = 1428; +pub const ERROR_GLOBAL_ONLY_HOOK: DWORD = 1429; +pub const ERROR_JOURNAL_HOOK_SET: DWORD = 1430; +pub const ERROR_HOOK_NOT_INSTALLED: DWORD = 1431; +pub const ERROR_INVALID_LB_MESSAGE: DWORD = 1432; +pub const ERROR_SETCOUNT_ON_BAD_LB: DWORD = 1433; +pub const ERROR_LB_WITHOUT_TABSTOPS: DWORD = 1434; +pub const ERROR_DESTROY_OBJECT_OF_OTHER_THREAD: DWORD = 1435; +pub const ERROR_CHILD_WINDOW_MENU: DWORD = 1436; +pub const ERROR_NO_SYSTEM_MENU: DWORD = 1437; +pub const ERROR_INVALID_MSGBOX_STYLE: DWORD = 1438; +pub const ERROR_INVALID_SPI_VALUE: DWORD = 1439; +pub const ERROR_SCREEN_ALREADY_LOCKED: DWORD = 1440; +pub const ERROR_HWNDS_HAVE_DIFF_PARENT: DWORD = 1441; +pub const ERROR_NOT_CHILD_WINDOW: DWORD = 1442; +pub const ERROR_INVALID_GW_COMMAND: DWORD = 1443; +pub const ERROR_INVALID_THREAD_ID: DWORD = 1444; +pub const ERROR_NON_MDICHILD_WINDOW: DWORD = 1445; +pub const ERROR_POPUP_ALREADY_ACTIVE: DWORD = 1446; +pub const ERROR_NO_SCROLLBARS: DWORD = 1447; +pub const ERROR_INVALID_SCROLLBAR_RANGE: DWORD = 1448; +pub const ERROR_INVALID_SHOWWIN_COMMAND: DWORD = 1449; +pub const ERROR_NO_SYSTEM_RESOURCES: DWORD = 1450; +pub const ERROR_NONPAGED_SYSTEM_RESOURCES: DWORD = 1451; +pub const ERROR_PAGED_SYSTEM_RESOURCES: DWORD = 1452; +pub const ERROR_WORKING_SET_QUOTA: DWORD = 1453; +pub const ERROR_PAGEFILE_QUOTA: DWORD = 1454; +pub const ERROR_COMMITMENT_LIMIT: DWORD = 1455; +pub const ERROR_MENU_ITEM_NOT_FOUND: DWORD = 1456; +pub const ERROR_INVALID_KEYBOARD_HANDLE: DWORD = 1457; +pub const ERROR_HOOK_TYPE_NOT_ALLOWED: DWORD = 1458; +pub const ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION: DWORD = 1459; +pub const ERROR_TIMEOUT: DWORD = 1460; +pub const ERROR_INVALID_MONITOR_HANDLE: DWORD = 1461; +pub const ERROR_INCORRECT_SIZE: DWORD = 1462; +pub const ERROR_SYMLINK_CLASS_DISABLED: DWORD = 1463; +pub const ERROR_SYMLINK_NOT_SUPPORTED: DWORD = 1464; +pub const ERROR_XML_PARSE_ERROR: DWORD = 1465; +pub const ERROR_XMLDSIG_ERROR: DWORD = 1466; +pub const ERROR_RESTART_APPLICATION: DWORD = 1467; +pub const ERROR_WRONG_COMPARTMENT: DWORD = 1468; +pub const ERROR_AUTHIP_FAILURE: DWORD = 1469; +pub const ERROR_NO_NVRAM_RESOURCES: DWORD = 1470; +pub const ERROR_NOT_GUI_PROCESS: DWORD = 1471; +pub const ERROR_EVENTLOG_FILE_CORRUPT: DWORD = 1500; +pub const ERROR_EVENTLOG_CANT_START: DWORD = 1501; +pub const ERROR_LOG_FILE_FULL: DWORD = 1502; +pub const ERROR_EVENTLOG_FILE_CHANGED: DWORD = 1503; +pub const ERROR_INVALID_TASK_NAME: DWORD = 1550; +pub const ERROR_INVALID_TASK_INDEX: DWORD = 1551; +pub const ERROR_THREAD_ALREADY_IN_TASK: DWORD = 1552; +pub const ERROR_INSTALL_SERVICE_FAILURE: DWORD = 1601; +pub const ERROR_INSTALL_USEREXIT: DWORD = 1602; +pub const ERROR_INSTALL_FAILURE: DWORD = 1603; +pub const ERROR_INSTALL_SUSPEND: DWORD = 1604; +pub const ERROR_UNKNOWN_PRODUCT: DWORD = 1605; +pub const ERROR_UNKNOWN_FEATURE: DWORD = 1606; +pub const ERROR_UNKNOWN_COMPONENT: DWORD = 1607; +pub const ERROR_UNKNOWN_PROPERTY: DWORD = 1608; +pub const ERROR_INVALID_HANDLE_STATE: DWORD = 1609; +pub const ERROR_BAD_CONFIGURATION: DWORD = 1610; +pub const ERROR_INDEX_ABSENT: DWORD = 1611; +pub const ERROR_INSTALL_SOURCE_ABSENT: DWORD = 1612; +pub const ERROR_INSTALL_PACKAGE_VERSION: DWORD = 1613; +pub const ERROR_PRODUCT_UNINSTALLED: DWORD = 1614; +pub const ERROR_BAD_QUERY_SYNTAX: DWORD = 1615; +pub const ERROR_INVALID_FIELD: DWORD = 1616; +pub const ERROR_DEVICE_REMOVED: DWORD = 1617; +pub const ERROR_INSTALL_ALREADY_RUNNING: DWORD = 1618; +pub const ERROR_INSTALL_PACKAGE_OPEN_FAILED: DWORD = 1619; +pub const ERROR_INSTALL_PACKAGE_INVALID: DWORD = 1620; +pub const ERROR_INSTALL_UI_FAILURE: DWORD = 1621; +pub const ERROR_INSTALL_LOG_FAILURE: DWORD = 1622; +pub const ERROR_INSTALL_LANGUAGE_UNSUPPORTED: DWORD = 1623; +pub const ERROR_INSTALL_TRANSFORM_FAILURE: DWORD = 1624; +pub const ERROR_INSTALL_PACKAGE_REJECTED: DWORD = 1625; +pub const ERROR_FUNCTION_NOT_CALLED: DWORD = 1626; +pub const ERROR_FUNCTION_FAILED: DWORD = 1627; +pub const ERROR_INVALID_TABLE: DWORD = 1628; +pub const ERROR_DATATYPE_MISMATCH: DWORD = 1629; +pub const ERROR_UNSUPPORTED_TYPE: DWORD = 1630; +pub const ERROR_CREATE_FAILED: DWORD = 1631; +pub const ERROR_INSTALL_TEMP_UNWRITABLE: DWORD = 1632; +pub const ERROR_INSTALL_PLATFORM_UNSUPPORTED: DWORD = 1633; +pub const ERROR_INSTALL_NOTUSED: DWORD = 1634; +pub const ERROR_PATCH_PACKAGE_OPEN_FAILED: DWORD = 1635; +pub const ERROR_PATCH_PACKAGE_INVALID: DWORD = 1636; +pub const ERROR_PATCH_PACKAGE_UNSUPPORTED: DWORD = 1637; +pub const ERROR_PRODUCT_VERSION: DWORD = 1638; +pub const ERROR_INVALID_COMMAND_LINE: DWORD = 1639; +pub const ERROR_INSTALL_REMOTE_DISALLOWED: DWORD = 1640; +pub const ERROR_SUCCESS_REBOOT_INITIATED: DWORD = 1641; +pub const ERROR_PATCH_TARGET_NOT_FOUND: DWORD = 1642; +pub const ERROR_PATCH_PACKAGE_REJECTED: DWORD = 1643; +pub const ERROR_INSTALL_TRANSFORM_REJECTED: DWORD = 1644; +pub const ERROR_INSTALL_REMOTE_PROHIBITED: DWORD = 1645; +pub const ERROR_PATCH_REMOVAL_UNSUPPORTED: DWORD = 1646; +pub const ERROR_UNKNOWN_PATCH: DWORD = 1647; +pub const ERROR_PATCH_NO_SEQUENCE: DWORD = 1648; +pub const ERROR_PATCH_REMOVAL_DISALLOWED: DWORD = 1649; +pub const ERROR_INVALID_PATCH_XML: DWORD = 1650; +pub const ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT: DWORD = 1651; +pub const ERROR_INSTALL_SERVICE_SAFEBOOT: DWORD = 1652; +pub const ERROR_FAIL_FAST_EXCEPTION: DWORD = 1653; +pub const ERROR_INSTALL_REJECTED: DWORD = 1654; +pub const ERROR_DYNAMIC_CODE_BLOCKED: DWORD = 1655; +pub const RPC_S_INVALID_STRING_BINDING: DWORD = 1700; +pub const RPC_S_WRONG_KIND_OF_BINDING: DWORD = 1701; +pub const RPC_S_INVALID_BINDING: DWORD = 1702; +pub const RPC_S_PROTSEQ_NOT_SUPPORTED: DWORD = 1703; +pub const RPC_S_INVALID_RPC_PROTSEQ: DWORD = 1704; +pub const RPC_S_INVALID_STRING_UUID: DWORD = 1705; +pub const RPC_S_INVALID_ENDPOINT_FORMAT: DWORD = 1706; +pub const RPC_S_INVALID_NET_ADDR: DWORD = 1707; +pub const RPC_S_NO_ENDPOINT_FOUND: DWORD = 1708; +pub const RPC_S_INVALID_TIMEOUT: DWORD = 1709; +pub const RPC_S_OBJECT_NOT_FOUND: DWORD = 1710; +pub const RPC_S_ALREADY_REGISTERED: DWORD = 1711; +pub const RPC_S_TYPE_ALREADY_REGISTERED: DWORD = 1712; +pub const RPC_S_ALREADY_LISTENING: DWORD = 1713; +pub const RPC_S_NO_PROTSEQS_REGISTERED: DWORD = 1714; +pub const RPC_S_NOT_LISTENING: DWORD = 1715; +pub const RPC_S_UNKNOWN_MGR_TYPE: DWORD = 1716; +pub const RPC_S_UNKNOWN_IF: DWORD = 1717; +pub const RPC_S_NO_BINDINGS: DWORD = 1718; +pub const RPC_S_NO_PROTSEQS: DWORD = 1719; +pub const RPC_S_CANT_CREATE_ENDPOINT: DWORD = 1720; +pub const RPC_S_OUT_OF_RESOURCES: DWORD = 1721; +pub const RPC_S_SERVER_UNAVAILABLE: DWORD = 1722; +pub const RPC_S_SERVER_TOO_BUSY: DWORD = 1723; +pub const RPC_S_INVALID_NETWORK_OPTIONS: DWORD = 1724; +pub const RPC_S_NO_CALL_ACTIVE: DWORD = 1725; +pub const RPC_S_CALL_FAILED: DWORD = 1726; +pub const RPC_S_CALL_FAILED_DNE: DWORD = 1727; +pub const RPC_S_PROTOCOL_ERROR: DWORD = 1728; +pub const RPC_S_PROXY_ACCESS_DENIED: DWORD = 1729; +pub const RPC_S_UNSUPPORTED_TRANS_SYN: DWORD = 1730; +pub const RPC_S_UNSUPPORTED_TYPE: DWORD = 1732; +pub const RPC_S_INVALID_TAG: DWORD = 1733; +pub const RPC_S_INVALID_BOUND: DWORD = 1734; +pub const RPC_S_NO_ENTRY_NAME: DWORD = 1735; +pub const RPC_S_INVALID_NAME_SYNTAX: DWORD = 1736; +pub const RPC_S_UNSUPPORTED_NAME_SYNTAX: DWORD = 1737; +pub const RPC_S_UUID_NO_ADDRESS: DWORD = 1739; +pub const RPC_S_DUPLICATE_ENDPOINT: DWORD = 1740; +pub const RPC_S_UNKNOWN_AUTHN_TYPE: DWORD = 1741; +pub const RPC_S_MAX_CALLS_TOO_SMALL: DWORD = 1742; +pub const RPC_S_STRING_TOO_LONG: DWORD = 1743; +pub const RPC_S_PROTSEQ_NOT_FOUND: DWORD = 1744; +pub const RPC_S_PROCNUM_OUT_OF_RANGE: DWORD = 1745; +pub const RPC_S_BINDING_HAS_NO_AUTH: DWORD = 1746; +pub const RPC_S_UNKNOWN_AUTHN_SERVICE: DWORD = 1747; +pub const RPC_S_UNKNOWN_AUTHN_LEVEL: DWORD = 1748; +pub const RPC_S_INVALID_AUTH_IDENTITY: DWORD = 1749; +pub const RPC_S_UNKNOWN_AUTHZ_SERVICE: DWORD = 1750; +pub const EPT_S_INVALID_ENTRY: DWORD = 1751; +pub const EPT_S_CANT_PERFORM_OP: DWORD = 1752; +pub const EPT_S_NOT_REGISTERED: DWORD = 1753; +pub const RPC_S_NOTHING_TO_EXPORT: DWORD = 1754; +pub const RPC_S_INCOMPLETE_NAME: DWORD = 1755; +pub const RPC_S_INVALID_VERS_OPTION: DWORD = 1756; +pub const RPC_S_NO_MORE_MEMBERS: DWORD = 1757; +pub const RPC_S_NOT_ALL_OBJS_UNEXPORTED: DWORD = 1758; +pub const RPC_S_INTERFACE_NOT_FOUND: DWORD = 1759; +pub const RPC_S_ENTRY_ALREADY_EXISTS: DWORD = 1760; +pub const RPC_S_ENTRY_NOT_FOUND: DWORD = 1761; +pub const RPC_S_NAME_SERVICE_UNAVAILABLE: DWORD = 1762; +pub const RPC_S_INVALID_NAF_ID: DWORD = 1763; +pub const RPC_S_CANNOT_SUPPORT: DWORD = 1764; +pub const RPC_S_NO_CONTEXT_AVAILABLE: DWORD = 1765; +pub const RPC_S_INTERNAL_ERROR: DWORD = 1766; +pub const RPC_S_ZERO_DIVIDE: DWORD = 1767; +pub const RPC_S_ADDRESS_ERROR: DWORD = 1768; +pub const RPC_S_FP_DIV_ZERO: DWORD = 1769; +pub const RPC_S_FP_UNDERFLOW: DWORD = 1770; +pub const RPC_S_FP_OVERFLOW: DWORD = 1771; +pub const RPC_X_NO_MORE_ENTRIES: DWORD = 1772; +pub const RPC_X_SS_CHAR_TRANS_OPEN_FAIL: DWORD = 1773; +pub const RPC_X_SS_CHAR_TRANS_SHORT_FILE: DWORD = 1774; +pub const RPC_X_SS_IN_NULL_CONTEXT: DWORD = 1775; +pub const RPC_X_SS_CONTEXT_DAMAGED: DWORD = 1777; +pub const RPC_X_SS_HANDLES_MISMATCH: DWORD = 1778; +pub const RPC_X_SS_CANNOT_GET_CALL_HANDLE: DWORD = 1779; +pub const RPC_X_NULL_REF_POINTER: DWORD = 1780; +pub const RPC_X_ENUM_VALUE_OUT_OF_RANGE: DWORD = 1781; +pub const RPC_X_BYTE_COUNT_TOO_SMALL: DWORD = 1782; +pub const RPC_X_BAD_STUB_DATA: DWORD = 1783; +pub const ERROR_INVALID_USER_BUFFER: DWORD = 1784; +pub const ERROR_UNRECOGNIZED_MEDIA: DWORD = 1785; +pub const ERROR_NO_TRUST_LSA_SECRET: DWORD = 1786; +pub const ERROR_NO_TRUST_SAM_ACCOUNT: DWORD = 1787; +pub const ERROR_TRUSTED_DOMAIN_FAILURE: DWORD = 1788; +pub const ERROR_TRUSTED_RELATIONSHIP_FAILURE: DWORD = 1789; +pub const ERROR_TRUST_FAILURE: DWORD = 1790; +pub const RPC_S_CALL_IN_PROGRESS: DWORD = 1791; +pub const ERROR_NETLOGON_NOT_STARTED: DWORD = 1792; +pub const ERROR_ACCOUNT_EXPIRED: DWORD = 1793; +pub const ERROR_REDIRECTOR_HAS_OPEN_HANDLES: DWORD = 1794; +pub const ERROR_PRINTER_DRIVER_ALREADY_INSTALLED: DWORD = 1795; +pub const ERROR_UNKNOWN_PORT: DWORD = 1796; +pub const ERROR_UNKNOWN_PRINTER_DRIVER: DWORD = 1797; +pub const ERROR_UNKNOWN_PRINTPROCESSOR: DWORD = 1798; +pub const ERROR_INVALID_SEPARATOR_FILE: DWORD = 1799; +pub const ERROR_INVALID_PRIORITY: DWORD = 1800; +pub const ERROR_INVALID_PRINTER_NAME: DWORD = 1801; +pub const ERROR_PRINTER_ALREADY_EXISTS: DWORD = 1802; +pub const ERROR_INVALID_PRINTER_COMMAND: DWORD = 1803; +pub const ERROR_INVALID_DATATYPE: DWORD = 1804; +pub const ERROR_INVALID_ENVIRONMENT: DWORD = 1805; +pub const RPC_S_NO_MORE_BINDINGS: DWORD = 1806; +pub const ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: DWORD = 1807; +pub const ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT: DWORD = 1808; +pub const ERROR_NOLOGON_SERVER_TRUST_ACCOUNT: DWORD = 1809; +pub const ERROR_DOMAIN_TRUST_INCONSISTENT: DWORD = 1810; +pub const ERROR_SERVER_HAS_OPEN_HANDLES: DWORD = 1811; +pub const ERROR_RESOURCE_DATA_NOT_FOUND: DWORD = 1812; +pub const ERROR_RESOURCE_TYPE_NOT_FOUND: DWORD = 1813; +pub const ERROR_RESOURCE_NAME_NOT_FOUND: DWORD = 1814; +pub const ERROR_RESOURCE_LANG_NOT_FOUND: DWORD = 1815; +pub const ERROR_NOT_ENOUGH_QUOTA: DWORD = 1816; +pub const RPC_S_NO_INTERFACES: DWORD = 1817; +pub const RPC_S_CALL_CANCELLED: DWORD = 1818; +pub const RPC_S_BINDING_INCOMPLETE: DWORD = 1819; +pub const RPC_S_COMM_FAILURE: DWORD = 1820; +pub const RPC_S_UNSUPPORTED_AUTHN_LEVEL: DWORD = 1821; +pub const RPC_S_NO_PRINC_NAME: DWORD = 1822; +pub const RPC_S_NOT_RPC_ERROR: DWORD = 1823; +pub const RPC_S_UUID_LOCAL_ONLY: DWORD = 1824; +pub const RPC_S_SEC_PKG_ERROR: DWORD = 1825; +pub const RPC_S_NOT_CANCELLED: DWORD = 1826; +pub const RPC_X_INVALID_ES_ACTION: DWORD = 1827; +pub const RPC_X_WRONG_ES_VERSION: DWORD = 1828; +pub const RPC_X_WRONG_STUB_VERSION: DWORD = 1829; +pub const RPC_X_INVALID_PIPE_OBJECT: DWORD = 1830; +pub const RPC_X_WRONG_PIPE_ORDER: DWORD = 1831; +pub const RPC_X_WRONG_PIPE_VERSION: DWORD = 1832; +pub const RPC_S_COOKIE_AUTH_FAILED: DWORD = 1833; +pub const RPC_S_GROUP_MEMBER_NOT_FOUND: DWORD = 1898; +pub const EPT_S_CANT_CREATE: DWORD = 1899; +pub const RPC_S_INVALID_OBJECT: DWORD = 1900; +pub const ERROR_INVALID_TIME: DWORD = 1901; +pub const ERROR_INVALID_FORM_NAME: DWORD = 1902; +pub const ERROR_INVALID_FORM_SIZE: DWORD = 1903; +pub const ERROR_ALREADY_WAITING: DWORD = 1904; +pub const ERROR_PRINTER_DELETED: DWORD = 1905; +pub const ERROR_INVALID_PRINTER_STATE: DWORD = 1906; +pub const ERROR_PASSWORD_MUST_CHANGE: DWORD = 1907; +pub const ERROR_DOMAIN_CONTROLLER_NOT_FOUND: DWORD = 1908; +pub const ERROR_ACCOUNT_LOCKED_OUT: DWORD = 1909; +pub const OR_INVALID_OXID: DWORD = 1910; +pub const OR_INVALID_OID: DWORD = 1911; +pub const OR_INVALID_SET: DWORD = 1912; +pub const RPC_S_SEND_INCOMPLETE: DWORD = 1913; +pub const RPC_S_INVALID_ASYNC_HANDLE: DWORD = 1914; +pub const RPC_S_INVALID_ASYNC_CALL: DWORD = 1915; +pub const RPC_X_PIPE_CLOSED: DWORD = 1916; +pub const RPC_X_PIPE_DISCIPLINE_ERROR: DWORD = 1917; +pub const RPC_X_PIPE_EMPTY: DWORD = 1918; +pub const ERROR_NO_SITENAME: DWORD = 1919; +pub const ERROR_CANT_ACCESS_FILE: DWORD = 1920; +pub const ERROR_CANT_RESOLVE_FILENAME: DWORD = 1921; +pub const RPC_S_ENTRY_TYPE_MISMATCH: DWORD = 1922; +pub const RPC_S_NOT_ALL_OBJS_EXPORTED: DWORD = 1923; +pub const RPC_S_INTERFACE_NOT_EXPORTED: DWORD = 1924; +pub const RPC_S_PROFILE_NOT_ADDED: DWORD = 1925; +pub const RPC_S_PRF_ELT_NOT_ADDED: DWORD = 1926; +pub const RPC_S_PRF_ELT_NOT_REMOVED: DWORD = 1927; +pub const RPC_S_GRP_ELT_NOT_ADDED: DWORD = 1928; +pub const RPC_S_GRP_ELT_NOT_REMOVED: DWORD = 1929; +pub const ERROR_KM_DRIVER_BLOCKED: DWORD = 1930; +pub const ERROR_CONTEXT_EXPIRED: DWORD = 1931; +pub const ERROR_PER_USER_TRUST_QUOTA_EXCEEDED: DWORD = 1932; +pub const ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED: DWORD = 1933; +pub const ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED: DWORD = 1934; +pub const ERROR_AUTHENTICATION_FIREWALL_FAILED: DWORD = 1935; +pub const ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED: DWORD = 1936; +pub const ERROR_NTLM_BLOCKED: DWORD = 1937; +pub const ERROR_PASSWORD_CHANGE_REQUIRED: DWORD = 1938; +pub const ERROR_INVALID_PIXEL_FORMAT: DWORD = 2000; +pub const ERROR_BAD_DRIVER: DWORD = 2001; +pub const ERROR_INVALID_WINDOW_STYLE: DWORD = 2002; +pub const ERROR_METAFILE_NOT_SUPPORTED: DWORD = 2003; +pub const ERROR_TRANSFORM_NOT_SUPPORTED: DWORD = 2004; +pub const ERROR_CLIPPING_NOT_SUPPORTED: DWORD = 2005; +pub const ERROR_INVALID_CMM: DWORD = 2010; +pub const ERROR_INVALID_PROFILE: DWORD = 2011; +pub const ERROR_TAG_NOT_FOUND: DWORD = 2012; +pub const ERROR_TAG_NOT_PRESENT: DWORD = 2013; +pub const ERROR_DUPLICATE_TAG: DWORD = 2014; +pub const ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE: DWORD = 2015; +pub const ERROR_PROFILE_NOT_FOUND: DWORD = 2016; +pub const ERROR_INVALID_COLORSPACE: DWORD = 2017; +pub const ERROR_ICM_NOT_ENABLED: DWORD = 2018; +pub const ERROR_DELETING_ICM_XFORM: DWORD = 2019; +pub const ERROR_INVALID_TRANSFORM: DWORD = 2020; +pub const ERROR_COLORSPACE_MISMATCH: DWORD = 2021; +pub const ERROR_INVALID_COLORINDEX: DWORD = 2022; +pub const ERROR_PROFILE_DOES_NOT_MATCH_DEVICE: DWORD = 2023; +pub const ERROR_CONNECTED_OTHER_PASSWORD: DWORD = 2108; +pub const ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT: DWORD = 2109; +pub const ERROR_BAD_USERNAME: DWORD = 2202; +pub const ERROR_NOT_CONNECTED: DWORD = 2250; +pub const ERROR_OPEN_FILES: DWORD = 2401; +pub const ERROR_ACTIVE_CONNECTIONS: DWORD = 2402; +pub const ERROR_DEVICE_IN_USE: DWORD = 2404; +pub const ERROR_UNKNOWN_PRINT_MONITOR: DWORD = 3000; +pub const ERROR_PRINTER_DRIVER_IN_USE: DWORD = 3001; +pub const ERROR_SPOOL_FILE_NOT_FOUND: DWORD = 3002; +pub const ERROR_SPL_NO_STARTDOC: DWORD = 3003; +pub const ERROR_SPL_NO_ADDJOB: DWORD = 3004; +pub const ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED: DWORD = 3005; +pub const ERROR_PRINT_MONITOR_ALREADY_INSTALLED: DWORD = 3006; +pub const ERROR_INVALID_PRINT_MONITOR: DWORD = 3007; +pub const ERROR_PRINT_MONITOR_IN_USE: DWORD = 3008; +pub const ERROR_PRINTER_HAS_JOBS_QUEUED: DWORD = 3009; +pub const ERROR_SUCCESS_REBOOT_REQUIRED: DWORD = 3010; +pub const ERROR_SUCCESS_RESTART_REQUIRED: DWORD = 3011; +pub const ERROR_PRINTER_NOT_FOUND: DWORD = 3012; +pub const ERROR_PRINTER_DRIVER_WARNED: DWORD = 3013; +pub const ERROR_PRINTER_DRIVER_BLOCKED: DWORD = 3014; +pub const ERROR_PRINTER_DRIVER_PACKAGE_IN_USE: DWORD = 3015; +pub const ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND: DWORD = 3016; +pub const ERROR_FAIL_REBOOT_REQUIRED: DWORD = 3017; +pub const ERROR_FAIL_REBOOT_INITIATED: DWORD = 3018; +pub const ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED: DWORD = 3019; +pub const ERROR_PRINT_JOB_RESTART_REQUIRED: DWORD = 3020; +pub const ERROR_INVALID_PRINTER_DRIVER_MANIFEST: DWORD = 3021; +pub const ERROR_PRINTER_NOT_SHAREABLE: DWORD = 3022; +pub const ERROR_REQUEST_PAUSED: DWORD = 3050; +pub const ERROR_IO_REISSUE_AS_CACHED: DWORD = 3950; +pub const ERROR_WINS_INTERNAL: DWORD = 4000; +pub const ERROR_CAN_NOT_DEL_LOCAL_WINS: DWORD = 4001; +pub const ERROR_STATIC_INIT: DWORD = 4002; +pub const ERROR_INC_BACKUP: DWORD = 4003; +pub const ERROR_FULL_BACKUP: DWORD = 4004; +pub const ERROR_REC_NON_EXISTENT: DWORD = 4005; +pub const ERROR_RPL_NOT_ALLOWED: DWORD = 4006; +pub const PEERDIST_ERROR_CONTENTINFO_VERSION_UNSUPPORTED: DWORD = 4050; +pub const PEERDIST_ERROR_CANNOT_PARSE_CONTENTINFO: DWORD = 4051; +pub const PEERDIST_ERROR_MISSING_DATA: DWORD = 4052; +pub const PEERDIST_ERROR_NO_MORE: DWORD = 4053; +pub const PEERDIST_ERROR_NOT_INITIALIZED: DWORD = 4054; +pub const PEERDIST_ERROR_ALREADY_INITIALIZED: DWORD = 4055; +pub const PEERDIST_ERROR_SHUTDOWN_IN_PROGRESS: DWORD = 4056; +pub const PEERDIST_ERROR_INVALIDATED: DWORD = 4057; +pub const PEERDIST_ERROR_ALREADY_EXISTS: DWORD = 4058; +pub const PEERDIST_ERROR_OPERATION_NOTFOUND: DWORD = 4059; +pub const PEERDIST_ERROR_ALREADY_COMPLETED: DWORD = 4060; +pub const PEERDIST_ERROR_OUT_OF_BOUNDS: DWORD = 4061; +pub const PEERDIST_ERROR_VERSION_UNSUPPORTED: DWORD = 4062; +pub const PEERDIST_ERROR_INVALID_CONFIGURATION: DWORD = 4063; +pub const PEERDIST_ERROR_NOT_LICENSED: DWORD = 4064; +pub const PEERDIST_ERROR_SERVICE_UNAVAILABLE: DWORD = 4065; +pub const PEERDIST_ERROR_TRUST_FAILURE: DWORD = 4066; +pub const ERROR_DHCP_ADDRESS_CONFLICT: DWORD = 4100; +pub const ERROR_WMI_GUID_NOT_FOUND: DWORD = 4200; +pub const ERROR_WMI_INSTANCE_NOT_FOUND: DWORD = 4201; +pub const ERROR_WMI_ITEMID_NOT_FOUND: DWORD = 4202; +pub const ERROR_WMI_TRY_AGAIN: DWORD = 4203; +pub const ERROR_WMI_DP_NOT_FOUND: DWORD = 4204; +pub const ERROR_WMI_UNRESOLVED_INSTANCE_REF: DWORD = 4205; +pub const ERROR_WMI_ALREADY_ENABLED: DWORD = 4206; +pub const ERROR_WMI_GUID_DISCONNECTED: DWORD = 4207; +pub const ERROR_WMI_SERVER_UNAVAILABLE: DWORD = 4208; +pub const ERROR_WMI_DP_FAILED: DWORD = 4209; +pub const ERROR_WMI_INVALID_MOF: DWORD = 4210; +pub const ERROR_WMI_INVALID_REGINFO: DWORD = 4211; +pub const ERROR_WMI_ALREADY_DISABLED: DWORD = 4212; +pub const ERROR_WMI_READ_ONLY: DWORD = 4213; +pub const ERROR_WMI_SET_FAILURE: DWORD = 4214; +pub const ERROR_NOT_APPCONTAINER: DWORD = 4250; +pub const ERROR_APPCONTAINER_REQUIRED: DWORD = 4251; +pub const ERROR_NOT_SUPPORTED_IN_APPCONTAINER: DWORD = 4252; +pub const ERROR_INVALID_PACKAGE_SID_LENGTH: DWORD = 4253; +pub const ERROR_INVALID_MEDIA: DWORD = 4300; +pub const ERROR_INVALID_LIBRARY: DWORD = 4301; +pub const ERROR_INVALID_MEDIA_POOL: DWORD = 4302; +pub const ERROR_DRIVE_MEDIA_MISMATCH: DWORD = 4303; +pub const ERROR_MEDIA_OFFLINE: DWORD = 4304; +pub const ERROR_LIBRARY_OFFLINE: DWORD = 4305; +pub const ERROR_EMPTY: DWORD = 4306; +pub const ERROR_NOT_EMPTY: DWORD = 4307; +pub const ERROR_MEDIA_UNAVAILABLE: DWORD = 4308; +pub const ERROR_RESOURCE_DISABLED: DWORD = 4309; +pub const ERROR_INVALID_CLEANER: DWORD = 4310; +pub const ERROR_UNABLE_TO_CLEAN: DWORD = 4311; +pub const ERROR_OBJECT_NOT_FOUND: DWORD = 4312; +pub const ERROR_DATABASE_FAILURE: DWORD = 4313; +pub const ERROR_DATABASE_FULL: DWORD = 4314; +pub const ERROR_MEDIA_INCOMPATIBLE: DWORD = 4315; +pub const ERROR_RESOURCE_NOT_PRESENT: DWORD = 4316; +pub const ERROR_INVALID_OPERATION: DWORD = 4317; +pub const ERROR_MEDIA_NOT_AVAILABLE: DWORD = 4318; +pub const ERROR_DEVICE_NOT_AVAILABLE: DWORD = 4319; +pub const ERROR_REQUEST_REFUSED: DWORD = 4320; +pub const ERROR_INVALID_DRIVE_OBJECT: DWORD = 4321; +pub const ERROR_LIBRARY_FULL: DWORD = 4322; +pub const ERROR_MEDIUM_NOT_ACCESSIBLE: DWORD = 4323; +pub const ERROR_UNABLE_TO_LOAD_MEDIUM: DWORD = 4324; +pub const ERROR_UNABLE_TO_INVENTORY_DRIVE: DWORD = 4325; +pub const ERROR_UNABLE_TO_INVENTORY_SLOT: DWORD = 4326; +pub const ERROR_UNABLE_TO_INVENTORY_TRANSPORT: DWORD = 4327; +pub const ERROR_TRANSPORT_FULL: DWORD = 4328; +pub const ERROR_CONTROLLING_IEPORT: DWORD = 4329; +pub const ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA: DWORD = 4330; +pub const ERROR_CLEANER_SLOT_SET: DWORD = 4331; +pub const ERROR_CLEANER_SLOT_NOT_SET: DWORD = 4332; +pub const ERROR_CLEANER_CARTRIDGE_SPENT: DWORD = 4333; +pub const ERROR_UNEXPECTED_OMID: DWORD = 4334; +pub const ERROR_CANT_DELETE_LAST_ITEM: DWORD = 4335; +pub const ERROR_MESSAGE_EXCEEDS_MAX_SIZE: DWORD = 4336; +pub const ERROR_VOLUME_CONTAINS_SYS_FILES: DWORD = 4337; +pub const ERROR_INDIGENOUS_TYPE: DWORD = 4338; +pub const ERROR_NO_SUPPORTING_DRIVES: DWORD = 4339; +pub const ERROR_CLEANER_CARTRIDGE_INSTALLED: DWORD = 4340; +pub const ERROR_IEPORT_FULL: DWORD = 4341; +pub const ERROR_FILE_OFFLINE: DWORD = 4350; +pub const ERROR_REMOTE_STORAGE_NOT_ACTIVE: DWORD = 4351; +pub const ERROR_REMOTE_STORAGE_MEDIA_ERROR: DWORD = 4352; +pub const ERROR_NOT_A_REPARSE_POINT: DWORD = 4390; +pub const ERROR_REPARSE_ATTRIBUTE_CONFLICT: DWORD = 4391; +pub const ERROR_INVALID_REPARSE_DATA: DWORD = 4392; +pub const ERROR_REPARSE_TAG_INVALID: DWORD = 4393; +pub const ERROR_REPARSE_TAG_MISMATCH: DWORD = 4394; +pub const ERROR_APP_DATA_NOT_FOUND: DWORD = 4400; +pub const ERROR_APP_DATA_EXPIRED: DWORD = 4401; +pub const ERROR_APP_DATA_CORRUPT: DWORD = 4402; +pub const ERROR_APP_DATA_LIMIT_EXCEEDED: DWORD = 4403; +pub const ERROR_APP_DATA_REBOOT_REQUIRED: DWORD = 4404; +pub const ERROR_SECUREBOOT_ROLLBACK_DETECTED: DWORD = 4420; +pub const ERROR_SECUREBOOT_POLICY_VIOLATION: DWORD = 4421; +pub const ERROR_SECUREBOOT_INVALID_POLICY: DWORD = 4422; +pub const ERROR_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND: DWORD = 4423; +pub const ERROR_SECUREBOOT_POLICY_NOT_SIGNED: DWORD = 4424; +pub const ERROR_SECUREBOOT_NOT_ENABLED: DWORD = 4425; +pub const ERROR_SECUREBOOT_FILE_REPLACED: DWORD = 4426; +pub const ERROR_OFFLOAD_READ_FLT_NOT_SUPPORTED: DWORD = 4440; +pub const ERROR_OFFLOAD_WRITE_FLT_NOT_SUPPORTED: DWORD = 4441; +pub const ERROR_OFFLOAD_READ_FILE_NOT_SUPPORTED: DWORD = 4442; +pub const ERROR_OFFLOAD_WRITE_FILE_NOT_SUPPORTED: DWORD = 4443; +pub const ERROR_VOLUME_NOT_SIS_ENABLED: DWORD = 4500; +pub const ERROR_DEPENDENT_RESOURCE_EXISTS: DWORD = 5001; +pub const ERROR_DEPENDENCY_NOT_FOUND: DWORD = 5002; +pub const ERROR_DEPENDENCY_ALREADY_EXISTS: DWORD = 5003; +pub const ERROR_RESOURCE_NOT_ONLINE: DWORD = 5004; +pub const ERROR_HOST_NODE_NOT_AVAILABLE: DWORD = 5005; +pub const ERROR_RESOURCE_NOT_AVAILABLE: DWORD = 5006; +pub const ERROR_RESOURCE_NOT_FOUND: DWORD = 5007; +pub const ERROR_SHUTDOWN_CLUSTER: DWORD = 5008; +pub const ERROR_CANT_EVICT_ACTIVE_NODE: DWORD = 5009; +pub const ERROR_OBJECT_ALREADY_EXISTS: DWORD = 5010; +pub const ERROR_OBJECT_IN_LIST: DWORD = 5011; +pub const ERROR_GROUP_NOT_AVAILABLE: DWORD = 5012; +pub const ERROR_GROUP_NOT_FOUND: DWORD = 5013; +pub const ERROR_GROUP_NOT_ONLINE: DWORD = 5014; +pub const ERROR_HOST_NODE_NOT_RESOURCE_OWNER: DWORD = 5015; +pub const ERROR_HOST_NODE_NOT_GROUP_OWNER: DWORD = 5016; +pub const ERROR_RESMON_CREATE_FAILED: DWORD = 5017; +pub const ERROR_RESMON_ONLINE_FAILED: DWORD = 5018; +pub const ERROR_RESOURCE_ONLINE: DWORD = 5019; +pub const ERROR_QUORUM_RESOURCE: DWORD = 5020; +pub const ERROR_NOT_QUORUM_CAPABLE: DWORD = 5021; +pub const ERROR_CLUSTER_SHUTTING_DOWN: DWORD = 5022; +pub const ERROR_INVALID_STATE: DWORD = 5023; +pub const ERROR_RESOURCE_PROPERTIES_STORED: DWORD = 5024; +pub const ERROR_NOT_QUORUM_CLASS: DWORD = 5025; +pub const ERROR_CORE_RESOURCE: DWORD = 5026; +pub const ERROR_QUORUM_RESOURCE_ONLINE_FAILED: DWORD = 5027; +pub const ERROR_QUORUMLOG_OPEN_FAILED: DWORD = 5028; +pub const ERROR_CLUSTERLOG_CORRUPT: DWORD = 5029; +pub const ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE: DWORD = 5030; +pub const ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE: DWORD = 5031; +pub const ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND: DWORD = 5032; +pub const ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE: DWORD = 5033; +pub const ERROR_QUORUM_OWNER_ALIVE: DWORD = 5034; +pub const ERROR_NETWORK_NOT_AVAILABLE: DWORD = 5035; +pub const ERROR_NODE_NOT_AVAILABLE: DWORD = 5036; +pub const ERROR_ALL_NODES_NOT_AVAILABLE: DWORD = 5037; +pub const ERROR_RESOURCE_FAILED: DWORD = 5038; +pub const ERROR_CLUSTER_INVALID_NODE: DWORD = 5039; +pub const ERROR_CLUSTER_NODE_EXISTS: DWORD = 5040; +pub const ERROR_CLUSTER_JOIN_IN_PROGRESS: DWORD = 5041; +pub const ERROR_CLUSTER_NODE_NOT_FOUND: DWORD = 5042; +pub const ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND: DWORD = 5043; +pub const ERROR_CLUSTER_NETWORK_EXISTS: DWORD = 5044; +pub const ERROR_CLUSTER_NETWORK_NOT_FOUND: DWORD = 5045; +pub const ERROR_CLUSTER_NETINTERFACE_EXISTS: DWORD = 5046; +pub const ERROR_CLUSTER_NETINTERFACE_NOT_FOUND: DWORD = 5047; +pub const ERROR_CLUSTER_INVALID_REQUEST: DWORD = 5048; +pub const ERROR_CLUSTER_INVALID_NETWORK_PROVIDER: DWORD = 5049; +pub const ERROR_CLUSTER_NODE_DOWN: DWORD = 5050; +pub const ERROR_CLUSTER_NODE_UNREACHABLE: DWORD = 5051; +pub const ERROR_CLUSTER_NODE_NOT_MEMBER: DWORD = 5052; +pub const ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS: DWORD = 5053; +pub const ERROR_CLUSTER_INVALID_NETWORK: DWORD = 5054; +pub const ERROR_CLUSTER_NODE_UP: DWORD = 5056; +pub const ERROR_CLUSTER_IPADDR_IN_USE: DWORD = 5057; +pub const ERROR_CLUSTER_NODE_NOT_PAUSED: DWORD = 5058; +pub const ERROR_CLUSTER_NO_SECURITY_CONTEXT: DWORD = 5059; +pub const ERROR_CLUSTER_NETWORK_NOT_INTERNAL: DWORD = 5060; +pub const ERROR_CLUSTER_NODE_ALREADY_UP: DWORD = 5061; +pub const ERROR_CLUSTER_NODE_ALREADY_DOWN: DWORD = 5062; +pub const ERROR_CLUSTER_NETWORK_ALREADY_ONLINE: DWORD = 5063; +pub const ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE: DWORD = 5064; +pub const ERROR_CLUSTER_NODE_ALREADY_MEMBER: DWORD = 5065; +pub const ERROR_CLUSTER_LAST_INTERNAL_NETWORK: DWORD = 5066; +pub const ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS: DWORD = 5067; +pub const ERROR_INVALID_OPERATION_ON_QUORUM: DWORD = 5068; +pub const ERROR_DEPENDENCY_NOT_ALLOWED: DWORD = 5069; +pub const ERROR_CLUSTER_NODE_PAUSED: DWORD = 5070; +pub const ERROR_NODE_CANT_HOST_RESOURCE: DWORD = 5071; +pub const ERROR_CLUSTER_NODE_NOT_READY: DWORD = 5072; +pub const ERROR_CLUSTER_NODE_SHUTTING_DOWN: DWORD = 5073; +pub const ERROR_CLUSTER_JOIN_ABORTED: DWORD = 5074; +pub const ERROR_CLUSTER_INCOMPATIBLE_VERSIONS: DWORD = 5075; +pub const ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED: DWORD = 5076; +pub const ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED: DWORD = 5077; +pub const ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND: DWORD = 5078; +pub const ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED: DWORD = 5079; +pub const ERROR_CLUSTER_RESNAME_NOT_FOUND: DWORD = 5080; +pub const ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED: DWORD = 5081; +pub const ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST: DWORD = 5082; +pub const ERROR_CLUSTER_DATABASE_SEQMISMATCH: DWORD = 5083; +pub const ERROR_RESMON_INVALID_STATE: DWORD = 5084; +pub const ERROR_CLUSTER_GUM_NOT_LOCKER: DWORD = 5085; +pub const ERROR_QUORUM_DISK_NOT_FOUND: DWORD = 5086; +pub const ERROR_DATABASE_BACKUP_CORRUPT: DWORD = 5087; +pub const ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT: DWORD = 5088; +pub const ERROR_RESOURCE_PROPERTY_UNCHANGEABLE: DWORD = 5089; +pub const ERROR_NO_ADMIN_ACCESS_POINT: DWORD = 5090; +pub const ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE: DWORD = 5890; +pub const ERROR_CLUSTER_QUORUMLOG_NOT_FOUND: DWORD = 5891; +pub const ERROR_CLUSTER_MEMBERSHIP_HALT: DWORD = 5892; +pub const ERROR_CLUSTER_INSTANCE_ID_MISMATCH: DWORD = 5893; +pub const ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP: DWORD = 5894; +pub const ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH: DWORD = 5895; +pub const ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP: DWORD = 5896; +pub const ERROR_CLUSTER_PARAMETER_MISMATCH: DWORD = 5897; +pub const ERROR_NODE_CANNOT_BE_CLUSTERED: DWORD = 5898; +pub const ERROR_CLUSTER_WRONG_OS_VERSION: DWORD = 5899; +pub const ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME: DWORD = 5900; +pub const ERROR_CLUSCFG_ALREADY_COMMITTED: DWORD = 5901; +pub const ERROR_CLUSCFG_ROLLBACK_FAILED: DWORD = 5902; +pub const ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT: DWORD = 5903; +pub const ERROR_CLUSTER_OLD_VERSION: DWORD = 5904; +pub const ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME: DWORD = 5905; +pub const ERROR_CLUSTER_NO_NET_ADAPTERS: DWORD = 5906; +pub const ERROR_CLUSTER_POISONED: DWORD = 5907; +pub const ERROR_CLUSTER_GROUP_MOVING: DWORD = 5908; +pub const ERROR_CLUSTER_RESOURCE_TYPE_BUSY: DWORD = 5909; +pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; +pub const ERROR_INVALID_CLUSTER_IPV6_ADDRESS: DWORD = 5911; +pub const ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION: DWORD = 5912; +pub const ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS: DWORD = 5913; +pub const ERROR_CLUSTER_PARTIAL_SEND: DWORD = 5914; +pub const ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION: DWORD = 5915; +pub const ERROR_CLUSTER_INVALID_STRING_TERMINATION: DWORD = 5916; +pub const ERROR_CLUSTER_INVALID_STRING_FORMAT: DWORD = 5917; +pub const ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS: DWORD = 5918; +pub const ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS: DWORD = 5919; +pub const ERROR_CLUSTER_NULL_DATA: DWORD = 5920; +pub const ERROR_CLUSTER_PARTIAL_READ: DWORD = 5921; +pub const ERROR_CLUSTER_PARTIAL_WRITE: DWORD = 5922; +pub const ERROR_CLUSTER_CANT_DESERIALIZE_DATA: DWORD = 5923; +pub const ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT: DWORD = 5924; +pub const ERROR_CLUSTER_NO_QUORUM: DWORD = 5925; +pub const ERROR_CLUSTER_INVALID_IPV6_NETWORK: DWORD = 5926; +pub const ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK: DWORD = 5927; +pub const ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP: DWORD = 5928; +pub const ERROR_DEPENDENCY_TREE_TOO_COMPLEX: DWORD = 5929; +pub const ERROR_EXCEPTION_IN_RESOURCE_CALL: DWORD = 5930; +pub const ERROR_CLUSTER_RHS_FAILED_INITIALIZATION: DWORD = 5931; +pub const ERROR_CLUSTER_NOT_INSTALLED: DWORD = 5932; +pub const ERROR_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE: DWORD = 5933; +pub const ERROR_CLUSTER_MAX_NODES_IN_CLUSTER: DWORD = 5934; +pub const ERROR_CLUSTER_TOO_MANY_NODES: DWORD = 5935; +pub const ERROR_CLUSTER_OBJECT_ALREADY_USED: DWORD = 5936; +pub const ERROR_NONCORE_GROUPS_FOUND: DWORD = 5937; +pub const ERROR_FILE_SHARE_RESOURCE_CONFLICT: DWORD = 5938; +pub const ERROR_CLUSTER_EVICT_INVALID_REQUEST: DWORD = 5939; +pub const ERROR_CLUSTER_SINGLETON_RESOURCE: DWORD = 5940; +pub const ERROR_CLUSTER_GROUP_SINGLETON_RESOURCE: DWORD = 5941; +pub const ERROR_CLUSTER_RESOURCE_PROVIDER_FAILED: DWORD = 5942; +pub const ERROR_CLUSTER_RESOURCE_CONFIGURATION_ERROR: DWORD = 5943; +pub const ERROR_CLUSTER_GROUP_BUSY: DWORD = 5944; +pub const ERROR_CLUSTER_NOT_SHARED_VOLUME: DWORD = 5945; +pub const ERROR_CLUSTER_INVALID_SECURITY_DESCRIPTOR: DWORD = 5946; +pub const ERROR_CLUSTER_SHARED_VOLUMES_IN_USE: DWORD = 5947; +pub const ERROR_CLUSTER_USE_SHARED_VOLUMES_API: DWORD = 5948; +pub const ERROR_CLUSTER_BACKUP_IN_PROGRESS: DWORD = 5949; +pub const ERROR_NON_CSV_PATH: DWORD = 5950; +pub const ERROR_CSV_VOLUME_NOT_LOCAL: DWORD = 5951; +pub const ERROR_CLUSTER_WATCHDOG_TERMINATING: DWORD = 5952; +pub const ERROR_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES: DWORD = 5953; +pub const ERROR_CLUSTER_INVALID_NODE_WEIGHT: DWORD = 5954; +pub const ERROR_CLUSTER_RESOURCE_VETOED_CALL: DWORD = 5955; +pub const ERROR_RESMON_SYSTEM_RESOURCES_LACKING: DWORD = 5956; +pub const ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION: DWORD = 5957; +pub const ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE: DWORD = 5958; +pub const ERROR_CLUSTER_GROUP_QUEUED: DWORD = 5959; +pub const ERROR_CLUSTER_RESOURCE_LOCKED_STATUS: DWORD = 5960; +pub const ERROR_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED: DWORD = 5961; +pub const ERROR_CLUSTER_NODE_DRAIN_IN_PROGRESS: DWORD = 5962; +pub const ERROR_CLUSTER_DISK_NOT_CONNECTED: DWORD = 5963; +pub const ERROR_DISK_NOT_CSV_CAPABLE: DWORD = 5964; +pub const ERROR_RESOURCE_NOT_IN_AVAILABLE_STORAGE: DWORD = 5965; +pub const ERROR_CLUSTER_SHARED_VOLUME_REDIRECTED: DWORD = 5966; +pub const ERROR_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED: DWORD = 5967; +pub const ERROR_CLUSTER_CANNOT_RETURN_PROPERTIES: DWORD = 5968; +pub const ERROR_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES: DWORD = 5969; +pub const ERROR_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE: DWORD = 5970; +pub const ERROR_CLUSTER_AFFINITY_CONFLICT: DWORD = 5971; +pub const ERROR_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE: DWORD = 5972; +pub const ERROR_ENCRYPTION_FAILED: DWORD = 6000; +pub const ERROR_DECRYPTION_FAILED: DWORD = 6001; +pub const ERROR_FILE_ENCRYPTED: DWORD = 6002; +pub const ERROR_NO_RECOVERY_POLICY: DWORD = 6003; +pub const ERROR_NO_EFS: DWORD = 6004; +pub const ERROR_WRONG_EFS: DWORD = 6005; +pub const ERROR_NO_USER_KEYS: DWORD = 6006; +pub const ERROR_FILE_NOT_ENCRYPTED: DWORD = 6007; +pub const ERROR_NOT_EXPORT_FORMAT: DWORD = 6008; +pub const ERROR_FILE_READ_ONLY: DWORD = 6009; +pub const ERROR_DIR_EFS_DISALLOWED: DWORD = 6010; +pub const ERROR_EFS_SERVER_NOT_TRUSTED: DWORD = 6011; +pub const ERROR_BAD_RECOVERY_POLICY: DWORD = 6012; +pub const ERROR_EFS_ALG_BLOB_TOO_BIG: DWORD = 6013; +pub const ERROR_VOLUME_NOT_SUPPORT_EFS: DWORD = 6014; +pub const ERROR_EFS_DISABLED: DWORD = 6015; +pub const ERROR_EFS_VERSION_NOT_SUPPORT: DWORD = 6016; +pub const ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE: DWORD = 6017; +pub const ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER: DWORD = 6018; +pub const ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE: DWORD = 6019; +pub const ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE: DWORD = 6020; +pub const ERROR_CS_ENCRYPTION_FILE_NOT_CSE: DWORD = 6021; +pub const ERROR_ENCRYPTION_POLICY_DENIES_OPERATION: DWORD = 6022; +pub const ERROR_NO_BROWSER_SERVERS_FOUND: DWORD = 6118; +pub const SCHED_E_SERVICE_NOT_LOCALSYSTEM: DWORD = 6200; +pub const ERROR_LOG_SECTOR_INVALID: DWORD = 6600; +pub const ERROR_LOG_SECTOR_PARITY_INVALID: DWORD = 6601; +pub const ERROR_LOG_SECTOR_REMAPPED: DWORD = 6602; +pub const ERROR_LOG_BLOCK_INCOMPLETE: DWORD = 6603; +pub const ERROR_LOG_INVALID_RANGE: DWORD = 6604; +pub const ERROR_LOG_BLOCKS_EXHAUSTED: DWORD = 6605; +pub const ERROR_LOG_READ_CONTEXT_INVALID: DWORD = 6606; +pub const ERROR_LOG_RESTART_INVALID: DWORD = 6607; +pub const ERROR_LOG_BLOCK_VERSION: DWORD = 6608; +pub const ERROR_LOG_BLOCK_INVALID: DWORD = 6609; +pub const ERROR_LOG_READ_MODE_INVALID: DWORD = 6610; +pub const ERROR_LOG_NO_RESTART: DWORD = 6611; +pub const ERROR_LOG_METADATA_CORRUPT: DWORD = 6612; +pub const ERROR_LOG_METADATA_INVALID: DWORD = 6613; +pub const ERROR_LOG_METADATA_INCONSISTENT: DWORD = 6614; +pub const ERROR_LOG_RESERVATION_INVALID: DWORD = 6615; +pub const ERROR_LOG_CANT_DELETE: DWORD = 6616; +pub const ERROR_LOG_CONTAINER_LIMIT_EXCEEDED: DWORD = 6617; +pub const ERROR_LOG_START_OF_LOG: DWORD = 6618; +pub const ERROR_LOG_POLICY_ALREADY_INSTALLED: DWORD = 6619; +pub const ERROR_LOG_POLICY_NOT_INSTALLED: DWORD = 6620; +pub const ERROR_LOG_POLICY_INVALID: DWORD = 6621; +pub const ERROR_LOG_POLICY_CONFLICT: DWORD = 6622; +pub const ERROR_LOG_PINNED_ARCHIVE_TAIL: DWORD = 6623; +pub const ERROR_LOG_RECORD_NONEXISTENT: DWORD = 6624; +pub const ERROR_LOG_RECORDS_RESERVED_INVALID: DWORD = 6625; +pub const ERROR_LOG_SPACE_RESERVED_INVALID: DWORD = 6626; +pub const ERROR_LOG_TAIL_INVALID: DWORD = 6627; +pub const ERROR_LOG_FULL: DWORD = 6628; +pub const ERROR_COULD_NOT_RESIZE_LOG: DWORD = 6629; +pub const ERROR_LOG_MULTIPLEXED: DWORD = 6630; +pub const ERROR_LOG_DEDICATED: DWORD = 6631; +pub const ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS: DWORD = 6632; +pub const ERROR_LOG_ARCHIVE_IN_PROGRESS: DWORD = 6633; +pub const ERROR_LOG_EPHEMERAL: DWORD = 6634; +pub const ERROR_LOG_NOT_ENOUGH_CONTAINERS: DWORD = 6635; +pub const ERROR_LOG_CLIENT_ALREADY_REGISTERED: DWORD = 6636; +pub const ERROR_LOG_CLIENT_NOT_REGISTERED: DWORD = 6637; +pub const ERROR_LOG_FULL_HANDLER_IN_PROGRESS: DWORD = 6638; +pub const ERROR_LOG_CONTAINER_READ_FAILED: DWORD = 6639; +pub const ERROR_LOG_CONTAINER_WRITE_FAILED: DWORD = 6640; +pub const ERROR_LOG_CONTAINER_OPEN_FAILED: DWORD = 6641; +pub const ERROR_LOG_CONTAINER_STATE_INVALID: DWORD = 6642; +pub const ERROR_LOG_STATE_INVALID: DWORD = 6643; +pub const ERROR_LOG_PINNED: DWORD = 6644; +pub const ERROR_LOG_METADATA_FLUSH_FAILED: DWORD = 6645; +pub const ERROR_LOG_INCONSISTENT_SECURITY: DWORD = 6646; +pub const ERROR_LOG_APPENDED_FLUSH_FAILED: DWORD = 6647; +pub const ERROR_LOG_PINNED_RESERVATION: DWORD = 6648; +pub const ERROR_INVALID_TRANSACTION: DWORD = 6700; +pub const ERROR_TRANSACTION_NOT_ACTIVE: DWORD = 6701; +pub const ERROR_TRANSACTION_REQUEST_NOT_VALID: DWORD = 6702; +pub const ERROR_TRANSACTION_NOT_REQUESTED: DWORD = 6703; +pub const ERROR_TRANSACTION_ALREADY_ABORTED: DWORD = 6704; +pub const ERROR_TRANSACTION_ALREADY_COMMITTED: DWORD = 6705; +pub const ERROR_TM_INITIALIZATION_FAILED: DWORD = 6706; +pub const ERROR_RESOURCEMANAGER_READ_ONLY: DWORD = 6707; +pub const ERROR_TRANSACTION_NOT_JOINED: DWORD = 6708; +pub const ERROR_TRANSACTION_SUPERIOR_EXISTS: DWORD = 6709; +pub const ERROR_CRM_PROTOCOL_ALREADY_EXISTS: DWORD = 6710; +pub const ERROR_TRANSACTION_PROPAGATION_FAILED: DWORD = 6711; +pub const ERROR_CRM_PROTOCOL_NOT_FOUND: DWORD = 6712; +pub const ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER: DWORD = 6713; +pub const ERROR_CURRENT_TRANSACTION_NOT_VALID: DWORD = 6714; +pub const ERROR_TRANSACTION_NOT_FOUND: DWORD = 6715; +pub const ERROR_RESOURCEMANAGER_NOT_FOUND: DWORD = 6716; +pub const ERROR_ENLISTMENT_NOT_FOUND: DWORD = 6717; +pub const ERROR_TRANSACTIONMANAGER_NOT_FOUND: DWORD = 6718; +pub const ERROR_TRANSACTIONMANAGER_NOT_ONLINE: DWORD = 6719; +pub const ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION: DWORD = 6720; +pub const ERROR_TRANSACTION_NOT_ROOT: DWORD = 6721; +pub const ERROR_TRANSACTION_OBJECT_EXPIRED: DWORD = 6722; +pub const ERROR_TRANSACTION_RESPONSE_NOT_ENLISTED: DWORD = 6723; +pub const ERROR_TRANSACTION_RECORD_TOO_LONG: DWORD = 6724; +pub const ERROR_IMPLICIT_TRANSACTION_NOT_SUPPORTED: DWORD = 6725; +pub const ERROR_TRANSACTION_INTEGRITY_VIOLATED: DWORD = 6726; +pub const ERROR_TRANSACTIONMANAGER_IDENTITY_MISMATCH: DWORD = 6727; +pub const ERROR_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT: DWORD = 6728; +pub const ERROR_TRANSACTION_MUST_WRITETHROUGH: DWORD = 6729; +pub const ERROR_TRANSACTION_NO_SUPERIOR: DWORD = 6730; +pub const ERROR_HEURISTIC_DAMAGE_POSSIBLE: DWORD = 6731; +pub const ERROR_TRANSACTIONAL_CONFLICT: DWORD = 6800; +pub const ERROR_RM_NOT_ACTIVE: DWORD = 6801; +pub const ERROR_RM_METADATA_CORRUPT: DWORD = 6802; +pub const ERROR_DIRECTORY_NOT_RM: DWORD = 6803; +pub const ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE: DWORD = 6805; +pub const ERROR_LOG_RESIZE_INVALID_SIZE: DWORD = 6806; +pub const ERROR_OBJECT_NO_LONGER_EXISTS: DWORD = 6807; +pub const ERROR_STREAM_MINIVERSION_NOT_FOUND: DWORD = 6808; +pub const ERROR_STREAM_MINIVERSION_NOT_VALID: DWORD = 6809; +pub const ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION: DWORD = 6810; +pub const ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT: DWORD = 6811; +pub const ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS: DWORD = 6812; +pub const ERROR_REMOTE_FILE_VERSION_MISMATCH: DWORD = 6814; +pub const ERROR_HANDLE_NO_LONGER_VALID: DWORD = 6815; +pub const ERROR_NO_TXF_METADATA: DWORD = 6816; +pub const ERROR_LOG_CORRUPTION_DETECTED: DWORD = 6817; +pub const ERROR_CANT_RECOVER_WITH_HANDLE_OPEN: DWORD = 6818; +pub const ERROR_RM_DISCONNECTED: DWORD = 6819; +pub const ERROR_ENLISTMENT_NOT_SUPERIOR: DWORD = 6820; +pub const ERROR_RECOVERY_NOT_NEEDED: DWORD = 6821; +pub const ERROR_RM_ALREADY_STARTED: DWORD = 6822; +pub const ERROR_FILE_IDENTITY_NOT_PERSISTENT: DWORD = 6823; +pub const ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY: DWORD = 6824; +pub const ERROR_CANT_CROSS_RM_BOUNDARY: DWORD = 6825; +pub const ERROR_TXF_DIR_NOT_EMPTY: DWORD = 6826; +pub const ERROR_INDOUBT_TRANSACTIONS_EXIST: DWORD = 6827; +pub const ERROR_TM_VOLATILE: DWORD = 6828; +pub const ERROR_ROLLBACK_TIMER_EXPIRED: DWORD = 6829; +pub const ERROR_TXF_ATTRIBUTE_CORRUPT: DWORD = 6830; +pub const ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION: DWORD = 6831; +pub const ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED: DWORD = 6832; +pub const ERROR_LOG_GROWTH_FAILED: DWORD = 6833; +pub const ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE: DWORD = 6834; +pub const ERROR_TXF_METADATA_ALREADY_PRESENT: DWORD = 6835; +pub const ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET: DWORD = 6836; +pub const ERROR_TRANSACTION_REQUIRED_PROMOTION: DWORD = 6837; +pub const ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION: DWORD = 6838; +pub const ERROR_TRANSACTIONS_NOT_FROZEN: DWORD = 6839; +pub const ERROR_TRANSACTION_FREEZE_IN_PROGRESS: DWORD = 6840; +pub const ERROR_NOT_SNAPSHOT_VOLUME: DWORD = 6841; +pub const ERROR_NO_SAVEPOINT_WITH_OPEN_FILES: DWORD = 6842; +pub const ERROR_DATA_LOST_REPAIR: DWORD = 6843; +pub const ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION: DWORD = 6844; +pub const ERROR_TM_IDENTITY_MISMATCH: DWORD = 6845; +pub const ERROR_FLOATED_SECTION: DWORD = 6846; +pub const ERROR_CANNOT_ACCEPT_TRANSACTED_WORK: DWORD = 6847; +pub const ERROR_CANNOT_ABORT_TRANSACTIONS: DWORD = 6848; +pub const ERROR_BAD_CLUSTERS: DWORD = 6849; +pub const ERROR_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION: DWORD = 6850; +pub const ERROR_VOLUME_DIRTY: DWORD = 6851; +pub const ERROR_NO_LINK_TRACKING_IN_TRANSACTION: DWORD = 6852; +pub const ERROR_OPERATION_NOT_SUPPORTED_IN_TRANSACTION: DWORD = 6853; +pub const ERROR_EXPIRED_HANDLE: DWORD = 6854; +pub const ERROR_TRANSACTION_NOT_ENLISTED: DWORD = 6855; +pub const ERROR_CTX_WINSTATION_NAME_INVALID: DWORD = 7001; +pub const ERROR_CTX_INVALID_PD: DWORD = 7002; +pub const ERROR_CTX_PD_NOT_FOUND: DWORD = 7003; +pub const ERROR_CTX_WD_NOT_FOUND: DWORD = 7004; +pub const ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY: DWORD = 7005; +pub const ERROR_CTX_SERVICE_NAME_COLLISION: DWORD = 7006; +pub const ERROR_CTX_CLOSE_PENDING: DWORD = 7007; +pub const ERROR_CTX_NO_OUTBUF: DWORD = 7008; +pub const ERROR_CTX_MODEM_INF_NOT_FOUND: DWORD = 7009; +pub const ERROR_CTX_INVALID_MODEMNAME: DWORD = 7010; +pub const ERROR_CTX_MODEM_RESPONSE_ERROR: DWORD = 7011; +pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; +pub const ERROR_CTX_MODEM_RESPONSE_NO_CARRIER: DWORD = 7013; +pub const ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE: DWORD = 7014; +pub const ERROR_CTX_MODEM_RESPONSE_BUSY: DWORD = 7015; +pub const ERROR_CTX_MODEM_RESPONSE_VOICE: DWORD = 7016; +pub const ERROR_CTX_TD_ERROR: DWORD = 7017; +pub const ERROR_CTX_WINSTATION_NOT_FOUND: DWORD = 7022; +pub const ERROR_CTX_WINSTATION_ALREADY_EXISTS: DWORD = 7023; +pub const ERROR_CTX_WINSTATION_BUSY: DWORD = 7024; +pub const ERROR_CTX_BAD_VIDEO_MODE: DWORD = 7025; +pub const ERROR_CTX_GRAPHICS_INVALID: DWORD = 7035; +pub const ERROR_CTX_LOGON_DISABLED: DWORD = 7037; +pub const ERROR_CTX_NOT_CONSOLE: DWORD = 7038; +pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; +pub const ERROR_CTX_CONSOLE_DISCONNECT: DWORD = 7041; +pub const ERROR_CTX_CONSOLE_CONNECT: DWORD = 7042; +pub const ERROR_CTX_SHADOW_DENIED: DWORD = 7044; +pub const ERROR_CTX_WINSTATION_ACCESS_DENIED: DWORD = 7045; +pub const ERROR_CTX_INVALID_WD: DWORD = 7049; +pub const ERROR_CTX_SHADOW_INVALID: DWORD = 7050; +pub const ERROR_CTX_SHADOW_DISABLED: DWORD = 7051; +pub const ERROR_CTX_CLIENT_LICENSE_IN_USE: DWORD = 7052; +pub const ERROR_CTX_CLIENT_LICENSE_NOT_SET: DWORD = 7053; +pub const ERROR_CTX_LICENSE_NOT_AVAILABLE: DWORD = 7054; +pub const ERROR_CTX_LICENSE_CLIENT_INVALID: DWORD = 7055; +pub const ERROR_CTX_LICENSE_EXPIRED: DWORD = 7056; +pub const ERROR_CTX_SHADOW_NOT_RUNNING: DWORD = 7057; +pub const ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE: DWORD = 7058; +pub const ERROR_ACTIVATION_COUNT_EXCEEDED: DWORD = 7059; +pub const ERROR_CTX_WINSTATIONS_DISABLED: DWORD = 7060; +pub const ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED: DWORD = 7061; +pub const ERROR_CTX_SESSION_IN_USE: DWORD = 7062; +pub const ERROR_CTX_NO_FORCE_LOGOFF: DWORD = 7063; +pub const ERROR_CTX_ACCOUNT_RESTRICTION: DWORD = 7064; +pub const ERROR_RDP_PROTOCOL_ERROR: DWORD = 7065; +pub const ERROR_CTX_CDM_CONNECT: DWORD = 7066; +pub const ERROR_CTX_CDM_DISCONNECT: DWORD = 7067; +pub const ERROR_CTX_SECURITY_LAYER_ERROR: DWORD = 7068; +pub const ERROR_TS_INCOMPATIBLE_SESSIONS: DWORD = 7069; +pub const ERROR_TS_VIDEO_SUBSYSTEM_ERROR: DWORD = 7070; +pub const FRS_ERR_INVALID_API_SEQUENCE: DWORD = 8001; +pub const FRS_ERR_STARTING_SERVICE: DWORD = 8002; +pub const FRS_ERR_STOPPING_SERVICE: DWORD = 8003; +pub const FRS_ERR_INTERNAL_API: DWORD = 8004; +pub const FRS_ERR_INTERNAL: DWORD = 8005; +pub const FRS_ERR_SERVICE_COMM: DWORD = 8006; +pub const FRS_ERR_INSUFFICIENT_PRIV: DWORD = 8007; +pub const FRS_ERR_AUTHENTICATION: DWORD = 8008; +pub const FRS_ERR_PARENT_INSUFFICIENT_PRIV: DWORD = 8009; +pub const FRS_ERR_PARENT_AUTHENTICATION: DWORD = 8010; +pub const FRS_ERR_CHILD_TO_PARENT_COMM: DWORD = 8011; +pub const FRS_ERR_PARENT_TO_CHILD_COMM: DWORD = 8012; +pub const FRS_ERR_SYSVOL_POPULATE: DWORD = 8013; +pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; +pub const FRS_ERR_SYSVOL_IS_BUSY: DWORD = 8015; +pub const FRS_ERR_SYSVOL_DEMOTE: DWORD = 8016; +pub const FRS_ERR_INVALID_SERVICE_PARAMETER: DWORD = 8017; +pub const DS_S_SUCCESS: DWORD = NO_ERROR; +pub const ERROR_DS_NOT_INSTALLED: DWORD = 8200; +pub const ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY: DWORD = 8201; +pub const ERROR_DS_NO_ATTRIBUTE_OR_VALUE: DWORD = 8202; +pub const ERROR_DS_INVALID_ATTRIBUTE_SYNTAX: DWORD = 8203; +pub const ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED: DWORD = 8204; +pub const ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS: DWORD = 8205; +pub const ERROR_DS_BUSY: DWORD = 8206; +pub const ERROR_DS_UNAVAILABLE: DWORD = 8207; +pub const ERROR_DS_NO_RIDS_ALLOCATED: DWORD = 8208; +pub const ERROR_DS_NO_MORE_RIDS: DWORD = 8209; +pub const ERROR_DS_INCORRECT_ROLE_OWNER: DWORD = 8210; +pub const ERROR_DS_RIDMGR_INIT_ERROR: DWORD = 8211; +pub const ERROR_DS_OBJ_CLASS_VIOLATION: DWORD = 8212; +pub const ERROR_DS_CANT_ON_NON_LEAF: DWORD = 8213; +pub const ERROR_DS_CANT_ON_RDN: DWORD = 8214; +pub const ERROR_DS_CANT_MOD_OBJ_CLASS: DWORD = 8215; +pub const ERROR_DS_CROSS_DOM_MOVE_ERROR: DWORD = 8216; +pub const ERROR_DS_GC_NOT_AVAILABLE: DWORD = 8217; +pub const ERROR_SHARED_POLICY: DWORD = 8218; +pub const ERROR_POLICY_OBJECT_NOT_FOUND: DWORD = 8219; +pub const ERROR_POLICY_ONLY_IN_DS: DWORD = 8220; +pub const ERROR_PROMOTION_ACTIVE: DWORD = 8221; +pub const ERROR_NO_PROMOTION_ACTIVE: DWORD = 8222; +pub const ERROR_DS_OPERATIONS_ERROR: DWORD = 8224; +pub const ERROR_DS_PROTOCOL_ERROR: DWORD = 8225; +pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; +pub const ERROR_DS_SIZELIMIT_EXCEEDED: DWORD = 8227; +pub const ERROR_DS_ADMIN_LIMIT_EXCEEDED: DWORD = 8228; +pub const ERROR_DS_COMPARE_FALSE: DWORD = 8229; +pub const ERROR_DS_COMPARE_TRUE: DWORD = 8230; +pub const ERROR_DS_AUTH_METHOD_NOT_SUPPORTED: DWORD = 8231; +pub const ERROR_DS_STRONG_AUTH_REQUIRED: DWORD = 8232; +pub const ERROR_DS_INAPPROPRIATE_AUTH: DWORD = 8233; +pub const ERROR_DS_AUTH_UNKNOWN: DWORD = 8234; +pub const ERROR_DS_REFERRAL: DWORD = 8235; +pub const ERROR_DS_UNAVAILABLE_CRIT_EXTENSION: DWORD = 8236; +pub const ERROR_DS_CONFIDENTIALITY_REQUIRED: DWORD = 8237; +pub const ERROR_DS_INAPPROPRIATE_MATCHING: DWORD = 8238; +pub const ERROR_DS_CONSTRAINT_VIOLATION: DWORD = 8239; +pub const ERROR_DS_NO_SUCH_OBJECT: DWORD = 8240; +pub const ERROR_DS_ALIAS_PROBLEM: DWORD = 8241; +pub const ERROR_DS_INVALID_DN_SYNTAX: DWORD = 8242; +pub const ERROR_DS_IS_LEAF: DWORD = 8243; +pub const ERROR_DS_ALIAS_DEREF_PROBLEM: DWORD = 8244; +pub const ERROR_DS_UNWILLING_TO_PERFORM: DWORD = 8245; +pub const ERROR_DS_LOOP_DETECT: DWORD = 8246; +pub const ERROR_DS_NAMING_VIOLATION: DWORD = 8247; +pub const ERROR_DS_OBJECT_RESULTS_TOO_LARGE: DWORD = 8248; +pub const ERROR_DS_AFFECTS_MULTIPLE_DSAS: DWORD = 8249; +pub const ERROR_DS_SERVER_DOWN: DWORD = 8250; +pub const ERROR_DS_LOCAL_ERROR: DWORD = 8251; +pub const ERROR_DS_ENCODING_ERROR: DWORD = 8252; +pub const ERROR_DS_DECODING_ERROR: DWORD = 8253; +pub const ERROR_DS_FILTER_UNKNOWN: DWORD = 8254; +pub const ERROR_DS_PARAM_ERROR: DWORD = 8255; +pub const ERROR_DS_NOT_SUPPORTED: DWORD = 8256; +pub const ERROR_DS_NO_RESULTS_RETURNED: DWORD = 8257; +pub const ERROR_DS_CONTROL_NOT_FOUND: DWORD = 8258; +pub const ERROR_DS_CLIENT_LOOP: DWORD = 8259; +pub const ERROR_DS_REFERRAL_LIMIT_EXCEEDED: DWORD = 8260; +pub const ERROR_DS_SORT_CONTROL_MISSING: DWORD = 8261; +pub const ERROR_DS_OFFSET_RANGE_ERROR: DWORD = 8262; +pub const ERROR_DS_RIDMGR_DISABLED: DWORD = 8263; +pub const ERROR_DS_ROOT_MUST_BE_NC: DWORD = 8301; +pub const ERROR_DS_ADD_REPLICA_INHIBITED: DWORD = 8302; +pub const ERROR_DS_ATT_NOT_DEF_IN_SCHEMA: DWORD = 8303; +pub const ERROR_DS_MAX_OBJ_SIZE_EXCEEDED: DWORD = 8304; +pub const ERROR_DS_OBJ_STRING_NAME_EXISTS: DWORD = 8305; +pub const ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA: DWORD = 8306; +pub const ERROR_DS_RDN_DOESNT_MATCH_SCHEMA: DWORD = 8307; +pub const ERROR_DS_NO_REQUESTED_ATTS_FOUND: DWORD = 8308; +pub const ERROR_DS_USER_BUFFER_TO_SMALL: DWORD = 8309; +pub const ERROR_DS_ATT_IS_NOT_ON_OBJ: DWORD = 8310; +pub const ERROR_DS_ILLEGAL_MOD_OPERATION: DWORD = 8311; +pub const ERROR_DS_OBJ_TOO_LARGE: DWORD = 8312; +pub const ERROR_DS_BAD_INSTANCE_TYPE: DWORD = 8313; +pub const ERROR_DS_MASTERDSA_REQUIRED: DWORD = 8314; +pub const ERROR_DS_OBJECT_CLASS_REQUIRED: DWORD = 8315; +pub const ERROR_DS_MISSING_REQUIRED_ATT: DWORD = 8316; +pub const ERROR_DS_ATT_NOT_DEF_FOR_CLASS: DWORD = 8317; +pub const ERROR_DS_ATT_ALREADY_EXISTS: DWORD = 8318; +pub const ERROR_DS_CANT_ADD_ATT_VALUES: DWORD = 8320; +pub const ERROR_DS_SINGLE_VALUE_CONSTRAINT: DWORD = 8321; +pub const ERROR_DS_RANGE_CONSTRAINT: DWORD = 8322; +pub const ERROR_DS_ATT_VAL_ALREADY_EXISTS: DWORD = 8323; +pub const ERROR_DS_CANT_REM_MISSING_ATT: DWORD = 8324; +pub const ERROR_DS_CANT_REM_MISSING_ATT_VAL: DWORD = 8325; +pub const ERROR_DS_ROOT_CANT_BE_SUBREF: DWORD = 8326; +pub const ERROR_DS_NO_CHAINING: DWORD = 8327; +pub const ERROR_DS_NO_CHAINED_EVAL: DWORD = 8328; +pub const ERROR_DS_NO_PARENT_OBJECT: DWORD = 8329; +pub const ERROR_DS_PARENT_IS_AN_ALIAS: DWORD = 8330; +pub const ERROR_DS_CANT_MIX_MASTER_AND_REPS: DWORD = 8331; +pub const ERROR_DS_CHILDREN_EXIST: DWORD = 8332; +pub const ERROR_DS_OBJ_NOT_FOUND: DWORD = 8333; +pub const ERROR_DS_ALIASED_OBJ_MISSING: DWORD = 8334; +pub const ERROR_DS_BAD_NAME_SYNTAX: DWORD = 8335; +pub const ERROR_DS_ALIAS_POINTS_TO_ALIAS: DWORD = 8336; +pub const ERROR_DS_CANT_DEREF_ALIAS: DWORD = 8337; +pub const ERROR_DS_OUT_OF_SCOPE: DWORD = 8338; +pub const ERROR_DS_OBJECT_BEING_REMOVED: DWORD = 8339; +pub const ERROR_DS_CANT_DELETE_DSA_OBJ: DWORD = 8340; +pub const ERROR_DS_GENERIC_ERROR: DWORD = 8341; +pub const ERROR_DS_DSA_MUST_BE_INT_MASTER: DWORD = 8342; +pub const ERROR_DS_CLASS_NOT_DSA: DWORD = 8343; +pub const ERROR_DS_INSUFF_ACCESS_RIGHTS: DWORD = 8344; +pub const ERROR_DS_ILLEGAL_SUPERIOR: DWORD = 8345; +pub const ERROR_DS_ATTRIBUTE_OWNED_BY_SAM: DWORD = 8346; +pub const ERROR_DS_NAME_TOO_MANY_PARTS: DWORD = 8347; +pub const ERROR_DS_NAME_TOO_LONG: DWORD = 8348; +pub const ERROR_DS_NAME_VALUE_TOO_LONG: DWORD = 8349; +pub const ERROR_DS_NAME_UNPARSEABLE: DWORD = 8350; +pub const ERROR_DS_NAME_TYPE_UNKNOWN: DWORD = 8351; +pub const ERROR_DS_NOT_AN_OBJECT: DWORD = 8352; +pub const ERROR_DS_SEC_DESC_TOO_SHORT: DWORD = 8353; +pub const ERROR_DS_SEC_DESC_INVALID: DWORD = 8354; +pub const ERROR_DS_NO_DELETED_NAME: DWORD = 8355; +pub const ERROR_DS_SUBREF_MUST_HAVE_PARENT: DWORD = 8356; +pub const ERROR_DS_NCNAME_MUST_BE_NC: DWORD = 8357; +pub const ERROR_DS_CANT_ADD_SYSTEM_ONLY: DWORD = 8358; +pub const ERROR_DS_CLASS_MUST_BE_CONCRETE: DWORD = 8359; +pub const ERROR_DS_INVALID_DMD: DWORD = 8360; +pub const ERROR_DS_OBJ_GUID_EXISTS: DWORD = 8361; +pub const ERROR_DS_NOT_ON_BACKLINK: DWORD = 8362; +pub const ERROR_DS_NO_CROSSREF_FOR_NC: DWORD = 8363; +pub const ERROR_DS_SHUTTING_DOWN: DWORD = 8364; +pub const ERROR_DS_UNKNOWN_OPERATION: DWORD = 8365; +pub const ERROR_DS_INVALID_ROLE_OWNER: DWORD = 8366; +pub const ERROR_DS_COULDNT_CONTACT_FSMO: DWORD = 8367; +pub const ERROR_DS_CROSS_NC_DN_RENAME: DWORD = 8368; +pub const ERROR_DS_CANT_MOD_SYSTEM_ONLY: DWORD = 8369; +pub const ERROR_DS_REPLICATOR_ONLY: DWORD = 8370; +pub const ERROR_DS_OBJ_CLASS_NOT_DEFINED: DWORD = 8371; +pub const ERROR_DS_OBJ_CLASS_NOT_SUBCLASS: DWORD = 8372; +pub const ERROR_DS_NAME_REFERENCE_INVALID: DWORD = 8373; +pub const ERROR_DS_CROSS_REF_EXISTS: DWORD = 8374; +pub const ERROR_DS_CANT_DEL_MASTER_CROSSREF: DWORD = 8375; +pub const ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD: DWORD = 8376; +pub const ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX: DWORD = 8377; +pub const ERROR_DS_DUP_RDN: DWORD = 8378; +pub const ERROR_DS_DUP_OID: DWORD = 8379; +pub const ERROR_DS_DUP_MAPI_ID: DWORD = 8380; +pub const ERROR_DS_DUP_SCHEMA_ID_GUID: DWORD = 8381; +pub const ERROR_DS_DUP_LDAP_DISPLAY_NAME: DWORD = 8382; +pub const ERROR_DS_SEMANTIC_ATT_TEST: DWORD = 8383; +pub const ERROR_DS_SYNTAX_MISMATCH: DWORD = 8384; +pub const ERROR_DS_EXISTS_IN_MUST_HAVE: DWORD = 8385; +pub const ERROR_DS_EXISTS_IN_MAY_HAVE: DWORD = 8386; +pub const ERROR_DS_NONEXISTENT_MAY_HAVE: DWORD = 8387; +pub const ERROR_DS_NONEXISTENT_MUST_HAVE: DWORD = 8388; +pub const ERROR_DS_AUX_CLS_TEST_FAIL: DWORD = 8389; +pub const ERROR_DS_NONEXISTENT_POSS_SUP: DWORD = 8390; +pub const ERROR_DS_SUB_CLS_TEST_FAIL: DWORD = 8391; +pub const ERROR_DS_BAD_RDN_ATT_ID_SYNTAX: DWORD = 8392; +pub const ERROR_DS_EXISTS_IN_AUX_CLS: DWORD = 8393; +pub const ERROR_DS_EXISTS_IN_SUB_CLS: DWORD = 8394; +pub const ERROR_DS_EXISTS_IN_POSS_SUP: DWORD = 8395; +pub const ERROR_DS_RECALCSCHEMA_FAILED: DWORD = 8396; +pub const ERROR_DS_TREE_DELETE_NOT_FINISHED: DWORD = 8397; +pub const ERROR_DS_CANT_DELETE: DWORD = 8398; +pub const ERROR_DS_ATT_SCHEMA_REQ_ID: DWORD = 8399; +pub const ERROR_DS_BAD_ATT_SCHEMA_SYNTAX: DWORD = 8400; +pub const ERROR_DS_CANT_CACHE_ATT: DWORD = 8401; +pub const ERROR_DS_CANT_CACHE_CLASS: DWORD = 8402; +pub const ERROR_DS_CANT_REMOVE_ATT_CACHE: DWORD = 8403; +pub const ERROR_DS_CANT_REMOVE_CLASS_CACHE: DWORD = 8404; +pub const ERROR_DS_CANT_RETRIEVE_DN: DWORD = 8405; +pub const ERROR_DS_MISSING_SUPREF: DWORD = 8406; +pub const ERROR_DS_CANT_RETRIEVE_INSTANCE: DWORD = 8407; +pub const ERROR_DS_CODE_INCONSISTENCY: DWORD = 8408; +pub const ERROR_DS_DATABASE_ERROR: DWORD = 8409; +pub const ERROR_DS_GOVERNSID_MISSING: DWORD = 8410; +pub const ERROR_DS_MISSING_EXPECTED_ATT: DWORD = 8411; +pub const ERROR_DS_NCNAME_MISSING_CR_REF: DWORD = 8412; +pub const ERROR_DS_SECURITY_CHECKING_ERROR: DWORD = 8413; +pub const ERROR_DS_SCHEMA_NOT_LOADED: DWORD = 8414; +pub const ERROR_DS_SCHEMA_ALLOC_FAILED: DWORD = 8415; +pub const ERROR_DS_ATT_SCHEMA_REQ_SYNTAX: DWORD = 8416; +pub const ERROR_DS_GCVERIFY_ERROR: DWORD = 8417; +pub const ERROR_DS_DRA_SCHEMA_MISMATCH: DWORD = 8418; +pub const ERROR_DS_CANT_FIND_DSA_OBJ: DWORD = 8419; +pub const ERROR_DS_CANT_FIND_EXPECTED_NC: DWORD = 8420; +pub const ERROR_DS_CANT_FIND_NC_IN_CACHE: DWORD = 8421; +pub const ERROR_DS_CANT_RETRIEVE_CHILD: DWORD = 8422; +pub const ERROR_DS_SECURITY_ILLEGAL_MODIFY: DWORD = 8423; +pub const ERROR_DS_CANT_REPLACE_HIDDEN_REC: DWORD = 8424; +pub const ERROR_DS_BAD_HIERARCHY_FILE: DWORD = 8425; +pub const ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED: DWORD = 8426; +pub const ERROR_DS_CONFIG_PARAM_MISSING: DWORD = 8427; +pub const ERROR_DS_COUNTING_AB_INDICES_FAILED: DWORD = 8428; +pub const ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED: DWORD = 8429; +pub const ERROR_DS_INTERNAL_FAILURE: DWORD = 8430; +pub const ERROR_DS_UNKNOWN_ERROR: DWORD = 8431; +pub const ERROR_DS_ROOT_REQUIRES_CLASS_TOP: DWORD = 8432; +pub const ERROR_DS_REFUSING_FSMO_ROLES: DWORD = 8433; +pub const ERROR_DS_MISSING_FSMO_SETTINGS: DWORD = 8434; +pub const ERROR_DS_UNABLE_TO_SURRENDER_ROLES: DWORD = 8435; +pub const ERROR_DS_DRA_GENERIC: DWORD = 8436; +pub const ERROR_DS_DRA_INVALID_PARAMETER: DWORD = 8437; +pub const ERROR_DS_DRA_BUSY: DWORD = 8438; +pub const ERROR_DS_DRA_BAD_DN: DWORD = 8439; +pub const ERROR_DS_DRA_BAD_NC: DWORD = 8440; +pub const ERROR_DS_DRA_DN_EXISTS: DWORD = 8441; +pub const ERROR_DS_DRA_INTERNAL_ERROR: DWORD = 8442; +pub const ERROR_DS_DRA_INCONSISTENT_DIT: DWORD = 8443; +pub const ERROR_DS_DRA_CONNECTION_FAILED: DWORD = 8444; +pub const ERROR_DS_DRA_BAD_INSTANCE_TYPE: DWORD = 8445; +pub const ERROR_DS_DRA_OUT_OF_MEM: DWORD = 8446; +pub const ERROR_DS_DRA_MAIL_PROBLEM: DWORD = 8447; +pub const ERROR_DS_DRA_REF_ALREADY_EXISTS: DWORD = 8448; +pub const ERROR_DS_DRA_REF_NOT_FOUND: DWORD = 8449; +pub const ERROR_DS_DRA_OBJ_IS_REP_SOURCE: DWORD = 8450; +pub const ERROR_DS_DRA_DB_ERROR: DWORD = 8451; +pub const ERROR_DS_DRA_NO_REPLICA: DWORD = 8452; +pub const ERROR_DS_DRA_ACCESS_DENIED: DWORD = 8453; +pub const ERROR_DS_DRA_NOT_SUPPORTED: DWORD = 8454; +pub const ERROR_DS_DRA_RPC_CANCELLED: DWORD = 8455; +pub const ERROR_DS_DRA_SOURCE_DISABLED: DWORD = 8456; +pub const ERROR_DS_DRA_SINK_DISABLED: DWORD = 8457; +pub const ERROR_DS_DRA_NAME_COLLISION: DWORD = 8458; +pub const ERROR_DS_DRA_SOURCE_REINSTALLED: DWORD = 8459; +pub const ERROR_DS_DRA_MISSING_PARENT: DWORD = 8460; +pub const ERROR_DS_DRA_PREEMPTED: DWORD = 8461; +pub const ERROR_DS_DRA_ABANDON_SYNC: DWORD = 8462; +pub const ERROR_DS_DRA_SHUTDOWN: DWORD = 8463; +pub const ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET: DWORD = 8464; +pub const ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA: DWORD = 8465; +pub const ERROR_DS_DRA_EXTN_CONNECTION_FAILED: DWORD = 8466; +pub const ERROR_DS_INSTALL_SCHEMA_MISMATCH: DWORD = 8467; +pub const ERROR_DS_DUP_LINK_ID: DWORD = 8468; +pub const ERROR_DS_NAME_ERROR_RESOLVING: DWORD = 8469; +pub const ERROR_DS_NAME_ERROR_NOT_FOUND: DWORD = 8470; +pub const ERROR_DS_NAME_ERROR_NOT_UNIQUE: DWORD = 8471; +pub const ERROR_DS_NAME_ERROR_NO_MAPPING: DWORD = 8472; +pub const ERROR_DS_NAME_ERROR_DOMAIN_ONLY: DWORD = 8473; +pub const ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING: DWORD = 8474; +pub const ERROR_DS_CONSTRUCTED_ATT_MOD: DWORD = 8475; +pub const ERROR_DS_WRONG_OM_OBJ_CLASS: DWORD = 8476; +pub const ERROR_DS_DRA_REPL_PENDING: DWORD = 8477; +pub const ERROR_DS_DS_REQUIRED: DWORD = 8478; +pub const ERROR_DS_INVALID_LDAP_DISPLAY_NAME: DWORD = 8479; +pub const ERROR_DS_NON_BASE_SEARCH: DWORD = 8480; +pub const ERROR_DS_CANT_RETRIEVE_ATTS: DWORD = 8481; +pub const ERROR_DS_BACKLINK_WITHOUT_LINK: DWORD = 8482; +pub const ERROR_DS_EPOCH_MISMATCH: DWORD = 8483; +pub const ERROR_DS_SRC_NAME_MISMATCH: DWORD = 8484; +pub const ERROR_DS_SRC_AND_DST_NC_IDENTICAL: DWORD = 8485; +pub const ERROR_DS_DST_NC_MISMATCH: DWORD = 8486; +pub const ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC: DWORD = 8487; +pub const ERROR_DS_SRC_GUID_MISMATCH: DWORD = 8488; +pub const ERROR_DS_CANT_MOVE_DELETED_OBJECT: DWORD = 8489; +pub const ERROR_DS_PDC_OPERATION_IN_PROGRESS: DWORD = 8490; +pub const ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD: DWORD = 8491; +pub const ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION: DWORD = 8492; +pub const ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS: DWORD = 8493; +pub const ERROR_DS_NC_MUST_HAVE_NC_PARENT: DWORD = 8494; +pub const ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE: DWORD = 8495; +pub const ERROR_DS_DST_DOMAIN_NOT_NATIVE: DWORD = 8496; +pub const ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER: DWORD = 8497; +pub const ERROR_DS_CANT_MOVE_ACCOUNT_GROUP: DWORD = 8498; +pub const ERROR_DS_CANT_MOVE_RESOURCE_GROUP: DWORD = 8499; +pub const ERROR_DS_INVALID_SEARCH_FLAG: DWORD = 8500; +pub const ERROR_DS_NO_TREE_DELETE_ABOVE_NC: DWORD = 8501; +pub const ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE: DWORD = 8502; +pub const ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE: DWORD = 8503; +pub const ERROR_DS_SAM_INIT_FAILURE: DWORD = 8504; +pub const ERROR_DS_SENSITIVE_GROUP_VIOLATION: DWORD = 8505; +pub const ERROR_DS_CANT_MOD_PRIMARYGROUPID: DWORD = 8506; +pub const ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD: DWORD = 8507; +pub const ERROR_DS_NONSAFE_SCHEMA_CHANGE: DWORD = 8508; +pub const ERROR_DS_SCHEMA_UPDATE_DISALLOWED: DWORD = 8509; +pub const ERROR_DS_CANT_CREATE_UNDER_SCHEMA: DWORD = 8510; +pub const ERROR_DS_INSTALL_NO_SRC_SCH_VERSION: DWORD = 8511; +pub const ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE: DWORD = 8512; +pub const ERROR_DS_INVALID_GROUP_TYPE: DWORD = 8513; +pub const ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN: DWORD = 8514; +pub const ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN: DWORD = 8515; +pub const ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER: DWORD = 8516; +pub const ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER: DWORD = 8517; +pub const ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER: DWORD = 8518; +pub const ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER: DWORD = 8519; +pub const ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER: DWORD = 8520; +pub const ERROR_DS_HAVE_PRIMARY_MEMBERS: DWORD = 8521; +pub const ERROR_DS_STRING_SD_CONVERSION_FAILED: DWORD = 8522; +pub const ERROR_DS_NAMING_MASTER_GC: DWORD = 8523; +pub const ERROR_DS_DNS_LOOKUP_FAILURE: DWORD = 8524; +pub const ERROR_DS_COULDNT_UPDATE_SPNS: DWORD = 8525; +pub const ERROR_DS_CANT_RETRIEVE_SD: DWORD = 8526; +pub const ERROR_DS_KEY_NOT_UNIQUE: DWORD = 8527; +pub const ERROR_DS_WRONG_LINKED_ATT_SYNTAX: DWORD = 8528; +pub const ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD: DWORD = 8529; +pub const ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY: DWORD = 8530; +pub const ERROR_DS_CANT_START: DWORD = 8531; +pub const ERROR_DS_INIT_FAILURE: DWORD = 8532; +pub const ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION: DWORD = 8533; +pub const ERROR_DS_SOURCE_DOMAIN_IN_FOREST: DWORD = 8534; +pub const ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST: DWORD = 8535; +pub const ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED: DWORD = 8536; +pub const ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN: DWORD = 8537; +pub const ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER: DWORD = 8538; +pub const ERROR_DS_SRC_SID_EXISTS_IN_FOREST: DWORD = 8539; +pub const ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH: DWORD = 8540; +pub const ERROR_SAM_INIT_FAILURE: DWORD = 8541; +pub const ERROR_DS_DRA_SCHEMA_INFO_SHIP: DWORD = 8542; +pub const ERROR_DS_DRA_SCHEMA_CONFLICT: DWORD = 8543; +pub const ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT: DWORD = 8544; +pub const ERROR_DS_DRA_OBJ_NC_MISMATCH: DWORD = 8545; +pub const ERROR_DS_NC_STILL_HAS_DSAS: DWORD = 8546; +pub const ERROR_DS_GC_REQUIRED: DWORD = 8547; +pub const ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY: DWORD = 8548; +pub const ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS: DWORD = 8549; +pub const ERROR_DS_CANT_ADD_TO_GC: DWORD = 8550; +pub const ERROR_DS_NO_CHECKPOINT_WITH_PDC: DWORD = 8551; +pub const ERROR_DS_SOURCE_AUDITING_NOT_ENABLED: DWORD = 8552; +pub const ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC: DWORD = 8553; +pub const ERROR_DS_INVALID_NAME_FOR_SPN: DWORD = 8554; +pub const ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS: DWORD = 8555; +pub const ERROR_DS_UNICODEPWD_NOT_IN_QUOTES: DWORD = 8556; +pub const ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED: DWORD = 8557; +pub const ERROR_DS_MUST_BE_RUN_ON_DST_DC: DWORD = 8558; +pub const ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER: DWORD = 8559; +pub const ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ: DWORD = 8560; +pub const ERROR_DS_INIT_FAILURE_CONSOLE: DWORD = 8561; +pub const ERROR_DS_SAM_INIT_FAILURE_CONSOLE: DWORD = 8562; +pub const ERROR_DS_FOREST_VERSION_TOO_HIGH: DWORD = 8563; +pub const ERROR_DS_DOMAIN_VERSION_TOO_HIGH: DWORD = 8564; +pub const ERROR_DS_FOREST_VERSION_TOO_LOW: DWORD = 8565; +pub const ERROR_DS_DOMAIN_VERSION_TOO_LOW: DWORD = 8566; +pub const ERROR_DS_INCOMPATIBLE_VERSION: DWORD = 8567; +pub const ERROR_DS_LOW_DSA_VERSION: DWORD = 8568; +pub const ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN: DWORD = 8569; +pub const ERROR_DS_NOT_SUPPORTED_SORT_ORDER: DWORD = 8570; +pub const ERROR_DS_NAME_NOT_UNIQUE: DWORD = 8571; +pub const ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4: DWORD = 8572; +pub const ERROR_DS_OUT_OF_VERSION_STORE: DWORD = 8573; +pub const ERROR_DS_INCOMPATIBLE_CONTROLS_USED: DWORD = 8574; +pub const ERROR_DS_NO_REF_DOMAIN: DWORD = 8575; +pub const ERROR_DS_RESERVED_LINK_ID: DWORD = 8576; +pub const ERROR_DS_LINK_ID_NOT_AVAILABLE: DWORD = 8577; +pub const ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER: DWORD = 8578; +pub const ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE: DWORD = 8579; +pub const ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC: DWORD = 8580; +pub const ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG: DWORD = 8581; +pub const ERROR_DS_MODIFYDN_WRONG_GRANDPARENT: DWORD = 8582; +pub const ERROR_DS_NAME_ERROR_TRUST_REFERRAL: DWORD = 8583; +pub const ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER: DWORD = 8584; +pub const ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD: DWORD = 8585; +pub const ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2: DWORD = 8586; +pub const ERROR_DS_THREAD_LIMIT_EXCEEDED: DWORD = 8587; +pub const ERROR_DS_NOT_CLOSEST: DWORD = 8588; +pub const ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF: DWORD = 8589; +pub const ERROR_DS_SINGLE_USER_MODE_FAILED: DWORD = 8590; +pub const ERROR_DS_NTDSCRIPT_SYNTAX_ERROR: DWORD = 8591; +pub const ERROR_DS_NTDSCRIPT_PROCESS_ERROR: DWORD = 8592; +pub const ERROR_DS_DIFFERENT_REPL_EPOCHS: DWORD = 8593; +pub const ERROR_DS_DRS_EXTENSIONS_CHANGED: DWORD = 8594; +pub const ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR: DWORD = 8595; +pub const ERROR_DS_NO_MSDS_INTID: DWORD = 8596; +pub const ERROR_DS_DUP_MSDS_INTID: DWORD = 8597; +pub const ERROR_DS_EXISTS_IN_RDNATTID: DWORD = 8598; +pub const ERROR_DS_AUTHORIZATION_FAILED: DWORD = 8599; +pub const ERROR_DS_INVALID_SCRIPT: DWORD = 8600; +pub const ERROR_DS_REMOTE_CROSSREF_OP_FAILED: DWORD = 8601; +pub const ERROR_DS_CROSS_REF_BUSY: DWORD = 8602; +pub const ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN: DWORD = 8603; +pub const ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC: DWORD = 8604; +pub const ERROR_DS_DUPLICATE_ID_FOUND: DWORD = 8605; +pub const ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT: DWORD = 8606; +pub const ERROR_DS_GROUP_CONVERSION_ERROR: DWORD = 8607; +pub const ERROR_DS_CANT_MOVE_APP_BASIC_GROUP: DWORD = 8608; +pub const ERROR_DS_CANT_MOVE_APP_QUERY_GROUP: DWORD = 8609; +pub const ERROR_DS_ROLE_NOT_VERIFIED: DWORD = 8610; +pub const ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL: DWORD = 8611; +pub const ERROR_DS_DOMAIN_RENAME_IN_PROGRESS: DWORD = 8612; +pub const ERROR_DS_EXISTING_AD_CHILD_NC: DWORD = 8613; +pub const ERROR_DS_REPL_LIFETIME_EXCEEDED: DWORD = 8614; +pub const ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER: DWORD = 8615; +pub const ERROR_DS_LDAP_SEND_QUEUE_FULL: DWORD = 8616; +pub const ERROR_DS_DRA_OUT_SCHEDULE_WINDOW: DWORD = 8617; +pub const ERROR_DS_POLICY_NOT_KNOWN: DWORD = 8618; +pub const ERROR_NO_SITE_SETTINGS_OBJECT: DWORD = 8619; +pub const ERROR_NO_SECRETS: DWORD = 8620; +pub const ERROR_NO_WRITABLE_DC_FOUND: DWORD = 8621; +pub const ERROR_DS_NO_SERVER_OBJECT: DWORD = 8622; +pub const ERROR_DS_NO_NTDSA_OBJECT: DWORD = 8623; +pub const ERROR_DS_NON_ASQ_SEARCH: DWORD = 8624; +pub const ERROR_DS_AUDIT_FAILURE: DWORD = 8625; +pub const ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE: DWORD = 8626; +pub const ERROR_DS_INVALID_SEARCH_FLAG_TUPLE: DWORD = 8627; +pub const ERROR_DS_HIERARCHY_TABLE_TOO_DEEP: DWORD = 8628; +pub const ERROR_DS_DRA_CORRUPT_UTD_VECTOR: DWORD = 8629; +pub const ERROR_DS_DRA_SECRETS_DENIED: DWORD = 8630; +pub const ERROR_DS_RESERVED_MAPI_ID: DWORD = 8631; +pub const ERROR_DS_MAPI_ID_NOT_AVAILABLE: DWORD = 8632; +pub const ERROR_DS_DRA_MISSING_KRBTGT_SECRET: DWORD = 8633; +pub const ERROR_DS_DOMAIN_NAME_EXISTS_IN_FOREST: DWORD = 8634; +pub const ERROR_DS_FLAT_NAME_EXISTS_IN_FOREST: DWORD = 8635; +pub const ERROR_INVALID_USER_PRINCIPAL_NAME: DWORD = 8636; +pub const ERROR_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS: DWORD = 8637; +pub const ERROR_DS_OID_NOT_FOUND: DWORD = 8638; +pub const ERROR_DS_DRA_RECYCLED_TARGET: DWORD = 8639; +pub const ERROR_DS_DISALLOWED_NC_REDIRECT: DWORD = 8640; +pub const ERROR_DS_HIGH_ADLDS_FFL: DWORD = 8641; +pub const ERROR_DS_HIGH_DSA_VERSION: DWORD = 8642; +pub const ERROR_DS_LOW_ADLDS_FFL: DWORD = 8643; +pub const ERROR_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION: DWORD = 8644; +pub const ERROR_DS_UNDELETE_SAM_VALIDATION_FAILED: DWORD = 8645; +pub const ERROR_INCORRECT_ACCOUNT_TYPE: DWORD = 8646; +pub const ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST: DWORD = 8647; +pub const ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST: DWORD = 8648; +pub const DNS_ERROR_RESPONSE_CODES_BASE: DWORD = 9000; +pub const DNS_ERROR_RCODE_NO_ERROR: DWORD = NO_ERROR; +pub const DNS_ERROR_MASK: DWORD = 0x00002328; +pub const DNS_ERROR_RCODE_FORMAT_ERROR: DWORD = 9001; +pub const DNS_ERROR_RCODE_SERVER_FAILURE: DWORD = 9002; +pub const DNS_ERROR_RCODE_NAME_ERROR: DWORD = 9003; +pub const DNS_ERROR_RCODE_NOT_IMPLEMENTED: DWORD = 9004; +pub const DNS_ERROR_RCODE_REFUSED: DWORD = 9005; +pub const DNS_ERROR_RCODE_YXDOMAIN: DWORD = 9006; +pub const DNS_ERROR_RCODE_YXRRSET: DWORD = 9007; +pub const DNS_ERROR_RCODE_NXRRSET: DWORD = 9008; +pub const DNS_ERROR_RCODE_NOTAUTH: DWORD = 9009; +pub const DNS_ERROR_RCODE_NOTZONE: DWORD = 9010; +pub const DNS_ERROR_RCODE_BADSIG: DWORD = 9016; +pub const DNS_ERROR_RCODE_BADKEY: DWORD = 9017; +pub const DNS_ERROR_RCODE_BADTIME: DWORD = 9018; +pub const DNS_ERROR_RCODE_LAST: DWORD = DNS_ERROR_RCODE_BADTIME; +pub const DNS_ERROR_DNSSEC_BASE: DWORD = 9100; +pub const DNS_ERROR_KEYMASTER_REQUIRED: DWORD = 9101; +pub const DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE: DWORD = 9102; +pub const DNS_ERROR_NSEC3_INCOMPATIBLE_WITH_RSA_SHA1: DWORD = 9103; +pub const DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS: DWORD = 9104; +pub const DNS_ERROR_UNSUPPORTED_ALGORITHM: DWORD = 9105; +pub const DNS_ERROR_INVALID_KEY_SIZE: DWORD = 9106; +pub const DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE: DWORD = 9107; +pub const DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION: DWORD = 9108; +pub const DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR: DWORD = 9109; +pub const DNS_ERROR_UNEXPECTED_CNG_ERROR: DWORD = 9110; +pub const DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION: DWORD = 9111; +pub const DNS_ERROR_KSP_NOT_ACCESSIBLE: DWORD = 9112; +pub const DNS_ERROR_TOO_MANY_SKDS: DWORD = 9113; +pub const DNS_ERROR_INVALID_ROLLOVER_PERIOD: DWORD = 9114; +pub const DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET: DWORD = 9115; +pub const DNS_ERROR_ROLLOVER_IN_PROGRESS: DWORD = 9116; +pub const DNS_ERROR_STANDBY_KEY_NOT_PRESENT: DWORD = 9117; +pub const DNS_ERROR_NOT_ALLOWED_ON_ZSK: DWORD = 9118; +pub const DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD: DWORD = 9119; +pub const DNS_ERROR_ROLLOVER_ALREADY_QUEUED: DWORD = 9120; +pub const DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE: DWORD = 9121; +pub const DNS_ERROR_BAD_KEYMASTER: DWORD = 9122; +pub const DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD: DWORD = 9123; +pub const DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT: DWORD = 9124; +pub const DNS_ERROR_DNSSEC_IS_DISABLED: DWORD = 9125; +pub const DNS_ERROR_INVALID_XML: DWORD = 9126; +pub const DNS_ERROR_NO_VALID_TRUST_ANCHORS: DWORD = 9127; +pub const DNS_ERROR_ROLLOVER_NOT_POKEABLE: DWORD = 9128; +pub const DNS_ERROR_NSEC3_NAME_COLLISION: DWORD = 9129; +pub const DNS_ERROR_NSEC_INCOMPATIBLE_WITH_NSEC3_RSA_SHA1: DWORD = 9130; +pub const DNS_ERROR_PACKET_FMT_BASE: DWORD = 9500; +pub const DNS_INFO_NO_RECORDS: DWORD = 9501; +pub const DNS_ERROR_BAD_PACKET: DWORD = 9502; +pub const DNS_ERROR_NO_PACKET: DWORD = 9503; +pub const DNS_ERROR_RCODE: DWORD = 9504; +pub const DNS_ERROR_UNSECURE_PACKET: DWORD = 9505; +pub const DNS_STATUS_PACKET_UNSECURE: DWORD = DNS_ERROR_UNSECURE_PACKET; +pub const DNS_REQUEST_PENDING: DWORD = 9506; +pub const DNS_ERROR_NO_MEMORY: DWORD = ERROR_OUTOFMEMORY; +pub const DNS_ERROR_INVALID_NAME: DWORD = ERROR_INVALID_NAME; +pub const DNS_ERROR_INVALID_DATA: DWORD = ERROR_INVALID_DATA; +pub const DNS_ERROR_GENERAL_API_BASE: DWORD = 9550; +pub const DNS_ERROR_INVALID_TYPE: DWORD = 9551; +pub const DNS_ERROR_INVALID_IP_ADDRESS: DWORD = 9552; +pub const DNS_ERROR_INVALID_PROPERTY: DWORD = 9553; +pub const DNS_ERROR_TRY_AGAIN_LATER: DWORD = 9554; +pub const DNS_ERROR_NOT_UNIQUE: DWORD = 9555; +pub const DNS_ERROR_NON_RFC_NAME: DWORD = 9556; +pub const DNS_STATUS_FQDN: DWORD = 9557; +pub const DNS_STATUS_DOTTED_NAME: DWORD = 9558; +pub const DNS_STATUS_SINGLE_PART_NAME: DWORD = 9559; +pub const DNS_ERROR_INVALID_NAME_CHAR: DWORD = 9560; +pub const DNS_ERROR_NUMERIC_NAME: DWORD = 9561; +pub const DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER: DWORD = 9562; +pub const DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION: DWORD = 9563; +pub const DNS_ERROR_CANNOT_FIND_ROOT_HINTS: DWORD = 9564; +pub const DNS_ERROR_INCONSISTENT_ROOT_HINTS: DWORD = 9565; +pub const DNS_ERROR_DWORD_VALUE_TOO_SMALL: DWORD = 9566; +pub const DNS_ERROR_DWORD_VALUE_TOO_LARGE: DWORD = 9567; +pub const DNS_ERROR_BACKGROUND_LOADING: DWORD = 9568; +pub const DNS_ERROR_NOT_ALLOWED_ON_RODC: DWORD = 9569; +pub const DNS_ERROR_NOT_ALLOWED_UNDER_DNAME: DWORD = 9570; +pub const DNS_ERROR_DELEGATION_REQUIRED: DWORD = 9571; +pub const DNS_ERROR_INVALID_POLICY_TABLE: DWORD = 9572; +pub const DNS_ERROR_ZONE_BASE: DWORD = 9600; +pub const DNS_ERROR_ZONE_DOES_NOT_EXIST: DWORD = 9601; +pub const DNS_ERROR_NO_ZONE_INFO: DWORD = 9602; +pub const DNS_ERROR_INVALID_ZONE_OPERATION: DWORD = 9603; +pub const DNS_ERROR_ZONE_CONFIGURATION_ERROR: DWORD = 9604; +pub const DNS_ERROR_ZONE_HAS_NO_SOA_RECORD: DWORD = 9605; +pub const DNS_ERROR_ZONE_HAS_NO_NS_RECORDS: DWORD = 9606; +pub const DNS_ERROR_ZONE_LOCKED: DWORD = 9607; +pub const DNS_ERROR_ZONE_CREATION_FAILED: DWORD = 9608; +pub const DNS_ERROR_ZONE_ALREADY_EXISTS: DWORD = 9609; +pub const DNS_ERROR_AUTOZONE_ALREADY_EXISTS: DWORD = 9610; +pub const DNS_ERROR_INVALID_ZONE_TYPE: DWORD = 9611; +pub const DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP: DWORD = 9612; +pub const DNS_ERROR_ZONE_NOT_SECONDARY: DWORD = 9613; +pub const DNS_ERROR_NEED_SECONDARY_ADDRESSES: DWORD = 9614; +pub const DNS_ERROR_WINS_INIT_FAILED: DWORD = 9615; +pub const DNS_ERROR_NEED_WINS_SERVERS: DWORD = 9616; +pub const DNS_ERROR_NBSTAT_INIT_FAILED: DWORD = 9617; +pub const DNS_ERROR_SOA_DELETE_INVALID: DWORD = 9618; +pub const DNS_ERROR_FORWARDER_ALREADY_EXISTS: DWORD = 9619; +pub const DNS_ERROR_ZONE_REQUIRES_MASTER_IP: DWORD = 9620; +pub const DNS_ERROR_ZONE_IS_SHUTDOWN: DWORD = 9621; +pub const DNS_ERROR_ZONE_LOCKED_FOR_SIGNING: DWORD = 9622; +pub const DNS_ERROR_DATAFILE_BASE: DWORD = 9650; +pub const DNS_ERROR_PRIMARY_REQUIRES_DATAFILE: DWORD = 9651; +pub const DNS_ERROR_INVALID_DATAFILE_NAME: DWORD = 9652; +pub const DNS_ERROR_DATAFILE_OPEN_FAILURE: DWORD = 9653; +pub const DNS_ERROR_FILE_WRITEBACK_FAILED: DWORD = 9654; +pub const DNS_ERROR_DATAFILE_PARSING: DWORD = 9655; +pub const DNS_ERROR_DATABASE_BASE: DWORD = 9700; +pub const DNS_ERROR_RECORD_DOES_NOT_EXIST: DWORD = 9701; +pub const DNS_ERROR_RECORD_FORMAT: DWORD = 9702; +pub const DNS_ERROR_NODE_CREATION_FAILED: DWORD = 9703; +pub const DNS_ERROR_UNKNOWN_RECORD_TYPE: DWORD = 9704; +pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; +pub const DNS_ERROR_NAME_NOT_IN_ZONE: DWORD = 9706; +pub const DNS_ERROR_CNAME_LOOP: DWORD = 9707; +pub const DNS_ERROR_NODE_IS_CNAME: DWORD = 9708; +pub const DNS_ERROR_CNAME_COLLISION: DWORD = 9709; +pub const DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT: DWORD = 9710; +pub const DNS_ERROR_RECORD_ALREADY_EXISTS: DWORD = 9711; +pub const DNS_ERROR_SECONDARY_DATA: DWORD = 9712; +pub const DNS_ERROR_NO_CREATE_CACHE_DATA: DWORD = 9713; +pub const DNS_ERROR_NAME_DOES_NOT_EXIST: DWORD = 9714; +pub const DNS_WARNING_PTR_CREATE_FAILED: DWORD = 9715; +pub const DNS_WARNING_DOMAIN_UNDELETED: DWORD = 9716; +pub const DNS_ERROR_DS_UNAVAILABLE: DWORD = 9717; +pub const DNS_ERROR_DS_ZONE_ALREADY_EXISTS: DWORD = 9718; +pub const DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE: DWORD = 9719; +pub const DNS_ERROR_NODE_IS_DNAME: DWORD = 9720; +pub const DNS_ERROR_DNAME_COLLISION: DWORD = 9721; +pub const DNS_ERROR_ALIAS_LOOP: DWORD = 9722; +pub const DNS_ERROR_OPERATION_BASE: DWORD = 9750; +pub const DNS_INFO_AXFR_COMPLETE: DWORD = 9751; +pub const DNS_ERROR_AXFR: DWORD = 9752; +pub const DNS_INFO_ADDED_LOCAL_WINS: DWORD = 9753; +pub const DNS_ERROR_SECURE_BASE: DWORD = 9800; +pub const DNS_STATUS_CONTINUE_NEEDED: DWORD = 9801; +pub const DNS_ERROR_SETUP_BASE: DWORD = 9850; +pub const DNS_ERROR_NO_TCPIP: DWORD = 9851; +pub const DNS_ERROR_NO_DNS_SERVERS: DWORD = 9852; +pub const DNS_ERROR_DP_BASE: DWORD = 9900; +pub const DNS_ERROR_DP_DOES_NOT_EXIST: DWORD = 9901; +pub const DNS_ERROR_DP_ALREADY_EXISTS: DWORD = 9902; +pub const DNS_ERROR_DP_NOT_ENLISTED: DWORD = 9903; +pub const DNS_ERROR_DP_ALREADY_ENLISTED: DWORD = 9904; +pub const DNS_ERROR_DP_NOT_AVAILABLE: DWORD = 9905; +pub const DNS_ERROR_DP_FSMO_ERROR: DWORD = 9906; +pub const DNS_ERROR_ZONESCOPE_ALREADY_EXISTS: DWORD = 9951; +pub const DNS_ERROR_ZONESCOPE_DOES_NOT_EXIST: DWORD = 9952; +pub const DNS_ERROR_DEFAULT_ZONESCOPE: DWORD = 9953; +pub const DNS_ERROR_INVALID_ZONESCOPE_NAME: DWORD = 9954; +pub const DNS_ERROR_NOT_ALLOWED_WITH_ZONESCOPES: DWORD = 9955; +pub const DNS_ERROR_LOAD_ZONESCOPE_FAILED: DWORD = 9956; +pub const DNS_ERROR_ZONESCOPE_FILE_WRITEBACK_FAILED: DWORD = 9957; +pub const DNS_ERROR_INVALID_SCOPE_NAME: DWORD = 9958; +pub const DNS_ERROR_SCOPE_DOES_NOT_EXIST: DWORD = 9959; +pub const DNS_ERROR_DEFAULT_SCOPE: DWORD = 9960; +pub const DNS_ERROR_INVALID_SCOPE_OPERATION: DWORD = 9961; +pub const DNS_ERROR_SCOPE_LOCKED: DWORD = 9962; +pub const DNS_ERROR_SCOPE_ALREADY_EXISTS: DWORD = 9963; +pub const WSABASEERR: DWORD = 10000; +pub const WSAEINTR: DWORD = 10004; +pub const WSAEBADF: DWORD = 10009; +pub const WSAEACCES: DWORD = 10013; +pub const WSAEFAULT: DWORD = 10014; +pub const WSAEINVAL: DWORD = 10022; +pub const WSAEMFILE: DWORD = 10024; +pub const WSAEWOULDBLOCK: DWORD = 10035; +pub const WSAEINPROGRESS: DWORD = 10036; +pub const WSAEALREADY: DWORD = 10037; +pub const WSAENOTSOCK: DWORD = 10038; +pub const WSAEDESTADDRREQ: DWORD = 10039; +pub const WSAEMSGSIZE: DWORD = 10040; +pub const WSAEPROTOTYPE: DWORD = 10041; +pub const WSAENOPROTOOPT: DWORD = 10042; +pub const WSAEPROTONOSUPPORT: DWORD = 10043; +pub const WSAESOCKTNOSUPPORT: DWORD = 10044; +pub const WSAEOPNOTSUPP: DWORD = 10045; +pub const WSAEPFNOSUPPORT: DWORD = 10046; +pub const WSAEAFNOSUPPORT: DWORD = 10047; +pub const WSAEADDRINUSE: DWORD = 10048; +pub const WSAEADDRNOTAVAIL: DWORD = 10049; +pub const WSAENETDOWN: DWORD = 10050; +pub const WSAENETUNREACH: DWORD = 10051; +pub const WSAENETRESET: DWORD = 10052; +pub const WSAECONNABORTED: DWORD = 10053; +pub const WSAECONNRESET: DWORD = 10054; +pub const WSAENOBUFS: DWORD = 10055; +pub const WSAEISCONN: DWORD = 10056; +pub const WSAENOTCONN: DWORD = 10057; +pub const WSAESHUTDOWN: DWORD = 10058; +pub const WSAETOOMANYREFS: DWORD = 10059; +pub const WSAETIMEDOUT: DWORD = 10060; +pub const WSAECONNREFUSED: DWORD = 10061; +pub const WSAELOOP: DWORD = 10062; +pub const WSAENAMETOOLONG: DWORD = 10063; +pub const WSAEHOSTDOWN: DWORD = 10064; +pub const WSAEHOSTUNREACH: DWORD = 10065; +pub const WSAENOTEMPTY: DWORD = 10066; +pub const WSAEPROCLIM: DWORD = 10067; +pub const WSAEUSERS: DWORD = 10068; +pub const WSAEDQUOT: DWORD = 10069; +pub const WSAESTALE: DWORD = 10070; +pub const WSAEREMOTE: DWORD = 10071; +pub const WSASYSNOTREADY: DWORD = 10091; +pub const WSAVERNOTSUPPORTED: DWORD = 10092; +pub const WSANOTINITIALISED: DWORD = 10093; +pub const WSAEDISCON: DWORD = 10101; +pub const WSAENOMORE: DWORD = 10102; +pub const WSAECANCELLED: DWORD = 10103; +pub const WSAEINVALIDPROCTABLE: DWORD = 10104; +pub const WSAEINVALIDPROVIDER: DWORD = 10105; +pub const WSAEPROVIDERFAILEDINIT: DWORD = 10106; +pub const WSASYSCALLFAILURE: DWORD = 10107; +pub const WSASERVICE_NOT_FOUND: DWORD = 10108; +pub const WSATYPE_NOT_FOUND: DWORD = 10109; +pub const WSA_E_NO_MORE: DWORD = 10110; +pub const WSA_E_CANCELLED: DWORD = 10111; +pub const WSAEREFUSED: DWORD = 10112; +pub const WSAHOST_NOT_FOUND: DWORD = 11001; +pub const WSATRY_AGAIN: DWORD = 11002; +pub const WSANO_RECOVERY: DWORD = 11003; +pub const WSANO_DATA: DWORD = 11004; +pub const WSA_QOS_RECEIVERS: DWORD = 11005; +pub const WSA_QOS_SENDERS: DWORD = 11006; +pub const WSA_QOS_NO_SENDERS: DWORD = 11007; +pub const WSA_QOS_NO_RECEIVERS: DWORD = 11008; +pub const WSA_QOS_REQUEST_CONFIRMED: DWORD = 11009; +pub const WSA_QOS_ADMISSION_FAILURE: DWORD = 11010; +pub const WSA_QOS_POLICY_FAILURE: DWORD = 11011; +pub const WSA_QOS_BAD_STYLE: DWORD = 11012; +pub const WSA_QOS_BAD_OBJECT: DWORD = 11013; +pub const WSA_QOS_TRAFFIC_CTRL_ERROR: DWORD = 11014; +pub const WSA_QOS_GENERIC_ERROR: DWORD = 11015; +pub const WSA_QOS_ESERVICETYPE: DWORD = 11016; +pub const WSA_QOS_EFLOWSPEC: DWORD = 11017; +pub const WSA_QOS_EPROVSPECBUF: DWORD = 11018; +pub const WSA_QOS_EFILTERSTYLE: DWORD = 11019; +pub const WSA_QOS_EFILTERTYPE: DWORD = 11020; +pub const WSA_QOS_EFILTERCOUNT: DWORD = 11021; +pub const WSA_QOS_EOBJLENGTH: DWORD = 11022; +pub const WSA_QOS_EFLOWCOUNT: DWORD = 11023; +pub const WSA_QOS_EUNKOWNPSOBJ: DWORD = 11024; +pub const WSA_QOS_EPOLICYOBJ: DWORD = 11025; +pub const WSA_QOS_EFLOWDESC: DWORD = 11026; +pub const WSA_QOS_EPSFLOWSPEC: DWORD = 11027; +pub const WSA_QOS_EPSFILTERSPEC: DWORD = 11028; +pub const WSA_QOS_ESDMODEOBJ: DWORD = 11029; +pub const WSA_QOS_ESHAPERATEOBJ: DWORD = 11030; +pub const WSA_QOS_RESERVED_PETYPE: DWORD = 11031; +pub const WSA_SECURE_HOST_NOT_FOUND: DWORD = 11032; +pub const WSA_IPSEC_NAME_POLICY_ERROR: DWORD = 11033; +pub const ERROR_IPSEC_QM_POLICY_EXISTS: DWORD = 13000; +pub const ERROR_IPSEC_QM_POLICY_NOT_FOUND: DWORD = 13001; +pub const ERROR_IPSEC_QM_POLICY_IN_USE: DWORD = 13002; +pub const ERROR_IPSEC_MM_POLICY_EXISTS: DWORD = 13003; +pub const ERROR_IPSEC_MM_POLICY_NOT_FOUND: DWORD = 13004; +pub const ERROR_IPSEC_MM_POLICY_IN_USE: DWORD = 13005; +pub const ERROR_IPSEC_MM_FILTER_EXISTS: DWORD = 13006; +pub const ERROR_IPSEC_MM_FILTER_NOT_FOUND: DWORD = 13007; +pub const ERROR_IPSEC_TRANSPORT_FILTER_EXISTS: DWORD = 13008; +pub const ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND: DWORD = 13009; +pub const ERROR_IPSEC_MM_AUTH_EXISTS: DWORD = 13010; +pub const ERROR_IPSEC_MM_AUTH_NOT_FOUND: DWORD = 13011; +pub const ERROR_IPSEC_MM_AUTH_IN_USE: DWORD = 13012; +pub const ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND: DWORD = 13013; +pub const ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND: DWORD = 13014; +pub const ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND: DWORD = 13015; +pub const ERROR_IPSEC_TUNNEL_FILTER_EXISTS: DWORD = 13016; +pub const ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND: DWORD = 13017; +pub const ERROR_IPSEC_MM_FILTER_PENDING_DELETION: DWORD = 13018; +pub const ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION: DWORD = 13019; +pub const ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION: DWORD = 13020; +pub const ERROR_IPSEC_MM_POLICY_PENDING_DELETION: DWORD = 13021; +pub const ERROR_IPSEC_MM_AUTH_PENDING_DELETION: DWORD = 13022; +pub const ERROR_IPSEC_QM_POLICY_PENDING_DELETION: DWORD = 13023; +pub const WARNING_IPSEC_MM_POLICY_PRUNED: DWORD = 13024; +pub const WARNING_IPSEC_QM_POLICY_PRUNED: DWORD = 13025; +pub const ERROR_IPSEC_IKE_NEG_STATUS_BEGIN: DWORD = 13800; +pub const ERROR_IPSEC_IKE_AUTH_FAIL: DWORD = 13801; +pub const ERROR_IPSEC_IKE_ATTRIB_FAIL: DWORD = 13802; +pub const ERROR_IPSEC_IKE_NEGOTIATION_PENDING: DWORD = 13803; +pub const ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR: DWORD = 13804; +pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; +pub const ERROR_IPSEC_IKE_NO_CERT: DWORD = 13806; +pub const ERROR_IPSEC_IKE_SA_DELETED: DWORD = 13807; +pub const ERROR_IPSEC_IKE_SA_REAPED: DWORD = 13808; +pub const ERROR_IPSEC_IKE_MM_ACQUIRE_DROP: DWORD = 13809; +pub const ERROR_IPSEC_IKE_QM_ACQUIRE_DROP: DWORD = 13810; +pub const ERROR_IPSEC_IKE_QUEUE_DROP_MM: DWORD = 13811; +pub const ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM: DWORD = 13812; +pub const ERROR_IPSEC_IKE_DROP_NO_RESPONSE: DWORD = 13813; +pub const ERROR_IPSEC_IKE_MM_DELAY_DROP: DWORD = 13814; +pub const ERROR_IPSEC_IKE_QM_DELAY_DROP: DWORD = 13815; +pub const ERROR_IPSEC_IKE_ERROR: DWORD = 13816; +pub const ERROR_IPSEC_IKE_CRL_FAILED: DWORD = 13817; +pub const ERROR_IPSEC_IKE_INVALID_KEY_USAGE: DWORD = 13818; +pub const ERROR_IPSEC_IKE_INVALID_CERT_TYPE: DWORD = 13819; +pub const ERROR_IPSEC_IKE_NO_PRIVATE_KEY: DWORD = 13820; +pub const ERROR_IPSEC_IKE_SIMULTANEOUS_REKEY: DWORD = 13821; +pub const ERROR_IPSEC_IKE_DH_FAIL: DWORD = 13822; +pub const ERROR_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED: DWORD = 13823; +pub const ERROR_IPSEC_IKE_INVALID_HEADER: DWORD = 13824; +pub const ERROR_IPSEC_IKE_NO_POLICY: DWORD = 13825; +pub const ERROR_IPSEC_IKE_INVALID_SIGNATURE: DWORD = 13826; +pub const ERROR_IPSEC_IKE_KERBEROS_ERROR: DWORD = 13827; +pub const ERROR_IPSEC_IKE_NO_PUBLIC_KEY: DWORD = 13828; +pub const ERROR_IPSEC_IKE_PROCESS_ERR: DWORD = 13829; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_SA: DWORD = 13830; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_PROP: DWORD = 13831; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_TRANS: DWORD = 13832; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_KE: DWORD = 13833; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_ID: DWORD = 13834; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_CERT: DWORD = 13835; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ: DWORD = 13836; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_HASH: DWORD = 13837; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_SIG: DWORD = 13838; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NONCE: DWORD = 13839; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY: DWORD = 13840; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_DELETE: DWORD = 13841; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR: DWORD = 13842; +pub const ERROR_IPSEC_IKE_INVALID_PAYLOAD: DWORD = 13843; +pub const ERROR_IPSEC_IKE_LOAD_SOFT_SA: DWORD = 13844; +pub const ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN: DWORD = 13845; +pub const ERROR_IPSEC_IKE_INVALID_COOKIE: DWORD = 13846; +pub const ERROR_IPSEC_IKE_NO_PEER_CERT: DWORD = 13847; +pub const ERROR_IPSEC_IKE_PEER_CRL_FAILED: DWORD = 13848; +pub const ERROR_IPSEC_IKE_POLICY_CHANGE: DWORD = 13849; +pub const ERROR_IPSEC_IKE_NO_MM_POLICY: DWORD = 13850; +pub const ERROR_IPSEC_IKE_NOTCBPRIV: DWORD = 13851; +pub const ERROR_IPSEC_IKE_SECLOADFAIL: DWORD = 13852; +pub const ERROR_IPSEC_IKE_FAILSSPINIT: DWORD = 13853; +pub const ERROR_IPSEC_IKE_FAILQUERYSSP: DWORD = 13854; +pub const ERROR_IPSEC_IKE_SRVACQFAIL: DWORD = 13855; +pub const ERROR_IPSEC_IKE_SRVQUERYCRED: DWORD = 13856; +pub const ERROR_IPSEC_IKE_GETSPIFAIL: DWORD = 13857; +pub const ERROR_IPSEC_IKE_INVALID_FILTER: DWORD = 13858; +pub const ERROR_IPSEC_IKE_OUT_OF_MEMORY: DWORD = 13859; +pub const ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED: DWORD = 13860; +pub const ERROR_IPSEC_IKE_INVALID_POLICY: DWORD = 13861; +pub const ERROR_IPSEC_IKE_UNKNOWN_DOI: DWORD = 13862; +pub const ERROR_IPSEC_IKE_INVALID_SITUATION: DWORD = 13863; +pub const ERROR_IPSEC_IKE_DH_FAILURE: DWORD = 13864; +pub const ERROR_IPSEC_IKE_INVALID_GROUP: DWORD = 13865; +pub const ERROR_IPSEC_IKE_ENCRYPT: DWORD = 13866; +pub const ERROR_IPSEC_IKE_DECRYPT: DWORD = 13867; +pub const ERROR_IPSEC_IKE_POLICY_MATCH: DWORD = 13868; +pub const ERROR_IPSEC_IKE_UNSUPPORTED_ID: DWORD = 13869; +pub const ERROR_IPSEC_IKE_INVALID_HASH: DWORD = 13870; +pub const ERROR_IPSEC_IKE_INVALID_HASH_ALG: DWORD = 13871; +pub const ERROR_IPSEC_IKE_INVALID_HASH_SIZE: DWORD = 13872; +pub const ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG: DWORD = 13873; +pub const ERROR_IPSEC_IKE_INVALID_AUTH_ALG: DWORD = 13874; +pub const ERROR_IPSEC_IKE_INVALID_SIG: DWORD = 13875; +pub const ERROR_IPSEC_IKE_LOAD_FAILED: DWORD = 13876; +pub const ERROR_IPSEC_IKE_RPC_DELETE: DWORD = 13877; +pub const ERROR_IPSEC_IKE_BENIGN_REINIT: DWORD = 13878; +pub const ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY: DWORD = 13879; +pub const ERROR_IPSEC_IKE_INVALID_MAJOR_VERSION: DWORD = 13880; +pub const ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN: DWORD = 13881; +pub const ERROR_IPSEC_IKE_MM_LIMIT: DWORD = 13882; +pub const ERROR_IPSEC_IKE_NEGOTIATION_DISABLED: DWORD = 13883; +pub const ERROR_IPSEC_IKE_QM_LIMIT: DWORD = 13884; +pub const ERROR_IPSEC_IKE_MM_EXPIRED: DWORD = 13885; +pub const ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID: DWORD = 13886; +pub const ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH: DWORD = 13887; +pub const ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID: DWORD = 13888; +pub const ERROR_IPSEC_IKE_INVALID_AUTH_PAYLOAD: DWORD = 13889; +pub const ERROR_IPSEC_IKE_DOS_COOKIE_SENT: DWORD = 13890; +pub const ERROR_IPSEC_IKE_SHUTTING_DOWN: DWORD = 13891; +pub const ERROR_IPSEC_IKE_CGA_AUTH_FAILED: DWORD = 13892; +pub const ERROR_IPSEC_IKE_PROCESS_ERR_NATOA: DWORD = 13893; +pub const ERROR_IPSEC_IKE_INVALID_MM_FOR_QM: DWORD = 13894; +pub const ERROR_IPSEC_IKE_QM_EXPIRED: DWORD = 13895; +pub const ERROR_IPSEC_IKE_TOO_MANY_FILTERS: DWORD = 13896; +pub const ERROR_IPSEC_IKE_NEG_STATUS_END: DWORD = 13897; +pub const ERROR_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL: DWORD = 13898; +pub const ERROR_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE: DWORD = 13899; +pub const ERROR_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING: DWORD = 13900; +pub const ERROR_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING: DWORD = 13901; +pub const ERROR_IPSEC_IKE_COEXISTENCE_SUPPRESS: DWORD = 13902; +pub const ERROR_IPSEC_IKE_RATELIMIT_DROP: DWORD = 13903; +pub const ERROR_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE: DWORD = 13904; +pub const ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE: DWORD = 13905; +pub const ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE: DWORD = 13906; +pub const ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY: DWORD = 13907; +pub const ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE: DWORD = 13908; +pub const ERROR_IPSEC_IKE_NEG_STATUS_EXTENDED_END: DWORD = 13909; +pub const ERROR_IPSEC_BAD_SPI: DWORD = 13910; +pub const ERROR_IPSEC_SA_LIFETIME_EXPIRED: DWORD = 13911; +pub const ERROR_IPSEC_WRONG_SA: DWORD = 13912; +pub const ERROR_IPSEC_REPLAY_CHECK_FAILED: DWORD = 13913; +pub const ERROR_IPSEC_INVALID_PACKET: DWORD = 13914; +pub const ERROR_IPSEC_INTEGRITY_CHECK_FAILED: DWORD = 13915; +pub const ERROR_IPSEC_CLEAR_TEXT_DROP: DWORD = 13916; +pub const ERROR_IPSEC_AUTH_FIREWALL_DROP: DWORD = 13917; +pub const ERROR_IPSEC_THROTTLE_DROP: DWORD = 13918; +pub const ERROR_IPSEC_DOSP_BLOCK: DWORD = 13925; +pub const ERROR_IPSEC_DOSP_RECEIVED_MULTICAST: DWORD = 13926; +pub const ERROR_IPSEC_DOSP_INVALID_PACKET: DWORD = 13927; +pub const ERROR_IPSEC_DOSP_STATE_LOOKUP_FAILED: DWORD = 13928; +pub const ERROR_IPSEC_DOSP_MAX_ENTRIES: DWORD = 13929; +pub const ERROR_IPSEC_DOSP_KEYMOD_NOT_ALLOWED: DWORD = 13930; +pub const ERROR_IPSEC_DOSP_NOT_INSTALLED: DWORD = 13931; +pub const ERROR_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES: DWORD = 13932; +pub const ERROR_SXS_SECTION_NOT_FOUND: DWORD = 14000; +pub const ERROR_SXS_CANT_GEN_ACTCTX: DWORD = 14001; +pub const ERROR_SXS_INVALID_ACTCTXDATA_FORMAT: DWORD = 14002; +pub const ERROR_SXS_ASSEMBLY_NOT_FOUND: DWORD = 14003; +pub const ERROR_SXS_MANIFEST_FORMAT_ERROR: DWORD = 14004; +pub const ERROR_SXS_MANIFEST_PARSE_ERROR: DWORD = 14005; +pub const ERROR_SXS_ACTIVATION_CONTEXT_DISABLED: DWORD = 14006; +pub const ERROR_SXS_KEY_NOT_FOUND: DWORD = 14007; +pub const ERROR_SXS_VERSION_CONFLICT: DWORD = 14008; +pub const ERROR_SXS_WRONG_SECTION_TYPE: DWORD = 14009; +pub const ERROR_SXS_THREAD_QUERIES_DISABLED: DWORD = 14010; +pub const ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET: DWORD = 14011; +pub const ERROR_SXS_UNKNOWN_ENCODING_GROUP: DWORD = 14012; +pub const ERROR_SXS_UNKNOWN_ENCODING: DWORD = 14013; +pub const ERROR_SXS_INVALID_XML_NAMESPACE_URI: DWORD = 14014; +pub const ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED: DWORD = 14015; +pub const ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED: DWORD = 14016; +pub const ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE: DWORD = 14017; +pub const ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE: DWORD = 14018; +pub const ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE: DWORD = 14019; +pub const ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT: DWORD = 14020; +pub const ERROR_SXS_DUPLICATE_DLL_NAME: DWORD = 14021; +pub const ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME: DWORD = 14022; +pub const ERROR_SXS_DUPLICATE_CLSID: DWORD = 14023; +pub const ERROR_SXS_DUPLICATE_IID: DWORD = 14024; +pub const ERROR_SXS_DUPLICATE_TLBID: DWORD = 14025; +pub const ERROR_SXS_DUPLICATE_PROGID: DWORD = 14026; +pub const ERROR_SXS_DUPLICATE_ASSEMBLY_NAME: DWORD = 14027; +pub const ERROR_SXS_FILE_HASH_MISMATCH: DWORD = 14028; +pub const ERROR_SXS_POLICY_PARSE_ERROR: DWORD = 14029; +pub const ERROR_SXS_XML_E_MISSINGQUOTE: DWORD = 14030; +pub const ERROR_SXS_XML_E_COMMENTSYNTAX: DWORD = 14031; +pub const ERROR_SXS_XML_E_BADSTARTNAMECHAR: DWORD = 14032; +pub const ERROR_SXS_XML_E_BADNAMECHAR: DWORD = 14033; +pub const ERROR_SXS_XML_E_BADCHARINSTRING: DWORD = 14034; +pub const ERROR_SXS_XML_E_XMLDECLSYNTAX: DWORD = 14035; +pub const ERROR_SXS_XML_E_BADCHARDATA: DWORD = 14036; +pub const ERROR_SXS_XML_E_MISSINGWHITESPACE: DWORD = 14037; +pub const ERROR_SXS_XML_E_EXPECTINGTAGEND: DWORD = 14038; +pub const ERROR_SXS_XML_E_MISSINGSEMICOLON: DWORD = 14039; +pub const ERROR_SXS_XML_E_UNBALANCEDPAREN: DWORD = 14040; +pub const ERROR_SXS_XML_E_INTERNALERROR: DWORD = 14041; +pub const ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE: DWORD = 14042; +pub const ERROR_SXS_XML_E_INCOMPLETE_ENCODING: DWORD = 14043; +pub const ERROR_SXS_XML_E_MISSING_PAREN: DWORD = 14044; +pub const ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE: DWORD = 14045; +pub const ERROR_SXS_XML_E_MULTIPLE_COLONS: DWORD = 14046; +pub const ERROR_SXS_XML_E_INVALID_DECIMAL: DWORD = 14047; +pub const ERROR_SXS_XML_E_INVALID_HEXIDECIMAL: DWORD = 14048; +pub const ERROR_SXS_XML_E_INVALID_UNICODE: DWORD = 14049; +pub const ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK: DWORD = 14050; +pub const ERROR_SXS_XML_E_UNEXPECTEDENDTAG: DWORD = 14051; +pub const ERROR_SXS_XML_E_UNCLOSEDTAG: DWORD = 14052; +pub const ERROR_SXS_XML_E_DUPLICATEATTRIBUTE: DWORD = 14053; +pub const ERROR_SXS_XML_E_MULTIPLEROOTS: DWORD = 14054; +pub const ERROR_SXS_XML_E_INVALIDATROOTLEVEL: DWORD = 14055; +pub const ERROR_SXS_XML_E_BADXMLDECL: DWORD = 14056; +pub const ERROR_SXS_XML_E_MISSINGROOT: DWORD = 14057; +pub const ERROR_SXS_XML_E_UNEXPECTEDEOF: DWORD = 14058; +pub const ERROR_SXS_XML_E_BADPEREFINSUBSET: DWORD = 14059; +pub const ERROR_SXS_XML_E_UNCLOSEDSTARTTAG: DWORD = 14060; +pub const ERROR_SXS_XML_E_UNCLOSEDENDTAG: DWORD = 14061; +pub const ERROR_SXS_XML_E_UNCLOSEDSTRING: DWORD = 14062; +pub const ERROR_SXS_XML_E_UNCLOSEDCOMMENT: DWORD = 14063; +pub const ERROR_SXS_XML_E_UNCLOSEDDECL: DWORD = 14064; +pub const ERROR_SXS_XML_E_UNCLOSEDCDATA: DWORD = 14065; +pub const ERROR_SXS_XML_E_RESERVEDNAMESPACE: DWORD = 14066; +pub const ERROR_SXS_XML_E_INVALIDENCODING: DWORD = 14067; +pub const ERROR_SXS_XML_E_INVALIDSWITCH: DWORD = 14068; +pub const ERROR_SXS_XML_E_BADXMLCASE: DWORD = 14069; +pub const ERROR_SXS_XML_E_INVALID_STANDALONE: DWORD = 14070; +pub const ERROR_SXS_XML_E_UNEXPECTED_STANDALONE: DWORD = 14071; +pub const ERROR_SXS_XML_E_INVALID_VERSION: DWORD = 14072; +pub const ERROR_SXS_XML_E_MISSINGEQUALS: DWORD = 14073; +pub const ERROR_SXS_PROTECTION_RECOVERY_FAILED: DWORD = 14074; +pub const ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT: DWORD = 14075; +pub const ERROR_SXS_PROTECTION_CATALOG_NOT_VALID: DWORD = 14076; +pub const ERROR_SXS_UNTRANSLATABLE_HRESULT: DWORD = 14077; +pub const ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING: DWORD = 14078; +pub const ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE: DWORD = 14079; +pub const ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME: DWORD = 14080; +pub const ERROR_SXS_ASSEMBLY_MISSING: DWORD = 14081; +pub const ERROR_SXS_CORRUPT_ACTIVATION_STACK: DWORD = 14082; +pub const ERROR_SXS_CORRUPTION: DWORD = 14083; +pub const ERROR_SXS_EARLY_DEACTIVATION: DWORD = 14084; +pub const ERROR_SXS_INVALID_DEACTIVATION: DWORD = 14085; +pub const ERROR_SXS_MULTIPLE_DEACTIVATION: DWORD = 14086; +pub const ERROR_SXS_PROCESS_TERMINATION_REQUESTED: DWORD = 14087; +pub const ERROR_SXS_RELEASE_ACTIVATION_CONTEXT: DWORD = 14088; +pub const ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY: DWORD = 14089; +pub const ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE: DWORD = 14090; +pub const ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME: DWORD = 14091; +pub const ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE: DWORD = 14092; +pub const ERROR_SXS_IDENTITY_PARSE_ERROR: DWORD = 14093; +pub const ERROR_MALFORMED_SUBSTITUTION_STRING: DWORD = 14094; +pub const ERROR_SXS_INCORRECT_PUBLIC_KEY_TOKEN: DWORD = 14095; +pub const ERROR_UNMAPPED_SUBSTITUTION_STRING: DWORD = 14096; +pub const ERROR_SXS_ASSEMBLY_NOT_LOCKED: DWORD = 14097; +pub const ERROR_SXS_COMPONENT_STORE_CORRUPT: DWORD = 14098; +pub const ERROR_ADVANCED_INSTALLER_FAILED: DWORD = 14099; +pub const ERROR_XML_ENCODING_MISMATCH: DWORD = 14100; +pub const ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT: DWORD = 14101; +pub const ERROR_SXS_IDENTITIES_DIFFERENT: DWORD = 14102; +pub const ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT: DWORD = 14103; +pub const ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY: DWORD = 14104; +pub const ERROR_SXS_MANIFEST_TOO_BIG: DWORD = 14105; +pub const ERROR_SXS_SETTING_NOT_REGISTERED: DWORD = 14106; +pub const ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE: DWORD = 14107; +pub const ERROR_SMI_PRIMITIVE_INSTALLER_FAILED: DWORD = 14108; +pub const ERROR_GENERIC_COMMAND_FAILED: DWORD = 14109; +pub const ERROR_SXS_FILE_HASH_MISSING: DWORD = 14110; +pub const ERROR_EVT_INVALID_CHANNEL_PATH: DWORD = 15000; +pub const ERROR_EVT_INVALID_QUERY: DWORD = 15001; +pub const ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND: DWORD = 15002; +pub const ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND: DWORD = 15003; +pub const ERROR_EVT_INVALID_PUBLISHER_NAME: DWORD = 15004; +pub const ERROR_EVT_INVALID_EVENT_DATA: DWORD = 15005; +pub const ERROR_EVT_CHANNEL_NOT_FOUND: DWORD = 15007; +pub const ERROR_EVT_MALFORMED_XML_TEXT: DWORD = 15008; +pub const ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL: DWORD = 15009; +pub const ERROR_EVT_CONFIGURATION_ERROR: DWORD = 15010; +pub const ERROR_EVT_QUERY_RESULT_STALE: DWORD = 15011; +pub const ERROR_EVT_QUERY_RESULT_INVALID_POSITION: DWORD = 15012; +pub const ERROR_EVT_NON_VALIDATING_MSXML: DWORD = 15013; +pub const ERROR_EVT_FILTER_ALREADYSCOPED: DWORD = 15014; +pub const ERROR_EVT_FILTER_NOTELTSET: DWORD = 15015; +pub const ERROR_EVT_FILTER_INVARG: DWORD = 15016; +pub const ERROR_EVT_FILTER_INVTEST: DWORD = 15017; +pub const ERROR_EVT_FILTER_INVTYPE: DWORD = 15018; +pub const ERROR_EVT_FILTER_PARSEERR: DWORD = 15019; +pub const ERROR_EVT_FILTER_UNSUPPORTEDOP: DWORD = 15020; +pub const ERROR_EVT_FILTER_UNEXPECTEDTOKEN: DWORD = 15021; +pub const ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL: DWORD = 15022; +pub const ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE: DWORD = 15023; +pub const ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE: DWORD = 15024; +pub const ERROR_EVT_CHANNEL_CANNOT_ACTIVATE: DWORD = 15025; +pub const ERROR_EVT_FILTER_TOO_COMPLEX: DWORD = 15026; +pub const ERROR_EVT_MESSAGE_NOT_FOUND: DWORD = 15027; +pub const ERROR_EVT_MESSAGE_ID_NOT_FOUND: DWORD = 15028; +pub const ERROR_EVT_UNRESOLVED_VALUE_INSERT: DWORD = 15029; +pub const ERROR_EVT_UNRESOLVED_PARAMETER_INSERT: DWORD = 15030; +pub const ERROR_EVT_MAX_INSERTS_REACHED: DWORD = 15031; +pub const ERROR_EVT_EVENT_DEFINITION_NOT_FOUND: DWORD = 15032; +pub const ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND: DWORD = 15033; +pub const ERROR_EVT_VERSION_TOO_OLD: DWORD = 15034; +pub const ERROR_EVT_VERSION_TOO_NEW: DWORD = 15035; +pub const ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY: DWORD = 15036; +pub const ERROR_EVT_PUBLISHER_DISABLED: DWORD = 15037; +pub const ERROR_EVT_FILTER_OUT_OF_RANGE: DWORD = 15038; +pub const ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE: DWORD = 15080; +pub const ERROR_EC_LOG_DISABLED: DWORD = 15081; +pub const ERROR_EC_CIRCULAR_FORWARDING: DWORD = 15082; +pub const ERROR_EC_CREDSTORE_FULL: DWORD = 15083; +pub const ERROR_EC_CRED_NOT_FOUND: DWORD = 15084; +pub const ERROR_EC_NO_ACTIVE_CHANNEL: DWORD = 15085; +pub const ERROR_MUI_FILE_NOT_FOUND: DWORD = 15100; +pub const ERROR_MUI_INVALID_FILE: DWORD = 15101; +pub const ERROR_MUI_INVALID_RC_CONFIG: DWORD = 15102; +pub const ERROR_MUI_INVALID_LOCALE_NAME: DWORD = 15103; +pub const ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME: DWORD = 15104; +pub const ERROR_MUI_FILE_NOT_LOADED: DWORD = 15105; +pub const ERROR_RESOURCE_ENUM_USER_STOP: DWORD = 15106; +pub const ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED: DWORD = 15107; +pub const ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME: DWORD = 15108; +pub const ERROR_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE: DWORD = 15110; +pub const ERROR_MRM_INVALID_PRICONFIG: DWORD = 15111; +pub const ERROR_MRM_INVALID_FILE_TYPE: DWORD = 15112; +pub const ERROR_MRM_UNKNOWN_QUALIFIER: DWORD = 15113; +pub const ERROR_MRM_INVALID_QUALIFIER_VALUE: DWORD = 15114; +pub const ERROR_MRM_NO_CANDIDATE: DWORD = 15115; +pub const ERROR_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE: DWORD = 15116; +pub const ERROR_MRM_RESOURCE_TYPE_MISMATCH: DWORD = 15117; +pub const ERROR_MRM_DUPLICATE_MAP_NAME: DWORD = 15118; +pub const ERROR_MRM_DUPLICATE_ENTRY: DWORD = 15119; +pub const ERROR_MRM_INVALID_RESOURCE_IDENTIFIER: DWORD = 15120; +pub const ERROR_MRM_FILEPATH_TOO_LONG: DWORD = 15121; +pub const ERROR_MRM_UNSUPPORTED_DIRECTORY_TYPE: DWORD = 15122; +pub const ERROR_MRM_INVALID_PRI_FILE: DWORD = 15126; +pub const ERROR_MRM_NAMED_RESOURCE_NOT_FOUND: DWORD = 15127; +pub const ERROR_MRM_MAP_NOT_FOUND: DWORD = 15135; +pub const ERROR_MRM_UNSUPPORTED_PROFILE_TYPE: DWORD = 15136; +pub const ERROR_MRM_INVALID_QUALIFIER_OPERATOR: DWORD = 15137; +pub const ERROR_MRM_INDETERMINATE_QUALIFIER_VALUE: DWORD = 15138; +pub const ERROR_MRM_AUTOMERGE_ENABLED: DWORD = 15139; +pub const ERROR_MRM_TOO_MANY_RESOURCES: DWORD = 15140; +pub const ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE: DWORD = 15141; +pub const ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE: DWORD = 15142; +pub const ERROR_MRM_NO_CURRENT_VIEW_ON_THREAD: DWORD = 15143; +pub const ERROR_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST: DWORD = 15144; +pub const ERROR_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT: DWORD = 15145; +pub const ERROR_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE: DWORD = 15146; +pub const ERROR_MRM_GENERATION_COUNT_MISMATCH: DWORD = 15147; +pub const ERROR_MCA_INVALID_CAPABILITIES_STRING: DWORD = 15200; +pub const ERROR_MCA_INVALID_VCP_VERSION: DWORD = 15201; +pub const ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION: DWORD = 15202; +pub const ERROR_MCA_MCCS_VERSION_MISMATCH: DWORD = 15203; +pub const ERROR_MCA_UNSUPPORTED_MCCS_VERSION: DWORD = 15204; +pub const ERROR_MCA_INTERNAL_ERROR: DWORD = 15205; +pub const ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED: DWORD = 15206; +pub const ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE: DWORD = 15207; +pub const ERROR_AMBIGUOUS_SYSTEM_DEVICE: DWORD = 15250; +pub const ERROR_SYSTEM_DEVICE_NOT_FOUND: DWORD = 15299; +pub const ERROR_HASH_NOT_SUPPORTED: DWORD = 15300; +pub const ERROR_HASH_NOT_PRESENT: DWORD = 15301; +pub const ERROR_SECONDARY_IC_PROVIDER_NOT_REGISTERED: DWORD = 15321; +pub const ERROR_GPIO_CLIENT_INFORMATION_INVALID: DWORD = 15322; +pub const ERROR_GPIO_VERSION_NOT_SUPPORTED: DWORD = 15323; +pub const ERROR_GPIO_INVALID_REGISTRATION_PACKET: DWORD = 15324; +pub const ERROR_GPIO_OPERATION_DENIED: DWORD = 15325; +pub const ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE: DWORD = 15326; +pub const ERROR_GPIO_INTERRUPT_ALREADY_UNMASKED: DWORD = 15327; +pub const ERROR_CANNOT_SWITCH_RUNLEVEL: DWORD = 15400; +pub const ERROR_INVALID_RUNLEVEL_SETTING: DWORD = 15401; +pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; +pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; +pub const ERROR_RUNLEVEL_SWITCH_IN_PROGRESS: DWORD = 15404; +pub const ERROR_SERVICES_FAILED_AUTOSTART: DWORD = 15405; +pub const ERROR_COM_TASK_STOP_PENDING: DWORD = 15501; +pub const ERROR_INSTALL_OPEN_PACKAGE_FAILED: DWORD = 15600; +pub const ERROR_INSTALL_PACKAGE_NOT_FOUND: DWORD = 15601; +pub const ERROR_INSTALL_INVALID_PACKAGE: DWORD = 15602; +pub const ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED: DWORD = 15603; +pub const ERROR_INSTALL_OUT_OF_DISK_SPACE: DWORD = 15604; +pub const ERROR_INSTALL_NETWORK_FAILURE: DWORD = 15605; +pub const ERROR_INSTALL_REGISTRATION_FAILURE: DWORD = 15606; +pub const ERROR_INSTALL_DEREGISTRATION_FAILURE: DWORD = 15607; +pub const ERROR_INSTALL_CANCEL: DWORD = 15608; +pub const ERROR_INSTALL_FAILED: DWORD = 15609; +pub const ERROR_REMOVE_FAILED: DWORD = 15610; +pub const ERROR_PACKAGE_ALREADY_EXISTS: DWORD = 15611; +pub const ERROR_NEEDS_REMEDIATION: DWORD = 15612; +pub const ERROR_INSTALL_PREREQUISITE_FAILED: DWORD = 15613; +pub const ERROR_PACKAGE_REPOSITORY_CORRUPTED: DWORD = 15614; +pub const ERROR_INSTALL_POLICY_FAILURE: DWORD = 15615; +pub const ERROR_PACKAGE_UPDATING: DWORD = 15616; +pub const ERROR_DEPLOYMENT_BLOCKED_BY_POLICY: DWORD = 15617; +pub const ERROR_PACKAGES_IN_USE: DWORD = 15618; +pub const ERROR_RECOVERY_FILE_CORRUPT: DWORD = 15619; +pub const ERROR_INVALID_STAGED_SIGNATURE: DWORD = 15620; +pub const ERROR_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED: DWORD = 15621; +pub const ERROR_INSTALL_PACKAGE_DOWNGRADE: DWORD = 15622; +pub const ERROR_SYSTEM_NEEDS_REMEDIATION: DWORD = 15623; +pub const ERROR_APPX_INTEGRITY_FAILURE_CLR_NGEN: DWORD = 15624; +pub const ERROR_RESILIENCY_FILE_CORRUPT: DWORD = 15625; +pub const ERROR_INSTALL_FIREWALL_SERVICE_NOT_RUNNING: DWORD = 15626; +pub const APPMODEL_ERROR_NO_PACKAGE: DWORD = 15700; +pub const APPMODEL_ERROR_PACKAGE_RUNTIME_CORRUPT: DWORD = 15701; +pub const APPMODEL_ERROR_PACKAGE_IDENTITY_CORRUPT: DWORD = 15702; +pub const APPMODEL_ERROR_NO_APPLICATION: DWORD = 15703; +pub const APPMODEL_ERROR_DYNAMIC_PROPERTY_READ_FAILED: DWORD = 15704; +pub const APPMODEL_ERROR_DYNAMIC_PROPERTY_INVALID: DWORD = 15705; +pub const ERROR_STATE_LOAD_STORE_FAILED: DWORD = 15800; +pub const ERROR_STATE_GET_VERSION_FAILED: DWORD = 15801; +pub const ERROR_STATE_SET_VERSION_FAILED: DWORD = 15802; +pub const ERROR_STATE_STRUCTURED_RESET_FAILED: DWORD = 15803; +pub const ERROR_STATE_OPEN_CONTAINER_FAILED: DWORD = 15804; +pub const ERROR_STATE_CREATE_CONTAINER_FAILED: DWORD = 15805; +pub const ERROR_STATE_DELETE_CONTAINER_FAILED: DWORD = 15806; +pub const ERROR_STATE_READ_SETTING_FAILED: DWORD = 15807; +pub const ERROR_STATE_WRITE_SETTING_FAILED: DWORD = 15808; +pub const ERROR_STATE_DELETE_SETTING_FAILED: DWORD = 15809; +pub const ERROR_STATE_QUERY_SETTING_FAILED: DWORD = 15810; +pub const ERROR_STATE_READ_COMPOSITE_SETTING_FAILED: DWORD = 15811; +pub const ERROR_STATE_WRITE_COMPOSITE_SETTING_FAILED: DWORD = 15812; +pub const ERROR_STATE_ENUMERATE_CONTAINER_FAILED: DWORD = 15813; +pub const ERROR_STATE_ENUMERATE_SETTINGS_FAILED: DWORD = 15814; +pub const ERROR_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED: DWORD = 15815; +pub const ERROR_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED: DWORD = 15816; +pub const ERROR_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED: DWORD = 15817; +pub const ERROR_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED: DWORD = 15818; +pub const ERROR_API_UNAVAILABLE: DWORD = 15841; +pub const STORE_ERROR_UNLICENSED: DWORD = 15861; +pub const STORE_ERROR_UNLICENSED_USER: DWORD = 15862; +pub const STORE_ERROR_PENDING_COM_TRANSACTION: DWORD = 15863; +pub const STORE_ERROR_LICENSE_REVOKED: DWORD = 15864; +pub const SEVERITY_SUCCESS: HRESULT = 0; +pub const SEVERITY_ERROR: HRESULT = 1; +#[inline] +pub fn SUCCEEDED(hr: HRESULT) -> bool { + hr >= 0 +} +#[inline] +pub fn FAILED(hr: HRESULT) -> bool { + hr < 0 +} +#[inline] +pub fn IS_ERROR(hr: HRESULT) -> bool { + (hr as u32) >> 31 == (SEVERITY_ERROR as u32) +} +#[inline] +pub fn HRESULT_CODE(hr: HRESULT) -> HRESULT { + hr & 0xFFFF +} +#[inline] +pub fn SCODE_CODE(sc: SCODE) -> HRESULT { + sc & 0xFFFF +} +#[inline] +pub fn HRESULT_FACILITY(hr: HRESULT) -> HRESULT { + (hr >> 16) & 0x1fff +} +#[inline] +pub fn SCODE_FACILITY(sc: SCODE) -> HRESULT { + (sc >> 16) & 0x1fff +} +#[inline] +pub fn HRESULT_SEVERITY(hr: HRESULT) -> HRESULT { + (hr >> 31) & 0x1 +} +#[inline] +pub fn SCODE_SEVERITY(sc: SCODE) -> HRESULT { + (sc >> 31) & 0x1 +} +#[inline] +pub fn MAKE_HRESULT(sev: HRESULT, fac: HRESULT, code: HRESULT) -> HRESULT { + (sev << 31) | (fac << 16) | code +} +#[inline] +pub fn MAKE_SCODE(sev: HRESULT, fac: HRESULT, code: HRESULT) -> SCODE { + (sev << 31) | (fac << 16) | code +} +pub const FACILITY_NT_BIT: HRESULT = 0x10000000; +#[inline] +pub fn HRESULT_FROM_WIN32(x: c_ulong) -> HRESULT { + if x as i32 <= 0 { + x as i32 + } else { + ((x & 0x0000FFFF) | ((FACILITY_WIN32 as u32) << 16) | 0x80000000) as i32 + } +} +pub type HRESULT = c_long; +#[inline] +pub fn HRESULT_FROM_NT(x: c_ulong) -> HRESULT { + (x | FACILITY_NT_BIT as u32) as i32 +} +pub const NOERROR: HRESULT = 0; +pub const E_UNEXPECTED: HRESULT = 0x8000FFFF; +pub const E_NOTIMPL: HRESULT = 0x80004001; +pub const E_OUTOFMEMORY: HRESULT = 0x8007000E; +pub const E_INVALIDARG: HRESULT = 0x80070057; +pub const E_NOINTERFACE: HRESULT = 0x80004002; +pub const E_POINTER: HRESULT = 0x80004003; +pub const E_HANDLE: HRESULT = 0x80070006; +pub const E_ABORT: HRESULT = 0x80004004; +pub const E_FAIL: HRESULT = 0x80004005; +pub const E_ACCESSDENIED: HRESULT = 0x80070005; +pub const E_PENDING: HRESULT = 0x8000000A; +pub const E_BOUNDS: HRESULT = 0x8000000B; +pub const E_CHANGED_STATE: HRESULT = 0x8000000C; +pub const E_ILLEGAL_STATE_CHANGE: HRESULT = 0x8000000D; +pub const E_ILLEGAL_METHOD_CALL: HRESULT = 0x8000000E; +pub const RO_E_METADATA_NAME_NOT_FOUND: HRESULT = 0x8000000F; +pub const RO_E_METADATA_NAME_IS_NAMESPACE: HRESULT = 0x80000010; +pub const RO_E_METADATA_INVALID_TYPE_FORMAT: HRESULT = 0x80000011; +pub const RO_E_INVALID_METADATA_FILE: HRESULT = 0x80000012; +pub const RO_E_CLOSED: HRESULT = 0x80000013; +pub const RO_E_EXCLUSIVE_WRITE: HRESULT = 0x80000014; +pub const RO_E_CHANGE_NOTIFICATION_IN_PROGRESS: HRESULT = 0x80000015; +pub const RO_E_ERROR_STRING_NOT_FOUND: HRESULT = 0x80000016; +pub const E_STRING_NOT_NULL_TERMINATED: HRESULT = 0x80000017; +pub const E_ILLEGAL_DELEGATE_ASSIGNMENT: HRESULT = 0x80000018; +pub const E_ASYNC_OPERATION_NOT_STARTED: HRESULT = 0x80000019; +pub const E_APPLICATION_EXITING: HRESULT = 0x8000001A; +pub const E_APPLICATION_VIEW_EXITING: HRESULT = 0x8000001B; +pub const RO_E_MUST_BE_AGILE: HRESULT = 0x8000001C; +pub const RO_E_UNSUPPORTED_FROM_MTA: HRESULT = 0x8000001D; +pub const RO_E_COMMITTED: HRESULT = 0x8000001E; +pub const RO_E_BLOCKED_CROSS_ASTA_CALL: HRESULT = 0x8000001F; +pub const CO_E_INIT_TLS: HRESULT = 0x80004006; +pub const CO_E_INIT_SHARED_ALLOCATOR: HRESULT = 0x80004007; +pub const CO_E_INIT_MEMORY_ALLOCATOR: HRESULT = 0x80004008; +pub const CO_E_INIT_CLASS_CACHE: HRESULT = 0x80004009; +pub const CO_E_INIT_RPC_CHANNEL: HRESULT = 0x8000400A; +pub const CO_E_INIT_TLS_SET_CHANNEL_CONTROL: HRESULT = 0x8000400B; +pub const CO_E_INIT_TLS_CHANNEL_CONTROL: HRESULT = 0x8000400C; +pub const CO_E_INIT_UNACCEPTED_USER_ALLOCATOR: HRESULT = 0x8000400D; +pub const CO_E_INIT_SCM_MUTEX_EXISTS: HRESULT = 0x8000400E; +pub const CO_E_INIT_SCM_FILE_MAPPING_EXISTS: HRESULT = 0x8000400F; +pub const CO_E_INIT_SCM_MAP_VIEW_OF_FILE: HRESULT = 0x80004010; +pub const CO_E_INIT_SCM_EXEC_FAILURE: HRESULT = 0x80004011; +pub const CO_E_INIT_ONLY_SINGLE_THREADED: HRESULT = 0x80004012; +pub const CO_E_CANT_REMOTE: HRESULT = 0x80004013; +pub const CO_E_BAD_SERVER_NAME: HRESULT = 0x80004014; +pub const CO_E_WRONG_SERVER_IDENTITY: HRESULT = 0x80004015; +pub const CO_E_OLE1DDE_DISABLED: HRESULT = 0x80004016; +pub const CO_E_RUNAS_SYNTAX: HRESULT = 0x80004017; +pub const CO_E_CREATEPROCESS_FAILURE: HRESULT = 0x80004018; +pub const CO_E_RUNAS_CREATEPROCESS_FAILURE: HRESULT = 0x80004019; +pub const CO_E_RUNAS_LOGON_FAILURE: HRESULT = 0x8000401A; +pub const CO_E_LAUNCH_PERMSSION_DENIED: HRESULT = 0x8000401B; +pub const CO_E_START_SERVICE_FAILURE: HRESULT = 0x8000401C; +pub const CO_E_REMOTE_COMMUNICATION_FAILURE: HRESULT = 0x8000401D; +pub const CO_E_SERVER_START_TIMEOUT: HRESULT = 0x8000401E; +pub const CO_E_CLSREG_INCONSISTENT: HRESULT = 0x8000401F; +pub const CO_E_IIDREG_INCONSISTENT: HRESULT = 0x80004020; +pub const CO_E_NOT_SUPPORTED: HRESULT = 0x80004021; +pub const CO_E_RELOAD_DLL: HRESULT = 0x80004022; +pub const CO_E_MSI_ERROR: HRESULT = 0x80004023; +pub const CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT: HRESULT = 0x80004024; +pub const CO_E_SERVER_PAUSED: HRESULT = 0x80004025; +pub const CO_E_SERVER_NOT_PAUSED: HRESULT = 0x80004026; +pub const CO_E_CLASS_DISABLED: HRESULT = 0x80004027; +pub const CO_E_CLRNOTAVAILABLE: HRESULT = 0x80004028; +pub const CO_E_ASYNC_WORK_REJECTED: HRESULT = 0x80004029; +pub const CO_E_SERVER_INIT_TIMEOUT: HRESULT = 0x8000402A; +pub const CO_E_NO_SECCTX_IN_ACTIVATE: HRESULT = 0x8000402B; +pub const CO_E_TRACKER_CONFIG: HRESULT = 0x80004030; +pub const CO_E_THREADPOOL_CONFIG: HRESULT = 0x80004031; +pub const CO_E_SXS_CONFIG: HRESULT = 0x80004032; +pub const CO_E_MALFORMED_SPN: HRESULT = 0x80004033; +pub const CO_E_UNREVOKED_REGISTRATION_ON_APARTMENT_SHUTDOWN: HRESULT = 0x80004034; +pub const CO_E_PREMATURE_STUB_RUNDOWN: HRESULT = 0x80004035; +pub const S_OK: HRESULT = 0; +pub const S_FALSE: HRESULT = 1; +pub const OLE_E_FIRST: HRESULT = 0x80040000; +pub const OLE_E_LAST: HRESULT = 0x800400FF; +pub const OLE_S_FIRST: HRESULT = 0x00040000; +pub const OLE_S_LAST: HRESULT = 0x000400FF; +pub const OLE_E_OLEVERB: HRESULT = 0x80040000; +pub const OLE_E_ADVF: HRESULT = 0x80040001; +pub const OLE_E_ENUM_NOMORE: HRESULT = 0x80040002; +pub const OLE_E_ADVISENOTSUPPORTED: HRESULT = 0x80040003; +pub const OLE_E_NOCONNECTION: HRESULT = 0x80040004; +pub const OLE_E_NOTRUNNING: HRESULT = 0x80040005; +pub const OLE_E_NOCACHE: HRESULT = 0x80040006; +pub const OLE_E_BLANK: HRESULT = 0x80040007; +pub const OLE_E_CLASSDIFF: HRESULT = 0x80040008; +pub const OLE_E_CANT_GETMONIKER: HRESULT = 0x80040009; +pub const OLE_E_CANT_BINDTOSOURCE: HRESULT = 0x8004000A; +pub const OLE_E_STATIC: HRESULT = 0x8004000B; +pub const OLE_E_PROMPTSAVECANCELLED: HRESULT = 0x8004000C; +pub const OLE_E_INVALIDRECT: HRESULT = 0x8004000D; +pub const OLE_E_WRONGCOMPOBJ: HRESULT = 0x8004000E; +pub const OLE_E_INVALIDHWND: HRESULT = 0x8004000F; +pub const OLE_E_NOT_INPLACEACTIVE: HRESULT = 0x80040010; +pub const OLE_E_CANTCONVERT: HRESULT = 0x80040011; +pub const OLE_E_NOSTORAGE: HRESULT = 0x80040012; +pub const DV_E_FORMATETC: HRESULT = 0x80040064; +pub const DV_E_DVTARGETDEVICE: HRESULT = 0x80040065; +pub const DV_E_STGMEDIUM: HRESULT = 0x80040066; +pub const DV_E_STATDATA: HRESULT = 0x80040067; +pub const DV_E_LINDEX: HRESULT = 0x80040068; +pub const DV_E_TYMED: HRESULT = 0x80040069; +pub const DV_E_CLIPFORMAT: HRESULT = 0x8004006A; +pub const DV_E_DVASPECT: HRESULT = 0x8004006B; +pub const DV_E_DVTARGETDEVICE_SIZE: HRESULT = 0x8004006C; +pub const DV_E_NOIVIEWOBJECT: HRESULT = 0x8004006D; +pub const DRAGDROP_E_FIRST: HRESULT = 0x80040100; +pub const DRAGDROP_E_LAST: HRESULT = 0x8004010F; +pub const DRAGDROP_S_FIRST: HRESULT = 0x00040100; +pub const DRAGDROP_S_LAST: HRESULT = 0x0004010F; +pub const DRAGDROP_E_NOTREGISTERED: HRESULT = 0x80040100; +pub const DRAGDROP_E_ALREADYREGISTERED: HRESULT = 0x80040101; +pub const DRAGDROP_E_INVALIDHWND: HRESULT = 0x80040102; +pub const DRAGDROP_E_CONCURRENT_DRAG_ATTEMPTED: HRESULT = 0x80040103; +pub const CLASSFACTORY_E_FIRST: HRESULT = 0x80040110; +pub const CLASSFACTORY_E_LAST: HRESULT = 0x8004011F; +pub const CLASSFACTORY_S_FIRST: HRESULT = 0x00040110; +pub const CLASSFACTORY_S_LAST: HRESULT = 0x0004011F; +pub const CLASS_E_NOAGGREGATION: HRESULT = 0x80040110; +pub const CLASS_E_CLASSNOTAVAILABLE: HRESULT = 0x80040111; +pub const CLASS_E_NOTLICENSED: HRESULT = 0x80040112; +pub const MARSHAL_E_FIRST: HRESULT = 0x80040120; +pub const MARSHAL_E_LAST: HRESULT = 0x8004012F; +pub const MARSHAL_S_FIRST: HRESULT = 0x00040120; +pub const MARSHAL_S_LAST: HRESULT = 0x0004012F; +pub const DATA_E_FIRST: HRESULT = 0x80040130; +pub const DATA_E_LAST: HRESULT = 0x8004013F; +pub const DATA_S_FIRST: HRESULT = 0x00040130; +pub const DATA_S_LAST: HRESULT = 0x0004013F; +pub const VIEW_E_FIRST: HRESULT = 0x80040140; +pub const VIEW_E_LAST: HRESULT = 0x8004014F; +pub const VIEW_S_FIRST: HRESULT = 0x00040140; +pub const VIEW_S_LAST: HRESULT = 0x0004014F; +pub const VIEW_E_DRAW: HRESULT = 0x80040140; +pub const REGDB_E_FIRST: HRESULT = 0x80040150; +pub const REGDB_E_LAST: HRESULT = 0x8004015F; +pub const REGDB_S_FIRST: HRESULT = 0x00040150; +pub const REGDB_S_LAST: HRESULT = 0x0004015F; +pub const REGDB_E_READREGDB: HRESULT = 0x80040150; +pub const REGDB_E_WRITEREGDB: HRESULT = 0x80040151; +pub const REGDB_E_KEYMISSING: HRESULT = 0x80040152; +pub const REGDB_E_INVALIDVALUE: HRESULT = 0x80040153; +pub const REGDB_E_CLASSNOTREG: HRESULT = 0x80040154; +pub const REGDB_E_IIDNOTREG: HRESULT = 0x80040155; +pub const REGDB_E_BADTHREADINGMODEL: HRESULT = 0x80040156; +pub const CAT_E_FIRST: HRESULT = 0x80040160; +pub const CAT_E_LAST: HRESULT = 0x80040161; +pub const CAT_E_CATIDNOEXIST: HRESULT = 0x80040160; +pub const CAT_E_NODESCRIPTION: HRESULT = 0x80040161; +pub const CS_E_FIRST: HRESULT = 0x80040164; +pub const CS_E_LAST: HRESULT = 0x8004016F; +pub const CS_E_PACKAGE_NOTFOUND: HRESULT = 0x80040164; +pub const CS_E_NOT_DELETABLE: HRESULT = 0x80040165; +pub const CS_E_CLASS_NOTFOUND: HRESULT = 0x80040166; +pub const CS_E_INVALID_VERSION: HRESULT = 0x80040167; +pub const CS_E_NO_CLASSSTORE: HRESULT = 0x80040168; +pub const CS_E_OBJECT_NOTFOUND: HRESULT = 0x80040169; +pub const CS_E_OBJECT_ALREADY_EXISTS: HRESULT = 0x8004016A; +pub const CS_E_INVALID_PATH: HRESULT = 0x8004016B; +pub const CS_E_NETWORK_ERROR: HRESULT = 0x8004016C; +pub const CS_E_ADMIN_LIMIT_EXCEEDED: HRESULT = 0x8004016D; +pub const CS_E_SCHEMA_MISMATCH: HRESULT = 0x8004016E; +pub const CS_E_INTERNAL_ERROR: HRESULT = 0x8004016F; +pub const CACHE_E_FIRST: HRESULT = 0x80040170; +pub const CACHE_E_LAST: HRESULT = 0x8004017F; +pub const CACHE_S_FIRST: HRESULT = 0x00040170; +pub const CACHE_S_LAST: HRESULT = 0x0004017F; +pub const CACHE_E_NOCACHE_UPDATED: HRESULT = 0x80040170; +pub const OLEOBJ_E_FIRST: HRESULT = 0x80040180; +pub const OLEOBJ_E_LAST: HRESULT = 0x8004018F; +pub const OLEOBJ_S_FIRST: HRESULT = 0x00040180; +pub const OLEOBJ_S_LAST: HRESULT = 0x0004018F; +pub const OLEOBJ_E_NOVERBS: HRESULT = 0x80040180; +pub const OLEOBJ_E_INVALIDVERB: HRESULT = 0x80040181; +pub const CLIENTSITE_E_FIRST: HRESULT = 0x80040190; +pub const CLIENTSITE_E_LAST: HRESULT = 0x8004019F; +pub const CLIENTSITE_S_FIRST: HRESULT = 0x00040190; +pub const CLIENTSITE_S_LAST: HRESULT = 0x0004019F; +pub const INPLACE_E_NOTUNDOABLE: HRESULT = 0x800401A0; +pub const INPLACE_E_NOTOOLSPACE: HRESULT = 0x800401A1; +pub const INPLACE_E_FIRST: HRESULT = 0x800401A0; +pub const INPLACE_E_LAST: HRESULT = 0x800401AF; +pub const INPLACE_S_FIRST: HRESULT = 0x000401A0; +pub const INPLACE_S_LAST: HRESULT = 0x000401AF; +pub const ENUM_E_FIRST: HRESULT = 0x800401B0; +pub const ENUM_E_LAST: HRESULT = 0x800401BF; +pub const ENUM_S_FIRST: HRESULT = 0x000401B0; +pub const ENUM_S_LAST: HRESULT = 0x000401BF; +pub const CONVERT10_E_FIRST: HRESULT = 0x800401C0; +pub const CONVERT10_E_LAST: HRESULT = 0x800401CF; +pub const CONVERT10_S_FIRST: HRESULT = 0x000401C0; +pub const CONVERT10_S_LAST: HRESULT = 0x000401CF; +pub const CONVERT10_E_OLESTREAM_GET: HRESULT = 0x800401C0; +pub const CONVERT10_E_OLESTREAM_PUT: HRESULT = 0x800401C1; +pub const CONVERT10_E_OLESTREAM_FMT: HRESULT = 0x800401C2; +pub const CONVERT10_E_OLESTREAM_BITMAP_TO_DIB: HRESULT = 0x800401C3; +pub const CONVERT10_E_STG_FMT: HRESULT = 0x800401C4; +pub const CONVERT10_E_STG_NO_STD_STREAM: HRESULT = 0x800401C5; +pub const CONVERT10_E_STG_DIB_TO_BITMAP: HRESULT = 0x800401C6; +pub const CLIPBRD_E_FIRST: HRESULT = 0x800401D0; +pub const CLIPBRD_E_LAST: HRESULT = 0x800401DF; +pub const CLIPBRD_S_FIRST: HRESULT = 0x000401D0; +pub const CLIPBRD_S_LAST: HRESULT = 0x000401DF; +pub const CLIPBRD_E_CANT_OPEN: HRESULT = 0x800401D0; +pub const CLIPBRD_E_CANT_EMPTY: HRESULT = 0x800401D1; +pub const CLIPBRD_E_CANT_SET: HRESULT = 0x800401D2; +pub const CLIPBRD_E_BAD_DATA: HRESULT = 0x800401D3; +pub const CLIPBRD_E_CANT_CLOSE: HRESULT = 0x800401D4; +pub const MK_E_FIRST: HRESULT = 0x800401E0; +pub const MK_E_LAST: HRESULT = 0x800401EF; +pub const MK_S_FIRST: HRESULT = 0x000401E0; +pub const MK_S_LAST: HRESULT = 0x000401EF; +pub const MK_E_CONNECTMANUALLY: HRESULT = 0x800401E0; +pub const MK_E_EXCEEDEDDEADLINE: HRESULT = 0x800401E1; +pub const MK_E_NEEDGENERIC: HRESULT = 0x800401E2; +pub const MK_E_UNAVAILABLE: HRESULT = 0x800401E3; +pub const MK_E_SYNTAX: HRESULT = 0x800401E4; +pub const MK_E_NOOBJECT: HRESULT = 0x800401E5; +pub const MK_E_INVALIDEXTENSION: HRESULT = 0x800401E6; +pub const MK_E_INTERMEDIATEINTERFACENOTSUPPORTED: HRESULT = 0x800401E7; +pub const MK_E_NOTBINDABLE: HRESULT = 0x800401E8; +pub const MK_E_NOTBOUND: HRESULT = 0x800401E9; +pub const MK_E_CANTOPENFILE: HRESULT = 0x800401EA; +pub const MK_E_MUSTBOTHERUSER: HRESULT = 0x800401EB; +pub const MK_E_NOINVERSE: HRESULT = 0x800401EC; +pub const MK_E_NOSTORAGE: HRESULT = 0x800401ED; +pub const MK_E_NOPREFIX: HRESULT = 0x800401EE; +pub const MK_E_ENUMERATION_FAILED: HRESULT = 0x800401EF; +pub const CO_E_FIRST: HRESULT = 0x800401F0; +pub const CO_E_LAST: HRESULT = 0x800401FF; +pub const CO_S_FIRST: HRESULT = 0x000401F0; +pub const CO_S_LAST: HRESULT = 0x000401FF; +pub const CO_E_NOTINITIALIZED: HRESULT = 0x800401F0; +pub const CO_E_ALREADYINITIALIZED: HRESULT = 0x800401F1; +pub const CO_E_CANTDETERMINECLASS: HRESULT = 0x800401F2; +pub const CO_E_CLASSSTRING: HRESULT = 0x800401F3; +pub const CO_E_IIDSTRING: HRESULT = 0x800401F4; +pub const CO_E_APPNOTFOUND: HRESULT = 0x800401F5; +pub const CO_E_APPSINGLEUSE: HRESULT = 0x800401F6; +pub const CO_E_ERRORINAPP: HRESULT = 0x800401F7; +pub const CO_E_DLLNOTFOUND: HRESULT = 0x800401F8; +pub const CO_E_ERRORINDLL: HRESULT = 0x800401F9; +pub const CO_E_WRONGOSFORAPP: HRESULT = 0x800401FA; +pub const CO_E_OBJNOTREG: HRESULT = 0x800401FB; +pub const CO_E_OBJISREG: HRESULT = 0x800401FC; +pub const CO_E_OBJNOTCONNECTED: HRESULT = 0x800401FD; +pub const CO_E_APPDIDNTREG: HRESULT = 0x800401FE; +pub const CO_E_RELEASED: HRESULT = 0x800401FF; +pub const EVENT_E_FIRST: HRESULT = 0x80040200; +pub const EVENT_E_LAST: HRESULT = 0x8004021F; +pub const EVENT_S_FIRST: HRESULT = 0x00040200; +pub const EVENT_S_LAST: HRESULT = 0x0004021F; +pub const EVENT_S_SOME_SUBSCRIBERS_FAILED: HRESULT = 0x00040200; +pub const EVENT_E_ALL_SUBSCRIBERS_FAILED: HRESULT = 0x80040201; +pub const EVENT_S_NOSUBSCRIBERS: HRESULT = 0x00040202; +pub const EVENT_E_QUERYSYNTAX: HRESULT = 0x80040203; +pub const EVENT_E_QUERYFIELD: HRESULT = 0x80040204; +pub const EVENT_E_INTERNALEXCEPTION: HRESULT = 0x80040205; +pub const EVENT_E_INTERNALERROR: HRESULT = 0x80040206; +pub const EVENT_E_INVALID_PER_USER_SID: HRESULT = 0x80040207; +pub const EVENT_E_USER_EXCEPTION: HRESULT = 0x80040208; +pub const EVENT_E_TOO_MANY_METHODS: HRESULT = 0x80040209; +pub const EVENT_E_MISSING_EVENTCLASS: HRESULT = 0x8004020A; +pub const EVENT_E_NOT_ALL_REMOVED: HRESULT = 0x8004020B; +pub const EVENT_E_COMPLUS_NOT_INSTALLED: HRESULT = 0x8004020C; +pub const EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT: HRESULT = 0x8004020D; +pub const EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT: HRESULT = 0x8004020E; +pub const EVENT_E_INVALID_EVENT_CLASS_PARTITION: HRESULT = 0x8004020F; +pub const EVENT_E_PER_USER_SID_NOT_LOGGED_ON: HRESULT = 0x80040210; +pub const TPC_E_INVALID_PROPERTY: HRESULT = 0x80040241; +pub const TPC_E_NO_DEFAULT_TABLET: HRESULT = 0x80040212; +pub const TPC_E_UNKNOWN_PROPERTY: HRESULT = 0x8004021B; +pub const TPC_E_INVALID_INPUT_RECT: HRESULT = 0x80040219; +pub const TPC_E_INVALID_STROKE: HRESULT = 0x80040222; +pub const TPC_E_INITIALIZE_FAIL: HRESULT = 0x80040223; +pub const TPC_E_NOT_RELEVANT: HRESULT = 0x80040232; +pub const TPC_E_INVALID_PACKET_DESCRIPTION: HRESULT = 0x80040233; +pub const TPC_E_RECOGNIZER_NOT_REGISTERED: HRESULT = 0x80040235; +pub const TPC_E_INVALID_RIGHTS: HRESULT = 0x80040236; +pub const TPC_E_OUT_OF_ORDER_CALL: HRESULT = 0x80040237; +pub const TPC_E_QUEUE_FULL: HRESULT = 0x80040238; +pub const TPC_E_INVALID_CONFIGURATION: HRESULT = 0x80040239; +pub const TPC_E_INVALID_DATA_FROM_RECOGNIZER: HRESULT = 0x8004023A; +pub const TPC_S_TRUNCATED: HRESULT = 0x00040252; +pub const TPC_S_INTERRUPTED: HRESULT = 0x00040253; +pub const TPC_S_NO_DATA_TO_PROCESS: HRESULT = 0x00040254; +pub const XACT_E_FIRST: HRESULT = 0x8004D000; +pub const XACT_E_LAST: HRESULT = 0x8004D02B; +pub const XACT_S_FIRST: HRESULT = 0x0004D000; +pub const XACT_S_LAST: HRESULT = 0x0004D010; +pub const XACT_E_ALREADYOTHERSINGLEPHASE: HRESULT = 0x8004D000; +pub const XACT_E_CANTRETAIN: HRESULT = 0x8004D001; +pub const XACT_E_COMMITFAILED: HRESULT = 0x8004D002; +pub const XACT_E_COMMITPREVENTED: HRESULT = 0x8004D003; +pub const XACT_E_HEURISTICABORT: HRESULT = 0x8004D004; +pub const XACT_E_HEURISTICCOMMIT: HRESULT = 0x8004D005; +pub const XACT_E_HEURISTICDAMAGE: HRESULT = 0x8004D006; +pub const XACT_E_HEURISTICDANGER: HRESULT = 0x8004D007; +pub const XACT_E_ISOLATIONLEVEL: HRESULT = 0x8004D008; +pub const XACT_E_NOASYNC: HRESULT = 0x8004D009; +pub const XACT_E_NOENLIST: HRESULT = 0x8004D00A; +pub const XACT_E_NOISORETAIN: HRESULT = 0x8004D00B; +pub const XACT_E_NORESOURCE: HRESULT = 0x8004D00C; +pub const XACT_E_NOTCURRENT: HRESULT = 0x8004D00D; +pub const XACT_E_NOTRANSACTION: HRESULT = 0x8004D00E; +pub const XACT_E_NOTSUPPORTED: HRESULT = 0x8004D00F; +pub const XACT_E_UNKNOWNRMGRID: HRESULT = 0x8004D010; +pub const XACT_E_WRONGSTATE: HRESULT = 0x8004D011; +pub const XACT_E_WRONGUOW: HRESULT = 0x8004D012; +pub const XACT_E_XTIONEXISTS: HRESULT = 0x8004D013; +pub const XACT_E_NOIMPORTOBJECT: HRESULT = 0x8004D014; +pub const XACT_E_INVALIDCOOKIE: HRESULT = 0x8004D015; +pub const XACT_E_INDOUBT: HRESULT = 0x8004D016; +pub const XACT_E_NOTIMEOUT: HRESULT = 0x8004D017; +pub const XACT_E_ALREADYINPROGRESS: HRESULT = 0x8004D018; +pub const XACT_E_ABORTED: HRESULT = 0x8004D019; +pub const XACT_E_LOGFULL: HRESULT = 0x8004D01A; +pub const XACT_E_TMNOTAVAILABLE: HRESULT = 0x8004D01B; +pub const XACT_E_CONNECTION_DOWN: HRESULT = 0x8004D01C; +pub const XACT_E_CONNECTION_DENIED: HRESULT = 0x8004D01D; +pub const XACT_E_REENLISTTIMEOUT: HRESULT = 0x8004D01E; +pub const XACT_E_TIP_CONNECT_FAILED: HRESULT = 0x8004D01F; +pub const XACT_E_TIP_PROTOCOL_ERROR: HRESULT = 0x8004D020; +pub const XACT_E_TIP_PULL_FAILED: HRESULT = 0x8004D021; +pub const XACT_E_DEST_TMNOTAVAILABLE: HRESULT = 0x8004D022; +pub const XACT_E_TIP_DISABLED: HRESULT = 0x8004D023; +pub const XACT_E_NETWORK_TX_DISABLED: HRESULT = 0x8004D024; +pub const XACT_E_PARTNER_NETWORK_TX_DISABLED: HRESULT = 0x8004D025; +pub const XACT_E_XA_TX_DISABLED: HRESULT = 0x8004D026; +pub const XACT_E_UNABLE_TO_READ_DTC_CONFIG: HRESULT = 0x8004D027; +pub const XACT_E_UNABLE_TO_LOAD_DTC_PROXY: HRESULT = 0x8004D028; +pub const XACT_E_ABORTING: HRESULT = 0x8004D029; +pub const XACT_E_PUSH_COMM_FAILURE: HRESULT = 0x8004D02A; +pub const XACT_E_PULL_COMM_FAILURE: HRESULT = 0x8004D02B; +pub const XACT_E_LU_TX_DISABLED: HRESULT = 0x8004D02C; +pub const XACT_E_CLERKNOTFOUND: HRESULT = 0x8004D080; +pub const XACT_E_CLERKEXISTS: HRESULT = 0x8004D081; +pub const XACT_E_RECOVERYINPROGRESS: HRESULT = 0x8004D082; +pub const XACT_E_TRANSACTIONCLOSED: HRESULT = 0x8004D083; +pub const XACT_E_INVALIDLSN: HRESULT = 0x8004D084; +pub const XACT_E_REPLAYREQUEST: HRESULT = 0x8004D085; +pub const XACT_S_ASYNC: HRESULT = 0x0004D000; +pub const XACT_S_DEFECT: HRESULT = 0x0004D001; +pub const XACT_S_READONLY: HRESULT = 0x0004D002; +pub const XACT_S_SOMENORETAIN: HRESULT = 0x0004D003; +pub const XACT_S_OKINFORM: HRESULT = 0x0004D004; +pub const XACT_S_MADECHANGESCONTENT: HRESULT = 0x0004D005; +pub const XACT_S_MADECHANGESINFORM: HRESULT = 0x0004D006; +pub const XACT_S_ALLNORETAIN: HRESULT = 0x0004D007; +pub const XACT_S_ABORTING: HRESULT = 0x0004D008; +pub const XACT_S_SINGLEPHASE: HRESULT = 0x0004D009; +pub const XACT_S_LOCALLY_OK: HRESULT = 0x0004D00A; +pub const XACT_S_LASTRESOURCEMANAGER: HRESULT = 0x0004D010; +pub const CONTEXT_E_FIRST: HRESULT = 0x8004E000; +pub const CONTEXT_E_LAST: HRESULT = 0x8004E02F; +pub const CONTEXT_S_FIRST: HRESULT = 0x0004E000; +pub const CONTEXT_S_LAST: HRESULT = 0x0004E02F; +pub const CONTEXT_E_ABORTED: HRESULT = 0x8004E002; +pub const CONTEXT_E_ABORTING: HRESULT = 0x8004E003; +pub const CONTEXT_E_NOCONTEXT: HRESULT = 0x8004E004; +pub const CONTEXT_E_WOULD_DEADLOCK: HRESULT = 0x8004E005; +pub const CONTEXT_E_SYNCH_TIMEOUT: HRESULT = 0x8004E006; +pub const CONTEXT_E_OLDREF: HRESULT = 0x8004E007; +pub const CONTEXT_E_ROLENOTFOUND: HRESULT = 0x8004E00C; +pub const CONTEXT_E_TMNOTAVAILABLE: HRESULT = 0x8004E00F; +pub const CO_E_ACTIVATIONFAILED: HRESULT = 0x8004E021; +pub const CO_E_ACTIVATIONFAILED_EVENTLOGGED: HRESULT = 0x8004E022; +pub const CO_E_ACTIVATIONFAILED_CATALOGERROR: HRESULT = 0x8004E023; +pub const CO_E_ACTIVATIONFAILED_TIMEOUT: HRESULT = 0x8004E024; +pub const CO_E_INITIALIZATIONFAILED: HRESULT = 0x8004E025; +pub const CONTEXT_E_NOJIT: HRESULT = 0x8004E026; +pub const CONTEXT_E_NOTRANSACTION: HRESULT = 0x8004E027; +pub const CO_E_THREADINGMODEL_CHANGED: HRESULT = 0x8004E028; +pub const CO_E_NOIISINTRINSICS: HRESULT = 0x8004E029; +pub const CO_E_NOCOOKIES: HRESULT = 0x8004E02A; +pub const CO_E_DBERROR: HRESULT = 0x8004E02B; +pub const CO_E_NOTPOOLED: HRESULT = 0x8004E02C; +pub const CO_E_NOTCONSTRUCTED: HRESULT = 0x8004E02D; +pub const CO_E_NOSYNCHRONIZATION: HRESULT = 0x8004E02E; +pub const CO_E_ISOLEVELMISMATCH: HRESULT = 0x8004E02F; +pub const CO_E_CALL_OUT_OF_TX_SCOPE_NOT_ALLOWED: HRESULT = 0x8004E030; +pub const CO_E_EXIT_TRANSACTION_SCOPE_NOT_CALLED: HRESULT = 0x8004E031; +pub const OLE_S_USEREG: HRESULT = 0x00040000; +pub const OLE_S_STATIC: HRESULT = 0x00040001; +pub const OLE_S_MAC_CLIPFORMAT: HRESULT = 0x00040002; +pub const DRAGDROP_S_DROP: HRESULT = 0x00040100; +pub const DRAGDROP_S_CANCEL: HRESULT = 0x00040101; +pub const DRAGDROP_S_USEDEFAULTCURSORS: HRESULT = 0x00040102; +pub const DATA_S_SAMEFORMATETC: HRESULT = 0x00040130; +pub const VIEW_S_ALREADY_FROZEN: HRESULT = 0x00040140; +pub const CACHE_S_FORMATETC_NOTSUPPORTED: HRESULT = 0x00040170; +pub const CACHE_S_SAMECACHE: HRESULT = 0x00040171; +pub const CACHE_S_SOMECACHES_NOTUPDATED: HRESULT = 0x00040172; +pub const OLEOBJ_S_INVALIDVERB: HRESULT = 0x00040180; +pub const OLEOBJ_S_CANNOT_DOVERB_NOW: HRESULT = 0x00040181; +pub const OLEOBJ_S_INVALIDHWND: HRESULT = 0x00040182; +pub const INPLACE_S_TRUNCATED: HRESULT = 0x000401A0; +pub const CONVERT10_S_NO_PRESENTATION: HRESULT = 0x000401C0; +pub const MK_S_REDUCED_TO_SELF: HRESULT = 0x000401E2; +pub const MK_S_ME: HRESULT = 0x000401E4; +pub const MK_S_HIM: HRESULT = 0x000401E5; +pub const MK_S_US: HRESULT = 0x000401E6; +pub const MK_S_MONIKERALREADYREGISTERED: HRESULT = 0x000401E7; +pub const SCHED_S_TASK_READY: HRESULT = 0x00041300; +pub const SCHED_S_TASK_RUNNING: HRESULT = 0x00041301; +pub const SCHED_S_TASK_DISABLED: HRESULT = 0x00041302; +pub const SCHED_S_TASK_HAS_NOT_RUN: HRESULT = 0x00041303; +pub const SCHED_S_TASK_NO_MORE_RUNS: HRESULT = 0x00041304; +pub const SCHED_S_TASK_NOT_SCHEDULED: HRESULT = 0x00041305; +pub const SCHED_S_TASK_TERMINATED: HRESULT = 0x00041306; +pub const SCHED_S_TASK_NO_VALID_TRIGGERS: HRESULT = 0x00041307; +pub const SCHED_S_EVENT_TRIGGER: HRESULT = 0x00041308; +pub const SCHED_E_TRIGGER_NOT_FOUND: HRESULT = 0x80041309; +pub const SCHED_E_TASK_NOT_READY: HRESULT = 0x8004130A; +pub const SCHED_E_TASK_NOT_RUNNING: HRESULT = 0x8004130B; +pub const SCHED_E_SERVICE_NOT_INSTALLED: HRESULT = 0x8004130C; +pub const SCHED_E_CANNOT_OPEN_TASK: HRESULT = 0x8004130D; +pub const SCHED_E_INVALID_TASK: HRESULT = 0x8004130E; +pub const SCHED_E_ACCOUNT_INFORMATION_NOT_SET: HRESULT = 0x8004130F; +pub const SCHED_E_ACCOUNT_NAME_NOT_FOUND: HRESULT = 0x80041310; +pub const SCHED_E_ACCOUNT_DBASE_CORRUPT: HRESULT = 0x80041311; +pub const SCHED_E_NO_SECURITY_SERVICES: HRESULT = 0x80041312; +pub const SCHED_E_UNKNOWN_OBJECT_VERSION: HRESULT = 0x80041313; +pub const SCHED_E_UNSUPPORTED_ACCOUNT_OPTION: HRESULT = 0x80041314; +pub const SCHED_E_SERVICE_NOT_RUNNING: HRESULT = 0x80041315; +pub const SCHED_E_UNEXPECTEDNODE: HRESULT = 0x80041316; +pub const SCHED_E_NAMESPACE: HRESULT = 0x80041317; +pub const SCHED_E_INVALIDVALUE: HRESULT = 0x80041318; +pub const SCHED_E_MISSINGNODE: HRESULT = 0x80041319; +pub const SCHED_E_MALFORMEDXML: HRESULT = 0x8004131A; +pub const SCHED_S_SOME_TRIGGERS_FAILED: HRESULT = 0x0004131B; +pub const SCHED_S_BATCH_LOGON_PROBLEM: HRESULT = 0x0004131C; +pub const SCHED_E_TOO_MANY_NODES: HRESULT = 0x8004131D; +pub const SCHED_E_PAST_END_BOUNDARY: HRESULT = 0x8004131E; +pub const SCHED_E_ALREADY_RUNNING: HRESULT = 0x8004131F; +pub const SCHED_E_USER_NOT_LOGGED_ON: HRESULT = 0x80041320; +pub const SCHED_E_INVALID_TASK_HASH: HRESULT = 0x80041321; +pub const SCHED_E_SERVICE_NOT_AVAILABLE: HRESULT = 0x80041322; +pub const SCHED_E_SERVICE_TOO_BUSY: HRESULT = 0x80041323; +pub const SCHED_E_TASK_ATTEMPTED: HRESULT = 0x80041324; +pub const SCHED_S_TASK_QUEUED: HRESULT = 0x00041325; +pub const SCHED_E_TASK_DISABLED: HRESULT = 0x80041326; +pub const SCHED_E_TASK_NOT_V1_COMPAT: HRESULT = 0x80041327; +pub const SCHED_E_START_ON_DEMAND: HRESULT = 0x80041328; +pub const SCHED_E_TASK_NOT_UBPM_COMPAT: HRESULT = 0x80041329; +pub const SCHED_E_DEPRECATED_FEATURE_USED: HRESULT = 0x80041330; +pub const CO_E_CLASS_CREATE_FAILED: HRESULT = 0x80080001; +pub const CO_E_SCM_ERROR: HRESULT = 0x80080002; +pub const CO_E_SCM_RPC_FAILURE: HRESULT = 0x80080003; +pub const CO_E_BAD_PATH: HRESULT = 0x80080004; +pub const CO_E_SERVER_EXEC_FAILURE: HRESULT = 0x80080005; +pub const CO_E_OBJSRV_RPC_FAILURE: HRESULT = 0x80080006; +pub const MK_E_NO_NORMALIZED: HRESULT = 0x80080007; +pub const CO_E_SERVER_STOPPING: HRESULT = 0x80080008; +pub const MEM_E_INVALID_ROOT: HRESULT = 0x80080009; +pub const MEM_E_INVALID_LINK: HRESULT = 0x80080010; +pub const MEM_E_INVALID_SIZE: HRESULT = 0x80080011; +pub const CO_S_NOTALLINTERFACES: HRESULT = 0x00080012; +pub const CO_S_MACHINENAMENOTFOUND: HRESULT = 0x00080013; +pub const CO_E_MISSING_DISPLAYNAME: HRESULT = 0x80080015; +pub const CO_E_RUNAS_VALUE_MUST_BE_AAA: HRESULT = 0x80080016; +pub const CO_E_ELEVATION_DISABLED: HRESULT = 0x80080017; +pub const APPX_E_PACKAGING_INTERNAL: HRESULT = 0x80080200; +pub const APPX_E_INTERLEAVING_NOT_ALLOWED: HRESULT = 0x80080201; +pub const APPX_E_RELATIONSHIPS_NOT_ALLOWED: HRESULT = 0x80080202; +pub const APPX_E_MISSING_REQUIRED_FILE: HRESULT = 0x80080203; +pub const APPX_E_INVALID_MANIFEST: HRESULT = 0x80080204; +pub const APPX_E_INVALID_BLOCKMAP: HRESULT = 0x80080205; +pub const APPX_E_CORRUPT_CONTENT: HRESULT = 0x80080206; +pub const APPX_E_BLOCK_HASH_INVALID: HRESULT = 0x80080207; +pub const APPX_E_REQUESTED_RANGE_TOO_LARGE: HRESULT = 0x80080208; +pub const APPX_E_INVALID_SIP_CLIENT_DATA: HRESULT = 0x80080209; +pub const BT_E_SPURIOUS_ACTIVATION: HRESULT = 0x80080300; +pub const DISP_E_UNKNOWNINTERFACE: HRESULT = 0x80020001; +pub const DISP_E_MEMBERNOTFOUND: HRESULT = 0x80020003; +pub const DISP_E_PARAMNOTFOUND: HRESULT = 0x80020004; +pub const DISP_E_TYPEMISMATCH: HRESULT = 0x80020005; +pub const DISP_E_UNKNOWNNAME: HRESULT = 0x80020006; +pub const DISP_E_NONAMEDARGS: HRESULT = 0x80020007; +pub const DISP_E_BADVARTYPE: HRESULT = 0x80020008; +pub const DISP_E_EXCEPTION: HRESULT = 0x80020009; +pub const DISP_E_OVERFLOW: HRESULT = 0x8002000A; +pub const DISP_E_BADINDEX: HRESULT = 0x8002000B; +pub const DISP_E_UNKNOWNLCID: HRESULT = 0x8002000C; +pub const DISP_E_ARRAYISLOCKED: HRESULT = 0x8002000D; +pub const DISP_E_BADPARAMCOUNT: HRESULT = 0x8002000E; +pub const DISP_E_PARAMNOTOPTIONAL: HRESULT = 0x8002000F; +pub const DISP_E_BADCALLEE: HRESULT = 0x80020010; +pub const DISP_E_NOTACOLLECTION: HRESULT = 0x80020011; +pub const DISP_E_DIVBYZERO: HRESULT = 0x80020012; +pub const DISP_E_BUFFERTOOSMALL: HRESULT = 0x80020013; +pub const TYPE_E_BUFFERTOOSMALL: HRESULT = 0x80028016; +pub const TYPE_E_FIELDNOTFOUND: HRESULT = 0x80028017; +pub const TYPE_E_INVDATAREAD: HRESULT = 0x80028018; +pub const TYPE_E_UNSUPFORMAT: HRESULT = 0x80028019; +pub const TYPE_E_REGISTRYACCESS: HRESULT = 0x8002801C; +pub const TYPE_E_LIBNOTREGISTERED: HRESULT = 0x8002801D; +pub const TYPE_E_UNDEFINEDTYPE: HRESULT = 0x80028027; +pub const TYPE_E_QUALIFIEDNAMEDISALLOWED: HRESULT = 0x80028028; +pub const TYPE_E_INVALIDSTATE: HRESULT = 0x80028029; +pub const TYPE_E_WRONGTYPEKIND: HRESULT = 0x8002802A; +pub const TYPE_E_ELEMENTNOTFOUND: HRESULT = 0x8002802B; +pub const TYPE_E_AMBIGUOUSNAME: HRESULT = 0x8002802C; +pub const TYPE_E_NAMECONFLICT: HRESULT = 0x8002802D; +pub const TYPE_E_UNKNOWNLCID: HRESULT = 0x8002802E; +pub const TYPE_E_DLLFUNCTIONNOTFOUND: HRESULT = 0x8002802F; +pub const TYPE_E_BADMODULEKIND: HRESULT = 0x800288BD; +pub const TYPE_E_SIZETOOBIG: HRESULT = 0x800288C5; +pub const TYPE_E_DUPLICATEID: HRESULT = 0x800288C6; +pub const TYPE_E_INVALIDID: HRESULT = 0x800288CF; +pub const TYPE_E_TYPEMISMATCH: HRESULT = 0x80028CA0; +pub const TYPE_E_OUTOFBOUNDS: HRESULT = 0x80028CA1; +pub const TYPE_E_IOERROR: HRESULT = 0x80028CA2; +pub const TYPE_E_CANTCREATETMPFILE: HRESULT = 0x80028CA3; +pub const TYPE_E_CANTLOADLIBRARY: HRESULT = 0x80029C4A; +pub const TYPE_E_INCONSISTENTPROPFUNCS: HRESULT = 0x80029C83; +pub const TYPE_E_CIRCULARTYPE: HRESULT = 0x80029C84; +pub const STG_E_INVALIDFUNCTION: HRESULT = 0x80030001; +pub const STG_E_FILENOTFOUND: HRESULT = 0x80030002; +pub const STG_E_PATHNOTFOUND: HRESULT = 0x80030003; +pub const STG_E_TOOMANYOPENFILES: HRESULT = 0x80030004; +pub const STG_E_ACCESSDENIED: HRESULT = 0x80030005; +pub const STG_E_INVALIDHANDLE: HRESULT = 0x80030006; +pub const STG_E_INSUFFICIENTMEMORY: HRESULT = 0x80030008; +pub const STG_E_INVALIDPOINTER: HRESULT = 0x80030009; +pub const STG_E_NOMOREFILES: HRESULT = 0x80030012; +pub const STG_E_DISKISWRITEPROTECTED: HRESULT = 0x80030013; +pub const STG_E_SEEKERROR: HRESULT = 0x80030019; +pub const STG_E_WRITEFAULT: HRESULT = 0x8003001D; +pub const STG_E_READFAULT: HRESULT = 0x8003001E; +pub const STG_E_SHAREVIOLATION: HRESULT = 0x80030020; +pub const STG_E_LOCKVIOLATION: HRESULT = 0x80030021; +pub const STG_E_FILEALREADYEXISTS: HRESULT = 0x80030050; +pub const STG_E_INVALIDPARAMETER: HRESULT = 0x80030057; +pub const STG_E_MEDIUMFULL: HRESULT = 0x80030070; +pub const STG_E_PROPSETMISMATCHED: HRESULT = 0x800300F0; +pub const STG_E_ABNORMALAPIEXIT: HRESULT = 0x800300FA; +pub const STG_E_INVALIDHEADER: HRESULT = 0x800300FB; +pub const STG_E_INVALIDNAME: HRESULT = 0x800300FC; +pub const STG_E_UNKNOWN: HRESULT = 0x800300FD; +pub const STG_E_UNIMPLEMENTEDFUNCTION: HRESULT = 0x800300FE; +pub const STG_E_INVALIDFLAG: HRESULT = 0x800300FF; +pub const STG_E_INUSE: HRESULT = 0x80030100; +pub const STG_E_NOTCURRENT: HRESULT = 0x80030101; +pub const STG_E_REVERTED: HRESULT = 0x80030102; +pub const STG_E_CANTSAVE: HRESULT = 0x80030103; +pub const STG_E_OLDFORMAT: HRESULT = 0x80030104; +pub const STG_E_OLDDLL: HRESULT = 0x80030105; +pub const STG_E_SHAREREQUIRED: HRESULT = 0x80030106; +pub const STG_E_NOTFILEBASEDSTORAGE: HRESULT = 0x80030107; +pub const STG_E_EXTANTMARSHALLINGS: HRESULT = 0x80030108; +pub const STG_E_DOCFILECORRUPT: HRESULT = 0x80030109; +pub const STG_E_BADBASEADDRESS: HRESULT = 0x80030110; +pub const STG_E_DOCFILETOOLARGE: HRESULT = 0x80030111; +pub const STG_E_NOTSIMPLEFORMAT: HRESULT = 0x80030112; +pub const STG_E_INCOMPLETE: HRESULT = 0x80030201; +pub const STG_E_TERMINATED: HRESULT = 0x80030202; +pub const STG_S_CONVERTED: HRESULT = 0x00030200; +pub const STG_S_BLOCK: HRESULT = 0x00030201; +pub const STG_S_RETRYNOW: HRESULT = 0x00030202; +pub const STG_S_MONITORING: HRESULT = 0x00030203; +pub const STG_S_MULTIPLEOPENS: HRESULT = 0x00030204; +pub const STG_S_CONSOLIDATIONFAILED: HRESULT = 0x00030205; +pub const STG_S_CANNOTCONSOLIDATE: HRESULT = 0x00030206; +pub const STG_E_STATUS_COPY_PROTECTION_FAILURE: HRESULT = 0x80030305; +pub const STG_E_CSS_AUTHENTICATION_FAILURE: HRESULT = 0x80030306; +pub const STG_E_CSS_KEY_NOT_PRESENT: HRESULT = 0x80030307; +pub const STG_E_CSS_KEY_NOT_ESTABLISHED: HRESULT = 0x80030308; +pub const STG_E_CSS_SCRAMBLED_SECTOR: HRESULT = 0x80030309; +pub const STG_E_CSS_REGION_MISMATCH: HRESULT = 0x8003030A; +pub const STG_E_RESETS_EXHAUSTED: HRESULT = 0x8003030B; +pub const RPC_E_CALL_REJECTED: HRESULT = 0x80010001; +pub const RPC_E_CALL_CANCELED: HRESULT = 0x80010002; +pub const RPC_E_CANTPOST_INSENDCALL: HRESULT = 0x80010003; +pub const RPC_E_CANTCALLOUT_INASYNCCALL: HRESULT = 0x80010004; +pub const RPC_E_CANTCALLOUT_INEXTERNALCALL: HRESULT = 0x80010005; +pub const RPC_E_CONNECTION_TERMINATED: HRESULT = 0x80010006; +pub const RPC_E_SERVER_DIED: HRESULT = 0x80010007; +pub const RPC_E_CLIENT_DIED: HRESULT = 0x80010008; +pub const RPC_E_INVALID_DATAPACKET: HRESULT = 0x80010009; +pub const RPC_E_CANTTRANSMIT_CALL: HRESULT = 0x8001000A; +pub const RPC_E_CLIENT_CANTMARSHAL_DATA: HRESULT = 0x8001000B; +pub const RPC_E_CLIENT_CANTUNMARSHAL_DATA: HRESULT = 0x8001000C; +pub const RPC_E_SERVER_CANTMARSHAL_DATA: HRESULT = 0x8001000D; +pub const RPC_E_SERVER_CANTUNMARSHAL_DATA: HRESULT = 0x8001000E; +pub const RPC_E_INVALID_DATA: HRESULT = 0x8001000F; +pub const RPC_E_INVALID_PARAMETER: HRESULT = 0x80010010; +pub const RPC_E_CANTCALLOUT_AGAIN: HRESULT = 0x80010011; +pub const RPC_E_SERVER_DIED_DNE: HRESULT = 0x80010012; +pub const RPC_E_SYS_CALL_FAILED: HRESULT = 0x80010100; +pub const RPC_E_OUT_OF_RESOURCES: HRESULT = 0x80010101; +pub const RPC_E_ATTEMPTED_MULTITHREAD: HRESULT = 0x80010102; +pub const RPC_E_NOT_REGISTERED: HRESULT = 0x80010103; +pub const RPC_E_FAULT: HRESULT = 0x80010104; +pub const RPC_E_SERVERFAULT: HRESULT = 0x80010105; +pub const RPC_E_CHANGED_MODE: HRESULT = 0x80010106; +pub const RPC_E_INVALIDMETHOD: HRESULT = 0x80010107; +pub const RPC_E_DISCONNECTED: HRESULT = 0x80010108; +pub const RPC_E_RETRY: HRESULT = 0x80010109; +pub const RPC_E_SERVERCALL_RETRYLATER: HRESULT = 0x8001010A; +pub const RPC_E_SERVERCALL_REJECTED: HRESULT = 0x8001010B; +pub const RPC_E_INVALID_CALLDATA: HRESULT = 0x8001010C; +pub const RPC_E_CANTCALLOUT_ININPUTSYNCCALL: HRESULT = 0x8001010D; +pub const RPC_E_WRONG_THREAD: HRESULT = 0x8001010E; +pub const RPC_E_THREAD_NOT_INIT: HRESULT = 0x8001010F; +pub const RPC_E_VERSION_MISMATCH: HRESULT = 0x80010110; +pub const RPC_E_INVALID_HEADER: HRESULT = 0x80010111; +pub const RPC_E_INVALID_EXTENSION: HRESULT = 0x80010112; +pub const RPC_E_INVALID_IPID: HRESULT = 0x80010113; +pub const RPC_E_INVALID_OBJECT: HRESULT = 0x80010114; +pub const RPC_S_CALLPENDING: HRESULT = 0x80010115; +pub const RPC_S_WAITONTIMER: HRESULT = 0x80010116; +pub const RPC_E_CALL_COMPLETE: HRESULT = 0x80010117; +pub const RPC_E_UNSECURE_CALL: HRESULT = 0x80010118; +pub const RPC_E_TOO_LATE: HRESULT = 0x80010119; +pub const RPC_E_NO_GOOD_SECURITY_PACKAGES: HRESULT = 0x8001011A; +pub const RPC_E_ACCESS_DENIED: HRESULT = 0x8001011B; +pub const RPC_E_REMOTE_DISABLED: HRESULT = 0x8001011C; +pub const RPC_E_INVALID_OBJREF: HRESULT = 0x8001011D; +pub const RPC_E_NO_CONTEXT: HRESULT = 0x8001011E; +pub const RPC_E_TIMEOUT: HRESULT = 0x8001011F; +pub const RPC_E_NO_SYNC: HRESULT = 0x80010120; +pub const RPC_E_FULLSIC_REQUIRED: HRESULT = 0x80010121; +pub const RPC_E_INVALID_STD_NAME: HRESULT = 0x80010122; +pub const CO_E_FAILEDTOIMPERSONATE: HRESULT = 0x80010123; +pub const CO_E_FAILEDTOGETSECCTX: HRESULT = 0x80010124; +pub const CO_E_FAILEDTOOPENTHREADTOKEN: HRESULT = 0x80010125; +pub const CO_E_FAILEDTOGETTOKENINFO: HRESULT = 0x80010126; +pub const CO_E_TRUSTEEDOESNTMATCHCLIENT: HRESULT = 0x80010127; +pub const CO_E_FAILEDTOQUERYCLIENTBLANKET: HRESULT = 0x80010128; +pub const CO_E_FAILEDTOSETDACL: HRESULT = 0x80010129; +pub const CO_E_ACCESSCHECKFAILED: HRESULT = 0x8001012A; +pub const CO_E_NETACCESSAPIFAILED: HRESULT = 0x8001012B; +pub const CO_E_WRONGTRUSTEENAMESYNTAX: HRESULT = 0x8001012C; +pub const CO_E_INVALIDSID: HRESULT = 0x8001012D; +pub const CO_E_CONVERSIONFAILED: HRESULT = 0x8001012E; +pub const CO_E_NOMATCHINGSIDFOUND: HRESULT = 0x8001012F; +pub const CO_E_LOOKUPACCSIDFAILED: HRESULT = 0x80010130; +pub const CO_E_NOMATCHINGNAMEFOUND: HRESULT = 0x80010131; +pub const CO_E_LOOKUPACCNAMEFAILED: HRESULT = 0x80010132; +pub const CO_E_SETSERLHNDLFAILED: HRESULT = 0x80010133; +pub const CO_E_FAILEDTOGETWINDIR: HRESULT = 0x80010134; +pub const CO_E_PATHTOOLONG: HRESULT = 0x80010135; +pub const CO_E_FAILEDTOGENUUID: HRESULT = 0x80010136; +pub const CO_E_FAILEDTOCREATEFILE: HRESULT = 0x80010137; +pub const CO_E_FAILEDTOCLOSEHANDLE: HRESULT = 0x80010138; +pub const CO_E_EXCEEDSYSACLLIMIT: HRESULT = 0x80010139; +pub const CO_E_ACESINWRONGORDER: HRESULT = 0x8001013A; +pub const CO_E_INCOMPATIBLESTREAMVERSION: HRESULT = 0x8001013B; +pub const CO_E_FAILEDTOOPENPROCESSTOKEN: HRESULT = 0x8001013C; +pub const CO_E_DECODEFAILED: HRESULT = 0x8001013D; +pub const CO_E_ACNOTINITIALIZED: HRESULT = 0x8001013F; +pub const CO_E_CANCEL_DISABLED: HRESULT = 0x80010140; +pub const RPC_E_UNEXPECTED: HRESULT = 0x8001FFFF; +pub const ERROR_AUDITING_DISABLED: HRESULT = 0xC0090001; +pub const ERROR_ALL_SIDS_FILTERED: HRESULT = 0xC0090002; +pub const ERROR_BIZRULES_NOT_ENABLED: HRESULT = 0xC0090003; +pub const NTE_BAD_UID: HRESULT = 0x80090001; +pub const NTE_BAD_HASH: HRESULT = 0x80090002; +pub const NTE_BAD_KEY: HRESULT = 0x80090003; +pub const NTE_BAD_LEN: HRESULT = 0x80090004; +pub const NTE_BAD_DATA: HRESULT = 0x80090005; +pub const NTE_BAD_SIGNATURE: HRESULT = 0x80090006; +pub const NTE_BAD_VER: HRESULT = 0x80090007; +pub const NTE_BAD_ALGID: HRESULT = 0x80090008; +pub const NTE_BAD_FLAGS: HRESULT = 0x80090009; +pub const NTE_BAD_TYPE: HRESULT = 0x8009000A; +pub const NTE_BAD_KEY_STATE: HRESULT = 0x8009000B; +pub const NTE_BAD_HASH_STATE: HRESULT = 0x8009000C; +pub const NTE_NO_KEY: HRESULT = 0x8009000D; +pub const NTE_NO_MEMORY: HRESULT = 0x8009000E; +pub const NTE_EXISTS: HRESULT = 0x8009000F; +pub const NTE_PERM: HRESULT = 0x80090010; +pub const NTE_NOT_FOUND: HRESULT = 0x80090011; +pub const NTE_DOUBLE_ENCRYPT: HRESULT = 0x80090012; +pub const NTE_BAD_PROVIDER: HRESULT = 0x80090013; +pub const NTE_BAD_PROV_TYPE: HRESULT = 0x80090014; +pub const NTE_BAD_PUBLIC_KEY: HRESULT = 0x80090015; +pub const NTE_BAD_KEYSET: HRESULT = 0x80090016; +pub const NTE_PROV_TYPE_NOT_DEF: HRESULT = 0x80090017; +pub const NTE_PROV_TYPE_ENTRY_BAD: HRESULT = 0x80090018; +pub const NTE_KEYSET_NOT_DEF: HRESULT = 0x80090019; +pub const NTE_KEYSET_ENTRY_BAD: HRESULT = 0x8009001A; +pub const NTE_PROV_TYPE_NO_MATCH: HRESULT = 0x8009001B; +pub const NTE_SIGNATURE_FILE_BAD: HRESULT = 0x8009001C; +pub const NTE_PROVIDER_DLL_FAIL: HRESULT = 0x8009001D; +pub const NTE_PROV_DLL_NOT_FOUND: HRESULT = 0x8009001E; +pub const NTE_BAD_KEYSET_PARAM: HRESULT = 0x8009001F; +pub const NTE_FAIL: HRESULT = 0x80090020; +pub const NTE_SYS_ERR: HRESULT = 0x80090021; +pub const NTE_SILENT_CONTEXT: HRESULT = 0x80090022; +pub const NTE_TOKEN_KEYSET_STORAGE_FULL: HRESULT = 0x80090023; +pub const NTE_TEMPORARY_PROFILE: HRESULT = 0x80090024; +pub const NTE_FIXEDPARAMETER: HRESULT = 0x80090025; +pub const NTE_INVALID_HANDLE: HRESULT = 0x80090026; +pub const NTE_INVALID_PARAMETER: HRESULT = 0x80090027; +pub const NTE_BUFFER_TOO_SMALL: HRESULT = 0x80090028; +pub const NTE_NOT_SUPPORTED: HRESULT = 0x80090029; +pub const NTE_NO_MORE_ITEMS: HRESULT = 0x8009002A; +pub const NTE_BUFFERS_OVERLAP: HRESULT = 0x8009002B; +pub const NTE_DECRYPTION_FAILURE: HRESULT = 0x8009002C; +pub const NTE_INTERNAL_ERROR: HRESULT = 0x8009002D; +pub const NTE_UI_REQUIRED: HRESULT = 0x8009002E; +pub const NTE_HMAC_NOT_SUPPORTED: HRESULT = 0x8009002F; +pub const NTE_DEVICE_NOT_READY: HRESULT = 0x80090030; +pub const NTE_AUTHENTICATION_IGNORED: HRESULT = 0x80090031; +pub const NTE_VALIDATION_FAILED: HRESULT = 0x80090032; +pub const NTE_INCORRECT_PASSWORD: HRESULT = 0x80090033; +pub const NTE_ENCRYPTION_FAILURE: HRESULT = 0x80090034; +pub const NTE_DEVICE_NOT_FOUND: HRESULT = 0x80090035; +pub const SEC_E_INSUFFICIENT_MEMORY: HRESULT = 0x80090300; +pub const SEC_E_INVALID_HANDLE: HRESULT = 0x80090301; +pub const SEC_E_UNSUPPORTED_FUNCTION: HRESULT = 0x80090302; +pub const SEC_E_TARGET_UNKNOWN: HRESULT = 0x80090303; +pub const SEC_E_INTERNAL_ERROR: HRESULT = 0x80090304; +pub const SEC_E_SECPKG_NOT_FOUND: HRESULT = 0x80090305; +pub const SEC_E_NOT_OWNER: HRESULT = 0x80090306; +pub const SEC_E_CANNOT_INSTALL: HRESULT = 0x80090307; +pub const SEC_E_INVALID_TOKEN: HRESULT = 0x80090308; +pub const SEC_E_CANNOT_PACK: HRESULT = 0x80090309; +pub const SEC_E_QOP_NOT_SUPPORTED: HRESULT = 0x8009030A; +pub const SEC_E_NO_IMPERSONATION: HRESULT = 0x8009030B; +pub const SEC_E_LOGON_DENIED: HRESULT = 0x8009030C; +pub const SEC_E_UNKNOWN_CREDENTIALS: HRESULT = 0x8009030D; +pub const SEC_E_NO_CREDENTIALS: HRESULT = 0x8009030E; +pub const SEC_E_MESSAGE_ALTERED: HRESULT = 0x8009030F; +pub const SEC_E_OUT_OF_SEQUENCE: HRESULT = 0x80090310; +pub const SEC_E_NO_AUTHENTICATING_AUTHORITY: HRESULT = 0x80090311; +pub const SEC_I_CONTINUE_NEEDED: HRESULT = 0x00090312; +pub const SEC_I_COMPLETE_NEEDED: HRESULT = 0x00090313; +pub const SEC_I_COMPLETE_AND_CONTINUE: HRESULT = 0x00090314; +pub const SEC_I_LOCAL_LOGON: HRESULT = 0x00090315; +pub const SEC_E_BAD_PKGID: HRESULT = 0x80090316; +pub const SEC_E_CONTEXT_EXPIRED: HRESULT = 0x80090317; +pub const SEC_I_CONTEXT_EXPIRED: HRESULT = 0x00090317; +pub const SEC_E_INCOMPLETE_MESSAGE: HRESULT = 0x80090318; +pub const SEC_E_INCOMPLETE_CREDENTIALS: HRESULT = 0x80090320; +pub const SEC_E_BUFFER_TOO_SMALL: HRESULT = 0x80090321; +pub const SEC_I_INCOMPLETE_CREDENTIALS: HRESULT = 0x00090320; +pub const SEC_I_RENEGOTIATE: HRESULT = 0x00090321; +pub const SEC_E_WRONG_PRINCIPAL: HRESULT = 0x80090322; +pub const SEC_I_NO_LSA_CONTEXT: HRESULT = 0x00090323; +pub const SEC_E_TIME_SKEW: HRESULT = 0x80090324; +pub const SEC_E_UNTRUSTED_ROOT: HRESULT = 0x80090325; +pub const SEC_E_ILLEGAL_MESSAGE: HRESULT = 0x80090326; +pub const SEC_E_CERT_UNKNOWN: HRESULT = 0x80090327; +pub const SEC_E_CERT_EXPIRED: HRESULT = 0x80090328; +pub const SEC_E_ENCRYPT_FAILURE: HRESULT = 0x80090329; +pub const SEC_E_DECRYPT_FAILURE: HRESULT = 0x80090330; +pub const SEC_E_ALGORITHM_MISMATCH: HRESULT = 0x80090331; +pub const SEC_E_SECURITY_QOS_FAILED: HRESULT = 0x80090332; +pub const SEC_E_UNFINISHED_CONTEXT_DELETED: HRESULT = 0x80090333; +pub const SEC_E_NO_TGT_REPLY: HRESULT = 0x80090334; +pub const SEC_E_NO_IP_ADDRESSES: HRESULT = 0x80090335; +pub const SEC_E_WRONG_CREDENTIAL_HANDLE: HRESULT = 0x80090336; +pub const SEC_E_CRYPTO_SYSTEM_INVALID: HRESULT = 0x80090337; +pub const SEC_E_MAX_REFERRALS_EXCEEDED: HRESULT = 0x80090338; +pub const SEC_E_MUST_BE_KDC: HRESULT = 0x80090339; +pub const SEC_E_STRONG_CRYPTO_NOT_SUPPORTED: HRESULT = 0x8009033A; +pub const SEC_E_TOO_MANY_PRINCIPALS: HRESULT = 0x8009033B; +pub const SEC_E_NO_PA_DATA: HRESULT = 0x8009033C; +pub const SEC_E_PKINIT_NAME_MISMATCH: HRESULT = 0x8009033D; +pub const SEC_E_SMARTCARD_LOGON_REQUIRED: HRESULT = 0x8009033E; +pub const SEC_E_SHUTDOWN_IN_PROGRESS: HRESULT = 0x8009033F; +pub const SEC_E_KDC_INVALID_REQUEST: HRESULT = 0x80090340; +pub const SEC_E_KDC_UNABLE_TO_REFER: HRESULT = 0x80090341; +pub const SEC_E_KDC_UNKNOWN_ETYPE: HRESULT = 0x80090342; +pub const SEC_E_UNSUPPORTED_PREAUTH: HRESULT = 0x80090343; +pub const SEC_E_DELEGATION_REQUIRED: HRESULT = 0x80090345; +pub const SEC_E_BAD_BINDINGS: HRESULT = 0x80090346; +pub const SEC_E_MULTIPLE_ACCOUNTS: HRESULT = 0x80090347; +pub const SEC_E_NO_KERB_KEY: HRESULT = 0x80090348; +pub const SEC_E_CERT_WRONG_USAGE: HRESULT = 0x80090349; +pub const SEC_E_DOWNGRADE_DETECTED: HRESULT = 0x80090350; +pub const SEC_E_SMARTCARD_CERT_REVOKED: HRESULT = 0x80090351; +pub const SEC_E_ISSUING_CA_UNTRUSTED: HRESULT = 0x80090352; +pub const SEC_E_REVOCATION_OFFLINE_C: HRESULT = 0x80090353; +pub const SEC_E_PKINIT_CLIENT_FAILURE: HRESULT = 0x80090354; +pub const SEC_E_SMARTCARD_CERT_EXPIRED: HRESULT = 0x80090355; +pub const SEC_E_NO_S4U_PROT_SUPPORT: HRESULT = 0x80090356; +pub const SEC_E_CROSSREALM_DELEGATION_FAILURE: HRESULT = 0x80090357; +pub const SEC_E_REVOCATION_OFFLINE_KDC: HRESULT = 0x80090358; +pub const SEC_E_ISSUING_CA_UNTRUSTED_KDC: HRESULT = 0x80090359; +pub const SEC_E_KDC_CERT_EXPIRED: HRESULT = 0x8009035A; +pub const SEC_E_KDC_CERT_REVOKED: HRESULT = 0x8009035B; +pub const SEC_I_SIGNATURE_NEEDED: HRESULT = 0x0009035C; +pub const SEC_E_INVALID_PARAMETER: HRESULT = 0x8009035D; +pub const SEC_E_DELEGATION_POLICY: HRESULT = 0x8009035E; +pub const SEC_E_POLICY_NLTM_ONLY: HRESULT = 0x8009035F; +pub const SEC_I_NO_RENEGOTIATION: HRESULT = 0x00090360; +pub const SEC_E_NO_CONTEXT: HRESULT = 0x80090361; +pub const SEC_E_PKU2U_CERT_FAILURE: HRESULT = 0x80090362; +pub const SEC_E_MUTUAL_AUTH_FAILED: HRESULT = 0x80090363; +pub const SEC_I_MESSAGE_FRAGMENT: HRESULT = 0x00090364; +pub const SEC_E_ONLY_HTTPS_ALLOWED: HRESULT = 0x80090365; +pub const SEC_I_CONTINUE_NEEDED_MESSAGE_OK: HRESULT = 0x00090366; +pub const SEC_E_APPLICATION_PROTOCOL_MISMATCH: HRESULT = 0x80090367; +pub const SEC_E_NO_SPM: HRESULT = SEC_E_INTERNAL_ERROR; +pub const SEC_E_NOT_SUPPORTED: HRESULT = SEC_E_UNSUPPORTED_FUNCTION; +pub const CRYPT_E_MSG_ERROR: HRESULT = 0x80091001; +pub const CRYPT_E_UNKNOWN_ALGO: HRESULT = 0x80091002; +pub const CRYPT_E_OID_FORMAT: HRESULT = 0x80091003; +pub const CRYPT_E_INVALID_MSG_TYPE: HRESULT = 0x80091004; +pub const CRYPT_E_UNEXPECTED_ENCODING: HRESULT = 0x80091005; +pub const CRYPT_E_AUTH_ATTR_MISSING: HRESULT = 0x80091006; +pub const CRYPT_E_HASH_VALUE: HRESULT = 0x80091007; +pub const CRYPT_E_INVALID_INDEX: HRESULT = 0x80091008; +pub const CRYPT_E_ALREADY_DECRYPTED: HRESULT = 0x80091009; +pub const CRYPT_E_NOT_DECRYPTED: HRESULT = 0x8009100A; +pub const CRYPT_E_RECIPIENT_NOT_FOUND: HRESULT = 0x8009100B; +pub const CRYPT_E_CONTROL_TYPE: HRESULT = 0x8009100C; +pub const CRYPT_E_ISSUER_SERIALNUMBER: HRESULT = 0x8009100D; +pub const CRYPT_E_SIGNER_NOT_FOUND: HRESULT = 0x8009100E; +pub const CRYPT_E_ATTRIBUTES_MISSING: HRESULT = 0x8009100F; +pub const CRYPT_E_STREAM_MSG_NOT_READY: HRESULT = 0x80091010; +pub const CRYPT_E_STREAM_INSUFFICIENT_DATA: HRESULT = 0x80091011; +pub const CRYPT_I_NEW_PROTECTION_REQUIRED: HRESULT = 0x00091012; +pub const CRYPT_E_BAD_LEN: HRESULT = 0x80092001; +pub const CRYPT_E_BAD_ENCODE: HRESULT = 0x80092002; +pub const CRYPT_E_FILE_ERROR: HRESULT = 0x80092003; +pub const CRYPT_E_NOT_FOUND: HRESULT = 0x80092004; +pub const CRYPT_E_EXISTS: HRESULT = 0x80092005; +pub const CRYPT_E_NO_PROVIDER: HRESULT = 0x80092006; +pub const CRYPT_E_SELF_SIGNED: HRESULT = 0x80092007; +pub const CRYPT_E_DELETED_PREV: HRESULT = 0x80092008; +pub const CRYPT_E_NO_MATCH: HRESULT = 0x80092009; +pub const CRYPT_E_UNEXPECTED_MSG_TYPE: HRESULT = 0x8009200A; +pub const CRYPT_E_NO_KEY_PROPERTY: HRESULT = 0x8009200B; +pub const CRYPT_E_NO_DECRYPT_CERT: HRESULT = 0x8009200C; +pub const CRYPT_E_BAD_MSG: HRESULT = 0x8009200D; +pub const CRYPT_E_NO_SIGNER: HRESULT = 0x8009200E; +pub const CRYPT_E_PENDING_CLOSE: HRESULT = 0x8009200F; +pub const CRYPT_E_REVOKED: HRESULT = 0x80092010; +pub const CRYPT_E_NO_REVOCATION_DLL: HRESULT = 0x80092011; +pub const CRYPT_E_NO_REVOCATION_CHECK: HRESULT = 0x80092012; +pub const CRYPT_E_REVOCATION_OFFLINE: HRESULT = 0x80092013; +pub const CRYPT_E_NOT_IN_REVOCATION_DATABASE: HRESULT = 0x80092014; +pub const CRYPT_E_INVALID_NUMERIC_STRING: HRESULT = 0x80092020; +pub const CRYPT_E_INVALID_PRINTABLE_STRING: HRESULT = 0x80092021; +pub const CRYPT_E_INVALID_IA5_STRING: HRESULT = 0x80092022; +pub const CRYPT_E_INVALID_X500_STRING: HRESULT = 0x80092023; +pub const CRYPT_E_NOT_CHAR_STRING: HRESULT = 0x80092024; +pub const CRYPT_E_FILERESIZED: HRESULT = 0x80092025; +pub const CRYPT_E_SECURITY_SETTINGS: HRESULT = 0x80092026; +pub const CRYPT_E_NO_VERIFY_USAGE_DLL: HRESULT = 0x80092027; +pub const CRYPT_E_NO_VERIFY_USAGE_CHECK: HRESULT = 0x80092028; +pub const CRYPT_E_VERIFY_USAGE_OFFLINE: HRESULT = 0x80092029; +pub const CRYPT_E_NOT_IN_CTL: HRESULT = 0x8009202A; +pub const CRYPT_E_NO_TRUSTED_SIGNER: HRESULT = 0x8009202B; +pub const CRYPT_E_MISSING_PUBKEY_PARA: HRESULT = 0x8009202C; +pub const CRYPT_E_OBJECT_LOCATOR_OBJECT_NOT_FOUND: HRESULT = 0x8009202D; +pub const CRYPT_E_OSS_ERROR: HRESULT = 0x80093000; +pub const OSS_MORE_BUF: HRESULT = 0x80093001; +pub const OSS_NEGATIVE_UINTEGER: HRESULT = 0x80093002; +pub const OSS_PDU_RANGE: HRESULT = 0x80093003; +pub const OSS_MORE_INPUT: HRESULT = 0x80093004; +pub const OSS_DATA_ERROR: HRESULT = 0x80093005; +pub const OSS_BAD_ARG: HRESULT = 0x80093006; +pub const OSS_BAD_VERSION: HRESULT = 0x80093007; +pub const OSS_OUT_MEMORY: HRESULT = 0x80093008; +pub const OSS_PDU_MISMATCH: HRESULT = 0x80093009; +pub const OSS_LIMITED: HRESULT = 0x8009300A; +pub const OSS_BAD_PTR: HRESULT = 0x8009300B; +pub const OSS_BAD_TIME: HRESULT = 0x8009300C; +pub const OSS_INDEFINITE_NOT_SUPPORTED: HRESULT = 0x8009300D; +pub const OSS_MEM_ERROR: HRESULT = 0x8009300E; +pub const OSS_BAD_TABLE: HRESULT = 0x8009300F; +pub const OSS_TOO_LONG: HRESULT = 0x80093010; +pub const OSS_CONSTRAINT_VIOLATED: HRESULT = 0x80093011; +pub const OSS_FATAL_ERROR: HRESULT = 0x80093012; +pub const OSS_ACCESS_SERIALIZATION_ERROR: HRESULT = 0x80093013; +pub const OSS_NULL_TBL: HRESULT = 0x80093014; +pub const OSS_NULL_FCN: HRESULT = 0x80093015; +pub const OSS_BAD_ENCRULES: HRESULT = 0x80093016; +pub const OSS_UNAVAIL_ENCRULES: HRESULT = 0x80093017; +pub const OSS_CANT_OPEN_TRACE_WINDOW: HRESULT = 0x80093018; +pub const OSS_UNIMPLEMENTED: HRESULT = 0x80093019; +pub const OSS_OID_DLL_NOT_LINKED: HRESULT = 0x8009301A; +pub const OSS_CANT_OPEN_TRACE_FILE: HRESULT = 0x8009301B; +pub const OSS_TRACE_FILE_ALREADY_OPEN: HRESULT = 0x8009301C; +pub const OSS_TABLE_MISMATCH: HRESULT = 0x8009301D; +pub const OSS_TYPE_NOT_SUPPORTED: HRESULT = 0x8009301E; +pub const OSS_REAL_DLL_NOT_LINKED: HRESULT = 0x8009301F; +pub const OSS_REAL_CODE_NOT_LINKED: HRESULT = 0x80093020; +pub const OSS_OUT_OF_RANGE: HRESULT = 0x80093021; +pub const OSS_COPIER_DLL_NOT_LINKED: HRESULT = 0x80093022; +pub const OSS_CONSTRAINT_DLL_NOT_LINKED: HRESULT = 0x80093023; +pub const OSS_COMPARATOR_DLL_NOT_LINKED: HRESULT = 0x80093024; +pub const OSS_COMPARATOR_CODE_NOT_LINKED: HRESULT = 0x80093025; +pub const OSS_MEM_MGR_DLL_NOT_LINKED: HRESULT = 0x80093026; +pub const OSS_PDV_DLL_NOT_LINKED: HRESULT = 0x80093027; +pub const OSS_PDV_CODE_NOT_LINKED: HRESULT = 0x80093028; +pub const OSS_API_DLL_NOT_LINKED: HRESULT = 0x80093029; +pub const OSS_BERDER_DLL_NOT_LINKED: HRESULT = 0x8009302A; +pub const OSS_PER_DLL_NOT_LINKED: HRESULT = 0x8009302B; +pub const OSS_OPEN_TYPE_ERROR: HRESULT = 0x8009302C; +pub const OSS_MUTEX_NOT_CREATED: HRESULT = 0x8009302D; +pub const OSS_CANT_CLOSE_TRACE_FILE: HRESULT = 0x8009302E; +pub const CRYPT_E_ASN1_ERROR: HRESULT = 0x80093100; +pub const CRYPT_E_ASN1_INTERNAL: HRESULT = 0x80093101; +pub const CRYPT_E_ASN1_EOD: HRESULT = 0x80093102; +pub const CRYPT_E_ASN1_CORRUPT: HRESULT = 0x80093103; +pub const CRYPT_E_ASN1_LARGE: HRESULT = 0x80093104; +pub const CRYPT_E_ASN1_CONSTRAINT: HRESULT = 0x80093105; +pub const CRYPT_E_ASN1_MEMORY: HRESULT = 0x80093106; +pub const CRYPT_E_ASN1_OVERFLOW: HRESULT = 0x80093107; +pub const CRYPT_E_ASN1_BADPDU: HRESULT = 0x80093108; +pub const CRYPT_E_ASN1_BADARGS: HRESULT = 0x80093109; +pub const CRYPT_E_ASN1_BADREAL: HRESULT = 0x8009310A; +pub const CRYPT_E_ASN1_BADTAG: HRESULT = 0x8009310B; +pub const CRYPT_E_ASN1_CHOICE: HRESULT = 0x8009310C; +pub const CRYPT_E_ASN1_RULE: HRESULT = 0x8009310D; +pub const CRYPT_E_ASN1_UTF8: HRESULT = 0x8009310E; +pub const CRYPT_E_ASN1_PDU_TYPE: HRESULT = 0x80093133; +pub const CRYPT_E_ASN1_NYI: HRESULT = 0x80093134; +pub const CRYPT_E_ASN1_EXTENDED: HRESULT = 0x80093201; +pub const CRYPT_E_ASN1_NOEOD: HRESULT = 0x80093202; +pub const CERTSRV_E_BAD_REQUESTSUBJECT: HRESULT = 0x80094001; +pub const CERTSRV_E_NO_REQUEST: HRESULT = 0x80094002; +pub const CERTSRV_E_BAD_REQUESTSTATUS: HRESULT = 0x80094003; +pub const CERTSRV_E_PROPERTY_EMPTY: HRESULT = 0x80094004; +pub const CERTSRV_E_INVALID_CA_CERTIFICATE: HRESULT = 0x80094005; +pub const CERTSRV_E_SERVER_SUSPENDED: HRESULT = 0x80094006; +pub const CERTSRV_E_ENCODING_LENGTH: HRESULT = 0x80094007; +pub const CERTSRV_E_ROLECONFLICT: HRESULT = 0x80094008; +pub const CERTSRV_E_RESTRICTEDOFFICER: HRESULT = 0x80094009; +pub const CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED: HRESULT = 0x8009400A; +pub const CERTSRV_E_NO_VALID_KRA: HRESULT = 0x8009400B; +pub const CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL: HRESULT = 0x8009400C; +pub const CERTSRV_E_NO_CAADMIN_DEFINED: HRESULT = 0x8009400D; +pub const CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE: HRESULT = 0x8009400E; +pub const CERTSRV_E_NO_DB_SESSIONS: HRESULT = 0x8009400F; +pub const CERTSRV_E_ALIGNMENT_FAULT: HRESULT = 0x80094010; +pub const CERTSRV_E_ENROLL_DENIED: HRESULT = 0x80094011; +pub const CERTSRV_E_TEMPLATE_DENIED: HRESULT = 0x80094012; +pub const CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE: HRESULT = 0x80094013; +pub const CERTSRV_E_ADMIN_DENIED_REQUEST: HRESULT = 0x80094014; +pub const CERTSRV_E_NO_POLICY_SERVER: HRESULT = 0x80094015; +pub const CERTSRV_E_WEAK_SIGNATURE_OR_KEY: HRESULT = 0x80094016; +pub const CERTSRV_E_KEY_ATTESTATION_NOT_SUPPORTED: HRESULT = 0x80094017; +pub const CERTSRV_E_ENCRYPTION_CERT_REQUIRED: HRESULT = 0x80094018; +pub const CERTSRV_E_UNSUPPORTED_CERT_TYPE: HRESULT = 0x80094800; +pub const CERTSRV_E_NO_CERT_TYPE: HRESULT = 0x80094801; +pub const CERTSRV_E_TEMPLATE_CONFLICT: HRESULT = 0x80094802; +pub const CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED: HRESULT = 0x80094803; +pub const CERTSRV_E_ARCHIVED_KEY_REQUIRED: HRESULT = 0x80094804; +pub const CERTSRV_E_SMIME_REQUIRED: HRESULT = 0x80094805; +pub const CERTSRV_E_BAD_RENEWAL_SUBJECT: HRESULT = 0x80094806; +pub const CERTSRV_E_BAD_TEMPLATE_VERSION: HRESULT = 0x80094807; +pub const CERTSRV_E_TEMPLATE_POLICY_REQUIRED: HRESULT = 0x80094808; +pub const CERTSRV_E_SIGNATURE_POLICY_REQUIRED: HRESULT = 0x80094809; +pub const CERTSRV_E_SIGNATURE_COUNT: HRESULT = 0x8009480A; +pub const CERTSRV_E_SIGNATURE_REJECTED: HRESULT = 0x8009480B; +pub const CERTSRV_E_ISSUANCE_POLICY_REQUIRED: HRESULT = 0x8009480C; +pub const CERTSRV_E_SUBJECT_UPN_REQUIRED: HRESULT = 0x8009480D; +pub const CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED: HRESULT = 0x8009480E; +pub const CERTSRV_E_SUBJECT_DNS_REQUIRED: HRESULT = 0x8009480F; +pub const CERTSRV_E_ARCHIVED_KEY_UNEXPECTED: HRESULT = 0x80094810; +pub const CERTSRV_E_KEY_LENGTH: HRESULT = 0x80094811; +pub const CERTSRV_E_SUBJECT_EMAIL_REQUIRED: HRESULT = 0x80094812; +pub const CERTSRV_E_UNKNOWN_CERT_TYPE: HRESULT = 0x80094813; +pub const CERTSRV_E_CERT_TYPE_OVERLAP: HRESULT = 0x80094814; +pub const CERTSRV_E_TOO_MANY_SIGNATURES: HRESULT = 0x80094815; +pub const CERTSRV_E_RENEWAL_BAD_PUBLIC_KEY: HRESULT = 0x80094816; +pub const CERTSRV_E_INVALID_EK: HRESULT = 0x80094817; +pub const CERTSRV_E_INVALID_IDBINDING: HRESULT = 0x80094818; +pub const CERTSRV_E_INVALID_ATTESTATION: HRESULT = 0x80094819; +pub const CERTSRV_E_KEY_ATTESTATION: HRESULT = 0x8009481A; +pub const CERTSRV_E_CORRUPT_KEY_ATTESTATION: HRESULT = 0x8009481B; +pub const CERTSRV_E_EXPIRED_CHALLENGE: HRESULT = 0x8009481C; +pub const CERTSRV_E_INVALID_RESPONSE: HRESULT = 0x8009481D; +pub const CERTSRV_E_INVALID_REQUESTID: HRESULT = 0x8009481E; +pub const XENROLL_E_KEY_NOT_EXPORTABLE: HRESULT = 0x80095000; +pub const XENROLL_E_CANNOT_ADD_ROOT_CERT: HRESULT = 0x80095001; +pub const XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND: HRESULT = 0x80095002; +pub const XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH: HRESULT = 0x80095003; +pub const XENROLL_E_RESPONSE_KA_HASH_MISMATCH: HRESULT = 0x80095004; +pub const XENROLL_E_KEYSPEC_SMIME_MISMATCH: HRESULT = 0x80095005; +pub const TRUST_E_SYSTEM_ERROR: HRESULT = 0x80096001; +pub const TRUST_E_NO_SIGNER_CERT: HRESULT = 0x80096002; +pub const TRUST_E_COUNTER_SIGNER: HRESULT = 0x80096003; +pub const TRUST_E_CERT_SIGNATURE: HRESULT = 0x80096004; +pub const TRUST_E_TIME_STAMP: HRESULT = 0x80096005; +pub const TRUST_E_BAD_DIGEST: HRESULT = 0x80096010; +pub const TRUST_E_BASIC_CONSTRAINTS: HRESULT = 0x80096019; +pub const TRUST_E_FINANCIAL_CRITERIA: HRESULT = 0x8009601E; +pub const MSSIPOTF_E_OUTOFMEMRANGE: HRESULT = 0x80097001; +pub const MSSIPOTF_E_CANTGETOBJECT: HRESULT = 0x80097002; +pub const MSSIPOTF_E_NOHEADTABLE: HRESULT = 0x80097003; +pub const MSSIPOTF_E_BAD_MAGICNUMBER: HRESULT = 0x80097004; +pub const MSSIPOTF_E_BAD_OFFSET_TABLE: HRESULT = 0x80097005; +pub const MSSIPOTF_E_TABLE_TAGORDER: HRESULT = 0x80097006; +pub const MSSIPOTF_E_TABLE_LONGWORD: HRESULT = 0x80097007; +pub const MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT: HRESULT = 0x80097008; +pub const MSSIPOTF_E_TABLES_OVERLAP: HRESULT = 0x80097009; +pub const MSSIPOTF_E_TABLE_PADBYTES: HRESULT = 0x8009700A; +pub const MSSIPOTF_E_FILETOOSMALL: HRESULT = 0x8009700B; +pub const MSSIPOTF_E_TABLE_CHECKSUM: HRESULT = 0x8009700C; +pub const MSSIPOTF_E_FILE_CHECKSUM: HRESULT = 0x8009700D; +pub const MSSIPOTF_E_FAILED_POLICY: HRESULT = 0x80097010; +pub const MSSIPOTF_E_FAILED_HINTS_CHECK: HRESULT = 0x80097011; +pub const MSSIPOTF_E_NOT_OPENTYPE: HRESULT = 0x80097012; +pub const MSSIPOTF_E_FILE: HRESULT = 0x80097013; +pub const MSSIPOTF_E_CRYPT: HRESULT = 0x80097014; +pub const MSSIPOTF_E_BADVERSION: HRESULT = 0x80097015; +pub const MSSIPOTF_E_DSIG_STRUCTURE: HRESULT = 0x80097016; +pub const MSSIPOTF_E_PCONST_CHECK: HRESULT = 0x80097017; +pub const MSSIPOTF_E_STRUCTURE: HRESULT = 0x80097018; +pub const ERROR_CRED_REQUIRES_CONFIRMATION: HRESULT = 0x80097019; +pub const NTE_OP_OK: HRESULT = 0; +pub const TRUST_E_PROVIDER_UNKNOWN: HRESULT = 0x800B0001; +pub const TRUST_E_ACTION_UNKNOWN: HRESULT = 0x800B0002; +pub const TRUST_E_SUBJECT_FORM_UNKNOWN: HRESULT = 0x800B0003; +pub const TRUST_E_SUBJECT_NOT_TRUSTED: HRESULT = 0x800B0004; +pub const DIGSIG_E_ENCODE: HRESULT = 0x800B0005; +pub const DIGSIG_E_DECODE: HRESULT = 0x800B0006; +pub const DIGSIG_E_EXTENSIBILITY: HRESULT = 0x800B0007; +pub const DIGSIG_E_CRYPTO: HRESULT = 0x800B0008; +pub const PERSIST_E_SIZEDEFINITE: HRESULT = 0x800B0009; +pub const PERSIST_E_SIZEINDEFINITE: HRESULT = 0x800B000A; +pub const PERSIST_E_NOTSELFSIZING: HRESULT = 0x800B000B; +pub const TRUST_E_NOSIGNATURE: HRESULT = 0x800B0100; +pub const CERT_E_EXPIRED: HRESULT = 0x800B0101; +pub const CERT_E_VALIDITYPERIODNESTING: HRESULT = 0x800B0102; +pub const CERT_E_ROLE: HRESULT = 0x800B0103; +pub const CERT_E_PATHLENCONST: HRESULT = 0x800B0104; +pub const CERT_E_CRITICAL: HRESULT = 0x800B0105; +pub const CERT_E_PURPOSE: HRESULT = 0x800B0106; +pub const CERT_E_ISSUERCHAINING: HRESULT = 0x800B0107; +pub const CERT_E_MALFORMED: HRESULT = 0x800B0108; +pub const CERT_E_UNTRUSTEDROOT: HRESULT = 0x800B0109; +pub const CERT_E_CHAINING: HRESULT = 0x800B010A; +pub const TRUST_E_FAIL: HRESULT = 0x800B010B; +pub const CERT_E_REVOKED: HRESULT = 0x800B010C; +pub const CERT_E_UNTRUSTEDTESTROOT: HRESULT = 0x800B010D; +pub const CERT_E_REVOCATION_FAILURE: HRESULT = 0x800B010E; +pub const CERT_E_CN_NO_MATCH: HRESULT = 0x800B010F; +pub const CERT_E_WRONG_USAGE: HRESULT = 0x800B0110; +pub const TRUST_E_EXPLICIT_DISTRUST: HRESULT = 0x800B0111; +pub const CERT_E_UNTRUSTEDCA: HRESULT = 0x800B0112; +pub const CERT_E_INVALID_POLICY: HRESULT = 0x800B0113; +pub const CERT_E_INVALID_NAME: HRESULT = 0x800B0114; +pub const SPAPI_E_EXPECTED_SECTION_NAME: HRESULT = 0x800F0000; +pub const SPAPI_E_BAD_SECTION_NAME_LINE: HRESULT = 0x800F0001; +pub const SPAPI_E_SECTION_NAME_TOO_LONG: HRESULT = 0x800F0002; +pub const SPAPI_E_GENERAL_SYNTAX: HRESULT = 0x800F0003; +pub const SPAPI_E_WRONG_INF_STYLE: HRESULT = 0x800F0100; +pub const SPAPI_E_SECTION_NOT_FOUND: HRESULT = 0x800F0101; +pub const SPAPI_E_LINE_NOT_FOUND: HRESULT = 0x800F0102; +pub const SPAPI_E_NO_BACKUP: HRESULT = 0x800F0103; +pub const SPAPI_E_NO_ASSOCIATED_CLASS: HRESULT = 0x800F0200; +pub const SPAPI_E_CLASS_MISMATCH: HRESULT = 0x800F0201; +pub const SPAPI_E_DUPLICATE_FOUND: HRESULT = 0x800F0202; +pub const SPAPI_E_NO_DRIVER_SELECTED: HRESULT = 0x800F0203; +pub const SPAPI_E_KEY_DOES_NOT_EXIST: HRESULT = 0x800F0204; +pub const SPAPI_E_INVALID_DEVINST_NAME: HRESULT = 0x800F0205; +pub const SPAPI_E_INVALID_CLASS: HRESULT = 0x800F0206; +pub const SPAPI_E_DEVINST_ALREADY_EXISTS: HRESULT = 0x800F0207; +pub const SPAPI_E_DEVINFO_NOT_REGISTERED: HRESULT = 0x800F0208; +pub const SPAPI_E_INVALID_REG_PROPERTY: HRESULT = 0x800F0209; +pub const SPAPI_E_NO_INF: HRESULT = 0x800F020A; +pub const SPAPI_E_NO_SUCH_DEVINST: HRESULT = 0x800F020B; +pub const SPAPI_E_CANT_LOAD_CLASS_ICON: HRESULT = 0x800F020C; +pub const SPAPI_E_INVALID_CLASS_INSTALLER: HRESULT = 0x800F020D; +pub const SPAPI_E_DI_DO_DEFAULT: HRESULT = 0x800F020E; +pub const SPAPI_E_DI_NOFILECOPY: HRESULT = 0x800F020F; +pub const SPAPI_E_INVALID_HWPROFILE: HRESULT = 0x800F0210; +pub const SPAPI_E_NO_DEVICE_SELECTED: HRESULT = 0x800F0211; +pub const SPAPI_E_DEVINFO_LIST_LOCKED: HRESULT = 0x800F0212; +pub const SPAPI_E_DEVINFO_DATA_LOCKED: HRESULT = 0x800F0213; +pub const SPAPI_E_DI_BAD_PATH: HRESULT = 0x800F0214; +pub const SPAPI_E_NO_CLASSINSTALL_PARAMS: HRESULT = 0x800F0215; +pub const SPAPI_E_FILEQUEUE_LOCKED: HRESULT = 0x800F0216; +pub const SPAPI_E_BAD_SERVICE_INSTALLSECT: HRESULT = 0x800F0217; +pub const SPAPI_E_NO_CLASS_DRIVER_LIST: HRESULT = 0x800F0218; +pub const SPAPI_E_NO_ASSOCIATED_SERVICE: HRESULT = 0x800F0219; +pub const SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE: HRESULT = 0x800F021A; +pub const SPAPI_E_DEVICE_INTERFACE_ACTIVE: HRESULT = 0x800F021B; +pub const SPAPI_E_DEVICE_INTERFACE_REMOVED: HRESULT = 0x800F021C; +pub const SPAPI_E_BAD_INTERFACE_INSTALLSECT: HRESULT = 0x800F021D; +pub const SPAPI_E_NO_SUCH_INTERFACE_CLASS: HRESULT = 0x800F021E; +pub const SPAPI_E_INVALID_REFERENCE_STRING: HRESULT = 0x800F021F; +pub const SPAPI_E_INVALID_MACHINENAME: HRESULT = 0x800F0220; +pub const SPAPI_E_REMOTE_COMM_FAILURE: HRESULT = 0x800F0221; +pub const SPAPI_E_MACHINE_UNAVAILABLE: HRESULT = 0x800F0222; +pub const SPAPI_E_NO_CONFIGMGR_SERVICES: HRESULT = 0x800F0223; +pub const SPAPI_E_INVALID_PROPPAGE_PROVIDER: HRESULT = 0x800F0224; +pub const SPAPI_E_NO_SUCH_DEVICE_INTERFACE: HRESULT = 0x800F0225; +pub const SPAPI_E_DI_POSTPROCESSING_REQUIRED: HRESULT = 0x800F0226; +pub const SPAPI_E_INVALID_COINSTALLER: HRESULT = 0x800F0227; +pub const SPAPI_E_NO_COMPAT_DRIVERS: HRESULT = 0x800F0228; +pub const SPAPI_E_NO_DEVICE_ICON: HRESULT = 0x800F0229; +pub const SPAPI_E_INVALID_INF_LOGCONFIG: HRESULT = 0x800F022A; +pub const SPAPI_E_DI_DONT_INSTALL: HRESULT = 0x800F022B; +pub const SPAPI_E_INVALID_FILTER_DRIVER: HRESULT = 0x800F022C; +pub const SPAPI_E_NON_WINDOWS_NT_DRIVER: HRESULT = 0x800F022D; +pub const SPAPI_E_NON_WINDOWS_DRIVER: HRESULT = 0x800F022E; +pub const SPAPI_E_NO_CATALOG_FOR_OEM_INF: HRESULT = 0x800F022F; +pub const SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE: HRESULT = 0x800F0230; +pub const SPAPI_E_NOT_DISABLEABLE: HRESULT = 0x800F0231; +pub const SPAPI_E_CANT_REMOVE_DEVINST: HRESULT = 0x800F0232; +pub const SPAPI_E_INVALID_TARGET: HRESULT = 0x800F0233; +pub const SPAPI_E_DRIVER_NONNATIVE: HRESULT = 0x800F0234; +pub const SPAPI_E_IN_WOW64: HRESULT = 0x800F0235; +pub const SPAPI_E_SET_SYSTEM_RESTORE_POINT: HRESULT = 0x800F0236; +pub const SPAPI_E_INCORRECTLY_COPIED_INF: HRESULT = 0x800F0237; +pub const SPAPI_E_SCE_DISABLED: HRESULT = 0x800F0238; +pub const SPAPI_E_UNKNOWN_EXCEPTION: HRESULT = 0x800F0239; +pub const SPAPI_E_PNP_REGISTRY_ERROR: HRESULT = 0x800F023A; +pub const SPAPI_E_REMOTE_REQUEST_UNSUPPORTED: HRESULT = 0x800F023B; +pub const SPAPI_E_NOT_AN_INSTALLED_OEM_INF: HRESULT = 0x800F023C; +pub const SPAPI_E_INF_IN_USE_BY_DEVICES: HRESULT = 0x800F023D; +pub const SPAPI_E_DI_FUNCTION_OBSOLETE: HRESULT = 0x800F023E; +pub const SPAPI_E_NO_AUTHENTICODE_CATALOG: HRESULT = 0x800F023F; +pub const SPAPI_E_AUTHENTICODE_DISALLOWED: HRESULT = 0x800F0240; +pub const SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER: HRESULT = 0x800F0241; +pub const SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED: HRESULT = 0x800F0242; +pub const SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED: HRESULT = 0x800F0243; +pub const SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH: HRESULT = 0x800F0244; +pub const SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE: HRESULT = 0x800F0245; +pub const SPAPI_E_DEVICE_INSTALLER_NOT_READY: HRESULT = 0x800F0246; +pub const SPAPI_E_DRIVER_STORE_ADD_FAILED: HRESULT = 0x800F0247; +pub const SPAPI_E_DEVICE_INSTALL_BLOCKED: HRESULT = 0x800F0248; +pub const SPAPI_E_DRIVER_INSTALL_BLOCKED: HRESULT = 0x800F0249; +pub const SPAPI_E_WRONG_INF_TYPE: HRESULT = 0x800F024A; +pub const SPAPI_E_FILE_HASH_NOT_IN_CATALOG: HRESULT = 0x800F024B; +pub const SPAPI_E_DRIVER_STORE_DELETE_FAILED: HRESULT = 0x800F024C; +pub const SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW: HRESULT = 0x800F0300; +pub const SPAPI_E_ERROR_NOT_INSTALLED: HRESULT = 0x800F1000; +pub const SCARD_S_SUCCESS: HRESULT = NO_ERROR as i32; +pub const SCARD_F_INTERNAL_ERROR: HRESULT = 0x80100001; +pub const SCARD_E_CANCELLED: HRESULT = 0x80100002; +pub const SCARD_E_INVALID_HANDLE: HRESULT = 0x80100003; +pub const SCARD_E_INVALID_PARAMETER: HRESULT = 0x80100004; +pub const SCARD_E_INVALID_TARGET: HRESULT = 0x80100005; +pub const SCARD_E_NO_MEMORY: HRESULT = 0x80100006; +pub const SCARD_F_WAITED_TOO_LONG: HRESULT = 0x80100007; +pub const SCARD_E_INSUFFICIENT_BUFFER: HRESULT = 0x80100008; +pub const SCARD_E_UNKNOWN_READER: HRESULT = 0x80100009; +pub const SCARD_E_TIMEOUT: HRESULT = 0x8010000A; +pub const SCARD_E_SHARING_VIOLATION: HRESULT = 0x8010000B; +pub const SCARD_E_NO_SMARTCARD: HRESULT = 0x8010000C; +pub const SCARD_E_UNKNOWN_CARD: HRESULT = 0x8010000D; +pub const SCARD_E_CANT_DISPOSE: HRESULT = 0x8010000E; +pub const SCARD_E_PROTO_MISMATCH: HRESULT = 0x8010000F; +pub const SCARD_E_NOT_READY: HRESULT = 0x80100010; +pub const SCARD_E_INVALID_VALUE: HRESULT = 0x80100011; +pub const SCARD_E_SYSTEM_CANCELLED: HRESULT = 0x80100012; +pub const SCARD_F_COMM_ERROR: HRESULT = 0x80100013; +pub const SCARD_F_UNKNOWN_ERROR: HRESULT = 0x80100014; +pub const SCARD_E_INVALID_ATR: HRESULT = 0x80100015; +pub const SCARD_E_NOT_TRANSACTED: HRESULT = 0x80100016; +pub const SCARD_E_READER_UNAVAILABLE: HRESULT = 0x80100017; +pub const SCARD_P_SHUTDOWN: HRESULT = 0x80100018; +pub const SCARD_E_PCI_TOO_SMALL: HRESULT = 0x80100019; +pub const SCARD_E_READER_UNSUPPORTED: HRESULT = 0x8010001A; +pub const SCARD_E_DUPLICATE_READER: HRESULT = 0x8010001B; +pub const SCARD_E_CARD_UNSUPPORTED: HRESULT = 0x8010001C; +pub const SCARD_E_NO_SERVICE: HRESULT = 0x8010001D; +pub const SCARD_E_SERVICE_STOPPED: HRESULT = 0x8010001E; +pub const SCARD_E_UNEXPECTED: HRESULT = 0x8010001F; +pub const SCARD_E_ICC_INSTALLATION: HRESULT = 0x80100020; +pub const SCARD_E_ICC_CREATEORDER: HRESULT = 0x80100021; +pub const SCARD_E_UNSUPPORTED_FEATURE: HRESULT = 0x80100022; +pub const SCARD_E_DIR_NOT_FOUND: HRESULT = 0x80100023; +pub const SCARD_E_FILE_NOT_FOUND: HRESULT = 0x80100024; +pub const SCARD_E_NO_DIR: HRESULT = 0x80100025; +pub const SCARD_E_NO_FILE: HRESULT = 0x80100026; +pub const SCARD_E_NO_ACCESS: HRESULT = 0x80100027; +pub const SCARD_E_WRITE_TOO_MANY: HRESULT = 0x80100028; +pub const SCARD_E_BAD_SEEK: HRESULT = 0x80100029; +pub const SCARD_E_INVALID_CHV: HRESULT = 0x8010002A; +pub const SCARD_E_UNKNOWN_RES_MNG: HRESULT = 0x8010002B; +pub const SCARD_E_NO_SUCH_CERTIFICATE: HRESULT = 0x8010002C; +pub const SCARD_E_CERTIFICATE_UNAVAILABLE: HRESULT = 0x8010002D; +pub const SCARD_E_NO_READERS_AVAILABLE: HRESULT = 0x8010002E; +pub const SCARD_E_COMM_DATA_LOST: HRESULT = 0x8010002F; +pub const SCARD_E_NO_KEY_CONTAINER: HRESULT = 0x80100030; +pub const SCARD_E_SERVER_TOO_BUSY: HRESULT = 0x80100031; +pub const SCARD_E_PIN_CACHE_EXPIRED: HRESULT = 0x80100032; +pub const SCARD_E_NO_PIN_CACHE: HRESULT = 0x80100033; +pub const SCARD_E_READ_ONLY_CARD: HRESULT = 0x80100034; +pub const SCARD_W_UNSUPPORTED_CARD: HRESULT = 0x80100065; +pub const SCARD_W_UNRESPONSIVE_CARD: HRESULT = 0x80100066; +pub const SCARD_W_UNPOWERED_CARD: HRESULT = 0x80100067; +pub const SCARD_W_RESET_CARD: HRESULT = 0x80100068; +pub const SCARD_W_REMOVED_CARD: HRESULT = 0x80100069; +pub const SCARD_W_SECURITY_VIOLATION: HRESULT = 0x8010006A; +pub const SCARD_W_WRONG_CHV: HRESULT = 0x8010006B; +pub const SCARD_W_CHV_BLOCKED: HRESULT = 0x8010006C; +pub const SCARD_W_EOF: HRESULT = 0x8010006D; +pub const SCARD_W_CANCELLED_BY_USER: HRESULT = 0x8010006E; +pub const SCARD_W_CARD_NOT_AUTHENTICATED: HRESULT = 0x8010006F; +pub const SCARD_W_CACHE_ITEM_NOT_FOUND: HRESULT = 0x80100070; +pub const SCARD_W_CACHE_ITEM_STALE: HRESULT = 0x80100071; +pub const SCARD_W_CACHE_ITEM_TOO_BIG: HRESULT = 0x80100072; +pub const COMADMIN_E_OBJECTERRORS: HRESULT = 0x80110401; +pub const COMADMIN_E_OBJECTINVALID: HRESULT = 0x80110402; +pub const COMADMIN_E_KEYMISSING: HRESULT = 0x80110403; +pub const COMADMIN_E_ALREADYINSTALLED: HRESULT = 0x80110404; +pub const COMADMIN_E_APP_FILE_WRITEFAIL: HRESULT = 0x80110407; +pub const COMADMIN_E_APP_FILE_READFAIL: HRESULT = 0x80110408; +pub const COMADMIN_E_APP_FILE_VERSION: HRESULT = 0x80110409; +pub const COMADMIN_E_BADPATH: HRESULT = 0x8011040A; +pub const COMADMIN_E_APPLICATIONEXISTS: HRESULT = 0x8011040B; +pub const COMADMIN_E_ROLEEXISTS: HRESULT = 0x8011040C; +pub const COMADMIN_E_CANTCOPYFILE: HRESULT = 0x8011040D; +pub const COMADMIN_E_NOUSER: HRESULT = 0x8011040F; +pub const COMADMIN_E_INVALIDUSERIDS: HRESULT = 0x80110410; +pub const COMADMIN_E_NOREGISTRYCLSID: HRESULT = 0x80110411; +pub const COMADMIN_E_BADREGISTRYPROGID: HRESULT = 0x80110412; +pub const COMADMIN_E_AUTHENTICATIONLEVEL: HRESULT = 0x80110413; +pub const COMADMIN_E_USERPASSWDNOTVALID: HRESULT = 0x80110414; +pub const COMADMIN_E_CLSIDORIIDMISMATCH: HRESULT = 0x80110418; +pub const COMADMIN_E_REMOTEINTERFACE: HRESULT = 0x80110419; +pub const COMADMIN_E_DLLREGISTERSERVER: HRESULT = 0x8011041A; +pub const COMADMIN_E_NOSERVERSHARE: HRESULT = 0x8011041B; +pub const COMADMIN_E_DLLLOADFAILED: HRESULT = 0x8011041D; +pub const COMADMIN_E_BADREGISTRYLIBID: HRESULT = 0x8011041E; +pub const COMADMIN_E_APPDIRNOTFOUND: HRESULT = 0x8011041F; +pub const COMADMIN_E_REGISTRARFAILED: HRESULT = 0x80110423; +pub const COMADMIN_E_COMPFILE_DOESNOTEXIST: HRESULT = 0x80110424; +pub const COMADMIN_E_COMPFILE_LOADDLLFAIL: HRESULT = 0x80110425; +pub const COMADMIN_E_COMPFILE_GETCLASSOBJ: HRESULT = 0x80110426; +pub const COMADMIN_E_COMPFILE_CLASSNOTAVAIL: HRESULT = 0x80110427; +pub const COMADMIN_E_COMPFILE_BADTLB: HRESULT = 0x80110428; +pub const COMADMIN_E_COMPFILE_NOTINSTALLABLE: HRESULT = 0x80110429; +pub const COMADMIN_E_NOTCHANGEABLE: HRESULT = 0x8011042A; +pub const COMADMIN_E_NOTDELETEABLE: HRESULT = 0x8011042B; +pub const COMADMIN_E_SESSION: HRESULT = 0x8011042C; +pub const COMADMIN_E_COMP_MOVE_LOCKED: HRESULT = 0x8011042D; +pub const COMADMIN_E_COMP_MOVE_BAD_DEST: HRESULT = 0x8011042E; +pub const COMADMIN_E_REGISTERTLB: HRESULT = 0x80110430; +pub const COMADMIN_E_SYSTEMAPP: HRESULT = 0x80110433; +pub const COMADMIN_E_COMPFILE_NOREGISTRAR: HRESULT = 0x80110434; +pub const COMADMIN_E_COREQCOMPINSTALLED: HRESULT = 0x80110435; +pub const COMADMIN_E_SERVICENOTINSTALLED: HRESULT = 0x80110436; +pub const COMADMIN_E_PROPERTYSAVEFAILED: HRESULT = 0x80110437; +pub const COMADMIN_E_OBJECTEXISTS: HRESULT = 0x80110438; +pub const COMADMIN_E_COMPONENTEXISTS: HRESULT = 0x80110439; +pub const COMADMIN_E_REGFILE_CORRUPT: HRESULT = 0x8011043B; +pub const COMADMIN_E_PROPERTY_OVERFLOW: HRESULT = 0x8011043C; +pub const COMADMIN_E_NOTINREGISTRY: HRESULT = 0x8011043E; +pub const COMADMIN_E_OBJECTNOTPOOLABLE: HRESULT = 0x8011043F; +pub const COMADMIN_E_APPLID_MATCHES_CLSID: HRESULT = 0x80110446; +pub const COMADMIN_E_ROLE_DOES_NOT_EXIST: HRESULT = 0x80110447; +pub const COMADMIN_E_START_APP_NEEDS_COMPONENTS: HRESULT = 0x80110448; +pub const COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM: HRESULT = 0x80110449; +pub const COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY: HRESULT = 0x8011044A; +pub const COMADMIN_E_CAN_NOT_START_APP: HRESULT = 0x8011044B; +pub const COMADMIN_E_CAN_NOT_EXPORT_SYS_APP: HRESULT = 0x8011044C; +pub const COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT: HRESULT = 0x8011044D; +pub const COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER: HRESULT = 0x8011044E; +pub const COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE: HRESULT = 0x8011044F; +pub const COMADMIN_E_BASE_PARTITION_ONLY: HRESULT = 0x80110450; +pub const COMADMIN_E_START_APP_DISABLED: HRESULT = 0x80110451; +pub const COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME: HRESULT = 0x80110457; +pub const COMADMIN_E_CAT_INVALID_PARTITION_NAME: HRESULT = 0x80110458; +pub const COMADMIN_E_CAT_PARTITION_IN_USE: HRESULT = 0x80110459; +pub const COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES: HRESULT = 0x8011045A; +pub const COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED: HRESULT = 0x8011045B; +pub const COMADMIN_E_AMBIGUOUS_APPLICATION_NAME: HRESULT = 0x8011045C; +pub const COMADMIN_E_AMBIGUOUS_PARTITION_NAME: HRESULT = 0x8011045D; +pub const COMADMIN_E_REGDB_NOTINITIALIZED: HRESULT = 0x80110472; +pub const COMADMIN_E_REGDB_NOTOPEN: HRESULT = 0x80110473; +pub const COMADMIN_E_REGDB_SYSTEMERR: HRESULT = 0x80110474; +pub const COMADMIN_E_REGDB_ALREADYRUNNING: HRESULT = 0x80110475; +pub const COMADMIN_E_MIG_VERSIONNOTSUPPORTED: HRESULT = 0x80110480; +pub const COMADMIN_E_MIG_SCHEMANOTFOUND: HRESULT = 0x80110481; +pub const COMADMIN_E_CAT_BITNESSMISMATCH: HRESULT = 0x80110482; +pub const COMADMIN_E_CAT_UNACCEPTABLEBITNESS: HRESULT = 0x80110483; +pub const COMADMIN_E_CAT_WRONGAPPBITNESS: HRESULT = 0x80110484; +pub const COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED: HRESULT = 0x80110485; +pub const COMADMIN_E_CAT_SERVERFAULT: HRESULT = 0x80110486; +pub const COMQC_E_APPLICATION_NOT_QUEUED: HRESULT = 0x80110600; +pub const COMQC_E_NO_QUEUEABLE_INTERFACES: HRESULT = 0x80110601; +pub const COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE: HRESULT = 0x80110602; +pub const COMQC_E_NO_IPERSISTSTREAM: HRESULT = 0x80110603; +pub const COMQC_E_BAD_MESSAGE: HRESULT = 0x80110604; +pub const COMQC_E_UNAUTHENTICATED: HRESULT = 0x80110605; +pub const COMQC_E_UNTRUSTED_ENQUEUER: HRESULT = 0x80110606; +pub const MSDTC_E_DUPLICATE_RESOURCE: HRESULT = 0x80110701; +pub const COMADMIN_E_OBJECT_PARENT_MISSING: HRESULT = 0x80110808; +pub const COMADMIN_E_OBJECT_DOES_NOT_EXIST: HRESULT = 0x80110809; +pub const COMADMIN_E_APP_NOT_RUNNING: HRESULT = 0x8011080A; +pub const COMADMIN_E_INVALID_PARTITION: HRESULT = 0x8011080B; +pub const COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE: HRESULT = 0x8011080D; +pub const COMADMIN_E_USER_IN_SET: HRESULT = 0x8011080E; +pub const COMADMIN_E_CANTRECYCLELIBRARYAPPS: HRESULT = 0x8011080F; +pub const COMADMIN_E_CANTRECYCLESERVICEAPPS: HRESULT = 0x80110811; +pub const COMADMIN_E_PROCESSALREADYRECYCLED: HRESULT = 0x80110812; +pub const COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED: HRESULT = 0x80110813; +pub const COMADMIN_E_CANTMAKEINPROCSERVICE: HRESULT = 0x80110814; +pub const COMADMIN_E_PROGIDINUSEBYCLSID: HRESULT = 0x80110815; +pub const COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET: HRESULT = 0x80110816; +pub const COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED: HRESULT = 0x80110817; +pub const COMADMIN_E_PARTITION_ACCESSDENIED: HRESULT = 0x80110818; +pub const COMADMIN_E_PARTITION_MSI_ONLY: HRESULT = 0x80110819; +pub const COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT: HRESULT = 0x8011081A; +pub const COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS: HRESULT + = 0x8011081B; +pub const COMADMIN_E_COMP_MOVE_SOURCE: HRESULT = 0x8011081C; +pub const COMADMIN_E_COMP_MOVE_DEST: HRESULT = 0x8011081D; +pub const COMADMIN_E_COMP_MOVE_PRIVATE: HRESULT = 0x8011081E; +pub const COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET: HRESULT = 0x8011081F; +pub const COMADMIN_E_CANNOT_ALIAS_EVENTCLASS: HRESULT = 0x80110820; +pub const COMADMIN_E_PRIVATE_ACCESSDENIED: HRESULT = 0x80110821; +pub const COMADMIN_E_SAFERINVALID: HRESULT = 0x80110822; +pub const COMADMIN_E_REGISTRY_ACCESSDENIED: HRESULT = 0x80110823; +pub const COMADMIN_E_PARTITIONS_DISABLED: HRESULT = 0x80110824; +pub const WER_S_REPORT_DEBUG: HRESULT = 0x001B0000; +pub const WER_S_REPORT_UPLOADED: HRESULT = 0x001B0001; +pub const WER_S_REPORT_QUEUED: HRESULT = 0x001B0002; +pub const WER_S_DISABLED: HRESULT = 0x001B0003; +pub const WER_S_SUSPENDED_UPLOAD: HRESULT = 0x001B0004; +pub const WER_S_DISABLED_QUEUE: HRESULT = 0x001B0005; +pub const WER_S_DISABLED_ARCHIVE: HRESULT = 0x001B0006; +pub const WER_S_REPORT_ASYNC: HRESULT = 0x001B0007; +pub const WER_S_IGNORE_ASSERT_INSTANCE: HRESULT = 0x001B0008; +pub const WER_S_IGNORE_ALL_ASSERTS: HRESULT = 0x001B0009; +pub const WER_S_ASSERT_CONTINUE: HRESULT = 0x001B000A; +pub const WER_S_THROTTLED: HRESULT = 0x001B000B; +pub const WER_E_CRASH_FAILURE: HRESULT = 0x801B8000; +pub const WER_E_CANCELED: HRESULT = 0x801B8001; +pub const WER_E_NETWORK_FAILURE: HRESULT = 0x801B8002; +pub const WER_E_NOT_INITIALIZED: HRESULT = 0x801B8003; +pub const WER_E_ALREADY_REPORTING: HRESULT = 0x801B8004; +pub const WER_E_DUMP_THROTTLED: HRESULT = 0x801B8005; +pub const ERROR_FLT_IO_COMPLETE: HRESULT = 0x001F0001; +pub const ERROR_FLT_NO_HANDLER_DEFINED: HRESULT = 0x801F0001; +pub const ERROR_FLT_CONTEXT_ALREADY_DEFINED: HRESULT = 0x801F0002; +pub const ERROR_FLT_INVALID_ASYNCHRONOUS_REQUEST: HRESULT = 0x801F0003; +pub const ERROR_FLT_DISALLOW_FAST_IO: HRESULT = 0x801F0004; +pub const ERROR_FLT_INVALID_NAME_REQUEST: HRESULT = 0x801F0005; +pub const ERROR_FLT_NOT_SAFE_TO_POST_OPERATION: HRESULT = 0x801F0006; +pub const ERROR_FLT_NOT_INITIALIZED: HRESULT = 0x801F0007; +pub const ERROR_FLT_FILTER_NOT_READY: HRESULT = 0x801F0008; +pub const ERROR_FLT_POST_OPERATION_CLEANUP: HRESULT = 0x801F0009; +pub const ERROR_FLT_INTERNAL_ERROR: HRESULT = 0x801F000A; +pub const ERROR_FLT_DELETING_OBJECT: HRESULT = 0x801F000B; +pub const ERROR_FLT_MUST_BE_NONPAGED_POOL: HRESULT = 0x801F000C; +pub const ERROR_FLT_DUPLICATE_ENTRY: HRESULT = 0x801F000D; +pub const ERROR_FLT_CBDQ_DISABLED: HRESULT = 0x801F000E; +pub const ERROR_FLT_DO_NOT_ATTACH: HRESULT = 0x801F000F; +pub const ERROR_FLT_DO_NOT_DETACH: HRESULT = 0x801F0010; +pub const ERROR_FLT_INSTANCE_ALTITUDE_COLLISION: HRESULT = 0x801F0011; +pub const ERROR_FLT_INSTANCE_NAME_COLLISION: HRESULT = 0x801F0012; +pub const ERROR_FLT_FILTER_NOT_FOUND: HRESULT = 0x801F0013; +pub const ERROR_FLT_VOLUME_NOT_FOUND: HRESULT = 0x801F0014; +pub const ERROR_FLT_INSTANCE_NOT_FOUND: HRESULT = 0x801F0015; +pub const ERROR_FLT_CONTEXT_ALLOCATION_NOT_FOUND: HRESULT = 0x801F0016; +pub const ERROR_FLT_INVALID_CONTEXT_REGISTRATION: HRESULT = 0x801F0017; +pub const ERROR_FLT_NAME_CACHE_MISS: HRESULT = 0x801F0018; +pub const ERROR_FLT_NO_DEVICE_OBJECT: HRESULT = 0x801F0019; +pub const ERROR_FLT_VOLUME_ALREADY_MOUNTED: HRESULT = 0x801F001A; +pub const ERROR_FLT_ALREADY_ENLISTED: HRESULT = 0x801F001B; +pub const ERROR_FLT_CONTEXT_ALREADY_LINKED: HRESULT = 0x801F001C; +pub const ERROR_FLT_NO_WAITER_FOR_REPLY: HRESULT = 0x801F0020; +pub const ERROR_FLT_REGISTRATION_BUSY: HRESULT = 0x801F0023; +pub const ERROR_HUNG_DISPLAY_DRIVER_THREAD: HRESULT = 0x80260001; +pub const DWM_E_COMPOSITIONDISABLED: HRESULT = 0x80263001; +pub const DWM_E_REMOTING_NOT_SUPPORTED: HRESULT = 0x80263002; +pub const DWM_E_NO_REDIRECTION_SURFACE_AVAILABLE: HRESULT = 0x80263003; +pub const DWM_E_NOT_QUEUING_PRESENTS: HRESULT = 0x80263004; +pub const DWM_E_ADAPTER_NOT_FOUND: HRESULT = 0x80263005; +pub const DWM_S_GDI_REDIRECTION_SURFACE: HRESULT = 0x00263005; +pub const DWM_E_TEXTURE_TOO_LARGE: HRESULT = 0x80263007; +pub const ERROR_MONITOR_NO_DESCRIPTOR: HRESULT = 0x80261001; +pub const ERROR_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT: HRESULT = 0x80261002; +pub const ERROR_MONITOR_INVALID_DESCRIPTOR_CHECKSUM: HRESULT = 0xC0261003; +pub const ERROR_MONITOR_INVALID_STANDARD_TIMING_BLOCK: HRESULT = 0xC0261004; +pub const ERROR_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED: HRESULT = 0xC0261005; +pub const ERROR_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK: HRESULT = 0xC0261006; +pub const ERROR_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK: HRESULT = 0xC0261007; +pub const ERROR_MONITOR_NO_MORE_DESCRIPTOR_DATA: HRESULT = 0xC0261008; +pub const ERROR_MONITOR_INVALID_DETAILED_TIMING_BLOCK: HRESULT = 0xC0261009; +pub const ERROR_MONITOR_INVALID_MANUFACTURE_DATE: HRESULT = 0xC026100A; +pub const ERROR_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER: HRESULT = 0xC0262000; +pub const ERROR_GRAPHICS_INSUFFICIENT_DMA_BUFFER: HRESULT = 0xC0262001; +pub const ERROR_GRAPHICS_INVALID_DISPLAY_ADAPTER: HRESULT = 0xC0262002; +pub const ERROR_GRAPHICS_ADAPTER_WAS_RESET: HRESULT = 0xC0262003; +pub const ERROR_GRAPHICS_INVALID_DRIVER_MODEL: HRESULT = 0xC0262004; +pub const ERROR_GRAPHICS_PRESENT_MODE_CHANGED: HRESULT = 0xC0262005; +pub const ERROR_GRAPHICS_PRESENT_OCCLUDED: HRESULT = 0xC0262006; +pub const ERROR_GRAPHICS_PRESENT_DENIED: HRESULT = 0xC0262007; +pub const ERROR_GRAPHICS_CANNOTCOLORCONVERT: HRESULT = 0xC0262008; +pub const ERROR_GRAPHICS_DRIVER_MISMATCH: HRESULT = 0xC0262009; +pub const ERROR_GRAPHICS_PARTIAL_DATA_POPULATED: HRESULT = 0x4026200A; +pub const ERROR_GRAPHICS_PRESENT_REDIRECTION_DISABLED: HRESULT = 0xC026200B; +pub const ERROR_GRAPHICS_PRESENT_UNOCCLUDED: HRESULT = 0xC026200C; +pub const ERROR_GRAPHICS_WINDOWDC_NOT_AVAILABLE: HRESULT = 0xC026200D; +pub const ERROR_GRAPHICS_WINDOWLESS_PRESENT_DISABLED: HRESULT = 0xC026200E; +pub const ERROR_GRAPHICS_NO_VIDEO_MEMORY: HRESULT = 0xC0262100; +pub const ERROR_GRAPHICS_CANT_LOCK_MEMORY: HRESULT = 0xC0262101; +pub const ERROR_GRAPHICS_ALLOCATION_BUSY: HRESULT = 0xC0262102; +pub const ERROR_GRAPHICS_TOO_MANY_REFERENCES: HRESULT = 0xC0262103; +pub const ERROR_GRAPHICS_TRY_AGAIN_LATER: HRESULT = 0xC0262104; +pub const ERROR_GRAPHICS_TRY_AGAIN_NOW: HRESULT = 0xC0262105; +pub const ERROR_GRAPHICS_ALLOCATION_INVALID: HRESULT = 0xC0262106; +pub const ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE: HRESULT = 0xC0262107; +pub const ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED: HRESULT = 0xC0262108; +pub const ERROR_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION: HRESULT = 0xC0262109; +pub const ERROR_GRAPHICS_INVALID_ALLOCATION_USAGE: HRESULT = 0xC0262110; +pub const ERROR_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION: HRESULT = 0xC0262111; +pub const ERROR_GRAPHICS_ALLOCATION_CLOSED: HRESULT = 0xC0262112; +pub const ERROR_GRAPHICS_INVALID_ALLOCATION_INSTANCE: HRESULT = 0xC0262113; +pub const ERROR_GRAPHICS_INVALID_ALLOCATION_HANDLE: HRESULT = 0xC0262114; +pub const ERROR_GRAPHICS_WRONG_ALLOCATION_DEVICE: HRESULT = 0xC0262115; +pub const ERROR_GRAPHICS_ALLOCATION_CONTENT_LOST: HRESULT = 0xC0262116; +pub const ERROR_GRAPHICS_GPU_EXCEPTION_ON_DEVICE: HRESULT = 0xC0262200; +pub const ERROR_GRAPHICS_SKIP_ALLOCATION_PREPARATION: HRESULT = 0x40262201; +pub const ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY: HRESULT = 0xC0262300; +pub const ERROR_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED: HRESULT = 0xC0262301; +pub const ERROR_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED: HRESULT + = 0xC0262302; +pub const ERROR_GRAPHICS_INVALID_VIDPN: HRESULT = 0xC0262303; +pub const ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE: HRESULT = 0xC0262304; +pub const ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET: HRESULT = 0xC0262305; +pub const ERROR_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED: HRESULT = 0xC0262306; +pub const ERROR_GRAPHICS_MODE_NOT_PINNED: HRESULT = 0x00262307; +pub const ERROR_GRAPHICS_INVALID_VIDPN_SOURCEMODESET: HRESULT = 0xC0262308; +pub const ERROR_GRAPHICS_INVALID_VIDPN_TARGETMODESET: HRESULT = 0xC0262309; +pub const ERROR_GRAPHICS_INVALID_FREQUENCY: HRESULT = 0xC026230A; +pub const ERROR_GRAPHICS_INVALID_ACTIVE_REGION: HRESULT = 0xC026230B; +pub const ERROR_GRAPHICS_INVALID_TOTAL_REGION: HRESULT = 0xC026230C; +pub const ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE: HRESULT = 0xC0262310; +pub const ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE: HRESULT = 0xC0262311; +pub const ERROR_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET: HRESULT = 0xC0262312; +pub const ERROR_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY: HRESULT = 0xC0262313; +pub const ERROR_GRAPHICS_MODE_ALREADY_IN_MODESET: HRESULT = 0xC0262314; +pub const ERROR_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET: HRESULT = 0xC0262315; +pub const ERROR_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET: HRESULT = 0xC0262316; +pub const ERROR_GRAPHICS_SOURCE_ALREADY_IN_SET: HRESULT = 0xC0262317; +pub const ERROR_GRAPHICS_TARGET_ALREADY_IN_SET: HRESULT = 0xC0262318; +pub const ERROR_GRAPHICS_INVALID_VIDPN_PRESENT_PATH: HRESULT = 0xC0262319; +pub const ERROR_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY: HRESULT = 0xC026231A; +pub const ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET: HRESULT = 0xC026231B; +pub const ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE: HRESULT = 0xC026231C; +pub const ERROR_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET: HRESULT = 0xC026231D; +pub const ERROR_GRAPHICS_NO_PREFERRED_MODE: HRESULT = 0x0026231E; +pub const ERROR_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET: HRESULT = 0xC026231F; +pub const ERROR_GRAPHICS_STALE_MODESET: HRESULT = 0xC0262320; +pub const ERROR_GRAPHICS_INVALID_MONITOR_SOURCEMODESET: HRESULT = 0xC0262321; +pub const ERROR_GRAPHICS_INVALID_MONITOR_SOURCE_MODE: HRESULT = 0xC0262322; +pub const ERROR_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN: HRESULT = 0xC0262323; +pub const ERROR_GRAPHICS_MODE_ID_MUST_BE_UNIQUE: HRESULT = 0xC0262324; +pub const ERROR_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION: HRESULT + = 0xC0262325; +pub const ERROR_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES: HRESULT + = 0xC0262326; +pub const ERROR_GRAPHICS_PATH_NOT_IN_TOPOLOGY: HRESULT = 0xC0262327; +pub const ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE: HRESULT = 0xC0262328; +pub const ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET: HRESULT = 0xC0262329; +pub const ERROR_GRAPHICS_INVALID_MONITORDESCRIPTORSET: HRESULT = 0xC026232A; +pub const ERROR_GRAPHICS_INVALID_MONITORDESCRIPTOR: HRESULT = 0xC026232B; +pub const ERROR_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET: HRESULT = 0xC026232C; +pub const ERROR_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET: HRESULT = 0xC026232D; +pub const ERROR_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE: HRESULT = 0xC026232E; +pub const ERROR_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE: HRESULT = 0xC026232F; +pub const ERROR_GRAPHICS_RESOURCES_NOT_RELATED: HRESULT = 0xC0262330; +pub const ERROR_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE: HRESULT = 0xC0262331; +pub const ERROR_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE: HRESULT = 0xC0262332; +pub const ERROR_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET: HRESULT = 0xC0262333; +pub const ERROR_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER: HRESULT + = 0xC0262334; +pub const ERROR_GRAPHICS_NO_VIDPNMGR: HRESULT = 0xC0262335; +pub const ERROR_GRAPHICS_NO_ACTIVE_VIDPN: HRESULT = 0xC0262336; +pub const ERROR_GRAPHICS_STALE_VIDPN_TOPOLOGY: HRESULT = 0xC0262337; +pub const ERROR_GRAPHICS_MONITOR_NOT_CONNECTED: HRESULT = 0xC0262338; +pub const ERROR_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY: HRESULT = 0xC0262339; +pub const ERROR_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE: HRESULT = 0xC026233A; +pub const ERROR_GRAPHICS_INVALID_VISIBLEREGION_SIZE: HRESULT = 0xC026233B; +pub const ERROR_GRAPHICS_INVALID_STRIDE: HRESULT = 0xC026233C; +pub const ERROR_GRAPHICS_INVALID_PIXELFORMAT: HRESULT = 0xC026233D; +pub const ERROR_GRAPHICS_INVALID_COLORBASIS: HRESULT = 0xC026233E; +pub const ERROR_GRAPHICS_INVALID_PIXELVALUEACCESSMODE: HRESULT = 0xC026233F; +pub const ERROR_GRAPHICS_TARGET_NOT_IN_TOPOLOGY: HRESULT = 0xC0262340; +pub const ERROR_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT: HRESULT = 0xC0262341; +pub const ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE: HRESULT = 0xC0262342; +pub const ERROR_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN: HRESULT = 0xC0262343; +pub const ERROR_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL: HRESULT = 0xC0262344; +pub const ERROR_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION: HRESULT + = 0xC0262345; +pub const ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED: HRESULT + = 0xC0262346; +pub const ERROR_GRAPHICS_INVALID_GAMMA_RAMP: HRESULT = 0xC0262347; +pub const ERROR_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED: HRESULT = 0xC0262348; +pub const ERROR_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED: HRESULT = 0xC0262349; +pub const ERROR_GRAPHICS_MODE_NOT_IN_MODESET: HRESULT = 0xC026234A; +pub const ERROR_GRAPHICS_DATASET_IS_EMPTY: HRESULT = 0x0026234B; +pub const ERROR_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET: HRESULT = 0x0026234C; +pub const ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON: HRESULT + = 0xC026234D; +pub const ERROR_GRAPHICS_INVALID_PATH_CONTENT_TYPE: HRESULT = 0xC026234E; +pub const ERROR_GRAPHICS_INVALID_COPYPROTECTION_TYPE: HRESULT = 0xC026234F; +pub const ERROR_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS: HRESULT = 0xC0262350; +pub const ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED: HRESULT = 0x00262351; +pub const ERROR_GRAPHICS_INVALID_SCANLINE_ORDERING: HRESULT = 0xC0262352; +pub const ERROR_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED: HRESULT = 0xC0262353; +pub const ERROR_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS: HRESULT = 0xC0262354; +pub const ERROR_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT: HRESULT = 0xC0262355; +pub const ERROR_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM: HRESULT = 0xC0262356; +pub const ERROR_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN: HRESULT = 0xC0262357; +pub const ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT: HRESULT + = 0xC0262358; +pub const ERROR_GRAPHICS_MAX_NUM_PATHS_REACHED: HRESULT = 0xC0262359; +pub const ERROR_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION: HRESULT = 0xC026235A; +pub const ERROR_GRAPHICS_INVALID_CLIENT_TYPE: HRESULT = 0xC026235B; +pub const ERROR_GRAPHICS_CLIENTVIDPN_NOT_SET: HRESULT = 0xC026235C; +pub const ERROR_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED: HRESULT = 0xC0262400; +pub const ERROR_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED: HRESULT = 0xC0262401; +pub const ERROR_GRAPHICS_UNKNOWN_CHILD_STATUS: HRESULT = 0x4026242F; +pub const ERROR_GRAPHICS_NOT_A_LINKED_ADAPTER: HRESULT = 0xC0262430; +pub const ERROR_GRAPHICS_LEADLINK_NOT_ENUMERATED: HRESULT = 0xC0262431; +pub const ERROR_GRAPHICS_CHAINLINKS_NOT_ENUMERATED: HRESULT = 0xC0262432; +pub const ERROR_GRAPHICS_ADAPTER_CHAIN_NOT_READY: HRESULT = 0xC0262433; +pub const ERROR_GRAPHICS_CHAINLINKS_NOT_STARTED: HRESULT = 0xC0262434; +pub const ERROR_GRAPHICS_CHAINLINKS_NOT_POWERED_ON: HRESULT = 0xC0262435; +pub const ERROR_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE: HRESULT = 0xC0262436; +pub const ERROR_GRAPHICS_LEADLINK_START_DEFERRED: HRESULT = 0x40262437; +pub const ERROR_GRAPHICS_NOT_POST_DEVICE_DRIVER: HRESULT = 0xC0262438; +pub const ERROR_GRAPHICS_POLLING_TOO_FREQUENTLY: HRESULT = 0x40262439; +pub const ERROR_GRAPHICS_START_DEFERRED: HRESULT = 0x4026243A; +pub const ERROR_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED: HRESULT = 0xC026243B; +pub const ERROR_GRAPHICS_OPM_NOT_SUPPORTED: HRESULT = 0xC0262500; +pub const ERROR_GRAPHICS_COPP_NOT_SUPPORTED: HRESULT = 0xC0262501; +pub const ERROR_GRAPHICS_UAB_NOT_SUPPORTED: HRESULT = 0xC0262502; +pub const ERROR_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS: HRESULT = 0xC0262503; +pub const ERROR_GRAPHICS_OPM_NO_VIDEO_OUTPUTS_EXIST: HRESULT = 0xC0262505; +pub const ERROR_GRAPHICS_OPM_INTERNAL_ERROR: HRESULT = 0xC026250B; +pub const ERROR_GRAPHICS_OPM_INVALID_HANDLE: HRESULT = 0xC026250C; +pub const ERROR_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH: HRESULT = 0xC026250E; +pub const ERROR_GRAPHICS_OPM_SPANNING_MODE_ENABLED: HRESULT = 0xC026250F; +pub const ERROR_GRAPHICS_OPM_THEATER_MODE_ENABLED: HRESULT = 0xC0262510; +pub const ERROR_GRAPHICS_PVP_HFS_FAILED: HRESULT = 0xC0262511; +pub const ERROR_GRAPHICS_OPM_INVALID_SRM: HRESULT = 0xC0262512; +pub const ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP: HRESULT = 0xC0262513; +pub const ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP: HRESULT = 0xC0262514; +pub const ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA: HRESULT = 0xC0262515; +pub const ERROR_GRAPHICS_OPM_HDCP_SRM_NEVER_SET: HRESULT = 0xC0262516; +pub const ERROR_GRAPHICS_OPM_RESOLUTION_TOO_HIGH: HRESULT = 0xC0262517; +pub const ERROR_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE: HRESULT = 0xC0262518; +pub const ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_NO_LONGER_EXISTS: HRESULT = 0xC026251A; +pub const ERROR_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS: HRESULT = 0xC026251B; +pub const ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS: HRESULT + = 0xC026251C; +pub const ERROR_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST: HRESULT = 0xC026251D; +pub const ERROR_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR: HRESULT = 0xC026251E; +pub const ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS: HRESULT + = 0xC026251F; +pub const ERROR_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED: HRESULT = 0xC0262520; +pub const ERROR_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST: HRESULT = 0xC0262521; +pub const ERROR_GRAPHICS_I2C_NOT_SUPPORTED: HRESULT = 0xC0262580; +pub const ERROR_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST: HRESULT = 0xC0262581; +pub const ERROR_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA: HRESULT = 0xC0262582; +pub const ERROR_GRAPHICS_I2C_ERROR_RECEIVING_DATA: HRESULT = 0xC0262583; +pub const ERROR_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED: HRESULT = 0xC0262584; +pub const ERROR_GRAPHICS_DDCCI_INVALID_DATA: HRESULT = 0xC0262585; +pub const ERROR_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE: HRESULT + = 0xC0262586; +pub const ERROR_GRAPHICS_MCA_INVALID_CAPABILITIES_STRING: HRESULT = 0xC0262587; +pub const ERROR_GRAPHICS_MCA_INTERNAL_ERROR: HRESULT = 0xC0262588; +pub const ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND: HRESULT = 0xC0262589; +pub const ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH: HRESULT = 0xC026258A; +pub const ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM: HRESULT = 0xC026258B; +pub const ERROR_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE: HRESULT = 0xC026258C; +pub const ERROR_GRAPHICS_MONITOR_NO_LONGER_EXISTS: HRESULT = 0xC026258D; +pub const ERROR_GRAPHICS_DDCCI_CURRENT_CURRENT_VALUE_GREATER_THAN_MAXIMUM_VALUE: HRESULT + = 0xC02625D8; +pub const ERROR_GRAPHICS_MCA_INVALID_VCP_VERSION: HRESULT = 0xC02625D9; +pub const ERROR_GRAPHICS_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION: HRESULT + = 0xC02625DA; +pub const ERROR_GRAPHICS_MCA_MCCS_VERSION_MISMATCH: HRESULT = 0xC02625DB; +pub const ERROR_GRAPHICS_MCA_UNSUPPORTED_MCCS_VERSION: HRESULT = 0xC02625DC; +pub const ERROR_GRAPHICS_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED: HRESULT = 0xC02625DE; +pub const ERROR_GRAPHICS_MCA_UNSUPPORTED_COLOR_TEMPERATURE: HRESULT = 0xC02625DF; +pub const ERROR_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED: HRESULT = 0xC02625E0; +pub const ERROR_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME: HRESULT = 0xC02625E1; +pub const ERROR_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP: HRESULT + = 0xC02625E2; +pub const ERROR_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED: HRESULT = 0xC02625E3; +pub const ERROR_GRAPHICS_INVALID_POINTER: HRESULT = 0xC02625E4; +pub const ERROR_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE: HRESULT + = 0xC02625E5; +pub const ERROR_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL: HRESULT = 0xC02625E6; +pub const ERROR_GRAPHICS_INTERNAL_ERROR: HRESULT = 0xC02625E7; +pub const ERROR_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS: HRESULT = 0xC02605E8; +pub const NAP_E_INVALID_PACKET: HRESULT = 0x80270001; +pub const NAP_E_MISSING_SOH: HRESULT = 0x80270002; +pub const NAP_E_CONFLICTING_ID: HRESULT = 0x80270003; +pub const NAP_E_NO_CACHED_SOH: HRESULT = 0x80270004; +pub const NAP_E_STILL_BOUND: HRESULT = 0x80270005; +pub const NAP_E_NOT_REGISTERED: HRESULT = 0x80270006; +pub const NAP_E_NOT_INITIALIZED: HRESULT = 0x80270007; +pub const NAP_E_MISMATCHED_ID: HRESULT = 0x80270008; +pub const NAP_E_NOT_PENDING: HRESULT = 0x80270009; +pub const NAP_E_ID_NOT_FOUND: HRESULT = 0x8027000A; +pub const NAP_E_MAXSIZE_TOO_SMALL: HRESULT = 0x8027000B; +pub const NAP_E_SERVICE_NOT_RUNNING: HRESULT = 0x8027000C; +pub const NAP_S_CERT_ALREADY_PRESENT: HRESULT = 0x0027000D; +pub const NAP_E_ENTITY_DISABLED: HRESULT = 0x8027000E; +pub const NAP_E_NETSH_GROUPPOLICY_ERROR: HRESULT = 0x8027000F; +pub const NAP_E_TOO_MANY_CALLS: HRESULT = 0x80270010; +pub const NAP_E_SHV_CONFIG_EXISTED: HRESULT = 0x80270011; +pub const NAP_E_SHV_CONFIG_NOT_FOUND: HRESULT = 0x80270012; +pub const NAP_E_SHV_TIMEOUT: HRESULT = 0x80270013; +pub const TPM_E_ERROR_MASK: HRESULT = 0x80280000; +pub const TPM_E_AUTHFAIL: HRESULT = 0x80280001; +pub const TPM_E_BADINDEX: HRESULT = 0x80280002; +pub const TPM_E_BAD_PARAMETER: HRESULT = 0x80280003; +pub const TPM_E_AUDITFAILURE: HRESULT = 0x80280004; +pub const TPM_E_CLEAR_DISABLED: HRESULT = 0x80280005; +pub const TPM_E_DEACTIVATED: HRESULT = 0x80280006; +pub const TPM_E_DISABLED: HRESULT = 0x80280007; +pub const TPM_E_DISABLED_CMD: HRESULT = 0x80280008; +pub const TPM_E_FAIL: HRESULT = 0x80280009; +pub const TPM_E_BAD_ORDINAL: HRESULT = 0x8028000A; +pub const TPM_E_INSTALL_DISABLED: HRESULT = 0x8028000B; +pub const TPM_E_INVALID_KEYHANDLE: HRESULT = 0x8028000C; +pub const TPM_E_KEYNOTFOUND: HRESULT = 0x8028000D; +pub const TPM_E_INAPPROPRIATE_ENC: HRESULT = 0x8028000E; +pub const TPM_E_MIGRATEFAIL: HRESULT = 0x8028000F; +pub const TPM_E_INVALID_PCR_INFO: HRESULT = 0x80280010; +pub const TPM_E_NOSPACE: HRESULT = 0x80280011; +pub const TPM_E_NOSRK: HRESULT = 0x80280012; +pub const TPM_E_NOTSEALED_BLOB: HRESULT = 0x80280013; +pub const TPM_E_OWNER_SET: HRESULT = 0x80280014; +pub const TPM_E_RESOURCES: HRESULT = 0x80280015; +pub const TPM_E_SHORTRANDOM: HRESULT = 0x80280016; +pub const TPM_E_SIZE: HRESULT = 0x80280017; +pub const TPM_E_WRONGPCRVAL: HRESULT = 0x80280018; +pub const TPM_E_BAD_PARAM_SIZE: HRESULT = 0x80280019; +pub const TPM_E_SHA_THREAD: HRESULT = 0x8028001A; +pub const TPM_E_SHA_ERROR: HRESULT = 0x8028001B; +pub const TPM_E_FAILEDSELFTEST: HRESULT = 0x8028001C; +pub const TPM_E_AUTH2FAIL: HRESULT = 0x8028001D; +pub const TPM_E_BADTAG: HRESULT = 0x8028001E; +pub const TPM_E_IOERROR: HRESULT = 0x8028001F; +pub const TPM_E_ENCRYPT_ERROR: HRESULT = 0x80280020; +pub const TPM_E_DECRYPT_ERROR: HRESULT = 0x80280021; +pub const TPM_E_INVALID_AUTHHANDLE: HRESULT = 0x80280022; +pub const TPM_E_NO_ENDORSEMENT: HRESULT = 0x80280023; +pub const TPM_E_INVALID_KEYUSAGE: HRESULT = 0x80280024; +pub const TPM_E_WRONG_ENTITYTYPE: HRESULT = 0x80280025; +pub const TPM_E_INVALID_POSTINIT: HRESULT = 0x80280026; +pub const TPM_E_INAPPROPRIATE_SIG: HRESULT = 0x80280027; +pub const TPM_E_BAD_KEY_PROPERTY: HRESULT = 0x80280028; +pub const TPM_E_BAD_MIGRATION: HRESULT = 0x80280029; +pub const TPM_E_BAD_SCHEME: HRESULT = 0x8028002A; +pub const TPM_E_BAD_DATASIZE: HRESULT = 0x8028002B; +pub const TPM_E_BAD_MODE: HRESULT = 0x8028002C; +pub const TPM_E_BAD_PRESENCE: HRESULT = 0x8028002D; +pub const TPM_E_BAD_VERSION: HRESULT = 0x8028002E; +pub const TPM_E_NO_WRAP_TRANSPORT: HRESULT = 0x8028002F; +pub const TPM_E_AUDITFAIL_UNSUCCESSFUL: HRESULT = 0x80280030; +pub const TPM_E_AUDITFAIL_SUCCESSFUL: HRESULT = 0x80280031; +pub const TPM_E_NOTRESETABLE: HRESULT = 0x80280032; +pub const TPM_E_NOTLOCAL: HRESULT = 0x80280033; +pub const TPM_E_BAD_TYPE: HRESULT = 0x80280034; +pub const TPM_E_INVALID_RESOURCE: HRESULT = 0x80280035; +pub const TPM_E_NOTFIPS: HRESULT = 0x80280036; +pub const TPM_E_INVALID_FAMILY: HRESULT = 0x80280037; +pub const TPM_E_NO_NV_PERMISSION: HRESULT = 0x80280038; +pub const TPM_E_REQUIRES_SIGN: HRESULT = 0x80280039; +pub const TPM_E_KEY_NOTSUPPORTED: HRESULT = 0x8028003A; +pub const TPM_E_AUTH_CONFLICT: HRESULT = 0x8028003B; +pub const TPM_E_AREA_LOCKED: HRESULT = 0x8028003C; +pub const TPM_E_BAD_LOCALITY: HRESULT = 0x8028003D; +pub const TPM_E_READ_ONLY: HRESULT = 0x8028003E; +pub const TPM_E_PER_NOWRITE: HRESULT = 0x8028003F; +pub const TPM_E_FAMILYCOUNT: HRESULT = 0x80280040; +pub const TPM_E_WRITE_LOCKED: HRESULT = 0x80280041; +pub const TPM_E_BAD_ATTRIBUTES: HRESULT = 0x80280042; +pub const TPM_E_INVALID_STRUCTURE: HRESULT = 0x80280043; +pub const TPM_E_KEY_OWNER_CONTROL: HRESULT = 0x80280044; +pub const TPM_E_BAD_COUNTER: HRESULT = 0x80280045; +pub const TPM_E_NOT_FULLWRITE: HRESULT = 0x80280046; +pub const TPM_E_CONTEXT_GAP: HRESULT = 0x80280047; +pub const TPM_E_MAXNVWRITES: HRESULT = 0x80280048; +pub const TPM_E_NOOPERATOR: HRESULT = 0x80280049; +pub const TPM_E_RESOURCEMISSING: HRESULT = 0x8028004A; +pub const TPM_E_DELEGATE_LOCK: HRESULT = 0x8028004B; +pub const TPM_E_DELEGATE_FAMILY: HRESULT = 0x8028004C; +pub const TPM_E_DELEGATE_ADMIN: HRESULT = 0x8028004D; +pub const TPM_E_TRANSPORT_NOTEXCLUSIVE: HRESULT = 0x8028004E; +pub const TPM_E_OWNER_CONTROL: HRESULT = 0x8028004F; +pub const TPM_E_DAA_RESOURCES: HRESULT = 0x80280050; +pub const TPM_E_DAA_INPUT_DATA0: HRESULT = 0x80280051; +pub const TPM_E_DAA_INPUT_DATA1: HRESULT = 0x80280052; +pub const TPM_E_DAA_ISSUER_SETTINGS: HRESULT = 0x80280053; +pub const TPM_E_DAA_TPM_SETTINGS: HRESULT = 0x80280054; +pub const TPM_E_DAA_STAGE: HRESULT = 0x80280055; +pub const TPM_E_DAA_ISSUER_VALIDITY: HRESULT = 0x80280056; +pub const TPM_E_DAA_WRONG_W: HRESULT = 0x80280057; +pub const TPM_E_BAD_HANDLE: HRESULT = 0x80280058; +pub const TPM_E_BAD_DELEGATE: HRESULT = 0x80280059; +pub const TPM_E_BADCONTEXT: HRESULT = 0x8028005A; +pub const TPM_E_TOOMANYCONTEXTS: HRESULT = 0x8028005B; +pub const TPM_E_MA_TICKET_SIGNATURE: HRESULT = 0x8028005C; +pub const TPM_E_MA_DESTINATION: HRESULT = 0x8028005D; +pub const TPM_E_MA_SOURCE: HRESULT = 0x8028005E; +pub const TPM_E_MA_AUTHORITY: HRESULT = 0x8028005F; +pub const TPM_E_PERMANENTEK: HRESULT = 0x80280061; +pub const TPM_E_BAD_SIGNATURE: HRESULT = 0x80280062; +pub const TPM_E_NOCONTEXTSPACE: HRESULT = 0x80280063; +pub const TPM_E_COMMAND_BLOCKED: HRESULT = 0x80280400; +pub const TPM_E_INVALID_HANDLE: HRESULT = 0x80280401; +pub const TPM_E_DUPLICATE_VHANDLE: HRESULT = 0x80280402; +pub const TPM_E_EMBEDDED_COMMAND_BLOCKED: HRESULT = 0x80280403; +pub const TPM_E_EMBEDDED_COMMAND_UNSUPPORTED: HRESULT = 0x80280404; +pub const TPM_E_RETRY: HRESULT = 0x80280800; +pub const TPM_E_NEEDS_SELFTEST: HRESULT = 0x80280801; +pub const TPM_E_DOING_SELFTEST: HRESULT = 0x80280802; +pub const TPM_E_DEFEND_LOCK_RUNNING: HRESULT = 0x80280803; +pub const TBS_E_INTERNAL_ERROR: HRESULT = 0x80284001; +pub const TBS_E_BAD_PARAMETER: HRESULT = 0x80284002; +pub const TBS_E_INVALID_OUTPUT_POINTER: HRESULT = 0x80284003; +pub const TBS_E_INVALID_CONTEXT: HRESULT = 0x80284004; +pub const TBS_E_INSUFFICIENT_BUFFER: HRESULT = 0x80284005; +pub const TBS_E_IOERROR: HRESULT = 0x80284006; +pub const TBS_E_INVALID_CONTEXT_PARAM: HRESULT = 0x80284007; +pub const TBS_E_SERVICE_NOT_RUNNING: HRESULT = 0x80284008; +pub const TBS_E_TOO_MANY_TBS_CONTEXTS: HRESULT = 0x80284009; +pub const TBS_E_TOO_MANY_RESOURCES: HRESULT = 0x8028400A; +pub const TBS_E_SERVICE_START_PENDING: HRESULT = 0x8028400B; +pub const TBS_E_PPI_NOT_SUPPORTED: HRESULT = 0x8028400C; +pub const TBS_E_COMMAND_CANCELED: HRESULT = 0x8028400D; +pub const TBS_E_BUFFER_TOO_LARGE: HRESULT = 0x8028400E; +pub const TBS_E_TPM_NOT_FOUND: HRESULT = 0x8028400F; +pub const TBS_E_SERVICE_DISABLED: HRESULT = 0x80284010; +pub const TBS_E_NO_EVENT_LOG: HRESULT = 0x80284011; +pub const TBS_E_ACCESS_DENIED: HRESULT = 0x80284012; +pub const TBS_E_PROVISIONING_NOT_ALLOWED: HRESULT = 0x80284013; +pub const TBS_E_PPI_FUNCTION_UNSUPPORTED: HRESULT = 0x80284014; +pub const TBS_E_OWNERAUTH_NOT_FOUND: HRESULT = 0x80284015; +pub const TBS_E_PROVISIONING_INCOMPLETE: HRESULT = 0x80284016; +pub const TPMAPI_E_INVALID_STATE: HRESULT = 0x80290100; +pub const TPMAPI_E_NOT_ENOUGH_DATA: HRESULT = 0x80290101; +pub const TPMAPI_E_TOO_MUCH_DATA: HRESULT = 0x80290102; +pub const TPMAPI_E_INVALID_OUTPUT_POINTER: HRESULT = 0x80290103; +pub const TPMAPI_E_INVALID_PARAMETER: HRESULT = 0x80290104; +pub const TPMAPI_E_OUT_OF_MEMORY: HRESULT = 0x80290105; +pub const TPMAPI_E_BUFFER_TOO_SMALL: HRESULT = 0x80290106; +pub const TPMAPI_E_INTERNAL_ERROR: HRESULT = 0x80290107; +pub const TPMAPI_E_ACCESS_DENIED: HRESULT = 0x80290108; +pub const TPMAPI_E_AUTHORIZATION_FAILED: HRESULT = 0x80290109; +pub const TPMAPI_E_INVALID_CONTEXT_HANDLE: HRESULT = 0x8029010A; +pub const TPMAPI_E_TBS_COMMUNICATION_ERROR: HRESULT = 0x8029010B; +pub const TPMAPI_E_TPM_COMMAND_ERROR: HRESULT = 0x8029010C; +pub const TPMAPI_E_MESSAGE_TOO_LARGE: HRESULT = 0x8029010D; +pub const TPMAPI_E_INVALID_ENCODING: HRESULT = 0x8029010E; +pub const TPMAPI_E_INVALID_KEY_SIZE: HRESULT = 0x8029010F; +pub const TPMAPI_E_ENCRYPTION_FAILED: HRESULT = 0x80290110; +pub const TPMAPI_E_INVALID_KEY_PARAMS: HRESULT = 0x80290111; +pub const TPMAPI_E_INVALID_MIGRATION_AUTHORIZATION_BLOB: HRESULT = 0x80290112; +pub const TPMAPI_E_INVALID_PCR_INDEX: HRESULT = 0x80290113; +pub const TPMAPI_E_INVALID_DELEGATE_BLOB: HRESULT = 0x80290114; +pub const TPMAPI_E_INVALID_CONTEXT_PARAMS: HRESULT = 0x80290115; +pub const TPMAPI_E_INVALID_KEY_BLOB: HRESULT = 0x80290116; +pub const TPMAPI_E_INVALID_PCR_DATA: HRESULT = 0x80290117; +pub const TPMAPI_E_INVALID_OWNER_AUTH: HRESULT = 0x80290118; +pub const TPMAPI_E_FIPS_RNG_CHECK_FAILED: HRESULT = 0x80290119; +pub const TPMAPI_E_EMPTY_TCG_LOG: HRESULT = 0x8029011A; +pub const TPMAPI_E_INVALID_TCG_LOG_ENTRY: HRESULT = 0x8029011B; +pub const TPMAPI_E_TCG_SEPARATOR_ABSENT: HRESULT = 0x8029011C; +pub const TPMAPI_E_TCG_INVALID_DIGEST_ENTRY: HRESULT = 0x8029011D; +pub const TPMAPI_E_POLICY_DENIES_OPERATION: HRESULT = 0x8029011E; +pub const TBSIMP_E_BUFFER_TOO_SMALL: HRESULT = 0x80290200; +pub const TBSIMP_E_CLEANUP_FAILED: HRESULT = 0x80290201; +pub const TBSIMP_E_INVALID_CONTEXT_HANDLE: HRESULT = 0x80290202; +pub const TBSIMP_E_INVALID_CONTEXT_PARAM: HRESULT = 0x80290203; +pub const TBSIMP_E_TPM_ERROR: HRESULT = 0x80290204; +pub const TBSIMP_E_HASH_BAD_KEY: HRESULT = 0x80290205; +pub const TBSIMP_E_DUPLICATE_VHANDLE: HRESULT = 0x80290206; +pub const TBSIMP_E_INVALID_OUTPUT_POINTER: HRESULT = 0x80290207; +pub const TBSIMP_E_INVALID_PARAMETER: HRESULT = 0x80290208; +pub const TBSIMP_E_RPC_INIT_FAILED: HRESULT = 0x80290209; +pub const TBSIMP_E_SCHEDULER_NOT_RUNNING: HRESULT = 0x8029020A; +pub const TBSIMP_E_COMMAND_CANCELED: HRESULT = 0x8029020B; +pub const TBSIMP_E_OUT_OF_MEMORY: HRESULT = 0x8029020C; +pub const TBSIMP_E_LIST_NO_MORE_ITEMS: HRESULT = 0x8029020D; +pub const TBSIMP_E_LIST_NOT_FOUND: HRESULT = 0x8029020E; +pub const TBSIMP_E_NOT_ENOUGH_SPACE: HRESULT = 0x8029020F; +pub const TBSIMP_E_NOT_ENOUGH_TPM_CONTEXTS: HRESULT = 0x80290210; +pub const TBSIMP_E_COMMAND_FAILED: HRESULT = 0x80290211; +pub const TBSIMP_E_UNKNOWN_ORDINAL: HRESULT = 0x80290212; +pub const TBSIMP_E_RESOURCE_EXPIRED: HRESULT = 0x80290213; +pub const TBSIMP_E_INVALID_RESOURCE: HRESULT = 0x80290214; +pub const TBSIMP_E_NOTHING_TO_UNLOAD: HRESULT = 0x80290215; +pub const TBSIMP_E_HASH_TABLE_FULL: HRESULT = 0x80290216; +pub const TBSIMP_E_TOO_MANY_TBS_CONTEXTS: HRESULT = 0x80290217; +pub const TBSIMP_E_TOO_MANY_RESOURCES: HRESULT = 0x80290218; +pub const TBSIMP_E_PPI_NOT_SUPPORTED: HRESULT = 0x80290219; +pub const TBSIMP_E_TPM_INCOMPATIBLE: HRESULT = 0x8029021A; +pub const TBSIMP_E_NO_EVENT_LOG: HRESULT = 0x8029021B; +pub const TPM_E_PPI_ACPI_FAILURE: HRESULT = 0x80290300; +pub const TPM_E_PPI_USER_ABORT: HRESULT = 0x80290301; +pub const TPM_E_PPI_BIOS_FAILURE: HRESULT = 0x80290302; +pub const TPM_E_PPI_NOT_SUPPORTED: HRESULT = 0x80290303; +pub const TPM_E_PPI_BLOCKED_IN_BIOS: HRESULT = 0x80290304; +pub const TPM_E_PCP_ERROR_MASK: HRESULT = 0x80290400; +pub const TPM_E_PCP_DEVICE_NOT_READY: HRESULT = 0x80290401; +pub const TPM_E_PCP_INVALID_HANDLE: HRESULT = 0x80290402; +pub const TPM_E_PCP_INVALID_PARAMETER: HRESULT = 0x80290403; +pub const TPM_E_PCP_FLAG_NOT_SUPPORTED: HRESULT = 0x80290404; +pub const TPM_E_PCP_NOT_SUPPORTED: HRESULT = 0x80290405; +pub const TPM_E_PCP_BUFFER_TOO_SMALL: HRESULT = 0x80290406; +pub const TPM_E_PCP_INTERNAL_ERROR: HRESULT = 0x80290407; +pub const TPM_E_PCP_AUTHENTICATION_FAILED: HRESULT = 0x80290408; +pub const TPM_E_PCP_AUTHENTICATION_IGNORED: HRESULT = 0x80290409; +pub const TPM_E_PCP_POLICY_NOT_FOUND: HRESULT = 0x8029040A; +pub const TPM_E_PCP_PROFILE_NOT_FOUND: HRESULT = 0x8029040B; +pub const TPM_E_PCP_VALIDATION_FAILED: HRESULT = 0x8029040C; +pub const PLA_E_DCS_NOT_FOUND: HRESULT = 0x80300002; +pub const PLA_E_DCS_IN_USE: HRESULT = 0x803000AA; +pub const PLA_E_TOO_MANY_FOLDERS: HRESULT = 0x80300045; +pub const PLA_E_NO_MIN_DISK: HRESULT = 0x80300070; +pub const PLA_E_DCS_ALREADY_EXISTS: HRESULT = 0x803000B7; +pub const PLA_S_PROPERTY_IGNORED: HRESULT = 0x00300100; +pub const PLA_E_PROPERTY_CONFLICT: HRESULT = 0x80300101; +pub const PLA_E_DCS_SINGLETON_REQUIRED: HRESULT = 0x80300102; +pub const PLA_E_CREDENTIALS_REQUIRED: HRESULT = 0x80300103; +pub const PLA_E_DCS_NOT_RUNNING: HRESULT = 0x80300104; +pub const PLA_E_CONFLICT_INCL_EXCL_API: HRESULT = 0x80300105; +pub const PLA_E_NETWORK_EXE_NOT_VALID: HRESULT = 0x80300106; +pub const PLA_E_EXE_ALREADY_CONFIGURED: HRESULT = 0x80300107; +pub const PLA_E_EXE_PATH_NOT_VALID: HRESULT = 0x80300108; +pub const PLA_E_DC_ALREADY_EXISTS: HRESULT = 0x80300109; +pub const PLA_E_DCS_START_WAIT_TIMEOUT: HRESULT = 0x8030010A; +pub const PLA_E_DC_START_WAIT_TIMEOUT: HRESULT = 0x8030010B; +pub const PLA_E_REPORT_WAIT_TIMEOUT: HRESULT = 0x8030010C; +pub const PLA_E_NO_DUPLICATES: HRESULT = 0x8030010D; +pub const PLA_E_EXE_FULL_PATH_REQUIRED: HRESULT = 0x8030010E; +pub const PLA_E_INVALID_SESSION_NAME: HRESULT = 0x8030010F; +pub const PLA_E_PLA_CHANNEL_NOT_ENABLED: HRESULT = 0x80300110; +pub const PLA_E_TASKSCHED_CHANNEL_NOT_ENABLED: HRESULT = 0x80300111; +pub const PLA_E_RULES_MANAGER_FAILED: HRESULT = 0x80300112; +pub const PLA_E_CABAPI_FAILURE: HRESULT = 0x80300113; +pub const FVE_E_LOCKED_VOLUME: HRESULT = 0x80310000; +pub const FVE_E_NOT_ENCRYPTED: HRESULT = 0x80310001; +pub const FVE_E_NO_TPM_BIOS: HRESULT = 0x80310002; +pub const FVE_E_NO_MBR_METRIC: HRESULT = 0x80310003; +pub const FVE_E_NO_BOOTSECTOR_METRIC: HRESULT = 0x80310004; +pub const FVE_E_NO_BOOTMGR_METRIC: HRESULT = 0x80310005; +pub const FVE_E_WRONG_BOOTMGR: HRESULT = 0x80310006; +pub const FVE_E_SECURE_KEY_REQUIRED: HRESULT = 0x80310007; +pub const FVE_E_NOT_ACTIVATED: HRESULT = 0x80310008; +pub const FVE_E_ACTION_NOT_ALLOWED: HRESULT = 0x80310009; +pub const FVE_E_AD_SCHEMA_NOT_INSTALLED: HRESULT = 0x8031000A; +pub const FVE_E_AD_INVALID_DATATYPE: HRESULT = 0x8031000B; +pub const FVE_E_AD_INVALID_DATASIZE: HRESULT = 0x8031000C; +pub const FVE_E_AD_NO_VALUES: HRESULT = 0x8031000D; +pub const FVE_E_AD_ATTR_NOT_SET: HRESULT = 0x8031000E; +pub const FVE_E_AD_GUID_NOT_FOUND: HRESULT = 0x8031000F; +pub const FVE_E_BAD_INFORMATION: HRESULT = 0x80310010; +pub const FVE_E_TOO_SMALL: HRESULT = 0x80310011; +pub const FVE_E_SYSTEM_VOLUME: HRESULT = 0x80310012; +pub const FVE_E_FAILED_WRONG_FS: HRESULT = 0x80310013; +pub const FVE_E_BAD_PARTITION_SIZE: HRESULT = 0x80310014; +pub const FVE_E_NOT_SUPPORTED: HRESULT = 0x80310015; +pub const FVE_E_BAD_DATA: HRESULT = 0x80310016; +pub const FVE_E_VOLUME_NOT_BOUND: HRESULT = 0x80310017; +pub const FVE_E_TPM_NOT_OWNED: HRESULT = 0x80310018; +pub const FVE_E_NOT_DATA_VOLUME: HRESULT = 0x80310019; +pub const FVE_E_AD_INSUFFICIENT_BUFFER: HRESULT = 0x8031001A; +pub const FVE_E_CONV_READ: HRESULT = 0x8031001B; +pub const FVE_E_CONV_WRITE: HRESULT = 0x8031001C; +pub const FVE_E_KEY_REQUIRED: HRESULT = 0x8031001D; +pub const FVE_E_CLUSTERING_NOT_SUPPORTED: HRESULT = 0x8031001E; +pub const FVE_E_VOLUME_BOUND_ALREADY: HRESULT = 0x8031001F; +pub const FVE_E_OS_NOT_PROTECTED: HRESULT = 0x80310020; +pub const FVE_E_PROTECTION_DISABLED: HRESULT = 0x80310021; +pub const FVE_E_RECOVERY_KEY_REQUIRED: HRESULT = 0x80310022; +pub const FVE_E_FOREIGN_VOLUME: HRESULT = 0x80310023; +pub const FVE_E_OVERLAPPED_UPDATE: HRESULT = 0x80310024; +pub const FVE_E_TPM_SRK_AUTH_NOT_ZERO: HRESULT = 0x80310025; +pub const FVE_E_FAILED_SECTOR_SIZE: HRESULT = 0x80310026; +pub const FVE_E_FAILED_AUTHENTICATION: HRESULT = 0x80310027; +pub const FVE_E_NOT_OS_VOLUME: HRESULT = 0x80310028; +pub const FVE_E_AUTOUNLOCK_ENABLED: HRESULT = 0x80310029; +pub const FVE_E_WRONG_BOOTSECTOR: HRESULT = 0x8031002A; +pub const FVE_E_WRONG_SYSTEM_FS: HRESULT = 0x8031002B; +pub const FVE_E_POLICY_PASSWORD_REQUIRED: HRESULT = 0x8031002C; +pub const FVE_E_CANNOT_SET_FVEK_ENCRYPTED: HRESULT = 0x8031002D; +pub const FVE_E_CANNOT_ENCRYPT_NO_KEY: HRESULT = 0x8031002E; +pub const FVE_E_BOOTABLE_CDDVD: HRESULT = 0x80310030; +pub const FVE_E_PROTECTOR_EXISTS: HRESULT = 0x80310031; +pub const FVE_E_RELATIVE_PATH: HRESULT = 0x80310032; +pub const FVE_E_PROTECTOR_NOT_FOUND: HRESULT = 0x80310033; +pub const FVE_E_INVALID_KEY_FORMAT: HRESULT = 0x80310034; +pub const FVE_E_INVALID_PASSWORD_FORMAT: HRESULT = 0x80310035; +pub const FVE_E_FIPS_RNG_CHECK_FAILED: HRESULT = 0x80310036; +pub const FVE_E_FIPS_PREVENTS_RECOVERY_PASSWORD: HRESULT = 0x80310037; +pub const FVE_E_FIPS_PREVENTS_EXTERNAL_KEY_EXPORT: HRESULT = 0x80310038; +pub const FVE_E_NOT_DECRYPTED: HRESULT = 0x80310039; +pub const FVE_E_INVALID_PROTECTOR_TYPE: HRESULT = 0x8031003A; +pub const FVE_E_NO_PROTECTORS_TO_TEST: HRESULT = 0x8031003B; +pub const FVE_E_KEYFILE_NOT_FOUND: HRESULT = 0x8031003C; +pub const FVE_E_KEYFILE_INVALID: HRESULT = 0x8031003D; +pub const FVE_E_KEYFILE_NO_VMK: HRESULT = 0x8031003E; +pub const FVE_E_TPM_DISABLED: HRESULT = 0x8031003F; +pub const FVE_E_NOT_ALLOWED_IN_SAFE_MODE: HRESULT = 0x80310040; +pub const FVE_E_TPM_INVALID_PCR: HRESULT = 0x80310041; +pub const FVE_E_TPM_NO_VMK: HRESULT = 0x80310042; +pub const FVE_E_PIN_INVALID: HRESULT = 0x80310043; +pub const FVE_E_AUTH_INVALID_APPLICATION: HRESULT = 0x80310044; +pub const FVE_E_AUTH_INVALID_CONFIG: HRESULT = 0x80310045; +pub const FVE_E_FIPS_DISABLE_PROTECTION_NOT_ALLOWED: HRESULT = 0x80310046; +pub const FVE_E_FS_NOT_EXTENDED: HRESULT = 0x80310047; +pub const FVE_E_FIRMWARE_TYPE_NOT_SUPPORTED: HRESULT = 0x80310048; +pub const FVE_E_NO_LICENSE: HRESULT = 0x80310049; +pub const FVE_E_NOT_ON_STACK: HRESULT = 0x8031004A; +pub const FVE_E_FS_MOUNTED: HRESULT = 0x8031004B; +pub const FVE_E_TOKEN_NOT_IMPERSONATED: HRESULT = 0x8031004C; +pub const FVE_E_DRY_RUN_FAILED: HRESULT = 0x8031004D; +pub const FVE_E_REBOOT_REQUIRED: HRESULT = 0x8031004E; +pub const FVE_E_DEBUGGER_ENABLED: HRESULT = 0x8031004F; +pub const FVE_E_RAW_ACCESS: HRESULT = 0x80310050; +pub const FVE_E_RAW_BLOCKED: HRESULT = 0x80310051; +pub const FVE_E_BCD_APPLICATIONS_PATH_INCORRECT: HRESULT = 0x80310052; +pub const FVE_E_NOT_ALLOWED_IN_VERSION: HRESULT = 0x80310053; +pub const FVE_E_NO_AUTOUNLOCK_MASTER_KEY: HRESULT = 0x80310054; +pub const FVE_E_MOR_FAILED: HRESULT = 0x80310055; +pub const FVE_E_HIDDEN_VOLUME: HRESULT = 0x80310056; +pub const FVE_E_TRANSIENT_STATE: HRESULT = 0x80310057; +pub const FVE_E_PUBKEY_NOT_ALLOWED: HRESULT = 0x80310058; +pub const FVE_E_VOLUME_HANDLE_OPEN: HRESULT = 0x80310059; +pub const FVE_E_NO_FEATURE_LICENSE: HRESULT = 0x8031005A; +pub const FVE_E_INVALID_STARTUP_OPTIONS: HRESULT = 0x8031005B; +pub const FVE_E_POLICY_RECOVERY_PASSWORD_NOT_ALLOWED: HRESULT = 0x8031005C; +pub const FVE_E_POLICY_RECOVERY_PASSWORD_REQUIRED: HRESULT = 0x8031005D; +pub const FVE_E_POLICY_RECOVERY_KEY_NOT_ALLOWED: HRESULT = 0x8031005E; +pub const FVE_E_POLICY_RECOVERY_KEY_REQUIRED: HRESULT = 0x8031005F; +pub const FVE_E_POLICY_STARTUP_PIN_NOT_ALLOWED: HRESULT = 0x80310060; +pub const FVE_E_POLICY_STARTUP_PIN_REQUIRED: HRESULT = 0x80310061; +pub const FVE_E_POLICY_STARTUP_KEY_NOT_ALLOWED: HRESULT = 0x80310062; +pub const FVE_E_POLICY_STARTUP_KEY_REQUIRED: HRESULT = 0x80310063; +pub const FVE_E_POLICY_STARTUP_PIN_KEY_NOT_ALLOWED: HRESULT = 0x80310064; +pub const FVE_E_POLICY_STARTUP_PIN_KEY_REQUIRED: HRESULT = 0x80310065; +pub const FVE_E_POLICY_STARTUP_TPM_NOT_ALLOWED: HRESULT = 0x80310066; +pub const FVE_E_POLICY_STARTUP_TPM_REQUIRED: HRESULT = 0x80310067; +pub const FVE_E_POLICY_INVALID_PIN_LENGTH: HRESULT = 0x80310068; +pub const FVE_E_KEY_PROTECTOR_NOT_SUPPORTED: HRESULT = 0x80310069; +pub const FVE_E_POLICY_PASSPHRASE_NOT_ALLOWED: HRESULT = 0x8031006A; +pub const FVE_E_POLICY_PASSPHRASE_REQUIRED: HRESULT = 0x8031006B; +pub const FVE_E_FIPS_PREVENTS_PASSPHRASE: HRESULT = 0x8031006C; +pub const FVE_E_OS_VOLUME_PASSPHRASE_NOT_ALLOWED: HRESULT = 0x8031006D; +pub const FVE_E_INVALID_BITLOCKER_OID: HRESULT = 0x8031006E; +pub const FVE_E_VOLUME_TOO_SMALL: HRESULT = 0x8031006F; +pub const FVE_E_DV_NOT_SUPPORTED_ON_FS: HRESULT = 0x80310070; +pub const FVE_E_DV_NOT_ALLOWED_BY_GP: HRESULT = 0x80310071; +pub const FVE_E_POLICY_USER_CERTIFICATE_NOT_ALLOWED: HRESULT = 0x80310072; +pub const FVE_E_POLICY_USER_CERTIFICATE_REQUIRED: HRESULT = 0x80310073; +pub const FVE_E_POLICY_USER_CERT_MUST_BE_HW: HRESULT = 0x80310074; +pub const FVE_E_POLICY_USER_CONFIGURE_FDV_AUTOUNLOCK_NOT_ALLOWED: HRESULT + = 0x80310075; +pub const FVE_E_POLICY_USER_CONFIGURE_RDV_AUTOUNLOCK_NOT_ALLOWED: HRESULT + = 0x80310076; +pub const FVE_E_POLICY_USER_CONFIGURE_RDV_NOT_ALLOWED: HRESULT = 0x80310077; +pub const FVE_E_POLICY_USER_ENABLE_RDV_NOT_ALLOWED: HRESULT = 0x80310078; +pub const FVE_E_POLICY_USER_DISABLE_RDV_NOT_ALLOWED: HRESULT = 0x80310079; +pub const FVE_E_POLICY_INVALID_PASSPHRASE_LENGTH: HRESULT = 0x80310080; +pub const FVE_E_POLICY_PASSPHRASE_TOO_SIMPLE: HRESULT = 0x80310081; +pub const FVE_E_RECOVERY_PARTITION: HRESULT = 0x80310082; +pub const FVE_E_POLICY_CONFLICT_FDV_RK_OFF_AUK_ON: HRESULT = 0x80310083; +pub const FVE_E_POLICY_CONFLICT_RDV_RK_OFF_AUK_ON: HRESULT = 0x80310084; +pub const FVE_E_NON_BITLOCKER_OID: HRESULT = 0x80310085; +pub const FVE_E_POLICY_PROHIBITS_SELFSIGNED: HRESULT = 0x80310086; +pub const FVE_E_POLICY_CONFLICT_RO_AND_STARTUP_KEY_REQUIRED: HRESULT = 0x80310087; +pub const FVE_E_CONV_RECOVERY_FAILED: HRESULT = 0x80310088; +pub const FVE_E_VIRTUALIZED_SPACE_TOO_BIG: HRESULT = 0x80310089; +pub const FVE_E_POLICY_CONFLICT_OSV_RP_OFF_ADB_ON: HRESULT = 0x80310090; +pub const FVE_E_POLICY_CONFLICT_FDV_RP_OFF_ADB_ON: HRESULT = 0x80310091; +pub const FVE_E_POLICY_CONFLICT_RDV_RP_OFF_ADB_ON: HRESULT = 0x80310092; +pub const FVE_E_NON_BITLOCKER_KU: HRESULT = 0x80310093; +pub const FVE_E_PRIVATEKEY_AUTH_FAILED: HRESULT = 0x80310094; +pub const FVE_E_REMOVAL_OF_DRA_FAILED: HRESULT = 0x80310095; +pub const FVE_E_OPERATION_NOT_SUPPORTED_ON_VISTA_VOLUME: HRESULT = 0x80310096; +pub const FVE_E_CANT_LOCK_AUTOUNLOCK_ENABLED_VOLUME: HRESULT = 0x80310097; +pub const FVE_E_FIPS_HASH_KDF_NOT_ALLOWED: HRESULT = 0x80310098; +pub const FVE_E_ENH_PIN_INVALID: HRESULT = 0x80310099; +pub const FVE_E_INVALID_PIN_CHARS: HRESULT = 0x8031009A; +pub const FVE_E_INVALID_DATUM_TYPE: HRESULT = 0x8031009B; +pub const FVE_E_EFI_ONLY: HRESULT = 0x8031009C; +pub const FVE_E_MULTIPLE_NKP_CERTS: HRESULT = 0x8031009D; +pub const FVE_E_REMOVAL_OF_NKP_FAILED: HRESULT = 0x8031009E; +pub const FVE_E_INVALID_NKP_CERT: HRESULT = 0x8031009F; +pub const FVE_E_NO_EXISTING_PIN: HRESULT = 0x803100A0; +pub const FVE_E_PROTECTOR_CHANGE_PIN_MISMATCH: HRESULT = 0x803100A1; +pub const FVE_E_PIN_PROTECTOR_CHANGE_BY_STD_USER_DISALLOWED: HRESULT = 0x803100A2; +pub const FVE_E_PROTECTOR_CHANGE_MAX_PIN_CHANGE_ATTEMPTS_REACHED: HRESULT + = 0x803100A3; +pub const FVE_E_POLICY_PASSPHRASE_REQUIRES_ASCII: HRESULT = 0x803100A4; +pub const FVE_E_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE: HRESULT = 0x803100A5; +pub const FVE_E_WIPE_NOT_ALLOWED_ON_TP_STORAGE: HRESULT = 0x803100A6; +pub const FVE_E_KEY_LENGTH_NOT_SUPPORTED_BY_EDRIVE: HRESULT = 0x803100A7; +pub const FVE_E_NO_EXISTING_PASSPHRASE: HRESULT = 0x803100A8; +pub const FVE_E_PROTECTOR_CHANGE_PASSPHRASE_MISMATCH: HRESULT = 0x803100A9; +pub const FVE_E_PASSPHRASE_TOO_LONG: HRESULT = 0x803100AA; +pub const FVE_E_NO_PASSPHRASE_WITH_TPM: HRESULT = 0x803100AB; +pub const FVE_E_NO_TPM_WITH_PASSPHRASE: HRESULT = 0x803100AC; +pub const FVE_E_NOT_ALLOWED_ON_CSV_STACK: HRESULT = 0x803100AD; +pub const FVE_E_NOT_ALLOWED_ON_CLUSTER: HRESULT = 0x803100AE; +pub const FVE_E_EDRIVE_NO_FAILOVER_TO_SW: HRESULT = 0x803100AF; +pub const FVE_E_EDRIVE_BAND_IN_USE: HRESULT = 0x803100B0; +pub const FVE_E_EDRIVE_DISALLOWED_BY_GP: HRESULT = 0x803100B1; +pub const FVE_E_EDRIVE_INCOMPATIBLE_VOLUME: HRESULT = 0x803100B2; +pub const FVE_E_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING: HRESULT = 0x803100B3; +pub const FVE_E_EDRIVE_DV_NOT_SUPPORTED: HRESULT = 0x803100B4; +pub const FVE_E_NO_PREBOOT_KEYBOARD_DETECTED: HRESULT = 0x803100B5; +pub const FVE_E_NO_PREBOOT_KEYBOARD_OR_WINRE_DETECTED: HRESULT = 0x803100B6; +pub const FVE_E_POLICY_REQUIRES_STARTUP_PIN_ON_TOUCH_DEVICE: HRESULT = 0x803100B7; +pub const FVE_E_POLICY_REQUIRES_RECOVERY_PASSWORD_ON_TOUCH_DEVICE: HRESULT + = 0x803100B8; +pub const FVE_E_WIPE_CANCEL_NOT_APPLICABLE: HRESULT = 0x803100B9; +pub const FVE_E_SECUREBOOT_DISABLED: HRESULT = 0x803100BA; +pub const FVE_E_SECUREBOOT_CONFIGURATION_INVALID: HRESULT = 0x803100BB; +pub const FVE_E_EDRIVE_DRY_RUN_FAILED: HRESULT = 0x803100BC; +pub const FVE_E_SHADOW_COPY_PRESENT: HRESULT = 0x803100BD; +pub const FVE_E_POLICY_INVALID_ENHANCED_BCD_SETTINGS: HRESULT = 0x803100BE; +pub const FVE_E_EDRIVE_INCOMPATIBLE_FIRMWARE: HRESULT = 0x803100BF; +pub const FVE_E_PROTECTOR_CHANGE_MAX_PASSPHRASE_CHANGE_ATTEMPTS_REACHED: HRESULT + = 0x803100C0; +pub const FVE_E_PASSPHRASE_PROTECTOR_CHANGE_BY_STD_USER_DISALLOWED: HRESULT + = 0x803100C1; +pub const FVE_E_LIVEID_ACCOUNT_SUSPENDED: HRESULT = 0x803100C2; +pub const FVE_E_LIVEID_ACCOUNT_BLOCKED: HRESULT = 0x803100C3; +pub const FVE_E_NOT_PROVISIONED_ON_ALL_VOLUMES: HRESULT = 0x803100C4; +pub const FVE_E_DE_FIXED_DATA_NOT_SUPPORTED: HRESULT = 0x803100C5; +pub const FVE_E_DE_HARDWARE_NOT_COMPLIANT: HRESULT = 0x803100C6; +pub const FVE_E_DE_WINRE_NOT_CONFIGURED: HRESULT = 0x803100C7; +pub const FVE_E_DE_PROTECTION_SUSPENDED: HRESULT = 0x803100C8; +pub const FVE_E_DE_OS_VOLUME_NOT_PROTECTED: HRESULT = 0x803100C9; +pub const FVE_E_DE_DEVICE_LOCKEDOUT: HRESULT = 0x803100CA; +pub const FVE_E_DE_PROTECTION_NOT_YET_ENABLED: HRESULT = 0x803100CB; +pub const FVE_E_INVALID_PIN_CHARS_DETAILED: HRESULT = 0x803100CC; +pub const FVE_E_DEVICE_LOCKOUT_COUNTER_UNAVAILABLE: HRESULT = 0x803100CD; +pub const FVE_E_DEVICELOCKOUT_COUNTER_MISMATCH: HRESULT = 0x803100CE; +pub const FVE_E_BUFFER_TOO_LARGE: HRESULT = 0x803100CF; +pub const FVE_E_NO_SUCH_CAPABILITY_ON_TARGET: HRESULT = 0x803100D0; +pub const FVE_E_DE_PREVENTED_FOR_OS: HRESULT = 0x803100D1; +pub const FVE_E_DE_VOLUME_OPTED_OUT: HRESULT = 0x803100D2; +pub const FVE_E_DE_VOLUME_NOT_SUPPORTED: HRESULT = 0x803100D3; +pub const FVE_E_EOW_NOT_SUPPORTED_IN_VERSION: HRESULT = 0x803100D4; +pub const FVE_E_ADBACKUP_NOT_ENABLED: HRESULT = 0x803100D5; +pub const FVE_E_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT: HRESULT = 0x803100D6; +pub const FVE_E_NOT_DE_VOLUME: HRESULT = 0x803100D7; +pub const FVE_E_PROTECTION_CANNOT_BE_DISABLED: HRESULT = 0x803100D8; +pub const FWP_E_CALLOUT_NOT_FOUND: HRESULT = 0x80320001; +pub const FWP_E_CONDITION_NOT_FOUND: HRESULT = 0x80320002; +pub const FWP_E_FILTER_NOT_FOUND: HRESULT = 0x80320003; +pub const FWP_E_LAYER_NOT_FOUND: HRESULT = 0x80320004; +pub const FWP_E_PROVIDER_NOT_FOUND: HRESULT = 0x80320005; +pub const FWP_E_PROVIDER_CONTEXT_NOT_FOUND: HRESULT = 0x80320006; +pub const FWP_E_SUBLAYER_NOT_FOUND: HRESULT = 0x80320007; +pub const FWP_E_NOT_FOUND: HRESULT = 0x80320008; +pub const FWP_E_ALREADY_EXISTS: HRESULT = 0x80320009; +pub const FWP_E_IN_USE: HRESULT = 0x8032000A; +pub const FWP_E_DYNAMIC_SESSION_IN_PROGRESS: HRESULT = 0x8032000B; +pub const FWP_E_WRONG_SESSION: HRESULT = 0x8032000C; +pub const FWP_E_NO_TXN_IN_PROGRESS: HRESULT = 0x8032000D; +pub const FWP_E_TXN_IN_PROGRESS: HRESULT = 0x8032000E; +pub const FWP_E_TXN_ABORTED: HRESULT = 0x8032000F; +pub const FWP_E_SESSION_ABORTED: HRESULT = 0x80320010; +pub const FWP_E_INCOMPATIBLE_TXN: HRESULT = 0x80320011; +pub const FWP_E_TIMEOUT: HRESULT = 0x80320012; +pub const FWP_E_NET_EVENTS_DISABLED: HRESULT = 0x80320013; +pub const FWP_E_INCOMPATIBLE_LAYER: HRESULT = 0x80320014; +pub const FWP_E_KM_CLIENTS_ONLY: HRESULT = 0x80320015; +pub const FWP_E_LIFETIME_MISMATCH: HRESULT = 0x80320016; +pub const FWP_E_BUILTIN_OBJECT: HRESULT = 0x80320017; +pub const FWP_E_TOO_MANY_CALLOUTS: HRESULT = 0x80320018; +pub const FWP_E_NOTIFICATION_DROPPED: HRESULT = 0x80320019; +pub const FWP_E_TRAFFIC_MISMATCH: HRESULT = 0x8032001A; +pub const FWP_E_INCOMPATIBLE_SA_STATE: HRESULT = 0x8032001B; +pub const FWP_E_NULL_POINTER: HRESULT = 0x8032001C; +pub const FWP_E_INVALID_ENUMERATOR: HRESULT = 0x8032001D; +pub const FWP_E_INVALID_FLAGS: HRESULT = 0x8032001E; +pub const FWP_E_INVALID_NET_MASK: HRESULT = 0x8032001F; +pub const FWP_E_INVALID_RANGE: HRESULT = 0x80320020; +pub const FWP_E_INVALID_INTERVAL: HRESULT = 0x80320021; +pub const FWP_E_ZERO_LENGTH_ARRAY: HRESULT = 0x80320022; +pub const FWP_E_NULL_DISPLAY_NAME: HRESULT = 0x80320023; +pub const FWP_E_INVALID_ACTION_TYPE: HRESULT = 0x80320024; +pub const FWP_E_INVALID_WEIGHT: HRESULT = 0x80320025; +pub const FWP_E_MATCH_TYPE_MISMATCH: HRESULT = 0x80320026; +pub const FWP_E_TYPE_MISMATCH: HRESULT = 0x80320027; +pub const FWP_E_OUT_OF_BOUNDS: HRESULT = 0x80320028; +pub const FWP_E_RESERVED: HRESULT = 0x80320029; +pub const FWP_E_DUPLICATE_CONDITION: HRESULT = 0x8032002A; +pub const FWP_E_DUPLICATE_KEYMOD: HRESULT = 0x8032002B; +pub const FWP_E_ACTION_INCOMPATIBLE_WITH_LAYER: HRESULT = 0x8032002C; +pub const FWP_E_ACTION_INCOMPATIBLE_WITH_SUBLAYER: HRESULT = 0x8032002D; +pub const FWP_E_CONTEXT_INCOMPATIBLE_WITH_LAYER: HRESULT = 0x8032002E; +pub const FWP_E_CONTEXT_INCOMPATIBLE_WITH_CALLOUT: HRESULT = 0x8032002F; +pub const FWP_E_INCOMPATIBLE_AUTH_METHOD: HRESULT = 0x80320030; +pub const FWP_E_INCOMPATIBLE_DH_GROUP: HRESULT = 0x80320031; +pub const FWP_E_EM_NOT_SUPPORTED: HRESULT = 0x80320032; +pub const FWP_E_NEVER_MATCH: HRESULT = 0x80320033; +pub const FWP_E_PROVIDER_CONTEXT_MISMATCH: HRESULT = 0x80320034; +pub const FWP_E_INVALID_PARAMETER: HRESULT = 0x80320035; +pub const FWP_E_TOO_MANY_SUBLAYERS: HRESULT = 0x80320036; +pub const FWP_E_CALLOUT_NOTIFICATION_FAILED: HRESULT = 0x80320037; +pub const FWP_E_INVALID_AUTH_TRANSFORM: HRESULT = 0x80320038; +pub const FWP_E_INVALID_CIPHER_TRANSFORM: HRESULT = 0x80320039; +pub const FWP_E_INCOMPATIBLE_CIPHER_TRANSFORM: HRESULT = 0x8032003A; +pub const FWP_E_INVALID_TRANSFORM_COMBINATION: HRESULT = 0x8032003B; +pub const FWP_E_DUPLICATE_AUTH_METHOD: HRESULT = 0x8032003C; +pub const FWP_E_INVALID_TUNNEL_ENDPOINT: HRESULT = 0x8032003D; +pub const FWP_E_L2_DRIVER_NOT_READY: HRESULT = 0x8032003E; +pub const FWP_E_KEY_DICTATOR_ALREADY_REGISTERED: HRESULT = 0x8032003F; +pub const FWP_E_KEY_DICTATION_INVALID_KEYING_MATERIAL: HRESULT = 0x80320040; +pub const FWP_E_CONNECTIONS_DISABLED: HRESULT = 0x80320041; +pub const FWP_E_INVALID_DNS_NAME: HRESULT = 0x80320042; +pub const FWP_E_STILL_ON: HRESULT = 0x80320043; +pub const FWP_E_IKEEXT_NOT_RUNNING: HRESULT = 0x80320044; +pub const FWP_E_DROP_NOICMP: HRESULT = 0x80320104; +pub const WS_S_ASYNC: HRESULT = 0x003D0000; +pub const WS_S_END: HRESULT = 0x003D0001; +pub const WS_E_INVALID_FORMAT: HRESULT = 0x803D0000; +pub const WS_E_OBJECT_FAULTED: HRESULT = 0x803D0001; +pub const WS_E_NUMERIC_OVERFLOW: HRESULT = 0x803D0002; +pub const WS_E_INVALID_OPERATION: HRESULT = 0x803D0003; +pub const WS_E_OPERATION_ABORTED: HRESULT = 0x803D0004; +pub const WS_E_ENDPOINT_ACCESS_DENIED: HRESULT = 0x803D0005; +pub const WS_E_OPERATION_TIMED_OUT: HRESULT = 0x803D0006; +pub const WS_E_OPERATION_ABANDONED: HRESULT = 0x803D0007; +pub const WS_E_QUOTA_EXCEEDED: HRESULT = 0x803D0008; +pub const WS_E_NO_TRANSLATION_AVAILABLE: HRESULT = 0x803D0009; +pub const WS_E_SECURITY_VERIFICATION_FAILURE: HRESULT = 0x803D000A; +pub const WS_E_ADDRESS_IN_USE: HRESULT = 0x803D000B; +pub const WS_E_ADDRESS_NOT_AVAILABLE: HRESULT = 0x803D000C; +pub const WS_E_ENDPOINT_NOT_FOUND: HRESULT = 0x803D000D; +pub const WS_E_ENDPOINT_NOT_AVAILABLE: HRESULT = 0x803D000E; +pub const WS_E_ENDPOINT_FAILURE: HRESULT = 0x803D000F; +pub const WS_E_ENDPOINT_UNREACHABLE: HRESULT = 0x803D0010; +pub const WS_E_ENDPOINT_ACTION_NOT_SUPPORTED: HRESULT = 0x803D0011; +pub const WS_E_ENDPOINT_TOO_BUSY: HRESULT = 0x803D0012; +pub const WS_E_ENDPOINT_FAULT_RECEIVED: HRESULT = 0x803D0013; +pub const WS_E_ENDPOINT_DISCONNECTED: HRESULT = 0x803D0014; +pub const WS_E_PROXY_FAILURE: HRESULT = 0x803D0015; +pub const WS_E_PROXY_ACCESS_DENIED: HRESULT = 0x803D0016; +pub const WS_E_NOT_SUPPORTED: HRESULT = 0x803D0017; +pub const WS_E_PROXY_REQUIRES_BASIC_AUTH: HRESULT = 0x803D0018; +pub const WS_E_PROXY_REQUIRES_DIGEST_AUTH: HRESULT = 0x803D0019; +pub const WS_E_PROXY_REQUIRES_NTLM_AUTH: HRESULT = 0x803D001A; +pub const WS_E_PROXY_REQUIRES_NEGOTIATE_AUTH: HRESULT = 0x803D001B; +pub const WS_E_SERVER_REQUIRES_BASIC_AUTH: HRESULT = 0x803D001C; +pub const WS_E_SERVER_REQUIRES_DIGEST_AUTH: HRESULT = 0x803D001D; +pub const WS_E_SERVER_REQUIRES_NTLM_AUTH: HRESULT = 0x803D001E; +pub const WS_E_SERVER_REQUIRES_NEGOTIATE_AUTH: HRESULT = 0x803D001F; +pub const WS_E_INVALID_ENDPOINT_URL: HRESULT = 0x803D0020; +pub const WS_E_OTHER: HRESULT = 0x803D0021; +pub const WS_E_SECURITY_TOKEN_EXPIRED: HRESULT = 0x803D0022; +pub const WS_E_SECURITY_SYSTEM_FAILURE: HRESULT = 0x803D0023; +pub const ERROR_NDIS_INTERFACE_CLOSING: HRESULT = 0x80340002; +pub const ERROR_NDIS_BAD_VERSION: HRESULT = 0x80340004; +pub const ERROR_NDIS_BAD_CHARACTERISTICS: HRESULT = 0x80340005; +pub const ERROR_NDIS_ADAPTER_NOT_FOUND: HRESULT = 0x80340006; +pub const ERROR_NDIS_OPEN_FAILED: HRESULT = 0x80340007; +pub const ERROR_NDIS_DEVICE_FAILED: HRESULT = 0x80340008; +pub const ERROR_NDIS_MULTICAST_FULL: HRESULT = 0x80340009; +pub const ERROR_NDIS_MULTICAST_EXISTS: HRESULT = 0x8034000A; +pub const ERROR_NDIS_MULTICAST_NOT_FOUND: HRESULT = 0x8034000B; +pub const ERROR_NDIS_REQUEST_ABORTED: HRESULT = 0x8034000C; +pub const ERROR_NDIS_RESET_IN_PROGRESS: HRESULT = 0x8034000D; +pub const ERROR_NDIS_NOT_SUPPORTED: HRESULT = 0x803400BB; +pub const ERROR_NDIS_INVALID_PACKET: HRESULT = 0x8034000F; +pub const ERROR_NDIS_ADAPTER_NOT_READY: HRESULT = 0x80340011; +pub const ERROR_NDIS_INVALID_LENGTH: HRESULT = 0x80340014; +pub const ERROR_NDIS_INVALID_DATA: HRESULT = 0x80340015; +pub const ERROR_NDIS_BUFFER_TOO_SHORT: HRESULT = 0x80340016; +pub const ERROR_NDIS_INVALID_OID: HRESULT = 0x80340017; +pub const ERROR_NDIS_ADAPTER_REMOVED: HRESULT = 0x80340018; +pub const ERROR_NDIS_UNSUPPORTED_MEDIA: HRESULT = 0x80340019; +pub const ERROR_NDIS_GROUP_ADDRESS_IN_USE: HRESULT = 0x8034001A; +pub const ERROR_NDIS_FILE_NOT_FOUND: HRESULT = 0x8034001B; +pub const ERROR_NDIS_ERROR_READING_FILE: HRESULT = 0x8034001C; +pub const ERROR_NDIS_ALREADY_MAPPED: HRESULT = 0x8034001D; +pub const ERROR_NDIS_RESOURCE_CONFLICT: HRESULT = 0x8034001E; +pub const ERROR_NDIS_MEDIA_DISCONNECTED: HRESULT = 0x8034001F; +pub const ERROR_NDIS_INVALID_ADDRESS: HRESULT = 0x80340022; +pub const ERROR_NDIS_INVALID_DEVICE_REQUEST: HRESULT = 0x80340010; +pub const ERROR_NDIS_PAUSED: HRESULT = 0x8034002A; +pub const ERROR_NDIS_INTERFACE_NOT_FOUND: HRESULT = 0x8034002B; +pub const ERROR_NDIS_UNSUPPORTED_REVISION: HRESULT = 0x8034002C; +pub const ERROR_NDIS_INVALID_PORT: HRESULT = 0x8034002D; +pub const ERROR_NDIS_INVALID_PORT_STATE: HRESULT = 0x8034002E; +pub const ERROR_NDIS_LOW_POWER_STATE: HRESULT = 0x8034002F; +pub const ERROR_NDIS_REINIT_REQUIRED: HRESULT = 0x80340030; +pub const ERROR_NDIS_DOT11_AUTO_CONFIG_ENABLED: HRESULT = 0x80342000; +pub const ERROR_NDIS_DOT11_MEDIA_IN_USE: HRESULT = 0x80342001; +pub const ERROR_NDIS_DOT11_POWER_STATE_INVALID: HRESULT = 0x80342002; +pub const ERROR_NDIS_PM_WOL_PATTERN_LIST_FULL: HRESULT = 0x80342003; +pub const ERROR_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL: HRESULT = 0x80342004; +pub const ERROR_NDIS_INDICATION_REQUIRED: HRESULT = 0x00340001; +pub const ERROR_NDIS_OFFLOAD_POLICY: HRESULT = 0xC034100F; +pub const ERROR_NDIS_OFFLOAD_CONNECTION_REJECTED: HRESULT = 0xC0341012; +pub const ERROR_NDIS_OFFLOAD_PATH_REJECTED: HRESULT = 0xC0341013; +pub const ERROR_HV_INVALID_HYPERCALL_CODE: HRESULT = 0xC0350002; +pub const ERROR_HV_INVALID_HYPERCALL_INPUT: HRESULT = 0xC0350003; +pub const ERROR_HV_INVALID_ALIGNMENT: HRESULT = 0xC0350004; +pub const ERROR_HV_INVALID_PARAMETER: HRESULT = 0xC0350005; +pub const ERROR_HV_ACCESS_DENIED: HRESULT = 0xC0350006; +pub const ERROR_HV_INVALID_PARTITION_STATE: HRESULT = 0xC0350007; +pub const ERROR_HV_OPERATION_DENIED: HRESULT = 0xC0350008; +pub const ERROR_HV_UNKNOWN_PROPERTY: HRESULT = 0xC0350009; +pub const ERROR_HV_PROPERTY_VALUE_OUT_OF_RANGE: HRESULT = 0xC035000A; +pub const ERROR_HV_INSUFFICIENT_MEMORY: HRESULT = 0xC035000B; +pub const ERROR_HV_PARTITION_TOO_DEEP: HRESULT = 0xC035000C; +pub const ERROR_HV_INVALID_PARTITION_ID: HRESULT = 0xC035000D; +pub const ERROR_HV_INVALID_VP_INDEX: HRESULT = 0xC035000E; +pub const ERROR_HV_INVALID_PORT_ID: HRESULT = 0xC0350011; +pub const ERROR_HV_INVALID_CONNECTION_ID: HRESULT = 0xC0350012; +pub const ERROR_HV_INSUFFICIENT_BUFFERS: HRESULT = 0xC0350013; +pub const ERROR_HV_NOT_ACKNOWLEDGED: HRESULT = 0xC0350014; +pub const ERROR_HV_ACKNOWLEDGED: HRESULT = 0xC0350016; +pub const ERROR_HV_INVALID_SAVE_RESTORE_STATE: HRESULT = 0xC0350017; +pub const ERROR_HV_INVALID_SYNIC_STATE: HRESULT = 0xC0350018; +pub const ERROR_HV_OBJECT_IN_USE: HRESULT = 0xC0350019; +pub const ERROR_HV_INVALID_PROXIMITY_DOMAIN_INFO: HRESULT = 0xC035001A; +pub const ERROR_HV_NO_DATA: HRESULT = 0xC035001B; +pub const ERROR_HV_INACTIVE: HRESULT = 0xC035001C; +pub const ERROR_HV_NO_RESOURCES: HRESULT = 0xC035001D; +pub const ERROR_HV_FEATURE_UNAVAILABLE: HRESULT = 0xC035001E; +pub const ERROR_HV_INSUFFICIENT_BUFFER: HRESULT = 0xC0350033; +pub const ERROR_HV_INSUFFICIENT_DEVICE_DOMAINS: HRESULT = 0xC0350038; +pub const ERROR_HV_INVALID_LP_INDEX: HRESULT = 0xC0350041; +pub const ERROR_HV_NOT_PRESENT: HRESULT = 0xC0351000; +pub const ERROR_VID_DUPLICATE_HANDLER: HRESULT = 0xC0370001; +pub const ERROR_VID_TOO_MANY_HANDLERS: HRESULT = 0xC0370002; +pub const ERROR_VID_QUEUE_FULL: HRESULT = 0xC0370003; +pub const ERROR_VID_HANDLER_NOT_PRESENT: HRESULT = 0xC0370004; +pub const ERROR_VID_INVALID_OBJECT_NAME: HRESULT = 0xC0370005; +pub const ERROR_VID_PARTITION_NAME_TOO_LONG: HRESULT = 0xC0370006; +pub const ERROR_VID_MESSAGE_QUEUE_NAME_TOO_LONG: HRESULT = 0xC0370007; +pub const ERROR_VID_PARTITION_ALREADY_EXISTS: HRESULT = 0xC0370008; +pub const ERROR_VID_PARTITION_DOES_NOT_EXIST: HRESULT = 0xC0370009; +pub const ERROR_VID_PARTITION_NAME_NOT_FOUND: HRESULT = 0xC037000A; +pub const ERROR_VID_MESSAGE_QUEUE_ALREADY_EXISTS: HRESULT = 0xC037000B; +pub const ERROR_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT: HRESULT = 0xC037000C; +pub const ERROR_VID_MB_STILL_REFERENCED: HRESULT = 0xC037000D; +pub const ERROR_VID_CHILD_GPA_PAGE_SET_CORRUPTED: HRESULT = 0xC037000E; +pub const ERROR_VID_INVALID_NUMA_SETTINGS: HRESULT = 0xC037000F; +pub const ERROR_VID_INVALID_NUMA_NODE_INDEX: HRESULT = 0xC0370010; +pub const ERROR_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED: HRESULT = 0xC0370011; +pub const ERROR_VID_INVALID_MEMORY_BLOCK_HANDLE: HRESULT = 0xC0370012; +pub const ERROR_VID_PAGE_RANGE_OVERFLOW: HRESULT = 0xC0370013; +pub const ERROR_VID_INVALID_MESSAGE_QUEUE_HANDLE: HRESULT = 0xC0370014; +pub const ERROR_VID_INVALID_GPA_RANGE_HANDLE: HRESULT = 0xC0370015; +pub const ERROR_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE: HRESULT = 0xC0370016; +pub const ERROR_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED: HRESULT = 0xC0370017; +pub const ERROR_VID_INVALID_PPM_HANDLE: HRESULT = 0xC0370018; +pub const ERROR_VID_MBPS_ARE_LOCKED: HRESULT = 0xC0370019; +pub const ERROR_VID_MESSAGE_QUEUE_CLOSED: HRESULT = 0xC037001A; +pub const ERROR_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED: HRESULT = 0xC037001B; +pub const ERROR_VID_STOP_PENDING: HRESULT = 0xC037001C; +pub const ERROR_VID_INVALID_PROCESSOR_STATE: HRESULT = 0xC037001D; +pub const ERROR_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT: HRESULT = 0xC037001E; +pub const ERROR_VID_KM_INTERFACE_ALREADY_INITIALIZED: HRESULT = 0xC037001F; +pub const ERROR_VID_MB_PROPERTY_ALREADY_SET_RESET: HRESULT = 0xC0370020; +pub const ERROR_VID_MMIO_RANGE_DESTROYED: HRESULT = 0xC0370021; +pub const ERROR_VID_INVALID_CHILD_GPA_PAGE_SET: HRESULT = 0xC0370022; +pub const ERROR_VID_RESERVE_PAGE_SET_IS_BEING_USED: HRESULT = 0xC0370023; +pub const ERROR_VID_RESERVE_PAGE_SET_TOO_SMALL: HRESULT = 0xC0370024; +pub const ERROR_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE: HRESULT = 0xC0370025; +pub const ERROR_VID_MBP_COUNT_EXCEEDED_LIMIT: HRESULT = 0xC0370026; +pub const ERROR_VID_SAVED_STATE_CORRUPT: HRESULT = 0xC0370027; +pub const ERROR_VID_SAVED_STATE_UNRECOGNIZED_ITEM: HRESULT = 0xC0370028; +pub const ERROR_VID_SAVED_STATE_INCOMPATIBLE: HRESULT = 0xC0370029; +pub const ERROR_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED: HRESULT = 0x80370001; +pub const ERROR_VOLMGR_INCOMPLETE_REGENERATION: HRESULT = 0x80380001; +pub const ERROR_VOLMGR_INCOMPLETE_DISK_MIGRATION: HRESULT = 0x80380002; +pub const ERROR_VOLMGR_DATABASE_FULL: HRESULT = 0xC0380001; +pub const ERROR_VOLMGR_DISK_CONFIGURATION_CORRUPTED: HRESULT = 0xC0380002; +pub const ERROR_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC: HRESULT = 0xC0380003; +pub const ERROR_VOLMGR_PACK_CONFIG_UPDATE_FAILED: HRESULT = 0xC0380004; +pub const ERROR_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME: HRESULT = 0xC0380005; +pub const ERROR_VOLMGR_DISK_DUPLICATE: HRESULT = 0xC0380006; +pub const ERROR_VOLMGR_DISK_DYNAMIC: HRESULT = 0xC0380007; +pub const ERROR_VOLMGR_DISK_ID_INVALID: HRESULT = 0xC0380008; +pub const ERROR_VOLMGR_DISK_INVALID: HRESULT = 0xC0380009; +pub const ERROR_VOLMGR_DISK_LAST_VOTER: HRESULT = 0xC038000A; +pub const ERROR_VOLMGR_DISK_LAYOUT_INVALID: HRESULT = 0xC038000B; +pub const ERROR_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS: HRESULT + = 0xC038000C; +pub const ERROR_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED: HRESULT = 0xC038000D; +pub const ERROR_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL: HRESULT = 0xC038000E; +pub const ERROR_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS: HRESULT + = 0xC038000F; +pub const ERROR_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS: HRESULT = 0xC0380010; +pub const ERROR_VOLMGR_DISK_MISSING: HRESULT = 0xC0380011; +pub const ERROR_VOLMGR_DISK_NOT_EMPTY: HRESULT = 0xC0380012; +pub const ERROR_VOLMGR_DISK_NOT_ENOUGH_SPACE: HRESULT = 0xC0380013; +pub const ERROR_VOLMGR_DISK_REVECTORING_FAILED: HRESULT = 0xC0380014; +pub const ERROR_VOLMGR_DISK_SECTOR_SIZE_INVALID: HRESULT = 0xC0380015; +pub const ERROR_VOLMGR_DISK_SET_NOT_CONTAINED: HRESULT = 0xC0380016; +pub const ERROR_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS: HRESULT = 0xC0380017; +pub const ERROR_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES: HRESULT = 0xC0380018; +pub const ERROR_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED: HRESULT = 0xC0380019; +pub const ERROR_VOLMGR_EXTENT_ALREADY_USED: HRESULT = 0xC038001A; +pub const ERROR_VOLMGR_EXTENT_NOT_CONTIGUOUS: HRESULT = 0xC038001B; +pub const ERROR_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION: HRESULT = 0xC038001C; +pub const ERROR_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED: HRESULT = 0xC038001D; +pub const ERROR_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION: HRESULT = 0xC038001E; +pub const ERROR_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH: HRESULT = 0xC038001F; +pub const ERROR_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED: HRESULT = 0xC0380020; +pub const ERROR_VOLMGR_INTERLEAVE_LENGTH_INVALID: HRESULT = 0xC0380021; +pub const ERROR_VOLMGR_MAXIMUM_REGISTERED_USERS: HRESULT = 0xC0380022; +pub const ERROR_VOLMGR_MEMBER_IN_SYNC: HRESULT = 0xC0380023; +pub const ERROR_VOLMGR_MEMBER_INDEX_DUPLICATE: HRESULT = 0xC0380024; +pub const ERROR_VOLMGR_MEMBER_INDEX_INVALID: HRESULT = 0xC0380025; +pub const ERROR_VOLMGR_MEMBER_MISSING: HRESULT = 0xC0380026; +pub const ERROR_VOLMGR_MEMBER_NOT_DETACHED: HRESULT = 0xC0380027; +pub const ERROR_VOLMGR_MEMBER_REGENERATING: HRESULT = 0xC0380028; +pub const ERROR_VOLMGR_ALL_DISKS_FAILED: HRESULT = 0xC0380029; +pub const ERROR_VOLMGR_NO_REGISTERED_USERS: HRESULT = 0xC038002A; +pub const ERROR_VOLMGR_NO_SUCH_USER: HRESULT = 0xC038002B; +pub const ERROR_VOLMGR_NOTIFICATION_RESET: HRESULT = 0xC038002C; +pub const ERROR_VOLMGR_NUMBER_OF_MEMBERS_INVALID: HRESULT = 0xC038002D; +pub const ERROR_VOLMGR_NUMBER_OF_PLEXES_INVALID: HRESULT = 0xC038002E; +pub const ERROR_VOLMGR_PACK_DUPLICATE: HRESULT = 0xC038002F; +pub const ERROR_VOLMGR_PACK_ID_INVALID: HRESULT = 0xC0380030; +pub const ERROR_VOLMGR_PACK_INVALID: HRESULT = 0xC0380031; +pub const ERROR_VOLMGR_PACK_NAME_INVALID: HRESULT = 0xC0380032; +pub const ERROR_VOLMGR_PACK_OFFLINE: HRESULT = 0xC0380033; +pub const ERROR_VOLMGR_PACK_HAS_QUORUM: HRESULT = 0xC0380034; +pub const ERROR_VOLMGR_PACK_WITHOUT_QUORUM: HRESULT = 0xC0380035; +pub const ERROR_VOLMGR_PARTITION_STYLE_INVALID: HRESULT = 0xC0380036; +pub const ERROR_VOLMGR_PARTITION_UPDATE_FAILED: HRESULT = 0xC0380037; +pub const ERROR_VOLMGR_PLEX_IN_SYNC: HRESULT = 0xC0380038; +pub const ERROR_VOLMGR_PLEX_INDEX_DUPLICATE: HRESULT = 0xC0380039; +pub const ERROR_VOLMGR_PLEX_INDEX_INVALID: HRESULT = 0xC038003A; +pub const ERROR_VOLMGR_PLEX_LAST_ACTIVE: HRESULT = 0xC038003B; +pub const ERROR_VOLMGR_PLEX_MISSING: HRESULT = 0xC038003C; +pub const ERROR_VOLMGR_PLEX_REGENERATING: HRESULT = 0xC038003D; +pub const ERROR_VOLMGR_PLEX_TYPE_INVALID: HRESULT = 0xC038003E; +pub const ERROR_VOLMGR_PLEX_NOT_RAID5: HRESULT = 0xC038003F; +pub const ERROR_VOLMGR_PLEX_NOT_SIMPLE: HRESULT = 0xC0380040; +pub const ERROR_VOLMGR_STRUCTURE_SIZE_INVALID: HRESULT = 0xC0380041; +pub const ERROR_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS: HRESULT = 0xC0380042; +pub const ERROR_VOLMGR_TRANSACTION_IN_PROGRESS: HRESULT = 0xC0380043; +pub const ERROR_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE: HRESULT = 0xC0380044; +pub const ERROR_VOLMGR_VOLUME_CONTAINS_MISSING_DISK: HRESULT = 0xC0380045; +pub const ERROR_VOLMGR_VOLUME_ID_INVALID: HRESULT = 0xC0380046; +pub const ERROR_VOLMGR_VOLUME_LENGTH_INVALID: HRESULT = 0xC0380047; +pub const ERROR_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE: HRESULT = 0xC0380048; +pub const ERROR_VOLMGR_VOLUME_NOT_MIRRORED: HRESULT = 0xC0380049; +pub const ERROR_VOLMGR_VOLUME_NOT_RETAINED: HRESULT = 0xC038004A; +pub const ERROR_VOLMGR_VOLUME_OFFLINE: HRESULT = 0xC038004B; +pub const ERROR_VOLMGR_VOLUME_RETAINED: HRESULT = 0xC038004C; +pub const ERROR_VOLMGR_NUMBER_OF_EXTENTS_INVALID: HRESULT = 0xC038004D; +pub const ERROR_VOLMGR_DIFFERENT_SECTOR_SIZE: HRESULT = 0xC038004E; +pub const ERROR_VOLMGR_BAD_BOOT_DISK: HRESULT = 0xC038004F; +pub const ERROR_VOLMGR_PACK_CONFIG_OFFLINE: HRESULT = 0xC0380050; +pub const ERROR_VOLMGR_PACK_CONFIG_ONLINE: HRESULT = 0xC0380051; +pub const ERROR_VOLMGR_NOT_PRIMARY_PACK: HRESULT = 0xC0380052; +pub const ERROR_VOLMGR_PACK_LOG_UPDATE_FAILED: HRESULT = 0xC0380053; +pub const ERROR_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID: HRESULT = 0xC0380054; +pub const ERROR_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID: HRESULT = 0xC0380055; +pub const ERROR_VOLMGR_VOLUME_MIRRORED: HRESULT = 0xC0380056; +pub const ERROR_VOLMGR_PLEX_NOT_SIMPLE_SPANNED: HRESULT = 0xC0380057; +pub const ERROR_VOLMGR_NO_VALID_LOG_COPIES: HRESULT = 0xC0380058; +pub const ERROR_VOLMGR_PRIMARY_PACK_PRESENT: HRESULT = 0xC0380059; +pub const ERROR_VOLMGR_NUMBER_OF_DISKS_INVALID: HRESULT = 0xC038005A; +pub const ERROR_VOLMGR_MIRROR_NOT_SUPPORTED: HRESULT = 0xC038005B; +pub const ERROR_VOLMGR_RAID5_NOT_SUPPORTED: HRESULT = 0xC038005C; +pub const ERROR_BCD_NOT_ALL_ENTRIES_IMPORTED: HRESULT = 0x80390001; +pub const ERROR_BCD_TOO_MANY_ELEMENTS: HRESULT = 0xC0390002; +pub const ERROR_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED: HRESULT = 0x80390003; +pub const ERROR_VHD_DRIVE_FOOTER_MISSING: HRESULT = 0xC03A0001; +pub const ERROR_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH: HRESULT = 0xC03A0002; +pub const ERROR_VHD_DRIVE_FOOTER_CORRUPT: HRESULT = 0xC03A0003; +pub const ERROR_VHD_FORMAT_UNKNOWN: HRESULT = 0xC03A0004; +pub const ERROR_VHD_FORMAT_UNSUPPORTED_VERSION: HRESULT = 0xC03A0005; +pub const ERROR_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH: HRESULT = 0xC03A0006; +pub const ERROR_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION: HRESULT = 0xC03A0007; +pub const ERROR_VHD_SPARSE_HEADER_CORRUPT: HRESULT = 0xC03A0008; +pub const ERROR_VHD_BLOCK_ALLOCATION_FAILURE: HRESULT = 0xC03A0009; +pub const ERROR_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT: HRESULT = 0xC03A000A; +pub const ERROR_VHD_INVALID_BLOCK_SIZE: HRESULT = 0xC03A000B; +pub const ERROR_VHD_BITMAP_MISMATCH: HRESULT = 0xC03A000C; +pub const ERROR_VHD_PARENT_VHD_NOT_FOUND: HRESULT = 0xC03A000D; +pub const ERROR_VHD_CHILD_PARENT_ID_MISMATCH: HRESULT = 0xC03A000E; +pub const ERROR_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH: HRESULT = 0xC03A000F; +pub const ERROR_VHD_METADATA_READ_FAILURE: HRESULT = 0xC03A0010; +pub const ERROR_VHD_METADATA_WRITE_FAILURE: HRESULT = 0xC03A0011; +pub const ERROR_VHD_INVALID_SIZE: HRESULT = 0xC03A0012; +pub const ERROR_VHD_INVALID_FILE_SIZE: HRESULT = 0xC03A0013; +pub const ERROR_VIRTDISK_PROVIDER_NOT_FOUND: HRESULT = 0xC03A0014; +pub const ERROR_VIRTDISK_NOT_VIRTUAL_DISK: HRESULT = 0xC03A0015; +pub const ERROR_VHD_PARENT_VHD_ACCESS_DENIED: HRESULT = 0xC03A0016; +pub const ERROR_VHD_CHILD_PARENT_SIZE_MISMATCH: HRESULT = 0xC03A0017; +pub const ERROR_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED: HRESULT = 0xC03A0018; +pub const ERROR_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT: HRESULT = 0xC03A0019; +pub const ERROR_VIRTUAL_DISK_LIMITATION: HRESULT = 0xC03A001A; +pub const ERROR_VHD_INVALID_TYPE: HRESULT = 0xC03A001B; +pub const ERROR_VHD_INVALID_STATE: HRESULT = 0xC03A001C; +pub const ERROR_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE: HRESULT = 0xC03A001D; +pub const ERROR_VIRTDISK_DISK_ALREADY_OWNED: HRESULT = 0xC03A001E; +pub const ERROR_VIRTDISK_DISK_ONLINE_AND_WRITABLE: HRESULT = 0xC03A001F; +pub const ERROR_CTLOG_TRACKING_NOT_INITIALIZED: HRESULT = 0xC03A0020; +pub const ERROR_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE: HRESULT = 0xC03A0021; +pub const ERROR_CTLOG_VHD_CHANGED_OFFLINE: HRESULT = 0xC03A0022; +pub const ERROR_CTLOG_INVALID_TRACKING_STATE: HRESULT = 0xC03A0023; +pub const ERROR_CTLOG_INCONSISTENT_TRACKING_FILE: HRESULT = 0xC03A0024; +pub const ERROR_VHD_RESIZE_WOULD_TRUNCATE_DATA: HRESULT = 0xC03A0025; +pub const ERROR_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE: HRESULT = 0xC03A0026; +pub const ERROR_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE: HRESULT = 0xC03A0027; +pub const ERROR_VHD_METADATA_FULL: HRESULT = 0xC03A0028; +pub const ERROR_QUERY_STORAGE_ERROR: HRESULT = 0x803A0001; +pub const SDIAG_E_CANCELLED: HRESULT = 0x803C0100; +pub const SDIAG_E_SCRIPT: HRESULT = 0x803C0101; +pub const SDIAG_E_POWERSHELL: HRESULT = 0x803C0102; +pub const SDIAG_E_MANAGEDHOST: HRESULT = 0x803C0103; +pub const SDIAG_E_NOVERIFIER: HRESULT = 0x803C0104; +pub const SDIAG_S_CANNOTRUN: HRESULT = 0x003C0105; +pub const SDIAG_E_DISABLED: HRESULT = 0x803C0106; +pub const SDIAG_E_TRUST: HRESULT = 0x803C0107; +pub const SDIAG_E_CANNOTRUN: HRESULT = 0x803C0108; +pub const SDIAG_E_VERSION: HRESULT = 0x803C0109; +pub const SDIAG_E_RESOURCE: HRESULT = 0x803C010A; +pub const SDIAG_E_ROOTCAUSE: HRESULT = 0x803C010B; +pub const WPN_E_CHANNEL_CLOSED: HRESULT = 0x803E0100; +pub const WPN_E_CHANNEL_REQUEST_NOT_COMPLETE: HRESULT = 0x803E0101; +pub const WPN_E_INVALID_APP: HRESULT = 0x803E0102; +pub const WPN_E_OUTSTANDING_CHANNEL_REQUEST: HRESULT = 0x803E0103; +pub const WPN_E_DUPLICATE_CHANNEL: HRESULT = 0x803E0104; +pub const WPN_E_PLATFORM_UNAVAILABLE: HRESULT = 0x803E0105; +pub const WPN_E_NOTIFICATION_POSTED: HRESULT = 0x803E0106; +pub const WPN_E_NOTIFICATION_HIDDEN: HRESULT = 0x803E0107; +pub const WPN_E_NOTIFICATION_NOT_POSTED: HRESULT = 0x803E0108; +pub const WPN_E_CLOUD_DISABLED: HRESULT = 0x803E0109; +pub const WPN_E_CLOUD_INCAPABLE: HRESULT = 0x803E0110; +pub const WPN_E_CLOUD_AUTH_UNAVAILABLE: HRESULT = 0x803E011A; +pub const WPN_E_CLOUD_SERVICE_UNAVAILABLE: HRESULT = 0x803E011B; +pub const WPN_E_FAILED_LOCK_SCREEN_UPDATE_INTIALIZATION: HRESULT = 0x803E011C; +pub const WPN_E_NOTIFICATION_DISABLED: HRESULT = 0x803E0111; +pub const WPN_E_NOTIFICATION_INCAPABLE: HRESULT = 0x803E0112; +pub const WPN_E_INTERNET_INCAPABLE: HRESULT = 0x803E0113; +pub const WPN_E_NOTIFICATION_TYPE_DISABLED: HRESULT = 0x803E0114; +pub const WPN_E_NOTIFICATION_SIZE: HRESULT = 0x803E0115; +pub const WPN_E_TAG_SIZE: HRESULT = 0x803E0116; +pub const WPN_E_ACCESS_DENIED: HRESULT = 0x803E0117; +pub const WPN_E_DUPLICATE_REGISTRATION: HRESULT = 0x803E0118; +pub const WPN_E_PUSH_NOTIFICATION_INCAPABLE: HRESULT = 0x803E0119; +pub const WPN_E_DEV_ID_SIZE: HRESULT = 0x803E0120; +pub const WPN_E_TAG_ALPHANUMERIC: HRESULT = 0x803E012A; +pub const WPN_E_INVALID_HTTP_STATUS_CODE: HRESULT = 0x803E012B; +pub const WPN_E_OUT_OF_SESSION: HRESULT = 0x803E0200; +pub const WPN_E_POWER_SAVE: HRESULT = 0x803E0201; +pub const WPN_E_IMAGE_NOT_FOUND_IN_CACHE: HRESULT = 0x803E0202; +pub const WPN_E_ALL_URL_NOT_COMPLETED: HRESULT = 0x803E0203; +pub const WPN_E_INVALID_CLOUD_IMAGE: HRESULT = 0x803E0204; +pub const WPN_E_NOTIFICATION_ID_MATCHED: HRESULT = 0x803E0205; +pub const WPN_E_CALLBACK_ALREADY_REGISTERED: HRESULT = 0x803E0206; +pub const WPN_E_TOAST_NOTIFICATION_DROPPED: HRESULT = 0x803E0207; +pub const WPN_E_STORAGE_LOCKED: HRESULT = 0x803E0208; +pub const E_MBN_CONTEXT_NOT_ACTIVATED: HRESULT = 0x80548201; +pub const E_MBN_BAD_SIM: HRESULT = 0x80548202; +pub const E_MBN_DATA_CLASS_NOT_AVAILABLE: HRESULT = 0x80548203; +pub const E_MBN_INVALID_ACCESS_STRING: HRESULT = 0x80548204; +pub const E_MBN_MAX_ACTIVATED_CONTEXTS: HRESULT = 0x80548205; +pub const E_MBN_PACKET_SVC_DETACHED: HRESULT = 0x80548206; +pub const E_MBN_PROVIDER_NOT_VISIBLE: HRESULT = 0x80548207; +pub const E_MBN_RADIO_POWER_OFF: HRESULT = 0x80548208; +pub const E_MBN_SERVICE_NOT_ACTIVATED: HRESULT = 0x80548209; +pub const E_MBN_SIM_NOT_INSERTED: HRESULT = 0x8054820A; +pub const E_MBN_VOICE_CALL_IN_PROGRESS: HRESULT = 0x8054820B; +pub const E_MBN_INVALID_CACHE: HRESULT = 0x8054820C; +pub const E_MBN_NOT_REGISTERED: HRESULT = 0x8054820D; +pub const E_MBN_PROVIDERS_NOT_FOUND: HRESULT = 0x8054820E; +pub const E_MBN_PIN_NOT_SUPPORTED: HRESULT = 0x8054820F; +pub const E_MBN_PIN_REQUIRED: HRESULT = 0x80548210; +pub const E_MBN_PIN_DISABLED: HRESULT = 0x80548211; +pub const E_MBN_FAILURE: HRESULT = 0x80548212; +pub const E_MBN_INVALID_PROFILE: HRESULT = 0x80548218; +pub const E_MBN_DEFAULT_PROFILE_EXIST: HRESULT = 0x80548219; +pub const E_MBN_SMS_ENCODING_NOT_SUPPORTED: HRESULT = 0x80548220; +pub const E_MBN_SMS_FILTER_NOT_SUPPORTED: HRESULT = 0x80548221; +pub const E_MBN_SMS_INVALID_MEMORY_INDEX: HRESULT = 0x80548222; +pub const E_MBN_SMS_LANG_NOT_SUPPORTED: HRESULT = 0x80548223; +pub const E_MBN_SMS_MEMORY_FAILURE: HRESULT = 0x80548224; +pub const E_MBN_SMS_NETWORK_TIMEOUT: HRESULT = 0x80548225; +pub const E_MBN_SMS_UNKNOWN_SMSC_ADDRESS: HRESULT = 0x80548226; +pub const E_MBN_SMS_FORMAT_NOT_SUPPORTED: HRESULT = 0x80548227; +pub const E_MBN_SMS_OPERATION_NOT_ALLOWED: HRESULT = 0x80548228; +pub const E_MBN_SMS_MEMORY_FULL: HRESULT = 0x80548229; +pub const PEER_E_IPV6_NOT_INSTALLED: HRESULT = 0x80630001; +pub const PEER_E_NOT_INITIALIZED: HRESULT = 0x80630002; +pub const PEER_E_CANNOT_START_SERVICE: HRESULT = 0x80630003; +pub const PEER_E_NOT_LICENSED: HRESULT = 0x80630004; +pub const PEER_E_INVALID_GRAPH: HRESULT = 0x80630010; +pub const PEER_E_DBNAME_CHANGED: HRESULT = 0x80630011; +pub const PEER_E_DUPLICATE_GRAPH: HRESULT = 0x80630012; +pub const PEER_E_GRAPH_NOT_READY: HRESULT = 0x80630013; +pub const PEER_E_GRAPH_SHUTTING_DOWN: HRESULT = 0x80630014; +pub const PEER_E_GRAPH_IN_USE: HRESULT = 0x80630015; +pub const PEER_E_INVALID_DATABASE: HRESULT = 0x80630016; +pub const PEER_E_TOO_MANY_ATTRIBUTES: HRESULT = 0x80630017; +pub const PEER_E_CONNECTION_NOT_FOUND: HRESULT = 0x80630103; +pub const PEER_E_CONNECT_SELF: HRESULT = 0x80630106; +pub const PEER_E_ALREADY_LISTENING: HRESULT = 0x80630107; +pub const PEER_E_NODE_NOT_FOUND: HRESULT = 0x80630108; +pub const PEER_E_CONNECTION_FAILED: HRESULT = 0x80630109; +pub const PEER_E_CONNECTION_NOT_AUTHENTICATED: HRESULT = 0x8063010A; +pub const PEER_E_CONNECTION_REFUSED: HRESULT = 0x8063010B; +pub const PEER_E_CLASSIFIER_TOO_LONG: HRESULT = 0x80630201; +pub const PEER_E_TOO_MANY_IDENTITIES: HRESULT = 0x80630202; +pub const PEER_E_NO_KEY_ACCESS: HRESULT = 0x80630203; +pub const PEER_E_GROUPS_EXIST: HRESULT = 0x80630204; +pub const PEER_E_RECORD_NOT_FOUND: HRESULT = 0x80630301; +pub const PEER_E_DATABASE_ACCESSDENIED: HRESULT = 0x80630302; +pub const PEER_E_DBINITIALIZATION_FAILED: HRESULT = 0x80630303; +pub const PEER_E_MAX_RECORD_SIZE_EXCEEDED: HRESULT = 0x80630304; +pub const PEER_E_DATABASE_ALREADY_PRESENT: HRESULT = 0x80630305; +pub const PEER_E_DATABASE_NOT_PRESENT: HRESULT = 0x80630306; +pub const PEER_E_IDENTITY_NOT_FOUND: HRESULT = 0x80630401; +pub const PEER_E_EVENT_HANDLE_NOT_FOUND: HRESULT = 0x80630501; +pub const PEER_E_INVALID_SEARCH: HRESULT = 0x80630601; +pub const PEER_E_INVALID_ATTRIBUTES: HRESULT = 0x80630602; +pub const PEER_E_INVITATION_NOT_TRUSTED: HRESULT = 0x80630701; +pub const PEER_E_CHAIN_TOO_LONG: HRESULT = 0x80630703; +pub const PEER_E_INVALID_TIME_PERIOD: HRESULT = 0x80630705; +pub const PEER_E_CIRCULAR_CHAIN_DETECTED: HRESULT = 0x80630706; +pub const PEER_E_CERT_STORE_CORRUPTED: HRESULT = 0x80630801; +pub const PEER_E_NO_CLOUD: HRESULT = 0x80631001; +pub const PEER_E_CLOUD_NAME_AMBIGUOUS: HRESULT = 0x80631005; +pub const PEER_E_INVALID_RECORD: HRESULT = 0x80632010; +pub const PEER_E_NOT_AUTHORIZED: HRESULT = 0x80632020; +pub const PEER_E_PASSWORD_DOES_NOT_MEET_POLICY: HRESULT = 0x80632021; +pub const PEER_E_DEFERRED_VALIDATION: HRESULT = 0x80632030; +pub const PEER_E_INVALID_GROUP_PROPERTIES: HRESULT = 0x80632040; +pub const PEER_E_INVALID_PEER_NAME: HRESULT = 0x80632050; +pub const PEER_E_INVALID_CLASSIFIER: HRESULT = 0x80632060; +pub const PEER_E_INVALID_FRIENDLY_NAME: HRESULT = 0x80632070; +pub const PEER_E_INVALID_ROLE_PROPERTY: HRESULT = 0x80632071; +pub const PEER_E_INVALID_CLASSIFIER_PROPERTY: HRESULT = 0x80632072; +pub const PEER_E_INVALID_RECORD_EXPIRATION: HRESULT = 0x80632080; +pub const PEER_E_INVALID_CREDENTIAL_INFO: HRESULT = 0x80632081; +pub const PEER_E_INVALID_CREDENTIAL: HRESULT = 0x80632082; +pub const PEER_E_INVALID_RECORD_SIZE: HRESULT = 0x80632083; +pub const PEER_E_UNSUPPORTED_VERSION: HRESULT = 0x80632090; +pub const PEER_E_GROUP_NOT_READY: HRESULT = 0x80632091; +pub const PEER_E_GROUP_IN_USE: HRESULT = 0x80632092; +pub const PEER_E_INVALID_GROUP: HRESULT = 0x80632093; +pub const PEER_E_NO_MEMBERS_FOUND: HRESULT = 0x80632094; +pub const PEER_E_NO_MEMBER_CONNECTIONS: HRESULT = 0x80632095; +pub const PEER_E_UNABLE_TO_LISTEN: HRESULT = 0x80632096; +pub const PEER_E_IDENTITY_DELETED: HRESULT = 0x806320A0; +pub const PEER_E_SERVICE_NOT_AVAILABLE: HRESULT = 0x806320A1; +pub const PEER_E_CONTACT_NOT_FOUND: HRESULT = 0x80636001; +pub const PEER_S_GRAPH_DATA_CREATED: HRESULT = 0x00630001; +pub const PEER_S_NO_EVENT_DATA: HRESULT = 0x00630002; +pub const PEER_S_ALREADY_CONNECTED: HRESULT = 0x00632000; +pub const PEER_S_SUBSCRIPTION_EXISTS: HRESULT = 0x00636000; +pub const PEER_S_NO_CONNECTIVITY: HRESULT = 0x00630005; +pub const PEER_S_ALREADY_A_MEMBER: HRESULT = 0x00630006; +pub const PEER_E_CANNOT_CONVERT_PEER_NAME: HRESULT = 0x80634001; +pub const PEER_E_INVALID_PEER_HOST_NAME: HRESULT = 0x80634002; +pub const PEER_E_NO_MORE: HRESULT = 0x80634003; +pub const PEER_E_PNRP_DUPLICATE_PEER_NAME: HRESULT = 0x80634005; +pub const PEER_E_INVITE_CANCELLED: HRESULT = 0x80637000; +pub const PEER_E_INVITE_RESPONSE_NOT_AVAILABLE: HRESULT = 0x80637001; +pub const PEER_E_NOT_SIGNED_IN: HRESULT = 0x80637003; +pub const PEER_E_PRIVACY_DECLINED: HRESULT = 0x80637004; +pub const PEER_E_TIMEOUT: HRESULT = 0x80637005; +pub const PEER_E_INVALID_ADDRESS: HRESULT = 0x80637007; +pub const PEER_E_FW_EXCEPTION_DISABLED: HRESULT = 0x80637008; +pub const PEER_E_FW_BLOCKED_BY_POLICY: HRESULT = 0x80637009; +pub const PEER_E_FW_BLOCKED_BY_SHIELDS_UP: HRESULT = 0x8063700A; +pub const PEER_E_FW_DECLINED: HRESULT = 0x8063700B; +pub const UI_E_CREATE_FAILED: HRESULT = 0x802A0001; +pub const UI_E_SHUTDOWN_CALLED: HRESULT = 0x802A0002; +pub const UI_E_ILLEGAL_REENTRANCY: HRESULT = 0x802A0003; +pub const UI_E_OBJECT_SEALED: HRESULT = 0x802A0004; +pub const UI_E_VALUE_NOT_SET: HRESULT = 0x802A0005; +pub const UI_E_VALUE_NOT_DETERMINED: HRESULT = 0x802A0006; +pub const UI_E_INVALID_OUTPUT: HRESULT = 0x802A0007; +pub const UI_E_BOOLEAN_EXPECTED: HRESULT = 0x802A0008; +pub const UI_E_DIFFERENT_OWNER: HRESULT = 0x802A0009; +pub const UI_E_AMBIGUOUS_MATCH: HRESULT = 0x802A000A; +pub const UI_E_FP_OVERFLOW: HRESULT = 0x802A000B; +pub const UI_E_WRONG_THREAD: HRESULT = 0x802A000C; +pub const UI_E_STORYBOARD_ACTIVE: HRESULT = 0x802A0101; +pub const UI_E_STORYBOARD_NOT_PLAYING: HRESULT = 0x802A0102; +pub const UI_E_START_KEYFRAME_AFTER_END: HRESULT = 0x802A0103; +pub const UI_E_END_KEYFRAME_NOT_DETERMINED: HRESULT = 0x802A0104; +pub const UI_E_LOOPS_OVERLAP: HRESULT = 0x802A0105; +pub const UI_E_TRANSITION_ALREADY_USED: HRESULT = 0x802A0106; +pub const UI_E_TRANSITION_NOT_IN_STORYBOARD: HRESULT = 0x802A0107; +pub const UI_E_TRANSITION_ECLIPSED: HRESULT = 0x802A0108; +pub const UI_E_TIME_BEFORE_LAST_UPDATE: HRESULT = 0x802A0109; +pub const UI_E_TIMER_CLIENT_ALREADY_CONNECTED: HRESULT = 0x802A010A; +pub const UI_E_INVALID_DIMENSION: HRESULT = 0x802A010B; +pub const UI_E_PRIMITIVE_OUT_OF_BOUNDS: HRESULT = 0x802A010C; +pub const UI_E_WINDOW_CLOSED: HRESULT = 0x802A0201; +pub const E_BLUETOOTH_ATT_INVALID_HANDLE: HRESULT = 0x80650001; +pub const E_BLUETOOTH_ATT_READ_NOT_PERMITTED: HRESULT = 0x80650002; +pub const E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED: HRESULT = 0x80650003; +pub const E_BLUETOOTH_ATT_INVALID_PDU: HRESULT = 0x80650004; +pub const E_BLUETOOTH_ATT_INSUFFICIENT_AUTHENTICATION: HRESULT = 0x80650005; +pub const E_BLUETOOTH_ATT_REQUEST_NOT_SUPPORTED: HRESULT = 0x80650006; +pub const E_BLUETOOTH_ATT_INVALID_OFFSET: HRESULT = 0x80650007; +pub const E_BLUETOOTH_ATT_INSUFFICIENT_AUTHORIZATION: HRESULT = 0x80650008; +pub const E_BLUETOOTH_ATT_PREPARE_QUEUE_FULL: HRESULT = 0x80650009; +pub const E_BLUETOOTH_ATT_ATTRIBUTE_NOT_FOUND: HRESULT = 0x8065000A; +pub const E_BLUETOOTH_ATT_ATTRIBUTE_NOT_LONG: HRESULT = 0x8065000B; +pub const E_BLUETOOTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE: HRESULT = 0x8065000C; +pub const E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH: HRESULT = 0x8065000D; +pub const E_BLUETOOTH_ATT_UNLIKELY: HRESULT = 0x8065000E; +pub const E_BLUETOOTH_ATT_INSUFFICIENT_ENCRYPTION: HRESULT = 0x8065000F; +pub const E_BLUETOOTH_ATT_UNSUPPORTED_GROUP_TYPE: HRESULT = 0x80650010; +pub const E_BLUETOOTH_ATT_INSUFFICIENT_RESOURCES: HRESULT = 0x80650011; +pub const E_BLUETOOTH_ATT_UNKNOWN_ERROR: HRESULT = 0x80651000; +pub const E_AUDIO_ENGINE_NODE_NOT_FOUND: HRESULT = 0x80660001; +pub const E_HDAUDIO_EMPTY_CONNECTION_LIST: HRESULT = 0x80660002; +pub const E_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED: HRESULT = 0x80660003; +pub const E_HDAUDIO_NO_LOGICAL_DEVICES_CREATED: HRESULT = 0x80660004; +pub const E_HDAUDIO_NULL_LINKED_LIST_ENTRY: HRESULT = 0x80660005; +pub const ERROR_SPACES_POOL_WAS_DELETED: HRESULT = 0x00E70001; +pub const ERROR_SPACES_RESILIENCY_TYPE_INVALID: HRESULT = 0x80E70003; +pub const ERROR_SPACES_DRIVE_SECTOR_SIZE_INVALID: HRESULT = 0x80E70004; +pub const ERROR_SPACES_DRIVE_REDUNDANCY_INVALID: HRESULT = 0x80E70006; +pub const ERROR_SPACES_NUMBER_OF_DATA_COPIES_INVALID: HRESULT = 0x80E70007; +pub const ERROR_SPACES_PARITY_LAYOUT_INVALID: HRESULT = 0x80E70008; +pub const ERROR_SPACES_INTERLEAVE_LENGTH_INVALID: HRESULT = 0x80E70009; +pub const ERROR_SPACES_NUMBER_OF_COLUMNS_INVALID: HRESULT = 0x80E7000A; +pub const ERROR_SPACES_NOT_ENOUGH_DRIVES: HRESULT = 0x80E7000B; +pub const ERROR_VOLSNAP_BOOTFILE_NOT_VALID: HRESULT = 0x80820001; +pub const ERROR_TIERING_NOT_SUPPORTED_ON_VOLUME: HRESULT = 0x80830001; +pub const ERROR_TIERING_VOLUME_DISMOUNT_IN_PROGRESS: HRESULT = 0x80830002; +pub const ERROR_TIERING_STORAGE_TIER_NOT_FOUND: HRESULT = 0x80830003; +pub const ERROR_TIERING_INVALID_FILE_ID: HRESULT = 0x80830004; +pub const ERROR_TIERING_WRONG_CLUSTER_NODE: HRESULT = 0x80830005; +pub const ERROR_TIERING_ALREADY_PROCESSING: HRESULT = 0x80830006; +pub const ERROR_TIERING_CANNOT_PIN_OBJECT: HRESULT = 0x80830007; +pub const DXGI_STATUS_OCCLUDED: HRESULT = 0x087A0001; +pub const DXGI_STATUS_CLIPPED: HRESULT = 0x087A0002; +pub const DXGI_STATUS_NO_REDIRECTION: HRESULT = 0x087A0004; +pub const DXGI_STATUS_NO_DESKTOP_ACCESS: HRESULT = 0x087A0005; +pub const DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: HRESULT = 0x087A0006; +pub const DXGI_STATUS_MODE_CHANGED: HRESULT = 0x087A0007; +pub const DXGI_STATUS_MODE_CHANGE_IN_PROGRESS: HRESULT = 0x087A0008; +pub const DXGI_ERROR_INVALID_CALL: HRESULT = 0x887A0001; +pub const DXGI_ERROR_NOT_FOUND: HRESULT = 0x887A0002; +pub const DXGI_ERROR_MORE_DATA: HRESULT = 0x887A0003; +pub const DXGI_ERROR_UNSUPPORTED: HRESULT = 0x887A0004; +pub const DXGI_ERROR_DEVICE_REMOVED: HRESULT = 0x887A0005; +pub const DXGI_ERROR_DEVICE_HUNG: HRESULT = 0x887A0006; +pub const DXGI_ERROR_DEVICE_RESET: HRESULT = 0x887A0007; +pub const DXGI_ERROR_WAS_STILL_DRAWING: HRESULT = 0x887A000A; +pub const DXGI_ERROR_FRAME_STATISTICS_DISJOINT: HRESULT = 0x887A000B; +pub const DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE: HRESULT = 0x887A000C; +pub const DXGI_ERROR_DRIVER_INTERNAL_ERROR: HRESULT = 0x887A0020; +pub const DXGI_ERROR_NONEXCLUSIVE: HRESULT = 0x887A0021; +pub const DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: HRESULT = 0x887A0022; +pub const DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED: HRESULT = 0x887A0023; +pub const DXGI_ERROR_REMOTE_OUTOFMEMORY: HRESULT = 0x887A0024; +pub const DXGI_ERROR_ACCESS_LOST: HRESULT = 0x887A0026; +pub const DXGI_ERROR_WAIT_TIMEOUT: HRESULT = 0x887A0027; +pub const DXGI_ERROR_SESSION_DISCONNECTED: HRESULT = 0x887A0028; +pub const DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE: HRESULT = 0x887A0029; +pub const DXGI_ERROR_CANNOT_PROTECT_CONTENT: HRESULT = 0x887A002A; +pub const DXGI_ERROR_ACCESS_DENIED: HRESULT = 0x887A002B; +pub const DXGI_ERROR_NAME_ALREADY_EXISTS: HRESULT = 0x887A002C; +pub const DXGI_ERROR_SDK_COMPONENT_MISSING: HRESULT = 0x887A002D; +pub const DXGI_STATUS_UNOCCLUDED: HRESULT = 0x087A0009; +pub const DXGI_STATUS_DDA_WAS_STILL_DRAWING: HRESULT = 0x087A000A; +pub const DXGI_ERROR_MODE_CHANGE_IN_PROGRESS: HRESULT = 0x887A0025; +pub const DXGI_DDI_ERR_WASSTILLDRAWING: HRESULT = 0x887B0001; +pub const DXGI_DDI_ERR_UNSUPPORTED: HRESULT = 0x887B0002; +pub const DXGI_DDI_ERR_NONEXCLUSIVE: HRESULT = 0x887B0003; +pub const D3D10_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS: HRESULT = 0x88790001; +pub const D3D10_ERROR_FILE_NOT_FOUND: HRESULT = 0x88790002; +pub const D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS: HRESULT = 0x887C0001; +pub const D3D11_ERROR_FILE_NOT_FOUND: HRESULT = 0x887C0002; +pub const D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS: HRESULT = 0x887C0003; +pub const D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD: HRESULT + = 0x887C0004; +pub const D2DERR_WRONG_STATE: HRESULT = 0x88990001; +pub const D2DERR_NOT_INITIALIZED: HRESULT = 0x88990002; +pub const D2DERR_UNSUPPORTED_OPERATION: HRESULT = 0x88990003; +pub const D2DERR_SCANNER_FAILED: HRESULT = 0x88990004; +pub const D2DERR_SCREEN_ACCESS_DENIED: HRESULT = 0x88990005; +pub const D2DERR_DISPLAY_STATE_INVALID: HRESULT = 0x88990006; +pub const D2DERR_ZERO_VECTOR: HRESULT = 0x88990007; +pub const D2DERR_INTERNAL_ERROR: HRESULT = 0x88990008; +pub const D2DERR_DISPLAY_FORMAT_NOT_SUPPORTED: HRESULT = 0x88990009; +pub const D2DERR_INVALID_CALL: HRESULT = 0x8899000A; +pub const D2DERR_NO_HARDWARE_DEVICE: HRESULT = 0x8899000B; +pub const D2DERR_RECREATE_TARGET: HRESULT = 0x8899000C; +pub const D2DERR_TOO_MANY_SHADER_ELEMENTS: HRESULT = 0x8899000D; +pub const D2DERR_SHADER_COMPILE_FAILED: HRESULT = 0x8899000E; +pub const D2DERR_MAX_TEXTURE_SIZE_EXCEEDED: HRESULT = 0x8899000F; +pub const D2DERR_UNSUPPORTED_VERSION: HRESULT = 0x88990010; +pub const D2DERR_BAD_NUMBER: HRESULT = 0x88990011; +pub const D2DERR_WRONG_FACTORY: HRESULT = 0x88990012; +pub const D2DERR_LAYER_ALREADY_IN_USE: HRESULT = 0x88990013; +pub const D2DERR_POP_CALL_DID_NOT_MATCH_PUSH: HRESULT = 0x88990014; +pub const D2DERR_WRONG_RESOURCE_DOMAIN: HRESULT = 0x88990015; +pub const D2DERR_PUSH_POP_UNBALANCED: HRESULT = 0x88990016; +pub const D2DERR_RENDER_TARGET_HAS_LAYER_OR_CLIPRECT: HRESULT = 0x88990017; +pub const D2DERR_INCOMPATIBLE_BRUSH_TYPES: HRESULT = 0x88990018; +pub const D2DERR_WIN32_ERROR: HRESULT = 0x88990019; +pub const D2DERR_TARGET_NOT_GDI_COMPATIBLE: HRESULT = 0x8899001A; +pub const D2DERR_TEXT_EFFECT_IS_WRONG_TYPE: HRESULT = 0x8899001B; +pub const D2DERR_TEXT_RENDERER_NOT_RELEASED: HRESULT = 0x8899001C; +pub const D2DERR_EXCEEDS_MAX_BITMAP_SIZE: HRESULT = 0x8899001D; +pub const D2DERR_INVALID_GRAPH_CONFIGURATION: HRESULT = 0x8899001E; +pub const D2DERR_INVALID_INTERNAL_GRAPH_CONFIGURATION: HRESULT = 0x8899001F; +pub const D2DERR_CYCLIC_GRAPH: HRESULT = 0x88990020; +pub const D2DERR_BITMAP_CANNOT_DRAW: HRESULT = 0x88990021; +pub const D2DERR_OUTSTANDING_BITMAP_REFERENCES: HRESULT = 0x88990022; +pub const D2DERR_ORIGINAL_TARGET_NOT_BOUND: HRESULT = 0x88990023; +pub const D2DERR_INVALID_TARGET: HRESULT = 0x88990024; +pub const D2DERR_BITMAP_BOUND_AS_TARGET: HRESULT = 0x88990025; +pub const D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES: HRESULT = 0x88990026; +pub const D2DERR_INTERMEDIATE_TOO_LARGE: HRESULT = 0x88990027; +pub const D2DERR_EFFECT_IS_NOT_REGISTERED: HRESULT = 0x88990028; +pub const D2DERR_INVALID_PROPERTY: HRESULT = 0x88990029; +pub const D2DERR_NO_SUBPROPERTIES: HRESULT = 0x8899002A; +pub const D2DERR_PRINT_JOB_CLOSED: HRESULT = 0x8899002B; +pub const D2DERR_PRINT_FORMAT_NOT_SUPPORTED: HRESULT = 0x8899002C; +pub const D2DERR_TOO_MANY_TRANSFORM_INPUTS: HRESULT = 0x8899002D; +pub const DWRITE_E_FILEFORMAT: HRESULT = 0x88985000; +pub const DWRITE_E_UNEXPECTED: HRESULT = 0x88985001; +pub const DWRITE_E_NOFONT: HRESULT = 0x88985002; +pub const DWRITE_E_FILENOTFOUND: HRESULT = 0x88985003; +pub const DWRITE_E_FILEACCESS: HRESULT = 0x88985004; +pub const DWRITE_E_FONTCOLLECTIONOBSOLETE: HRESULT = 0x88985005; +pub const DWRITE_E_ALREADYREGISTERED: HRESULT = 0x88985006; +pub const DWRITE_E_CACHEFORMAT: HRESULT = 0x88985007; +pub const DWRITE_E_CACHEVERSION: HRESULT = 0x88985008; +pub const DWRITE_E_UNSUPPORTEDOPERATION: HRESULT = 0x88985009; +pub const DWRITE_E_TEXTRENDERERINCOMPATIBLE: HRESULT = 0x8898500A; +pub const DWRITE_E_FLOWDIRECTIONCONFLICTS: HRESULT = 0x8898500B; +pub const DWRITE_E_NOCOLOR: HRESULT = 0x8898500C; +pub const WINCODEC_ERR_WRONGSTATE: HRESULT = 0x88982F04; +pub const WINCODEC_ERR_VALUEOUTOFRANGE: HRESULT = 0x88982F05; +pub const WINCODEC_ERR_UNKNOWNIMAGEFORMAT: HRESULT = 0x88982F07; +pub const WINCODEC_ERR_UNSUPPORTEDVERSION: HRESULT = 0x88982F0B; +pub const WINCODEC_ERR_NOTINITIALIZED: HRESULT = 0x88982F0C; +pub const WINCODEC_ERR_ALREADYLOCKED: HRESULT = 0x88982F0D; +pub const WINCODEC_ERR_PROPERTYNOTFOUND: HRESULT = 0x88982F40; +pub const WINCODEC_ERR_PROPERTYNOTSUPPORTED: HRESULT = 0x88982F41; +pub const WINCODEC_ERR_PROPERTYSIZE: HRESULT = 0x88982F42; +pub const WINCODEC_ERR_CODECPRESENT: HRESULT = 0x88982F43; +pub const WINCODEC_ERR_CODECNOTHUMBNAIL: HRESULT = 0x88982F44; +pub const WINCODEC_ERR_PALETTEUNAVAILABLE: HRESULT = 0x88982F45; +pub const WINCODEC_ERR_CODECTOOMANYSCANLINES: HRESULT = 0x88982F46; +pub const WINCODEC_ERR_INTERNALERROR: HRESULT = 0x88982F48; +pub const WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS: HRESULT = 0x88982F49; +pub const WINCODEC_ERR_COMPONENTNOTFOUND: HRESULT = 0x88982F50; +pub const WINCODEC_ERR_IMAGESIZEOUTOFRANGE: HRESULT = 0x88982F51; +pub const WINCODEC_ERR_TOOMUCHMETADATA: HRESULT = 0x88982F52; +pub const WINCODEC_ERR_BADIMAGE: HRESULT = 0x88982F60; +pub const WINCODEC_ERR_BADHEADER: HRESULT = 0x88982F61; +pub const WINCODEC_ERR_FRAMEMISSING: HRESULT = 0x88982F62; +pub const WINCODEC_ERR_BADMETADATAHEADER: HRESULT = 0x88982F63; +pub const WINCODEC_ERR_BADSTREAMDATA: HRESULT = 0x88982F70; +pub const WINCODEC_ERR_STREAMWRITE: HRESULT = 0x88982F71; +pub const WINCODEC_ERR_STREAMREAD: HRESULT = 0x88982F72; +pub const WINCODEC_ERR_STREAMNOTAVAILABLE: HRESULT = 0x88982F73; +pub const WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT: HRESULT = 0x88982F80; +pub const WINCODEC_ERR_UNSUPPORTEDOPERATION: HRESULT = 0x88982F81; +pub const WINCODEC_ERR_INVALIDREGISTRATION: HRESULT = 0x88982F8A; +pub const WINCODEC_ERR_COMPONENTINITIALIZEFAILURE: HRESULT = 0x88982F8B; +pub const WINCODEC_ERR_INSUFFICIENTBUFFER: HRESULT = 0x88982F8C; +pub const WINCODEC_ERR_DUPLICATEMETADATAPRESENT: HRESULT = 0x88982F8D; +pub const WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE: HRESULT = 0x88982F8E; +pub const WINCODEC_ERR_UNEXPECTEDSIZE: HRESULT = 0x88982F8F; +pub const WINCODEC_ERR_INVALIDQUERYREQUEST: HRESULT = 0x88982F90; +pub const WINCODEC_ERR_UNEXPECTEDMETADATATYPE: HRESULT = 0x88982F91; +pub const WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT: HRESULT = 0x88982F92; +pub const WINCODEC_ERR_INVALIDQUERYCHARACTER: HRESULT = 0x88982F93; +pub const WINCODEC_ERR_WIN32ERROR: HRESULT = 0x88982F94; +pub const WINCODEC_ERR_INVALIDPROGRESSIVELEVEL: HRESULT = 0x88982F95; +pub const MILERR_OBJECTBUSY: HRESULT = 0x88980001; +pub const MILERR_INSUFFICIENTBUFFER: HRESULT = 0x88980002; +pub const MILERR_WIN32ERROR: HRESULT = 0x88980003; +pub const MILERR_SCANNER_FAILED: HRESULT = 0x88980004; +pub const MILERR_SCREENACCESSDENIED: HRESULT = 0x88980005; +pub const MILERR_DISPLAYSTATEINVALID: HRESULT = 0x88980006; +pub const MILERR_NONINVERTIBLEMATRIX: HRESULT = 0x88980007; +pub const MILERR_ZEROVECTOR: HRESULT = 0x88980008; +pub const MILERR_TERMINATED: HRESULT = 0x88980009; +pub const MILERR_BADNUMBER: HRESULT = 0x8898000A; +pub const MILERR_INTERNALERROR: HRESULT = 0x88980080; +pub const MILERR_DISPLAYFORMATNOTSUPPORTED: HRESULT = 0x88980084; +pub const MILERR_INVALIDCALL: HRESULT = 0x88980085; +pub const MILERR_ALREADYLOCKED: HRESULT = 0x88980086; +pub const MILERR_NOTLOCKED: HRESULT = 0x88980087; +pub const MILERR_DEVICECANNOTRENDERTEXT: HRESULT = 0x88980088; +pub const MILERR_GLYPHBITMAPMISSED: HRESULT = 0x88980089; +pub const MILERR_MALFORMEDGLYPHCACHE: HRESULT = 0x8898008A; +pub const MILERR_GENERIC_IGNORE: HRESULT = 0x8898008B; +pub const MILERR_MALFORMED_GUIDELINE_DATA: HRESULT = 0x8898008C; +pub const MILERR_NO_HARDWARE_DEVICE: HRESULT = 0x8898008D; +pub const MILERR_NEED_RECREATE_AND_PRESENT: HRESULT = 0x8898008E; +pub const MILERR_ALREADY_INITIALIZED: HRESULT = 0x8898008F; +pub const MILERR_MISMATCHED_SIZE: HRESULT = 0x88980090; +pub const MILERR_NO_REDIRECTION_SURFACE_AVAILABLE: HRESULT = 0x88980091; +pub const MILERR_REMOTING_NOT_SUPPORTED: HRESULT = 0x88980092; +pub const MILERR_QUEUED_PRESENT_NOT_SUPPORTED: HRESULT = 0x88980093; +pub const MILERR_NOT_QUEUING_PRESENTS: HRESULT = 0x88980094; +pub const MILERR_NO_REDIRECTION_SURFACE_RETRY_LATER: HRESULT = 0x88980095; +pub const MILERR_TOOMANYSHADERELEMNTS: HRESULT = 0x88980096; +pub const MILERR_MROW_READLOCK_FAILED: HRESULT = 0x88980097; +pub const MILERR_MROW_UPDATE_FAILED: HRESULT = 0x88980098; +pub const MILERR_SHADER_COMPILE_FAILED: HRESULT = 0x88980099; +pub const MILERR_MAX_TEXTURE_SIZE_EXCEEDED: HRESULT = 0x8898009A; +pub const MILERR_QPC_TIME_WENT_BACKWARD: HRESULT = 0x8898009B; +pub const MILERR_DXGI_ENUMERATION_OUT_OF_SYNC: HRESULT = 0x8898009D; +pub const MILERR_ADAPTER_NOT_FOUND: HRESULT = 0x8898009E; +pub const MILERR_COLORSPACE_NOT_SUPPORTED: HRESULT = 0x8898009F; +pub const MILERR_PREFILTER_NOT_SUPPORTED: HRESULT = 0x889800A0; +pub const MILERR_DISPLAYID_ACCESS_DENIED: HRESULT = 0x889800A1; +pub const UCEERR_INVALIDPACKETHEADER: HRESULT = 0x88980400; +pub const UCEERR_UNKNOWNPACKET: HRESULT = 0x88980401; +pub const UCEERR_ILLEGALPACKET: HRESULT = 0x88980402; +pub const UCEERR_MALFORMEDPACKET: HRESULT = 0x88980403; +pub const UCEERR_ILLEGALHANDLE: HRESULT = 0x88980404; +pub const UCEERR_HANDLELOOKUPFAILED: HRESULT = 0x88980405; +pub const UCEERR_RENDERTHREADFAILURE: HRESULT = 0x88980406; +pub const UCEERR_CTXSTACKFRSTTARGETNULL: HRESULT = 0x88980407; +pub const UCEERR_CONNECTIONIDLOOKUPFAILED: HRESULT = 0x88980408; +pub const UCEERR_BLOCKSFULL: HRESULT = 0x88980409; +pub const UCEERR_MEMORYFAILURE: HRESULT = 0x8898040A; +pub const UCEERR_PACKETRECORDOUTOFRANGE: HRESULT = 0x8898040B; +pub const UCEERR_ILLEGALRECORDTYPE: HRESULT = 0x8898040C; +pub const UCEERR_OUTOFHANDLES: HRESULT = 0x8898040D; +pub const UCEERR_UNCHANGABLE_UPDATE_ATTEMPTED: HRESULT = 0x8898040E; +pub const UCEERR_NO_MULTIPLE_WORKER_THREADS: HRESULT = 0x8898040F; +pub const UCEERR_REMOTINGNOTSUPPORTED: HRESULT = 0x88980410; +pub const UCEERR_MISSINGENDCOMMAND: HRESULT = 0x88980411; +pub const UCEERR_MISSINGBEGINCOMMAND: HRESULT = 0x88980412; +pub const UCEERR_CHANNELSYNCTIMEDOUT: HRESULT = 0x88980413; +pub const UCEERR_CHANNELSYNCABANDONED: HRESULT = 0x88980414; +pub const UCEERR_UNSUPPORTEDTRANSPORTVERSION: HRESULT = 0x88980415; +pub const UCEERR_TRANSPORTUNAVAILABLE: HRESULT = 0x88980416; +pub const UCEERR_FEEDBACK_UNSUPPORTED: HRESULT = 0x88980417; +pub const UCEERR_COMMANDTRANSPORTDENIED: HRESULT = 0x88980418; +pub const UCEERR_GRAPHICSSTREAMUNAVAILABLE: HRESULT = 0x88980419; +pub const UCEERR_GRAPHICSSTREAMALREADYOPEN: HRESULT = 0x88980420; +pub const UCEERR_TRANSPORTDISCONNECTED: HRESULT = 0x88980421; +pub const UCEERR_TRANSPORTOVERLOADED: HRESULT = 0x88980422; +pub const UCEERR_PARTITION_ZOMBIED: HRESULT = 0x88980423; +pub const MILAVERR_NOCLOCK: HRESULT = 0x88980500; +pub const MILAVERR_NOMEDIATYPE: HRESULT = 0x88980501; +pub const MILAVERR_NOVIDEOMIXER: HRESULT = 0x88980502; +pub const MILAVERR_NOVIDEOPRESENTER: HRESULT = 0x88980503; +pub const MILAVERR_NOREADYFRAMES: HRESULT = 0x88980504; +pub const MILAVERR_MODULENOTLOADED: HRESULT = 0x88980505; +pub const MILAVERR_WMPFACTORYNOTREGISTERED: HRESULT = 0x88980506; +pub const MILAVERR_INVALIDWMPVERSION: HRESULT = 0x88980507; +pub const MILAVERR_INSUFFICIENTVIDEORESOURCES: HRESULT = 0x88980508; +pub const MILAVERR_VIDEOACCELERATIONNOTAVAILABLE: HRESULT = 0x88980509; +pub const MILAVERR_REQUESTEDTEXTURETOOBIG: HRESULT = 0x8898050A; +pub const MILAVERR_SEEKFAILED: HRESULT = 0x8898050B; +pub const MILAVERR_UNEXPECTEDWMPFAILURE: HRESULT = 0x8898050C; +pub const MILAVERR_MEDIAPLAYERCLOSED: HRESULT = 0x8898050D; +pub const MILAVERR_UNKNOWNHARDWAREERROR: HRESULT = 0x8898050E; +pub const MILEFFECTSERR_UNKNOWNPROPERTY: HRESULT = 0x8898060E; +pub const MILEFFECTSERR_EFFECTNOTPARTOFGROUP: HRESULT = 0x8898060F; +pub const MILEFFECTSERR_NOINPUTSOURCEATTACHED: HRESULT = 0x88980610; +pub const MILEFFECTSERR_CONNECTORNOTCONNECTED: HRESULT = 0x88980611; +pub const MILEFFECTSERR_CONNECTORNOTASSOCIATEDWITHEFFECT: HRESULT = 0x88980612; +pub const MILEFFECTSERR_RESERVED: HRESULT = 0x88980613; +pub const MILEFFECTSERR_CYCLEDETECTED: HRESULT = 0x88980614; +pub const MILEFFECTSERR_EFFECTINMORETHANONEGRAPH: HRESULT = 0x88980615; +pub const MILEFFECTSERR_EFFECTALREADYINAGRAPH: HRESULT = 0x88980616; +pub const MILEFFECTSERR_EFFECTHASNOCHILDREN: HRESULT = 0x88980617; +pub const MILEFFECTSERR_ALREADYATTACHEDTOLISTENER: HRESULT = 0x88980618; +pub const MILEFFECTSERR_NOTAFFINETRANSFORM: HRESULT = 0x88980619; +pub const MILEFFECTSERR_EMPTYBOUNDS: HRESULT = 0x8898061A; +pub const MILEFFECTSERR_OUTPUTSIZETOOLARGE: HRESULT = 0x8898061B; +pub const DWMERR_STATE_TRANSITION_FAILED: HRESULT = 0x88980700; +pub const DWMERR_THEME_FAILED: HRESULT = 0x88980701; +pub const DWMERR_CATASTROPHIC_FAILURE: HRESULT = 0x88980702; +pub const DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED: HRESULT = 0x88980800; +pub const DCOMPOSITION_ERROR_SURFACE_BEING_RENDERED: HRESULT = 0x88980801; +pub const DCOMPOSITION_ERROR_SURFACE_NOT_BEING_RENDERED: HRESULT = 0x88980802; +pub const ONL_E_INVALID_AUTHENTICATION_TARGET: HRESULT = 0x80860001; +pub const ONL_E_ACCESS_DENIED_BY_TOU: HRESULT = 0x80860002; +pub const ONL_E_INVALID_APPLICATION: HRESULT = 0x80860003; +pub const ONL_E_PASSWORD_UPDATE_REQUIRED: HRESULT = 0x80860004; +pub const ONL_E_ACCOUNT_UPDATE_REQUIRED: HRESULT = 0x80860005; +pub const ONL_E_FORCESIGNIN: HRESULT = 0x80860006; +pub const ONL_E_ACCOUNT_LOCKED: HRESULT = 0x80860007; +pub const ONL_E_PARENTAL_CONSENT_REQUIRED: HRESULT = 0x80860008; +pub const ONL_E_EMAIL_VERIFICATION_REQUIRED: HRESULT = 0x80860009; +pub const ONL_E_ACCOUNT_SUSPENDED_COMPROIMISE: HRESULT = 0x8086000A; +pub const ONL_E_ACCOUNT_SUSPENDED_ABUSE: HRESULT = 0x8086000B; +pub const ONL_E_ACTION_REQUIRED: HRESULT = 0x8086000C; +pub const ONL_CONNECTION_COUNT_LIMIT: HRESULT = 0x8086000D; +pub const ONL_E_CONNECTED_ACCOUNT_CAN_NOT_SIGNOUT: HRESULT = 0x8086000E; +pub const ONL_E_USER_AUTHENTICATION_REQUIRED: HRESULT = 0x8086000F; +pub const ONL_E_REQUEST_THROTTLED: HRESULT = 0x80860010; +pub const FA_E_MAX_PERSISTED_ITEMS_REACHED: HRESULT = 0x80270220; +pub const FA_E_HOMEGROUP_NOT_AVAILABLE: HRESULT = 0x80270222; +pub const E_MONITOR_RESOLUTION_TOO_LOW: HRESULT = 0x80270250; +pub const E_ELEVATED_ACTIVATION_NOT_SUPPORTED: HRESULT = 0x80270251; +pub const E_UAC_DISABLED: HRESULT = 0x80270252; +pub const E_FULL_ADMIN_NOT_SUPPORTED: HRESULT = 0x80270253; +pub const E_APPLICATION_NOT_REGISTERED: HRESULT = 0x80270254; +pub const E_MULTIPLE_EXTENSIONS_FOR_APPLICATION: HRESULT = 0x80270255; +pub const E_MULTIPLE_PACKAGES_FOR_FAMILY: HRESULT = 0x80270256; +pub const E_APPLICATION_MANAGER_NOT_RUNNING: HRESULT = 0x80270257; +pub const S_STORE_LAUNCHED_FOR_REMEDIATION: HRESULT = 0x00270258; +pub const S_APPLICATION_ACTIVATION_ERROR_HANDLED_BY_DIALOG: HRESULT = 0x00270259; +pub const E_APPLICATION_ACTIVATION_TIMED_OUT: HRESULT = 0x8027025A; +pub const E_APPLICATION_ACTIVATION_EXEC_FAILURE: HRESULT = 0x8027025B; +pub const E_APPLICATION_TEMPORARY_LICENSE_ERROR: HRESULT = 0x8027025C; +pub const E_APPLICATION_TRIAL_LICENSE_EXPIRED: HRESULT = 0x8027025D; +pub const E_SKYDRIVE_ROOT_TARGET_FILE_SYSTEM_NOT_SUPPORTED: HRESULT = 0x80270260; +pub const E_SKYDRIVE_ROOT_TARGET_OVERLAP: HRESULT = 0x80270261; +pub const E_SKYDRIVE_ROOT_TARGET_CANNOT_INDEX: HRESULT = 0x80270262; +pub const E_SKYDRIVE_FILE_NOT_UPLOADED: HRESULT = 0x80270263; +pub const E_SKYDRIVE_UPDATE_AVAILABILITY_FAIL: HRESULT = 0x80270264; +pub const E_SKYDRIVE_ROOT_TARGET_VOLUME_ROOT_NOT_SUPPORTED: HRESULT = 0x80270265; +pub const E_SYNCENGINE_FILE_SIZE_OVER_LIMIT: HRESULT = 0x8802B001; +pub const E_SYNCENGINE_FILE_SIZE_EXCEEDS_REMAINING_QUOTA: HRESULT = 0x8802B002; +pub const E_SYNCENGINE_UNSUPPORTED_FILE_NAME: HRESULT = 0x8802B003; +pub const E_SYNCENGINE_FOLDER_ITEM_COUNT_LIMIT_EXCEEDED: HRESULT = 0x8802B004; +pub const E_SYNCENGINE_FILE_SYNC_PARTNER_ERROR: HRESULT = 0x8802B005; +pub const E_SYNCENGINE_SYNC_PAUSED_BY_SERVICE: HRESULT = 0x8802B006; +pub const E_SYNCENGINE_FILE_IDENTIFIER_UNKNOWN: HRESULT = 0x8802C002; +pub const E_SYNCENGINE_SERVICE_AUTHENTICATION_FAILED: HRESULT = 0x8802C003; +pub const E_SYNCENGINE_UNKNOWN_SERVICE_ERROR: HRESULT = 0x8802C004; +pub const E_SYNCENGINE_SERVICE_RETURNED_UNEXPECTED_SIZE: HRESULT = 0x8802C005; +pub const E_SYNCENGINE_REQUEST_BLOCKED_BY_SERVICE: HRESULT = 0x8802C006; +pub const E_SYNCENGINE_REQUEST_BLOCKED_DUE_TO_CLIENT_ERROR: HRESULT = 0x8802C007; +pub const E_SYNCENGINE_FOLDER_INACCESSIBLE: HRESULT = 0x8802D001; +pub const E_SYNCENGINE_UNSUPPORTED_FOLDER_NAME: HRESULT = 0x8802D002; +pub const E_SYNCENGINE_UNSUPPORTED_MARKET: HRESULT = 0x8802D003; +pub const E_SYNCENGINE_PATH_LENGTH_LIMIT_EXCEEDED: HRESULT = 0x8802D004; +pub const E_SYNCENGINE_REMOTE_PATH_LENGTH_LIMIT_EXCEEDED: HRESULT = 0x8802D005; +pub const E_SYNCENGINE_CLIENT_UPDATE_NEEDED: HRESULT = 0x8802D006; +pub const E_SYNCENGINE_PROXY_AUTHENTICATION_REQUIRED: HRESULT = 0x8802D007; +pub const E_SYNCENGINE_STORAGE_SERVICE_PROVISIONING_FAILED: HRESULT = 0x8802D008; +pub const E_SYNCENGINE_UNSUPPORTED_REPARSE_POINT: HRESULT = 0x8802D009; +pub const E_SYNCENGINE_STORAGE_SERVICE_BLOCKED: HRESULT = 0x8802D00A; +pub const E_SYNCENGINE_FOLDER_IN_REDIRECTION: HRESULT = 0x8802D00B; +pub const EAS_E_POLICY_NOT_MANAGED_BY_OS: HRESULT = 0x80550001; +pub const EAS_E_POLICY_COMPLIANT_WITH_ACTIONS: HRESULT = 0x80550002; +pub const EAS_E_REQUESTED_POLICY_NOT_ENFORCEABLE: HRESULT = 0x80550003; +pub const EAS_E_CURRENT_USER_HAS_BLANK_PASSWORD: HRESULT = 0x80550004; +pub const EAS_E_REQUESTED_POLICY_PASSWORD_EXPIRATION_INCOMPATIBLE: HRESULT + = 0x80550005; +pub const EAS_E_USER_CANNOT_CHANGE_PASSWORD: HRESULT = 0x80550006; +pub const EAS_E_ADMINS_HAVE_BLANK_PASSWORD: HRESULT = 0x80550007; +pub const EAS_E_ADMINS_CANNOT_CHANGE_PASSWORD: HRESULT = 0x80550008; +pub const EAS_E_LOCAL_CONTROLLED_USERS_CANNOT_CHANGE_PASSWORD: HRESULT = 0x80550009; +pub const EAS_E_PASSWORD_POLICY_NOT_ENFORCEABLE_FOR_CONNECTED_ADMINS: HRESULT + = 0x8055000A; +pub const EAS_E_CONNECTED_ADMINS_NEED_TO_CHANGE_PASSWORD: HRESULT = 0x8055000B; +pub const EAS_E_PASSWORD_POLICY_NOT_ENFORCEABLE_FOR_CURRENT_CONNECTED_USER: HRESULT + = 0x8055000C; +pub const EAS_E_CURRENT_CONNECTED_USER_NEED_TO_CHANGE_PASSWORD: HRESULT = 0x8055000D; +pub const WEB_E_UNSUPPORTED_FORMAT: HRESULT = 0x83750001; +pub const WEB_E_INVALID_XML: HRESULT = 0x83750002; +pub const WEB_E_MISSING_REQUIRED_ELEMENT: HRESULT = 0x83750003; +pub const WEB_E_MISSING_REQUIRED_ATTRIBUTE: HRESULT = 0x83750004; +pub const WEB_E_UNEXPECTED_CONTENT: HRESULT = 0x83750005; +pub const WEB_E_RESOURCE_TOO_LARGE: HRESULT = 0x83750006; +pub const WEB_E_INVALID_JSON_STRING: HRESULT = 0x83750007; +pub const WEB_E_INVALID_JSON_NUMBER: HRESULT = 0x83750008; +pub const WEB_E_JSON_VALUE_NOT_FOUND: HRESULT = 0x83750009; +pub const HTTP_E_STATUS_UNEXPECTED: HRESULT = 0x80190001; +pub const HTTP_E_STATUS_UNEXPECTED_REDIRECTION: HRESULT = 0x80190003; +pub const HTTP_E_STATUS_UNEXPECTED_CLIENT_ERROR: HRESULT = 0x80190004; +pub const HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR: HRESULT = 0x80190005; +pub const HTTP_E_STATUS_AMBIGUOUS: HRESULT = 0x8019012C; +pub const HTTP_E_STATUS_MOVED: HRESULT = 0x8019012D; +pub const HTTP_E_STATUS_REDIRECT: HRESULT = 0x8019012E; +pub const HTTP_E_STATUS_REDIRECT_METHOD: HRESULT = 0x8019012F; +pub const HTTP_E_STATUS_NOT_MODIFIED: HRESULT = 0x80190130; +pub const HTTP_E_STATUS_USE_PROXY: HRESULT = 0x80190131; +pub const HTTP_E_STATUS_REDIRECT_KEEP_VERB: HRESULT = 0x80190133; +pub const HTTP_E_STATUS_BAD_REQUEST: HRESULT = 0x80190190; +pub const HTTP_E_STATUS_DENIED: HRESULT = 0x80190191; +pub const HTTP_E_STATUS_PAYMENT_REQ: HRESULT = 0x80190192; +pub const HTTP_E_STATUS_FORBIDDEN: HRESULT = 0x80190193; +pub const HTTP_E_STATUS_NOT_FOUND: HRESULT = 0x80190194; +pub const HTTP_E_STATUS_BAD_METHOD: HRESULT = 0x80190195; +pub const HTTP_E_STATUS_NONE_ACCEPTABLE: HRESULT = 0x80190196; +pub const HTTP_E_STATUS_PROXY_AUTH_REQ: HRESULT = 0x80190197; +pub const HTTP_E_STATUS_REQUEST_TIMEOUT: HRESULT = 0x80190198; +pub const HTTP_E_STATUS_CONFLICT: HRESULT = 0x80190199; +pub const HTTP_E_STATUS_GONE: HRESULT = 0x8019019A; +pub const HTTP_E_STATUS_LENGTH_REQUIRED: HRESULT = 0x8019019B; +pub const HTTP_E_STATUS_PRECOND_FAILED: HRESULT = 0x8019019C; +pub const HTTP_E_STATUS_REQUEST_TOO_LARGE: HRESULT = 0x8019019D; +pub const HTTP_E_STATUS_URI_TOO_LONG: HRESULT = 0x8019019E; +pub const HTTP_E_STATUS_UNSUPPORTED_MEDIA: HRESULT = 0x8019019F; +pub const HTTP_E_STATUS_RANGE_NOT_SATISFIABLE: HRESULT = 0x801901A0; +pub const HTTP_E_STATUS_EXPECTATION_FAILED: HRESULT = 0x801901A1; +pub const HTTP_E_STATUS_SERVER_ERROR: HRESULT = 0x801901F4; +pub const HTTP_E_STATUS_NOT_SUPPORTED: HRESULT = 0x801901F5; +pub const HTTP_E_STATUS_BAD_GATEWAY: HRESULT = 0x801901F6; +pub const HTTP_E_STATUS_SERVICE_UNAVAIL: HRESULT = 0x801901F7; +pub const HTTP_E_STATUS_GATEWAY_TIMEOUT: HRESULT = 0x801901F8; +pub const HTTP_E_STATUS_VERSION_NOT_SUP: HRESULT = 0x801901F9; +pub const E_INVALID_PROTOCOL_OPERATION: HRESULT = 0x83760001; +pub const E_INVALID_PROTOCOL_FORMAT: HRESULT = 0x83760002; +pub const E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED: HRESULT = 0x83760003; +pub const E_SUBPROTOCOL_NOT_SUPPORTED: HRESULT = 0x83760004; +pub const E_PROTOCOL_VERSION_NOT_SUPPORTED: HRESULT = 0x83760005; +pub const INPUT_E_OUT_OF_ORDER: HRESULT = 0x80400000; +pub const INPUT_E_REENTRANCY: HRESULT = 0x80400001; +pub const INPUT_E_MULTIMODAL: HRESULT = 0x80400002; +pub const INPUT_E_PACKET: HRESULT = 0x80400003; +pub const INPUT_E_FRAME: HRESULT = 0x80400004; +pub const INPUT_E_HISTORY: HRESULT = 0x80400005; +pub const INPUT_E_DEVICE_INFO: HRESULT = 0x80400006; +pub const INPUT_E_TRANSFORM: HRESULT = 0x80400007; +pub const INPUT_E_DEVICE_PROPERTY: HRESULT = 0x80400008; +pub const INET_E_INVALID_URL: HRESULT = 0x800C0002; +pub const INET_E_NO_SESSION: HRESULT = 0x800C0003; +pub const INET_E_CANNOT_CONNECT: HRESULT = 0x800C0004; +pub const INET_E_RESOURCE_NOT_FOUND: HRESULT = 0x800C0005; +pub const INET_E_OBJECT_NOT_FOUND: HRESULT = 0x800C0006; +pub const INET_E_DATA_NOT_AVAILABLE: HRESULT = 0x800C0007; +pub const INET_E_DOWNLOAD_FAILURE: HRESULT = 0x800C0008; +pub const INET_E_AUTHENTICATION_REQUIRED: HRESULT = 0x800C0009; +pub const INET_E_NO_VALID_MEDIA: HRESULT = 0x800C000A; +pub const INET_E_CONNECTION_TIMEOUT: HRESULT = 0x800C000B; +pub const INET_E_INVALID_REQUEST: HRESULT = 0x800C000C; +pub const INET_E_UNKNOWN_PROTOCOL: HRESULT = 0x800C000D; +pub const INET_E_SECURITY_PROBLEM: HRESULT = 0x800C000E; +pub const INET_E_CANNOT_LOAD_DATA: HRESULT = 0x800C000F; +pub const INET_E_CANNOT_INSTANTIATE_OBJECT: HRESULT = 0x800C0010; +pub const INET_E_INVALID_CERTIFICATE: HRESULT = 0x800C0019; +pub const INET_E_REDIRECT_FAILED: HRESULT = 0x800C0014; +pub const INET_E_REDIRECT_TO_DIR: HRESULT = 0x800C0015; +pub const ERROR_DBG_CREATE_PROCESS_FAILURE_LOCKDOWN: HRESULT = 0x80B00001; +pub const ERROR_DBG_ATTACH_PROCESS_FAILURE_LOCKDOWN: HRESULT = 0x80B00002; +pub const ERROR_DBG_CONNECT_SERVER_FAILURE_LOCKDOWN: HRESULT = 0x80B00003; +pub const ERROR_DBG_START_SERVER_FAILURE_LOCKDOWN: HRESULT = 0x80B00004; +pub const ERROR_IO_PREEMPTED: HRESULT = 0x89010001; +pub const JSCRIPT_E_CANTEXECUTE: HRESULT = 0x89020001; +pub const WEP_E_NOT_PROVISIONED_ON_ALL_VOLUMES: HRESULT = 0x88010001; +pub const WEP_E_FIXED_DATA_NOT_SUPPORTED: HRESULT = 0x88010002; +pub const WEP_E_HARDWARE_NOT_COMPLIANT: HRESULT = 0x88010003; +pub const WEP_E_LOCK_NOT_CONFIGURED: HRESULT = 0x88010004; +pub const WEP_E_PROTECTION_SUSPENDED: HRESULT = 0x88010005; +pub const WEP_E_NO_LICENSE: HRESULT = 0x88010006; +pub const WEP_E_OS_NOT_PROTECTED: HRESULT = 0x88010007; +pub const WEP_E_UNEXPECTED_FAIL: HRESULT = 0x88010008; +pub const WEP_E_BUFFER_TOO_LARGE: HRESULT = 0x88010009; +pub const ERROR_SVHDX_ERROR_STORED: HRESULT = 0xC05C0000; +pub const ERROR_SVHDX_ERROR_NOT_AVAILABLE: HRESULT = 0xC05CFF00; +pub const ERROR_SVHDX_UNIT_ATTENTION_AVAILABLE: HRESULT = 0xC05CFF01; +pub const ERROR_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED: HRESULT = 0xC05CFF02; +pub const ERROR_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED: HRESULT = 0xC05CFF03; +pub const ERROR_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED: HRESULT = 0xC05CFF04; +pub const ERROR_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED: HRESULT = 0xC05CFF05; +pub const ERROR_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED: HRESULT + = 0xC05CFF06; +pub const ERROR_SVHDX_RESERVATION_CONFLICT: HRESULT = 0xC05CFF07; +pub const ERROR_SVHDX_WRONG_FILE_TYPE: HRESULT = 0xC05CFF08; +pub const ERROR_SVHDX_VERSION_MISMATCH: HRESULT = 0xC05CFF09; +pub const ERROR_VHD_SHARED: HRESULT = 0xC05CFF0A; +pub const WININET_E_OUT_OF_HANDLES: HRESULT = 0x80072EE1; +pub const WININET_E_TIMEOUT: HRESULT = 0x80072EE2; +pub const WININET_E_EXTENDED_ERROR: HRESULT = 0x80072EE3; +pub const WININET_E_INTERNAL_ERROR: HRESULT = 0x80072EE4; +pub const WININET_E_INVALID_URL: HRESULT = 0x80072EE5; +pub const WININET_E_UNRECOGNIZED_SCHEME: HRESULT = 0x80072EE6; +pub const WININET_E_NAME_NOT_RESOLVED: HRESULT = 0x80072EE7; +pub const WININET_E_PROTOCOL_NOT_FOUND: HRESULT = 0x80072EE8; +pub const WININET_E_INVALID_OPTION: HRESULT = 0x80072EE9; +pub const WININET_E_BAD_OPTION_LENGTH: HRESULT = 0x80072EEA; +pub const WININET_E_OPTION_NOT_SETTABLE: HRESULT = 0x80072EEB; +pub const WININET_E_SHUTDOWN: HRESULT = 0x80072EEC; +pub const WININET_E_INCORRECT_USER_NAME: HRESULT = 0x80072EED; +pub const WININET_E_INCORRECT_PASSWORD: HRESULT = 0x80072EEE; +pub const WININET_E_LOGIN_FAILURE: HRESULT = 0x80072EEF; +pub const WININET_E_INVALID_OPERATION: HRESULT = 0x80072EF0; +pub const WININET_E_OPERATION_CANCELLED: HRESULT = 0x80072EF1; +pub const WININET_E_INCORRECT_HANDLE_TYPE: HRESULT = 0x80072EF2; +pub const WININET_E_INCORRECT_HANDLE_STATE: HRESULT = 0x80072EF3; +pub const WININET_E_NOT_PROXY_REQUEST: HRESULT = 0x80072EF4; +pub const WININET_E_REGISTRY_VALUE_NOT_FOUND: HRESULT = 0x80072EF5; +pub const WININET_E_BAD_REGISTRY_PARAMETER: HRESULT = 0x80072EF6; +pub const WININET_E_NO_DIRECT_ACCESS: HRESULT = 0x80072EF7; +pub const WININET_E_NO_CONTEXT: HRESULT = 0x80072EF8; +pub const WININET_E_NO_CALLBACK: HRESULT = 0x80072EF9; +pub const WININET_E_REQUEST_PENDING: HRESULT = 0x80072EFA; +pub const WININET_E_INCORRECT_FORMAT: HRESULT = 0x80072EFB; +pub const WININET_E_ITEM_NOT_FOUND: HRESULT = 0x80072EFC; +pub const WININET_E_CANNOT_CONNECT: HRESULT = 0x80072EFD; +pub const WININET_E_CONNECTION_ABORTED: HRESULT = 0x80072EFE; +pub const WININET_E_CONNECTION_RESET: HRESULT = 0x80072EFF; +pub const WININET_E_FORCE_RETRY: HRESULT = 0x80072F00; +pub const WININET_E_INVALID_PROXY_REQUEST: HRESULT = 0x80072F01; +pub const WININET_E_NEED_UI: HRESULT = 0x80072F02; +pub const WININET_E_HANDLE_EXISTS: HRESULT = 0x80072F04; +pub const WININET_E_SEC_CERT_DATE_INVALID: HRESULT = 0x80072F05; +pub const WININET_E_SEC_CERT_CN_INVALID: HRESULT = 0x80072F06; +pub const WININET_E_HTTP_TO_HTTPS_ON_REDIR: HRESULT = 0x80072F07; +pub const WININET_E_HTTPS_TO_HTTP_ON_REDIR: HRESULT = 0x80072F08; +pub const WININET_E_MIXED_SECURITY: HRESULT = 0x80072F09; +pub const WININET_E_CHG_POST_IS_NON_SECURE: HRESULT = 0x80072F0A; +pub const WININET_E_POST_IS_NON_SECURE: HRESULT = 0x80072F0B; +pub const WININET_E_CLIENT_AUTH_CERT_NEEDED: HRESULT = 0x80072F0C; +pub const WININET_E_INVALID_CA: HRESULT = 0x80072F0D; +pub const WININET_E_CLIENT_AUTH_NOT_SETUP: HRESULT = 0x80072F0E; +pub const WININET_E_ASYNC_THREAD_FAILED: HRESULT = 0x80072F0F; +pub const WININET_E_REDIRECT_SCHEME_CHANGE: HRESULT = 0x80072F10; +pub const WININET_E_DIALOG_PENDING: HRESULT = 0x80072F11; +pub const WININET_E_RETRY_DIALOG: HRESULT = 0x80072F12; +pub const WININET_E_NO_NEW_CONTAINERS: HRESULT = 0x80072F13; +pub const WININET_E_HTTPS_HTTP_SUBMIT_REDIR: HRESULT = 0x80072F14; +pub const WININET_E_SEC_CERT_ERRORS: HRESULT = 0x80072F17; +pub const WININET_E_SEC_CERT_REV_FAILED: HRESULT = 0x80072F19; +pub const WININET_E_HEADER_NOT_FOUND: HRESULT = 0x80072F76; +pub const WININET_E_DOWNLEVEL_SERVER: HRESULT = 0x80072F77; +pub const WININET_E_INVALID_SERVER_RESPONSE: HRESULT = 0x80072F78; +pub const WININET_E_INVALID_HEADER: HRESULT = 0x80072F79; +pub const WININET_E_INVALID_QUERY_REQUEST: HRESULT = 0x80072F7A; +pub const WININET_E_HEADER_ALREADY_EXISTS: HRESULT = 0x80072F7B; +pub const WININET_E_REDIRECT_FAILED: HRESULT = 0x80072F7C; +pub const WININET_E_SECURITY_CHANNEL_ERROR: HRESULT = 0x80072F7D; +pub const WININET_E_UNABLE_TO_CACHE_FILE: HRESULT = 0x80072F7E; +pub const WININET_E_TCPIP_NOT_INSTALLED: HRESULT = 0x80072F7F; +pub const WININET_E_DISCONNECTED: HRESULT = 0x80072F83; +pub const WININET_E_SERVER_UNREACHABLE: HRESULT = 0x80072F84; +pub const WININET_E_PROXY_SERVER_UNREACHABLE: HRESULT = 0x80072F85; +pub const WININET_E_BAD_AUTO_PROXY_SCRIPT: HRESULT = 0x80072F86; +pub const WININET_E_UNABLE_TO_DOWNLOAD_SCRIPT: HRESULT = 0x80072F87; +pub const WININET_E_SEC_INVALID_CERT: HRESULT = 0x80072F89; +pub const WININET_E_SEC_CERT_REVOKED: HRESULT = 0x80072F8A; +pub const WININET_E_FAILED_DUETOSECURITYCHECK: HRESULT = 0x80072F8B; +pub const WININET_E_NOT_INITIALIZED: HRESULT = 0x80072F8C; +pub const WININET_E_LOGIN_FAILURE_DISPLAY_ENTITY_BODY: HRESULT = 0x80072F8E; +pub const WININET_E_DECODING_FAILED: HRESULT = 0x80072F8F; +pub const WININET_E_NOT_REDIRECTED: HRESULT = 0x80072F80; +pub const WININET_E_COOKIE_NEEDS_CONFIRMATION: HRESULT = 0x80072F81; +pub const WININET_E_COOKIE_DECLINED: HRESULT = 0x80072F82; +pub const WININET_E_REDIRECT_NEEDS_CONFIRMATION: HRESULT = 0x80072F88; diff --git a/winapi/src/shared/winusbio.rs b/winapi/src/shared/winusbio.rs new file mode 100644 index 000000000..800694333 --- /dev/null +++ b/winapi/src/shared/winusbio.rs @@ -0,0 +1,38 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Public header for WINUSB +use shared::minwindef::{UCHAR, ULONG, USHORT}; +use shared::usb::USBD_PIPE_TYPE; +pub const SHORT_PACKET_TERMINATE: ULONG = 0x01; +pub const AUTO_CLEAR_STALL: ULONG = 0x02; +pub const PIPE_TRANSFER_TIMEOUT: ULONG = 0x03; +pub const IGNORE_SHORT_PACKETS: ULONG = 0x04; +pub const ALLOW_PARTIAL_READS: ULONG = 0x05; +pub const AUTO_FLUSH: ULONG = 0x06; +pub const RAW_IO: ULONG = 0x07; +pub const MAXIMUM_TRANSFER_SIZE: ULONG = 0x08; +pub const RESET_PIPE_ON_RESUME: ULONG = 0x09; +pub const DEVICE_SPEED: ULONG = 0x01; +pub const LowSpeed: ULONG = 0x01; +pub const FullSpeed: ULONG = 0x02; +pub const HighSpeed: ULONG = 0x03; +DEFINE_GUID!{WinUSB_TestGuid, + 0xda812bff, 0x12c3, 0x46a2, 0x8e, 0x2b, 0xdb, 0xd3, 0xb7, 0x83, 0x4c, 0x43} +STRUCT!{struct WINUSB_PIPE_INFORMATION { + PipeType: USBD_PIPE_TYPE, + PipeId: UCHAR, + MaximumPacketSize: USHORT, + Interval: UCHAR, +}} +pub type PWINUSB_PIPE_INFORMATION = *mut WINUSB_PIPE_INFORMATION; +STRUCT!{struct WINUSB_PIPE_INFORMATION_EX { + PipeType: USBD_PIPE_TYPE, + PipeId: UCHAR, + MaximumPacketSize: USHORT, + Interval: UCHAR, + MaximumBytesPerInterval: ULONG, +}} +pub type PWINUSB_PIPE_INFORMATION_EX = *mut WINUSB_PIPE_INFORMATION_EX; diff --git a/winapi/src/shared/wmistr.rs b/winapi/src/shared/wmistr.rs new file mode 100644 index 000000000..35374e92b --- /dev/null +++ b/winapi/src/shared/wmistr.rs @@ -0,0 +1,199 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{ULONG64, ULONG_PTR}; +use shared::guiddef::GUID; +use shared::minwindef::{UCHAR, ULONG}; +use um::winnt::{HANDLE, LARGE_INTEGER, STANDARD_RIGHTS_READ, SYNCHRONIZE, WCHAR}; +STRUCT!{struct WNODE_HEADER_u1_s { + Version: ULONG, + Linkage: ULONG, +}} +UNION!{union WNODE_HEADER_u1 { + [u64; 1], + HistoricalContext HistoricalContext_mut: ULONG64, + s s_mut: WNODE_HEADER_u1_s, +}} +UNION!{union WNODE_HEADER_u2 { + [u64; 1], + CountLost CountLost_mut: ULONG, + KernelHandle KernelHandle_mut: HANDLE, + TimeStamp TimeStamp_mut: LARGE_INTEGER, +}} +STRUCT!{struct WNODE_HEADER { + BufferSize: ULONG, + ProviderId: ULONG, + u1: WNODE_HEADER_u1, + u2: WNODE_HEADER_u2, + Guid: GUID, + ClientContext: ULONG, + Flags: ULONG, +}} +pub type PWNODE_HEADER = *mut WNODE_HEADER; +pub const WNODE_FLAG_ALL_DATA: ULONG = 0x00000001; +pub const WNODE_FLAG_SINGLE_INSTANCE: ULONG = 0x00000002; +pub const WNODE_FLAG_SINGLE_ITEM: ULONG = 0x00000004; +pub const WNODE_FLAG_EVENT_ITEM: ULONG = 0x00000008; +pub const WNODE_FLAG_FIXED_INSTANCE_SIZE: ULONG = 0x00000010; +pub const WNODE_FLAG_TOO_SMALL: ULONG = 0x00000020; +pub const WNODE_FLAG_INSTANCES_SAME: ULONG = 0x00000040; +pub const WNODE_FLAG_STATIC_INSTANCE_NAMES: ULONG = 0x00000080; +pub const WNODE_FLAG_INTERNAL: ULONG = 0x00000100; +pub const WNODE_FLAG_USE_TIMESTAMP: ULONG = 0x00000200; +pub const WNODE_FLAG_PERSIST_EVENT: ULONG = 0x00000400; +pub const WNODE_FLAG_EVENT_REFERENCE: ULONG = 0x00002000; +pub const WNODE_FLAG_ANSI_INSTANCENAMES: ULONG = 0x00004000; +pub const WNODE_FLAG_METHOD_ITEM: ULONG = 0x00008000; +pub const WNODE_FLAG_PDO_INSTANCE_NAMES: ULONG = 0x00010000; +pub const WNODE_FLAG_TRACED_GUID: ULONG = 0x00020000; +pub const WNODE_FLAG_LOG_WNODE: ULONG = 0x00040000; +pub const WNODE_FLAG_USE_GUID_PTR: ULONG = 0x00080000; +pub const WNODE_FLAG_USE_MOF_PTR: ULONG = 0x00100000; +pub const WNODE_FLAG_NO_HEADER: ULONG = 0x00200000; +pub const WNODE_FLAG_SEND_DATA_BLOCK: ULONG = 0x00400000; +pub const WNODE_FLAG_VERSIONED_PROPERTIES: ULONG = 0x00800000; +pub const WNODE_FLAG_SEVERITY_MASK: ULONG = 0xff000000; +STRUCT!{struct OFFSETINSTANCEDATAANDLENGTH { + OffsetInstanceData: ULONG, + LengthInstanceData: ULONG, +}} +pub type POFFSETINSTANCEDATAANDLENGTH = *mut OFFSETINSTANCEDATAANDLENGTH; +UNION!{union WNODE_ALL_DATA_u { + [u32; 2], + FixedInstanceSize FixedInstanceSize_mut: ULONG, + OffsetInstanceDataAndLength OffsetInstanceDataAndLength_mut: + [OFFSETINSTANCEDATAANDLENGTH; 0], +}} +STRUCT!{struct WNODE_ALL_DATA { + WnodeHeader: WNODE_HEADER, + DataBlockOffset: ULONG, + InstanceCount: ULONG, + OffsetInstanceNameOffsets: ULONG, + u: WNODE_ALL_DATA_u, +}} +pub type PWNODE_ALL_DATA = *mut WNODE_ALL_DATA; +STRUCT!{struct WNODE_SINGLE_INSTANCE { + WnodeHeader: WNODE_HEADER, + OffsetInstanceName: ULONG, + InstanceIndex: ULONG, + DataBlockOffset: ULONG, + SizeDataBlock: ULONG, + VariableData: [UCHAR; 0], +}} +pub type PWNODE_SINGLE_INSTANCE = *mut WNODE_SINGLE_INSTANCE; +STRUCT!{struct WNODE_SINGLE_ITEM { + WnodeHeader: WNODE_HEADER, + OffsetInstanceName: ULONG, + InstanceIndex: ULONG, + ItemId: ULONG, + DataBlockOffset: ULONG, + SizeDataItem: ULONG, + VariableData: [UCHAR; 0], +}} +pub type PWNODE_SINGLE_ITEM = *mut WNODE_SINGLE_ITEM; +STRUCT!{struct WNODE_METHOD_ITEM { + WnodeHeader: WNODE_HEADER, + OffsetInstanceName: ULONG, + InstanceIndex: ULONG, + MethodId: ULONG, + DataBlockOffset: ULONG, + SizeDataBlock: ULONG, + VariableData: [UCHAR; 0], +}} +pub type PWNODE_METHOD_ITEM = *mut WNODE_METHOD_ITEM; +STRUCT!{struct WNODE_EVENT_ITEM { + WnodeHeader: WNODE_HEADER, +}} +pub type PWNODE_EVENT_ITEM = *mut WNODE_EVENT_ITEM; +UNION!{union WNODE_EVENT_REFERENCE_u { + [u32; 1], + TargetInstanceIndex TargetInstanceIndex_mut: ULONG, + TargetInstanceName TargetInstanceName_mut: [WCHAR; 0], +}} +STRUCT!{struct WNODE_EVENT_REFERENCE { + WnodeHeader: WNODE_HEADER, + TargetGuid: GUID, + TargetDataBlockSize: ULONG, + u: WNODE_EVENT_REFERENCE_u, +}} +pub type PWNODE_EVENT_REFERENCE = *mut WNODE_EVENT_REFERENCE; +STRUCT!{struct WNODE_TOO_SMALL { + WnodeHeader: WNODE_HEADER, + SizeNeeded: ULONG, +}} +pub type PWNODE_TOO_SMALL = *mut WNODE_TOO_SMALL; +UNION!{union WMIREGGUIDW_u { + [usize; 1], + InstanceNameList InstanceNameList_mut: ULONG, + BaseNameOffset BaseNameOffset_mut: ULONG, + Pdo Pdo_mut: ULONG_PTR, + InstanceInfo InstanceInfo_mut: ULONG_PTR, +}} +STRUCT!{struct WMIREGGUIDW { + Guid: GUID, + Flags: ULONG, + InstanceCount: ULONG, + u: WMIREGGUIDW_u, +}} +pub type PWMIREGGUIDW = *mut WMIREGGUIDW; +pub const WMIREG_FLAG_EXPENSIVE: ULONG = 0x00000001; +pub const WMIREG_FLAG_INSTANCE_LIST: ULONG = 0x00000004; +pub const WMIREG_FLAG_INSTANCE_BASENAME: ULONG = 0x00000008; +pub const WMIREG_FLAG_INSTANCE_PDO: ULONG = 0x00000020; +pub const WMIREG_FLAG_REMOVE_GUID: ULONG = 0x00010000; +pub const WMIREG_FLAG_RESERVED1: ULONG = 0x00020000; +pub const WMIREG_FLAG_RESERVED2: ULONG = 0x00040000; +pub const WMIREG_FLAG_TRACED_GUID: ULONG = 0x00080000; +pub const WMIREG_FLAG_TRACE_CONTROL_GUID: ULONG = 0x00001000; +pub const WMIREG_FLAG_EVENT_ONLY_GUID: ULONG = 0x00000040; +STRUCT!{struct WMIREGINFOW { + BufferSize: ULONG, + NextWmiRegInfo: ULONG, + RegistryPath: ULONG, + MofResourceName: ULONG, + GuidGount: ULONG, + WmiRegGuid: [WMIREGGUIDW; 0], +}} +pub type PWMIREGINFOW = *mut WMIREGINFOW; +ENUM!{enum WMIDPREQUESTCODE { + WMI_GET_ALL_DATA = 0, + WMI_GET_SINGLE_INSTANCE = 1, + WMI_SET_SINGLE_INSTANCE = 2, + WMI_SET_SINGLE_ITEM = 3, + WMI_ENABLE_EVENTS = 4, + WMI_DISABLE_EVENTS = 5, + WMI_ENABLE_COLLECTION = 6, + WMI_DISABLE_COLLECTION = 7, + WMI_REGINFO = 8, + WMI_EXECUTE_METHOD = 9, + WMI_CAPTURE_STATE = 10, +}} +pub const WMI_GUIDTYPE_TRACECONTROL: ULONG = 0; +pub const WMI_GUIDTYPE_TRACE: ULONG = 1; +pub const WMI_GUIDTYPE_DATA: ULONG = 2; +pub const WMI_GUIDTYPE_EVENT: ULONG = 3; +pub const WMIGUID_QUERY: ULONG = 0x0001; +pub const WMIGUID_SET: ULONG = 0x0002; +pub const WMIGUID_NOTIFICATION: ULONG = 0x0004; +pub const WMIGUID_READ_DESCRIPTION: ULONG = 0x0008; +pub const WMIGUID_EXECUTE: ULONG = 0x0010; +pub const TRACELOG_CREATE_REALTIME: ULONG = 0x0020; +pub const TRACELOG_CREATE_ONDISK: ULONG = 0x0040; +pub const TRACELOG_GUID_ENABLE: ULONG = 0x0080; +pub const TRACELOG_ACCESS_KERNEL_LOGGER: ULONG = 0x0100; +pub const TRACELOG_LOG_EVENT: ULONG = 0x0200; +pub const TRACELOG_CREATE_INPROC: ULONG = 0x0200; +pub const TRACELOG_ACCESS_REALTIME: ULONG = 0x0400; +pub const TRACELOG_REGISTER_GUIDS: ULONG = 0x0800; +pub const TRACELOG_JOIN_GROUP: ULONG = 0x1000; +pub const WMIGUID_ALL_ACCESS_WIN2K: ULONG = STANDARD_RIGHTS_READ | WMIGUID_QUERY | WMIGUID_SET + | WMIGUID_NOTIFICATION | WMIGUID_READ_DESCRIPTION | WMIGUID_EXECUTE | TRACELOG_CREATE_REALTIME + | TRACELOG_CREATE_ONDISK | TRACELOG_GUID_ENABLE | TRACELOG_ACCESS_KERNEL_LOGGER + | TRACELOG_CREATE_INPROC | TRACELOG_ACCESS_REALTIME; +pub const WMIGUID_ALL_ACCESS_WINXP: ULONG = WMIGUID_ALL_ACCESS_WIN2K | SYNCHRONIZE + | TRACELOG_REGISTER_GUIDS; +pub const WMIGUID_ALL_ACCESS_RS1: ULONG = WMIGUID_ALL_ACCESS_WINXP | TRACELOG_JOIN_GROUP; +pub const WMIGUID_ALL_ACCESS: ULONG = WMIGUID_ALL_ACCESS_RS1; +pub const WMI_GLOBAL_LOGGER_ID: ULONG = 0x0001; diff --git a/winapi/src/shared/wnnc.rs b/winapi/src/shared/wnnc.rs new file mode 100644 index 000000000..305137c58 --- /dev/null +++ b/winapi/src/shared/wnnc.rs @@ -0,0 +1,77 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Provides the Windows Networking WNNC_NET definitions to winnetwk.h and the IFS Kit. +use shared::minwindef::DWORD; +pub const WNNC_NET_MSNET: DWORD = 0x00010000; +pub const WNNC_NET_SMB: DWORD = 0x00020000; +pub const WNNC_NET_NETWARE: DWORD = 0x00030000; +pub const WNNC_NET_VINES: DWORD = 0x00040000; +pub const WNNC_NET_10NET: DWORD = 0x00050000; +pub const WNNC_NET_LOCUS: DWORD = 0x00060000; +pub const WNNC_NET_SUN_PC_NFS: DWORD = 0x00070000; +pub const WNNC_NET_LANSTEP: DWORD = 0x00080000; +pub const WNNC_NET_9TILES: DWORD = 0x00090000; +pub const WNNC_NET_LANTASTIC: DWORD = 0x000A0000; +pub const WNNC_NET_AS400: DWORD = 0x000B0000; +pub const WNNC_NET_FTP_NFS: DWORD = 0x000C0000; +pub const WNNC_NET_PATHWORKS: DWORD = 0x000D0000; +pub const WNNC_NET_LIFENET: DWORD = 0x000E0000; +pub const WNNC_NET_POWERLAN: DWORD = 0x000F0000; +pub const WNNC_NET_BWNFS: DWORD = 0x00100000; +pub const WNNC_NET_COGENT: DWORD = 0x00110000; +pub const WNNC_NET_FARALLON: DWORD = 0x00120000; +pub const WNNC_NET_APPLETALK: DWORD = 0x00130000; +pub const WNNC_NET_INTERGRAPH: DWORD = 0x00140000; +pub const WNNC_NET_SYMFONET: DWORD = 0x00150000; +pub const WNNC_NET_CLEARCASE: DWORD = 0x00160000; +pub const WNNC_NET_FRONTIER: DWORD = 0x00170000; +pub const WNNC_NET_BMC: DWORD = 0x00180000; +pub const WNNC_NET_DCE: DWORD = 0x00190000; +pub const WNNC_NET_AVID: DWORD = 0x001A0000; +pub const WNNC_NET_DOCUSPACE: DWORD = 0x001B0000; +pub const WNNC_NET_MANGOSOFT: DWORD = 0x001C0000; +pub const WNNC_NET_SERNET: DWORD = 0x001D0000; +pub const WNNC_NET_RIVERFRONT1: DWORD = 0x001E0000; +pub const WNNC_NET_RIVERFRONT2: DWORD = 0x001F0000; +pub const WNNC_NET_DECORB: DWORD = 0x00200000; +pub const WNNC_NET_PROTSTOR: DWORD = 0x00210000; +pub const WNNC_NET_FJ_REDIR: DWORD = 0x00220000; +pub const WNNC_NET_DISTINCT: DWORD = 0x00230000; +pub const WNNC_NET_TWINS: DWORD = 0x00240000; +pub const WNNC_NET_RDR2SAMPLE: DWORD = 0x00250000; +pub const WNNC_NET_CSC: DWORD = 0x00260000; +pub const WNNC_NET_3IN1: DWORD = 0x00270000; +pub const WNNC_NET_EXTENDNET: DWORD = 0x00290000; +pub const WNNC_NET_STAC: DWORD = 0x002A0000; +pub const WNNC_NET_FOXBAT: DWORD = 0x002B0000; +pub const WNNC_NET_YAHOO: DWORD = 0x002C0000; +pub const WNNC_NET_EXIFS: DWORD = 0x002D0000; +pub const WNNC_NET_DAV: DWORD = 0x002E0000; +pub const WNNC_NET_KNOWARE: DWORD = 0x002F0000; +pub const WNNC_NET_OBJECT_DIRE: DWORD = 0x00300000; +pub const WNNC_NET_MASFAX: DWORD = 0x00310000; +pub const WNNC_NET_HOB_NFS: DWORD = 0x00320000; +pub const WNNC_NET_SHIVA: DWORD = 0x00330000; +pub const WNNC_NET_IBMAL: DWORD = 0x00340000; +pub const WNNC_NET_LOCK: DWORD = 0x00350000; +pub const WNNC_NET_TERMSRV: DWORD = 0x00360000; +pub const WNNC_NET_SRT: DWORD = 0x00370000; +pub const WNNC_NET_QUINCY: DWORD = 0x00380000; +pub const WNNC_NET_OPENAFS: DWORD = 0x00390000; +pub const WNNC_NET_AVID1: DWORD = 0x003A0000; +pub const WNNC_NET_DFS: DWORD = 0x003B0000; +pub const WNNC_NET_KWNP: DWORD = 0x003C0000; +pub const WNNC_NET_ZENWORKS: DWORD = 0x003D0000; +pub const WNNC_NET_DRIVEONWEB: DWORD = 0x003E0000; +pub const WNNC_NET_VMWARE: DWORD = 0x003F0000; +pub const WNNC_NET_RSFX: DWORD = 0x00400000; +pub const WNNC_NET_MFILES: DWORD = 0x00410000; +pub const WNNC_NET_MS_NFS: DWORD = 0x00420000; +pub const WNNC_NET_GOOGLE: DWORD = 0x00430000; +pub const WNNC_NET_NDFS: DWORD = 0x00440000; +pub const WNNC_NET_DOCUSHARE: DWORD = 0x00450000; +pub const WNNC_CRED_MANAGER: DWORD = 0xFFFF0000; +pub const WNNC_NET_LANMAN: DWORD = WNNC_NET_SMB; diff --git a/winapi/src/shared/ws2def.rs b/winapi/src/shared/ws2def.rs new file mode 100644 index 000000000..484f6d4a6 --- /dev/null +++ b/winapi/src/shared/ws2def.rs @@ -0,0 +1,556 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Core definitions for the Winsock2 specification +use ctypes::{__int64, c_char, c_int, c_long, c_short, c_void}; +use shared::basetsd::SIZE_T; +use shared::guiddef::LPGUID; +use shared::inaddr::IN_ADDR; +use shared::minwindef::{DWORD, INT, UCHAR, ULONG, USHORT}; +use um::winnt::{CHAR, HANDLE, LONG, PROCESSOR_NUMBER, PWSTR}; +use vc::vcruntime::size_t; +pub type ADDRESS_FAMILY = USHORT; +pub const AF_UNSPEC: c_int = 0; +pub const AF_UNIX: c_int = 1; +pub const AF_INET: c_int = 2; +pub const AF_IMPLINK: c_int = 3; +pub const AF_PUP: c_int = 4; +pub const AF_CHAOS: c_int = 5; +pub const AF_NS: c_int = 6; +pub const AF_IPX: c_int = AF_NS; +pub const AF_ISO: c_int = 7; +pub const AF_OSI: c_int = AF_ISO; +pub const AF_ECMA: c_int = 8; +pub const AF_DATAKIT: c_int = 9; +pub const AF_CCITT: c_int = 10; +pub const AF_SNA: c_int = 11; +pub const AF_DECnet: c_int = 12; +pub const AF_DLI: c_int = 13; +pub const AF_LAT: c_int = 14; +pub const AF_HYLINK: c_int = 15; +pub const AF_APPLETALK: c_int = 16; +pub const AF_NETBIOS: c_int = 17; +pub const AF_VOICEVIEW: c_int = 18; +pub const AF_FIREFOX: c_int = 19; +pub const AF_UNKNOWN1: c_int = 20; +pub const AF_BAN: c_int = 21; +pub const AF_ATM: c_int = 22; +pub const AF_INET6: c_int = 23; +pub const AF_CLUSTER: c_int = 24; +pub const AF_12844: c_int = 25; +pub const AF_IRDA: c_int = 26; +pub const AF_NETDES: c_int = 28; +pub const AF_TCNPROCESS: c_int = 29; +pub const AF_TCNMESSAGE: c_int = 30; +pub const AF_ICLFXBM: c_int = 31; +pub const AF_BTH: c_int = 32; +pub const AF_LINK: c_int = 33; +pub const AF_HYPERV: c_int = 34; +pub const AF_MAX: c_int = 35; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SOL_SOCKET: c_int = 0xffff; +pub const SO_DEBUG: c_int = 0x0001; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_DONTLINGER: c_int = !SO_LINGER; +pub const SO_EXCLUSIVEADDRUSE: c_int = !SO_REUSEADDR; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_BSP_STATE: c_int = 0x1009; +pub const SO_GROUP_ID: c_int = 0x2001; +pub const SO_GROUP_PRIORITY: c_int = 0x2002; +pub const SO_MAX_MSG_SIZE: c_int = 0x2003; +pub const SO_CONDITIONAL_ACCEPT: c_int = 0x3002; +pub const SO_PAUSE_ACCEPT: c_int = 0x3003; +pub const SO_COMPARTMENT_ID: c_int = 0x3004; +pub const SO_RANDOMIZE_PORT: c_int = 0x3005; +pub const SO_PORT_SCALABILITY: c_int = 0x3006; +pub const SO_REUSE_UNICASTPORT: c_int = 0x3007; +pub const SO_REUSE_MULTICASTPORT: c_int = 0x3008; +pub const WSK_SO_BASE: c_int = 0x4000; +pub const TCP_NODELAY: c_int = 0x0001; +STRUCT!{struct SOCKADDR { + sa_family: ADDRESS_FAMILY, + sa_data: [CHAR; 14], +}} +pub type PSOCKADDR = *mut SOCKADDR; +pub type LPSOCKADDR = *mut SOCKADDR; +STRUCT!{struct SOCKET_ADDRESS { + lpSockaddr: LPSOCKADDR, + iSockaddrLength: INT, +}} +pub type PSOCKET_ADDRESS = *mut SOCKET_ADDRESS; +pub type LPSOCKET_ADDRESS = *mut SOCKET_ADDRESS; +STRUCT!{struct SOCKET_ADDRESS_LIST { + iAddressCount: INT, + Address: [SOCKET_ADDRESS; 1], +}} +pub type PSOCKET_ADDRESS_LIST = *mut SOCKET_ADDRESS_LIST; +pub type LPSOCKET_ADDRESS_LIST = *mut SOCKET_ADDRESS_LIST; +STRUCT!{struct CSADDR_INFO { + LocalAddr: SOCKET_ADDRESS, + RemoteAddr: SOCKET_ADDRESS, + iSocketType: INT, + iProtocol: INT, +}} +pub type PCSADDR_INFO = *mut CSADDR_INFO; +pub type LPCSADDR_INFO = *mut CSADDR_INFO; +STRUCT!{struct SOCKADDR_STORAGE_LH { + ss_family: ADDRESS_FAMILY, + __ss_pad1: [CHAR; 6], + __ss_align: __int64, + __ss_pad2: [CHAR; 112], +}} +pub type PSOCKADDR_STORAGE_LH = *mut SOCKADDR_STORAGE_LH; +pub type LPSOCKADDR_STORAGE_LH = *mut SOCKADDR_STORAGE_LH; +STRUCT!{struct SOCKADDR_STORAGE_XP { + ss_family: c_short, + __ss_pad1: [CHAR; 6], + __ss_align: __int64, + __ss_pad2: [CHAR; 112], +}} +pub type PSOCKADDR_STORAGE_XP = *mut SOCKADDR_STORAGE_XP; +pub type LPSOCKADDR_STORAGE_XP = *mut SOCKADDR_STORAGE_XP; +pub type SOCKADDR_STORAGE = SOCKADDR_STORAGE_LH; +pub type PSOCKADDR_STORAGE = *mut SOCKADDR_STORAGE; +pub type LPSOCKADDR_STORAGE = *mut SOCKADDR_STORAGE; +STRUCT!{struct SOCKET_PROCESSOR_AFFINITY { + Processor: PROCESSOR_NUMBER, + NumaNodeId: USHORT, + Reserved: USHORT, +}} +pub type PSOCKET_PROCESSOR_AFFINITY = *mut SOCKET_PROCESSOR_AFFINITY; +pub const IOC_UNIX: DWORD = 0x00000000; +pub const IOC_WS2: DWORD = 0x08000000; +pub const IOC_PROTOCOL: DWORD = 0x10000000; +pub const IOC_VENDOR: DWORD = 0x18000000; +pub const IOC_WSK: DWORD = IOC_WS2 | 0x07000000; +pub const SIO_ASSOCIATE_HANDLE: DWORD = _WSAIOW!(IOC_WS2, 1); +pub const SIO_ENABLE_CIRCULAR_QUEUEING: DWORD = _WSAIO!(IOC_WS2, 2); +pub const SIO_FIND_ROUTE: DWORD = _WSAIOR!(IOC_WS2, 3); +pub const SIO_FLUSH: DWORD = _WSAIO!(IOC_WS2, 4); +pub const SIO_GET_BROADCAST_ADDRESS: DWORD = _WSAIOR!(IOC_WS2, 5); +pub const SIO_GET_EXTENSION_FUNCTION_POINTER: DWORD = _WSAIORW!(IOC_WS2, 6); +pub const SIO_GET_QOS: DWORD = _WSAIORW!(IOC_WS2, 7); +pub const SIO_GET_GROUP_QOS: DWORD = _WSAIORW!(IOC_WS2, 8); +pub const SIO_MULTIPOINT_LOOPBACK: DWORD = _WSAIOW!(IOC_WS2, 9); +pub const SIO_MULTICAST_SCOPE: DWORD = _WSAIOW!(IOC_WS2, 10); +pub const SIO_SET_QOS: DWORD = _WSAIOW!(IOC_WS2, 11); +pub const SIO_SET_GROUP_QOS: DWORD = _WSAIOW!(IOC_WS2, 12); +pub const SIO_TRANSLATE_HANDLE: DWORD = _WSAIORW!(IOC_WS2, 13); +pub const SIO_ROUTING_INTERFACE_QUERY: DWORD = _WSAIORW!(IOC_WS2, 20); +pub const SIO_ROUTING_INTERFACE_CHANGE: DWORD = _WSAIOW!(IOC_WS2, 21); +pub const SIO_ADDRESS_LIST_QUERY: DWORD = _WSAIOR!(IOC_WS2, 22); +pub const SIO_ADDRESS_LIST_CHANGE: DWORD = _WSAIO!(IOC_WS2, 23); +pub const SIO_QUERY_TARGET_PNP_HANDLE: DWORD = _WSAIOR!(IOC_WS2, 24); +pub const SIO_QUERY_RSS_PROCESSOR_INFO: DWORD = _WSAIOR!(IOC_WS2, 37); +pub const SIO_ADDRESS_LIST_SORT: DWORD = _WSAIORW!(IOC_WS2, 25); +pub const SIO_RESERVED_1: DWORD = _WSAIOW!(IOC_WS2, 26); +pub const SIO_RESERVED_2: DWORD = _WSAIOW!(IOC_WS2, 33); +pub const SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER: DWORD = _WSAIORW!(IOC_WS2, 36); +pub const IPPROTO_IP: c_int = 0; +ENUM!{enum IPPROTO { + IPPROTO_HOPOPTS = 0, // IPv6 Hop-by-Hop options + IPPROTO_ICMP = 1, + IPPROTO_IGMP = 2, + IPPROTO_GGP = 3, + IPPROTO_IPV4 = 4, + IPPROTO_ST = 5, + IPPROTO_TCP = 6, + IPPROTO_CBT = 7, + IPPROTO_EGP = 8, + IPPROTO_IGP = 9, + IPPROTO_PUP = 12, + IPPROTO_UDP = 17, + IPPROTO_IDP = 22, + IPPROTO_RDP = 27, + IPPROTO_IPV6 = 41, // IPv6 header + IPPROTO_ROUTING = 43, // IPv6 Routing header + IPPROTO_FRAGMENT = 44, // IPv6 fragmentation header + IPPROTO_ESP = 50, // encapsulating security payload + IPPROTO_AH = 51, // authentication header + IPPROTO_ICMPV6 = 58, // ICMPv6 + IPPROTO_NONE = 59, // IPv6 no next header + IPPROTO_DSTOPTS = 60, // IPv6 Destination options + IPPROTO_ND = 77, + IPPROTO_ICLFXBM = 78, + IPPROTO_PIM = 103, + IPPROTO_PGM = 113, + IPPROTO_L2TP = 115, + IPPROTO_SCTP = 132, + IPPROTO_RAW = 255, + IPPROTO_MAX = 256, + IPPROTO_RESERVED_RAW = 257, + IPPROTO_RESERVED_IPSEC = 258, + IPPROTO_RESERVED_IPSECOFFLOAD = 259, + IPPROTO_RESERVED_WNV = 260, + IPPROTO_RESERVED_MAX = 261, +}} +pub type PIPPROTO = *mut IPPROTO; +pub const IPPORT_TCPMUX: USHORT = 1; +pub const IPPORT_ECHO: USHORT = 7; +pub const IPPORT_DISCARD: USHORT = 9; +pub const IPPORT_SYSTAT: USHORT = 11; +pub const IPPORT_DAYTIME: USHORT = 13; +pub const IPPORT_NETSTAT: USHORT = 15; +pub const IPPORT_QOTD: USHORT = 17; +pub const IPPORT_MSP: USHORT = 18; +pub const IPPORT_CHARGEN: USHORT = 19; +pub const IPPORT_FTP_DATA: USHORT = 20; +pub const IPPORT_FTP: USHORT = 21; +pub const IPPORT_TELNET: USHORT = 23; +pub const IPPORT_SMTP: USHORT = 25; +pub const IPPORT_TIMESERVER: USHORT = 37; +pub const IPPORT_NAMESERVER: USHORT = 42; +pub const IPPORT_WHOIS: USHORT = 43; +pub const IPPORT_MTP: USHORT = 57; +pub const IPPORT_TFTP: USHORT = 69; +pub const IPPORT_RJE: USHORT = 77; +pub const IPPORT_FINGER: USHORT = 79; +pub const IPPORT_TTYLINK: USHORT = 87; +pub const IPPORT_SUPDUP: USHORT = 95; +pub const IPPORT_POP3: USHORT = 110; +pub const IPPORT_NTP: USHORT = 123; +pub const IPPORT_EPMAP: USHORT = 135; +pub const IPPORT_NETBIOS_NS: USHORT = 137; +pub const IPPORT_NETBIOS_DGM: USHORT = 138; +pub const IPPORT_NETBIOS_SSN: USHORT = 139; +pub const IPPORT_IMAP: USHORT = 143; +pub const IPPORT_SNMP: USHORT = 161; +pub const IPPORT_SNMP_TRAP: USHORT = 162; +pub const IPPORT_IMAP3: USHORT = 220; +pub const IPPORT_LDAP: USHORT = 389; +pub const IPPORT_HTTPS: USHORT = 443; +pub const IPPORT_MICROSOFT_DS: USHORT = 445; +pub const IPPORT_EXECSERVER: USHORT = 512; +pub const IPPORT_LOGINSERVER: USHORT = 513; +pub const IPPORT_CMDSERVER: USHORT = 514; +pub const IPPORT_EFSSERVER: USHORT = 520; +pub const IPPORT_BIFFUDP: USHORT = 512; +pub const IPPORT_WHOSERVER: USHORT = 513; +pub const IPPORT_ROUTESERVER: USHORT = 520; +pub const IPPORT_RESERVED: USHORT = 1024; +pub const IPPORT_REGISTERED_MIN: USHORT = IPPORT_RESERVED; +pub const IPPORT_REGISTERED_MAX: USHORT = 0xbfff; +pub const IPPORT_DYNAMIC_MIN: USHORT = 0xc000; +pub const IPPORT_DYNAMIC_MAX: USHORT = 0xffff; +#[inline] +pub fn IN_CLASSA(i: LONG) -> bool { + (i & 0x80000000) == 0 +} +pub const IN_CLASSA_NET: LONG = 0xff000000; +pub const IN_CLASSA_NSHIFT: LONG = 24; +pub const IN_CLASSA_HOST: LONG = 0x00ffffff; +pub const IN_CLASSA_MAX: LONG = 128; +#[inline] +pub fn IN_CLASSB(i: LONG) -> bool { + (i as u32 & 0xc0000000) == 0x80000000 +} +pub const IN_CLASSB_NET: LONG = 0xffff0000; +pub const IN_CLASSB_NSHIFT: LONG = 16; +pub const IN_CLASSB_HOST: LONG = 0x0000ffff; +pub const IN_CLASSB_MAX: LONG = 65536; +#[inline] +pub fn IN_CLASSC(i: LONG) -> bool { + (i as u32 & 0xe0000000) == 0xc0000000 +} +pub const IN_CLASSC_NET: LONG = 0xffffff00; +pub const IN_CLASSC_NSHIFT: LONG = 8; +pub const IN_CLASSC_HOST: LONG = 0x000000ff; +#[inline] +pub fn IN_CLASSD(i: c_long) -> bool { + (i as u32 & 0xf0000000) == 0xe0000000 +} +pub const IN_CLASSD_NET: LONG = 0xf0000000; +pub const IN_CLASSD_NSHIFT: LONG = 28; +pub const IN_CLASSD_HOST: LONG = 0x0fffffff; +#[inline] +pub fn IN_MULTICAST(i: c_long) -> bool { + IN_CLASSD(i) +} +pub const INADDR_ANY: ULONG = 0x00000000; +pub const INADDR_LOOPBACK: ULONG = 0x7f000001; +pub const INADDR_BROADCAST: ULONG = 0xffffffff; +pub const INADDR_NONE: ULONG = 0xffffffff; +ENUM!{enum SCOPE_LEVEL { + ScopeLevelInterface = 1, + ScopeLevelLink = 2, + ScopeLevelSubnet = 3, + ScopeLevelAdmin = 4, + ScopeLevelSite = 5, + ScopeLevelOrganization = 8, + ScopeLevelGlobal = 14, + ScopeLevelCount = 16, +}} +STRUCT!{struct SCOPE_ID_u_s { + bitfield: ULONG, +}} +BITFIELD!{SCOPE_ID_u_s bitfield: ULONG [ + Zone set_Zone[0..28], + Level set_Level[28..32], +]} +UNION!{union SCOPE_ID_u { + [u32; 1], + s s_mut: SCOPE_ID_u_s, + Value Value_mut: ULONG, +}} +STRUCT!{struct SCOPE_ID { + u: SCOPE_ID_u, +}} +pub type PSCOPE_ID = *mut SCOPE_ID; +STRUCT!{struct SOCKADDR_IN { + sin_family: ADDRESS_FAMILY, + sin_port: USHORT, + sin_addr: IN_ADDR, + sin_zero: [CHAR; 8], +}} +pub type PSOCKADDR_IN = *mut SOCKADDR_IN; +STRUCT!{struct SOCKADDR_DL { + sdl_family: ADDRESS_FAMILY, + sdl_data: [UCHAR; 8], + sdl_zero: [UCHAR; 4], +}} +pub type PSOCKADDR_DL = *mut SOCKADDR_DL; +pub const IOCPARM_MASK: DWORD = 0x7f; +pub const IOC_VOID: DWORD = 0x20000000; +pub const IOC_OUT: DWORD = 0x40000000; +pub const IOC_IN: DWORD = 0x80000000; +pub const IOC_INOUT: DWORD = IOC_IN | IOC_OUT; +STRUCT!{struct WSABUF { + len: ULONG, + buf: *mut CHAR, +}} +pub type LPWSABUF = *mut WSABUF; +STRUCT!{struct WSAMSG { + name: LPSOCKADDR, + namelen: INT, + lpBuffers: LPWSABUF, + dwBufferCount: ULONG, + Control: WSABUF, + dwFlags: ULONG, +}} +pub type PWSAMSG = *mut WSAMSG; +pub type LPWSAMSG = *mut WSAMSG; +STRUCT!{struct WSACMSGHDR { + cmsg_len: SIZE_T, + cmsg_level: INT, + cmsg_type: INT, +}} +pub type PWSACMSGHDR = *mut WSACMSGHDR; +pub type LPWSACMSGHDR = *mut WSACMSGHDR; +pub type CMSGHDR = WSACMSGHDR; +pub type PCMSGHDR = *mut WSACMSGHDR; +pub const MSG_TRUNC: ULONG = 0x0100; +pub const MSG_CTRUNC: ULONG = 0x0200; +pub const MSG_BCAST: ULONG = 0x0400; +pub const MSG_MCAST: ULONG = 0x0800; +pub const AI_PASSIVE: c_int = 0x00000001; +pub const AI_CANONNAME: c_int = 0x00000002; +pub const AI_NUMERICHOST: c_int = 0x00000004; +pub const AI_NUMERICSERV: c_int = 0x00000008; +pub const AI_DNS_ONLY: c_int = 0x00000010; +pub const AI_ALL: c_int = 0x00000100; +pub const AI_ADDRCONFIG: c_int = 0x00000400; +pub const AI_V4MAPPED: c_int = 0x00000800; +pub const AI_NON_AUTHORITATIVE: c_int = 0x00004000; +pub const AI_SECURE: c_int = 0x00008000; +pub const AI_RETURN_PREFERRED_NAMES: c_int = 0x00010000; +pub const AI_FQDN: c_int = 0x00020000; +pub const AI_FILESERVER: c_int = 0x00040000; +pub const AI_DISABLE_IDN_ENCODING: c_int = 0x00080000; +pub const AI_EXTENDED: c_int = 0x80000000; +pub const AI_RESOLUTION_HANDLE: c_int = 0x40000000; +STRUCT!{struct ADDRINFOA { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *mut c_char, + ai_addr: *mut SOCKADDR, + ai_next: *mut ADDRINFOA, +}} +pub type PADDRINFOA = *mut ADDRINFOA; +STRUCT!{struct ADDRINFOW { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: PWSTR, + ai_addr: *mut SOCKADDR, + ai_next: *mut ADDRINFOW, +}} +pub type PADDRINFOW = *mut ADDRINFOW; +STRUCT!{struct ADDRINFOEXA { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *mut c_char, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEXA, +}} +pub type PADDRINFOEXA = *mut ADDRINFOEXA; +pub type LPADDRINFOEXA = *mut ADDRINFOEXA; +STRUCT!{struct ADDRINFOEXW { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: PWSTR, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEXW, +}} +pub type PADDRINFOEXW = *mut ADDRINFOEXW; +pub type LPADDRINFOEXW = *mut ADDRINFOEXW; +pub const ADDRINFOEX_VERSION_2: c_int = 2; +pub const ADDRINFOEX_VERSION_3: c_int = 3; +pub const ADDRINFOEX_VERSION_4: c_int = 4; +STRUCT!{struct ADDRINFOEX2A { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *mut c_char, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEX2W, + ai_version: c_int, + ai_fqdn: *mut c_char, +}} +pub type PADDRINFOEX2A = *mut ADDRINFOEX2A; +pub type LPADDRINFOEX2A = *mut ADDRINFOEX2A; +STRUCT!{struct ADDRINFOEX2W { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: PWSTR, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEX2W, + ai_version: c_int, + ai_fqdn: PWSTR, +}} +pub type PADDRINFOEX2W = *mut ADDRINFOEX2W; +pub type LPADDRINFOEX2W = *mut ADDRINFOEX2W; +STRUCT!{struct ADDRINFOEX3A { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *mut c_char, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEX3W, + ai_version: c_int, + ai_fqdn: *mut c_char, + ai_interfaceindex: c_int, +}} +pub type PADDRINFOEX3A = *mut ADDRINFOEX3A; +pub type LPADDRINFOEX3A = *mut ADDRINFOEX3A; +STRUCT!{struct ADDRINFOEX3W { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: PWSTR, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEX3W, + ai_version: c_int, + ai_fqdn: PWSTR, + ai_interfaceindex: c_int, +}} +pub type PADDRINFOEX3W = *mut ADDRINFOEX3W; +pub type LPADDRINFOEX3W = *mut ADDRINFOEX3W; +STRUCT!{struct ADDRINFOEX4 { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: PWSTR, + ai_addr: *mut SOCKADDR, + ai_blob: *mut c_void, + ai_bloblen: size_t, + ai_provider: LPGUID, + ai_next: *mut ADDRINFOEX4, + ai_version: c_int, + ai_fqdn: PWSTR, + ai_interfaceindex: c_int, + ai_resolutionhandle: HANDLE, +}} +pub type PADDRINFOEX4 = *mut ADDRINFOEX4; +pub type LPADDRINFOEX4 = *mut ADDRINFOEX4; +pub const NS_ALL: DWORD = 0; +pub const NS_SAP: DWORD = 1; +pub const NS_NDS: DWORD = 2; +pub const NS_PEER_BROWSE: DWORD = 3; +pub const NS_SLP: DWORD = 5; +pub const NS_DHCP: DWORD = 6; +pub const NS_TCPIP_LOCAL: DWORD = 10; +pub const NS_TCPIP_HOSTS: DWORD = 11; +pub const NS_DNS: DWORD = 12; +pub const NS_NETBT: DWORD = 13; +pub const NS_WINS: DWORD = 14; +pub const NS_NLA: DWORD = 15; +pub const NS_BTH: DWORD = 16; +pub const NS_NBP: DWORD = 20; +pub const NS_MS: DWORD = 30; +pub const NS_STDA: DWORD = 31; +pub const NS_NTDS: DWORD = 32; +pub const NS_EMAIL: DWORD = 37; +pub const NS_PNRPNAME: DWORD = 38; +pub const NS_PNRPCLOUD: DWORD = 39; +pub const NS_X500: DWORD = 40; +pub const NS_NIS: DWORD = 41; +pub const NS_NISPLUS: DWORD = 42; +pub const NS_WRQ: DWORD = 50; +pub const NS_NETDES: DWORD = 60; +pub const NI_NOFQDN: c_int = 0x01; +pub const NI_NUMERICHOST: c_int = 0x02; +pub const NI_NAMEREQD: c_int = 0x04; +pub const NI_NUMERICSERV: c_int = 0x08; +pub const NI_DGRAM: c_int = 0x10; +pub const NI_MAXHOST: c_int = 1025; +pub const NI_MAXSERV: c_int = 32; diff --git a/winapi/src/shared/ws2ipdef.rs b/winapi/src/shared/ws2ipdef.rs new file mode 100644 index 000000000..b48518ecc --- /dev/null +++ b/winapi/src/shared/ws2ipdef.rs @@ -0,0 +1,92 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! TCP/IP specific information for use by WinSock2 compatible applications. +use ctypes::c_int; +use shared::in6addr::IN6_ADDR; +use shared::inaddr::IN_ADDR; +use shared::minwindef::{ULONG, USHORT}; +use shared::ws2def::{ADDRESS_FAMILY, SCOPE_ID}; +pub const IFF_UP: ULONG = 0x00000001; +pub const IFF_BROADCAST: ULONG = 0x00000002; +pub const IFF_LOOPBACK: ULONG = 0x00000004; +pub const IFF_POINTTOPOINT: ULONG = 0x00000008; +pub const IFF_MULTICAST: ULONG = 0x00000010; +pub const IP_OPTIONS: c_int = 1; +pub const IP_HDRINCL: c_int = 2; +pub const IP_TOS: c_int = 3; +pub const IP_TTL: c_int = 4; +pub const IP_MULTICAST_IF: c_int = 9; +pub const IP_MULTICAST_TTL: c_int = 10; +pub const IP_MULTICAST_LOOP: c_int = 11; +pub const IP_ADD_MEMBERSHIP: c_int = 12; +pub const IP_DROP_MEMBERSHIP: c_int = 13; +pub const IP_DONTFRAGMENT: c_int = 14; +pub const IP_ADD_SOURCE_MEMBERSHIP: c_int = 15; +pub const IP_DROP_SOURCE_MEMBERSHIP: c_int = 16; +pub const IP_BLOCK_SOURCE: c_int = 17; +pub const IP_UNBLOCK_SOURCE: c_int = 18; +pub const IP_PKTINFO: c_int = 19; +pub const IP_RECEIVE_BROADCAST: c_int = 22; +pub const IP_RECVDSTADDR: c_int = 25; +UNION!{union SOCKADDR_IN6_LH_u { + [u32; 1], + sin6_scope_id sin6_scope_id_mut: ULONG, + sin6_scope_struct sin6_scope_struct_mut: SCOPE_ID, +}} +STRUCT!{struct SOCKADDR_IN6_LH { + sin6_family: ADDRESS_FAMILY, + sin6_port: USHORT, + sin6_flowinfo: ULONG, + sin6_addr: IN6_ADDR, + u: SOCKADDR_IN6_LH_u, +}} +pub type PSOCKADDR_IN6_LH = *mut SOCKADDR_IN6_LH; +STRUCT!{struct IP_MREQ { + imr_multiaddr: IN_ADDR, + imr_interface: IN_ADDR, +}} +pub type PIP_MREQ = *mut IP_MREQ; +pub const IPV6_HOPOPTS: c_int = 1; +pub const IPV6_HDRINCL: c_int = 2; +pub const IPV6_UNICAST_HOPS: c_int = 4; +pub const IPV6_MULTICAST_IF: c_int = 9; +pub const IPV6_MULTICAST_HOPS: c_int = 10; +pub const IPV6_MULTICAST_LOOP: c_int = 11; +pub const IPV6_ADD_MEMBERSHIP: c_int = 12; +pub const IPV6_JOIN_GROUP: c_int = IPV6_ADD_MEMBERSHIP; +pub const IPV6_DROP_MEMBERSHIP: c_int = 13; +pub const IPV6_LEAVE_GROUP: c_int = IPV6_DROP_MEMBERSHIP; +pub const IPV6_DONTFRAG: c_int = 14; +pub const IPV6_PKTINFO: c_int = 19; +pub const IPV6_HOPLIMIT: c_int = 21; +pub const IPV6_PROTECTION_LEVEL: c_int = 23; +pub const IPV6_RECVIF: c_int = 24; +pub const IPV6_RECVDSTADDR: c_int = 25; +pub const IPV6_CHECKSUM: c_int = 26; +pub const IPV6_V6ONLY: c_int = 27; +pub const IPV6_IFLIST: c_int = 28; +pub const IPV6_ADD_IFLIST: c_int = 29; +pub const IPV6_DEL_IFLIST: c_int = 30; +pub const IPV6_UNICAST_IF: c_int = 31; +pub const IPV6_RTHDR: c_int = 32; +pub const IPV6_RECVRTHDR: c_int = 38; +pub const IPV6_TCLASS: c_int = 39; +pub const IPV6_RECVTCLASS: c_int = 40; +STRUCT!{struct IPV6_MREQ { + ipv6mr_multiaddr: IN6_ADDR, + ipv6mr_interface: ULONG, +}} +pub type PIPV6_MREQ = *mut IPV6_MREQ; +STRUCT!{struct IN_PKTINFO { + ipi_addr: IN_ADDR, + ipi_ifindex: ULONG, +}} +pub type PIN_PKTINFO = *mut IN_PKTINFO; +STRUCT!{struct IN6_PKTINFO { + ipi6_addr: IN6_ADDR, + ipi6_ifindex: ULONG, +}} +pub type PIN6_PKTINFO = *mut IN6_PKTINFO; diff --git a/winapi/src/shared/wtypes.rs b/winapi/src/shared/wtypes.rs new file mode 100644 index 000000000..8b5c88811 --- /dev/null +++ b/winapi/src/shared/wtypes.rs @@ -0,0 +1,344 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{__int64, c_double, c_short, c_ushort, c_void, wchar_t}; +use shared::guiddef::{CLSID, GUID}; +use shared::minwindef::{BYTE, DWORD, ULONG, USHORT, WORD}; +use shared::ntdef::{LCID, LONG, LONGLONG, ULONGLONG}; +use shared::rpcndr::byte; +use shared::wtypesbase::{ + BYTE_BLOB, DWORD_BLOB, FLAGGED_BYTE_BLOB, FLAGGED_WORD_BLOB, LPOLESTR, OLECHAR +}; +use um::wingdi::LOGPALETTE; +// extern RPC_IF_HANDLE __MIDL_itf_wtypes_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wtypes_0000_0000_v0_0_s_ifspec; +STRUCT!{struct RemHGLOBAL { + fNullHGlobal: LONG, + cbData: ULONG, + data: [byte; 1], +}} +STRUCT!{struct RemHMETAFILEPICT { + mm: LONG, + xExt: LONG, + yExt: LONG, + cbData: ULONG, + data: [byte; 1], +}} +STRUCT!{struct RemHENHMETAFILE { + cbData: ULONG, + data: [byte; 1], +}} +STRUCT!{struct RemHBITMAP { + cbData: ULONG, + data: [byte; 1], +}} +STRUCT!{struct RemHPALETTE { + cbData: ULONG, + data: [byte; 1], +}} +STRUCT!{struct RemHBRUSH { + cbData: ULONG, + data: [byte; 1], +}} +pub const ROTFLAGS_REGISTRATIONKEEPSALIVE: DWORD = 0x1; +pub const ROTFLAGS_ALLOWANYCLIENT: DWORD = 0x2; +pub const ROT_COMPARE_MAX: DWORD = 2048; +ENUM!{enum DVASPECT { + DVASPECT_CONTENT = 1, + DVASPECT_THUMBNAIL = 2, + DVASPECT_ICON = 4, + DVASPECT_DOCPRINT = 8, +}} +ENUM!{enum STGC { + STGC_DEFAULT = 0, + STGC_OVERWRITE = 1, + STGC_ONLYIFCURRENT = 2, + STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4, + STGC_CONSOLIDATE = 8, +}} +ENUM!{enum STGMOVE { + STGMOVE_MOVE = 0, + STGMOVE_COPY = 1, + STGMOVE_SHALLOWCOPY = 2, +}} +ENUM!{enum STATFLAG { + STATFLAG_DEFAULT = 0, + STATFLAG_NONAME = 1, + STATFLAG_NOOPEN = 2, +}} +pub type HCONTEXT = *mut c_void; +pub const WDT_INPROC_CALL: ULONG = 0x48746457; +pub const WDT_REMOTE_CALL: ULONG = 0x52746457; +pub const WDT_INPROC64_CALL: ULONG = 0x50746457; +UNION!{union userCLIPFORMAT_u { + [usize; 1], + dwValue dwValue_mut: DWORD, + pwszName pwszName_mut: *mut wchar_t, +}} +STRUCT!{struct userCLIPFORMAT { + fContext: LONG, + u: userCLIPFORMAT_u, +}} +pub type wireCLIPFORMAT = *mut userCLIPFORMAT; +pub type CLIPFORMAT = WORD; +UNION!{union GDI_NONREMOTE_u { + [usize; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut DWORD_BLOB, +}} +STRUCT!{struct GDI_NONREMOTE { + fContext: LONG, + u: GDI_NONREMOTE_u, +}} +UNION!{union userHGLOBAL_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut FLAGGED_BYTE_BLOB, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHGLOBAL { + fContext: LONG, + u: userHGLOBAL_u, +}} +pub type wireHGLOBAL = *mut userHGLOBAL; +UNION!{union userHMETAFILE_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut BYTE_BLOB, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHMETAFILE { + fContext: LONG, + u: userHMETAFILE_u, +}} +STRUCT!{struct remoteMETAFILEPICT { + mm: LONG, + xExt: LONG, + yExt: LONG, + hMF: *mut userHMETAFILE, +}} +UNION!{union userHMETAFILEPICT_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut remoteMETAFILEPICT, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHMETAFILEPICT { + fContext: LONG, + u: userHMETAFILEPICT_u, +}} +UNION!{union userHENHMETAFILE_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut BYTE_BLOB, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHENHMETAFILE { + fContext: LONG, + u: userHENHMETAFILE_u, +}} +STRUCT!{struct userBITMAP { + bmType: LONG, + bmWidth: LONG, + bmHeight: LONG, + bmWidthBytes: LONG, + bmPlanes: WORD, + bmBitsPixel: WORD, + cbSize: ULONG, + pBuffer: [byte; 1], +}} +UNION!{union userHBITMAP_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut userBITMAP, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHBITMAP { + fContext: LONG, + u: userHBITMAP_u, +}} +UNION!{union userHPALETTE_u { + [u64; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: *mut LOGPALETTE, + hInproc64 hInproc64_mut: __int64, +}} +STRUCT!{struct userHPALETTE { + fContext: LONG, + u: userHPALETTE_u, +}} +UNION!{union RemotableHandle_u { + [u32; 1], + hInproc hInproc_mut: LONG, + hRemote hRemote_mut: LONG, +}} +STRUCT!{struct RemotableHandle { + fContext: LONG, + u: RemotableHandle_u, +}} +pub type wireHWND = *mut RemotableHandle; +pub type wireHMENU = *mut RemotableHandle; +pub type wireHACCEL = *mut RemotableHandle; +pub type wireHBRUSH = *mut RemotableHandle; +pub type wireHFONT = *mut RemotableHandle; +pub type wireHDC = *mut RemotableHandle; +pub type wireHICON = *mut RemotableHandle; +pub type wireHRGN = *mut RemotableHandle; +pub type wireHMONITOR = *mut RemotableHandle; +pub type wireHBITMAP = *mut userHBITMAP; +pub type wireHPALETTE = *mut userHPALETTE; +pub type wireHENHMETAFILE = *mut userHENHMETAFILE; +pub type wireHMETAFILE = *mut userHMETAFILE; +pub type wireHMETAFILEPICT = *mut userHMETAFILEPICT; +pub type HMETAFILEPICT = *mut c_void; +// extern RPC_IF_HANDLE IWinTypes_v0_1_c_ifspec; +// extern RPC_IF_HANDLE IWinTypes_v0_1_s_ifspec; +pub type DATE = c_double; +STRUCT!{struct CY { + int64: LONGLONG, +}} +pub type LPCY = *mut CY; +STRUCT!{struct DECIMAL { + wReserved: USHORT, + scale: BYTE, + sign: BYTE, + Hi32: ULONG, + Lo64: ULONGLONG, +}} +pub const DECIMAL_NEG: BYTE = 0x80; +#[inline] +pub fn DECIMAL_SETZERO(dec: &mut DECIMAL) { + dec.Lo64 = 0; + dec.Hi32 = 0; + dec.scale = 0; + dec.sign = 0; +} +pub type LPDECIMAL = *mut DECIMAL; +pub type wireBSTR = *mut FLAGGED_WORD_BLOB; +pub type BSTR = *mut OLECHAR; +pub type LPBSTR = *mut BSTR; +pub type VARIANT_BOOL = c_short; +STRUCT!{struct BSTRBLOB { + cbSize: ULONG, + pData: *mut BYTE, +}} +pub type LPBSTRBLOB = *mut BSTRBLOB; +pub const VARIANT_TRUE: VARIANT_BOOL = -1; +pub const VARIANT_FALSE: VARIANT_BOOL = 0; +STRUCT!{struct CLIPDATA { + cbSize: ULONG, + ulClipFmt: LONG, + pClipData: *mut BYTE, +}} +#[inline] +pub fn CBPCLIPDATA(clipdata: CLIPDATA) -> ULONG { + clipdata.cbSize - 4 +} +pub type VARTYPE = c_ushort; +ENUM!{enum VARENUM { + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_INT_PTR = 37, + VT_UINT_PTR = 38, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_VERSIONED_STREAM = 73, + VT_BSTR_BLOB = 0xfff, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000, + VT_RESERVED = 0x8000, + VT_ILLEGAL = 0xffff, + VT_ILLEGALMASKED = 0xfff, + VT_TYPEMASK = 0xfff, +}} +pub type PROPID = ULONG; +STRUCT!{struct PROPERTYKEY { + fmtid: GUID, + pid: DWORD, +}} +STRUCT!{struct CSPLATFORM { + dwPlatformId: DWORD, + dwVersionHi: DWORD, + dwVersionLo: DWORD, + dwProcessorArch: DWORD, +}} +STRUCT!{struct QUERYCONTEXT { + dwContext: DWORD, + Platform: CSPLATFORM, + Locale: LCID, + dwVersionHi: DWORD, + dwVersionLo: DWORD, +}} +ENUM!{enum TYSPEC { + TYSPEC_CLSID, + TYSPEC_FILEEXT, + TYSPEC_MIMETYPE, + TYSPEC_FILENAME, + TYSPEC_PROGID, + TYSPEC_PACKAGENAME, + TYSPEC_OBJECTID, +}} +STRUCT!{struct uCLSSPEC_ByName { + pPackageName: LPOLESTR, + PolicyId: GUID, +}} +STRUCT!{struct uCLSSPEC_ByObjectId { + ObjectId: GUID, + PolicyId: GUID, +}} +UNION!{union uCLSSPEC_u { + [u32; 8] [u64; 4], + clsid clsid_mut: CLSID, + pFileExt pFileExt_mut: LPOLESTR, + pMimeType pMimeType_mut: LPOLESTR, + pProgId pProgId_mut: LPOLESTR, + pFileName pFileName_mut: LPOLESTR, + ByName ByName_mut: uCLSSPEC_ByName, + ByObjectId ByObjectId_mut: uCLSSPEC_ByObjectId, +}} +STRUCT!{struct uCLSSPEC { + tyspec: DWORD, + u: uCLSSPEC_u, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wtypes_0000_0001_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wtypes_0000_0001_v0_0_s_ifspec; diff --git a/winapi/src/shared/wtypesbase.rs b/winapi/src/shared/wtypesbase.rs new file mode 100644 index 000000000..e8ca7ee08 --- /dev/null +++ b/winapi/src/shared/wtypesbase.rs @@ -0,0 +1,161 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_double, c_short, c_uchar, c_ushort}; +use shared::minwindef::{BYTE, DWORD}; +use shared::rpcndr::{boolean, byte, hyper}; +use um::winnt::{LONG, LPWSTR, WCHAR}; +pub type OLECHAR = WCHAR; +pub type LPOLESTR = *mut OLECHAR; +pub type LPCOLESTR = *const OLECHAR; +pub type UCHAR = c_uchar; +pub type SHORT = c_short; +pub type USHORT = c_ushort; +pub type ULONG = DWORD; +pub type DOUBLE = c_double; +STRUCT!{struct COAUTHIDENTITY { + User: *mut USHORT, + UserLength: ULONG, + Domain: *mut USHORT, + DomainLength: ULONG, + Password: *mut USHORT, + PasswordLength: ULONG, + Flags: ULONG, +}} +STRUCT!{struct COAUTHINFO { + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pwszServerPrincName: LPWSTR, + dwAuthnLevel: DWORD, + dwImpersonationLevel: DWORD, + pAuthIdentityData: *mut COAUTHIDENTITY, + dwCapabilities: DWORD, +}} +pub type SCODE = LONG; +pub type PSCODE = *mut SCODE; +ENUM!{enum MEMCTX { + MEMCTX_TASK = 1, + MEMCTX_SHARED = 2, + MEMCTX_MACSYSTEM = 3, + MEMCTX_UNKNOWN = -1i32 as u32, + MEMCTX_SAME = -2i32 as u32, +}} +pub const ROTREGFLAGS_ALLOWANYCLIENT: DWORD = 0x1; +pub const APPIDREGFLAGS_ACTIVATE_IUSERVER_INDESKTOP: DWORD = 0x1; +pub const APPIDREGFLAGS_SECURE_SERVER_PROCESS_SD_AND_BIND: DWORD = 0x2; +pub const APPIDREGFLAGS_ISSUE_ACTIVATION_RPC_AT_IDENTIFY: DWORD = 0x4; +pub const APPIDREGFLAGS_IUSERVER_UNMODIFIED_LOGON_TOKEN: DWORD = 0x8; +pub const APPIDREGFLAGS_IUSERVER_SELF_SID_IN_LAUNCH_PERMISSION: DWORD = 0x10; +pub const APPIDREGFLAGS_IUSERVER_ACTIVATE_IN_CLIENT_SESSION_ONLY: DWORD = 0x20; +pub const APPIDREGFLAGS_RESERVED1: DWORD = 0x40; +pub const APPIDREGFLAGS_RESERVED2: DWORD = 0x80; +pub const APPIDREGFLAGS_RESERVED3: DWORD = 0x100; +pub const APPIDREGFLAGS_RESERVED4: DWORD = 0x200; +pub const APPIDREGFLAGS_RESERVED5: DWORD = 0x400; +pub const APPIDREGFLAGS_RESERVED6: DWORD = 0x800; +pub const DCOMSCM_ACTIVATION_USE_ALL_AUTHNSERVICES: DWORD = 0x1; +pub const DCOMSCM_ACTIVATION_DISALLOW_UNSECURE_CALL: DWORD = 0x2; +pub const DCOMSCM_RESOLVE_USE_ALL_AUTHNSERVICES: DWORD = 0x4; +pub const DCOMSCM_RESOLVE_DISALLOW_UNSECURE_CALL: DWORD = 0x8; +pub const DCOMSCM_PING_USE_MID_AUTHNSERVICE: DWORD = 0x10; +pub const DCOMSCM_PING_DISALLOW_UNSECURE_CALL: DWORD = 0x20; +ENUM!{enum CLSCTX { + CLSCTX_INPROC_SERVER = 0x1, + CLSCTX_INPROC_HANDLER = 0x2, + CLSCTX_LOCAL_SERVER = 0x4, + CLSCTX_INPROC_SERVER16 = 0x8, + CLSCTX_REMOTE_SERVER = 0x10, + CLSCTX_INPROC_HANDLER16 = 0x20, + CLSCTX_RESERVED1 = 0x40, + CLSCTX_RESERVED2 = 0x80, + CLSCTX_RESERVED3 = 0x100, + CLSCTX_RESERVED4 = 0x200, + CLSCTX_NO_CODE_DOWNLOAD = 0x400, + CLSCTX_RESERVED5 = 0x800, + CLSCTX_NO_CUSTOM_MARSHAL = 0x1000, + CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000, + CLSCTX_NO_FAILURE_LOG = 0x4000, + CLSCTX_DISABLE_AAA = 0x8000, + CLSCTX_ENABLE_AAA = 0x10000, + CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000, + CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000, + CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000, + CLSCTX_ENABLE_CLOAKING = 0x100000, + CLSCTX_APPCONTAINER = 0x400000, + CLSCTX_ACTIVATE_AAA_AS_IU = 0x800000, + CLSCTX_PS_DLL = 0x80000000, +}} +pub const CLSCTX_VALID_MASK: CLSCTX = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER + | CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER16 | CLSCTX_REMOTE_SERVER + | CLSCTX_NO_CODE_DOWNLOAD | CLSCTX_NO_CUSTOM_MARSHAL | CLSCTX_ENABLE_CODE_DOWNLOAD + | CLSCTX_NO_FAILURE_LOG | CLSCTX_DISABLE_AAA | CLSCTX_ENABLE_AAA | CLSCTX_FROM_DEFAULT_CONTEXT + | CLSCTX_ACTIVATE_32_BIT_SERVER | CLSCTX_ACTIVATE_64_BIT_SERVER | CLSCTX_ENABLE_CLOAKING + | CLSCTX_APPCONTAINER | CLSCTX_ACTIVATE_AAA_AS_IU | CLSCTX_PS_DLL; +ENUM!{enum MSHLFLAGS { + MSHLFLAGS_NORMAL = 0, + MSHLFLAGS_TABLESTRONG = 1, + MSHLFLAGS_TABLEWEAK = 2, + MSHLFLAGS_NOPING = 4, + MSHLFLAGS_RESERVED1 = 8, + MSHLFLAGS_RESERVED2 = 16, + MSHLFLAGS_RESERVED3 = 32, + MSHLFLAGS_RESERVED4 = 64, +}} +ENUM!{enum MSHCTX { + MSHCTX_LOCAL = 0, + MSHCTX_NOSHAREDMEM = 1, + MSHCTX_DIFFERENTMACHINE = 2, + MSHCTX_INPROC = 3, + MSHCTX_CROSSCTX = 4, +}} +STRUCT!{struct BYTE_BLOB { + clSize: ULONG, + abData: [byte; 1], +}} +pub type UP_BYTE_BLOB = *mut BYTE_BLOB; +STRUCT!{struct WORD_BLOB { + clSize: ULONG, + asData: [c_ushort; 1], +}} +pub type UP_WORD_BLOB = *mut WORD_BLOB; +STRUCT!{struct DWORD_BLOB { + clSize: ULONG, + alData: [ULONG; 1], +}} +pub type UP_DWORD_BLOB = *mut DWORD_BLOB; +STRUCT!{struct FLAGGED_BYTE_BLOB { + fFlags: ULONG, + clSize: ULONG, + abData: [byte; 1], +}} +pub type UP_FLAGGED_BYTE_BLOB = *mut FLAGGED_BYTE_BLOB; +STRUCT!{struct FLAGGED_WORD_BLOB { + fFlags: ULONG, + clSize: ULONG, + alData: [ULONG; 1], +}} +pub type UP_FLAGGED_WORD_BLOB = *mut FLAGGED_WORD_BLOB; +STRUCT!{struct BYTE_SIZEDARR { + clSize: ULONG, + pData: *mut byte, +}} +STRUCT!{struct WORD_SIZEDARR { + clSize: ULONG, + pData: *mut c_ushort, +}} +STRUCT!{struct DWORD_SIZEDARR { + clSize: ULONG, + pData: *mut ULONG, +}} +STRUCT!{struct HYPER_SIZEDARR { + clSize: ULONG, + pData: *mut hyper, +}} +pub type BOOLEAN = boolean; +STRUCT!{struct BLOB { + cbSize: ULONG, + pBlobData: *mut BYTE, +}} +pub type LPBLOB = *mut BLOB; diff --git a/winapi/src/um/accctrl.rs b/winapi/src/um/accctrl.rs new file mode 100644 index 000000000..829ce5793 --- /dev/null +++ b/winapi/src/um/accctrl.rs @@ -0,0 +1,371 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, ULONG}; +use um::winbase::LocalFree; +use um::winnt::{HANDLE, LONG, LPSTR, LPWSTR, PVOID, SID}; +#[inline] +pub unsafe fn AccFree(p: PVOID) -> PVOID { + LocalFree(p) +} +ENUM!{enum SE_OBJECT_TYPE { + SE_UNKNOWN_OBJECT_TYPE = 0, + SE_FILE_OBJECT, + SE_SERVICE, + SE_PRINTER, + SE_REGISTRY_KEY, + SE_LMSHARE, + SE_KERNEL_OBJECT, + SE_WINDOW_OBJECT, + SE_DS_OBJECT, + SE_DS_OBJECT_ALL, + SE_PROVIDER_DEFINED_OBJECT, + SE_WMIGUID_OBJECT, + SE_REGISTRY_WOW64_32KEY, + SE_REGISTRY_WOW64_64KEY, +}} +ENUM!{enum TRUSTEE_TYPE { + TRUSTEE_IS_UNKNOWN, + TRUSTEE_IS_USER, + TRUSTEE_IS_GROUP, + TRUSTEE_IS_DOMAIN, + TRUSTEE_IS_ALIAS, + TRUSTEE_IS_WELL_KNOWN_GROUP, + TRUSTEE_IS_DELETED, + TRUSTEE_IS_INVALID, + TRUSTEE_IS_COMPUTER, +}} +ENUM!{enum TRUSTEE_FORM { + TRUSTEE_IS_SID, + TRUSTEE_IS_NAME, + TRUSTEE_BAD_FORM, + TRUSTEE_IS_OBJECTS_AND_SID, + TRUSTEE_IS_OBJECTS_AND_NAME, +}} +ENUM!{enum MULTIPLE_TRUSTEE_OPERATION { + NO_MULTIPLE_TRUSTEE, + TRUSTEE_IS_IMPERSONATE, +}} +STRUCT!{struct OBJECTS_AND_SID { + ObjectsPresent: DWORD, + ObjectTypeGuid: GUID, + InheritedObjectTypeGuid: GUID, + pSid: *mut SID, +}} +pub type POBJECTS_AND_SID = *mut OBJECTS_AND_SID; +STRUCT!{struct OBJECTS_AND_NAME_A { + ObjectsPresent: DWORD, + ObjectType: SE_OBJECT_TYPE, + ObjectTypeName: LPSTR, + InheritedObjectTypeName: LPSTR, + ptstrName: LPSTR, +}} +pub type POBJECTS_AND_NAME_A = *mut OBJECTS_AND_NAME_A; +STRUCT!{struct OBJECTS_AND_NAME_W { + ObjectsPresent: DWORD, + ObjectType: SE_OBJECT_TYPE, + ObjectTypeName: LPWSTR, + InheritedObjectTypeName: LPWSTR, + ptstrName: LPWSTR, +}} +pub type POBJECTS_AND_NAME_W = *mut OBJECTS_AND_NAME_W; +STRUCT!{struct TRUSTEE_A { + pMultipleTrustee: *mut TRUSTEE_A, + MultipleTrusteeOperation: MULTIPLE_TRUSTEE_OPERATION, + TrusteeForm: TRUSTEE_FORM, + TrusteeType: TRUSTEE_TYPE, + ptstrName: LPSTR, +}} +pub type PTRUSTEE_A = *mut TRUSTEE_A; +pub type TRUSTEEA = TRUSTEE_A; +pub type PTRUSTEEA = PTRUSTEE_A; +STRUCT!{struct TRUSTEE_W { + pMultipleTrustee: *mut TRUSTEE_W, + MultipleTrusteeOperation: MULTIPLE_TRUSTEE_OPERATION, + TrusteeForm: TRUSTEE_FORM, + TrusteeType: TRUSTEE_TYPE, + ptstrName: LPWSTR, +}} +pub type PTRUSTEE_W = *mut TRUSTEE_W; +pub type TRUSTEEW = TRUSTEE_W; +pub type PTRUSTEEW = PTRUSTEE_W; +ENUM!{enum ACCESS_MODE { + NOT_USED_ACCESS = 0, + GRANT_ACCESS, + SET_ACCESS, + DENY_ACCESS, + REVOKE_ACCESS, + SET_AUDIT_SUCCESS, + SET_AUDIT_FAILURE, +}} +pub const NO_INHERITANCE: DWORD = 0x0; +pub const SUB_OBJECTS_ONLY_INHERIT: DWORD = 0x1; +pub const SUB_CONTAINERS_ONLY_INHERIT: DWORD = 0x2; +pub const SUB_CONTAINERS_AND_OBJECTS_INHERIT: DWORD = 0x3; +pub const INHERIT_NO_PROPAGATE: DWORD = 0x4; +pub const INHERIT_ONLY: DWORD = 0x8; +pub const INHERITED_ACCESS_ENTRY: DWORD = 0x10; +pub const INHERITED_PARENT: DWORD = 0x10000000; +pub const INHERITED_GRANDPARENT: DWORD = 0x20000000; +STRUCT!{struct EXPLICIT_ACCESS_A { + grfAccessPermissions: DWORD, + grfAccessMode: ACCESS_MODE, + grfInheritance: DWORD, + Trustee: TRUSTEE_A, +}} +pub type PEXPLICIT_ACCESS_A = *mut EXPLICIT_ACCESS_A; +pub type EXPLICIT_ACCESSA = EXPLICIT_ACCESS_A; +pub type PEXPLICIT_ACCESSA = PEXPLICIT_ACCESS_A; +STRUCT!{struct EXPLICIT_ACCESS_W { + grfAccessPermissions: DWORD, + grfAccessMode: ACCESS_MODE, + grfInheritance: DWORD, + Trustee: TRUSTEE_W, +}} +pub type PEXPLICIT_ACCESS_W = *mut EXPLICIT_ACCESS_W; +pub type EXPLICIT_ACCESSW = EXPLICIT_ACCESS_W; +pub type PEXPLICIT_ACCESSW = PEXPLICIT_ACCESS_W; +pub const ACCCTRL_DEFAULT_PROVIDER: &'static str = "Windows NT Access Provider"; +pub type ACCESS_RIGHTS = ULONG; +pub type PACCESS_RIGHTS = *mut ACCESS_RIGHTS; +pub type INHERIT_FLAGS = ULONG; +pub type PINHERIT_FLAGS = *mut INHERIT_FLAGS; +STRUCT!{struct ACTRL_ACCESS_ENTRYA { + Trustee: TRUSTEE_A, + fAccessFlags: ULONG, + Access: ACCESS_RIGHTS, + ProvSpecificAccess: ACCESS_RIGHTS, + Inheritance: INHERIT_FLAGS, + lpInheritProperty: LPSTR, +}} +pub type PACTRL_ACCESS_ENTRYA = *mut ACTRL_ACCESS_ENTRYA; +STRUCT!{struct ACTRL_ACCESS_ENTRYW { + Trustee: TRUSTEE_W, + fAccessFlags: ULONG, + Access: ACCESS_RIGHTS, + ProvSpecificAccess: ACCESS_RIGHTS, + Inheritance: INHERIT_FLAGS, + lpInheritProperty: LPWSTR, +}} +pub type PACTRL_ACCESS_ENTRYW = *mut ACTRL_ACCESS_ENTRYW; +STRUCT!{struct ACTRL_ACCESS_ENTRY_LISTA { + cEntries: ULONG, + pAccessList: *mut ACTRL_ACCESS_ENTRYA, +}} +pub type PACTRL_ACCESS_ENTRY_LISTA = *mut ACTRL_ACCESS_ENTRY_LISTA; +STRUCT!{struct ACTRL_ACCESS_ENTRY_LISTW { + cEntries: ULONG, + pAccessList: *mut ACTRL_ACCESS_ENTRYW, +}} +pub type PACTRL_ACCESS_ENTRY_LISTW = *mut ACTRL_ACCESS_ENTRY_LISTW; +STRUCT!{struct ACTRL_PROPERTY_ENTRYA { + lpProperty: LPSTR, + pAccessEntryList: PACTRL_ACCESS_ENTRY_LISTA, + fListFlags: ULONG, +}} +pub type PACTRL_PROPERTY_ENTRYA = *mut ACTRL_PROPERTY_ENTRYA; +STRUCT!{struct ACTRL_PROPERTY_ENTRYW { + lpProperty: LPWSTR, + pAccessEntryList: PACTRL_ACCESS_ENTRY_LISTW, + fListFlags: ULONG, +}} +pub type PACTRL_PROPERTY_ENTRYW = *mut ACTRL_PROPERTY_ENTRYW; +STRUCT!{struct ACTRL_ACCESSA { + cEntries: ULONG, + pPropertyAccessList: PACTRL_PROPERTY_ENTRYA, +}} +pub type PACTRL_ACCESSA = *mut ACTRL_ACCESSA; +pub type ACTRL_AUDITA = ACTRL_ACCESSA; +pub type PACTRL_AUDITA = *mut ACTRL_AUDITA; +STRUCT!{struct ACTRL_ACCESSW { + cEntries: ULONG, + pPropertyAccessList: PACTRL_PROPERTY_ENTRYW, +}} +pub type PACTRL_ACCESSW = *mut ACTRL_ACCESSW; +pub type ACTRL_AUDITW = ACTRL_ACCESSW; +pub type PACTRL_AUDITW = *mut ACTRL_AUDITW; +pub const TRUSTEE_ACCESS_ALLOWED: ULONG = 0x00000001; +pub const TRUSTEE_ACCESS_READ: ULONG = 0x00000002; +pub const TRUSTEE_ACCESS_WRITE: ULONG = 0x00000004; +pub const TRUSTEE_ACCESS_EXPLICIT: ULONG = 0x00000001; +pub const TRUSTEE_ACCESS_READ_WRITE: ULONG = TRUSTEE_ACCESS_READ | TRUSTEE_ACCESS_WRITE; +pub const TRUSTEE_ACCESS_ALL: ULONG = 0xFFFFFFFF; +STRUCT!{struct TRUSTEE_ACCESSA { + lpProperty: LPSTR, + Access: ACCESS_RIGHTS, + fAccessFlags: ULONG, + fReturnedAccess: ULONG, +}} +pub type PTRUSTEE_ACCESSA = *mut TRUSTEE_ACCESSA; +STRUCT!{struct TRUSTEE_ACCESSW { + lpProperty: LPWSTR, + Access: ACCESS_RIGHTS, + fAccessFlags: ULONG, + fReturnedAccess: ULONG, +}} +pub type PTRUSTEE_ACCESSW = *mut TRUSTEE_ACCESSW; +pub const ACTRL_RESERVED: ULONG = 0x00000000; +pub const ACTRL_PERM_1: ULONG = 0x00000001; +pub const ACTRL_PERM_2: ULONG = 0x00000002; +pub const ACTRL_PERM_3: ULONG = 0x00000004; +pub const ACTRL_PERM_4: ULONG = 0x00000008; +pub const ACTRL_PERM_5: ULONG = 0x00000010; +pub const ACTRL_PERM_6: ULONG = 0x00000020; +pub const ACTRL_PERM_7: ULONG = 0x00000040; +pub const ACTRL_PERM_8: ULONG = 0x00000080; +pub const ACTRL_PERM_9: ULONG = 0x00000100; +pub const ACTRL_PERM_10: ULONG = 0x00000200; +pub const ACTRL_PERM_11: ULONG = 0x00000400; +pub const ACTRL_PERM_12: ULONG = 0x00000800; +pub const ACTRL_PERM_13: ULONG = 0x00001000; +pub const ACTRL_PERM_14: ULONG = 0x00002000; +pub const ACTRL_PERM_15: ULONG = 0x00004000; +pub const ACTRL_PERM_16: ULONG = 0x00008000; +pub const ACTRL_PERM_17: ULONG = 0x00010000; +pub const ACTRL_PERM_18: ULONG = 0x00020000; +pub const ACTRL_PERM_19: ULONG = 0x00040000; +pub const ACTRL_PERM_20: ULONG = 0x00080000; +pub const ACTRL_ACCESS_ALLOWED: ULONG = 0x00000001; +pub const ACTRL_ACCESS_DENIED: ULONG = 0x00000002; +pub const ACTRL_AUDIT_SUCCESS: ULONG = 0x00000004; +pub const ACTRL_AUDIT_FAILURE: ULONG = 0x00000008; +pub const ACTRL_ACCESS_PROTECTED: ULONG = 0x00000001; +pub const ACTRL_SYSTEM_ACCESS: ULONG = 0x04000000; +pub const ACTRL_DELETE: ULONG = 0x08000000; +pub const ACTRL_READ_CONTROL: ULONG = 0x10000000; +pub const ACTRL_CHANGE_ACCESS: ULONG = 0x20000000; +pub const ACTRL_CHANGE_OWNER: ULONG = 0x40000000; +pub const ACTRL_SYNCHRONIZE: ULONG = 0x80000000; +pub const ACTRL_STD_RIGHTS_ALL: ULONG = 0xf8000000; +pub const ACTRL_STD_RIGHT_REQUIRED: ULONG = ACTRL_STD_RIGHTS_ALL & !ACTRL_SYNCHRONIZE; +pub const ACTRL_DS_OPEN: ULONG = ACTRL_RESERVED; +pub const ACTRL_DS_CREATE_CHILD: ULONG = ACTRL_PERM_1; +pub const ACTRL_DS_DELETE_CHILD: ULONG = ACTRL_PERM_2; +pub const ACTRL_DS_LIST: ULONG = ACTRL_PERM_3; +pub const ACTRL_DS_SELF: ULONG = ACTRL_PERM_4; +pub const ACTRL_DS_READ_PROP: ULONG = ACTRL_PERM_5; +pub const ACTRL_DS_WRITE_PROP: ULONG = ACTRL_PERM_6; +pub const ACTRL_DS_DELETE_TREE: ULONG = ACTRL_PERM_7; +pub const ACTRL_DS_LIST_OBJECT: ULONG = ACTRL_PERM_8; +pub const ACTRL_DS_CONTROL_ACCESS: ULONG = ACTRL_PERM_9; +pub const ACTRL_FILE_READ: ULONG = ACTRL_PERM_1; +pub const ACTRL_FILE_WRITE: ULONG = ACTRL_PERM_2; +pub const ACTRL_FILE_APPEND: ULONG = ACTRL_PERM_3; +pub const ACTRL_FILE_READ_PROP: ULONG = ACTRL_PERM_4; +pub const ACTRL_FILE_WRITE_PROP: ULONG = ACTRL_PERM_5; +pub const ACTRL_FILE_EXECUTE: ULONG = ACTRL_PERM_6; +pub const ACTRL_FILE_READ_ATTRIB: ULONG = ACTRL_PERM_8; +pub const ACTRL_FILE_WRITE_ATTRIB: ULONG = ACTRL_PERM_9; +pub const ACTRL_FILE_CREATE_PIPE: ULONG = ACTRL_PERM_10; +pub const ACTRL_DIR_LIST: ULONG = ACTRL_PERM_1; +pub const ACTRL_DIR_CREATE_OBJECT: ULONG = ACTRL_PERM_2; +pub const ACTRL_DIR_CREATE_CHILD: ULONG = ACTRL_PERM_3; +pub const ACTRL_DIR_DELETE_CHILD: ULONG = ACTRL_PERM_7; +pub const ACTRL_DIR_TRAVERSE: ULONG = ACTRL_PERM_6; +pub const ACTRL_KERNEL_TERMINATE: ULONG = ACTRL_PERM_1; +pub const ACTRL_KERNEL_THREAD: ULONG = ACTRL_PERM_2; +pub const ACTRL_KERNEL_VM: ULONG = ACTRL_PERM_3; +pub const ACTRL_KERNEL_VM_READ: ULONG = ACTRL_PERM_4; +pub const ACTRL_KERNEL_VM_WRITE: ULONG = ACTRL_PERM_5; +pub const ACTRL_KERNEL_DUP_HANDLE: ULONG = ACTRL_PERM_6; +pub const ACTRL_KERNEL_PROCESS: ULONG = ACTRL_PERM_7; +pub const ACTRL_KERNEL_SET_INFO: ULONG = ACTRL_PERM_8; +pub const ACTRL_KERNEL_GET_INFO: ULONG = ACTRL_PERM_9; +pub const ACTRL_KERNEL_CONTROL: ULONG = ACTRL_PERM_10; +pub const ACTRL_KERNEL_ALERT: ULONG = ACTRL_PERM_11; +pub const ACTRL_KERNEL_GET_CONTEXT: ULONG = ACTRL_PERM_12; +pub const ACTRL_KERNEL_SET_CONTEXT: ULONG = ACTRL_PERM_13; +pub const ACTRL_KERNEL_TOKEN: ULONG = ACTRL_PERM_14; +pub const ACTRL_KERNEL_IMPERSONATE: ULONG = ACTRL_PERM_15; +pub const ACTRL_KERNEL_DIMPERSONATE: ULONG = ACTRL_PERM_16; +pub const ACTRL_PRINT_SADMIN: ULONG = ACTRL_PERM_1; +pub const ACTRL_PRINT_SLIST: ULONG = ACTRL_PERM_2; +pub const ACTRL_PRINT_PADMIN: ULONG = ACTRL_PERM_3; +pub const ACTRL_PRINT_PUSE: ULONG = ACTRL_PERM_4; +pub const ACTRL_PRINT_JADMIN: ULONG = ACTRL_PERM_5; +pub const ACTRL_SVC_GET_INFO: ULONG = ACTRL_PERM_1; +pub const ACTRL_SVC_SET_INFO: ULONG = ACTRL_PERM_2; +pub const ACTRL_SVC_STATUS: ULONG = ACTRL_PERM_3; +pub const ACTRL_SVC_LIST: ULONG = ACTRL_PERM_4; +pub const ACTRL_SVC_START: ULONG = ACTRL_PERM_5; +pub const ACTRL_SVC_STOP: ULONG = ACTRL_PERM_6; +pub const ACTRL_SVC_PAUSE: ULONG = ACTRL_PERM_7; +pub const ACTRL_SVC_INTERROGATE: ULONG = ACTRL_PERM_8; +pub const ACTRL_SVC_UCONTROL: ULONG = ACTRL_PERM_9; +pub const ACTRL_REG_QUERY: ULONG = ACTRL_PERM_1; +pub const ACTRL_REG_SET: ULONG = ACTRL_PERM_2; +pub const ACTRL_REG_CREATE_CHILD: ULONG = ACTRL_PERM_3; +pub const ACTRL_REG_LIST: ULONG = ACTRL_PERM_4; +pub const ACTRL_REG_NOTIFY: ULONG = ACTRL_PERM_5; +pub const ACTRL_REG_LINK: ULONG = ACTRL_PERM_6; +pub const ACTRL_WIN_CLIPBRD: ULONG = ACTRL_PERM_1; +pub const ACTRL_WIN_GLOBAL_ATOMS: ULONG = ACTRL_PERM_2; +pub const ACTRL_WIN_CREATE: ULONG = ACTRL_PERM_3; +pub const ACTRL_WIN_LIST_DESK: ULONG = ACTRL_PERM_4; +pub const ACTRL_WIN_LIST: ULONG = ACTRL_PERM_5; +pub const ACTRL_WIN_READ_ATTRIBS: ULONG = ACTRL_PERM_6; +pub const ACTRL_WIN_WRITE_ATTRIBS: ULONG = ACTRL_PERM_7; +pub const ACTRL_WIN_SCREEN: ULONG = ACTRL_PERM_8; +pub const ACTRL_WIN_EXIT: ULONG = ACTRL_PERM_9; +UNION!{union ACTRL_OVERLAPPED_u { + [u32; 1] [u64; 1], + Provider Provider_mut: PVOID, + Reserved1 Reserved1_mut: ULONG, +}} +STRUCT!{struct ACTRL_OVERLAPPED { + u: ACTRL_OVERLAPPED_u, + Reserved2: ULONG, + hEvent: HANDLE, +}} +pub type PACTRL_OVERLAPPED = *mut ACTRL_OVERLAPPED; +STRUCT!{struct ACTRL_ACCESS_INFOA { + fAccessPermission: ULONG, + lpAccessPermissionName: LPSTR, +}} +pub type PACTRL_ACCESS_INFOA = *mut ACTRL_ACCESS_INFOA; +STRUCT!{struct ACTRL_ACCESS_INFOW { + fAccessPermission: ULONG, + lpAccessPermissionName: LPWSTR, +}} +pub type PACTRL_ACCESS_INFOW = *mut ACTRL_ACCESS_INFOW; +STRUCT!{struct ACTRL_CONTROL_INFOA { + lpControlId: LPSTR, + lpControlName: LPSTR, +}} +pub type PACTRL_CONTROL_INFOA = *mut ACTRL_CONTROL_INFOA; +STRUCT!{struct ACTRL_CONTROL_INFOW { + lpControlId: LPWSTR, + lpControlName: LPWSTR, +}} +pub type PACTRL_CONTROL_INFOW = *mut ACTRL_CONTROL_INFOW; +pub const ACTRL_ACCESS_NO_OPTIONS: DWORD = 0x00000000; +pub const ACTRL_ACCESS_SUPPORTS_OBJECT_ENTRIES: DWORD = 0x00000001; +pub const TREE_SEC_INFO_SET: DWORD = 0x00000001; +pub const TREE_SEC_INFO_RESET: DWORD = 0x00000002; +pub const TREE_SEC_INFO_RESET_KEEP_EXPLICIT: DWORD = 0x00000003; +ENUM!{enum PROG_INVOKE_SETTING { + ProgressInvokeNever = 1, + ProgressInvokeEveryObject, + ProgressInvokeOnError, + ProgressCancelOperation, + ProgressRetryOperation, + ProgressInvokePrePostError, +}} +pub type PPROG_INVOKE_SETTING = *mut PROG_INVOKE_SETTING; +STRUCT!{struct FN_OBJECT_MGR_FUNCTS { + Placeholder: ULONG, +}} +pub type PFN_OBJECT_MGR_FUNCTS = *mut FN_OBJECT_MGR_FUNCTS; +STRUCT!{struct INHERITED_FROMA { + GenerationGap: LONG, + AncestorName: LPSTR, +}} +pub type PINHERITED_FROMA = *mut INHERITED_FROMA; +STRUCT!{struct INHERITED_FROMW { + GenerationGap: LONG, + AncestorName: LPWSTR, +}} +pub type PINHERITED_FROMW = *mut INHERITED_FROMW; diff --git a/winapi/src/um/aclapi.rs b/winapi/src/um/aclapi.rs new file mode 100644 index 000000000..5c2c5f121 --- /dev/null +++ b/winapi/src/um/aclapi.rs @@ -0,0 +1,362 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, PULONG, ULONG, USHORT}; +use um::accctrl::{ + ACCESS_MODE, MULTIPLE_TRUSTEE_OPERATION, PEXPLICIT_ACCESS_A, PEXPLICIT_ACCESS_W, + PFN_OBJECT_MGR_FUNCTS, PINHERITED_FROMA, PINHERITED_FROMW, POBJECTS_AND_NAME_A, + POBJECTS_AND_NAME_W, POBJECTS_AND_SID, PPROG_INVOKE_SETTING, PROG_INVOKE_SETTING, PTRUSTEE_A, + PTRUSTEE_W, SE_OBJECT_TYPE, TRUSTEE_FORM, TRUSTEE_TYPE +}; +use um::winnt::{ + HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PACCESS_MASK, PACL, PGENERIC_MAPPING, + PSECURITY_DESCRIPTOR, PSID, PVOID, SECURITY_INFORMATION +}; +FN!{cdecl FN_PROGRESS( + pObjectName: LPWSTR, + Status: DWORD, + pInvokeSetting: PPROG_INVOKE_SETTING, + Args: PVOID, + SecuritySet: BOOL, +) -> ()} +extern "system" { + pub fn SetEntriesInAclA( + cCountOfExplicitEntries: ULONG, + pListOfExplicitEntries: PEXPLICIT_ACCESS_A, + OldAcl: PACL, + NewAcl: *mut PACL, + ) -> DWORD; + pub fn SetEntriesInAclW( + cCountOfExplicitEntries: ULONG, + pListOfExplicitEntries: PEXPLICIT_ACCESS_W, + OldAcl: PACL, + NewAcl: *mut PACL, + ) -> DWORD; + pub fn GetExplicitEntriesFromAclA( + pacl: PACL, + pcCountOfExplicitEntries: PULONG, + pListOfExplicitEntries: *mut PEXPLICIT_ACCESS_A, + ) -> DWORD; + pub fn GetExplicitEntriesFromAclW( + pacl: PACL, + pcCountOfExplicitEntries: PULONG, + pListOfExplicitEntries: *mut PEXPLICIT_ACCESS_W, + ) -> DWORD; + pub fn GetEffectiveRightsFromAclA( + pacl: PACL, + pTrustee: PTRUSTEE_A, + pAccessRight: PACCESS_MASK, + ) -> DWORD; + pub fn GetEffectiveRightsFromAclW( + pacl: PACL, + pTrustee: PTRUSTEE_W, + pAccessRight: PACCESS_MASK, + ) -> DWORD; + pub fn GetAuditedPermissionsFromAclA( + pAcl: PACL, + pTrustee: PTRUSTEE_A, + pSuccessfulAuditedRights: PACCESS_MASK, + pFailedAuditRights: PACCESS_MASK, + ) -> DWORD; + pub fn GetAuditedPermissionsFromAclW( + pAcl: PACL, + pTrustee: PTRUSTEE_W, + pSuccessfulAuditedRights: PACCESS_MASK, + pFailedAuditRights: PACCESS_MASK, + ) -> DWORD; + pub fn GetNamedSecurityInfoA( + pObjectName: LPCSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + ppsidOwner: *mut PSID, + ppsidGroup: *mut PSID, + ppDacl: *mut PACL, + ppSacl: *mut PACL, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn GetNamedSecurityInfoW( + pObjectName: LPCWSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + ppsidOwner: *mut PSID, + ppsidGroup: *mut PSID, + ppDacl: *mut PACL, + ppSacl: *mut PACL, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn GetSecurityInfo( + handle: HANDLE, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + ppsidOwner: *mut PSID, + ppsidGroup: *mut PSID, + ppDacl: *mut PACL, + ppSacl: *mut PACL, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn SetNamedSecurityInfoA( + pObjectame: LPSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + psidOwner: PSID, + psidGroup: PSID, + pDacl: PACL, + pSacl: PACL, + ) -> DWORD; + pub fn SetNamedSecurityInfoW( + pObjectame: LPWSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + psidOwner: PSID, + psidGroup: PSID, + pDacl: PACL, + pSacl: PACL, + ) -> DWORD; + pub fn SetSecurityInfo( + handle: HANDLE, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + psidOwner: PSID, + psidGroup: PSID, + pDacl: PACL, + pSacl: PACL, + ) -> DWORD; + pub fn GetInheritanceSourceA( + pObjectName: LPSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + Container: BOOL, + pObjectClassGuids: *mut *mut GUID, + GuidCount: DWORD, + pAcl: PACL, + pfnArray: PFN_OBJECT_MGR_FUNCTS, + pGenericMapping: PGENERIC_MAPPING, + pInheritArray: PINHERITED_FROMA, + ) -> DWORD; + pub fn GetInheritanceSourceW( + pObjectName: LPWSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + Container: BOOL, + pObjectClassGuids: *mut *mut GUID, + GuidCount: DWORD, + pAcl: PACL, + pfnArray: PFN_OBJECT_MGR_FUNCTS, + pGenericMapping: PGENERIC_MAPPING, + pInheritArray: PINHERITED_FROMW, + ) -> DWORD; + pub fn FreeInheritedFromArray( + pInheritArray: PINHERITED_FROMW, + AceCnt: USHORT, + pfnArray: PFN_OBJECT_MGR_FUNCTS, + ) -> DWORD; + pub fn TreeResetNamedSecurityInfoA( + pObjectName: LPSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + pOwner: PSID, + pGroup: PSID, + pDacl: PACL, + pSacl: PACL, + KeepExplicit: BOOL, + fnProgress: FN_PROGRESS, + ProgressInvokeSetting: PROG_INVOKE_SETTING, + Args: PVOID, + ) -> DWORD; + pub fn TreeResetNamedSecurityInfoW( + pObjectName: LPWSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + pOwner: PSID, + pGroup: PSID, + pDacl: PACL, + pSacl: PACL, + KeepExplicit: BOOL, + fnProgress: FN_PROGRESS, + ProgressInvokeSetting: PROG_INVOKE_SETTING, + Args: PVOID, + ) -> DWORD; + pub fn TreeSetNamedSecurityInfoA( + pObjectName: LPSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + pOwner: PSID, + pGroup: PSID, + pDacl: PACL, + pSacl: PACL, + dwAction: DWORD, + fnProgress: FN_PROGRESS, + ProgressInvokeSetting: PROG_INVOKE_SETTING, + Args: PVOID, + ) -> DWORD; + pub fn TreeSetNamedSecurityInfoW( + pObjectName: LPWSTR, + ObjectType: SE_OBJECT_TYPE, + SecurityInfo: SECURITY_INFORMATION, + pOwner: PSID, + pGroup: PSID, + pDacl: PACL, + pSacl: PACL, + dwAction: DWORD, + fnProgress: FN_PROGRESS, + ProgressInvokeSetting: PROG_INVOKE_SETTING, + Args: PVOID, + ) -> DWORD; + pub fn BuildSecurityDescriptorA( + pOwner: PTRUSTEE_A, + pGroup: PTRUSTEE_A, + cCountOfAccessEntries: ULONG, + pListOfAccessEntries: PEXPLICIT_ACCESS_A, + cCountOfAuditEntries: ULONG, + pListOfAuditEntries: PEXPLICIT_ACCESS_A, + pOldSD: PSECURITY_DESCRIPTOR, + pSizeNewSD: PULONG, + pNewSD: *mut PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn BuildSecurityDescriptorW( + pOwner: PTRUSTEE_W, + pGroup: PTRUSTEE_W, + cCountOfAccessEntries: ULONG, + pListOfAccessEntries: PEXPLICIT_ACCESS_W, + cCountOfAuditEntries: ULONG, + pListOfAuditEntries: PEXPLICIT_ACCESS_W, + pOldSD: PSECURITY_DESCRIPTOR, + pSizeNewSD: PULONG, + pNewSD: *mut PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn LookupSecurityDescriptorPartsA( + ppOwner: *mut PTRUSTEE_A, + ppGroup: *mut PTRUSTEE_A, + pcCountOfAccessEntries: PULONG, + ppListOfAccessEntries: *mut PEXPLICIT_ACCESS_A, + pcCountOfAuditEntries: PULONG, + ppListOfAuditEntries: *mut PEXPLICIT_ACCESS_A, + pSD: PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn LookupSecurityDescriptorPartsW( + ppOwner: *mut PTRUSTEE_W, + ppGroup: *mut PTRUSTEE_W, + pcCountOfAccessEntries: PULONG, + ppListOfAccessEntries: *mut PEXPLICIT_ACCESS_W, + pcCountOfAuditEntries: PULONG, + ppListOfAuditEntries: *mut PEXPLICIT_ACCESS_W, + pSD: PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn BuildExplicitAccessWithNameA( + pExplicitAccess: PEXPLICIT_ACCESS_A, + pTrusteeName: LPSTR, + AccessPermissions: DWORD, + AccessMode: ACCESS_MODE, + Inheritance: DWORD, + ); + pub fn BuildExplicitAccessWithNameW( + pExplicitAccess: PEXPLICIT_ACCESS_W, + pTrusteeName: LPWSTR, + AccessPermissions: DWORD, + AccessMode: ACCESS_MODE, + Inheritance: DWORD, + ); + pub fn BuildImpersonateExplicitAccessWithNameA( + pExplicitAccess: PEXPLICIT_ACCESS_A, + pTrusteeName: LPSTR, + pTrustee: PTRUSTEE_A, + AccessPermissions: DWORD, + AccessMode: ACCESS_MODE, + Inheritance: DWORD, + ); + pub fn BuildImpersonateExplicitAccessWithNameW( + pExplicitAccess: PEXPLICIT_ACCESS_W, + pTrusteeName: LPWSTR, + pTrustee: PTRUSTEE_W, + AccessPermissions: DWORD, + AccessMode: ACCESS_MODE, + Inheritance: DWORD, + ); + pub fn BuildTrusteeWithNameA( + pTrustee: PTRUSTEE_A, + pName: LPSTR, + ); + pub fn BuildTrusteeWithNameW( + pTrustee: PTRUSTEE_W, + pName: LPWSTR, + ); + pub fn BuildImpersonateTrusteeA( + pTrustee: PTRUSTEE_A, + pImpersonateTrustee: PTRUSTEE_A, + ); + pub fn BuildImpersonateTrusteeW( + pTrustee: PTRUSTEE_W, + pImpersonateTrustee: PTRUSTEE_W, + ); + pub fn BuildTrusteeWithSidA( + pTrustee: PTRUSTEE_A, + pSid: PSID, + ); + pub fn BuildTrusteeWithSidW( + pTrustee: PTRUSTEE_W, + pSid: PSID, + ); + pub fn BuildTrusteeWithObjectsAndSidA( + pTrustee: PTRUSTEE_A, + pObjSid: POBJECTS_AND_SID, + pObjectGuid: *mut GUID, + pInheritedObjectGuid: *mut GUID, + pSid: PSID, + ); + pub fn BuildTrusteeWithObjectsAndSidW( + pTrustee: PTRUSTEE_W, + pObjSid: POBJECTS_AND_SID, + pObjectGuid: *mut GUID, + pInheritedObjectGuid: *mut GUID, + pSid: PSID, + ); + pub fn BuildTrusteeWithObjectsAndNameA( + pTrustee: PTRUSTEE_A, + pObjName: POBJECTS_AND_NAME_A, + ObjectType: SE_OBJECT_TYPE, + ObjectTypeName: LPSTR, + InheritedObjectTypeName: LPSTR, + Name: LPSTR, + ); + pub fn BuildTrusteeWithObjectsAndNameW( + pTrustee: PTRUSTEE_W, + pObjName: POBJECTS_AND_NAME_W, + ObjectType: SE_OBJECT_TYPE, + ObjectTypeName: LPWSTR, + InheritedObjectTypeName: LPWSTR, + Name: LPWSTR, + ); + pub fn GetTrusteeNameA( + pTrustee: PTRUSTEE_A, + ) -> LPSTR; + pub fn GetTrusteeNameW( + pTrustee: PTRUSTEE_W, + ) -> LPWSTR; + pub fn GetTrusteeTypeA( + pTrustee: PTRUSTEE_A, + ) -> TRUSTEE_TYPE; + pub fn GetTrusteeTypeW( + pTrustee: PTRUSTEE_W, + ) -> TRUSTEE_TYPE; + pub fn GetTrusteeFormA( + pTrustee: PTRUSTEE_A, + ) -> TRUSTEE_FORM; + pub fn GetTrusteeFormW( + pTrustee: PTRUSTEE_W, + ) -> TRUSTEE_FORM; + pub fn GetMultipleTrusteeOperationA( + pTrustee: PTRUSTEE_A, + ) -> MULTIPLE_TRUSTEE_OPERATION; + pub fn GetMultipleTrusteeOperationW( + pTrustee: PTRUSTEE_W, + ) -> MULTIPLE_TRUSTEE_OPERATION; + pub fn GetMultipleTrusteeA( + pTrustee: PTRUSTEE_A, + ) -> PTRUSTEE_A; + pub fn GetMultipleTrusteeW( + pTrustee: PTRUSTEE_W, + ) -> PTRUSTEE_W; +} diff --git a/winapi/src/um/appmgmt.rs b/winapi/src/um/appmgmt.rs new file mode 100644 index 000000000..1d7b910d4 --- /dev/null +++ b/winapi/src/um/appmgmt.rs @@ -0,0 +1,122 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, LPDWORD}; +use um::winnt::{LANGID, LCID, LPWSTR, WCHAR}; +ENUM!{enum INSTALLSPECTYPE { + APPNAME = 1, + FILEEXT, + PROGID, + COMCLASS, +}} +STRUCT!{struct INSTALLSPEC_APPNAME { + Name: *mut WCHAR, + GPOId: GUID, +}} +STRUCT!{struct INSTALLSPEC_COMCLASS { + Clsid: GUID, + ClsCtx: DWORD, +}} +UNION!{union INSTALLSPEC { + [u32; 5] [u64; 3], + AppName AppName_mut: INSTALLSPEC_APPNAME, + FileExt FileExt_mut: *mut WCHAR, + ProgId ProgId_mut: *mut WCHAR, + COMClass COMClass_mut: INSTALLSPEC_COMCLASS, +}} +STRUCT!{struct INSTALLDATA { + Type: INSTALLSPECTYPE, + Spec: INSTALLSPEC, +}} +pub type PINSTALLDATA = *mut INSTALLDATA; +ENUM!{enum APPSTATE { + ABSENT, + ASSIGNED, + PUBLISHED, +}} +pub const LOCALSTATE_ASSIGNED: DWORD = 0x1; +pub const LOCALSTATE_PUBLISHED: DWORD = 0x2; +pub const LOCALSTATE_UNINSTALL_UNMANAGED: DWORD = 0x4; +pub const LOCALSTATE_POLICYREMOVE_ORPHAN: DWORD = 0x8; +pub const LOCALSTATE_POLICYREMOVE_UNINSTALL: DWORD = 0x10; +pub const LOCALSTATE_ORPHANED: DWORD = 0x20; +pub const LOCALSTATE_UNINSTALLED: DWORD = 0x40; +STRUCT!{struct LOCALMANAGEDAPPLICATION { + pszDeploymentName: LPWSTR, + pszPolicyName: LPWSTR, + pszProductId: LPWSTR, + dwState: DWORD, +}} +pub type PLOCALMANAGEDAPPLICATION = *mut LOCALMANAGEDAPPLICATION; +pub const MANAGED_APPS_USERAPPLICATIONS: DWORD = 0x1; +pub const MANAGED_APPS_FROMCATEGORY: DWORD = 0x2; +pub const MANAGED_APPS_INFOLEVEL_DEFAULT: DWORD = 0x10000; +pub const MANAGED_APPTYPE_WINDOWSINSTALLER: DWORD = 0x1; +pub const MANAGED_APPTYPE_SETUPEXE: DWORD = 0x2; +pub const MANAGED_APPTYPE_UNSUPPORTED: DWORD = 0x3; +STRUCT!{struct MANAGEDAPPLICATION { + pszPackageName: LPWSTR, + pszPublisher: LPWSTR, + dwVersionHi: DWORD, + dwVersionLo: DWORD, + dwRevision: DWORD, + GpoId: GUID, + pszPolicyName: LPWSTR, + ProductId: GUID, + Language: LANGID, + pszOwner: LPWSTR, + pszCompany: LPWSTR, + pszComments: LPWSTR, + pszContact: LPWSTR, + pszSupportUrl: LPWSTR, + dwPathType: DWORD, + bInstalled: BOOL, +}} +pub type PMANAGEDAPPLICATION = *mut MANAGEDAPPLICATION; +STRUCT!{struct APPCATEGORYINFO { + Locale: LCID, + pszDescription: LPWSTR, + AppCategoryId: GUID, +}} +STRUCT!{struct APPCATEGORYINFOLIST { + cCategory: DWORD, + pCategoryInfo: *mut APPCATEGORYINFO, +}} +extern "system" { + pub fn InstallApplication( + pInstallInfo: PINSTALLDATA, + ) -> DWORD; + pub fn UninstallApplication( + ProductCode: LPWSTR, + dwStatus: DWORD, + ) -> DWORD; + pub fn CommandLineFromMsiDescriptor( + Descriptor: LPWSTR, + CommandLine: LPWSTR, + CommandLineLength: *mut DWORD, + ) -> DWORD; + pub fn GetManagedApplications( + pCategory: *mut GUID, + dwQueryFlags: DWORD, + dwInfoLevel: DWORD, + pdwApps: LPDWORD, + prgManagedApps: *mut PMANAGEDAPPLICATION, + ) -> DWORD; + pub fn GetLocalManagedApplications( + bUserApps: BOOL, + pdwApps: LPDWORD, + prgManagedApps: *mut PMANAGEDAPPLICATION, + ) -> DWORD; + pub fn GetLocalManagedApplicationData( + ProductCode: LPWSTR, + DisplayName: *mut LPWSTR, + SupportUrl: *mut LPWSTR, + ); + pub fn GetManagedApplicationCategories( + dwReserved: DWORD, + pAppCategory: *mut APPCATEGORYINFOLIST, + ) -> DWORD; +} diff --git a/winapi/src/um/audioclient.rs b/winapi/src/um/audioclient.rs new file mode 100644 index 000000000..5f7b83e46 --- /dev/null +++ b/winapi/src/um/audioclient.rs @@ -0,0 +1,172 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! this ALWAYS GENERATED file contains the definitions for the interfaces +use ctypes::c_float; +use shared::basetsd::{UINT32, UINT64}; +use shared::guiddef::{LPCGUID, REFIID}; +use shared::minwindef::{BYTE, DWORD, LPVOID}; +use shared::mmreg::WAVEFORMATEX; +use shared::winerror::{FACILITY_AUDCLNT, SEVERITY_ERROR, SEVERITY_SUCCESS}; +use shared::wtypesbase::SCODE; +use um::audiosessiontypes::AUDCLNT_SHAREMODE; +use um::strmif::REFERENCE_TIME; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT}; +//1627 +pub const AUDCLNT_E_NOT_INITIALIZED: HRESULT = AUDCLNT_ERR!(0x001); +pub const AUDCLNT_E_ALREADY_INITIALIZED: HRESULT = AUDCLNT_ERR!(0x002); +pub const AUDCLNT_E_WRONG_ENDPOINT_TYPE: HRESULT = AUDCLNT_ERR!(0x003); +pub const AUDCLNT_E_DEVICE_INVALIDATED: HRESULT = AUDCLNT_ERR!(0x004); +pub const AUDCLNT_E_NOT_STOPPED: HRESULT = AUDCLNT_ERR!(0x005); +pub const AUDCLNT_E_BUFFER_TOO_LARGE: HRESULT = AUDCLNT_ERR!(0x006); +pub const AUDCLNT_E_OUT_OF_ORDER: HRESULT = AUDCLNT_ERR!(0x007); +pub const AUDCLNT_E_UNSUPPORTED_FORMAT: HRESULT = AUDCLNT_ERR!(0x008); +pub const AUDCLNT_E_INVALID_SIZE: HRESULT = AUDCLNT_ERR!(0x009); +pub const AUDCLNT_E_DEVICE_IN_USE: HRESULT = AUDCLNT_ERR!(0x00a); +pub const AUDCLNT_E_BUFFER_OPERATION_PENDING: HRESULT = AUDCLNT_ERR!(0x00b); +pub const AUDCLNT_E_THREAD_NOT_REGISTERED: HRESULT = AUDCLNT_ERR!(0x00c); +pub const AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: HRESULT = AUDCLNT_ERR!(0x00e); +pub const AUDCLNT_E_ENDPOINT_CREATE_FAILED: HRESULT = AUDCLNT_ERR!(0x00f); +pub const AUDCLNT_E_SERVICE_NOT_RUNNING: HRESULT = AUDCLNT_ERR!(0x010); +pub const AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: HRESULT = AUDCLNT_ERR!(0x011); +pub const AUDCLNT_E_EXCLUSIVE_MODE_ONLY: HRESULT = AUDCLNT_ERR!(0x012); +pub const AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: HRESULT = AUDCLNT_ERR!(0x013); +pub const AUDCLNT_E_EVENTHANDLE_NOT_SET: HRESULT = AUDCLNT_ERR!(0x014); +pub const AUDCLNT_E_INCORRECT_BUFFER_SIZE: HRESULT = AUDCLNT_ERR!(0x015); +pub const AUDCLNT_E_BUFFER_SIZE_ERROR: HRESULT = AUDCLNT_ERR!(0x016); +pub const AUDCLNT_E_CPUUSAGE_EXCEEDED: HRESULT = AUDCLNT_ERR!(0x017); +pub const AUDCLNT_E_BUFFER_ERROR: HRESULT = AUDCLNT_ERR!(0x018); +pub const AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED: HRESULT = AUDCLNT_ERR!(0x019); +pub const AUDCLNT_E_INVALID_DEVICE_PERIOD: HRESULT = AUDCLNT_ERR!(0x020); +pub const AUDCLNT_E_INVALID_STREAM_FLAG: HRESULT = AUDCLNT_ERR!(0x021); +pub const AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE: HRESULT = AUDCLNT_ERR!(0x022); +pub const AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES: HRESULT = AUDCLNT_ERR!(0x023); +pub const AUDCLNT_E_OFFLOAD_MODE_ONLY: HRESULT = AUDCLNT_ERR!(0x024); +pub const AUDCLNT_E_NONOFFLOAD_MODE_ONLY: HRESULT = AUDCLNT_ERR!(0x025); +pub const AUDCLNT_E_RESOURCES_INVALIDATED: HRESULT = AUDCLNT_ERR!(0x026); +pub const AUDCLNT_E_RAW_MODE_UNSUPPORTED: HRESULT = AUDCLNT_ERR!(0x027); +pub const AUDCLNT_S_BUFFER_EMPTY: SCODE = AUDCLNT_SUCCESS!(0x001); +pub const AUDCLNT_S_THREAD_ALREADY_REGISTERED: SCODE = AUDCLNT_SUCCESS!(0x002); +pub const AUDCLNT_S_POSITION_STALLED: SCODE = AUDCLNT_SUCCESS!(0x003); +ENUM!{enum AUDCLNT_BUFFERFLAGS { + AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY = 0x1, + AUDCLNT_BUFFERFLAGS_SILENT = 0x2, + AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR = 0x4, +}} +DEFINE_GUID!{IID_IAudioClient, + 0x1CB9AD4C, 0xDBFA, 0x4c32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2} +DEFINE_GUID!{IID_IAudioRenderClient, + 0xF294ACFC, 0x3146, 0x4483, 0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2} +DEFINE_GUID!{IID_IAudioCaptureClient, + 0xc8adbd64, 0xe71e, 0x48a0, 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17} +DEFINE_GUID!{IID_IAudioClock, + 0xcd63314f, 0x3fba, 0x4a1b, 0x81, 0x2c, 0xef, 0x96, 0x35, 0x87, 0x28, 0xe7} +DEFINE_GUID!{IID_IAudioStreamVolume, + 0x93014887, 0x242d, 0x4068, 0x8a, 0x15, 0xcf, 0x5e, 0x93, 0xb9, 0x0f, 0xe3} +RIDL!{#[uuid(0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2)] +interface IAudioClient(IAudioClientVtbl): IUnknown(IUnknownVtbl) { + fn Initialize( + ShareMode: AUDCLNT_SHAREMODE, + StreamFlags: DWORD, + hnsBufferDuration: REFERENCE_TIME, + hnsPeriodicity: REFERENCE_TIME, + pFormat: *const WAVEFORMATEX, + AudioSessionGuid: LPCGUID, + ) -> HRESULT, + fn GetBufferSize( + pNumBufferFrames: *mut UINT32, + ) -> HRESULT, + fn GetStreamLatency( + phnsLatency: *mut REFERENCE_TIME, + ) -> HRESULT, + fn GetCurrentPadding( + pNumPaddingFrames: *mut UINT32, + ) -> HRESULT, + fn IsFormatSupported( + ShareMode: AUDCLNT_SHAREMODE, + pFormat: *const WAVEFORMATEX, + ppClosestMatch: *mut *mut WAVEFORMATEX, + ) -> HRESULT, + fn GetMixFormat( + ppDeviceFormat: *mut *mut WAVEFORMATEX, + ) -> HRESULT, + fn GetDevicePeriod( + phnsDefaultDevicePeriod: *mut REFERENCE_TIME, + phnsMinimumDevicePeriod: *mut REFERENCE_TIME, + ) -> HRESULT, + fn Start() -> HRESULT, + fn Stop() -> HRESULT, + fn Reset() -> HRESULT, + fn SetEventHandle( + eventHandle: HANDLE, + ) -> HRESULT, + fn GetService( + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2)] +interface IAudioRenderClient(IAudioRenderClientVtbl): IUnknown(IUnknownVtbl) { + fn GetBuffer( + NumFramesRequested: UINT32, + ppData: *mut *mut BYTE, + ) -> HRESULT, + fn ReleaseBuffer( + NumFramesWritten: UINT32, + dwFlags: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc8adbd64, 0xe71e, 0x48a0, 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17)] +interface IAudioCaptureClient(IAudioCaptureClientVtbl): IUnknown(IUnknownVtbl) { + fn GetBuffer( + ppData: *mut *mut BYTE, + pNumFramesToRead: *mut UINT32, + pdwFlags: *mut DWORD, + pu64DevicePosition: *mut UINT64, + pu64QPCPosition: *mut UINT64, + ) -> HRESULT, + fn ReleaseBuffer( + NumFramesRead: UINT32, + ) -> HRESULT, + fn GetNextPacketSize( + pNumFramesInNextPacket: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xcd63314f, 0x3fba, 0x4a1b, 0x81, 0x2c, 0xef, 0x96, 0x35, 0x87, 0x28, 0xe7)] +interface IAudioClock(IAudioClockVtbl): IUnknown(IUnknownVtbl) { + fn GetFrequency( + pu64Frequency: *mut UINT64, + ) -> HRESULT, + fn GetPosition( + pu64Position: *mut UINT64, + pu64QPCPosition: *mut UINT64, + ) -> HRESULT, + fn GetCharacteristics( + pdwCharacteristics: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x93014887, 0x242d, 0x4068, 0x8a, 0x15, 0xcf, 0x5e, 0x93, 0xb9, 0x0f, 0xe3)] +interface IAudioStreamVolume(IAudioStreamVolumeVtbl): IUnknown(IUnknownVtbl) { + fn GetChannelCount( + pdwCount: *mut UINT32, + ) -> HRESULT, + fn SetChannelVolume( + dwIndex: UINT32, + fLevel: c_float, + ) -> HRESULT, + fn GetChannelVolume( + dwIndex: UINT32, + pfLevel: *mut c_float, + ) -> HRESULT, + fn SetAllVolumes( + dwCount: UINT32, + pfVolumes: *const c_float, + ) -> HRESULT, + fn GetAllVolumes( + dwCount: UINT32, + pfVolumes: *mut c_float, + ) -> HRESULT, +}} diff --git a/winapi/src/um/audiosessiontypes.rs b/winapi/src/um/audiosessiontypes.rs new file mode 100644 index 000000000..3c64f4244 --- /dev/null +++ b/winapi/src/um/audiosessiontypes.rs @@ -0,0 +1,37 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::DWORD; +ENUM!{enum AUDCLNT_SHAREMODE { + AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_SHAREMODE_EXCLUSIVE, +}} +ENUM!{enum AUDIO_STREAM_CATEGORY { + AudioCategory_Other = 0, + AudioCategory_ForegroundOnlyMedia = 1, + AudioCategory_BackgroundCapableMedia = 2, + AudioCategory_Communications = 3, + AudioCategory_Alerts = 4, + AudioCategory_SoundEffects = 5, + AudioCategory_GameEffects = 6, + AudioCategory_GameMedia = 7, + AudioCategory_GameChat = 8, + AudioCategory_Speech = 9, + AudioCategory_Movie = 10, + AudioCategory_Media = 11, +}} +pub const AUDCLNT_STREAMFLAGS_CROSSPROCESS: DWORD = 0x00010000; +pub const AUDCLNT_STREAMFLAGS_LOOPBACK: DWORD = 0x00020000; +pub const AUDCLNT_STREAMFLAGS_EVENTCALLBACK: DWORD = 0x00040000; +pub const AUDCLNT_STREAMFLAGS_NOPERSIST: DWORD = 0x00080000; +pub const AUDCLNT_STREAMFLAGS_RATEADJUST: DWORD = 0x00100000; +pub const AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED: DWORD = 0x10000000; +pub const AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE: DWORD = 0x20000000; +pub const AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED: DWORD = 0x40000000; +ENUM!{enum AudioSessionState { + AudioSessionStateInactive = 0, + AudioSessionStateActive = 1, + AudioSessionStateExpired = 2, +}} diff --git a/winapi/src/um/avrt.rs b/winapi/src/um/avrt.rs new file mode 100644 index 000000000..62b0e9c88 --- /dev/null +++ b/winapi/src/um/avrt.rs @@ -0,0 +1,82 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_longlong; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, LPDWORD, PULONG}; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR, PHANDLE, PLARGE_INTEGER}; +ENUM!{enum AVRT_PRIORITY { + AVRT_PRIORITY_VERYLOW = -2i32 as u32, + AVRT_PRIORITY_LOW, + AVRT_PRIORITY_NORMAL = 0, + AVRT_PRIORITY_HIGH, + AVRT_PRIORITY_CRITICAL, +}} +pub const THREAD_ORDER_GROUP_INFINITE_TIMEOUT: c_longlong = -1; +extern "system" { + pub fn AvSetMmThreadCharacteristicsA( + TaskName: LPCSTR, + TaskIndex: LPDWORD, + ) -> HANDLE; + pub fn AvSetMmThreadCharacteristicsW( + TaskName: LPCWSTR, + TaskIndex: LPDWORD, + ) -> HANDLE; + pub fn AvSetMmMaxThreadCharacteristicsA( + FirstTask: LPCSTR, + SecondTask: LPCSTR, + TaskIndex: LPDWORD, + ) -> HANDLE; + pub fn AvSetMmMaxThreadCharacteristicsW( + FirstTask: LPCWSTR, + SecondTask: LPCWSTR, + TaskIndex: LPDWORD, + ) -> HANDLE; + pub fn AvRevertMmThreadCharacteristics( + avrt_handle: HANDLE, + ) -> BOOL; + pub fn AvSetMmThreadPriority( + AvrtHandle: HANDLE, + Priority: AVRT_PRIORITY, + ) -> BOOL; + pub fn AvRtCreateThreadOrderingGroup( + Context: PHANDLE, + Period: PLARGE_INTEGER, + ThreadOrderingGuid: *mut GUID, + Timeout: PLARGE_INTEGER, + ) -> BOOL; + pub fn AvRtCreateThreadOrderingGroupExA( + Context: PHANDLE, + Period: PLARGE_INTEGER, + ThreadOrderingGuid: *mut GUID, + Timeout: PLARGE_INTEGER, + TaskName: LPCSTR, + )-> BOOL; + pub fn AvRtCreateThreadOrderingGroupExW( + Context: PHANDLE, + Period: PLARGE_INTEGER, + ThreadOrderingGuid: *mut GUID, + Timeout: PLARGE_INTEGER, + TaskName: LPCWSTR, + ) -> BOOL; + pub fn AvRtJoinThreadOrderingGroup( + Context: PHANDLE, + ThreadOrderingGuid: *mut GUID, + Before: BOOL, + ) -> BOOL; + pub fn AvRtWaitOnThreadOrderingGroup( + Context: HANDLE, + ) -> BOOL; + pub fn AvRtLeaveThreadOrderingGroup( + Context: HANDLE, + ) -> BOOL; + pub fn AvRtDeleteThreadOrderingGroup( + Context: HANDLE, + ) -> BOOL; + pub fn AvQuerySystemResponsiveness( + AvrtHandle: HANDLE, + SystemResponsivenessValue: PULONG, + ) -> BOOL; +} diff --git a/winapi/src/um/bits.rs b/winapi/src/um/bits.rs new file mode 100644 index 000000000..aef603fe0 --- /dev/null +++ b/winapi/src/um/bits.rs @@ -0,0 +1,295 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::guiddef::{GUID, REFGUID}; +use shared::minwindef::{BOOL, DWORD, FILETIME, ULONG}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, WCHAR}; +RIDL!{#[uuid(0x4991d34b, 0x80a1, 0x4291, 0x83, 0xb6, 0x33, 0x28, 0x36, 0x6b, 0x90, 0x97)] +class BackgroundCopyManager;} +pub const BG_SIZE_UNKNOWN: UINT64 = -1i64 as u64; +STRUCT!{struct BG_FILE_PROGRESS { + BytesTotal: UINT64, + BytesTransferred: UINT64, + Completed: BOOL, +}} +RIDL!{#[uuid(0x01b7bd23, 0xfb88, 0x4a77, 0x84, 0x90, 0x58, 0x91, 0xd3, 0xe4, 0x65, 0x3a)] +interface IBackgroundCopyFile(IBackgroundCopyFileVtbl): IUnknown(IUnknownVtbl) { + fn GetRemoteName( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn GetLocalName( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn GetProgress( + pVal: *mut BG_FILE_PROGRESS, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xca51e165, 0xc365, 0x424c, 0x8d, 0x41, 0x24, 0xaa, 0xa4, 0xff, 0x3c, 0x40)] +interface IEnumBackgroundCopyFiles(IEnumBackgroundCopyFilesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IBackgroundCopyFile, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumBackgroundCopyFiles, + ) -> HRESULT, + fn GetCount( + puCount: *mut ULONG, + ) -> HRESULT, +}} +ENUM!{enum BG_ERROR_CONTEXT { + BG_ERROR_CONTEXT_NONE = 0, + BG_ERROR_CONTEXT_UNKNOWN = 1, + BG_ERROR_CONTEXT_GENERAL_QUEUE_MANAGER = 2, + BG_ERROR_CONTEXT_QUEUE_MANAGER_NOTIFICATION = 3, + BG_ERROR_CONTEXT_LOCAL_FILE = 4, + BG_ERROR_CONTEXT_REMOTE_FILE = 5, + BG_ERROR_CONTEXT_GENERAL_TRANSPORT = 6, + BG_ERROR_CONTEXT_REMOTE_APPLICATION = 7, +}} +RIDL!{#[uuid(0x19c613a0, 0xfcb8, 0x4f28, 0x81, 0xae, 0x89, 0x7c, 0x3d, 0x07, 0x8f, 0x81)] +interface IBackgroundCopyError(IBackgroundCopyErrorVtbl): IUnknown(IUnknownVtbl) { + fn GetError( + pContext: *mut BG_ERROR_CONTEXT, + pCode: *mut HRESULT, + ) -> HRESULT, + fn GetFile( + pVal: *mut *mut IBackgroundCopyFile, + ) -> HRESULT, + fn GetErrorDescription( + LanguageId: DWORD, + pErrorDescription: *mut LPWSTR, + ) -> HRESULT, + fn GetErrorContextDescription( + LanguageId: DWORD, + pContextDescription: *mut LPWSTR, + ) -> HRESULT, + fn GetProtocol( + pProtocol: *mut LPWSTR, + ) -> HRESULT, +}} +STRUCT!{struct BG_FILE_INFO { + RemoteName: LPWSTR, + LocalName: LPWSTR, +}} +STRUCT!{struct BG_JOB_PROGRESS { + BytesTotal: UINT64, + BytesTransferred: UINT64, + FilesTotal: ULONG, + FilesTransferred: ULONG, +}} +STRUCT!{struct BG_JOB_TIMES { + CreationTime: FILETIME, + ModificationTime: FILETIME, + TransferCompletionTime: FILETIME, +}} +ENUM!{enum BG_JOB_PRIORITY { + BG_JOB_PRIORITY_FOREGROUND = 0, + BG_JOB_PRIORITY_HIGH = BG_JOB_PRIORITY_FOREGROUND + 1, + BG_JOB_PRIORITY_NORMAL = BG_JOB_PRIORITY_HIGH + 1, + BG_JOB_PRIORITY_LOW = BG_JOB_PRIORITY_NORMAL + 1, +}} +ENUM!{enum BG_JOB_STATE { + BG_JOB_STATE_QUEUED = 0, + BG_JOB_STATE_CONNECTING = BG_JOB_STATE_QUEUED + 1, + BG_JOB_STATE_TRANSFERRING = BG_JOB_STATE_CONNECTING + 1, + BG_JOB_STATE_SUSPENDED = BG_JOB_STATE_TRANSFERRING + 1, + BG_JOB_STATE_ERROR = BG_JOB_STATE_SUSPENDED + 1, + BG_JOB_STATE_TRANSIENT_ERROR = BG_JOB_STATE_ERROR + 1, + BG_JOB_STATE_TRANSFERRED = BG_JOB_STATE_TRANSIENT_ERROR + 1, + BG_JOB_STATE_ACKNOWLEDGED = BG_JOB_STATE_TRANSFERRED + 1, + BG_JOB_STATE_CANCELLED = BG_JOB_STATE_ACKNOWLEDGED + 1, +}} +ENUM!{enum BG_JOB_TYPE { + BG_JOB_TYPE_DOWNLOAD = 0, + BG_JOB_TYPE_UPLOAD = BG_JOB_TYPE_DOWNLOAD + 1, + BG_JOB_TYPE_UPLOAD_REPLY = BG_JOB_TYPE_UPLOAD + 1, +}} +ENUM!{enum BG_JOB_PROXY_USAGE { + BG_JOB_PROXY_USAGE_PRECONFIG = 0, + BG_JOB_PROXY_USAGE_NO_PROXY = BG_JOB_PROXY_USAGE_PRECONFIG + 1, + BG_JOB_PROXY_USAGE_OVERRIDE = BG_JOB_PROXY_USAGE_NO_PROXY + 1, + BG_JOB_PROXY_USAGE_AUTODETECT = BG_JOB_PROXY_USAGE_OVERRIDE + 1, +}} +RIDL!{#[uuid(0x37668d37, 0x507e, 0x4160, 0x93, 0x16, 0x26, 0x30, 0x6d, 0x15, 0x0b, 0x12)] +interface IBackgroundCopyJob(IBackgroundCopyJobVtbl): IUnknown(IUnknownVtbl) { + fn AddFileSet( + cFileCount: ULONG, + pFileSet: *mut BG_FILE_INFO, + ) -> HRESULT, + fn AddFile( + RemoteUrl: LPCWSTR, + LocalName: LPCWSTR, + ) -> HRESULT, + fn EnumFiles( + pErrorDescription: *mut *mut IEnumBackgroundCopyFiles, + ) -> HRESULT, + fn Suspend() -> HRESULT, + fn Resume() -> HRESULT, + fn Cancel() -> HRESULT, + fn Complete() -> HRESULT, + fn GetId( + pVal: *mut GUID, + ) -> HRESULT, + fn GetType( + pVal: *mut BG_JOB_TYPE, + ) -> HRESULT, + fn GetProgress( + pVal: *mut BG_JOB_PROGRESS, + ) -> HRESULT, + fn GetTimes( + pVal: *mut BG_JOB_TIMES, + ) -> HRESULT, + fn GetState( + pVal: *mut BG_JOB_STATE, + ) -> HRESULT, + fn GetError( + ppError: *mut *mut IBackgroundCopyError, + ) -> HRESULT, + fn GetOwner( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn SetDisplayName( + Val: LPCWSTR, + ) -> HRESULT, + fn GetDisplayName( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn SetDescription( + Val: LPCWSTR, + ) -> HRESULT, + fn GetDescription( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn SetPriority( + Val: BG_JOB_PRIORITY, + ) -> HRESULT, + fn GetPriority( + pVal: *mut BG_JOB_PRIORITY, + ) -> HRESULT, + fn SetNotifyFlags( + Val: ULONG, + ) -> HRESULT, + fn GetNotifyFlags( + pVal: *mut ULONG, + ) -> HRESULT, + fn SetNotifyInterface( + Val: *mut IUnknown, + ) -> HRESULT, + fn GetNotifyInterface( + pVal: *mut *mut IUnknown, + ) -> HRESULT, + fn SetMinimumRetryDelay( + Seconds: ULONG, + ) -> HRESULT, + fn GetMinimumRetryDelay( + Seconds: *mut ULONG, + ) -> HRESULT, + fn SetNoProgressTimeout( + Seconds: ULONG, + ) -> HRESULT, + fn GetNoProgressTimeout( + Seconds: *mut ULONG, + ) -> HRESULT, + fn GetErrorCount( + Errors: *mut ULONG, + ) -> HRESULT, + fn SetProxySettings( + ProxyUsage: BG_JOB_PROXY_USAGE, + ProxyList: *const WCHAR, + ProxyBypassList: *const WCHAR, + ) -> HRESULT, + fn GetProxySettings( + pProxyUsage: *mut BG_JOB_PROXY_USAGE, + pProxyList: *mut LPWSTR, + pProxyBypassListpProxyList: *mut LPWSTR, + ) -> HRESULT, + fn TakeOwnership() -> HRESULT, +}} +RIDL!{#[uuid(0x1af4f612, 0x3b71, 0x466f, 0x8f, 0x58, 0x7b, 0x6f, 0x73, 0xac, 0x57, 0xad)] +interface IEnumBackgroundCopyJobs(IEnumBackgroundCopyJobsVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IBackgroundCopyJob, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumBackgroundCopyJobs, + ) -> HRESULT, + fn GetCount( + puCount: *mut ULONG, + ) -> HRESULT, +}} +pub const BG_NOTIFY_JOB_TRANSFERRED: DWORD = 0x0001; +pub const BG_NOTIFY_JOB_ERROR: DWORD = 0x0002; +pub const BG_NOTIFY_DISABLE: DWORD = 0x0004; +pub const BG_NOTIFY_JOB_MODIFICATION: DWORD = 0x0008; +pub const BG_NOTIFY_FILE_TRANSFERRED: DWORD = 0x0010; +pub const BG_NOTIFY_FILE_RANGES_TRANSFERRED: DWORD = 0x0020; +RIDL!{#[uuid(0x97ea99c7, 0x0186, 0x4ad4, 0x8d, 0xf9, 0xc5, 0xb4, 0xe0, 0xed, 0x6b, 0x22)] +interface IBackgroundCopyCallback(IBackgroundCopyCallbackVtbl): IUnknown(IUnknownVtbl) { + fn JobTransferred( + pJob: *mut IBackgroundCopyJob, + ) -> HRESULT, + fn JobError( + pJob: *mut IBackgroundCopyJob, + pError: *mut IBackgroundCopyError, + ) -> HRESULT, + fn JobModification( + pJob: *mut IBackgroundCopyJob, + dwReserved: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xca29d251, 0xb4bb, 0x4679, 0xa3, 0xd9, 0xae, 0x80, 0x06, 0x11, 0x9d, 0x54)] +interface AsyncIBackgroundCopyCallback(AsyncIBackgroundCopyCallbackVtbl): IUnknown(IUnknownVtbl) { + fn Begin_JobTransferred( + pJob: *mut IBackgroundCopyJob, + ) -> HRESULT, + fn Finish_JobTransferred() -> HRESULT, + fn Begin_JobError( + pJob: *mut IBackgroundCopyJob, + pError: *mut IBackgroundCopyError, + ) -> HRESULT, + fn Finish_JobError() -> HRESULT, + fn Begin_JobModification( + pJob: *mut IBackgroundCopyJob, + dwReserved: DWORD, + ) -> HRESULT, + fn Finish_JobModification() -> HRESULT, +}} +pub const BG_JOB_ENUM_ALL_USERS: DWORD = 0x0001; +RIDL!{#[uuid(0x5ce34c0d, 0x0dc9, 0x4c1f, 0x89, 0x7c, 0xda, 0xa1, 0xb7, 0x8c, 0xee, 0x7c)] +interface IBackgroundCopyManager(IBackgroundCopyManagerVtbl): IUnknown(IUnknownVtbl) { + fn CreateJob( + DisplayName: LPCWSTR, + Type: BG_JOB_TYPE, + pJobId: *mut GUID, + ppJob: *mut *mut IBackgroundCopyJob, + ) -> HRESULT, + fn GetJob( + jobID: REFGUID, + ppJob: *mut *mut IBackgroundCopyJob, + ) -> HRESULT, + fn EnumJobs( + dwFlags: DWORD, + ppEnum: *mut *mut IEnumBackgroundCopyJobs, + ) -> HRESULT, + fn GetErrorDescription( + hResult: HRESULT, + LanguageId: DWORD, + pErrorDescription: *mut LPWSTR, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits10_1.rs b/winapi/src/um/bits10_1.rs new file mode 100644 index 000000000..327161a8d --- /dev/null +++ b/winapi/src/um/bits10_1.rs @@ -0,0 +1,37 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::minwindef::DWORD; +use um::bits::{IBackgroundCopyFile, IBackgroundCopyJob}; +use um::bits2_0::BG_FILE_RANGE; +use um::bits3_0::{IBackgroundCopyCallback2, IBackgroundCopyCallback2Vtbl}; +use um::bits5_0::{IBackgroundCopyFile5, IBackgroundCopyFile5Vtbl}; +use um::winnt::HRESULT; +RIDL!{#[uuid(0x98c97bd2, 0xe32b, 0x4ad8, 0xa5, 0x28, 0x95, 0xfd, 0x8b, 0x16, 0xbd, 0x42)] +interface IBackgroundCopyCallback3(IBackgroundCopyCallback3Vtbl): + IBackgroundCopyCallback2(IBackgroundCopyCallback2Vtbl) { + fn FileRangesTransferred( + job: *mut IBackgroundCopyJob, + file: *mut IBackgroundCopyFile, + rangeCount: DWORD, + ranges: *const BG_FILE_RANGE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xcf6784f7, 0xd677, 0x49fd, 0x93, 0x68, 0xcb, 0x47, 0xae, 0xe9, 0xd1, 0xad)] +interface IBackgroundCopyFile6(IBackgroundCopyFile6Vtbl): + IBackgroundCopyFile5(IBackgroundCopyFile5Vtbl) { + fn UpdateDownloadPosition( + offset: UINT64, + ) -> HRESULT, + fn RequestFileRanges( + rangeCount: DWORD, + ranges: *const BG_FILE_RANGE, + ) -> HRESULT, + fn GetFilledFileRanges( + rangeCount: *mut DWORD, + ranges: *mut *mut BG_FILE_RANGE, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits1_5.rs b/winapi/src/um/bits1_5.rs new file mode 100644 index 000000000..b2890e7db --- /dev/null +++ b/winapi/src/um/bits1_5.rs @@ -0,0 +1,70 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::rpcndr::byte; +use um::bits::{IBackgroundCopyJob, IBackgroundCopyJobVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR}; +STRUCT!{struct BG_JOB_REPLY_PROGRESS { + BytesTotal: UINT64, + BytesTransferred: UINT64, +}} +ENUM!{enum BG_AUTH_TARGET { + BG_AUTH_TARGET_SERVER = 1, + BG_AUTH_TARGET_PROXY = BG_AUTH_TARGET_SERVER + 1, +}} +ENUM!{enum BG_AUTH_SCHEME { + BG_AUTH_SCHEME_BASIC = 1, + BG_AUTH_SCHEME_DIGEST = BG_AUTH_SCHEME_BASIC + 1, + BG_AUTH_SCHEME_NTLM = BG_AUTH_SCHEME_DIGEST + 1, + BG_AUTH_SCHEME_NEGOTIATE = BG_AUTH_SCHEME_NTLM + 1, + BG_AUTH_SCHEME_PASSPORT = BG_AUTH_SCHEME_NEGOTIATE + 1, +}} +STRUCT!{struct BG_BASIC_CREDENTIALS { + UserName: LPWSTR, + Password: LPWSTR, +}} +UNION!{union BG_AUTH_CREDENTIALS_UNION { + [usize; 2], + Basic Basic_mut: BG_BASIC_CREDENTIALS, +}} +STRUCT!{struct BG_AUTH_CREDENTIALS { + Target: BG_AUTH_TARGET, + Scheme: BG_AUTH_SCHEME, + Credentials: BG_AUTH_CREDENTIALS_UNION, +}} +pub type PBG_AUTH_CREDENTIALS = *mut BG_AUTH_CREDENTIALS; +RIDL!{#[uuid(0x54b50739, 0x686f, 0x45eb, 0x9d, 0xff, 0xd6, 0xa9, 0xa0, 0xfa, 0xa9, 0xaf)] +interface IBackgroundCopyJob2(IBackgroundCopyJob2Vtbl): + IBackgroundCopyJob(IBackgroundCopyJobVtbl) { + fn SetNotifyCmdLine( + Program: LPCWSTR, + Parameters: LPCWSTR, + ) -> HRESULT, + fn GetNotifyCmdLine( + pProgram: *mut LPWSTR, + pParameters: *mut LPWSTR, + ) -> HRESULT, + fn GetReplyProgress( + pProgress: *mut BG_JOB_REPLY_PROGRESS, + ) -> HRESULT, + fn GetReplyData( + ppBuffer: *mut *mut byte, + pLength: *mut UINT64, + ) -> HRESULT, + fn SetReplyFileName( + ReplyFileName: LPCWSTR, + ) -> HRESULT, + fn GetReplyFileName( + pReplyFileName: *mut LPWSTR, + ) -> HRESULT, + fn SetCredentials( + credentials: *mut BG_AUTH_CREDENTIALS, + ) -> HRESULT, + fn RemoveCredentials( + Target: BG_AUTH_TARGET, + Scheme: BG_AUTH_SCHEME, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits2_0.rs b/winapi/src/um/bits2_0.rs new file mode 100644 index 000000000..15e582708 --- /dev/null +++ b/winapi/src/um/bits2_0.rs @@ -0,0 +1,51 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::minwindef::DWORD; +use um::bits::{IBackgroundCopyFile, IBackgroundCopyFileVtbl}; +use um::bits1_5::{IBackgroundCopyJob2, IBackgroundCopyJob2Vtbl}; +use um::winnt::{HRESULT, LPCWSTR}; +pub const BG_LENGTH_TO_EOF: UINT64 = -1i64 as u64; +STRUCT!{struct BG_FILE_RANGE { + InitialOffset: UINT64, + Length: UINT64, +}} +pub const BG_COPY_FILE_OWNER: DWORD = 1; +pub const BG_COPY_FILE_GROUP: DWORD = 2; +pub const BG_COPY_FILE_DACL: DWORD = 4; +pub const BG_COPY_FILE_SACL: DWORD = 8; +pub const BG_COPY_FILE_ALL: DWORD = 15; +RIDL!{#[uuid(0x443c8934, 0x90ff, 0x48ed, 0xbc, 0xde, 0x26, 0xf5, 0xc7, 0x45, 0x00, 0x42)] +interface IBackgroundCopyJob3(IBackgroundCopyJob3Vtbl): + IBackgroundCopyJob2(IBackgroundCopyJob2Vtbl) { + fn ReplaceRemotePrefix( + OldPrefix: LPCWSTR, + NewPrefix: LPCWSTR, + ) -> HRESULT, + fn AddFileWithRanges( + RemoteUrl: LPCWSTR, + LocalName: LPCWSTR, + RangeCount: DWORD, + Ranges: *mut BG_FILE_RANGE, + ) -> HRESULT, + fn SetFileACLFlags( + Flags: DWORD, + ) -> HRESULT, + fn GetFileACLFlags( + Flags: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x83e81b93, 0x0873, 0x474d, 0x8a, 0x8c, 0xf2, 0x01, 0x8b, 0x1a, 0x93, 0x9c)] +interface IBackgroundCopyFile2(IBackgroundCopyFile2Vtbl): + IBackgroundCopyFile(IBackgroundCopyFileVtbl) { + fn GetFileRanges( + RangeCount: *mut DWORD, + Ranges: *mut *mut BG_FILE_RANGE, + ) -> HRESULT, + fn SetRemoteName( + Val: LPCWSTR, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits2_5.rs b/winapi/src/um/bits2_5.rs new file mode 100644 index 000000000..50a5b4d17 --- /dev/null +++ b/winapi/src/um/bits2_5.rs @@ -0,0 +1,64 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::ULONG; +use shared::rpcndr::byte; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR}; +ENUM!{enum BG_CERT_STORE_LOCATION { + BG_CERT_STORE_LOCATION_CURRENT_USER = 0, + BG_CERT_STORE_LOCATION_LOCAL_MACHINE = BG_CERT_STORE_LOCATION_CURRENT_USER + 1, + BG_CERT_STORE_LOCATION_CURRENT_SERVICE = BG_CERT_STORE_LOCATION_LOCAL_MACHINE + 1, + BG_CERT_STORE_LOCATION_SERVICES = BG_CERT_STORE_LOCATION_CURRENT_SERVICE + 1, + BG_CERT_STORE_LOCATION_USERS = BG_CERT_STORE_LOCATION_SERVICES + 1, + BG_CERT_STORE_LOCATION_CURRENT_USER_GROUP_POLICY = BG_CERT_STORE_LOCATION_USERS + 1, + BG_CERT_STORE_LOCATION_LOCAL_MACHINE_GROUP_POLICY + = BG_CERT_STORE_LOCATION_CURRENT_USER_GROUP_POLICY + 1, + BG_CERT_STORE_LOCATION_LOCAL_MACHINE_ENTERPRISE + = BG_CERT_STORE_LOCATION_LOCAL_MACHINE_GROUP_POLICY + 1, +}} +RIDL!{#[uuid(0xf1bd1079, 0x9f01, 0x4bdc, 0x80, 0x36, 0xf0, 0x9b, 0x70, 0x09, 0x50, 0x66)] +interface IBackgroundCopyJobHttpOptions(IBackgroundCopyJobHttpOptionsVtbl): + IUnknown(IUnknownVtbl) { + fn SetClientCertificateByID( + StoreLocation: BG_CERT_STORE_LOCATION, + StoreName: LPCWSTR, + pCertHashBlob: *mut byte, + ) -> HRESULT, + fn SetClientCertificateByName( + StoreLocation: BG_CERT_STORE_LOCATION, + StoreName: LPCWSTR, + SubjectName: LPCWSTR, + ) -> HRESULT, + fn RemoveClientCertificate() -> HRESULT, + fn GetClientCertificate( + pStoreLocation: *mut BG_CERT_STORE_LOCATION, + pStoreName: *mut LPWSTR, + ppCertHashBlob: *mut *mut byte, + pSubjectName: *mut LPWSTR, + ) -> HRESULT, + fn SetCustomHeaders( + RequestHeaders: LPCWSTR, + ) -> HRESULT, + fn GetCustomHeaders( + pRequestHeaders: *mut LPWSTR, + ) -> HRESULT, + fn SetSecurityFlags( + Flags: ULONG, + ) -> HRESULT, + fn GetSecurityFlags( + pFlags: *mut ULONG, + ) -> HRESULT, +}} +pub const BG_SSL_ENABLE_CRL_CHECK: ULONG = 0x0001; +pub const BG_SSL_IGNORE_CERT_CN_INVALID: ULONG = 0x0002; +pub const BG_SSL_IGNORE_CERT_DATE_INVALID: ULONG = 0x0004; +pub const BG_SSL_IGNORE_UNKNOWN_CA: ULONG = 0x0008; +pub const BG_SSL_IGNORE_CERT_WRONG_USAGE: ULONG = 0x0010; +pub const BG_HTTP_REDIRECT_POLICY_MASK: ULONG = 0x0700; +pub const BG_HTTP_REDIRECT_POLICY_ALLOW_SILENT: ULONG = 0x0000; +pub const BG_HTTP_REDIRECT_POLICY_ALLOW_REPORT: ULONG = 0x0100; +pub const BG_HTTP_REDIRECT_POLICY_DISALLOW: ULONG = 0x0200; +pub const BG_HTTP_REDIRECT_POLICY_ALLOW_HTTPS_TO_HTTP: ULONG = 0x0800; diff --git a/winapi/src/um/bits3_0.rs b/winapi/src/um/bits3_0.rs new file mode 100644 index 000000000..478dce642 --- /dev/null +++ b/winapi/src/um/bits3_0.rs @@ -0,0 +1,179 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::guiddef::{GUID, REFGUID}; +use shared::minwindef::{BOOL, DWORD, FILETIME, ULONG}; +use um::bits::{ + IBackgroundCopyCallback, IBackgroundCopyCallbackVtbl, IBackgroundCopyFile, IBackgroundCopyJob, +}; +use um::bits2_0::{ + BG_FILE_RANGE, IBackgroundCopyFile2, IBackgroundCopyFile2Vtbl, IBackgroundCopyJob3, + IBackgroundCopyJob3Vtbl, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR}; +RIDL!{#[uuid(0x659cdeaf, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBitsPeerCacheRecord(IBitsPeerCacheRecordVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pVal: *mut GUID, + ) -> HRESULT, + fn GetOriginUrl( + pVal: *mut LPWSTR, + ) -> HRESULT, + fn GetFileSize( + pVal: *mut UINT64, + ) -> HRESULT, + fn GetFileModificationTime( + pVal: *mut FILETIME, + ) -> HRESULT, + fn GetLastAccessTime( + pVal: *mut FILETIME, + ) -> HRESULT, + fn IsFileValidated() -> HRESULT, + fn GetFileRanges( + pRangeCount: *mut DWORD, + ppRanges: *mut *mut BG_FILE_RANGE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x659cdea4, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IEnumBitsPeerCacheRecords(IEnumBitsPeerCacheRecordsVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IBitsPeerCacheRecord, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumBitsPeerCacheRecords, + ) -> HRESULT, + fn GetCount( + puCount: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x659cdea2, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBitsPeer(IBitsPeerVtbl): IUnknown(IUnknownVtbl) { + fn GetPeerName( + pName: *mut LPWSTR, + ) -> HRESULT, + fn IsAuthenticated( + pAuth: *mut BOOL, + ) -> HRESULT, + fn IsAvailable( + pOnline: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x659cdea5, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IEnumBitsPeers(IEnumBitsPeersVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IBitsPeer, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumBitsPeers, + ) -> HRESULT, + fn GetCount( + puCount: *mut ULONG, + ) -> HRESULT, +}} +pub const BG_ENABLE_PEERCACHING_CLIENT: DWORD = 0x0001; +pub const BG_ENABLE_PEERCACHING_SERVER: DWORD = 0x0002; +pub const BG_DISABLE_BRANCH_CACHE: DWORD = 0x0004; +RIDL!{#[uuid(0x659cdead, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBitsPeerCacheAdministration(IBitsPeerCacheAdministrationVtbl): IUnknown(IUnknownVtbl) { + fn GetMaximumCacheSize( + pBytes: *mut DWORD, + ) -> HRESULT, + fn SetMaximumCacheSize( + Bytes: DWORD, + ) -> HRESULT, + fn GetMaximumContentAge( + pSeconds: *mut ULONG, + ) -> HRESULT, + fn SetMaximumContentAge( + Seconds: ULONG, + ) -> HRESULT, + fn GetConfigurationFlags( + pFlags: *mut DWORD, + ) -> HRESULT, + fn SetConfigurationFlags( + Flags: DWORD, + ) -> HRESULT, + fn EnumRecords( + ppEnum: *mut *mut IEnumBitsPeerCacheRecords, + ) -> HRESULT, + fn GetRecord( + ppRecord: *mut *mut IBitsPeerCacheRecord, + ) -> HRESULT, + fn ClearRecords() -> HRESULT, + fn DeleteRecord( + id: REFGUID, + ) -> HRESULT, + fn DeleteUrl( + url: LPCWSTR, + ) -> HRESULT, + fn EnumPeers( + ppEnum: *mut *mut IEnumBitsPeers, + ) -> HRESULT, + fn ClearPeers() -> HRESULT, + fn DiscoverPeers() -> HRESULT, +}} +pub const BG_JOB_ENABLE_PEERCACHING_CLIENT: DWORD = 0x0001; +pub const BG_JOB_ENABLE_PEERCACHING_SERVER: DWORD = 0x0002; +pub const BG_JOB_DISABLE_BRANCH_CACHE: DWORD = 0x0004; +RIDL!{#[uuid(0x659cdeae, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBackgroundCopyJob4(IBackgroundCopyJob4Vtbl): + IBackgroundCopyJob3(IBackgroundCopyJob3Vtbl) { + fn SetPeerCachingFlags( + Flags: DWORD, + ) -> HRESULT, + fn GetPeerCachingFlags( + pFlags: *mut DWORD, + ) -> HRESULT, + fn GetOwnerIntegrityLevel( + pLevel: *mut ULONG, + ) -> HRESULT, + fn GetOwnerElevationState( + pElevated: *mut BOOL, + ) -> HRESULT, + fn SetMaximumDownloadTime( + Timeout: ULONG, + ) -> HRESULT, + fn GetMaximumDownloadTime( + pTimeout: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x659cdeaa, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBackgroundCopyFile3(IBackgroundCopyFile3Vtbl): + IBackgroundCopyFile2(IBackgroundCopyFile2Vtbl) { + fn GetTemporaryName( + pFilename: *mut LPWSTR, + ) -> HRESULT, + fn SetValidationState( + state: BOOL, + ) -> HRESULT, + fn GetValidationState( + pState: *mut BOOL, + ) -> HRESULT, + fn IsDownloadedFromPeer( + pVal: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x659cdeac, 0x489e, 0x11d9, 0xa9, 0xcd, 0x00, 0x0d, 0x56, 0x96, 0x52, 0x51)] +interface IBackgroundCopyCallback2(IBackgroundCopyCallback2Vtbl): + IBackgroundCopyCallback(IBackgroundCopyCallbackVtbl) { + fn FileTransferred( + pJob: *mut IBackgroundCopyJob, + pFile: *mut IBackgroundCopyFile, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits4_0.rs b/winapi/src/um/bits4_0.rs new file mode 100644 index 000000000..2cd763a68 --- /dev/null +++ b/winapi/src/um/bits4_0.rs @@ -0,0 +1,32 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::PUINT64; +use shared::minwindef::DWORD; +use um::bits3_0::{IBackgroundCopyFile3, IBackgroundCopyFile3Vtbl}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPWSTR}; +RIDL!{#[uuid(0x9a2584c3, 0xf7d2, 0x457a, 0x9a, 0x5e, 0x22, 0xb6, 0x7b, 0xff, 0xc7, 0xd2)] +interface IBitsTokenOptions(IBitsTokenOptionsVtbl): IUnknown(IUnknownVtbl) { + fn SetHelperTokenFlags( + UsageFlags: DWORD, + ) -> HRESULT, + fn GetHelperTokenFlags( + pFlags: *mut DWORD, + ) -> HRESULT, + fn SetHelperToken() -> HRESULT, + fn ClearHelperToken() -> HRESULT, + fn GetHelperTokenSid( + pSid: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xef7e0655, 0x7888, 0x4960, 0xb0, 0xe5, 0x73, 0x08, 0x46, 0xe0, 0x34, 0x92)] +interface IBackgroundCopyFile4(IBackgroundCopyFile4Vtbl): + IBackgroundCopyFile3(IBackgroundCopyFile3Vtbl) { + fn GetPeerDownloadStats( + pFromOrigin: PUINT64, + pFromPeers: PUINT64, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bits5_0.rs b/winapi/src/um/bits5_0.rs new file mode 100644 index 000000000..97166eb83 --- /dev/null +++ b/winapi/src/um/bits5_0.rs @@ -0,0 +1,95 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD}; +use um::bits1_5::BG_AUTH_TARGET; +use um::bits3_0::{IBackgroundCopyJob4, IBackgroundCopyJob4Vtbl}; +use um::bits4_0::{IBackgroundCopyFile4, IBackgroundCopyFile4Vtbl}; +use um::winnt::{HRESULT, LPWSTR}; +pub const BITS_COST_STATE_UNRESTRICTED: DWORD = 0x1; +pub const BITS_COST_STATE_CAPPED_USAGE_UNKNOWN: DWORD = 0x2; +pub const BITS_COST_STATE_BELOW_CAP: DWORD = 0x4; +pub const BITS_COST_STATE_NEAR_CAP: DWORD = 0x8; +pub const BITS_COST_STATE_OVERCAP_CHARGED: DWORD = 0x10; +pub const BITS_COST_STATE_OVERCAP_THROTTLED: DWORD = 0x20; +pub const BITS_COST_STATE_USAGE_BASED: DWORD = 0x40; +pub const BITS_COST_STATE_ROAMING: DWORD = 0x80; +pub const BITS_COST_OPTION_IGNORE_CONGESTION: DWORD = 0x80000000; +pub const BITS_COST_STATE_RESERVED: DWORD = 0x40000000; +pub const BITS_COST_STATE_TRANSFER_NOT_ROAMING: DWORD = BITS_COST_OPTION_IGNORE_CONGESTION + | BITS_COST_STATE_USAGE_BASED | BITS_COST_STATE_OVERCAP_THROTTLED + | BITS_COST_STATE_OVERCAP_CHARGED | BITS_COST_STATE_NEAR_CAP | BITS_COST_STATE_BELOW_CAP + | BITS_COST_STATE_CAPPED_USAGE_UNKNOWN | BITS_COST_STATE_UNRESTRICTED; +pub const BITS_COST_STATE_TRANSFER_NO_SURCHARGE: DWORD = BITS_COST_OPTION_IGNORE_CONGESTION + | BITS_COST_STATE_USAGE_BASED | BITS_COST_STATE_OVERCAP_THROTTLED | BITS_COST_STATE_NEAR_CAP + | BITS_COST_STATE_BELOW_CAP | BITS_COST_STATE_CAPPED_USAGE_UNKNOWN + | BITS_COST_STATE_UNRESTRICTED; +pub const BITS_COST_STATE_TRANSFER_STANDARD: DWORD = BITS_COST_OPTION_IGNORE_CONGESTION + | BITS_COST_STATE_USAGE_BASED | BITS_COST_STATE_OVERCAP_THROTTLED | BITS_COST_STATE_BELOW_CAP + | BITS_COST_STATE_CAPPED_USAGE_UNKNOWN | BITS_COST_STATE_UNRESTRICTED; +pub const BITS_COST_STATE_TRANSFER_UNRESTRICTED: DWORD = BITS_COST_OPTION_IGNORE_CONGESTION + | BITS_COST_STATE_OVERCAP_THROTTLED | BITS_COST_STATE_UNRESTRICTED; +pub const BITS_COST_STATE_TRANSFER_ALWAYS: DWORD = BITS_COST_OPTION_IGNORE_CONGESTION + | BITS_COST_STATE_ROAMING | BITS_COST_STATE_USAGE_BASED | BITS_COST_STATE_OVERCAP_THROTTLED + | BITS_COST_STATE_OVERCAP_CHARGED | BITS_COST_STATE_NEAR_CAP | BITS_COST_STATE_BELOW_CAP + | BITS_COST_STATE_CAPPED_USAGE_UNKNOWN | BITS_COST_STATE_UNRESTRICTED; +ENUM!{enum BITS_JOB_TRANSFER_POLICY { + BITS_JOB_TRANSFER_POLICY_ALWAYS = 0x800000ff, + BITS_JOB_TRANSFER_POLICY_NOT_ROAMING = 0x8000007f, + BITS_JOB_TRANSFER_POLICY_NO_SURCHARGE = 0x8000006f, + BITS_JOB_TRANSFER_POLICY_STANDARD = 0x80000067, + BITS_JOB_TRANSFER_POLICY_UNRESTRICTED = 0x80000021, +}} +ENUM!{enum BITS_JOB_PROPERTY_ID { + BITS_JOB_PROPERTY_ID_COST_FLAGS = 1, + BITS_JOB_PROPERTY_NOTIFICATION_CLSID = 2, + BITS_JOB_PROPERTY_DYNAMIC_CONTENT = 3, + BITS_JOB_PROPERTY_HIGH_PERFORMANCE = 4, + BITS_JOB_PROPERTY_MAX_DOWNLOAD_SIZE = 5, + BITS_JOB_PROPERTY_USE_STORED_CREDENTIALS = 7, + BITS_JOB_PROPERTY_MINIMUM_NOTIFICATION_INTERVAL_MS = 9, + BITS_JOB_PROPERTY_ON_DEMAND_MODE = 10, +}} +UNION!{union BITS_JOB_PROPERTY_VALUE { + [u64; 2], + Dword Dword_mut: DWORD, + ClsID ClsID_mut: GUID, + Enable Enable_mut: BOOL, + Uint64 Uint64_mut: UINT64, + Target Target_mut: BG_AUTH_TARGET, +}} +ENUM!{enum BITS_FILE_PROPERTY_ID { + BITS_FILE_PROPERTY_ID_HTTP_RESPONSE_HEADERS = 1, +}} +UNION!{union BITS_FILE_PROPERTY_VALUE { + [usize; 1], + String String_mut: LPWSTR, +}} +RIDL!{#[uuid(0xe847030c, 0xbbba, 0x4657, 0xaf, 0x6d, 0x48, 0x4a, 0xa4, 0x2b, 0xf1, 0xfe)] +interface IBackgroundCopyJob5(IBackgroundCopyJob5Vtbl): + IBackgroundCopyJob4(IBackgroundCopyJob4Vtbl) { + fn SetProperty( + PropertyId: BITS_JOB_PROPERTY_ID, + PropertyValue: BITS_JOB_PROPERTY_VALUE, + ) -> HRESULT, + fn GetProperty( + PropertyId: BITS_JOB_PROPERTY_ID, + PropertyValue: *mut BITS_JOB_PROPERTY_VALUE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x85c1657f, 0xdafc, 0x40e8, 0x88, 0x34, 0xdf, 0x18, 0xea, 0x25, 0x71, 0x7e)] +interface IBackgroundCopyFile5(IBackgroundCopyFile5Vtbl): + IBackgroundCopyFile4(IBackgroundCopyFile4Vtbl) { + fn SetProperty( + PropertyId: BITS_JOB_PROPERTY_ID, + PropertyValue: BITS_JOB_PROPERTY_VALUE, + ) -> HRESULT, + fn GetProperty( + PropertyId: BITS_JOB_PROPERTY_ID, + PropertyValue: *mut BITS_JOB_PROPERTY_VALUE, + ) -> HRESULT, +}} diff --git a/winapi/src/um/bitscfg.rs b/winapi/src/um/bitscfg.rs new file mode 100644 index 000000000..3d9f46a2d --- /dev/null +++ b/winapi/src/um/bitscfg.rs @@ -0,0 +1,70 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_uchar, c_ulong}; +use shared::guiddef::REFIID; +use shared::wtypes::BSTR; +use um::oaidl::{IDispatch, IDispatchVtbl}; +use um::unknwnbase::IUnknown; +use um::winnt::HRESULT; +RIDL!{#[uuid(0x29cfbbf7, 0x09e4, 0x4b97, 0xb0, 0xbc, 0xf2, 0x28, 0x7e, 0x3d, 0x8e, 0xb3)] +interface IBITSExtensionSetup(IBITSExtensionSetupVtbl): IDispatch(IDispatchVtbl) { + fn EnableBITSUploads() -> HRESULT, + fn DisableBITSUploads() -> HRESULT, + fn GetCleanupTaskName( + pTaskName: *mut BSTR, + ) -> HRESULT, + fn GetCleanupTask( + riid: REFIID, + ppUnk: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd5d2d542, 0x5503, 0x4e64, 0x8b, 0x48, 0x72, 0xef, 0x91, 0xa3, 0x2e, 0xe1)] +interface IBITSExtensionSetupFactory(IBITSExtensionSetupFactoryVtbl): IDispatch(IDispatchVtbl) { + fn GetObject( + Path: BSTR, + ppExtensionSetup: *mut *mut IBITSExtensionSetup, + ) -> HRESULT, +}} +extern "system" { + pub fn BSTR_UserSize( + pFlags: *mut c_ulong, + Offset: c_ulong, + pBstr: *mut BSTR, + ) -> c_ulong; + pub fn BSTR_UserMarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserUnmarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserFree( + pFlags: *mut c_ulong, + pBstr: *mut BSTR, + ); + pub fn BSTR_UserSize64( + pFlags: *mut c_ulong, + Offset: c_ulong, + pBstr: *mut BSTR, + ) -> c_ulong; + pub fn BSTR_UserMarshal64( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserUnmarshal64( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserFree64( + pFlags: *mut c_ulong, + pBstr: *mut BSTR, + ); +} diff --git a/winapi/src/um/bitsmsg.rs b/winapi/src/um/bitsmsg.rs new file mode 100644 index 000000000..b7029f730 --- /dev/null +++ b/winapi/src/um/bitsmsg.rs @@ -0,0 +1,142 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! error code definitions for the background file copier +use shared::minwindef::DWORD; +pub const BG_E_NOT_FOUND: DWORD = 0x80200001; +pub const BG_E_INVALID_STATE: DWORD = 0x80200002; +pub const BG_E_EMPTY: DWORD = 0x80200003; +pub const BG_E_FILE_NOT_AVAILABLE: DWORD = 0x80200004; +pub const BG_E_PROTOCOL_NOT_AVAILABLE: DWORD = 0x80200005; +pub const BG_S_ERROR_CONTEXT_NONE: DWORD = 0x00200006; +pub const BG_E_ERROR_CONTEXT_UNKNOWN: DWORD = 0x80200007; +pub const BG_E_ERROR_CONTEXT_GENERAL_QUEUE_MANAGER: DWORD = 0x80200008; +pub const BG_E_ERROR_CONTEXT_LOCAL_FILE: DWORD = 0x80200009; +pub const BG_E_ERROR_CONTEXT_REMOTE_FILE: DWORD = 0x8020000A; +pub const BG_E_ERROR_CONTEXT_GENERAL_TRANSPORT: DWORD = 0x8020000B; +pub const BG_E_ERROR_CONTEXT_QUEUE_MANAGER_NOTIFICATION: DWORD = 0x8020000C; +pub const BG_E_DESTINATION_LOCKED: DWORD = 0x8020000D; +pub const BG_E_VOLUME_CHANGED: DWORD = 0x8020000E; +pub const BG_E_ERROR_INFORMATION_UNAVAILABLE: DWORD = 0x8020000F; +pub const BG_E_NETWORK_DISCONNECTED: DWORD = 0x80200010; +pub const BG_E_MISSING_FILE_SIZE: DWORD = 0x80200011; +pub const BG_E_INSUFFICIENT_HTTP_SUPPORT: DWORD = 0x80200012; +pub const BG_E_INSUFFICIENT_RANGE_SUPPORT: DWORD = 0x80200013; +pub const BG_E_REMOTE_NOT_SUPPORTED: DWORD = 0x80200014; +pub const BG_E_NEW_OWNER_DIFF_MAPPING: DWORD = 0x80200015; +pub const BG_E_NEW_OWNER_NO_FILE_ACCESS: DWORD = 0x80200016; +pub const BG_S_PARTIAL_COMPLETE: DWORD = 0x00200017; +pub const BG_E_PROXY_LIST_TOO_LARGE: DWORD = 0x80200018; +pub const BG_E_PROXY_BYPASS_LIST_TOO_LARGE: DWORD = 0x80200019; +pub const BG_S_UNABLE_TO_DELETE_FILES: DWORD = 0x0020001A; +pub const BG_E_INVALID_SERVER_RESPONSE: DWORD = 0x8020001B; +pub const BG_E_TOO_MANY_FILES: DWORD = 0x8020001C; +pub const BG_E_LOCAL_FILE_CHANGED: DWORD = 0x8020001D; +pub const BG_E_ERROR_CONTEXT_REMOTE_APPLICATION: DWORD = 0x8020001E; +pub const BG_E_SESSION_NOT_FOUND: DWORD = 0x8020001F; +pub const BG_E_TOO_LARGE: DWORD = 0x80200020; +pub const BG_E_STRING_TOO_LONG: DWORD = 0x80200021; +pub const BG_E_CLIENT_SERVER_PROTOCOL_MISMATCH: DWORD = 0x80200022; +pub const BG_E_SERVER_EXECUTE_ENABLE: DWORD = 0x80200023; +pub const BG_E_NO_PROGRESS: DWORD = 0x80200024; +pub const BG_E_USERNAME_TOO_LARGE: DWORD = 0x80200025; +pub const BG_E_PASSWORD_TOO_LARGE: DWORD = 0x80200026; +pub const BG_E_INVALID_AUTH_TARGET: DWORD = 0x80200027; +pub const BG_E_INVALID_AUTH_SCHEME: DWORD = 0x80200028; +pub const BG_E_FILE_NOT_FOUND: DWORD = 0x80200029; +pub const BG_S_PROXY_CHANGED: DWORD = 0x0020002A; +pub const BG_E_INVALID_RANGE: DWORD = 0x8020002B; +pub const BG_E_OVERLAPPING_RANGES: DWORD = 0x8020002C; +pub const BG_E_CONNECT_FAILURE: DWORD = 0x8020002D; +pub const BG_E_CONNECTION_CLOSED: DWORD = 0x8020002E; +pub const BG_E_BLOCKED_BY_POLICY: DWORD = 0x8020003E; +pub const BG_E_INVALID_PROXY_INFO: DWORD = 0x8020003F; +pub const BG_E_INVALID_CREDENTIALS: DWORD = 0x80200040; +pub const BG_E_INVALID_HASH_ALGORITHM: DWORD = 0x80200041; +pub const BG_E_RECORD_DELETED: DWORD = 0x80200042; +pub const BG_E_COMMIT_IN_PROGRESS: DWORD = 0x80200043; +pub const BG_E_DISCOVERY_IN_PROGRESS: DWORD = 0x80200044; +pub const BG_E_UPNP_ERROR: DWORD = 0x80200045; +pub const BG_E_TEST_OPTION_BLOCKED_DOWNLOAD: DWORD = 0x80200046; +pub const BG_E_PEERCACHING_DISABLED: DWORD = 0x80200047; +pub const BG_E_BUSYCACHERECORD: DWORD = 0x80200048; +pub const BG_E_TOO_MANY_JOBS_PER_USER: DWORD = 0x80200049; +pub const BG_E_TOO_MANY_JOBS_PER_MACHINE: DWORD = 0x80200050; +pub const BG_E_TOO_MANY_FILES_IN_JOB: DWORD = 0x80200051; +pub const BG_E_TOO_MANY_RANGES_IN_FILE: DWORD = 0x80200052; +pub const BG_E_VALIDATION_FAILED: DWORD = 0x80200053; +pub const BG_E_MAXDOWNLOAD_TIMEOUT: DWORD = 0x80200054; +pub const BG_S_OVERRIDDEN_BY_POLICY: DWORD = 0x00200055; +pub const BG_E_TOKEN_REQUIRED: DWORD = 0x80200056; +pub const BG_E_UNKNOWN_PROPERTY_ID: DWORD = 0x80200057; +pub const BG_E_READ_ONLY_PROPERTY: DWORD = 0x80200058; +pub const BG_E_BLOCKED_BY_COST_TRANSFER_POLICY: DWORD = 0x80200059; +pub const BG_E_PROPERTY_SUPPORTED_FOR_DOWNLOAD_JOBS_ONLY: DWORD = 0x80200060; +pub const BG_E_READ_ONLY_PROPERTY_AFTER_ADDFILE: DWORD = 0x80200061; +pub const BG_E_READ_ONLY_PROPERTY_AFTER_RESUME: DWORD = 0x80200062; +pub const BG_E_MAX_DOWNLOAD_SIZE_INVALID_VALUE: DWORD = 0x80200063; +pub const BG_E_MAX_DOWNLOAD_SIZE_LIMIT_REACHED: DWORD = 0x80200064; +pub const BG_E_STANDBY_MODE: DWORD = 0x80200065; +pub const BG_E_USE_STORED_CREDENTIALS_NOT_SUPPORTED: DWORD = 0x80200066; +pub const BG_E_BLOCKED_BY_BATTERY_POLICY: DWORD = 0x80200067; +pub const BG_E_BLOCKED_BY_BATTERY_SAVER: DWORD = 0x80200068; +pub const BG_E_WATCHDOG_TIMEOUT: DWORD = 0x80200069; +pub const BG_E_APP_PACKAGE_NOT_FOUND: DWORD = 0x8020006A; +pub const BG_E_APP_PACKAGE_SCENARIO_NOT_SUPPORTED: DWORD = 0x8020006B; +pub const BG_E_DATABASE_CORRUPT: DWORD = 0x8020006C; +pub const BG_E_RANDOM_ACCESS_NOT_SUPPORTED: DWORD = 0x8020006D; +pub const BG_E_HTTP_ERROR_100: DWORD = 0x80190064; +pub const BG_E_HTTP_ERROR_101: DWORD = 0x80190065; +pub const BG_E_HTTP_ERROR_200: DWORD = 0x801900C8; +pub const BG_E_HTTP_ERROR_201: DWORD = 0x801900C9; +pub const BG_E_HTTP_ERROR_202: DWORD = 0x801900CA; +pub const BG_E_HTTP_ERROR_203: DWORD = 0x801900CB; +pub const BG_E_HTTP_ERROR_204: DWORD = 0x801900CC; +pub const BG_E_HTTP_ERROR_205: DWORD = 0x801900CD; +pub const BG_E_HTTP_ERROR_206: DWORD = 0x801900CE; +pub const BG_E_HTTP_ERROR_300: DWORD = 0x8019012C; +pub const BG_E_HTTP_ERROR_301: DWORD = 0x8019012D; +pub const BG_E_HTTP_ERROR_302: DWORD = 0x8019012E; +pub const BG_E_HTTP_ERROR_303: DWORD = 0x8019012F; +pub const BG_E_HTTP_ERROR_304: DWORD = 0x80190130; +pub const BG_E_HTTP_ERROR_305: DWORD = 0x80190131; +pub const BG_E_HTTP_ERROR_307: DWORD = 0x80190133; +pub const BG_E_HTTP_ERROR_400: DWORD = 0x80190190; +pub const BG_E_HTTP_ERROR_401: DWORD = 0x80190191; +pub const BG_E_HTTP_ERROR_402: DWORD = 0x80190192; +pub const BG_E_HTTP_ERROR_403: DWORD = 0x80190193; +pub const BG_E_HTTP_ERROR_404: DWORD = 0x80190194; +pub const BG_E_HTTP_ERROR_405: DWORD = 0x80190195; +pub const BG_E_HTTP_ERROR_406: DWORD = 0x80190196; +pub const BG_E_HTTP_ERROR_407: DWORD = 0x80190197; +pub const BG_E_HTTP_ERROR_408: DWORD = 0x80190198; +pub const BG_E_HTTP_ERROR_409: DWORD = 0x80190199; +pub const BG_E_HTTP_ERROR_410: DWORD = 0x8019019A; +pub const BG_E_HTTP_ERROR_411: DWORD = 0x8019019B; +pub const BG_E_HTTP_ERROR_412: DWORD = 0x8019019C; +pub const BG_E_HTTP_ERROR_413: DWORD = 0x8019019D; +pub const BG_E_HTTP_ERROR_414: DWORD = 0x8019019E; +pub const BG_E_HTTP_ERROR_415: DWORD = 0x8019019F; +pub const BG_E_HTTP_ERROR_416: DWORD = 0x801901A0; +pub const BG_E_HTTP_ERROR_417: DWORD = 0x801901A1; +pub const BG_E_HTTP_ERROR_449: DWORD = 0x801901C1; +pub const BG_E_HTTP_ERROR_500: DWORD = 0x801901F4; +pub const BG_E_HTTP_ERROR_501: DWORD = 0x801901F5; +pub const BG_E_HTTP_ERROR_502: DWORD = 0x801901F6; +pub const BG_E_HTTP_ERROR_503: DWORD = 0x801901F7; +pub const BG_E_HTTP_ERROR_504: DWORD = 0x801901F8; +pub const BG_E_HTTP_ERROR_505: DWORD = 0x801901F9; +pub const BITS_MC_JOB_CANCELLED: DWORD = 0x80194000; +pub const BITS_MC_FILE_DELETION_FAILED: DWORD = 0x80194001; +pub const BITS_MC_FILE_DELETION_FAILED_MORE: DWORD = 0x80194002; +pub const BITS_MC_JOB_PROPERTY_CHANGE: DWORD = 0x80194003; +pub const BITS_MC_JOB_TAKE_OWNERSHIP: DWORD = 0x80194004; +pub const BITS_MC_JOB_SCAVENGED: DWORD = 0x80194005; +pub const BITS_MC_JOB_NOTIFICATION_FAILURE: DWORD = 0x80194006; +pub const BITS_MC_STATE_FILE_CORRUPT: DWORD = 0x80194007; +pub const BITS_MC_FAILED_TO_START: DWORD = 0x80194008; +pub const BITS_MC_FATAL_IGD_ERROR: DWORD = 0x80194009; +pub const BITS_MC_PEERCACHING_PORT: DWORD = 0x8019400A; +pub const BITS_MC_WSD_PORT: DWORD = 0x8019400B; diff --git a/winapi/src/um/cfgmgr32.rs b/winapi/src/um/cfgmgr32.rs new file mode 100644 index 000000000..2c4c7f39f --- /dev/null +++ b/winapi/src/um/cfgmgr32.rs @@ -0,0 +1,2077 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! user APIs for the Configuration Manager +use shared::basetsd::{DWORD_PTR, ULONG32, ULONG64, ULONG_PTR}; +use shared::cfg::PPNP_VETO_TYPE; +use shared::devpropdef::{DEVPROPKEY, DEVPROPTYPE}; +use shared::guiddef::{GUID, LPGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, MAX_PATH, PBOOL, PBYTE, PHKEY, PULONG, ULONG, WORD}; +use um::winnt::{ + ANYSIZE_ARRAY, CHAR, DWORDLONG, HANDLE, LARGE_INTEGER, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, + PCHAR, PCSTR, PCWSTR, PDWORDLONG, PSTR, PVOID, PWCHAR, PWSTR, ULONGLONG, VOID, WCHAR +}; +use um::winreg::REGSAM; +pub type PCVOID = *const VOID; +pub const MAX_DEVICE_ID_LEN: usize = 200; +pub const MAX_DEVNODE_ID_LEN: usize = MAX_DEVICE_ID_LEN; +pub const MAX_GUID_STRING_LEN: usize = 39; +pub const MAX_CLASS_NAME_LEN: usize = 32; +pub const MAX_PROFILE_LEN: usize = 80; +pub const MAX_CONFIG_VALUE: DWORD = 9999; +pub const MAX_INSTANCE_VALUE: DWORD = 9999; +pub const MAX_MEM_REGISTERS: DWORD = 9; +pub const MAX_IO_PORTS: DWORD = 20; +pub const MAX_IRQS: DWORD = 7; +pub const MAX_DMA_CHANNELS: DWORD = 7; +pub const DWORD_MAX: DWORD = 0xffffffff; +pub const DWORDLONG_MAX: DWORDLONG = 0xffffffffffffffff; +pub const CONFIGMG_VERSION: DWORD = 0x0400; +pub type RETURN_TYPE = DWORD; +pub type CONFIGRET = RETURN_TYPE; +pub type DEVNODE = DWORD; +pub type DEVINST = DWORD; +pub type PDEVNODE = *mut DEVNODE; +pub type PDEVINST = *mut DEVNODE; +pub type DEVNODEID_A = *mut CHAR; +pub type DEVINSTID_A = *mut CHAR; +pub type DEVNODEID_W = *mut WCHAR; +pub type DEVINSTID_W = *mut WCHAR; +pub type LOG_CONF = DWORD_PTR; +pub type PLOG_CONF = *mut LOG_CONF; +pub type RES_DES = DWORD_PTR; +pub type PRES_DES = *mut RES_DES; +pub type RESOURCEID = ULONG; +pub type PRESOURCEID = *mut RESOURCEID; +pub type PRIORITY = ULONG; +pub type PPRIORITY = *mut PRIORITY; +pub type RANGE_LIST = DWORD_PTR; +pub type PRANGE_LIST = *mut RANGE_LIST; +pub type RANGE_ELEMENT = DWORD_PTR; +pub type PRANGE_ELEMENT = *mut RANGE_ELEMENT; +pub type HMACHINE = HANDLE; +pub type PHMACHINE = *mut HMACHINE; +pub type CONFLICT_LIST = ULONG_PTR; +pub type PCONFLICT_LIST = *mut CONFLICT_LIST; +STRUCT!{struct CONFLICT_DETAILS_A { + CD_ulSize: ULONG, + CD_ulMask: ULONG, + CD_dnDevInst: DEVINST, + CD_rdResDes: RES_DES, + CD_ulFlags: ULONG, + CD_szDescription: [CHAR; MAX_PATH], +}} +pub type PCONFLICT_DETAILS_A = *mut CONFLICT_DETAILS_A; +STRUCT!{struct CONFLICT_DETAILS_W { + CD_ulSize: ULONG, + CD_ulMask: ULONG, + CD_dnDevInst: DEVINST, + CD_rdResDes: RES_DES, + CD_ulFlags: ULONG, + CD_szDescription: [WCHAR; MAX_PATH], +}} +pub type PCONFLICT_DETAILS_W = *mut CONFLICT_DETAILS_W; +pub const CM_CDMASK_DEVINST: ULONG = 0x00000001; +pub const CM_CDMASK_RESDES: ULONG = 0x00000002; +pub const CM_CDMASK_FLAGS: ULONG = 0x00000004; +pub const CM_CDMASK_DESCRIPTION: ULONG = 0x00000008; +pub const CM_CDMASK_VALID: ULONG = 0x0000000F; +pub const CM_CDFLAGS_DRIVER: ULONG = 0x00000001; +pub const CM_CDFLAGS_ROOT_OWNED: ULONG = 0x00000002; +pub const CM_CDFLAGS_RESERVED: ULONG = 0x00000004; +pub type REGDISPOSITION = ULONG; +pub const mMD_MemoryType: DWORD = 0x1; +pub const fMD_MemoryType: DWORD = mMD_MemoryType; +pub const fMD_ROM: DWORD = 0x0; +pub const fMD_RAM: DWORD = 0x1; +pub const mMD_32_24: DWORD = 0x2; +pub const fMD_32_24: DWORD = mMD_32_24; +pub const fMD_24: DWORD = 0x0; +pub const fMD_32: DWORD = 0x2; +pub const mMD_Prefetchable: DWORD = 0x4; +pub const fMD_Prefetchable: DWORD = mMD_Prefetchable; +pub const fMD_Pref: DWORD = mMD_Prefetchable; +pub const fMD_PrefetchDisallowed: DWORD = 0x0; +pub const fMD_PrefetchAllowed: DWORD = 0x4; +pub const mMD_Readable: DWORD = 0x8; +pub const fMD_Readable: DWORD = mMD_Readable; +pub const fMD_ReadAllowed: DWORD = 0x0; +pub const fMD_ReadDisallowed: DWORD = 0x8; +pub const mMD_CombinedWrite: DWORD = 0x10; +pub const fMD_CombinedWrite: DWORD = mMD_CombinedWrite; +pub const fMD_CombinedWriteDisallowed: DWORD = 0x0; +pub const fMD_CombinedWriteAllowed: DWORD = 0x10; +pub const mMD_Cacheable: DWORD = 0x20; +pub const fMD_NonCacheable: DWORD = 0x0; +pub const fMD_Cacheable: DWORD = 0x20; +pub const fMD_WINDOW_DECODE: DWORD = 0x40; +pub const fMD_MEMORY_BAR: DWORD = 0x80; +STRUCT!{#[repr(packed)] struct MEM_RANGE { + MR_Align: DWORDLONG, + MR_nBytes: ULONG, + MR_Min: DWORDLONG, + MR_Max: DWORDLONG, + MR_Flags: DWORD, + MR_Reserved: DWORD, +}} +pub type PMEM_RANGE = *mut MEM_RANGE; +STRUCT!{#[repr(packed)] struct MEM_DES { + MD_Count: DWORD, + MD_Type: DWORD, + MD_Alloc_Base: DWORDLONG, + MD_Alloc_End: DWORDLONG, + MD_Flags: DWORD, + MD_Reserved: DWORD, +}} +pub type PMEM_DES = *mut MEM_DES; +STRUCT!{#[repr(packed)] struct MEM_RESOURCE { + MEM_Header: MEM_DES, + MEM_Data: [MEM_RANGE; ANYSIZE_ARRAY], +}} +pub type PMEM_RESOURCE = *mut MEM_RESOURCE; +STRUCT!{#[repr(packed)] struct MEM_LARGE_RANGE { + MLR_Align: DWORDLONG, + MLR_nBytes: ULONGLONG, + MLR_Min: DWORDLONG, + MLR_Max: DWORDLONG, + MLR_Flags: DWORD, + MLR_Reserved: DWORD, +}} +pub type PMEM_LARGE_RANGE = *mut MEM_LARGE_RANGE; +STRUCT!{#[repr(packed)] struct MEM_LARGE_DES { + MLD_Count: DWORD, + MLD_Type: DWORD, + MLD_Alloc_Base: DWORDLONG, + MLD_Alloc_End: DWORDLONG, + MLD_Flags: DWORD, + MLD_Reserved: DWORD, +}} +pub type PMEM_LARGE_DES = *mut MEM_LARGE_DES; +STRUCT!{#[repr(packed)] struct MEM_LARGE_RESOURCE { + MEM_LARGE_Header: MEM_LARGE_DES, + MEM_LARGE_Data: [MEM_LARGE_RANGE; ANYSIZE_ARRAY], +}} +pub type PMEM_LARGE_RESOURCE = *mut MEM_LARGE_RESOURCE; +pub const fIOD_PortType: DWORD = 0x1; +pub const fIOD_Memory: DWORD = 0x0; +pub const fIOD_IO: DWORD = 0x1; +pub const fIOD_DECODE: DWORD = 0x00fc; +pub const fIOD_10_BIT_DECODE: DWORD = 0x0004; +pub const fIOD_12_BIT_DECODE: DWORD = 0x0008; +pub const fIOD_16_BIT_DECODE: DWORD = 0x0010; +pub const fIOD_POSITIVE_DECODE: DWORD = 0x0020; +pub const fIOD_PASSIVE_DECODE: DWORD = 0x0040; +pub const fIOD_WINDOW_DECODE: DWORD = 0x0080; +pub const fIOD_PORT_BAR: DWORD = 0x0100; +pub const IO_ALIAS_10_BIT_DECODE: DWORDLONG = 0x00000004; +pub const IO_ALIAS_12_BIT_DECODE: DWORDLONG = 0x00000010; +pub const IO_ALIAS_16_BIT_DECODE: DWORDLONG = 0x00000000; +pub const IO_ALIAS_POSITIVE_DECODE: DWORDLONG = 0x000000FF; +STRUCT!{#[repr(packed)] struct IO_RANGE { + IOR_Align: DWORDLONG, + IOR_nPorts: DWORD, + IOR_Min: DWORDLONG, + IOR_Max: DWORDLONG, + IOR_RangeFlags: DWORD, + IOR_Alias: DWORDLONG, +}} +pub type PIO_RANGE = *mut IO_RANGE; +STRUCT!{#[repr(packed)] struct IO_DES { + IOD_Count: DWORD, + IOD_Type: DWORD, + IOD_Alloc_Base: DWORDLONG, + IOD_Alloc_End: DWORDLONG, + IOD_DesFlags: DWORD, +}} +pub type PIO_DES = *mut IO_DES; +STRUCT!{#[repr(packed)] struct IO_RESOURCE { + IO_Header: IO_DES, + IO_Data: [IO_RANGE; ANYSIZE_ARRAY], +}} +pub type PIO_RESOURCE = *mut IO_RESOURCE; +pub const mDD_Width: ULONG = 0x3; +pub const fDD_BYTE: ULONG = 0x0; +pub const fDD_WORD: ULONG = 0x1; +pub const fDD_DWORD: ULONG = 0x2; +pub const fDD_BYTE_AND_WORD: ULONG = 0x3; +pub const mDD_BusMaster: ULONG = 0x4; +pub const fDD_NoBusMaster: ULONG = 0x0; +pub const fDD_BusMaster: ULONG = 0x4; +pub const mDD_Type: ULONG = 0x18; +pub const fDD_TypeStandard: ULONG = 0x00; +pub const fDD_TypeA: ULONG = 0x08; +pub const fDD_TypeB: ULONG = 0x10; +pub const fDD_TypeF: ULONG = 0x18; +STRUCT!{#[repr(packed)] struct DMA_RANGE { + DR_Min: ULONG, + DR_Max: ULONG, + DR_Flags: ULONG, +}} +pub type PDMA_RANGE = *mut DMA_RANGE; +STRUCT!{#[repr(packed)] struct DMA_DES { + DD_Count: DWORD, + DD_Type: DWORD, + DD_Flags: DWORD, + DD_Alloc_Chan: ULONG, +}} +pub type PDMA_DES = *mut DMA_DES; +STRUCT!{#[repr(packed)] struct DMA_RESOURCE { + DMA_Header: DMA_DES, + DMA_Data: [DMA_RANGE; ANYSIZE_ARRAY], +}} +pub type PDMA_RESOURCE = *mut DMA_RESOURCE; +pub const mIRQD_Share: ULONG = 0x1; +pub const fIRQD_Exclusive: ULONG = 0x0; +pub const fIRQD_Share: ULONG = 0x1; +pub const fIRQD_Share_Bit: ULONG = 0; +pub const fIRQD_Level_Bit: ULONG = 1; +pub const mIRQD_Edge_Level: ULONG = 0x2; +pub const fIRQD_Level: ULONG = 0x0; +pub const fIRQD_Edge: ULONG = 0x2; +STRUCT!{#[repr(packed)] struct IRQ_RANGE { + IRQR_Min: ULONG, + IRQR_Max: ULONG, + IRQR_Flags: ULONG, +}} +pub type PIRQ_RANGE = *mut IRQ_RANGE; +STRUCT!{#[repr(packed)] struct IRQ_DES_32 { + IRQD_Count: DWORD, + IRQD_Type: DWORD, + IRQD_Flags: DWORD, + IRQD_Alloc_Num: ULONG, + IRQD_Affinity: ULONG32, +}} +pub type PIRQ_DES_32 = *mut IRQ_DES_32; +STRUCT!{#[repr(packed)] struct IRQ_DES_64 { + IRQD_Count: DWORD, + IRQD_Type: DWORD, + IRQD_Flags: DWORD, + IRQD_Alloc_Num: ULONG, + IRQD_Affinity: ULONG64, +}} +pub type PIRQ_DES_64 = *mut IRQ_DES_64; +STRUCT!{#[repr(packed)] struct IRQ_RESOURCE_32 { + IRQ_Header: IRQ_DES_32, + IRQ_Data: [IRQ_RANGE; ANYSIZE_ARRAY], +}} +pub type PIRQ_RESOURCE_32 = *mut IRQ_RESOURCE_32; +STRUCT!{#[repr(packed)] struct IRQ_RESOURCE_64 { + IRQ_Header: IRQ_DES_64, + IRQ_Data: [IRQ_RANGE; ANYSIZE_ARRAY], +}} +pub type PIRQ_RESOURCE_64 = *mut IRQ_RESOURCE_64; +STRUCT!{#[repr(packed)] struct DEVPRIVATE_RANGE { + PR_Data1: DWORD, + PR_Data2: DWORD, + PR_Data3: DWORD, +}} +pub type PDEVPRIVATE_RANGE = *mut DEVPRIVATE_RANGE; +STRUCT!{#[repr(packed)] struct DEVPRIVATE_DES { + PD_Count: DWORD, + PD_Type: DWORD, + PD_Data1: DWORD, + PD_Data2: DWORD, + PD_Data3: DWORD, + PD_Flags: DWORD, +}} +pub type PDEVPRIVATE_DES = *mut DEVPRIVATE_DES; +STRUCT!{#[repr(packed)] struct DEVPRIVATE_RESOURCE { + PRV_Header: DEVPRIVATE_DES, + PRV_Data: [DEVPRIVATE_RANGE; ANYSIZE_ARRAY], +}} +pub type PDEVPRIVATE_RESOURCE = *mut DEVPRIVATE_RESOURCE; +STRUCT!{#[repr(packed)] struct CS_DES { + CSD_SignatureLength: DWORD, + CSD_LegacyDataOffset: DWORD, + CSD_LegacyDataSize: DWORD, + CSD_Flags: DWORD, + CSD_ClassGuid: GUID, + CSD_Signature: [BYTE; ANYSIZE_ARRAY], +}} +pub type PCS_DES = *mut CS_DES; +STRUCT!{#[repr(packed)] struct CS_RESOURCE { + CS_Header: CS_DES, +}} +pub type PCS_RESOURCE = *mut CS_RESOURCE; +pub const mPCD_IO_8_16: DWORD = 0x1; +pub const fPCD_IO_8: DWORD = 0x0; +pub const fPCD_IO_16: DWORD = 0x1; +pub const mPCD_MEM_8_16: DWORD = 0x2; +pub const fPCD_MEM_8: DWORD = 0x0; +pub const fPCD_MEM_16: DWORD = 0x2; +pub const mPCD_MEM_A_C: DWORD = 0xC; +pub const fPCD_MEM1_A: DWORD = 0x4; +pub const fPCD_MEM2_A: DWORD = 0x8; +pub const fPCD_IO_ZW_8: DWORD = 0x10; +pub const fPCD_IO_SRC_16: DWORD = 0x20; +pub const fPCD_IO_WS_16: DWORD = 0x40; +pub const mPCD_MEM_WS: DWORD = 0x300; +pub const fPCD_MEM_WS_ONE: DWORD = 0x100; +pub const fPCD_MEM_WS_TWO: DWORD = 0x200; +pub const fPCD_MEM_WS_THREE: DWORD = 0x300; +pub const fPCD_MEM_A: DWORD = 0x4; +pub const fPCD_ATTRIBUTES_PER_WINDOW: DWORD = 0x8000; +pub const fPCD_IO1_16: DWORD = 0x00010000; +pub const fPCD_IO1_ZW_8: DWORD = 0x00020000; +pub const fPCD_IO1_SRC_16: DWORD = 0x00040000; +pub const fPCD_IO1_WS_16: DWORD = 0x00080000; +pub const fPCD_IO2_16: DWORD = 0x00100000; +pub const fPCD_IO2_ZW_8: DWORD = 0x00200000; +pub const fPCD_IO2_SRC_16: DWORD = 0x00400000; +pub const fPCD_IO2_WS_16: DWORD = 0x00800000; +pub const mPCD_MEM1_WS: DWORD = 0x03000000; +pub const fPCD_MEM1_WS_TWO: DWORD = 0x02000000; +pub const fPCD_MEM1_WS_THREE: DWORD = 0x03000000; +pub const fPCD_MEM1_16: DWORD = 0x04000000; +pub const mPCD_MEM2_WS: DWORD = 0x30000000; +pub const fPCD_MEM2_WS_ONE: DWORD = 0x10000000; +pub const fPCD_MEM2_WS_TWO: DWORD = 0x20000000; +pub const fPCD_MEM2_WS_THREE: DWORD = 0x30000000; +pub const fPCD_MEM2_16: DWORD = 0x40000000; +pub const PCD_MAX_MEMORY: usize = 2; +pub const PCD_MAX_IO: usize = 2; +STRUCT!{#[repr(packed)] struct PCCARD_DES { + PCD_Count: DWORD, + PCD_Type: DWORD, + PCD_Flags: DWORD, + PCD_ConfigIndex: BYTE, + PCD_Reserved: [BYTE; 3], + PCD_MemoryCardBase1: DWORD, + PCD_MemoryCardBase2: DWORD, + PCD_MemoryCardBase: [DWORD; PCD_MAX_MEMORY], + PCD_MemoryFlags: [WORD; PCD_MAX_MEMORY], + PCD_IoFlags: [BYTE; PCD_MAX_IO], +}} +pub type PPCCARD_DES = *mut PCCARD_DES; +STRUCT!{#[repr(packed)] struct PCCARD_RESOURCE { + PcCard_Header: PCCARD_DES, +}} +pub type PPCCARD_RESOURCE = *mut PCCARD_RESOURCE; +pub const mPMF_AUDIO_ENABLE: DWORD = 0x8; +pub const fPMF_AUDIO_ENABLE: DWORD = 0x8; +STRUCT!{#[repr(packed)] struct MFCARD_DES { + PMF_Count: DWORD, + PMF_Type: DWORD, + PMF_Flags: DWORD, + PMF_ConfigOptions: BYTE, + PMF_IoResourceIndex: BYTE, + PMF_Reserved: [BYTE; 2], + PMF_ConfigRegisterBase: DWORD, +}} +pub type PMFCARD_DES = *mut MFCARD_DES; +STRUCT!{#[repr(packed)] struct MFCARD_RESOURCE { + MfCard_Header: MFCARD_DES, +}} +pub type PMFCARD_RESOURCE = *mut MFCARD_RESOURCE; +STRUCT!{#[repr(packed)] struct BUSNUMBER_RANGE { + BUSR_Min: ULONG, + BUSR_Max: ULONG, + BUSR_nBusNumbers: ULONG, + BUSR_Flags: ULONG, +}} +pub type PBUSNUMBER_RANGE = *mut BUSNUMBER_RANGE; +STRUCT!{#[repr(packed)] struct BUSNUMBER_DES { + BUSD_Count: DWORD, + BUSD_Type: DWORD, + BUSD_Flags: DWORD, + BUSD_Alloc_Base: ULONG, + BUSD_Alloc_End: ULONG, +}} +pub type PBUSNUMBER_DES = *mut BUSNUMBER_DES; +STRUCT!{#[repr(packed)] struct BUSNUMBER_RESOURCE { + BusNumber_Header: BUSNUMBER_DES, + BusNumber_Data: [BUSNUMBER_RANGE; ANYSIZE_ARRAY], +}} +pub type PBUSNUMBER_RESOURCE = *mut BUSNUMBER_RESOURCE; +STRUCT!{#[repr(packed)] struct CONNECTION_DES { + COND_Type: DWORD, + COND_Flags: DWORD, + COND_Class: BYTE, + COND_ClassType: BYTE, + COND_Reserved1: BYTE, + COND_Reserved2: BYTE, + COND_Id: LARGE_INTEGER, +}} +pub type PCONNECTION_DES = *mut CONNECTION_DES; +STRUCT!{#[repr(packed)] struct CONNECTION_RESOURCE { + Connection_Header: CONNECTION_DES, +}} +pub type PCONNECTION_RESOURCE = *mut CONNECTION_RESOURCE; +pub const CM_HWPI_NOT_DOCKABLE: DWORD = 0x00000000; +pub const CM_HWPI_UNDOCKED: DWORD = 0x00000001; +pub const CM_HWPI_DOCKED: DWORD = 0x00000002; +STRUCT!{#[repr(packed)] struct HWPROFILEINFO_A { + HWPI_ulHWProfile: ULONG, + HWPI_szFriendlyName: [CHAR; MAX_PROFILE_LEN], + HWPI_dwFlags: DWORD, +}} +pub type PHWPROFILEINFO_A = *mut HWPROFILEINFO_A; +STRUCT!{#[repr(packed)] struct HWPROFILEINFO_W { + HWPI_ulHWProfile: ULONG, + HWPI_szFriendlyName: [WCHAR; MAX_PROFILE_LEN], + HWPI_dwFlags: DWORD, +}} +pub type PHWPROFILEINFO_W = *mut HWPROFILEINFO_W; +pub const ResType_All: RESOURCEID = 0x00000000; +pub const ResType_None: RESOURCEID = 0x00000000; +pub const ResType_Mem: RESOURCEID = 0x00000001; +pub const ResType_IO: RESOURCEID = 0x00000002; +pub const ResType_DMA: RESOURCEID = 0x00000003; +pub const ResType_IRQ: RESOURCEID = 0x00000004; +pub const ResType_DoNotUse: RESOURCEID = 0x00000005; +pub const ResType_BusNumber: RESOURCEID = 0x00000006; +pub const ResType_MemLarge: RESOURCEID = 0x00000007; +pub const ResType_MAX: RESOURCEID = 0x00000007; +pub const ResType_Ignored_Bit: RESOURCEID = 0x00008000; +pub const ResType_ClassSpecific: RESOURCEID = 0x0000FFFF; +pub const ResType_Reserved: RESOURCEID = 0x00008000; +pub const ResType_DevicePrivate: RESOURCEID = 0x00008001; +pub const ResType_PcCardConfig: RESOURCEID = 0x00008002; +pub const ResType_MfCardConfig: RESOURCEID = 0x00008003; +pub const ResType_Connection: RESOURCEID = 0x00008004; +pub const CM_ADD_RANGE_ADDIFCONFLICT: ULONG = 0x00000000; +pub const CM_ADD_RANGE_DONOTADDIFCONFLICT: ULONG = 0x00000001; +pub const CM_ADD_RANGE_BITS: ULONG = 0x00000001; +pub const BASIC_LOG_CONF: ULONG = 0x00000000; +pub const FILTERED_LOG_CONF: ULONG = 0x00000001; +pub const ALLOC_LOG_CONF: ULONG = 0x00000002; +pub const BOOT_LOG_CONF: ULONG = 0x00000003; +pub const FORCED_LOG_CONF: ULONG = 0x00000004; +pub const OVERRIDE_LOG_CONF: ULONG = 0x00000005; +pub const NUM_LOG_CONF: ULONG = 0x00000006; +pub const LOG_CONF_BITS: ULONG = 0x00000007; +pub const PRIORITY_EQUAL_FIRST: ULONG = 0x00000008; +pub const PRIORITY_EQUAL_LAST: ULONG = 0x00000000; +pub const PRIORITY_BIT: ULONG = 0x00000008; +pub const RegDisposition_OpenAlways: REGDISPOSITION = 0x00000000; +pub const RegDisposition_OpenExisting: REGDISPOSITION = 0x00000001; +pub const RegDisposition_Bits: REGDISPOSITION = 0x00000001; +pub const CM_ADD_ID_HARDWARE: ULONG = 0x00000000; +pub const CM_ADD_ID_COMPATIBLE: ULONG = 0x00000001; +pub const CM_ADD_ID_BITS: ULONG = 0x00000001; +pub const CM_CREATE_DEVNODE_NORMAL: ULONG = 0x00000000; +pub const CM_CREATE_DEVNODE_NO_WAIT_INSTALL: ULONG = 0x00000001; +pub const CM_CREATE_DEVNODE_PHANTOM: ULONG = 0x00000002; +pub const CM_CREATE_DEVNODE_GENERATE_ID: ULONG = 0x00000004; +pub const CM_CREATE_DEVNODE_DO_NOT_INSTALL: ULONG = 0x00000008; +pub const CM_CREATE_DEVNODE_BITS: ULONG = 0x0000000F; +pub const CM_CREATE_DEVINST_NORMAL: ULONG = CM_CREATE_DEVNODE_NORMAL; +pub const CM_CREATE_DEVINST_NO_WAIT_INSTALL: ULONG = CM_CREATE_DEVNODE_NO_WAIT_INSTALL; +pub const CM_CREATE_DEVINST_PHANTOM: ULONG = CM_CREATE_DEVNODE_PHANTOM; +pub const CM_CREATE_DEVINST_GENERATE_ID: ULONG = CM_CREATE_DEVNODE_GENERATE_ID; +pub const CM_CREATE_DEVINST_DO_NOT_INSTALL: ULONG = CM_CREATE_DEVNODE_DO_NOT_INSTALL; +pub const CM_CREATE_DEVINST_BITS: ULONG = CM_CREATE_DEVNODE_BITS; +pub const CM_DELETE_CLASS_ONLY: ULONG = 0x00000000; +pub const CM_DELETE_CLASS_SUBKEYS: ULONG = 0x00000001; +pub const CM_DELETE_CLASS_INTERFACE: ULONG = 0x00000002; +pub const CM_DELETE_CLASS_BITS: ULONG = 0x00000003; +pub const CM_ENUMERATE_CLASSES_INSTALLER: ULONG = 0x00000000; +pub const CM_ENUMERATE_CLASSES_INTERFACE: ULONG = 0x00000001; +pub const CM_ENUMERATE_CLASSES_BITS: ULONG = 0x00000001; +pub const CM_DETECT_NEW_PROFILE: ULONG = 0x00000001; +pub const CM_DETECT_CRASHED: ULONG = 0x00000002; +pub const CM_DETECT_HWPROF_FIRST_BOOT: ULONG = 0x00000004; +pub const CM_DETECT_RUN: ULONG = 0x80000000; +pub const CM_DETECT_BITS: ULONG = 0x80000007; +pub const CM_DISABLE_POLITE: ULONG = 0x00000000; +pub const CM_DISABLE_ABSOLUTE: ULONG = 0x00000001; +pub const CM_DISABLE_HARDWARE: ULONG = 0x00000002; +pub const CM_DISABLE_UI_NOT_OK: ULONG = 0x00000004; +pub const CM_DISABLE_BITS: ULONG = 0x00000007; +pub const CM_GETIDLIST_FILTER_NONE: ULONG = 0x00000000; +pub const CM_GETIDLIST_FILTER_ENUMERATOR: ULONG = 0x00000001; +pub const CM_GETIDLIST_FILTER_SERVICE: ULONG = 0x00000002; +pub const CM_GETIDLIST_FILTER_EJECTRELATIONS: ULONG = 0x00000004; +pub const CM_GETIDLIST_FILTER_REMOVALRELATIONS: ULONG = 0x00000008; +pub const CM_GETIDLIST_FILTER_POWERRELATIONS: ULONG = 0x00000010; +pub const CM_GETIDLIST_FILTER_BUSRELATIONS: ULONG = 0x00000020; +pub const CM_GETIDLIST_DONOTGENERATE: ULONG = 0x10000040; +pub const CM_GETIDLIST_FILTER_TRANSPORTRELATIONS: ULONG = 0x00000080; +pub const CM_GETIDLIST_FILTER_PRESENT: ULONG = 0x00000100; +pub const CM_GETIDLIST_FILTER_CLASS: ULONG = 0x00000200; +pub const CM_GETIDLIST_FILTER_BITS: ULONG = 0x100003FF; +pub const CM_GET_DEVICE_INTERFACE_LIST_PRESENT: ULONG = 0x00000000; +pub const CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES: ULONG = 0x00000001; +pub const CM_GET_DEVICE_INTERFACE_LIST_BITS: ULONG = 0x00000001; +pub const CM_DRP_DEVICEDESC: ULONG = 0x00000001; +pub const CM_DRP_HARDWAREID: ULONG = 0x00000002; +pub const CM_DRP_COMPATIBLEIDS: ULONG = 0x00000003; +pub const CM_DRP_UNUSED0: ULONG = 0x00000004; +pub const CM_DRP_SERVICE: ULONG = 0x00000005; +pub const CM_DRP_UNUSED1: ULONG = 0x00000006; +pub const CM_DRP_UNUSED2: ULONG = 0x00000007; +pub const CM_DRP_CLASS: ULONG = 0x00000008; +pub const CM_DRP_CLASSGUID: ULONG = 0x00000009; +pub const CM_DRP_DRIVER: ULONG = 0x0000000A; +pub const CM_DRP_CONFIGFLAGS: ULONG = 0x0000000B; +pub const CM_DRP_MFG: ULONG = 0x0000000C; +pub const CM_DRP_FRIENDLYNAME: ULONG = 0x0000000D; +pub const CM_DRP_LOCATION_INFORMATION: ULONG = 0x0000000E; +pub const CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME: ULONG = 0x0000000F; +pub const CM_DRP_CAPABILITIES: ULONG = 0x00000010; +pub const CM_DRP_UI_NUMBER: ULONG = 0x00000011; +pub const CM_DRP_UPPERFILTERS: ULONG = 0x00000012; +pub const CM_CRP_UPPERFILTERS: ULONG = CM_DRP_UPPERFILTERS; +pub const CM_DRP_LOWERFILTERS: ULONG = 0x00000013; +pub const CM_CRP_LOWERFILTERS: ULONG = CM_DRP_LOWERFILTERS; +pub const CM_DRP_BUSTYPEGUID: ULONG = 0x00000014; +pub const CM_DRP_LEGACYBUSTYPE: ULONG = 0x00000015; +pub const CM_DRP_BUSNUMBER: ULONG = 0x00000016; +pub const CM_DRP_ENUMERATOR_NAME: ULONG = 0x00000017; +pub const CM_DRP_SECURITY: ULONG = 0x00000018; +pub const CM_CRP_SECURITY: ULONG = CM_DRP_SECURITY; +pub const CM_DRP_SECURITY_SDS: ULONG = 0x00000019; +pub const CM_CRP_SECURITY_SDS: ULONG = CM_DRP_SECURITY_SDS; +pub const CM_DRP_DEVTYPE: ULONG = 0x0000001A; +pub const CM_CRP_DEVTYPE: ULONG = CM_DRP_DEVTYPE; +pub const CM_DRP_EXCLUSIVE: ULONG = 0x0000001B; +pub const CM_CRP_EXCLUSIVE: ULONG = CM_DRP_EXCLUSIVE; +pub const CM_DRP_CHARACTERISTICS: ULONG = 0x0000001C; +pub const CM_CRP_CHARACTERISTICS: ULONG = CM_DRP_CHARACTERISTICS; +pub const CM_DRP_ADDRESS: ULONG = 0x0000001D; +pub const CM_DRP_UI_NUMBER_DESC_FORMAT: ULONG = 0x0000001E; +pub const CM_DRP_DEVICE_POWER_DATA: ULONG = 0x0000001F; +pub const CM_DRP_REMOVAL_POLICY: ULONG = 0x00000020; +pub const CM_DRP_REMOVAL_POLICY_HW_DEFAULT: ULONG = 0x00000021; +pub const CM_DRP_REMOVAL_POLICY_OVERRIDE: ULONG = 0x00000022; +pub const CM_DRP_INSTALL_STATE: ULONG = 0x00000023; +pub const CM_DRP_LOCATION_PATHS: ULONG = 0x00000024; +pub const CM_DRP_BASE_CONTAINERID: ULONG = 0x00000025; +pub const CM_DRP_MIN: ULONG = 0x00000001; +pub const CM_CRP_MIN: ULONG = CM_DRP_MIN; +pub const CM_DRP_MAX: ULONG = 0x00000025; +pub const CM_CRP_MAX: ULONG = CM_DRP_MAX; +pub const CM_DEVCAP_LOCKSUPPORTED: ULONG = 0x00000001; +pub const CM_DEVCAP_EJECTSUPPORTED: ULONG = 0x00000002; +pub const CM_DEVCAP_REMOVABLE: ULONG = 0x00000004; +pub const CM_DEVCAP_DOCKDEVICE: ULONG = 0x00000008; +pub const CM_DEVCAP_UNIQUEID: ULONG = 0x00000010; +pub const CM_DEVCAP_SILENTINSTALL: ULONG = 0x00000020; +pub const CM_DEVCAP_RAWDEVICEOK: ULONG = 0x00000040; +pub const CM_DEVCAP_SURPRISEREMOVALOK: ULONG = 0x00000080; +pub const CM_DEVCAP_HARDWAREDISABLED: ULONG = 0x00000100; +pub const CM_DEVCAP_NONDYNAMIC: ULONG = 0x00000200; +pub const CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL: ULONG = 1; +pub const CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL: ULONG = 2; +pub const CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL: ULONG = 3; +pub const CM_INSTALL_STATE_INSTALLED: ULONG = 0; +pub const CM_INSTALL_STATE_NEEDS_REINSTALL: ULONG = 1; +pub const CM_INSTALL_STATE_FAILED_INSTALL: ULONG = 2; +pub const CM_INSTALL_STATE_FINISH_INSTALL: ULONG = 3; +pub const CM_LOCATE_DEVNODE_NORMAL: ULONG = 0x00000000; +pub const CM_LOCATE_DEVNODE_PHANTOM: ULONG = 0x00000001; +pub const CM_LOCATE_DEVNODE_CANCELREMOVE: ULONG = 0x00000002; +pub const CM_LOCATE_DEVNODE_NOVALIDATION: ULONG = 0x00000004; +pub const CM_LOCATE_DEVNODE_BITS: ULONG = 0x00000007; +pub const CM_LOCATE_DEVINST_NORMAL: ULONG = CM_LOCATE_DEVNODE_NORMAL; +pub const CM_LOCATE_DEVINST_PHANTOM: ULONG = CM_LOCATE_DEVNODE_PHANTOM; +pub const CM_LOCATE_DEVINST_CANCELREMOVE: ULONG = CM_LOCATE_DEVNODE_CANCELREMOVE; +pub const CM_LOCATE_DEVINST_NOVALIDATION: ULONG = CM_LOCATE_DEVNODE_NOVALIDATION; +pub const CM_LOCATE_DEVINST_BITS: ULONG = CM_LOCATE_DEVNODE_BITS; +pub const CM_OPEN_CLASS_KEY_INSTALLER: ULONG = 0x00000000; +pub const CM_OPEN_CLASS_KEY_INTERFACE: ULONG = 0x00000001; +pub const CM_OPEN_CLASS_KEY_BITS: ULONG = 0x00000001; +pub const CM_REMOVE_UI_OK: ULONG = 0x00000000; +pub const CM_REMOVE_UI_NOT_OK: ULONG = 0x00000001; +pub const CM_REMOVE_NO_RESTART: ULONG = 0x00000002; +pub const CM_REMOVE_BITS: ULONG = 0x00000003; +pub const CM_QUERY_REMOVE_UI_OK: ULONG = CM_REMOVE_UI_OK; +pub const CM_QUERY_REMOVE_UI_NOT_OK: ULONG = CM_REMOVE_UI_NOT_OK; +pub const CM_QUERY_REMOVE_BITS: ULONG = CM_QUERY_REMOVE_UI_OK | CM_QUERY_REMOVE_UI_NOT_OK; +pub const CM_REENUMERATE_NORMAL: ULONG = 0x00000000; +pub const CM_REENUMERATE_SYNCHRONOUS: ULONG = 0x00000001; +pub const CM_REENUMERATE_RETRY_INSTALLATION: ULONG = 0x00000002; +pub const CM_REENUMERATE_ASYNCHRONOUS: ULONG = 0x00000004; +pub const CM_REENUMERATE_BITS: ULONG = 0x00000007; +pub const CM_REGISTER_DEVICE_DRIVER_STATIC: ULONG = 0x00000000; +pub const CM_REGISTER_DEVICE_DRIVER_DISABLEABLE: ULONG = 0x00000001; +pub const CM_REGISTER_DEVICE_DRIVER_REMOVABLE: ULONG = 0x00000002; +pub const CM_REGISTER_DEVICE_DRIVER_BITS: ULONG = 0x00000003; +pub const CM_REGISTRY_HARDWARE: ULONG = 0x00000000; +pub const CM_REGISTRY_SOFTWARE: ULONG = 0x00000001; +pub const CM_REGISTRY_USER: ULONG = 0x00000100; +pub const CM_REGISTRY_CONFIG: ULONG = 0x00000200; +pub const CM_REGISTRY_BITS: ULONG = 0x00000301; +pub const CM_SET_DEVNODE_PROBLEM_NORMAL: ULONG = 0x00000000; +pub const CM_SET_DEVNODE_PROBLEM_OVERRIDE: ULONG = 0x00000001; +pub const CM_SET_DEVNODE_PROBLEM_BITS: ULONG = 0x00000001; +pub const CM_SET_DEVINST_PROBLEM_NORMAL: ULONG = CM_SET_DEVNODE_PROBLEM_NORMAL; +pub const CM_SET_DEVINST_PROBLEM_OVERRIDE: ULONG = CM_SET_DEVNODE_PROBLEM_OVERRIDE; +pub const CM_SET_DEVINST_PROBLEM_BITS: ULONG = CM_SET_DEVNODE_PROBLEM_BITS; +pub const CM_SET_HW_PROF_FLAGS_UI_NOT_OK: ULONG = 0x00000001; +pub const CM_SET_HW_PROF_FLAGS_BITS: ULONG = 0x00000001; +pub const CM_SETUP_DEVNODE_READY: ULONG = 0x00000000; +pub const CM_SETUP_DEVINST_READY: ULONG = CM_SETUP_DEVNODE_READY; +pub const CM_SETUP_DOWNLOAD: ULONG = 0x00000001; +pub const CM_SETUP_WRITE_LOG_CONFS: ULONG = 0x00000002; +pub const CM_SETUP_PROP_CHANGE: ULONG = 0x00000003; +pub const CM_SETUP_DEVNODE_RESET: ULONG = 0x00000004; +pub const CM_SETUP_DEVINST_RESET: ULONG = CM_SETUP_DEVNODE_RESET; +pub const CM_SETUP_DEVNODE_CONFIG: ULONG = 0x00000005; +pub const CM_SETUP_DEVINST_CONFIG: ULONG = CM_SETUP_DEVNODE_CONFIG; +pub const CM_SETUP_DEVNODE_CONFIG_CLASS: ULONG = 0x00000006; +pub const CM_SETUP_DEVINST_CONFIG_CLASS: ULONG = CM_SETUP_DEVNODE_CONFIG_CLASS; +pub const CM_SETUP_DEVNODE_CONFIG_EXTENSIONS: ULONG = 0x00000007; +pub const CM_SETUP_DEVINST_CONFIG_EXTENSIONS: ULONG = CM_SETUP_DEVNODE_CONFIG_EXTENSIONS; +pub const CM_SETUP_BITS: ULONG = 0x00000007; +pub const CM_QUERY_ARBITRATOR_RAW: ULONG = 0x00000000; +pub const CM_QUERY_ARBITRATOR_TRANSLATED: ULONG = 0x00000001; +pub const CM_QUERY_ARBITRATOR_BITS: ULONG = 0x00000001; +pub const CM_CUSTOMDEVPROP_MERGE_MULTISZ: ULONG = 0x00000001; +pub const CM_CUSTOMDEVPROP_BITS: ULONG = 0x00000001; +pub const CM_NAME_ATTRIBUTE_NAME_RETRIEVED_FROM_DEVICE: ULONG = 0x1; +pub const CM_NAME_ATTRIBUTE_USER_ASSIGNED_NAME: ULONG = 0x2; +pub const CM_CLASS_PROPERTY_INSTALLER: ULONG = 0x00000000; +pub const CM_CLASS_PROPERTY_INTERFACE: ULONG = 0x00000001; +pub const CM_CLASS_PROPERTY_BITS: ULONG = 0x00000001; +DECLARE_HANDLE!{HCMNOTIFICATION, HCMNOTIFICATION__} +pub type PHCMNOTIFICATION = *mut HCMNOTIFICATION; +pub const CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES: ULONG = 0x00000001; +pub const CM_NOTIFY_FILTER_FLAG_ALL_DEVICE_INSTANCES: ULONG = 0x00000002; +pub const CM_NOTIFY_FILTER_VALID_FLAGS: ULONG = CM_NOTIFY_FILTER_FLAG_ALL_INTERFACE_CLASSES + | CM_NOTIFY_FILTER_FLAG_ALL_DEVICE_INSTANCES; +ENUM!{enum CM_NOTIFY_FILTER_TYPE { + CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0, + CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE, + CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE, + CM_NOTIFY_FILTER_TYPE_MAX, +}} +pub type PCM_NOTIFY_FILTER_TYPE = *mut CM_NOTIFY_FILTER_TYPE; +STRUCT!{struct CM_NOTIFY_FILTER_DeviceInterface { + ClassGuid: GUID, +}} +STRUCT!{struct CM_NOTIFY_FILTER_DeviceHandle { + hTarget: HANDLE, +}} +STRUCT!{struct CM_NOTIFY_FILTER_DeviceInstance { + InstanceId: [WCHAR; MAX_DEVICE_ID_LEN], +}} +UNION!{union CM_NOTIFY_FILTER_u { + [u32; 100] [u64; 50], + DeviceInterface DeviceInterface_mut: CM_NOTIFY_FILTER_DeviceInterface, + DeviceHandle DeviceHandle_mut: CM_NOTIFY_FILTER_DeviceHandle, + DeviceInstance DeviceInstance_mut: CM_NOTIFY_FILTER_DeviceInstance, +}} +STRUCT!{struct CM_NOTIFY_FILTER { + cbSize: DWORD, + Flags: DWORD, + FilterType: CM_NOTIFY_FILTER_TYPE, + Reserved: DWORD, + u: CM_NOTIFY_FILTER_u, +}} +pub type PCM_NOTIFY_FILTER = *mut CM_NOTIFY_FILTER; +ENUM!{enum CM_NOTIFY_ACTION { + CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0, + CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL, + CM_NOTIFY_ACTION_DEVICEQUERYREMOVE, + CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED, + CM_NOTIFY_ACTION_DEVICEREMOVEPENDING, + CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE, + CM_NOTIFY_ACTION_DEVICECUSTOMEVENT, + CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED, + CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED, + CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED, + CM_NOTIFY_ACTION_MAX, +}} +pub type PCM_NOTIFY_ACTION = *mut CM_NOTIFY_ACTION; +STRUCT!{struct CM_NOTIFY_EVENT_DATA_DeviceInterface { + ClassGuid: GUID, + SymbolicLink: [WCHAR; ANYSIZE_ARRAY], +}} +STRUCT!{struct CM_NOTIFY_EVENT_DATA_DeviceHandle { + EventGuid: GUID, + NameOffset: LONG, + DataSize: DWORD, + Data: [BYTE; ANYSIZE_ARRAY], +}} +STRUCT!{struct CM_NOTIFY_EVENT_DATA_DeviceInstance { + InstanceId: [WCHAR; ANYSIZE_ARRAY], +}} +UNION!{union CM_NOTIFY_EVENT_DATA_u { + [u32; 7], + DeviceInterface DeviceInterface_mut: CM_NOTIFY_EVENT_DATA_DeviceInterface, + DeviceHandle DeviceHandle_mut: CM_NOTIFY_EVENT_DATA_DeviceHandle, + DeviceInstance DeviceInstance_mut: CM_NOTIFY_EVENT_DATA_DeviceInstance, +}} +STRUCT!{struct CM_NOTIFY_EVENT_DATA { + FilterType: CM_NOTIFY_FILTER_TYPE, + Reserved: DWORD, + u: CM_NOTIFY_EVENT_DATA_u, +}} +pub type PCM_NOTIFY_EVENT_DATA = *mut CM_NOTIFY_EVENT_DATA; +FN!{stdcall PCM_NOTIFY_CALLBACK( + hNotify: HCMNOTIFICATION, + Context: PVOID, + Action: CM_NOTIFY_ACTION, + EventData: PCM_NOTIFY_EVENT_DATA, + EventDataSize: DWORD, +) -> DWORD} +extern "system" { + pub fn CM_Add_Empty_Log_Conf( + plcLogConf: PLOG_CONF, + dnDevInst: DEVINST, + Priority: PRIORITY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Add_Empty_Log_Conf_Ex( + plcLogConf: PLOG_CONF, + dnDevInst: DEVINST, + Priority: PRIORITY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Add_IDA( + dnDevInst: DEVINST, + pszID: PSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Add_IDW( + dnDevInst: DEVINST, + pszID: PWSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Add_ID_ExA( + dnDevInst: DEVINST, + pszID: PSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Add_ID_ExW( + dnDevInst: DEVINST, + pszID: PWSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Add_Range( + ullStartValue: DWORDLONG, + ullEndValue: DWORDLONG, + rlh: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Add_Res_Des( + prdResDes: PRES_DES, + lcLogConf: LOG_CONF, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Add_Res_Des_Ex( + prdResDes: PRES_DES, + lcLogConf: LOG_CONF, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Connect_MachineA( + UNCServerName: PCSTR, + phMachine: PHMACHINE, + ) -> CONFIGRET; + pub fn CM_Connect_MachineW( + UNCServerName: PCWSTR, + phMachine: PHMACHINE, + ) -> CONFIGRET; + pub fn CM_Create_DevNodeA( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_A, + dnParent: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Create_DevNodeW( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_W, + dnParent: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Create_DevNode_ExA( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_A, + dnParent: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Create_DevNode_ExW( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_W, + dnParent: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Create_Range_List( + prlh: PRANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Delete_Class_Key( + ClassGuid: LPGUID, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Delete_Class_Key_Ex( + ClassGuid: LPGUID, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Delete_DevNode_Key( + dnDevNode: DEVNODE, + ulHardwareProfile: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Delete_DevNode_Key_Ex( + dnDevNode: DEVNODE, + ulHardwareProfile: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Delete_Range( + ullStartValue: DWORDLONG, + ullEndValue: DWORDLONG, + rlh: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Detect_Resource_Conflict( + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + pbConflictDetected: PBOOL, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Detect_Resource_Conflict_Ex( + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + pbConflictDetected: PBOOL, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Disable_DevNode( + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Disable_DevNode_Ex( + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Disconnect_Machine( + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Dup_Range_List( + rlhOld: RANGE_LIST, + rlhNew: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Enable_DevNode( + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Enable_DevNode_Ex( + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Enumerate_Classes( + ulClassIndex: ULONG, + ClassGuid: LPGUID, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Enumerate_Classes_Ex( + ulClassIndex: ULONG, + ClassGuid: LPGUID, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Enumerate_EnumeratorsA( + ulEnumIndex: ULONG, + Buffer: PSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Enumerate_EnumeratorsW( + ulEnumIndex: ULONG, + Buffer: PWSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Enumerate_Enumerators_ExA( + ulEnumIndex: ULONG, + Buffer: PSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Enumerate_Enumerators_ExW( + ulEnumIndex: ULONG, + Buffer: PWSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Find_Range( + pullStart: PDWORDLONG, + ullStart: DWORDLONG, + ulLength: ULONG, + ullAlignment: DWORDLONG, + ullEnd: DWORDLONG, + rlh: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_First_Range( + rlh: RANGE_LIST, + pullStart: PDWORDLONG, + pullEnd: PDWORDLONG, + preElement: PRANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Free_Log_Conf( + lcLogConfToBeFreed: LOG_CONF, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Free_Log_Conf_Ex( + lcLogConfToBeFreed: LOG_CONF, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Free_Log_Conf_Handle( + lcLogConf: LOG_CONF, + ) -> CONFIGRET; + pub fn CM_Free_Range_List( + rlh: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Free_Res_Des( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Free_Res_Des_Ex( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Free_Res_Des_Handle( + rdResDes: RES_DES, + ) -> CONFIGRET; + pub fn CM_Get_Child( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Child_Ex( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Class_Key_NameA( + ClassGuid: LPGUID, + pszKeyName: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Class_Key_NameW( + ClassGuid: LPGUID, + pszKeyName: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Class_Key_Name_ExA( + ClassGuid: LPGUID, + pszKeyName: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Class_Key_Name_ExW( + ClassGuid: LPGUID, + pszKeyName: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Class_NameA( + ClassGuid: LPGUID, + Buffer: PSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Class_NameW( + ClassGuid: LPGUID, + Buffer: PWSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Class_Name_ExA( + ClassGuid: LPGUID, + Buffer: PSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Class_Name_ExW( + ClassGuid: LPGUID, + Buffer: PWSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Depth( + pulDepth: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Depth_Ex( + pulDepth: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_IDA( + dnDevInst: DEVINST, + Buffer: PSTR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_IDW( + dnDevInst: DEVINST, + Buffer: PWSTR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_ExA( + dnDevInst: DEVINST, + Buffer: PSTR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_ExW( + dnDevInst: DEVINST, + Buffer: PWSTR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_ListA( + pszFilter: PCSTR, + Buffer: PCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_ListW( + pszFilter: PCWSTR, + Buffer: PWCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_ExA( + pszFilter: PCSTR, + Buffer: PCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_ExW( + pszFilter: PCWSTR, + Buffer: PWCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_SizeA( + pulLen: PULONG, + pszFilter: PCSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_SizeW( + pulLen: PULONG, + pszFilter: PCWSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_Size_ExA( + pulLen: PULONG, + pszFilter: PCSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_List_Size_ExW( + pulLen: PULONG, + pszFilter: PCWSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_Size( + pulLen: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_ID_Size_Ex( + pulLen: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_PropertyW( + dnDevInst: DEVINST, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_PropertyExW( + dnDevInst: DEVINST, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Registry_PropertyA( + dnDevInst: DEVINST, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Registry_PropertyW( + dnDevInst: DEVINST, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Registry_Property_ExA( + dnDevInst: DEVINST, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Registry_Property_ExW( + dnDevInst: DEVINST, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Custom_PropertyA( + dnDevInst: DEVINST, + pszCustomPropertyName: PCSTR, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Custom_PropertyW( + dnDevInst: DEVINST, + pszCustomPropertyName: PCWSTR, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Custom_Property_ExA( + dnDevInst: DEVINST, + pszCustomPropertyName: PCSTR, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Custom_Property_ExW( + dnDevInst: DEVINST, + pszCustomPropertyName: PCWSTR, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Status( + pulStatus: PULONG, + pulProblemNumber: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_DevNode_Status_Ex( + pulStatus: PULONG, + pulProblemNumber: PULONG, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_First_Log_Conf( + plcLogConf: PLOG_CONF, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_First_Log_Conf_Ex( + plcLogConf: PLOG_CONF, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Global_State( + pulState: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Global_State_Ex( + pulState: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Hardware_Profile_InfoA( + ulIndex: ULONG, + pHWProfileInfo: PHWPROFILEINFO_A, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Hardware_Profile_Info_ExA( + ulIndex: ULONG, + pHWProfileInfo: PHWPROFILEINFO_A, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Hardware_Profile_InfoW( + ulIndex: ULONG, + pHWProfileInfo: PHWPROFILEINFO_W, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Hardware_Profile_Info_ExW( + ulIndex: ULONG, + pHWProfileInfo: PHWPROFILEINFO_W, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_HW_Prof_FlagsA( + pDeviceID: DEVINSTID_A, + ulHardwareProfile: ULONG, + pulValue: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_HW_Prof_FlagsW( + pDeviceID: DEVINSTID_W, + ulHardwareProfile: ULONG, + pulValue: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_HW_Prof_Flags_ExA( + pDeviceID: DEVINSTID_A, + ulHardwareProfile: ULONG, + pulValue: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_HW_Prof_Flags_ExW( + pDeviceID: DEVINSTID_W, + ulHardwareProfile: ULONG, + pulValue: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_AliasA( + pszDeviceInterface: LPCSTR, + AliasInterfaceGuid: LPGUID, + pszAliasDeviceInterface: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_AliasW( + pszDeviceInterface: LPCWSTR, + AliasInterfaceGuid: LPGUID, + pszAliasDeviceInterface: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_Alias_ExA( + pszDeviceInterface: LPCSTR, + AliasInterfaceGuid: LPGUID, + pszAliasDeviceInterface: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_Alias_ExW( + pszDeviceInterface: LPCWSTR, + AliasInterfaceGuid: LPGUID, + pszAliasDeviceInterface: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_ListA( + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_A, + Buffer: PCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_ListW( + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_W, + Buffer: PWCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_ExA( + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_A, + Buffer: PCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_ExW( + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_W, + Buffer: PWCHAR, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_SizeA( + pulLen: PULONG, + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_A, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_SizeW( + pulLen: PULONG, + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_W, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_Size_ExA( + pulLen: PULONG, + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_A, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_List_Size_ExW( + pulLen: PULONG, + InterfaceClassGuid: LPGUID, + pDeviceID: DEVINSTID_W, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_PropertyW( + pszDeviceInterface: LPCWSTR, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Device_Interface_PropertyExW( + pszDeviceInterface: LPCWSTR, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Log_Conf_Priority( + lcLogConf: LOG_CONF, + pPriority: PRIORITY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Log_Conf_Priority_Ex( + lcLogConf: LOG_CONF, + pPriority: PRIORITY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Next_Log_Conf( + plcLogConf: PLOG_CONF, + lcLogConf: LOG_CONF, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Next_Log_Conf_Ex( + plcLogConf: PLOG_CONF, + lcLogConf: LOG_CONF, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Parent( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Parent_Ex( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Res_Des_Data( + rdResDes: RES_DES, + Buffer: PVOID, + BufferLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Res_Des_Data_Ex( + rdResDes: RES_DES, + Buffer: PVOID, + BufferLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Res_Des_Data_Size( + pulSize: PULONG, + rdResDes: RES_DES, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Res_Des_Data_Size_Ex( + pulSize: PULONG, + rdResDes: RES_DES, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Sibling( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Sibling_Ex( + pdnDevInst: PDEVINST, + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Version() -> WORD; + pub fn CM_Get_Version_Ex( + hMachine: HMACHINE, + ) -> WORD; + pub fn CM_Is_Version_Available( + wVersion: WORD, + ) -> BOOL; + pub fn CM_Is_Version_Available_Ex( + wVersion: WORD, + hMachine: HMACHINE, + ) -> BOOL; + pub fn CM_Intersect_Range_List( + rlhOld1: RANGE_LIST, + rlhOld2: RANGE_LIST, + rlhNew: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Invert_Range_List( + rlhOld: RANGE_LIST, + rlhNew: RANGE_LIST, + ullMaxValue: DWORDLONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Locate_DevNodeA( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_A, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Locate_DevNodeW( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_W, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Locate_DevNode_ExA( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_A, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Locate_DevNode_ExW( + pdnDevInst: PDEVINST, + pDeviceID: DEVINSTID_W, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Merge_Range_List( + rlhOld1: RANGE_LIST, + rlhOld2: RANGE_LIST, + rlhNew: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Modify_Res_Des( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Modify_Res_Des_Ex( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Move_DevNode( + dnFromDevInst: DEVINST, + dnToDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Move_DevNode_Ex( + dnFromDevInst: DEVINST, + dnToDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Next_Range( + preElement: PRANGE_LIST, + pullStart: PDWORDLONG, + pullEnd: PDWORDLONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Next_Res_Des( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ForResource: RESOURCEID, + pResourceID: PRESOURCEID, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Get_Next_Res_Des_Ex( + prdResDes: PRES_DES, + rdResDes: RES_DES, + ForResource: RESOURCEID, + pResourceID: PRESOURCEID, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Open_Class_KeyA( + ClassGuid: LPGUID, + pszClassName: LPCSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkClass: PHKEY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Open_Class_KeyW( + ClassGuid: LPGUID, + pszClassName: LPCWSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkClass: PHKEY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Open_Class_Key_ExA( + ClassGuid: LPGUID, + pszClassName: LPCSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkClass: PHKEY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Open_Class_Key_ExW( + ClassGuid: LPGUID, + pszClassName: LPCWSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkClass: PHKEY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Open_DevNode_Key( + dnDevNode: DEVINST, + samDesired: REGSAM, + ulHardwareProfile: ULONG, + Disposition: REGDISPOSITION, + phkDevice: PHKEY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Open_DevNode_Key_Ex( + dnDevNode: DEVINST, + samDesired: REGSAM, + ulHardwareProfile: ULONG, + Disposition: REGDISPOSITION, + phkDevice: PHKEY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Open_Device_Interface_KeyA( + pszDeviceInterface: LPCSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkDeviceInterface: PHKEY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Open_Device_Interface_KeyW( + pszDeviceInterface: LPCWSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkDeviceInterface: PHKEY, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Open_Device_Interface_Key_ExA( + pszDeviceInterface: LPCSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkDeviceInterface: PHKEY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Open_Device_Interface_Key_ExW( + pszDeviceInterface: LPCWSTR, + samDesired: REGSAM, + Disposition: REGDISPOSITION, + phkDeviceInterface: PHKEY, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Delete_Device_Interface_KeyA( + pszDeviceInterface: LPCSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Delete_Device_Interface_KeyW( + pszDeviceInterface: LPCWSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Delete_Device_Interface_Key_ExA( + pszDeviceInterface: LPCSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Delete_Device_Interface_Key_ExW( + pszDeviceInterface: LPCWSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_Arbitrator_Free_Data( + pData: PVOID, + DataLen: ULONG, + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Query_Arbitrator_Free_Data_Ex( + pData: PVOID, + DataLen: ULONG, + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_Arbitrator_Free_Size( + pulSize: PULONG, + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Query_Arbitrator_Free_Size_Ex( + pulSize: PULONG, + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_Remove_SubTree( + dnAncestor: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Query_Remove_SubTree_Ex( + dnAncestor: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_And_Remove_SubTreeA( + dnAncestor: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Query_And_Remove_SubTree_ExA( + dnAncestor: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_And_Remove_SubTreeW( + dnAncestor: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPWSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Query_And_Remove_SubTree_ExW( + dnAncestor: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPWSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Request_Device_EjectA( + dnDevInst: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Request_Device_Eject_ExA( + dnDevInst: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Request_Device_EjectW( + dnDevInst: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPWSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Request_Device_Eject_ExW( + dnDevInst: DEVINST, + pVetoType: PPNP_VETO_TYPE, + pszVetoName: LPWSTR, + ulNameLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Reenumerate_DevNode( + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Reenumerate_DevNode_Ex( + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Register_Device_InterfaceA( + dnDevInst: DEVINST, + InterfaceClassGuid: LPGUID, + pszReference: LPCSTR, + pszDeviceInterface: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Register_Device_InterfaceW( + dnDevInst: DEVINST, + InterfaceClassGuid: LPGUID, + pszReference: LPCWSTR, + pszDeviceInterface: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Register_Device_Interface_ExA( + dnDevInst: DEVINST, + InterfaceClassGuid: LPGUID, + pszReference: LPCSTR, + pszDeviceInterface: LPSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Register_Device_Interface_ExW( + dnDevInst: DEVINST, + InterfaceClassGuid: LPGUID, + pszReference: LPCWSTR, + pszDeviceInterface: LPWSTR, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Problem_Ex( + dnDevInst: DEVINST, + ulProblem: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Problem( + dnDevInst: DEVINST, + ulProblem: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Unregister_Device_InterfaceA( + pszDeviceInterface: LPCSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Unregister_Device_InterfaceW( + pszDeviceInterface: LPCWSTR, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Unregister_Device_Interface_ExA( + pszDeviceInterface: LPCSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Unregister_Device_Interface_ExW( + pszDeviceInterface: LPCWSTR, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Register_Device_Driver( + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Register_Device_Driver_Ex( + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Remove_SubTree( + dnAncestor: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Remove_SubTree_Ex( + dnAncestor: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Registry_PropertyA( + dnDevInst: DEVINST, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Registry_PropertyW( + dnDevInst: DEVINST, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Registry_Property_ExA( + dnDevInst: DEVINST, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_DevNode_Registry_Property_ExW( + dnDevInst: DEVINST, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Is_Dock_Station_Present( + pbPresent: PBOOL, + ) -> CONFIGRET; + pub fn CM_Is_Dock_Station_Present_Ex( + pbPresent: PBOOL, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Request_Eject_PC() -> CONFIGRET; + pub fn CM_Request_Eject_PC_Ex( + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof_FlagsA( + pDeviceID: DEVINSTID_A, + ulConfig: ULONG, + ulValue: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof_FlagsW( + pDeviceID: DEVINSTID_W, + ulConfig: ULONG, + ulValue: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof_Flags_ExA( + pDeviceID: DEVINSTID_A, + ulConfig: ULONG, + ulValue: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof_Flags_ExW( + pDeviceID: DEVINSTID_A, + ulConfig: ULONG, + ulValue: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Setup_DevNode( + dnDevInst: DEVINST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Setup_DevNode_Ex( + dnDevInst: DEVINST, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Test_Range_Available( + ullStartValue: DWORDLONG, + ullEndValue: DWORDLONG, + rlh: RANGE_LIST, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Uninstall_DevNode( + dnDevInst: DEVNODE, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Uninstall_DevNode_Ex( + dnDevInst: DEVNODE, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Run_Detection( + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Run_Detection_Ex( + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof( + ulHardwareProfile: ULONG, + ulFlags: ULONG, + ) -> CONFIGRET; + pub fn CM_Set_HW_Prof_Ex( + ulHardwareProfile: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Query_Resource_Conflict_List( + pclConflictList: PCONFLICT_LIST, + dnDevInst: DEVINST, + ResourceID: RESOURCEID, + ResourceData: PCVOID, + ResourceLen: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Free_Resource_Conflict_Handle( + clConflictList: CONFLICT_LIST, + ) -> CONFIGRET; + pub fn CM_Get_Resource_Conflict_Count( + clConflictList: CONFLICT_LIST, + pulCount: PULONG, + ) -> CONFIGRET; + pub fn CM_Get_Resource_Conflict_DetailsA( + clConflictList: CONFLICT_LIST, + ulIndex: ULONG, + pConflictDetails: PCONFLICT_DETAILS_A, + ) -> CONFIGRET; + pub fn CM_Get_Resource_Conflict_DetailsW( + clConflictList: CONFLICT_LIST, + ulIndex: ULONG, + pConflictDetails: PCONFLICT_DETAILS_W, + ) -> CONFIGRET; + pub fn CM_Get_Class_Registry_PropertyW( + ClassGuid: LPGUID, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_Class_Registry_PropertyW( + ClassGuid: LPGUID, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Get_Class_Registry_PropertyA( + ClassGuid: LPGUID, + ulProperty: ULONG, + pulRegDataType: PULONG, + Buffer: PVOID, + pulLength: PULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CM_Set_Class_Registry_PropertyA( + ClassGuid: LPGUID, + ulProperty: ULONG, + Buffer: PCVOID, + ulLength: ULONG, + ulFlags: ULONG, + hMachine: HMACHINE, + ) -> CONFIGRET; + pub fn CMP_WaitNoPendingInstallEvents( + dwTimeout: DWORD, + ) -> DWORD; +} +pub const CR_SUCCESS: CONFIGRET = 0x00000000; +pub const CR_DEFAULT: CONFIGRET = 0x00000001; +pub const CR_OUT_OF_MEMORY: CONFIGRET = 0x00000002; +pub const CR_INVALID_POINTER: CONFIGRET = 0x00000003; +pub const CR_INVALID_FLAG: CONFIGRET = 0x00000004; +pub const CR_INVALID_DEVNODE: CONFIGRET = 0x00000005; +pub const CR_INVALID_DEVINST: CONFIGRET = CR_INVALID_DEVNODE; +pub const CR_INVALID_RES_DES: CONFIGRET = 0x00000006; +pub const CR_INVALID_LOG_CONF: CONFIGRET = 0x00000007; +pub const CR_INVALID_ARBITRATOR: CONFIGRET = 0x00000008; +pub const CR_INVALID_NODELIST: CONFIGRET = 0x00000009; +pub const CR_DEVNODE_HAS_REQS: CONFIGRET = 0x0000000A; +pub const CR_DEVINST_HAS_REQS: CONFIGRET = CR_DEVNODE_HAS_REQS; +pub const CR_INVALID_RESOURCEID: CONFIGRET = 0x0000000B; +pub const CR_DLVXD_NOT_FOUND: CONFIGRET = 0x0000000C; +pub const CR_NO_SUCH_DEVNODE: CONFIGRET = 0x0000000D; +pub const CR_NO_SUCH_DEVINST: CONFIGRET = CR_NO_SUCH_DEVNODE; +pub const CR_NO_MORE_LOG_CONF: CONFIGRET = 0x0000000E; +pub const CR_NO_MORE_RES_DES: CONFIGRET = 0x0000000F; +pub const CR_ALREADY_SUCH_DEVNODE: CONFIGRET = 0x00000010; +pub const CR_ALREADY_SUCH_DEVINST: CONFIGRET = CR_ALREADY_SUCH_DEVNODE; +pub const CR_INVALID_RANGE_LIST: CONFIGRET = 0x00000011; +pub const CR_INVALID_RANGE: CONFIGRET = 0x00000012; +pub const CR_FAILURE: CONFIGRET = 0x00000013; +pub const CR_NO_SUCH_LOGICAL_DEV: CONFIGRET = 0x00000014; +pub const CR_CREATE_BLOCKED: CONFIGRET = 0x00000015; +pub const CR_NOT_SYSTEM_VM: CONFIGRET = 0x00000016; +pub const CR_REMOVE_VETOED: CONFIGRET = 0x00000017; +pub const CR_APM_VETOED: CONFIGRET = 0x00000018; +pub const CR_INVALID_LOAD_TYPE: CONFIGRET = 0x00000019; +pub const CR_BUFFER_SMALL: CONFIGRET = 0x0000001A; +pub const CR_NO_ARBITRATOR: CONFIGRET = 0x0000001B; +pub const CR_NO_REGISTRY_HANDLE: CONFIGRET = 0x0000001C; +pub const CR_REGISTRY_ERROR: CONFIGRET = 0x0000001D; +pub const CR_INVALID_DEVICE_ID: CONFIGRET = 0x0000001E; +pub const CR_INVALID_DATA: CONFIGRET = 0x0000001F; +pub const CR_INVALID_API: CONFIGRET = 0x00000020; +pub const CR_DEVLOADER_NOT_READY: CONFIGRET = 0x00000021; +pub const CR_NEED_RESTART: CONFIGRET = 0x00000022; +pub const CR_NO_MORE_HW_PROFILES: CONFIGRET = 0x00000023; +pub const CR_DEVICE_NOT_THERE: CONFIGRET = 0x00000024; +pub const CR_NO_SUCH_VALUE: CONFIGRET = 0x00000025; +pub const CR_WRONG_TYPE: CONFIGRET = 0x00000026; +pub const CR_INVALID_PRIORITY: CONFIGRET = 0x00000027; +pub const CR_NOT_DISABLEABLE: CONFIGRET = 0x00000028; +pub const CR_FREE_RESOURCES: CONFIGRET = 0x00000029; +pub const CR_QUERY_VETOED: CONFIGRET = 0x0000002A; +pub const CR_CANT_SHARE_IRQ: CONFIGRET = 0x0000002B; +pub const CR_NO_DEPENDENT: CONFIGRET = 0x0000002C; +pub const CR_SAME_RESOURCES: CONFIGRET = 0x0000002D; +pub const CR_NO_SUCH_REGISTRY_KEY: CONFIGRET = 0x0000002E; +pub const CR_INVALID_MACHINENAME: CONFIGRET = 0x0000002F; +pub const CR_REMOTE_COMM_FAILURE: CONFIGRET = 0x00000030; +pub const CR_MACHINE_UNAVAILABLE: CONFIGRET = 0x00000031; +pub const CR_NO_CM_SERVICES: CONFIGRET = 0x00000032; +pub const CR_ACCESS_DENIED: CONFIGRET = 0x00000033; +pub const CR_CALL_NOT_IMPLEMENTED: CONFIGRET = 0x00000034; +pub const CR_INVALID_PROPERTY: CONFIGRET = 0x00000035; +pub const CR_DEVICE_INTERFACE_ACTIVE: CONFIGRET = 0x00000036; +pub const CR_NO_SUCH_DEVICE_INTERFACE: CONFIGRET = 0x00000037; +pub const CR_INVALID_REFERENCE_STRING: CONFIGRET = 0x00000038; +pub const CR_INVALID_CONFLICT_LIST: CONFIGRET = 0x00000039; +pub const CR_INVALID_INDEX: CONFIGRET = 0x0000003A; +pub const CR_INVALID_STRUCTURE_SIZE: CONFIGRET = 0x0000003B; +pub const NUM_CR_RESULTS: CONFIGRET = 0x0000003C; diff --git a/winapi/src/um/cguid.rs b/winapi/src/um/cguid.rs new file mode 100644 index 000000000..be7f92958 --- /dev/null +++ b/winapi/src/um/cguid.rs @@ -0,0 +1,134 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +// Some of these definitions are commented out because I could not find their value +DEFINE_GUID!{GUID_NULL, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +DEFINE_GUID!{CATID_MARSHALER, + 0x00000003, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IRpcChannel, + 0x00000004, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IRpcStub, + 0x00000005, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IStubManager, + 0x00000006, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IRpcProxy, + 0x00000007, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IProxyManager, + 0x00000008, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IPSFactory, + 0x00000009, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IInternalMoniker, + 0x00000011, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IDfReserved1, + 0x00000013, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IDfReserved2, + 0x00000014, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IDfReserved3, + 0x00000015, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_StdMarshal, + 0x00000017, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +// extern const CLSID CLSID_AggStdMarshal; +DEFINE_GUID!{CLSID_StdAsyncActManager, + 0x00000329, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IStub, + 0x00000026, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IProxy, + 0x00000027, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IEnumGeneric, + 0x00000106, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IEnumHolder, + 0x00000107, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IEnumCallback, + 0x00000108, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IOleManager, + 0x0000011f, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IOlePresObj, + 0x00000120, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IDebug, + 0x00000123, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{IID_IDebugStream, + 0x00000124, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSGenObject, + 0x0000030c, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSClientSite, + 0x0000030d, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSClassObject, + 0x0000030e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSInPlaceActive, + 0x0000030f, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSInPlaceFrame, + 0x00000310, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSDragDrop, + 0x00000311, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSBindCtx, + 0x00000312, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_PSEnumerators, + 0x00000313, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_StaticMetafile, + 0x00000315, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_StaticDib, + 0x00000316, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +// extern const CLSID CID_CDfsVolume; +DEFINE_GUID!{CLSID_DCOMAccessControl, + 0x0000031d, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_GlobalOptions, + 0x0000034b, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_StdGlobalInterfaceTable, + 0x00000323, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_ComBinding, + 0x00000328, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_StdEvent, + 0x0000032b, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_ManualResetEvent, + 0x0000032c, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_SynchronizeContainer, + 0x0000032d, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_AddrControl, + 0x00000348, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_ContextSwitcher, + 0x0000034e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +// extern const CLSID CLSID_CCDFormKrnl; +// extern const CLSID CLSID_CCDPropertyPage; +// extern const CLSID CLSID_CCDFormDialog; +// extern const CLSID CLSID_CCDCommandButton; +// extern const CLSID CLSID_CCDComboBox; +// extern const CLSID CLSID_CCDTextBox; +// extern const CLSID CLSID_CCDCheckBox; +// extern const CLSID CLSID_CCDLabel; +// extern const CLSID CLSID_CCDOptionButton; +// extern const CLSID CLSID_CCDListBox; +// extern const CLSID CLSID_CCDScrollBar; +// extern const CLSID CLSID_CCDGroupBox; +// extern const CLSID CLSID_CCDGeneralPropertyPage; +// extern const CLSID CLSID_CCDGenericPropertyPage; +// extern const CLSID CLSID_CCDFontPropertyPage; +// extern const CLSID CLSID_CCDColorPropertyPage; +// extern const CLSID CLSID_CCDLabelPropertyPage; +// extern const CLSID CLSID_CCDCheckBoxPropertyPage; +// extern const CLSID CLSID_CCDTextBoxPropertyPage; +// extern const CLSID CLSID_CCDOptionButtonPropertyPage; +// extern const CLSID CLSID_CCDListBoxPropertyPage; +// extern const CLSID CLSID_CCDCommandButtonPropertyPage; +// extern const CLSID CLSID_CCDComboBoxPropertyPage; +// extern const CLSID CLSID_CCDScrollBarPropertyPage; +// extern const CLSID CLSID_CCDGroupBoxPropertyPage; +// extern const CLSID CLSID_CCDXObjectPropertyPage; +// extern const CLSID CLSID_CStdPropertyFrame; +// extern const CLSID CLSID_CFormPropertyPage; +// extern const CLSID CLSID_CGridPropertyPage; +// extern const CLSID CLSID_CWSJArticlePage; +// extern const CLSID CLSID_CSystemPage; +// extern const CLSID CLSID_IdentityUnmarshal; +DEFINE_GUID!{CLSID_InProcFreeMarshaler, + 0x0000033a, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_Picture_Metafile, + 0x00000315, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_Picture_EnhMetafile, + 0x00000319, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{CLSID_Picture_Dib, + 0x00000316, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} +DEFINE_GUID!{GUID_TRISTATE, + 0x6650430a, 0xbe0f, 0x101a, 0x8b, 0xbb, 0x00, 0xaa, 0x00, 0x30, 0x0c, 0xab} diff --git a/winapi/src/um/combaseapi.rs b/winapi/src/um/combaseapi.rs new file mode 100644 index 000000000..823c026ac --- /dev/null +++ b/winapi/src/um/combaseapi.rs @@ -0,0 +1,477 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Base Component Object Model defintions. +use ctypes::{c_int, c_void}; +use shared::basetsd::{SIZE_T, UINT64, ULONG_PTR}; +use shared::guiddef::{CLSID, GUID, LPCLSID, LPIID, REFCLSID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, FILETIME, HGLOBAL, LPDWORD, LPHANDLE, LPVOID, ULONG}; +use shared::rpcdce::{RPC_AUTHZ_HANDLE, RPC_AUTH_IDENTITY_HANDLE}; +use shared::wtypesbase::{ + CLSCTX, CLSCTX_INPROC_HANDLER, CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, CLSCTX_REMOTE_SERVER, + LPCOLESTR, LPOLESTR, OLECHAR, +}; +use um::objidl::SOLE_AUTHENTICATION_SERVICE; +use um::objidlbase::{ + APTTYPE, APTTYPEQUALIFIER, COSERVERINFO, IActivationFilter, IAgileReference, LPMALLOC, + LPMARSHAL, LPSTREAM, LPSURROGATE, MULTI_QI, +}; +use um::propidl::PROPVARIANT; +use um::unknwnbase::{IUnknown, LPUNKNOWN}; +use um::winnt::{HANDLE, HRESULT, LARGE_INTEGER, LONG, PSECURITY_DESCRIPTOR, PVOID, ULARGE_INTEGER}; +#[inline] +pub fn LISet32(li: &mut LARGE_INTEGER, v: DWORD) { + unsafe { + li.u_mut().HighPart = if (v as LONG) < 0 { + -1 + } else { + 0 + }; + li.u_mut().LowPart = v; + } +} +#[inline] +pub fn ULISet32(li: &mut ULARGE_INTEGER, v: DWORD) { + unsafe { + li.u_mut().HighPart = 0; + li.u_mut().LowPart = v; + } +} +pub const CLSCTX_INPROC: CLSCTX = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER; +pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER + | CLSCTX_REMOTE_SERVER; +pub const CLSCTX_SERVER: CLSCTX = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER + | CLSCTX_REMOTE_SERVER; +ENUM!{enum REGCLS { + REGCLS_SINGLEUSE = 0, + REGCLS_MULTIPLEUSE = 1, + REGCLS_MULTI_SEPARATE = 2, + REGCLS_SUSPENDED = 4, + REGCLS_SURROGATE = 8, + REGCLS_AGILE = 0x10, +}} +ENUM!{enum COINITBASE { + COINITBASE_MULTITHREADED = 0x0, +}} +extern "system" { + pub fn CoGetMalloc( + dwMemContext: DWORD, + ppMalloc: *mut LPMALLOC, + ) -> HRESULT; + pub fn CreateStreamOnHGlobal( + hGlobal: HGLOBAL, + fDeleteOnRelease: BOOL, + ppstm: *mut LPSTREAM, + ) -> HRESULT; + pub fn GetHGlobalFromStream( + pstm: LPSTREAM, + phglobal: *mut HGLOBAL, + ) -> HRESULT; + pub fn CoUninitialize() -> (); + pub fn CoGetCurrentProcess() -> DWORD; + pub fn CoInitializeEx( + pvReserved: LPVOID, + dwCoInit: DWORD, + ) -> HRESULT; + pub fn CoGetCallerTID( + lpdwTID: LPDWORD, + ) -> HRESULT; + pub fn CoGetCurrentLogicalThreadId( + pguid: *mut GUID, + ) -> HRESULT; + pub fn CoGetContextToken( + pToken: *mut ULONG_PTR, + ) -> HRESULT; + pub fn CoGetDefaultContext( + aptType: APTTYPE, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; + pub fn CoGetApartmentType( + pAptType: *mut APTTYPE, + pAptQualifier: *mut APTTYPEQUALIFIER, + ) -> HRESULT; +} +STRUCT!{struct ServerInformation { + dwServerPid: DWORD, + dwServerTid: DWORD, + ui64ServerAddress: UINT64, +}} +pub type PServerInformation = *mut ServerInformation; +extern "system" { + pub fn CoDecodeProxy( + dwClientPid: DWORD, + ui64ProxyAddress: UINT64, + pServerInformation: PServerInformation, + ) -> HRESULT; +} +DECLARE_HANDLE!{CO_MTA_USAGE_COOKIE, CO_MTA_USAGE_COOKIE__} +extern "system" { + pub fn CoIncrementMTAUsage( + pCookie: *mut CO_MTA_USAGE_COOKIE, + ) -> HRESULT; + pub fn CoDecrementMTAUsage( + Cookie: CO_MTA_USAGE_COOKIE, + ) -> HRESULT; + pub fn CoAllowUnmarshalerCLSID( + clsid: REFCLSID, + ) -> HRESULT; + pub fn CoGetObjectContext( + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn CoGetClassObject( + rclsid: REFCLSID, + dwClsContext: DWORD, + pvReserved: LPVOID, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn CoRegisterClassObject( + rclsid: REFCLSID, + pUnk: LPUNKNOWN, + dwClsContext: DWORD, + flags: DWORD, + lpdwRegister: LPDWORD, + ) -> HRESULT; + pub fn CoRevokeClassObject( + dwRegister: DWORD, + ) -> HRESULT; + pub fn CoResumeClassObjects() -> HRESULT; + pub fn CoSuspendClassObjects() -> HRESULT; + pub fn CoAddRefServerProcess() -> ULONG; + pub fn CoReleaseServerProcess() -> ULONG; + pub fn CoGetPSClsid( + riid: REFIID, + pClsid: *mut CLSID, + ) -> HRESULT; + pub fn CoRegisterPSClsid( + riid: REFIID, + rclsid: REFCLSID, + ) -> HRESULT; + pub fn CoRegisterSurrogate( + pSurrogate: LPSURROGATE, + ) -> HRESULT; + pub fn CoGetMarshalSizeMax( + pulSize: *mut ULONG, + riid: REFIID, + pUnk: LPUNKNOWN, + dwDestContext: DWORD, + pvDestContext: LPVOID, + mshlflags: DWORD, + ) -> HRESULT; + pub fn CoMarshalInterface( + pStm: LPSTREAM, + riid: REFIID, + pUnk: LPUNKNOWN, + dwDestContext: DWORD, + pvDestContext: LPVOID, + mshlflags: DWORD, + ) -> HRESULT; + pub fn CoUnmarshalInterface( + pStm: LPSTREAM, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn CoMarshalHresult( + pstm: LPSTREAM, + hresult: HRESULT, + ) -> HRESULT; + pub fn CoUnmarshalHresult( + pstm: LPSTREAM, + phresult: *mut HRESULT, + ) -> HRESULT; + pub fn CoReleaseMarshalData( + pstm: LPSTREAM, + ) -> HRESULT; + pub fn CoDisconnectObject( + pUnk: LPUNKNOWN, + dwReserved: DWORD, + ) -> HRESULT; + pub fn CoLockObjectExternal( + pUnk: LPUNKNOWN, + fLock: BOOL, + fLastUnlockReleases: BOOL, + ) -> HRESULT; + pub fn CoGetStandardMarshal( + riid: REFIID, + pUnk: LPUNKNOWN, + dwDestContext: DWORD, + pvDestContext: LPVOID, + mshlflags: DWORD, + ppMarshal: *mut LPMARSHAL, + ) -> HRESULT; + pub fn CoGetStdMarshalEx( + pUnkOuter: LPUNKNOWN, + smexflags: DWORD, + ppUnkInner: *mut LPUNKNOWN, + ) -> HRESULT; +} +ENUM!{enum STDMSHLFLAGS { + SMEXF_SERVER = 0x01, + SMEXF_HANDLER = 0x02, +}} +extern "system" { + pub fn CoIsHandlerConnected( + pUnk: LPUNKNOWN, + ) -> BOOL; + pub fn CoMarshalInterThreadInterfaceInStream( + riid: REFIID, + pUnk: LPUNKNOWN, + ppStm: *mut LPSTREAM, + ) -> HRESULT; + pub fn CoGetInterfaceAndReleaseStream( + pStm: LPSTREAM, + iid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn CoCreateFreeThreadedMarshaler( + punkOuter: LPUNKNOWN, + ppunkMarshal: *mut LPUNKNOWN, + ) -> HRESULT; + pub fn CoFreeUnusedLibraries(); + pub fn CoFreeUnusedLibrariesEx( + dwUnloadDelay: DWORD, + dwReserved: DWORD, + ); + pub fn CoDisconnectContext( + dwTimeout: DWORD, + )-> HRESULT; + pub fn CoInitializeSecurity( + pSecDesc: PSECURITY_DESCRIPTOR, + cAuthSvc: LONG, + asAuthSvc: *mut SOLE_AUTHENTICATION_SERVICE, + pReserved1: *mut c_void, + dwAuthnLevel: DWORD, + dwImpLevel: DWORD, + pAuthList: *mut c_void, + dwCapabilities: DWORD, + pReserved3: *mut c_void, + ) -> HRESULT; + pub fn CoGetCallContext( + riid: REFIID, + ppInterface: *mut *mut c_void, + ) -> HRESULT; + pub fn CoQueryProxyBlanket( + pProxy: *mut IUnknown, + pwAuthnSvc: *mut DWORD, + pAuthzSvc: *mut DWORD, + pServerPrincName: *mut LPOLESTR, + pAuthnLevel: *mut DWORD, + pImpLevel: *mut DWORD, + pAuthInfo: *mut RPC_AUTH_IDENTITY_HANDLE, + pCapabilites: *mut DWORD, + ) -> HRESULT; + pub fn CoSetProxyBlanket( + pProxy: *mut IUnknown, + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pServerPrincName: *mut OLECHAR, + dwAuthnLevel: DWORD, + dwImpLevel: DWORD, + pAuthInfo: RPC_AUTH_IDENTITY_HANDLE, + dwCapabilities: DWORD, + ) -> HRESULT; + pub fn CoCopyProxy( + pProxy: *mut IUnknown, + ppCopy: *mut *mut IUnknown, + ) -> HRESULT; + pub fn CoQueryClientBlanket( + pAuthnSvc: *mut DWORD, + pAuthzSvc: *mut DWORD, + pServerPrincName: *mut LPOLESTR, + pAuthnLevel: *mut DWORD, + pImpLevel: *mut DWORD, + pPrivs: *mut RPC_AUTHZ_HANDLE, + pCapabilities: *mut DWORD, + ) -> HRESULT; + pub fn CoImpersonateClient() -> HRESULT; + pub fn CoRevertToSelf() -> HRESULT; + pub fn CoQueryAuthenticationServices( + pcAuthSvc: *mut DWORD, + asAuthSvc: *mut *mut SOLE_AUTHENTICATION_SERVICE, + ) -> HRESULT; + pub fn CoSwitchCallContext( + pNewObject: *mut IUnknown, + ppOldObject: *mut *mut IUnknown, + ) -> HRESULT; +} +pub const COM_RIGHTS_EXECUTE: DWORD = 1; +pub const COM_RIGHTS_EXECUTE_LOCAL: DWORD = 2; +pub const COM_RIGHTS_EXECUTE_REMOTE: DWORD = 4; +pub const COM_RIGHTS_ACTIVATE_LOCAL: DWORD = 8; +pub const COM_RIGHTS_ACTIVATE_REMOTE: DWORD = 16; +extern "system" { + pub fn CoCreateInstance( + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn CoCreateInstanceEx( + Clsid: REFCLSID, + punkOuter: *mut IUnknown, + dwClsCtx: DWORD, + pServerInfo: *mut COSERVERINFO, + dwCount: DWORD, + pResults: *mut MULTI_QI, + ) -> HRESULT; + pub fn CoRegisterActivationFilter( + pActivationFilter: *mut IActivationFilter, + ) -> HRESULT; + pub fn CoCreateInstanceFromApp( + Clsid: REFCLSID, + punkOuter: *mut IUnknown, + dwClsCtx: DWORD, + reserved: PVOID, + dwCount: DWORD, + pResults: *mut MULTI_QI, + ) -> HRESULT; + pub fn CoGetCancelObject( + dwThreadId: DWORD, + iid: REFIID, + ppUnk: *mut *mut c_void, + ) -> HRESULT; + pub fn CoSetCancelObject( + pUnk: *mut *mut IUnknown, + ) -> HRESULT; + pub fn CoCancelCall( + dwThreadId: DWORD, + ulTimeout: ULONG, + ) -> HRESULT; + pub fn CoTestCancel() -> HRESULT; + pub fn CoEnableCallCancellation( + pReserved: LPVOID, + ) -> HRESULT; + pub fn CoDisableCallCancellation( + pReserved: LPVOID, + ) -> HRESULT; + pub fn StringFromCLSID( + rclsid: REFCLSID, + lplpsz: *mut LPOLESTR, + ) -> HRESULT; + pub fn CLSIDFromString( + lpsz: LPCOLESTR, + pclsid: LPCLSID, + ) -> HRESULT; + pub fn StringFromIID( + rclsid: REFIID, + lplpsz: *mut LPOLESTR, + ) -> HRESULT; + pub fn IIDFromString( + lpsz: LPCOLESTR, + lpiid: LPIID, + ) -> HRESULT; + pub fn ProgIDFromCLSID( + clsid: REFCLSID, + lplpszProgID: *mut LPOLESTR, + ) -> HRESULT; + pub fn CLSIDFromProgID( + lpszProgID: LPCOLESTR, + lpclsid: LPCLSID, + ) -> HRESULT; + pub fn StringFromGUID2( + rguid: REFGUID, + lpsz: LPOLESTR, + cchMax: c_int, + ) -> c_int; + pub fn CoCreateGuid( + pguid: *mut GUID, + ) -> HRESULT; + pub fn PropVariantCopy( + pvarDest: *mut PROPVARIANT, + pvarSrc: *const PROPVARIANT, + ) -> HRESULT; + pub fn PropVariantClear( + pvar: *mut PROPVARIANT, + ) -> HRESULT; + pub fn FreePropVariantArray( + cVariants: ULONG, + rgvars: *mut PROPVARIANT, + ) -> HRESULT; + pub fn CoWaitForMultipleHandles( + dwFlags: DWORD, + dwTimeout: DWORD, + cHandles: ULONG, + pHandles: LPHANDLE, + lpdwindex: LPDWORD, + ) -> HRESULT; +} +ENUM!{enum COWAIT_FLAGS { + COWAIT_DEFAULT = 0, + COWAIT_WAITALL = 1, + COWAIT_ALERTABLE = 2, + COWAIT_INPUTAVAILABLE = 4, + COWAIT_DISPATCH_CALLS = 8, + COWAIT_DISPATCH_WINDOW_MESSAGES = 0x10, +}} +ENUM!{enum CWMO_FLAGS { + CWMO_DEFAULT = 0, + CWMO_DISPATCH_CALLS = 1, + CWMO_DISPATCH_WINDOW_MESSAGES = 2, +}} +extern "system" { + pub fn CoWaitForMultipleObjects( + dwFlags: DWORD, + dwTimeout: DWORD, + cHandles: ULONG, + pHandles: *const HANDLE, + lpdwindex: LPDWORD, + ) -> HRESULT; +} +pub const CWMO_MAX_HANDLES: ULONG = 56; +extern "system" { + pub fn CoGetTreatAsClass( + clsidOld: REFCLSID, + pClsidNew: LPCLSID, + ) -> HRESULT; + pub fn CoInvalidateRemoteMachineBindings( + pszMachineName: LPOLESTR, + ) -> HRESULT; +} +ENUM!{enum AgileReferenceOptions { + AGILEREFERENCE_DEFAULT = 0, + AGILEREFERENCE_DELAYEDMARSHAL = 1, +}} +extern "system" { + pub fn RoGetAgileReference( + options: AgileReferenceOptions, + riid: REFIID, + pUnk: *mut IUnknown, + ppAgileReference: *mut *mut IAgileReference, + ) -> HRESULT; +} +FN!{stdcall LPFNGETCLASSOBJECT( + REFCLSID, + REFIID, + *mut LPVOID, +) -> HRESULT} +FN!{stdcall LPFNCANUNLOADNOW() -> HRESULT} +extern "system" { + pub fn DllGetClassObject( + rclsid: REFCLSID, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn DllCanUnloadNow() -> HRESULT; + pub fn CoTaskMemAlloc( + cb: SIZE_T, + ) -> LPVOID; + pub fn CoTaskMemRealloc( + pv: LPVOID, + cb: SIZE_T, + ) -> LPVOID; + pub fn CoTaskMemFree( + pv: LPVOID, + ); + pub fn CoFileTimeNow( + lpFileTime: *mut FILETIME, + ) -> HRESULT; + pub fn CLSIDFromProgIDEx( + lpszProgID: LPCOLESTR, + lpclsid: LPCLSID, + ) -> HRESULT; +} diff --git a/winapi/src/um/coml2api.rs b/winapi/src/um/coml2api.rs new file mode 100644 index 000000000..449be87e3 --- /dev/null +++ b/winapi/src/um/coml2api.rs @@ -0,0 +1,10 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Structured storage, property sets, and related APIs. +use shared::minwindef::DWORD; +pub const STGM_READ: DWORD = 0x00000000; +pub const STGM_WRITE: DWORD = 0x00000001; +pub const STGM_READWRITE: DWORD = 0x00000002; diff --git a/winapi/src/um/commapi.rs b/winapi/src/um/commapi.rs new file mode 100644 index 000000000..433bb78fa --- /dev/null +++ b/winapi/src/um/commapi.rs @@ -0,0 +1,87 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_char; +use shared::minwindef::{BOOL, DWORD, LPDWORD}; +use um::minwinbase::LPOVERLAPPED; +use um::winbase::{LPCOMMCONFIG, LPCOMMPROP, LPCOMMTIMEOUTS, LPCOMSTAT, LPDCB}; +use um::winnt::HANDLE; +extern "system" { + pub fn ClearCommBreak( + hFile: HANDLE, + ) -> BOOL; + pub fn ClearCommError( + hFile: HANDLE, + lpErrors: LPDWORD, + lpStat: LPCOMSTAT, + ) -> BOOL; + pub fn SetupComm( + hFile: HANDLE, + dwInQueue: DWORD, + dwOutQueue: DWORD, + ) -> BOOL; + pub fn EscapeCommFunction( + hFile: HANDLE, + dwFunc: DWORD, + ) -> BOOL; + pub fn GetCommConfig( + hCommDev: HANDLE, + lpCC: LPCOMMCONFIG, + lpdwSize: LPDWORD, + ) -> BOOL; + pub fn GetCommMask( + hFile: HANDLE, + lpEvtMask: LPDWORD, + ) -> BOOL; + pub fn GetCommModemStatus( + hFile: HANDLE, + lpModemStat: LPDWORD, + ) -> BOOL; + pub fn GetCommProperties( + hFile: HANDLE, + lpCommProp: LPCOMMPROP, + ) -> BOOL; + pub fn GetCommState( + hFile: HANDLE, + lpDCB: LPDCB, + ) -> BOOL; + pub fn GetCommTimeouts( + hFile: HANDLE, + lpCommTimeouts: LPCOMMTIMEOUTS, + ) -> BOOL; + pub fn PurgeComm( + hFile: HANDLE, + dwFlags: DWORD, + ) -> BOOL; + pub fn SetCommBreak( + hFile: HANDLE, + ) -> BOOL; + pub fn SetCommConfig( + hCommDev: HANDLE, + lpCC: LPCOMMCONFIG, + dwSize: DWORD, + ) -> BOOL; + pub fn SetCommMask( + hFile: HANDLE, + dwEvtMask: DWORD, + ) -> BOOL; + pub fn SetCommState( + hFile: HANDLE, + lpDCB: LPDCB, + ) -> BOOL; + pub fn SetCommTimeouts( + hFile: HANDLE, + lpCommTimeouts: LPCOMMTIMEOUTS, + ) -> BOOL; + pub fn TransmitCommChar( + hFile: HANDLE, + cChar: c_char, + ) -> BOOL; + pub fn WaitCommEvent( + hFile: HANDLE, + lpEvtMask: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; +} diff --git a/winapi/src/um/commctrl.rs b/winapi/src/um/commctrl.rs new file mode 100644 index 000000000..9b32d3259 --- /dev/null +++ b/winapi/src/um/commctrl.rs @@ -0,0 +1,4135 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, c_int, c_long, c_short, c_void}; +use shared::basetsd::{DWORD_PTR, INT_PTR, LONG_PTR, UINT_PTR}; +#[cfg(target_pointer_width = "64")] use shared::basetsd::PINT_PTR; +use shared::guiddef::{IID, REFIID}; +use shared::minwindef::{ + BOOL, BYTE, DWORD, HINSTANCE, HKEY, INT, LPARAM, LPINT, LRESULT, PUINT, UINT, ULONG, WORD, + WPARAM, +}; +use shared::windef::{ + COLORREF, HBITMAP, HBRUSH, HDC, HICON, HMENU, HPEN, HWND, LPCRECT, LPRECT, POINT, RECT, SIZE, +}; +use um::commoncontrols::IImageList; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{CHAR, LANGID, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCWSTR, PVOID, PWSTR, WCHAR}; +use um::winuser::{ + CB_DELETESTRING, IMAGE_BITMAP, LPSCROLLINFO, LPTRACKMOUSEEVENT, NMHDR, + WINDOWPOS, WM_USER, +}; +use vc::vcruntime::size_t; +pub type HRESULT = c_long; +extern "system" { + pub fn InitCommonControls(); +} +//138 +STRUCT!{struct INITCOMMONCONTROLSEX { + dwSize: DWORD, + dwICC: DWORD, +}} +pub type LPINITCOMMONCONTROLSEX = *mut INITCOMMONCONTROLSEX; +pub const ICC_LISTVIEW_CLASSES: DWORD = 0x1; +pub const ICC_TREEVIEW_CLASSES: DWORD = 0x2; +pub const ICC_BAR_CLASSES: DWORD = 0x4; +pub const ICC_TAB_CLASSES: DWORD = 0x8; +pub const ICC_UPDOWN_CLASS: DWORD = 0x10; +pub const ICC_PROGRESS_CLASS: DWORD = 0x20; +pub const ICC_HOTKEY_CLASS: DWORD = 0x40; +pub const ICC_ANIMATE_CLASS: DWORD = 0x80; +pub const ICC_WIN95_CLASSES: DWORD = 0xFF; +pub const ICC_DATE_CLASSES: DWORD = 0x100; +pub const ICC_USEREX_CLASSES: DWORD = 0x200; +pub const ICC_COOL_CLASSES: DWORD = 0x400; +pub const ICC_INTERNET_CLASSES: DWORD = 0x800; +pub const ICC_PAGESCROLLER_CLASS: DWORD = 0x1000; +pub const ICC_NATIVEFNTCTL_CLASS: DWORD = 0x2000; +pub const ICC_STANDARD_CLASSES: DWORD = 0x4000; +pub const ICC_LINK_CLASS: DWORD = 0x8000; +extern "system" { + pub fn InitCommonControlsEx( + lpInitCtrls: *const INITCOMMONCONTROLSEX, + ) -> BOOL; +} +pub const ODT_HEADER: UINT = 100; +pub const ODT_TAB: UINT = 101; +pub const ODT_LISTVIEW: UINT = 102; +pub const LVM_FIRST: UINT = 0x1000; +pub const TV_FIRST: UINT = 0x1100; +pub const HDM_FIRST: UINT = 0x1200; +pub const TCM_FIRST: UINT = 0x1300; +pub const PGM_FIRST: UINT = 0x1400; +pub const ECM_FIRST: UINT = 0x1500; +pub const BCM_FIRST: UINT = 0x1600; +pub const CBM_FIRST: UINT = 0x1700; +pub const CCM_FIRST: UINT = 0x2000; +pub const CCM_LAST: UINT = CCM_FIRST + 0x200; +pub const CCM_SETBKCOLOR: UINT = CCM_FIRST + 1; +STRUCT!{struct COLORSCHEME { + dwSize: DWORD, + clrBtnHighlight: COLORREF, + clrBtnShadow: COLORREF, +}} +pub type LPCOLORSCHEME = *mut COLORSCHEME; +pub const CCM_SETCOLORSCHEME: UINT = CCM_FIRST + 2; +pub const CCM_GETCOLORSCHEME: UINT = CCM_FIRST + 3; +pub const CCM_GETDROPTARGET: UINT = CCM_FIRST + 4; +pub const CCM_SETUNICODEFORMAT: UINT = CCM_FIRST + 5; +pub const CCM_GETUNICODEFORMAT: UINT = CCM_FIRST + 6; +pub const CCM_SETVERSION: UINT = CCM_FIRST + 7; +pub const CCM_GETVERSION: UINT = CCM_FIRST + 8; +pub const CCM_SETNOTIFYWINDOW: UINT = CCM_FIRST + 9; +pub const CCM_SETWINDOWTHEME: UINT = CCM_FIRST + 0xb; +pub const CCM_DPISCALE: UINT = CCM_FIRST + 0xc; +pub const INFOTIPSIZE: c_int = 1024; +pub const NM_OUTOFMEMORY: UINT = (NM_FIRST as i32 - 1) as u32; +pub const NM_CLICK: UINT = (NM_FIRST as i32 - 2) as u32; +pub const NM_DBLCLK: UINT = (NM_FIRST as i32 - 3) as u32; +pub const NM_RETURN: UINT = (NM_FIRST as i32 - 4) as u32; +pub const NM_RCLICK: UINT = (NM_FIRST as i32 - 5) as u32; +pub const NM_RDBLCLK: UINT = (NM_FIRST as i32 - 6) as u32; +pub const NM_SETFOCUS: UINT = (NM_FIRST as i32 - 7) as u32; +pub const NM_KILLFOCUS: UINT = (NM_FIRST as i32 - 8) as u32; +pub const NM_CUSTOMDRAW: UINT = (NM_FIRST as i32 - 12) as u32; +pub const NM_HOVER: UINT = (NM_FIRST as i32 - 13) as u32; +pub const NM_NCHITTEST: UINT = (NM_FIRST as i32 - 14) as u32; +pub const NM_KEYDOWN: UINT = (NM_FIRST as i32 - 15) as u32; +pub const NM_RELEASEDCAPTURE: UINT = (NM_FIRST as i32 - 16) as u32; +pub const NM_SETCURSOR: UINT = (NM_FIRST as i32 - 17) as u32; +pub const NM_CHAR: UINT = (NM_FIRST as i32 - 18) as u32; +pub const NM_TOOLTIPSCREATED: UINT = (NM_FIRST as i32 - 19) as u32; +pub const NM_LDOWN: UINT = (NM_FIRST as i32 - 20) as u32; +pub const NM_RDOWN: UINT = (NM_FIRST as i32 - 21) as u32; +pub const NM_THEMECHANGED: UINT = (NM_FIRST as i32 - 22) as u32; +pub const NM_FONTCHANGED: UINT = (NM_FIRST as i32 - 23) as u32; +pub const NM_CUSTOMTEXT: UINT = (NM_FIRST as i32 - 24) as u32; +pub const NM_TVSTATEIMAGECHANGING: UINT = (NM_FIRST as i32 - 24) as u32; +STRUCT!{struct NMTOOLTIPSCREATED { + hdr: NMHDR, + hwndToolTips: HWND, +}} +pub type LPNMTOOLTIPSCREATED = *mut NMTOOLTIPSCREATED; +STRUCT!{struct NMMOUSE { + hdr: NMHDR, + dwItemSpec: DWORD_PTR, + dwItemData: DWORD_PTR, + pt: POINT, + dwHitInfo: LPARAM, +}} +pub type LPNMMOUSE = *mut NMMOUSE; +pub type NMCLICK = NMMOUSE; +pub type LPNMCLICK = LPNMMOUSE; +STRUCT!{struct NMOBJECTNOTIFY { + hdr: NMHDR, + iItem: c_int, + piid: *const IID, + pObject: *mut c_void, + hResult: HRESULT, + dwFlags: DWORD, +}} +pub type LPNMOBJECTNOTIFY = *mut NMOBJECTNOTIFY; +STRUCT!{struct NMKEY { + hdr: NMHDR, + nVKey: UINT, + uFlags: UINT, +}} +pub type LPNMKEY = *mut NMKEY; +STRUCT!{struct NMCHAR { + hdr: NMHDR, + ch: UINT, + dwItemPrev: DWORD, + dwItemNext: DWORD, +}} +pub type LPNMCHAR = *mut NMCHAR; +STRUCT!{struct NMCUSTOMTEXT { + hdr: NMHDR, + hDC: HDC, + lpString: LPCWSTR, + nCount: c_int, + lpRect: LPRECT, + uFormat: UINT, + fLink: BOOL, +}} +pub type LPNMCUSTOMTEXT = *mut NMCUSTOMTEXT; +pub const NM_FIRST: UINT = 0; +pub const NM_LAST: UINT = -99i32 as u32; +pub const LVN_FIRST: UINT = -100i32 as u32; +pub const LVN_LAST: UINT = -199i32 as u32; +pub const HDN_FIRST: UINT = -300i32 as u32; +pub const HDN_LAST: UINT = -399i32 as u32; +pub const TVN_FIRST: UINT = -400i32 as u32; +pub const TVN_LAST: UINT = -499i32 as u32; +pub const TTN_FIRST: UINT = -520i32 as u32; +pub const TTN_LAST: UINT = -549i32 as u32; +pub const TCN_FIRST: UINT = -550i32 as u32; +pub const TCN_LAST: UINT = -580i32 as u32; +pub const CDN_FIRST: UINT = -601i32 as u32; +pub const CDN_LAST: UINT = -699i32 as u32; +pub const TBN_FIRST: UINT = -700i32 as u32; +pub const TBN_LAST: UINT = -720i32 as u32; +pub const UDN_FIRST: UINT = -721i32 as u32; +pub const UDN_LAST: UINT = -729i32 as u32; +pub const DTN_FIRST: UINT = -740i32 as u32; +pub const DTN_LAST: UINT = -745i32 as u32; +pub const MCN_FIRST: UINT = -746i32 as u32; +pub const MCN_LAST: UINT = -752i32 as u32; +pub const DTN_FIRST2: UINT = -753i32 as u32; +pub const DTN_LAST2: UINT = -799i32 as u32; +pub const CBEN_FIRST: UINT = -800i32 as u32; +pub const CBEN_LAST: UINT = -830i32 as u32; +pub const RBN_FIRST: UINT = -831i32 as u32; +pub const RBN_LAST: UINT = -859i32 as u32; +pub const IPN_FIRST: UINT = -860i32 as u32; +pub const IPN_LAST: UINT = -879i32 as u32; +pub const SBN_FIRST: UINT = -880i32 as u32; +pub const SBN_LAST: UINT = -899i32 as u32; +pub const PGN_FIRST: UINT = -900i32 as u32; +pub const PGN_LAST: UINT = -950i32 as u32; +pub const WMN_FIRST: UINT = -1000i32 as u32; +pub const WMN_LAST: UINT = -1200i32 as u32; +pub const BCN_FIRST: UINT = -1250i32 as u32; +pub const BCN_LAST: UINT = -1350i32 as u32; +pub const TRBN_FIRST: UINT = -1501i32 as u32; +pub const TRBN_LAST: UINT = -1519i32 as u32; +pub const MSGF_COMMCTRL_BEGINDRAG: c_int = 0x4200; +pub const MSGF_COMMCTRL_SIZEHEADER: c_int = 0x4201; +pub const MSGF_COMMCTRL_DRAGSELECT: c_int = 0x4202; +pub const MSGF_COMMCTRL_TOOLBARCUST: c_int = 0x4203; +pub const CDRF_DODEFAULT: LRESULT = 0x00000000; +pub const CDRF_NEWFONT: LRESULT = 0x00000002; +pub const CDRF_SKIPDEFAULT: LRESULT = 0x00000004; +pub const CDRF_DOERASE: LRESULT = 0x00000008; +pub const CDRF_SKIPPOSTPAINT: LRESULT = 0x00000100; +pub const CDRF_NOTIFYPOSTPAINT: LRESULT = 0x00000010; +pub const CDRF_NOTIFYITEMDRAW: LRESULT = 0x00000020; +pub const CDRF_NOTIFYSUBITEMDRAW: LRESULT = 0x00000020; +pub const CDRF_NOTIFYPOSTERASE: LRESULT = 0x00000040; +pub const CDDS_PREPAINT: DWORD = 0x00000001; +pub const CDDS_POSTPAINT: DWORD = 0x00000002; +pub const CDDS_PREERASE: DWORD = 0x00000003; +pub const CDDS_POSTERASE: DWORD = 0x00000004; +pub const CDDS_ITEM: DWORD = 0x00010000; +pub const CDDS_ITEMPREPAINT: DWORD = CDDS_ITEM | CDDS_PREPAINT; +pub const CDDS_ITEMPOSTPAINT: DWORD = CDDS_ITEM | CDDS_POSTPAINT; +pub const CDDS_ITEMPREERASE: DWORD = CDDS_ITEM | CDDS_PREERASE; +pub const CDDS_ITEMPOSTERASE: DWORD = CDDS_ITEM | CDDS_POSTERASE; +pub const CDDS_SUBITEM: DWORD = 0x00020000; +pub const CDIS_SELECTED: UINT = 0x0001; +pub const CDIS_GRAYED: UINT = 0x0002; +pub const CDIS_DISABLED: UINT = 0x0004; +pub const CDIS_CHECKED: UINT = 0x0008; +pub const CDIS_FOCUS: UINT = 0x0010; +pub const CDIS_DEFAULT: UINT = 0x0020; +pub const CDIS_HOT: UINT = 0x0040; +pub const CDIS_MARKED: UINT = 0x0080; +pub const CDIS_INDETERMINATE: UINT = 0x0100; +pub const CDIS_SHOWKEYBOARDCUES: UINT = 0x0200; +pub const CDIS_NEARHOT: UINT = 0x0400; +pub const CDIS_OTHERSIDEHOT: UINT = 0x0800; +pub const CDIS_DROPHILITED: UINT = 0x1000; +STRUCT!{struct NMCUSTOMDRAW { + hdr: NMHDR, + dwDrawStage: DWORD, + hdc: HDC, + rc: RECT, + dwItemSpec: DWORD_PTR, + uItemState: UINT, + lItemlParam: LPARAM, +}} +pub type LPNMCUSTOMDRAW = *mut NMCUSTOMDRAW; +STRUCT!{struct NMTTCUSTOMDRAW { + nmcd: NMCUSTOMDRAW, + uDrawFlags: UINT, +}} +pub type LPNMTTCUSTOMDRAW = *mut NMTTCUSTOMDRAW; +STRUCT!{struct NMCUSTOMSPLITRECTINFO { + hdr: NMHDR, + rcClient: RECT, + rcButton: RECT, + rcSplit: RECT, +}} +pub type LPNMCUSTOMSPLITRECTINFO = *mut NMCUSTOMSPLITRECTINFO; +pub const NM_GETCUSTOMSPLITRECT: UINT = BCN_FIRST + 0x0003; +pub const CLR_NONE: DWORD = 0xFFFFFFFF; +pub const CLR_DEFAULT: DWORD = 0xFF000000; +pub enum IMAGELIST {} +pub type HIMAGELIST = *mut IMAGELIST; +STRUCT!{struct IMAGELISTDRAWPARAMS { + cbSize: DWORD, + himl: HIMAGELIST, + i: c_int, + hdcDst: HDC, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + xBitmap: c_int, + yBitmap: c_int, + rgbBk: COLORREF, + rgbFg: COLORREF, + fStyle: UINT, + dwRop: DWORD, + fState: DWORD, + Frame: DWORD, + crEffect: COLORREF, +}} +pub type LPIMAGELISTDRAWPARAMS = *mut IMAGELISTDRAWPARAMS; +pub const ILC_MASK: UINT = 0x00000001; +pub const ILC_COLOR: UINT = 0x00000000; +pub const ILC_COLORDDB: UINT = 0x000000FE; +pub const ILC_COLOR4: UINT = 0x00000004; +pub const ILC_COLOR8: UINT = 0x00000008; +pub const ILC_COLOR16: UINT = 0x00000010; +pub const ILC_COLOR24: UINT = 0x00000018; +pub const ILC_COLOR32: UINT = 0x00000020; +pub const ILC_PALETTE: UINT = 0x00000800; +pub const ILC_MIRROR: UINT = 0x00002000; +pub const ILC_PERITEMMIRROR: UINT = 0x00008000; +pub const ILC_ORIGINALSIZE: UINT = 0x00010000; +pub const ILC_HIGHQUALITYSCALE: UINT = 0x00020000; +extern "system" { + pub fn ImageList_Create( + cx: c_int, + cy: c_int, + flags: UINT, + cInitial: c_int, + cGrow: c_int, + ) -> HIMAGELIST; + pub fn ImageList_Destroy( + himl: HIMAGELIST, + ) -> BOOL; + pub fn ImageList_GetImageCount( + himl: HIMAGELIST, + ) -> c_int; + pub fn ImageList_SetImageCount( + himl: HIMAGELIST, + uNewCount: UINT, + ) -> BOOL; + pub fn ImageList_Add( + himl: HIMAGELIST, + hbmImage: HBITMAP, + hbmMask: HBITMAP, + ) -> c_int; + pub fn ImageList_ReplaceIcon( + himl: HIMAGELIST, + i: c_int, + hicon: HICON, + ) -> c_int; + pub fn ImageList_SetBkColor( + himl: HIMAGELIST, + clrBk: COLORREF, + ) -> COLORREF; + pub fn ImageList_GetBkColor( + himl: HIMAGELIST, + ) -> COLORREF; + pub fn ImageList_SetOverlayImage( + himl: HIMAGELIST, + iImage: c_int, + iOverlay: c_int, + ) -> BOOL; +} +#[inline] +pub unsafe fn ImageList_AddIcon(himl: HIMAGELIST, hicon: HICON) -> c_int { + ImageList_ReplaceIcon(himl, -1, hicon) +} +pub const ILD_NORMAL: UINT = 0x00000000; +pub const ILD_TRANSPARENT: UINT = 0x00000001; +pub const ILD_MASK: UINT = 0x00000010; +pub const ILD_IMAGE: UINT = 0x00000020; +pub const ILD_ROP: UINT = 0x00000040; +pub const ILD_BLEND25: UINT = 0x00000002; +pub const ILD_BLEND50: UINT = 0x00000004; +pub const ILD_OVERLAYMASK: UINT = 0x00000F00; +#[inline] +pub fn INDEXTOOVERLAYMASK(i: UINT) -> UINT { + i << 8 +} +pub const ILD_PRESERVEALPHA: UINT = 0x00001000; +pub const ILD_SCALE: UINT = 0x00002000; +pub const ILD_DPISCALE: UINT = 0x00004000; +pub const ILD_ASYNC: UINT = 0x00008000; +pub const ILD_SELECTED: UINT = ILD_BLEND50; +pub const ILD_FOCUS: UINT = ILD_BLEND25; +pub const ILD_BLEND: UINT = ILD_BLEND50; +pub const CLR_HILIGHT: DWORD = CLR_DEFAULT; +pub const ILS_NORMAL: DWORD = 0x00000000; +pub const ILS_GLOW: DWORD = 0x00000001; +pub const ILS_SHADOW: DWORD = 0x00000002; +pub const ILS_SATURATE: DWORD = 0x00000004; +pub const ILS_ALPHA: DWORD = 0x00000008; +pub const ILGT_NORMAL: DWORD = 0x00000000; +pub const ILGT_ASYNC : DWORD = 0x00000001; +extern "system" { + pub fn ImageList_Draw( + himl: HIMAGELIST, + i: c_int, + hdcDst: HDC, + x: c_int, + y: c_int, + fStyle: UINT, + ) -> BOOL; +} +pub const HBITMAP_CALLBACK: HBITMAP = -1isize as HBITMAP; +extern "system" { + pub fn ImageList_Replace( + himl: HIMAGELIST, + i: c_int, + hbmImage: HBITMAP, + hbmMask: HBITMAP, + ) -> BOOL; + pub fn ImageList_AddMasked( + himl: HIMAGELIST, + hbmImage: HBITMAP, + crMask: COLORREF, + ) -> c_int; + pub fn ImageList_DrawEx( + himl: HIMAGELIST, + i: c_int, + hdcDst: HDC, + x: c_int, + y: c_int, + dx: c_int, + dy: c_int, + rgbBk: COLORREF, + rgbFg: COLORREF, + fStyle: UINT, + ) -> BOOL; + pub fn ImageList_DrawIndirect( + pimldp: *mut IMAGELISTDRAWPARAMS, + ) -> BOOL; + pub fn ImageList_Remove( + himl: HIMAGELIST, + i: c_int, + ) -> BOOL; + pub fn ImageList_GetIcon( + himl: HIMAGELIST, + i: c_int, + flags: UINT, + ) -> HICON; + pub fn ImageList_LoadImageA( + hi: HINSTANCE, + lpbmp: LPCSTR, + cx: c_int, + cGrow: c_int, + crMask: COLORREF, + uType: UINT, + uFlags: UINT, + ) -> HIMAGELIST; + pub fn ImageList_LoadImageW( + hi: HINSTANCE, + lpbmp: LPCWSTR, + cx: c_int, + cGrow: c_int, + crMask: COLORREF, + uType: UINT, + uFlags: UINT, + ) -> HIMAGELIST; +} +pub const ILCF_MOVE: UINT = 0x00000000; +pub const ILCF_SWAP: UINT = 0x00000001; +extern "system" { + pub fn ImageList_Copy( + himlDst: HIMAGELIST, + iDst: c_int, + himlSrc: HIMAGELIST, + iSrc: c_int, + uFlags: UINT, + ) -> BOOL; + pub fn ImageList_BeginDrag( + himlTrack: HIMAGELIST, + iTrack: c_int, + dxHotspot: c_int, + dyHotspot: c_int, + ) -> BOOL; + pub fn ImageList_EndDrag(); + pub fn ImageList_DragEnter( + hwndLock: HWND, + x: c_int, + y: c_int, + ) -> BOOL; + pub fn ImageList_DragLeave( + hwndLock: HWND, + ) -> BOOL; + pub fn ImageList_DragMove( + x: c_int, + y: c_int, + ) -> BOOL; + pub fn ImageList_SetDragCursorImage( + himlDrag: HIMAGELIST, + iDrag: c_int, + dxHotspot: c_int, + dyHotspot: c_int, + ) -> BOOL; + pub fn ImageList_DragShowNolock( + fShow: BOOL, + ) -> BOOL; + pub fn ImageList_GetDragImage( + ppt: *mut POINT, + pptHotspot: *mut POINT, + ) -> HIMAGELIST; +} +#[inline] +pub unsafe fn ImageList_RemoveAll(himl: HIMAGELIST) -> BOOL { + ImageList_Remove(himl, -1) +} +#[inline] +pub unsafe fn ImageList_ExtractIcon(_: HINSTANCE, himl: HIMAGELIST, i: c_int) -> HICON { + ImageList_GetIcon(himl, i, 0) +} +#[inline] +pub unsafe fn ImageList_LoadBitmap( + hi: HINSTANCE, + lpbmp: LPCWSTR, + cx: c_int, + cGrow: c_int, + crMask: COLORREF, +) -> HIMAGELIST { + ImageList_LoadImageW(hi, lpbmp, cx, cGrow, crMask, IMAGE_BITMAP, 0) +} +pub enum IStream {} +extern "system" { + pub fn ImageList_Read( + pstm: *mut IStream, + ) -> HIMAGELIST; + pub fn ImageList_Write( + himl: HIMAGELIST, + pstm: *mut IStream, + ) -> BOOL; +} +pub const ILP_NORMAL: DWORD = 0; +pub const ILP_DOWNLEVEL: DWORD = 0; +extern "system" { + pub fn ImageList_ReadEx( + dwFlags: DWORD, + pstm: *mut IStream, + riid: REFIID, + ppv: *mut PVOID, + ) -> HRESULT; + pub fn ImageList_WriteEx( + himl: HIMAGELIST, + dwFlags: DWORD, + pstm: *mut IStream, + ) -> HRESULT; +} +STRUCT!{struct IMAGEINFO { + hbmImage: HBITMAP, + hbmMask: HBITMAP, + Unused1: c_int, + Unused2: c_int, + rcImage: RECT, +}} +pub type LPIMAGEINFO = *mut IMAGEINFO; +extern "system" { + pub fn ImageList_GetIconSize( + himl: HIMAGELIST, + cx: *mut c_int, + cy: *mut c_int, + ) -> BOOL; + pub fn ImageList_SetIconSize( + himl: HIMAGELIST, + cx: c_int, + cy: c_int, + ) -> BOOL; + pub fn ImageList_GetImageInfo( + himl: HIMAGELIST, + i: c_int, + pImageInfo: *mut IMAGEINFO, + ) -> BOOL; + pub fn ImageList_Merge( + himl1: HIMAGELIST, + i1: c_int, + himl2: HIMAGELIST, + i2: c_int, + dx: c_int, + dy: c_int, + ) -> HIMAGELIST; + pub fn ImageList_Duplicate( + himl: HIMAGELIST, + ) -> HIMAGELIST; + pub fn HIMAGELIST_QueryInterface( + himl: HIMAGELIST, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; +} +#[inline] +pub fn IImageListToHIMAGELIST(himl: *mut IImageList) -> HIMAGELIST { + himl as HIMAGELIST +} +pub const WC_HEADER: &'static str = "SysHeader32"; +pub const HDS_HORZ: DWORD = 0x0000; +pub const HDS_BUTTONS: DWORD = 0x0002; +pub const HDS_HOTTRACK: DWORD = 0x0004; +pub const HDS_HIDDEN: DWORD = 0x0008; +pub const HDS_DRAGDROP: DWORD = 0x0040; +pub const HDS_FULLDRAG: DWORD = 0x0080; +pub const HDS_FILTERBAR: DWORD = 0x0100; +pub const HDS_FLAT: DWORD = 0x0200; +pub const HDS_CHECKBOXES: DWORD = 0x0400; +pub const HDS_NOSIZING: DWORD = 0x0800; +pub const HDS_OVERFLOW: DWORD = 0x1000; +pub const HDFT_ISSTRING: UINT = 0x0000; +pub const HDFT_ISNUMBER: UINT = 0x0001; +pub const HDFT_ISDATE: UINT = 0x0002; +pub const HDFT_HASNOVALUE: UINT = 0x8000; +STRUCT!{struct HD_TEXTFILTERA { + pszText: LPSTR, + cchTextMax: INT, +}} +pub type LPHD_TEXTFILTERA = *mut HD_TEXTFILTERA; +STRUCT!{struct HD_TEXTFILTERW { + pszText: LPWSTR, + cchTextMax: INT, +}} +pub type LPHD_TEXTFILTERW = *mut HD_TEXTFILTERW; +STRUCT!{struct HDITEMA { + mask: UINT, + cxy: c_int, + pszText: LPSTR, + hbm: HBITMAP, + cchTextMax: c_int, + fmt: c_int, + lParam: LPARAM, + iImage: c_int, + iOrder: c_int, + _type: UINT, + pvFilter: *mut c_void, + state: UINT, +}} +pub type LPHDITEMA = *mut HDITEMA; +STRUCT!{struct HDITEMW { + mask: UINT, + cxy: c_int, + pszText: LPWSTR, + hbm: HBITMAP, + cchTextMax: c_int, + fmt: c_int, + lParam: LPARAM, + iImage: c_int, + iOrder: c_int, + _type: UINT, + pvFilter: *mut c_void, + state: UINT, +}} +pub type LPHDITEMW = *mut HDITEMW; +pub const HDI_WIDTH: UINT = 0x0001; +pub const HDI_HEIGHT: UINT = HDI_WIDTH; +pub const HDI_TEXT: UINT = 0x0002; +pub const HDI_FORMAT: UINT = 0x0004; +pub const HDI_LPARAM: UINT = 0x0008; +pub const HDI_BITMAP: UINT = 0x0010; +pub const HDI_IMAGE: UINT = 0x0020; +pub const HDI_DI_SETITEM: UINT = 0x0040; +pub const HDI_ORDER: UINT = 0x0080; +pub const HDI_FILTER: UINT = 0x0100; +pub const HDI_STATE: UINT = 0x0200; +pub const HDF_LEFT: c_int = 0x0000; +pub const HDF_RIGHT: c_int = 0x0001; +pub const HDF_CENTER: c_int = 0x0002; +pub const HDF_JUSTIFYMASK: c_int = 0x0003; +pub const HDF_RTLREADING: c_int = 0x0004; +pub const HDF_BITMAP: c_int = 0x2000; +pub const HDF_STRING: c_int = 0x4000; +pub const HDF_OWNERDRAW: c_int = 0x8000; +pub const HDF_IMAGE: c_int = 0x0800; +pub const HDF_BITMAP_ON_RIGHT: c_int = 0x1000; +pub const HDF_SORTUP: c_int = 0x0400; +pub const HDF_SORTDOWN: c_int = 0x0200; +pub const HDF_CHECKBOX: c_int = 0x0040; +pub const HDF_CHECKED: c_int = 0x0080; +pub const HDF_FIXEDWIDTH: c_int = 0x0100; +pub const HDF_SPLITBUTTON: c_int = 0x1000000; +pub const HDIS_FOCUSED: UINT = 0x00000001; +pub const HDM_GETITEMCOUNT: UINT = HDM_FIRST + 0; +pub const HDM_INSERTITEMA: UINT = HDM_FIRST + 1; +pub const HDM_INSERTITEMW: UINT = HDM_FIRST + 10; +pub const HDM_DELETEITEM: UINT = HDM_FIRST + 2; +pub const HDM_GETITEMA: UINT = HDM_FIRST + 3; +pub const HDM_GETITEMW: UINT = HDM_FIRST + 11; +pub const HDM_SETITEMA: UINT = HDM_FIRST + 4; +pub const HDM_SETITEMW: UINT = HDM_FIRST + 12; +STRUCT!{struct HDLAYOUT { + prc: *mut RECT, + pwpos: *mut WINDOWPOS, +}} +pub type LPHDLAYOUT = *mut HDLAYOUT; +pub const HDM_LAYOUT: UINT = HDM_FIRST + 5; +pub const HHT_NOWHERE: UINT = 0x0001; +pub const HHT_ONHEADER: UINT = 0x0002; +pub const HHT_ONDIVIDER: UINT = 0x0004; +pub const HHT_ONDIVOPEN: UINT = 0x0008; +pub const HHT_ONFILTER: UINT = 0x0010; +pub const HHT_ONFILTERBUTTON: UINT = 0x0020; +pub const HHT_ABOVE: UINT = 0x0100; +pub const HHT_BELOW: UINT = 0x0200; +pub const HHT_TORIGHT: UINT = 0x0400; +pub const HHT_TOLEFT: UINT = 0x0800; +pub const HHT_ONITEMSTATEICON: UINT = 0x1000; +pub const HHT_ONDROPDOWN: UINT = 0x2000; +pub const HHT_ONOVERFLOW: UINT = 0x4000; +STRUCT!{struct HDHITTESTINFO { + pt: POINT, + flags: UINT, + iItem: c_int, +}} +pub type LPHDHITTESTINFO = *mut HDHITTESTINFO; +pub type HD_HITTESTINFO = HDHITTESTINFO; +pub const HDSIL_NORMAL: WPARAM = 0; +pub const HDSIL_STATE: WPARAM = 1; +pub const HDM_HITTEST: UINT = HDM_FIRST + 6; +pub const HDM_GETITEMRECT: UINT = HDM_FIRST + 7; +pub const HDM_SETIMAGELIST: UINT = HDM_FIRST + 8; +pub const HDM_GETIMAGELIST: UINT = HDM_FIRST + 9; +pub const HDM_ORDERTOINDEX: UINT = HDM_FIRST + 15; +pub const HDM_CREATEDRAGIMAGE: UINT = HDM_FIRST + 16; +pub const HDM_GETORDERARRAY: UINT = HDM_FIRST + 17; +pub const HDM_SETORDERARRAY: UINT = HDM_FIRST + 18; +pub const HDM_SETHOTDIVIDER: UINT = HDM_FIRST + 19; +pub const HDM_SETBITMAPMARGIN: UINT = HDM_FIRST + 20; +pub const HDM_GETBITMAPMARGIN: UINT = HDM_FIRST + 21; +pub const HDM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const HDM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const HDM_SETFILTERCHANGETIMEOUT: UINT = HDM_FIRST + 22; +pub const HDM_EDITFILTER: UINT = HDM_FIRST + 23; +pub const HDM_CLEARFILTER: UINT = HDM_FIRST + 24; +pub const HDM_GETITEMDROPDOWNRECT: UINT = HDM_FIRST + 25; +pub const HDM_GETOVERFLOWRECT: UINT = HDM_FIRST + 26; +pub const HDM_GETFOCUSEDITEM: UINT = HDM_FIRST + 27; +pub const HDM_SETFOCUSEDITEM: UINT = HDM_FIRST + 28; +pub const HDN_ITEMCHANGINGA: UINT = HDN_FIRST - 0; +pub const HDN_ITEMCHANGINGW: UINT = HDN_FIRST - 20; +pub const HDN_ITEMCHANGEDA: UINT = HDN_FIRST - 1; +pub const HDN_ITEMCHANGEDW: UINT = HDN_FIRST - 21; +pub const HDN_ITEMCLICKA: UINT = HDN_FIRST - 2; +pub const HDN_ITEMCLICKW: UINT = HDN_FIRST - 22; +pub const HDN_ITEMDBLCLICKA: UINT = HDN_FIRST - 3; +pub const HDN_ITEMDBLCLICKW: UINT = HDN_FIRST - 23; +pub const HDN_DIVIDERDBLCLICKA: UINT = HDN_FIRST - 5; +pub const HDN_DIVIDERDBLCLICKW: UINT = HDN_FIRST - 25; +pub const HDN_BEGINTRACKA: UINT = HDN_FIRST - 6; +pub const HDN_BEGINTRACKW: UINT = HDN_FIRST - 26; +pub const HDN_ENDTRACKA: UINT = HDN_FIRST - 7; +pub const HDN_ENDTRACKW: UINT = HDN_FIRST - 27; +pub const HDN_TRACKA: UINT = HDN_FIRST - 8; +pub const HDN_TRACKW: UINT = HDN_FIRST - 28; +pub const HDN_GETDISPINFOA: UINT = HDN_FIRST - 9; +pub const HDN_GETDISPINFOW: UINT = HDN_FIRST - 29; +pub const HDN_BEGINDRAG: UINT = HDN_FIRST - 10; +pub const HDN_ENDDRAG: UINT = HDN_FIRST - 11; +pub const HDN_FILTERCHANGE: UINT = HDN_FIRST - 12; +pub const HDN_FILTERBTNCLICK: UINT = HDN_FIRST - 13; +pub const HDN_BEGINFILTEREDIT: UINT = HDN_FIRST - 14; +pub const HDN_ENDFILTEREDIT: UINT = HDN_FIRST - 15; +pub const HDN_ITEMSTATEICONCLICK: UINT = HDN_FIRST - 16; +pub const HDN_ITEMKEYDOWN: UINT = HDN_FIRST - 17; +pub const HDN_DROPDOWN: UINT = HDN_FIRST - 18; +pub const HDN_OVERFLOWCLICK: UINT = HDN_FIRST - 19; +STRUCT!{struct NMHEADERA { + hdr: NMHDR, + iItem: c_int, + iButton: c_int, + pitem: *mut HDITEMA, +}} +pub type LPNMHEADERA = *mut NMHEADERA; +pub type HD_NOTIFYA = NMHEADERA; +STRUCT!{struct NMHEADERW { + hdr: NMHDR, + iItem: c_int, + iButton: c_int, + pitem: *mut HDITEMW, +}} +pub type LPNMHEADERW = *mut NMHEADERW; +pub type HD_NOTIFYW = NMHEADERW; +STRUCT!{struct NMHDDISPINFOW { + hdr: NMHDR, + iItem: c_int, + mask: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, +}} +pub type LPNMHDDISPINFOW = *mut NMHDDISPINFOW; +STRUCT!{struct NMHDDISPINFOA { + hdr: NMHDR, + iItem: c_int, + mask: UINT, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, +}} +pub type LPNMHDDISPINFOA = *mut NMHDDISPINFOA; +STRUCT!{struct NMHDFILTERBTNCLICK { + hdr: NMHDR, + iItem: INT, + rc: RECT, +}} +pub type LPNMHDFILTERBTNCLICK = *mut NMHDFILTERBTNCLICK; +pub const TOOLBARCLASSNAME: &'static str = "ToolbarWindow32"; +#[cfg(target_arch = "x86")] +STRUCT!{struct TBBUTTON { + iBitmap: c_int, + idCommand: c_int, + fsState: BYTE, + fsStyle: BYTE, + bReserved: [BYTE; 2], + dwData: DWORD_PTR, + iString: INT_PTR, +}} +#[cfg(target_pointer_width = "64")] +STRUCT!{struct TBBUTTON { + iBitmap: c_int, + idCommand: c_int, + fsState: BYTE, + fsStyle: BYTE, + bReserved: [BYTE; 6], + dwData: DWORD_PTR, + iString: INT_PTR, +}} +pub type PTBBUTTON = *mut TBBUTTON; +pub type LPTBBUTTON = *mut TBBUTTON; +pub type LPCTBBUTTON = *const TBBUTTON; +STRUCT!{struct COLORMAP { + from: COLORREF, + to: COLORREF, +}} +pub type LPCOLORMAP = *mut COLORMAP; +extern "system" { + pub fn CreateToolbarEx( + hwnd: HWND, + ws: DWORD, + wID: UINT, + nBitmaps: c_int, + hBMInst: HINSTANCE, + wBMID: UINT_PTR, + lpButtons: LPCTBBUTTON, + iNumButtons: c_int, + dxButton: c_int, + dyButton: c_int, + dxBitmap: c_int, + dyBitmap: c_int, + uStructSize: UINT, + ) -> HWND; + pub fn CreateMappedBitmap( + hInstance: HINSTANCE, + idBitmap: INT_PTR, + wFlags: UINT, + lpColorMap: LPCOLORMAP, + iNumMaps: c_int, + ) -> HBITMAP; +} +pub const CMB_MASKED: UINT = 0x02; +pub const TBSTATE_CHECKED: BYTE = 0x01; +pub const TBSTATE_PRESSED: BYTE = 0x02; +pub const TBSTATE_ENABLED: BYTE = 0x04; +pub const TBSTATE_HIDDEN: BYTE = 0x08; +pub const TBSTATE_INDETERMINATE: BYTE = 0x10; +pub const TBSTATE_WRAP: BYTE = 0x20; +pub const TBSTATE_ELLIPSES: BYTE = 0x40; +pub const TBSTATE_MARKED: BYTE = 0x80; +pub const TBSTYLE_BUTTON: DWORD = 0x0000; +pub const TBSTYLE_SEP: DWORD = 0x0001; +pub const TBSTYLE_CHECK: DWORD = 0x0002; +pub const TBSTYLE_GROUP: DWORD = 0x0004; +pub const TBSTYLE_CHECKGROUP: DWORD = TBSTYLE_GROUP | TBSTYLE_CHECK; +pub const TBSTYLE_DROPDOWN: DWORD = 0x0008; +pub const TBSTYLE_AUTOSIZE: DWORD = 0x0010; +pub const TBSTYLE_NOPREFIX: DWORD = 0x0020; +pub const TBSTYLE_TOOLTIPS: DWORD = 0x0100; +pub const TBSTYLE_WRAPABLE: DWORD = 0x0200; +pub const TBSTYLE_ALTDRAG: DWORD = 0x0400; +pub const TBSTYLE_FLAT: DWORD = 0x0800; +pub const TBSTYLE_LIST: DWORD = 0x1000; +pub const TBSTYLE_CUSTOMERASE: DWORD = 0x2000; +pub const TBSTYLE_REGISTERDROP: DWORD = 0x4000; +pub const TBSTYLE_TRANSPARENT: DWORD = 0x8000; +pub const TBSTYLE_EX_DRAWDDARROWS: DWORD = 0x00000001; +pub const BTNS_BUTTON: DWORD = TBSTYLE_BUTTON; +pub const BTNS_SEP: DWORD = TBSTYLE_SEP; +pub const BTNS_CHECK: DWORD = TBSTYLE_CHECK; +pub const BTNS_GROUP: DWORD = TBSTYLE_GROUP; +pub const BTNS_CHECKGROUP: DWORD = TBSTYLE_CHECKGROUP; +pub const BTNS_DROPDOWN: DWORD = TBSTYLE_DROPDOWN; +pub const BTNS_AUTOSIZE: DWORD = TBSTYLE_AUTOSIZE; +pub const BTNS_NOPREFIX: DWORD = TBSTYLE_NOPREFIX; +pub const BTNS_SHOWTEXT: DWORD = 0x0040; +pub const BTNS_WHOLEDROPDOWN: DWORD = 0x0080; +pub const TBSTYLE_EX_MIXEDBUTTONS: DWORD = 0x00000008; +pub const TBSTYLE_EX_HIDECLIPPEDBUTTONS: DWORD = 0x00000010; +pub const TBSTYLE_EX_MULTICOLUMN: DWORD = 0x00000002; +pub const TBSTYLE_EX_VERTICAL: DWORD = 0x00000004; +pub const TBSTYLE_EX_DOUBLEBUFFER: DWORD = 0x00000080; +STRUCT!{struct NMTBCUSTOMDRAW { + nmcd: NMCUSTOMDRAW, + hbrMonoDither: HBRUSH, + hbrLines: HBRUSH, + hpenLines: HPEN, + clrText: COLORREF, + clrMark: COLORREF, + clrTextHighlight: COLORREF, + clrBtnFace: COLORREF, + clrBtnHighlight: COLORREF, + clrHighlightHotTrack: COLORREF, + rcText: RECT, + nStringBkMode: c_int, + nHLStringBkMode: c_int, + iListGap: c_int, +}} +pub type LPNMTBCUSTOMDRAW = *mut NMTBCUSTOMDRAW; +pub const TBCDRF_NOEDGES: LRESULT = 0x00010000; +pub const TBCDRF_HILITEHOTTRACK: LRESULT = 0x00020000; +pub const TBCDRF_NOOFFSET: LRESULT = 0x00040000; +pub const TBCDRF_NOMARK: LRESULT = 0x00080000; +pub const TBCDRF_NOETCHEDEFFECT: LRESULT = 0x00100000; +pub const TBCDRF_BLENDICON: LRESULT = 0x00200000; +pub const TBCDRF_NOBACKGROUND: LRESULT = 0x00400000; +pub const TBCDRF_USECDCOLORS: LRESULT = 0x00800000; +pub const TB_ENABLEBUTTON: UINT = WM_USER + 1; +pub const TB_CHECKBUTTON: UINT = WM_USER + 2; +pub const TB_PRESSBUTTON: UINT = WM_USER + 3; +pub const TB_HIDEBUTTON: UINT = WM_USER + 4; +pub const TB_INDETERMINATE: UINT = WM_USER + 5; +pub const TB_MARKBUTTON: UINT = WM_USER + 6; +pub const TB_ISBUTTONENABLED: UINT = WM_USER + 9; +pub const TB_ISBUTTONCHECKED: UINT = WM_USER + 10; +pub const TB_ISBUTTONPRESSED: UINT = WM_USER + 11; +pub const TB_ISBUTTONHIDDEN: UINT = WM_USER + 12; +pub const TB_ISBUTTONINDETERMINATE: UINT = WM_USER + 13; +pub const TB_ISBUTTONHIGHLIGHTED: UINT = WM_USER + 14; +pub const TB_SETSTATE: UINT = WM_USER + 17; +pub const TB_GETSTATE: UINT = WM_USER + 18; +pub const TB_ADDBITMAP: UINT = WM_USER + 19; +STRUCT!{struct TBADDBITMAP { + hInst: HINSTANCE, + nID: UINT_PTR, +}} +pub type LPTBADDBITMAP = *mut TBADDBITMAP; +pub const HINST_COMMCTRL: HINSTANCE = -1isize as HINSTANCE; +pub const IDB_STD_SMALL_COLOR: WPARAM = 0; +pub const IDB_STD_LARGE_COLOR: WPARAM = 1; +pub const IDB_VIEW_SMALL_COLOR: WPARAM = 4; +pub const IDB_VIEW_LARGE_COLOR: WPARAM = 5; +pub const IDB_HIST_SMALL_COLOR: WPARAM = 8; +pub const IDB_HIST_LARGE_COLOR: WPARAM = 9; +pub const IDB_HIST_NORMAL: WPARAM = 12; +pub const IDB_HIST_HOT: WPARAM = 13; +pub const IDB_HIST_DISABLED: WPARAM = 14; +pub const IDB_HIST_PRESSED: WPARAM = 15; +pub const STD_CUT: c_int = 0; +pub const STD_COPY: c_int = 1; +pub const STD_PASTE: c_int = 2; +pub const STD_UNDO: c_int = 3; +pub const STD_REDOW: c_int = 4; +pub const STD_DELETE: c_int = 5; +pub const STD_FILENEW: c_int = 6; +pub const STD_FILEOPEN: c_int = 7; +pub const STD_FILESAVE: c_int = 8; +pub const STD_PRINTPRE: c_int = 9; +pub const STD_PROPERTIES: c_int = 10; +pub const STD_HELP: c_int = 11; +pub const STD_FIND: c_int = 12; +pub const STD_REPLACE: c_int = 13; +pub const STD_PRINT: c_int = 14; +pub const VIEW_LARGEICONS: c_int = 0; +pub const VIEW_SMALLICONS: c_int = 1; +pub const VIEW_LIST: c_int = 2; +pub const VIEW_DETAILS: c_int = 3; +pub const VIEW_SORTNAME: c_int = 4; +pub const VIEW_SORTSIZE: c_int = 5; +pub const VIEW_SORTDATE: c_int = 6; +pub const VIEW_SORTTYPE: c_int = 7; +pub const VIEW_PARENTFOLDER: c_int = 8; +pub const VIEW_NETCONNECT: c_int = 9; +pub const VIEW_NETDISCONNECT: c_int = 10; +pub const VIEW_NEWFOLDER: c_int = 11; +pub const VIEW_VIEWMENU: c_int = 12; +pub const HIST_BACK: c_int = 0; +pub const HIST_FORWARD: c_int = 1; +pub const HIST_FAVORITES: c_int = 2; +pub const HIST_ADDTOFAVORITES: c_int = 3; +pub const HIST_VIEWTREE: c_int = 4; +pub const TB_ADDBUTTONSA: UINT = WM_USER + 20; +pub const TB_INSERTBUTTONA: UINT = WM_USER + 21; +pub const TB_DELETEBUTTON: UINT = WM_USER + 22; +pub const TB_GETBUTTON: UINT = WM_USER + 23; +pub const TB_BUTTONCOUNT: UINT = WM_USER + 24; +pub const TB_COMMANDTOINDEX: UINT = WM_USER + 25; +STRUCT!{struct TBSAVEPARAMSA { + hkr: HKEY, + pszSubKey: LPCSTR, + pszValueName: LPCSTR, +}} +pub type LPTBSAVEPARAMSA = *mut TBSAVEPARAMSA; +STRUCT!{struct TBSAVEPARAMSW { + hkr: HKEY, + pszSubKey: LPCWSTR, + pszValueName: LPCWSTR, +}} +pub type LPTBSAVEPARAMSW = *mut TBSAVEPARAMSW; +pub const TB_SAVERESTOREA: UINT = WM_USER + 26; +pub const TB_SAVERESTOREW: UINT = WM_USER + 76; +pub const TB_CUSTOMIZE: UINT = WM_USER + 27; +pub const TB_ADDSTRINGA: UINT = WM_USER + 28; +pub const TB_ADDSTRINGW: UINT = WM_USER + 77; +pub const TB_GETITEMRECT: UINT = WM_USER + 29; +pub const TB_BUTTONSTRUCTSIZE: UINT = WM_USER + 30; +pub const TB_SETBUTTONSIZE: UINT = WM_USER + 31; +pub const TB_SETBITMAPSIZE: UINT = WM_USER + 32; +pub const TB_AUTOSIZE: UINT = WM_USER + 33; +pub const TB_GETTOOLTIPS: UINT = WM_USER + 35; +pub const TB_SETTOOLTIPS: UINT = WM_USER + 36; +pub const TB_SETPARENT: UINT = WM_USER + 37; +pub const TB_SETROWS: UINT = WM_USER + 39; +pub const TB_GETROWS: UINT = WM_USER + 40; +pub const TB_SETCMDID: UINT = WM_USER + 42; +pub const TB_CHANGEBITMAP: UINT = WM_USER + 43; +pub const TB_GETBITMAP: UINT = WM_USER + 44; +pub const TB_GETBUTTONTEXTA: UINT = WM_USER + 45; +pub const TB_GETBUTTONTEXTW: UINT = WM_USER + 75; +pub const TB_REPLACEBITMAP: UINT = WM_USER + 46; +pub const TB_SETINDENT: UINT = WM_USER + 47; +pub const TB_SETIMAGELIST: UINT = WM_USER + 48; +pub const TB_GETIMAGELIST: UINT = WM_USER + 49; +pub const TB_LOADIMAGES: UINT = WM_USER + 50; +pub const TB_GETRECT: UINT = WM_USER + 51; +pub const TB_SETHOTIMAGELIST: UINT = WM_USER + 52; +pub const TB_GETHOTIMAGELIST: UINT = WM_USER + 53; +pub const TB_SETDISABLEDIMAGELIST: UINT = WM_USER + 54; +pub const TB_GETDISABLEDIMAGELIST: UINT = WM_USER + 55; +pub const TB_SETSTYLE: UINT = WM_USER + 56; +pub const TB_GETSTYLE: UINT = WM_USER + 57; +pub const TB_GETBUTTONSIZE: UINT = WM_USER + 58; +pub const TB_SETBUTTONWIDTH: UINT = WM_USER + 59; +pub const TB_SETMAXTEXTROWS: UINT = WM_USER + 60; +pub const TB_GETTEXTROWS: UINT = WM_USER + 61; +pub const TB_GETOBJECT: UINT = WM_USER + 62; +pub const TB_GETHOTITEM: UINT = WM_USER + 71; +pub const TB_SETHOTITEM: UINT = WM_USER + 72; +pub const TB_SETANCHORHIGHLIGHT: UINT = WM_USER + 73; +pub const TB_GETANCHORHIGHLIGHT: UINT = WM_USER + 74; +pub const TB_MAPACCELERATORA: UINT = WM_USER + 78; +STRUCT!{struct TBINSERTMARK { + iButton: c_int, + dwFlags: DWORD, +}} +pub type LPTBINSERTMARK = *mut TBINSERTMARK; +pub const TBIMHT_AFTER: DWORD = 0x00000001; +pub const TBIMHT_BACKGROUND: DWORD = 0x00000002; +pub const TB_GETINSERTMARK: UINT = WM_USER + 79; +pub const TB_SETINSERTMARK: UINT = WM_USER + 80; +pub const TB_INSERTMARKHITTEST: UINT = WM_USER + 81; +pub const TB_MOVEBUTTON: UINT = WM_USER + 82; +pub const TB_GETMAXSIZE: UINT = WM_USER + 83; +pub const TB_SETEXTENDEDSTYLE: UINT = WM_USER + 84; +pub const TB_GETEXTENDEDSTYLE: UINT = WM_USER + 85; +pub const TB_GETPADDING: UINT = WM_USER + 86; +pub const TB_SETPADDING: UINT = WM_USER + 87; +pub const TB_SETINSERTMARKCOLOR: UINT = WM_USER + 88; +pub const TB_GETINSERTMARKCOLOR: UINT = WM_USER + 89; +pub const TB_SETCOLORSCHEME: UINT = CCM_SETCOLORSCHEME; +pub const TB_GETCOLORSCHEME: UINT = CCM_GETCOLORSCHEME; +pub const TB_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const TB_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const TB_MAPACCELERATORW: UINT = WM_USER + 90; +STRUCT!{struct TBREPLACEBITMAP { + hInstOld: HINSTANCE, + nIDOld: UINT_PTR, + hInstNew: HINSTANCE, + nIDNew: UINT_PTR, + nButtons: c_int, +}} +pub type LPTBREPLACEBITMAP = *mut TBREPLACEBITMAP; +pub const TBBF_LARGE: DWORD = 0x0001; +pub const TB_GETBITMAPFLAGS: UINT = WM_USER + 41; +pub const TBIF_IMAGE: DWORD = 0x00000001; +pub const TBIF_TEXT: DWORD = 0x00000002; +pub const TBIF_STATE: DWORD = 0x00000004; +pub const TBIF_STYLE: DWORD = 0x00000008; +pub const TBIF_LPARAM: DWORD = 0x00000010; +pub const TBIF_COMMAND: DWORD = 0x00000020; +pub const TBIF_SIZE: DWORD = 0x00000040; +pub const TBIF_BYINDEX: DWORD = 0x80000000; +STRUCT!{struct TBBUTTONINFOA { + cbSize: UINT, + dwMask: DWORD, + idCommand: c_int, + iImage: c_int, + fsState: BYTE, + fsStyle: BYTE, + cx: WORD, + lParam: DWORD_PTR, + pszText: LPSTR, + cchText: c_int, +}} +pub type LPTBBUTTONINFOA = *mut TBBUTTONINFOA; +STRUCT!{struct TBBUTTONINFOW { + cbSize: UINT, + dwMask: DWORD, + idCommand: c_int, + iImage: c_int, + fsState: BYTE, + fsStyle: BYTE, + cx: WORD, + lParam: DWORD_PTR, + pszText: LPWSTR, + cchText: c_int, +}} +pub type LPTBBUTTONINFOW = *mut TBBUTTONINFOW; +pub const TB_GETBUTTONINFOW: UINT = WM_USER + 63; +pub const TB_SETBUTTONINFOW: UINT = WM_USER + 64; +pub const TB_GETBUTTONINFOA: UINT = WM_USER + 65; +pub const TB_SETBUTTONINFOA: UINT = WM_USER + 66; +pub const TB_INSERTBUTTONW: UINT = WM_USER + 67; +pub const TB_ADDBUTTONSW: UINT = WM_USER + 68; +pub const TB_HITTEST: UINT = WM_USER + 69; +pub const TB_SETDRAWTEXTFLAGS: UINT = WM_USER + 70; +pub const TB_GETSTRINGW: UINT = WM_USER + 91; +pub const TB_GETSTRINGA: UINT = WM_USER + 92; +pub const TB_SETBOUNDINGSIZE: UINT = WM_USER + 93; +pub const TB_SETHOTITEM2: UINT = WM_USER + 94; +pub const TB_HASACCELERATOR: UINT = WM_USER + 95; +pub const TB_SETLISTGAP: UINT = WM_USER + 96; +pub const TB_GETIMAGELISTCOUNT: UINT = WM_USER + 98; +pub const TB_GETIDEALSIZE: UINT = WM_USER + 99; +pub const TBMF_PAD: DWORD = 0x00000001; +pub const TBMF_BARPAD: DWORD = 0x00000002; +pub const TBMF_BUTTONSPACING: DWORD = 0x00000004; +STRUCT!{struct TBMETRICS { + cbSize: UINT, + dwMask: DWORD, + cxPad: c_int, + cyPad: c_int, + cxBarPad: c_int, + cyBarPad: c_int, + cxButtonSpacing: c_int, + cyButtonSpacing: c_int, +}} +pub type LPTBMETRICS = *mut TBMETRICS; +pub const TB_GETMETRICS: UINT = WM_USER + 101; +pub const TB_SETMETRICS: UINT = WM_USER + 102; +pub const TB_GETITEMDROPDOWNRECT: UINT = WM_USER + 103; +pub const TB_SETPRESSEDIMAGELIST: UINT = WM_USER + 104; +pub const TB_GETPRESSEDIMAGELIST: UINT = WM_USER + 105; +pub const TB_SETWINDOWTHEME: UINT = CCM_SETWINDOWTHEME; +pub const TBN_GETBUTTONINFOA: UINT = TBN_FIRST - 0; +pub const TBN_BEGINDRAG: UINT = TBN_FIRST - 1; +pub const TBN_ENDDRAG: UINT = TBN_FIRST - 2; +pub const TBN_BEGINADJUST: UINT = TBN_FIRST - 3; +pub const TBN_ENDADJUST: UINT = TBN_FIRST - 4; +pub const TBN_RESET: UINT = TBN_FIRST - 5; +pub const TBN_QUERYINSERT: UINT = TBN_FIRST - 6; +pub const TBN_QUERYDELETE: UINT = TBN_FIRST - 7; +pub const TBN_TOOLBARCHANGE: UINT = TBN_FIRST - 8; +pub const TBN_CUSTHELP: UINT = TBN_FIRST - 9; +pub const TBN_DROPDOWN: UINT = TBN_FIRST - 10; +pub const TBN_GETOBJECT: UINT = TBN_FIRST - 12; +STRUCT!{struct NMTBHOTITEM { + hdr: NMHDR, + idOld: c_int, + idNew: c_int, + dwFlags: DWORD, +}} +pub type LPNMTBHOTITEM = *mut NMTBHOTITEM; +pub const HICF_OTHER: DWORD = 0x00000000; +pub const HICF_MOUSE: DWORD = 0x00000001; +pub const HICF_ARROWKEYS: DWORD = 0x00000002; +pub const HICF_ACCELERATOR: DWORD = 0x00000004; +pub const HICF_DUPACCEL: DWORD = 0x00000008; +pub const HICF_ENTERING: DWORD = 0x00000010; +pub const HICF_LEAVING: DWORD = 0x00000020; +pub const HICF_RESELECT: DWORD = 0x00000040; +pub const HICF_LMOUSE: DWORD = 0x00000080; +pub const HICF_TOGGLEDROPDOWN: DWORD = 0x00000100; +pub const TBN_HOTITEMCHANGE: UINT = TBN_FIRST - 13; +pub const TBN_DRAGOUT: UINT = TBN_FIRST - 14; +pub const TBN_DELETINGBUTTON: UINT = TBN_FIRST - 15; +pub const TBN_GETDISPINFOA: UINT = TBN_FIRST - 16; +pub const TBN_GETDISPINFOW: UINT = TBN_FIRST - 17; +pub const TBN_GETINFOTIPA: UINT = TBN_FIRST - 18; +pub const TBN_GETINFOTIPW: UINT = TBN_FIRST - 19; +pub const TBN_GETBUTTONINFOW: UINT = TBN_FIRST - 20; +pub const TBN_RESTORE: UINT = TBN_FIRST - 21; +pub const TBN_SAVE: UINT = TBN_FIRST - 22; +pub const TBN_INITCUSTOMIZE: UINT = TBN_FIRST - 23; +pub const TBNRF_HIDEHELP: LRESULT = 0x00000001; +pub const TBNRF_ENDCUSTOMIZE: LRESULT = 0x00000002; +pub const TBN_WRAPHOTITEM: UINT = TBN_FIRST - 24; +pub const TBN_DUPACCELERATOR: UINT = TBN_FIRST - 25; +pub const TBN_WRAPACCELERATOR: UINT = TBN_FIRST - 26; +pub const TBN_DRAGOVER: UINT = TBN_FIRST - 27; +pub const TBN_MAPACCELERATOR: UINT = TBN_FIRST - 28; +STRUCT!{struct NMTBSAVE { + hdr: NMHDR, + pData: *mut DWORD, + pCurrent: *mut DWORD, + cbData: UINT, + iItem: c_int, + cButtons: c_int, + tbButton: TBBUTTON, +}} +pub type LPNMTBSAVE = *mut NMTBSAVE; +STRUCT!{struct NMTBRESTORE { + hdr: NMHDR, + pData: *mut DWORD, + pCurrent: *mut DWORD, + cbData: UINT, + iItem: c_int, + cButtons: c_int, + cbBytesPerRecord: c_int, + tbButton: TBBUTTON, +}} +pub type LPNMTBRESTORE = *mut NMTBRESTORE; +STRUCT!{struct NMTBGETINFOTIPA { + hdr: NMHDR, + pszText: LPSTR, + cchTextMax: c_int, + iItem: c_int, + lParal: LPARAM, +}} +pub type LPNMTBGETINFOTIPA = *mut NMTBGETINFOTIPA; +STRUCT!{struct NMTBGETINFOTIPW { + hdr: NMHDR, + pszText: LPWSTR, + cchTextMax: c_int, + iItem: c_int, + lParal: LPARAM, +}} +pub type LPNMTBGETINFOTIPW = *mut NMTBGETINFOTIPW; +pub const TBNF_IMAGE: DWORD = 0x00000001; +pub const TBNF_TEXT: DWORD = 0x00000002; +pub const TBNF_DI_SETITEM: DWORD = 0x10000000; +STRUCT!{struct NMTBDISPINFOA { + hdr: NMHDR, + dwMask: DWORD, + idCommand: c_int, + lParam: DWORD_PTR, + iImage: c_int, + pszText: LPSTR, + cchText: c_int, +}} +pub type LPNMTBDISPINFOA = *mut NMTBDISPINFOA; +STRUCT!{struct NMTBDISPINFOW { + hdr: NMHDR, + dwMask: DWORD, + idCommand: c_int, + lParam: DWORD_PTR, + iImage: c_int, + pszText: LPWSTR, + cchText: c_int, +}} +pub type LPNMTBDISPINFOW = *mut NMTBDISPINFOW; +pub const TBDDRET_DEFAULT: LRESULT = 0; +pub const TBDDRET_NODEFAULT: LRESULT = 1; +pub const TBDDRET_TREATPRESSED: LRESULT = 2; +pub type TBNOTIFYA = NMTOOLBARA; +pub type TBNOTIFYW = NMTOOLBARW; +pub type LPTBNOTIFYA = LPNMTOOLBARA; +pub type LPTBNOTIFYW = LPNMTOOLBARW; +STRUCT!{struct NMTOOLBARA { + hdr: NMHDR, + iItem: c_int, + tbButton: TBBUTTON, + cchText: c_int, + pszText: LPSTR, + rcButton: RECT, +}} +pub type LPNMTOOLBARA = *mut NMTOOLBARA; +STRUCT!{struct NMTOOLBARW { + hdr: NMHDR, + iItem: c_int, + tbButton: TBBUTTON, + cchText: c_int, + pszText: LPWSTR, + rcButton: RECT, +}} +pub type LPNMTOOLBARW = *mut NMTOOLBARW; +pub const REBARCLASSNAME: &'static str = "ReBarWindow32"; +pub const RBIM_IMAGELIST: UINT = 0x00000001; +pub const RBS_TOOLTIPS: DWORD = 0x00000100; +pub const RBS_VARHEIGHT: DWORD = 0x00000200; +pub const RBS_BANDBORDERS: DWORD = 0x00000400; +pub const RBS_FIXEDORDER: DWORD = 0x00000800; +pub const RBS_REGISTERDROP: DWORD = 0x00001000; +pub const RBS_AUTOSIZE: DWORD = 0x00002000; +pub const RBS_VERTICALGRIPPER: DWORD = 0x00004000; +pub const RBS_DBLCLKTOGGLE: DWORD = 0x00008000; +STRUCT!{struct REBARINFO { + cbSize: UINT, + fMask: UINT, + himl: HIMAGELIST, +}} +pub type LPREBARINFO = *mut REBARINFO; +pub const RBBS_BREAK: UINT = 0x00000001; +pub const RBBS_FIXEDSIZE: UINT = 0x00000002; +pub const RBBS_CHILDEDGE: UINT = 0x00000004; +pub const RBBS_HIDDEN: UINT = 0x00000008; +pub const RBBS_NOVERT: UINT = 0x00000010; +pub const RBBS_FIXEDBMP: UINT = 0x00000020; +pub const RBBS_VARIABLEHEIGHT: UINT = 0x00000040; +pub const RBBS_GRIPPERALWAYS: UINT = 0x00000080; +pub const RBBS_NOGRIPPER: UINT = 0x00000100; +pub const RBBS_USECHEVRON: UINT = 0x00000200; +pub const RBBS_HIDETITLE: UINT = 0x00000400; +pub const RBBS_TOPALIGN: UINT = 0x00000800; +pub const RBBIM_STYLE: UINT = 0x00000001; +pub const RBBIM_COLORS: UINT = 0x00000002; +pub const RBBIM_TEXT: UINT = 0x00000004; +pub const RBBIM_IMAGE: UINT = 0x00000008; +pub const RBBIM_CHILD: UINT = 0x00000010; +pub const RBBIM_CHILDSIZE: UINT = 0x00000020; +pub const RBBIM_SIZE: UINT = 0x00000040; +pub const RBBIM_BACKGROUND: UINT = 0x00000080; +pub const RBBIM_ID: UINT = 0x00000100; +pub const RBBIM_IDEALSIZE: UINT = 0x00000200; +pub const RBBIM_LPARAM: UINT = 0x00000400; +pub const RBBIM_HEADERSIZE: UINT = 0x00000800; +pub const RBBIM_CHEVRONLOCATION: UINT = 0x00001000; +pub const RBBIM_CHEVRONSTATE: UINT = 0x00002000; +STRUCT!{struct REBARBANDINFOA { + cbSize: UINT, + fMask: UINT, + fStyle: UINT, + clrFore: COLORREF, + clrBack: COLORREF, + lpText: LPSTR, + cch: UINT, + iImage: c_int, + hwndChild: HWND, + cxMinChild: UINT, + cyMinChild: UINT, + cx: UINT, + hbmBack: HBITMAP, + wID: UINT, + cyChild: UINT, + cyMaxChild: UINT, + cyIntegral: UINT, + cxIdeal: UINT, + lParam: LPARAM, + cxHeader: UINT, + rcChevronLocation: RECT, + uChevronState: UINT, +}} +pub type LPREBARBANDINFOA = *mut REBARBANDINFOA; +pub type LPCREBARBANDINFOA = *const REBARBANDINFOA; +STRUCT!{struct REBARBANDINFOW { + cbSize: UINT, + fMask: UINT, + fStyle: UINT, + clrFore: COLORREF, + clrBack: COLORREF, + lpText: LPWSTR, + cch: UINT, + iImage: c_int, + hwndChild: HWND, + cxMinChild: UINT, + cyMinChild: UINT, + cx: UINT, + hbmBack: HBITMAP, + wID: UINT, + cyChild: UINT, + cyMaxChild: UINT, + cyIntegral: UINT, + cxIdeal: UINT, + lParam: LPARAM, + cxHeader: UINT, + rcChevronLocation: RECT, + uChevronState: UINT, +}} +pub type LPREBARBANDINFOW = *mut REBARBANDINFOW; +pub type LPCREBARBANDINFOW = *const REBARBANDINFOW; +pub const RB_INSERTBANDA: UINT = WM_USER + 1; +pub const RB_DELETEBAND: UINT = WM_USER + 2; +pub const RB_GETBARINFO: UINT = WM_USER + 3; +pub const RB_SETBARINFO: UINT = WM_USER + 4; +pub const RB_SETBANDINFOA: UINT = WM_USER + 6; +pub const RB_SETPARENT: UINT = WM_USER + 7; +pub const RB_HITTEST: UINT = WM_USER + 8; +pub const RB_GETRECT: UINT = WM_USER + 9; +pub const RB_INSERTBANDW: UINT = WM_USER + 10; +pub const RB_SETBANDINFOW: UINT = WM_USER + 11; +pub const RB_GETBANDCOUNT: UINT = WM_USER + 12; +pub const RB_GETROWCOUNT: UINT = WM_USER + 13; +pub const RB_GETROWHEIGHT: UINT = WM_USER + 14; +pub const RB_IDTOINDEX: UINT = WM_USER + 16; +pub const RB_GETTOOLTIPS: UINT = WM_USER + 17; +pub const RB_SETTOOLTIPS: UINT = WM_USER + 18; +pub const RB_SETBKCOLOR: UINT = WM_USER + 19; +pub const RB_GETBKCOLOR: UINT = WM_USER + 20; +pub const RB_SETTEXTCOLOR: UINT = WM_USER + 21; +pub const RB_GETTEXTCOLOR: UINT = WM_USER + 22; +pub const RBSTR_CHANGERECT: WPARAM = 0x0001; +pub const RB_SIZETORECT: UINT = WM_USER + 23; +pub const RB_SETCOLORSCHEME: UINT = CCM_SETCOLORSCHEME; +pub const RB_GETCOLORSCHEME: UINT = CCM_GETCOLORSCHEME; +pub const RB_BEGINDRAG: UINT = WM_USER + 24; +pub const RB_ENDDRAG: UINT = WM_USER + 25; +pub const RB_DRAGMOVE: UINT = WM_USER + 26; +pub const RB_GETBARHEIGHT: UINT = WM_USER + 27; +pub const RB_GETBANDINFOW: UINT = WM_USER + 28; +pub const RB_GETBANDINFOA: UINT = WM_USER + 29; +pub const RB_MINIMIZEBAND: UINT = WM_USER + 30; +pub const RB_MAXIMIZEBAND: UINT = WM_USER + 31; +pub const RB_GETDROPTARGET: UINT = CCM_GETDROPTARGET; +pub const RB_GETBANDBORDERS: UINT = WM_USER + 34; +pub const RB_SHOWBAND: UINT = WM_USER + 35; +pub const RB_SETPALETTE: UINT = WM_USER + 37; +pub const RB_GETPALETTE: UINT = WM_USER + 38; +pub const RB_MOVEBAND: UINT = WM_USER + 39; +pub const RB_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const RB_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const RB_GETBANDMARGINS: UINT = WM_USER + 40; +pub const RB_SETWINDOWTHEME: UINT = CCM_SETWINDOWTHEME; +pub const RB_SETEXTENDEDSTYLE: UINT = WM_USER + 41; +pub const RB_GETEXTENDEDSTYLE: UINT = WM_USER + 42; +pub const RB_PUSHCHEVRON: UINT = WM_USER + 43; +pub const RB_SETBANDWIDTH: UINT = WM_USER + 44; +pub const RBN_HEIGHTCHANGE: UINT = RBN_FIRST - 0; +pub const RBN_GETOBJECT: UINT = RBN_FIRST - 1; +pub const RBN_LAYOUTCHANGED: UINT = RBN_FIRST - 2; +pub const RBN_AUTOSIZE: UINT = RBN_FIRST - 3; +pub const RBN_BEGINDRAG: UINT = RBN_FIRST - 4; +pub const RBN_ENDDRAG: UINT = RBN_FIRST - 5; +pub const RBN_DELETINGBAND: UINT = RBN_FIRST - 6; +pub const RBN_DELETEDBAND: UINT = RBN_FIRST - 7; +pub const RBN_CHILDSIZE: UINT = RBN_FIRST - 8; +pub const RBN_CHEVRONPUSHED: UINT = RBN_FIRST - 10; +pub const RBN_SPLITTERDRAG: UINT = RBN_FIRST - 11; +pub const RBN_MINMAX: UINT = RBN_FIRST - 21; +pub const RBN_AUTOBREAK: UINT = RBN_FIRST - 22; +STRUCT!{struct NMREBARCHILDSIZE { + hdr: NMHDR, + uBand: UINT, + wID: UINT, + rcChild: RECT, + rcBand: RECT, +}} +pub type LPNMREBARCHILDSIZE = *mut NMREBARCHILDSIZE; +STRUCT!{struct NMREBAR { + hdr: NMHDR, + dwMask: DWORD, + uBand: UINT, + fStyle: UINT, + wID: UINT, + lParam: LPARAM, +}} +pub type LPNMREBAR = *mut NMREBAR; +pub const RBNM_ID: DWORD = 0x00000001; +pub const RBNM_STYLE: DWORD = 0x00000002; +pub const RBNM_LPARAM: DWORD = 0x00000004; +STRUCT!{struct NMRBAUTOSIZE { + hdr: NMHDR, + fChanged: BOOL, + rcTarget: RECT, + rcActual: RECT, +}} +pub type LPNMRBAUTOSIZE = *mut NMRBAUTOSIZE; +STRUCT!{struct NMREBARCHEVRON { + hdr: NMHDR, + uBand: UINT, + wID: UINT, + lParam: LPARAM, + rc: RECT, + lParamNM: LPARAM, +}} +pub type LPNMREBARCHEVRON = *mut NMREBARCHEVRON; +STRUCT!{struct NMREBARSPLITTER { + hdr: NMHDR, + rcSizing: RECT, +}} +pub type LPNMREBARSPLITTER = *mut NMREBARSPLITTER; +pub const RBAB_AUTOSIZE: UINT = 0x0001; +pub const RBAB_ADDBAND: UINT = 0x0002; +STRUCT!{struct NMREBARAUTOBREAK { + hdr: NMHDR, + uBand: UINT, + wID: UINT, + lParam: LPARAM, + uMsg: UINT, + fStyleCurrent: UINT, + fAutoBreak: UINT, +}} +pub type LPNMREBARAUTOBREAK = *mut NMREBARAUTOBREAK; +pub const RBHT_NOWHERE: UINT = 0x0001; +pub const RBHT_CAPTION: UINT = 0x0002; +pub const RBHT_CLIENT: UINT = 0x0003; +pub const RBHT_GRABBER: UINT = 0x0004; +pub const RBHT_CHEVRON: UINT = 0x0008; +pub const RBHT_SPLITTER: UINT = 0x0010; +STRUCT!{struct RBHITTESTINFO { + pt: POINT, + flags: UINT, + iBand: c_int, +}} +pub type LPRBHITTESTINFO = *mut RBHITTESTINFO; +pub const TOOLTIPS_CLASS: &'static str = "tooltips_class32"; +pub type LPTOOLINFOA = LPTTTOOLINFOA; +pub type LPTOOLINFOW = LPTTTOOLINFOW; +pub type TOOLINFOA = TTTOOLINFOA; +pub type TOOLINFOW = TTTOOLINFOW; +STRUCT!{struct TTTOOLINFOA { + cbSize: UINT, + uFlags: UINT, + hwnd: HWND, + uId: UINT_PTR, + rect: RECT, + hinst: HINSTANCE, + lpszText: LPSTR, + lParam: LPARAM, + lpReserved: *mut c_void, +}} +pub type PTTTOOLINFOA = *mut TTTOOLINFOA; +pub type LPTTTOOLINFOA = *mut TTTOOLINFOA; +STRUCT!{struct TTTOOLINFOW { + cbSize: UINT, + uFlags: UINT, + hwnd: HWND, + uId: UINT_PTR, + rect: RECT, + hinst: HINSTANCE, + lpszText: LPSTR, + lParam: LPARAM, + lpReserved: *mut c_void, +}} +pub type PTTTOOLINFOW = *mut TTTOOLINFOW; +pub type LPTTTOOLINFOW = *mut TTTOOLINFOW; +pub const TTS_ALWAYSTIP: DWORD = 0x01; +pub const TTS_NOPREFIX: DWORD = 0x02; +pub const TTS_NOANIMATE: DWORD = 0x10; +pub const TTS_NOFADE: DWORD = 0x20; +pub const TTS_BALLOON: DWORD = 0x40; +pub const TTS_CLOSE: DWORD = 0x80; +pub const TTS_USEVISUALSTYLE: DWORD = 0x100; +pub const TTF_IDISHWND: UINT = 0x0001; +pub const TTF_CENTERTIP: UINT = 0x0002; +pub const TTF_RTLREADING: UINT = 0x0004; +pub const TTF_SUBCLASS: UINT = 0x0010; +pub const TTF_TRACK: UINT = 0x0020; +pub const TTF_ABSOLUTE: UINT = 0x0080; +pub const TTF_TRANSPARENT: UINT = 0x0100; +pub const TTF_PARSELINKS: UINT = 0x1000; +pub const TTF_DI_SETITEM: UINT = 0x8000; +pub const TTDT_AUTOMATIC: WPARAM = 0; +pub const TTDT_RESHOW: WPARAM = 1; +pub const TTDT_AUTOPOP: WPARAM = 2; +pub const TTDT_INITIAL: WPARAM = 3; +pub const TTI_NONE: WPARAM = 0; +pub const TTI_INFO: WPARAM = 1; +pub const TTI_WARNING: WPARAM = 2; +pub const TTI_ERROR: WPARAM = 3; +pub const TTI_INFO_LARGE: WPARAM = 4; +pub const TTI_WARNING_LARGE: WPARAM = 5; +pub const TTI_ERROR_LARGE: WPARAM = 6; +pub const TTM_ACTIVATE: UINT = WM_USER + 1; +pub const TTM_SETDELAYTIME: UINT = WM_USER + 3; +pub const TTM_ADDTOOLA: UINT = WM_USER + 4; +pub const TTM_ADDTOOLW: UINT = WM_USER + 50; +pub const TTM_DELTOOLA: UINT = WM_USER + 5; +pub const TTM_DELTOOLW: UINT = WM_USER + 51; +pub const TTM_NEWTOOLRECTA: UINT = WM_USER + 6; +pub const TTM_NEWTOOLRECTW: UINT = WM_USER + 52; +pub const TTM_RELAYEVENT: UINT = WM_USER + 7; +pub const TTM_GETTOOLINFOA: UINT = WM_USER + 8; +pub const TTM_GETTOOLINFOW: UINT = WM_USER + 53; +pub const TTM_SETTOOLINFOA: UINT = WM_USER + 9; +pub const TTM_SETTOOLINFOW: UINT = WM_USER + 54; +pub const TTM_HITTESTA: UINT = WM_USER + 10; +pub const TTM_HITTESTW: UINT = WM_USER + 55; +pub const TTM_GETTEXTA: UINT = WM_USER + 11; +pub const TTM_GETTEXTW: UINT = WM_USER + 56; +pub const TTM_UPDATETIPTEXTA: UINT = WM_USER + 12; +pub const TTM_UPDATETIPTEXTW: UINT = WM_USER + 57; +pub const TTM_GETTOOLCOUNT: UINT = WM_USER + 13; +pub const TTM_ENUMTOOLSA: UINT = WM_USER + 14; +pub const TTM_ENUMTOOLSW: UINT = WM_USER + 58; +pub const TTM_GETCURRENTTOOLA: UINT = WM_USER + 15; +pub const TTM_GETCURRENTTOOLW: UINT = WM_USER + 59; +pub const TTM_WINDOWFROMPOINT: UINT = WM_USER + 16; +pub const TTM_TRACKACTIVATE: UINT = WM_USER + 17; +pub const TTM_TRACKPOSITION: UINT = WM_USER + 18; +pub const TTM_SETTIPBKCOLOR: UINT = WM_USER + 19; +pub const TTM_SETTIPTEXTCOLOR: UINT = WM_USER + 20; +pub const TTM_GETDELAYTIME: UINT = WM_USER + 21; +pub const TTM_GETTIPBKCOLOR: UINT = WM_USER + 22; +pub const TTM_GETTIPTEXTCOLOR: UINT = WM_USER + 23; +pub const TTM_SETMAXTIPWIDTH: UINT = WM_USER + 24; +pub const TTM_GETMAXTIPWIDTH: UINT = WM_USER + 25; +pub const TTM_SETMARGIN: UINT = WM_USER + 26; +pub const TTM_GETMARGIN: UINT = WM_USER + 27; +pub const TTM_POP: UINT = WM_USER + 28; +pub const TTM_UPDATE: UINT = WM_USER + 29; +pub const TTM_GETBUBBLESIZE: UINT = WM_USER + 30; +pub const TTM_ADJUSTRECT: UINT = WM_USER + 31; +pub const TTM_SETTITLEA: UINT = WM_USER + 32; +pub const TTM_SETTITLEW: UINT = WM_USER + 33; +pub const TTM_POPUP: UINT = WM_USER + 34; +pub const TTM_GETTITLE: UINT = WM_USER + 35; +STRUCT!{struct TTGETTITLE { + dwSize: DWORD, + uTitleBitmap: UINT, + cch: UINT, + pszTitle: *mut WCHAR, +}} +pub type LPTTGETTITLE = *mut TTGETTITLE; +pub const TTM_SETWINDOWTHEME: UINT = CCM_SETWINDOWTHEME; +pub type LPHITTESTINFOW = LPTTHITTESTINFOW; +pub type LPHITTESTINFOA = LPTTHITTESTINFOA; +STRUCT!{struct TTHITTESTINFOA { + hwnd: HWND, + pt: POINT, + ti: TTTOOLINFOA, +}} +pub type LPTTHITTESTINFOA = *mut TTHITTESTINFOA; +STRUCT!{struct TTHITTESTINFOW { + hwnd: HWND, + pt: POINT, + ti: TTTOOLINFOW, +}} +pub type LPTTHITTESTINFOW = *mut TTHITTESTINFOW; +pub const TTN_GETDISPINFOA: UINT = TTN_FIRST - 0; +pub const TTN_GETDISPINFOW: UINT = TTN_FIRST - 10; +pub const TTN_SHOW: UINT = TTN_FIRST - 1; +pub const TTN_POP: UINT = TTN_FIRST - 2; +pub const TTN_LINKCLICK: UINT = TTN_FIRST - 3; +pub const TTN_NEEDTEXTA: UINT = TTN_GETDISPINFOA; +pub const TTN_NEEDTEXTW: UINT = TTN_GETDISPINFOW; +pub type TOOLTIPTEXTW = NMTTDISPINFOW; +pub type TOOLTIPTEXTA = NMTTDISPINFOA; +pub type LPTOOLTIPTEXTA = LPNMTTDISPINFOA; +pub type LPTOOLTIPTEXTW = LPNMTTDISPINFOW; +STRUCT!{struct NMTTDISPINFOA { + hdr: NMHDR, + lpszText: LPSTR, + szText: [c_char; 80], + hinst: HINSTANCE, + uFlags: UINT, + lParam: LPARAM, +}} +pub type LPNMTTDISPINFOA = *mut NMTTDISPINFOA; +STRUCT!{struct NMTTDISPINFOW { + hdr: NMHDR, + lpszText: LPWSTR, + szText: [WCHAR; 80], + hinst: HINSTANCE, + uFlags: UINT, + lParam: LPARAM, +}} +pub type LPNMTTDISPINFOW = *mut NMTTDISPINFOW; +pub const SBARS_SIZEGRIP: DWORD = 0x0100; +pub const SBARS_TOOLTIPS: DWORD = 0x0800; +pub const SBT_TOOLTIPS: DWORD = 0x0800; +extern "system" { + pub fn DrawStatusTextA( + hDC: HDC, + lprc: LPCRECT, + pszText: LPCSTR, + uFlags: UINT, + ); + pub fn DrawStatusTextW( + hDC: HDC, + lprc: LPCRECT, + pszText: LPCWSTR, + uFlags: UINT, + ); + pub fn CreateStatusWindowA( + style: LONG, + lpszText: LPCSTR, + hwndParent: HWND, + wID: UINT, + ) -> HWND; + pub fn CreateStatusWindowW( + style: LONG, + lpszText: LPCWSTR, + hwndParent: HWND, + wID: UINT, + ) -> HWND; +} +pub const STATUSCLASSNAME: &'static str = "msctls_statusbar32"; +pub const SB_SETTEXTA: UINT = WM_USER + 1; +pub const SB_SETTEXTW: UINT = WM_USER + 11; +pub const SB_GETTEXTA: UINT = WM_USER + 2; +pub const SB_GETTEXTW: UINT = WM_USER + 13; +pub const SB_GETTEXTLENGTHA: UINT = WM_USER + 3; +pub const SB_GETTEXTLENGTHW: UINT = WM_USER + 12; +pub const SB_SETPARTS: UINT = WM_USER + 4; +pub const SB_GETPARTS: UINT = WM_USER + 6; +pub const SB_GETBORDERS: UINT = WM_USER + 7; +pub const SB_SETMINHEIGHT: UINT = WM_USER + 8; +pub const SB_SIMPLE: UINT = WM_USER + 9; +pub const SB_GETRECT: UINT = WM_USER + 10; +pub const SB_ISSIMPLE: UINT = WM_USER + 14; +pub const SB_SETICON: UINT = WM_USER + 15; +pub const SB_SETTIPTEXTA: UINT = WM_USER + 16; +pub const SB_SETTIPTEXTW: UINT = WM_USER + 17; +pub const SB_GETTIPTEXTA: UINT = WM_USER + 18; +pub const SB_GETTIPTEXTW: UINT = WM_USER + 19; +pub const SB_GETICON: UINT = WM_USER + 20; +pub const SB_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const SB_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const SBT_OWNERDRAW: WPARAM = 0x1000; +pub const SBT_NOBORDERS: WPARAM = 0x0100; +pub const SBT_POPOUT: WPARAM = 0x0200; +pub const SBT_RTLREADING: WPARAM = 0x0400; +pub const SBT_NOTABPARSING: WPARAM = 0x0800; +pub const SB_SETBKCOLOR: UINT = CCM_SETBKCOLOR; +pub const SBN_SIMPLEMODECHANGE: UINT = SBN_FIRST - 0; +pub const SB_SIMPLEID: WPARAM = 0x00ff; +extern "system" { + pub fn MenuHelp( + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + hMainMenu: HMENU, + hInst: HINSTANCE, + hwndStatus: HWND, + lpwIDs: *mut UINT, + ); + pub fn ShowHideMenuCtl( + hWnd: HWND, + uFlags: UINT_PTR, + lpInfo: LPINT, + ) -> BOOL; + pub fn GetEffectiveClientRect( + hWnd: HWND, + lprc: LPRECT, + lpInfo: *const INT, + ); +} +pub const TRACKBAR_CLASS: &'static str = "msctls_trackbar32"; +pub const TBS_AUTOTICKS: DWORD = 0x0001; +pub const TBS_VERT: DWORD = 0x0002; +pub const TBS_HORZ: DWORD = 0x0000; +pub const TBS_TOP: DWORD = 0x0004; +pub const TBS_BOTTOM: DWORD = 0x0000; +pub const TBS_LEFT: DWORD = 0x0004; +pub const TBS_RIGHT: DWORD = 0x0000; +pub const TBS_BOTH: DWORD = 0x0008; +pub const TBS_NOTICKS: DWORD = 0x0010; +pub const TBS_ENABLESELRANGE: DWORD = 0x0020; +pub const TBS_FIXEDLENGTH: DWORD = 0x0040; +pub const TBS_NOTHUMB: DWORD = 0x0080; +pub const TBS_TOOLTIPS: DWORD = 0x0100; +pub const TBS_REVERSED: DWORD = 0x0200; +pub const TBS_DOWNISLEFT: DWORD = 0x0400; +pub const TBS_NOTIFYBEFOREMOVE: DWORD = 0x0800; +pub const TBS_TRANSPARENTBKGND: DWORD = 0x1000; +pub const TBM_GETPOS: UINT = WM_USER; +pub const TBM_GETRANGEMIN: UINT = WM_USER + 1; +pub const TBM_GETRANGEMAX: UINT = WM_USER + 2; +pub const TBM_GETTIC: UINT = WM_USER + 3; +pub const TBM_SETTIC: UINT = WM_USER + 4; +pub const TBM_SETPOS: UINT = WM_USER + 5; +pub const TBM_SETRANGE: UINT = WM_USER + 6; +pub const TBM_SETRANGEMIN: UINT = WM_USER + 7; +pub const TBM_SETRANGEMAX: UINT = WM_USER + 8; +pub const TBM_CLEARTICS: UINT = WM_USER + 9; +pub const TBM_SETSEL: UINT = WM_USER + 10; +pub const TBM_SETSELSTART: UINT = WM_USER + 11; +pub const TBM_SETSELEND: UINT = WM_USER + 12; +pub const TBM_GETPTICS: UINT = WM_USER + 14; +pub const TBM_GETTICPOS: UINT = WM_USER + 15; +pub const TBM_GETNUMTICS: UINT = WM_USER + 16; +pub const TBM_GETSELSTART: UINT = WM_USER + 17; +pub const TBM_GETSELEND: UINT = WM_USER + 18; +pub const TBM_CLEARSEL: UINT = WM_USER + 19; +pub const TBM_SETTICFREQ: UINT = WM_USER + 20; +pub const TBM_SETPAGESIZE: UINT = WM_USER + 21; +pub const TBM_GETPAGESIZE: UINT = WM_USER + 22; +pub const TBM_SETLINESIZE: UINT = WM_USER + 23; +pub const TBM_GETLINESIZE: UINT = WM_USER + 24; +pub const TBM_GETTHUMBRECT: UINT = WM_USER + 25; +pub const TBM_GETCHANNELRECT: UINT = WM_USER + 26; +pub const TBM_SETTHUMBLENGTH: UINT = WM_USER + 27; +pub const TBM_GETTHUMBLENGTH: UINT = WM_USER + 28; +pub const TBM_SETTOOLTIPS: UINT = WM_USER + 29; +pub const TBM_GETTOOLTIPS: UINT = WM_USER + 30; +pub const TBM_SETTIPSIDE: UINT = WM_USER + 31; +pub const TBTS_TOP: WPARAM = 0; +pub const TBTS_LEFT: WPARAM = 1; +pub const TBTS_BOTTOM: WPARAM = 2; +pub const TBTS_RIGHT: WPARAM = 3; +pub const TBM_SETBUDDY: UINT = WM_USER + 32; +pub const TBM_GETBUDDY: UINT = WM_USER + 33; +pub const TBM_SETPOSNOTIFY: UINT = WM_USER + 34; +pub const TBM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const TBM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const TB_LINEUP: WPARAM = 0; +pub const TB_LINEDOWN: WPARAM = 1; +pub const TB_PAGEUP: WPARAM = 2; +pub const TB_PAGEDOWN: WPARAM = 3; +pub const TB_THUMBPOSITION: WPARAM = 4; +pub const TB_THUMBTRACK: WPARAM = 5; +pub const TB_TOP: WPARAM = 6; +pub const TB_BOTTOM: WPARAM = 7; +pub const TB_ENDTRACK: WPARAM = 8; +pub const TBCD_TICS: DWORD_PTR = 0x0001; +pub const TBCD_THUMB: DWORD_PTR = 0x0001; +pub const TBCD_CHANNEL: DWORD_PTR = 0x0001; +pub const TRBN_THUMBPOSCHANGING: UINT = TRBN_FIRST - 1; +STRUCT!{struct NMTRBTHUMBPOSCHANGING { + hdr: NMHDR, + dwPos: DWORD, + nReason: c_int, +}} +STRUCT!{struct DRAGLISTINFO { + uNotification: UINT, + hWnd: HWND, + ptCursor: POINT, +}} +pub type LPDRAGLISTINFO = *mut DRAGLISTINFO; +pub const DL_BEGINDRAG: UINT = WM_USER + 133; +pub const DL_DRAGGING: UINT = WM_USER + 134; +pub const DL_DROPPED: UINT = WM_USER + 135; +pub const DL_CANCELDRAG: UINT = WM_USER + 136; +pub const DL_CURSORSET: UINT = 0; +pub const DL_STOPCURSOR: UINT = 1; +pub const DL_COPYCURSOR: UINT = 2; +pub const DL_MOVECURSOR: UINT = 3; +pub const DRAGLISTMSGSTRING: &'static str = "commctrl_DragListMsg"; +extern "system" { + pub fn MakeDragList( + hLB: HWND, + ) -> BOOL; + pub fn DrawInsert( + handParent: HWND, + hLB: HWND, + nItem: c_int, + ); + pub fn LBItemFromPt( + hLB: HWND, + pt: POINT, + bAutoScroll: BOOL, + ) -> c_int; +} +pub const UPDOWN_CLASS: &'static str = "msctls_updown32"; +STRUCT!{struct UDACCEL { + nSec: UINT, + nInc: UINT, +}} +pub type LPUDACCEL = *mut UDACCEL; +pub const UD_MAXVAL: c_short = 0x7fff; +pub const UD_MINVAL: c_short = 0 - UD_MAXVAL; +pub const UDS_WRAP: DWORD = 0x0001; +pub const UDS_SETBUDDYINT: DWORD = 0x0002; +pub const UDS_ALIGNRIGHT: DWORD = 0x0004; +pub const UDS_ALIGNLEFT: DWORD = 0x0008; +pub const UDS_AUTOBUDDY: DWORD = 0x0010; +pub const UDS_ARROWKEYS: DWORD = 0x0020; +pub const UDS_HORZ: DWORD = 0x0040; +pub const UDS_NOTHOUSANDS: DWORD = 0x0080; +pub const UDS_HOTTRACK: DWORD = 0x0100; +pub const UDM_SETRANGE: UINT = WM_USER + 101; +pub const UDM_GETRANGE: UINT = WM_USER + 102; +pub const UDM_SETPOS: UINT = WM_USER + 103; +pub const UDM_GETPOS: UINT = WM_USER + 104; +pub const UDM_SETBUDDY: UINT = WM_USER + 105; +pub const UDM_GETBUDDY: UINT = WM_USER + 106; +pub const UDM_SETACCEL: UINT = WM_USER + 107; +pub const UDM_GETACCEL: UINT = WM_USER + 108; +pub const UDM_SETBASE: UINT = WM_USER + 109; +pub const UDM_GETBASE: UINT = WM_USER + 110; +pub const UDM_SETRANGE32: UINT = WM_USER + 111; +pub const UDM_GETRANGE32: UINT = WM_USER + 112; +pub const UDM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const UDM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const UDM_SETPOS32: UINT = WM_USER + 113; +pub const UDM_GETPOS32: UINT = WM_USER + 114; +extern "system" { + pub fn CreateUpDownControl( + dwStyle: DWORD, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + hParent: HWND, + nID: c_int, + hInst: HINSTANCE, + nBuddy: HWND, + nUpper: c_int, + nLower: c_int, + nPos: c_int, + ) -> HWND; +} +pub type NM_UPDOWN = NMUPDOWN; +pub type LPNM_UPDOWN = LPNMUPDOWN; +STRUCT!{struct NMUPDOWN { + hdr: NMHDR, + iPos: c_int, + iDelta: c_int, +}} +pub type LPNMUPDOWN = *mut NMUPDOWN; +pub const UDN_DELTAPOS: UINT = UDN_FIRST - 1; +pub const PROGRESS_CLASS: &'static str = "msctls_progress32"; +pub const PBS_SMOOTH: DWORD = 0x01; +pub const PBS_VERTICAL: DWORD = 0x04; +pub const PBM_SETRANGE: UINT = WM_USER + 1; +pub const PBM_SETPOS: UINT = WM_USER + 2; +pub const PBM_DELTAPOS: UINT = WM_USER + 3; +pub const PBM_SETSTEP: UINT = WM_USER + 4; +pub const PBM_STEPIT: UINT = WM_USER + 5; +pub const PBM_SETRANGE32: UINT = WM_USER + 6; +STRUCT!{struct PBRANGE { + iLow: c_int, + iHigh: c_int, +}} +pub type LPPBRANGE = *mut PBRANGE; +pub const PBM_GETRANGE: UINT = WM_USER + 7; +pub const PBM_GETPOS: UINT = WM_USER + 8; +pub const PBM_SETBARCOLOR: UINT = WM_USER + 9; +pub const PBM_SETBKCOLOR: UINT = CCM_SETBKCOLOR; +pub const PBS_MARQUEE: DWORD = 0x08; +pub const PBM_SETMARQUEE: UINT = WM_USER + 10; +pub const PBS_SMOOTHREVERSE: DWORD = 0x10; +pub const PBM_GETSTEP: UINT = WM_USER + 13; +pub const PBM_GETBKCOLOR: UINT = WM_USER + 14; +pub const PBM_GETBARCOLOR: UINT = WM_USER + 15; +pub const PBM_SETSTATE: UINT = WM_USER + 16; +pub const PBM_GETSTATE: UINT = WM_USER + 17; +pub const PBST_NORMAL: c_int = 0x0001; +pub const PBST_ERROR: c_int = 0x0002; +pub const PBST_PAUSED: c_int = 0x0003; +pub const HOTKEYF_SHIFT: BYTE = 0x01; +pub const HOTKEYF_CONTROL: BYTE = 0x02; +pub const HOTKEYF_ALT: BYTE = 0x04; +pub const HOTKEYF_EXT: BYTE = 0x08; +pub const HKCOMB_NONE: WPARAM = 0x0001; +pub const HKCOMB_S: WPARAM = 0x0002; +pub const HKCOMB_C: WPARAM = 0x0004; +pub const HKCOMB_A: WPARAM = 0x0008; +pub const HKCOMB_SC: WPARAM = 0x0010; +pub const HKCOMB_SA: WPARAM = 0x0020; +pub const HKCOMB_CA: WPARAM = 0x0040; +pub const HKCOMB_SCA: WPARAM = 0x0080; +pub const HKM_SETHOTKEY: UINT = WM_USER + 1; +pub const HKM_GETHOTKEY: UINT = WM_USER + 2; +pub const HKM_SETRULES: UINT = WM_USER + 3; +pub const HOTKEY_CLASS: &'static str = "msctls_hotkey32"; +pub const CCS_TOP: DWORD = 0x00000001; +pub const CCS_NOMOVEY: DWORD = 0x00000002; +pub const CCS_BOTTOM: DWORD = 0x00000003; +pub const CCS_NORESIZE: DWORD = 0x00000004; +pub const CCS_NOPARENTALIGN: DWORD = 0x00000008; +pub const CCS_ADJUSTABLE: DWORD = 0x00000020; +pub const CCS_NODIVIDER: DWORD = 0x00000040; +pub const CCS_VERT: DWORD = 0x00000080; +pub const CCS_LEFT: DWORD = CCS_VERT | CCS_TOP; +pub const CCS_RIGHT: DWORD = CCS_VERT | CCS_BOTTOM; +pub const CCS_NOMOVEX: DWORD = CCS_VERT | CCS_NOMOVEY; +pub const INVALID_LINK_INDEX: c_int = -1; +pub const MAX_LINKID_TEXT: usize = 48; +pub const L_MAX_URL_LENGTH: usize = 2048 + 32 + 4; +pub const WC_LINK: &'static str = "SysLink"; +pub const LWS_TRANSPARENT: DWORD = 0x0001; +pub const LWS_IGNORERETURN: DWORD = 0x0002; +pub const LWS_NOPREFIX: DWORD = 0x0004; +pub const LWS_USEVISUALSTYLE: DWORD = 0x0008; +pub const LWS_USECUSTOMTEXT: DWORD = 0x0010; +pub const LWS_RIGHT: DWORD = 0x0020; +pub const LIF_ITEMINDEX: UINT = 0x00000001; +pub const LIF_STATE: UINT = 0x00000002; +pub const LIF_ITEMID: UINT = 0x00000004; +pub const LIF_URL: UINT = 0x00000008; +pub const LIS_FOCUSED: UINT = 0x00000001; +pub const LIS_ENABLED: UINT = 0x00000002; +pub const LIS_VISITED: UINT = 0x00000004; +pub const LIS_HOTTRACK: UINT = 0x00000008; +pub const LIS_DEFAULTCOLORS: UINT = 0x00000010; +STRUCT!{struct LITEM { + mask: UINT, + iLink: c_int, + state: UINT, + stateMask: UINT, + szID: [WCHAR; MAX_LINKID_TEXT], + szUrl: [WCHAR; L_MAX_URL_LENGTH], +}} +pub type PLITEM = *mut LITEM; +STRUCT!{struct LHITTESTINFO { + pt: POINT, + item: LITEM, +}} +pub type PLHITTESTINFO = *mut LHITTESTINFO; +STRUCT!{struct NMLINK { + hdr: NMHDR, + item: LITEM, +}} +pub type PNMLINK = *mut NMLINK; +pub const LM_HITTEST: UINT = WM_USER + 0x300; +pub const LM_GETIDEALHEIGHT: UINT = WM_USER + 0x301; +pub const LM_SETITEM: UINT = WM_USER + 0x302; +pub const LM_GETITEM: UINT = WM_USER + 0x303; +pub const LM_GETIDEALSIZE: UINT = LM_GETIDEALHEIGHT; +pub const WC_LISTVIEW: &'static str = "SysListView32"; +pub const LVS_ICON: DWORD = 0x0000; +pub const LVS_REPORT: DWORD = 0x0001; +pub const LVS_SMALLICON: DWORD = 0x0002; +pub const LVS_LIST: DWORD = 0x0003; +pub const LVS_TYPEMASK: DWORD = 0x0003; +pub const LVS_SINGLESEL: DWORD = 0x0004; +pub const LVS_SHOWSELALWAYS: DWORD = 0x0008; +pub const LVS_SORTASCENDING: DWORD = 0x0010; +pub const LVS_SORTDESCENDING: DWORD = 0x0020; +pub const LVS_SHAREIMAGELISTS: DWORD = 0x0040; +pub const LVS_NOLABELWRAP: DWORD = 0x0080; +pub const LVS_AUTOARRANGE: DWORD = 0x0100; +pub const LVS_EDITLABELS: DWORD = 0x0200; +pub const LVS_OWNERDATA: DWORD = 0x1000; +pub const LVS_NOSCROLL: DWORD = 0x2000; +pub const LVS_TYPESTYLEMASK: DWORD = 0xfc00; +pub const LVS_ALIGNTOP: DWORD = 0x0000; +pub const LVS_ALIGNLEFT: DWORD = 0x0800; +pub const LVS_ALIGNMASK: DWORD = 0x0c00; +pub const LVS_OWNERDRAWFIXED: DWORD = 0x0400; +pub const LVS_NOCOLUMNHEADER: DWORD = 0x4000; +pub const LVS_NOSORTHEADER: DWORD = 0x8000; +pub const LVM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const LVM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const LVM_GETBKCOLOR: UINT = LVM_FIRST + 0; +pub const LVM_SETBKCOLOR: UINT = LVM_FIRST + 1; +pub const LVM_GETIMAGELIST: UINT = LVM_FIRST + 2; +pub const LVSIL_NORMAL: c_int = 0; +pub const LVSIL_SMALL: c_int = 1; +pub const LVSIL_STATE: c_int = 2; +pub const LVSIL_GROUPHEADER: c_int = 3; +pub const LVM_SETIMAGELIST: UINT = LVM_FIRST + 3; +pub const LVM_GETITEMCOUNT: UINT = LVM_FIRST + 4; +pub const LVIF_TEXT: UINT = 0x00000001; +pub const LVIF_IMAGE: UINT = 0x00000002; +pub const LVIF_PARAM: UINT = 0x00000004; +pub const LVIF_STATE: UINT = 0x00000008; +pub const LVIF_INDENT: UINT = 0x00000010; +pub const LVIF_NORECOMPUTE: UINT = 0x00000800; +pub const LVIF_GROUPID: UINT = 0x00000100; +pub const LVIF_COLUMNS: UINT = 0x00000200; +pub const LVIF_COLFMT: UINT = 0x00010000; +pub const LVIS_FOCUSED: UINT = 0x0001; +pub const LVIS_SELECTED: UINT = 0x0002; +pub const LVIS_CUT: UINT = 0x0004; +pub const LVIS_DROPHILITED: UINT = 0x0008; +pub const LVIS_GLOW: UINT = 0x0010; +pub const LVIS_ACTIVATING: UINT = 0x0020; +pub const LVIS_OVERLAYMASK: UINT = 0x0F00; +pub const LVIS_STATEIMAGEMASK: UINT = 0xF000; +#[inline] +pub fn INDEXTOSTATEIMAGEMASK(i: UINT) -> UINT { + i << 12 +} +pub const I_INDENTCALLBACK: c_int = -1; +pub type LV_ITEMA = LVITEMA; +pub type LV_ITEMW = LVITEMW; +pub const I_GROUPIDCALLBACK: c_int = -1; +pub const I_GROUPIDNONE: c_int = -2; +STRUCT!{struct LVITEMA { + mask: UINT, + iItem: c_int, + iSubItem: c_int, + state: UINT, + stateMask: UINT, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, + iIndent: c_int, + iGroupId: c_int, + cColumns: UINT, + puColumns: PUINT, + piColFmt: *mut c_int, + iGroup: c_int, +}} +pub type LPLVITEMA = *mut LVITEMA; +STRUCT!{struct LVITEMW { + mask: UINT, + iItem: c_int, + iSubItem: c_int, + state: UINT, + stateMask: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, + iIndent: c_int, + iGroupId: c_int, + cColumns: UINT, + puColumns: PUINT, + piColFmt: *mut c_int, + iGroup: c_int, +}} +pub type LPLVITEMW = *mut LVITEMW; +pub const LPSTR_TEXTCALLBACKW: LPWSTR = -1isize as LPWSTR; +pub const LPSTR_TEXTCALLBACKA: LPSTR = -1isize as LPSTR; +pub const I_IMAGECALLBACK: c_int = -1; +pub const I_IMAGENONE: c_int = -2; +pub const I_COLUMNSCALLBACK: UINT = -1i32 as u32; +pub const LVM_GETITEMA: UINT = LVM_FIRST + 5; +pub const LVM_GETITEMW: UINT = LVM_FIRST + 75; +pub const LVM_SETITEMA: UINT = LVM_FIRST + 6; +pub const LVM_SETITEMW: UINT = LVM_FIRST + 76; +pub const LVM_INSERTITEMA: UINT = LVM_FIRST + 7; +pub const LVM_INSERTITEMW: UINT = LVM_FIRST + 77; +pub const LVM_DELETEITEM: UINT = LVM_FIRST + 8; +pub const LVM_DELETEALLITEMS: UINT = LVM_FIRST + 9; +pub const LVM_GETCALLBACKMASK: UINT = LVM_FIRST + 10; +pub const LVM_SETCALLBACKMASK: UINT = LVM_FIRST + 11; +pub const LVNI_ALL: LPARAM = 0x0000; +pub const LVNI_FOCUSED: LPARAM = 0x0001; +pub const LVNI_SELECTED: LPARAM = 0x0002; +pub const LVNI_CUT: LPARAM = 0x0004; +pub const LVNI_DROPHILITED: LPARAM = 0x0008; +pub const LVNI_STATEMASK: LPARAM = LVNI_FOCUSED | LVNI_SELECTED | LVNI_CUT | LVNI_DROPHILITED; +pub const LVNI_VISIBLEORDER: LPARAM = 0x0010; +pub const LVNI_PREVIOUS: LPARAM = 0x0020; +pub const LVNI_VISIBLEONLY: LPARAM = 0x0040; +pub const LVNI_SAMEGROUPONLY: LPARAM = 0x0080; +pub const LVNI_ABOVE: LPARAM = 0x0100; +pub const LVNI_BELOW: LPARAM = 0x0200; +pub const LVNI_TOLEFT: LPARAM = 0x0400; +pub const LVNI_TORIGHT: LPARAM = 0x0800; +pub const LVNI_DIRECTIONMASK: LPARAM = LVNI_ABOVE | LVNI_BELOW | LVNI_TOLEFT | LVNI_TORIGHT; +pub const LVM_GETNEXTITEM: UINT = LVM_FIRST + 12; +pub const LVFI_PARAM: UINT = 0x0001; +pub const LVFI_STRING: UINT = 0x0002; +pub const LVFI_SUBSTRING: UINT = 0x0004; +pub const LVFI_PARTIAL: UINT = 0x0008; +pub const LVFI_WRAP: UINT = 0x0020; +pub const LVFI_NEARESTXY: UINT = 0x0040; +pub type LV_FINDINFOA = LVFINDINFOA; +pub type LV_FINDINFOW = LVFINDINFOW; +STRUCT!{struct LVFINDINFOA { + flags: UINT, + psz: LPCSTR, + lParam: LPARAM, + pt: POINT, + vkDirection: UINT, +}} +pub type LPFINDINFOA = *mut LVFINDINFOA; +STRUCT!{struct LVFINDINFOW { + flags: UINT, + psz: LPCWSTR, + lParam: LPARAM, + pt: POINT, + vkDirection: UINT, +}} +pub type LPFINDINFOW = *mut LVFINDINFOW; +pub const LVM_FINDITEMA: UINT = LVM_FIRST + 13; +pub const LVM_FINDITEMW: UINT = LVM_FIRST + 83; +pub const LVIR_BOUNDS: c_int = 0; +pub const LVIR_ICON: c_int = 1; +pub const LVIR_LABEL: c_int = 2; +pub const LVIR_SELECTBOUNDS: c_int = 3; +pub const LVM_GETITEMRECT: UINT = LVM_FIRST + 14; +pub const LVM_SETITEMPOSITION: UINT = LVM_FIRST + 15; +pub const LVM_GETITEMPOSITION: UINT = LVM_FIRST + 16; +pub const LVM_GETSTRINGWIDTHA: UINT = LVM_FIRST + 17; +pub const LVM_GETSTRINGWIDTHW: UINT = LVM_FIRST + 87; +pub const LVHT_NOWHERE: UINT = 0x00000001; +pub const LVHT_ONITEMICON: UINT = 0x00000002; +pub const LVHT_ONITEMLABEL: UINT = 0x00000004; +pub const LVHT_ONITEMSTATEICON: UINT = 0x00000008; +pub const LVHT_ONITEM: UINT = LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON; +pub const LVHT_ABOVE: UINT = 0x00000008; +pub const LVHT_BELOW: UINT = 0x00000010; +pub const LVHT_TORIGHT: UINT = 0x00000020; +pub const LVHT_TOLEFT: UINT = 0x00000040; +pub const LVHT_EX_GROUP_HEADER: UINT = 0x10000000; +pub const LVHT_EX_GROUP_FOOTER: UINT = 0x20000000; +pub const LVHT_EX_GROUP_COLLAPSE: UINT = 0x40000000; +pub const LVHT_EX_GROUP_BACKGROUND: UINT = 0x80000000; +pub const LVHT_EX_GROUP_STATEICON: UINT = 0x01000000; +pub const LVHT_EX_GROUP_SUBSETLINK: UINT = 0x02000000; +pub const LVHT_EX_GROUP: UINT = LVHT_EX_GROUP_BACKGROUND | LVHT_EX_GROUP_COLLAPSE + | LVHT_EX_GROUP_FOOTER | LVHT_EX_GROUP_HEADER | LVHT_EX_GROUP_STATEICON + | LVHT_EX_GROUP_SUBSETLINK; +pub const LVHT_EX_ONCONTENTS: UINT = 0x04000000; +pub const LVHT_EX_FOOTER: UINT = 0x08000000; +pub type LV_HITTESTINFO = LVHITTESTINFO; +STRUCT!{struct LVHITTESTINFO { + pt: POINT, + flags: UINT, + iItem: c_int, + iSubItem: c_int, + iGroup: c_int, +}} +pub type LPLVHITTESTINFO = *mut LVHITTESTINFO; +pub const LVM_HITTEST: UINT = LVM_FIRST + 18; +pub const LVM_ENSUREVISIBLE: UINT = LVM_FIRST + 19; +pub const LVM_SCROLL: UINT = LVM_FIRST + 20; +pub const LVM_REDRAWITEMS: UINT = LVM_FIRST + 21; +pub const LVA_DEFAULT: WPARAM = 0x0000; +pub const LVA_ALIGNLEFT: WPARAM = 0x0001; +pub const LVA_ALIGNTOP: WPARAM = 0x0002; +pub const LVA_SNAPTOGRID: WPARAM = 0x0005; +pub const LVM_ARRANGE: UINT = LVM_FIRST + 22; +pub const LVM_EDITLABELA: UINT = LVM_FIRST + 23; +pub const LVM_EDITLABELW: UINT = LVM_FIRST + 118; +pub const LVM_GETEDITCONTROL: UINT = LVM_FIRST + 24; +pub type LV_COLUMNA = LVCOLUMNA; +pub type LV_COLUMNW = LVCOLUMNW; +STRUCT!{struct LVCOLUMNA { + mask: UINT, + fmt: c_int, + cx: c_int, + pszText: LPSTR, + cchTextMax: c_int, + iSubItem: c_int, + iImage: c_int, + iOrder: c_int, + cxMin: c_int, + cxDefault: c_int, + cxIdeal: c_int, +}} +pub type LPLVCOLUMNA = *mut LVCOLUMNA; +STRUCT!{struct LVCOLUMNW { + mask: UINT, + fmt: c_int, + cx: c_int, + pszText: LPWSTR, + cchTextMax: c_int, + iSubItem: c_int, + iImage: c_int, + iOrder: c_int, + cxMin: c_int, + cxDefault: c_int, + cxIdeal: c_int, +}} +pub type LPLVCOLUMNW = *mut LVCOLUMNW; +pub const LVCF_FMT: UINT = 0x0001; +pub const LVCF_WIDTH: UINT = 0x0002; +pub const LVCF_TEXT: UINT = 0x0004; +pub const LVCF_SUBITEM: UINT = 0x0008; +pub const LVCF_IMAGE: UINT = 0x0010; +pub const LVCF_ORDER: UINT = 0x0020; +pub const LVCF_MINWIDTH: UINT = 0x0040; +pub const LVCF_DEFAULTWIDTH: UINT = 0x0080; +pub const LVCF_IDEALWIDTH: UINT = 0x0100; +pub const LVCFMT_LEFT: c_int = 0x0000; +pub const LVCFMT_RIGHT: c_int = 0x0001; +pub const LVCFMT_CENTER: c_int = 0x0002; +pub const LVCFMT_JUSTIFYMASK: c_int = 0x0003; +pub const LVCFMT_IMAGE: c_int = 0x0800; +pub const LVCFMT_BITMAP_ON_RIGHT: c_int = 0x1000; +pub const LVCFMT_COL_HAS_IMAGES: c_int = 0x8000; +pub const LVCFMT_FIXED_WIDTH: c_int = 0x00100; +pub const LVCFMT_NO_DPI_SCALE: c_int = 0x40000; +pub const LVCFMT_FIXED_RATIO: c_int = 0x80000; +pub const LVCFMT_LINE_BREAK: c_int = 0x100000; +pub const LVCFMT_FILL: c_int = 0x200000; +pub const LVCFMT_WRAP: c_int = 0x400000; +pub const LVCFMT_NO_TITLE: c_int = 0x800000; +pub const LVCFMT_TILE_PLACEMENTMASK: c_int = LVCFMT_LINE_BREAK | LVCFMT_FILL; +pub const LVCFMT_SPLITBUTTON: c_int = 0x1000000; +pub const LVM_GETCOLUMNA: UINT = LVM_FIRST + 25; +pub const LVM_GETCOLUMNW: UINT = LVM_FIRST + 95; +pub const LVM_SETCOLUMNA: UINT = LVM_FIRST + 26; +pub const LVM_SETCOLUMNW: UINT = LVM_FIRST + 96; +pub const LVM_INSERTCOLUMNA: UINT = LVM_FIRST + 27; +pub const LVM_INSERTCOLUMNW: UINT = LVM_FIRST + 97; +pub const LVM_DELETECOLUMN: UINT = LVM_FIRST + 28; +pub const LVM_GETCOLUMNWIDTH: UINT = LVM_FIRST + 29; +pub const LVSCW_AUTOSIZE: c_int = -1; +pub const LVSCW_AUTOSIZE_USEHEADER: c_int = -2; +pub const LVM_SETCOLUMNWIDTH: UINT = LVM_FIRST + 30; +pub const LVM_GETHEADER: UINT = LVM_FIRST + 31; +pub const LVM_CREATEDRAGIMAGE: UINT = LVM_FIRST + 33; +pub const LVM_GETVIEWRECT: UINT = LVM_FIRST + 34; +pub const LVM_GETTEXTCOLOR: UINT = LVM_FIRST + 35; +pub const LVM_SETTEXTCOLOR: UINT = LVM_FIRST + 36; +pub const LVM_GETTEXTBKCOLOR: UINT = LVM_FIRST + 37; +pub const LVM_SETTEXTBKCOLOR: UINT = LVM_FIRST + 38; +pub const LVM_GETTOPINDEX: UINT = LVM_FIRST + 39; +pub const LVM_GETCOUNTPERPAGE: UINT = LVM_FIRST + 40; +pub const LVM_GETORIGIN: UINT = LVM_FIRST + 41; +pub const LVM_UPDATE: UINT = LVM_FIRST + 42; +pub const LVM_SETITEMSTATE: UINT = LVM_FIRST + 43; +pub const LVM_GETITEMSTATE: UINT = LVM_FIRST + 44; +pub const LVM_GETITEMTEXTA: UINT = LVM_FIRST + 45; +pub const LVM_GETITEMTEXTW: UINT = LVM_FIRST + 115; +pub const LVM_SETITEMTEXTA: UINT = LVM_FIRST + 46; +pub const LVM_SETITEMTEXTW: UINT = LVM_FIRST + 116; +pub const LVSICF_NOINVALIDATEALL: LPARAM = 0x00000001; +pub const LVSICF_NOSCROLL: LPARAM = 0x00000002; +pub const LVM_SETITEMCOUNT: UINT = LVM_FIRST + 47; +FN!{stdcall PFNLVCOMPARE( + LPARAM, + LPARAM, + LPARAM, +) -> c_int} +pub const LVM_SORTITEMS: UINT = LVM_FIRST + 48; +pub const LVM_SETITEMPOSITION32: UINT = LVM_FIRST + 49; +pub const LVM_GETSELECTEDCOUNT: UINT = LVM_FIRST + 50; +pub const LVM_GETITEMSPACING: UINT = LVM_FIRST + 51; +pub const LVM_GETISEARCHSTRINGA: UINT = LVM_FIRST + 52; +pub const LVM_GETISEARCHSTRINGW: UINT = LVM_FIRST + 117; +pub const LVM_SETICONSPACING: UINT = LVM_FIRST + 53; +pub const LVM_SETEXTENDEDLISTVIEWSTYLE: UINT = LVM_FIRST + 54; +pub const LVM_GETEXTENDEDLISTVIEWSTYLE: UINT = LVM_FIRST + 55; +pub const LVS_EX_GRIDLINES: DWORD = 0x00000001; +pub const LVS_EX_SUBITEMIMAGES: DWORD = 0x00000002; +pub const LVS_EX_CHECKBOXES: DWORD = 0x00000004; +pub const LVS_EX_TRACKSELECT: DWORD = 0x00000008; +pub const LVS_EX_HEADERDRAGDROP: DWORD = 0x00000010; +pub const LVS_EX_FULLROWSELECT: DWORD = 0x00000020; +pub const LVS_EX_ONECLICKACTIVATE: DWORD = 0x00000040; +pub const LVS_EX_TWOCLICKACTIVATE: DWORD = 0x00000080; +pub const LVS_EX_FLATSB: DWORD = 0x00000100; +pub const LVS_EX_REGIONAL: DWORD = 0x00000200; +pub const LVS_EX_INFOTIP: DWORD = 0x00000400; +pub const LVS_EX_UNDERLINEHOT: DWORD = 0x00000800; +pub const LVS_EX_UNDERLINECOLD: DWORD = 0x00001000; +pub const LVS_EX_MULTIWORKAREAS: DWORD = 0x00002000; +pub const LVS_EX_LABELTIP: DWORD = 0x00004000; +pub const LVS_EX_BORDERSELECT: DWORD = 0x00008000; +pub const LVS_EX_DOUBLEBUFFER: DWORD = 0x00010000; +pub const LVS_EX_HIDELABELS: DWORD = 0x00020000; +pub const LVS_EX_SINGLEROW: DWORD = 0x00040000; +pub const LVS_EX_SNAPTOGRID: DWORD = 0x00080000; +pub const LVS_EX_SIMPLESELECT: DWORD = 0x00100000; +pub const LVS_EX_JUSTIFYCOLUMNS: DWORD = 0x00200000; +pub const LVS_EX_TRANSPARENTBKGND: DWORD = 0x00400000; +pub const LVS_EX_TRANSPARENTSHADOWTEXT: DWORD = 0x00800000; +pub const LVS_EX_AUTOAUTOARRANGE: DWORD = 0x01000000; +pub const LVS_EX_HEADERINALLVIEWS: DWORD = 0x02000000; +pub const LVS_EX_AUTOCHECKSELECT: DWORD = 0x08000000; +pub const LVS_EX_AUTOSIZECOLUMNS: DWORD = 0x10000000; +pub const LVS_EX_COLUMNSNAPPOINTS: DWORD = 0x40000000; +pub const LVS_EX_COLUMNOVERFLOW: DWORD = 0x80000000; +pub const LVM_GETSUBITEMRECT: UINT = LVM_FIRST + 56; +pub const LVM_SUBITEMHITTEST: UINT = LVM_FIRST + 57; +pub const LVM_SETCOLUMNORDERARRAY: UINT = LVM_FIRST + 58; +pub const LVM_GETCOLUMNORDERARRAY: UINT = LVM_FIRST + 59; +pub const LVM_SETHOTITEM: UINT = LVM_FIRST + 60; +pub const LVM_GETHOTITEM: UINT = LVM_FIRST + 61; +pub const LVM_SETHOTCURSOR: UINT = LVM_FIRST + 62; +pub const LVM_GETHOTCURSOR: UINT = LVM_FIRST + 63; +pub const LVM_APPROXIMATEVIEWRECT: UINT = LVM_FIRST + 64; +pub const LV_MAX_WORKAREAS: WPARAM = 16; +pub const LVM_SETWORKAREAS: UINT = LVM_FIRST + 65; +pub const LVM_GETWORKAREAS: UINT = LVM_FIRST + 70; +pub const LVM_GETNUMBEROFWORKAREAS: UINT = LVM_FIRST + 73; +pub const LVM_GETSELECTIONMARK: UINT = LVM_FIRST + 66; +pub const LVM_SETSELECTIONMARK: UINT = LVM_FIRST + 67; +pub const LVM_SETHOVERTIME: UINT = LVM_FIRST + 71; +pub const LVM_GETHOVERTIME: UINT = LVM_FIRST + 72; +pub const LVM_SETTOOLTIPS: UINT = LVM_FIRST + 74; +pub const LVM_GETTOOLTIPS: UINT = LVM_FIRST + 78; +pub const LVM_SORTITEMSEX: UINT = LVM_FIRST + 81; +STRUCT!{struct LVBKIMAGEA { + ulFlags: ULONG, + hbm: HBITMAP, + pszImage: LPSTR, + cchImageMax: UINT, + xOffsetPercent: c_int, + yOffsetPercent: c_int, +}} +pub type LPLVBKIMAGEA = *mut LVBKIMAGEA; +STRUCT!{struct LVBKIMAGEW { + ulFlags: ULONG, + hbm: HBITMAP, + pszImage: LPWSTR, + cchImageMax: UINT, + xOffsetPercent: c_int, + yOffsetPercent: c_int, +}} +pub type LPLVBKIMAGEW = *mut LVBKIMAGEW; +pub const LVBKIF_SOURCE_NONE: ULONG = 0x00000000; +pub const LVBKIF_SOURCE_HBITMAP: ULONG = 0x00000001; +pub const LVBKIF_SOURCE_URL: ULONG = 0x00000002; +pub const LVBKIF_SOURCE_MASK: ULONG = 0x00000003; +pub const LVBKIF_STYLE_NORMAL: ULONG = 0x00000000; +pub const LVBKIF_STYLE_TILE: ULONG = 0x00000010; +pub const LVBKIF_STYLE_MASK: ULONG = 0x00000010; +pub const LVBKIF_FLAG_TILEOFFSET: ULONG = 0x00000100; +pub const LVBKIF_TYPE_WATERMARK: ULONG = 0x10000000; +pub const LVBKIF_FLAG_ALPHABLEND: ULONG = 0x20000000; +pub const LVM_SETBKIMAGEA: UINT = LVM_FIRST + 68; +pub const LVM_SETBKIMAGEW: UINT = LVM_FIRST + 138; +pub const LVM_GETBKIMAGEA: UINT = LVM_FIRST + 69; +pub const LVM_GETBKIMAGEW: UINT = LVM_FIRST + 139; +pub const LVM_SETSELECTEDCOLUMN: UINT = LVM_FIRST + 140; +pub const LV_VIEW_ICON: DWORD = 0x0000; +pub const LV_VIEW_DETAILS: DWORD = 0x0001; +pub const LV_VIEW_SMALLICON: DWORD = 0x0002; +pub const LV_VIEW_LIST: DWORD = 0x0003; +pub const LV_VIEW_TILE: DWORD = 0x0004; +pub const LV_VIEW_MAX: DWORD = 0x0004; +pub const LVM_SETVIEW: UINT = LVM_FIRST + 142; +pub const LVM_GETVIEW: UINT = LVM_FIRST + 143; +pub const LVGF_NONE: UINT = 0x00000000; +pub const LVGF_HEADER: UINT = 0x00000001; +pub const LVGF_FOOTER: UINT = 0x00000002; +pub const LVGF_STATE: UINT = 0x00000004; +pub const LVGF_ALIGN: UINT = 0x00000008; +pub const LVGF_GROUPID: UINT = 0x00000010; +pub const LVGF_SUBTITLE: UINT = 0x00000100; +pub const LVGF_TASK: UINT = 0x00000200; +pub const LVGF_DESCRIPTIONTOP: UINT = 0x00000400; +pub const LVGF_DESCRIPTIONBOTTOM: UINT = 0x00000800; +pub const LVGF_TITLEIMAGE: UINT = 0x00001000; +pub const LVGF_EXTENDEDIMAGE: UINT = 0x00002000; +pub const LVGF_ITEMS: UINT = 0x00004000; +pub const LVGF_SUBSET: UINT = 0x00008000; +pub const LVGF_SUBSETITEMS: UINT = 0x00010000; +pub const LVGS_NORMAL: UINT = 0x00000000; +pub const LVGS_COLLAPSED: UINT = 0x00000001; +pub const LVGS_HIDDEN: UINT = 0x00000002; +pub const LVGS_NOHEADER: UINT = 0x00000004; +pub const LVGS_COLLAPSIBLE: UINT = 0x00000008; +pub const LVGS_FOCUSED: UINT = 0x00000010; +pub const LVGS_SELECTED: UINT = 0x00000020; +pub const LVGS_SUBSETED: UINT = 0x00000040; +pub const LVGS_SUBSETLINKFOCUSED: UINT = 0x00000080; +pub const LVGA_HEADER_LEFT: UINT = 0x00000001; +pub const LVGA_HEADER_CENTER: UINT = 0x00000002; +pub const LVGA_HEADER_RIGHT: UINT = 0x00000004; +pub const LVGA_FOOTER_LEFT: UINT = 0x00000008; +pub const LVGA_FOOTER_CENTER: UINT = 0x00000010; +pub const LVGA_FOOTER_RIGHT: UINT = 0x00000020; +STRUCT!{struct LVGROUP { + cbSize: UINT, + mask: UINT, + pszHeader: LPWSTR, + cchHeader: c_int, + pszFooter: LPWSTR, + cchFooter: c_int, + iGroupId: c_int, + stateMask: UINT, + state: UINT, + uAlign: UINT, + pszSubtitle: LPWSTR, + cchSubtitle: UINT, + pszTask: LPWSTR, + cchTask: UINT, + pszDescriptionTop: LPWSTR, + cchDescriptionTop: UINT, + pszDescriptionBottom: LPWSTR, + cchDescriptionBottom: UINT, + iTitleImage: c_int, + iExtendedImage: c_int, + iFirstItem: c_int, + cItems: UINT, + pszSubsetTitle: LPWSTR, + cchSubsetTitle: UINT, +}} +pub type PLVGROUP = *mut LVGROUP; +pub const LVM_INSERTGROUP: UINT = LVM_FIRST + 145; +pub const LVM_SETGROUPINFO: UINT = LVM_FIRST + 147; +pub const LVM_GETGROUPINFO: UINT = LVM_FIRST + 149; +pub const LVM_REMOVEGROUP: UINT = LVM_FIRST + 150; +pub const LVM_MOVEGROUP: UINT = LVM_FIRST + 151; +pub const LVM_GETGROUPCOUNT: UINT = LVM_FIRST + 152; +pub const LVM_GETGROUPINFOBYINDEX: UINT = LVM_FIRST + 153; +pub const LVM_MOVEITEMTOGROUP: UINT = LVM_FIRST + 154; +pub const LVGGR_GROUP: LPARAM = 0; +pub const LVGGR_HEADER: LPARAM = 1; +pub const LVGGR_LABEL: LPARAM = 2; +pub const LVGGR_SUBSETLINK: LPARAM = 3; +pub const LVM_GETGROUPRECT: UINT = LVM_FIRST + 98; +pub const LVGMF_NONE: UINT = 0x00000000; +pub const LVGMF_BORDERSIZE: UINT = 0x00000001; +pub const LVGMF_BORDERCOLOR: UINT = 0x00000002; +pub const LVGMF_TEXTCOLOR: UINT = 0x00000004; +STRUCT!{struct LVGROUPMETRICS { + cbSize: UINT, + mask: UINT, + Left: UINT, + Top: UINT, + Right: UINT, + Bottom: UINT, + crLeft: COLORREF, + crTop: COLORREF, + crRight: COLORREF, + crBottom: COLORREF, + crHeader: COLORREF, + crFooter: COLORREF, +}} +pub type PLVGROUPMETRICS = *mut LVGROUPMETRICS; +pub const LVM_SETGROUPMETRICS: UINT = LVM_FIRST + 155; +pub const LVM_GETGROUPMETRICS: UINT = LVM_FIRST + 156; +pub const LVM_ENABLEGROUPVIEW: UINT = LVM_FIRST + 157; +FN!{stdcall PFNLVGROUPCOMPARE( + c_int, + c_int, + *mut c_void, +) -> c_int} +pub const LVM_SORTGROUPS: UINT = LVM_FIRST + 158; +STRUCT!{struct LVINSERTGROUPSORTED { + pfnGroupCompare: PFNLVGROUPCOMPARE, + pvData: *mut c_void, + lvGroup: LVGROUP, +}} +pub type PLVINSERTGROUPSORTED = *mut LVINSERTGROUPSORTED; +pub const LVM_INSERTGROUPSORTED: UINT = LVM_FIRST + 159; +pub const LVM_REMOVEALLGROUPS: UINT = LVM_FIRST + 160; +pub const LVM_HASGROUP: UINT = LVM_FIRST + 161; +pub const LVM_GETGROUPSTATE: UINT = LVM_FIRST + 92; +pub const LVM_GETFOCUSEDGROUP: UINT = LVM_FIRST + 93; +pub const LVTVIF_AUTOSIZE: DWORD = 0x00000000; +pub const LVTVIF_FIXEDWIDTH: DWORD = 0x00000001; +pub const LVTVIF_FIXEDHEIGHT: DWORD = 0x00000002; +pub const LVTVIF_FIXEDSIZE: DWORD = 0x00000003; +pub const LVTVIF_EXTENDED: DWORD = 0x00000004; +pub const LVTVIM_TILESIZE: DWORD = 0x00000001; +pub const LVTVIM_COLUMNS: DWORD = 0x00000002; +pub const LVTVIM_LABELMARGIN: DWORD = 0x00000004; +STRUCT!{struct LVTILEVIEWINFO { + cbSize: UINT, + dwMask: DWORD, + dwFlags: DWORD, + sizeTile: SIZE, + cLines: c_int, + rcLabelMargin: RECT, +}} +pub type PLVTILEVIEWINFO = *mut LVTILEVIEWINFO; +STRUCT!{struct LVTILEINFO { + cbSize: UINT, + iItem: c_int, + cColumns: UINT, + puColumns: PUINT, + piColFmt: *mut c_int, +}} +pub type PLVTILEINFO = *mut LVTILEINFO; +pub const LVM_SETTILEVIEWINFO: UINT = LVM_FIRST + 162; +pub const LVM_GETTILEVIEWINFO: UINT = LVM_FIRST + 163; +pub const LVM_SETTILEINFO: UINT = LVM_FIRST + 164; +pub const LVM_GETTILEINFO: UINT = LVM_FIRST + 165; +STRUCT!{struct LVINSERTMARK { + cbSize: UINT, + dwFlags: DWORD, + iItem: c_int, + dwReserved: DWORD, +}} +pub type LPLVINSERTMARK = *mut LVINSERTMARK; +pub const LVIM_AFTER: DWORD = 0x00000001; +pub const LVM_SETINSERTMARK: UINT = LVM_FIRST + 166; +pub const LVM_GETINSERTMARK: UINT = LVM_FIRST + 167; +pub const LVM_INSERTMARKHITTEST: UINT = LVM_FIRST + 168; +pub const LVM_GETINSERTMARKRECT: UINT = LVM_FIRST + 169; +pub const LVM_SETINSERTMARKCOLOR: UINT = LVM_FIRST + 170; +pub const LVM_GETINSERTMARKCOLOR: UINT = LVM_FIRST + 171; +STRUCT!{struct LVSETINFOTIP { + cbSize: UINT, + dwFlags: DWORD, + pszText: LPWSTR, + iItem: c_int, + iSubItem: c_int, +}} +pub type PLVSETINFOTIP = *mut LVSETINFOTIP; +pub const LVM_SETINFOTIP: UINT = LVM_FIRST + 173; +pub const LVM_GETSELECTEDCOLUMN: UINT = LVM_FIRST + 174; +pub const LVM_ISGROUPVIEWENABLED: UINT = LVM_FIRST + 175; +pub const LVM_GETOUTLINECOLOR: UINT = LVM_FIRST + 176; +pub const LVM_SETOUTLINECOLOR: UINT = LVM_FIRST + 177; +pub const LVM_CANCELEDITLABEL: UINT = LVM_FIRST + 179; +pub const LVM_MAPINDEXTOID: UINT = LVM_FIRST + 180; +pub const LVM_MAPIDTOINDEX: UINT = LVM_FIRST + 181; +pub const LVM_ISITEMVISIBLE: UINT = LVM_FIRST + 182; +pub const LVM_GETEMPTYTEXT: UINT = LVM_FIRST + 204; +pub const LVM_GETFOOTERRECT: UINT = LVM_FIRST + 205; +pub const LVFF_ITEMCOUNT: UINT = 0x00000001; +STRUCT!{struct LVFOOTERINFO { + mask: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + cItems: UINT, +}} +pub type LPLVFOOTERINFO = *mut LVFOOTERINFO; +pub const LVM_GETFOOTERINFO: UINT = LVM_FIRST + 206; +pub const LVM_GETFOOTERITEMRECT: UINT = LVM_FIRST + 207; +pub const LVFIF_TEXT: UINT = 0x00000001; +pub const LVFIF_STATE: UINT = 0x00000002; +pub const LVFIS_FOCUSED: UINT = 0x0001; +STRUCT!{struct LVFOOTERITEM { + mask: UINT, + iItem: c_int, + pszText: LPWSTR, + cchTextMax: c_int, + state: UINT, + stateMask: UINT, +}} +pub type LPLVFOOTERITEM = *mut LVFOOTERITEM; +pub const LVM_GETFOOTERITEM: UINT = LVM_FIRST + 208; +STRUCT!{struct LVITEMINDEX { + iItem: c_int, + iGroup: c_int, +}} +pub type PLVITEMINDEX = *mut LVITEMINDEX; +pub const LVM_GETITEMINDEXRECT: UINT = LVM_FIRST + 209; +pub const LVM_SETITEMINDEXSTATE: UINT = LVM_FIRST + 210; +pub const LVM_GETNEXTITEMINDEX: UINT = LVM_FIRST + 211; +pub type LPNM_LISTVIEW = LPNMLISTVIEW; +pub type NM_LISTVIEW = NMLISTVIEW; +STRUCT!{struct NMLISTVIEW { + hdr: NMHDR, + iItem: c_int, + iSubItem: c_int, + uNewState: UINT, + uOldState: UINT, + uChanged: UINT, + ptAction: POINT, + lParam: LPARAM, +}} +pub type LPNMLISTVIEW = *mut NMLISTVIEW; +STRUCT!{struct NMITEMACTIVATE { + hdr: NMHDR, + iItem: c_int, + iSubItem: c_int, + uNewState: UINT, + uOldState: UINT, + uChanged: UINT, + ptAction: POINT, + lParam: LPARAM, + uKeyFlags: UINT, +}} +pub type LPNMITEMACTIVATE = *mut NMITEMACTIVATE; +pub const LVKF_ALT: UINT = 0x0001; +pub const LVKF_CONTROL: UINT = 0x0002; +pub const LVKF_SHIFT: UINT = 0x0004; +STRUCT!{struct NMLVCUSTOMDRAW { + nmcd: NMCUSTOMDRAW, + clrText: COLORREF, + clrTextBk: COLORREF, + iSubItem: c_int, + dwItemType: DWORD, + clrFace: COLORREF, + iIconEffect: c_int, + iIconPhase: c_int, + iPartId: c_int, + iStateId: c_int, + rcText: RECT, + uAlign: UINT, +}} +pub type LPNMLVCUSTOMDRAW = *mut NMLVCUSTOMDRAW; +pub const LVCDI_ITEM: DWORD = 0x00000000; +pub const LVCDI_GROUP: DWORD = 0x00000001; +pub const LVCDI_ITEMSLIST: DWORD = 0x00000002; +pub const LVCDRF_NOSELECT: LRESULT = 0x00010000; +pub const LVCDRF_NOGROUPFRAME: LRESULT = 0x00020000; +STRUCT!{struct NMLVCACHEHINT { + hdr: NMHDR, + iFrom: c_int, + iTo: c_int, +}} +pub type LPNMLVCACHEHINT = *mut NMLVCACHEHINT; +pub type LPNM_CACHEHINT = LPNMLVCACHEHINT; +pub type PNM_CACHEHINT = LPNMLVCACHEHINT; +pub type NM_CACHEHINT = NMLVCACHEHINT; +STRUCT!{struct NMLVFINDITEMA { + hdr: NMHDR, + iStart: c_int, + lvfi: LVFINDINFOA, +}} +pub type LPNMLVFINDITEMA = *mut NMLVFINDITEMA; +STRUCT!{struct NMLVFINDITEMW { + hdr: NMHDR, + iStart: c_int, + lvfi: LVFINDINFOW, +}} +pub type LPNMLVFINDITEMW = *mut NMLVFINDITEMW; +pub type PNM_FINDITEMA = LPNMLVFINDITEMA; +pub type LPNM_FINDITEMA = LPNMLVFINDITEMA; +pub type NM_FINDITEMA = NMLVFINDITEMA; +pub type PNM_FINDITEMW = LPNMLVFINDITEMW; +pub type LPNM_FINDITEMW = LPNMLVFINDITEMW; +pub type NM_FINDITEMW = NMLVFINDITEMW; +STRUCT!{struct NMLVODSTATECHANGE { + hdr: NMHDR, + iFrom: c_int, + iTo: c_int, + uNewState: UINT, + uOldState: UINT, +}} +pub type LPNMLVODSTATECHANGE = *mut NMLVODSTATECHANGE; +pub type PNM_ODSTATECHANGE = LPNMLVODSTATECHANGE; +pub type LPNM_ODSTATECHANGE = LPNMLVODSTATECHANGE; +pub type NM_ODSTATECHANGE = NMLVODSTATECHANGE; +pub const LVN_ITEMCHANGING: UINT = LVN_FIRST - 0; +pub const LVN_ITEMCHANGED: UINT = LVN_FIRST - 1; +pub const LVN_INSERTITEM: UINT = LVN_FIRST - 2; +pub const LVN_DELETEITEM: UINT = LVN_FIRST - 3; +pub const LVN_DELETEALLITEMS: UINT = LVN_FIRST - 4; +pub const LVN_BEGINLABELEDITA: UINT = LVN_FIRST - 5; +pub const LVN_BEGINLABELEDITW: UINT = LVN_FIRST - 75; +pub const LVN_ENDLABELEDITA: UINT = LVN_FIRST - 6; +pub const LVN_ENDLABELEDITW: UINT = LVN_FIRST - 76; +pub const LVN_COLUMNCLICK: UINT = LVN_FIRST - 8; +pub const LVN_BEGINDRAG: UINT = LVN_FIRST - 9; +pub const LVN_BEGINRDRAG: UINT = LVN_FIRST - 11; +pub const LVN_ODCACHEHINT: UINT = LVN_FIRST - 13; +pub const LVN_ODFINDITEMA: UINT = LVN_FIRST - 52; +pub const LVN_ODFINDITEMW: UINT = LVN_FIRST - 79; +pub const LVN_ITEMACTIVATE: UINT = LVN_FIRST - 14; +pub const LVN_ODSTATECHANGED: UINT = LVN_FIRST - 15; +pub const LVN_HOTTRACK: UINT = LVN_FIRST - 21; +pub const LVN_GETDISPINFOA: UINT = LVN_FIRST - 50; +pub const LVN_GETDISPINFOW: UINT = LVN_FIRST - 77; +pub const LVN_SETDISPINFOA: UINT = LVN_FIRST - 51; +pub const LVN_SETDISPINFOW: UINT = LVN_FIRST - 78; +pub const LVIF_DI_SETITEM: UINT = 0x1000; +pub type LV_DISPINFOA = NMLVDISPINFOA; +pub type LV_DISPINFOW = NMLVDISPINFOW; +STRUCT!{struct NMLVDISPINFOA { + hdr: NMHDR, + item: LVITEMA, +}} +pub type LPNMLVDISPINFOA = *mut NMLVDISPINFOA; +STRUCT!{struct NMLVDISPINFOW { + hdr: NMHDR, + item: LVITEMW, +}} +pub type LPNMLVDISPINFOW = *mut NMLVDISPINFOW; +pub const LVN_KEYDOWN: UINT = LVN_FIRST - 55; +pub type LV_KEYDOWN = NMLVKEYDOWN; +STRUCT!{#[repr(packed)] struct NMLVKEYDOWN { + hdr: NMHDR, + wVKey: WORD, + flags: UINT, +}} +pub type LPNMLVKEYDOWN = *mut NMLVKEYDOWN; +pub const LVN_MARQUEEBEGIN: UINT = LVN_FIRST - 56; +STRUCT!{struct NMLVLINK { + hdr: NMHDR, + link: LITEM, + iItem: c_int, + iSubItem: c_int, +}} +pub type PNMLVLINK = *mut NMLVLINK; +STRUCT!{struct NMLVGETINFOTIPA { + hdr: NMHDR, + dwFlags: DWORD, + pszText: LPSTR, + cchTextMax: c_int, + iItem: c_int, + iSubItem: c_int, + lParam: LPARAM, +}} +pub type LPNMLVGETINFOTIPA = *mut NMLVGETINFOTIPA; +STRUCT!{struct NMLVGETINFOTIPW { + hdr: NMHDR, + dwFlags: DWORD, + pszText: LPWSTR, + cchTextMax: c_int, + iItem: c_int, + iSubItem: c_int, + lParam: LPARAM, +}} +pub type LPNMLVGETINFOTIPW = *mut NMLVGETINFOTIPW; +pub const LVGIT_UNFOLDED: DWORD = 0x0001; +pub const LVN_GETINFOTIPA: UINT = LVN_FIRST - 57; +pub const LVN_GETINFOTIPW: UINT = LVN_FIRST - 58; +pub const LVNSCH_DEFAULT: LPARAM = -1; +pub const LVNSCH_ERROR: LPARAM = -2; +pub const LVNSCH_IGNORE: LPARAM = -3; +pub const LVN_INCREMENTALSEARCHA: UINT = LVN_FIRST - 62; +pub const LVN_INCREMENTALSEARCHW: UINT = LVN_FIRST - 63; +pub const LVN_COLUMNDROPDOWN: UINT = LVN_FIRST - 64; +pub const LVN_COLUMNOVERFLOWCLICK: UINT = LVN_FIRST - 66; +STRUCT!{struct NMLVSCROLL { + hdr: NMHDR, + dx: c_int, + dy: c_int, +}} +pub type LPNMLVSCROLL = *mut NMLVSCROLL; +pub const LVN_BEGINSCROLL: UINT = LVN_FIRST - 80; +pub const LVN_ENDSCROLL: UINT = LVN_FIRST - 81; +pub const LVN_LINKCLICK: UINT = LVN_FIRST - 84; +pub const EMF_CENTERED: DWORD = 0x00000001; +STRUCT!{struct NMLVEMPTYMARKUP { + hdr: NMHDR, + dwFlags: DWORD, + szMarkup: [WCHAR; L_MAX_URL_LENGTH], +}} +pub const LVN_GETEMPTYMARKUP: UINT = LVN_FIRST - 87; +pub const WC_TREEVIEW: &'static str = "SysTreeView32"; +pub const TVS_HASBUTTONS: DWORD = 0x0001; +pub const TVS_HASLINES: DWORD = 0x0002; +pub const TVS_LINESATROOT: DWORD = 0x0004; +pub const TVS_EDITLABELS: DWORD = 0x0008; +pub const TVS_DISABLEDRAGDROP: DWORD = 0x0010; +pub const TVS_SHOWSELALWAYS: DWORD = 0x0020; +pub const TVS_RTLREADING: DWORD = 0x0040; +pub const TVS_NOTOOLTIPS: DWORD = 0x0080; +pub const TVS_CHECKBOXES: DWORD = 0x0100; +pub const TVS_TRACKSELECT: DWORD = 0x0200; +pub const TVS_SINGLEEXPAND: DWORD = 0x0400; +pub const TVS_INFOTIP: DWORD = 0x0800; +pub const TVS_FULLROWSELECT: DWORD = 0x1000; +pub const TVS_NOSCROLL: DWORD = 0x2000; +pub const TVS_NONEVENHEIGHT: DWORD = 0x4000; +pub const TVS_NOHSCROLL: DWORD = 0x8000; +pub const TVS_EX_NOSINGLECOLLAPSE: DWORD = 0x0001; +pub const TVS_EX_MULTISELECT: DWORD = 0x0002; +pub const TVS_EX_DOUBLEBUFFER: DWORD = 0x0004; +pub const TVS_EX_NOINDENTSTATE: DWORD = 0x0008; +pub const TVS_EX_RICHTOOLTIP: DWORD = 0x0010; +pub const TVS_EX_AUTOHSCROLL: DWORD = 0x0020; +pub const TVS_EX_FADEINOUTEXPANDOS: DWORD = 0x0040; +pub const TVS_EX_PARTIALCHECKBOXES: DWORD = 0x0080; +pub const TVS_EX_EXCLUSIONCHECKBOXES: DWORD = 0x0100; +pub const TVS_EX_DIMMEDCHECKBOXES: DWORD = 0x0200; +pub const TVS_EX_DRAWIMAGEASYNC: DWORD = 0x0400; +pub enum TREEITEM {} +pub type HTREEITEM = *mut TREEITEM; +pub const TVIF_TEXT: UINT = 0x0001; +pub const TVIF_IMAGE: UINT = 0x0002; +pub const TVIF_PARAM: UINT = 0x0004; +pub const TVIF_STATE: UINT = 0x0008; +pub const TVIF_HANDLE: UINT = 0x0010; +pub const TVIF_SELECTEDIMAGE: UINT = 0x0020; +pub const TVIF_CHILDREN: UINT = 0x0040; +pub const TVIF_INTEGRAL: UINT = 0x0080; +pub const TVIF_STATEEX: UINT = 0x0100; +pub const TVIF_EXPANDEDIMAGE: UINT = 0x0200; +pub const TVIS_SELECTED: UINT = 0x0002; +pub const TVIS_CUT: UINT = 0x0004; +pub const TVIS_DROPHILITED: UINT = 0x0008; +pub const TVIS_BOLD: UINT = 0x0010; +pub const TVIS_EXPANDED: UINT = 0x0020; +pub const TVIS_EXPANDEDONCE: UINT = 0x0040; +pub const TVIS_EXPANDPARTIAL: UINT = 0x0080; +pub const TVIS_OVERLAYMASK: UINT = 0x0F00; +pub const TVIS_STATEIMAGEMASK: UINT = 0xF000; +pub const TVIS_USERMASK: UINT = 0xF000; +pub const TVIS_EX_FLAT: UINT = 0x0001; +pub const TVIS_EX_DISABLED: UINT = 0x0002; +pub const TVIS_EX_ALL: UINT = 0x0002; +STRUCT!{struct NMTVSTATEIMAGECHANGING { + hdr: NMHDR, + hti: HTREEITEM, + iOldStateImageIndex: c_int, + iNewStateImageIndex: c_int, +}} +pub type LPNMTVSTATEIMAGECHANGING = *mut NMTVSTATEIMAGECHANGING; +pub const I_CHILDRENCALLBACK: c_int = -1; +pub const I_CHILDRENAUTO: c_int = -2; +pub type LPTV_ITEMW = LPTVITEMW; +pub type LPTV_ITEMA = LPTVITEMA; +pub type TV_ITEMW = TVITEMW; +pub type TV_ITEMA = TVITEMA; +STRUCT!{struct TVITEMA { + mask: UINT, + hItem: HTREEITEM, + state: UINT, + stateMask: UINT, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + cChildren: c_int, + lParam: LPARAM, +}} +pub type LPTVITEMA = *mut TVITEMA; +STRUCT!{struct TVITEMW { + mask: UINT, + hItem: HTREEITEM, + state: UINT, + stateMask: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + cChildren: c_int, + lParam: LPARAM, +}} +pub type LPTVITEMW = *mut TVITEMW; +STRUCT!{struct TVITEMEXA { + mask: UINT, + hItem: HTREEITEM, + state: UINT, + stateMask: UINT, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + cChildren: c_int, + lParam: LPARAM, + iIntegral: c_int, + uStateEx: UINT, + hwnd: HWND, + iExpandedImage: c_int, + iReserved: c_int, +}} +pub type LPTVITEMEXA = *mut TVITEMEXA; +STRUCT!{struct TVITEMEXW { + mask: UINT, + hItem: HTREEITEM, + state: UINT, + stateMask: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + cChildren: c_int, + lParam: LPARAM, + iIntegral: c_int, + uStateEx: UINT, + hwnd: HWND, + iExpandedImage: c_int, + iReserved: c_int, +}} +pub type LPTVITEMEXW = *mut TVITEMEXW; +pub const TVI_ROOT: HTREEITEM = -0x10000isize as HTREEITEM; +pub const TVI_FIRST: HTREEITEM = -0x0FFFFisize as HTREEITEM; +pub const TVI_LAST: HTREEITEM = -0x0FFFEisize as HTREEITEM; +pub const TVI_SORT: HTREEITEM = -0x0FFFDisize as HTREEITEM; +pub type LPTV_INSERTSTRUCTA = LPTVINSERTSTRUCTA; +pub type LPTV_INSERTSTRUCTW = LPTVINSERTSTRUCTW; +pub type TV_INSERTSTRUCTA = TVINSERTSTRUCTA; +pub type TV_INSERTSTRUCTW = TVINSERTSTRUCTW; +UNION!{union TVINSERTSTRUCTA_u { + [u32; 15] [u64; 10], + itemex itemex_mut: TVITEMEXA, + item item_mut: TV_ITEMA, +}} +STRUCT!{struct TVINSERTSTRUCTA { + hParent: HTREEITEM, + hInsertAfter: HTREEITEM, + u: TVINSERTSTRUCTA_u, +}} +pub type LPTVINSERTSTRUCTA = *mut TVINSERTSTRUCTA; +UNION!{union TVINSERTSTRUCTW_u { + [u32; 15] [u64; 10], + itemex itemex_mut: TVITEMEXW, + item item_mut: TV_ITEMW, +}} +STRUCT!{struct TVINSERTSTRUCTW { + hParent: HTREEITEM, + hInsertAfter: HTREEITEM, + u: TVINSERTSTRUCTW_u, +}} +pub type LPTVINSERTSTRUCTW = *mut TVINSERTSTRUCTW; +pub const TVM_INSERTITEMA: UINT = TV_FIRST + 0; +pub const TVM_INSERTITEMW: UINT = TV_FIRST + 50; +pub const TVM_DELETEITEM: UINT = TV_FIRST + 1; +pub const TVM_EXPAND: UINT = TV_FIRST + 2; +pub const TVE_COLLAPSE: WPARAM = 0x0001; +pub const TVE_EXPAND: WPARAM = 0x0002; +pub const TVE_TOGGLE: WPARAM = 0x0003; +pub const TVE_EXPANDPARTIAL: WPARAM = 0x4000; +pub const TVE_COLLAPSERESET: WPARAM = 0x8000; +pub const TVM_GETITEMRECT: UINT = TV_FIRST + 4; +pub const TVM_GETCOUNT: UINT = TV_FIRST + 5; +pub const TVM_GETINDENT: UINT = TV_FIRST + 6; +pub const TVM_SETINDENT: UINT = TV_FIRST + 7; +pub const TVM_GETIMAGELIST: UINT = TV_FIRST + 8; +pub const TVSIL_NORMAL: WPARAM = 0; +pub const TVSIL_STATE: WPARAM = 2; +pub const TVM_SETIMAGELIST: UINT = TV_FIRST + 9; +pub const TVM_GETNEXTITEM: UINT = TV_FIRST + 10; +pub const TVGN_ROOT: WPARAM = 0x0000; +pub const TVGN_NEXT: WPARAM = 0x0001; +pub const TVGN_PREVIOUS: WPARAM = 0x0002; +pub const TVGN_PARENT: WPARAM = 0x0003; +pub const TVGN_CHILD: WPARAM = 0x0004; +pub const TVGN_FIRSTVISIBLE: WPARAM = 0x0005; +pub const TVGN_NEXTVISIBLE: WPARAM = 0x0006; +pub const TVGN_PREVIOUSVISIBLE: WPARAM = 0x0007; +pub const TVGN_DROPHILITE: WPARAM = 0x0008; +pub const TVGN_CARET: WPARAM = 0x0009; +pub const TVGN_LASTVISIBLE: WPARAM = 0x000A; +pub const TVGN_NEXTSELECTED: WPARAM = 0x000B; +pub const TVSI_NOSINGLEEXPAND: WPARAM = 0x8000; +pub const TVM_SELECTITEM: UINT = TV_FIRST + 11; +pub const TVM_GETITEMA: UINT = TV_FIRST + 12; +pub const TVM_GETITEMW: UINT = TV_FIRST + 62; +pub const TVM_SETITEMA: UINT = TV_FIRST + 13; +pub const TVM_SETITEMW: UINT = TV_FIRST + 63; +pub const TVM_EDITLABELA: UINT = TV_FIRST + 14; +pub const TVM_EDITLABELW: UINT = TV_FIRST + 65; +pub const TVM_GETEDITCONTROL: UINT = TV_FIRST + 15; +pub const TVM_GETVISIBLECOUNT: UINT = TV_FIRST + 16; +pub const TVM_HITTEST: UINT = TV_FIRST + 17; +pub type LPTV_HITTESTINFO = LPTVHITTESTINFO; +pub type TV_HITTESTINFO = TVHITTESTINFO; +STRUCT!{struct TVHITTESTINFO { + pt: POINT, + flags: UINT, + hItem: HTREEITEM, +}} +pub type LPTVHITTESTINFO = *mut TVHITTESTINFO; +pub const TVHT_NOWHERE: UINT = 0x0001; +pub const TVHT_ONITEMICON: UINT = 0x0002; +pub const TVHT_ONITEMLABEL: UINT = 0x0004; +pub const TVHT_ONITEM: UINT = TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMSTATEICON; +pub const TVHT_ONITEMINDENT: UINT = 0x0008; +pub const TVHT_ONITEMBUTTON: UINT = 0x0010; +pub const TVHT_ONITEMRIGHT: UINT = 0x0020; +pub const TVHT_ONITEMSTATEICON: UINT = 0x0040; +pub const TVHT_ABOVE: UINT = 0x0100; +pub const TVHT_BELOW: UINT = 0x0200; +pub const TVHT_TORIGHT: UINT = 0x0400; +pub const TVHT_TOLEFT: UINT = 0x0800; +pub const TVM_CREATEDRAGIMAGE: UINT = TV_FIRST + 18; +pub const TVM_SORTCHILDREN: UINT = TV_FIRST + 19; +pub const TVM_ENSUREVISIBLE: UINT = TV_FIRST + 20; +pub const TVM_SORTCHILDRENCB: UINT = TV_FIRST + 21; +pub const TVM_ENDEDITLABELNOW: UINT = TV_FIRST + 22; +pub const TVM_GETISEARCHSTRINGA: UINT = TV_FIRST + 23; +pub const TVM_GETISEARCHSTRINGW: UINT = TV_FIRST + 64; +pub const TVM_SETTOOLTIPS: UINT = TV_FIRST + 24; +pub const TVM_GETTOOLTIPS: UINT = TV_FIRST + 25; +pub const TVM_SETINSERTMARK: UINT = TV_FIRST + 26; +pub const TVM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const TVM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const TVM_SETITEMHEIGHT: UINT = TV_FIRST + 27; +pub const TVM_GETITEMHEIGHT: UINT = TV_FIRST + 28; +pub const TVM_SETBKCOLOR: UINT = TV_FIRST + 29; +pub const TVM_SETTEXTCOLOR: UINT = TV_FIRST + 30; +pub const TVM_GETBKCOLOR: UINT = TV_FIRST + 31; +pub const TVM_GETTEXTCOLOR: UINT = TV_FIRST + 32; +pub const TVM_SETSCROLLTIME: UINT = TV_FIRST + 33; +pub const TVM_GETSCROLLTIME: UINT = TV_FIRST + 34; +pub const TVM_SETINSERTMARKCOLOR: UINT = TV_FIRST + 37; +pub const TVM_GETINSERTMARKCOLOR: UINT = TV_FIRST + 38; +pub const TVM_SETBORDER: UINT = TV_FIRST + 35; +pub const TVSBF_XBORDER: WPARAM = 0x00000001; +pub const TVSBF_YBORDER: WPARAM = 0x00000002; +pub const TVM_GETITEMSTATE: UINT = TV_FIRST + 39; +pub const TVM_SETLINECOLOR: UINT = TV_FIRST + 40; +pub const TVM_GETLINECOLOR: UINT = TV_FIRST + 41; +pub const TVM_MAPACCIDTOHTREEITEM: UINT = TV_FIRST + 42; +pub const TVM_MAPHTREEITEMTOACCID: UINT = TV_FIRST + 43; +pub const TVM_SETEXTENDEDSTYLE: UINT = TV_FIRST + 44; +pub const TVM_GETEXTENDEDSTYLE: UINT = TV_FIRST + 45; +pub const TVM_SETAUTOSCROLLINFO: UINT = TV_FIRST + 59; +pub const TVM_SETHOT: UINT = TV_FIRST + 58; +pub const TVM_GETSELECTEDCOUNT: UINT = TV_FIRST + 70; +pub const TVM_SHOWINFOTIP: UINT = TV_FIRST + 71; +ENUM!{enum TVITEMPART { + TVGIPR_BUTTON = 0x0001, +}} +STRUCT!{struct TVGETITEMPARTRECTINFO { + hti: HTREEITEM, + prc: *mut RECT, + partID: TVITEMPART, +}} +pub const TVM_GETITEMPARTRECT: UINT = TV_FIRST + 72; +FN!{stdcall PFNTVCOMPARE( + lParam1: LPARAM, + lParam2: LPARAM, + lParamSort: LPARAM, +) -> c_int} +pub type LPTV_SORTCB = LPTVSORTCB; +pub type TV_SORTCB = TVSORTCB; +STRUCT!{struct TVSORTCB { + hParent: HTREEITEM, + lpfnCompare: PFNTVCOMPARE, + lParam: LPARAM, +}} +pub type LPTVSORTCB = *mut TVSORTCB; +pub type LPNM_TREEVIEWA = LPNMTREEVIEWA; +pub type LPNM_TREEVIEWW = LPNMTREEVIEWW; +pub type NM_TREEVIEWA = NMTREEVIEWA; +pub type NM_TREEVIEWW = NMTREEVIEWW; +STRUCT!{struct NMTREEVIEWA { + hdr: NMHDR, + action: UINT, + itemOld: TVITEMA, + itemNew: TVITEMA, + ptDrag: POINT, +}} +pub type LPNMTREEVIEWA = *mut NMTREEVIEWA; +STRUCT!{struct NMTREEVIEWW { + hdr: NMHDR, + action: UINT, + itemOld: TVITEMW, + itemNew: TVITEMW, + ptDrag: POINT, +}} +pub type LPNMTREEVIEWW = *mut NMTREEVIEWW; +pub const TVN_SELCHANGINGA: UINT = TVN_FIRST - 1; +pub const TVN_SELCHANGINGW: UINT = TVN_FIRST - 50; +pub const TVN_SELCHANGEDA: UINT = TVN_FIRST - 2; +pub const TVN_SELCHANGEDW: UINT = TVN_FIRST - 51; +pub const TVC_UNKNOWN: LPARAM = 0x0000; +pub const TVC_BYMOUSE: LPARAM = 0x0001; +pub const TVC_BYKEYBOARD: LPARAM = 0x0002; +pub const TVN_GETDISPINFOA: UINT = TVN_FIRST - 3; +pub const TVN_GETDISPINFOW: UINT = TVN_FIRST - 52; +pub const TVN_SETDISPINFOA: UINT = TVN_FIRST - 4; +pub const TVN_SETDISPINFOW: UINT = TVN_FIRST - 53; +pub const TVIF_DI_SETITEM: UINT = 0x1000; +pub type TV_DISPINFOA = NMTVDISPINFOA; +pub type TV_DISPINFOW = NMTVDISPINFOW; +STRUCT!{struct NMTVDISPINFOA { + hdr: NMHDR, + item: TVITEMA, +}} +pub type LPNMTVDISPINFOA = *mut NMTVDISPINFOA; +STRUCT!{struct NMTVDISPINFOW { + hdr: NMHDR, + item: TVITEMW, +}} +pub type LPNMTVDISPINFOW = *mut NMTVDISPINFOW; +STRUCT!{struct NMTVDISPINFOEXA { + hdr: NMHDR, + item: TVITEMEXA, +}} +pub type LPNMTVDISPINFOEXA = *mut NMTVDISPINFOEXA; +STRUCT!{struct NMTVDISPINFOEXW { + hdr: NMHDR, + item: TVITEMEXW, +}} +pub type LPNMTVDISPINFOEXW = *mut NMTVDISPINFOEXW; +pub type TV_DISPINFOEXA = NMTVDISPINFOEXA; +pub type TV_DISPINFOEXW = NMTVDISPINFOEXW; +pub const TVN_ITEMEXPANDINGA: UINT = TVN_FIRST - 5; +pub const TVN_ITEMEXPANDINGW: UINT = TVN_FIRST - 54; +pub const TVN_ITEMEXPANDEDA: UINT = TVN_FIRST - 6; +pub const TVN_ITEMEXPANDEDW: UINT = TVN_FIRST - 55; +pub const TVN_BEGINDRAGA: UINT = TVN_FIRST - 7; +pub const TVN_BEGINDRAGW: UINT = TVN_FIRST - 56; +pub const TVN_BEGINRDRAGA: UINT = TVN_FIRST - 8; +pub const TVN_BEGINRDRAGW: UINT = TVN_FIRST - 57; +pub const TVN_DELETEITEMA: UINT = TVN_FIRST - 9; +pub const TVN_DELETEITEMW: UINT = TVN_FIRST - 58; +pub const TVN_BEGINLABELEDITA: UINT = TVN_FIRST - 10; +pub const TVN_BEGINLABELEDITW: UINT = TVN_FIRST - 59; +pub const TVN_ENDLABELEDITA: UINT = TVN_FIRST - 11; +pub const TVN_ENDLABELEDITW: UINT = TVN_FIRST - 60; +pub const TVN_KEYDOWN: UINT = TVN_FIRST - 12; +pub const TVN_GETINFOTIPA: UINT = TVN_FIRST - 13; +pub const TVN_GETINFOTIPW: UINT = TVN_FIRST - 14; +pub const TVN_SINGLEEXPAND: UINT = TVN_FIRST - 15; +pub const TVNRET_DEFAULT: LRESULT = 0; +pub const TVNRET_SKIPOLD: LRESULT = 1; +pub const TVNRET_SKIPNEW: LRESULT = 2; +pub const TVN_ITEMCHANGINGA: UINT = TVN_FIRST - 16; +pub const TVN_ITEMCHANGINGW: UINT = TVN_FIRST - 17; +pub const TVN_ITEMCHANGEDA: UINT = TVN_FIRST - 18; +pub const TVN_ITEMCHANGEDW: UINT = TVN_FIRST - 19; +pub const TVN_ASYNCDRAW: UINT = TVN_FIRST - 20; +pub type TV_KEYDOWN = NMTVKEYDOWN; +STRUCT!{#[repr(packed)] struct NMTVKEYDOWN { + hdr: NMHDR, + wVKey: WORD, + flags: UINT, +}} +pub type LPNMTVKEYDOWN = *mut NMTVKEYDOWN; +STRUCT!{struct NMTVCUSTOMDRAW { + nmcd: NMCUSTOMDRAW, + clrText: COLORREF, + clrTextBk: COLORREF, + iLevel: c_int, +}} +pub type LPNMTVCUSTOMDRAW = *mut NMTVCUSTOMDRAW; +STRUCT!{struct NMTVGETINFOTIPA { + hdr: NMHDR, + pszText: LPSTR, + cchTextMax: c_int, + hItem: HTREEITEM, + lParam: LPARAM, +}} +pub type LPNMTVGETINFOTIPA = *mut NMTVGETINFOTIPA; +STRUCT!{struct NMTVGETINFOTIPW { + hdr: NMHDR, + pszText: LPWSTR, + cchTextMax: c_int, + hItem: HTREEITEM, + lParam: LPARAM, +}} +pub type LPNMTVGETINFOTIPW = *mut NMTVGETINFOTIPW; +pub const TVCDRF_NOIMAGES: LRESULT = 0x00010000; +STRUCT!{struct NMTVITEMCHANGE { + hdr: NMHDR, + uChanged: UINT, + hItem: HTREEITEM, + uStateNew: UINT, + uStateOld: UINT, + lParam: LPARAM, +}} +STRUCT!{struct NMTVASYNCDRAW { + hdr: NMHDR, + pimldp: *mut IMAGELISTDRAWPARAMS, + hr: HRESULT, + hItem: HTREEITEM, + lParam: LPARAM, + dwRetFlags: DWORD, + iRetImageIndex: c_int, +}} +pub const WC_COMBOBOXEX: &'static str = "ComboBoxEx32"; +pub const CBEIF_TEXT: UINT = 0x00000001; +pub const CBEIF_IMAGE: UINT = 0x00000002; +pub const CBEIF_SELECTEDIMAGE: UINT = 0x00000004; +pub const CBEIF_OVERLAY: UINT = 0x00000008; +pub const CBEIF_INDENT: UINT = 0x00000010; +pub const CBEIF_LPARAM: UINT = 0x00000020; +pub const CBEIF_DI_SETITEM: UINT = 0x10000000; +STRUCT!{struct COMBOBOXEXITEMA { + mask: UINT, + iItem: INT_PTR, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + iOverlay: c_int, + iIndent: c_int, + lParam: LPARAM, +}} +pub type PCOMBOBOXEXITEMA = *mut COMBOBOXEXITEMA; +pub type PCCOMBOBOXEXITEMA = *const COMBOBOXEXITEMA; +STRUCT!{struct COMBOBOXEXITEMW { + mask: UINT, + iItem: INT_PTR, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + iSelectedImage: c_int, + iOverlay: c_int, + iIndent: c_int, + lParam: LPARAM, +}} +pub type PCOMBOBOXEXITEMW = *mut COMBOBOXEXITEMW; +pub type PCCOMBOBOXEXITEMW = *const COMBOBOXEXITEMW; +pub const CBEM_INSERTITEMA: UINT = WM_USER + 1; +pub const CBEM_SETIMAGELIST: UINT = WM_USER + 2; +pub const CBEM_GETIMAGELIST: UINT = WM_USER + 3; +pub const CBEM_GETITEMA: UINT = WM_USER + 4; +pub const CBEM_SETITEMA: UINT = WM_USER + 5; +pub const CBEM_DELETEITEM: UINT = CB_DELETESTRING; +pub const CBEM_GETCOMBOCONTROL: UINT = WM_USER + 6; +pub const CBEM_GETEDITCONTROL: UINT = WM_USER + 7; +pub const CBEM_SETEXSTYLE: UINT = WM_USER + 8; +pub const CBEM_SETEXTENDEDSTYLE: UINT = WM_USER + 14; +pub const CBEM_GETEXSTYLE: UINT = WM_USER + 9; +pub const CBEM_GETEXTENDEDSTYLE: UINT = WM_USER + 9; +pub const CBEM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const CBEM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const CBEM_HASEDITCHANGED: UINT = WM_USER + 10; +pub const CBEM_INSERTITEMW: UINT = WM_USER + 11; +pub const CBEM_SETITEMW: UINT = WM_USER + 12; +pub const CBEM_GETITEMW: UINT = WM_USER + 13; +pub const CBEM_SETWINDOWTHEME: UINT = CCM_SETWINDOWTHEME; +pub const CBES_EX_NOEDITIMAGE: DWORD = 0x00000001; +pub const CBES_EX_NOEDITIMAGEINDENT: DWORD = 0x00000002; +pub const CBES_EX_PATHWORDBREAKPROC: DWORD = 0x00000004; +pub const CBES_EX_NOSIZELIMIT: DWORD = 0x00000008; +pub const CBES_EX_CASESENSITIVE: DWORD = 0x00000010; +pub const CBES_EX_TEXTENDELLIPSIS: DWORD = 0x00000020; +STRUCT!{struct NMCOMBOBOXEXA { + hdr: NMHDR, + ceItem: COMBOBOXEXITEMA, +}} +pub type PNMCOMBOBOXEXA = *mut NMCOMBOBOXEXA; +STRUCT!{struct NMCOMBOBOXEXW { + hdr: NMHDR, + ceItem: COMBOBOXEXITEMW, +}} +pub type PNMCOMBOBOXEXW = *mut NMCOMBOBOXEXW; +pub const CBEN_GETDISPINFOA: UINT = CBEN_FIRST - 0; +pub const CBEN_INSERTITEM: UINT = CBEN_FIRST - 1; +pub const CBEN_DELETEITEM: UINT = CBEN_FIRST - 2; +pub const CBEN_BEGINEDIT: UINT = CBEN_FIRST - 4; +pub const CBEN_ENDEDITA: UINT = CBEN_FIRST - 5; +pub const CBEN_ENDEDITW: UINT = CBEN_FIRST - 6; +pub const CBEN_GETDISPINFOW: UINT = CBEN_FIRST - 7; +pub const CBEN_DRAGBEGINA: UINT = CBEN_FIRST - 8; +pub const CBEN_DRAGBEGINW: UINT = CBEN_FIRST - 9; +pub const CBENF_KILLFOCUS: c_int = 1; +pub const CBENF_RETURN: c_int = 2; +pub const CBENF_ESCAPE: c_int = 3; +pub const CBENF_DROPDOWN: c_int = 4; +pub const CBEMAXSTRLEN: usize = 260; +STRUCT!{struct NMCBEDRAGBEGINW { + hdr: NMHDR, + iItemid: c_int, + szText: [WCHAR; CBEMAXSTRLEN], +}} +pub type PNMCBEDRAGBEGINW = *mut NMCBEDRAGBEGINW; +pub type LPNMCBEDRAGBEGINW = *mut NMCBEDRAGBEGINW; +STRUCT!{struct NMCBEDRAGBEGINA { + hdr: NMHDR, + iItemid: c_int, + szText: [c_char; CBEMAXSTRLEN], +}} +pub type PNMCBEDRAGBEGINA = *mut NMCBEDRAGBEGINA; +pub type LPNMCBEDRAGBEGINA = *mut NMCBEDRAGBEGINA; +STRUCT!{struct NMCBEENDEDITW { + hdr: NMHDR, + fChanged: BOOL, + iNewSelection: c_int, + szText: [WCHAR; CBEMAXSTRLEN], + iWhy: c_int, +}} +pub type PNMCBEENDEDITW = *mut NMCBEENDEDITW; +pub type LPNMCBEENDEDITW = *mut NMCBEENDEDITW; +STRUCT!{struct NMCBEENDEDITA { + hdr: NMHDR, + fChanged: BOOL, + iNewSelection: c_int, + szText: [c_char; CBEMAXSTRLEN], + iWhy: c_int, +}} +pub type PNMCBEENDEDITA = *mut NMCBEENDEDITA; +pub type LPNMCBEENDEDITA = *mut NMCBEENDEDITA; +pub const WC_TABCONTROL: &'static str = "SysTabControl32"; +pub const TCS_SCROLLOPPOSITE: DWORD = 0x0001; +pub const TCS_BOTTOM: DWORD = 0x0002; +pub const TCS_RIGHT: DWORD = 0x0002; +pub const TCS_MULTISELECT: DWORD = 0x0004; +pub const TCS_FLATBUTTONS: DWORD = 0x0008; +pub const TCS_FORCEICONLEFT: DWORD = 0x0010; +pub const TCS_FORCELABELLEFT: DWORD = 0x0020; +pub const TCS_HOTTRACK: DWORD = 0x0040; +pub const TCS_VERTICAL: DWORD = 0x0080; +pub const TCS_TABS: DWORD = 0x0000; +pub const TCS_BUTTONS: DWORD = 0x0100; +pub const TCS_SINGLELINE: DWORD = 0x0000; +pub const TCS_MULTILINE: DWORD = 0x0200; +pub const TCS_RIGHTJUSTIFY: DWORD = 0x0000; +pub const TCS_FIXEDWIDTH: DWORD = 0x0400; +pub const TCS_RAGGEDRIGHT: DWORD = 0x0800; +pub const TCS_FOCUSONBUTTONDOWN: DWORD = 0x1000; +pub const TCS_OWNERDRAWFIXED: DWORD = 0x2000; +pub const TCS_TOOLTIPS: DWORD = 0x4000; +pub const TCS_FOCUSNEVER: DWORD = 0x8000; +pub const TCS_EX_FLATSEPARATORS: DWORD = 0x00000001; +pub const TCS_EX_REGISTERDROP: DWORD = 0x00000002; +pub const TCM_GETIMAGELIST: UINT = TCM_FIRST + 2; +pub const TCM_SETIMAGELIST: UINT = TCM_FIRST + 3; +pub const TCM_GETITEMCOUNT: UINT = TCM_FIRST + 4; +pub const TCIF_TEXT: UINT = 0x0001; +pub const TCIF_IMAGE: UINT = 0x0002; +pub const TCIF_RTLREADING: UINT = 0x0004; +pub const TCIF_PARAM: UINT = 0x0008; +pub const TCIF_STATE: UINT = 0x0010; +pub const TCIS_BUTTONPRESSED: DWORD = 0x0001; +pub const TCIS_HIGHLIGHTED: DWORD = 0x0002; +pub type TC_ITEMHEADERA = TCITEMHEADERA; +pub type TC_ITEMHEADERW = TCITEMHEADERW; +STRUCT!{struct TCITEMHEADERA { + mask: UINT, + lpReserved1: UINT, + lpReserved2: UINT, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, +}} +pub type LPTCITEMHEADERA = *mut TCITEMHEADERA; +STRUCT!{struct TCITEMHEADERW { + mask: UINT, + lpReserved1: UINT, + lpReserved2: UINT, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, +}} +pub type LPTCITEMHEADERW = *mut TCITEMHEADERW; +pub type TC_ITEMA = TCITEMA; +pub type TC_ITEMW = TCITEMW; +STRUCT!{struct TCITEMA { + mask: UINT, + dwState: DWORD, + dwStateMask: DWORD, + pszText: LPSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, +}} +pub type LPTCITEMA = *mut TCITEMA; +STRUCT!{struct TCITEMW { + mask: UINT, + dwState: DWORD, + dwStateMask: DWORD, + pszText: LPWSTR, + cchTextMax: c_int, + iImage: c_int, + lParam: LPARAM, +}} +pub type LPTCITEMW = *mut TCITEMW; +pub const TCM_GETITEMA: UINT = TCM_FIRST + 5; +pub const TCM_GETITEMW: UINT = TCM_FIRST + 60; +pub const TCM_SETITEMA: UINT = TCM_FIRST + 6; +pub const TCM_SETITEMW: UINT = TCM_FIRST + 61; +pub const TCM_INSERTITEMA: UINT = TCM_FIRST + 7; +pub const TCM_INSERTITEMW: UINT = TCM_FIRST + 62; +pub const TCM_DELETEITEM: UINT = TCM_FIRST + 8; +pub const TCM_DELETEALLITEMS: UINT = TCM_FIRST + 9; +pub const TCM_GETITEMRECT: UINT = TCM_FIRST + 10; +pub const TCM_GETCURSEL: UINT = TCM_FIRST + 11; +pub const TCM_SETCURSEL: UINT = TCM_FIRST + 12; +pub const TCHT_NOWHERE: UINT = 0x0001; +pub const TCHT_ONITEMICON: UINT = 0x0002; +pub const TCHT_ONITEMLABEL: UINT = 0x0004; +pub const TCHT_ONITEM: UINT = TCHT_ONITEMICON | TCHT_ONITEMLABEL; +pub type LPTC_HITTESTINFO = LPTCHITTESTINFO; +pub type TC_HITTESTINFO = TCHITTESTINFO; +STRUCT!{struct TCHITTESTINFO { + pt: POINT, + flags: UINT, +}} +pub type LPTCHITTESTINFO = *mut TCHITTESTINFO; +pub const TCM_HITTEST: UINT = TCM_FIRST + 13; +pub const TCM_SETITEMEXTRA: UINT = TCM_FIRST + 14; +pub const TCM_ADJUSTRECT: UINT = TCM_FIRST + 40; +pub const TCM_SETITEMSIZE: UINT = TCM_FIRST + 41; +pub const TCM_REMOVEIMAGE: UINT = TCM_FIRST + 42; +pub const TCM_SETPADDING: UINT = TCM_FIRST + 43; +pub const TCM_GETROWCOUNT: UINT = TCM_FIRST + 44; +pub const TCM_GETTOOLTIPS: UINT = TCM_FIRST + 45; +pub const TCM_SETTOOLTIPS: UINT = TCM_FIRST + 46; +pub const TCM_GETCURFOCUS: UINT = TCM_FIRST + 47; +pub const TCM_SETCURFOCUS: UINT = TCM_FIRST + 48; +pub const TCM_SETMINTABWIDTH: UINT = TCM_FIRST + 49; +pub const TCM_DESELECTALL: UINT = TCM_FIRST + 50; +pub const TCM_HIGHLIGHTITEM: UINT = TCM_FIRST + 51; +pub const TCM_SETEXTENDEDSTYLE: UINT = TCM_FIRST + 52; +pub const TCM_GETEXTENDEDSTYLE: UINT = TCM_FIRST + 53; +pub const TCM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const TCM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const TCN_KEYDOWN: UINT = TCN_FIRST - 0; +pub type TC_KEYDOWN = NMTCKEYDOWN; +STRUCT!{#[repr(packed)] struct NMTCKEYDOWN { + hdr: NMHDR, + wVKey: WORD, + flags: UINT, +}} +pub const TCN_SELCHANGE: UINT = TCN_FIRST - 1; +pub const TCN_SELCHANGING: UINT = TCN_FIRST - 2; +pub const TCN_GETOBJECT: UINT = TCN_FIRST - 3; +pub const TCN_FOCUSCHANGE: UINT = TCN_FIRST - 4; +pub const ANIMATE_CLASS: &'static str = "SysAnimate32"; +pub const ACS_CENTER: DWORD = 0x0001; +pub const ACS_TRANSPARENT: DWORD = 0x0002; +pub const ACS_AUTOPLAY: DWORD = 0x0004; +pub const ACS_TIMER: DWORD = 0x0008; +pub const ACM_OPENA: UINT = WM_USER + 100; +pub const ACM_OPENW: UINT = WM_USER + 103; +pub const ACM_PLAY: UINT = WM_USER + 101; +pub const ACM_STOP: UINT = WM_USER + 102; +pub const ACM_ISPLAYING: UINT = WM_USER + 104; +pub const ACN_START: WPARAM = 1; +pub const ACN_STOP: WPARAM = 2; +pub const MONTHCAL_CLASS: &'static str = "SysMonthCal32"; +pub type MONTHDAYSTATE = DWORD; +pub type LPMONTHDAYSTATE = *mut DWORD; +pub const MCM_FIRST: UINT = 0x1000; +pub const MCM_GETCURSEL: UINT = MCM_FIRST + 1; +pub const MCM_SETCURSEL: UINT = MCM_FIRST + 2; +pub const MCM_GETMAXSELCOUNT: UINT = MCM_FIRST + 3; +pub const MCM_SETMAXSELCOUNT: UINT = MCM_FIRST + 4; +pub const MCM_GETSELRANGE: UINT = MCM_FIRST + 5; +pub const MCM_SETSELRANGE: UINT = MCM_FIRST + 6; +pub const MCM_GETMONTHRANGE: UINT = MCM_FIRST + 7; +pub const MCM_SETDAYSTATE: UINT = MCM_FIRST + 8; +pub const MCM_GETMINREQRECT: UINT = MCM_FIRST + 9; +pub const MCM_SETCOLOR: UINT = MCM_FIRST + 10; +pub const MCM_GETCOLOR: UINT = MCM_FIRST + 11; +pub const MCSC_BACKGROUND: WPARAM = 0; +pub const MCSC_TEXT: WPARAM = 1; +pub const MCSC_TITLEBK: WPARAM = 2; +pub const MCSC_TITLETEXT: WPARAM = 3; +pub const MCSC_MONTHBK: WPARAM = 4; +pub const MCSC_TRAILINGTEXT: WPARAM = 5; +pub const MCM_SETTODAY: UINT = MCM_FIRST + 12; +pub const MCM_GETTODAY: UINT = MCM_FIRST + 13; +pub const MCM_HITTEST: UINT = MCM_FIRST + 14; +STRUCT!{struct MCHITTESTINFO { + cbSize: UINT, + pt: POINT, + uHit: UINT, + st: SYSTEMTIME, + rc: RECT, + iOffset: c_int, + iRow: c_int, + iCol: c_int, +}} +pub type PMCHITTESTINFO = *mut MCHITTESTINFO; +pub const MCHT_TITLE: UINT = 0x00010000; +pub const MCHT_CALENDAR: UINT = 0x00020000; +pub const MCHT_TODAYLINK: UINT = 0x00030000; +pub const MCHT_CALENDARCONTROL: UINT = 0x00100000; +pub const MCHT_NEXT: UINT = 0x01000000; +pub const MCHT_PREV: UINT = 0x02000000; +pub const MCHT_NOWHERE: UINT = 0x00000000; +pub const MCHT_TITLEBK: UINT = MCHT_TITLE; +pub const MCHT_TITLEMONTH: UINT = MCHT_TITLE | 0x0001; +pub const MCHT_TITLEYEAR: UINT = MCHT_TITLE | 0x0002; +pub const MCHT_TITLEBTNNEXT: UINT = MCHT_TITLE | MCHT_NEXT | 0x0003; +pub const MCHT_TITLEBTNPREV: UINT = MCHT_TITLE | MCHT_PREV | 0x0003; +pub const MCHT_CALENDARBK: UINT = MCHT_CALENDAR; +pub const MCHT_CALENDARDATE: UINT = MCHT_CALENDAR | 0x0001; +pub const MCHT_CALENDARDATENEXT: UINT = MCHT_CALENDARDATE | MCHT_NEXT; +pub const MCHT_CALENDARDATEPREV: UINT = MCHT_CALENDARDATE | MCHT_PREV; +pub const MCHT_CALENDARDAY: UINT = MCHT_CALENDAR | 0x0002; +pub const MCHT_CALENDARWEEKNUM: UINT = MCHT_CALENDAR | 0x0003; +pub const MCHT_CALENDARDATEMIN: UINT = MCHT_CALENDAR | 0x0004; +pub const MCHT_CALENDARDATEMAX: UINT = MCHT_CALENDAR | 0x0005; +pub const MCM_SETFIRSTDAYOFWEEK: UINT = MCM_FIRST + 15; +pub const MCM_GETFIRSTDAYOFWEEK: UINT = MCM_FIRST + 16; +pub const MCM_GETRANGE: UINT = MCM_FIRST + 17; +pub const MCM_SETRANGE: UINT = MCM_FIRST + 18; +pub const MCM_GETMONTHDELTA: UINT = MCM_FIRST + 19; +pub const MCM_SETMONTHDELTA: UINT = MCM_FIRST + 20; +pub const MCM_GETMAXTODAYWIDTH: UINT = MCM_FIRST + 21; +pub const MCM_SETUNICODEFORMAT: UINT = CCM_SETUNICODEFORMAT; +pub const MCM_GETUNICODEFORMAT: UINT = CCM_GETUNICODEFORMAT; +pub const MCMV_MONTH: DWORD = 0; +pub const MCMV_YEAR: DWORD = 1; +pub const MCMV_DECADE: DWORD = 2; +pub const MCMV_CENTURY: DWORD = 3; +pub const MCMV_MAX: DWORD = MCMV_CENTURY; +pub const MCM_GETCURRENTVIEW: UINT = MCM_FIRST + 22; +pub const MCM_GETCALENDARCOUNT: UINT = MCM_FIRST + 23; +pub const MCGIP_CALENDARCONTROL: DWORD = 0; +pub const MCGIP_NEXT: DWORD = 1; +pub const MCGIP_PREV: DWORD = 2; +pub const MCGIP_FOOTER: DWORD = 3; +pub const MCGIP_CALENDAR: DWORD = 4; +pub const MCGIP_CALENDARHEADER: DWORD = 5; +pub const MCGIP_CALENDARBODY: DWORD = 6; +pub const MCGIP_CALENDARROW: DWORD = 7; +pub const MCGIP_CALENDARCELL: DWORD = 8; +pub const MCGIF_DATE: DWORD = 0x00000001; +pub const MCGIF_RECT: DWORD = 0x00000002; +pub const MCGIF_NAME: DWORD = 0x00000004; +STRUCT!{struct MCGRIDINFO { + cbSize: UINT, + dwPart: DWORD, + dwFlags: DWORD, + iCalendar: c_int, + iRow: c_int, + iCol: c_int, + bSelected: BOOL, + stStart: SYSTEMTIME, + stEnd: SYSTEMTIME, + rc: RECT, + pszName: PWSTR, + cchName: size_t, +}} +pub type PMCGRIDINFO = *mut MCGRIDINFO; +pub const MCM_GETCALENDARGRIDINFO: UINT = MCM_FIRST + 24; +pub const MCM_GETCALID: UINT = MCM_FIRST + 27; +pub const MCM_SETCALID: UINT = MCM_FIRST + 28; +pub const MCM_SIZERECTTOMIN: UINT = MCM_FIRST + 29; +pub const MCM_SETCALENDARBORDER: UINT = MCM_FIRST + 30; +pub const MCM_GETCALENDARBORDER: UINT = MCM_FIRST + 31; +pub const MCM_SETCURRENTVIEW: UINT = MCM_FIRST + 32; +STRUCT!{struct NMSELCHANGE { + nmhdr: NMHDR, + stSelStart: SYSTEMTIME, + stSelEnd: SYSTEMTIME, +}} +pub type LPNMSELCHANGE = *mut NMSELCHANGE; +pub const MCN_SELCHANGE: UINT = MCN_FIRST - 3; +STRUCT!{struct NMDAYSTATE { + nmhdr: NMHDR, + stStart: SYSTEMTIME, + cDayState: c_int, + prgDayState: LPMONTHDAYSTATE, +}} +pub type LPNMDAYSTATE = *mut NMDAYSTATE; +pub const MCN_GETDAYSTATE: UINT = MCN_FIRST - 1; +pub type NMSELECT = NMSELCHANGE; +pub type LPNMSELECT = *mut NMSELCHANGE; +pub const MCN_SELECT: UINT = MCN_FIRST; +STRUCT!{struct NMVIEWCHANGE { + nmhdr: NMHDR, + dwOldView: DWORD, + dwNewView: DWORD, +}} +pub type LPNMVIEWCHANGE = *mut NMVIEWCHANGE; +pub const MCN_VIEWCHANGE: UINT = MCN_FIRST - 4; +pub const MCS_DAYSTATE: DWORD = 0x0001; +pub const MCS_MULTISELECT: DWORD = 0x0002; +pub const MCS_WEEKNUMBERS: DWORD = 0x0004; +pub const MCS_NOTODAYCIRCLE: DWORD = 0x0008; +pub const MCS_NOTODAY: DWORD = 0x0010; +pub const MCS_NOTRAILINGDATES: DWORD = 0x0040; +pub const MCS_SHORTDAYSOFWEEK: DWORD = 0x0080; +pub const MCS_NOSELCHANGEONNAV: DWORD = 0x0100; +pub const GMR_VISIBLE: DWORD = 0; +pub const GMR_DAYSTATE: DWORD = 1; +pub const DATETIMEPICK_CLASS: &'static str = "SysDateTimePick32"; +STRUCT!{struct DATETIMEPICKERINFO { + cbSize: UINT, + rcCheck: RECT, + stateCheck: DWORD, + rcButton: RECT, + stateButton: DWORD, + hwndEdit: HWND, + hwndUD: HWND, + hwndDropDown: HWND, +}} +pub type LPDATETIMEPICKERINFO = *mut DATETIMEPICKERINFO; +pub const DTM_FIRST: UINT = 0x1000; +pub const DTM_GETSYSTEMTIME: UINT = DTM_FIRST + 1; +pub const DTM_SETSYSTEMTIME: UINT = DTM_FIRST + 2; +pub const DTM_GETRANGE: UINT = DTM_FIRST + 3; +pub const DTM_SETRANGE: UINT = DTM_FIRST + 4; +pub const DTM_SETFORMATA: UINT = DTM_FIRST + 5; +pub const DTM_SETFORMATW: UINT = DTM_FIRST + 50; +pub const DTM_SETMCCOLOR: UINT = DTM_FIRST + 6; +pub const DTM_GETMCCOLOR: UINT = DTM_FIRST + 7; +pub const DTM_GETMONTHCAL: UINT = DTM_FIRST + 8; +pub const DTM_SETMCFONT: UINT = DTM_FIRST + 9; +pub const DTM_GETMCFONT: UINT = DTM_FIRST + 10; +pub const DTM_SETMCSTYLE: UINT = DTM_FIRST + 11; +pub const DTM_GETMCSTYLE: UINT = DTM_FIRST + 12; +pub const DTM_CLOSEMONTHCAL: UINT = DTM_FIRST + 13; +pub const DTM_GETDATETIMEPICKERINFO: UINT = DTM_FIRST + 14; +pub const DTM_GETIDEALSIZE: UINT = DTM_FIRST + 15; +pub const DTS_UPDOWN: DWORD = 0x0001; +pub const DTS_SHOWNONE: DWORD = 0x0002; +pub const DTS_SHORTDATEFORMAT: DWORD = 0x0000; +pub const DTS_LONGDATEFORMAT: DWORD = 0x0004; +pub const DTS_SHORTDATECENTURYFORMAT: DWORD = 0x000C; +pub const DTS_TIMEFORMAT: DWORD = 0x0009; +pub const DTS_APPCANPARSE: DWORD = 0x0010; +pub const DTS_RIGHTALIGN: DWORD = 0x0020; +pub const DTN_DATETIMECHANGE: UINT = DTN_FIRST2 - 6; +STRUCT!{struct NMDATETIMECHANGE { + nmhdr: NMHDR, + dwFlags: DWORD, + st: SYSTEMTIME, +}} +pub type LPNMDATETIMECHANGE = *mut NMDATETIMECHANGE; +pub const DTN_USERSTRINGA: UINT = DTN_FIRST2 - 5; +pub const DTN_USERSTRINGW: UINT = DTN_FIRST - 5; +STRUCT!{struct NMDATETIMESTRINGA { + nmhdr: NMHDR, + pszUserString: LPCSTR, + st: SYSTEMTIME, + dwFlags: DWORD, +}} +pub type LPNMDATETIMESTRINGA = *mut NMDATETIMESTRINGA; +STRUCT!{struct NMDATETIMESTRINGW { + nmhdr: NMHDR, + pszUserString: LPCWSTR, + st: SYSTEMTIME, + dwFlags: DWORD, +}} +pub type LPNMDATETIMESTRINGW = *mut NMDATETIMESTRINGW; +pub const DTN_WMKEYDOWNA: UINT = DTN_FIRST2 - 4; +pub const DTN_WMKEYDOWNW: UINT = DTN_FIRST - 4; +STRUCT!{struct NMDATETIMEWMKEYDOWNA { + nmhdr: NMHDR, + nVirtKey: c_int, + pszFormat: LPCSTR, + st: SYSTEMTIME, +}} +pub type LPNMDATETIMEWMKEYDOWNA = *mut NMDATETIMEWMKEYDOWNA; +STRUCT!{struct NMDATETIMEWMKEYDOWNW { + nmhdr: NMHDR, + nVirtKey: c_int, + pszFormat: LPCWSTR, + st: SYSTEMTIME, +}} +pub type LPNMDATETIMEWMKEYDOWNW = *mut NMDATETIMEWMKEYDOWNW; +pub const DTN_FORMATA: UINT = DTN_FIRST2 - 3; +pub const DTN_FORMATW: UINT = DTN_FIRST - 3; +STRUCT!{struct NMDATETIMEFORMATA { + nmhdr: NMHDR, + pszFormat: LPCSTR, + st: SYSTEMTIME, + pszDisplay: LPCSTR, + szDisplay: [CHAR; 64], +}} +pub type LPNMDATETIMEFORMATA = *mut NMDATETIMEFORMATA; +STRUCT!{struct NMDATETIMEFORMATW { + nmhdr: NMHDR, + pszFormat: LPCWSTR, + st: SYSTEMTIME, + pszDisplay: LPCWSTR, + szDisplay: [WCHAR; 64], +}} +pub type LPNMDATETIMEFORMATW = *mut NMDATETIMEFORMATW; +pub const DTN_FORMATQUERYA: UINT = DTN_FIRST2 - 2; +pub const DTN_FORMATQUERYW: UINT = DTN_FIRST - 2; +STRUCT!{struct NMDATETIMEFORMATQUERYA { + nmhdr: NMHDR, + pszFormat: LPCSTR, + szMax: SIZE, +}} +pub type LPNMDATETIMEFORMATQUERYA = *mut NMDATETIMEFORMATQUERYA; +STRUCT!{struct NMDATETIMEFORMATQUERYW { + nmhdr: NMHDR, + pszFormat: LPCWSTR, + szMax: SIZE, +}} +pub type LPNMDATETIMEFORMATQUERYW = *mut NMDATETIMEFORMATQUERYW; +pub const DTN_DROPDOWN: UINT = DTN_FIRST2 - 1; +pub const DTN_CLOSEUP: UINT = DTN_FIRST2; +pub const GDTR_MIN: WPARAM = 0x0001; +pub const GDTR_MAX: WPARAM = 0x0002; +pub const GDT_ERROR: LRESULT = -1; +pub const GDT_VALID: LRESULT = 0; +pub const GDT_NONE: LRESULT = 1; +pub const IPM_CLEARADDRESS: UINT = WM_USER + 100; +pub const IPM_SETADDRESS: UINT = WM_USER + 101; +pub const IPM_GETADDRESS: UINT = WM_USER + 102; +pub const IPM_SETRANGE: UINT = WM_USER + 103; +pub const IPM_SETFOCUS: UINT = WM_USER + 104; +pub const IPM_ISBLANK: UINT = WM_USER + 105; +pub const WC_IPADDRESS: &'static str = "SysIPAddress32"; +pub const IPN_FIELDCHANGED: UINT = IPN_FIRST - 0; +STRUCT!{struct NMIPADDRESS { + hdr: NMHDR, + iField: c_int, + iValue: c_int, +}} +pub type LPNMIPADDRESS = *mut NMIPADDRESS; +#[inline] +pub fn MAKEIPRANGE(low: BYTE, high: BYTE) -> LPARAM { + (((high as WORD) << 8) + low as WORD) as LPARAM +} +#[inline] +pub fn MAKEIPADDRESS(b1: DWORD, b2: DWORD, b3: DWORD, b4: DWORD) -> LPARAM { + ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4) as LPARAM +} +#[inline] +pub fn FIRST_IPADDRESS(x: LPARAM) -> BYTE { + ((x >> 24) & 0xff) as BYTE +} +#[inline] +pub fn SECOND_IPADDRESS(x: LPARAM) -> BYTE { + ((x >> 16) & 0xff) as BYTE +} +#[inline] +pub fn THIRD_IPADDRESS(x: LPARAM) -> BYTE { + ((x >> 8) & 0xff) as BYTE +} +#[inline] +pub fn FOURTH_IPADDRESS(x: LPARAM) -> BYTE { + (x & 0xff) as BYTE +} +pub const WC_PAGESCROLLER: &'static str = "SysPager"; +pub const PGS_VERT: DWORD = 0x00000000; +pub const PGS_HORZ: DWORD = 0x00000001; +pub const PGS_AUTOSCROLL: DWORD = 0x00000002; +pub const PGS_DRAGNDROP: DWORD = 0x00000004; +pub const PGF_INVISIBLE: DWORD = 0; +pub const PGF_NORMAL: DWORD = 1; +pub const PGF_GRAYED: DWORD = 2; +pub const PGF_DEPRESSED: DWORD = 4; +pub const PGF_HOT: DWORD = 8; +pub const PGB_TOPORLEFT: c_int = 0; +pub const PGB_BOTTOMORRIGHT: c_int = 1; +pub const PGM_SETCHILD: UINT = PGM_FIRST + 1; +pub const PGM_RECALCSIZE: UINT = PGM_FIRST + 2; +pub const PGM_FORWARDMOUSE: UINT = PGM_FIRST + 3; +pub const PGM_SETBKCOLOR: UINT = PGM_FIRST + 4; +pub const PGM_GETBKCOLOR: UINT = PGM_FIRST + 5; +pub const PGM_SETBORDER: UINT = PGM_FIRST + 6; +pub const PGM_GETBORDER: UINT = PGM_FIRST + 7; +pub const PGM_SETPOS: UINT = PGM_FIRST + 8; +pub const PGM_GETPOS: UINT = PGM_FIRST + 9; +pub const PGM_SETBUTTONSIZE: UINT = PGM_FIRST + 10; +pub const PGM_GETBUTTONSIZE: UINT = PGM_FIRST + 11; +pub const PGM_GETBUTTONSTATE: UINT = PGM_FIRST + 12; +pub const PGM_GETDROPTARGET: UINT = CCM_GETDROPTARGET; +pub const PGM_SETSCROLLINFO: UINT = PGM_FIRST + 13; +pub const PGN_SCROLL: UINT = PGN_FIRST - 1; +pub const PGF_SCROLLUP: c_int = 1; +pub const PGF_SCROLLDOWN: c_int = 2; +pub const PGF_SCROLLLEFT: c_int = 4; +pub const PGF_SCROLLRIGHT: c_int = 8; +pub const PGK_SHIFT: BOOL = 1; +pub const PGK_CONTROL: BOOL = 2; +pub const PGK_MENU: BOOL = 4; +STRUCT!{#[repr(packed)] struct NMPGSCROLL { + hdr: NMHDR, + fwKeys: WORD, + rcParent: RECT, + iDir: c_int, + iXpos: c_int, + iYpos: c_int, + iScroll: c_int, +}} +pub type LPNMPGSCROLL = *mut NMPGSCROLL; +pub const PGN_CALCSIZE: UINT = PGN_FIRST - 2; +pub const PGF_CALCWIDTH: DWORD = 1; +pub const PGF_CALCHEIGHT: DWORD = 2; +STRUCT!{struct NMPGCALCSIZE { + hdr: NMHDR, + dwFlag: DWORD, + iWidth: c_int, + iHeight: c_int, +}} +pub type LPNMPGCALCSIZE = *mut NMPGCALCSIZE; +pub const PGN_HOTITEMCHANGE: UINT = PGN_FIRST - 3; +STRUCT!{struct NMPGHOTITEM { + hdr: NMHDR, + idOld: c_int, + idNew: c_int, + dwFlags: DWORD, +}} +pub type LPNMPGHOTITEM = *mut NMPGHOTITEM; +pub const WC_NATIVEFONTCTL: &'static str = "NativeFontCtl"; +pub const NFS_EDIT: DWORD = 0x0001; +pub const NFS_STATIC: DWORD = 0x0002; +pub const NFS_LISTCOMBO: DWORD = 0x0004; +pub const NFS_BUTTON: DWORD = 0x0008; +pub const NFS_ALL: DWORD = 0x0010; +pub const NFS_USEFONTASSOC: DWORD = 0x0020; +pub const WC_BUTTONA: &'static str = "Button"; +pub const BUTTON_IMAGELIST_ALIGN_LEFT: UINT = 0; +pub const BUTTON_IMAGELIST_ALIGN_RIGHT: UINT = 1; +pub const BUTTON_IMAGELIST_ALIGN_TOP: UINT = 2; +pub const BUTTON_IMAGELIST_ALIGN_BOTTOM: UINT = 3; +pub const BUTTON_IMAGELIST_ALIGN_CENTER: UINT = 4; +STRUCT!{struct BUTTON_IMAGELIST { + himl: HIMAGELIST, + margin: RECT, + uAlign: UINT, +}} +pub type PBUTTON_IMAGELIST = *mut BUTTON_IMAGELIST; +pub const BCM_GETIDEALSIZE: UINT = BCM_FIRST + 0x0001; +pub const BCM_SETIMAGELIST: UINT = BCM_FIRST + 0x0002; +pub const BCM_GETIMAGELIST: UINT = BCM_FIRST + 0x0003; +pub const BCM_SETTEXTMARGIN: UINT = BCM_FIRST + 0x0004; +pub const BCM_GETTEXTMARGIN: UINT = BCM_FIRST + 0x0005; +STRUCT!{struct NMBCHOTITEM { + hdr: NMHDR, + dwFlags: DWORD, +}} +pub type LPNMBCHOTITEM = *mut NMBCHOTITEM; +pub const BCN_HOTITEMCHANGE: UINT = BCN_FIRST + 0x0001; +pub const BS_SPLITBUTTON: UINT = 0x0000000C; +pub const BS_DEFSPLITBUTTON: UINT = 0x0000000D; +pub const BS_COMMANDLINK: UINT = 0x0000000E; +pub const BS_DEFCOMMANDLINK: UINT = 0x0000000F; +pub const BCSIF_GLYPH: UINT = 0x0001; +pub const BCSIF_IMAGE: UINT = 0x0002; +pub const BCSIF_STYLE: UINT = 0x0004; +pub const BCSIF_SIZE: UINT = 0x0008; +pub const BCSS_NOSPLIT: UINT = 0x0001; +pub const BCSS_STRETCH: UINT = 0x0002; +pub const BCSS_ALIGNLEFT: UINT = 0x0004; +pub const BCSS_IMAGE: UINT = 0x0008; +STRUCT!{struct BUTTON_SPLITINFO { + mask: UINT, + himlGlyph: HIMAGELIST, + uSplitStyle: UINT, + size: SIZE, +}} +pub type PBUTTON_SPLITINFO = *mut BUTTON_SPLITINFO; +pub const BCM_SETDROPDOWNSTATE: UINT = BCM_FIRST + 0x0006; +pub const BCM_SETSPLITINFO: UINT = BCM_FIRST + 0x0007; +pub const BCM_GETSPLITINFO: UINT = BCM_FIRST + 0x0008; +pub const BCM_SETNOTE: UINT = BCM_FIRST + 0x0009; +pub const BCM_GETNOTE: UINT = BCM_FIRST + 0x000A; +pub const BCM_GETNOTELENGTH: UINT = BCM_FIRST + 0x000B; +pub const BCM_SETSHIELD: UINT = BCM_FIRST + 0x000C; +pub const BCCL_NOGLYPH: HIMAGELIST = -1isize as HIMAGELIST; +STRUCT!{struct NMBCDROPDOWN { + hdr: NMHDR, + rcButton: RECT, +}} +pub type LPNMBCDROPDOWN = *mut NMBCDROPDOWN; +pub const BCN_DROPDOWN: UINT = BCN_FIRST + 0x0002; +pub const WC_STATIC: &'static str = "Static"; +pub const WC_EDIT: &'static str = "Edit"; +pub const EM_SETCUEBANNER: UINT = ECM_FIRST + 1; +pub const EM_GETCUEBANNER: UINT = ECM_FIRST + 2; +STRUCT!{struct EDITBALLOONTIP { + cbStruct: DWORD, + pszTitle: LPCWSTR, + pszText: LPCWSTR, + ttiIcon: INT, +}} +pub type PEDITBALLOONTIP = *mut EDITBALLOONTIP; +pub const EM_SHOWBALLOONTIP: UINT = ECM_FIRST + 3; +pub const EM_HIDEBALLOONTIP: UINT = ECM_FIRST + 4; +pub const EM_SETHILITE: UINT = ECM_FIRST + 5; +pub const EM_GETHILITE: UINT = ECM_FIRST + 6; +pub const EM_NOSETFOCUS: UINT = ECM_FIRST + 7; +pub const EM_TAKEFOCUS: UINT = ECM_FIRST + 8; +pub const WC_LISTBOX: &'static str = "ListBox"; +pub const WC_COMBOBOX: &'static str = "ComboBox"; +pub const CB_SETMINVISIBLE: UINT = CBM_FIRST + 1; +pub const CB_GETMINVISIBLE: UINT = CBM_FIRST + 2; +pub const CB_SETCUEBANNER: UINT = CBM_FIRST + 3; +pub const CB_GETCUEBANNER: UINT = CBM_FIRST + 4; +pub const WC_SCROLLBAR: &'static str = "ScrollBar"; +FN!{stdcall PFTASKDIALOGCALLBACK( + hwnd: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + lpRefData: LONG_PTR, +) -> HRESULT} +ENUM!{enum TASKDIALOG_FLAGS { + TDF_ENABLE_HYPERLINKS = 0x0001, + TDF_USE_HICON_MAIN = 0x0002, + TDF_USE_HICON_FOOTER = 0x0004, + TDF_ALLOW_DIALOG_CANCELLATION = 0x0008, + TDF_USE_COMMAND_LINKS = 0x0010, + TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020, + TDF_EXPAND_FOOTER_AREA = 0x0040, + TDF_EXPANDED_BY_DEFAULT = 0x0080, + TDF_VERIFICATION_FLAG_CHECKED = 0x0100, + TDF_SHOW_PROGRESS_BAR = 0x0200, + TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400, + TDF_CALLBACK_TIMER = 0x0800, + TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000, + TDF_RTL_LAYOUT = 0x2000, + TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000, + TDF_CAN_BE_MINIMIZED = 0x8000, + TDF_NO_SET_FOREGROUND = 0x00010000, + TDF_SIZE_TO_CONTENT = 0x01000000, +}} +ENUM!{enum TASKDIALOG_MESSAGES { + TDM_NAVIGATE_PAGE = WM_USER + 101, + TDM_CLICK_BUTTON = WM_USER + 102, + TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, + TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, + TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, + TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, + TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, + TDM_SET_ELEMENT_TEXT = WM_USER + 108, + TDM_CLICK_RADIO_BUTTON = WM_USER + 110, + TDM_ENABLE_BUTTON = WM_USER + 111, + TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, + TDM_CLICK_VERIFICATION = WM_USER + 113, + TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, + TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, + TDM_UPDATE_ICON = WM_USER + 116, +}} +ENUM!{enum TASKDIALOG_NOTIFICATIONS { + TDN_CREATED = 0, + TDN_NAVIGATED = 1, + TDN_BUTTON_CLICKED = 2, + TDN_HYPERLINK_CLICKED = 3, + TDN_TIMER = 4, + TDN_DESTROYED = 5, + TDN_RADIO_BUTTON_CLICKED = 6, + TDN_DIALOG_CONSTRUCTED = 7, + TDN_VERIFICATION_CLICKED = 8, + TDN_HELP = 9, + TDN_EXPANDO_BUTTON_CLICKED = 10, +}} +STRUCT!{#[repr(packed)] struct TASKDIALOG_BUTTON { + nButtonID: c_int, + pszButtonText: PCWSTR, +}} +ENUM!{enum TASKDIALOG_ELEMENTS { + TDE_CONTENT, + TDE_EXPANDED_INFORMATION, + TDE_FOOTER, + TDE_MAIN_INSTRUCTION, +}} +ENUM!{enum TASKDIALOG_ICON_ELEMENTS { + TDIE_ICON_MAIN, + TDIE_ICON_FOOTER, +}} +pub const TD_WARNING_ICON: LPWSTR = MAKEINTRESOURCE!(-1i16); +pub const TD_ERROR_ICON: LPWSTR = MAKEINTRESOURCE!(-2i16); +pub const TD_INFORMATION_ICON: LPWSTR = MAKEINTRESOURCE!(-3i16); +pub const TD_SHIELD_ICON: LPWSTR = MAKEINTRESOURCE!(-4i16); +ENUM!{enum TASKDIALOG_COMMON_BUTTON_FLAGS { + TDCBF_OK_BUTTON = 0x0001, + TDCBF_YES_BUTTON = 0x0002, + TDCBF_NO_BUTTON = 0x0004, + TDCBF_CANCEL_BUTTON = 0x0008, + TDCBF_RETRY_BUTTON = 0x0010, + TDCBF_CLOSE_BUTTON = 0x0020, +}} +UNION!{#[repr(packed)] union TASKDIALOGCONFIG_u1 { + [usize; 1], + hMainIcon hMainIcon_mut: HICON, + pszMainIcon pszMainIcon_mut: PCWSTR, +}} +UNION!{#[repr(packed)] union TASKDIALOGCONFIG_u2 { + [usize; 1], + hFooterIcon hFooterIcon_mut: HICON, + pszFooterIcon pszFooterIcon_mut: PCWSTR, +}} +STRUCT!{#[repr(packed)] struct TASKDIALOGCONFIG { + cbSize: UINT, + hwndParent: HWND, + hInstance: HINSTANCE, + dwFlags: TASKDIALOG_FLAGS, + dwCommonButtons: TASKDIALOG_COMMON_BUTTON_FLAGS, + pszWindowTitle: PCWSTR, + u1: TASKDIALOGCONFIG_u1, + pszMainInstruction: PCWSTR, + pszContent: PCWSTR, + cButtons: UINT, + pButtons: *const TASKDIALOG_BUTTON, + nDefaultButton: c_int, + cRadioButtons: UINT, + pRadioButtons: *const TASKDIALOG_BUTTON, + nDefaultRadioButton: c_int, + pszVerificationText: PCWSTR, + pszExpandedInformation: PCWSTR, + pszExpandedControlText: PCWSTR, + pszCollapsedControlText: PCWSTR, + u2: TASKDIALOGCONFIG_u2, + pszFooter: PCWSTR, + pfCallback: PFTASKDIALOGCALLBACK, + lpCallbackData: LONG_PTR, + cxWidth: UINT, +}} +extern "system" { + pub fn TaskDialogIndirect( + pTaskConfig: *const TASKDIALOGCONFIG, + pnButton: *mut c_int, + pnRadioButton: *mut c_int, + pfVerificationFlagChecked: *mut BOOL, + ) -> HRESULT; + pub fn TaskDialog( + hwndOwner: HWND, + hInstance: HINSTANCE, + pszWindowTitle: PCWSTR, + pszMainInstruction: PCWSTR, + pszContent: PCWSTR, + dwCommonButtons: TASKDIALOG_COMMON_BUTTON_FLAGS, + pszIcon: PCWSTR, + pnButton: *mut c_int, + ) -> HRESULT; + pub fn InitMUILanguage( + uiLang: LANGID, + ); + pub fn GetMUILanguage() -> LANGID; + pub fn _TrackMouseEvent( + lpEventTrack: LPTRACKMOUSEEVENT, + ) -> BOOL; +} +pub const WSB_PROP_CYVSCROLL: UINT = 0x00000001; +pub const WSB_PROP_CXHSCROLL: UINT = 0x00000002; +pub const WSB_PROP_CYHSCROLL: UINT = 0x00000004; +pub const WSB_PROP_CXVSCROLL: UINT = 0x00000008; +pub const WSB_PROP_CXHTHUMB: UINT = 0x00000010; +pub const WSB_PROP_CYVTHUMB: UINT = 0x00000020; +pub const WSB_PROP_VBKGCOLOR: UINT = 0x00000040; +pub const WSB_PROP_HBKGCOLOR: UINT = 0x00000080; +pub const WSB_PROP_VSTYLE: UINT = 0x00000100; +pub const WSB_PROP_HSTYLE: UINT = 0x00000200; +pub const WSB_PROP_WINSTYLE: UINT = 0x00000400; +pub const WSB_PROP_PALETTE: UINT = 0x00000800; +pub const WSB_PROP_MASK: UINT = 0x00000FFF; +pub const FSB_FLAT_MODE: INT_PTR = 2; +pub const FSB_ENCARTA_MODE: INT_PTR = 1; +pub const FSB_REGULAR_MODE: INT_PTR = 0; +extern "system" { + pub fn FlatSB_EnableScrollBar( + hWnd: HWND, + wSBflags: c_int, + wArrows: UINT, + ) -> BOOL; + pub fn FlatSB_ShowScrollBar( + hWnd: HWND, + code: c_int, + fShow: BOOL, + ) -> BOOL; + pub fn FlatSB_GetScrollRange( + hWnd: HWND, + code: c_int, + lpMinPos: LPINT, + lpMaxPos: LPINT, + ) -> BOOL; + pub fn FlatSB_GetScrollInfo( + hwnd: HWND, + code: c_int, + lpsi: LPSCROLLINFO, + ) -> BOOL; + pub fn FlatSB_GetScrollPos( + hWnd: HWND, + code: c_int, + ) -> c_int; + pub fn FlatSB_GetScrollProp(hWnd: HWND, + propIndex: c_int, + pValue: LPINT, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn FlatSB_GetScrollPropPtr( + hWnd: HWND, + propIndex: c_int, + pValue: PINT_PTR, + ) -> BOOL; + pub fn FlatSB_SetScrollPos( + hWnd: HWND, + code: c_int, + pos: c_int, + fRedraw: BOOL, + ) -> c_int; + pub fn FlatSB_SetScrollInfo( + hWnd: HWND, + code: c_int, + psi: LPSCROLLINFO, + fRedraw: BOOL, + ) -> c_int; + pub fn FlatSB_SetScrollRange( + hWnd: HWND, + code: c_int, + min: c_int, + max: c_int, + fRedraw: BOOL, + ) -> c_int; + pub fn FlatSB_SetScrollProp( + hWnd: HWND, + index: UINT, + newValue: INT_PTR, + fRedraw: BOOL, + ) -> BOOL; + pub fn InitializeFlatSB( + hWnd: HWND, + ) -> BOOL; + pub fn UninitializeFlatSB( + hWnd: HWND, + ) -> HRESULT; +} +FN!{stdcall SUBCLASSPROC( + hWnd: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + uIdSubclass: UINT_PTR, + dwRefData: DWORD_PTR, +) -> LRESULT} +extern "system" { + pub fn SetWindowSubclass( + hWnd: HWND, + pfnSubclass: SUBCLASSPROC, + uIdSubclass: UINT_PTR, + dwRefData: DWORD_PTR, + ) -> BOOL; + pub fn GetWindowSubclass( + hWnd: HWND, + pfnSubclass: SUBCLASSPROC, + uIdSubclass: UINT_PTR, + pdwRefData: *mut DWORD_PTR, + ) -> BOOL; + pub fn RemoveWindowSubclass( + hWnd: HWND, + pfnSubclass: SUBCLASSPROC, + uIdSubclass: UINT_PTR, + ) -> BOOL; + pub fn DefSubclassProc( + hWnd: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; +} +ENUM!{enum REGCLS { + LIM_SMALL, + LIM_LARGE, +}} +extern "system" { + pub fn LoadIconMetric( + hinst: HINSTANCE, + pszName: PCWSTR, + lims: c_int, + phico: *mut HICON, + ) -> HRESULT; + pub fn LoadIconWithScaleDown( + hinst: HINSTANCE, + pszName: PCWSTR, + cx: c_int, + cy: c_int, + phico: *mut HICON, + ) -> HRESULT; + pub fn DrawShadowText( + hdc: HDC, + pszText: LPCWSTR, + cch: UINT, + prc: *mut RECT, + dwFlags: DWORD, + crText: COLORREF, + crShadow: COLORREF, + ixOffset: c_int, + iyOffset: c_int, + ) -> c_int; +} diff --git a/winapi/src/um/commdlg.rs b/winapi/src/um/commdlg.rs new file mode 100644 index 000000000..c9326a6fc --- /dev/null +++ b/winapi/src/um/commdlg.rs @@ -0,0 +1,712 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! 32-Bit Common Dialog APIs +use ctypes::{c_short, c_void}; +use shared::basetsd::UINT_PTR; +use shared::minwindef::{ + BOOL, DWORD, HGLOBAL, HINSTANCE, INT, LPARAM, LPVOID, LRESULT, UINT, WORD, WPARAM, +}; +use shared::windef::{COLORREF, HDC, HWND, POINT, RECT}; +use um::prsht::HPROPSHEETPAGE; +use um::unknwnbase::{IUnknown, IUnknownVtbl, LPUNKNOWN}; +use um::wingdi::{DM_COLLATE, DM_COPIES, LPDEVMODEW, LPLOGFONTA, LPLOGFONTW}; +use um::winnt::{HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR}; +use um::winuser::{NMHDR, WM_USER}; +FN!{stdcall LPOFNHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPENFILENAME_NT4A { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpstrFilter: LPCSTR, + lpstrCustomFilter: LPSTR, + nMaxCustFilter: DWORD, + nFilterIndex: DWORD, + lpstrFile: LPSTR, + nMaxFile: DWORD, + lpstrFileTitle: LPSTR, + nMaxFileTitle: DWORD, + lpstrInitialDir: LPCSTR, + lpstrTitle: LPCSTR, + Flags: DWORD, + nFileOffset: WORD, + nFileExtension: WORD, + lpstrDefExt: LPCSTR, + lCustData: LPARAM, + lpfnHook: LPOFNHOOKPROC, + lpTemplateName: LPCSTR, +}} +pub type LPOPENFILENAME_NT4A = *mut OPENFILENAME_NT4A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPENFILENAME_NT4W { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpstrFilter: LPCWSTR, + lpstrCustomFilter: LPWSTR, + nMaxCustFilter: DWORD, + nFilterIndex: DWORD, + lpstrFile: LPWSTR, + nMaxFile: DWORD, + lpstrFileTitle: LPWSTR, + nMaxFileTitle: DWORD, + lpstrInitialDir: LPCWSTR, + lpstrTitle: LPCWSTR, + Flags: DWORD, + nFileOffset: WORD, + nFileExtension: WORD, + lpstrDefExt: LPCWSTR, + lCustData: LPARAM, + lpfnHook: LPOFNHOOKPROC, + lpTemplateName: LPCWSTR, +}} +pub type LPOPENFILENAME_NT4W = *mut OPENFILENAME_NT4W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPENFILENAMEA { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpstrFilter: LPCSTR, + lpstrCustomFilter: LPSTR, + nMaxCustFilter: DWORD, + nFilterIndex: DWORD, + lpstrFile: LPSTR, + nMaxFile: DWORD, + lpstrFileTitle: LPSTR, + nMaxFileTitle: DWORD, + lpstrInitialDir: LPCSTR, + lpstrTitle: LPCSTR, + Flags: DWORD, + nFileOffset: WORD, + nFileExtension: WORD, + lpstrDefExt: LPCSTR, + lCustData: LPARAM, + lpfnHook: LPOFNHOOKPROC, + lpTemplateName: LPCSTR, + pvReserved: *mut c_void, + dwReserved: DWORD, + FlagsEx: DWORD, +}} +pub type LPOPENFILENAMEA = *mut OPENFILENAMEA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPENFILENAMEW { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpstrFilter: LPCWSTR, + lpstrCustomFilter: LPWSTR, + nMaxCustFilter: DWORD, + nFilterIndex: DWORD, + lpstrFile: LPWSTR, + nMaxFile: DWORD, + lpstrFileTitle: LPWSTR, + nMaxFileTitle: DWORD, + lpstrInitialDir: LPCWSTR, + lpstrTitle: LPCWSTR, + Flags: DWORD, + nFileOffset: WORD, + nFileExtension: WORD, + lpstrDefExt: LPCWSTR, + lCustData: LPARAM, + lpfnHook: LPOFNHOOKPROC, + lpTemplateName: LPCWSTR, + pvReserved: *mut c_void, + dwReserved: DWORD, + FlagsEx: DWORD, +}} +pub type LPOPENFILENAMEW = *mut OPENFILENAMEW; +extern "system" { + pub fn GetOpenFileNameA( + lpofn: LPOPENFILENAMEA, + ) -> BOOL; + pub fn GetOpenFileNameW( + lpofn: LPOPENFILENAMEW, + ) -> BOOL; + pub fn GetSaveFileNameA( + lpofn: LPOPENFILENAMEA, + ) -> BOOL; + pub fn GetSaveFileNameW( + lpofn: LPOPENFILENAMEW, + ) -> BOOL; + pub fn GetFileTitleA( + lpszFile: LPCSTR, + Buf: LPSTR, + cchSize: WORD, + ) -> c_short; + pub fn GetFileTitleW( + lpszFile: LPCWSTR, + Buf: LPWSTR, + cchSize: WORD, + ) -> c_short; +} +pub const OFN_READONLY: DWORD = 0x00000001; +pub const OFN_OVERWRITEPROMPT: DWORD = 0x00000002; +pub const OFN_HIDEREADONLY: DWORD = 0x00000004; +pub const OFN_NOCHANGEDIR: DWORD = 0x00000008; +pub const OFN_SHOWHELP: DWORD = 0x00000010; +pub const OFN_ENABLEHOOK: DWORD = 0x00000020; +pub const OFN_ENABLETEMPLATE: DWORD = 0x00000040; +pub const OFN_ENABLETEMPLATEHANDLE: DWORD = 0x00000080; +pub const OFN_NOVALIDATE: DWORD = 0x00000100; +pub const OFN_ALLOWMULTISELECT: DWORD = 0x00000200; +pub const OFN_EXTENSIONDIFFERENT: DWORD = 0x00000400; +pub const OFN_PATHMUSTEXIST: DWORD = 0x00000800; +pub const OFN_FILEMUSTEXIST: DWORD = 0x00001000; +pub const OFN_CREATEPROMPT: DWORD = 0x00002000; +pub const OFN_SHAREAWARE: DWORD = 0x00004000; +pub const OFN_NOREADONLYRETURN: DWORD = 0x00008000; +pub const OFN_NOTESTFILECREATE: DWORD = 0x00010000; +pub const OFN_NONETWORKBUTTON: DWORD = 0x00020000; +pub const OFN_NOLONGNAMES: DWORD = 0x00040000; +pub const OFN_EXPLORER: DWORD = 0x00080000; +pub const OFN_NODEREFERENCELINKS: DWORD = 0x00100000; +pub const OFN_LONGNAMES: DWORD = 0x00200000; +pub const OFN_ENABLEINCLUDENOTIFY: DWORD = 0x00400000; +pub const OFN_ENABLESIZING: DWORD = 0x00800000; +pub const OFN_DONTADDTORECENT: DWORD = 0x02000000; +pub const OFN_FORCESHOWHIDDEN: DWORD = 0x10000000; +pub const OFN_EX_NOPLACESBAR: DWORD = 0x00000001; +pub const OFN_SHAREFALLTHROUGH: UINT_PTR = 2; +pub const OFN_SHARENOWARN: UINT_PTR = 1; +pub const OFN_SHAREWARN: UINT_PTR = 0; +FN!{stdcall LPCCHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OFNOTIFYA { + hdr: NMHDR, + lpOFN: LPOPENFILENAMEA, + pszFile: LPSTR, +}} +pub type LPOFNOTIFYA = *mut OFNOTIFYA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OFNOTIFYW { + hdr: NMHDR, + lpOFN: LPOPENFILENAMEW, + pszFile: LPWSTR, +}} +pub type LPOFNOTIFYW = *mut OFNOTIFYW; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OFNOTIFYEXA { + hdr: NMHDR, + lpOFN: LPOPENFILENAMEA, + psf: LPVOID, + pidl: LPVOID, +}} +pub type LPOFNOTIFYEXA = *mut OFNOTIFYEXA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OFNOTIFYEXW { + hdr: NMHDR, + lpOFN: LPOPENFILENAMEW, + psf: LPVOID, + pidl: LPVOID, +}} +pub type LPOFNOTIFYEXW = *mut OFNOTIFYEXW; +pub const CDN_FIRST: UINT = -601i32 as u32; +pub const CDN_LAST: UINT = -699i32 as u32; +pub const CDN_INITDONE: UINT = CDN_FIRST - 0x0000; +pub const CDN_SELCHANGE: UINT = CDN_FIRST - 0x0001; +pub const CDN_FOLDERCHANGE: UINT = CDN_FIRST - 0x0002; +pub const CDN_SHAREVIOLATION: UINT = CDN_FIRST - 0x0003; +pub const CDN_HELP: UINT = CDN_FIRST - 0x0004; +pub const CDN_FILEOK: UINT = CDN_FIRST - 0x0005; +pub const CDN_TYPECHANGE: UINT = CDN_FIRST - 0x0006; +pub const CDN_INCLUDEITEM: UINT = CDN_FIRST - 0x0007; +pub const CDM_FIRST: UINT = WM_USER + 100; +pub const CDM_LAST: UINT = WM_USER + 200; +pub const CDM_GETSPEC: UINT = CDM_FIRST + 0x0000; +pub const CDM_GETFILEPATH: UINT = CDM_FIRST + 0x0001; +pub const CDM_GETFOLDERPATH: UINT = CDM_FIRST + 0x0002; +pub const CDM_GETFOLDERIDLIST: UINT = CDM_FIRST + 0x0003; +pub const CDM_SETCONTROLTEXT: UINT = CDM_FIRST + 0x0004; +pub const CDM_HIDECONTROL: UINT = CDM_FIRST + 0x0005; +pub const CDM_SETDEFEXT: UINT = CDM_FIRST + 0x0006; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CHOOSECOLORA { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HWND, + rgbResult: COLORREF, + lpCustColors: *mut COLORREF, + Flags: DWORD, + lCustData: LPARAM, + lpfnHook: LPCCHOOKPROC, + lpTemplateName: LPCSTR, +}} +pub type LPCHOOSECOLORA = *mut CHOOSECOLORA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CHOOSECOLORW { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HWND, + rgbResult: COLORREF, + lpCustColors: *mut COLORREF, + Flags: DWORD, + lCustData: LPARAM, + lpfnHook: LPCCHOOKPROC, + lpTemplateName: LPCWSTR, +}} +pub type LPCHOOSECOLORW = *mut CHOOSECOLORW; +extern "system" { + pub fn ChooseColorA( + lpcc: LPCHOOSECOLORA, + ) -> BOOL; + pub fn ChooseColorW( + lpcc: LPCHOOSECOLORW, + ) -> BOOL; +} +pub const CC_RGBINIT: DWORD = 0x00000001; +pub const CC_FULLOPEN: DWORD = 0x00000002; +pub const CC_PREVENTFULLOPEN: DWORD = 0x00000004; +pub const CC_SHOWHELP: DWORD = 0x00000008; +pub const CC_ENABLEHOOK: DWORD = 0x00000010; +pub const CC_ENABLETEMPLATE: DWORD = 0x00000020; +pub const CC_ENABLETEMPLATEHANDLE: DWORD = 0x00000040; +pub const CC_SOLIDCOLOR: DWORD = 0x00000080; +pub const CC_ANYCOLOR: DWORD = 0x00000100; +FN!{stdcall LPFRHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FINDREPLACEA { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + Flags: DWORD, + lpstrFindWhat: LPSTR, + lpstrReplaceWith: LPSTR, + wFindWhatLen: WORD, + wReplaceWithLen: WORD, + lCustData: LPARAM, + lpfnHook: LPFRHOOKPROC, + lpTemplateName: LPCSTR, +}} +pub type LPFINDREPLACEA = *mut FINDREPLACEA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FINDREPLACEW { + lStructSize: DWORD, + hwndOwner: HWND, + hInstance: HINSTANCE, + Flags: DWORD, + lpstrFindWhat: LPWSTR, + lpstrReplaceWith: LPWSTR, + wFindWhatLen: WORD, + wReplaceWithLen: WORD, + lCustData: LPARAM, + lpfnHook: LPFRHOOKPROC, + lpTemplateName: LPCWSTR, +}} +pub type LPFINDREPLACEW = *mut FINDREPLACEW; +pub const FR_DOWN: DWORD = 0x00000001; +pub const FR_WHOLEWORD: DWORD = 0x00000002; +pub const FR_MATCHCASE: DWORD = 0x00000004; +pub const FR_FINDNEXT: DWORD = 0x00000008; +pub const FR_REPLACE: DWORD = 0x00000010; +pub const FR_REPLACEALL: DWORD = 0x00000020; +pub const FR_DIALOGTERM: DWORD = 0x00000040; +pub const FR_SHOWHELP: DWORD = 0x00000080; +pub const FR_ENABLEHOOK: DWORD = 0x00000100; +pub const FR_ENABLETEMPLATE: DWORD = 0x00000200; +pub const FR_NOUPDOWN: DWORD = 0x00000400; +pub const FR_NOMATCHCASE: DWORD = 0x00000800; +pub const FR_NOWHOLEWORD: DWORD = 0x00001000; +pub const FR_ENABLETEMPLATEHANDLE: DWORD = 0x00002000; +pub const FR_HIDEUPDOWN: DWORD = 0x00004000; +pub const FR_HIDEMATCHCASE: DWORD = 0x00008000; +pub const FR_HIDEWHOLEWORD: DWORD = 0x00010000; +pub const FR_RAW: DWORD = 0x00020000; +pub const FR_MATCHDIAC: DWORD = 0x20000000; +pub const FR_MATCHKASHIDA: DWORD = 0x40000000; +pub const FR_MATCHALEFHAMZA: DWORD = 0x80000000; +extern "system" { + pub fn FindTextA( + lpfr: LPFINDREPLACEA, + ) -> HWND; + pub fn FindTextW( + lpfr: LPFINDREPLACEW, + ) -> HWND; + pub fn ReplaceTextA( + lpfr: LPFINDREPLACEA, + ) -> HWND; + pub fn ReplaceTextW( + lpfr: LPFINDREPLACEW, + ) -> HWND; +} +FN!{stdcall LPCFHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CHOOSEFONTA { + lStructSize: DWORD, + hwndOwner: HWND, + hDC: HDC, + lpLogFont: LPLOGFONTA, + iPointSize: INT, + Flags: DWORD, + rgbColors: COLORREF, + lCustData: LPARAM, + lpfnHook: LPCFHOOKPROC, + lpTemplateName: LPCSTR, + hInstance: HINSTANCE, + lpszStyle: LPSTR, + nFontType: WORD, + ___MISSING_ALIGNMENT__: WORD, + nSizeMin: INT, + nSizeMax: INT, +}} +pub type LPCHOOSEFONTA = *mut CHOOSEFONTA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CHOOSEFONTW { + lStructSize: DWORD, + hwndOwner: HWND, + hDC: HDC, + lpLogFont: LPLOGFONTW, + iPointSize: INT, + Flags: DWORD, + rgbColors: COLORREF, + lCustData: LPARAM, + lpfnHook: LPCFHOOKPROC, + lpTemplateName: LPCWSTR, + hInstance: HINSTANCE, + lpszStyle: LPWSTR, + nFontType: WORD, + ___MISSING_ALIGNMENT__: WORD, + nSizeMin: INT, + nSizeMax: INT, +}} +pub type LPCHOOSEFONTW = *mut CHOOSEFONTW; +extern "system" { + pub fn ChooseFontA( + lpcf: LPCHOOSEFONTA, + ) -> BOOL; + pub fn ChooseFontW( + lpcf: LPCHOOSEFONTW, + ) -> BOOL; +} +pub const CF_SCREENFONTS: DWORD = 0x00000001; +pub const CF_PRINTERFONTS: DWORD = 0x00000002; +pub const CF_BOTH: DWORD = CF_SCREENFONTS | CF_PRINTERFONTS; +pub const CF_SHOWHELP: DWORD = 0x00000004; +pub const CF_ENABLEHOOK: DWORD = 0x00000008; +pub const CF_ENABLETEMPLATE: DWORD = 0x00000010; +pub const CF_ENABLETEMPLATEHANDLE: DWORD = 0x00000020; +pub const CF_INITTOLOGFONTSTRUCT: DWORD = 0x00000040; +pub const CF_USESTYLE: DWORD = 0x00000080; +pub const CF_EFFECTS: DWORD = 0x00000100; +pub const CF_APPLY: DWORD = 0x00000200; +pub const CF_ANSIONLY: DWORD = 0x00000400; +pub const CF_SCRIPTSONLY: DWORD = CF_ANSIONLY; +pub const CF_NOVECTORFONTS: DWORD = 0x00000800; +pub const CF_NOOEMFONTS: DWORD = CF_NOVECTORFONTS; +pub const CF_NOSIMULATIONS: DWORD = 0x00001000; +pub const CF_LIMITSIZE: DWORD = 0x00002000; +pub const CF_FIXEDPITCHONLY: DWORD = 0x00004000; +pub const CF_WYSIWYG: DWORD = 0x00008000; +pub const CF_FORCEFONTEXIST: DWORD = 0x00010000; +pub const CF_SCALABLEONLY: DWORD = 0x00020000; +pub const CF_TTONLY: DWORD = 0x00040000; +pub const CF_NOFACESEL: DWORD = 0x00080000; +pub const CF_NOSTYLESEL: DWORD = 0x00100000; +pub const CF_NOSIZESEL: DWORD = 0x00200000; +pub const CF_SELECTSCRIPT: DWORD = 0x00400000; +pub const CF_NOSCRIPTSEL: DWORD = 0x00800000; +pub const CF_NOVERTFONTS: DWORD = 0x01000000; +pub const CF_INACTIVEFONTS: DWORD = 0x02000000; +pub const SIMULATED_FONTTYPE: WORD = 0x8000; +pub const PRINTER_FONTTYPE: WORD = 0x4000; +pub const SCREEN_FONTTYPE: WORD = 0x2000; +pub const BOLD_FONTTYPE: WORD = 0x0100; +pub const ITALIC_FONTTYPE: WORD = 0x0200; +pub const REGULAR_FONTTYPE: WORD = 0x0400; +pub const PS_OPENTYPE_FONTTYPE: DWORD = 0x10000; +pub const TT_OPENTYPE_FONTTYPE: DWORD = 0x20000; +pub const TYPE1_FONTTYPE: DWORD = 0x40000; +pub const SYMBOL_FONTTYPE: DWORD = 0x80000; +pub const WM_CHOOSEFONT_GETLOGFONT: UINT = WM_USER + 1; +pub const WM_CHOOSEFONT_SETLOGFONT: UINT = WM_USER + 101; +pub const WM_CHOOSEFONT_SETFLAGS: UINT = WM_USER + 102; +pub const CD_LBSELNOITEMS: WORD = -1i16 as u16; +pub const CD_LBSELCHANGE: WORD = 0; +pub const CD_LBSELSUB: WORD = 1; +pub const CD_LBSELADD: WORD = 2; +FN!{stdcall LPPRINTHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +FN!{stdcall LPSETUPHOOKPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PRINTDLGA { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + hDC: HDC, + Flags: DWORD, + nFromPage: WORD, + nToPage: WORD, + nMinPage: WORD, + nMaxPage: WORD, + nCopies: WORD, + hInstance: HINSTANCE, + lCustData: LPARAM, + lpfnPrintHook: LPPRINTHOOKPROC, + lpfnSetupHook: LPSETUPHOOKPROC, + lpPrintTemplateName: LPCSTR, + lpSetupTemplateName: LPCSTR, + hPrintTemplate: HGLOBAL, + hSetupTemplate: HGLOBAL, +}} +pub type LPPRINTDLGA = *mut PRINTDLGA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PRINTDLGW { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + hDC: HDC, + Flags: DWORD, + nFromPage: WORD, + nToPage: WORD, + nMinPage: WORD, + nMaxPage: WORD, + nCopies: WORD, + hInstance: HINSTANCE, + lCustData: LPARAM, + lpfnPrintHook: LPPRINTHOOKPROC, + lpfnSetupHook: LPSETUPHOOKPROC, + lpPrintTemplateName: LPCWSTR, + lpSetupTemplateName: LPCWSTR, + hPrintTemplate: HGLOBAL, + hSetupTemplate: HGLOBAL, +}} +pub type LPPRINTDLGW = *mut PRINTDLGW; +extern "system" { + pub fn PrintDlgA( + pPD: LPPRINTDLGA, + ) -> BOOL; + pub fn PrintDlgW( + pPD: LPPRINTDLGW, + ) -> BOOL; +} +RIDL!{#[uuid(0x5852a2c3, 0x6530, 0x11d1, 0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9)] +interface IPrintDialogCallback(IPrintDialogCallbackVtbl): IUnknown(IUnknownVtbl) { + fn InitDone() -> HRESULT, + fn SelectionChange() -> HRESULT, + fn HandleMessage( + hDlg: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + pResult: *mut LRESULT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x509aaeda, 0x5639, 0x11d1, 0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9)] +interface IPrintDialogServices(IPrintDialogServicesVtbl): IUnknown(IUnknownVtbl) { + fn GetCurrentDevMode( + pDevMode: LPDEVMODEW, + pcbSize: *mut UINT, + ) -> HRESULT, + fn GetCurrentPrinterName( + pPrinterName: LPWSTR, + pcchSize: *mut UINT, + ) -> HRESULT, + fn GetCurrentPortName( + pPortName: LPWSTR, + pcchSize: *mut UINT, + ) -> HRESULT, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PRINTPAGERANGE { + nFromPage: DWORD, + nToPage: DWORD, +}} +pub type LPPRINTPAGERANGE = *mut PRINTPAGERANGE; +pub type PCPRINTPAGERANGE = *const PRINTPAGERANGE; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PRINTDLGEXA { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + hDC: HDC, + Flags: DWORD, + Flags2: DWORD, + ExclusionFlags: DWORD, + nPageRanges: DWORD, + nMaxPageRanges: DWORD, + lpPageRanges: LPPRINTPAGERANGE, + nMinPage: DWORD, + nMaxPage: DWORD, + nCopies: DWORD, + hInstance: HINSTANCE, + lpPrintTemplateName: LPCSTR, + lpCallback: LPUNKNOWN, + nPropertyPages: DWORD, + lphPropertyPages: *mut HPROPSHEETPAGE, + nStartPage: DWORD, + dwResultAction: DWORD, +}} +pub type LPPRINTDLGEXA = *mut PRINTDLGEXA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PRINTDLGEXW { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + hDC: HDC, + Flags: DWORD, + Flags2: DWORD, + ExclusionFlags: DWORD, + nPageRanges: DWORD, + nMaxPageRanges: DWORD, + lpPageRanges: LPPRINTPAGERANGE, + nMinPage: DWORD, + nMaxPage: DWORD, + nCopies: DWORD, + hInstance: HINSTANCE, + lpPrintTemplateName: LPCWSTR, + lpCallback: LPUNKNOWN, + nPropertyPages: DWORD, + lphPropertyPages: *mut HPROPSHEETPAGE, + nStartPage: DWORD, + dwResultAction: DWORD, +}} +pub type LPPRINTDLGEXW = *mut PRINTDLGEXW; +extern "system" { + pub fn PrintDlgExA( + pPD: LPPRINTDLGEXA, + ) -> HRESULT; + pub fn PrintDlgExW( + pPD: LPPRINTDLGEXW, + ) -> HRESULT; +} +pub const PD_ALLPAGES: DWORD = 0x00000000; +pub const PD_SELECTION: DWORD = 0x00000001; +pub const PD_PAGENUMS: DWORD = 0x00000002; +pub const PD_NOSELECTION: DWORD = 0x00000004; +pub const PD_NOPAGENUMS: DWORD = 0x00000008; +pub const PD_COLLATE: DWORD = 0x00000010; +pub const PD_PRINTTOFILE: DWORD = 0x00000020; +pub const PD_PRINTSETUP: DWORD = 0x00000040; +pub const PD_NOWARNING: DWORD = 0x00000080; +pub const PD_RETURNDC: DWORD = 0x00000100; +pub const PD_RETURNIC: DWORD = 0x00000200; +pub const PD_RETURNDEFAULT: DWORD = 0x00000400; +pub const PD_SHOWHELP: DWORD = 0x00000800; +pub const PD_ENABLEPRINTHOOK: DWORD = 0x00001000; +pub const PD_ENABLESETUPHOOK: DWORD = 0x00002000; +pub const PD_ENABLEPRINTTEMPLATE: DWORD = 0x00004000; +pub const PD_ENABLESETUPTEMPLATE: DWORD = 0x00008000; +pub const PD_ENABLEPRINTTEMPLATEHANDLE: DWORD = 0x00010000; +pub const PD_ENABLESETUPTEMPLATEHANDLE: DWORD = 0x00020000; +pub const PD_USEDEVMODECOPIES: DWORD = 0x00040000; +pub const PD_USEDEVMODECOPIESANDCOLLATE: DWORD = 0x00040000; +pub const PD_DISABLEPRINTTOFILE: DWORD = 0x00080000; +pub const PD_HIDEPRINTTOFILE: DWORD = 0x00100000; +pub const PD_NONETWORKBUTTON: DWORD = 0x00200000; +pub const PD_CURRENTPAGE: DWORD = 0x00400000; +pub const PD_NOCURRENTPAGE: DWORD = 0x00800000; +pub const PD_EXCLUSIONFLAGS: DWORD = 0x01000000; +pub const PD_USELARGETEMPLATE: DWORD = 0x10000000; +pub const PD_EXCL_COPIESANDCOLLATE: DWORD = DM_COPIES | DM_COLLATE; +pub const START_PAGE_GENERAL: DWORD = 0xffffffff; +pub const PD_RESULT_CANCEL: DWORD = 0; +pub const PD_RESULT_PRINT: DWORD = 1; +pub const PD_RESULT_APPLY: DWORD = 2; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct DEVNAMES { + wDriverOffset: WORD, + wDeviceOffset: WORD, + wOutputOffset: WORD, + wDefault: WORD, +}} +pub type LPDEVNAMES = *mut DEVNAMES; +pub type PCDEVNAMES = *const DEVNAMES; +pub const DN_DEFAULTPRN: WORD = 0x0001; +extern "system" { + pub fn CommDlgExtendedError() -> DWORD; +} +pub const WM_PSD_PAGESETUPDLG: UINT = WM_USER; +pub const WM_PSD_FULLPAGERECT: UINT = WM_USER + 1; +pub const WM_PSD_MINMARGINRECT: UINT = WM_USER + 2; +pub const WM_PSD_MARGINRECT: UINT = WM_USER + 3; +pub const WM_PSD_GREEKTEXTRECT: UINT = WM_USER + 4; +pub const WM_PSD_ENVSTAMPRECT: UINT = WM_USER + 5; +pub const WM_PSD_YAFULLPAGERECT: UINT = WM_USER + 6; +FN!{stdcall LPPAGEPAINTHOOK( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +FN!{stdcall LPPAGESETUPHOOK( + HWND, + UINT, + WPARAM, + LPARAM, +) -> UINT_PTR} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PAGESETUPDLGA { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + Flags: DWORD, + ptPaperSize: POINT, + rtMinMargin: RECT, + rtMargin: RECT, + hInstance: HINSTANCE, + lCustData: LPARAM, + lpfnPageSetupHook: LPPAGESETUPHOOK, + lpfnPagePaintHook: LPPAGEPAINTHOOK, + lpPageSetupTemplateName: LPCSTR, + hPageSetupTemplate: HGLOBAL, +}} +pub type LPPAGESETUPDLGA = *mut PAGESETUPDLGA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct PAGESETUPDLGW { + lStructSize: DWORD, + hwndOwner: HWND, + hDevMode: HGLOBAL, + hDevNames: HGLOBAL, + Flags: DWORD, + ptPaperSize: POINT, + rtMinMargin: RECT, + rtMargin: RECT, + hInstance: HINSTANCE, + lCustData: LPARAM, + lpfnPageSetupHook: LPPAGESETUPHOOK, + lpfnPagePaintHook: LPPAGEPAINTHOOK, + lpPageSetupTemplateName: LPCWSTR, + hPageSetupTemplate: HGLOBAL, +}} +pub type LPPAGESETUPDLGW = *mut PAGESETUPDLGW; +extern "system" { + pub fn PageSetupDlgA( + lppsd: LPPAGESETUPDLGA, + ) -> BOOL; + pub fn PageSetupDlgW( + lppsd: LPPAGESETUPDLGW, + ) -> BOOL; +} +pub const PSD_DEFAULTMINMARGINS: DWORD = 0x00000000; +pub const PSD_INWININIINTLMEASURE: DWORD = 0x00000000; +pub const PSD_MINMARGINS: DWORD = 0x00000001; +pub const PSD_MARGINS: DWORD = 0x00000002; +pub const PSD_INTHOUSANDTHSOFINCHES: DWORD = 0x00000004; +pub const PSD_INHUNDREDTHSOFMILLIMETERS: DWORD = 0x00000008; +pub const PSD_DISABLEMARGINS: DWORD = 0x00000010; +pub const PSD_DISABLEPRINTER: DWORD = 0x00000020; +pub const PSD_NOWARNING: DWORD = 0x00000080; +pub const PSD_DISABLEORIENTATION: DWORD = 0x00000100; +pub const PSD_RETURNDEFAULT: DWORD = 0x00000400; +pub const PSD_DISABLEPAPER: DWORD = 0x00000200; +pub const PSD_SHOWHELP: DWORD = 0x00000800; +pub const PSD_ENABLEPAGESETUPHOOK: DWORD = 0x00002000; +pub const PSD_ENABLEPAGESETUPTEMPLATE: DWORD = 0x00008000; +pub const PSD_ENABLEPAGESETUPTEMPLATEHANDLE: DWORD = 0x00020000; +pub const PSD_ENABLEPAGEPAINTHOOK: DWORD = 0x00040000; +pub const PSD_DISABLEPAGEPAINTING: DWORD = 0x00080000; +pub const PSD_NONETWORKBUTTON: DWORD = 0x00200000; diff --git a/winapi/src/um/commoncontrols.rs b/winapi/src/um/commoncontrols.rs new file mode 100644 index 000000000..d659e046a --- /dev/null +++ b/winapi/src/um/commoncontrols.rs @@ -0,0 +1,232 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_int, c_void}; +use shared::guiddef::{REFCLSID, REFIID}; +use shared::minwindef::{BOOL, DWORD, LRESULT, UINT}; +use shared::windef::{COLORREF, HBITMAP, HICON, HWND, POINT, RECT}; +use um::commctrl::{IMAGEINFO, IMAGELISTDRAWPARAMS}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +extern "system" { + pub fn ImageList_CoCreateInstance( + rclsid: REFCLSID, + punkOuter: *const IUnknown, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; +} +pub const ILIF_ALPHA: DWORD = 0x00000001; +pub const ILIF_LOWQUALITY: DWORD = 0x00000001; +pub const ILDRF_IMAGELOWQUALITY: LRESULT = 0x00000001; +pub const ILDRF_OVERLAYLOWQUALITY: LRESULT = 0x00000010; +RIDL!{#[uuid(0x46eb5926, 0x582e, 0x4017, 0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x09, 0x50)] +interface IImageList(IImageListVtbl): IUnknown(IUnknownVtbl) { + fn Add( + hbmImage: HBITMAP, + hbmMask: HBITMAP, + pi: *mut c_int, + ) -> HRESULT, + fn ReplaceIcon( + hicon: HICON, + pi: *mut c_int, + ) -> HRESULT, + fn SetOverlayImage( + iImage: c_int, + iOverlay: c_int, + ) -> HRESULT, + fn Replace( + hbmImage: HBITMAP, + hbmMask: HBITMAP, + ) -> HRESULT, + fn AddMasked( + hbmImage: HBITMAP, + crMask: COLORREF, + pi: *mut c_int, + ) -> HRESULT, + fn Draw( + pimldp: *mut IMAGELISTDRAWPARAMS, + ) -> HRESULT, + fn Remove( + i: c_int, + ) -> HRESULT, + fn GetIcon( + i: c_int, + flags: UINT, + picon: *mut HICON, + ) -> HRESULT, + fn GetImageInfo( + i: c_int, + pImageInfo: *mut IMAGEINFO, + ) -> HRESULT, + fn Copy( + iDst: c_int, + punkSrc: *mut IUnknown, + iSrc: c_int, + uFlags: UINT, + ) -> HRESULT, + fn Merge( + i1: c_int, + punk2: *mut IUnknown, + i2: c_int, + dx: c_int, + dy: c_int, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn Clone( + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn GetImageRect( + i: c_int, + prc: *mut RECT, + ) -> HRESULT, + fn GetIconSize( + cx: *mut c_int, + cy: *mut c_int, + ) -> HRESULT, + fn SetIconSize( + cx: c_int, + cy: c_int, + ) -> HRESULT, + fn GetImageCount( + pi: *mut c_int, + ) -> HRESULT, + fn SetImageCount( + uNewCount: UINT, + ) -> HRESULT, + fn SetBkColor( + clrBk: COLORREF, + pclr: *mut COLORREF, + ) -> HRESULT, + fn GetBkColor( + pclr: *mut COLORREF, + ) -> HRESULT, + fn BeginDrag( + iTrack: c_int, + dxHotspot: c_int, + dyHotspot: c_int, + ) -> HRESULT, + fn EndDrag() -> HRESULT, + fn DragEnter( + hwndLock: HWND, + x: c_int, + y: c_int, + ) -> HRESULT, + fn DragLeave( + hwndLock: HWND, + ) -> HRESULT, + fn DragMove( + x: c_int, + y: c_int, + ) -> HRESULT, + fn SetDragCursorImage( + punk: *mut IUnknown, + iDrag: c_int, + dxHotspot: c_int, + dyHotspot: c_int, + ) -> HRESULT, + fn DragShowNolock( + fShow: BOOL, + ) -> HRESULT, + fn GetDragImage( + ppt: *mut POINT, + pptHotspot: *mut POINT, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn GetItemFlags( + dwFlags: *mut DWORD, + ) -> HRESULT, + fn GetOverlayImage( + iOverlay: c_int, + piIndex: *mut c_int, + ) -> HRESULT, +}} +pub const ILR_DEFAULT: DWORD = 0x0000; +pub const ILR_HORIZONTAL_LEFT: DWORD = 0x0000; +pub const ILR_HORIZONTAL_CENTER: DWORD = 0x0001; +pub const ILR_HORIZONTAL_RIGHT: DWORD = 0x0002; +pub const ILR_VERTICAL_TOP: DWORD = 0x0000; +pub const ILR_VERTICAL_CENTER: DWORD = 0x0010; +pub const ILR_VERTICAL_BOTTOM: DWORD = 0x0020; +pub const ILR_SCALE_CLIP: DWORD = 0x0000; +pub const ILR_SCALE_ASPECTRATIO: DWORD = 0x0100; +pub const ILGOS_ALWAYS: DWORD = 0x00000000; +pub const ILGOS_FROMSTANDBY: DWORD = 0x00000001; +pub const ILFIP_ALWAYS: DWORD = 0x00000000; +pub const ILFIP_FROMSTANDBY: DWORD = 0x00000001; +pub const ILDI_PURGE: DWORD = 0x00000001; +pub const ILDI_STANDBY: DWORD = 0x00000002; +pub const ILDI_RESETACCESS: DWORD = 0x00000004; +pub const ILDI_QUERYACCESS: DWORD = 0x00000008; +STRUCT!{struct IMAGELISTSTATS { + cbSize: DWORD, + cAlloc: c_int, + cUsed: c_int, + cStandby: c_int, +}} +RIDL!{#[uuid(0x192b9d83, 0x58fc, 0x457b, 0x90, 0xa0, 0x2b, 0x82, 0xa8, 0xb5, 0xda, 0xe1)] +interface IImageList2(IImageList2Vtbl): IImageList(IImageListVtbl) { + fn Resize( + cxNewIconSize: c_int, + cyNewIconSize: c_int, + ) -> HRESULT, + fn GetOriginalSize( + iImage: c_int, + dwFlags: DWORD, + pcx: *mut c_int, + pcy: *mut c_int, + ) -> HRESULT, + fn SetOriginalSize( + iImage: c_int, + cx: c_int, + cy: c_int, + ) -> HRESULT, + fn SetCallback( + punk: *mut IUnknown, + ) -> HRESULT, + fn GetCallback( + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn ForceImagePresent( + iImage: c_int, + dwFlags: DWORD, + ) -> HRESULT, + fn DiscardImages( + iFirstImage: c_int, + iLastImage: c_int, + dwFlags: DWORD, + ) -> HRESULT, + fn PreloadImages( + pimldp: *mut IMAGELISTDRAWPARAMS, + ) -> HRESULT, + fn GetStatistics( + pils: *mut IMAGELISTSTATS, + ) -> HRESULT, + fn Initialize( + cx: c_int, + cy: c_int, + flags: UINT, + cInitial: c_int, + cGrow: c_int, + ) -> HRESULT, + fn Replace2( + i: c_int, + hbmImage: HBITMAP, + hbmMask: HBITMAP, + punk: *mut IUnknown, + dwFlags: DWORD, + ) -> HRESULT, + fn ReplaceFromImageList( + i: c_int, + pil: *mut IImageList, + iSrc: c_int, + punk: *mut IUnknown, + dwFlags: DWORD, + ) -> HRESULT, +}} diff --git a/winapi/src/um/consoleapi.rs b/winapi/src/um/consoleapi.rs new file mode 100644 index 000000000..3f5496b95 --- /dev/null +++ b/winapi/src/um/consoleapi.rs @@ -0,0 +1,91 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-console-l1 +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, UINT}; +use um::wincon::{PCONSOLE_READCONSOLE_CONTROL, PHANDLER_ROUTINE}; +use um::wincontypes::{COORD, HPCON, PINPUT_RECORD}; +use um::winnt::{HANDLE, HRESULT, VOID}; +extern "system" { + pub fn AllocConsole() -> BOOL; + pub fn GetConsoleCP() -> UINT; + pub fn GetConsoleMode( + hConsoleHandle: HANDLE, + lpMode: LPDWORD, + ) -> BOOL; + pub fn GetConsoleOutputCP() -> UINT; + pub fn GetNumberOfConsoleInputEvents( + hConsoleInput: HANDLE, + lpNumberOfEvents: LPDWORD, + ) -> BOOL; + pub fn PeekConsoleInputA( + hConsoleInput: HANDLE, + lpBuffer: PINPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD, + ) -> BOOL; + pub fn ReadConsoleA( + hConsoleInput: HANDLE, + lpBuffer: LPVOID, + nNumberOfCharsToRead: DWORD, + lpNumberOfCharsRead: LPDWORD, + pInputControl: PCONSOLE_READCONSOLE_CONTROL, + ) -> BOOL; + pub fn ReadConsoleW( + hConsoleInput: HANDLE, + lpBuffer: LPVOID, + nNumberOfCharsToRead: DWORD, + lpNumberOfCharsRead: LPDWORD, + pInputControl: PCONSOLE_READCONSOLE_CONTROL, + ) -> BOOL; + pub fn ReadConsoleInputA( + hConsoleInput: HANDLE, + lpBuffer: PINPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD, + ) -> BOOL; + pub fn ReadConsoleInputW( + hConsoleInput: HANDLE, + lpBuffer: PINPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD, + ) -> BOOL; + pub fn SetConsoleCtrlHandler( + HandlerRoutine: PHANDLER_ROUTINE, + Add: BOOL, + ) -> BOOL; + pub fn SetConsoleMode( + hConsoleHandle: HANDLE, + dwMode: DWORD, + ) -> BOOL; + pub fn WriteConsoleA( + hConsoleOutput: HANDLE, + lpBuffer: *const VOID, + nNumberOfCharsToWrite: DWORD, + lpNumberOfCharsWritten: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn WriteConsoleW( + hConsoleOutput: HANDLE, + lpBuffer: *const VOID, + nNumberOfCharsToWrite: DWORD, + lpNumberOfCharsWritten: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn CreatePseudoConsole( + size: COORD, + hInput: HANDLE, + hOutput: HANDLE, + dwFlags: DWORD, + phPC: *mut HPCON, + ) -> HRESULT; + pub fn ResizePseudoConsole( + hPC: HPCON, + size: COORD, + ) -> HRESULT; + pub fn ClosePseudoConsole( + hPC: HPCON, + ); +} diff --git a/winapi/src/um/corsym.rs b/winapi/src/um/corsym.rs new file mode 100644 index 000000000..2e7c0f983 --- /dev/null +++ b/winapi/src/um/corsym.rs @@ -0,0 +1,89 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Common Language Runtime Debugging Symbol Reader/Writer/Binder Interfaces +use shared::basetsd::ULONG32; +use um::objidlbase::IStream; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, WCHAR}; +DEFINE_GUID!{CorSym_LanguageType_C, + 0x63a08714, 0xfc37, 0x11d2, 0x90, 0x4c, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1} +DEFINE_GUID!{CorSym_LanguageType_CPlusPlus, + 0x3a12d0b7, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2} +DEFINE_GUID!{CorSym_LanguageType_CSharp, + 0x3f5162f8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1} +DEFINE_GUID!{CorSym_LanguageType_Basic, + 0x3a12d0b8, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2} +DEFINE_GUID!{CorSym_LanguageType_Java, + 0x3a12d0b4, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2} +DEFINE_GUID!{CorSym_LanguageType_Cobol, + 0xaf046cd1, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc} +DEFINE_GUID!{CorSym_LanguageType_Pascal, + 0xaf046cd2, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc} +DEFINE_GUID!{CorSym_LanguageType_ILAssembly, + 0xaf046cd3, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc} +DEFINE_GUID!{CorSym_LanguageType_JScript, + 0x3a12d0b6, 0xc26c, 0x11d0, 0xb4, 0x42, 0x00, 0xa0, 0x24, 0x4a, 0x1d, 0xd2} +DEFINE_GUID!{CorSym_LanguageType_SMC, + 0xd9b9f7b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x0, 0x0, 0xf8, 0x8, 0x49, 0xbd} +DEFINE_GUID!{CorSym_LanguageType_MCPlusPlus, + 0x4b35fde8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1} +DEFINE_GUID!{CorSym_LanguageVendor_Microsoft, + 0x994b45c4, 0xe6e9, 0x11d2, 0x90, 0x3f, 0x00, 0xc0, 0x4f, 0xa3, 0x02, 0xa1} +DEFINE_GUID!{CorSym_DocumentType_Text, + 0x5a869d0b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x0, 0x0, 0xf8, 0x8, 0x49, 0xbd} +DEFINE_GUID!{CorSym_DocumentType_MC, + 0xeb40cb65, 0x3c1f, 0x4352, 0x9d, 0x7b, 0xba, 0xf, 0xc4, 0x7a, 0x9d, 0x77} +DEFINE_GUID!{CorSym_SourceHash_MD5, + 0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99} +DEFINE_GUID!{CorSym_SourceHash_SHA1, + 0xff1816ec, 0xaa5e, 0x4d10, 0x87, 0xf7, 0x6f, 0x49, 0x63, 0x83, 0x34, 0x60} +ENUM!{enum CorSymAddrKind { + ADDR_IL_OFFSET = 1, + ADDR_NATIVE_RVA = 2, + ADDR_NATIVE_REGISTER = 3, + ADDR_NATIVE_REGREL = 4, + ADDR_NATIVE_OFFSET = 5, + ADDR_NATIVE_REGREG = 6, + ADDR_NATIVE_REGSTK = 7, + ADDR_NATIVE_STKREG = 8, + ADDR_BITFIELD = 9, + ADDR_NATIVE_ISECTOFFSET = 10, +}} +ENUM!{enum CorSymVarFlag { + VAR_IS_COMP_GEN = 1, +}} +RIDL!{#[uuid(0xaa544d42, 0x28cb, 0x11d3, 0xbd, 0x22, 0x00, 0x00, 0xf8, 0x08, 0x49, 0xbd)] +interface ISymUnmanagedBinder(ISymUnmanagedBinderVtbl): IUnknown(IUnknownVtbl) { + fn GetReaderForFile( + importer: *mut IUnknown, + fileName: *const WCHAR, + searchPath: *const WCHAR, + pRetVal: *mut *mut ISymUnmanagedReader, + ) -> HRESULT, + fn GetReaderFromStream( + importer: *mut IUnknown, + pstream: *mut IStream, + pRetVal: *mut *mut ISymUnmanagedReader, + ) -> HRESULT, +}} +ENUM!{enum CorSymSearchPolicyAttributes { + AllowRegistryAccess = 0x1, + AllowSymbolServerAccess = 0x2, + AllowOriginalPathAccess = 0x4, + AllowReferencePathAccess = 0x8, +}} +RIDL!{#[uuid(0xaccee350, 0x89af, 0x4ccb, 0x8b, 0x40, 0x1c, 0x2c, 0x4c, 0x6f, 0x94, 0x34)] +interface ISymUnmanagedBinder2(ISymUnmanagedBinder2Vtbl): + ISymUnmanagedBinder(ISymUnmanagedBinderVtbl) { + fn GetReaderForFile2( + importer: *mut IUnknown, + fileName: *const WCHAR, + searchPath: *const WCHAR, + searchPolicy: ULONG32, + pRetVal: *mut *mut ISymUnmanagedReader, + ) -> HRESULT, +}} +pub enum ISymUnmanagedReader {} // TODO diff --git a/winapi/src/um/d2d1.rs b/winapi/src/um/d2d1.rs new file mode 100644 index 000000000..0632e6891 --- /dev/null +++ b/winapi/src/um/d2d1.rs @@ -0,0 +1,982 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Mappings for the contents of d2d1.h +use ctypes::c_void; +use shared::basetsd::{UINT32, UINT64}; +use shared::dxgi::IDXGISurface; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, DWORD, FLOAT}; +use shared::windef::{HDC, HWND, RECT}; +use um::d2dbasetypes::{ + D2D_COLOR_F, D2D_MATRIX_3X2_F, D2D_POINT_2F, D2D_POINT_2U, D2D_RECT_F, D2D_RECT_U, D2D_SIZE_F, + D2D_SIZE_U, +}; +use um::d3dcommon::{D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1}; +use um::dcommon::{D2D1_PIXEL_FORMAT, DWRITE_MEASURING_MODE}; +use um::dwrite::{DWRITE_GLYPH_RUN, IDWriteRenderingParams, IDWriteTextFormat, IDWriteTextLayout}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wincodec::{IWICBitmap, IWICBitmapSource}; +use um::winnt::{HRESULT, WCHAR}; +// Types confirmed affected by the ABI issue: +// D2D1_SIZE_F, D2D1_SIZE_U, D2D1_COLOR_F, D2D1_PIXEL_FORMAT, D2D1_POINT_2F +pub const D2D1_DEFAULT_FLATTENING_TOLERANCE: FLOAT = 0.25; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_NEAREST_NEIGHBOR: DWORD = 0; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_LINEAR: DWORD = 1; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_CUBIC: DWORD = 2; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_MULTI_SAMPLE_LINEAR: DWORD = 3; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_ANISOTROPIC: DWORD = 4; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_HIGH_QUALITY_CUBIC: DWORD = 5; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_FANT: DWORD = 6; +pub const D2D1_INTERPOLATION_MODE_DEFINITION_MIPMAP_LINEAR: DWORD = 7; +ENUM!{enum D2D1_GAMMA { + D2D1_GAMMA_2_2 = 0, + D2D1_GAMMA_1_0 = 1, +}} +ENUM!{enum D2D1_OPACITY_MASK_CONTENT { + D2D1_OPACITY_MASK_CONTENT_GRAPHICS = 0, + D2D1_OPACITY_MASK_CONTENT_TEXT_NATURAL = 1, + D2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE = 2, +}} +ENUM!{enum D2D1_EXTEND_MODE { + D2D1_EXTEND_MODE_CLAMP = 0, + D2D1_EXTEND_MODE_WRAP = 1, + D2D1_EXTEND_MODE_MIRROR = 2, +}} +ENUM!{enum D2D1_ANTIALIAS_MODE { + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE = 0, + D2D1_ANTIALIAS_MODE_ALIASED = 1, +}} +ENUM!{enum D2D1_TEXT_ANTIALIAS_MODE { + D2D1_TEXT_ANTIALIAS_MODE_DEFAULT = 0, + D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE = 1, + D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE = 2, + D2D1_TEXT_ANTIALIAS_MODE_ALIASED = 3, +}} +ENUM!{enum D2D1_BITMAP_INTERPOLATION_MODE { + D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR = + D2D1_INTERPOLATION_MODE_DEFINITION_NEAREST_NEIGHBOR, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR = + D2D1_INTERPOLATION_MODE_DEFINITION_LINEAR, +}} +ENUM!{enum D2D1_DRAW_TEXT_OPTIONS { + D2D1_DRAW_TEXT_OPTIONS_NO_SNAP = 0x00000001, + D2D1_DRAW_TEXT_OPTIONS_CLIP = 0x00000002, + D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT = 0x00000004, + D2D1_DRAW_TEXT_OPTIONS_NONE = 0x00000000, +}} +pub type D2D1_POINT_2U = D2D_POINT_2U; +pub type D2D1_POINT_2F = D2D_POINT_2F; +pub type D2D1_RECT_F = D2D_RECT_F; +pub type D2D1_RECT_U = D2D_RECT_U; +pub type D2D1_SIZE_F = D2D_SIZE_F; +pub type D2D1_SIZE_U = D2D_SIZE_U; +pub type D2D1_COLOR_F = D2D_COLOR_F; +pub type D2D1_MATRIX_3X2_F = D2D_MATRIX_3X2_F; +pub type D2D1_TAG = UINT64; +STRUCT!{struct D2D1_BITMAP_PROPERTIES { + pixelFormat: D2D1_PIXEL_FORMAT, + dpiX: FLOAT, + dpiY: FLOAT, +}} +STRUCT!{struct D2D1_GRADIENT_STOP { + position: FLOAT, + color: D2D1_COLOR_F, +}} +STRUCT!{struct D2D1_BRUSH_PROPERTIES { + opacity: FLOAT, + transform: D2D1_MATRIX_3X2_F, +}} +STRUCT!{struct D2D1_BITMAP_BRUSH_PROPERTIES { + extendModeX: D2D1_EXTEND_MODE, + extendModeY: D2D1_EXTEND_MODE, + interpolationMode: D2D1_BITMAP_INTERPOLATION_MODE, +}} +STRUCT!{struct D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES { + startPoint: D2D1_POINT_2F, + endPoint: D2D1_POINT_2F, +}} +STRUCT!{struct D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES { + center: D2D1_POINT_2F, + gradientOriginOffset: D2D1_POINT_2F, + radiusX: FLOAT, + radiusY: FLOAT, +}} +ENUM!{enum D2D1_ARC_SIZE { + D2D1_ARC_SIZE_SMALL = 0, + D2D1_ARC_SIZE_LARGE = 1, +}} +ENUM!{enum D2D1_CAP_STYLE { + D2D1_CAP_STYLE_FLAT = 0, + D2D1_CAP_STYLE_SQUARE = 1, + D2D1_CAP_STYLE_ROUND = 2, + D2D1_CAP_STYLE_TRIANGLE = 3, +}} +ENUM!{enum D2D1_DASH_STYLE { + D2D1_DASH_STYLE_SOLID = 0, + D2D1_DASH_STYLE_DASH = 1, + D2D1_DASH_STYLE_DOT = 2, + D2D1_DASH_STYLE_DASH_DOT = 3, + D2D1_DASH_STYLE_DASH_DOT_DOT = 4, + D2D1_DASH_STYLE_CUSTOM = 5, +}} +ENUM!{enum D2D1_LINE_JOIN { + D2D1_LINE_JOIN_MITER = 0, + D2D1_LINE_JOIN_BEVEL = 1, + D2D1_LINE_JOIN_ROUND = 2, + D2D1_LINE_JOIN_MITER_OR_BEVEL = 3, +}} +ENUM!{enum D2D1_COMBINE_MODE { + D2D1_COMBINE_MODE_UNION = 0, + D2D1_COMBINE_MODE_INTERSECT = 1, + D2D1_COMBINE_MODE_XOR = 2, + D2D1_COMBINE_MODE_EXCLUDE = 3, +}} +ENUM!{enum D2D1_GEOMETRY_RELATION { + D2D1_GEOMETRY_RELATION_UNKNOWN = 0, + D2D1_GEOMETRY_RELATION_DISJOINT = 1, + D2D1_GEOMETRY_RELATION_IS_CONTAINED = 2, + D2D1_GEOMETRY_RELATION_CONTAINS = 3, + D2D1_GEOMETRY_RELATION_OVERLAP = 4, +}} +ENUM!{enum D2D1_GEOMETRY_SIMPLIFICATION_OPTION { + D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES = 0, + D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES = 1, +}} +ENUM!{enum D2D1_FIGURE_BEGIN { + D2D1_FIGURE_BEGIN_FILLED = 0, + D2D1_FIGURE_BEGIN_HOLLOW = 1, +}} +ENUM!{enum D2D1_FIGURE_END { + D2D1_FIGURE_END_OPEN = 0, + D2D1_FIGURE_END_CLOSED = 1, +}} +STRUCT!{struct D2D1_BEZIER_SEGMENT { + point1: D2D1_POINT_2F, + point2: D2D1_POINT_2F, + point3: D2D1_POINT_2F, +}} +STRUCT!{struct D2D1_TRIANGLE { + point1: D2D1_POINT_2F, + point2: D2D1_POINT_2F, + point3: D2D1_POINT_2F, +}} +ENUM!{enum D2D1_PATH_SEGMENT { + D2D1_PATH_SEGMENT_NONE = 0x00000000, + D2D1_PATH_SEGMENT_FORCE_UNSTROKED = 0x00000001, + D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN = 0x00000002, +}} +ENUM!{enum D2D1_SWEEP_DIRECTION { + D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE = 0, + D2D1_SWEEP_DIRECTION_CLOCKWISE = 1, +}} +ENUM!{enum D2D1_FILL_MODE { + D2D1_FILL_MODE_ALTERNATE = 0, + D2D1_FILL_MODE_WINDING = 1, +}} +STRUCT!{struct D2D1_ARC_SEGMENT { + point: D2D1_POINT_2F, + size: D2D1_SIZE_F, + rotationAngle: FLOAT, + sweepDirection: D2D1_SWEEP_DIRECTION, + arcSize: D2D1_ARC_SIZE, +}} +STRUCT!{struct D2D1_QUADRATIC_BEZIER_SEGMENT { + point1: D2D1_POINT_2F, + point2: D2D1_POINT_2F, +}} +STRUCT!{struct D2D1_ELLIPSE { + point: D2D1_POINT_2F, + radiusX: FLOAT, + radiusY: FLOAT, +}} +STRUCT!{struct D2D1_ROUNDED_RECT { + rect: D2D1_RECT_F, + radiusX: FLOAT, + radiusY: FLOAT, +}} +STRUCT!{struct D2D1_STROKE_STYLE_PROPERTIES { + startCap: D2D1_CAP_STYLE, + endCap: D2D1_CAP_STYLE, + dashCap: D2D1_CAP_STYLE, + lineJoin: D2D1_LINE_JOIN, + miterLimit: FLOAT, + dashStyle: D2D1_DASH_STYLE, + dashOffset: FLOAT, +}} +ENUM!{enum D2D1_LAYER_OPTIONS { + D2D1_LAYER_OPTIONS_NONE = 0x00000000, + D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE = 0x00000001, +}} +STRUCT!{struct D2D1_LAYER_PARAMETERS { + contentBounds: D2D1_RECT_F, + geometricMask: *mut ID2D1Geometry, + maskAntialiasMode: D2D1_ANTIALIAS_MODE, + maskTransform: D2D1_MATRIX_3X2_F, + opacity: FLOAT, + opacityBrush: *mut ID2D1Brush, + layerOptions: D2D1_LAYER_OPTIONS, +}} +ENUM!{enum D2D1_WINDOW_STATE { + D2D1_WINDOW_STATE_NONE = 0x0000000, + D2D1_WINDOW_STATE_OCCLUDED = 0x0000001, +}} +ENUM!{enum D2D1_RENDER_TARGET_TYPE { + D2D1_RENDER_TARGET_TYPE_DEFAULT = 0, + D2D1_RENDER_TARGET_TYPE_SOFTWARE = 1, + D2D1_RENDER_TARGET_TYPE_HARDWARE = 2, +}} +ENUM!{enum D2D1_FEATURE_LEVEL { + D2D1_FEATURE_LEVEL_DEFAULT = 0, + D2D1_FEATURE_LEVEL_9 = D3D_FEATURE_LEVEL_9_1, + D2D1_FEATURE_LEVEL_10 = D3D_FEATURE_LEVEL_10_0, +}} +ENUM!{enum D2D1_RENDER_TARGET_USAGE { + D2D1_RENDER_TARGET_USAGE_NONE = 0x00000000, + D2D1_RENDER_TARGET_USAGE_FORCE_BITMAP_REMOTING = 0x00000001, + D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE = 0x00000002, +}} +ENUM!{enum D2D1_PRESENT_OPTIONS { + D2D1_PRESENT_OPTIONS_NONE = 0x00000000, + D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS = 0x00000001, + D2D1_PRESENT_OPTIONS_IMMEDIATELY = 0x00000002, +}} +STRUCT!{struct D2D1_RENDER_TARGET_PROPERTIES { + _type: D2D1_RENDER_TARGET_TYPE, + pixelFormat: D2D1_PIXEL_FORMAT, + dpiX: FLOAT, + dpiY: FLOAT, + usage: D2D1_RENDER_TARGET_USAGE, + minLevel: D2D1_FEATURE_LEVEL, +}} +STRUCT!{struct D2D1_HWND_RENDER_TARGET_PROPERTIES { + hwnd: HWND, + pixelSize: D2D1_SIZE_U, + presentOptions: D2D1_PRESENT_OPTIONS, +}} +ENUM!{enum D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS { + D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE = 0x00000000, + D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE = 0x00000001, +}} +STRUCT!{struct D2D1_DRAWING_STATE_DESCRIPTION { + antialiasMode: D2D1_ANTIALIAS_MODE, + textAntialiasMode: D2D1_TEXT_ANTIALIAS_MODE, + tag1: D2D1_TAG, + tag2: D2D1_TAG, + transform: D2D1_MATRIX_3X2_F, +}} +ENUM!{enum D2D1_DC_INITIALIZE_MODE { + D2D1_DC_INITIALIZE_MODE_COPY = 0, + D2D1_DC_INITIALIZE_MODE_CLEAR = 1, +}} +ENUM!{enum D2D1_DEBUG_LEVEL { + D2D1_DEBUG_LEVEL_NONE = 0, + D2D1_DEBUG_LEVEL_ERROR = 1, + D2D1_DEBUG_LEVEL_WARNING = 2, + D2D1_DEBUG_LEVEL_INFORMATION = 3, +}} +ENUM!{enum D2D1_FACTORY_TYPE { + D2D1_FACTORY_TYPE_SINGLE_THREADED = 0, + D2D1_FACTORY_TYPE_MULTI_THREADED = 1, +}} +STRUCT!{struct D2D1_FACTORY_OPTIONS { + debugLevel: D2D1_DEBUG_LEVEL, +}} +RIDL!{#[uuid(0x2cd90691, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1Resource(ID2D1ResourceVtbl): IUnknown(IUnknownVtbl) { + fn GetFactory( + factory: *mut *mut ID2D1Factory, + ) -> (), +}} +RIDL!{#[uuid(0x65019f75, 0x8da2, 0x497c, 0xb3, 0x2c, 0xdf, 0xa3, 0x4e, 0x48, 0xed, 0xe6)] +interface ID2D1Image(ID2D1ImageVtbl): ID2D1Resource(ID2D1ResourceVtbl) {}} +RIDL!{#[uuid(0xa2296057, 0xea42, 0x4099, 0x98, 0x3b, 0x53, 0x9f, 0xb6, 0x50, 0x54, 0x26)] +interface ID2D1Bitmap(ID2D1BitmapVtbl): ID2D1Image(ID2D1ImageVtbl) { + #[fixme] fn GetSize() -> D2D1_SIZE_F, + #[fixme] fn GetPixelSize() -> D2D1_SIZE_U, + #[fixme] fn GetPixelFormat() -> D2D1_PIXEL_FORMAT, + fn GetDpi( + dpiX: *mut FLOAT, + dpiY: *mut FLOAT, + ) -> (), + fn CopyFromBitmap( + destPoint: *const D2D1_POINT_2U, + bitmap: *mut ID2D1Bitmap, + srcRect: *const D2D1_RECT_U, + ) -> HRESULT, + fn CopyFromRenderTarget( + destPoint: *const D2D1_POINT_2U, + renderTarget: *mut ID2D1RenderTarget, + srcRect: *const D2D1_RECT_U, + ) -> HRESULT, + fn CopyFromMemory( + dstRect: *const D2D1_RECT_U, + srcData: *const c_void, + pitch: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2cd906a7, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1GradientStopCollection(ID2D1GradientStopCollectionVtbl): + ID2D1Resource(ID2D1ResourceVtbl) { + fn GetGradientStopCount() -> UINT32, + fn GetGradientStops( + gradientStops: *mut D2D1_GRADIENT_STOP, + gradientStopsCount: UINT32, + ) -> (), + fn GetColorInterpolationGamma() -> D2D1_GAMMA, + fn GetExtendMode() -> D2D1_EXTEND_MODE, +}} +RIDL!{#[uuid(0x2cd906a8, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1Brush(ID2D1BrushVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn SetOpacity( + opacity: FLOAT, + ) -> (), + fn SetTransform( + transform: *const D2D1_MATRIX_3X2_F, + ) -> (), + fn GetOpacity() -> FLOAT, + fn GetTransform( + transform: *mut D2D1_MATRIX_3X2_F, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906aa, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1BitmapBrush(ID2D1BitmapBrushVtbl): ID2D1Brush(ID2D1BrushVtbl) { + fn SetExtendModeX( + extendModeX: D2D1_EXTEND_MODE, + ) -> (), + fn SetExtendModeY( + extendModeY: D2D1_EXTEND_MODE, + ) -> (), + fn SetInterpolationMode( + interpolationMode: D2D1_BITMAP_INTERPOLATION_MODE, + ) -> (), + fn SetBitmap( + bitmap: *mut ID2D1Bitmap, + ) -> (), + fn GetExtendModeX() -> D2D1_EXTEND_MODE, + fn GetExtendModeY() -> D2D1_EXTEND_MODE, + fn GetInterpolationMode() -> D2D1_BITMAP_INTERPOLATION_MODE, + fn GetBitmap( + bitmap: *mut *mut ID2D1Bitmap, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906a9, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1SolidColorBrush(ID2D1SolidColorBrushVtbl): ID2D1Brush(ID2D1BrushVtbl) { + fn SetColor( + color: *const D2D1_COLOR_F, + ) -> (), + #[fixme] fn GetColor() -> D2D1_COLOR_F, +}} +RIDL!{#[uuid(0x2cd906ab, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1LinearGradientBrush(ID2D1LinearGradientBrushVtbl): ID2D1Brush(ID2D1BrushVtbl) { + fn SetStartPoint( + startPoint: D2D1_POINT_2F, + ) -> (), + fn SetEndPoint( + endPoint: D2D1_POINT_2F, + ) -> (), + #[fixme] fn GetStartPoint() -> D2D1_POINT_2F, + #[fixme] fn GetEndPoint() -> D2D1_POINT_2F, + fn GetGradientStopCollection( + gradientStopCollection: *mut *mut ID2D1GradientStopCollection, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906ac, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1RadialGradientBrush(ID2D1RadialGradientBrushVtbl): ID2D1Brush(ID2D1BrushVtbl) { + fn SetCenter( + center: D2D1_POINT_2F, + ) -> (), + fn SetGradientOriginOffset( + gradientOriginOffset: D2D1_POINT_2F, + ) -> (), + fn SetRadiusX( + radiusX: FLOAT, + ) -> (), + fn SetRadiusY( + radiusY: FLOAT, + ) -> (), + #[fixme] fn GetCenter() -> D2D1_POINT_2F, + #[fixme] fn GetGradientOriginOffset() -> D2D1_POINT_2F, + fn GetRadiusX() -> FLOAT, + fn GetRadiusY() -> FLOAT, + fn GetGradientStopCollection( + gradientStopCollection: *mut *mut ID2D1GradientStopCollection, + ) -> (), +}} +RIDL!{#[uuid(0x2cd9069d, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1StrokeStyle(ID2D1StrokeStyleVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetStartCap() -> D2D1_CAP_STYLE, + fn GetEndCap() -> D2D1_CAP_STYLE, + fn GetDashCap() -> D2D1_CAP_STYLE, + fn GetMiterLimit() -> FLOAT, + fn GetLineJoin() -> D2D1_LINE_JOIN, + fn GetDashOffset() -> FLOAT, + fn GetDashStyle() -> D2D1_DASH_STYLE, + fn GetDashesCount() -> UINT32, + fn GetDashes( + dashes: *mut FLOAT, + dashesCount: UINT32, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906a1, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1Geometry(ID2D1GeometryVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetBounds( + worldTransform: *const D2D1_MATRIX_3X2_F, + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn GetWidenedBounds( + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn StrokeContainsPoint( + point: D2D1_POINT_2F, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + contains: *mut BOOL, + ) -> HRESULT, + fn FillContainsPoint( + point: D2D1_POINT_2F, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + contains: *mut BOOL, + ) -> HRESULT, + fn CompareWithGeometry( + inputGeometry: *mut ID2D1Geometry, + inputGeometryTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + relation: *mut D2D1_GEOMETRY_RELATION, + ) -> HRESULT, + fn Simplify( + simplificationOption: D2D1_GEOMETRY_SIMPLIFICATION_OPTION, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + geometrySink: *mut ID2D1SimplifiedGeometrySink, + ) -> HRESULT, + fn Tessellate( + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + tessellationSink: *mut ID2D1TessellationSink, + ) -> HRESULT, + fn CombineWithGeometry( + inputGeometry: *mut ID2D1Geometry, + combineMode: D2D1_COMBINE_MODE, + inputGeometryTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + geometrySink: *mut ID2D1SimplifiedGeometrySink, + ) -> HRESULT, + fn Outline( + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + geometrySink: *mut ID2D1SimplifiedGeometrySink, + ) -> HRESULT, + fn ComputeArea( + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + area: *mut FLOAT, + ) -> HRESULT, + fn ComputeLength( + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + length: *mut FLOAT, + ) -> HRESULT, + fn ComputePointAtLength( + length: FLOAT, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + point: *mut D2D1_POINT_2F, + unitTangentVector: *mut D2D1_POINT_2F, + ) -> HRESULT, + fn Widen( + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + geometrySink: *mut ID2D1SimplifiedGeometrySink, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2cd906a2, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1RectangleGeometry(ID2D1RectangleGeometryVtbl): ID2D1Geometry(ID2D1GeometryVtbl) { + fn GetRect( + rect: *mut D2D1_RECT_F, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906a3, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1RoundedRectangleGeometry(ID2D1RoundedRectangleGeometryVtbl): + ID2D1Geometry(ID2D1GeometryVtbl) { + fn GetRoundedRect( + roundedRect: *mut D2D1_ROUNDED_RECT, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906a4, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1EllipseGeometry(ID2D1EllipseGeometryVtbl): ID2D1Geometry(ID2D1GeometryVtbl) { + fn GetEllipse( + ellipse: *mut D2D1_ELLIPSE, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906a6, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1GeometryGroup(ID2D1GeometryGroupVtbl): ID2D1Geometry(ID2D1GeometryVtbl) { + fn GetFillMode() -> D2D1_FILL_MODE, + fn GetSourceGeometryCount() -> UINT32, + fn GetSourceGeometries( + geometries: *mut *mut ID2D1Geometry, + geometriesCount: UINT32, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906bb, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1TransformedGeometry(ID2D1TransformedGeometryVtbl): + ID2D1Geometry(ID2D1GeometryVtbl) { + fn GetSourceGeometry( + sourceGeometry: *mut *mut ID2D1Geometry, + ) -> (), + fn GetTransform( + transform: *mut D2D1_MATRIX_3X2_F, + ) -> (), +}} +RIDL!{#[uuid(0x2cd9069e, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1SimplifiedGeometrySink(ID2D1SimplifiedGeometrySinkVtbl): IUnknown(IUnknownVtbl) { + fn SetFillMode( + fillMode: D2D1_FILL_MODE, + ) -> (), + fn SetSegmentFlags( + vertexFlags: D2D1_PATH_SEGMENT, + ) -> (), + fn BeginFigure( + startPoint: D2D1_POINT_2F, + figureBegin: D2D1_FIGURE_BEGIN, + ) -> (), + fn AddLines( + points: *const D2D1_POINT_2F, + pointsCount: UINT32, + ) -> (), + fn AddBeziers( + beziers: *const D2D1_BEZIER_SEGMENT, + beziersCount: UINT32, + ) -> (), + fn EndFigure( + figureEnd: D2D1_FIGURE_END, + ) -> (), + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0x2cd9069f, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1GeometrySink(ID2D1GeometrySinkVtbl): + ID2D1SimplifiedGeometrySink(ID2D1SimplifiedGeometrySinkVtbl) { + fn AddLine( + point: D2D1_POINT_2F, + ) -> (), + fn AddBezier( + bezier: *const D2D1_BEZIER_SEGMENT, + ) -> (), + fn AddQuadraticBezier( + bezier: *const D2D1_QUADRATIC_BEZIER_SEGMENT, + ) -> (), + fn AddQuadraticBeziers( + beziers: *const D2D1_QUADRATIC_BEZIER_SEGMENT, + beziersCount: UINT32, + ) -> (), + fn AddArc( + arc: *const D2D1_ARC_SEGMENT, + ) -> (), +}} +RIDL!{#[uuid(0x2cd906c1, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1TessellationSink(ID2D1TessellationSinkVtbl): IUnknown(IUnknownVtbl) { + fn AddTriangles( + triangles: *const D2D1_TRIANGLE, + triangleCount: UINT32, + ) -> (), + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0x2cd906a5, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1PathGeometry(ID2D1PathGeometryVtbl): ID2D1Geometry(ID2D1GeometryVtbl) { + fn Open( + geometrySink: *mut *mut ID2D1GeometrySink, + ) -> HRESULT, + fn Stream( + geometrySink: *mut ID2D1GeometrySink, + ) -> HRESULT, + fn GetSegmentCount( + count: *mut UINT32, + ) -> HRESULT, + fn GetFigureCount( + count: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2cd906c2, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1Mesh(ID2D1MeshVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn Open( + tessellationSink: *mut *mut ID2D1TessellationSink, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2cd9069b, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1Layer(ID2D1LayerVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + #[fixme] fn GetSize() -> D2D1_SIZE_F, +}} +RIDL!{#[uuid(0x28506e39, 0xebf6, 0x46a1, 0xbb, 0x47, 0xfd, 0x85, 0x56, 0x5a, 0xb9, 0x57)] +interface ID2D1DrawingStateBlock(ID2D1DrawingStateBlockVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetDescription( + stateDescription: *mut D2D1_DRAWING_STATE_DESCRIPTION, + ) -> (), + fn SetDescription( + stateDescription: *const D2D1_DRAWING_STATE_DESCRIPTION, + ) -> (), + fn SetTextRenderingParams( + textRenderingParams: *mut IDWriteRenderingParams, + ) -> (), + fn GetTextRenderingParams( + textRenderingParams: *mut *mut IDWriteRenderingParams, + ) -> (), +}} +RIDL!{#[uuid(0x2cd90694, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1RenderTarget(ID2D1RenderTargetVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn CreateBitmap( + size: D2D1_SIZE_U, + srcData: *const c_void, + pitch: UINT32, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES, + bitmap: *mut *mut ID2D1Bitmap, + ) -> HRESULT, + fn CreateBitmapFromWicBitmap( + wicBitmapSource: *mut IWICBitmapSource, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES, + bitmap: *mut *mut ID2D1Bitmap, + ) -> HRESULT, + fn CreateSharedBitmap( + riid: REFIID, + data: *const c_void, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES, + bitmap: *mut *mut ID2D1Bitmap, + ) -> HRESULT, + fn CreateBitmapBrush( + bitmap: *mut ID2D1Bitmap, + bitmapBrushProperties: *const D2D1_BITMAP_BRUSH_PROPERTIES, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + bitmapBrush: *mut *mut ID2D1BitmapBrush, + ) -> HRESULT, + fn CreateSolidColorBrush( + color: *const D2D1_COLOR_F, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + solidColorBrush: *mut *mut ID2D1SolidColorBrush, + ) -> HRESULT, + fn CreateGradientStopCollection( + gradientStops: *const D2D1_GRADIENT_STOP, + gradientStopsCount: UINT32, + colorInterpolationGamma: D2D1_GAMMA, + extendMode: D2D1_EXTEND_MODE, + gradientStopCollection: *mut *mut ID2D1GradientStopCollection, + ) -> HRESULT, + fn CreateLinearGradientBrush( + linearGradientBrushProperties: *const D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + gradientStopCollection: *mut ID2D1GradientStopCollection, + linearGradientBrush: *mut *mut ID2D1LinearGradientBrush, + ) -> HRESULT, + fn CreateRadialGradientBrush( + radialGradientBrushProperties: *const D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + gradientStopCollection: *mut ID2D1GradientStopCollection, + radialGradientBrush: *mut *mut ID2D1RadialGradientBrush, + ) -> HRESULT, + fn CreateCompatibleRenderTarget( + desiredSize: *const D2D1_SIZE_F, + desiredPixelSize: *const D2D1_SIZE_U, + desiredFormat: *const D2D1_PIXEL_FORMAT, + options: D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS, + bitmapRenderTarget: *mut *mut ID2D1BitmapRenderTarget, + ) -> HRESULT, + fn CreateLayer( + size: *const D2D1_SIZE_F, + layer: *mut *mut ID2D1Layer, + ) -> HRESULT, + fn CreateMesh( + mesh: *mut *mut ID2D1Mesh, + ) -> HRESULT, + fn DrawLine( + point0: D2D1_POINT_2F, + point1: D2D1_POINT_2F, + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + strokeStype: *mut ID2D1StrokeStyle, + ) -> (), + fn DrawRectangle( + rect: *const D2D1_RECT_F, + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + ) -> (), + fn FillRectangle( + rect: *const D2D1_RECT_F, + brush: *mut ID2D1Brush, + ) -> (), + fn DrawRoundedRectangle( + roundedRect: *const D2D1_ROUNDED_RECT, + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + ) -> (), + fn FillRoundedRectangle( + roundedRect: *const D2D1_ROUNDED_RECT, + brush: *mut ID2D1Brush, + ) -> (), + fn DrawEllipse( + ellipse: *const D2D1_ELLIPSE, + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + ) -> (), + fn FillEllipse( + ellipse: *const D2D1_ELLIPSE, + brush: *mut ID2D1Brush, + ) -> (), + fn DrawGeometry( + geometry: *mut ID2D1Geometry, + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + ) -> (), + fn FillGeometry( + geometry: *mut ID2D1Geometry, + brush: *mut ID2D1Brush, + opacityBrush: *mut ID2D1Brush, + ) -> (), + fn FillMesh( + mesh: *mut ID2D1Mesh, + brush: *const ID2D1Brush, + ) -> (), + fn FillOpacityMask( + opacityMask: *mut ID2D1Bitmap, + brush: *mut ID2D1Brush, + content: D2D1_OPACITY_MASK_CONTENT, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangle: *const D2D1_RECT_F, + ) -> (), + fn DrawBitmap( + bitmap: *mut ID2D1Bitmap, + destinationRectangle: *const D2D1_RECT_F, + opacity: FLOAT, + interpolationMode: D2D1_BITMAP_INTERPOLATION_MODE, + sourceRectangle: *const D2D1_RECT_F, + ) -> (), + fn DrawText( + string: *const WCHAR, + stringLength: UINT32, + textFormat: *mut IDWriteTextFormat, + layoutRect: *const D2D1_RECT_F, + defaultForegroundBrush: *mut ID2D1Brush, + options: D2D1_DRAW_TEXT_OPTIONS, + measuringMode: DWRITE_MEASURING_MODE, + ) -> (), + fn DrawTextLayout( + origin: D2D1_POINT_2F, + textLayout: *mut IDWriteTextLayout, + defaultForegroundBrush: *mut ID2D1Brush, + options: D2D1_DRAW_TEXT_OPTIONS, + ) -> (), + fn DrawGlyphRun( + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + foregroundBrush: *mut ID2D1Brush, + measuringMode: DWRITE_MEASURING_MODE, + ) -> (), + fn SetTransform( + transform: *const D2D1_MATRIX_3X2_F, + ) -> (), + fn GetTransform( + transform: *mut D2D1_MATRIX_3X2_F, + ) -> (), + fn SetAntialiasMode( + antialiasMode: D2D1_ANTIALIAS_MODE, + ) -> (), + fn GetAntialiasMode() -> D2D1_ANTIALIAS_MODE, + fn SetTextAntialiasMode( + textAntialiasMode: D2D1_TEXT_ANTIALIAS_MODE, + ) -> (), + fn GetTextAntialiasMode() -> D2D1_TEXT_ANTIALIAS_MODE, + fn SetTextRenderingParams( + textRenderingParams: *mut IDWriteRenderingParams, + ) -> (), + fn GetTextRenderingParams( + textRenderingParams: *mut *mut IDWriteRenderingParams, + ) -> (), + fn SetTags( + tag1: D2D1_TAG, + tag2: D2D1_TAG, + ) -> (), + fn GetTags( + tag1: *mut D2D1_TAG, + tag2: *mut D2D1_TAG, + ) -> (), + fn PushLayer( + layerParameters: *const D2D1_LAYER_PARAMETERS, + layer: *mut ID2D1Layer, + ) -> (), + fn PopLayer() -> (), + fn Flush( + tag1: *mut D2D1_TAG, + tag2: *mut D2D1_TAG, + ) -> HRESULT, + fn SaveDrawingState( + drawingStateBlock: *mut ID2D1DrawingStateBlock, + ) -> (), + fn RestoreDrawingState( + drawingStateBlock: *mut ID2D1DrawingStateBlock, + ) -> (), + fn PushAxisAlignedClip( + clipRect: *const D2D1_RECT_F, + antialiasMode: D2D1_ANTIALIAS_MODE, + ) -> (), + fn PopAxisAlignedClip() -> (), + fn Clear( + clearColor: *const D2D1_COLOR_F, + ) -> (), + fn BeginDraw() -> (), + fn EndDraw( + tag1: *mut D2D1_TAG, + tag2: *mut D2D1_TAG, + ) -> HRESULT, + #[fixme] fn GetPixelFormat() -> D2D1_PIXEL_FORMAT, + fn SetDpi( + dpiX: FLOAT, + dpiY: FLOAT, + ) -> (), + fn GetDpi( + dpiX: *mut FLOAT, + dpiY: *mut FLOAT, + ) -> (), + #[fixme] fn GetSize() -> D2D1_SIZE_F, + #[fixme] fn GetPixelSize() -> D2D1_SIZE_U, + fn GetMaximumBitmapSize() -> UINT32, + fn IsSupported( + renderTargetProperties: *const D2D1_RENDER_TARGET_PROPERTIES, + ) -> BOOL, +}} +RIDL!{#[uuid(0x2cd90695, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1BitmapRenderTarget(ID2D1BitmapRenderTargetVtbl): + ID2D1RenderTarget(ID2D1RenderTargetVtbl) { + fn GetBitmap( + bitmap: *mut *mut ID2D1Bitmap, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2cd90698, 0x12e2, 0x11dc, 0x9f, 0xed, 0x00, 0x11, 0x43, 0xa0, 0x55, 0xf9)] +interface ID2D1HwndRenderTarget(ID2D1HwndRenderTargetVtbl): + ID2D1RenderTarget(ID2D1RenderTargetVtbl) { + fn CheckWindowState() -> D2D1_WINDOW_STATE, + fn Resize( + pixelSize: *const D2D1_SIZE_U, + ) -> HRESULT, + fn GetHwnd() -> HWND, +}} +RIDL!{#[uuid(0xe0db51c3, 0x6f77, 0x4bae, 0xb3, 0xd5, 0xe4, 0x75, 0x09, 0xb3, 0x58, 0x38)] +interface ID2D1GdiInteropRenderTarget(ID2D1GdiInteropRenderTargetVtbl): IUnknown(IUnknownVtbl) { + fn GetDC( + mode: D2D1_DC_INITIALIZE_MODE, + hdc: *mut HDC, + ) -> HRESULT, + fn ReleaseDC( + update: *const RECT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1c51bc64, 0xde61, 0x46fd, 0x98, 0x99, 0x63, 0xa5, 0xd8, 0xf0, 0x39, 0x50)] +interface ID2D1DCRenderTarget(ID2D1DCRenderTargetVtbl): ID2D1RenderTarget(ID2D1RenderTargetVtbl) { + fn BindDC( + hDC: HDC, + pSubRect: *const RECT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x06152247, 0x6f50, 0x465a, 0x92, 0x45, 0x11, 0x8b, 0xfd, 0x3b, 0x60, 0x07)] +interface ID2D1Factory(ID2D1FactoryVtbl): IUnknown(IUnknownVtbl) { + fn ReloadSystemMetrics() -> HRESULT, + fn GetDesktopDpi( + dpiX: *mut FLOAT, + dpiY: *mut FLOAT, + ) -> (), + fn CreateRectangleGeometry( + rectangle: *const D2D1_RECT_F, + rectangleGeometry: *mut *mut ID2D1RectangleGeometry, + ) -> HRESULT, + fn CreateRoundedRectangleGeometry( + roundedRectangle: *const D2D1_ROUNDED_RECT, + roundedRectangleGeometry: *mut *mut ID2D1RoundedRectangleGeometry, + ) -> HRESULT, + fn CreateEllipseGeometry( + ellipse: *const D2D1_ELLIPSE, + ellipseGeometry: *mut *mut ID2D1EllipseGeometry, + ) -> HRESULT, + fn CreateGeometryGroup( + fillMode: D2D1_FILL_MODE, + geometries: *mut *mut ID2D1Geometry, + geometriesCount: UINT32, + geometryGroup: *mut *mut ID2D1GeometryGroup, + ) -> HRESULT, + fn CreateTransformedGeometry( + sourceGeometry: *mut ID2D1Geometry, + transform: *const D2D1_MATRIX_3X2_F, + transformedGeometry: *mut *mut ID2D1TransformedGeometry, + ) -> HRESULT, + fn CreatePathGeometry( + pathGeometry: *mut *mut ID2D1PathGeometry, + ) -> HRESULT, + fn CreateStrokeStyle( + strokeStyleProperties: *const D2D1_STROKE_STYLE_PROPERTIES, + dashes: *const FLOAT, + dashesCount: UINT32, + strokeStyle: *mut *mut ID2D1StrokeStyle, + ) -> HRESULT, + fn CreateDrawingStateBlock( + drawingStateDescription: *const D2D1_DRAWING_STATE_DESCRIPTION, + textRenderingParams: *mut IDWriteRenderingParams, + drawingStateBlock: *mut *mut ID2D1DrawingStateBlock, + ) -> HRESULT, + fn CreateWicBitmapRenderTarget( + target: *mut IWICBitmap, + renderTargetProperties: *const D2D1_RENDER_TARGET_PROPERTIES, + renderTarget: *mut *mut ID2D1RenderTarget, + ) -> HRESULT, + fn CreateHwndRenderTarget( + renderTargetProperties: *const D2D1_RENDER_TARGET_PROPERTIES, + hwndRenderTargetProperties: *const D2D1_HWND_RENDER_TARGET_PROPERTIES, + hwndRenderTarget: *mut *mut ID2D1HwndRenderTarget, + ) -> HRESULT, + fn CreateDxgiSurfaceRenderTarget( + dxgiSurface: *mut IDXGISurface, + renderTargetProperties: *const D2D1_RENDER_TARGET_PROPERTIES, + renderTarget: *mut *mut ID2D1RenderTarget, + ) -> HRESULT, + fn CreateDCRenderTarget( + renderTargetProperties: *const D2D1_RENDER_TARGET_PROPERTIES, + dcRenderTarget: *mut *mut ID2D1DCRenderTarget, + ) -> HRESULT, +}} +extern "system" { + pub fn D2D1CreateFactory( + factoryType: D2D1_FACTORY_TYPE, + riid: REFIID, + pFactoryOptions: *const D2D1_FACTORY_OPTIONS, + ppIFactory: *mut *mut c_void, + ) -> HRESULT; + pub fn D2D1MakeRotateMatrix( + angle: FLOAT, + center: D2D1_POINT_2F, + matrix: *mut D2D1_MATRIX_3X2_F, + ); + pub fn D2D1MakeSkewMatrix( + angleX: FLOAT, + angleY: FLOAT, + center: D2D1_POINT_2F, + matrix: *mut D2D1_MATRIX_3X2_F, + ); + pub fn D2D1IsMatrixInvertible( + matrix: *const D2D1_MATRIX_3X2_F, + ) -> BOOL; + pub fn D2D1InvertMatrix( + matrix: *mut D2D1_MATRIX_3X2_F, + ) -> BOOL; + pub fn D2D1ComputeMaximumScaleFactor( + matrix: *const D2D1_MATRIX_3X2_F, + ) -> FLOAT; +} diff --git a/winapi/src/um/d2d1_1.rs b/winapi/src/um/d2d1_1.rs new file mode 100644 index 000000000..8217e30ab --- /dev/null +++ b/winapi/src/um/d2d1_1.rs @@ -0,0 +1,847 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1_1.h +use ctypes::c_void; +use shared::basetsd::{UINT32, UINT64}; +use shared::dxgi::{IDXGIDevice, IDXGISurface}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::guiddef::{CLSID, REFCLSID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT}; +use um::d2d1::{ + D2D1_ANTIALIAS_MODE, D2D1_BRUSH_PROPERTIES, D2D1_CAP_STYLE, D2D1_COLOR_F, + D2D1_DASH_STYLE, D2D1_DEBUG_LEVEL, D2D1_EXTEND_MODE, D2D1_GRADIENT_STOP, + D2D1_INTERPOLATION_MODE_DEFINITION_ANISOTROPIC, D2D1_INTERPOLATION_MODE_DEFINITION_CUBIC, + D2D1_INTERPOLATION_MODE_DEFINITION_HIGH_QUALITY_CUBIC, + D2D1_INTERPOLATION_MODE_DEFINITION_LINEAR, + D2D1_INTERPOLATION_MODE_DEFINITION_MULTI_SAMPLE_LINEAR, + D2D1_INTERPOLATION_MODE_DEFINITION_NEAREST_NEIGHBOR, D2D1_LINE_JOIN, D2D1_MATRIX_3X2_F, + D2D1_POINT_2F, D2D1_RECT_F, D2D1_SIZE_U, D2D1_TAG, D2D1_TEXT_ANTIALIAS_MODE, ID2D1Bitmap, + ID2D1BitmapBrush, ID2D1BitmapBrushVtbl, ID2D1BitmapVtbl, ID2D1Brush, ID2D1BrushVtbl, + ID2D1DrawingStateBlock, ID2D1DrawingStateBlockVtbl, ID2D1Factory, ID2D1FactoryVtbl, + ID2D1Geometry, ID2D1GradientStopCollection, ID2D1GradientStopCollectionVtbl, ID2D1Image, + ID2D1ImageVtbl, ID2D1Layer, ID2D1Mesh, ID2D1PathGeometry, ID2D1PathGeometryVtbl, + ID2D1RenderTarget, ID2D1RenderTargetVtbl, ID2D1Resource, ID2D1ResourceVtbl, ID2D1StrokeStyle, + ID2D1StrokeStyleVtbl, +}; +use um::d2d1effectauthor::D2D1_PROPERTY_BINDING; +use um::d2dbasetypes::D2D_SIZE_F; +use um::dcommon::{D2D1_PIXEL_FORMAT, DWRITE_MEASURING_MODE}; +use um::documenttarget::IPrintDocumentPackageTarget; +use um::dwrite::{DWRITE_GLYPH_RUN, DWRITE_GLYPH_RUN_DESCRIPTION, IDWriteRenderingParams}; +use um::objidlbase::IStream; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wincodec::{IWICBitmapSource, IWICColorContext, IWICImagingFactory}; +use um::winnt::{HRESULT, PCWSTR, PWSTR}; +FN!{stdcall PD2D1_EFFECT_FACTORY( + effectImpl: *mut *mut IUnknown, +) -> HRESULT} +pub use um::d2dbasetypes::D2D_RECT_L as D2D1_RECT_L; +pub use um::d2dbasetypes::D2D_POINT_2L as D2D1_POINT_2L; +ENUM!{enum D2D1_PROPERTY_TYPE { + D2D1_PROPERTY_TYPE_UNKNOWN = 0, + D2D1_PROPERTY_TYPE_STRING = 1, + D2D1_PROPERTY_TYPE_BOOL = 2, + D2D1_PROPERTY_TYPE_UINT32 = 3, + D2D1_PROPERTY_TYPE_INT32 = 4, + D2D1_PROPERTY_TYPE_FLOAT = 5, + D2D1_PROPERTY_TYPE_VECTOR2 = 6, + D2D1_PROPERTY_TYPE_VECTOR3 = 7, + D2D1_PROPERTY_TYPE_VECTOR4 = 8, + D2D1_PROPERTY_TYPE_BLOB = 9, + D2D1_PROPERTY_TYPE_IUNKNOWN = 10, + D2D1_PROPERTY_TYPE_ENUM = 11, + D2D1_PROPERTY_TYPE_ARRAY = 12, + D2D1_PROPERTY_TYPE_CLSID = 13, + D2D1_PROPERTY_TYPE_MATRIX_3X2 = 14, + D2D1_PROPERTY_TYPE_MATRIX_4X3 = 15, + D2D1_PROPERTY_TYPE_MATRIX_4X4 = 16, + D2D1_PROPERTY_TYPE_MATRIX_5X4 = 17, + D2D1_PROPERTY_TYPE_COLOR_CONTEXT = 18, + D2D1_PROPERTY_TYPE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_PROPERTY { + D2D1_PROPERTY_CLSID = 0x80000000, + D2D1_PROPERTY_DISPLAYNAME = 0x80000001, + D2D1_PROPERTY_AUTHOR = 0x80000002, + D2D1_PROPERTY_CATEGORY = 0x80000003, + D2D1_PROPERTY_DESCRIPTION = 0x80000004, + D2D1_PROPERTY_INPUTS = 0x80000005, + D2D1_PROPERTY_CACHED = 0x80000006, + D2D1_PROPERTY_PRECISION = 0x80000007, + D2D1_PROPERTY_MIN_INPUTS = 0x80000008, + D2D1_PROPERTY_MAX_INPUTS = 0x80000009, + D2D1_PROPERTY_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SUBPROPERTY { + D2D1_SUBPROPERTY_DISPLAYNAME = 0x80000000, + D2D1_SUBPROPERTY_ISREADONLY = 0x80000001, + D2D1_SUBPROPERTY_MIN = 0x80000002, + D2D1_SUBPROPERTY_MAX = 0x80000003, + D2D1_SUBPROPERTY_DEFAULT = 0x80000004, + D2D1_SUBPROPERTY_FIELDS = 0x80000005, + D2D1_SUBPROPERTY_INDEX = 0x80000006, + D2D1_SUBPROPERTY_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BITMAP_OPTIONS { + D2D1_BITMAP_OPTIONS_NONE = 0x00000000, + D2D1_BITMAP_OPTIONS_TARGET = 0x00000001, + D2D1_BITMAP_OPTIONS_CANNOT_DRAW = 0x00000002, + D2D1_BITMAP_OPTIONS_CPU_READ = 0x00000004, + D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE = 0x00000008, + D2D1_BITMAP_OPTIONS_FORCE_DWORD = 0xffffffff, +}} +// DEFINE_ENUM_FLAG_OPERATORS(D2D1_BITMAP_OPTIONS); +ENUM!{enum D2D1_COMPOSITE_MODE { + D2D1_COMPOSITE_MODE_SOURCE_OVER = 0, + D2D1_COMPOSITE_MODE_DESTINATION_OVER = 1, + D2D1_COMPOSITE_MODE_SOURCE_IN = 2, + D2D1_COMPOSITE_MODE_DESTINATION_IN = 3, + D2D1_COMPOSITE_MODE_SOURCE_OUT = 4, + D2D1_COMPOSITE_MODE_DESTINATION_OUT = 5, + D2D1_COMPOSITE_MODE_SOURCE_ATOP = 6, + D2D1_COMPOSITE_MODE_DESTINATION_ATOP = 7, + D2D1_COMPOSITE_MODE_XOR = 8, + D2D1_COMPOSITE_MODE_PLUS = 9, + D2D1_COMPOSITE_MODE_SOURCE_COPY = 10, + D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY = 11, + D2D1_COMPOSITE_MODE_MASK_INVERT = 12, + D2D1_COMPOSITE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BUFFER_PRECISION { + D2D1_BUFFER_PRECISION_UNKNOWN = 0, + D2D1_BUFFER_PRECISION_8BPC_UNORM = 1, + D2D1_BUFFER_PRECISION_8BPC_UNORM_SRGB = 2, + D2D1_BUFFER_PRECISION_16BPC_UNORM = 3, + D2D1_BUFFER_PRECISION_16BPC_FLOAT = 4, + D2D1_BUFFER_PRECISION_32BPC_FLOAT = 5, + D2D1_BUFFER_PRECISION_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_MAP_OPTIONS { + D2D1_MAP_OPTIONS_NONE = 0, + D2D1_MAP_OPTIONS_READ = 1, + D2D1_MAP_OPTIONS_WRITE = 2, + D2D1_MAP_OPTIONS_DISCARD = 4, + D2D1_MAP_OPTIONS_FORCE_DWORD = 0xffffffff, +}} +//DEFINE_ENUM_FLAG_OPERATORS(D2D1_MAP_OPTIONS); +ENUM!{enum D2D1_INTERPOLATION_MODE { + D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR = D2D1_INTERPOLATION_MODE_DEFINITION_NEAREST_NEIGHBOR, + D2D1_INTERPOLATION_MODE_LINEAR = D2D1_INTERPOLATION_MODE_DEFINITION_LINEAR, + D2D1_INTERPOLATION_MODE_CUBIC = D2D1_INTERPOLATION_MODE_DEFINITION_CUBIC, + D2D1_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR + = D2D1_INTERPOLATION_MODE_DEFINITION_MULTI_SAMPLE_LINEAR, + D2D1_INTERPOLATION_MODE_ANISOTROPIC = D2D1_INTERPOLATION_MODE_DEFINITION_ANISOTROPIC, + D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC + = D2D1_INTERPOLATION_MODE_DEFINITION_HIGH_QUALITY_CUBIC, + D2D1_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_UNIT_MODE { + D2D1_UNIT_MODE_DIPS = 0, + D2D1_UNIT_MODE_PIXELS = 1, + D2D1_UNIT_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLOR_SPACE { + D2D1_COLOR_SPACE_CUSTOM = 0, + D2D1_COLOR_SPACE_SRGB = 1, + D2D1_COLOR_SPACE_SCRGB = 2, + D2D1_COLOR_SPACE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DEVICE_CONTEXT_OPTIONS { + D2D1_DEVICE_CONTEXT_OPTIONS_NONE = 0, + D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS = 1, + D2D1_DEVICE_CONTEXT_OPTIONS_FORCE_DWORD = 0xffffffff, +}} +//DEFINE_ENUM_FLAG_OPERATORS(D2D1_DEVICE_CONTEXT_OPTIONS); +ENUM!{enum D2D1_STROKE_TRANSFORM_TYPE { + D2D1_STROKE_TRANSFORM_TYPE_NORMAL = 0, + D2D1_STROKE_TRANSFORM_TYPE_FIXED = 1, + D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE = 2, + D2D1_STROKE_TRANSFORM_TYPE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_PRIMITIVE_BLEND { + D2D1_PRIMITIVE_BLEND_SOURCE_OVER = 0, + D2D1_PRIMITIVE_BLEND_COPY = 1, + D2D1_PRIMITIVE_BLEND_MIN = 2, + D2D1_PRIMITIVE_BLEND_ADD = 3, + D2D1_PRIMITIVE_BLEND_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_THREADING_MODE { + D2D1_THREADING_MODE_SINGLE_THREADED = super::d2d1::D2D1_FACTORY_TYPE_SINGLE_THREADED, + D2D1_THREADING_MODE_MULTI_THREADED = super::d2d1::D2D1_FACTORY_TYPE_MULTI_THREADED, + D2D1_THREADING_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLOR_INTERPOLATION_MODE { + D2D1_COLOR_INTERPOLATION_MODE_STRAIGHT = 0, + D2D1_COLOR_INTERPOLATION_MODE_PREMULTIPLIED = 1, + D2D1_COLOR_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +pub use um::d2dbasetypes::D2D_VECTOR_2F as D2D1_VECTOR_2F; +pub use um::d2dbasetypes::D2D_VECTOR_3F as D2D1_VECTOR_3F; +pub use um::d2dbasetypes::D2D_VECTOR_4F as D2D1_VECTOR_4F; +STRUCT!{struct D2D1_BITMAP_PROPERTIES1 { + pixelFormat: D2D1_PIXEL_FORMAT, + dpiX: FLOAT, + dpiY: FLOAT, + bitmapOptions: D2D1_BITMAP_OPTIONS, + colorContext: *const ID2D1ColorContext, +}} +STRUCT!{struct D2D1_MAPPED_RECT { + pitch: UINT32, + bits: *const BYTE, +}} +STRUCT!{struct D2D1_RENDERING_CONTROLS { + bufferPrecision: D2D1_BUFFER_PRECISION, + tileSize: D2D1_SIZE_U, +}} +STRUCT!{struct D2D1_EFFECT_INPUT_DESCRIPTION { + effect: *const ID2D1Effect, + inputIndex: UINT32, + inputRectangle: D2D1_RECT_F, +}} +pub use um::d2dbasetypes::D2D_MATRIX_4X3_F as D2D1_MATRIX_4X3_F; +pub use um::d2dbasetypes::D2D_MATRIX_4X4_F as D2D1_MATRIX_4X4_F; +pub use um::d2dbasetypes::D2D_MATRIX_5X4_F as D2D1_MATRIX_5X4_F; +STRUCT!{struct D2D1_POINT_DESCRIPTION { + point: D2D1_POINT_2F, + unitTangentVector: D2D1_POINT_2F, + endSegment: UINT32, + endFigure: UINT32, + lengthToEndSegment: FLOAT, +}} +STRUCT!{struct D2D1_IMAGE_BRUSH_PROPERTIES { + sourceRectangle: D2D1_RECT_F, + extendModeX: D2D1_EXTEND_MODE, + extendModeY: D2D1_EXTEND_MODE, + interpolationMode: D2D1_INTERPOLATION_MODE, +}} +STRUCT!{struct D2D1_BITMAP_BRUSH_PROPERTIES1 { + extendModeX: D2D1_EXTEND_MODE, + extendModeY: D2D1_EXTEND_MODE, + interpolationMode: D2D1_INTERPOLATION_MODE, +}} +STRUCT!{struct D2D1_STROKE_STYLE_PROPERTIES1 { + startCap: D2D1_CAP_STYLE, + endCap: D2D1_CAP_STYLE, + dashCap: D2D1_CAP_STYLE, + lineJoin: D2D1_LINE_JOIN, + miterLimit: FLOAT, + dashStyle: D2D1_DASH_STYLE, + dashOffset: FLOAT, + transformType: D2D1_STROKE_TRANSFORM_TYPE, +}} +ENUM!{enum D2D1_LAYER_OPTIONS1 { + D2D1_LAYER_OPTIONS1_NONE = 0, + D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND = 1, + D2D1_LAYER_OPTIONS1_IGNORE_ALPHA = 2, + D2D1_LAYER_OPTIONS1_FORCE_DWORD = 0xffffffff, +}} +//DEFINE_ENUM_FLAG_OPERATORS(D2D1_LAYER_OPTIONS1); +STRUCT!{struct D2D1_LAYER_PARAMETERS1 { + contentBounds: D2D1_RECT_F, + geometricMask: *const ID2D1Geometry, + maskAntialiasMode: D2D1_ANTIALIAS_MODE, + maskTransform: D2D1_MATRIX_3X2_F, + opacity: FLOAT, + opacityBrush: *const ID2D1Brush, + layerOptions: D2D1_LAYER_OPTIONS1, +}} +ENUM!{enum D2D1_PRINT_FONT_SUBSET_MODE { + D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT = 0, + D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE = 1, + D2D1_PRINT_FONT_SUBSET_MODE_NONE = 2, + D2D1_PRINT_FONT_SUBSET_MODE_FORCE_DWORD = 0xffffffff, +}} +STRUCT!{struct D2D1_DRAWING_STATE_DESCRIPTION1 { + antialiasMode: D2D1_ANTIALIAS_MODE, + textAntialiasMode: D2D1_TEXT_ANTIALIAS_MODE, + tag1: D2D1_TAG, + tag2: D2D1_TAG, + transform: D2D1_MATRIX_3X2_F, + primitiveBlend: D2D1_PRIMITIVE_BLEND, + unitMode: D2D1_UNIT_MODE, +}} +STRUCT!{struct D2D1_PRINT_CONTROL_PROPERTIES { + fontSubset: D2D1_PRINT_FONT_SUBSET_MODE, + rasterDPI: FLOAT, + colorSpace: D2D1_COLOR_SPACE, +}} +STRUCT!{struct D2D1_CREATION_PROPERTIES { + threadingMode: D2D1_THREADING_MODE, + debugLevel: D2D1_DEBUG_LEVEL, + options: D2D1_DEVICE_CONTEXT_OPTIONS, +}} +RIDL!{#[uuid(0x82237326, 0x8111, 0x4f7c, 0xbc, 0xf4, 0xb5, 0xc1, 0x17, 0x55, 0x64, 0xfe)] +interface ID2D1GdiMetafileSink(ID2D1GdiMetafileSinkVtbl): IUnknown(IUnknownVtbl) { + fn ProcessRecord( + recordType: DWORD, + recordData: *const c_void, + recordDataSize: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2f543dc3, 0xcfc1, 0x4211, 0x86, 0x4f, 0xcf, 0xd9, 0x1c, 0x6f, 0x33, 0x95)] +interface ID2D1GdiMetafile(ID2D1GdiMetafileVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn Stream( + sink: *const ID2D1GdiMetafileSink, + ) -> HRESULT, + fn GetBounds( + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x54d7898a, 0xa061, 0x40a7, 0xbe, 0xc7, 0xe4, 0x65, 0xbc, 0xba, 0x2c, 0x4f)] +interface ID2D1CommandSink(ID2D1CommandSinkVtbl): IUnknown(IUnknownVtbl) { + fn BeginDraw() -> HRESULT, + fn EndDraw() -> HRESULT, + fn SetAntialiasMode( + antialiasMode: D2D1_ANTIALIAS_MODE, + ) -> HRESULT, + fn SetTags( + tag1: D2D1_TAG, + tag2: D2D1_TAG, + ) -> HRESULT, + fn SetTextAntialiasMode( + textAntialiasMode: D2D1_TEXT_ANTIALIAS_MODE, + ) -> HRESULT, + fn SetTextRenderingParams( + textRenderingParams: *const IDWriteRenderingParams, + ) -> HRESULT, + fn SetTransform( + transform: *const D2D1_MATRIX_3X2_F, + ) -> HRESULT, + fn SetPrimitiveBlend( + primitiveBlend: D2D1_PRIMITIVE_BLEND, + ) -> HRESULT, + fn SetUnitMode( + unitMode: D2D1_UNIT_MODE, + ) -> HRESULT, + fn Clear( + color: *const D2D1_COLOR_F, + ) -> HRESULT, + fn DrawGlyphRun( + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + glyphRunDescription: *const DWRITE_GLYPH_RUN_DESCRIPTION, + foregroundBrush: *const ID2D1Brush, + measuringMode: DWRITE_MEASURING_MODE, + ) -> HRESULT, + fn DrawLine( + point0: D2D1_POINT_2F, + point1: D2D1_POINT_2F, + brush: *const ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *const ID2D1StrokeStyle, + ) -> HRESULT, + fn DrawGeometry( + geometry: *const ID2D1Geometry, + brush: *const ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *const ID2D1StrokeStyle, + ) -> HRESULT, + fn DrawRectangle( + rect: *const D2D1_RECT_F, + brush: *const ID2D1Brush, + strokeWidth: FLOAT, + strokeStyle: *const ID2D1StrokeStyle, + ) -> HRESULT, + fn DrawBitmap( + bitmap: *const ID2D1Bitmap, + destinationRectangle: *const D2D1_RECT_F, + opacity: FLOAT, + interpolationMode: D2D1_INTERPOLATION_MODE, + sourceRectangle: *const D2D1_RECT_F, + perspectiveTransform: *const D2D1_MATRIX_4X4_F, + ) -> HRESULT, + fn DrawImage( + image: *const ID2D1Image, + targetOffset: *const D2D1_POINT_2F, + imageRectangle: *const D2D1_RECT_F, + interpolationMode: D2D1_INTERPOLATION_MODE, + compositeMode: D2D1_COMPOSITE_MODE, + ) -> HRESULT, + fn DrawGdiMetafile( + gdiMetafile: *const ID2D1GdiMetafile, + targetOffset: *const D2D1_POINT_2F, + ) -> HRESULT, + fn FillMesh( + mesh: *const ID2D1Mesh, + brush: *const ID2D1Brush, + ) -> HRESULT, + fn FillOpacityMask( + opacityMask: *const ID2D1Bitmap, + brush: *const ID2D1Brush, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangle: *const D2D1_RECT_F, + ) -> HRESULT, + fn FillGeometry( + geometry: *const ID2D1Geometry, + brush: *const ID2D1Brush, + opacityBrush: *const ID2D1Brush, + ) -> HRESULT, + fn FillRectangle( + rect: *const D2D1_RECT_F, + brush: *const ID2D1Brush, + ) -> HRESULT, + fn PushAxisAlignedClip( + clipRect: *const D2D1_RECT_F, + antialiasMode: D2D1_ANTIALIAS_MODE, + ) -> HRESULT, + fn PushLayer( + layerParameters1: *const D2D1_LAYER_PARAMETERS1, + layer: *const ID2D1Layer, + ) -> HRESULT, + fn PopAxisAlignedClip() -> HRESULT, + fn PopLayer() -> HRESULT, +}} +RIDL!{#[uuid(0xb4f34a19, 0x2383, 0x4d76, 0x94, 0xf6, 0xec, 0x34, 0x36, 0x57, 0xc3, 0xdc)] +interface ID2D1CommandList(ID2D1CommandListVtbl): ID2D1Image(ID2D1ImageVtbl) { + fn Stream( + sink: *const ID2D1CommandSink, + ) -> HRESULT, + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0x2c1d867d, 0xc290, 0x41c8, 0xae, 0x7e, 0x34, 0xa9, 0x87, 0x02, 0xe9, 0xa5)] +interface ID2D1PrintControl(ID2D1PrintControlVtbl): IUnknown(IUnknownVtbl) { + fn AddPage( + commandList: *const ID2D1CommandList, + pageSize: D2D_SIZE_F, + pagePrintTicketStream: *const IStream, + tag1: *mut D2D1_TAG, + tag2: *mut D2D1_TAG, + ) -> HRESULT, + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0xfe9e984d, 0x3f95, 0x407c, 0xb5, 0xdb, 0xcb, 0x94, 0xd4, 0xe8, 0xf8, 0x7c)] +interface ID2D1ImageBrush(ID2D1ImageBrushVtbl): ID2D1Brush(ID2D1BrushVtbl) { + fn SetImage( + image: *const ID2D1Image, + ) -> (), + fn SetExtendModeX( + extendModeX: D2D1_EXTEND_MODE, + ) -> (), + fn SetExtendModeY( + extendModeY: D2D1_EXTEND_MODE, + ) -> (), + fn SetInterpolationMode( + interpolationMode: D2D1_INTERPOLATION_MODE, + ) -> (), + fn SetSourceRectangle( + sourceRectangle: *const D2D1_RECT_F, + ) -> (), + fn GetImage( + image: *mut *mut ID2D1Image, + ) -> (), + fn GetExtendModeX() -> D2D1_EXTEND_MODE, + fn GetExtendModeY() -> D2D1_EXTEND_MODE, + fn GetInterpolationMode() -> D2D1_INTERPOLATION_MODE, + fn GetSourceRectangle( + sourceRectangle: *mut D2D1_RECT_F, + ) -> (), +}} +RIDL!{#[uuid(0x41343a53, 0xe41a, 0x49a2, 0x91, 0xcd, 0x21, 0x79, 0x3b, 0xbb, 0x62, 0xe5)] +interface ID2D1BitmapBrush1(ID2D1BitmapBrush1Vtbl): ID2D1BitmapBrush(ID2D1BitmapBrushVtbl) { + fn SetInterpolationMode1( + interpolationMode: D2D1_INTERPOLATION_MODE, + ) -> (), + fn GetInterpolationMode1() -> D2D1_INTERPOLATION_MODE, +}} +RIDL!{#[uuid(0x10a72a66, 0xe91c, 0x43f4, 0x99, 0x3f, 0xdd, 0xf4, 0xb8, 0x2b, 0x0b, 0x4a)] +interface ID2D1StrokeStyle1(ID2D1StrokeStyle1Vtbl): ID2D1StrokeStyle(ID2D1StrokeStyleVtbl) { + fn GetStrokeTransformType() -> D2D1_STROKE_TRANSFORM_TYPE, +}} +RIDL!{#[uuid(0x62baa2d2, 0xab54, 0x41b7, 0xb8, 0x72, 0x78, 0x7e, 0x01, 0x06, 0xa4, 0x21)] +interface ID2D1PathGeometry1(ID2D1PathGeometry1Vtbl): ID2D1PathGeometry(ID2D1PathGeometryVtbl) { + fn ComputePointAndSegmentAtLength( + length: FLOAT, + startSegment: UINT32, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + pointDescription: *mut D2D1_POINT_DESCRIPTION, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x483473d7, 0xcd46, 0x4f9d, 0x9d, 0x3a, 0x31, 0x12, 0xaa, 0x80, 0x15, 0x9d)] +interface ID2D1Properties(ID2D1PropertiesVtbl): IUnknown(IUnknownVtbl) { + fn GetPropertyCount() -> UINT32, + fn GetPropertyName( + index: UINT32, + name: PWSTR, + nameCount: UINT32, + ) -> HRESULT, + fn GetPropertyNameLength( + index: UINT32, + ) -> UINT32, + fn GetType( + index: UINT32, + ) -> D2D1_PROPERTY_TYPE, + fn GetPropertyIndex( + name: PCWSTR, + ) -> UINT32, + fn SetValueByName( + name: PCWSTR, + prop_type: D2D1_PROPERTY_TYPE, + data: *const BYTE, + dataSize: UINT32, + ) -> HRESULT, + fn SetValue( + index: UINT32, + prop_type: D2D1_PROPERTY_TYPE, + data: *const BYTE, + dataSize: UINT32, + ) -> HRESULT, + fn GetValueByName( + name: PCWSTR, + prop_type: D2D1_PROPERTY_TYPE, + data: *mut BYTE, + dataSize: UINT32, + ) -> HRESULT, + fn GetValue( + index: UINT32, + prop_type: D2D1_PROPERTY_TYPE, + data: *mut BYTE, + dataSize: UINT32, + ) -> HRESULT, + fn GetValueSize( + index: UINT32, + ) -> UINT32, + fn GetSubProperties( + index: UINT32, + subProperties: *mut *mut ID2D1Properties, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x28211a43, 0x7d89, 0x476f, 0x81, 0x81, 0x2d, 0x61, 0x59, 0xb2, 0x20, 0xad)] +interface ID2D1Effect(ID2D1EffectVtbl): ID2D1Properties(ID2D1PropertiesVtbl) { + fn SetInput( + index: UINT32, + input: *const ID2D1Image, + invalidate: BOOL, + ) -> (), + fn SetInputCount( + inputCount: UINT32, + ) -> HRESULT, + fn GetInput( + index: UINT32, + input: *mut *mut ID2D1Image, + ) -> (), + fn GetInputCount() -> UINT32, + fn GetOutput( + outputImage: *mut *mut ID2D1Image, + ) -> (), +}} +RIDL!{#[uuid(0xa898a84c, 0x3873, 0x4588, 0xb0, 0x8b, 0xeb, 0xbf, 0x97, 0x8d, 0xf0, 0x41)] +interface ID2D1Bitmap1(ID2D1Bitmap1Vtbl): ID2D1Bitmap(ID2D1BitmapVtbl) { + fn GetColorContext( + colorContext: *mut *mut ID2D1ColorContext, + ) -> (), + fn GetOptions() -> D2D1_BITMAP_OPTIONS, + fn GetSurface( + dxgiSurface: *mut *mut IDXGISurface, + ) -> HRESULT, + fn Map( + options: D2D1_MAP_OPTIONS, + mappedRect: *mut D2D1_MAPPED_RECT, + ) -> HRESULT, + fn Unmap() -> HRESULT, +}} +RIDL!{#[uuid(0x1c4820bb, 0x5771, 0x4518, 0xa5, 0x81, 0x2f, 0xe4, 0xdd, 0x0e, 0xc6, 0x57)] +interface ID2D1ColorContext(ID2D1ColorContextVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetColorSpace() -> D2D1_COLOR_SPACE, + fn GetProfileSize() -> UINT32, + fn GetProfile( + profile: *mut BYTE, + profileSize: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xae1572f4, 0x5dd0, 0x4777, 0x99, 0x8b, 0x92, 0x79, 0x47, 0x2a, 0xe6, 0x3b)] +interface ID2D1GradientStopCollection1(ID2D1GradientStopCollection1Vtbl): + ID2D1GradientStopCollection(ID2D1GradientStopCollectionVtbl) { + fn GetGradientStops1( + gradientStops: *mut D2D1_GRADIENT_STOP, + gradientStopsCount: UINT32, + ) -> (), + fn GetPreInterpolationSpace() -> D2D1_COLOR_SPACE, + fn GetPostInterpolationSpace() -> D2D1_COLOR_SPACE, + fn GetBufferPrecision() -> D2D1_BUFFER_PRECISION, + fn GetColorInterpolationMode() -> D2D1_COLOR_INTERPOLATION_MODE, +}} +RIDL!{#[uuid(0x689f1f85, 0xc72e, 0x4e33, 0x8f, 0x19, 0x85, 0x75, 0x4e, 0xfd, 0x5a, 0xce)] +interface ID2D1DrawingStateBlock1(ID2D1DrawingStateBlock1Vtbl): + ID2D1DrawingStateBlock(ID2D1DrawingStateBlockVtbl) { + fn GetDescription( + stateDescription: *mut D2D1_DRAWING_STATE_DESCRIPTION1, + ) -> (), + fn SetDescription( + stateDescription: *const D2D1_DRAWING_STATE_DESCRIPTION1, + ) -> (), +}} +RIDL!{#[uuid(0xe8f7fe7a, 0x191c, 0x466d, 0xad, 0x95, 0x97, 0x56, 0x78, 0xbd, 0xa9, 0x98)] +interface ID2D1DeviceContext(ID2D1DeviceContextVtbl): ID2D1RenderTarget(ID2D1RenderTargetVtbl) { + fn CreateBitmap( + size: D2D1_SIZE_U, + sourceData: *const c_void, + pitch: UINT32, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES1, + bitmap: *mut *mut ID2D1Bitmap1, + ) -> HRESULT, + fn CreateBitmapFromWicBitmap( + wicBitmapSource: *const IWICBitmapSource, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES1, + bitmap: *mut *mut ID2D1Bitmap1, + ) -> HRESULT, + fn CreateColorContext( + space: D2D1_COLOR_SPACE, + profile: *const BYTE, + profileSize: UINT32, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CreateColorContextFromFilename( + filename: PCWSTR, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CreateColorContextFromWicColorContext( + wicColorContext: *const IWICColorContext, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CreateBitmapFromDxgiSurface( + surface: *const IDXGISurface, + bitmapProperties: *const D2D1_BITMAP_PROPERTIES1, + bitmap: *mut *mut ID2D1Bitmap1, + ) -> HRESULT, + fn CreateEffect( + effectId: REFCLSID, + effect: *mut *mut ID2D1Effect, + ) -> HRESULT, + fn CreateGradientStopCollection( + straightAlphaGradientStops: *const D2D1_GRADIENT_STOP, + straightAlphaGradientStopsCount: UINT32, + preInterpolationSpace: D2D1_COLOR_SPACE, + postInterpolationSpace: D2D1_COLOR_SPACE, + bufferPrecision: D2D1_BUFFER_PRECISION, + extendMode: D2D1_EXTEND_MODE, + colorInterpolationMode: D2D1_COLOR_INTERPOLATION_MODE, + gradientStopCollection1: *mut *mut ID2D1GradientStopCollection1, + ) -> HRESULT, + fn CreateImageBrush( + image: *const ID2D1Image, + imageBrushProperties: *const D2D1_IMAGE_BRUSH_PROPERTIES, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + imageBrush: *mut *mut ID2D1ImageBrush, + ) -> HRESULT, + fn CreateBitmapBrush( + bitmap: *const ID2D1Bitmap, + bitmapBrushProperties: *const D2D1_BITMAP_BRUSH_PROPERTIES1, + brushProperties: *const D2D1_BRUSH_PROPERTIES, + bitmapBrush: *mut *mut ID2D1BitmapBrush1, + ) -> HRESULT, + fn CreateCommandList( + commandList: *mut *mut ID2D1CommandList, + ) -> HRESULT, + fn IsDxgiFormatSupported( + format: DXGI_FORMAT, + ) -> BOOL, + fn IsBufferPrecisionSupported( + bufferPrecision: D2D1_BUFFER_PRECISION, + ) -> BOOL, + fn GetImageLocalBounds( + image: *const ID2D1Image, + localBounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn GetImageWorldBounds( + image: *const ID2D1Image, + worldBounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn GetGlyphRunWorldBounds( + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + measuringMode: DWRITE_MEASURING_MODE, + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn GetDevice( + device: *mut *mut ID2D1Device, + ) -> (), + fn SetTarget( + image: *const ID2D1Image, + ) -> (), + fn GetTarget( + image: *mut *mut ID2D1Image, + ) -> (), + fn SetRenderingControls( + renderingControls: *const D2D1_RENDERING_CONTROLS, + ) -> (), + fn GetRenderingControls( + renderingControls: *mut D2D1_RENDERING_CONTROLS, + ) -> (), + fn SetPrimitiveBlend( + primitiveBlend: D2D1_PRIMITIVE_BLEND, + ) -> (), + fn GetPrimitiveBlend() -> D2D1_PRIMITIVE_BLEND, + fn SetUnitMode( + unitMode: D2D1_UNIT_MODE, + ) -> (), + fn GetUnitMode() -> D2D1_UNIT_MODE, + fn DrawGlyphRun( + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + glyphRunDescription: *const DWRITE_GLYPH_RUN_DESCRIPTION, + foregroundBrush: *const ID2D1Brush, + measuringMode: DWRITE_MEASURING_MODE, + ) -> (), + fn DrawImage( + image: *const ID2D1Image, + targetOffset: *const D2D1_POINT_2F, + imageRectangle: *const D2D1_RECT_F, + interpolationMode: D2D1_INTERPOLATION_MODE, + compositeMode: D2D1_COMPOSITE_MODE, + ) -> (), + fn DrawGdiMetafile( + gdiMetafile: *const ID2D1GdiMetafile, + targetOffset: *const D2D1_POINT_2F, + ) -> (), + fn DrawBitmap( + bitmap: *const ID2D1Bitmap, + destinationRectangle: *const D2D1_RECT_F, + opacity: FLOAT, + interpolationMode: D2D1_INTERPOLATION_MODE, + sourceRectangle: *const D2D1_RECT_F, + perspectiveTransform: *const D2D1_MATRIX_4X4_F, + ) -> (), + fn PushLayer( + layerParameters: *const D2D1_LAYER_PARAMETERS1, + layer: *const ID2D1Layer, + ) -> (), + fn InvalidateEffectInputRectangle( + effect: *const ID2D1Effect, + input: UINT32, + inputRectangle: *const D2D1_RECT_F, + ) -> HRESULT, + fn GetEffectInvalidRectangleCount( + effect: *const ID2D1Effect, + rectangleCount: *mut UINT32, + ) -> HRESULT, + fn GetEffectInvalidRectangles( + effect: *const ID2D1Effect, + rectangles: *mut D2D1_RECT_F, + rectanglesCount: UINT32, + ) -> HRESULT, + fn GetEffectRequiredInputRectangles( + renderEffect: *const ID2D1Effect, + renderImageRectangle: *const D2D1_RECT_F, + inputDescriptions: *const D2D1_EFFECT_INPUT_DESCRIPTION, + requiredInputRects: *mut D2D1_RECT_F, + inputCount: UINT32, + ) -> HRESULT, + fn FillOpacityMask( + opacityMask: *const ID2D1Bitmap, + brush: *const ID2D1Brush, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangle: *const D2D1_RECT_F, + ) -> (), +}} +RIDL!{#[uuid(0x47dd575d, 0xac05, 0x4cdd, 0x80, 0x49, 0x9b, 0x02, 0xcd, 0x16, 0xf4, 0x4c)] +interface ID2D1Device(ID2D1DeviceVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext: *mut *mut ID2D1DeviceContext, + ) -> HRESULT, + fn CreatePrintControl( + wicFactory: *const IWICImagingFactory, + documentTarget: *const IPrintDocumentPackageTarget, + printControlProperties: *const D2D1_PRINT_CONTROL_PROPERTIES, + printControl: *mut *mut ID2D1PrintControl, + ) -> HRESULT, + fn SetMaximumTextureMemory( + maximumInBytes: UINT64, + ) -> (), + fn GetMaximumTextureMemory() -> UINT64, + fn ClearResources( + millisecondsSinceUse: UINT32, + ) -> (), +}} +RIDL!{#[uuid(0xbb12d362, 0xdaee, 0x4b9a, 0xaa, 0x1d, 0x14, 0xba, 0x40, 0x1c, 0xfa, 0x1f)] +interface ID2D1Factory1(ID2D1Factory1Vtbl): ID2D1Factory(ID2D1FactoryVtbl) { + fn CreateDevice( + dxgiDevice: *const IDXGIDevice, + d2dDevice: *mut *mut ID2D1Device, + ) -> HRESULT, + fn CreateStrokeStyle( + strokeStyleProperties: *const D2D1_STROKE_STYLE_PROPERTIES1, + dashes: *const FLOAT, + dashesCount: UINT32, + strokeStyle: *mut *mut ID2D1StrokeStyle1, + ) -> HRESULT, + fn CreatePathGeometry( + pathGeometry: *mut *mut ID2D1PathGeometry1, + ) -> HRESULT, + fn CreateDrawingStateBlock( + drawingStateDescription: *const D2D1_DRAWING_STATE_DESCRIPTION1, + textRenderingParams: *const IDWriteRenderingParams, + drawingStateBlock: *mut *mut ID2D1DrawingStateBlock1, + ) -> HRESULT, + fn CreateGdiMetafile( + metafileStream: *const IStream, + metafile: *mut *mut ID2D1GdiMetafile, + ) -> HRESULT, + fn RegisterEffectFromStream( + classId: REFCLSID, + propertyXml: *const IStream, + bindings: *const D2D1_PROPERTY_BINDING, + bindingsCount: UINT32, + effectFactory: PD2D1_EFFECT_FACTORY, + ) -> HRESULT, + fn RegisterEffectFromString( + classId: REFCLSID, + propertyXml: PCWSTR, + bindings: *const D2D1_PROPERTY_BINDING, + bindingsCount: UINT32, + effectFactory: PD2D1_EFFECT_FACTORY, + ) -> HRESULT, + fn UnregisterEffect( + classId: REFCLSID, + ) -> HRESULT, + fn GetRegisteredEffects( + effects: *mut CLSID, + effectsCount: UINT32, + effectsReturned: *mut UINT32, + effectsRegistered: *mut UINT32, + ) -> HRESULT, + fn GetEffectProperties( + effectId: REFCLSID, + properties: *mut *mut ID2D1Properties, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x31e6e7bc, 0xe0ff, 0x4d46, 0x8c, 0x64, 0xa0, 0xa8, 0xc4, 0x1c, 0x15, 0xd3)] +interface ID2D1Multithread(ID2D1MultithreadVtbl): IUnknown(IUnknownVtbl) { + fn GetMultithreadProtected() -> BOOL, + fn Enter() -> (), + fn Leave() -> (), +}} +extern "system" { + pub fn D2D1CreateDevice( + dxgiDevice: *const IDXGIDevice, + creationProperties: *const D2D1_CREATION_PROPERTIES, + d2dDevice: *mut *mut ID2D1Device, + ) -> HRESULT; + pub fn D2D1CreateDeviceContext( + dxgiSurface: *const IDXGISurface, + creationProperties: *const D2D1_CREATION_PROPERTIES, + d2dDeviceContext: *mut *mut ID2D1DeviceContext, + ) -> HRESULT; + pub fn D2D1ConvertColorSpace( + sourceColorSpace: D2D1_COLOR_SPACE, + destinationColorSpace: D2D1_COLOR_SPACE, + color: *const D2D1_COLOR_F, + ) -> D2D1_COLOR_F; + pub fn D2D1SinCos( + angle: FLOAT, + s: *mut FLOAT, + c: *mut FLOAT, + ) -> (); + pub fn D2D1Tan( + angle: FLOAT, + ) -> FLOAT; + pub fn D2D1Vec3Length( + x: FLOAT, + y: FLOAT, + z: FLOAT, + ) -> FLOAT; +} diff --git a/winapi/src/um/d2d1_2.rs b/winapi/src/um/d2d1_2.rs new file mode 100644 index 000000000..31b051390 --- /dev/null +++ b/winapi/src/um/d2d1_2.rs @@ -0,0 +1,68 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1_2.h +use shared::dxgi::IDXGIDevice; +use shared::minwindef::FLOAT; +use um::d2d1::{ID2D1Brush, ID2D1Geometry, ID2D1StrokeStyle}; +use um::d2d1::{ID2D1Resource, ID2D1ResourceVtbl}; +use um::d2d1_1::{D2D1_DEVICE_CONTEXT_OPTIONS, D2D1_PRIMITIVE_BLEND}; +use um::d2d1_1::{ID2D1DeviceContext, ID2D1DeviceContextVtbl}; +use um::d2d1_1::{ID2D1Device, ID2D1DeviceVtbl}; +use um::d2d1_1::{ID2D1Factory1, ID2D1Factory1Vtbl}; +use um::d2d1_1::{ID2D1CommandSink, ID2D1CommandSinkVtbl}; +use um::winnt::HRESULT; +ENUM!{enum D2D1_RENDERING_PRIORITY { + D2D1_RENDERING_PRIORITY_NORMAL = 0, + D2D1_RENDERING_PRIORITY_LOW = 1, + D2D1_RENDERING_PRIORITY_FORCE_DWORD = 0xffffffff, +}} +RIDL!{#[uuid(0xa16907d7, 0xbc02, 0x4801, 0x99, 0xe8, 0x8c, 0xf7, 0xf4, 0x85, 0xf7, 0x74)] +interface ID2D1GeometryRealization(ID2D1GeometryRealizationVtbl): + ID2D1Resource(ID2D1ResourceVtbl) {}} +RIDL!{#[uuid(0xd37f57e4, 0x6908, 0x459f, 0xa1, 0x99, 0xe7, 0x2f, 0x24, 0xf7, 0x99, 0x87)] +interface ID2D1DeviceContext1(ID2D1DeviceContext1Vtbl): + ID2D1DeviceContext(ID2D1DeviceContextVtbl) { + fn CreateFilledGeometryRealization( + geometry: *mut ID2D1Geometry, + flatteningTolerance: FLOAT, + geometryRealization: *mut *mut ID2D1GeometryRealization, + ) -> HRESULT, + fn CreateStrokedGeometryRealization( + geometry: *mut ID2D1Geometry, + flatteningTolerance: FLOAT, + strokeWidth: FLOAT, + strokeStyle: *mut ID2D1StrokeStyle, + geometryRealization: *mut *mut ID2D1GeometryRealization, + ) -> HRESULT, + fn DrawGeometryRealization( + geometryRealization: *mut ID2D1GeometryRealization, + brush: *mut ID2D1Brush, + ) -> (), +}} +RIDL!{#[uuid(0xd21768e1, 0x23a4, 0x4823, 0xa1, 0x4b, 0x7c, 0x3e, 0xba, 0x85, 0xd6, 0x58)] +interface ID2D1Device1(ID2D1Device1Vtbl): ID2D1Device(ID2D1DeviceVtbl) { + fn GetRenderingPriority() -> D2D1_RENDERING_PRIORITY, + fn SetRenderingPriority( + renderingPriority: D2D1_RENDERING_PRIORITY, + ) -> (), + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext1: *mut *mut ID2D1DeviceContext1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x94f81a73, 0x9212, 0x4376, 0x9c, 0x58, 0xb1, 0x6a, 0x3a, 0x0d, 0x39, 0x92)] +interface ID2D1Factory2(ID2D1Factory2Vtbl): ID2D1Factory1(ID2D1Factory1Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice1: *mut *mut ID2D1Device1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9eb767fd, 0x4269, 0x4467, 0xb8, 0xc2, 0xeb, 0x30, 0xcb, 0x30, 0x57, 0x43)] +interface ID2D1CommandSink1(ID2D1CommandSink1Vtbl): ID2D1CommandSink(ID2D1CommandSinkVtbl) { + fn SetPrimitiveBlend1( + primitiveBlend: D2D1_PRIMITIVE_BLEND, + ) -> HRESULT, +}} diff --git a/winapi/src/um/d2d1_3.rs b/winapi/src/um/d2d1_3.rs new file mode 100644 index 000000000..64b7bd394 --- /dev/null +++ b/winapi/src/um/d2d1_3.rs @@ -0,0 +1,698 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1_3.h +use ctypes::c_void; +use shared::basetsd::{UINT16, UINT32, UINT64}; +use shared::dxgi::{IDXGIDevice, IDXGISurface}; +use shared::dxgitype::DXGI_COLOR_SPACE_TYPE; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT}; +use shared::ntdef::WCHAR; +use shared::winerror::HRESULT; +use um::d2d1::{ + D2D1_BITMAP_INTERPOLATION_MODE, D2D1_COLOR_F, D2D1_DRAW_TEXT_OPTIONS, D2D1_GAMMA_1_0, + D2D1_GAMMA_2_2, D2D1_MATRIX_3X2_F, D2D1_POINT_2F, D2D1_RECT_F, D2D1_RECT_U, D2D1_SIZE_F, + ID2D1Bitmap, ID2D1Brush, ID2D1Image, ID2D1ImageVtbl, ID2D1Resource, ID2D1ResourceVtbl, + ID2D1SimplifiedGeometrySink, +}; +use um::d2d1_1::{ + D2D1_BUFFER_PRECISION, D2D1_DEVICE_CONTEXT_OPTIONS, D2D1_INTERPOLATION_MODE, + D2D1_PRIMITIVE_BLEND, ID2D1ColorContext, ID2D1ColorContextVtbl, ID2D1CommandList, + ID2D1GdiMetafile, ID2D1GdiMetafileSink, ID2D1GdiMetafileSinkVtbl, ID2D1GdiMetafileVtbl, +}; +use um::d2d1_2::{ + ID2D1CommandSink1, ID2D1CommandSink1Vtbl, ID2D1Device1, ID2D1Device1Vtbl, ID2D1DeviceContext1, + ID2D1DeviceContext1Vtbl, ID2D1Factory2, ID2D1Factory2Vtbl, +}; +use um::d2d1effects::D2D1_BLEND_MODE; +use um::d2d1svg::ID2D1SvgDocument; +use um::dcommon::{D2D1_ALPHA_MODE, DWRITE_GLYPH_IMAGE_FORMATS, DWRITE_MEASURING_MODE}; +use um::dwrite::{DWRITE_GLYPH_RUN, IDWriteFontFace, IDWriteTextFormat, IDWriteTextLayout}; +use um::objidlbase::IStream; +use um::wincodec::IWICBitmapSource; +ENUM!{enum D2D1_INK_NIB_SHAPE { + D2D1_INK_NIB_SHAPE_ROUND = 0, + D2D1_INK_NIB_SHAPE_SQUARE = 1, +}} +ENUM!{enum D2D1_ORIENTATION { + D2D1_ORIENTATION_DEFAULT = 1, + D2D1_ORIENTATION_FLIP_HORIZONTAL = 2, + D2D1_ORIENTATION_ROTATE_CLOCKWISE180 = 3, + D2D1_ORIENTATION_ROTATE_CLOCKWISE180_FLIP_HORIZONTAL = 4, + D2D1_ORIENTATION_ROTATE_CLOCKWISE90_FLIP_HORIZONTAL = 5, + D2D1_ORIENTATION_ROTATE_CLOCKWISE270 = 6, + D2D1_ORIENTATION_ROTATE_CLOCKWISE270_FLIP_HORIZONTAL = 7, + D2D1_ORIENTATION_ROTATE_CLOCKWISE90 = 8, +}} +ENUM!{enum D2D1_IMAGE_SOURCE_LOADING_OPTIONS { + D2D1_IMAGE_SOURCE_LOADING_OPTIONS_NONE = 0, + D2D1_IMAGE_SOURCE_LOADING_OPTIONS_RELEASE_SOURCE = 1, + D2D1_IMAGE_SOURCE_LOADING_OPTIONS_CACHE_ON_DEMAND = 2, +}} +ENUM!{enum D2D1_IMAGE_SOURCE_FROM_DXGI_OPTIONS { + D2D1_IMAGE_SOURCE_FROM_DXGI_OPTIONS_NONE = 0, + D2D1_IMAGE_SOURCE_FROM_DXGI_OPTIONS_LOW_QUALITY_PRIMARY_CONVERSION = 1, +}} +ENUM!{enum D2D1_TRANSFORMED_IMAGE_SOURCE_OPTIONS { + D2D1_TRANSFORMED_IMAGE_SOURCE_OPTIONS_NONE = 0, + D2D1_TRANSFORMED_IMAGE_SOURCE_OPTIONS_DISABLE_DPI_SCALE = 1, +}} +STRUCT!{struct D2D1_TRANSFORMED_IMAGE_SOURCE_PROPERTIES { + orientation: D2D1_ORIENTATION, + scaleX: FLOAT, + scaleY: FLOAT, + interpolationMode: D2D1_INTERPOLATION_MODE, + options: D2D1_TRANSFORMED_IMAGE_SOURCE_OPTIONS, +}} +STRUCT!{struct D2D1_INK_POINT { + x: FLOAT, + y: FLOAT, + radius: FLOAT, +}} +STRUCT!{struct D2D1_INK_BEZIER_SEGMENT { + point1: D2D1_INK_POINT, + point2: D2D1_INK_POINT, + point3: D2D1_INK_POINT, +}} +STRUCT!{struct D2D1_INK_STYLE_PROPERTIES { + nibShape: D2D1_INK_NIB_SHAPE, + nibTransform: D2D1_MATRIX_3X2_F, +}} +ENUM!{enum D2D1_PATCH_EDGE_MODE { + D2D1_PATCH_EDGE_MODE_ALIASED = 0, + D2D1_PATCH_EDGE_MODE_ANTIALIASED = 1, + D2D1_PATCH_EDGE_MODE_ALIASED_INFLATED = 2, +}} +STRUCT!{struct D2D1_GRADIENT_MESH_PATCH { + point00: D2D1_POINT_2F, + point01: D2D1_POINT_2F, + point02: D2D1_POINT_2F, + point03: D2D1_POINT_2F, + point10: D2D1_POINT_2F, + point11: D2D1_POINT_2F, + point12: D2D1_POINT_2F, + point13: D2D1_POINT_2F, + point20: D2D1_POINT_2F, + point21: D2D1_POINT_2F, + point22: D2D1_POINT_2F, + point23: D2D1_POINT_2F, + point30: D2D1_POINT_2F, + point31: D2D1_POINT_2F, + point32: D2D1_POINT_2F, + point33: D2D1_POINT_2F, + color00: D2D1_COLOR_F, + color03: D2D1_COLOR_F, + color30: D2D1_COLOR_F, + color33: D2D1_COLOR_F, + topEdgeMode: D2D1_PATCH_EDGE_MODE, + leftEdgeMode: D2D1_PATCH_EDGE_MODE, + bottomEdgeMode: D2D1_PATCH_EDGE_MODE, + rightEdgeMode: D2D1_PATCH_EDGE_MODE, +}} +ENUM!{enum D2D1_SPRITE_OPTIONS { + D2D1_SPRITE_OPTIONS_NONE = 0, + D2D1_SPRITE_OPTIONS_CLAMP_TO_SOURCE_RECTANGLE = 1, +}} +ENUM!{enum D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION { + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT = 0, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DISABLE = 1, +}} +ENUM!{enum D2D1_GAMMA1 { + D2D1_GAMMA1_G22 = D2D1_GAMMA_2_2, + D2D1_GAMMA1_G10 = D2D1_GAMMA_1_0, + D2D1_GAMMA1_G2084 = 2, +}} +STRUCT!{struct D2D1_SIMPLE_COLOR_PROFILE { + redPrimary: D2D1_POINT_2F, + greenPrimary: D2D1_POINT_2F, + bluePrimary: D2D1_POINT_2F, + whitePointXZ: D2D1_POINT_2F, + gamma: D2D1_GAMMA1, +}} +ENUM!{enum D2D1_COLOR_CONTEXT_TYPE { + D2D1_COLOR_CONTEXT_TYPE_ICC = 0, + D2D1_COLOR_CONTEXT_TYPE_SIMPLE = 1, + D2D1_COLOR_CONTEXT_TYPE_DXGI = 2, +}} +DEFINE_GUID!{IID_ID2D1InkStyle, + 0xbae8b344, 0x23fc, 0x4071, 0x8c, 0xb5, 0xd0, 0x5d, 0x6f, 0x07, 0x38, 0x48} +DEFINE_GUID!{IID_ID2D1Ink, + 0xb499923b, 0x7029, 0x478f, 0xa8, 0xb3, 0x43, 0x2c, 0x7c, 0x5f, 0x53, 0x12} +DEFINE_GUID!{IID_ID2D1GradientMesh, + 0xf292e401, 0xc050, 0x4cde, 0x83, 0xd7, 0x04, 0x96, 0x2d, 0x3b, 0x23, 0xc2} +DEFINE_GUID!{IID_ID2D1ImageSource, + 0xc9b664e5, 0x74a1, 0x4378, 0x9a, 0xc2, 0xee, 0xfc, 0x37, 0xa3, 0xf4, 0xd8} +DEFINE_GUID!{IID_ID2D1ImageSourceFromWic, + 0x77395441, 0x1c8f, 0x4555, 0x86, 0x83, 0xf5, 0x0d, 0xab, 0x0f, 0xe7, 0x92} +DEFINE_GUID!{IID_ID2D1TransformedImageSource, + 0x7f1f79e5, 0x2796, 0x416c, 0x8f, 0x55, 0x70, 0x0f, 0x91, 0x14, 0x45, 0xe5} +DEFINE_GUID!{IID_ID2D1LookupTable3D, + 0x53dd9855, 0xa3b0, 0x4d5b, 0x82, 0xe1, 0x26, 0xe2, 0x5c, 0x5e, 0x57, 0x97} +DEFINE_GUID!{IID_ID2D1DeviceContext2, + 0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7} +DEFINE_GUID!{IID_ID2D1Device2, + 0xa44472e1, 0x8dfb, 0x4e60, 0x84, 0x92, 0x6e, 0x28, 0x61, 0xc9, 0xca, 0x8b} +DEFINE_GUID!{IID_ID2D1Factory3, + 0x0869759f, 0x4f00, 0x413f, 0xb0, 0x3e, 0x2b, 0xda, 0x45, 0x40, 0x4d, 0x0f} +DEFINE_GUID!{IID_ID2D1CommandSink2, + 0x3bab440e, 0x417e, 0x47df, 0xa2, 0xe2, 0xbc, 0x0b, 0xe6, 0xa0, 0x09, 0x16} +DEFINE_GUID!{IID_ID2D1GdiMetafile1, + 0x2e69f9e8, 0xdd3f, 0x4bf9, 0x95, 0xba, 0xc0, 0x4f, 0x49, 0xd7, 0x88, 0xdf} +DEFINE_GUID!{IID_ID2D1GdiMetafileSink1, + 0xfd0ecb6b, 0x91e6, 0x411e, 0x86, 0x55, 0x39, 0x5e, 0x76, 0x0f, 0x91, 0xb4} +DEFINE_GUID!{IID_ID2D1SpriteBatch, + 0x4dc583bf, 0x3a10, 0x438a, 0x87, 0x22, 0xe9, 0x76, 0x52, 0x24, 0xf1, 0xf1} +DEFINE_GUID!{IID_ID2D1DeviceContext3, + 0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00} +DEFINE_GUID!{IID_ID2D1Device3, + 0x852f2087, 0x802c, 0x4037, 0xab, 0x60, 0xff, 0x2e, 0x7e, 0xe6, 0xfc, 0x01} +DEFINE_GUID!{IID_ID2D1Factory4, + 0xbd4ec2d2, 0x0662, 0x4bee, 0xba, 0x8e, 0x6f, 0x29, 0xf0, 0x32, 0xe0, 0x96} +DEFINE_GUID!{IID_ID2D1CommandSink3, + 0x18079135, 0x4cf3, 0x4868, 0xbc, 0x8e, 0x06, 0x06, 0x7e, 0x6d, 0x24, 0x2d} +DEFINE_GUID!{IID_ID2D1SvgGlyphStyle, + 0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38} +DEFINE_GUID!{IID_ID2D1DeviceContext4, + 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb} +DEFINE_GUID!{IID_ID2D1Device4, + 0xd7bdb159, 0x5683, 0x4a46, 0xbc, 0x9c, 0x72, 0xdc, 0x72, 0x0b, 0x85, 0x8b} +DEFINE_GUID!{IID_ID2D1Factory5, + 0xc4349994, 0x838e, 0x4b0f, 0x8c, 0xab, 0x44, 0x99, 0x7d, 0x9e, 0xea, 0xcc} +DEFINE_GUID!{IID_ID2D1CommandSink4, + 0xc78a6519, 0x40d6, 0x4218, 0xb2, 0xde, 0xbe, 0xee, 0xb7, 0x44, 0xbb, 0x3e} +DEFINE_GUID!{IID_ID2D1ColorContext1, + 0x1ab42875, 0xc57f, 0x4be9, 0xbd, 0x85, 0x9c, 0xd7, 0x8d, 0x6f, 0x55, 0xee} +DEFINE_GUID!{IID_ID2D1DeviceContext5, + 0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7} +DEFINE_GUID!{IID_ID2D1Device5, + 0xd55ba0a4, 0x6405, 0x4694, 0xae, 0xf5, 0x08, 0xee, 0x1a, 0x43, 0x58, 0xb4} +DEFINE_GUID!{IID_ID2D1Factory6, + 0xf9976f46, 0xf642, 0x44c1, 0x97, 0xca, 0xda, 0x32, 0xea, 0x2a, 0x26, 0x35} +DEFINE_GUID!{IID_ID2D1CommandSink5, + 0x7047dd26, 0xb1e7, 0x44a7, 0x95, 0x9a, 0x83, 0x49, 0xe2, 0x14, 0x4f, 0xa8} +DEFINE_GUID!{IID_ID2D1DeviceContext6, + 0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06} +DEFINE_GUID!{IID_ID2D1Device6, + 0x7bfef914, 0x2d75, 0x4bad, 0xbe, 0x87, 0xe1, 0x8d, 0xdb, 0x07, 0x7b, 0x6d} +DEFINE_GUID!{IID_ID2D1Factory7, + 0xbdc2bdd3, 0xb96c, 0x4de6, 0xbd, 0xf7, 0x99, 0xd4, 0x74, 0x54, 0x54, 0xde} +RIDL!{#[uuid(0xbae8b344, 0x23fc, 0x4071, 0x8c, 0xb5, 0xd0, 0x5d, 0x6f, 0x07, 0x38, 0x48)] +interface ID2D1InkStyle(ID2D1InkStyleVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn SetNibTransform( + transform: *const D2D1_MATRIX_3X2_F, + ) -> (), + fn GetNibTransform( + transform: *mut D2D1_MATRIX_3X2_F, + ) -> (), + fn SetNibShape( + nibShape: D2D1_INK_NIB_SHAPE, + ) -> (), + fn GetNibShape() -> D2D1_INK_NIB_SHAPE, +}} +RIDL!{#[uuid(0xb499923b, 0x7029, 0x478f, 0xa8, 0xb3, 0x43, 0x2c, 0x7c, 0x5f, 0x53, 0x12)] +interface ID2D1Ink(ID2D1InkVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn SetStartPoint( + startPoint: *const D2D1_INK_POINT, + ) -> (), + fn GetStartPoint() -> D2D1_INK_POINT, + fn AddSegments( + segments: *const D2D1_INK_BEZIER_SEGMENT, + segmentsCount: UINT32, + ) -> HRESULT, + fn RemoveSegmentsAtEnd( + segmentsCount: UINT32, + ) -> HRESULT, + fn SetSegments( + startSegment: UINT32, + segments: *const D2D1_INK_BEZIER_SEGMENT, + segmentsCount: UINT32, + ) -> HRESULT, + fn SetSegmentAtEnd( + segment: *const D2D1_INK_BEZIER_SEGMENT, + ) -> HRESULT, + fn GetSegmentCount() -> UINT32, + fn GetSegments( + startSegment: UINT32, + segments: *mut D2D1_INK_BEZIER_SEGMENT, + segmentsCount: UINT32, + ) -> HRESULT, + fn StreamAsGeometry( + inkStyle: *mut ID2D1InkStyle, + worldTransform: *const D2D1_MATRIX_3X2_F, + flatteningTolerance: FLOAT, + geometrySink: *mut ID2D1SimplifiedGeometrySink, + ) -> HRESULT, + fn GetBounds( + inkStyle: *mut ID2D1InkStyle, + worldTransform: *const D2D1_MATRIX_3X2_F, + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf292e401, 0xc050, 0x4cde, 0x83, 0xd7, 0x04, 0x96, 0x2d, 0x3b, 0x23, 0xc2)] +interface ID2D1GradientMesh(ID2D1GradientMeshVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetPatchCount() -> UINT32, + fn GetPatches( + startIndex: UINT32, + patches: *mut D2D1_GRADIENT_MESH_PATCH, + patchesCount: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc9b664e5, 0x74a1, 0x4378, 0x9a, 0xc2, 0xee, 0xfc, 0x37, 0xa3, 0xf4, 0xd8)] +interface ID2D1ImageSource(ID2D1ImageSourceVtbl): ID2D1Image(ID2D1ImageVtbl) { + fn OfferResources() -> HRESULT, + fn TryReclaimResources( + resourcesDiscarded: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x77395441, 0x1c8f, 0x4555, 0x86, 0x83, 0xf5, 0x0d, 0xab, 0x0f, 0xe7, 0x92)] +interface ID2D1ImageSourceFromWic(ID2D1ImageSourceFromWicVtbl): + ID2D1ImageSource(ID2D1ImageSourceVtbl) { + fn EnsureCached( + rectangleToFill: *const D2D1_RECT_U, + ) -> HRESULT, + fn TrimCache( + rectangleToPreserve: *const D2D1_RECT_U, + ) -> HRESULT, + fn GetSource( + wicBitmapSource: *mut *mut IWICBitmapSource, + ) -> (), +}} +RIDL!{#[uuid(0x7f1f79e5, 0x2796, 0x416c, 0x8f, 0x55, 0x70, 0x0f, 0x91, 0x14, 0x45, 0xe5)] +interface ID2D1TransformedImageSource(ID2D1TransformedImageSourceVtbl): + ID2D1Image(ID2D1ImageVtbl) { + fn GetSource( + imageSource: *mut *mut ID2D1ImageSource, + ) -> (), + fn GetProperties( + properties: *mut D2D1_TRANSFORMED_IMAGE_SOURCE_PROPERTIES, + ) -> (), +}} +RIDL!{#[uuid(0x53dd9855, 0xa3b0, 0x4d5b, 0x82, 0xe1, 0x26, 0xe2, 0x5c, 0x5e, 0x57, 0x97)] +interface ID2D1LookupTable3D(ID2D1LookupTable3DVtbl): ID2D1Resource(ID2D1ResourceVtbl) {}} +RIDL!{#[uuid(0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7)] +interface ID2D1DeviceContext2(ID2D1DeviceContext2Vtbl): + ID2D1DeviceContext1(ID2D1DeviceContext1Vtbl) { + fn CreateInk( + startPoint: *const D2D1_INK_POINT, + ink: *mut *mut ID2D1Ink, + ) -> HRESULT, + fn CreateInkStyle( + inkStyleProperties: *const D2D1_INK_STYLE_PROPERTIES, + inkStyle: *mut *mut ID2D1InkStyle, + ) -> HRESULT, + fn CreateGradientMesh( + patches: *const D2D1_GRADIENT_MESH_PATCH, + patchesCount: UINT32, + gradientMesh: *mut *mut ID2D1GradientMesh, + ) -> HRESULT, + fn CreateImageSourceFromWic( + wicBitmapSource: *mut IWICBitmapSource, + loadingOptions: D2D1_IMAGE_SOURCE_LOADING_OPTIONS, + alphaMode: D2D1_ALPHA_MODE, + imageSource: *mut *mut ID2D1ImageSourceFromWic, + ) -> HRESULT, + fn CreateLookupTable3D( + precision: D2D1_BUFFER_PRECISION, + extents: *const UINT32, + data: *const BYTE, + dataCount: UINT32, + strides: *const UINT32, + lookupTable: *mut *mut ID2D1LookupTable3D, + ) -> HRESULT, + fn CreateImageSourceFromDxgi( + surfaces: *const *mut IDXGISurface, + surfaceCount: UINT32, + colorSpace: DXGI_COLOR_SPACE_TYPE, + options: D2D1_IMAGE_SOURCE_FROM_DXGI_OPTIONS, + imageSource: *mut *mut ID2D1ImageSource, + ) -> HRESULT, + fn GetGradientMeshWorldBounds( + gradientMesh: *mut ID2D1GradientMesh, + pBounds: *mut D2D1_RECT_F, + ) -> HRESULT, + fn DrawInk( + ink: *mut ID2D1Ink, + brush: *mut ID2D1Brush, + inkStyle: *mut ID2D1InkStyle, + ) -> (), + fn DrawGradientMesh( + gradientMesh: *mut ID2D1GradientMesh, + ) -> (), + fn DrawGdiMetafile( + gdiMetafile: *mut ID2D1GdiMetafile, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangle: *const D2D1_RECT_F, + ) -> (), + fn CreateTransformedImageSource( + imageSource: *mut ID2D1ImageSource, + properties: *const D2D1_TRANSFORMED_IMAGE_SOURCE_PROPERTIES, + transformedImageSource: *mut *mut ID2D1TransformedImageSource, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa44472e1, 0x8dfb, 0x4e60, 0x84, 0x92, 0x6e, 0x28, 0x61, 0xc9, 0xca, 0x8b)] +interface ID2D1Device2(ID2D1Device2Vtbl): ID2D1Device1(ID2D1Device1Vtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext2: *mut *mut ID2D1DeviceContext2, + ) -> HRESULT, + fn FlushDeviceContexts( + bitmap: *mut ID2D1Bitmap, + ) -> (), + fn GetDxgiDevice( + dxgiDevice: *mut *mut IDXGIDevice, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0869759f, 0x4f00, 0x413f, 0xb0, 0x3e, 0x2b, 0xda, 0x45, 0x40, 0x4d, 0x0f)] +interface ID2D1Factory3(ID2D1Factory3Vtbl): ID2D1Factory2(ID2D1Factory2Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice2: *mut *mut ID2D1Device2, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3bab440e, 0x417e, 0x47df, 0xa2, 0xe2, 0xbc, 0x0b, 0xe6, 0xa0, 0x09, 0x16)] +interface ID2D1CommandSink2(ID2D1CommandSink2Vtbl): ID2D1CommandSink1(ID2D1CommandSink1Vtbl) { + fn DrawInk( + ink: *mut ID2D1Ink, + brush: *mut ID2D1Brush, + inkStyle: *mut ID2D1InkStyle, + ) -> (), + fn DrawGradientMesh( + gradientMesh: *mut ID2D1GradientMesh, + ) -> (), + fn DrawGdiMetafile( + gdiMetafile: *mut ID2D1GdiMetafile, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangle: *const D2D1_RECT_F, + ) -> (), +}} +RIDL!{#[uuid(0x2e69f9e8, 0xdd3f, 0x4bf9, 0x95, 0xba, 0xc0, 0x4f, 0x49, 0xd7, 0x88, 0xdf)] +interface ID2D1GdiMetafile1(ID2D1GdiMetafile1Vtbl): ID2D1GdiMetafile(ID2D1GdiMetafileVtbl) { + fn GetDpi( + dpiX: *mut FLOAT, + dpiY: *mut FLOAT, + ) -> HRESULT, + fn GetSourceBounds( + bounds: *mut D2D1_RECT_F, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfd0ecb6b, 0x91e6, 0x411e, 0x86, 0x55, 0x39, 0x5e, 0x76, 0x0f, 0x91, 0xb4)] +interface ID2D1GdiMetafileSink1(ID2D1GdiMetafileSink1Vtbl): + ID2D1GdiMetafileSink(ID2D1GdiMetafileSinkVtbl) { + fn ProcessRecord( + recordType: DWORD, + recordData: *const c_void, + recordDataSize: DWORD, + flags: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4dc583bf, 0x3a10, 0x438a, 0x87, 0x22, 0xe9, 0x76, 0x52, 0x24, 0xf1, 0xf1)] +interface ID2D1SpriteBatch(ID2D1SpriteBatchVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn AddSprites( + spriteCount: UINT32, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangles: *const D2D1_RECT_U, + colors: *const D2D1_COLOR_F, + transforms: *const D2D1_MATRIX_3X2_F, + destinationRectanglesStride: UINT32, + sourceRectanglesStride: UINT32, + colorsStride: UINT32, + transformsStride: D2D1_MATRIX_3X2_F, + ) -> HRESULT, + fn SetSprites( + startIndex: UINT32, + spriteCount: UINT32, + destinationRectangle: *const D2D1_RECT_F, + sourceRectangles: *const D2D1_RECT_U, + colors: *const D2D1_COLOR_F, + transforms: *const D2D1_MATRIX_3X2_F, + destinationRectanglesStride: UINT32, + sourceRectanglesStride: UINT32, + colorsStride: UINT32, + transformsStride: D2D1_MATRIX_3X2_F, + ) -> HRESULT, + fn GetSprites( + startIndex: UINT32, + spriteCount: UINT32, + destinationRectangle: *mut D2D1_RECT_F, + sourceRectangles: *mut D2D1_RECT_U, + colors: *mut D2D1_COLOR_F, + transforms: *mut D2D1_MATRIX_3X2_F, + ) -> HRESULT, + fn GetSpriteCount() -> UINT32, + fn Clear() -> (), +}} +RIDL!{#[uuid(0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00)] +interface ID2D1DeviceContext3(ID2D1DeviceContext3Vtbl): + ID2D1DeviceContext2(ID2D1DeviceContext2Vtbl) { + fn CreateSpriteBatch( + spriteBatch: *mut *mut ID2D1SpriteBatch, + ) -> HRESULT, + fn DrawSpriteBatch( + spriteBatch: *mut ID2D1SpriteBatch, + startIndex: UINT32, + spriteCount: UINT32, + bitmap: *mut ID2D1Bitmap, + interpolationMode: D2D1_BITMAP_INTERPOLATION_MODE, + spriteOptions: D2D1_SPRITE_OPTIONS, + ) -> (), +}} +RIDL!{#[uuid(0x852f2087, 0x802c, 0x4037, 0xab, 0x60, 0xff, 0x2e, 0x7e, 0xe6, 0xfc, 0x01)] +interface ID2D1Device3(ID2D1Device3Vtbl): ID2D1Device2(ID2D1Device2Vtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext3: *mut *mut ID2D1DeviceContext3, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbd4ec2d2, 0x0662, 0x4bee, 0xba, 0x8e, 0x6f, 0x29, 0xf0, 0x32, 0xe0, 0x96)] +interface ID2D1Factory4(ID2D1Factory4Vtbl): ID2D1Factory3(ID2D1Factory3Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice3: *mut *mut ID2D1Device3, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x18079135, 0x4cf3, 0x4868, 0xbc, 0x8e, 0x06, 0x06, 0x7e, 0x6d, 0x24, 0x2d)] +interface ID2D1CommandSink3(ID2D1CommandSink3Vtbl): ID2D1CommandSink2(ID2D1CommandSink2Vtbl) { + fn DrawSpriteBatch( + spriteBatch: *mut ID2D1SpriteBatch, + startIndex: UINT32, + spriteCount: UINT32, + bitmap: *mut ID2D1Bitmap, + interpolationMode: D2D1_BITMAP_INTERPOLATION_MODE, + spriteOptions: D2D1_SPRITE_OPTIONS, + ) -> (), +}} +RIDL!{#[uuid(0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38)] +interface ID2D1SvgGlyphStyle(ID2D1SvgGlyphStyleVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn SetFill( + brush: *mut ID2D1Brush, + ) -> HRESULT, + fn GetFill( + brush: *mut *mut ID2D1Brush, + ) -> (), + fn SetStroke( + brush: *mut ID2D1Brush, + strokeWidth: FLOAT, + dashes: *const FLOAT, + dashesCount: UINT32, + dashOffset: FLOAT, + ) -> HRESULT, + fn GetStrokeDashesCount() -> UINT32, + fn GetStroke( + brush: *mut *mut ID2D1Brush, + strokeWidth: *mut FLOAT, + dashes: *mut FLOAT, + dashesCount: UINT32, + dashOffset: *mut FLOAT, + ) -> (), +}} +RIDL!{#[uuid(0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb)] +interface ID2D1DeviceContext4(ID2D1DeviceContext4Vtbl): + ID2D1DeviceContext3(ID2D1DeviceContext3Vtbl) { + fn CreateSvgGlyphStyle( + svgGlyphStyle: *mut *mut ID2D1SvgGlyphStyle, + ) -> HRESULT, + fn DrawText( + string: *const WCHAR, + stringLength: UINT32, + textFormat: *mut IDWriteTextFormat, + layoutRect: *const D2D1_RECT_F, + defaultFillBrush: *mut ID2D1Brush, + svgGlyphStyle: *mut ID2D1SvgGlyphStyle, + colorPaletteIndex: UINT32, + options: D2D1_DRAW_TEXT_OPTIONS, + measuringMode: DWRITE_MEASURING_MODE, + ) -> (), + fn DrawTextLayout( + origin: D2D1_POINT_2F, + textLayout: *mut IDWriteTextLayout, + defaultFillBrush: *mut ID2D1Brush, + svgGlyphStyle: *mut ID2D1SvgGlyphStyle, + colorPaletteIndex: UINT32, + options: D2D1_DRAW_TEXT_OPTIONS, + ) -> (), + fn DrawColorBitmapGlyphRun( + glyphImageFormat: DWRITE_GLYPH_IMAGE_FORMATS, + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + measuringMode: DWRITE_MEASURING_MODE, + bitmapSnapOption: D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION, + ) -> (), + fn DrawSvgGlyphRun( + baselineOrigin: D2D1_POINT_2F, + glyphRun: *const DWRITE_GLYPH_RUN, + defaultFillBrush: *mut ID2D1Brush, + svgGlyphStyle: *mut ID2D1SvgGlyphStyle, + colorPaletteIndex: UINT32, + measuringMode: DWRITE_MEASURING_MODE, + ) -> (), + fn GetColorBitmapGlyphImage( + glyphImageFormat: DWRITE_GLYPH_IMAGE_FORMATS, + glyphOrigin: D2D1_POINT_2F, + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + glyphIndex: UINT16, + isSideways: BOOL, + worldTransform: *const D2D1_MATRIX_3X2_F, + dpiX: FLOAT, + dpiY: FLOAT, + glyphTransform: *mut D2D1_MATRIX_3X2_F, + glyphImage: *mut *mut ID2D1Image, + ) -> HRESULT, + fn GetSvgGlyphImage( + glyphImageFormat: DWRITE_GLYPH_IMAGE_FORMATS, + glyphOrigin: D2D1_POINT_2F, + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + glyphIndex: UINT16, + isSideways: BOOL, + worldTransform: *const D2D1_MATRIX_3X2_F, + defaultFillBrush: *mut ID2D1Brush, + svgGlyphStyle: *mut ID2D1SvgGlyphStyle, + colorPaletteIndex: UINT32, + glyphTransform: *mut D2D1_MATRIX_3X2_F, + glyphImage: *mut *mut ID2D1CommandList, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd7bdb159, 0x5683, 0x4a46, 0xbc, 0x9c, 0x72, 0xdc, 0x72, 0x0b, 0x85, 0x8b)] +interface ID2D1Device4(ID2D1Device4Vtbl): ID2D1Device3(ID2D1Device3Vtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext4: *mut *mut ID2D1DeviceContext4, + ) -> HRESULT, + fn SetMaximumColorGlyphCacheMemory( + maximumInBytes: UINT64, + ) -> (), + fn GetMaximumColorGlyphCacheMemory() -> UINT64, +}} +RIDL!{#[uuid(0xc4349994, 0x838e, 0x4b0f, 0x8c, 0xab, 0x44, 0x99, 0x7d, 0x9e, 0xea, 0xcc)] +interface ID2D1Factory5(ID2D1Factory5Vtbl): ID2D1Factory4(ID2D1Factory4Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice4: *mut *mut ID2D1Device4, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc78a6519, 0x40d6, 0x4218, 0xb2, 0xde, 0xbe, 0xee, 0xb7, 0x44, 0xbb, 0x3e)] +interface ID2D1CommandSink4(ID2D1CommandSink4Vtbl): ID2D1CommandSink3(ID2D1CommandSink3Vtbl) { + fn SetPrimitiveBlend2( + primitiveBlend: D2D1_PRIMITIVE_BLEND, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1ab42875, 0xc57f, 0x4be9, 0xbd, 0x85, 0x9c, 0xd7, 0x8d, 0x6f, 0x55, 0xee)] +interface ID2D1ColorContext1(ID2D1ColorContext1Vtbl): ID2D1ColorContext(ID2D1ColorContextVtbl) { + fn GetColorContextType() -> D2D1_COLOR_CONTEXT_TYPE, + fn GetDXGIColorSpace() -> DXGI_COLOR_SPACE_TYPE, + fn GetSimpleColorProfile( + simpleProfile: *mut D2D1_SIMPLE_COLOR_PROFILE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7836d248, 0x68cc, 0x4df6, 0xb9, 0xe8, 0xde, 0x99, 0x1b, 0xf6, 0x2e, 0xb7)] +interface ID2D1DeviceContext5(ID2D1DeviceContext5Vtbl): + ID2D1DeviceContext4(ID2D1DeviceContext4Vtbl) { + fn CreateSvgDocument( + inputXmlStream: *mut IStream, + viewportSize: D2D1_SIZE_F, + svgDocument: *mut *mut ID2D1SvgDocument, + ) -> HRESULT, + fn DrawSvgDocument( + svgDocument: *mut ID2D1SvgDocument, + ) -> (), + fn CreateColorContextFromDxgiColorSpace( + colorSpace: DXGI_COLOR_SPACE_TYPE, + colorContext: *mut *mut ID2D1ColorContext1, + ) -> HRESULT, + fn CreateColorContextFromSimpleColorProfile( + simpleProfile: *const D2D1_SIMPLE_COLOR_PROFILE, + colorContext: *mut *mut ID2D1ColorContext1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd55ba0a4, 0x6405, 0x4694, 0xae, 0xf5, 0x08, 0xee, 0x1a, 0x43, 0x58, 0xb4)] +interface ID2D1Device5(ID2D1Device5Vtbl): ID2D1Device4(ID2D1Device4Vtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext5: *mut *mut ID2D1DeviceContext5, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf9976f46, 0xf642, 0x44c1, 0x97, 0xca, 0xda, 0x32, 0xea, 0x2a, 0x26, 0x35)] +interface ID2D1Factory6(ID2D1Factory6Vtbl): ID2D1Factory5(ID2D1Factory5Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice5: *mut *mut ID2D1Device5, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7047dd26, 0xb1e7, 0x44a7, 0x95, 0x9a, 0x83, 0x49, 0xe2, 0x14, 0x4f, 0xa8)] +interface ID2D1CommandSink5(ID2D1CommandSink5Vtbl): ID2D1CommandSink4(ID2D1CommandSink4Vtbl) { + fn BlendImage( + image: *mut ID2D1Image, + blendMode: D2D1_BLEND_MODE, + targetOffset: *const D2D1_POINT_2F, + imageRectangle: *const D2D1_RECT_F, + interpolationMode: D2D1_INTERPOLATION_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x985f7e37, 0x4ed0, 0x4a19, 0x98, 0xa3, 0x15, 0xb0, 0xed, 0xfd, 0xe3, 0x06)] +interface ID2D1DeviceContext6(ID2D1DeviceContext6Vtbl): + ID2D1DeviceContext5(ID2D1DeviceContext5Vtbl) { + fn BlendImage( + image: *mut ID2D1Image, + blendMode: D2D1_BLEND_MODE, + targetOffset: *const D2D1_POINT_2F, + imageRectangle: *const D2D1_RECT_F, + interpolationMode: D2D1_INTERPOLATION_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7bfef914, 0x2d75, 0x4bad, 0xbe, 0x87, 0xe1, 0x8d, 0xdb, 0x07, 0x7b, 0x6d)] +interface ID2D1Device6(ID2D1Device6Vtbl): ID2D1Device5(ID2D1Device5Vtbl) { + fn CreateDeviceContext( + options: D2D1_DEVICE_CONTEXT_OPTIONS, + deviceContext6: *mut *mut ID2D1DeviceContext6, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbdc2bdd3, 0xb96c, 0x4de6, 0xbd, 0xf7, 0x99, 0xd4, 0x74, 0x54, 0x54, 0xde)] +interface ID2D1Factory7(ID2D1Factory7Vtbl): ID2D1Factory6(ID2D1Factory6Vtbl) { + fn CreateDevice( + dxgiDevice: *mut IDXGIDevice, + d2dDevice6: *mut *mut ID2D1Device6, + ) -> HRESULT, +}} +extern "system" { + pub fn D2D1GetGradientMeshInteriorPointsFromCoonsPatch( + pPoint0: *const D2D1_POINT_2F, + pPoint1: *const D2D1_POINT_2F, + pPoint2: *const D2D1_POINT_2F, + pPoint3: *const D2D1_POINT_2F, + pPoint4: *const D2D1_POINT_2F, + pPoint5: *const D2D1_POINT_2F, + pPoint6: *const D2D1_POINT_2F, + pPoint7: *const D2D1_POINT_2F, + pPoint8: *const D2D1_POINT_2F, + pPoint9: *const D2D1_POINT_2F, + pPoint10: *const D2D1_POINT_2F, + pPoint11: *const D2D1_POINT_2F, + pTensorPoint11: *mut D2D1_POINT_2F, + pTensorPoint12: *mut D2D1_POINT_2F, + pTensorPoint21: *mut D2D1_POINT_2F, + pTensorPoint22: *mut D2D1_POINT_2F, + ); +} diff --git a/winapi/src/um/d2d1effectauthor.rs b/winapi/src/um/d2d1effectauthor.rs new file mode 100644 index 000000000..c8322791c --- /dev/null +++ b/winapi/src/um/d2d1effectauthor.rs @@ -0,0 +1,516 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::basetsd::UINT32; +use shared::dxgiformat::DXGI_FORMAT; +use shared::guiddef::{GUID, REFCLSID, REFGUID}; +use shared::minwindef::{BOOL, BYTE, FLOAT}; +use shared::ntdef::{HRESULT, PCSTR, PCWSTR}; +use um::d2d1::D2D1_EXTEND_MODE; +use um::d2d1_1::{ + D2D1_BUFFER_PRECISION, D2D1_COLOR_SPACE, ID2D1Bitmap1, ID2D1ColorContext, ID2D1Effect, +}; +use um::d2dbasetypes::{D2D_POINT_2L, D2D_POINT_2U, D2D_RECT_L}; +use um::d3dcommon::D3D_FEATURE_LEVEL; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wincodec::IWICColorContext; +FN!{stdcall PD2D1_PROPERTY_SET_FUNCTION( + effect: *const IUnknown, + data: *const BYTE, + dataSize: UINT32, +) -> HRESULT} +FN!{stdcall PD2D1_PROPERTY_GET_FUNCTION( + effect: *const IUnknown, + data: *mut BYTE, + dataSize: UINT32, + actualSize: *mut UINT32, +) -> HRESULT} +ENUM!{enum D2D1_CHANGE_TYPE { + D2D1_CHANGE_TYPE_NONE = 0, + D2D1_CHANGE_TYPE_PROPERTIES = 1, + D2D1_CHANGE_TYPE_CONTEXT = 2, + D2D1_CHANGE_TYPE_GRAPH = 3, +}} +ENUM!{enum D2D1_PIXEL_OPTIONS { + D2D1_PIXEL_OPTIONS_NONE = 0, + D2D1_PIXEL_OPTIONS_TRIVIAL_SAMPLING = 1, +}} +ENUM!{enum D2D1_VERTEX_OPTIONS { + D2D1_VERTEX_OPTIONS_NONE = 0, + D2D1_VERTEX_OPTIONS_DO_NOT_CLEAR = 1, + D2D1_VERTEX_OPTIONS_USE_DEPTH_BUFFER = 2, + D2D1_VERTEX_OPTIONS_ASSUME_NO_OVERLAP = 4, +}} +ENUM!{enum D2D1_VERTEX_USAGE { + D2D1_VERTEX_USAGE_STATIC = 0, + D2D1_VERTEX_USAGE_DYNAMIC = 1, +}} +ENUM!{enum D2D1_BLEND_OPERATION { + D2D1_BLEND_OPERATION_ADD = 1, + D2D1_BLEND_OPERATION_SUBTRACT = 2, + D2D1_BLEND_OPERATION_REV_SUBTRACT = 3, + D2D1_BLEND_OPERATION_MIN = 4, + D2D1_BLEND_OPERATION_MAX = 5, +}} +ENUM!{enum D2D1_BLEND { + D2D1_BLEND_ZERO = 1, + D2D1_BLEND_ONE = 2, + D2D1_BLEND_SRC_COLOR = 3, + D2D1_BLEND_INV_SRC_COLOR = 4, + D2D1_BLEND_SRC_ALPHA = 5, + D2D1_BLEND_INV_SRC_ALPHA = 6, + D2D1_BLEND_DEST_ALPHA = 7, + D2D1_BLEND_INV_DEST_ALPHA = 8, + D2D1_BLEND_DEST_COLOR = 9, + D2D1_BLEND_INV_DEST_COLOR = 10, + D2D1_BLEND_SRC_ALPHA_SAT = 11, + D2D1_BLEND_BLEND_FACTOR = 14, + D2D1_BLEND_INV_BLEND_FACTOR = 15, +}} +ENUM!{enum D2D1_CHANNEL_DEPTH { + D2D1_CHANNEL_DEPTH_DEFAULT = 0, + D2D1_CHANNEL_DEPTH_1 = 1, + D2D1_CHANNEL_DEPTH_4 = 4, +}} +ENUM!{enum D2D1_FILTER { + D2D1_FILTER_MIN_MAG_MIP_POINT = 0x00, + D2D1_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x01, + D2D1_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x04, + D2D1_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x05, + D2D1_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10, + D2D1_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11, + D2D1_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14, + D2D1_FILTER_MIN_MAG_MIP_LINEAR = 0x15, + D2D1_FILTER_ANISOTROPIC = 0x55, +}} +ENUM!{enum D2D1_FEATURE { + D2D1_FEATURE_DOUBLES = 0, + D2D1_FEATURE_D3D10_X_HARDWARE_OPTIONS = 1, +}} +STRUCT!{struct D2D1_PROPERTY_BINDING { + propertyName: PCWSTR, + setFunction: PD2D1_PROPERTY_SET_FUNCTION, + getFunction: PD2D1_PROPERTY_GET_FUNCTION, +}} +STRUCT!{struct D2D1_RESOURCE_TEXTURE_PROPERTIES { + extents: *const UINT32, + dimensions: UINT32, + bufferPrecision: D2D1_BUFFER_PRECISION, + channelDepth: D2D1_CHANNEL_DEPTH, + filter: D2D1_FILTER, + extendModes: *const D2D1_EXTEND_MODE, +}} +STRUCT!{struct D2D1_INPUT_ELEMENT_DESC { + semanticName: PCSTR, + semanticIndex: UINT32, + format: DXGI_FORMAT, + inputSlot: UINT32, + alignedByteOffset: UINT32, +}} +pub const D2D1_APPEND_ALIGNED_ELEMENT: UINT32 = 0xffffffff; +STRUCT!{struct D2D1_VERTEX_BUFFER_PROPERTIES { + inputCount: UINT32, + usage: D2D1_VERTEX_USAGE, + data: *const BYTE, + byteWidth: UINT32, +}} +STRUCT!{struct D2D1_CUSTOM_VERTEX_BUFFER_PROPERTIES { + shaderBufferWithInputSignature: *const BYTE, + shaderBufferSize: UINT32, + inputElements: *const D2D1_INPUT_ELEMENT_DESC, + elementCount: UINT32, + stride: UINT32, +}} +STRUCT!{struct D2D1_VERTEX_RANGE { + startVertex: UINT32, + vertexCount: UINT32, +}} +STRUCT!{struct D2D1_BLEND_DESCRIPTION { + sourceBlend: D2D1_BLEND, + destinationBlend: D2D1_BLEND, + blendOperation: D2D1_BLEND_OPERATION, + sourceBlendAlpha: D2D1_BLEND, + destinationBlendAlpha: D2D1_BLEND, + blendOperationAlpha: D2D1_BLEND_OPERATION, + blendFactor: [FLOAT; 4], +}} +STRUCT!{struct D2D1_INPUT_DESCRIPTION { + filter: D2D1_FILTER, + leveOfDetailCount: UINT32, +}} +STRUCT!{struct D2D1_FEATURE_DATA_DOUBLES { + doublePrecisionFloatShaderOps: BOOL, +}} +STRUCT!{struct D2D1_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS { + computeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x: BOOL, +}} +DEFINE_GUID!{IID_ID2D1VertexBuffer, + 0x9b8b1336, 0x00a5, 0x4668, 0x92, 0xb7, 0xce, 0xd5, 0xd8, 0xbf, 0x9b, 0x7b} +DEFINE_GUID!{IID_ID2D1ResourceTexture, + 0x688d15c3, 0x02b0, 0x438d, 0xb1, 0x3a, 0xd1, 0xb4, 0x4c, 0x32, 0xc3, 0x9a} +DEFINE_GUID!{IID_ID2D1RenderInfo, + 0x519ae1bd, 0xd19a, 0x420d, 0xb8, 0x49, 0x36, 0x4f, 0x59, 0x47, 0x76, 0xb7} +DEFINE_GUID!{IID_ID2D1DrawInfo, + 0x693ce632, 0x7f2f, 0x45de, 0x93, 0xfe, 0x18, 0xd8, 0x8b, 0x37, 0xaa, 0x21} +DEFINE_GUID!{IID_ID2D1ComputeInfo, + 0x5598b14b, 0x9fd7, 0x48b7, 0x9b, 0xdb, 0x8f, 0x09, 0x64, 0xeb, 0x38, 0xbc} +DEFINE_GUID!{IID_ID2D1TransformNode, + 0xb2efe1e7, 0x729f, 0x4102, 0x94, 0x9f, 0x50, 0x5f, 0xa2, 0x1b, 0xf6, 0x66} +DEFINE_GUID!{IID_ID2D1TransformGraph, + 0x13d29038, 0xc3e6, 0x4034, 0x90, 0x81, 0x13, 0xb5, 0x3a, 0x41, 0x79, 0x92} +DEFINE_GUID!{IID_ID2D1Transform, + 0xef1a287d, 0x342a, 0x4f76, 0x8f, 0xdb, 0xda, 0x0d, 0x6e, 0xa9, 0xf9, 0x2b} +DEFINE_GUID!{IID_ID2D1DrawTransform, + 0x36bfdcb6, 0x9739, 0x435d, 0xa3, 0x0d, 0xa6, 0x53, 0xbe, 0xff, 0x6a, 0x6f} +DEFINE_GUID!{IID_ID2D1ComputeTransform, + 0x0d85573c, 0x01e3, 0x4f7d, 0xbf, 0xd9, 0x0d, 0x60, 0x60, 0x8b, 0xf3, 0xc3} +DEFINE_GUID!{IID_ID2D1AnalysisTransform, + 0x0359dc30, 0x95e6, 0x4568, 0x90, 0x55, 0x27, 0x72, 0x0d, 0x13, 0x0e, 0x93} +DEFINE_GUID!{IID_ID2D1SourceTransform, + 0xdb1800dd, 0x0c34, 0x4cf9, 0xbe, 0x90, 0x31, 0xcc, 0x0a, 0x56, 0x53, 0xe1} +DEFINE_GUID!{IID_ID2D1ConcreteTransform, + 0x1a799d8a, 0x69f7, 0x4e4c, 0x9f, 0xed, 0x43, 0x7c, 0xcc, 0x66, 0x84, 0xcc} +DEFINE_GUID!{IID_ID2D1BlendTransform, + 0x63ac0b32, 0xba44, 0x450f, 0x88, 0x06, 0x7f, 0x4c, 0xa1, 0xff, 0x2f, 0x1b} +DEFINE_GUID!{IID_ID2D1BorderTransform, + 0x4998735c, 0x3a19, 0x473c, 0x97, 0x81, 0x65, 0x68, 0x47, 0xe3, 0xa3, 0x47} +DEFINE_GUID!{IID_ID2D1OffsetTransform, + 0x3fe6adea, 0x7643, 0x4f53, 0xbd, 0x14, 0xa0, 0xce, 0x63, 0xf2, 0x40, 0x42} +DEFINE_GUID!{IID_ID2D1BoundsAdjustmentTransform, + 0x90f732e2, 0x5092, 0x4606, 0xa8, 0x19, 0x86, 0x51, 0x97, 0x0b, 0xac, 0xcd} +DEFINE_GUID!{IID_ID2D1EffectImpl, + 0xa248fd3f, 0x3e6c, 0x4e63, 0x9f, 0x03, 0x7f, 0x68, 0xec, 0xc9, 0x1d, 0xb9} +DEFINE_GUID!{IID_ID2D1EffectContext, + 0x3d9f916b, 0x27dc, 0x4ad7, 0xb4, 0xf1, 0x64, 0x94, 0x53, 0x40, 0xf5, 0x63} +RIDL!{#[uuid(0x9b8b1336, 0x00a5, 0x4668, 0x92, 0xb7, 0xce, 0xd5, 0xd8, 0xbf, 0x9b, 0x7b)] +interface ID2D1VertexBuffer(ID2D1VertexBufferVtbl): IUnknown(IUnknownVtbl) { + fn Map( + data: *mut *mut BYTE, + ) -> HRESULT, + fn Unmap() -> HRESULT, +}} +RIDL!{#[uuid(0x688d15c3, 0x02b0, 0x438d, 0xb1, 0x3a, 0xd1, 0xb4, 0x4c, 0x32, 0xc3, 0x9a)] +interface ID2D1ResourceTexture(ID2D1ResourceTextureVtbl): IUnknown(IUnknownVtbl) { + fn Update( + minimumExtents: *const UINT32, + maximumExtents: *const UINT32, + strides: *const UINT32, + dimensions: UINT32, + data: *const BYTE, + dataCount: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x519ae1bd, 0xd19a, 0x420d, 0xb8, 0x49, 0x36, 0x4f, 0x59, 0x47, 0x76, 0xb7)] +interface ID2D1RenderInfo(ID2D1RenderInfoVtbl): IUnknown(IUnknownVtbl) { + fn SetInputDescription( + inputIndex: UINT32, + inputDescription: D2D1_INPUT_DESCRIPTION, + ) -> HRESULT, + fn SetOutputBuffer( + bufferPrecision: D2D1_BUFFER_PRECISION, + channelDepth: D2D1_CHANNEL_DEPTH, + ) -> HRESULT, + fn SetCached( + isCached: BOOL, + ) -> (), + fn SetInstructionCountHint( + instructionCount: UINT32, + ) -> (), +}} +RIDL!{#[uuid(0x693ce632, 0x7f2f, 0x45de, 0x93, 0xfe, 0x18, 0xd8, 0x8b, 0x37, 0xaa, 0x21)] +interface ID2D1DrawInfo(ID2D1DrawInfoVtbl): ID2D1RenderInfo(ID2D1RenderInfoVtbl) { + fn SetPixelShaderConstantBuffer( + buffer: *const BYTE, + bufferCount: UINT32, + ) -> HRESULT, + fn SetResourceTexture( + textureIndex: UINT32, + resourceTexture: *mut ID2D1ResourceTexture, + ) -> HRESULT, + fn SetVertexShaderConstantBuffer( + buffer: *const BYTE, + bufferCount: UINT32, + ) -> HRESULT, + fn SetPixelShader( + shaderId: REFGUID, + pixelOptions: D2D1_PIXEL_OPTIONS, + ) -> HRESULT, + fn SetVertexProcessing( + vertexBuffer: *mut ID2D1VertexBuffer, + vertexOptions: D2D1_VERTEX_OPTIONS, + blendDescription: *const D2D1_BLEND_DESCRIPTION, + vertexRange: *const D2D1_VERTEX_RANGE, + vertexShader: *const GUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5598b14b, 0x9fd7, 0x48b7, 0x9b, 0xdb, 0x8f, 0x09, 0x64, 0xeb, 0x38, 0xbc)] +interface ID2D1ComputeInfo(ID2D1ComputeInfoVtbl): ID2D1RenderInfo(ID2D1RenderInfoVtbl) { + fn SetComputeShaderConstantBuffer( + buffer: *const BYTE, + bufferCount: UINT32, + ) -> HRESULT, + fn SetComputeShader( + shaderId: REFGUID, + ) -> HRESULT, + fn SetResourceTexture( + textureIndex: UINT32, + resourceTexture: *mut ID2D1ResourceTexture, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb2efe1e7, 0x729f, 0x4102, 0x94, 0x9f, 0x50, 0x5f, 0xa2, 0x1b, 0xf6, 0x66)] +interface ID2D1TransformNode(ID2D1TransformNodeVtbl): IUnknown(IUnknownVtbl) { + fn GetInputCount() -> UINT32, +}} +RIDL!{#[uuid(0x13d29038, 0xc3e6, 0x4034, 0x90, 0x81, 0x13, 0xb5, 0x3a, 0x41, 0x79, 0x92)] +interface ID2D1TransformGraph(ID2D1TransformGraphVtbl): IUnknown(IUnknownVtbl) { + fn GetInputCount() -> UINT32, + fn SetSingleTransformNode( + node: *mut ID2D1TransformNode, + ) -> HRESULT, + fn AddNode( + node: *mut ID2D1TransformNode, + ) -> HRESULT, + fn RemoveNode( + node: *mut ID2D1TransformNode, + ) -> HRESULT, + fn SetOutputNode( + node: *mut ID2D1TransformNode, + ) -> HRESULT, + fn ConnectNode( + fromNode: *mut ID2D1TransformNode, + toNode: *mut ID2D1TransformNode, + toNodeInputIndex: UINT32, + ) -> HRESULT, + fn ConnectToEffectInput( + toEffectInputIndex: UINT32, + node: *mut ID2D1TransformNode, + toNodeInputIndex: UINT32, + ) -> HRESULT, + fn Clear() -> (), + fn SetPassthroughGraph( + effectInputIndex: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xef1a287d, 0x342a, 0x4f76, 0x8f, 0xdb, 0xda, 0x0d, 0x6e, 0xa9, 0xf9, 0x2b)] +interface ID2D1Transform(ID2D1TransformVtbl): ID2D1TransformNode(ID2D1TransformNodeVtbl) { + fn MapOutputRectToInputRects( + outputRect: *const D2D_RECT_L, + inputRects: *mut D2D_RECT_L, + inputRectsCount: UINT32, + ) -> HRESULT, + fn MapInputRectsToOutputRect( + inputRects: *const D2D_RECT_L, + inputOpaqueSubRects: *const D2D_RECT_L, + inputRectCount: UINT32, + outputRect: *mut D2D_RECT_L, + outputOpaqueSubRect: *mut D2D_RECT_L, + ) -> HRESULT, + fn MapInvalidRect( + inputIndex: UINT32, + invalidInputRect: D2D_RECT_L, + invalidOutputRect: *mut D2D_RECT_L, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x36bfdcb6, 0x9739, 0x435d, 0xa3, 0x0d, 0xa6, 0x53, 0xbe, 0xff, 0x6a, 0x6f)] +interface ID2D1DrawTransform(ID2D1DrawTransformVtbl): ID2D1Transform(ID2D1TransformVtbl) { + fn SetDrawInfo( + drawInfo: *mut ID2D1DrawInfo, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0d85573c, 0x01e3, 0x4f7d, 0xbf, 0xd9, 0x0d, 0x60, 0x60, 0x8b, 0xf3, 0xc3)] +interface ID2D1ComputeTransform(ID2D1ComputeTransformVtbl): ID2D1Transform(ID2D1TransformVtbl) { + fn SetComputeInfo( + computeInfo: *mut ID2D1ComputeInfo, + ) -> HRESULT, + fn CalculateThreadgroups( + outputRect: *const D2D_RECT_L, + dimensionX: *mut UINT32, + dimensionY: *mut UINT32, + dimensionZ: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0359dc30, 0x95e6, 0x4568, 0x90, 0x55, 0x27, 0x72, 0x0d, 0x13, 0x0e, 0x93)] +interface ID2D1AnalysisTransform(ID2D1AnalysisTransformVtbl): IUnknown(IUnknownVtbl) { + fn ProcessAnalysisResults( + analysisData: *const BYTE, + analysisDataCount: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb1800dd, 0x0c34, 0x4cf9, 0xbe, 0x90, 0x31, 0xcc, 0x0a, 0x56, 0x53, 0xe1)] +interface ID2D1SourceTransform(ID2D1SourceTransformVtbl): ID2D1Transform(ID2D1TransformVtbl) { + fn SetRenderInfo( + renderInfo: *mut ID2D1RenderInfo, + ) -> HRESULT, + fn Draw( + target: *mut ID2D1Bitmap1, + drawRect: *mut D2D_RECT_L, + targetOrigin: D2D_POINT_2U, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1a799d8a, 0x69f7, 0x4e4c, 0x9f, 0xed, 0x43, 0x7c, 0xcc, 0x66, 0x84, 0xcc)] +interface ID2D1ConcreteTransform(ID2D1ConcreteTransformVtbl): + ID2D1TransformNode(ID2D1TransformNodeVtbl) { + fn SetOutputBuffer( + bufferPrecision: D2D1_BUFFER_PRECISION, + channelDepth: D2D1_CHANNEL_DEPTH, + ) -> HRESULT, + fn SetCached( + isCached: BOOL, + ) -> (), +}} +RIDL!{#[uuid(0x63ac0b32, 0xba44, 0x450f, 0x88, 0x06, 0x7f, 0x4c, 0xa1, 0xff, 0x2f, 0x1b)] +interface ID2D1BlendTransform(ID2D1BlendTransformVtbl): + ID2D1ConcreteTransform(ID2D1ConcreteTransformVtbl) { + fn SetDescription( + description: *const D2D1_BLEND_DESCRIPTION, + ) -> (), + fn GetDescription( + description: *mut D2D1_BLEND_DESCRIPTION, + ) -> (), +}} +RIDL!{#[uuid(0x4998735c, 0x3a19, 0x473c, 0x97, 0x81, 0x65, 0x68, 0x47, 0xe3, 0xa3, 0x47)] +interface ID2D1BorderTransform(ID2D1BorderTransformVtbl): + ID2D1ConcreteTransform(ID2D1ConcreteTransformVtbl) { + fn SetExtendModeX( + extendMode: D2D1_EXTEND_MODE, + ) -> (), + fn SetExtendModeY( + extendMode: D2D1_EXTEND_MODE, + ) -> (), + fn GetExtendModeX() -> D2D1_EXTEND_MODE, + fn GetExtendModeY() -> D2D1_EXTEND_MODE, +}} +RIDL!{#[uuid(0x3fe6adea, 0x7643, 0x4f53, 0xbd, 0x14, 0xa0, 0xce, 0x63, 0xf2, 0x40, 0x42)] +interface ID2D1OffsetTransform(ID2D1OffsetTransformVtbl): + ID2D1TransformNode(ID2D1TransformNodeVtbl) { + fn SetOffset( + offset: D2D_POINT_2L, + ) -> (), + fn GetOffset() -> D2D_POINT_2L, +}} +RIDL!{#[uuid(0x90f732e2, 0x5092, 0x4606, 0xa8, 0x19, 0x86, 0x51, 0x97, 0x0b, 0xac, 0xcd)] +interface ID2D1BoundsAdjustmentTransform(ID2D1BoundsAdjustmentTransformVtbl): + ID2D1TransformNode(ID2D1TransformNodeVtbl) { + fn SetOutputBounds( + outputBounds: *const D2D_RECT_L, + ) -> (), + fn GetOutputBounds( + outputBounds: *mut D2D_RECT_L, + ) -> (), +}} +RIDL!{#[uuid(0xa248fd3f, 0x3e6c, 0x4e63, 0x9f, 0x03, 0x7f, 0x68, 0xec, 0xc9, 0x1d, 0xb9)] +interface ID2D1EffectImpl(ID2D1EffectImplVtbl): IUnknown(IUnknownVtbl) { + fn Initialize( + effectContext: *mut ID2D1EffectContext, + transformGraph: *mut ID2D1TransformGraph, + ) -> HRESULT, + fn PrepareForRender( + changeType: D2D1_CHANGE_TYPE, + ) -> HRESULT, + fn SetGraph( + transformGraph: *mut ID2D1TransformGraph, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3d9f916b, 0x27dc, 0x4ad7, 0xb4, 0xf1, 0x64, 0x94, 0x53, 0x40, 0xf5, 0x63)] +interface ID2D1EffectContext(ID2D1EffectContextVtbl): IUnknown(IUnknownVtbl) { + fn GetDpi( + dpiX: *mut FLOAT, + dpiY: *mut FLOAT, + ) -> (), + fn CreateEffect( + effectId: REFCLSID, + effect: *mut *mut ID2D1Effect, + ) -> HRESULT, + fn GetMaximumSupportedFeatureLevel( + featureLevels: *const D3D_FEATURE_LEVEL, + featureLevelsCount: UINT32, + maximumSupportedFeatureLevel: *mut D3D_FEATURE_LEVEL, + ) -> HRESULT, + fn CreateTransformNodeFromEffect( + effect: *mut ID2D1Effect, + transformNode: *mut *mut ID2D1TransformNode, + ) -> HRESULT, + fn CreateBlendTransform( + numInputs: UINT32, + blendDescription: D2D1_BLEND_DESCRIPTION, + transform: *mut *mut ID2D1BlendTransform, + ) -> HRESULT, + fn CreateBorderTransform( + extendModeX: D2D1_EXTEND_MODE, + extendModeY: D2D1_EXTEND_MODE, + transform: *mut *mut ID2D1BorderTransform, + ) -> HRESULT, + fn CreateOffsetTransform( + offset: D2D_POINT_2L, + transform: *mut *mut ID2D1OffsetTransform, + ) -> HRESULT, + fn CreateBoundsAdjustmentTransform( + outputRectangle: *mut D2D_RECT_L, + transform: ID2D1BoundsAdjustmentTransform, + ) -> HRESULT, + fn LoadPixelShader( + shaderId: REFGUID, + shaderBuffer: *const BYTE, + shaderBufferCount: UINT32, + ) -> HRESULT, + fn LoadVertexShader( + resourceId: REFGUID, + shaderBuffer: *const BYTE, + shaderBufferCount: UINT32, + ) -> HRESULT, + fn LoadComputeShader( + resourceId: REFGUID, + shaderBuffer: *const BYTE, + shaderBufferCount: UINT32, + ) -> HRESULT, + fn IsShaderLoaded( + shaderId: REFGUID, + ) -> BOOL, + fn CreateResourceTexture( + resourceId: *const GUID, + resourceTextureProperties: *const D2D1_RESOURCE_TEXTURE_PROPERTIES, + data: *const BYTE, + strides: *const UINT32, + dataSize: UINT32, + resourceTexture: *mut *mut ID2D1ResourceTexture, + ) -> HRESULT, + fn FindResourceTexture( + resourceId: *const GUID, + resourceTexture: *mut *mut ID2D1ResourceTexture, + ) -> HRESULT, + fn CreateVertexBuffer( + vertexBufferProperties: *const D2D1_VERTEX_BUFFER_PROPERTIES, + resourceId: *const GUID, + customVertexBufferProperties: *const D2D1_CUSTOM_VERTEX_BUFFER_PROPERTIES, + buffer: *mut *mut ID2D1VertexBuffer, + ) -> HRESULT, + fn FindVertexBuffer( + resourceId: *const GUID, + buffer: *mut *mut ID2D1VertexBuffer, + ) -> HRESULT, + fn CreateColorContext( + space: D2D1_COLOR_SPACE, + profile: *const BYTE, + profileSize: UINT32, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CreateColorContextFromFilename( + filename: PCWSTR, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CreateColorContextFromWicColorContext( + wicColorContext: *mut IWICColorContext, + colorContext: *mut *mut ID2D1ColorContext, + ) -> HRESULT, + fn CheckFeatureSupport( + feature: D2D1_FEATURE, + featureSupportData: *mut c_void, + featureSupportDataSize: UINT32, + ) -> HRESULT, + fn IsBufferPrecisionSupported( + bufferPrecision: D2D1_BUFFER_PRECISION, + ) -> BOOL, +}} diff --git a/winapi/src/um/d2d1effects.rs b/winapi/src/um/d2d1effects.rs new file mode 100644 index 000000000..c2d1f58a1 --- /dev/null +++ b/winapi/src/um/d2d1effects.rs @@ -0,0 +1,617 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1effects.h +DEFINE_GUID!{CLSID_D2D12DAffineTransform, + 0x6AA97485, 0x6354, 0x4cfc, 0x90, 0x8C, 0xE4, 0xA7, 0x4F, 0x62, 0xC9, 0x6C} +DEFINE_GUID!{CLSID_D2D13DPerspectiveTransform, + 0xC2844D0B, 0x3D86, 0x46e7, 0x85, 0xBA, 0x52, 0x6C, 0x92, 0x40, 0xF3, 0xFB} +DEFINE_GUID!{CLSID_D2D13DTransform, + 0xe8467b04, 0xec61, 0x4b8a, 0xb5, 0xde, 0xd4, 0xd7, 0x3d, 0xeb, 0xea, 0x5a} +DEFINE_GUID!{CLSID_D2D1ArithmeticComposite, + 0xfc151437, 0x049a, 0x4784, 0xa2, 0x4a, 0xf1, 0xc4, 0xda, 0xf2, 0x09, 0x87} +DEFINE_GUID!{CLSID_D2D1Atlas, + 0x913e2be4, 0xfdcf, 0x4fe2, 0xa5, 0xf0, 0x24, 0x54, 0xf1, 0x4f, 0xf4, 0x08} +DEFINE_GUID!{CLSID_D2D1BitmapSource, + 0x5fb6c24d, 0xc6dd, 0x4231, 0x94, 0x4, 0x50, 0xf4, 0xd5, 0xc3, 0x25, 0x2d} +DEFINE_GUID!{CLSID_D2D1Blend, + 0x81c5b77b, 0x13f8, 0x4cdd, 0xad, 0x20, 0xc8, 0x90, 0x54, 0x7a, 0xc6, 0x5d} +DEFINE_GUID!{CLSID_D2D1Border, + 0x2A2D49C0, 0x4ACF, 0x43c7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27} +DEFINE_GUID!{CLSID_D2D1Brightness, + 0x8cea8d1e, 0x77b0, 0x4986, 0xb3, 0xb9, 0x2f, 0x0c, 0x0e, 0xae, 0x78, 0x87} +DEFINE_GUID!{CLSID_D2D1ColorManagement, + 0x1A28524C, 0xFDD6, 0x4AA4, 0xAE, 0x8F, 0x83, 0x7E, 0xB8, 0x26, 0x7B, 0x37} +DEFINE_GUID!{CLSID_D2D1ColorMatrix, + 0x921F03D6, 0x641C, 0x47DF, 0x85, 0x2D, 0xB4, 0xBB, 0x61, 0x53, 0xAE, 0x11} +DEFINE_GUID!{CLSID_D2D1Composite, + 0x48fc9f51, 0xf6ac, 0x48f1, 0x8b, 0x58, 0x3b, 0x28, 0xac, 0x46, 0xf7, 0x6d} +DEFINE_GUID!{CLSID_D2D1ConvolveMatrix, + 0x407f8c08, 0x5533, 0x4331, 0xa3, 0x41, 0x23, 0xcc, 0x38, 0x77, 0x84, 0x3e} +DEFINE_GUID!{CLSID_D2D1Crop, + 0xE23F7110, 0x0E9A, 0x4324, 0xAF, 0x47, 0x6A, 0x2C, 0x0C, 0x46, 0xF3, 0x5B} +DEFINE_GUID!{CLSID_D2D1DirectionalBlur, + 0x174319a6, 0x58e9, 0x49b2, 0xbb, 0x63, 0xca, 0xf2, 0xc8, 0x11, 0xa3, 0xdb} +DEFINE_GUID!{CLSID_D2D1DiscreteTransfer, + 0x90866fcd, 0x488e, 0x454b, 0xaf, 0x06, 0xe5, 0x04, 0x1b, 0x66, 0xc3, 0x6c} +DEFINE_GUID!{CLSID_D2D1DisplacementMap, + 0xedc48364, 0x417, 0x4111, 0x94, 0x50, 0x43, 0x84, 0x5f, 0xa9, 0xf8, 0x90} +DEFINE_GUID!{CLSID_D2D1DistantDiffuse, + 0x3e7efd62, 0xa32d, 0x46d4, 0xa8, 0x3c, 0x52, 0x78, 0x88, 0x9a, 0xc9, 0x54} +DEFINE_GUID!{CLSID_D2D1DistantSpecular, + 0x428c1ee5, 0x77b8, 0x4450, 0x8a, 0xb5, 0x72, 0x21, 0x9c, 0x21, 0xab, 0xda} +DEFINE_GUID!{CLSID_D2D1DpiCompensation, + 0x6c26c5c7, 0x34e0, 0x46fc, 0x9c, 0xfd, 0xe5, 0x82, 0x37, 0x6, 0xe2, 0x28} +DEFINE_GUID!{CLSID_D2D1Flood, + 0x61c23c20, 0xae69, 0x4d8e, 0x94, 0xcf, 0x50, 0x07, 0x8d, 0xf6, 0x38, 0xf2} +DEFINE_GUID!{CLSID_D2D1GammaTransfer, + 0x409444c4, 0xc419, 0x41a0, 0xb0, 0xc1, 0x8c, 0xd0, 0xc0, 0xa1, 0x8e, 0x42} +DEFINE_GUID!{CLSID_D2D1GaussianBlur, + 0x1feb6d69, 0x2fe6, 0x4ac9, 0x8c, 0x58, 0x1d, 0x7f, 0x93, 0xe7, 0xa6, 0xa5} +DEFINE_GUID!{CLSID_D2D1Scale, + 0x9daf9369, 0x3846, 0x4d0e, 0xa4, 0x4e, 0xc, 0x60, 0x79, 0x34, 0xa5, 0xd7} +DEFINE_GUID!{CLSID_D2D1Histogram, + 0x881db7d0, 0xf7ee, 0x4d4d, 0xa6, 0xd2, 0x46, 0x97, 0xac, 0xc6, 0x6e, 0xe8} +DEFINE_GUID!{CLSID_D2D1HueRotation, + 0x0f4458ec, 0x4b32, 0x491b, 0x9e, 0x85, 0xbd, 0x73, 0xf4, 0x4d, 0x3e, 0xb6} +DEFINE_GUID!{CLSID_D2D1LinearTransfer, + 0xad47c8fd, 0x63ef, 0x4acc, 0x9b, 0x51, 0x67, 0x97, 0x9c, 0x03, 0x6c, 0x06} +DEFINE_GUID!{CLSID_D2D1LuminanceToAlpha, + 0x41251ab7, 0x0beb, 0x46f8, 0x9d, 0xa7, 0x59, 0xe9, 0x3f, 0xcc, 0xe5, 0xde} +DEFINE_GUID!{CLSID_D2D1Morphology, + 0xeae6c40d, 0x626a, 0x4c2d, 0xbf, 0xcb, 0x39, 0x10, 0x01, 0xab, 0xe2, 0x02} +DEFINE_GUID!{CLSID_D2D1OpacityMetadata, + 0x6c53006a, 0x4450, 0x4199, 0xaa, 0x5b, 0xad, 0x16, 0x56, 0xfe, 0xce, 0x5e} +DEFINE_GUID!{CLSID_D2D1PointDiffuse, + 0xb9e303c3, 0xc08c, 0x4f91, 0x8b, 0x7b, 0x38, 0x65, 0x6b, 0xc4, 0x8c, 0x20} +DEFINE_GUID!{CLSID_D2D1PointSpecular, + 0x09c3ca26, 0x3ae2, 0x4f09, 0x9e, 0xbc, 0xed, 0x38, 0x65, 0xd5, 0x3f, 0x22} +DEFINE_GUID!{CLSID_D2D1Premultiply, + 0x06eab419, 0xdeed, 0x4018, 0x80, 0xd2, 0x3e, 0x1d, 0x47, 0x1a, 0xde, 0xb2} +DEFINE_GUID!{CLSID_D2D1Saturation, + 0x5cb2d9cf, 0x327d, 0x459f, 0xa0, 0xce, 0x40, 0xc0, 0xb2, 0x08, 0x6b, 0xf7} +DEFINE_GUID!{CLSID_D2D1Shadow, + 0xC67EA361, 0x1863, 0x4e69, 0x89, 0xDB, 0x69, 0x5D, 0x3E, 0x9A, 0x5B, 0x6B} +DEFINE_GUID!{CLSID_D2D1SpotDiffuse, + 0x818a1105, 0x7932, 0x44f4, 0xaa, 0x86, 0x08, 0xae, 0x7b, 0x2f, 0x2c, 0x93} +DEFINE_GUID!{CLSID_D2D1SpotSpecular, + 0xedae421e, 0x7654, 0x4a37, 0x9d, 0xb8, 0x71, 0xac, 0xc1, 0xbe, 0xb3, 0xc1} +DEFINE_GUID!{CLSID_D2D1TableTransfer, + 0x5bf818c3, 0x5e43, 0x48cb, 0xb6, 0x31, 0x86, 0x83, 0x96, 0xd6, 0xa1, 0xd4} +DEFINE_GUID!{CLSID_D2D1Tile, + 0xB0784138, 0x3B76, 0x4bc5, 0xB1, 0x3B, 0x0F, 0xA2, 0xAD, 0x02, 0x65, 0x9F} +DEFINE_GUID!{CLSID_D2D1Turbulence, + 0xCF2BB6AE, 0x889A, 0x4ad7, 0xBA, 0x29, 0xA2, 0xFD, 0x73, 0x2C, 0x9F, 0xC9} +DEFINE_GUID!{CLSID_D2D1UnPremultiply, + 0xfb9ac489, 0xad8d, 0x41ed, 0x99, 0x99, 0xbb, 0x63, 0x47, 0xd1, 0x10, 0xf7} +ENUM!{enum D2D1_BORDER_MODE { + D2D1_BORDER_MODE_SOFT = 0, + D2D1_BORDER_MODE_HARD = 1, + D2D1_BORDER_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_CHANNEL_SELECTOR { + D2D1_CHANNEL_SELECTOR_R = 0, + D2D1_CHANNEL_SELECTOR_G = 1, + D2D1_CHANNEL_SELECTOR_B = 2, + D2D1_CHANNEL_SELECTOR_A = 3, + D2D1_CHANNEL_SELECTOR_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BITMAPSOURCE_ORIENTATION { + D2D1_BITMAPSOURCE_ORIENTATION_DEFAULT = 1, + D2D1_BITMAPSOURCE_ORIENTATION_FLIP_HORIZONTAL = 2, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE180 = 3, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE180_FLIP_HORIZONTAL = 4, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE270_FLIP_HORIZONTAL = 5, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE90 = 6, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE90_FLIP_HORIZONTAL = 7, + D2D1_BITMAPSOURCE_ORIENTATION_ROTATE_CLOCKWISE270 = 8, + D2D1_BITMAPSOURCE_ORIENTATION_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_GAUSSIANBLUR_PROP { + D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION = 0, + D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION = 1, + D2D1_GAUSSIANBLUR_PROP_BORDER_MODE = 2, + D2D1_GAUSSIANBLUR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_GAUSSIANBLUR_OPTIMIZATION { + D2D1_GAUSSIANBLUR_OPTIMIZATION_SPEED = 0, + D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED = 1, + D2D1_GAUSSIANBLUR_OPTIMIZATION_QUALITY = 2, + D2D1_GAUSSIANBLUR_OPTIMIZATION_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DIRECTIONALBLUR_PROP { + D2D1_DIRECTIONALBLUR_PROP_STANDARD_DEVIATION = 0, + D2D1_DIRECTIONALBLUR_PROP_ANGLE = 1, + D2D1_DIRECTIONALBLUR_PROP_OPTIMIZATION = 2, + D2D1_DIRECTIONALBLUR_PROP_BORDER_MODE = 3, + D2D1_DIRECTIONALBLUR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DIRECTIONALBLUR_OPTIMIZATION { + D2D1_DIRECTIONALBLUR_OPTIMIZATION_SPEED = 0, + D2D1_DIRECTIONALBLUR_OPTIMIZATION_BALANCED = 1, + D2D1_DIRECTIONALBLUR_OPTIMIZATION_QUALITY = 2, + D2D1_DIRECTIONALBLUR_OPTIMIZATION_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SHADOW_PROP { + D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION = 0, + D2D1_SHADOW_PROP_COLOR = 1, + D2D1_SHADOW_PROP_OPTIMIZATION = 2, + D2D1_SHADOW_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SHADOW_OPTIMIZATION { + D2D1_SHADOW_OPTIMIZATION_SPEED = 0, + D2D1_SHADOW_OPTIMIZATION_BALANCED = 1, + D2D1_SHADOW_OPTIMIZATION_QUALITY = 2, + D2D1_SHADOW_OPTIMIZATION_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BLEND_PROP { + D2D1_BLEND_PROP_MODE = 0, + D2D1_BLEND_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BLEND_MODE { + D2D1_BLEND_MODE_MULTIPLY = 0, + D2D1_BLEND_MODE_SCREEN = 1, + D2D1_BLEND_MODE_DARKEN = 2, + D2D1_BLEND_MODE_LIGHTEN = 3, + D2D1_BLEND_MODE_DISSOLVE = 4, + D2D1_BLEND_MODE_COLOR_BURN = 5, + D2D1_BLEND_MODE_LINEAR_BURN = 6, + D2D1_BLEND_MODE_DARKER_COLOR = 7, + D2D1_BLEND_MODE_LIGHTER_COLOR = 8, + D2D1_BLEND_MODE_COLOR_DODGE = 9, + D2D1_BLEND_MODE_LINEAR_DODGE = 10, + D2D1_BLEND_MODE_OVERLAY = 11, + D2D1_BLEND_MODE_SOFT_LIGHT = 12, + D2D1_BLEND_MODE_HARD_LIGHT = 13, + D2D1_BLEND_MODE_VIVID_LIGHT = 14, + D2D1_BLEND_MODE_LINEAR_LIGHT = 15, + D2D1_BLEND_MODE_PIN_LIGHT = 16, + D2D1_BLEND_MODE_HARD_MIX = 17, + D2D1_BLEND_MODE_DIFFERENCE = 18, + D2D1_BLEND_MODE_EXCLUSION = 19, + D2D1_BLEND_MODE_HUE = 20, + D2D1_BLEND_MODE_SATURATION = 21, + D2D1_BLEND_MODE_COLOR = 22, + D2D1_BLEND_MODE_LUMINOSITY = 23, + D2D1_BLEND_MODE_SUBTRACT = 24, + D2D1_BLEND_MODE_DIVISION = 25, + D2D1_BLEND_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SATURATION_PROP { + D2D1_SATURATION_PROP_SATURATION = 0, + D2D1_SATURATION_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_HUEROTATION_PROP { + D2D1_HUEROTATION_PROP_ANGLE = 0, + D2D1_HUEROTATION_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMATRIX_PROP { + D2D1_COLORMATRIX_PROP_COLOR_MATRIX = 0, + D2D1_COLORMATRIX_PROP_ALPHA_MODE = 1, + D2D1_COLORMATRIX_PROP_CLAMP_OUTPUT = 2, + D2D1_COLORMATRIX_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMATRIX_ALPHA_MODE { + D2D1_COLORMATRIX_ALPHA_MODE_PREMULTIPLIED = 1, + D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT = 2, + D2D1_COLORMATRIX_ALPHA_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BITMAPSOURCE_PROP { + D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE = 0, + D2D1_BITMAPSOURCE_PROP_SCALE = 1, + D2D1_BITMAPSOURCE_PROP_INTERPOLATION_MODE = 2, + D2D1_BITMAPSOURCE_PROP_ENABLE_DPI_CORRECTION = 3, + D2D1_BITMAPSOURCE_PROP_ALPHA_MODE = 4, + D2D1_BITMAPSOURCE_PROP_ORIENTATION = 5, + D2D1_BITMAPSOURCE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BITMAPSOURCE_INTERPOLATION_MODE { + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_LINEAR = 1, + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_CUBIC = 2, + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_FANT = 6, + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_MIPMAP_LINEAR = 7, + D2D1_BITMAPSOURCE_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BITMAPSOURCE_ALPHA_MODE { + D2D1_BITMAPSOURCE_ALPHA_MODE_PREMULTIPLIED = 1, + D2D1_BITMAPSOURCE_ALPHA_MODE_STRAIGHT = 2, + D2D1_BITMAPSOURCE_ALPHA_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COMPOSITE_PROP { + D2D1_COMPOSITE_PROP_MODE = 0, + D2D1_COMPOSITE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_3DTRANSFORM_PROP { + D2D1_3DTRANSFORM_PROP_INTERPOLATION_MODE = 0, + D2D1_3DTRANSFORM_PROP_BORDER_MODE = 1, + D2D1_3DTRANSFORM_PROP_TRANSFORM_MATRIX = 2, + D2D1_3DTRANSFORM_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_3DTRANSFORM_INTERPOLATION_MODE { + D2D1_3DTRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_3DTRANSFORM_INTERPOLATION_MODE_LINEAR = 1, + D2D1_3DTRANSFORM_INTERPOLATION_MODE_CUBIC = 2, + D2D1_3DTRANSFORM_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_3DTRANSFORM_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_3DTRANSFORM_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_3DPERSPECTIVETRANSFORM_PROP { + D2D1_3DPERSPECTIVETRANSFORM_PROP_INTERPOLATION_MODE = 0, + D2D1_3DPERSPECTIVETRANSFORM_PROP_BORDER_MODE = 1, + D2D1_3DPERSPECTIVETRANSFORM_PROP_DEPTH = 2, + D2D1_3DPERSPECTIVETRANSFORM_PROP_PERSPECTIVE_ORIGIN = 3, + D2D1_3DPERSPECTIVETRANSFORM_PROP_LOCAL_OFFSET = 4, + D2D1_3DPERSPECTIVETRANSFORM_PROP_GLOBAL_OFFSET = 5, + D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION_ORIGIN = 6, + D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION = 7, + D2D1_3DPERSPECTIVETRANSFORM_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE { + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_LINEAR = 1, + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_CUBIC = 2, + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_3DPERSPECTIVETRANSFORM_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_2DAFFINETRANSFORM_PROP { + D2D1_2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE = 0, + D2D1_2DAFFINETRANSFORM_PROP_BORDER_MODE = 1, + D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX = 2, + D2D1_2DAFFINETRANSFORM_PROP_SHARPNESS = 3, + D2D1_2DAFFINETRANSFORM_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE { + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR = 1, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_CUBIC = 2, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DPICOMPENSATION_PROP { + D2D1_DPICOMPENSATION_PROP_INTERPOLATION_MODE = 0, + D2D1_DPICOMPENSATION_PROP_BORDER_MODE = 1, + D2D1_DPICOMPENSATION_PROP_INPUT_DPI = 2, + D2D1_DPICOMPENSATION_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DPICOMPENSATION_INTERPOLATION_MODE { + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_LINEAR = 1, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_CUBIC = 2, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_DPICOMPENSATION_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SCALE_PROP { + D2D1_SCALE_PROP_SCALE = 0, + D2D1_SCALE_PROP_CENTER_POINT = 1, + D2D1_SCALE_PROP_INTERPOLATION_MODE = 2, + D2D1_SCALE_PROP_BORDER_MODE = 3, + D2D1_SCALE_PROP_SHARPNESS = 4, + D2D1_SCALE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SCALE_INTERPOLATION_MODE { + D2D1_SCALE_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_SCALE_INTERPOLATION_MODE_LINEAR = 1, + D2D1_SCALE_INTERPOLATION_MODE_CUBIC = 2, + D2D1_SCALE_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_SCALE_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_SCALE_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_SCALE_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_TURBULENCE_PROP { + D2D1_TURBULENCE_PROP_OFFSET = 0, + D2D1_TURBULENCE_PROP_SIZE = 1, + D2D1_TURBULENCE_PROP_BASE_FREQUENCY = 2, + D2D1_TURBULENCE_PROP_NUM_OCTAVES = 3, + D2D1_TURBULENCE_PROP_SEED = 4, + D2D1_TURBULENCE_PROP_NOISE = 5, + D2D1_TURBULENCE_PROP_STITCHABLE = 6, + D2D1_TURBULENCE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_TURBULENCE_NOISE { + D2D1_TURBULENCE_NOISE_FRACTAL_SUM = 0, + D2D1_TURBULENCE_NOISE_TURBULENCE = 1, + D2D1_TURBULENCE_NOISE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISPLACEMENTMAP_PROP { + D2D1_DISPLACEMENTMAP_PROP_SCALE = 0, + D2D1_DISPLACEMENTMAP_PROP_X_CHANNEL_SELECT = 1, + D2D1_DISPLACEMENTMAP_PROP_Y_CHANNEL_SELECT = 2, + D2D1_DISPLACEMENTMAP_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMANAGEMENT_PROP { + D2D1_COLORMANAGEMENT_PROP_SOURCE_COLOR_CONTEXT = 0, + D2D1_COLORMANAGEMENT_PROP_SOURCE_RENDERING_INTENT = 1, + D2D1_COLORMANAGEMENT_PROP_DESTINATION_COLOR_CONTEXT = 2, + D2D1_COLORMANAGEMENT_PROP_DESTINATION_RENDERING_INTENT = 3, + D2D1_COLORMANAGEMENT_PROP_ALPHA_MODE = 4, + D2D1_COLORMANAGEMENT_PROP_QUALITY = 5, + D2D1_COLORMANAGEMENT_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMANAGEMENT_ALPHA_MODE { + D2D1_COLORMANAGEMENT_ALPHA_MODE_PREMULTIPLIED = 1, + D2D1_COLORMANAGEMENT_ALPHA_MODE_STRAIGHT = 2, + D2D1_COLORMANAGEMENT_ALPHA_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMANAGEMENT_QUALITY { + D2D1_COLORMANAGEMENT_QUALITY_PROOF = 0, + D2D1_COLORMANAGEMENT_QUALITY_NORMAL = 1, + D2D1_COLORMANAGEMENT_QUALITY_BEST = 2, + D2D1_COLORMANAGEMENT_QUALITY_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_COLORMANAGEMENT_RENDERING_INTENT { + D2D1_COLORMANAGEMENT_RENDERING_INTENT_PERCEPTUAL = 0, + D2D1_COLORMANAGEMENT_RENDERING_INTENT_RELATIVE_COLORIMETRIC = 1, + D2D1_COLORMANAGEMENT_RENDERING_INTENT_SATURATION = 2, + D2D1_COLORMANAGEMENT_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = 3, + D2D1_COLORMANAGEMENT_RENDERING_INTENT_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_HISTOGRAM_PROP { + D2D1_HISTOGRAM_PROP_NUM_BINS = 0, + D2D1_HISTOGRAM_PROP_CHANNEL_SELECT = 1, + D2D1_HISTOGRAM_PROP_HISTOGRAM_OUTPUT = 2, + D2D1_HISTOGRAM_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_POINTSPECULAR_PROP { + D2D1_POINTSPECULAR_PROP_LIGHT_POSITION = 0, + D2D1_POINTSPECULAR_PROP_SPECULAR_EXPONENT = 1, + D2D1_POINTSPECULAR_PROP_SPECULAR_CONSTANT = 2, + D2D1_POINTSPECULAR_PROP_SURFACE_SCALE = 3, + D2D1_POINTSPECULAR_PROP_COLOR = 4, + D2D1_POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH = 5, + D2D1_POINTSPECULAR_PROP_SCALE_MODE = 6, + D2D1_POINTSPECULAR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_POINTSPECULAR_SCALE_MODE { + D2D1_POINTSPECULAR_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_POINTSPECULAR_SCALE_MODE_LINEAR = 1, + D2D1_POINTSPECULAR_SCALE_MODE_CUBIC = 2, + D2D1_POINTSPECULAR_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_POINTSPECULAR_SCALE_MODE_ANISOTROPIC = 4, + D2D1_POINTSPECULAR_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_POINTSPECULAR_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SPOTSPECULAR_PROP { + D2D1_SPOTSPECULAR_PROP_LIGHT_POSITION = 0, + D2D1_SPOTSPECULAR_PROP_POINTS_AT = 1, + D2D1_SPOTSPECULAR_PROP_FOCUS = 2, + D2D1_SPOTSPECULAR_PROP_LIMITING_CONE_ANGLE = 3, + D2D1_SPOTSPECULAR_PROP_SPECULAR_EXPONENT = 4, + D2D1_SPOTSPECULAR_PROP_SPECULAR_CONSTANT = 5, + D2D1_SPOTSPECULAR_PROP_SURFACE_SCALE = 6, + D2D1_SPOTSPECULAR_PROP_COLOR = 7, + D2D1_SPOTSPECULAR_PROP_KERNEL_UNIT_LENGTH = 8, + D2D1_SPOTSPECULAR_PROP_SCALE_MODE = 9, + D2D1_SPOTSPECULAR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SPOTSPECULAR_SCALE_MODE { + D2D1_SPOTSPECULAR_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_SPOTSPECULAR_SCALE_MODE_LINEAR = 1, + D2D1_SPOTSPECULAR_SCALE_MODE_CUBIC = 2, + D2D1_SPOTSPECULAR_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_SPOTSPECULAR_SCALE_MODE_ANISOTROPIC = 4, + D2D1_SPOTSPECULAR_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_SPOTSPECULAR_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISTANTSPECULAR_PROP { + D2D1_DISTANTSPECULAR_PROP_AZIMUTH = 0, + D2D1_DISTANTSPECULAR_PROP_ELEVATION = 1, + D2D1_DISTANTSPECULAR_PROP_SPECULAR_EXPONENT = 2, + D2D1_DISTANTSPECULAR_PROP_SPECULAR_CONSTANT = 3, + D2D1_DISTANTSPECULAR_PROP_SURFACE_SCALE = 4, + D2D1_DISTANTSPECULAR_PROP_COLOR = 5, + D2D1_DISTANTSPECULAR_PROP_KERNEL_UNIT_LENGTH = 6, + D2D1_DISTANTSPECULAR_PROP_SCALE_MODE = 7, + D2D1_DISTANTSPECULAR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISTANTSPECULAR_SCALE_MODE { + D2D1_DISTANTSPECULAR_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_DISTANTSPECULAR_SCALE_MODE_LINEAR = 1, + D2D1_DISTANTSPECULAR_SCALE_MODE_CUBIC = 2, + D2D1_DISTANTSPECULAR_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_DISTANTSPECULAR_SCALE_MODE_ANISOTROPIC = 4, + D2D1_DISTANTSPECULAR_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_DISTANTSPECULAR_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_POINTDIFFUSE_PROP { + D2D1_POINTDIFFUSE_PROP_LIGHT_POSITION = 0, + D2D1_POINTDIFFUSE_PROP_DIFFUSE_CONSTANT = 1, + D2D1_POINTDIFFUSE_PROP_SURFACE_SCALE = 2, + D2D1_POINTDIFFUSE_PROP_COLOR = 3, + D2D1_POINTDIFFUSE_PROP_KERNEL_UNIT_LENGTH = 4, + D2D1_POINTDIFFUSE_PROP_SCALE_MODE = 5, + D2D1_POINTDIFFUSE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_POINTDIFFUSE_SCALE_MODE { + D2D1_POINTDIFFUSE_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_POINTDIFFUSE_SCALE_MODE_LINEAR = 1, + D2D1_POINTDIFFUSE_SCALE_MODE_CUBIC = 2, + D2D1_POINTDIFFUSE_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_POINTDIFFUSE_SCALE_MODE_ANISOTROPIC = 4, + D2D1_POINTDIFFUSE_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_POINTDIFFUSE_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SPOTDIFFUSE_PROP { + D2D1_SPOTDIFFUSE_PROP_LIGHT_POSITION = 0, + D2D1_SPOTDIFFUSE_PROP_POINTS_AT = 1, + D2D1_SPOTDIFFUSE_PROP_FOCUS = 2, + D2D1_SPOTDIFFUSE_PROP_LIMITING_CONE_ANGLE = 3, + D2D1_SPOTDIFFUSE_PROP_DIFFUSE_CONSTANT = 4, + D2D1_SPOTDIFFUSE_PROP_SURFACE_SCALE = 5, + D2D1_SPOTDIFFUSE_PROP_COLOR = 6, + D2D1_SPOTDIFFUSE_PROP_KERNEL_UNIT_LENGTH = 7, + D2D1_SPOTDIFFUSE_PROP_SCALE_MODE = 8, + D2D1_SPOTDIFFUSE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_SPOTDIFFUSE_SCALE_MODE { + D2D1_SPOTDIFFUSE_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_SPOTDIFFUSE_SCALE_MODE_LINEAR = 1, + D2D1_SPOTDIFFUSE_SCALE_MODE_CUBIC = 2, + D2D1_SPOTDIFFUSE_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_SPOTDIFFUSE_SCALE_MODE_ANISOTROPIC = 4, + D2D1_SPOTDIFFUSE_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_SPOTDIFFUSE_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISTANTDIFFUSE_PROP { + D2D1_DISTANTDIFFUSE_PROP_AZIMUTH = 0, + D2D1_DISTANTDIFFUSE_PROP_ELEVATION = 1, + D2D1_DISTANTDIFFUSE_PROP_DIFFUSE_CONSTANT = 2, + D2D1_DISTANTDIFFUSE_PROP_SURFACE_SCALE = 3, + D2D1_DISTANTDIFFUSE_PROP_COLOR = 4, + D2D1_DISTANTDIFFUSE_PROP_KERNEL_UNIT_LENGTH = 5, + D2D1_DISTANTDIFFUSE_PROP_SCALE_MODE = 6, + D2D1_DISTANTDIFFUSE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISTANTDIFFUSE_SCALE_MODE { + D2D1_DISTANTDIFFUSE_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_DISTANTDIFFUSE_SCALE_MODE_LINEAR = 1, + D2D1_DISTANTDIFFUSE_SCALE_MODE_CUBIC = 2, + D2D1_DISTANTDIFFUSE_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_DISTANTDIFFUSE_SCALE_MODE_ANISOTROPIC = 4, + D2D1_DISTANTDIFFUSE_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_DISTANTDIFFUSE_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_FLOOD_PROP { + D2D1_FLOOD_PROP_COLOR = 0, + D2D1_FLOOD_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_LINEARTRANSFER_PROP { + D2D1_LINEARTRANSFER_PROP_RED_Y_INTERCEPT = 0, + D2D1_LINEARTRANSFER_PROP_RED_SLOPE = 1, + D2D1_LINEARTRANSFER_PROP_RED_DISABLE = 2, + D2D1_LINEARTRANSFER_PROP_GREEN_Y_INTERCEPT = 3, + D2D1_LINEARTRANSFER_PROP_GREEN_SLOPE = 4, + D2D1_LINEARTRANSFER_PROP_GREEN_DISABLE = 5, + D2D1_LINEARTRANSFER_PROP_BLUE_Y_INTERCEPT = 6, + D2D1_LINEARTRANSFER_PROP_BLUE_SLOPE = 7, + D2D1_LINEARTRANSFER_PROP_BLUE_DISABLE = 8, + D2D1_LINEARTRANSFER_PROP_ALPHA_Y_INTERCEPT = 9, + D2D1_LINEARTRANSFER_PROP_ALPHA_SLOPE = 10, + D2D1_LINEARTRANSFER_PROP_ALPHA_DISABLE = 11, + D2D1_LINEARTRANSFER_PROP_CLAMP_OUTPUT = 12, + D2D1_LINEARTRANSFER_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_GAMMATRANSFER_PROP { + D2D1_GAMMATRANSFER_PROP_RED_AMPLITUDE = 0, + D2D1_GAMMATRANSFER_PROP_RED_EXPONENT = 1, + D2D1_GAMMATRANSFER_PROP_RED_OFFSET = 2, + D2D1_GAMMATRANSFER_PROP_RED_DISABLE = 3, + D2D1_GAMMATRANSFER_PROP_GREEN_AMPLITUDE = 4, + D2D1_GAMMATRANSFER_PROP_GREEN_EXPONENT = 5, + D2D1_GAMMATRANSFER_PROP_GREEN_OFFSET = 6, + D2D1_GAMMATRANSFER_PROP_GREEN_DISABLE = 7, + D2D1_GAMMATRANSFER_PROP_BLUE_AMPLITUDE = 8, + D2D1_GAMMATRANSFER_PROP_BLUE_EXPONENT = 9, + D2D1_GAMMATRANSFER_PROP_BLUE_OFFSET = 10, + D2D1_GAMMATRANSFER_PROP_BLUE_DISABLE = 11, + D2D1_GAMMATRANSFER_PROP_ALPHA_AMPLITUDE = 12, + D2D1_GAMMATRANSFER_PROP_ALPHA_EXPONENT = 13, + D2D1_GAMMATRANSFER_PROP_ALPHA_OFFSET = 14, + D2D1_GAMMATRANSFER_PROP_ALPHA_DISABLE = 15, + D2D1_GAMMATRANSFER_PROP_CLAMP_OUTPUT = 16, + D2D1_GAMMATRANSFER_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_TABLETRANSFER_PROP { + D2D1_TABLETRANSFER_PROP_RED_TABLE = 0, + D2D1_TABLETRANSFER_PROP_RED_DISABLE = 1, + D2D1_TABLETRANSFER_PROP_GREEN_TABLE = 2, + D2D1_TABLETRANSFER_PROP_GREEN_DISABLE = 3, + D2D1_TABLETRANSFER_PROP_BLUE_TABLE = 4, + D2D1_TABLETRANSFER_PROP_BLUE_DISABLE = 5, + D2D1_TABLETRANSFER_PROP_ALPHA_TABLE = 6, + D2D1_TABLETRANSFER_PROP_ALPHA_DISABLE = 7, + D2D1_TABLETRANSFER_PROP_CLAMP_OUTPUT = 8, + D2D1_TABLETRANSFER_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_DISCRETETRANSFER_PROP { + D2D1_DISCRETETRANSFER_PROP_RED_TABLE = 0, + D2D1_DISCRETETRANSFER_PROP_RED_DISABLE = 1, + D2D1_DISCRETETRANSFER_PROP_GREEN_TABLE = 2, + D2D1_DISCRETETRANSFER_PROP_GREEN_DISABLE = 3, + D2D1_DISCRETETRANSFER_PROP_BLUE_TABLE = 4, + D2D1_DISCRETETRANSFER_PROP_BLUE_DISABLE = 5, + D2D1_DISCRETETRANSFER_PROP_ALPHA_TABLE = 6, + D2D1_DISCRETETRANSFER_PROP_ALPHA_DISABLE = 7, + D2D1_DISCRETETRANSFER_PROP_CLAMP_OUTPUT = 8, + D2D1_DISCRETETRANSFER_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_CONVOLVEMATRIX_PROP { + D2D1_CONVOLVEMATRIX_PROP_KERNEL_UNIT_LENGTH = 0, + D2D1_CONVOLVEMATRIX_PROP_SCALE_MODE = 1, + D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_X = 2, + D2D1_CONVOLVEMATRIX_PROP_KERNEL_SIZE_Y = 3, + D2D1_CONVOLVEMATRIX_PROP_KERNEL_MATRIX = 4, + D2D1_CONVOLVEMATRIX_PROP_DIVISOR = 5, + D2D1_CONVOLVEMATRIX_PROP_BIAS = 6, + D2D1_CONVOLVEMATRIX_PROP_KERNEL_OFFSET = 7, + D2D1_CONVOLVEMATRIX_PROP_PRESERVE_ALPHA = 8, + D2D1_CONVOLVEMATRIX_PROP_BORDER_MODE = 9, + D2D1_CONVOLVEMATRIX_PROP_CLAMP_OUTPUT = 10, + D2D1_CONVOLVEMATRIX_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_CONVOLVEMATRIX_SCALE_MODE { + D2D1_CONVOLVEMATRIX_SCALE_MODE_NEAREST_NEIGHBOR = 0, + D2D1_CONVOLVEMATRIX_SCALE_MODE_LINEAR = 1, + D2D1_CONVOLVEMATRIX_SCALE_MODE_CUBIC = 2, + D2D1_CONVOLVEMATRIX_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_CONVOLVEMATRIX_SCALE_MODE_ANISOTROPIC = 4, + D2D1_CONVOLVEMATRIX_SCALE_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_CONVOLVEMATRIX_SCALE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BRIGHTNESS_PROP { + D2D1_BRIGHTNESS_PROP_WHITE_POINT = 0, + D2D1_BRIGHTNESS_PROP_BLACK_POINT = 1, + D2D1_BRIGHTNESS_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_ARITHMETICCOMPOSITE_PROP { + D2D1_ARITHMETICCOMPOSITE_PROP_COEFFICIENTS = 0, + D2D1_ARITHMETICCOMPOSITE_PROP_CLAMP_OUTPUT = 1, + D2D1_ARITHMETICCOMPOSITE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_CROP_PROP { + D2D1_CROP_PROP_RECT = 0, + D2D1_CROP_PROP_BORDER_MODE = 1, + D2D1_CROP_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BORDER_PROP { + D2D1_BORDER_PROP_EDGE_MODE_X = 0, + D2D1_BORDER_PROP_EDGE_MODE_Y = 1, + D2D1_BORDER_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_BORDER_EDGE_MODE { + D2D1_BORDER_EDGE_MODE_CLAMP = 0, + D2D1_BORDER_EDGE_MODE_WRAP = 1, + D2D1_BORDER_EDGE_MODE_MIRROR = 2, + D2D1_BORDER_EDGE_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_MORPHOLOGY_PROP { + D2D1_MORPHOLOGY_PROP_MODE = 0, + D2D1_MORPHOLOGY_PROP_WIDTH = 1, + D2D1_MORPHOLOGY_PROP_HEIGHT = 2, + D2D1_MORPHOLOGY_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_MORPHOLOGY_MODE { + D2D1_MORPHOLOGY_MODE_ERODE = 0, + D2D1_MORPHOLOGY_MODE_DILATE = 1, + D2D1_MORPHOLOGY_MODE_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_TILE_PROP { + D2D1_TILE_PROP_RECT = 0, + D2D1_TILE_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_ATLAS_PROP { + D2D1_ATLAS_PROP_INPUT_RECT = 0, + D2D1_ATLAS_PROP_INPUT_PADDING_RECT = 1, + D2D1_ATLAS_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_OPACITYMETADATA_PROP { + D2D1_OPACITYMETADATA_PROP_INPUT_OPAQUE_RECT = 0, + D2D1_OPACITYMETADATA_PROP_FORCE_DWORD = 0xffffffff, +}} diff --git a/winapi/src/um/d2d1effects_1.rs b/winapi/src/um/d2d1effects_1.rs new file mode 100644 index 000000000..ba97f0149 --- /dev/null +++ b/winapi/src/um/d2d1effects_1.rs @@ -0,0 +1,31 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +// Mappings for the contents of d2d1effects_1.h +DEFINE_GUID!{CLSID_D2D1YCbCr, + 0x99503cc1, 0x66c7, 0x45c9, 0xa8, 0x75, 0x8a, 0xd8, 0xa7, 0x91, 0x44, 0x01} +ENUM!{enum D2D1_YCBCR_PROP { + D2D1_YCBCR_PROP_CHROMA_SUBSAMPLING = 0, + D2D1_YCBCR_PROP_TRANSFORM_MATRIX = 1, + D2D1_YCBCR_PROP_INTERPOLATION_MODE = 2, + D2D1_YCBCR_PROP_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_YCBCR_CHROMA_SUBSAMPLING { + D2D1_YCBCR_CHROMA_SUBSAMPLING_AUTO = 0, + D2D1_YCBCR_CHROMA_SUBSAMPLING_420 = 1, + D2D1_YCBCR_CHROMA_SUBSAMPLING_422 = 2, + D2D1_YCBCR_CHROMA_SUBSAMPLING_444 = 3, + D2D1_YCBCR_CHROMA_SUBSAMPLING_440 = 4, + D2D1_YCBCR_CHROMA_SUBSAMPLING_FORCE_DWORD = 0xffffffff, +}} +ENUM!{enum D2D1_YCBCR_INTERPOLATION_MODE { + D2D1_YCBCR_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0, + D2D1_YCBCR_INTERPOLATION_MODE_LINEAR = 1, + D2D1_YCBCR_INTERPOLATION_MODE_CUBIC = 2, + D2D1_YCBCR_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3, + D2D1_YCBCR_INTERPOLATION_MODE_ANISOTROPIC = 4, + D2D1_YCBCR_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC = 5, + D2D1_YCBCR_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff, +}} diff --git a/winapi/src/um/d2d1effects_2.rs b/winapi/src/um/d2d1effects_2.rs new file mode 100644 index 000000000..40eea83a2 --- /dev/null +++ b/winapi/src/um/d2d1effects_2.rs @@ -0,0 +1,40 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1effects_2.h +DEFINE_GUID!{CLSID_D2D1Contrast, + 0xb648a78a, 0x0ed5, 0x4f80, 0xa9, 0x4a, 0x8e, 0x82, 0x5a, 0xca, 0x6b, 0x77} +DEFINE_GUID!{CLSID_D2D1RgbToHue, + 0x23f3e5ec, 0x91e8, 0x4d3d, 0xad, 0x0a, 0xaf, 0xad, 0xc1, 0x00, 0x4a, 0xa1} +DEFINE_GUID!{CLSID_D2D1HueToRgb, + 0x7b78a6bd, 0x0141, 0x4def, 0x8a, 0x52, 0x63, 0x56, 0xee, 0x0c, 0xbd, 0xd5} +DEFINE_GUID!{CLSID_D2D1ChromaKey, + 0x74c01f5b, 0x2a0d, 0x408c, 0x88, 0xe2, 0xc7, 0xa3, 0xc7, 0x19, 0x77, 0x42} +DEFINE_GUID!{CLSID_D2D1Emboss, + 0xb1c5eb2b, 0x0348, 0x43f0, 0x81, 0x07, 0x49, 0x57, 0xca, 0xcb, 0xa2, 0xae} +DEFINE_GUID!{CLSID_D2D1Exposure, + 0xb56c8cfa, 0xf634, 0x41ee, 0xbe, 0xe0, 0xff, 0xa6, 0x17, 0x10, 0x60, 0x04} +DEFINE_GUID!{CLSID_D2D1Grayscale, + 0x36dde0eb, 0x3725, 0x42e0, 0x83, 0x6d, 0x52, 0xfb, 0x20, 0xae, 0xe6, 0x44} +DEFINE_GUID!{CLSID_D2D1Invert, + 0xe0c3784d, 0xcb39, 0x4e84, 0xb6, 0xfd, 0x6b, 0x72, 0xf0, 0x81, 0x02, 0x63} +DEFINE_GUID!{CLSID_D2D1Posterize, + 0x2188945e, 0x33a3, 0x4366, 0xb7, 0xbc, 0x08, 0x6b, 0xd0, 0x2d, 0x08, 0x84} +DEFINE_GUID!{CLSID_D2D1Sepia, + 0x3a1af410, 0x5f1d, 0x4dbe, 0x84, 0xdf, 0x91, 0x5d, 0xa7, 0x9b, 0x71, 0x53} +DEFINE_GUID!{CLSID_D2D1Sharpen, + 0xc9b887cb, 0xc5ff, 0x4dc5, 0x97, 0x79, 0x27, 0x3d, 0xcf, 0x41, 0x7c, 0x7d} +DEFINE_GUID!{CLSID_D2D1Straighten, + 0x4da47b12, 0x79a3, 0x4fb0, 0x82, 0x37, 0xbb, 0xc3, 0xb2, 0xa4, 0xde, 0x08} +DEFINE_GUID!{CLSID_D2D1TemperatureTint, + 0x89176087, 0x8af9, 0x4a08, 0xae, 0xb1, 0x89, 0x5f, 0x38, 0xdb, 0x17, 0x66} +DEFINE_GUID!{CLSID_D2D1Vignette, + 0xc00c40be, 0x5e67, 0x4ca3, 0x95, 0xb4, 0xf4, 0xb0, 0x2c, 0x11, 0x51, 0x35} +DEFINE_GUID!{CLSID_D2D1EdgeDetection, + 0xeff583ca, 0xcb07, 0x4aa9, 0xac, 0x5d, 0x2c, 0xc4, 0x4c, 0x76, 0x46, 0x0f} +DEFINE_GUID!{CLSID_D2D1HighlightsShadows, + 0xcadc8384, 0x323f, 0x4c7e, 0xa3, 0x61, 0x2e, 0x2b, 0x24, 0xdf, 0x6e, 0xe4} +DEFINE_GUID!{CLSID_D2D1LookupTable3D, + 0x349e0eda, 0x0088, 0x4a79, 0x9c, 0xa3, 0xc7, 0xe3, 0x00, 0x20, 0x20, 0x20} diff --git a/winapi/src/um/d2d1svg.rs b/winapi/src/um/d2d1svg.rs new file mode 100644 index 000000000..33e133ebe --- /dev/null +++ b/winapi/src/um/d2d1svg.rs @@ -0,0 +1,411 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2d1svg.h +use ctypes::c_void; +use shared::basetsd::UINT32; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, FLOAT}; +use shared::ntdef::{PCWSTR, PWSTR, WCHAR}; +use shared::winerror::HRESULT; +use um::d2d1::{ + D2D1_CAP_STYLE_FLAT, D2D1_CAP_STYLE_ROUND, D2D1_CAP_STYLE_SQUARE, D2D1_COLOR_F, D2D1_FILL_MODE, + D2D1_LINE_JOIN_BEVEL, D2D1_LINE_JOIN_MITER_OR_BEVEL, D2D1_LINE_JOIN_ROUND, D2D1_POINT_2F, + D2D1_SIZE_F, ID2D1Resource, ID2D1ResourceVtbl +}; +use um::d2d1_1::ID2D1PathGeometry1; +use um::objidlbase::IStream; +ENUM!{enum D2D1_SVG_PAINT_TYPE { + D2D1_SVG_PAINT_TYPE_NONE = 0, + D2D1_SVG_PAINT_TYPE_COLOR = 1, + D2D1_SVG_PAINT_TYPE_CURRENT_COLOR = 2, + D2D1_SVG_PAINT_TYPE_URI = 3, + D2D1_SVG_PAINT_TYPE_URI_NONE = 4, + D2D1_SVG_PAINT_TYPE_URI_COLOR = 5, + D2D1_SVG_PAINT_TYPE_URI_CURRENT_COLOR = 6, +}} +ENUM!{enum D2D1_SVG_LENGTH_UNITS { + D2D1_SVG_LENGTH_UNITS_NUMBER = 0, + D2D1_SVG_LENGTH_UNITS_PERCENTAGE = 1, +}} +ENUM!{enum D2D1_SVG_DISPLAY { + D2D1_SVG_DISPLAY_INLINE = 0, + D2D1_SVG_DISPLAY_NONE = 1, +}} +ENUM!{enum D2D1_SVG_VISIBILITY { + D2D1_SVG_VISIBILITY_VISIBLE = 0, + D2D1_SVG_VISIBILITY_HIDDEN = 1, +}} +ENUM!{enum D2D1_SVG_OVERFLOW { + D2D1_SVG_OVERFLOW_VISIBLE = 0, + D2D1_SVG_OVERFLOW_HIDDEN = 1, +}} +ENUM!{enum D2D1_SVG_LINE_CAP { + D2D1_SVG_LINE_CAP_BUTT = D2D1_CAP_STYLE_FLAT, + D2D1_SVG_LINE_CAP_SQUARE = D2D1_CAP_STYLE_SQUARE, + D2D1_SVG_LINE_CAP_ROUND = D2D1_CAP_STYLE_ROUND, +}} +ENUM!{enum D2D1_SVG_LINE_JOIN { + D2D1_SVG_LINE_JOIN_BEVEL = D2D1_LINE_JOIN_BEVEL, + D2D1_SVG_LINE_JOIN_MITER = D2D1_LINE_JOIN_MITER_OR_BEVEL, + D2D1_SVG_LINE_JOIN_ROUND = D2D1_LINE_JOIN_ROUND, +}} +ENUM!{enum D2D1_SVG_ASPECT_ALIGN { + D2D1_SVG_ASPECT_ALIGN_NONE = 0, + D2D1_SVG_ASPECT_ALIGN_X_MIN_Y_MIN = 1, + D2D1_SVG_ASPECT_ALIGN_X_MID_Y_MIN = 2, + D2D1_SVG_ASPECT_ALIGN_X_MAX_Y_MIN = 3, + D2D1_SVG_ASPECT_ALIGN_X_MIN_Y_MID = 4, + D2D1_SVG_ASPECT_ALIGN_X_MID_Y_MID = 5, + D2D1_SVG_ASPECT_ALIGN_X_MAX_Y_MID = 6, + D2D1_SVG_ASPECT_ALIGN_X_MIN_Y_MAX = 7, + D2D1_SVG_ASPECT_ALIGN_X_MID_Y_MAX = 8, + D2D1_SVG_ASPECT_ALIGN_X_MAX_Y_MAX = 9, +}} +ENUM!{enum D2D1_SVG_ASPECT_SCALING { + D2D1_SVG_ASPECT_SCALING_MEET = 0, + D2D1_SVG_ASPECT_SCALING_SLICE = 1, +}} +ENUM!{enum D2D1_SVG_PATH_COMMAND { + D2D1_SVG_PATH_COMMAND_CLOSE_PATH = 0, + D2D1_SVG_PATH_COMMAND_MOVE_ABSOLUTE = 1, + D2D1_SVG_PATH_COMMAND_MOVE_RELATIVE = 2, + D2D1_SVG_PATH_COMMAND_LINE_ABSOLUTE = 3, + D2D1_SVG_PATH_COMMAND_LINE_RELATIVE = 4, + D2D1_SVG_PATH_COMMAND_CUBIC_ABSOLUTE = 5, + D2D1_SVG_PATH_COMMAND_CUBIC_RELATIVE = 6, + D2D1_SVG_PATH_COMMAND_QUADRADIC_ABSOLUTE = 7, + D2D1_SVG_PATH_COMMAND_QUADRADIC_RELATIVE = 8, + D2D1_SVG_PATH_COMMAND_ARC_ABSOLUTE = 9, + D2D1_SVG_PATH_COMMAND_ARC_RELATIVE = 10, + D2D1_SVG_PATH_COMMAND_HORIZONTAL_ABSOLUTE = 11, + D2D1_SVG_PATH_COMMAND_HORIZONTAL_RELATIVE = 12, + D2D1_SVG_PATH_COMMAND_VERTICAL_ABSOLUTE = 13, + D2D1_SVG_PATH_COMMAND_VERTICAL_RELATIVE = 14, + D2D1_SVG_PATH_COMMAND_CUBIC_SMOOTH_ABSOLUTE = 15, + D2D1_SVG_PATH_COMMAND_CUBIC_SMOOTH_RELATIVE = 16, + D2D1_SVG_PATH_COMMAND_QUADRADIC_SMOOTH_ABSOLUTE = 17, + D2D1_SVG_PATH_COMMAND_QUADRADIC_SMOOTH_RELATIVE = 18, +}} +ENUM!{enum D2D1_SVG_UNIT_TYPE { + D2D1_SVG_UNIT_TYPE_USER_SPACE_ON_USE = 0, + D2D1_SVG_UNIT_TYPE_OBJECT_BOUNDING_BOX = 1, +}} +ENUM!{enum D2D1_SVG_ATTRIBUTE_STRING_TYPE { + D2D1_SVG_ATTRIBUTE_STRING_TYPE_SVG = 0, + D2D1_SVG_ATTRIBUTE_STRING_TYPE_ID = 1, +}} +ENUM!{enum D2D1_SVG_ATTRIBUTE_POD_TYPE { + D2D1_SVG_ATTRIBUTE_POD_TYPE_FLOAT = 0, + D2D1_SVG_ATTRIBUTE_POD_TYPE_COLOR = 1, + D2D1_SVG_ATTRIBUTE_POD_TYPE_FILL_MODE = 2, + D2D1_SVG_ATTRIBUTE_POD_TYPE_DISPLAY = 3, + D2D1_SVG_ATTRIBUTE_POD_TYPE_OVERFLOW = 4, + D2D1_SVG_ATTRIBUTE_POD_TYPE_LINE_CAP = 5, + D2D1_SVG_ATTRIBUTE_POD_TYPE_LINE_JOIN = 6, + D2D1_SVG_ATTRIBUTE_POD_TYPE_VISIBILITY = 7, + D2D1_SVG_ATTRIBUTE_POD_TYPE_MATRIX = 8, + D2D1_SVG_ATTRIBUTE_POD_TYPE_UNIT_TYPE = 9, + D2D1_SVG_ATTRIBUTE_POD_TYPE_EXTEND_MODE = 10, + D2D1_SVG_ATTRIBUTE_POD_TYPE_PRESERVE_ASPECT_RATIO = 11, + D2D1_SVG_ATTRIBUTE_POD_TYPE_VIEWBOX = 12, + D2D1_SVG_ATTRIBUTE_POD_TYPE_LENGTH = 13, +}} +STRUCT!{struct D2D1_SVG_LENGTH { + value: FLOAT, + units: D2D1_SVG_LENGTH_UNITS, +}} +STRUCT!{struct D2D1_SVG_PRESERVE_ASPECT_RATIO { + defer: BOOL, + align: D2D1_SVG_ASPECT_ALIGN, + meetOrSlice: D2D1_SVG_ASPECT_SCALING, +}} +STRUCT!{struct D2D1_SVG_VIEWBOX { + x: FLOAT, + y: FLOAT, + width: FLOAT, + height: FLOAT, +}} +DEFINE_GUID!{IID_ID2D1SvgAttribute, + 0xc9cdb0dd, 0xf8c9, 0x4e70, 0xb7, 0xc2, 0x30, 0x1c, 0x80, 0x29, 0x2c, 0x5e} +DEFINE_GUID!{IID_ID2D1SvgPaint, + 0xd59bab0a, 0x68a2, 0x455b, 0xa5, 0xdc, 0x9e, 0xb2, 0x85, 0x4e, 0x24, 0x90} +DEFINE_GUID!{IID_ID2D1SvgStrokeDashArray, + 0xf1c0ca52, 0x92a3, 0x4f00, 0xb4, 0xce, 0xf3, 0x56, 0x91, 0xef, 0xd9, 0xd9} +DEFINE_GUID!{IID_ID2D1SvgPointCollection, + 0x9dbe4c0d, 0x3572, 0x4dd9, 0x98, 0x25, 0x55, 0x30, 0x81, 0x3b, 0xb7, 0x12} +DEFINE_GUID!{IID_ID2D1SvgPathData, + 0xc095e4f4, 0xbb98, 0x43d6, 0x97, 0x45, 0x4d, 0x1b, 0x84, 0xec, 0x98, 0x88} +DEFINE_GUID!{IID_ID2D1SvgElement, + 0xac7b67a6, 0x183e, 0x49c1, 0xa8, 0x23, 0x0e, 0xbe, 0x40, 0xb0, 0xdb, 0x29} +DEFINE_GUID!{IID_ID2D1SvgDocument, + 0x86b88e4d, 0xafa4, 0x4d7b, 0x88, 0xe4, 0x68, 0xa5, 0x1c, 0x4a, 0x0a, 0xec} +RIDL!{#[uuid(0xc9cdb0dd, 0xf8c9, 0x4e70, 0xb7, 0xc2, 0x30, 0x1c, 0x80, 0x29, 0x2c, 0x5e)] +interface ID2D1SvgAttribute(ID2D1SvgAttributeVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetElement( + element: *mut *mut ID2D1SvgElement, + ) -> (), + fn Clone( + attribute: *mut *mut ID2D1SvgAttribute, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd59bab0a, 0x68a2, 0x455b, 0xa5, 0xdc, 0x9e, 0xb2, 0x85, 0x4e, 0x24, 0x90)] +interface ID2D1SvgPaint(ID2D1SvgPaintVtbl): ID2D1SvgAttribute(ID2D1SvgAttributeVtbl) { + fn SetPaintType( + paintType: D2D1_SVG_PAINT_TYPE, + ) -> HRESULT, + fn GetPaintType() -> D2D1_SVG_PAINT_TYPE, + fn SetColor( + color: D2D1_COLOR_F, + ) -> HRESULT, + fn GetColor( + color: *mut D2D1_COLOR_F, + ) -> (), + fn SetId( + id: PCWSTR, + ) -> HRESULT, + fn GetId( + id: PWSTR, + idCount: UINT32, + ) -> HRESULT, + fn GetIdLength() -> UINT32, +}} +RIDL!{#[uuid(0xf1c0ca52, 0x92a3, 0x4f00, 0xb4, 0xce, 0xf3, 0x56, 0x91, 0xef, 0xd9, 0xd9)] +interface ID2D1SvgStrokeDashArray(ID2D1SvgStrokeDashArrayVtbl): + ID2D1SvgAttribute(ID2D1SvgAttributeVtbl) { + fn RemoveDashesAtEnd( + dashesCount: UINT32, + ) -> HRESULT, + fn UpdateDashes_1( + dashes: *const D2D1_SVG_LENGTH, + dashesCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn UpdateDashes_2( + dashes: *const FLOAT, + dashesCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetDashes_1( + dashes: *mut D2D1_SVG_LENGTH, + dashesCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetDashes_2( + dashes: *mut FLOAT, + dashesCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetDashesCount() -> UINT32, +}} +RIDL!{#[uuid(0x9dbe4c0d, 0x3572, 0x4dd9, 0x98, 0x25, 0x55, 0x30, 0x81, 0x3b, 0xb7, 0x12)] +interface ID2D1SvgPointCollection(ID2D1SvgPointCollectionVtbl): + ID2D1SvgAttribute(ID2D1SvgAttributeVtbl) { + fn RemovePointsAtEnd( + pointsCount: UINT32, + ) -> HRESULT, + fn UpdatePoints( + points: *const D2D1_POINT_2F, + pointsCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetPoints( + points: *mut D2D1_POINT_2F, + pointsCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetPointsCount() -> UINT32, +}} +RIDL!{#[uuid(0xc095e4f4, 0xbb98, 0x43d6, 0x97, 0x45, 0x4d, 0x1b, 0x84, 0xec, 0x98, 0x88)] +interface ID2D1SvgPathData(ID2D1SvgPathDataVtbl): ID2D1SvgAttribute(ID2D1SvgAttributeVtbl) { + fn RemoveSegmentDataAtEnd( + dataCount: UINT32, + ) -> HRESULT, + fn UpdateSegmentData( + data: *const FLOAT, + dataCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetSegmentData( + data: *mut FLOAT, + dataCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetSegmentDataCount() -> UINT32, + fn RemoveCommandsAtEnd( + commandsCount: UINT32, + ) -> HRESULT, + fn UpdateCommands( + commands: *const D2D1_SVG_PATH_COMMAND, + commandsCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetCommands( + commands: *mut D2D1_SVG_PATH_COMMAND, + commandsCount: UINT32, + startIndex: UINT32, + ) -> HRESULT, + fn GetCommandsCount() -> UINT32, + fn CreatePathGeometry( + fillMode: D2D1_FILL_MODE, + pathGeometry: *mut *mut ID2D1PathGeometry1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xac7b67a6, 0x183e, 0x49c1, 0xa8, 0x23, 0x0e, 0xbe, 0x40, 0xb0, 0xdb, 0x29)] +interface ID2D1SvgElement(ID2D1SvgElementVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn GetDocument( + document: *mut *mut ID2D1SvgDocument, + ) -> (), + fn GetTagName( + name: PWSTR, + nameCount: UINT32, + ) -> HRESULT, + fn GetTagNameLength() -> UINT32, + fn IsTextContent() -> BOOL, + fn GetParent( + parent: *mut *mut ID2D1SvgElement, + ) -> (), + fn HasChildren() -> BOOL, + fn GetFirstChild( + child: *mut *mut ID2D1SvgElement, + ) -> (), + fn GetLastChild( + child: *mut *mut ID2D1SvgElement, + ) -> (), + fn GetPreviousChild( + referenceChild: *mut ID2D1SvgElement, + previousChild: *mut *mut ID2D1SvgElement, + ) -> HRESULT, + fn GetNextChild( + referenceChild: *mut ID2D1SvgElement, + nextChild: *mut *mut ID2D1SvgElement, + ) -> HRESULT, + fn InsertChildBefore( + newChild: *mut ID2D1SvgElement, + referenceChild: *mut ID2D1SvgElement, + ) -> HRESULT, + fn AppendChild( + newChild: *mut ID2D1SvgElement, + ) -> HRESULT, + fn ReplaceChild( + newChild: *mut ID2D1SvgElement, + oldChild: *mut ID2D1SvgElement, + ) -> HRESULT, + fn RemoveChild( + oldChild: *mut ID2D1SvgElement, + ) -> HRESULT, + fn IsAttributeSpecified( + name: PCWSTR, inherited: *mut BOOL, + ) -> BOOL, + fn GetSpecifiedAttributeCount() -> UINT32, + fn GetSpecifiedAttributeName( + index: UINT32, + name: PWSTR, + nameCount: UINT32, + inherited: *mut BOOL, + ) -> HRESULT, + fn GetSpecifiedAttributeNameLength( + index: UINT32, + nameLength: *mut UINT32, + inherited: *mut BOOL, + ) -> HRESULT, + fn RemoveAttribute( + name: PCWSTR, + ) -> HRESULT, + fn SetTextValue( + name: *const WCHAR, + nameCount: UINT32, + ) -> HRESULT, + fn GetTextValue( + name: PWSTR, + nameCount: UINT32, + ) -> HRESULT, + fn GetTextValueLength() -> UINT32, + fn SetAttributeValue_1( + name: PCWSTR, + value: *mut ID2D1SvgAttribute, + ) -> HRESULT, + fn SetAttributeValue_2( + name: PCWSTR, + type_: D2D1_SVG_ATTRIBUTE_POD_TYPE, + value: *const c_void, + valueSizeInBytes: UINT32, + ) -> HRESULT, + fn SetAttributeValue_3( + name: PCWSTR, + type_: D2D1_SVG_ATTRIBUTE_STRING_TYPE, + value: PCWSTR, + ) -> HRESULT, + fn GetAttributeValue_1( + name: PCWSTR, + riid: REFIID, + value: *mut *mut c_void, + ) -> HRESULT, + fn GetAttributeValue_2( + name: PCWSTR, + type_: D2D1_SVG_ATTRIBUTE_POD_TYPE, + value: *mut c_void, + valueSizeInBytes: UINT32, + ) -> HRESULT, + fn GetAttributeValue_3( + name: PCWSTR, + type_: D2D1_SVG_ATTRIBUTE_STRING_TYPE, + value: PWSTR, + valueCount: UINT32, + ) -> HRESULT, + fn GetAttributeValueLength( + name: PCWSTR, + type_: D2D1_SVG_ATTRIBUTE_STRING_TYPE, + valueLength: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x86b88e4d, 0xafa4, 0x4d7b, 0x88, 0xe4, 0x68, 0xa5, 0x1c, 0x4a, 0x0a, 0xec)] +interface ID2D1SvgDocument(ID2D1SvgDocumentVtbl): ID2D1Resource(ID2D1ResourceVtbl) { + fn SetViewportSize( + viewportSize: D2D1_SIZE_F, + ) -> HRESULT, + fn GetViewportSize() -> D2D1_SIZE_F, + fn SetRoot( + root: *mut ID2D1SvgElement, + ) -> HRESULT, + fn GetRoot( + root: *mut *mut ID2D1SvgElement, + ) -> (), + fn FindElementById( + id: PCWSTR, + svgElement: *mut *mut ID2D1SvgElement, + ) -> HRESULT, + fn Serialize( + outputXmlStream: *mut IStream, + subtree: *mut ID2D1SvgElement, + ) -> HRESULT, + fn Deserialize( + inputXmlStream: *mut IStream, + subtree: *mut *mut ID2D1SvgElement, + ) -> HRESULT, + fn CreatePaint( + paintType: D2D1_SVG_PAINT_TYPE, + color: *const D2D1_COLOR_F, + id: PCWSTR, + paint: *mut *mut ID2D1SvgPaint, + ) -> HRESULT, + fn CreateStrokeDashArray( + dashes: *const D2D1_SVG_LENGTH, + dashesCount: UINT32, + strokeDashArray: *mut *mut ID2D1SvgStrokeDashArray, + ) -> HRESULT, + fn CreatePointCollection( + points: *const D2D1_POINT_2F, + pountsCount: UINT32, + pointCollection: *mut ID2D1SvgPointCollection, + ) -> HRESULT, + fn CreatePathData( + segmentData: *const FLOAT, + segmentDataCount: UINT32, + commands: *const D2D1_SVG_PATH_COMMAND, + commandsCount: UINT32, + pathData: *mut *mut ID2D1SvgPathData, + ) -> HRESULT, +}} diff --git a/winapi/src/um/d2dbasetypes.rs b/winapi/src/um/d2dbasetypes.rs new file mode 100644 index 000000000..754a05572 --- /dev/null +++ b/winapi/src/um/d2dbasetypes.rs @@ -0,0 +1,15 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d2dbasetypes.h +use shared::d3d9types::D3DCOLORVALUE; +// FIXME: Remove in next major version +pub use um::dcommon::{ + D2D1_MATRIX_3X2_F, D2D1_POINT_2F, D2D1_POINT_2L, D2D1_POINT_2U, D2D1_RECT_F, D2D1_RECT_L, + D2D1_RECT_U, D2D1_SIZE_F, D2D1_SIZE_U, D2D_MATRIX_3X2_F, D2D_MATRIX_4X3_F, D2D_MATRIX_4X4_F, + D2D_MATRIX_5X4_F, D2D_POINT_2F, D2D_POINT_2L, D2D_POINT_2U, D2D_RECT_F, D2D_RECT_L, D2D_RECT_U, + D2D_SIZE_F, D2D_SIZE_U, D2D_VECTOR_2F, D2D_VECTOR_3F, D2D_VECTOR_4F, +}; +pub type D2D_COLOR_F = D3DCOLORVALUE; diff --git a/winapi/src/um/d3d.rs b/winapi/src/um/d3d.rs new file mode 100644 index 000000000..e4b0250b6 --- /dev/null +++ b/winapi/src/um/d3d.rs @@ -0,0 +1,61 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_IDirect3D, + 0x3bba0080, 0x2421, 0x11cf, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirect3D2, + 0x6aae1ec1, 0x662a, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{IID_IDirect3D3, + 0xbb223240, 0xe72b, 0x11d0, 0xa9, 0xb4, 0x00, 0xaa, 0x00, 0xc0, 0x99, 0x3e} +DEFINE_GUID!{IID_IDirect3D7, + 0xf5049e77, 0x4861, 0x11d2, 0xa4, 0x07, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{IID_IDirect3DRampDevice, + 0xf2086b20, 0x259f, 0x11cf, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirect3DRGBDevice, + 0xa4665c60, 0x2673, 0x11cf, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirect3DHALDevice, + 0x84e63de0, 0x46aa, 0x11cf, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e} +DEFINE_GUID!{IID_IDirect3DMMXDevice, + 0x881949a1, 0xd6f3, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DRefDevice, + 0x50936643, 0x13e9, 0x11d1, 0x89, 0xaa, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DNullDevice, + 0x8767df22, 0xbacc, 0x11d1, 0x89, 0x69, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{IID_IDirect3DTnLHalDevice, + 0xf5049e78, 0x4861, 0x11d2, 0xa4, 0x07, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{IID_IDirect3DDevice, + 0x64108800, 0x957d, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DDevice2, + 0x93281501, 0x8cf8, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DDevice3, + 0xb0ab3b60, 0x33d7, 0x11d1, 0xa9, 0x81, 0x00, 0xc0, 0x4f, 0xd7, 0xb1, 0x74} +DEFINE_GUID!{IID_IDirect3DDevice7, + 0xf5049e79, 0x4861, 0x11d2, 0xa4, 0x07, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{IID_IDirect3DTexture, + 0x2cdcd9e0, 0x25a0, 0x11cf, 0xa3, 0x1a, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirect3DTexture2, + 0x93281502, 0x8cf8, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DLight, + 0x4417c142, 0x33ad, 0x11cf, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e} +DEFINE_GUID!{IID_IDirect3DMaterial, + 0x4417c144, 0x33ad, 0x11cf, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e} +DEFINE_GUID!{IID_IDirect3DIndexBuffer8, + 0x0e689c9a, 0x053d, 0x44a0, 0x9d, 0x92, 0xdb, 0x0e, 0x3d, 0x75, 0x0f, 0x86} +DEFINE_GUID!{IID_IDirect3DMaterial2, + 0x93281503, 0x8cf8, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DMaterial3, + 0xca9c46f4, 0xd3c5, 0x11d1, 0xb7, 0x5a, 0x00, 0x60, 0x08, 0x52, 0xb3, 0x12} +DEFINE_GUID!{IID_IDirect3DExecuteBuffer, + 0x4417c145, 0x33ad, 0x11cf, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e} +DEFINE_GUID!{IID_IDirect3DViewport, + 0x4417c146, 0x33ad, 0x11cf, 0x81, 0x6f, 0x00, 0x00, 0xc0, 0x20, 0x15, 0x6e} +DEFINE_GUID!{IID_IDirect3DViewport2, + 0x93281500, 0x8cf8, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirect3DViewport3, + 0xb0ab3b61, 0x33d7, 0x11d1, 0xa9, 0x81, 0x00, 0xc0, 0x4f, 0xd7, 0xb1, 0x74} +DEFINE_GUID!{IID_IDirect3DVertexBuffer, + 0x7a503555, 0x4a83, 0x11d1, 0xa5, 0xdb, 0x00, 0xa0, 0xc9, 0x03, 0x67, 0xf8} +DEFINE_GUID!{IID_IDirect3DVertexBuffer7, + 0xf5049e7d, 0x4861, 0x11d2, 0xa4, 0x07, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} diff --git a/winapi/src/um/d3d10.rs b/winapi/src/um/d3d10.rs new file mode 100644 index 000000000..887b7a344 --- /dev/null +++ b/winapi/src/um/d3d10.rs @@ -0,0 +1,57 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use um::d3dcommon::{D3D_PRIMITIVE, D3D_PRIMITIVE_TOPOLOGY, D3D_SRV_DIMENSION}; +pub type D3D10_PRIMITIVE_TOPOLOGY = D3D_PRIMITIVE_TOPOLOGY; +pub type D3D10_PRIMITIVE = D3D_PRIMITIVE; +pub type D3D10_SRV_DIMENSION = D3D_SRV_DIMENSION; +DEFINE_GUID!{IID_ID3D10DeviceChild, + 0x9b7e4c00, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10DepthStencilState, + 0x2b4b1cc8, 0xa4ad, 0x41f8, 0x83, 0x22, 0xca, 0x86, 0xfc, 0x3e, 0xc6, 0x75} +DEFINE_GUID!{IID_ID3D10BlendState, + 0xedad8d19, 0x8a35, 0x4d6d, 0x85, 0x66, 0x2e, 0xa2, 0x76, 0xcd, 0xe1, 0x61} +DEFINE_GUID!{IID_ID3D10RasterizerState, + 0xa2a07292, 0x89af, 0x4345, 0xbe, 0x2e, 0xc5, 0x3d, 0x9f, 0xbb, 0x6e, 0x9f} +DEFINE_GUID!{IID_ID3D10Resource, + 0x9b7e4c01, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Buffer, + 0x9b7e4c02, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Texture1D, + 0x9b7e4c03, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Texture2D, + 0x9b7e4c04, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Texture3D, + 0x9b7e4c05, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10View, + 0xc902b03f, 0x60a7, 0x49ba, 0x99, 0x36, 0x2a, 0x3a, 0xb3, 0x7a, 0x7e, 0x33} +DEFINE_GUID!{IID_ID3D10ShaderResourceView, + 0x9b7e4c07, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10RenderTargetView, + 0x9b7e4c08, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10DepthStencilView, + 0x9b7e4c09, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10VertexShader, + 0x9b7e4c0a, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10GeometryShader, + 0x6316be88, 0x54cd, 0x4040, 0xab, 0x44, 0x20, 0x46, 0x1b, 0xc8, 0x1f, 0x68} +DEFINE_GUID!{IID_ID3D10PixelShader, + 0x4968b601, 0x9d00, 0x4cde, 0x83, 0x46, 0x8e, 0x7f, 0x67, 0x58, 0x19, 0xb6} +DEFINE_GUID!{IID_ID3D10InputLayout, + 0x9b7e4c0b, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10SamplerState, + 0x9b7e4c0c, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Asynchronous, + 0x9b7e4c0d, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Query, + 0x9b7e4c0e, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Predicate, + 0x9b7e4c10, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Counter, + 0x9b7e4c11, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Device, + 0x9b7e4c0f, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Multithread, + 0x9b7e4e00, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} diff --git a/winapi/src/um/d3d10_1.rs b/winapi/src/um/d3d10_1.rs new file mode 100644 index 000000000..3765ce309 --- /dev/null +++ b/winapi/src/um/d3d10_1.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3D10BlendState1, + 0xedad8d99, 0x8a35, 0x4d6d, 0x85, 0x66, 0x2e, 0xa2, 0x76, 0xcd, 0xe1, 0x61} +DEFINE_GUID!{IID_ID3D10ShaderResourceView1, + 0x9b7e4c87, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10Device1, + 0x9b7e4c8f, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} diff --git a/winapi/src/um/d3d10_1shader.rs b/winapi/src/um/d3d10_1shader.rs new file mode 100644 index 000000000..69d9583ce --- /dev/null +++ b/winapi/src/um/d3d10_1shader.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3D10ShaderReflection1, + 0xc3457783, 0xa846, 0x47ce, 0x95, 0x20, 0xce, 0xa6, 0xf6, 0x6e, 0x74, 0x47} diff --git a/winapi/src/um/d3d10effect.rs b/winapi/src/um/d3d10effect.rs new file mode 100644 index 000000000..de93acec4 --- /dev/null +++ b/winapi/src/um/d3d10effect.rs @@ -0,0 +1,45 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3D10StateBlock, + 0x0803425a, 0x57f5, 0x4dd6, 0x94, 0x65, 0xa8, 0x75, 0x70, 0x83, 0x4a, 0x08} +DEFINE_GUID!{IID_ID3D10EffectType, + 0x4e9e1ddc, 0xcd9d, 0x4772, 0xa8, 0x37, 0x00, 0x18, 0x0b, 0x9b, 0x88, 0xfd} +DEFINE_GUID!{IID_ID3D10EffectVariable, + 0xae897105, 0x00e6, 0x45bf, 0xbb, 0x8e, 0x28, 0x1d, 0xd6, 0xdb, 0x8e, 0x1b} +DEFINE_GUID!{IID_ID3D10EffectScalarVariable, + 0x00e48f7b, 0xd2c8, 0x49e8, 0xa8, 0x6c, 0x02, 0x2d, 0xee, 0x53, 0x43, 0x1f} +DEFINE_GUID!{IID_ID3D10EffectVectorVariable, + 0x62b98c44, 0x1f82, 0x4c67, 0xbc, 0xd0, 0x72, 0xcf, 0x8f, 0x21, 0x7e, 0x81} +DEFINE_GUID!{IID_ID3D10EffectMatrixVariable, + 0x50666c24, 0xb82f, 0x4eed, 0xa1, 0x72, 0x5b, 0x6e, 0x7e, 0x85, 0x22, 0xe0} +DEFINE_GUID!{IID_ID3D10EffectStringVariable, + 0x71417501, 0x8df9, 0x4e0a, 0xa7, 0x8a, 0x25, 0x5f, 0x97, 0x56, 0xba, 0xff} +DEFINE_GUID!{IID_ID3D10EffectShaderResourceVariable, + 0xc0a7157b, 0xd872, 0x4b1d, 0x80, 0x73, 0xef, 0xc2, 0xac, 0xd4, 0xb1, 0xfc} +DEFINE_GUID!{IID_ID3D10EffectRenderTargetViewVariable, + 0x28ca0cc3, 0xc2c9, 0x40bb, 0xb5, 0x7f, 0x67, 0xb7, 0x37, 0x12, 0x2b, 0x17} +DEFINE_GUID!{IID_ID3D10EffectDepthStencilViewVariable, + 0x3e02c918, 0xcc79, 0x4985, 0xb6, 0x22, 0x2d, 0x92, 0xad, 0x70, 0x16, 0x23} +DEFINE_GUID!{IID_ID3D10EffectConstantBuffer, + 0x56648f4d, 0xcc8b, 0x4444, 0xa5, 0xad, 0xb5, 0xa3, 0xd7, 0x6e, 0x91, 0xb3} +DEFINE_GUID!{IID_ID3D10EffectShaderVariable, + 0x80849279, 0xc799, 0x4797, 0x8c, 0x33, 0x04, 0x07, 0xa0, 0x7d, 0x9e, 0x06} +DEFINE_GUID!{IID_ID3D10EffectBlendVariable, + 0x1fcd2294, 0xdf6d, 0x4eae, 0x86, 0xb3, 0x0e, 0x91, 0x60, 0xcf, 0xb0, 0x7b} +DEFINE_GUID!{IID_ID3D10EffectDepthStencilVariable, + 0xaf482368, 0x330a, 0x46a5, 0x9a, 0x5c, 0x01, 0xc7, 0x1a, 0xf2, 0x4c, 0x8d} +DEFINE_GUID!{IID_ID3D10EffectRasterizerVariable, + 0x21af9f0e, 0x4d94, 0x4ea9, 0x97, 0x85, 0x2c, 0xb7, 0x6b, 0x8c, 0x0b, 0x34} +DEFINE_GUID!{IID_ID3D10EffectSamplerVariable, + 0x6530d5c7, 0x07e9, 0x4271, 0xa4, 0x18, 0xe7, 0xce, 0x4b, 0xd1, 0xe4, 0x80} +DEFINE_GUID!{IID_ID3D10EffectPass, + 0x5cfbeb89, 0x1a06, 0x46e0, 0xb2, 0x82, 0xe3, 0xf9, 0xbf, 0xa3, 0x6a, 0x54} +DEFINE_GUID!{IID_ID3D10EffectTechnique, + 0xdb122ce8, 0xd1c9, 0x4292, 0xb2, 0x37, 0x24, 0xed, 0x3d, 0xe8, 0xb1, 0x75} +DEFINE_GUID!{IID_ID3D10Effect, + 0x51b0ca8b, 0xec0b, 0x4519, 0x87, 0x0d, 0x8e, 0xe1, 0xcb, 0x50, 0x17, 0xc7} +DEFINE_GUID!{IID_ID3D10EffectPool, + 0x9537ab04, 0x3250, 0x412e, 0x82, 0x13, 0xfc, 0xd2, 0xf8, 0x67, 0x79, 0x33} diff --git a/winapi/src/um/d3d10misc.rs b/winapi/src/um/d3d10misc.rs new file mode 100644 index 000000000..5303f2eb3 --- /dev/null +++ b/winapi/src/um/d3d10misc.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{GUID_DeviceType, + 0xd722fb4d, 0x7a68, 0x437a, 0xb2, 0x0c, 0x58, 0x04, 0xee, 0x24, 0x94, 0xa6} diff --git a/winapi/src/um/d3d10sdklayers.rs b/winapi/src/um/d3d10sdklayers.rs new file mode 100644 index 000000000..d71c483e4 --- /dev/null +++ b/winapi/src/um/d3d10sdklayers.rs @@ -0,0 +1,13 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{DXGI_DEBUG_D3D10, + 0x243b4c52, 0x3606, 0x4d3a, 0x99, 0xd7, 0xa7, 0xe7, 0xb3, 0x3e, 0xd7, 0x06} +DEFINE_GUID!{IID_ID3D10Debug, + 0x9b7e4e01, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10SwitchToRef, + 0x9b7e4e02, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0} +DEFINE_GUID!{IID_ID3D10InfoQueue, + 0x1b940b17, 0x2642, 0x4d1f, 0xab, 0x1f, 0xb9, 0x9b, 0xad, 0x0c, 0x39, 0x5f} diff --git a/winapi/src/um/d3d10shader.rs b/winapi/src/um/d3d10shader.rs new file mode 100644 index 000000000..952fd6dc2 --- /dev/null +++ b/winapi/src/um/d3d10shader.rs @@ -0,0 +1,206 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +use shared::minwindef::{BYTE, LPVOID, UINT}; +use um::d3d10::{D3D10_PRIMITIVE_TOPOLOGY, D3D10_SRV_DIMENSION}; +use um::d3dcommon::{ + D3D_CBUFFER_TYPE, D3D_INCLUDE_TYPE, D3D_NAME, D3D_REGISTER_COMPONENT_TYPE, + D3D_RESOURCE_RETURN_TYPE, D3D_SHADER_CBUFFER_FLAGS, D3D_SHADER_INPUT_FLAGS, + D3D_SHADER_INPUT_TYPE, D3D_SHADER_MACRO, D3D_SHADER_VARIABLE_CLASS, D3D_SHADER_VARIABLE_FLAGS, + D3D_SHADER_VARIABLE_TYPE, ID3DInclude, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +pub const D3D10_SHADER_DEBUG: UINT = 1 << 0; +pub const D3D10_SHADER_SKIP_VALIDATION: UINT = 1 << 1; +pub const D3D10_SHADER_SKIP_OPTIMIZATION: UINT = 1 << 2; +pub const D3D10_SHADER_PACK_MATRIX_ROW_MAJOR: UINT = 1 << 3; +pub const D3D10_SHADER_PACK_MATRIX_COLUMN_MAJOR: UINT = 1 << 4; +pub const D3D10_SHADER_PARTIAL_PRECISION: UINT = 1 << 5; +pub const D3D10_SHADER_FORCE_VS_SOFTWARE_NO_OPT: UINT = 1 << 6; +pub const D3D10_SHADER_FORCE_PS_SOFTWARE_NO_OPT: UINT = 1 << 7; +pub const D3D10_SHADER_NO_PRESHADER: UINT = 1 << 8; +pub const D3D10_SHADER_AVOID_FLOW_CONTROL: UINT = 1 << 9; +pub const D3D10_SHADER_PREFER_FLOW_CONTROL: UINT = 1 << 10; +pub const D3D10_SHADER_ENABLE_STRICTNESS: UINT = 1 << 11; +pub const D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY: UINT = 1 << 12; +pub const D3D10_SHADER_IEEE_STRICTNESS: UINT = 1 << 13; +pub const D3D10_SHADER_WARNINGS_ARE_ERRORS: UINT = 1 << 18; +pub const D3D10_SHADER_RESOURCES_MAY_ALIAS: UINT = 1 << 19; +pub const D3D10_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES: UINT = 1 << 20; +pub const D3D10_ALL_RESOURCES_BOUND: UINT = 1 << 21; +pub const D3D10_SHADER_OPTIMIZATION_LEVEL0: UINT = 1 << 14; +pub const D3D10_SHADER_OPTIMIZATION_LEVEL1: UINT = 0; +pub const D3D10_SHADER_OPTIMIZATION_LEVEL2: UINT = (1 << 14) | (1 << 15); +pub const D3D10_SHADER_OPTIMIZATION_LEVEL3: UINT = 1 << 15; +pub const D3D10_SHADER_FLAGS2_FORCE_ROOT_SIGNATURE_LATEST: UINT = 0; +pub const D3D10_SHADER_FLAGS2_FORCE_ROOT_SIGNATURE_1_0: UINT = 1 << 4; +pub const D3D10_SHADER_FLAGS2_FORCE_ROOT_SIGNATURE_1_1: UINT = 1 << 5; +pub type D3D10_SHADER_MACRO = D3D_SHADER_MACRO; +pub type LPD3D10_SHADER_MACRO = *mut D3D10_SHADER_MACRO; +pub type D3D10_SHADER_VARIABLE_CLASS = D3D_SHADER_VARIABLE_CLASS; +pub type LPD3D10_SHADER_VARIABLE_CLASS = *mut D3D10_SHADER_VARIABLE_CLASS; +pub type D3D10_SHADER_VARIABLE_FLAGS = D3D_SHADER_VARIABLE_FLAGS; +pub type LPD3D10_SHADER_VARIABLE_FLAGS = *mut D3D10_SHADER_VARIABLE_FLAGS; +pub type D3D10_SHADER_VARIABLE_TYPE = D3D_SHADER_VARIABLE_TYPE; +pub type LPD3D10_SHADER_VARIABLE_TYPE = *mut D3D10_SHADER_VARIABLE_TYPE; +pub type D3D10_SHADER_INPUT_FLAGS = D3D_SHADER_INPUT_FLAGS; +pub type LPD3D10_SHADER_INPUT_FLAGS = *mut D3D10_SHADER_INPUT_FLAGS; +pub type D3D10_SHADER_INPUT_TYPE = D3D_SHADER_INPUT_TYPE; +pub type LPD3D10_SHADER_INPUT_TYPE = *mut D3D10_SHADER_INPUT_TYPE; +pub type D3D10_SHADER_CBUFFER_FLAGS = D3D_SHADER_CBUFFER_FLAGS; +pub type LPD3D10_SHADER_CBUFFER_FLAGS = *mut D3D10_SHADER_CBUFFER_FLAGS; +pub type D3D10_CBUFFER_TYPE = D3D_CBUFFER_TYPE; +pub type LPD3D10_CBUFFER_TYPE = *mut D3D10_CBUFFER_TYPE; +pub type D3D10_NAME = D3D_NAME; +pub type D3D10_RESOURCE_RETURN_TYPE = D3D_RESOURCE_RETURN_TYPE; +pub type D3D10_REGISTER_COMPONENT_TYPE = D3D_REGISTER_COMPONENT_TYPE; +pub type D3D10_INCLUDE_TYPE = D3D_INCLUDE_TYPE; +pub type ID3D10Include = ID3DInclude; +pub type LPD3D10INCLUDE = *mut ID3DInclude; +// const IID_ID3D10Include: IID = IID_ID3DInclude; +STRUCT!{struct D3D10_SHADER_DESC { + Version: UINT, + Creator: LPCSTR, + Flags: UINT, + ConstantBuffers: UINT, + BoundResources: UINT, + InputParameters: UINT, + OutputParameters: UINT, + InstructionCount: UINT, + TempRegisterCount: UINT, + TempArrayCount: UINT, + DefCount: UINT, + DclCount: UINT, + TextureNormalInstructions: UINT, + TextureLoadInstructions: UINT, + TextureCompInstructions: UINT, + TextureBiasInstructions: UINT, + TextureGradientInstructions: UINT, + FloatInstructionCount: UINT, + IntInstructionCount: UINT, + UintInstructionCount: UINT, + StaticFlowControlCount: UINT, + DynamicFlowControlCount: UINT, + MacroInstructionCount: UINT, + ArrayInstructionCount: UINT, + CutInstructionCount: UINT, + EmitInstructionCount: UINT, + GSOutputTopology: D3D10_PRIMITIVE_TOPOLOGY, + GSMaxOutputVertexCount: UINT, +}} +STRUCT!{struct D3D10_SHADER_BUFFER_DESC { + Name: LPCSTR, + Type: D3D10_CBUFFER_TYPE, + Variables: UINT, + Size: UINT, + uFlags: UINT, +}} +STRUCT!{struct D3D10_SHADER_VARIABLE_DESC { + Name: LPCSTR, + StartOffset: UINT, + Size: UINT, + uFlags: UINT, + DefaultValue: LPVOID, +}} +STRUCT!{struct D3D10_SHADER_TYPE_DESC { + Class: D3D10_SHADER_VARIABLE_CLASS, + Type: D3D10_SHADER_VARIABLE_TYPE, + Rows: UINT, + Columns: UINT, + Elements: UINT, + Members: UINT, + Offset: UINT, +}} +STRUCT!{struct D3D10_SHADER_INPUT_BIND_DESC { + Name: LPCSTR, + Type: D3D10_SHADER_INPUT_TYPE, + BindPoint: UINT, + BindCount: UINT, + uFlags: UINT, + ReturnType: D3D10_RESOURCE_RETURN_TYPE, + Dimension: D3D10_SRV_DIMENSION, + NumSamples: UINT, +}} +STRUCT!{struct D3D10_SIGNATURE_PARAMETER_DESC { + SemanticName: LPCSTR, + SemanticIndex: UINT, + Register: UINT, + SystemValueType: D3D10_NAME, + ComponentType: D3D10_REGISTER_COMPONENT_TYPE, + Mask: BYTE, + ReadWriteMask: BYTE, +}} +pub type LPD3D10SHADERREFLECTIONTYPE = *mut ID3D10ShaderReflectionType; +DEFINE_GUID!{IID_ID3D10ShaderReflectionType, + 0xc530ad7d, 0x9b16, 0x4395, 0xa9, 0x79, 0xba, 0x2e, 0xcf, 0xf8, 0x3a, 0xdd} +RIDL!{#[uuid(0xc530ad7d, 0x9b16, 0x4395, 0xa9, 0x79, 0xba, 0x2e, 0xcf, 0xf8, 0x3a, 0xdd)] +interface ID3D10ShaderReflectionType(ID3D10ShaderReflectionTypeVtbl) { + fn GetDesc( + pDesc: *mut D3D10_SHADER_TYPE_DESC, + ) -> HRESULT, + fn GetMemberTypeByIndex( + Index: UINT, + ) -> *mut ID3D10ShaderReflectionType, + fn GetMemberTypeByName( + Name: LPCSTR, + ) -> *mut ID3D10ShaderReflectionType, + fn GetMemberTypeName( + Index: UINT, + ) -> LPCSTR, +}} +pub type LPD3D10SHADERREFLECTIONVARIABLE = *mut ID3D10ShaderReflectionVariable; +DEFINE_GUID!{IID_ID3D10ShaderReflectionVariable, + 0x1bf63c95, 0x2650, 0x405d, 0x99, 0xc1, 0x36, 0x36, 0xbd, 0x1d, 0xa0, 0xa1} +RIDL!{#[uuid(0x1bf63c95, 0x2650, 0x405d, 0x99, 0xc1, 0x36, 0x36, 0xbd, 0x1d, 0xa0, 0xa1)] +interface ID3D10ShaderReflectionVariable(ID3D10ShaderReflectionVariableVtbl) { + fn GetDesc( + pDesc: *mut D3D10_SHADER_VARIABLE_DESC, + ) -> HRESULT, + fn GetType() -> *mut ID3D10ShaderReflectionType, +}} +pub type LPD3D10SHADERREFLECTIONCONSTANTBUFFER = *mut ID3D10ShaderReflectionConstantBuffer; +DEFINE_GUID!{IID_ID3D10ShaderReflectionConstantBuffer, + 0x66c66a94, 0xdddd, 0x4b62, 0xa6, 0x6a, 0xf0, 0xda, 0x33, 0xc2, 0xb4, 0xd0} +RIDL!{#[uuid(0x66c66a94, 0xdddd, 0x4b62, 0xa6, 0x6a, 0xf0, 0xda, 0x33, 0xc2, 0xb4, 0xd0)] +interface ID3D10ShaderReflectionConstantBuffer(ID3D10ShaderReflectionConstantBufferVtbl) { + fn GetDesc( + pDesc: *mut D3D10_SHADER_BUFFER_DESC, + ) -> HRESULT, + fn GetVariableByIndex( + Index: UINT, + ) -> *mut ID3D10ShaderReflectionVariable, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D10ShaderReflectionVariable, +}} +pub type LPD3D10SHADERREFLECTION = *mut ID3D10ShaderReflection; +DEFINE_GUID!{IID_ID3D10ShaderReflection, + 0xd40e20b6, 0xf8f7, 0x42ad, 0xab, 0x20, 0x4b, 0xaf, 0x8f, 0x15, 0xdf, 0xaa} +RIDL!{#[uuid(0xd40e20b6, 0xf8f7, 0x42ad, 0xab, 0x20, 0x4b, 0xaf, 0x8f, 0x15, 0xdf, 0xaa)] +interface ID3D10ShaderReflection(ID3D10ShaderReflectionVtbl): IUnknown(IUnknownVtbl) { + fn GetDesc( + pDesc: *mut D3D10_SHADER_DESC, + ) -> HRESULT, + fn GetConstantBufferByIndex( + Index: UINT, + ) -> *mut ID3D10ShaderReflectionConstantBuffer, + fn GetConstantBufferByName( + Name: LPCSTR, + ) -> *mut ID3D10ShaderReflectionConstantBuffer, + fn GetResourceBindingDesc( + ResourceIndex: UINT, + pDesc: *mut D3D10_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetInputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D10_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetOutputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D10_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, +}} +// TODO Some functions diff --git a/winapi/src/um/d3d11.rs b/winapi/src/um/d3d11.rs new file mode 100644 index 000000000..d6e306a2b --- /dev/null +++ b/winapi/src/um/d3d11.rs @@ -0,0 +1,3420 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_float, c_int, c_long, c_void}; +use shared::basetsd::{SIZE_T, UINT64, UINT8}; +use shared::dxgi::{DXGI_SWAP_CHAIN_DESC, IDXGIAdapter, IDXGISwapChain}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::{DXGI_RATIONAL, DXGI_SAMPLE_DESC}; +use shared::guiddef::{GUID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, HMODULE, INT, UINT, USHORT}; +use shared::windef::{RECT, SIZE}; +use um::d3dcommon::{ + D3D_DRIVER_TYPE, D3D_FEATURE_LEVEL, D3D_PRIMITIVE, D3D_PRIMITIVE_TOPOLOGY, D3D_SRV_DIMENSION, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LPCSTR, LPSTR, ULONGLONG}; +pub const D3D11_16BIT_INDEX_STRIP_CUT_VALUE: DWORD = 0xffff; +pub const D3D11_32BIT_INDEX_STRIP_CUT_VALUE: DWORD = 0xffffffff; +pub const D3D11_8BIT_INDEX_STRIP_CUT_VALUE: DWORD = 0xff; +pub const D3D11_ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT: DWORD = 9; +pub const D3D11_CLIP_OR_CULL_DISTANCE_COUNT: DWORD = 8; +pub const D3D11_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT: DWORD = 2; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT: DWORD = 14; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_COMPONENTS: DWORD = 4; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT: DWORD = 15; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT: DWORD = 16; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT: DWORD = 15; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_COMMONSHADER_FLOWCONTROL_NESTING_LIMIT: DWORD = 64; +pub const D3D11_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT: DWORD = 1; +pub const D3D11_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT: DWORD = 128; +pub const D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT: DWORD = 128; +pub const D3D11_COMMONSHADER_SAMPLER_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_COMMONSHADER_SAMPLER_REGISTER_COUNT: DWORD = 16; +pub const D3D11_COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_COMMONSHADER_SAMPLER_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT: DWORD = 16; +pub const D3D11_COMMONSHADER_SUBROUTINE_NESTING_LIMIT: DWORD = 32; +pub const D3D11_COMMONSHADER_TEMP_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_COMMONSHADER_TEMP_REGISTER_COUNT: DWORD = 4096; +pub const D3D11_COMMONSHADER_TEMP_REGISTER_READS_PER_INST: DWORD = 3; +pub const D3D11_COMMONSHADER_TEMP_REGISTER_READ_PORTS: DWORD = 3; +pub const D3D11_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX: DWORD = 10; +pub const D3D11_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN: c_long = -10; +pub const D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE: c_long = -8; +pub const D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE: DWORD = 7; +pub const D3D11_CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 256; +pub const D3D11_CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP: DWORD = 64; +pub const D3D11_CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 240; +pub const D3D11_CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP: DWORD = 68; +pub const D3D11_CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 224; +pub const D3D11_CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP: DWORD = 72; +pub const D3D11_CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 208; +pub const D3D11_CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP: DWORD = 76; +pub const D3D11_CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 192; +pub const D3D11_CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP: DWORD = 84; +pub const D3D11_CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 176; +pub const D3D11_CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP: DWORD = 92; +pub const D3D11_CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 160; +pub const D3D11_CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP: DWORD = 100; +pub const D3D11_CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 144; +pub const D3D11_CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP: DWORD = 112; +pub const D3D11_CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 128; +pub const D3D11_CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP: DWORD = 128; +pub const D3D11_CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 112; +pub const D3D11_CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP: DWORD = 144; +pub const D3D11_CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 96; +pub const D3D11_CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP: DWORD = 168; +pub const D3D11_CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 80; +pub const D3D11_CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP: DWORD = 204; +pub const D3D11_CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 64; +pub const D3D11_CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP: DWORD = 256; +pub const D3D11_CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 48; +pub const D3D11_CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP: DWORD = 340; +pub const D3D11_CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 32; +pub const D3D11_CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP: DWORD = 512; +pub const D3D11_CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: DWORD = 16; +pub const D3D11_CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP: DWORD = 768; +pub const D3D11_CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION: DWORD = 1; +pub const D3D11_CS_4_X_RAW_UAV_BYTE_ALIGNMENT: DWORD = 256; +pub const D3D11_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP: DWORD = 768; +pub const D3D11_CS_4_X_THREAD_GROUP_MAX_X: DWORD = 768; +pub const D3D11_CS_4_X_THREAD_GROUP_MAX_Y: DWORD = 768; +pub const D3D11_CS_4_X_UAV_REGISTER_COUNT: DWORD = 1; +pub const D3D11_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION: DWORD = 65535; +pub const D3D11_CS_TGSM_REGISTER_COUNT: DWORD = 8192; +pub const D3D11_CS_TGSM_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_CS_TGSM_RESOURCE_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_CS_TGSM_RESOURCE_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_CS_THREADGROUPID_REGISTER_COMPONENTS: DWORD = 3; +pub const D3D11_CS_THREADGROUPID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT: DWORD = 1; +pub const D3D11_CS_THREADIDINGROUP_REGISTER_COMPONENTS: DWORD = 3; +pub const D3D11_CS_THREADIDINGROUP_REGISTER_COUNT: DWORD = 1; +pub const D3D11_CS_THREADID_REGISTER_COMPONENTS: DWORD = 3; +pub const D3D11_CS_THREADID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP: DWORD = 1024; +pub const D3D11_CS_THREAD_GROUP_MAX_X: DWORD = 1024; +pub const D3D11_CS_THREAD_GROUP_MAX_Y: DWORD = 1024; +pub const D3D11_CS_THREAD_GROUP_MAX_Z: DWORD = 64; +pub const D3D11_CS_THREAD_GROUP_MIN_X: DWORD = 1; +pub const D3D11_CS_THREAD_GROUP_MIN_Y: DWORD = 1; +pub const D3D11_CS_THREAD_GROUP_MIN_Z: DWORD = 1; +pub const D3D11_CS_THREAD_LOCAL_TEMP_REGISTER_POOL: DWORD = 16384; +pub const D3D11_DEFAULT_BLEND_FACTOR_ALPHA: FLOAT = 1.0; +pub const D3D11_DEFAULT_BLEND_FACTOR_BLUE: FLOAT = 1.0; +pub const D3D11_DEFAULT_BLEND_FACTOR_GREEN: FLOAT = 1.0; +pub const D3D11_DEFAULT_BLEND_FACTOR_RED: FLOAT = 1.0; +pub const D3D11_DEFAULT_BORDER_COLOR_COMPONENT: FLOAT = 0.0; +pub const D3D11_DEFAULT_DEPTH_BIAS: DWORD = 0; +pub const D3D11_DEFAULT_DEPTH_BIAS_CLAMP: FLOAT = 0.0; +pub const D3D11_DEFAULT_MAX_ANISOTROPY: DWORD = 16; +pub const D3D11_DEFAULT_MIP_LOD_BIAS: FLOAT = 0.0; +pub const D3D11_DEFAULT_RENDER_TARGET_ARRAY_INDEX: DWORD = 0; +pub const D3D11_DEFAULT_SAMPLE_MASK: DWORD = 0xffffffff; +pub const D3D11_DEFAULT_SCISSOR_ENDX: DWORD = 0; +pub const D3D11_DEFAULT_SCISSOR_ENDY: DWORD = 0; +pub const D3D11_DEFAULT_SCISSOR_STARTX: DWORD = 0; +pub const D3D11_DEFAULT_SCISSOR_STARTY: DWORD = 0; +pub const D3D11_DEFAULT_SLOPE_SCALED_DEPTH_BIAS: FLOAT = 0.0; +pub const D3D11_DEFAULT_STENCIL_READ_MASK: DWORD = 0xff; +pub const D3D11_DEFAULT_STENCIL_REFERENCE: DWORD = 0; +pub const D3D11_DEFAULT_STENCIL_WRITE_MASK: DWORD = 0xff; +pub const D3D11_DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX: DWORD = 0; +pub const D3D11_DEFAULT_VIEWPORT_HEIGHT: DWORD = 0; +pub const D3D11_DEFAULT_VIEWPORT_MAX_DEPTH: FLOAT = 0.0; +pub const D3D11_DEFAULT_VIEWPORT_MIN_DEPTH: FLOAT = 0.0; +pub const D3D11_DEFAULT_VIEWPORT_TOPLEFTX: DWORD = 0; +pub const D3D11_DEFAULT_VIEWPORT_TOPLEFTY: DWORD = 0; +pub const D3D11_DEFAULT_VIEWPORT_WIDTH: DWORD = 0; +pub const D3D11_DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS: DWORD = 3968; +pub const D3D11_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_CONTROL_POINT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS: DWORD = 3; +pub const D3D11_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_DOMAIN_POINT_REGISTER_COUNT: DWORD = 1; +pub const D3D11_DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_DS_OUTPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_DS_OUTPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_FLOAT16_FUSED_TOLERANCE_IN_ULP: FLOAT = 0.6; +pub const D3D11_FLOAT32_MAX: FLOAT = 3.402823466E+38; +pub const D3D11_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP: FLOAT = 0.6; +pub const D3D11_FLOAT_TO_SRGB_EXPONENT_DENOMINATOR: FLOAT = 2.4; +pub const D3D11_FLOAT_TO_SRGB_EXPONENT_NUMERATOR: FLOAT = 1.0; +pub const D3D11_FLOAT_TO_SRGB_OFFSET: FLOAT = 0.055; +pub const D3D11_FLOAT_TO_SRGB_SCALE_1: FLOAT = 12.92; +pub const D3D11_FLOAT_TO_SRGB_SCALE_2: FLOAT = 1.055; +pub const D3D11_FLOAT_TO_SRGB_THRESHOLD: FLOAT = 0.0031308; +pub const D3D11_FTOI_INSTRUCTION_MAX_INPUT: FLOAT = 2147483647.999; +pub const D3D11_FTOI_INSTRUCTION_MIN_INPUT: FLOAT = -2147483648.999; +pub const D3D11_FTOU_INSTRUCTION_MAX_INPUT: FLOAT = 4294967295.999; +pub const D3D11_FTOU_INSTRUCTION_MIN_INPUT: FLOAT = 0.0; +pub const D3D11_GS_INPUT_INSTANCE_ID_READS_PER_INST: DWORD = 2; +pub const D3D11_GS_INPUT_INSTANCE_ID_READ_PORTS: DWORD = 1; +pub const D3D11_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_GS_INPUT_INSTANCE_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_GS_INPUT_PRIM_CONST_REGISTER_COUNT: DWORD = 1; +pub const D3D11_GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_GS_INPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_GS_INPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_GS_INPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_GS_INPUT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_GS_INPUT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_GS_INPUT_REGISTER_VERTICES: DWORD = 32; +pub const D3D11_GS_MAX_INSTANCE_COUNT: DWORD = 32; +pub const D3D11_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES: DWORD = 1024; +pub const D3D11_GS_OUTPUT_ELEMENTS: DWORD = 32; +pub const D3D11_GS_OUTPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_GS_OUTPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_HS_CONTROL_POINT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_CONTROL_POINT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_CONTROL_POINT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND: DWORD = 0xffffffff; +pub const D3D11_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND: DWORD = 0xffffffff; +pub const D3D11_HS_MAXTESSFACTOR_LOWER_BOUND: FLOAT = 1.0; +pub const D3D11_HS_MAXTESSFACTOR_UPPER_BOUND: FLOAT = 64.0; +pub const D3D11_HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS: DWORD = 3968; +pub const D3D11_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT: DWORD = 1; +pub const D3D11_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS: DWORD = 128; +pub const D3D11_IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES: DWORD = 0; +pub const D3D11_IA_DEFAULT_PRIMITIVE_TOPOLOGY: DWORD = 0; +pub const D3D11_IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES: DWORD = 0; +pub const D3D11_IA_INDEX_INPUT_RESOURCE_SLOT_COUNT: DWORD = 1; +pub const D3D11_IA_INSTANCE_ID_BIT_COUNT: DWORD = 32; +pub const D3D11_IA_INTEGER_ARITHMETIC_BIT_COUNT: DWORD = 32; +pub const D3D11_IA_PATCH_MAX_CONTROL_POINT_COUNT: DWORD = 32; +pub const D3D11_IA_PRIMITIVE_ID_BIT_COUNT: DWORD = 32; +pub const D3D11_IA_VERTEX_ID_BIT_COUNT: DWORD = 32; +pub const D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT: DWORD = 32; +pub const D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS: DWORD = 128; +pub const D3D11_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT: DWORD = 32; +pub const D3D11_INTEGER_DIVIDE_BY_ZERO_QUOTIENT: DWORD = 0xffffffff; +pub const D3D11_INTEGER_DIVIDE_BY_ZERO_REMAINDER: DWORD = 0xffffffff; +pub const D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL: DWORD = 0xffffffff; +pub const D3D11_KEEP_UNORDERED_ACCESS_VIEWS: DWORD = 0xffffffff; +pub const D3D11_LINEAR_GAMMA: FLOAT = 1.0; +pub const D3D11_MAJOR_VERSION: DWORD = 11; +pub const D3D11_MAX_BORDER_COLOR_COMPONENT: FLOAT = 1.0; +pub const D3D11_MAX_DEPTH: FLOAT = 1.0; +pub const D3D11_MAX_MAXANISOTROPY: DWORD = 16; +pub const D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT: DWORD = 32; +pub const D3D11_MAX_POSITION_VALUE: FLOAT = 3.402823466E+34; +pub const D3D11_MAX_TEXTURE_DIMENSION_2_TO_EXP: DWORD = 17; +pub const D3D11_MINOR_VERSION: DWORD = 0; +pub const D3D11_MIN_BORDER_COLOR_COMPONENT: FLOAT = 0.0; +pub const D3D11_MIN_DEPTH: FLOAT = 0.0; +pub const D3D11_MIN_MAXANISOTROPY: DWORD = 0; +pub const D3D11_MIP_LOD_BIAS_MAX: FLOAT = 15.99; +pub const D3D11_MIP_LOD_BIAS_MIN: FLOAT = -16.0; +pub const D3D11_MIP_LOD_FRACTIONAL_BIT_COUNT: DWORD = 8; +pub const D3D11_MIP_LOD_RANGE_BIT_COUNT: DWORD = 8; +pub const D3D11_MULTISAMPLE_ANTIALIAS_LINE_WIDTH: FLOAT = 1.4; +pub const D3D11_NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT: DWORD = 0; +pub const D3D11_PIXEL_ADDRESS_RANGE_BIT_COUNT: DWORD = 15; +pub const D3D11_PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT: DWORD = 16; +pub const D3D11_PS_CS_UAV_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_PS_CS_UAV_REGISTER_COUNT: DWORD = 8; +pub const D3D11_PS_CS_UAV_REGISTER_READS_PER_INST: DWORD = 1; +pub const D3D11_PS_CS_UAV_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_PS_FRONTFACING_DEFAULT_VALUE: DWORD = 0xffffffff; +pub const D3D11_PS_FRONTFACING_FALSE_VALUE: DWORD = 0; +pub const D3D11_PS_FRONTFACING_TRUE_VALUE: DWORD = 0xffffffff; +pub const D3D11_PS_INPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_PS_INPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_PS_INPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_PS_INPUT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_PS_INPUT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT: FLOAT = 0.0; +pub const D3D11_PS_OUTPUT_DEPTH_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_PS_OUTPUT_DEPTH_REGISTER_COUNT: DWORD = 1; +pub const D3D11_PS_OUTPUT_MASK_REGISTER_COMPONENTS: DWORD = 1; +pub const D3D11_PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_PS_OUTPUT_MASK_REGISTER_COUNT: DWORD = 1; +pub const D3D11_PS_OUTPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_PS_OUTPUT_REGISTER_COUNT: DWORD = 8; +pub const D3D11_PS_PIXEL_CENTER_FRACTIONAL_COMPONENT: FLOAT = 0.5; +pub const D3D11_RAW_UAV_SRV_BYTE_ALIGNMENT: DWORD = 16; +pub const D3D11_REQ_BLEND_OBJECT_COUNT_PER_DEVICE: DWORD = 4096; +pub const D3D11_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP: DWORD = 27; +pub const D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT: DWORD = 4096; +pub const D3D11_REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE: DWORD = 4096; +pub const D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP: DWORD = 32; +pub const D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP: DWORD = 32; +pub const D3D11_REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION: DWORD = 16384; +pub const D3D11_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT: DWORD = 1024; +pub const D3D11_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT: DWORD = 4096; +pub const D3D11_REQ_MAXANISOTROPY: DWORD = 16; +pub const D3D11_REQ_MIP_LEVELS: DWORD = 15; +pub const D3D11_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES: DWORD = 2048; +pub const D3D11_REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE: DWORD = 4096; +pub const D3D11_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH: DWORD = 16384; +pub const D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM: DWORD = 128; +pub const D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM: FLOAT = 0.25; +pub const D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM: DWORD = 2048; +pub const D3D11_REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP: DWORD = 20; +pub const D3D11_REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE: DWORD = 4096; +pub const D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION: DWORD = 2048; +pub const D3D11_REQ_TEXTURE1D_U_DIMENSION: DWORD = 16384; +pub const D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION: DWORD = 2048; +pub const D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION: DWORD = 16384; +pub const D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION: DWORD = 2048; +pub const D3D11_REQ_TEXTURECUBE_DIMENSION: DWORD = 16384; +pub const D3D11_RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL: DWORD = 0; +pub const D3D11_SHADER_MAJOR_VERSION: DWORD = 5; +pub const D3D11_SHADER_MAX_INSTANCES: DWORD = 65535; +pub const D3D11_SHADER_MAX_INTERFACES: DWORD = 253; +pub const D3D11_SHADER_MAX_INTERFACE_CALL_SITES: DWORD = 4096; +pub const D3D11_SHADER_MAX_TYPES: DWORD = 65535; +pub const D3D11_SHADER_MINOR_VERSION: DWORD = 0; +pub const D3D11_SHIFT_INSTRUCTION_PAD_VALUE: DWORD = 0; +pub const D3D11_SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT: DWORD = 5; +pub const D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT: DWORD = 8; +pub const D3D11_SO_BUFFER_MAX_STRIDE_IN_BYTES: DWORD = 2048; +pub const D3D11_SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES: DWORD = 512; +pub const D3D11_SO_BUFFER_SLOT_COUNT: DWORD = 4; +pub const D3D11_SO_DDI_REGISTER_INDEX_DENOTING_GAP: DWORD = 0xffffffff; +pub const D3D11_SO_NO_RASTERIZED_STREAM: DWORD = 0xffffffff; +pub const D3D11_SO_OUTPUT_COMPONENT_COUNT: DWORD = 128; +pub const D3D11_SO_STREAM_COUNT: DWORD = 4; +pub const D3D11_SPEC_DATE_DAY: DWORD = 16; +pub const D3D11_SPEC_DATE_MONTH: DWORD = 0o5; +pub const D3D11_SPEC_DATE_YEAR: DWORD = 2011; +pub const D3D11_SPEC_VERSION: FLOAT = 1.07; +pub const D3D11_SRGB_GAMMA: FLOAT = 2.2; +pub const D3D11_SRGB_TO_FLOAT_DENOMINATOR_1: FLOAT = 12.92; +pub const D3D11_SRGB_TO_FLOAT_DENOMINATOR_2: FLOAT = 1.055; +pub const D3D11_SRGB_TO_FLOAT_EXPONENT: FLOAT = 2.4; +pub const D3D11_SRGB_TO_FLOAT_OFFSET: FLOAT = 0.055; +pub const D3D11_SRGB_TO_FLOAT_THRESHOLD: FLOAT = 0.04045; +pub const D3D11_SRGB_TO_FLOAT_TOLERANCE_IN_ULP: FLOAT = 0.5; +pub const D3D11_STANDARD_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_STANDARD_COMPONENT_BIT_COUNT_DOUBLED: DWORD = 64; +pub const D3D11_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE: DWORD = 4; +pub const D3D11_STANDARD_PIXEL_COMPONENT_COUNT: DWORD = 128; +pub const D3D11_STANDARD_PIXEL_ELEMENT_COUNT: DWORD = 32; +pub const D3D11_STANDARD_VECTOR_SIZE: DWORD = 4; +pub const D3D11_STANDARD_VERTEX_ELEMENT_COUNT: DWORD = 32; +pub const D3D11_STANDARD_VERTEX_TOTAL_COMPONENT_COUNT: DWORD = 64; +pub const D3D11_SUBPIXEL_FRACTIONAL_BIT_COUNT: DWORD = 8; +pub const D3D11_SUBTEXEL_FRACTIONAL_BIT_COUNT: DWORD = 8; +pub const D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR: DWORD = 64; +pub const D3D11_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR: DWORD = 64; +pub const D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR: DWORD = 63; +pub const D3D11_TESSELLATOR_MAX_TESSELLATION_FACTOR: DWORD = 64; +pub const D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR: DWORD = 2; +pub const D3D11_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR: DWORD = 1; +pub const D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR: DWORD = 1; +pub const D3D11_TEXEL_ADDRESS_RANGE_BIT_COUNT: DWORD = 16; +pub const D3D11_UNBOUND_MEMORY_ACCESS_RESULT: DWORD = 0; +pub const D3D11_VIEWPORT_AND_SCISSORRECT_MAX_INDEX: DWORD = 15; +pub const D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE: DWORD = 16; +pub const D3D11_VIEWPORT_BOUNDS_MAX: DWORD = 32767; +pub const D3D11_VIEWPORT_BOUNDS_MIN: c_long = -32768; +pub const D3D11_VS_INPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_VS_INPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_VS_INPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_VS_INPUT_REGISTER_READS_PER_INST: DWORD = 2; +pub const D3D11_VS_INPUT_REGISTER_READ_PORTS: DWORD = 1; +pub const D3D11_VS_OUTPUT_REGISTER_COMPONENTS: DWORD = 4; +pub const D3D11_VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: DWORD = 32; +pub const D3D11_VS_OUTPUT_REGISTER_COUNT: DWORD = 32; +pub const D3D11_WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT: DWORD = 10; +pub const D3D11_WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP: DWORD = 25; +pub const D3D11_WHQL_DRAW_VERTEX_COUNT_2_TO_EXP: DWORD = 25; +pub const D3D11_1_UAV_SLOT_COUNT: DWORD = 64; +pub const D3D11_2_TILED_RESOURCE_TILE_SIZE_IN_BYTES: DWORD = 65536; +ENUM!{enum D3D11_INPUT_CLASSIFICATION { + D3D11_INPUT_PER_VERTEX_DATA = 0, + D3D11_INPUT_PER_INSTANCE_DATA = 1, +}} +pub const D3D11_APPEND_ALIGNED_ELEMENT: DWORD = 0xffffffff; +STRUCT!{struct D3D11_INPUT_ELEMENT_DESC { + SemanticName: LPCSTR, + SemanticIndex: UINT, + Format: DXGI_FORMAT, + InputSlot: UINT, + AlignedByteOffset: UINT, + InputSlotClass: D3D11_INPUT_CLASSIFICATION, + InstanceDataStepRate: UINT, +}} +ENUM!{enum D3D11_FILL_MODE { + D3D11_FILL_WIREFRAME = 2, + D3D11_FILL_SOLID = 3, +}} +pub type D3D11_PRIMITIVE_TOPOLOGY = D3D_PRIMITIVE_TOPOLOGY; +pub type D3D11_PRIMITIVE = D3D_PRIMITIVE; +ENUM!{enum D3D11_CULL_MODE { + D3D11_CULL_NONE = 1, + D3D11_CULL_FRONT = 2, + D3D11_CULL_BACK = 3, +}} +STRUCT!{struct D3D11_SO_DECLARATION_ENTRY { + Stream: UINT, + SemanticName: LPCSTR, + SemanticIndex: UINT, + StartComponent: BYTE, + ComponentCount: BYTE, + OutputSlot: BYTE, +}} +STRUCT!{struct D3D11_VIEWPORT { + TopLeftX: FLOAT, + TopLeftY: FLOAT, + Width: FLOAT, + Height: FLOAT, + MinDepth: FLOAT, + MaxDepth: FLOAT, +}} +STRUCT!{struct D3D11_DRAW_INSTANCED_INDIRECT_ARGS { + VertexCountPerInstance: UINT, + InstanceCount: UINT, + StartVertexLocation: UINT, + StartInstanceLocation: UINT, +}} +STRUCT!{struct D3D11_DRAW_INDEXED_INSTANCED_INDIRECT_ARGS { + IndexCountPerInstance: UINT, + InstanceCount: UINT, + StartIndexLocation: UINT, + BaseVertexLocation: INT, + StartInstanceLocation: UINT, +}} +ENUM!{enum D3D11_RESOURCE_DIMENSION { + D3D11_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D11_RESOURCE_DIMENSION_BUFFER = 1, + D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4, +}} +pub type D3D11_SRV_DIMENSION = D3D_SRV_DIMENSION; +ENUM!{enum D3D11_DSV_DIMENSION { + D3D11_DSV_DIMENSION_UNKNOWN = 0, + D3D11_DSV_DIMENSION_TEXTURE1D = 1, + D3D11_DSV_DIMENSION_TEXTURE1DARRAY = 2, + D3D11_DSV_DIMENSION_TEXTURE2D = 3, + D3D11_DSV_DIMENSION_TEXTURE2DARRAY = 4, + D3D11_DSV_DIMENSION_TEXTURE2DMS = 5, + D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY = 6, +}} +ENUM!{enum D3D11_RTV_DIMENSION { + D3D11_RTV_DIMENSION_UNKNOWN = 0, + D3D11_RTV_DIMENSION_BUFFER = 1, + D3D11_RTV_DIMENSION_TEXTURE1D = 2, + D3D11_RTV_DIMENSION_TEXTURE1DARRAY = 3, + D3D11_RTV_DIMENSION_TEXTURE2D = 4, + D3D11_RTV_DIMENSION_TEXTURE2DARRAY = 5, + D3D11_RTV_DIMENSION_TEXTURE2DMS = 6, + D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY = 7, + D3D11_RTV_DIMENSION_TEXTURE3D = 8, +}} +ENUM!{enum D3D11_UAV_DIMENSION { + D3D11_UAV_DIMENSION_UNKNOWN = 0, + D3D11_UAV_DIMENSION_BUFFER = 1, + D3D11_UAV_DIMENSION_TEXTURE1D = 2, + D3D11_UAV_DIMENSION_TEXTURE1DARRAY = 3, + D3D11_UAV_DIMENSION_TEXTURE2D = 4, + D3D11_UAV_DIMENSION_TEXTURE2DARRAY = 5, + D3D11_UAV_DIMENSION_TEXTURE3D = 8, +}} +ENUM!{enum D3D11_USAGE { + D3D11_USAGE_DEFAULT = 0, + D3D11_USAGE_IMMUTABLE = 1, + D3D11_USAGE_DYNAMIC = 2, + D3D11_USAGE_STAGING = 3, +}} +ENUM!{enum D3D11_BIND_FLAG { + D3D11_BIND_VERTEX_BUFFER = 0x1, + D3D11_BIND_INDEX_BUFFER = 0x2, + D3D11_BIND_CONSTANT_BUFFER = 0x4, + D3D11_BIND_SHADER_RESOURCE = 0x8, + D3D11_BIND_STREAM_OUTPUT = 0x10, + D3D11_BIND_RENDER_TARGET = 0x20, + D3D11_BIND_DEPTH_STENCIL = 0x40, + D3D11_BIND_UNORDERED_ACCESS = 0x80, + D3D11_BIND_DECODER = 0x200, + D3D11_BIND_VIDEO_ENCODER = 0x400, +}} +ENUM!{enum D3D11_CPU_ACCESS_FLAG { + D3D11_CPU_ACCESS_WRITE = 0x10000, + D3D11_CPU_ACCESS_READ = 0x20000, +}} +ENUM!{enum D3D11_RESOURCE_MISC_FLAG { + D3D11_RESOURCE_MISC_GENERATE_MIPS = 0x1, + D3D11_RESOURCE_MISC_SHARED = 0x2, + D3D11_RESOURCE_MISC_TEXTURECUBE = 0x4, + D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS = 0x10, + D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS = 0x20, + D3D11_RESOURCE_MISC_BUFFER_STRUCTURED = 0x40, + D3D11_RESOURCE_MISC_RESOURCE_CLAMP = 0x80, + D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX = 0x100, + D3D11_RESOURCE_MISC_GDI_COMPATIBLE = 0x200, + D3D11_RESOURCE_MISC_SHARED_NTHANDLE = 0x800, + D3D11_RESOURCE_MISC_RESTRICTED_CONTENT = 0x1000, + D3D11_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE = 0x2000, + D3D11_RESOURCE_MISC_RESTRICT_SHARED_RESOURCE_DRIVER = 0x4000, + D3D11_RESOURCE_MISC_GUARDED = 0x8000, + D3D11_RESOURCE_MISC_TILE_POOL = 0x20000, + D3D11_RESOURCE_MISC_TILED = 0x40000, + D3D11_RESOURCE_MISC_HW_PROTECTED = 0x80000, +}} +ENUM!{enum D3D11_MAP { + D3D11_MAP_READ = 1, + D3D11_MAP_WRITE = 2, + D3D11_MAP_READ_WRITE = 3, + D3D11_MAP_WRITE_DISCARD = 4, + D3D11_MAP_WRITE_NO_OVERWRITE = 5, +}} +ENUM!{enum D3D11_MAP_FLAG { + D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000, +}} +ENUM!{enum D3D11_RAISE_FLAG { + D3D11_RAISE_FLAG_DRIVER_INTERNAL_ERROR = 0x1, +}} +ENUM!{enum D3D11_CLEAR_FLAG { + D3D11_CLEAR_DEPTH = 0x1, + D3D11_CLEAR_STENCIL = 0x2, +}} +pub type D3D11_RECT = RECT; +STRUCT!{struct D3D11_BOX { + left: UINT, + top: UINT, + front: UINT, + right: UINT, + bottom: UINT, + back: UINT, +}} +RIDL!{#[uuid(0x1841e5c8, 0x16b0, 0x489b, 0xbc, 0xc8, 0x44, 0xcf, 0xb0, 0xd5, 0xde, 0xae)] +interface ID3D11DeviceChild(ID3D11DeviceChildVtbl): IUnknown(IUnknownVtbl) { + fn GetDevice( + ppDevice: *mut *mut ID3D11Device, + ) -> (), + fn GetPrivateData( + guid: REFGUID, + pDataSize: *mut UINT, + pData: *mut c_void, + ) -> HRESULT, + fn SetPrivateData( + guid: REFGUID, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn SetPrivateDataInterface( + guid: REFGUID, + pData: *const IUnknown, + ) -> HRESULT, +}} +ENUM!{enum D3D11_COMPARISON_FUNC { + D3D11_COMPARISON_NEVER = 1, + D3D11_COMPARISON_LESS = 2, + D3D11_COMPARISON_EQUAL = 3, + D3D11_COMPARISON_LESS_EQUAL = 4, + D3D11_COMPARISON_GREATER = 5, + D3D11_COMPARISON_NOT_EQUAL = 6, + D3D11_COMPARISON_GREATER_EQUAL = 7, + D3D11_COMPARISON_ALWAYS = 8, +}} +ENUM!{enum D3D11_DEPTH_WRITE_MASK { + D3D11_DEPTH_WRITE_MASK_ZERO = 0, + D3D11_DEPTH_WRITE_MASK_ALL = 1, +}} +ENUM!{enum D3D11_STENCIL_OP { + D3D11_STENCIL_OP_KEEP = 1, + D3D11_STENCIL_OP_ZERO = 2, + D3D11_STENCIL_OP_REPLACE = 3, + D3D11_STENCIL_OP_INCR_SAT = 4, + D3D11_STENCIL_OP_DECR_SAT = 5, + D3D11_STENCIL_OP_INVERT = 6, + D3D11_STENCIL_OP_INCR = 7, + D3D11_STENCIL_OP_DECR = 8, +}} +STRUCT!{struct D3D11_DEPTH_STENCILOP_DESC { + StencilFailOp: D3D11_STENCIL_OP, + StencilDepthFailOp: D3D11_STENCIL_OP, + StencilPassOp: D3D11_STENCIL_OP, + StencilFunc: D3D11_COMPARISON_FUNC, +}} +STRUCT!{struct D3D11_DEPTH_STENCIL_DESC { + DepthEnable: BOOL, + DepthWriteMask: D3D11_DEPTH_WRITE_MASK, + DepthFunc: D3D11_COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: UINT8, + StencilWriteMask: UINT8, + FrontFace: D3D11_DEPTH_STENCILOP_DESC, + BackFace: D3D11_DEPTH_STENCILOP_DESC, +}} +RIDL!{#[uuid(0x03823efb, 0x8d8f, 0x4e1c, 0x9a, 0xa2, 0xf6, 0x4b, 0xb2, 0xcb, 0xfd, 0xf1)] +interface ID3D11DepthStencilState(ID3D11DepthStencilStateVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDesc( + pDesc: *mut D3D11_DEPTH_STENCIL_DESC, + ) -> (), +}} +ENUM!{enum D3D11_BLEND { + D3D11_BLEND_ZERO = 1, + D3D11_BLEND_ONE = 2, + D3D11_BLEND_SRC_COLOR = 3, + D3D11_BLEND_INV_SRC_COLOR = 4, + D3D11_BLEND_SRC_ALPHA = 5, + D3D11_BLEND_INV_SRC_ALPHA = 6, + D3D11_BLEND_DEST_ALPHA = 7, + D3D11_BLEND_INV_DEST_ALPHA = 8, + D3D11_BLEND_DEST_COLOR = 9, + D3D11_BLEND_INV_DEST_COLOR = 10, + D3D11_BLEND_SRC_ALPHA_SAT = 11, + D3D11_BLEND_BLEND_FACTOR = 14, + D3D11_BLEND_INV_BLEND_FACTOR = 15, + D3D11_BLEND_SRC1_COLOR = 16, + D3D11_BLEND_INV_SRC1_COLOR = 17, + D3D11_BLEND_SRC1_ALPHA = 18, + D3D11_BLEND_INV_SRC1_ALPHA = 19, +}} +ENUM!{enum D3D11_BLEND_OP { + D3D11_BLEND_OP_ADD = 1, + D3D11_BLEND_OP_SUBTRACT = 2, + D3D11_BLEND_OP_REV_SUBTRACT = 3, + D3D11_BLEND_OP_MIN = 4, + D3D11_BLEND_OP_MAX = 5, +}} +ENUM!{enum D3D11_COLOR_WRITE_ENABLE { + D3D11_COLOR_WRITE_ENABLE_RED = 1, + D3D11_COLOR_WRITE_ENABLE_GREEN = 2, + D3D11_COLOR_WRITE_ENABLE_BLUE = 4, + D3D11_COLOR_WRITE_ENABLE_ALPHA = 8, + D3D11_COLOR_WRITE_ENABLE_ALL = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN + | D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_ALPHA, +}} +STRUCT!{struct D3D11_RENDER_TARGET_BLEND_DESC { + BlendEnable: BOOL, + SrcBlend: D3D11_BLEND, + DestBlend: D3D11_BLEND, + BlendOp: D3D11_BLEND_OP, + SrcBlendAlpha: D3D11_BLEND, + DestBlendAlpha: D3D11_BLEND, + BlendOpAlpha: D3D11_BLEND_OP, + RenderTargetWriteMask: UINT8, +}} +STRUCT!{struct D3D11_BLEND_DESC { + AlphaToCoverageEnable: BOOL, + IndependentBlendEnable: BOOL, + RenderTarget: [D3D11_RENDER_TARGET_BLEND_DESC; 8], +}} +RIDL!{#[uuid(0x75b68faa, 0x347d, 0x4159, 0x8f, 0x45, 0xa0, 0x64, 0x0f, 0x01, 0xcd, 0x9a)] +interface ID3D11BlendState(ID3D11BlendStateVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDesc( + pDesc: *mut D3D11_BLEND_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_RASTERIZER_DESC { + FillMode: D3D11_FILL_MODE, + CullMode: D3D11_CULL_MODE, + FrontCounterClockwise: BOOL, + DepthBias: INT, + DepthBiasClamp: FLOAT, + SlopeScaledDepthBias: FLOAT, + DepthClipEnable: BOOL, + ScissorEnable: BOOL, + MultisampleEnable: BOOL, + AntialiasedLineEnable: BOOL, +}} +RIDL!{#[uuid(0x9bb4ab81, 0xab1a, 0x4d8f, 0xb5, 0x06, 0xfc, 0x04, 0x20, 0x0b, 0x6e, 0xe7)] +interface ID3D11RasterizerState(ID3D11RasterizerStateVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDesc( + pDesc: *mut D3D11_RASTERIZER_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_SUBRESOURCE_DATA { + pSysMem: *const c_void, + SysMemPitch: UINT, + SysMemSlicePitch: UINT, +}} +STRUCT!{struct D3D11_MAPPED_SUBRESOURCE { + pData: *mut c_void, + RowPitch: UINT, + DepthPitch: UINT, +}} +RIDL!{#[uuid(0xdc8e63f3, 0xd12b, 0x4952, 0xb4, 0x7b, 0x5e, 0x45, 0x02, 0x6a, 0x86, 0x2d)] +interface ID3D11Resource(ID3D11ResourceVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetType( + pResourceDimension: *mut D3D11_RESOURCE_DIMENSION, + ) -> (), + fn SetEvictionPriority( + EvictionPriority: UINT, + ) -> (), + fn GetEvictionPriority() -> UINT, +}} +STRUCT!{struct D3D11_BUFFER_DESC { + ByteWidth: UINT, + Usage: D3D11_USAGE, + BindFlags: UINT, + CPUAccessFlags: UINT, + MiscFlags: UINT, + StructureByteStride: UINT, +}} +RIDL!{#[uuid(0x48570b85, 0xd1ee, 0x4fcd, 0xa2, 0x50, 0xeb, 0x35, 0x07, 0x22, 0xb0, 0x37)] +interface ID3D11Buffer(ID3D11BufferVtbl): ID3D11Resource(ID3D11ResourceVtbl) { + fn GetDesc( + pDesc: *mut D3D11_BUFFER_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_TEXTURE1D_DESC { + Width: UINT, + MipLevels: UINT, + ArraySize: UINT, + Format: DXGI_FORMAT, + Usage: D3D11_USAGE, + BindFlags: UINT, + CPUAccessFlags: UINT, + MiscFlags: UINT, +}} +RIDL!{#[uuid(0xf8fb5c27, 0xc6b3, 0x4f75, 0xa4, 0xc8, 0x43, 0x9a, 0xf2, 0xef, 0x56, 0x4c)] +interface ID3D11Texture1D(ID3D11Texture1DVtbl): ID3D11Resource(ID3D11ResourceVtbl) { + fn GetDesc( + pDesc: *mut D3D11_TEXTURE1D_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_TEXTURE2D_DESC { + Width: UINT, + Height: UINT, + MipLevels: UINT, + ArraySize: UINT, + Format: DXGI_FORMAT, + SampleDesc: DXGI_SAMPLE_DESC, + Usage: D3D11_USAGE, + BindFlags: UINT, + CPUAccessFlags: UINT, + MiscFlags: UINT, +}} +RIDL!{#[uuid(0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c)] +interface ID3D11Texture2D(ID3D11Texture2DVtbl): ID3D11Resource(ID3D11ResourceVtbl) { + fn GetDesc( + pDesc: *mut D3D11_TEXTURE2D_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_TEXTURE3D_DESC { + Width: UINT, + Height: UINT, + Depth: UINT, + MipLevels: UINT, + Format: DXGI_FORMAT, + Usage: D3D11_USAGE, + BindFlags: UINT, + CPUAccessFlags: UINT, + MiscFlags: UINT, +}} +RIDL!{#[uuid(0x037e866e, 0xf56d, 0x4357, 0xa8, 0xaf, 0x9d, 0xab, 0xbe, 0x6e, 0x25, 0x0e)] +interface ID3D11Texture3D(ID3D11Texture3DVtbl): ID3D11Resource(ID3D11ResourceVtbl) { + fn GetDesc( + pDesc: *mut D3D11_TEXTURE3D_DESC, + ) -> (), +}} +ENUM!{enum D3D11_TEXTURECUBE_FACE { + D3D11_TEXTURECUBE_FACE_POSITIVE_X = 0, + D3D11_TEXTURECUBE_FACE_NEGATIVE_X = 1, + D3D11_TEXTURECUBE_FACE_POSITIVE_Y = 2, + D3D11_TEXTURECUBE_FACE_NEGATIVE_Y = 3, + D3D11_TEXTURECUBE_FACE_POSITIVE_Z = 4, + D3D11_TEXTURECUBE_FACE_NEGATIVE_Z = 5, +}} +RIDL!{#[uuid(0x839d1216, 0xbb2e, 0x412b, 0xb7, 0xf4, 0xa9, 0xdb, 0xeb, 0xe0, 0x8e, 0xd1)] +interface ID3D11View(ID3D11ViewVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetResource( + ppResource: *mut *mut ID3D11Resource, + ) -> (), +}} +UNION!{union D3D11_BUFFER_SRV_u1 { + [u32; 1], + FirstElement FirstElement_mut: UINT, + ElementOffset ElementOffset_mut: UINT, +}} +UNION!{union D3D11_BUFFER_SRV_u2 { + [u32; 1], + NumElements NumElements_mut: UINT, + ElementWidth ElementWidth_mut: UINT, +}} +STRUCT!{struct D3D11_BUFFER_SRV { + u1: D3D11_BUFFER_SRV_u1, + u2: D3D11_BUFFER_SRV_u2, +}} +ENUM!{enum D3D11_BUFFEREX_SRV_FLAG { + D3D11_BUFFEREX_SRV_FLAG_RAW = 0x1, +}} +STRUCT!{struct D3D11_BUFFEREX_SRV { + FirstElement: UINT, + NumElements: UINT, + Flags: UINT, +}} +STRUCT!{struct D3D11_TEX1D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, +}} +STRUCT!{struct D3D11_TEX1D_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, +}} +STRUCT!{struct D3D11_TEX2D_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX3D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, +}} +STRUCT!{struct D3D11_TEXCUBE_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, +}} +STRUCT!{struct D3D11_TEXCUBE_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + First2DArrayFace: UINT, + NumCubes: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_SRV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_ARRAY_SRV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +UNION!{union D3D11_SHADER_RESOURCE_VIEW_DESC_u { + [u32; 4], + Buffer Buffer_mut: D3D11_BUFFER_SRV, + Texture1D Texture1D_mut: D3D11_TEX1D_SRV, + Texture1DArray Texture1DArray_mut: D3D11_TEX1D_ARRAY_SRV, + Texture2D Texture2D_mut: D3D11_TEX2D_SRV, + Texture2DArray Texture2DArray_mut: D3D11_TEX2D_ARRAY_SRV, + Texture2DMS Texture2DMS_mut: D3D11_TEX2DMS_SRV, + Texture2DMSArray Texture2DMSArray_mut: D3D11_TEX2DMS_ARRAY_SRV, + Texture3D Texture3D_mut: D3D11_TEX3D_SRV, + TextureCube TextureCube_mut: D3D11_TEXCUBE_SRV, + TextureCubeArray TextureCubeArray_mut: D3D11_TEXCUBE_ARRAY_SRV, + BufferEx BufferEx_mut: D3D11_BUFFEREX_SRV, +}} +STRUCT!{struct D3D11_SHADER_RESOURCE_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D11_SRV_DIMENSION, + u: D3D11_SHADER_RESOURCE_VIEW_DESC_u, +}} +RIDL!{#[uuid(0xb0e06fe0, 0x8192, 0x4e1a, 0xb1, 0xca, 0x36, 0xd7, 0x41, 0x47, 0x10, 0xb2)] +interface ID3D11ShaderResourceView(ID3D11ShaderResourceViewVtbl): ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SHADER_RESOURCE_VIEW_DESC, + ) -> (), +}} +UNION!{union D3D11_BUFFER_RTV_u1 { + [u32; 1], + FirstElement FirstElement_mut: UINT, + ElementOffset ElementOffset_mut: UINT, +}} +UNION!{union D3D11_BUFFER_RTV_u2 { + [u32; 1], + NumElements NumElements_mut: UINT, + ElementWidth ElementWidth_mut: UINT, +}} +STRUCT!{struct D3D11_BUFFER_RTV { + u1: D3D11_BUFFER_RTV_u1, + u2: D3D11_BUFFER_RTV_u2, +}} +STRUCT!{struct D3D11_TEX1D_RTV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX1D_ARRAY_RTV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2D_RTV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_RTV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D11_TEX2D_ARRAY_RTV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_ARRAY_RTV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX3D_RTV { + MipSlice: UINT, + FirstWSlice: UINT, + WSize: UINT, +}} +UNION!{union D3D11_RENDER_TARGET_VIEW_DESC_u { + [u32; 3], + Buffer Buffer_mut: D3D11_BUFFER_RTV, + Texture1D Texture1D_mut: D3D11_TEX1D_RTV, + Texture1DArray Texture1DArray_mut: D3D11_TEX1D_ARRAY_RTV, + Texture2D Texture2D_mut: D3D11_TEX2D_RTV, + Texture2DArray Texture2DArray_mut: D3D11_TEX2D_ARRAY_RTV, + Texture2DMS Texture2DMS_mut: D3D11_TEX2DMS_RTV, + Texture2DMSArray Texture2DMSArray_mut: D3D11_TEX2DMS_ARRAY_RTV, + Texture3D Texture3D_mut: D3D11_TEX3D_RTV, +}} +STRUCT!{struct D3D11_RENDER_TARGET_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D11_RTV_DIMENSION, + u: D3D11_RENDER_TARGET_VIEW_DESC_u, +}} +RIDL!{#[uuid(0xdfdba067, 0x0b8d, 0x4865, 0x87, 0x5b, 0xd7, 0xb4, 0x51, 0x6c, 0xc1, 0x64)] +interface ID3D11RenderTargetView(ID3D11RenderTargetViewVtbl): ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_RENDER_TARGET_VIEW_DESC, + ) -> (), +}} +STRUCT!{struct D3D11_TEX1D_DSV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX1D_ARRAY_DSV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2D_DSV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX2D_ARRAY_DSV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_DSV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D11_TEX2DMS_ARRAY_DSV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +ENUM!{enum D3D11_DSV_FLAG { + D3D11_DSV_READ_ONLY_DEPTH = 0x1, + D3D11_DSV_READ_ONLY_STENCIL = 0x2, +}} +UNION!{union D3D11_DEPTH_STENCIL_VIEW_DESC_u { + [u32; 3], + Texture1D Texture1D_mut: D3D11_TEX1D_DSV, + Texture1DArray Texture1DArray_mut: D3D11_TEX1D_ARRAY_DSV, + Texture2D Texture2D_mut: D3D11_TEX2D_DSV, + Texture2DArray Texture2DArray_mut: D3D11_TEX2D_ARRAY_DSV, + Texture2DMS Texture2DMS_mut: D3D11_TEX2DMS_DSV, + Texture2DMSArray Texture2DMSArray_mut: D3D11_TEX2DMS_ARRAY_DSV, +}} +STRUCT!{struct D3D11_DEPTH_STENCIL_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D11_DSV_DIMENSION, + Flags: UINT, + u: D3D11_DEPTH_STENCIL_VIEW_DESC_u, +}} +RIDL!{#[uuid(0x9fdac92a, 0x1876, 0x48c3, 0xaf, 0xad, 0x25, 0xb9, 0x4f, 0x84, 0xa9, 0xb6)] +interface ID3D11DepthStencilView(ID3D11DepthStencilViewVtbl): ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_DEPTH_STENCIL_VIEW_DESC, + ) -> (), +}} +ENUM!{enum D3D11_BUFFER_UAV_FLAG { + D3D11_BUFFER_UAV_FLAG_RAW = 0x1, + D3D11_BUFFER_UAV_FLAG_APPEND = 0x2, + D3D11_BUFFER_UAV_FLAG_COUNTER = 0x4, +}} +STRUCT!{struct D3D11_BUFFER_UAV { + FirstElement: UINT, + NumElements: UINT, + Flags: UINT, +}} +STRUCT!{struct D3D11_TEX1D_UAV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX1D_ARRAY_UAV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX2D_UAV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX2D_ARRAY_UAV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D11_TEX3D_UAV { + MipSlice: UINT, + FirstWSlice: UINT, + WSize: UINT, +}} +UNION!{union D3D11_UNORDERED_ACCESS_VIEW_DESC_u { + [u32; 3], + Buffer Buffer_mut: D3D11_BUFFER_UAV, + Texture1D Texture1D_mut: D3D11_TEX1D_UAV, + Texture1DArray Texture1DArray_mut: D3D11_TEX1D_ARRAY_UAV, + Texture2D Texture2D_mut: D3D11_TEX2D_UAV, + Texture2DArray Texture2DArray_mut: D3D11_TEX2D_ARRAY_UAV, + Texture3D Texture3D_mut: D3D11_TEX3D_UAV, +}} +STRUCT!{struct D3D11_UNORDERED_ACCESS_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D11_UAV_DIMENSION, + u: D3D11_UNORDERED_ACCESS_VIEW_DESC_u, +}} +RIDL!{#[uuid(0x28acf509, 0x7f5c, 0x48f6, 0x86, 0x11, 0xf3, 0x16, 0x01, 0x0a, 0x63, 0x80)] +interface ID3D11UnorderedAccessView(ID3D11UnorderedAccessViewVtbl): ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_UNORDERED_ACCESS_VIEW_DESC, + ) -> (), +}} +RIDL!{#[uuid(0x3b301d64, 0xd678, 0x4289, 0x88, 0x97, 0x22, 0xf8, 0x92, 0x8b, 0x72, 0xf3)] +interface ID3D11VertexShader(ID3D11VertexShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0x8e5c6061, 0x628a, 0x4c8e, 0x82, 0x64, 0xbb, 0xe4, 0x5c, 0xb3, 0xd5, 0xdd)] +interface ID3D11HullShader(ID3D11HullShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0xf582c508, 0x0f36, 0x490c, 0x99, 0x77, 0x31, 0xee, 0xce, 0x26, 0x8c, 0xfa)] +interface ID3D11DomainShader(ID3D11DomainShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0x38325b96, 0xeffb, 0x4022, 0xba, 0x02, 0x2e, 0x79, 0x5b, 0x70, 0x27, 0x5c)] +interface ID3D11GeometryShader(ID3D11GeometryShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0xea82e40d, 0x51dc, 0x4f33, 0x93, 0xd4, 0xdb, 0x7c, 0x91, 0x25, 0xae, 0x8c)] +interface ID3D11PixelShader(ID3D11PixelShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0x4f5b196e, 0xc2bd, 0x495e, 0xbd, 0x01, 0x1f, 0xde, 0xd3, 0x8e, 0x49, 0x69)] +interface ID3D11ComputeShader(ID3D11ComputeShaderVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0xe4819ddc, 0x4cf0, 0x4025, 0xbd, 0x26, 0x5d, 0xe8, 0x2a, 0x3e, 0x07, 0xb7)] +interface ID3D11InputLayout(ID3D11InputLayoutVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +ENUM!{enum D3D11_FILTER { + D3D11_FILTER_MIN_MAG_MIP_POINT = 0, + D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1, + D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4, + D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5, + D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10, + D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11, + D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14, + D3D11_FILTER_MIN_MAG_MIP_LINEAR = 0x15, + D3D11_FILTER_ANISOTROPIC = 0x55, + D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80, + D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81, + D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84, + D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85, + D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90, + D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91, + D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94, + D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95, + D3D11_FILTER_COMPARISON_ANISOTROPIC = 0xd5, + D3D11_FILTER_MINIMUM_MIN_MAG_MIP_POINT = 0x100, + D3D11_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x101, + D3D11_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x104, + D3D11_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x105, + D3D11_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x110, + D3D11_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x111, + D3D11_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x114, + D3D11_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR = 0x115, + D3D11_FILTER_MINIMUM_ANISOTROPIC = 0x155, + D3D11_FILTER_MAXIMUM_MIN_MAG_MIP_POINT = 0x180, + D3D11_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x181, + D3D11_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x184, + D3D11_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x185, + D3D11_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x190, + D3D11_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x191, + D3D11_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x194, + D3D11_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR = 0x195, + D3D11_FILTER_MAXIMUM_ANISOTROPIC = 0x1d5, +}} +ENUM!{enum D3D11_FILTER_TYPE { + D3D11_FILTER_TYPE_POINT = 0, + D3D11_FILTER_TYPE_LINEAR = 1, +}} +ENUM!{enum D3D11_FILTER_REDUCTION_TYPE { + D3D11_FILTER_REDUCTION_TYPE_STANDARD = 0, + D3D11_FILTER_REDUCTION_TYPE_COMPARISON = 1, + D3D11_FILTER_REDUCTION_TYPE_MINIMUM = 2, + D3D11_FILTER_REDUCTION_TYPE_MAXIMUM = 3, +}} +pub const D3D11_FILTER_REDUCTION_TYPE_MASK: DWORD = 0x3; +pub const D3D11_FILTER_REDUCTION_TYPE_SHIFT: DWORD = 7; +pub const D3D11_FILTER_TYPE_MASK: DWORD = 0x3; +pub const D3D11_MIN_FILTER_SHIFT: DWORD = 4; +pub const D3D11_MAG_FILTER_SHIFT: DWORD = 2; +pub const D3D11_MIP_FILTER_SHIFT: DWORD = 0; +pub const D3D11_COMPARISON_FILTERING_BIT: DWORD = 0x80; +pub const D3D11_ANISOTROPIC_FILTERING_BIT: DWORD = 0x40; +ENUM!{enum D3D11_TEXTURE_ADDRESS_MODE { + D3D11_TEXTURE_ADDRESS_WRAP = 1, + D3D11_TEXTURE_ADDRESS_MIRROR = 2, + D3D11_TEXTURE_ADDRESS_CLAMP = 3, + D3D11_TEXTURE_ADDRESS_BORDER = 4, + D3D11_TEXTURE_ADDRESS_MIRROR_ONCE = 5, +}} +STRUCT!{struct D3D11_SAMPLER_DESC { + Filter: D3D11_FILTER, + AddressU: D3D11_TEXTURE_ADDRESS_MODE, + AddressV: D3D11_TEXTURE_ADDRESS_MODE, + AddressW: D3D11_TEXTURE_ADDRESS_MODE, + MipLODBias: FLOAT, + MaxAnisotropy: UINT, + ComparisonFunc: D3D11_COMPARISON_FUNC, + BorderColor: [FLOAT; 4], + MinLOD: FLOAT, + MaxLOD: FLOAT, +}} +RIDL!{#[uuid(0xda6fea51, 0x564c, 0x4487, 0x98, 0x10, 0xf0, 0xd0, 0xf9, 0xb4, 0xe3, 0xa5)] +interface ID3D11SamplerState(ID3D11SamplerStateVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SAMPLER_DESC, + ) -> (), +}} +ENUM!{enum D3D11_FORMAT_SUPPORT { + D3D11_FORMAT_SUPPORT_BUFFER = 0x1, + D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER = 0x2, + D3D11_FORMAT_SUPPORT_IA_INDEX_BUFFER = 0x4, + D3D11_FORMAT_SUPPORT_SO_BUFFER = 0x8, + D3D11_FORMAT_SUPPORT_TEXTURE1D = 0x10, + D3D11_FORMAT_SUPPORT_TEXTURE2D = 0x20, + D3D11_FORMAT_SUPPORT_TEXTURE3D = 0x40, + D3D11_FORMAT_SUPPORT_TEXTURECUBE = 0x80, + D3D11_FORMAT_SUPPORT_SHADER_LOAD = 0x100, + D3D11_FORMAT_SUPPORT_SHADER_SAMPLE = 0x200, + D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_COMPARISON = 0x400, + D3D11_FORMAT_SUPPORT_SHADER_SAMPLE_MONO_TEXT = 0x800, + D3D11_FORMAT_SUPPORT_MIP = 0x1000, + D3D11_FORMAT_SUPPORT_MIP_AUTOGEN = 0x2000, + D3D11_FORMAT_SUPPORT_RENDER_TARGET = 0x4000, + D3D11_FORMAT_SUPPORT_BLENDABLE = 0x8000, + D3D11_FORMAT_SUPPORT_DEPTH_STENCIL = 0x10000, + D3D11_FORMAT_SUPPORT_CPU_LOCKABLE = 0x20000, + D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE = 0x40000, + D3D11_FORMAT_SUPPORT_DISPLAY = 0x80000, + D3D11_FORMAT_SUPPORT_CAST_WITHIN_BIT_LAYOUT = 0x100000, + D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET = 0x200000, + D3D11_FORMAT_SUPPORT_MULTISAMPLE_LOAD = 0x400000, + D3D11_FORMAT_SUPPORT_SHADER_GATHER = 0x800000, + D3D11_FORMAT_SUPPORT_BACK_BUFFER_CAST = 0x1000000, + D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW = 0x2000000, + D3D11_FORMAT_SUPPORT_SHADER_GATHER_COMPARISON = 0x4000000, + D3D11_FORMAT_SUPPORT_DECODER_OUTPUT = 0x8000000, + D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT = 0x10000000, + D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT = 0x20000000, + D3D11_FORMAT_SUPPORT_VIDEO_ENCODER = 0x40000000, +}} +ENUM!{enum D3D11_FORMAT_SUPPORT2 { + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x1, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x2, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x4, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x8, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x10, + D3D11_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x20, + D3D11_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x40, + D3D11_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x80, + D3D11_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x100, + D3D11_FORMAT_SUPPORT2_TILED = 0x200, + D3D11_FORMAT_SUPPORT2_SHAREABLE = 0x400, + D3D11_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x4000, +}} +RIDL!{#[uuid(0x4b35d0cd, 0x1e15, 0x4258, 0x9c, 0x98, 0x1b, 0x13, 0x33, 0xf6, 0xdd, 0x3b)] +interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDataSize() -> UINT, +}} +ENUM!{enum D3D11_ASYNC_GETDATA_FLAG { + D3D11_ASYNC_GETDATA_DONOTFLUSH = 0x1, +}} +ENUM!{enum D3D11_QUERY { + D3D11_QUERY_EVENT = 0, + D3D11_QUERY_OCCLUSION = D3D11_QUERY_EVENT + 1u32, + D3D11_QUERY_TIMESTAMP = D3D11_QUERY_OCCLUSION + 1u32, + D3D11_QUERY_TIMESTAMP_DISJOINT = D3D11_QUERY_TIMESTAMP + 1u32, + D3D11_QUERY_PIPELINE_STATISTICS = D3D11_QUERY_TIMESTAMP_DISJOINT + 1u32, + D3D11_QUERY_OCCLUSION_PREDICATE = D3D11_QUERY_PIPELINE_STATISTICS + 1u32, + D3D11_QUERY_SO_STATISTICS = D3D11_QUERY_OCCLUSION_PREDICATE + 1u32, + D3D11_QUERY_SO_OVERFLOW_PREDICATE = D3D11_QUERY_SO_STATISTICS + 1u32, + D3D11_QUERY_SO_STATISTICS_STREAM0 = D3D11_QUERY_SO_OVERFLOW_PREDICATE + 1u32, + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0 = D3D11_QUERY_SO_STATISTICS_STREAM0 + 1u32, + D3D11_QUERY_SO_STATISTICS_STREAM1 = D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM0 + 1u32, + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1 = D3D11_QUERY_SO_STATISTICS_STREAM1 + 1u32, + D3D11_QUERY_SO_STATISTICS_STREAM2 = D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM1 + 1u32, + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2 = D3D11_QUERY_SO_STATISTICS_STREAM2 + 1u32, + D3D11_QUERY_SO_STATISTICS_STREAM3 = D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM2 + 1u32, + D3D11_QUERY_SO_OVERFLOW_PREDICATE_STREAM3 = D3D11_QUERY_SO_STATISTICS_STREAM3 + 1u32, +}} +ENUM!{enum D3D11_QUERY_MISC_FLAG { + D3D11_QUERY_MISC_PREDICATEHINT = 0x1, +}} +STRUCT!{struct D3D11_QUERY_DESC { + Query: D3D11_QUERY, + MiscFlags: UINT, +}} +RIDL!{#[uuid(0xd6c00747, 0x87b7, 0x425e, 0xb8, 0x4d, 0x44, 0xd1, 0x08, 0x56, 0x0a, 0xfd)] +interface ID3D11Query(ID3D11QueryVtbl): ID3D11Asynchronous(ID3D11AsynchronousVtbl) { + fn GetDesc( + pDesc: *mut D3D11_QUERY_DESC, + ) -> (), +}} +RIDL!{#[uuid(0x9eb576dd, 0x9f77, 0x4d86, 0x81, 0xaa, 0x8b, 0xab, 0x5f, 0xe4, 0x90, 0xe2)] +interface ID3D11Predicate(ID3D11PredicateVtbl): ID3D11Query(ID3D11QueryVtbl) {}} +STRUCT!{struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT { + Frequency: UINT64, + Disjoint: BOOL, +}} +STRUCT!{struct D3D11_QUERY_DATA_PIPELINE_STATISTICS { + IAVertices: UINT64, + IAPrimitives: UINT64, + VSInvocations: UINT64, + GSInvocations: UINT64, + GSPrimitives: UINT64, + CInvocations: UINT64, + CPrimitives: UINT64, + PSInvocations: UINT64, + HSInvocations: UINT64, + DSInvocations: UINT64, + CSInvocations: UINT64, +}} +STRUCT!{struct D3D11_QUERY_DATA_SO_STATISTICS { + NumPrimitivesWritten: UINT64, + PrimitivesStorageNeeded: UINT64, +}} +ENUM!{enum D3D11_COUNTER { + D3D11_COUNTER_DEVICE_DEPENDENT_0 = 0x40000000, +}} +ENUM!{enum D3D11_COUNTER_TYPE { + D3D11_COUNTER_TYPE_FLOAT32 = 0, + D3D11_COUNTER_TYPE_UINT16 = D3D11_COUNTER_TYPE_FLOAT32 + 1u32, + D3D11_COUNTER_TYPE_UINT32 = D3D11_COUNTER_TYPE_UINT16 + 1u32, + D3D11_COUNTER_TYPE_UINT64 = D3D11_COUNTER_TYPE_UINT32 + 1u32, +}} +STRUCT!{struct D3D11_COUNTER_DESC { + Counter: D3D11_COUNTER, + MiscFlags: UINT, +}} +STRUCT!{struct D3D11_COUNTER_INFO { + LastDeviceDependentCounter: D3D11_COUNTER, + NumSimultaneousCounters: UINT, + NumDetectableParallelUnits: UINT8, +}} +RIDL!{#[uuid(0x6e8c49fb, 0xa371, 0x4770, 0xb4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xb7, 0x41)] +interface ID3D11Counter(ID3D11CounterVtbl): ID3D11Asynchronous(ID3D11AsynchronousVtbl) { + fn GetDesc( + pDesc: *mut D3D11_COUNTER_DESC, + ) -> (), +}} +ENUM!{enum D3D11_STANDARD_MULTISAMPLE_QUALITY_LEVELS { + D3D11_STANDARD_MULTISAMPLE_PATTERN = 0xffffffff, + D3D11_CENTER_MULTISAMPLE_PATTERN = 0xfffffffe, +}} +ENUM!{enum D3D11_DEVICE_CONTEXT_TYPE { + D3D11_DEVICE_CONTEXT_IMMEDIATE = 0, + D3D11_DEVICE_CONTEXT_DEFERRED = D3D11_DEVICE_CONTEXT_IMMEDIATE + 1u32, +}} +STRUCT!{struct D3D11_CLASS_INSTANCE_DESC { + InstanceId: UINT, + InstanceIndex: UINT, + TypeId: UINT, + ConstantBuffer: UINT, + BaseConstantBufferOffset: UINT, + BaseTexture: UINT, + BaseSampler: UINT, + Created: BOOL, +}} +RIDL!{#[uuid(0xa6cd7faa, 0xb0b7, 0x4a2f, 0x94, 0x36, 0x86, 0x62, 0xa6, 0x57, 0x97, 0xcb)] +interface ID3D11ClassInstance(ID3D11ClassInstanceVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetClassLinkage( + ppLinkage: *mut *mut ID3D11ClassLinkage, + ) -> (), + fn GetDesc( + pDesc: *mut D3D11_CLASS_INSTANCE_DESC, + ) -> (), + fn GetInstanceName( + pInstanceName: LPSTR, + pBufferLength: *mut SIZE_T, + ) -> (), + fn GetTypeName( + pTypeName: LPSTR, + pBufferLength: *mut SIZE_T, + ) -> (), +}} +RIDL!{#[uuid(0xddf57cba, 0x9543, 0x46e4, 0xa1, 0x2b, 0xf2, 0x07, 0xa0, 0xfe, 0x7f, 0xed)] +interface ID3D11ClassLinkage(ID3D11ClassLinkageVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetClassInstance( + GetClassInstance: LPCSTR, + InstanceIndex: UINT, + ppInstance: *mut *mut ID3D11ClassInstance, + ) -> HRESULT, + fn CreateClassInstance( + pClassTypeName: LPCSTR, + ConstantBufferOffset: UINT, + ConstantVectorOffset: UINT, + TextureOffset: UINT, + SamplerOffset: UINT, + ppInstance: *mut *mut ID3D11ClassInstance, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa24bc4d1, 0x769e, 0x43f7, 0x80, 0x13, 0x98, 0xff, 0x56, 0x6c, 0x18, 0xe2)] +interface ID3D11CommandList(ID3D11CommandListVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetContextFlags() -> UINT, +}} +ENUM!{enum D3D11_FEATURE { + D3D11_FEATURE_THREADING = 0, + D3D11_FEATURE_DOUBLES = D3D11_FEATURE_THREADING + 1u32, + D3D11_FEATURE_FORMAT_SUPPORT = D3D11_FEATURE_DOUBLES + 1u32, + D3D11_FEATURE_FORMAT_SUPPORT2 = D3D11_FEATURE_FORMAT_SUPPORT + 1u32, + D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS = D3D11_FEATURE_FORMAT_SUPPORT2 + 1u32, + D3D11_FEATURE_D3D11_OPTIONS = D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS + 1u32, + D3D11_FEATURE_ARCHITECTURE_INFO = D3D11_FEATURE_D3D11_OPTIONS + 1u32, + D3D11_FEATURE_D3D9_OPTIONS = D3D11_FEATURE_ARCHITECTURE_INFO + 1u32, + D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT = D3D11_FEATURE_D3D9_OPTIONS + 1u32, + D3D11_FEATURE_D3D9_SHADOW_SUPPORT = D3D11_FEATURE_SHADER_MIN_PRECISION_SUPPORT + 1u32, + D3D11_FEATURE_D3D11_OPTIONS1 = D3D11_FEATURE_D3D9_SHADOW_SUPPORT + 1u32, + D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT = D3D11_FEATURE_D3D11_OPTIONS1 + 1u32, + D3D11_FEATURE_MARKER_SUPPORT = D3D11_FEATURE_D3D9_SIMPLE_INSTANCING_SUPPORT + 1u32, + D3D11_FEATURE_D3D9_OPTIONS1 = D3D11_FEATURE_MARKER_SUPPORT + 1u32, + D3D11_FEATURE_D3D11_OPTIONS2 = D3D11_FEATURE_D3D9_OPTIONS1 + 1u32, + D3D11_FEATURE_D3D11_OPTIONS3 = D3D11_FEATURE_D3D11_OPTIONS2 + 1u32, + D3D11_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT = D3D11_FEATURE_D3D11_OPTIONS3 + 1u32, +}} +STRUCT!{struct D3D11_FEATURE_DATA_THREADING { + DriverConcurrentCreates: BOOL, + DriverCommandLists: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_DOUBLES { + DoublePrecisionFloatShaderOps: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_FORMAT_SUPPORT { + InFormat: DXGI_FORMAT, + OutFormatSupport: UINT, +}} +STRUCT!{struct D3D11_FEATURE_DATA_FORMAT_SUPPORT2 { + InFormat: DXGI_FORMAT, + OutFormatSupport2: UINT, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS { + ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D11_OPTIONS { + OutputMergerLogicOp: BOOL, + UAVOnlyRenderingForcedSampleCount: BOOL, + DiscardAPIsSeenByDriver: BOOL, + FlagsForUpdateAndCopySeenByDriver: BOOL, + ClearView: BOOL, + CopyWithOverlap: BOOL, + ConstantBufferPartialUpdate: BOOL, + ConstantBufferOffsetting: BOOL, + MapNoOverwriteOnDynamicConstantBuffer: BOOL, + MapNoOverwriteOnDynamicBufferSRV: BOOL, + MultisampleRTVWithForcedSampleCountOne: BOOL, + SAD4ShaderInstructions: BOOL, + ExtendedDoublesShaderInstructions: BOOL, + ExtendedResourceSharing: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_ARCHITECTURE_INFO { + TileBasedDeferredRenderer: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D9_OPTIONS { + FullNonPow2TextureSupport: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D9_SHADOW_SUPPORT { + SupportsDepthAsTextureWithLessEqualComparisonFilter: BOOL, +}} +ENUM!{enum D3D11_SHADER_MIN_PRECISION_SUPPORT { + D3D11_SHADER_MIN_PRECISION_10_BIT = 0x1, + D3D11_SHADER_MIN_PRECISION_16_BIT = 0x2, +}} +STRUCT!{struct D3D11_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT { + PixelShaderMinPrecision: UINT, + AllOtherShaderStagesMinPrecision: UINT, +}} +ENUM!{enum D3D11_TILED_RESOURCES_TIER { + D3D11_TILED_RESOURCES_NOT_SUPPORTED = 0, + D3D11_TILED_RESOURCES_TIER_1 = 1, + D3D11_TILED_RESOURCES_TIER_2 = 2, + D3D11_TILED_RESOURCES_TIER_3 = 3, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D11_OPTIONS1 { + TiledResourcesTier: D3D11_TILED_RESOURCES_TIER, + MinMaxFiltering: BOOL, + ClearViewAlsoSupportsDepthOnlyFormats: BOOL, + MapOnDefaultBuffers: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D9_SIMPLE_INSTANCING_SUPPORT { + SimpleInstancingSupported: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_MARKER_SUPPORT { + Profile: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D9_OPTIONS1 { + FullNonPow2TextureSupported: BOOL, + DepthAsTextureWithLessEqualComparisonFilterSupported: BOOL, + SimpleInstancingSupported: BOOL, + TextureCubeFaceRenderTargetWithNonCubeDepthStencilSupported: BOOL, +}} +ENUM!{enum D3D11_CONSERVATIVE_RASTERIZATION_TIER { + D3D11_CONSERVATIVE_RASTERIZATION_NOT_SUPPORTED = 0, + D3D11_CONSERVATIVE_RASTERIZATION_TIER_1 = 1, + D3D11_CONSERVATIVE_RASTERIZATION_TIER_2 = 2, + D3D11_CONSERVATIVE_RASTERIZATION_TIER_3 = 3, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D11_OPTIONS2 { + PSSpecifiedStencilRefSupported: BOOL, + TypedUAVLoadAdditionalFormats: BOOL, + ROVsSupported: BOOL, + ConservativeRasterizationTier: D3D11_CONSERVATIVE_RASTERIZATION_TIER, + TiledResourcesTier: D3D11_TILED_RESOURCES_TIER, + MapOnDefaultTextures: BOOL, + StandardSwizzle: BOOL, + UnifiedMemoryArchitecture: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_D3D11_OPTIONS3 { + VPAndRTArrayIndexFromAnyShaderFeedingRasterizer: BOOL, +}} +STRUCT!{struct D3D11_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT { + MaxGPUVirtualAddressBitsPerResource: UINT, + MaxGPUVirtualAddressBitsPerProcess: UINT, +}} +RIDL!{#[uuid(0xc0bfa96c, 0xe089, 0x44fb, 0x8e, 0xaf, 0x26, 0xf8, 0x79, 0x61, 0x90, 0xda)] +interface ID3D11DeviceContext(ID3D11DeviceContextVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn VSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn PSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn PSSetShader( + pPixelShader: *mut ID3D11PixelShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn PSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn VSSetShader( + pVertexShader: *mut ID3D11VertexShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn DrawIndexed( + IndexCount: UINT, + StartIndexLocation: UINT, + BaseVertexLocation: INT, + ) -> (), + fn Draw( + VertexCount: UINT, + StartVertexLocation: UINT, + ) -> (), + fn Map( + pResource: *mut ID3D11Resource, + Subresource: UINT, + MapType: D3D11_MAP, + MapFlags: UINT, + pMappedResource: *mut D3D11_MAPPED_SUBRESOURCE, + ) -> HRESULT, + fn Unmap( + pResource: *mut ID3D11Resource, + Subresource: UINT, + ) -> (), + fn PSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn IASetInputLayout( + pInputLayout: *mut ID3D11InputLayout, + ) -> (), + fn IASetVertexBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppVertexBuffers: *const *mut ID3D11Buffer, + pStrides: *const UINT, + pOffsets: *const UINT, + ) -> (), + fn IASetIndexBuffer( + pIndexBuffer: *mut ID3D11Buffer, + Format: DXGI_FORMAT, + Offset: UINT, + ) -> (), + fn DrawIndexedInstanced( + IndexCountPerInstance: UINT, + InstanceCount: UINT, + StartIndexLocation: UINT, + BaseVertexLocation: INT, + StartInstanceLocation: UINT, + ) -> (), + fn DrawInstanced( + VertexCountPerInstance: UINT, + InstanceCount: UINT, + StartVertexLocation: UINT, + StartInstanceLocation: UINT, + ) -> (), + fn GSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn GSSetShader( + pShader: *mut ID3D11GeometryShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn IASetPrimitiveTopology( + Topology: D3D11_PRIMITIVE_TOPOLOGY, + ) -> (), + fn VSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn VSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn Begin( + pAsync: *mut ID3D11Asynchronous, + ) -> (), + fn End( + pAsync: *mut ID3D11Asynchronous, + ) -> (), + fn GetData( + pAsync: *mut ID3D11Asynchronous, + pData: *mut c_void, + DataSize: UINT, + GetDataFlags: UINT, + ) -> HRESULT, + fn SetPredication( + pPredicate: *mut ID3D11Predicate, + PredicateValue: BOOL, + ) -> (), + fn GSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn GSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn OMSetRenderTargets( + NumViews: UINT, + ppRenderTargetViews: *const *mut ID3D11RenderTargetView, + pDepthStencilView: *mut ID3D11DepthStencilView, + ) -> (), + fn OMSetRenderTargetsAndUnorderedAccessViews( + NumRTVs: UINT, + ppRenderTargetViews: *const *mut ID3D11RenderTargetView, + pDepthStencilView: *mut ID3D11DepthStencilView, + UAVStartSlot: UINT, + NumUAVs: UINT, + ppUnorderedAccessViews: *const *mut ID3D11UnorderedAccessView, + pUAVInitialCounts: *const UINT, + ) -> (), + fn OMSetBlendState( + pBlendState: *mut ID3D11BlendState, + BlendFactor: &[FLOAT; 4], + SampleMask: UINT, + ) -> (), + fn OMSetDepthStencilState( + pDepthStencilState: *mut ID3D11DepthStencilState, + StencilRef: UINT, + ) -> (), + fn SOSetTargets( + NumBuffers: UINT, + ppSOTargets: *const *mut ID3D11Buffer, + pOffsets: *const UINT, + ) -> (), + fn DrawAuto() -> (), + fn DrawIndexedInstancedIndirect( + pBufferForArgs: *mut ID3D11Buffer, + AlignedByteOffsetForArgs: UINT, + ) -> (), + fn DrawInstancedIndirect( + pBufferForArgs: *mut ID3D11Buffer, + AlignedByteOffsetForArgs: UINT, + ) -> (), + fn Dispatch( + ThreadGroupCountX: UINT, + ThreadGroupCountY: UINT, + ThreadGroupCountZ: UINT, + ) -> (), + fn DispatchIndirect( + pBufferForArgs: *mut ID3D11Buffer, + AlignedByteOffsetForArgs: UINT, + ) -> (), + fn RSSetState( + pRasterizerState: *mut ID3D11RasterizerState, + ) -> (), + fn RSSetViewports( + NumViewports: UINT, + pViewports: *const D3D11_VIEWPORT, + ) -> (), + fn RSSetScissorRects( + NumRects: UINT, + pRects: *const D3D11_RECT, + ) -> (), + fn CopySubresourceRegion( + pDstResource: *mut ID3D11Resource, + DstSubresource: UINT, + DstX: UINT, + DstY: UINT, + DstZ: UINT, + pSrcResource: *mut ID3D11Resource, + SrcSubresource: UINT, + pSrcBox: *const D3D11_BOX, + ) -> (), + fn CopyResource( + pDstResource: *mut ID3D11Resource, + pSrcResource: *mut ID3D11Resource, + ) -> (), + fn UpdateSubresource( + pDstResource: *mut ID3D11Resource, + DstSubresource: UINT, + pDstBox: *const D3D11_BOX, + pSrcData: *const c_void, + SrcRowPitch: UINT, + SrcDepthPitch: UINT, + ) -> (), + fn CopyStructureCount( + pDstBuffer: *mut ID3D11Buffer, + DstAlignedByteOffset: UINT, + pSrcView: *mut ID3D11UnorderedAccessView, + ) -> (), + fn ClearRenderTargetView( + pRenderTargetView: *mut ID3D11RenderTargetView, + ColorRGBA: &[FLOAT; 4], + ) -> (), + fn ClearUnorderedAccessViewUint( + pUnorderedAccessView: *mut ID3D11UnorderedAccessView, + Values: &[UINT; 4], + ) -> (), + fn ClearUnorderedAccessViewFloat( + pUnorderedAccessView: *mut ID3D11UnorderedAccessView, + Values: &[FLOAT; 4], + ) -> (), + fn ClearDepthStencilView( + pDepthStencilView: *mut ID3D11DepthStencilView, + ClearFlags: UINT, + Depth: FLOAT, + Stencil: UINT8, + ) -> (), + fn GenerateMips( + pShaderResourceView: *mut ID3D11ShaderResourceView, + ) -> (), + fn SetResourceMinLOD( + pResource: *mut ID3D11Resource, + MinLOD: FLOAT, + ) -> (), + fn GetResourceMinLOD( + pResource: *mut ID3D11Resource, + ) -> FLOAT, + fn ResolveSubresource( + pDstResource: *mut ID3D11Resource, + DstSubresource: UINT, + pSrcResource: *mut ID3D11Resource, + SrcSubresource: UINT, + Format: DXGI_FORMAT, + ) -> (), + fn ExecuteCommandList( + pCommandList: *mut ID3D11CommandList, + RestoreContextState: BOOL, + ) -> (), + fn HSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn HSSetShader( + pHullShader: *mut ID3D11HullShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn HSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn HSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn DSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn DSSetShader( + pDomainShader: *mut ID3D11DomainShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn DSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn DSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn CSSetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *const *mut ID3D11ShaderResourceView, + ) -> (), + fn CSSetUnorderedAccessViews( + StartSlot: UINT, + NumUAVs: UINT, + ppUnorderedAccessViews: *const *mut ID3D11UnorderedAccessView, + pUAVInitialCounts: *const UINT, + ) -> (), + fn CSSetShader( + pComputeShader: *mut ID3D11ComputeShader, + ppClassInstances: *const *mut ID3D11ClassInstance, + NumClassInstances: UINT, + ) -> (), + fn CSSetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *const *mut ID3D11SamplerState, + ) -> (), + fn CSSetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + ) -> (), + fn VSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn PSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn PSGetShader( + ppPixelShader: *mut *mut ID3D11PixelShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn PSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn VSGetShader( + ppVertexShader: *mut *mut ID3D11VertexShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn PSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn IAGetInputLayout( + ppInputLayout: *mut *mut ID3D11InputLayout, + ) -> (), + fn IAGetVertexBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppVertexBuffers: *mut *mut ID3D11Buffer, + pStrides: *mut UINT, + pOffsets: *mut UINT, + ) -> (), + fn IAGetIndexBuffer( + pIndexBuffer: *mut *mut ID3D11Buffer, + Format: *mut DXGI_FORMAT, + Offset: *mut UINT, + ) -> (), + fn GSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn GSGetShader( + ppGeometryShader: *mut *mut ID3D11GeometryShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn IAGetPrimitiveTopology( + pTopology: *mut D3D11_PRIMITIVE_TOPOLOGY, + ) -> (), + fn VSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn VSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn GetPredication( + ppPredicate: *mut *mut ID3D11Predicate, + pPredicateValue: *mut BOOL, + ) -> (), + fn GSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn GSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn OMGetRenderTargets( + NumViews: UINT, + ppRenderTargetViews: *mut *mut ID3D11RenderTargetView, + ppDepthStencilView: *mut *mut ID3D11DepthStencilView, + ) -> (), + fn OMGetRenderTargetsAndUnorderedAccessViews( + NumRTVs: UINT, + ppRenderTargetViews: *mut *mut ID3D11RenderTargetView, + ppDepthStencilView: *mut *mut ID3D11DepthStencilView, + UAVStartSlot: UINT, + ppUnorderedAccessViews: *mut *mut ID3D11UnorderedAccessView, + ) -> (), + fn OMGetBlendState( + ppBlendState: *mut *mut ID3D11BlendState, + BlendFactor: &mut [FLOAT; 4], + pSampleMask: *mut UINT, + ) -> (), + fn OMGetDepthStencilState( + ppDepthStencilState: *mut *mut ID3D11DepthStencilState, + pStencilRef: *mut UINT, + ) -> (), + fn SOGetTargets( + NumBuffers: UINT, + ppSOTargets: *mut *mut ID3D11Buffer, + ) -> (), + fn RSGetState( + ppRasterizerState: *mut *mut ID3D11RasterizerState, + ) -> (), + fn RSGetViewports( + pNumViewports: *mut UINT, + pViewports: *mut D3D11_VIEWPORT, + ) -> (), + fn RSGetScissorRects( + pNumRects: *mut UINT, + pRects: *mut D3D11_RECT, + ) -> (), + fn HSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn HSGetShader( + ppHullShader: *mut *mut ID3D11HullShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn HSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn HSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn DSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn DSGetShader( + ppDomainShader: *mut *mut ID3D11DomainShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn DSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn DSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn CSGetShaderResources( + StartSlot: UINT, + NumViews: UINT, + ppShaderResourceViews: *mut *mut ID3D11ShaderResourceView, + ) -> (), + fn CSGetUnorderedAccessViews( + StartSlot: UINT, + NumUAVs: UINT, + ppUnorderedAccessViews: *mut *mut ID3D11UnorderedAccessView, + ) -> (), + fn CSGetShader( + ppComputeShader: *mut *mut ID3D11ComputeShader, + ppClassInstances: *mut *mut ID3D11ClassInstance, + pNumClassInstances: *mut UINT, + ) -> (), + fn CSGetSamplers( + StartSlot: UINT, + NumSamplers: UINT, + ppSamplers: *mut *mut ID3D11SamplerState, + ) -> (), + fn CSGetConstantBuffers( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + ) -> (), + fn ClearState() -> (), + fn Flush() -> (), + fn GetType() -> D3D11_DEVICE_CONTEXT_TYPE, + fn GetContextFlags() -> UINT, + fn FinishCommandList( + RestoreDeferredContextState: BOOL, + ppCommandList: *mut *mut ID3D11CommandList, + ) -> HRESULT, +}} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG2_MOCOMP, + 0xe6a9f44b, 0x61b0, 0x4563, 0x9e, 0xa4, 0x63, 0xd2, 0xa3, 0xc6, 0xfe, 0x66} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG2_IDCT, + 0xbf22ad00, 0x03ea, 0x4690, 0x80, 0x77, 0x47, 0x33, 0x46, 0x20, 0x9b, 0x7e} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG2_VLD, + 0xee27417f, 0x5e28, 0x4e65, 0xbe, 0xea, 0x1d, 0x26, 0xb5, 0x08, 0xad, 0xc9} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG1_VLD, + 0x6f3ec719, 0x3735, 0x42cc, 0x80, 0x63, 0x65, 0xcc, 0x3c, 0xb3, 0x66, 0x16} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG2and1_VLD, + 0x86695f12, 0x340e, 0x4f04, 0x9f, 0xd3, 0x92, 0x53, 0xdd, 0x32, 0x74, 0x60} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_MOCOMP_NOFGT, + 0x1b81be64, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_MOCOMP_FGT, + 0x1b81be65, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_IDCT_NOFGT, + 0x1b81be66, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_IDCT_FGT, + 0x1b81be67, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_NOFGT, + 0x1b81be68, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_FGT, + 0x1b81be69, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_WITHFMOASO_NOFGT, + 0xd5f04ff9, 0x3418, 0x45d8, 0x95, 0x61, 0x32, 0xa7, 0x6a, 0xae, 0x2d, 0xdd} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_STEREO_PROGRESSIVE_NOFGT, + 0xd79be8da, 0x0cf1, 0x4c81, 0xb8, 0x2a, 0x69, 0xa4, 0xe2, 0x36, 0xf4, 0x3d} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_STEREO_NOFGT, + 0xf9aaccbb, 0xc2b6, 0x4cfc, 0x87, 0x79, 0x57, 0x07, 0xb1, 0x76, 0x05, 0x52} +DEFINE_GUID!{D3D11_DECODER_PROFILE_H264_VLD_MULTIVIEW_NOFGT, + 0x705b9d82, 0x76cf, 0x49d6, 0xb7, 0xe6, 0xac, 0x88, 0x72, 0xdb, 0x01, 0x3c} +DEFINE_GUID!{D3D11_DECODER_PROFILE_WMV8_POSTPROC, + 0x1b81be80, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_WMV8_MOCOMP, + 0x1b81be81, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_WMV9_POSTPROC, + 0x1b81be90, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_WMV9_MOCOMP, + 0x1b81be91, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_WMV9_IDCT, + 0x1b81be94, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VC1_POSTPROC, + 0x1b81bea0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VC1_MOCOMP, + 0x1b81bea1, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VC1_IDCT, + 0x1b81bea2, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VC1_VLD, + 0x1b81bea3, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VC1_D2010, + 0x1b81bea4, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG4PT2_VLD_SIMPLE, + 0xefd64d74, 0xc9e8, 0x41d7, 0xa5, 0xe9, 0xe9, 0xb0, 0xe3, 0x9f, 0xa3, 0x19} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_NOGMC, + 0xed418a9f, 0x010d, 0x4eda, 0x9a, 0xe3, 0x9a, 0x65, 0x35, 0x8d, 0x8d, 0x2e} +DEFINE_GUID!{D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_GMC, + 0xab998b5b, 0x4258, 0x44a9, 0x9f, 0xeb, 0x94, 0xe5, 0x97, 0xa6, 0xba, 0xae} +DEFINE_GUID!{D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, + 0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0} +DEFINE_GUID!{D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10, + 0x107af0e0, 0xef1a, 0x4d19, 0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0, + 0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e} +DEFINE_GUID!{D3D11_DECODER_PROFILE_VP8_VLD, + 0x90b899ea, 0x3a62, 0x4705, 0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7} +STRUCT!{struct D3D11_VIDEO_DECODER_DESC { + Guid: GUID, + SampleWidth: UINT, + SampleHeight: UINT, + OutputFormat: DXGI_FORMAT, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_CONFIG { + guidConfigBitstreamEncryption: GUID, + guidConfigMBcontrolEncryption: GUID, + guidConfigResidDiffEncryption: GUID, + ConfigBitstreamRaw: UINT, + ConfigMBcontrolRasterOrder: UINT, + ConfigResidDiffHost: UINT, + ConfigSpatialResid8: UINT, + ConfigResid8Subtraction: UINT, + ConfigSpatialHost8or9Clipping: UINT, + ConfigSpatialResidInterleaved: UINT, + ConfigIntraResidUnsigned: UINT, + ConfigResidDiffAccelerator: UINT, + ConfigHostInverseScan: UINT, + ConfigSpecificIDCT: UINT, + Config4GroupedCoefs: UINT, + ConfigMinRenderTargetBuffCount: USHORT, + ConfigDecoderSpecific: USHORT, +}} +ENUM!{enum D3D11_VIDEO_DECODER_BUFFER_TYPE { + D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS = 0, + D3D11_VIDEO_DECODER_BUFFER_MACROBLOCK_CONTROL = 1, + D3D11_VIDEO_DECODER_BUFFER_RESIDUAL_DIFFERENCE = 2, + D3D11_VIDEO_DECODER_BUFFER_DEBLOCKING_CONTROL = 3, + D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX = 4, + D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL = 5, + D3D11_VIDEO_DECODER_BUFFER_BITSTREAM = 6, + D3D11_VIDEO_DECODER_BUFFER_MOTION_VECTOR = 7, + D3D11_VIDEO_DECODER_BUFFER_FILM_GRAIN = 8, +}} +STRUCT!{struct D3D11_AES_CTR_IV { + IV: UINT64, + Count: UINT64, +}} +STRUCT!{struct D3D11_ENCRYPTED_BLOCK_INFO { + NumEncryptedBytesAtBeginning: UINT, + NumBytesInSkipPattern: UINT, + NumBytesInEncryptPattern: UINT, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_BUFFER_DESC { + BufferType: D3D11_VIDEO_DECODER_BUFFER_TYPE, + BufferIndex: UINT, + DataOffset: UINT, + DataSize: UINT, + FirstMBaddress: UINT, + NumMBsInBuffer: UINT, + Width: UINT, + Height: UINT, + Stride: UINT, + ReservedBits: UINT, + pIV: *mut c_void, + IVSize: UINT, + PartialEncryption: BOOL, + EncryptedBlockInfo: D3D11_ENCRYPTED_BLOCK_INFO, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_EXTENSION { + Function: UINT, + pPrivateInputData: *mut c_void, + PrivateInputDataSize: UINT, + pPrivateOutputData: *mut c_void, + PrivateOutputDataSize: UINT, + ResourceCount: UINT, + ppResourceList: *mut *mut ID3D11Resource, +}} +RIDL!{#[uuid(0x3c9c5b51, 0x995d, 0x48d1, 0x9b, 0x8d, 0xfa, 0x5c, 0xae, 0xde, 0xd6, 0x5c)] +interface ID3D11VideoDecoder(ID3D11VideoDecoderVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetCreationParameters( + pVideoDesc: *mut D3D11_VIDEO_DECODER_DESC, + pConfig: *mut D3D11_VIDEO_DECODER_CONFIG, + ) -> HRESULT, + fn GetDriverHandle( + pDriverHandle: *mut HANDLE, + ) -> HRESULT, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT { + D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT = 0x1, + D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT = 0x2, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_DEVICE_CAPS { + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_LINEAR_SPACE = 0x1, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_xvYCC = 0x2, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_RGB_RANGE_CONVERSION = 0x4, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_YCbCr_MATRIX_CONVERSION = 0x8, + D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_NOMINAL_RANGE = 0x10, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_FEATURE_CAPS { + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_FILL = 0x1, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_CONSTRICTION = 0x2, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_LUMA_KEY = 0x4, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_PALETTE = 0x8, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_LEGACY = 0x10, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_STEREO = 0x20, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION = 0x40, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ALPHA_STREAM = 0x80, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_PIXEL_ASPECT_RATIO = 0x100, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_MIRROR = 0x200, + D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_SHADER_USAGE = 0x400, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_FILTER_CAPS { + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_BRIGHTNESS = 0x1, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_CONTRAST = 0x2, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_HUE = 0x4, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_SATURATION = 0x8, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_NOISE_REDUCTION = 0x10, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_EDGE_ENHANCEMENT = 0x20, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_ANAMORPHIC_SCALING = 0x40, + D3D11_VIDEO_PROCESSOR_FILTER_CAPS_STEREO_ADJUSTMENT = 0x80, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_FORMAT_CAPS { + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_INTERLACED = 0x1, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_PROCAMP = 0x2, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_RGB_LUMA_KEY = 0x4, + D3D11_VIDEO_PROCESSOR_FORMAT_CAPS_PALETTE_INTERLACED = 0x8, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS { + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_DENOISE = 0x1, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_DERINGING = 0x2, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_EDGE_ENHANCEMENT = 0x4, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_COLOR_CORRECTION = 0x8, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_FLESH_TONE_MAPPING = 0x10, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_IMAGE_STABILIZATION = 0x20, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_SUPER_RESOLUTION = 0x40, + D3D11_VIDEO_PROCESSOR_AUTO_STREAM_CAPS_ANAMORPHIC_SCALING = 0x80, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_STEREO_CAPS { + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_MONO_OFFSET = 0x1, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_ROW_INTERLEAVED = 0x2, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_COLUMN_INTERLEAVED = 0x4, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_CHECKERBOARD = 0x8, + D3D11_VIDEO_PROCESSOR_STEREO_CAPS_FLIP_MODE = 0x10, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_CAPS { + DeviceCaps: UINT, + FeatureCaps: UINT, + FilterCaps: UINT, + InputFormatCaps: UINT, + AutoStreamCaps: UINT, + StereoCaps: UINT, + RateConversionCapsCount: UINT, + MaxInputStreams: UINT, + MaxStreamStates: UINT, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS { + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND = 0x1, + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB = 0x2, + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE = 0x4, + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION = 0x8, + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE = 0x10, + D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_FRAME_RATE_CONVERSION = 0x20, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS { + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_32 = 0x1, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_22 = 0x2, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_2224 = 0x4, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_2332 = 0x8, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_32322 = 0x10, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_55 = 0x20, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_64 = 0x40, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_87 = 0x80, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_222222222223 = 0x100, + D3D11_VIDEO_PROCESSOR_ITELECINE_CAPS_OTHER = 0x80000000, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS { + PastFrames: UINT, + FutureFrames: UINT, + ProcessorCaps: UINT, + ITelecineCaps: UINT, + CustomRateCount: UINT, +}} +ENUM!{enum D3D11_CONTENT_PROTECTION_CAPS { + D3D11_CONTENT_PROTECTION_CAPS_SOFTWARE = 0x1, + D3D11_CONTENT_PROTECTION_CAPS_HARDWARE = 0x2, + D3D11_CONTENT_PROTECTION_CAPS_PROTECTION_ALWAYS_ON = 0x4, + D3D11_CONTENT_PROTECTION_CAPS_PARTIAL_DECRYPTION = 0x8, + D3D11_CONTENT_PROTECTION_CAPS_CONTENT_KEY = 0x10, + D3D11_CONTENT_PROTECTION_CAPS_FRESHEN_SESSION_KEY = 0x20, + D3D11_CONTENT_PROTECTION_CAPS_ENCRYPTED_READ_BACK = 0x40, + D3D11_CONTENT_PROTECTION_CAPS_ENCRYPTED_READ_BACK_KEY = 0x80, + D3D11_CONTENT_PROTECTION_CAPS_SEQUENTIAL_CTR_IV = 0x100, + D3D11_CONTENT_PROTECTION_CAPS_ENCRYPT_SLICEDATA_ONLY = 0x200, + D3D11_CONTENT_PROTECTION_CAPS_DECRYPTION_BLT = 0x400, + D3D11_CONTENT_PROTECTION_CAPS_HARDWARE_PROTECT_UNCOMPRESSED = 0x800, + D3D11_CONTENT_PROTECTION_CAPS_HARDWARE_PROTECTED_MEMORY_PAGEABLE = 0x1000, + D3D11_CONTENT_PROTECTION_CAPS_HARDWARE_TEARDOWN = 0x2000, + D3D11_CONTENT_PROTECTION_CAPS_HARDWARE_DRM_COMMUNICATION = 0x4000, +}} +DEFINE_GUID!{D3D11_CRYPTO_TYPE_AES128_CTR, + 0x9b6bd711, 0x4f74, 0x41c9, 0x9e, 0x7b, 0x0b, 0xe2, 0xd7, 0xd9, 0x3b, 0x4f} +DEFINE_GUID!{D3D11_DECODER_ENCRYPTION_HW_CENC, + 0x89d6ac4f, 0x09f2, 0x4229, 0xb2, 0xcd, 0x37, 0x74, 0x0a, 0x6d, 0xfd, 0x81} +DEFINE_GUID!{D3D11_KEY_EXCHANGE_HW_PROTECTION, + 0xb1170d8a, 0x628d, 0x4da3, 0xad, 0x3b, 0x82, 0xdd, 0xb0, 0x8b, 0x49, 0x70} +STRUCT!{struct D3D11_VIDEO_CONTENT_PROTECTION_CAPS { + Caps: UINT, + KeyExchangeTypeCount: UINT, + BlockAlignmentSize: UINT, + ProtectedMemorySize: ULONGLONG, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_CUSTOM_RATE { + CustomRate: DXGI_RATIONAL, + OutputFrames: UINT, + InputInterlaced: BOOL, + InputFramesOrFields: UINT, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_FILTER { + D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS = 0, + D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST = 1, + D3D11_VIDEO_PROCESSOR_FILTER_HUE = 2, + D3D11_VIDEO_PROCESSOR_FILTER_SATURATION = 3, + D3D11_VIDEO_PROCESSOR_FILTER_NOISE_REDUCTION = 4, + D3D11_VIDEO_PROCESSOR_FILTER_EDGE_ENHANCEMENT = 5, + D3D11_VIDEO_PROCESSOR_FILTER_ANAMORPHIC_SCALING = 6, + D3D11_VIDEO_PROCESSOR_FILTER_STEREO_ADJUSTMENT = 7, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_FILTER_RANGE { + Minimum: c_int, + Maximum: c_int, + Default: c_int, + Multiplier: c_float, +}} +ENUM!{enum D3D11_VIDEO_FRAME_FORMAT { + D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE = 0, + D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST = 1, + D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST = 2, +}} +ENUM!{enum D3D11_VIDEO_USAGE { + D3D11_VIDEO_USAGE_PLAYBACK_NORMAL = 0, + D3D11_VIDEO_USAGE_OPTIMAL_SPEED = 1, + D3D11_VIDEO_USAGE_OPTIMAL_QUALITY = 2, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_CONTENT_DESC { + InputFrameFormat: D3D11_VIDEO_FRAME_FORMAT, + InputFrameRate: DXGI_RATIONAL, + InputWidth: UINT, + InputHeight: UINT, + OutputFrameRate: DXGI_RATIONAL, + OutputWidth: UINT, + OutputHeight: UINT, + Usage: D3D11_VIDEO_USAGE, +}} +RIDL!{#[uuid(0x31627037, 0x53ab, 0x4200, 0x90, 0x61, 0x05, 0xfa, 0xa9, 0xab, 0x45, 0xf9)] +interface ID3D11VideoProcessorEnumerator(ID3D11VideoProcessorEnumeratorVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetVideoProcessorContentDesc( + pContentDesc: *mut D3D11_VIDEO_PROCESSOR_CONTENT_DESC, + ) -> HRESULT, + fn CheckVideoProcessorFormat( + Format: DXGI_FORMAT, + pFlags: *mut UINT, + ) -> HRESULT, + fn GetVideoProcessorCaps( + pCaps: *mut D3D11_VIDEO_PROCESSOR_CAPS, + ) -> HRESULT, + fn GetVideoProcessorRateConversionCaps( + TypeIndex: UINT, + pCaps: *mut D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS, + ) -> HRESULT, + fn GetVideoProcessorCustomRate( + TypeIndex: UINT, + CustomRateIndex: UINT, + pRate: *mut D3D11_VIDEO_PROCESSOR_CUSTOM_RATE, + ) -> HRESULT, + fn GetVideoProcessorFilterRange( + Filter: D3D11_VIDEO_PROCESSOR_FILTER, + Range: *mut D3D11_VIDEO_PROCESSOR_FILTER_RANGE, + ) -> HRESULT, +}} +STRUCT!{struct D3D11_VIDEO_COLOR_RGBA { + R: c_float, + G: c_float, + B: c_float, + A: c_float, +}} +STRUCT!{struct D3D11_VIDEO_COLOR_YCbCrA { + Y: c_float, + Cb: c_float, + Cr: c_float, + A: c_float, +}} +UNION!{union D3D11_VIDEO_COLOR { + [f32; 4], + YCbCr YCbCr_mut: D3D11_VIDEO_COLOR_YCbCrA, + RGBA RGBA_mut: D3D11_VIDEO_COLOR_RGBA, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE { + D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_UNDEFINED = 0, + D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235 = 1, + D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255 = 2, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_COLOR_SPACE { + bitfield: UINT, +}} +BITFIELD!{D3D11_VIDEO_PROCESSOR_COLOR_SPACE bitfield: UINT [ + Usage set_Usage[0..1], + RGB_Range set_RGB_Range[1..2], + YCbCr_Matrix set_YCbCr_Matrix[2..3], + YCbCr_xvYCC set_YCbCr_xvYCC[3..4], + Nominal_Range set_Nominal_Range[4..6], +]} +ENUM!{enum D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE { + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE_OPAQUE = 0, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE_BACKGROUND = 1, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE_DESTINATION = 2, + D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE_SOURCE_STREAM = 3, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_OUTPUT_RATE { + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL = 0, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_HALF = 1, + D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_CUSTOM = 2, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_STEREO_FORMAT { + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_MONO = 0, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_HORIZONTAL = 1, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_VERTICAL = 2, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_SEPARATE = 3, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_MONO_OFFSET = 4, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_ROW_INTERLEAVED = 5, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_COLUMN_INTERLEAVED = 6, + D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_CHECKERBOARD = 7, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE { + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_NONE = 0, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_FRAME0 = 1, + D3D11_VIDEO_PROCESSOR_STEREO_FLIP_FRAME1 = 2, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_ROTATION { + D3D11_VIDEO_PROCESSOR_ROTATION_IDENTITY = 0, + D3D11_VIDEO_PROCESSOR_ROTATION_90 = 1, + D3D11_VIDEO_PROCESSOR_ROTATION_180 = 2, + D3D11_VIDEO_PROCESSOR_ROTATION_270 = 3, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_STREAM { + Enable: BOOL, + OutputIndex: UINT, + InputFrameOrField: UINT, + PastFrames: UINT, + FutureFrames: UINT, + ppPastSurfaces: *mut *mut ID3D11VideoProcessorInputView, + pInputSurface: *mut ID3D11VideoProcessorInputView, + ppFutureSurfaces: *mut *mut ID3D11VideoProcessorInputView, + ppPastSurfacesRight: *mut *mut ID3D11VideoProcessorInputView, + pInputSurfaceRight: *mut ID3D11VideoProcessorInputView, + ppFutureSurfacesRight: *mut *mut ID3D11VideoProcessorInputView, +}} +RIDL!{#[uuid(0x1d7b0652, 0x185f, 0x41c6, 0x85, 0xce, 0x0c, 0x5b, 0xe3, 0xd4, 0xae, 0x6c)] +interface ID3D11VideoProcessor(ID3D11VideoProcessorVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetContentDesc( + pDesc: *mut D3D11_VIDEO_PROCESSOR_CONTENT_DESC, + ) -> (), + fn GetRateConversionCaps( + pCaps: *mut D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS, + ) -> (), +}} +STRUCT!{struct D3D11_OMAC { + Omac: [BYTE; 16], +}} +ENUM!{enum D3D11_AUTHENTICATED_CHANNEL_TYPE { + D3D11_AUTHENTICATED_CHANNEL_D3D11 = 1, + D3D11_AUTHENTICATED_CHANNEL_DRIVER_SOFTWARE = 2, + D3D11_AUTHENTICATED_CHANNEL_DRIVER_HARDWARE = 3, +}} +RIDL!{#[uuid(0x3015a308, 0xdcbd, 0x47aa, 0xa7, 0x47, 0x19, 0x24, 0x86, 0xd1, 0x4d, 0x4a)] +interface ID3D11AuthenticatedChannel(ID3D11AuthenticatedChannelVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetCertificateSize( + pCertificateSize: *mut UINT, + ) -> HRESULT, + fn GetCertificate( + CertificateSize: UINT, + pCertificate: *mut BYTE, + ) -> HRESULT, + fn GetChannelHandle( + pChannelHandle: *mut HANDLE, + ) -> (), +}} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_PROTECTION, + 0xa84eb584, 0xc495, 0x48aa, 0xb9, 0x4d, 0x8b, 0xd2, 0xd6, 0xfb, 0xce, 0x05} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_CHANNEL_TYPE, + 0xbc1b18a5, 0xb1fb, 0x42ab, 0xbd, 0x94, 0xb5, 0x82, 0x8b, 0x4b, 0xf7, 0xbe} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_DEVICE_HANDLE, + 0xec1c539d, 0x8cff, 0x4e2a, 0xbc, 0xc4, 0xf5, 0x69, 0x2f, 0x99, 0xf4, 0x80} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_CRYPTO_SESSION, + 0x2634499e, 0xd018, 0x4d74, 0xac, 0x17, 0x7f, 0x72, 0x40, 0x59, 0x52, 0x8d} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_COUNT, + 0x0db207b3, 0x9450, 0x46a6, 0x82, 0xde, 0x1b, 0x96, 0xd4, 0x4f, 0x9c, 0xf2} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS, + 0x649bbadb, 0xf0f4, 0x4639, 0xa1, 0x5b, 0x24, 0x39, 0x3f, 0xc3, 0xab, 0xac} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_UNRESTRICTED_PROTECTED_SHARED_RESOURCE_COUNT, + 0x012f0bd6, 0xe662, 0x4474, 0xbe, 0xfd, 0xaa, 0x53, 0xe5, 0x14, 0x3c, 0x6d} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_OUTPUT_ID_COUNT, + 0x2c042b5e, 0x8c07, 0x46d5, 0xaa, 0xbe, 0x8f, 0x75, 0xcb, 0xad, 0x4c, 0x31} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_OUTPUT_ID, + 0x839ddca3, 0x9b4e, 0x41e4, 0xb0, 0x53, 0x89, 0x2b, 0xd2, 0xa1, 0x1e, 0xe7} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_ACCESSIBILITY_ATTRIBUTES, + 0x6214d9d2, 0x432c, 0x4abb, 0x9f, 0xce, 0x21, 0x6e, 0xea, 0x26, 0x9e, 0x3b} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_ENCRYPTION_WHEN_ACCESSIBLE_GUID_COUNT, + 0xb30f7066, 0x203c, 0x4b07, 0x93, 0xfc, 0xce, 0xaa, 0xfd, 0x61, 0x24, 0x1e} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_ENCRYPTION_WHEN_ACCESSIBLE_GUID, + 0xf83a5958, 0xe986, 0x4bda, 0xbe, 0xb0, 0x41, 0x1f, 0x6a, 0x7a, 0x01, 0xb7} +DEFINE_GUID!{D3D11_AUTHENTICATED_QUERY_CURRENT_ENCRYPTION_WHEN_ACCESSIBLE, + 0xec1791c7, 0xdad3, 0x4f15, 0x9e, 0xc3, 0xfa, 0xa9, 0x3d, 0x60, 0xd4, 0xf0} +DEFINE_GUID!{D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE, + 0x06114bdb, 0x3523, 0x470a, 0x8d, 0xca, 0xfb, 0xc2, 0x84, 0x51, 0x54, 0xf0} +DEFINE_GUID!{D3D11_AUTHENTICATED_CONFIGURE_PROTECTION, + 0x50455658, 0x3f47, 0x4362, 0xbf, 0x99, 0xbf, 0xdf, 0xcd, 0xe9, 0xed, 0x29} +DEFINE_GUID!{D3D11_AUTHENTICATED_CONFIGURE_CRYPTO_SESSION, + 0x6346cc54, 0x2cfc, 0x4ad4, 0x82, 0x24, 0xd1, 0x58, 0x37, 0xde, 0x77, 0x00} +DEFINE_GUID!{D3D11_AUTHENTICATED_CONFIGURE_SHARED_RESOURCE, + 0x0772d047, 0x1b40, 0x48e8, 0x9c, 0xa6, 0xb5, 0xf5, 0x10, 0xde, 0x9f, 0x01} +DEFINE_GUID!{D3D11_AUTHENTICATED_CONFIGURE_ENCRYPTION_WHEN_ACCESSIBLE, + 0x41fff286, 0x6ae0, 0x4d43, 0x9d, 0x55, 0xa4, 0x6e, 0x9e, 0xfd, 0x15, 0x8a} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_INPUT { + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_OUTPUT { + omac: D3D11_OMAC, + QueryType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, + ReturnCode: HRESULT, +}} +//FIXME bitfield +STRUCT!{struct D3D11_AUTHENTICATED_PROTECTION_FLAGS { + u: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_PROTECTION_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + ProtectionFlags: D3D11_AUTHENTICATED_PROTECTION_FLAGS, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_CHANNEL_TYPE_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + ChannelType: D3D11_AUTHENTICATED_CHANNEL_TYPE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_DEVICE_HANDLE_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_CRYPTO_SESSION_INPUT { + Input: D3D11_AUTHENTICATED_QUERY_INPUT, + DecoderHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_CRYPTO_SESSION_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + DecoderHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_COUNT_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + RestrictedSharedResourceProcessCount: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_INPUT { + Input: D3D11_AUTHENTICATED_QUERY_INPUT, + ProcessIndex: UINT, +}} +ENUM!{enum D3D11_AUTHENTICATED_PROCESS_IDENTIFIER_TYPE { + DD3D11_PROCESSIDTYPE_UNKNOWN = 0, + DD3D11_PROCESSIDTYPE_DWM = 1, + DD3D11_PROCESSIDTYPE_HANDLE = 2, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_RESTRICTED_SHARED_RESOURCE_PROCESS_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + ProcessIndex: UINT, + ProcessIdentifier: D3D11_AUTHENTICATED_PROCESS_IDENTIFIER_TYPE, + ProcessHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_UNRESTRICTED_PROTECTED_SHARED_RESOURCE_COUNT_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + UnrestrictedProtectedSharedResourceCount: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_OUTPUT_ID_COUNT_INPUT { + Input: D3D11_AUTHENTICATED_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_OUTPUT_ID_COUNT_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDCount: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_OUTPUT_ID_INPUT { + Input: D3D11_AUTHENTICATED_QUERY_INPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_OUTPUT_ID_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + DeviceHandle: HANDLE, + CryptoSessionHandle: HANDLE, + OutputIDIndex: UINT, + OutputID: UINT64, +}} +ENUM!{enum D3D11_BUS_TYPE { + D3D11_BUS_TYPE_OTHER = 0, + D3D11_BUS_TYPE_PCI = 0x1, + D3D11_BUS_TYPE_PCIX = 0x2, + D3D11_BUS_TYPE_PCIEXPRESS = 0x3, + D3D11_BUS_TYPE_AGP = 0x4, + D3D11_BUS_IMPL_MODIFIER_INSIDE_OF_CHIPSET = 0x10000, + D3D11_BUS_IMPL_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_CHIP = 0x20000, + D3D11_BUS_IMPL_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_SOCKET = 0x30000, + D3D11_BUS_IMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR = 0x40000, + D3D11_BUS_IMPL_MODIFIER_DAUGHTER_BOARD_CONNECTOR_INSIDE_OF_NUAE = 0x50000, + D3D11_BUS_IMPL_MODIFIER_NON_STANDARD = 0x80000000, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_ACESSIBILITY_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + BusType: D3D11_BUS_TYPE, + AccessibleInContiguousBlocks: BOOL, + AccessibleInNonContiguousBlocks: BOOL, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_COUNT_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuidCount: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_INPUT { + Input: D3D11_AUTHENTICATED_QUERY_INPUT, + EncryptionGuidIndex: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_ACCESSIBILITY_ENCRYPTION_GUID_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuidIndex: UINT, + EncryptionGuid: GUID, +}} +STRUCT!{struct D3D11_AUTHENTICATED_QUERY_CURRENT_ACCESSIBILITY_ENCRYPTION_OUTPUT { + Output: D3D11_AUTHENTICATED_QUERY_OUTPUT, + EncryptionGuid: GUID, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_INPUT { + omac: D3D11_OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_OUTPUT { + omac: D3D11_OMAC, + ConfigureType: GUID, + hChannel: HANDLE, + SequenceNumber: UINT, + ReturnCode: HRESULT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_INITIALIZE_INPUT { + Parameters: D3D11_AUTHENTICATED_CONFIGURE_INPUT, + StartSequenceQuery: UINT, + StartSequenceConfigure: UINT, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_PROTECTION_INPUT { + Parameters: D3D11_AUTHENTICATED_CONFIGURE_INPUT, + Protections: D3D11_AUTHENTICATED_PROTECTION_FLAGS, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_CRYPTO_SESSION_INPUT { + Parameters: D3D11_AUTHENTICATED_CONFIGURE_INPUT, + DecoderHandle: HANDLE, + CryptoSessionHandle: HANDLE, + DeviceHandle: HANDLE, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_SHARED_RESOURCE_INPUT { + Parameters: D3D11_AUTHENTICATED_CONFIGURE_INPUT, + ProcessType: D3D11_AUTHENTICATED_PROCESS_IDENTIFIER_TYPE, + ProcessHandle: HANDLE, + AllowAccess: BOOL, +}} +STRUCT!{struct D3D11_AUTHENTICATED_CONFIGURE_ACCESSIBLE_ENCRYPTION_INPUT { + Parameters: D3D11_AUTHENTICATED_CONFIGURE_INPUT, + EncryptionGuid: GUID, +}} +DEFINE_GUID!{D3D11_KEY_EXCHANGE_RSAES_OAEP, + 0xc1949895, 0xd72a, 0x4a1d, 0x8e, 0x5d, 0xed, 0x85, 0x7d, 0x17, 0x15, 0x20} +RIDL!{#[uuid(0x9b32f9ad, 0xbdcc, 0x40a6, 0xa3, 0x9d, 0xd5, 0xc8, 0x65, 0x84, 0x57, 0x20)] +interface ID3D11CryptoSession(ID3D11CryptoSessionVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetCryptoType( + pCryptoType: *mut GUID, + ) -> (), + fn GetDecoderProfile( + pDecoderProfile: *mut GUID, + ) -> (), + fn GetCertificateSize( + pCertificateSize: *mut UINT, + ) -> HRESULT, + fn GetCertificate( + CertificateSize: UINT, + pCertificate: *mut BYTE, + ) -> HRESULT, + fn GetCryptoSessionHandle( + pCertificate: *mut HANDLE, + ) -> (), +}} +ENUM!{enum D3D11_VDOV_DIMENSION { + D3D11_VDOV_DIMENSION_UNKNOWN = 0, + D3D11_VDOV_DIMENSION_TEXTURE2D = 1, +}} +STRUCT!{struct D3D11_TEX2D_VDOV { + ArraySlice: UINT, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC { + DecodeProfile: GUID, + ViewDimension: D3D11_VDOV_DIMENSION, + Texture2D: D3D11_TEX2D_VDOV, +}} +RIDL!{#[uuid(0xc2931aea, 0x2a85, 0x4f20, 0x86, 0x0f, 0xfb, 0xa1, 0xfd, 0x25, 0x6e, 0x18)] +interface ID3D11VideoDecoderOutputView(ID3D11VideoDecoderOutputViewVtbl): + ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC, + ) -> (), +}} +ENUM!{enum D3D11_VPIV_DIMENSION { + D3D11_VPIV_DIMENSION_UNKNOWN = 0, + D3D11_VPIV_DIMENSION_TEXTURE2D = 1, +}} +STRUCT!{struct D3D11_TEX2D_VPIV { + MipSlice: UINT, + ArraySlice: UINT, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC { + FourCC: UINT, + ViewDimension: D3D11_VPIV_DIMENSION, + Texture2D: D3D11_TEX2D_VPIV, +}} +RIDL!{#[uuid(0x11ec5a5f, 0x51dc, 0x4945, 0xab, 0x34, 0x6e, 0x8c, 0x21, 0x30, 0x0e, 0xa5)] +interface ID3D11VideoProcessorInputView(ID3D11VideoProcessorInputViewVtbl): + ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC, + ) -> (), +}} +ENUM!{enum D3D11_VPOV_DIMENSION { + D3D11_VPOV_DIMENSION_UNKNOWN = 0, + D3D11_VPOV_DIMENSION_TEXTURE2D = 1, + D3D11_VPOV_DIMENSION_TEXTURE2DARRAY = 2, +}} +STRUCT!{struct D3D11_TEX2D_VPOV { + MipSlice: UINT, +}} +STRUCT!{struct D3D11_TEX2D_ARRAY_VPOV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +UNION!{union D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC_u { + [u32; 3], + Texture2D Texture2D_mut: D3D11_TEX2D_VPOV, + Texture2DArray Texture2DArray_mut: D3D11_TEX2D_ARRAY_VPOV, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC { + ViewDimension: D3D11_VPOV_DIMENSION, + u: D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC_u, +}} +RIDL!{#[uuid(0xa048285e, 0x25a9, 0x4527, 0xbd, 0x93, 0xd6, 0x8b, 0x68, 0xc4, 0x42, 0x54)] +interface ID3D11VideoProcessorOutputView(ID3D11VideoProcessorOutputViewVtbl): + ID3D11View(ID3D11ViewVtbl) { + fn GetDesc( + pDesc: *mut D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, + ) -> (), +}} +RIDL!{#[uuid(0x61f21c45, 0x3c0e, 0x4a74, 0x9c, 0xea, 0x67, 0x10, 0x0d, 0x9a, 0xd5, 0xe4)] +interface ID3D11VideoContext(ID3D11VideoContextVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) { + fn GetDecoderBuffer( + pDecoder: *mut ID3D11VideoDecoder, + Type: D3D11_VIDEO_DECODER_BUFFER_TYPE, + pBufferSize: *mut UINT, + ppBuffer: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseDecoderBuffer( + pDecoder: *mut ID3D11VideoDecoder, + Type: D3D11_VIDEO_DECODER_BUFFER_TYPE, + ) -> HRESULT, + fn DecoderBeginFrame( + pDecoder: *mut ID3D11VideoDecoder, + pView: *mut ID3D11VideoDecoderOutputView, + ContentKeySize: UINT, + pContentKey: *const c_void, + ) -> HRESULT, + fn DecoderEndFrame( + pDecoder: *mut ID3D11VideoDecoder, + ) -> HRESULT, + fn SubmitDecoderBuffers( + pDecoder: *mut ID3D11VideoDecoder, + NumBuffers: UINT, + pBufferDesc: *const D3D11_VIDEO_DECODER_BUFFER_DESC, + ) -> HRESULT, + fn DecoderExtension( + pDecoder: *mut ID3D11VideoDecoder, + pExtensionData: *const D3D11_VIDEO_DECODER_EXTENSION, + ) -> HRESULT, + fn VideoProcessorSetOutputTargetRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + Enable: BOOL, + pRect: *const RECT, + ) -> (), + fn VideoProcessorSetOutputBackgroundColor( + pVideoProcessor: *mut ID3D11VideoProcessor, + YCbCr: BOOL, + pRect: *const RECT, + ) -> (), + fn VideoProcessorSetOutputColorSpace( + pVideoProcessor: *mut ID3D11VideoProcessor, + pColorSpace: *const D3D11_VIDEO_PROCESSOR_COLOR_SPACE, + ) -> HRESULT, + fn VideoProcessorSetOutputAlphaFillMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + AlphaFillMode: D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE, + StreamIndex: UINT, + ) -> (), + fn VideoProcessorSetOutputConstriction( + pVideoProcessor: *mut ID3D11VideoProcessor, + Enable: BOOL, + Size: SIZE, + ) -> (), + fn VideoProcessorSetOutputStereoMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + Enable: BOOL, + ) -> (), + fn VideoProcessorSetOutputExtension( + pVideoProcessor: *mut ID3D11VideoProcessor, + pExtensionGuid: *const GUID, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn VideoProcessorGetOutputTargetRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + Enabled: *mut BOOL, + pRect: *mut RECT, + ) -> (), + fn VideoProcessorGetOutputBackgroundColor( + pVideoProcessor: *mut ID3D11VideoProcessor, + pYCbCr: *mut BOOL, + pColor: *mut D3D11_VIDEO_COLOR, + ) -> (), + fn VideoProcessorGetOutputColorSpace( + pVideoProcessor: *mut ID3D11VideoProcessor, + pColorSpace: *mut D3D11_VIDEO_PROCESSOR_COLOR_SPACE, + ) -> (), + fn VideoProcessorGetOutputAlphaFillMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + pAlphaFillMode: *mut D3D11_VIDEO_PROCESSOR_ALPHA_FILL_MODE, + pStreamIndex: *mut UINT, + ) -> (), + fn VideoProcessorGetOutputConstriction( + pVideoProcessor: *mut ID3D11VideoProcessor, + pEnabled: *mut BOOL, + pSize: *mut SIZE, + ) -> (), + fn VideoProcessorGetOutputStereoMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + pEnabled: *mut BOOL, + ) -> (), + fn VideoProcessorGetOutputExtension( + pVideoProcessor: *mut ID3D11VideoProcessor, + pExtensionGuid: *const GUID, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn VideoProcessorSetStreamFrameFormat( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + FrameFormat: D3D11_VIDEO_FRAME_FORMAT, + ) -> (), + fn VideoProcessorSetStreamColorSpace( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pColorSpace: *const D3D11_VIDEO_PROCESSOR_COLOR_SPACE, + ) -> (), + fn VideoProcessorSetStreamOutputRate( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + OutputRate: D3D11_VIDEO_PROCESSOR_OUTPUT_RATE, + RepeatFrame: BOOL, + pCustomRate: *const DXGI_RATIONAL, + ) -> (), + fn VideoProcessorSetStreamSourceRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + pRect: *const RECT, + ) -> (), + fn VideoProcessorSetStreamDestRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + pRect: *const RECT, + ) -> (), + fn VideoProcessorSetStreamAlpha( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + Alpha: FLOAT, + ) -> (), + fn VideoProcessorSetStreamPalette( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Count: UINT, + pEntries: *const UINT, + ) -> (), + fn VideoProcessorSetStreamPixelAspectRatio( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + pSourceAspectRatio: *const DXGI_RATIONAL, + pDestinationAspectRatio: *const DXGI_RATIONAL, + ) -> (), + fn VideoProcessorSetStreamLumaKey( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + Lower: FLOAT, + Upper: FLOAT, + ) -> (), + fn VideoProcessorSetStreamStereoFormat( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + Format: D3D11_VIDEO_PROCESSOR_STEREO_FORMAT, + LeftViewFrame0: BOOL, + BaseViewFrame0: BOOL, + FlipMode: D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE, + ) -> (), + fn VideoProcessorSetStreamAutoProcessingMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + ) -> (), + fn VideoProcessorSetStreamFilter( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Filter: D3D11_VIDEO_PROCESSOR_FILTER, + Enable: BOOL, + Level: c_int, + ) -> (), + fn VideoProcessorSetStreamExtension( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pExtensionGuid: *const GUID, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn VideoProcessorGetStreamFrameFormat( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pFrameFormat: *mut D3D11_VIDEO_FRAME_FORMAT, + ) -> (), + fn VideoProcessorGetStreamColorSpace( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pColorSpace: *mut D3D11_VIDEO_PROCESSOR_COLOR_SPACE, + ) -> (), + fn VideoProcessorGetStreamOutputRate( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pOutputRate: *mut D3D11_VIDEO_PROCESSOR_OUTPUT_RATE, + pRepeatFrame: *mut BOOL, + pCustomRate: *mut DXGI_RATIONAL, + ) -> (), + fn VideoProcessorGetStreamSourceRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pRect: *mut RECT, + ) -> (), + fn VideoProcessorGetStreamDestRect( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pRect: *mut RECT, + ) -> (), + fn VideoProcessorGetStreamAlpha( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pAlpha: *mut FLOAT, + ) -> (), + fn VideoProcessorGetStreamPalette( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Count: UINT, + pEntries: *mut UINT, + ) -> (), + fn VideoProcessorGetStreamPixelAspectRatio( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pSourceAspectRatio: *mut DXGI_RATIONAL, + pDestinationAspectRatio: *mut DXGI_RATIONAL, + ) -> (), + fn VideoProcessorGetStreamLumaKey( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pLower: *mut FLOAT, + pUpper: *mut FLOAT, + ) -> (), + fn VideoProcessorGetStreamStereoFormat( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + pFormat: *mut D3D11_VIDEO_PROCESSOR_STEREO_FORMAT, + pLeftViewFrame0: *mut BOOL, + pBaseViewFrame0: *mut BOOL, + pFlipMode: *mut D3D11_VIDEO_PROCESSOR_STEREO_FLIP_MODE, + MonoOffset: *mut c_int, + ) -> (), + fn VideoProcessorGetStreamAutoProcessingMode( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnabled: *mut BOOL, + ) -> (), + fn VideoProcessorGetStreamFilter( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Filter: D3D11_VIDEO_PROCESSOR_FILTER, + pEnabled: *mut BOOL, + pLevel: *mut c_int, + ) -> (), + fn VideoProcessorGetStreamExtension( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pExtensionGuid: *const GUID, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn VideoProcessorBlt( + pVideoProcessor: *mut ID3D11VideoProcessor, + pView: *mut ID3D11VideoProcessorOutputView, + OutputFrame: UINT, + StreamCount: UINT, + pStreams: *const D3D11_VIDEO_PROCESSOR_STREAM, + ) -> HRESULT, + fn NegotiateCryptoSessionKeyExchange( + pCryptoSession: *mut ID3D11CryptoSession, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn EncryptionBlt( + pCryptoSession: *mut ID3D11CryptoSession, + pSrcSurface: *mut ID3D11Texture2D, + pDstSurface: *mut ID3D11Texture2D, + IVSize: UINT, + pIV: *mut c_void, + ) -> HRESULT, + fn DecryptionBlt( + pCryptoSession: *mut ID3D11CryptoSession, + pSrcSurface: *mut ID3D11Texture2D, + pDstSurface: *mut ID3D11Texture2D, + pEncryptedBlockInfo: *mut D3D11_ENCRYPTED_BLOCK_INFO, + ContentKeySize: UINT, + pContentKey: *const c_void, + IVSize: UINT, + pIV: *mut c_void, + ) -> HRESULT, + fn StartSessionKeyRefresh( + pCryptoSession: *mut ID3D11CryptoSession, + RandomNumberSize: UINT, + pRandomNumber: *mut c_void, + ) -> HRESULT, + fn FinishSessionKeyRefresh( + pCryptoSession: *mut ID3D11CryptoSession, + ) -> HRESULT, + fn GetEncryptionBltKey( + pCryptoSession: *mut ID3D11CryptoSession, + KeySize: UINT, + pReadbackKey: *mut c_void, + ) -> HRESULT, + fn NegotiateAuthenticatedChannelKeyExchange( + pChannel: *mut ID3D11AuthenticatedChannel, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn QueryAuthenticatedChannel( + pChannel: *mut ID3D11AuthenticatedChannel, + InputSize: UINT, + pInput: *const c_void, + OutputSize: UINT, + pOutput: *mut c_void, + ) -> HRESULT, + fn ConfigureAuthenticatedChannel( + pChannel: *mut ID3D11AuthenticatedChannel, + InputSize: UINT, + pInput: *const c_void, + pOutput: *mut D3D11_AUTHENTICATED_CONFIGURE_OUTPUT, + ) -> HRESULT, + fn VideoProcessorSetStreamRotation( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + Rotation: D3D11_VIDEO_PROCESSOR_ROTATION, + ) -> HRESULT, + fn VideoProcessorGetStreamRotation( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnable: *mut BOOL, + pRotation: *mut D3D11_VIDEO_PROCESSOR_ROTATION, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x10ec4d5b, 0x975a, 0x4689, 0xb9, 0xe4, 0xd0, 0xaa, 0xc3, 0x0f, 0xe3, 0x33)] +interface ID3D11VideoDevice(ID3D11VideoDeviceVtbl): IUnknown(IUnknownVtbl) { + fn CreateVideoDecoder( + pVideoDesc: *const D3D11_VIDEO_DECODER_DESC, + pConfig: *const D3D11_VIDEO_DECODER_CONFIG, + ppDecoder: *mut *mut ID3D11VideoDecoder, + ) -> HRESULT, + fn CreateVideoProcessor( + pEnum: *mut ID3D11VideoProcessorEnumerator, + RateConversionIndex: UINT, + ppVideoProcessor: *mut *mut ID3D11VideoProcessor, + ) -> HRESULT, + fn CreateAuthenticatedChannel( + ChannelType: D3D11_AUTHENTICATED_CHANNEL_TYPE, + ppAuthenticatedChannel: *mut *mut ID3D11AuthenticatedChannel, + ) -> HRESULT, + fn CreateCryptoSession( + pCryptoType: *const GUID, + pDecoderProfile: *const GUID, + pKeyExchangeType: *const GUID, + ppCryptoSession: *mut *mut ID3D11CryptoSession, + ) -> HRESULT, + fn CreateVideoDecoderOutputView( + pResource: *mut ID3D11Resource, + pDesc: *const D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC, + ppVDOVView: *mut *mut ID3D11VideoDecoderOutputView, + ) -> HRESULT, + fn CreateVideoProcessorInputView( + pResource: *mut ID3D11Resource, + pEnum: *mut ID3D11VideoProcessorEnumerator, + pDesc: *const D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC, + ppVPIView: *mut *mut ID3D11VideoProcessorInputView, + ) -> HRESULT, + fn CreateVideoProcessorOutputView( + pResource: *mut ID3D11Resource, + pEnum: *mut ID3D11VideoProcessorEnumerator, + pDesc: *const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC, + ppVPOView: *mut *mut ID3D11VideoProcessorOutputView, + ) -> HRESULT, + fn CreateVideoProcessorEnumerator( + pDesc: *const D3D11_VIDEO_PROCESSOR_CONTENT_DESC, + ppEnum: *mut *mut ID3D11VideoProcessorEnumerator, + ) -> HRESULT, + fn GetVideoDecoderProfileCount() -> UINT, + fn GetVideoDecoderProfile( + Index: UINT, + pDecoderProfile: *mut GUID, + ) -> HRESULT, + fn CheckVideoDecoderFormat( + pDecoderProfile: *const GUID, + Format: DXGI_FORMAT, + pSupported: *mut BOOL, + ) -> HRESULT, + fn GetVideoDecoderConfigCount( + pDesc: *const D3D11_VIDEO_DECODER_DESC, + pCount: *mut UINT, + ) -> HRESULT, + fn GetVideoDecoderConfig( + pDesc: *const D3D11_VIDEO_DECODER_DESC, + Index: UINT, + pConfig: *mut D3D11_VIDEO_DECODER_CONFIG, + ) -> HRESULT, + fn GetContentProtectionCaps( + pCryptoType: *const GUID, + pDecoderProfile: *const GUID, + pCaps: *mut D3D11_VIDEO_CONTENT_PROTECTION_CAPS, + ) -> HRESULT, + fn CheckCryptoKeyExchange( + pCryptoType: *const GUID, + pDecoderProfile: *const GUID, + Index: UINT, + pKeyExchangeType: *mut GUID, + ) -> HRESULT, + fn SetPrivateData( + guid: REFGUID, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn SetPrivateDataInterface( + guid: REFGUID, + pData: *const IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb6f6ddb, 0xac77, 0x4e88, 0x82, 0x53, 0x81, 0x9d, 0xf9, 0xbb, 0xf1, 0x40)] +interface ID3D11Device(ID3D11DeviceVtbl): IUnknown(IUnknownVtbl) { + fn CreateBuffer( + pDesc: *const D3D11_BUFFER_DESC, + pInitialData: *const D3D11_SUBRESOURCE_DATA, + ppBuffer: *mut *mut ID3D11Buffer, + ) -> HRESULT, + fn CreateTexture1D( + pDesc: *const D3D11_TEXTURE1D_DESC, + pInitialData: *const D3D11_SUBRESOURCE_DATA, + ppTexture1D: *mut *mut ID3D11Texture1D, + ) -> HRESULT, + fn CreateTexture2D( + pDesc: *const D3D11_TEXTURE2D_DESC, + pInitialData: *const D3D11_SUBRESOURCE_DATA, + ppTexture2D: *mut *mut ID3D11Texture2D, + ) -> HRESULT, + fn CreateTexture3D( + pDesc: *const D3D11_TEXTURE3D_DESC, + pInitialData: *const D3D11_SUBRESOURCE_DATA, + ppTexture3D: *mut *mut ID3D11Texture3D, + ) -> HRESULT, + fn CreateShaderResourceView( + pResource: *mut ID3D11Resource, + pDesc: *const D3D11_SHADER_RESOURCE_VIEW_DESC, + ppSRView: *mut *mut ID3D11ShaderResourceView, + ) -> HRESULT, + fn CreateUnorderedAccessView( + pResource: *mut ID3D11Resource, + pDesc: *const D3D11_UNORDERED_ACCESS_VIEW_DESC, + ppUAView: *mut *mut ID3D11UnorderedAccessView, + ) -> HRESULT, + fn CreateRenderTargetView( + pResource: *mut ID3D11Resource, + pDesc: *const D3D11_RENDER_TARGET_VIEW_DESC, + ppRTView: *mut *mut ID3D11RenderTargetView, + ) -> HRESULT, + fn CreateDepthStencilView( + pResource: *mut ID3D11Resource, + pDesc: *const D3D11_DEPTH_STENCIL_VIEW_DESC, + ppDepthStencilView: *mut *mut ID3D11DepthStencilView, + ) -> HRESULT, + fn CreateInputLayout( + pInputElementDescs: *const D3D11_INPUT_ELEMENT_DESC, + NumElements: UINT, + pShaderBytecodeWithInputSignature: *const c_void, + BytecodeLength: SIZE_T, + ppInputLayout: *mut *mut ID3D11InputLayout, + ) -> HRESULT, + fn CreateVertexShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppVertexShader: *mut *mut ID3D11VertexShader, + ) -> HRESULT, + fn CreateGeometryShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppGeometryShader: *mut *mut ID3D11GeometryShader, + ) -> HRESULT, + fn CreateGeometryShaderWithStreamOutput( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pSODeclaration: *const D3D11_SO_DECLARATION_ENTRY, + NumEntries: UINT, + pBufferStrides: *const UINT, + NumStrides: UINT, + RasterizedStream: UINT, + pClassLinkage: *mut ID3D11ClassLinkage, + ppGeometryShader: *mut *mut ID3D11GeometryShader, + ) -> HRESULT, + fn CreatePixelShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppPixelShader: *mut *mut ID3D11PixelShader, + ) -> HRESULT, + fn CreateHullShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppHullShader: *mut *mut ID3D11HullShader, + ) -> HRESULT, + fn CreateDomainShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppDomainShader: *mut *mut ID3D11DomainShader, + ) -> HRESULT, + fn CreateComputeShader( + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, + pClassLinkage: *mut ID3D11ClassLinkage, + ppComputeShader: *mut *mut ID3D11ComputeShader, + ) -> HRESULT, + fn CreateClassLinkage( + ppLinkage: *mut *mut ID3D11ClassLinkage, + ) -> HRESULT, + fn CreateBlendState( + pBlendStateDesc: *const D3D11_BLEND_DESC, + ppBlendState: *mut *mut ID3D11BlendState, + ) -> HRESULT, + fn CreateDepthStencilState( + pDepthStencilDesc: *const D3D11_DEPTH_STENCIL_DESC, + ppDepthStencilState: *mut *mut ID3D11DepthStencilState, + ) -> HRESULT, + fn CreateRasterizerState( + pRasterizerDesc: *const D3D11_RASTERIZER_DESC, + ppRasterizerState: *mut *mut ID3D11RasterizerState, + ) -> HRESULT, + fn CreateSamplerState( + pSamplerDesc: *const D3D11_SAMPLER_DESC, + ppSamplerState: *mut *mut ID3D11SamplerState, + ) -> HRESULT, + fn CreateQuery( + pQueryDesc: *const D3D11_QUERY_DESC, + ppQuery: *mut *mut ID3D11Query, + ) -> HRESULT, + fn CreatePredicate( + pPredicateDesc: *const D3D11_QUERY_DESC, + ppPredicate: *mut *mut ID3D11Predicate, + ) -> HRESULT, + fn CreateCounter( + pCounterDesc: *const D3D11_COUNTER_DESC, + ppCounter: *mut *mut ID3D11Counter, + ) -> HRESULT, + fn CreateDeferredContext( + ContextFlags: UINT, + ppDeferredContext: *mut *mut ID3D11DeviceContext, + ) -> HRESULT, + fn OpenSharedResource( + hResource: HANDLE, + ReturnedInterface: REFIID, + ppResource: *mut *mut c_void, + ) -> HRESULT, + fn CheckFormatSupport( + Format: DXGI_FORMAT, + pFormatSupport: *mut UINT, + ) -> HRESULT, + fn CheckMultisampleQualityLevels( + Format: DXGI_FORMAT, + SampleCount: UINT, + pNumQualityLevels: *mut UINT, + ) -> HRESULT, + fn CheckCounterInfo( + pCounterInfo: *mut D3D11_COUNTER_INFO, + ) -> (), + fn CheckCounter( + pDesc: *const D3D11_COUNTER_DESC, + pType: *mut D3D11_COUNTER_TYPE, + pActiveCounters: *mut UINT, + szName: LPSTR, + pNameLength: *mut UINT, + szUnits: LPSTR, + pUnitsLength: *mut UINT, + szDescription: LPSTR, + pDescriptionLength: *mut UINT, + ) -> HRESULT, + fn CheckFeatureSupport( + Feature: D3D11_FEATURE, + pFeatureSupportData: *mut c_void, + FeatureSupportDataSize: UINT, + ) -> HRESULT, + fn GetPrivateData( + guid: REFGUID, + pDataSize: *mut UINT, + pData: *mut c_void, + ) -> HRESULT, + fn SetPrivateData( + guid: REFGUID, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn SetPrivateDataInterface( + guid: REFGUID, + pData: *const IUnknown, + ) -> HRESULT, + fn GetFeatureLevel() -> D3D_FEATURE_LEVEL, + fn GetCreationFlags() -> UINT, + fn GetDeviceRemovedReason() -> HRESULT, + fn GetImmediateContext( + ppImmediateContext: *mut *mut ID3D11DeviceContext, + ) -> (), + fn SetExceptionMode( + RaiseFlags: UINT, + ) -> HRESULT, + fn GetExceptionMode() -> UINT, +}} +ENUM!{enum D3D11_CREATE_DEVICE_FLAG { + D3D11_CREATE_DEVICE_SINGLETHREADED = 0x1, + D3D11_CREATE_DEVICE_DEBUG = 0x2, + D3D11_CREATE_DEVICE_SWITCH_TO_REF = 0x4, + D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS = 0x8, + D3D11_CREATE_DEVICE_BGRA_SUPPORT = 0x20, + D3D11_CREATE_DEVICE_DEBUGGABLE = 0x40, + D3D11_CREATE_DEVICE_PREVENT_ALTERING_LAYER_SETTINGS_FROM_REGISTRY = 0x80, + D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT = 0x100, + D3D11_CREATE_DEVICE_VIDEO_SUPPORT = 0x800, +}} +pub const D3D11_SDK_VERSION: DWORD = 7; +#[inline] +pub fn D3D11CalcSubresource(MipSlice: UINT, ArraySlice: UINT, MipLevels: UINT) -> UINT { + MipSlice + ArraySlice * MipLevels +} +extern "system" { + pub fn D3D11CreateDevice( + pAdapter: *mut IDXGIAdapter, + DriverType: D3D_DRIVER_TYPE, + Software: HMODULE, + Flags: UINT, + pFeatureLevels: *const D3D_FEATURE_LEVEL, + FeatureLevels: UINT, + SDKVersion: UINT, + ppDevice: *mut *mut ID3D11Device, + pFeatureLevel: *mut D3D_FEATURE_LEVEL, + ppImmediateContext: *mut *mut ID3D11DeviceContext, + ) -> HRESULT; + pub fn D3D11CreateDeviceAndSwapChain( + pAdapter: *mut IDXGIAdapter, + DriverType: D3D_DRIVER_TYPE, + Software: HMODULE, + Flags: UINT, + pFeatureLevels: *const D3D_FEATURE_LEVEL, + FeatureLevels: UINT, + SDKVersion: UINT, + pSwapChainDesc: *const DXGI_SWAP_CHAIN_DESC, + ppSwapChain: *mut *mut IDXGISwapChain, + ppDevice: *mut *mut ID3D11Device, + pFeatureLevel: *mut D3D_FEATURE_LEVEL, + ppImmediateContext: *mut *mut ID3D11DeviceContext, + ) -> HRESULT; +} +DEFINE_GUID!{IID_ID3D11DeviceChild, + 0x1841e5c8, 0x16b0, 0x489b, 0xbc, 0xc8, 0x44, 0xcf, 0xb0, 0xd5, 0xde, 0xae} +DEFINE_GUID!{IID_ID3D11DepthStencilState, + 0x03823efb, 0x8d8f, 0x4e1c, 0x9a, 0xa2, 0xf6, 0x4b, 0xb2, 0xcb, 0xfd, 0xf1} +DEFINE_GUID!{IID_ID3D11BlendState, + 0x75b68faa, 0x347d, 0x4159, 0x8f, 0x45, 0xa0, 0x64, 0x0f, 0x01, 0xcd, 0x9a} +DEFINE_GUID!{IID_ID3D11RasterizerState, + 0x9bb4ab81, 0xab1a, 0x4d8f, 0xb5, 0x06, 0xfc, 0x04, 0x20, 0x0b, 0x6e, 0xe7} +DEFINE_GUID!{IID_ID3D11Resource, + 0xdc8e63f3, 0xd12b, 0x4952, 0xb4, 0x7b, 0x5e, 0x45, 0x02, 0x6a, 0x86, 0x2d} +DEFINE_GUID!{IID_ID3D11Buffer, + 0x48570b85, 0xd1ee, 0x4fcd, 0xa2, 0x50, 0xeb, 0x35, 0x07, 0x22, 0xb0, 0x37} +DEFINE_GUID!{IID_ID3D11Texture1D, + 0xf8fb5c27, 0xc6b3, 0x4f75, 0xa4, 0xc8, 0x43, 0x9a, 0xf2, 0xef, 0x56, 0x4c} +DEFINE_GUID!{IID_ID3D11Texture2D, + 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c} +DEFINE_GUID!{IID_ID3D11Texture3D, + 0x037e866e, 0xf56d, 0x4357, 0xa8, 0xaf, 0x9d, 0xab, 0xbe, 0x6e, 0x25, 0x0e} +DEFINE_GUID!{IID_ID3D11View, + 0x839d1216, 0xbb2e, 0x412b, 0xb7, 0xf4, 0xa9, 0xdb, 0xeb, 0xe0, 0x8e, 0xd1} +DEFINE_GUID!{IID_ID3D11ShaderResourceView, + 0xb0e06fe0, 0x8192, 0x4e1a, 0xb1, 0xca, 0x36, 0xd7, 0x41, 0x47, 0x10, 0xb2} +DEFINE_GUID!{IID_ID3D11RenderTargetView, + 0xdfdba067, 0x0b8d, 0x4865, 0x87, 0x5b, 0xd7, 0xb4, 0x51, 0x6c, 0xc1, 0x64} +DEFINE_GUID!{IID_ID3D11DepthStencilView, + 0x9fdac92a, 0x1876, 0x48c3, 0xaf, 0xad, 0x25, 0xb9, 0x4f, 0x84, 0xa9, 0xb6} +DEFINE_GUID!{IID_ID3D11UnorderedAccessView, + 0x28acf509, 0x7f5c, 0x48f6, 0x86, 0x11, 0xf3, 0x16, 0x01, 0x0a, 0x63, 0x80} +DEFINE_GUID!{IID_ID3D11VertexShader, + 0x3b301d64, 0xd678, 0x4289, 0x88, 0x97, 0x22, 0xf8, 0x92, 0x8b, 0x72, 0xf3} +DEFINE_GUID!{IID_ID3D11HullShader, + 0x8e5c6061, 0x628a, 0x4c8e, 0x82, 0x64, 0xbb, 0xe4, 0x5c, 0xb3, 0xd5, 0xdd} +DEFINE_GUID!{IID_ID3D11DomainShader, + 0xf582c508, 0x0f36, 0x490c, 0x99, 0x77, 0x31, 0xee, 0xce, 0x26, 0x8c, 0xfa} +DEFINE_GUID!{IID_ID3D11GeometryShader, + 0x38325b96, 0xeffb, 0x4022, 0xba, 0x02, 0x2e, 0x79, 0x5b, 0x70, 0x27, 0x5c} +DEFINE_GUID!{IID_ID3D11PixelShader, + 0xea82e40d, 0x51dc, 0x4f33, 0x93, 0xd4, 0xdb, 0x7c, 0x91, 0x25, 0xae, 0x8c} +DEFINE_GUID!{IID_ID3D11ComputeShader, + 0x4f5b196e, 0xc2bd, 0x495e, 0xbd, 0x01, 0x1f, 0xde, 0xd3, 0x8e, 0x49, 0x69} +DEFINE_GUID!{IID_ID3D11InputLayout, + 0xe4819ddc, 0x4cf0, 0x4025, 0xbd, 0x26, 0x5d, 0xe8, 0x2a, 0x3e, 0x07, 0xb7} +DEFINE_GUID!{IID_ID3D11SamplerState, + 0xda6fea51, 0x564c, 0x4487, 0x98, 0x10, 0xf0, 0xd0, 0xf9, 0xb4, 0xe3, 0xa5} +DEFINE_GUID!{IID_ID3D11Asynchronous, + 0x4b35d0cd, 0x1e15, 0x4258, 0x9c, 0x98, 0x1b, 0x13, 0x33, 0xf6, 0xdd, 0x3b} +DEFINE_GUID!{IID_ID3D11Query, + 0xd6c00747, 0x87b7, 0x425e, 0xb8, 0x4d, 0x44, 0xd1, 0x08, 0x56, 0x0a, 0xfd} +DEFINE_GUID!{IID_ID3D11Predicate, + 0x9eb576dd, 0x9f77, 0x4d86, 0x81, 0xaa, 0x8b, 0xab, 0x5f, 0xe4, 0x90, 0xe2} +DEFINE_GUID!{IID_ID3D11Counter, + 0x6e8c49fb, 0xa371, 0x4770, 0xb4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xb7, 0x41} +DEFINE_GUID!{IID_ID3D11ClassInstance, + 0xa6cd7faa, 0xb0b7, 0x4a2f, 0x94, 0x36, 0x86, 0x62, 0xa6, 0x57, 0x97, 0xcb} +DEFINE_GUID!{IID_ID3D11ClassLinkage, + 0xddf57cba, 0x9543, 0x46e4, 0xa1, 0x2b, 0xf2, 0x07, 0xa0, 0xfe, 0x7f, 0xed} +DEFINE_GUID!{IID_ID3D11CommandList, + 0xa24bc4d1, 0x769e, 0x43f7, 0x80, 0x13, 0x98, 0xff, 0x56, 0x6c, 0x18, 0xe2} +DEFINE_GUID!{IID_ID3D11DeviceContext, + 0xc0bfa96c, 0xe089, 0x44fb, 0x8e, 0xaf, 0x26, 0xf8, 0x79, 0x61, 0x90, 0xda} +DEFINE_GUID!{IID_ID3D11VideoDecoder, + 0x3c9c5b51, 0x995d, 0x48d1, 0x9b, 0x8d, 0xfa, 0x5c, 0xae, 0xde, 0xd6, 0x5c} +DEFINE_GUID!{IID_ID3D11VideoProcessorEnumerator, + 0x31627037, 0x53ab, 0x4200, 0x90, 0x61, 0x05, 0xfa, 0xa9, 0xab, 0x45, 0xf9} +DEFINE_GUID!{IID_ID3D11VideoProcessor, + 0x1d7b0652, 0x185f, 0x41c6, 0x85, 0xce, 0x0c, 0x5b, 0xe3, 0xd4, 0xae, 0x6c} +DEFINE_GUID!{IID_ID3D11AuthenticatedChannel, + 0x3015a308, 0xdcbd, 0x47aa, 0xa7, 0x47, 0x19, 0x24, 0x86, 0xd1, 0x4d, 0x4a} +DEFINE_GUID!{IID_ID3D11CryptoSession, + 0x9b32f9ad, 0xbdcc, 0x40a6, 0xa3, 0x9d, 0xd5, 0xc8, 0x65, 0x84, 0x57, 0x20} +DEFINE_GUID!{IID_ID3D11VideoDecoderOutputView, + 0xc2931aea, 0x2a85, 0x4f20, 0x86, 0x0f, 0xfb, 0xa1, 0xfd, 0x25, 0x6e, 0x18} +DEFINE_GUID!{IID_ID3D11VideoProcessorInputView, + 0x11ec5a5f, 0x51dc, 0x4945, 0xab, 0x34, 0x6e, 0x8c, 0x21, 0x30, 0x0e, 0xa5} +DEFINE_GUID!{IID_ID3D11VideoProcessorOutputView, + 0xa048285e, 0x25a9, 0x4527, 0xbd, 0x93, 0xd6, 0x8b, 0x68, 0xc4, 0x42, 0x54} +DEFINE_GUID!{IID_ID3D11VideoContext, + 0x61f21c45, 0x3c0e, 0x4a74, 0x9c, 0xea, 0x67, 0x10, 0x0d, 0x9a, 0xd5, 0xe4} +DEFINE_GUID!{IID_ID3D11VideoDevice, + 0x10ec4d5b, 0x975a, 0x4689, 0xb9, 0xe4, 0xd0, 0xaa, 0xc3, 0x0f, 0xe3, 0x33} +DEFINE_GUID!{IID_ID3D11Device, + 0xdb6f6ddb, 0xac77, 0x4e88, 0x82, 0x53, 0x81, 0x9d, 0xf9, 0xbb, 0xf1, 0x40} diff --git a/winapi/src/um/d3d11_1.rs b/winapi/src/um/d3d11_1.rs new file mode 100644 index 000000000..7b0b46ec2 --- /dev/null +++ b/winapi/src/um/d3d11_1.rs @@ -0,0 +1,484 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::basetsd::{UINT64, UINT8}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::{DXGI_COLOR_SPACE_TYPE, DXGI_RATIONAL}; +use shared::guiddef::{GUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, UINT}; +use um::d3d11::{ + D3D11_BLEND, D3D11_BLEND_OP, D3D11_BOX, D3D11_CULL_MODE, D3D11_FILL_MODE, D3D11_RECT, + D3D11_VIDEO_DECODER_BUFFER_TYPE, D3D11_VIDEO_DECODER_CONFIG, D3D11_VIDEO_DECODER_DESC, + ID3D11BlendState, ID3D11BlendStateVtbl, ID3D11Buffer, ID3D11CryptoSession, ID3D11Device, + ID3D11DeviceChild, ID3D11DeviceChildVtbl, ID3D11DeviceContext, ID3D11DeviceContextVtbl, + ID3D11DeviceVtbl, ID3D11RasterizerState, ID3D11RasterizerStateVtbl, ID3D11Resource, + ID3D11VideoContext, ID3D11VideoContextVtbl, ID3D11VideoDecoder, ID3D11VideoDevice, + ID3D11VideoDeviceVtbl, ID3D11VideoProcessor, ID3D11VideoProcessorEnumerator, + ID3D11VideoProcessorEnumeratorVtbl, ID3D11View +}; +use um::d3dcommon::D3D_FEATURE_LEVEL; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LPCWSTR}; +DEFINE_GUID!{IID_ID3D11BlendState1, + 0xcc86fabe, 0xda55, 0x401d, 0x85, 0xe7, 0xe3, 0xc9, 0xde, 0x28, 0x77, 0xe9} +DEFINE_GUID!{IID_ID3D11RasterizerState1, + 0x1217d7a6, 0x5039, 0x418c, 0xb0, 0x42, 0x9c, 0xbe, 0x25, 0x6a, 0xfd, 0x6e} +DEFINE_GUID!{IID_ID3DDeviceContextState, + 0x5c1e0d8a, 0x7c23, 0x48f9, 0x8c, 0x59, 0xa9, 0x29, 0x58, 0xce, 0xff, 0x11} +DEFINE_GUID!{IID_ID3D11DeviceContext1, + 0xbb2c6faa, 0xb5fb, 0x4082, 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1} +DEFINE_GUID!{IID_ID3D11VideoContext1, + 0xa7f026da, 0xa5f8, 0x4487, 0xa5, 0x64, 0x15, 0xe3, 0x43, 0x57, 0x65, 0x1e} +DEFINE_GUID!{IID_ID3D11VideoDevice1, + 0x29da1d51, 0x1321, 0x4454, 0x80, 0x4b, 0xf5, 0xfc, 0x9f, 0x86, 0x1f, 0x0f} +DEFINE_GUID!{IID_ID3D11VideoProcessorEnumerator1, + 0x465217f2, 0x5568, 0x43cf, 0xb5, 0xb9, 0xf6, 0x1d, 0x54, 0x53, 0x1c, 0xa1} +DEFINE_GUID!{IID_ID3D11Device1, + 0xa04bfb29, 0x08ef, 0x43d6, 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86} +DEFINE_GUID!{IID_ID3DUserDefinedAnnotation, + 0xb2daad8b, 0x03d4, 0x4dbf, 0x95, 0xeb, 0x32, 0xab, 0x4b, 0x63, 0xd0, 0xab} +ENUM!{enum D3D11_COPY_FLAGS { + D3D11_COPY_NO_OVERWRITE = 0x00000001, + D3D11_COPY_DISCARD = 0x00000002, +}} +ENUM!{enum D3D11_LOGIC_OP { + D3D11_LOGIC_OP_CLEAR = 0, + D3D11_LOGIC_OP_SET = 1, + D3D11_LOGIC_OP_COPY = 2, + D3D11_LOGIC_OP_COPY_INVERTED = 3, + D3D11_LOGIC_OP_NOOP = 4, + D3D11_LOGIC_OP_INVERT = 5, + D3D11_LOGIC_OP_AND = 6, + D3D11_LOGIC_OP_NAND = 7, + D3D11_LOGIC_OP_OR = 8, + D3D11_LOGIC_OP_NOR = 9, + D3D11_LOGIC_OP_XOR = 10, + D3D11_LOGIC_OP_EQUIV = 11, + D3D11_LOGIC_OP_AND_REVERSE = 12, + D3D11_LOGIC_OP_AND_INVERTED = 13, + D3D11_LOGIC_OP_OR_REVERSE = 14, + D3D11_LOGIC_OP_OR_INVERTED = 15, +}} +STRUCT!{struct D3D11_RENDER_TARGET_BLEND_DESC1 { + BlendEnable: BOOL, + LogicOpEnable: BOOL, + SrcBlend: D3D11_BLEND, + DestBlend: D3D11_BLEND, + BlendOp: D3D11_BLEND_OP, + SrcBlendAlpha: D3D11_BLEND, + DestBlendAlpha: D3D11_BLEND, + BlendOpAlpha: D3D11_BLEND_OP, + LogicOp: D3D11_LOGIC_OP, + RenderTargetWriteMask: UINT8, +}} +STRUCT!{struct D3D11_BLEND_DESC1 { + AlphaToCoverageEnable: BOOL, + IndependentBlendEnable: BOOL, + RenderTarget: [D3D11_RENDER_TARGET_BLEND_DESC1; 8], +}} +RIDL!{#[uuid(0xcc86fabe, 0xda55, 0x401d, 0x85, 0xe7, 0xe3, 0xc9, 0xde, 0x28, 0x77, 0xe9)] +interface ID3D11BlendState1(ID3D11BlendState1Vtbl): ID3D11BlendState(ID3D11BlendStateVtbl) { + fn GetDesc1( + pDesc: *mut D3D11_BLEND_DESC1, + ) -> (), +}} +STRUCT!{struct D3D11_RASTERIZER_DESC1 { + FillMode: D3D11_FILL_MODE, + CullMode: D3D11_CULL_MODE, + FrontCounterClockwise: BOOL, + DepthBias: INT, + DepthBiasClamp: FLOAT, + SlopeScaledDepthBias: FLOAT, + DepthClipEnable: BOOL, + ScissorEnable: BOOL, + MultisampleEnable: BOOL, + AntialiasedLineEnable: BOOL, + ForcedSampleCount: UINT, +}} +RIDL!{#[uuid(0x1217d7a6, 0x5039, 0x418c, 0xb0, 0x42, 0x9c, 0xbe, 0x25, 0x6a, 0xfd, 0x6e)] +interface ID3D11RasterizerState1(ID3D11RasterizerState1Vtbl): + ID3D11RasterizerState(ID3D11RasterizerStateVtbl) { + fn GetDesc1( + pDesc: *mut D3D11_RASTERIZER_DESC1, + ) -> (), +}} +ENUM!{enum D3D11_1_CREATE_DEVICE_CONTEXT_STATE_FLAG { + D3D11_1_CREATE_DEVICE_CONTEXT_STATE_SINGLETHREADED = 0x1, +}} +RIDL!{#[uuid(0x5c1e0d8a, 0x7c23, 0x48f9, 0x8c, 0x59, 0xa9, 0x29, 0x58, 0xce, 0xff, 0x11)] +interface ID3DDeviceContextState(ID3DDeviceContextStateVtbl): + ID3D11DeviceChild(ID3D11DeviceChildVtbl) {}} +RIDL!{#[uuid(0xbb2c6faa, 0xb5fb, 0x4082, 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1)] +interface ID3D11DeviceContext1(ID3D11DeviceContext1Vtbl): + ID3D11DeviceContext(ID3D11DeviceContextVtbl) { + fn CopySubresourceRegion1( + pDstResource: *mut ID3D11Resource, + DstSubresource: UINT, + DstX: UINT, + DstY: UINT, + DstZ: UINT, + pSrcResource: *mut ID3D11Resource, + SrcSubresource: UINT, + pSrcBox: *const D3D11_BOX, + CopyFlags: UINT, + ) -> (), + fn UpdateSubresource1( + pDstResource: *mut ID3D11Resource, + DstSubresource: UINT, + pDstBox: *const D3D11_BOX, + pSrcData: *mut c_void, + SrcRowPitch: UINT, + SrcDepthPitch: UINT, + CopyFlags: UINT, + ) -> (), + fn DiscardResource( + pResource: *mut ID3D11Resource, + ) -> (), + fn DiscardView( + pResource: *mut ID3D11Resource, + ) -> (), + fn VSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn HSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn DSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn GSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn PSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn CSSetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *const *mut ID3D11Buffer, + pFirstConstant: *const UINT, + pNumConstants: *const UINT, + ) -> (), + fn VSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn HSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn DSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn GSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn PSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn CSGetConstantBuffers1( + StartSlot: UINT, + NumBuffers: UINT, + ppConstantBuffers: *mut *mut ID3D11Buffer, + pFirstConstant: *mut UINT, + pNumConstants: *mut UINT, + ) -> (), + fn SwapDeviceContextState( + pState: *mut ID3DDeviceContextState, + ppPreviousState: *mut *mut ID3DDeviceContextState, + ) -> (), + fn ClearView( + pView: *mut ID3D11View, + Color: [FLOAT; 4], + pRect: *const D3D11_RECT, + NumRects: UINT, + ) -> (), + fn DiscardView1( + pResourceView: *mut ID3D11View, + pRects: *const D3D11_RECT, + NumRects: UINT, + ) -> (), +}} +STRUCT!{struct D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK { + ClearSize: UINT, + EncryptedSize: UINT, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_BUFFER_DESC1 { + BufferType: D3D11_VIDEO_DECODER_BUFFER_TYPE, + DataOffset: UINT, + DataSize: UINT, + pIV: *mut c_void, + IVSize: UINT, + pSubSampleMappingBlock: *mut D3D11_VIDEO_DECODER_SUB_SAMPLE_MAPPING_BLOCK, + SubSampleMappingCount: UINT, +}} +STRUCT!{struct D3D11_VIDEO_DECODER_BEGIN_FRAME_CRYPTO_SESSION { + pCryptoSession: *mut ID3D11CryptoSession, + BlobSize: UINT, + pBlob: *mut c_void, + pKeyInfoId: *mut GUID, + PrivateDataSize: UINT, + pPrivateData: *mut c_void, +}} +ENUM!{enum D3D11_VIDEO_DECODER_CAPS { + D3D11_VIDEO_DECODER_CAPS_DOWNSAMPLE = 0x1, + D3D11_VIDEO_DECODER_CAPS_NON_REAL_TIME = 0x02, + D3D11_VIDEO_DECODER_CAPS_DOWNSAMPLE_DYNAMIC = 0x04, + D3D11_VIDEO_DECODER_CAPS_DOWNSAMPLE_REQUIRED = 0x08, + D3D11_VIDEO_DECODER_CAPS_UNSUPPORTED = 0x10, +}} +ENUM!{enum D3D11_VIDEO_PROCESSOR_BEHAVIOR_HINTS { + D3D11_VIDEO_PROCESSOR_BEHAVIOR_HINT_MULTIPLANE_OVERLAY_ROTATION = 0x01, + D3D11_VIDEO_PROCESSOR_BEHAVIOR_HINT_MULTIPLANE_OVERLAY_RESIZE = 0x02, + D3D11_VIDEO_PROCESSOR_BEHAVIOR_HINT_MULTIPLANE_OVERLAY_COLOR_SPACE_CONVERSION = 0x04, + D3D11_VIDEO_PROCESSOR_BEHAVIOR_HINT_TRIPLE_BUFFER_OUTPUT = 0x08, +}} +STRUCT!{struct D3D11_VIDEO_PROCESSOR_STREAM_BEHAVIOR_HINT { + Enable: BOOL, + Width: UINT, + Height: UINT, + Format: DXGI_FORMAT, +}} +ENUM!{enum D3D11_CRYPTO_SESSION_STATUS { + D3D11_CRYPTO_SESSION_STATUS_OK = 0, + D3D11_CRYPTO_SESSION_STATUS_KEY_LOST = 1, + D3D11_CRYPTO_SESSION_STATUS_KEY_AND_CONTENT_LOST = 2, +}} +STRUCT!{struct D3D11_KEY_EXCHANGE_HW_PROTECTION_INPUT_DATA { + PrivateDataSize: UINT, + HWProtectionDataSize: UINT, + pbInput: [BYTE; 4], +}} +STRUCT!{struct D3D11_KEY_EXCHANGE_HW_PROTECTION_OUTPUT_DATA { + PrivateDataSize: UINT, + MaxHWProtectionDataSize: UINT, + HWProtectionDataSize: UINT, + TransportTime: UINT64, + ExecutionTime: UINT64, + pbOutput: [BYTE; 4], +}} +STRUCT!{struct D3D11_KEY_EXCHANGE_HW_PROTECTION_DATA { + HWProtectionFunctionID: UINT, + pInputData: *mut D3D11_KEY_EXCHANGE_HW_PROTECTION_INPUT_DATA, + pOutputData: *mut D3D11_KEY_EXCHANGE_HW_PROTECTION_OUTPUT_DATA, + Status: HRESULT, +}} +STRUCT!{struct D3D11_VIDEO_SAMPLE_DESC { + Width: UINT, + Height: UINT, + Format: DXGI_FORMAT, + ColorSpace: DXGI_COLOR_SPACE_TYPE, +}} +RIDL!{#[uuid(0xa7f026da, 0xa5f8, 0x4487, 0xa5, 0x64, 0x15, 0xe3, 0x43, 0x57, 0x65, 0x1e)] +interface ID3D11VideoContext1(ID3D11VideoContext1Vtbl): + ID3D11VideoContext(ID3D11VideoContextVtbl) { + fn SubmitDecoderBuffers1( + pDecoder: *mut ID3D11VideoDecoder, + NumBuffers: UINT, + pBufferDesc: *const D3D11_VIDEO_DECODER_BUFFER_DESC1, + ) -> HRESULT, + fn GetDataForNewHardwareKey( + pCryptoSession: *mut ID3D11CryptoSession, + PrivateInputSize: UINT, + pPrivateInputData: *const c_void, + pPrivateOutputData: *mut UINT64, + ) -> HRESULT, + fn CheckCryptoSessionStatus( + pCryptoSession: *mut ID3D11CryptoSession, + pStatus: *mut D3D11_CRYPTO_SESSION_STATUS, + ) -> HRESULT, + fn DecoderEnableDownsampling( + pDecoder: *mut ID3D11VideoDecoder, + InputColorSpace: DXGI_COLOR_SPACE_TYPE, + pOutputDesc: *const D3D11_VIDEO_SAMPLE_DESC, + ReferenceFrameCount: UINT, + ) -> HRESULT, + fn DecoderUpdateDownsampling( + pDecoder: *mut ID3D11VideoDecoder, + pOutputDesc: *const D3D11_VIDEO_SAMPLE_DESC, + ) -> HRESULT, + fn VideoProcessorSetOutputColorSpace1( + pVideoProcessor: *mut ID3D11VideoProcessor, + ColorSpace: DXGI_COLOR_SPACE_TYPE, + ) -> (), + fn VideoProcessorSetOutputShaderUsage( + pVideoProcessor: *mut ID3D11VideoProcessor, + ShaderUsage: BOOL, + ) -> (), + fn VideoProcessorGetOutputColorSpace1( + pVideoProcessor: *mut ID3D11VideoProcessor, + pColorSpace: *mut DXGI_COLOR_SPACE_TYPE, + ) -> (), + fn VideoProcessorGetOutputShaderUsage( + pVideoProcessor: *mut ID3D11VideoProcessor, + pShaderUsage: *mut BOOL, + ) -> (), + fn VideoProcessorSetStreamColorSpace1( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + ColorSpace: DXGI_COLOR_SPACE_TYPE, + ) -> (), + fn VideoProcessorSetStreamMirror( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + Enable: BOOL, + FlipHorizontal: BOOL, + FlipVertical: BOOL, + ) -> (), + fn VideoProcessorGetStreamColorSpace1( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pColorSpace: *mut DXGI_COLOR_SPACE_TYPE, + ) -> (), + fn VideoProcessorGetStreamMirror( + pVideoProcessor: *mut ID3D11VideoProcessor, + StreamIndex: UINT, + pEnable: *mut BOOL, + pFlipHorizontal: *mut BOOL, + pFlipVertical: *mut BOOL, + ) -> (), + fn VideoProcessorGetBehaviorHints( + pVideoProcessor: *mut ID3D11VideoProcessor, + OutputWidth: UINT, + OutputHeight: UINT, + OutputFormat: DXGI_FORMAT, + StreamCount: UINT, + pStreams: *const D3D11_VIDEO_PROCESSOR_STREAM_BEHAVIOR_HINT, + pBehaviorHints: *mut UINT, + ) -> (), +}} +RIDL!{#[uuid(0x29da1d51, 0x1321, 0x4454, 0x80, 0x4b, 0xf5, 0xfc, 0x9f, 0x86, 0x1f, 0x0f)] +interface ID3D11VideoDevice1(ID3D11VideoDevice1Vtbl): ID3D11VideoDevice(ID3D11VideoDeviceVtbl) { + fn GetCryptoSessionPrivateDataSize( + pCryptoType: *const GUID, + pDecoderProfile: *const GUID, + pKeyExchangeType: *const GUID, + pPrivateInputSize: *mut UINT, + pPrivateOutputSize: *mut UINT, + ) -> HRESULT, + fn GetVideoDecoderCaps( + pDecoderProfile: *const GUID, + SampleWidth: UINT, + SampleHeight: UINT, + pFrameRate: *const DXGI_RATIONAL, + BitRate: UINT, + pCryptoType: *const GUID, + pDecoderCaps: *mut UINT, + ) -> HRESULT, + fn CheckVideoDecoderDownsampling( + pInputDesc: *const D3D11_VIDEO_DECODER_DESC, + InputColorSpace: DXGI_COLOR_SPACE_TYPE, + pInputConfig: *const D3D11_VIDEO_DECODER_CONFIG, + pFrameRate: *const DXGI_RATIONAL, + pOutputDesc: *const D3D11_VIDEO_SAMPLE_DESC, + pSupported: *mut BOOL, + pRealTimeHint: *mut BOOL, + ) -> HRESULT, + fn RecommendVideoDecoderDownsampleParameters( + pInputDesc: *const D3D11_VIDEO_DECODER_DESC, + InputColorSpace: DXGI_COLOR_SPACE_TYPE, + pInputConfig: *const D3D11_VIDEO_DECODER_CONFIG, + pRecommendedOutputDesc: *mut D3D11_VIDEO_SAMPLE_DESC, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x465217f2, 0x5568, 0x43cf, 0xb5, 0xb9, 0xf6, 0x1d, 0x54, 0x53, 0x1c, 0xa1)] +interface ID3D11VideoProcessorEnumerator1(ID3D11VideoProcessorEnumerator1Vtbl): + ID3D11VideoProcessorEnumerator(ID3D11VideoProcessorEnumeratorVtbl) { + fn CheckVideoProcessorFormatConversion( + InputFormat: DXGI_FORMAT, + InputCOlorSpace: DXGI_COLOR_SPACE_TYPE, + OutputFormat: DXGI_FORMAT, + OutputColorSpace: DXGI_COLOR_SPACE_TYPE, + pSupported: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa04bfb29, 0x08ef, 0x43d6, 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86)] +interface ID3D11Device1(ID3D11Device1Vtbl): ID3D11Device(ID3D11DeviceVtbl) { + fn GetImmediateContext1( + ppImmediateContext: *mut *mut ID3D11DeviceContext1, + ) -> (), + fn CreateDeferredContext1( + ContextFlags: UINT, + ppDeferredContext: *mut *mut ID3D11DeviceContext1, + ) -> HRESULT, + fn CreateBlendState( + pBlendStateDesc: *const D3D11_BLEND_DESC1, + ppBlendState: *mut *mut ID3D11BlendState1, + ) -> HRESULT, + fn CreateRasterizerState( + pRasterizerDesc: *const D3D11_RASTERIZER_DESC1, + ppRasterizerState: *mut *mut ID3D11RasterizerState1, + ) -> HRESULT, + fn CreateDeviceContextState( + Flags: UINT, + pFeatureLevels: *const D3D_FEATURE_LEVEL, + FeatureLevels: UINT, + SDKVersion: UINT, + EmulatedInterface: REFIID, + pChosenFeatureLevel: *mut D3D_FEATURE_LEVEL, + ppContextState: *mut *mut ID3DDeviceContextState, + ) -> HRESULT, + fn OpenSharedResource1( + hResource: HANDLE, + returnedInterface: REFIID, + ppResource: *mut *mut c_void, + ) -> HRESULT, + fn OpenSharedResourceByName( + Name: LPCWSTR, + dwDesiredAccess: DWORD, + returnedInterface: REFIID, + ppResource: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb2daad8b, 0x03d4, 0x4dbf, 0x95, 0xeb, 0x32, 0xab, 0x4b, 0x63, 0xd0, 0xab)] +interface ID3DUserDefinedAnnotation(ID3DUserDefinedAnnotationVtbl): IUnknown(IUnknownVtbl) { + fn BeginEvent( + Name: LPCWSTR, + ) -> INT, + fn EndEvent() -> INT, + fn SetMarker( + Name: LPCWSTR, + ) -> (), + fn GetStatus() -> BOOL, +}} diff --git a/winapi/src/um/d3d11_2.rs b/winapi/src/um/d3d11_2.rs new file mode 100644 index 000000000..28b655a05 --- /dev/null +++ b/winapi/src/um/d3d11_2.rs @@ -0,0 +1,146 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::basetsd::{UINT16, UINT64, UINT8}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::minwindef::{BOOL, INT, UINT}; +use um::d3d11::{ID3D11Buffer, ID3D11DeviceChild, ID3D11Resource}; +use um::d3d11_1::{ + ID3D11Device1, ID3D11Device1Vtbl, ID3D11DeviceContext1, ID3D11DeviceContext1Vtbl, +}; +use um::winnt::{HRESULT, LPCWSTR}; +DEFINE_GUID!{IID_ID3D11DeviceContext2, + 0x420d5b32, 0xb90c, 0x4da4, 0xbe, 0xf0, 0x35, 0x9f, 0x6a, 0x24, 0xa8, 0x3a} +DEFINE_GUID!{IID_ID3D11Device2, + 0x9d06dffa, 0xd1e5, 0x4d07, 0x83, 0xa8, 0x1b, 0xb1, 0x23, 0xf2, 0xf8, 0x41} +STRUCT!{struct D3D11_TILED_RESOURCE_COORDINATE { + X: UINT, + Y: UINT, + Z: UINT, + Subresource: UINT, +}} +STRUCT!{struct D3D11_TILE_REGION_SIZE { + NumTiles: UINT, + bUseBox: BOOL, + Width: UINT, + Height: UINT16, + Depth: UINT16, +}} +ENUM!{enum D3D11_TILE_MAPPING_FLAG { + D3D11_TILE_MAPPING_NO_OVERWRITE = 0x00000001, +}} +ENUM!{enum D3D11_TILE_RANGE_FLAG { + D3D11_TILE_RANGE_NULL = 0x00000001, + D3D11_TILE_RANGE_SKIP = 0x00000002, + D3D11_TILE_RANGE_REUSE_SINGLE_TILE = 0x00000004, +}} +STRUCT!{struct D3D11_SUBRESOURCE_TILING { + WidthInTiles: UINT, + HeightInTiles: UINT16, + DepthInTiles: UINT16, + StartTileIndexInOverallResource: UINT, +}} +STRUCT!{struct D3D11_TILE_SHAPE { + WidthInTexels: UINT, + HeightInTexels: UINT, + DepthInTexels: UINT, +}} +STRUCT!{struct D3D11_PACKED_MIP_DESC { + NumStandardMips: UINT8, + NumPackedMips: UINT8, + NumTilesForPackedMips: UINT, + StartTileIndexInOverallResource: UINT, +}} +ENUM!{enum D3D11_CHECK_MULTISAMPLE_QUALITY_LEVELS_FLAG { + D3D11_CHECK_MULTISAMPLE_QUALITY_LEVELS_TILED_RESOURCE = 0x00000001, +}} +ENUM!{enum D3D11_TILE_COPY_FLAG { + D3D11_TILE_COPY_NO_OVERWRITE = 0x00000001, + D3D11_TILE_COPY_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE = 0x00000002, + D3D11_TILE_COPY_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER = 0x00000004, +}} +RIDL!{#[uuid(0x420d5b32, 0xb90c, 0x4da4, 0xbe, 0xf0, 0x35, 0x9f, 0x6a, 0x24, 0xa8, 0x3a)] +interface ID3D11DeviceContext2(ID3D11DeviceContext2Vtbl): + ID3D11DeviceContext1(ID3D11DeviceContext1Vtbl) { + fn UpdateTileMappings( + pTiledResource: *mut ID3D11Resource, + NumTiledResourceRegions: UINT, + pTiledResourceRegionStartCoordinates: *const D3D11_TILED_RESOURCE_COORDINATE, + pTiledResourceRegionSizes: *const D3D11_TILE_REGION_SIZE, + pTilePool: *mut ID3D11Buffer, + NumRanges: UINT, + pRangeFlags: *const UINT, + pTilePoolStartOffsets: *const UINT, + pRangeTileCounts: *const UINT, + Flags: UINT, + ) -> HRESULT, + fn CopyTileMappings( + pDestTiledResource: *mut ID3D11Resource, + pDestRegionStartCoordinate: *const D3D11_TILED_RESOURCE_COORDINATE, + pSourceTiledResource: *mut ID3D11Resource, + pSourceRegionStartCoordinate: *const D3D11_TILED_RESOURCE_COORDINATE, + pTileRegionSize: *const D3D11_TILE_REGION_SIZE, + Flags: UINT, + ) -> HRESULT, + fn CopyTiles( + pTiledResource: *mut ID3D11Resource, + pTileRegionStartCoordinate: *const D3D11_TILED_RESOURCE_COORDINATE, + pTileRegionSize: *const D3D11_TILE_REGION_SIZE, + pBuffer: *mut ID3D11Buffer, + BufferStartOffsetInBytes: UINT64, + Flags: UINT, + ) -> (), + fn UpdateTiles( + pDestTiledResource: *mut ID3D11Resource, + pDestTileRegionStartCoordinate: *const D3D11_TILED_RESOURCE_COORDINATE, + pDestTileRegionSize: *const D3D11_TILE_REGION_SIZE, + pSourceTileData: *const c_void, + Flags: UINT, + ) -> (), + fn ResizeTilePool( + pTilePool: *mut ID3D11Buffer, + NewSizeInBytes: UINT64, + ) -> HRESULT, + fn TiledResourceBarrier( + pTiledResourceOrViewAccessBeforeBarrier: *mut ID3D11DeviceChild, + pTiledResourceOrViewAccessAfterBarrier: *mut ID3D11DeviceChild, + ) -> (), + fn IsAnnotationEnabled() -> BOOL, + fn SetMarkerInt( + pLabel: LPCWSTR, + Data: INT, + ) -> (), + fn BeginEventInt( + pLabel: LPCWSTR, + Data: INT, + ) -> (), + fn EndEvent() -> (), +}} +RIDL!{#[uuid(0x9d06dffa, 0xd1e5, 0x4d07, 0x83, 0xa8, 0x1b, 0xb1, 0x23, 0xf2, 0xf8, 0x41)] +interface ID3D11Device2(ID3D11Device2Vtbl): ID3D11Device1(ID3D11Device1Vtbl) { + fn GetImmediateContext2( + ppImmediateContext: *mut *mut ID3D11DeviceContext2, + ) -> (), + fn CreateDeferredContext2( + ContextFlags: UINT, + ppDeferredContext: *mut *mut ID3D11DeviceContext2, + ) -> HRESULT, + fn GetResourceTiling( + pTiledResource: *mut ID3D11Resource, + pNumTilesForEntireResource: *mut UINT, + pPackedMipDesc: *mut D3D11_PACKED_MIP_DESC, + pStandardTileShapeForNonPackedMips: *mut D3D11_TILE_SHAPE, + pNumSubresourceTilings: *mut UINT, + FirstSubresourceTilingToGet: UINT, + pSubresourceTilingsForNonPackedMips: *mut D3D11_SUBRESOURCE_TILING, + ) -> (), + fn CheckMultisampleQualityLevels1( + Format: DXGI_FORMAT, + SampleCount: UINT, + Flags: UINT, + pNumQualityLevels: *mut UINT, + ) -> HRESULT, +}} diff --git a/winapi/src/um/d3d11_3.rs b/winapi/src/um/d3d11_3.rs new file mode 100644 index 000000000..5ae721380 --- /dev/null +++ b/winapi/src/um/d3d11_3.rs @@ -0,0 +1,23 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3D11Texture2D1, + 0x51218251, 0x1e33, 0x4617, 0x9c, 0xcb, 0x4d, 0x3a, 0x43, 0x67, 0xe7, 0xbb} +DEFINE_GUID!{IID_ID3D11Texture3D1, + 0x0c711683, 0x2853, 0x4846, 0x9b, 0xb0, 0xf3, 0xe6, 0x06, 0x39, 0xe4, 0x6a} +DEFINE_GUID!{IID_ID3D11RasterizerState2, + 0x6fbd02fb, 0x209f, 0x46c4, 0xb0, 0x59, 0x2e, 0xd1, 0x55, 0x86, 0xa6, 0xac} +DEFINE_GUID!{IID_ID3D11ShaderResourceView1, + 0x91308b87, 0x9040, 0x411d, 0x8c, 0x67, 0xc3, 0x92, 0x53, 0xce, 0x38, 0x02} +DEFINE_GUID!{IID_ID3D11RenderTargetView1, + 0xffbe2e23, 0xf011, 0x418a, 0xac, 0x56, 0x5c, 0xee, 0xd7, 0xc5, 0xb9, 0x4b} +DEFINE_GUID!{IID_ID3D11UnorderedAccessView1, + 0x7b3b6153, 0xa886, 0x4544, 0xab, 0x37, 0x65, 0x37, 0xc8, 0x50, 0x04, 0x03} +DEFINE_GUID!{IID_ID3D11Query1, + 0x631b4766, 0x36dc, 0x461d, 0x8d, 0xb6, 0xc4, 0x7e, 0x13, 0xe6, 0x09, 0x16} +DEFINE_GUID!{IID_ID3D11DeviceContext3, + 0xb4e3c01d, 0xe79e, 0x4637, 0x91, 0xb2, 0x51, 0x0e, 0x9f, 0x4c, 0x9b, 0x8f} +DEFINE_GUID!{IID_ID3D11Device3, + 0xa05c8c37, 0xd2c6, 0x4732, 0xb3, 0xa0, 0x9c, 0xe0, 0xb0, 0xdc, 0x9a, 0xe6} diff --git a/winapi/src/um/d3d11_4.rs b/winapi/src/um/d3d11_4.rs new file mode 100644 index 000000000..5d0da98b5 --- /dev/null +++ b/winapi/src/um/d3d11_4.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3D11Device4, + 0x8992ab71, 0x02e6, 0x4b8d, 0xba, 0x48, 0xb0, 0x56, 0xdc, 0xda, 0x42, 0xc4} diff --git a/winapi/src/um/d3d11on12.rs b/winapi/src/um/d3d11on12.rs new file mode 100644 index 000000000..bf106a38b --- /dev/null +++ b/winapi/src/um/d3d11on12.rs @@ -0,0 +1,67 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the content of d3d11on12.h +use ctypes::c_void; +use shared::guiddef::IID; +use shared::minwindef::UINT; +use um::d3d11::{ID3D11Device, ID3D11DeviceContext, ID3D11Resource}; +use um::d3d12::D3D12_RESOURCE_STATES; +use um::d3dcommon::D3D_FEATURE_LEVEL; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +FN!{stdcall PFN_D3D11ON12_CREATE_DEVICE( + *mut IUnknown, + UINT, + *const D3D_FEATURE_LEVEL, + UINT, + *mut *mut IUnknown, + UINT, + UINT, + *mut *mut ID3D11Device, + *mut *mut ID3D11DeviceContext, + *mut D3D_FEATURE_LEVEL, +) -> HRESULT} +extern "system" { + pub fn D3D11On12CreateDevice( + pDevice: *mut IUnknown, + Flags: UINT, + pFeatureLevels: *const D3D_FEATURE_LEVEL, + FeatureLevels: UINT, + ppCommandQueues: *mut *mut IUnknown, + NumQueues: UINT, + NodeMask: UINT, + ppDevice: *mut *mut ID3D11Device, + ppImmediateContext: *mut *mut ID3D11DeviceContext, + pChosenFeatureLevel: *mut D3D_FEATURE_LEVEL, + ) -> HRESULT; +} +STRUCT!{struct D3D11_RESOURCE_FLAGS { + BindFlags: UINT, + MiscFlags: UINT, + CPUAccessFlags: UINT, + StructureByteStride: UINT, +}} +RIDL!{#[uuid(0x85611e73, 0x70a9, 0x490e, 0x96, 0x14, 0xa9, 0xe3, 0x02, 0x77, 0x79, 0x04)] +interface ID3D11On12Device(ID3D11On12DeviceVtbl): IUnknown(IUnknownVtbl) { + fn CreateWrappedResource( + pResource12: *mut IUnknown, + pFlags11: *const D3D11_RESOURCE_FLAGS, + InState: D3D12_RESOURCE_STATES, + OutState: D3D12_RESOURCE_STATES, + riid: *const IID, + ppResource11: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseWrappedResources( + ppResources: *mut *mut ID3D11Resource, + NumResources: UINT, + ) -> (), + fn AcquireWrappedResources( + ppResources: *mut *mut ID3D11Resource, + NumResources: UINT, + ) -> (), +}} +DEFINE_GUID!{IID_ID3D11On12Device, + 0x85611e73, 0x70a9, 0x490e, 0x96, 0x14, 0xa9, 0xe3, 0x02, 0x77, 0x79, 0x04} diff --git a/winapi/src/um/d3d11sdklayers.rs b/winapi/src/um/d3d11sdklayers.rs new file mode 100644 index 000000000..e70b6686e --- /dev/null +++ b/winapi/src/um/d3d11sdklayers.rs @@ -0,0 +1,2679 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_char; +use shared::basetsd::{SIZE_T, UINT64}; +use shared::dxgi::IDXGISwapChain; +use shared::minwindef::{BOOL, UINT}; +use um::d3d11::ID3D11DeviceContext; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +pub const D3D11_SDK_LAYERS_VERSION: UINT = 0x1; +pub const D3D11_DEBUG_FEATURE_FLUSH_PER_RENDER_OP: UINT = 0x1; +pub const D3D11_DEBUG_FEATURE_FINISH_PER_RENDER_OP: UINT = 0x2; +pub const D3D11_DEBUG_FEATURE_PRESENT_PER_RENDER_OP: UINT = 0x4; +pub const D3D11_DEBUG_FEATURE_ALWAYS_DISCARD_OFFERED_RESOURCE: UINT = 0x8; +pub const D3D11_DEBUG_FEATURE_NEVER_DISCARD_OFFERED_RESOURCE: UINT = 0x10; +pub const D3D11_DEBUG_FEATURE_AVOID_BEHAVIOR_CHANGING_DEBUG_AIDS: UINT = 0x40; +pub const D3D11_DEBUG_FEATURE_DISABLE_TILED_RESOURCE_MAPPING_TRACKING_AND_VALIDATION: UINT = 0x80; +ENUM!{enum D3D11_RLDO_FLAGS { + D3D11_RLDO_SUMMARY = 0x1, + D3D11_RLDO_DETAIL = 0x2, + D3D11_RLDO_IGNORE_INTERNAL = 0x4, +}} +RIDL!{#[uuid(0x79cf2233, 0x7536, 0x4948, 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60)] +interface ID3D11Debug(ID3D11DebugVtbl): IUnknown(IUnknownVtbl) { + fn SetFeatureMask( + Mask: UINT, + ) -> HRESULT, + fn GetFeatureMask() -> UINT, + fn SetPresentPerRenderOpDelay( + Milliseconds: UINT, + ) -> HRESULT, + fn GetPresentPerRenderOpDelay() -> UINT, + fn SetSwapChain( + pSwapChain: *mut IDXGISwapChain, + ) -> HRESULT, + fn GetSwapChain( + ppSwapChain: *mut *mut IDXGISwapChain, + ) -> HRESULT, + fn ValidateContext( + pContext: *const ID3D11DeviceContext, + ) -> HRESULT, + fn ReportLiveDeviceObjects( + Flags: D3D11_RLDO_FLAGS, + ) -> HRESULT, + fn ValidateContextForDispatch( + pContext: *mut ID3D11DeviceContext, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1ef337e3, 0x58e7, 0x4f83, 0xa6, 0x92, 0xdb, 0x22, 0x1f, 0x5e, 0xd4, 0x7e)] +interface ID3D11SwitchToRef(ID3D11SwitchToRefVtbl): IUnknown(IUnknownVtbl) { + fn SetUseRef( + UseRef: BOOL, + ) -> BOOL, + fn GetUseRef() -> BOOL, +}} +ENUM!{enum D3D11_SHADER_TRACKING_RESOURCE_TYPE { + D3D11_SHADER_TRACKING_RESOURCE_TYPE_NONE = 0, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_UAV_DEVICEMEMORY = 1, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_NON_UAV_DEVICEMEMORY = 2, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_ALL_DEVICEMEMORY = 3, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_GROUPSHARED_MEMORY = 4, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_ALL_SHARED_MEMORY = 5, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_GROUPSHARED_NON_UAV = 6, + D3D11_SHADER_TRACKING_RESOURCE_TYPE_ALL = 7, +}} +ENUM!{enum D3D11_SHADER_TRACKING_OPTION { + D3D11_SHADER_TRACKING_OPTION_IGNORE = 0, + D3D11_SHADER_TRACKING_OPTION_TRACK_UNINITIALIZED = 0x1, + D3D11_SHADER_TRACKING_OPTION_TRACK_RAW = 0x2, + D3D11_SHADER_TRACKING_OPTION_TRACK_WAR = 0x4, + D3D11_SHADER_TRACKING_OPTION_TRACK_WAW = 0x8, + D3D11_SHADER_TRACKING_OPTION_ALLOW_SAME = 0x10, + D3D11_SHADER_TRACKING_OPTION_TRACK_ATOMIC_CONSISTENCY = 0x20, + D3D11_SHADER_TRACKING_OPTION_TRACK_RAW_ACROSS_THREADGROUPS = 0x40, + D3D11_SHADER_TRACKING_OPTION_TRACK_WAR_ACROSS_THREADGROUPS = 0x80, + D3D11_SHADER_TRACKING_OPTION_TRACK_WAW_ACROSS_THREADGROUPS = 0x100, + D3D11_SHADER_TRACKING_OPTION_TRACK_ATOMIC_CONSISTENCY_ACROSS_THREADGROUPS = 0x200, + D3D11_SHADER_TRACKING_OPTION_UAV_SPECIFIC_FLAGS + = D3D11_SHADER_TRACKING_OPTION_TRACK_RAW_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_WAR_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_WAW_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_ATOMIC_CONSISTENCY_ACROSS_THREADGROUPS, + D3D11_SHADER_TRACKING_OPTION_ALL_HAZARDS = D3D11_SHADER_TRACKING_OPTION_TRACK_RAW + | D3D11_SHADER_TRACKING_OPTION_TRACK_WAR | D3D11_SHADER_TRACKING_OPTION_TRACK_WAW + | D3D11_SHADER_TRACKING_OPTION_TRACK_ATOMIC_CONSISTENCY + | D3D11_SHADER_TRACKING_OPTION_TRACK_RAW_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_WAR_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_WAW_ACROSS_THREADGROUPS + | D3D11_SHADER_TRACKING_OPTION_TRACK_ATOMIC_CONSISTENCY_ACROSS_THREADGROUPS, + D3D11_SHADER_TRACKING_OPTION_ALL_HAZARDS_ALLOWING_SAME + = D3D11_SHADER_TRACKING_OPTION_ALL_HAZARDS | D3D11_SHADER_TRACKING_OPTION_ALLOW_SAME, + D3D11_SHADER_TRACKING_OPTION_ALL_OPTIONS + = D3D11_SHADER_TRACKING_OPTION_ALL_HAZARDS_ALLOWING_SAME + | D3D11_SHADER_TRACKING_OPTION_TRACK_UNINITIALIZED, +}} +RIDL!{#[uuid(0x1911c771, 0x1587, 0x413e, 0xa7, 0xe0, 0xfb, 0x26, 0xc3, 0xde, 0x02, 0x68)] +interface ID3D11TracingDevice(ID3D11TracingDeviceVtbl): IUnknown(IUnknownVtbl) { + fn SetShaderTrackingOptionsByType( + ResourceTypeFlags: UINT, + Options: UINT, + ) -> HRESULT, + fn SetShaderTrackingOptions( + pShader: *const IUnknown, + Options: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x193dacdf, 0x0db2, 0x4c05, 0xa5, 0x5c, 0xef, 0x06, 0xca, 0xc5, 0x6f, 0xd9)] +interface ID3D11RefTrackingOptions(ID3D11RefTrackingOptionsVtbl): IUnknown(IUnknownVtbl) { + fn SetTrackingOptions( + Options: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x03916615, 0xc644, 0x418c, 0x9b, 0xf4, 0x75, 0xdb, 0x5b, 0xe6, 0x3c, 0xa0)] +interface ID3D11RefDefaultTrackingOptions(ID3D11RefDefaultTrackingOptionsVtbl): + IUnknown(IUnknownVtbl) { + fn SetTrackingOptions( + ResourceTypeFlags: UINT, + Options: UINT, + ) -> HRESULT, +}} +DEFINE_GUID!{DXGI_DEBUG_D3D11, + 0x4b99317b, 0xac39, 0x4aa6, 0xbb, 0x0b, 0xba, 0xa0, 0x47, 0x84, 0x79, 0x8f} +pub const D3D11_REGKEY_PATH: &'static str = "Software\\Microsoft\\Direct3D"; +pub const D3D11_MUTE_DEBUG_OUTPUT: &'static str = "MuteDebugOutput"; +pub const D3D11_ENABLE_BREAK_ON_MESSAGE: &'static str = "EnableBreakOnMessage"; +pub const D3D11_INFOQUEUE_STORAGE_FILTER_OVERRIDE: &'static str = "InfoQueueStorageFilterOverride"; +pub const D3D11_MUTE_CATEGORY: &'static str = "Mute_CATEGORY_%s"; +pub const D3D11_MUTE_SEVERITY: &'static str = "Mute_SEVERITY_%s"; +pub const D3D11_MUTE_ID_STRING: &'static str = "Mute_ID_%s"; +pub const D3D11_MUTE_ID_DECIMAL: &'static str = "Mute_ID_%d"; +pub const D3D11_UNMUTE_SEVERITY_INFO: &'static str = "Unmute_SEVERITY_INFO"; +pub const D3D11_BREAKON_CATEGORY: &'static str = "BreakOn_CATEGORY_%s"; +pub const D3D11_BREAKON_SEVERITY: &'static str = "BreakOn_SEVERITY_%s"; +pub const D3D11_BREAKON_ID_STRING: &'static str = "BreakOn_ID_%s"; +pub const D3D11_BREAKON_ID_DECIMAL: &'static str = "BreakOn_ID_%d"; +pub const D3D11_APPSIZE_STRING: &'static str = "Size"; +pub const D3D11_APPNAME_STRING: &'static str = "Name"; +pub const D3D11_FORCE_DEBUGGABLE: &'static str = "ForceDebuggable"; +pub const D3D11_FORCE_SHADER_SKIP_OPTIMIZATION: &'static str = "ForceShaderSkipOptimization"; +ENUM!{enum D3D11_MESSAGE_CATEGORY { + D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED = 0, + D3D11_MESSAGE_CATEGORY_MISCELLANEOUS = D3D11_MESSAGE_CATEGORY_APPLICATION_DEFINED + 1, + D3D11_MESSAGE_CATEGORY_INITIALIZATION = D3D11_MESSAGE_CATEGORY_MISCELLANEOUS + 1, + D3D11_MESSAGE_CATEGORY_CLEANUP = D3D11_MESSAGE_CATEGORY_INITIALIZATION + 1, + D3D11_MESSAGE_CATEGORY_COMPILATION = D3D11_MESSAGE_CATEGORY_CLEANUP + 1, + D3D11_MESSAGE_CATEGORY_STATE_CREATION = D3D11_MESSAGE_CATEGORY_COMPILATION + 1, + D3D11_MESSAGE_CATEGORY_STATE_SETTING = D3D11_MESSAGE_CATEGORY_STATE_CREATION + 1, + D3D11_MESSAGE_CATEGORY_STATE_GETTING = D3D11_MESSAGE_CATEGORY_STATE_SETTING + 1, + D3D11_MESSAGE_CATEGORY_RESOURCE_MANIPULATION = D3D11_MESSAGE_CATEGORY_STATE_GETTING + 1, + D3D11_MESSAGE_CATEGORY_EXECUTION = D3D11_MESSAGE_CATEGORY_RESOURCE_MANIPULATION + 1, + D3D11_MESSAGE_CATEGORY_SHADER = D3D11_MESSAGE_CATEGORY_EXECUTION + 1, +}} +ENUM!{enum D3D11_MESSAGE_SEVERITY { + D3D11_MESSAGE_SEVERITY_CORRUPTION = 0, + D3D11_MESSAGE_SEVERITY_ERROR = D3D11_MESSAGE_SEVERITY_CORRUPTION + 1, + D3D11_MESSAGE_SEVERITY_WARNING = D3D11_MESSAGE_SEVERITY_ERROR + 1, + D3D11_MESSAGE_SEVERITY_INFO = D3D11_MESSAGE_SEVERITY_WARNING + 1, + D3D11_MESSAGE_SEVERITY_MESSAGE = D3D11_MESSAGE_SEVERITY_INFO + 1, +}} +ENUM!{enum D3D11_MESSAGE_ID { + D3D11_MESSAGE_ID_UNKNOWN = 0, + D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_HAZARD = D3D11_MESSAGE_ID_UNKNOWN + 1, + D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_HAZARD + = D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_VSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_VSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_VSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_GSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_DEVICE_VSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_GSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_GSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_DEVICE_GSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_PSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_PSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_SOSETTARGETS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETS_HAZARD + 1, + D3D11_MESSAGE_ID_STRING_FROM_APPLICATION = D3D11_MESSAGE_ID_DEVICE_SOSETTARGETS_HAZARD + 1, + D3D11_MESSAGE_ID_CORRUPTED_THIS = D3D11_MESSAGE_ID_STRING_FROM_APPLICATION + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER1 = D3D11_MESSAGE_ID_CORRUPTED_THIS + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER2 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER1 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER3 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER2 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER4 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER3 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER5 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER4 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER6 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER5 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER7 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER6 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER8 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER7 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER9 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER8 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER10 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER9 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER11 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER10 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER12 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER11 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER13 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER12 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER14 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER13 + 1, + D3D11_MESSAGE_ID_CORRUPTED_PARAMETER15 = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER14 + 1, + D3D11_MESSAGE_ID_CORRUPTED_MULTITHREADING = D3D11_MESSAGE_ID_CORRUPTED_PARAMETER15 + 1, + D3D11_MESSAGE_ID_MESSAGE_REPORTING_OUTOFMEMORY + = D3D11_MESSAGE_ID_CORRUPTED_MULTITHREADING + 1, + D3D11_MESSAGE_ID_IASETINPUTLAYOUT_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_MESSAGE_REPORTING_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_IASETINPUTLAYOUT_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_IASETINDEXBUFFER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_VSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_IASETINDEXBUFFER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_VSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_VSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_VSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_VSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_GSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_VSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_GSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_GSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_GSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_GSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_SOSETTARGETS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_GSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_PSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_SOSETTARGETS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_PSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_PSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_PSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_PSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_RSSETSTATE_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_PSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_OMSETBLENDSTATE_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_RSSETSTATE_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_OMSETDEPTHSTENCILSTATE_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_OMSETBLENDSTATE_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_OMSETRENDERTARGETS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_OMSETDEPTHSTENCILSTATE_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_SETPREDICATION_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_OMSETRENDERTARGETS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_GETPRIVATEDATA_MOREDATA + = D3D11_MESSAGE_ID_SETPREDICATION_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDFREEDATA = D3D11_MESSAGE_ID_GETPRIVATEDATA_MOREDATA + 1, + D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDIUNKNOWN + = D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDFREEDATA + 1, + D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDFLAGS + = D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDIUNKNOWN + 1, + D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS + = D3D11_MESSAGE_ID_SETPRIVATEDATA_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_SETPRIVATEDATA_OUTOFMEMORY + = D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_SETPRIVATEDATA_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDSAMPLES + = D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDUSAGE + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDSAMPLES + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDBINDFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDUSAGE + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDMISCFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_UNRECOGNIZEDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDBINDFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDINITIALDATA + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDINITIALDATA + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDMIPLEVELS + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDMISCFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDMIPLEVELS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_NULLDESC = D3D11_MESSAGE_ID_CREATEBUFFER_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDCONSTANTBUFFERBINDINGS + = D3D11_MESSAGE_ID_CREATEBUFFER_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_LARGEALLOCATION + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDCONSTANTBUFFERBINDINGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATEBUFFER_LARGEALLOCATION + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDSAMPLES + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDUSAGE + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDSAMPLES + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDUSAGE + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_UNRECOGNIZEDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDINITIALDATA + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDINITIALDATA + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDMIPLEVELS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDMIPLEVELS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_NULLDESC + = D3D11_MESSAGE_ID_CREATETEXTURE1D_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_LARGEALLOCATION + = D3D11_MESSAGE_ID_CREATETEXTURE1D_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE1D_LARGEALLOCATION + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDSAMPLES + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDUSAGE + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDSAMPLES + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDUSAGE + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_UNRECOGNIZEDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDINITIALDATA + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDINITIALDATA + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDMIPLEVELS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDMIPLEVELS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_NULLDESC + = D3D11_MESSAGE_ID_CREATETEXTURE2D_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_LARGEALLOCATION + = D3D11_MESSAGE_ID_CREATETEXTURE2D_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE2D_LARGEALLOCATION + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDSAMPLES + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDUSAGE + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDSAMPLES + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDUSAGE + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDCPUACCESSFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_UNRECOGNIZEDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDBINDFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDCPUACCESSFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDINITIALDATA + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDBINDFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDINITIALDATA + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDMIPLEVELS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDMISCFLAGS + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDMIPLEVELS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATETEXTURE3D_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_NULLDESC + = D3D11_MESSAGE_ID_CREATETEXTURE3D_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATETEXTURE3D_LARGEALLOCATION + = D3D11_MESSAGE_ID_CREATETEXTURE3D_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATETEXTURE3D_LARGEALLOCATION + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDESC + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDESC + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDRESOURCE + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_UNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDESC + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_UNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDESC + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDRESOURCE + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDESC + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDESC + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDRESOURCE + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TOOMANYELEMENTS + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TOOMANYELEMENTS + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INCOMPATIBLEFORMAT + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOT + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INCOMPATIBLEFORMAT + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDINPUTSLOTCLASS + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOT + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_STEPRATESLOTCLASSMISMATCH + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDINPUTSLOTCLASS + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOTCLASSCHANGE + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_STEPRATESLOTCLASSMISMATCH + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSTEPRATECHANGE + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOTCLASSCHANGE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDALIGNMENT + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSTEPRATECHANGE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_DUPLICATESEMANTIC + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDALIGNMENT + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_UNPARSEABLEINPUTSIGNATURE + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_DUPLICATESEMANTIC + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_NULLSEMANTIC + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_UNPARSEABLEINPUTSIGNATURE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_MISSINGELEMENT + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_NULLSEMANTIC + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_NULLDESC + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_MISSINGELEMENT + 1, + D3D11_MESSAGE_ID_CREATEVERTEXSHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEVERTEXSHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMENTRIES + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSTREAMSTRIDEUNUSED + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMENTRIES + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDDECL + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSTREAMSTRIDEUNUSED + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_EXPECTEDDECL + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDDECL + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSLOT0EXPECTED + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_EXPECTEDDECL + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSLOT + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSLOT0EXPECTED + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_ONLYONEELEMENTPERSLOT + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSLOT + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCOMPONENTCOUNT + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_ONLYONEELEMENTPERSLOT + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTARTCOMPONENTANDCOMPONENTCOUNT + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCOMPONENTCOUNT + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDGAPDEFINITION = + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTARTCOMPONENTANDCOMPONENTCOUNT + + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_REPEATEDOUTPUT + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDGAPDEFINITION + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSTREAMSTRIDE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_REPEATEDOUTPUT + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGSEMANTIC + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSTREAMSTRIDE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MASKMISMATCH + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGSEMANTIC + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_CANTHAVEONLYGAPS + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MASKMISMATCH + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DECLTOOCOMPLEX + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_CANTHAVEONLYGAPS + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGOUTPUTSIGNATURE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DECLTOOCOMPLEX + 1, + D3D11_MESSAGE_ID_CREATEPIXELSHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGOUTPUTSIGNATURE + 1, + D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEPIXELSHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFILLMODE + = D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDCULLMODE + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFILLMODE + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDDEPTHBIASCLAMP + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDCULLMODE + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDSLOPESCALEDDEPTHBIAS + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDDEPTHBIASCLAMP + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDSLOPESCALEDDEPTHBIAS + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_NULLDESC + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHWRITEMASK + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHFUNC + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHWRITEMASK + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFAILOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHFUNC + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILZFAILOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFAILOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILPASSOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILZFAILOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFUNC + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILPASSOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFAILOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFUNC + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILZFAILOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFAILOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILPASSOP + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILZFAILOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFUNC + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILPASSOP + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFUNC + 1, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_NULLDESC + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLEND + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLEND + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLEND + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOP + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLEND + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLENDALPHA + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOP + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLENDALPHA + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLENDALPHA + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOPALPHA + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLENDALPHA + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDRENDERTARGETWRITEMASK + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOPALPHA + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDRENDERTARGETWRITEMASK + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NULLDESC + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDFILTER + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSU + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDFILTER + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSV + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSU + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSW + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSV + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMIPLODBIAS + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSW + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXANISOTROPY + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMIPLODBIAS + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDCOMPARISONFUNC + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXANISOTROPY + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMINLOD + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDCOMPARISONFUNC + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXLOD + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMINLOD + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXLOD + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NULLDESC + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDQUERY + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NULLDESC + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDMISCFLAGS + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDQUERY + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_UNEXPECTEDMISCFLAG + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDMISCFLAGS + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_NULLDESC + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_UNEXPECTEDMISCFLAG + 1, + D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNRECOGNIZED + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_NULLDESC + 1, + D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNDEFINED + = D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNRECOGNIZED + 1, + D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNDEFINED + 1, + D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_OFFSET_TOO_LARGE + = D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_OFFSET_TOO_LARGE + 1, + D3D11_MESSAGE_ID_IASETINDEXBUFFER_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_FORMAT_INVALID + = D3D11_MESSAGE_ID_IASETINDEXBUFFER_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_OFFSET_TOO_LARGE + = D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_FORMAT_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_OFFSET_TOO_LARGE + 1, + D3D11_MESSAGE_ID_DEVICE_VSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_IASETINDEXBUFFER_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_VSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_VSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_VSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_VSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_VSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_GSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_GSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_GSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_SOSETTARGETS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_GSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_SOSETTARGETS_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_SOSETTARGETS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_SOSETTARGETS_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_PSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_PSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_PSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_PSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_INVALIDVIEWPORT + = D3D11_MESSAGE_ID_DEVICE_PSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_INVALIDSCISSOR + = D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_INVALIDVIEWPORT + 1, + D3D11_MESSAGE_ID_CLEARRENDERTARGETVIEW_DENORMFLUSH + = D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_INVALIDSCISSOR + 1, + D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DENORMFLUSH + = D3D11_MESSAGE_ID_CLEARRENDERTARGETVIEW_DENORMFLUSH + 1, + D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_INVALID + = D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DENORMFLUSH + 1, + D3D11_MESSAGE_ID_DEVICE_IAGETVERTEXBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_VSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_IAGETVERTEXBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_VSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_VSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_VSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_VSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_VSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_GSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_GSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_SOGETTARGETS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_GSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_PSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_SOGETTARGETS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_PSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_PSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_PSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_PSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_RSGETVIEWPORTS_VIEWPORTS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_PSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_RSGETSCISSORRECTS_RECTS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_RSGETVIEWPORTS_VIEWPORTS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_GENERATEMIPS_RESOURCE_INVALID + = D3D11_MESSAGE_ID_DEVICE_RSGETSCISSORRECTS_RECTS_EMPTY + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDDESTINATIONSUBRESOURCE + = D3D11_MESSAGE_ID_DEVICE_GENERATEMIPS_RESOURCE_INVALID + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCESUBRESOURCE + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDDESTINATIONSUBRESOURCE + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCEBOX + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCESUBRESOURCE + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCE + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCEBOX + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDDESTINATIONSTATE + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCE + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCESTATE + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDDESTINATIONSTATE + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCE + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_INVALIDSOURCESTATE + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDDESTINATIONSTATE + = D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCE + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCESTATE + = D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDDESTINATIONSTATE + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSUBRESOURCE + = D3D11_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCESTATE + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONBOX + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSUBRESOURCE + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSTATE + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONBOX + 1, + D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_INVALID + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSTATE + 1, + D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_SUBRESOURCE_INVALID + = D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_INVALID + = D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_SUBRESOURCE_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_SUBRESOURCE_INVALID + = D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_FORMAT_INVALID + = D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_SUBRESOURCE_INVALID + 1, + D3D11_MESSAGE_ID_BUFFER_MAP_INVALIDMAPTYPE + = D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_FORMAT_INVALID + 1, + D3D11_MESSAGE_ID_BUFFER_MAP_INVALIDFLAGS = D3D11_MESSAGE_ID_BUFFER_MAP_INVALIDMAPTYPE + 1, + D3D11_MESSAGE_ID_BUFFER_MAP_ALREADYMAPPED = D3D11_MESSAGE_ID_BUFFER_MAP_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_BUFFER_MAP_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_BUFFER_MAP_ALREADYMAPPED + 1, + D3D11_MESSAGE_ID_BUFFER_UNMAP_NOTMAPPED = D3D11_MESSAGE_ID_BUFFER_MAP_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDMAPTYPE = D3D11_MESSAGE_ID_BUFFER_UNMAP_NOTMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDMAPTYPE + 1, + D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDFLAGS + = D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_TEXTURE1D_MAP_ALREADYMAPPED = D3D11_MESSAGE_ID_TEXTURE1D_MAP_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_TEXTURE1D_MAP_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_TEXTURE1D_MAP_ALREADYMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE1D_UNMAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE1D_MAP_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_TEXTURE1D_UNMAP_NOTMAPPED + = D3D11_MESSAGE_ID_TEXTURE1D_UNMAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDMAPTYPE = D3D11_MESSAGE_ID_TEXTURE1D_UNMAP_NOTMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDMAPTYPE + 1, + D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDFLAGS + = D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_TEXTURE2D_MAP_ALREADYMAPPED + = D3D11_MESSAGE_ID_TEXTURE2D_MAP_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_TEXTURE2D_MAP_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_TEXTURE2D_MAP_ALREADYMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE2D_UNMAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE2D_MAP_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_TEXTURE2D_UNMAP_NOTMAPPED + = D3D11_MESSAGE_ID_TEXTURE2D_UNMAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDMAPTYPE = D3D11_MESSAGE_ID_TEXTURE2D_UNMAP_NOTMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDMAPTYPE + 1, + D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDFLAGS + = D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_TEXTURE3D_MAP_ALREADYMAPPED = D3D11_MESSAGE_ID_TEXTURE3D_MAP_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_TEXTURE3D_MAP_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_TEXTURE3D_MAP_ALREADYMAPPED + 1, + D3D11_MESSAGE_ID_TEXTURE3D_UNMAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_TEXTURE3D_MAP_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_TEXTURE3D_UNMAP_NOTMAPPED + = D3D11_MESSAGE_ID_TEXTURE3D_UNMAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_DEPRECATED + = D3D11_MESSAGE_ID_TEXTURE3D_UNMAP_NOTMAPPED + 1, + D3D11_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_FORMAT_DEPRECATED + = D3D11_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_DEPRECATED + 1, + D3D11_MESSAGE_ID_SETEXCEPTIONMODE_UNRECOGNIZEDFLAGS + = D3D11_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_FORMAT_DEPRECATED + 1, + D3D11_MESSAGE_ID_SETEXCEPTIONMODE_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_SETEXCEPTIONMODE_UNRECOGNIZEDFLAGS + 1, + D3D11_MESSAGE_ID_SETEXCEPTIONMODE_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_SETEXCEPTIONMODE_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_REF_SIMULATING_INFINITELY_FAST_HARDWARE + = D3D11_MESSAGE_ID_SETEXCEPTIONMODE_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_REF_THREADING_MODE + = D3D11_MESSAGE_ID_REF_SIMULATING_INFINITELY_FAST_HARDWARE + 1, + D3D11_MESSAGE_ID_REF_UMDRIVER_EXCEPTION = D3D11_MESSAGE_ID_REF_THREADING_MODE + 1, + D3D11_MESSAGE_ID_REF_KMDRIVER_EXCEPTION = D3D11_MESSAGE_ID_REF_UMDRIVER_EXCEPTION + 1, + D3D11_MESSAGE_ID_REF_HARDWARE_EXCEPTION = D3D11_MESSAGE_ID_REF_KMDRIVER_EXCEPTION + 1, + D3D11_MESSAGE_ID_REF_ACCESSING_INDEXABLE_TEMP_OUT_OF_RANGE + = D3D11_MESSAGE_ID_REF_HARDWARE_EXCEPTION + 1, + D3D11_MESSAGE_ID_REF_PROBLEM_PARSING_SHADER + = D3D11_MESSAGE_ID_REF_ACCESSING_INDEXABLE_TEMP_OUT_OF_RANGE + 1, + D3D11_MESSAGE_ID_REF_OUT_OF_MEMORY = D3D11_MESSAGE_ID_REF_PROBLEM_PARSING_SHADER + 1, + D3D11_MESSAGE_ID_REF_INFO = D3D11_MESSAGE_ID_REF_OUT_OF_MEMORY + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEXPOS_OVERFLOW = D3D11_MESSAGE_ID_REF_INFO + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDEXED_INDEXPOS_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEXPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINSTANCED_VERTEXPOS_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAWINDEXED_INDEXPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINSTANCED_INSTANCEPOS_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAWINSTANCED_VERTEXPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INSTANCEPOS_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAWINSTANCED_INSTANCEPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INDEXPOS_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INSTANCEPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_SHADER_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INDEXPOS_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_SHADER_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERINDEX + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_COMPONENTTYPE + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERINDEX + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERMASK + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_COMPONENTTYPE + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SYSTEMVALUE + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERMASK + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_NEVERWRITTEN_ALWAYSREADS + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SYSTEMVALUE + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_NEVERWRITTEN_ALWAYSREADS + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INPUTLAYOUT_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_INPUTLAYOUT_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL + = D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SHADERRESOURCEVIEW_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VIEW_DIMENSION_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_SHADERRESOURCEVIEW_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL + = D3D11_MESSAGE_ID_DEVICE_DRAW_VIEW_DIMENSION_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_FORMAT_INVALID + = D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_TOO_SMALL + = D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_FORMAT_INVALID + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_GS_INPUT_PRIMITIVE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_BUFFER_TOO_SMALL + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_RETURN_TYPE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_GS_INPUT_PRIMITIVE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_POSITION_NOT_PRESENT + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_RETURN_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_OUTPUT_STREAM_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_POSITION_NOT_PRESENT + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_BOUND_RESOURCE_MAPPED + = D3D11_MESSAGE_ID_DEVICE_DRAW_OUTPUT_STREAM_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_PRIMITIVETOPOLOGY + = D3D11_MESSAGE_ID_DEVICE_DRAW_BOUND_RESOURCE_MAPPED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_PRIMITIVETOPOLOGY + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_STRIDE_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DRAW_VERTEX_STRIDE_UNALIGNED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_OUTPUT_STREAM_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DRAW_INDEX_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_LD_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_OUTPUT_STREAM_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_LD_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_C_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_MULTISAMPLE_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_SAMPLE_C_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SO_TARGETS_BOUND_WITHOUT_SOURCE + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_MULTISAMPLE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SO_STRIDE_LARGER_THAN_BUFFER + = D3D11_MESSAGE_ID_DEVICE_DRAW_SO_TARGETS_BOUND_WITHOUT_SOURCE + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_BLENDING + = D3D11_MESSAGE_ID_DEVICE_DRAW_SO_STRIDE_LARGER_THAN_BUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_OM_DUAL_SOURCE_BLENDING_CAN_ONLY_HAVE_RENDER_TARGET_0 + = D3D11_MESSAGE_ID_DEVICE_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_BLENDING + 1, + D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_AT_FAULT + = D3D11_MESSAGE_ID_DEVICE_DRAW_OM_DUAL_SOURCE_BLENDING_CAN_ONLY_HAVE_RENDER_TARGET_0 + 1, + D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_POSSIBLY_AT_FAULT + = D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_AT_FAULT + 1, + D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_NOT_AT_FAULT + = D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_POSSIBLY_AT_FAULT + 1, + D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_NOT_AT_FAULT + 1, + D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BADINTERFACE_RETURN + = D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_VIEWPORT_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BADINTERFACE_RETURN + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TRAILING_DIGIT_IN_SEMANTIC + = D3D11_MESSAGE_ID_DEVICE_DRAW_VIEWPORT_NOT_SET + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_TRAILING_DIGIT_IN_SEMANTIC + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TRAILING_DIGIT_IN_SEMANTIC + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_DENORMFLUSH + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_TRAILING_DIGIT_IN_SEMANTIC + 1, + D3D11_MESSAGE_ID_OMSETRENDERTARGETS_INVALIDVIEW + = D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_DENORMFLUSH + 1, + D3D11_MESSAGE_ID_DEVICE_SETTEXTFILTERSIZE_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_OMSETRENDERTARGETS_INVALIDVIEW + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_SETTEXTFILTERSIZE_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLER_MISMATCH + 1, + D3D11_MESSAGE_ID_BLENDSTATE_GETDESC_LEGACY + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_SHADERRESOURCEVIEW_GETDESC_LEGACY + = D3D11_MESSAGE_ID_BLENDSTATE_GETDESC_LEGACY + 1, + D3D11_MESSAGE_ID_CREATEQUERY_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_SHADERRESOURCEVIEW_GETDESC_LEGACY + 1, + D3D11_MESSAGE_ID_CREATEPREDICATE_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEQUERY_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_OUTOFRANGE_COUNTER + = D3D11_MESSAGE_ID_CREATEPREDICATE_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_SIMULTANEOUS_ACTIVE_COUNTERS_EXHAUSTED + = D3D11_MESSAGE_ID_CREATECOUNTER_OUTOFRANGE_COUNTER + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_UNSUPPORTED_WELLKNOWN_COUNTER + = D3D11_MESSAGE_ID_CREATECOUNTER_SIMULTANEOUS_ACTIVE_COUNTERS_EXHAUSTED + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATECOUNTER_UNSUPPORTED_WELLKNOWN_COUNTER + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_NONEXCLUSIVE_RETURN + = D3D11_MESSAGE_ID_CREATECOUNTER_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATECOUNTER_NULLDESC + = D3D11_MESSAGE_ID_CREATECOUNTER_NONEXCLUSIVE_RETURN + 1, + D3D11_MESSAGE_ID_CHECKCOUNTER_OUTOFRANGE_COUNTER = D3D11_MESSAGE_ID_CREATECOUNTER_NULLDESC + 1, + D3D11_MESSAGE_ID_CHECKCOUNTER_UNSUPPORTED_WELLKNOWN_COUNTER + = D3D11_MESSAGE_ID_CHECKCOUNTER_OUTOFRANGE_COUNTER + 1, + D3D11_MESSAGE_ID_SETPREDICATION_INVALID_PREDICATE_STATE + = D3D11_MESSAGE_ID_CHECKCOUNTER_UNSUPPORTED_WELLKNOWN_COUNTER + 1, + D3D11_MESSAGE_ID_QUERY_BEGIN_UNSUPPORTED + = D3D11_MESSAGE_ID_SETPREDICATION_INVALID_PREDICATE_STATE + 1, + D3D11_MESSAGE_ID_PREDICATE_BEGIN_DURING_PREDICATION + = D3D11_MESSAGE_ID_QUERY_BEGIN_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_QUERY_BEGIN_DUPLICATE + = D3D11_MESSAGE_ID_PREDICATE_BEGIN_DURING_PREDICATION + 1, + D3D11_MESSAGE_ID_QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS + = D3D11_MESSAGE_ID_QUERY_BEGIN_DUPLICATE + 1, + D3D11_MESSAGE_ID_PREDICATE_END_DURING_PREDICATION + = D3D11_MESSAGE_ID_QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS + 1, + D3D11_MESSAGE_ID_QUERY_END_ABANDONING_PREVIOUS_RESULTS + = D3D11_MESSAGE_ID_PREDICATE_END_DURING_PREDICATION + 1, + D3D11_MESSAGE_ID_QUERY_END_WITHOUT_BEGIN + = D3D11_MESSAGE_ID_QUERY_END_ABANDONING_PREVIOUS_RESULTS + 1, + D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_DATASIZE = D3D11_MESSAGE_ID_QUERY_END_WITHOUT_BEGIN + 1, + D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_FLAGS + = D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_DATASIZE + 1, + D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_CALL = D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_FLAGS + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_PS_OUTPUT_TYPE_MISMATCH + = D3D11_MESSAGE_ID_QUERY_GETDATA_INVALID_CALL + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_GATHER_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_PS_OUTPUT_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_CENTER_MULTISAMPLE_PATTERN + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_GATHER_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_STRIDE_TOO_LARGE + = D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_CENTER_MULTISAMPLE_PATTERN + 1, + D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_INVALIDRANGE + = D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_STRIDE_TOO_LARGE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT + = D3D11_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_INVALIDRANGE + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_SAMPLE_COUNT_MISMATCH + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT + 1, + D3D11_MESSAGE_ID_LIVE_OBJECT_SUMMARY + = D3D11_MESSAGE_ID_DEVICE_DRAW_RESOURCE_SAMPLE_COUNT_MISMATCH + 1, + D3D11_MESSAGE_ID_LIVE_BUFFER = D3D11_MESSAGE_ID_LIVE_OBJECT_SUMMARY + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE1D = D3D11_MESSAGE_ID_LIVE_BUFFER + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE2D = D3D11_MESSAGE_ID_LIVE_TEXTURE1D + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE3D = D3D11_MESSAGE_ID_LIVE_TEXTURE2D + 1, + D3D11_MESSAGE_ID_LIVE_SHADERRESOURCEVIEW = D3D11_MESSAGE_ID_LIVE_TEXTURE3D + 1, + D3D11_MESSAGE_ID_LIVE_RENDERTARGETVIEW = D3D11_MESSAGE_ID_LIVE_SHADERRESOURCEVIEW + 1, + D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILVIEW = D3D11_MESSAGE_ID_LIVE_RENDERTARGETVIEW + 1, + D3D11_MESSAGE_ID_LIVE_VERTEXSHADER = D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILVIEW + 1, + D3D11_MESSAGE_ID_LIVE_GEOMETRYSHADER = D3D11_MESSAGE_ID_LIVE_VERTEXSHADER + 1, + D3D11_MESSAGE_ID_LIVE_PIXELSHADER = D3D11_MESSAGE_ID_LIVE_GEOMETRYSHADER + 1, + D3D11_MESSAGE_ID_LIVE_INPUTLAYOUT = D3D11_MESSAGE_ID_LIVE_PIXELSHADER + 1, + D3D11_MESSAGE_ID_LIVE_SAMPLER = D3D11_MESSAGE_ID_LIVE_INPUTLAYOUT + 1, + D3D11_MESSAGE_ID_LIVE_BLENDSTATE = D3D11_MESSAGE_ID_LIVE_SAMPLER + 1, + D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILSTATE = D3D11_MESSAGE_ID_LIVE_BLENDSTATE + 1, + D3D11_MESSAGE_ID_LIVE_RASTERIZERSTATE = D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILSTATE + 1, + D3D11_MESSAGE_ID_LIVE_QUERY = D3D11_MESSAGE_ID_LIVE_RASTERIZERSTATE + 1, + D3D11_MESSAGE_ID_LIVE_PREDICATE = D3D11_MESSAGE_ID_LIVE_QUERY + 1, + D3D11_MESSAGE_ID_LIVE_COUNTER = D3D11_MESSAGE_ID_LIVE_PREDICATE + 1, + D3D11_MESSAGE_ID_LIVE_DEVICE = D3D11_MESSAGE_ID_LIVE_COUNTER + 1, + D3D11_MESSAGE_ID_LIVE_SWAPCHAIN = D3D11_MESSAGE_ID_LIVE_DEVICE + 1, + D3D11_MESSAGE_ID_D3D10_MESSAGES_END = D3D11_MESSAGE_ID_LIVE_SWAPCHAIN + 1, + D3D11_MESSAGE_ID_D3D10L9_MESSAGES_START = 0x100000, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_STENCIL_NO_TWO_SIDED + = D3D11_MESSAGE_ID_D3D10L9_MESSAGES_START + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_DepthBiasClamp_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_STENCIL_NO_TWO_SIDED + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NO_COMPARISON_SUPPORT + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_DepthBiasClamp_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_EXCESSIVE_ANISOTROPY + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NO_COMPARISON_SUPPORT + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_BORDER_OUT_OF_RANGE + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_EXCESSIVE_ANISOTROPY + 1, + D3D11_MESSAGE_ID_VSSETSAMPLERS_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_BORDER_OUT_OF_RANGE + 1, + D3D11_MESSAGE_ID_VSSETSAMPLERS_TOO_MANY_SAMPLERS + = D3D11_MESSAGE_ID_VSSETSAMPLERS_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_PSSETSAMPLERS_TOO_MANY_SAMPLERS + = D3D11_MESSAGE_ID_VSSETSAMPLERS_TOO_MANY_SAMPLERS + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_ARRAYS + = D3D11_MESSAGE_ID_PSSETSAMPLERS_TOO_MANY_SAMPLERS + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_VB_AND_IB_BIND + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_ARRAYS + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_TEXTURE_1D + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_VB_AND_IB_BIND + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_DIMENSION_OUT_OF_RANGE + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_TEXTURE_1D + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NOT_BINDABLE_AS_SHADER_RESOURCE + = D3D11_MESSAGE_ID_CREATERESOURCE_DIMENSION_OUT_OF_RANGE + 1, + D3D11_MESSAGE_ID_OMSETRENDERTARGETS_TOO_MANY_RENDER_TARGETS + = D3D11_MESSAGE_ID_CREATERESOURCE_NOT_BINDABLE_AS_SHADER_RESOURCE + 1, + D3D11_MESSAGE_ID_OMSETRENDERTARGETS_NO_DIFFERING_BIT_DEPTHS + = D3D11_MESSAGE_ID_OMSETRENDERTARGETS_TOO_MANY_RENDER_TARGETS + 1, + D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_BAD_BUFFER_INDEX + = D3D11_MESSAGE_ID_OMSETRENDERTARGETS_NO_DIFFERING_BIT_DEPTHS + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_TOO_MANY_VIEWPORTS + = D3D11_MESSAGE_ID_IASETVERTEXBUFFERS_BAD_BUFFER_INDEX + 1, + D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_ADJACENCY_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_TOO_MANY_VIEWPORTS + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_TOO_MANY_SCISSORS + = D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_ADJACENCY_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_ONLY_TEXTURE_2D_WITHIN_GPU_MEMORY + = D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_TOO_MANY_SCISSORS + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_NO_TEXTURE_3D_READBACK + = D3D11_MESSAGE_ID_COPYRESOURCE_ONLY_TEXTURE_2D_WITHIN_GPU_MEMORY + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_NO_TEXTURE_ONLY_READBACK + = D3D11_MESSAGE_ID_COPYRESOURCE_NO_TEXTURE_3D_READBACK + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_UNSUPPORTED_FORMAT + = D3D11_MESSAGE_ID_COPYRESOURCE_NO_TEXTURE_ONLY_READBACK + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_ALPHA_TO_COVERAGE + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_UNSUPPORTED_FORMAT + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_DepthClipEnable_MUST_BE_TRUE + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_ALPHA_TO_COVERAGE + 1, + D3D11_MESSAGE_ID_DRAWINDEXED_STARTINDEXLOCATION_MUST_BE_POSITIVE + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_DepthClipEnable_MUST_BE_TRUE + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_MUST_USE_LOWEST_LOD + = D3D11_MESSAGE_ID_DRAWINDEXED_STARTINDEXLOCATION_MUST_BE_POSITIVE + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_MINLOD_MUST_NOT_BE_FRACTIONAL + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_MUST_USE_LOWEST_LOD + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_MAXLOD_MUST_BE_FLT_MAX + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_MINLOD_MUST_NOT_BE_FRACTIONAL + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_FIRSTARRAYSLICE_MUST_BE_ZERO + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_MAXLOD_MUST_BE_FLT_MAX + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_CUBES_MUST_HAVE_6_SIDES + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_FIRSTARRAYSLICE_MUST_BE_ZERO + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NOT_BINDABLE_AS_RENDER_TARGET + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_CUBES_MUST_HAVE_6_SIDES + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_DWORD_INDEX_BUFFER + = D3D11_MESSAGE_ID_CREATERESOURCE_NOT_BINDABLE_AS_RENDER_TARGET + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_MSAA_PRECLUDES_SHADER_RESOURCE + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_DWORD_INDEX_BUFFER + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_PRESENTATION_PRECLUDES_SHADER_RESOURCE + = D3D11_MESSAGE_ID_CREATERESOURCE_MSAA_PRECLUDES_SHADER_RESOURCE + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_INDEPENDENT_BLEND_ENABLE + = D3D11_MESSAGE_ID_CREATERESOURCE_PRESENTATION_PRECLUDES_SHADER_RESOURCE + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_INDEPENDENT_WRITE_MASKS + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_INDEPENDENT_BLEND_ENABLE + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_STREAM_OUT + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_INDEPENDENT_WRITE_MASKS + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_ONLY_VB_IB_FOR_BUFFERS + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_STREAM_OUT + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NO_AUTOGEN_FOR_VOLUMES + = D3D11_MESSAGE_ID_CREATERESOURCE_ONLY_VB_IB_FOR_BUFFERS + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_DXGI_FORMAT_R8G8B8A8_CANNOT_BE_SHARED + = D3D11_MESSAGE_ID_CREATERESOURCE_NO_AUTOGEN_FOR_VOLUMES + 1, + D3D11_MESSAGE_ID_VSSHADERRESOURCES_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATERESOURCE_DXGI_FORMAT_R8G8B8A8_CANNOT_BE_SHARED + 1, + D3D11_MESSAGE_ID_GEOMETRY_SHADER_NOT_SUPPORTED + = D3D11_MESSAGE_ID_VSSHADERRESOURCES_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_STREAM_OUT_NOT_SUPPORTED = D3D11_MESSAGE_ID_GEOMETRY_SHADER_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_TEXT_FILTER_NOT_SUPPORTED = D3D11_MESSAGE_ID_STREAM_OUT_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_SEPARATE_ALPHA_BLEND + = D3D11_MESSAGE_ID_TEXT_FILTER_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_MRT_BLEND + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_SEPARATE_ALPHA_BLEND + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_OPERATION_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_NO_MRT_BLEND + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NO_MIRRORONCE + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_OPERATION_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_DRAWINSTANCED_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_NO_MIRRORONCE + 1, + D3D11_MESSAGE_ID_DRAWINDEXEDINSTANCED_NOT_SUPPORTED_BELOW_9_3 + = D3D11_MESSAGE_ID_DRAWINSTANCED_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_DRAWINDEXED_POINTLIST_UNSUPPORTED + = D3D11_MESSAGE_ID_DRAWINDEXEDINSTANCED_NOT_SUPPORTED_BELOW_9_3 + 1, + D3D11_MESSAGE_ID_SETBLENDSTATE_SAMPLE_MASK_CANNOT_BE_ZERO + = D3D11_MESSAGE_ID_DRAWINDEXED_POINTLIST_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_DIMENSION_EXCEEDS_FEATURE_LEVEL_DEFINITION + = D3D11_MESSAGE_ID_SETBLENDSTATE_SAMPLE_MASK_CANNOT_BE_ZERO + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_ONLY_SINGLE_MIP_LEVEL_DEPTH_STENCIL_SUPPORTED + = D3D11_MESSAGE_ID_CREATERESOURCE_DIMENSION_EXCEEDS_FEATURE_LEVEL_DEFINITION + 1, + D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_NEGATIVESCISSOR + = D3D11_MESSAGE_ID_CREATERESOURCE_ONLY_SINGLE_MIP_LEVEL_DEPTH_STENCIL_SUPPORTED + 1, + D3D11_MESSAGE_ID_SLOT_ZERO_MUST_BE_D3D10_INPUT_PER_VERTEX_DATA + = D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_NEGATIVESCISSOR + 1, + D3D11_MESSAGE_ID_CREATERESOURCE_NON_POW_2_MIPMAP + = D3D11_MESSAGE_ID_SLOT_ZERO_MUST_BE_D3D10_INPUT_PER_VERTEX_DATA + 1, + D3D11_MESSAGE_ID_CREATESAMPLERSTATE_BORDER_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATERESOURCE_NON_POW_2_MIPMAP + 1, + D3D11_MESSAGE_ID_OMSETRENDERTARGETS_NO_SRGB_MRT + = D3D11_MESSAGE_ID_CREATESAMPLERSTATE_BORDER_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_COPYRESOURCE_NO_3D_MISMATCHED_UPDATES + = D3D11_MESSAGE_ID_OMSETRENDERTARGETS_NO_SRGB_MRT + 1, + D3D11_MESSAGE_ID_D3D10L9_MESSAGES_END + = D3D11_MESSAGE_ID_COPYRESOURCE_NO_3D_MISMATCHED_UPDATES + 1, + D3D11_MESSAGE_ID_D3D11_MESSAGES_START = 0x200000, + D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFLAGS + = D3D11_MESSAGE_ID_D3D11_MESSAGES_START + 1, + D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTREAMS + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAMTORASTERIZER + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTREAMS + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTREAMS + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAMTORASTERIZER + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTREAMS + 1, + D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALID_COMMANDLISTFLAGS + = D3D11_MESSAGE_ID_CREATEPIXELSHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_SINGLETHREADED + = D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALID_COMMANDLISTFLAGS + 1, + D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_SINGLETHREADED + 1, + D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALID_CALL_RETURN + = D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_INVALID_CALL_RETURN + 1, + D3D11_MESSAGE_ID_FINISHDISPLAYLIST_ONIMMEDIATECONTEXT + = D3D11_MESSAGE_ID_CREATEDEFERREDCONTEXT_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_FINISHDISPLAYLIST_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_FINISHDISPLAYLIST_ONIMMEDIATECONTEXT + 1, + D3D11_MESSAGE_ID_FINISHDISPLAYLIST_INVALID_CALL_RETURN + = D3D11_MESSAGE_ID_FINISHDISPLAYLIST_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAM + = D3D11_MESSAGE_ID_FINISHDISPLAYLIST_INVALID_CALL_RETURN + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDENTRIES + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTRIDES + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDENTRIES + 1, + D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTRIDES + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTRIDES + 1, + D3D11_MESSAGE_ID_DEVICE_HSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTRIDES + 1, + D3D11_MESSAGE_ID_DEVICE_HSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_HSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_HSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DEVICE_HSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_HSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDCALL + = D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEHULLSHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDCALL + 1, + D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEHULLSHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_DEVICE_HSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_CREATEHULLSHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_HSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_HSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_HSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_HSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_HSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_HSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_HSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_HSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_HSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_HSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_DEVICE_HSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_DSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_DSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DEVICE_DSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCALL + = D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEDOMAINSHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCALL + 1, + D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATEDOMAINSHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_DEVICE_DSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_DSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_DSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_DSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_DSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_DSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_DSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_HS_XOR_DS_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEFERRED_CONTEXT_REMOVAL_PROCESS_AT_FAULT + = D3D11_MESSAGE_ID_DEVICE_DRAW_HS_XOR_DS_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_INVALID_ARG_BUFFER + = D3D11_MESSAGE_ID_DEFERRED_CONTEXT_REMOVAL_PROCESS_AT_FAULT + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_INVALID_ARG_BUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDMAPTYPE + = D3D11_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_OVERFLOW + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDMAPTYPE + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDFLAGS + = D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_ALREADYMAPPED = D3D11_MESSAGE_ID_RESOURCE_MAP_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_DEVICEREMOVED_RETURN + = D3D11_MESSAGE_ID_RESOURCE_MAP_ALREADYMAPPED + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_RESOURCE_MAP_DEVICEREMOVED_RETURN + 1, + D3D11_MESSAGE_ID_RESOURCE_MAP_WITHOUT_INITIAL_DISCARD + = D3D11_MESSAGE_ID_RESOURCE_MAP_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_RESOURCE_UNMAP_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_RESOURCE_MAP_WITHOUT_INITIAL_DISCARD + 1, + D3D11_MESSAGE_ID_RESOURCE_UNMAP_NOTMAPPED + = D3D11_MESSAGE_ID_RESOURCE_UNMAP_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RASTERIZING_CONTROL_POINTS + = D3D11_MESSAGE_ID_RESOURCE_UNMAP_NOTMAPPED + 1, + D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_RASTERIZING_CONTROL_POINTS + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_SIGNATURE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_HULL_SHADER_INPUT_TOPOLOGY_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_SIGNATURE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_CONTROL_POINT_COUNT_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_HULL_SHADER_INPUT_TOPOLOGY_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_TESSELLATOR_DOMAIN_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_CONTROL_POINT_COUNT_MISMATCH + 1, + D3D11_MESSAGE_ID_CREATE_CONTEXT + = D3D11_MESSAGE_ID_DEVICE_DRAW_HS_DS_TESSELLATOR_DOMAIN_MISMATCH + 1, + D3D11_MESSAGE_ID_LIVE_CONTEXT = D3D11_MESSAGE_ID_CREATE_CONTEXT + 1, + D3D11_MESSAGE_ID_DESTROY_CONTEXT = D3D11_MESSAGE_ID_LIVE_CONTEXT + 1, + D3D11_MESSAGE_ID_CREATE_BUFFER = D3D11_MESSAGE_ID_DESTROY_CONTEXT + 1, + D3D11_MESSAGE_ID_LIVE_BUFFER_WIN7 = D3D11_MESSAGE_ID_CREATE_BUFFER + 1, + D3D11_MESSAGE_ID_DESTROY_BUFFER = D3D11_MESSAGE_ID_LIVE_BUFFER_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_TEXTURE1D = D3D11_MESSAGE_ID_DESTROY_BUFFER + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE1D_WIN7 = D3D11_MESSAGE_ID_CREATE_TEXTURE1D + 1, + D3D11_MESSAGE_ID_DESTROY_TEXTURE1D = D3D11_MESSAGE_ID_LIVE_TEXTURE1D_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_TEXTURE2D = D3D11_MESSAGE_ID_DESTROY_TEXTURE1D + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE2D_WIN7 = D3D11_MESSAGE_ID_CREATE_TEXTURE2D + 1, + D3D11_MESSAGE_ID_DESTROY_TEXTURE2D = D3D11_MESSAGE_ID_LIVE_TEXTURE2D_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_TEXTURE3D = D3D11_MESSAGE_ID_DESTROY_TEXTURE2D + 1, + D3D11_MESSAGE_ID_LIVE_TEXTURE3D_WIN7 = D3D11_MESSAGE_ID_CREATE_TEXTURE3D + 1, + D3D11_MESSAGE_ID_DESTROY_TEXTURE3D = D3D11_MESSAGE_ID_LIVE_TEXTURE3D_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_SHADERRESOURCEVIEW = D3D11_MESSAGE_ID_DESTROY_TEXTURE3D + 1, + D3D11_MESSAGE_ID_LIVE_SHADERRESOURCEVIEW_WIN7 = D3D11_MESSAGE_ID_CREATE_SHADERRESOURCEVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_SHADERRESOURCEVIEW + = D3D11_MESSAGE_ID_LIVE_SHADERRESOURCEVIEW_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_RENDERTARGETVIEW = D3D11_MESSAGE_ID_DESTROY_SHADERRESOURCEVIEW + 1, + D3D11_MESSAGE_ID_LIVE_RENDERTARGETVIEW_WIN7 = D3D11_MESSAGE_ID_CREATE_RENDERTARGETVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_RENDERTARGETVIEW = D3D11_MESSAGE_ID_LIVE_RENDERTARGETVIEW_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_DEPTHSTENCILVIEW = D3D11_MESSAGE_ID_DESTROY_RENDERTARGETVIEW + 1, + D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILVIEW_WIN7 = D3D11_MESSAGE_ID_CREATE_DEPTHSTENCILVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_DEPTHSTENCILVIEW = D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILVIEW_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_VERTEXSHADER = D3D11_MESSAGE_ID_DESTROY_DEPTHSTENCILVIEW + 1, + D3D11_MESSAGE_ID_LIVE_VERTEXSHADER_WIN7 = D3D11_MESSAGE_ID_CREATE_VERTEXSHADER + 1, + D3D11_MESSAGE_ID_DESTROY_VERTEXSHADER = D3D11_MESSAGE_ID_LIVE_VERTEXSHADER_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_HULLSHADER = D3D11_MESSAGE_ID_DESTROY_VERTEXSHADER + 1, + D3D11_MESSAGE_ID_LIVE_HULLSHADER = D3D11_MESSAGE_ID_CREATE_HULLSHADER + 1, + D3D11_MESSAGE_ID_DESTROY_HULLSHADER = D3D11_MESSAGE_ID_LIVE_HULLSHADER + 1, + D3D11_MESSAGE_ID_CREATE_DOMAINSHADER = D3D11_MESSAGE_ID_DESTROY_HULLSHADER + 1, + D3D11_MESSAGE_ID_LIVE_DOMAINSHADER = D3D11_MESSAGE_ID_CREATE_DOMAINSHADER + 1, + D3D11_MESSAGE_ID_DESTROY_DOMAINSHADER = D3D11_MESSAGE_ID_LIVE_DOMAINSHADER + 1, + D3D11_MESSAGE_ID_CREATE_GEOMETRYSHADER = D3D11_MESSAGE_ID_DESTROY_DOMAINSHADER + 1, + D3D11_MESSAGE_ID_LIVE_GEOMETRYSHADER_WIN7 = D3D11_MESSAGE_ID_CREATE_GEOMETRYSHADER + 1, + D3D11_MESSAGE_ID_DESTROY_GEOMETRYSHADER = D3D11_MESSAGE_ID_LIVE_GEOMETRYSHADER_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_PIXELSHADER = D3D11_MESSAGE_ID_DESTROY_GEOMETRYSHADER + 1, + D3D11_MESSAGE_ID_LIVE_PIXELSHADER_WIN7 = D3D11_MESSAGE_ID_CREATE_PIXELSHADER + 1, + D3D11_MESSAGE_ID_DESTROY_PIXELSHADER = D3D11_MESSAGE_ID_LIVE_PIXELSHADER_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_INPUTLAYOUT = D3D11_MESSAGE_ID_DESTROY_PIXELSHADER + 1, + D3D11_MESSAGE_ID_LIVE_INPUTLAYOUT_WIN7 = D3D11_MESSAGE_ID_CREATE_INPUTLAYOUT + 1, + D3D11_MESSAGE_ID_DESTROY_INPUTLAYOUT = D3D11_MESSAGE_ID_LIVE_INPUTLAYOUT_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_SAMPLER = D3D11_MESSAGE_ID_DESTROY_INPUTLAYOUT + 1, + D3D11_MESSAGE_ID_LIVE_SAMPLER_WIN7 = D3D11_MESSAGE_ID_CREATE_SAMPLER + 1, + D3D11_MESSAGE_ID_DESTROY_SAMPLER = D3D11_MESSAGE_ID_LIVE_SAMPLER_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_BLENDSTATE = D3D11_MESSAGE_ID_DESTROY_SAMPLER + 1, + D3D11_MESSAGE_ID_LIVE_BLENDSTATE_WIN7 = D3D11_MESSAGE_ID_CREATE_BLENDSTATE + 1, + D3D11_MESSAGE_ID_DESTROY_BLENDSTATE = D3D11_MESSAGE_ID_LIVE_BLENDSTATE_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_DEPTHSTENCILSTATE = D3D11_MESSAGE_ID_DESTROY_BLENDSTATE + 1, + D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILSTATE_WIN7 = D3D11_MESSAGE_ID_CREATE_DEPTHSTENCILSTATE + 1, + D3D11_MESSAGE_ID_DESTROY_DEPTHSTENCILSTATE = D3D11_MESSAGE_ID_LIVE_DEPTHSTENCILSTATE_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_RASTERIZERSTATE = D3D11_MESSAGE_ID_DESTROY_DEPTHSTENCILSTATE + 1, + D3D11_MESSAGE_ID_LIVE_RASTERIZERSTATE_WIN7 = D3D11_MESSAGE_ID_CREATE_RASTERIZERSTATE + 1, + D3D11_MESSAGE_ID_DESTROY_RASTERIZERSTATE = D3D11_MESSAGE_ID_LIVE_RASTERIZERSTATE_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_QUERY = D3D11_MESSAGE_ID_DESTROY_RASTERIZERSTATE + 1, + D3D11_MESSAGE_ID_LIVE_QUERY_WIN7 = D3D11_MESSAGE_ID_CREATE_QUERY + 1, + D3D11_MESSAGE_ID_DESTROY_QUERY = D3D11_MESSAGE_ID_LIVE_QUERY_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_PREDICATE = D3D11_MESSAGE_ID_DESTROY_QUERY + 1, + D3D11_MESSAGE_ID_LIVE_PREDICATE_WIN7 = D3D11_MESSAGE_ID_CREATE_PREDICATE + 1, + D3D11_MESSAGE_ID_DESTROY_PREDICATE = D3D11_MESSAGE_ID_LIVE_PREDICATE_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_COUNTER = D3D11_MESSAGE_ID_DESTROY_PREDICATE + 1, + D3D11_MESSAGE_ID_DESTROY_COUNTER = D3D11_MESSAGE_ID_CREATE_COUNTER + 1, + D3D11_MESSAGE_ID_CREATE_COMMANDLIST = D3D11_MESSAGE_ID_DESTROY_COUNTER + 1, + D3D11_MESSAGE_ID_LIVE_COMMANDLIST = D3D11_MESSAGE_ID_CREATE_COMMANDLIST + 1, + D3D11_MESSAGE_ID_DESTROY_COMMANDLIST = D3D11_MESSAGE_ID_LIVE_COMMANDLIST + 1, + D3D11_MESSAGE_ID_CREATE_CLASSINSTANCE = D3D11_MESSAGE_ID_DESTROY_COMMANDLIST + 1, + D3D11_MESSAGE_ID_LIVE_CLASSINSTANCE = D3D11_MESSAGE_ID_CREATE_CLASSINSTANCE + 1, + D3D11_MESSAGE_ID_DESTROY_CLASSINSTANCE = D3D11_MESSAGE_ID_LIVE_CLASSINSTANCE + 1, + D3D11_MESSAGE_ID_CREATE_CLASSLINKAGE = D3D11_MESSAGE_ID_DESTROY_CLASSINSTANCE + 1, + D3D11_MESSAGE_ID_LIVE_CLASSLINKAGE = D3D11_MESSAGE_ID_CREATE_CLASSLINKAGE + 1, + D3D11_MESSAGE_ID_DESTROY_CLASSLINKAGE = D3D11_MESSAGE_ID_LIVE_CLASSLINKAGE + 1, + D3D11_MESSAGE_ID_LIVE_DEVICE_WIN7 = D3D11_MESSAGE_ID_DESTROY_CLASSLINKAGE + 1, + D3D11_MESSAGE_ID_LIVE_OBJECT_SUMMARY_WIN7 = D3D11_MESSAGE_ID_LIVE_DEVICE_WIN7 + 1, + D3D11_MESSAGE_ID_CREATE_COMPUTESHADER = D3D11_MESSAGE_ID_LIVE_OBJECT_SUMMARY_WIN7 + 1, + D3D11_MESSAGE_ID_LIVE_COMPUTESHADER = D3D11_MESSAGE_ID_CREATE_COMPUTESHADER + 1, + D3D11_MESSAGE_ID_DESTROY_COMPUTESHADER = D3D11_MESSAGE_ID_LIVE_COMPUTESHADER + 1, + D3D11_MESSAGE_ID_CREATE_UNORDEREDACCESSVIEW = D3D11_MESSAGE_ID_DESTROY_COMPUTESHADER + 1, + D3D11_MESSAGE_ID_LIVE_UNORDEREDACCESSVIEW = D3D11_MESSAGE_ID_CREATE_UNORDEREDACCESSVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_UNORDEREDACCESSVIEW = D3D11_MESSAGE_ID_LIVE_UNORDEREDACCESSVIEW + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INTERFACES_FEATURELEVEL + = D3D11_MESSAGE_ID_DESTROY_UNORDEREDACCESSVIEW + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INTERFACE_COUNT_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INTERFACES_FEATURELEVEL + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INTERFACE_COUNT_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_INDEX + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_TYPE + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_INDEX + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_DATA + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_TYPE + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_UNBOUND_INSTANCE_DATA + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INVALID_INSTANCE_DATA + 1, + D3D11_MESSAGE_ID_DEVICE_SETSHADER_INSTANCE_DATA_BINDINGS + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_UNBOUND_INSTANCE_DATA + 1, + D3D11_MESSAGE_ID_DEVICE_CREATESHADER_CLASSLINKAGE_FULL + = D3D11_MESSAGE_ID_DEVICE_SETSHADER_INSTANCE_DATA_BINDINGS + 1, + D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_UNRECOGNIZED_FEATURE + = D3D11_MESSAGE_ID_DEVICE_CREATESHADER_CLASSLINKAGE_FULL + 1, + D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_MISMATCHED_DATA_SIZE + = D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_UNRECOGNIZED_FEATURE + 1, + D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_MISMATCHED_DATA_SIZE + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_HAZARD + = D3D11_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETCONSTANTBUFFERS_HAZARD + = D3D11_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_HAZARD + 1, + D3D11_MESSAGE_ID_CSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DEVICE_CSSETCONSTANTBUFFERS_HAZARD + 1, + D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_CSSETSHADERRESOURCES_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCALL + = D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATECOMPUTESHADER_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCALL + 1, + D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDSHADERBYTECODE + = D3D11_MESSAGE_ID_CREATECOMPUTESHADER_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDSHADERTYPE + = D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDSHADERBYTECODE + 1, + D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCLASSLINKAGE + = D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDSHADERTYPE + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCLASSLINKAGE + 1, + D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_INVALIDBUFFER + = D3D11_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_CSSETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CSGETSHADERRESOURCES_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_CSSETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CSGETCONSTANTBUFFERS_BUFFERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_CSGETSHADERRESOURCES_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CSGETSAMPLERS_SAMPLERS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_CSGETCONSTANTBUFFERS_BUFFERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CSGETSAMPLERS_SAMPLERS_EMPTY + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEFLOATOPSNOTSUPPORTED + + 1, + D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEFLOATOPSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDSTRUCTURESTRIDE + = D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEFLOATOPSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFLAGS + = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDSTRUCTURESTRIDE + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDRESOURCE + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDESC + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDESC + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDIMENSIONS + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_UNRECOGNIZEDFORMAT + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDIMENSIONS + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_HAZARD + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_UNRECOGNIZEDFORMAT + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_OVERLAPPING_OLD_SLOTS + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_NO_OP + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_OVERLAPPING_OLD_SLOTS + + 1, + D3D11_MESSAGE_ID_CSSETUNORDEREDACCESSVIEWS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_NO_OP + 1, + D3D11_MESSAGE_ID_PSSETUNORDEREDACCESSVIEWS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_CSSETUNORDEREDACCESSVIEWS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_PSSETUNORDEREDACCESSVIEWS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_HAZARD + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEW_DENORMFLUSH + = D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_HAZARD + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSS_VIEWS_EMPTY + = D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEW_DENORMFLUSH + 1, + D3D11_MESSAGE_ID_DEVICE_CSGETUNORDEREDACCESSS_VIEWS_EMPTY + = D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSS_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFLAGS + = D3D11_MESSAGE_ID_DEVICE_CSGETUNORDEREDACCESSS_VIEWS_EMPTY + 1, + D3D11_MESSAGE_ID_CREATESHADERRESESOURCEVIEW_TOOMANYOBJECTS + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_INVALID_ARG_BUFFER + = D3D11_MESSAGE_ID_CREATESHADERRESESOURCEVIEW_TOOMANYOBJECTS + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_UNALIGNED + = D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_INVALID_ARG_BUFFER + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_UNALIGNED + 1, + D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDCONTEXT + = D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDRESOURCE + = D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDCONTEXT + 1, + D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDMINLOD + = D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_DEVICE_GETRESOURCEMINLOD_INVALIDCONTEXT + = D3D11_MESSAGE_ID_DEVICE_SETRESOURCEMINLOD_INVALIDMINLOD + 1, + D3D11_MESSAGE_ID_DEVICE_GETRESOURCEMINLOD_INVALIDRESOURCE + = D3D11_MESSAGE_ID_DEVICE_GETRESOURCEMINLOD_INVALIDCONTEXT + 1, + D3D11_MESSAGE_ID_OMSETDEPTHSTENCIL_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DEVICE_GETRESOURCEMINLOD_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DEPTH_READONLY + = D3D11_MESSAGE_ID_OMSETDEPTHSTENCIL_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_STENCIL_READONLY + = D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DEPTH_READONLY + 1, + D3D11_MESSAGE_ID_CHECKFEATURESUPPORT_FORMAT_DEPRECATED + = D3D11_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_STENCIL_READONLY + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RETURN_TYPE_MISMATCH + = D3D11_MESSAGE_ID_CHECKFEATURESUPPORT_FORMAT_DEPRECATED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RETURN_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_UNORDEREDACCESSVIEW_RENDERTARGETVIEW_OVERLAP + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_DIMENSION_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DRAW_UNORDEREDACCESSVIEW_RENDERTARGETVIEW_OVERLAP + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_APPEND_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_DIMENSION_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMICS_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_APPEND_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_STRUCTURE_STRIDE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMICS_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_BUFFER_TYPE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_STRUCTURE_STRIDE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RAW_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_BUFFER_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_LD_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RAW_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_STORE_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_LD_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_ADD_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_STORE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_BITWISE_OPS_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_ADD_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_CMPSTORE_CMPEXCHANGE_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_BITWISE_OPS_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_EXCHANGE_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_CMPSTORE_CMPEXCHANGE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_SIGNED_MINMAX_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_EXCHANGE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_UNSIGNED_MINMAX_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_SIGNED_MINMAX_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCH_BOUND_RESOURCE_MAPPED + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_UNSIGNED_MINMAX_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_OVERFLOW + = D3D11_MESSAGE_ID_DEVICE_DISPATCH_BOUND_RESOURCE_MAPPED + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_ZERO + = D3D11_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_OVERFLOW + 1, + D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_STRUCTURE_STRIDE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_ZERO + 1, + D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_BUFFER_TYPE_MISMATCH + = D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_STRUCTURE_STRIDE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_RAW_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_BUFFER_TYPE_MISMATCH + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCH_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_RAW_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DISPATCH_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDOFFSET + = D3D11_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_LARGEOFFSET + = D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDOFFSET + 1, + D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDDESTINATIONSTATE + = D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_LARGEOFFSET + 1, + D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDSOURCESTATE + = D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDDESTINATIONSTATE + 1, + D3D11_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_NOT_SUPPORTED + = D3D11_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDSOURCESTATE + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_INVALIDVIEW + = D3D11_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_INVALIDOFFSET + = D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_INVALIDVIEW + 1, + D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_TOOMANYVIEWS + = D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_INVALIDOFFSET + 1, + D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWFLOAT_INVALIDFORMAT + = D3D11_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSVIEWS_TOOMANYVIEWS + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_COUNTER_UNSUPPORTED + = D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWFLOAT_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_REF_WARNING + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_COUNTER_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_PIXEL_SHADER_WITHOUT_RTV_OR_DSV + = D3D11_MESSAGE_ID_REF_WARNING + 1, + D3D11_MESSAGE_ID_SHADER_ABORT + = D3D11_MESSAGE_ID_DEVICE_DRAW_PIXEL_SHADER_WITHOUT_RTV_OR_DSV + 1, + D3D11_MESSAGE_ID_SHADER_MESSAGE = D3D11_MESSAGE_ID_SHADER_ABORT + 1, + D3D11_MESSAGE_ID_SHADER_ERROR = D3D11_MESSAGE_ID_SHADER_MESSAGE + 1, + D3D11_MESSAGE_ID_OFFERRESOURCES_INVALIDRESOURCE = D3D11_MESSAGE_ID_SHADER_ERROR + 1, + D3D11_MESSAGE_ID_HSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_OFFERRESOURCES_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_DSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_HSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CSSETSAMPLERS_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_HSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_CSSETSAMPLERS_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_DSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_HSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_CSSETSHADER_UNBINDDELETINGOBJECT + = D3D11_MESSAGE_ID_DSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_ENQUEUESETEVENT_INVALIDARG_RETURN + = D3D11_MESSAGE_ID_CSSETSHADER_UNBINDDELETINGOBJECT + 1, + D3D11_MESSAGE_ID_ENQUEUESETEVENT_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_ENQUEUESETEVENT_INVALIDARG_RETURN + 1, + D3D11_MESSAGE_ID_ENQUEUESETEVENT_ACCESSDENIED_RETURN + = D3D11_MESSAGE_ID_ENQUEUESETEVENT_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_NUMUAVS_INVALIDRANGE + = D3D11_MESSAGE_ID_ENQUEUESETEVENT_ACCESSDENIED_RETURN + 1, + D3D11_MESSAGE_ID_USE_OF_ZERO_REFCOUNT_OBJECT + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_NUMUAVS_INVALIDRANGE + + 1, + D3D11_MESSAGE_ID_D3D11_MESSAGES_END = D3D11_MESSAGE_ID_USE_OF_ZERO_REFCOUNT_OBJECT + 1, + D3D11_MESSAGE_ID_D3D11_1_MESSAGES_START = 0x300000, + D3D11_MESSAGE_ID_CREATE_VIDEODECODER = D3D11_MESSAGE_ID_D3D11_1_MESSAGES_START + 1, + D3D11_MESSAGE_ID_CREATE_VIDEOPROCESSORENUM = D3D11_MESSAGE_ID_CREATE_VIDEODECODER + 1, + D3D11_MESSAGE_ID_CREATE_VIDEOPROCESSOR = D3D11_MESSAGE_ID_CREATE_VIDEOPROCESSORENUM + 1, + D3D11_MESSAGE_ID_CREATE_DECODEROUTPUTVIEW = D3D11_MESSAGE_ID_CREATE_VIDEOPROCESSOR + 1, + D3D11_MESSAGE_ID_CREATE_PROCESSORINPUTVIEW = D3D11_MESSAGE_ID_CREATE_DECODEROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_CREATE_PROCESSOROUTPUTVIEW = D3D11_MESSAGE_ID_CREATE_PROCESSORINPUTVIEW + 1, + D3D11_MESSAGE_ID_CREATE_DEVICECONTEXTSTATE = D3D11_MESSAGE_ID_CREATE_PROCESSOROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_LIVE_VIDEODECODER = D3D11_MESSAGE_ID_CREATE_DEVICECONTEXTSTATE + 1, + D3D11_MESSAGE_ID_LIVE_VIDEOPROCESSORENUM = D3D11_MESSAGE_ID_LIVE_VIDEODECODER + 1, + D3D11_MESSAGE_ID_LIVE_VIDEOPROCESSOR = D3D11_MESSAGE_ID_LIVE_VIDEOPROCESSORENUM + 1, + D3D11_MESSAGE_ID_LIVE_DECODEROUTPUTVIEW = D3D11_MESSAGE_ID_LIVE_VIDEOPROCESSOR + 1, + D3D11_MESSAGE_ID_LIVE_PROCESSORINPUTVIEW = D3D11_MESSAGE_ID_LIVE_DECODEROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_LIVE_PROCESSOROUTPUTVIEW = D3D11_MESSAGE_ID_LIVE_PROCESSORINPUTVIEW + 1, + D3D11_MESSAGE_ID_LIVE_DEVICECONTEXTSTATE = D3D11_MESSAGE_ID_LIVE_PROCESSOROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_VIDEODECODER = D3D11_MESSAGE_ID_LIVE_DEVICECONTEXTSTATE + 1, + D3D11_MESSAGE_ID_DESTROY_VIDEOPROCESSORENUM = D3D11_MESSAGE_ID_DESTROY_VIDEODECODER + 1, + D3D11_MESSAGE_ID_DESTROY_VIDEOPROCESSOR = D3D11_MESSAGE_ID_DESTROY_VIDEOPROCESSORENUM + 1, + D3D11_MESSAGE_ID_DESTROY_DECODEROUTPUTVIEW = D3D11_MESSAGE_ID_DESTROY_VIDEOPROCESSOR + 1, + D3D11_MESSAGE_ID_DESTROY_PROCESSORINPUTVIEW = D3D11_MESSAGE_ID_DESTROY_DECODEROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_PROCESSOROUTPUTVIEW = D3D11_MESSAGE_ID_DESTROY_PROCESSORINPUTVIEW + 1, + D3D11_MESSAGE_ID_DESTROY_DEVICECONTEXTSTATE = D3D11_MESSAGE_ID_DESTROY_PROCESSOROUTPUTVIEW + 1, + D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDFLAGS + = D3D11_MESSAGE_ID_DESTROY_DEVICECONTEXTSTATE + 1, + D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDFEATURELEVEL + = D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_FEATURELEVELS_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDFEATURELEVEL + 1, + D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDREFIID + = D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_FEATURELEVELS_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_DISCARDVIEW_INVALIDVIEW + = D3D11_MESSAGE_ID_CREATEDEVICECONTEXTSTATE_INVALIDREFIID + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION1_INVALIDCOPYFLAGS + = D3D11_MESSAGE_ID_DEVICE_DISCARDVIEW_INVALIDVIEW + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE1_INVALIDCOPYFLAGS + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION1_INVALIDCOPYFLAGS + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFORCEDSAMPLECOUNT + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE1_INVALIDCOPYFLAGS + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFORCEDSAMPLECOUNT + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_ZEROWIDTHHEIGHT + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_DRIVER_INVALIDBUFFERSIZE + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_ZEROWIDTHHEIGHT + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODER_DRIVER_INVALIDBUFFERUSAGE + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_DRIVER_INVALIDBUFFERSIZE + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERPROFILECOUNT_OUTOFMEMORY + = D3D11_MESSAGE_ID_CREATEVIDEODECODER_DRIVER_INVALIDBUFFERUSAGE + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEODECODERPROFILECOUNT_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_INVALIDINDEX + = D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_INVALIDINDEX + 1, + D3D11_MESSAGE_ID_CHECKVIDEODECODERFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEODECODERPROFILE_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CHECKVIDEODECODERFORMAT_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CHECKVIDEODECODERFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCONFIGCOUNT_NULLPARAM + = D3D11_MESSAGE_ID_CHECKVIDEODECODERFORMAT_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCONFIGCOUNT_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_GETVIDEODECODERCONFIGCOUNT_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEODECODERCONFIGCOUNT_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_INVALIDINDEX + = D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_INVALIDINDEX + 1, + D3D11_MESSAGE_ID_GETDECODERCREATIONPARAMS_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEODECODERCONFIG_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_GETDECODERDRIVERHANDLE_NULLPARAM + = D3D11_MESSAGE_ID_GETDECODERCREATIONPARAMS_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETDECODERBUFFER_NULLPARAM + = D3D11_MESSAGE_ID_GETDECODERDRIVERHANDLE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETDECODERBUFFER_INVALIDBUFFER + = D3D11_MESSAGE_ID_GETDECODERBUFFER_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETDECODERBUFFER_INVALIDTYPE + = D3D11_MESSAGE_ID_GETDECODERBUFFER_INVALIDBUFFER + 1, + D3D11_MESSAGE_ID_GETDECODERBUFFER_LOCKED = D3D11_MESSAGE_ID_GETDECODERBUFFER_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_NULLPARAM = D3D11_MESSAGE_ID_GETDECODERBUFFER_LOCKED + 1, + D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_INVALIDTYPE + = D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_NULLPARAM + 1, + D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_NOTLOCKED + = D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_DECODERBEGINFRAME_NULLPARAM + = D3D11_MESSAGE_ID_RELEASEDECODERBUFFER_NOTLOCKED + 1, + D3D11_MESSAGE_ID_DECODERBEGINFRAME_HAZARD = D3D11_MESSAGE_ID_DECODERBEGINFRAME_NULLPARAM + 1, + D3D11_MESSAGE_ID_DECODERENDFRAME_NULLPARAM = D3D11_MESSAGE_ID_DECODERBEGINFRAME_HAZARD + 1, + D3D11_MESSAGE_ID_SUBMITDECODERBUFFERS_NULLPARAM + = D3D11_MESSAGE_ID_DECODERENDFRAME_NULLPARAM + 1, + D3D11_MESSAGE_ID_SUBMITDECODERBUFFERS_INVALIDTYPE + = D3D11_MESSAGE_ID_SUBMITDECODERBUFFERS_NULLPARAM + 1, + D3D11_MESSAGE_ID_DECODEREXTENSION_NULLPARAM + = D3D11_MESSAGE_ID_SUBMITDECODERBUFFERS_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_DECODEREXTENSION_INVALIDRESOURCE + = D3D11_MESSAGE_ID_DECODEREXTENSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_DECODEREXTENSION_INVALIDRESOURCE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDFRAMEFORMAT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDUSAGE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDFRAMEFORMAT + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDINPUTFRAMERATE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDUSAGE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDOUTPUTFRAMERATE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDINPUTFRAMERATE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDWIDTHHEIGHT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDOUTPUTFRAMERATE + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORCONTENTDESC_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORENUMERATOR_INVALIDWIDTHHEIGHT + 1, + D3D11_MESSAGE_ID_CHECKVIDEOPROCESSORFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORCONTENTDESC_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORCAPS_NULLPARAM + = D3D11_MESSAGE_ID_CHECKVIDEOPROCESSORFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORRATECONVERSIONCAPS_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORCAPS_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORRATECONVERSIONCAPS_INVALIDINDEX + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORRATECONVERSIONCAPS_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORCUSTOMRATE_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORRATECONVERSIONCAPS_INVALIDINDEX + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORCUSTOMRATE_INVALIDINDEX + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORCUSTOMRATE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORFILTERRANGE_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORCUSTOMRATE_INVALIDINDEX + 1, + D3D11_MESSAGE_ID_GETVIDEOPROCESSORFILTERRANGE_UNSUPPORTED + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORFILTERRANGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOR_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_GETVIDEOPROCESSORFILTERRANGE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOR_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOR_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTTARGETRECT_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOR_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTBACKGROUNDCOLOR_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTTARGETRECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTBACKGROUNDCOLOR_INVALIDALPHA + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTBACKGROUNDCOLOR_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCOLORSPACE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTBACKGROUNDCOLOR_INVALIDALPHA + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCOLORSPACE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_INVALIDFILLMODE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTALPHAFILLMODE_INVALIDFILLMODE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSTEREOMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSTEREOMODE_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSTEREOMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTEXTENSION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSTEREOMODE_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTTARGETRECT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTEXTENSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTBACKGROUNDCOLOR_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTTARGETRECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCOLORSPACE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTBACKGROUNDCOLOR_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTALPHAFILLMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCOLORSPACE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCONSTRICTION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTALPHAFILLMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCONSTRICTION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_INVALIDSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTSTEREOMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCONSTRICTION_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTEXTENSION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTSTEREOMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTEXTENSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_INVALIDFORMAT + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFRAMEFORMAT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDRATE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDFLAG + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDRATE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDFLAG + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMOUTPUTRATE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_INVALIDRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSOURCERECT_INVALIDRECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_INVALIDRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMDESTRECT_INVALIDRECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_INVALIDALPHA + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_INVALIDALPHA + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDCOUNT + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDALPHA + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDCOUNT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPALETTE_INVALIDALPHA + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_INVALIDRATIO + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_INVALIDRATIO + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_INVALIDRANGE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_INVALIDRANGE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMLUMAKEY_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_FLIPUNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_MONOOFFSETUNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_FLIPUNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_FORMATUNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_MONOOFFSETUNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_INVALIDFORMAT + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_FORMATUNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMAUTOPROCESSINGMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMSTEREOFORMAT_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMAUTOPROCESSINGMODE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMAUTOPROCESSINGMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMAUTOPROCESSINGMODE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDFILTER + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDFILTER + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDLEVEL + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMEXTENSION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMFILTER_INVALIDLEVEL + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMEXTENSION_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMEXTENSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFRAMEFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMEXTENSION_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFRAMEFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMOUTPUTRATE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSOURCERECT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMOUTPUTRATE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMDESTRECT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSOURCERECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMALPHA_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMDESTRECT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPALETTE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMALPHA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPIXELASPECTRATIO_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPALETTE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMLUMAKEY_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPIXELASPECTRATIO_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSTEREOFORMAT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMLUMAKEY_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMAUTOPROCESSINGMODE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSTEREOFORMAT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFILTER_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMAUTOPROCESSINGMODE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMEXTENSION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFILTER_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMEXTENSION_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMEXTENSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMEXTENSION_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDSTREAMCOUNT + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_TARGETRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDSTREAMCOUNT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDOUTPUT + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_TARGETRECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDPASTFRAMES + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDOUTPUT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDFUTUREFRAMES + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDPASTFRAMES + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDSOURCERECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDFUTUREFRAMES + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDDESTRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDSOURCERECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDINPUTRESOURCE + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDDESTRECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDARRAYSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDINPUTRESOURCE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDARRAY + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDARRAYSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_RIGHTEXPECTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDARRAY + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_RIGHTNOTEXPECTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_RIGHTEXPECTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_STEREONOTENABLED + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_RIGHTNOTEXPECTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDRIGHTRESOURCE + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_STEREONOTENABLED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_NOSTEREOSTREAMS + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INVALIDRIGHTRESOURCE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INPUTHAZARD + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_NOSTEREOSTREAMS + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_OUTPUTHAZARD + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_INPUTHAZARD + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_VIDEOPROCESSORBLT_OUTPUTHAZARD + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDTYPE + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDBIND + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_UNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDBIND + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDMIP + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_UNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_UNSUPPORTEMIP + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDARRAYSIZE + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_UNSUPPORTEMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDARRAY + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDARRAYSIZE + 1, + D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDDIMENSION + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDARRAY + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEVIDEODECODEROUTPUTVIEW_INVALIDDIMENSION + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDTYPE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDBIND + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMISC + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDBIND + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDUSAGE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMISC + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDUSAGE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDFOURCC + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMIP + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDFOURCC + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_UNSUPPORTEDMIP + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDARRAYSIZE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_UNSUPPORTEDMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDARRAY + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDARRAYSIZE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDDIMENSION + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDARRAY + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDDIMENSION + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_NULLPARAM + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDTYPE + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDBIND + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDFORMAT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDBIND + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDMIP + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDFORMAT + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_UNSUPPORTEDMIP + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_UNSUPPORTEDARRAY + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_UNSUPPORTEDMIP + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDARRAY + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_UNSUPPORTEDARRAY + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDDIMENSION + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDARRAY + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_FORCED_SAMPLE_COUNT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDDIMENSION + 1, + D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDLOGICOPS + = D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_FORCED_SAMPLE_COUNT + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDARRAYWITHDECODER + = D3D11_MESSAGE_ID_CREATEBLENDSTATE_INVALIDLOGICOPS + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDARRAYWITHDECODER + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDARRAYWITHDECODER + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDARRAYWITHDECODER + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDARRAYWITHDECODER + 1, + D3D11_MESSAGE_ID_DEVICE_LOCKEDOUT_INTERFACE + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDARRAYWITHDECODER + 1, + D3D11_MESSAGE_ID_REF_WARNING_ATOMIC_INCONSISTENT + = D3D11_MESSAGE_ID_DEVICE_LOCKEDOUT_INTERFACE + 1, + D3D11_MESSAGE_ID_REF_WARNING_READING_UNINITIALIZED_RESOURCE + = D3D11_MESSAGE_ID_REF_WARNING_ATOMIC_INCONSISTENT + 1, + D3D11_MESSAGE_ID_REF_WARNING_RAW_HAZARD + = D3D11_MESSAGE_ID_REF_WARNING_READING_UNINITIALIZED_RESOURCE + 1, + D3D11_MESSAGE_ID_REF_WARNING_WAR_HAZARD = D3D11_MESSAGE_ID_REF_WARNING_RAW_HAZARD + 1, + D3D11_MESSAGE_ID_REF_WARNING_WAW_HAZARD = D3D11_MESSAGE_ID_REF_WARNING_WAR_HAZARD + 1, + D3D11_MESSAGE_ID_CREATECRYPTOSESSION_NULLPARAM = D3D11_MESSAGE_ID_REF_WARNING_WAW_HAZARD + 1, + D3D11_MESSAGE_ID_CREATECRYPTOSESSION_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATECRYPTOSESSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOTYPE_NULLPARAM + = D3D11_MESSAGE_ID_CREATECRYPTOSESSION_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_GETDECODERPROFILE_NULLPARAM = D3D11_MESSAGE_ID_GETCRYPTOTYPE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATESIZE_NULLPARAM + = D3D11_MESSAGE_ID_GETDECODERPROFILE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATE_NULLPARAM + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATESIZE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATE_WRONGSIZE + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONHANDLE_WRONGSIZE + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONCERTIFICATE_WRONGSIZE + 1, + D3D11_MESSAGE_ID_NEGOTIATECRPYTOSESSIONKEYEXCHANGE_NULLPARAM + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONHANDLE_WRONGSIZE + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_UNSUPPORTED + = D3D11_MESSAGE_ID_NEGOTIATECRPYTOSESSIONKEYEXCHANGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_NULLPARAM = D3D11_MESSAGE_ID_ENCRYPTIONBLT_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_WRONGDEVICE = D3D11_MESSAGE_ID_ENCRYPTIONBLT_NULLPARAM + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_WRONGDEVICE + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_WRONGDEVICE + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_FORMAT_MISMATCH + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_WRONGDEVICE + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SIZE_MISMATCH + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_FORMAT_MISMATCH + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_MULTISAMPLED + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SIZE_MISMATCH + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_NOT_STAGING + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_MULTISAMPLED + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_MAPPED = D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_NOT_STAGING + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_MAPPED = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_MAPPED + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_OFFERED = D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_MAPPED + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_OFFERED = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_OFFERED + 1, + D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_CONTENT_UNDEFINED + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_DST_OFFERED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_UNSUPPORTED + = D3D11_MESSAGE_ID_ENCRYPTIONBLT_SRC_CONTENT_UNDEFINED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_NULLPARAM = D3D11_MESSAGE_ID_DECRYPTIONBLT_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_WRONGDEVICE = D3D11_MESSAGE_ID_DECRYPTIONBLT_NULLPARAM + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_WRONGDEVICE + = D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_WRONGDEVICE + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_FORMAT_MISMATCH + = D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_WRONGDEVICE + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SIZE_MISMATCH + = D3D11_MESSAGE_ID_DECRYPTIONBLT_FORMAT_MISMATCH + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_MULTISAMPLED + = D3D11_MESSAGE_ID_DECRYPTIONBLT_SIZE_MISMATCH + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_NOT_STAGING + = D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_MULTISAMPLED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_NOT_RENDER_TARGET + = D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_NOT_STAGING + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_MAPPED + = D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_NOT_RENDER_TARGET + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_MAPPED = D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_MAPPED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_OFFERED = D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_MAPPED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_OFFERED = D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_OFFERED + 1, + D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_CONTENT_UNDEFINED + = D3D11_MESSAGE_ID_DECRYPTIONBLT_DST_OFFERED + 1, + D3D11_MESSAGE_ID_STARTSESSIONKEYREFRESH_NULLPARAM + = D3D11_MESSAGE_ID_DECRYPTIONBLT_SRC_CONTENT_UNDEFINED + 1, + D3D11_MESSAGE_ID_STARTSESSIONKEYREFRESH_INVALIDSIZE + = D3D11_MESSAGE_ID_STARTSESSIONKEYREFRESH_NULLPARAM + 1, + D3D11_MESSAGE_ID_FINISHSESSIONKEYREFRESH_NULLPARAM + = D3D11_MESSAGE_ID_STARTSESSIONKEYREFRESH_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_GETENCRYPTIONBLTKEY_NULLPARAM + = D3D11_MESSAGE_ID_FINISHSESSIONKEYREFRESH_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETENCRYPTIONBLTKEY_INVALIDSIZE + = D3D11_MESSAGE_ID_GETENCRYPTIONBLTKEY_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCONTENTPROTECTIONCAPS_NULLPARAM + = D3D11_MESSAGE_ID_GETENCRYPTIONBLTKEY_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_CHECKCRYPTOKEYEXCHANGE_NULLPARAM + = D3D11_MESSAGE_ID_GETCONTENTPROTECTIONCAPS_NULLPARAM + 1, + D3D11_MESSAGE_ID_CHECKCRYPTOKEYEXCHANGE_INVALIDINDEX + = D3D11_MESSAGE_ID_CHECKCRYPTOKEYEXCHANGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_NULLPARAM + = D3D11_MESSAGE_ID_CHECKCRYPTOKEYEXCHANGE_INVALIDINDEX + 1, + D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_UNSUPPORTED + = D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_NULLPARAM + 1, + D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_INVALIDTYPE + = D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_OUTOFMEMORY_RETURN + = D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATESIZE_INVALIDCHANNEL + = D3D11_MESSAGE_ID_CREATEAUTHENTICATEDCHANNEL_OUTOFMEMORY_RETURN + 1, + D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATESIZE_NULLPARAM + = D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATESIZE_INVALIDCHANNEL + 1, + D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_INVALIDCHANNEL + = D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATESIZE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_NULLPARAM + = D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_INVALIDCHANNEL + 1, + D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_WRONGSIZE + = D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_NULLPARAM + 1, + D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_INVALIDCHANNEL + = D3D11_MESSAGE_ID_GETAUTHENTICATEDCHANNELCERTIFICATE_WRONGSIZE + 1, + D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_NULLPARAM + = D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_INVALIDCHANNEL + 1, + D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_NULLPARAM + = D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_WRONGCHANNEL + = D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_NULLPARAM + 1, + D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_UNSUPPORTEDQUERY + = D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_WRONGCHANNEL + 1, + D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_WRONGSIZE + = D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_UNSUPPORTEDQUERY + 1, + D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_INVALIDPROCESSINDEX + = D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_WRONGSIZE + 1, + D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_NULLPARAM + = D3D11_MESSAGE_ID_QUERYAUTHENTICATEDCHANNEL_INVALIDPROCESSINDEX + 1, + D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_WRONGCHANNEL + = D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_NULLPARAM + 1, + D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_UNSUPPORTEDCONFIGURE + = D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_WRONGCHANNEL + 1, + D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_WRONGSIZE + = D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_UNSUPPORTEDCONFIGURE + 1, + D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_INVALIDPROCESSIDTYPE + = D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_WRONGSIZE + 1, + D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_CONFIGUREAUTHENTICATEDCHANNEL_INVALIDPROCESSIDTYPE + 1, + D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_VSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_DSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_HSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_GSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + = D3D11_MESSAGE_ID_PSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_NEGOTIATECRPYTOSESSIONKEYEXCHANGE_INVALIDSIZE + = D3D11_MESSAGE_ID_CSSETCONSTANTBUFFERS_INVALIDBUFFEROFFSETORCOUNT + 1, + D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_INVALIDSIZE + = D3D11_MESSAGE_ID_NEGOTIATECRPYTOSESSIONKEYEXCHANGE_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_OFFERRESOURCES_INVALIDPRIORITY + = D3D11_MESSAGE_ID_NEGOTIATEAUTHENTICATEDCHANNELKEYEXCHANGE_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONHANDLE_OUTOFMEMORY + = D3D11_MESSAGE_ID_OFFERRESOURCES_INVALIDPRIORITY + 1, + D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_NULLPARAM + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONHANDLE_OUTOFMEMORY + 1, + D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDTYPE + = D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_NULLPARAM + 1, + D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDBIND + = D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDTYPE + 1, + D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDARRAY + = D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDBIND + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_NULLPARAM + = D3D11_MESSAGE_ID_ACQUIREHANDLEFORCAPTURE_INVALIDARRAY + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_INVALID + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_INVALID + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMROTATION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMROTATION_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDVIEW + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMROTATION_NULLPARAM + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDVIEW + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEEXTENSIONSNOTSUPPORTED + + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_SHADEREXTENSIONSNOTSUPPORTED + + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEEXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_SHADEREXTENSIONSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEEXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_MINPRECISION + = D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_SHADEREXTENSIONSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_UNSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_MINPRECISION + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMALPHA_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMPIXELASPECTRATIO_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEHULLSHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_UAVSNOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_INVALIDOFFSET + = D3D11_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_UAVSNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_TOOMANYVIEWS + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_INVALIDOFFSET + 1, + D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_NOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_TOOMANYVIEWS + 1, + D3D11_MESSAGE_ID_SWAPDEVICECONTEXTSTATE_NOTSUPPORTED + = D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_NOTSUPPORTED + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE_PREFERUPDATESUBRESOURCE1 + = D3D11_MESSAGE_ID_SWAPDEVICECONTEXTSTATE_NOTSUPPORTED + 1, + D3D11_MESSAGE_ID_GETDC_INACCESSIBLE + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE_PREFERUPDATESUBRESOURCE1 + 1, + D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDRECT = D3D11_MESSAGE_ID_GETDC_INACCESSIBLE + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLE_MASK_IGNORED_ON_FL9 + = D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDRECT + 1, + D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE1_NOT_SUPPORTED + = D3D11_MESSAGE_ID_DEVICE_DRAW_SAMPLE_MASK_IGNORED_ON_FL9 + 1, + D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BY_NAME_NOT_SUPPORTED + = D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE1_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_ENQUEUESETEVENT_NOT_SUPPORTED + = D3D11_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BY_NAME_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_OFFERRELEASE_NOT_SUPPORTED + = D3D11_MESSAGE_ID_ENQUEUESETEVENT_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_OFFERRESOURCES_INACCESSIBLE = D3D11_MESSAGE_ID_OFFERRELEASE_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMSAA + = D3D11_MESSAGE_ID_OFFERRESOURCES_INACCESSIBLE + 1, + D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDMSAA + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMSAA + 1, + D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDSOURCERECT + = D3D11_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDMSAA + 1, + D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_EMPTYRECT + = D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDSOURCERECT + 1, + D3D11_MESSAGE_ID_UPDATESUBRESOURCE_EMPTYDESTBOX + = D3D11_MESSAGE_ID_DEVICE_CLEARVIEW_EMPTYRECT + 1, + D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_EMPTYSOURCEBOX + = D3D11_MESSAGE_ID_UPDATESUBRESOURCE_EMPTYDESTBOX + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_LOGIC_OPS + = D3D11_MESSAGE_ID_COPYSUBRESOURCEREGION_EMPTYSOURCEBOX + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_DEPTHSTENCILVIEW_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_LOGIC_OPS + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + = D3D11_MESSAGE_ID_DEVICE_DRAW_DEPTHSTENCILVIEW_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET_DUE_TO_FLIP_PRESENT + = D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET + 1, + D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET_DUE_TO_FLIP_PRESENT + = D3D11_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET_DUE_TO_FLIP_PRESENT + 1, + D3D11_MESSAGE_ID_GETDATAFORNEWHARDWAREKEY_NULLPARAM + = D3D11_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET_DUE_TO_FLIP_PRESENT + 1, + D3D11_MESSAGE_ID_CHECKCRYPTOSESSIONSTATUS_NULLPARAM + = D3D11_MESSAGE_ID_GETDATAFORNEWHARDWAREKEY_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONPRIVATEDATASIZE_NULLPARAM + = D3D11_MESSAGE_ID_CHECKCRYPTOSESSIONSTATUS_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCAPS_NULLPARAM + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONPRIVATEDATASIZE_NULLPARAM + 1, + D3D11_MESSAGE_ID_GETVIDEODECODERCAPS_ZEROWIDTHHEIGHT + = D3D11_MESSAGE_ID_GETVIDEODECODERCAPS_NULLPARAM + 1, + D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_NULLPARAM + = D3D11_MESSAGE_ID_GETVIDEODECODERCAPS_ZEROWIDTHHEIGHT + 1, + D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE + = D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_NULLPARAM + 1, + D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT + = D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE + 1, + D3D11_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_NULLPARAM + = D3D11_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT + 1, + D3D11_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_NULLPARAM + = D3D11_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_NULLPARAM + 1, + D3D11_MESSAGE_ID_CHECKVIDEOPROCESSORFORMATCONVERSION_NULLPARAM + = D3D11_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCOLORSPACE1_NULLPARAM + = D3D11_MESSAGE_ID_CHECKVIDEOPROCESSORFORMATCONVERSION_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCOLORSPACE1_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCOLORSPACE1_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCOLORSPACE1_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_UNSUPPORTED + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE1_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_UNSUPPORTED + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMMIRROR_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE1_NULLPARAM + 1, + D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMMIRROR_NULLPARAM + 1, + D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE + = D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_NULLPARAM + 1, + D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT + = D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSHADERUSAGE_NULLPARAM + = D3D11_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTSHADERUSAGE_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSHADERUSAGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTSHADERUSAGE_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSTREAMCOUNT + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_TARGETRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSTREAMCOUNT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSOURCERECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_TARGETRECT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDDESTRECT + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSOURCERECT + 1, + D3D11_MESSAGE_ID_GETCRYPTOSESSIONPRIVATEDATASIZE_INVALID_KEY_EXCHANGE_TYPE + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDDESTRECT + 1, + D3D11_MESSAGE_ID_D3D11_1_MESSAGES_END + = D3D11_MESSAGE_ID_GETCRYPTOSESSIONPRIVATEDATASIZE_INVALID_KEY_EXCHANGE_TYPE + 1, + D3D11_MESSAGE_ID_D3D11_2_MESSAGES_START = D3D11_MESSAGE_ID_D3D11_1_MESSAGES_END + 1, + D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDUSAGE = D3D11_MESSAGE_ID_D3D11_2_MESSAGES_START + 1, + D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDUSAGE = D3D11_MESSAGE_ID_CREATEBUFFER_INVALIDUSAGE + 1, + D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDUSAGE + = D3D11_MESSAGE_ID_CREATETEXTURE1D_INVALIDUSAGE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_STEPRATE_NOT_1 + = D3D11_MESSAGE_ID_CREATETEXTURE2D_INVALIDUSAGE + 1, + D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_INSTANCING_NOT_SUPPORTED + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_STEPRATE_NOT_1 + 1, + D3D11_MESSAGE_ID_UPDATETILEMAPPINGS_INVALID_PARAMETER + = D3D11_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_INSTANCING_NOT_SUPPORTED + 1, + D3D11_MESSAGE_ID_COPYTILEMAPPINGS_INVALID_PARAMETER + = D3D11_MESSAGE_ID_UPDATETILEMAPPINGS_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_COPYTILES_INVALID_PARAMETER + = D3D11_MESSAGE_ID_COPYTILEMAPPINGS_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_UPDATETILES_INVALID_PARAMETER + = D3D11_MESSAGE_ID_COPYTILES_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_RESIZETILEPOOL_INVALID_PARAMETER + = D3D11_MESSAGE_ID_UPDATETILES_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_TILEDRESOURCEBARRIER_INVALID_PARAMETER + = D3D11_MESSAGE_ID_RESIZETILEPOOL_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_WARNING + = D3D11_MESSAGE_ID_TILEDRESOURCEBARRIER_INVALID_PARAMETER + 1, + D3D11_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_ERROR + = D3D11_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_WARNING + 1, + D3D11_MESSAGE_ID_DIRTY_TILE_MAPPING_ACCESS + = D3D11_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_ERROR + 1, + D3D11_MESSAGE_ID_DUPLICATE_TILE_MAPPINGS_IN_COVERED_AREA + = D3D11_MESSAGE_ID_DIRTY_TILE_MAPPING_ACCESS + 1, + D3D11_MESSAGE_ID_TILE_MAPPINGS_IN_COVERED_AREA_DUPLICATED_OUTSIDE + = D3D11_MESSAGE_ID_DUPLICATE_TILE_MAPPINGS_IN_COVERED_AREA + 1, + D3D11_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INCOMPATIBLE_RESOURCES + = D3D11_MESSAGE_ID_TILE_MAPPINGS_IN_COVERED_AREA_DUPLICATED_OUTSIDE + 1, + D3D11_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INPUT_AND_OUTPUT + = D3D11_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INCOMPATIBLE_RESOURCES + 1, + D3D11_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_INVALIDFLAGS + = D3D11_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INPUT_AND_OUTPUT + 1, + D3D11_MESSAGE_ID_GETRESOURCETILING_NONTILED_RESOURCE + = D3D11_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_INVALIDFLAGS + 1, + D3D11_MESSAGE_ID_RESIZETILEPOOL_SHRINK_WITH_MAPPINGS_STILL_DEFINED_PAST_END + = D3D11_MESSAGE_ID_GETRESOURCETILING_NONTILED_RESOURCE + 1, + D3D11_MESSAGE_ID_NEED_TO_CALL_TILEDRESOURCEBARRIER + = D3D11_MESSAGE_ID_RESIZETILEPOOL_SHRINK_WITH_MAPPINGS_STILL_DEFINED_PAST_END + 1, + D3D11_MESSAGE_ID_CREATEDEVICE_INVALIDARGS + = D3D11_MESSAGE_ID_NEED_TO_CALL_TILEDRESOURCEBARRIER + 1, + D3D11_MESSAGE_ID_CREATEDEVICE_WARNING = D3D11_MESSAGE_ID_CREATEDEVICE_INVALIDARGS + 1, + D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWUINT_HAZARD + = D3D11_MESSAGE_ID_CREATEDEVICE_WARNING + 1, + D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWFLOAT_HAZARD + = D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWUINT_HAZARD + 1, + D3D11_MESSAGE_ID_TILED_RESOURCE_TIER_1_BUFFER_TEXTURE_MISMATCH + = D3D11_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWFLOAT_HAZARD + 1, + D3D11_MESSAGE_ID_CREATE_CRYPTOSESSION + = D3D11_MESSAGE_ID_TILED_RESOURCE_TIER_1_BUFFER_TEXTURE_MISMATCH + 1, + D3D11_MESSAGE_ID_CREATE_AUTHENTICATEDCHANNEL = D3D11_MESSAGE_ID_CREATE_CRYPTOSESSION + 1, + D3D11_MESSAGE_ID_LIVE_CRYPTOSESSION = D3D11_MESSAGE_ID_CREATE_AUTHENTICATEDCHANNEL + 1, + D3D11_MESSAGE_ID_LIVE_AUTHENTICATEDCHANNEL = D3D11_MESSAGE_ID_LIVE_CRYPTOSESSION + 1, + D3D11_MESSAGE_ID_DESTROY_CRYPTOSESSION = D3D11_MESSAGE_ID_LIVE_AUTHENTICATEDCHANNEL + 1, + D3D11_MESSAGE_ID_DESTROY_AUTHENTICATEDCHANNEL = D3D11_MESSAGE_ID_DESTROY_CRYPTOSESSION + 1, + D3D11_MESSAGE_ID_D3D11_2_MESSAGES_END = D3D11_MESSAGE_ID_DESTROY_AUTHENTICATEDCHANNEL + 1, + D3D11_MESSAGE_ID_D3D11_3_MESSAGES_START = D3D11_MESSAGE_ID_D3D11_2_MESSAGES_END + 1, + D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALID_CONSERVATIVERASTERMODE + = D3D11_MESSAGE_ID_D3D11_3_MESSAGES_START + 1, + D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_SYSTEMVALUE + = D3D11_MESSAGE_ID_CREATERASTERIZERSTATE_INVALID_CONSERVATIVERASTERMODE + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDCONTEXTTYPE + = D3D11_MESSAGE_ID_DEVICE_DRAW_INVALID_SYSTEMVALUE + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_DECODENOTSUPPORTED + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDCONTEXTTYPE + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_ENCODENOTSUPPORTED + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_DECODENOTSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDPLANEINDEX + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_ENCODENOTSUPPORTED + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_AMBIGUOUSVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDPLANEINDEX + = D3D11_MESSAGE_ID_CREATESHADERRESOURCEVIEW_AMBIGUOUSVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_AMBIGUOUSVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDPLANEINDEX + = D3D11_MESSAGE_ID_CREATERENDERTARGETVIEW_AMBIGUOUSVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDPLANEINDEX + 1, + D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_AMBIGUOUSVIDEOPLANEINDEX + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSCANDATAOFFSET + = D3D11_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_AMBIGUOUSVIDEOPLANEINDEX + 1, + D3D11_MESSAGE_ID_JPEGDECODE_NOTSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSCANDATAOFFSET + 1, + D3D11_MESSAGE_ID_JPEGDECODE_DIMENSIONSTOOLARGE = D3D11_MESSAGE_ID_JPEGDECODE_NOTSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDCOMPONENTS + = D3D11_MESSAGE_ID_JPEGDECODE_DIMENSIONSTOOLARGE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_DESTINATIONNOT2D + = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDCOMPONENTS + 1, + D3D11_MESSAGE_ID_JPEGDECODE_TILEDRESOURCESUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_DESTINATIONNOT2D + 1, + D3D11_MESSAGE_ID_JPEGDECODE_GUARDRECTSUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_TILEDRESOURCESUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_FORMATUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_GUARDRECTSUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_JPEGDECODE_FORMATUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDMIPLEVEL + = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_EMPTYDESTBOX = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDMIPLEVEL + 1, + D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXNOT2D = D3D11_MESSAGE_ID_JPEGDECODE_EMPTYDESTBOX + 1, + D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXNOTSUB = D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXNOT2D + 1, + D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXESINTERSECT = D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXNOTSUB + 1, + D3D11_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEMISMATCH + = D3D11_MESSAGE_ID_JPEGDECODE_DESTBOXESINTERSECT + 1, + D3D11_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEMISMATCH + = D3D11_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEODD = D3D11_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEODD = D3D11_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEODD + 1, + D3D11_MESSAGE_ID_JPEGDECODE_OUTPUTDIMENSIONSTOOLARGE + = D3D11_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEODD + 1, + D3D11_MESSAGE_ID_JPEGDECODE_NONPOW2SCALEUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_OUTPUTDIMENSIONSTOOLARGE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_FRACTIONALDOWNSCALETOLARGE + = D3D11_MESSAGE_ID_JPEGDECODE_NONPOW2SCALEUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_CHROMASIZEMISMATCH + = D3D11_MESSAGE_ID_JPEGDECODE_FRACTIONALDOWNSCALETOLARGE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_LUMACHROMASIZEMISMATCH + = D3D11_MESSAGE_ID_JPEGDECODE_CHROMASIZEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDNUMDESTINATIONS + = D3D11_MESSAGE_ID_JPEGDECODE_LUMACHROMASIZEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGDECODE_SUBBOXUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDNUMDESTINATIONS + 1, + D3D11_MESSAGE_ID_JPEGDECODE_1DESTUNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_JPEGDECODE_SUBBOXUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_3DESTUNSUPPORTEDFORMAT + = D3D11_MESSAGE_ID_JPEGDECODE_1DESTUNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_JPEGDECODE_SCALEUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_3DESTUNSUPPORTEDFORMAT + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSOURCESIZE + = D3D11_MESSAGE_ID_JPEGDECODE_SCALEUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGDECODE_INVALIDCOPYFLAGS + = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDSOURCESIZE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_HAZARD = D3D11_MESSAGE_ID_JPEGDECODE_INVALIDCOPYFLAGS + 1, + D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERUSAGE = D3D11_MESSAGE_ID_JPEGDECODE_HAZARD + 1, + D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERMISCFLAGS + = D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERUSAGE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDDSTTEXTUREUSAGE + = D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERMISCFLAGS + 1, + D3D11_MESSAGE_ID_JPEGDECODE_BACKBUFFERNOTSUPPORTED + = D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDDSTTEXTUREUSAGE + 1, + D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPRTEDCOPYFLAGS + = D3D11_MESSAGE_ID_JPEGDECODE_BACKBUFFERNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGENCODE_NOTSUPPORTED = D3D11_MESSAGE_ID_JPEGDECODE_UNSUPPRTEDCOPYFLAGS + 1, + D3D11_MESSAGE_ID_JPEGENCODE_INVALIDSCANDATAOFFSET + = D3D11_MESSAGE_ID_JPEGENCODE_NOTSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGENCODE_INVALIDCOMPONENTS + = D3D11_MESSAGE_ID_JPEGENCODE_INVALIDSCANDATAOFFSET + 1, + D3D11_MESSAGE_ID_JPEGENCODE_SOURCENOT2D = D3D11_MESSAGE_ID_JPEGENCODE_INVALIDCOMPONENTS + 1, + D3D11_MESSAGE_ID_JPEGENCODE_TILEDRESOURCESUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGENCODE_SOURCENOT2D + 1, + D3D11_MESSAGE_ID_JPEGENCODE_GUARDRECTSUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGENCODE_TILEDRESOURCESUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGENCODE_XSUBSAMPLEMISMATCH + = D3D11_MESSAGE_ID_JPEGENCODE_GUARDRECTSUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGENCODE_YSUBSAMPLEMISMATCH + = D3D11_MESSAGE_ID_JPEGENCODE_XSUBSAMPLEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGENCODE_FORMATUNSUPPORTED + = D3D11_MESSAGE_ID_JPEGENCODE_YSUBSAMPLEMISMATCH + 1, + D3D11_MESSAGE_ID_JPEGENCODE_INVALIDSUBRESOURCE + = D3D11_MESSAGE_ID_JPEGENCODE_FORMATUNSUPPORTED + 1, + D3D11_MESSAGE_ID_JPEGENCODE_INVALIDMIPLEVEL + = D3D11_MESSAGE_ID_JPEGENCODE_INVALIDSUBRESOURCE + 1, + D3D11_MESSAGE_ID_JPEGENCODE_DIMENSIONSTOOLARGE + = D3D11_MESSAGE_ID_JPEGENCODE_INVALIDMIPLEVEL + 1, + D3D11_MESSAGE_ID_JPEGENCODE_HAZARD = D3D11_MESSAGE_ID_JPEGENCODE_DIMENSIONSTOOLARGE + 1, + D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERUSAGE = D3D11_MESSAGE_ID_JPEGENCODE_HAZARD + 1, + D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERMISCFLAGS + = D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERUSAGE + 1, + D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDSRCTEXTUREUSAGE + = D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERMISCFLAGS + 1, + D3D11_MESSAGE_ID_JPEGENCODE_BACKBUFFERNOTSUPPORTED + = D3D11_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDSRCTEXTUREUSAGE + 1, + D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_UNSUPPORTEDCONTEXTTTYPEFORQUERY + = D3D11_MESSAGE_ID_JPEGENCODE_BACKBUFFERNOTSUPPORTED + 1, + D3D11_MESSAGE_ID_FLUSH1_INVALIDCONTEXTTYPE + = D3D11_MESSAGE_ID_CREATEQUERYORPREDICATE_UNSUPPORTEDCONTEXTTTYPEFORQUERY + 1, + D3D11_MESSAGE_ID_DEVICE_SETHARDWAREPROTECTION_INVALIDCONTEXT + = D3D11_MESSAGE_ID_FLUSH1_INVALIDCONTEXTTYPE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTHDRMETADATA_NULLPARAM + = D3D11_MESSAGE_ID_DEVICE_SETHARDWAREPROTECTION_INVALIDCONTEXT + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTHDRMETADATA_INVALIDSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTHDRMETADATA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTHDRMETADATA_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTHDRMETADATA_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTHDRMETADATA_INVALIDSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTHDRMETADATA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTHDRMETADATA_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_INVALIDSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_NULLPARAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORSETSTREAMHDRMETADATA_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_NULLPARAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_INVALIDSIZE + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFRAMEFORMAT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMHDRMETADATA_INVALIDSIZE + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFRAMEFORMAT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMOUTPUTRATE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSOURCERECT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMOUTPUTRATE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMDESTRECT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSOURCERECT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMALPHA_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMDESTRECT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPALETTE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMALPHA_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPIXELASPECTRATIO_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPALETTE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMLUMAKEY_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMPIXELASPECTRATIO_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSTEREOFORMAT_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMLUMAKEY_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMAUTOPROCESSINGMODE_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMSTEREOFORMAT_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFILTER_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMAUTOPROCESSINGMODE_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMROTATION_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMFILTER_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE1_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMROTATION_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMMIRROR_INVALIDSTREAM + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE1_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_CREATE_FENCE + = D3D11_MESSAGE_ID_VIDEOPROCESSORGETSTREAMMIRROR_INVALIDSTREAM + 1, + D3D11_MESSAGE_ID_LIVE_FENCE = D3D11_MESSAGE_ID_CREATE_FENCE + 1, + D3D11_MESSAGE_ID_DESTROY_FENCE = D3D11_MESSAGE_ID_LIVE_FENCE + 1, + D3D11_MESSAGE_ID_D3D11_3_MESSAGES_END = D3D11_MESSAGE_ID_DESTROY_FENCE + 1, +}} +STRUCT!{struct D3D11_MESSAGE { + Category: D3D11_MESSAGE_CATEGORY, + Severity: D3D11_MESSAGE_SEVERITY, + ID: D3D11_MESSAGE_ID, + pDescription: *const c_char, + DescriptionByteLength: SIZE_T, +}} +STRUCT!{struct D3D11_INFO_QUEUE_FILTER_DESC { + NumCategories: UINT, + pCategoryList: *const D3D11_MESSAGE_CATEGORY, + NumSeverities: UINT, + pSeverityList: *const D3D11_MESSAGE_SEVERITY, + NumIDs: UINT, + pIDList: *const D3D11_MESSAGE_ID, +}} +STRUCT!{struct D3D11_INFO_QUEUE_FILTER { + AllowList: D3D11_INFO_QUEUE_FILTER_DESC, + DenyList: D3D11_INFO_QUEUE_FILTER_DESC, +}} +pub const D3D11_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT: UINT64 = 1024; +RIDL!{#[uuid(0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6)] +interface ID3D11InfoQueue(ID3D11InfoQueueVtbl): IUnknown(IUnknownVtbl) { + fn SetMessageCountLimit( + MessageCountLimit: UINT64, + ) -> HRESULT, + fn ClearStoredMessages() -> (), + fn GetMessage( + MessageIndex: UINT64, + pMessage: *mut D3D11_MESSAGE, + pMessageByteLength: *mut SIZE_T, + ) -> HRESULT, + fn GetNumMessagesAllowedByStorageFilter() -> UINT64, + fn GetNumMessagesDeniedByStorageFilter() -> UINT64, + fn GetNumStoredMessages() -> UINT64, + fn GetNumStoredMessagesAllowedByRetrievalFilter() -> UINT64, + fn GetNumMessagesDiscardedByMessageCountLimit() -> UINT64, + fn GetMessageCountLimit() -> UINT64, + fn AddStorageFilterEntries( + pFilter: *const D3D11_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetStorageFilter( + pFilter: *mut D3D11_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearStorageFilter() -> (), + fn PushEmptyStorageFilter() -> HRESULT, + fn PushCopyOfStorageFilter() -> HRESULT, + fn PushStorageFilter( + pFilter: *const D3D11_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopStorageFilter() -> (), + fn GetStorageFilterStackSize() -> UINT, + fn AddRetrievalFilterEntries( + pFilter: *const D3D11_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetRetrievalFilter( + pFilter: *mut D3D11_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearRetrievalFilter() -> (), + fn PushEmptyRetrievalFilter() -> HRESULT, + fn PushCopyOfRetrievalFilter() -> HRESULT, + fn PushRetrievalFilter( + pFilter: *const D3D11_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopRetrievalFilter() -> (), + fn GetRetrievalFilterStackSize() -> UINT, + fn AddMessage( + Category: D3D11_MESSAGE_CATEGORY, + Severity: D3D11_MESSAGE_SEVERITY, + ID: D3D11_MESSAGE_ID, + pDescription: LPCSTR, + ) -> HRESULT, + fn AddApplicationMessage( + Severity: D3D11_MESSAGE_SEVERITY, + pDescription: LPCSTR, + ) -> HRESULT, + fn SetBreakOnCategory( + Category: D3D11_MESSAGE_CATEGORY, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnSeverity( + ID: D3D11_MESSAGE_ID, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnID( + Severity: D3D11_MESSAGE_SEVERITY, + bEnable: BOOL, + ) -> HRESULT, + fn GetBreakOnCategory( + Category: D3D11_MESSAGE_CATEGORY, + ) -> BOOL, + fn GetBreakOnSeverity( + Severity: D3D11_MESSAGE_SEVERITY, + ) -> BOOL, + fn GetBreakOnID( + ID: D3D11_MESSAGE_ID, + ) -> BOOL, + fn SetMuteDebugOutput( + bMute: BOOL, + ) -> (), + fn GetMuteDebugOutput() -> BOOL, +}} +DEFINE_GUID!{IID_ID3D11Debug, + 0x79cf2233, 0x7536, 0x4948, 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60} +DEFINE_GUID!{IID_ID3D11SwitchToRef, + 0x1ef337e3, 0x58e7, 0x4f83, 0xa6, 0x92, 0xdb, 0x22, 0x1f, 0x5e, 0xd4, 0x7e} +DEFINE_GUID!{IID_ID3D11TracingDevice, + 0x1911c771, 0x1587, 0x413e, 0xa7, 0xe0, 0xfb, 0x26, 0xc3, 0xde, 0x02, 0x68} +DEFINE_GUID!{IID_ID3D11RefTrackingOptions, + 0x193dacdf, 0x0db2, 0x4c05, 0xa5, 0x5c, 0xef, 0x06, 0xca, 0xc5, 0x6f, 0xd9} +DEFINE_GUID!{IID_ID3D11RefDefaultTrackingOptions, + 0x03916615, 0xc644, 0x418c, 0x9b, 0xf4, 0x75, 0xdb, 0x5b, 0xe6, 0x3c, 0xa0} +DEFINE_GUID!{IID_ID3D11InfoQueue, + 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6} diff --git a/winapi/src/um/d3d11shader.rs b/winapi/src/um/d3d11shader.rs new file mode 100644 index 000000000..ebe06b424 --- /dev/null +++ b/winapi/src/um/d3d11shader.rs @@ -0,0 +1,477 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_int; +use shared::basetsd::UINT64; +use shared::minwindef::{BOOL, BYTE, INT, LPVOID, UINT}; +use um::d3dcommon::{ + D3D_CBUFFER_TYPE, D3D_FEATURE_LEVEL, D3D_INTERPOLATION_MODE, D3D_MIN_PRECISION, D3D_NAME, + D3D_PARAMETER_FLAGS, D3D_PRIMITIVE, D3D_PRIMITIVE_TOPOLOGY, D3D_REGISTER_COMPONENT_TYPE, + D3D_RESOURCE_RETURN_TYPE, D3D_SHADER_INPUT_TYPE, D3D_SHADER_VARIABLE_CLASS, + D3D_SHADER_VARIABLE_TYPE, D3D_SRV_DIMENSION, D3D_TESSELLATOR_DOMAIN, + D3D_TESSELLATOR_OUTPUT_PRIMITIVE, D3D_TESSELLATOR_PARTITIONING, ID3DBlob, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +ENUM!{enum D3D11_SHADER_VERSION_TYPE { + D3D11_SHVER_PIXEL_SHADER = 0, + D3D11_SHVER_VERTEX_SHADER = 1, + D3D11_SHVER_GEOMETRY_SHADER = 2, + D3D11_SHVER_HULL_SHADER = 3, + D3D11_SHVER_DOMAIN_SHADER = 4, + D3D11_SHVER_COMPUTE_SHADER = 5, + D3D11_SHVER_RESERVED0 = 0xFFF0, +}} +pub const D3D_RETURN_PARAMETER_INDEX: c_int = -1; +pub type D3D11_RESOURCE_RETURN_TYPE = D3D_RESOURCE_RETURN_TYPE; +pub type D3D11_CBUFFER_TYPE = D3D_CBUFFER_TYPE; +STRUCT!{struct D3D11_SIGNATURE_PARAMETER_DESC { + SemanticName: LPCSTR, + SemanticIndex: UINT, + Register: UINT, + SystemValueType: D3D_NAME, + ComponentType: D3D_REGISTER_COMPONENT_TYPE, + Mask: BYTE, + ReadWriteMask: BYTE, + Stream: UINT, + MinPrecision: D3D_MIN_PRECISION, +}} +STRUCT!{struct D3D11_SHADER_BUFFER_DESC { + Name: LPCSTR, + Type: D3D_CBUFFER_TYPE, + Variables: UINT, + Size: UINT, + uFlags: UINT, +}} +STRUCT!{struct D3D11_SHADER_VARIABLE_DESC { + Name: LPCSTR, + StartOffset: UINT, + Size: UINT, + uFlags: UINT, + DefaultValue: LPVOID, + StartTexture: UINT, + TextureSize: UINT, + StartSampler: UINT, + SamplerSize: UINT, +}} +STRUCT!{struct D3D11_SHADER_TYPE_DESC { + Class: D3D_SHADER_VARIABLE_CLASS, + Type: D3D_SHADER_VARIABLE_TYPE, + Rows: UINT, + Columns: UINT, + Elements: UINT, + Members: UINT, + Offset: UINT, + Name: LPCSTR, +}} +pub type D3D11_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN; +pub type D3D11_TESSELLATOR_PARTITIONING = D3D_TESSELLATOR_PARTITIONING; +pub type D3D11_TESSELLATOR_OUTPUT_PRIMITIVE = D3D_TESSELLATOR_OUTPUT_PRIMITIVE; +STRUCT!{struct D3D11_SHADER_DESC { + Version: UINT, + Creator: LPCSTR, + Flags: UINT, + ConstantBuffers: UINT, + BoundResources: UINT, + InputParameters: UINT, + OutputParameters: UINT, + InstructionCount: UINT, + TempRegisterCount: UINT, + TempArrayCount: UINT, + DefCount: UINT, + DclCount: UINT, + TextureNormalInstructions: UINT, + TextureLoadInstructions: UINT, + TextureCompInstructions: UINT, + TextureBiasInstructions: UINT, + TextureGradientInstructions: UINT, + FloatInstructionCount: UINT, + IntInstructionCount: UINT, + UintInstructionCount: UINT, + StaticFlowControlCount: UINT, + DynamicFlowControlCount: UINT, + MacroInstructionCount: UINT, + ArrayInstructionCount: UINT, + CutInstructionCount: UINT, + EmitInstructionCount: UINT, + GSOutputTopology: D3D_PRIMITIVE_TOPOLOGY, + GSMaxOutputVertexCount: UINT, + InputPrimitive: D3D_PRIMITIVE, + PatchConstantParameters: UINT, + cGSInstanceCount: UINT, + cControlPoints: UINT, + HSOutputPrimitive: D3D_TESSELLATOR_OUTPUT_PRIMITIVE, + HSPartitioning: D3D_TESSELLATOR_PARTITIONING, + TessellatorDomain: D3D_TESSELLATOR_DOMAIN, + cBarrierInstructions: UINT, + cInterlockedInstructions: UINT, + cTextureStoreInstructions: UINT, +}} +STRUCT!{struct D3D11_SHADER_INPUT_BIND_DESC { + Name: LPCSTR, + Type: D3D_SHADER_INPUT_TYPE, + BindPoint: UINT, + BindCount: UINT, + uFlags: UINT, + ReturnType: D3D_RESOURCE_RETURN_TYPE, + Dimension: D3D_SRV_DIMENSION, + NumSamples: UINT, +}} +pub const D3D_SHADER_REQUIRES_DOUBLES: UINT64 = 0x00000001; +pub const D3D_SHADER_REQUIRES_EARLY_DEPTH_STENCIL: UINT64 = 0x00000002; +pub const D3D_SHADER_REQUIRES_UAVS_AT_EVERY_STAGE: UINT64 = 0x00000004; +pub const D3D_SHADER_REQUIRES_64_UAVS: UINT64 = 0x00000008; +pub const D3D_SHADER_REQUIRES_MINIMUM_PRECISION: UINT64 = 0x00000010; +pub const D3D_SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS: UINT64 = 0x00000020; +pub const D3D_SHADER_REQUIRES_11_1_SHADER_EXTENSIONS: UINT64 = 0x00000040; +pub const D3D_SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING: UINT64 = 0x00000080; +pub const D3D_SHADER_REQUIRES_TILED_RESOURCES: UINT64 = 0x00000100; +STRUCT!{struct D3D11_LIBRARY_DESC { + Creator: LPCSTR, + Flags: UINT, + FunctionCount: UINT, +}} +STRUCT!{struct D3D11_FUNCTION_DESC { + Version: UINT, + Creator: LPCSTR, + Flags: UINT, + ConstantBuffers: UINT, + BoundResources: UINT, + InstructionCount: UINT, + TempRegisterCount: UINT, + TempArrayCount: UINT, + DefCount: UINT, + DclCount: UINT, + TextureNormalInstructions: UINT, + TextureLoadInstructions: UINT, + TextureCompInstructions: UINT, + TextureBiasInstructions: UINT, + TextureGradientInstructions: UINT, + FloatInstructionCount: UINT, + IntInstructionCount: UINT, + UintInstructionCount: UINT, + StaticFlowControlCount: UINT, + DynamicFlowControlCount: UINT, + MacroInstructionCount: UINT, + ArrayInstructionCount: UINT, + MovInstructionCount: UINT, + MovcInstructionCount: UINT, + ConversionInstructionCount: UINT, + BitwiseInstructionCount: UINT, + MinFeatureLevel: D3D_FEATURE_LEVEL, + RequiredFeatureFlags: UINT64, + Name: LPCSTR, + FunctionParameterCount: INT, + HasReturn: BOOL, + Has10Level9VertexShader: BOOL, + Has10Level9PixelShader: BOOL, +}} +STRUCT!{struct D3D11_PARAMETER_DESC { + Name: LPCSTR, + SemanticName: LPCSTR, + Type: D3D_SHADER_VARIABLE_TYPE, + Class: D3D_SHADER_VARIABLE_CLASS, + Rows: UINT, + Columns: UINT, + InterpolationMode: D3D_INTERPOLATION_MODE, + Flags: D3D_PARAMETER_FLAGS, + FirstInRegister: UINT, + FirstInComponent: UINT, + FirstOutRegister: UINT, + FirstOutComponent: UINT, +}} +DEFINE_GUID!{IID_ID3D11ShaderReflectionType, + 0x6e6ffa6a, 0x9bae, 0x4613, 0xa5, 0x1e, 0x91, 0x65, 0x2d, 0x50, 0x8c, 0x21} +RIDL!{#[uuid(0x6e6ffa6a, 0x9bae, 0x4613, 0xa5, 0x1e, 0x91, 0x65, 0x2d, 0x50, 0x8c, 0x21)] +interface ID3D11ShaderReflectionType(ID3D11ShaderReflectionTypeVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SHADER_TYPE_DESC, + ) -> HRESULT, + fn GetMemberTypeByIndex( + Index: UINT, + ) -> *mut ID3D11ShaderReflectionType, + fn GetMemberTypeByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionType, + fn GetMemberTypeName( + Index: UINT, + ) -> LPCSTR, + fn IsEqual( + pType: *mut ID3D11ShaderReflectionType, + ) -> HRESULT, + fn GetSubType() -> *mut ID3D11ShaderReflectionType, + fn GetBaseClass() -> *mut ID3D11ShaderReflectionType, + fn GetNumInterfaces() -> UINT, + fn GetInterfaceByIndex( + uIndex: UINT, + ) -> *mut ID3D11ShaderReflectionType, + fn IsOfType( + pType: *mut ID3D11ShaderReflectionType, + ) -> HRESULT, + fn ImplementsInterface( + pBase: *mut ID3D11ShaderReflectionType, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D11ShaderReflectionVariable, + 0x51f23923, 0xf3e5, 0x4bd1, 0x91, 0xcb, 0x60, 0x61, 0x77, 0xd8, 0xdb, 0x4c} +RIDL!{#[uuid(0x51f23923, 0xf3e5, 0x4bd1, 0x91, 0xcb, 0x60, 0x61, 0x77, 0xd8, 0xdb, 0x4c)] +interface ID3D11ShaderReflectionVariable(ID3D11ShaderReflectionVariableVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SHADER_VARIABLE_DESC, + ) -> HRESULT, + fn GetType() -> *mut ID3D11ShaderReflectionType, + fn GetBuffer() -> *mut ID3D11ShaderReflectionConstantBuffer, + fn GetInterfaceSlot( + uArrayIndex: UINT, + ) -> UINT, +}} +DEFINE_GUID!{IID_ID3D11ShaderReflectionConstantBuffer, + 0xeb62d63d, 0x93dd, 0x4318, 0x8a, 0xe8, 0xc6, 0xf8, 0x3a, 0xd3, 0x71, 0xb8} +RIDL!{#[uuid(0xeb62d63d, 0x93dd, 0x4318, 0x8a, 0xe8, 0xc6, 0xf8, 0x3a, 0xd3, 0x71, 0xb8)] +interface ID3D11ShaderReflectionConstantBuffer(ID3D11ShaderReflectionConstantBufferVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SHADER_BUFFER_DESC, + ) -> HRESULT, + fn GetVariableByIndex( + Index: UINT, + ) -> *mut ID3D11ShaderReflectionVariable, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionVariable, +}} +DEFINE_GUID!{IID_ID3D11ShaderReflection, + 0x8d536ca1, 0x0cca, 0x4956, 0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84} +RIDL!{#[uuid(0x8d536ca1, 0x0cca, 0x4956, 0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84)] +interface ID3D11ShaderReflection(ID3D11ShaderReflectionVtbl): IUnknown(IUnknownVtbl) { + fn GetDesc( + pDesc: *mut D3D11_SHADER_DESC, + ) -> HRESULT, + fn GetConstantBufferByIndex( + Index: UINT, + ) -> *mut ID3D11ShaderReflectionConstantBuffer, + fn GetConstantBufferByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionConstantBuffer, + fn GetResourceBindingDesc( + ResourceIndex: UINT, + pDesc: *mut D3D11_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetInputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D11_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetOutputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D11_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetPatchConstantParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D11_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionVariable, + fn GetResourceBindingDescByName( + Name: LPCSTR, + pDesc: *mut D3D11_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetMovInstructionCount() -> UINT, + fn GetMovcInstructionCount() -> UINT, + fn GetConversionInstructionCount() -> UINT, + fn GetBitwiseInstructionCount() -> UINT, + fn GetGSInputPrimitive() -> D3D_PRIMITIVE, + fn IsSampleFrequencyShader() -> BOOL, + fn GetNumInterfaceSlots() -> UINT, + fn GetMinFeatureLevel( + pLevel: *mut D3D_FEATURE_LEVEL, + ) -> HRESULT, + fn GetThreadGroupSize( + pSizeX: *mut UINT, + pSizeY: *mut UINT, + pSizeZ: *mut UINT, + ) -> UINT, + fn GetRequiresFlags() -> UINT64, +}} +DEFINE_GUID!{IID_ID3D11LibraryReflection, + 0x54384f1b, 0x5b3e, 0x4bb7, 0xae, 0x01, 0x60, 0xba, 0x30, 0x97, 0xcb, 0xb6} +RIDL!{#[uuid(0x54384f1b, 0x5b3e, 0x4bb7, 0xae, 0x01, 0x60, 0xba, 0x30, 0x97, 0xcb, 0xb6)] +interface ID3D11LibraryReflection(ID3D11LibraryReflectionVtbl): IUnknown(IUnknownVtbl) { + fn GetDesc( + pDesc: *mut D3D11_LIBRARY_DESC, + ) -> HRESULT, + fn GetFunctionByIndex( + FunctionIndex: INT, + ) -> *mut ID3D11FunctionReflection, +}} +DEFINE_GUID!{IID_ID3D11FunctionReflection, + 0x207bcecb, 0xd683, 0x4a06, 0xa8, 0xa3, 0x9b, 0x14, 0x9b, 0x9f, 0x73, 0xa4} +RIDL!{#[uuid(0x207bcecb, 0xd683, 0x4a06, 0xa8, 0xa3, 0x9b, 0x14, 0x9b, 0x9f, 0x73, 0xa4)] +interface ID3D11FunctionReflection(ID3D11FunctionReflectionVtbl) { + fn GetDesc( + pDesc: *mut D3D11_FUNCTION_DESC, + ) -> HRESULT, + fn GetConstantBufferByIndex( + BufferIndex: UINT, + ) -> *mut ID3D11ShaderReflectionConstantBuffer, + fn GetConstantBufferByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionConstantBuffer, + fn GetResourceBindingDesc( + ResourceIndex: UINT, + pDesc: *mut D3D11_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D11ShaderReflectionVariable, + fn GetResourceBindingDescByName( + Name: LPCSTR, + pDesc: *mut D3D11_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetFunctionParameter( + ParameterIndex: INT, + ) -> *mut ID3D11FunctionParameterReflection, +}} +DEFINE_GUID!{IID_ID3D11FunctionParameterReflection, + 0x42757488, 0x334f, 0x47fe, 0x98, 0x2e, 0x1a, 0x65, 0xd0, 0x8c, 0xc4, 0x62} +RIDL!{#[uuid(0x42757488, 0x334f, 0x47fe, 0x98, 0x2e, 0x1a, 0x65, 0xd0, 0x8c, 0xc4, 0x62)] +interface ID3D11FunctionParameterReflection(ID3D11FunctionParameterReflectionVtbl) { + fn GetDesc( + pDesc: *mut D3D11_PARAMETER_DESC, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D11Module, + 0xcac701ee, 0x80fc, 0x4122, 0x82, 0x42, 0x10, 0xb3, 0x9c, 0x8c, 0xec, 0x34} +RIDL!{#[uuid(0xcac701ee, 0x80fc, 0x4122, 0x82, 0x42, 0x10, 0xb3, 0x9c, 0x8c, 0xec, 0x34)] +interface ID3D11Module(ID3D11ModuleVtbl): IUnknown(IUnknownVtbl) { + fn CreateInstance( + pNamespace: LPCSTR, + ppModuleInstance: *mut *mut ID3D11ModuleInstance, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D11ModuleInstance, + 0x469e07f7, 0x045a, 0x48d5, 0xaa, 0x12, 0x68, 0xa4, 0x78, 0xcd, 0xf7, 0x5d} +RIDL!{#[uuid(0x469e07f7, 0x045a, 0x48d5, 0xaa, 0x12, 0x68, 0xa4, 0x78, 0xcd, 0xf7, 0x5d)] +interface ID3D11ModuleInstance(ID3D11ModuleInstanceVtbl): IUnknown(IUnknownVtbl) { + fn BindConstantBuffer( + uSrcSlot: UINT, + uDstSlot: UINT, + cbDstOffset: UINT, + ) -> HRESULT, + fn BindConstantBufferByName( + pName: LPCSTR, + uDstSlot: UINT, + cbDstOffset: UINT, + ) -> HRESULT, + fn BindResource( + uSrcSlot: UINT, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindResourceByName( + pName: LPCSTR, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindSampler( + uSrcSlot: UINT, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindSamplerByName( + pName: LPCSTR, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindUnorderedAccessView( + uSrcSlot: UINT, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindUnorderedAccessViewByName( + pName: LPCSTR, + uDstSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindResourceAsUnorderedAccessView( + uSrcSrvSlot: UINT, + uDstUavSlot: UINT, + uCount: UINT, + ) -> HRESULT, + fn BindResourceAsUnorderedAccessViewByName( + pSrvName: LPCSTR, + uDstUavSlot: UINT, + uCount: UINT, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D11Linker, + 0x59a6cd0e, 0xe10d, 0x4c1f, 0x88, 0xc0, 0x63, 0xab, 0xa1, 0xda, 0xf3, 0x0e} +RIDL!{#[uuid(0x59a6cd0e, 0xe10d, 0x4c1f, 0x88, 0xc0, 0x63, 0xab, 0xa1, 0xda, 0xf3, 0x0e)] +interface ID3D11Linker(ID3D11LinkerVtbl): IUnknown(IUnknownVtbl) { + fn Link( + pEntry: *mut ID3D11ModuleInstance, + pEntryName: LPCSTR, + pTargetName: LPCSTR, + uFlags: UINT, + ppShaderBlob: *mut *mut ID3DBlob, + ppErrorBuffer: *mut *mut ID3DBlob, + ) -> HRESULT, + fn UseLibrary( + pLibraryMI: *mut ID3D11ModuleInstance, + ) -> HRESULT, + fn AddClipPlaneFromCBuffer( + uCBufferSlot: UINT, + uCBufferEntry: UINT, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D11LinkingNode, + 0xd80dd70c, 0x8d2f, 0x4751, 0x94, 0xa1, 0x03, 0xc7, 0x9b, 0x35, 0x56, 0xdb} +RIDL!{#[uuid(0xd80dd70c, 0x8d2f, 0x4751, 0x94, 0xa1, 0x03, 0xc7, 0x9b, 0x35, 0x56, 0xdb)] +interface ID3D11LinkingNode(ID3D11LinkingNodeVtbl): IUnknown(IUnknownVtbl) {}} +DEFINE_GUID!{IID_ID3D11FunctionLinkingGraph, + 0x54133220, 0x1ce8, 0x43d3, 0x82, 0x36, 0x98, 0x55, 0xc5, 0xce, 0xec, 0xff} +RIDL!{#[uuid(0x54133220, 0x1ce8, 0x43d3, 0x82, 0x36, 0x98, 0x55, 0xc5, 0xce, 0xec, 0xff)] +interface ID3D11FunctionLinkingGraph(ID3D11FunctionLinkingGraphVtbl): IUnknown(IUnknownVtbl) { + fn CreateModuleInstance( + ppModuleInstance: *mut *mut ID3D11ModuleInstance, + ppErrorBuffer: *mut *mut ID3DBlob, + ) -> HRESULT, + fn SetInputSignature( + pInputParameters: *const D3D11_PARAMETER_DESC, + cInputParameters: UINT, + ppInputNode: *mut *mut ID3D11LinkingNode, + ) -> HRESULT, + fn SetOutputSignature( + pOutputParameters: *const D3D11_PARAMETER_DESC, + cOutputParameters: UINT, + ppOutputNode: *mut *mut ID3D11LinkingNode, + ) -> HRESULT, + fn CallFunction( + pModuleInstanceNamespace: LPCSTR, + pModuleWithFunctionPrototype: *mut ID3D11Module, + pFunctionName: LPCSTR, + ppCallNode: *mut *mut ID3D11LinkingNode, + ) -> HRESULT, + fn PassValue( + pSrcNode: *mut ID3D11LinkingNode, + SrcParameterIndex: INT, + pDstNode: *mut ID3D11LinkingNode, + DstParameterIndex: INT, + ) -> HRESULT, + fn PassValueWithSwizzle( + pSrcNode: *mut ID3D11LinkingNode, + SrcParameterIndex: INT, + pSrcSwizzle: LPCSTR, + pDstNode: *mut ID3D11LinkingNode, + DstParameterIndex: INT, + pDstSwizzle: LPCSTR, + ) -> HRESULT, + fn GetLastError( + ppErrorBuffer: *mut *mut ID3DBlob, + ) -> HRESULT, + fn GenerateHlsl( + uFlags: UINT, + ppBuffer: *mut *mut ID3DBlob, + ) -> HRESULT, +}} diff --git a/winapi/src/um/d3d11tokenizedprogramformat.rs b/winapi/src/um/d3d11tokenizedprogramformat.rs new file mode 100644 index 000000000..e81926214 --- /dev/null +++ b/winapi/src/um/d3d11tokenizedprogramformat.rs @@ -0,0 +1,1335 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, UINT}; +ENUM!{enum D3D10_SB_TOKENIZED_PROGRAM_TYPE { + D3D10_SB_PIXEL_SHADER = 0, + D3D10_SB_VERTEX_SHADER = 1, + D3D10_SB_GEOMETRY_SHADER = 2, + D3D11_SB_HULL_SHADER = 3, + D3D11_SB_DOMAIN_SHADER = 4, + D3D11_SB_COMPUTE_SHADER = 5, + D3D11_SB_RESERVED0 = 0xFFF0, +}} +pub const D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK: DWORD = 0xffff0000; +pub const D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT: DWORD = 16; +#[inline] +pub fn DECODE_D3D10_SB_TOKENIZED_PROGRAM_TYPE(VerTok: DWORD) -> DWORD { + (((VerTok & D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK) >> D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT) + as D3D10_SB_TOKENIZED_PROGRAM_TYPE) +} +pub const D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK: DWORD = 0x000000f0; +pub const D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT: DWORD = 4; +pub const D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK: DWORD = 0x0000000f; +#[inline] +pub fn DECODE_D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION(VerTok: DWORD) -> DWORD { + ((VerTok & D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK) + >> D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT) +} +#[inline] +pub fn DECODE_D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION(VerTok: DWORD) -> DWORD { + (VerTok & D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK) +} +#[inline] +pub fn ENCODE_D3D10_SB_TOKENIZED_PROGRAM_VERSION_TOKEN( + ProgType: DWORD, + MajorVer: DWORD, + MinorVer: DWORD, +) -> DWORD { + ((ProgType << D3D10_SB_TOKENIZED_PROGRAM_TYPE_SHIFT) & D3D10_SB_TOKENIZED_PROGRAM_TYPE_MASK) + | ((MajorVer << D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_SHIFT) + & D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION_MASK) + | (MinorVer & D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION_MASK) +} +#[inline] +pub fn DECODE_D3D10_SB_TOKENIZED_PROGRAM_LENGTH(LenTok: DWORD) -> DWORD { + LenTok +} +#[inline] +pub fn ENCODE_D3D10_SB_TOKENIZED_PROGRAM_LENGTH(Length: DWORD) -> DWORD { + Length +} +pub const MAX_D3D10_SB_TOKENIZED_PROGRAM_LENGTH: DWORD = 0xffffffff; +ENUM!{enum D3D10_SB_OPCODE_TYPE { + D3D10_SB_OPCODE_ADD = 0, + D3D10_SB_OPCODE_AND = 1, + D3D10_SB_OPCODE_BREAK = 2, + D3D10_SB_OPCODE_BREAKC = 3, + D3D10_SB_OPCODE_CALL = 4, + D3D10_SB_OPCODE_CALLC = 5, + D3D10_SB_OPCODE_CASE = 6, + D3D10_SB_OPCODE_CONTINUE = 7, + D3D10_SB_OPCODE_CONTINUEC = 8, + D3D10_SB_OPCODE_CUT = 9, + D3D10_SB_OPCODE_DEFAULT = 10, + D3D10_SB_OPCODE_DERIV_RTX = 11, + D3D10_SB_OPCODE_DERIV_RTY = 12, + D3D10_SB_OPCODE_DISCARD = 13, + D3D10_SB_OPCODE_DIV = 14, + D3D10_SB_OPCODE_DP2 = 15, + D3D10_SB_OPCODE_DP3 = 16, + D3D10_SB_OPCODE_DP4 = 17, + D3D10_SB_OPCODE_ELSE = 18, + D3D10_SB_OPCODE_EMIT = 19, + D3D10_SB_OPCODE_EMITTHENCUT = 20, + D3D10_SB_OPCODE_ENDIF = 21, + D3D10_SB_OPCODE_ENDLOOP = 22, + D3D10_SB_OPCODE_ENDSWITCH = 23, + D3D10_SB_OPCODE_EQ = 24, + D3D10_SB_OPCODE_EXP = 25, + D3D10_SB_OPCODE_FRC = 26, + D3D10_SB_OPCODE_FTOI = 27, + D3D10_SB_OPCODE_FTOU = 28, + D3D10_SB_OPCODE_GE = 29, + D3D10_SB_OPCODE_IADD = 30, + D3D10_SB_OPCODE_IF = 31, + D3D10_SB_OPCODE_IEQ = 32, + D3D10_SB_OPCODE_IGE = 33, + D3D10_SB_OPCODE_ILT = 34, + D3D10_SB_OPCODE_IMAD = 35, + D3D10_SB_OPCODE_IMAX = 36, + D3D10_SB_OPCODE_IMIN = 37, + D3D10_SB_OPCODE_IMUL = 38, + D3D10_SB_OPCODE_INE = 39, + D3D10_SB_OPCODE_INEG = 40, + D3D10_SB_OPCODE_ISHL = 41, + D3D10_SB_OPCODE_ISHR = 42, + D3D10_SB_OPCODE_ITOF = 43, + D3D10_SB_OPCODE_LABEL = 44, + D3D10_SB_OPCODE_LD = 45, + D3D10_SB_OPCODE_LD_MS = 46, + D3D10_SB_OPCODE_LOG = 47, + D3D10_SB_OPCODE_LOOP = 48, + D3D10_SB_OPCODE_LT = 49, + D3D10_SB_OPCODE_MAD = 50, + D3D10_SB_OPCODE_MIN = 51, + D3D10_SB_OPCODE_MAX = 52, + D3D10_SB_OPCODE_CUSTOMDATA = 53, + D3D10_SB_OPCODE_MOV = 54, + D3D10_SB_OPCODE_MOVC = 55, + D3D10_SB_OPCODE_MUL = 56, + D3D10_SB_OPCODE_NE = 57, + D3D10_SB_OPCODE_NOP = 58, + D3D10_SB_OPCODE_NOT = 59, + D3D10_SB_OPCODE_OR = 60, + D3D10_SB_OPCODE_RESINFO = 61, + D3D10_SB_OPCODE_RET = 62, + D3D10_SB_OPCODE_RETC = 63, + D3D10_SB_OPCODE_ROUND_NE = 64, + D3D10_SB_OPCODE_ROUND_NI = 65, + D3D10_SB_OPCODE_ROUND_PI = 66, + D3D10_SB_OPCODE_ROUND_Z = 67, + D3D10_SB_OPCODE_RSQ = 68, + D3D10_SB_OPCODE_SAMPLE = 69, + D3D10_SB_OPCODE_SAMPLE_C = 70, + D3D10_SB_OPCODE_SAMPLE_C_LZ = 71, + D3D10_SB_OPCODE_SAMPLE_L = 72, + D3D10_SB_OPCODE_SAMPLE_D = 73, + D3D10_SB_OPCODE_SAMPLE_B = 74, + D3D10_SB_OPCODE_SQRT = 75, + D3D10_SB_OPCODE_SWITCH = 76, + D3D10_SB_OPCODE_SINCOS = 77, + D3D10_SB_OPCODE_UDIV = 78, + D3D10_SB_OPCODE_ULT = 79, + D3D10_SB_OPCODE_UGE = 80, + D3D10_SB_OPCODE_UMUL = 81, + D3D10_SB_OPCODE_UMAD = 82, + D3D10_SB_OPCODE_UMAX = 83, + D3D10_SB_OPCODE_UMIN = 84, + D3D10_SB_OPCODE_USHR = 85, + D3D10_SB_OPCODE_UTOF = 86, + D3D10_SB_OPCODE_XOR = 87, + D3D10_SB_OPCODE_DCL_RESOURCE = 88, + D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER = 89, + D3D10_SB_OPCODE_DCL_SAMPLER = 90, + D3D10_SB_OPCODE_DCL_INDEX_RANGE = 91, + D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY = 92, + D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE = 93, + D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT = 94, + D3D10_SB_OPCODE_DCL_INPUT = 95, + D3D10_SB_OPCODE_DCL_INPUT_SGV = 96, + D3D10_SB_OPCODE_DCL_INPUT_SIV = 97, + D3D10_SB_OPCODE_DCL_INPUT_PS = 98, + D3D10_SB_OPCODE_DCL_INPUT_PS_SGV = 99, + D3D10_SB_OPCODE_DCL_INPUT_PS_SIV = 100, + D3D10_SB_OPCODE_DCL_OUTPUT = 101, + D3D10_SB_OPCODE_DCL_OUTPUT_SGV = 102, + D3D10_SB_OPCODE_DCL_OUTPUT_SIV = 103, + D3D10_SB_OPCODE_DCL_TEMPS = 104, + D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP = 105, + D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS = 106, + D3D10_SB_OPCODE_RESERVED0 = 107, + D3D10_1_SB_OPCODE_LOD = 108, + D3D10_1_SB_OPCODE_GATHER4 = 109, + D3D10_1_SB_OPCODE_SAMPLE_POS = 110, + D3D10_1_SB_OPCODE_SAMPLE_INFO = 111, + D3D10_1_SB_OPCODE_RESERVED1 = 112, + D3D11_SB_OPCODE_HS_DECLS = 113, + D3D11_SB_OPCODE_HS_CONTROL_POINT_PHASE = 114, + D3D11_SB_OPCODE_HS_FORK_PHASE = 115, + D3D11_SB_OPCODE_HS_JOIN_PHASE = 116, + D3D11_SB_OPCODE_EMIT_STREAM = 117, + D3D11_SB_OPCODE_CUT_STREAM = 118, + D3D11_SB_OPCODE_EMITTHENCUT_STREAM = 119, + D3D11_SB_OPCODE_INTERFACE_CALL = 120, + D3D11_SB_OPCODE_BUFINFO = 121, + D3D11_SB_OPCODE_DERIV_RTX_COARSE = 122, + D3D11_SB_OPCODE_DERIV_RTX_FINE = 123, + D3D11_SB_OPCODE_DERIV_RTY_COARSE = 124, + D3D11_SB_OPCODE_DERIV_RTY_FINE = 125, + D3D11_SB_OPCODE_GATHER4_C = 126, + D3D11_SB_OPCODE_GATHER4_PO = 127, + D3D11_SB_OPCODE_GATHER4_PO_C = 128, + D3D11_SB_OPCODE_RCP = 129, + D3D11_SB_OPCODE_F32TOF16 = 130, + D3D11_SB_OPCODE_F16TOF32 = 131, + D3D11_SB_OPCODE_UADDC = 132, + D3D11_SB_OPCODE_USUBB = 133, + D3D11_SB_OPCODE_COUNTBITS = 134, + D3D11_SB_OPCODE_FIRSTBIT_HI = 135, + D3D11_SB_OPCODE_FIRSTBIT_LO = 136, + D3D11_SB_OPCODE_FIRSTBIT_SHI = 137, + D3D11_SB_OPCODE_UBFE = 138, + D3D11_SB_OPCODE_IBFE = 139, + D3D11_SB_OPCODE_BFI = 140, + D3D11_SB_OPCODE_BFREV = 141, + D3D11_SB_OPCODE_SWAPC = 142, + D3D11_SB_OPCODE_DCL_STREAM = 143, + D3D11_SB_OPCODE_DCL_FUNCTION_BODY = 144, + D3D11_SB_OPCODE_DCL_FUNCTION_TABLE = 145, + D3D11_SB_OPCODE_DCL_INTERFACE = 146, + D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT = 147, + D3D11_SB_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT = 148, + D3D11_SB_OPCODE_DCL_TESS_DOMAIN = 149, + D3D11_SB_OPCODE_DCL_TESS_PARTITIONING = 150, + D3D11_SB_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE = 151, + D3D11_SB_OPCODE_DCL_HS_MAX_TESSFACTOR = 152, + D3D11_SB_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT = 153, + D3D11_SB_OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT = 154, + D3D11_SB_OPCODE_DCL_THREAD_GROUP = 155, + D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED = 156, + D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW = 157, + D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED = 158, + D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW = 159, + D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED = 160, + D3D11_SB_OPCODE_DCL_RESOURCE_RAW = 161, + D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED = 162, + D3D11_SB_OPCODE_LD_UAV_TYPED = 163, + D3D11_SB_OPCODE_STORE_UAV_TYPED = 164, + D3D11_SB_OPCODE_LD_RAW = 165, + D3D11_SB_OPCODE_STORE_RAW = 166, + D3D11_SB_OPCODE_LD_STRUCTURED = 167, + D3D11_SB_OPCODE_STORE_STRUCTURED = 168, + D3D11_SB_OPCODE_ATOMIC_AND = 169, + D3D11_SB_OPCODE_ATOMIC_OR = 170, + D3D11_SB_OPCODE_ATOMIC_XOR = 171, + D3D11_SB_OPCODE_ATOMIC_CMP_STORE = 172, + D3D11_SB_OPCODE_ATOMIC_IADD = 173, + D3D11_SB_OPCODE_ATOMIC_IMAX = 174, + D3D11_SB_OPCODE_ATOMIC_IMIN = 175, + D3D11_SB_OPCODE_ATOMIC_UMAX = 176, + D3D11_SB_OPCODE_ATOMIC_UMIN = 177, + D3D11_SB_OPCODE_IMM_ATOMIC_ALLOC = 178, + D3D11_SB_OPCODE_IMM_ATOMIC_CONSUME = 179, + D3D11_SB_OPCODE_IMM_ATOMIC_IADD = 180, + D3D11_SB_OPCODE_IMM_ATOMIC_AND = 181, + D3D11_SB_OPCODE_IMM_ATOMIC_OR = 182, + D3D11_SB_OPCODE_IMM_ATOMIC_XOR = 183, + D3D11_SB_OPCODE_IMM_ATOMIC_EXCH = 184, + D3D11_SB_OPCODE_IMM_ATOMIC_CMP_EXCH = 185, + D3D11_SB_OPCODE_IMM_ATOMIC_IMAX = 186, + D3D11_SB_OPCODE_IMM_ATOMIC_IMIN = 187, + D3D11_SB_OPCODE_IMM_ATOMIC_UMAX = 188, + D3D11_SB_OPCODE_IMM_ATOMIC_UMIN = 189, + D3D11_SB_OPCODE_SYNC = 190, + D3D11_SB_OPCODE_DADD = 191, + D3D11_SB_OPCODE_DMAX = 192, + D3D11_SB_OPCODE_DMIN = 193, + D3D11_SB_OPCODE_DMUL = 194, + D3D11_SB_OPCODE_DEQ = 195, + D3D11_SB_OPCODE_DGE = 196, + D3D11_SB_OPCODE_DLT = 197, + D3D11_SB_OPCODE_DNE = 198, + D3D11_SB_OPCODE_DMOV = 199, + D3D11_SB_OPCODE_DMOVC = 200, + D3D11_SB_OPCODE_DTOF = 201, + D3D11_SB_OPCODE_FTOD = 202, + D3D11_SB_OPCODE_EVAL_SNAPPED = 203, + D3D11_SB_OPCODE_EVAL_SAMPLE_INDEX = 204, + D3D11_SB_OPCODE_EVAL_CENTROID = 205, + D3D11_SB_OPCODE_DCL_GS_INSTANCE_COUNT = 206, + D3D11_SB_OPCODE_ABORT = 207, + D3D11_SB_OPCODE_DEBUG_BREAK = 208, + D3D11_SB_OPCODE_RESERVED0 = 209, + D3D11_1_SB_OPCODE_DDIV = 210, + D3D11_1_SB_OPCODE_DFMA = 211, + D3D11_1_SB_OPCODE_DRCP = 212, + D3D11_1_SB_OPCODE_MSAD = 213, + D3D11_1_SB_OPCODE_DTOI = 214, + D3D11_1_SB_OPCODE_DTOU = 215, + D3D11_1_SB_OPCODE_ITOD = 216, + D3D11_1_SB_OPCODE_UTOD = 217, + D3D11_1_SB_OPCODE_RESERVED0 = 218, + D3DWDDM1_3_SB_OPCODE_GATHER4_FEEDBACK = 219, + D3DWDDM1_3_SB_OPCODE_GATHER4_C_FEEDBACK = 220, + D3DWDDM1_3_SB_OPCODE_GATHER4_PO_FEEDBACK = 221, + D3DWDDM1_3_SB_OPCODE_GATHER4_PO_C_FEEDBACK = 222, + D3DWDDM1_3_SB_OPCODE_LD_FEEDBACK = 223, + D3DWDDM1_3_SB_OPCODE_LD_MS_FEEDBACK = 224, + D3DWDDM1_3_SB_OPCODE_LD_UAV_TYPED_FEEDBACK = 225, + D3DWDDM1_3_SB_OPCODE_LD_RAW_FEEDBACK = 226, + D3DWDDM1_3_SB_OPCODE_LD_STRUCTURED_FEEDBACK = 227, + D3DWDDM1_3_SB_OPCODE_SAMPLE_L_FEEDBACK = 228, + D3DWDDM1_3_SB_OPCODE_SAMPLE_C_LZ_FEEDBACK = 229, + D3DWDDM1_3_SB_OPCODE_SAMPLE_CLAMP_FEEDBACK = 230, + D3DWDDM1_3_SB_OPCODE_SAMPLE_B_CLAMP_FEEDBACK = 231, + D3DWDDM1_3_SB_OPCODE_SAMPLE_D_CLAMP_FEEDBACK = 232, + D3DWDDM1_3_SB_OPCODE_SAMPLE_C_CLAMP_FEEDBACK = 233, + D3DWDDM1_3_SB_OPCODE_CHECK_ACCESS_FULLY_MAPPED = 234, + D3DWDDM1_3_SB_OPCODE_RESERVED0 = 235, + D3D10_SB_NUM_OPCODES = 236, +}} +pub const D3D10_SB_OPCODE_TYPE_MASK: DWORD = 0x00007ff; +#[inline] +pub fn DECODE_D3D10_SB_OPCODE_TYPE(OpcodeToken0: DWORD) -> D3D10_SB_OPCODE_TYPE { + (OpcodeToken0 & D3D10_SB_OPCODE_TYPE_MASK) as D3D10_SB_OPCODE_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_OPCODE_TYPE(OpcodeName: D3D10_SB_OPCODE_TYPE) -> DWORD { + OpcodeName & D3D10_SB_OPCODE_TYPE_MASK +} +pub const D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK: DWORD = 0x7f000000; +pub const D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT: DWORD = 24; +#[inline] +pub fn DECODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(OpcodeToken0: DWORD) -> DWORD { + (OpcodeToken0 & D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK) + >> D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT +} +#[inline] +pub fn ENCODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(Length: DWORD) -> DWORD { + (Length << D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_SHIFT) + & D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH_MASK +} +pub const MAX_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH: DWORD = 127; +pub const D3D10_SB_INSTRUCTION_SATURATE_MASK: DWORD = 0x00002000; +#[inline] +pub fn DECODE_IS_D3D10_SB_INSTRUCTION_SATURATE_ENABLED(OpcodeToken0: DWORD) -> DWORD { + OpcodeToken0 & D3D10_SB_INSTRUCTION_SATURATE_MASK +} +#[inline] +pub fn ENCODE_D3D10_SB_INSTRUCTION_SATURATE(bSat: DWORD) -> DWORD { + if bSat != 0 { + D3D10_SB_INSTRUCTION_SATURATE_MASK + } else { + 0 + } +} +ENUM!{enum D3D10_SB_INSTRUCTION_TEST_BOOLEAN { + D3D10_SB_INSTRUCTION_TEST_ZERO = 0, + D3D10_SB_INSTRUCTION_TEST_NONZERO = 1, +}} +pub const D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK: DWORD = 0x00040000; +pub const D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT: DWORD = 18; +#[inline] +pub fn DECODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN( + OpcodeToken0: DWORD, +) -> D3D10_SB_INSTRUCTION_TEST_BOOLEAN { + ((OpcodeToken0 & D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK) + >> D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT) as D3D10_SB_INSTRUCTION_TEST_BOOLEAN +} +#[inline] +pub fn ENCODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN( + Boolean: D3D10_SB_INSTRUCTION_TEST_BOOLEAN, +) -> DWORD { + (Boolean << D3D10_SB_INSTRUCTION_TEST_BOOLEAN_SHIFT) & D3D10_SB_INSTRUCTION_TEST_BOOLEAN_MASK +} +pub const D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK: DWORD = 0x00780000; +pub const D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT: DWORD = 19; +#[inline] +pub fn DECODE_D3D11_SB_INSTRUCTION_PRECISE_VALUES(OpcodeToken0: DWORD) -> DWORD { + (OpcodeToken0 & D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK) + >> D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT +} +#[inline] +pub fn ENCODE_D3D11_SB_INSTRUCTION_PRECISE_VALUES(ComponentMask: DWORD) -> DWORD { + (ComponentMask << D3D11_SB_INSTRUCTION_PRECISE_VALUES_SHIFT) + & D3D11_SB_INSTRUCTION_PRECISE_VALUES_MASK +} +ENUM!{enum D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE { + D3D10_SB_RESINFO_INSTRUCTION_RETURN_FLOAT = 0, + D3D10_SB_RESINFO_INSTRUCTION_RETURN_RCPFLOAT = 1, + D3D10_SB_RESINFO_INSTRUCTION_RETURN_UINT = 2, +}} +pub const D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK: DWORD = 0x00001800; +pub const D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE( + OpcodeToken0: DWORD, +) -> D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE { + ((OpcodeToken0 & D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK) + >> D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT) + as D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE( + ReturnType: D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE, +) -> DWORD { + (ReturnType << D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_SHIFT) + & D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE_MASK +} +pub const D3D11_SB_SYNC_THREADS_IN_GROUP: DWORD = 0x00000800; +pub const D3D11_SB_SYNC_THREAD_GROUP_SHARED_MEMORY: DWORD = 0x00001000; +pub const D3D11_SB_SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GROUP: DWORD = 0x00002000; +pub const D3D11_SB_SYNC_UNORDERED_ACCESS_VIEW_MEMORY_GLOBAL: DWORD = 0x00004000; +pub const D3D11_SB_SYNC_FLAGS_MASK: DWORD = 0x00007800; +#[inline] +pub fn DECODE_D3D11_SB_SYNC_FLAGS(OperandToken0: DWORD) -> DWORD { + OperandToken0 & D3D11_SB_SYNC_FLAGS_MASK +} +#[inline] +pub fn ENCODE_D3D11_SB_SYNC_FLAGS(Flags: DWORD) -> DWORD { + Flags & D3D11_SB_SYNC_FLAGS_MASK +} +pub const D3D10_SB_OPCODE_EXTENDED_MASK: DWORD = 0x80000000; +pub const D3D10_SB_OPCODE_EXTENDED_SHIFT: DWORD = 31; +#[inline] +pub fn DECODE_IS_D3D10_SB_OPCODE_EXTENDED(OpcodeToken0: DWORD) -> DWORD { + (OpcodeToken0 & D3D10_SB_OPCODE_EXTENDED_MASK) >> D3D10_SB_OPCODE_EXTENDED_SHIFT +} +#[inline] +pub fn ENCODE_D3D10_SB_OPCODE_EXTENDED(bExtended: DWORD) -> DWORD { + if bExtended != 0 { + D3D10_SB_OPCODE_EXTENDED_MASK + } else { + 0 + } +} +ENUM!{enum D3D10_SB_EXTENDED_OPCODE_TYPE { + D3D10_SB_EXTENDED_OPCODE_EMPTY = 0, + D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS = 1, + D3D11_SB_EXTENDED_OPCODE_RESOURCE_DIM = 2, + D3D11_SB_EXTENDED_OPCODE_RESOURCE_RETURN_TYPE = 3, +}} +pub const D3D11_SB_MAX_SIMULTANEOUS_EXTENDED_OPCODES: DWORD = 3; +pub const D3D10_SB_EXTENDED_OPCODE_TYPE_MASK: DWORD = 0x0000003f; +#[inline] +pub fn DECODE_D3D10_SB_EXTENDED_OPCODE_TYPE(OpcodeToken1: DWORD) -> D3D10_SB_EXTENDED_OPCODE_TYPE { + (OpcodeToken1 & D3D10_SB_EXTENDED_OPCODE_TYPE_MASK) as D3D10_SB_EXTENDED_OPCODE_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_EXTENDED_OPCODE_TYPE( + ExtOpcodeType: D3D10_SB_EXTENDED_OPCODE_TYPE, +) -> DWORD { + ExtOpcodeType & D3D10_SB_EXTENDED_OPCODE_TYPE_MASK +} +ENUM!{enum D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD { + D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_U = 0, + D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_V = 1, + D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_W = 2, +}} +pub const D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD_MASK: DWORD = 3; +#[inline] +pub fn D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord: DWORD) -> DWORD { + 9 + 4 * (Coord & D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_COORD_MASK) +} +#[inline] +pub fn D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord: DWORD) -> DWORD { + 0x0000000f << D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord) +} +#[inline] +pub fn DECODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET( + Coord: DWORD, + OpcodeToken1: DWORD, +) -> DWORD { + (OpcodeToken1 & D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord)) + >> D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord) +} +#[inline] +pub fn ENCODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET( + Coord: DWORD, + ImmediateOffset: DWORD, +) -> DWORD { + (ImmediateOffset << D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_SHIFT(Coord)) + & D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_MASK(Coord) +} +pub const D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK: DWORD = 0x000007C0; +pub const D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT: DWORD = 6; +#[inline] +pub fn DECODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION( + OpcodeTokenN: DWORD, +) -> D3D10_SB_RESOURCE_DIMENSION { + ((OpcodeTokenN & D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK) + >> D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT) as D3D10_SB_RESOURCE_DIMENSION +} +#[inline] +pub fn ENCODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION( + ResourceDim: D3D10_SB_RESOURCE_DIMENSION, +) -> DWORD { + (ResourceDim << D3D11_SB_EXTENDED_RESOURCE_DIMENSION_SHIFT) + & D3D11_SB_EXTENDED_RESOURCE_DIMENSION_MASK +} +pub const D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK: DWORD = 0x007FF800; +pub const D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE(OpcodeTokenN: DWORD) -> DWORD { + (OpcodeTokenN & D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK) + >> D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT +} +#[inline] +pub fn ENCODE_D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE(Stride: DWORD) -> DWORD { + (Stride << D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_SHIFT) + & D3D11_SB_EXTENDED_RESOURCE_DIMENSION_STRUCTURE_STRIDE_MASK +} +pub const D3D10_SB_RESOURCE_RETURN_TYPE_MASK: DWORD = 0x0000000f; +pub const D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS: DWORD = 0x00000004; +pub const D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT: DWORD = 6; +#[inline] +pub fn DECODE_D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE( + OpcodeTokenN: DWORD, + Component: DWORD, +) -> DWORD { + ((OpcodeTokenN >> (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS + + D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT)) + & D3D10_SB_RESOURCE_RETURN_TYPE_MASK) as D3D10_SB_RESOURCE_RETURN_TYPE +} +#[inline] +pub fn ENCODE_D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE( + ReturnType: DWORD, + Component: DWORD, +) -> DWORD { + (ReturnType & D3D10_SB_RESOURCE_RETURN_TYPE_MASK) + << (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS + + D3D11_SB_EXTENDED_RESOURCE_RETURN_TYPE_SHIFT) +} +ENUM!{enum D3D10_SB_CUSTOMDATA_CLASS { + D3D10_SB_CUSTOMDATA_COMMENT = 0, + D3D10_SB_CUSTOMDATA_DEBUGINFO = 1, + D3D10_SB_CUSTOMDATA_OPAQUE = 2, + D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER = 3, + D3D11_SB_CUSTOMDATA_SHADER_MESSAGE = 4, + D3D11_SB_CUSTOMDATA_SHADER_CLIP_PLANE_CONSTANT_MAPPINGS_FOR_DX9 = 5, +}} +pub const D3D10_SB_CUSTOMDATA_CLASS_MASK: DWORD = 0xfffff800; +pub const D3D10_SB_CUSTOMDATA_CLASS_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_CUSTOMDATA_CLASS(CustomDataDescTok: DWORD) -> D3D10_SB_CUSTOMDATA_CLASS { + ((CustomDataDescTok & D3D10_SB_CUSTOMDATA_CLASS_MASK) >> D3D10_SB_CUSTOMDATA_CLASS_SHIFT) + as D3D10_SB_CUSTOMDATA_CLASS +} +#[inline] +pub fn ENCODE_D3D10_SB_CUSTOMDATA_CLASS(CustomDataClass: D3D10_SB_CUSTOMDATA_CLASS) -> DWORD { + ENCODE_D3D10_SB_OPCODE_TYPE(D3D10_SB_OPCODE_CUSTOMDATA) + | ((CustomDataClass << D3D10_SB_CUSTOMDATA_CLASS_SHIFT) & D3D10_SB_CUSTOMDATA_CLASS_MASK) +} +ENUM!{enum D3D10_SB_OPERAND_NUM_COMPONENTS { + D3D10_SB_OPERAND_0_COMPONENT = 0, + D3D10_SB_OPERAND_1_COMPONENT = 1, + D3D10_SB_OPERAND_4_COMPONENT = 2, + D3D10_SB_OPERAND_N_COMPONENT = 3, +}} +pub const D3D10_SB_OPERAND_NUM_COMPONENTS_MASK: DWORD = 0x00000003; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_NUM_COMPONENTS(OperandToken0: DWORD) -> DWORD { + (OperandToken0 & D3D10_SB_OPERAND_NUM_COMPONENTS_MASK) as D3D10_SB_OPERAND_NUM_COMPONENTS +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_NUM_COMPONENTS(NumComp: DWORD) -> DWORD { + NumComp & D3D10_SB_OPERAND_NUM_COMPONENTS_MASK +} +ENUM!{enum D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE { + D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE = 0, + D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE = 1, + D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE = 2, +}} +pub const D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK: DWORD = 0x0000000c; +pub const D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT: DWORD = 2; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE( + OperandToken0: DWORD, +) -> D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE { + ((OperandToken0 & D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK) + >> D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT) + as D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE( + SelectionMode: D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE, +) -> DWORD { + (SelectionMode << D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_SHIFT) + & D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE_MASK +} +ENUM!{enum D3D10_SB_4_COMPONENT_NAME { + D3D10_SB_4_COMPONENT_X = 0, + D3D10_SB_4_COMPONENT_Y = 1, + D3D10_SB_4_COMPONENT_Z = 2, + D3D10_SB_4_COMPONENT_W = 3, + D3D10_SB_4_COMPONENT_R = 0, + D3D10_SB_4_COMPONENT_G = 1, + D3D10_SB_4_COMPONENT_B = 2, + D3D10_SB_4_COMPONENT_A = 3, +}} +pub const D3D10_SB_4_COMPONENT_NAME_MASK: DWORD = 3; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK: DWORD = 0x000000f0; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_SHIFT: DWORD = 4; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_X: DWORD = 0x00000010; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_Y: DWORD = 0x00000020; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_Z: DWORD = 0x00000040; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_W: DWORD = 0x00000080; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_R: DWORD = D3D10_SB_OPERAND_4_COMPONENT_MASK_X; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_G: DWORD = D3D10_SB_OPERAND_4_COMPONENT_MASK_Y; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_B: DWORD = D3D10_SB_OPERAND_4_COMPONENT_MASK_Z; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_A: DWORD = D3D10_SB_OPERAND_4_COMPONENT_MASK_W; +pub const D3D10_SB_OPERAND_4_COMPONENT_MASK_ALL: DWORD = D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(OperandToken0: DWORD) -> DWORD { + OperandToken0 & D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(ComponentMask: DWORD) -> DWORD { + ComponentMask & D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_MASK(ComponentName: DWORD) -> DWORD { + (1 << (D3D10_SB_OPERAND_4_COMPONENT_MASK_SHIFT + ComponentName)) + & D3D10_SB_OPERAND_4_COMPONENT_MASK_MASK +} +pub const D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MASK: DWORD = 0x00000ff0; +pub const D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT: DWORD = 4; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE(OperandToken0: DWORD) -> DWORD { + OperandToken0 & D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MASK +} +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE( + OperandToken0: DWORD, + DestComp: DWORD, +) -> D3D10_SB_4_COMPONENT_NAME { + ((OperandToken0 >> (D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT + 2 + * (DestComp & D3D10_SB_4_COMPONENT_NAME_MASK))) + & D3D10_SB_4_COMPONENT_NAME_MASK) as D3D10_SB_4_COMPONENT_NAME +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + XSrc: DWORD, + YSrc: DWORD, + ZSrc: DWORD, + WSrc: DWORD, +) -> DWORD { + ((XSrc & D3D10_SB_4_COMPONENT_NAME_MASK) + | ((YSrc & D3D10_SB_4_COMPONENT_NAME_MASK) << 2) + | ((ZSrc & D3D10_SB_4_COMPONENT_NAME_MASK) << 4) + | ((WSrc & D3D10_SB_4_COMPONENT_NAME_MASK) << 6)) + << D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SHIFT +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_NOSWIZZLE() -> DWORD { + ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + D3D10_SB_4_COMPONENT_X, + D3D10_SB_4_COMPONENT_Y, + D3D10_SB_4_COMPONENT_Z, + D3D10_SB_4_COMPONENT_W, + ) +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEX() -> DWORD { + ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + D3D10_SB_4_COMPONENT_X, + D3D10_SB_4_COMPONENT_X, + D3D10_SB_4_COMPONENT_X, + D3D10_SB_4_COMPONENT_X, + ) +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEY() -> DWORD { + ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + D3D10_SB_4_COMPONENT_Y, + D3D10_SB_4_COMPONENT_Y, + D3D10_SB_4_COMPONENT_Y, + D3D10_SB_4_COMPONENT_Y, + ) +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEZ() -> DWORD { + ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + D3D10_SB_4_COMPONENT_Z, + D3D10_SB_4_COMPONENT_Z, + D3D10_SB_4_COMPONENT_Z, + D3D10_SB_4_COMPONENT_Z, + ) +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEW() -> DWORD { + ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE( + D3D10_SB_4_COMPONENT_W, + D3D10_SB_4_COMPONENT_W, + D3D10_SB_4_COMPONENT_W, + D3D10_SB_4_COMPONENT_W, + ) +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATERED() -> DWORD { + D3D10_SB_OPERAND_4_COMPONENT_REPLICATEX() +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEGREEN() -> DWORD { + D3D10_SB_OPERAND_4_COMPONENT_REPLICATEY() +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEBLUE() -> DWORD { + D3D10_SB_OPERAND_4_COMPONENT_REPLICATEZ() +} +#[inline] +pub fn D3D10_SB_OPERAND_4_COMPONENT_REPLICATEALPHA() -> DWORD { + D3D10_SB_OPERAND_4_COMPONENT_REPLICATEW() +} +pub const D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK: DWORD = 0x00000030; +pub const D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT: DWORD = 4; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1( + OperandToken0: DWORD, +) -> D3D10_SB_4_COMPONENT_NAME { + ((OperandToken0 & D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK) + >> D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT) as D3D10_SB_4_COMPONENT_NAME +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1( + SelectedComp: D3D10_SB_4_COMPONENT_NAME, +) -> DWORD { + (SelectedComp << D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_SHIFT) + & D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MASK +} +ENUM!{enum D3D10_SB_OPERAND_TYPE { + D3D10_SB_OPERAND_TYPE_TEMP = 0, + D3D10_SB_OPERAND_TYPE_INPUT = 1, + D3D10_SB_OPERAND_TYPE_OUTPUT = 2, + D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP = 3, + D3D10_SB_OPERAND_TYPE_IMMEDIATE32 = 4, + D3D10_SB_OPERAND_TYPE_IMMEDIATE64 = 5, + D3D10_SB_OPERAND_TYPE_SAMPLER = 6, + D3D10_SB_OPERAND_TYPE_RESOURCE = 7, + D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER= 8, + D3D10_SB_OPERAND_TYPE_IMMEDIATE_CONSTANT_BUFFER= 9, + D3D10_SB_OPERAND_TYPE_LABEL = 10, + D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID = 11, + D3D10_SB_OPERAND_TYPE_OUTPUT_DEPTH = 12, + D3D10_SB_OPERAND_TYPE_NULL = 13, + D3D10_SB_OPERAND_TYPE_RASTERIZER = 14, + D3D10_SB_OPERAND_TYPE_OUTPUT_COVERAGE_MASK = 15, + D3D11_SB_OPERAND_TYPE_STREAM = 16, + D3D11_SB_OPERAND_TYPE_FUNCTION_BODY = 17, + D3D11_SB_OPERAND_TYPE_FUNCTION_TABLE = 18, + D3D11_SB_OPERAND_TYPE_INTERFACE = 19, + D3D11_SB_OPERAND_TYPE_FUNCTION_INPUT = 20, + D3D11_SB_OPERAND_TYPE_FUNCTION_OUTPUT = 21, + D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID = 22, + D3D11_SB_OPERAND_TYPE_INPUT_FORK_INSTANCE_ID = 23, + D3D11_SB_OPERAND_TYPE_INPUT_JOIN_INSTANCE_ID = 24, + D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT = 25, + D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT = 26, + D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT = 27, + D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT = 28, + D3D11_SB_OPERAND_TYPE_THIS_POINTER = 29, + D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW = 30, + D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY = 31, + D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID = 32, + D3D11_SB_OPERAND_TYPE_INPUT_THREAD_GROUP_ID = 33, + D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP = 34, + D3D11_SB_OPERAND_TYPE_INPUT_COVERAGE_MASK = 35, + D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED = 36, + D3D11_SB_OPERAND_TYPE_INPUT_GS_INSTANCE_ID = 37, + D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL = 38, + D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL = 39, + D3D11_SB_OPERAND_TYPE_CYCLE_COUNTER = 40, +}} +pub const D3D10_SB_OPERAND_TYPE_MASK: DWORD = 0x000ff000; +pub const D3D10_SB_OPERAND_TYPE_SHIFT: DWORD = 12; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_TYPE(OperandToken0: DWORD) -> D3D10_SB_OPERAND_TYPE { + ((OperandToken0 & D3D10_SB_OPERAND_TYPE_MASK) >> D3D10_SB_OPERAND_TYPE_SHIFT) + as D3D10_SB_OPERAND_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_TYPE(OperandType: D3D10_SB_OPERAND_TYPE) -> DWORD { + (OperandType << D3D10_SB_OPERAND_TYPE_SHIFT) & D3D10_SB_OPERAND_TYPE_MASK +} +ENUM!{enum D3D10_SB_OPERAND_INDEX_DIMENSION { + D3D10_SB_OPERAND_INDEX_0D = 0, + D3D10_SB_OPERAND_INDEX_1D = 1, + D3D10_SB_OPERAND_INDEX_2D = 2, + D3D10_SB_OPERAND_INDEX_3D = 3, +}} +pub const D3D10_SB_OPERAND_INDEX_DIMENSION_MASK: DWORD = 0x00300000; +pub const D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT: DWORD = 20; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_INDEX_DIMENSION( + OperandToken0: DWORD, +) -> D3D10_SB_OPERAND_INDEX_DIMENSION { + ((OperandToken0 & D3D10_SB_OPERAND_INDEX_DIMENSION_MASK) + >> D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT) as D3D10_SB_OPERAND_INDEX_DIMENSION +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_INDEX_DIMENSION( + OperandIndexDim: D3D10_SB_OPERAND_INDEX_DIMENSION, +) -> DWORD { + (OperandIndexDim << D3D10_SB_OPERAND_INDEX_DIMENSION_SHIFT) + & D3D10_SB_OPERAND_INDEX_DIMENSION_MASK +} +ENUM!{enum D3D10_SB_OPERAND_INDEX_REPRESENTATION { + D3D10_SB_OPERAND_INDEX_IMMEDIATE32 = 0, + D3D10_SB_OPERAND_INDEX_IMMEDIATE64 = 1, + D3D10_SB_OPERAND_INDEX_RELATIVE = 2, + D3D10_SB_OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE = 3, + D3D10_SB_OPERAND_INDEX_IMMEDIATE64_PLUS_RELATIVE = 4, +}} +#[inline] +pub fn D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim: DWORD) -> DWORD { + 22 + 3 * (Dim & 3) +} +#[inline] +pub fn D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim: DWORD) -> DWORD { + 0x3 << D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim) +} +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION( + Dim: DWORD, + OperandToken0: DWORD, +) -> D3D10_SB_OPERAND_INDEX_REPRESENTATION { + ((OperandToken0 & D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim)) + >> D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim)) + as D3D10_SB_OPERAND_INDEX_REPRESENTATION +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION( + Dim: DWORD, + IndexRepresentation: D3D10_SB_OPERAND_INDEX_REPRESENTATION, +) -> DWORD { + (IndexRepresentation << D3D10_SB_OPERAND_INDEX_REPRESENTATION_SHIFT(Dim)) + & D3D10_SB_OPERAND_INDEX_REPRESENTATION_MASK(Dim) +} +pub const D3D10_SB_OPERAND_EXTENDED_MASK: DWORD = 0x80000000; +pub const D3D10_SB_OPERAND_EXTENDED_SHIFT: DWORD = 31; +#[inline] +pub fn DECODE_IS_D3D10_SB_OPERAND_EXTENDED(OperandToken0: DWORD) -> DWORD { + (OperandToken0 & D3D10_SB_OPERAND_EXTENDED_MASK) >> D3D10_SB_OPERAND_EXTENDED_SHIFT +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_EXTENDED(bExtended: DWORD) -> DWORD { + if bExtended != 0 { + D3D10_SB_OPERAND_EXTENDED_MASK + } else { + 0 + } +} +ENUM!{enum D3D10_SB_EXTENDED_OPERAND_TYPE { + D3D10_SB_EXTENDED_OPERAND_EMPTY = 0, + D3D10_SB_EXTENDED_OPERAND_MODIFIER = 1, +}} +pub const D3D10_SB_EXTENDED_OPERAND_TYPE_MASK: DWORD = 0x0000003f; +#[inline] +pub fn DECODE_D3D10_SB_EXTENDED_OPERAND_TYPE( + OperandToken1: DWORD, +) -> D3D10_SB_EXTENDED_OPERAND_TYPE { + (OperandToken1 & D3D10_SB_EXTENDED_OPERAND_TYPE_MASK) as D3D10_SB_EXTENDED_OPERAND_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_EXTENDED_OPERAND_TYPE( + ExtOperandType: D3D10_SB_EXTENDED_OPERAND_TYPE, +) -> DWORD { + ExtOperandType & D3D10_SB_EXTENDED_OPERAND_TYPE_MASK +} +ENUM!{enum D3D10_SB_OPERAND_MODIFIER { + D3D10_SB_OPERAND_MODIFIER_NONE = 0, + D3D10_SB_OPERAND_MODIFIER_NEG = 1, + D3D10_SB_OPERAND_MODIFIER_ABS = 2, + D3D10_SB_OPERAND_MODIFIER_ABSNEG = 3, +}} +pub const D3D10_SB_OPERAND_MODIFIER_MASK: DWORD = 0x00003fc0; +pub const D3D10_SB_OPERAND_MODIFIER_SHIFT: DWORD = 6; +#[inline] +pub fn DECODE_D3D10_SB_OPERAND_MODIFIER(OperandToken1: DWORD) -> D3D10_SB_OPERAND_MODIFIER { + ((OperandToken1 & D3D10_SB_OPERAND_MODIFIER_MASK) >> D3D10_SB_OPERAND_MODIFIER_SHIFT) + as D3D10_SB_OPERAND_MODIFIER +} +#[inline] +pub fn ENCODE_D3D10_SB_EXTENDED_OPERAND_MODIFIER(SourceMod: D3D10_SB_OPERAND_MODIFIER) -> DWORD { + ((SourceMod << D3D10_SB_OPERAND_MODIFIER_SHIFT) & D3D10_SB_OPERAND_MODIFIER_MASK) + | ENCODE_D3D10_SB_EXTENDED_OPERAND_TYPE(D3D10_SB_EXTENDED_OPERAND_MODIFIER) + | ENCODE_D3D10_SB_OPERAND_DOUBLE_EXTENDED(0) +} +ENUM!{enum D3D11_SB_OPERAND_MIN_PRECISION { + D3D11_SB_OPERAND_MIN_PRECISION_DEFAULT = 0, + D3D11_SB_OPERAND_MIN_PRECISION_FLOAT_16 = 1, + D3D11_SB_OPERAND_MIN_PRECISION_FLOAT_2_8 = 2, + D3D11_SB_OPERAND_MIN_PRECISION_SINT_16 = 4, + D3D11_SB_OPERAND_MIN_PRECISION_UINT_16 = 5, +}} +pub const D3D11_SB_OPERAND_MIN_PRECISION_MASK: DWORD = 0x0001C000; +pub const D3D11_SB_OPERAND_MIN_PRECISION_SHIFT: DWORD = 14; +#[inline] +pub fn DECODE_D3D11_SB_OPERAND_MIN_PRECISION( + OperandToken1: DWORD, +) -> D3D11_SB_OPERAND_MIN_PRECISION { + ((OperandToken1 & D3D11_SB_OPERAND_MIN_PRECISION_MASK) >> D3D11_SB_OPERAND_MIN_PRECISION_SHIFT) + as D3D11_SB_OPERAND_MIN_PRECISION +} +#[inline] +pub fn ENCODE_D3D11_SB_OPERAND_MIN_PRECISION( + MinPrecision: D3D11_SB_OPERAND_MIN_PRECISION, +) -> DWORD { + (MinPrecision << D3D11_SB_OPERAND_MIN_PRECISION_SHIFT) & D3D11_SB_OPERAND_MIN_PRECISION_MASK +} +pub const D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK: DWORD = 0x80000000; +pub const D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT: DWORD = 31; +#[inline] +pub fn DECODE_IS_D3D10_SB_OPERAND_DOUBLE_EXTENDED(OperandToken1: DWORD) -> DWORD { + (OperandToken1 & D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK) + >> D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT +} +#[inline] +pub fn ENCODE_D3D10_SB_OPERAND_DOUBLE_EXTENDED(bExtended: DWORD) -> DWORD { + if bExtended != 0 { + D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK + } else { + 0 + } +} +pub const D3D10_SB_NAME_MASK: DWORD = 0x0000ffff; +#[inline] +pub fn DECODE_D3D10_SB_NAME(NameToken: DWORD) -> D3D10_SB_NAME { + (NameToken & D3D10_SB_NAME_MASK) as D3D10_SB_NAME +} +#[inline] +pub fn ENCODE_D3D10_SB_NAME(Name: D3D10_SB_NAME) -> DWORD { + Name & D3D10_SB_NAME_MASK +} +pub const D3D10_SB_GLOBAL_FLAG_REFACTORING_ALLOWED: DWORD = (1 << 11); +pub const D3D11_SB_GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS: DWORD = (1 << 12); +pub const D3D11_SB_GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL: DWORD = (1 << 13); +pub const D3D11_SB_GLOBAL_FLAG_ENABLE_RAW_AND_STRUCTURED_BUFFERS: DWORD = (1 << 14); +pub const D3D11_1_SB_GLOBAL_FLAG_SKIP_OPTIMIZATION: DWORD = (1 << 15); +pub const D3D11_1_SB_GLOBAL_FLAG_ENABLE_MINIMUM_PRECISION: DWORD = (1 << 16); +pub const D3D11_1_SB_GLOBAL_FLAG_ENABLE_DOUBLE_EXTENSIONS: DWORD = (1 << 17); +pub const D3D11_1_SB_GLOBAL_FLAG_ENABLE_SHADER_EXTENSIONS: DWORD = (1 << 18); +pub const D3D10_SB_GLOBAL_FLAGS_MASK: DWORD = 0x00fff800; +#[inline] +pub fn DECODE_D3D10_SB_GLOBAL_FLAGS(OpcodeToken0: DWORD) -> DWORD { + OpcodeToken0 & D3D10_SB_GLOBAL_FLAGS_MASK +} +#[inline] +pub fn ENCODE_D3D10_SB_GLOBAL_FLAGS(Flags: DWORD) -> DWORD { + Flags & D3D10_SB_GLOBAL_FLAGS_MASK +} +pub const D3D10_SB_RESOURCE_DIMENSION_MASK: DWORD = 0x0000F800; +pub const D3D10_SB_RESOURCE_DIMENSION_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_RESOURCE_DIMENSION(OpcodeToken0: DWORD) -> D3D10_SB_RESOURCE_DIMENSION { + ((OpcodeToken0 & D3D10_SB_RESOURCE_DIMENSION_MASK) >> D3D10_SB_RESOURCE_DIMENSION_SHIFT) + as D3D10_SB_RESOURCE_DIMENSION +} +#[inline] +pub fn ENCODE_D3D10_SB_RESOURCE_DIMENSION(ResourceDim: D3D10_SB_RESOURCE_DIMENSION) -> DWORD { + (ResourceDim << D3D10_SB_RESOURCE_DIMENSION_SHIFT) & D3D10_SB_RESOURCE_DIMENSION_MASK +} +pub const D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK: DWORD = 0x07F0000; +pub const D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT: DWORD = 16; +#[inline] +pub fn DECODE_D3D10_SB_RESOURCE_SAMPLE_COUNT(OpcodeToken0: DWORD) -> UINT { + ((OpcodeToken0 & D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK) >> D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT) + as UINT +} +#[inline] +pub fn ENCODE_D3D10_SB_RESOURCE_SAMPLE_COUNT(SampleCount: DWORD) -> DWORD { + (if SampleCount > 127 { 127 } else { SampleCount } << D3D10_SB_RESOURCE_SAMPLE_COUNT_SHIFT) + & D3D10_SB_RESOURCE_SAMPLE_COUNT_MASK +} +#[inline] +pub fn DECODE_D3D10_SB_RESOURCE_RETURN_TYPE( + ResourceReturnTypeToken: D3D10_SB_RESOURCE_RETURN_TYPE, + Component: DWORD, +) -> D3D10_SB_RESOURCE_RETURN_TYPE { + ((ResourceReturnTypeToken >> (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS)) + & D3D10_SB_RESOURCE_RETURN_TYPE_MASK) as D3D10_SB_RESOURCE_RETURN_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_RESOURCE_RETURN_TYPE( + ReturnType: DWORD, + Component: DWORD, +) -> D3D10_SB_RESOURCE_RETURN_TYPE { + (ReturnType & D3D10_SB_RESOURCE_RETURN_TYPE_MASK) + << (Component * D3D10_SB_RESOURCE_RETURN_TYPE_NUMBITS) +} +ENUM!{enum D3D10_SB_SAMPLER_MODE { + D3D10_SB_SAMPLER_MODE_DEFAULT = 0, + D3D10_SB_SAMPLER_MODE_COMPARISON = 1, + D3D10_SB_SAMPLER_MODE_MONO = 2, +}} +pub const D3D10_SB_SAMPLER_MODE_MASK: DWORD = 0x00007800; +pub const D3D10_SB_SAMPLER_MODE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_SAMPLER_MODE(OpcodeToken0: DWORD) -> D3D10_SB_SAMPLER_MODE { + ((OpcodeToken0 & D3D10_SB_SAMPLER_MODE_MASK) >> D3D10_SB_SAMPLER_MODE_SHIFT) + as D3D10_SB_SAMPLER_MODE +} +#[inline] +pub fn ENCODE_D3D10_SB_SAMPLER_MODE(SamplerMode: D3D10_SB_SAMPLER_MODE) -> DWORD { + (SamplerMode << D3D10_SB_SAMPLER_MODE_SHIFT) & D3D10_SB_SAMPLER_MODE_MASK +} +pub const D3D10_SB_INPUT_INTERPOLATION_MODE_MASK: DWORD = 0x00007800; +pub const D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_INPUT_INTERPOLATION_MODE( + OpcodeToken0: DWORD, +) -> D3D10_SB_INTERPOLATION_MODE { + ((OpcodeToken0 & D3D10_SB_INPUT_INTERPOLATION_MODE_MASK) + >> D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT) as D3D10_SB_INTERPOLATION_MODE +} +#[inline] +pub fn ENCODE_D3D10_SB_INPUT_INTERPOLATION_MODE( + InterpolationMode: D3D10_SB_INTERPOLATION_MODE, +) -> DWORD { + (InterpolationMode << D3D10_SB_INPUT_INTERPOLATION_MODE_SHIFT) + & D3D10_SB_INPUT_INTERPOLATION_MODE_MASK +} +ENUM!{enum D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN { + D3D10_SB_CONSTANT_BUFFER_IMMEDIATE_INDEXED = 0, + D3D10_SB_CONSTANT_BUFFER_DYNAMIC_INDEXED = 1, +}} +pub const D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK: DWORD = 0x00000800; +pub const D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN( + OpcodeToken0: DWORD, +) -> D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN { + ((OpcodeToken0 & D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK) + >> D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT) + as D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN +} +#[inline] +pub fn ENCODE_D3D10_SB_D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN( + AccessPattern: D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN, +) -> DWORD { + (AccessPattern << D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_SHIFT) + & D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN_MASK +} +ENUM!{enum D3D11_SB_SHADER_MESSAGE_ID { + D3D11_SB_SHADER_MESSAGE_ID_MESSAGE = 0x00200102, + D3D11_SB_SHADER_MESSAGE_ID_ERROR = 0x00200103, +}} +ENUM!{enum D3D11_SB_SHADER_MESSAGE_FORMAT { + D3D11_SB_SHADER_MESSAGE_FORMAT_ANSI_TEXT = 0, + D3D11_SB_SHADER_MESSAGE_FORMAT_ANSI_PRINTF = 1, +}} +pub const D3D10_SB_GS_INPUT_PRIMITIVE_MASK: DWORD = 0x0001f800; +pub const D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_GS_INPUT_PRIMITIVE(OpcodeToken0: DWORD) -> D3D10_SB_PRIMITIVE { + ((OpcodeToken0 & D3D10_SB_GS_INPUT_PRIMITIVE_MASK) >> D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT) + as D3D10_SB_PRIMITIVE +} +#[inline] +pub fn ENCODE_D3D10_SB_GS_INPUT_PRIMITIVE(Prim: D3D10_SB_PRIMITIVE) -> DWORD { + (Prim << D3D10_SB_GS_INPUT_PRIMITIVE_SHIFT) & D3D10_SB_GS_INPUT_PRIMITIVE_MASK +} +pub const D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK: DWORD = 0x0001f800; +pub const D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY( + OpcodeToken0: DWORD, +) -> D3D10_SB_PRIMITIVE_TOPOLOGY { + ((OpcodeToken0 & D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK) + >> D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT) as D3D10_SB_PRIMITIVE_TOPOLOGY +} +#[inline] +pub fn ENCODE_D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY( + PrimTopology: D3D10_SB_PRIMITIVE_TOPOLOGY, +) -> DWORD { + (PrimTopology << D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_SHIFT) + & D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY_MASK +} +pub const D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK: DWORD = 0x0001f800; +pub const D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_INPUT_CONTROL_POINT_COUNT(OpcodeToken0: DWORD) -> UINT { + ((OpcodeToken0 & D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK) + >> D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT) as UINT +} +#[inline] +pub fn ENCODE_D3D11_SB_INPUT_CONTROL_POINT_COUNT(Count: DWORD) -> DWORD { + (Count << D3D11_SB_INPUT_CONTROL_POINT_COUNT_SHIFT) & D3D11_SB_INPUT_CONTROL_POINT_COUNT_MASK +} +pub const D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK: DWORD = 0x0001f800; +pub const D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_OUTPUT_CONTROL_POINT_COUNT(OpcodeToken0: DWORD) -> UINT { + ((OpcodeToken0 & D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK) + >> D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT) as UINT +} +#[inline] +pub fn ENCODE_D3D11_SB_OUTPUT_CONTROL_POINT_COUNT(Count: DWORD) -> DWORD { + (Count << D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_SHIFT) & D3D11_SB_OUTPUT_CONTROL_POINT_COUNT_MASK +} +ENUM!{enum D3D11_SB_TESSELLATOR_DOMAIN { + D3D11_SB_TESSELLATOR_DOMAIN_UNDEFINED = 0, + D3D11_SB_TESSELLATOR_DOMAIN_ISOLINE = 1, + D3D11_SB_TESSELLATOR_DOMAIN_TRI = 2, + D3D11_SB_TESSELLATOR_DOMAIN_QUAD = 3, +}} +pub const D3D11_SB_TESS_DOMAIN_MASK: DWORD = 0x00001800; +pub const D3D11_SB_TESS_DOMAIN_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_TESS_DOMAIN(OpcodeToken0: DWORD) -> D3D11_SB_TESSELLATOR_DOMAIN { + ((OpcodeToken0 & D3D11_SB_TESS_DOMAIN_MASK) >> D3D11_SB_TESS_DOMAIN_SHIFT) + as D3D11_SB_TESSELLATOR_DOMAIN +} +#[inline] +pub fn ENCODE_D3D11_SB_TESS_DOMAIN(Domain: D3D11_SB_TESSELLATOR_DOMAIN) -> DWORD { + (Domain << D3D11_SB_TESS_DOMAIN_SHIFT) & D3D11_SB_TESS_DOMAIN_MASK +} +ENUM!{enum D3D11_SB_TESSELLATOR_PARTITIONING { + D3D11_SB_TESSELLATOR_PARTITIONING_UNDEFINED = 0, + D3D11_SB_TESSELLATOR_PARTITIONING_INTEGER = 1, + D3D11_SB_TESSELLATOR_PARTITIONING_POW2 = 2, + D3D11_SB_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD = 3, + D3D11_SB_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN = 4, +}} +pub const D3D11_SB_TESS_PARTITIONING_MASK: DWORD = 0x00003800; +pub const D3D11_SB_TESS_PARTITIONING_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_TESS_PARTITIONING( + OpcodeToken0: DWORD, +) -> D3D11_SB_TESSELLATOR_PARTITIONING { + ((OpcodeToken0 & D3D11_SB_TESS_PARTITIONING_MASK) >> D3D11_SB_TESS_PARTITIONING_SHIFT) + as D3D11_SB_TESSELLATOR_PARTITIONING +} +#[inline] +pub fn ENCODE_D3D11_SB_TESS_PARTITIONING( + Partitioning: D3D11_SB_TESSELLATOR_PARTITIONING, +) -> DWORD { + (Partitioning << D3D11_SB_TESS_PARTITIONING_SHIFT) & D3D11_SB_TESS_PARTITIONING_MASK +} +ENUM!{enum D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE { + D3D11_SB_TESSELLATOR_OUTPUT_UNDEFINED = 0, + D3D11_SB_TESSELLATOR_OUTPUT_POINT = 1, + D3D11_SB_TESSELLATOR_OUTPUT_LINE = 2, + D3D11_SB_TESSELLATOR_OUTPUT_TRIANGLE_CW = 3, + D3D11_SB_TESSELLATOR_OUTPUT_TRIANGLE_CCW = 4, +}} +pub const D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK: DWORD = 0x00003800; +pub const D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D11_SB_TESS_OUTPUT_PRIMITIVE( + OpcodeToken0: DWORD, +) -> D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE { + ((OpcodeToken0 & D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK) >> D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT) + as D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE +} +#[inline] +pub fn ENCODE_D3D11_SB_TESS_OUTPUT_PRIMITIVE( + OutputPrimitive: D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE, +) -> DWORD { + (OutputPrimitive << D3D11_SB_TESS_OUTPUT_PRIMITIVE_SHIFT) & D3D11_SB_TESS_OUTPUT_PRIMITIVE_MASK +} +ENUM!{enum D3D10_SB_INTERPOLATION_MODE { + D3D10_SB_INTERPOLATION_UNDEFINED = 0, + D3D10_SB_INTERPOLATION_CONSTANT = 1, + D3D10_SB_INTERPOLATION_LINEAR = 2, + D3D10_SB_INTERPOLATION_LINEAR_CENTROID = 3, + D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE = 4, + D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID = 5, + D3D10_SB_INTERPOLATION_LINEAR_SAMPLE = 6, + D3D10_SB_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE = 7, +}} +ENUM!{enum D3D10_SB_PRIMITIVE_TOPOLOGY { + D3D10_SB_PRIMITIVE_TOPOLOGY_UNDEFINED = 0, + D3D10_SB_PRIMITIVE_TOPOLOGY_POINTLIST = 1, + D3D10_SB_PRIMITIVE_TOPOLOGY_LINELIST = 2, + D3D10_SB_PRIMITIVE_TOPOLOGY_LINESTRIP = 3, + D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4, + D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5, + D3D10_SB_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10, + D3D10_SB_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11, + D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12, + D3D10_SB_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13, +}} +ENUM!{enum D3D10_SB_PRIMITIVE { + D3D10_SB_PRIMITIVE_UNDEFINED = 0, + D3D10_SB_PRIMITIVE_POINT = 1, + D3D10_SB_PRIMITIVE_LINE = 2, + D3D10_SB_PRIMITIVE_TRIANGLE = 3, + D3D10_SB_PRIMITIVE_LINE_ADJ = 6, + D3D10_SB_PRIMITIVE_TRIANGLE_ADJ = 7, + D3D11_SB_PRIMITIVE_1_CONTROL_POINT_PATCH = 8, + D3D11_SB_PRIMITIVE_2_CONTROL_POINT_PATCH = 9, + D3D11_SB_PRIMITIVE_3_CONTROL_POINT_PATCH = 10, + D3D11_SB_PRIMITIVE_4_CONTROL_POINT_PATCH = 11, + D3D11_SB_PRIMITIVE_5_CONTROL_POINT_PATCH = 12, + D3D11_SB_PRIMITIVE_6_CONTROL_POINT_PATCH = 13, + D3D11_SB_PRIMITIVE_7_CONTROL_POINT_PATCH = 14, + D3D11_SB_PRIMITIVE_8_CONTROL_POINT_PATCH = 15, + D3D11_SB_PRIMITIVE_9_CONTROL_POINT_PATCH = 16, + D3D11_SB_PRIMITIVE_10_CONTROL_POINT_PATCH = 17, + D3D11_SB_PRIMITIVE_11_CONTROL_POINT_PATCH = 18, + D3D11_SB_PRIMITIVE_12_CONTROL_POINT_PATCH = 19, + D3D11_SB_PRIMITIVE_13_CONTROL_POINT_PATCH = 20, + D3D11_SB_PRIMITIVE_14_CONTROL_POINT_PATCH = 21, + D3D11_SB_PRIMITIVE_15_CONTROL_POINT_PATCH = 22, + D3D11_SB_PRIMITIVE_16_CONTROL_POINT_PATCH = 23, + D3D11_SB_PRIMITIVE_17_CONTROL_POINT_PATCH = 24, + D3D11_SB_PRIMITIVE_18_CONTROL_POINT_PATCH = 25, + D3D11_SB_PRIMITIVE_19_CONTROL_POINT_PATCH = 26, + D3D11_SB_PRIMITIVE_20_CONTROL_POINT_PATCH = 27, + D3D11_SB_PRIMITIVE_21_CONTROL_POINT_PATCH = 28, + D3D11_SB_PRIMITIVE_22_CONTROL_POINT_PATCH = 29, + D3D11_SB_PRIMITIVE_23_CONTROL_POINT_PATCH = 30, + D3D11_SB_PRIMITIVE_24_CONTROL_POINT_PATCH = 31, + D3D11_SB_PRIMITIVE_25_CONTROL_POINT_PATCH = 32, + D3D11_SB_PRIMITIVE_26_CONTROL_POINT_PATCH = 33, + D3D11_SB_PRIMITIVE_27_CONTROL_POINT_PATCH = 34, + D3D11_SB_PRIMITIVE_28_CONTROL_POINT_PATCH = 35, + D3D11_SB_PRIMITIVE_29_CONTROL_POINT_PATCH = 36, + D3D11_SB_PRIMITIVE_30_CONTROL_POINT_PATCH = 37, + D3D11_SB_PRIMITIVE_31_CONTROL_POINT_PATCH = 38, + D3D11_SB_PRIMITIVE_32_CONTROL_POINT_PATCH = 39, +}} +ENUM!{enum D3D10_SB_COMPONENT_MASK { + D3D10_SB_COMPONENT_MASK_X = 1, + D3D10_SB_COMPONENT_MASK_Y = 2, + D3D10_SB_COMPONENT_MASK_Z = 4, + D3D10_SB_COMPONENT_MASK_W = 8, + D3D10_SB_COMPONENT_MASK_R = 1, + D3D10_SB_COMPONENT_MASK_G = 2, + D3D10_SB_COMPONENT_MASK_B = 4, + D3D10_SB_COMPONENT_MASK_A = 8, + D3D10_SB_COMPONENT_MASK_ALL = 15, +}} +ENUM!{enum D3D10_SB_NAME { + D3D10_SB_NAME_UNDEFINED = 0, + D3D10_SB_NAME_POSITION = 1, + D3D10_SB_NAME_CLIP_DISTANCE = 2, + D3D10_SB_NAME_CULL_DISTANCE = 3, + D3D10_SB_NAME_RENDER_TARGET_ARRAY_INDEX = 4, + D3D10_SB_NAME_VIEWPORT_ARRAY_INDEX = 5, + D3D10_SB_NAME_VERTEX_ID = 6, + D3D10_SB_NAME_PRIMITIVE_ID = 7, + D3D10_SB_NAME_INSTANCE_ID = 8, + D3D10_SB_NAME_IS_FRONT_FACE = 9, + D3D10_SB_NAME_SAMPLE_INDEX = 10, + D3D11_SB_NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR = 11, + D3D11_SB_NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR = 12, + D3D11_SB_NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR = 13, + D3D11_SB_NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR = 14, + D3D11_SB_NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR = 15, + D3D11_SB_NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR = 16, + D3D11_SB_NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR = 17, + D3D11_SB_NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR = 18, + D3D11_SB_NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR = 19, + D3D11_SB_NAME_FINAL_TRI_INSIDE_TESSFACTOR = 20, + D3D11_SB_NAME_FINAL_LINE_DETAIL_TESSFACTOR = 21, + D3D11_SB_NAME_FINAL_LINE_DENSITY_TESSFACTOR = 22, +}} +ENUM!{enum D3D10_SB_RESOURCE_DIMENSION { + D3D10_SB_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D10_SB_RESOURCE_DIMENSION_BUFFER = 1, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DMS = 4, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE3D = 5, + D3D10_SB_RESOURCE_DIMENSION_TEXTURECUBE = 6, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE1DARRAY = 7, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DARRAY = 8, + D3D10_SB_RESOURCE_DIMENSION_TEXTURE2DMSARRAY = 9, + D3D10_SB_RESOURCE_DIMENSION_TEXTURECUBEARRAY = 10, + D3D11_SB_RESOURCE_DIMENSION_RAW_BUFFER = 11, + D3D11_SB_RESOURCE_DIMENSION_STRUCTURED_BUFFER = 12, +}} +ENUM!{enum D3D10_SB_RESOURCE_RETURN_TYPE { + D3D10_SB_RETURN_TYPE_UNORM = 1, + D3D10_SB_RETURN_TYPE_SNORM = 2, + D3D10_SB_RETURN_TYPE_SINT = 3, + D3D10_SB_RETURN_TYPE_UINT = 4, + D3D10_SB_RETURN_TYPE_FLOAT = 5, + D3D10_SB_RETURN_TYPE_MIXED = 6, + D3D11_SB_RETURN_TYPE_DOUBLE = 7, + D3D11_SB_RETURN_TYPE_CONTINUED = 8, + D3D11_SB_RETURN_TYPE_UNUSED = 9, +}} +ENUM!{enum D3D10_SB_REGISTER_COMPONENT_TYPE { + D3D10_SB_REGISTER_COMPONENT_UNKNOWN = 0, + D3D10_SB_REGISTER_COMPONENT_UINT32 = 1, + D3D10_SB_REGISTER_COMPONENT_SINT32 = 2, + D3D10_SB_REGISTER_COMPONENT_FLOAT32 = 3, +}} +ENUM!{enum D3D10_SB_INSTRUCTION_RETURN_TYPE { + D3D10_SB_INSTRUCTION_RETURN_FLOAT = 0, + D3D10_SB_INSTRUCTION_RETURN_UINT = 1, +}} +pub const D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK: DWORD = 0x00001800; +pub const D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT: DWORD = 11; +#[inline] +pub fn DECODE_D3D10_SB_INSTRUCTION_RETURN_TYPE( + OpcodeToken0: DWORD, +) -> D3D10_SB_INSTRUCTION_RETURN_TYPE { + ((OpcodeToken0 & D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK) + >> D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT) as D3D10_SB_INSTRUCTION_RETURN_TYPE +} +#[inline] +pub fn ENCODE_D3D10_SB_INSTRUCTION_RETURN_TYPE( + ReturnType: D3D10_SB_INSTRUCTION_RETURN_TYPE, +) -> DWORD { + (ReturnType << D3D10_SB_INSTRUCTION_RETURN_TYPE_SHIFT) & D3D10_SB_INSTRUCTION_RETURN_TYPE_MASK +} +pub const D3D11_SB_INTERFACE_INDEXED_BIT_MASK: DWORD = 0x00000800; +pub const D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT: DWORD = 11; +pub const D3D11_SB_INTERFACE_TABLE_LENGTH_MASK: DWORD = 0x0000ffff; +pub const D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT: DWORD = 0; +pub const D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK: DWORD = 0xffff0000; +pub const D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT: DWORD = 16; +#[inline] +pub fn DECODE_D3D11_SB_INTERFACE_INDEXED_BIT(OpcodeToken0: DWORD) -> DWORD { + if (OpcodeToken0 & D3D11_SB_INTERFACE_INDEXED_BIT_MASK) >> D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT + != 0 { 1 } else { 0 } +} +#[inline] +pub fn ENCODE_D3D11_SB_INTERFACE_INDEXED_BIT(IndexedBit: DWORD) -> DWORD { + (IndexedBit << D3D11_SB_INTERFACE_INDEXED_BIT_SHIFT) & D3D11_SB_INTERFACE_INDEXED_BIT_MASK +} +#[inline] +pub fn DECODE_D3D11_SB_INTERFACE_TABLE_LENGTH(OpcodeToken0: DWORD) -> UINT { + ((OpcodeToken0 & D3D11_SB_INTERFACE_TABLE_LENGTH_MASK) + >> D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT) as UINT +} +#[inline] +pub fn ENCODE_D3D11_SB_INTERFACE_TABLE_LENGTH(TableLength: DWORD) -> DWORD { + (TableLength << D3D11_SB_INTERFACE_TABLE_LENGTH_SHIFT) & D3D11_SB_INTERFACE_TABLE_LENGTH_MASK +} +#[inline] +pub fn DECODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(OpcodeToken0: DWORD) -> UINT { + ((OpcodeToken0 & D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK) + >> D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT) as UINT +} +#[inline] +pub fn ENCODE_D3D11_SB_INTERFACE_ARRAY_LENGTH(ArrayLength: DWORD) -> DWORD { + (ArrayLength << D3D11_SB_INTERFACE_ARRAY_LENGTH_SHIFT) & D3D11_SB_INTERFACE_ARRAY_LENGTH_MASK +} +pub const D3D11_SB_GLOBALLY_COHERENT_ACCESS: DWORD = 0x00010000; +pub const D3D11_SB_ACCESS_COHERENCY_MASK: DWORD = 0x00010000; +#[inline] +pub fn DECODE_D3D11_SB_ACCESS_COHERENCY_FLAGS(OperandToken0: DWORD) -> DWORD { + OperandToken0 & D3D11_SB_ACCESS_COHERENCY_MASK +} +#[inline] +pub fn ENCODE_D3D11_SB_ACCESS_COHERENCY_FLAGS(Flags: DWORD) -> DWORD { + Flags & D3D11_SB_ACCESS_COHERENCY_MASK +} +pub const D3D11_SB_UAV_HAS_ORDER_PRESERVING_COUNTER: DWORD = 0x00800000; +pub const D3D11_SB_UAV_FLAGS_MASK: DWORD = 0x00800000; +#[inline] +pub fn DECODE_D3D11_SB_UAV_FLAGS(OperandToken0: DWORD) -> DWORD { + OperandToken0 & D3D11_SB_UAV_FLAGS_MASK +} +#[inline] +pub fn ENCODE_D3D11_SB_UAV_FLAGS(Flags: DWORD) -> DWORD { + Flags & D3D11_SB_UAV_FLAGS_MASK +} diff --git a/winapi/src/um/d3d12.rs b/winapi/src/um/d3d12.rs new file mode 100644 index 000000000..56048d939 --- /dev/null +++ b/winapi/src/um/d3d12.rs @@ -0,0 +1,2722 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::basetsd::{INT8, LONG_PTR, SIZE_T, UINT16, UINT64, UINT8}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::DXGI_SAMPLE_DESC; +use shared::guiddef::{IID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, LPCVOID, UINT}; +use shared::windef::RECT; +use um::d3dcommon::{D3D_FEATURE_LEVEL, D3D_PRIMITIVE, D3D_PRIMITIVE_TOPOLOGY, ID3DBlob}; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LPCSTR, LPCWSTR, LUID}; +pub const D3D12_16BIT_INDEX_STRIP_CUT_VALUE: UINT = 0xffff; +pub const D3D12_32BIT_INDEX_STRIP_CUT_VALUE: UINT = 0xffffffff; +pub const D3D12_8BIT_INDEX_STRIP_CUT_VALUE: UINT = 0xff; +pub const D3D12_APPEND_ALIGNED_ELEMENT: UINT = 0xffffffff; +pub const D3D12_ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT: UINT = 9; +pub const D3D12_CLIP_OR_CULL_DISTANCE_COUNT: UINT = 8; +pub const D3D12_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT: UINT = 2; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT: UINT = 14; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENTS: UINT = 4; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT: UINT = 15; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT: UINT = 16; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT: UINT = 15; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_COMMONSHADER_FLOWCONTROL_NESTING_LIMIT: UINT = 64; +pub const D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT: UINT = 1; +pub const D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT: UINT = 128; +pub const D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT: UINT = 128; +pub const D3D12_COMMONSHADER_SAMPLER_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_COMMONSHADER_SAMPLER_REGISTER_COUNT: UINT = 16; +pub const D3D12_COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_COMMONSHADER_SAMPLER_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_COMMONSHADER_SAMPLER_SLOT_COUNT: UINT = 16; +pub const D3D12_COMMONSHADER_SUBROUTINE_NESTING_LIMIT: UINT = 32; +pub const D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_COMMONSHADER_TEMP_REGISTER_COUNT: UINT = 4096; +pub const D3D12_COMMONSHADER_TEMP_REGISTER_READS_PER_INST: UINT = 3; +pub const D3D12_COMMONSHADER_TEMP_REGISTER_READ_PORTS: UINT = 3; +pub const D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX: INT = 10; +pub const D3D12_COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN: INT = -10; +pub const D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE: INT = -8; +pub const D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE: INT = 7; +pub const D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT: UINT = 256; +pub const D3D12_CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 256; +pub const D3D12_CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP: UINT = 64; +pub const D3D12_CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 240; +pub const D3D12_CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP: UINT = 68; +pub const D3D12_CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 224; +pub const D3D12_CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP: UINT = 72; +pub const D3D12_CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 208; +pub const D3D12_CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP: UINT = 76; +pub const D3D12_CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 192; +pub const D3D12_CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP: UINT = 84; +pub const D3D12_CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 176; +pub const D3D12_CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP: UINT = 92; +pub const D3D12_CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 160; +pub const D3D12_CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP: UINT = 100; +pub const D3D12_CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 144; +pub const D3D12_CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP: UINT = 112; +pub const D3D12_CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 128; +pub const D3D12_CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP: UINT = 128; +pub const D3D12_CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 112; +pub const D3D12_CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP: UINT = 144; +pub const D3D12_CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 96; +pub const D3D12_CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP: UINT = 168; +pub const D3D12_CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 80; +pub const D3D12_CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP: UINT = 204; +pub const D3D12_CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 64; +pub const D3D12_CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP: UINT = 256; +pub const D3D12_CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 48; +pub const D3D12_CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP: UINT = 340; +pub const D3D12_CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 32; +pub const D3D12_CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP: UINT = 512; +pub const D3D12_CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD: UINT = 16; +pub const D3D12_CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP: UINT = 768; +pub const D3D12_CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION: UINT = 1; +pub const D3D12_CS_4_X_RAW_UAV_BYTE_ALIGNMENT: UINT = 256; +pub const D3D12_CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP: UINT = 768; +pub const D3D12_CS_4_X_THREAD_GROUP_MAX_X: UINT = 768; +pub const D3D12_CS_4_X_THREAD_GROUP_MAX_Y: UINT = 768; +pub const D3D12_CS_4_X_UAV_REGISTER_COUNT: UINT = 1; +pub const D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION: UINT = 65535; +pub const D3D12_CS_TGSM_REGISTER_COUNT: UINT = 8192; +pub const D3D12_CS_TGSM_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_CS_TGSM_RESOURCE_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_CS_TGSM_RESOURCE_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_CS_THREADGROUPID_REGISTER_COMPONENTS: UINT = 3; +pub const D3D12_CS_THREADGROUPID_REGISTER_COUNT: UINT = 1; +pub const D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT: UINT = 1; +pub const D3D12_CS_THREADIDINGROUP_REGISTER_COMPONENTS: UINT = 3; +pub const D3D12_CS_THREADIDINGROUP_REGISTER_COUNT: UINT = 1; +pub const D3D12_CS_THREADID_REGISTER_COMPONENTS: UINT = 3; +pub const D3D12_CS_THREADID_REGISTER_COUNT: UINT = 1; +pub const D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP: UINT = 1024; +pub const D3D12_CS_THREAD_GROUP_MAX_X: UINT = 1024; +pub const D3D12_CS_THREAD_GROUP_MAX_Y: UINT = 1024; +pub const D3D12_CS_THREAD_GROUP_MAX_Z: UINT = 64; +pub const D3D12_CS_THREAD_GROUP_MIN_X: UINT = 1; +pub const D3D12_CS_THREAD_GROUP_MIN_Y: UINT = 1; +pub const D3D12_CS_THREAD_GROUP_MIN_Z: UINT = 1; +pub const D3D12_CS_THREAD_LOCAL_TEMP_REGISTER_POOL: UINT = 16384; +pub const D3D12_DEFAULT_BLEND_FACTOR_ALPHA: FLOAT = 1.0; +pub const D3D12_DEFAULT_BLEND_FACTOR_BLUE: FLOAT = 1.0; +pub const D3D12_DEFAULT_BLEND_FACTOR_GREEN: FLOAT = 1.0; +pub const D3D12_DEFAULT_BLEND_FACTOR_RED: FLOAT = 1.0; +pub const D3D12_DEFAULT_BORDER_COLOR_COMPONENT: FLOAT = 0.0; +pub const D3D12_DEFAULT_DEPTH_BIAS: UINT = 0; +pub const D3D12_DEFAULT_DEPTH_BIAS_CLAMP: FLOAT = 0.0; +pub const D3D12_DEFAULT_MAX_ANISOTROPY: UINT = 16; +pub const D3D12_DEFAULT_MIP_LOD_BIAS: FLOAT = 0.0; +pub const D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT: UINT = 4194304; +pub const D3D12_DEFAULT_RENDER_TARGET_ARRAY_INDEX: UINT = 0; +pub const D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT: UINT = 65536; +pub const D3D12_DEFAULT_SAMPLE_MASK: UINT = 0xffffffff; +pub const D3D12_DEFAULT_SCISSOR_ENDX: UINT = 0; +pub const D3D12_DEFAULT_SCISSOR_ENDY: UINT = 0; +pub const D3D12_DEFAULT_SCISSOR_STARTX: UINT = 0; +pub const D3D12_DEFAULT_SCISSOR_STARTY: UINT = 0; +pub const D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS: FLOAT = 0.0; +pub const D3D12_DEFAULT_STENCIL_READ_MASK: UINT = 0xff; +pub const D3D12_DEFAULT_STENCIL_REFERENCE: UINT = 0; +pub const D3D12_DEFAULT_STENCIL_WRITE_MASK: UINT = 0xff; +pub const D3D12_DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX: UINT = 0; +pub const D3D12_DEFAULT_VIEWPORT_HEIGHT: UINT = 0; +pub const D3D12_DEFAULT_VIEWPORT_MAX_DEPTH: FLOAT = 0.0; +pub const D3D12_DEFAULT_VIEWPORT_MIN_DEPTH: FLOAT = 0.0; +pub const D3D12_DEFAULT_VIEWPORT_TOPLEFTX: UINT = 0; +pub const D3D12_DEFAULT_VIEWPORT_TOPLEFTY: UINT = 0; +pub const D3D12_DEFAULT_VIEWPORT_WIDTH: UINT = 0; +pub const D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND: UINT = 0xffffffff; +pub const D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_END: UINT = 0xfffffff7; +pub const D3D12_DRIVER_RESERVED_REGISTER_SPACE_VALUES_START: UINT = 0xfffffff0; +pub const D3D12_DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS: UINT = 3968; +pub const D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_CONTROL_POINT_REGISTER_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS: UINT = 3; +pub const D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_COUNT: UINT = 1; +pub const D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_DS_OUTPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_DS_OUTPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_FLOAT16_FUSED_TOLERANCE_IN_ULP: FLOAT = 0.6; +pub const D3D12_FLOAT32_MAX: FLOAT = 3.402823466e+38; +pub const D3D12_FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP: FLOAT = 0.6; +pub const D3D12_FLOAT_TO_SRGB_EXPONENT_DENOMINATOR: FLOAT = 2.4; +pub const D3D12_FLOAT_TO_SRGB_EXPONENT_NUMERATOR: FLOAT = 1.0; +pub const D3D12_FLOAT_TO_SRGB_OFFSET: FLOAT = 0.055; +pub const D3D12_FLOAT_TO_SRGB_SCALE_1: FLOAT = 12.92; +pub const D3D12_FLOAT_TO_SRGB_SCALE_2: FLOAT = 1.055; +pub const D3D12_FLOAT_TO_SRGB_THRESHOLD: FLOAT = 0.0031308; +pub const D3D12_FTOI_INSTRUCTION_MAX_INPUT: FLOAT = 2147483647.999; +pub const D3D12_FTOI_INSTRUCTION_MIN_INPUT: FLOAT = -2147483648.999; +pub const D3D12_FTOU_INSTRUCTION_MAX_INPUT: FLOAT = 4294967295.999; +pub const D3D12_FTOU_INSTRUCTION_MIN_INPUT: FLOAT = 0.0; +pub const D3D12_GS_INPUT_INSTANCE_ID_READS_PER_INST: UINT = 2; +pub const D3D12_GS_INPUT_INSTANCE_ID_READ_PORTS: UINT = 1; +pub const D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_GS_INPUT_INSTANCE_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_GS_INPUT_PRIM_CONST_REGISTER_COUNT: UINT = 1; +pub const D3D12_GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_GS_INPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_GS_INPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_GS_INPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_GS_INPUT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_GS_INPUT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_GS_INPUT_REGISTER_VERTICES: UINT = 32; +pub const D3D12_GS_MAX_INSTANCE_COUNT: UINT = 32; +pub const D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES: UINT = 1024; +pub const D3D12_GS_OUTPUT_ELEMENTS: UINT = 32; +pub const D3D12_GS_OUTPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_GS_OUTPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_HS_CONTROL_POINT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_CONTROL_POINT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_CONTROL_POINT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND: UINT = 0xffffffff; +pub const D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND: UINT = 0xffffffff; +pub const D3D12_HS_MAXTESSFACTOR_LOWER_BOUND: FLOAT = 1.0; +pub const D3D12_HS_MAXTESSFACTOR_UPPER_BOUND: FLOAT = 64.0; +pub const D3D12_HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS: UINT = 3968; +pub const D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT: UINT = 1; +pub const D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT: UINT = 32; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS: UINT = 128; +pub const D3D12_IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES: UINT = 0; +pub const D3D12_IA_DEFAULT_PRIMITIVE_TOPOLOGY: UINT = 0; +pub const D3D12_IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES: UINT = 0; +pub const D3D12_IA_INDEX_INPUT_RESOURCE_SLOT_COUNT: UINT = 1; +pub const D3D12_IA_INSTANCE_ID_BIT_COUNT: UINT = 32; +pub const D3D12_IA_INTEGER_ARITHMETIC_BIT_COUNT: UINT = 32; +pub const D3D12_IA_PATCH_MAX_CONTROL_POINT_COUNT: UINT = 32; +pub const D3D12_IA_PRIMITIVE_ID_BIT_COUNT: UINT = 32; +pub const D3D12_IA_VERTEX_ID_BIT_COUNT: UINT = 32; +pub const D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT: UINT = 32; +pub const D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS: UINT = 128; +pub const D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT: UINT = 32; +pub const D3D12_INTEGER_DIVIDE_BY_ZERO_QUOTIENT: UINT = 0xffffffff; +pub const D3D12_INTEGER_DIVIDE_BY_ZERO_REMAINDER: UINT = 0xffffffff; +pub const D3D12_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL: UINT = 0xffffffff; +pub const D3D12_KEEP_UNORDERED_ACCESS_VIEWS: UINT = 0xffffffff; +pub const D3D12_LINEAR_GAMMA: FLOAT = 1.0; +pub const D3D12_MAJOR_VERSION: UINT = 12; +pub const D3D12_MAX_BORDER_COLOR_COMPONENT: FLOAT = 1.0; +pub const D3D12_MAX_DEPTH: FLOAT = 1.0; +pub const D3D12_MAX_LIVE_STATIC_SAMPLERS: UINT = 2032; +pub const D3D12_MAX_MAXANISOTROPY: UINT = 16; +pub const D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT: UINT = 32; +pub const D3D12_MAX_POSITION_VALUE: FLOAT = 3.402823466e+34; +pub const D3D12_MAX_ROOT_COST: UINT = 64; +pub const D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1: UINT = 1000000; +pub const D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2: UINT = 1000000; +pub const D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE: UINT = 2048; +pub const D3D12_MAX_TEXTURE_DIMENSION_2_TO_EXP: UINT = 17; +pub const D3D12_MINOR_VERSION: UINT = 0; +pub const D3D12_MIN_BORDER_COLOR_COMPONENT: FLOAT = 0.0; +pub const D3D12_MIN_DEPTH: FLOAT = 0.0; +pub const D3D12_MIN_MAXANISOTROPY: UINT = 0; +pub const D3D12_MIP_LOD_BIAS_MAX: FLOAT = 15.99; +pub const D3D12_MIP_LOD_BIAS_MIN: FLOAT = -16.0; +pub const D3D12_MIP_LOD_FRACTIONAL_BIT_COUNT: UINT = 8; +pub const D3D12_MIP_LOD_RANGE_BIT_COUNT: UINT = 8; +pub const D3D12_MULTISAMPLE_ANTIALIAS_LINE_WIDTH: FLOAT = 1.4; +pub const D3D12_NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT: UINT = 0; +pub const D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_END: UINT = 0xffffffff; +pub const D3D12_OS_RESERVED_REGISTER_SPACE_VALUES_START: UINT = 0xfffffff8; +pub const D3D12_PACKED_TILE: UINT = 0xffffffff; +pub const D3D12_PIXEL_ADDRESS_RANGE_BIT_COUNT: UINT = 15; +pub const D3D12_PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT: UINT = 16; +pub const D3D12_PS_CS_UAV_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_PS_CS_UAV_REGISTER_COUNT: UINT = 8; +pub const D3D12_PS_CS_UAV_REGISTER_READS_PER_INST: UINT = 1; +pub const D3D12_PS_CS_UAV_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_PS_FRONTFACING_DEFAULT_VALUE: UINT = 0xffffffff; +pub const D3D12_PS_FRONTFACING_FALSE_VALUE: UINT = 0; +pub const D3D12_PS_FRONTFACING_TRUE_VALUE: UINT = 0xffffffff; +pub const D3D12_PS_INPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_PS_INPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_PS_INPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_PS_INPUT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_PS_INPUT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT: FLOAT = 0.0; +pub const D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_PS_OUTPUT_DEPTH_REGISTER_COUNT: UINT = 1; +pub const D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENTS: UINT = 1; +pub const D3D12_PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_PS_OUTPUT_MASK_REGISTER_COUNT: UINT = 1; +pub const D3D12_PS_OUTPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_PS_OUTPUT_REGISTER_COUNT: UINT = 8; +pub const D3D12_PS_PIXEL_CENTER_FRACTIONAL_COMPONENT: FLOAT = 0.5; +pub const D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT: UINT = 16; +pub const D3D12_REQ_BLEND_OBJECT_COUNT_PER_DEVICE: UINT = 4096; +pub const D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP: UINT = 27; +pub const D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT: UINT = 4096; +pub const D3D12_REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE: UINT = 4096; +pub const D3D12_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP: UINT = 32; +pub const D3D12_REQ_DRAW_VERTEX_COUNT_2_TO_EXP: UINT = 32; +pub const D3D12_REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION: UINT = 16384; +pub const D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT: UINT = 1024; +pub const D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT: UINT = 4096; +pub const D3D12_REQ_MAXANISOTROPY: UINT = 16; +pub const D3D12_REQ_MIP_LEVELS: UINT = 15; +pub const D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES: UINT = 2048; +pub const D3D12_REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE: UINT = 4096; +pub const D3D12_REQ_RENDER_TO_BUFFER_WINDOW_WIDTH: UINT = 16384; +pub const D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM: UINT = 128; +pub const D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM: FLOAT = 0.25; +pub const D3D12_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM: UINT = 2048; +pub const D3D12_REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP: UINT = 20; +pub const D3D12_REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE: UINT = 4096; +pub const D3D12_REQ_SUBRESOURCES: UINT = 30720; +pub const D3D12_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION: UINT = 2048; +pub const D3D12_REQ_TEXTURE1D_U_DIMENSION: UINT = 16384; +pub const D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION: UINT = 2048; +pub const D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION: UINT = 16384; +pub const D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION: UINT = 2048; +pub const D3D12_REQ_TEXTURECUBE_DIMENSION: UINT = 16384; +pub const D3D12_RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL: UINT = 0; +pub const D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES: UINT = 0xffffffff; +pub const D3D12_SHADER_MAJOR_VERSION: UINT = 5; +pub const D3D12_SHADER_MAX_INSTANCES: UINT = 65535; +pub const D3D12_SHADER_MAX_INTERFACES: UINT = 253; +pub const D3D12_SHADER_MAX_INTERFACE_CALL_SITES: UINT = 4096; +pub const D3D12_SHADER_MAX_TYPES: UINT = 65535; +pub const D3D12_SHADER_MINOR_VERSION: UINT = 1; +pub const D3D12_SHIFT_INSTRUCTION_PAD_VALUE: UINT = 0; +pub const D3D12_SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT: UINT = 5; +pub const D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT: UINT = 8; +pub const D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT: UINT = 65536; +pub const D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT: UINT = 4096; +pub const D3D12_SO_BUFFER_MAX_STRIDE_IN_BYTES: UINT = 2048; +pub const D3D12_SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES: UINT = 512; +pub const D3D12_SO_BUFFER_SLOT_COUNT: UINT = 4; +pub const D3D12_SO_DDI_REGISTER_INDEX_DENOTING_GAP: UINT = 0xffffffff; +pub const D3D12_SO_NO_RASTERIZED_STREAM: UINT = 0xffffffff; +pub const D3D12_SO_OUTPUT_COMPONENT_COUNT: UINT = 128; +pub const D3D12_SO_STREAM_COUNT: UINT = 4; +pub const D3D12_SPEC_DATE_DAY: UINT = 14; +pub const D3D12_SPEC_DATE_MONTH: UINT = 11; +pub const D3D12_SPEC_DATE_YEAR: UINT = 2014; +pub const D3D12_SPEC_VERSION: FLOAT = 1.16; +pub const D3D12_SRGB_GAMMA: FLOAT = 2.2; +pub const D3D12_SRGB_TO_FLOAT_DENOMINATOR_1: FLOAT = 12.92; +pub const D3D12_SRGB_TO_FLOAT_DENOMINATOR_2: FLOAT = 1.055; +pub const D3D12_SRGB_TO_FLOAT_EXPONENT: FLOAT = 2.4; +pub const D3D12_SRGB_TO_FLOAT_OFFSET: FLOAT = 0.055; +pub const D3D12_SRGB_TO_FLOAT_THRESHOLD: FLOAT = 0.04045; +pub const D3D12_SRGB_TO_FLOAT_TOLERANCE_IN_ULP: FLOAT = 0.5; +pub const D3D12_STANDARD_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_STANDARD_COMPONENT_BIT_COUNT_DOUBLED: UINT = 64; +pub const D3D12_STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE: UINT = 4; +pub const D3D12_STANDARD_PIXEL_COMPONENT_COUNT: UINT = 128; +pub const D3D12_STANDARD_PIXEL_ELEMENT_COUNT: UINT = 32; +pub const D3D12_STANDARD_VECTOR_SIZE: UINT = 4; +pub const D3D12_STANDARD_VERTEX_ELEMENT_COUNT: UINT = 32; +pub const D3D12_STANDARD_VERTEX_TOTAL_COMPONENT_COUNT: UINT = 64; +pub const D3D12_SUBPIXEL_FRACTIONAL_BIT_COUNT: UINT = 8; +pub const D3D12_SUBTEXEL_FRACTIONAL_BIT_COUNT: UINT = 8; +pub const D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_END: UINT = 0xffffffff; +pub const D3D12_SYSTEM_RESERVED_REGISTER_SPACE_VALUES_START: UINT = 0xfffffff0; +pub const D3D12_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR: UINT = 64; +pub const D3D12_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR: UINT = 64; +pub const D3D12_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR: UINT = 63; +pub const D3D12_TESSELLATOR_MAX_TESSELLATION_FACTOR: UINT = 64; +pub const D3D12_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR: UINT = 2; +pub const D3D12_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR: UINT = 1; +pub const D3D12_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR: UINT = 1; +pub const D3D12_TEXEL_ADDRESS_RANGE_BIT_COUNT: UINT = 16; +pub const D3D12_TEXTURE_DATA_PITCH_ALIGNMENT: UINT = 256; +pub const D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT: UINT = 512; +pub const D3D12_TILED_RESOURCE_TILE_SIZE_IN_BYTES: UINT = 65536; +pub const D3D12_UAV_COUNTER_PLACEMENT_ALIGNMENT: UINT = 4096; +pub const D3D12_UAV_SLOT_COUNT: UINT = 64; +pub const D3D12_UNBOUND_MEMORY_ACCESS_RESULT: UINT = 0; +pub const D3D12_VIEWPORT_AND_SCISSORRECT_MAX_INDEX: UINT = 15; +pub const D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE: UINT = 16; +pub const D3D12_VIEWPORT_BOUNDS_MAX: INT = 32767; +pub const D3D12_VIEWPORT_BOUNDS_MIN: INT = -32768; +pub const D3D12_VS_INPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_VS_INPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_VS_INPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_VS_INPUT_REGISTER_READS_PER_INST: UINT = 2; +pub const D3D12_VS_INPUT_REGISTER_READ_PORTS: UINT = 1; +pub const D3D12_VS_OUTPUT_REGISTER_COMPONENTS: UINT = 4; +pub const D3D12_VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT: UINT = 32; +pub const D3D12_VS_OUTPUT_REGISTER_COUNT: UINT = 32; +pub const D3D12_WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT: UINT = 10; +pub const D3D12_WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP: UINT = 25; +pub const D3D12_WHQL_DRAW_VERTEX_COUNT_2_TO_EXP: UINT = 25; +pub type D3D12_GPU_VIRTUAL_ADDRESS = UINT64; +ENUM!{enum D3D12_COMMAND_LIST_TYPE { + D3D12_COMMAND_LIST_TYPE_DIRECT = 0, + D3D12_COMMAND_LIST_TYPE_BUNDLE = 1, + D3D12_COMMAND_LIST_TYPE_COMPUTE = 2, + D3D12_COMMAND_LIST_TYPE_COPY = 3, +}} +ENUM!{enum D3D12_COMMAND_QUEUE_FLAGS { + D3D12_COMMAND_QUEUE_FLAG_NONE = 0x0, + D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT = 0x1, +}} +ENUM!{enum D3D12_COMMAND_QUEUE_PRIORITY { + D3D12_COMMAND_QUEUE_PRIORITY_NORMAL = 0, + D3D12_COMMAND_QUEUE_PRIORITY_HIGH = 100, + D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME = 10000, +}} +STRUCT!{struct D3D12_COMMAND_QUEUE_DESC { + Type: D3D12_COMMAND_LIST_TYPE, + Priority: INT, + Flags: D3D12_COMMAND_QUEUE_FLAGS, + NodeMask: UINT, +}} +ENUM!{enum D3D12_PRIMITIVE_TOPOLOGY_TYPE { + D3D12_PRIMITIVE_TOPOLOGY_TYPE_UNDEFINED = 0, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT = 1, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE = 2, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE = 3, + D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH = 4, +}} +ENUM!{enum D3D12_INPUT_CLASSIFICATION { + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA = 0, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA = 1, +}} +STRUCT!{struct D3D12_INPUT_ELEMENT_DESC { + SemanticName: LPCSTR, + SemanticIndex: UINT, + Format: DXGI_FORMAT, + InputSlot: UINT, + AlignedByteOffset: UINT, + InputSlotClass: D3D12_INPUT_CLASSIFICATION, + InstanceDataStepRate: UINT, +}} +ENUM!{enum D3D12_FILL_MODE { + D3D12_FILL_MODE_WIREFRAME = 2, + D3D12_FILL_MODE_SOLID = 3, +}} +pub type D3D12_PRIMITIVE_TOPOLOGY = D3D_PRIMITIVE_TOPOLOGY; +pub type D3D12_PRIMITIVE = D3D_PRIMITIVE; +ENUM!{enum D3D12_CULL_MODE { + D3D12_CULL_MODE_NONE = 1, + D3D12_CULL_MODE_FRONT = 2, + D3D12_CULL_MODE_BACK = 3, +}} +STRUCT!{struct D3D12_SO_DECLARATION_ENTRY { + Stream: UINT, + SemanticName: LPCSTR, + SemanticIndex: UINT, + StartComponent: BYTE, + ComponentCount: BYTE, + OutputSlot: BYTE, +}} +STRUCT!{struct D3D12_VIEWPORT { + TopLeftX: FLOAT, + TopLeftY: FLOAT, + Width: FLOAT, + Height: FLOAT, + MinDepth: FLOAT, + MaxDepth: FLOAT, +}} +pub type D3D12_RECT = RECT; +STRUCT!{struct D3D12_BOX { + left: UINT, + top: UINT, + front: UINT, + right: UINT, + bottom: UINT, + back: UINT, +}} +ENUM!{enum D3D12_COMPARISON_FUNC { + D3D12_COMPARISON_FUNC_NEVER = 1, + D3D12_COMPARISON_FUNC_LESS = 2, + D3D12_COMPARISON_FUNC_EQUAL = 3, + D3D12_COMPARISON_FUNC_LESS_EQUAL = 4, + D3D12_COMPARISON_FUNC_GREATER = 5, + D3D12_COMPARISON_FUNC_NOT_EQUAL = 6, + D3D12_COMPARISON_FUNC_GREATER_EQUAL = 7, + D3D12_COMPARISON_FUNC_ALWAYS = 8, +}} +ENUM!{enum D3D12_DEPTH_WRITE_MASK { + D3D12_DEPTH_WRITE_MASK_ZERO = 0, + D3D12_DEPTH_WRITE_MASK_ALL = 1, +}} +ENUM!{enum D3D12_STENCIL_OP { + D3D12_STENCIL_OP_KEEP = 1, + D3D12_STENCIL_OP_ZERO = 2, + D3D12_STENCIL_OP_REPLACE = 3, + D3D12_STENCIL_OP_INCR_SAT = 4, + D3D12_STENCIL_OP_DECR_SAT = 5, + D3D12_STENCIL_OP_INVERT = 6, + D3D12_STENCIL_OP_INCR = 7, + D3D12_STENCIL_OP_DECR = 8, +}} +STRUCT!{struct D3D12_DEPTH_STENCILOP_DESC { + StencilFailOp: D3D12_STENCIL_OP, + StencilDepthFailOp: D3D12_STENCIL_OP, + StencilPassOp: D3D12_STENCIL_OP, + StencilFunc: D3D12_COMPARISON_FUNC, +}} +STRUCT!{struct D3D12_DEPTH_STENCIL_DESC { + DepthEnable: BOOL, + DepthWriteMask: D3D12_DEPTH_WRITE_MASK, + DepthFunc: D3D12_COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: UINT8, + StencilWriteMask: UINT8, + FrontFace: D3D12_DEPTH_STENCILOP_DESC, + BackFace: D3D12_DEPTH_STENCILOP_DESC, +}} +STRUCT!{struct D3D12_DEPTH_STENCIL_DESC1 { + DepthEnable: BOOL, + DepthWriteMask: D3D12_DEPTH_WRITE_MASK, + DepthFunc: D3D12_COMPARISON_FUNC, + StencilEnable: BOOL, + StencilReadMask: UINT8, + StencilWriteMask: UINT8, + FrontFace: D3D12_DEPTH_STENCILOP_DESC, + BackFace: D3D12_DEPTH_STENCILOP_DESC, + DepthBoundsTestEnable: BOOL, +}} +ENUM!{enum D3D12_BLEND { + D3D12_BLEND_ZERO = 1, + D3D12_BLEND_ONE = 2, + D3D12_BLEND_SRC_COLOR = 3, + D3D12_BLEND_INV_SRC_COLOR = 4, + D3D12_BLEND_SRC_ALPHA = 5, + D3D12_BLEND_INV_SRC_ALPHA = 6, + D3D12_BLEND_DEST_ALPHA = 7, + D3D12_BLEND_INV_DEST_ALPHA = 8, + D3D12_BLEND_DEST_COLOR = 9, + D3D12_BLEND_INV_DEST_COLOR = 10, + D3D12_BLEND_SRC_ALPHA_SAT = 11, + D3D12_BLEND_BLEND_FACTOR = 14, + D3D12_BLEND_INV_BLEND_FACTOR = 15, + D3D12_BLEND_SRC1_COLOR = 16, + D3D12_BLEND_INV_SRC1_COLOR = 17, + D3D12_BLEND_SRC1_ALPHA = 18, + D3D12_BLEND_INV_SRC1_ALPHA = 19, +}} +ENUM!{enum D3D12_BLEND_OP { + D3D12_BLEND_OP_ADD = 1, + D3D12_BLEND_OP_SUBTRACT = 2, + D3D12_BLEND_OP_REV_SUBTRACT = 3, + D3D12_BLEND_OP_MIN = 4, + D3D12_BLEND_OP_MAX = 5, +}} +ENUM!{enum D3D12_COLOR_WRITE_ENABLE { + D3D12_COLOR_WRITE_ENABLE_RED = 1, + D3D12_COLOR_WRITE_ENABLE_GREEN = 2, + D3D12_COLOR_WRITE_ENABLE_BLUE = 4, + D3D12_COLOR_WRITE_ENABLE_ALPHA = 8, + D3D12_COLOR_WRITE_ENABLE_ALL = D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN + | D3D12_COLOR_WRITE_ENABLE_BLUE | D3D12_COLOR_WRITE_ENABLE_ALPHA, +}} +ENUM!{enum D3D12_LOGIC_OP { + D3D12_LOGIC_OP_CLEAR = 0, + D3D12_LOGIC_OP_SET = 1, + D3D12_LOGIC_OP_COPY = 2, + D3D12_LOGIC_OP_COPY_INVERTED = 3, + D3D12_LOGIC_OP_NOOP = 4, + D3D12_LOGIC_OP_INVERT = 5, + D3D12_LOGIC_OP_AND = 6, + D3D12_LOGIC_OP_NAND = 7, + D3D12_LOGIC_OP_OR = 8, + D3D12_LOGIC_OP_NOR = 9, + D3D12_LOGIC_OP_XOR = 10, + D3D12_LOGIC_OP_EQUIV = 11, + D3D12_LOGIC_OP_AND_REVERSE = 12, + D3D12_LOGIC_OP_AND_INVERTED = 13, + D3D12_LOGIC_OP_OR_REVERSE = 14, + D3D12_LOGIC_OP_OR_INVERTED = 15, +}} +STRUCT!{struct D3D12_RENDER_TARGET_BLEND_DESC { + BlendEnable: BOOL, + LogicOpEnable: BOOL, + SrcBlend: D3D12_BLEND, + DestBlend: D3D12_BLEND, + BlendOp: D3D12_BLEND_OP, + SrcBlendAlpha: D3D12_BLEND, + DestBlendAlpha: D3D12_BLEND, + BlendOpAlpha: D3D12_BLEND_OP, + LogicOp: D3D12_LOGIC_OP, + RenderTargetWriteMask: UINT8, +}} +STRUCT!{struct D3D12_BLEND_DESC { + AlphaToCoverageEnable: BOOL, + IndependentBlendEnable: BOOL, + RenderTarget: [D3D12_RENDER_TARGET_BLEND_DESC; 8], +}} +ENUM!{enum D3D12_CONSERVATIVE_RASTERIZATION_MODE { + D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF = 0, + D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON = 1, +}} +STRUCT!{struct D3D12_RASTERIZER_DESC { + FillMode: D3D12_FILL_MODE, + CullMode: D3D12_CULL_MODE, + FrontCounterClockwise: BOOL, + DepthBias: INT, + DepthBiasClamp: FLOAT, + SlopeScaledDepthBias: FLOAT, + DepthClipEnable: BOOL, + MultisampleEnable: BOOL, + AntialiasedLineEnable: BOOL, + ForcedSampleCount: UINT, + ConservativeRaster: D3D12_CONSERVATIVE_RASTERIZATION_MODE, +}} +RIDL!{#[uuid(0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14)] +interface ID3D12RootSignature(ID3D12RootSignatureVtbl): + ID3D12DeviceChild(ID3D12DeviceChildVtbl) {}} +STRUCT!{struct D3D12_SHADER_BYTECODE { + pShaderBytecode: *const c_void, + BytecodeLength: SIZE_T, +}} +STRUCT!{struct D3D12_STREAM_OUTPUT_DESC { + pSODeclaration: *const D3D12_SO_DECLARATION_ENTRY, + NumEntries: UINT, + pBufferStrides: *const UINT, + NumStrides: UINT, + RasterizedStream: UINT, +}} +STRUCT!{struct D3D12_INPUT_LAYOUT_DESC { + pInputElementDescs: *const D3D12_INPUT_ELEMENT_DESC, + NumElements: UINT, +}} +ENUM!{enum D3D12_INDEX_BUFFER_STRIP_CUT_VALUE { + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED = 0, + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF = 1, + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF = 2, +}} +STRUCT!{struct D3D12_CACHED_PIPELINE_STATE { + pCachedBlob: *const c_void, + CachedBlobSizeInBytes: SIZE_T, +}} +ENUM!{enum D3D12_PIPELINE_STATE_FLAGS { + D3D12_PIPELINE_STATE_FLAG_NONE = 0, + D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG = 0x1, +}} +STRUCT!{struct D3D12_GRAPHICS_PIPELINE_STATE_DESC { + pRootSignature: *mut ID3D12RootSignature, + VS: D3D12_SHADER_BYTECODE, + PS: D3D12_SHADER_BYTECODE, + DS: D3D12_SHADER_BYTECODE, + HS: D3D12_SHADER_BYTECODE, + GS: D3D12_SHADER_BYTECODE, + StreamOutput: D3D12_STREAM_OUTPUT_DESC, + BlendState: D3D12_BLEND_DESC, + SampleMask: UINT, + RasterizerState: D3D12_RASTERIZER_DESC, + DepthStencilState: D3D12_DEPTH_STENCIL_DESC, + InputLayout: D3D12_INPUT_LAYOUT_DESC, + IBStripCutValue: D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, + PrimitiveTopologyType: D3D12_PRIMITIVE_TOPOLOGY_TYPE, + NumRenderTargets: UINT, + RTVFormats: [DXGI_FORMAT; 8], + DSVFormat: DXGI_FORMAT, + SampleDesc: DXGI_SAMPLE_DESC, + NodeMask: UINT, + CachedPSO: D3D12_CACHED_PIPELINE_STATE, + Flags: D3D12_PIPELINE_STATE_FLAGS, +}} +STRUCT!{struct D3D12_COMPUTE_PIPELINE_STATE_DESC { + pRootSignature: *mut ID3D12RootSignature, + CS: D3D12_SHADER_BYTECODE, + NodeMask: UINT, + CachedPSO: D3D12_CACHED_PIPELINE_STATE, + Flags: D3D12_PIPELINE_STATE_FLAGS, +}} +STRUCT!{struct D3D12_RT_FORMAT_ARRAY { + RTFormats: [DXGI_FORMAT; 8], + NumRenderTargets: UINT, +}} +STRUCT!{struct D3D12_PIPELINE_STATE_STREAM_DESC { + SizeInBytes: SIZE_T, + pPipelineStateSubobjectStream: *mut c_void, +}} +ENUM!{enum D3D12_PIPELINE_STATE_SUBOBJECT_TYPE { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE = 0, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS = 1, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS = 2, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS = 3, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS = 4, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS = 5, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS = 6, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT = 7, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND = 8, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK = 9, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER = 10, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL = 11, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT = 12, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE = 13, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY = 14, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS = 15, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT = 16, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC = 17, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK = 18, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO = 19, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS = 20, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1 = 21, + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MAX_VALID = 22, +}} +ENUM!{enum D3D12_FEATURE { + D3D12_FEATURE_D3D12_OPTIONS = 0, + D3D12_FEATURE_ARCHITECTURE = 1, + D3D12_FEATURE_FEATURE_LEVELS = 2, + D3D12_FEATURE_FORMAT_SUPPORT = 3, + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS = 4, + D3D12_FEATURE_FORMAT_INFO = 5, + D3D12_FEATURE_GPU_VIRTUAL_ADDRESS_SUPPORT = 6, + D3D12_FEATURE_SHADER_MODEL = 7, + D3D12_FEATURE_D3D12_OPTIONS1 = 8, + D3D12_FEATURE_ROOT_SIGNATURE = 12, + D3D12_FEATURE_ARCHITECTURE1 = 16, + D3D12_FEATURE_D3D12_OPTIONS2 = 18, + D3D12_FEATURE_SHADER_CACHE = 19, + D3D12_FEATURE_COMMAND_QUEUE_PRIORITY = 20, +}} +ENUM!{enum D3D12_SHADER_MIN_PRECISION_SUPPORT { + D3D12_SHADER_MIN_PRECISION_SUPPORT_NONE = 0, + D3D12_SHADER_MIN_PRECISION_SUPPORT_10_BIT = 0x1, + D3D12_SHADER_MIN_PRECISION_SUPPORT_16_BIT = 0x2, +}} +ENUM!{enum D3D12_TILED_RESOURCES_TIER { + D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED = 0, + D3D12_TILED_RESOURCES_TIER_1 = 1, + D3D12_TILED_RESOURCES_TIER_2 = 2, + D3D12_TILED_RESOURCES_TIER_3 = 3, +}} +ENUM!{enum D3D12_RESOURCE_BINDING_TIER { + D3D12_RESOURCE_BINDING_TIER_1 = 1, + D3D12_RESOURCE_BINDING_TIER_2 = 2, + D3D12_RESOURCE_BINDING_TIER_3 = 3, +}} +ENUM!{enum D3D12_CONSERVATIVE_RASTERIZATION_TIER { + D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED = 0, + D3D12_CONSERVATIVE_RASTERIZATION_TIER_1 = 1, + D3D12_CONSERVATIVE_RASTERIZATION_TIER_2 = 2, + D3D12_CONSERVATIVE_RASTERIZATION_TIER_3 = 3, +}} +ENUM!{enum D3D12_FORMAT_SUPPORT1 { + D3D12_FORMAT_SUPPORT1_NONE = 0, + D3D12_FORMAT_SUPPORT1_BUFFER = 0x1, + D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER = 0x2, + D3D12_FORMAT_SUPPORT1_IA_INDEX_BUFFER = 0x4, + D3D12_FORMAT_SUPPORT1_SO_BUFFER = 0x8, + D3D12_FORMAT_SUPPORT1_TEXTURE1D = 0x10, + D3D12_FORMAT_SUPPORT1_TEXTURE2D = 0x20, + D3D12_FORMAT_SUPPORT1_TEXTURE3D = 0x40, + D3D12_FORMAT_SUPPORT1_TEXTURECUBE = 0x80, + D3D12_FORMAT_SUPPORT1_SHADER_LOAD = 0x100, + D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE = 0x200, + D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON = 0x400, + D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_MONO_TEXT = 0x800, + D3D12_FORMAT_SUPPORT1_MIP = 0x1000, + D3D12_FORMAT_SUPPORT1_RENDER_TARGET = 0x4000, + D3D12_FORMAT_SUPPORT1_BLENDABLE = 0x8000, + D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL = 0x10000, + D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE = 0x40000, + D3D12_FORMAT_SUPPORT1_DISPLAY = 0x80000, + D3D12_FORMAT_SUPPORT1_CAST_WITHIN_BIT_LAYOUT = 0x100000, + D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RENDERTARGET = 0x200000, + D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD = 0x400000, + D3D12_FORMAT_SUPPORT1_SHADER_GATHER = 0x800000, + D3D12_FORMAT_SUPPORT1_BACK_BUFFER_CAST = 0x1000000, + D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW = 0x2000000, + D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON = 0x4000000, + D3D12_FORMAT_SUPPORT1_DECODER_OUTPUT = 0x8000000, + D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_OUTPUT = 0x10000000, + D3D12_FORMAT_SUPPORT1_VIDEO_PROCESSOR_INPUT = 0x20000000, + D3D12_FORMAT_SUPPORT1_VIDEO_ENCODER = 0x40000000, +}} +ENUM!{enum D3D12_FORMAT_SUPPORT2 { + D3D12_FORMAT_SUPPORT2_NONE = 0, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD = 0x1, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS = 0x2, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE = 0x4, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE = 0x8, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX = 0x10, + D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX = 0x20, + D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD = 0x40, + D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE = 0x80, + D3D12_FORMAT_SUPPORT2_OUTPUT_MERGER_LOGIC_OP = 0x100, + D3D12_FORMAT_SUPPORT2_TILED = 0x200, + D3D12_FORMAT_SUPPORT2_MULTIPLANE_OVERLAY = 0x4000, +}} +ENUM!{enum D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS { + D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE = 0, + D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_TILED_RESOURCE = 0x1, +}} +ENUM!{enum D3D12_CROSS_NODE_SHARING_TIER { + D3D12_CROSS_NODE_SHARING_TIER_NOT_SUPPORTED = 0, + D3D12_CROSS_NODE_SHARING_TIER_1_EMULATED = 1, + D3D12_CROSS_NODE_SHARING_TIER_1 = 2, + D3D12_CROSS_NODE_SHARING_TIER_2 = 3, +}} +ENUM!{enum D3D12_RESOURCE_HEAP_TIER { + D3D12_RESOURCE_HEAP_TIER_1 = 1, + D3D12_RESOURCE_HEAP_TIER_2 = 2, +}} +ENUM!{enum D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER { + D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED = 0, + D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_1 = 1, + D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_2 = 2, +}} +STRUCT!{struct D3D12_FEATURE_DATA_D3D12_OPTIONS { + DoublePrecisionFloatShaderOps: BOOL, + OutputMergerLogicOp: BOOL, + MinPrecisionSupport: D3D12_SHADER_MIN_PRECISION_SUPPORT, + TiledResourcesTier: D3D12_TILED_RESOURCES_TIER, + ResourceBindingTier: D3D12_RESOURCE_BINDING_TIER, + PSSpecifiedStencilRefSupported: BOOL, + TypedUAVLoadAdditionalFormats: BOOL, + ROVsSupported: BOOL, + ConservativeRasterizationTier: D3D12_CONSERVATIVE_RASTERIZATION_TIER, + MaxGPUVirtualAddressBitsPerResource: UINT, + StandardSwizzle64KBSupported: BOOL, + CrossNodeSharingTier: D3D12_CROSS_NODE_SHARING_TIER, + CrossAdapterRowMajorTextureSupported: BOOL, + VPAndRTArrayIndexFromAnyShaderFeedingRasterizerSupportedWithoutGSEmulation: BOOL, + ResourceHeapTier: D3D12_RESOURCE_HEAP_TIER, +}} +STRUCT!{struct D3D12_FEATURE_DATA_D3D12_OPTIONS1 { + WaveOps: BOOL, + WaveLaneCountMin: UINT, + WaveLaneCountMax: UINT, + TotalLaneCount: UINT, + ExpandedComputeResourceStates: BOOL, + Int64ShaderOps: BOOL, +}} +STRUCT!{struct D3D12_FEATURE_DATA_D3D12_OPTIONS2 { + DepthBoundsTestSupported: BOOL, + ProgrammableSamplePositionsTier: D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER, +}} +ENUM!{enum D3D_ROOT_SIGNATURE_VERSION { + D3D_ROOT_SIGNATURE_VERSION_1 = 0x1, + D3D_ROOT_SIGNATURE_VERSION_1_0 = 0x1, + D3D_ROOT_SIGNATURE_VERSION_1_1 = 0x2, +}} +STRUCT!{struct D3D12_FEATURE_DATA_ROOT_SIGNATURE { + HighestVersion: D3D_ROOT_SIGNATURE_VERSION, +}} +STRUCT!{struct D3D12_FEATURE_DATA_ARCHITECTURE { + NodeIndex: UINT, + TileBasedRenderer: BOOL, + UMA: BOOL, + CacheCoherentUMA: BOOL, +}} +STRUCT!{struct D3D12_FEATURE_DATA_ARCHITECTURE1 { + NodeIndex: UINT, + TileBasedRenderer: BOOL, + UMA: BOOL, + CacheCoherentUMA: BOOL, + IsolatedMMU: BOOL, +}} +STRUCT!{struct D3D12_FEATURE_DATA_FEATURE_LEVELS { + NumFeatureLevels: UINT, + pFeatureLevelsRequested: *const D3D_FEATURE_LEVEL, + MaxSupportedFeatureLevel: D3D_FEATURE_LEVEL, +}} +ENUM!{enum D3D_SHADER_MODEL { + D3D_SHADER_MODEL_5_1 = 0x51, + D3D_SHADER_MODEL_6_0 = 0x60, +}} +STRUCT!{struct D3D12_FEATURE_DATA_SHADER_MODEL { + HighestShaderModel: D3D_SHADER_MODEL, +}} +STRUCT!{struct D3D12_FEATURE_DATA_FORMAT_SUPPORT { + Format: DXGI_FORMAT, + Support1: D3D12_FORMAT_SUPPORT1, + Support2: D3D12_FORMAT_SUPPORT2, +}} +STRUCT!{struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS { + Format: DXGI_FORMAT, + SampleCount: UINT, + Flags: D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS, + NumQualityLevels: UINT, +}} +STRUCT!{struct D3D12_FEATURE_DATA_FORMAT_INFO { + Format: DXGI_FORMAT, + PlaneCount: UINT8, +}} +STRUCT!{struct D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT { + MaxGPUVirtualAddressBitsPerResource: UINT, + MaxGPUVirtualAddressBitsPerProcess: UINT, +}} +ENUM!{enum D3D12_SHADER_CACHE_SUPPORT_FLAGS { + D3D12_SHADER_CACHE_SUPPORT_NONE = 0, + D3D12_SHADER_CACHE_SUPPORT_SINGLE_PSO = 0x1, + D3D12_SHADER_CACHE_SUPPORT_LIBRARY = 0x2, + D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_INPROC_CACHE = 0x4, + D3D12_SHADER_CACHE_SUPPORT_AUTOMATIC_DISK_CACHE = 0x8, +}} +STRUCT!{struct D3D12_FEATURE_DATA_SHADER_CACHE { + SupportFlags: D3D12_SHADER_CACHE_SUPPORT_FLAGS, +}} +STRUCT!{struct D3D12_FEATURE_DATA_COMMAND_QUEUE_PRIORITY { + CommandListType: D3D12_COMMAND_LIST_TYPE, + Priority: UINT, + PriorityForTypeIsSupported: BOOL, +}} +STRUCT!{struct D3D12_RESOURCE_ALLOCATION_INFO { + SizeInBytes: UINT64, + Alignment: UINT64, +}} +ENUM!{enum D3D12_HEAP_TYPE { + D3D12_HEAP_TYPE_DEFAULT = 1, + D3D12_HEAP_TYPE_UPLOAD = 2, + D3D12_HEAP_TYPE_READBACK = 3, + D3D12_HEAP_TYPE_CUSTOM = 4, +}} +ENUM!{enum D3D12_CPU_PAGE_PROPERTY { + D3D12_CPU_PAGE_PROPERTY_UNKNOWN = 0, + D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE = 1, + D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE = 2, + D3D12_CPU_PAGE_PROPERTY_WRITE_BACK = 3, +}} +ENUM!{enum D3D12_MEMORY_POOL { + D3D12_MEMORY_POOL_UNKNOWN = 0, + D3D12_MEMORY_POOL_L0 = 1, + D3D12_MEMORY_POOL_L1 = 2, +}} +STRUCT!{struct D3D12_HEAP_PROPERTIES { + Type: D3D12_HEAP_TYPE, + CPUPageProperty: D3D12_CPU_PAGE_PROPERTY, + MemoryPoolPreference: D3D12_MEMORY_POOL, + CreationNodeMask: UINT, + VisibleNodeMask: UINT, +}} +ENUM!{enum D3D12_HEAP_FLAGS { + D3D12_HEAP_FLAG_NONE = 0, + D3D12_HEAP_FLAG_SHARED = 0x1, + D3D12_HEAP_FLAG_DENY_BUFFERS = 0x4, + D3D12_HEAP_FLAG_ALLOW_DISPLAY = 0x8, + D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER = 0x20, + D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES = 0x40, + D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES = 0x80, + D3D12_HEAP_FLAG_HARDWARE_PROTECTED = 0x100, + D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH = 0x200, + D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES = 0, + D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS = 0xc0, + D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES = 0x44, + D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES = 0x84, +}} +STRUCT!{struct D3D12_HEAP_DESC { + SizeInBytes: UINT64, + Properties: D3D12_HEAP_PROPERTIES, + Alignment: UINT64, + Flags: D3D12_HEAP_FLAGS, +}} +ENUM!{enum D3D12_RESOURCE_DIMENSION { + D3D12_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D12_RESOURCE_DIMENSION_BUFFER = 1, + D3D12_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D12_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D12_RESOURCE_DIMENSION_TEXTURE3D = 4, +}} +ENUM!{enum D3D12_TEXTURE_LAYOUT { + D3D12_TEXTURE_LAYOUT_UNKNOWN = 0, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR = 1, + D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE = 2, + D3D12_TEXTURE_LAYOUT_64KB_STANDARD_SWIZZLE = 3, +}} +ENUM!{enum D3D12_RESOURCE_FLAGS { + D3D12_RESOURCE_FLAG_NONE = 0, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET = 0x1, + D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL = 0x2, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS = 0x4, + D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE = 0x8, + D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER = 0x10, + D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS = 0x20, +}} +STRUCT!{struct D3D12_RESOURCE_DESC { + Dimension: D3D12_RESOURCE_DIMENSION, + Alignment: UINT64, + Width: UINT64, + Height: UINT, + DepthOrArraySize: UINT16, + MipLevels: UINT16, + Format: DXGI_FORMAT, + SampleDesc: DXGI_SAMPLE_DESC, + Layout: D3D12_TEXTURE_LAYOUT, + Flags: D3D12_RESOURCE_FLAGS, +}} +STRUCT!{struct D3D12_DEPTH_STENCIL_VALUE { + Depth: FLOAT, + Stencil: UINT8, +}} +UNION!{union D3D12_CLEAR_VALUE_u { + [u32; 4], + Color Color_mut: [FLOAT; 4], + DepthStencil DepthStencil_mut: D3D12_DEPTH_STENCIL_VALUE, +}} +STRUCT!{struct D3D12_CLEAR_VALUE { + Format: DXGI_FORMAT, + u: D3D12_CLEAR_VALUE_u, +}} +STRUCT!{struct D3D12_RANGE { + Begin: SIZE_T, + End: SIZE_T, +}} +STRUCT!{struct D3D12_RANGE_UINT64 { + Begin: UINT64, + End: UINT64, +}} +STRUCT!{struct D3D12_SUBRESOURCE_RANGE_UINT64 { + Subresource: UINT, + Range: D3D12_RANGE_UINT64, +}} +STRUCT!{struct D3D12_SUBRESOURCE_INFO { + Offset: UINT64, + RowPitch: UINT, + DepthPitch: UINT, +}} +STRUCT!{struct D3D12_TILED_RESOURCE_COORDINATE { + X: UINT, + Y: UINT, + Z: UINT, + Subresource: UINT, +}} +STRUCT!{struct D3D12_TILE_REGION_SIZE { + NumTiles: UINT, + UseBox: BOOL, + Width: UINT, + Height: UINT16, + Depth: UINT16, +}} +ENUM!{enum D3D12_TILE_RANGE_FLAGS { + D3D12_TILE_RANGE_FLAG_NONE = 0, + D3D12_TILE_RANGE_FLAG_NULL = 1, + D3D12_TILE_RANGE_FLAG_SKIP = 2, + D3D12_TILE_RANGE_FLAG_REUSE_SINGLE_TILE = 4, +}} +STRUCT!{struct D3D12_SUBRESOURCE_TILING { + WidthInTiles: UINT, + HeightInTiles: UINT16, + DepthInTiles: UINT16, + StartTileIndexInOverallResource: UINT, +}} +STRUCT!{struct D3D12_TILE_SHAPE { + WidthInTexels: UINT, + HeightInTexels: UINT, + DepthInTexels: UINT, +}} +STRUCT!{struct D3D12_PACKED_MIP_INFO { + NumStandardMips: UINT8, + NumPackedMips: UINT8, + NumTilesForPackedMips: UINT, + StartTileIndexInOverallResource: UINT, +}} +ENUM!{enum D3D12_TILE_MAPPING_FLAGS { + D3D12_TILE_MAPPING_FLAG_NONE = 0, + D3D12_TILE_MAPPING_FLAG_NO_HAZARD = 0x1, +}} +ENUM!{enum D3D12_TILE_COPY_FLAGS { + D3D12_TILE_COPY_FLAG_NONE = 0, + D3D12_TILE_COPY_FLAG_NO_HAZARD = 0x1, + D3D12_TILE_COPY_FLAG_LINEAR_BUFFER_TO_SWIZZLED_TILED_RESOURCE = 0x2, + D3D12_TILE_COPY_FLAG_SWIZZLED_TILED_RESOURCE_TO_LINEAR_BUFFER = 0x4, +}} +ENUM!{enum D3D12_RESOURCE_STATES { + D3D12_RESOURCE_STATE_COMMON = 0, + D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER = 0x1, + D3D12_RESOURCE_STATE_INDEX_BUFFER = 0x2, + D3D12_RESOURCE_STATE_RENDER_TARGET = 0x4, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS = 0x8, + D3D12_RESOURCE_STATE_DEPTH_WRITE = 0x10, + D3D12_RESOURCE_STATE_DEPTH_READ = 0x20, + D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE = 0x40, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE = 0x80, + D3D12_RESOURCE_STATE_STREAM_OUT = 0x100, + D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT = 0x200, + D3D12_RESOURCE_STATE_COPY_DEST = 0x400, + D3D12_RESOURCE_STATE_COPY_SOURCE = 0x800, + D3D12_RESOURCE_STATE_RESOLVE_DEST = 0x1000, + D3D12_RESOURCE_STATE_RESOLVE_SOURCE = 0x2000, + D3D12_RESOURCE_STATE_GENERIC_READ = 0x1 | 0x2 | 0x40 | 0x80 | 0x200 | 0x800, + D3D12_RESOURCE_STATE_PRESENT = 0, + D3D12_RESOURCE_STATE_PREDICATION = 0x200, +}} +ENUM!{enum D3D12_RESOURCE_BARRIER_TYPE { + D3D12_RESOURCE_BARRIER_TYPE_TRANSITION = 0, + D3D12_RESOURCE_BARRIER_TYPE_ALIASING = 1, + D3D12_RESOURCE_BARRIER_TYPE_UAV = 2, +}} +STRUCT!{struct D3D12_RESOURCE_TRANSITION_BARRIER { + pResource: *mut ID3D12Resource, + Subresource: UINT, + StateBefore: D3D12_RESOURCE_STATES, + StateAfter: D3D12_RESOURCE_STATES, +}} +STRUCT!{struct D3D12_RESOURCE_ALIASING_BARRIER { + pResourceBefore: *mut ID3D12Resource, + pResourceAfter: *mut ID3D12Resource, +}} +STRUCT!{struct D3D12_RESOURCE_UAV_BARRIER { + pResource: *mut ID3D12Resource, +}} +ENUM!{enum D3D12_RESOURCE_BARRIER_FLAGS { + D3D12_RESOURCE_BARRIER_FLAG_NONE = 0x0, + D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY = 0x1, + D3D12_RESOURCE_BARRIER_FLAG_END_ONLY = 0x2, +}} +UNION!{union D3D12_RESOURCE_BARRIER_u { + [u32; 4] [u64; 3], + Transition Transition_mut: D3D12_RESOURCE_TRANSITION_BARRIER, + Aliasing Aliasing_mut: D3D12_RESOURCE_ALIASING_BARRIER, + UAV UAV_mut: D3D12_RESOURCE_UAV_BARRIER, +}} +STRUCT!{struct D3D12_RESOURCE_BARRIER { + Type: D3D12_RESOURCE_BARRIER_TYPE, + Flags: D3D12_RESOURCE_BARRIER_FLAGS, + u: D3D12_RESOURCE_BARRIER_u, +}} +STRUCT!{struct D3D12_SUBRESOURCE_FOOTPRINT { + Format: DXGI_FORMAT, + Width: UINT, + Height: UINT, + Depth: UINT, + RowPitch: UINT, +}} +STRUCT!{struct D3D12_PLACED_SUBRESOURCE_FOOTPRINT { + Offset: UINT64, + Footprint: D3D12_SUBRESOURCE_FOOTPRINT, +}} +ENUM!{enum D3D12_TEXTURE_COPY_TYPE { + D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX = 0, + D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT = 1, +}} +UNION!{union D3D12_TEXTURE_COPY_LOCATION_u { + [u64; 4], + PlacedFootprint PlacedFootprint_mut: D3D12_PLACED_SUBRESOURCE_FOOTPRINT, + SubresourceIndex SubresourceIndex_mut: UINT, +}} +STRUCT!{struct D3D12_TEXTURE_COPY_LOCATION { + pResource: *mut ID3D12Resource, + Type: D3D12_TEXTURE_COPY_TYPE, + u: D3D12_TEXTURE_COPY_LOCATION_u, +}} +ENUM!{enum D3D12_RESOLVE_MODE { + D3D12_RESOLVE_MODE_DECOMPRESS = 0, + D3D12_RESOLVE_MODE_MIN = 1, + D3D12_RESOLVE_MODE_MAX = 2, + D3D12_RESOLVE_MODE_AVERAGE = 3, +}} +STRUCT!{struct D3D12_SAMPLE_POSITION { + X: INT8, + Y: INT8, +}} +ENUM!{enum D3D12_SHADER_COMPONENT_MAPPING { + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 = 0, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1 = 1, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2 = 2, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3 = 3, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0 = 4, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1 = 5, +}} +pub const D3D12_SHADER_COMPONENT_MAPPING_MASK: UINT = 0x7; +pub const D3D12_SHADER_COMPONENT_MAPPING_SHIFT: UINT = 3; +pub const D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES: UINT = 1 + << (D3D12_SHADER_COMPONENT_MAPPING_SHIFT * 4); +// D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING +// D3D12_DECODE_SHADER_4_COMPONENT_MAPPING +// D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING +ENUM!{enum D3D12_BUFFER_SRV_FLAGS { + D3D12_BUFFER_SRV_FLAG_NONE = 0x0, + D3D12_BUFFER_SRV_FLAG_RAW = 0x1, +}} +STRUCT!{struct D3D12_BUFFER_SRV { + FirstElement: UINT64, + NumElements: UINT, + StructureByteStride: UINT, + Flags: D3D12_BUFFER_SRV_FLAGS, +}} +STRUCT!{struct D3D12_TEX1D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEX1D_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEX2D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + PlaneSlice: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEX2D_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, + PlaneSlice: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEX3D_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEXCUBE_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEXCUBE_ARRAY_SRV { + MostDetailedMip: UINT, + MipLevels: UINT, + First2DArrayFace: UINT, + NumCubes: UINT, + ResourceMinLODClamp: FLOAT, +}} +STRUCT!{struct D3D12_TEX2DMS_SRV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D12_TEX2DMS_ARRAY_SRV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +ENUM!{enum D3D12_SRV_DIMENSION { + D3D12_SRV_DIMENSION_UNKNOWN = 0, + D3D12_SRV_DIMENSION_BUFFER = 1, + D3D12_SRV_DIMENSION_TEXTURE1D = 2, + D3D12_SRV_DIMENSION_TEXTURE1DARRAY = 3, + D3D12_SRV_DIMENSION_TEXTURE2D = 4, + D3D12_SRV_DIMENSION_TEXTURE2DARRAY = 5, + D3D12_SRV_DIMENSION_TEXTURE2DMS = 6, + D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY = 7, + D3D12_SRV_DIMENSION_TEXTURE3D = 8, + D3D12_SRV_DIMENSION_TEXTURECUBE = 9, + D3D12_SRV_DIMENSION_TEXTURECUBEARRAY = 10, +}} +UNION!{union D3D12_SHADER_RESOURCE_VIEW_DESC_u { + [u64; 3], + Buffer Buffer_mut: D3D12_BUFFER_SRV, + Texture1D Texture1D_mut: D3D12_TEX1D_SRV, + Texture1DArray Texture1DArray_mut: D3D12_TEX1D_ARRAY_SRV, + Texture2D Texture2D_mut: D3D12_TEX2D_SRV, + Texture2DArray Texture2DArray_mut: D3D12_TEX2D_ARRAY_SRV, + Texture2DMS Texture2DMS_mut: D3D12_TEX2DMS_SRV, + Texture2DMSArray Texture2DMSArray_mut: D3D12_TEX2DMS_ARRAY_SRV, + Texture3D Texture3D_mut: D3D12_TEX3D_SRV, + TextureCube TextureCube_mut: D3D12_TEXCUBE_SRV, + TextureCubeArray TextureCubeArray_mut: D3D12_TEXCUBE_ARRAY_SRV, +}} +STRUCT!{struct D3D12_SHADER_RESOURCE_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D12_SRV_DIMENSION, + Shader4ComponentMapping: UINT, + u: D3D12_SHADER_RESOURCE_VIEW_DESC_u, +}} +STRUCT!{struct D3D12_CONSTANT_BUFFER_VIEW_DESC { + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + SizeInBytes: UINT, +}} +ENUM!{enum D3D12_FILTER { + D3D12_FILTER_MIN_MAG_MIP_POINT = 0, + D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR = 0x1, + D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x4, + D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR = 0x5, + D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT = 0x10, + D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x11, + D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT = 0x14, + D3D12_FILTER_MIN_MAG_MIP_LINEAR = 0x15, + D3D12_FILTER_ANISOTROPIC = 0x55, + D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT = 0x80, + D3D12_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR = 0x81, + D3D12_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x84, + D3D12_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR = 0x85, + D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT = 0x90, + D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x91, + D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT = 0x94, + D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR = 0x95, + D3D12_FILTER_COMPARISON_ANISOTROPIC = 0xd5, + D3D12_FILTER_MINIMUM_MIN_MAG_MIP_POINT = 0x100, + D3D12_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x101, + D3D12_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x104, + D3D12_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x105, + D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x110, + D3D12_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x111, + D3D12_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x114, + D3D12_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR = 0x115, + D3D12_FILTER_MINIMUM_ANISOTROPIC = 0x155, + D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_POINT = 0x180, + D3D12_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR = 0x181, + D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT = 0x184, + D3D12_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR = 0x185, + D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT = 0x190, + D3D12_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR = 0x191, + D3D12_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT = 0x194, + D3D12_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR = 0x195, + D3D12_FILTER_MAXIMUM_ANISOTROPIC = 0x1d5, +}} +ENUM!{enum D3D12_FILTER_TYPE { + D3D12_FILTER_TYPE_POINT = 0, + D3D12_FILTER_TYPE_LINEAR = 1, +}} +ENUM!{enum D3D12_FILTER_REDUCTION_TYPE { + D3D12_FILTER_REDUCTION_TYPE_STANDARD = 0, + D3D12_FILTER_REDUCTION_TYPE_COMPARISON = 1, + D3D12_FILTER_REDUCTION_TYPE_MINIMUM = 2, + D3D12_FILTER_REDUCTION_TYPE_MAXIMUM = 3, +}} +pub const D3D12_FILTER_REDUCTION_TYPE_MASK: UINT = 0x3; +pub const D3D12_FILTER_REDUCTION_TYPE_SHIFT: UINT = 7; +pub const D3D12_FILTER_TYPE_MASK: UINT = 0x3; +pub const D3D12_MIN_FILTER_SHIFT: UINT = 4; +pub const D3D12_MAG_FILTER_SHIFT: UINT = 2; +pub const D3D12_MIP_FILTER_SHIFT: UINT = 0; +pub const D3D12_ANISOTROPIC_FILTERING_BIT: UINT = 0x40; +// D3D12_ENCODE_BASIC_FILTER +// D3D12_ENCODE_ANISOTROPIC_FILTER +// D3D12_DECODE_MIN_FILTER +// D3D12_DECODE_MAG_FILTER +// D3D12_DECODE_MIP_FILTER +// D3D12_DECODE_FILTER_REDUCTION +// D3D12_DECODE_IS_COMPARISON_FILTER +// D3D12_DECODE_IS_ANISOTROPIC_FILTER +ENUM!{enum D3D12_TEXTURE_ADDRESS_MODE { + D3D12_TEXTURE_ADDRESS_MODE_WRAP = 1, + D3D12_TEXTURE_ADDRESS_MODE_MIRROR = 2, + D3D12_TEXTURE_ADDRESS_MODE_CLAMP = 3, + D3D12_TEXTURE_ADDRESS_MODE_BORDER = 4, + D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE = 5, +}} +STRUCT!{struct D3D12_SAMPLER_DESC { + Filter: D3D12_FILTER, + AddressU: D3D12_TEXTURE_ADDRESS_MODE, + AddressV: D3D12_TEXTURE_ADDRESS_MODE, + AddressW: D3D12_TEXTURE_ADDRESS_MODE, + MipLODBias: FLOAT, + MaxAnisotropy: UINT, + ComparisonFunc: D3D12_COMPARISON_FUNC, + BorderColor: [FLOAT; 4], + MinLOD: FLOAT, + MaxLOD: FLOAT, +}} +ENUM!{enum D3D12_BUFFER_UAV_FLAGS { + D3D12_BUFFER_UAV_FLAG_NONE = 0, + D3D12_BUFFER_UAV_FLAG_RAW = 0x1, +}} +STRUCT!{struct D3D12_BUFFER_UAV { + FirstElement: UINT64, + NumElements: UINT, + StructureByteStride: UINT, + CounterOffsetInBytes: UINT64, + Flags: D3D12_BUFFER_UAV_FLAGS, +}} +STRUCT!{struct D3D12_TEX1D_UAV { + MipSlice: UINT, +}} +STRUCT!{struct D3D12_TEX1D_ARRAY_UAV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D12_TEX2D_UAV { + MipSlice: UINT, + PlaneSlice: UINT, +}} +STRUCT!{struct D3D12_TEX2D_ARRAY_UAV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, + PlaneSlice: UINT, +}} +STRUCT!{struct D3D12_TEX3D_UAV { + MipSlice: UINT, + FirstWSlice: UINT, + WSize: UINT, +}} +ENUM!{enum D3D12_UAV_DIMENSION { + D3D12_UAV_DIMENSION_UNKNOWN = 0, + D3D12_UAV_DIMENSION_BUFFER = 1, + D3D12_UAV_DIMENSION_TEXTURE1D = 2, + D3D12_UAV_DIMENSION_TEXTURE1DARRAY = 3, + D3D12_UAV_DIMENSION_TEXTURE2D = 4, + D3D12_UAV_DIMENSION_TEXTURE2DARRAY = 5, + D3D12_UAV_DIMENSION_TEXTURE3D = 8, +}} +UNION!{union D3D12_UNORDERED_ACCESS_VIEW_DESC_u { + [u64; 4], + Buffer Buffer_mut: D3D12_BUFFER_UAV, + Texture1D Texture1D_mut: D3D12_TEX1D_UAV, + Texture1DArray Texture1DArray_mut: D3D12_TEX1D_ARRAY_UAV, + Texture2D Texture2D_mut: D3D12_TEX2D_UAV, + Texture2DArray Texture2DArray_mut: D3D12_TEX2D_ARRAY_UAV, + Texture3D Texture3D_mut: D3D12_TEX3D_UAV, +}} +STRUCT!{struct D3D12_UNORDERED_ACCESS_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D12_UAV_DIMENSION, + u: D3D12_UNORDERED_ACCESS_VIEW_DESC_u, +}} +STRUCT!{struct D3D12_BUFFER_RTV { + FirstElement: UINT64, + NumElements: UINT, +}} +STRUCT!{struct D3D12_TEX1D_RTV { + MipSlice: UINT, +}} +STRUCT!{struct D3D12_TEX1D_ARRAY_RTV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D12_TEX2D_RTV { + MipSlice: UINT, + PlaneSlice: UINT, +}} +STRUCT!{struct D3D12_TEX2DMS_RTV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D12_TEX2D_ARRAY_RTV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, + PlaneSlice: UINT, +}} +STRUCT!{struct D3D12_TEX2DMS_ARRAY_RTV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D12_TEX3D_RTV { + MipSlice: UINT, + FirstWSlice: UINT, + WSize: UINT, +}} +ENUM!{enum D3D12_RTV_DIMENSION { + D3D12_RTV_DIMENSION_UNKNOWN = 0, + D3D12_RTV_DIMENSION_BUFFER = 1, + D3D12_RTV_DIMENSION_TEXTURE1D = 2, + D3D12_RTV_DIMENSION_TEXTURE1DARRAY = 3, + D3D12_RTV_DIMENSION_TEXTURE2D = 4, + D3D12_RTV_DIMENSION_TEXTURE2DARRAY = 5, + D3D12_RTV_DIMENSION_TEXTURE2DMS = 6, + D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY = 7, + D3D12_RTV_DIMENSION_TEXTURE3D = 8, +}} +UNION!{union D3D12_RENDER_TARGET_VIEW_DESC_u { + [u64; 2], + Buffer Buffer_mut: D3D12_BUFFER_RTV, + Texture1D Texture1D_mut: D3D12_TEX1D_RTV, + Texture1DArray Texture1DArray_mut: D3D12_TEX1D_ARRAY_RTV, + Texture2D Texture2D_mut: D3D12_TEX2D_RTV, + Texture2DArray Texture2DArray_mut: D3D12_TEX2D_ARRAY_RTV, + Texture2DMS Texture2DMS_mut: D3D12_TEX2DMS_RTV, + Texture2DMSArray Texture2DMSArray_mut: D3D12_TEX2DMS_ARRAY_RTV, + Texture3D Texture3D_mut: D3D12_TEX3D_RTV, +}} +STRUCT!{struct D3D12_RENDER_TARGET_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D12_RTV_DIMENSION, + u: D3D12_RENDER_TARGET_VIEW_DESC_u, +}} +STRUCT!{struct D3D12_TEX1D_DSV { + MipSlice: UINT, +}} +STRUCT!{struct D3D12_TEX1D_ARRAY_DSV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D12_TEX2D_DSV { + MipSlice: UINT, +}} +STRUCT!{struct D3D12_TEX2D_ARRAY_DSV { + MipSlice: UINT, + FirstArraySlice: UINT, + ArraySize: UINT, +}} +STRUCT!{struct D3D12_TEX2DMS_DSV { + UnusedField_NothingToDefine: UINT, +}} +STRUCT!{struct D3D12_TEX2DMS_ARRAY_DSV { + FirstArraySlice: UINT, + ArraySize: UINT, +}} +ENUM!{enum D3D12_DSV_FLAGS { + D3D12_DSV_FLAG_NONE = 0x0, + D3D12_DSV_FLAG_READ_ONLY_DEPTH = 0x1, + D3D12_DSV_FLAG_READ_ONLY_STENCIL = 0x2, +}} +ENUM!{enum D3D12_DSV_DIMENSION { + D3D12_DSV_DIMENSION_UNKNOWN = 0, + D3D12_DSV_DIMENSION_TEXTURE1D = 1, + D3D12_DSV_DIMENSION_TEXTURE1DARRAY = 2, + D3D12_DSV_DIMENSION_TEXTURE2D = 3, + D3D12_DSV_DIMENSION_TEXTURE2DARRAY = 4, + D3D12_DSV_DIMENSION_TEXTURE2DMS = 5, + D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY = 6, +}} +UNION!{union D3D12_DEPTH_STENCIL_VIEW_DESC_u { + [u32; 3], + Texture1D Texture1D_mut: D3D12_TEX1D_DSV, + Texture1DArray Texture1DArray_mut: D3D12_TEX1D_ARRAY_DSV, + Texture2D Texture2D_mut: D3D12_TEX2D_DSV, + Texture2DArray Texture2DArray_mut: D3D12_TEX2D_ARRAY_DSV, + Texture2DMS Texture2DMS_mut: D3D12_TEX2DMS_DSV, + Texture2DMSArray Texture2DMSArray_mut: D3D12_TEX2DMS_ARRAY_DSV, +}} +STRUCT!{struct D3D12_DEPTH_STENCIL_VIEW_DESC { + Format: DXGI_FORMAT, + ViewDimension: D3D12_DSV_DIMENSION, + Flags: D3D12_DSV_FLAGS, + u: D3D12_DEPTH_STENCIL_VIEW_DESC_u, +}} +ENUM!{enum D3D12_CLEAR_FLAGS { + D3D12_CLEAR_FLAG_DEPTH = 0x1, + D3D12_CLEAR_FLAG_STENCIL = 0x2, +}} +ENUM!{enum D3D12_FENCE_FLAGS { + D3D12_FENCE_FLAG_NONE = 0x0, + D3D12_FENCE_FLAG_SHARED = 0x1, + D3D12_FENCE_FLAG_SHARED_CROSS_ADAPTER = 0x2, +}} +ENUM!{enum D3D12_DESCRIPTOR_HEAP_TYPE { + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV = 0, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER = 1, + D3D12_DESCRIPTOR_HEAP_TYPE_RTV = 2, + D3D12_DESCRIPTOR_HEAP_TYPE_DSV = 3, + D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES = 4, +}} +ENUM!{enum D3D12_DESCRIPTOR_HEAP_FLAGS { + D3D12_DESCRIPTOR_HEAP_FLAG_NONE = 0x0, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE = 0x1, +}} +STRUCT!{struct D3D12_DESCRIPTOR_HEAP_DESC { + Type: D3D12_DESCRIPTOR_HEAP_TYPE, + NumDescriptors: UINT, + Flags: D3D12_DESCRIPTOR_HEAP_FLAGS, + NodeMask: UINT, +}} +ENUM!{enum D3D12_DESCRIPTOR_RANGE_TYPE { + D3D12_DESCRIPTOR_RANGE_TYPE_SRV = 0, + D3D12_DESCRIPTOR_RANGE_TYPE_UAV = 1, + D3D12_DESCRIPTOR_RANGE_TYPE_CBV = 2, + D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER = 3, +}} +STRUCT!{struct D3D12_DESCRIPTOR_RANGE { + RangeType: D3D12_DESCRIPTOR_RANGE_TYPE, + NumDescriptors: UINT, + BaseShaderRegister: UINT, + RegisterSpace: UINT, + OffsetInDescriptorsFromTableStart: UINT, +}} +STRUCT!{struct D3D12_ROOT_DESCRIPTOR_TABLE { + NumDescriptorRanges: UINT, + pDescriptorRanges: *const D3D12_DESCRIPTOR_RANGE, +}} +STRUCT!{struct D3D12_ROOT_CONSTANTS { + ShaderRegister: UINT, + RegisterSpace: UINT, + Num32BitValues: UINT, +}} +STRUCT!{struct D3D12_ROOT_DESCRIPTOR { + ShaderRegister: UINT, + RegisterSpace: UINT, +}} +ENUM!{enum D3D12_SHADER_VISIBILITY { + D3D12_SHADER_VISIBILITY_ALL = 0, + D3D12_SHADER_VISIBILITY_VERTEX = 1, + D3D12_SHADER_VISIBILITY_HULL = 2, + D3D12_SHADER_VISIBILITY_DOMAIN = 3, + D3D12_SHADER_VISIBILITY_GEOMETRY = 4, + D3D12_SHADER_VISIBILITY_PIXEL = 5, +}} +ENUM!{enum D3D12_ROOT_PARAMETER_TYPE { + D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE = 0, + D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS = 1, + D3D12_ROOT_PARAMETER_TYPE_CBV = 2, + D3D12_ROOT_PARAMETER_TYPE_SRV = 3, + D3D12_ROOT_PARAMETER_TYPE_UAV = 4, +}} +UNION!{union D3D12_ROOT_PARAMETER_u { + [u32; 3] [u64; 2], + DescriptorTable DescriptorTable_mut: D3D12_ROOT_DESCRIPTOR_TABLE, + Constants Constants_mut: D3D12_ROOT_CONSTANTS, + Descriptor Descriptor_mut: D3D12_ROOT_DESCRIPTOR, +}} +STRUCT!{struct D3D12_ROOT_PARAMETER { + ParameterType: D3D12_ROOT_PARAMETER_TYPE, + u: D3D12_ROOT_PARAMETER_u, + ShaderVisibility: D3D12_SHADER_VISIBILITY, +}} +ENUM!{enum D3D12_ROOT_SIGNATURE_FLAGS { + D3D12_ROOT_SIGNATURE_FLAG_NONE = 0x0, + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT = 0x1, + D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS = 0x2, + D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS = 0x4, + D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS = 0x8, + D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS = 0x10, + D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS = 0x20, + D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT = 0x40, +}} +ENUM!{enum D3D12_STATIC_BORDER_COLOR { + D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK = 0, + D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK = 1, + D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE = 2, +}} +STRUCT!{struct D3D12_STATIC_SAMPLER_DESC { + Filter: D3D12_FILTER, + AddressU: D3D12_TEXTURE_ADDRESS_MODE, + AddressV: D3D12_TEXTURE_ADDRESS_MODE, + AddressW: D3D12_TEXTURE_ADDRESS_MODE, + MipLODBias: FLOAT, + MaxAnisotropy: UINT, + ComparisonFunc: D3D12_COMPARISON_FUNC, + BorderColor: D3D12_STATIC_BORDER_COLOR, + MinLOD: FLOAT, + MaxLOD: FLOAT, + ShaderRegister: UINT, + RegisterSpace: UINT, + ShaderVisibility: D3D12_SHADER_VISIBILITY, +}} +STRUCT!{struct D3D12_ROOT_SIGNATURE_DESC { + NumParameters: UINT, + pParameters: *const D3D12_ROOT_PARAMETER, + NumStaticSamplers: UINT, + pStaticSamplers: *const D3D12_STATIC_SAMPLER_DESC, + Flags: D3D12_ROOT_SIGNATURE_FLAGS, +}} +ENUM!{enum D3D12_DESCRIPTOR_RANGE_FLAGS { + D3D12_DESCRIPTOR_RANGE_FLAG_NONE = 0, + D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE = 0x1, + D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE = 0x2, + D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4, + D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC = 0x8, +}} +STRUCT!{struct D3D12_DESCRIPTOR_RANGE1 { + RangeType: D3D12_DESCRIPTOR_RANGE_TYPE, + NumDescriptors: UINT, + BaseShaderRegister: UINT, + RegisterSpace: UINT, + Flags: D3D12_DESCRIPTOR_RANGE_FLAGS, + OffsetInDescriptorsFromTableStart: UINT, +}} +STRUCT!{struct D3D12_ROOT_DESCRIPTOR_TABLE1 { + NumDescriptorRanges: UINT, + pDescriptorRanges: *const D3D12_DESCRIPTOR_RANGE1, +}} +ENUM!{enum D3D12_ROOT_DESCRIPTOR_FLAGS { + D3D12_ROOT_DESCRIPTOR_FLAG_NONE = 0, + D3D12_ROOT_DESCRIPTOR_FLAG_DATA_VOLATILE = 0x2, + D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE = 0x4, + D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC = 0x8, +}} +STRUCT!{struct D3D12_ROOT_DESCRIPTOR1 { + ShaderRegister: UINT, + RegisterSpace: UINT, + Flags: D3D12_ROOT_DESCRIPTOR_FLAGS, +}} +UNION!{union D3D12_ROOT_PARAMETER1_u { + [u32; 3] [u64; 2], + DescriptorTable DescriptorTable_mut: D3D12_ROOT_DESCRIPTOR_TABLE1, + Constants Constants_mut: D3D12_ROOT_CONSTANTS, + Descriptor Descriptor_mut: D3D12_ROOT_DESCRIPTOR1, +}} +STRUCT!{struct D3D12_ROOT_PARAMETER1 { + ParameterType: D3D12_ROOT_PARAMETER_TYPE, + u: D3D12_ROOT_PARAMETER1_u, + ShaderVisibility: D3D12_SHADER_VISIBILITY, +}} +STRUCT!{struct D3D12_ROOT_SIGNATURE_DESC1 { + NumParameters: UINT, + pParameters: *const D3D12_ROOT_PARAMETER1, + NumStaticSamplers: UINT, + pStaticSamplers: *const D3D12_STATIC_SAMPLER_DESC, + Flags: D3D12_ROOT_SIGNATURE_FLAGS, +}} +UNION!{union D3D12_VERSIONED_ROOT_SIGNATURE_DESC_u { + [u32; 5] [u64; 5], + Desc_1_0 Desc_1_0_mut: D3D12_ROOT_SIGNATURE_DESC, + Desc_1_1 Desc_1_1_mut: D3D12_ROOT_SIGNATURE_DESC1, +}} +STRUCT!{struct D3D12_VERSIONED_ROOT_SIGNATURE_DESC { + Version: UINT, + u: D3D12_VERSIONED_ROOT_SIGNATURE_DESC_u, +}} +RIDL!{#[uuid(0x34ab647b, 0x3cc8, 0x46ac, 0x84, 0x1b, 0xc0, 0x96, 0x56, 0x45, 0xc0, 0x46)] +interface ID3D12RootSignatureDeserializer(ID3D12RootSignatureDeserializerVtbl): + IUnknown(IUnknownVtbl) { + fn GetRootSignatureDesc() -> *const D3D12_ROOT_SIGNATURE_DESC, +}} +RIDL!{#[uuid(0x7f91ce67, 0x090c, 0x4bb7, 0xb7, 0x8e, 0xed, 0x8f, 0xf2, 0xe3, 0x1d, 0xa0)] +interface ID3D12VersionedRootSignatureDeserializer(ID3D12VersionedRootSignatureDeserializerVtbl): + IUnknown(IUnknownVtbl) { + fn GetRootSignatureDescAtVersion( + convertToVersion: D3D_ROOT_SIGNATURE_VERSION, + ppDesc: *mut *mut D3D12_VERSIONED_ROOT_SIGNATURE_DESC, + ) -> HRESULT, + fn GetUnconvertedRootSignatureDesc() -> *const D3D12_VERSIONED_ROOT_SIGNATURE_DESC, +}} +FN!{stdcall PFN_D3D12_SERIALIZE_ROOT_SIGNATURE( + pRootSignature: *const D3D12_ROOT_SIGNATURE_DESC, + Version: D3D_ROOT_SIGNATURE_VERSION, + ppBlob: *mut *mut ID3DBlob, + ppErrorBlob: *mut *mut ID3DBlob, +) -> HRESULT} +extern "system" { + pub fn D3D12SerializeRootSignature( + pRootSignature: *const D3D12_ROOT_SIGNATURE_DESC, + Version: D3D_ROOT_SIGNATURE_VERSION, + ppBlob: *mut *mut ID3DBlob, + ppErrorBlob: *mut *mut ID3DBlob, + ) -> HRESULT; +} +FN!{stdcall PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER( + pSrcData: LPCVOID, + SrcDataSizeInBytes: SIZE_T, + pRootSignatureDeserializerInterface: REFIID, + ppRootSignatureDeserializer: *mut *mut c_void, +) -> HRESULT} +extern "system" { + pub fn D3D12CreateRootSignatureDeserializer( + pSrcData: LPCVOID, + SrcDataSizeInBytes: SIZE_T, + pRootSignatureDeserializerInterface: REFGUID, + ppRootSignatureDeserializer: *mut *mut c_void, + ) -> HRESULT; +} +FN!{stdcall PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE( + pRootSignature: *const D3D12_VERSIONED_ROOT_SIGNATURE_DESC, + ppBlob: *mut *mut ID3DBlob, + ppErrorBlob: *mut *mut ID3DBlob, +) -> HRESULT} +extern "system" { + pub fn D3D12SerializeVersionedRootSignature( + pRootSignature: *const D3D12_VERSIONED_ROOT_SIGNATURE_DESC, + ppBlob: *mut *mut ID3DBlob, + ppErrorBlob: *mut *mut ID3DBlob, + ) -> HRESULT; +} +FN!{stdcall PFN_D3D12_CREATE_VERSIONED_ROOT_SIGNATURE_DESERIALIZER( + pSrcData: LPCVOID, + SrcDataSizeInBytes: SIZE_T, + pRootSignatureDeserializerInterface: REFIID, + ppRootSignatureDeserializer: *mut *mut c_void, +) -> HRESULT} +extern "system" { + pub fn D3D12CreateVersionedRootSignatureDeserializer( + pSrcData: LPCVOID, + SrcDataSizeInBytes: SIZE_T, + pRootSignatureDeserializerInterface: REFIID, + ppRootSignatureDeserializer: *mut *mut c_void, + ) -> HRESULT; +} +STRUCT!{struct D3D12_CPU_DESCRIPTOR_HANDLE { + ptr: SIZE_T, +}} +STRUCT!{struct D3D12_GPU_DESCRIPTOR_HANDLE { + ptr: UINT64, +}} +STRUCT!{struct D3D12_DISCARD_REGION { + NumRects: UINT, + pRects: *const D3D12_RECT, + FirstSubresource: UINT, + NumSubresources: UINT, +}} +ENUM!{enum D3D12_QUERY_HEAP_TYPE { + D3D12_QUERY_HEAP_TYPE_OCCLUSION = 0, + D3D12_QUERY_HEAP_TYPE_TIMESTAMP = 1, + D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS = 2, + D3D12_QUERY_HEAP_TYPE_SO_STATISTICS = 3, +}} +STRUCT!{struct D3D12_QUERY_HEAP_DESC { + Type: D3D12_QUERY_HEAP_TYPE, + Count: UINT, + NodeMask: UINT, +}} +ENUM!{enum D3D12_QUERY_TYPE { + D3D12_QUERY_TYPE_OCCLUSION = 0, + D3D12_QUERY_TYPE_BINARY_OCCLUSION = 1, + D3D12_QUERY_TYPE_TIMESTAMP = 2, + D3D12_QUERY_TYPE_PIPELINE_STATISTICS = 3, + D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 = 4, + D3D12_QUERY_TYPE_SO_STATISTICS_STREAM1 = 5, + D3D12_QUERY_TYPE_SO_STATISTICS_STREAM2 = 6, + D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3 = 7, +}} +ENUM!{enum D3D12_PREDICATION_OP { + D3D12_PREDICATION_OP_EQUAL_ZERO = 0, + D3D12_PREDICATION_OP_NOT_EQUAL_ZERO = 1, +}} +STRUCT!{struct D3D12_QUERY_DATA_PIPELINE_STATISTICS { + IAVertices: UINT64, + IAPrimitives: UINT64, + VSInvocations: UINT64, + GSInvocations: UINT64, + GSPrimitives: UINT64, + CInvocations: UINT64, + CPrimitives: UINT64, + PSInvocations: UINT64, + HSInvocations: UINT64, + DSInvocations: UINT64, + CSInvocations: UINT64, +}} +STRUCT!{struct D3D12_QUERY_DATA_SO_STATISTICS { + NumPrimitivesWritten: UINT64, + PrimitivesStorageNeeded: UINT64, +}} +STRUCT!{struct D3D12_STREAM_OUTPUT_BUFFER_VIEW { + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + SizeInBytes: UINT64, + BufferFilledSizeLocation: D3D12_GPU_VIRTUAL_ADDRESS, +}} +STRUCT!{struct D3D12_DRAW_ARGUMENTS { + VertexCountPerInstance: UINT, + InstanceCount: UINT, + StartVertexLocation: UINT, + StartInstanceLocation: UINT, +}} +STRUCT!{struct D3D12_DRAW_INDEXED_ARGUMENTS { + IndexCountPerInstance: UINT, + InstanceCount: UINT, + StartIndexLocation: UINT, + BaseVertexLocation: INT, + StartInstanceLocation: UINT, +}} +STRUCT!{struct D3D12_DISPATCH_ARGUMENTS { + ThreadGroupCountX: UINT, + ThreadGroupCountY: UINT, + ThreadGroupCountZ: UINT, +}} +STRUCT!{struct D3D12_VERTEX_BUFFER_VIEW { + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + SizeInBytes: UINT, + StrideInBytes: UINT, +}} +STRUCT!{struct D3D12_INDEX_BUFFER_VIEW { + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + SizeInBytes: UINT, + Format: DXGI_FORMAT, +}} +ENUM!{enum D3D12_INDIRECT_ARGUMENT_TYPE { + D3D12_INDIRECT_ARGUMENT_TYPE_DRAW = 0, + D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED = 1, + D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH = 2, + D3D12_INDIRECT_ARGUMENT_TYPE_VERTEX_BUFFER_VIEW = 3, + D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW = 4, + D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT = 5, + D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT_BUFFER_VIEW = 6, + D3D12_INDIRECT_ARGUMENT_TYPE_SHADER_RESOURCE_VIEW = 7, + D3D12_INDIRECT_ARGUMENT_TYPE_UNORDERED_ACCESS_VIEW = 8, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC_VertexBuffer { + Slot: UINT, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC_Constant { + RootParameterIndex: UINT, + DestOffsetIn32BitValues: UINT, + Num32BitValuesToSet: UINT, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC_ConstantBufferView { + RootParameterIndex: UINT, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC_ShaderResourceView { + RootParameterIndex: UINT, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC_UnorderedAccessView { + RootParameterIndex: UINT, +}} +UNION!{union D3D12_INDIRECT_ARGUMENT_DESC_u { + [u32; 3], + VertexBuffer VertexBuffer_mut: D3D12_INDIRECT_ARGUMENT_DESC_VertexBuffer, + Constant Constant_mut: D3D12_INDIRECT_ARGUMENT_DESC_Constant, + ConstantBufferView ConstantBufferView_mut: D3D12_INDIRECT_ARGUMENT_DESC_ConstantBufferView, + ShaderResourceView ShaderResourceView_mut: D3D12_INDIRECT_ARGUMENT_DESC_ShaderResourceView, + UnorderedAccessView UnorderedAccessView_mut: D3D12_INDIRECT_ARGUMENT_DESC_UnorderedAccessView, +}} +STRUCT!{struct D3D12_INDIRECT_ARGUMENT_DESC { + Type: D3D12_INDIRECT_ARGUMENT_TYPE, + u: D3D12_INDIRECT_ARGUMENT_DESC_u, +}} +STRUCT!{struct D3D12_COMMAND_SIGNATURE_DESC { + ByteStride: UINT, + NumArgumentDescs: UINT, + pArgumentDescs: *const D3D12_INDIRECT_ARGUMENT_DESC, + NodeMask: UINT, +}} +RIDL!{#[uuid(0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8)] +interface ID3D12Object(ID3D12ObjectVtbl): IUnknown(IUnknownVtbl) { + fn GetPrivateData( + guid: REFGUID, + pDataSize: *mut UINT, + pData: *mut c_void, + ) -> HRESULT, + fn SetPrivateData( + guid: REFGUID, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn SetPrivateDataInterface( + guid: REFGUID, + pData: *const IUnknown, + ) -> HRESULT, + fn SetName( + Name: LPCWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x905db94b, 0xa00c, 0x4140, 0x9d, 0xf5, 0x2b, 0x64, 0xca, 0x9e, 0xa3, 0x57)] +interface ID3D12DeviceChild(ID3D12DeviceChildVtbl): ID3D12Object(ID3D12ObjectVtbl) { + fn GetDevice( + riid: REFIID, + ppvDevice: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x63ee58fb, 0x1268, 0x4835, 0x86, 0xda, 0xf0, 0x08, 0xce, 0x62, 0xf0, 0xd6)] +interface ID3D12Pageable(ID3D12PageableVtbl): ID3D12DeviceChild(ID3D12DeviceChildVtbl) {}} +RIDL!{#[uuid(0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3)] +interface ID3D12Heap(ID3D12HeapVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + #[fixme] fn GetDesc() -> D3D12_HEAP_DESC, +}} +RIDL!{#[uuid(0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad)] +interface ID3D12Resource(ID3D12ResourceVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + fn Map( + Subresource: UINT, + pReadRange: *const D3D12_RANGE, + ppData: *mut *mut c_void, + ) -> HRESULT, + fn Unmap( + Subresource: UINT, + pWrittenRange: *const D3D12_RANGE, + ) -> (), + #[fixme] fn GetDesc() -> D3D12_RESOURCE_DESC, + fn GetGPUVirtualAddress() -> D3D12_GPU_VIRTUAL_ADDRESS, + fn WriteToSubresource( + DstSubresource: UINT, + pDstBox: *const D3D12_BOX, + pSrcData: *const c_void, + SrcRowPitch: UINT, + SrcDepthPitch: UINT, + ) -> HRESULT, + fn ReadFromSubresource( + pDstData: *mut c_void, + DstRowPitch: UINT, + DstDepthPitch: UINT, + SrcSubresource: UINT, + pSrcBox: *const D3D12_BOX, + ) -> HRESULT, + fn GetHeapProperties( + pHeapProperties: *mut D3D12_HEAP_PROPERTIES, + pHeapFlags: *mut D3D12_HEAP_FLAGS, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24)] +interface ID3D12CommandAllocator(ID3D12CommandAllocatorVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + fn Reset() -> HRESULT, +}} +RIDL!{#[uuid(0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76)] +interface ID3D12Fence(ID3D12FenceVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + fn GetCompletedValue() -> UINT64, + fn SetEventOnCompletion( + Value: UINT64, + hEvent: HANDLE, + ) -> HRESULT, + fn Signal( + Value: UINT64, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45)] +interface ID3D12PipelineState(ID3D12PipelineStateVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + fn GetCachedBlob( + ppBlob: *mut *mut ID3DBlob, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51)] +interface ID3D12DescriptorHeap(ID3D12DescriptorHeapVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + #[fixme] fn GetDesc() -> D3D12_DESCRIPTOR_HEAP_DESC, + #[fixme] fn GetCPUDescriptorHandleForHeapStart() -> D3D12_CPU_DESCRIPTOR_HANDLE, + #[fixme] fn GetGPUDescriptorHandleForHeapStart() -> D3D12_GPU_DESCRIPTOR_HANDLE, +}} +RIDL!{#[uuid(0x0d9658ae, 0xed45, 0x469e, 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4)] +interface ID3D12QueryHeap(ID3D12QueryHeapVtbl): ID3D12Pageable(ID3D12PageableVtbl) {}} +RIDL!{#[uuid(0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1)] +interface ID3D12CommandSignature(ID3D12CommandSignatureVtbl): + ID3D12Pageable(ID3D12PageableVtbl) {}} +RIDL!{#[uuid(0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5)] +interface ID3D12CommandList(ID3D12CommandListVtbl): ID3D12DeviceChild(ID3D12DeviceChildVtbl) { + fn GetType() -> D3D12_COMMAND_LIST_TYPE, +}} +RIDL!{#[uuid(0x5b160d0f, 0xac1b, 0x4185, 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55)] +interface ID3D12GraphicsCommandList(ID3D12GraphicsCommandListVtbl): + ID3D12CommandList(ID3D12CommandListVtbl) { + fn Close() -> HRESULT, + fn Reset( + pAllocator: *mut ID3D12CommandAllocator, + pInitialState: *mut ID3D12PipelineState, + ) -> HRESULT, + fn ClearState( + pPipelineState: *mut ID3D12PipelineState, + ) -> (), + fn DrawInstanced( + VertexCountPerInstance: UINT, + InstanceCount: UINT, + StartVertexLocation: UINT, + StartInstanceLocation: UINT, + ) -> (), + fn DrawIndexedInstanced( + IndexCountPerInstance: UINT, + InstanceCount: UINT, + StartIndexLocation: UINT, + BaseVertexLocation: INT, + StartInstanceLocation: UINT, + ) -> (), + fn Dispatch( + ThreadGroupCountX: UINT, + ThreadGroupCountY: UINT, + ThreadGroupCountZ: UINT, + ) -> (), + fn CopyBufferRegion( + pDstBuffer: *mut ID3D12Resource, + DstOffset: UINT64, + pSrcBuffer: *mut ID3D12Resource, + SrcOffset: UINT64, + NumBytes: UINT64, + ) -> (), + fn CopyTextureRegion( + pDst: *const D3D12_TEXTURE_COPY_LOCATION, + DstX: UINT, + DstY: UINT, + DstZ: UINT, + pSrc: *const D3D12_TEXTURE_COPY_LOCATION, + pSrcBox: *const D3D12_BOX, + ) -> (), + fn CopyResource( + pDstResource: *mut ID3D12Resource, + pSrcResource: *mut ID3D12Resource, + ) -> (), + fn CopyTiles( + pTiledResource: *mut ID3D12Resource, + pTileRegionStartCoordinate: *const D3D12_TILED_RESOURCE_COORDINATE, + pTileRegionSize: *const D3D12_TILE_REGION_SIZE, + pBuffer: *mut ID3D12Resource, + BufferStartOffsetInBytes: UINT64, + Flags: D3D12_TILE_COPY_FLAGS, + ) -> (), + fn ResolveSubresource( + pDstResource: *mut ID3D12Resource, + DstSubresource: UINT, + pSrcResource: *mut ID3D12Resource, + SrcSubresource: UINT, + Format: DXGI_FORMAT, + ) -> (), + fn IASetPrimitiveTopology( + PrimitiveTopology: D3D12_PRIMITIVE_TOPOLOGY, + ) -> (), + fn RSSetViewports( + NumViewports: UINT, + pViewports: *const D3D12_VIEWPORT, + ) -> (), + fn RSSetScissorRects( + NumRects: UINT, + pRects: *const D3D12_RECT, + ) -> (), + fn OMSetBlendFactor( + BlendFactor: *const [FLOAT; 4], + ) -> (), + fn OMSetStencilRef( + StencilRef: UINT, + ) -> (), + fn SetPipelineState( + pPipelineState: *mut ID3D12PipelineState, + ) -> (), + fn ResourceBarrier( + NumBarriers: UINT, + pBarriers: *const D3D12_RESOURCE_BARRIER, + ) -> (), + fn ExecuteBundle( + pCommandList: *mut ID3D12GraphicsCommandList, + ) -> (), + fn SetDescriptorHeaps( + NumDescriptorHeaps: UINT, + ppDescriptorHeaps: *mut *mut ID3D12DescriptorHeap, + ) -> (), + fn SetComputeRootSignature( + pRootSignature: *mut ID3D12RootSignature, + ) -> (), + fn SetGraphicsRootSignature( + pRootSignature: *mut ID3D12RootSignature, + ) -> (), + fn SetComputeRootDescriptorTable( + RootParameterIndex: UINT, + BaseDescriptor: D3D12_GPU_DESCRIPTOR_HANDLE, + ) -> (), + fn SetGraphicsRootDescriptorTable( + RootParameterIndex: UINT, + BaseDescriptor: D3D12_GPU_DESCRIPTOR_HANDLE, + ) -> (), + fn SetComputeRoot32BitConstant( + RootParameterIndex: UINT, + SrcData: UINT, + DestOffsetIn32BitValues: UINT, + ) -> (), + fn SetGraphicsRoot32BitConstant( + RootParameterIndex: UINT, + SrcData: UINT, + DestOffsetIn32BitValues: UINT, + ) -> (), + fn SetComputeRoot32BitConstants( + RootParameterIndex: UINT, + Num32BitValuesToSet: UINT, + pSrcData: *const c_void, + DestOffsetIn32BitValues: UINT, + ) -> (), + fn SetGraphicsRoot32BitConstants( + RootParameterIndex: UINT, + Num32BitValuesToSet: UINT, + pSrcData: *const c_void, + DestOffsetIn32BitValues: UINT, + ) -> (), + fn SetComputeRootConstantBufferView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn SetGraphicsRootConstantBufferView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn SetComputeRootShaderResourceView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn SetGraphicsRootShaderResourceView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn SetComputeRootUnorderedAccessView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn SetGraphicsRootUnorderedAccessView( + RootParameterIndex: UINT, + BufferLocation: D3D12_GPU_VIRTUAL_ADDRESS, + ) -> (), + fn IASetIndexBuffer( + pView: *const D3D12_INDEX_BUFFER_VIEW, + ) -> (), + fn IASetVertexBuffers( + StartSlot: UINT, + NumViews: UINT, + pViews: *const D3D12_VERTEX_BUFFER_VIEW, + ) -> (), + fn SOSetTargets( + StartSlot: UINT, + NumViews: UINT, + pViews: *const D3D12_STREAM_OUTPUT_BUFFER_VIEW, + ) -> (), + fn OMSetRenderTargets( + NumRenderTargetDescriptors: UINT, + pRenderTargetDescriptors: *const D3D12_CPU_DESCRIPTOR_HANDLE, + RTsSingleHandleToDescriptorRange: BOOL, + pDepthStencilDescriptor: *const D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn ClearDepthStencilView( + DepthStencilView: D3D12_CPU_DESCRIPTOR_HANDLE, + ClearFlags: D3D12_CLEAR_FLAGS, + Depth: FLOAT, + Stencil: UINT8, + NumRects: UINT, + pRects: *const D3D12_RECT, + ) -> (), + fn ClearRenderTargetView( + RenderTargetView: D3D12_CPU_DESCRIPTOR_HANDLE, + ColorRGBA: *const [FLOAT; 4], + NumRects: UINT, + pRects: *const D3D12_RECT, + ) -> (), + fn ClearUnorderedAccessViewUint( + ViewGPUHandleInCurrentHeap: D3D12_GPU_DESCRIPTOR_HANDLE, + ViewCPUHandle: D3D12_CPU_DESCRIPTOR_HANDLE, + pResource: *mut ID3D12Resource, + Values: *const [UINT; 4], + NumRects: UINT, + pRects: *const D3D12_RECT, + ) -> (), + fn ClearUnorderedAccessViewFloat( + ViewGPUHandleInCurrentHeap: D3D12_GPU_DESCRIPTOR_HANDLE, + ViewCPUHandle: D3D12_CPU_DESCRIPTOR_HANDLE, + pResource: *mut ID3D12Resource, + Values: *const [FLOAT; 4], + NumRects: UINT, + pRects: *const D3D12_RECT, + ) -> (), + fn DiscardResource( + pResource: *mut ID3D12Resource, + pRegion: *const D3D12_DISCARD_REGION, + ) -> (), + fn BeginQuery( + pQueryHeap: *mut ID3D12QueryHeap, + Type: D3D12_QUERY_TYPE, + Index: UINT, + ) -> (), + fn EndQuery( + pQueryHeap: *mut ID3D12QueryHeap, + Type: D3D12_QUERY_TYPE, + Index: UINT, + ) -> (), + fn ResolveQueryData( + pQueryHeap: *mut ID3D12QueryHeap, + Type: D3D12_QUERY_TYPE, + StartIndex: UINT, + NumQueries: UINT, + pDestinationBuffer: *mut ID3D12Resource, + AlignedDestinationBufferOffset: UINT64, + ) -> (), + fn SetPredication( + pBuffer: *mut ID3D12Resource, + AlignedBufferOffset: UINT64, + Operation: D3D12_PREDICATION_OP, + ) -> (), + fn SetMarker( + Metadata: UINT, + pData: *const c_void, + Size: UINT, + ) -> (), + fn BeginEvent( + Metadata: UINT, + pData: *const c_void, + Size: UINT, + ) -> (), + fn EndEvent() -> (), + fn ExecuteIndirect( + pCommandSignature: *mut ID3D12CommandSignature, + MaxCommandCount: UINT, + pArgumentBuffer: *mut ID3D12Resource, + ArgumentBufferOffset: UINT64, + pCountBuffer: *mut ID3D12Resource, + CountBufferOffset: UINT64, + ) -> (), +}} +RIDL!{#[uuid(0x553103fb, 0x1fe7, 0x4557, 0xbb, 0x38, 0x94, 0x6d, 0x7d, 0x0e, 0x7c, 0xa7)] +interface ID3D12GraphicsCommandList1(ID3D12GraphicsCommandList1Vtbl): + ID3D12GraphicsCommandList(ID3D12GraphicsCommandListVtbl) { + fn AtomicCopyBufferUINT( + pDstBuffer: *mut ID3D12Resource, + DstOffset: UINT64, + pSrcBuffer: *mut ID3D12Resource, + SrcOffset: UINT64, + Dependencies: UINT, + ppDependentResources: *const *mut ID3D12Resource, + pDependentSubresourceRanges: *mut D3D12_SUBRESOURCE_RANGE_UINT64, + ) -> (), + fn AtomicCopyBufferUINT64( + pDstBuffer: *mut ID3D12Resource, + DstOffset: UINT64, + pSrcBuffer: *mut ID3D12Resource, + SrcOffset: UINT64, + Dependencies: UINT, + ppDependentResources: *const *mut ID3D12Resource, + pDependentSubresourceRanges: *mut D3D12_SUBRESOURCE_RANGE_UINT64, + ) -> (), + fn OMSetDepthBounds( + Min: FLOAT, + Max: FLOAT, + ) -> (), + fn SetSamplePositions( + NumSamplesPerPixel: UINT, + NumPixels: UINT, + pSamplePositions: *mut D3D12_SAMPLE_POSITION, + ) -> (), + fn ResolveSubresourceRegion( + pDstResource: *mut ID3D12Resource, + DstSubresource: UINT, + DstX: UINT, + DstY: UINT, + pSrcResource: *mut ID3D12Resource, + SrcSubresource: UINT, + pSrcRect: *mut D3D12_RECT, + Format: DXGI_FORMAT, + ResolveMode: D3D12_RESOLVE_MODE, + ) -> (), +}} +RIDL!{#[uuid(0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed)] +interface ID3D12CommandQueue(ID3D12CommandQueueVtbl): ID3D12Pageable(ID3D12PageableVtbl) { + fn UpdateTileMappings( + pResource: *mut ID3D12Resource, + NumResourceRegions: UINT, + pResourceRegionStartCoordinates: *const D3D12_TILED_RESOURCE_COORDINATE, + pResourceRegionSizes: *const D3D12_TILE_REGION_SIZE, + pHeap: *mut ID3D12Heap, + NumRanges: UINT, + pRangeFlags: *const D3D12_TILE_RANGE_FLAGS, + pHeapRangeStartOffsets: *const UINT, + pRangeTileCounts: *const UINT, + Flags: D3D12_TILE_MAPPING_FLAGS, + ) -> (), + fn CopyTileMappings( + pDstResource: *mut ID3D12Resource, + pDstRegionStartCoordinate: *const D3D12_TILED_RESOURCE_COORDINATE, + pSrcResource: *mut ID3D12Resource, + pSrcRegionStartCoordinate: *const D3D12_TILED_RESOURCE_COORDINATE, + pRegionSize: *const D3D12_TILE_REGION_SIZE, + Flags: D3D12_TILE_MAPPING_FLAGS, + ) -> (), + fn ExecuteCommandLists( + NumCommandLists: UINT, + ppCommandLists: *const *mut ID3D12CommandList, + ) -> (), + fn SetMarker( + Metadata: UINT, + pData: *const c_void, + Size: UINT, + ) -> (), + fn BeginEvent( + Metadata: UINT, + pData: *const c_void, + Size: UINT, + ) -> (), + fn EndEvent() -> (), + fn Signal( + pFence: *mut ID3D12Fence, + Value: UINT64, + ) -> HRESULT, + fn Wait( + pFence: *mut ID3D12Fence, + Value: UINT64, + ) -> HRESULT, + fn GetTimestampFrequency( + pFrequency: *mut UINT64, + ) -> HRESULT, + fn GetClockCalibration( + pGpuTimestamp: *mut UINT64, + pCpuTimestamp: *mut UINT64, + ) -> HRESULT, + #[fixme] fn GetDesc() -> D3D12_COMMAND_QUEUE_DESC, +}} +RIDL!{#[uuid(0x189819f1, 0x1db6, 0x4b57, 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7)] +interface ID3D12Device(ID3D12DeviceVtbl): ID3D12Object(ID3D12ObjectVtbl) { + fn GetNodeCount() -> UINT, + fn CreateCommandQueue( + pDesc: *const D3D12_COMMAND_QUEUE_DESC, + riid: REFGUID, + ppCommandQueue: *mut *mut c_void, + ) -> HRESULT, + fn CreateCommandAllocator( + type_: D3D12_COMMAND_LIST_TYPE, + riid: REFGUID, + ppCommandAllocator: *mut *mut c_void, + ) -> HRESULT, + fn CreateGraphicsPipelineState( + pDesc: *const D3D12_GRAPHICS_PIPELINE_STATE_DESC, + riid: REFGUID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, + fn CreateComputePipelineState( + pDesc: *const D3D12_COMPUTE_PIPELINE_STATE_DESC, + riid: REFGUID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, + fn CreateCommandList( + nodeMask: UINT, + type_: D3D12_COMMAND_LIST_TYPE, + pCommandAllocator: *mut ID3D12CommandAllocator, + pInitialState: *mut ID3D12PipelineState, + riid: REFGUID, + ppCommandList: *mut *mut c_void, + ) -> HRESULT, + fn CheckFeatureSupport( + Feature: D3D12_FEATURE, + pFeatureSupportData: *mut c_void, + FeatureSupportDataSize: UINT, + ) -> HRESULT, + fn CreateDescriptorHeap( + pDescriptorHeapDesc: *const D3D12_DESCRIPTOR_HEAP_DESC, + riid: REFGUID, + ppvHeap: *mut *mut c_void, + ) -> HRESULT, + fn GetDescriptorHandleIncrementSize( + DescriptorHeapType: D3D12_DESCRIPTOR_HEAP_TYPE, + ) -> UINT, + fn CreateRootSignature( + nodeMask: UINT, + pBlobWithRootSignature: *const c_void, + blobLengthInBytes: SIZE_T, + riid: REFGUID, + ppvRootSignature: *mut *mut c_void, + ) -> HRESULT, + fn CreateConstantBufferView( + pDesc: *const D3D12_CONSTANT_BUFFER_VIEW_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CreateShaderResourceView( + pResource: *mut ID3D12Resource, + pDesc: *const D3D12_SHADER_RESOURCE_VIEW_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CreateUnorderedAccessView( + pResource: *mut ID3D12Resource, + pCounterResource: *mut ID3D12Resource, + pDesc: *const D3D12_UNORDERED_ACCESS_VIEW_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CreateRenderTargetView( + pResource: *mut ID3D12Resource, + pDesc: *const D3D12_RENDER_TARGET_VIEW_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CreateDepthStencilView( + pResource: *mut ID3D12Resource, + pDesc: *const D3D12_DEPTH_STENCIL_VIEW_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CreateSampler( + pDesc: *const D3D12_SAMPLER_DESC, + DestDescriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> (), + fn CopyDescriptors( + NumDestDescriptorRanges: UINT, + pDestDescriptorRangeStarts: *const D3D12_CPU_DESCRIPTOR_HANDLE, + pDestDescriptorRangeSizes: *const UINT, + NumSrcDescriptorRanges: UINT, + pSrcDescriptorRangeStarts: *const D3D12_CPU_DESCRIPTOR_HANDLE, + pSrcDescriptorRangeSizes: *const UINT, + DescriptorHeapsType: D3D12_DESCRIPTOR_HEAP_TYPE, + ) -> (), + fn CopyDescriptorsSimple( + NumDescriptors: UINT, + DestDescriptorRangeStart: D3D12_CPU_DESCRIPTOR_HANDLE, + SrcDescriptorRangeStart: D3D12_CPU_DESCRIPTOR_HANDLE, + DescriptorHeapsType: D3D12_DESCRIPTOR_HEAP_TYPE, + ) -> (), + #[fixme] fn GetResourceAllocationInfo( + visibleMask: UINT, + numResourceDescs: UINT, + pResourceDescs: *const D3D12_RESOURCE_DESC, + ) -> D3D12_RESOURCE_ALLOCATION_INFO, + #[fixme] fn GetCustomHeapProperties( + nodeMask: UINT, + heapType: D3D12_HEAP_TYPE, + ) -> D3D12_HEAP_PROPERTIES, + fn CreateCommittedResource( + pHeapProperties: *const D3D12_HEAP_PROPERTIES, + HeapFlags: D3D12_HEAP_FLAGS, + pResourceDesc: *const D3D12_RESOURCE_DESC, + InitialResourceState: D3D12_RESOURCE_STATES, + pOptimizedClearValue: *const D3D12_CLEAR_VALUE, + riidResource: REFGUID, + ppvResource: *mut *mut c_void, + ) -> HRESULT, + fn CreateHeap( + pDesc: *const D3D12_HEAP_DESC, + riid: REFGUID, + ppvHeap: *mut *mut c_void, + ) -> HRESULT, + fn CreatePlacedResource( + pHeap: *mut ID3D12Heap, + HeapOffset: UINT64, + pDesc: *const D3D12_RESOURCE_DESC, + InitialState: D3D12_RESOURCE_STATES, + pOptimizedClearValue: *const D3D12_CLEAR_VALUE, + riid: REFGUID, + ppvResource: *mut *mut c_void, + ) -> HRESULT, + fn CreateReservedResource( + pDesc: *const D3D12_RESOURCE_DESC, + InitialState: D3D12_RESOURCE_STATES, + pOptimizedClearValue: *const D3D12_CLEAR_VALUE, + riid: REFGUID, + ppvResource: *mut *mut c_void, + ) -> HRESULT, + fn CreateSharedHandle( + pObject: *mut ID3D12DeviceChild, + pAttributes: *const SECURITY_ATTRIBUTES, + Access: DWORD, + Name: LPCWSTR, + pHandle: *mut HANDLE, + ) -> HRESULT, + fn OpenSharedHandle( + NTHandle: HANDLE, + riid: REFGUID, + ppvObj: *mut *mut c_void, + ) -> HRESULT, + fn OpenSharedHandleByName( + Name: LPCWSTR, + Access: DWORD, + pNTHandle: *mut HANDLE, + ) -> HRESULT, + fn MakeResident( + NumObjects: UINT, + ppObjects: *mut *mut ID3D12Pageable, + ) -> HRESULT, + fn Evict( + NumObjects: UINT, + ppObjects: *mut *mut ID3D12Pageable, + ) -> HRESULT, + fn CreateFence( + InitialValue: UINT64, + Flags: D3D12_FENCE_FLAGS, + riid: REFGUID, + ppFence: *mut *mut c_void, + ) -> HRESULT, + fn GetDeviceRemovedReason() -> HRESULT, + fn GetCopyableFootprints( + pResourceDesc: *const D3D12_RESOURCE_DESC, + FirstSubresource: UINT, + NumSubresources: UINT, + BaseOffset: UINT64, + pLayouts: *mut D3D12_PLACED_SUBRESOURCE_FOOTPRINT, + pNumRows: *mut UINT, + pRowSizeInBytes: *mut UINT64, + pTotalBytes: *mut UINT64, + ) -> (), + fn CreateQueryHeap( + pDesc: *const D3D12_QUERY_HEAP_DESC, + riid: REFGUID, + ppvHeap: *mut *mut c_void, + ) -> HRESULT, + fn SetStablePowerState( + Enable: BOOL, + ) -> HRESULT, + fn CreateCommandSignature( + pDesc: *const D3D12_COMMAND_SIGNATURE_DESC, + pRootSignature: *mut ID3D12RootSignature, + riid: REFGUID, + ppvCommandSignature: *mut *mut c_void, + ) -> HRESULT, + fn GetResourceTiling( + pTiledResource: *mut ID3D12Resource, + pNumTilesForEntireResource: *mut UINT, + pPackedMipDesc: *mut D3D12_PACKED_MIP_INFO, + pStandardTileShapeForNonPackedMips: *mut D3D12_TILE_SHAPE, + pNumSubresourceTilings: *mut UINT, + FirstSubresourceTilingToGet: UINT, + pSubresourceTilingsForNonPackedMips: *mut D3D12_SUBRESOURCE_TILING, + ) -> (), + #[fixme] fn GetAdapterLuid() -> LUID, +}} +RIDL!{#[uuid(0xc64226a8, 0x9201, 0x46af, 0xb4, 0xcc, 0x53, 0xfb, 0x9f, 0xf7, 0x41, 0x4f)] +interface ID3D12PipelineLibrary(ID3D12PipelineLibraryVtbl): + ID3D12DeviceChild(ID3D12DeviceChildVtbl) { + fn StorePipeline( + pName: LPCWSTR, + pPipeline: *mut ID3D12PipelineState, + ) -> HRESULT, + fn LoadGraphicsPipeline( + pName: LPCWSTR, + pDesc: *const D3D12_GRAPHICS_PIPELINE_STATE_DESC, + riid: REFIID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, + fn LoadComputePipeline( + pName: LPCWSTR, + pDesc: *const D3D12_COMPUTE_PIPELINE_STATE_DESC, + riid: REFIID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, + fn GetSerializedSize() -> SIZE_T, + fn Serialize( + pData: *mut c_void, + DataSizeInBytes: SIZE_T, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x80eabf42, 0x2568, 0x4e5e, 0xbd, 0x82, 0xc3, 0x7f, 0x86, 0x96, 0x1d, 0xc3)] +interface ID3D12PipelineLibrary1(ID3D12PipelineLibrary1Vtbl): + ID3D12PipelineLibrary(ID3D12PipelineLibraryVtbl) { + fn LoadPipeline( + pName: LPCWSTR, + pDesc: *const D3D12_PIPELINE_STATE_STREAM_DESC, + riid: REFIID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, +}} +ENUM!{enum D3D12_MULTIPLE_FENCE_WAIT_FLAGS { + D3D12_MULTIPLE_FENCE_WAIT_FLAG_NONE = 0, + D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY = 0x1, + D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL = 0, +}} +ENUM!{enum D3D12_RESIDENCY_PRIORITY { + D3D12_RESIDENCY_PRIORITY_MINIMUM = 0x28000000, + D3D12_RESIDENCY_PRIORITY_LOW = 0x50000000, + D3D12_RESIDENCY_PRIORITY_NORMAL = 0x78000000, + D3D12_RESIDENCY_PRIORITY_HIGH = 0xa0010000, + D3D12_RESIDENCY_PRIORITY_MAXIMUM = 0xc8000000, +}} +RIDL!{#[uuid(0x77acce80, 0x638e, 0x4e65, 0x88, 0x95, 0xc1, 0xf2, 0x33, 0x86, 0x86, 0x3e)] +interface ID3D12Device1(ID3D12Device1Vtbl): ID3D12Device(ID3D12DeviceVtbl) { + fn CreatePipelineLibrary( + pLibraryBlob: *const c_void, + BlobLength: SIZE_T, + riid: REFIID, + ppPipelineLibrary: *mut *mut c_void, + ) -> HRESULT, + fn SetEventOnMultipleFenceCompletion( + ppFences: *const *mut ID3D12Fence, + pFenceValues: *const UINT64, + NumFences: UINT, + Flags: D3D12_MULTIPLE_FENCE_WAIT_FLAGS, + hEvent: HANDLE, + ) -> HRESULT, + fn SetResidencyPriority( + NumObjects: UINT, + ppObjects: *const *mut ID3D12Pageable, + pPriorities: *const D3D12_RESIDENCY_PRIORITY, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x30baa41e, 0xb15b, 0x475c, 0xa0, 0xbb, 0x1a, 0xf5, 0xc5, 0xb6, 0x43, 0x28)] +interface ID3D12Device2(ID3D12Device2Vtbl): ID3D12Device1(ID3D12Device1Vtbl) { + fn CreatePipelineState( + pDesc: *const D3D12_PIPELINE_STATE_STREAM_DESC, + riid: REFIID, + ppPipelineState: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7071e1f0, 0xe84b, 0x4b33, 0x97, 0x4f, 0x12, 0xfa, 0x49, 0xde, 0x65, 0xc5)] +interface ID3D12Tools(ID3D12ToolsVtbl): IUnknown(IUnknownVtbl) { + fn EnableShaderInstrumentation( + bEnable: BOOL, + ) -> (), + fn ShaderInstrumentationEnabled() -> BOOL, +}} +STRUCT!{struct D3D12_SUBRESOURCE_DATA { + pData: *const c_void, + RowPitch: LONG_PTR, + SlicePitch: LONG_PTR, +}} +STRUCT!{struct D3D12_MEMCPY_DEST { + pData: *mut c_void, + RowPitch: SIZE_T, + SlicePitch: SIZE_T, +}} +FN!{stdcall PFN_D3D12_CREATE_DEVICE( + *mut IUnknown, + D3D_FEATURE_LEVEL, + REFIID, + *mut *mut c_void, +) -> HRESULT} +extern "system" { + pub fn D3D12CreateDevice( + pAdapter: *mut IUnknown, + MinimumFeatureLevel: D3D_FEATURE_LEVEL, + riid: REFGUID, + ppDevice: *mut *mut c_void, + ) -> HRESULT; +} +FN!{stdcall PFN_D3D12_GET_DEBUG_INTERFACE( + REFIID, + *mut *mut c_void, +) -> HRESULT} +extern "system" { + pub fn D3D12GetDebugInterface( + riid: REFGUID, + ppvDebug: *mut *mut c_void, + ) -> HRESULT; + pub fn D3D12EnableExperimentalFeatures( + NumFeatures: UINT, + pIIDs: *const IID, + pConfigurationStructs: *mut c_void, + pConfigurationStructSizes: *mut UINT, + ) -> HRESULT; +} +DEFINE_GUID!{IID_ID3D12Object, + 0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8} +DEFINE_GUID!{IID_ID3D12DeviceChild, + 0x905db94b, 0xa00c, 0x4140, 0x9d, 0xf5, 0x2b, 0x64, 0xca, 0x9e, 0xa3, 0x57} +DEFINE_GUID!{IID_ID3D12RootSignature, + 0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14} +DEFINE_GUID!{IID_ID3D12RootSignatureDeserializer, + 0x34AB647B, 0x3CC8, 0x46AC, 0x84, 0x1B, 0xC0, 0x96, 0x56, 0x45, 0xC0, 0x46} +DEFINE_GUID!{IID_ID3D12VersionedRootSignatureDeserializer, + 0x7F91CE67, 0x090C, 0x4BB7, 0xB7, 0x8E, 0xED, 0x8F, 0xF2, 0xE3, 0x1D, 0xA0} +DEFINE_GUID!{IID_ID3D12Pageable, + 0x63ee58fb, 0x1268, 0x4835, 0x86, 0xda, 0xf0, 0x08, 0xce, 0x62, 0xf0, 0xd6} +DEFINE_GUID!{IID_ID3D12Heap, + 0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3} +DEFINE_GUID!{IID_ID3D12Resource, + 0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad} +DEFINE_GUID!{IID_ID3D12CommandAllocator, + 0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24} +DEFINE_GUID!{IID_ID3D12Fence, + 0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76} +DEFINE_GUID!{IID_ID3D12PipelineState, + 0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45} +DEFINE_GUID!{IID_ID3D12DescriptorHeap, + 0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51} +DEFINE_GUID!{IID_ID3D12QueryHeap, + 0x0d9658ae, 0xed45, 0x469e, 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4} +DEFINE_GUID!{IID_ID3D12CommandSignature, + 0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1} +DEFINE_GUID!{IID_ID3D12CommandList, + 0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5} +DEFINE_GUID!{IID_ID3D12GraphicsCommandList, + 0x5b160d0f, 0xac1b, 0x4185, 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55} +DEFINE_GUID!{IID_ID3D12GraphicsCommandList1, + 0x553103fb, 0x1fe7, 0x4557, 0xbb, 0x38, 0x94, 0x6d, 0x7d, 0x0e, 0x7c, 0xa7} +DEFINE_GUID!{IID_ID3D12CommandQueue, + 0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed} +DEFINE_GUID!{IID_ID3D12Device, + 0x189819f1, 0x1db6, 0x4b57, 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7} +DEFINE_GUID!{IID_ID3D12PipelineLibrary, + 0xc64226a8, 0x9201, 0x46af, 0xb4, 0xcc, 0x53, 0xfb, 0x9f, 0xf7, 0x41, 0x4f} +DEFINE_GUID!{IID_ID3D12PipelineLibrary1, + 0x80eabf42, 0x2568, 0x4e5e, 0xbd, 0x82, 0xc3, 0x7f, 0x86, 0x96, 0x1d, 0xc3} +DEFINE_GUID!{IID_ID3D12Device1, + 0x77acce80, 0x638e, 0x4e65, 0x88, 0x95, 0xc1, 0xf2, 0x33, 0x86, 0x86, 0x3e} +DEFINE_GUID!{IID_ID3D12Device2, + 0x30baa41e, 0xb15b, 0x475c, 0xa0, 0xbb, 0x1a, 0xf5, 0xc5, 0xb6, 0x43, 0x28} +DEFINE_GUID!{IID_ID3D12Tools, + 0x7071e1f0, 0xe84b, 0x4b33, 0x97, 0x4f, 0x12, 0xfa, 0x49, 0xde, 0x65, 0xc5} diff --git a/winapi/src/um/d3d12sdklayers.rs b/winapi/src/um/d3d12sdklayers.rs new file mode 100644 index 000000000..bb9535ccf --- /dev/null +++ b/winapi/src/um/d3d12sdklayers.rs @@ -0,0 +1,1364 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, c_void}; +use shared::basetsd::{SIZE_T, UINT64}; +use shared::minwindef::{BOOL, FLOAT, UINT}; +use um::d3d12::ID3D12Resource; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +RIDL!{#[uuid(0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0)] +interface ID3D12Debug(ID3D12DebugVtbl): IUnknown(IUnknownVtbl) { + fn EnableDebugLayer() -> (), +}} +RIDL!{#[uuid(0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04)] +interface ID3D12Debug1(ID3D12Debug1Vtbl): IUnknown(IUnknownVtbl) { + fn EnableDebugLayer() -> (), + fn SetEnableGPUBasedValidation( + Enable: BOOL, + ) -> (), + fn SetEnableSynchronizedCommandQueueValidation( + Enable: BOOL, + ) -> (), +}} +ENUM!{enum D3D12_GPU_BASED_VALIDATION_FLAGS { + D3D12_GPU_BASED_VALIDATION_FLAGS_NONE = 0, + D3D12_GPU_BASED_VALIDATION_FLAGS_DISABLE_STATE_TRACKING = 0x01, +}} +RIDL!{#[uuid(0x93a665c4, 0xa3b2, 0x4e5d, 0xb6, 0x92, 0xa2, 0x6a, 0xe1, 0x4e, 0x33, 0x74)] +interface ID3D12Debug2(ID3D12Debug2Vtbl): IUnknown(IUnknownVtbl) { + fn SetGPUBasedValidationFlags( + Flags: D3D12_GPU_BASED_VALIDATION_FLAGS, + ) -> (), +}} +ENUM!{enum D3D12_RLDO_FLAGS { + D3D12_RLDO_NONE = 0, + D3D12_RLDO_SUMMARY = 0x1, + D3D12_RLDO_DETAIL = 0x2, + D3D12_RLDO_IGNORE_INTERNAL = 0x4, +}} +ENUM!{enum D3D12_DEBUG_DEVICE_PARAMETER_TYPE { + D3D12_DEBUG_DEVICE_PARAMETER_FEATURE_FLAGS = 0, + D3D12_DEBUG_DEVICE_PARAMETER_GPU_BASED_VALIDATION_SETTINGS = 1, + D3D12_DEBUG_DEVICE_PARAMETER_GPU_SLOWDOWN_PERFORMANCE_FACTOR = 2, +}} +ENUM!{enum D3D12_DEBUG_FEATURE { + D3D12_DEBUG_FEATURE_NONE = 0, + D3D12_DEBUG_FEATURE_TREAT_BUNDLE_AS_DRAW = 0x1, + D3D12_DEBUG_FEATURE_TREAT_BUNDLE_AS_DISPATCH = 0x2, + D3D12_DEBUG_FEATURE_DISABLE_VIRTUALIZED_BUNDLES_VALIDATION = 0x04, + D3D12_DEBUG_FEATURE_VALID_MASK = 0x7, +}} +ENUM!{enum D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE { + D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE_NONE = 0, + D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE_STATE_TRACKING_ONLY = 1, + D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE_UNGUARDED_VALIDATION = 2, + D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE_GUARDED_VALIDATION = 3, + NUM_D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODES = 4, +}} +ENUM!{enum D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAGS { + D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_NONE = 0, + D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_TRACKING_ONLY_SHADERS + = 0x01, + D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_UNGUARDED_VALIDATION_SHADERS = 0x02, + D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAG_FRONT_LOAD_CREATE_GUARDED_VALIDATION_SHADERS = 0x04, + D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAGS_VALID_MASK = 0x07, +}} +STRUCT!{struct D3D12_DEBUG_DEVICE_GPU_BASED_VALIDATION_SETTINGS { + MaxMessagesPerCommandList: UINT, + DefaultShaderPatchMode: D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE, + PipelineStateCreateFlags: D3D12_GPU_BASED_VALIDATION_PIPELINE_STATE_CREATE_FLAGS, +}} +STRUCT!{struct D3D12_DEBUG_DEVICE_GPU_SLOWDOWN_PERFORMANCE_FACTOR { + SlowdownFactor: FLOAT, +}} +RIDL!{#[uuid(0x3febd6dd, 0x4973, 0x4787, 0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e)] +interface ID3D12DebugDevice1(ID3D12DebugDevice1Vtbl): IUnknown(IUnknownVtbl) { + fn SetDebugParameter( + Type: D3D12_DEBUG_COMMAND_LIST_PARAMETER_TYPE, + pData: *const c_void, + DataSize: UINT, + ) -> HRESULT, + fn GetDebugParameter( + Type: D3D12_DEBUG_COMMAND_LIST_PARAMETER_TYPE, + pData: *mut c_void, + DataSize: UINT, + ) -> HRESULT, + fn ReportLiveDeviceObjects( + Flags: D3D12_RLDO_FLAGS, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3febd6dd, 0x4973, 0x4787, 0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e)] +interface ID3D12DebugDevice(ID3D12DebugDeviceVtbl): IUnknown(IUnknownVtbl) { + fn SetFeatureMask( + Mask: D3D12_DEBUG_FEATURE, + ) -> HRESULT, + fn GetFeatureMask() -> D3D12_DEBUG_FEATURE, + fn ReportLiveDeviceObjects( + Flags: D3D12_RLDO_FLAGS, + ) -> HRESULT, +}} +DEFINE_GUID!{DXGI_DEBUG_D3D12, + 0xcf59a98c, 0xa950, 0x4326, 0x91, 0xef, 0x9b, 0xba, 0xa1, 0x7b, 0xfd, 0x95} +RIDL!{#[uuid(0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3a)] +interface ID3D12DebugCommandQueue(ID3D12DebugCommandQueueVtbl): IUnknown(IUnknownVtbl) { + fn AssertResourceState( + pResource: *mut ID3D12Resource, + Subresource: UINT, + State: UINT, + ) -> BOOL, +}} +ENUM!{enum D3D12_DEBUG_COMMAND_LIST_PARAMETER_TYPE { + D3D12_DEBUG_COMMAND_LIST_PARAMETER_GPU_BASED_VALIDATION_SETTINGS = 0, +}} +STRUCT!{struct D3D12_DEBUG_COMMAND_LIST_GPU_BASED_VALIDATION_SETTINGS { + ShaderPatchMode: D3D12_GPU_BASED_VALIDATION_SHADER_PATCH_MODE, +}} +RIDL!{#[uuid(0x102ca951, 0x311b, 0x4b01, 0xb1, 0x1f, 0xec, 0xb8, 0x3e, 0x06, 0x1b, 0x37)] +interface ID3D12DebugCommandList1(ID3D12DebugCommandList1Vtbl): IUnknown(IUnknownVtbl) { + fn AssertResourceState( + pResource: *mut ID3D12Resource, + Subresource: UINT, + State: UINT, + ) -> BOOL, + fn SetDebugParameter( + Type: D3D12_DEBUG_COMMAND_LIST_PARAMETER_TYPE, + pData: *const c_void, + DataSize: UINT, + ) -> HRESULT, + fn GetDebugParameter( + Type: D3D12_DEBUG_COMMAND_LIST_PARAMETER_TYPE, + pData: *mut c_void, + DataSize: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3f)] +interface ID3D12DebugCommandList(ID3D12DebugCommandListVtbl): IUnknown(IUnknownVtbl) { + fn AssertResourceState( + pResource: *mut ID3D12Resource, + Subresource: UINT, + State: UINT, + ) -> BOOL, + fn SetFeatureMask( + Mask: D3D12_DEBUG_FEATURE, + ) -> HRESULT, + fn GetFeatureMask() -> D3D12_DEBUG_FEATURE, +}} +ENUM!{enum D3D12_MESSAGE_CATEGORY { + D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED = 0, + D3D12_MESSAGE_CATEGORY_MISCELLANEOUS = 1, + D3D12_MESSAGE_CATEGORY_INITIALIZATION = 2, + D3D12_MESSAGE_CATEGORY_CLEANUP = 3, + D3D12_MESSAGE_CATEGORY_COMPILATION = 4, + D3D12_MESSAGE_CATEGORY_STATE_CREATION = 5, + D3D12_MESSAGE_CATEGORY_STATE_SETTING = 6, + D3D12_MESSAGE_CATEGORY_STATE_GETTING = 7, + D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION = 8, + D3D12_MESSAGE_CATEGORY_EXECUTION = 9, + D3D12_MESSAGE_CATEGORY_SHADER = 10, +}} +ENUM!{enum D3D12_MESSAGE_SEVERITY { + D3D12_MESSAGE_SEVERITY_CORRUPTION = 0, + D3D12_MESSAGE_SEVERITY_ERROR = 1, + D3D12_MESSAGE_SEVERITY_WARNING = 2, + D3D12_MESSAGE_SEVERITY_INFO = 3, + D3D12_MESSAGE_SEVERITY_MESSAGE = 4, +}} +ENUM!{enum D3D12_MESSAGE_ID { + D3D12_MESSAGE_ID_UNKNOWN = 0, + D3D12_MESSAGE_ID_STRING_FROM_APPLICATION = 1, + D3D12_MESSAGE_ID_CORRUPTED_THIS = 2, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER1 = 3, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER2 = 4, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER3 = 5, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER4 = 6, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER5 = 7, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER6 = 8, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER7 = 9, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER8 = 10, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER9 = 11, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER10 = 12, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER11 = 13, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER12 = 14, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER13 = 15, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER14 = 16, + D3D12_MESSAGE_ID_CORRUPTED_PARAMETER15 = 17, + D3D12_MESSAGE_ID_CORRUPTED_MULTITHREADING = 18, + D3D12_MESSAGE_ID_MESSAGE_REPORTING_OUTOFMEMORY = 19, + D3D12_MESSAGE_ID_GETPRIVATEDATA_MOREDATA = 20, + D3D12_MESSAGE_ID_SETPRIVATEDATA_INVALIDFREEDATA = 21, + D3D12_MESSAGE_ID_SETPRIVATEDATA_INVALIDIUNKNOWN = 22, + D3D12_MESSAGE_ID_SETPRIVATEDATA_INVALIDFLAGS = 23, + D3D12_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS = 24, + D3D12_MESSAGE_ID_SETPRIVATEDATA_OUTOFMEMORY = 25, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_UNRECOGNIZEDFORMAT = 26, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDESC = 27, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFORMAT = 28, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDVIDEOPLANESLICE = 29, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDPLANESLICE = 30, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDIMENSIONS = 31, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDRESOURCE = 32, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDARG_RETURN = 33, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_OUTOFMEMORY_RETURN = 34, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_UNRECOGNIZEDFORMAT = 35, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_UNSUPPORTEDFORMAT = 36, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDESC = 37, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDFORMAT = 38, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDVIDEOPLANESLICE = 39, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDPLANESLICE = 40, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDIMENSIONS = 41, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDRESOURCE = 42, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDARG_RETURN = 43, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_OUTOFMEMORY_RETURN = 44, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_UNRECOGNIZEDFORMAT = 45, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDESC = 46, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFORMAT = 47, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDDIMENSIONS = 48, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDRESOURCE = 49, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDARG_RETURN = 50, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_OUTOFMEMORY_RETURN = 51, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_OUTOFMEMORY = 52, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TOOMANYELEMENTS = 53, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDFORMAT = 54, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INCOMPATIBLEFORMAT = 55, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOT = 56, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDINPUTSLOTCLASS = 57, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_STEPRATESLOTCLASSMISMATCH = 58, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSLOTCLASSCHANGE = 59, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDSTEPRATECHANGE = 60, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_INVALIDALIGNMENT = 61, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_DUPLICATESEMANTIC = 62, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_UNPARSEABLEINPUTSIGNATURE = 63, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_NULLSEMANTIC = 64, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_MISSINGELEMENT = 65, + D3D12_MESSAGE_ID_CREATEVERTEXSHADER_OUTOFMEMORY = 66, + D3D12_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERBYTECODE = 67, + D3D12_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDSHADERTYPE = 68, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADER_OUTOFMEMORY = 69, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERBYTECODE = 70, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDSHADERTYPE = 71, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTOFMEMORY = 72, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERBYTECODE = 73, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSHADERTYPE = 74, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMENTRIES = 75, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSTREAMSTRIDEUNUSED = 76, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDDECL = 77, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_EXPECTEDDECL = 78, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_OUTPUTSLOT0EXPECTED = 79, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSLOT = 80, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_ONLYONEELEMENTPERSLOT = 81, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCOMPONENTCOUNT = 82, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTARTCOMPONENTANDCOMPONENTCOUNT + = 83, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDGAPDEFINITION = 84, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_REPEATEDOUTPUT = 85, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDOUTPUTSTREAMSTRIDE = 86, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGSEMANTIC = 87, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MASKMISMATCH = 88, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_CANTHAVEONLYGAPS = 89, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DECLTOOCOMPLEX = 90, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_MISSINGOUTPUTSIGNATURE = 91, + D3D12_MESSAGE_ID_CREATEPIXELSHADER_OUTOFMEMORY = 92, + D3D12_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERBYTECODE = 93, + D3D12_MESSAGE_ID_CREATEPIXELSHADER_INVALIDSHADERTYPE = 94, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFILLMODE = 95, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDCULLMODE = 96, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDDEPTHBIASCLAMP = 97, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDSLOPESCALEDDEPTHBIAS = 98, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_NULLDESC = 99, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHWRITEMASK = 100, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDDEPTHFUNC = 101, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFAILOP = 102, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILZFAILOP = 103, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILPASSOP = 104, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDFRONTFACESTENCILFUNC = 105, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFAILOP = 106, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILZFAILOP = 107, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILPASSOP = 108, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_INVALIDBACKFACESTENCILFUNC = 109, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_NULLDESC = 110, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLEND = 111, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLEND = 112, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOP = 113, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDSRCBLENDALPHA = 114, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDDESTBLENDALPHA = 115, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDBLENDOPALPHA = 116, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDRENDERTARGETWRITEMASK = 117, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_NULLDESC = 118, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDFILTER = 119, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSU = 120, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSV = 121, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDADDRESSW = 122, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMIPLODBIAS = 123, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXANISOTROPY = 124, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDCOMPARISONFUNC = 125, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMINLOD = 126, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_INVALIDMAXLOD = 127, + D3D12_MESSAGE_ID_CREATESAMPLERSTATE_NULLDESC = 128, + D3D12_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNRECOGNIZED = 129, + D3D12_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNDEFINED = 130, + D3D12_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_INVALIDVIEWPORT = 131, + D3D12_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_INVALIDSCISSOR = 132, + D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_DENORMFLUSH = 133, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DENORMFLUSH = 134, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_INVALID = 135, + D3D12_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCE = 136, + D3D12_MESSAGE_ID_COPYRESOURCE_INVALIDDESTINATIONSTATE = 137, + D3D12_MESSAGE_ID_COPYRESOURCE_INVALIDSOURCESTATE = 138, + D3D12_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSUBRESOURCE = 139, + D3D12_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONBOX = 140, + D3D12_MESSAGE_ID_UPDATESUBRESOURCE_INVALIDDESTINATIONSTATE = 141, + D3D12_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_INVALID = 142, + D3D12_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_SUBRESOURCE_INVALID = 143, + D3D12_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_INVALID = 144, + D3D12_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_SOURCE_SUBRESOURCE_INVALID = 145, + D3D12_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_FORMAT_INVALID = 146, + D3D12_MESSAGE_ID_BUFFER_MAP_INVALIDMAPTYPE = 147, + D3D12_MESSAGE_ID_BUFFER_MAP_INVALIDFLAGS = 148, + D3D12_MESSAGE_ID_BUFFER_MAP_ALREADYMAPPED = 149, + D3D12_MESSAGE_ID_BUFFER_MAP_DEVICEREMOVED_RETURN = 150, + D3D12_MESSAGE_ID_BUFFER_UNMAP_NOTMAPPED = 151, + D3D12_MESSAGE_ID_TEXTURE1D_MAP_INVALIDMAPTYPE = 152, + D3D12_MESSAGE_ID_TEXTURE1D_MAP_INVALIDSUBRESOURCE = 153, + D3D12_MESSAGE_ID_TEXTURE1D_MAP_INVALIDFLAGS = 154, + D3D12_MESSAGE_ID_TEXTURE1D_MAP_ALREADYMAPPED = 155, + D3D12_MESSAGE_ID_TEXTURE1D_MAP_DEVICEREMOVED_RETURN = 156, + D3D12_MESSAGE_ID_TEXTURE1D_UNMAP_INVALIDSUBRESOURCE = 157, + D3D12_MESSAGE_ID_TEXTURE1D_UNMAP_NOTMAPPED = 158, + D3D12_MESSAGE_ID_TEXTURE2D_MAP_INVALIDMAPTYPE = 159, + D3D12_MESSAGE_ID_TEXTURE2D_MAP_INVALIDSUBRESOURCE = 160, + D3D12_MESSAGE_ID_TEXTURE2D_MAP_INVALIDFLAGS = 161, + D3D12_MESSAGE_ID_TEXTURE2D_MAP_ALREADYMAPPED = 162, + D3D12_MESSAGE_ID_TEXTURE2D_MAP_DEVICEREMOVED_RETURN = 163, + D3D12_MESSAGE_ID_TEXTURE2D_UNMAP_INVALIDSUBRESOURCE = 164, + D3D12_MESSAGE_ID_TEXTURE2D_UNMAP_NOTMAPPED = 165, + D3D12_MESSAGE_ID_TEXTURE3D_MAP_INVALIDMAPTYPE = 166, + D3D12_MESSAGE_ID_TEXTURE3D_MAP_INVALIDSUBRESOURCE = 167, + D3D12_MESSAGE_ID_TEXTURE3D_MAP_INVALIDFLAGS = 168, + D3D12_MESSAGE_ID_TEXTURE3D_MAP_ALREADYMAPPED = 169, + D3D12_MESSAGE_ID_TEXTURE3D_MAP_DEVICEREMOVED_RETURN = 170, + D3D12_MESSAGE_ID_TEXTURE3D_UNMAP_INVALIDSUBRESOURCE = 171, + D3D12_MESSAGE_ID_TEXTURE3D_UNMAP_NOTMAPPED = 172, + D3D12_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_DEPRECATED = 173, + D3D12_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_FORMAT_DEPRECATED = 174, + D3D12_MESSAGE_ID_SETEXCEPTIONMODE_UNRECOGNIZEDFLAGS = 175, + D3D12_MESSAGE_ID_SETEXCEPTIONMODE_INVALIDARG_RETURN = 176, + D3D12_MESSAGE_ID_SETEXCEPTIONMODE_DEVICEREMOVED_RETURN = 177, + D3D12_MESSAGE_ID_REF_SIMULATING_INFINITELY_FAST_HARDWARE = 178, + D3D12_MESSAGE_ID_REF_THREADING_MODE = 179, + D3D12_MESSAGE_ID_REF_UMDRIVER_EXCEPTION = 180, + D3D12_MESSAGE_ID_REF_KMDRIVER_EXCEPTION = 181, + D3D12_MESSAGE_ID_REF_HARDWARE_EXCEPTION = 182, + D3D12_MESSAGE_ID_REF_ACCESSING_INDEXABLE_TEMP_OUT_OF_RANGE = 183, + D3D12_MESSAGE_ID_REF_PROBLEM_PARSING_SHADER = 184, + D3D12_MESSAGE_ID_REF_OUT_OF_MEMORY = 185, + D3D12_MESSAGE_ID_REF_INFO = 186, + D3D12_MESSAGE_ID_DEVICE_DRAW_VERTEXPOS_OVERFLOW = 187, + D3D12_MESSAGE_ID_DEVICE_DRAWINDEXED_INDEXPOS_OVERFLOW = 188, + D3D12_MESSAGE_ID_DEVICE_DRAWINSTANCED_VERTEXPOS_OVERFLOW = 189, + D3D12_MESSAGE_ID_DEVICE_DRAWINSTANCED_INSTANCEPOS_OVERFLOW = 190, + D3D12_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INSTANCEPOS_OVERFLOW = 191, + D3D12_MESSAGE_ID_DEVICE_DRAWINDEXEDINSTANCED_INDEXPOS_OVERFLOW = 192, + D3D12_MESSAGE_ID_DEVICE_DRAW_VERTEX_SHADER_NOT_SET = 193, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND = 194, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERINDEX = 195, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_COMPONENTTYPE = 196, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERMASK = 197, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_SYSTEMVALUE = 198, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_NEVERWRITTEN_ALWAYSREADS = 199, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_ROOT_SIGNATURE_NOT_SET = 200, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_ROOT_SIGNATURE_MISMATCH = 201, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_NOT_SET = 202, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INPUTLAYOUT_NOT_SET = 203, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_CONSTANT_BUFFER_NOT_SET = 204, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_CONSTANT_BUFFER_TOO_SMALL = 205, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_SAMPLER_NOT_SET = 206, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_SHADERRESOURCEVIEW_NOT_SET = 207, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VIEW_DIMENSION_MISMATCH = 208, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_STRIDE_TOO_SMALL = 209, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_BUFFER_TOO_SMALL = 210, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INDEX_BUFFER_NOT_SET = 211, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INDEX_BUFFER_FORMAT_INVALID = 212, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INDEX_BUFFER_TOO_SMALL = 213, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_GS_INPUT_PRIMITIVE_MISMATCH = 214, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RESOURCE_RETURN_TYPE_MISMATCH = 215, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_POSITION_NOT_PRESENT = 216, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_OUTPUT_STREAM_NOT_SET = 217, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_BOUND_RESOURCE_MAPPED = 218, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INVALID_PRIMITIVETOPOLOGY = 219, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_OFFSET_UNALIGNED = 220, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_VERTEX_STRIDE_UNALIGNED = 221, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_INDEX_OFFSET_UNALIGNED = 222, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_OUTPUT_STREAM_OFFSET_UNALIGNED = 223, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RESOURCE_FORMAT_LD_UNSUPPORTED = 224, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RESOURCE_FORMAT_SAMPLE_UNSUPPORTED = 225, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RESOURCE_FORMAT_SAMPLE_C_UNSUPPORTED = 226, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RESOURCE_MULTISAMPLE_UNSUPPORTED = 227, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_SO_TARGETS_BOUND_WITHOUT_SOURCE = 228, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_SO_STRIDE_LARGER_THAN_BUFFER = 229, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_BLENDING = 230, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_OM_DUAL_SOURCE_BLENDING_CAN_ONLY_HAVE_RENDER_TARGET_0 = 231, + D3D12_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_AT_FAULT = 232, + D3D12_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_POSSIBLY_AT_FAULT = 233, + D3D12_MESSAGE_ID_DEVICE_REMOVAL_PROCESS_NOT_AT_FAULT = 234, + D3D12_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_INVALIDARG_RETURN = 235, + D3D12_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_OUTOFMEMORY_RETURN = 236, + D3D12_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BADINTERFACE_RETURN = 237, + D3D12_MESSAGE_ID_DEVICE_DRAW_VIEWPORT_NOT_SET = 238, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TRAILING_DIGIT_IN_SEMANTIC = 239, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_TRAILING_DIGIT_IN_SEMANTIC = 240, + D3D12_MESSAGE_ID_DEVICE_RSSETVIEWPORTS_DENORMFLUSH = 241, + D3D12_MESSAGE_ID_OMSETRENDERTARGETS_INVALIDVIEW = 242, + D3D12_MESSAGE_ID_DEVICE_SETTEXTFILTERSIZE_INVALIDDIMENSIONS = 243, + D3D12_MESSAGE_ID_DEVICE_DRAW_SAMPLER_MISMATCH = 244, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH = 245, + D3D12_MESSAGE_ID_BLENDSTATE_GETDESC_LEGACY = 246, + D3D12_MESSAGE_ID_SHADERRESOURCEVIEW_GETDESC_LEGACY = 247, + D3D12_MESSAGE_ID_DEVICE_DRAW_PS_OUTPUT_TYPE_MISMATCH = 248, + D3D12_MESSAGE_ID_DEVICE_DRAW_RESOURCE_FORMAT_GATHER_UNSUPPORTED = 249, + D3D12_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_CENTER_MULTISAMPLE_PATTERN = 250, + D3D12_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_STRIDE_TOO_LARGE = 251, + D3D12_MESSAGE_ID_DEVICE_IASETVERTEXBUFFERS_INVALIDRANGE = 252, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_EMPTY_LAYOUT = 253, + D3D12_MESSAGE_ID_DEVICE_DRAW_RESOURCE_SAMPLE_COUNT_MISMATCH = 254, + D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY = 255, + D3D12_MESSAGE_ID_LIVE_BUFFER = 256, + D3D12_MESSAGE_ID_LIVE_TEXTURE1D = 257, + D3D12_MESSAGE_ID_LIVE_TEXTURE2D = 258, + D3D12_MESSAGE_ID_LIVE_TEXTURE3D = 259, + D3D12_MESSAGE_ID_LIVE_SHADERRESOURCEVIEW = 260, + D3D12_MESSAGE_ID_LIVE_RENDERTARGETVIEW = 261, + D3D12_MESSAGE_ID_LIVE_DEPTHSTENCILVIEW = 262, + D3D12_MESSAGE_ID_LIVE_VERTEXSHADER = 263, + D3D12_MESSAGE_ID_LIVE_GEOMETRYSHADER = 264, + D3D12_MESSAGE_ID_LIVE_PIXELSHADER = 265, + D3D12_MESSAGE_ID_LIVE_INPUTLAYOUT = 266, + D3D12_MESSAGE_ID_LIVE_SAMPLER = 267, + D3D12_MESSAGE_ID_LIVE_BLENDSTATE = 268, + D3D12_MESSAGE_ID_LIVE_DEPTHSTENCILSTATE = 269, + D3D12_MESSAGE_ID_LIVE_RASTERIZERSTATE = 270, + D3D12_MESSAGE_ID_LIVE_QUERY = 271, + D3D12_MESSAGE_ID_LIVE_PREDICATE = 272, + D3D12_MESSAGE_ID_LIVE_COUNTER = 273, + D3D12_MESSAGE_ID_LIVE_DEVICE = 274, + D3D12_MESSAGE_ID_LIVE_SWAPCHAIN = 275, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILVIEW_INVALIDFLAGS = 276, + D3D12_MESSAGE_ID_CREATEVERTEXSHADER_INVALIDCLASSLINKAGE = 277, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADER_INVALIDCLASSLINKAGE = 278, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTREAMS = 279, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAMTORASTERIZER = 280, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTREAMS = 281, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDCLASSLINKAGE = 282, + D3D12_MESSAGE_ID_CREATEPIXELSHADER_INVALIDCLASSLINKAGE = 283, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDSTREAM = 284, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDENTRIES = 285, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UNEXPECTEDSTRIDES = 286, + D3D12_MESSAGE_ID_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_INVALIDNUMSTRIDES = 287, + D3D12_MESSAGE_ID_CREATEHULLSHADER_INVALIDCALL = 288, + D3D12_MESSAGE_ID_CREATEHULLSHADER_OUTOFMEMORY = 289, + D3D12_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERBYTECODE = 290, + D3D12_MESSAGE_ID_CREATEHULLSHADER_INVALIDSHADERTYPE = 291, + D3D12_MESSAGE_ID_CREATEHULLSHADER_INVALIDCLASSLINKAGE = 292, + D3D12_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCALL = 293, + D3D12_MESSAGE_ID_CREATEDOMAINSHADER_OUTOFMEMORY = 294, + D3D12_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERBYTECODE = 295, + D3D12_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDSHADERTYPE = 296, + D3D12_MESSAGE_ID_CREATEDOMAINSHADER_INVALIDCLASSLINKAGE = 297, + D3D12_MESSAGE_ID_DEVICE_DRAW_HS_XOR_DS_MISMATCH = 298, + D3D12_MESSAGE_ID_DEVICE_DRAWINDIRECT_INVALID_ARG_BUFFER = 299, + D3D12_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_UNALIGNED = 300, + D3D12_MESSAGE_ID_DEVICE_DRAWINDIRECT_OFFSET_OVERFLOW = 301, + D3D12_MESSAGE_ID_RESOURCE_MAP_INVALIDMAPTYPE = 302, + D3D12_MESSAGE_ID_RESOURCE_MAP_INVALIDSUBRESOURCE = 303, + D3D12_MESSAGE_ID_RESOURCE_MAP_INVALIDFLAGS = 304, + D3D12_MESSAGE_ID_RESOURCE_MAP_ALREADYMAPPED = 305, + D3D12_MESSAGE_ID_RESOURCE_MAP_DEVICEREMOVED_RETURN = 306, + D3D12_MESSAGE_ID_RESOURCE_MAP_OUTOFMEMORY_RETURN = 307, + D3D12_MESSAGE_ID_RESOURCE_MAP_WITHOUT_INITIAL_DISCARD = 308, + D3D12_MESSAGE_ID_RESOURCE_UNMAP_INVALIDSUBRESOURCE = 309, + D3D12_MESSAGE_ID_RESOURCE_UNMAP_NOTMAPPED = 310, + D3D12_MESSAGE_ID_DEVICE_DRAW_RASTERIZING_CONTROL_POINTS = 311, + D3D12_MESSAGE_ID_DEVICE_IASETPRIMITIVETOPOLOGY_TOPOLOGY_UNSUPPORTED = 312, + D3D12_MESSAGE_ID_DEVICE_DRAW_HS_DS_SIGNATURE_MISMATCH = 313, + D3D12_MESSAGE_ID_DEVICE_DRAW_HULL_SHADER_INPUT_TOPOLOGY_MISMATCH = 314, + D3D12_MESSAGE_ID_DEVICE_DRAW_HS_DS_CONTROL_POINT_COUNT_MISMATCH = 315, + D3D12_MESSAGE_ID_DEVICE_DRAW_HS_DS_TESSELLATOR_DOMAIN_MISMATCH = 316, + D3D12_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_UNRECOGNIZED_FEATURE = 317, + D3D12_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_MISMATCHED_DATA_SIZE = 318, + D3D12_MESSAGE_ID_DEVICE_CHECKFEATURESUPPORT_INVALIDARG_RETURN = 319, + D3D12_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCALL = 320, + D3D12_MESSAGE_ID_CREATECOMPUTESHADER_OUTOFMEMORY = 321, + D3D12_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDSHADERBYTECODE = 322, + D3D12_MESSAGE_ID_CREATECOMPUTESHADER_INVALIDCLASSLINKAGE = 323, + D3D12_MESSAGE_ID_DEVICE_CSSETSHADERRESOURCES_VIEWS_EMPTY = 324, + D3D12_MESSAGE_ID_CSSETCONSTANTBUFFERS_INVALIDBUFFER = 325, + D3D12_MESSAGE_ID_DEVICE_CSSETCONSTANTBUFFERS_BUFFERS_EMPTY = 326, + D3D12_MESSAGE_ID_DEVICE_CSSETSAMPLERS_SAMPLERS_EMPTY = 327, + D3D12_MESSAGE_ID_DEVICE_CSGETSHADERRESOURCES_VIEWS_EMPTY = 328, + D3D12_MESSAGE_ID_DEVICE_CSGETCONSTANTBUFFERS_BUFFERS_EMPTY = 329, + D3D12_MESSAGE_ID_DEVICE_CSGETSAMPLERS_SAMPLERS_EMPTY = 330, + D3D12_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 331, + D3D12_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 332, + D3D12_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 333, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 334, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEFLOATOPSNOTSUPPORTED = 335, + D3D12_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEFLOATOPSNOTSUPPORTED = 336, + D3D12_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEFLOATOPSNOTSUPPORTED = 337, + D3D12_MESSAGE_ID_CREATEBUFFER_INVALIDSTRUCTURESTRIDE = 338, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDFLAGS = 339, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDRESOURCE = 340, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDESC = 341, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFORMAT = 342, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDVIDEOPLANESLICE = 343, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDPLANESLICE = 344, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDIMENSIONS = 345, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_UNRECOGNIZEDFORMAT = 346, + D3D12_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_OVERLAPPING_OLD_SLOTS = 347, + D3D12_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_NO_OP = 348, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDARG_RETURN = 349, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_OUTOFMEMORY_RETURN = 350, + D3D12_MESSAGE_ID_CLEARUNORDEREDACCESSVIEW_DENORMFLUSH = 351, + D3D12_MESSAGE_ID_DEVICE_CSSETUNORDEREDACCESSS_VIEWS_EMPTY = 352, + D3D12_MESSAGE_ID_DEVICE_CSGETUNORDEREDACCESSS_VIEWS_EMPTY = 353, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDFLAGS = 354, + D3D12_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_INVALID_ARG_BUFFER = 355, + D3D12_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_UNALIGNED = 356, + D3D12_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_OFFSET_OVERFLOW = 357, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_DEPTH_READONLY = 358, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_STENCIL_READONLY = 359, + D3D12_MESSAGE_ID_CHECKFEATURESUPPORT_FORMAT_DEPRECATED = 360, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RETURN_TYPE_MISMATCH = 361, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET = 362, + D3D12_MESSAGE_ID_DEVICE_DRAW_UNORDEREDACCESSVIEW_RENDERTARGETVIEW_OVERLAP = 363, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_DIMENSION_MISMATCH = 364, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_APPEND_UNSUPPORTED = 365, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMICS_UNSUPPORTED = 366, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_STRUCTURE_STRIDE_MISMATCH = 367, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_BUFFER_TYPE_MISMATCH = 368, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_RAW_UNSUPPORTED = 369, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_LD_UNSUPPORTED = 370, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_FORMAT_STORE_UNSUPPORTED = 371, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_ADD_UNSUPPORTED = 372, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_BITWISE_OPS_UNSUPPORTED = 373, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_CMPSTORE_CMPEXCHANGE_UNSUPPORTED = 374, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_EXCHANGE_UNSUPPORTED = 375, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_SIGNED_MINMAX_UNSUPPORTED = 376, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_ATOMIC_UNSIGNED_MINMAX_UNSUPPORTED = 377, + D3D12_MESSAGE_ID_DEVICE_DISPATCH_BOUND_RESOURCE_MAPPED = 378, + D3D12_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_OVERFLOW = 379, + D3D12_MESSAGE_ID_DEVICE_DISPATCH_THREADGROUPCOUNT_ZERO = 380, + D3D12_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_STRUCTURE_STRIDE_MISMATCH = 381, + D3D12_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_BUFFER_TYPE_MISMATCH = 382, + D3D12_MESSAGE_ID_DEVICE_SHADERRESOURCEVIEW_RAW_UNSUPPORTED = 383, + D3D12_MESSAGE_ID_DEVICE_DISPATCH_UNSUPPORTED = 384, + D3D12_MESSAGE_ID_DEVICE_DISPATCHINDIRECT_UNSUPPORTED = 385, + D3D12_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDOFFSET = 386, + D3D12_MESSAGE_ID_COPYSTRUCTURECOUNT_LARGEOFFSET = 387, + D3D12_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDDESTINATIONSTATE = 388, + D3D12_MESSAGE_ID_COPYSTRUCTURECOUNT_INVALIDSOURCESTATE = 389, + D3D12_MESSAGE_ID_CHECKFORMATSUPPORT_FORMAT_NOT_SUPPORTED = 390, + D3D12_MESSAGE_ID_CLEARUNORDEREDACCESSVIEWFLOAT_INVALIDFORMAT = 391, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_COUNTER_UNSUPPORTED = 392, + D3D12_MESSAGE_ID_DEVICE_DRAW_PIXEL_SHADER_WITHOUT_RTV_OR_DSV = 393, + D3D12_MESSAGE_ID_SHADER_ABORT = 394, + D3D12_MESSAGE_ID_SHADER_MESSAGE = 395, + D3D12_MESSAGE_ID_SHADER_ERROR = 396, + D3D12_MESSAGE_ID_OFFERRESOURCES_INVALIDRESOURCE = 397, + D3D12_MESSAGE_ID_ENQUEUESETEVENT_INVALIDARG_RETURN = 398, + D3D12_MESSAGE_ID_ENQUEUESETEVENT_OUTOFMEMORY_RETURN = 399, + D3D12_MESSAGE_ID_ENQUEUESETEVENT_ACCESSDENIED_RETURN = 400, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALIDFORCEDSAMPLECOUNT = 401, + D3D12_MESSAGE_ID_DEVICE_DRAW_INVALID_USE_OF_FORCED_SAMPLE_COUNT = 402, + D3D12_MESSAGE_ID_CREATEBLENDSTATE_INVALIDLOGICOPS = 403, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDDARRAYWITHDECODER = 404, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDDARRAYWITHDECODER = 405, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDDARRAYWITHDECODER = 406, + D3D12_MESSAGE_ID_DEVICE_LOCKEDOUT_INTERFACE = 407, + D3D12_MESSAGE_ID_OFFERRESOURCES_INVALIDPRIORITY = 408, + D3D12_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDVIEW = 409, + D3D12_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 410, + D3D12_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_SHADEREXTENSIONSNOTSUPPORTED = 411, + D3D12_MESSAGE_ID_DEVICE_CREATEHULLSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 412, + D3D12_MESSAGE_ID_DEVICE_CREATEHULLSHADER_SHADEREXTENSIONSNOTSUPPORTED = 413, + D3D12_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 414, + D3D12_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_SHADEREXTENSIONSNOTSUPPORTED = 415, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 416, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_SHADEREXTENSIONSNOTSUPPORTED = 417, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_DOUBLEEXTENSIONSNOTSUPPORTED + = 418, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_SHADEREXTENSIONSNOTSUPPORTED + = 419, + D3D12_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 420, + D3D12_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_SHADEREXTENSIONSNOTSUPPORTED = 421, + D3D12_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_DOUBLEEXTENSIONSNOTSUPPORTED = 422, + D3D12_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_SHADEREXTENSIONSNOTSUPPORTED = 423, + D3D12_MESSAGE_ID_DEVICE_SHADER_LINKAGE_MINPRECISION = 424, + D3D12_MESSAGE_ID_DEVICE_CREATEVERTEXSHADER_UAVSNOTSUPPORTED = 425, + D3D12_MESSAGE_ID_DEVICE_CREATEHULLSHADER_UAVSNOTSUPPORTED = 426, + D3D12_MESSAGE_ID_DEVICE_CREATEDOMAINSHADER_UAVSNOTSUPPORTED = 427, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADER_UAVSNOTSUPPORTED = 428, + D3D12_MESSAGE_ID_DEVICE_CREATEGEOMETRYSHADERWITHSTREAMOUTPUT_UAVSNOTSUPPORTED = 429, + D3D12_MESSAGE_ID_DEVICE_CREATEPIXELSHADER_UAVSNOTSUPPORTED = 430, + D3D12_MESSAGE_ID_DEVICE_CREATECOMPUTESHADER_UAVSNOTSUPPORTED = 431, + D3D12_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_INVALIDOFFSET = 432, + D3D12_MESSAGE_ID_DEVICE_OMSETRENDERTARGETSANDUNORDEREDACCESSVIEWS_TOOMANYVIEWS = 433, + D3D12_MESSAGE_ID_DEVICE_CLEARVIEW_NOTSUPPORTED = 434, + D3D12_MESSAGE_ID_SWAPDEVICECONTEXTSTATE_NOTSUPPORTED = 435, + D3D12_MESSAGE_ID_UPDATESUBRESOURCE_PREFERUPDATESUBRESOURCE1 = 436, + D3D12_MESSAGE_ID_GETDC_INACCESSIBLE = 437, + D3D12_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDRECT = 438, + D3D12_MESSAGE_ID_DEVICE_DRAW_SAMPLE_MASK_IGNORED_ON_FL9 = 439, + D3D12_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE1_NOT_SUPPORTED = 440, + D3D12_MESSAGE_ID_DEVICE_OPEN_SHARED_RESOURCE_BY_NAME_NOT_SUPPORTED = 441, + D3D12_MESSAGE_ID_ENQUEUESETEVENT_NOT_SUPPORTED = 442, + D3D12_MESSAGE_ID_OFFERRELEASE_NOT_SUPPORTED = 443, + D3D12_MESSAGE_ID_OFFERRESOURCES_INACCESSIBLE = 444, + D3D12_MESSAGE_ID_CREATEVIDEOPROCESSORINPUTVIEW_INVALIDMSAA = 445, + D3D12_MESSAGE_ID_CREATEVIDEOPROCESSOROUTPUTVIEW_INVALIDMSAA = 446, + D3D12_MESSAGE_ID_DEVICE_CLEARVIEW_INVALIDSOURCERECT = 447, + D3D12_MESSAGE_ID_DEVICE_CLEARVIEW_EMPTYRECT = 448, + D3D12_MESSAGE_ID_UPDATESUBRESOURCE_EMPTYDESTBOX = 449, + D3D12_MESSAGE_ID_COPYSUBRESOURCEREGION_EMPTYSOURCEBOX = 450, + D3D12_MESSAGE_ID_DEVICE_DRAW_OM_RENDER_TARGET_DOES_NOT_SUPPORT_LOGIC_OPS = 451, + D3D12_MESSAGE_ID_DEVICE_DRAW_DEPTHSTENCILVIEW_NOT_SET = 452, + D3D12_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET = 453, + D3D12_MESSAGE_ID_DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET_DUE_TO_FLIP_PRESENT = 454, + D3D12_MESSAGE_ID_DEVICE_UNORDEREDACCESSVIEW_NOT_SET_DUE_TO_FLIP_PRESENT = 455, + D3D12_MESSAGE_ID_GETDATAFORNEWHARDWAREKEY_NULLPARAM = 456, + D3D12_MESSAGE_ID_CHECKCRYPTOSESSIONSTATUS_NULLPARAM = 457, + D3D12_MESSAGE_ID_SETEVENTONHARDWARECONTENTPROTECTIONTILT_NULLPARAM = 458, + D3D12_MESSAGE_ID_GETVIDEODECODERCAPS_NULLPARAM = 459, + D3D12_MESSAGE_ID_GETVIDEODECODERCAPS_ZEROWIDTHHEIGHT = 460, + D3D12_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_NULLPARAM = 461, + D3D12_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE = 462, + D3D12_MESSAGE_ID_CHECKVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT = 463, + D3D12_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_NULLPARAM = 464, + D3D12_MESSAGE_ID_VIDEODECODERENABLEDOWNSAMPLING_UNSUPPORTED = 465, + D3D12_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_NULLPARAM = 466, + D3D12_MESSAGE_ID_VIDEODECODERUPDATEDOWNSAMPLING_UNSUPPORTED = 467, + D3D12_MESSAGE_ID_CHECKVIDEOPROCESSORFORMATCONVERSION_NULLPARAM = 468, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTCOLORSPACE1_NULLPARAM = 469, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTCOLORSPACE1_NULLPARAM = 470, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_NULLPARAM = 471, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETSTREAMCOLORSPACE1_INVALIDSTREAM = 472, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_NULLPARAM = 473, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_INVALIDSTREAM = 474, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETSTREAMMIRROR_UNSUPPORTED = 475, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETSTREAMCOLORSPACE1_NULLPARAM = 476, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETSTREAMMIRROR_NULLPARAM = 477, + D3D12_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_NULLPARAM = 478, + D3D12_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_INVALIDCOLORSPACE = 479, + D3D12_MESSAGE_ID_RECOMMENDVIDEODECODERDOWNSAMPLING_ZEROWIDTHHEIGHT = 480, + D3D12_MESSAGE_ID_VIDEOPROCESSORSETOUTPUTSHADERUSAGE_NULLPARAM = 481, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETOUTPUTSHADERUSAGE_NULLPARAM = 482, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_NULLPARAM = 483, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSTREAMCOUNT = 484, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_TARGETRECT = 485, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDSOURCERECT = 486, + D3D12_MESSAGE_ID_VIDEOPROCESSORGETBEHAVIORHINTS_INVALIDDESTRECT = 487, + D3D12_MESSAGE_ID_CREATEBUFFER_INVALIDUSAGE = 488, + D3D12_MESSAGE_ID_CREATETEXTURE1D_INVALIDUSAGE = 489, + D3D12_MESSAGE_ID_CREATETEXTURE2D_INVALIDUSAGE = 490, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_STEPRATE_NOT_1 = 491, + D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_LEVEL9_INSTANCING_NOT_SUPPORTED = 492, + D3D12_MESSAGE_ID_UPDATETILEMAPPINGS_INVALID_PARAMETER = 493, + D3D12_MESSAGE_ID_COPYTILEMAPPINGS_INVALID_PARAMETER = 494, + D3D12_MESSAGE_ID_COPYTILES_INVALID_PARAMETER = 495, + D3D12_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_WARNING = 496, + D3D12_MESSAGE_ID_NULL_TILE_MAPPING_ACCESS_ERROR = 497, + D3D12_MESSAGE_ID_DIRTY_TILE_MAPPING_ACCESS = 498, + D3D12_MESSAGE_ID_DUPLICATE_TILE_MAPPINGS_IN_COVERED_AREA = 499, + D3D12_MESSAGE_ID_TILE_MAPPINGS_IN_COVERED_AREA_DUPLICATED_OUTSIDE = 500, + D3D12_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INCOMPATIBLE_RESOURCES = 501, + D3D12_MESSAGE_ID_TILE_MAPPINGS_SHARED_BETWEEN_INPUT_AND_OUTPUT = 502, + D3D12_MESSAGE_ID_CHECKMULTISAMPLEQUALITYLEVELS_INVALIDFLAGS = 503, + D3D12_MESSAGE_ID_GETRESOURCETILING_NONTILED_RESOURCE = 504, + D3D12_MESSAGE_ID_NEED_TO_CALL_TILEDRESOURCEBARRIER = 505, + D3D12_MESSAGE_ID_CREATEDEVICE_INVALIDARGS = 506, + D3D12_MESSAGE_ID_CREATEDEVICE_WARNING = 507, + D3D12_MESSAGE_ID_TILED_RESOURCE_TIER_1_BUFFER_TEXTURE_MISMATCH = 508, + D3D12_MESSAGE_ID_CREATE_CRYPTOSESSION = 509, + D3D12_MESSAGE_ID_CREATE_AUTHENTICATEDCHANNEL = 510, + D3D12_MESSAGE_ID_LIVE_CRYPTOSESSION = 511, + D3D12_MESSAGE_ID_LIVE_AUTHENTICATEDCHANNEL = 512, + D3D12_MESSAGE_ID_DESTROY_CRYPTOSESSION = 513, + D3D12_MESSAGE_ID_DESTROY_AUTHENTICATEDCHANNEL = 514, + D3D12_MESSAGE_ID_MAP_INVALID_SUBRESOURCE = 515, + D3D12_MESSAGE_ID_MAP_INVALID_TYPE = 516, + D3D12_MESSAGE_ID_MAP_UNSUPPORTED_TYPE = 517, + D3D12_MESSAGE_ID_UNMAP_INVALID_SUBRESOURCE = 518, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_TYPE = 519, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_NULL_POINTER = 520, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_SUBRESOURCE = 521, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_RESERVED_BITS = 522, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISSING_BIND_FLAGS = 523, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_MISC_FLAGS = 524, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_MATCHING_STATES = 525, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_COMBINATION = 526, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_BEFORE_AFTER_MISMATCH = 527, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_RESOURCE = 528, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_SAMPLE_COUNT = 529, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_FLAGS = 530, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_COMBINED_FLAGS = 531, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_FLAGS_FOR_FORMAT = 532, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_SPLIT_BARRIER = 533, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_UNMATCHED_END = 534, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_UNMATCHED_BEGIN = 535, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_FLAG = 536, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_COMMAND_LIST_TYPE = 537, + D3D12_MESSAGE_ID_INVALID_SUBRESOURCE_STATE = 538, + D3D12_MESSAGE_ID_INEFFICIENT_PRESENT = 539, + D3D12_MESSAGE_ID_COMMAND_ALLOCATOR_CONTENTION = 540, + D3D12_MESSAGE_ID_COMMAND_ALLOCATOR_RESET = 541, + D3D12_MESSAGE_ID_COMMAND_ALLOCATOR_RESET_BUNDLE = 542, + D3D12_MESSAGE_ID_COMMAND_ALLOCATOR_CANNOT_RESET = 543, + D3D12_MESSAGE_ID_COMMAND_LIST_OPEN = 544, + D3D12_MESSAGE_ID_QUERY_STATE_MISMATCH = 545, + D3D12_MESSAGE_ID_INVALID_BUNDLE_API = 546, + D3D12_MESSAGE_ID_COMMAND_LIST_CLOSED = 547, + D3D12_MESSAGE_ID_COMMAND_LIST_CLOSED_WITH_INVALID_RESOURCE = 548, + D3D12_MESSAGE_ID_WRONG_COMMAND_ALLOCATOR_TYPE = 549, + D3D12_MESSAGE_ID_INVALID_INDIRECT_ARGUMENT_BUFFER = 550, + D3D12_MESSAGE_ID_COMPUTE_AND_GRAPHICS_PIPELINE = 551, + D3D12_MESSAGE_ID_COMMAND_ALLOCATOR_SYNC = 552, + D3D12_MESSAGE_ID_COMMAND_LIST_SYNC = 553, + D3D12_MESSAGE_ID_SET_DESCRIPTOR_HEAP_INVALID = 554, + D3D12_MESSAGE_ID_CREATE_QUEUE_IMAGE_NOT_SUPPORTED = 555, + D3D12_MESSAGE_ID_CREATE_COMMAND_ALLOCATOR_IMAGE_NOT_SUPPORTED = 556, + D3D12_MESSAGE_ID_CREATE_COMMANDQUEUE = 557, + D3D12_MESSAGE_ID_CREATE_COMMANDALLOCATOR = 558, + D3D12_MESSAGE_ID_CREATE_PIPELINESTATE = 559, + D3D12_MESSAGE_ID_CREATE_COMMANDLIST12 = 560, + D3D12_MESSAGE_ID_CREATE_IMAGECOMMANDLIST = 561, + D3D12_MESSAGE_ID_CREATE_RESOURCE = 562, + D3D12_MESSAGE_ID_CREATE_DESCRIPTORHEAP = 563, + D3D12_MESSAGE_ID_CREATE_ROOTSIGNATURE = 564, + D3D12_MESSAGE_ID_CREATE_LIBRARY = 565, + D3D12_MESSAGE_ID_CREATE_HEAP = 566, + D3D12_MESSAGE_ID_CREATE_MONITOREDFENCE = 567, + D3D12_MESSAGE_ID_CREATE_QUERYHEAP = 568, + D3D12_MESSAGE_ID_CREATE_COMMANDSIGNATURE = 569, + D3D12_MESSAGE_ID_LIVE_COMMANDQUEUE = 570, + D3D12_MESSAGE_ID_LIVE_COMMANDALLOCATOR = 571, + D3D12_MESSAGE_ID_LIVE_PIPELINESTATE = 572, + D3D12_MESSAGE_ID_LIVE_COMMANDLIST12 = 573, + D3D12_MESSAGE_ID_LIVE_IMAGECOMMANDLIST = 574, + D3D12_MESSAGE_ID_LIVE_RESOURCE = 575, + D3D12_MESSAGE_ID_LIVE_DESCRIPTORHEAP = 576, + D3D12_MESSAGE_ID_LIVE_ROOTSIGNATURE = 577, + D3D12_MESSAGE_ID_LIVE_LIBRARY = 578, + D3D12_MESSAGE_ID_LIVE_HEAP = 579, + D3D12_MESSAGE_ID_LIVE_MONITOREDFENCE = 580, + D3D12_MESSAGE_ID_LIVE_QUERYHEAP = 581, + D3D12_MESSAGE_ID_LIVE_COMMANDSIGNATURE = 582, + D3D12_MESSAGE_ID_DESTROY_COMMANDQUEUE = 583, + D3D12_MESSAGE_ID_DESTROY_COMMANDALLOCATOR = 584, + D3D12_MESSAGE_ID_DESTROY_PIPELINESTATE = 585, + D3D12_MESSAGE_ID_DESTROY_COMMANDLIST12 = 586, + D3D12_MESSAGE_ID_DESTROY_IMAGECOMMANDLIST = 587, + D3D12_MESSAGE_ID_DESTROY_RESOURCE = 588, + D3D12_MESSAGE_ID_DESTROY_DESCRIPTORHEAP = 589, + D3D12_MESSAGE_ID_DESTROY_ROOTSIGNATURE = 590, + D3D12_MESSAGE_ID_DESTROY_LIBRARY = 591, + D3D12_MESSAGE_ID_DESTROY_HEAP = 592, + D3D12_MESSAGE_ID_DESTROY_MONITOREDFENCE = 593, + D3D12_MESSAGE_ID_DESTROY_QUERYHEAP = 594, + D3D12_MESSAGE_ID_DESTROY_COMMANDSIGNATURE = 595, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDHEAPTYPE = 596, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDDIMENSIONS = 597, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDMISCFLAGS = 598, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDMISCFLAGS = 599, + D3D12_MESSAGE_ID_CREATERESOURCE_LARGEALLOCATION = 600, + D3D12_MESSAGE_ID_CREATERESOURCE_SMALLALLOCATION = 601, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDARG_RETURN = 602, + D3D12_MESSAGE_ID_CREATERESOURCE_OUTOFMEMORY_RETURN = 603, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDDESC = 604, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDINITIALSTATE = 605, + D3D12_MESSAGE_ID_RESOURCE_HAS_PENDING_INITIAL_DATA = 606, + D3D12_MESSAGE_ID_POSSIBLY_INVALID_SUBRESOURCE_STATE = 607, + D3D12_MESSAGE_ID_INVALID_USE_OF_NON_RESIDENT_RESOURCE = 608, + D3D12_MESSAGE_ID_POSSIBLE_INVALID_USE_OF_NON_RESIDENT_RESOURCE = 609, + D3D12_MESSAGE_ID_BUNDLE_PIPELINE_STATE_MISMATCH = 610, + D3D12_MESSAGE_ID_PRIMITIVE_TOPOLOGY_MISMATCH_PIPELINE_STATE = 611, + D3D12_MESSAGE_ID_RENDER_TARGET_NUMBER_MISMATCH_PIPELINE_STATE = 612, + D3D12_MESSAGE_ID_RENDER_TARGET_FORMAT_MISMATCH_PIPELINE_STATE = 613, + D3D12_MESSAGE_ID_RENDER_TARGET_SAMPLE_DESC_MISMATCH_PIPELINE_STATE = 614, + D3D12_MESSAGE_ID_DEPTH_STENCIL_FORMAT_MISMATCH_PIPELINE_STATE = 615, + D3D12_MESSAGE_ID_DEPTH_STENCIL_SAMPLE_DESC_MISMATCH_PIPELINE_STATE = 616, + D3D12_MESSAGE_ID_RENDER_TARGET_NUMBER_MISMATCH_BUNDLE_PIPELINE_STATE = 617, + D3D12_MESSAGE_ID_RENDER_TARGET_FORMAT_MISMATCH_BUNDLE_PIPELINE_STATE = 618, + D3D12_MESSAGE_ID_RENDER_TARGET_SAMPLE_DESC_MISMATCH_BUNDLE_PIPELINE_STATE = 619, + D3D12_MESSAGE_ID_DEPTH_STENCIL_FORMAT_MISMATCH_BUNDLE_PIPELINE_STATE = 620, + D3D12_MESSAGE_ID_DEPTH_STENCIL_SAMPLE_DESC_MISMATCH_BUNDLE_PIPELINE_STATE = 621, + D3D12_MESSAGE_ID_CREATESHADER_INVALIDBYTECODE = 622, + D3D12_MESSAGE_ID_CREATEHEAP_NULLDESC = 623, + D3D12_MESSAGE_ID_CREATEHEAP_INVALIDSIZE = 624, + D3D12_MESSAGE_ID_CREATEHEAP_UNRECOGNIZEDHEAPTYPE = 625, + D3D12_MESSAGE_ID_CREATEHEAP_UNRECOGNIZEDCPUPAGEPROPERTIES = 626, + D3D12_MESSAGE_ID_CREATEHEAP_UNRECOGNIZEDMEMORYPOOL = 627, + D3D12_MESSAGE_ID_CREATEHEAP_INVALIDPROPERTIES = 628, + D3D12_MESSAGE_ID_CREATEHEAP_INVALIDALIGNMENT = 629, + D3D12_MESSAGE_ID_CREATEHEAP_UNRECOGNIZEDMISCFLAGS = 630, + D3D12_MESSAGE_ID_CREATEHEAP_INVALIDMISCFLAGS = 631, + D3D12_MESSAGE_ID_CREATEHEAP_INVALIDARG_RETURN = 632, + D3D12_MESSAGE_ID_CREATEHEAP_OUTOFMEMORY_RETURN = 633, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_NULLHEAPPROPERTIES = 634, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_UNRECOGNIZEDHEAPTYPE = 635, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_UNRECOGNIZEDCPUPAGEPROPERTIES = 636, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_UNRECOGNIZEDMEMORYPOOL = 637, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_INVALIDHEAPPROPERTIES = 638, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_UNRECOGNIZEDHEAPMISCFLAGS = 639, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS = 640, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_INVALIDARG_RETURN = 641, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_OUTOFMEMORY_RETURN = 642, + D3D12_MESSAGE_ID_GETCUSTOMHEAPPROPERTIES_UNRECOGNIZEDHEAPTYPE = 643, + D3D12_MESSAGE_ID_GETCUSTOMHEAPPROPERTIES_INVALIDHEAPTYPE = 644, + D3D12_MESSAGE_ID_CREATE_DESCRIPTOR_HEAP_INVALID_DESC = 645, + D3D12_MESSAGE_ID_INVALID_DESCRIPTOR_HANDLE = 646, + D3D12_MESSAGE_ID_CREATERASTERIZERSTATE_INVALID_CONSERVATIVERASTERMODE = 647, + D3D12_MESSAGE_ID_DEVICE_DRAW_INVALID_SYSTEMVALUE = 648, + D3D12_MESSAGE_ID_CREATE_CONSTANT_BUFFER_VIEW_INVALID_RESOURCE = 649, + D3D12_MESSAGE_ID_CREATE_CONSTANT_BUFFER_VIEW_INVALID_DESC = 650, + D3D12_MESSAGE_ID_CREATE_CONSTANT_BUFFER_VIEW_LARGE_OFFSET = 651, + D3D12_MESSAGE_ID_CREATE_UNORDEREDACCESS_VIEW_INVALID_COUNTER_USAGE = 652, + D3D12_MESSAGE_ID_COPY_DESCRIPTORS_INVALID_RANGES = 653, + D3D12_MESSAGE_ID_COPY_DESCRIPTORS_WRITE_ONLY_DESCRIPTOR = 654, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RTV_FORMAT_NOT_UNKNOWN = 655, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_RENDER_TARGET_COUNT = 656, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_VERTEX_SHADER_NOT_SET = 657, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INPUTLAYOUT_NOT_SET = 658, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_HS_DS_SIGNATURE_MISMATCH = 659, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_REGISTERINDEX = 660, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_COMPONENTTYPE = 661, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_REGISTERMASK = 662, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_SYSTEMVALUE = 663, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_NEVERWRITTEN_ALWAYSREADS = 664, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_MINPRECISION = 665, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_LINKAGE_SEMANTICNAME_NOT_FOUND = 666, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_HS_XOR_DS_MISMATCH = 667, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_HULL_SHADER_INPUT_TOPOLOGY_MISMATCH = 668, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_HS_DS_CONTROL_POINT_COUNT_MISMATCH = 669, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_HS_DS_TESSELLATOR_DOMAIN_MISMATCH = 670, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_USE_OF_CENTER_MULTISAMPLE_PATTERN = 671, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_USE_OF_FORCED_SAMPLE_COUNT = 672, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_PRIMITIVETOPOLOGY = 673, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_SYSTEMVALUE = 674, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_OM_DUAL_SOURCE_BLENDING_CAN_ONLY_HAVE_RENDER_TARGET_0 + = 675, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_OM_RENDER_TARGET_DOES_NOT_SUPPORT_BLENDING = 676, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_PS_OUTPUT_TYPE_MISMATCH = 677, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_OM_RENDER_TARGET_DOES_NOT_SUPPORT_LOGIC_OPS = 678, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET = 679, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET = 680, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_GS_INPUT_PRIMITIVE_MISMATCH = 681, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_POSITION_NOT_PRESENT = 682, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_MISSING_ROOT_SIGNATURE_FLAGS = 683, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_INDEX_BUFFER_PROPERTIES = 684, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_INVALID_SAMPLE_DESC = 685, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_HS_ROOT_SIGNATURE_MISMATCH = 686, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DS_ROOT_SIGNATURE_MISMATCH = 687, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_VS_ROOT_SIGNATURE_MISMATCH = 688, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_GS_ROOT_SIGNATURE_MISMATCH = 689, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_PS_ROOT_SIGNATURE_MISMATCH = 690, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_MISSING_ROOT_SIGNATURE = 691, + D3D12_MESSAGE_ID_EXECUTE_BUNDLE_OPEN_BUNDLE = 692, + D3D12_MESSAGE_ID_EXECUTE_BUNDLE_DESCRIPTOR_HEAP_MISMATCH = 693, + D3D12_MESSAGE_ID_EXECUTE_BUNDLE_TYPE = 694, + D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE = 695, + D3D12_MESSAGE_ID_CREATE_ROOT_SIGNATURE_BLOB_NOT_FOUND = 696, + D3D12_MESSAGE_ID_CREATE_ROOT_SIGNATURE_DESERIALIZE_FAILED = 697, + D3D12_MESSAGE_ID_CREATE_ROOT_SIGNATURE_INVALID_CONFIGURATION = 698, + D3D12_MESSAGE_ID_CREATE_ROOT_SIGNATURE_NOT_SUPPORTED_ON_DEVICE = 699, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_NULLRESOURCEPROPERTIES = 700, + D3D12_MESSAGE_ID_CREATERESOURCEANDHEAP_NULLHEAP = 701, + D3D12_MESSAGE_ID_GETRESOURCEALLOCATIONINFO_INVALIDRDESCS = 702, + D3D12_MESSAGE_ID_MAKERESIDENT_NULLOBJECTARRAY = 703, + D3D12_MESSAGE_ID_MAKERESIDENT_INVALIDOBJECT = 704, + D3D12_MESSAGE_ID_EVICT_NULLOBJECTARRAY = 705, + D3D12_MESSAGE_ID_EVICT_INVALIDOBJECT = 706, + D3D12_MESSAGE_ID_HEAPS_UNSUPPORTED = 707, + D3D12_MESSAGE_ID_SET_DESCRIPTOR_TABLE_INVALID = 708, + D3D12_MESSAGE_ID_SET_ROOT_CONSTANT_INVALID = 709, + D3D12_MESSAGE_ID_SET_ROOT_CONSTANT_BUFFER_VIEW_INVALID = 710, + D3D12_MESSAGE_ID_SET_ROOT_SHADER_RESOURCE_VIEW_INVALID = 711, + D3D12_MESSAGE_ID_SET_ROOT_UNORDERED_ACCESS_VIEW_INVALID = 712, + D3D12_MESSAGE_ID_SET_VERTEX_BUFFERS_INVALID_DESC = 713, + D3D12_MESSAGE_ID_SET_VERTEX_BUFFERS_LARGE_OFFSET = 714, + D3D12_MESSAGE_ID_SET_INDEX_BUFFER_INVALID_DESC = 715, + D3D12_MESSAGE_ID_SET_INDEX_BUFFER_LARGE_OFFSET = 716, + D3D12_MESSAGE_ID_SET_STREAM_OUTPUT_BUFFERS_INVALID_DESC = 717, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDDIMENSIONALITY = 718, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDLAYOUT = 719, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDDIMENSIONALITY = 720, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDALIGNMENT = 721, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDMIPLEVELS = 722, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDSAMPLEDESC = 723, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDLAYOUT = 724, + D3D12_MESSAGE_ID_SET_INDEX_BUFFER_INVALID = 725, + D3D12_MESSAGE_ID_SET_VERTEX_BUFFERS_INVALID = 726, + D3D12_MESSAGE_ID_SET_STREAM_OUTPUT_BUFFERS_INVALID = 727, + D3D12_MESSAGE_ID_SET_RENDER_TARGETS_INVALID = 728, + D3D12_MESSAGE_ID_CREATEQUERY_HEAP_INVALID_PARAMETERS = 729, + D3D12_MESSAGE_ID_CREATEQUERY_HEAP_JPEG_NOT_SUPPORTED = 730, + D3D12_MESSAGE_ID_BEGIN_END_QUERY_INVALID_PARAMETERS = 731, + D3D12_MESSAGE_ID_CLOSE_COMMAND_LIST_OPEN_QUERY = 732, + D3D12_MESSAGE_ID_RESOLVE_QUERY_DATA_INVALID_PARAMETERS = 733, + D3D12_MESSAGE_ID_SET_PREDICATION_INVALID_PARAMETERS = 734, + D3D12_MESSAGE_ID_TIMESTAMPS_NOT_SUPPORTED = 735, + D3D12_MESSAGE_ID_UNSTABLE_POWER_STATE = 736, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDFORMAT = 737, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDFORMAT = 738, + D3D12_MESSAGE_ID_GETCOPYABLELAYOUT_INVALIDSUBRESOURCERANGE = 739, + D3D12_MESSAGE_ID_GETCOPYABLELAYOUT_INVALIDBASEOFFSET = 740, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_INVALID_HEAP = 741, + D3D12_MESSAGE_ID_CREATE_SAMPLER_INVALID = 742, + D3D12_MESSAGE_ID_CREATECOMMANDSIGNATURE_INVALID = 743, + D3D12_MESSAGE_ID_EXECUTE_INDIRECT_INVALID_PARAMETERS = 744, + D3D12_MESSAGE_ID_GETGPUVIRTUALADDRESS_INVALID_RESOURCE_DIMENSION = 745, + D3D12_MESSAGE_ID_CREATEQUERYORPREDICATE_INVALIDCONTEXTTYPE = 746, + D3D12_MESSAGE_ID_CREATEQUERYORPREDICATE_DECODENOTSUPPORTED = 747, + D3D12_MESSAGE_ID_CREATEQUERYORPREDICATE_ENCODENOTSUPPORTED = 748, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDPLANEINDEX = 749, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_INVALIDVIDEOPLANEINDEX = 750, + D3D12_MESSAGE_ID_CREATESHADERRESOURCEVIEW_AMBIGUOUSVIDEOPLANEINDEX = 751, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDPLANEINDEX = 752, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_INVALIDVIDEOPLANEINDEX = 753, + D3D12_MESSAGE_ID_CREATERENDERTARGETVIEW_AMBIGUOUSVIDEOPLANEINDEX = 754, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDPLANEINDEX = 755, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_INVALIDVIDEOPLANEINDEX = 756, + D3D12_MESSAGE_ID_CREATEUNORDEREDACCESSVIEW_AMBIGUOUSVIDEOPLANEINDEX = 757, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDSCANDATAOFFSET = 758, + D3D12_MESSAGE_ID_JPEGDECODE_NOTSUPPORTED = 759, + D3D12_MESSAGE_ID_JPEGDECODE_DIMENSIONSTOOLARGE = 760, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDCOMPONENTS = 761, + D3D12_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDCOMPONENTS = 762, + D3D12_MESSAGE_ID_JPEGDECODE_DESTINATIONNOT2D = 763, + D3D12_MESSAGE_ID_JPEGDECODE_TILEDRESOURCESUNSUPPORTED = 764, + D3D12_MESSAGE_ID_JPEGDECODE_GUARDRECTSUNSUPPORTED = 765, + D3D12_MESSAGE_ID_JPEGDECODE_FORMATUNSUPPORTED = 766, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDSUBRESOURCE = 767, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDMIPLEVEL = 768, + D3D12_MESSAGE_ID_JPEGDECODE_EMPTYDESTBOX = 769, + D3D12_MESSAGE_ID_JPEGDECODE_DESTBOXNOT2D = 770, + D3D12_MESSAGE_ID_JPEGDECODE_DESTBOXNOTSUB = 771, + D3D12_MESSAGE_ID_JPEGDECODE_DESTBOXESINTERSECT = 772, + D3D12_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEMISMATCH = 773, + D3D12_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEMISMATCH = 774, + D3D12_MESSAGE_ID_JPEGDECODE_XSUBSAMPLEODD = 775, + D3D12_MESSAGE_ID_JPEGDECODE_YSUBSAMPLEODD = 776, + D3D12_MESSAGE_ID_JPEGDECODE_UPSCALEUNSUPPORTED = 777, + D3D12_MESSAGE_ID_JPEGDECODE_TIER4DOWNSCALETOLARGE = 778, + D3D12_MESSAGE_ID_JPEGDECODE_TIER3DOWNSCALEUNSUPPORTED = 779, + D3D12_MESSAGE_ID_JPEGDECODE_CHROMASIZEMISMATCH = 780, + D3D12_MESSAGE_ID_JPEGDECODE_LUMACHROMASIZEMISMATCH = 781, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDNUMDESTINATIONS = 782, + D3D12_MESSAGE_ID_JPEGDECODE_SUBBOXUNSUPPORTED = 783, + D3D12_MESSAGE_ID_JPEGDECODE_1DESTUNSUPPORTEDFORMAT = 784, + D3D12_MESSAGE_ID_JPEGDECODE_3DESTUNSUPPORTEDFORMAT = 785, + D3D12_MESSAGE_ID_JPEGDECODE_SCALEUNSUPPORTED = 786, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDSOURCESIZE = 787, + D3D12_MESSAGE_ID_JPEGDECODE_INVALIDCOPYFLAGS = 788, + D3D12_MESSAGE_ID_JPEGDECODE_HAZARD = 789, + D3D12_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERUSAGE = 790, + D3D12_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDSRCBUFFERMISCFLAGS = 791, + D3D12_MESSAGE_ID_JPEGDECODE_UNSUPPORTEDDSTTEXTUREUSAGE = 792, + D3D12_MESSAGE_ID_JPEGDECODE_BACKBUFFERNOTSUPPORTED = 793, + D3D12_MESSAGE_ID_JPEGDECODE_UNSUPPRTEDCOPYFLAGS = 794, + D3D12_MESSAGE_ID_JPEGENCODE_NOTSUPPORTED = 795, + D3D12_MESSAGE_ID_JPEGENCODE_INVALIDSCANDATAOFFSET = 796, + D3D12_MESSAGE_ID_JPEGENCODE_INVALIDCOMPONENTS = 797, + D3D12_MESSAGE_ID_JPEGENCODE_SOURCENOT2D = 798, + D3D12_MESSAGE_ID_JPEGENCODE_TILEDRESOURCESUNSUPPORTED = 799, + D3D12_MESSAGE_ID_JPEGENCODE_GUARDRECTSUNSUPPORTED = 800, + D3D12_MESSAGE_ID_JPEGENCODE_XSUBSAMPLEMISMATCH = 801, + D3D12_MESSAGE_ID_JPEGENCODE_YSUBSAMPLEMISMATCH = 802, + D3D12_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDCOMPONENTS = 803, + D3D12_MESSAGE_ID_JPEGENCODE_FORMATUNSUPPORTED = 804, + D3D12_MESSAGE_ID_JPEGENCODE_INVALIDSUBRESOURCE = 805, + D3D12_MESSAGE_ID_JPEGENCODE_INVALIDMIPLEVEL = 806, + D3D12_MESSAGE_ID_JPEGENCODE_DIMENSIONSTOOLARGE = 807, + D3D12_MESSAGE_ID_JPEGENCODE_HAZARD = 808, + D3D12_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERUSAGE = 809, + D3D12_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDDSTBUFFERMISCFLAGS = 810, + D3D12_MESSAGE_ID_JPEGENCODE_UNSUPPORTEDSRCTEXTUREUSAGE = 811, + D3D12_MESSAGE_ID_JPEGENCODE_BACKBUFFERNOTSUPPORTED = 812, + D3D12_MESSAGE_ID_CREATEQUERYORPREDICATE_UNSUPPORTEDCONTEXTTTYPEFORQUERY = 813, + D3D12_MESSAGE_ID_FLUSH1_INVALIDCONTEXTTYPE = 814, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDCLEARVALUE = 815, + D3D12_MESSAGE_ID_CREATERESOURCE_UNRECOGNIZEDCLEARVALUEFORMAT = 816, + D3D12_MESSAGE_ID_CREATERESOURCE_INVALIDCLEARVALUEFORMAT = 817, + D3D12_MESSAGE_ID_CREATERESOURCE_CLEARVALUEDENORMFLUSH = 818, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_INVALIDDEPTH = 819, + D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE = 820, + D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE = 821, + D3D12_MESSAGE_ID_MAP_INVALIDHEAP = 822, + D3D12_MESSAGE_ID_UNMAP_INVALIDHEAP = 823, + D3D12_MESSAGE_ID_MAP_INVALIDRESOURCE = 824, + D3D12_MESSAGE_ID_UNMAP_INVALIDRESOURCE = 825, + D3D12_MESSAGE_ID_MAP_INVALIDSUBRESOURCE = 826, + D3D12_MESSAGE_ID_UNMAP_INVALIDSUBRESOURCE = 827, + D3D12_MESSAGE_ID_MAP_INVALIDRANGE = 828, + D3D12_MESSAGE_ID_UNMAP_INVALIDRANGE = 829, + D3D12_MESSAGE_ID_MAP_NULLRANGE = 830, + D3D12_MESSAGE_ID_UNMAP_NULLRANGE = 831, + D3D12_MESSAGE_ID_MAP_INVALIDDATAPOINTER = 832, + D3D12_MESSAGE_ID_MAP_INVALIDARG_RETURN = 833, + D3D12_MESSAGE_ID_MAP_OUTOFMEMORY_RETURN = 834, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_BUNDLENOTSUPPORTED = 835, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_COMMANDLISTMISMATCH = 836, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_OPENCOMMANDLIST = 837, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_FAILEDCOMMANDLIST = 838, + D3D12_MESSAGE_ID_COPYBUFFERREGION_NULLDST = 839, + D3D12_MESSAGE_ID_COPYBUFFERREGION_INVALIDDSTRESOURCEDIMENSION = 840, + D3D12_MESSAGE_ID_COPYBUFFERREGION_DSTRANGEOUTOFBOUNDS = 841, + D3D12_MESSAGE_ID_COPYBUFFERREGION_NULLSRC = 842, + D3D12_MESSAGE_ID_COPYBUFFERREGION_INVALIDSRCRESOURCEDIMENSION = 843, + D3D12_MESSAGE_ID_COPYBUFFERREGION_SRCRANGEOUTOFBOUNDS = 844, + D3D12_MESSAGE_ID_COPYBUFFERREGION_INVALIDCOPYFLAGS = 845, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_NULLDST = 846, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_UNRECOGNIZEDDSTTYPE = 847, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTRESOURCEDIMENSION = 848, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTRESOURCE = 849, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTSUBRESOURCE = 850, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTOFFSET = 851, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_UNRECOGNIZEDDSTFORMAT = 852, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTFORMAT = 853, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTDIMENSIONS = 854, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTROWPITCH = 855, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTPLACEMENT = 856, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTDSPLACEDFOOTPRINTFORMAT = 857, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_DSTREGIONOUTOFBOUNDS = 858, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_NULLSRC = 859, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_UNRECOGNIZEDSRCTYPE = 860, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCRESOURCEDIMENSION = 861, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCRESOURCE = 862, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCSUBRESOURCE = 863, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCOFFSET = 864, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_UNRECOGNIZEDSRCFORMAT = 865, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCFORMAT = 866, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCDIMENSIONS = 867, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCROWPITCH = 868, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCPLACEMENT = 869, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCDSPLACEDFOOTPRINTFORMAT = 870, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_SRCREGIONOUTOFBOUNDS = 871, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDDSTCOORDINATES = 872, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDSRCBOX = 873, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_FORMATMISMATCH = 874, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_EMPTYBOX = 875, + D3D12_MESSAGE_ID_COPYTEXTUREREGION_INVALIDCOPYFLAGS = 876, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_INVALID_SUBRESOURCE_INDEX = 877, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_INVALID_FORMAT = 878, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_RESOURCE_MISMATCH = 879, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_INVALID_SAMPLE_COUNT = 880, + D3D12_MESSAGE_ID_CREATECOMPUTEPIPELINESTATE_INVALID_SHADER = 881, + D3D12_MESSAGE_ID_CREATECOMPUTEPIPELINESTATE_CS_ROOT_SIGNATURE_MISMATCH = 882, + D3D12_MESSAGE_ID_CREATECOMPUTEPIPELINESTATE_MISSING_ROOT_SIGNATURE = 883, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_INVALIDCACHEDBLOB = 884, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_CACHEDBLOBADAPTERMISMATCH = 885, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_CACHEDBLOBDRIVERVERSIONMISMATCH = 886, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_CACHEDBLOBDESCMISMATCH = 887, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_CACHEDBLOBIGNORED = 888, + D3D12_MESSAGE_ID_WRITETOSUBRESOURCE_INVALIDHEAP = 889, + D3D12_MESSAGE_ID_WRITETOSUBRESOURCE_INVALIDRESOURCE = 890, + D3D12_MESSAGE_ID_WRITETOSUBRESOURCE_INVALIDBOX = 891, + D3D12_MESSAGE_ID_WRITETOSUBRESOURCE_INVALIDSUBRESOURCE = 892, + D3D12_MESSAGE_ID_WRITETOSUBRESOURCE_EMPTYBOX = 893, + D3D12_MESSAGE_ID_READFROMSUBRESOURCE_INVALIDHEAP = 894, + D3D12_MESSAGE_ID_READFROMSUBRESOURCE_INVALIDRESOURCE = 895, + D3D12_MESSAGE_ID_READFROMSUBRESOURCE_INVALIDBOX = 896, + D3D12_MESSAGE_ID_READFROMSUBRESOURCE_INVALIDSUBRESOURCE = 897, + D3D12_MESSAGE_ID_READFROMSUBRESOURCE_EMPTYBOX = 898, + D3D12_MESSAGE_ID_TOO_MANY_NODES_SPECIFIED = 899, + D3D12_MESSAGE_ID_INVALID_NODE_INDEX = 900, + D3D12_MESSAGE_ID_GETHEAPPROPERTIES_INVALIDRESOURCE = 901, + D3D12_MESSAGE_ID_NODE_MASK_MISMATCH = 902, + D3D12_MESSAGE_ID_COMMAND_LIST_OUTOFMEMORY = 903, + D3D12_MESSAGE_ID_COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES = 904, + D3D12_MESSAGE_ID_COMMAND_LIST_TOO_MANY_SWAPCHAIN_REFERENCES = 905, + D3D12_MESSAGE_ID_COMMAND_QUEUE_TOO_MANY_SWAPCHAIN_REFERENCES = 906, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE = 907, + D3D12_MESSAGE_ID_COMMAND_LIST_SETRENDERTARGETS_INVALIDNUMRENDERTARGETS = 908, + D3D12_MESSAGE_ID_CREATE_QUEUE_INVALID_TYPE = 909, + D3D12_MESSAGE_ID_CREATE_QUEUE_INVALID_FLAGS = 910, + D3D12_MESSAGE_ID_CREATESHAREDRESOURCE_INVALIDFLAGS = 911, + D3D12_MESSAGE_ID_CREATESHAREDRESOURCE_INVALIDFORMAT = 912, + D3D12_MESSAGE_ID_CREATESHAREDHEAP_INVALIDFLAGS = 913, + D3D12_MESSAGE_ID_REFLECTSHAREDPROPERTIES_UNRECOGNIZEDPROPERTIES = 914, + D3D12_MESSAGE_ID_REFLECTSHAREDPROPERTIES_INVALIDSIZE = 915, + D3D12_MESSAGE_ID_REFLECTSHAREDPROPERTIES_INVALIDOBJECT = 916, + D3D12_MESSAGE_ID_KEYEDMUTEX_INVALIDOBJECT = 917, + D3D12_MESSAGE_ID_KEYEDMUTEX_INVALIDKEY = 918, + D3D12_MESSAGE_ID_KEYEDMUTEX_WRONGSTATE = 919, + D3D12_MESSAGE_ID_CREATE_QUEUE_INVALID_PRIORITY = 920, + D3D12_MESSAGE_ID_OBJECT_DELETED_WHILE_STILL_IN_USE = 921, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_INVALID_FLAGS = 922, + D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE = 923, + D3D12_MESSAGE_ID_COMMAND_LIST_DRAW_RENDER_TARGET_DELETED = 924, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_ALL_RENDER_TARGETS_HAVE_UNKNOWN_FORMAT = 925, + D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS = 926, + D3D12_MESSAGE_ID_EXECUTECOMMANDLISTS_GPU_WRITTEN_READBACK_RESOURCE_MAPPED = 927, + D3D12_MESSAGE_ID_UNMAP_RANGE_NOT_NEEDED = 928, + D3D12_MESSAGE_ID_UNMAP_RANGE_NOT_EMPTY = 929, + D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE = 930, + D3D12_MESSAGE_ID_UNMAP_INVALID_NULLRANGE = 931, + D3D12_MESSAGE_ID_NO_GRAPHICS_API_SUPPORT = 932, + D3D12_MESSAGE_ID_NO_COMPUTE_API_SUPPORT = 933, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_RESOURCE_FLAGS_NOT_SUPPORTED = 934, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_ROOT_ARGUMENT_UNINITIALIZED = 935, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_DESCRIPTOR_HEAP_INDEX_OUT_OF_BOUNDS = 936, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_DESCRIPTOR_TABLE_REGISTER_INDEX_OUT_OF_BOUNDS = 937, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_DESCRIPTOR_UNINITIALIZED = 938, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_DESCRIPTOR_TYPE_MISMATCH = 939, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_SRV_RESOURCE_DIMENSION_MISMATCH = 940, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_UAV_RESOURCE_DIMENSION_MISMATCH = 941, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_INCOMPATIBLE_RESOURCE_STATE = 942, + D3D12_MESSAGE_ID_COPYRESOURCE_NULLDST = 943, + D3D12_MESSAGE_ID_COPYRESOURCE_INVALIDDSTRESOURCE = 944, + D3D12_MESSAGE_ID_COPYRESOURCE_NULLSRC = 945, + D3D12_MESSAGE_ID_COPYRESOURCE_INVALIDSRCRESOURCE = 946, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_NULLDST = 947, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_INVALIDDSTRESOURCE = 948, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_NULLSRC = 949, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCE_INVALIDSRCRESOURCE = 950, + D3D12_MESSAGE_ID_PIPELINE_STATE_TYPE_MISMATCH = 951, + D3D12_MESSAGE_ID_COMMAND_LIST_DISPATCH_ROOT_SIGNATURE_NOT_SET = 952, + D3D12_MESSAGE_ID_COMMAND_LIST_DISPATCH_ROOT_SIGNATURE_MISMATCH = 953, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_ZERO_BARRIERS = 954, + D3D12_MESSAGE_ID_BEGIN_END_EVENT_MISMATCH = 955, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_POSSIBLE_BEFORE_AFTER_MISMATCH = 956, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_BEGIN_END = 957, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_INVALID_RESOURCE = 958, + D3D12_MESSAGE_ID_USE_OF_ZERO_REFCOUNT_OBJECT = 959, + D3D12_MESSAGE_ID_OBJECT_EVICTED_WHILE_STILL_IN_USE = 960, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_ROOT_DESCRIPTOR_ACCESS_OUT_OF_BOUNDS = 961, + D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_INVALIDLIBRARYBLOB = 962, + D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_DRIVERVERSIONMISMATCH = 963, + D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_ADAPTERVERSIONMISMATCH = 964, + D3D12_MESSAGE_ID_CREATEPIPELINELIBRARY_UNSUPPORTED = 965, + D3D12_MESSAGE_ID_CREATE_PIPELINELIBRARY = 966, + D3D12_MESSAGE_ID_LIVE_PIPELINELIBRARY = 967, + D3D12_MESSAGE_ID_DESTROY_PIPELINELIBRARY = 968, + D3D12_MESSAGE_ID_STOREPIPELINE_NONAME = 969, + D3D12_MESSAGE_ID_STOREPIPELINE_DUPLICATENAME = 970, + D3D12_MESSAGE_ID_LOADPIPELINE_NAMENOTFOUND = 971, + D3D12_MESSAGE_ID_LOADPIPELINE_INVALIDDESC = 972, + D3D12_MESSAGE_ID_PIPELINELIBRARY_SERIALIZE_NOTENOUGHMEMORY = 973, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_PS_OUTPUT_RT_OUTPUT_MISMATCH = 974, + D3D12_MESSAGE_ID_SETEVENTONMULTIPLEFENCECOMPLETION_INVALIDFLAGS = 975, + D3D12_MESSAGE_ID_CREATE_QUEUE_VIDEO_NOT_SUPPORTED = 976, + D3D12_MESSAGE_ID_CREATE_COMMAND_ALLOCATOR_VIDEO_NOT_SUPPORTED = 977, + D3D12_MESSAGE_ID_CREATEQUERY_HEAP_VIDEO_DECODE_STATISTICS_NOT_SUPPORTED = 978, + D3D12_MESSAGE_ID_CREATE_VIDEODECODECOMMANDLIST = 979, + D3D12_MESSAGE_ID_CREATE_VIDEODECODER = 980, + D3D12_MESSAGE_ID_CREATE_VIDEODECODESTREAM = 981, + D3D12_MESSAGE_ID_LIVE_VIDEODECODECOMMANDLIST = 982, + D3D12_MESSAGE_ID_LIVE_VIDEODECODER = 983, + D3D12_MESSAGE_ID_LIVE_VIDEODECODESTREAM = 984, + D3D12_MESSAGE_ID_DESTROY_VIDEODECODECOMMANDLIST = 985, + D3D12_MESSAGE_ID_DESTROY_VIDEODECODER = 986, + D3D12_MESSAGE_ID_DESTROY_VIDEODECODESTREAM = 987, + D3D12_MESSAGE_ID_DECODE_FRAME_INVALID_PARAMETERS = 988, + D3D12_MESSAGE_ID_DEPRECATED_API = 989, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE = 990, + D3D12_MESSAGE_ID_COMMAND_LIST_DESCRIPTOR_TABLE_NOT_SET = 991, + D3D12_MESSAGE_ID_COMMAND_LIST_ROOT_CONSTANT_BUFFER_VIEW_NOT_SET = 992, + D3D12_MESSAGE_ID_COMMAND_LIST_ROOT_SHADER_RESOURCE_VIEW_NOT_SET = 993, + D3D12_MESSAGE_ID_COMMAND_LIST_ROOT_UNORDERED_ACCESS_VIEW_NOT_SET = 994, + D3D12_MESSAGE_ID_DISCARD_INVALID_SUBRESOURCE_RANGE = 995, + D3D12_MESSAGE_ID_DISCARD_ONE_SUBRESOURCE_FOR_MIPS_WITH_RECTS = 996, + D3D12_MESSAGE_ID_DISCARD_NO_RECTS_FOR_NON_TEXTURE2D = 997, + D3D12_MESSAGE_ID_COPY_ON_SAME_SUBRESOURCE = 998, + D3D12_MESSAGE_ID_SETRESIDENCYPRIORITY_INVALID_PAGEABLE = 999, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_UNSUPPORTED = 1000, + D3D12_MESSAGE_ID_STATIC_DESCRIPTOR_INVALID_DESCRIPTOR_CHANGE = 1001, + D3D12_MESSAGE_ID_DATA_STATIC_DESCRIPTOR_INVALID_DATA_CHANGE = 1002, + D3D12_MESSAGE_ID_DATA_STATIC_WHILE_SET_AT_EXECUTE_DESCRIPTOR_INVALID_DATA_CHANGE = 1003, + D3D12_MESSAGE_ID_EXECUTE_BUNDLE_STATIC_DESCRIPTOR_DATA_STATIC_NOT_SET = 1004, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_RESOURCE_ACCESS_OUT_OF_BOUNDS = 1005, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_SAMPLER_MODE_MISMATCH = 1006, + D3D12_MESSAGE_ID_CREATE_FENCE_INVALID_FLAGS = 1007, + D3D12_MESSAGE_ID_RESOURCE_BARRIER_DUPLICATE_SUBRESOURCE_TRANSITIONS = 1008, + D3D12_MESSAGE_ID_SETRESIDENCYPRIORITY_INVALID_PRIORITY = 1009, + D3D12_MESSAGE_ID_CREATE_PASS = 1010, + D3D12_MESSAGE_ID_DESTROY_PASS = 1011, + D3D12_MESSAGE_ID_LIVE_PASS = 1012, + D3D12_MESSAGE_ID_CREATE_DESCRIPTOR_HEAP_LARGE_NUM_DESCRIPTORS = 1013, + D3D12_MESSAGE_ID_BEGIN_EVENT = 1014, + D3D12_MESSAGE_ID_END_EVENT = 1015, + D3D12_MESSAGE_ID_CREATEDEVICE_DEBUG_LAYER_STARTUP_OPTIONS = 1016, + D3D12_MESSAGE_ID_CREATEDEPTHSTENCILSTATE_DEPTHBOUNDSTEST_UNSUPPORTED = 1017, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_DUPLICATE_SUBOBJECT = 1018, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_UNKNOWN_SUBOBJECT = 1019, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_ZERO_SIZE_STREAM = 1020, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_INVALID_STREAM = 1021, + D3D12_MESSAGE_ID_CREATEPIPELINESTATE_CANNOT_DEDUCE_TYPE = 1022, + D3D12_MESSAGE_ID_COMMAND_LIST_STATIC_DESCRIPTOR_RESOURCE_DIMENSION_MISMATCH = 1023, + D3D12_MESSAGE_ID_CREATE_COMMAND_QUEUE_INSUFFICIENT_PRIVILEGE_FOR_GLOBAL_REALTIME = 1024, + D3D12_MESSAGE_ID_CREATE_COMMAND_QUEUE_INSUFFICIENT_HARDWARE_SUPPORT_FOR_GLOBAL_REALTIME = 1025, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_ARCHITECTURE = 1026, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_NULL_DST = 1027, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_DST_RESOURCE_DIMENSION = 1028, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_DST_RANGE_OUT_OF_BOUNDS = 1029, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_NULL_SRC = 1030, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_SRC_RESOURCE_DIMENSION = 1031, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_SRC_RANGE_OUT_OF_BOUNDS = 1032, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_OFFSET_ALIGNMENT = 1033, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_NULL_DEPENDENT_RESOURCES = 1034, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_NULL_DEPENDENT_SUBRESOURCE_RANGES = 1035, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_DEPENDENT_RESOURCE = 1036, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_INVALID_DEPENDENT_SUBRESOURCE_RANGE = 1037, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_DEPENDENT_SUBRESOURCE_OUT_OF_BOUNDS = 1038, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_DEPENDENT_RANGE_OUT_OF_BOUNDS = 1039, + D3D12_MESSAGE_ID_ATOMICCOPYBUFFER_ZERO_DEPENDENCIES = 1040, + D3D12_MESSAGE_ID_DEVICE_CREATE_SHARED_HANDLE_INVALIDARG = 1041, + D3D12_MESSAGE_ID_DESCRIPTOR_HANDLE_WITH_INVALID_RESOURCE = 1042, + D3D12_MESSAGE_ID_SETDEPTHBOUNDS_INVALIDARGS = 1043, + D3D12_MESSAGE_ID_GPU_BASED_VALIDATION_RESOURCE_STATE_IMPRECISE = 1044, + D3D12_MESSAGE_ID_COMMAND_LIST_PIPELINE_STATE_NOT_SET = 1045, + D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_SHADER_MODEL_MISMATCH = 1046, + D3D12_MESSAGE_ID_OBJECT_ACCESSED_WHILE_STILL_IN_USE = 1047, + D3D12_MESSAGE_ID_PROGRAMMABLE_MSAA_UNSUPPORTED = 1048, + D3D12_MESSAGE_ID_SETSAMPLEPOSITIONS_INVALIDARGS = 1049, + D3D12_MESSAGE_ID_RESOLVESUBRESOURCEREGION_INVALID_RECT = 1050, + D3D12_MESSAGE_ID_CREATE_VIDEODECODECOMMANDQUEUE = 1051, + D3D12_MESSAGE_ID_CREATE_VIDEOPROCESSCOMMANDLIST = 1052, + D3D12_MESSAGE_ID_CREATE_VIDEOPROCESSCOMMANDQUEUE = 1053, + D3D12_MESSAGE_ID_LIVE_VIDEODECODECOMMANDQUEUE = 1054, + D3D12_MESSAGE_ID_LIVE_VIDEOPROCESSCOMMANDLIST = 1055, + D3D12_MESSAGE_ID_LIVE_VIDEOPROCESSCOMMANDQUEUE = 1056, + D3D12_MESSAGE_ID_DESTROY_VIDEODECODECOMMANDQUEUE = 1057, + D3D12_MESSAGE_ID_DESTROY_VIDEOPROCESSCOMMANDLIST = 1058, + D3D12_MESSAGE_ID_DESTROY_VIDEOPROCESSCOMMANDQUEUE = 1059, + D3D12_MESSAGE_ID_CREATE_VIDEOPROCESSOR = 1060, + D3D12_MESSAGE_ID_CREATE_VIDEOPROCESSSTREAM = 1061, + D3D12_MESSAGE_ID_LIVE_VIDEOPROCESSOR = 1062, + D3D12_MESSAGE_ID_LIVE_VIDEOPROCESSSTREAM = 1063, + D3D12_MESSAGE_ID_DESTROY_VIDEOPROCESSOR = 1064, + D3D12_MESSAGE_ID_DESTROY_VIDEOPROCESSSTREAM = 1065, + D3D12_MESSAGE_ID_PROCESS_FRAME_INVALID_PARAMETERS = 1066, + D3D12_MESSAGE_ID_COPY_INVALIDLAYOUT = 1067, + D3D12_MESSAGE_ID_D3D12_MESSAGES_END = 1068, +}} +STRUCT!{struct D3D12_MESSAGE { + Category: D3D12_MESSAGE_CATEGORY, + Severity: D3D12_MESSAGE_SEVERITY, + ID: D3D12_MESSAGE_ID, + pDescription: *const c_char, + DescriptionByteLength: SIZE_T, +}} +STRUCT!{struct D3D12_INFO_QUEUE_FILTER_DESC { + NumCategories: UINT, + pCategoryList: *mut D3D12_MESSAGE_CATEGORY, + NumSeverities: UINT, + pSeverityList: *mut D3D12_MESSAGE_SEVERITY, + NumIDs: UINT, + pIDList: *mut D3D12_MESSAGE_ID, +}} +STRUCT!{struct D3D12_INFO_QUEUE_FILTER { + AllowList: D3D12_INFO_QUEUE_FILTER_DESC, + DenyList: D3D12_INFO_QUEUE_FILTER_DESC, +}} +pub const D3D12_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT: UINT = 1024; +RIDL!{#[uuid(0x0742a90b, 0xc387, 0x483f, 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58)] +interface ID3D12InfoQueue(ID3D12InfoQueueVtbl): IUnknown(IUnknownVtbl) { + fn SetMessageCountLimit( + MessageCountLimit: UINT64, + ) -> HRESULT, + fn ClearStoredMessages() -> (), + fn GetMessage( + MessageIndex: UINT64, + pMessage: *mut D3D12_MESSAGE, + pMessageByteLength: *mut SIZE_T, + ) -> HRESULT, + fn GetNumMessagesAllowedByStorageFilter() -> UINT64, + fn GetNumMessagesDeniedByStorageFilter() -> UINT64, + fn GetNumStoredMessages() -> UINT64, + fn GetNumStoredMessagesAllowedByRetrievalFilter() -> UINT64, + fn GetNumMessagesDiscardedByMessageCountLimit() -> UINT64, + fn GetMessageCountLimit() -> UINT64, + fn AddStorageFilterEntries( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetStorageFilter( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearStorageFilter() -> (), + fn PushEmptyStorageFilter() -> HRESULT, + fn PushCopyOfStorageFilter() -> HRESULT, + fn PushStorageFilter( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopStorageFilter() -> (), + fn GetStorageFilterStackSize() -> UINT, + fn AddRetrievalFilterEntries( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetRetrievalFilter( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearRetrievalFilter() -> (), + fn PushEmptyRetrievalFilter() -> HRESULT, + fn PushCopyOfRetrievalFilter() -> HRESULT, + fn PushRetrievalFilter( + pFilter: *mut D3D12_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopRetrievalFilter() -> (), + fn GetRetrievalFilterStackSize() -> UINT, + fn AddMessage( + Category: D3D12_MESSAGE_CATEGORY, + Severity: D3D12_MESSAGE_SEVERITY, + ID: D3D12_MESSAGE_ID, + pDescription: LPCSTR, + ) -> HRESULT, + fn AddApplicationMessage( + Severity: D3D12_MESSAGE_SEVERITY, + pDescription: LPCSTR, + ) -> HRESULT, + fn SetBreakOnCategory( + Category: D3D12_MESSAGE_CATEGORY, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnSeverity( + Severity: D3D12_MESSAGE_SEVERITY, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnID( + ID: D3D12_MESSAGE_ID, + bEnable: BOOL, + ) -> HRESULT, + fn GetBreakOnCategory( + Category: D3D12_MESSAGE_CATEGORY, + ) -> BOOL, + fn GetBreakOnSeverity( + Severity: D3D12_MESSAGE_SEVERITY, + ) -> BOOL, + fn GetBreakOnID( + ID: D3D12_MESSAGE_ID, + ) -> BOOL, + fn SetMuteDebugOutput( + bMute: BOOL, + ) -> (), + fn GetMuteDebugOutput() -> BOOL, +}} +DEFINE_GUID!{IID_ID3D12Debug, + 0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0} +DEFINE_GUID!{IID_ID3D12Debug1, + 0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04} +DEFINE_GUID!{IID_ID3D12Debug2, + 0x93a665c4, 0xa3b2, 0x4e5d, 0xb6, 0x92, 0xa2, 0x6a, 0xe1, 0x4e, 0x33, 0x74} +DEFINE_GUID!{IID_ID3D12DebugDevice1, + 0xa9b71770, 0xd099, 0x4a65, 0xa6, 0x98, 0x3d, 0xee, 0x10, 0x02, 0x0f, 0x88} +DEFINE_GUID!{IID_ID3D12DebugDevice, + 0x3febd6dd, 0x4973, 0x4787, 0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e} +DEFINE_GUID!{IID_ID3D12DebugCommandQueue, + 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3a} +DEFINE_GUID!{IID_ID3D12DebugCommandList1, + 0x102ca951, 0x311b, 0x4b01, 0xb1, 0x1f, 0xec, 0xb8, 0x3e, 0x06, 0x1b, 0x37} +DEFINE_GUID!{IID_ID3D12DebugCommandList, + 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3f} +DEFINE_GUID!{IID_ID3D12InfoQueue, + 0x0742a90b, 0xc387, 0x483f, 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58} diff --git a/winapi/src/um/d3d12shader.rs b/winapi/src/um/d3d12shader.rs new file mode 100644 index 000000000..f07bf83a6 --- /dev/null +++ b/winapi/src/um/d3d12shader.rs @@ -0,0 +1,347 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::minwindef::{BOOL, BYTE, INT, LPVOID, UINT}; +use um::d3dcommon::{ + D3D_CBUFFER_TYPE, D3D_FEATURE_LEVEL, D3D_INTERPOLATION_MODE, D3D_MIN_PRECISION, D3D_NAME, + D3D_PARAMETER_FLAGS, D3D_PRIMITIVE, D3D_PRIMITIVE_TOPOLOGY, D3D_REGISTER_COMPONENT_TYPE, + D3D_RESOURCE_RETURN_TYPE, D3D_SHADER_INPUT_TYPE, D3D_SHADER_VARIABLE_CLASS, + D3D_SHADER_VARIABLE_TYPE, D3D_SRV_DIMENSION, D3D_TESSELLATOR_DOMAIN, + D3D_TESSELLATOR_OUTPUT_PRIMITIVE, D3D_TESSELLATOR_PARTITIONING, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +ENUM!{enum D3D12_SHADER_VERSION_TYPE { + D3D12_SHVER_PIXEL_SHADER = 0x0, + D3D12_SHVER_VERTEX_SHADER = 0x1, + D3D12_SHVER_GEOMETRY_SHADER = 0x2, + D3D12_SHVER_HULL_SHADER = 0x3, + D3D12_SHVER_DOMAIN_SHADER = 0x4, + D3D12_SHVER_COMPUTE_SHADER = 0x5, + D3D12_SHVER_RESERVED0 = 0xFFF0, +}} +STRUCT!{struct D3D12_FUNCTION_DESC { + Version: UINT, + Creator: LPCSTR, + Flags: UINT, + ConstantBuffers: UINT, + BoundResources: UINT, + InstructionCount: UINT, + TempRegisterCount: UINT, + TempArrayCount: UINT, + DefCount: UINT, + DclCount: UINT, + TextureNormalInstructions: UINT, + TextureLoadInstructions: UINT, + TextureCompInstructions: UINT, + TextureBiasInstructions: UINT, + TextureGradientInstructions: UINT, + FloatInstructionCount: UINT, + IntInstructionCount: UINT, + UintInstructionCount: UINT, + StaticFlowControlCount: UINT, + DynamicFlowControlCount: UINT, + MacroInstructionCount: UINT, + ArrayInstructionCount: UINT, + MovInstructionCount: UINT, + MovcInstructionCount: UINT, + ConversionInstructionCount: UINT, + BitwiseInstructionCount: UINT, + MinFeatureLevel: D3D_FEATURE_LEVEL, + RequiredFeatureFlags: UINT64, + Name: LPCSTR, + FunctionParameterCount: INT, + HasReturn: BOOL, + Has10Level9VertexShader: BOOL, + Has10Level9PixelShader: BOOL, +}} +STRUCT!{struct D3D12_LIBRARY_DESC { + Creator: LPCSTR, + Flags: UINT, + FunctionCount: UINT, +}} +STRUCT!{struct D3D12_PARAMETER_DESC { + Name: LPCSTR, + SemanticName: LPCSTR, + Type: D3D_SHADER_VARIABLE_TYPE, + Class: D3D_SHADER_VARIABLE_CLASS, + Rows: UINT, + Columns: UINT, + InterpolationMode: D3D_INTERPOLATION_MODE, + Flags: D3D_PARAMETER_FLAGS, + FirstInRegister: UINT, + FirstInComponent: UINT, + FirstOutRegister: UINT, + FirstOutComponent: UINT, +}} +STRUCT!{struct D3D12_SHADER_BUFFER_DESC { + Name: LPCSTR, + Type: D3D_CBUFFER_TYPE, + Variables: UINT, + Size: UINT, + uFlags: UINT, +}} +STRUCT!{struct D3D12_SHADER_DESC { + Version: UINT, + Creator: LPCSTR, + Flags: UINT, + ConstantBuffers: UINT, + BoundResources: UINT, + InputParameters: UINT, + OutputParameters: UINT, + InstructionCount: UINT, + TempRegisterCount: UINT, + TempArrayCount: UINT, + DefCount: UINT, + DclCount: UINT, + TextureNormalInstructions: UINT, + TextureLoadInstructions: UINT, + TextureCompInstructions: UINT, + TextureBiasInstructions: UINT, + TextureGradientInstructions: UINT, + FloatInstructionCount: UINT, + IntInstructionCount: UINT, + UintInstructionCount: UINT, + StaticFlowControlCount: UINT, + DynamicFlowControlCount: UINT, + MacroInstructionCount: UINT, + ArrayInstructionCount: UINT, + CutInstructionCount: UINT, + EmitInstructionCount: UINT, + GSOutputTopology: D3D_PRIMITIVE_TOPOLOGY, + GSMaxOutputVertexCount: UINT, + InputPrimitive: D3D_PRIMITIVE, + PatchConstantParameters: UINT, + cGSInstanceCount: UINT, + cControlPoints: UINT, + HSOutputPrimitive: D3D_TESSELLATOR_OUTPUT_PRIMITIVE, + HSPartitioning: D3D_TESSELLATOR_PARTITIONING, + TessellatorDomain: D3D_TESSELLATOR_DOMAIN, + cBarrierInstructions: UINT, + cInterlockedInstructions: UINT, + cTextureStoreInstructions: UINT, +}} +STRUCT!{struct D3D12_SHADER_INPUT_BIND_DESC { + Name: LPCSTR, + Type: D3D_SHADER_INPUT_TYPE, + BindPoint: UINT, + BindCount: UINT, + uFlags: UINT, + ReturnType: D3D_RESOURCE_RETURN_TYPE, + Dimension: D3D_SRV_DIMENSION, + NumSamples: UINT, + Space: UINT, + uID: UINT, +}} +STRUCT!{struct D3D12_SHADER_TYPE_DESC { + Class: D3D_SHADER_VARIABLE_CLASS, + Type: D3D_SHADER_VARIABLE_TYPE, + Rows: UINT, + Columns: UINT, + Elements: UINT, + Members: UINT, + Offset: UINT, + Name: LPCSTR, +}} +STRUCT!{struct D3D12_SHADER_VARIABLE_DESC { + Name: LPCSTR, + StartOffset: UINT, + Size: UINT, + uFlags: UINT, + DefaultValue: LPVOID, + StartTexture: UINT, + TextureSize: UINT, + StartSampler: UINT, + SamplerSize: UINT, +}} +STRUCT!{struct D3D12_SIGNATURE_PARAMETER_DESC { + SemanticName: LPCSTR, + SemanticIndex: UINT, + Register: UINT, + SystemValueType: D3D_NAME, + ComponentType: D3D_REGISTER_COMPONENT_TYPE, + Mask: BYTE, + ReadWriteMask: BYTE, + Stream: UINT, + MinPrecision: D3D_MIN_PRECISION, +}} +RIDL!{#[uuid(0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x02, 0xcc, 0x33, 0x75, 0x73, 0x3f)] +interface ID3D12FunctionParameterReflection(ID3D12FunctionParameterReflectionVtbl) { + fn GetDesc( + pDesc: *mut D3D12_PARAMETER_DESC, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99)] +interface ID3D12FunctionReflection(ID3D12FunctionReflectionVtbl) { + fn GetDesc( + pDesc: *mut D3D12_FUNCTION_DESC, + ) -> HRESULT, + fn GetConstantBufferByIndex( + BufferIndex: UINT, + ) -> *mut ID3D12ShaderReflectionConstantBuffer, + fn GetConstantBufferByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionConstantBuffer, + fn GetResourceBindingDesc( + ResourceIndex: UINT, + pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionVariable, + fn GetResourceBindingDescByName( + Name: LPCSTR, + pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetFunctionParameter( + ParameterIndex: INT, + ) -> *mut ID3D12FunctionParameterReflection, +}} +RIDL!{#[uuid(0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x4)] +interface ID3D12LibraryReflection(ID3D12LibraryReflectionVtbl): IUnknown(IUnknownVtbl) { + fn GetDesc( + pDesc: *mut D3D12_LIBRARY_DESC, + ) -> HRESULT, + fn GetFunctionByIndex( + FunctionIndex: INT, + ) -> *mut ID3D12FunctionReflection, +}} +DEFINE_GUID!{IID_ID3D12ShaderReflectionConstantBuffer, + 0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7} +RIDL!{#[uuid(0xc59598b4, 0x48b3, 0x4869, 0xb9, 0xb1, 0xb1, 0x61, 0x8b, 0x14, 0xa8, 0xb7)] +interface ID3D12ShaderReflectionConstantBuffer(ID3D12ShaderReflectionConstantBufferVtbl) { + fn GetDesc( + pDesc: *mut D3D12_SHADER_BUFFER_DESC, + ) -> HRESULT, + fn GetVariableByIndex( + Index: UINT, + ) -> *mut ID3D12ShaderReflectionVariable, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionVariable, +}} +DEFINE_GUID!{IID_ID3D12ShaderReflectionType, + 0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56} +RIDL!{#[uuid(0xe913c351, 0x783d, 0x48ca, 0xa1, 0xd1, 0x4f, 0x30, 0x62, 0x84, 0xad, 0x56)] +interface ID3D12ShaderReflectionType(ID3D12ShaderReflectionTypeVtbl) { + fn GetDesc( + pDesc: *mut D3D12_SHADER_TYPE_DESC, + ) -> HRESULT, + fn GetMemberTypeByIndex( + Index: UINT, + ) -> *mut ID3D12ShaderReflectionType, + fn GetMemberTypeByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionType, + fn GetMemberTypeName( + Index: UINT, + ) -> LPCSTR, + fn IsEqual( + pType: *mut ID3D12ShaderReflectionType, + ) -> HRESULT, + fn GetSubType() -> *mut ID3D12ShaderReflectionType, + fn GetBaseClass() -> *mut ID3D12ShaderReflectionType, + fn GetNumInterfaces() -> UINT, + fn GetInterfaceByIndex( + uIndex: UINT, + ) -> *mut ID3D12ShaderReflectionType, + fn IsOfType( + pType: *mut ID3D12ShaderReflectionType, + ) -> HRESULT, + fn ImplementsInterface( + pBase: *mut ID3D12ShaderReflectionType, + ) -> HRESULT, +}} +DEFINE_GUID!{IID_ID3D12ShaderReflectionVariable, + 0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea} +RIDL!{#[uuid(0x8337a8a6, 0xa216, 0x444a, 0xb2, 0xf4, 0x31, 0x47, 0x33, 0xa7, 0x3a, 0xea)] +interface ID3D12ShaderReflectionVariable(ID3D12ShaderReflectionVariableVtbl) { + fn GetDesc( + pDesc: *mut D3D12_SHADER_VARIABLE_DESC, + ) -> HRESULT, + fn GetType() -> *mut ID3D12ShaderReflectionType, + fn GetBuffer() -> *mut ID3D12ShaderReflectionConstantBuffer, + fn GetInterfaceSlot( + uArrayIndex: UINT, + ) -> UINT, +}} +DEFINE_GUID!{IID_ID3D12ShaderReflection, + 0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e} +RIDL!{#[uuid(0x5a58797d, 0xa72c, 0x478d, 0x8b, 0xa2, 0xef, 0xc6, 0xb0, 0xef, 0xe8, 0x8e)] +interface ID3D12ShaderReflection(ID3D12ShaderReflectionVtbl): IUnknown(IUnknownVtbl) { + fn GetDesc( + pDesc: *mut D3D12_SHADER_DESC, + ) -> HRESULT, + fn GetConstantBufferByIndex( + Index: UINT, + ) -> *mut ID3D12ShaderReflectionConstantBuffer, + fn GetConstantBufferByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionConstantBuffer, + fn GetResourceBindingDesc( + ResourceIndex: UINT, + pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetInputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetOutputParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetPatchConstantParameterDesc( + ParameterIndex: UINT, + pDesc: *mut D3D12_SIGNATURE_PARAMETER_DESC, + ) -> HRESULT, + fn GetVariableByName( + Name: LPCSTR, + ) -> *mut ID3D12ShaderReflectionVariable, + fn GetResourceBindingDescByName( + Name: LPCSTR, + pDesc: *mut D3D12_SHADER_INPUT_BIND_DESC, + ) -> HRESULT, + fn GetMovInstructionCount() -> UINT, + fn GetMovcInstructionCount() -> UINT, + fn GetConversionInstructionCount() -> UINT, + fn GetBitwiseInstructionCount() -> UINT, + fn GetGSInputPrimitive() -> D3D_PRIMITIVE, + fn IsSampleFrequencyShader() -> BOOL, + fn GetNumInterfaceSlots() -> UINT, + fn GetMinFeatureLevel( + pLevel: *mut D3D_FEATURE_LEVEL, + ) -> HRESULT, + fn GetThreadGroupSize( + pSizeX: *mut UINT, + pSizeY: *mut UINT, + pSizeZ: *mut UINT, + ) -> UINT, + fn GetRequiresFlags() -> UINT64, +}} +DEFINE_GUID!{IID_ID3D12LibraryReflection, + 0x8e349d19, 0x54db, 0x4a56, 0x9d, 0xc9, 0x11, 0x9d, 0x87, 0xbd, 0xb8, 0x04} +DEFINE_GUID!{IID_ID3D12FunctionReflection, + 0x1108795c, 0x2772, 0x4ba9, 0xb2, 0xa8, 0xd4, 0x64, 0xdc, 0x7e, 0x27, 0x99} +DEFINE_GUID!{IID_ID3D12FunctionParameterReflection, + 0xec25f42d, 0x7006, 0x4f2b, 0xb3, 0x3e, 0x02, 0xcc, 0x33, 0x75, 0x73, 0x3f} +pub type D3D12_CBUFFER_TYPE = D3D_CBUFFER_TYPE; +pub type D3D12_RESOURCE_RETURN_TYPE = D3D_RESOURCE_RETURN_TYPE; +pub type D3D12_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN; +pub type D3D12_TESSELLATOR_OUTPUT_PRIMITIVE = D3D_TESSELLATOR_OUTPUT_PRIMITIVE; +pub type D3D12_TESSELLATOR_PARTITIONING = D3D_TESSELLATOR_PARTITIONING; +pub type LPD3D12FUNCTIONPARAMETERREFLECTION = *mut ID3D12FunctionParameterReflection; +pub type LPD3D12FUNCTIONREFLECTION = *mut ID3D12FunctionReflection; +pub type LPD3D12LIBRARYREFLECTION = *mut ID3D12LibraryReflection; +pub type LPD3D12SHADERREFLECTION = *mut ID3D12ShaderReflection; +pub type LPD3D12SHADERREFLECTIONCONSTANTBUFFER = *mut ID3D12ShaderReflectionConstantBuffer; +pub type LPD3D12SHADERREFLECTIONTYPE = *mut ID3D12ShaderReflectionType; +pub type LPD3D12SHADERREFLECTIONVARIABLE = *mut ID3D12ShaderReflectionVariable; +pub const D3D_SHADER_REQUIRES_INNER_COVERAGE: UINT64 = 0x00000400; +pub const D3D_SHADER_REQUIRES_ROVS: UINT64 = 0x00001000; +pub const D3D_SHADER_REQUIRES_STENCIL_REF: UINT64 = 0x00000200; +pub const D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS: UINT64 = 0x00000800; +pub const D3D_SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER: + UINT64 = 0x00002000; diff --git a/winapi/src/um/d3dcommon.rs b/winapi/src/um/d3dcommon.rs new file mode 100644 index 000000000..b4f67dd12 --- /dev/null +++ b/winapi/src/um/d3dcommon.rs @@ -0,0 +1,744 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of d3dcommon.h +use shared::basetsd::SIZE_T; +use shared::minwindef::{LPCVOID, LPVOID, UINT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +ENUM!{enum D3D_DRIVER_TYPE { + D3D_DRIVER_TYPE_UNKNOWN, + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_REFERENCE, + D3D_DRIVER_TYPE_NULL, + D3D_DRIVER_TYPE_SOFTWARE, + D3D_DRIVER_TYPE_WARP, +}} +ENUM!{enum D3D_FEATURE_LEVEL { + D3D_FEATURE_LEVEL_9_1 = 0x9100, + D3D_FEATURE_LEVEL_9_2 = 0x9200, + D3D_FEATURE_LEVEL_9_3 = 0x9300, + D3D_FEATURE_LEVEL_10_0 = 0xa000, + D3D_FEATURE_LEVEL_10_1 = 0xa100, + D3D_FEATURE_LEVEL_11_0 = 0xb000, + D3D_FEATURE_LEVEL_11_1 = 0xb100, + D3D_FEATURE_LEVEL_12_0 = 0xc000, + D3D_FEATURE_LEVEL_12_1 = 0xc100, +}} +ENUM!{enum D3D_PRIMITIVE_TOPOLOGY { + D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0, + D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1, + D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2, + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5, + D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10, + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13, + D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33, + D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34, + D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST = 35, + D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST = 36, + D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST = 37, + D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST = 38, + D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST = 39, + D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST = 40, + D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST = 41, + D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST = 42, + D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST = 43, + D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST = 44, + D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST = 45, + D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST = 46, + D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST = 47, + D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST = 48, + D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST = 49, + D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST = 50, + D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST = 51, + D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST = 52, + D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST = 53, + D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST = 54, + D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST = 55, + D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST = 56, + D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST = 57, + D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST = 58, + D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST = 59, + D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST = 60, + D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST = 61, + D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST = 62, + D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST = 63, + D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64, +}} +pub const D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; +pub const D3D10_PRIMITIVE_TOPOLOGY_POINTLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_POINTLIST; +pub const D3D10_PRIMITIVE_TOPOLOGY_LINELIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINELIST; +pub const D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; +pub const D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +pub const D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +pub const D3D10_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; +pub const D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ; +pub const D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; +pub const D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ; +pub const D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; +pub const D3D11_PRIMITIVE_TOPOLOGY_POINTLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_POINTLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_LINELIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINELIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; +pub const D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; +pub const D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; +pub const D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ; +pub const D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; +pub const D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ; +pub const D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST; +pub const D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: D3D_PRIMITIVE_TOPOLOGY = + D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST; +ENUM!{enum D3D_PRIMITIVE { + D3D_PRIMITIVE_UNDEFINED = 0, + D3D_PRIMITIVE_POINT = 1, + D3D_PRIMITIVE_LINE = 2, + D3D_PRIMITIVE_TRIANGLE = 3, + D3D_PRIMITIVE_LINE_ADJ = 6, + D3D_PRIMITIVE_TRIANGLE_ADJ = 7, + D3D_PRIMITIVE_1_CONTROL_POINT_PATCH = 8, + D3D_PRIMITIVE_2_CONTROL_POINT_PATCH = 9, + D3D_PRIMITIVE_3_CONTROL_POINT_PATCH = 10, + D3D_PRIMITIVE_4_CONTROL_POINT_PATCH = 11, + D3D_PRIMITIVE_5_CONTROL_POINT_PATCH = 12, + D3D_PRIMITIVE_6_CONTROL_POINT_PATCH = 13, + D3D_PRIMITIVE_7_CONTROL_POINT_PATCH = 14, + D3D_PRIMITIVE_8_CONTROL_POINT_PATCH = 15, + D3D_PRIMITIVE_9_CONTROL_POINT_PATCH = 16, + D3D_PRIMITIVE_10_CONTROL_POINT_PATCH = 17, + D3D_PRIMITIVE_11_CONTROL_POINT_PATCH = 18, + D3D_PRIMITIVE_12_CONTROL_POINT_PATCH = 19, + D3D_PRIMITIVE_13_CONTROL_POINT_PATCH = 20, + D3D_PRIMITIVE_14_CONTROL_POINT_PATCH = 21, + D3D_PRIMITIVE_15_CONTROL_POINT_PATCH = 22, + D3D_PRIMITIVE_16_CONTROL_POINT_PATCH = 23, + D3D_PRIMITIVE_17_CONTROL_POINT_PATCH = 24, + D3D_PRIMITIVE_18_CONTROL_POINT_PATCH = 25, + D3D_PRIMITIVE_19_CONTROL_POINT_PATCH = 26, + D3D_PRIMITIVE_20_CONTROL_POINT_PATCH = 28, + D3D_PRIMITIVE_21_CONTROL_POINT_PATCH = 29, + D3D_PRIMITIVE_22_CONTROL_POINT_PATCH = 30, + D3D_PRIMITIVE_23_CONTROL_POINT_PATCH = 31, + D3D_PRIMITIVE_24_CONTROL_POINT_PATCH = 32, + D3D_PRIMITIVE_25_CONTROL_POINT_PATCH = 33, + D3D_PRIMITIVE_26_CONTROL_POINT_PATCH = 34, + D3D_PRIMITIVE_27_CONTROL_POINT_PATCH = 35, + D3D_PRIMITIVE_28_CONTROL_POINT_PATCH = 36, + D3D_PRIMITIVE_29_CONTROL_POINT_PATCH = 37, + D3D_PRIMITIVE_30_CONTROL_POINT_PATCH = 38, + D3D_PRIMITIVE_31_CONTROL_POINT_PATCH = 39, + D3D_PRIMITIVE_32_CONTROL_POINT_PATCH = 40, +}} +pub const D3D10_PRIMITIVE_UNDEFINED: D3D_PRIMITIVE = D3D_PRIMITIVE_UNDEFINED; +pub const D3D10_PRIMITIVE_POINT: D3D_PRIMITIVE = D3D_PRIMITIVE_POINT; +pub const D3D10_PRIMITIVE_LINE: D3D_PRIMITIVE = D3D_PRIMITIVE_LINE; +pub const D3D10_PRIMITIVE_TRIANGLE: D3D_PRIMITIVE = D3D_PRIMITIVE_TRIANGLE; +pub const D3D10_PRIMITIVE_LINE_ADJ: D3D_PRIMITIVE = D3D_PRIMITIVE_LINE_ADJ; +pub const D3D10_PRIMITIVE_TRIANGLE_ADJ: D3D_PRIMITIVE = D3D_PRIMITIVE_TRIANGLE_ADJ; +pub const D3D11_PRIMITIVE_UNDEFINED: D3D_PRIMITIVE = D3D_PRIMITIVE_UNDEFINED; +pub const D3D11_PRIMITIVE_POINT: D3D_PRIMITIVE = D3D_PRIMITIVE_POINT; +pub const D3D11_PRIMITIVE_LINE: D3D_PRIMITIVE = D3D_PRIMITIVE_LINE; +pub const D3D11_PRIMITIVE_TRIANGLE: D3D_PRIMITIVE = D3D_PRIMITIVE_TRIANGLE; +pub const D3D11_PRIMITIVE_LINE_ADJ: D3D_PRIMITIVE = D3D_PRIMITIVE_LINE_ADJ; +pub const D3D11_PRIMITIVE_TRIANGLE_ADJ: D3D_PRIMITIVE = D3D_PRIMITIVE_TRIANGLE_ADJ; +pub const D3D11_PRIMITIVE_1_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_1_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_2_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_2_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_3_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_3_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_4_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_4_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_5_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_5_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_6_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_6_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_7_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_7_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_8_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_8_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_9_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_9_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_10_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_10_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_11_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_11_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_12_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_12_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_13_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_13_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_14_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_14_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_15_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_15_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_16_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_16_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_17_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_17_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_18_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_18_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_19_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_19_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_20_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_20_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_21_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_21_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_22_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_22_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_23_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_23_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_24_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_24_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_25_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_25_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_26_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_26_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_27_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_27_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_28_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_28_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_29_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_29_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_30_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_30_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_31_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_31_CONTROL_POINT_PATCH; +pub const D3D11_PRIMITIVE_32_CONTROL_POINT_PATCH: D3D_PRIMITIVE = + D3D_PRIMITIVE_32_CONTROL_POINT_PATCH; +ENUM!{enum D3D_SRV_DIMENSION { + D3D_SRV_DIMENSION_UNKNOWN = 0, + D3D_SRV_DIMENSION_BUFFER = 1, + D3D_SRV_DIMENSION_TEXTURE1D = 2, + D3D_SRV_DIMENSION_TEXTURE1DARRAY = 3, + D3D_SRV_DIMENSION_TEXTURE2D = 4, + D3D_SRV_DIMENSION_TEXTURE2DARRAY = 5, + D3D_SRV_DIMENSION_TEXTURE2DMS = 6, + D3D_SRV_DIMENSION_TEXTURE2DMSARRAY = 7, + D3D_SRV_DIMENSION_TEXTURE3D = 8, + D3D_SRV_DIMENSION_TEXTURECUBE = 9, + D3D_SRV_DIMENSION_TEXTURECUBEARRAY = 10, + D3D_SRV_DIMENSION_BUFFEREX = 11, +}} +pub const D3D10_SRV_DIMENSION_UNKNOWN: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_UNKNOWN; +pub const D3D10_SRV_DIMENSION_BUFFER: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_BUFFER; +pub const D3D10_SRV_DIMENSION_TEXTURE1D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE1D; +pub const D3D10_SRV_DIMENSION_TEXTURE1DARRAY: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE1DARRAY; +pub const D3D10_SRV_DIMENSION_TEXTURE2D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2D; +pub const D3D10_SRV_DIMENSION_TEXTURE2DARRAY: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2DARRAY; +pub const D3D10_SRV_DIMENSION_TEXTURE2DMS: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2DMS; +pub const D3D10_SRV_DIMENSION_TEXTURE2DMSARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURE2DMSARRAY; +pub const D3D10_SRV_DIMENSION_TEXTURE3D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE3D; +pub const D3D10_SRV_DIMENSION_TEXTURECUBE: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURECUBE; +pub const D3D10_1_SRV_DIMENSION_UNKNOWN: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_UNKNOWN; +pub const D3D10_1_SRV_DIMENSION_BUFFER: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_BUFFER; +pub const D3D10_1_SRV_DIMENSION_TEXTURE1D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE1D; +pub const D3D10_1_SRV_DIMENSION_TEXTURE1DARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURE1DARRAY; +pub const D3D10_1_SRV_DIMENSION_TEXTURE2D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2D; +pub const D3D10_1_SRV_DIMENSION_TEXTURE2DARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURE2DARRAY; +pub const D3D10_1_SRV_DIMENSION_TEXTURE2DMS: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2DMS; +pub const D3D10_1_SRV_DIMENSION_TEXTURE2DMSARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURE2DMSARRAY; +pub const D3D10_1_SRV_DIMENSION_TEXTURE3D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE3D; +pub const D3D10_1_SRV_DIMENSION_TEXTURECUBE: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURECUBE; +pub const D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURECUBEARRAY; +pub const D3D11_SRV_DIMENSION_UNKNOWN: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_UNKNOWN; +pub const D3D11_SRV_DIMENSION_BUFFER: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_BUFFER; +pub const D3D11_SRV_DIMENSION_TEXTURE1D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE1D; +pub const D3D11_SRV_DIMENSION_TEXTURE1DARRAY: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE1DARRAY; +pub const D3D11_SRV_DIMENSION_TEXTURE2D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2D; +pub const D3D11_SRV_DIMENSION_TEXTURE2DARRAY: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2DARRAY; +pub const D3D11_SRV_DIMENSION_TEXTURE2DMS: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE2DMS; +pub const D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURE2DMSARRAY; +pub const D3D11_SRV_DIMENSION_TEXTURE3D: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURE3D; +pub const D3D11_SRV_DIMENSION_TEXTURECUBE: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_TEXTURECUBE; +pub const D3D11_SRV_DIMENSION_TEXTURECUBEARRAY: D3D_SRV_DIMENSION = + D3D_SRV_DIMENSION_TEXTURECUBEARRAY; +pub const D3D11_SRV_DIMENSION_BUFFEREX: D3D_SRV_DIMENSION = D3D_SRV_DIMENSION_BUFFEREX; +STRUCT!{struct D3D_SHADER_MACRO { + Name: LPCSTR, + Definition: LPCSTR, +}} +pub type LPD3D_SHADER_MACRO = *mut D3D_SHADER_MACRO; +DEFINE_GUID!{IID_ID3D10Blob, + 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0x0d, 0x98, 0x9c, 0x3a, 0x01, 0x02} +RIDL!{#[uuid(0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2)] +interface ID3D10Blob(ID3D10BlobVtbl): IUnknown(IUnknownVtbl) { + fn GetBufferPointer() -> LPVOID, + fn GetBufferSize() -> SIZE_T, +}} +pub type LPD3D10BLOB = *mut ID3D10Blob; +pub type ID3DBlob = ID3D10Blob; +pub type LPD3DBLOB = *mut ID3DBlob; +ENUM!{enum D3D_INCLUDE_TYPE { + D3D_INCLUDE_LOCAL = 0, + D3D_INCLUDE_SYSTEM, +}} +pub const D3D10_INCLUDE_LOCAL: D3D_INCLUDE_TYPE = D3D_INCLUDE_LOCAL; +pub const D3D10_INCLUDE_SYSTEM: D3D_INCLUDE_TYPE = D3D_INCLUDE_SYSTEM; +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface ID3DInclude(ID3DIncludeVtbl) { + fn Open( + IncludeType: D3D_INCLUDE_TYPE, + pFileName: LPCSTR, + pParentData: LPCVOID, + ppData: *mut LPCVOID, + pBytes: *mut UINT, + ) -> HRESULT, + fn Close( + pData: LPCVOID, + ) -> HRESULT, +}} +pub type LPD3DINCLUDE = *mut ID3DInclude; +ENUM!{enum D3D_SHADER_VARIABLE_CLASS { + D3D_SVC_SCALAR = 0, + D3D_SVC_VECTOR, + D3D_SVC_MATRIX_ROWS, + D3D_SVC_MATRIX_COLUMNS, + D3D_SVC_OBJECT, + D3D_SVC_STRUCT, + D3D_SVC_INTERFACE_CLASS, + D3D_SVC_INTERFACE_POINTER, +}} +pub const D3D10_SVC_SCALAR: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_SCALAR; +pub const D3D10_SVC_VECTOR: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_VECTOR; +pub const D3D10_SVC_MATRIX_ROWS: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_MATRIX_ROWS; +pub const D3D10_SVC_MATRIX_COLUMNS: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_MATRIX_COLUMNS; +pub const D3D10_SVC_OBJECT: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_OBJECT; +pub const D3D10_SVC_STRUCT: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_STRUCT; +pub const D3D11_SVC_INTERFACE_CLASS: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_INTERFACE_CLASS; +pub const D3D11_SVC_INTERFACE_POINTER: D3D_SHADER_VARIABLE_CLASS = D3D_SVC_INTERFACE_POINTER; +ENUM!{enum D3D_SHADER_VARIABLE_FLAGS { + D3D_SVF_USERPACKED = 1, + D3D_SVF_USED = 2, + D3D_SVF_INTERFACE_POINTER = 4, + D3D_SVF_INTERFACE_PARAMETER = 8, +}} +pub const D3D10_SVF_USERPACKED: D3D_SHADER_VARIABLE_FLAGS = D3D_SVF_USERPACKED; +pub const D3D10_SVF_USED: D3D_SHADER_VARIABLE_FLAGS = D3D_SVF_USED; +pub const D3D11_SVF_INTERFACE_POINTER: D3D_SHADER_VARIABLE_FLAGS = D3D_SVF_INTERFACE_POINTER; +pub const D3D11_SVF_INTERFACE_PARAMETER: D3D_SHADER_VARIABLE_FLAGS = D3D_SVF_INTERFACE_PARAMETER; +ENUM!{enum D3D_SHADER_VARIABLE_TYPE { + D3D_SVT_VOID = 0, + D3D_SVT_BOOL = 1, + D3D_SVT_INT = 2, + D3D_SVT_FLOAT = 3, + D3D_SVT_STRING = 4, + D3D_SVT_TEXTURE = 5, + D3D_SVT_TEXTURE1D = 6, + D3D_SVT_TEXTURE2D = 7, + D3D_SVT_TEXTURE3D = 8, + D3D_SVT_TEXTURECUBE = 9, + D3D_SVT_SAMPLER = 10, + D3D_SVT_SAMPLER1D = 11, + D3D_SVT_SAMPLER2D = 12, + D3D_SVT_SAMPLER3D = 13, + D3D_SVT_SAMPLERCUBE = 14, + D3D_SVT_PIXELSHADER = 15, + D3D_SVT_VERTEXSHADER = 16, + D3D_SVT_PIXELFRAGMENT = 17, + D3D_SVT_VERTEXFRAGMENT = 18, + D3D_SVT_UINT = 19, + D3D_SVT_UINT8 = 20, + D3D_SVT_GEOMETRYSHADER = 21, + D3D_SVT_RASTERIZER = 22, + D3D_SVT_DEPTHSTENCIL = 23, + D3D_SVT_BLEND = 24, + D3D_SVT_BUFFER = 25, + D3D_SVT_CBUFFER = 26, + D3D_SVT_TBUFFER = 27, + D3D_SVT_TEXTURE1DARRAY = 28, + D3D_SVT_TEXTURE2DARRAY = 29, + D3D_SVT_RENDERTARGETVIEW = 30, + D3D_SVT_DEPTHSTENCILVIEW = 31, + D3D_SVT_TEXTURE2DMS = 32, + D3D_SVT_TEXTURE2DMSARRAY = 33, + D3D_SVT_TEXTURECUBEARRAY = 34, + D3D_SVT_HULLSHADER = 35, + D3D_SVT_DOMAINSHADER = 36, + D3D_SVT_INTERFACE_POINTER = 37, + D3D_SVT_COMPUTESHADER = 38, + D3D_SVT_DOUBLE = 39, + D3D_SVT_RWTEXTURE1D = 40, + D3D_SVT_RWTEXTURE1DARRAY = 41, + D3D_SVT_RWTEXTURE2D = 42, + D3D_SVT_RWTEXTURE2DARRAY = 43, + D3D_SVT_RWTEXTURE3D = 44, + D3D_SVT_RWBUFFER = 45, + D3D_SVT_BYTEADDRESS_BUFFER = 46, + D3D_SVT_RWBYTEADDRESS_BUFFER = 47, + D3D_SVT_STRUCTURED_BUFFER = 48, + D3D_SVT_RWSTRUCTURED_BUFFER = 49, + D3D_SVT_APPEND_STRUCTURED_BUFFER = 50, + D3D_SVT_CONSUME_STRUCTURED_BUFFER = 51, + D3D_SVT_MIN8FLOAT = 52, + D3D_SVT_MIN10FLOAT = 53, + D3D_SVT_MIN16FLOAT = 54, + D3D_SVT_MIN12INT = 55, + D3D_SVT_MIN16INT = 56, + D3D_SVT_MIN16UINT = 57, +}} +pub const D3D10_SVT_VOID: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_VOID; +pub const D3D10_SVT_BOOL: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_BOOL; +pub const D3D10_SVT_INT: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_INT; +pub const D3D10_SVT_FLOAT: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_FLOAT; +pub const D3D10_SVT_STRING: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_STRING; +pub const D3D10_SVT_TEXTURE: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE; +pub const D3D10_SVT_TEXTURE1D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE1D; +pub const D3D10_SVT_TEXTURE2D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE2D; +pub const D3D10_SVT_TEXTURE3D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE3D; +pub const D3D10_SVT_TEXTURECUBE: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURECUBE; +pub const D3D10_SVT_SAMPLER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_SAMPLER; +pub const D3D10_SVT_SAMPLER1D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_SAMPLER1D; +pub const D3D10_SVT_SAMPLER2D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_SAMPLER2D; +pub const D3D10_SVT_SAMPLER3D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_SAMPLER3D; +pub const D3D10_SVT_SAMPLERCUBE: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_SAMPLERCUBE; +pub const D3D10_SVT_PIXELSHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_PIXELSHADER; +pub const D3D10_SVT_VERTEXSHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_VERTEXSHADER; +pub const D3D10_SVT_PIXELFRAGMENT: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_PIXELFRAGMENT; +pub const D3D10_SVT_VERTEXFRAGMENT: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_VERTEXFRAGMENT; +pub const D3D10_SVT_UINT: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_UINT; +pub const D3D10_SVT_UINT8: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_UINT8; +pub const D3D10_SVT_GEOMETRYSHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_GEOMETRYSHADER; +pub const D3D10_SVT_RASTERIZER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RASTERIZER; +pub const D3D10_SVT_DEPTHSTENCIL: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_DEPTHSTENCIL; +pub const D3D10_SVT_BLEND: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_BLEND; +pub const D3D10_SVT_BUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_BUFFER; +pub const D3D10_SVT_CBUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_CBUFFER; +pub const D3D10_SVT_TBUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TBUFFER; +pub const D3D10_SVT_TEXTURE1DARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE1DARRAY; +pub const D3D10_SVT_TEXTURE2DARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE2DARRAY; +pub const D3D10_SVT_RENDERTARGETVIEW: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RENDERTARGETVIEW; +pub const D3D10_SVT_DEPTHSTENCILVIEW: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_DEPTHSTENCILVIEW; +pub const D3D10_SVT_TEXTURE2DMS: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE2DMS; +pub const D3D10_SVT_TEXTURE2DMSARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURE2DMSARRAY; +pub const D3D10_SVT_TEXTURECUBEARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_TEXTURECUBEARRAY; +pub const D3D11_SVT_HULLSHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_HULLSHADER; +pub const D3D11_SVT_DOMAINSHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_DOMAINSHADER; +pub const D3D11_SVT_INTERFACE_POINTER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_INTERFACE_POINTER; +pub const D3D11_SVT_COMPUTESHADER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_COMPUTESHADER; +pub const D3D11_SVT_DOUBLE: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_DOUBLE; +pub const D3D11_SVT_RWTEXTURE1D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWTEXTURE1D; +pub const D3D11_SVT_RWTEXTURE1DARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWTEXTURE1DARRAY; +pub const D3D11_SVT_RWTEXTURE2D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWTEXTURE2D; +pub const D3D11_SVT_RWTEXTURE2DARRAY: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWTEXTURE2DARRAY; +pub const D3D11_SVT_RWTEXTURE3D: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWTEXTURE3D; +pub const D3D11_SVT_RWBUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWBUFFER; +pub const D3D11_SVT_BYTEADDRESS_BUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_BYTEADDRESS_BUFFER; +pub const D3D11_SVT_RWBYTEADDRESS_BUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWBYTEADDRESS_BUFFER; +pub const D3D11_SVT_STRUCTURED_BUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_STRUCTURED_BUFFER; +pub const D3D11_SVT_RWSTRUCTURED_BUFFER: D3D_SHADER_VARIABLE_TYPE = D3D_SVT_RWSTRUCTURED_BUFFER; +pub const D3D11_SVT_APPEND_STRUCTURED_BUFFER: D3D_SHADER_VARIABLE_TYPE = + D3D_SVT_APPEND_STRUCTURED_BUFFER; +pub const D3D11_SVT_CONSUME_STRUCTURED_BUFFER: D3D_SHADER_VARIABLE_TYPE = + D3D_SVT_CONSUME_STRUCTURED_BUFFER; +ENUM!{enum D3D_SHADER_INPUT_FLAGS { + D3D_SIF_USERPACKED = 0x1, + D3D_SIF_COMPARISON_SAMPLER = 0x2, + D3D_SIF_TEXTURE_COMPONENT_0 = 0x4, + D3D_SIF_TEXTURE_COMPONENT_1 = 0x8, + D3D_SIF_TEXTURE_COMPONENTS = 0xc, + D3D_SIF_UNUSED = 0x10, +}} +pub const D3D10_SIF_USERPACKED: D3D_SHADER_INPUT_FLAGS = D3D_SIF_USERPACKED; +pub const D3D10_SIF_COMPARISON_SAMPLER: D3D_SHADER_INPUT_FLAGS = D3D_SIF_COMPARISON_SAMPLER; +pub const D3D10_SIF_TEXTURE_COMPONENT_0: D3D_SHADER_INPUT_FLAGS = D3D_SIF_TEXTURE_COMPONENT_0; +pub const D3D10_SIF_TEXTURE_COMPONENT_1: D3D_SHADER_INPUT_FLAGS = D3D_SIF_TEXTURE_COMPONENT_1; +pub const D3D10_SIF_TEXTURE_COMPONENTS: D3D_SHADER_INPUT_FLAGS = D3D_SIF_TEXTURE_COMPONENTS; +ENUM!{enum D3D_SHADER_INPUT_TYPE { + D3D_SIT_CBUFFER, + D3D_SIT_TBUFFER, + D3D_SIT_TEXTURE, + D3D_SIT_SAMPLER, + D3D_SIT_UAV_RWTYPED, + D3D_SIT_STRUCTURED, + D3D_SIT_UAV_RWSTRUCTURED, + D3D_SIT_BYTEADDRESS, + D3D_SIT_UAV_RWBYTEADDRESS, + D3D_SIT_UAV_APPEND_STRUCTURED, + D3D_SIT_UAV_CONSUME_STRUCTURED, + D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER, +}} +pub const D3D10_SIT_CBUFFER: D3D_SHADER_INPUT_TYPE = D3D_SIT_CBUFFER; +pub const D3D10_SIT_TBUFFER: D3D_SHADER_INPUT_TYPE = D3D_SIT_TBUFFER; +pub const D3D10_SIT_TEXTURE: D3D_SHADER_INPUT_TYPE = D3D_SIT_TEXTURE; +pub const D3D10_SIT_SAMPLER: D3D_SHADER_INPUT_TYPE = D3D_SIT_SAMPLER; +pub const D3D11_SIT_UAV_RWTYPED: D3D_SHADER_INPUT_TYPE = D3D_SIT_UAV_RWTYPED; +pub const D3D11_SIT_STRUCTURED: D3D_SHADER_INPUT_TYPE = D3D_SIT_STRUCTURED; +pub const D3D11_SIT_UAV_RWSTRUCTURED: D3D_SHADER_INPUT_TYPE = D3D_SIT_UAV_RWSTRUCTURED; +pub const D3D11_SIT_BYTEADDRESS: D3D_SHADER_INPUT_TYPE = D3D_SIT_BYTEADDRESS; +pub const D3D11_SIT_UAV_RWBYTEADDRESS: D3D_SHADER_INPUT_TYPE = D3D_SIT_UAV_RWBYTEADDRESS; +pub const D3D11_SIT_UAV_APPEND_STRUCTURED: D3D_SHADER_INPUT_TYPE = D3D_SIT_UAV_APPEND_STRUCTURED; +pub const D3D11_SIT_UAV_CONSUME_STRUCTURED: D3D_SHADER_INPUT_TYPE = D3D_SIT_UAV_CONSUME_STRUCTURED; +pub const D3D11_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: D3D_SHADER_INPUT_TYPE = + D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER; +ENUM!{enum D3D_SHADER_CBUFFER_FLAGS { + D3D_CBF_USERPACKED = 1, +}} +pub const D3D10_CBF_USERPACKED: D3D_SHADER_CBUFFER_FLAGS = D3D_CBF_USERPACKED; +ENUM!{enum D3D_CBUFFER_TYPE { + D3D_CT_CBUFFER, + D3D_CT_TBUFFER, + D3D_CT_INTERFACE_POINTERS, + D3D_CT_RESOURCE_BIND_INFO, +}} +pub const D3D10_CT_CBUFFER: D3D_CBUFFER_TYPE = D3D_CT_CBUFFER; +pub const D3D10_CT_TBUFFER: D3D_CBUFFER_TYPE = D3D_CT_TBUFFER; +pub const D3D11_CT_CBUFFER: D3D_CBUFFER_TYPE = D3D_CT_CBUFFER; +pub const D3D11_CT_TBUFFER: D3D_CBUFFER_TYPE = D3D_CT_TBUFFER; +pub const D3D11_CT_INTERFACE_POINTERS: D3D_CBUFFER_TYPE = D3D_CT_INTERFACE_POINTERS; +pub const D3D11_CT_RESOURCE_BIND_INFO: D3D_CBUFFER_TYPE = D3D_CT_RESOURCE_BIND_INFO; +ENUM!{enum D3D_NAME { + D3D_NAME_UNDEFINED = 0, + D3D_NAME_POSITION = 1, + D3D_NAME_CLIP_DISTANCE = 2, + D3D_NAME_CULL_DISTANCE = 3, + D3D_NAME_RENDER_TARGET_ARRAY_INDEX = 4, + D3D_NAME_VIEWPORT_ARRAY_INDEX = 5, + D3D_NAME_VERTEX_ID = 6, + D3D_NAME_PRIMITIVE_ID = 7, + D3D_NAME_INSTANCE_ID = 8, + D3D_NAME_IS_FRONT_FACE = 9, + D3D_NAME_SAMPLE_INDEX = 10, + D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR = 11, + D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR = 12, + D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR = 13, + D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR = 14, + D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR = 15, + D3D_NAME_FINAL_LINE_DENSITY_TESSFACTOR = 16, + D3D_NAME_TARGET = 64, + D3D_NAME_DEPTH = 65, + D3D_NAME_COVERAGE = 66, + D3D_NAME_DEPTH_GREATER_EQUAL = 67, + D3D_NAME_DEPTH_LESS_EQUAL = 68, +}} +pub const D3D10_NAME_UNDEFINED: D3D_NAME = D3D_NAME_UNDEFINED; +pub const D3D10_NAME_POSITION: D3D_NAME = D3D_NAME_POSITION; +pub const D3D10_NAME_CLIP_DISTANCE: D3D_NAME = D3D_NAME_CLIP_DISTANCE; +pub const D3D10_NAME_CULL_DISTANCE: D3D_NAME = D3D_NAME_CULL_DISTANCE; +pub const D3D10_NAME_RENDER_TARGET_ARRAY_INDEX: D3D_NAME = D3D_NAME_RENDER_TARGET_ARRAY_INDEX; +pub const D3D10_NAME_VIEWPORT_ARRAY_INDEX: D3D_NAME = D3D_NAME_VIEWPORT_ARRAY_INDEX; +pub const D3D10_NAME_VERTEX_ID: D3D_NAME = D3D_NAME_VERTEX_ID; +pub const D3D10_NAME_PRIMITIVE_ID: D3D_NAME = D3D_NAME_PRIMITIVE_ID; +pub const D3D10_NAME_INSTANCE_ID: D3D_NAME = D3D_NAME_INSTANCE_ID; +pub const D3D10_NAME_IS_FRONT_FACE: D3D_NAME = D3D_NAME_IS_FRONT_FACE; +pub const D3D10_NAME_SAMPLE_INDEX: D3D_NAME = D3D_NAME_SAMPLE_INDEX; +pub const D3D10_NAME_TARGET: D3D_NAME = D3D_NAME_TARGET; +pub const D3D10_NAME_DEPTH: D3D_NAME = D3D_NAME_DEPTH; +pub const D3D10_NAME_COVERAGE: D3D_NAME = D3D_NAME_COVERAGE; +pub const D3D11_NAME_FINAL_QUAD_EDGE_TESSFACTOR: D3D_NAME = D3D_NAME_FINAL_QUAD_EDGE_TESSFACTOR; +pub const D3D11_NAME_FINAL_QUAD_INSIDE_TESSFACTOR: D3D_NAME + = D3D_NAME_FINAL_QUAD_INSIDE_TESSFACTOR; +pub const D3D11_NAME_FINAL_TRI_EDGE_TESSFACTOR: D3D_NAME = D3D_NAME_FINAL_TRI_EDGE_TESSFACTOR; +pub const D3D11_NAME_FINAL_TRI_INSIDE_TESSFACTOR: D3D_NAME = D3D_NAME_FINAL_TRI_INSIDE_TESSFACTOR; +pub const D3D11_NAME_FINAL_LINE_DETAIL_TESSFACTOR: D3D_NAME + = D3D_NAME_FINAL_LINE_DETAIL_TESSFACTOR; +pub const D3D11_NAME_FINAL_LINE_DENSITY_TESSFACTOR: D3D_NAME + = D3D_NAME_FINAL_LINE_DENSITY_TESSFACTOR; +pub const D3D11_NAME_DEPTH_GREATER_EQUAL: D3D_NAME = D3D_NAME_DEPTH_GREATER_EQUAL; +pub const D3D11_NAME_DEPTH_LESS_EQUAL: D3D_NAME = D3D_NAME_DEPTH_LESS_EQUAL; +ENUM!{enum D3D_RESOURCE_RETURN_TYPE { + D3D_RETURN_TYPE_UNORM = 1, + D3D_RETURN_TYPE_SNORM = 2, + D3D_RETURN_TYPE_SINT = 3, + D3D_RETURN_TYPE_UINT = 4, + D3D_RETURN_TYPE_FLOAT = 5, + D3D_RETURN_TYPE_MIXED = 6, + D3D_RETURN_TYPE_DOUBLE = 7, + D3D_RETURN_TYPE_CONTINUED = 8, +}} +pub const D3D10_RETURN_TYPE_UNORM: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_UNORM; +pub const D3D10_RETURN_TYPE_SNORM: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_SNORM; +pub const D3D10_RETURN_TYPE_SINT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_SINT; +pub const D3D10_RETURN_TYPE_UINT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_UINT; +pub const D3D10_RETURN_TYPE_FLOAT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_FLOAT; +pub const D3D10_RETURN_TYPE_MIXED: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_MIXED; +pub const D3D11_RETURN_TYPE_UNORM: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_UNORM; +pub const D3D11_RETURN_TYPE_SNORM: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_SNORM; +pub const D3D11_RETURN_TYPE_SINT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_SINT; +pub const D3D11_RETURN_TYPE_UINT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_UINT; +pub const D3D11_RETURN_TYPE_FLOAT: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_FLOAT; +pub const D3D11_RETURN_TYPE_MIXED: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_MIXED; +pub const D3D11_RETURN_TYPE_DOUBLE: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_DOUBLE; +pub const D3D11_RETURN_TYPE_CONTINUED: D3D_RESOURCE_RETURN_TYPE = D3D_RETURN_TYPE_CONTINUED; +ENUM!{enum D3D_REGISTER_COMPONENT_TYPE { + D3D_REGISTER_COMPONENT_UNKNOWN = 0, + D3D_REGISTER_COMPONENT_UINT32 = 1, + D3D_REGISTER_COMPONENT_SINT32 = 2, + D3D_REGISTER_COMPONENT_FLOAT32 = 3, +}} +pub const D3D10_REGISTER_COMPONENT_UNKNOWN: D3D_REGISTER_COMPONENT_TYPE = + D3D_REGISTER_COMPONENT_UNKNOWN; +pub const D3D10_REGISTER_COMPONENT_UINT32: D3D_REGISTER_COMPONENT_TYPE = + D3D_REGISTER_COMPONENT_UINT32; +pub const D3D10_REGISTER_COMPONENT_SINT32: D3D_REGISTER_COMPONENT_TYPE = + D3D_REGISTER_COMPONENT_SINT32; +pub const D3D10_REGISTER_COMPONENT_FLOAT32: D3D_REGISTER_COMPONENT_TYPE = + D3D_REGISTER_COMPONENT_FLOAT32; +ENUM!{enum D3D_TESSELLATOR_DOMAIN { + D3D_TESSELLATOR_DOMAIN_UNDEFINED, + D3D_TESSELLATOR_DOMAIN_ISOLINE, + D3D_TESSELLATOR_DOMAIN_TRI, + D3D_TESSELLATOR_DOMAIN_QUAD, +}} +pub const D3D11_TESSELLATOR_DOMAIN_UNDEFINED: D3D_TESSELLATOR_DOMAIN = + D3D_TESSELLATOR_DOMAIN_UNDEFINED; +pub const D3D11_TESSELLATOR_DOMAIN_ISOLINE: D3D_TESSELLATOR_DOMAIN = + D3D_TESSELLATOR_DOMAIN_ISOLINE; +pub const D3D11_TESSELLATOR_DOMAIN_TRI: D3D_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN_TRI; +pub const D3D11_TESSELLATOR_DOMAIN_QUAD: D3D_TESSELLATOR_DOMAIN = D3D_TESSELLATOR_DOMAIN_QUAD; +ENUM!{enum D3D_TESSELLATOR_PARTITIONING { + D3D_TESSELLATOR_PARTITIONING_UNDEFINED, + D3D_TESSELLATOR_PARTITIONING_INTEGER, + D3D_TESSELLATOR_PARTITIONING_POW2, + D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD, + D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN, +}} +pub const D3D11_TESSELLATOR_PARTITIONING_UNDEFINED: D3D_TESSELLATOR_PARTITIONING = + D3D_TESSELLATOR_PARTITIONING_UNDEFINED; +pub const D3D11_TESSELLATOR_PARTITIONING_INTEGER: D3D_TESSELLATOR_PARTITIONING = + D3D_TESSELLATOR_PARTITIONING_INTEGER; +pub const D3D11_TESSELLATOR_PARTITIONING_POW2: D3D_TESSELLATOR_PARTITIONING = + D3D_TESSELLATOR_PARTITIONING_POW2; +pub const D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: D3D_TESSELLATOR_PARTITIONING = + D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD; +pub const D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: D3D_TESSELLATOR_PARTITIONING = + D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN; +ENUM!{enum D3D_TESSELLATOR_OUTPUT_PRIMITIVE { + D3D_TESSELLATOR_OUTPUT_UNDEFINED, + D3D_TESSELLATOR_OUTPUT_POINT, + D3D_TESSELLATOR_OUTPUT_LINE, + D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW, + D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW, +}} +pub const D3D11_TESSELLATOR_OUTPUT_UNDEFINED: D3D_TESSELLATOR_OUTPUT_PRIMITIVE = + D3D_TESSELLATOR_OUTPUT_UNDEFINED; +pub const D3D11_TESSELLATOR_OUTPUT_POINT: D3D_TESSELLATOR_OUTPUT_PRIMITIVE = + D3D_TESSELLATOR_OUTPUT_POINT; +pub const D3D11_TESSELLATOR_OUTPUT_LINE: D3D_TESSELLATOR_OUTPUT_PRIMITIVE = + D3D_TESSELLATOR_OUTPUT_LINE; +pub const D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW: D3D_TESSELLATOR_OUTPUT_PRIMITIVE = + D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW; +pub const D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW: D3D_TESSELLATOR_OUTPUT_PRIMITIVE = + D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW; +ENUM!{enum D3D_MIN_PRECISION { + D3D_MIN_PRECISION_DEFAULT, + D3D_MIN_PRECISION_FLOAT_16, + D3D_MIN_PRECISION_FLOAT_2_8, + D3D_MIN_PRECISION_RESERVED, + D3D_MIN_PRECISION_SINT_16, + D3D_MIN_PRECISION_UINT_16, + D3D_MIN_PRECISION_ANY_16 = 0xf0, + D3D_MIN_PRECISION_ANY_10 = 0xf1, +}} +ENUM!{enum D3D_INTERPOLATION_MODE { + D3D_INTERPOLATION_UNDEFINED, + D3D_INTERPOLATION_CONSTANT, + D3D_INTERPOLATION_LINEAR, + D3D_INTERPOLATION_LINEAR_CENTROID, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID, + D3D_INTERPOLATION_LINEAR_SAMPLE, + D3D_INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE, +}} +ENUM!{enum D3D_PARAMETER_FLAGS { + D3D_PF_NONE = 0, + D3D_PF_IN = 0x1, + D3D_PF_OUT = 0x2, +}} +DEFINE_GUID!{WKPDID_D3DDebugObjectName, + 0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00} +DEFINE_GUID!{WKPDID_D3DDebugObjectNameW, + 0x4cca5fd8, 0x921f, 0x42c8, 0x85, 0x66, 0x70, 0xca, 0xf2, 0xa9, 0xb7, 0x41} +DEFINE_GUID!{WKPDID_CommentStringW, + 0xd0149dc0, 0x90e8, 0x4ec8, 0x81, 0x44, 0xe9, 0x00, 0xad, 0x26, 0x6b, 0xb2} diff --git a/winapi/src/um/d3dcompiler.rs b/winapi/src/um/d3dcompiler.rs new file mode 100644 index 000000000..944ae25f0 --- /dev/null +++ b/winapi/src/um/d3dcompiler.rs @@ -0,0 +1,274 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::basetsd::SIZE_T; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, DWORD, LPCVOID, LPVOID, UINT}; +use um::d3d11shader::{ID3D11FunctionLinkingGraph, ID3D11Linker, ID3D11Module}; +use um::d3dcommon::{D3D_SHADER_MACRO, ID3DBlob, ID3DInclude}; +use um::winnt::{HRESULT, LPCSTR, LPCWSTR}; +pub const D3DCOMPILER_DLL: &'static str = "d3dcompiler_47.dll"; +pub const D3D_COMPILER_VERSION: DWORD = 47; +extern "system" { + pub fn D3DReadFileToBlob( + pFileName: LPCWSTR, + ppContents: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DWriteBlobToFile( + pBlob: *mut ID3DBlob, + pFileName: LPCWSTR, + bOverwrite: BOOL, + ) -> HRESULT; +} +pub const D3DCOMPILE_DEBUG: DWORD = 1 << 0; +pub const D3DCOMPILE_SKIP_VALIDATION: DWORD = 1 << 1; +pub const D3DCOMPILE_SKIP_OPTIMIZATION: DWORD = 1 << 2; +pub const D3DCOMPILE_PACK_MATRIX_ROW_MAJOR: DWORD = 1 << 3; +pub const D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR: DWORD = 1 << 4; +pub const D3DCOMPILE_PARTIAL_PRECISION: DWORD = 1 << 5; +pub const D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT: DWORD = 1 << 6; +pub const D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT: DWORD = 1 << 7; +pub const D3DCOMPILE_NO_PRESHADER: DWORD = 1 << 8; +pub const D3DCOMPILE_AVOID_FLOW_CONTROL: DWORD = 1 << 9; +pub const D3DCOMPILE_PREFER_FLOW_CONTROL: DWORD = 1 << 10; +pub const D3DCOMPILE_ENABLE_STRICTNESS: DWORD = 1 << 11; +pub const D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY: DWORD = 1 << 12; +pub const D3DCOMPILE_IEEE_STRICTNESS: DWORD = 1 << 13; +pub const D3DCOMPILE_OPTIMIZATION_LEVEL0: DWORD = 1 << 14; +pub const D3DCOMPILE_OPTIMIZATION_LEVEL1: DWORD = 0; +pub const D3DCOMPILE_OPTIMIZATION_LEVEL2: DWORD = (1 << 14) | (1 << 15); +pub const D3DCOMPILE_OPTIMIZATION_LEVEL3: DWORD = 1 << 15; +pub const D3DCOMPILE_RESERVED16: DWORD = 1 << 16; +pub const D3DCOMPILE_RESERVED17: DWORD = 1 << 17; +pub const D3DCOMPILE_WARNINGS_ARE_ERRORS: DWORD = 1 << 18; +pub const D3DCOMPILE_RESOURCES_MAY_ALIAS: DWORD = 1 << 19; +pub const D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES: DWORD = 1 << 20; +pub const D3DCOMPILE_ALL_RESOURCES_BOUND: DWORD = 1 << 21; +pub const D3DCOMPILE_EFFECT_CHILD_EFFECT: DWORD = 1 << 0; +pub const D3DCOMPILE_EFFECT_ALLOW_SLOW_OPS: DWORD = 1 << 1; +pub const D3D_COMPILE_STANDARD_FILE_INCLUDE: *mut ID3DInclude = 1 as *mut ID3DInclude; +extern "system" { + pub fn D3DCompile( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + pSourceName: LPCSTR, + pDefines: *const D3D_SHADER_MACRO, + pInclude: *mut ID3DInclude, + pEntrypoint: LPCSTR, + pTarget: LPCSTR, + Flags1: UINT, + Flags2: UINT, + ppCode: *mut *mut ID3DBlob, + ppErrorMsgs: *mut *mut ID3DBlob, + ) -> HRESULT; +} +pub const D3DCOMPILE_SECDATA_MERGE_UAV_SLOTS: DWORD = 0x00000001; +pub const D3DCOMPILE_SECDATA_PRESERVE_TEMPLATE_SLOTS: DWORD = 0x00000002; +pub const D3DCOMPILE_SECDATA_REQUIRE_TEMPLATE_MATCH: DWORD = 0x00000004; +extern "system" { + pub fn D3DCompile2( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + pSourceName: LPCSTR, + pDefines: *const D3D_SHADER_MACRO, + pInclude: *mut ID3DInclude, + pEntrypoint: LPCSTR, + pTarget: LPCSTR, + Flags1: UINT, + Flags2: UINT, + SecondaryDataFlags: UINT, + pSecondaryData: LPCVOID, + SecondaryDataSize: SIZE_T, + ppCode: *mut *mut ID3DBlob, + ppErrorMsgs: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DCompileFromFile( + pFileName: LPCWSTR, + pDefines: *const D3D_SHADER_MACRO, + pInclude: *mut ID3DInclude, + pEntrypoint: LPCSTR, + pTarget: LPCSTR, + Flags1: UINT, + Flags2: UINT, + ppCode: *mut *mut ID3DBlob, + ppErrorMsgs: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DPreprocess( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + pSourceName: LPCSTR, + pDefines: *const D3D_SHADER_MACRO, + pInclude: *mut ID3DInclude, + ppCodeText: *mut *mut ID3DBlob, + ppErrorMsgs: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DGetDebugInfo( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + ppDebugInfo: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DReflect( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + pInterface: REFIID, + ppReflector: *mut *mut c_void, + ) -> HRESULT; + pub fn D3DReflectLibrary( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + riid: REFIID, + ppReflector: *mut LPVOID, + ) -> HRESULT; +} +pub const D3D_DISASM_ENABLE_COLOR_CODE: DWORD = 0x00000001; +pub const D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS: DWORD = 0x00000002; +pub const D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING: DWORD = 0x00000004; +pub const D3D_DISASM_ENABLE_INSTRUCTION_CYCLE: DWORD = 0x00000008; +pub const D3D_DISASM_DISABLE_DEBUG_INFO: DWORD = 0x00000010; +pub const D3D_DISASM_ENABLE_INSTRUCTION_OFFSET: DWORD = 0x00000020; +pub const D3D_DISASM_INSTRUCTION_ONLY: DWORD = 0x00000040; +pub const D3D_DISASM_PRINT_HEX_LITERALS: DWORD = 0x00000080; +extern "system" { + pub fn D3DDisassemble( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + Flags: UINT, + szComments: LPCSTR, + ppDisassembly: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DDisassembleRegion( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + Flags: UINT, + szComments: LPCSTR, + StartByteOffset: SIZE_T, + NumInsts: SIZE_T, + pFinishByteOffset: *mut SIZE_T, + ppDisassembly: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DCreateLinker( + ppLinker: *mut *mut ID3D11Linker, + ) -> HRESULT; + pub fn D3DLoadModule( + pSrcData: LPCVOID, + cbSrcDataSize: SIZE_T, + ppModule: *mut *mut ID3D11Module, + ) -> HRESULT; + pub fn D3DCreateFunctionLinkingGraph( + uFlags: UINT, + ppFunctionLinkingGraph: *mut *mut ID3D11FunctionLinkingGraph, + ) -> HRESULT; +} +pub const D3D_GET_INST_OFFSETS_INCLUDE_NON_EXECUTABLE: DWORD = 0x00000001; +extern "system" { + pub fn D3DGetTraceInstructionOffsets( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + Flags: UINT, + StartInstIndex: SIZE_T, + NumInsts: SIZE_T, + pOffsets: *mut SIZE_T, + pTotalInsts: *mut SIZE_T, + ) -> HRESULT; + pub fn D3DGetInputSignatureBlob( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + ppSignatureBlob: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DGetOutputSignatureBlob( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + ppSignatureBlob: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DGetInputAndOutputSignatureBlob( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + ppSignatureBlob: *mut *mut ID3DBlob, + ) -> HRESULT; +} +ENUM!{enum D3DCOMPILER_STRIP_FLAGS { + D3DCOMPILER_STRIP_REFLECTION_DATA = 0x00000001, + D3DCOMPILER_STRIP_DEBUG_INFO = 0x00000002, + D3DCOMPILER_STRIP_TEST_BLOBS = 0x00000004, + D3DCOMPILER_STRIP_PRIVATE_DATA = 0x00000008, + D3DCOMPILER_STRIP_ROOT_SIGNATURE = 0x00000010, + D3DCOMPILER_STRIP_FORCE_DWORD = 0x7fffffff, +}} +extern "system" { + pub fn D3DStripShader( + pShaderBytecode: LPCVOID, + BytecodeLength: SIZE_T, + uStripFlags: UINT, + ppStrippedBlob: *mut *mut ID3DBlob, + ) -> HRESULT; +} +ENUM!{enum D3D_BLOB_PART { + D3D_BLOB_INPUT_SIGNATURE_BLOB, + D3D_BLOB_OUTPUT_SIGNATURE_BLOB, + D3D_BLOB_INPUT_AND_OUTPUT_SIGNATURE_BLOB, + D3D_BLOB_PATCH_CONSTANT_SIGNATURE_BLOB, + D3D_BLOB_ALL_SIGNATURE_BLOB, + D3D_BLOB_DEBUG_INFO, + D3D_BLOB_LEGACY_SHADER, + D3D_BLOB_XNA_PREPASS_SHADER, + D3D_BLOB_XNA_SHADER, + D3D_BLOB_PDB, + D3D_BLOB_PRIVATE_DATA, + D3D_BLOB_ROOT_SIGNATURE, + D3D_BLOB_TEST_ALTERNATE_SHADER = 0x8000, + D3D_BLOB_TEST_COMPILE_DETAILS, + D3D_BLOB_TEST_COMPILE_PERF, + D3D_BLOB_TEST_COMPILE_REPORT, +}} +extern "system" { + pub fn D3DGetBlobPart( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + Part: D3D_BLOB_PART, + Flags: UINT, + ppPart: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DSetBlobPart( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + Part: D3D_BLOB_PART, + Flags: UINT, + pPart: LPCVOID, + PartSize: SIZE_T, + ppNewShader: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DCreateBlob( + Size: SIZE_T, + ppBlob: *mut *mut ID3DBlob, + ) -> HRESULT; +} +STRUCT!{struct D3D_SHADER_DATA { + pBytecode: LPCVOID, + BytecodeLength: SIZE_T, +}} +extern "system" { + pub fn D3DCompressShaders( + uNumShaders: UINT, + pShaderData: *mut D3D_SHADER_DATA, + uFlags: UINT, + ppCompressedData: *mut *mut ID3DBlob, + ) -> HRESULT; + pub fn D3DDecompressShaders( + pSrcData: LPCVOID, + SrcDataSize: SIZE_T, + uNumShaders: UINT, + uStartIndex: UINT, + pIndices: *mut UINT, + uFlags: UINT, + ppShaders: *mut *mut ID3DBlob, + pTotalShaders: *mut UINT, + ) -> HRESULT; + // pub fn D3DDisassemble10Effect( + // pEffect: *mut ID3D10Effect, + // Flags: UINT, + // ppDisassembly: *mut *mut ID3DBlob, + // ) -> HRESULT; +} diff --git a/winapi/src/um/d3dcsx.rs b/winapi/src/um/d3dcsx.rs new file mode 100644 index 000000000..c12640061 --- /dev/null +++ b/winapi/src/um/d3dcsx.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3DX11Scan, + 0x5089b68f, 0xe71d, 0x4d38, 0xbe, 0x8e, 0xf3, 0x63, 0xb9, 0x5a, 0x94, 0x05} +DEFINE_GUID!{IID_ID3DX11SegmentedScan, + 0xa915128c, 0xd954, 0x4c79, 0xbf, 0xe1, 0x64, 0xdb, 0x92, 0x31, 0x94, 0xd6} +DEFINE_GUID!{IID_ID3DX11FFT, + 0xb3f7a938, 0x4c93, 0x4310, 0xa6, 0x75, 0xb3, 0x0d, 0x6d, 0xe5, 0x05, 0x53} diff --git a/winapi/src/um/d3dx10core.rs b/winapi/src/um/d3dx10core.rs new file mode 100644 index 000000000..c5fb44923 --- /dev/null +++ b/winapi/src/um/d3dx10core.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3DX10Sprite, + 0xba0b762d, 0x8d28, 0x43ec, 0xb9, 0xdc, 0x2f, 0x84, 0x44, 0x3b, 0x06, 0x14} +DEFINE_GUID!{IID_ID3DX10ThreadPump, + 0xc93fecfa, 0x6967, 0x478a, 0xab, 0xbc, 0x40, 0x2d, 0x90, 0x62, 0x1f, 0xcb} +DEFINE_GUID!{IID_ID3DX10Font, + 0xd79dbb70, 0x5f21, 0x4d36, 0xbb, 0xc2, 0xff, 0x52, 0x5c, 0x21, 0x3c, 0xdc} diff --git a/winapi/src/um/d3dx10math.rs b/winapi/src/um/d3dx10math.rs new file mode 100644 index 000000000..9c6179fdd --- /dev/null +++ b/winapi/src/um/d3dx10math.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3DXMatrixStack, + 0xc7885ba7, 0xf990, 0x4fe7, 0x92, 0x2d, 0x85, 0x15, 0xe4, 0x77, 0xdd, 0x85} diff --git a/winapi/src/um/d3dx10mesh.rs b/winapi/src/um/d3dx10mesh.rs new file mode 100644 index 000000000..319df62d8 --- /dev/null +++ b/winapi/src/um/d3dx10mesh.rs @@ -0,0 +1,19 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ID3DX10BaseMesh, + 0x7ed943dd, 0x52e8, 0x40b5, 0xa8, 0xd8, 0x76, 0x68, 0x5c, 0x40, 0x63, 0x30} +DEFINE_GUID!{IID_ID3DX10MeshBuffer, + 0x04b0d117, 0x1041, 0x46b1, 0xaa, 0x8a, 0x39, 0x52, 0x84, 0x8b, 0xa2, 0x2e} +DEFINE_GUID!{IID_ID3DX10Mesh, + 0x4020e5c2, 0x1403, 0x4929, 0x88, 0x3f, 0xe2, 0xe8, 0x49, 0xfa, 0xc1, 0x95} +DEFINE_GUID!{IID_ID3DX10PMesh, + 0x8875769a, 0xd579, 0x4088, 0xaa, 0xeb, 0x53, 0x4d, 0x1a, 0xd8, 0x4e, 0x96} +DEFINE_GUID!{IID_ID3DX10SPMesh, + 0x667ea4c7, 0xf1cd, 0x4386, 0xb5, 0x23, 0x7c, 0x02, 0x90, 0xb8, 0x3c, 0xc5} +DEFINE_GUID!{IID_ID3DX10PatchMesh, + 0x3ce6cc22, 0xdbf2, 0x44f4, 0x89, 0x4d, 0xf9, 0xc3, 0x4a, 0x33, 0x71, 0x39} +DEFINE_GUID!{IID_ID3DX10SkinInfo, + 0x420bd604, 0x1c76, 0x4a34, 0xa4, 0x66, 0xe4, 0x5d, 0x06, 0x58, 0xa3, 0x2c} diff --git a/winapi/src/um/datetimeapi.rs b/winapi/src/um/datetimeapi.rs new file mode 100644 index 000000000..e8102a108 --- /dev/null +++ b/winapi/src/um/datetimeapi.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_int; +use shared::minwindef::DWORD; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{LCID, LPCSTR, LPCWSTR, LPSTR, LPWSTR}; +extern "system" { + pub fn GetDateFormatA( + Locale: LCID, + dwFlags: DWORD, + lpDate: *const SYSTEMTIME, + lpFormat: LPCSTR, + lpDateStr: LPSTR, + cchDate: c_int, + ) -> c_int; + pub fn GetDateFormatW( + Locale: LCID, + dwFlags: DWORD, + lpDate: *const SYSTEMTIME, + lpFormat: LPCWSTR, + lpDateStr: LPWSTR, + cchDate: c_int, + ) -> c_int; + pub fn GetTimeFormatA( + Locale: LCID, + dwFlags: DWORD, + lpTime: *const SYSTEMTIME, + lpFormat: LPCSTR, + lpTimeStr: LPSTR, + cchTime: c_int, + ) -> c_int; + pub fn GetTimeFormatW( + Locale: LCID, + dwFlags: DWORD, + lpTime: *const SYSTEMTIME, + lpFormat: LPCWSTR, + lpTimeStr: LPWSTR, + cchTime: c_int, + ) -> c_int; + pub fn GetTimeFormatEx( + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lpTime: *const SYSTEMTIME, + lpFormat: LPCWSTR, + lpTimeStr: LPWSTR, + cchTime: c_int, + ) -> c_int; + pub fn GetDateFormatEx( + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lpDate: *const SYSTEMTIME, + lpFormat: LPCWSTR, + lpDateStr: LPWSTR, + cchDate: c_int, + lpCalendar: LPCWSTR, + ) -> c_int; +} diff --git a/winapi/src/um/davclnt.rs b/winapi/src/um/davclnt.rs new file mode 100644 index 000000000..9bfc5a371 --- /dev/null +++ b/winapi/src/um/davclnt.rs @@ -0,0 +1,104 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This module defines the DAV specific functions that are exposed to the user +use shared::minwindef::{BOOL, DWORD, LPDWORD, PBYTE, PULONG, ULONG}; +use um::winnt::{HANDLE, LPCWSTR, LPWSTR, PVOID, PWSTR}; +pub type OPAQUE_HANDLE = DWORD; +STRUCT!{struct DAV_CALLBACK_AUTH_BLOB { + pBuffer: PVOID, + ulSize: ULONG, + ulType: ULONG, +}} +pub type PDAV_CALLBACK_AUTH_BLOB = *mut DAV_CALLBACK_AUTH_BLOB; +STRUCT!{struct DAV_CALLBACK_AUTH_UNP { + pszUserName: LPWSTR, + ulUserNameLength: ULONG, + pszPassword: LPWSTR, + ulPasswordLength: ULONG, +}} +pub type PDAV_CALLBACK_AUTH_UNP = *mut DAV_CALLBACK_AUTH_UNP; +STRUCT!{struct DAV_CALLBACK_CRED { + AuthBlob: DAV_CALLBACK_AUTH_BLOB, + UNPBlob: DAV_CALLBACK_AUTH_UNP, + bAuthBlobValid: BOOL, + bSave: BOOL, +}} +pub type PDAV_CALLBACK_CRED = *mut DAV_CALLBACK_CRED; +pub const DAV_AUTHN_SCHEME_BASIC: DWORD = 0x00000001; +pub const DAV_AUTHN_SCHEME_NTLM: DWORD = 0x00000002; +pub const DAV_AUTHN_SCHEME_PASSPORT: DWORD = 0x00000004; +pub const DAV_AUTHN_SCHEME_DIGEST: DWORD = 0x00000008; +pub const DAV_AUTHN_SCHEME_NEGOTIATE: DWORD = 0x00000010; +pub const DAV_AUTHN_SCHEME_CERT: DWORD = 0x00010000; +pub const DAV_AUTHN_SCHEME_FBA: DWORD = 0x00100000; +ENUM!{enum AUTHNEXTSTEP { + DefaultBehavior, + RetryRequest, + CancelRequest, +}} +FN!{stdcall PFNDAVAUTHCALLBACK_FREECRED( + pbuffer: PVOID, +) -> DWORD} +FN!{stdcall PFNDAVAUTHCALLBACK( + lpwzServerName: LPWSTR, + lpwzRemoteName: LPWSTR, + dwAuthScheme: DWORD, + dwFlags: DWORD, + pCallbackCred: PDAV_CALLBACK_CRED, + NextStep: *mut AUTHNEXTSTEP, + pFreeCred: *mut PFNDAVAUTHCALLBACK_FREECRED, +) -> DWORD} +extern "system" { + pub fn DavAddConnection( + ConnectionHandle: *mut HANDLE, + RemoteName: LPCWSTR, + UserName: LPCWSTR, + Password: LPCWSTR, + ClientCert: PBYTE, + CertSize: DWORD, + ) -> DWORD; + pub fn DavDeleteConnection( + ConnectionHandle: HANDLE, + ) -> DWORD; + pub fn DavGetUNCFromHTTPPath( + HttpPath: LPCWSTR, + UncPath: LPWSTR, + lpSize: LPDWORD, + ) -> DWORD; + pub fn DavGetHTTPFromUNCPath( + UncPath: LPCWSTR, + HttpPath: LPWSTR, + lpSize: LPDWORD, + ) -> DWORD; + pub fn DavGetTheLockOwnerOfTheFile( + FileName: LPCWSTR, + LockOwnerName: PWSTR, + LockOwnerNameLengthInBytes: PULONG, + ) -> DWORD; + pub fn DavGetExtendedError( + hFile: HANDLE, + ExtError: *mut DWORD, + ExtErrorString: LPWSTR, + cChSize: *mut DWORD, + ) -> DWORD; + pub fn DavFlushFile( + hFile: HANDLE, + ) -> DWORD; + pub fn DavInvalidateCache( + URLName: LPWSTR, + ) -> DWORD; + pub fn DavCancelConnectionsToServer( + URLName: LPWSTR, + fForce: BOOL, + ) -> DWORD; + pub fn DavRegisterAuthCallback( + CallBack: PFNDAVAUTHCALLBACK, + Version: ULONG, + ) -> OPAQUE_HANDLE; + pub fn DavUnregisterAuthCallback( + hCallback: OPAQUE_HANDLE, + ); +} diff --git a/winapi/src/um/dbghelp.rs b/winapi/src/um/dbghelp.rs new file mode 100644 index 000000000..384c9a463 --- /dev/null +++ b/winapi/src/um/dbghelp.rs @@ -0,0 +1,667 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! DbgHelp include file +use shared::basetsd::{DWORD64, PDWORD64, ULONG64}; +use shared::guiddef::GUID; +use shared::minwindef::{ + BOOL, DWORD, HMODULE, LPDWORD, PDWORD, PUCHAR, PULONG, UCHAR, ULONG, USHORT, WORD, +}; +use um::winnt::{ + BOOLEAN, CHAR, HANDLE, LIST_ENTRY, PCSTR, PCWSTR, PIMAGE_NT_HEADERS, PIMAGE_SECTION_HEADER, + PSTR, PVOID, PWSTR, WCHAR, +}; +#[cfg(target_arch = "x86")] +use um::winnt::{ + PFPO_DATA, PIMAGE_COFF_SYMBOLS_HEADER, PIMAGE_DEBUG_DIRECTORY, PIMAGE_FUNCTION_ENTRY, + PIMAGE_NT_HEADERS32, +}; +#[cfg(target_pointer_width = "64")] +use um::winnt::PIMAGE_NT_HEADERS64; +use vc::vcruntime::size_t; +#[cfg(target_pointer_width = "64")] +STRUCT!{struct LOADED_IMAGE { + ModuleName: PSTR, + hFile: HANDLE, + MappedAddress: PUCHAR, + FileHeader: PIMAGE_NT_HEADERS64, + LastRvaSection: PIMAGE_SECTION_HEADER, + NumberOfSections: ULONG, + Sections: PIMAGE_SECTION_HEADER, + Characteristics: ULONG, + fSystemImage: BOOLEAN, + fDOSImage: BOOLEAN, + fReadOnly: BOOLEAN, + Version: UCHAR, + Links: LIST_ENTRY, + SizeOfImage: ULONG, +}} +#[cfg(target_arch = "x86")] +STRUCT!{struct LOADED_IMAGE { + ModuleName: PSTR, + hFile: HANDLE, + MappedAddress: PUCHAR, + FileHeader: PIMAGE_NT_HEADERS32, + LastRvaSection: PIMAGE_SECTION_HEADER, + NumberOfSections: ULONG, + Sections: PIMAGE_SECTION_HEADER, + Characteristics: ULONG, + fSystemImage: BOOLEAN, + fDOSImage: BOOLEAN, + fReadOnly: BOOLEAN, + Version: UCHAR, + Links: LIST_ENTRY, + SizeOfImage: ULONG, +}} +pub const MAX_SYM_NAME: usize = 2000; +pub const ERROR_IMAGE_NOT_STRIPPED: DWORD = 0x8800; +pub const ERROR_NO_DBG_POINTER: DWORD = 0x8801; +pub const ERROR_NO_PDB_POINTER: DWORD = 0x8802; +FN!{stdcall PFIND_DEBUG_FILE_CALLBACK( + FileHandle: HANDLE, + FileName: PCSTR, + CallerData: PVOID, +) -> BOOL} +FN!{stdcall PFIND_DEBUG_FILE_CALLBACKW( + FileHandle: HANDLE, + FileName: PCWSTR, + CallerData: PVOID, +) -> BOOL} +FN!{stdcall PFINDFILEINPATHCALLBACK( + filename: PCSTR, + context: PVOID, +) -> BOOL} +FN!{stdcall PFINDFILEINPATHCALLBACKW( + filename: PCWSTR, + context: PVOID, +) -> BOOL} +FN!{stdcall PFIND_EXE_FILE_CALLBACK( + FileHandle: HANDLE, + FileName: PCSTR, + CallerData: PVOID, +) -> BOOL} +FN!{stdcall PFIND_EXE_FILE_CALLBACKW( + FileHandle: HANDLE, + FileName: PCWSTR, + CallerData: PVOID, +) -> BOOL} +FN!{stdcall PSYM_ENUMERATESYMBOLS_CALLBACKW( + pSymInfo: PSYMBOL_INFOW, + SymbolSize: ULONG, + CallerData: PVOID, +) -> BOOL} +#[cfg(target_arch = "x86")] +STRUCT!{struct IMAGE_DEBUG_INFORMATION { + List: LIST_ENTRY, + ReservedSize: DWORD, + ReservedMappedBase: PVOID, + ReservedMachine: USHORT, + ReservedCharacteristics: USHORT, + ReservedCheckSum: DWORD, + ImageBase: DWORD, + SizeOfImage: DWORD, + ReservedNumberOfSections: DWORD, + ReservedSections: PIMAGE_SECTION_HEADER, + ReservedExportedNamesSize: DWORD, + ReservedExportedNames: PSTR, + ReservedNumberOfFunctionTableEntries: DWORD, + ReservedFunctionTableEntries: PIMAGE_FUNCTION_ENTRY, + ReservedLowestFunctionStartingAddress: DWORD, + ReservedHighestFunctionEndingAddress: DWORD, + ReservedNumberOfFpoTableEntries: DWORD, + ReservedFpoTableEntries: PFPO_DATA, + SizeOfCoffSymbols: DWORD, + CoffSymbols: PIMAGE_COFF_SYMBOLS_HEADER, + ReservedSizeOfCodeViewSymbols: DWORD, + ReservedCodeViewSymbols: PVOID, + ImageFilePath: PSTR, + ImageFileName: PSTR, + ReservedDebugFilePath: PSTR, + ReservedTimeDateStamp: DWORD, + ReservedRomImage: BOOL, + ReservedDebugDirectory: PIMAGE_DEBUG_DIRECTORY, + ReservedNumberOfDebugDirectories: DWORD, + ReservedOriginalFunctionTableBaseAddress: DWORD, + Reserved: [DWORD; 2], +}} +#[cfg(target_arch = "x86")] +pub type PIMAGE_DEBUG_INFORMATION = *mut IMAGE_DEBUG_INFORMATION; +FN!{stdcall PENUMDIRTREE_CALLBACK( + FilePath: PCSTR, + CallerData: PVOID, +) -> BOOL} +FN!{stdcall PENUMDIRTREE_CALLBACKW( + FilePath: PCWSTR, + CallerData: PVOID, +) -> BOOL} +pub const UNDNAME_COMPLETE: DWORD = 0x0000; +pub const UNDNAME_NO_LEADING_UNDERSCORES: DWORD = 0x0001; +pub const UNDNAME_NO_MS_KEYWORDS: DWORD = 0x0002; +pub const UNDNAME_NO_FUNCTION_RETURNS: DWORD = 0x0004; +pub const UNDNAME_NO_ALLOCATION_MODEL: DWORD = 0x0008; +pub const UNDNAME_NO_ALLOCATION_LANGUAGE: DWORD = 0x0010; +pub const UNDNAME_NO_MS_THISTYPE: DWORD = 0x0020; +pub const UNDNAME_NO_CV_THISTYPE: DWORD = 0x0040; +pub const UNDNAME_NO_THISTYPE: DWORD = 0x0060; +pub const UNDNAME_NO_ACCESS_SPECIFIERS: DWORD = 0x0080; +pub const UNDNAME_NO_THROW_SIGNATURES: DWORD = 0x0100; +pub const UNDNAME_NO_MEMBER_TYPE: DWORD = 0x0200; +pub const UNDNAME_NO_RETURN_UDT_MODEL: DWORD = 0x0400; +pub const UNDNAME_32_BIT_DECODE: DWORD = 0x0800; +pub const UNDNAME_NAME_ONLY: DWORD = 0x1000; +pub const UNDNAME_NO_ARGUMENTS: DWORD = 0x2000; +pub const UNDNAME_NO_SPECIAL_SYMS: DWORD = 0x4000; +pub const DBHHEADER_DEBUGDIRS: DWORD = 0x1; +pub const DBHHEADER_CVMISC: DWORD = 0x2; +pub const DBHHEADER_PDBGUID: DWORD = 0x3; +STRUCT!{struct MODLOAD_DATA { + ssize: DWORD, + ssig: DWORD, + data: PVOID, + size: DWORD, + flags: DWORD, +}} +pub type PMODLOAD_DATA = *mut MODLOAD_DATA; +STRUCT!{struct MODLOAD_CVMISC { + oCV: DWORD, + cCV: size_t, + oMisc: DWORD, + cMisc: size_t, + dtImage: DWORD, + cImage: DWORD, +}} +pub type PMODLOAD_CVMISC = *mut MODLOAD_CVMISC; +STRUCT!{struct MODLOAD_PDBGUID_PDBAGE { + PdbGuid: GUID, + PdbAge: DWORD, +}} +pub type PMODLOAD_PDBGUID_PDBAGE = *mut MODLOAD_PDBGUID_PDBAGE; +ENUM!{enum ADDRESS_MODE { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat, +}} +STRUCT!{struct ADDRESS64 { + Offset: DWORD64, + Segment: WORD, + Mode: ADDRESS_MODE, +}} +pub type LPADDRESS64 = *mut ADDRESS64; +#[cfg(target_pointer_width = "64")] +pub type ADDRESS = ADDRESS64; +#[cfg(target_pointer_width = "64")] +pub type LPADDRESS = LPADDRESS64; +#[cfg(target_arch = "x86")] +STRUCT!{struct ADDRESS { + Offset: DWORD, + Segment: WORD, + Mode: ADDRESS_MODE, +}} +#[cfg(target_arch = "x86")] +pub type LPADDRESS = *mut ADDRESS; +STRUCT!{struct KDHELP64 { + Thread: DWORD64, + ThCallbackStack: DWORD, + ThCallbackBStore: DWORD, + NextCallback: DWORD, + FramePointer: DWORD, + KiCallUserMode: DWORD64, + KeUserCallbackDispatcher: DWORD64, + SystemRangeStart: DWORD64, + KiUserExceptionDispatcher: DWORD64, + StackBase: DWORD64, + StackLimit: DWORD64, + BuildVersion: DWORD, + Reserved0: DWORD, + Reserved1: [DWORD64; 4], +}} +pub type PKDHELP64 = *mut KDHELP64; +#[cfg(target_pointer_width = "64")] +pub type KDHELP = KDHELP64; +#[cfg(target_pointer_width = "64")] +pub type PKDHELP = PKDHELP64; +#[cfg(target_arch = "x86")] +STRUCT!{struct KDHELP { + Thread: DWORD, + ThCallbackStack: DWORD, + NextCallback: DWORD, + FramePointer: DWORD, + KiCallUserMode: DWORD, + KeUserCallbackDispatcher: DWORD, + SystemRangeStart: DWORD, + ThCallbackBStore: DWORD, + KiUserExceptionDispatcher: DWORD, + StackBase: DWORD, + StackLimit: DWORD, + Reserved: [DWORD; 5], +}} +#[cfg(target_arch = "x86")] +pub type PKDHELP = *mut KDHELP; +STRUCT!{struct STACKFRAME64 { + AddrPC: ADDRESS64, + AddrReturn: ADDRESS64, + AddrFrame: ADDRESS64, + AddrStack: ADDRESS64, + AddrBStore: ADDRESS64, + FuncTableEntry: PVOID, + Params: [DWORD64; 4], + Far: BOOL, + Virtual: BOOL, + Reserved: [DWORD64; 3], + KdHelp: KDHELP64, +}} +pub type LPSTACKFRAME64 = *mut STACKFRAME64; +pub const INLINE_FRAME_CONTEXT_INIT: DWORD = 0; +pub const INLINE_FRAME_CONTEXT_IGNORE: DWORD = 0xFFFFFFFF; +STRUCT!{struct STACKFRAME_EX { + AddrPC: ADDRESS64, + AddrReturn: ADDRESS64, + AddrFrame: ADDRESS64, + AddrStack: ADDRESS64, + AddrBStore: ADDRESS64, + FuncTableEntry: PVOID, + Params: [DWORD64; 4], + Far: BOOL, + Virtual: BOOL, + Reserved: [DWORD64; 3], + KdHelp: KDHELP64, + StackFrameSize: DWORD, + InlineFrameContext: DWORD, +}} +pub type LPSTACKFRAME_EX = *mut STACKFRAME_EX; +#[cfg(target_pointer_width = "64")] +pub type STACKFRAME = STACKFRAME64; +#[cfg(target_pointer_width = "64")] +pub type LPSTACKFRAME = LPSTACKFRAME64; +#[cfg(target_arch = "x86")] +STRUCT!{struct STACKFRAME { + AddrPC: ADDRESS, + AddrReturn: ADDRESS, + AddrFrame: ADDRESS, + AddrStack: ADDRESS, + FuncTableEntry: PVOID, + Params: [DWORD; 4], + Far: BOOL, + Virtual: BOOL, + Reserved: [DWORD; 3], + KdHelp: KDHELP, + AddrBStore: ADDRESS, +}} +#[cfg(target_arch = "x86")] +pub type LPSTACKFRAME = *mut STACKFRAME; +FN!{stdcall PREAD_PROCESS_MEMORY_ROUTINE64( + hProcess: HANDLE, + qwBaseAddress: DWORD64, + lpBuffer: PVOID, + nSize: DWORD, + lpNumberOfBytesRead: LPDWORD, +) -> BOOL} +FN!{stdcall PFUNCTION_TABLE_ACCESS_ROUTINE64( + ahProcess: HANDLE, + AddrBase: DWORD64, +) -> PVOID} +FN!{stdcall PGET_MODULE_BASE_ROUTINE64( + hProcess: HANDLE, + Address: DWORD64, +) -> DWORD64} +FN!{stdcall PTRANSLATE_ADDRESS_ROUTINE64( + hProcess: HANDLE, + hThread: HANDLE, + lpaddr: LPADDRESS64, +) -> DWORD64} +pub const SYM_STKWALK_DEFAULT: DWORD = 0x00000000; +pub const SYM_STKWALK_FORCE_FRAMEPTR: DWORD = 0x00000001; +#[cfg(target_pointer_width = "64")] +pub type PREAD_PROCESS_MEMORY_ROUTINE = PREAD_PROCESS_MEMORY_ROUTINE64; +#[cfg(target_pointer_width = "64")] +pub type PFUNCTION_TABLE_ACCESS_ROUTINE = PFUNCTION_TABLE_ACCESS_ROUTINE64; +#[cfg(target_pointer_width = "64")] +pub type PGET_MODULE_BASE_ROUTINE = PGET_MODULE_BASE_ROUTINE64; +#[cfg(target_pointer_width = "64")] +pub type PTRANSLATE_ADDRESS_ROUTINE = PTRANSLATE_ADDRESS_ROUTINE64; +#[cfg(target_arch = "x86")] +FN!{stdcall PREAD_PROCESS_MEMORY_ROUTINE( + hProcess: HANDLE, + qwBaseAddress: DWORD, + lpBuffer: PVOID, + nSize: DWORD, + lpNumberOfBytesRead: PDWORD, +) -> BOOL} +#[cfg(target_arch = "x86")] +FN!{stdcall PFUNCTION_TABLE_ACCESS_ROUTINE( + ahProcess: HANDLE, + AddrBase: DWORD, +) -> PVOID} +#[cfg(target_arch = "x86")] +FN!{stdcall PGET_MODULE_BASE_ROUTINE( + hProcess: HANDLE, + Address: DWORD, +) -> DWORD} +#[cfg(target_arch = "x86")] +FN!{stdcall PTRANSLATE_ADDRESS_ROUTINE( + hProcess: HANDLE, + hThread: HANDLE, + lpaddr: LPADDRESS, +) -> DWORD} +pub const API_VERSION_NUMBER: USHORT = 12; +STRUCT!{struct API_VERSION { + MajorVersion: USHORT, + MinorVersion: USHORT, + Revision: USHORT, + Reserved: USHORT, +}} +pub type LPAPI_VERSION = *mut API_VERSION; +STRUCT!{struct SYMBOL_INFOW { + SizeOfStruct: ULONG, + TypeIndex: ULONG, + Reserved: [ULONG64; 2], + Index: ULONG, + Size: ULONG, + ModBase: ULONG64, + Flags: ULONG, + Value: ULONG64, + Address: ULONG64, + Register: ULONG, + Scope: ULONG, + Tag: ULONG, + NameLen: ULONG, + MaxNameLen: ULONG, + Name: [WCHAR; 1], +}} +pub type PSYMBOL_INFOW = *mut SYMBOL_INFOW; +STRUCT!{struct IMAGEHLP_SYMBOL64 { + SizeOfStruct: DWORD, + Address: DWORD64, + Size: DWORD, + Flags: DWORD, + MaxNameLength: DWORD, + Name: [CHAR; 1], +}} +pub type PIMAGEHLP_SYMBOL64 = *mut IMAGEHLP_SYMBOL64; +STRUCT!{struct IMAGEHLP_LINEW64 { + SizeOfStruct: DWORD, + Key: PVOID, + LineNumber: DWORD, + FileName: PWSTR, + Address: DWORD64, +}} +pub type PIMAGEHLP_LINEW64 = *mut IMAGEHLP_LINEW64; +extern "system" { + pub fn EnumDirTree( + hProcess: HANDLE, + RootPath: PCSTR, + InputPathName: PCSTR, + OutputPathBuffer: PSTR, + cb: PENUMDIRTREE_CALLBACK, + data: PVOID, + ) -> BOOL; + pub fn EnumDirTreeW( + hProcess: HANDLE, + RootPath: PCWSTR, + InputPathName: PCWSTR, + OutputPathBuffer: PWSTR, + cb: PENUMDIRTREE_CALLBACKW, + data: PVOID, + ) -> BOOL; + pub fn ImagehlpApiVersion() -> LPAPI_VERSION; + pub fn ImagehlpApiVersionEx( + AppVersion: LPAPI_VERSION, + ) -> LPAPI_VERSION; + pub fn MakeSureDirectoryPathExists( + DirPath: PCSTR, + ) -> BOOL; + pub fn SearchTreeForFile( + RootPath: PCSTR, + InputPathName: PCSTR, + OutputPathBuffer: PSTR, + ) -> BOOL; + pub fn SearchTreeForFileW( + RootPath: PCWSTR, + InputPathName: PCWSTR, + OutputPathBuffer: PWSTR, + ) -> BOOL; + pub fn FindDebugInfoFile( + FileName: PCSTR, + SymbolPath: PCSTR, + DebugFilePath: PSTR, + ) -> HANDLE; + pub fn FindDebugInfoFileEx( + FileName: PCSTR, + SymbolPath: PCSTR, + DebugFilePath: PSTR, + Callback: PFIND_DEBUG_FILE_CALLBACK, + CallerData: PVOID, + ) -> HANDLE; + pub fn FindDebugInfoFileExW( + FileName: PCWSTR, + SymbolPath: PCWSTR, + DebugFilePath: PWSTR, + Callback: PFIND_DEBUG_FILE_CALLBACKW, + CallerData: PVOID, + ) -> HANDLE; + pub fn FindExecutableImage( + FileName: PCSTR, + SymbolPath: PCSTR, + ImageFilePath: PSTR, + ) -> HANDLE; + pub fn FindExecutableImageEx( + FileName: PCSTR, + SymbolPath: PCSTR, + ImageFilePath: PSTR, + Callback: PFIND_EXE_FILE_CALLBACK, + CallerData: PVOID, + ) -> HANDLE; + pub fn FindExecutableImageExW( + FileName: PCWSTR, + SymbolPath: PCWSTR, + ImageFilePath: PWSTR, + Callback: PFIND_EXE_FILE_CALLBACKW, + CallerData: PVOID, + ) -> HANDLE; + pub fn StackWalk( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE, + ) -> BOOL; + pub fn StackWalkEx( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME64, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64, + Flags: DWORD, + ) -> BOOL; + pub fn StackWalk64( + MachineType: DWORD, + hProcess: HANDLE, + hThread: HANDLE, + StackFrame: LPSTACKFRAME64, + ContextRecord: PVOID, + ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64, + FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64, + GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64, + TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64, + ) -> BOOL; + pub fn UnDecorateSymbolName( + name: PCSTR, + outputString: PSTR, + maxStringLength: DWORD, + flags: DWORD, + ) -> DWORD; + pub fn UnDecorateSymbolNameW( + name: PCWSTR, + outputString: PWSTR, + maxStringLength: DWORD, + flags: DWORD, + ) -> DWORD; + pub fn GetTimestampForLoadedLibrary( + Module: HMODULE, + ) -> DWORD; + pub fn ImageDirectoryEntryToData( + Base: PVOID, + MappedAsImage: BOOLEAN, + DirectoryEntry: USHORT, + Size: PULONG, + ) -> PVOID; + pub fn ImageDirectoryEntryToDataEx( + Base: PVOID, + MappedAsImage: BOOLEAN, + DirectoryEntry: USHORT, + Size: PULONG, + FoundHeader: *mut PIMAGE_SECTION_HEADER, + ) -> PVOID; + pub fn ImageNtHeader( + Base: PVOID, + ) -> PIMAGE_NT_HEADERS; + pub fn ImageRvaToSection( + NtHeaders: PIMAGE_NT_HEADERS, + Base: PVOID, + Rva: ULONG, + ) -> PIMAGE_SECTION_HEADER; + pub fn ImageRvaToVa( + NtHeaders: PIMAGE_NT_HEADERS, + Base: PVOID, + Rva: ULONG, + LastRvaSection: *mut PIMAGE_SECTION_HEADER, + ) -> PVOID; + pub fn SymCleanup( + hProcess: HANDLE, + ) -> BOOL; + pub fn SymEnumSymbolsW( + hProcess: HANDLE, + BaseOfDll: ULONG64, + Mask: PCWSTR, + EnumSymbolsCallback: PSYM_ENUMERATESYMBOLS_CALLBACKW, + CallerData: PVOID, + ) -> BOOL; + pub fn SymFindDebugInfoFile( + hProcess: HANDLE, + FileName: PCSTR, + DebugFilePath: PSTR, + Callback: PFIND_DEBUG_FILE_CALLBACK, + CallerData: PVOID, + ) -> HANDLE; + pub fn SymFindDebugInfoFileW( + hProcess: HANDLE, + FileName: PCWSTR, + DebugFilePath: PWSTR, + Callback: PFIND_DEBUG_FILE_CALLBACKW, + CallerData: PVOID, + ) -> HANDLE; + pub fn SymFindExecutableImage( + hProcess: HANDLE, + FileName: PCSTR, + ImageFilePath: PSTR, + Callback: PFIND_EXE_FILE_CALLBACK, + CallerData: PVOID, + ) -> HANDLE; + pub fn SymFindExecutableImageW( + hProcess: HANDLE, + FileName: PCWSTR, + ImageFilePath: PWSTR, + Callback: PFIND_EXE_FILE_CALLBACKW, + CallerData: PVOID, + ) -> HANDLE; + pub fn SymFindFileInPath( + hprocess: HANDLE, + SearchPath: PCSTR, + FileName: PCSTR, + id: PVOID, + two: DWORD, + three: DWORD, + flags: DWORD, + FoundFile: PSTR, + callback: PFINDFILEINPATHCALLBACK, + context: PVOID, + ) -> BOOL; + pub fn SymFindFileInPathW( + hprocess: HANDLE, + SearchPath: PCWSTR, + FileName: PCWSTR, + id: PVOID, + two: DWORD, + three: DWORD, + flags: DWORD, + FoundFile: PWSTR, + callback: PFINDFILEINPATHCALLBACKW, + context: PVOID, + ) -> BOOL; + pub fn SymFromAddrW( + hProcess: HANDLE, + Address: DWORD64, + Displacement: PDWORD64, + Symbol: PSYMBOL_INFOW, + ) -> BOOL; + pub fn SymFromNameW( + hProcess: HANDLE, + Name: PCWSTR, + Symbol: PSYMBOL_INFOW, + ) -> BOOL; + pub fn SymFunctionTableAccess64( + hProcess: HANDLE, + AddrBase: DWORD64, + ) -> PVOID; + pub fn SymGetLineFromAddrW64( + hProcess: HANDLE, + dwAddr: DWORD64, + pdwDisplacement: PDWORD, + Line: PIMAGEHLP_LINEW64, + ) -> BOOL; + pub fn SymGetModuleBase64( + hProcess: HANDLE, + AddrBase: DWORD64, + ) -> DWORD64; + pub fn SymGetSymFromAddr64( + hProcess: HANDLE, + Address: DWORD64, + Displacement: PDWORD64, + Symbol: PIMAGEHLP_SYMBOL64, + ) -> BOOL; + pub fn SymInitializeW( + hProcess: HANDLE, + UserSearchPath: PCWSTR, + fInvadeProcess: BOOL, + ) -> BOOL; + pub fn SymLoadModuleExW( + hProcess: HANDLE, + hFile: HANDLE, + ImageName: PCWSTR, + ModuleName: PCWSTR, + BaseOfDll: DWORD64, + SizeOfDll: DWORD, + Data: PMODLOAD_DATA, + Flags: DWORD, + ) -> DWORD64; + pub fn SymUnloadModule( + hProcess: HANDLE, + BaseOfDll: DWORD, + ) -> BOOL; + pub fn SymUnloadModule64( + hProcess: HANDLE, + BaseOfDll: DWORD64, + ) -> BOOL; + #[cfg(any(target_arch = "x86", target_arch = "arm"))] + pub fn MapDebugInformation( + FileHandle: HANDLE, + FileName: PCSTR, + SymbolPath: PCSTR, + ImageBase: ULONG, + ) -> PIMAGE_DEBUG_INFORMATION; + #[cfg(any(target_arch = "x86", target_arch = "arm"))] + pub fn UnmapDebugInformation( + DebugInfo: PIMAGE_DEBUG_INFORMATION, + ) -> BOOL; +} diff --git a/winapi/src/um/dbt.rs b/winapi/src/um/dbt.rs new file mode 100644 index 000000000..e95a58ce9 --- /dev/null +++ b/winapi/src/um/dbt.rs @@ -0,0 +1,192 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, wchar_t}; +use shared::basetsd::{ULONG32, ULONG64}; +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, DWORD, UINT, WORD, WPARAM}; +use um::winnt::{HANDLE, LONG}; +use um::winuser::HDEVNOTIFY; +pub const WM_DEVICECHANGE: UINT = 0x0219; +pub const BSF_QUERY: DWORD = 0x00000001; +pub const BSF_IGNORECURRENTTASK: DWORD = 0x00000002; +pub const BSF_FLUSHDISK: DWORD = 0x00000004; +pub const BSF_NOHANG: DWORD = 0x00000008; +pub const BSF_POSTMESSAGE: DWORD = 0x00000010; +pub const BSF_FORCEIFHUNG: DWORD = 0x00000020; +pub const BSF_NOTIMEOUTIFNOTHUNG: DWORD = 0x00000040; +pub const BSF_MSGSRV32ISOK: DWORD = 0x80000000; +pub const BSF_MSGSRV32ISOK_BIT: usize = 31; +pub const BSM_ALLCOMPONENTS: DWORD = 0x00000000; +pub const BSM_VXDS: DWORD = 0x00000001; +pub const BSM_NETDRIVER: DWORD = 0x00000002; +pub const BSM_INSTALLABLEDRIVERS: DWORD = 0x00000004; +pub const BSM_APPLICATIONS: DWORD = 0x00000008; +pub const DBT_APPYBEGIN: WPARAM = 0x0000; +pub const DBT_APPYEND: WPARAM = 0x0001; +pub const DBT_DEVNODES_CHANGED: WPARAM = 0x0007; +pub const DBT_QUERYCHANGECONFIG: WPARAM = 0x0017; +pub const DBT_CONFIGCHANGED: WPARAM = 0x0018; +pub const DBT_CONFIGCHANGECANCELED: WPARAM = 0x0019; +pub const DBT_MONITORCHANGE: WPARAM = 0x001B; +pub const DBT_SHELLLOGGEDON: WPARAM = 0x0020; +pub const DBT_CONFIGMGAPI32: WPARAM = 0x0022; +pub const DBT_VXDINITCOMPLETE: WPARAM = 0x0023; +pub const DBT_VOLLOCKQUERYLOCK: WPARAM = 0x8041; +pub const DBT_VOLLOCKLOCKTAKEN: WPARAM = 0x8042; +pub const DBT_VOLLOCKLOCKFAILED: WPARAM = 0x8043; +pub const DBT_VOLLOCKQUERYUNLOCK: WPARAM = 0x8044; +pub const DBT_VOLLOCKLOCKRELEASED: WPARAM = 0x8045; +pub const DBT_VOLLOCKUNLOCKFAILED: WPARAM = 0x8046; +STRUCT!{struct DEV_BROADCAST_HDR { + dbch_size: DWORD, + dbch_devicetype: DWORD, + dbch_reserved: DWORD, +}} +pub type PDEV_BROADCAST_HDR = *mut DEV_BROADCAST_HDR; +STRUCT!{struct VolLockBroadcast { + vlb_dbh: DEV_BROADCAST_HDR, + vlb_owner: DWORD, + vlb_perms: BYTE, + vlb_lockType: BYTE, + vlb_drive: BYTE, + vlb_flags: BYTE, +}} +pub type pVolLockBroadcast = *mut VolLockBroadcast; +pub const LOCKP_ALLOW_WRITES: BYTE = 0x01; +pub const LOCKP_FAIL_WRITES: BYTE = 0x00; +pub const LOCKP_FAIL_MEM_MAPPING: BYTE = 0x02; +pub const LOCKP_ALLOW_MEM_MAPPING: BYTE = 0x00; +pub const LOCKP_USER_MASK: BYTE = 0x03; +pub const LOCKP_LOCK_FOR_FORMAT: BYTE = 0x04; +pub const LOCKF_LOGICAL_LOCK: BYTE = 0x00; +pub const LOCKF_PHYSICAL_LOCK: BYTE = 0x01; +pub const DBT_NO_DISK_SPACE: WPARAM = 0x0047; +pub const DBT_LOW_DISK_SPACE: WPARAM = 0x0048; +pub const DBT_CONFIGMGPRIVATE: WPARAM = 0x7FFF; +pub const DBT_DEVICEARRIVAL: WPARAM = 0x8000; +pub const DBT_DEVICEQUERYREMOVE: WPARAM = 0x8001; +pub const DBT_DEVICEQUERYREMOVEFAILED: WPARAM = 0x8002; +pub const DBT_DEVICEREMOVEPENDING: WPARAM = 0x8003; +pub const DBT_DEVICEREMOVECOMPLETE: WPARAM = 0x8004; +pub const DBT_DEVICETYPESPECIFIC: WPARAM = 0x8005; +pub const DBT_CUSTOMEVENT: WPARAM = 0x8006; +pub const DBT_DEVTYP_OEM: DWORD = 0x00000000; +pub const DBT_DEVTYP_DEVNODE: DWORD = 0x00000001; +pub const DBT_DEVTYP_VOLUME: DWORD = 0x00000002; +pub const DBT_DEVTYP_PORT: DWORD = 0x00000003; +pub const DBT_DEVTYP_NET: DWORD = 0x00000004; +pub const DBT_DEVTYP_DEVICEINTERFACE: DWORD = 0x00000005; +pub const DBT_DEVTYP_HANDLE: DWORD = 0x00000006; +STRUCT!{struct _DEV_BROADCAST_HEADER { + dbcd_size: DWORD, + dbcd_devicetype: DWORD, + dbcd_reserved: DWORD, +}} +STRUCT!{struct DEV_BROADCAST_OEM { + dbco_size: DWORD, + dbco_devicetype: DWORD, + dbco_reserved: DWORD, + dbco_identifier: DWORD, + dbco_suppfunc: DWORD, +}} +pub type PDEV_BROADCAST_OEM = *mut DEV_BROADCAST_OEM; +STRUCT!{struct DEV_BROADCAST_DEVNODE { + dbcd_size: DWORD, + dbcd_devicetype: DWORD, + dbcd_reserved: DWORD, + dbcd_devnode: DWORD, +}} +pub type PDEV_BROADCAST_DEVNODE = *mut DEV_BROADCAST_DEVNODE; +STRUCT!{struct DEV_BROADCAST_VOLUME { + dbcv_size: DWORD, + dbcv_devicetype: DWORD, + dbcv_reserved: DWORD, + dbcv_unitmask: DWORD, + dbcv_flags: WORD, +}} +pub type PDEV_BROADCAST_VOLUME = *mut DEV_BROADCAST_VOLUME; +pub const DBTF_MEDIA: WORD = 0x0001; +pub const DBTF_NET: WORD = 0x0002; +STRUCT!{struct DEV_BROADCAST_PORT_A { + dbcp_size: DWORD, + dbcp_devicetype: DWORD, + dbcp_reserved: DWORD, + dbcp_name: [c_char; 1], +}} +pub type PDEV_BROADCAST_PORT_A = *mut DEV_BROADCAST_PORT_A; +STRUCT!{struct DEV_BROADCAST_PORT_W { + dbcp_size: DWORD, + dbcp_devicetype: DWORD, + dbcp_reserved: DWORD, + dbcp_name: [wchar_t; 1], +}} +pub type PDEV_BROADCAST_PORT_W = *mut DEV_BROADCAST_PORT_W; +STRUCT!{struct DEV_BROADCAST_NET { + dbcn_size: DWORD, + dbcn_devicetype: DWORD, + dbcn_reserved: DWORD, + dbcn_resource: DWORD, + dbcn_flags: DWORD, +}} +pub type PDEV_BROADCAST_NET = *mut DEV_BROADCAST_NET; +STRUCT!{struct DEV_BROADCAST_DEVICEINTERFACE_A { + dbcc_size: DWORD, + dbcc_devicetype: DWORD, + dbcc_reserved: DWORD, + dbcc_classguid: GUID, + dbcc_name: [c_char; 1], +}} +pub type PDEV_BROADCAST_DEVICEINTERFACE_A = *mut DEV_BROADCAST_DEVICEINTERFACE_A; +STRUCT!{struct DEV_BROADCAST_DEVICEINTERFACE_W { + dbcc_size: DWORD, + dbcc_devicetype: DWORD, + dbcc_reserved: DWORD, + dbcc_classguid: GUID, + dbcc_name: [wchar_t; 1], +}} +pub type PDEV_BROADCAST_DEVICEINTERFACE_W = *mut DEV_BROADCAST_DEVICEINTERFACE_W; +STRUCT!{struct DEV_BROADCAST_HANDLE { + dbch_size: DWORD, + dbch_devicetype: DWORD, + dbch_reserved: DWORD, + dbch_handle: HANDLE, + dbch_hdevnotify: HDEVNOTIFY, + dbch_eventguid: GUID, + dbch_nameoffset: LONG, + dbch_data: [BYTE; 1], +}} +pub type PDEV_BROADCAST_HANDLE = *mut DEV_BROADCAST_HANDLE; +STRUCT!{struct DEV_BROADCAST_HANDLE32 { + dbch_size: DWORD, + dbch_devicetype: DWORD, + dbch_reserved: DWORD, + dbch_handle: ULONG32, + dbch_hdevnotify: ULONG32, + dbch_eventguid: GUID, + dbch_nameoffset: LONG, + dbch_data: [BYTE; 1], +}} +pub type PDEV_BROADCAST_HANDLE32 = *mut DEV_BROADCAST_HANDLE32; +STRUCT!{struct DEV_BROADCAST_HANDLE64 { + dbch_size: DWORD, + dbch_devicetype: DWORD, + dbch_reserved: DWORD, + dbch_handle: ULONG64, + dbch_hdevnotify: ULONG64, + dbch_eventguid: GUID, + dbch_nameoffset: LONG, + dbch_data: [BYTE; 1], +}} +pub type PDEV_BROADCAST_HANDLE64 = *mut DEV_BROADCAST_HANDLE64; +pub const DBTF_RESOURCE: DWORD = 0x00000001; +pub const DBTF_XPORT: DWORD = 0x00000002; +pub const DBTF_SLOWNET: DWORD = 0x00000004; +pub const DBT_VPOWERDAPI: WPARAM = 0x8100; +pub const DBT_USERDEFINED: WPARAM = 0xFFFF; +STRUCT!{struct _DEV_BROADCAST_USERDEFINED { + dbud_dbh: DEV_BROADCAST_HDR, + dbud_szName: [c_char; 1], +}} diff --git a/winapi/src/um/dcommon.rs b/winapi/src/um/dcommon.rs new file mode 100644 index 000000000..e0260cbd9 --- /dev/null +++ b/winapi/src/um/dcommon.rs @@ -0,0 +1,114 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dcommon.h +use ctypes::c_void; +use shared::basetsd::UINT32; +use shared::dxgiformat::DXGI_FORMAT; +use shared::minwindef::FLOAT; +use shared::windef::{POINT, RECT}; +ENUM!{enum DWRITE_MEASURING_MODE { + DWRITE_MEASURING_MODE_NATURAL = 0, + DWRITE_MEASURING_MODE_GDI_CLASSIC = 1, + DWRITE_MEASURING_MODE_GDI_NATURAL = 2, +}} +ENUM!{enum DWRITE_GLYPH_IMAGE_FORMATS { + DWRITE_GLYPH_IMAGE_FORMATS_NONE = 0x00000000, + DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE = 0x00000001, + DWRITE_GLYPH_IMAGE_FORMATS_CFF = 0x00000002, + DWRITE_GLYPH_IMAGE_FORMATS_COLR = 0x00000004, + DWRITE_GLYPH_IMAGE_FORMATS_SVG = 0x00000008, + DWRITE_GLYPH_IMAGE_FORMATS_PNG = 0x00000010, + DWRITE_GLYPH_IMAGE_FORMATS_JPEG = 0x00000020, + DWRITE_GLYPH_IMAGE_FORMATS_TIFF = 0x00000040, + DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8 = 0x00000080, +}} +STRUCT!{struct DWRITE_GLYPH_IMAGE_DATA { + imageData: *const c_void, + imageDataSize: UINT32, + uniqueDataId: UINT32, + pixelsPerEm: UINT32, + pixelSize: D2D1_SIZE_U, + horizontalLeftOrigin: D2D1_POINT_2L, + horizontalRightOrigin: D2D1_POINT_2L, + verticalTopOrigin: D2D1_POINT_2L, + verticalBottomOrigin: D2D1_POINT_2L, +}} +ENUM!{enum D2D1_ALPHA_MODE { + D2D1_ALPHA_MODE_UNKNOWN = 0, + D2D1_ALPHA_MODE_PREMULTIPLIED = 1, + D2D1_ALPHA_MODE_STRAIGHT = 2, + D2D1_ALPHA_MODE_IGNORE = 3, +}} +STRUCT!{struct D2D1_PIXEL_FORMAT { + format: DXGI_FORMAT, + alphaMode: D2D1_ALPHA_MODE, +}} +STRUCT!{struct D2D_POINT_2U { + x: UINT32, + y: UINT32, +}} +STRUCT!{struct D2D_POINT_2F { + x: FLOAT, + y: FLOAT, +}} +pub type D2D_POINT_2L = POINT; +STRUCT!{struct D2D_VECTOR_2F { + x: FLOAT, + y: FLOAT, +}} +STRUCT!{struct D2D_VECTOR_3F { + x: FLOAT, + y: FLOAT, + z: FLOAT, +}} +STRUCT!{struct D2D_VECTOR_4F { + x: FLOAT, + y: FLOAT, + z: FLOAT, + w: FLOAT, +}} +STRUCT!{struct D2D_RECT_F { + left: FLOAT, + top: FLOAT, + right: FLOAT, + bottom: FLOAT, +}} +STRUCT!{struct D2D_RECT_U { + left: UINT32, + top: UINT32, + right: UINT32, + bottom: UINT32, +}} +pub type D2D_RECT_L = RECT; +STRUCT!{struct D2D_SIZE_F { + width: FLOAT, + height: FLOAT, +}} +STRUCT!{struct D2D_SIZE_U { + width: UINT32, + height: UINT32, +}} +STRUCT!{struct D2D_MATRIX_3X2_F { + matrix: [[FLOAT; 2]; 3], +}} +STRUCT!{struct D2D_MATRIX_4X3_F { + matrix: [[FLOAT; 3]; 4], +}} +STRUCT!{struct D2D_MATRIX_4X4_F { + matrix: [[FLOAT; 4]; 4], +}} +STRUCT!{struct D2D_MATRIX_5X4_F { + matrix: [[FLOAT; 4]; 5], +}} +pub type D2D1_POINT_2F = D2D_POINT_2F; +pub type D2D1_POINT_2U = D2D_POINT_2U; +pub type D2D1_POINT_2L = D2D_POINT_2L; +pub type D2D1_RECT_F = D2D_RECT_F; +pub type D2D1_RECT_U = D2D_RECT_U; +pub type D2D1_RECT_L = D2D_RECT_L; +pub type D2D1_SIZE_F = D2D_SIZE_F; +pub type D2D1_SIZE_U = D2D_SIZE_U; +pub type D2D1_MATRIX_3X2_F = D2D_MATRIX_3X2_F; diff --git a/winapi/src/um/dcomp.rs b/winapi/src/um/dcomp.rs new file mode 100644 index 000000000..17048650a --- /dev/null +++ b/winapi/src/um/dcomp.rs @@ -0,0 +1,1159 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dcomp.h +use ctypes::{c_float, c_int, c_void}; +use shared::d3d9types::D3DMATRIX; +use shared::dcomptypes::{ + DCOMPOSITION_BACKFACE_VISIBILITY, DCOMPOSITION_BITMAP_INTERPOLATION_MODE, + DCOMPOSITION_BORDER_MODE, DCOMPOSITION_COMPOSITE_MODE, DCOMPOSITION_DEPTH_MODE, + DCOMPOSITION_FRAME_STATISTICS, DCOMPOSITION_OPACITY_MODE +}; +use shared::dxgi::IDXGIDevice; +use shared::dxgi1_2::DXGI_ALPHA_MODE; +use shared::dxgiformat::DXGI_FORMAT; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, DWORD, UINT}; +use shared::ntdef::{HANDLE, HRESULT}; +use shared::windef::{HWND, POINT, RECT}; +use um::d2d1::{D2D1_COLOR_F, D2D1_MATRIX_3X2_F}; +use um::d2d1_1::{D2D1_COMPOSITE_MODE, D2D1_MATRIX_5X4_F, D2D1_VECTOR_2F, D2D1_VECTOR_4F}; +use um::d2d1effects::{ + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE, D2D1_BLEND_MODE, D2D1_BORDER_MODE, + D2D1_COLORMATRIX_ALPHA_MODE, D2D1_TURBULENCE_NOISE +}; +use um::d2dbasetypes::{D2D_MATRIX_3X2_F, D2D_MATRIX_4X4_F, D2D_RECT_F}; +use um::d3dcommon::D3D_FEATURE_LEVEL; +use um::dcompanimation::IDCompositionAnimation; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +extern "system" { + pub fn DCompositionCreateDevice( + dxgiDevice: *const IDXGIDevice, + iid: REFIID, + dcompositionDevice: *mut *mut c_void, + ) -> HRESULT; + pub fn DCompositionCreateDevice2( + renderingDevice: *const IUnknown, + iid: REFIID, + dcompositionDevice: *mut *mut c_void, + ) -> HRESULT; + pub fn DCompositionCreateDevice3( + renderingDevice: *const IUnknown, + iid: REFIID, + dcompositionDevice: *mut *mut c_void, + ) -> HRESULT; + pub fn DCompositionGetFrameStatistics( + statistics: *const DCOMPOSITION_FRAME_STATISTICS, + minSafeFeaturelLevel: *const D3D_FEATURE_LEVEL, + maxHardwareFeaturelLevel: *const D3D_FEATURE_LEVEL, + ) -> HRESULT; + pub fn DCompositionCreateSurfaceHandle( + desiredAccess: DWORD, + securityAttributes: *const SECURITY_ATTRIBUTES, + surfaceHandle: *mut HANDLE, + ) -> HRESULT; + pub fn DCompositionAttachMouseWheelToHwnd( + visual: *const IDCompositionVisual, + hwnd: HWND, + enable: BOOL, + ) -> HRESULT; + pub fn DCompositionAttachMouseDragToHwnd( + visual: *const IDCompositionVisual, + hwnd: HWND, + enable: BOOL, + ) -> HRESULT; +} +RIDL!{#[uuid(0xc37ea93a, 0xe7aa, 0x450d, 0xb1, 0x6f, 0x97, 0x46, 0xcb, 0x04, 0x07, 0xf3)] +interface IDCompositionDevice(IDCompositionDeviceVtbl): IUnknown(IUnknownVtbl) { + fn Commit() -> HRESULT, + fn WaitForCommitCompletion() -> HRESULT, + fn GetFrameStatistics( + statistics: *mut DCOMPOSITION_FRAME_STATISTICS, + ) -> HRESULT, + fn CreateTargetForHwnd( + hwnd: HWND, + topmost: BOOL, + target: *mut *mut IDCompositionTarget, + ) -> HRESULT, + fn CreateVisual( + visual: *mut *mut IDCompositionVisual, + ) -> HRESULT, + fn CreateSurface( + width: UINT, + height: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + surface: *mut *mut IDCompositionSurface, + ) -> HRESULT, + fn CreateVirtualSurface( + initialWidth: UINT, + initialHeight: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + virtualSurface: *mut *mut IDCompositionVirtualSurface, + ) -> HRESULT, + fn CreateSurfaceFromHandle( + handle: HANDLE, + mutsurface: *mut *mut IUnknown, + ) -> HRESULT, + fn CreateSurfaceFromHwnd( + hwnd: HWND, + mutsurface: *mut *mut IUnknown, + ) -> HRESULT, + fn CreateTranslateTransform( + translateTransform: *mut *mut IDCompositionTranslateTransform, + ) -> HRESULT, + fn CreateScaleTransform( + scaleTransform: *mut *mut IDCompositionScaleTransform, + ) -> HRESULT, + fn CreateRotateTransform( + rotateTransform: *mut *mut IDCompositionRotateTransform, + ) -> HRESULT, + fn CreateSkewTransform( + skewTransform: *mut *mut IDCompositionSkewTransform, + ) -> HRESULT, + fn CreateMatrixTransform( + matrixTransform: *mut *mut IDCompositionMatrixTransform, + ) -> HRESULT, + fn CreateTransformGroup( + transforms: *const *const IDCompositionTransform, + elements: UINT, + transformGroup: *mut *mut IDCompositionTransform, + ) -> HRESULT, + fn CreateTranslateTransform3D( + translateTransform3D: *mut *mut IDCompositionTranslateTransform3D, + ) -> HRESULT, + fn CreateScaleTransform3D( + scaleTransform3D: *mut *mut IDCompositionScaleTransform3D, + ) -> HRESULT, + fn CreateRotateTransform3D( + rotateTransform3D: *mut *mut IDCompositionRotateTransform3D, + ) -> HRESULT, + fn CreateMatrixTransform3D( + matrixTransform3D: *mut *mut IDCompositionMatrixTransform3D, + ) -> HRESULT, + fn CreateTransform3DGroup( + transforms3D: *const *const IDCompositionTransform3D, + elements: UINT, + transform3DGroup: *mut *mut IDCompositionTransform3D, + ) -> HRESULT, + fn CreateEffectGroup( + effectGroup: *mut *mut IDCompositionEffectGroup, + ) -> HRESULT, + fn CreateRectangleClip( + clip: *mut *mut IDCompositionRectangleClip, + ) -> HRESULT, + fn CreateAnimation( + animation: *mut *mut IDCompositionAnimation, + ) -> HRESULT, + fn CheckDeviceState( + pfValid: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xeacdd04c, 0x117e, 0x4e17, 0x88, 0xf4, 0xd1, 0xb1, 0x2b, 0x0e, 0x3d, 0x89)] +interface IDCompositionTarget(IDCompositionTargetVtbl): IUnknown(IUnknownVtbl) { + fn SetRoot( + visual: *const IDCompositionVisual, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4d93059d, 0x097b, 0x4651, 0x9a, 0x60, 0xf0, 0xf2, 0x51, 0x16, 0xe2, 0xf3)] +interface IDCompositionVisual(IDCompositionVisualVtbl): IUnknown(IUnknownVtbl) { + fn SetOffsetX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetX_1( + offsetX: c_float, + ) -> HRESULT, + fn SetOffsetY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetY_1( + offsetY: c_float, + ) -> HRESULT, + fn SetTransform_2( + transform: *const IDCompositionTransform, + ) -> HRESULT, + fn SetTransform_1( + matrix: *const D2D_MATRIX_3X2_F, + ) -> HRESULT, + fn SetTransformParent( + visual: *const IDCompositionVisual, + ) -> HRESULT, + fn SetEffect( + effect: *const IDCompositionEffect, + ) -> HRESULT, + fn SetBitmapInterpolationMode( + interpolationMode: DCOMPOSITION_BITMAP_INTERPOLATION_MODE, + ) -> HRESULT, + fn SetBorderMode( + borderMode: DCOMPOSITION_BORDER_MODE, + ) -> HRESULT, + fn SetClip_2( + clip: *const IDCompositionClip, + ) -> HRESULT, + fn SetClip_1( + rect: *const D2D_RECT_F, + ) -> HRESULT, + fn SetContent( + content: *const IUnknown, + ) -> HRESULT, + fn AddVisual( + visual: *const IDCompositionVisual, + insertAbove: BOOL, + referenceVisual: *const IDCompositionVisual, + ) -> HRESULT, + fn RemoveVisual( + visual: *const IDCompositionVisual, + ) -> HRESULT, + fn RemoveAllVisuals() -> HRESULT, + fn SetCompositeMode( + compositeMode: DCOMPOSITION_COMPOSITE_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xec81b08f, 0xbfcb, 0x4e8d, 0xb1, 0x93, 0xa9, 0x15, 0x58, 0x79, 0x99, 0xe8)] +interface IDCompositionEffect(IDCompositionEffectVtbl): IUnknown(IUnknownVtbl) {}} +RIDL!{#[uuid(0x71185722, 0x246b, 0x41f2, 0xaa, 0xd1, 0x04, 0x43, 0xf7, 0xf4, 0xbf, 0xc2)] +interface IDCompositionTransform3D(IDCompositionTransform3DVtbl): + IDCompositionEffect(IDCompositionEffectVtbl) {}} +RIDL!{#[uuid(0xfd55faa7, 0x37e0, 0x4c20, 0x95, 0xd2, 0x9b, 0xe4, 0x5b, 0xc3, 0x3f, 0x55)] +interface IDCompositionTransform(IDCompositionTransformVtbl): + IDCompositionTransform3D(IDCompositionTransform3DVtbl) {}} +RIDL!{#[uuid(0x06791122, 0xc6f0, 0x417d, 0x83, 0x23, 0x26, 0x9e, 0x98, 0x7f, 0x59, 0x54)] +interface IDCompositionTranslateTransform(IDCompositionTranslateTransformVtbl): + IDCompositionTransform(IDCompositionTransformVtbl) { + fn SetOffsetX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetX_1( + offsetX: c_float, + ) -> HRESULT, + fn SetOffsetY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetY_1( + offsetY: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x71fde914, 0x40ef, 0x45ef, 0xbd, 0x51, 0x68, 0xb0, 0x37, 0xc3, 0x39, 0xf9)] +interface IDCompositionScaleTransform(IDCompositionScaleTransformVtbl): + IDCompositionTransform(IDCompositionTransformVtbl) { + fn SetScaleX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetScaleX_1( + scaleX: c_float, + ) -> HRESULT, + fn SetScaleY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetScaleY_1( + scaleY: c_float, + ) -> HRESULT, + fn SetCenterX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterX_1( + centerX: c_float, + ) -> HRESULT, + fn SetCenterY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterY_1( + centerY: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x641ed83c, 0xae96, 0x46c5, 0x90, 0xdc, 0x32, 0x77, 0x4c, 0xc5, 0xc6, 0xd5)] +interface IDCompositionRotateTransform(IDCompositionRotateTransformVtbl): + IDCompositionTransform(IDCompositionTransformVtbl) { + fn SetAngle_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAngle_1( + angle: c_float, + ) -> HRESULT, + fn SetCenterX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterX_1( + centerX: c_float, + ) -> HRESULT, + fn SetCenterY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterY_1( + centerY: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe57aa735, 0xdcdb, 0x4c72, 0x9c, 0x61, 0x05, 0x91, 0xf5, 0x88, 0x89, 0xee)] +interface IDCompositionSkewTransform(IDCompositionSkewTransformVtbl): + IDCompositionTransform(IDCompositionTransformVtbl) { + fn SetAngleX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAngleX_1( + angleX: c_float, + ) -> HRESULT, + fn SetAngleY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAngleY_1( + angleY: c_float, + ) -> HRESULT, + fn SetCenterX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterX_1( + centerX: c_float, + ) -> HRESULT, + fn SetCenterY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterY_1( + centerY: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x16cdff07, 0xc503, 0x419c, 0x83, 0xf2, 0x09, 0x65, 0xc7, 0xaf, 0x1f, 0xa6)] +interface IDCompositionMatrixTransform(IDCompositionMatrixTransformVtbl): + IDCompositionTransform(IDCompositionTransformVtbl) { + fn SetMatrix( + matrix: *const D2D_MATRIX_3X2_F, + ) -> HRESULT, + fn SetMatrixElement_2( + row: c_int, + column: c_int, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetMatrixElement_1( + row: c_int, + column: c_int, + value: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa7929a74, 0xe6b2, 0x4bd6, 0x8b, 0x95, 0x40, 0x40, 0x11, 0x9c, 0xa3, 0x4d)] +interface IDCompositionEffectGroup(IDCompositionEffectGroupVtbl): + IDCompositionEffect(IDCompositionEffectVtbl) { + fn SetOpacity_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOpacity_1( + opacity: c_float, + ) -> HRESULT, + fn SetTransform3D( + transform3D: *const IDCompositionTransform3D, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x91636d4b, 0x9ba1, 0x4532, 0xaa, 0xf7, 0xe3, 0x34, 0x49, 0x94, 0xd7, 0x88)] +interface IDCompositionTranslateTransform3D(IDCompositionTranslateTransform3DVtbl): + IDCompositionTransform3D(IDCompositionTransform3DVtbl) { + fn SetOffsetX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetX_1( + offsetX: c_float, + ) -> HRESULT, + fn SetOffsetY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetY_1( + offsetY: c_float, + ) -> HRESULT, + fn SetOffsetZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetZ_1( + offsetZ: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2a9e9ead, 0x364b, 0x4b15, 0xa7, 0xc4, 0xa1, 0x99, 0x7f, 0x78, 0xb3, 0x89)] +interface IDCompositionScaleTransform3D(IDCompositionScaleTransform3DVtbl): + IDCompositionTransform3D(IDCompositionTransform3DVtbl) { + fn SetScaleX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetScaleX_1( + scaleX: c_float, + ) -> HRESULT, + fn SetScaleY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetScaleY_1( + scaleY: c_float, + ) -> HRESULT, + fn SetScaleZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetScaleZ_1( + scaleZ: c_float, + ) -> HRESULT, + fn SetCenterX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterX_1( + centerX: c_float, + ) -> HRESULT, + fn SetCenterY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterY_1( + centerY: c_float, + ) -> HRESULT, + fn SetCenterZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterZ_1( + centerZ: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd8f5b23f, 0xd429, 0x4a91, 0xb5, 0x5a, 0xd2, 0xf4, 0x5f, 0xd7, 0x5b, 0x18)] +interface IDCompositionRotateTransform3D(IDCompositionRotateTransform3DVtbl): + IDCompositionTransform3D(IDCompositionTransform3DVtbl) { + fn SetAngle_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAngle_1( + angle: c_float, + ) -> HRESULT, + fn SetAxisX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAxisX_1( + axisX: c_float, + ) -> HRESULT, + fn SetAxisY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAxisY_1( + axisY: c_float, + ) -> HRESULT, + fn SetAxisZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAxisZ_1( + axisZ: c_float, + ) -> HRESULT, + fn SetCenterX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterX_1( + centerX: c_float, + ) -> HRESULT, + fn SetCenterY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterY_1( + centerY: c_float, + ) -> HRESULT, + fn SetCenterZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCenterZ_1( + centerZ: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4b3363f0, 0x643b, 0x41b7, 0xb6, 0xe0, 0xcc, 0xf2, 0x2d, 0x34, 0x46, 0x7c)] +interface IDCompositionMatrixTransform3D(IDCompositionMatrixTransform3DVtbl): + IDCompositionTransform3D(IDCompositionTransform3DVtbl) { + fn SetMatrix( + matrix: *const D3DMATRIX, + ) -> HRESULT, + fn SetMatrixElement_2( + row: c_int, + column: c_int, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetMatrixElement_1( + row: c_int, + column: c_int, + value: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x64ac3703, 0x9d3f, 0x45ec, 0xa1, 0x09, 0x7c, 0xac, 0x0e, 0x7a, 0x13, 0xa7)] +interface IDCompositionClip(IDCompositionClipVtbl): IUnknown(IUnknownVtbl) {}} +RIDL!{#[uuid(0x9842ad7d, 0xd9cf, 0x4908, 0xae, 0xd7, 0x48, 0xb5, 0x1d, 0xa5, 0xe7, 0xc2)] +interface IDCompositionRectangleClip(IDCompositionRectangleClipVtbl): + IDCompositionClip(IDCompositionClipVtbl) { + fn SetLeft_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetLeft_1( + left: c_float, + ) -> HRESULT, + fn SetTop_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTop_1( + top: c_float, + ) -> HRESULT, + fn SetRight_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetRight_1( + right: c_float, + ) -> HRESULT, + fn SetBottom_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBottom_1( + bottom: c_float, + ) -> HRESULT, + fn SetTopLeftRadiusX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTopLeftRadiusX_1( + radius: c_float, + ) -> HRESULT, + fn SetTopLeftRadiusY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTopLeftRadiusY_1( + radius: c_float, + ) -> HRESULT, + fn SetTopRightRadiusX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTopRightRadiusX_1( + radius: c_float, + ) -> HRESULT, + fn SetTopRightRadiusY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTopRightRadiusY_1( + radius: c_float, + ) -> HRESULT, + fn SetBottomLeftRadiusX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBottomLeftRadiusX_1( + radius: c_float, + ) -> HRESULT, + fn SetBottomLeftRadiusY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBottomLeftRadiusY_1( + radius: c_float, + ) -> HRESULT, + fn SetBottomRightRadiusX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBottomRightRadiusX_1( + radius: c_float, + ) -> HRESULT, + fn SetBottomRightRadiusY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBottomRightRadiusY_1( + radius: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbb8a4953, 0x2c99, 0x4f5a, 0x96, 0xf5, 0x48, 0x19, 0x02, 0x7f, 0xa3, 0xac)] +interface IDCompositionSurface(IDCompositionSurfaceVtbl): IUnknown(IUnknownVtbl) { + fn BeginDraw( + updateRect: *const RECT, + iid: REFIID, + updateObject: *mut *mut c_void, + updateOffset: *mut POINT, + ) -> HRESULT, + fn EndDraw() -> HRESULT, + fn SuspendDraw() -> HRESULT, + fn ResumeDraw() -> HRESULT, + fn Scroll( + scrollRect: *const RECT, + clipRect: *const RECT, + offsetX: c_int, + offsetY: c_int, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xae471c51, 0x5f53, 0x4a24, 0x8d, 0x3e, 0xd0, 0xc3, 0x9c, 0x30, 0xb3, 0xf0)] +interface IDCompositionVirtualSurface(IDCompositionVirtualSurfaceVtbl): + IDCompositionSurface(IDCompositionSurfaceVtbl) { + fn Resize( + width: UINT, + height: UINT, + ) -> HRESULT, + fn Trim( + rectangles: *const RECT, + count: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x75f6468d, 0x1b8e, 0x447c, 0x9b, 0xc6, 0x75, 0xfe, 0xa8, 0x0b, 0x5b, 0x25)] +interface IDCompositionDevice2(IDCompositionDevice2Vtbl): IUnknown(IUnknownVtbl) { + fn Commit() -> HRESULT, + fn WaitForCommitCompletion() -> HRESULT, + fn GetFrameStatistics( + statistics: *mut DCOMPOSITION_FRAME_STATISTICS, + ) -> HRESULT, + fn CreateVisual( + visual: *mut *mut IDCompositionVisual2, + ) -> HRESULT, + fn CreateSurfaceFactory( + renderingDevice: *const IUnknown, + surfaceFactory: *mut *mut IDCompositionSurfaceFactory, + ) -> HRESULT, + fn CreateSurface( + width: UINT, + height: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + surface: *mut *mut IDCompositionSurface, + ) -> HRESULT, + fn CreateVirtualSurface( + initialWidth: UINT, + initialHeight: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + virtualSurface: *mut *mut IDCompositionVirtualSurface, + ) -> HRESULT, + fn CreateTranslateTransform( + translateTransform: *mut *mut IDCompositionTranslateTransform, + ) -> HRESULT, + fn CreateScaleTransform( + scaleTransform: *mut *mut IDCompositionScaleTransform, + ) -> HRESULT, + fn CreateRotateTransform( + rotateTransform: *mut *mut IDCompositionRotateTransform, + ) -> HRESULT, + fn CreateSkewTransform( + skewTransform: *mut *mut IDCompositionSkewTransform, + ) -> HRESULT, + fn CreateMatrixTransform( + matrixTransform: *mut *mut IDCompositionMatrixTransform, + ) -> HRESULT, + fn CreateTransformGroup( + transforms: *const *const IDCompositionTransform, + elements: UINT, + transformGroup: *mut *mut IDCompositionTransform, + ) -> HRESULT, + fn CreateTranslateTransform3D( + translateTransform3D: *mut *mut IDCompositionTranslateTransform3D, + ) -> HRESULT, + fn CreateScaleTransform3D( + scaleTransform3D: *mut *mut IDCompositionScaleTransform3D, + ) -> HRESULT, + fn CreateRotateTransform3D( + rotateTransform3D: *mut *mut IDCompositionRotateTransform3D, + ) -> HRESULT, + fn CreateMatrixTransform3D( + matrixTransform3D: *mut *mut IDCompositionMatrixTransform3D, + ) -> HRESULT, + fn CreateTransform3DGroup( + transforms3D: *const *const IDCompositionTransform3D, + elements: UINT, + transform3DGroup: *mut *mut IDCompositionTransform3D, + ) -> HRESULT, + fn CreateEffectGroup( + effectGroup: *mut *mut IDCompositionEffectGroup, + ) -> HRESULT, + fn CreateRectangleClip( + clip: *mut *mut IDCompositionRectangleClip, + ) -> HRESULT, + fn CreateAnimation( + animation: *mut *mut IDCompositionAnimation, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5f4633fe, 0x1e08, 0x4cb8, 0x8c, 0x75, 0xce, 0x24, 0x33, 0x3f, 0x56, 0x02)] +interface IDCompositionDesktopDevice(IDCompositionDesktopDeviceVtbl): + IDCompositionDevice2(IDCompositionDevice2Vtbl) { + fn CreateTargetForHwnd( + hwnd: HWND, + topmost: BOOL, + target: *mut *mut IDCompositionTarget, + ) -> HRESULT, + fn CreateSurfaceFromHandle( + handle: HANDLE, + surface: *mut *mut IUnknown, + ) -> HRESULT, + fn CreateSurfaceFromHwnd( + hwnd: HWND, + surface: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa1a3c64a, 0x224f, 0x4a81, 0x97, 0x73, 0x4f, 0x03, 0xa8, 0x9d, 0x3c, 0x6c)] +interface IDCompositionDeviceDebug(IDCompositionDeviceDebugVtbl): IUnknown(IUnknownVtbl) { + fn EnableDebugCounters() -> HRESULT, + fn DisableDebugCounters() -> HRESULT, +}} +RIDL!{#[uuid(0xe334bc12, 0x3937, 0x4e02, 0x85, 0xeb, 0xfc, 0xf4, 0xeb, 0x30, 0xd2, 0xc8)] +interface IDCompositionSurfaceFactory(IDCompositionSurfaceFactoryVtbl): IUnknown(IUnknownVtbl) { + fn CreateSurface( + width: UINT, + height: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + surface: *mut *mut IDCompositionSurface, + ) -> HRESULT, + fn CreateVirtualSurface( + initialWidth: UINT, + initialHeight: UINT, + pixelFormat: DXGI_FORMAT, + alphaMode: DXGI_ALPHA_MODE, + virtualSurface: *mut *mut IDCompositionVirtualSurface, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe8de1639, 0x4331, 0x4b26, 0xbc, 0x5f, 0x6a, 0x32, 0x1d, 0x34, 0x7a, 0x85)] +interface IDCompositionVisual2(IDCompositionVisual2Vtbl): + IDCompositionVisual(IDCompositionVisualVtbl) { + fn SetOpacityMode( + mode: DCOMPOSITION_OPACITY_MODE, + ) -> HRESULT, + fn SetBackFaceVisibility( + visibility: DCOMPOSITION_BACKFACE_VISIBILITY, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfed2b808, 0x5eb4, 0x43a0, 0xae, 0xa3, 0x35, 0xf6, 0x52, 0x80, 0xf9, 0x1b)] +interface IDCompositionVisualDebug(IDCompositionVisualDebugVtbl): + IDCompositionVisual2(IDCompositionVisual2Vtbl) { + fn EnableHeatMap( + color: *const D2D1_COLOR_F, + ) -> HRESULT, + fn DisableHeatMap() -> HRESULT, + fn EnableRedrawRegions() -> HRESULT, + fn DisableRedrawRegions() -> HRESULT, +}} +RIDL!{#[uuid(0x2775f462, 0xb6c1, 0x4015, 0xb0, 0xbe, 0xb3, 0xe7, 0xd6, 0xa4, 0x97, 0x6d)] +interface IDCompositionVisual3(IDCompositionVisual3Vtbl): + IDCompositionVisualDebug(IDCompositionVisualDebugVtbl) { + fn SetDepthMode( + mode: DCOMPOSITION_DEPTH_MODE, + ) -> HRESULT, + fn SetOffsetZ_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOffsetZ_1( + offsetZ: c_float, + ) -> HRESULT, + fn SetOpacity_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetOpacity_1( + opacity: c_float, + ) -> HRESULT, + fn SetTransform_2( + transform: *const IDCompositionTransform3D, + ) -> HRESULT, + fn SetTransform_1( + matrix: *const D2D_MATRIX_4X4_F, + ) -> HRESULT, + fn SetVisible( + visible: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0987cb06, 0xf916, 0x48bf, 0x8d, 0x35, 0xce, 0x76, 0x41, 0x78, 0x1b, 0xd9)] +interface IDCompositionDevice3(IDCompositionDevice3Vtbl): + IDCompositionDevice2(IDCompositionDevice2Vtbl) { + fn CreateGaussianBlurEffect( + gaussianBlurEffect: *mut *mut IDCompositionGaussianBlurEffect, + ) -> HRESULT, + fn CreateBrightnessEffect( + brightnessEffect: *mut *mut IDCompositionBrightnessEffect, + ) -> HRESULT, + fn CreateColorMatrixEffect( + colorMatrixEffect: *mut *mut IDCompositionColorMatrixEffect, + ) -> HRESULT, + fn CreateShadowEffect( + shadowEffect: *mut *mut IDCompositionShadowEffect, + ) -> HRESULT, + fn CreateHueRotationEffect( + hueRotationEffect: *mut *mut IDCompositionHueRotationEffect, + ) -> HRESULT, + fn CreateSaturationEffect( + saturationEffect: *mut *mut IDCompositionSaturationEffect, + ) -> HRESULT, + fn CreateTurbulenceEffect( + turbulenceEffect: *mut *mut IDCompositionTurbulenceEffect, + ) -> HRESULT, + fn CreateLinearTransferEffect( + linearTransferEffect: *mut *mut IDCompositionLinearTransferEffect, + ) -> HRESULT, + fn CreateTableTransferEffect( + tableTransferEffect: *mut *mut IDCompositionTableTransferEffect, + ) -> HRESULT, + fn CreateCompositeEffect( + compositeEffect: *mut *mut IDCompositionCompositeEffect, + ) -> HRESULT, + fn CreateBlendEffect( + blendEffect: *mut *mut IDCompositionBlendEffect, + ) -> HRESULT, + fn CreateArithmeticCompositeEffect( + arithmeticCompositeEffect: *mut *mut IDCompositionArithmeticCompositeEffect, + ) -> HRESULT, + fn CreateAffineTransform2DEffect( + affineTransform2dEffect: *mut *mut IDCompositionAffineTransform2DEffect, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x30c421d5, 0x8cb2, 0x4e9f, 0xb1, 0x33, 0x37, 0xbe, 0x27, 0x0d, 0x4a, 0xc2)] +interface IDCompositionFilterEffect(IDCompositionFilterEffectVtbl): + IDCompositionEffect(IDCompositionEffectVtbl) { + fn SetInput( + index: UINT, + input: *const IUnknown, + flags: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x45d4d0b7, 0x1bd4, 0x454e, 0x88, 0x94, 0x2b, 0xfa, 0x68, 0x44, 0x30, 0x33)] +interface IDCompositionGaussianBlurEffect(IDCompositionGaussianBlurEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetStandardDeviation_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetStandardDeviation_1( + amount: c_float, + ) -> HRESULT, + fn SetBorderMode( + mode: D2D1_BORDER_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6027496e, 0xcb3a, 0x49ab, 0x93, 0x4f, 0xd7, 0x98, 0xda, 0x4f, 0x7d, 0xa6)] +interface IDCompositionBrightnessEffect(IDCompositionBrightnessEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetWhitePoint( + whitePoint: *const D2D1_VECTOR_2F, + ) -> HRESULT, + fn SetBlackPoint( + blackPoint: *const D2D1_VECTOR_2F, + ) -> HRESULT, + fn SetWhitePointX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetWhitePointX_1( + whitePointX: c_float, + ) -> HRESULT, + fn SetWhitePointY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetWhitePointY_1( + whitePointY: c_float, + ) -> HRESULT, + fn SetBlackPointX_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlackPointX_1( + blackPointX: c_float, + ) -> HRESULT, + fn SetBlackPointY_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlackPointY_1( + blackPointY: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc1170a22, 0x3ce2, 0x4966, 0x90, 0xd4, 0x55, 0x40, 0x8b, 0xfc, 0x84, 0xc4)] +interface IDCompositionColorMatrixEffect(IDCompositionColorMatrixEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetMatrix( + matrix: *const D2D1_MATRIX_5X4_F, + ) -> HRESULT, + fn SetMatrixElement_2( + row: c_int, + column: c_int, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetMatrixElement_1( + row: c_int, + column: c_int, + value: c_float, + ) -> HRESULT, + fn SetAlphaMode( + mode: D2D1_COLORMATRIX_ALPHA_MODE, + ) -> HRESULT, + fn SetClampOutput( + clamp: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4ad18ac0, 0xcfd2, 0x4c2f, 0xbb, 0x62, 0x96, 0xe5, 0x4f, 0xdb, 0x68, 0x79)] +interface IDCompositionShadowEffect(IDCompositionShadowEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetStandardDeviation_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetStandardDeviation_1( + amount: c_float, + ) -> HRESULT, + fn SetColor( + color: *const D2D1_VECTOR_4F, + ) -> HRESULT, + fn SetRed_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetRed_1( + amount: c_float, + ) -> HRESULT, + fn SetGreen_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetGreen_1( + amount: c_float, + ) -> HRESULT, + fn SetBlue_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlue_1( + amount: c_float, + ) -> HRESULT, + fn SetAlpha_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAlpha_1( + amount: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6db9f920, 0x0770, 0x4781, 0xb0, 0xc6, 0x38, 0x19, 0x12, 0xf9, 0xd1, 0x67)] +interface IDCompositionHueRotationEffect(IDCompositionHueRotationEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + // Changes the angle of rotation + fn SetAngle_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAngle_1( + amountDegrees: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa08debda, 0x3258, 0x4fa4, 0x9f, 0x16, 0x91, 0x74, 0xd3, 0xfe, 0x93, 0xb1)] +interface IDCompositionSaturationEffect(IDCompositionSaturationEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + // Changes the amount of saturation to be applied. + fn SetSaturation_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetSaturation_1( + ratio: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa6a55bda, 0xc09c, 0x49f3, 0x91, 0x93, 0xa4, 0x19, 0x22, 0xc8, 0x97, 0x15)] +interface IDCompositionTurbulenceEffect(IDCompositionTurbulenceEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetOffset( + offset: *const D2D1_VECTOR_2F, + ) -> HRESULT, + fn SetBaseFrequency( + frequency: *const D2D1_VECTOR_2F, + ) -> HRESULT, + fn SetSize( + size: *const D2D1_VECTOR_2F, + ) -> HRESULT, + fn SetNumOctaves( + numOctaves: UINT, + ) -> HRESULT, + fn SetSeed( + seed: UINT, + ) -> HRESULT, + fn SetNoise( + noise: D2D1_TURBULENCE_NOISE, + ) -> HRESULT, + fn SetStitchable( + stitchable: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4305ee5b, 0xc4a0, 0x4c88, 0x93, 0x85, 0x67, 0x12, 0x4e, 0x01, 0x76, 0x83)] +interface IDCompositionLinearTransferEffect(IDCompositionLinearTransferEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetRedYIntercept_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetRedYIntercept_1( + redYIntercept: c_float, + ) -> HRESULT, + fn SetRedSlope_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetRedSlope_1( + redSlope: c_float, + ) -> HRESULT, + fn SetRedDisable( + redDisable: BOOL, + ) -> HRESULT, + fn SetGreenYIntercept_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetGreenYIntercept_1( + greenYIntercept: c_float, + ) -> HRESULT, + fn SetGreenSlope_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetGreenSlope_1( + greenSlope: c_float, + ) -> HRESULT, + fn SetGreenDisable( + greenDisable: BOOL, + ) -> HRESULT, + fn SetBlueYIntercept_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlueYIntercept_1( + blueYIntercept: c_float, + ) -> HRESULT, + fn SetBlueSlope_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlueSlope_1( + blueSlope: c_float, + ) -> HRESULT, + fn SetBlueDisable( + blueDisable: BOOL, + ) -> HRESULT, + fn SetAlphaYIntercept_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAlphaYIntercept_1( + alphaYIntercept: c_float, + ) -> HRESULT, + fn SetAlphaSlope_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAlphaSlope_1( + alphaSlope: c_float, + ) -> HRESULT, + fn SetAlphaDisable( + alphaDisable: BOOL, + ) -> HRESULT, + fn SetClampOutput( + clampOutput: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9b7e82e2, 0x69c5, 0x4eb4, 0xa5, 0xf5, 0xa7, 0x03, 0x3f, 0x51, 0x32, 0xcd)] +interface IDCompositionTableTransferEffect(IDCompositionTableTransferEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetRedTable( + tableValues: *const c_float, + count: UINT, + ) -> HRESULT, + fn SetGreenTable( + tableValues: *const c_float, + count: UINT, + ) -> HRESULT, + fn SetBlueTable( + tableValues: *const c_float, + count: UINT, + ) -> HRESULT, + fn SetAlphaTable( + tableValues: *const c_float, + count: UINT, + ) -> HRESULT, + fn SetRedDisable( + redDisable: BOOL, + ) -> HRESULT, + fn SetGreenDisable( + greenDisable: BOOL, + ) -> HRESULT, + fn SetBlueDisable( + blueDisable: BOOL, + ) -> HRESULT, + fn SetAlphaDisable( + alphaDisable: BOOL, + ) -> HRESULT, + fn SetClampOutput( + clampOutput: BOOL, + ) -> HRESULT, + fn SetRedTableValue_2( + index: UINT, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetRedTableValue_1( + index: UINT, + value: c_float, + ) -> HRESULT, + fn SetGreenTableValue_2( + index: UINT, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetGreenTableValue_1( + index: UINT, + value: c_float, + ) -> HRESULT, + fn SetBlueTableValue_2( + index: UINT, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetBlueTableValue_1( + index: UINT, + value: c_float, + ) -> HRESULT, + fn SetAlphaTableValue_2( + index: UINT, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetAlphaTableValue_1( + index: UINT, + value: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x576616c0, 0xa231, 0x494d, 0xa3, 0x8d, 0x00, 0xfd, 0x5e, 0xc4, 0xdb, 0x46)] +interface IDCompositionCompositeEffect(IDCompositionCompositeEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetMode( + mode: D2D1_COMPOSITE_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x33ecdc0a, 0x578a, 0x4a11, 0x9c, 0x14, 0x0c, 0xb9, 0x05, 0x17, 0xf9, 0xc5)] +interface IDCompositionBlendEffect(IDCompositionBlendEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetMode( + mode: D2D1_BLEND_MODE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b67dfa8, 0xe3dd, 0x4e61, 0xb6, 0x40, 0x46, 0xc2, 0xf3, 0xd7, 0x39, 0xdc)] +interface IDCompositionArithmeticCompositeEffect(IDCompositionArithmeticCompositeEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetCoefficients( + coefficients: *const D2D1_VECTOR_4F, + ) -> HRESULT, + fn SetClampOutput( + clampoutput: BOOL, + ) -> HRESULT, + fn SetCoefficient1_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCoefficient1_1( + Coeffcient1: c_float, + ) -> HRESULT, + fn SetCoefficient2_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCoefficient2_1( + Coefficient2: c_float, + ) -> HRESULT, + fn SetCoefficient3_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCoefficient3_1( + Coefficient3: c_float, + ) -> HRESULT, + fn SetCoefficient4_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetCoefficient4_1( + Coefficient4: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0b74b9e8, 0xcdd6, 0x492f, 0xbb, 0xbc, 0x5e, 0xd3, 0x21, 0x57, 0x02, 0x6d)] +interface IDCompositionAffineTransform2DEffect(IDCompositionAffineTransform2DEffectVtbl): + IDCompositionFilterEffect(IDCompositionFilterEffectVtbl) { + fn SetInterpolationMode( + interpolationMode: D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE, + ) -> HRESULT, + fn SetBorderMode( + borderMode: D2D1_BORDER_MODE, + ) -> HRESULT, + fn SetTransformMatrix( + transformMatrix: *const D2D1_MATRIX_3X2_F, + ) -> HRESULT, + fn SetTransformMatrixElement_2( + row: c_int, + column: c_int, + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetTransformMatrixElement_1( + row: c_int, + column: c_int, + value: c_float, + ) -> HRESULT, + fn SetSharpness_2( + animation: *const IDCompositionAnimation, + ) -> HRESULT, + fn SetSharpness_1( + sharpness: c_float, + ) -> HRESULT, +}} diff --git a/winapi/src/um/dcompanimation.rs b/winapi/src/um/dcompanimation.rs new file mode 100644 index 000000000..ca54c405e --- /dev/null +++ b/winapi/src/um/dcompanimation.rs @@ -0,0 +1,38 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of dcompanimation.h +use ctypes::{c_double, c_float}; +use shared::ntdef::{HRESULT, LARGE_INTEGER}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +RIDL!{#[uuid(0xcbfd91d9, 0x51b2, 0x45e4, 0xb3, 0xde, 0xd1, 0x9c, 0xcf, 0xb8, 0x63, 0xc5)] +interface IDCompositionAnimation(IDCompositionAnimationVtbl): IUnknown(IUnknownVtbl) { + fn Reset() -> HRESULT, + fn SetAbsoluteBeginTime( + beginTime: LARGE_INTEGER, + ) -> HRESULT, + fn AddCubic( + beginOffset: c_double, + constantCoefficient: c_float, + linearCoefficient: c_float, + quadraticCoefficient: c_float, + cubicCoefficient: c_float, + )-> HRESULT, + fn AddSinusoidal( + beginOffset: c_double, + bias: c_float, + amplitude: c_float, + frequency: c_float, + phase: c_float, + )-> HRESULT, + fn AddRepeat( + beginOffset: c_double, + durationToRepeat: c_double, + )-> HRESULT, + fn End( + endOffset: c_double, + endValue: c_float, + ) -> HRESULT, +}} diff --git a/winapi/src/um/dde.rs b/winapi/src/um/dde.rs new file mode 100644 index 000000000..b3ce4a9da --- /dev/null +++ b/winapi/src/um/dde.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{PUINT_PTR, UINT_PTR}; +use shared::minwindef::{BOOL, LPARAM, UINT}; +extern "system" { + pub fn PackDDElParam( + msg: UINT, + uiLo: UINT_PTR, + uiHi: UINT_PTR, + ) -> LPARAM; + pub fn UnpackDDElParam( + msg: UINT, + lParam: LPARAM, + puiLo: PUINT_PTR, + puiHi: PUINT_PTR, + ) -> BOOL; +} diff --git a/winapi/src/um/ddraw.rs b/winapi/src/um/ddraw.rs new file mode 100644 index 000000000..fd0d9e89b --- /dev/null +++ b/winapi/src/um/ddraw.rs @@ -0,0 +1,37 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{CLSID_DirectDraw, + 0xd7b70ee0, 0x4340, 0x11cf, 0xb0, 0x63, 0x00, 0x20, 0xaf, 0xc2, 0xcd, 0x35} +DEFINE_GUID!{CLSID_DirectDraw7, + 0x3c305196, 0x50db, 0x11d3, 0x9c, 0xfe, 0x00, 0xc0, 0x4f, 0xd9, 0x30, 0xc5} +DEFINE_GUID!{CLSID_DirectDrawClipper, + 0x593817a0, 0x7db3, 0x11cf, 0xa2, 0xde, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirectDraw, + 0x6c14db80, 0xa733, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectDraw2, + 0xb3a6f3e0, 0x2b43, 0x11cf, 0xa2, 0xde, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirectDraw4, + 0x9c59509a, 0x39bd, 0x11d1, 0x8c, 0x4a, 0x00, 0xc0, 0x4f, 0xd9, 0x30, 0xc5} +DEFINE_GUID!{IID_IDirectDraw7, + 0x15e65ec0, 0x3b9c, 0x11d2, 0xb9, 0x2f, 0x00, 0x60, 0x97, 0x97, 0xea, 0x5b} +DEFINE_GUID!{IID_IDirectDrawSurface, + 0x6c14db81, 0xa733, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectDrawSurface2, + 0x57805885, 0x6eec, 0x11cf, 0x94, 0x41, 0xa8, 0x23, 0x03, 0xc1, 0x0e, 0x27} +DEFINE_GUID!{IID_IDirectDrawSurface3, + 0xda044e00, 0x69b2, 0x11d0, 0xa1, 0xd5, 0x00, 0xaa, 0x00, 0xb8, 0xdf, 0xbb} +DEFINE_GUID!{IID_IDirectDrawSurface4, + 0x0b2b8630, 0xad35, 0x11d0, 0x8e, 0xa6, 0x00, 0x60, 0x97, 0x97, 0xea, 0x5b} +DEFINE_GUID!{IID_IDirectDrawSurface7, + 0x06675a80, 0x3b9b, 0x11d2, 0xb9, 0x2f, 0x00, 0x60, 0x97, 0x97, 0xea, 0x5b} +DEFINE_GUID!{IID_IDirectDrawPalette, + 0x6c14db84, 0xa733, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectDrawClipper, + 0x6c14db85, 0xa733, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectDrawColorControl, + 0x4b9f0ee0, 0x0d7e, 0x11d0, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{IID_IDirectDrawGammaControl, + 0x69c11c3e, 0xb46b, 0x11d1, 0xad, 0x7a, 0x00, 0xc0, 0x4f, 0xc2, 0x9b, 0x4e} diff --git a/winapi/src/um/ddrawi.rs b/winapi/src/um/ddrawi.rs new file mode 100644 index 000000000..18e651863 --- /dev/null +++ b/winapi/src/um/ddrawi.rs @@ -0,0 +1,13 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{GUID_OptSurfaceKmodeInfo, + 0xe05c8472, 0x51d4, 0x11d1, 0x8c, 0xce, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{GUID_OptSurfaceUmodeInfo, + 0x9d792804, 0x5fa8, 0x11d1, 0x8c, 0xd0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{GUID_UserModeDriverInfo, + 0xf0b0e8e2, 0x5f97, 0x11d1, 0x8c, 0xd0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{GUID_UserModeDriverPassword, + 0x97f861b6, 0x60a1, 0x11d1, 0x8c, 0xd0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} diff --git a/winapi/src/um/ddrawint.rs b/winapi/src/um/ddrawint.rs new file mode 100644 index 000000000..2f9b7431b --- /dev/null +++ b/winapi/src/um/ddrawint.rs @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{GUID_MiscellaneousCallbacks, + 0xefd60cc0, 0x49e7, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{GUID_Miscellaneous2Callbacks, + 0x406b2f00, 0x3e5a, 0x11d1, 0xb6, 0x40, 0x00, 0xaa, 0x00, 0xa1, 0xf9, 0x6a} +DEFINE_GUID!{GUID_VideoPortCallbacks, + 0xefd60cc1, 0x49e7, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{GUID_ColorControlCallbacks, + 0xefd60cc2, 0x49e7, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{GUID_MotionCompCallbacks, + 0xb1122b40, 0x5da5, 0x11d1, 0x8f, 0xcf, 0x00, 0xc0, 0x4f, 0xc2, 0x9b, 0x4e} +DEFINE_GUID!{GUID_VideoPortCaps, + 0xefd60cc3, 0x49e7, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{GUID_D3DExtendedCaps, + 0x7de41f80, 0x9d93, 0x11d0, 0x89, 0xab, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{GUID_D3DCallbacks2, + 0x0ba584e1, 0x70b6, 0x11d0, 0x88, 0x9d, 0x00, 0xaa, 0x00, 0xbb, 0xb7, 0x6a} +DEFINE_GUID!{GUID_D3DCallbacks3, + 0xddf41230, 0xec0a, 0x11d0, 0xa9, 0xb6, 0x00, 0xaa, 0x00, 0xc0, 0x99, 0x3e} +DEFINE_GUID!{GUID_NonLocalVidMemCaps, + 0x86c4fa80, 0x8d84, 0x11d0, 0x94, 0xe8, 0x00, 0xc0, 0x4f, 0xc3, 0x41, 0x37} +DEFINE_GUID!{GUID_KernelCallbacks, + 0x80863800, 0x6b06, 0x11d0, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{GUID_KernelCaps, + 0xffaa7540, 0x7aa8, 0x11d0, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{GUID_ZPixelFormats, + 0x93869880, 0x36cf, 0x11d1, 0x9b, 0x1b, 0x00, 0xaa, 0x00, 0xbb, 0xb8, 0xae} +DEFINE_GUID!{GUID_DDMoreCaps, + 0x880baf30, 0xb030, 0x11d0, 0x8e, 0xa7, 0x00, 0x60, 0x97, 0x97, 0xea, 0x5b} +DEFINE_GUID!{GUID_D3DParseUnknownCommandCallback, + 0x2e04ffa0, 0x98e4, 0x11d1, 0x8c, 0xe1, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0xa8} +DEFINE_GUID!{GUID_NTCallbacks, + 0x6fe9ecde, 0xdf89, 0x11d1, 0x9d, 0xb0, 0x00, 0x60, 0x08, 0x27, 0x71, 0xba} +DEFINE_GUID!{GUID_DDMoreSurfaceCaps, + 0x3b8a0466, 0xf269, 0x11d1, 0x88, 0x0b, 0x00, 0xc0, 0x4f, 0xd9, 0x30, 0xc5} +DEFINE_GUID!{GUID_DDStereoMode, + 0xf828169c, 0xa8e8, 0x11d2, 0xa1, 0xf2, 0x00, 0xa0, 0xc9, 0x83, 0xea, 0xf6} diff --git a/winapi/src/um/debugapi.rs b/winapi/src/um/debugapi.rs new file mode 100644 index 000000000..442b50db4 --- /dev/null +++ b/winapi/src/um/debugapi.rs @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD, PBOOL}; +use um::minwinbase::LPDEBUG_EVENT; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR}; +extern "system" { + pub fn IsDebuggerPresent() -> BOOL; + pub fn DebugBreak(); + pub fn OutputDebugStringA( + lpOutputString: LPCSTR, + ); + pub fn OutputDebugStringW( + lpOutputString: LPCWSTR, + ); + pub fn ContinueDebugEvent( + dwProcessId: DWORD, + dwThreadId: DWORD, + dwContinueStatus: DWORD, + ) -> BOOL; + pub fn WaitForDebugEvent( + lpDebugEvent: LPDEBUG_EVENT, + dwMilliseconds: DWORD, + ) -> BOOL; + pub fn DebugActiveProcess( + dwProcessId: DWORD, + ) -> BOOL; + pub fn DebugActiveProcessStop( + dwProcessId: DWORD, + ) -> BOOL; + pub fn CheckRemoteDebuggerPresent( + hProcess: HANDLE, + pbDebuggerPresent: PBOOL, + ) -> BOOL; + pub fn WaitForDebugEventEx( + lpDebugEvent: LPDEBUG_EVENT, + dwMilliseconds: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/devicetopology.rs b/winapi/src/um/devicetopology.rs new file mode 100644 index 000000000..6f74ffba1 --- /dev/null +++ b/winapi/src/um/devicetopology.rs @@ -0,0 +1,462 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! The DeviceTopology API gives clients control over a variety of internal functions of audio +//! adapters that they cannot access through the MMDevice API, WASAPI, or the EndpointVolume API. +use ctypes::{c_float, c_void}; +use shared::guiddef::{GUID, LPCGUID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, UCHAR, UINT, ULONG, WORD}; +use shared::windef::COLORREF; +use shared::wtypes::VARTYPE; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LONG, LONGLONG, LPWSTR, WCHAR}; +DEFINE_GUID!{EVENTCONTEXT_VOLUMESLIDER, + 0xe2c2e9de, 0x09b1, 0x4b04, 0x84, 0xe5, 0x07, 0x93, 0x12, 0x25, 0xee, 0x04} +STRUCT!{struct KSDATAFORMAT { + FormatSize: ULONG, + Flags: ULONG, + SampleSize: ULONG, + Reserved: ULONG, + MajorFormat: GUID, + SubFormat: GUID, + Specifier: GUID, +}} +pub type PKSDATAFORMAT = *mut KSDATAFORMAT; +STRUCT!{struct KSIDENTIFIER_s { + Set: GUID, + Id: ULONG, + Flags: ULONG, +}} +UNION!{union KSIDENTIFIER { + [u64; 3], + s s_mut: KSIDENTIFIER_s, + Alignment Alignment_mut: LONGLONG, +}} +pub type KSPROPERTY = KSIDENTIFIER; +pub type PKSPROPERTY = *mut KSIDENTIFIER; +pub type KSMETHOD = KSIDENTIFIER; +pub type PKSMETHOD = *mut KSIDENTIFIER; +pub type KSEVENT = KSIDENTIFIER; +pub type PKSEVENT = *mut KSIDENTIFIER; +ENUM!{enum EPcxConnectionType { + eConnTypeUnknown = 0, + eConnType3Point5mm = 1, + eConnTypeQuarter = 2, + eConnTypeAtapiInternal = 3, + eConnTypeRCA = 4, + eConnTypeOptical = 5, + eConnTypeOtherDigital = 6, + eConnTypeOtherAnalog = 7, + eConnTypeMultichannelAnalogDIN = 8, + eConnTypeXlrProfessional = 9, + eConnTypeRJ11Modem = 10, + eConnTypeCombination = 11, +}} +ENUM!{enum EPcxGeoLocation { + eGeoLocRear = 1, + eGeoLocFront = 2, + eGeoLocLeft = 3, + eGeoLocRight = 4, + eGeoLocTop = 5, + eGeoLocBottom = 6, + eGeoLocRearPanel = 7, + eGeoLocRiser = 8, + eGeoLocInsideMobileLid = 9, + eGeoLocDrivebay = 10, + eGeoLocHDMI = 11, + eGeoLocOutsideMobileLid = 12, + eGeoLocATAPI = 13, + eGeoLocNotApplicable = 14, + eGeoLocReserved6 = 15, +}} +ENUM!{enum EPcxGenLocation { + eGenLocPrimaryBox = 0, + eGenLocInternal = 1, + eGenLocSeparate = 2, + eGenLocOther = 3, +}} +ENUM!{enum EPxcPortConnection { + ePortConnJack = 0, + ePortConnIntegratedDevice = 1, + ePortConnBothIntegratedAndJack = 2, + ePortConnUnknown = 3, +}} +STRUCT!{struct KSJACK_DESCRIPTION { + ChannelMapping: DWORD, + Color: COLORREF, + ConnectionType: EPcxConnectionType, + GeoLocation: EPcxGeoLocation, + GenLocation: EPcxGenLocation, + PortConnection: EPxcPortConnection, + IsConnected: BOOL, +}} +pub type PKSJACK_DESCRIPTION = *mut KSJACK_DESCRIPTION; +STRUCT!{struct LUID { + LowPart: DWORD, + HighPart: LONG, +}} +pub type PLUID = *mut LUID; +ENUM!{enum KSJACK_SINK_CONNECTIONTYPE { + KSJACK_SINK_CONNECTIONTYPE_HDMI = 0, + KSJACK_SINK_CONNECTIONTYPE_DISPLAYPORT = 1, +}} +STRUCT!{struct KSJACK_SINK_INFORMATION { + ConnType: KSJACK_SINK_CONNECTIONTYPE, + ManufacturerId: WORD, + ProductId: WORD, + AudioLatency: WORD, + HDCPCapable: BOOL, + AICapable: BOOL, + SinkDescriptionLength: UCHAR, + SinkDescription: [WCHAR; 32], + PortId: LUID, +}} +STRUCT!{struct KSJACK_DESCRIPTION2 { + DeviceStateInfo: DWORD, + JackCapabilities: DWORD, +}} +pub type PKSJACK_DESCRIPTION2 = *mut KSJACK_DESCRIPTION2; +ENUM!{enum DataFlow { + In = 0, + Out = 1, +}} +ENUM!{enum PartType { + Connector = 0, + Subunit = 1, +}} +ENUM!{enum ConnectorType { + Unknown_Connector = 0, + Physical_Internal = 1, + Physical_External = 2, + Software_IO = 3, + Software_Fixed = 4, + Network = 5, +}} +RIDL!{#[uuid(0x28f54685, 0x06fd, 0x11d2, 0xb2, 0x7a, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96)] +interface IKsControl(IKsControlVtbl): IUnknown(IUnknownVtbl) { + fn KsProperty( + Property: PKSPROPERTY, + PropertyLength: ULONG, + PropertyData: *mut c_void, + DataLength: ULONG, + BytesReturned: *mut ULONG, + ) -> HRESULT, + fn KsMethod( + Method: PKSMETHOD, + MethodLength: ULONG, + MethodData: *mut c_void, + DataLength: ULONG, + BytesReturned: *mut ULONG, + ) -> HRESULT, + fn KsEvent( + Event: PKSEVENT, + EventLength: ULONG, + EventData: *mut c_void, + DataLength: ULONG, + BytesReturned: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc2f8e001, 0xf205, 0x4bc9, 0x99, 0xbc, 0xc1, 0x3b, 0x1e, 0x04, 0x8c, 0xcb)] +interface IPerChannelDbLevel(IPerChannelDbLevelVtbl): IUnknown(IUnknownVtbl) { + fn GetChannelCount( + pcChannels: *mut UINT, + ) -> HRESULT, + fn GetLevelRange( + nChannel: UINT, + pfMinLevelDB: *mut c_float, + pfMaxLevelDB: *mut c_float, + pfStepping: *mut c_float, + ) -> HRESULT, + fn GetLevel( + nChannel: UINT, + pfLevelDB: *mut c_float, + ) -> HRESULT, + fn SetLevel( + nChannel: UINT, + fLevelDB: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn SetLevelUniform( + fLevelDB: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn SetLevelAllChannels( + aLevelsDB: *mut c_float, + cChannels: ULONG, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7fb7b48f, 0x531d, 0x44a2, 0xbc, 0xb3, 0x5a, 0xd5, 0xa1, 0x34, 0xb3, 0xdc)] +interface IAudioVolumeLevel(IAudioVolumeLevelVtbl): IPerChannelDbLevel(IPerChannelDbLevelVtbl) {}} +RIDL!{#[uuid(0xbb11c46f, 0xec28, 0x493c, 0xb8, 0x8a, 0x5d, 0xb8, 0x80, 0x62, 0xce, 0x98)] +interface IAudioChannelConfig(IAudioChannelConfigVtbl): IUnknown(IUnknownVtbl) { + fn SetChannelConfig( + dwConfig: DWORD, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn GetChannelConfig( + pdwConfig: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7d8b1437, 0xdd53, 0x4350, 0x9c, 0x1b, 0x1e, 0xe2, 0x89, 0x0b, 0xd9, 0x38)] +interface IAudioLoudness(IAudioLoudnessVtbl): IUnknown(IUnknownVtbl) { + fn GetEnabled( + pbEnabled: *mut BOOL, + ) -> HRESULT, + fn SetEnabled( + bEnable: BOOL, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4f03dc02, 0x5e6e, 0x4653, 0x8f, 0x72, 0xa0, 0x30, 0xc1, 0x23, 0xd5, 0x98)] +interface IAudioInputSelector(IAudioInputSelectorVtbl): IUnknown(IUnknownVtbl) { + fn GetSelection( + pnIdSelected: *mut UINT, + ) -> HRESULT, + fn SetSelection( + nIdSelect: UINT, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbb515f69, 0x94a7, 0x429e, 0x8b, 0x9c, 0x27, 0x1b, 0x3f, 0x11, 0xa3, 0xab)] +interface IAudioOutputSelector(IAudioOutputSelectorVtbl): IUnknown(IUnknownVtbl) { + fn GetSelection( + pnIdSelected: *mut UINT, + ) -> HRESULT, + fn SetSelection( + nIdSelect: UINT, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdf45aeea, 0xb74a, 0x4b6b, 0xaf, 0xad, 0x23, 0x66, 0xb6, 0xaa, 0x01, 0x2e)] +interface IAudioMute(IAudioMuteVtbl): IUnknown(IUnknownVtbl) { + fn SetMute( + bMuted: BOOL, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn GetMute( + pbMuted: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa2b1a1d9, 0x4db3, 0x425d, 0xa2, 0xb2, 0xbd, 0x33, 0x5c, 0xb3, 0xe2, 0xe5)] +interface IAudioBass(IAudioBassVtbl): IPerChannelDbLevel(IPerChannelDbLevelVtbl) {}} +RIDL!{#[uuid(0x5e54b6d7, 0xb44b, 0x40d9, 0x9a, 0x9e, 0xe6, 0x91, 0xd9, 0xce, 0x6e, 0xdf)] +interface IAudioMidrange(IAudioMidrangeVtbl): IPerChannelDbLevel(IPerChannelDbLevelVtbl) {}} +RIDL!{#[uuid(0x0a717812, 0x694e, 0x4907, 0xb7, 0x4b, 0xba, 0xfa, 0x5c, 0xfd, 0xca, 0x7b)] +interface IAudioTreble(IAudioTrebleVtbl): IPerChannelDbLevel(IPerChannelDbLevelVtbl) {}} +RIDL!{#[uuid(0x85401fd4, 0x6de4, 0x4b9d, 0x98, 0x69, 0x2d, 0x67, 0x53, 0xa8, 0x2f, 0x3c)] +interface IAudioAutoGainControl(IAudioAutoGainControlVtbl): IUnknown(IUnknownVtbl) { + fn GetEnabled( + pbEnabled: *mut BOOL, + ) -> HRESULT, + fn SetEnabled( + bEnable: BOOL, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdd79923c, 0x0599, 0x45e0, 0xb8, 0xb6, 0xc8, 0xdf, 0x7d, 0xb6, 0xe7, 0x96)] +interface IAudioPeakMeter(IAudioPeakMeterVtbl): IUnknown(IUnknownVtbl) { + fn GetChannelCount( + pcChannels: *mut UINT, + ) -> HRESULT, + fn GetLevel( + nChannel: UINT, + pfLevel: *mut c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b22bcbf, 0x2586, 0x4af0, 0x85, 0x83, 0x20, 0x5d, 0x39, 0x1b, 0x80, 0x7c)] +interface IDeviceSpecificProperty(IDeviceSpecificPropertyVtbl): IUnknown(IUnknownVtbl) { + fn GetType( + pVType: *mut VARTYPE, + ) -> HRESULT, + fn GetValue( + pvValue: *mut c_void, + pcbValue: *mut DWORD, + ) -> HRESULT, + fn SetValue( + pvValue: *mut c_void, + cbValue: DWORD, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn Get4BRange( + plMin: *mut LONG, + plMax: *mut LONG, + plStepping: *mut LONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3cb4a69d, 0xbb6f, 0x4d2b, 0x95, 0xb7, 0x45, 0x2d, 0x2c, 0x15, 0x5d, 0xb5)] +interface IKsFormatSupport(IKsFormatSupportVtbl): IUnknown(IUnknownVtbl) { + fn IsFormatSupported( + pKsFormat: PKSDATAFORMAT, + cbFormat: DWORD, + pbSupported: *mut BOOL, + ) -> HRESULT, + fn GetDevicePreferredFormat( + ppKsFormat: *mut PKSDATAFORMAT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4509f757, 0x2d46, 0x4637, 0x8e, 0x62, 0xce, 0x7d, 0xb9, 0x44, 0xf5, 0x7b)] +interface IKsJackDescription(IKsJackDescriptionVtbl): IUnknown(IUnknownVtbl) { + fn GetJackCount( + pcJacks: *mut UINT, + ) -> HRESULT, + fn GetJackDescription( + nJack: UINT, + pDescription: *mut KSJACK_DESCRIPTION, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x478f3a9b, 0xe0c9, 0x4827, 0x92, 0x28, 0x6f, 0x55, 0x05, 0xff, 0xe7, 0x6a)] +interface IKsJackDescription2(IKsJackDescription2Vtbl): IUnknown(IUnknownVtbl) { + fn GetJackCount( + pcJacks: *mut UINT, + ) -> HRESULT, + fn GetJackDescription2( + nJack: UINT, + pDescription2: *mut KSJACK_DESCRIPTION2, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd9bd72ed, 0x290f, 0x4581, 0x9f, 0xf3, 0x61, 0x02, 0x7a, 0x8f, 0xe5, 0x32)] +interface IKsJackSinkInformation(IKsJackSinkInformationVtbl): IUnknown(IUnknownVtbl) { + fn GetJackSinkInformation( + pJackSinkInformation: *mut KSJACK_SINK_INFORMATION, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc99af463, 0xd629, 0x4ec4, 0x8c, 0x00, 0xe5, 0x4d, 0x68, 0x15, 0x42, 0x48)] +interface IKsJackContainerId(IKsJackContainerIdVtbl): IUnknown(IUnknownVtbl) { + fn GetJackContainerId( + pJackContainerId: *mut GUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6daa848c, 0x5eb0, 0x45cc, 0xae, 0xa5, 0x99, 0x8a, 0x2c, 0xda, 0x1f, 0xfb)] +interface IPartsList(IPartsListVtbl): IUnknown(IUnknownVtbl) { + fn GetCount( + pCount: *mut UINT, + ) -> HRESULT, + fn GetPart( + nIndex: UINT, + ppPart: *mut *mut IPart, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xae2de0e4, 0x5bca, 0x4f2d, 0xaa, 0x46, 0x5d, 0x13, 0xf8, 0xfd, 0xb3, 0xa9)] +interface IPart(IPartVtbl): IUnknown(IUnknownVtbl) { + fn GetName( + ppwstrName: *mut LPWSTR, + ) -> HRESULT, + fn GetLocalId( + pnId: *mut UINT, + ) -> HRESULT, + fn GetGlobalId( + ppwstrGlobalId: *mut LPWSTR, + ) -> HRESULT, + fn GetPartType( + pPartType: *mut PartType, + ) -> HRESULT, + fn GetSubType( + pSubType: *mut GUID, + ) -> HRESULT, + fn GetControlInterfaceCount( + pCount: *mut UINT, + ) -> HRESULT, + fn GetControlInterface( + nIndex: UINT, + ppInterfaceDesc: *mut *mut IControlInterface, + ) -> HRESULT, + fn EnumPartsIncoming( + ppParts: *mut *mut IPartsList, + ) -> HRESULT, + fn EnumPartsOutgoing( + ppParts: *mut *mut IPartsList, + ) -> HRESULT, + fn GetTopologyObject( + ppTopology: *mut *mut IDeviceTopology, + ) -> HRESULT, + fn Activate( + dwClsContext: DWORD, + refiid: REFIID, + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn RegisterControlChangeCallback( + riid: REFGUID, + pNotify: *mut IControlChangeNotify, + ) -> HRESULT, + fn UnregisterControlChangeCallback( + pNotify: *mut IControlChangeNotify, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9c2c4058, 0x23f5, 0x41de, 0x87, 0x7a, 0xdf, 0x3a, 0xf2, 0x36, 0xa0, 0x9e)] +interface IConnector(IConnectorVtbl): IUnknown(IUnknownVtbl) { + fn GetType( + pType: *mut ConnectorType, + ) -> HRESULT, + fn GetDataFlow( + pFlow: *mut DataFlow, + ) -> HRESULT, + fn ConnectTo( + pConnectTo: *mut IConnector, + ) -> HRESULT, + fn Disconnect() -> HRESULT, + fn IsConnected( + pbConnected: *mut BOOL, + ) -> HRESULT, + fn GetConnectedTo( + ppConTo: *mut *mut IConnector, + ) -> HRESULT, + fn GetConnectorIdConnectedTo( + ppwstrConnectorId: *mut LPWSTR, + ) -> HRESULT, + fn GetDeviceIdConnectedTo( + ppwstrDeviceId: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x82149a85, 0xdba6, 0x4487, 0x86, 0xbb, 0xea, 0x8f, 0x7f, 0xef, 0xcc, 0x71)] +interface ISubunit(ISubunitVtbl): IUnknown(IUnknownVtbl) {}} +RIDL!{#[uuid(0x45d37c3f, 0x5140, 0x444a, 0xae, 0x24, 0x40, 0x07, 0x89, 0xf3, 0xcb, 0xf3)] +interface IControlInterface(IControlInterfaceVtbl): IUnknown(IUnknownVtbl) { + fn GetName( + ppwstrName: *mut LPWSTR, + ) -> HRESULT, + fn GetIID( + pIID: *mut GUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa09513ed, 0xc709, 0x4d21, 0xbd, 0x7b, 0x5f, 0x34, 0xc4, 0x7f, 0x39, 0x47)] +interface IControlChangeNotify(IControlChangeNotifyVtbl): IUnknown(IUnknownVtbl) { + fn OnNotify( + dwSenderProcessId: DWORD, + pguidEventContext: LPCGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2a07407e, 0x6497, 0x4a18, 0x97, 0x87, 0x32, 0xf7, 0x9b, 0xd0, 0xd9, 0x8f)] +interface IDeviceTopology(IDeviceTopologyVtbl): IUnknown(IUnknownVtbl) { + fn GetConnectorCount( + pCount: *mut UINT, + ) -> HRESULT, + fn GetConnector( + nIndex: UINT, + ppConnector: *mut *mut IConnector, + ) -> HRESULT, + fn GetSubunitCount( + pCount: *mut UINT, + ) -> HRESULT, + fn GetSubunit( + nIndex: UINT, + ppSubunit: *mut *mut ISubunit, + ) -> HRESULT, + fn GetPartById( + nId: UINT, + ppPart: *mut *mut IPart, + ) -> HRESULT, + fn GetDeviceId( + ppwstrDeviceId: *mut LPWSTR, + ) -> HRESULT, + fn GetSignalPath( + pIPartFrom: *mut IPart, + pIPartTo: *mut IPart, + bRejectMixedPaths: BOOL, + ppParts: *mut *mut IPartsList, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1df639d0, 0x5ec1, 0x47aa, 0x93, 0x79, 0x82, 0x8d, 0xc1, 0xaa, 0x8c, 0x59)] +class DeviceTopology;} diff --git a/winapi/src/um/dinput.rs b/winapi/src/um/dinput.rs new file mode 100644 index 000000000..5b5b1c5e5 --- /dev/null +++ b/winapi/src/um/dinput.rs @@ -0,0 +1,107 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{CLSID_DirectInput, + 0x25e609e0, 0xb259, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{CLSID_DirectInputDevice, + 0x25e609e1, 0xb259, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{CLSID_DirectInput8, + 0x25e609e4, 0xb259, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{CLSID_DirectInputDevice8, + 0x25e609e5, 0xb259, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputA, + 0x89521360, 0xaa8a, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputW, + 0x89521361, 0xaa8a, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInput2A, + 0x5944e662, 0xaa8a, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInput2W, + 0x5944e663, 0xaa8a, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInput7A, + 0x9a4cb684, 0x236d, 0x11d3, 0x8e, 0x9d, 0x00, 0xc0, 0x4f, 0x68, 0x44, 0xae} +DEFINE_GUID!{IID_IDirectInput7W, + 0x9a4cb685, 0x236d, 0x11d3, 0x8e, 0x9d, 0x00, 0xc0, 0x4f, 0x68, 0x44, 0xae} +DEFINE_GUID!{IID_IDirectInput8A, + 0xbf798030, 0x483a, 0x4da2, 0xaa, 0x99, 0x5d, 0x64, 0xed, 0x36, 0x97, 0x00} +DEFINE_GUID!{IID_IDirectInput8W, + 0xbf798031, 0x483a, 0x4da2, 0xaa, 0x99, 0x5d, 0x64, 0xed, 0x36, 0x97, 0x00} +DEFINE_GUID!{IID_IDirectInputDeviceA, + 0x5944e680, 0xc92e, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputDeviceW, + 0x5944e681, 0xc92e, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputDevice2A, + 0x5944e682, 0xc92e, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputDevice2W, + 0x5944e683, 0xc92e, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{IID_IDirectInputDevice7A, + 0x57d7c6bc, 0x2356, 0x11d3, 0x8e, 0x9d, 0x00, 0xc0, 0x4f, 0x68, 0x44, 0xae} +DEFINE_GUID!{IID_IDirectInputDevice7W, + 0x57d7c6bd, 0x2356, 0x11d3, 0x8e, 0x9d, 0x00, 0xc0, 0x4f, 0x68, 0x44, 0xae} +DEFINE_GUID!{IID_IDirectInputDevice8A, + 0x54d41080, 0xdc15, 0x4833, 0xa4, 0x1b, 0x74, 0x8f, 0x73, 0xa3, 0x81, 0x79} +DEFINE_GUID!{IID_IDirectInputDevice8W, + 0x54d41081, 0xdc15, 0x4833, 0xa4, 0x1b, 0x74, 0x8f, 0x73, 0xa3, 0x81, 0x79} +DEFINE_GUID!{IID_IDirectInputEffect, + 0xe7e1f7c0, 0x88d2, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_XAxis, + 0xa36d02e0, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_YAxis, + 0xa36d02e1, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_ZAxis, + 0xa36d02e2, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_RxAxis, + 0xa36d02f4, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_RyAxis, + 0xa36d02f5, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_RzAxis, + 0xa36d02e3, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_Slider, + 0xa36d02e4, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_Button, + 0xa36d02f0, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_Key, + 0x55728220, 0xd33c, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_POV, + 0xa36d02f2, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_Unknown, + 0xa36d02f3, 0xc9f3, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysMouse, + 0x6f1d2b60, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysKeyboard, + 0x6f1d2b61, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_Joystick, + 0x6f1d2b70, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysMouseEm, + 0x6f1d2b80, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysMouseEm2, + 0x6f1d2b81, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysKeyboardEm, + 0x6f1d2b82, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_SysKeyboardEm2, + 0x6f1d2b83, 0xd5a0, 0x11cf, 0xbf, 0xc7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{GUID_ConstantForce, + 0x13541c20, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_RampForce, + 0x13541c21, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Square, + 0x13541c22, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Sine, + 0x13541c23, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Triangle, + 0x13541c24, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_SawtoothUp, + 0x13541c25, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_SawtoothDown, + 0x13541c26, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Spring, + 0x13541c27, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Damper, + 0x13541c28, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Inertia, + 0x13541c29, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_Friction, + 0x13541c2a, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} +DEFINE_GUID!{GUID_CustomForce, + 0x13541c2b, 0x8e33, 0x11d0, 0x9a, 0xd0, 0x00, 0xa0, 0xc9, 0xa0, 0x6e, 0x35} diff --git a/winapi/src/um/dispex.rs b/winapi/src/um/dispex.rs new file mode 100644 index 000000000..a846b461f --- /dev/null +++ b/winapi/src/um/dispex.rs @@ -0,0 +1,221 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::DWORD_PTR; +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, WORD}; +use shared::winerror::HRESULT; +use shared::wtypes::{BSTR, VARIANT_BOOL, VARTYPE}; +use um::oaidl::{DISPID, DISPID_UNKNOWN, DISPPARAMS, EXCEPINFO, IDispatch, IDispatchVtbl, VARIANT}; +use um::servprov::IServiceProvider; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::LCID; +DEFINE_GUID!{IID_IDispatchEx, + 0xa6ef9860, 0xc720, 0x11d0, 0x93, 0x37, 0x0, 0xa0, 0xc9, 0xd, 0xca, 0xa9} +DEFINE_GUID!{IID_IDispError, + 0xa6ef9861, 0xc720, 0x11d0, 0x93, 0x37, 0x0, 0xa0, 0xc9, 0xd, 0xca, 0xa9} +DEFINE_GUID!{IID_IVariantChangeType, + 0xa6ef9862, 0xc720, 0x11d0, 0x93, 0x37, 0x0, 0xa0, 0xc9, 0xd, 0xca, 0xa9} +DEFINE_GUID!{SID_VariantConversion, + 0x1f101481, 0xbccd, 0x11d0, 0x93, 0x36, 0x0, 0xa0, 0xc9, 0xd, 0xca, 0xa9} +DEFINE_GUID!{SID_GetCaller, + 0x4717cc40, 0xbcb9, 0x11d0, 0x93, 0x36, 0x0, 0xa0, 0xc9, 0xd, 0xca, 0xa9} +DEFINE_GUID!{SID_ProvideRuntimeContext, + 0x74a5040c, 0xdd0c, 0x48f0, 0xac, 0x85, 0x19, 0x4c, 0x32, 0x59, 0x18, 0xa} +DEFINE_GUID!{IID_IProvideRuntimeContext, + 0x10e2414a, 0xec59, 0x49d2, 0xbc, 0x51, 0x5a, 0xdd, 0x2c, 0x36, 0xfe, 0xbc} +DEFINE_GUID!{IID_IObjectIdentity, + 0xca04b7e6, 0xd21, 0x11d1, 0x8c, 0xc5, 0x0, 0xc0, 0x4f, 0xc2, 0xb0, 0x85} +DEFINE_GUID!{IID_ICanHandleException, + 0xc5598e60, 0xb307, 0x11d1, 0xb2, 0x7d, 0x0, 0x60, 0x08, 0xc3, 0xfb, 0xfb} +// pub const SID_GetScriptSite = IID_IActiveScriptSite; +pub const fdexNameCaseSensitive: DWORD = 0x00000001; +pub const fdexNameEnsure: DWORD = 0x00000002; +pub const fdexNameImplicit: DWORD = 0x00000004; +pub const fdexNameCaseInsensitive: DWORD = 0x00000008; +pub const fdexNameInternal: DWORD = 0x00000010; +pub const fdexNameNoDynamicProperties: DWORD = 0x00000020; +pub const fdexPropCanGet: DWORD = 0x00000001; +pub const fdexPropCannotGet: DWORD = 0x00000002; +pub const fdexPropCanPut: DWORD = 0x00000004; +pub const fdexPropCannotPut: DWORD = 0x00000008; +pub const fdexPropCanPutRef: DWORD = 0x00000010; +pub const fdexPropCannotPutRef: DWORD = 0x00000020; +pub const fdexPropNoSideEffects: DWORD = 0x00000040; +pub const fdexPropDynamicType: DWORD = 0x00000080; +pub const fdexPropCanCall: DWORD = 0x00000100; +pub const fdexPropCannotCall: DWORD = 0x00000200; +pub const fdexPropCanConstruct: DWORD = 0x00000400; +pub const fdexPropCannotConstruct: DWORD = 0x00000800; +pub const fdexPropCanSourceEvents: DWORD = 0x00001000; +pub const fdexPropCannotSourceEvents: DWORD = 0x00002000; +pub const grfdexPropCanAll: DWORD = fdexPropCanGet | fdexPropCanPut | fdexPropCanPutRef + | fdexPropCanCall | fdexPropCanConstruct | fdexPropCanSourceEvents; +pub const grfdexPropCannotAll: DWORD = fdexPropCannotGet | fdexPropCannotPut | fdexPropCannotPutRef + | fdexPropCannotCall | fdexPropCannotConstruct | fdexPropCannotSourceEvents; +pub const grfdexPropExtraAll: DWORD = fdexPropNoSideEffects | fdexPropDynamicType; +pub const grfdexPropAll: DWORD = grfdexPropCanAll | grfdexPropCannotAll | grfdexPropExtraAll; +pub const fdexEnumDefault: DWORD = 0x00000001; +pub const fdexEnumAll: DWORD = 0x00000002; +pub const DISPATCH_CONSTRUCT: DWORD = 0x4000; +pub const DISPID_THIS: DISPID = -613; +pub const DISPID_STARTENUM: DISPID = DISPID_UNKNOWN; +// extern RPC_IF_HANDLE __MIDL_itf_dispex_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_dispex_0000_0000_v0_0_s_ifspec; +// EXTERN_C const IID IID_IDispatchEx; +RIDL!{#[uuid(0xa6ef9860, 0xc720, 0x11d0, 0x93, 0x37, 0x00, 0xa0, 0xc9, 0x0d, 0xca, 0xa9)] +interface IDispatchEx(IDispatchExVtbl): IDispatch(IDispatchVtbl) { + fn GetDispID( + bstrName: BSTR, + grfdex: DWORD, + pid: *mut DISPID, + ) -> HRESULT, + fn InvokeEx( + id: DISPID, + lcid: LCID, + wFlags: WORD, + pdp: *mut DISPPARAMS, + pvarRes: *mut VARIANT, + pei: *mut EXCEPINFO, + pspCaller: *mut IServiceProvider, + ) -> HRESULT, + fn DeleteMemberByName( + bstrName: BSTR, + grfdex: DWORD, + ) -> HRESULT, + fn DeleteMemberByDispID( + id: DISPID, + ) -> HRESULT, + fn GetMemberProperties( + id: DISPID, + grfdexFetch: DWORD, + pgrfdex: *mut DWORD, + ) -> HRESULT, + fn GetMemberName( + id: DISPID, + pbstrName: *mut BSTR, + ) -> HRESULT, + fn GetNextDispID( + grfdex: DWORD, + id: DISPID, + pid: *mut DISPID, + ) -> HRESULT, + fn GetNameSpaceParent( + ppunk: *mut *mut IUnknown, + ) -> HRESULT, +}} +// HRESULT STDMETHODCALLTYPE IDispatchEx_RemoteInvokeEx_Proxy( +// IDispatchEx * This, +// DISPID id, +// LCID lcid, +// DWORD dwFlags, +// DISPPARAMS *pdp, +// VARIANT *pvarRes, +// EXCEPINFO *pei, +// IServiceProvider *pspCaller, +// UINT cvarRefArg, +// UINT *rgiRefArg, +// VARIANT *rgvarRefArg); +// void __RPC_STUB IDispatchEx_RemoteInvokeEx_Stub( +// IRpcStubBuffer *This, +// IRpcChannelBuffer *_pRpcChannelBuffer, +// PRPC_MESSAGE _pRpcMessage, +// DWORD *_pdwStubPhase); +// EXTERN_C const IID IID_IDispError; +RIDL!{#[uuid(0xa6ef9861, 0xc720, 0x11d0, 0x93, 0x37, 0x00, 0xa0, 0xc9, 0x0d, 0xca, 0xa9)] +interface IDispError(IDispErrorVtbl): IUnknown(IUnknownVtbl) { + fn QueryErrorInfo( + guidErrorType: GUID, + ppde: *mut *mut IDispError, + ) -> HRESULT, + fn GetNext( + ppde: *mut *mut IDispError, + ) -> HRESULT, + fn GetHresult( + phr: *mut HRESULT, + ) -> HRESULT, + fn GetSource( + pbstrSource: *mut BSTR, + ) -> HRESULT, + fn GetHelpInfo( + pbstrFileName: *mut BSTR, + pdwContext: *mut DWORD, + ) -> HRESULT, + fn GetDescription( + pbstrDescription: *mut BSTR, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IVariantChangeType; +RIDL!{#[uuid(0xa6ef9862, 0xc720, 0x11d0, 0x93, 0x37, 0x00, 0xa0, 0xc9, 0x0d, 0xca, 0xa9)] +interface IVariantChangeType(IVariantChangeTypeVtbl): IUnknown(IUnknownVtbl) { + fn ChangeType( + pvarDst: *mut VARIANT, + pvarSrc: *mut VARIANT, + lcid: LCID, + vtNew: VARTYPE, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IObjectIdentity; +RIDL!{#[uuid(0xca04b7e6, 0x0d21, 0x11d1, 0x8c, 0xc5, 0x00, 0xc0, 0x4f, 0xc2, 0xb0, 0x85)] +interface IObjectIdentity(IObjectIdentityVtbl): IUnknown(IUnknownVtbl) { + fn IsEqualObject( + punk: *mut IUnknown, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ICanHandleException; +RIDL!{#[uuid(0xc5598e60, 0xb307, 0x11d1, 0xb2, 0x7d, 0x00, 0x60, 0x08, 0xc3, 0xfb, 0xfb)] +interface ICanHandleException(ICanHandleExceptionVtbl): IUnknown(IUnknownVtbl) { + fn CanHandleException( + pExcepInfo: *mut EXCEPINFO, + pvar: *mut VARIANT, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IProvideRuntimeContext; +RIDL!{#[uuid(0x10e2414a, 0xec59, 0x49d2, 0xbc, 0x51, 0x5a, 0xdd, 0x2c, 0x36, 0xfe, 0xbc)] +interface IProvideRuntimeContext(IProvideRuntimeContextVtbl): IUnknown(IUnknownVtbl) { + fn GetCurrentSourceContext( + pdwContext: *mut DWORD_PTR, + pfExecutingGlobalCode: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +// extern RPC_IF_HANDLE __MIDL_itf_dispex_0000_0006_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_dispex_0000_0006_v0_0_s_ifspec; +// unsigned long __RPC_USER BSTR_UserSize( __RPC__in unsigned long *, unsigned long, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree( __RPC__in unsigned long *, __RPC__in BSTR * ); +// unsigned long __RPC_USER VARIANT_UserSize( __RPC__in unsigned long *, unsigned long, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree( __RPC__in unsigned long *, __RPC__in VARIANT * ); +// unsigned long __RPC_USER BSTR_UserSize64( __RPC__in unsigned long *, unsigned long, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal64( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal64(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree64( __RPC__in unsigned long *, __RPC__in BSTR * ); +// unsigned long __RPC_USER VARIANT_UserSize64( __RPC__in unsigned long *, unsigned long, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal64( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal64(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree64( __RPC__in unsigned long *, __RPC__in VARIANT * ); +// HRESULT STDMETHODCALLTYPE IDispatchEx_InvokeEx_Proxy( +// IDispatchEx * This, +// DISPID id, +// LCID lcid, +// WORD wFlags, +// DISPPARAMS *pdp, +// VARIANT *pvarRes, +// EXCEPINFO *pei, +// IServiceProvider *pspCaller); +// HRESULT STDMETHODCALLTYPE IDispatchEx_InvokeEx_Stub( +// IDispatchEx * This, +// DISPID id, +// LCID lcid, +// DWORD dwFlags, +// DISPPARAMS *pdp, +// VARIANT *pvarRes, +// EXCEPINFO *pei, +// IServiceProvider *pspCaller, +// UINT cvarRefArg, +// UINT *rgiRefArg, +// VARIANT *rgvarRefArg); diff --git a/winapi/src/um/dmksctl.rs b/winapi/src/um/dmksctl.rs new file mode 100644 index 000000000..252ab7387 --- /dev/null +++ b/winapi/src/um/dmksctl.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_IKsControl, + 0x28f54685, 0x06fd, 0x11d2, 0xb2, 0x7a, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_MIDI, + 0x1d262760, 0xe957, 0x11cf, 0xa5, 0xd6, 0x28, 0xdb, 0x04, 0xc1, 0x00, 0x00} +DEFINE_GUID!{KSDATAFORMAT_SUBTYPE_DIRECTMUSIC, + 0x1a82f8bc, 0x3f8b, 0x11d2, 0xb7, 0x74, 0x00, 0x60, 0x08, 0x33, 0x16, 0xc1} diff --git a/winapi/src/um/dmusicc.rs b/winapi/src/um/dmusicc.rs new file mode 100644 index 000000000..ee87b6fde --- /dev/null +++ b/winapi/src/um/dmusicc.rs @@ -0,0 +1,71 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{CLSID_DirectMusic, + 0x636b9f10, 0x0c7d, 0x11d1, 0x95, 0xb2, 0x00, 0x20, 0xaf, 0xdc, 0x74, 0x21} +DEFINE_GUID!{CLSID_DirectMusicCollection, + 0x480ff4b0, 0x28b2, 0x11d1, 0xbe, 0xf7, 0x00, 0xc0, 0x4f, 0xbf, 0x8f, 0xef} +DEFINE_GUID!{CLSID_DirectMusicSynth, + 0x58c2b4d0, 0x46e7, 0x11d1, 0x89, 0xac, 0x00, 0xa0, 0xc9, 0x05, 0x41, 0x29} +DEFINE_GUID!{IID_IDirectMusic, + 0x6536115a, 0x7b2d, 0x11d2, 0xba, 0x18, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{IID_IDirectMusicBuffer, + 0xd2ac2878, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusicPort, + 0x08f2d8c9, 0x37c2, 0x11d2, 0xb9, 0xf9, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{IID_IDirectMusicThru, + 0xced153e7, 0x3606, 0x11d2, 0xb9, 0xf9, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{IID_IDirectMusicPortDownload, + 0xd2ac287a, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusicDownload, + 0xd2ac287b, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusicCollection, + 0xd2ac287c, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusicInstrument, + 0xd2ac287d, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusicDownloadedInstrument, + 0xd2ac287e, 0xb39b, 0x11d1, 0x87, 0x04, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{IID_IDirectMusic2, + 0x6fc2cae1, 0xbc78, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{IID_IDirectMusic8, + 0x2d3629f7, 0x813d, 0x4939, 0x85, 0x08, 0xf0, 0x5c, 0x6b, 0x75, 0xfd, 0x97} +DEFINE_GUID!{GUID_DMUS_PROP_GM_Hardware, + 0x178f2f24, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_GS_Hardware, + 0x178f2f25, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_XG_Hardware, + 0x178f2f26, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_XG_Capable, + 0x6496aba1, 0x61b0, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_GS_Capable, + 0x6496aba2, 0x61b0, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_DLS1, + 0x178f2f27, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_DLS2, + 0xf14599e5, 0x4689, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_INSTRUMENT2, + 0x865fd372, 0x9f67, 0x11d2, 0x87, 0x2a, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{GUID_DMUS_PROP_SynthSink_DSOUND, + 0x0aa97844, 0xc877, 0x11d1, 0x87, 0x0c, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{GUID_DMUS_PROP_SynthSink_WAVE, + 0x0aa97845, 0xc877, 0x11d1, 0x87, 0x0c, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{GUID_DMUS_PROP_SampleMemorySize, + 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_SamplePlaybackRate, + 0x2a91f713, 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x00, 0x60, 0x08, 0x33, 0xdb, 0xd8} +DEFINE_GUID!{GUID_DMUS_PROP_WriteLatency, + 0x268a0fa0, 0x60f2, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_WritePeriod, + 0x268a0fa1, 0x60f2, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_MemorySize, + 0x178f2f28, 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_WavesReverb, + 0x04cb5622, 0x32e5, 0x11d2, 0xaf, 0xa6, 0x00, 0xaa, 0x00, 0x24, 0xd8, 0xb6} +DEFINE_GUID!{GUID_DMUS_PROP_Effects, + 0xcda8d611, 0x684a, 0x11d2, 0x87, 0x1e, 0x00, 0x60, 0x08, 0x93, 0xb1, 0xbd} +DEFINE_GUID!{GUID_DMUS_PROP_LegacyCaps, + 0xcfa7cdc2, 0x00a1, 0x11d2, 0xaa, 0xd5, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} +DEFINE_GUID!{GUID_DMUS_PROP_Volume, + 0xfedfae25, 0xe46e, 0x11d1, 0xaa, 0xce, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12} diff --git a/winapi/src/um/docobj.rs b/winapi/src/um/docobj.rs new file mode 100644 index 000000000..e14ddb9e3 --- /dev/null +++ b/winapi/src/um/docobj.rs @@ -0,0 +1,136 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::wchar_t; +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, ULONG}; +use um::oaidl::VARIANT; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +ENUM!{enum OLECMDF { + OLECMDF_SUPPORTED = 0x1, + OLECMDF_ENABLED = 0x2, + OLECMDF_LATCHED = 0x4, + OLECMDF_NINCHED = 0x8, + OLECMDF_INVISIBLE = 0x10, + OLECMDF_DEFHIDEONCTXTMENU = 0x20, +}} +STRUCT!{struct OLECMD { + cmdID: ULONG, + cmdf: DWORD, +}} +STRUCT!{struct OLECMDTEXT { + cmdtextf: DWORD, + cwActual: ULONG, + cwBuf: ULONG, + rgwz: [wchar_t; 1], +}} +ENUM!{enum OLECMDEXECOPT { + OLECMDEXECOPT_DODEFAULT = 0, + OLECMDEXECOPT_PROMPTUSER = 1, + OLECMDEXECOPT_DONTPROMPTUSER = 2, + OLECMDEXECOPT_SHOWHELP = 3, +}} +ENUM!{enum OLECMDID { + OLECMDID_OPEN = 1, + OLECMDID_NEW = 2, + OLECMDID_SAVE = 3, + OLECMDID_SAVEAS = 4, + OLECMDID_SAVECOPYAS = 5, + OLECMDID_PRINT = 6, + OLECMDID_PRINTPREVIEW = 7, + OLECMDID_PAGESETUP = 8, + OLECMDID_SPELL = 9, + OLECMDID_PROPERTIES = 10, + OLECMDID_CUT = 11, + OLECMDID_COPY = 12, + OLECMDID_PASTE = 13, + OLECMDID_PASTESPECIAL = 14, + OLECMDID_UNDO = 15, + OLECMDID_REDO = 16, + OLECMDID_SELECTALL = 17, + OLECMDID_CLEARSELECTION = 18, + OLECMDID_ZOOM = 19, + OLECMDID_GETZOOMRANGE = 20, + OLECMDID_UPDATECOMMANDS = 21, + OLECMDID_REFRESH = 22, + OLECMDID_STOP = 23, + OLECMDID_HIDETOOLBARS = 24, + OLECMDID_SETPROGRESSMAX = 25, + OLECMDID_SETPROGRESSPOS = 26, + OLECMDID_SETPROGRESSTEXT = 27, + OLECMDID_SETTITLE = 28, + OLECMDID_SETDOWNLOADSTATE = 29, + OLECMDID_STOPDOWNLOAD = 30, + OLECMDID_ONTOOLBARACTIVATED = 31, + OLECMDID_FIND = 32, + OLECMDID_DELETE = 33, + OLECMDID_HTTPEQUIV = 34, + OLECMDID_HTTPEQUIV_DONE = 35, + OLECMDID_ENABLE_INTERACTION = 36, + OLECMDID_ONUNLOAD = 37, + OLECMDID_PROPERTYBAG2 = 38, + OLECMDID_PREREFRESH = 39, + OLECMDID_SHOWSCRIPTERROR = 40, + OLECMDID_SHOWMESSAGE = 41, + OLECMDID_SHOWFIND = 42, + OLECMDID_SHOWPAGESETUP = 43, + OLECMDID_SHOWPRINT = 44, + OLECMDID_CLOSE = 45, + OLECMDID_ALLOWUILESSSAVEAS = 46, + OLECMDID_DONTDOWNLOADCSS = 47, + OLECMDID_UPDATEPAGESTATUS = 48, + OLECMDID_PRINT2 = 49, + OLECMDID_PRINTPREVIEW2 = 50, + OLECMDID_SETPRINTTEMPLATE = 51, + OLECMDID_GETPRINTTEMPLATE = 52, + OLECMDID_PAGEACTIONBLOCKED = 55, + OLECMDID_PAGEACTIONUIQUERY = 56, + OLECMDID_FOCUSVIEWCONTROLS = 57, + OLECMDID_FOCUSVIEWCONTROLSQUERY = 58, + OLECMDID_SHOWPAGEACTIONMENU = 59, + OLECMDID_ADDTRAVELENTRY = 60, + OLECMDID_UPDATETRAVELENTRY = 61, + OLECMDID_UPDATEBACKFORWARDSTATE = 62, + OLECMDID_OPTICAL_ZOOM = 63, + OLECMDID_OPTICAL_GETZOOMRANGE = 64, + OLECMDID_WINDOWSTATECHANGED = 65, + OLECMDID_ACTIVEXINSTALLSCOPE = 66, + OLECMDID_UPDATETRAVELENTRY_DATARECOVERY = 67, + OLECMDID_SHOWTASKDLG = 68, + OLECMDID_POPSTATEEVENT = 69, + OLECMDID_VIEWPORT_MODE = 70, + OLECMDID_LAYOUT_VIEWPORT_WIDTH = 71, + OLECMDID_VISUAL_VIEWPORT_EXCLUDE_BOTTOM = 72, + OLECMDID_USER_OPTICAL_ZOOM = 73, + OLECMDID_PAGEAVAILABLE = 74, + OLECMDID_GETUSERSCALABLE = 75, + OLECMDID_UPDATE_CARET = 76, + OLECMDID_ENABLE_VISIBILITY = 77, + OLECMDID_MEDIA_PLAYBACK = 78, + OLECMDID_SETFAVICON = 79, + OLECMDID_SET_HOST_FULLSCREENMODE = 80, + OLECMDID_EXITFULLSCREEN = 81, + OLECMDID_SCROLLCOMPLETE = 82, + OLECMDID_ONBEFOREUNLOAD = 83, + OLECMDID_SHOWMESSAGE_BLOCKABLE = 84, + OLECMDID_SHOWTASKDLG_BLOCKABLE = 85, +}} +RIDL!{#[uuid(0xb722bccb, 0x4e68, 0x101b, 0xa2, 0xbc, 0x00, 0xaa, 0x00, 0x40, 0x47, 0x70)] +interface IOleCommandTarget(IOleCommandTargetVtbl): IUnknown(IUnknownVtbl) { + fn QueryStatus( + pguidCmdGroup: *const GUID, + cCmds: ULONG, + prgCmds: *mut OLECMD, + pCmdText: *mut OLECMDTEXT, + ) -> HRESULT, + fn Exec( + pguidCmdGroup: *const GUID, + nCmdID: DWORD, + nCmdexecopt: DWORD, + pvaIn: *mut VARIANT, + pvaOut: *mut VARIANT, + ) -> HRESULT, +}} diff --git a/winapi/src/um/documenttarget.rs b/winapi/src/um/documenttarget.rs new file mode 100644 index 000000000..b4cc1ae0c --- /dev/null +++ b/winapi/src/um/documenttarget.rs @@ -0,0 +1,24 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +// TODO:It is a minimal implementation. +use ctypes::c_void; +use shared::basetsd::UINT32; +use shared::guiddef::{GUID, REFGUID, REFIID}; +use shared::ntdef::HRESULT; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +RIDL!{#[uuid(0x1b8efec4, 0x3019, 0x4c27, 0x96, 0x4e, 0x36, 0x72, 0x02, 0x15, 0x69, 0x06)] +interface IPrintDocumentPackageTarget(IPrintDocumentPackageTargetVtbl): IUnknown(IUnknownVtbl) { + fn GetPackageTargetTypes( + targetCount: *mut UINT32, + targetTypes: *mut *mut GUID, + ) -> HRESULT, + fn GetPackageTarget( + guidTargetType: REFGUID, + riid: REFIID, + ppvTarget: *mut *mut c_void, + ) -> HRESULT, + fn Cancel() -> HRESULT, +}} diff --git a/winapi/src/um/dpa_dsa.rs b/winapi/src/um/dpa_dsa.rs new file mode 100644 index 000000000..21a3f4b3b --- /dev/null +++ b/winapi/src/um/dpa_dsa.rs @@ -0,0 +1,283 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_int, c_void}; +use shared::basetsd::INT_PTR; +use shared::minwindef::{BOOL, DWORD, LPARAM, UINT}; +use um::winnt::{HANDLE, HRESULT, LPCWSTR, LPWSTR, PVOID, ULONGLONG}; +pub const DA_LAST: c_int = 0x7FFFFFFF; +pub const DA_ERR: c_int = -1; +FN!{stdcall PFNDAENUMCALLBACK( + p: *mut c_void, + pData: *mut c_void, +) -> c_int} +FN!{stdcall PFNDAENUMCALLBACKCONST( + p: *const c_void, + pData: *mut c_void, +) -> c_int} +FN!{stdcall PFNDACOMPARE( + p1: *mut c_void, + p2: *mut c_void, + lParam: LPARAM, +) -> c_int} +FN!{stdcall PFNDACOMPARECONST( + p1: *const c_void, + p2: *const c_void, + lParam: LPARAM, +) -> c_int} +pub enum DSA {} +pub type HDSA = *mut DSA; +extern "system" { + pub fn DSA_Create( + cbItem: c_int, + cItemGrow: c_int, + ) -> HDSA; + pub fn DSA_Destroy( + hdsa: HDSA, + ) -> BOOL; + pub fn DSA_DestroyCallback( + hdsa: HDSA, + pfnCB: PFNDAENUMCALLBACK, + pData: *mut c_void, + ); + pub fn DSA_DeleteItem( + hdsa: HDSA, + i: c_int, + ) -> BOOL; + pub fn DSA_DeleteAllItems( + hdsa: HDSA, + ) -> BOOL; + pub fn DSA_EnumCallback( + hdsa: HDSA, + pfnCB: PFNDAENUMCALLBACK, + pData: *mut c_void, + ); + pub fn DSA_InsertItem( + hdsa: HDSA, + i: c_int, + pitem: *const c_void, + ) -> c_int; + pub fn DSA_GetItemPtr( + hdsa: HDSA, + i: c_int, + ) -> PVOID; + pub fn DSA_GetItem( + hdsa: HDSA, + i: c_int, + pitem: *mut c_void, + ) -> BOOL; + pub fn DSA_SetItem( + hdsa: HDSA, + i: c_int, + pitem: *const c_void, + ) -> BOOL; +} +#[inline] +pub unsafe fn DSA_GetItemCount(hdsa: HDSA) -> c_int { + *(hdsa as *mut c_int) +} +#[inline] +pub unsafe fn DSA_AppendItem(hdsa: HDSA, pitem: *const c_void) -> c_int { + DSA_InsertItem(hdsa, DA_LAST, pitem) +} +extern "system" { + pub fn DSA_Clone( + hdsa: HDSA, + ) -> HDSA; + pub fn DSA_GetSize( + hdsa: HDSA, + ) -> ULONGLONG; + pub fn DSA_Sort( + pdsa: HDSA, + pfnCompare: PFNDACOMPARE, + lParam: LPARAM, + ) -> BOOL; +} +pub const DSA_APPEND: c_int = DA_LAST; +pub const DSA_ERR: c_int = DA_ERR; +pub type PFNDSAENUMCALLBACK = PFNDAENUMCALLBACK; +pub type PFNDSAENUMCALLBACKCONST = PFNDAENUMCALLBACKCONST; +pub type PFNDSACOMPARE = PFNDACOMPARE; +pub type PFNDSACOMPARECONST = PFNDACOMPARECONST; +pub enum DPA {} +pub type HDPA = *mut DPA; +extern "system" { + pub fn DPA_Create( + cItemGrow: c_int, + ) -> HDPA; + pub fn DPA_CreateEx( + cpGrow: c_int, + hheap: HANDLE, + ) -> HDPA; + pub fn DPA_Clone( + hdpa: HDPA, + hdpaNew: HDPA, + ) -> HDPA; + pub fn DPA_Destroy( + hdpa: HDPA, + ) -> BOOL; + pub fn DPA_DestroyCallback( + hdpa: HDPA, + pfnCB: PFNDAENUMCALLBACK, + pData: *mut c_void, + ); + pub fn DPA_DeletePtr( + hdpa: HDPA, + i: c_int, + ) -> PVOID; + pub fn DPA_DeleteAllPtrs( + hdpa: HDPA, + ) -> BOOL; + pub fn DPA_EnumCallback( + hdpa: HDPA, + pfnCB: PFNDAENUMCALLBACK, + pData: *mut c_void, + ); + pub fn DPA_Grow( + hdpa: HDPA, + cp: c_int, + ) -> BOOL; + pub fn DPA_InsertPtr( + hdpa: HDPA, + i: c_int, + p: *mut c_void, + ) -> c_int; + pub fn DPA_SetPtr( + hdpa: HDPA, + i: c_int, + p: *mut c_void, + ) -> BOOL; + pub fn DPA_GetPtr( + hdpa: HDPA, + i: INT_PTR, + ) -> PVOID; + pub fn DPA_GetPtrIndex( + hdpa: HDPA, + p: *const c_void, + ) -> c_int; +} +#[inline] +pub unsafe fn DPA_GetPtrCount(hdpa: HDPA) -> c_int { + *(hdpa as *mut c_int) +} +#[inline] +pub unsafe fn DPA_SetPtrCount(hdpa: HDPA, cItems: c_int) { + *(hdpa as *mut c_int) = cItems; +} +#[inline] +pub unsafe fn DPA_FastDeleteLastPtr(hdpa: HDPA) -> c_int { + *(hdpa as *mut c_int) -= 1; + *(hdpa as *mut c_int) +} +#[inline] +pub unsafe fn DPA_AppendPtr(hdpa: HDPA, pitem: *mut c_void) -> c_int { + DPA_InsertPtr(hdpa, DA_LAST, pitem) +} +extern "system" { + pub fn DPA_GetSize( + hdpa: HDPA, + ) -> ULONGLONG; + pub fn DPA_Sort( + hdpa: HDPA, + pfnCompare: PFNDACOMPARE, + lParam: LPARAM, + ) -> BOOL; +} +STRUCT!{struct DPASTREAMINFO { + iPos: c_int, + pvItem: *mut c_void, +}} +pub enum IStream {} +FN!{stdcall PFNDPASTREAM( + pinfo: *mut DPASTREAMINFO, + pstream: *mut IStream, + pvInstData: *mut c_void, +) -> HRESULT} +extern "system" { + pub fn DPA_LoadStream( + phdpa: *mut HDPA, + pfn: PFNDPASTREAM, + pstream: *mut IStream, + pvInstData: *mut c_void, + ) -> HRESULT; + pub fn DPA_SaveStream( + hdpa: HDPA, + pfn: PFNDPASTREAM, + pstream: *mut IStream, + pvInstData: *mut c_void, + ) -> HRESULT; +} +pub const DPAM_SORTED: DWORD = 0x00000001; +pub const DPAM_NORMAL: DWORD = 0x00000002; +pub const DPAM_UNION: DWORD = 0x00000004; +pub const DPAM_INTERSECT: DWORD = 0x00000008; +FN!{stdcall PFNDPAMERGE( + uMsg: UINT, + pvDest: *mut c_void, + pvSrc: *mut c_void, + lParam: LPARAM, +) -> *mut c_void} +FN!{stdcall PFNDPAMERGECONST( + uMsg: UINT, + pvDest: *const c_void, + pvSrc: *const c_void, + lParam: LPARAM, +) -> *const c_void} +pub const DPAMM_MERGE: UINT = 1; +pub const DPAMM_DELETE: UINT = 2; +pub const DPAMM_INSERT: UINT = 3; +extern "system" { + pub fn DPA_Merge( + hdpaDest: HDPA, + hdpaSrc: HDPA, + dwFlags: DWORD, + pfnCompare: PFNDACOMPARE, + pfnMerge: PFNDPAMERGE, + lParam: LPARAM, + ) -> BOOL; +} +pub const DPAS_SORTED: UINT = 0x0001; +pub const DPAS_INSERTBEFORE: UINT = 0x0002; +pub const DPAS_INSERTAFTER: UINT = 0x0004; +extern "system" { + pub fn DPA_Search( + hdpa: HDPA, + pFind: *mut c_void, + iStart: c_int, + pfnCompare: PFNDACOMPARE, + lParam: LPARAM, + options: UINT, + ) -> c_int; +} +#[inline] +pub unsafe fn DPA_SortedInsertPtr( + hdpa: HDPA, + pFind: *mut c_void, + iStart: c_int, + pfnCompare: PFNDACOMPARE, + lParam: LPARAM, + options: UINT, + pitem: *mut c_void, +) -> c_int { + DPA_InsertPtr( + hdpa, + DPA_Search( + hdpa, pFind, iStart, pfnCompare, lParam, DPAS_SORTED | options, + ), + pitem, + ) +} +pub const DPA_APPEND: c_int = DA_LAST; +pub const DPA_ERR: c_int = DA_ERR; +pub type PFNDPAENUMCALLBACK = PFNDAENUMCALLBACK; +pub type PFNDPAENUMCALLBACKCONST = PFNDAENUMCALLBACKCONST; +pub type PFNDPACOMPARE = PFNDACOMPARE; +pub type PFNDPACOMPARECONST = PFNDACOMPARECONST; +extern "system" { + pub fn Str_SetPtrW( + ppsz: *mut LPWSTR, + psz: LPCWSTR, + ) -> BOOL; +} diff --git a/winapi/src/um/dpapi.rs b/winapi/src/um/dpapi.rs new file mode 100644 index 000000000..42f5824f5 --- /dev/null +++ b/winapi/src/um/dpapi.rs @@ -0,0 +1,100 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Data Protection API Prototypes and Definitions +use shared::minwindef::{BOOL, BYTE, DWORD, LPVOID}; +use shared::windef::HWND; +use um::wincrypt::DATA_BLOB; +use um::winnt::{LPCWSTR, LPWSTR, PSID, PVOID}; +pub const szFORCE_KEY_PROTECTION: &'static str = "ForceKeyProtection"; +pub const dwFORCE_KEY_PROTECTION_DISABLED: DWORD = 0x0; +pub const dwFORCE_KEY_PROTECTION_USER_SELECT: DWORD = 0x1; +pub const dwFORCE_KEY_PROTECTION_HIGH: DWORD = 0x2; +STRUCT!{struct CRYPTPROTECT_PROMPTSTRUCT { + cbSize: DWORD, + dwPromptFlags: DWORD, + hwndApp: HWND, + szPrompt: LPCWSTR, +}} +pub type PCRYPTPROTECT_PROMPTSTRUCT = *mut CRYPTPROTECT_PROMPTSTRUCT; +pub const CRYPTPROTECT_PROMPT_ON_UNPROTECT: DWORD = 0x1; +pub const CRYPTPROTECT_PROMPT_ON_PROTECT: DWORD = 0x2; +pub const CRYPTPROTECT_PROMPT_RESERVED: DWORD = 0x04; +pub const CRYPTPROTECT_PROMPT_STRONG: DWORD = 0x08; +pub const CRYPTPROTECT_PROMPT_REQUIRE_STRONG: DWORD = 0x10; +pub const CRYPTPROTECT_UI_FORBIDDEN: DWORD = 0x1; +pub const CRYPTPROTECT_LOCAL_MACHINE: DWORD = 0x4; +pub const CRYPTPROTECT_CRED_SYNC: DWORD = 0x8; +pub const CRYPTPROTECT_AUDIT: DWORD = 0x10; +pub const CRYPTPROTECT_NO_RECOVERY: DWORD = 0x20; +pub const CRYPTPROTECT_VERIFY_PROTECTION: DWORD = 0x40; +pub const CRYPTPROTECT_CRED_REGENERATE: DWORD = 0x80; +pub const CRYPTPROTECT_FIRST_RESERVED_FLAGVAL: DWORD = 0x0FFFFFFF; +pub const CRYPTPROTECT_LAST_RESERVED_FLAGVAL: DWORD = 0xFFFFFFFF; +extern "system" { + pub fn CryptProtectData( + pDataIn: *mut DATA_BLOB, + szDataDescr: LPCWSTR, + pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, + pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, + dwFlags: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptUnprotectData( + pDataIn: *mut DATA_BLOB, + ppszDataDescr: *mut LPWSTR, + pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, + pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, + dwFlags: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptProtectDataNoUI( + pDataIn: *mut DATA_BLOB, + szDataDescr: LPCWSTR, + pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, + pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, + dwFlags: DWORD, + pbOptionalPassword: *const BYTE, + cbOptionalPassword: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptUnprotectDataNoUI( + pDataIn: *mut DATA_BLOB, + ppszDataDescr: *mut LPWSTR, + pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, + pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, + dwFlags: DWORD, + pbOptionalPassword: *const BYTE, + cbOptionalPassword: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptUpdateProtectedState( + pOldSid: PSID, + pwszOldPassword: LPCWSTR, + dwFlags: DWORD, + pdwSuccessCount: *mut DWORD, + pdwFailureCount: *mut DWORD, + ) -> BOOL; +} +pub const CRYPTPROTECTMEMORY_BLOCK_SIZE: DWORD = 16; +pub const CRYPTPROTECTMEMORY_SAME_PROCESS: DWORD = 0x00; +pub const CRYPTPROTECTMEMORY_CROSS_PROCESS: DWORD = 0x01; +pub const CRYPTPROTECTMEMORY_SAME_LOGON: DWORD = 0x02; +extern "system" { + pub fn CryptProtectMemory( + pDataIn: LPVOID, + cbDataIn: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptUnprotectMemory( + pDataIn: LPVOID, + cbDataIn: DWORD, + dwFlags: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/dsgetdc.rs b/winapi/src/um/dsgetdc.rs new file mode 100644 index 000000000..860a652ec --- /dev/null +++ b/winapi/src/um/dsgetdc.rs @@ -0,0 +1,267 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains structures, function prototypes, and definitions for the DsGetDcName API. +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, PULONG, ULONG}; +use shared::ws2def::{LPSOCKET_ADDRESS, PSOCKET_ADDRESS}; +use um::ntsecapi::PLSA_FOREST_TRUST_INFORMATION; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PHANDLE, PSID}; +pub const DS_FORCE_REDISCOVERY: ULONG = 0x00000001; +pub const DS_DIRECTORY_SERVICE_REQUIRED: ULONG = 0x00000010; +pub const DS_DIRECTORY_SERVICE_PREFERRED: ULONG = 0x00000020; +pub const DS_GC_SERVER_REQUIRED: ULONG = 0x00000040; +pub const DS_PDC_REQUIRED: ULONG = 0x00000080; +pub const DS_BACKGROUND_ONLY: ULONG = 0x00000100; +pub const DS_IP_REQUIRED: ULONG = 0x00000200; +pub const DS_KDC_REQUIRED: ULONG = 0x00000400; +pub const DS_TIMESERV_REQUIRED: ULONG = 0x00000800; +pub const DS_WRITABLE_REQUIRED: ULONG = 0x00001000; +pub const DS_GOOD_TIMESERV_PREFERRED: ULONG = 0x00002000; +pub const DS_AVOID_SELF: ULONG = 0x00004000; +pub const DS_ONLY_LDAP_NEEDED: ULONG = 0x00008000; +pub const DS_IS_FLAT_NAME: ULONG = 0x00010000; +pub const DS_IS_DNS_NAME: ULONG = 0x00020000; +pub const DS_TRY_NEXTCLOSEST_SITE: ULONG = 0x00040000; +pub const DS_DIRECTORY_SERVICE_6_REQUIRED: ULONG = 0x00080000; +pub const DS_WEB_SERVICE_REQUIRED: ULONG = 0x00100000; +pub const DS_DIRECTORY_SERVICE_8_REQUIRED: ULONG = 0x00200000; +pub const DS_DIRECTORY_SERVICE_9_REQUIRED: ULONG = 0x00400000; +pub const DS_DIRECTORY_SERVICE_10_REQUIRED: ULONG = 0x00800000; +pub const DS_RETURN_DNS_NAME: ULONG = 0x40000000; +pub const DS_RETURN_FLAT_NAME: ULONG = 0x80000000; +pub const DSGETDC_VALID_FLAGS: ULONG = DS_FORCE_REDISCOVERY | DS_DIRECTORY_SERVICE_REQUIRED + | DS_DIRECTORY_SERVICE_PREFERRED | DS_GC_SERVER_REQUIRED | DS_PDC_REQUIRED | DS_BACKGROUND_ONLY + | DS_IP_REQUIRED | DS_KDC_REQUIRED | DS_TIMESERV_REQUIRED | DS_WRITABLE_REQUIRED + | DS_GOOD_TIMESERV_PREFERRED | DS_AVOID_SELF | DS_ONLY_LDAP_NEEDED | DS_IS_FLAT_NAME + | DS_IS_DNS_NAME | DS_TRY_NEXTCLOSEST_SITE | DS_DIRECTORY_SERVICE_6_REQUIRED + | DS_DIRECTORY_SERVICE_8_REQUIRED | DS_DIRECTORY_SERVICE_9_REQUIRED + | DS_DIRECTORY_SERVICE_10_REQUIRED | DS_WEB_SERVICE_REQUIRED | DS_RETURN_FLAT_NAME + | DS_RETURN_DNS_NAME; +STRUCT!{struct DOMAIN_CONTROLLER_INFOA { + DomainControllerName: LPSTR, + DomainControllerAddress: LPSTR, + DomainControllerAddressType: ULONG, + DomainGuid: GUID, + DomainName: LPSTR, + DnsForestName: LPSTR, + Flags: ULONG, + DcSiteName: LPSTR, + ClientSiteName: LPSTR, +}} +pub type PDOMAIN_CONTROLLER_INFOA = *mut DOMAIN_CONTROLLER_INFOA; +STRUCT!{struct DOMAIN_CONTROLLER_INFOW { + DomainControllerName: LPWSTR, + DomainControllerAddress: LPWSTR, + DomainControllerAddressType: ULONG, + DomainGuid: GUID, + DomainName: LPWSTR, + DnsForestName: LPWSTR, + Flags: ULONG, + DcSiteName: LPWSTR, + ClientSiteName: LPWSTR, +}} +pub type PDOMAIN_CONTROLLER_INFOW = *mut DOMAIN_CONTROLLER_INFOW; +pub const DS_INET_ADDRESS: ULONG = 1; +pub const DS_NETBIOS_ADDRESS: ULONG = 2; +pub const DS_PDC_FLAG: ULONG = 0x00000001; +pub const DS_GC_FLAG: ULONG = 0x00000004; +pub const DS_LDAP_FLAG: ULONG = 0x00000008; +pub const DS_DS_FLAG: ULONG = 0x00000010; +pub const DS_KDC_FLAG: ULONG = 0x00000020; +pub const DS_TIMESERV_FLAG: ULONG = 0x00000040; +pub const DS_CLOSEST_FLAG: ULONG = 0x00000080; +pub const DS_WRITABLE_FLAG: ULONG = 0x00000100; +pub const DS_GOOD_TIMESERV_FLAG: ULONG = 0x00000200; +pub const DS_NDNC_FLAG: ULONG = 0x00000400; +pub const DS_SELECT_SECRET_DOMAIN_6_FLAG: ULONG = 0x00000800; +pub const DS_FULL_SECRET_DOMAIN_6_FLAG: ULONG = 0x00001000; +pub const DS_WS_FLAG: ULONG = 0x00002000; +pub const DS_DS_8_FLAG: ULONG = 0x00004000; +pub const DS_DS_9_FLAG: ULONG = 0x00008000; +pub const DS_DS_10_FLAG: ULONG = 0x00010000; +pub const DS_PING_FLAGS: ULONG = 0x000FFFFF; +pub const DS_DNS_CONTROLLER_FLAG: ULONG = 0x20000000; +pub const DS_DNS_DOMAIN_FLAG: ULONG = 0x40000000; +pub const DS_DNS_FOREST_FLAG: ULONG = 0x80000000; +extern "system" { + pub fn DsGetDcNameA( + ComputerName: LPCSTR, + DomainName: LPCSTR, + DomainGuid: *mut GUID, + SiteName: LPCSTR, + Flags: ULONG, + DomainControllerInfo: *mut PDOMAIN_CONTROLLER_INFOA, + ) -> DWORD; + pub fn DsGetDcNameW( + ComputerName: LPCWSTR, + DomainName: LPCWSTR, + DomainGuid: *mut GUID, + SiteName: LPCWSTR, + Flags: ULONG, + DomainControllerInfo: *mut PDOMAIN_CONTROLLER_INFOW, + ) -> DWORD; + pub fn DsGetSiteNameA( + ComputerName: LPCSTR, + SiteName: *mut LPSTR, + ) -> DWORD; + pub fn DsGetSiteNameW( + ComputerName: LPCWSTR, + SiteName: *mut LPWSTR, + ) -> DWORD; + pub fn DsValidateSubnetNameW( + SubnetName: LPCWSTR, + ) -> DWORD; + pub fn DsValidateSubnetNameA( + SubnetName: LPCSTR, + ) -> DWORD; + pub fn DsAddressToSiteNamesW( + ComputerName: LPCWSTR, + EntryCount: DWORD, + SocketAddresses: PSOCKET_ADDRESS, + SiteNames: *mut *mut LPWSTR, + ) -> DWORD; + pub fn DsAddressToSiteNamesA( + ComputerName: LPCSTR, + EntryCount: DWORD, + SocketAddresses: PSOCKET_ADDRESS, + SiteNames: *mut *mut LPSTR, + ) -> DWORD; + pub fn DsAddressToSiteNamesExW( + ComputerName: LPCWSTR, + EntryCount: DWORD, + SocketAddresses: PSOCKET_ADDRESS, + SiteNames: *mut *mut LPWSTR, + SubnetNames: *mut *mut LPWSTR, + ) -> DWORD; + pub fn DsAddressToSiteNamesExA( + ComputerName: LPCSTR, + EntryCount: DWORD, + SocketAddresses: PSOCKET_ADDRESS, + SiteNames: *mut *mut LPSTR, + SubnetNames: *mut *mut LPSTR, + ) -> DWORD; +} +pub const DS_DOMAIN_IN_FOREST: ULONG = 0x0001; +pub const DS_DOMAIN_DIRECT_OUTBOUND: ULONG = 0x0002; +pub const DS_DOMAIN_TREE_ROOT: ULONG = 0x0004; +pub const DS_DOMAIN_PRIMARY: ULONG = 0x0008; +pub const DS_DOMAIN_NATIVE_MODE: ULONG = 0x0010; +pub const DS_DOMAIN_DIRECT_INBOUND: ULONG = 0x0020; +pub const DS_DOMAIN_VALID_FLAGS: ULONG = DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND + | DS_DOMAIN_TREE_ROOT | DS_DOMAIN_PRIMARY | DS_DOMAIN_NATIVE_MODE | DS_DOMAIN_DIRECT_INBOUND; +STRUCT!{struct DS_DOMAIN_TRUSTSW { + NetbiosDomainName: LPWSTR, + DnsDomainName: LPWSTR, + Flags: ULONG, + ParentIndex: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, + DomainSid: PSID, + DomainGuid: GUID, +}} +pub type PDS_DOMAIN_TRUSTSW = *mut DS_DOMAIN_TRUSTSW; +STRUCT!{struct DS_DOMAIN_TRUSTSA { + NetbiosDomainName: LPSTR, + DnsDomainName: LPSTR, + Flags: ULONG, + ParentIndex: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, + DomainSid: PSID, + DomainGuid: GUID, +}} +pub type PDS_DOMAIN_TRUSTSA = *mut DS_DOMAIN_TRUSTSA; +extern "system" { + pub fn DsEnumerateDomainTrustsW( + ServerName: LPWSTR, + Flags: ULONG, + Domains: *mut PDS_DOMAIN_TRUSTSW, + DomainCount: PULONG, + ) -> DWORD; + pub fn DsEnumerateDomainTrustsA( + ServerName: LPSTR, + Flags: ULONG, + Domains: *mut PDS_DOMAIN_TRUSTSA, + DomainCount: PULONG, + ) -> DWORD; + pub fn DsGetForestTrustInformationW( + ServerName: LPCWSTR, + TrustedDomainName: LPCWSTR, + Flags: DWORD, + ForestTrustInfo: *mut PLSA_FOREST_TRUST_INFORMATION, + ) -> DWORD; + pub fn DsMergeForestTrustInformationW( + DomainName: LPCWSTR, + NewForestTrustInfo: PLSA_FOREST_TRUST_INFORMATION, + OldForestTrustInfo: PLSA_FOREST_TRUST_INFORMATION, + MergedForestTrustInfo: *mut PLSA_FOREST_TRUST_INFORMATION, + ) -> DWORD; + pub fn DsGetDcSiteCoverageW( + ServerName: LPCWSTR, + EntryCount: PULONG, + SiteNames: *mut *mut LPWSTR, + ) -> DWORD; + pub fn DsGetDcSiteCoverageA( + ServerName: LPCSTR, + EntryCount: PULONG, + SiteNames: *mut *mut LPSTR, + ) -> DWORD; + pub fn DsDeregisterDnsHostRecordsW( + ServerName: LPWSTR, + DnsDomainName: LPWSTR, + DomainGuid: *mut GUID, + DsaGuid: *mut GUID, + DnsHostName: LPWSTR, + ) -> DWORD; + pub fn DsDeregisterDnsHostRecordsA( + ServerName: LPSTR, + DnsDomainName: LPSTR, + DomainGuid: *mut GUID, + DsaGuid: *mut GUID, + DnsHostName: LPSTR, + ) -> DWORD; +} +pub const DS_ONLY_DO_SITE_NAME: ULONG = 0x01; +pub const DS_NOTIFY_AFTER_SITE_RECORDS: ULONG = 0x02; +pub const DS_OPEN_VALID_OPTION_FLAGS: ULONG = DS_ONLY_DO_SITE_NAME + | DS_NOTIFY_AFTER_SITE_RECORDS; +pub const DS_OPEN_VALID_FLAGS: ULONG = DS_FORCE_REDISCOVERY | DS_ONLY_LDAP_NEEDED + | DS_KDC_REQUIRED | DS_PDC_REQUIRED | DS_GC_SERVER_REQUIRED | DS_WRITABLE_REQUIRED; +extern "system" { + pub fn DsGetDcOpenW( + DnsName: LPCWSTR, + OptionFlags: ULONG, + SiteName: LPCWSTR, + DomainGuid: *mut GUID, + DnsForestName: LPCWSTR, + DcFlags: ULONG, + RetGetDcContext: PHANDLE, + ) -> DWORD; + pub fn DsGetDcOpenA( + DnsName: LPCSTR, + OptionFlags: ULONG, + SiteName: LPCSTR, + DomainGuid: *mut GUID, + DnsForestName: LPCSTR, + DcFlags: ULONG, + RetGetDcContext: PHANDLE, + ) -> DWORD; + pub fn DsGetDcNextA( + GetDcContextHandle: HANDLE, + SockAddressCount: PULONG, + SockAddresses: *mut LPSOCKET_ADDRESS, + DnsHostName: *mut LPSTR, + ) -> DWORD; + pub fn DsGetDcNextW( + GetDcContextHandle: HANDLE, + SockAddressCount: PULONG, + SockAddresses: *mut LPSOCKET_ADDRESS, + DnsHostName: *mut LPWSTR, + ) -> DWORD; + pub fn DsGetDcCloseW( + GetDcContextHandle: HANDLE, + ); +} diff --git a/winapi/src/um/dsound.rs b/winapi/src/um/dsound.rs new file mode 100644 index 000000000..9c23bbf53 --- /dev/null +++ b/winapi/src/um/dsound.rs @@ -0,0 +1,342 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! DSound procedure declarations, constant definitions and macros +use shared::guiddef::{GUID, LPCGUID, LPGUID}; +use shared::minwindef::{DWORD, LPDWORD, LPLONG, LPVOID}; +use shared::windef::HWND; +use shared::winerror::{E_FAIL, S_OK}; +use um::mmsystem::{LPCWAVEFORMATEX, LPWAVEFORMATEX}; +use um::unknwnbase::{IUnknown, IUnknownVtbl, LPUNKNOWN}; +use um::winnt::{HRESULT, LONG}; +DEFINE_GUID!{CLSID_DirectSound, + 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} +DEFINE_GUID!{CLSID_DirectSound8, + 0x3901cc3f, 0x84b5, 0x4fa4, 0xba, 0x35, 0xaa, 0x81, 0x72, 0xb8, 0xa0, 0x9b} +DEFINE_GUID!{CLSID_DirectSoundCapture, + 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16} +DEFINE_GUID!{CLSID_DirectSoundCapture8, + 0xe4bcac13, 0x7f99, 0x4908, 0x9a, 0x8e, 0x74, 0xe3, 0xbf, 0x24, 0xb6, 0xe1} +DEFINE_GUID!{CLSID_DirectSoundFullDuplex, + 0xfea4300c, 0x7959, 0x4147, 0xb2, 0x6a, 0x23, 0x77, 0xb9, 0xe7, 0xa9, 0x1d} +DEFINE_GUID!{DSDEVID_DefaultPlayback, + 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03} +DEFINE_GUID!{DSDEVID_DefaultCapture, + 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03} +DEFINE_GUID!{DSDEVID_DefaultVoicePlayback, + 0xdef00002, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03} +DEFINE_GUID!{DSDEVID_DefaultVoiceCapture, + 0xdef00003, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03} +STRUCT!{struct DSCAPS { + dwSize: DWORD, + dwFlags: DWORD, + dwMinSecondarySampleRate: DWORD, + dwMaxSecondarySampleRate: DWORD, + dwPrimaryBuffers: DWORD, + dwMaxHwMixingAllBuffers: DWORD, + dwMaxHwMixingStaticBuffers: DWORD, + dwMaxHwMixingStreamingBuffers: DWORD, + dwFreeHwMixingAllBuffers: DWORD, + dwFreeHwMixingStaticBuffers: DWORD, + dwFreeHwMixingStreamingBuffers: DWORD, + dwMaxHw3DAllBuffers: DWORD, + dwMaxHw3DStaticBuffers: DWORD, + dwMaxHw3DStreamingBuffers: DWORD, + dwFreeHw3DAllBuffers: DWORD, + dwFreeHw3DStaticBuffers: DWORD, + dwFreeHw3DStreamingBuffers: DWORD, + dwTotalHwMemBytes: DWORD, + dwFreeHwMemBytes: DWORD, + dwMaxContigFreeHwMemBytes: DWORD, + dwUnlockTransferRateHwBuffers: DWORD, + dwPlayCpuOverheadSwBuffers: DWORD, + dwReserved1: DWORD, + dwReserved2: DWORD, +}} +pub type LPDSCAPS = *mut DSCAPS; +STRUCT!{struct DSBCAPS { + dwSize: DWORD, + dwFlags: DWORD, + dwBufferBytes: DWORD, + dwUnlockTransferRate: DWORD, + dwPlayCpuOverhead: DWORD, +}} +pub type LPDSBCAPS = *mut DSBCAPS; +STRUCT!{struct DSBUFFERDESC { + dwSize: DWORD, + dwFlags: DWORD, + dwBufferBytes: DWORD, + dwReserved: DWORD, + lpwfxFormat: LPWAVEFORMATEX, + guid3DAlgorithm: GUID, +}} +pub type LPCDSBUFFERDESC = *const DSBUFFERDESC; +RIDL!{#[uuid(0x279afa85, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60)] +interface IDirectSoundBuffer(IDirectSoundBufferVtbl): IUnknown(IUnknownVtbl) { + fn GetCaps( + pDSBufferCaps: LPDSBCAPS, + ) -> HRESULT, + fn GetCurrentPosition( + pdwCurrentPlayCursor: LPDWORD, + pdwCurrentWriteCursor: LPDWORD, + ) -> HRESULT, + fn GetFormat( + pwfxFormat: LPWAVEFORMATEX, + dwSizeAllocated: DWORD, + pdwSizeWritten: LPDWORD, + ) -> HRESULT, + fn GetVolume( + plVolume: LPLONG, + ) -> HRESULT, + fn GetPan( + plPan: LPLONG, + ) -> HRESULT, + fn GetFrequency( + pdwFrequency: LPDWORD, + ) -> HRESULT, + fn GetStatus( + pdwStatus: LPDWORD, + ) -> HRESULT, + fn Initialize( + pDirectSound: LPDIRECTSOUND, + pcDSBufferDesc: LPCDSBUFFERDESC, + ) -> HRESULT, + fn Lock( + dwOffset: DWORD, + dwBytes: DWORD, + ppvAudioPtr1: *mut LPVOID, + pdwAudioBytes1: LPDWORD, + ppvAudioPtr2: *mut LPVOID, + pdwAudioBytes2: LPDWORD, + dwFlags: DWORD, + ) -> HRESULT, + fn Play( + dwReserved1: DWORD, + dwPriority: DWORD, + dwFlags: DWORD, + ) -> HRESULT, + fn SetCurrentPosition( + dwNewPosition: DWORD, + ) -> HRESULT, + fn SetFormat( + pcfxFormat: LPCWAVEFORMATEX, + ) -> HRESULT, + fn SetVolume( + lVolume: LONG, + ) -> HRESULT, + fn SetPan( + lPan: LONG, + ) -> HRESULT, + fn SetFrequency( + dwFrequency: DWORD, + ) -> HRESULT, + fn Stop() -> HRESULT, + fn Unlock( + pvAudioPtr1: LPVOID, + dwAudioBytes1: DWORD, + pvAudioPtr2: LPVOID, + dwAudioBytes2: DWORD, + ) -> HRESULT, + fn Restore() -> HRESULT, +}} +pub type LPDIRECTSOUNDBUFFER = *mut IDirectSoundBuffer; +DEFINE_GUID!{IID_IReferenceClock, + 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} +DEFINE_GUID!{IID_IDirectSound, + 0x279afa83, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +RIDL!{#[uuid(0x279afa83, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60)] +interface IDirectSound(IDirectSoundVtbl): IUnknown(IUnknownVtbl) { + fn CreateSoundBuffer( + pcDSBufferDesc: LPCDSBUFFERDESC, + ppDSBuffer: *mut LPDIRECTSOUNDBUFFER, + pUnkOuter: LPUNKNOWN, + ) -> HRESULT, + fn GetCaps( + pDSCaps: LPDSCAPS, + ) -> HRESULT, + fn DuplicateSoundBuffer( + pDSBufferOriginal: LPDIRECTSOUNDBUFFER, + ppDSBufferDuplicate: *mut LPDIRECTSOUNDBUFFER, + ) -> HRESULT, + fn SetCooperativeLevel( + hWnd: HWND, + dwLevel: DWORD, + ) -> HRESULT, + fn Compact() -> HRESULT, + fn GetSpeakerConfig( + pdwSpeakerConfig: LPDWORD, + ) -> HRESULT, + fn SetSpeakerConfig( + dwSpeakerConfig: DWORD, + ) -> HRESULT, + fn Initialize( + pcGuidDevice: LPCGUID, + ) -> HRESULT, +}} +pub type LPDIRECTSOUND = *mut IDirectSound; +DEFINE_GUID!{IID_IDirectSound8, + 0xc50a7e93, 0xf395, 0x4834, 0x9e, 0xf6, 0x7f, 0xa9, 0x9d, 0xe5, 0x09, 0x66} +DEFINE_GUID!{IID_IDirectSoundBuffer, + 0x279afa85, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectSoundBuffer8, + 0x6825a449, 0x7524, 0x4d82, 0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e} +DEFINE_GUID!{GUID_All_Objects, + 0xaa114de5, 0xc262, 0x4169, 0xa1, 0xc8, 0x23, 0xd6, 0x98, 0xcc, 0x73, 0xb5} +DEFINE_GUID!{IID_IDirectSound3DListener, + 0x279afa84, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectSound3DBuffer, + 0x279afa86, 0x4981, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectSoundCapture, + 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16} +DEFINE_GUID!{IID_IDirectSoundCaptureBuffer, + 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16} +DEFINE_GUID!{IID_IDirectSoundCaptureBuffer8, + 0x00990df4, 0x0dbb, 0x4872, 0x83, 0x3e, 0x6d, 0x30, 0x3e, 0x80, 0xae, 0xb6} +DEFINE_GUID!{IID_IDirectSoundNotify, + 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16} +DEFINE_GUID!{IID_IKsPropertySet, + 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93} +DEFINE_GUID!{IID_IDirectSoundFXGargle, + 0xd616f352, 0xd622, 0x11ce, 0xaa, 0xc5, 0x00, 0x20, 0xaf, 0x0b, 0x99, 0xa3} +DEFINE_GUID!{IID_IDirectSoundFXChorus, + 0x880842e3, 0x145f, 0x43e6, 0xa9, 0x34, 0xa7, 0x18, 0x06, 0xe5, 0x05, 0x47} +DEFINE_GUID!{IID_IDirectSoundFXFlanger, + 0x903e9878, 0x2c92, 0x4072, 0x9b, 0x2c, 0xea, 0x68, 0xf5, 0x39, 0x67, 0x83} +DEFINE_GUID!{IID_IDirectSoundFXEcho, + 0x8bd28edf, 0x50db, 0x4e92, 0xa2, 0xbd, 0x44, 0x54, 0x88, 0xd1, 0xed, 0x42} +DEFINE_GUID!{IID_IDirectSoundFXDistortion, + 0x8ecf4326, 0x455f, 0x4d8b, 0xbd, 0xa9, 0x8d, 0x5d, 0x3e, 0x9e, 0x3e, 0x0b} +DEFINE_GUID!{IID_IDirectSoundFXCompressor, + 0x4bbd1154, 0x62f6, 0x4e2c, 0xa1, 0x5c, 0xd3, 0xb6, 0xc4, 0x17, 0xf7, 0xa0} +DEFINE_GUID!{IID_IDirectSoundFXParamEq, + 0xc03ca9fe, 0xfe90, 0x4204, 0x80, 0x78, 0x82, 0x33, 0x4c, 0xd1, 0x77, 0xda} +DEFINE_GUID!{IID_IDirectSoundFXI3DL2Reverb, + 0x4b166a6a, 0x0d66, 0x43f3, 0x80, 0xe3, 0xee, 0x62, 0x80, 0xde, 0xe1, 0xa4} +DEFINE_GUID!{IID_IDirectSoundFXWavesReverb, + 0x46858c3a, 0x0dc6, 0x45e3, 0xb7, 0x60, 0xd4, 0xee, 0xf1, 0x6c, 0xb3, 0x25} +DEFINE_GUID!{IID_IDirectSoundCaptureFXAec, + 0xad74143d, 0x903d, 0x4ab7, 0x80, 0x66, 0x28, 0xd3, 0x63, 0x03, 0x6d, 0x65} +DEFINE_GUID!{IID_IDirectSoundCaptureFXNoiseSuppress, + 0xed311e41, 0xfbae, 0x4175, 0x96, 0x25, 0xcd, 0x08, 0x54, 0xf6, 0x93, 0xca} +DEFINE_GUID!{IID_IDirectSoundFullDuplex, + 0xedcb4c7a, 0xdaab, 0x4216, 0xa4, 0x2e, 0x6c, 0x50, 0x59, 0x6d, 0xdc, 0x1d} +pub const DS_OK: HRESULT = S_OK; +pub const DSERR_GENERIC: HRESULT = E_FAIL; +pub const DSSCL_NORMAL: DWORD = 0x00000001; +pub const DSSCL_PRIORITY: DWORD = 0x00000002; +pub const DSSCL_EXCLUSIVE: DWORD = 0x00000003; +pub const DSSCL_WRITEPRIMARY: DWORD = 0x00000004; +pub const DSBCAPS_PRIMARYBUFFER: DWORD = 0x00000001; +pub const DSBCAPS_STATIC: DWORD = 0x00000002; +pub const DSBCAPS_LOCHARDWARE: DWORD = 0x00000004; +pub const DSBCAPS_LOCSOFTWARE: DWORD = 0x00000008; +pub const DSBCAPS_CTRL3D: DWORD = 0x00000010; +pub const DSBCAPS_CTRLFREQUENCY: DWORD = 0x00000020; +pub const DSBCAPS_CTRLPAN: DWORD = 0x00000040; +pub const DSBCAPS_CTRLVOLUME: DWORD = 0x00000080; +pub const DSBCAPS_CTRLPOSITIONNOTIFY: DWORD = 0x00000100; +pub const DSBCAPS_CTRLFX: DWORD = 0x00000200; +pub const DSBCAPS_STICKYFOCUS: DWORD = 0x00004000; +pub const DSBCAPS_GLOBALFOCUS: DWORD = 0x00008000; +pub const DSBCAPS_GETCURRENTPOSITION2: DWORD = 0x00010000; +pub const DSBCAPS_MUTE3DATMAXDISTANCE: DWORD = 0x00020000; +pub const DSBCAPS_LOCDEFER: DWORD = 0x00040000; +pub const DSBCAPS_TRUEPLAYPOSITION: DWORD = 0x00080000; +pub const DSBPLAY_LOOPING: DWORD = 0x00000001; +pub const DSBPLAY_LOCHARDWARE: DWORD = 0x00000002; +pub const DSBPLAY_LOCSOFTWARE: DWORD = 0x00000004; +pub const DSBPLAY_TERMINATEBY_TIME: DWORD = 0x00000008; +pub const DSBPLAY_TERMINATEBY_DISTANCE: DWORD = 0x000000010; +pub const DSBPLAY_TERMINATEBY_PRIORITY: DWORD = 0x000000020; +extern "system" { + pub fn DirectSoundCreate( + pcGuidDevice: LPCGUID, + ppDS: *mut LPDIRECTSOUND, + pUnkOuter: LPUNKNOWN, + ) -> HRESULT; + // pub fn DirectSoundEnumerateA( + // pDSEnumCallback: LPDSENUMCALLBACKA, + // pContext: LPVOID, + // ) -> HRESULT; + // pub fn DirectSoundEnumerateW( + // pDSEnumCallback: LPDSENUMCALLBACKW, + // pContext: LPVOID, + // ) -> HRESULT; + // pub fn DirectSoundCaptureCreate( + // pcGuidDevice: LPCGUID, + // ppDSC: *mut LPDIRECTSOUNDCAPTURE, + // pUnkOuter: LPUNKNOWN, + // ) -> HRESULT; + // pub fn DirectSoundCaptureEnumerateA( + // pDSEnumCallback: LPDSENUMCALLBACKA, + // pContext: LPVOID, + // ) -> HRESULT; + // pub fn DirectSoundCaptureEnumerateW( + // pDSEnumCallback: LPDSENUMCALLBACKW, + // pContext: LPVOID, + // ) -> HRESULT; + // pub fn DirectSoundCreate8( + // pcGuidDevice: LPCGUID, + // ppDS8: *mut LPDIRECTSOUND8, + // pUnkOuter: LPUNKNOWN, + // ) -> HRESULT; + // pub fn DirectSoundCaptureCreate8( + // pcGuidDevice: LPCGUID, + // ppDSC8: *mut LPDIRECTSOUNDCAPTURE8, + // pUnkOuter: LPUNKNOWN, + // ) -> HRESULT; + // pub fn DirectSoundFullDuplexCreate( + // pcGuidCaptureDevice: LPCGUID, + // pcGuidRenderDevice: LPCGUID, + // pcDSCBufferDesc: LPCDSCBUFFERDESC, + // pcDSBufferDesc: LPCDSBUFFERDESC, + // hWnd: HWND, + // dwLevel: DWORD, + // ppDSFD: *mut LPDIRECTSOUNDFULLDUPLEX, + // ppDSCBuffer8: *mut LPDIRECTSOUNDCAPTUREBUFFER8, + // ppDSBuffer8: *mut LPDIRECTSOUNDBUFFER8, + // pUnkOuter: LPUNKNOWN, + // ) -> HRESULT; + pub fn GetDeviceID( + pGuidSrc: LPCGUID, + pGuidDest: LPGUID, + ) -> HRESULT; +} +DEFINE_GUID!{DS3DALG_NO_VIRTUALIZATION, + 0xc241333f, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca} +DEFINE_GUID!{DS3DALG_HRTF_FULL, + 0xc2413340, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca} +DEFINE_GUID!{DS3DALG_HRTF_LIGHT, + 0xc2413342, 0x1c1b, 0x11d2, 0x94, 0xf5, 0x00, 0xc0, 0x4f, 0xc2, 0x8a, 0xca} +DEFINE_GUID!{GUID_DSFX_STANDARD_GARGLE, + 0xdafd8210, 0x5711, 0x4b91, 0x9f, 0xe3, 0xf7, 0x5b, 0x7a, 0xe2, 0x79, 0xbf} +DEFINE_GUID!{GUID_DSFX_STANDARD_CHORUS, + 0xefe6629c, 0x81f7, 0x4281, 0xbd, 0x91, 0xc9, 0xd6, 0x04, 0xa9, 0x5a, 0xf6} +DEFINE_GUID!{GUID_DSFX_STANDARD_FLANGER, + 0xefca3d92, 0xdfd8, 0x4672, 0xa6, 0x03, 0x74, 0x20, 0x89, 0x4b, 0xad, 0x98} +DEFINE_GUID!{GUID_DSFX_STANDARD_ECHO, + 0xef3e932c, 0xd40b, 0x4f51, 0x8c, 0xcf, 0x3f, 0x98, 0xf1, 0xb2, 0x9d, 0x5d} +DEFINE_GUID!{GUID_DSFX_STANDARD_DISTORTION, + 0xef114c90, 0xcd1d, 0x484e, 0x96, 0xe5, 0x09, 0xcf, 0xaf, 0x91, 0x2a, 0x21} +DEFINE_GUID!{GUID_DSFX_STANDARD_COMPRESSOR, + 0xef011f79, 0x4000, 0x406d, 0x87, 0xaf, 0xbf, 0xfb, 0x3f, 0xc3, 0x9d, 0x57} +DEFINE_GUID!{GUID_DSFX_STANDARD_PARAMEQ, + 0x120ced89, 0x3bf4, 0x4173, 0xa1, 0x32, 0x3c, 0xb4, 0x06, 0xcf, 0x32, 0x31} +DEFINE_GUID!{GUID_DSFX_STANDARD_I3DL2REVERB, + 0xef985e71, 0xd5c7, 0x42d4, 0xba, 0x4d, 0x2d, 0x07, 0x3e, 0x2e, 0x96, 0xf4} +DEFINE_GUID!{GUID_DSFX_WAVES_REVERB, + 0x87fc0268, 0x9a55, 0x4360, 0x95, 0xaa, 0x00, 0x4a, 0x1d, 0x9d, 0xe2, 0x6c} +DEFINE_GUID!{GUID_DSCFX_CLASS_AEC, + 0xbf963d80, 0xc559, 0x11d0, 0x8a, 0x2b, 0x00, 0xa0, 0xc9, 0x25, 0x5a, 0xc1} +DEFINE_GUID!{GUID_DSCFX_MS_AEC, + 0xcdebb919, 0x379a, 0x488a, 0x87, 0x65, 0xf5, 0x3c, 0xfd, 0x36, 0xde, 0x40} +DEFINE_GUID!{GUID_DSCFX_SYSTEM_AEC, + 0x1c22c56d, 0x9879, 0x4f5b, 0xa3, 0x89, 0x27, 0x99, 0x6d, 0xdc, 0x28, 0x10} +DEFINE_GUID!{GUID_DSCFX_CLASS_NS, + 0xe07f903f, 0x62fd, 0x4e60, 0x8c, 0xdd, 0xde, 0xa7, 0x23, 0x66, 0x65, 0xb5} +DEFINE_GUID!{GUID_DSCFX_MS_NS, + 0x11c5c73b, 0x66e9, 0x4ba1, 0xa0, 0xba, 0xe8, 0x14, 0xc6, 0xee, 0xd9, 0x2d} +DEFINE_GUID!{GUID_DSCFX_SYSTEM_NS, + 0x5ab0882e, 0x7274, 0x4516, 0x87, 0x7d, 0x4e, 0xee, 0x99, 0xba, 0x4f, 0xd0} diff --git a/winapi/src/um/dsrole.rs b/winapi/src/um/dsrole.rs new file mode 100644 index 000000000..b644d7994 --- /dev/null +++ b/winapi/src/um/dsrole.rs @@ -0,0 +1,66 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Contains public interfaces to query the network roles of workstations, servers, and DCs +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, PBYTE, ULONG}; +use um::winnt::{LPCWSTR, LPWSTR, PVOID}; +ENUM!{enum DSROLE_MACHINE_ROLE { + DsRole_RoleStandaloneWorkstation, + DsRole_RoleMemberWorkstation, + DsRole_RoleStandaloneServer, + DsRole_RoleMemberServer, + DsRole_RoleBackupDomainController, + DsRole_RolePrimaryDomainController, +}} +ENUM!{enum DSROLE_SERVER_STATE { + DsRoleServerUnknown = 0, + DsRoleServerPrimary, + DsRoleServerBackup, +}} +pub type PDSROLE_SERVER_STATE = *mut DSROLE_SERVER_STATE; +ENUM!{enum DSROLE_PRIMARY_DOMAIN_INFO_LEVEL { + DsRolePrimaryDomainInfoBasic = 1, + DsRoleUpgradeStatus, + DsRoleOperationState, +}} +pub const DSROLE_PRIMARY_DS_RUNNING: ULONG = 0x00000001; +pub const DSROLE_PRIMARY_DS_MIXED_MODE: ULONG = 0x00000002; +pub const DSROLE_UPGRADE_IN_PROGRESS: ULONG = 0x00000004; +pub const DSROLE_PRIMARY_DS_READONLY: ULONG = 0x00000008; +pub const DSROLE_PRIMARY_DOMAIN_GUID_PRESENT: ULONG = 0x01000000; +STRUCT!{struct DSROLE_PRIMARY_DOMAIN_INFO_BASIC { + MachineRole: DSROLE_MACHINE_ROLE, + Flags: ULONG, + DomainNameFlat: LPWSTR, + DomainNameDns: LPWSTR, + DomainForestName: LPWSTR, + DomainGuid: GUID, +}} +pub type PDSROLE_PRIMARY_DOMAIN_INFO_BASIC = *mut DSROLE_PRIMARY_DOMAIN_INFO_BASIC; +STRUCT!{struct DSROLE_UPGRADE_STATUS_INFO { + OperationState: ULONG, + PreviousServerState: DSROLE_SERVER_STATE, +}} +pub type PDSROLE_UPGRADE_STATUS_INFO = *mut DSROLE_UPGRADE_STATUS_INFO; +ENUM!{enum DSROLE_OPERATION_STATE { + DsRoleOperationIdle = 0, + DsRoleOperationActive, + DsRoleOperationNeedReboot, +}} +STRUCT!{struct DSROLE_OPERATION_STATE_INFO { + OperationState: DSROLE_OPERATION_STATE, +}} +pub type PDSROLE_OPERATION_STATE_INFO = *mut DSROLE_OPERATION_STATE_INFO; +extern "system" { + pub fn DsRoleGetPrimaryDomainInformation( + lpServer: LPCWSTR, + InfoLevel: DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, + Buffer: *mut PBYTE, + ) -> DWORD; + pub fn DsRoleFreeMemory( + Buffer: PVOID, + ); +} diff --git a/winapi/src/um/dvp.rs b/winapi/src/um/dvp.rs new file mode 100644 index 000000000..5760732e0 --- /dev/null +++ b/winapi/src/um/dvp.rs @@ -0,0 +1,25 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_IDDVideoPortContainer, + 0x6c142760, 0xa733, 0x11ce, 0xa5, 0x21, 0x00, 0x20, 0xaf, 0x0b, 0xe5, 0x60} +DEFINE_GUID!{IID_IDirectDrawVideoPort, + 0xb36d93e0, 0x2b43, 0x11cf, 0xa2, 0xde, 0x00, 0xaa, 0x00, 0xb9, 0x33, 0x56} +DEFINE_GUID!{IID_IDirectDrawVideoPortNotify, + 0xa655fb94, 0x0589, 0x4e57, 0xb3, 0x33, 0x56, 0x7a, 0x89, 0x46, 0x8c, 0x88} +DEFINE_GUID!{DDVPTYPE_E_HREFH_VREFH, + 0x54f39980, 0xda60, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_E_HREFH_VREFL, + 0x92783220, 0xda60, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_E_HREFL_VREFH, + 0xa07a02e0, 0xda60, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_E_HREFL_VREFL, + 0xe09c77e0, 0xda60, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_CCIR656, + 0xfca326a0, 0xda60, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_BROOKTREE, + 0x1352a560, 0xda61, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} +DEFINE_GUID!{DDVPTYPE_PHILIPS, + 0x332cf160, 0xda61, 0x11cf, 0x9b, 0x06, 0x00, 0xa0, 0xc9, 0x03, 0xa3, 0xb8} diff --git a/winapi/src/um/dwmapi.rs b/winapi/src/um/dwmapi.rs new file mode 100644 index 000000000..475473f9a --- /dev/null +++ b/winapi/src/um/dwmapi.rs @@ -0,0 +1,295 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Procedure declarations, constant definitions, and macros for the NLS component. +use shared::basetsd::UINT32; +use shared::minwindef::{ + BOOL, BYTE, DWORD, HRGN, INT, LPARAM, LPCVOID, LPVOID, LRESULT, UINT, WPARAM +}; +use shared::windef::{HBITMAP, HWND, POINT, PSIZE, RECT}; +use um::uxtheme::MARGINS; +use um::winnt::{HANDLE, HRESULT, ULONGLONG}; +pub const DWM_BB_ENABLE: DWORD = 0x00000001; +pub const DWM_BB_BLURREGION: DWORD = 0x00000002; +pub const DWM_BB_TRANSITIONONMAXIMIZED: DWORD = 0x00000004; +STRUCT!{#[repr(packed)] struct DWM_BLURBEHIND { + dwFlags: DWORD, + fEnable: BOOL, + hRgnBlur: HRGN, + fTransitionOnMaximized: BOOL, +}} +ENUM!{enum DWMWINDOWATTRIBUTE { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY = 2, + DWMWA_TRANSITIONS_FORCEDISABLED = 3, + DWMWA_ALLOW_NCPAINT = 4, + DWMWA_CAPTION_BUTTON_BOUNDS = 5, + DWMWA_NONCLIENT_RTL_LAYOUT = 6, + DWMWA_FORCE_ICONIC_REPRESENTATION = 7, + DWMWA_FLIP3D_POLICY = 8, + DWMWA_EXTENDED_FRAME_BOUNDS = 9, + DWMWA_HAS_ICONIC_BITMAP = 10, + DWMWA_DISALLOW_PEEK = 11, + DWMWA_EXCLUDED_FROM_PEEK = 12, + DWMWA_CLOAK = 13, + DWMWA_CLOAKED = 14, + DWMWA_FREEZE_REPRESENTATION = 15, + DWMWA_LAST = 16, +}} +ENUM!{enum DWMNCRENDERINGPOLICY { + DWMNCRP_USEWINDOWSTYLE = 0, + DWMNCRP_DISABLED = 1, + DWMNCRP_ENABLED = 2, + DWMNCRP_LAST = 3, +}} +ENUM!{enum DWMFLIP3DWINDOWPOLICY { + DWMFLIP3D_DEFAULT = 0, + DWMFLIP3D_EXCLUDEBELOW = 1, + DWMFLIP3D_EXCLUDEABOVE = 2, + DWMFLIP3D_LAST = 3, +}} +pub const DWM_CLOAKED_APP: u32 = 0x00000001; +pub const DWM_CLOAKED_SHELL: u32 = 0x00000002; +pub const DWM_CLOAKED_INHERITED: u32 = 0x00000004; +pub type HTHUMBNAIL = HANDLE; +pub type PHTHUMBNAIL = *mut HTHUMBNAIL; +pub const DWM_TNP_RECTDESTINATION: DWORD = 0x00000001; +pub const DWM_TNP_RECTSOURCE: DWORD = 0x00000002; +pub const DWM_TNP_OPACITY: DWORD = 0x00000004; +pub const DWM_TNP_VISIBLE: DWORD = 0x00000008; +pub const DWM_TNP_SOURCECLIENTAREAONLY: DWORD = 0x00000010; +STRUCT!{#[repr(packed)] struct DWM_THUMBNAIL_PROPERTIES { + dwFlags: DWORD, + rcDestination: RECT, + rcSource: RECT, + opacity: BYTE, + fVisible: BOOL, + fSourceClientAreaOnly: BOOL, +}} +pub type PDWM_THUMBNAIL_PROPERTIES = *mut DWM_THUMBNAIL_PROPERTIES; +pub type DWM_FRAME_COUNT = ULONGLONG; +pub type QPC_TIME = ULONGLONG; +STRUCT!{#[repr(packed)] struct UNSIGNED_RATIO { + uiNumerator: UINT32, + uiDenominator: UINT32, +}} +STRUCT!{#[repr(packed)] struct DWM_TIMING_INFO { + cbSize: UINT32, + rateRefresh: UNSIGNED_RATIO, + qpcRefreshPeriod: QPC_TIME, + rateCompose: UNSIGNED_RATIO, + qpcVBlank: QPC_TIME, + cRefresh: DWM_FRAME_COUNT, + cDXRefresh: UINT, + qpcCompose: QPC_TIME, + cFrame: DWM_FRAME_COUNT, + cDXPresent: UINT, + cRefreshFrame: DWM_FRAME_COUNT, + cFrameSubmitted: DWM_FRAME_COUNT, + cDXPresentSubmitted: UINT, + cFrameConfirmed: DWM_FRAME_COUNT, + cDXPresentConfirmed: UINT, + cRefreshConfirmed: DWM_FRAME_COUNT, + cDXRefreshConfirmed: UINT, + cFramesLate: DWM_FRAME_COUNT, + cFramesOutstanding: UINT, + cFrameDisplayed: DWM_FRAME_COUNT, + qpcFrameDisplayed: QPC_TIME, + cRefreshFrameDisplayed: DWM_FRAME_COUNT, + cFrameComplete: DWM_FRAME_COUNT, + qpcFrameComplete: QPC_TIME, + cFramePending: DWM_FRAME_COUNT, + qpcFramePending: QPC_TIME, + cFramesDisplayed: DWM_FRAME_COUNT, + cFramesComplete: DWM_FRAME_COUNT, + cFramesPending: DWM_FRAME_COUNT, + cFramesAvailable: DWM_FRAME_COUNT, + cFramesDropped: DWM_FRAME_COUNT, + cFramesMissed: DWM_FRAME_COUNT, + cRefreshNextDisplayed: DWM_FRAME_COUNT, + cRefreshNextPresented: DWM_FRAME_COUNT, + cRefreshesDisplayed: DWM_FRAME_COUNT, + cRefreshesPresented: DWM_FRAME_COUNT, + cRefreshStarted: DWM_FRAME_COUNT, + cPixelsReceived: ULONGLONG, + cPixelsDrawn: ULONGLONG, + cBuffersEmpty: DWM_FRAME_COUNT, +}} +ENUM!{enum DWM_SOURCE_FRAME_SAMPLING { + DWM_SOURCE_FRAME_SAMPLING_POINT = 0, + DWM_SOURCE_FRAME_SAMPLING_COVERAGE = 1, + DWM_SOURCE_FRAME_SAMPLING_LAST = 2, +}} +// pub const c_DwmMaxQueuedBuffers: UINT = 8; +// pub const c_DwmMaxMonitors: UINT = 16; +// pub const c_DwmMaxAdapters: UINT = 16; +STRUCT!{#[repr(packed)] struct DWM_PRESENT_PARAMETERS { + cbSize: UINT32, + fQueue: BOOL, + cRefreshStart: DWM_FRAME_COUNT, + cBuffer: UINT, + fUseSourceRate: BOOL, + rateSource: UNSIGNED_RATIO, + cRefreshesPerFrame: UINT, + eSampling: DWM_SOURCE_FRAME_SAMPLING, +}} +// pub const DWM_FRAME_DURATION_DEFAULT: i32 = -1; +extern "system" { + pub fn DwmDefWindowProc( + hWnd: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + plResult: *mut LRESULT, + ) -> BOOL; + pub fn DwmEnableBlurBehindWindow( + hWnd: HWND, + pBlurBehind: *const DWM_BLURBEHIND, + ) -> HRESULT; +} +pub const DWM_EC_DISABLECOMPOSITION: UINT = 0; +pub const DWM_EC_ENABLECOMPOSITION: UINT = 1; +extern "system" { + pub fn DwmEnableComposition( + uCompositionAction: UINT, + ) -> HRESULT; + pub fn DwmEnableMMCSS( + fEnableMMCSS: BOOL, + ) -> HRESULT; + pub fn DwmExtendFrameIntoClientArea( + hWnd: HWND, + pMarInset: *const MARGINS, + ) -> HRESULT; + pub fn DwmGetColorizationColor( + pcrColorization: *mut DWORD, + pfOpaqueBlend: *mut BOOL, + ) -> HRESULT; + pub fn DwmGetCompositionTimingInfo( + hWnd: HWND, + pTimingInfo: *mut DWM_TIMING_INFO, + ) -> HRESULT; + pub fn DwmGetWindowAttribute( + hWnd: HWND, + dwAttribute: DWORD, + pvAttribute: LPVOID, + cbAttribute: DWORD, + ) -> HRESULT; + pub fn DwmIsCompositionEnabled( + pfEnabled: *mut BOOL, + ) -> HRESULT; + pub fn DwmModifyPreviousDxFrameDuration( + hwnd: HWND, + cRefreshes: INT, + fRelative: BOOL, + ) -> HRESULT; + pub fn DwmQueryThumbnailSourceSize( + hThumbnail: HTHUMBNAIL, + pSize: PSIZE, + ) -> HRESULT; + pub fn DwmRegisterThumbnail( + hwndDestination: HWND, + hwndSource: HWND, + phThumbnailId: PHTHUMBNAIL, + ) -> HRESULT; + pub fn DwmSetDxFrameDuration( + hwnd: HWND, + cRefreshes: INT, + ) -> HRESULT; + pub fn DwmSetPresentParameters( + hwnd: HWND, + pPresentParams: *mut DWM_PRESENT_PARAMETERS, + ) -> HRESULT; + pub fn DwmSetWindowAttribute( + hWnd: HWND, + dwAttribute: DWORD, + pvAttribute: LPCVOID, + cbAttribute: DWORD, + ) -> HRESULT; + pub fn DwmUnregisterThumbnail( + hThumbnailId: HTHUMBNAIL, + ) -> HRESULT; + pub fn DwmUpdateThumbnailProperties( + hThumbnailId: HTHUMBNAIL, + ptnProperties: *const DWM_THUMBNAIL_PROPERTIES, + ) -> HRESULT; +} +pub const DWM_SIT_DISPLAYFRAME: DWORD = 0x00000001; +extern "system" { + pub fn DwmSetIconicThumbnail( + hwnd: HWND, + hbmp: HBITMAP, + dwSITFlags: DWORD, + ) -> HRESULT; + pub fn DwmSetIconicLivePreviewBitmap( + hwnd: HWND, + hbmp: HBITMAP, + pptClient: *mut POINT, + dwSITFlags: DWORD, + ) -> HRESULT; + pub fn DwmInvalidateIconicBitmaps( + hwnd: HWND, + ) -> HRESULT; + // pub fn DwmAttachMilContent(hwnd: HWND) -> HRESULT; + // pub fn DwmDetachMilContent(hwnd: HWND) -> HRESULT; + pub fn DwmFlush() -> HRESULT; + // pub fn DwmGetGraphicsStreamTransformHint(); + // pub fn DwmGetGraphicsStreamClient(); + pub fn DwmGetTransportAttributes( + pfIsRemoting: *mut BOOL, + pfIsConnected: *mut BOOL, + pDwGeneration: *mut DWORD, + ) -> HRESULT; +} +ENUM!{enum DWMTRANSITION_OWNEDWINDOW_TARGET { + DWMTRANSITION_OWNEDWINDOW_NULL = -1i32 as u32, + DWMTRANSITION_OWNEDWINDOW_REPOSITION = 0, +}} +extern "system" { + pub fn DwmTransitionOwnedWindow( + hwnd: HWND, + target: DWMTRANSITION_OWNEDWINDOW_TARGET, + ) -> HRESULT; +} +ENUM!{enum GESTURE_TYPE { + GT_PEN_TAP = 0, + GT_PEN_DOUBLETAP = 1, + GT_PEN_RIGHTTAP = 2, + GT_PEN_PRESSANDHOLD = 3, + GT_PEN_PRESSANDHOLDABORT = 4, + GT_TOUCH_TAP = 5, + GT_TOUCH_DOUBLETAP = 6, + GT_TOUCH_RIGHTTAP = 7, + GT_TOUCH_PRESSANDHOLD = 8, + GT_TOUCH_PRESSANDHOLDABORT = 9, + GT_TOUCH_PRESSANDTAP = 10, +}} +extern "system" { + pub fn DwmRenderGesture( + gt: GESTURE_TYPE, + cContacts: UINT, + pdwPointerID: *const DWORD, + pPoints: *const POINT, + ) -> HRESULT; + pub fn DwmTetherContact( + dwPointerID: DWORD, + fEnable: BOOL, + ptTether: POINT, + ) -> HRESULT; +} +ENUM!{enum DWM_SHOWCONTACT { + DWMSC_DOWN = 0x00000001, + DWMSC_UP = 0x00000002, + DWMSC_DRAG = 0x00000004, + DWMSC_HOLD = 0x00000008, + DWMSC_PENBARREL = 0x00000010, + DWMSC_NONE = 0x00000000, + DWMSC_ALL = 0xFFFFFFFF, +}} +extern "system" { + pub fn DwmShowContact( + dwPointerID: DWORD, + eShowContact: DWM_SHOWCONTACT, + ) -> HRESULT; +} diff --git a/winapi/src/um/dwrite.rs b/winapi/src/um/dwrite.rs new file mode 100644 index 000000000..b21cd6f8d --- /dev/null +++ b/winapi/src/um/dwrite.rs @@ -0,0 +1,1477 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! DirectX Typography Services public API definitions. +use ctypes::c_void; +use shared::basetsd::{INT16, INT32, UINT16, UINT32, UINT64, UINT8}; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, BYTE, FILETIME, FLOAT}; +use shared::windef::{COLORREF, HDC, HMONITOR, RECT, SIZE}; +use shared::winerror::SEVERITY_ERROR; +use um::d2d1::ID2D1SimplifiedGeometrySink; +use um::dcommon::DWRITE_MEASURING_MODE; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wingdi::LOGFONTW; +use um::winnt::{HRESULT, WCHAR}; +ENUM!{enum DWRITE_FONT_FILE_TYPE { + DWRITE_FONT_FILE_TYPE_UNKNOWN, + DWRITE_FONT_FILE_TYPE_CFF, + DWRITE_FONT_FILE_TYPE_TRUETYPE, + DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION, + DWRITE_FONT_FILE_TYPE_TYPE1_PFM, + DWRITE_FONT_FILE_TYPE_TYPE1_PFB, + DWRITE_FONT_FILE_TYPE_VECTOR, + DWRITE_FONT_FILE_TYPE_BITMAP, + DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION = DWRITE_FONT_FILE_TYPE_OPENTYPE_COLLECTION, +}} +ENUM!{enum DWRITE_FONT_FACE_TYPE { + DWRITE_FONT_FACE_TYPE_CFF, + DWRITE_FONT_FACE_TYPE_TRUETYPE, + DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, + DWRITE_FONT_FACE_TYPE_TYPE1, + DWRITE_FONT_FACE_TYPE_VECTOR, + DWRITE_FONT_FACE_TYPE_BITMAP, + DWRITE_FONT_FACE_TYPE_UNKNOWN, + DWRITE_FONT_FACE_TYPE_RAW_CFF, + DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION = DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, +}} +ENUM!{enum DWRITE_FONT_SIMULATIONS { + DWRITE_FONT_SIMULATIONS_NONE = 0x0000, + DWRITE_FONT_SIMULATIONS_BOLD = 0x0001, + DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002, +}} +ENUM!{enum DWRITE_FONT_WEIGHT { + DWRITE_FONT_WEIGHT_THIN = 100, + DWRITE_FONT_WEIGHT_EXTRA_LIGHT = 200, + DWRITE_FONT_WEIGHT_ULTRA_LIGHT = 200, + DWRITE_FONT_WEIGHT_LIGHT = 300, + DWRITE_FONT_WEIGHT_SEMI_LIGHT = 350, + DWRITE_FONT_WEIGHT_NORMAL = 400, + DWRITE_FONT_WEIGHT_REGULAR = 400, + DWRITE_FONT_WEIGHT_MEDIUM = 500, + DWRITE_FONT_WEIGHT_DEMI_BOLD = 600, + DWRITE_FONT_WEIGHT_SEMI_BOLD = 600, + DWRITE_FONT_WEIGHT_BOLD = 700, + DWRITE_FONT_WEIGHT_EXTRA_BOLD = 800, + DWRITE_FONT_WEIGHT_ULTRA_BOLD = 800, + DWRITE_FONT_WEIGHT_BLACK = 900, + DWRITE_FONT_WEIGHT_HEAVY = 900, + DWRITE_FONT_WEIGHT_EXTRA_BLACK = 950, + DWRITE_FONT_WEIGHT_ULTRA_BLACK = 950, +}} +ENUM!{enum DWRITE_FONT_STRETCH { + DWRITE_FONT_STRETCH_UNDEFINED = 0, + DWRITE_FONT_STRETCH_ULTRA_CONDENSED = 1, + DWRITE_FONT_STRETCH_EXTRA_CONDENSED = 2, + DWRITE_FONT_STRETCH_CONDENSED = 3, + DWRITE_FONT_STRETCH_SEMI_CONDENSED = 4, + DWRITE_FONT_STRETCH_NORMAL = 5, + DWRITE_FONT_STRETCH_MEDIUM = 5, + DWRITE_FONT_STRETCH_SEMI_EXPANDED = 6, + DWRITE_FONT_STRETCH_EXPANDED = 7, + DWRITE_FONT_STRETCH_EXTRA_EXPANDED = 8, + DWRITE_FONT_STRETCH_ULTRA_EXPANDED = 9, +}} +ENUM!{enum DWRITE_FONT_STYLE { + DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STYLE_OBLIQUE, + DWRITE_FONT_STYLE_ITALIC, +}} +ENUM!{enum DWRITE_INFORMATIONAL_STRING_ID { + DWRITE_INFORMATIONAL_STRING_NONE, + DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, + DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, + DWRITE_INFORMATIONAL_STRING_TRADEMARK, + DWRITE_INFORMATIONAL_STRING_MANUFACTURER, + DWRITE_INFORMATIONAL_STRING_DESIGNER, + DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, + DWRITE_INFORMATIONAL_STRING_DESCRIPTION, + DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL, + DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, + DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, + DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_PREFERRED_FAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES, + DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, + DWRITE_INFORMATIONAL_STRING_FULL_NAME, + DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, + DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, + DWRITE_INFORMATIONAL_STRING_WWS_FAMILY_NAME, + DWRITE_INFORMATIONAL_STRING_DESIGN_SCRIPT_LANGUAGE_TAG, + DWRITE_INFORMATIONAL_STRING_SUPPORTED_SCRIPT_LANGUAGE_TAG, +}} +STRUCT!{struct DWRITE_FONT_METRICS { + designUnitsPerEm: UINT16, + ascent: UINT16, + descent: UINT16, + lineGap: INT16, + capHeight: UINT16, + xHeight: UINT16, + underlinePosition: INT16, + underlineThickness: UINT16, + strikethroughPosition: INT16, + strikethroughThickness: UINT16, +}} +STRUCT!{struct DWRITE_GLYPH_METRICS { + leftSideBearing: INT32, + advanceWidth: UINT32, + rightSideBearing: INT32, + topSideBearing: INT32, + advanceHeight: UINT32, + bottomSideBearing: INT32, + verticalOriginY: INT32, +}} +STRUCT!{struct DWRITE_GLYPH_OFFSET { + advanceOffset: FLOAT, + ascenderOffset: FLOAT, +}} +ENUM!{enum DWRITE_FACTORY_TYPE { + DWRITE_FACTORY_TYPE_SHARED, + DWRITE_FACTORY_TYPE_ISOLATED, +}} +RIDL!{#[uuid(0x727cad4e, 0xd6af, 0x4c9e, 0x8a, 0x08, 0xd6, 0x95, 0xb1, 0x1c, 0xaa, 0x49)] +interface IDWriteFontFileLoader(IDWriteFontFileLoaderVtbl): IUnknown(IUnknownVtbl) { + fn CreateStreamFromKey( + fontFileReferenceKey: *const c_void, + fontFileReferenceKeySize: UINT32, + fontFileStream: *mut *mut IDWriteFontFileStream, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb2d9f3ec, 0xc9fe, 0x4a11, 0xa2, 0xec, 0xd8, 0x62, 0x08, 0xf7, 0xc0, 0xa2)] +interface IDWriteLocalFontFileLoader(IDWriteLocalFontFileLoaderVtbl): + IDWriteFontFileLoader(IDWriteFontFileLoaderVtbl) { + fn GetFilePathLengthFromKey( + fontFileReferenceKey: *const c_void, + fontFileReferenceKeySize: UINT32, + filePathLength: *mut UINT32, + ) -> HRESULT, + fn GetFilePathFromKey( + fontFileReferenceKey: *const c_void, + fontFileReferenceKeySize: UINT32, + filePath: *mut WCHAR, + filePathSize: UINT32, + ) -> HRESULT, + fn GetLastWriteTimeFromKey( + fontFileReferenceKey: *const c_void, + fontFileReferenceKeySize: UINT32, + lastWriteTime: *mut FILETIME, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6d4865fe, 0x0ab8, 0x4d91, 0x8f, 0x62, 0x5d, 0xd6, 0xbe, 0x34, 0xa3, 0xe0)] +interface IDWriteFontFileStream(IDWriteFontFileStreamVtbl): IUnknown(IUnknownVtbl) { + fn ReadFileFragment( + fragmentStart: *mut *const c_void, + fileOffset: UINT64, + fragmentSize: UINT64, + fragmentContext: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseFileFragment( + fragmentContext: *mut c_void, + ) -> (), + fn GetFileSize( + fileSize: *mut UINT64, + ) -> HRESULT, + fn GetLastWriteTime( + lastWriteTime: *mut UINT64, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_OUTLINE_THRESHOLD { + DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, + DWRITE_OUTLINE_THRESHOLD_ALIASED, +}} +STRUCT!{struct DWRITE_FONT_METRICS1 { + designUnitsPerEm: UINT16, + ascent: UINT16, + descent: UINT16, + lineGap: INT16, + capHeight: UINT16, + xHeight: UINT16, + underlinePosition: INT16, + underlineThickness: UINT16, + strikethroughPosition: INT16, + strikethroughThickness: UINT16, + glyphBoxLeft: INT16, + glyphBoxTop: INT16, + glyphBoxRight: INT16, + glyphBoxBottom: INT16, + subscriptPositionX: INT16, + subscriptPositionY: INT16, + subscriptSizeX: INT16, + subscriptSizeY: INT16, + superscriptPositionX: INT16, + superscriptPositionY: INT16, + superscriptSizeX: INT16, + superscriptSizeY: INT16, + hasTypographicMetrics: BOOL, +}} +STRUCT!{struct DWRITE_UNICODE_RANGE { + first: UINT32, + last: UINT32, +}} +STRUCT!{struct DWRITE_CARET_METRICS { + slopeRise: INT16, + slopeRun: INT16, + offset: INT16, +}} +#[inline] +pub fn DWRITE_MAKE_OPENTYPE_TAG(a: u8, b: u8, c: u8, d: u8) -> u32 { + ((d as u32) << 24) | ((c as u32) << 16) | ((b as u32) << 8) | (a as u32) +} +RIDL!{#[uuid(0x739d886a, 0xcef5, 0x47dc, 0x87, 0x69, 0x1a, 0x8b, 0x41, 0xbe, 0xbb, 0xb0)] +interface IDWriteFontFile(IDWriteFontFileVtbl): IUnknown(IUnknownVtbl) { + fn GetReferenceKey( + fontFileReferenceKey: *mut *const c_void, + fontFileReferenceKeySize: *mut UINT32, + ) -> HRESULT, + fn GetLoader( + fontFileLoader: *mut *mut IDWriteFontFileLoader, + ) -> HRESULT, + fn Analyze( + isSupportedFontType: *mut BOOL, + fontFileType: *mut DWRITE_FONT_FILE_TYPE, + fontFaceType: *mut DWRITE_FONT_FACE_TYPE, + numberOfFaces: *mut UINT32, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_PIXEL_GEOMETRY { + DWRITE_PIXEL_GEOMETRY_FLAT, + DWRITE_PIXEL_GEOMETRY_RGB, + DWRITE_PIXEL_GEOMETRY_BGR, +}} +ENUM!{enum DWRITE_RENDERING_MODE { + DWRITE_RENDERING_MODE_DEFAULT, + DWRITE_RENDERING_MODE_ALIASED, + DWRITE_RENDERING_MODE_GDI_CLASSIC, + DWRITE_RENDERING_MODE_GDI_NATURAL, + DWRITE_RENDERING_MODE_NATURAL, + DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, + DWRITE_RENDERING_MODE_OUTLINE, + DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC = DWRITE_RENDERING_MODE_GDI_CLASSIC, + DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL = DWRITE_RENDERING_MODE_GDI_NATURAL, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL = DWRITE_RENDERING_MODE_NATURAL, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, +}} +STRUCT!{struct DWRITE_MATRIX { + m11: FLOAT, + m12: FLOAT, + m21: FLOAT, + m22: FLOAT, + dx: FLOAT, + dy: FLOAT, +}} +RIDL!{#[uuid(0x2f0da53a, 0x2add, 0x47cd, 0x82, 0xee, 0xd9, 0xec, 0x34, 0x68, 0x8e, 0x75)] +interface IDWriteRenderingParams(IDWriteRenderingParamsVtbl): IUnknown(IUnknownVtbl) { + fn GetGamma() -> FLOAT, + fn GetEnhancedContrast() -> FLOAT, + fn GetClearTypeLevel() -> FLOAT, + fn GetPixelGeometry() -> DWRITE_PIXEL_GEOMETRY, + fn GetRenderingMode() -> DWRITE_RENDERING_MODE, +}} +pub type IDWriteGeometrySink = ID2D1SimplifiedGeometrySink; +RIDL!{#[uuid(0x5f49804d, 0x7024, 0x4d43, 0xbf, 0xa9, 0xd2, 0x59, 0x84, 0xf5, 0x38, 0x49)] +interface IDWriteFontFace(IDWriteFontFaceVtbl): IUnknown(IUnknownVtbl) { + fn GetType() -> DWRITE_FONT_FACE_TYPE, + fn GetFiles( + numberOfFiles: *mut UINT32, + fontFiles: *mut *mut IDWriteFontFile, + ) -> HRESULT, + fn GetIndex() -> UINT32, + fn GetSimulations() -> DWRITE_FONT_SIMULATIONS, + fn IsSymbolFont() -> BOOL, + fn GetMetrics( + fontFaceMetrics: *mut DWRITE_FONT_METRICS, + ) -> (), + fn GetGlyphCount() -> UINT16, + fn GetDesignGlyphMetrics( + glyphIndices: *const UINT16, + glyphCount: UINT32, + glyphMetrics: *mut DWRITE_GLYPH_METRICS, + isSideways: BOOL, + ) -> HRESULT, + fn GetGlyphIndices( + codePoints: *const UINT32, + codePointCount: UINT32, + glyphIndices: *mut UINT16, + ) -> HRESULT, + fn TryGetFontTable( + openTypeTableTag: UINT32, + tableData: *mut *const c_void, + tableSize: *mut UINT32, + tableContext: *mut *mut c_void, + exists: *mut BOOL, + ) -> HRESULT, + fn ReleaseFontTable( + tableContext: *mut c_void, + ) -> HRESULT, + fn GetGlyphRunOutline( + emSize: FLOAT, + glyphIndices: *const UINT16, + glyphAdvances: *const FLOAT, + glyphOffsets: *const DWRITE_GLYPH_OFFSET, + glyphCount: UINT32, + isSideways: BOOL, + isRightToLeft: BOOL, + geometrySink: *mut IDWriteGeometrySink, + ) -> HRESULT, + fn GetRecommendedRenderingMode( + emSize: FLOAT, + pixelsPerDip: FLOAT, + measuringMode: DWRITE_MEASURING_MODE, + renderingParams: *mut IDWriteRenderingParams, + renderingMode: *mut DWRITE_RENDERING_MODE, + ) -> HRESULT, + fn GetGdiCompatibleMetrics( + emSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + fontFaceMetrics: *mut DWRITE_FONT_METRICS, + ) -> HRESULT, + fn GetGdiCompatibleGlyphMetrics( + enSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + useGdiNatrual: BOOL, + glyphIndices: *const UINT16, + glyphCount: UINT32, + glyphMetrics: *mut DWRITE_GLYPH_METRICS, + isSideways: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa71efdb4, 0x9fdb, 0x4838, 0xad, 0x90, 0xcf, 0xc3, 0xbe, 0x8c, 0x3d, 0xaf)] +interface IDWriteFontFace1(IDWriteFontFace1Vtbl): IDWriteFontFace(IDWriteFontFaceVtbl) { + fn GetMetrics( + fontFaceMetrics: *mut DWRITE_FONT_METRICS1, + ) -> (), + fn GetGdiCompatibleMetrics( + emSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + fontFaceMetrics: *mut DWRITE_FONT_METRICS1, + ) -> HRESULT, + fn GetCaretMetrics( + caretMetrics: *mut DWRITE_CARET_METRICS, + ) -> (), + fn GetUnicodeRanges( + maxRangeCount: UINT32, + unicodeRanges: *mut DWRITE_UNICODE_RANGE, + actualRangeCount: *mut UINT32, + ) -> HRESULT, + fn IsMonoSpacedFont() -> BOOL, + fn GetDesignGlyphAdvances( + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvances: *mut INT32, + isSideways: BOOL, + ) -> HRESULT, + fn GetGdiCompatibleGlyphAdvance( + emSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + useGdiNatural: BOOL, + isSideways: BOOL, + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvances: *mut INT32, + ) -> HRESULT, + fn GetKerningPairAdjustments( + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvanceAdjustments: *mut INT32, + ) -> HRESULT, + fn HasKerningPairs() -> BOOL, + fn GetRecommendedRenderingMode( + fontEmSize: FLOAT, + dpiX: FLOAT, + dpiY: FLOAT, + transform: *const DWRITE_MATRIX, + isSideways: BOOL, + outlineThreshold: DWRITE_OUTLINE_THRESHOLD, + measuringMode: DWRITE_MEASURING_MODE, + renderingMode: *mut DWRITE_RENDERING_MODE, + ) -> HRESULT, + fn GetVerticalGlyphVariants( + nominalGlyphIndices: *const UINT16, + verticalGlyphIndices: *mut UINT16, + ) -> HRESULT, + fn HasVerticalGlyphVariants() -> BOOL, +}} +RIDL!{#[uuid(0xcca920e4, 0x52f0, 0x492b, 0xbf, 0xa8, 0x29, 0xc7, 0x2e, 0xe0, 0xa4, 0x68)] +interface IDWriteFontCollectionLoader(IDWriteFontCollectionLoaderVtbl): + IUnknown(IUnknownVtbl) { + fn CreateEnumeratorFromKey( + factory: *mut IDWriteFactory, + collectionKey: *const c_void, + collectionKeySize: UINT32, + fontFileEnumerator: *mut *mut IDWriteFontFileEnumerator, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x72755049, 0x5ff7, 0x435d, 0x83, 0x48, 0x4b, 0xe9, 0x7c, 0xfa, 0x6c, 0x7c)] +interface IDWriteFontFileEnumerator(IDWriteFontFileEnumeratorVtbl): IUnknown(IUnknownVtbl) { + fn MoveNext( + hasCurrentFile: *mut BOOL, + ) -> HRESULT, + fn GetCurrentFontFile( + fontFile: *mut *mut IDWriteFontFile, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x08256209, 0x099a, 0x4b34, 0xb8, 0x6d, 0xc2, 0x2b, 0x11, 0x0e, 0x77, 0x71)] +interface IDWriteLocalizedStrings(IDWriteLocalizedStringsVtbl): IUnknown(IUnknownVtbl) { + fn GetCount() -> UINT32, + fn FindLocaleName( + localeName: *const WCHAR, + index: *mut UINT32, + exists: *mut BOOL, + ) -> HRESULT, + fn GetLocaleNameLength( + index: UINT32, + length: *mut UINT32, + ) -> HRESULT, + fn GetLocaleName( + index: UINT32, + localeName: *mut WCHAR, + size: UINT32, + ) -> HRESULT, + fn GetStringLength( + index: UINT32, + length: *mut UINT32, + ) -> HRESULT, + fn GetString( + index: UINT32, + stringBuffer: *mut WCHAR, + size: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa84cee02, 0x3eea, 0x4eee, 0xa8, 0x27, 0x87, 0xc1, 0xa0, 0x2a, 0x0f, 0xcc)] +interface IDWriteFontCollection(IDWriteFontCollectionVtbl): IUnknown(IUnknownVtbl) { + fn GetFontFamilyCount() -> UINT32, + fn GetFontFamily( + index: UINT32, + fontFamily: *mut *mut IDWriteFontFamily, + ) -> HRESULT, + fn FindFamilyName( + familyName: *const WCHAR, + index: *mut UINT32, + exists: *mut BOOL, + ) -> HRESULT, + fn GetFontFromFontFace( + fontFace: *mut IDWriteFontFace, + font: *mut *mut IDWriteFont, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1a0d8438, 0x1d97, 0x4ec1, 0xae, 0xf9, 0xa2, 0xfb, 0x86, 0xed, 0x6a, 0xcb)] +interface IDWriteFontList(IDWriteFontListVtbl): IUnknown(IUnknownVtbl) { + fn GetFontCollection( + fontCollection: *mut *mut IDWriteFontCollection, + ) -> HRESULT, + fn GetFontCount() -> UINT32, + fn GetFont( + index: UINT32, + font: *mut *mut IDWriteFont, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xda20d8ef, 0x812a, 0x4c43, 0x98, 0x02, 0x62, 0xec, 0x4a, 0xbd, 0x7a, 0xdd)] +interface IDWriteFontFamily(IDWriteFontFamilyVtbl): IDWriteFontList(IDWriteFontListVtbl) { + fn GetFamilyNames( + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetFirstMatchingFont( + weight: DWRITE_FONT_WEIGHT, + stretch: DWRITE_FONT_STRETCH, + style: DWRITE_FONT_STYLE, + matchingFont: *mut *mut IDWriteFont, + ) -> HRESULT, + fn GetMatchingFonts( + weight: DWRITE_FONT_WEIGHT, + stretch: DWRITE_FONT_STRETCH, + style: DWRITE_FONT_STYLE, + matchingFonts: *mut *mut IDWriteFontList, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xacd16696, 0x8c14, 0x4f5d, 0x87, 0x7e, 0xfe, 0x3f, 0xc1, 0xd3, 0x27, 0x37)] +interface IDWriteFont(IDWriteFontVtbl): IUnknown(IUnknownVtbl) { + fn GetFontFamily( + fontFamily: *mut *mut IDWriteFontFamily, + ) -> HRESULT, + fn GetWeight() -> DWRITE_FONT_WEIGHT, + fn GetStretch() -> DWRITE_FONT_STRETCH, + fn GetStyle() -> DWRITE_FONT_STYLE, + fn IsSymbolFont() -> BOOL, + fn GetFaceNames( + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetInformationalStrings( + informationalStringId: DWRITE_INFORMATIONAL_STRING_ID, + informationalStrings: *mut *mut IDWriteLocalizedStrings, + exists: *mut BOOL, + ) -> HRESULT, + fn GetSimulations() -> DWRITE_FONT_SIMULATIONS, + fn GetMetrics( + fontMetrics: *mut DWRITE_FONT_METRICS, + ) -> (), + fn HasCharacter( + unicodeValue: UINT32, + exists: *mut BOOL, + ) -> HRESULT, + fn CreateFontFace( + fontFace: *mut *mut IDWriteFontFace, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_READING_DIRECTION { + DWRITE_READING_DIRECTION_LEFT_TO_RIGHT = 0, + DWRITE_READING_DIRECTION_RIGHT_TO_LEFT = 1, + DWRITE_READING_DIRECTION_TOP_TO_BOTTOM = 2, + DWRITE_READING_DIRECTION_BOTTOM_TO_TOP = 3, +}} +ENUM!{enum DWRITE_FLOW_DIRECTION { + DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM = 0, + DWRITE_FLOW_DIRECTION_BOTTOM_TO_TOP = 1, + DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT = 2, + DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT = 3, +}} +ENUM!{enum DWRITE_TEXT_ALIGNMENT { + DWRITE_TEXT_ALIGNMENT_LEADING, + DWRITE_TEXT_ALIGNMENT_TRAILING, + DWRITE_TEXT_ALIGNMENT_CENTER, + DWRITE_TEXT_ALIGNMENT_JUSTIFIED, +}} +ENUM!{enum DWRITE_PARAGRAPH_ALIGNMENT { + DWRITE_PARAGRAPH_ALIGNMENT_NEAR, + DWRITE_PARAGRAPH_ALIGNMENT_FAR, + DWRITE_PARAGRAPH_ALIGNMENT_CENTER, +}} +ENUM!{enum DWRITE_WORD_WRAPPING { + DWRITE_WORD_WRAPPING_WRAP = 0, + DWRITE_WORD_WRAPPING_NO_WRAP = 1, + DWRITE_WORD_WRAPPING_EMERGENCY_BREAK = 2, + DWRITE_WORD_WRAPPING_WHOLE_WORD = 3, + DWRITE_WORD_WRAPPING_CHARACTER = 4, +}} +ENUM!{enum DWRITE_LINE_SPACING_METHOD { + DWRITE_LINE_SPACING_METHOD_DEFAULT, + DWRITE_LINE_SPACING_METHOD_UNIFORM, + DWRITE_LINE_SPACING_METHOD_PROPORTIONAL, +}} +ENUM!{enum DWRITE_TRIMMING_GRANULARITY { + DWRITE_TRIMMING_GRANULARITY_NONE, + DWRITE_TRIMMING_GRANULARITY_CHARACTER, + DWRITE_TRIMMING_GRANULARITY_WORD, +}} +ENUM!{enum DWRITE_FONT_FEATURE_TAG { + DWRITE_FONT_FEATURE_TAG_ALTERNATIVE_FRACTIONS = 0x63726661, // 'afrc' + DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS_FROM_CAPITALS = 0x63703263, // 'c2pc' + DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS_FROM_CAPITALS = 0x63733263, // 'c2sc' + DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES = 0x746c6163, // 'calt' + DWRITE_FONT_FEATURE_TAG_CASE_SENSITIVE_FORMS = 0x65736163, // 'case' + DWRITE_FONT_FEATURE_TAG_GLYPH_COMPOSITION_DECOMPOSITION = 0x706d6363, // 'ccmp' + DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES = 0x67696c63, // 'clig' + DWRITE_FONT_FEATURE_TAG_CAPITAL_SPACING = 0x70737063, // 'cpsp' + DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_SWASH = 0x68777363, // 'cswh' + DWRITE_FONT_FEATURE_TAG_CURSIVE_POSITIONING = 0x73727563, // 'curs' + DWRITE_FONT_FEATURE_TAG_DEFAULT = 0x746c6664, // 'dflt' + DWRITE_FONT_FEATURE_TAG_DISCRETIONARY_LIGATURES = 0x67696c64, // 'dlig' + DWRITE_FONT_FEATURE_TAG_EXPERT_FORMS = 0x74707865, // 'expt' + DWRITE_FONT_FEATURE_TAG_FRACTIONS = 0x63617266, // 'frac' + DWRITE_FONT_FEATURE_TAG_FULL_WIDTH = 0x64697766, // 'fwid' + DWRITE_FONT_FEATURE_TAG_HALF_FORMS = 0x666c6168, // 'half' + DWRITE_FONT_FEATURE_TAG_HALANT_FORMS = 0x6e6c6168, // 'haln' + DWRITE_FONT_FEATURE_TAG_ALTERNATE_HALF_WIDTH = 0x746c6168, // 'halt' + DWRITE_FONT_FEATURE_TAG_HISTORICAL_FORMS = 0x74736968, // 'hist' + DWRITE_FONT_FEATURE_TAG_HORIZONTAL_KANA_ALTERNATES = 0x616e6b68, // 'hkna' + DWRITE_FONT_FEATURE_TAG_HISTORICAL_LIGATURES = 0x67696c68, // 'hlig' + DWRITE_FONT_FEATURE_TAG_HALF_WIDTH = 0x64697768, // 'hwid' + DWRITE_FONT_FEATURE_TAG_HOJO_KANJI_FORMS = 0x6f6a6f68, // 'hojo' + DWRITE_FONT_FEATURE_TAG_JIS04_FORMS = 0x3430706a, // 'jp04' + DWRITE_FONT_FEATURE_TAG_JIS78_FORMS = 0x3837706a, // 'jp78' + DWRITE_FONT_FEATURE_TAG_JIS83_FORMS = 0x3338706a, // 'jp83' + DWRITE_FONT_FEATURE_TAG_JIS90_FORMS = 0x3039706a, // 'jp90' + DWRITE_FONT_FEATURE_TAG_KERNING = 0x6e72656b, // 'kern' + DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES = 0x6167696c, // 'liga' + DWRITE_FONT_FEATURE_TAG_LINING_FIGURES = 0x6d756e6c, // 'lnum' + DWRITE_FONT_FEATURE_TAG_LOCALIZED_FORMS = 0x6c636f6c, // 'locl' + DWRITE_FONT_FEATURE_TAG_MARK_POSITIONING = 0x6b72616d, // 'mark' + DWRITE_FONT_FEATURE_TAG_MATHEMATICAL_GREEK = 0x6b72676d, // 'mgrk' + DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING = 0x6b6d6b6d, // 'mkmk' + DWRITE_FONT_FEATURE_TAG_ALTERNATE_ANNOTATION_FORMS = 0x746c616e, // 'nalt' + DWRITE_FONT_FEATURE_TAG_NLC_KANJI_FORMS = 0x6b636c6e, // 'nlck' + DWRITE_FONT_FEATURE_TAG_OLD_STYLE_FIGURES = 0x6d756e6f, // 'onum' + DWRITE_FONT_FEATURE_TAG_ORDINALS = 0x6e64726f, // 'ordn' + DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_ALTERNATE_WIDTH = 0x746c6170, // 'palt' + DWRITE_FONT_FEATURE_TAG_PETITE_CAPITALS = 0x70616370, // 'pcap' + DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_FIGURES = 0x6d756e70, // 'pnum' + DWRITE_FONT_FEATURE_TAG_PROPORTIONAL_WIDTHS = 0x64697770, // 'pwid' + DWRITE_FONT_FEATURE_TAG_QUARTER_WIDTHS = 0x64697771, // 'qwid' + DWRITE_FONT_FEATURE_TAG_REQUIRED_LIGATURES = 0x67696c72, // 'rlig' + DWRITE_FONT_FEATURE_TAG_RUBY_NOTATION_FORMS = 0x79627572, // 'ruby' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_ALTERNATES = 0x746c6173, // 'salt' + DWRITE_FONT_FEATURE_TAG_SCIENTIFIC_INFERIORS = 0x666e6973, // 'sinf' + DWRITE_FONT_FEATURE_TAG_SMALL_CAPITALS = 0x70636d73, // 'smcp' + DWRITE_FONT_FEATURE_TAG_SIMPLIFIED_FORMS = 0x6c706d73, // 'smpl' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_1 = 0x31307373, // 'ss01' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_2 = 0x32307373, // 'ss02' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_3 = 0x33307373, // 'ss03' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_4 = 0x34307373, // 'ss04' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_5 = 0x35307373, // 'ss05' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_6 = 0x36307373, // 'ss06' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_7 = 0x37307373, // 'ss07' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_8 = 0x38307373, // 'ss08' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_9 = 0x39307373, // 'ss09' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_10 = 0x30317373, // 'ss10' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_11 = 0x31317373, // 'ss11' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_12 = 0x32317373, // 'ss12' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_13 = 0x33317373, // 'ss13' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_14 = 0x34317373, // 'ss14' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_15 = 0x35317373, // 'ss15' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_16 = 0x36317373, // 'ss16' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_17 = 0x37317373, // 'ss17' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_18 = 0x38317373, // 'ss18' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_19 = 0x39317373, // 'ss19' + DWRITE_FONT_FEATURE_TAG_STYLISTIC_SET_20 = 0x30327373, // 'ss20' + DWRITE_FONT_FEATURE_TAG_SUBSCRIPT = 0x73627573, // 'subs' + DWRITE_FONT_FEATURE_TAG_SUPERSCRIPT = 0x73707573, // 'sups' + DWRITE_FONT_FEATURE_TAG_SWASH = 0x68737773, // 'swsh' + DWRITE_FONT_FEATURE_TAG_TITLING = 0x6c746974, // 'titl' + DWRITE_FONT_FEATURE_TAG_TRADITIONAL_NAME_FORMS = 0x6d616e74, // 'tnam' + DWRITE_FONT_FEATURE_TAG_TABULAR_FIGURES = 0x6d756e74, // 'tnum' + DWRITE_FONT_FEATURE_TAG_TRADITIONAL_FORMS = 0x64617274, // 'trad' + DWRITE_FONT_FEATURE_TAG_THIRD_WIDTHS = 0x64697774, // 'twid' + DWRITE_FONT_FEATURE_TAG_UNICASE = 0x63696e75, // 'unic' + DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING = 0x74726576, // 'vert' + DWRITE_FONT_FEATURE_TAG_VERTICAL_ALTERNATES_AND_ROTATION = 0x32747276, // 'vrt2' + DWRITE_FONT_FEATURE_TAG_SLASHED_ZERO = 0x6f72657a, // 'zero' +}} +STRUCT!{struct DWRITE_TEXT_RANGE { + startPosition: UINT32, + length: UINT32, +}} +STRUCT!{struct DWRITE_FONT_FEATURE { + nameTag: DWRITE_FONT_FEATURE_TAG, + parameter: UINT32, +}} +STRUCT!{struct DWRITE_TYPOGRAPHIC_FEATURES { + features: *mut DWRITE_FONT_FEATURE, + featureCount: UINT32, +}} +STRUCT!{struct DWRITE_TRIMMING { + granularity: DWRITE_TRIMMING_GRANULARITY, + delimiter: UINT32, + delimiterCount: UINT32, +}} +RIDL!{#[uuid(0x9c906818, 0x31d7, 0x4fd3, 0xa1, 0x51, 0x7c, 0x5e, 0x22, 0x5d, 0xb5, 0x5a)] +interface IDWriteTextFormat(IDWriteTextFormatVtbl): IUnknown(IUnknownVtbl) { + fn SetTextAlignment( + textAlignment: DWRITE_TEXT_ALIGNMENT, + ) -> HRESULT, + fn SetParagraphAlignment( + paragraphAlignment: DWRITE_PARAGRAPH_ALIGNMENT, + ) -> HRESULT, + fn SetWordWrapping( + wordWrapping: DWRITE_WORD_WRAPPING, + ) -> HRESULT, + fn SetReadingDirection( + readingDirection: DWRITE_READING_DIRECTION, + ) -> HRESULT, + fn SetFlowDirection( + flowDirection: DWRITE_FLOW_DIRECTION, + ) -> HRESULT, + fn SetIncrementalTabStop( + incrementalTabStop: FLOAT, + ) -> HRESULT, + fn SetTrimming( + trimmingOptions: *const DWRITE_TRIMMING, + trimmingSign: *mut IDWriteInlineObject, + ) -> HRESULT, + fn SetLineSpacing( + lineSpacingMethod: DWRITE_LINE_SPACING_METHOD, + lineSpacing: FLOAT, + baseLine: FLOAT, + ) -> HRESULT, + fn GetTextAlignment() -> DWRITE_TEXT_ALIGNMENT, + fn GetParagraphAlignment() -> DWRITE_PARAGRAPH_ALIGNMENT, + fn GetWordWrapping() -> DWRITE_WORD_WRAPPING, + fn GetReadingDirection() -> DWRITE_READING_DIRECTION, + fn GetFlowDirection() -> DWRITE_FLOW_DIRECTION, + fn GetIncrementalTabStop() -> FLOAT, + fn GetTrimming( + trimmingOptions: *mut DWRITE_TRIMMING, + trimmingSign: *mut *mut IDWriteInlineObject, + ) -> HRESULT, + fn GetLineSpacing( + lineSpacingMethod: *mut DWRITE_LINE_SPACING_METHOD, + lineSpacing: *mut FLOAT, + baseline: *mut FLOAT, + ) -> HRESULT, + fn GetFontCollection( + fontCollection: *mut *mut IDWriteFontCollection, + ) -> HRESULT, + fn GetFontFamilyNameLength() -> UINT32, + fn GetFontFamilyName( + fontFamilyName: *mut WCHAR, + nameSize: UINT32, + ) -> HRESULT, + fn GetFontWeight() -> DWRITE_FONT_WEIGHT, + fn GetFontStyle() -> DWRITE_FONT_STYLE, + fn GetFontStretch() -> DWRITE_FONT_STRETCH, + fn GetFontSize() -> FLOAT, + fn GetLocaleNameLength() -> UINT32, + fn GetLocaleName( + localeName: *mut WCHAR, + nameSize: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x55f1112b, 0x1dc2, 0x4b3c, 0x95, 0x41, 0xf4, 0x68, 0x94, 0xed, 0x85, 0xb6)] +interface IDWriteTypography(IDWriteTypographyVtbl): IUnknown(IUnknownVtbl) { + fn AddFontFeature( + fontFeature: DWRITE_FONT_FEATURE, + ) -> HRESULT, + fn GetFontFeatureCount() -> UINT32, + fn GetFontFeature( + fontFeatureIndex: UINT32, + fontFeature: *mut DWRITE_FONT_FEATURE, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_SCRIPT_SHAPES { + DWRITE_SCRIPT_SHAPES_DEFAULT = 0, + DWRITE_SCRIPT_SHAPES_NO_VISUAL = 1, +}} +STRUCT!{struct DWRITE_SCRIPT_ANALYSIS { + script: UINT16, + shapes: DWRITE_SCRIPT_SHAPES, +}} +ENUM!{enum DWRITE_BREAK_CONDITION { + DWRITE_BREAK_CONDITION_NEUTRAL, + DWRITE_BREAK_CONDITION_CAN_BREAK, + DWRITE_BREAK_CONDITION_MAY_NOT_BREAK, + DWRITE_BREAK_CONDITION_MUST_BREAK, +}} +STRUCT!{struct DWRITE_LINE_BREAKPOINT { + bit_fields: UINT8, +}} +BITFIELD!{DWRITE_LINE_BREAKPOINT bit_fields: UINT8 [ + breakConditionBefore set_breakConditionBefore[0..2], + breakConditionAfter set_breakConditionAfter[2..4], + isWhitespace set_isWhitespace[4..5], + isSoftHyphen set_isSoftHyphen[5..6], + padding set_padding[6..8], +]} +ENUM!{enum DWRITE_NUMBER_SUBSTITUTION_METHOD { + DWRITE_NUMBER_SUBSTITUTION_METHOD_FROM_CULTURE, + DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL, + DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, + DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL, + DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL, +}} +RIDL!{#[uuid(0x14885cc9, 0xbab0, 0x4f90, 0xb6, 0xed, 0x5c, 0x36, 0x6a, 0x2c, 0xd0, 0x3d)] +interface IDWriteNumberSubstitution(IDWriteNumberSubstitutionVtbl): IUnknown(IUnknownVtbl) {}} +STRUCT!{struct DWRITE_SHAPING_TEXT_PROPERTIES { + bit_fields: UINT16, +}} +BITFIELD!{DWRITE_SHAPING_TEXT_PROPERTIES bit_fields: UINT16 [ + isShapedAlone set_isShapedAlone[0..1], + reserved set_reserved[1..16], +]} +STRUCT!{struct DWRITE_SHAPING_GLYPH_PROPERTIES { + bit_fields: UINT16, +}} +BITFIELD!{DWRITE_SHAPING_GLYPH_PROPERTIES bit_fields: UINT16 [ + justification set_justification[0..4], + isClusterStart set_isClusterStart[4..5], + isDiacritic set_isDiacritic[5..6], + isZeroWidthSpace set_isZeroWidthSpace[6..7], + reserved set_reserved[7..16], +]} +RIDL!{#[uuid(0x688e1a58, 0x5094, 0x47c8, 0xad, 0xc8, 0xfb, 0xce, 0xa6, 0x0a, 0xe9, 0x2b)] +interface IDWriteTextAnalysisSource(IDWriteTextAnalysisSourceVtbl): IUnknown(IUnknownVtbl) { + fn GetTextAtPosition( + textPosition: UINT32, + textString: *mut *const WCHAR, + textLength: *mut UINT32, + ) -> HRESULT, + fn GetTextBeforePosition( + textPosition: UINT32, + textString: *mut *const WCHAR, + textLength: *mut UINT32, + ) -> HRESULT, + fn GetParagraphReadingDirection() -> DWRITE_READING_DIRECTION, + fn GetLocaleName( + textPosition: UINT32, + textLength: *mut UINT32, + localeName: *mut *const WCHAR, + ) -> HRESULT, + fn GetNumberSubstitution( + textPosition: UINT32, + textLength: *mut UINT32, + numberSubstitution: *mut *mut IDWriteNumberSubstitution, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5810cd44, 0x0ca0, 0x4701, 0xb3, 0xfa, 0xbe, 0xc5, 0x18, 0x2a, 0xe4, 0xf6)] +interface IDWriteTextAnalysisSink(IDWriteTextAnalysisSinkVtbl): IUnknown(IUnknownVtbl) { + fn SetScriptAnalysis( + textPosition: UINT32, + textLength: UINT32, + scriptAnalysis: *const DWRITE_SCRIPT_ANALYSIS, + ) -> HRESULT, + fn SetLineBreakpoints( + textPosition: UINT32, + textLength: UINT32, + lineBreakpoints: *const DWRITE_LINE_BREAKPOINT, + ) -> HRESULT, + fn SetBidiLevel( + textPosition: UINT32, + textLength: UINT32, + explicitLevel: UINT8, + resolvedLevel: UINT8, + ) -> HRESULT, + fn SetNumberSubstitution( + textPosition: UINT32, + textLength: UINT32, + numberSubstitution: *mut IDWriteNumberSubstitution, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb7e6163e, 0x7f46, 0x43b4, 0x84, 0xb3, 0xe4, 0xe6, 0x24, 0x9c, 0x36, 0x5d)] +interface IDWriteTextAnalyzer(IDWriteTextAnalyzerVtbl): IUnknown(IUnknownVtbl) { + fn AnalyzeScript( + analysisSource: *mut IDWriteTextAnalysisSource, + textPosition: UINT32, + textLength: UINT32, + analysisSink: *mut IDWriteTextAnalysisSink, + ) -> HRESULT, + fn AnalyzeBidi( + analysisSource: *mut IDWriteTextAnalysisSource, + textPosition: UINT32, + textLength: UINT32, + analysisSink: *mut IDWriteTextAnalysisSink, + ) -> HRESULT, + fn AnalyzeNumberSubstitution( + analysisSource: *mut IDWriteTextAnalysisSource, + textPosition: UINT32, + textLength: UINT32, + analysisSink: *mut IDWriteTextAnalysisSink, + ) -> HRESULT, + fn AnalyzeLineBreakpoints( + analysisSource: *mut IDWriteTextAnalysisSource, + textPosition: UINT32, + textLength: UINT32, + analysisSink: *mut IDWriteTextAnalysisSink, + ) -> HRESULT, + fn GetGlyphs( + textString: *const WCHAR, + textLength: UINT32, + fontFace: *mut IDWriteFontFace, + isSideways: BOOL, + isRightToLeft: BOOL, + scriptAnalysis: *const DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + numberSubstitution: *mut IDWriteNumberSubstitution, + features: *mut *const DWRITE_TYPOGRAPHIC_FEATURES, + featureRangeLengths: *const UINT32, + featureRanges: UINT32, + maxGlyphCount: UINT32, + clusterMap: *mut UINT16, + textProps: *mut DWRITE_SHAPING_TEXT_PROPERTIES, + glyphIndices: *mut UINT16, + glyphProps: *mut DWRITE_SHAPING_GLYPH_PROPERTIES, + actualGlyphCount: *mut UINT32, + ) -> HRESULT, + fn GetGlyphPlacements( + textString: *const WCHAR, + clusterMap: *const UINT16, + textProps: *mut DWRITE_SHAPING_TEXT_PROPERTIES, + textLength: UINT32, + glyphIndices: *const UINT16, + glyphProps: *const DWRITE_SHAPING_GLYPH_PROPERTIES, + glyphCount: UINT32, + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + isSideways: BOOL, + isRightToLeft: BOOL, + scriptAnalysis: *const DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + features: *mut *const DWRITE_TYPOGRAPHIC_FEATURES, + featureRangeLengths: *const UINT32, + featureRanges: UINT32, + glyphAdvances: *mut FLOAT, + glyphOffsets: *mut DWRITE_GLYPH_OFFSET, + ) -> HRESULT, + fn GetGdiCompatibleGlyphPlacements( + textString: *const WCHAR, + clusterMap: *const UINT16, + textProps: *mut DWRITE_SHAPING_TEXT_PROPERTIES, + textLength: UINT32, + glyphIndices: *const UINT16, + glyphProps: *const DWRITE_SHAPING_GLYPH_PROPERTIES, + glyphCount: UINT32, + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + useGdiNatrual: BOOL, + isSideways: BOOL, + isRightToLeft: BOOL, + scriptAnalysis: *const DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + features: *mut *const DWRITE_TYPOGRAPHIC_FEATURES, + featureRangeLengths: *const UINT32, + featureRanges: UINT32, + glyphAdvances: *mut FLOAT, + glyphOffsets: *mut DWRITE_GLYPH_OFFSET, + ) -> HRESULT, +}} +STRUCT!{struct DWRITE_GLYPH_RUN { + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvances: *const FLOAT, + glyphOffsets: *const DWRITE_GLYPH_OFFSET, + isSideways: BOOL, + bidiLevel: UINT32, +}} +STRUCT!{struct DWRITE_GLYPH_RUN_DESCRIPTION { + localeName: *const WCHAR, + string: *const WCHAR, + stringLength: UINT32, + clusterMap: *const UINT16, + textPosition: UINT32, +}} +STRUCT!{struct DWRITE_UNDERLINE { + width: FLOAT, + thickness: FLOAT, + offset: FLOAT, + runHeight: FLOAT, + readingDirection: DWRITE_READING_DIRECTION, + flowDirection: DWRITE_FLOW_DIRECTION, + localeName: *const WCHAR, + measuringMode: DWRITE_MEASURING_MODE, +}} +STRUCT!{struct DWRITE_STRIKETHROUGH { + width: FLOAT, + thickness: FLOAT, + offset: FLOAT, + readingDirection: DWRITE_READING_DIRECTION, + flowDirection: DWRITE_FLOW_DIRECTION, + localeName: *const WCHAR, + measuringMode: DWRITE_MEASURING_MODE, +}} +STRUCT!{struct DWRITE_LINE_METRICS { + length: UINT32, + trailingWhitespaceLength: UINT32, + newlineLength: UINT32, + height: FLOAT, + baseline: FLOAT, + isTrimmed: BOOL, +}} +STRUCT!{struct DWRITE_CLUSTER_METRICS { + width: FLOAT, + length: UINT16, + bit_fields: UINT16, +}} +BITFIELD!{DWRITE_CLUSTER_METRICS bit_fields: UINT16 [ + canWrapLineAfter set_canWrapLineAfter[0..1], + isWhitespace set_isWhitespace[1..2], + isNewline set_isNewline[2..3], + isSoftHyphen set_isSoftHyphen[3..4], + isRightToLeft set_isRightToLeft[4..5], + padding set_padding[5..16], +]} +STRUCT!{struct DWRITE_TEXT_METRICS { + left: FLOAT, + top: FLOAT, + width: FLOAT, + widthIncludingTrailingWhitespace: FLOAT, + height: FLOAT, + layoutWidth: FLOAT, + layoutHeight: FLOAT, + maxBidiReorderingDepth: UINT32, + lineCount: UINT32, +}} +STRUCT!{struct DWRITE_INLINE_OBJECT_METRICS { + width: FLOAT, + height: FLOAT, + baseline: FLOAT, + supportsSideways: BOOL, +}} +STRUCT!{struct DWRITE_OVERHANG_METRICS { + left: FLOAT, + top: FLOAT, + right: FLOAT, + bottom: FLOAT, +}} +STRUCT!{struct DWRITE_HIT_TEST_METRICS { + textPosition: UINT32, + length: UINT32, + left: FLOAT, + top: FLOAT, + width: FLOAT, + height: FLOAT, + bidiLevel: UINT32, + isText: BOOL, + isTrimmed: BOOL, +}} +RIDL!{#[uuid(0x8339fde3, 0x106f, 0x47ab, 0x83, 0x73, 0x1c, 0x62, 0x95, 0xeb, 0x10, 0xb3)] +interface IDWriteInlineObject(IDWriteInlineObjectVtbl): IUnknown(IUnknownVtbl) { + fn Draw( + clientDrawingContext: *mut c_void, + renderer: *mut IDWriteTextRenderer, + originX: FLOAT, + originY: FLOAT, + isSideways: BOOL, + isRightToLeft: BOOL, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn GetMetrics( + metrics: *mut DWRITE_INLINE_OBJECT_METRICS, + ) -> HRESULT, + fn GetOverhangMetrics( + overhangs: *mut DWRITE_OVERHANG_METRICS, + ) -> HRESULT, + fn GetBreakConditions( + breakConditionBefore: *mut DWRITE_BREAK_CONDITION, + breakConditionAfter: *mut DWRITE_BREAK_CONDITION, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xeaf3a2da, 0xecf4, 0x4d24, 0xb6, 0x44, 0xb3, 0x4f, 0x68, 0x42, 0x02, 0x4b)] +interface IDWritePixelSnapping(IDWritePixelSnappingVtbl): IUnknown(IUnknownVtbl) { + fn IsPixelSnappingDisabled( + clientDrawingContext: *mut c_void, + isDisabled: *mut BOOL, + ) -> HRESULT, + fn GetCurrentTransform( + clientDrawingContext: *mut c_void, + transform: *mut DWRITE_MATRIX, + ) -> HRESULT, + fn GetPixelsPerDip( + clientDrawingContext: *mut c_void, + pixelsPerDip: *mut FLOAT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xef8a8135, 0x5cc6, 0x45fe, 0x88, 0x25, 0xc5, 0xa0, 0x72, 0x4e, 0xb8, 0x19)] +interface IDWriteTextRenderer(IDWriteTextRendererVtbl): + IDWritePixelSnapping(IDWritePixelSnappingVtbl) { + fn DrawGlyphRun( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + measuringMode: DWRITE_MEASURING_MODE, + glyphRun: *const DWRITE_GLYPH_RUN, + glyphRunDescription: *const DWRITE_GLYPH_RUN_DESCRIPTION, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawUnderline( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + underline: *const DWRITE_UNDERLINE, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawStrikethrough( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + strikethrough: *const DWRITE_STRIKETHROUGH, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawInlineObject( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + inlineObject: *mut IDWriteInlineObject, + isSideways: BOOL, + isRightToLeft: BOOL, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x53737037, 0x6d14, 0x410b, 0x9b, 0xfe, 0x0b, 0x18, 0x2b, 0xb7, 0x09, 0x61)] +interface IDWriteTextLayout(IDWriteTextLayoutVtbl): + IDWriteTextFormat(IDWriteTextFormatVtbl) { + fn SetMaxWidth( + maxWidth: FLOAT, + ) -> HRESULT, + fn SetMaxHeight( + maxHeight: FLOAT, + ) -> HRESULT, + fn SetFontCollection( + fontCollection: *mut IDWriteFontCollection, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetFontFamilyName( + fontFamilyName: *const WCHAR, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetFontWeight( + fontWeight: DWRITE_FONT_WEIGHT, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetFontStyle( + fontStyle: DWRITE_FONT_STYLE, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetFontStretch( + fontStretch: DWRITE_FONT_STRETCH, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetFontSize( + fontSize: FLOAT, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetUnderline( + hasUnderline: BOOL, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetStrikethrough( + hasStrikethrough: BOOL, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetDrawingEffect( + drawingEffect: *mut IUnknown, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetInlineObject( + inlineObject: *mut IDWriteInlineObject, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetTypography( + typography: *mut IDWriteTypography, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetLocaleName( + localeName: *const WCHAR, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetMaxWidth() -> FLOAT, + fn GetMaxHeight() -> FLOAT, + fn GetFontCollection( + currentPosition: UINT32, + fontCollection: *mut *mut IDWriteFontCollection, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontFamilyNameLength( + currentPosition: UINT32, + nameLength: *mut UINT32, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontFamilyName( + currentPosition: UINT32, + fontFamilyName: *mut WCHAR, + nameSize: UINT32, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontWeight( + currentPosition: UINT32, + fontWeight: *mut DWRITE_FONT_WEIGHT, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontStyle( + currentPosition: UINT32, + fontStyle: *mut DWRITE_FONT_STYLE, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontStretch( + currentPosition: UINT32, + fontStretch: *mut DWRITE_FONT_STRETCH, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetFontSize( + currentPosition: UINT32, + fontSize: *mut FLOAT, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetUnderline( + currentPosition: UINT32, + hasUnderline: *mut BOOL, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetStrikethrough( + currentPosition: UINT32, + hasStrikethrough: *mut BOOL, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetDrawingEffect( + currentPosition: UINT32, + drawingEffect: *mut *mut IUnknown, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetInlineObject( + currentPosition: UINT32, + inlineObject: *mut *mut IDWriteInlineObject, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetTypography( + currentPosition: UINT32, + typography: *mut *mut IDWriteTypography, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetLocaleNameLength( + currentPosition: UINT32, + nameLength: *mut UINT32, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetLocaleName( + currentPosition: UINT32, + localeName: *mut WCHAR, + nameSize: UINT32, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn Draw( + clientDrawingContext: *mut c_void, + renderer: *mut IDWriteTextRenderer, + originX: FLOAT, + originY: FLOAT, + ) -> HRESULT, + fn GetLineMetrics( + lineMetrics: *mut DWRITE_LINE_METRICS, + maxLineCount: UINT32, + actualLineCount: *mut UINT32, + ) -> HRESULT, + fn GetMetrics( + textMetrics: *mut DWRITE_TEXT_METRICS, + ) -> HRESULT, + fn GetOverhangMetrics( + overhangs: *mut DWRITE_OVERHANG_METRICS, + ) -> HRESULT, + fn GetClusterMetrics( + clusterMetrics: *mut DWRITE_CLUSTER_METRICS, + maxClusterCount: UINT32, + actualClusterCount: *mut UINT32, + ) -> HRESULT, + fn DetermineMinWidth( + minWidth: *mut FLOAT, + ) -> HRESULT, + fn HitTestPoint( + pointX: FLOAT, + pointY: FLOAT, + isTrailingHit: *mut BOOL, + isInside: *mut BOOL, + hitTestMetrics: *mut DWRITE_HIT_TEST_METRICS, + ) -> HRESULT, + fn HitTestTextPosition( + textPosition: UINT32, + isTrailingHit: BOOL, + pointX: *mut FLOAT, + pointY: *mut FLOAT, + hitTestMetrics: *mut DWRITE_HIT_TEST_METRICS, + ) -> HRESULT, + fn HitTestTextRange( + textPosition: UINT32, + textLength: UINT32, + originX: FLOAT, + originY: FLOAT, + hitTestMetrics: *mut DWRITE_HIT_TEST_METRICS, + maxHitTestMetricsCount: UINT32, + actualHitTestMetricsCount: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5e5a32a3, 0x8dff, 0x4773, 0x9f, 0xf6, 0x06, 0x96, 0xea, 0xb7, 0x72, 0x67)] +interface IDWriteBitmapRenderTarget(IDWriteBitmapRenderTargetVtbl): IUnknown(IUnknownVtbl) { + fn DrawGlyphRun( + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + measuringMode: DWRITE_MEASURING_MODE, + glyphRun: *const DWRITE_GLYPH_RUN, + renderingParams: *mut IDWriteRenderingParams, + textColor: COLORREF, + blackBoxRect: *mut RECT, + ) -> HRESULT, + fn GetMemoryDC() -> HDC, + fn GetPixelsPerDip() -> FLOAT, + fn SetPixelsPerDip( + pixelsPerDip: FLOAT, + ) -> HRESULT, + fn GetCurrentTransform( + transform: *mut DWRITE_MATRIX, + ) -> HRESULT, + fn SetCurrentTransform( + transform: *const DWRITE_MATRIX, + ) -> HRESULT, + fn GetSize( + size: *mut SIZE, + ) -> HRESULT, + fn Resize( + width: UINT32, + height: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1edd9491, 0x9853, 0x4299, 0x89, 0x8f, 0x64, 0x32, 0x98, 0x3b, 0x6f, 0x3a)] +interface IDWriteGdiInterop(IDWriteGdiInteropVtbl): IUnknown(IUnknownVtbl) { + fn CreateFontFromLOGFONT( + logFont: *const LOGFONTW, + font: *mut *mut IDWriteFont, + ) -> HRESULT, + fn ConvertFontToLOGFONT( + font: *mut IDWriteFont, + logFont: *mut LOGFONTW, + isSystemFont: *mut BOOL, + ) -> HRESULT, + fn ConvertFontFaceToLOGFONT( + font: *mut IDWriteFontFace, + logFont: *mut LOGFONTW, + ) -> HRESULT, + fn CreateFontFaceFromHdc( + hdc: HDC, + fontFace: *mut *mut IDWriteFontFace, + ) -> HRESULT, + fn CreateBitmapRenderTarget( + hdc: HDC, + width: UINT32, + height: UINT32, + renderTarget: *mut *mut IDWriteBitmapRenderTarget, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_TEXTURE_TYPE { + DWRITE_TEXTURE_ALIASED_1x1 = 0, + DWRITE_TEXTURE_CLEARTYPE_3x1 = 1, +}} +pub const DWRITE_ALPHA_MAX: BYTE = 255; +RIDL!{#[uuid(0x7d97dbf7, 0xe085, 0x42d4, 0x81, 0xe3, 0x6a, 0x88, 0x3b, 0xde, 0xd1, 0x18)] +interface IDWriteGlyphRunAnalysis(IDWriteGlyphRunAnalysisVtbl): IUnknown(IUnknownVtbl) { + fn GetAlphaTextureBounds( + textureType: DWRITE_TEXTURE_TYPE, + textureBounds: *mut RECT, + ) -> HRESULT, + fn CreateAlphaTexture( + textureType: DWRITE_TEXTURE_TYPE, + textureBounds: *const RECT, + alphaValues: *mut BYTE, + bufferSize: UINT32, + ) -> HRESULT, + fn GetAlphaBlendParams( + renderingParams: *mut IDWriteRenderingParams, + blendGamma: *mut FLOAT, + blendEnhancedContrast: *mut FLOAT, + blendClearTypeLevel: *mut FLOAT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48)] +interface IDWriteFactory(IDWriteFactoryVtbl): IUnknown(IUnknownVtbl) { + fn GetSystemFontCollection( + fontCollection: *mut *mut IDWriteFontCollection, + checkForUpdates: BOOL, + ) -> HRESULT, + fn CreateCustomFontCollection( + collectionLoader: *mut IDWriteFontCollectionLoader, + collectionKey: *const c_void, + collectionKeySize: UINT32, + fontCollection: *mut *mut IDWriteFontCollection, + ) -> HRESULT, + fn RegisterFontCollectionLoader( + fontCollectionLoader: *mut IDWriteFontCollectionLoader, + ) -> HRESULT, + fn UnregisterFontCollectionLoader( + fontCollectionLoader: *mut IDWriteFontCollectionLoader, + ) -> HRESULT, + fn CreateFontFileReference( + filePath: *const WCHAR, + lastWriteTime: *const FILETIME, + fontFile: *mut *mut IDWriteFontFile, + ) -> HRESULT, + fn CreateCustomFontFileReference( + fontFileReferenceKey: *const c_void, + fontFileReferenceKeySize: UINT32, + fontFileLoader: *mut IDWriteFontFileLoader, + fontFile: *mut *mut IDWriteFontFile, + ) -> HRESULT, + fn CreateFontFace( + fontFaceType: DWRITE_FONT_FACE_TYPE, + numberOfFiles: UINT32, + fontFiles: *const *mut IDWriteFontFile, + faceIndex: UINT32, + fontFaceSimulationFlags: DWRITE_FONT_SIMULATIONS, + fontFace: *mut *mut IDWriteFontFace, + ) -> HRESULT, + fn CreateRenderingParams( + renderingParams: *mut *mut IDWriteRenderingParams, + ) -> HRESULT, + fn CreateMonitorRenderingParams( + monitor: HMONITOR, + renderingParams: *mut *mut IDWriteRenderingParams, + ) -> HRESULT, + fn CreateCustomRenderingParams( + gamma: FLOAT, + enhancedContrast: FLOAT, + clearTypeLevel: FLOAT, + pixelGeometry: DWRITE_PIXEL_GEOMETRY, + renderingMode: DWRITE_RENDERING_MODE, + renderingParams: *mut *mut IDWriteRenderingParams, + ) -> HRESULT, + fn RegisterFontFileLoader( + fontFileLoader: *mut IDWriteFontFileLoader, + ) -> HRESULT, + fn UnregisterFontFileLoader( + fontFileLoader: *mut IDWriteFontFileLoader, + ) -> HRESULT, + fn CreateTextFormat( + fontFamilyName: *const WCHAR, + fontCollection: *mut IDWriteFontCollection, + fontWeight: DWRITE_FONT_WEIGHT, + fontStyle: DWRITE_FONT_STYLE, + fontStretch: DWRITE_FONT_STRETCH, + fontSize: FLOAT, + localeName: *const WCHAR, + textFormat: *mut *mut IDWriteTextFormat, + ) -> HRESULT, + fn CreateTypography( + typography: *mut *mut IDWriteTypography, + ) -> HRESULT, + fn GetGdiInterop( + gdiInterop: *mut *mut IDWriteGdiInterop, + ) -> HRESULT, + fn CreateTextLayout( + string: *const WCHAR, + stringLength: UINT32, + textFormat: *mut IDWriteTextFormat, + maxWidth: FLOAT, + maxHeight: FLOAT, + textLayout: *mut *mut IDWriteTextLayout, + ) -> HRESULT, + fn CreateGdiCompatibleTextLayout( + string: *const WCHAR, + stringLength: UINT32, + textFormat: *mut IDWriteTextFormat, + layoutWidth: FLOAT, + layoutHeight: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + useGdiNatrual: BOOL, + textLayout: *mut *mut IDWriteTextLayout, + ) -> HRESULT, + fn CreateEllipsisTrimmingSign( + textFormat: *mut IDWriteTextFormat, + trimmingSign: *mut *mut IDWriteInlineObject, + ) -> HRESULT, + fn CreateTextAnalyzer( + textAnalyzer: *mut *mut IDWriteTextAnalyzer, + ) -> HRESULT, + fn CreateNumberSubstitution( + substitutionMethod: DWRITE_NUMBER_SUBSTITUTION_METHOD, + localeName: *const WCHAR, + ignoreUserOverride: BOOL, + numberSubstitution: *mut *mut IDWriteNumberSubstitution, + ) -> HRESULT, + fn CreateGlyphRunAnalysis( + glyphRun: *const DWRITE_GLYPH_RUN, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + renderingMode: DWRITE_RENDERING_MODE, + measuringMode: DWRITE_MEASURING_MODE, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + glyphRunAnalysis: *mut *mut IDWriteGlyphRunAnalysis, + ) -> HRESULT, +}} +pub const FACILITY_DWRITE: HRESULT = 0x898; +pub const DWRITE_ERR_BASE: HRESULT = 0x5000; +#[inline] +pub fn MAKE_DWRITE_HR(severity: HRESULT, code: HRESULT) -> HRESULT { + MAKE_HRESULT!(severity, FACILITY_DWRITE, DWRITE_ERR_BASE + code) +} +#[inline] +pub fn MAKE_DWRITE_HR_ERR(code: HRESULT) -> HRESULT { + MAKE_DWRITE_HR(SEVERITY_ERROR, code) +} +extern "system" { + pub fn DWriteCreateFactory( + factoryType: DWRITE_FACTORY_TYPE, iid: REFIID, factory: *mut *mut IUnknown, + ) -> HRESULT; +} diff --git a/winapi/src/um/dwrite_1.rs b/winapi/src/um/dwrite_1.rs new file mode 100644 index 000000000..b762bbdcb --- /dev/null +++ b/winapi/src/um/dwrite_1.rs @@ -0,0 +1,746 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the content of dwrite_1.h +use shared::basetsd::{INT16, INT32, UINT16, UINT32, UINT8}; +use shared::minwindef::{BOOL, FLOAT}; +use um::dcommon::DWRITE_MEASURING_MODE; +use um::dwrite::{ + DWRITE_GLYPH_OFFSET, DWRITE_MATRIX, DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE, + DWRITE_SCRIPT_ANALYSIS, DWRITE_SHAPING_GLYPH_PROPERTIES, DWRITE_TEXT_RANGE, + IDWriteBitmapRenderTarget, IDWriteBitmapRenderTargetVtbl, IDWriteFactory, IDWriteFactoryVtbl, + IDWriteFont, IDWriteFontCollection, IDWriteFontFace, IDWriteFontFaceVtbl, IDWriteFontVtbl, + IDWriteRenderingParams, IDWriteRenderingParamsVtbl, IDWriteTextAnalysisSink, + IDWriteTextAnalysisSinkVtbl, IDWriteTextAnalysisSource, IDWriteTextAnalysisSourceVtbl, + IDWriteTextAnalyzer, IDWriteTextAnalyzerVtbl, IDWriteTextLayout, IDWriteTextLayoutVtbl, +}; +use um::winnt::{HRESULT, WCHAR}; +ENUM!{enum DWRITE_PANOSE_FAMILY { + DWRITE_PANOSE_FAMILY_ANY = 0x0, // 0 + DWRITE_PANOSE_FAMILY_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_FAMILY_TEXT_DISPLAY = 0x2, // 2 + DWRITE_PANOSE_FAMILY_SCRIPT = 0x3, // 3 + DWRITE_PANOSE_FAMILY_DECORATIVE = 0x4, // 4 + DWRITE_PANOSE_FAMILY_SYMBOL = 0x5, // 5 + DWRITE_PANOSE_FAMILY_PICTORIAL = 0x5, // 5 +}} +ENUM!{enum DWRITE_PANOSE_SERIF_STYLE { + DWRITE_PANOSE_SERIF_STYLE_ANY = 0x0, // 0 + DWRITE_PANOSE_SERIF_STYLE_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SERIF_STYLE_COVE = 0x2, // 2 + DWRITE_PANOSE_SERIF_STYLE_OBTUSE_COVE = 0x3, // 3 + DWRITE_PANOSE_SERIF_STYLE_SQUARE_COVE = 0x4, // 4 + DWRITE_PANOSE_SERIF_STYLE_OBTUSE_SQUARE_COVE = 0x5, // 5 + DWRITE_PANOSE_SERIF_STYLE_SQUARE = 0x6, // 6 + DWRITE_PANOSE_SERIF_STYLE_THIN = 0x7, // 7 + DWRITE_PANOSE_SERIF_STYLE_OVAL = 0x8, // 8 + DWRITE_PANOSE_SERIF_STYLE_EXAGGERATED = 0x9, // 9 + DWRITE_PANOSE_SERIF_STYLE_TRIANGLE = 0xA, // 10 + DWRITE_PANOSE_SERIF_STYLE_NORMAL_SANS = 0xB, // 11 + DWRITE_PANOSE_SERIF_STYLE_OBTUSE_SANS = 0xC, // 12 + DWRITE_PANOSE_SERIF_STYLE_PERPENDICULAR_SANS = 0xD, // 13 + DWRITE_PANOSE_SERIF_STYLE_FLARED = 0xE, // 14 + DWRITE_PANOSE_SERIF_STYLE_ROUNDED = 0xF, // 15 + DWRITE_PANOSE_SERIF_STYLE_SCRIPT = 0x10, // 16 + DWRITE_PANOSE_SERIF_STYLE_PERP_SANS = 0xD, // 13 + DWRITE_PANOSE_SERIF_STYLE_BONE = 0x8, // 8 +}} +ENUM!{enum DWRITE_PANOSE_WEIGHT { + DWRITE_PANOSE_WEIGHT_ANY = 0x0, // 0 + DWRITE_PANOSE_WEIGHT_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_WEIGHT_VERY_LIGHT = 0x2, // 2 + DWRITE_PANOSE_WEIGHT_LIGHT = 0x3, // 3 + DWRITE_PANOSE_WEIGHT_THIN = 0x4, // 4 + DWRITE_PANOSE_WEIGHT_BOOK = 0x5, // 5 + DWRITE_PANOSE_WEIGHT_MEDIUM = 0x6, // 6 + DWRITE_PANOSE_WEIGHT_DEMI = 0x7, // 7 + DWRITE_PANOSE_WEIGHT_BOLD = 0x8, // 8 + DWRITE_PANOSE_WEIGHT_HEAVY = 0x9, // 9 + DWRITE_PANOSE_WEIGHT_BLACK = 0xA, // 10 + DWRITE_PANOSE_WEIGHT_EXTRA_BLACK = 0xB, // 11 + DWRITE_PANOSE_WEIGHT_NORD = 0xB, // 11 +}} +ENUM!{enum DWRITE_PANOSE_PROPORTION { + DWRITE_PANOSE_PROPORTION_ANY = 0x0, // 0 + DWRITE_PANOSE_PROPORTION_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_PROPORTION_OLD_STYLE = 0x2, // 2 + DWRITE_PANOSE_PROPORTION_MODERN = 0x3, // 3 + DWRITE_PANOSE_PROPORTION_EVEN_WIDTH = 0x4, // 4 + DWRITE_PANOSE_PROPORTION_EXPANDED = 0x5, // 5 + DWRITE_PANOSE_PROPORTION_CONDENSED = 0x6, // 6 + DWRITE_PANOSE_PROPORTION_VERY_EXPANDED = 0x7, // 7 + DWRITE_PANOSE_PROPORTION_VERY_CONDENSED = 0x8, // 8 + DWRITE_PANOSE_PROPORTION_MONOSPACED = 0x9, // 9 +}} +ENUM!{enum DWRITE_PANOSE_CONTRAST { + DWRITE_PANOSE_CONTRAST_ANY = 0x0, // 0 + DWRITE_PANOSE_CONTRAST_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_CONTRAST_NONE = 0x2, // 2 + DWRITE_PANOSE_CONTRAST_VERY_LOW = 0x3, // 3 + DWRITE_PANOSE_CONTRAST_LOW = 0x4, // 4 + DWRITE_PANOSE_CONTRAST_MEDIUM_LOW = 0x5, // 5 + DWRITE_PANOSE_CONTRAST_MEDIUM = 0x6, // 6 + DWRITE_PANOSE_CONTRAST_MEDIUM_HIGH = 0x7, // 7 + DWRITE_PANOSE_CONTRAST_HIGH = 0x8, // 8 + DWRITE_PANOSE_CONTRAST_VERY_HIGH = 0x9, // 9 + DWRITE_PANOSE_CONTRAST_HORIZONTAL_LOW = 0xA, // 10 + DWRITE_PANOSE_CONTRAST_HORIZONTAL_MEDIUM = 0xB, // 11 + DWRITE_PANOSE_CONTRAST_HORIZONTAL_HIGH = 0xC, // 12 + DWRITE_PANOSE_CONTRAST_BROKEN = 0xD, // 13 +}} +ENUM!{enum DWRITE_PANOSE_STROKE_VARIATION { + DWRITE_PANOSE_STROKE_VARIATION_ANY = 0x0, // 0 + DWRITE_PANOSE_STROKE_VARIATION_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_STROKE_VARIATION_NO_VARIATION = 0x2, // 2 + DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_DIAGONAL = 0x3, // 3 + DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_TRANSITIONAL = 0x4, // 4 + DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_VERTICAL = 0x5, // 5 + DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_HORIZONTAL = 0x6, // 6 + DWRITE_PANOSE_STROKE_VARIATION_RAPID_VERTICAL = 0x7, // 7 + DWRITE_PANOSE_STROKE_VARIATION_RAPID_HORIZONTAL = 0x8, // 8 + DWRITE_PANOSE_STROKE_VARIATION_INSTANT_VERTICAL = 0x9, // 9 + DWRITE_PANOSE_STROKE_VARIATION_INSTANT_HORIZONTAL = 0xA, // 10 +}} +ENUM!{enum DWRITE_PANOSE_ARM_STYLE { + DWRITE_PANOSE_ARM_STYLE_ANY = 0x0, // 0 + DWRITE_PANOSE_ARM_STYLE_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_HORIZONTAL = 0x2, // 2 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_WEDGE = 0x3, // 3 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_VERTICAL = 0x4, // 4 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_SINGLE_SERIF = 0x5, // 5 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_DOUBLE_SERIF = 0x6, // 6 + DWRITE_PANOSE_ARM_STYLE_NONSTRAIGHT_ARMS_HORIZONTAL = 0x7, // 7 + DWRITE_PANOSE_ARM_STYLE_NONSTRAIGHT_ARMS_WEDGE = 0x8, // 8 + DWRITE_PANOSE_ARM_STYLE_NONSTRAIGHT_ARMS_VERTICAL = 0x9, // 9 + DWRITE_PANOSE_ARM_STYLE_NONSTRAIGHT_ARMS_SINGLE_SERIF = 0xA, // 10 + DWRITE_PANOSE_ARM_STYLE_NONSTRAIGHT_ARMS_DOUBLE_SERIF = 0xB, // 11 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_HORZ = 0x2, // 2 + DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_VERT = 0x4, // 4 + DWRITE_PANOSE_ARM_STYLE_BENT_ARMS_HORZ = 0x7, // 7 + DWRITE_PANOSE_ARM_STYLE_BENT_ARMS_WEDGE = 0x8, // 8 + DWRITE_PANOSE_ARM_STYLE_BENT_ARMS_VERT = 0x9, // 9 + DWRITE_PANOSE_ARM_STYLE_BENT_ARMS_SINGLE_SERIF = 0xA, // 10 + DWRITE_PANOSE_ARM_STYLE_BENT_ARMS_DOUBLE_SERIF = 0xB, // 11 +}} +ENUM!{enum DWRITE_PANOSE_LETTERFORM { + DWRITE_PANOSE_LETTERFORM_ANY = 0x0, // 0 + DWRITE_PANOSE_LETTERFORM_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_LETTERFORM_NORMAL_CONTACT = 0x2, // 2 + DWRITE_PANOSE_LETTERFORM_NORMAL_WEIGHTED = 0x3, // 3 + DWRITE_PANOSE_LETTERFORM_NORMAL_BOXED = 0x4, // 4 + DWRITE_PANOSE_LETTERFORM_NORMAL_FLATTENED = 0x5, // 5 + DWRITE_PANOSE_LETTERFORM_NORMAL_ROUNDED = 0x6, // 6 + DWRITE_PANOSE_LETTERFORM_NORMAL_OFF_CENTER = 0x7, // 7 + DWRITE_PANOSE_LETTERFORM_NORMAL_SQUARE = 0x8, // 8 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_CONTACT = 0x9, // 9 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_WEIGHTED = 0xA, // 10 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_BOXED = 0xB, // 11 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_FLATTENED = 0xC, // 12 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_ROUNDED = 0xD, // 13 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_OFF_CENTER = 0xE, // 14 + DWRITE_PANOSE_LETTERFORM_OBLIQUE_SQUARE = 0xF, // 15 +}} +ENUM!{enum DWRITE_PANOSE_MIDLINE { + DWRITE_PANOSE_MIDLINE_ANY = 0x0, // 0 + DWRITE_PANOSE_MIDLINE_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_MIDLINE_STANDARD_TRIMMED = 0x2, // 2 + DWRITE_PANOSE_MIDLINE_STANDARD_POINTED = 0x3, // 3 + DWRITE_PANOSE_MIDLINE_STANDARD_SERIFED = 0x4, // 4 + DWRITE_PANOSE_MIDLINE_HIGH_TRIMMED = 0x5, // 5 + DWRITE_PANOSE_MIDLINE_HIGH_POINTED = 0x6, // 6 + DWRITE_PANOSE_MIDLINE_HIGH_SERIFED = 0x7, // 7 + DWRITE_PANOSE_MIDLINE_CONSTANT_TRIMMED = 0x8, // 8 + DWRITE_PANOSE_MIDLINE_CONSTANT_POINTED = 0x9, // 9 + DWRITE_PANOSE_MIDLINE_CONSTANT_SERIFED = 0xA, // 10 + DWRITE_PANOSE_MIDLINE_LOW_TRIMMED = 0xB, // 11 + DWRITE_PANOSE_MIDLINE_LOW_POINTED = 0xC, // 12 + DWRITE_PANOSE_MIDLINE_LOW_SERIFED = 0xD, // 13 +}} +ENUM!{enum DWRITE_PANOSE_XHEIGHT { + DWRITE_PANOSE_XHEIGHT_ANY = 0x0, // 0 + DWRITE_PANOSE_XHEIGHT_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_XHEIGHT_CONSTANT_SMALL = 0x2, // 2 + DWRITE_PANOSE_XHEIGHT_CONSTANT_STANDARD = 0x3, // 3 + DWRITE_PANOSE_XHEIGHT_CONSTANT_LARGE = 0x4, // 4 + DWRITE_PANOSE_XHEIGHT_DUCKING_SMALL = 0x5, // 5 + DWRITE_PANOSE_XHEIGHT_DUCKING_STANDARD = 0x6, // 6 + DWRITE_PANOSE_XHEIGHT_DUCKING_LARGE = 0x7, // 7 + DWRITE_PANOSE_XHEIGHT_CONSTANT_STD = 0x3, // 3 + DWRITE_PANOSE_XHEIGHT_DUCKING_STD = 0x6, // 6 +}} +ENUM!{enum DWRITE_PANOSE_TOOL_KIND { + DWRITE_PANOSE_TOOL_KIND_ANY = 0x0, // 0 + DWRITE_PANOSE_TOOL_KIND_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_TOOL_KIND_FLAT_NIB = 0x2, // 2 + DWRITE_PANOSE_TOOL_KIND_PRESSURE_POINT = 0x3, // 3 + DWRITE_PANOSE_TOOL_KIND_ENGRAVED = 0x4, // 4 + DWRITE_PANOSE_TOOL_KIND_BALL = 0x5, // 5 + DWRITE_PANOSE_TOOL_KIND_BRUSH = 0x6, // 6 + DWRITE_PANOSE_TOOL_KIND_ROUGH = 0x7, // 7 + DWRITE_PANOSE_TOOL_KIND_FELT_PEN_BRUSH_TIP = 0x8, // 8 + DWRITE_PANOSE_TOOL_KIND_WILD_BRUSH = 0x9, // 9 +}} +ENUM!{enum DWRITE_PANOSE_SPACING { + DWRITE_PANOSE_SPACING_ANY = 0x0, // 0 + DWRITE_PANOSE_SPACING_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SPACING_PROPORTIONAL_SPACED = 0x2, // 2 + DWRITE_PANOSE_SPACING_MONOSPACED = 0x3, // 3 +}} +ENUM!{enum DWRITE_PANOSE_ASPECT_RATIO { + DWRITE_PANOSE_ASPECT_RATIO_ANY = 0x0, // 0 + DWRITE_PANOSE_ASPECT_RATIO_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_ASPECT_RATIO_VERY_CONDENSED = 0x2, // 2 + DWRITE_PANOSE_ASPECT_RATIO_CONDENSED = 0x3, // 3 + DWRITE_PANOSE_ASPECT_RATIO_NORMAL = 0x4, // 4 + DWRITE_PANOSE_ASPECT_RATIO_EXPANDED = 0x5, // 5 + DWRITE_PANOSE_ASPECT_RATIO_VERY_EXPANDED = 0x6, // 6 +}} +ENUM!{enum DWRITE_PANOSE_SCRIPT_TOPOLOGY { + DWRITE_PANOSE_SCRIPT_TOPOLOGY_ANY = 0x0, // 0 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_ROMAN_DISCONNECTED = 0x2, // 2 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_ROMAN_TRAILING = 0x3, // 3 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_ROMAN_CONNECTED = 0x4, // 4 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_CURSIVE_DISCONNECTED = 0x5, // 5 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_CURSIVE_TRAILING = 0x6, // 6 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_CURSIVE_CONNECTED = 0x7, // 7 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_BLACKLETTER_DISCONNECTED = 0x8, // 8 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_BLACKLETTER_TRAILING = 0x9, // 9 + DWRITE_PANOSE_SCRIPT_TOPOLOGY_BLACKLETTER_CONNECTED = 0xA, // 10 +}} +ENUM!{enum DWRITE_PANOSE_SCRIPT_FORM { + DWRITE_PANOSE_SCRIPT_FORM_ANY = 0x0, // 0 + DWRITE_PANOSE_SCRIPT_FORM_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SCRIPT_FORM_UPRIGHT_NO_WRAPPING = 0x2, // 2 + DWRITE_PANOSE_SCRIPT_FORM_UPRIGHT_SOME_WRAPPING = 0x3, // 3 + DWRITE_PANOSE_SCRIPT_FORM_UPRIGHT_MORE_WRAPPING = 0x4, // 4 + DWRITE_PANOSE_SCRIPT_FORM_UPRIGHT_EXTREME_WRAPPING = 0x5, // 5 + DWRITE_PANOSE_SCRIPT_FORM_OBLIQUE_NO_WRAPPING = 0x6, // 6 + DWRITE_PANOSE_SCRIPT_FORM_OBLIQUE_SOME_WRAPPING = 0x7, // 7 + DWRITE_PANOSE_SCRIPT_FORM_OBLIQUE_MORE_WRAPPING = 0x8, // 8 + DWRITE_PANOSE_SCRIPT_FORM_OBLIQUE_EXTREME_WRAPPING = 0x9, // 9 + DWRITE_PANOSE_SCRIPT_FORM_EXAGGERATED_NO_WRAPPING = 0xA, // 10 + DWRITE_PANOSE_SCRIPT_FORM_EXAGGERATED_SOME_WRAPPING = 0xB, // 11 + DWRITE_PANOSE_SCRIPT_FORM_EXAGGERATED_MORE_WRAPPING = 0xC, // 12 + DWRITE_PANOSE_SCRIPT_FORM_EXAGGERATED_EXTREME_WRAPPING = 0xD, // 13 +}} +ENUM!{enum DWRITE_PANOSE_FINIALS { + DWRITE_PANOSE_FINIALS_ANY = 0x0, // 0 + DWRITE_PANOSE_FINIALS_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_FINIALS_NONE_NO_LOOPS = 0x2, // 2 + DWRITE_PANOSE_FINIALS_NONE_CLOSED_LOOPS = 0x3, // 3 + DWRITE_PANOSE_FINIALS_NONE_OPEN_LOOPS = 0x4, // 4 + DWRITE_PANOSE_FINIALS_SHARP_NO_LOOPS = 0x5, // 5 + DWRITE_PANOSE_FINIALS_SHARP_CLOSED_LOOPS = 0x6, // 6 + DWRITE_PANOSE_FINIALS_SHARP_OPEN_LOOPS = 0x7, // 7 + DWRITE_PANOSE_FINIALS_TAPERED_NO_LOOPS = 0x8, // 8 + DWRITE_PANOSE_FINIALS_TAPERED_CLOSED_LOOPS = 0x9, // 9 + DWRITE_PANOSE_FINIALS_TAPERED_OPEN_LOOPS = 0xA, // 10 + DWRITE_PANOSE_FINIALS_ROUND_NO_LOOPS = 0xB, // 11 + DWRITE_PANOSE_FINIALS_ROUND_CLOSED_LOOPS = 0xC, // 12 + DWRITE_PANOSE_FINIALS_ROUND_OPEN_LOOPS = 0xD, // 13 +}} +ENUM!{enum DWRITE_PANOSE_XASCENT { + DWRITE_PANOSE_XASCENT_ANY = 0x0, // 0 + DWRITE_PANOSE_XASCENT_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_XASCENT_VERY_LOW = 0x2, // 2 + DWRITE_PANOSE_XASCENT_LOW = 0x3, // 3 + DWRITE_PANOSE_XASCENT_MEDIUM = 0x4, // 4 + DWRITE_PANOSE_XASCENT_HIGH = 0x5, // 5 + DWRITE_PANOSE_XASCENT_VERY_HIGH = 0x6, // 6 +}} +ENUM!{enum DWRITE_PANOSE_DECORATIVE_CLASS { + DWRITE_PANOSE_DECORATIVE_CLASS_ANY = 0x0, // 0 + DWRITE_PANOSE_DECORATIVE_CLASS_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_DECORATIVE_CLASS_DERIVATIVE = 0x2, // 2 + DWRITE_PANOSE_DECORATIVE_CLASS_NONSTANDARD_TOPOLOGY = 0x3, // 3 + DWRITE_PANOSE_DECORATIVE_CLASS_NONSTANDARD_ELEMENTS = 0x4, // 4 + DWRITE_PANOSE_DECORATIVE_CLASS_NONSTANDARD_ASPECT = 0x5, // 5 + DWRITE_PANOSE_DECORATIVE_CLASS_INITIALS = 0x6, // 6 + DWRITE_PANOSE_DECORATIVE_CLASS_CARTOON = 0x7, // 7 + DWRITE_PANOSE_DECORATIVE_CLASS_PICTURE_STEMS = 0x8, // 8 + DWRITE_PANOSE_DECORATIVE_CLASS_ORNAMENTED = 0x9, // 9 + DWRITE_PANOSE_DECORATIVE_CLASS_TEXT_AND_BACKGROUND = 0xA, // 10 + DWRITE_PANOSE_DECORATIVE_CLASS_COLLAGE = 0xB, // 11 + DWRITE_PANOSE_DECORATIVE_CLASS_MONTAGE = 0xC, // 12 +}} +ENUM!{enum DWRITE_PANOSE_ASPECT { + DWRITE_PANOSE_ASPECT_ANY = 0x0, // 0 + DWRITE_PANOSE_ASPECT_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_ASPECT_SUPER_CONDENSED = 0x2, // 2 + DWRITE_PANOSE_ASPECT_VERY_CONDENSED = 0x3, // 3 + DWRITE_PANOSE_ASPECT_CONDENSED = 0x4, // 4 + DWRITE_PANOSE_ASPECT_NORMAL = 0x5, // 5 + DWRITE_PANOSE_ASPECT_EXTENDED = 0x6, // 6 + DWRITE_PANOSE_ASPECT_VERY_EXTENDED = 0x7, // 7 + DWRITE_PANOSE_ASPECT_SUPER_EXTENDED = 0x8, // 8 + DWRITE_PANOSE_ASPECT_MONOSPACED = 0x9, // 9 +}} +ENUM!{enum DWRITE_PANOSE_FILL { + DWRITE_PANOSE_FILL_ANY = 0x0, // 0 + DWRITE_PANOSE_FILL_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_FILL_STANDARD_SOLID_FILL = 0x2, // 2 + DWRITE_PANOSE_FILL_NO_FILL = 0x3, // 3 + DWRITE_PANOSE_FILL_PATTERNED_FILL = 0x4, // 4 + DWRITE_PANOSE_FILL_COMPLEX_FILL = 0x5, // 5 + DWRITE_PANOSE_FILL_SHAPED_FILL = 0x6, // 6 + DWRITE_PANOSE_FILL_DRAWN_DISTRESSED = 0x7, // 7 +}} +ENUM!{enum DWRITE_PANOSE_LINING { + DWRITE_PANOSE_LINING_ANY = 0x0, // 0 + DWRITE_PANOSE_LINING_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_LINING_NONE = 0x2, // 2 + DWRITE_PANOSE_LINING_INLINE = 0x3, // 3 + DWRITE_PANOSE_LINING_OUTLINE = 0x4, // 4 + DWRITE_PANOSE_LINING_ENGRAVED = 0x5, // 5 + DWRITE_PANOSE_LINING_SHADOW = 0x6, // 6 + DWRITE_PANOSE_LINING_RELIEF = 0x7, // 7 + DWRITE_PANOSE_LINING_BACKDROP = 0x8, // 8 +}} +ENUM!{enum DWRITE_PANOSE_DECORATIVE_TOPOLOGY { + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_ANY = 0x0, // 0 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_STANDARD = 0x2, // 2 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_SQUARE = 0x3, // 3 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_MULTIPLE_SEGMENT = 0x4, // 4 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_ART_DECO = 0x5, // 5 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_UNEVEN_WEIGHTING = 0x6, // 6 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_DIVERSE_ARMS = 0x7, // 7 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_DIVERSE_FORMS = 0x8, // 8 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_LOMBARDIC_FORMS = 0x9, // 9 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_UPPER_CASE_IN_LOWER_CASE = 0xA, // 10 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_IMPLIED_TOPOLOGY = 0xB, // 11 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_HORSESHOE_E_AND_A = 0xC, // 12 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_CURSIVE = 0xD, // 13 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_BLACKLETTER = 0xE, // 14 + DWRITE_PANOSE_DECORATIVE_TOPOLOGY_SWASH_VARIANCE = 0xF, // 15 +}} +ENUM!{enum DWRITE_PANOSE_CHARACTER_RANGES { + DWRITE_PANOSE_CHARACTER_RANGES_ANY = 0x0, // 0 + DWRITE_PANOSE_CHARACTER_RANGES_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_CHARACTER_RANGES_EXTENDED_COLLECTION = 0x2, // 2 + DWRITE_PANOSE_CHARACTER_RANGES_LITERALS = 0x3, // 3 + DWRITE_PANOSE_CHARACTER_RANGES_NO_LOWER_CASE = 0x4, // 4 + DWRITE_PANOSE_CHARACTER_RANGES_SMALL_CAPS = 0x5, // 5 +}} +ENUM!{enum DWRITE_PANOSE_SYMBOL_KIND { + DWRITE_PANOSE_SYMBOL_KIND_ANY = 0x0, // 0 + DWRITE_PANOSE_SYMBOL_KIND_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SYMBOL_KIND_MONTAGES = 0x2, // 2 + DWRITE_PANOSE_SYMBOL_KIND_PICTURES = 0x3, // 3 + DWRITE_PANOSE_SYMBOL_KIND_SHAPES = 0x4, // 4 + DWRITE_PANOSE_SYMBOL_KIND_SCIENTIFIC = 0x5, // 5 + DWRITE_PANOSE_SYMBOL_KIND_MUSIC = 0x6, // 6 + DWRITE_PANOSE_SYMBOL_KIND_EXPERT = 0x7, // 7 + DWRITE_PANOSE_SYMBOL_KIND_PATTERNS = 0x8, // 8 + DWRITE_PANOSE_SYMBOL_KIND_BOARDERS = 0x9, // 9 + DWRITE_PANOSE_SYMBOL_KIND_ICONS = 0xA, // 10 + DWRITE_PANOSE_SYMBOL_KIND_LOGOS = 0xB, // 11 + DWRITE_PANOSE_SYMBOL_KIND_INDUSTRY_SPECIFIC = 0xC, // 12 +}} +ENUM!{enum DWRITE_PANOSE_SYMBOL_ASPECT_RATIO { + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_ANY = 0x0, // 0 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_NO_FIT = 0x1, // 1 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_NO_WIDTH = 0x2, // 2 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_EXCEPTIONALLY_WIDE = 0x3, // 3 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_SUPER_WIDE = 0x4, // 4 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_VERY_WIDE = 0x5, // 5 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_WIDE = 0x6, // 6 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_NORMAL = 0x7, // 7 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_NARROW = 0x8, // 8 + DWRITE_PANOSE_SYMBOL_ASPECT_RATIO_VERY_NARROW = 0x9, // 9 +}} +ENUM!{enum DWRITE_OUTLINE_THRESHOLD { + DWRITE_OUTLINE_THRESHOLD_ANTIALIASED = 0x0, // 0 + DWRITE_OUTLINE_THRESHOLD_ALIASED = 0x1, // 1 +}} +ENUM!{enum DWRITE_BASELINE { + DWRITE_BASELINE_DEFAULT = 0x0, // 0 + DWRITE_BASELINE_ROMAN = 0x1, // 1 + DWRITE_BASELINE_CENTRAL = 0x2, // 2 + DWRITE_BASELINE_MATH = 0x3, // 3 + DWRITE_BASELINE_HANGING = 0x4, // 4 + DWRITE_BASELINE_IDEOGRAPHIC_BOTTOM = 0x5, // 5 + DWRITE_BASELINE_IDEOGRAPHIC_TOP = 0x6, // 6 + DWRITE_BASELINE_MINIMUM = 0x7, // 7 + DWRITE_BASELINE_MAXIMUM = 0x8, // 8 +}} +ENUM!{enum DWRITE_VERTICAL_GLYPH_ORIENTATION { + DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT = 0x0, // 0 + DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED = 0x1, // 1 +}} +ENUM!{enum DWRITE_GLYPH_ORIENTATION_ANGLE { + DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES = 0x0, // 0 + DWRITE_GLYPH_ORIENTATION_ANGLE_90_DEGREES = 0x1, // 1 + DWRITE_GLYPH_ORIENTATION_ANGLE_180_DEGREES = 0x2, // 2 + DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES = 0x3, // 3 +}} +STRUCT!{struct DWRITE_FONT_METRICS1 { + designUnitsPerEm: UINT16, + ascent: UINT16, + descent: UINT16, + lineGap: INT16, + capHeight: UINT16, + xHeight: UINT16, + underlinePosition: INT16, + underlineThickness: UINT16, + strikethroughPosition: INT16, + strikethroughThickness: UINT16, + glyphBoxLeft: INT16, + glyphBoxTop: INT16, + glyphBoxRight: INT16, + glyphBoxBottom: INT16, + subscriptPositionX: INT16, + subscriptPositionY: INT16, + subscriptSizeX: INT16, + subscriptSizeY: INT16, + superscriptPositionX: INT16, + superscriptPositionY: INT16, + superscriptSizeX: INT16, + superscriptSizeY: INT16, + hasTypographicMetrics: BOOL, +}} +STRUCT!{struct DWRITE_CARET_METRICS { + slopeRise: INT16, + slopeRun: INT16, + offset: INT16, +}} +STRUCT!{struct DWRITE_PANOSE_text { + familyKind: UINT8, + serifStyle: UINT8, + weight: UINT8, + proportion: UINT8, + contrast: UINT8, + strokeVariation: UINT8, + armStyle: UINT8, + letterform: UINT8, + midline: UINT8, + xHeight: UINT8, +}} +STRUCT!{struct DWRITE_PANOSE_script { + familyKind: UINT8, + toolKind: UINT8, + weight: UINT8, + spacing: UINT8, + aspectRatio: UINT8, + contrast: UINT8, + scriptTopology: UINT8, + scriptForm: UINT8, + finials: UINT8, + xAscent: UINT8, +}} +STRUCT!{struct DWRITE_PANOSE_decorative { + familyKind: UINT8, + decorativeClass: UINT8, + weight: UINT8, + aspect: UINT8, + contrast: UINT8, + serifVariant: UINT8, + fill: UINT8, + lining: UINT8, + decorativeTopology: UINT8, + characterRange: UINT8, +}} +STRUCT!{struct DWRITE_PANOSE_symbol { + familyKind: UINT8, + symbolKind: UINT8, + weight: UINT8, + spacing: UINT8, + aspectRatioAndContrast: UINT8, + aspectRatio94: UINT8, + aspectRatio119: UINT8, + aspectRatio157: UINT8, + aspectRatio163: UINT8, + aspectRatio211: UINT8, +}} +UNION!{union DWRITE_PANOSE { + [u8; 10], + values values_mut: [UINT8; 10], + familyKind familyKind_mut: UINT8, + text text_mut: DWRITE_PANOSE_text, + script script_mut: DWRITE_PANOSE_script, + decorative decorative_mut: DWRITE_PANOSE_decorative, + symbol symbol_mut: DWRITE_PANOSE_symbol, +}} +STRUCT!{struct DWRITE_UNICODE_RANGE { + first: UINT32, + last: UINT32, +}} +STRUCT!{struct DWRITE_SCRIPT_PROPERTIES { + isoScriptCode: UINT32, + isoScriptNumber: UINT32, + clusterLookahead: UINT32, + justificationCharacter: UINT32, + bitfield0: UINT32, +}} +BITFIELD!{DWRITE_SCRIPT_PROPERTIES bitfield0: UINT32 [ + restrictCaretToClusters set_restrictCaretToClusters[0..1], + usesWordDividers set_usesWordDividers[1..2], + isDiscreteWriting set_isDiscreteWriting[2..3], + isBlockWriting set_isBlockWriting[3..4], + isDistributedWithinCluster set_isDistributedWithinCluster[4..5], + isConnectedWriting set_isConnectedWriting[5..6], + isCursiveWriting set_isCursiveWriting[6..7], + reserved set_reserved[7..32], +]} +STRUCT!{struct DWRITE_JUSTIFICATION_OPPORTUNITY { + expansionMinimum: FLOAT, + expansionMaximum: FLOAT, + compressionMaximum: FLOAT, + bitfield0: UINT32, +}} +BITFIELD!{DWRITE_JUSTIFICATION_OPPORTUNITY bitfield0: UINT32 [ + expansionPriority set_expansionPriority[0..8], + compressionPriority set_compressionPriority[8..16], + allowResidualExpansion set_allowResidualExpansion[16..17], + allowResidualCompression set_allowResidualCompression[17..18], + applyToLeadingEdge set_applyToLeadingEdge[18..19], + applyToTrailingEdge set_applyToTrailingEdge[19..20], + reserved set_reserved[20..32], +]} +RIDL!{#[uuid(0x30572f99, 0xdac6, 0x41db, 0xa1, 0x6e, 0x04, 0x86, 0x30, 0x7e, 0x60, 0x6a)] +interface IDWriteFactory1(IDWriteFactory1Vtbl): IDWriteFactory(IDWriteFactoryVtbl) { + fn GetEudcFontCollection( + fontCollection: *mut *mut IDWriteFontCollection, + checkForUpdates: BOOL, + ) -> HRESULT, + fn CreateCustomRenderingParams( + gamma: FLOAT, + enhancedContrast: FLOAT, + enhancedContrastGrayscale: FLOAT, + clearTypeLevel: FLOAT, + pixelGeometry: DWRITE_PIXEL_GEOMETRY, + renderingMode: DWRITE_RENDERING_MODE, + renderingParams: *mut *mut IDWriteRenderingParams1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa71efdb4, 0x9fdb, 0x4838, 0xad, 0x90, 0xcf, 0xc3, 0xbe, 0x8c, 0x3d, 0xaf)] +interface IDWriteFontFace1(IDWriteFontFace1Vtbl): IDWriteFontFace(IDWriteFontFaceVtbl) { + fn GetMetrics( + fontMetrics: *mut DWRITE_FONT_METRICS1, + ) -> (), + fn GetGdiCompatibleMetrics( + emSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + fontMetrics: *mut DWRITE_FONT_METRICS1, + ) -> HRESULT, + fn GetCaretMetrics( + caretMetrics: *mut DWRITE_CARET_METRICS, + ) -> (), + fn GetUnicodeRanges( + maxRangeCount: UINT32, + unicodeRanges: *mut DWRITE_UNICODE_RANGE, + actualRangeCount: *mut UINT32, + ) -> HRESULT, + fn IsMonospacedFont() -> BOOL, + fn GetDesignGlyphAdvances( + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvances: *mut INT32, + isSideways: BOOL, + ) -> HRESULT, + fn GetGdiCompatibleGlyphAdvances( + emSize: FLOAT, + pixelsPerDip: FLOAT, + transform: *const DWRITE_MATRIX, + useGdiNatural: BOOL, + isSideways: BOOL, + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvances: *mut INT32, + ) -> HRESULT, + fn GetKerningPairAdjustments( + glyphCount: UINT32, + glyphIndices: *const UINT16, + glyphAdvanceAdjustments: *mut INT32, + ) -> HRESULT, + fn HasKerningPairs() -> BOOL, + fn GetRecommendedRenderingMode( + fontEmSize: FLOAT, + dpiX: FLOAT, + dpiY: FLOAT, + transform: *const DWRITE_MATRIX, + isSideways: BOOL, + outlineThreshold: DWRITE_OUTLINE_THRESHOLD, + measuringMode: DWRITE_MEASURING_MODE, + renderingMode: *mut DWRITE_RENDERING_MODE, + ) -> HRESULT, + fn GetVerticalGlyphVariants( + glyphCount: UINT32, + nominalGlyphIndices: *const UINT16, + verticalGlyphIndices: *mut UINT16, + ) -> HRESULT, + fn HasVerticalGlyphVariants() -> BOOL, +}} +RIDL!{#[uuid(0xacd16696, 0x8c14, 0x4f5d, 0x87, 0x7e, 0xfe, 0x3f, 0xc1, 0xd3, 0x27, 0x38)] +interface IDWriteFont1(IDWriteFont1Vtbl): IDWriteFont(IDWriteFontVtbl) { + fn GetMetrics( + fontMetrics: *mut DWRITE_FONT_METRICS1, + ) -> (), + fn GetPanose( + panose: *mut DWRITE_PANOSE, + ) -> (), + fn GetUnicodeRanges( + maxRangeCount: UINT32, + unicodeRanges: *mut DWRITE_UNICODE_RANGE, + actualRangeCount: *mut UINT32, + ) -> HRESULT, + fn IsMonospacedFont() -> BOOL, +}} +RIDL!{#[uuid(0x94413cf4, 0xa6fc, 0x4248, 0x8b, 0x50, 0x66, 0x74, 0x34, 0x8f, 0xca, 0xd3)] +interface IDWriteRenderingParams1(IDWriteRenderingParams1Vtbl): + IDWriteRenderingParams(IDWriteRenderingParamsVtbl) { + fn GetGrayscaleEnhancedContrast() -> FLOAT, +}} +RIDL!{#[uuid(0x80dad800, 0xe21f, 0x4e83, 0x96, 0xce, 0xbf, 0xcc, 0xe5, 0x00, 0xdb, 0x7c)] +interface IDWriteTextAnalyzer1(IDWriteTextAnalyzer1Vtbl): + IDWriteTextAnalyzer(IDWriteTextAnalyzerVtbl) { + fn ApplyCharacterSpacing( + leadingSpacing: FLOAT, + trailingSpacing: FLOAT, + minimumAdvanceWidth: FLOAT, + textLength: UINT32, + glyphCount: UINT32, + clusterMap: *const UINT16, + glyphAdvances: *const FLOAT, + glyphOffsets: *const DWRITE_GLYPH_OFFSET, + glyphProperties: *const DWRITE_SHAPING_GLYPH_PROPERTIES, + modifiedGlyphAdvances: *mut FLOAT, + modifiedGlyphOffsets: *mut DWRITE_GLYPH_OFFSET, + ) -> HRESULT, + fn GetBaseline( + fontFace: *mut IDWriteFontFace, + baseline: DWRITE_BASELINE, + isVertical: BOOL, + isSimulationAllowed: BOOL, + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + baselineCoordinate: *mut INT32, + exists: *mut BOOL, + ) -> HRESULT, + fn AnalyzeVerticalGlyphOrientation( + analysisSource: *mut IDWriteTextAnalysisSource1, + textPosition: UINT32, + textLength: UINT32, + analysisSink: *mut IDWriteTextAnalysisSink1, + ) -> HRESULT, + fn GetGlyphOrientationTransform( + glyphOrientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + isSideways: BOOL, + transform: *mut DWRITE_MATRIX, + ) -> HRESULT, + fn GetScriptProperties( + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + scriptProperties: *mut DWRITE_SCRIPT_PROPERTIES, + ) -> HRESULT, + fn GetTextComplexity( + textString: *const WCHAR, + textLength: UINT32, + fontFace: *mut IDWriteFontFace, + isTextSimple: *mut BOOL, + textLengthRead: *mut UINT32, + glyphIndices: *mut UINT16, + ) -> HRESULT, + fn GetJustificationOpportunities( + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + textLength: UINT32, + glyphCount: UINT32, + textString: *const WCHAR, + clusterMap: *const UINT16, + glyphProperties: *const DWRITE_SHAPING_GLYPH_PROPERTIES, + justificationOpportunities: *mut DWRITE_JUSTIFICATION_OPPORTUNITY, + ) -> HRESULT, + fn JustifyGlyphAdvances( + lineWidth: FLOAT, + glyphCount: UINT32, + justificationOpportunities: *const DWRITE_JUSTIFICATION_OPPORTUNITY, + glyphAdvances: *const FLOAT, + glyphOffsets: *const DWRITE_GLYPH_OFFSET, + justifiedGlyphAdvances: *mut FLOAT, + justifiedGlyphOffsets: *mut DWRITE_GLYPH_OFFSET, + ) -> HRESULT, + fn GetJustifiedGlyphs( + fontFace: *mut IDWriteFontFace, + fontEmSize: FLOAT, + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + textLength: UINT32, + glyphCount: UINT32, + maxGlyphCount: UINT32, + clusterMap: *const UINT16, + glyphIndices: *const UINT16, + glyphAdvances: *const FLOAT, + justifiedGlyphAdvances: *const FLOAT, + justifiedGlyphOffsets: *const DWRITE_GLYPH_OFFSET, + glyphProperties: *const DWRITE_SHAPING_GLYPH_PROPERTIES, + actualGlyphCount: *mut UINT32, + modifiedClusterMap: *mut UINT16, + modifiedGlyphIndices: *mut UINT16, + modifiedGlyphAdvances: *mut FLOAT, + modifiedGlyphOffsets: *mut DWRITE_GLYPH_OFFSET, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x639cfad8, 0x0fb4, 0x4b21, 0xa5, 0x8a, 0x06, 0x79, 0x20, 0x12, 0x00, 0x09)] +interface IDWriteTextAnalysisSource1(IDWriteTextAnalysisSource1Vtbl): + IDWriteTextAnalysisSource(IDWriteTextAnalysisSourceVtbl) { + fn GetVerticalGlyphOrientation( + textPosition: UINT32, + textLength: *mut UINT32, + glyphOrientation: *mut DWRITE_VERTICAL_GLYPH_ORIENTATION, + bidiLevel: *mut UINT8, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb0d941a0, 0x85e7, 0x4d8b, 0x9f, 0xd3, 0x5c, 0xed, 0x99, 0x34, 0x48, 0x2a)] +interface IDWriteTextAnalysisSink1(IDWriteTextAnalysisSink1Vtbl): + IDWriteTextAnalysisSink(IDWriteTextAnalysisSinkVtbl) { + fn SetGlyphOrientation( + textPosition: UINT32, + textLength: UINT32, + glyphOrientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + adjustedBidiLevel: UINT8, + isSideways: BOOL, + isRightToLeft: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9064d822, 0x80a7, 0x465c, 0xa9, 0x86, 0xdf, 0x65, 0xf7, 0x8b, 0x8f, 0xeb)] +interface IDWriteTextLayout1(IDWriteTextLayout1Vtbl): + IDWriteTextLayout(IDWriteTextLayoutVtbl) { + fn SetPairKerning( + isPairKerningEnabled: BOOL, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetPairKerning( + currentPosition: UINT32, + isPairKerningEnabled: *mut BOOL, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn SetCharacterSpacing( + leadingSpacing: FLOAT, + trailingSpacing: FLOAT, + minimumAdvanceWidth: FLOAT, + textRange: DWRITE_TEXT_RANGE, + ) -> HRESULT, + fn GetCharacterSpacing( + currentPosition: UINT32, + leadingSpacing: *mut FLOAT, + trailingSpacing: *mut FLOAT, + minimumAdvanceWidth: *mut FLOAT, + textRange: *mut DWRITE_TEXT_RANGE, + ) -> HRESULT, +}} +ENUM!{enum DWRITE_TEXT_ANTIALIAS_MODE { + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE = 0x0, // 0 + DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE = 0x1, // 1 +}} +RIDL!{#[uuid(0x791e8298, 0x3ef3, 0x4230, 0x98, 0x80, 0xc9, 0xbd, 0xec, 0xc4, 0x20, 0x64)] +interface IDWriteBitmapRenderTarget1(IDWriteBitmapRenderTarget1Vtbl): + IDWriteBitmapRenderTarget(IDWriteBitmapRenderTargetVtbl) { + fn GetTextAntialiasMode() -> DWRITE_TEXT_ANTIALIAS_MODE, + fn SetTextAntialiasMode( + antialiasMode: DWRITE_TEXT_ANTIALIAS_MODE, + ) -> HRESULT, +}} diff --git a/winapi/src/um/dwrite_2.rs b/winapi/src/um/dwrite_2.rs new file mode 100644 index 000000000..e9810bba0 --- /dev/null +++ b/winapi/src/um/dwrite_2.rs @@ -0,0 +1,293 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the content of dwrite_2.h +use ctypes::{c_void, wchar_t}; +use shared::basetsd::{UINT16, UINT32, UINT8}; +use shared::d3d9types::D3DCOLORVALUE; +use shared::minwindef::{BOOL, FLOAT}; +use um::dcommon::DWRITE_MEASURING_MODE; +use um::dwrite::{ + DWRITE_FONT_FEATURE_TAG, DWRITE_FONT_STRETCH, DWRITE_FONT_STYLE, DWRITE_FONT_WEIGHT, + DWRITE_GLYPH_RUN, DWRITE_GLYPH_RUN_DESCRIPTION, DWRITE_MATRIX, DWRITE_PIXEL_GEOMETRY, + DWRITE_RENDERING_MODE, DWRITE_SCRIPT_ANALYSIS, DWRITE_STRIKETHROUGH, DWRITE_UNDERLINE, + IDWriteFont, IDWriteFontCollection, IDWriteFontFace, IDWriteGlyphRunAnalysis, + IDWriteInlineObject, IDWriteRenderingParams, IDWriteTextAnalysisSource, IDWriteTextFormat, + IDWriteTextFormatVtbl, IDWriteTextRenderer, IDWriteTextRendererVtbl, +}; +use um::dwrite_1::{ + DWRITE_GLYPH_ORIENTATION_ANGLE, DWRITE_OUTLINE_THRESHOLD, DWRITE_TEXT_ANTIALIAS_MODE, + DWRITE_UNICODE_RANGE, DWRITE_VERTICAL_GLYPH_ORIENTATION, IDWriteFactory1, + IDWriteFactory1Vtbl, IDWriteFont1, IDWriteFont1Vtbl, IDWriteFontFace1, IDWriteFontFace1Vtbl, + IDWriteRenderingParams1, IDWriteRenderingParams1Vtbl, IDWriteTextAnalyzer1, + IDWriteTextAnalyzer1Vtbl, IDWriteTextLayout1, IDWriteTextLayout1Vtbl, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, WCHAR}; +ENUM!{enum DWRITE_OPTICAL_ALIGNMENT { + DWRITE_OPTICAL_ALIGNMENT_NONE = 0x0, // 0 + DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS = 0x1, // 1 +}} +ENUM!{enum DWRITE_GRID_FIT_MODE { + DWRITE_GRID_FIT_MODE_DEFAULT = 0x0, // 0 + DWRITE_GRID_FIT_MODE_DISABLED = 0x1, // 1 + DWRITE_GRID_FIT_MODE_ENABLED = 0x2, // 2 +}} +STRUCT!{struct DWRITE_TEXT_METRICS1 { + left: FLOAT, + top: FLOAT, + width: FLOAT, + widthIncludingTrailingWhitespace: FLOAT, + height: FLOAT, + layoutWidth: FLOAT, + layoutHeight: FLOAT, + maxBidiReorderingDepth: UINT32, + lineCount: UINT32, + heightIncludingTrailingWhitespace: FLOAT, +}} +RIDL!{#[uuid(0xd3e0e934, 0x22a0, 0x427e, 0xaa, 0xe4, 0x7d, 0x95, 0x74, 0xb5, 0x9d, 0xb1)] +interface IDWriteTextRenderer1(IDWriteTextRenderer1Vtbl): + IDWriteTextRenderer(IDWriteTextRendererVtbl) { + fn DrawGlyphRun( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + orientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + measuringMode: DWRITE_MEASURING_MODE, + glyphRun: *const DWRITE_GLYPH_RUN, + glyphRunDescription: *const DWRITE_GLYPH_RUN_DESCRIPTION, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawUnderline( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + orientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + underline: *const DWRITE_UNDERLINE, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawStrikethrough( + clientDrawingContext: *mut c_void, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + orientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + strikethrough: *const DWRITE_STRIKETHROUGH, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, + fn DrawInlineObject( + clientDrawingContext: *mut c_void, + originX: FLOAT, + originY: FLOAT, + orientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + inlineObject: *mut IDWriteInlineObject, + isSideways: BOOL, + isRightToLeft: BOOL, + clientDrawingEffect: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5f174b49, 0x0d8b, 0x4cfb, 0x8b, 0xca, 0xf1, 0xcc, 0xe9, 0xd0, 0x6c, 0x67)] +interface IDWriteTextFormat1(IDWriteTextFormat1Vtbl): + IDWriteTextFormat(IDWriteTextFormatVtbl) { + fn SetVerticalGlyphOrientation( + glyphOrientation: DWRITE_VERTICAL_GLYPH_ORIENTATION, + ) -> HRESULT, + fn GetVerticalGlyphOrientation() -> DWRITE_VERTICAL_GLYPH_ORIENTATION, + fn SetLastLineWrapping( + isLastLineWrappingEnabled: BOOL, + ) -> HRESULT, + fn GetLastLineWrapping() -> BOOL, + fn SetOpticalAlignment( + opticalAlignment: DWRITE_OPTICAL_ALIGNMENT, + ) -> HRESULT, + fn GetOpticalAlignment() -> DWRITE_OPTICAL_ALIGNMENT, + fn SetFontFallback( + fontFallback: *mut IDWriteFontFallback, + ) -> HRESULT, + fn GetFontFallback( + fontFallback: *mut *mut IDWriteFontFallback, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1093c18f, 0x8d5e, 0x43f0, 0xb0, 0x64, 0x09, 0x17, 0x31, 0x1b, 0x52, 0x5e)] +interface IDWriteTextLayout2(IDWriteTextLayout2Vtbl): + IDWriteTextLayout1(IDWriteTextLayout1Vtbl) { + fn GetMetrics( + textMetrics: *mut DWRITE_TEXT_METRICS1, + ) -> HRESULT, + fn SetVerticalGlyphOrientation( + glyphOrientation: DWRITE_VERTICAL_GLYPH_ORIENTATION, + ) -> HRESULT, + fn GetVerticalGlyphOrientation() -> DWRITE_VERTICAL_GLYPH_ORIENTATION, + fn SetLastLineWrapping( + isLastLineWrappingEnabled: BOOL, + ) -> HRESULT, + fn GetLastLineWrapping() -> BOOL, + fn SetOpticalAlignment( + opticalAlignment: DWRITE_OPTICAL_ALIGNMENT, + ) -> HRESULT, + fn GetOpticalAlignment() -> DWRITE_OPTICAL_ALIGNMENT, + fn SetFontFallback( + fontFallback: *mut IDWriteFontFallback, + ) -> HRESULT, + fn GetFontFallback( + fontFallback: *mut *mut IDWriteFontFallback, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x553a9ff3, 0x5693, 0x4df7, 0xb5, 0x2b, 0x74, 0x80, 0x6f, 0x7f, 0x2e, 0xb9)] +interface IDWriteTextAnalyzer2(IDWriteTextAnalyzer2Vtbl): + IDWriteTextAnalyzer1(IDWriteTextAnalyzer1Vtbl) { + fn GetGlyphOrientationTransform( + glyphOrientationAngle: DWRITE_GLYPH_ORIENTATION_ANGLE, + isSideways: BOOL, + originX: FLOAT, + originY: FLOAT, + transform: *mut DWRITE_MATRIX, + ) -> HRESULT, + fn GetTypographicFeatures( + fontFace: *mut IDWriteFontFace, + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + maxTagCount: UINT32, + actualTagCount: *mut UINT32, + tags: *mut DWRITE_FONT_FEATURE_TAG, + ) -> HRESULT, + fn CheckTypographicFeature( + fontFace: *mut IDWriteFontFace, + scriptAnalysis: DWRITE_SCRIPT_ANALYSIS, + localeName: *const WCHAR, + featureTag: DWRITE_FONT_FEATURE_TAG, + glyphCount: UINT32, + glyphIndices: *const UINT16, + featureApplies: *mut UINT8, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xefa008f9, 0xf7a1, 0x48bf, 0xb0, 0x5c, 0xf2, 0x24, 0x71, 0x3c, 0xc0, 0xff)] +interface IDWriteFontFallback(IDWriteFontFallbackVtbl): IUnknown(IUnknownVtbl) { + fn MapCharacters( + analysisSource: *mut IDWriteTextAnalysisSource, + textPosition: UINT32, + textLength: UINT32, + baseFontCollection: *mut IDWriteFontCollection, + baseFamilyName: *mut wchar_t, + baseWeight: DWRITE_FONT_WEIGHT, + baseStyle: DWRITE_FONT_STYLE, + baseStretch: DWRITE_FONT_STRETCH, + mappedLength: *mut UINT32, + mappedFont: *mut *mut IDWriteFont, + scale: *mut FLOAT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfd882d06, 0x8aba, 0x4fb8, 0xb8, 0x49, 0x8b, 0xe8, 0xb7, 0x3e, 0x14, 0xde)] +interface IDWriteFontFallbackBuilder(IDWriteFontFallbackBuilderVtbl): + IUnknown(IUnknownVtbl) { + fn AddMapping( + ranges: *const DWRITE_UNICODE_RANGE, + rangesCount: UINT32, + targetFamilyNames: *mut *const WCHAR, + targetFamilyNamesCount: UINT32, + fontCollection: *mut IDWriteFontCollection, + localeName: *const WCHAR, + baseFamilyName: *const WCHAR, + scale: FLOAT, + ) -> HRESULT, + fn AddMappings( + fontFallback: *mut IDWriteFontFallback, + ) -> HRESULT, + fn CreateFontFallback( + fontFallback: *mut *mut IDWriteFontFallback, + ) -> HRESULT, +}} +pub type DWRITE_COLOR_F = D3DCOLORVALUE; +RIDL!{#[uuid(0x29748ed6, 0x8c9c, 0x4a6a, 0xbe, 0x0b, 0xd9, 0x12, 0xe8, 0x53, 0x89, 0x44)] +interface IDWriteFont2(IDWriteFont2Vtbl): IDWriteFont1(IDWriteFont1Vtbl) { + fn IsColorFont() -> BOOL, +}} +RIDL!{#[uuid(0xd8b768ff, 0x64bc, 0x4e66, 0x98, 0x2b, 0xec, 0x8e, 0x87, 0xf6, 0x93, 0xf7)] +interface IDWriteFontFace2(IDWriteFontFace2Vtbl): + IDWriteFontFace1(IDWriteFontFace1Vtbl) { + fn IsColorFont() -> BOOL, + fn GetColorPaletteCount() -> UINT32, + fn GetPaletteEntryCount() -> UINT32, + fn GetPaletteEntries( + colorPaletteIndex: UINT32, + firstEntryIndex: UINT32, + entryCount: UINT32, + paletteEntries: *mut DWRITE_COLOR_F, + ) -> HRESULT, + fn GetRecommendedRenderingMode( + fontEmSize: FLOAT, + dpiX: FLOAT, + dpiY: FLOAT, + transform: *const DWRITE_MATRIX, + isSideways: BOOL, + outlineThreshold: DWRITE_OUTLINE_THRESHOLD, + measuringMode: DWRITE_MEASURING_MODE, + renderingParams: *mut IDWriteRenderingParams, + renderingMode: *mut DWRITE_RENDERING_MODE, + gridFitMode: *mut DWRITE_GRID_FIT_MODE, + ) -> HRESULT, +}} +STRUCT!{struct DWRITE_COLOR_GLYPH_RUN { + glyphRun: DWRITE_GLYPH_RUN, + glyphRunDescription: *mut DWRITE_GLYPH_RUN_DESCRIPTION, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + runColor: DWRITE_COLOR_F, + paletteIndex: UINT16, +}} +RIDL!{#[uuid(0xd31fbe17, 0xf157, 0x41a2, 0x8d, 0x24, 0xcb, 0x77, 0x9e, 0x05, 0x60, 0xe8)] +interface IDWriteColorGlyphRunEnumerator(IDWriteColorGlyphRunEnumeratorVtbl): + IUnknown(IUnknownVtbl) { + fn MoveNext( + hasRun: *mut BOOL, + ) -> HRESULT, + fn GetCurrentRun( + colorGlyphRun: *mut *const DWRITE_COLOR_GLYPH_RUN, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf9d711c3, 0x9777, 0x40ae, 0x87, 0xe8, 0x3e, 0x5a, 0xf9, 0xbf, 0x09, 0x48)] +interface IDWriteRenderingParams2(IDWriteRenderingParams2Vtbl): + IDWriteRenderingParams1(IDWriteRenderingParams1Vtbl) { + fn GetGridFitMode() -> DWRITE_GRID_FIT_MODE, +}} +RIDL!{#[uuid(0x0439fc60, 0xca44, 0x4994, 0x8d, 0xee, 0x3a, 0x9a, 0xf7, 0xb7, 0x32, 0xec)] +interface IDWriteFactory2(IDWriteFactory2Vtbl): IDWriteFactory1(IDWriteFactory1Vtbl) { + fn GetSystemFontFallback( + fontFallback: *mut *mut IDWriteFontFallback, + ) -> HRESULT, + fn CreateFontFallbackBuilder( + fontFallbackBuilder: *mut *mut IDWriteFontFallbackBuilder, + ) -> HRESULT, + fn TranslateColorGlyphRun( + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + glyphRun: *const DWRITE_GLYPH_RUN, + glyphRunDescription: *const DWRITE_GLYPH_RUN_DESCRIPTION, + measuringMode: DWRITE_MEASURING_MODE, + worldToDeviceTransform: *const DWRITE_MATRIX, + colorPaletteIndex: UINT32, + colorLayers: *mut *mut IDWriteColorGlyphRunEnumerator, + ) -> HRESULT, + fn CreateCustomRenderingParams( + gamma: FLOAT, + enhancedContrast: FLOAT, + grayscaleEnhancedContrast: FLOAT, + clearTypeLevel: FLOAT, + pixelGeometry: DWRITE_PIXEL_GEOMETRY, + renderingMode: DWRITE_RENDERING_MODE, + gridFitMode: DWRITE_GRID_FIT_MODE, + renderingParams: *mut *mut IDWriteRenderingParams2, + ) -> HRESULT, + fn CreateGlyphRunAnalysis( + glyphRun: *const DWRITE_GLYPH_RUN, + transform: *const DWRITE_MATRIX, + renderingMode: DWRITE_RENDERING_MODE, + measuringMode: DWRITE_MEASURING_MODE, + gridFitMode: DWRITE_GRID_FIT_MODE, + antialiasMode: DWRITE_TEXT_ANTIALIAS_MODE, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + glyphRunAnalysis: *mut *mut IDWriteGlyphRunAnalysis, + ) -> HRESULT, +}} diff --git a/winapi/src/um/dwrite_3.rs b/winapi/src/um/dwrite_3.rs new file mode 100644 index 000000000..f6645c347 --- /dev/null +++ b/winapi/src/um/dwrite_3.rs @@ -0,0 +1,578 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the content of dwrite_3.h +use ctypes::c_void; +use shared::basetsd::{UINT16, UINT32, UINT64}; +use shared::minwindef::{BOOL, FILETIME, FLOAT}; +use um::dcommon::{DWRITE_GLYPH_IMAGE_DATA, DWRITE_GLYPH_IMAGE_FORMATS, DWRITE_MEASURING_MODE}; +use um::dwrite::{ + DWRITE_FONT_SIMULATIONS, DWRITE_FONT_STRETCH, DWRITE_FONT_STYLE, DWRITE_FONT_WEIGHT, + DWRITE_GLYPH_RUN, DWRITE_INFORMATIONAL_STRING_ID, DWRITE_LINE_SPACING_METHOD, DWRITE_MATRIX, + DWRITE_PIXEL_GEOMETRY, DWRITE_RENDERING_MODE_ALIASED, DWRITE_RENDERING_MODE_DEFAULT, + DWRITE_RENDERING_MODE_GDI_CLASSIC, DWRITE_RENDERING_MODE_GDI_NATURAL, + DWRITE_RENDERING_MODE_NATURAL, DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, + DWRITE_RENDERING_MODE_OUTLINE, IDWriteFont, IDWriteFontCollection, IDWriteFontCollectionVtbl, + IDWriteFontFace, IDWriteFontFamily, IDWriteFontFamilyVtbl, IDWriteFontFile, IDWriteFontList, + IDWriteFontListVtbl, IDWriteGdiInterop, IDWriteGdiInteropVtbl, IDWriteGlyphRunAnalysis, + IDWriteLocalizedStrings, IDWriteRenderingParams, +}; +use um::dwrite_1::{DWRITE_OUTLINE_THRESHOLD, DWRITE_PANOSE, DWRITE_TEXT_ANTIALIAS_MODE}; +use um::dwrite_2::{ + DWRITE_GRID_FIT_MODE, IDWriteFactory2, IDWriteFactory2Vtbl, IDWriteFont2, IDWriteFont2Vtbl, + IDWriteFontFace2, IDWriteFontFace2Vtbl, IDWriteRenderingParams2, IDWriteRenderingParams2Vtbl, + IDWriteTextFormat1, IDWriteTextFormat1Vtbl, IDWriteTextLayout2, IDWriteTextLayout2Vtbl, +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wingdi::{FONTSIGNATURE, LOGFONTW}; +use um::winnt::{HRESULT, WCHAR}; +pub const DWRITE_E_REMOTEFONT: HRESULT = 0x8898500D; +pub const DWRITE_E_DOWNLOADCANCELLED: HRESULT = 0x8898500E; +pub const DWRITE_E_DOWNLOADFAILED: HRESULT = 0x8898500F; +pub const DWRITE_E_TOOMANYDOWNLOADS: HRESULT = 0x88985010; +ENUM!{enum DWRITE_FONT_PROPERTY_ID { + DWRITE_FONT_PROPERTY_ID_NONE, + DWRITE_FONT_PROPERTY_ID_FAMILY_NAME, + DWRITE_FONT_PROPERTY_ID_PREFERRED_FAMILY_NAME, + DWRITE_FONT_PROPERTY_ID_FACE_NAME, + DWRITE_FONT_PROPERTY_ID_FULL_NAME, + DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME, + DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, + DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG, + DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG, + DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG, + DWRITE_FONT_PROPERTY_ID_WEIGHT , + DWRITE_FONT_PROPERTY_ID_STRETCH, + DWRITE_FONT_PROPERTY_ID_STYLE, + DWRITE_FONT_PROPERTY_ID_TOTAL, +}} +STRUCT!{struct DWRITE_FONT_PROPERTY { + propertyId: DWRITE_FONT_PROPERTY_ID, + propertyValue: *const WCHAR, + localeName: *const WCHAR, +}} +ENUM!{enum DWRITE_LOCALITY { + DWRITE_LOCALITY_REMOTE, + DWRITE_LOCALITY_PARTIAL, + DWRITE_LOCALITY_LOCAL, +}} +ENUM!{enum DWRITE_RENDERING_MODE1 { + DWRITE_RENDERING_MODE1_DEFAULT = DWRITE_RENDERING_MODE_DEFAULT, + DWRITE_RENDERING_MODE1_ALIASED = DWRITE_RENDERING_MODE_ALIASED, + DWRITE_RENDERING_MODE1_GDI_CLASSIC = DWRITE_RENDERING_MODE_GDI_CLASSIC, + DWRITE_RENDERING_MODE1_GDI_NATURAL = DWRITE_RENDERING_MODE_GDI_NATURAL, + DWRITE_RENDERING_MODE1_NATURAL = DWRITE_RENDERING_MODE_NATURAL, + DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, + DWRITE_RENDERING_MODE1_OUTLINE = DWRITE_RENDERING_MODE_OUTLINE, + DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, +}} +RIDL!{#[uuid(0xb7924baa, 0x391b, 0x412a, 0x8c, 0x5c, 0xe4, 0x4c, 0xc2, 0xd8, 0x67, 0xdc)] +interface IDWriteRenderingParams3(IDWriteRenderingParams3Vtbl): + IDWriteRenderingParams2(IDWriteRenderingParams2Vtbl) { + fn GetRenderingMode1() -> DWRITE_RENDERING_MODE1, +}} +RIDL!{#[uuid(0x9a1b41c3, 0xd3bb, 0x466a, 0x87, 0xfc, 0xfe, 0x67, 0x55, 0x6a, 0x3b, 0x65)] +interface IDWriteFactory3(IDWriteFactory3Vtbl): IDWriteFactory2(IDWriteFactory2Vtbl) { + fn CreateGlyphRunAnalysis( + glyphRun: *const DWRITE_GLYPH_RUN, + transform: *const DWRITE_MATRIX, + renderingMode: DWRITE_RENDERING_MODE1, + measuringMode: DWRITE_MEASURING_MODE, + gridFitMode: DWRITE_GRID_FIT_MODE, + antialiasMode: DWRITE_TEXT_ANTIALIAS_MODE, + baselineOriginX: FLOAT, + baselineOriginY: FLOAT, + glyphRunAnalysis: *mut *mut IDWriteGlyphRunAnalysis, + ) -> HRESULT, + fn CreateCustomRenderingParams( + gamma: FLOAT, + enhancedContrast: FLOAT, + grayscaleEnhancedContrast: FLOAT, + clearTypeLevel: FLOAT, + pixelGeometry: DWRITE_PIXEL_GEOMETRY, + renderingMode: DWRITE_RENDERING_MODE1, + gridFitMode: DWRITE_GRID_FIT_MODE, + renderingParams: *mut *mut IDWriteRenderingParams3, + ) -> HRESULT, + fn CreateFontFaceReference_2( + fontFile: *mut IDWriteFontFile, + faceIndex: UINT32, + fontSimulations: DWRITE_FONT_SIMULATIONS, + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn CreateFontFaceReference_1( + filePath: *const WCHAR, + lastWriteTime: *const FILETIME, + faceIndex: UINT32, + fontSimulations: DWRITE_FONT_SIMULATIONS, + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn GetSystemFontSet( + fontSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, + fn CreateFontSetBuilder( + fontSetBuilder: *mut *mut IDWriteFontSetBuilder, + ) -> HRESULT, + fn CreateFontCollectionFromFontSet( + fontSet: *mut IDWriteFontSet, + fontCollection: *mut *mut IDWriteFontCollection1, + ) -> HRESULT, + fn GetSystemFontCollection( + includeDownloadableFonts: BOOL, + fontCollection: *mut *mut IDWriteFontCollection1, + checkForUpdates: BOOL, + ) -> HRESULT, + fn GetFontDownloadQueue( + fontDownloadQueue: *mut *mut IDWriteFontDownloadQueue, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x53585141, 0xd9f8, 0x4095, 0x83, 0x21, 0xd7, 0x3c, 0xf6, 0xbd, 0x11, 0x6b)] +interface IDWriteFontSet(IDWriteFontSetVtbl): IUnknown(IUnknownVtbl) { + fn GetFontCount() -> UINT32, + fn GetFontFaceReference( + listIndex: UINT32, + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn FindFontFaceReference( + fontFaceReference: *mut IDWriteFontFaceReference, + listIndex: *mut UINT32, + exists: *mut BOOL, + ) -> HRESULT, + fn FindFontFace( + fontFace: *mut IDWriteFontFace, + listIndex: *mut UINT32, + exists: *mut BOOL, + ) -> HRESULT, + fn GetPropertyValues_3( + propertyID: DWRITE_FONT_PROPERTY_ID, + values: *mut *mut IDWriteStringList, + ) -> HRESULT, + fn GetPropertyValues_2( + propertyID: DWRITE_FONT_PROPERTY_ID, + preferredLocaleNames: *const WCHAR, + values: *mut *mut IDWriteStringList, + ) -> HRESULT, + fn GetPropertyValues_1( + listIndex: UINT32, + propertyId: DWRITE_FONT_PROPERTY_ID, + exists: *mut BOOL, + values: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetPropertyOccurrenceCount( + property: *const DWRITE_FONT_PROPERTY, + propertyOccurrenceCount: *mut UINT32, + ) -> HRESULT, + fn GetMatchingFonts_2( + familyName: *const WCHAR, + fontWeight: DWRITE_FONT_WEIGHT, + fontStretch: DWRITE_FONT_STRETCH, + fontStyle: DWRITE_FONT_STYLE, + filteredSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, + fn GetMatchingFonts_1( + properties: *const DWRITE_FONT_PROPERTY, + propertyCount: UINT32, + filteredSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2f642afe, 0x9c68, 0x4f40, 0xb8, 0xbe, 0x45, 0x74, 0x01, 0xaf, 0xcb, 0x3d)] +interface IDWriteFontSetBuilder(IDWriteFontSetBuilderVtbl): IUnknown(IUnknownVtbl) { + fn AddFontFaceReference_2( + fontFaceReference: *mut IDWriteFontFaceReference, + properties: *const DWRITE_FONT_PROPERTY, + propertyCount: UINT32, + ) -> HRESULT, + fn AddFontFaceReference_1( + fontFaceReference: *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn AddFontSet( + fontSet: *mut IDWriteFontSet, + ) -> HRESULT, + fn CreateFontSet( + fontSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x53585141, 0xd9f8, 0x4095, 0x83, 0x21, 0xd7, 0x3c, 0xf6, 0xbd, 0x11, 0x6c)] +interface IDWriteFontCollection1(IDWriteFontCollection1Vtbl): + IDWriteFontCollection(IDWriteFontCollectionVtbl) { + fn GetFontSet( + fontSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, + fn GetFontFamily( + index: UINT32, + fontFamily: *mut *mut IDWriteFontFamily1, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xda20d8ef, 0x812a, 0x4c43, 0x98, 0x02, 0x62, 0xec, 0x4a, 0xbd, 0x7a, 0xdf)] +interface IDWriteFontFamily1(IDWriteFontFamily1Vtbl): + IDWriteFontFamily(IDWriteFontFamilyVtbl) { + fn GetFontLocality( + listIndex: UINT32, + ) -> DWRITE_LOCALITY, + fn GetFont( + listIndex: UINT32, + font: *mut *mut IDWriteFont3, + ) -> HRESULT, + fn GetFontFaceReference( + listIndex: UINT32, + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xda20d8ef, 0x812a, 0x4c43, 0x98, 0x02, 0x62, 0xec, 0x4a, 0xbd, 0x7a, 0xde)] +interface IDWriteFontList1(IDWriteFontList1Vtbl): IDWriteFontList(IDWriteFontListVtbl) { + fn GetFontLocality( + listIndex: UINT32, + ) -> DWRITE_LOCALITY, + fn GetFont( + listIndex: UINT32, + font: *mut *mut IDWriteFont3, + ) -> HRESULT, + fn GetFontFaceReference( + listIndex: UINT32, + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5e7fa7ca, 0xdde3, 0x424c, 0x89, 0xf0, 0x9f, 0xcd, 0x6f, 0xed, 0x58, 0xcd)] +interface IDWriteFontFaceReference(IDWriteFontFaceReferenceVtbl): + IUnknown(IUnknownVtbl) { + fn CreateFontFace( + fontFace: *mut *mut IDWriteFontFace3, + ) -> HRESULT, + fn CreateFontFaceWithSimulations( + fontFaceSimulationFlags: DWRITE_FONT_SIMULATIONS, + fontFace: *mut *mut IDWriteFontFace3, + ) -> HRESULT, + fn Equals( + fontFaceReference: *mut IDWriteFontFaceReference, + ) -> BOOL, + fn GetFontFaceIndex() -> UINT32, + fn GetSimulations() -> DWRITE_FONT_SIMULATIONS, + fn GetFontFile( + fontFile: *mut *mut IDWriteFontFile, + ) -> HRESULT, + fn GetLocalFileSize() -> UINT64, + fn GetFileSize() -> UINT64, + fn GetFileTime( + lastWriteTime: *mut FILETIME, + ) -> HRESULT, + fn GetLocality() -> DWRITE_LOCALITY, + fn EnqueueFontDownloadRequest() -> HRESULT, + fn EnqueueCharacterDownloadRequest( + characters: *const WCHAR, + characterCount: UINT32, + ) -> HRESULT, + fn EnqueueGlyphDownloadRequest( + glyphIndices: *const UINT16, + glyphCount: UINT32, + ) -> HRESULT, + fn EnqueueFileFragmentDownloadRequest( + fileOffset: UINT64, + fragmentSize: UINT64, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x29748ed6, 0x8c9c, 0x4a6a, 0xbe, 0x0b, 0xd9, 0x12, 0xe8, 0x53, 0x89, 0x44)] +interface IDWriteFont3(IDWriteFont3Vtbl): IDWriteFont2(IDWriteFont2Vtbl) { + fn CreateFontFace( + fontFace: *mut *mut IDWriteFontFace3, + ) -> HRESULT, + fn Equals( + font: *mut IDWriteFont, + ) -> BOOL, + fn GetFontFaceReference( + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn HasCharacter( + unicodeValue: UINT32, + ) -> BOOL, + fn GetLocality() -> DWRITE_LOCALITY, +}} +RIDL!{#[uuid(0xd37d7598, 0x09be, 0x4222, 0xa2, 0x36, 0x20, 0x81, 0x34, 0x1c, 0xc1, 0xf2)] +interface IDWriteFontFace3(IDWriteFontFace3Vtbl): + IDWriteFontFace2(IDWriteFontFace2Vtbl) { + fn GetFontFaceReference( + fontFaceReference: *mut *mut IDWriteFontFaceReference, + ) -> HRESULT, + fn GetPanose( + panose: *mut DWRITE_PANOSE, + ) -> (), + fn GetWeight() -> DWRITE_FONT_WEIGHT, + fn GetStretch() -> DWRITE_FONT_STRETCH, + fn GetStyle() -> DWRITE_FONT_STYLE, + fn GetFamilyNames( + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetFaceNames( + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetInformationalStrings( + informationalStringID: DWRITE_INFORMATIONAL_STRING_ID, + informationalStrings: *mut *mut IDWriteLocalizedStrings, + exists: *mut BOOL, + ) -> HRESULT, + fn HasCharacter( + unicodeValue: UINT32, + ) -> BOOL, + fn GetRecommendedRenderingMode( + fontEmSize: FLOAT, + dpiX: FLOAT, + dpiY: FLOAT, + transform: *const DWRITE_MATRIX, + isSideways: BOOL, + outlineThreshold: DWRITE_OUTLINE_THRESHOLD, + measuringMode: DWRITE_MEASURING_MODE, + renderingParams: *mut IDWriteRenderingParams, + renderingMode: *mut DWRITE_RENDERING_MODE1, + gridFitMode: *mut DWRITE_GRID_FIT_MODE, + ) -> HRESULT, + fn IsCharacterLocal( + unicodeValue: UINT32, + ) -> BOOL, + fn IsGlyphLocal( + glyphId: UINT16, + ) -> BOOL, + fn AreCharactersLocal( + characters: *const WCHAR, + characterCount: UINT32, + enqueueIfNotLocal: BOOL, + isLocal: *mut BOOL, + ) -> HRESULT, + fn AreGlyphsLocal( + glyphIndices: *const UINT16, + glyphCount: UINT32, + enqueueIfNotLocal: BOOL, + isLocal: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xcfee3140, 0x1157, 0x47ca, 0x8b, 0x85, 0x31, 0xbf, 0xcf, 0x3f, 0x2d, 0x0e)] +interface IDWriteStringList(IDWriteStringListVtbl): IUnknown(IUnknownVtbl) { + fn GetCount() -> UINT32, + fn GetLocaleNameLength( + listIndex: UINT32, + length: *mut UINT32, + ) -> HRESULT, + fn GetLocaleName( + listIndex: UINT32, + localeName: *mut WCHAR, + size: UINT32, + ) -> HRESULT, + fn GetStringLength( + listIndex: UINT32, + length: *mut UINT32, + ) -> HRESULT, + fn GetString( + listIndex: UINT32, + stringBuffer: *mut WCHAR, + stringBufferSize: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb06fe5b9, 0x43ec, 0x4393, 0x88, 0x1b, 0xdb, 0xe4, 0xdc, 0x72, 0xfd, 0xa7)] +interface IDWriteFontDownloadListener(IDWriteFontDownloadListenerVtbl): + IUnknown(IUnknownVtbl) { + fn DownloadCompleted( + downloadQueue: *mut IDWriteFontDownloadQueue, + context: *mut IUnknown, + downloadResult: HRESULT, + ) -> (), +}} +RIDL!{#[uuid(0xb71e6052, 0x5aea, 0x4fa3, 0x83, 0x2e, 0xf6, 0x0d, 0x43, 0x1f, 0x7e, 0x91)] +interface IDWriteFontDownloadQueue(IDWriteFontDownloadQueueVtbl): + IUnknown(IUnknownVtbl) { + fn AddListener( + listener: *mut IDWriteFontDownloadListener, + token: *mut UINT32, + ) -> HRESULT, + fn RemoveListener( + token: UINT32, + ) -> HRESULT, + fn IsEmpty() -> BOOL, + fn BeginDownload( + context: *mut IUnknown, + ) -> HRESULT, + fn CancelDownload() -> HRESULT, + fn GetGenerationCount() -> UINT64, +}} +RIDL!{#[uuid(0x4556be70, 0x3abd, 0x4f70, 0x90, 0xbe, 0x42, 0x17, 0x80, 0xa6, 0xf5, 0x15)] +interface IDWriteGdiInterop1(IDWriteGdiInterop1Vtbl): + IDWriteGdiInterop(IDWriteGdiInteropVtbl) { + fn CreateFontFromLOGFONT( + logFont: *const LOGFONTW, + fontCollection: *mut IDWriteFontCollection, + font: *mut *mut IDWriteFont, + ) -> HRESULT, + fn GetFontSignature_2( + fontFace: *mut IDWriteFontFace, + fontSignature: *mut FONTSIGNATURE, + ) -> HRESULT, + fn GetFontSignature_1( + font: *mut IDWriteFont, + fontSignature: *mut FONTSIGNATURE, + ) -> HRESULT, + fn GetMatchingFontsByLOGFONT( + logFont: *const LOGFONTW, + fontSet: *mut IDWriteFontSet, + filteredSet: *mut *mut IDWriteFontSet, + ) -> HRESULT, +}} +STRUCT!{struct DWRITE_LINE_METRICS1 { + length: UINT32, + trailingWhitespaceLength: UINT32, + newlineLength: UINT32, + height: FLOAT, + baseline: FLOAT, + isTrimmed: BOOL, + leadingBefore: FLOAT, + leadingAfter: FLOAT, +}} +ENUM!{enum DWRITE_FONT_LINE_GAP_USAGE { + DWRITE_FONT_LINE_GAP_USAGE_DEFAULT, + DWRITE_FONT_LINE_GAP_USAGE_DISABLED, + DWRITE_FONT_LINE_GAP_USAGE_ENABLED, +}} +STRUCT!{struct DWRITE_LINE_SPACING { + method: DWRITE_LINE_SPACING_METHOD, + height: FLOAT, + baseline: FLOAT, + leadingBefore: FLOAT, + fontLineGapUsage: DWRITE_FONT_LINE_GAP_USAGE, +}} +RIDL!{#[uuid(0xf67e0edd, 0x9e3d, 0x4ecc, 0x8c, 0x32, 0x41, 0x83, 0x25, 0x3d, 0xfe, 0x70)] +interface IDWriteTextFormat2(IDWriteTextFormat2Vtbl): + IDWriteTextFormat1(IDWriteTextFormat1Vtbl) { + fn SetLineSpacing( + lineSpacingOptions: *const DWRITE_LINE_SPACING, + ) -> HRESULT, + fn GetLineSpacing( + lineSpacingOptions: *mut DWRITE_LINE_SPACING, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x07ddcd52, 0x020e, 0x4de8, 0xac, 0x33, 0x6c, 0x95, 0x3d, 0x83, 0xf9, 0x2d)] +interface IDWriteTextLayout3(IDWriteTextLayout3Vtbl): + IDWriteTextLayout2(IDWriteTextLayout2Vtbl) { + fn InvalidateLayout() -> HRESULT, + fn SetLineSpacing( + lineSpacingOptions: *const DWRITE_LINE_SPACING, + ) -> HRESULT, + fn GetLineSpacing( + lineSpacingOptions: *mut DWRITE_LINE_SPACING, + ) -> HRESULT, + fn GetLineMetrics( + lineMetrics: *mut DWRITE_LINE_METRICS1, + maxLineCount: UINT32, + actualLineCount: *mut UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x27f2a904, 0x4eb8, 0x441d, 0x96, 0x78, 0x05, 0x63, 0xf5, 0x3e, 0x3e, 0x2f)] +interface IDWriteFontFace4(IDWriteFontFace4Vtbl): IDWriteFontFace3(IDWriteFontFace3Vtbl) { + fn GetGlyphImageFormats_2( + glyph: UINT16, + ppemFirst: UINT32, + ppemLast: UINT32, + formats: *mut DWRITE_GLYPH_IMAGE_FORMATS, + ) -> HRESULT, + fn GetGlyphImageFormats_1() -> DWRITE_GLYPH_IMAGE_FORMATS, + fn GetGlyphImageData( + glyph: UINT16, + ppem: UINT32, + format: DWRITE_GLYPH_IMAGE_FORMATS, + data: *mut DWRITE_GLYPH_IMAGE_DATA, + context: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseGlyphImageData( + context: *mut c_void, + ) -> (), +}} +ENUM!{enum DWRITE_FONT_AXIS_TAG { + DWRITE_FONT_AXIS_TAG_WEIGHT = 0x74686777, + DWRITE_FONT_AXIS_TAG_WIDTH = 0x68746477, + DWRITE_FONT_AXIS_TAG_SLANT = 0x746e6c73, + DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE = 0x7a73706f, + DWRITE_FONT_AXIS_TAG_ITALIC = 0x6c617469, +}} +STRUCT!{struct DWRITE_FONT_AXIS_VALUE { + axisTag: DWRITE_FONT_AXIS_TAG, + value: FLOAT, +}} +STRUCT!{struct DWRITE_FONT_AXIS_RANGE { + axisTag: DWRITE_FONT_AXIS_TAG, + minValue: FLOAT, + maxValue: FLOAT, +}} +ENUM!{enum DWRITE_FONT_AXIS_ATTRIBUTES { + DWRITE_FONT_AXIS_ATTRIBUTES_NONE, + DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE, + DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN, +}} +RIDL!{#[uuid(0x98eff3a5, 0xb667, 0x479a, 0xb1, 0x45, 0xe2, 0xfa, 0x5b, 0x9f, 0xdc, 0x29)] +interface IDWriteFontFace5(IDWriteFontFace5Vtbl): IDWriteFontFace4(IDWriteFontFace4Vtbl) { + fn GetFontAxisValueCount() -> UINT32, + fn GetFontAxisValues( + values: *mut DWRITE_FONT_AXIS_VALUE, + valueCount: UINT32, + ) -> HRESULT, + fn HasVariations() -> BOOL, + fn GetFontResource( + resource: *mut *mut IDWriteFontResource, + ) -> HRESULT, + fn Equals( + fontFace: *mut IDWriteFontFace, + ) -> BOOL, +}} +RIDL!{#[uuid(0xc081fe77, 0x2fd1, 0x41ac, 0xa5, 0xa3, 0x34, 0x98, 0x3c, 0x4b, 0xa6, 0x1a)] +interface IDWriteFontFaceReference1(IDWriteFontFaceReference1Vtbl): + IDWriteFontFaceReference(IDWriteFontFaceReferenceVtbl) { + fn CreateFontFace( + fontFace: *mut *mut IDWriteFontFace5, + ) -> HRESULT, + fn GetFontAxisValueCount() -> UINT32, + fn GetFontAxisValues( + values: *mut DWRITE_FONT_AXIS_VALUE, + numValues: UINT32, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1f803a76, 0x6871, 0x48e8, 0x98, 0x7f, 0xb9, 0x75, 0x55, 0x1c, 0x50, 0xf2)] +interface IDWriteFontResource(IDWriteFontResourceVtbl): IUnknown(IUnknownVtbl) { + fn GetFontFile( + fontFile: *mut *mut IDWriteFontFile, + ) -> HRESULT, + fn GetFontFaceIndex() -> UINT32, + fn GetFontAxisCount() -> UINT32, + fn GetDefaultFontAxisValues( + values: *const DWRITE_FONT_AXIS_VALUE, + numValues: UINT32, + ) -> HRESULT, + fn GetFontAxisRanges( + ranges: *const DWRITE_FONT_AXIS_RANGE, + numRanges: UINT32, + ) -> HRESULT, + fn GetFontAxisAttributes( + axis: UINT32, + ) -> DWRITE_FONT_AXIS_ATTRIBUTES, + fn GetAxisNames( + axis: UINT32, + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn GetAxisValueNameCount( + axis: UINT32, + ) -> UINT32, + fn GetAxisValueNames( + axis: UINT32, + axisValue: UINT32, + axisRange: *mut DWRITE_FONT_AXIS_RANGE, + names: *mut *mut IDWriteLocalizedStrings, + ) -> HRESULT, + fn HasVariations() -> BOOL, + fn CreateFontFace( + simulations: DWRITE_FONT_SIMULATIONS, + axisValues: *const DWRITE_FONT_AXIS_VALUE, + numValues: UINT32, + fontFace: *mut *mut IDWriteFontFace5, + ) -> HRESULT, + fn CreateFontFaceReference( + simulations: DWRITE_FONT_SIMULATIONS, + axisValues: *const DWRITE_FONT_AXIS_VALUE, + numValues: UINT32, + reference: *mut *mut IDWriteFontFaceReference1, + ) -> HRESULT, +}} diff --git a/winapi/src/um/dxdiag.rs b/winapi/src/um/dxdiag.rs new file mode 100644 index 000000000..6f46c7ac7 --- /dev/null +++ b/winapi/src/um/dxdiag.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{CLSID_DxDiagProvider, + 0xa65b8071, 0x3bfe, 0x4213, 0x9a, 0x5b, 0x49, 0x1d, 0xa4, 0x46, 0x1c, 0xa7} +DEFINE_GUID!{IID_IDxDiagProvider, + 0x9c6b4cb0, 0x23f8, 0x49cc, 0xa3, 0xed, 0x45, 0xa5, 0x50, 0x00, 0xa6, 0xd2} +DEFINE_GUID!{IID_IDxDiagContainer, + 0x7d0f462f, 0x4064, 0x4862, 0xbc, 0x7f, 0x93, 0x3e, 0x50, 0x58, 0xc1, 0x0f} diff --git a/winapi/src/um/dxfile.rs b/winapi/src/um/dxfile.rs new file mode 100644 index 000000000..67ba32c4b --- /dev/null +++ b/winapi/src/um/dxfile.rs @@ -0,0 +1,23 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{CLSID_CDirectXFile, + 0x4516ec43, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3} +DEFINE_GUID!{IID_IDirectXFile, + 0x3d82ab40, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileEnumObject, + 0x3d82ab41, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileSaveObject, + 0x3d82ab42, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileObject, + 0x3d82ab43, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileData, + 0x3d82ab44, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileDataReference, + 0x3d82ab45, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{IID_IDirectXFileBinary, + 0x3d82ab46, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_DXFILEHeader, + 0x3d82ab43, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} diff --git a/winapi/src/um/dxgidebug.rs b/winapi/src/um/dxgidebug.rs new file mode 100644 index 000000000..3478da300 --- /dev/null +++ b/winapi/src/um/dxgidebug.rs @@ -0,0 +1,235 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, c_int, c_void}; +use shared::basetsd::{SIZE_T, UINT64}; +use shared::guiddef::{GUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, UINT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCSTR}; +pub const DXGI_DEBUG_BINARY_VERSION: DWORD = 1; +ENUM!{enum DXGI_DEBUG_RLO_FLAGS { + DXGI_DEBUG_RLO_SUMMARY = 0x1, + DXGI_DEBUG_RLO_DETAIL = 0x2, + DXGI_DEBUG_RLO_IGNORE_INTERNAL = 0x4, + DXGI_DEBUG_RLO_ALL = 0x7, +}} +pub type DXGI_DEBUG_ID = GUID; +DEFINE_GUID!{DXGI_DEBUG_ALL, + 0xe48ae283, 0xda80, 0x490b, 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x08} +DEFINE_GUID!{DXGI_DEBUG_DX, + 0x35cdd7fc, 0x13b2, 0x421d, 0xa5, 0xd7, 0x7e, 0x44, 0x51, 0x28, 0x7d, 0x64} +DEFINE_GUID!{DXGI_DEBUG_DXGI, + 0x25cddaa4, 0xb1c6, 0x47e1, 0xac, 0x3e, 0x98, 0x87, 0x5b, 0x5a, 0x2e, 0x2a} +DEFINE_GUID!{DXGI_DEBUG_APP, + 0x06cd6e01, 0x4219, 0x4ebd, 0x87, 0x09, 0x27, 0xed, 0x23, 0x36, 0x0c, 0x62} +ENUM!{enum DXGI_INFO_QUEUE_MESSAGE_CATEGORY { + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_UNKNOWN = 0, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_MISCELLANEOUS = 1, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_INITIALIZATION = 2, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_CLEANUP = 3, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_COMPILATION = 4, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_STATE_CREATION = 5, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_STATE_SETTING = 6, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_STATE_GETTING = 7, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_RESOURCE_MANIPULATION = 8, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_EXECUTION = 9, + DXGI_INFO_QUEUE_MESSAGE_CATEGORY_SHADER = 10, +}} +ENUM!{enum DXGI_INFO_QUEUE_MESSAGE_SEVERITY { + DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION = 0, + DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR = 1, + DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING = 2, + DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO = 3, + DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE = 4, +}} +pub type DXGI_INFO_QUEUE_MESSAGE_ID = c_int; +STRUCT!{struct DXGI_INFO_QUEUE_MESSAGE { + Producer: DXGI_DEBUG_ID, + Category: DXGI_INFO_QUEUE_MESSAGE_CATEGORY, + Severity: DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + ID: DXGI_INFO_QUEUE_MESSAGE_ID, + pDescription: *const c_char, + DescriptionByteLength: SIZE_T, +}} +STRUCT!{struct DXGI_INFO_QUEUE_FILTER_DESC { + NumCategories: UINT, + pCategoryList: *mut DXGI_INFO_QUEUE_MESSAGE_CATEGORY, + NumSeverities: UINT, + pSeverityList: *mut DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + NumIDs: UINT, + pIDList: *mut DXGI_INFO_QUEUE_MESSAGE_ID, +}} +STRUCT!{struct DXGI_INFO_QUEUE_FILTER { + AllowList: DXGI_INFO_QUEUE_FILTER_DESC, + DenyList: DXGI_INFO_QUEUE_FILTER_DESC, +}} +pub const DXGI_INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT: DWORD = 1024; +extern "system" { + pub fn DXGIGetDebugInterface( + riid: REFIID, + ppDebug: *mut *mut c_void, + ) -> HRESULT; +} +RIDL!{#[uuid(0xd67441c7, 0x672a, 0x476f, 0x9e, 0x82, 0xcd, 0x55, 0xb4, 0x49, 0x49, 0xce)] +interface IDXGIInfoQueue(IDXGIInfoQueueVtbl): IUnknown(IUnknownVtbl) { + fn SetMessageCountLimit( + Producer: DXGI_DEBUG_ID, + MessageCountLimit: UINT64, + ) -> HRESULT, + fn ClearStoredMessages( + Producer: DXGI_DEBUG_ID, + ) -> (), + fn GetMessage( + Producer: DXGI_DEBUG_ID, + MessageIndex: UINT64, + pMessage: *mut DXGI_INFO_QUEUE_MESSAGE, + pMessageByteLength: *mut SIZE_T, + ) -> HRESULT, + fn GetNumStoredMessagesAllowedByRetrievalFilters( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn GetNumStoredMessages( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn GetNumMessagesDiscardedByMessageCountLimit( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn GetMessageCountLimit( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn GetNumMessagesAllowedByStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn GetNumMessagesDeniedByStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> UINT64, + fn AddStorageFilterEntries( + Producer: DXGI_DEBUG_ID, + pFilter: *const DXGI_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetStorageFilter( + Producer: DXGI_DEBUG_ID, + pFilter: *mut DXGI_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> (), + fn PushEmptyStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushDenyAllStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushCopyOfStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushStorageFilter( + Producer: DXGI_DEBUG_ID, + pFilter: *const DXGI_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopStorageFilter( + Producer: DXGI_DEBUG_ID, + ) -> (), + fn GetStorageFilterStackSize( + Producer: DXGI_DEBUG_ID, + ) -> UINT, + fn AddRetrievalFilterEntries( + Producer: DXGI_DEBUG_ID, + pFilter: *const DXGI_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn GetRetrievalFilter( + Producer: DXGI_DEBUG_ID, + pFilter: *mut DXGI_INFO_QUEUE_FILTER, + pFilterByteLength: *mut SIZE_T, + ) -> HRESULT, + fn ClearRetrievalFilter( + Producer: DXGI_DEBUG_ID, + ) -> (), + fn PushEmptyRetrievalFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushDenyAllRetrievalFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushCopyOfRetrievalFilter( + Producer: DXGI_DEBUG_ID, + ) -> HRESULT, + fn PushRetrievalFilter( + Producer: DXGI_DEBUG_ID, + pFilter: *const DXGI_INFO_QUEUE_FILTER, + ) -> HRESULT, + fn PopRetrievalFilter( + Producer: DXGI_DEBUG_ID, + ) -> (), + fn GetRetrievalFilterStackSize( + Producer: DXGI_DEBUG_ID, + ) -> UINT, + fn AddMessage( + Producer: DXGI_DEBUG_ID, + Category: DXGI_INFO_QUEUE_MESSAGE_CATEGORY, + Severity: DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + ID: DXGI_INFO_QUEUE_MESSAGE_ID, + pDescription: LPCSTR, + ) -> HRESULT, + fn AddApplicationMessage( + Severity: DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + pDescription: LPCSTR, + ) -> HRESULT, + fn SetBreakOnCategory( + Producer: DXGI_DEBUG_ID, + Category: DXGI_INFO_QUEUE_MESSAGE_CATEGORY, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnSeverity( + Producer: DXGI_DEBUG_ID, + Severity: DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + bEnable: BOOL, + ) -> HRESULT, + fn SetBreakOnID( + Producer: DXGI_DEBUG_ID, + ID: DXGI_INFO_QUEUE_MESSAGE_ID, + bEnable: BOOL, + ) -> HRESULT, + fn GetBreakOnCategory( + Producer: DXGI_DEBUG_ID, + Category: DXGI_INFO_QUEUE_MESSAGE_CATEGORY, + ) -> BOOL, + fn GetBreakOnSeverity( + Producer: DXGI_DEBUG_ID, + Severity: DXGI_INFO_QUEUE_MESSAGE_SEVERITY, + ) -> BOOL, + fn GetBreakOnID( + Producer: DXGI_DEBUG_ID, + ID: DXGI_INFO_QUEUE_MESSAGE_ID, + ) -> BOOL, + fn SetMuteDebugOutput( + Producer: DXGI_DEBUG_ID, + bMute: BOOL, + ) -> (), + fn GetMuteDebugOutput( + Producer: DXGI_DEBUG_ID, + ) -> BOOL, +}} +RIDL!{#[uuid(0x119e7452, 0xde9e, 0x40fe, 0x88, 0x06, 0x88, 0xf9, 0x0c, 0x12, 0xb4, 0x41)] +interface IDXGIDebug(IDXGIDebugVtbl): IUnknown(IUnknownVtbl) { + fn ReportLiveObjects( + apiid: GUID, + flags: DXGI_DEBUG_RLO_FLAGS, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x119e7452, 0xde9e, 0x40fe, 0x88, 0x06, 0x88, 0xf9, 0x0c, 0x12, 0xb4, 0x41)] +interface IDXGIDebug1(IDXGIDebug1Vtbl): IDXGIDebug(IDXGIDebugVtbl) { + fn EnableLeakTrackingForThread() -> (), + fn DisableLeakTrackingForThread() -> (), + fn IsLeakTrackingEnabledForThread() -> BOOL, +}} +DEFINE_GUID!{IID_IDXGIInfoQueue, + 0xd67441c7, 0x672a, 0x476f, 0x9e, 0x82, 0xcd, 0x55, 0xb4, 0x49, 0x49, 0xce} +DEFINE_GUID!{IID_IDXGIDebug, + 0x119e7452, 0xde9e, 0x40fe, 0x88, 0x06, 0x88, 0xf9, 0x0c, 0x12, 0xb4, 0x41} +DEFINE_GUID!{IID_IDXGIDebug1, + 0xc5a05f0c, 0x16f2, 0x4adf, 0x9f, 0x4d, 0xa8, 0xc4, 0xd5, 0x8a, 0xc5, 0x50} diff --git a/winapi/src/um/dxva2api.rs b/winapi/src/um/dxva2api.rs new file mode 100644 index 000000000..db07c40e9 --- /dev/null +++ b/winapi/src/um/dxva2api.rs @@ -0,0 +1,706 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_float, c_void}; +use shared::basetsd::UINT64; +use shared::d3d9::{IDirect3DDevice9, IDirect3DSurface9}; +use shared::d3d9types::{D3DFORMAT, D3DPOOL}; +use shared::guiddef::{GUID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, FLOAT, HIWORD, LOWORD, UCHAR, UINT, USHORT}; +use shared::windef::{RECT, SIZE}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LONG, LONGLONG, PVOID, SHORT}; +DEFINE_GUID!{DXVA2_ModeMPEG2_MoComp, + 0xe6a9f44b, 0x61b0, 0x4563, 0x9e, 0xa4, 0x63, 0xd2, 0xa3, 0xc6, 0xfe, 0x66} +DEFINE_GUID!{DXVA2_ModeMPEG2_IDCT, + 0xbf22ad00, 0x03ea, 0x4690, 0x80, 0x77, 0x47, 0x33, 0x46, 0x20, 0x9b, 0x7e} +DEFINE_GUID!{DXVA2_ModeMPEG2_VLD, + 0xee27417f, 0x5e28, 0x4e65, 0xbe, 0xea, 0x1d, 0x26, 0xb5, 0x08, 0xad, 0xc9} +DEFINE_GUID!{DXVA2_ModeMPEG1_VLD, + 0x6f3ec719, 0x3735, 0x42cc, 0x80, 0x63, 0x65, 0xcc, 0x3c, 0xb3, 0x66, 0x16} +DEFINE_GUID!{DXVA2_ModeMPEG2and1_VLD, + 0x86695f12, 0x340e, 0x4f04, 0x9f, 0xd3, 0x92, 0x53, 0xdd, 0x32, 0x74, 0x60} +DEFINE_GUID!{DXVA2_ModeH264_A, + 0x1b81be64, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_B, + 0x1b81be65, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_C, + 0x1b81be66, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_D, + 0x1b81be67, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_E, + 0x1b81be68, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_F, + 0x1b81be69, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeH264_VLD_WithFMOASO_NoFGT, + 0xd5f04ff9, 0x3418, 0x45d8, 0x95, 0x61, 0x32, 0xa7, 0x6a, 0xae, 0x2d, 0xdd} +DEFINE_GUID!{DXVA2_ModeH264_VLD_Stereo_Progressive_NoFGT, + 0xd79be8da, 0x0cf1, 0x4c81, 0xb8, 0x2a, 0x69, 0xa4, 0xe2, 0x36, 0xf4, 0x3d} +DEFINE_GUID!{DXVA2_ModeH264_VLD_Stereo_NoFGT, + 0xf9aaccbb, 0xc2b6, 0x4cfc, 0x87, 0x79, 0x57, 0x07, 0xb1, 0x76, 0x05, 0x52} +DEFINE_GUID!{DXVA2_ModeH264_VLD_Multiview_NoFGT, + 0x705b9d82, 0x76cf, 0x49d6, 0xb7, 0xe6, 0xac, 0x88, 0x72, 0xdb, 0x01, 0x3c} +DEFINE_GUID!{DXVA2_ModeWMV8_A, + 0x1b81be80, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeWMV8_B, + 0x1b81be81, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeWMV9_A, + 0x1b81be90, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeWMV9_B, + 0x1b81be91, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeWMV9_C, + 0x1b81be94, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeVC1_A, + 0x1b81bea0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeVC1_B, + 0x1b81bea1, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeVC1_C, + 0x1b81bea2, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeVC1_D, + 0x1b81bea3, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_ModeVC1_D2010, + 0x1b81bea4, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_NoEncrypt, + 0x1b81bed0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5} +DEFINE_GUID!{DXVA2_VideoProcProgressiveDevice, + 0x5a54a0c9, 0xc7ec, 0x4bd9, 0x8e, 0xde, 0xf3, 0xc7, 0x5d, 0xc4, 0x39, 0x3b} +DEFINE_GUID!{DXVA2_VideoProcBobDevice, + 0x335aa36e, 0x7884, 0x43a4, 0x9c, 0x91, 0x7f, 0x87, 0xfa, 0xf3, 0xe3, 0x7e} +DEFINE_GUID!{DXVA2_VideoProcSoftwareDevice, + 0x4553d47f, 0xee7e, 0x4e3f, 0x94, 0x75, 0xdb, 0xf1, 0x37, 0x6c, 0x48, 0x10} +DEFINE_GUID!{DXVA2_ModeMPEG4pt2_VLD_Simple, + 0xefd64d74, 0xc9e8, 0x41d7, 0xa5, 0xe9, 0xe9, 0xb0, 0xe3, 0x9f, 0xa3, 0x19} +DEFINE_GUID!{DXVA2_ModeMPEG4pt2_VLD_AdvSimple_NoGMC, + 0xed418a9f, 0x010d, 0x4eda, 0x9a, 0xe3, 0x9a, 0x65, 0x35, 0x8d, 0x8d, 0x2e} +DEFINE_GUID!{DXVA2_ModeMPEG4pt2_VLD_AdvSimple_GMC, + 0xab998b5b, 0x4258, 0x44a9, 0x9f, 0xeb, 0x94, 0xe5, 0x97, 0xa6, 0xba, 0xae} +DEFINE_GUID!{DXVA2_ModeHEVC_VLD_Main, + 0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0} +DEFINE_GUID!{DXVA2_ModeHEVC_VLD_Main10, + 0x107af0e0, 0xef1a, 0x4d19, 0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13} +DEFINE_GUID!{DXVA2_ModeVP9_VLD_Profile0, + 0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e} +DEFINE_GUID!{DXVA2_ModeVP9_VLD_10bit_Profile2, + 0xa4c749ef, 0x6ecf, 0x48aa, 0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7} +DEFINE_GUID!{DXVA2_ModeVP8_VLD, + 0x90b899ea, 0x3a62, 0x4705, 0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7} +pub const DXVA2_ModeMPEG2_MOCOMP: GUID = DXVA2_ModeMPEG2_MoComp; +pub const DXVA2_ModeWMV8_PostProc: GUID = DXVA2_ModeWMV8_A; +pub const DXVA2_ModeWMV8_MoComp: GUID = DXVA2_ModeWMV8_B; +pub const DXVA2_ModeWMV9_PostProc: GUID = DXVA2_ModeWMV9_A; +pub const DXVA2_ModeWMV9_MoComp: GUID = DXVA2_ModeWMV9_B; +pub const DXVA2_ModeWMV9_IDCT: GUID = DXVA2_ModeWMV9_C; +pub const DXVA2_ModeVC1_PostProc: GUID = DXVA2_ModeVC1_A; +pub const DXVA2_ModeVC1_MoComp: GUID = DXVA2_ModeVC1_B; +pub const DXVA2_ModeVC1_IDCT: GUID = DXVA2_ModeVC1_C; +pub const DXVA2_ModeVC1_VLD: GUID = DXVA2_ModeVC1_D; +pub const DXVA2_ModeH264_MoComp_NoFGT: GUID = DXVA2_ModeH264_A; +pub const DXVA2_ModeH264_MoComp_FGT: GUID = DXVA2_ModeH264_B; +pub const DXVA2_ModeH264_IDCT_NoFGT: GUID = DXVA2_ModeH264_C; +pub const DXVA2_ModeH264_IDCT_FGT: GUID = DXVA2_ModeH264_D; +pub const DXVA2_ModeH264_VLD_NoFGT: GUID = DXVA2_ModeH264_E; +pub const DXVA2_ModeH264_VLD_FGT: GUID = DXVA2_ModeH264_F; +pub const DXVA2_E_NOT_INITIALIZED: HRESULT = 0x80041000; +pub const DXVA2_E_NEW_VIDEO_DEVICE: HRESULT = 0x80041001; +pub const DXVA2_E_VIDEO_DEVICE_LOCKED: HRESULT = 0x80041002; +pub const DXVA2_E_NOT_AVAILABLE: HRESULT = 0x80041003; +DEFINE_GUID!{IID_IDirect3DDeviceManager9, + 0xa0cade0f, 0x06d5, 0x4cf4, 0xa1, 0xc7, 0xf3, 0xcd, 0xd7, 0x25, 0xaa, 0x75} +DEFINE_GUID!{IID_IDirectXVideoAccelerationService, + 0xfc51a550, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02} +DEFINE_GUID!{IID_IDirectXVideoDecoderService, + 0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02} +DEFINE_GUID!{IID_IDirectXVideoProcessorService, + 0xfc51a552, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02} +DEFINE_GUID!{IID_IDirectXVideoDecoder, + 0xf2b0810a, 0xfd00, 0x43c9, 0x91, 0x8c, 0xdf, 0x94, 0xe2, 0xd8, 0xef, 0x7d} +DEFINE_GUID!{IID_IDirectXVideoProcessor, + 0x8c3a39f0, 0x916e, 0x4690, 0x80, 0x4f, 0x4c, 0x80, 0x01, 0x35, 0x5d, 0x25} +DEFINE_GUID!{IID_IDirectXVideoMemoryConfiguration, + 0xb7f916dd, 0xdb3b, 0x49c1, 0x84, 0xd7, 0xe4, 0x5e, 0xf9, 0x9e, 0xc7, 0x26} +pub const MAX_DEINTERLACE_SURFACES: usize = 32; +pub const MAX_SUBSTREAMS: usize = 15; +STRUCT!{struct DXVA2_ExtendedFormat { + value: UINT, +}} +BITFIELD!{DXVA2_ExtendedFormat value: UINT [ + SampleFormat set_SampleFormat[0..8], + VideoChromaSubsampling set_VideoChromaSubsampling[8..12], + NominalRange set_NominalRange[12..15], + VideoTransferMatrix set_VideoTransferMatrix[15..18], + VideoLighting set_VideoLighting[18..22], + VideoPrimaries set_VideoPrimaries[22..27], + VideoTransferFunction set_VideoTransferFunction[27..32], +]} +ENUM!{enum DXVA2_SampleFormat { + DXVA2_SampleFormatMask = 0xff, + DXVA2_SampleUnknown = 0, + DXVA2_SampleProgressiveFrame = 2, + DXVA2_SampleFieldInterleavedEvenFirst = 3, + DXVA2_SampleFieldInterleavedOddFirst = 4, + DXVA2_SampleFieldSingleEven = 5, + DXVA2_SampleFieldSingleOdd = 6, + DXVA2_SampleSubStream = 7, +}} +ENUM!{enum DXVA2_VideoChromaSubSampling { + DXVA2_VideoChromaSubsamplingMask = 0xf, + DXVA2_VideoChromaSubsampling_Unknown = 0, + DXVA2_VideoChromaSubsampling_ProgressiveChroma = 0x8, + DXVA2_VideoChromaSubsampling_Horizontally_Cosited = 0x4, + DXVA2_VideoChromaSubsampling_Vertically_Cosited = 0x2, + DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes = 0x1, + DXVA2_VideoChromaSubsampling_MPEG2 = DXVA2_VideoChromaSubsampling_Horizontally_Cosited | + DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes, + DXVA2_VideoChromaSubsampling_MPEG1 = + DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes, + DXVA2_VideoChromaSubsampling_DV_PAL = DXVA2_VideoChromaSubsampling_Horizontally_Cosited | + DXVA2_VideoChromaSubsampling_Vertically_Cosited, + DXVA2_VideoChromaSubsampling_Cosited = DXVA2_VideoChromaSubsampling_Horizontally_Cosited | + DXVA2_VideoChromaSubsampling_Vertically_Cosited | + DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes, +}} +ENUM!{enum DXVA2_NominalRange { + DXVA2_NominalRangeMask = 0x7, + DXVA2_NominalRange_Unknown = 0, + DXVA2_NominalRange_Normal = 1, + DXVA2_NominalRange_Wide = 2, + DXVA2_NominalRange_0_255 = 1, + DXVA2_NominalRange_16_235 = 2, + DXVA2_NominalRange_48_208 = 3, +}} +ENUM!{enum DXVA2_VideoTransferMatrix { + DXVA2_VideoTransferMatrixMask = 0x7, + DXVA2_VideoTransferMatrix_Unknown = 0, + DXVA2_VideoTransferMatrix_BT709 = 1, + DXVA2_VideoTransferMatrix_BT601 = 2, + DXVA2_VideoTransferMatrix_SMPTE240M = 3, +}} +ENUM!{enum DXVA2_VideoLighting { + DXVA2_VideoLightingMask = 0xf, + DXVA2_VideoLighting_Unknown = 0, + DXVA2_VideoLighting_bright = 1, + DXVA2_VideoLighting_office = 2, + DXVA2_VideoLighting_dim = 3, + DXVA2_VideoLighting_dark = 4, +}} +ENUM!{enum DXVA2_VideoPrimaries { + DXVA2_VideoPrimariesMask = 0x1f, + DXVA2_VideoPrimaries_Unknown = 0, + DXVA2_VideoPrimaries_reserved = 1, + DXVA2_VideoPrimaries_BT709 = 2, + DXVA2_VideoPrimaries_BT470_2_SysM = 3, + DXVA2_VideoPrimaries_BT470_2_SysBG = 4, + DXVA2_VideoPrimaries_SMPTE170M = 5, + DXVA2_VideoPrimaries_SMPTE240M = 6, + DXVA2_VideoPrimaries_EBU3213 = 7, + DXVA2_VideoPrimaries_SMPTE_C = 8, +}} +ENUM!{enum DXVA2_VideoTransferFunction { + DXVA2_VideoTransFuncMask = 0x1f, + DXVA2_VideoTransFunc_Unknown = 0, + DXVA2_VideoTransFunc_10 = 1, + DXVA2_VideoTransFunc_18 = 2, + DXVA2_VideoTransFunc_20 = 3, + DXVA2_VideoTransFunc_22 = 4, + DXVA2_VideoTransFunc_709 = 5, + DXVA2_VideoTransFunc_240M = 6, + DXVA2_VideoTransFunc_sRGB = 7, + DXVA2_VideoTransFunc_28 = 8, +}} +pub const DXVA2_VideoTransFunc_22_709: DWORD = DXVA2_VideoTransFunc_709; +pub const DXVA2_VideoTransFunc_22_240M: DWORD = DXVA2_VideoTransFunc_240M; +pub const DXVA2_VideoTransFunc_22_8bit_sRGB: DWORD = DXVA2_VideoTransFunc_sRGB; +STRUCT!{struct DXVA2_Frequency { + Numerator: UINT, + Denominator: UINT, +}} +STRUCT!{struct DXVA2_VideoDesc { + SampleWidth: UINT, + SampleHeight: UINT, + SampleFormat: DXVA2_ExtendedFormat, + Format: D3DFORMAT, + InputSampleFreq: DXVA2_Frequency, + OutputFrameFreq: DXVA2_Frequency, + UABProtectionLevel: UINT, + Reserved: UINT, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0003 { + DXVA2_DeinterlaceTech_Unknown = 0, + DXVA2_DeinterlaceTech_BOBLineReplicate = 0x1, + DXVA2_DeinterlaceTech_BOBVerticalStretch = 0x2, + DXVA2_DeinterlaceTech_BOBVerticalStretch4Tap = 0x4, + DXVA2_DeinterlaceTech_MedianFiltering = 0x8, + DXVA2_DeinterlaceTech_EdgeFiltering = 0x10, + DXVA2_DeinterlaceTech_FieldAdaptive = 0x20, + DXVA2_DeinterlaceTech_PixelAdaptive = 0x40, + DXVA2_DeinterlaceTech_MotionVectorSteered = 0x80, + DXVA2_DeinterlaceTech_InverseTelecine = 0x100, + DXVA2_DeinterlaceTech_Mask = 0x1ff, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0004 { + DXVA2_NoiseFilterLumaLevel = 1, + DXVA2_NoiseFilterLumaThreshold = 2, + DXVA2_NoiseFilterLumaRadius = 3, + DXVA2_NoiseFilterChromaLevel = 4, + DXVA2_NoiseFilterChromaThreshold = 5, + DXVA2_NoiseFilterChromaRadius = 6, + DXVA2_DetailFilterLumaLevel = 7, + DXVA2_DetailFilterLumaThreshold = 8, + DXVA2_DetailFilterLumaRadius = 9, + DXVA2_DetailFilterChromaLevel = 10, + DXVA2_DetailFilterChromaThreshold = 11, + DXVA2_DetailFilterChromaRadius = 12, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0005 { + DXVA2_NoiseFilterTech_Unsupported = 0, + DXVA2_NoiseFilterTech_Unknown = 0x1, + DXVA2_NoiseFilterTech_Median = 0x2, + DXVA2_NoiseFilterTech_Temporal = 0x4, + DXVA2_NoiseFilterTech_BlockNoise = 0x8, + DXVA2_NoiseFilterTech_MosquitoNoise = 0x10, + DXVA2_NoiseFilterTech_Mask = 0x1f, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0006 { + DXVA2_DetailFilterTech_Unsupported = 0, + DXVA2_DetailFilterTech_Unknown = 0x1, + DXVA2_DetailFilterTech_Edge = 0x2, + DXVA2_DetailFilterTech_Sharpening = 0x4, + DXVA2_DetailFilterTech_Mask = 0x7, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0007 { + DXVA2_ProcAmp_None = 0, + DXVA2_ProcAmp_Brightness = 0x1, + DXVA2_ProcAmp_Contrast = 0x2, + DXVA2_ProcAmp_Hue = 0x4, + DXVA2_ProcAmp_Saturation = 0x8, + DXVA2_ProcAmp_Mask = 0xf, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0008 { + DXVA2_VideoProcess_None = 0, + DXVA2_VideoProcess_YUV2RGB = 0x1, + DXVA2_VideoProcess_StretchX = 0x2, + DXVA2_VideoProcess_StretchY = 0x4, + DXVA2_VideoProcess_AlphaBlend = 0x8, + DXVA2_VideoProcess_SubRects = 0x10, + DXVA2_VideoProcess_SubStreams = 0x20, + DXVA2_VideoProcess_SubStreamsExtended = 0x40, + DXVA2_VideoProcess_YUV2RGBExtended = 0x80, + DXVA2_VideoProcess_AlphaBlendExtended = 0x100, + DXVA2_VideoProcess_Constriction = 0x200, + DXVA2_VideoProcess_NoiseFilter = 0x400, + DXVA2_VideoProcess_DetailFilter = 0x800, + DXVA2_VideoProcess_PlanarAlpha = 0x1000, + DXVA2_VideoProcess_LinearScaling = 0x2000, + DXVA2_VideoProcess_GammaCompensated = 0x4000, + DXVA2_VideoProcess_MaintainsOriginalFieldData = 0x8000, + DXVA2_VideoProcess_Mask = 0xffff, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0009 { + DXVA2_VPDev_HardwareDevice = 0x1, + DXVA2_VPDev_EmulatedDXVA1 = 0x2, + DXVA2_VPDev_SoftwareDevice = 0x4, + DXVA2_VPDev_Mask = 0x7, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0010 { + DXVA2_SampleData_RFF = 0x1, + DXVA2_SampleData_TFF = 0x2, + DXVA2_SampleData_RFF_TFF_Present = 0x4, + DXVA2_SampleData_Mask = 0xffff, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0011 { + DXVA2_DestData_RFF = 0x1, + DXVA2_DestData_TFF = 0x2, + DXVA2_DestData_RFF_TFF_Present = 0x4, + DXVA2_DestData_Mask = 0xffff, +}} +STRUCT!{struct DXVA2_VideoProcessorCaps { + DeviceCaps: UINT, + InputPool: D3DPOOL, + NumForwardRefSamples: UINT, + NumBackwardRefSamples: UINT, + Reserved: UINT, + DeinterlaceTechnology: UINT, + ProcAmpControlCaps: UINT, + VideoProcessorOperations: UINT, + NoiseFilterTechnology: UINT, + DetailFilterTechnology: UINT, +}} +STRUCT!{struct DXVA2_Fixed32_s { + Fraction: USHORT, + Value: SHORT, +}} +UNION!{union DXVA2_Fixed32 { + [u32; 1], + s s_mut: DXVA2_Fixed32_s, + ll s_ll: LONG, +}} +STRUCT!{struct DXVA2_AYUVSample8 { + Cr: UCHAR, + Cb: UCHAR, + Y: UCHAR, + Alpha: UCHAR, +}} +STRUCT!{struct DXVA2_AYUVSample16 { + Cr: USHORT, + Cb: USHORT, + Y: USHORT, + Alpha: USHORT, +}} +pub type REFERENCE_TIME = LONGLONG; +STRUCT!{struct DXVA2_VideoSample { + Start: REFERENCE_TIME, + End: REFERENCE_TIME, + SampleFormat: DXVA2_ExtendedFormat, + SrcSurface: *mut IDirect3DSurface9, + SrcRect: RECT, + DstRect: RECT, + Pal: [DXVA2_AYUVSample8; 16], + PlanarAlpha: DXVA2_Fixed32, + SampleData: DWORD, +}} +STRUCT!{struct DXVA2_ValueRange { + MinValue: DXVA2_Fixed32, + MaxValue: DXVA2_Fixed32, + DefaultValue: DXVA2_Fixed32, + StepSize: DXVA2_Fixed32, +}} +STRUCT!{struct DXVA2_ProcAmpValues { + Brightness: DXVA2_Fixed32, + Contrast: DXVA2_Fixed32, + Hue: DXVA2_Fixed32, + Saturation: DXVA2_Fixed32, +}} +STRUCT!{struct DXVA2_FilterValues { + Level: DXVA2_Fixed32, + Threshold: DXVA2_Fixed32, + Radius: DXVA2_Fixed32, +}} +STRUCT!{struct DXVA2_VideoProcessBltParams { + TargetFrame: REFERENCE_TIME, + TargetRect: RECT, + ConstrictionSize: SIZE, + StreamingFlags: UINT, + BackgroundColor: DXVA2_AYUVSample16, + DestFormat: DXVA2_ExtendedFormat, + ProcAmpValues: DXVA2_ProcAmpValues, + Alpha: DXVA2_Fixed32, + NoiseFilterLuma: DXVA2_FilterValues, + NoiseFilterChroma: DXVA2_FilterValues, + DetailFilterLuma: DXVA2_FilterValues, + DetailFilterChroma: DXVA2_FilterValues, + DestData: DWORD, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0012 { + DXVA2_PictureParametersBufferType = 0, + DXVA2_MacroBlockControlBufferType = 1, + DXVA2_ResidualDifferenceBufferType = 2, + DXVA2_DeblockingControlBufferType = 3, + DXVA2_InverseQuantizationMatrixBufferType = 4, + DXVA2_SliceControlBufferType = 5, + DXVA2_BitStreamDateBufferType = 6, + DXVA2_MotionVectorBuffer = 7, + DXVA2_FilmGrainBuffer = 8, +}} +ENUM!{enum __MIDL___MIDL_itf_dxva2api_0000_0000_0013 { + DXVA2_VideoDecoderRenderTarget = 0, + DXVA2_VideoProcessorRenderTarget = 1, + DXVA2_VideoSoftwareRenderTarget = 2, +}} +STRUCT!{struct DXVA2_ConfigPictureDecode { + guidConfigBitstreamEncryption: GUID, + guidConfigMBcontrolEncryption: GUID, + guidConfigResidDiffEncryption: GUID, + ConfigBitstreamRaw: UINT, + ConfigMBcontrolRasterOrder: UINT, + ConfigResidDiffHost: UINT, + ConfigSpatialResid8: UINT, + ConfigResid8Subtraction: UINT, + ConfigSpatialHost8or9Clipping: UINT, + ConfigSpatialResidInterleaved: UINT, + ConfigIntraResidUnsigned: UINT, + ConfigResidDiffAccelerator: UINT, + ConfigHostInverseScan: UINT, + ConfigSpecificIDCT: UINT, + Config4GroupedCoefs: UINT, + ConfigMinRenderTargetBuffCount: USHORT, + ConfigDecoderSpecific: USHORT, +}} +STRUCT!{struct DXVA2_DecodeBufferDesc { + CompressedBufferType: DWORD, + BufferIndex: UINT, + DataOffset: UINT, + DataSize: UINT, + FirstMBaddress: UINT, + NumMBsInBuffer: UINT, + Width: UINT, + Height: UINT, + Stride: UINT, + ReservedBits: UINT, + pvPVPState: PVOID, +}} +STRUCT!{struct DXVA2_AES_CTR_IV { + IV: UINT64, + Count: UINT64, +}} +STRUCT!{struct DXVA2_DecodeExtensionData { + Function: UINT, + pPrivateInputData: PVOID, + PrivateInputDataSize: UINT, + pPrivateOutputData: PVOID, + PrivateOutputDataSize: UINT, +}} +pub const DXVA2_DECODE_GET_DRIVER_HANDLE: UINT = 0x725; +pub const DXVA2_DECODE_SPECIFY_ENCRYPTED_BLOCKS: UINT = 0x724; +STRUCT!{struct DXVA2_DecodeExecuteParams { + NumCompBuffers: UINT, + pCompressedBuffers: *mut DXVA2_DecodeBufferDesc, + pExtensionData: *mut DXVA2_DecodeExtensionData, +}} +RIDL!{#[uuid(0xa0cade0f, 0x06d5, 0x4cf4, 0xa1, 0xc7, 0xf3, 0xcd, 0xd7, 0x25, 0xaa, 0x75)] +interface IDirect3DDeviceManager9(IDirect3DDeviceManager9Vtbl): IUnknown(IUnknownVtbl) { + fn ResetDevice( + pDevice: *mut IDirect3DDevice9, + resetToken: UINT, + ) -> HRESULT, + fn OpenDeviceHandle( + phDevice: *mut HANDLE, + ) -> HRESULT, + fn CloseDeviceHandle( + hDevice: HANDLE, + ) -> HRESULT, + fn TestDevice( + hDevice: HANDLE, + ) -> HRESULT, + fn LockDevice( + hDevice: HANDLE, + ppDevice: *mut *mut IDirect3DDevice9, + fBloc: BOOL, + ) -> HRESULT, + fn UnlockDevice( + hDevice: HANDLE, + fSaveState: BOOL, + ) -> HRESULT, + fn GetVideoService( + hDevice: HANDLE, + riid: REFIID, + ppService: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfc51a550, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02)] +interface IDirectXVideoAccelerationService(IDirectXVideoAccelerationServiceVtbl): + IUnknown(IUnknownVtbl) { + fn CreateSurface( + Width: UINT, + Height: UINT, + BackBuffers: UINT, + Format: D3DFORMAT, + Pool: D3DPOOL, + Usage: DWORD, + DxvaType: DWORD, + ppSurface: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02)] +interface IDirectXVideoDecoderService(IDirectXVideoDecoderServiceVtbl): + IDirectXVideoAccelerationService(IDirectXVideoAccelerationServiceVtbl) { + fn GetDecoderDeviceGuids( + pCount: *mut UINT, + pGuids: *mut *mut GUID, + ) -> HRESULT, + fn GetDecoderRenderTargets( + Guid: REFGUID, + pCount: *mut UINT, + pFormats: *mut *mut D3DFORMAT, + ) -> HRESULT, + fn GetDecoderConfigurations( + Guid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + pReserved: *mut c_void, + pCount: *mut UINT, + ppConfigs: *mut *mut DXVA2_ConfigPictureDecode, + ) -> HRESULT, + fn CreateVideoDecoder( + Guid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + pConfig: *const DXVA2_ConfigPictureDecode, + ppDecoderRenderTargets: *mut *mut IDirect3DSurface9, + NumRenderTargets: UINT, + ppDecode: *mut *mut IDirectXVideoDecoder, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfc51a552, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02)] +interface IDirectXVideoProcessorService(IDirectXVideoProcessorServiceVtbl): + IDirectXVideoAccelerationService(IDirectXVideoAccelerationServiceVtbl) { + fn RegisterVideoProcessorSoftwareDevice( + pCallbacks: *mut c_void, + ) -> HRESULT, + fn GetVideoProcessorDeviceGuids( + pVideoDesc: *mut DXVA2_VideoDesc, + pCount: *mut UINT, + pGuids: *mut *mut GUID, + ) -> HRESULT, + fn GetVideoProcessorRenderTargets( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + pCount: *mut UINT, + pFormats: *mut *mut D3DFORMAT, + ) -> HRESULT, + fn GetVideoProcessorSubStreamFormats( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + RenderTargetFormat: D3DFORMAT, + pCount: *mut UINT, + pFormats: *mut *mut D3DFORMAT, + ) -> HRESULT, + fn GetVideoProcessorCaps( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + RenderTargetFormat: D3DFORMAT, + pCaps: *mut DXVA2_VideoProcessorCaps, + ) -> HRESULT, + fn GetProcAmpRange( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + RenderTargetFormat: D3DFORMAT, + ProcAmpCap: UINT, + pRange: *mut DXVA2_ValueRange, + ) -> HRESULT, + fn GetFilterPropertyRange( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + RenderTargetFormat: D3DFORMAT, + FilterSetting: UINT, + pRange: *mut DXVA2_ValueRange, + ) -> HRESULT, + fn CreateVideoProcessor( + VideoProcDeviceGuid: REFGUID, + pVideoDesc: *const DXVA2_VideoDesc, + RenderTargetFormat: D3DFORMAT, + MaxNumSubStreams: UINT, + ppVidProcess: *mut *mut IDirectXVideoProcessor, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf2b0810a, 0xfd00, 0x43c9, 0x91, 0x8c, 0xdf, 0x94, 0xe2, 0xd8, 0xef, 0x7d)] +interface IDirectXVideoDecoder(IDirectXVideoDecoderVtbl): IUnknown(IUnknownVtbl) { + fn GetVideoDecoderService( + ppService: *mut *mut IDirectXVideoDecoderService, + ) -> HRESULT, + fn GetCreationParameters( + pDeviceGuid: *mut GUID, + pVideoDesc: *mut DXVA2_VideoDesc, + pConfig: *mut DXVA2_ConfigPictureDecode, + pDecoderRenderTargets: *mut *mut *mut IDirect3DSurface9, + pNumSurfaces: *mut UINT, + ) -> HRESULT, + fn GetBuffer( + BufferType: UINT, + ppBuffer: *mut *mut c_void, + pBufferSize: *mut UINT, + ) -> HRESULT, + fn ReleaseBuffer( + BufferType: UINT, + ) -> HRESULT, + fn BeginFrame( + pRenderTarget: *mut IDirect3DSurface9, + pvPVPData: *mut c_void, + ) -> HRESULT, + fn EndFrame( + pHandleComplete: *mut HANDLE, + ) -> HRESULT, + fn Execute( + pExecuteParams: *const DXVA2_DecodeExecuteParams, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8c3a39f0, 0x916e, 0x4690, 0x80, 0x4f, 0x4c, 0x80, 0x01, 0x35, 0x5d, 0x25)] +interface IDirectXVideoProcessor(IDirectXVideoProcessorVtbl): IUnknown(IUnknownVtbl) { + fn GetVideoProcessorService( + ppService: *mut *mut IDirectXVideoProcessorService, + ) -> HRESULT, + fn GetCreationParameters( + pDeviceGuid: *mut GUID, + pVideoDesc: *mut DXVA2_VideoDesc, + pRenderTargetFormat: *mut D3DFORMAT, + pMaxNumSubStreams: *mut UINT, + ) -> HRESULT, + fn GetVideoProcessorCaps( + pCaps: *mut DXVA2_VideoProcessorCaps, + ) -> HRESULT, + fn GetProcAmpRange( + ProcAmpCap: UINT, + pRange: *mut DXVA2_ValueRange, + ) -> HRESULT, + fn GetFilterPropertyRange( + FilterSetting: UINT, + pRange: *mut DXVA2_ValueRange, + ) -> HRESULT, + fn VideoProcessBlt( + pRenderTarget: *mut IDirect3DSurface9, + pBltParams: *const DXVA2_VideoProcessBltParams, + pSamples: *const DXVA2_VideoSample, + NumSamples: UINT, + pHandleComplete: *mut HANDLE, + ) -> HRESULT, +}} +ENUM!{enum DXVA2_SurfaceType { + DXVA2_SurfaceType_DecoderRenderTarget = 0, + DXVA2_SurfaceType_ProcessorRenderTarget = 1, + DXVA2_SurfaceType_D3DRenderTargetTexture = 2, +}} +RIDL!{#[uuid(0xb7f916dd, 0xdb3b, 0x49c1, 0x84, 0xd7, 0xe4, 0x5e, 0xf9, 0x9e, 0xc7, 0x26)] +interface IDirectXVideoMemoryConfiguration(IDirectXVideoMemoryConfigurationVtbl): + IUnknown(IUnknownVtbl) { + fn GetAvailableSurfaceTypeByIndex( + dwTypeIndex: DWORD, + pdwType: *mut DXVA2_SurfaceType, + ) -> HRESULT, + fn SetSurfaceType( + dwType: DXVA2_SurfaceType, + ) -> HRESULT, +}} +extern "system" { + pub fn DXVA2CreateDirect3DDeviceManager9( + pResetToken: *mut UINT, + ppDeviceManager: *mut *mut IDirect3DDeviceManager9, + ) -> HRESULT; + pub fn DXVA2CreateVideoService( + pDD: *mut IDirect3DDevice9, + riid: REFIID, + ppService: *mut *mut c_void, + ) -> HRESULT; +} +#[inline] +pub fn DXVA2FloatToFixed(_float_: c_float) -> DXVA2_Fixed32 { + unsafe { + let mut _fixed_: DXVA2_Fixed32 = ::core::mem::uninitialized(); + _fixed_.s_mut().Fraction = LOWORD((_float_ * 0x10000 as c_float) as DWORD); + _fixed_.s_mut().Value = HIWORD((_float_ * 0x10000 as c_float) as DWORD) as SHORT; + _fixed_ + } +} +#[inline] +pub fn DXVA2FixedToFloat(_fixed_: DXVA2_Fixed32) -> c_float { + unsafe { + _fixed_.s().Value as FLOAT + _fixed_.s().Fraction as FLOAT / 0x10000 as FLOAT + } +} +#[inline] +pub fn DXVA2_Fixed32TransparentAlpha() -> DXVA2_Fixed32 { + unsafe { + let mut _fixed_: DXVA2_Fixed32 = ::core::mem::uninitialized(); + _fixed_.s_mut().Fraction = 0; + _fixed_.s_mut().Value = 0; + _fixed_ + } +} +#[inline] +pub fn DXVA2_Fixed32OpaqueAlpha() -> DXVA2_Fixed32 { + unsafe { + let mut _fixed_: DXVA2_Fixed32 = ::core::mem::uninitialized(); + _fixed_.s_mut().Fraction = 0; + _fixed_.s_mut().Value = 1; + _fixed_ + } +} diff --git a/winapi/src/um/dxvahd.rs b/winapi/src/um/dxvahd.rs new file mode 100644 index 000000000..755dfdc23 --- /dev/null +++ b/winapi/src/um/dxvahd.rs @@ -0,0 +1,555 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::d3d9::{IDirect3DDevice9Ex, IDirect3DSurface9}; +use shared::d3d9types::{D3DCOLOR, D3DFORMAT, D3DPOOL}; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, FLOAT, INT, UINT}; +use shared::windef::{RECT, SIZE}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, ULONGLONG}; +DEFINE_GUID!{IID_IDXVAHD_Device, + 0x95f12dfd, 0xd77e, 0x49be, 0x81, 0x5f, 0x57, 0xd5, 0x79, 0x63, 0x4d, 0x6d} +DEFINE_GUID!{IID_IDXVAHD_VideoProcessor, + 0x95f4edf4, 0x6e03, 0x4cd7, 0xbe, 0x1b, 0x30, 0x75, 0xd6, 0x65, 0xaa, 0x52} +ENUM!{enum DXVAHD_FRAME_FORMAT { + DXVAHD_FRAME_FORMAT_PROGRESSIVE = 0, + DXVAHD_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST = 1, + DXVAHD_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST = 2, +}} +ENUM!{enum DXVAHD_DEVICE_USAGE { + DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL = 0, + DXVAHD_DEVICE_USAGE_OPTIMAL_SPEED = 1, + DXVAHD_DEVICE_USAGE_OPTIMAL_QUALITY = 2, +}} +ENUM!{enum DXVAHD_SURFACE_TYPE { + DXVAHD_SURFACE_TYPE_VIDEO_INPUT = 0, + DXVAHD_SURFACE_TYPE_VIDEO_INPUT_PRIVATE = 1, + DXVAHD_SURFACE_TYPE_VIDEO_OUTPUT = 2, +}} +ENUM!{enum DXVAHD_DEVICE_TYPE { + DXVAHD_DEVICE_TYPE_HARDWARE = 0, + DXVAHD_DEVICE_TYPE_SOFTWARE = 1, + DXVAHD_DEVICE_TYPE_REFERENCE = 2, + DXVAHD_DEVICE_TYPE_OTHER = 3, +}} +ENUM!{enum DXVAHD_DEVICE_CAPS { + DXVAHD_DEVICE_CAPS_LINEAR_SPACE = 0x1, + DXVAHD_DEVICE_CAPS_xvYCC = 0x2, + DXVAHD_DEVICE_CAPS_RGB_RANGE_CONVERSION = 0x4, + DXVAHD_DEVICE_CAPS_YCbCr_MATRIX_CONVERSION = 0x8, +}} +ENUM!{enum DXVAHD_FEATURE_CAPS { + DXVAHD_FEATURE_CAPS_ALPHA_FILL = 0x1, + DXVAHD_FEATURE_CAPS_CONSTRICTION = 0x2, + DXVAHD_FEATURE_CAPS_LUMA_KEY = 0x4, + DXVAHD_FEATURE_CAPS_ALPHA_PALETTE = 0x8, +}} +ENUM!{enum DXVAHD_FILTER_CAPS { + DXVAHD_FILTER_CAPS_BRIGHTNESS = 0x1, + DXVAHD_FILTER_CAPS_CONTRAST = 0x2, + DXVAHD_FILTER_CAPS_HUE = 0x4, + DXVAHD_FILTER_CAPS_SATURATION = 0x8, + DXVAHD_FILTER_CAPS_NOISE_REDUCTION = 0x10, + DXVAHD_FILTER_CAPS_EDGE_ENHANCEMENT = 0x20, + DXVAHD_FILTER_CAPS_ANAMORPHIC_SCALING = 0x40, +}} +ENUM!{enum DXVAHD_INPUT_FORMAT_CAPS { + DXVAHD_INPUT_FORMAT_CAPS_RGB_INTERLACED = 0x1, + DXVAHD_INPUT_FORMAT_CAPS_RGB_PROCAMP = 0x2, + DXVAHD_INPUT_FORMAT_CAPS_RGB_LUMA_KEY = 0x4, + DXVAHD_INPUT_FORMAT_CAPS_PALETTE_INTERLACED = 0x8, +}} +ENUM!{enum DXVAHD_PROCESSOR_CAPS { + DXVAHD_PROCESSOR_CAPS_DEINTERLACE_BLEND = 0x1, + DXVAHD_PROCESSOR_CAPS_DEINTERLACE_BOB = 0x2, + DXVAHD_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE = 0x4, + DXVAHD_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION = 0x8, + DXVAHD_PROCESSOR_CAPS_INVERSE_TELECINE = 0x10, + DXVAHD_PROCESSOR_CAPS_FRAME_RATE_CONVERSION = 0x20, +}} +ENUM!{enum DXVAHD_ITELECINE_CAPS { + DXVAHD_ITELECINE_CAPS_32 = 0x1, + DXVAHD_ITELECINE_CAPS_22 = 0x2, + DXVAHD_ITELECINE_CAPS_2224 = 0x4, + DXVAHD_ITELECINE_CAPS_2332 = 0x8, + DXVAHD_ITELECINE_CAPS_32322 = 0x10, + DXVAHD_ITELECINE_CAPS_55 = 0x20, + DXVAHD_ITELECINE_CAPS_64 = 0x40, + DXVAHD_ITELECINE_CAPS_87 = 0x80, + DXVAHD_ITELECINE_CAPS_222222222223 = 0x100, + DXVAHD_ITELECINE_CAPS_OTHER = 0x80000000, +}} +ENUM!{enum DXVAHD_FILTER { + DXVAHD_FILTER_BRIGHTNESS = 0, + DXVAHD_FILTER_CONTRAST = 1, + DXVAHD_FILTER_HUE = 2, + DXVAHD_FILTER_SATURATION = 3, + DXVAHD_FILTER_NOISE_REDUCTION = 4, + DXVAHD_FILTER_EDGE_ENHANCEMENT = 5, + DXVAHD_FILTER_ANAMORPHIC_SCALING = 6, +}} +ENUM!{enum DXVAHD_BLT_STATE { + DXVAHD_BLT_STATE_TARGET_RECT = 0, + DXVAHD_BLT_STATE_BACKGROUND_COLOR = 1, + DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE = 2, + DXVAHD_BLT_STATE_ALPHA_FILL = 3, + DXVAHD_BLT_STATE_CONSTRICTION = 4, + DXVAHD_BLT_STATE_PRIVATE = 1000, +}} +ENUM!{enum DXVAHD_ALPHA_FILL_MODE { + DXVAHD_ALPHA_FILL_MODE_OPAQUE = 0, + DXVAHD_ALPHA_FILL_MODE_BACKGROUND = 1, + DXVAHD_ALPHA_FILL_MODE_DESTINATION = 2, + DXVAHD_ALPHA_FILL_MODE_SOURCE_STREAM = 3, +}} +ENUM!{enum DXVAHD_STREAM_STATE { + DXVAHD_STREAM_STATE_D3DFORMAT = 0, + DXVAHD_STREAM_STATE_FRAME_FORMAT = 1, + DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE = 2, + DXVAHD_STREAM_STATE_OUTPUT_RATE = 3, + DXVAHD_STREAM_STATE_SOURCE_RECT = 4, + DXVAHD_STREAM_STATE_DESTINATION_RECT = 5, + DXVAHD_STREAM_STATE_ALPHA = 6, + DXVAHD_STREAM_STATE_PALETTE = 7, + DXVAHD_STREAM_STATE_LUMA_KEY = 8, + DXVAHD_STREAM_STATE_ASPECT_RATIO = 9, + DXVAHD_STREAM_STATE_FILTER_BRIGHTNESS = 100, + DXVAHD_STREAM_STATE_FILTER_CONTRAST = 101, + DXVAHD_STREAM_STATE_FILTER_HUE = 102, + DXVAHD_STREAM_STATE_FILTER_SATURATION = 103, + DXVAHD_STREAM_STATE_FILTER_NOISE_REDUCTION = 104, + DXVAHD_STREAM_STATE_FILTER_EDGE_ENHANCEMENT = 105, + DXVAHD_STREAM_STATE_FILTER_ANAMORPHIC_SCALING = 106, + DXVAHD_STREAM_STATE_PRIVATE = 1000, +}} +ENUM!{enum DXVAHD_OUTPUT_RATE { + DXVAHD_OUTPUT_RATE_NORMAL = 0, + DXVAHD_OUTPUT_RATE_HALF = 1, + DXVAHD_OUTPUT_RATE_CUSTOM = 2, +}} +STRUCT!{struct DXVAHD_RATIONAL { + Numerator: UINT, + Denominator: UINT, +}} +STRUCT!{struct DXVAHD_COLOR_RGBA { + R: FLOAT, + G: FLOAT, + B: FLOAT, + A: FLOAT, +}} +STRUCT!{struct DXVAHD_COLOR_YCbCrA { + Y: FLOAT, + Cb: FLOAT, + Cr: FLOAT, + A: FLOAT, +}} +UNION!{union DXVAHD_COLOR { + [u32; 4], + RGB RGB_mut: DXVAHD_COLOR_RGBA, + YCbCr YCbCr_mut: DXVAHD_COLOR_YCbCrA, +}} +STRUCT!{struct DXVAHD_CONTENT_DESC { + InputFrameFormat: DXVAHD_FRAME_FORMAT, + InputFrameRate: DXVAHD_RATIONAL, + InputWidth: UINT, + InputHeight: UINT, + OutputFrameRate: DXVAHD_RATIONAL, + OutputWidth: UINT, + OutputHeight: UINT, +}} +STRUCT!{struct DXVAHD_VPDEVCAPS { + DeviceType: DXVAHD_DEVICE_TYPE, + DeviceCaps: UINT, + FeatureCaps: UINT, + FilterCaps: UINT, + InputFormatCaps: UINT, + InputPool: D3DPOOL, + OutputFormatCount: UINT, + InputFormatCount: UINT, + VideoProcessorCount: UINT, + MaxInputStreams: UINT, + MaxStreamStates: UINT, +}} +STRUCT!{struct DXVAHD_VPCAPS { + VPGuid: GUID, + PastFrames: UINT, + FutureFrames: UINT, + ProcessorCaps: UINT, + ITelecineCaps: UINT, + CustomRateCount: UINT, +}} +STRUCT!{struct DXVAHD_CUSTOM_RATE_DATA { + CustomRate: DXVAHD_RATIONAL, + OutputFrames: UINT, + InputInterlaced: BOOL, + InputFramesOrFields: UINT, +}} +STRUCT!{struct DXVAHD_FILTER_RANGE_DATA { + Minimum: INT, + Maximum: INT, + Default: INT, + Multiplier: FLOAT, +}} +STRUCT!{struct DXVAHD_BLT_STATE_TARGET_RECT_DATA { + Enable: BOOL, + TargetRect: RECT, +}} +STRUCT!{struct DXVAHD_BLT_STATE_BACKGROUND_COLOR_DATA { + YCbCr: BOOL, + BackgroundColor: DXVAHD_COLOR, +}} +STRUCT!{struct DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE_DATA { + Value: UINT, +}} +BITFIELD!{DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE_DATA Value: UINT [ + Usage set_Usage[0..1], + RGB_Range set_RGB_Range[1..2], + YCbCr_Matrix set_YCbCr_Matrix[2..3], + YCbCr_xvYCC set_YCbCr_xvYCC[3..4], + Reserved set_Reserved[4..32], +]} +STRUCT!{struct DXVAHD_BLT_STATE_ALPHA_FILL_DATA { + Mode: DXVAHD_ALPHA_FILL_MODE, + StreamNumber: UINT, +}} +STRUCT!{struct DXVAHD_BLT_STATE_CONSTRICTION_DATA { + Enable: BOOL, + Size: SIZE, +}} +STRUCT!{struct DXVAHD_BLT_STATE_PRIVATE_DATA { + Guid: GUID, + DataSize: UINT, + pData: *mut c_void, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_D3DFORMAT_DATA { + Format: D3DFORMAT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_FRAME_FORMAT_DATA { + FrameFormat: DXVAHD_FRAME_FORMAT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE_DATA { + Value: UINT, +}} +BITFIELD!{DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE_DATA Value: UINT [ + Type set_Type[0..1], + RGB_Range set_RGB_Range[1..2], + YCbCr_Matrix set_YCbCr_Matrix[2..3], + YCbCr_xvYCC set_YCbCr_xvYCC[3..4], + Reserved set_Reserved[4..32], +]} +STRUCT!{struct DXVAHD_STREAM_STATE_OUTPUT_RATE_DATA { + RepeatFrame: BOOL, + OutputRate: DXVAHD_OUTPUT_RATE, + CustomRate: DXVAHD_RATIONAL, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_SOURCE_RECT_DATA { + Enable: BOOL, + SourceRect: RECT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_DESTINATION_RECT_DATA { + Enable: BOOL, + DestinationRect: RECT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_ALPHA_DATA { + Enable: BOOL, + Alpha: FLOAT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_PALETTE_DATA { + Count: UINT, + pEntries: *mut D3DCOLOR, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_LUMA_KEY_DATA { + Enable: BOOL, + Lower: FLOAT, + Upper: FLOAT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_ASPECT_RATIO_DATA { + Enable: BOOL, + SourceAspectRatio: DXVAHD_RATIONAL, + DestinationAspectRatio: DXVAHD_RATIONAL, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_FILTER_DATA { + Enable: BOOL, + Level: INT, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_PRIVATE_DATA { + Guid: GUID, + DataSize: UINT, + pData: *mut c_void, +}} +STRUCT!{struct DXVAHD_STREAM_DATA { + Enable: BOOL, + OutputIndex: UINT, + InputFrameOrField: UINT, + PastFrames: UINT, + FutureFrames: UINT, + ppPastSurfaces: *mut *mut IDirect3DSurface9, + pInputSurface: *mut IDirect3DSurface9, + ppFutureSurfaces: *mut *mut IDirect3DSurface9, +}} +STRUCT!{struct DXVAHD_STREAM_STATE_PRIVATE_IVTC_DATA { + Enable: BOOL, + ITelecineFlags: UINT, + Frames: UINT, + InputField: UINT, +}} +RIDL!{#[uuid(0x95f12dfd, 0xd77e, 0x49be, 0x81, 0x5f, 0x57, 0xd5, 0x79, 0x63, 0x4d, 0x6d)] +interface IDXVAHD_Device(IDXVAHD_DeviceVtbl): IUnknown(IUnknownVtbl) { + fn CreateVideoSurface( + Width: UINT, + Height: UINT, + Format: D3DFORMAT, + Pool: D3DPOOL, + Usage: DWORD, + Type: DXVAHD_SURFACE_TYPE, + NumSurfaces: UINT, + ppSurfaces: *mut *mut IDirect3DSurface9, + pSharedHandle: *mut HANDLE, + ) -> HRESULT, + fn GetVideoProcessorDeviceCaps( + pCaps: *mut DXVAHD_VPDEVCAPS, + ) -> HRESULT, + fn GetVideoProcessorOutputFormats( + Count: UINT, + pFormats: *mut D3DFORMAT, + ) -> HRESULT, + fn GetVideoProcessorInputFormats( + Count: UINT, + pFormats: *mut D3DFORMAT, + ) -> HRESULT, + fn GetVideoProcessorCaps( + Count: UINT, + pCaps: *mut DXVAHD_VPCAPS, + ) -> HRESULT, + fn GetVideoProcessorCustomRates( + pVPGuid: *const GUID, + Count: UINT, + pRates: *mut DXVAHD_CUSTOM_RATE_DATA, + ) -> HRESULT, + fn GetVideoProcessorFilterRange( + Filter: DXVAHD_FILTER, + pRange: *mut DXVAHD_FILTER_RANGE_DATA, + ) -> HRESULT, + fn CreateVideoProcessor( + pVPGuid: *const GUID, + ppVideoProcessor: *mut *mut IDXVAHD_VideoProcessor, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x95f4edf4, 0x6e03, 0x4cd7, 0xbe, 0x1b, 0x30, 0x75, 0xd6, 0x65, 0xaa, 0x52)] +interface IDXVAHD_VideoProcessor(IDXVAHD_VideoProcessorVtbl): IUnknown(IUnknownVtbl) { + fn SetVideoProcessBltState( + State: DXVAHD_BLT_STATE, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn GetVideoProcessBltState( + State: DXVAHD_BLT_STATE, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn SetVideoProcessStreamState( + StreamNumber: UINT, + State: DXVAHD_STREAM_STATE, + DataSize: UINT, + pData: *const c_void, + ) -> HRESULT, + fn GetVideoProcessStreamState( + StreamNumber: UINT, + State: DXVAHD_STREAM_STATE, + DataSize: UINT, + pData: *mut c_void, + ) -> HRESULT, + fn VideoProcessBltHD( + pOutputSurface: *mut IDirect3DSurface9, + OutputFrame: UINT, + StreamCount: UINT, + pStreams: *const DXVAHD_STREAM_DATA, + ) -> HRESULT, +}} +FN!{stdcall PDXVAHDSW_CreateDevice( + pD3DDevice: *mut IDirect3DDevice9Ex, + phDevice: *mut HANDLE, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_ProposeVideoPrivateFormat( + hDevice: HANDLE, + pFormat: *mut D3DFORMAT, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorDeviceCaps( + hDevice: HANDLE, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + pCaps: *mut DXVAHD_VPDEVCAPS, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorOutputFormats( + hDevice: HANDLE, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + Count: UINT, + pFormats: *mut D3DFORMAT, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorInputFormats( + hDevice: HANDLE, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + Count: UINT, + pFormats: *mut D3DFORMAT, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorCaps( + hDevice: HANDLE, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + Count: UINT, + pCaps: *mut DXVAHD_VPCAPS, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorCustomRates( + hDevice: HANDLE, + pVPGuid: *const GUID, + Count: UINT, + pRates: *mut DXVAHD_CUSTOM_RATE_DATA, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessorFilterRange( + hDevice: HANDLE, + Filter: DXVAHD_FILTER, + pRange: *mut DXVAHD_FILTER_RANGE_DATA, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_DestroyDevice( + hDevice: HANDLE, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_CreateVideoProcessor( + hDevice: HANDLE, + pVPGuid: *const GUID, + phVideoProcessor: *mut HANDLE, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_SetVideoProcessBltState( + hVideoProcessor: HANDLE, + State: DXVAHD_BLT_STATE, + DataSize: UINT, + pData: *const c_void, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessBltStatePrivate( + hVideoProcessor: HANDLE, + pData: *mut DXVAHD_BLT_STATE_PRIVATE_DATA, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_SetVideoProcessStreamState( + hVideoProcessor: HANDLE, + StreamNumber: UINT, + State: DXVAHD_STREAM_STATE, + DataSize: UINT, + pData: *const c_void, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_GetVideoProcessStreamStatePrivate( + hVideoProcessor: HANDLE, + StreamNumber: UINT, + pData: *mut DXVAHD_STREAM_STATE_PRIVATE_DATA, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_VideoProcessBltHD( + hVideoProcessor: HANDLE, + pOutputSurface: *mut IDirect3DSurface9, + OutputFrame: UINT, + StreamCount: UINT, + pStreams: *const DXVAHD_STREAM_DATA, +) -> HRESULT} +FN!{stdcall PDXVAHDSW_DestroyVideoProcessor( + hVideoProcessor: HANDLE, +) -> HRESULT} +STRUCT!{struct DXVAHDSW_CALLBACKS { + CreateDevice: PDXVAHDSW_CreateDevice, + ProposeVideoPrivateFormat: PDXVAHDSW_ProposeVideoPrivateFormat, + GetVideoProcessorDeviceCaps: PDXVAHDSW_GetVideoProcessorDeviceCaps, + GetVideoProcessorOutputFormats: PDXVAHDSW_GetVideoProcessorOutputFormats, + GetVideoProcessorInputFormats: PDXVAHDSW_GetVideoProcessorInputFormats, + GetVideoProcessorCaps: PDXVAHDSW_GetVideoProcessorCaps, + GetVideoProcessorCustomRates: PDXVAHDSW_GetVideoProcessorCustomRates, + GetVideoProcessorFilterRange: PDXVAHDSW_GetVideoProcessorFilterRange, + DestroyDevice: PDXVAHDSW_DestroyDevice, + CreateVideoProcessor: PDXVAHDSW_CreateVideoProcessor, + SetVideoProcessBltState: PDXVAHDSW_SetVideoProcessBltState, + GetVideoProcessBltStatePrivate: PDXVAHDSW_GetVideoProcessBltStatePrivate, + SetVideoProcessStreamState: PDXVAHDSW_SetVideoProcessStreamState, + GetVideoProcessStreamStatePrivate: PDXVAHDSW_GetVideoProcessStreamStatePrivate, + VideoProcessBltHD: PDXVAHDSW_VideoProcessBltHD, + DestroyVideoProcessor: PDXVAHDSW_DestroyVideoProcessor, +}} +FN!{stdcall PDXVAHDSW_Plugin( + Size: UINT, + pCallbacks: *mut c_void, +) -> HRESULT} +DEFINE_GUID!{DXVAHDControlGuid, + 0xa0386e75, 0xf70c, 0x464c, 0xa9, 0xce, 0x33, 0xc4, 0x4e, 0x09, 0x16, 0x23} +DEFINE_GUID!{DXVAHDETWGUID_CREATEVIDEOPROCESSOR, + 0x681e3d1e, 0x5674, 0x4fb3, 0xa5, 0x03, 0x2f, 0x20, 0x55, 0xe9, 0x1f, 0x60} +DEFINE_GUID!{DXVAHDETWGUID_VIDEOPROCESSBLTSTATE, + 0x76c94b5a, 0x193f, 0x4692, 0x94, 0x84, 0xa4, 0xd9, 0x99, 0xda, 0x81, 0xa8} +DEFINE_GUID!{DXVAHDETWGUID_VIDEOPROCESSSTREAMSTATE, + 0x262c0b02, 0x209d, 0x47ed, 0x94, 0xd8, 0x82, 0xae, 0x02, 0xb8, 0x4a, 0xa7} +DEFINE_GUID!{DXVAHDETWGUID_VIDEOPROCESSBLTHD, + 0xbef3d435, 0x78c7, 0x4de3, 0x97, 0x07, 0xcd, 0x1b, 0x08, 0x3b, 0x16, 0x0a} +DEFINE_GUID!{DXVAHDETWGUID_VIDEOPROCESSBLTHD_STREAM, + 0x27ae473e, 0xa5fc, 0x4be5, 0xb4, 0xe3, 0xf2, 0x49, 0x94, 0xd3, 0xc4, 0x95} +DEFINE_GUID!{DXVAHDETWGUID_DESTROYVIDEOPROCESSOR, + 0xf943f0a0, 0x3f16, 0x43e0, 0x80, 0x93, 0x10, 0x5a, 0x98, 0x6a, 0xa5, 0xf1} +STRUCT!{struct DXVAHDETW_CREATEVIDEOPROCESSOR { + pObject: ULONGLONG, + pD3D9Ex: ULONGLONG, + VPGuid: GUID, +}} +STRUCT!{struct DXVAHDETW_VIDEOPROCESSBLTSTATE { + pObject: ULONGLONG, + State: DXVAHD_BLT_STATE, + DataSize: UINT, + SetState: BOOL, +}} +STRUCT!{struct DXVAHDETW_VIDEOPROCESSSTREAMSTATE { + pObject: ULONGLONG, + StreamNumber: UINT, + State: DXVAHD_STREAM_STATE, + DataSize: UINT, + SetState: BOOL, +}} +STRUCT!{struct DXVAHDETW_VIDEOPROCESSBLTHD { + pObject: ULONGLONG, + pOutputSurface: ULONGLONG, + TargetRect: RECT, + OutputFormat: D3DFORMAT, + ColorSpace: UINT, + OutputFrame: UINT, + StreamCount: UINT, + Enter: BOOL, +}} +STRUCT!{struct DXVAHDETW_VIDEOPROCESSBLTHD_STREAM { + pObject: ULONGLONG, + pInputSurface: ULONGLONG, + SourceRect: RECT, + DestinationRect: RECT, + InputFormat: D3DFORMAT, + FrameFormat: DXVAHD_FRAME_FORMAT, + ColorSpace: UINT, + StreamNumber: UINT, + OutputIndex: UINT, + InputFrameOrField: UINT, + PastFrames: UINT, + FutureFrames: UINT, +}} +STRUCT!{struct DXVAHDETW_DESTROYVIDEOPROCESSOR { + pObject: ULONGLONG, +}} +extern "system" { + pub fn DXVAHD_CreateDevice( + pD3DDevice: *mut IDirect3DDevice9Ex, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + pPlugin: PDXVAHDSW_Plugin, + ppDevice: *mut *mut IDXVAHD_Device, + ) -> HRESULT; +} +FN!{stdcall PDXVAHD_CreateDevice( + pD3DDevice: *mut IDirect3DDevice9Ex, + pContentDesc: *const DXVAHD_CONTENT_DESC, + Usage: DXVAHD_DEVICE_USAGE, + pPlugin: PDXVAHDSW_Plugin, + ppDevice: *mut *mut IDXVAHD_Device, +) -> HRESULT} diff --git a/winapi/src/um/enclaveapi.rs b/winapi/src/um/enclaveapi.rs new file mode 100644 index 000000000..b2da8e145 --- /dev/null +++ b/winapi/src/um/enclaveapi.rs @@ -0,0 +1,64 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{PSIZE_T, SIZE_T}; +use shared::minwindef::{BOOL, DWORD, LPCVOID, LPDWORD, LPVOID}; +use shared::ntdef::{HANDLE}; +use um::minwinbase::LPENCLAVE_ROUTINE; +use um::winnt::{LPCSTR, LPCWSTR}; +extern "system" { + pub fn IsEnclaveTypeSupported( + flEnclaveType: DWORD, + ) -> BOOL; + pub fn CreateEnclave( + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + dwInitialCommitment: SIZE_T, + flEnclaveType: DWORD, + lpEnclaveInformation: LPCVOID, + dwInfoLength: DWORD, + lpEnclaveError: LPDWORD, + ) -> LPVOID; + pub fn LoadEnclaveData( + hProcess: HANDLE, + lpAddress: LPVOID, + lpBuffer: LPCVOID, + nSize: SIZE_T, + flProtect: DWORD, + lpPageInformation: LPCVOID, + dwInfoLength: DWORD, + lpNumberOfBytesWritten: PSIZE_T, + lpEnclaveError: LPDWORD, + ) -> BOOL; + pub fn InitializeEnclave( + hProcess: HANDLE, + lpAddress: LPVOID, + lpEnclaveInformation: LPCVOID, + dwInfoLength: DWORD, + lpEnclaveError: LPDWORD, + ) -> BOOL; + pub fn LoadEnclaveImageA( + lpEnclaveAddress: LPVOID, + lpImageName: LPCSTR, + ) -> BOOL; + pub fn LoadEnclaveImageW( + lpEnclaveAddress: LPVOID, + lpImageName: LPCWSTR, + ) -> BOOL; + pub fn CallEnclave( + lpRoutine: LPENCLAVE_ROUTINE, + lpParameter: LPVOID, + fWaitForThread: BOOL, + lpReturnValue: *mut LPVOID, + ) -> BOOL; + pub fn TerminateEnclave( + lpAddress: LPVOID, + fWait: BOOL, + ) -> BOOL; + pub fn DeleteEnclave( + lpAddress: LPVOID, + ) -> BOOL; +} diff --git a/winapi/src/um/endpointvolume.rs b/winapi/src/um/endpointvolume.rs new file mode 100644 index 000000000..384e47b6c --- /dev/null +++ b/winapi/src/um/endpointvolume.rs @@ -0,0 +1,123 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_float; +use shared::basetsd::UINT32; +use shared::guiddef::{GUID, LPCGUID}; +use shared::minwindef::{BOOL, DWORD, UINT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +STRUCT!{struct AUDIO_VOLUME_NOTIFICATION_DATA { + guidEventContext: GUID, + bMuted: BOOL, + fMasterVolume: c_float, + nChannels: UINT, + afChannelVolumes: [c_float; 1], +}} +pub type PAUDIO_VOLUME_NOTIFICATION_DATA = *mut AUDIO_VOLUME_NOTIFICATION_DATA; +pub const ENDPOINT_HARDWARE_SUPPORT_VOLUME: DWORD = 0x00000001; +pub const ENDPOINT_HARDWARE_SUPPORT_MUTE: DWORD = 0x00000002; +pub const ENDPOINT_HARDWARE_SUPPORT_METER: DWORD = 0x00000004; +RIDL!{#[uuid(0x657804fa, 0xd6ad, 0x4496, 0x8a, 0x60, 0x35, 0x27, 0x52, 0xaf, 0x4f, 0x89)] +interface IAudioEndpointVolumeCallback(IAudioEndpointVolumeCallbackVtbl): IUnknown(IUnknownVtbl) { + fn OnNotify( + pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5cdf2c82, 0x841e, 0x4546, 0x97, 0x22, 0x0c, 0xf7, 0x40, 0x78, 0x22, 0x9a)] +interface IAudioEndpointVolume(IAudioEndpointVolumeVtbl): IUnknown(IUnknownVtbl) { + fn RegisterControlChangeNotify( + pNotify: *mut IAudioEndpointVolumeCallback, + ) -> HRESULT, + fn UnregisterControlChangeNotify( + pNotify: *mut IAudioEndpointVolumeCallback, + ) -> HRESULT, + fn GetChannelCount( + pnChannelCount: *mut UINT, + ) -> HRESULT, + fn SetMasterVolumeLevel( + fLevelDB: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn SetMasterVolumeLevelScalar( + fLevel: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn GetMasterVolumeLevel( + pfLevelDB: *mut c_float, + ) -> HRESULT, + fn GetMasterVolumeLevelScalar( + pfLevel: *mut c_float, + ) -> HRESULT, + fn SetChannelVolumeLevel( + nChannel: UINT, + fLevelDB: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn SetChannelVolumeLevelScalar( + nChannel: UINT, + fLevel: c_float, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn GetChannelVolumeLevel( + nChannel: UINT, + pfLevelDB: *mut c_float, + ) -> HRESULT, + fn GetChannelVolumeLevelScalar( + nChannel: UINT, + pfLevel: *mut c_float, + ) -> HRESULT, + fn SetMute( + bMute: BOOL, + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn GetMute( + pbMute: *mut BOOL, + ) -> HRESULT, + fn GetVolumeStepInfo( + pnStep: *mut UINT, + pnStepCount: *mut UINT, + ) -> HRESULT, + fn VolumeStepUp( + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn VolumeStepDown( + pguidEventContext: LPCGUID, + ) -> HRESULT, + fn QueryHardwareSupport( + pdwHardwareSupportMask: *mut DWORD, + ) -> HRESULT, + fn GetVolumeRange( + pflVolumeMindB: *mut c_float, + pflVolumeMaxdB: *mut c_float, + pflVolumeIncrementdB: *mut c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x66e11784, 0xf695, 0x4f28, 0xa5, 0x05, 0xa7, 0x08, 0x00, 0x81, 0xa7, 0x8f)] +interface IAudioEndpointVolumeEx(IAudioEndpointVolumeExVtbl): + IAudioEndpointVolume(IAudioEndpointVolumeVtbl) { + fn GetVolumeRangeChannel( + iChannel: UINT, + pflVolumeMindB: *mut c_float, + pflVolumeMaxdB: *mut c_float, + pflVolumeIncrementdB: *mut c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc02216f6, 0x8c67, 0x4b5b, 0x9d, 0x00, 0xd0, 0x08, 0xe7, 0x3e, 0x00, 0x64)] +interface IAudioMeterInformation(IAudioMeterInformationVtbl): IUnknown(IUnknownVtbl) { + fn GetPeakValue( + pfPeak: *mut c_float, + ) -> HRESULT, + fn GetMeteringChannelCount( + pnChannelCount: *mut UINT, + ) -> HRESULT, + fn GetChannelsPeakValues( + u32ChannelCount: UINT32, + afPeakValues: *mut c_float, + ) -> HRESULT, + fn QueryHardwareSupport( + pdwHardwareSupportMask: *mut DWORD, + ) -> HRESULT, +}} diff --git a/winapi/src/um/errhandlingapi.rs b/winapi/src/um/errhandlingapi.rs new file mode 100644 index 000000000..66d7618de --- /dev/null +++ b/winapi/src/um/errhandlingapi.rs @@ -0,0 +1,75 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-errorhandling-l1 +use shared::basetsd::ULONG_PTR; +use shared::minwindef::{BOOL, DWORD, LPDWORD, UINT, ULONG}; +use um::winnt::{ + EXCEPTION_POINTERS, LONG, LPCSTR, LPCWSTR, PCONTEXT, PEXCEPTION_RECORD, + PVECTORED_EXCEPTION_HANDLER, PVOID, +}; +FN!{stdcall PTOP_LEVEL_EXCEPTION_FILTER( + ExceptionInfo: *mut EXCEPTION_POINTERS, +) -> LONG} +pub type LPTOP_LEVEL_EXCEPTION_FILTER = PTOP_LEVEL_EXCEPTION_FILTER; +extern "system" { + pub fn RaiseException( + dwExceptionCode: DWORD, + dwExceptionFlags: DWORD, + nNumberOfArguments: DWORD, + lpArguments: *const ULONG_PTR, + ); + pub fn UnhandledExceptionFilter( + ExceptionInfo: *mut EXCEPTION_POINTERS, + ) -> LONG; + pub fn SetUnhandledExceptionFilter( + lpTopLevelExceptionFilter: LPTOP_LEVEL_EXCEPTION_FILTER, + ) -> LPTOP_LEVEL_EXCEPTION_FILTER; + pub fn GetLastError() -> DWORD; + pub fn SetLastError( + dwErrCode: DWORD, + ); + pub fn GetErrorMode() -> UINT; + pub fn SetErrorMode( + uMode: UINT, + ) -> UINT; + pub fn AddVectoredExceptionHandler( + First: ULONG, + Handler: PVECTORED_EXCEPTION_HANDLER, + ) -> PVOID; + pub fn RemoveVectoredExceptionHandler( + Handle: PVOID, + ) -> ULONG; + pub fn AddVectoredContinueHandler( + First: ULONG, + Handler: PVECTORED_EXCEPTION_HANDLER, + ) -> PVOID; + pub fn RemoveVectoredContinueHandler( + Handle: PVOID, + ) -> ULONG; +} +// RestoreLastError +extern "system" { + pub fn RaiseFailFastException( + pExceptionRecord: PEXCEPTION_RECORD, + pContextRecord: PCONTEXT, + dwFlags: DWORD, + ); + pub fn FatalAppExitA( + uAction: UINT, + lpMessageText: LPCSTR, + ); + pub fn FatalAppExitW( + uAction: UINT, + lpMessageText: LPCWSTR, + ); + pub fn GetThreadErrorMode() -> DWORD; + pub fn SetThreadErrorMode( + dwNewMode: DWORD, + lpOldMode: LPDWORD, + ) -> BOOL; +} +// What library provides this function? +// TerminateProcessOnMemoryExhaustion diff --git a/winapi/src/um/evntcons.rs b/winapi/src/um/evntcons.rs new file mode 100644 index 000000000..48d4d700d --- /dev/null +++ b/winapi/src/um/evntcons.rs @@ -0,0 +1,229 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::ULONG64; +use shared::evntprov::EVENT_DESCRIPTOR; +use shared::evntrace::ETW_BUFFER_CONTEXT; +use shared::guiddef::{GUID, LPGUID}; +use shared::minwindef::{PUCHAR, PULONG, PUSHORT, UCHAR, ULONG, USHORT}; +use um::winnt::{ + ANYSIZE_ARRAY, BOOLEAN, LARGE_INTEGER, PCSTR, PSECURITY_DESCRIPTOR, PSID, PVOID, ULONGLONG, +}; +pub const EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID: USHORT = 0x0001; +pub const EVENT_HEADER_EXT_TYPE_SID: USHORT = 0x0002; +pub const EVENT_HEADER_EXT_TYPE_TS_ID: USHORT = 0x0003; +pub const EVENT_HEADER_EXT_TYPE_INSTANCE_INFO: USHORT = 0x0004; +pub const EVENT_HEADER_EXT_TYPE_STACK_TRACE32: USHORT = 0x0005; +pub const EVENT_HEADER_EXT_TYPE_STACK_TRACE64: USHORT = 0x0006; +pub const EVENT_HEADER_EXT_TYPE_PEBS_INDEX: USHORT = 0x0007; +pub const EVENT_HEADER_EXT_TYPE_PMC_COUNTERS: USHORT = 0x0008; +pub const EVENT_HEADER_EXT_TYPE_PSM_KEY: USHORT = 0x0009; +pub const EVENT_HEADER_EXT_TYPE_EVENT_KEY: USHORT = 0x000A; +pub const EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL: USHORT = 0x000B; +pub const EVENT_HEADER_EXT_TYPE_PROV_TRAITS: USHORT = 0x000C; +pub const EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY: USHORT = 0x000D; +pub const EVENT_HEADER_EXT_TYPE_CONTROL_GUID: USHORT = 0x000E; +pub const EVENT_HEADER_EXT_TYPE_MAX: USHORT = 0x000F; +STRUCT!{struct EVENT_HEADER_EXTENDED_DATA_ITEM_s { + bitfield: USHORT, +}} +BITFIELD!{EVENT_HEADER_EXTENDED_DATA_ITEM_s bitfield: USHORT [ + Linkage set_Linkage[0..1], + Reserved2 set_Reserved2[1..16], +]} +STRUCT!{struct EVENT_HEADER_EXTENDED_DATA_ITEM { + Reserved1: USHORT, + ExtType: USHORT, + s: EVENT_HEADER_EXTENDED_DATA_ITEM_s, + DataSize: USHORT, + DataPtr: ULONGLONG, +}} +pub type PEVENT_HEADER_EXTENDED_DATA_ITEM = *mut EVENT_HEADER_EXTENDED_DATA_ITEM; +STRUCT!{struct EVENT_EXTENDED_ITEM_INSTANCE { + InstanceId: ULONG, + ParentInstanceId: ULONG, + ParentGuid: GUID, +}} +pub type PEVENT_EXTENDED_ITEM_INSTANCE = *mut EVENT_EXTENDED_ITEM_INSTANCE; +STRUCT!{struct EVENT_EXTENDED_ITEM_RELATED_ACTIVITYID { + RelatedActivityId: GUID, +}} +pub type PEVENT_EXTENDED_ITEM_RELATED_ACTIVITYID = *mut EVENT_EXTENDED_ITEM_RELATED_ACTIVITYID; +STRUCT!{struct EVENT_EXTENDED_ITEM_TS_ID { + SessionId: ULONG, +}} +pub type PEVENT_EXTENDED_ITEM_TS_ID = *mut EVENT_EXTENDED_ITEM_TS_ID; +STRUCT!{struct EVENT_EXTENDED_ITEM_STACK_TRACE32 { + MatchId: ULONG64, + Address: [ULONG; ANYSIZE_ARRAY], +}} +pub type PEVENT_EXTENDED_ITEM_STACK_TRACE32 = *mut EVENT_EXTENDED_ITEM_STACK_TRACE32; +STRUCT!{struct EVENT_EXTENDED_ITEM_STACK_TRACE64 { + MatchId: ULONG64, + Address: [ULONG64; ANYSIZE_ARRAY], +}} +pub type PEVENT_EXTENDED_ITEM_STACK_TRACE64 = *mut EVENT_EXTENDED_ITEM_STACK_TRACE64; +STRUCT!{struct EVENT_EXTENDED_ITEM_PEBS_INDEX { + PebsIndex: ULONG64, +}} +pub type PEVENT_EXTENDED_ITEM_PEBS_INDEX = *mut EVENT_EXTENDED_ITEM_PEBS_INDEX; +STRUCT!{struct EVENT_EXTENDED_ITEM_PMC_COUNTERS { + Counter: [ULONG64; ANYSIZE_ARRAY], +}} +pub type PEVENT_EXTENDED_ITEM_PMC_COUNTERS = *mut EVENT_EXTENDED_ITEM_PMC_COUNTERS; +STRUCT!{struct EVENT_EXTENDED_ITEM_PROCESS_START_KEY { + ProcessStartKey: ULONG64, +}} +pub type PEVENT_EXTENDED_ITEM_PROCESS_START_KEY = *mut EVENT_EXTENDED_ITEM_PROCESS_START_KEY; +STRUCT!{struct EVENT_EXTENDED_ITEM_EVENT_KEY { + Key: ULONG64, +}} +pub type PEVENT_EXTENDED_ITEM_EVENT_KEY = *mut EVENT_EXTENDED_ITEM_EVENT_KEY; +pub const EVENT_HEADER_PROPERTY_XML: USHORT = 0x0001; +pub const EVENT_HEADER_PROPERTY_FORWARDED_XML: USHORT = 0x0002; +pub const EVENT_HEADER_PROPERTY_LEGACY_EVENTLOG: USHORT = 0x0004; +pub const EVENT_HEADER_PROPERTY_RELOGGABLE: USHORT = 0x0008; +pub const EVENT_HEADER_FLAG_EXTENDED_INFO: USHORT = 0x0001; +pub const EVENT_HEADER_FLAG_PRIVATE_SESSION: USHORT = 0x0002; +pub const EVENT_HEADER_FLAG_STRING_ONLY: USHORT = 0x0004; +pub const EVENT_HEADER_FLAG_TRACE_MESSAGE: USHORT = 0x0008; +pub const EVENT_HEADER_FLAG_NO_CPUTIME: USHORT = 0x0010; +pub const EVENT_HEADER_FLAG_32_BIT_HEADER: USHORT = 0x0020; +pub const EVENT_HEADER_FLAG_64_BIT_HEADER: USHORT = 0x0040; +pub const EVENT_HEADER_FLAG_CLASSIC_HEADER: USHORT = 0x0100; +pub const EVENT_HEADER_FLAG_PROCESSOR_INDEX: USHORT = 0x0200; +STRUCT!{struct EVENT_HEADER_u_s { + KernelTime: ULONG, + UserTime: ULONG, +}} +UNION!{union EVENT_HEADER_u { + [u64; 1], + s s_mut: EVENT_HEADER_u_s, + ProcessorTime ProcessorTime_mut: ULONG64, +}} +STRUCT!{struct EVENT_HEADER { + Size: USHORT, + HeaderType: USHORT, + Flags: USHORT, + EventProperty: USHORT, + ThreadId: ULONG, + ProcessId: ULONG, + TimeStamp: LARGE_INTEGER, + ProviderId: GUID, + EventDescriptor: EVENT_DESCRIPTOR, + u: EVENT_HEADER_u, + ActivityId: GUID, +}} +pub type PEVENT_HEADER = *mut EVENT_HEADER; +STRUCT!{struct EVENT_RECORD { + EventHeader: EVENT_HEADER, + BufferContext: ETW_BUFFER_CONTEXT, + ExtendedDataCount: USHORT, + UserDataLength: USHORT, + ExtendedData: PEVENT_HEADER_EXTENDED_DATA_ITEM, + UserData: PVOID, + UserContext: PVOID, +}} +pub type PEVENT_RECORD = *mut EVENT_RECORD; +pub type PCEVENT_RECORD = *const EVENT_RECORD; +pub const EVENT_ENABLE_PROPERTY_SID: USHORT = 0x00000001; +pub const EVENT_ENABLE_PROPERTY_TS_ID: USHORT = 0x00000002; +pub const EVENT_ENABLE_PROPERTY_STACK_TRACE: USHORT = 0x00000004; +pub const EVENT_ENABLE_PROPERTY_PSM_KEY: USHORT = 0x00000008; +pub const EVENT_ENABLE_PROPERTY_IGNORE_KEYWORD_0: USHORT = 0x00000010; +pub const EVENT_ENABLE_PROPERTY_PROVIDER_GROUP: USHORT = 0x00000020; +pub const EVENT_ENABLE_PROPERTY_ENABLE_KEYWORD_0: USHORT = 0x00000040; +pub const EVENT_ENABLE_PROPERTY_PROCESS_START_KEY: USHORT = 0x00000080; +pub const EVENT_ENABLE_PROPERTY_EVENT_KEY: USHORT = 0x00000100; +pub const EVENT_ENABLE_PROPERTY_EXCLUDE_INPRIVATE: USHORT = 0x00000200; +pub const PROCESS_TRACE_MODE_REAL_TIME: ULONG = 0x00000100; +pub const PROCESS_TRACE_MODE_RAW_TIMESTAMP: ULONG = 0x00001000; +pub const PROCESS_TRACE_MODE_EVENT_RECORD: ULONG = 0x10000000; +#[inline] +pub unsafe fn GetEventProcessorIndex(EventRecord: PCEVENT_RECORD) -> ULONG { + if (*EventRecord).EventHeader.Flags & EVENT_HEADER_FLAG_PROCESSOR_INDEX != 0 { + *(*EventRecord).BufferContext.u.ProcessorIndex() as ULONG + } else { + (*EventRecord).BufferContext.u.s().ProcessorNumber as ULONG + } +} +ENUM!{enum ETW_PROVIDER_TRAIT_TYPE { + EtwProviderTraitTypeGroup = 1, + EtwProviderTraitDecodeGuid = 2, + EtwProviderTraitTypeMax, +}} +#[inline] +unsafe fn strnlen(s: PCSTR, max_len: isize) -> isize { + let mut len = 0; + while *s.offset(len) != 0 && len < max_len { + len += 1 + } + len +} +// Taken from Rust 1.17.0 sources +#[inline] +unsafe fn read_unaligned<T>(src: *const T) -> T { + use core::{mem, ptr}; + let mut tmp: T = mem::uninitialized(); + ptr::copy_nonoverlapping( + src as *const u8, + &mut tmp as *mut T as *mut u8, + mem::size_of::<T>(), + ); + tmp +} +#[inline] +pub unsafe fn EtwGetTraitFromProviderTraits( + ProviderTraits: PVOID, TraitType: UCHAR, Trait: *mut PVOID, Size: PUSHORT, +) { + use core::ptr::null_mut; + let ByteCount = read_unaligned(ProviderTraits as *mut USHORT) as isize; + let mut Ptr = ProviderTraits as PUCHAR; + let PtrEnd = Ptr.offset(ByteCount); + *Trait = null_mut(); + *Size = 0; + if ByteCount < 3 { + return; + } + Ptr = Ptr.offset(2); + Ptr = Ptr.offset(strnlen(Ptr as PCSTR, (ByteCount - 3) as isize)); + Ptr = Ptr.offset(1); + while Ptr < PtrEnd { + let TraitByteCount = read_unaligned(Ptr as *const USHORT); + if TraitByteCount < 3 { + return; + } + if *Ptr.offset(2) == TraitType && Ptr.offset(TraitByteCount as isize) <= PtrEnd { + *Trait = Ptr.offset(3) as PVOID; + *Size = TraitByteCount - 3; + return; + } + Ptr = Ptr.offset(TraitByteCount as isize); + } +} +ENUM!{enum EVENTSECURITYOPERATION { + EventSecuritySetDACL, + EventSecuritySetSACL, + EventSecurityAddDACL, + EventSecurityAddSACL, + EventSecurityMax, +}} +extern "system" { + pub fn EventAccessControl( + Guid: LPGUID, + Operation: ULONG, + Sid: PSID, + Rights: ULONG, + AllowOrDeny: BOOLEAN, + ) -> ULONG; + pub fn EventAccessQuery( + Guid: LPGUID, + Buffer: PSECURITY_DESCRIPTOR, + BufferSize: PULONG, + ) -> ULONG; + pub fn EventAccessRemove( + Guid: LPGUID, + ) -> ULONG; +} diff --git a/winapi/src/um/exdisp.rs b/winapi/src/um/exdisp.rs new file mode 100644 index 000000000..3d44fd385 --- /dev/null +++ b/winapi/src/um/exdisp.rs @@ -0,0 +1,220 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of ExDisp.h +use shared::basetsd::SHANDLE_PTR; +use shared::wtypes::{BSTR, VARIANT_BOOL}; +use um::docobj::{OLECMDEXECOPT, OLECMDF, OLECMDID}; +use um::oaidl::{IDispatch, IDispatchVtbl, VARIANT}; +use um::ocidl::READYSTATE; +use um::winnt::{HRESULT, INT, LONG}; +DEFINE_GUID!{IID_IWebBrowser2, + 0xd30c1661, 0xcdaf, 0x11d0, 0x8a, 0x3e, 0x00, 0xc0, 0x4f, 0xc9, 0xe2, 0x6e} +RIDL!{#[uuid(0xeab22ac1, 0x30c1, 0x11cf, 0xa7, 0xeb, 0x00, 0x00, 0xc0, 0x5b, 0xae, 0x0b)] +interface IWebBrowser(IWebBrowserVtbl): IDispatch(IDispatchVtbl) { + fn GoBack() -> HRESULT, + fn GoForward() -> HRESULT, + fn GoHome() -> HRESULT, + fn GoSearch() -> HRESULT, + fn Navigate( + URL: BSTR, + Flags: *const VARIANT, + TargetFrameName: *const VARIANT, + PostData: *const VARIANT, + Headers: *const VARIANT, + ) -> HRESULT, + fn Refresh() -> HRESULT, + fn Refresh2( + Level: *const VARIANT, + ) -> HRESULT, + fn Stop() -> HRESULT, + fn get_Application( + ppDisp: *mut *mut IDispatch, + ) -> HRESULT, + fn get_Parent( + ppDisp: *mut *mut IDispatch, + ) -> HRESULT, + fn get_Container( + ppDisp: *mut *mut IDispatch, + ) -> HRESULT, + fn get_Document( + ppDisp: *mut *mut IDispatch, + ) -> HRESULT, + fn get_TopLevelContainer( + pBool: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_Type( + Type: *mut BSTR, + ) -> HRESULT, + fn get_Left( + pl: *mut LONG, + ) -> HRESULT, + fn put_Left( + Left: LONG, + ) -> HRESULT, + fn get_Top( + pl: *mut LONG, + ) -> HRESULT, + fn put_Top( + Top: LONG, + ) -> HRESULT, + fn get_Width( + pl: *mut LONG, + ) -> HRESULT, + fn put_Width( + Width: LONG, + ) -> HRESULT, + fn get_Height( + pl: *mut LONG, + ) -> HRESULT, + fn put_Height( + Height: LONG, + ) -> HRESULT, + fn get_LocationName( + LocationName: *mut BSTR, + ) -> HRESULT, + fn get_LocationURL( + LocationURL: *mut BSTR, + ) -> HRESULT, + fn get_Busy( + pBool: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0002df05, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IWebBrowserApp(IWebBrowserAppVtbl): IWebBrowser(IWebBrowserVtbl) { + fn Quit() -> HRESULT, + fn ClientToWindow( + pcx: *mut INT, + pcy: *mut INT, + ) -> HRESULT, + fn PutProperty( + Property: BSTR, + vtValue: VARIANT, + ) -> HRESULT, + fn GetProperty( + Property: BSTR, + pvtValue: *mut VARIANT, + ) -> HRESULT, + fn get_Name( + Name: *mut BSTR, + ) -> HRESULT, + fn get_HWND( + pHWND: *mut SHANDLE_PTR, + ) -> HRESULT, + fn get_FullName( + FullName: *mut BSTR, + ) -> HRESULT, + fn get_Path( + Path: *mut BSTR, + ) -> HRESULT, + fn get_Visible( + pBool: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Visible( + Value: VARIANT_BOOL, + ) -> HRESULT, + fn get_StatusBar( + pBool: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_StatusBar( + Value: VARIANT_BOOL, + ) -> HRESULT, + fn get_StatusText( + StatusText: *mut BSTR, + ) -> HRESULT, + fn put_StatusText( + StatusText: BSTR, + ) -> HRESULT, + fn get_ToolBar( + Value: *mut INT, + ) -> HRESULT, + fn put_ToolBar( + Value: INT, + ) -> HRESULT, + fn get_MenuBar( + Value: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_MenuBar( + Value: VARIANT_BOOL, + ) -> HRESULT, + fn get_FullScreen( + pbFullScreen: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_FullScreen( + bFullScreen: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd30c1661, 0xcdaf, 0x11d0, 0x8a, 0x3e, 0x00, 0xc0, 0x4f, 0xc9, 0xe2, 0x6e)] +interface IWebBrowser2(IWebBrowser2Vtbl): IWebBrowserApp(IWebBrowserAppVtbl) { + fn Navigate2( + URL: *const VARIANT, + Flags: *const VARIANT, + TargetFrameName: *const VARIANT, + PostData: *const VARIANT, + Headers: *const VARIANT, + ) -> HRESULT, + fn QueryStatusWB( + cmdID: OLECMDID, + pcmdf: *mut OLECMDF, + ) -> HRESULT, + fn ExecWB( + cmdID: OLECMDID, + cmdexecopt: OLECMDEXECOPT, + pvaIn: *const VARIANT, + pvaOut: *mut VARIANT, + ) -> HRESULT, + fn ShowBrowserBar( + pvaClsid: *const VARIANT, + pvarShow: *const VARIANT, + pvarSize: *const VARIANT, + ) -> HRESULT, + fn get_ReadyState( + plReadyState: *mut READYSTATE, + ) -> HRESULT, + fn get_Offline( + pbOffline: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Offline( + bOffline: VARIANT_BOOL, + ) -> HRESULT, + fn get_Silent( + pbSilent: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Silent( + bSilent: VARIANT_BOOL, + ) -> HRESULT, + fn get_RegisterAsBrowser( + pbRegister: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RegisterAsBrowser( + bRegister: VARIANT_BOOL, + ) -> HRESULT, + fn get_RegisterAsDropTarget( + pbRegister: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RegisterAsDropTarget( + bRegister: VARIANT_BOOL, + ) -> HRESULT, + fn get_TheaterMode( + pbRegister: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_TheaterMode( + bRegister: VARIANT_BOOL, + ) -> HRESULT, + fn get_AddressBar( + Value: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_AddressBar( + Value: VARIANT_BOOL, + ) -> HRESULT, + fn get_Resizable( + Value: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Resizable( + Value: VARIANT_BOOL, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_InternetExplorer, + 0x0002df01, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46} diff --git a/winapi/src/um/fibersapi.rs b/winapi/src/um/fibersapi.rs new file mode 100644 index 000000000..c2e3b08ff --- /dev/null +++ b/winapi/src/um/fibersapi.rs @@ -0,0 +1,23 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD}; +use um::winnt::{PFLS_CALLBACK_FUNCTION, PVOID}; +extern "system" { + pub fn FlsAlloc( + lpCallback: PFLS_CALLBACK_FUNCTION, + ) -> DWORD; + pub fn FlsGetValue( + dwFlsIndex: DWORD, + ) -> PVOID; + pub fn FlsSetValue( + dwFlsIndex: DWORD, + lpFlsData: PVOID, + ) -> BOOL; + pub fn FlsFree( + dwFlsIndex: DWORD, + ) -> BOOL; + pub fn IsThreadAFiber() -> BOOL; +} diff --git a/winapi/src/um/fileapi.rs b/winapi/src/um/fileapi.rs new file mode 100644 index 000000000..ed183a5fb --- /dev/null +++ b/winapi/src/um/fileapi.rs @@ -0,0 +1,639 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-file-l1 +use shared::minwindef::{ + BOOL, DWORD, FILETIME, LPCVOID, LPDWORD, LPFILETIME, LPVOID, PDWORD, PUCHAR, UCHAR, UINT, + ULONG, WORD, +}; +use um::minwinbase::{ + FILE_INFO_BY_HANDLE_CLASS, FINDEX_INFO_LEVELS, FINDEX_SEARCH_OPS, GET_FILEEX_INFO_LEVELS, + LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE, LPSECURITY_ATTRIBUTES, LPWIN32_FIND_DATAA, + LPWIN32_FIND_DATAW +}; +use um::winnt::{ + BOOLEAN, CCHAR, FILE_ID_128, FILE_SEGMENT_ELEMENT, HANDLE, LARGE_INTEGER, LONG, LONGLONG, + LPCSTR, LPCWSTR, LPSTR, LPWCH, LPWSTR, PLARGE_INTEGER, PLONG, PULARGE_INTEGER, PWSTR, + ULONGLONG, WCHAR, +}; +pub const CREATE_NEW: DWORD = 1; +pub const CREATE_ALWAYS: DWORD = 2; +pub const OPEN_EXISTING: DWORD = 3; +pub const OPEN_ALWAYS: DWORD = 4; +pub const TRUNCATE_EXISTING: DWORD = 5; +pub const INVALID_FILE_SIZE: DWORD = 0xFFFFFFFF; +pub const INVALID_SET_FILE_POINTER: DWORD = 0xFFFFFFFF; +pub const INVALID_FILE_ATTRIBUTES: DWORD = 0xFFFFFFFF; +STRUCT!{struct WIN32_FILE_ATTRIBUTE_DATA { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, +}} +pub type LPWIN32_FILE_ATTRIBUTE_DATA = *mut WIN32_FILE_ATTRIBUTE_DATA; +STRUCT!{struct BY_HANDLE_FILE_INFORMATION { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + dwVolumeSerialNumber: DWORD, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + nNumberOfLinks: DWORD, + nFileIndexHigh: DWORD, + nFileIndexLow: DWORD, +}} +pub type PBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; +pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; +STRUCT!{struct CREATEFILE2_EXTENDED_PARAMETERS { + dwSize: DWORD, + dwFileAttributes: DWORD, + dwFileFlags: DWORD, + dwSecurityQosFlags: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + hTemplateFile: HANDLE, +}} +pub type PCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS; +pub type LPCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS; +ENUM!{enum PRIORITY_HINT { + IoPriorityHintVeryLow = 0, + IoPriorityHintLow = 1, + IoPriorityHintNormal = 2, + MaximumIoPriorityHintType = 3, +}} +STRUCT!{struct FILE_BASIC_INFO { + CreationTime: LARGE_INTEGER, + LastAccessTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, + FileAttributes: DWORD, +}} +STRUCT!{struct FILE_STANDARD_INFO { + AllocationSize: LARGE_INTEGER, + EndOfFile: LARGE_INTEGER, + NumberOfLinks: DWORD, + DeletePending: BOOLEAN, + Directory: BOOLEAN, +}} +STRUCT!{struct FILE_NAME_INFO { + FileNameLength: DWORD, + FileName: [WCHAR; 1], +}} +STRUCT!{struct FILE_RENAME_INFO { + ReplaceIfExists: BOOL, + RootDirectory: HANDLE, + FileNameLength: DWORD, + FileName: [WCHAR; 1], +}} +STRUCT!{struct FILE_DISPOSITION_INFO { + DeleteFile: BOOLEAN, +}} +STRUCT!{struct FILE_ALLOCATION_INFO { + AllocationSize: LARGE_INTEGER, +}} +STRUCT!{struct FILE_END_OF_FILE_INFO { + EndOfFile: LARGE_INTEGER, +}} +STRUCT!{struct FILE_STREAM_INFO { + NextEntryOffset: DWORD, + StreamNameLength: DWORD, + StreamSize: LARGE_INTEGER, + StreamAllocationSize: LARGE_INTEGER, + StreamName: [WCHAR; 1], +}} +STRUCT!{struct FILE_COMPRESSION_INFO { + CompressedFileSize: LARGE_INTEGER, + CompressionFormat: WORD, + CompressionUnitShift: UCHAR, + ChunkShift: UCHAR, + ClusterShift: UCHAR, + Reserved: [UCHAR; 3], +}} +STRUCT!{struct FILE_ATTRIBUTE_TAG_INFO { + NextEntryOffset: DWORD, + ReparseTag: DWORD, +}} +STRUCT!{struct FILE_ID_BOTH_DIR_INFO { + NextEntryOffset: DWORD, + FileIndex: DWORD, + CreationTime: LARGE_INTEGER, + LastAccessTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, + EndOfFile: LARGE_INTEGER, + AllocationSize: LARGE_INTEGER, + FileAttributes: DWORD, + FileNameLength: DWORD, + EaSize: DWORD, + ShortNameLength: CCHAR, + ShortName: [WCHAR; 12], + FileId: LARGE_INTEGER, + FileName: [WCHAR; 1], +}} +STRUCT!{struct FILE_IO_PRIORITY_HINT_INFO { + PriorityHint: PRIORITY_HINT, +}} +STRUCT!{struct FILE_FULL_DIR_INFO { + NextEntryOffset: ULONG, + FileIndex: ULONG, + CreationTime: LARGE_INTEGER, + LastAccessTime: LARGE_INTEGER, + LastWriteTime: LARGE_INTEGER, + ChangeTime: LARGE_INTEGER, + EndOfFile: LARGE_INTEGER, + AllocationSize: LARGE_INTEGER, + FileAttributes: ULONG, + FileNameLength: ULONG, + EaSize: ULONG, + FileName: [WCHAR; 1], +}} +STRUCT!{struct FILE_STORAGE_INFO { + LogicalBytesPerSector: ULONG, + PhysicalBytesPerSectorForAtomicity: ULONG, + PhysicalBytesPerSectorForPerformance: ULONG, + FileSystemEffectivePhysicalBytesPerSectorForAtomicity: ULONG, + Flags: ULONG, + ByteOffsetForSectorAlignment: ULONG, + ByteOffsetForPartitionAlignment: ULONG, +}} +STRUCT!{struct FILE_ALIGNMENT_INFO { + AlignmentRequirement: ULONG, +}} +STRUCT!{struct FILE_ID_INFO { + VolumeSerialNumber: ULONGLONG, + FileId: FILE_ID_128, +}} +extern "system" { + pub fn CompareFileTime( + lpFileTime1: *const FILETIME, + lpFileTime2: *const FILETIME, + ) -> LONG; + pub fn CreateDirectoryA( + lpPathName: LPCSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateDirectoryW( + lpPathName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateFileA( + lpFileName: LPCSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + ) -> HANDLE; + pub fn CreateFileW( + lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + ) -> HANDLE; + pub fn DefineDosDeviceW( + dwFlags: DWORD, + lpDeviceName: LPCWSTR, + lpTargetPath: LPCWSTR, + ) -> BOOL; + pub fn DeleteFileA( + lpFileName: LPCSTR, + ) -> BOOL; + pub fn DeleteFileW( + lpFileName: LPCWSTR, + ) -> BOOL; + pub fn DeleteVolumeMountPointW( + lpszVolumeMountPoint: LPCWSTR, + ) -> BOOL; + pub fn FileTimeToLocalFileTime( + lpFileTime: *const FILETIME, + lpLocalFileTime: LPFILETIME, + ) -> BOOL; + pub fn FindClose( + hFindFile: HANDLE, + ) -> BOOL; + pub fn FindCloseChangeNotification( + hChangeHandle: HANDLE, + ) -> BOOL; + pub fn FindFirstChangeNotificationA( + lpPathName: LPCSTR, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + ) -> HANDLE; + pub fn FindFirstChangeNotificationW( + lpPathName: LPCWSTR, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + ) -> HANDLE; + pub fn FindFirstFileA( + lpFileName: LPCSTR, + lpFindFileData: LPWIN32_FIND_DATAA, + ) -> HANDLE; + pub fn FindFirstFileW( + lpFileName: LPCWSTR, + lpFindFileData: LPWIN32_FIND_DATAW, + ) -> HANDLE; + pub fn FindFirstFileExA( + lpFileName: LPCSTR, + fInfoLevelId: FINDEX_INFO_LEVELS, + lpFindFileData: LPVOID, + fSearchOp: FINDEX_SEARCH_OPS, + lpSearchFilter: LPVOID, + dwAdditionalFlags: DWORD, + ) -> HANDLE; + pub fn FindFirstFileExW( + lpFileName: LPCWSTR, + fInfoLevelId: FINDEX_INFO_LEVELS, + lpFindFileData: LPVOID, + fSearchOp: FINDEX_SEARCH_OPS, + lpSearchFilter: LPVOID, + dwAdditionalFlags: DWORD, + ) -> HANDLE; + pub fn FindFirstVolumeW( + lpszVolumeName: LPWSTR, + cchBufferLength: DWORD, + ) -> HANDLE; + pub fn FindNextChangeNotification( + hChangeHandle: HANDLE, + ) -> BOOL; + pub fn FindNextFileA( + hFindFile: HANDLE, + lpFindFileData: LPWIN32_FIND_DATAA, + ) -> BOOL; + pub fn FindNextFileW( + hFindFile: HANDLE, + lpFindFileData: LPWIN32_FIND_DATAW, + ) -> BOOL; + pub fn FindNextVolumeW( + hFindVolume: HANDLE, + lpszVolumeName: LPWSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn FindVolumeClose( + hFindVolume: HANDLE, + ) -> BOOL; + pub fn FlushFileBuffers( + hFile: HANDLE, + ) -> BOOL; + pub fn GetDiskFreeSpaceA( + lpRootPathName: LPCSTR, + lpSectorsPerCluster: LPDWORD, + lpBytesPerSector: LPDWORD, + lpNumberOfFreeClusters: LPDWORD, + lpTotalNumberOfClusters: LPDWORD, + ) -> BOOL; + pub fn GetDiskFreeSpaceW( + lpRootPathName: LPCWSTR, + lpSectorsPerCluster: LPDWORD, + lpBytesPerSector: LPDWORD, + lpNumberOfFreeClusters: LPDWORD, + lpTotalNumberOfClusters: LPDWORD, + ) -> BOOL; + pub fn GetDiskFreeSpaceExA( + lpDirectoryName: LPCSTR, + lpFreeBytesAvailableToCaller: PULARGE_INTEGER, + lpTotalNumberOfBytes: PULARGE_INTEGER, + lpTotalNumberOfFreeBytes: PULARGE_INTEGER, + ) -> BOOL; + pub fn GetDiskFreeSpaceExW( + lpDirectoryName: LPCWSTR, + lpFreeBytesAvailableToCaller: PULARGE_INTEGER, + lpTotalNumberOfBytes: PULARGE_INTEGER, + lpTotalNumberOfFreeBytes: PULARGE_INTEGER, + ) -> BOOL; + pub fn GetDriveTypeA( + lpRootPathName: LPCSTR, + ) -> UINT; + pub fn GetDriveTypeW( + lpRootPathName: LPCWSTR, + ) -> UINT; + pub fn GetFileAttributesA( + lpFileName: LPCSTR, + ) -> DWORD; + pub fn GetFileAttributesW( + lpFileName: LPCWSTR, + ) -> DWORD; + pub fn GetFileAttributesExA( + lpFileName: LPCSTR, + fInfoLevelId: GET_FILEEX_INFO_LEVELS, + lpFileInformation: LPVOID, + ) -> BOOL; + pub fn GetFileAttributesExW( + lpFileName: LPCWSTR, + fInfoLevelId: GET_FILEEX_INFO_LEVELS, + lpFileInformation: LPVOID, + ) -> BOOL; + pub fn GetFileInformationByHandle( + hFile: HANDLE, + lpFileInformation: LPBY_HANDLE_FILE_INFORMATION, + ) -> BOOL; + pub fn GetFileSize( + hFile: HANDLE, + lpFileSizeHigh: LPDWORD, + ) -> DWORD; + pub fn GetFileSizeEx( + hFile: HANDLE, + lpFileSize: PLARGE_INTEGER, + ) -> BOOL; + pub fn GetFileType( + hFile: HANDLE, + ) -> DWORD; + pub fn GetFinalPathNameByHandleA( + hFile: HANDLE, + lpszFilePath: LPSTR, + cchFilePath: DWORD, + dwFlags: DWORD, + ) -> DWORD; + pub fn GetFinalPathNameByHandleW( + hFile: HANDLE, + lpszFilePath: LPWSTR, + cchFilePath: DWORD, + dwFlags: DWORD, + ) -> DWORD; + pub fn GetFileTime( + hFile: HANDLE, + lpCreationTime: LPFILETIME, + lpLastAccessTime: LPFILETIME, + lpLastWriteTime: LPFILETIME, + ) -> BOOL; + pub fn GetFullPathNameW( + lpFileName: LPCWSTR, + nBufferLength: DWORD, + lpBuffer: LPWSTR, + lpFilePart: *mut LPWSTR, + ) -> DWORD; + pub fn GetFullPathNameA( + lpFileName: LPCSTR, + nBufferLength: DWORD, + lpBuffer: LPSTR, + lpFilePart: *mut LPSTR, + ) -> DWORD; + pub fn GetLogicalDrives() -> DWORD; + pub fn GetLogicalDriveStringsW( + nBufferLength: DWORD, + lpBuffer: LPWSTR, + ) -> DWORD; + pub fn GetLongPathNameA( + lpszShortPath: LPCSTR, + lpszLongPath: LPSTR, + cchBuffer: DWORD, + ) -> DWORD; + pub fn GetLongPathNameW( + lpszShortPath: LPCWSTR, + lpszLongPath: LPWSTR, + cchBuffer: DWORD, + ) -> DWORD; + pub fn GetShortPathNameW( + lpszLongPath: LPCWSTR, + lpszShortPath: LPWSTR, + cchBuffer: DWORD, + ) -> DWORD; + pub fn GetTempFileNameW( + lpPathName: LPCWSTR, + lpPrefixString: LPCWSTR, + uUnique: UINT, + lpTempFileName: LPWSTR, + ) -> UINT; + pub fn GetVolumeInformationByHandleW( + hFile: HANDLE, + lpVolumeNameBuffer: LPWSTR, + nVolumeNameSize: DWORD, + lpVolumeSerialNumber: LPDWORD, + lpMaximumComponentLength: LPDWORD, + lpFileSystemFlags: LPDWORD, + lpFileSystemNameBuffer: LPWSTR, + nFileSystemNameSize: DWORD, + ) -> BOOL; + pub fn GetVolumeInformationW( + lpRootPathName: LPCWSTR, + lpVolumeNameBuffer: LPWSTR, + nVolumeNameSize: DWORD, + lpVolumeSerialNumber: LPDWORD, + lpMaximumComponentLength: LPDWORD, + lpFileSystemFlags: LPDWORD, + lpFileSystemNameBuffer: LPWSTR, + nFileSystemNameSize: DWORD, + ) -> BOOL; + pub fn GetVolumePathNameW( + lpszFileName: LPCWSTR, + lpszVolumePathName: LPWSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn LocalFileTimeToFileTime( + lpLocalFileTime: *const FILETIME, + lpFileTime: LPFILETIME, + ) -> BOOL; + pub fn LockFile( + hFile: HANDLE, + dwFileOffsetLow: DWORD, + dwFileOffsetHigh: DWORD, + nNumberOfBytesToLockLow: DWORD, + nNumberOfBytesToLockHigh: DWORD, + ) -> BOOL; + pub fn LockFileEx( + hFile: HANDLE, + dwFlags: DWORD, + dwReserved: DWORD, + nNumberOfBytesToLockLow: DWORD, + nNumberOfBytesToLockHigh: DWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn QueryDosDeviceW( + lpDeviceName: LPCWSTR, + lpTargetPath: LPWSTR, + ucchMax: DWORD, + ) -> DWORD; + pub fn ReadFile( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToRead: DWORD, + lpNumberOfBytesRead: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn ReadFileEx( + hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToRead: DWORD, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, + ) -> BOOL; + pub fn ReadFileScatter( + hFile: HANDLE, + aSegmentArray: *mut FILE_SEGMENT_ELEMENT, + nNumberOfBytesToRead: DWORD, + lpReserved: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn RemoveDirectoryA( + lpPathName: LPCSTR, + ) -> BOOL; + pub fn RemoveDirectoryW( + lpPathName: LPCWSTR, + ) -> BOOL; + pub fn SetEndOfFile( + hFile: HANDLE, + ) -> BOOL; + pub fn SetFileAttributesA( + lpFileName: LPCSTR, + dwFileAttributes: DWORD, + ) -> BOOL; + pub fn SetFileAttributesW( + lpFileName: LPCWSTR, + dwFileAttributes: DWORD, + ) -> BOOL; + pub fn SetFileInformationByHandle( + hFile: HANDLE, + FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; + pub fn SetFilePointer( + hFile: HANDLE, + lDistanceToMove: LONG, + lpDistanceToMoveHigh: PLONG, + dwMoveMethod: DWORD, + ) -> DWORD; + pub fn SetFilePointerEx( + hFile: HANDLE, + liDistanceToMove: LARGE_INTEGER, + lpNewFilePointer: PLARGE_INTEGER, + dwMoveMethod: DWORD, + ) -> BOOL; + pub fn SetFileTime( + hFile: HANDLE, + lpCreationTime: *const FILETIME, + lpLastAccessTime: *const FILETIME, + lpLastWriteTime: *const FILETIME, + ) -> BOOL; + pub fn SetFileValidData( + hFile: HANDLE, + ValidDataLength: LONGLONG, + ) -> BOOL; + pub fn UnlockFile( + hFile: HANDLE, + dwFileOffsetLow: DWORD, + dwFileOffsetHigh: DWORD, + nNumberOfBytesToUnlockLow: DWORD, + nNumberOfBytesToUnlockHigh: DWORD, + ) -> BOOL; + pub fn UnlockFileEx( + hFile: HANDLE, + dwReserved: DWORD, + nNumberOfBytesToUnlockLow: DWORD, + nNumberOfBytesToUnlockHigh: DWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WriteFile( + hFile: HANDLE, + lpBuffer: LPCVOID, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WriteFileEx( + hFile: HANDLE, + lpBuffer: LPCVOID, + nNumberOfBytesToWrite: DWORD, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, + ) -> BOOL; + pub fn WriteFileGather( + hFile: HANDLE, + aSegmentArray: *mut FILE_SEGMENT_ELEMENT, + nNumberOfBytesToWrite: DWORD, + lpReserved: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn GetTempPathW( + nBufferLength: DWORD, + lpBuffer: LPWSTR, + ) -> DWORD; + pub fn GetVolumeNameForVolumeMountPointW( + lpszVolumeMountPoint: LPCWSTR, + lpszVolumeName: LPWSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn GetVolumePathNamesForVolumeNameW( + lpszVolumeName: LPCWSTR, + lpszVolumePathNames: LPWCH, + cchBufferLength: DWORD, + lpcchReturnLength: PDWORD, + ) -> BOOL; + pub fn CreateFile2( + lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + dwCreationDisposition: DWORD, + pCreateExParams: LPCREATEFILE2_EXTENDED_PARAMETERS, + ) -> HANDLE; + pub fn SetFileIoOverlappedRange( + FileHandle: HANDLE, + OverlappedRangeStart: PUCHAR, + Length: ULONG, + ) -> BOOL; + pub fn GetCompressedFileSizeA( + lpFileName: LPCSTR, + lpFileSizeHigh: LPDWORD, + ) -> DWORD; + pub fn GetCompressedFileSizeW( + lpFileName: LPCWSTR, + lpFileSizeHigh: LPDWORD, + ) -> DWORD; +} +ENUM!{enum STREAM_INFO_LEVELS { + FindStreamInfoStandard, + FindStreamInfoMaxInfoLevel, +}} +extern "system" { + pub fn FindFirstStreamW( + lpFileName: LPCWSTR, + InfoLevel: STREAM_INFO_LEVELS, + lpFindStreamData: LPVOID, + dwFlags: DWORD, + ) -> HANDLE; + pub fn FindNextStreamW( + hFindStream: HANDLE, + lpFindStreamData: LPVOID, + ) -> BOOL; + pub fn AreFileApisANSI() -> BOOL; + pub fn GetTempPathA( + nBufferLength: DWORD, + lpBuffer: LPSTR, + ) -> DWORD; + pub fn FindFirstFileNameW( + lpFileName: LPCWSTR, + dwFlags: DWORD, + StringLength: LPDWORD, + LinkName: PWSTR, + ) -> HANDLE; + pub fn FindNextFileNameW( + hFindStream: HANDLE, + StringLength: LPDWORD, + LinkName: PWSTR, + ) -> BOOL; + pub fn GetVolumeInformationA( + lpRootPathName: LPCSTR, + lpVolumeNameBuffer: LPSTR, + nVolumeNameSize: DWORD, + lpVolumeSerialNumber: LPDWORD, + lpMaximumComponentLength: LPDWORD, + lpFileSystemFlags: LPDWORD, + lpFileSystemNameBuffer: LPSTR, + nFileSystemNameSize: DWORD, + ) -> BOOL; + pub fn GetTempFileNameA( + lpPathName: LPCSTR, + lpPrefixString: LPCSTR, + uUnique: UINT, + lpTempFileName: LPSTR, + ) -> UINT; + pub fn SetFileApisToOEM(); + pub fn SetFileApisToANSI(); +} diff --git a/winapi/src/um/gl/gl.rs b/winapi/src/um/gl/gl.rs new file mode 100644 index 000000000..d7c1b586e --- /dev/null +++ b/winapi/src/um/gl/gl.rs @@ -0,0 +1,52 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_double, c_float, c_int, c_schar, c_short, c_uchar, c_uint, c_ushort, c_void}; +//48 +pub type GLenum = c_uint; +pub type GLboolean = c_uchar; +pub type GLbitfield = c_uint; +pub type GLbyte = c_schar; +pub type GLshort = c_short; +pub type GLint = c_int; +pub type GLsizei = c_int; +pub type GLubyte = c_uchar; +pub type GLushort = c_ushort; +pub type GLuint = c_uint; +pub type GLfloat = c_float; +pub type GLclampf = c_float; +pub type GLdouble = c_double; +pub type GLclampd = c_double; +pub type GLvoid = c_void; +//63 +//68 +//AccumOp +pub const GL_ACCUM: GLenum = 0x0100; +pub const GL_LOAD: GLenum = 0x0101; +pub const GL_RETURN: GLenum = 0x0102; +pub const GL_MULT: GLenum = 0x0103; +pub const GL_ADD: GLenum = 0x0104; +//AlphaFunction +pub const GL_NEVER: GLenum = 0x0200; +pub const GL_LESS: GLenum = 0x0201; +pub const GL_EQUAL: GLenum = 0x0202; +pub const GL_LEQUAL: GLenum = 0x0203; +pub const GL_GREATER: GLenum = 0x0204; +pub const GL_NOTEQUAL: GLenum = 0x0205; +pub const GL_GEQUAL: GLenum = 0x0206; +pub const GL_ALWAYS: GLenum = 0x0207; +// TODO: we're missing about 1500 lines of defines and methods +// until that time, you can use the excellent GL crate +// https://github.com/brendanzab/gl-rs +extern "system" { + pub fn glAccum( + op: GLenum, + value: GLfloat, + ); + pub fn glAlphaFunc( + func: GLenum, + reference: GLclampf, + ); +} diff --git a/winapi/src/um/gl/mod.rs b/winapi/src/um/gl/mod.rs new file mode 100644 index 000000000..6ce6d067f --- /dev/null +++ b/winapi/src/um/gl/mod.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Headers for user mode only +#[cfg(feature = "gl-gl")] pub mod gl; diff --git a/winapi/src/um/handleapi.rs b/winapi/src/um/handleapi.rs new file mode 100644 index 000000000..1d7e43d77 --- /dev/null +++ b/winapi/src/um/handleapi.rs @@ -0,0 +1,36 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! handleapi include file +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPHANDLE}; +use um::winnt::HANDLE; +pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE; +extern "system" { + pub fn CloseHandle( + hObject: HANDLE, + ) -> BOOL; + pub fn DuplicateHandle( + hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD, + ) -> BOOL; + pub fn CompareObjectHandles( + hFirstObjectHandle: HANDLE, + hSecondObjectHandle: HANDLE, + ) -> BOOL; + pub fn GetHandleInformation( + hObject: HANDLE, + lpdwFlags: LPDWORD, + ) -> BOOL; + pub fn SetHandleInformation( + hObject: HANDLE, + dwMask: DWORD, + dwFlags: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/heapapi.rs b/winapi/src/um/heapapi.rs new file mode 100644 index 000000000..83073b31e --- /dev/null +++ b/winapi/src/um/heapapi.rs @@ -0,0 +1,92 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-heap-l1 +use shared::basetsd::{PSIZE_T, SIZE_T}; +use shared::minwindef::{BOOL, DWORD, LPCVOID, LPVOID}; +use um::minwinbase::LPPROCESS_HEAP_ENTRY; +use um::winnt::{HANDLE, HEAP_INFORMATION_CLASS, PHANDLE, PVOID}; +STRUCT!{struct HEAP_SUMMARY { + cb: DWORD, + cbAllocated: SIZE_T, + cbCommitted: SIZE_T, + cbReserved: SIZE_T, + cbMaxReserve: SIZE_T, +}} +pub type PHEAP_SUMMARY = *mut HEAP_SUMMARY; +pub type LPHEAP_SUMMARY = PHEAP_SUMMARY; +extern "system" { + pub fn HeapCreate( + flOptions: DWORD, + dwInitialSize: SIZE_T, + dwMaximumSize: SIZE_T, + ) -> HANDLE; + pub fn HeapDestroy( + hHeap: HANDLE, + ) -> BOOL; + pub fn HeapAlloc( + hHeap: HANDLE, + dwFlags: DWORD, + dwBytes: SIZE_T, + ) -> LPVOID; + pub fn HeapReAlloc( + hHeap: HANDLE, + dwFlags: DWORD, + lpMem: LPVOID, + dwBytes: SIZE_T, + ) -> LPVOID; + pub fn HeapFree( + hHeap: HANDLE, + dwFlags: DWORD, + lpMem: LPVOID, + ) -> BOOL; + pub fn HeapSize( + hHeap: HANDLE, + dwFlags: DWORD, + lpMem: LPCVOID, + ) -> SIZE_T; + pub fn GetProcessHeap() -> HANDLE; + pub fn HeapCompact( + hHeap: HANDLE, + dwFlags: DWORD, + ) -> SIZE_T; + pub fn HeapSetInformation( + HeapHandle: HANDLE, + HeapInformationClass: HEAP_INFORMATION_CLASS, + HeapInformation: PVOID, + HeapInformationLength: SIZE_T, + ) -> BOOL; + pub fn HeapValidate( + hHeap: HANDLE, + dwFlags: DWORD, + lpMem: LPCVOID, + ) -> BOOL; + pub fn HeapSummary( + hHeap: HANDLE, + dwFlags: DWORD, + lpSummary: LPHEAP_SUMMARY, + ) -> BOOL; + pub fn GetProcessHeaps( + NumberOfHeaps: DWORD, + ProcessHeaps: PHANDLE, + ) -> DWORD; + pub fn HeapLock( + hHeap: HANDLE, + ) -> BOOL; + pub fn HeapUnlock( + hHeap: HANDLE, + ) -> BOOL; + pub fn HeapWalk( + hHeap: HANDLE, + lpEntry: LPPROCESS_HEAP_ENTRY, + ) -> BOOL; + pub fn HeapQueryInformation( + HeapHandle: HANDLE, + HeapInformationClass: HEAP_INFORMATION_CLASS, + HeapInformation: PVOID, + HeapInformationLength: SIZE_T, + ReturnLength: PSIZE_T, + ) -> BOOL; +} diff --git a/winapi/src/um/highlevelmonitorconfigurationapi.rs b/winapi/src/um/highlevelmonitorconfigurationapi.rs new file mode 100644 index 000000000..f187aeb26 --- /dev/null +++ b/winapi/src/um/highlevelmonitorconfigurationapi.rs @@ -0,0 +1,171 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, LPDWORD}; +use um::physicalmonitorenumerationapi::_BOOL; +use um::winnt::HANDLE; +pub const MC_CAPS_NONE: DWORD = 0x00000000; +pub const MC_CAPS_MONITOR_TECHNOLOGY_TYPE: DWORD = 0x00000001; +pub const MC_CAPS_BRIGHTNESS: DWORD = 0x00000002; +pub const MC_CAPS_CONTRAST: DWORD = 0x00000004; +pub const MC_CAPS_COLOR_TEMPERATURE: DWORD = 0x00000008; +pub const MC_CAPS_RED_GREEN_BLUE_GAIN: DWORD = 0x00000010; +pub const MC_CAPS_RED_GREEN_BLUE_DRIVE: DWORD = 0x00000020; +pub const MC_CAPS_DEGAUSS: DWORD = 0x00000040; +pub const MC_CAPS_DISPLAY_AREA_POSITION: DWORD = 0x00000080; +pub const MC_CAPS_DISPLAY_AREA_SIZE: DWORD = 0x00000100; +pub const MC_CAPS_RESTORE_FACTORY_DEFAULTS: DWORD = 0x00000400; +pub const MC_CAPS_RESTORE_FACTORY_COLOR_DEFAULTS: DWORD = 0x00000800; +pub const MC_RESTORE_FACTORY_DEFAULTS_ENABLES_MONITOR_SETTINGS: DWORD = 0x00001000; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_NONE: DWORD = 0x00000000; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_4000K: DWORD = 0x00000001; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_5000K: DWORD = 0x00000002; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_6500K: DWORD = 0x00000004; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_7500K: DWORD = 0x00000008; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_8200K: DWORD = 0x00000010; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_9300K: DWORD = 0x00000020; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_10000K: DWORD = 0x00000040; +pub const MC_SUPPORTED_COLOR_TEMPERATURE_11500K: DWORD = 0x00000080; +ENUM!{enum MC_DISPLAY_TECHNOLOGY_TYPE { + MC_SHADOW_MASK_CATHODE_RAY_TUBE, + MC_APERTURE_GRILL_CATHODE_RAY_TUBE, + MC_THIN_FILM_TRANSISTOR, + MC_LIQUID_CRYSTAL_ON_SILICON, + MC_PLASMA, + MC_ORGANIC_LIGHT_EMITTING_DIODE, + MC_ELECTROLUMINESCENT, + MC_MICROELECTROMECHANICAL, + MC_FIELD_EMISSION_DEVICE, +}} +pub type LPMC_DISPLAY_TECHNOLOGY_TYPE = *mut MC_DISPLAY_TECHNOLOGY_TYPE; +ENUM!{enum MC_DRIVE_TYPE { + MC_RED_DRIVE, + MC_GREEN_DRIVE, + MC_BLUE_DRIVE, +}} +ENUM!{enum MC_GAIN_TYPE { + MC_RED_GAIN, + MC_GREEN_GAIN, + MC_BLUE_GAIN, +}} +ENUM!{enum MC_POSITION_TYPE { + MC_HORIZONTAL_POSITION, + MC_VERTICAL_POSITION, +}} +ENUM!{enum MC_SIZE_TYPE { + MC_WIDTH, + MC_HEIGHT, +}} +ENUM!{enum MC_COLOR_TEMPERATURE { + MC_COLOR_TEMPERATURE_UNKNOWN, + MC_COLOR_TEMPERATURE_4000K, + MC_COLOR_TEMPERATURE_5000K, + MC_COLOR_TEMPERATURE_6500K, + MC_COLOR_TEMPERATURE_7500K, + MC_COLOR_TEMPERATURE_8200K, + MC_COLOR_TEMPERATURE_9300K, + MC_COLOR_TEMPERATURE_10000K, + MC_COLOR_TEMPERATURE_11500K, +}} +pub type LPMC_COLOR_TEMPERATURE = *mut MC_COLOR_TEMPERATURE; +extern "system" { + pub fn GetMonitorCapabilities( + hMonitor: HANDLE, + pdwMonitorCapabilities: LPDWORD, + pdwSupportedColorTemperature: LPDWORD, + ) -> _BOOL; + pub fn SaveCurrentMonitorSettings( + hMonitor: HANDLE, + ) -> _BOOL; + pub fn GetMonitorTechnologyType( + hMonitor: HANDLE, + pdtyDisplayTechnologyType: LPMC_DISPLAY_TECHNOLOGY_TYPE, + ) -> _BOOL; + pub fn GetMonitorBrightness( + hMonitor: HANDLE, + pdwMinimumBrightness: LPDWORD, + pdwCurrentBrightness: LPDWORD, + pdwMaximumBrightness: LPDWORD, + ) -> _BOOL; + pub fn GetMonitorContrast( + hMonitor: HANDLE, + pdwMinimumContrast: LPDWORD, + pdwCurrentContrast: LPDWORD, + pdwMaximumContrast: LPDWORD, + ) -> _BOOL; + pub fn GetMonitorColorTemperature( + hMonitor: HANDLE, + pctCurrentColorTemperature: LPMC_COLOR_TEMPERATURE, + ) -> _BOOL; + pub fn GetMonitorRedGreenOrBlueDrive( + hMonitor: HANDLE, + dtDriveType: MC_DRIVE_TYPE, + pdwMinimumDrive: LPDWORD, + pdwCurrentDrive: LPDWORD, + pdwMaximumDrive: LPDWORD, + ) -> _BOOL; + pub fn GetMonitorRedGreenOrBlueGain( + hMonitor: HANDLE, + gtGainType: MC_GAIN_TYPE, + pdwMinimumGain: LPDWORD, + pdwCurrentGain: LPDWORD, + pdwMaximumGain: LPDWORD, + ) -> _BOOL; + pub fn SetMonitorBrightness( + hMonitor: HANDLE, + dwNewBrightness: DWORD, + ) -> _BOOL; + pub fn SetMonitorContrast( + hMonitor: HANDLE, + dwNewContrast: DWORD, + ) -> _BOOL; + pub fn SetMonitorColorTemperature( + hMonitor: HANDLE, + ctCurrentColorTemperature: MC_COLOR_TEMPERATURE, + ) -> _BOOL; + pub fn SetMonitorRedGreenOrBlueDrive( + hMonitor: HANDLE, + dtDriveType: MC_DRIVE_TYPE, + dwNewDrive: DWORD, + ) -> _BOOL; + pub fn SetMonitorRedGreenOrBlueGain( + hMonitor: HANDLE, + gtGainType: MC_GAIN_TYPE, + dwNewGain: DWORD, + ) -> _BOOL; + pub fn DegaussMonitor( + hMonitor: HANDLE, + ) -> _BOOL; + pub fn GetMonitorDisplayAreaSize( + hMonitor: HANDLE, + stSizeType: MC_SIZE_TYPE, + pdwMinimumWidthOrHeight: LPDWORD, + pdwCurrentWidthOrHeight: LPDWORD, + pdwMaximumWidthOrHeight: LPDWORD, + ) -> _BOOL; + pub fn GetMonitorDisplayAreaPosition( + hMonitor: HANDLE, + ptPositionType: MC_POSITION_TYPE, + pdwMinimumPosition: LPDWORD, + pdwCurrentPosition: LPDWORD, + pdwMaximumPosition: LPDWORD, + ) -> _BOOL; + pub fn SetMonitorDisplayAreaSize( + hMonitor: HANDLE, + stSizeType: MC_SIZE_TYPE, + dwNewDisplayAreaWidthOrHeight: DWORD, + ) -> _BOOL; + pub fn SetMonitorDisplayAreaPosition( + hMonitor: HANDLE, + ptPositionType: MC_POSITION_TYPE, + dwNewPosition: DWORD, + ) -> _BOOL; + pub fn RestoreMonitorFactoryColorDefaults( + hMonitor: HANDLE, + ) -> _BOOL; + pub fn RestoreMonitorFactoryDefaults( + hMonitor: HANDLE, + ) -> _BOOL; +} diff --git a/winapi/src/um/http.rs b/winapi/src/um/http.rs new file mode 100644 index 000000000..38608d1df --- /dev/null +++ b/winapi/src/um/http.rs @@ -0,0 +1,1072 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! HTTP API specification +use shared::guiddef::GUID; +use shared::minwindef::{DWORD, PUCHAR, PULONG, UCHAR, ULONG, USHORT}; +use shared::sspi::SECURITY_STATUS; +use shared::ws2def::{PSOCKADDR, SOCKADDR_STORAGE}; +use um::minwinbase::{LPOVERLAPPED, PSECURITY_ATTRIBUTES}; +use um::winnt::{ + ANYSIZE_ARRAY, BOOLEAN, HANDLE, PCHAR, PCSTR, PCWSTR, PHANDLE, PSECURITY_DESCRIPTOR, PVOID, + PWCHAR, PWSTR, ULARGE_INTEGER, ULONGLONG, +}; +pub const HTTP_INITIALIZE_SERVER: ULONG = 0x00000001; +pub const HTTP_INITIALIZE_CONFIG: ULONG = 0x00000002; +pub const HTTP_DEMAND_CBT: ULONG = 0x00000004; +ENUM!{enum HTTP_SERVER_PROPERTY { + HttpServerAuthenticationProperty, + HttpServerLoggingProperty, + HttpServerQosProperty, + HttpServerTimeoutsProperty, + HttpServerQueueLengthProperty, + HttpServerStateProperty, + HttpServer503VerbosityProperty, + HttpServerBindingProperty, + HttpServerExtendedAuthenticationProperty, + HttpServerListenEndpointProperty, + HttpServerChannelBindProperty, + HttpServerProtectionLevelProperty, +}} +pub type PHTTP_SERVER_PROPERTY = *mut HTTP_SERVER_PROPERTY; +STRUCT!{struct HTTP_PROPERTY_FLAGS { + BitFields: ULONG, +}} +BITFIELD!{HTTP_PROPERTY_FLAGS BitFields: ULONG [ + Present set_Present[0..1], +]} +pub type PHTTP_PROPERTY_FLAGS = *mut HTTP_PROPERTY_FLAGS; +ENUM!{enum HTTP_ENABLED_STATE { + HttpEnabledStateActive, + HttpEnabledStateInactive, +}} +pub type PHTTP_ENABLED_STATE = *mut HTTP_ENABLED_STATE; +STRUCT!{struct HTTP_STATE_INFO { + Flags: HTTP_PROPERTY_FLAGS, + State: HTTP_ENABLED_STATE, +}} +pub type PHTTP_STATE_INFO = *mut HTTP_STATE_INFO; +ENUM!{enum HTTP_503_RESPONSE_VERBOSITY { + Http503ResponseVerbosityBasic, + Http503ResponseVerbosityLimited, + Http503ResponseVerbosityFull, +}} +pub type PHTTP_503_RESPONSE_VERBOSITY = *mut HTTP_503_RESPONSE_VERBOSITY; +ENUM!{enum HTTP_QOS_SETTING_TYPE { + HttpQosSettingTypeBandwidth, + HttpQosSettingTypeConnectionLimit, + HttpQosSettingTypeFlowRate, +}} +pub type PHTTP_QOS_SETTING_TYPE = *mut HTTP_QOS_SETTING_TYPE; +STRUCT!{struct HTTP_QOS_SETTING_INFO { + QosType: HTTP_QOS_SETTING_TYPE, + QosSetting: PVOID, +}} +pub type PHTTP_QOS_SETTING_INFO = *mut HTTP_QOS_SETTING_INFO; +STRUCT!{struct HTTP_CONNECTION_LIMIT_INFO { + Flags: HTTP_PROPERTY_FLAGS, + MaxConnections: ULONG, +}} +pub type PHTTP_CONNECTION_LIMIT_INFO = *mut HTTP_CONNECTION_LIMIT_INFO; +STRUCT!{struct HTTP_BANDWIDTH_LIMIT_INFO { + Flags: HTTP_PROPERTY_FLAGS, + MaxBandwidth: ULONG, +}} +pub type PHTTP_BANDWIDTH_LIMIT_INFO = *mut HTTP_BANDWIDTH_LIMIT_INFO; +STRUCT!{struct HTTP_FLOWRATE_INFO { + Flags: HTTP_PROPERTY_FLAGS, + MaxBandwidth: ULONG, + MaxPeakBandwidth: ULONG, + BurstSize: ULONG, +}} +pub type PHTTP_FLOWRATE_INFO = *mut HTTP_FLOWRATE_INFO; +pub const HTTP_MIN_ALLOWED_BANDWIDTH_THROTTLING_RATE: ULONG = 1024; +pub const HTTP_LIMIT_INFINITE: ULONG = !0; +ENUM!{enum HTTP_SERVICE_CONFIG_TIMEOUT_KEY { + IdleConnectionTimeout = 0, + HeaderWaitTimeout, +}} +pub type PHTTP_SERVICE_CONFIG_TIMEOUT_KEY = *mut HTTP_SERVICE_CONFIG_TIMEOUT_KEY; +pub type HTTP_SERVICE_CONFIG_TIMEOUT_PARAM = USHORT; +pub type PHTTP_SERVICE_CONFIG_TIMEOUT_PARAM = *mut USHORT; +STRUCT!{struct HTTP_SERVICE_CONFIG_TIMEOUT_SET { + KeyDesc: HTTP_SERVICE_CONFIG_TIMEOUT_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_TIMEOUT_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_TIMEOUT_SET = *mut HTTP_SERVICE_CONFIG_TIMEOUT_SET; +STRUCT!{struct HTTP_TIMEOUT_LIMIT_INFO { + Flags: HTTP_PROPERTY_FLAGS, + EntityBody: USHORT, + DrainEntityBody: USHORT, + RequestQueue: USHORT, + IdleConnection: USHORT, + HeaderWait: USHORT, + MinSendRate: ULONG, +}} +pub type PHTTP_TIMEOUT_LIMIT_INFO = *mut HTTP_TIMEOUT_LIMIT_INFO; +STRUCT!{struct HTTP_LISTEN_ENDPOINT_INFO { + Flags: HTTP_PROPERTY_FLAGS, + EnableSharing: BOOLEAN, +}} +pub type PHTTP_LISTEN_ENDPOINT_INFO = *mut HTTP_LISTEN_ENDPOINT_INFO; +STRUCT!{struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS { + DomainNameLength: USHORT, + DomainName: PWSTR, + RealmLength: USHORT, + Realm: PWSTR, +}} +pub type PHTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS = *mut HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS; +STRUCT!{struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS { + RealmLength: USHORT, + Realm: PWSTR, +}} +pub type PHTTP_SERVER_AUTHENTICATION_BASIC_PARAMS = *mut HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS; +pub const HTTP_AUTH_ENABLE_BASIC: ULONG = 0x00000001; +pub const HTTP_AUTH_ENABLE_DIGEST: ULONG = 0x00000002; +pub const HTTP_AUTH_ENABLE_NTLM: ULONG = 0x00000004; +pub const HTTP_AUTH_ENABLE_NEGOTIATE: ULONG = 0x00000008; +pub const HTTP_AUTH_ENABLE_KERBEROS: ULONG = 0x00000010; +pub const HTTP_AUTH_ENABLE_ALL: ULONG = HTTP_AUTH_ENABLE_BASIC | HTTP_AUTH_ENABLE_DIGEST | + HTTP_AUTH_ENABLE_NTLM | HTTP_AUTH_ENABLE_NEGOTIATE | HTTP_AUTH_ENABLE_KERBEROS; +pub const HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING: UCHAR = 0x01; +pub const HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIAL: UCHAR = 0x02; +STRUCT!{struct HTTP_SERVER_AUTHENTICATION_INFO { + Flags: HTTP_PROPERTY_FLAGS, + AuthSchemes: ULONG, + ReceiveMutualAuth: BOOLEAN, + ReceiveContextHandle: BOOLEAN, + DisableNTLMCredentialCaching: BOOLEAN, + ExFlags: UCHAR, + DigestParams: HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS, + BasicParams: HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS, +}} +pub type PHTTP_SERVER_AUTHENTICATION_INFO = *mut HTTP_SERVER_AUTHENTICATION_INFO; +ENUM!{enum HTTP_SERVICE_BINDING_TYPE { + HttpServiceBindingTypeNone = 0, + HttpServiceBindingTypeW, + HttpServiceBindingTypeA, +}} +STRUCT!{struct HTTP_SERVICE_BINDING_BASE { + Type: HTTP_SERVICE_BINDING_TYPE, +}} +pub type PHTTP_SERVICE_BINDING_BASE = *mut HTTP_SERVICE_BINDING_BASE; +STRUCT!{struct HTTP_SERVICE_BINDING_A { + Base: HTTP_SERVICE_BINDING_BASE, + Buffer: PCHAR, + BufferSize: ULONG, +}} +pub type PHTTP_SERVICE_BINDING_A = *mut HTTP_SERVICE_BINDING_A; +STRUCT!{struct HTTP_SERVICE_BINDING_W { + Base: HTTP_SERVICE_BINDING_BASE, + Buffer: PWCHAR, + BufferSize: ULONG, +}} +pub type PHTTP_SERVICE_BINDING_W = *mut HTTP_SERVICE_BINDING_W; +ENUM!{enum HTTP_AUTHENTICATION_HARDENING_LEVELS { + HttpAuthenticationHardeningLegacy = 0, + HttpAuthenticationHardeningMedium, + HttpAuthenticationHardeningStrict, +}} +pub const HTTP_CHANNEL_BIND_PROXY: ULONG = 0x1; +pub const HTTP_CHANNEL_BIND_PROXY_COHOSTING: ULONG = 0x20; +pub const HTTP_CHANNEL_BIND_NO_SERVICE_NAME_CHECK: ULONG = 0x2; +pub const HTTP_CHANNEL_BIND_DOTLESS_SERVICE: ULONG = 0x4; +pub const HTTP_CHANNEL_BIND_SECURE_CHANNEL_TOKEN: ULONG = 0x8; +pub const HTTP_CHANNEL_BIND_CLIENT_SERVICE: ULONG = 0x10; +STRUCT!{struct HTTP_CHANNEL_BIND_INFO { + Hardening: HTTP_AUTHENTICATION_HARDENING_LEVELS, + Flags: ULONG, + ServiceNames: *mut PHTTP_SERVICE_BINDING_BASE, + NumberOfServiceNames: ULONG, +}} +pub type PHTTP_CHANNEL_BIND_INFO = *mut HTTP_CHANNEL_BIND_INFO; +STRUCT!{struct HTTP_REQUEST_CHANNEL_BIND_STATUS { + ServiceName: PHTTP_SERVICE_BINDING_BASE, + ChannelToken: PUCHAR, + ChannelTokenSize: ULONG, + Flags: ULONG, +}} +pub type PHTTP_REQUEST_CHANNEL_BIND_STATUS = *mut HTTP_REQUEST_CHANNEL_BIND_STATUS; +pub const HTTP_LOG_FIELD_DATE: ULONG = 0x00000001; +pub const HTTP_LOG_FIELD_TIME: ULONG = 0x00000002; +pub const HTTP_LOG_FIELD_CLIENT_IP: ULONG = 0x00000004; +pub const HTTP_LOG_FIELD_USER_NAME: ULONG = 0x00000008; +pub const HTTP_LOG_FIELD_SITE_NAME: ULONG = 0x00000010; +pub const HTTP_LOG_FIELD_COMPUTER_NAME: ULONG = 0x00000020; +pub const HTTP_LOG_FIELD_SERVER_IP: ULONG = 0x00000040; +pub const HTTP_LOG_FIELD_METHOD: ULONG = 0x00000080; +pub const HTTP_LOG_FIELD_URI_STEM: ULONG = 0x00000100; +pub const HTTP_LOG_FIELD_URI_QUERY: ULONG = 0x00000200; +pub const HTTP_LOG_FIELD_STATUS: ULONG = 0x00000400; +pub const HTTP_LOG_FIELD_WIN32_STATUS: ULONG = 0x00000800; +pub const HTTP_LOG_FIELD_BYTES_SENT: ULONG = 0x00001000; +pub const HTTP_LOG_FIELD_BYTES_RECV: ULONG = 0x00002000; +pub const HTTP_LOG_FIELD_TIME_TAKEN: ULONG = 0x00004000; +pub const HTTP_LOG_FIELD_SERVER_PORT: ULONG = 0x00008000; +pub const HTTP_LOG_FIELD_USER_AGENT: ULONG = 0x00010000; +pub const HTTP_LOG_FIELD_COOKIE: ULONG = 0x00020000; +pub const HTTP_LOG_FIELD_REFERER: ULONG = 0x00040000; +pub const HTTP_LOG_FIELD_VERSION: ULONG = 0x00080000; +pub const HTTP_LOG_FIELD_HOST: ULONG = 0x00100000; +pub const HTTP_LOG_FIELD_SUB_STATUS: ULONG = 0x00200000; +pub const HTTP_LOG_FIELD_CLIENT_PORT: ULONG = 0x00400000; +pub const HTTP_LOG_FIELD_URI: ULONG = 0x00800000; +pub const HTTP_LOG_FIELD_SITE_ID: ULONG = 0x01000000; +pub const HTTP_LOG_FIELD_REASON: ULONG = 0x02000000; +pub const HTTP_LOG_FIELD_QUEUE_NAME: ULONG = 0x04000000; +ENUM!{enum HTTP_LOGGING_TYPE { + HttpLoggingTypeW3C, + HttpLoggingTypeIIS, + HttpLoggingTypeNCSA, + HttpLoggingTypeRaw, +}} +ENUM!{enum HTTP_LOGGING_ROLLOVER_TYPE { + HttpLoggingRolloverSize, + HttpLoggingRolloverDaily, + HttpLoggingRolloverWeekly, + HttpLoggingRolloverMonthly, + HttpLoggingRolloverHourly, +}} +pub const HTTP_MIN_ALLOWED_LOG_FILE_ROLLOVER_SIZE: ULONG = 1 * 1024 * 1024; +pub const HTTP_LOGGING_FLAG_LOCAL_TIME_ROLLOVER: ULONG = 0x00000001; +pub const HTTP_LOGGING_FLAG_USE_UTF8_CONVERSION: ULONG = 0x00000002; +pub const HTTP_LOGGING_FLAG_LOG_ERRORS_ONLY: ULONG = 0x00000004; +pub const HTTP_LOGGING_FLAG_LOG_SUCCESS_ONLY: ULONG = 0x00000008; +STRUCT!{struct HTTP_LOGGING_INFO { + Flags: HTTP_PROPERTY_FLAGS, + LoggingFlags: ULONG, + SoftwareName: PCWSTR, + SoftwareNameLength: USHORT, + DirectoryNameLength: USHORT, + DirectoryName: PCWSTR, + Format: HTTP_LOGGING_TYPE, + Fields: ULONG, + pExtFields: PVOID, + NumOfExtFields: USHORT, + MaxRecordSize: USHORT, + RolloverType: HTTP_LOGGING_ROLLOVER_TYPE, + RolloverSize: ULONG, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PHTTP_LOGGING_INFO = *mut HTTP_LOGGING_INFO; +STRUCT!{struct HTTP_BINDING_INFO { + Flags: HTTP_PROPERTY_FLAGS, + RequestQueueHandle: HANDLE, +}} +pub type PHTTP_BINDING_INFO = *mut HTTP_BINDING_INFO; +ENUM!{enum HTTP_PROTECTION_LEVEL_TYPE { + HttpProtectionLevelUnrestricted, + HttpProtectionLevelEdgeRestricted, + HttpProtectionLevelRestricted, +}} +pub type PHTTP_PROTECTION_LEVEL_TYPE = *mut HTTP_PROTECTION_LEVEL_TYPE; +STRUCT!{struct HTTP_PROTECTION_LEVEL_INFO { + Flags: HTTP_PROPERTY_FLAGS, + Level: HTTP_PROTECTION_LEVEL_TYPE, +}} +pub type PHTTP_PROTECTION_LEVEL_INFO = *mut HTTP_PROTECTION_LEVEL_INFO; +pub const HTTP_CREATE_REQUEST_QUEUE_FLAG_OPEN_EXISTING: ULONG = 0x00000001; +pub const HTTP_CREATE_REQUEST_QUEUE_FLAG_CONTROLLER: ULONG = 0x00000002; +pub const HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY: ULONG = 0x00000001; +pub const HTTP_RECEIVE_REQUEST_FLAG_FLUSH_BODY: ULONG = 0x00000002; +pub const HTTP_RECEIVE_REQUEST_ENTITY_BODY_FLAG_FILL_BUFFER: ULONG = 0x00000001; +pub const HTTP_SEND_RESPONSE_FLAG_DISCONNECT: ULONG = 0x00000001; +pub const HTTP_SEND_RESPONSE_FLAG_MORE_DATA: ULONG = 0x00000002; +pub const HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA: ULONG = 0x00000004; +pub const HTTP_SEND_RESPONSE_FLAG_ENABLE_NAGLING: ULONG = 0x00000008; +pub const HTTP_SEND_RESPONSE_FLAG_PROCESS_RANGES: ULONG = 0x00000020; +pub const HTTP_SEND_RESPONSE_FLAG_OPAQUE: ULONG = 0x00000040; +pub const HTTP_FLUSH_RESPONSE_FLAG_RECURSIVE: ULONG = 0x00000001; +pub type HTTP_OPAQUE_ID = ULONGLONG; +pub type PHTTP_OPAQUE_ID = *mut ULONGLONG; +pub type HTTP_REQUEST_ID = HTTP_OPAQUE_ID; +pub type PHTTP_REQUEST_ID = *mut HTTP_OPAQUE_ID; +pub type HTTP_CONNECTION_ID = HTTP_OPAQUE_ID; +pub type PHTTP_CONNECTION_ID = *mut HTTP_OPAQUE_ID; +pub type HTTP_RAW_CONNECTION_ID = HTTP_OPAQUE_ID; +pub type PHTTP_RAW_CONNECTION_ID = *mut HTTP_OPAQUE_ID; +pub type HTTP_URL_GROUP_ID = HTTP_OPAQUE_ID; +pub type PHTTP_URL_GROUP_ID = *mut HTTP_OPAQUE_ID; +pub type HTTP_SERVER_SESSION_ID = HTTP_OPAQUE_ID; +pub type PHTTP_SERVER_SESSION_ID = *mut HTTP_OPAQUE_ID; +pub const HTTP_BYTE_RANGE_TO_EOF: ULONGLONG = !0; +STRUCT!{struct HTTP_BYTE_RANGE { + StartingOffset: ULARGE_INTEGER, + Length: ULARGE_INTEGER, +}} +pub type PHTTP_BYTE_RANGE = *mut HTTP_BYTE_RANGE; +STRUCT!{struct HTTP_VERSION { + MajorVersion: USHORT, + MinorVersion: USHORT, +}} +pub type PHTTP_VERSION = *mut HTTP_VERSION; +pub const HTTP_VERSION_UNKNOWN: HTTP_VERSION = HTTP_VERSION { MajorVersion: 0, MinorVersion: 0 }; +pub const HTTP_VERSION_0_9: HTTP_VERSION = HTTP_VERSION { MajorVersion: 0, MinorVersion: 9 }; +pub const HTTP_VERSION_1_0: HTTP_VERSION = HTTP_VERSION { MajorVersion: 1, MinorVersion: 0 }; +pub const HTTP_VERSION_1_1: HTTP_VERSION = HTTP_VERSION { MajorVersion: 1, MinorVersion: 1 }; +#[inline] +pub fn HTTP_SET_VERSION(mut version: HTTP_VERSION, major: USHORT, minor: USHORT) { + version.MajorVersion = major; + version.MinorVersion = minor; +} +#[inline] +pub fn HTTP_EQUAL_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + version.MajorVersion == major && version.MinorVersion == minor +} +#[inline] +pub fn HTTP_GREATER_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + version.MajorVersion > major || (version.MajorVersion == major && version.MinorVersion > minor) +} +#[inline] +pub fn HTTP_LESS_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + version.MajorVersion < major || (version.MajorVersion == major && version.MinorVersion < minor) +} +#[inline] +pub fn HTTP_NOT_EQUAL_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + !HTTP_EQUAL_VERSION(version, major, minor) +} +#[inline] +pub fn HTTP_GREATER_EQUAL_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + !HTTP_LESS_VERSION(version, major, minor) +} +#[inline] +pub fn HTTP_LESS_EQUAL_VERSION(version: HTTP_VERSION, major: USHORT, minor: USHORT) -> bool { + !HTTP_GREATER_VERSION(version, major, minor) +} +ENUM!{enum HTTP_VERB { + HttpVerbUnparsed, + HttpVerbUnknown, + HttpVerbInvalid, + HttpVerbOPTIONS, + HttpVerbGET, + HttpVerbHEAD, + HttpVerbPOST, + HttpVerbPUT, + HttpVerbDELETE, + HttpVerbTRACE, + HttpVerbCONNECT, + HttpVerbTRACK, + HttpVerbMOVE, + HttpVerbCOPY, + HttpVerbPROPFIND, + HttpVerbPROPPATCH, + HttpVerbMKCOL, + HttpVerbLOCK, + HttpVerbUNLOCK, + HttpVerbSEARCH, + HttpVerbMaximum, +}} +pub type PHTTP_VERB = *mut HTTP_VERB; +ENUM!{enum HTTP_HEADER_ID { + HttpHeaderCacheControl = 0, + HttpHeaderConnection = 1, + HttpHeaderDate = 2, + HttpHeaderKeepAlive = 3, + HttpHeaderPragma = 4, + HttpHeaderTrailer = 5, + HttpHeaderTransferEncoding = 6, + HttpHeaderUpgrade = 7, + HttpHeaderVia = 8, + HttpHeaderWarning = 9, + HttpHeaderAllow = 10, + HttpHeaderContentLength = 11, + HttpHeaderContentType = 12, + HttpHeaderContentEncoding = 13, + HttpHeaderContentLanguage = 14, + HttpHeaderContentLocation = 15, + HttpHeaderContentMd5 = 16, + HttpHeaderContentRange = 17, + HttpHeaderExpires = 18, + HttpHeaderLastModified = 19, + HttpHeaderAccept = 20, + HttpHeaderAcceptCharset = 21, + HttpHeaderAcceptEncoding = 22, + HttpHeaderAcceptLanguage = 23, + HttpHeaderAuthorization = 24, + HttpHeaderCookie = 25, + HttpHeaderExpect = 26, + HttpHeaderFrom = 27, + HttpHeaderHost = 28, + HttpHeaderIfMatch = 29, + HttpHeaderIfModifiedSince = 30, + HttpHeaderIfNoneMatch = 31, + HttpHeaderIfRange = 32, + HttpHeaderIfUnmodifiedSince = 33, + HttpHeaderMaxForwards = 34, + HttpHeaderProxyAuthorization = 35, + HttpHeaderReferer = 36, + HttpHeaderRange = 37, + HttpHeaderTe = 38, + HttpHeaderTranslate = 39, + HttpHeaderUserAgent = 40, + HttpHeaderRequestMaximum = 41, + HttpHeaderAcceptRanges = 20, + HttpHeaderAge = 21, + HttpHeaderEtag = 22, + HttpHeaderLocation = 23, + HttpHeaderProxyAuthenticate = 24, + HttpHeaderRetryAfter = 25, + HttpHeaderServer = 26, + HttpHeaderSetCookie = 27, + HttpHeaderVary = 28, + HttpHeaderWwwAuthenticate = 29, + HttpHeaderResponseMaximum = 30, + HttpHeaderMaximum = 41, +}} +pub type PHTTP_HEADER_ID = *mut HTTP_HEADER_ID; +STRUCT!{struct HTTP_KNOWN_HEADER { + RawValueLength: USHORT, + pRawValue: PCSTR, +}} +pub type PHTTP_KNOWN_HEADER = *mut HTTP_KNOWN_HEADER; +STRUCT!{struct HTTP_UNKNOWN_HEADER { + NameLength: USHORT, + RawValueLength: USHORT, + pName: PCSTR, + pRawValue: PCSTR, +}} +pub type PHTTP_UNKNOWN_HEADER = *mut HTTP_UNKNOWN_HEADER; +ENUM!{enum HTTP_LOG_DATA_TYPE { + HttpLogDataTypeFields = 0, +}} +pub type PHTTP_LOG_DATA_TYPE = *mut HTTP_LOG_DATA_TYPE; +STRUCT!{struct HTTP_LOG_DATA { + Type: HTTP_LOG_DATA_TYPE, +}} +pub type PHTTP_LOG_DATA = *mut HTTP_LOG_DATA; +STRUCT!{struct HTTP_LOG_FIELDS_DATA { + Base: HTTP_LOG_DATA, + UserNameLength: USHORT, + UriStemLength: USHORT, + ClientIpLength: USHORT, + ServerNameLength: USHORT, + ServiceNameLength: USHORT, + ServerIpLength: USHORT, + MethodLength: USHORT, + UriQueryLength: USHORT, + HostLength: USHORT, + UserAgentLength: USHORT, + CookieLength: USHORT, + ReferrerLength: USHORT, + UserName: PWCHAR, + UriStem: PWCHAR, + ClientIp: PCHAR, + ServerName: PCHAR, + ServiceName: PCHAR, + ServerIp: PCHAR, + Method: PCHAR, + UriQuery: PCHAR, + Host: PCHAR, + UserAgent: PCHAR, + Cookie: PCHAR, + Referrer: PCHAR, + ServerPort: USHORT, + ProtocolStatus: USHORT, + Win32Status: ULONG, + MethodNum: HTTP_VERB, + SubStatus: USHORT, +}} +pub type PHTTP_LOG_FIELDS_DATA = *mut HTTP_LOG_FIELDS_DATA; +ENUM!{enum HTTP_DATA_CHUNK_TYPE { + HttpDataChunkFromMemory, + HttpDataChunkFromFileHandle, + HttpDataChunkFromFragmentCache, + HttpDataChunkFromFragmentCacheEx, + HttpDataChunkMaximum, +}} +pub type PHTTP_DATA_CHUNK_TYPE = *mut HTTP_DATA_CHUNK_TYPE; +STRUCT!{struct HTTP_DATA_CHUNK_FromMemory { + pBuffer: PVOID, + BufferLength: ULONG, +}} +STRUCT!{struct HTTP_DATA_CHUNK_FromFileHandle { + ByteRange: HTTP_BYTE_RANGE, + FileHandle: HANDLE, +}} +STRUCT!{struct HTTP_DATA_CHUNK_FromFragmentCache { + FragmentNameLength: USHORT, + pFragmentName: PCWSTR, +}} +STRUCT!{struct HTTP_DATA_CHUNK_FromFragmentCacheEx { + ByteRange: HTTP_BYTE_RANGE, + pFragmentName: PCWSTR, +}} +UNION!{union HTTP_DATA_CHUNK_u { + [u64; 3], + FromMemory FromMemory_mut: HTTP_DATA_CHUNK_FromMemory, + FromFileHandle FromFileHandle_mut: HTTP_DATA_CHUNK_FromFileHandle, + FromFragmentCache FromFragmentCache_mut: HTTP_DATA_CHUNK_FromFragmentCache, + FromFragmentCacheEx FromFragmentCacheEx_mut: HTTP_DATA_CHUNK_FromFragmentCacheEx, +}} +STRUCT!{struct HTTP_DATA_CHUNK { + DataChunkType: HTTP_DATA_CHUNK_TYPE, + u: HTTP_DATA_CHUNK_u, +}} +pub type PHTTP_DATA_CHUNK = *mut HTTP_DATA_CHUNK; +STRUCT!{struct HTTP_REQUEST_HEADERS { + UnknownHeaderCount: USHORT, + pUnknownHeaders: PHTTP_UNKNOWN_HEADER, + TrailerCount: USHORT, + pTrailers: PHTTP_UNKNOWN_HEADER, + KnownHeaders: [HTTP_KNOWN_HEADER; 41], // FIXME HttpHeaderRequestMaximum +}} +pub type PHTTP_REQUEST_HEADERS = *mut HTTP_REQUEST_HEADERS; +STRUCT!{struct HTTP_RESPONSE_HEADERS { + UnknownHeaderCount: USHORT, + pUnknownHeaders: PHTTP_UNKNOWN_HEADER, + TrailerCount: USHORT, + pTrailers: PHTTP_UNKNOWN_HEADER, + KnownHeaders: [HTTP_KNOWN_HEADER; 30], // FIXME HttpHeaderResponseMaximum +}} +pub type PHTTP_RESPONSE_HEADERS = *mut HTTP_RESPONSE_HEADERS; +STRUCT!{struct HTTP_TRANSPORT_ADDRESS { + pRemoteAddress: PSOCKADDR, + pLocalAddress: PSOCKADDR, +}} +pub type PHTTP_TRANSPORT_ADDRESS = *mut HTTP_TRANSPORT_ADDRESS; +STRUCT!{struct HTTP_COOKED_URL { + FullUrlLength: USHORT, + HostLength: USHORT, + AbsPathLength: USHORT, + QueryStringLength: USHORT, + pFullUrl: PCWSTR, + pHost: PCWSTR, + pAbsPath: PCWSTR, + pQueryString: PCWSTR, +}} +pub type PHTTP_COOKED_URL = *mut HTTP_COOKED_URL; +pub type HTTP_URL_CONTEXT = ULONGLONG; +pub const HTTP_URL_FLAG_REMOVE_ALL: ULONG = 0x00000001; +ENUM!{enum HTTP_AUTH_STATUS { + HttpAuthStatusSuccess, + HttpAuthStatusNotAuthenticated, + HttpAuthStatusFailure, +}} +pub type PHTTP_AUTH_STATUS = *mut HTTP_AUTH_STATUS; +ENUM!{enum HTTP_REQUEST_AUTH_TYPE { + HttpRequestAuthTypeNone = 0, + HttpRequestAuthTypeBasic, + HttpRequestAuthTypeDigest, + HttpRequestAuthTypeNTLM, + HttpRequestAuthTypeNegotiate, + HttpRequestAuthTypeKerberos, +}} +pub type PHTTP_REQUEST_AUTH_TYPE = *mut HTTP_REQUEST_AUTH_TYPE; +STRUCT!{struct HTTP_SSL_CLIENT_CERT_INFO { + CertFlags: ULONG, + CertEncodedSize: ULONG, + pCertEncoded: PUCHAR, + Token: HANDLE, + CertDeniedByMapper: BOOLEAN, +}} +pub type PHTTP_SSL_CLIENT_CERT_INFO = *mut HTTP_SSL_CLIENT_CERT_INFO; +pub const HTTP_RECEIVE_SECURE_CHANNEL_TOKEN: ULONG = 0x1; +STRUCT!{struct HTTP_SSL_INFO { + ServerCertKeySize: USHORT, + ConnectionKeySize: USHORT, + ServerCertIssuerSize: ULONG, + ServerCertSubjectSize: ULONG, + pServerCertIssuer: PCSTR, + pServerCertSubject: PCSTR, + pClientCertInfo: PHTTP_SSL_CLIENT_CERT_INFO, + SslClientCertNegotiated: ULONG, +}} +pub type PHTTP_SSL_INFO = *mut HTTP_SSL_INFO; +ENUM!{enum HTTP_REQUEST_INFO_TYPE { + HttpRequestInfoTypeAuth, + HttpRequestInfoTypeChannelBind, +}} +STRUCT!{struct HTTP_REQUEST_INFO { + InfoType: HTTP_REQUEST_INFO_TYPE, + InfoLength: ULONG, + pInfo: PVOID, +}} +pub type PHTTP_REQUEST_INFO = *mut HTTP_REQUEST_INFO; +pub const HTTP_REQUEST_AUTH_FLAG_TOKEN_FOR_CACHED_CRED: ULONG = 0x00000001; +STRUCT!{struct HTTP_REQUEST_AUTH_INFO { + AuthStatus: HTTP_AUTH_STATUS, + SecStatus: SECURITY_STATUS, + Flags: ULONG, + AuthType: HTTP_REQUEST_AUTH_TYPE, + AccessToken: HANDLE, + ContextAttributes: ULONG, + PackedContextLength: ULONG, + PackedContextType: ULONG, + PackedContext: PVOID, + MutualAuthDataLength: ULONG, + pMutualAuthData: PCHAR, + PackageNameLength: USHORT, + pPackageName: PWSTR, +}} +pub type PHTTP_REQUEST_AUTH_INFO = *mut HTTP_REQUEST_AUTH_INFO; +STRUCT!{struct HTTP_REQUEST_V1 { + Flags: ULONG, + ConnectionId: HTTP_CONNECTION_ID, + RequestId: HTTP_REQUEST_ID, + UrlContext: HTTP_URL_CONTEXT, + Version: HTTP_VERSION, + Verb: HTTP_VERB, + UnknownVerbLength: USHORT, + RawUrlLength: USHORT, + pUnknownVerb: PCSTR, + pRawUrl: PCSTR, + CookedUrl: HTTP_COOKED_URL, + Address: HTTP_TRANSPORT_ADDRESS, + Headers: HTTP_REQUEST_HEADERS, + BytesReceived: ULONGLONG, + EntityChunkCount: USHORT, + pEntityChunks: PHTTP_DATA_CHUNK, + RawConnectionId: HTTP_RAW_CONNECTION_ID, + pSslInfo: PHTTP_SSL_INFO, +}} +pub type PHTTP_REQUEST_V1 = *mut HTTP_REQUEST_V1; +STRUCT!{struct HTTP_REQUEST_V2 { + Base: HTTP_REQUEST_V1, + RequestInfoCount: USHORT, + pRequestInfo: PHTTP_REQUEST_INFO, +}} +pub type PHTTP_REQUEST_V2 = *mut HTTP_REQUEST_V2; +pub type HTTP_REQUEST = HTTP_REQUEST_V2; +pub type PHTTP_REQUEST = *mut HTTP_REQUEST; +pub const HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS: ULONG = 0x00000001; +pub const HTTP_REQUEST_FLAG_IP_ROUTED: ULONG = 0x00000002; +STRUCT!{struct HTTP_RESPONSE_V1 { + Flags: ULONG, + Version: HTTP_VERSION, + StatusCode: USHORT, + ReasonLength: USHORT, + pReason: PCSTR, + Headers: HTTP_RESPONSE_HEADERS, + EntityChunkCount: USHORT, + pEntityChunks: PHTTP_DATA_CHUNK, +}} +pub type PHTTP_RESPONSE_V1 = *mut HTTP_RESPONSE_V1; +pub const HTTP_RESPONSE_FLAG_MULTIPLE_ENCODINGS_AVAILABLE: ULONG = 0x00000001; +ENUM!{enum HTTP_RESPONSE_INFO_TYPE { + HttpResponseInfoTypeMultipleKnownHeaders, + HttpResponseInfoTypeAuthenticationProperty, + HttpResponseInfoTypeQoSProperty, + HttpResponseInfoTypeChannelBind, +}} +pub type PHTTP_RESPONSE_INFO_TYPE = *mut HTTP_RESPONSE_INFO_TYPE; +STRUCT!{struct HTTP_RESPONSE_INFO { + Type: HTTP_RESPONSE_INFO_TYPE, + Length: ULONG, + pInfo: PVOID, +}} +pub type PHTTP_RESPONSE_INFO = *mut HTTP_RESPONSE_INFO; +pub const HTTP_RESPONSE_INFO_FLAGS_PRESERVE_ORDER: ULONG = 0x00000001; +STRUCT!{struct HTTP_MULTIPLE_KNOWN_HEADERS { + HeaderId: HTTP_HEADER_ID, + Flags: ULONG, + KnownHeaderCount: USHORT, + KnownHeaders: PHTTP_KNOWN_HEADER, +}} +pub type PHTTP_MULTIPLE_KNOWN_HEADERS = *mut HTTP_MULTIPLE_KNOWN_HEADERS; +STRUCT!{struct HTTP_RESPONSE_V2 { + Base: HTTP_RESPONSE_V1, + ResponseInfoCount: USHORT, + pResponseInfo: PHTTP_RESPONSE_INFO, +}} +pub type PHTTP_RESPONSE_V2 = *mut HTTP_RESPONSE_V2; +pub type HTTP_RESPONSE = HTTP_RESPONSE_V2; +pub type PHTTP_RESPONSE = *mut HTTP_RESPONSE; +STRUCT!{struct HTTPAPI_VERSION { + HttpApiMajorVersion: USHORT, + HttpApiMinorVersion: USHORT, +}} +pub type PHTTPAPI_VERSION = *mut HTTPAPI_VERSION; +pub const HTTPAPI_VERSION_2: HTTPAPI_VERSION = HTTPAPI_VERSION { + HttpApiMajorVersion: 2, + HttpApiMinorVersion: 0, +}; +pub const HTTPAPI_VERSION_1: HTTPAPI_VERSION = HTTPAPI_VERSION { + HttpApiMajorVersion: 1, + HttpApiMinorVersion: 0, +}; +#[inline] +pub fn HTTPAPI_EQUAL_VERSION(version: HTTPAPI_VERSION, major: USHORT, minor: USHORT) -> bool { + version.HttpApiMajorVersion == major && version.HttpApiMinorVersion == minor +} +#[inline] +pub fn HTTPAPI_GREATER_VERSION(version: HTTPAPI_VERSION, major: USHORT, minor: USHORT) -> bool { + version.HttpApiMajorVersion > major || + (version.HttpApiMajorVersion == major && version.HttpApiMinorVersion > minor) +} +#[inline] +pub fn HTTPAPI_LESS_VERSION(version: HTTPAPI_VERSION, major: USHORT, minor: USHORT) -> bool { + version.HttpApiMajorVersion < major || + (version.HttpApiMajorVersion == major && version.HttpApiMinorVersion < minor) +} +#[inline] +pub fn HTTPAPI_VERSION_GREATER_OR_EQUAL( + version: HTTPAPI_VERSION, + major: USHORT, + minor: USHORT, +) -> bool { + !HTTPAPI_LESS_VERSION(version, major, minor) +} +ENUM!{enum HTTP_CACHE_POLICY_TYPE { + HttpCachePolicyNocache, + HttpCachePolicyUserInvalidates, + HttpCachePolicyTimeToLive, + HttpCachePolicyMaximum, +}} +pub type PHTTP_CACHE_POLICY_TYPE = *mut HTTP_CACHE_POLICY_TYPE; +STRUCT!{struct HTTP_CACHE_POLICY { + Policy: HTTP_CACHE_POLICY_TYPE, + SecondsToLive: ULONG, +}} +pub type PHTTP_CACHE_POLICY = *mut HTTP_CACHE_POLICY; +ENUM!{enum HTTP_SERVICE_CONFIG_ID { + HttpServiceConfigIPListenList, + HttpServiceConfigSSLCertInfo, + HttpServiceConfigUrlAclInfo, + HttpServiceConfigTimeout, + HttpServiceConfigCache, + HttpServiceConfigSslSniCertInfo, + HttpServiceConfigSslCcsCertInfo, + HttpServiceConfigMax, +}} +pub type PHTTP_SERVICE_CONFIG_ID = *mut HTTP_SERVICE_CONFIG_ID; +ENUM!{enum HTTP_SERVICE_CONFIG_QUERY_TYPE { + HttpServiceConfigQueryExact, + HttpServiceConfigQueryNext, + HttpServiceConfigQueryMax, +}} +pub type PHTTP_SERVICE_CONFIG_QUERY_TYPE = *mut HTTP_SERVICE_CONFIG_QUERY_TYPE; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_KEY { + pIpPort: PSOCKADDR, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_KEY = *mut HTTP_SERVICE_CONFIG_SSL_KEY; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_SNI_KEY { + IpPort: SOCKADDR_STORAGE, + Host: PWSTR, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_SNI_KEY = *mut HTTP_SERVICE_CONFIG_SSL_SNI_KEY; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_CCS_KEY { + LocalAddress: SOCKADDR_STORAGE, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_CCS_KEY = *mut HTTP_SERVICE_CONFIG_SSL_CCS_KEY; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_PARAM { + SslHashLength: ULONG, + pSslHash: PVOID, + AppId: GUID, + pSslCertStoreName: PWSTR, + DefaultCertCheckMode: DWORD, + DefaultRevocationFreshnessTime: DWORD, + DefaultRevocationUrlRetrievalTimeout: DWORD, + pDefaultSslCtlIdentifier: PWSTR, + pDefaultSslCtlStoreName: PWSTR, + DefaultFlags: DWORD, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_PARAM = *mut HTTP_SERVICE_CONFIG_SSL_PARAM; +pub const HTTP_SERVICE_CONFIG_SSL_FLAG_USE_DS_MAPPER: DWORD = 0x00000001; +pub const HTTP_SERVICE_CONFIG_SSL_FLAG_NEGOTIATE_CLIENT_CERT: DWORD = 0x00000002; +pub const HTTP_SERVICE_CONFIG_SSL_FLAG_NO_RAW_FILTER: DWORD = 0x00000004; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_SET { + KeyDesc: HTTP_SERVICE_CONFIG_SSL_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_SSL_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_SET = *mut HTTP_SERVICE_CONFIG_SSL_SET; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_SNI_SET { + KeyDesc: HTTP_SERVICE_CONFIG_SSL_SNI_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_SSL_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_SNI_SET = *mut HTTP_SERVICE_CONFIG_SSL_SNI_SET; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_CCS_SET { + KeyDesc: HTTP_SERVICE_CONFIG_SSL_CCS_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_SSL_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_CCS_SET = *mut HTTP_SERVICE_CONFIG_SSL_CCS_SET; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_QUERY { + QueryDesc: HTTP_SERVICE_CONFIG_QUERY_TYPE, + KeyDesc: HTTP_SERVICE_CONFIG_SSL_KEY, + dwToken: DWORD, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_QUERY = *mut HTTP_SERVICE_CONFIG_SSL_QUERY; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_SNI_QUERY { + QueryDesc: HTTP_SERVICE_CONFIG_QUERY_TYPE, + KeyDesc: HTTP_SERVICE_CONFIG_SSL_SNI_KEY, + dwToken: DWORD, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_SNI_QUERY = *mut HTTP_SERVICE_CONFIG_SSL_SNI_QUERY; +STRUCT!{struct HTTP_SERVICE_CONFIG_SSL_CCS_QUERY { + QueryDesc: HTTP_SERVICE_CONFIG_QUERY_TYPE, + KeyDesc: HTTP_SERVICE_CONFIG_SSL_CCS_KEY, + dwToken: DWORD, +}} +pub type PHTTP_SERVICE_CONFIG_SSL_CCS_QUERY = *mut HTTP_SERVICE_CONFIG_SSL_CCS_QUERY; +STRUCT!{struct HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM { + AddrLength: USHORT, + pAddress: PSOCKADDR, +}} +pub type PHTTP_SERVICE_CONFIG_IP_LISTEN_PARAM = *mut HTTP_SERVICE_CONFIG_IP_LISTEN_PARAM; +STRUCT!{struct HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY { + AddrCount: ULONG, + AddrList: [SOCKADDR_STORAGE; ANYSIZE_ARRAY], +}} +pub type PHTTP_SERVICE_CONFIG_IP_LISTEN_QUERY = *mut HTTP_SERVICE_CONFIG_IP_LISTEN_QUERY; +STRUCT!{struct HTTP_SERVICE_CONFIG_URLACL_KEY { + pUrlPrefix: PWSTR, +}} +pub type PHTTP_SERVICE_CONFIG_URLACL_KEY = *mut HTTP_SERVICE_CONFIG_URLACL_KEY; +STRUCT!{struct HTTP_SERVICE_CONFIG_URLACL_PARAM { + pStringSecurityDescriptor: PWSTR, +}} +pub type PHTTP_SERVICE_CONFIG_URLACL_PARAM = *mut HTTP_SERVICE_CONFIG_URLACL_PARAM; +STRUCT!{struct HTTP_SERVICE_CONFIG_URLACL_SET { + KeyDesc: HTTP_SERVICE_CONFIG_URLACL_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_URLACL_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_URLACL_SET = *mut HTTP_SERVICE_CONFIG_URLACL_SET; +STRUCT!{struct HTTP_SERVICE_CONFIG_URLACL_QUERY { + QueryDesc: HTTP_SERVICE_CONFIG_QUERY_TYPE, + KeyDesc: HTTP_SERVICE_CONFIG_URLACL_KEY, + dwToken: DWORD, +}} +pub type PHTTP_SERVICE_CONFIG_URLACL_QUERY = *mut HTTP_SERVICE_CONFIG_URLACL_QUERY; +ENUM!{enum HTTP_SERVICE_CONFIG_CACHE_KEY { + MaxCacheResponseSize = 0, + CacheRangeChunkSize, +}} +pub type PHTTP_SERVICE_CONFIG_CACHE_KEY = *mut HTTP_SERVICE_CONFIG_CACHE_KEY; +pub type HTTP_SERVICE_CONFIG_CACHE_PARAM = ULONG; +pub type PHTTP_SERVICE_CONFIG_CACHE_PARAM = *mut ULONG; +STRUCT!{struct HTTP_SERVICE_CONFIG_CACHE_SET { + KeyDesc: HTTP_SERVICE_CONFIG_CACHE_KEY, + ParamDesc: HTTP_SERVICE_CONFIG_CACHE_PARAM, +}} +pub type PHTTP_SERVICE_CONFIG_CACHE_SET = *mut HTTP_SERVICE_CONFIG_CACHE_SET; +extern "system" { + pub fn HttpInitialize( + Version: HTTPAPI_VERSION, + Flags: ULONG, + pReserved: PVOID, + ) -> ULONG; + pub fn HttpTerminate( + Flags: ULONG, + pReserved: PVOID, + ) -> ULONG; + pub fn HttpCreateHttpHandle( + pReqQueueHandle: HANDLE, + Reserved: ULONG, + ) -> ULONG; + pub fn HttpCreateRequestQueue( + Version: HTTPAPI_VERSION, + pName: PCWSTR, + pSecurityAttributes: PSECURITY_ATTRIBUTES, + Flags: ULONG, + pReqQueueHandle: PHANDLE, + ) -> ULONG; + pub fn HttpCloseRequestQueue( + ReqQueueHandle: HANDLE, + ) -> ULONG; + pub fn HttpSetRequestQueueProperty( + Handle: HANDLE, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + Reserved: ULONG, + pReserved: PVOID, + ) -> ULONG; + pub fn HttpQueryRequestQueueProperty( + Handle: HANDLE, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + Reserved: ULONG, + pReturnLength: PULONG, + pReserved: PVOID, + ) -> ULONG; + pub fn HttpShutdownRequestQueue( + ReqQueueHandle: HANDLE, + ) -> ULONG; + pub fn HttpReceiveClientCertificate( + ReqQueueHandle: HANDLE, + ConnectionId: HTTP_CONNECTION_ID, + Flags: ULONG, + pSslClientCertInfo: PHTTP_SSL_CLIENT_CERT_INFO, + SslClientCertInfoSize: ULONG, + pBytesReceived: PULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpCreateServerSession( + Version: HTTPAPI_VERSION, + pServerSessionId: PHTTP_SERVER_SESSION_ID, + Reserved: ULONG, + ) -> ULONG; + pub fn HttpCloseServerSession( + ServerSessionId: HTTP_SERVER_SESSION_ID, + ) -> ULONG; + pub fn HttpQueryServerSessionProperty( + ServerSessionId: HTTP_SERVER_SESSION_ID, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + pReturnLength: PULONG, + ) -> ULONG; + pub fn HttpSetServerSessionProperty( + ServerSessionId: HTTP_SERVER_SESSION_ID, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + ) -> ULONG; + pub fn HttpAddUrl( + ReqQueueHandle: HANDLE, + pFullyQualifiedUrl: PCWSTR, + pReserved: PVOID, + ) -> ULONG; + pub fn HttpRemoveUrl( + ReqQueueHandle: HANDLE, + pFullyQualifiedUrl: PCWSTR, + ) -> ULONG; + pub fn HttpCreateUrlGroup( + ServerSessionId: HTTP_SERVER_SESSION_ID, + pUrlGroupId: PHTTP_URL_GROUP_ID, + Reserved: ULONG, + ) -> ULONG; + pub fn HttpCloseUrlGroup( + UrlGroupId: HTTP_URL_GROUP_ID, + ) -> ULONG; + pub fn HttpAddUrlToUrlGroup( + UrlGroupId: HTTP_URL_GROUP_ID, + pFullyQualifiedUrl: PCWSTR, + UrlContext: HTTP_URL_CONTEXT, + Reserved: ULONG, + ) -> ULONG; + pub fn HttpRemoveUrlFromUrlGroup( + UrlGroupId: HTTP_URL_GROUP_ID, + pFullyQualifiedUrl: PCWSTR, + Flags: ULONG, + ) -> ULONG; + pub fn HttpSetUrlGroupProperty( + UrlGroupId: HTTP_URL_GROUP_ID, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + ) -> ULONG; + pub fn HttpQueryUrlGroupProperty( + UrlGroupId: HTTP_URL_GROUP_ID, + Property: HTTP_SERVER_PROPERTY, + pPropertyInformation: PVOID, + PropertyInformationLength: ULONG, + pReturnLength: PULONG, + ) -> ULONG; + pub fn HttpPrepareUrl( + Reserved: PVOID, + Flags: ULONG, + Url: PCWSTR, + PreparedUrl: *mut PWSTR, + ) -> ULONG; + pub fn HttpReceiveHttpRequest( + ReqQueueHandle: HANDLE, + RequestId: HTTP_REQUEST_ID, + Flags: ULONG, + pRequestBuffer: PHTTP_REQUEST, + RequestBufferLength: ULONG, + pBytesReturned: PULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpReceiveRequestEntityBody( + ReqQueueHandle: HANDLE, + RequestId: HTTP_REQUEST_ID, + Flags: ULONG, + pBuffer: PVOID, + EntityBufferLength: ULONG, + pBytesReturned: PULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpSendHttpResponse( + ReqQueueHandle: HANDLE, + RequestId: HTTP_REQUEST_ID, + Flags: ULONG, + pHttpResponse: PHTTP_RESPONSE, + pCachePolicy: PHTTP_CACHE_POLICY, + pBytesSent: PULONG, + pReserved1: PVOID, + Reserved2: ULONG, + pOverlapped: LPOVERLAPPED, + pLogData: PHTTP_LOG_DATA, + ) -> ULONG; + pub fn HttpSendResponseEntityBody( + ReqQueueHandle: HANDLE, + RequestId: HTTP_REQUEST_ID, + Flags: ULONG, + EntityChunkCount: USHORT, + pEntityChunks: PHTTP_DATA_CHUNK, + pBytesSent: PULONG, + pReserved1: PVOID, + Reserved2: ULONG, + pOverlapped: LPOVERLAPPED, + pLogData: PHTTP_LOG_DATA, + ) -> ULONG; + pub fn HttpWaitForDisconnect( + ReqQueueHandle: HANDLE, + ConnectionId: HTTP_CONNECTION_ID, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpWaitForDisconnectEx( + ReqQueueHandle: HANDLE, + ConnectionId: HTTP_CONNECTION_ID, + Reserved: ULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpCancelHttpRequest( + ReqQueueHandle: HANDLE, + RequestId: HTTP_REQUEST_ID, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpWaitForDemandStart( + ReqQueueHandle: HANDLE, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpFlushResponseCache( + ReqQueueHandle: HANDLE, + pUrlPrefix: PCWSTR, + Flags: ULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpAddFragmentToCache( + ReqQueueHandle: HANDLE, + pUrlPrefix: PCWSTR, + pDataChunk: PHTTP_DATA_CHUNK, + pCachePolicy: PHTTP_CACHE_POLICY, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpReadFragmentFromCache( + ReqQueueHandle: HANDLE, + pUrlPrefix: PCWSTR, + pByteRange: PHTTP_BYTE_RANGE, + pBuffer: PVOID, + BufferLength: ULONG, + pBytesRead: PULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpSetServiceConfiguration( + ServiceHandle: HANDLE, + ConfigId: HTTP_SERVICE_CONFIG_ID, + pConfigInformation: PVOID, + ConfigInformationLength: ULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpDeleteServiceConfiguration( + ServiceHandle: HANDLE, + ConfigId: HTTP_SERVICE_CONFIG_ID, + pConfigInformation: PVOID, + ConfigInformationLength: ULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; + pub fn HttpQueryServiceConfiguration( + ServiceHandle: HANDLE, + ConfigId: HTTP_SERVICE_CONFIG_ID, + pInput: PVOID, + InputLength: ULONG, + pOutput: PVOID, + OutputLength: ULONG, + pReturnLength: PULONG, + pOverlapped: LPOVERLAPPED, + ) -> ULONG; +} diff --git a/winapi/src/um/imm.rs b/winapi/src/um/imm.rs new file mode 100644 index 000000000..ddf4c3f2c --- /dev/null +++ b/winapi/src/um/imm.rs @@ -0,0 +1,42 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_uint; +use shared::minwindef::{BOOL, DWORD, UINT}; +use shared::windef::{HWND, POINT, RECT}; +pub type LPUINT = *mut c_uint; +STRUCT!{struct COMPOSITIONFORM { + dwStyle: DWORD, + ptCurrentPos: POINT, + rcArea: RECT, +}} +DECLARE_HANDLE!{HIMC, HIMC__} +pub type LPCOMPOSITIONFORM = *mut COMPOSITIONFORM; +extern "system" { + pub fn ImmGetContext( + hwnd: HWND, + ) -> HIMC; + pub fn ImmGetOpenStatus( + himc: HIMC, + ) -> BOOL; + pub fn ImmSetOpenStatus( + himc: HIMC, + fopen: BOOL, + ) -> BOOL; + pub fn ImmSetCompositionWindow( + himc: HIMC, + lpCompForm: LPCOMPOSITIONFORM, + ) -> BOOL; + pub fn ImmReleaseContext( + hwnd: HWND, + himc: HIMC, + ) -> BOOL; +} +pub const CFS_DEFAULT: UINT = 0x0000; +pub const CFS_RECT: UINT = 0x0001; +pub const CFS_POINT: UINT = 0x0002; +pub const CFS_FORCE_POSITION: UINT = 0x0020; +pub const CFS_CANDIDATEPOS: UINT = 0x0040; +pub const CFS_EXCLUDE: UINT = 0x0080; diff --git a/winapi/src/um/interlockedapi.rs b/winapi/src/um/interlockedapi.rs new file mode 100644 index 000000000..17f656db9 --- /dev/null +++ b/winapi/src/um/interlockedapi.rs @@ -0,0 +1,31 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{ULONG, USHORT}; +use um::winnt::{PSLIST_ENTRY, PSLIST_HEADER}; +extern "system" { + pub fn InitializeSListHead( + ListHead: PSLIST_HEADER, + ); + pub fn InterlockedPopEntrySList( + ListHead: PSLIST_HEADER, + ) -> PSLIST_ENTRY; + pub fn InterlockedPushEntrySList( + ListHead: PSLIST_HEADER, + ListEntry: PSLIST_ENTRY, + ) -> PSLIST_ENTRY; + pub fn InterlockedPushListSListEx( + ListHead: PSLIST_HEADER, + List: PSLIST_ENTRY, + ListEnd: PSLIST_ENTRY, + Count: ULONG, + ) -> PSLIST_ENTRY; + pub fn InterlockedFlushSList( + ListHead: PSLIST_HEADER, + ) -> PSLIST_ENTRY; + pub fn QueryDepthSList( + ListHead: PSLIST_HEADER, + ) -> USHORT; +} diff --git a/winapi/src/um/ioapiset.rs b/winapi/src/um/ioapiset.rs new file mode 100644 index 000000000..b9b710964 --- /dev/null +++ b/winapi/src/um/ioapiset.rs @@ -0,0 +1,71 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{PULONG_PTR, ULONG_PTR}; +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, PULONG, ULONG}; +use um::minwinbase::{LPOVERLAPPED, LPOVERLAPPED_ENTRY}; +use um::winnt::HANDLE; +extern "system" { + pub fn CreateIoCompletionPort( + FileHandle: HANDLE, + ExistingCompletionPort: HANDLE, + CompletionKey: ULONG_PTR, + NumberOfConcurrentThreads: DWORD, + ) -> HANDLE; + pub fn GetQueuedCompletionStatus( + CompletionPort: HANDLE, + lpNumberOfBytesTransferred: LPDWORD, + lpCompletionKey: PULONG_PTR, + lpOverlapped: *mut LPOVERLAPPED, + dwMilliseconds: DWORD, + ) -> BOOL; + pub fn GetQueuedCompletionStatusEx( + CompletionPort: HANDLE, + lpCompletionPortEntries: LPOVERLAPPED_ENTRY, + ulCount: ULONG, + ulNumEntriesRemoved: PULONG, + dwMilliseconds: DWORD, + fAlertable: BOOL, + ) -> BOOL; + pub fn PostQueuedCompletionStatus( + CompletionPort: HANDLE, + dwNumberOfBytesTransferred: DWORD, + dwCompletionKey: ULONG_PTR, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn DeviceIoControl( + hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn GetOverlappedResult( + hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + bWait: BOOL, + ) -> BOOL; + pub fn CancelIoEx( + hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn CancelIo( + hFile: HANDLE, + ) -> BOOL; + pub fn GetOverlappedResultEx( + hFile: HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + dwMilliseconds: DWORD, + bAlertable: BOOL, + ) -> BOOL; + pub fn CancelSynchronousIo( + hThread: HANDLE, + ) -> BOOL; +} diff --git a/winapi/src/um/jobapi.rs b/winapi/src/um/jobapi.rs new file mode 100644 index 000000000..cbe45c1dc --- /dev/null +++ b/winapi/src/um/jobapi.rs @@ -0,0 +1,14 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, PBOOL}; +use um::winnt::HANDLE; +extern "system" { + pub fn IsProcessInJob( + ProcessHandle: HANDLE, + JobHandle: HANDLE, + Result: PBOOL, + ) -> BOOL; +} diff --git a/winapi/src/um/jobapi2.rs b/winapi/src/um/jobapi2.rs new file mode 100644 index 000000000..98eb1e9d1 --- /dev/null +++ b/winapi/src/um/jobapi2.rs @@ -0,0 +1,63 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::LONG64; +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, UINT, ULONG}; +use shared::ntdef::{HANDLE, LPCWSTR, PCWSTR, VOID}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::winnt::JOBOBJECTINFOCLASS; +STRUCT!{struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION { + MaxIops: LONG64, + MaxBandwidth: LONG64, + ReservationIops: LONG64, + VolumeName: PCWSTR, + BaseIoSize: ULONG, + ControlFlags: ULONG, +}} +extern "system" { + pub fn CreateJobObjectW( + lpJobAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn FreeMemoryJobObject( + Buffer: *mut VOID, + ) -> (); + pub fn OpenJobObjectW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn AssignProcessToJobObject( + hJob: HANDLE, + hProcess: HANDLE, + ) -> BOOL; + pub fn TerminateJobObject( + hJob: HANDLE, + uExitCode: UINT, + ) -> BOOL; + pub fn SetInformationJobObject( + hJob: HANDLE, + JobObjectInformationClass: JOBOBJECTINFOCLASS, + lpJobObjectInformation: LPVOID, + cbJovObjectInformationLength: DWORD, + ) -> BOOL; + pub fn SetIoRateControlInformationJobObject( + hJob: HANDLE, + IoRateControlInfo: *mut JOBOBJECT_IO_RATE_CONTROL_INFORMATION, + ) -> DWORD; + pub fn QueryInformationJobObject( + hJob: HANDLE, + JobObjectInformationClass: JOBOBJECTINFOCLASS, + lpJobObjectInformation: LPVOID, + cbJovObjectInformationLength: DWORD, + lpReturnLength: LPDWORD, + ) -> BOOL; + pub fn QueryIoRateControlInformationJobObject( + hJob: HANDLE, + VolumeName: PCWSTR, + InfoBlocks: *mut *mut JOBOBJECT_IO_RATE_CONTROL_INFORMATION, + InfoBlockCount: *mut ULONG, + ) -> DWORD; +} diff --git a/winapi/src/um/knownfolders.rs b/winapi/src/um/knownfolders.rs new file mode 100644 index 000000000..a761ce297 --- /dev/null +++ b/winapi/src/um/knownfolders.rs @@ -0,0 +1,287 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{FOLDERID_NetworkFolder, + 0xD20BEEC4, 0x5CA8, 0x4905, 0xAE, 0x3B, 0xBF, 0x25, 0x1E, 0xA0, 0x9B, 0x53} +DEFINE_GUID!{FOLDERID_ComputerFolder, + 0x0AC0837C, 0xBBF8, 0x452A, 0x85, 0x0D, 0x79, 0xD0, 0x8E, 0x66, 0x7C, 0xA7} +DEFINE_GUID!{FOLDERID_InternetFolder, + 0x4D9F7874, 0x4E0C, 0x4904, 0x96, 0x7B, 0x40, 0xB0, 0xD2, 0x0C, 0x3E, 0x4B} +DEFINE_GUID!{FOLDERID_ControlPanelFolder, + 0x82A74AEB, 0xAEB4, 0x465C, 0xA0, 0x14, 0xD0, 0x97, 0xEE, 0x34, 0x6D, 0x63} +DEFINE_GUID!{FOLDERID_PrintersFolder, + 0x76FC4E2D, 0xD6AD, 0x4519, 0xA6, 0x63, 0x37, 0xBD, 0x56, 0x06, 0x81, 0x85} +DEFINE_GUID!{FOLDERID_SyncManagerFolder, + 0x43668BF8, 0xC14E, 0x49B2, 0x97, 0xC9, 0x74, 0x77, 0x84, 0xD7, 0x84, 0xB7} +DEFINE_GUID!{FOLDERID_SyncSetupFolder, + 0x0f214138, 0xb1d3, 0x4a90, 0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a} +DEFINE_GUID!{FOLDERID_ConflictFolder, + 0x4bfefb45, 0x347d, 0x4006, 0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92} +DEFINE_GUID!{FOLDERID_SyncResultsFolder, + 0x289a9a43, 0xbe44, 0x4057, 0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9} +DEFINE_GUID!{FOLDERID_RecycleBinFolder, + 0xB7534046, 0x3ECB, 0x4C18, 0xBE, 0x4E, 0x64, 0xCD, 0x4C, 0xB7, 0xD6, 0xAC} +DEFINE_GUID!{FOLDERID_ConnectionsFolder, + 0x6F0CD92B, 0x2E97, 0x45D1, 0x88, 0xFF, 0xB0, 0xD1, 0x86, 0xB8, 0xDE, 0xDD} +DEFINE_GUID!{FOLDERID_Fonts, + 0xFD228CB7, 0xAE11, 0x4AE3, 0x86, 0x4C, 0x16, 0xF3, 0x91, 0x0A, 0xB8, 0xFE} +DEFINE_GUID!{FOLDERID_Desktop, + 0xB4BFCC3A, 0xDB2C, 0x424C, 0xB0, 0x29, 0x7F, 0xE9, 0x9A, 0x87, 0xC6, 0x41} +DEFINE_GUID!{FOLDERID_Startup, + 0xB97D20BB, 0xF46A, 0x4C97, 0xBA, 0x10, 0x5E, 0x36, 0x08, 0x43, 0x08, 0x54} +DEFINE_GUID!{FOLDERID_Programs, + 0xA77F5D77, 0x2E2B, 0x44C3, 0xA6, 0xA2, 0xAB, 0xA6, 0x01, 0x05, 0x4A, 0x51} +DEFINE_GUID!{FOLDERID_StartMenu, + 0x625B53C3, 0xAB48, 0x4EC1, 0xBA, 0x1F, 0xA1, 0xEF, 0x41, 0x46, 0xFC, 0x19} +DEFINE_GUID!{FOLDERID_Recent, + 0xAE50C081, 0xEBD2, 0x438A, 0x86, 0x55, 0x8A, 0x09, 0x2E, 0x34, 0x98, 0x7A} +DEFINE_GUID!{FOLDERID_SendTo, + 0x8983036C, 0x27C0, 0x404B, 0x8F, 0x08, 0x10, 0x2D, 0x10, 0xDC, 0xFD, 0x74} +DEFINE_GUID!{FOLDERID_Documents, + 0xFDD39AD0, 0x238F, 0x46AF, 0xAD, 0xB4, 0x6C, 0x85, 0x48, 0x03, 0x69, 0xC7} +DEFINE_GUID!{FOLDERID_Favorites, + 0x1777F761, 0x68AD, 0x4D8A, 0x87, 0xBD, 0x30, 0xB7, 0x59, 0xFA, 0x33, 0xDD} +DEFINE_GUID!{FOLDERID_NetHood, + 0xC5ABBF53, 0xE17F, 0x4121, 0x89, 0x00, 0x86, 0x62, 0x6F, 0xC2, 0xC9, 0x73} +DEFINE_GUID!{FOLDERID_PrintHood, + 0x9274BD8D, 0xCFD1, 0x41C3, 0xB3, 0x5E, 0xB1, 0x3F, 0x55, 0xA7, 0x58, 0xF4} +DEFINE_GUID!{FOLDERID_Templates, + 0xA63293E8, 0x664E, 0x48DB, 0xA0, 0x79, 0xDF, 0x75, 0x9E, 0x05, 0x09, 0xF7} +DEFINE_GUID!{FOLDERID_CommonStartup, + 0x82A5EA35, 0xD9CD, 0x47C5, 0x96, 0x29, 0xE1, 0x5D, 0x2F, 0x71, 0x4E, 0x6E} +DEFINE_GUID!{FOLDERID_CommonPrograms, + 0x0139D44E, 0x6AFE, 0x49F2, 0x86, 0x90, 0x3D, 0xAF, 0xCA, 0xE6, 0xFF, 0xB8} +DEFINE_GUID!{FOLDERID_CommonStartMenu, + 0xA4115719, 0xD62E, 0x491D, 0xAA, 0x7C, 0xE7, 0x4B, 0x8B, 0xE3, 0xB0, 0x67} +DEFINE_GUID!{FOLDERID_PublicDesktop, + 0xC4AA340D, 0xF20F, 0x4863, 0xAF, 0xEF, 0xF8, 0x7E, 0xF2, 0xE6, 0xBA, 0x25} +DEFINE_GUID!{FOLDERID_ProgramData, + 0x62AB5D82, 0xFDC1, 0x4DC3, 0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97} +DEFINE_GUID!{FOLDERID_CommonTemplates, + 0xB94237E7, 0x57AC, 0x4347, 0x91, 0x51, 0xB0, 0x8C, 0x6C, 0x32, 0xD1, 0xF7} +DEFINE_GUID!{FOLDERID_PublicDocuments, + 0xED4824AF, 0xDCE4, 0x45A8, 0x81, 0xE2, 0xFC, 0x79, 0x65, 0x08, 0x36, 0x34} +DEFINE_GUID!{FOLDERID_RoamingAppData, + 0x3EB685DB, 0x65F9, 0x4CF6, 0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D} +DEFINE_GUID!{FOLDERID_LocalAppData, + 0xF1B32785, 0x6FBA, 0x4FCF, 0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91} +DEFINE_GUID!{FOLDERID_LocalAppDataLow, + 0xA520A1A4, 0x1780, 0x4FF6, 0xBD, 0x18, 0x16, 0x73, 0x43, 0xC5, 0xAF, 0x16} +DEFINE_GUID!{FOLDERID_InternetCache, + 0x352481E8, 0x33BE, 0x4251, 0xBA, 0x85, 0x60, 0x07, 0xCA, 0xED, 0xCF, 0x9D} +DEFINE_GUID!{FOLDERID_Cookies, + 0x2B0F765D, 0xC0E9, 0x4171, 0x90, 0x8E, 0x08, 0xA6, 0x11, 0xB8, 0x4F, 0xF6} +DEFINE_GUID!{FOLDERID_History, + 0xD9DC8A3B, 0xB784, 0x432E, 0xA7, 0x81, 0x5A, 0x11, 0x30, 0xA7, 0x59, 0x63} +DEFINE_GUID!{FOLDERID_System, + 0x1AC14E77, 0x02E7, 0x4E5D, 0xB7, 0x44, 0x2E, 0xB1, 0xAE, 0x51, 0x98, 0xB7} +DEFINE_GUID!{FOLDERID_SystemX86, + 0xD65231B0, 0xB2F1, 0x4857, 0xA4, 0xCE, 0xA8, 0xE7, 0xC6, 0xEA, 0x7D, 0x27} +DEFINE_GUID!{FOLDERID_Windows, + 0xF38BF404, 0x1D43, 0x42F2, 0x93, 0x05, 0x67, 0xDE, 0x0B, 0x28, 0xFC, 0x23} +DEFINE_GUID!{FOLDERID_Profile, + 0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73} +DEFINE_GUID!{FOLDERID_Pictures, + 0x33E28130, 0x4E1E, 0x4676, 0x83, 0x5A, 0x98, 0x39, 0x5C, 0x3B, 0xC3, 0xBB} +DEFINE_GUID!{FOLDERID_ProgramFilesX86, + 0x7C5A40EF, 0xA0FB, 0x4BFC, 0x87, 0x4A, 0xC0, 0xF2, 0xE0, 0xB9, 0xFA, 0x8E} +DEFINE_GUID!{FOLDERID_ProgramFilesCommonX86, + 0xDE974D24, 0xD9C6, 0x4D3E, 0xBF, 0x91, 0xF4, 0x45, 0x51, 0x20, 0xB9, 0x17} +DEFINE_GUID!{FOLDERID_ProgramFilesX64, + 0x6d809377, 0x6af0, 0x444b, 0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e} +DEFINE_GUID!{FOLDERID_ProgramFilesCommonX64, + 0x6365d5a7, 0x0f0d, 0x45e5, 0x87, 0xf6, 0x0d, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d} +DEFINE_GUID!{FOLDERID_ProgramFiles, + 0x905e63b6, 0xc1bf, 0x494e, 0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a} +DEFINE_GUID!{FOLDERID_ProgramFilesCommon, + 0xF7F1ED05, 0x9F6D, 0x47A2, 0xAA, 0xAE, 0x29, 0xD3, 0x17, 0xC6, 0xF0, 0x66} +DEFINE_GUID!{FOLDERID_UserProgramFiles, + 0x5cd7aee2, 0x2219, 0x4a67, 0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb} +DEFINE_GUID!{FOLDERID_UserProgramFilesCommon, + 0xbcbd3057, 0xca5c, 0x4622, 0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16} +DEFINE_GUID!{FOLDERID_AdminTools, + 0x724EF170, 0xA42D, 0x4FEF, 0x9F, 0x26, 0xB6, 0x0E, 0x84, 0x6F, 0xBA, 0x4F} +DEFINE_GUID!{FOLDERID_CommonAdminTools, + 0xD0384E7D, 0xBAC3, 0x4797, 0x8F, 0x14, 0xCB, 0xA2, 0x29, 0xB3, 0x92, 0xB5} +DEFINE_GUID!{FOLDERID_Music, + 0x4BD8D571, 0x6D19, 0x48D3, 0xBE, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0E, 0x43} +DEFINE_GUID!{FOLDERID_Videos, + 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0x7C, 0x74, 0xE4, 0xDD, 0xFC} +DEFINE_GUID!{FOLDERID_Ringtones, + 0xC870044B, 0xF49E, 0x4126, 0xA9, 0xC3, 0xB5, 0x2A, 0x1F, 0xF4, 0x11, 0xE8} +DEFINE_GUID!{FOLDERID_PublicPictures, + 0xB6EBFB86, 0x6907, 0x413C, 0x9A, 0xF7, 0x4F, 0xC2, 0xAB, 0xF0, 0x7C, 0xC5} +DEFINE_GUID!{FOLDERID_PublicMusic, + 0x3214FAB5, 0x9757, 0x4298, 0xBB, 0x61, 0x92, 0xA9, 0xDE, 0xAA, 0x44, 0xFF} +DEFINE_GUID!{FOLDERID_PublicVideos, + 0x2400183A, 0x6185, 0x49FB, 0xA2, 0xD8, 0x4A, 0x39, 0x2A, 0x60, 0x2B, 0xA3} +DEFINE_GUID!{FOLDERID_PublicRingtones, + 0xE555AB60, 0x153B, 0x4D17, 0x9F, 0x04, 0xA5, 0xFE, 0x99, 0xFC, 0x15, 0xEC} +DEFINE_GUID!{FOLDERID_ResourceDir, + 0x8AD10C31, 0x2ADB, 0x4296, 0xA8, 0xF7, 0xE4, 0x70, 0x12, 0x32, 0xC9, 0x72} +DEFINE_GUID!{FOLDERID_LocalizedResourcesDir, + 0x2A00375E, 0x224C, 0x49DE, 0xB8, 0xD1, 0x44, 0x0D, 0xF7, 0xEF, 0x3D, 0xDC} +DEFINE_GUID!{FOLDERID_CommonOEMLinks, + 0xC1BAE2D0, 0x10DF, 0x4334, 0xBE, 0xDD, 0x7A, 0xA2, 0x0B, 0x22, 0x7A, 0x9D} +DEFINE_GUID!{FOLDERID_CDBurning, + 0x9E52AB10, 0xF80D, 0x49DF, 0xAC, 0xB8, 0x43, 0x30, 0xF5, 0x68, 0x78, 0x55} +DEFINE_GUID!{FOLDERID_UserProfiles, + 0x0762D272, 0xC50A, 0x4BB0, 0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80} +DEFINE_GUID!{FOLDERID_Playlists, + 0xDE92C1C7, 0x837F, 0x4F69, 0xA3, 0xBB, 0x86, 0xE6, 0x31, 0x20, 0x4A, 0x23} +DEFINE_GUID!{FOLDERID_SamplePlaylists, + 0x15CA69B3, 0x30EE, 0x49C1, 0xAC, 0xE1, 0x6B, 0x5E, 0xC3, 0x72, 0xAF, 0xB5} +DEFINE_GUID!{FOLDERID_SampleMusic, + 0xB250C668, 0xF57D, 0x4EE1, 0xA6, 0x3C, 0x29, 0x0E, 0xE7, 0xD1, 0xAA, 0x1F} +DEFINE_GUID!{FOLDERID_SamplePictures, + 0xC4900540, 0x2379, 0x4C75, 0x84, 0x4B, 0x64, 0xE6, 0xFA, 0xF8, 0x71, 0x6B} +DEFINE_GUID!{FOLDERID_SampleVideos, + 0x859EAD94, 0x2E85, 0x48AD, 0xA7, 0x1A, 0x09, 0x69, 0xCB, 0x56, 0xA6, 0xCD} +DEFINE_GUID!{FOLDERID_PhotoAlbums, + 0x69D2CF90, 0xFC33, 0x4FB7, 0x9A, 0x0C, 0xEB, 0xB0, 0xF0, 0xFC, 0xB4, 0x3C} +DEFINE_GUID!{FOLDERID_Public, + 0xDFDF76A2, 0xC82A, 0x4D63, 0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85} +DEFINE_GUID!{FOLDERID_ChangeRemovePrograms, + 0xdf7266ac, 0x9274, 0x4867, 0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d} +DEFINE_GUID!{FOLDERID_AppUpdates, + 0xa305ce99, 0xf527, 0x492b, 0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4} +DEFINE_GUID!{FOLDERID_AddNewPrograms, + 0xde61d971, 0x5ebc, 0x4f02, 0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04} +DEFINE_GUID!{FOLDERID_Downloads, + 0x374de290, 0x123f, 0x4565, 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b} +DEFINE_GUID!{FOLDERID_PublicDownloads, + 0x3d644c9b, 0x1fb8, 0x4f30, 0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0} +DEFINE_GUID!{FOLDERID_SavedSearches, + 0x7d1d3a04, 0xdebb, 0x4115, 0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda} +DEFINE_GUID!{FOLDERID_QuickLaunch, + 0x52a4f021, 0x7b75, 0x48a9, 0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f} +DEFINE_GUID!{FOLDERID_Contacts, + 0x56784854, 0xc6cb, 0x462b, 0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82} +DEFINE_GUID!{FOLDERID_SidebarParts, + 0xa75d362e, 0x50fc, 0x4fb7, 0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93} +DEFINE_GUID!{FOLDERID_SidebarDefaultParts, + 0x7b396e54, 0x9ec5, 0x4300, 0xbe, 0x0a, 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26} +DEFINE_GUID!{FOLDERID_PublicGameTasks, + 0xdebf2536, 0xe1a8, 0x4c59, 0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea} +DEFINE_GUID!{FOLDERID_GameTasks, + 0x054fae61, 0x4dd8, 0x4787, 0x80, 0xb6, 0x09, 0x02, 0x20, 0xc4, 0xb7, 0x0} +DEFINE_GUID!{FOLDERID_SavedGames, + 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4} +DEFINE_GUID!{FOLDERID_Games, + 0xcac52c1a, 0xb53d, 0x4edc, 0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34} +DEFINE_GUID!{FOLDERID_SEARCH_MAPI, + 0x98ec0e18, 0x2098, 0x4d44, 0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81} +DEFINE_GUID!{FOLDERID_SEARCH_CSC, + 0xee32e446, 0x31ca, 0x4aba, 0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e} +DEFINE_GUID!{FOLDERID_Links, + 0xbfb9d5e0, 0xc6a9, 0x404c, 0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68} +DEFINE_GUID!{FOLDERID_UsersFiles, + 0xf3ce0f7c, 0x4901, 0x4acc, 0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f} +DEFINE_GUID!{FOLDERID_UsersLibraries, + 0xa302545d, 0xdeff, 0x464b, 0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b} +DEFINE_GUID!{FOLDERID_SearchHome, + 0x190337d1, 0xb8ca, 0x4121, 0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a} +DEFINE_GUID!{FOLDERID_OriginalImages, + 0x2C36C0AA, 0x5812, 0x4b87, 0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39} +DEFINE_GUID!{FOLDERID_DocumentsLibrary, + 0x7b0db17d, 0x9cd2, 0x4a93, 0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c} +DEFINE_GUID!{FOLDERID_MusicLibrary, + 0x2112ab0a, 0xc86a, 0x4ffe, 0xa3, 0x68, 0x0d, 0xe9, 0x6e, 0x47, 0x01, 0x2e} +DEFINE_GUID!{FOLDERID_PicturesLibrary, + 0xa990ae9f, 0xa03b, 0x4e80, 0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x4} +DEFINE_GUID!{FOLDERID_VideosLibrary, + 0x491e922f, 0x5643, 0x4af4, 0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74} +DEFINE_GUID!{FOLDERID_RecordedTVLibrary, + 0x1a6fdba2, 0xf42d, 0x4358, 0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5} +DEFINE_GUID!{FOLDERID_HomeGroup, + 0x52528a6b, 0xb9e3, 0x4add, 0xb6, 0x0d, 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d} +DEFINE_GUID!{FOLDERID_HomeGroupCurrentUser, + 0x9b74b6a3, 0x0dfd, 0x4f11, 0x9e, 0x78, 0x5f, 0x78, 0x00, 0xf2, 0xe7, 0x72} +DEFINE_GUID!{FOLDERID_DeviceMetadataStore, + 0x5ce4a5e9, 0xe4eb, 0x479d, 0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55} +DEFINE_GUID!{FOLDERID_Libraries, + 0x1b3ea5dc, 0xb587, 0x4786, 0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae} +DEFINE_GUID!{FOLDERID_PublicLibraries, + 0x48daf80b, 0xe6cf, 0x4f4e, 0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84} +DEFINE_GUID!{FOLDERID_UserPinned, + 0x9e3995ab, 0x1f9c, 0x4f13, 0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74} +DEFINE_GUID!{FOLDERID_ImplicitAppShortcuts, + 0xbcb5256f, 0x79f6, 0x4cee, 0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x02, 0xfd, 0x46} +DEFINE_GUID!{FOLDERID_AccountPictures, + 0x008ca0b1, 0x55b4, 0x4c56, 0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe} +DEFINE_GUID!{FOLDERID_PublicUserTiles, + 0x0482af6c, 0x08f1, 0x4c34, 0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17} +DEFINE_GUID!{FOLDERID_AppsFolder, + 0x1e87508d, 0x89c2, 0x42f0, 0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58} +DEFINE_GUID!{FOLDERID_StartMenuAllPrograms, + 0xf26305ef, 0x6948, 0x40b9, 0xb2, 0x55, 0x81, 0x45, 0x3d, 0x09, 0xc7, 0x85} +DEFINE_GUID!{FOLDERID_CommonStartMenuPlaces, + 0xa440879f, 0x87a0, 0x4f7d, 0xb7, 0x00, 0x02, 0x07, 0xb9, 0x66, 0x19, 0x4a} +DEFINE_GUID!{FOLDERID_ApplicationShortcuts, + 0xa3918781, 0xe5f2, 0x4890, 0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c} +DEFINE_GUID!{FOLDERID_RoamingTiles, + 0x00bcfc5a, 0xed94, 0x4e48, 0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90} +DEFINE_GUID!{FOLDERID_RoamedTileImages, + 0xaaa8d5a5, 0xf1d6, 0x4259, 0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e} +DEFINE_GUID!{FOLDERID_Screenshots, + 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f} +DEFINE_GUID!{FOLDERID_CameraRoll, + 0xab5fb87b, 0x7ce2, 0x4f83, 0x91, 0x5d, 0x55, 0x08, 0x46, 0xc9, 0x53, 0x7b} +DEFINE_GUID!{FOLDERID_SkyDrive, + 0xa52bba46, 0xe9e1, 0x435f, 0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6} +DEFINE_GUID!{FOLDERID_OneDrive, + 0xa52bba46, 0xe9e1, 0x435f, 0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6} +DEFINE_GUID!{FOLDERID_SkyDriveDocuments, + 0x24d89e24, 0x2f19, 0x4534, 0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe} +DEFINE_GUID!{FOLDERID_SkyDrivePictures, + 0x339719b5, 0x8c47, 0x4894, 0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6} +DEFINE_GUID!{FOLDERID_SkyDriveMusic, + 0xc3f2459e, 0x80d6, 0x45dc, 0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30} +DEFINE_GUID!{FOLDERID_SkyDriveCameraRoll, + 0x767e6811, 0x49cb, 0x4273, 0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b} +DEFINE_GUID!{FOLDERID_SearchHistory, + 0x0d4c3db6, 0x03a3, 0x462f, 0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4} +DEFINE_GUID!{FOLDERID_SearchTemplates, + 0x7e636bfe, 0xdfa9, 0x4d5e, 0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9} +DEFINE_GUID!{FOLDERID_CameraRollLibrary, + 0x2b20df75, 0x1eda, 0x4039, 0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7} +DEFINE_GUID!{FOLDERID_SavedPictures, + 0x3b193882, 0xd3ad, 0x4eab, 0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f} +DEFINE_GUID!{FOLDERID_SavedPicturesLibrary, + 0xe25b5812, 0xbe88, 0x4bd9, 0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3} +DEFINE_GUID!{FOLDERID_RetailDemo, + 0x12d4c69e, 0x24ad, 0x4923, 0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67} +DEFINE_GUID!{FOLDERID_Device, + 0x1C2AC1DC, 0x4358, 0x4B6C, 0x97, 0x33, 0xAF, 0x21, 0x15, 0x65, 0x76, 0xF0} +DEFINE_GUID!{FOLDERID_DevelopmentFiles, + 0xdbe8e08e, 0x3053, 0x4bbc, 0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59} +DEFINE_GUID!{FOLDERID_Objects3D, + 0x31c0dd25, 0x9439, 0x4f12, 0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22} +DEFINE_GUID!{FOLDERID_AppCaptures, + 0xedc0fe71, 0x98d8, 0x4f4a, 0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65} +DEFINE_GUID!{FOLDERID_LocalDocuments, + 0xf42ee2d3, 0x909f, 0x4907, 0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56} +DEFINE_GUID!{FOLDERID_LocalPictures, + 0x0ddd015d, 0xb06c, 0x45d5, 0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39} +DEFINE_GUID!{FOLDERID_LocalVideos, + 0x35286a68, 0x3c57, 0x41a1, 0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95} +DEFINE_GUID!{FOLDERID_LocalMusic, + 0xa0c69a99, 0x21c8, 0x4671, 0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d} +DEFINE_GUID!{FOLDERID_LocalDownloads, + 0x7d83ee9b, 0x2244, 0x4e70, 0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4} +DEFINE_GUID!{FOLDERID_RecordedCalls, + 0x2f8b40c2, 0x83ed, 0x48ee, 0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a} +DEFINE_GUID!{FOLDERID_AllAppMods, + 0x7ad67899, 0x66af, 0x43ba, 0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96} +DEFINE_GUID!{FOLDERID_CurrentAppMods, + 0x3db40b20, 0x2a30, 0x4dbe, 0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99} +DEFINE_GUID!{FOLDERID_AppDataDesktop, + 0xb2c5e279, 0x7add, 0x439f, 0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72} +DEFINE_GUID!{FOLDERID_AppDataDocuments, + 0x7be16610, 0x1f7f, 0x44ac, 0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1} +DEFINE_GUID!{FOLDERID_AppDataFavorites, + 0x7cfbefbc, 0xde1f, 0x45aa, 0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9} +DEFINE_GUID!{FOLDERID_AppDataProgramData, + 0x559d40a3, 0xa036, 0x40fa, 0xaf, 0x61, 0x84, 0xcb, 0x43, 0x0a, 0x4d, 0x34} diff --git a/winapi/src/um/ktmw32.rs b/winapi/src/um/ktmw32.rs new file mode 100644 index 000000000..c1b882247 --- /dev/null +++ b/winapi/src/um/ktmw32.rs @@ -0,0 +1,63 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! FFI bindings to ktmw32. +use shared::guiddef::LPGUID; +use shared::minwindef::{BOOL, DWORD}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::winnt::{HANDLE, LPWSTR}; +extern "system" { + pub fn CreateTransaction( + lpTransactionAttributes: LPSECURITY_ATTRIBUTES, + UOW: LPGUID, + CreateOptions: DWORD, + IsolationLevel: DWORD, + IsolationFlags: DWORD, + Timeout: DWORD, + Description: LPWSTR, + ) -> HANDLE; + // pub fn OpenTransaction(); + pub fn CommitTransaction( + TransactionHandle: HANDLE, + ) -> BOOL; + // pub fn CommitTransactionAsync(); + pub fn RollbackTransaction( + TransactionHandle: HANDLE, + ) -> BOOL; + // pub fn RollbackTransactionAsync(); + // pub fn GetTransactionId(); + // pub fn GetTransactionInformation(); + // pub fn SetTransactionInformation(); + // pub fn CreateTransactionManager(); + // pub fn OpenTransactionManager(); + // pub fn OpenTransactionManagerById(); + // pub fn RenameTransactionManager(); + // pub fn RollforwardTransactionManager(); + // pub fn RecoverTransactionManager(); + // pub fn GetCurrentClockTransactionManager(); + // pub fn GetTransactionManagerId(); + // pub fn CreateResourceManager(); + // pub fn OpenResourceManager(); + // pub fn RecoverResourceManager(); + // pub fn GetNotificationResourceManager(); + // pub fn GetNotificationResourceManagerAsync(); + // pub fn SetResourceManagerCompletionPort(); + // pub fn CreateEnlistment(); + // pub fn OpenEnlistment(); + // pub fn RecoverEnlistment(); + // pub fn GetEnlistmentRecoveryInformation(); + // pub fn GetEnlistmentId(); + // pub fn SetEnlistmentRecoveryInformation(); + // pub fn PrepareEnlistment(); + // pub fn PrePrepareEnlistment(); + // pub fn CommitEnlistment(); + // pub fn RollbackEnlistment(); + // pub fn PrePrepareComplete(); + // pub fn PrepareComplete(); + // pub fn ReadOnlyEnlistment(); + // pub fn CommitComplete(); + // pub fn RollbackComplete(); + // pub fn SinglePhaseReject(); +} diff --git a/winapi/src/um/libloaderapi.rs b/winapi/src/um/libloaderapi.rs new file mode 100644 index 000000000..05e3017d2 --- /dev/null +++ b/winapi/src/um/libloaderapi.rs @@ -0,0 +1,236 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-libraryloader-l1 +use ctypes::c_int; +use shared::basetsd::LONG_PTR; +use shared::minwindef::{ + BOOL, DWORD, FARPROC, HGLOBAL, HINSTANCE, HMODULE, HRSRC, LPVOID, UINT, WORD +}; +use um::winnt::{HANDLE, LANGID, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCWSTR, PVOID}; +pub const GET_MODULE_HANDLE_EX_FLAG_PIN: DWORD = 0x00000001; +pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: DWORD = 0x00000002; +pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: DWORD = 0x00000004; +pub const DONT_RESOLVE_DLL_REFERENCES: DWORD = 0x00000001; +pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = 0x00000002; +pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = 0x00000008; +pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = 0x00000010; +pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = 0x00000020; +pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = 0x00000040; +pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = 0x00000080; +pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = 0x00000100; +pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = 0x00000200; +pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = 0x00000400; +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = 0x00000800; +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = 0x00001000; +pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = 0x00002000; +pub const LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER: DWORD = 0x00004000; +pub const LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY: DWORD = 0x00008000; +FN!{stdcall ENUMRESLANGPROCA( + hModule: HMODULE, + lpType: LPCSTR, + lpName: LPCSTR, + wLanguage: WORD, + lParam: LONG_PTR, +) -> BOOL} +FN!{stdcall ENUMRESLANGPROCW( + hModule: HMODULE, + lpType: LPCWSTR, + lpName: LPCWSTR, + wLanguage: WORD, + lParam: LONG_PTR, +) -> BOOL} +FN!{stdcall ENUMRESNAMEPROCA( + hModule: HMODULE, + lpType: LPCSTR, + lpName: LPSTR, + lParam: LONG_PTR, +) -> BOOL} +FN!{stdcall ENUMRESNAMEPROCW( + hModule: HMODULE, + lpType: LPCWSTR, + lpName: LPWSTR, + lParam: LONG_PTR, +) -> BOOL} +FN!{stdcall ENUMRESTYPEPROCA( + hModule: HMODULE, + lpType: LPSTR, + lParam: LONG_PTR, +) -> BOOL} +FN!{stdcall ENUMRESTYPEPROCW( + hModule: HMODULE, + lpType: LPWSTR, + lParam: LONG_PTR, +) -> BOOL} +extern "system" { + pub fn DisableThreadLibraryCalls( + hLibModule: HMODULE, + ) -> BOOL; + pub fn FindResourceExW( + hModule: HMODULE, + lpName: LPCWSTR, + lpType: LPCWSTR, + wLanguage: WORD, + ) -> HRSRC; + pub fn FindStringOrdinal( + dwFindStringOrdinalFlags: DWORD, + lpStringSource: LPCWSTR, + cchSource: c_int, + lpStringValue: LPCWSTR, + cchValue: c_int, + bIgnoreCase: BOOL, + ) -> c_int; + pub fn FreeLibrary( + hLibModule: HMODULE, + ) -> BOOL; + pub fn FreeLibraryAndExitThread( + hLibModule: HMODULE, + dwExitCode: DWORD, + ); + pub fn FreeResource( + hResData: HGLOBAL, + ) -> BOOL; + pub fn GetModuleFileNameA( + hModule: HMODULE, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleFileNameW( + hModule: HMODULE, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleHandleA( + lpModuleName: LPCSTR, + ) -> HMODULE; + pub fn GetModuleHandleW( + lpModuleName: LPCWSTR, + ) -> HMODULE; + pub fn GetModuleHandleExA( + dwFlags: DWORD, + lpModuleName: LPCSTR, + phModule: *mut HMODULE, + ) -> BOOL; + pub fn GetModuleHandleExW( + dwFlags: DWORD, + lpModuleName: LPCWSTR, + phModule: *mut HMODULE, + ) -> BOOL; + pub fn GetProcAddress( + hModule: HMODULE, + lpProcName: LPCSTR, + ) -> FARPROC; + pub fn LoadLibraryExA( + lpLibFileName: LPCSTR, + hFile: HANDLE, + dwFlags: DWORD, + ) -> HMODULE; + pub fn LoadLibraryExW( + lpLibFileName: LPCWSTR, + hFile: HANDLE, + dwFlags: DWORD, + ) -> HMODULE; + pub fn LoadResource( + hModule: HMODULE, + hResInfo: HRSRC, + ) -> HGLOBAL; + pub fn LoadStringA( + hInstance: HINSTANCE, + uID: UINT, + lpBuffer: LPSTR, + cchBufferMax: c_int, + ) -> c_int; + pub fn LoadStringW( + hInstance: HINSTANCE, + uID: UINT, + lpBuffer: LPWSTR, + cchBufferMax: c_int, + ) -> c_int; + pub fn LockResource( + hResData: HGLOBAL, + ) -> LPVOID; + pub fn SizeofResource( + hModule: HMODULE, + hResInfo: HRSRC, + ) -> DWORD; +} +pub type DLL_DIRECTORY_COOKIE = PVOID; +pub type PDLL_DIRECTORY_COOKIE = *mut PVOID; +extern "system" { + pub fn AddDllDirectory( + NewDirectory: PCWSTR, + ) -> DLL_DIRECTORY_COOKIE; + pub fn RemoveDllDirectory( + Cookie: DLL_DIRECTORY_COOKIE, + ) -> BOOL; + pub fn SetDefaultDllDirectories( + DirectoryFlags: DWORD, + ) -> BOOL; + pub fn EnumResourceLanguagesExA( + hModule: HMODULE, + lpType: LPCSTR, + lpName: LPCSTR, + lpEnumFunc: ENUMRESLANGPROCA, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn EnumResourceLanguagesExW( + hModule: HMODULE, + lpType: LPCWSTR, + lpName: LPCWSTR, + lpEnumFunc: ENUMRESLANGPROCW, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn EnumResourceNamesExA( + hModule: HMODULE, + lpType: LPCSTR, + lpEnumFunc: ENUMRESNAMEPROCA, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn EnumResourceNamesExW( + hModule: HMODULE, + lpType: LPCWSTR, + lpEnumFunc: ENUMRESNAMEPROCW, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn EnumResourceTypesExA( + hModule: HMODULE, + lpEnumFunc: ENUMRESTYPEPROCA, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn EnumResourceTypesExW( + hModule: HMODULE, + lpEnumFunc: ENUMRESTYPEPROCW, + lParam: LONG_PTR, + dwFlags: DWORD, + LangId: LANGID, + ) -> BOOL; + pub fn FindResourceW( + hModule: HMODULE, + lpName: LPCWSTR, + lpType: LPCWSTR, + ) -> HRSRC; + pub fn LoadLibraryA( + lpFileName: LPCSTR, + ) -> HMODULE; + pub fn LoadLibraryW( + lpFileName: LPCWSTR, + ) -> HMODULE; + pub fn EnumResourceNamesW( + hModule: HMODULE, + lpType: LPCWSTR, + lpEnumFunc: ENUMRESNAMEPROCW, + lParam: LONG_PTR, + ) -> BOOL; +} diff --git a/winapi/src/um/lmaccess.rs b/winapi/src/um/lmaccess.rs new file mode 100644 index 000000000..3c6c430cb --- /dev/null +++ b/winapi/src/um/lmaccess.rs @@ -0,0 +1,1214 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +// This file contains structures, function prototypes, and definitions +// for the NetUser, NetUserModals, NetGroup, NetAccess, and NetLogon API. +use shared::basetsd::PDWORD_PTR; +use shared::lmcons::{ENCRYPTED_PWLEN, NET_API_STATUS, PARMNUM_BASE_INFOLEVEL, PWLEN}; +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, LPBYTE, LPDWORD, LPVOID, PBYTE, ULONG}; +use um::winnt::{BOOLEAN, LONG, LPCWSTR, LPWSTR, PSID, PVOID, PZPWSTR, SID_NAME_USE}; +extern "system" { + pub fn NetUserAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserEnum( + servername: LPCWSTR, + level: DWORD, + filter: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserGetInfo( + servername: LPCWSTR, + username: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetUserSetInfo( + servername: LPCWSTR, + username: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserDel( + servername: LPCWSTR, + username: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetUserGetGroups( + servername: LPCWSTR, + username: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserSetGroups( + servername: LPCWSTR, + username: LPCWSTR, + level: DWORD, + buf: LPBYTE, + num_entries: DWORD, + ) -> NET_API_STATUS; + pub fn NetUserGetLocalGroups( + servername: LPCWSTR, + level: DWORD, + flags: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserModalsGet( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetUserModalsSet( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUserChangePassword( + domainname: LPCWSTR, + username: LPCWSTR, + oldpassword: LPCWSTR, + newpassword: LPCWSTR, + ) -> NET_API_STATUS; +} +STRUCT!{struct USER_INFO_0 { + usri0_name: LPWSTR, +}} +pub type PUSER_INFO_0 = *mut USER_INFO_0; +pub type LPUSER_INFO_0 = *mut USER_INFO_0; +STRUCT!{struct USER_INFO_1 { + usri1_name: LPWSTR, + usri1_password: LPWSTR, + usri1_password_age: DWORD, + usri1_priv: DWORD, + usri1_home_dir: LPWSTR, + usri1_comment: LPWSTR, + usri1_flags: DWORD, + usri1_script_path: LPWSTR, +}} +pub type PUSER_INFO_1 = *mut USER_INFO_1; +pub type LPUSER_INFO_1 = *mut USER_INFO_1; +STRUCT!{struct USER_INFO_2 { + usri2_name: LPWSTR, + usri2_password: LPWSTR, + usri2_password_age: DWORD, + usri2_priv: DWORD, + usri2_home_dir: LPWSTR, + usri2_comment: LPWSTR, + usri2_flags: DWORD, + usri2_script_path: LPWSTR, + usri2_auth_flags: DWORD, + usri2_full_name: LPWSTR, + usri2_usr_comment: LPWSTR, + usri2_parms: LPWSTR, + usri2_workstations: LPWSTR, + usri2_last_logon: DWORD, + usri2_last_logoff: DWORD, + usri2_acct_expires: DWORD, + usri2_max_storage: DWORD, + usri2_units_per_week: DWORD, + usri2_logon_hours: PBYTE, + usri2_bad_pw_count: DWORD, + usri2_num_logons: DWORD, + usri2_logon_server: LPWSTR, + usri2_country_code: DWORD, + usri2_code_page: DWORD, +}} +pub type PUSER_INFO_2 = *mut USER_INFO_2; +pub type LPUSER_INFO_2 = *mut USER_INFO_2; +STRUCT!{struct USER_INFO_3 { + usri3_name: LPWSTR, + usri3_password: LPWSTR, + usri3_password_age: DWORD, + usri3_priv: DWORD, + usri3_home_dir: LPWSTR, + usri3_comment: LPWSTR, + usri3_flags: DWORD, + usri3_script_path: LPWSTR, + usri3_auth_flags: DWORD, + usri3_full_name: LPWSTR, + usri3_usr_comment: LPWSTR, + usri3_parms: LPWSTR, + usri3_workstations: LPWSTR, + usri3_last_logon: DWORD, + usri3_last_logoff: DWORD, + usri3_acct_expires: DWORD, + usri3_max_storage: DWORD, + usri3_units_per_week: DWORD, + usri3_logon_hours: PBYTE, + usri3_bad_pw_count: DWORD, + usri3_num_logons: DWORD, + usri3_logon_server: LPWSTR, + usri3_country_code: DWORD, + usri3_code_page: DWORD, + usri3_user_id: DWORD, + usri3_primary_group_id: DWORD, + usri3_profile: LPWSTR, + usri3_home_dir_drive: LPWSTR, + usri3_password_expired: DWORD, +}} +pub type PUSER_INFO_3 = *mut USER_INFO_3; +pub type LPUSER_INFO_3 = *mut USER_INFO_3; +STRUCT!{struct USER_INFO_4 { + usri4_name: LPWSTR, + usri4_password: LPWSTR, + usri4_password_age: DWORD, + usri4_priv: DWORD, + usri4_home_dir: LPWSTR, + usri4_comment: LPWSTR, + usri4_flags: DWORD, + usri4_script_path: LPWSTR, + usri4_auth_flags: DWORD, + usri4_full_name: LPWSTR, + usri4_usr_comment: LPWSTR, + usri4_parms: LPWSTR, + usri4_workstations: LPWSTR, + usri4_last_logon: DWORD, + usri4_last_logoff: DWORD, + usri4_acct_expires: DWORD, + usri4_max_storage: DWORD, + usri4_units_per_week: DWORD, + usri4_logon_hours: PBYTE, + usri4_bad_pw_count: DWORD, + usri4_num_logons: DWORD, + usri4_logon_server: LPWSTR, + usri4_country_code: DWORD, + usri4_code_page: DWORD, + usri4_user_sid: PSID, + usri4_primary_group_id: DWORD, + usri4_profile: LPWSTR, + usri4_home_dir_drive: LPWSTR, + usri4_password_expired: DWORD, +}} +pub type PUSER_INFO_4 = *mut USER_INFO_4; +pub type LPUSER_INFO_4 = *mut USER_INFO_4; +STRUCT!{struct USER_INFO_10 { + usri10_name: LPWSTR, + usri10_comment: LPWSTR, + usri10_usr_comment: LPWSTR, + usri10_full_name: LPWSTR, +}} +pub type PUSER_INFO_10 = *mut USER_INFO_10; +pub type LPUSER_INFO_10 = *mut USER_INFO_10; +STRUCT!{struct USER_INFO_11 { + usri11_name: LPWSTR, + usri11_comment: LPWSTR, + usri11_usr_comment: LPWSTR, + usri11_full_name: LPWSTR, + usri11_priv: DWORD, + usri11_auth_flags: DWORD, + usri11_password_age: DWORD, + usri11_home_dir: LPWSTR, + usri11_parms: LPWSTR, + usri11_last_logon: DWORD, + usri11_last_logoff: DWORD, + usri11_bad_pw_count: DWORD, + usri11_num_logons: DWORD, + usri11_logon_server: LPWSTR, + usri11_country_code: DWORD, + usri11_workstations: LPWSTR, + usri11_max_storage: DWORD, + usri11_units_per_week: DWORD, + usri11_logon_hours: PBYTE, + usri11_code_page: DWORD, +}} +pub type PUSER_INFO_11 = *mut USER_INFO_11; +pub type LPUSER_INFO_11 = *mut USER_INFO_11; +STRUCT!{struct USER_INFO_20 { + usri20_name: LPWSTR, + usri20_full_name: LPWSTR, + usri20_comment: LPWSTR, + usri20_flags: DWORD, + usri20_user_id: DWORD, +}} +pub type PUSER_INFO_20 = *mut USER_INFO_20; +pub type LPUSER_INFO_20 = *mut USER_INFO_20; +STRUCT!{struct USER_INFO_21 { + usri21_password: [BYTE; ENCRYPTED_PWLEN], +}} +pub type PUSER_INFO_21 = *mut USER_INFO_21; +pub type LPUSER_INFO_21 = *mut USER_INFO_21; +STRUCT!{struct USER_INFO_22 { + usri22_name: LPWSTR, + usri22_password: [BYTE; ENCRYPTED_PWLEN], + usri22_password_age: DWORD, + usri22_priv: DWORD, + usri22_home_dir: LPWSTR, + usri22_comment: LPWSTR, + usri22_flags: DWORD, + usri22_script_path: LPWSTR, + usri22_auth_flags: DWORD, + usri22_full_name: LPWSTR, + usri22_usr_comment: LPWSTR, + usri22_parms: LPWSTR, + usri22_workstations: LPWSTR, + usri22_last_logon: DWORD, + usri22_last_logoff: DWORD, + usri22_acct_expires: DWORD, + usri22_max_storage: DWORD, + usri22_units_per_week: DWORD, + usri22_logon_hours: PBYTE, + usri22_bad_pw_count: DWORD, + usri22_num_logons: DWORD, + usri22_logon_server: LPWSTR, + usri22_country_code: DWORD, + usri22_code_page: DWORD, +}} +pub type PUSER_INFO_22 = *mut USER_INFO_22; +pub type LPUSER_INFO_22 = *mut USER_INFO_22; +STRUCT!{struct USER_INFO_23 { + usri23_name: LPWSTR, + usri23_full_name: LPWSTR, + usri23_comment: LPWSTR, + usri23_flags: DWORD, + usri23_user_sid: PSID, +}} +pub type PUSER_INFO_23 = *mut USER_INFO_23; +pub type LPUSER_INFO_23 = *mut USER_INFO_23; +STRUCT!{struct USER_INFO_24 { + usri24_internet_identity: BOOL, + usri24_flags: DWORD, + usri24_internet_provider_name: LPWSTR, + usri24_internet_principal_name: LPWSTR, + usri24_user_sid: PSID, +}} +pub type PUSER_INFO_24 = *mut USER_INFO_24; +pub type LPUSER_INFO_24 = *mut USER_INFO_24; +STRUCT!{struct USER_INFO_1003 { + usri1003_password: LPWSTR, +}} +pub type PUSER_INFO_1003 = *mut USER_INFO_1003; +pub type LPUSER_INFO_1003 = *mut USER_INFO_1003; +STRUCT!{struct USER_INFO_1005 { + usri1005_priv: DWORD, +}} +pub type PUSER_INFO_1005 = *mut USER_INFO_1005; +pub type LPUSER_INFO_1005 = *mut USER_INFO_1005; +STRUCT!{struct USER_INFO_1006 { + usri1006_home_dir: LPWSTR, +}} +pub type PUSER_INFO_1006 = *mut USER_INFO_1006; +pub type LPUSER_INFO_1006 = *mut USER_INFO_1006; +STRUCT!{struct USER_INFO_1007 { + usri1007_comment: LPWSTR, +}} +pub type PUSER_INFO_1007 = *mut USER_INFO_1007; +pub type LPUSER_INFO_1007 = *mut USER_INFO_1007; +STRUCT!{struct USER_INFO_1008 { + usri1008_flags: DWORD, +}} +pub type PUSER_INFO_1008 = *mut USER_INFO_1008; +pub type LPUSER_INFO_1008 = *mut USER_INFO_1008; +STRUCT!{struct USER_INFO_1009 { + usri1009_script_path: LPWSTR, +}} +pub type PUSER_INFO_1009 = *mut USER_INFO_1009; +pub type LPUSER_INFO_1009 = *mut USER_INFO_1009; +STRUCT!{struct USER_INFO_1010 { + usri1010_auth_flags: DWORD, +}} +pub type PUSER_INFO_1010 = *mut USER_INFO_1010; +pub type LPUSER_INFO_1010 = *mut USER_INFO_1010; +STRUCT!{struct USER_INFO_1011 { + usri1011_full_name: LPWSTR, +}} +pub type PUSER_INFO_1011 = *mut USER_INFO_1011; +pub type LPUSER_INFO_1011 = *mut USER_INFO_1011; +STRUCT!{struct USER_INFO_1012 { + usri1012_usr_comment: LPWSTR, +}} +pub type PUSER_INFO_1012 = *mut USER_INFO_1012; +pub type LPUSER_INFO_1012 = *mut USER_INFO_1012; +STRUCT!{struct USER_INFO_1013 { + usri1013_parms: LPWSTR, +}} +pub type PUSER_INFO_1013 = *mut USER_INFO_1013; +pub type LPUSER_INFO_1013 = *mut USER_INFO_1013; +STRUCT!{struct USER_INFO_1014 { + usri1014_workstations: LPWSTR, +}} +pub type PUSER_INFO_1014 = *mut USER_INFO_1014; +pub type LPUSER_INFO_1014 = *mut USER_INFO_1014; +STRUCT!{struct USER_INFO_1017 { + usri1017_acct_expires: DWORD, +}} +pub type PUSER_INFO_1017 = *mut USER_INFO_1017; +pub type LPUSER_INFO_1017 = *mut USER_INFO_1017; +STRUCT!{struct USER_INFO_1018 { + usri1018_max_storage: DWORD, +}} +pub type PUSER_INFO_1018 = *mut USER_INFO_1018; +pub type LPUSER_INFO_1018 = *mut USER_INFO_1018; +STRUCT!{struct USER_INFO_1020 { + usri1020_units_per_week: DWORD, + usri1020_logon_hours: LPBYTE, +}} +pub type PUSER_INFO_1020 = *mut USER_INFO_1020; +pub type LPUSER_INFO_1020 = *mut USER_INFO_1020; +STRUCT!{struct USER_INFO_1023 { + usri1023_logon_server: LPWSTR, +}} +pub type PUSER_INFO_1023 = *mut USER_INFO_1023; +pub type LPUSER_INFO_1023 = *mut USER_INFO_1023; +STRUCT!{struct USER_INFO_1024 { + usri1024_country_code: DWORD, +}} +pub type PUSER_INFO_1024 = *mut USER_INFO_1024; +pub type LPUSER_INFO_1024 = *mut USER_INFO_1024; +STRUCT!{struct USER_INFO_1025 { + usri1025_code_page: DWORD, +}} +pub type PUSER_INFO_1025 = *mut USER_INFO_1025; +pub type LPUSER_INFO_1025 = *mut USER_INFO_1025; +STRUCT!{struct USER_INFO_1051 { + usri1051_primary_group_id: DWORD, +}} +pub type PUSER_INFO_1051 = *mut USER_INFO_1051; +pub type LPUSER_INFO_1051 = *mut USER_INFO_1051; +STRUCT!{struct USER_INFO_1052 { + usri1052_profile: LPWSTR, +}} +pub type PUSER_INFO_1052 = *mut USER_INFO_1052; +pub type LPUSER_INFO_1052 = *mut USER_INFO_1052; +STRUCT!{struct USER_INFO_1053 { + usri1053_home_dir_drive: LPWSTR, +}} +pub type PUSER_INFO_1053 = *mut USER_INFO_1053; +pub type LPUSER_INFO_1053 = *mut USER_INFO_1053; +STRUCT!{struct USER_MODALS_INFO_0 { + usrmod0_min_passwd_len: DWORD, + usrmod0_max_passwd_age: DWORD, + usrmod0_min_passwd_age: DWORD, + usrmod0_force_logoff: DWORD, + usrmod0_password_hist_len: DWORD, +}} +pub type PUSER_MODALS_INFO_0 = *mut USER_MODALS_INFO_0; +pub type LPUSER_MODALS_INFO_0 = *mut USER_MODALS_INFO_0; +STRUCT!{struct USER_MODALS_INFO_1 { + usrmod1_role: DWORD, + usrmod1_primary: LPWSTR, +}} +pub type PUSER_MODALS_INFO_1 = *mut USER_MODALS_INFO_1; +pub type LPUSER_MODALS_INFO_1 = *mut USER_MODALS_INFO_1; +STRUCT!{struct USER_MODALS_INFO_2 { + usrmod2_domain_name: LPWSTR, + usrmod2_domain_id: PSID, +}} +pub type PUSER_MODALS_INFO_2 = *mut USER_MODALS_INFO_2; +pub type LPUSER_MODALS_INFO_2 = *mut USER_MODALS_INFO_2; +STRUCT!{struct USER_MODALS_INFO_3 { + usrmod3_lockout_duration: DWORD, + usrmod3_lockout_observation_window: DWORD, + usrmod3_lockout_threshold: DWORD, +}} +pub type PUSER_MODALS_INFO_3 = *mut USER_MODALS_INFO_3; +pub type LPUSER_MODALS_INFO_3 = *mut USER_MODALS_INFO_3; +STRUCT!{struct USER_MODALS_INFO_1001 { + usrmod1001_min_passwd_len: DWORD, +}} +pub type PUSER_MODALS_INFO_1001 = *mut USER_MODALS_INFO_1001; +pub type LPUSER_MODALS_INFO_1001 = *mut USER_MODALS_INFO_1001; +STRUCT!{struct USER_MODALS_INFO_1002 { + usrmod1002_max_passwd_age: DWORD, +}} +pub type PUSER_MODALS_INFO_1002 = *mut USER_MODALS_INFO_1002; +pub type LPUSER_MODALS_INFO_1002 = *mut USER_MODALS_INFO_1002; +STRUCT!{struct USER_MODALS_INFO_1003 { + usrmod1003_min_passwd_age: DWORD, +}} +pub type PUSER_MODALS_INFO_1003 = *mut USER_MODALS_INFO_1003; +pub type LPUSER_MODALS_INFO_1003 = *mut USER_MODALS_INFO_1003; +STRUCT!{struct USER_MODALS_INFO_1004 { + usrmod1004_force_logoff: DWORD, +}} +pub type PUSER_MODALS_INFO_1004 = *mut USER_MODALS_INFO_1004; +pub type LPUSER_MODALS_INFO_1004 = *mut USER_MODALS_INFO_1004; +STRUCT!{struct USER_MODALS_INFO_1005 { + usrmod1005_password_hist_len: DWORD, +}} +pub type PUSER_MODALS_INFO_1005 = *mut USER_MODALS_INFO_1005; +pub type LPUSER_MODALS_INFO_1005 = *mut USER_MODALS_INFO_1005; +STRUCT!{struct USER_MODALS_INFO_1006 { + usrmod1006_role: DWORD, +}} +pub type PUSER_MODALS_INFO_1006 = *mut USER_MODALS_INFO_1006; +pub type LPUSER_MODALS_INFO_1006 = *mut USER_MODALS_INFO_1006; +STRUCT!{struct USER_MODALS_INFO_1007 { + usrmod1007_primary: LPWSTR, +}} +pub type PUSER_MODALS_INFO_1007 = *mut USER_MODALS_INFO_1007; +pub type LPUSER_MODALS_INFO_1007 = *mut USER_MODALS_INFO_1007; +pub const UF_SCRIPT: DWORD = 0x0001; +pub const UF_ACCOUNTDISABLE: DWORD = 0x0002; +pub const UF_HOMEDIR_REQUIRED: DWORD = 0x0008; +pub const UF_LOCKOUT: DWORD = 0x0010; +pub const UF_PASSWD_NOTREQD: DWORD = 0x0020; +pub const UF_PASSWD_CANT_CHANGE: DWORD = 0x0040; +pub const UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED: DWORD = 0x0080; +pub const UF_TEMP_DUPLICATE_ACCOUNT: DWORD = 0x0100; +pub const UF_NORMAL_ACCOUNT: DWORD = 0x0200; +pub const UF_INTERDOMAIN_TRUST_ACCOUNT: DWORD = 0x0800; +pub const UF_WORKSTATION_TRUST_ACCOUNT: DWORD = 0x1000; +pub const UF_SERVER_TRUST_ACCOUNT: DWORD = 0x2000; +pub const UF_MACHINE_ACCOUNT_MASK: DWORD = UF_INTERDOMAIN_TRUST_ACCOUNT + | UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT; +pub const UF_ACCOUNT_TYPE_MASK: DWORD = UF_TEMP_DUPLICATE_ACCOUNT | UF_NORMAL_ACCOUNT + | UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT; +pub const UF_DONT_EXPIRE_PASSWD: DWORD = 0x10000; +pub const UF_MNS_LOGON_ACCOUNT: DWORD = 0x20000; +pub const UF_SMARTCARD_REQUIRED: DWORD = 0x40000; +pub const UF_TRUSTED_FOR_DELEGATION: DWORD = 0x80000; +pub const UF_NOT_DELEGATED: DWORD = 0x100000; +pub const UF_USE_DES_KEY_ONLY: DWORD = 0x200000; +pub const UF_DONT_REQUIRE_PREAUTH: DWORD = 0x400000; +pub const UF_PASSWORD_EXPIRED: DWORD = 0x800000; +pub const UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: DWORD = 0x1000000; +pub const UF_NO_AUTH_DATA_REQUIRED: DWORD = 0x2000000; +pub const UF_PARTIAL_SECRETS_ACCOUNT: DWORD = 0x4000000; +pub const UF_USE_AES_KEYS: DWORD = 0x8000000; +pub const UF_SETTABLE_BITS: DWORD = UF_SCRIPT | UF_ACCOUNTDISABLE | UF_LOCKOUT + | UF_HOMEDIR_REQUIRED | UF_PASSWD_NOTREQD | UF_PASSWD_CANT_CHANGE | UF_ACCOUNT_TYPE_MASK + | UF_DONT_EXPIRE_PASSWD | UF_MNS_LOGON_ACCOUNT | UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED + | UF_SMARTCARD_REQUIRED | UF_TRUSTED_FOR_DELEGATION | UF_NOT_DELEGATED | UF_USE_DES_KEY_ONLY + | UF_DONT_REQUIRE_PREAUTH | UF_PASSWORD_EXPIRED | UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION + | UF_NO_AUTH_DATA_REQUIRED | UF_USE_AES_KEYS | UF_PARTIAL_SECRETS_ACCOUNT; +pub const FILTER_TEMP_DUPLICATE_ACCOUNT: DWORD = 0x0001; +pub const FILTER_NORMAL_ACCOUNT: DWORD = 0x0002; +pub const FILTER_INTERDOMAIN_TRUST_ACCOUNT: DWORD = 0x0008; +pub const FILTER_WORKSTATION_TRUST_ACCOUNT: DWORD = 0x0010; +pub const FILTER_SERVER_TRUST_ACCOUNT: DWORD = 0x0020; +pub const LG_INCLUDE_INDIRECT: DWORD = 0x0001; +pub const AF_OP_PRINT: DWORD = 0x1; +pub const AF_OP_COMM: DWORD = 0x2; +pub const AF_OP_SERVER: DWORD = 0x4; +pub const AF_OP_ACCOUNTS: DWORD = 0x8; +pub const AF_SETTABLE_BITS: DWORD = AF_OP_PRINT | AF_OP_COMM | AF_OP_SERVER | AF_OP_ACCOUNTS; +pub const UAS_ROLE_STANDALONE: DWORD = 0; +pub const UAS_ROLE_MEMBER: DWORD = 1; +pub const UAS_ROLE_BACKUP: DWORD = 2; +pub const UAS_ROLE_PRIMARY: DWORD = 3; +pub const USER_NAME_PARMNUM: DWORD = 1; +pub const USER_PASSWORD_PARMNUM: DWORD = 3; +pub const USER_PASSWORD_AGE_PARMNUM: DWORD = 4; +pub const USER_PRIV_PARMNUM: DWORD = 5; +pub const USER_HOME_DIR_PARMNUM: DWORD = 6; +pub const USER_COMMENT_PARMNUM: DWORD = 7; +pub const USER_FLAGS_PARMNUM: DWORD = 8; +pub const USER_SCRIPT_PATH_PARMNUM: DWORD = 9; +pub const USER_AUTH_FLAGS_PARMNUM: DWORD = 10; +pub const USER_FULL_NAME_PARMNUM: DWORD = 11; +pub const USER_USR_COMMENT_PARMNUM: DWORD = 12; +pub const USER_PARMS_PARMNUM: DWORD = 13; +pub const USER_WORKSTATIONS_PARMNUM: DWORD = 14; +pub const USER_LAST_LOGON_PARMNUM: DWORD = 15; +pub const USER_LAST_LOGOFF_PARMNUM: DWORD = 16; +pub const USER_ACCT_EXPIRES_PARMNUM: DWORD = 17; +pub const USER_MAX_STORAGE_PARMNUM: DWORD = 18; +pub const USER_UNITS_PER_WEEK_PARMNUM: DWORD = 19; +pub const USER_LOGON_HOURS_PARMNUM: DWORD = 20; +pub const USER_PAD_PW_COUNT_PARMNUM: DWORD = 21; +pub const USER_NUM_LOGONS_PARMNUM: DWORD = 22; +pub const USER_LOGON_SERVER_PARMNUM: DWORD = 23; +pub const USER_COUNTRY_CODE_PARMNUM: DWORD = 24; +pub const USER_CODE_PAGE_PARMNUM: DWORD = 25; +pub const USER_PRIMARY_GROUP_PARMNUM: DWORD = 51; +pub const USER_PROFILE: DWORD = 52; +pub const USER_PROFILE_PARMNUM: DWORD = 52; +pub const USER_HOME_DIR_DRIVE_PARMNUM: DWORD = 53; +pub const USER_NAME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_NAME_PARMNUM; +pub const USER_PASSWORD_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_PASSWORD_PARMNUM; +pub const USER_PASSWORD_AGE_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_PASSWORD_AGE_PARMNUM; +pub const USER_PRIV_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_PRIV_PARMNUM; +pub const USER_HOME_DIR_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_HOME_DIR_PARMNUM; +pub const USER_COMMENT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_COMMENT_PARMNUM; +pub const USER_FLAGS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_FLAGS_PARMNUM; +pub const USER_SCRIPT_PATH_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_SCRIPT_PATH_PARMNUM; +pub const USER_AUTH_FLAGS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_AUTH_FLAGS_PARMNUM; +pub const USER_FULL_NAME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_FULL_NAME_PARMNUM; +pub const USER_USR_COMMENT_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_USR_COMMENT_PARMNUM; +pub const USER_PARMS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_PARMS_PARMNUM; +pub const USER_WORKSTATIONS_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_WORKSTATIONS_PARMNUM; +pub const USER_LAST_LOGON_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_LAST_LOGON_PARMNUM; +pub const USER_LAST_LOGOFF_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_LAST_LOGOFF_PARMNUM; +pub const USER_ACCT_EXPIRES_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_ACCT_EXPIRES_PARMNUM; +pub const USER_MAX_STORAGE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_MAX_STORAGE_PARMNUM; +pub const USER_UNITS_PER_WEEK_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_UNITS_PER_WEEK_PARMNUM; +pub const USER_LOGON_HOURS_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_LOGON_HOURS_PARMNUM; +pub const USER_PAD_PW_COUNT_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_PAD_PW_COUNT_PARMNUM; +pub const USER_NUM_LOGONS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_NUM_LOGONS_PARMNUM; +pub const USER_LOGON_SERVER_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_LOGON_SERVER_PARMNUM; +pub const USER_COUNTRY_CODE_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_COUNTRY_CODE_PARMNUM; +pub const USER_CODE_PAGE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + USER_CODE_PAGE_PARMNUM; +pub const USER_PRIMARY_GROUP_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_PRIMARY_GROUP_PARMNUM; +pub const USER_HOME_DIR_DRIVE_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + USER_HOME_DIR_DRIVE_PARMNUM; +pub const NULL_USERSETINFO_PASSWD: &'static str = " "; +pub const TIMEQ_FOREVER: DWORD = -1i32 as u32; +pub const USER_MAXSTORAGE_UNLIMITED: DWORD = -1i32 as u32; +pub const USER_NO_LOGOFF: DWORD = -1i32 as u32; +pub const UNITS_PER_DAY: DWORD = 24; +pub const UNITS_PER_WEEK: DWORD = UNITS_PER_DAY * 7; +pub const USER_PRIV_MASK: DWORD = 0x3; +pub const USER_PRIV_GUEST: DWORD = 0; +pub const USER_PRIV_USER: DWORD = 1; +pub const USER_PRIV_ADMIN: DWORD = 2; +pub const MAX_PASSWD_LEN: DWORD = PWLEN; +pub const DEF_MIN_PWLEN: DWORD = 6; +pub const DEF_PWUNIQUENESS: DWORD = 5; +pub const DEF_MAX_PWHIST: DWORD = 8; +pub const DEF_MAX_PWAGE: DWORD = TIMEQ_FOREVER; +pub const DEF_MIN_PWAGE: DWORD = 0; +pub const DEF_FORCE_LOGOFF: DWORD = 0xffffffff; +pub const DEF_MAX_BADPW: DWORD = 0; +pub const ONE_DAY: DWORD = 1 * 24 * 3600; +pub const VALIDATED_LOGON: DWORD = 0; +pub const PASSWORD_EXPIRED: DWORD = 2; +pub const NON_VALIDATED_LOGON: DWORD = 3; +pub const VALID_LOGOFF: DWORD = 1; +pub const MODALS_MIN_PASSWD_LEN_PARMNUM: DWORD = 1; +pub const MODALS_MAX_PASSWD_AGE_PARMNUM: DWORD = 2; +pub const MODALS_MIN_PASSWD_AGE_PARMNUM: DWORD = 3; +pub const MODALS_FORCE_LOGOFF_PARMNUM: DWORD = 4; +pub const MODALS_PASSWD_HIST_LEN_PARMNUM: DWORD = 5; +pub const MODALS_ROLE_PARMNUM: DWORD = 6; +pub const MODALS_PRIMARY_PARMNUM: DWORD = 7; +pub const MODALS_DOMAIN_NAME_PARMNUM: DWORD = 8; +pub const MODALS_DOMAIN_ID_PARMNUM: DWORD = 9; +pub const MODALS_LOCKOUT_DURATION_PARMNUM: DWORD = 10; +pub const MODALS_LOCKOUT_OBSERVATION_WINDOW_PARMNUM: DWORD = 11; +pub const MODALS_LOCKOUT_THRESHOLD_PARMNUM: DWORD = 12; +pub const MODALS_MIN_PASSWD_LEN_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_MIN_PASSWD_LEN_PARMNUM; +pub const MODALS_MAX_PASSWD_AGE_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_MAX_PASSWD_AGE_PARMNUM; +pub const MODALS_MIN_PASSWD_AGE_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_MIN_PASSWD_AGE_PARMNUM; +pub const MODALS_FORCE_LOGOFF_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_FORCE_LOGOFF_PARMNUM; +pub const MODALS_PASSWD_HIST_LEN_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_PASSWD_HIST_LEN_PARMNUM; +pub const MODALS_ROLE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + MODALS_ROLE_PARMNUM; +pub const MODALS_PRIMARY_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + MODALS_PRIMARY_PARMNUM; +pub const MODALS_DOMAIN_NAME_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + MODALS_DOMAIN_NAME_PARMNUM; +pub const MODALS_DOMAIN_ID_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + MODALS_DOMAIN_ID_PARMNUM; +extern "system" { + pub fn NetGroupAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetGroupAddUser( + servername: LPCWSTR, + GroupName: LPCWSTR, + username: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetGroupEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resume_handle: PDWORD_PTR, + ) -> NET_API_STATUS; + pub fn NetGroupGetInfo( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetGroupSetInfo( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetGroupDel( + servername: LPCWSTR, + groupname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetGroupDelUser( + servername: LPCWSTR, + GroupName: LPCWSTR, + Username: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetGroupGetUsers( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + ResumeHandle: PDWORD_PTR, + ) -> NET_API_STATUS; + pub fn NetGroupSetUsers( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + totalentries: DWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct GROUP_INFO_0 { + grpi0_name: LPWSTR, +}} +pub type PGROUP_INFO_0 = *mut GROUP_INFO_0; +pub type LPGROUP_INFO_0 = *mut GROUP_INFO_0; +STRUCT!{struct GROUP_INFO_1 { + grpi1_name: LPWSTR, + grpi1_comment: LPWSTR, +}} +pub type PGROUP_INFO_1 = *mut GROUP_INFO_1; +pub type LPGROUP_INFO_1 = *mut GROUP_INFO_1; +STRUCT!{struct GROUP_INFO_2 { + grpi2_name: LPWSTR, + grpi2_comment: LPWSTR, + grpi2_group_id: DWORD, + grpi2_attributes: DWORD, +}} +pub type PGROUP_INFO_2 = *mut GROUP_INFO_2; +STRUCT!{struct GROUP_INFO_3 { + grpi3_name: LPWSTR, + grpi3_comment: LPWSTR, + grpi3_group_sid: PSID, + grpi3_attributes: DWORD, +}} +pub type PGROUP_INFO_3 = *mut GROUP_INFO_3; +STRUCT!{struct GROUP_INFO_1002 { + grpi1002_comment: LPWSTR, +}} +pub type PGROUP_INFO_1002 = *mut GROUP_INFO_1002; +pub type LPGROUP_INFO_1002 = *mut GROUP_INFO_1002; +STRUCT!{struct GROUP_INFO_1005 { + grpi1005_attributes: DWORD, +}} +pub type PGROUP_INFO_1005 = *mut GROUP_INFO_1005; +pub type LPGROUP_INFO_1005 = *mut GROUP_INFO_1005; +STRUCT!{struct GROUP_USERS_INFO_0 { + grui0_name: LPWSTR, +}} +pub type PGROUP_USERS_INFO_0 = *mut GROUP_USERS_INFO_0; +pub type LPGROUP_USERS_INFO_0 = *mut GROUP_USERS_INFO_0; +STRUCT!{struct GROUP_USERS_INFO_1 { + grui1_name: LPWSTR, + grui1_attributes: DWORD, +}} +pub type PGROUP_USERS_INFO_1 = *mut GROUP_USERS_INFO_1; +pub type LPGROUP_USERS_INFO_1 = *mut GROUP_USERS_INFO_1; +pub const GROUPIDMASK: DWORD = 0x8000; +pub const GROUP_SPECIALGRP_USERS: &'static str = "USERS"; +pub const GROUP_SPECIALGRP_ADMINS: &'static str = "ADMINS"; +pub const GROUP_SPECIALGRP_GUESTS: &'static str = "GUESTS"; +pub const GROUP_SPECIALGRP_LOCAL: &'static str = "LOCAL"; +pub const GROUP_ALL_PARMNUM: DWORD = 0; +pub const GROUP_NAME_PARMNUM: DWORD = 1; +pub const GROUP_COMMENT_PARMNUM: DWORD = 2; +pub const GROUP_ATTRIBUTES_PARMNUM: DWORD = 3; +pub const GROUP_ALL_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + GROUP_ALL_PARMNUM; +pub const GROUP_NAME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + GROUP_NAME_PARMNUM; +pub const GROUP_COMMENT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + GROUP_COMMENT_PARMNUM; +pub const GROUP_ATTRIBUTES_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + GROUP_ATTRIBUTES_PARMNUM; +extern "system" { + pub fn NetLocalGroupAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetLocalGroupAddMember( + servername: LPCWSTR, + groupname: LPCWSTR, + membersid: PSID, + ) -> NET_API_STATUS; + pub fn NetLocalGroupEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: PDWORD_PTR, + ) -> NET_API_STATUS; + pub fn NetLocalGroupGetInfo( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetLocalGroupSetInfo( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetLocalGroupDel( + servername: LPCWSTR, + groupname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetLocalGroupDelMember( + servername: LPCWSTR, + groupname: LPCWSTR, + membersid: PSID, + ) -> NET_API_STATUS; + pub fn NetLocalGroupGetMembers( + servername: LPCWSTR, + localgroupname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: PDWORD_PTR, + ) -> NET_API_STATUS; + pub fn NetLocalGroupSetMembers( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + totalentries: DWORD, + ) -> NET_API_STATUS; + pub fn NetLocalGroupAddMembers( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + totalentries: DWORD, + ) -> NET_API_STATUS; + pub fn NetLocalGroupDelMembers( + servername: LPCWSTR, + groupname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + totalentries: DWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct LOCALGROUP_INFO_0 { + lgrpi0_name: LPWSTR, +}} +pub type PLOCALGROUP_INFO_0 = *mut LOCALGROUP_INFO_0; +pub type LPLOCALGROUP_INFO_0 = *mut LOCALGROUP_INFO_0; +STRUCT!{struct LOCALGROUP_INFO_1 { + lgrpi1_name: LPWSTR, + lgrpi1_comment: LPWSTR, +}} +pub type PLOCALGROUP_INFO_1 = *mut LOCALGROUP_INFO_1; +pub type LPLOCALGROUP_INFO_1 = *mut LOCALGROUP_INFO_1; +STRUCT!{struct LOCALGROUP_INFO_1002 { + lgrpi1002_comment: LPWSTR, +}} +pub type PLOCALGROUP_INFO_1002 = *mut LOCALGROUP_INFO_1002; +pub type LPLOCALGROUP_INFO_1002 = *mut LOCALGROUP_INFO_1002; +STRUCT!{struct LOCALGROUP_MEMBERS_INFO_0 { + lgrmi0_sid: PSID, +}} +pub type PLOCALGROUP_MEMBERS_INFO_0 = *mut LOCALGROUP_MEMBERS_INFO_0; +pub type LPLOCALGROUP_MEMBERS_INFO_0 = *mut LOCALGROUP_MEMBERS_INFO_0; +STRUCT!{struct LOCALGROUP_MEMBERS_INFO_1 { + lgrmi1_sid: PSID, + lgrmi1_sidusage: SID_NAME_USE, + lgrmi1_name: LPWSTR, +}} +pub type PLOCALGROUP_MEMBERS_INFO_1 = *mut LOCALGROUP_MEMBERS_INFO_1; +pub type LPLOCALGROUP_MEMBERS_INFO_1 = *mut LOCALGROUP_MEMBERS_INFO_1; +STRUCT!{struct LOCALGROUP_MEMBERS_INFO_2 { + lgrmi2_sid: PSID, + lgrmi2_sidusage: SID_NAME_USE, + lgrmi2_domainandname: LPWSTR, +}} +pub type PLOCALGROUP_MEMBERS_INFO_2 = *mut LOCALGROUP_MEMBERS_INFO_2; +pub type LPLOCALGROUP_MEMBERS_INFO_2 = *mut LOCALGROUP_MEMBERS_INFO_2; +STRUCT!{struct LOCALGROUP_MEMBERS_INFO_3 { + lgrmi3_domainandname: LPWSTR, +}} +pub type PLOCALGROUP_MEMBERS_INFO_3 = *mut LOCALGROUP_MEMBERS_INFO_3; +pub type LPLOCALGROUP_MEMBERS_INFO_3 = *mut LOCALGROUP_MEMBERS_INFO_3; +STRUCT!{struct LOCALGROUP_USERS_INFO_0 { + lgrui0_name: LPWSTR, +}} +pub type PLOCALGROUP_USERS_INFO_0 = *mut LOCALGROUP_USERS_INFO_0; +pub type LPLOCALGROUP_USERS_INFO_0 = *mut LOCALGROUP_USERS_INFO_0; +pub const LOCALGROUP_NAME_PARMNUM: DWORD = 1; +pub const LOCALGROUP_COMMENT_PARMNUM: DWORD = 2; +extern "system" { + pub fn NetQueryDisplayInformation( + ServerName: LPCWSTR, + Level: DWORD, + Index: DWORD, + EntriesRequested: DWORD, + PreferredMaximumLength: DWORD, + ReturnedEntryCount: LPDWORD, + SortedBuffer: *mut PVOID, + ) -> NET_API_STATUS; + pub fn NetGetDisplayInformationIndex( + ServerName: LPCWSTR, + Level: DWORD, + Prefix: LPCWSTR, + Index: LPDWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct NET_DISPLAY_USER { + usri1_name: LPWSTR, + usri1_comment: LPWSTR, + usri1_flags: DWORD, + usri1_full_name: LPWSTR, + usri1_user_id: DWORD, + usri1_next_index: DWORD, +}} +pub type PNET_DISPLAY_USER = *mut NET_DISPLAY_USER; +STRUCT!{struct NET_DISPLAY_MACHINE { + usri2_name: LPWSTR, + usri2_comment: LPWSTR, + usri2_flags: DWORD, + usri2_user_id: DWORD, + usri2_next_index: DWORD, +}} +pub type PNET_DISPLAY_MACHINE = *mut NET_DISPLAY_MACHINE; +STRUCT!{struct NET_DISPLAY_GROUP { + usri3_name: LPWSTR, + usri3_comment: LPWSTR, + grpi3_group_id: DWORD, + grpi3_attributes: DWORD, + grpi3_next_index: DWORD, +}} +pub type PNET_DISPLAY_GROUP = *mut NET_DISPLAY_GROUP; +extern "system" { + pub fn NetAccessAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetAccessEnum( + servername: LPCWSTR, + BasePath: LPCWSTR, + Recursive: DWORD, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resume_handle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetAccessGetInfo( + servername: LPCWSTR, + resource: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetAccessSetInfo( + servername: LPCWSTR, + resource: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetAccessDel( + servername: LPCWSTR, + resource: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetAccessGetUserPerms( + servername: LPCWSTR, + UGname: LPCWSTR, + resource: LPCWSTR, + Perms: LPDWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct ACCESS_INFO_0 { + acc0_resource_name: LPWSTR, +}} +pub type PACCESS_INFO_0 = *mut ACCESS_INFO_0; +pub type LPACCESS_INFO_0 = *mut ACCESS_INFO_0; +STRUCT!{struct ACCESS_INFO_1 { + acc1_resource_name: LPWSTR, + acc1_attr: DWORD, + acc1_count: DWORD, +}} +pub type PACCESS_INFO_1 = *mut ACCESS_INFO_1; +pub type LPACCESS_INFO_1 = *mut ACCESS_INFO_1; +STRUCT!{struct ACCESS_INFO_1002 { + acc1002_attr: DWORD, +}} +pub type PACCESS_INFO_1002 = *mut ACCESS_INFO_1002; +pub type LPACCESS_INFO_1002 = *mut ACCESS_INFO_1002; +STRUCT!{struct ACCESS_LIST { + acl_ugname: LPWSTR, + acl_access: DWORD, +}} +pub type PACCESS_LIST = *mut ACCESS_LIST; +pub type LPACCESS_LIST = *mut ACCESS_LIST; +pub const MAXPERMENTRIES: DWORD = 64; +pub const ACCESS_NONE: DWORD = 0; +pub const ACCESS_ALL: DWORD = ACCESS_READ | ACCESS_WRITE | ACCESS_CREATE | ACCESS_EXEC + | ACCESS_DELETE | ACCESS_ATRIB | ACCESS_PERM; +pub const ACCESS_READ: DWORD = 0x01; +pub const ACCESS_WRITE: DWORD = 0x02; +pub const ACCESS_CREATE: DWORD = 0x04; +pub const ACCESS_EXEC: DWORD = 0x08; +pub const ACCESS_DELETE: DWORD = 0x10; +pub const ACCESS_ATRIB: DWORD = 0x20; +pub const ACCESS_PERM: DWORD = 0x40; +pub const ACCESS_GROUP: DWORD = 0x8000; +pub const ACCESS_AUDIT: DWORD = 0x1; +pub const ACCESS_SUCCESS_OPEN: DWORD = 0x10; +pub const ACCESS_SUCCESS_WRITE: DWORD = 0x20; +pub const ACCESS_SUCCESS_DELETE: DWORD = 0x40; +pub const ACCESS_SUCCESS_ACL: DWORD = 0x80; +pub const ACCESS_SUCCESS_MASK: DWORD = 0xF0; +pub const ACCESS_FAIL_OPEN: DWORD = 0x100; +pub const ACCESS_FAIL_WRITE: DWORD = 0x200; +pub const ACCESS_FAIL_DELETE: DWORD = 0x400; +pub const ACCESS_FAIL_ACL: DWORD = 0x800; +pub const ACCESS_FAIL_MASK: DWORD = 0xF00; +pub const ACCESS_FAIL_SHIFT: DWORD = 4; +pub const ACCESS_RESOURCE_NAME_PARMNUM: DWORD = 1; +pub const ACCESS_ATTR_PARMNUM: DWORD = 2; +pub const ACCESS_COUNT_PARMNUM: DWORD = 3; +pub const ACCESS_ACCESS_LIST_PARMNUM: DWORD = 4; +pub const ACCESS_RESOURCE_NAME_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + ACCESS_RESOURCE_NAME_PARMNUM; +pub const ACCESS_ATTR_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + ACCESS_ATTR_PARMNUM; +pub const ACCESS_COUNT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + ACCESS_COUNT_PARMNUM; +pub const ACCESS_ACCESS_LIST_INFOLEVEL: DWORD = + PARMNUM_BASE_INFOLEVEL + ACCESS_ACCESS_LIST_PARMNUM; +pub const ACCESS_LETTERS: &'static str = "RWCXDAP "; +ENUM!{enum NET_VALIDATE_PASSWORD_TYPE { + NetValidateAuthentication = 1, + NetValidatePasswordChange, + NetValidatePasswordReset, +}} +pub type PNET_VALIDATE_PASSWORD_TYPE = *mut NET_VALIDATE_PASSWORD_TYPE; +STRUCT!{struct NET_VALIDATE_PASSWORD_HASH { + Length: ULONG, + Hash: LPBYTE, +}} +pub type PNET_VALIDATE_PASSWORD_HASH = *mut NET_VALIDATE_PASSWORD_HASH; +pub const NET_VALIDATE_PASSWORD_LAST_SET: ULONG = 0x00000001; +pub const NET_VALIDATE_BAD_PASSWORD_TIME: ULONG = 0x00000002; +pub const NET_VALIDATE_LOCKOUT_TIME: ULONG = 0x00000004; +pub const NET_VALIDATE_BAD_PASSWORD_COUNT: ULONG = 0x00000008; +pub const NET_VALIDATE_PASSWORD_HISTORY_LENGTH: ULONG = 0x00000010; +pub const NET_VALIDATE_PASSWORD_HISTORY: ULONG = 0x00000020; +STRUCT!{struct NET_VALIDATE_PERSISTED_FIELDS { + PresentFields: ULONG, + PasswordLastSet: FILETIME, + BadPasswordTime: FILETIME, + LockoutTime: FILETIME, + BadPasswordCount: ULONG, + PasswordHistoryLength: ULONG, + PasswordHistory: PNET_VALIDATE_PASSWORD_HASH, +}} +pub type PNET_VALIDATE_PERSISTED_FIELDS = *mut NET_VALIDATE_PERSISTED_FIELDS; +STRUCT!{struct NET_VALIDATE_OUTPUT_ARG { + ChangedPersistedFields: NET_VALIDATE_PERSISTED_FIELDS, + ValidationStatus: NET_API_STATUS, +}} +pub type PNET_VALIDATE_OUTPUT_ARG = *mut NET_VALIDATE_OUTPUT_ARG; +STRUCT!{struct NET_VALIDATE_AUTHENTICATION_INPUT_ARG { + InputPersistedFields: NET_VALIDATE_PERSISTED_FIELDS, + PasswordMatched: BOOLEAN, +}} +pub type PNET_VALIDATE_AUTHENTICATION_INPUT_ARG = *mut NET_VALIDATE_AUTHENTICATION_INPUT_ARG; +STRUCT!{struct NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG { + InputPersistedFields: NET_VALIDATE_PERSISTED_FIELDS, + ClearPassword: LPWSTR, + UserAccountName: LPWSTR, + HashedPassword: NET_VALIDATE_PASSWORD_HASH, + PasswordMatch: BOOLEAN, +}} +pub type PNET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG = *mut NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG; +STRUCT!{struct NET_VALIDATE_PASSWORD_RESET_INPUT_ARG { + InputPersistedFields: NET_VALIDATE_PERSISTED_FIELDS, + ClearPassword: LPWSTR, + UserAccountName: LPWSTR, + HashedPassword: NET_VALIDATE_PASSWORD_HASH, + PasswordMustChangeAtNextLogon: BOOLEAN, + ClearLockout: BOOLEAN, +}} +pub type PNET_VALIDATE_PASSWORD_RESET_INPUT_ARG = *mut NET_VALIDATE_PASSWORD_RESET_INPUT_ARG; +extern "system" { + pub fn NetValidatePasswordPolicy( + ServerName: LPCWSTR, + Qualifier: LPVOID, + ValidationType: NET_VALIDATE_PASSWORD_TYPE, + InputArg: LPVOID, + OutputArg: *mut LPVOID, + ) -> NET_API_STATUS; + pub fn NetValidatePasswordPolicyFree( + OutputArg: *mut LPVOID, + ) -> NET_API_STATUS; + pub fn NetGetDCName( + servername: LPCWSTR, + domainname: LPCWSTR, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetGetAnyDCName( + servername: LPCWSTR, + domainname: LPCWSTR, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn I_NetLogonControl( + ServerName: LPCWSTR, + FunctionCode: DWORD, + QueryLevel: DWORD, + Buffer: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn I_NetLogonControl2( + ServerName: LPCWSTR, + FunctionCode: DWORD, + QueryLevel: DWORD, + Data: LPBYTE, + Buffer: *mut LPBYTE, + ) -> NET_API_STATUS; +} +pub type NTSTATUS = LONG; +pub type PNTSTATUS = *mut LONG; +extern "system" { + pub fn NetEnumerateTrustedDomains( + ServerName: LPWSTR, + DomainNames: *mut LPWSTR, + ) -> NTSTATUS; +} +pub const NETLOGON_CONTROL_QUERY: DWORD = 1; +pub const NETLOGON_CONTROL_REPLICATE: DWORD = 2; +pub const NETLOGON_CONTROL_SYNCHRONIZE: DWORD = 3; +pub const NETLOGON_CONTROL_PDC_REPLICATE: DWORD = 4; +pub const NETLOGON_CONTROL_REDISCOVER: DWORD = 5; +pub const NETLOGON_CONTROL_TC_QUERY: DWORD = 6; +pub const NETLOGON_CONTROL_TRANSPORT_NOTIFY: DWORD = 7; +pub const NETLOGON_CONTROL_FIND_USER: DWORD = 8; +pub const NETLOGON_CONTROL_CHANGE_PASSWORD: DWORD = 9; +pub const NETLOGON_CONTROL_TC_VERIFY: DWORD = 10; +pub const NETLOGON_CONTROL_FORCE_DNS_REG: DWORD = 11; +pub const NETLOGON_CONTROL_QUERY_DNS_REG: DWORD = 12; +pub const NETLOGON_CONTROL_QUERY_ENC_TYPES: DWORD = 13; +pub const NETLOGON_CONTROL_UNLOAD_NETLOGON_DLL: DWORD = 0xFFFB; +pub const NETLOGON_CONTROL_BACKUP_CHANGE_LOG: DWORD = 0xFFFC; +pub const NETLOGON_CONTROL_TRUNCATE_LOG: DWORD = 0xFFFD; +pub const NETLOGON_CONTROL_SET_DBFLAG: DWORD = 0xFFFE; +pub const NETLOGON_CONTROL_BREAKPOINT: DWORD = 0xFFFF; +STRUCT!{struct NETLOGON_INFO_1 { + netlog1_flags: DWORD, + netlog1_pdc_connection_status: NET_API_STATUS, +}} +pub type PNETLOGON_INFO_1 = *mut NETLOGON_INFO_1; +STRUCT!{struct NETLOGON_INFO_2 { + netlog2_flags: DWORD, + netlog2_pdc_connection_status: NET_API_STATUS, + netlog2_trusted_dc_name: LPWSTR, + netlog2_tc_connection_status: NET_API_STATUS, +}} +pub type PNETLOGON_INFO_2 = *mut NETLOGON_INFO_2; +STRUCT!{struct NETLOGON_INFO_3 { + netlog3_flags: DWORD, + netlog3_logon_attempts: DWORD, + netlog3_reserved1: DWORD, + netlog3_reserved2: DWORD, + netlog3_reserved3: DWORD, + netlog3_reserved4: DWORD, + netlog3_reserved5: DWORD, +}} +pub type PNETLOGON_INFO_3 = *mut NETLOGON_INFO_3; +STRUCT!{struct NETLOGON_INFO_4 { + netlog4_trusted_dc_name: LPWSTR, + netlog4_trusted_domain_name: LPWSTR, +}} +pub type PNETLOGON_INFO_4 = *mut NETLOGON_INFO_4; +pub const NETLOGON_REPLICATION_NEEDED: DWORD = 0x01; +pub const NETLOGON_REPLICATION_IN_PROGRESS: DWORD = 0x02; +pub const NETLOGON_FULL_SYNC_REPLICATION: DWORD = 0x04; +pub const NETLOGON_REDO_NEEDED: DWORD = 0x08; +pub const NETLOGON_HAS_IP: DWORD = 0x10; +pub const NETLOGON_HAS_TIMESERV: DWORD = 0x20; +pub const NETLOGON_DNS_UPDATE_FAILURE: DWORD = 0x40; +pub const NETLOGON_VERIFY_STATUS_RETURNED: DWORD = 0x80; +pub const SERVICE_ACCOUNT_PASSWORD: &'static str = "_SA_{262E99C9-6160-4871-ACEC-4E61736B6F21}"; +pub const SERVICE_ACCOUNT_SECRET_PREFIX: &'static str + = "_SC_{262E99C9-6160-4871-ACEC-4E61736B6F21}_"; +DEFINE_GUID!{ServiceAccountPasswordGUID, + 0x262E99C9, 0x6160, 0x4871, 0xAC, 0xEC, 0x4E, 0x61, 0x73, 0x6B, 0x6F, 0x21} +extern "system" { + pub fn NetAddServiceAccount( + ServerName: LPWSTR, + AccountName: LPWSTR, + Password: LPWSTR, + Flags: DWORD, + ) -> NTSTATUS; +} +pub const SERVICE_ACCOUNT_FLAG_LINK_TO_HOST_ONLY: DWORD = 0x00000001; +pub const SERVICE_ACCOUNT_FLAG_ADD_AGAINST_RODC: DWORD = 0x00000002; +pub const SERVICE_ACCOUNT_FLAG_UNLINK_FROM_HOST_ONLY: DWORD = 0x00000001; +pub const SERVICE_ACCOUNT_FLAG_REMOVE_OFFLINE: DWORD = 0x00000002; +extern "system" { + pub fn NetRemoveServiceAccount( + ServerName: LPWSTR, + AccountName: LPWSTR, + Flags: DWORD, + ) -> NTSTATUS; + pub fn NetEnumerateServiceAccounts( + ServerName: LPWSTR, + Flags: DWORD, + AccountsCount: *mut DWORD, + Accounts: *mut PZPWSTR, + ) -> NTSTATUS; + pub fn NetIsServiceAccount( + ServerName: LPWSTR, + AccountName: LPWSTR, + IsService: *mut BOOL, + ) -> NTSTATUS; + pub fn NetQueryServiceAccount( + ServerName: LPWSTR, + AccountName: LPWSTR, + InfoLevel: DWORD, + Buffer: *mut PBYTE, + ) -> NTSTATUS; +} +ENUM!{enum MSA_INFO_LEVEL { + MsaInfoLevel0 = 0, + MsaInfoLevelMax, +}} +pub type PMSA_INFO_LEVEL = *mut MSA_INFO_LEVEL; +ENUM!{enum MSA_INFO_STATE { + MsaInfoNotExist = 1, + MsaInfoNotService, + MsaInfoCannotInstall, + MsaInfoCanInstall, + MsaInfoInstalled, +}} +pub type PMSA_INFO_STATE = *mut MSA_INFO_STATE; +STRUCT!{struct MSA_INFO_0 { + State: MSA_INFO_STATE, +}} +pub type PMSA_INFO_0 = *mut MSA_INFO_0; +pub type LPMSA_INFO_0 = *mut MSA_INFO_0; diff --git a/winapi/src/um/lmalert.rs b/winapi/src/um/lmalert.rs new file mode 100644 index 000000000..e406d807c --- /dev/null +++ b/winapi/src/um/lmalert.rs @@ -0,0 +1,75 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains structures for communication with the Alerter service +use shared::lmcons::{EVLEN, NET_API_STATUS, SNLEN}; +use shared::minwindef::{DWORD, LPVOID}; +use um::winnt::{LPCWSTR, WCHAR}; +extern "system" { + pub fn NetAlertRaise( + AlertType: LPCWSTR, + Buffer: LPVOID, + BufferSize: DWORD, + ) -> NET_API_STATUS; + pub fn NetAlertRaiseEx( + AlertType: LPCWSTR, + VariableInfo: LPVOID, + VariableInfoSize: DWORD, + ServiceName: LPCWSTR, + ) -> NET_API_STATUS; +} +STRUCT!{struct STD_ALERT { + alrt_timestamp: DWORD, + alrt_eventname: [WCHAR; EVLEN + 1], + alrt_servicename: [WCHAR; SNLEN + 1], +}} +pub type PSTD_ALERT = *mut STD_ALERT; +pub type LPSTD_ALERT = *mut STD_ALERT; +STRUCT!{struct ADMIN_OTHER_INFO { + alrtad_errcode: DWORD, + alrtad_numstrings: DWORD, +}} +pub type PADMIN_OTHER_INFO = *mut ADMIN_OTHER_INFO; +pub type LPADMIN_OTHER_INFO = *mut ADMIN_OTHER_INFO; +STRUCT!{struct ERRLOG_OTHER_INFO { + alrter_errcode: DWORD, + alrter_offset: DWORD, +}} +pub type PERRLOG_OTHER_INFO = *mut ERRLOG_OTHER_INFO; +pub type LPERRLOG_OTHER_INFO = *mut ERRLOG_OTHER_INFO; +STRUCT!{struct PRINT_OTHER_INFO { + alrtpr_jobid: DWORD, + alrtpr_status: DWORD, + alrtpr_submitted: DWORD, + alrtpr_size: DWORD, +}} +pub type PPRINT_OTHER_INFO = *mut PRINT_OTHER_INFO; +pub type LPPRINT_OTHER_INFO = *mut PRINT_OTHER_INFO; +STRUCT!{struct USER_OTHER_INFO { + alrtus_errcode: DWORD, + alrtus_numstrings: DWORD, +}} +pub type PUSER_OTHER_INFO = *mut USER_OTHER_INFO; +pub type LPUSER_OTHER_INFO = *mut USER_OTHER_INFO; +pub const ALERTER_MAILSLOT: &'static str = "\\\\.\\MAILSLOT\\Alerter"; +pub const ALERT_PRINT_EVENT: &'static str = "PRINTING"; +pub const ALERT_MESSAGE_EVENT: &'static str = "MESSAGE"; +pub const ALERT_ERRORLOG_EVENT: &'static str = "ERRORLOG"; +pub const ALERT_ADMIN_EVENT: &'static str = "ADMIN"; +pub const ALERT_USER_EVENT: &'static str = "USER"; +pub const PRJOB_QSTATUS: DWORD = 0x3; +pub const PRJOB_DEVSTATUS: DWORD = 0x1fc; +pub const PRJOB_COMPLETE: DWORD = 0x4; +pub const PRJOB_INTERV: DWORD = 0x8; +pub const PRJOB_ERROR: DWORD = 0x10; +pub const PRJOB_DESTOFFLINE: DWORD = 0x20; +pub const PRJOB_DESTPAUSED: DWORD = 0x40; +pub const PRJOB_NOTIFY: DWORD = 0x80; +pub const PRJOB_DESTNOPAPER: DWORD = 0x100; +pub const PRJOB_DELETED: DWORD = 0x8000; +pub const PRJOB_QS_QUEUED: DWORD = 0; +pub const PRJOB_QS_PAUSED: DWORD = 1; +pub const PRJOB_QS_SPOOLING: DWORD = 2; +pub const PRJOB_QS_PRINTING: DWORD = 3; diff --git a/winapi/src/um/lmapibuf.rs b/winapi/src/um/lmapibuf.rs new file mode 100644 index 000000000..620a1319b --- /dev/null +++ b/winapi/src/um/lmapibuf.rs @@ -0,0 +1,30 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains information about NetApiBuffer APIs +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPDWORD, LPVOID}; +extern "system" { + pub fn NetApiBufferAllocate( + ByteCount: DWORD, + Buffer: *mut LPVOID, + ) -> NET_API_STATUS; + pub fn NetApiBufferFree( + Buffer: LPVOID, + ) -> NET_API_STATUS; + pub fn NetApiBufferReallocate( + OldBuffer: LPVOID, + NewByteCount: DWORD, + NewBuffer: *mut LPVOID, + ) -> NET_API_STATUS; + pub fn NetApiBufferSize( + Buffer: LPVOID, + ByteCount: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetapipBufferAllocate( + ByteCount: DWORD, + Buffer: *mut LPVOID, + ) -> NET_API_STATUS; +} diff --git a/winapi/src/um/lmat.rs b/winapi/src/um/lmat.rs new file mode 100644 index 000000000..46742eb1b --- /dev/null +++ b/winapi/src/um/lmat.rs @@ -0,0 +1,62 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::DWORD_PTR; +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, UCHAR}; +use um::winnt::{LPCWSTR, LPWSTR}; +pub const JOB_RUN_PERIODICALLY: UCHAR = 0x01; +pub const JOB_EXEC_ERROR: UCHAR = 0x02; +pub const JOB_RUNS_TODAY: UCHAR = 0x04; +pub const JOB_ADD_CURRENT_DATE: UCHAR = 0x08; +pub const JOB_NONINTERACTIVE: UCHAR = 0x10; +pub const JOB_INPUT_FLAGS: UCHAR = JOB_RUN_PERIODICALLY | JOB_ADD_CURRENT_DATE + | JOB_NONINTERACTIVE; +pub const JOB_OUTPUT_FLAGS: UCHAR = JOB_RUN_PERIODICALLY | JOB_EXEC_ERROR | JOB_RUNS_TODAY + | JOB_NONINTERACTIVE; +STRUCT!{struct AT_INFO { + JobTime: DWORD_PTR, + DaysOfMonth: DWORD, + DaysOfWeek: UCHAR, + Flags: UCHAR, + Command: LPWSTR, +}} +pub type PAT_INFO = *mut AT_INFO; +pub type LPAT_INFO = *mut AT_INFO; +STRUCT!{struct AT_ENUM { + JobId: DWORD, + JobTime: DWORD_PTR, + DaysOfMonth: DWORD, + DaysOfWeek: UCHAR, + Flags: UCHAR, + Command: LPWSTR, +}} +pub type PAT_ENUM = *mut AT_ENUM; +pub type LPAT_ENUM = *mut AT_ENUM; +extern "system" { + pub fn NetScheduleJobAdd( + Servername: LPCWSTR, + Buffer: LPBYTE, + JobId: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetScheduleJobDel( + Servername: LPCWSTR, + MinJobId: DWORD, + MaxJobId: DWORD, + ) -> NET_API_STATUS; + pub fn NetScheduleJobEnum( + Servername: LPCWSTR, + PointerToBuffer: *mut LPBYTE, + PointerToBuffer: DWORD, + EntriesRead: LPDWORD, + TotalEntries: LPDWORD, + ResumeHandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetScheduleJobGetInfo( + Servername: LPCWSTR, + JobId: DWORD, + PointerToBuffer: *mut LPBYTE, + ) -> NET_API_STATUS; +} diff --git a/winapi/src/um/lmdfs.rs b/winapi/src/um/lmdfs.rs new file mode 100644 index 000000000..a0be98b26 --- /dev/null +++ b/winapi/src/um/lmdfs.rs @@ -0,0 +1,483 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +// This file contains structures, function prototypes, and definitions for the NetDfs API +use shared::guiddef::GUID; +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, ULONG, USHORT}; +use um::winnt::{LPWSTR, PSECURITY_DESCRIPTOR, PWSTR, SECURITY_INFORMATION, ULONGLONG, WCHAR}; +pub const DFS_VOLUME_STATES: DWORD = 0xF; +pub const DFS_VOLUME_STATE_OK: DWORD = 1; +pub const DFS_VOLUME_STATE_INCONSISTENT: DWORD = 2; +pub const DFS_VOLUME_STATE_OFFLINE: DWORD = 3; +pub const DFS_VOLUME_STATE_ONLINE: DWORD = 4; +pub const DFS_VOLUME_STATE_RESYNCHRONIZE: DWORD = 0x10; +pub const DFS_VOLUME_STATE_STANDBY: DWORD = 0x20; +pub const DFS_VOLUME_STATE_FORCE_SYNC: DWORD = 0x40; +pub const DFS_VOLUME_FLAVORS: DWORD = 0x0300; +pub const DFS_VOLUME_FLAVOR_UNUSED1: DWORD = 0x0000; +pub const DFS_VOLUME_FLAVOR_STANDALONE: DWORD = 0x0100; +pub const DFS_VOLUME_FLAVOR_AD_BLOB: DWORD = 0x0200; +pub const DFS_STORAGE_FLAVOR_UNUSED2: DWORD = 0x0300; +pub const DFS_STORAGE_STATES: ULONG = 0xF; +pub const DFS_STORAGE_STATE_OFFLINE: ULONG = 1; +pub const DFS_STORAGE_STATE_ONLINE: ULONG = 2; +pub const DFS_STORAGE_STATE_ACTIVE: ULONG = 4; +ENUM!{enum DFS_TARGET_PRIORITY_CLASS { + DfsInvalidPriorityClass = -1i32 as u32, + DfsSiteCostNormalPriorityClass = 0, + DfsGlobalHighPriorityClass, + DfsSiteCostHighPriorityClass, + DfsSiteCostLowPriorityClass, + DfsGlobalLowPriorityClass, +}} +STRUCT!{struct DFS_TARGET_PRIORITY { + TargetPriorityClass: DFS_TARGET_PRIORITY_CLASS, + TargetPriorityRank: USHORT, + Reserved: USHORT, +}} +pub type PDFS_TARGET_PRIORITY = *mut DFS_TARGET_PRIORITY; +STRUCT!{struct DFS_INFO_1 { + EntryPath: LPWSTR, +}} +pub type PDFS_INFO_1 = *mut DFS_INFO_1; +pub type LPDFS_INFO_1 = *mut DFS_INFO_1; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct DFS_INFO_1_32 { + EntryPath: ULONG, +}} +pub type PDFS_INFO_1_32 = *mut DFS_INFO_1_32; +pub type LPDFS_INFO_1_32 = *mut DFS_INFO_1_32; +} +STRUCT!{struct DFS_INFO_2 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + NumberOfStorages: DWORD, +}} +pub type PDFS_INFO_2 = *mut DFS_INFO_2; +pub type LPDFS_INFO_2 = *mut DFS_INFO_2; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct DFS_INFO_2_32 { + EntryPath: ULONG, + Comment: ULONG, + State: DWORD, + NumberOfStorages: DWORD, +}} +pub type PDFS_INFO_2_32 = *mut DFS_INFO_2_32; +pub type LPDFS_INFO_2_32 = *mut DFS_INFO_2_32; +} +STRUCT!{struct DFS_STORAGE_INFO { + State: ULONG, + ServerName: LPWSTR, + ShareName: LPWSTR, +}} +pub type PDFS_STORAGE_INFO = *mut DFS_STORAGE_INFO; +pub type LPDFS_STORAGE_INFO = *mut DFS_STORAGE_INFO; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct DFS_STORAGE_INFO_0_32 { + State: ULONG, + ServerName: ULONG, + ShareName: ULONG, +}} +pub type PDFS_STORAGE_INFO_0_32 = *mut DFS_STORAGE_INFO_0_32; +pub type LPDFS_STORAGE_INFO_0_32 = *mut DFS_STORAGE_INFO_0_32; +} +STRUCT!{struct DFS_STORAGE_INFO_1 { + State: ULONG, + ServerName: LPWSTR, + ShareName: LPWSTR, + TargetPriority: DFS_TARGET_PRIORITY, +}} +pub type PDFS_STORAGE_INFO_1 = *mut DFS_STORAGE_INFO_1; +pub type LPDFS_STORAGE_INFO_1 = *mut DFS_STORAGE_INFO_1; +STRUCT!{struct DFS_INFO_3 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + NumberOfStorages: DWORD, + Storage: LPDFS_STORAGE_INFO, +}} +pub type PDFS_INFO_3 = *mut DFS_INFO_3; +pub type LPDFS_INFO_3 = *mut DFS_INFO_3; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct DFS_INFO_3_32 { + EntryPath: ULONG, + Comment: ULONG, + State: DWORD, + NumberOfStorages: DWORD, + Storage: ULONG, +}} +pub type PDFS_INFO_3_32 = *mut DFS_INFO_3_32; +pub type LPDFS_INFO_3_32 = *mut DFS_INFO_3_32; +} +STRUCT!{struct DFS_INFO_4 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + NumberOfStorages: DWORD, + Storage: LPDFS_STORAGE_INFO, +}} +pub type PDFS_INFO_4 = *mut DFS_INFO_4; +pub type LPDFS_INFO_4 = *mut DFS_INFO_4; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct DFS_INFO_4_32 { + EntryPath: ULONG, + Comment: ULONG, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + NumberOfStorages: DWORD, + Storage: ULONG, +}} +pub type PDFS_INFO_4_32 = *mut DFS_INFO_4_32; +pub type LPDFS_INFO_4_32 = *mut DFS_INFO_4_32; +} +STRUCT!{struct DFS_INFO_5 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + PropertyFlags: ULONG, + MetadataSize: ULONG, + NumberOfStorages: DWORD, +}} +pub type PDFS_INFO_5 = *mut DFS_INFO_5; +pub type LPDFS_INFO_5 = *mut DFS_INFO_5; +STRUCT!{struct DFS_INFO_6 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + PropertyFlags: ULONG, + MetadataSize: ULONG, + NumberOfStorages: DWORD, + Storage: LPDFS_STORAGE_INFO, +}} +pub type PDFS_INFO_6 = *mut DFS_INFO_6; +pub type LPDFS_INFO_6 = *mut DFS_INFO_6; +STRUCT!{struct DFS_INFO_7 { + GenerationGuid: GUID, +}} +pub type PDFS_INFO_7 = *mut DFS_INFO_7; +pub type LPDFS_INFO_7 = *mut DFS_INFO_7; +STRUCT!{struct DFS_INFO_8 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + PropertyFlags: ULONG, + MetadataSize: ULONG, + SdLengthReserved: ULONG, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + NumberOfStorages: DWORD, +}} +pub type PDFS_INFO_8 = *mut DFS_INFO_8; +pub type LPDFS_INFO_8 = *mut DFS_INFO_8; +STRUCT!{struct DFS_INFO_9 { + EntryPath: LPWSTR, + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + Guid: GUID, + PropertyFlags: ULONG, + MetadataSize: ULONG, + SdLengthReserved: ULONG, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + NumberOfStorages: DWORD, + Storage: LPDFS_STORAGE_INFO, +}} +pub type PDFS_INFO_9 = *mut DFS_INFO_9; +pub type LPDFS_INFO_9 = *mut DFS_INFO_9; +pub const DFS_VALID_PROPERTY_FLAGS: ULONG = DFS_PROPERTY_FLAG_INSITE_REFERRALS + | DFS_PROPERTY_FLAG_ROOT_SCALABILITY | DFS_PROPERTY_FLAG_SITE_COSTING + | DFS_PROPERTY_FLAG_TARGET_FAILBACK | DFS_PROPERTY_FLAG_CLUSTER_ENABLED + | DFS_PROPERTY_FLAG_ABDE; +pub const DFS_PROPERTY_FLAG_INSITE_REFERRALS: ULONG = 0x00000001; +pub const DFS_PROPERTY_FLAG_ROOT_SCALABILITY: ULONG = 0x00000002; +pub const DFS_PROPERTY_FLAG_SITE_COSTING: ULONG = 0x00000004; +pub const DFS_PROPERTY_FLAG_TARGET_FAILBACK: ULONG = 0x00000008; +pub const DFS_PROPERTY_FLAG_CLUSTER_ENABLED: ULONG = 0x00000010; +pub const DFS_PROPERTY_FLAG_ABDE: ULONG = 0x00000020; +STRUCT!{struct DFS_INFO_50 { + NamespaceMajorVersion: ULONG, + NamespaceMinorVersion: ULONG, + NamespaceCapabilities: ULONGLONG, +}} +pub type PDFS_INFO_50 = *mut DFS_INFO_50; +pub type LPDFS_INFO_50 = *mut DFS_INFO_50; +STRUCT!{struct DFS_INFO_100 { + Comment: LPWSTR, +}} +pub type PDFS_INFO_100 = *mut DFS_INFO_100; +pub type LPDFS_INFO_100 = *mut DFS_INFO_100; +STRUCT!{struct DFS_INFO_101 { + State: DWORD, +}} +pub type PDFS_INFO_101 = *mut DFS_INFO_101; +pub type LPDFS_INFO_101 = *mut DFS_INFO_101; +STRUCT!{struct DFS_INFO_102 { + Timeout: ULONG, +}} +pub type PDFS_INFO_102 = *mut DFS_INFO_102; +pub type LPDFS_INFO_102 = *mut DFS_INFO_102; +STRUCT!{struct DFS_INFO_103 { + PropertyFlagMask: ULONG, + PropertyFlags: ULONG, +}} +pub type PDFS_INFO_103 = *mut DFS_INFO_103; +pub type LPDFS_INFO_103 = *mut DFS_INFO_103; +STRUCT!{struct DFS_INFO_104 { + TargetPriority: DFS_TARGET_PRIORITY, +}} +pub type PDFS_INFO_104 = *mut DFS_INFO_104; +pub type LPDFS_INFO_104 = *mut DFS_INFO_104; +STRUCT!{struct DFS_INFO_105 { + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + PropertyFlagMask: ULONG, + PropertyFlags: ULONG, +}} +pub type PDFS_INFO_105 = *mut DFS_INFO_105; +pub type LPDFS_INFO_105 = *mut DFS_INFO_105; +STRUCT!{struct DFS_INFO_106 { + State: DWORD, + TargetPriority: DFS_TARGET_PRIORITY, +}} +pub type PDFS_INFO_106 = *mut DFS_INFO_106; +pub type LPDFS_INFO_106 = *mut DFS_INFO_106; +STRUCT!{struct DFS_INFO_107 { + Comment: LPWSTR, + State: DWORD, + Timeout: ULONG, + PropertyFlagMask: ULONG, + PropertyFlags: ULONG, + SdLengthReserved: ULONG, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PDFS_INFO_107 = *mut DFS_INFO_107; +pub type LPDFS_INFO_107 = *mut DFS_INFO_107; +STRUCT!{struct DFS_INFO_150 { + SdLengthReserved: ULONG, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PDFS_INFO_150 = *mut DFS_INFO_150; +pub type LPDFS_INFO_150 = *mut DFS_INFO_150; +STRUCT!{struct DFS_INFO_200 { + FtDfsName: LPWSTR, +}} +pub type PDFS_INFO_200 = *mut DFS_INFO_200; +pub type LPDFS_INFO_200 = *mut DFS_INFO_200; +STRUCT!{struct DFS_INFO_300 { + Flags: DWORD, + DfsName: LPWSTR, +}} +pub type PDFS_INFO_300 = *mut DFS_INFO_300; +pub type LPDFS_INFO_300 = *mut DFS_INFO_300; +extern "system" { + pub fn NetDfsAdd( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + Comment: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; +} +pub const DFS_ADD_VOLUME: DWORD = 1; +pub const DFS_RESTORE_VOLUME: DWORD = 2; +extern "system" { + pub fn NetDfsAddStdRoot( + ServerName: LPWSTR, + RootShare: LPWSTR, + Comment: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; + pub fn NetDfsRemoveStdRoot( + ServerName: LPWSTR, + RootShare: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; + pub fn NetDfsAddFtRoot( + ServerName: LPWSTR, + RootShare: LPWSTR, + FtDfsName: LPWSTR, + Comment: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; + pub fn NetDfsRemoveFtRoot( + ServerName: LPWSTR, + RootShare: LPWSTR, + FtDfsName: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; + pub fn NetDfsRemoveFtRootForced( + DomainName: LPWSTR, + ServerName: LPWSTR, + RootShare: LPWSTR, + FtDfsName: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; +} +pub const NET_DFS_SETDC_FLAGS: DWORD = 0x00000000; +pub const NET_DFS_SETDC_TIMEOUT: DWORD = 0x00000001; +pub const NET_DFS_SETDC_INITPKT: DWORD = 0x00000002; +STRUCT!{struct DFS_SITENAME_INFO { + SiteFlags: ULONG, + SiteName: LPWSTR, +}} +pub type PDFS_SITENAME_INFO = *mut DFS_SITENAME_INFO; +pub type LPDFS_SITENAME_INFO = *mut DFS_SITENAME_INFO; +pub const DFS_SITE_PRIMARY: ULONG = 0x1; +STRUCT!{struct DFS_SITELIST_INFO { + cSites: ULONG, + Site: [DFS_SITENAME_INFO; 1], +}} +pub type PDFS_SITELIST_INFO = *mut DFS_SITELIST_INFO; +pub type LPDFS_SITELIST_INFO = *mut DFS_SITELIST_INFO; +extern "system" { + pub fn NetDfsRemove( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + ) -> NET_API_STATUS; + pub fn NetDfsEnum( + DfsName: LPWSTR, + Level: DWORD, + PrefMaxLen: DWORD, + Buffer: *mut LPBYTE, + EntriesRead: LPDWORD, + ResumeHandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetDfsGetInfo( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + Level: DWORD, + Buffer: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetDfsSetInfo( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + Level: DWORD, + Buffer: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetDfsGetClientInfo( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + Level: DWORD, + Buffer: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetDfsSetClientInfo( + DfsEntryPath: LPWSTR, + ServerName: LPWSTR, + ShareName: LPWSTR, + Level: DWORD, + Buffer: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetDfsMove( + OldDfsEntryPath: LPWSTR, + NewDfsEntryPath: LPWSTR, + Flags: ULONG, + ) -> NET_API_STATUS; +} +pub const DFS_MOVE_FLAG_REPLACE_IF_EXISTS: ULONG = 0x00000001; +extern "system" { + pub fn NetDfsRename( + Path: LPWSTR, + NewPath: LPWSTR, + ) -> NET_API_STATUS; + pub fn NetDfsAddRootTarget( + pDfsPath: LPWSTR, + pTargetPath: LPWSTR, + MajorVersion: ULONG, + pComment: LPWSTR, + Flags: ULONG, + ) -> NET_API_STATUS; +} +pub const DFS_FORCE_REMOVE: ULONG = 0x80000000; +extern "system" { + pub fn NetDfsRemoveRootTarget( + pDfsPath: LPWSTR, + pTargetPath: LPWSTR, + Flags: DWORD, + ) -> NET_API_STATUS; + pub fn NetDfsGetSecurity( + DfsEntryPath: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + lpcbSecurityDescriptor: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetDfsSetSecurity( + DfsEntryPath: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> NET_API_STATUS; + pub fn NetDfsGetStdContainerSecurity( + MachineName: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + lpcbSecurityDescriptor: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetDfsSetStdContainerSecurity( + MachineName: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> NET_API_STATUS; + pub fn NetDfsGetFtContainerSecurity( + DomainName: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + lpcbSecurityDescriptor: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetDfsSetFtContainerSecurity( + DomainName: LPWSTR, + SecurityInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> NET_API_STATUS; +} +ENUM!{enum DFS_NAMESPACE_VERSION_ORIGIN { + DFS_NAMESPACE_VERSION_ORIGIN_COMBINED = 0, + DFS_NAMESPACE_VERSION_ORIGIN_SERVER, + DFS_NAMESPACE_VERSION_ORIGIN_DOMAIN, +}} +pub type PDFS_NAMESPACE_VERSION_ORIGIN = *mut DFS_NAMESPACE_VERSION_ORIGIN; +pub const DFS_NAMESPACE_CAPABILITY_ABDE: ULONGLONG = 0x0000000000000001; +STRUCT!{struct DFS_SUPPORTED_NAMESPACE_VERSION_INFO { + DomainDfsMajorVersion: ULONG, + DomainDfsMinorVersion: ULONG, + DomainDfsCapabilities: ULONGLONG, + StandaloneDfsMajorVersion: ULONG, + StandaloneDfsMinorVersion: ULONG, + StandaloneDfsCapabilities: ULONGLONG, +}} +pub type PDFS_SUPPORTED_NAMESPACE_VERSION_INFO = *mut DFS_SUPPORTED_NAMESPACE_VERSION_INFO; +extern "system" { + pub fn NetDfsGetSupportedNamespaceVersion( + Origin: DFS_NAMESPACE_VERSION_ORIGIN, + pName: PWSTR, + ppVersionInfo: *mut PDFS_SUPPORTED_NAMESPACE_VERSION_INFO, + ) -> NET_API_STATUS; +} +STRUCT!{struct DFS_GET_PKT_ENTRY_STATE_ARG { + DfsEntryPathLen: USHORT, + ServerNameLen: USHORT, + ShareNameLen: USHORT, + Level: ULONG, + Buffer: [WCHAR; 1], +}} +pub type PDFS_GET_PKT_ENTRY_STATE_ARG = *mut DFS_GET_PKT_ENTRY_STATE_ARG; diff --git a/winapi/src/um/lmerrlog.rs b/winapi/src/um/lmerrlog.rs new file mode 100644 index 000000000..8a07f731c --- /dev/null +++ b/winapi/src/um/lmerrlog.rs @@ -0,0 +1,268 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, LPBYTE}; +use um::winnt::LPWSTR; +STRUCT!{struct ERROR_LOG { + el_len: DWORD, + el_reserved: DWORD, + el_time: DWORD, + el_error: DWORD, + el_name: LPWSTR, + el_text: LPWSTR, + el_data: LPBYTE, + el_data_size: DWORD, + el_nstrings: DWORD, +}} +pub type PERROR_LOG = *mut ERROR_LOG; +pub type LPERROR_LOG = *mut ERROR_LOG; +STRUCT!{struct HLOG { + time: DWORD, + last_flags: DWORD, + offset: DWORD, + rec_offset: DWORD, +}} +pub type PHLOG = *mut HLOG; +pub type LPHLOG = *mut HLOG; +pub const LOGFLAGS_FORWARD: DWORD = 0; +pub const LOGFLAGS_BACKWARD: DWORD = 0x1; +pub const LOGFLAGS_SEEK: DWORD = 0x2; +pub const ERRLOG_BASE: DWORD = 3100; +pub const NELOG_Internal_Error: DWORD = ERRLOG_BASE + 0; +pub const NELOG_Resource_Shortage: DWORD = ERRLOG_BASE + 1; +pub const NELOG_Unable_To_Lock_Segment: DWORD = ERRLOG_BASE + 2; +pub const NELOG_Unable_To_Unlock_Segment: DWORD = ERRLOG_BASE + 3; +pub const NELOG_Uninstall_Service: DWORD = ERRLOG_BASE + 4; +pub const NELOG_Init_Exec_Fail: DWORD = ERRLOG_BASE + 5; +pub const NELOG_Ncb_Error: DWORD = ERRLOG_BASE + 6; +pub const NELOG_Net_Not_Started: DWORD = ERRLOG_BASE + 7; +pub const NELOG_Ioctl_Error: DWORD = ERRLOG_BASE + 8; +pub const NELOG_System_Semaphore: DWORD = ERRLOG_BASE + 9; +pub const NELOG_Init_OpenCreate_Err: DWORD = ERRLOG_BASE + 10; +pub const NELOG_NetBios: DWORD = ERRLOG_BASE + 11; +pub const NELOG_SMB_Illegal: DWORD = ERRLOG_BASE + 12; +pub const NELOG_Service_Fail: DWORD = ERRLOG_BASE + 13; +pub const NELOG_Entries_Lost: DWORD = ERRLOG_BASE + 14; +pub const NELOG_Init_Seg_Overflow: DWORD = ERRLOG_BASE + 20; +pub const NELOG_Srv_No_Mem_Grow: DWORD = ERRLOG_BASE + 21; +pub const NELOG_Access_File_Bad: DWORD = ERRLOG_BASE + 22; +pub const NELOG_Srvnet_Not_Started: DWORD = ERRLOG_BASE + 23; +pub const NELOG_Init_Chardev_Err: DWORD = ERRLOG_BASE + 24; +pub const NELOG_Remote_API: DWORD = ERRLOG_BASE + 25; +pub const NELOG_Ncb_TooManyErr: DWORD = ERRLOG_BASE + 26; +pub const NELOG_Mailslot_err: DWORD = ERRLOG_BASE + 27; +pub const NELOG_ReleaseMem_Alert: DWORD = ERRLOG_BASE + 28; +pub const NELOG_AT_cannot_write: DWORD = ERRLOG_BASE + 29; +pub const NELOG_Cant_Make_Msg_File: DWORD = ERRLOG_BASE + 30; +pub const NELOG_Exec_Netservr_NoMem: DWORD = ERRLOG_BASE + 31; +pub const NELOG_Server_Lock_Failure: DWORD = ERRLOG_BASE + 32; +pub const NELOG_Msg_Shutdown: DWORD = ERRLOG_BASE + 40; +pub const NELOG_Msg_Sem_Shutdown: DWORD = ERRLOG_BASE + 41; +pub const NELOG_Msg_Log_Err: DWORD = ERRLOG_BASE + 50; +pub const NELOG_VIO_POPUP_ERR: DWORD = ERRLOG_BASE + 51; +pub const NELOG_Msg_Unexpected_SMB_Type: DWORD = ERRLOG_BASE + 52; +pub const NELOG_Wksta_Infoseg: DWORD = ERRLOG_BASE + 60; +pub const NELOG_Wksta_Compname: DWORD = ERRLOG_BASE + 61; +pub const NELOG_Wksta_BiosThreadFailure: DWORD = ERRLOG_BASE + 62; +pub const NELOG_Wksta_IniSeg: DWORD = ERRLOG_BASE + 63; +pub const NELOG_Wksta_HostTab_Full: DWORD = ERRLOG_BASE + 64; +pub const NELOG_Wksta_Bad_Mailslot_SMB: DWORD = ERRLOG_BASE + 65; +pub const NELOG_Wksta_UASInit: DWORD = ERRLOG_BASE + 66; +pub const NELOG_Wksta_SSIRelogon: DWORD = ERRLOG_BASE + 67; +pub const NELOG_Build_Name: DWORD = ERRLOG_BASE + 70; +pub const NELOG_Name_Expansion: DWORD = ERRLOG_BASE + 71; +pub const NELOG_Message_Send: DWORD = ERRLOG_BASE + 72; +pub const NELOG_Mail_Slt_Err: DWORD = ERRLOG_BASE + 73; +pub const NELOG_AT_cannot_read: DWORD = ERRLOG_BASE + 74; +pub const NELOG_AT_sched_err: DWORD = ERRLOG_BASE + 75; +pub const NELOG_AT_schedule_file_created: DWORD = ERRLOG_BASE + 76; +pub const NELOG_Srvnet_NB_Open: DWORD = ERRLOG_BASE + 77; +pub const NELOG_AT_Exec_Err: DWORD = ERRLOG_BASE + 78; +pub const NELOG_Lazy_Write_Err: DWORD = ERRLOG_BASE + 80; +pub const NELOG_HotFix: DWORD = ERRLOG_BASE + 81; +pub const NELOG_HardErr_From_Server: DWORD = ERRLOG_BASE + 82; +pub const NELOG_LocalSecFail1: DWORD = ERRLOG_BASE + 83; +pub const NELOG_LocalSecFail2: DWORD = ERRLOG_BASE + 84; +pub const NELOG_LocalSecFail3: DWORD = ERRLOG_BASE + 85; +pub const NELOG_LocalSecGeneralFail: DWORD = ERRLOG_BASE + 86; +pub const NELOG_NetWkSta_Internal_Error: DWORD = ERRLOG_BASE + 90; +pub const NELOG_NetWkSta_No_Resource: DWORD = ERRLOG_BASE + 91; +pub const NELOG_NetWkSta_SMB_Err: DWORD = ERRLOG_BASE + 92; +pub const NELOG_NetWkSta_VC_Err: DWORD = ERRLOG_BASE + 93; +pub const NELOG_NetWkSta_Stuck_VC_Err: DWORD = ERRLOG_BASE + 94; +pub const NELOG_NetWkSta_NCB_Err: DWORD = ERRLOG_BASE + 95; +pub const NELOG_NetWkSta_Write_Behind_Err: DWORD = ERRLOG_BASE + 96; +pub const NELOG_NetWkSta_Reset_Err: DWORD = ERRLOG_BASE + 97; +pub const NELOG_NetWkSta_Too_Many: DWORD = ERRLOG_BASE + 98; +pub const NELOG_Srv_Thread_Failure: DWORD = ERRLOG_BASE + 104; +pub const NELOG_Srv_Close_Failure: DWORD = ERRLOG_BASE + 105; +pub const NELOG_ReplUserCurDir: DWORD = ERRLOG_BASE + 106; +pub const NELOG_ReplCannotMasterDir: DWORD = ERRLOG_BASE + 107; +pub const NELOG_ReplUpdateError: DWORD = ERRLOG_BASE + 108; +pub const NELOG_ReplLostMaster: DWORD = ERRLOG_BASE + 109; +pub const NELOG_NetlogonAuthDCFail: DWORD = ERRLOG_BASE + 110; +pub const NELOG_ReplLogonFailed: DWORD = ERRLOG_BASE + 111; +pub const NELOG_ReplNetErr: DWORD = ERRLOG_BASE + 112; +pub const NELOG_ReplMaxFiles: DWORD = ERRLOG_BASE + 113; +pub const NELOG_ReplMaxTreeDepth: DWORD = ERRLOG_BASE + 114; +pub const NELOG_ReplBadMsg: DWORD = ERRLOG_BASE + 115; +pub const NELOG_ReplSysErr: DWORD = ERRLOG_BASE + 116; +pub const NELOG_ReplUserLoged: DWORD = ERRLOG_BASE + 117; +pub const NELOG_ReplBadImport: DWORD = ERRLOG_BASE + 118; +pub const NELOG_ReplBadExport: DWORD = ERRLOG_BASE + 119; +pub const NELOG_ReplSignalFileErr: DWORD = ERRLOG_BASE + 120; +pub const NELOG_DiskFT: DWORD = ERRLOG_BASE + 121; +pub const NELOG_ReplAccessDenied: DWORD = ERRLOG_BASE + 122; +pub const NELOG_NetlogonFailedPrimary: DWORD = ERRLOG_BASE + 123; +pub const NELOG_NetlogonPasswdSetFailed: DWORD = ERRLOG_BASE + 124; +pub const NELOG_NetlogonTrackingError: DWORD = ERRLOG_BASE + 125; +pub const NELOG_NetlogonSyncError: DWORD = ERRLOG_BASE + 126; +pub const NELOG_NetlogonRequireSignOrSealError: DWORD = ERRLOG_BASE + 127; +pub const NELOG_UPS_PowerOut: DWORD = ERRLOG_BASE + 130; +pub const NELOG_UPS_Shutdown: DWORD = ERRLOG_BASE + 131; +pub const NELOG_UPS_CmdFileError: DWORD = ERRLOG_BASE + 132; +pub const NELOG_UPS_CannotOpenDriver: DWORD = ERRLOG_BASE + 133; +pub const NELOG_UPS_PowerBack: DWORD = ERRLOG_BASE + 134; +pub const NELOG_UPS_CmdFileConfig: DWORD = ERRLOG_BASE + 135; +pub const NELOG_UPS_CmdFileExec: DWORD = ERRLOG_BASE + 136; +pub const NELOG_Missing_Parameter: DWORD = ERRLOG_BASE + 150; +pub const NELOG_Invalid_Config_Line: DWORD = ERRLOG_BASE + 151; +pub const NELOG_Invalid_Config_File: DWORD = ERRLOG_BASE + 152; +pub const NELOG_File_Changed: DWORD = ERRLOG_BASE + 153; +pub const NELOG_Files_Dont_Fit: DWORD = ERRLOG_BASE + 154; +pub const NELOG_Wrong_DLL_Version: DWORD = ERRLOG_BASE + 155; +pub const NELOG_Error_in_DLL: DWORD = ERRLOG_BASE + 156; +pub const NELOG_System_Error: DWORD = ERRLOG_BASE + 157; +pub const NELOG_FT_ErrLog_Too_Large: DWORD = ERRLOG_BASE + 158; +pub const NELOG_FT_Update_In_Progress: DWORD = ERRLOG_BASE + 159; +pub const NELOG_Joined_Domain: DWORD = ERRLOG_BASE + 160; +pub const NELOG_Joined_Workgroup: DWORD = ERRLOG_BASE + 161; +pub const NELOG_OEM_Code: DWORD = ERRLOG_BASE + 199; +pub const ERRLOG2_BASE: DWORD = 5700; +pub const NELOG_NetlogonSSIInitError: DWORD = ERRLOG2_BASE + 0; +pub const NELOG_NetlogonFailedToUpdateTrustList: DWORD = ERRLOG2_BASE + 1; +pub const NELOG_NetlogonFailedToAddRpcInterface: DWORD = ERRLOG2_BASE + 2; +pub const NELOG_NetlogonFailedToReadMailslot: DWORD = ERRLOG2_BASE + 3; +pub const NELOG_NetlogonFailedToRegisterSC: DWORD = ERRLOG2_BASE + 4; +pub const NELOG_NetlogonChangeLogCorrupt: DWORD = ERRLOG2_BASE + 5; +pub const NELOG_NetlogonFailedToCreateShare: DWORD = ERRLOG2_BASE + 6; +pub const NELOG_NetlogonDownLevelLogonFailed: DWORD = ERRLOG2_BASE + 7; +pub const NELOG_NetlogonDownLevelLogoffFailed: DWORD = ERRLOG2_BASE + 8; +pub const NELOG_NetlogonNTLogonFailed: DWORD = ERRLOG2_BASE + 9; +pub const NELOG_NetlogonNTLogoffFailed: DWORD = ERRLOG2_BASE + 10; +pub const NELOG_NetlogonPartialSyncCallSuccess: DWORD = ERRLOG2_BASE + 11; +pub const NELOG_NetlogonPartialSyncCallFailed: DWORD = ERRLOG2_BASE + 12; +pub const NELOG_NetlogonFullSyncCallSuccess: DWORD = ERRLOG2_BASE + 13; +pub const NELOG_NetlogonFullSyncCallFailed: DWORD = ERRLOG2_BASE + 14; +pub const NELOG_NetlogonPartialSyncSuccess: DWORD = ERRLOG2_BASE + 15; +pub const NELOG_NetlogonPartialSyncFailed: DWORD = ERRLOG2_BASE + 16; +pub const NELOG_NetlogonFullSyncSuccess: DWORD = ERRLOG2_BASE + 17; +pub const NELOG_NetlogonFullSyncFailed: DWORD = ERRLOG2_BASE + 18; +pub const NELOG_NetlogonAuthNoDomainController: DWORD = ERRLOG2_BASE + 19; +pub const NELOG_NetlogonAuthNoTrustLsaSecret: DWORD = ERRLOG2_BASE + 20; +pub const NELOG_NetlogonAuthNoTrustSamAccount: DWORD = ERRLOG2_BASE + 21; +pub const NELOG_NetlogonServerAuthFailed: DWORD = ERRLOG2_BASE + 22; +pub const NELOG_NetlogonServerAuthNoTrustSamAccount: DWORD = ERRLOG2_BASE + 23; +pub const NELOG_FailedToRegisterSC: DWORD = ERRLOG2_BASE + 24; +pub const NELOG_FailedToSetServiceStatus: DWORD = ERRLOG2_BASE + 25; +pub const NELOG_FailedToGetComputerName: DWORD = ERRLOG2_BASE + 26; +pub const NELOG_DriverNotLoaded: DWORD = ERRLOG2_BASE + 27; +pub const NELOG_NoTranportLoaded: DWORD = ERRLOG2_BASE + 28; +pub const NELOG_NetlogonFailedDomainDelta: DWORD = ERRLOG2_BASE + 29; +pub const NELOG_NetlogonFailedGlobalGroupDelta: DWORD = ERRLOG2_BASE + 30; +pub const NELOG_NetlogonFailedLocalGroupDelta: DWORD = ERRLOG2_BASE + 31; +pub const NELOG_NetlogonFailedUserDelta: DWORD = ERRLOG2_BASE + 32; +pub const NELOG_NetlogonFailedPolicyDelta: DWORD = ERRLOG2_BASE + 33; +pub const NELOG_NetlogonFailedTrustedDomainDelta: DWORD = ERRLOG2_BASE + 34; +pub const NELOG_NetlogonFailedAccountDelta: DWORD = ERRLOG2_BASE + 35; +pub const NELOG_NetlogonFailedSecretDelta: DWORD = ERRLOG2_BASE + 36; +pub const NELOG_NetlogonSystemError: DWORD = ERRLOG2_BASE + 37; +pub const NELOG_NetlogonDuplicateMachineAccounts: DWORD = ERRLOG2_BASE + 38; +pub const NELOG_NetlogonTooManyGlobalGroups: DWORD = ERRLOG2_BASE + 39; +pub const NELOG_NetlogonBrowserDriver: DWORD = ERRLOG2_BASE + 40; +pub const NELOG_NetlogonAddNameFailure: DWORD = ERRLOG2_BASE + 41; +pub const NELOG_RplMessages: DWORD = ERRLOG2_BASE + 42; +pub const NELOG_RplXnsBoot: DWORD = ERRLOG2_BASE + 43; +pub const NELOG_RplSystem: DWORD = ERRLOG2_BASE + 44; +pub const NELOG_RplWkstaTimeout: DWORD = ERRLOG2_BASE + 45; +pub const NELOG_RplWkstaFileOpen: DWORD = ERRLOG2_BASE + 46; +pub const NELOG_RplWkstaFileRead: DWORD = ERRLOG2_BASE + 47; +pub const NELOG_RplWkstaMemory: DWORD = ERRLOG2_BASE + 48; +pub const NELOG_RplWkstaFileChecksum: DWORD = ERRLOG2_BASE + 49; +pub const NELOG_RplWkstaFileLineCount: DWORD = ERRLOG2_BASE + 50; +pub const NELOG_RplWkstaBbcFile: DWORD = ERRLOG2_BASE + 51; +pub const NELOG_RplWkstaFileSize: DWORD = ERRLOG2_BASE + 52; +pub const NELOG_RplWkstaInternal: DWORD = ERRLOG2_BASE + 53; +pub const NELOG_RplWkstaWrongVersion: DWORD = ERRLOG2_BASE + 54; +pub const NELOG_RplWkstaNetwork: DWORD = ERRLOG2_BASE + 55; +pub const NELOG_RplAdapterResource: DWORD = ERRLOG2_BASE + 56; +pub const NELOG_RplFileCopy: DWORD = ERRLOG2_BASE + 57; +pub const NELOG_RplFileDelete: DWORD = ERRLOG2_BASE + 58; +pub const NELOG_RplFilePerms: DWORD = ERRLOG2_BASE + 59; +pub const NELOG_RplCheckConfigs: DWORD = ERRLOG2_BASE + 60; +pub const NELOG_RplCreateProfiles: DWORD = ERRLOG2_BASE + 61; +pub const NELOG_RplRegistry: DWORD = ERRLOG2_BASE + 62; +pub const NELOG_RplReplaceRPLDISK: DWORD = ERRLOG2_BASE + 63; +pub const NELOG_RplCheckSecurity: DWORD = ERRLOG2_BASE + 64; +pub const NELOG_RplBackupDatabase: DWORD = ERRLOG2_BASE + 65; +pub const NELOG_RplInitDatabase: DWORD = ERRLOG2_BASE + 66; +pub const NELOG_RplRestoreDatabaseFailure: DWORD = ERRLOG2_BASE + 67; +pub const NELOG_RplRestoreDatabaseSuccess: DWORD = ERRLOG2_BASE + 68; +pub const NELOG_RplInitRestoredDatabase: DWORD = ERRLOG2_BASE + 69; +pub const NELOG_NetlogonSessionTypeWrong: DWORD = ERRLOG2_BASE + 70; +pub const NELOG_RplUpgradeDBTo40: DWORD = ERRLOG2_BASE + 71; +pub const NELOG_NetlogonLanmanBdcsNotAllowed: DWORD = ERRLOG2_BASE + 72; +pub const NELOG_NetlogonNoDynamicDns: DWORD = ERRLOG2_BASE + 73; +pub const NELOG_NetlogonDynamicDnsRegisterFailure: DWORD = ERRLOG2_BASE + 74; +pub const NELOG_NetlogonDynamicDnsDeregisterFailure: DWORD = ERRLOG2_BASE + 75; +pub const NELOG_NetlogonFailedFileCreate: DWORD = ERRLOG2_BASE + 76; +pub const NELOG_NetlogonGetSubnetToSite: DWORD = ERRLOG2_BASE + 77; +pub const NELOG_NetlogonNoSiteForClient: DWORD = ERRLOG2_BASE + 78; +pub const NELOG_NetlogonBadSiteName: DWORD = ERRLOG2_BASE + 79; +pub const NELOG_NetlogonBadSubnetName: DWORD = ERRLOG2_BASE + 80; +pub const NELOG_NetlogonDynamicDnsServerFailure: DWORD = ERRLOG2_BASE + 81; +pub const NELOG_NetlogonDynamicDnsFailure: DWORD = ERRLOG2_BASE + 82; +pub const NELOG_NetlogonRpcCallCancelled: DWORD = ERRLOG2_BASE + 83; +pub const NELOG_NetlogonDcSiteCovered: DWORD = ERRLOG2_BASE + 84; +pub const NELOG_NetlogonDcSiteNotCovered: DWORD = ERRLOG2_BASE + 85; +pub const NELOG_NetlogonGcSiteCovered: DWORD = ERRLOG2_BASE + 86; +pub const NELOG_NetlogonGcSiteNotCovered: DWORD = ERRLOG2_BASE + 87; +pub const NELOG_NetlogonFailedSpnUpdate: DWORD = ERRLOG2_BASE + 88; +pub const NELOG_NetlogonFailedDnsHostNameUpdate: DWORD = ERRLOG2_BASE + 89; +pub const NELOG_NetlogonAuthNoUplevelDomainController: DWORD = ERRLOG2_BASE + 90; +pub const NELOG_NetlogonAuthDomainDowngraded: DWORD = ERRLOG2_BASE + 91; +pub const NELOG_NetlogonNdncSiteCovered: DWORD = ERRLOG2_BASE + 92; +pub const NELOG_NetlogonNdncSiteNotCovered: DWORD = ERRLOG2_BASE + 93; +pub const NELOG_NetlogonDcOldSiteCovered: DWORD = ERRLOG2_BASE + 94; +pub const NELOG_NetlogonDcSiteNotCoveredAuto: DWORD = ERRLOG2_BASE + 95; +pub const NELOG_NetlogonGcOldSiteCovered: DWORD = ERRLOG2_BASE + 96; +pub const NELOG_NetlogonGcSiteNotCoveredAuto: DWORD = ERRLOG2_BASE + 97; +pub const NELOG_NetlogonNdncOldSiteCovered: DWORD = ERRLOG2_BASE + 98; +pub const NELOG_NetlogonNdncSiteNotCoveredAuto: DWORD = ERRLOG2_BASE + 99; +pub const NELOG_NetlogonSpnMultipleSamAccountNames: DWORD = ERRLOG2_BASE + 100; +pub const NELOG_NetlogonSpnCrackNamesFailure: DWORD = ERRLOG2_BASE + 101; +pub const NELOG_NetlogonNoAddressToSiteMapping: DWORD = ERRLOG2_BASE + 102; +pub const NELOG_NetlogonInvalidGenericParameterValue: DWORD = ERRLOG2_BASE + 103; +pub const NELOG_NetlogonInvalidDwordParameterValue: DWORD = ERRLOG2_BASE + 104; +pub const NELOG_NetlogonServerAuthFailedNoAccount: DWORD = ERRLOG2_BASE + 105; +pub const NELOG_NetlogonNoDynamicDnsManual: DWORD = ERRLOG2_BASE + 106; +pub const NELOG_NetlogonNoSiteForClients: DWORD = ERRLOG2_BASE + 107; +pub const NELOG_NetlogonDnsDeregAborted: DWORD = ERRLOG2_BASE + 108; +pub const NELOG_NetlogonRpcPortRequestFailure: DWORD = ERRLOG2_BASE + 109; +pub const NELOG_NetlogonPartialSiteMappingForClients: DWORD = ERRLOG2_BASE + 110; +pub const NELOG_NetlogonRemoteDynamicDnsRegisterFailure: DWORD = ERRLOG2_BASE + 111; +pub const NELOG_NetlogonRemoteDynamicDnsDeregisterFailure: DWORD = ERRLOG2_BASE + 112; +pub const NELOG_NetlogonRejectedRemoteDynamicDnsRegister: DWORD = ERRLOG2_BASE + 113; +pub const NELOG_NetlogonRejectedRemoteDynamicDnsDeregister: DWORD = ERRLOG2_BASE + 114; +pub const NELOG_NetlogonRemoteDynamicDnsUpdateRequestFailure: DWORD = ERRLOG2_BASE + 115; +pub const NELOG_NetlogonUserValidationReqInitialTimeOut: DWORD = ERRLOG2_BASE + 116; +pub const NELOG_NetlogonUserValidationReqRecurringTimeOut: DWORD = ERRLOG2_BASE + 117; +pub const NELOG_NetlogonUserValidationReqWaitInitialWarning: DWORD = ERRLOG2_BASE + 118; +pub const NELOG_NetlogonUserValidationReqWaitRecurringWarning: DWORD = ERRLOG2_BASE + 119; +pub const NELOG_NetlogonFailedToAddAuthzRpcInterface: DWORD = ERRLOG2_BASE + 120; +pub const NELOG_NetLogonFailedToInitializeAuthzRm: DWORD = ERRLOG2_BASE + 121; +pub const NELOG_NetLogonFailedToInitializeRPCSD: DWORD = ERRLOG2_BASE + 122; +pub const NELOG_NetlogonMachinePasswdSetSucceeded: DWORD = ERRLOG2_BASE + 123; +pub const NELOG_NetlogonMsaPasswdSetSucceeded: DWORD = ERRLOG2_BASE + 124; diff --git a/winapi/src/um/lmjoin.rs b/winapi/src/um/lmjoin.rs new file mode 100644 index 000000000..72c72c0ee --- /dev/null +++ b/winapi/src/um/lmjoin.rs @@ -0,0 +1,232 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +// Definitions and prototypes for the Net setup apis +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{BYTE, DWORD, PBYTE, PDWORD, ULONG}; +use um::wincrypt::PCCERT_CONTEXT; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, PVOID}; +ENUM!{enum NETSETUP_NAME_TYPE { + NetSetupUnknown = 0, + NetSetupMachine, + NetSetupWorkgroup, + NetSetupDomain, + NetSetupNonExistentDomain, + NetSetupDnsMachine, +}} +pub type PNETSETUP_NAME_TYPE = *mut NETSETUP_NAME_TYPE; +ENUM!{enum DSREG_JOIN_TYPE { + DSREG_UNKNOWN_JOIN = 0, + DSREG_DEVICE_JOIN = 1, + DSREG_WORKPLACE_JOIN = 2, +}} +pub type PDSREG_JOIN_TYPE = *mut DSREG_JOIN_TYPE; +STRUCT!{struct DSREG_USER_INFO { + pszUserEmail: LPWSTR, + pszUserKeyId: LPWSTR, + pszUserKeyName: LPWSTR, +}} +pub type PDSREG_USER_INFO = *mut DSREG_USER_INFO; +STRUCT!{struct DSREG_JOIN_INFO { + joinType: DSREG_JOIN_TYPE, + pJoinCertificate: PCCERT_CONTEXT, + pszDeviceId: LPWSTR, + pszIdpDomain: LPWSTR, + pszTenantId: LPWSTR, + pszJoinUserEmail: LPWSTR, + pszTenantDisplayName: LPWSTR, + pszMdmEnrollmentUrl: LPWSTR, + pszMdmTermsOfUseUrl: LPWSTR, + pszMdmComplianceUrl: LPWSTR, + pszUserSettingSyncUrl: LPWSTR, + pUserInfo: *mut DSREG_USER_INFO, +}} +pub type PDSREG_JOIN_INFO = *mut DSREG_JOIN_INFO; +pub const NETSETUP_JOIN_DOMAIN: DWORD = 0x00000001; +pub const NETSETUP_ACCT_CREATE: DWORD = 0x00000002; +pub const NETSETUP_ACCT_DELETE: DWORD = 0x00000004; +pub const NETSETUP_WIN9X_UPGRADE: DWORD = 0x00000010; +pub const NETSETUP_DOMAIN_JOIN_IF_JOINED: DWORD = 0x00000020; +pub const NETSETUP_JOIN_UNSECURE: DWORD = 0x00000040; +pub const NETSETUP_MACHINE_PWD_PASSED: DWORD = 0x00000080; +pub const NETSETUP_DEFER_SPN_SET: DWORD = 0x00000100; +pub const NETSETUP_JOIN_DC_ACCOUNT: DWORD = 0x00000200; +pub const NETSETUP_JOIN_WITH_NEW_NAME: DWORD = 0x00000400; +pub const NETSETUP_JOIN_READONLY: DWORD = 0x00000800; +pub const NETSETUP_DNS_NAME_CHANGES_ONLY: DWORD = 0x00001000; +pub const NETSETUP_INSTALL_INVOCATION: DWORD = 0x00040000; +pub const NETSETUP_AMBIGUOUS_DC: DWORD = 0x00001000; +pub const NETSETUP_NO_NETLOGON_CACHE: DWORD = 0x00002000; +pub const NETSETUP_DONT_CONTROL_SERVICES: DWORD = 0x00004000; +pub const NETSETUP_SET_MACHINE_NAME: DWORD = 0x00008000; +pub const NETSETUP_FORCE_SPN_SET: DWORD = 0x00010000; +pub const NETSETUP_NO_ACCT_REUSE: DWORD = 0x00020000; +pub const NETSETUP_ALT_SAMACCOUNTNAME: DWORD = 0x00020000; +pub const NETSETUP_IGNORE_UNSUPPORTED_FLAGS: DWORD = 0x10000000; +pub const NETSETUP_VALID_UNJOIN_FLAGS: DWORD = NETSETUP_ACCT_DELETE + | NETSETUP_IGNORE_UNSUPPORTED_FLAGS | NETSETUP_JOIN_DC_ACCOUNT; +pub const NETSETUP_PROCESS_OFFLINE_FLAGS: DWORD = NETSETUP_JOIN_DOMAIN + | NETSETUP_DOMAIN_JOIN_IF_JOINED | NETSETUP_JOIN_WITH_NEW_NAME | NETSETUP_DONT_CONTROL_SERVICES + | NETSETUP_MACHINE_PWD_PASSED; +extern "system" { + pub fn NetJoinDomain( + lpServer: LPCWSTR, + lpDomain: LPCWSTR, + lpMachineAccountOU: LPCWSTR, + lpAccount: LPCWSTR, + lpPassword: LPCWSTR, + fJoinOptions: DWORD, + ) -> NET_API_STATUS; + pub fn NetUnjoinDomain( + lpServer: LPCWSTR, + lpAccount: LPCWSTR, + lpPassword: LPCWSTR, + fUnjoinOptions: DWORD, + ) -> NET_API_STATUS; + pub fn NetRenameMachineInDomain( + lpServer: LPCWSTR, + lpNewMachineName: LPCWSTR, + lpAccount: LPCWSTR, + lpPassword: LPCWSTR, + fRenameOptions: DWORD, + ) -> NET_API_STATUS; + pub fn NetValidateName( + lpServer: LPCWSTR, + lpName: LPCWSTR, + lpAccount: LPCWSTR, + lpPassword: LPCWSTR, + NameType: NETSETUP_NAME_TYPE, + ) -> NET_API_STATUS; + pub fn NetGetJoinableOUs( + lpServer: LPCWSTR, + lpDomain: LPCWSTR, + lpAccount: LPCWSTR, + lpPassword: LPCWSTR, + OUCount: *mut DWORD, + OUs: *mut *mut LPWSTR, + ) -> NET_API_STATUS; +} +pub const NET_IGNORE_UNSUPPORTED_FLAGS: DWORD = 0x01; +extern "system" { + pub fn NetAddAlternateComputerName( + Server: LPCWSTR, + AlternateName: LPCWSTR, + DomainAccount: LPCWSTR, + DomainAccountPassword: LPCWSTR, + Reserved: ULONG, + ) -> NET_API_STATUS; + pub fn NetRemoveAlternateComputerName( + Server: LPCWSTR, + AlternateName: LPCWSTR, + DomainAccount: LPCWSTR, + DomainAccountPassword: LPCWSTR, + Reserved: ULONG, + ) -> NET_API_STATUS; + pub fn NetSetPrimaryComputerName( + Server: LPCWSTR, + PrimaryName: LPCWSTR, + DomainAccount: LPCWSTR, + DomainAccountPassword: LPCWSTR, + Reserved: ULONG, + ) -> NET_API_STATUS; +} +ENUM!{enum NET_COMPUTER_NAME_TYPE { + NetPrimaryComputerName, + NetAlternateComputerNames, + NetAllComputerNames, + NetComputerNameTypeMax, +}} +pub type PNET_COMPUTER_NAME_TYPE = *mut NET_COMPUTER_NAME_TYPE; +extern "system" { + pub fn NetEnumerateComputerNames( + Server: LPCWSTR, + NameType: NET_COMPUTER_NAME_TYPE, + Reserved: ULONG, + EntryCount: PDWORD, + ComputerNames: *mut *mut LPWSTR, + ) -> NET_API_STATUS; +} +pub const NETSETUP_PROVISION_DOWNLEVEL_PRIV_SUPPORT: DWORD = 0x00000001; +pub const NETSETUP_PROVISION_REUSE_ACCOUNT: DWORD = 0x00000002; +pub const NETSETUP_PROVISION_USE_DEFAULT_PASSWORD: DWORD = 0x00000004; +pub const NETSETUP_PROVISION_SKIP_ACCOUNT_SEARCH: DWORD = 0x00000008; +pub const NETSETUP_PROVISION_ROOT_CA_CERTS: DWORD = 0x00000010; +pub const NETSETUP_PROVISION_PERSISTENTSITE: DWORD = 0x00000020; +pub const NETSETUP_PROVISION_ONLINE_CALLER: DWORD = 0x40000000; +pub const NETSETUP_PROVISION_CHECK_PWD_ONLY: DWORD = 0x80000000; +extern "system" { + pub fn NetProvisionComputerAccount( + lpDomain: LPCWSTR, + lpMachineName: LPCWSTR, + lpMachineAccountOU: LPCWSTR, + lpDcName: LPCWSTR, + dwOptions: DWORD, + pProvisionBinData: *mut PBYTE, + pdwProvisionBinDataSize: *mut DWORD, + pProvisionTextData: *mut LPWSTR, + ) -> NET_API_STATUS; + pub fn NetRequestOfflineDomainJoin( + pProvisionBinData: *mut BYTE, + cbProvisionBinDataSize: DWORD, + dwOptions: DWORD, + lpWindowsPath: LPCWSTR, + ) -> NET_API_STATUS; +} +pub const NETSETUP_PROVISIONING_PARAMS_WIN8_VERSION: DWORD = 0x00000001; +pub const NETSETUP_PROVISIONING_PARAMS_CURRENT_VERSION: DWORD = 0x00000002; +STRUCT!{struct NETSETUP_PROVISIONING_PARAMS { + dwVersion: DWORD, + lpDomain: LPCWSTR, + lpHostName: LPCWSTR, + lpMachineAccountOU: LPCWSTR, + lpDcName: LPCWSTR, + dwProvisionOptions: DWORD, + aCertTemplateNames: *mut LPCWSTR, + cCertTemplateNames: DWORD, + aMachinePolicyNames: *mut LPCWSTR, + cMachinePolicyNames: DWORD, + aMachinePolicyPaths: *mut LPCWSTR, + cMachinePolicyPaths: DWORD, + lpNetbiosName: LPWSTR, + lpSiteName: LPWSTR, + lpPrimaryDNSDomain: LPWSTR, +}} +pub type PNETSETUP_PROVISIONING_PARAMS = *mut NETSETUP_PROVISIONING_PARAMS; +extern "system" { + pub fn NetCreateProvisioningPackage( + pProvisioningParams: PNETSETUP_PROVISIONING_PARAMS, + ppPackageBinData: *mut PBYTE, + pdwPackageBinDataSize: *mut DWORD, + ppPackageTextData: *mut LPWSTR, + ) -> NET_API_STATUS; + pub fn NetRequestProvisioningPackageInstall( + pPackageBinData: *mut BYTE, + dwPackageBinDataSize: DWORD, + dwProvisionOptions: DWORD, + lpWindowsPath: LPCWSTR, + pvReserved: PVOID, + ) -> NET_API_STATUS; + pub fn NetGetAadJoinInformation( + pcszTenantId: LPCWSTR, + ppJoinInfo: *mut PDSREG_JOIN_INFO, + ) -> HRESULT; + pub fn NetFreeAadJoinInformation( + pJoinInfo: PDSREG_JOIN_INFO, + ); +} +ENUM!{enum NETSETUP_JOIN_STATUS { + NetSetupUnknownStatus = 0, + NetSetupUnjoined, + NetSetupWorkgroupName, + NetSetupDomainName, +}} +pub type PNETSETUP_JOIN_STATUS = *mut NETSETUP_JOIN_STATUS; +extern "system" { + pub fn NetGetJoinInformation( + lpServer: LPCWSTR, + lpNameBuffer: *mut LPWSTR, + BufferType: PNETSETUP_JOIN_STATUS, + ) -> NET_API_STATUS; +} diff --git a/winapi/src/um/lmmsg.rs b/winapi/src/um/lmmsg.rs new file mode 100644 index 000000000..9970fe94e --- /dev/null +++ b/winapi/src/um/lmmsg.rs @@ -0,0 +1,56 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains structures, function prototypes, and definitions for the NetMessage API +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD}; +use um::winnt::{LPCWSTR, LPWSTR}; +extern "system" { + pub fn NetMessageNameAdd( + servername: LPCWSTR, + msgname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetMessageNameEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetMessageNameGetInfo( + servername: LPCWSTR, + msgname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetMessageNameDel( + servername: LPCWSTR, + msgname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetMessageBufferSend( + servername: LPCWSTR, + msgname: LPCWSTR, + fromname: LPCWSTR, + buf: LPBYTE, + buflen: DWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct MSG_INFO_0 { + msgi0_name: LPWSTR, +}} +pub type PMSG_INFO_0 = *mut MSG_INFO_0; +pub type LPMSG_INFO_0 = *mut MSG_INFO_0; +STRUCT!{struct MSG_INFO_1 { + msgi1_name: LPWSTR, + msgi1_forward_flag: DWORD, + msgi1_forward: LPWSTR, +}} +pub type PMSG_INFO_1 = *mut MSG_INFO_1; +pub type LPMSG_INFO_1 = *mut MSG_INFO_1; +pub const MSGNAME_NOT_FORWARDED: DWORD = 0; +pub const MSGNAME_FORWARDED_TO: DWORD = 0x04; +pub const MSGNAME_FORWARDED_FROM: DWORD = 0x10; diff --git a/winapi/src/um/lmremutl.rs b/winapi/src/um/lmremutl.rs new file mode 100644 index 000000000..27275203b --- /dev/null +++ b/winapi/src/um/lmremutl.rs @@ -0,0 +1,61 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains structures, function prototypes, and definitions for the NetRemote API +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD}; +use um::winnt::{CHAR, LONG, LPCWSTR, LPSTR}; +pub type DESC_CHAR = CHAR; +pub type LPDESC = LPSTR; +extern "system" { + pub fn NetRemoteTOD( + UncServerName: LPCWSTR, + BufferPtr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetRemoteComputerSupports( + UncServerName: LPCWSTR, + OptionsWanted: DWORD, + OptionsSupported: LPDWORD, + ) -> NET_API_STATUS; +} +extern "C" { + pub fn RxRemoteApi( + ApiNumber: DWORD, + UncServerName: LPCWSTR, + ParmDescString: LPDESC, + DataDesc16: LPDESC, + DataDesc32: LPDESC, + DataDescSmb: LPDESC, + AuxDesc16: LPDESC, + AuxDesc32: LPDESC, + AuxDescSmb: LPDESC, + Flags: DWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct TIME_OF_DAY_INFO { + tod_elapsedt: DWORD, + tod_msecs: DWORD, + tod_hours: DWORD, + tod_mins: DWORD, + tod_secs: DWORD, + tod_hunds: DWORD, + tod_timezone: LONG, + tod_tinterval: DWORD, + tod_day: DWORD, + tod_month: DWORD, + tod_year: DWORD, + tod_weekday: DWORD, +}} +pub type PTIME_OF_DAY_INFO = *mut TIME_OF_DAY_INFO; +pub type LPTIME_OF_DAY_INFO = *mut TIME_OF_DAY_INFO; +pub const SUPPORTS_REMOTE_ADMIN_PROTOCOL: DWORD = 0x00000002; +pub const SUPPORTS_RPC: DWORD = 0x00000004; +pub const SUPPORTS_SAM_PROTOCOL: DWORD = 0x00000008; +pub const SUPPORTS_UNICODE: DWORD = 0x00000010; +pub const SUPPORTS_LOCAL: DWORD = 0x00000020; +pub const SUPPORTS_ANY: DWORD = 0xFFFFFFFF; +pub const NO_PERMISSION_REQUIRED: DWORD = 0x00000001; +pub const ALLOCATE_RESPONSE: DWORD = 0x00000002; +pub const USE_SPECIFIC_TRANSPORT: DWORD = 0x80000000; diff --git a/winapi/src/um/lmrepl.rs b/winapi/src/um/lmrepl.rs new file mode 100644 index 000000000..81a665be5 --- /dev/null +++ b/winapi/src/um/lmrepl.rs @@ -0,0 +1,200 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains structures, function prototypes, and definitions for the replicator APIs +use shared::lmcons::{NET_API_STATUS, PARMNUM_BASE_INFOLEVEL}; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD}; +use um::winnt::{LPCWSTR, LPWSTR}; +pub const REPL_ROLE_EXPORT: DWORD = 1; +pub const REPL_ROLE_IMPORT: DWORD = 2; +pub const REPL_ROLE_BOTH: DWORD = 3; +pub const REPL_INTERVAL_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 0; +pub const REPL_PULSE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 1; +pub const REPL_GUARDTIME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 2; +pub const REPL_RANDOM_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 3; +STRUCT!{struct REPL_INFO_0 { + rp0_role: DWORD, + rp0_exportpath: LPWSTR, + rp0_exportlist: LPWSTR, + rp0_importpath: LPWSTR, + rp0_importlist: LPWSTR, + rp0_logonusername: LPWSTR, + rp0_interval: DWORD, + rp0_pulse: DWORD, + rp0_guardtime: DWORD, + rp0_random: DWORD, +}} +pub type PREPL_INFO_0 = *mut REPL_INFO_0; +pub type LPREPL_INFO_0 = *mut REPL_INFO_0; +STRUCT!{struct REPL_INFO_1000 { + rp1000_interval: DWORD, +}} +pub type PREPL_INFO_1000 = *mut REPL_INFO_1000; +pub type LPREPL_INFO_1000 = *mut REPL_INFO_1000; +STRUCT!{struct REPL_INFO_1001 { + rp1001_pulse: DWORD, +}} +pub type PREPL_INFO_1001 = *mut REPL_INFO_1001; +pub type LPREPL_INFO_1001 = *mut REPL_INFO_1001; +STRUCT!{struct REPL_INFO_1002 { + rp1002_guardtime: DWORD, +}} +pub type PREPL_INFO_1002 = *mut REPL_INFO_1002; +pub type LPREPL_INFO_1002 = *mut REPL_INFO_1002; +STRUCT!{struct REPL_INFO_1003 { + rp1003_random: DWORD, +}} +pub type PREPL_INFO_1003 = *mut REPL_INFO_1003; +pub type LPREPL_INFO_1003 = *mut REPL_INFO_1003; +extern "system" { + pub fn NetReplGetInfo( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetReplSetInfo( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; +} +pub const REPL_INTEGRITY_FILE: DWORD = 1; +pub const REPL_INTEGRITY_TREE: DWORD = 2; +pub const REPL_EXTENT_FILE: DWORD = 1; +pub const REPL_EXTENT_TREE: DWORD = 2; +pub const REPL_EXPORT_INTEGRITY_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 0; +pub const REPL_EXPORT_EXTENT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + 1; +STRUCT!{struct REPL_EDIR_INFO_0 { + rped0_dirname: LPWSTR, +}} +pub type PREPL_EDIR_INFO_0 = *mut REPL_EDIR_INFO_0; +pub type LPREPL_EDIR_INFO_0 = *mut REPL_EDIR_INFO_0; +STRUCT!{struct REPL_EDIR_INFO_1 { + rped1_dirname: LPWSTR, + rped1_integrity: DWORD, + rped1_extent: DWORD, +}} +pub type PREPL_EDIR_INFO_1 = *mut REPL_EDIR_INFO_1; +pub type LPREPL_EDIR_INFO_1 = *mut REPL_EDIR_INFO_1; +STRUCT!{struct REPL_EDIR_INFO_2 { + rped2_dirname: LPWSTR, + rped2_integrity: DWORD, + rped2_extent: DWORD, + rped2_lockcount: DWORD, + rped2_locktime: DWORD, +}} +pub type PREPL_EDIR_INFO_2 = *mut REPL_EDIR_INFO_2; +pub type LPREPL_EDIR_INFO_2 = *mut REPL_EDIR_INFO_2; +STRUCT!{struct REPL_EDIR_INFO_1000 { + rped1000_integrity: DWORD, +}} +pub type PREPL_EDIR_INFO_1000 = *mut REPL_EDIR_INFO_1000; +pub type LPREPL_EDIR_INFO_1000 = *mut REPL_EDIR_INFO_1000; +STRUCT!{struct REPL_EDIR_INFO_1001 { + rped1001_extent: DWORD, +}} +pub type PREPL_EDIR_INFO_1001 = *mut REPL_EDIR_INFO_1001; +pub type LPREPL_EDIR_INFO_1001 = *mut REPL_EDIR_INFO_1001; +extern "system" { + pub fn NetReplExportDirAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetReplExportDirDel( + servername: LPCWSTR, + dirname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetReplExportDirEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetReplExportDirGetInfo( + servername: LPCWSTR, + dirname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetReplExportDirSetInfo( + servername: LPCWSTR, + dirname: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetReplExportDirLock( + servername: LPCWSTR, + dirname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetReplExportDirUnlock( + servername: LPCWSTR, + dirname: LPCWSTR, + unlockforce: DWORD, + ) -> NET_API_STATUS; +} +pub const REPL_UNLOCK_NOFORCE: DWORD = 0; +pub const REPL_UNLOCK_FORCE: DWORD = 1; +STRUCT!{struct REPL_IDIR_INFO_0 { + rpid0_dirname: LPWSTR, +}} +pub type PREPL_IDIR_INFO_0 = *mut REPL_IDIR_INFO_0; +pub type LPREPL_IDIR_INFO_0 = *mut REPL_IDIR_INFO_0; +STRUCT!{struct REPL_IDIR_INFO_1 { + rpid1_dirname: LPWSTR, + rpid1_state: DWORD, + rpid1_mastername: LPWSTR, + rpid1_last_update_time: DWORD, + rpid1_lockcount: DWORD, + rpid1_locktime: DWORD, +}} +pub type PREPL_IDIR_INFO_1 = *mut REPL_IDIR_INFO_1; +pub type LPREPL_IDIR_INFO_1 = *mut REPL_IDIR_INFO_1; +extern "system" { + pub fn NetReplImportDirAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetReplImportDirDel( + servername: LPCWSTR, + dirname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetReplImportDirEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetReplImportDirGetInfo( + servername: LPCWSTR, + dirname: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetReplImportDirLock( + servername: LPCWSTR, + dirname: LPCWSTR, + ) -> NET_API_STATUS; + pub fn NetReplImportDirUnlock( + servername: LPCWSTR, + dirname: LPCWSTR, + unlockforce: DWORD, + ) -> NET_API_STATUS; +} +pub const REPL_STATE_OK: DWORD = 0; +pub const REPL_STATE_NO_MASTER: DWORD = 1; +pub const REPL_STATE_NO_SYNC: DWORD = 2; +pub const REPL_STATE_NEVER_REPLICATED: DWORD = 3; diff --git a/winapi/src/um/lmserver.rs b/winapi/src/um/lmserver.rs new file mode 100644 index 000000000..621c4be9a --- /dev/null +++ b/winapi/src/um/lmserver.rs @@ -0,0 +1,1255 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This file contains information about NetServer APIs +use shared::guiddef::GUID; +use shared::lmcons::{LMCSTR, LMSTR, NET_API_STATUS, PARMNUM_BASE_INFOLEVEL, PATHLEN}; +use shared::minwindef::{BOOL, BYTE, DWORD, LPBYTE, LPDWORD, ULONG}; +use um::winnt::{BOOLEAN, LONG}; +use um::winsvc::SERVICE_STATUS_HANDLE; +extern "system" { + pub fn NetServerEnum( + servername: LMCSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + servertype: DWORD, + domain: LMCSTR, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetServerEnumEx( + servername: LMCSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + servertype: DWORD, + domain: LMCSTR, + FirstNameToReturn: LMCSTR, + ) -> NET_API_STATUS; + pub fn NetServerGetInfo( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerSetInfo( + servername: LMSTR, + level: DWORD, + buf: LPBYTE, + ParmError: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetServerDiskEnum( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetServerComputerNameAdd( + ServerName: LMSTR, + EmulatedDomainName: LMSTR, + EmulatedServerName: LMSTR, + ) -> NET_API_STATUS; + pub fn NetServerComputerNameDel( + ServerName: LMSTR, + EmulatedServerName: LMSTR, + ) -> NET_API_STATUS; + pub fn NetServerTransportAdd( + servername: LMSTR, + level: DWORD, + bufptr: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerTransportAddEx( + servername: LMSTR, + level: DWORD, + bufptr: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerTransportDel( + servername: LMSTR, + level: DWORD, + bufptr: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerTransportEnum( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn SetServiceBits( + hServiceStatus: SERVICE_STATUS_HANDLE, + dwServiceBits: DWORD, + bSetBitsOn: BOOL, + bUpdateImmediately: BOOL, + ) -> BOOL; +} +STRUCT!{struct SERVER_INFO_100 { + sv100_platform_id: DWORD, + sv100_name: LMSTR, +}} +pub type PSERVER_INFO_100 = *mut SERVER_INFO_100; +pub type LPSERVER_INFO_100 = *mut SERVER_INFO_100; +STRUCT!{struct SERVER_INFO_101 { + sv101_platform_id: DWORD, + sv101_name: LMSTR, + sv101_version_major: DWORD, + sv101_version_minor: DWORD, + sv101_type: DWORD, + sv101_comment: LMSTR, +}} +pub type PSERVER_INFO_101 = *mut SERVER_INFO_101; +pub type LPSERVER_INFO_101 = *mut SERVER_INFO_101; +STRUCT!{struct SERVER_INFO_102 { + sv102_platform_id: DWORD, + sv102_name: LMSTR, + sv102_version_major: DWORD, + sv102_version_minor: DWORD, + sv102_type: DWORD, + sv102_comment: LMSTR, + sv102_users: DWORD, + sv102_disc: LONG, + sv102_hidden: BOOL, + sv102_announce: DWORD, + sv102_anndelta: DWORD, + sv102_licenses: DWORD, + sv102_userpath: LMSTR, +}} +pub type PSERVER_INFO_102 = *mut SERVER_INFO_102; +pub type LPSERVER_INFO_102 = *mut SERVER_INFO_102; +STRUCT!{struct SERVER_INFO_103 { + sv103_platform_id: DWORD, + sv103_name: LMSTR, + sv103_version_major: DWORD, + sv103_version_minor: DWORD, + sv103_type: DWORD, + sv103_comment: LMSTR, + sv103_users: DWORD, + sv103_disc: LONG, + sv103_hidden: BOOL, + sv103_announce: DWORD, + sv103_anndelta: DWORD, + sv103_licenses: DWORD, + sv103_userpath: LMSTR, + sv103_capabilities: DWORD, +}} +pub type PSERVER_INFO_103 = *mut SERVER_INFO_103; +pub type LPSERVER_INFO_103 = *mut SERVER_INFO_103; +STRUCT!{struct SERVER_INFO_402 { + sv402_ulist_mtime: DWORD, + sv402_glist_mtime: DWORD, + sv402_alist_mtime: DWORD, + sv402_alerts: LMSTR, + sv402_security: DWORD, + sv402_numadmin: DWORD, + sv402_lanmask: DWORD, + sv402_guestacct: LMSTR, + sv402_chdevs: DWORD, + sv402_chdevq: DWORD, + sv402_chdevjobs: DWORD, + sv402_connections: DWORD, + sv402_shares: DWORD, + sv402_openfiles: DWORD, + sv402_sessopens: DWORD, + sv402_sessvcs: DWORD, + sv402_sessreqs: DWORD, + sv402_opensearch: DWORD, + sv402_activelocks: DWORD, + sv402_numreqbuf: DWORD, + sv402_sizreqbuf: DWORD, + sv402_numbigbuf: DWORD, + sv402_numfiletasks: DWORD, + sv402_alertsched: DWORD, + sv402_erroralert: DWORD, + sv402_logonalert: DWORD, + sv402_accessalert: DWORD, + sv402_diskalert: DWORD, + sv402_netioalert: DWORD, + sv402_maxauditsz: DWORD, + sv402_srvheuristics: LMSTR, +}} +pub type PSERVER_INFO_402 = *mut SERVER_INFO_402; +pub type LPSERVER_INFO_402 = *mut SERVER_INFO_402; +STRUCT!{struct SERVER_INFO_403 { + sv403_ulist_mtime: DWORD, + sv403_glist_mtime: DWORD, + sv403_alist_mtime: DWORD, + sv403_alerts: LMSTR, + sv403_security: DWORD, + sv403_numadmin: DWORD, + sv403_lanmask: DWORD, + sv403_guestacct: LMSTR, + sv403_chdevs: DWORD, + sv403_chdevq: DWORD, + sv403_chdevjobs: DWORD, + sv403_connections: DWORD, + sv403_shares: DWORD, + sv403_openfiles: DWORD, + sv403_sessopens: DWORD, + sv403_sessvcs: DWORD, + sv403_sessreqs: DWORD, + sv403_opensearch: DWORD, + sv403_activelocks: DWORD, + sv403_numreqbuf: DWORD, + sv403_sizreqbuf: DWORD, + sv403_numbigbuf: DWORD, + sv403_numfiletasks: DWORD, + sv403_alertsched: DWORD, + sv403_erroralert: DWORD, + sv403_logonalert: DWORD, + sv403_accessalert: DWORD, + sv403_diskalert: DWORD, + sv403_netioalert: DWORD, + sv403_maxauditsz: DWORD, + sv403_srvheuristics: LMSTR, + sv403_auditedevents: DWORD, + sv403_autoprofile: DWORD, + sv403_autopath: LMSTR, +}} +pub type PSERVER_INFO_403 = *mut SERVER_INFO_403; +pub type LPSERVER_INFO_403 = *mut SERVER_INFO_403; +STRUCT!{struct SERVER_INFO_502 { + sv502_sessopens: DWORD, + sv502_sessvcs: DWORD, + sv502_opensearch: DWORD, + sv502_sizreqbuf: DWORD, + sv502_initworkitems: DWORD, + sv502_maxworkitems: DWORD, + sv502_rawworkitems: DWORD, + sv502_irpstacksize: DWORD, + sv502_maxrawbuflen: DWORD, + sv502_sessusers: DWORD, + sv502_sessconns: DWORD, + sv502_maxpagedmemoryusage: DWORD, + sv502_maxnonpagedmemoryusage: DWORD, + sv502_enablesoftcompat: BOOL, + sv502_enableforcedlogoff: BOOL, + sv502_timesource: BOOL, + sv502_acceptdownlevelapis: BOOL, + sv502_lmannounce: BOOL, +}} +pub type PSERVER_INFO_502 = *mut SERVER_INFO_502; +pub type LPSERVER_INFO_502 = *mut SERVER_INFO_502; +STRUCT!{struct SERVER_INFO_503 { + sv503_sessopens : DWORD, + sv503_sessvcs: DWORD, + sv503_opensearch: DWORD, + sv503_sizreqbuf: DWORD, + sv503_initworkitems: DWORD, + sv503_maxworkitems: DWORD, + sv503_rawworkitems: DWORD, + sv503_irpstacksize: DWORD, + sv503_maxrawbuflen: DWORD, + sv503_sessusers: DWORD, + sv503_sessconns: DWORD, + sv503_maxpagedmemoryusage: DWORD, + sv503_maxnonpagedmemoryusage: DWORD, + sv503_enablesoftcompat: BOOL, + sv503_enableforcedlogoff: BOOL, + sv503_timesource: BOOL, + sv503_acceptdownlevelapis: BOOL, + sv503_lmannounce: BOOL, + sv503_domain: LMSTR, + sv503_maxcopyreadlen: DWORD, + sv503_maxcopywritelen: DWORD, + sv503_minkeepsearch: DWORD, + sv503_maxkeepsearch: DWORD, + sv503_minkeepcomplsearch: DWORD, + sv503_maxkeepcomplsearch: DWORD, + sv503_threadcountadd: DWORD, + sv503_numblockthreads: DWORD, + sv503_scavtimeout: DWORD, + sv503_minrcvqueue: DWORD, + sv503_minfreeworkitems: DWORD, + sv503_xactmemsize: DWORD, + sv503_threadpriority: DWORD, + sv503_maxmpxct: DWORD, + sv503_oplockbreakwait: DWORD, + sv503_oplockbreakresponsewait: DWORD, + sv503_enableoplocks: BOOL, + sv503_enableoplockforceclose: BOOL, + sv503_enablefcbopens: BOOL, + sv503_enableraw: BOOL, + sv503_enablesharednetdrives: BOOL, + sv503_minfreeconnections: DWORD, + sv503_maxfreeconnections: DWORD, +}} +pub type PSERVER_INFO_503 = *mut SERVER_INFO_503; +pub type LPSERVER_INFO_503 = *mut SERVER_INFO_503; +STRUCT!{struct SERVER_INFO_599 { + sv599_sessopens: DWORD, + sv599_sessvcs: DWORD, + sv599_opensearch: DWORD, + sv599_sizreqbuf: DWORD, + sv599_initworkitems: DWORD, + sv599_maxworkitems: DWORD, + sv599_rawworkitems: DWORD, + sv599_irpstacksize: DWORD, + sv599_maxrawbuflen: DWORD, + sv599_sessusers: DWORD, + sv599_sessconns: DWORD, + sv599_maxpagedmemoryusage: DWORD, + sv599_maxnonpagedmemoryusage: DWORD, + sv599_enablesoftcompat: BOOL, + sv599_enableforcedlogoff: BOOL, + sv599_timesource: BOOL, + sv599_acceptdownlevelapis: BOOL, + sv599_lmannounce: BOOL, + sv599_domain: LMSTR, + sv599_maxcopyreadlen: DWORD, + sv599_maxcopywritelen: DWORD, + sv599_minkeepsearch: DWORD, + sv599_maxkeepsearch: DWORD, + sv599_minkeepcomplsearch: DWORD, + sv599_maxkeepcomplsearch: DWORD, + sv599_threadcountadd: DWORD, + sv599_numblockthreads: DWORD, + sv599_scavtimeout: DWORD, + sv599_minrcvqueue: DWORD, + sv599_minfreeworkitems: DWORD, + sv599_xactmemsize: DWORD, + sv599_threadpriority: DWORD, + sv599_maxmpxct: DWORD, + sv599_oplockbreakwait: DWORD, + sv599_oplockbreakresponsewait: DWORD, + sv599_enableoplocks: BOOL, + sv599_enableoplockforceclose: BOOL, + sv599_enablefcbopens: BOOL, + sv599_enableraw: BOOL, + sv599_enablesharednetdrives: BOOL, + sv599_minfreeconnections: DWORD, + sv599_maxfreeconnections: DWORD, + sv599_initsesstable: DWORD, + sv599_initconntable: DWORD, + sv599_initfiletable: DWORD, + sv599_initsearchtable: DWORD, + sv599_alertschedule: DWORD, + sv599_errorthreshold: DWORD, + sv599_networkerrorthreshold: DWORD, + sv599_diskspacethreshold: DWORD, + sv599_reserved: DWORD, + sv599_maxlinkdelay: DWORD, + sv599_minlinkthroughput: DWORD, + sv599_linkinfovalidtime: DWORD, + sv599_scavqosinfoupdatetime: DWORD, + sv599_maxworkitemidletime: DWORD, +}} +pub type PSERVER_INFO_599 = *mut SERVER_INFO_599; +pub type LPSERVER_INFO_599 = *mut SERVER_INFO_599; +STRUCT!{struct SERVER_INFO_598 { + sv598_maxrawworkitems: DWORD, + sv598_maxthreadsperqueue: DWORD, + sv598_producttype: DWORD, + sv598_serversize: DWORD, + sv598_connectionlessautodisc: DWORD, + sv598_sharingviolationretries: DWORD, + sv598_sharingviolationdelay: DWORD, + sv598_maxglobalopensearch: DWORD, + sv598_removeduplicatesearches: DWORD, + sv598_lockviolationoffset: DWORD, + sv598_lockviolationdelay: DWORD, + sv598_mdlreadswitchover: DWORD, + sv598_cachedopenlimit: DWORD, + sv598_otherqueueaffinity: DWORD, + sv598_restrictnullsessaccess: BOOL, + sv598_enablewfw311directipx: BOOL, + sv598_queuesamplesecs: DWORD, + sv598_balancecount: DWORD, + sv598_preferredaffinity: DWORD, + sv598_maxfreerfcbs: DWORD, + sv598_maxfreemfcbs: DWORD, + sv598_maxfreelfcbs: DWORD, + sv598_maxfreepagedpoolchunks: DWORD, + sv598_minpagedpoolchunksize: DWORD, + sv598_maxpagedpoolchunksize: DWORD, + sv598_sendsfrompreferredprocessor: BOOL, + sv598_cacheddirectorylimit: DWORD, + sv598_maxcopylength: DWORD, + sv598_enablecompression: BOOL, + sv598_autosharewks: BOOL, + sv598_autoshareserver: BOOL, + sv598_enablesecuritysignature: BOOL, + sv598_requiresecuritysignature: BOOL, + sv598_minclientbuffersize: DWORD, + sv598_serverguid: GUID, + sv598_ConnectionNoSessionsTimeout: DWORD, + sv598_IdleThreadTimeOut: DWORD, + sv598_enableW9xsecuritysignature: BOOL, + sv598_enforcekerberosreauthentication: BOOL, + sv598_disabledos: BOOL, + sv598_lowdiskspaceminimum: DWORD, + sv598_disablestrictnamechecking: BOOL, + sv598_enableauthenticateusersharing: BOOL, +}} +pub type PSERVER_INFO_598 = *mut SERVER_INFO_598; +pub type LPSERVER_INFO_598 = *mut SERVER_INFO_598; +STRUCT!{struct SERVER_INFO_1005 { + sv1005_comment: LMSTR, +}} +pub type PSERVER_INFO_1005 = *mut SERVER_INFO_1005; +pub type LPSERVER_INFO_1005 = *mut SERVER_INFO_1005; +STRUCT!{struct SERVER_INFO_1107 { + sv1107_users: DWORD, +}} +pub type PSERVER_INFO_1107 = *mut SERVER_INFO_1107; +pub type LPSERVER_INFO_1107 = *mut SERVER_INFO_1107; +STRUCT!{struct SERVER_INFO_1010 { + sv1010_disc: LONG, +}} +pub type PSERVER_INFO_1010 = *mut SERVER_INFO_1010; +pub type LPSERVER_INFO_1010 = *mut SERVER_INFO_1010; +STRUCT!{struct SERVER_INFO_1016 { + sv1016_hidden: BOOL, +}} +pub type PSERVER_INFO_1016 = *mut SERVER_INFO_1016; +pub type LPSERVER_INFO_1016 = *mut SERVER_INFO_1016; +STRUCT!{struct SERVER_INFO_1017 { + sv1017_announce: DWORD, +}} +pub type PSERVER_INFO_1017 = *mut SERVER_INFO_1017; +pub type LPSERVER_INFO_1017 = *mut SERVER_INFO_1017; +STRUCT!{struct SERVER_INFO_1018 { + sv1018_anndelta: DWORD, +}} +pub type PSERVER_INFO_1018 = *mut SERVER_INFO_1018; +pub type LPSERVER_INFO_1018 = *mut SERVER_INFO_1018; +STRUCT!{struct SERVER_INFO_1501 { + sv1501_sessopens: DWORD, +}} +pub type PSERVER_INFO_1501 = *mut SERVER_INFO_1501; +pub type LPSERVER_INFO_1501 = *mut SERVER_INFO_1501; +STRUCT!{struct SERVER_INFO_1502 { + sv1502_sessvcs: DWORD, +}} +pub type PSERVER_INFO_1502 = *mut SERVER_INFO_1502; +pub type LPSERVER_INFO_1502 = *mut SERVER_INFO_1502; +STRUCT!{struct SERVER_INFO_1503 { + sv1503_opensearch: DWORD, +}} +pub type PSERVER_INFO_1503 = *mut SERVER_INFO_1503; +pub type LPSERVER_INFO_1503 = *mut SERVER_INFO_1503; +STRUCT!{struct SERVER_INFO_1506 { + sv1506_maxworkitems: DWORD, +}} +pub type PSERVER_INFO_1506 = *mut SERVER_INFO_1506; +pub type LPSERVER_INFO_1506 = *mut SERVER_INFO_1506; +STRUCT!{struct SERVER_INFO_1509 { + sv1509_maxrawbuflen: DWORD, +}} +pub type PSERVER_INFO_1509 = *mut SERVER_INFO_1509; +pub type LPSERVER_INFO_1509 = *mut SERVER_INFO_1509; +STRUCT!{struct SERVER_INFO_1510 { + sv1510_sessusers: DWORD, +}} +pub type PSERVER_INFO_1510 = *mut SERVER_INFO_1510; +pub type LPSERVER_INFO_1510 = *mut SERVER_INFO_1510; +STRUCT!{struct SERVER_INFO_1511 { + sv1511_sessconns: DWORD, +}} +pub type PSERVER_INFO_1511 = *mut SERVER_INFO_1511; +pub type LPSERVER_INFO_1511 = *mut SERVER_INFO_1511; +STRUCT!{struct SERVER_INFO_1512 { + sv1512_maxnonpagedmemoryusage: DWORD, +}} +pub type PSERVER_INFO_1512 = *mut SERVER_INFO_1512; +pub type LPSERVER_INFO_1512 = *mut SERVER_INFO_1512; +STRUCT!{struct SERVER_INFO_1513 { + sv1513_maxpagedmemoryusage: DWORD, +}} +pub type PSERVER_INFO_1513 = *mut SERVER_INFO_1513; +pub type LPSERVER_INFO_1513 = *mut SERVER_INFO_1513; +STRUCT!{struct SERVER_INFO_1514 { + sv1514_enablesoftcompat: BOOL, +}} +pub type PSERVER_INFO_1514 = *mut SERVER_INFO_1514; +pub type LPSERVER_INFO_1514 = *mut SERVER_INFO_1514; +STRUCT!{struct SERVER_INFO_1515 { + sv1515_enableforcedlogoff: BOOL, +}} +pub type PSERVER_INFO_1515 = *mut SERVER_INFO_1515; +pub type LPSERVER_INFO_1515 = *mut SERVER_INFO_1515; +STRUCT!{struct SERVER_INFO_1516 { + sv1516_timesource: BOOL, +}} +pub type PSERVER_INFO_1516 = *mut SERVER_INFO_1516; +pub type LPSERVER_INFO_1516 = *mut SERVER_INFO_1516; +STRUCT!{struct SERVER_INFO_1518 { + sv1518_lmannounce: BOOL, +}} +pub type PSERVER_INFO_1518 = *mut SERVER_INFO_1518; +pub type LPSERVER_INFO_1518 = *mut SERVER_INFO_1518; +STRUCT!{struct SERVER_INFO_1520 { + sv1520_maxcopyreadlen: DWORD, +}} +pub type PSERVER_INFO_1520 = *mut SERVER_INFO_1520; +pub type LPSERVER_INFO_1520 = *mut SERVER_INFO_1520; +STRUCT!{struct SERVER_INFO_1521 { + sv1521_maxcopywritelen: DWORD, +}} +pub type PSERVER_INFO_1521 = *mut SERVER_INFO_1521; +pub type LPSERVER_INFO_1521 = *mut SERVER_INFO_1521; +STRUCT!{struct SERVER_INFO_1522 { + sv1522_minkeepsearch: DWORD, +}} +pub type PSERVER_INFO_1522 = *mut SERVER_INFO_1522; +pub type LPSERVER_INFO_1522 = *mut SERVER_INFO_1522; +STRUCT!{struct SERVER_INFO_1523 { + sv1523_maxkeepsearch: DWORD, +}} +pub type PSERVER_INFO_1523 = *mut SERVER_INFO_1523; +pub type LPSERVER_INFO_1523 = *mut SERVER_INFO_1523; +STRUCT!{struct SERVER_INFO_1524 { + sv1524_minkeepcomplsearch: DWORD, +}} +pub type PSERVER_INFO_1524 = *mut SERVER_INFO_1524; +pub type LPSERVER_INFO_1524 = *mut SERVER_INFO_1524; +STRUCT!{struct SERVER_INFO_1525 { + sv1525_maxkeepcomplsearch: DWORD, +}} +pub type PSERVER_INFO_1525 = *mut SERVER_INFO_1525; +pub type LPSERVER_INFO_1525 = *mut SERVER_INFO_1525; +STRUCT!{struct SERVER_INFO_1528 { + sv1528_scavtimeout: DWORD, +}} +pub type PSERVER_INFO_1528 = *mut SERVER_INFO_1528; +pub type LPSERVER_INFO_1528 = *mut SERVER_INFO_1528; +STRUCT!{struct SERVER_INFO_1529 { + sv1529_minrcvqueue: DWORD, +}} +pub type PSERVER_INFO_1529 = *mut SERVER_INFO_1529; +pub type LPSERVER_INFO_1529 = *mut SERVER_INFO_1529; +STRUCT!{struct SERVER_INFO_1530 { + sv1530_minfreeworkitems: DWORD, +}} +pub type PSERVER_INFO_1530 = *mut SERVER_INFO_1530; +pub type LPSERVER_INFO_1530 = *mut SERVER_INFO_1530; +STRUCT!{struct SERVER_INFO_1533 { + sv1533_maxmpxct: DWORD, +}} +pub type PSERVER_INFO_1533 = *mut SERVER_INFO_1533; +pub type LPSERVER_INFO_1533 = *mut SERVER_INFO_1533; +STRUCT!{struct SERVER_INFO_1534 { + sv1534_oplockbreakwait: DWORD, +}} +pub type PSERVER_INFO_1534 = *mut SERVER_INFO_1534; +pub type LPSERVER_INFO_1534 = *mut SERVER_INFO_1534; +STRUCT!{struct SERVER_INFO_1535 { + sv1535_oplockbreakresponsewait: DWORD, +}} +pub type PSERVER_INFO_1535 = *mut SERVER_INFO_1535; +pub type LPSERVER_INFO_1535 = *mut SERVER_INFO_1535; +STRUCT!{struct SERVER_INFO_1536 { + sv1536_enableoplocks: BOOL, +}} +pub type PSERVER_INFO_1536 = *mut SERVER_INFO_1536; +pub type LPSERVER_INFO_1536 = *mut SERVER_INFO_1536; +STRUCT!{struct SERVER_INFO_1537 { + sv1537_enableoplockforceclose: BOOL, +}} +pub type PSERVER_INFO_1537 = *mut SERVER_INFO_1537; +pub type LPSERVER_INFO_1537 = *mut SERVER_INFO_1537; +STRUCT!{struct SERVER_INFO_1538 { + sv1538_enablefcbopens: BOOL, +}} +pub type PSERVER_INFO_1538 = *mut SERVER_INFO_1538; +pub type LPSERVER_INFO_1538 = *mut SERVER_INFO_1538; +STRUCT!{struct SERVER_INFO_1539 { + sv1539_enableraw: BOOL, +}} +pub type PSERVER_INFO_1539 = *mut SERVER_INFO_1539; +pub type LPSERVER_INFO_1539 = *mut SERVER_INFO_1539; +STRUCT!{struct SERVER_INFO_1540 { + sv1540_enablesharednetdrives: BOOL, +}} +pub type PSERVER_INFO_1540 = *mut SERVER_INFO_1540; +pub type LPSERVER_INFO_1540 = *mut SERVER_INFO_1540; +STRUCT!{struct SERVER_INFO_1541 { + sv1541_minfreeconnections: BOOL, +}} +pub type PSERVER_INFO_1541 = *mut SERVER_INFO_1541; +pub type LPSERVER_INFO_1541 = *mut SERVER_INFO_1541; +STRUCT!{struct SERVER_INFO_1542 { + sv1542_maxfreeconnections: BOOL, +}} +pub type PSERVER_INFO_1542 = *mut SERVER_INFO_1542; +pub type LPSERVER_INFO_1542 = *mut SERVER_INFO_1542; +STRUCT!{struct SERVER_INFO_1543 { + sv1543_initsesstable: DWORD, +}} +pub type PSERVER_INFO_1543 = *mut SERVER_INFO_1543; +pub type LPSERVER_INFO_1543 = *mut SERVER_INFO_1543; +STRUCT!{struct SERVER_INFO_1544 { + sv1544_initconntable: DWORD, +}} +pub type PSERVER_INFO_1544 = *mut SERVER_INFO_1544; +pub type LPSERVER_INFO_1544 = *mut SERVER_INFO_1544; +STRUCT!{struct SERVER_INFO_1545 { + sv1545_initfiletable: DWORD, +}} +pub type PSERVER_INFO_1545 = *mut SERVER_INFO_1545; +pub type LPSERVER_INFO_1545 = *mut SERVER_INFO_1545; +STRUCT!{struct SERVER_INFO_1546 { + sv1546_initsearchtable: DWORD, +}} +pub type PSERVER_INFO_1546 = *mut SERVER_INFO_1546; +pub type LPSERVER_INFO_1546 = *mut SERVER_INFO_1546; +STRUCT!{struct SERVER_INFO_1547 { + sv1547_alertschedule: DWORD, +}} +pub type PSERVER_INFO_1547 = *mut SERVER_INFO_1547; +pub type LPSERVER_INFO_1547 = *mut SERVER_INFO_1547; +STRUCT!{struct SERVER_INFO_1548 { + sv1548_errorthreshold: DWORD, +}} +pub type PSERVER_INFO_1548 = *mut SERVER_INFO_1548; +pub type LPSERVER_INFO_1548 = *mut SERVER_INFO_1548; +STRUCT!{struct SERVER_INFO_1549 { + sv1549_networkerrorthreshold: DWORD, +}} +pub type PSERVER_INFO_1549 = *mut SERVER_INFO_1549; +pub type LPSERVER_INFO_1549 = *mut SERVER_INFO_1549; +STRUCT!{struct SERVER_INFO_1550 { + sv1550_diskspacethreshold: DWORD, +}} +pub type PSERVER_INFO_1550 = *mut SERVER_INFO_1550; +pub type LPSERVER_INFO_1550 = *mut SERVER_INFO_1550; +STRUCT!{struct SERVER_INFO_1552 { + sv1552_maxlinkdelay: DWORD, +}} +pub type PSERVER_INFO_1552 = *mut SERVER_INFO_1552; +pub type LPSERVER_INFO_1552 = *mut SERVER_INFO_1552; +STRUCT!{struct SERVER_INFO_1553 { + sv1553_minlinkthroughput: DWORD, +}} +pub type PSERVER_INFO_1553 = *mut SERVER_INFO_1553; +pub type LPSERVER_INFO_1553 = *mut SERVER_INFO_1553; +STRUCT!{struct SERVER_INFO_1554 { + sv1554_linkinfovalidtime: DWORD, +}} +pub type PSERVER_INFO_1554 = *mut SERVER_INFO_1554; +pub type LPSERVER_INFO_1554 = *mut SERVER_INFO_1554; +STRUCT!{struct SERVER_INFO_1555 { + sv1555_scavqosinfoupdatetime: DWORD, +}} +pub type PSERVER_INFO_1555 = *mut SERVER_INFO_1555; +pub type LPSERVER_INFO_1555 = *mut SERVER_INFO_1555; +STRUCT!{struct SERVER_INFO_1556 { + sv1556_maxworkitemidletime: DWORD, +}} +pub type PSERVER_INFO_1556 = *mut SERVER_INFO_1556; +pub type LPSERVER_INFO_1556 = *mut SERVER_INFO_1556; +STRUCT!{struct SERVER_INFO_1557 { + sv1557_maxrawworkitems: DWORD, +}} +pub type PSERVER_INFO_1557 = *mut SERVER_INFO_1557; +pub type LPSERVER_INFO_1557 = *mut SERVER_INFO_1557; +STRUCT!{struct SERVER_INFO_1560 { + sv1560_producttype: DWORD, +}} +pub type PSERVER_INFO_1560 = *mut SERVER_INFO_1560; +pub type LPSERVER_INFO_1560 = *mut SERVER_INFO_1560; +STRUCT!{struct SERVER_INFO_1561 { + sv1561_serversize: DWORD, +}} +pub type PSERVER_INFO_1561 = *mut SERVER_INFO_1561; +pub type LPSERVER_INFO_1561 = *mut SERVER_INFO_1561; +STRUCT!{struct SERVER_INFO_1562 { + sv1562_connectionlessautodisc: DWORD, +}} +pub type PSERVER_INFO_1562 = *mut SERVER_INFO_1562; +pub type LPSERVER_INFO_1562 = *mut SERVER_INFO_1562; +STRUCT!{struct SERVER_INFO_1563 { + sv1563_sharingviolationretries: DWORD, +}} +pub type PSERVER_INFO_1563 = *mut SERVER_INFO_1563; +pub type LPSERVER_INFO_1563 = *mut SERVER_INFO_1563; +STRUCT!{struct SERVER_INFO_1564 { + sv1564_sharingviolationdelay: DWORD, +}} +pub type PSERVER_INFO_1564 = *mut SERVER_INFO_1564; +pub type LPSERVER_INFO_1564 = *mut SERVER_INFO_1564; +STRUCT!{struct SERVER_INFO_1565 { + sv1565_maxglobalopensearch: DWORD, +}} +pub type PSERVER_INFO_1565 = *mut SERVER_INFO_1565; +pub type LPSERVER_INFO_1565 = *mut SERVER_INFO_1565; +STRUCT!{struct SERVER_INFO_1566 { + sv1566_removeduplicatesearches: BOOL, +}} +pub type PSERVER_INFO_1566 = *mut SERVER_INFO_1566; +pub type LPSERVER_INFO_1566 = *mut SERVER_INFO_1566; +STRUCT!{struct SERVER_INFO_1567 { + sv1567_lockviolationretries: DWORD, +}} +pub type PSERVER_INFO_1567 = *mut SERVER_INFO_1567; +pub type LPSERVER_INFO_1567 = *mut SERVER_INFO_1567; +STRUCT!{struct SERVER_INFO_1568 { + sv1568_lockviolationoffset: DWORD, +}} +pub type PSERVER_INFO_1568 = *mut SERVER_INFO_1568; +pub type LPSERVER_INFO_1568 = *mut SERVER_INFO_1568; +STRUCT!{struct SERVER_INFO_1569 { + sv1569_lockviolationdelay: DWORD, +}} +pub type PSERVER_INFO_1569 = *mut SERVER_INFO_1569; +pub type LPSERVER_INFO_1569 = *mut SERVER_INFO_1569; +STRUCT!{struct SERVER_INFO_1570 { + sv1570_mdlreadswitchover: DWORD, +}} +pub type PSERVER_INFO_1570 = *mut SERVER_INFO_1570; +pub type LPSERVER_INFO_1570 = *mut SERVER_INFO_1570; +STRUCT!{struct SERVER_INFO_1571 { + sv1571_cachedopenlimit: DWORD, +}} +pub type PSERVER_INFO_1571 = *mut SERVER_INFO_1571; +pub type LPSERVER_INFO_1571 = *mut SERVER_INFO_1571; +STRUCT!{struct SERVER_INFO_1572 { + sv1572_criticalthreads: DWORD, +}} +pub type PSERVER_INFO_1572 = *mut SERVER_INFO_1572; +pub type LPSERVER_INFO_1572 = *mut SERVER_INFO_1572; +STRUCT!{struct SERVER_INFO_1573 { + sv1573_restrictnullsessaccess: DWORD, +}} +pub type PSERVER_INFO_1573 = *mut SERVER_INFO_1573; +pub type LPSERVER_INFO_1573 = *mut SERVER_INFO_1573; +STRUCT!{struct SERVER_INFO_1574 { + sv1574_enablewfw311directipx: DWORD, +}} +pub type PSERVER_INFO_1574 = *mut SERVER_INFO_1574; +pub type LPSERVER_INFO_1574 = *mut SERVER_INFO_1574; +STRUCT!{struct SERVER_INFO_1575 { + sv1575_otherqueueaffinity: DWORD, +}} +pub type PSERVER_INFO_1575 = *mut SERVER_INFO_1575; +pub type LPSERVER_INFO_1575 = *mut SERVER_INFO_1575; +STRUCT!{struct SERVER_INFO_1576 { + sv1576_queuesamplesecs: DWORD, +}} +pub type PSERVER_INFO_1576 = *mut SERVER_INFO_1576; +pub type LPSERVER_INFO_1576 = *mut SERVER_INFO_1576; +STRUCT!{struct SERVER_INFO_1577 { + sv1577_balancecount: DWORD, +}} +pub type PSERVER_INFO_1577 = *mut SERVER_INFO_1577; +pub type LPSERVER_INFO_1577 = *mut SERVER_INFO_1577; +STRUCT!{struct SERVER_INFO_1578 { + sv1578_preferredaffinity: DWORD, +}} +pub type PSERVER_INFO_1578 = *mut SERVER_INFO_1578; +pub type LPSERVER_INFO_1578 = *mut SERVER_INFO_1578; +STRUCT!{struct SERVER_INFO_1579 { + sv1579_maxfreerfcbs: DWORD, +}} +pub type PSERVER_INFO_1579 = *mut SERVER_INFO_1579; +pub type LPSERVER_INFO_1579 = *mut SERVER_INFO_1579; +STRUCT!{struct SERVER_INFO_1580 { + sv1580_maxfreemfcbs: DWORD, +}} +pub type PSERVER_INFO_1580 = *mut SERVER_INFO_1580; +pub type LPSERVER_INFO_1580 = *mut SERVER_INFO_1580; +STRUCT!{struct SERVER_INFO_1581 { + sv1581_maxfreemlcbs: DWORD, +}} +pub type PSERVER_INFO_1581 = *mut SERVER_INFO_1581; +pub type LPSERVER_INFO_1581 = *mut SERVER_INFO_1581; +STRUCT!{struct SERVER_INFO_1582 { + sv1582_maxfreepagedpoolchunks: DWORD, +}} +pub type PSERVER_INFO_1582 = *mut SERVER_INFO_1582; +pub type LPSERVER_INFO_1582 = *mut SERVER_INFO_1582; +STRUCT!{struct SERVER_INFO_1583 { + sv1583_minpagedpoolchunksize: DWORD, +}} +pub type PSERVER_INFO_1583 = *mut SERVER_INFO_1583; +pub type LPSERVER_INFO_1583 = *mut SERVER_INFO_1583; +STRUCT!{struct SERVER_INFO_1584 { + sv1584_maxpagedpoolchunksize: DWORD, +}} +pub type PSERVER_INFO_1584 = *mut SERVER_INFO_1584; +pub type LPSERVER_INFO_1584 = *mut SERVER_INFO_1584; +STRUCT!{struct SERVER_INFO_1585 { + sv1585_sendsfrompreferredprocessor: BOOL, +}} +pub type PSERVER_INFO_1585 = *mut SERVER_INFO_1585; +pub type LPSERVER_INFO_1585 = *mut SERVER_INFO_1585; +STRUCT!{struct SERVER_INFO_1586 { + sv1586_maxthreadsperqueue: DWORD, +}} +pub type PSERVER_INFO_1586 = *mut SERVER_INFO_1586; +pub type LPSERVER_INFO_1586 = *mut SERVER_INFO_1586; +STRUCT!{struct SERVER_INFO_1587 { + sv1587_cacheddirectorylimit: DWORD, +}} +pub type PSERVER_INFO_1587 = *mut SERVER_INFO_1587; +pub type LPSERVER_INFO_1587 = *mut SERVER_INFO_1587; +STRUCT!{struct SERVER_INFO_1588 { + sv1588_maxcopylength: DWORD, +}} +pub type PSERVER_INFO_1588 = *mut SERVER_INFO_1588; +pub type LPSERVER_INFO_1588 = *mut SERVER_INFO_1588; +STRUCT!{struct SERVER_INFO_1590 { + sv1590_enablecompression: DWORD, +}} +pub type PSERVER_INFO_1590 = *mut SERVER_INFO_1590; +pub type LPSERVER_INFO_1590 = *mut SERVER_INFO_1590; +STRUCT!{struct SERVER_INFO_1591 { + sv1591_autosharewks: DWORD, +}} +pub type PSERVER_INFO_1591 = *mut SERVER_INFO_1591; +pub type LPSERVER_INFO_1591 = *mut SERVER_INFO_1591; +STRUCT!{struct SERVER_INFO_1592 { + sv1592_autosharewks: DWORD, +}} +pub type PSERVER_INFO_1592 = *mut SERVER_INFO_1592; +pub type LPSERVER_INFO_1592 = *mut SERVER_INFO_1592; +STRUCT!{struct SERVER_INFO_1593 { + sv1593_enablesecuritysignature: DWORD, +}} +pub type PSERVER_INFO_1593 = *mut SERVER_INFO_1593; +pub type LPSERVER_INFO_1593 = *mut SERVER_INFO_1593; +STRUCT!{struct SERVER_INFO_1594 { + sv1594_requiresecuritysignature: DWORD, +}} +pub type PSERVER_INFO_1594 = *mut SERVER_INFO_1594; +pub type LPSERVER_INFO_1594 = *mut SERVER_INFO_1594; +STRUCT!{struct SERVER_INFO_1595 { + sv1595_minclientbuffersize: DWORD, +}} +pub type PSERVER_INFO_1595 = *mut SERVER_INFO_1595; +pub type LPSERVER_INFO_1595 = *mut SERVER_INFO_1595; +STRUCT!{struct SERVER_INFO_1596 { + sv1596_ConnectionNoSessionsTimeout: DWORD, +}} +pub type PSERVER_INFO_1596 = *mut SERVER_INFO_1596; +pub type LPSERVER_INFO_1596 = *mut SERVER_INFO_1596; +STRUCT!{struct SERVER_INFO_1597 { + sv1597_IdleThreadTimeOut: DWORD, +}} +pub type PSERVER_INFO_1597 = *mut SERVER_INFO_1597; +pub type LPSERVER_INFO_1597 = *mut SERVER_INFO_1597; +STRUCT!{struct SERVER_INFO_1598 { + sv1598_enableW9xsecuritysignature: DWORD, +}} +pub type PSERVER_INFO_1598 = *mut SERVER_INFO_1598; +pub type LPSERVER_INFO_1598 = *mut SERVER_INFO_1598; +STRUCT!{struct SERVER_INFO_1599 { + sv1598_enforcekerberosreauthentication: BOOLEAN, +}} +pub type PSERVER_INFO_1599 = *mut SERVER_INFO_1599; +pub type LPSERVER_INFO_1599 = *mut SERVER_INFO_1599; +STRUCT!{struct SERVER_INFO_1600 { + sv1598_disabledos: BOOLEAN, +}} +pub type PSERVER_INFO_1600 = *mut SERVER_INFO_1600; +pub type LPSERVER_INFO_1600 = *mut SERVER_INFO_1600; +STRUCT!{struct SERVER_INFO_1601 { + sv1598_lowdiskspaceminimum: DWORD, +}} +pub type PSERVER_INFO_1601 = *mut SERVER_INFO_1601; +pub type LPSERVER_INFO_1601 = *mut SERVER_INFO_1601; +STRUCT!{struct SERVER_INFO_1602 { + sv_1598_disablestrictnamechecking: BOOL, +}} +pub type PSERVER_INFO_1602 = *mut SERVER_INFO_1602; +pub type LPSERVER_INFO_1602 = *mut SERVER_INFO_1602; +STRUCT!{struct SERVER_TRANSPORT_INFO_0 { + svti0_numberofvcs: DWORD, + svti0_transportname: LMSTR, + svti0_transportaddress: LPBYTE, + svti0_transportaddresslength: DWORD, + svti0_networkaddress: LMSTR, +}} +pub type PSERVER_TRANSPORT_INFO_0 = *mut SERVER_TRANSPORT_INFO_0; +pub type LPSERVER_TRANSPORT_INFO_0 = *mut SERVER_TRANSPORT_INFO_0; +STRUCT!{struct SERVER_TRANSPORT_INFO_1 { + svti1_numberofvcs: DWORD, + svti1_transportname: LMSTR, + svti1_transportaddress: LPBYTE, + svti1_transportaddresslength: DWORD, + svti1_networkaddress: LMSTR, + svti1_domain: LMSTR, +}} +pub type PSERVER_TRANSPORT_INFO_1 = *mut SERVER_TRANSPORT_INFO_1; +pub type LPSERVER_TRANSPORT_INFO_1 = *mut SERVER_TRANSPORT_INFO_1; +STRUCT!{struct SERVER_TRANSPORT_INFO_2 { + svti2_numberofvcs: DWORD, + svti2_transportname: LMSTR, + svti2_transportaddress: LPBYTE, + svti2_transportaddresslength: DWORD, + svti2_networkaddress: LMSTR, + svti2_domain: LMSTR, + svti2_flags: ULONG, +}} +pub type PSERVER_TRANSPORT_INFO_2 = *mut SERVER_TRANSPORT_INFO_2; +pub type LPSERVER_TRANSPORT_INFO_2 = *mut SERVER_TRANSPORT_INFO_2; +STRUCT!{struct SERVER_TRANSPORT_INFO_3 { + svti3_numberofvcs: DWORD, + svti3_transportname: LMSTR, + svti3_transportaddress: LPBYTE, + svti3_transportaddresslength: DWORD, + svti3_networkaddress: LMSTR, + svti3_domain: LMSTR, + svti3_flags: ULONG, + svti3_passwordlength: DWORD, + svti3_password: [BYTE; 256], +}} +pub type PSERVER_TRANSPORT_INFO_3 = *mut SERVER_TRANSPORT_INFO_3; +pub type LPSERVER_TRANSPORT_INFO_3 = *mut SERVER_TRANSPORT_INFO_3; +pub const SV_PLATFORM_ID_OS2: DWORD = 400; +pub const SV_PLATFORM_ID_NT: DWORD = 500; +pub const MAJOR_VERSION_MASK: DWORD = 0x0F; +pub const SV_TYPE_WORKSTATION: DWORD = 0x00000001; +pub const SV_TYPE_SERVER: DWORD = 0x00000002; +pub const SV_TYPE_SQLSERVER: DWORD = 0x00000004; +pub const SV_TYPE_DOMAIN_CTRL: DWORD = 0x00000008; +pub const SV_TYPE_DOMAIN_BAKCTRL: DWORD = 0x00000010; +pub const SV_TYPE_TIME_SOURCE: DWORD = 0x00000020; +pub const SV_TYPE_AFP: DWORD = 0x00000040; +pub const SV_TYPE_NOVELL: DWORD = 0x00000080; +pub const SV_TYPE_DOMAIN_MEMBER: DWORD = 0x00000100; +pub const SV_TYPE_PRINTQ_SERVER: DWORD = 0x00000200; +pub const SV_TYPE_DIALIN_SERVER: DWORD = 0x00000400; +pub const SV_TYPE_XENIX_SERVER: DWORD = 0x00000800; +pub const SV_TYPE_SERVER_UNIX: DWORD = SV_TYPE_XENIX_SERVER; +pub const SV_TYPE_NT: DWORD = 0x00001000; +pub const SV_TYPE_WFW: DWORD = 0x00002000; +pub const SV_TYPE_SERVER_MFPN: DWORD = 0x00004000; +pub const SV_TYPE_SERVER_NT: DWORD = 0x00008000; +pub const SV_TYPE_POTENTIAL_BROWSER: DWORD = 0x00010000; +pub const SV_TYPE_BACKUP_BROWSER: DWORD = 0x00020000; +pub const SV_TYPE_MASTER_BROWSER: DWORD = 0x00040000; +pub const SV_TYPE_DOMAIN_MASTER: DWORD = 0x00080000; +pub const SV_TYPE_SERVER_OSF: DWORD = 0x00100000; +pub const SV_TYPE_SERVER_VMS: DWORD = 0x00200000; +pub const SV_TYPE_WINDOWS: DWORD = 0x00400000; +pub const SV_TYPE_DFS: DWORD = 0x00800000; +pub const SV_TYPE_CLUSTER_NT: DWORD = 0x01000000; +pub const SV_TYPE_TERMINALSERVER: DWORD = 0x02000000; +pub const SV_TYPE_CLUSTER_VS_NT: DWORD = 0x04000000; +pub const SV_TYPE_DCE: DWORD = 0x10000000; +pub const SV_TYPE_ALTERNATE_XPORT: DWORD = 0x20000000; +pub const SV_TYPE_LOCAL_LIST_ONLY: DWORD = 0x40000000; +pub const SV_TYPE_DOMAIN_ENUM: DWORD = 0x80000000; +pub const SV_TYPE_ALL: DWORD = 0xFFFFFFFF; +pub const SV_NODISC: DWORD = -1i32 as u32; +pub const SV_USERSECURITY: DWORD = 1; +pub const SV_SHARESECURITY: DWORD = 0; +pub const SV_HIDDEN: DWORD = 1; +pub const SV_VISIBLE: DWORD = 0; +pub const SV_PLATFORM_ID_PARMNUM: DWORD = 101; +pub const SV_NAME_PARMNUM: DWORD = 102; +pub const SV_VERSION_MAJOR_PARMNUM: DWORD = 103; +pub const SV_VERSION_MINOR_PARMNUM: DWORD = 104; +pub const SV_TYPE_PARMNUM: DWORD = 105; +pub const SV_COMMENT_PARMNUM: DWORD = 5; +pub const SV_USERS_PARMNUM: DWORD = 107; +pub const SV_DISC_PARMNUM: DWORD = 10; +pub const SV_HIDDEN_PARMNUM: DWORD = 16; +pub const SV_ANNOUNCE_PARMNUM: DWORD = 17; +pub const SV_ANNDELTA_PARMNUM: DWORD = 18; +pub const SV_USERPATH_PARMNUM: DWORD = 112; +pub const SV_ULIST_MTIME_PARMNUM: DWORD = 401; +pub const SV_GLIST_MTIME_PARMNUM: DWORD = 402; +pub const SV_ALIST_MTIME_PARMNUM: DWORD = 403; +pub const SV_ALERTS_PARMNUM: DWORD = 11; +pub const SV_SECURITY_PARMNUM: DWORD = 405; +pub const SV_NUMADMIN_PARMNUM: DWORD = 406; +pub const SV_LANMASK_PARMNUM: DWORD = 407; +pub const SV_GUESTACC_PARMNUM: DWORD = 408; +pub const SV_CHDEVQ_PARMNUM: DWORD = 410; +pub const SV_CHDEVJOBS_PARMNUM: DWORD = 411; +pub const SV_CONNECTIONS_PARMNUM: DWORD = 412; +pub const SV_SHARES_PARMNUM: DWORD = 413; +pub const SV_OPENFILES_PARMNUM: DWORD = 414; +pub const SV_SESSREQS_PARMNUM: DWORD = 417; +pub const SV_ACTIVELOCKS_PARMNUM: DWORD = 419; +pub const SV_NUMREQBUF_PARMNUM: DWORD = 420; +pub const SV_NUMBIGBUF_PARMNUM: DWORD = 422; +pub const SV_NUMFILETASKS_PARMNUM: DWORD = 423; +pub const SV_ALERTSCHED_PARMNUM: DWORD = 37; +pub const SV_ERRORALERT_PARMNUM: DWORD = 38; +pub const SV_LOGONALERT_PARMNUM: DWORD = 39; +pub const SV_ACCESSALERT_PARMNUM: DWORD = 40; +pub const SV_DISKALERT_PARMNUM: DWORD = 41; +pub const SV_NETIOALERT_PARMNUM: DWORD = 42; +pub const SV_MAXAUDITSZ_PARMNUM: DWORD = 43; +pub const SV_SRVHEURISTICS_PARMNUM: DWORD = 431; +pub const SV_SESSOPENS_PARMNUM: DWORD = 501; +pub const SV_SESSVCS_PARMNUM: DWORD = 502; +pub const SV_OPENSEARCH_PARMNUM: DWORD = 503; +pub const SV_SIZREQBUF_PARMNUM: DWORD = 504; +pub const SV_INITWORKITEMS_PARMNUM: DWORD = 505; +pub const SV_MAXWORKITEMS_PARMNUM: DWORD = 506; +pub const SV_RAWWORKITEMS_PARMNUM: DWORD = 507; +pub const SV_IRPSTACKSIZE_PARMNUM: DWORD = 508; +pub const SV_MAXRAWBUFLEN_PARMNUM: DWORD = 509; +pub const SV_SESSUSERS_PARMNUM: DWORD = 510; +pub const SV_SESSCONNS_PARMNUM: DWORD = 511; +pub const SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM: DWORD = 512; +pub const SV_MAXPAGEDMEMORYUSAGE_PARMNUM: DWORD = 513; +pub const SV_ENABLESOFTCOMPAT_PARMNUM: DWORD = 514; +pub const SV_ENABLEFORCEDLOGOFF_PARMNUM: DWORD = 515; +pub const SV_TIMESOURCE_PARMNUM: DWORD = 516; +pub const SV_ACCEPTDOWNLEVELAPIS_PARMNUM: DWORD = 517; +pub const SV_LMANNOUNCE_PARMNUM: DWORD = 518; +pub const SV_DOMAIN_PARMNUM: DWORD = 519; +pub const SV_MAXCOPYREADLEN_PARMNUM: DWORD = 520; +pub const SV_MAXCOPYWRITELEN_PARMNUM: DWORD = 521; +pub const SV_MINKEEPSEARCH_PARMNUM: DWORD = 522; +pub const SV_MAXKEEPSEARCH_PARMNUM: DWORD = 523; +pub const SV_MINKEEPCOMPLSEARCH_PARMNUM: DWORD = 524; +pub const SV_MAXKEEPCOMPLSEARCH_PARMNUM: DWORD = 525; +pub const SV_THREADCOUNTADD_PARMNUM: DWORD = 526; +pub const SV_NUMBLOCKTHREADS_PARMNUM: DWORD = 527; +pub const SV_SCAVTIMEOUT_PARMNUM: DWORD = 528; +pub const SV_MINRCVQUEUE_PARMNUM: DWORD = 529; +pub const SV_MINFREEWORKITEMS_PARMNUM: DWORD = 530; +pub const SV_XACTMEMSIZE_PARMNUM: DWORD = 531; +pub const SV_THREADPRIORITY_PARMNUM: DWORD = 532; +pub const SV_MAXMPXCT_PARMNUM: DWORD = 533; +pub const SV_OPLOCKBREAKWAIT_PARMNUM: DWORD = 534; +pub const SV_OPLOCKBREAKRESPONSEWAIT_PARMNUM: DWORD = 535; +pub const SV_ENABLEOPLOCKS_PARMNUM: DWORD = 536; +pub const SV_ENABLEOPLOCKFORCECLOSE_PARMNUM: DWORD = 537; +pub const SV_ENABLEFCBOPENS_PARMNUM: DWORD = 538; +pub const SV_ENABLERAW_PARMNUM: DWORD = 539; +pub const SV_ENABLESHAREDNETDRIVES_PARMNUM: DWORD = 540; +pub const SV_MINFREECONNECTIONS_PARMNUM: DWORD = 541; +pub const SV_MAXFREECONNECTIONS_PARMNUM: DWORD = 542; +pub const SV_INITSESSTABLE_PARMNUM: DWORD = 543; +pub const SV_INITCONNTABLE_PARMNUM: DWORD = 544; +pub const SV_INITFILETABLE_PARMNUM: DWORD = 545; +pub const SV_INITSEARCHTABLE_PARMNUM: DWORD = 546; +pub const SV_ALERTSCHEDULE_PARMNUM: DWORD = 547; +pub const SV_ERRORTHRESHOLD_PARMNUM: DWORD = 548; +pub const SV_NETWORKERRORTHRESHOLD_PARMNUM: DWORD = 549; +pub const SV_DISKSPACETHRESHOLD_PARMNUM: DWORD = 550; +pub const SV_MAXLINKDELAY_PARMNUM: DWORD = 552; +pub const SV_MINLINKTHROUGHPUT_PARMNUM: DWORD = 553; +pub const SV_LINKINFOVALIDTIME_PARMNUM: DWORD = 554; +pub const SV_SCAVQOSINFOUPDATETIME_PARMNUM: DWORD = 555; +pub const SV_MAXWORKITEMIDLETIME_PARMNUM: DWORD = 556; +pub const SV_MAXRAWWORKITEMS_PARMNUM: DWORD = 557; +pub const SV_PRODUCTTYPE_PARMNUM: DWORD = 560; +pub const SV_SERVERSIZE_PARMNUM: DWORD = 561; +pub const SV_CONNECTIONLESSAUTODISC_PARMNUM: DWORD = 562; +pub const SV_SHARINGVIOLATIONRETRIES_PARMNUM: DWORD = 563; +pub const SV_SHARINGVIOLATIONDELAY_PARMNUM: DWORD = 564; +pub const SV_MAXGLOBALOPENSEARCH_PARMNUM: DWORD = 565; +pub const SV_REMOVEDUPLICATESEARCHES_PARMNUM: DWORD = 566; +pub const SV_LOCKVIOLATIONRETRIES_PARMNUM: DWORD = 567; +pub const SV_LOCKVIOLATIONOFFSET_PARMNUM: DWORD = 568; +pub const SV_LOCKVIOLATIONDELAY_PARMNUM: DWORD = 569; +pub const SV_MDLREADSWITCHOVER_PARMNUM: DWORD = 570; +pub const SV_CACHEDOPENLIMIT_PARMNUM: DWORD = 571; +pub const SV_CRITICALTHREADS_PARMNUM: DWORD = 572; +pub const SV_RESTRICTNULLSESSACCESS_PARMNUM: DWORD = 573; +pub const SV_ENABLEWFW311DIRECTIPX_PARMNUM: DWORD = 574; +pub const SV_OTHERQUEUEAFFINITY_PARMNUM: DWORD = 575; +pub const SV_QUEUESAMPLESECS_PARMNUM: DWORD = 576; +pub const SV_BALANCECOUNT_PARMNUM: DWORD = 577; +pub const SV_PREFERREDAFFINITY_PARMNUM: DWORD = 578; +pub const SV_MAXFREERFCBS_PARMNUM: DWORD = 579; +pub const SV_MAXFREEMFCBS_PARMNUM: DWORD = 580; +pub const SV_MAXFREELFCBS_PARMNUM: DWORD = 581; +pub const SV_MAXFREEPAGEDPOOLCHUNKS_PARMNUM: DWORD = 582; +pub const SV_MINPAGEDPOOLCHUNKSIZE_PARMNUM: DWORD = 583; +pub const SV_MAXPAGEDPOOLCHUNKSIZE_PARMNUM: DWORD = 584; +pub const SV_SENDSFROMPREFERREDPROCESSOR_PARMNUM: DWORD = 585; +pub const SV_MAXTHREADSPERQUEUE_PARMNUM: DWORD = 586; +pub const SV_CACHEDDIRECTORYLIMIT_PARMNUM: DWORD = 587; +pub const SV_MAXCOPYLENGTH_PARMNUM: DWORD = 588; +pub const SV_ENABLECOMPRESSION_PARMNUM: DWORD = 590; +pub const SV_AUTOSHAREWKS_PARMNUM: DWORD = 591; +pub const SV_AUTOSHARESERVER_PARMNUM: DWORD = 592; +pub const SV_ENABLESECURITYSIGNATURE_PARMNUM: DWORD = 593; +pub const SV_REQUIRESECURITYSIGNATURE_PARMNUM: DWORD = 594; +pub const SV_MINCLIENTBUFFERSIZE_PARMNUM: DWORD = 595; +pub const SV_CONNECTIONNOSESSIONSTIMEOUT_PARMNUM: DWORD = 596; +pub const SV_IDLETHREADTIMEOUT_PARMNUM: DWORD = 597; +pub const SV_ENABLEW9XSECURITYSIGNATURE_PARMNUM: DWORD = 598; +pub const SV_ENFORCEKERBEROSREAUTHENTICATION_PARMNUM: DWORD = 599; +pub const SV_DISABLEDOS_PARMNUM: DWORD = 600; +pub const SV_LOWDISKSPACEMINIMUM_PARMNUM: DWORD = 601; +pub const SV_DISABLESTRICTNAMECHECKING_PARMNUM: DWORD = 602; +pub const SV_ENABLEAUTHENTICATEUSERSHARING_PARMNUM: DWORD = 603; +pub const SV_COMMENT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_COMMENT_PARMNUM; +pub const SV_USERS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_USERS_PARMNUM; +pub const SV_DISC_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_DISC_PARMNUM; +pub const SV_HIDDEN_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_HIDDEN_PARMNUM; +pub const SV_ANNOUNCE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ANNOUNCE_PARMNUM; +pub const SV_ANNDELTA_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ANNDELTA_PARMNUM; +pub const SV_SESSOPENS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SESSOPENS_PARMNUM; +pub const SV_SESSVCS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SESSVCS_PARMNUM; +pub const SV_OPENSEARCH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_OPENSEARCH_PARMNUM; +pub const SV_MAXWORKITEMS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXWORKITEMS_PARMNUM; +pub const SV_MAXRAWBUFLEN_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXRAWBUFLEN_PARMNUM; +pub const SV_SESSUSERS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SESSUSERS_PARMNUM; +pub const SV_SESSCONNS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SESSCONNS_PARMNUM; +pub const SV_MAXNONPAGEDMEMORYUSAGE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM; +pub const SV_MAXPAGEDMEMORYUSAGE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXPAGEDMEMORYUSAGE_PARMNUM; +pub const SV_ENABLESOFTCOMPAT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLESOFTCOMPAT_PARMNUM; +pub const SV_ENABLEFORCEDLOGOFF_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLEFORCEDLOGOFF_PARMNUM; +pub const SV_TIMESOURCE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_TIMESOURCE_PARMNUM; +pub const SV_LMANNOUNCE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_LMANNOUNCE_PARMNUM; +pub const SV_MAXCOPYREADLEN_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXCOPYREADLEN_PARMNUM; +pub const SV_MAXCOPYWRITELEN_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXCOPYWRITELEN_PARMNUM; +pub const SV_MINKEEPSEARCH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MINKEEPSEARCH_PARMNUM; +pub const SV_MAXKEEPSEARCH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXKEEPSEARCH_PARMNUM; +pub const SV_MINKEEPCOMPLSEARCH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINKEEPCOMPLSEARCH_PARMNUM; +pub const SV_MAXKEEPCOMPLSEARCH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXKEEPCOMPLSEARCH_PARMNUM; +pub const SV_SCAVTIMEOUT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SCAVTIMEOUT_PARMNUM; +pub const SV_MINRCVQUEUE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MINRCVQUEUE_PARMNUM; +pub const SV_MINFREEWORKITEMS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINFREEWORKITEMS_PARMNUM; +pub const SV_MAXMPXCT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXMPXCT_PARMNUM; +pub const SV_OPLOCKBREAKWAIT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_OPLOCKBREAKWAIT_PARMNUM; +pub const SV_OPLOCKBREAKRESPONSEWAIT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_OPLOCKBREAKRESPONSEWAIT_PARMNUM; +pub const SV_ENABLEOPLOCKS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ENABLEOPLOCKS_PARMNUM; +pub const SV_ENABLEOPLOCKFORCECLOSE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLEOPLOCKFORCECLOSE_PARMNUM; +pub const SV_ENABLEFCBOPENS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ENABLEFCBOPENS_PARMNUM; +pub const SV_ENABLERAW_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ENABLERAW_PARMNUM; +pub const SV_ENABLESHAREDNETDRIVES_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLESHAREDNETDRIVES_PARMNUM; +pub const SV_MINFREECONNECTIONS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINFREECONNECTIONS_PARMNUM; +pub const SV_MAXFREECONNECTIONS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXFREECONNECTIONS_PARMNUM; +pub const SV_INITSESSTABLE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_INITSESSTABLE_PARMNUM; +pub const SV_INITCONNTABLE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_INITCONNTABLE_PARMNUM; +pub const SV_INITFILETABLE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_INITFILETABLE_PARMNUM; +pub const SV_INITSEARCHTABLE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_INITSEARCHTABLE_PARMNUM; +pub const SV_ALERTSCHEDULE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ALERTSCHEDULE_PARMNUM; +pub const SV_ERRORTHRESHOLD_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_ERRORTHRESHOLD_PARMNUM; +pub const SV_NETWORKERRORTHRESHOLD_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_NETWORKERRORTHRESHOLD_PARMNUM; +pub const SV_DISKSPACETHRESHOLD_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_DISKSPACETHRESHOLD_PARMNUM; +pub const SV_MAXLINKDELAY_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXLINKDELAY_PARMNUM; +pub const SV_MINLINKTHROUGHPUT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINLINKTHROUGHPUT_PARMNUM; +pub const SV_LINKINFOVALIDTIME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_LINKINFOVALIDTIME_PARMNUM; +pub const SV_SCAVQOSINFOUPDATETIME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_SCAVQOSINFOUPDATETIME_PARMNUM; +pub const SV_MAXWORKITEMIDLETIME_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXWORKITEMIDLETIME_PARMNUM; +pub const SV_MAXRAWWORKITEMS_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXRAWWORKITEMS_PARMNUM; +pub const SV_PRODUCTTYPE_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_PRODUCTTYPE_PARMNUM; +pub const SV_SERVERSIZE_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_SERVERSIZE_PARMNUM; +pub const SV_CONNECTIONLESSAUTODISC_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_CONNECTIONLESSAUTODISC_PARMNUM; +pub const SV_SHARINGVIOLATIONRETRIES_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_SHARINGVIOLATIONRETRIES_PARMNUM; +pub const SV_SHARINGVIOLATIONDELAY_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_SHARINGVIOLATIONDELAY_PARMNUM; +pub const SV_MAXGLOBALOPENSEARCH_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXGLOBALOPENSEARCH_PARMNUM; +pub const SV_REMOVEDUPLICATESEARCHES_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_REMOVEDUPLICATESEARCHES_PARMNUM; +pub const SV_LOCKVIOLATIONRETRIES_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_LOCKVIOLATIONRETRIES_PARMNUM; +pub const SV_LOCKVIOLATIONOFFSET_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_LOCKVIOLATIONOFFSET_PARMNUM; +pub const SV_LOCKVIOLATIONDELAY_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_LOCKVIOLATIONDELAY_PARMNUM; +pub const SV_MDLREADSWITCHOVER_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MDLREADSWITCHOVER_PARMNUM; +pub const SV_CACHEDOPENLIMIT_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_CACHEDOPENLIMIT_PARMNUM; +pub const SV_CRITICALTHREADS_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_CRITICALTHREADS_PARMNUM; +pub const SV_RESTRICTNULLSESSACCESS_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_RESTRICTNULLSESSACCESS_PARMNUM; +pub const SV_ENABLEWFW311DIRECTIPX_INFOLOEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLEWFW311DIRECTIPX_PARMNUM; +pub const SV_OTHERQUEUEAFFINITY_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_OTHERQUEUEAFFINITY_PARMNUM; +pub const SV_QUEUESAMPLESECS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_QUEUESAMPLESECS_PARMNUM; +pub const SV_BALANCECOUNT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_BALANCECOUNT_PARMNUM; +pub const SV_PREFERREDAFFINITY_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_PREFERREDAFFINITY_PARMNUM; +pub const SV_MAXFREERFCBS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXFREERFCBS_PARMNUM; +pub const SV_MAXFREEMFCBS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXFREEMFCBS_PARMNUM; +pub const SV_MAXFREELFCBS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXFREELFCBS_PARMNUM; +pub const SV_MAXFREEPAGEDPOOLCHUNKS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXFREEPAGEDPOOLCHUNKS_PARMNUM; +pub const SV_MINPAGEDPOOLCHUNKSIZE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINPAGEDPOOLCHUNKSIZE_PARMNUM; +pub const SV_MAXPAGEDPOOLCHUNKSIZE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXPAGEDPOOLCHUNKSIZE_PARMNUM; +pub const SV_SENDSFROMPREFERREDPROCESSOR_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_SENDSFROMPREFERREDPROCESSOR_PARMNUM; +pub const SV_MAXTHREADSPERQUEUE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MAXTHREADSPERQUEUE_PARMNUM; +pub const SV_CACHEDDIRECTORYLIMIT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_CACHEDDIRECTORYLIMIT_PARMNUM; +pub const SV_MAXCOPYLENGTH_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_MAXCOPYLENGTH_PARMNUM; +pub const SV_ENABLECOMPRESSION_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLECOMPRESSION_PARMNUM; +pub const SV_AUTOSHAREWKS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_AUTOSHAREWKS_PARMNUM; +pub const SV_AUTOSHARESERVER_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_AUTOSHARESERVER_PARMNUM; +pub const SV_ENABLESECURITYSIGNATURE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLESECURITYSIGNATURE_PARMNUM; +pub const SV_REQUIRESECURITYSIGNATURE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_REQUIRESECURITYSIGNATURE_PARMNUM; +pub const SV_MINCLIENTBUFFERSIZE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_MINCLIENTBUFFERSIZE_PARMNUM; +pub const SV_CONNECTIONNOSESSIONSTIMEOUT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_CONNECTIONNOSESSIONSTIMEOUT_PARMNUM; +pub const SV_IDLETHREADTIMEOUT_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_IDLETHREADTIMEOUT_PARMNUM; +pub const SV_ENABLEW9XSECURITYSIGNATURE_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLEW9XSECURITYSIGNATURE_PARMNUM; +pub const SV_ENFORCEKERBEROSREAUTHENTICATION_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENFORCEKERBEROSREAUTHENTICATION_PARMNUM; +pub const SV_DISABLEDOS_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SV_DISABLEDOS_PARMNUM; +pub const SV_LOWDISKSPACEMINIMUM_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_LOWDISKSPACEMINIMUM_PARMNUM; +pub const SV_DISABLESTRICTNAMECHECKING_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_DISABLESTRICTNAMECHECKING_PARMNUM; +pub const SV_ENABLEAUTHENTICATEUSERSHARING_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + + SV_ENABLEAUTHENTICATEUSERSHARING_PARMNUM; +pub const SVI1_NUM_ELEMENTS: DWORD = 5; +pub const SVI2_NUM_ELEMENTS: DWORD = 40; +pub const SVI3_NUM_ELEMENTS: DWORD = 44; +pub const SV_MAX_CMD_LEN: DWORD = PATHLEN; +pub const SW_AUTOPROF_LOAD_MASK: DWORD = 0x1; +pub const SW_AUTOPROF_SAVE_MASK: DWORD = 0x2; +pub const SV_MAX_SRV_HEUR_LEN: DWORD = 32; +pub const SV_USERS_PER_LICENSE: DWORD = 5; +pub const SVTI2_REMAP_PIPE_NAMES: DWORD = 0x02; +pub const SVTI2_SCOPED_NAME: DWORD = 0x04; +pub const SVTI2_CLUSTER_NAME: DWORD = 0x08; +pub const SVTI2_CLUSTER_DNN_NAME: DWORD = 0x10; +pub const SVTI2_UNICODE_TRANSPORT_ADDRESS: DWORD = 0x20; +pub const SVTI2_RESERVED1: DWORD = 0x1000; +pub const SVTI2_RESERVED2: DWORD = 0x2000; +pub const SVTI2_RESERVED3: DWORD = 0x4000; +pub const SVTI2_VALID_FLAGS: DWORD = SVTI2_REMAP_PIPE_NAMES | SVTI2_SCOPED_NAME + | SVTI2_CLUSTER_NAME | SVTI2_CLUSTER_DNN_NAME | SVTI2_UNICODE_TRANSPORT_ADDRESS; +pub const SRV_SUPPORT_HASH_GENERATION: DWORD = 0x0001; +pub const SRV_HASH_GENERATION_ACTIVE: DWORD = 0x0002; diff --git a/winapi/src/um/lmshare.rs b/winapi/src/um/lmshare.rs new file mode 100644 index 000000000..3024ac3aa --- /dev/null +++ b/winapi/src/um/lmshare.rs @@ -0,0 +1,379 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the API function prototypes and data structures +use shared::basetsd::PDWORD_PTR; +use shared::guiddef::GUID; +use shared::lmcons::{LMSTR, NET_API_STATUS, PARMNUM_BASE_INFOLEVEL}; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, ULONG}; +use um::winnt::{BOOLEAN, PSECURITY_DESCRIPTOR}; +extern "system" { + pub fn NetShareAdd( + servername: LMSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetShareEnum( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetShareEnumSticky( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetShareGetInfo( + servername: LMSTR, + netname: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetShareSetInfo( + servername: LMSTR, + netname: LMSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetShareDel( + servername: LMSTR, + netname: LMSTR, + reserved: DWORD, + ) -> NET_API_STATUS; + pub fn NetShareDelSticky( + servername: LMSTR, + netname: LMSTR, + reserved: DWORD, + ) -> NET_API_STATUS; + pub fn NetShareCheck( + servername: LMSTR, + device: LMSTR, + _type: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetShareDelEx( + servername: LMSTR, + level: DWORD, + buf: LPBYTE, + ) -> NET_API_STATUS; +} +STRUCT!{struct SHARE_INFO_0 { + shi0_netname: LMSTR, +}} +pub type PSHARE_INFO_0 = *mut SHARE_INFO_0; +pub type LPSHARE_INFO_0 = *mut SHARE_INFO_0; +STRUCT!{struct SHARE_INFO_1 { + shi1_netname: LMSTR, + shi1_type: DWORD, + shi1_remark: LMSTR, +}} +pub type PSHARE_INFO_1 = *mut SHARE_INFO_1; +pub type LPSHARE_INFO_1 = *mut SHARE_INFO_1; +STRUCT!{struct SHARE_INFO_2 { + shi2_netname: LMSTR, + shi2_type: DWORD, + shi2_remark: LMSTR, + shi2_permissions: DWORD, + shi2_max_uses: DWORD, + shi2_current_uses: DWORD, + shi2_path: LMSTR, + shi2_passwd: LMSTR, +}} +pub type PSHARE_INFO_2 = *mut SHARE_INFO_2; +pub type LPSHARE_INFO_2 = *mut SHARE_INFO_2; +STRUCT!{struct SHARE_INFO_501 { + shi501_netname: LMSTR, + shi501_type: DWORD, + shi501_remark: LMSTR, + shi501_flags: DWORD, +}} +pub type PSHARE_INFO_501 = *mut SHARE_INFO_501; +pub type LPSHARE_INFO_501 = *mut SHARE_INFO_501; +STRUCT!{struct SHARE_INFO_502 { + shi502_netname: LMSTR, + shi502_type: DWORD, + shi502_remark: LMSTR, + shi502_permissions: DWORD, + shi502_max_uses: DWORD, + shi502_current_uses: DWORD, + shi502_path: LMSTR, + shi502_passwd: LMSTR, + shi502_reserved: DWORD, + shi502_security_descriptor: PSECURITY_DESCRIPTOR, +}} +pub type PSHARE_INFO_502 = *mut SHARE_INFO_502; +pub type LPSHARE_INFO_502 = *mut SHARE_INFO_502; +STRUCT!{struct SHARE_INFO_503 { + shi503_netname: LMSTR, + shi503_type: DWORD, + shi503_remark: LMSTR, + shi503_permissions: DWORD, + shi503_max_uses: DWORD, + shi503_current_uses: DWORD, + shi503_path: LMSTR, + shi503_passwd: LMSTR, + shi503_servername: LMSTR, + shi503_reserved: DWORD, + shi503_security_descriptor: PSECURITY_DESCRIPTOR, +}} +pub type PSHARE_INFO_503 = *mut SHARE_INFO_503; +pub type LPSHARE_INFO_503 = *mut SHARE_INFO_503; +STRUCT!{struct SHARE_INFO_1004 { + shi1004_remark: LMSTR, +}} +pub type PSHARE_INFO_1004 = *mut SHARE_INFO_1004; +pub type LPSHARE_INFO_1004 = *mut SHARE_INFO_1004; +STRUCT!{struct SHARE_INFO_1005 { + shi1005_flags: DWORD, +}} +pub type PSHARE_INFO_1005 = *mut SHARE_INFO_1005; +pub type LPSHARE_INFO_1005 = *mut SHARE_INFO_1005; +STRUCT!{struct SHARE_INFO_1006 { + shi1006_max_uses: DWORD, +}} +pub type PSHARE_INFO_1006 = *mut SHARE_INFO_1006; +pub type LPSHARE_INFO_1006 = *mut SHARE_INFO_1006; +STRUCT!{struct SHARE_INFO_1501 { + shi1501_reserved: DWORD, + shi1501_security_descriptor: PSECURITY_DESCRIPTOR, +}} +pub type PSHARE_INFO_1501 = *mut SHARE_INFO_1501; +pub type LPSHARE_INFO_1501 = *mut SHARE_INFO_1501; +STRUCT!{struct SHARE_INFO_1503 { + shi1503_sharefilter: GUID, +}} +pub type PSHARE_INFO_1503 = *mut SHARE_INFO_1503; +pub type LPSHARE_INFO_1503 = *mut SHARE_INFO_1503; +extern "system" { + pub fn NetServerAliasAdd( + servername: LMSTR, + level: DWORD, + buf: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerAliasDel( + servername: LMSTR, + level: DWORD, + buf: LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServerAliasEnum( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct SERVER_ALIAS_INFO_0 { + srvai0_alias: LMSTR, + srvai0_target: LMSTR, + srvai0_default: BOOLEAN, + srvai0_reserved: ULONG, +}} +pub type PSERVER_ALIAS_INFO_0 = *mut SERVER_ALIAS_INFO_0; +pub type LPSERVER_ALIAS_INFO_0 = *mut SERVER_ALIAS_INFO_0; +pub const SHARE_NETNAME_PARMNUM: DWORD = 1; +pub const SHARE_TYPE_PARMNUM: DWORD = 3; +pub const SHARE_REMARK_PARMNUM: DWORD = 4; +pub const SHARE_PERMISSIONS_PARMNUM: DWORD = 5; +pub const SHARE_MAX_USES_PARMNUM: DWORD = 6; +pub const SHARE_CURRENT_USES_PARMNUM: DWORD = 7; +pub const SHARE_PATH_PARMNUM: DWORD = 8; +pub const SHARE_PASSWD_PARMNUM: DWORD = 9; +pub const SHARE_FILE_SD_PARMNUM: DWORD = 501; +pub const SHARE_SERVER_PARMNUM: DWORD = 503; +pub const SHARE_REMARK_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SHARE_REMARK_PARMNUM; +pub const SHARE_MAX_USES_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SHARE_MAX_USES_PARMNUM; +pub const SHARE_FILE_SD_INFOLEVEL: DWORD = PARMNUM_BASE_INFOLEVEL + SHARE_FILE_SD_PARMNUM; +pub const SHI1_NUM_ELEMENTS: DWORD = 4; +pub const SHI2_NUM_ELEMENTS: DWORD = 10; +pub const STYPE_DISKTREE: DWORD = 0; +pub const STYPE_PRINTQ: DWORD = 1; +pub const STYPE_DEVICE: DWORD = 2; +pub const STYPE_IPC: DWORD = 3; +pub const STYPE_MASK: DWORD = 0x000000FF; +pub const STYPE_RESERVED1: DWORD = 0x01000000; +pub const STYPE_RESERVED2: DWORD = 0x02000000; +pub const STYPE_RESERVED3: DWORD = 0x04000000; +pub const STYPE_RESERVED4: DWORD = 0x08000000; +pub const STYPE_RESERVED_ALL: DWORD = 0x3FFFFF00; +pub const STYPE_TEMPORARY: DWORD = 0x40000000; +pub const STYPE_SPECIAL: DWORD = 0x80000000; +pub const SHI_USES_UNLIMITED: DWORD = -1i32 as u32; +pub const SHI1005_FLAGS_DFS: DWORD = 0x0001; +pub const SHI1005_FLAGS_DFS_ROOT: DWORD = 0x0002; +pub const CSC_MASK_EXT: DWORD = 0x2030; +pub const CSC_MASK: DWORD = 0x0030; +pub const CSC_CACHE_MANUAL_REINT: DWORD = 0x0000; +pub const CSC_CACHE_AUTO_REINT: DWORD = 0x0010; +pub const CSC_CACHE_VDO: DWORD = 0x0020; +pub const CSC_CACHE_NONE: DWORD = 0x0030; +pub const SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS: DWORD = 0x00100; +pub const SHI1005_FLAGS_FORCE_SHARED_DELETE: DWORD = 0x00200; +pub const SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING: DWORD = 0x00400; +pub const SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM: DWORD = 0x00800; +pub const SHI1005_FLAGS_FORCE_LEVELII_OPLOCK: DWORD = 0x01000; +pub const SHI1005_FLAGS_ENABLE_HASH: DWORD = 0x02000; +pub const SHI1005_FLAGS_ENABLE_CA: DWORD = 0x04000; +pub const SHI1005_FLAGS_ENCRYPT_DATA: DWORD = 0x08000; +pub const SHI1005_FLAGS_RESERVED: DWORD = 0x10000; +pub const SHI1005_VALID_FLAGS_SET: DWORD = CSC_MASK | SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS + | SHI1005_FLAGS_FORCE_SHARED_DELETE | SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING + | SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM | SHI1005_FLAGS_FORCE_LEVELII_OPLOCK + | SHI1005_FLAGS_ENABLE_HASH | SHI1005_FLAGS_ENABLE_CA | SHI1005_FLAGS_ENCRYPT_DATA + | SHI1005_FLAGS_RESERVED; +extern "system" { + pub fn NetSessionEnum( + servername: LMSTR, + UncClientName: LMSTR, + username: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetSessionDel( + servername: LMSTR, + UncClientName: LMSTR, + username: LMSTR, + ) -> NET_API_STATUS; + pub fn NetSessionGetInfo( + servername: LMSTR, + UncClientName: LMSTR, + username: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; +} +STRUCT!{struct SESSION_INFO_0 { + sesi0_cname: LMSTR, +}} +pub type PSESSION_INFO_0 = *mut SESSION_INFO_0; +pub type LPSESSION_INFO_0 = *mut SESSION_INFO_0; +STRUCT!{struct SESSION_INFO_1 { + sesi1_cname: LMSTR, + sesi1_username: LMSTR, + sesi1_num_opens: DWORD, + sesi1_time: DWORD, + sesi1_idle_time: DWORD, + sesi1_user_flags: DWORD, +}} +pub type PSESSION_INFO_1 = *mut SESSION_INFO_1; +pub type LPSESSION_INFO_1 = *mut SESSION_INFO_1; +STRUCT!{struct SESSION_INFO_2 { + sesi2_cname: LMSTR, + sesi2_username: LMSTR, + sesi2_num_opens: DWORD, + sesi2_time: DWORD, + sesi2_idle_time: DWORD, + sesi2_user_flags: DWORD, + sesi2_cltype_name: LMSTR, +}} +pub type PSESSION_INFO_2 = *mut SESSION_INFO_2; +pub type LPSESSION_INFO_2 = *mut SESSION_INFO_2; +STRUCT!{struct SESSION_INFO_10 { + sesi10_cname: LMSTR, + sesi10_username: LMSTR, + sesi10_time: DWORD, + sesi10_idle_time: DWORD, +}} +pub type PSESSION_INFO_10 = *mut SESSION_INFO_10; +pub type LPSESSION_INFO_10 = *mut SESSION_INFO_10; +STRUCT!{struct SESSION_INFO_502 { + sesi502_cname: LMSTR, + sesi502_username: LMSTR, + sesi502_num_opens: DWORD, + sesi502_time: DWORD, + sesi502_idle_time: DWORD, + sesi502_user_flags: DWORD, + sesi502_cltype_name: LMSTR, + sesi502_transport: LMSTR, +}} +pub type PSESSION_INFO_502 = *mut SESSION_INFO_502; +pub type LPSESSION_INFO_502 = *mut SESSION_INFO_502; +pub const SESS_GUEST: DWORD = 0x00000001; +pub const SESS_NOENCRYPTION: DWORD = 0x00000002; +pub const SESI1_NUM_ELEMENTS: DWORD = 8; +pub const SESI2_NUM_ELEMENTS: DWORD = 9; +extern "system" { + pub fn NetConnectionEnum( + servername: LMSTR, + qualifier: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resume_handle: LPDWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct CONNECTION_INFO_0 { + coni0_id: DWORD, +}} +pub type PCONNECTION_INFO_0 = *mut CONNECTION_INFO_0; +pub type LPCONNECTION_INFO_0 = *mut CONNECTION_INFO_0; +STRUCT!{struct CONNECTION_INFO_1 { + coni1_id: DWORD, + coni1_type: DWORD, + coni1_num_opens: DWORD, + coni1_num_users: DWORD, + coni1_time: DWORD, + coni1_username: LMSTR, + coni1_netname: LMSTR, +}} +pub type PCONNECTION_INFO_1 = *mut CONNECTION_INFO_1; +pub type LPCONNECTION_INFO_1 = *mut CONNECTION_INFO_1; +extern "system" { + pub fn NetFileClose( + servername: LMSTR, + fileid: DWORD, + ) -> NET_API_STATUS; + pub fn NetFileEnum( + servername: LMSTR, + basepath: LMSTR, + username: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resume_handle: PDWORD_PTR, + ) -> NET_API_STATUS; + pub fn NetFileGetInfo( + servername: LMSTR, + fileid: DWORD, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; +} +STRUCT!{struct FILE_INFO_2 { + fi2_id: DWORD, +}} +pub type PFILE_INFO_2 = *mut FILE_INFO_2; +pub type LPFILE_INFO_2 = *mut FILE_INFO_2; +STRUCT!{struct FILE_INFO_3 { + fi3_id: DWORD, + fi3_permissions: DWORD, + fi3_num_locks: DWORD, + fi3_pathname: LMSTR, + fi3_username: LMSTR, +}} +pub type PFILE_INFO_3 = *mut FILE_INFO_3; +pub type LPFILE_INFO_3 = *mut FILE_INFO_3; +pub const PERM_FILE_READ: DWORD = 0x1; +pub const PERM_FILE_WRITE: DWORD = 0x2; +pub const PERM_FILE_CREATE: DWORD = 0x4; diff --git a/winapi/src/um/lmstats.rs b/winapi/src/um/lmstats.rs new file mode 100644 index 000000000..c0bfc3746 --- /dev/null +++ b/winapi/src/um/lmstats.rs @@ -0,0 +1,85 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE}; +use um::winnt::{LARGE_INTEGER, LPCWSTR}; +extern "system" { + pub fn NetStatisticsGet( + ServerName: LPCWSTR, + Service: LPCWSTR, + Level: DWORD, + Options: DWORD, + Buffer: *mut LPBYTE, + ) -> NET_API_STATUS; +} +STRUCT!{struct STAT_WORKSTATION_0 { + StatisticsStartTime: LARGE_INTEGER, + BytesReceived: LARGE_INTEGER, + SmbsReceived: LARGE_INTEGER, + PagingReadBytesRequested: LARGE_INTEGER, + NonPagingReadBytesRequested: LARGE_INTEGER, + CacheReadBytesRequested: LARGE_INTEGER, + NetworkReadBytesRequested: LARGE_INTEGER, + BytesTransmitted: LARGE_INTEGER, + SmbsTransmitted: LARGE_INTEGER, + PagingWriteBytesRequested: LARGE_INTEGER, + NonPagingWriteBytesRequested: LARGE_INTEGER, + CacheWriteBytesRequested: LARGE_INTEGER, + NetworkWriteBytesRequested: LARGE_INTEGER, + InitiallyFailedOperations: DWORD, + FailedCompletionOperations: DWORD, + ReadOperations: DWORD, + RandomReadOperations: DWORD, + ReadSmbs: DWORD, + LargeReadSmbs: DWORD, + SmallReadSmbs: DWORD, + WriteOperations: DWORD, + RandomWriteOperations: DWORD, + WriteSmbs: DWORD, + LargeWriteSmbs: DWORD, + SmallWriteSmbs: DWORD, + RawReadsDenied: DWORD, + RawWritesDenied: DWORD, + NetworkErrors: DWORD, + Sessions: DWORD, + FailedSessions: DWORD, + Reconnects: DWORD, + CoreConnects: DWORD, + Lanman20Connects: DWORD, + Lanman21Connects: DWORD, + LanmanNtConnects: DWORD, + ServerDisconnects: DWORD, + HungSessions: DWORD, + UseCount: DWORD, + FailedUseCount: DWORD, + CurrentCommands: DWORD, +}} +pub type PSTAT_WORKSTATION_0 = *mut STAT_WORKSTATION_0; +pub type LPSTAT_WORKSTATION_0 = *mut STAT_WORKSTATION_0; +STRUCT!{struct STAT_SERVER_0 { + sts0_start: DWORD, + sts0_fopens: DWORD, + sts0_devopens: DWORD, + sts0_jobsqueued: DWORD, + sts0_sopens: DWORD, + sts0_stimedout: DWORD, + sts0_serrorout: DWORD, + sts0_pwerrors: DWORD, + sts0_permerrors: DWORD, + sts0_syserrors: DWORD, + sts0_bytessent_low: DWORD, + sts0_bytessent_high: DWORD, + sts0_bytesrcvd_low: DWORD, + sts0_bytesrcvd_high: DWORD, + sts0_avresponse: DWORD, + sts0_reqbufneed: DWORD, + sts0_bigbufneed: DWORD, +}} +pub type PSTAT_SERVER_0 = *mut STAT_SERVER_0; +pub type LPSTAT_SERVER_0 = *mut STAT_SERVER_0; +pub const STATSOPT_CLR: DWORD = 1; +pub const STATS_NO_VALUE: DWORD = -1i32 as u32; +pub const STATS_OVERFLOW: DWORD = -2i32 as u32; diff --git a/winapi/src/um/lmsvc.rs b/winapi/src/um/lmsvc.rs new file mode 100644 index 000000000..2d9ee5e2e --- /dev/null +++ b/winapi/src/um/lmsvc.rs @@ -0,0 +1,180 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This file contains structures, function prototypes, and definitions for the NetService API +use ctypes::c_long; +use shared::lmcons::NET_API_STATUS; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD}; +use um::winnt::{LPCWSTR, LPWSTR}; +STRUCT!{struct SERVICE_INFO_0 { + svci0_name: LPWSTR, +}} +pub type PSERVICE_INFO_0 = *mut SERVICE_INFO_0; +pub type LPSERVICE_INFO_0 = *mut SERVICE_INFO_0; +STRUCT!{struct SERVICE_INFO_1 { + svci1_name: LPWSTR, + svci1_status: DWORD, + svci1_code: DWORD, + svci1_pid: DWORD, +}} +pub type PSERVICE_INFO_1 = *mut SERVICE_INFO_1; +pub type LPSERVICE_INFO_1 = *mut SERVICE_INFO_1; +STRUCT!{struct SERVICE_INFO_2 { + svci2_name: LPWSTR, + svci2_status: DWORD, + svci2_code: DWORD, + svci2_pid: DWORD, + svci2_text: LPWSTR, + svci2_specific_error: DWORD, + svci2_display_name: LPWSTR, +}} +pub type PSERVICE_INFO_2 = *mut SERVICE_INFO_2; +pub type LPSERVICE_INFO_2 = *mut SERVICE_INFO_2; +extern "system" { + pub fn NetServiceControl( + servername: LPCWSTR, + service: LPCWSTR, + opcode: DWORD, + arg: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServiceEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetServiceGetInfo( + servername: LPCWSTR, + service: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetServiceInstall( + servername: LPCWSTR, + service: LPCWSTR, + argc: DWORD, + argv: *mut LPCWSTR, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; +} +pub const SERVICE_INSTALL_STATE: DWORD = 0x03; +pub const SERVICE_UNINSTALLED: DWORD = 0x00; +pub const SERVICE_INSTALL_PENDING: DWORD = 0x01; +pub const SERVICE_UNINSTALL_PENDING: DWORD = 0x02; +pub const SERVICE_INSTALLED: DWORD = 0x03; +pub const SERVICE_PAUSE_STATE: DWORD = 0x0C; +pub const LM20_SERVICE_ACTIVE: DWORD = 0x00; +pub const LM20_SERVICE_CONTINUE_PENDING: DWORD = 0x04; +pub const LM20_SERVICE_PAUSE_PENDING: DWORD = 0x08; +pub const LM20_SERVICE_PAUSED: DWORD = 0x0C; +pub const SERVICE_NOT_UNINSTALLABLE: DWORD = 0x00; +pub const SERVICE_UNINSTALLABLE: DWORD = 0x10; +pub const SERVICE_NOT_PAUSABLE: DWORD = 0x00; +pub const SERVICE_PAUSABLE: DWORD = 0x20; +pub const SERVICE_REDIR_PAUSED: DWORD = 0x700; +pub const SERVICE_REDIR_DISK_PAUSED: DWORD = 0x100; +pub const SERVICE_REDIR_PRINT_PAUSED: DWORD = 0x200; +pub const SERVICE_REDIR_COMM_PAUSED: DWORD = 0x400; +pub const SERVICE_DOS_ENCRYPTION: &'static str = "ENCRYPT"; +pub const SERVICE_CTRL_INTERROGATE: DWORD = 0; +pub const SERVICE_CTRL_PAUSE: DWORD = 1; +pub const SERVICE_CTRL_CONTINUE: DWORD = 2; +pub const SERVICE_CTRL_UNINSTALL: DWORD = 3; +pub const SERVICE_CTRL_REDIR_DISK: DWORD = 0x1; +pub const SERVICE_CTRL_REDIR_PRINT: DWORD = 0x2; +pub const SERVICE_CTRL_REDIR_COMM: DWORD = 0x4; +pub const SERVICE_IP_NO_HINT: DWORD = 0x0; +pub const SERVICE_CCP_NO_HINT: DWORD = 0x0; +pub const SERVICE_IP_QUERY_HINT: DWORD = 0x10000; +pub const SERVICE_CCP_QUERY_HINT: DWORD = 0x10000; +pub const SERVICE_IP_CHKPT_NUM: DWORD = 0x0FF; +pub const SERVICE_CCP_CHKPT_NUM: DWORD = 0x0FF; +pub const SERVICE_IP_WAIT_TIME: DWORD = 0x0FF00; +pub const SERVICE_CCP_WAIT_TIME: DWORD = 0x0FF00; +pub const SERVICE_IP_WAITTIME_SHIFT: DWORD = 8; +pub const SERVICE_NTIP_WAITTIME_SHIFT: DWORD = 12; +pub const UPPER_HINT_MASK: DWORD = 0x0000FF00; +pub const LOWER_HINT_MASK: DWORD = 0x000000FF; +pub const UPPER_GET_HINT_MASK: DWORD = 0x0FF00000; +pub const LOWER_GET_HINT_MASK: DWORD = 0x0000FF00; +pub const SERVICE_NT_MAXTIME: DWORD = 0x0000FFFF; +pub const SERVICE_RESRV_MASK: DWORD = 0x0001FFFF; +pub const SERVICE_MAXTIME: DWORD = 0x000000FF; +pub const SERVICE_BASE: DWORD = 3050; +pub const SERVICE_UIC_NORMAL: DWORD = 0; +pub const SERVICE_UIC_BADPARMVAL: DWORD = SERVICE_BASE + 1; +pub const SERVICE_UIC_MISSPARM: DWORD = SERVICE_BASE + 2; +pub const SERVICE_UIC_UNKPARM: DWORD = SERVICE_BASE + 3; +pub const SERVICE_UIC_RESOURCE: DWORD = SERVICE_BASE + 4; +pub const SERVICE_UIC_CONFIG: DWORD = SERVICE_BASE + 5; +pub const SERVICE_UIC_SYSTEM: DWORD = SERVICE_BASE + 6; +pub const SERVICE_UIC_INTERNAL: DWORD = SERVICE_BASE + 7; +pub const SERVICE_UIC_AMBIGPARM: DWORD = SERVICE_BASE + 8; +pub const SERVICE_UIC_DUPPARM: DWORD = SERVICE_BASE + 9; +pub const SERVICE_UIC_KILL: DWORD = SERVICE_BASE + 10; +pub const SERVICE_UIC_EXEC: DWORD = SERVICE_BASE + 11; +pub const SERVICE_UIC_SUBSERV: DWORD = SERVICE_BASE + 12; +pub const SERVICE_UIC_CONFLPARM: DWORD = SERVICE_BASE + 13; +pub const SERVICE_UIC_FILE: DWORD = SERVICE_BASE + 14; +pub const SERVICE_UIC_M_NULL: DWORD = 0; +pub const SERVICE_UIC_M_MEMORY: DWORD = SERVICE_BASE + 20; +pub const SERVICE_UIC_M_DISK: DWORD = SERVICE_BASE + 21; +pub const SERVICE_UIC_M_THREADS: DWORD = SERVICE_BASE + 22; +pub const SERVICE_UIC_M_PROCESSES: DWORD = SERVICE_BASE + 23; +pub const SERVICE_UIC_M_SECURITY: DWORD = SERVICE_BASE + 24; +pub const SERVICE_UIC_M_LANROOT: DWORD = SERVICE_BASE + 25; +pub const SERVICE_UIC_M_REDIR: DWORD = SERVICE_BASE + 26; +pub const SERVICE_UIC_M_SERVER: DWORD = SERVICE_BASE + 27; +pub const SERVICE_UIC_M_SEC_FILE_ERR: DWORD = SERVICE_BASE + 28; +pub const SERVICE_UIC_M_FILES: DWORD = SERVICE_BASE + 29; +pub const SERVICE_UIC_M_LOGS: DWORD = SERVICE_BASE + 30; +pub const SERVICE_UIC_M_LANGROUP: DWORD = SERVICE_BASE + 31; +pub const SERVICE_UIC_M_MSGNAME: DWORD = SERVICE_BASE + 32; +pub const SERVICE_UIC_M_ANNOUNCE: DWORD = SERVICE_BASE + 33; +pub const SERVICE_UIC_M_UAS: DWORD = SERVICE_BASE + 34; +pub const SERVICE_UIC_M_SERVER_SEC_ERR: DWORD = SERVICE_BASE + 35; +pub const SERVICE_UIC_M_WKSTA: DWORD = SERVICE_BASE + 37; +pub const SERVICE_UIC_M_ERRLOG: DWORD = SERVICE_BASE + 38; +pub const SERVICE_UIC_M_FILE_UW: DWORD = SERVICE_BASE + 39; +pub const SERVICE_UIC_M_ADDPAK: DWORD = SERVICE_BASE + 40; +pub const SERVICE_UIC_M_LAZY: DWORD = SERVICE_BASE + 41; +pub const SERVICE_UIC_M_UAS_MACHINE_ACCT: DWORD = SERVICE_BASE + 42; +pub const SERVICE_UIC_M_UAS_SERVERS_NMEMB: DWORD = SERVICE_BASE + 43; +pub const SERVICE_UIC_M_UAS_SERVERS_NOGRP: DWORD = SERVICE_BASE + 44; +pub const SERVICE_UIC_M_UAS_INVALID_ROLE: DWORD = SERVICE_BASE + 45; +pub const SERVICE_UIC_M_NETLOGON_NO_DC: DWORD = SERVICE_BASE + 46; +pub const SERVICE_UIC_M_NETLOGON_DC_CFLCT: DWORD = SERVICE_BASE + 47; +pub const SERVICE_UIC_M_NETLOGON_AUTH: DWORD = SERVICE_BASE + 48; +pub const SERVICE_UIC_M_UAS_PROLOG: DWORD = SERVICE_BASE + 49; +pub const SERVICE2_BASE: DWORD = 5600; +pub const SERVICE_UIC_M_NETLOGON_MPATH: DWORD = SERVICE2_BASE + 0; +pub const SERVICE_UIC_M_LSA_MACHINE_ACCT: DWORD = SERVICE2_BASE + 1; +pub const SERVICE_UIC_M_DATABASE_ERROR: DWORD = SERVICE2_BASE + 2; +#[inline] +pub fn SERVICE_IP_CODE(tt: DWORD, nn: DWORD) -> c_long { + (SERVICE_IP_QUERY_HINT | (nn | (tt << SERVICE_IP_WAITTIME_SHIFT))) as c_long +} +#[inline] +pub fn SERVICE_CCP_CODE(tt: DWORD, nn: DWORD) -> c_long { + (SERVICE_CCP_QUERY_HINT | (nn | (tt << SERVICE_IP_WAITTIME_SHIFT))) as c_long +} +#[inline] +pub fn SERVICE_UIC_CODE(cc: DWORD, mm: DWORD) -> c_long { + ((cc << 16) | mm) as c_long +} +#[inline] +pub fn SERVICE_NT_CCP_CODE(tt: DWORD, nn: DWORD) -> c_long { + (SERVICE_CCP_QUERY_HINT | nn | ((tt & LOWER_HINT_MASK) << SERVICE_IP_WAITTIME_SHIFT) + | ((tt & UPPER_HINT_MASK) << SERVICE_NTIP_WAITTIME_SHIFT)) as c_long +} +#[inline] +pub fn SERVICE_NT_WAIT_GET(code: DWORD) -> DWORD { + ((code & UPPER_GET_HINT_MASK) >> SERVICE_NTIP_WAITTIME_SHIFT) + | ((code & LOWER_GET_HINT_MASK) >> SERVICE_IP_WAITTIME_SHIFT) +} diff --git a/winapi/src/um/lmuse.rs b/winapi/src/um/lmuse.rs new file mode 100644 index 000000000..66423121f --- /dev/null +++ b/winapi/src/um/lmuse.rs @@ -0,0 +1,101 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This file contains structures, function prototypes, and definitions for the NetUse API +use shared::lmcons::{LMSTR, NET_API_STATUS}; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, PBYTE, ULONG}; +use um::winnt::LPWSTR; +extern "system" { + pub fn NetUseAdd( + servername: LPWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUseDel( + UncServerName: LMSTR, + UseName: LMSTR, + ForceCond: DWORD, + ) -> NET_API_STATUS; + pub fn NetUseEnum( + UncServerName: LMSTR, + Level: DWORD, + BufPtr: *mut LPBYTE, + PreferedMaximumSize: DWORD, + EntriesRead: LPDWORD, + TotalEntries: LPDWORD, + ResumeHandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetUseGetInfo( + UncServerName: LMSTR, + UseName: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; +} +STRUCT!{struct USE_INFO_0 { + ui0_local: LMSTR, + ui0_remote: LMSTR, +}} +pub type PUSE_INFO_0 = *mut USE_INFO_0; +pub type LPUSE_INFO_0 = *mut USE_INFO_0; +STRUCT!{struct USE_INFO_1 { + ui1_local: LMSTR, + ui1_remote: LMSTR, + ui1_password: LMSTR, + ui1_status: DWORD, + ui1_asg_type: DWORD, + ui1_refcount: DWORD, + ui1_usecount: DWORD, +}} +pub type PUSE_INFO_1 = *mut USE_INFO_1; +pub type LPUSE_INFO_1 = *mut USE_INFO_1; +STRUCT!{struct USE_INFO_2 { + ui2_local: LMSTR, + ui2_remote: LMSTR, + ui2_password: LMSTR, + ui2_status: DWORD, + ui2_asg_type: DWORD, + ui2_refcount: DWORD, + ui2_usecount: DWORD, + ui2_username: LMSTR, + ui2_domainname: LMSTR, +}} +pub type PUSE_INFO_2 = *mut USE_INFO_2; +pub type LPUSE_INFO_2 = *mut USE_INFO_2; +STRUCT!{struct USE_INFO_3 { + ui3_ui2: USE_INFO_2, + ui3_flags: ULONG, +}} +pub type PUSE_INFO_3 = *mut USE_INFO_3; +STRUCT!{struct USE_INFO_4 { + ui4_ui3: USE_INFO_3, + ui4_auth_identity_length: DWORD, + ui4_auth_identity: PBYTE, +}} +pub type PUSE_INFO_4 = *mut USE_INFO_4; +pub type LPUSE_INFO_4 = *mut USE_INFO_4; +pub const USE_LOCAL_PARMNUM: DWORD = 1; +pub const USE_REMOTE_PARMNUM: DWORD = 2; +pub const USE_PASSWORD_PARMNUM: DWORD = 3; +pub const USE_ASGTYPE_PARMNUM: DWORD = 4; +pub const USE_USERNAME_PARMNUM: DWORD = 5; +pub const USE_DOMAINNAME_PARMNUM: DWORD = 6; +pub const USE_OK: DWORD = 0; +pub const USE_PAUSED: DWORD = 1; +pub const USE_SESSLOST: DWORD = 2; +pub const USE_DISCONN: DWORD = 2; +pub const USE_NETERR: DWORD = 3; +pub const USE_CONN: DWORD = 4; +pub const USE_RECONN: DWORD = 5; +pub const USE_WILDCARD: DWORD = -1i32 as u32; +pub const USE_DISKDEV: DWORD = 0; +pub const USE_SPOOLDEV: DWORD = 1; +pub const USE_CHARDEV: DWORD = 2; +pub const USE_IPC: DWORD = 3; +pub const CREATE_NO_CONNECT: ULONG = 0x1; +pub const CREATE_BYPASS_CSC: ULONG = 0x2; +pub const CREATE_CRED_RESET: ULONG = 0x4; +pub const USE_DEFAULT_CREDENTIALS: ULONG = 0x4; diff --git a/winapi/src/um/lmwksta.rs b/winapi/src/um/lmwksta.rs new file mode 100644 index 000000000..9b086bf60 --- /dev/null +++ b/winapi/src/um/lmwksta.rs @@ -0,0 +1,421 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +use shared::lmcons::{LMSTR, NET_API_STATUS}; +use shared::minwindef::{BOOL, DWORD, LPBYTE, LPDWORD}; +use um::winnt::LPCWSTR; +extern "system" { + pub fn NetWkstaGetInfo( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetWkstaSetInfo( + servername: LMSTR, + level: DWORD, + buffer: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetWkstaUserGetInfo( + reserved: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + ) -> NET_API_STATUS; + pub fn NetWkstaUserSetInfo( + reserved: LMSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetWkstaUserEnum( + servername: LMSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetWkstaTransportAdd( + servername: LPCWSTR, + level: DWORD, + buf: LPBYTE, + parm_err: LPDWORD, + ) -> NET_API_STATUS; + pub fn NetWkstaTransportDel( + servername: LMSTR, + transportname: LMSTR, + ucond: DWORD, + ) -> NET_API_STATUS; + pub fn NetWkstaTransportEnum( + servername: LPCWSTR, + level: DWORD, + bufptr: *mut LPBYTE, + prefmaxlen: DWORD, + entriesread: LPDWORD, + totalentries: LPDWORD, + resumehandle: LPDWORD, + ) -> NET_API_STATUS; +} +STRUCT!{struct WKSTA_INFO_100 { + wki100_platform_id: DWORD, + wki100_computername: LMSTR, + wki100_langroup: LMSTR, + wki100_ver_major: DWORD, + wki100_ver_minor: DWORD, +}} +pub type PWKSTA_INFO_100 = *mut WKSTA_INFO_100; +pub type LPWKSTA_INFO_100 = *mut WKSTA_INFO_100; +STRUCT!{struct WKSTA_INFO_101 { + wki101_platform_id: DWORD, + wki101_computername: LMSTR, + wki101_langroup: LMSTR, + wki101_ver_major: DWORD, + wki101_ver_minor: DWORD, + wki101_lanroot: LMSTR, +}} +pub type PWKSTA_INFO_101 = *mut WKSTA_INFO_101; +pub type LPWKSTA_INFO_101 = *mut WKSTA_INFO_101; +STRUCT!{struct WKSTA_INFO_102 { + wki102_platform_id: DWORD, + wki102_computername: LMSTR, + wki102_langroup: LMSTR, + wki102_ver_major: DWORD, + wki102_ver_minor: DWORD, + wki102_lanroot: LMSTR, + wki102_logged_on_users: DWORD, +}} +pub type PWKSTA_INFO_102 = *mut WKSTA_INFO_102; +pub type LPWKSTA_INFO_102 = *mut WKSTA_INFO_102; +STRUCT!{struct WKSTA_INFO_302 { + wki302_char_wait: DWORD, + wki302_collection_time: DWORD, + wki302_maximum_collection_count: DWORD, + wki302_keep_conn: DWORD, + wki302_keep_search: DWORD, + wki302_max_cmds: DWORD, + wki302_num_work_buf: DWORD, + wki302_siz_work_buf: DWORD, + wki302_max_wrk_cache: DWORD, + wki302_sess_timeout: DWORD, + wki302_siz_error: DWORD, + wki302_num_alerts: DWORD, + wki302_num_services: DWORD, + wki302_errlog_sz: DWORD, + wki302_print_buf_time: DWORD, + wki302_num_char_buf: DWORD, + wki302_siz_char_buf: DWORD, + wki302_wrk_heuristics: LMSTR, + wki302_mailslots: DWORD, + wki302_num_dgram_buf: DWORD, +}} +pub type PWKSTA_INFO_302 = *mut WKSTA_INFO_302; +pub type LPWKSTA_INFO_302 = *mut WKSTA_INFO_302; +STRUCT!{struct WKSTA_INFO_402 { + wki402_char_wait: DWORD, + wki402_collection_time: DWORD, + wki402_maximum_collection_count: DWORD, + wki402_keep_conn: DWORD, + wki402_keep_search: DWORD, + wki402_max_cmds: DWORD, + wki402_num_work_buf: DWORD, + wki402_siz_work_buf: DWORD, + wki402_max_wrk_cache: DWORD, + wki402_sess_timeout: DWORD, + wki402_siz_error: DWORD, + wki402_num_alerts: DWORD, + wki402_num_services: DWORD, + wki402_errlog_sz: DWORD, + wki402_print_buf_time: DWORD, + wki402_num_char_buf: DWORD, + wki402_siz_char_buf: DWORD, + wki402_wrk_heuristics: LMSTR, + wki402_mailslots: DWORD, + wki402_num_dgram_buf: DWORD, + wki402_max_threads: DWORD, +}} +pub type PWKSTA_INFO_402 = *mut WKSTA_INFO_402; +pub type LPWKSTA_INFO_402 = *mut WKSTA_INFO_402; +STRUCT!{struct WKSTA_INFO_502 { + wki502_char_wait: DWORD, + wki502_collection_time: DWORD, + wki502_maximum_collection_count: DWORD, + wki502_keep_conn: DWORD, + wki502_max_cmds: DWORD, + wki502_sess_timeout: DWORD, + wki502_siz_char_buf: DWORD, + wki502_max_threads: DWORD, + wki502_lock_quota: DWORD, + wki502_lock_increment: DWORD, + wki502_lock_maximum: DWORD, + wki502_pipe_increment: DWORD, + wki502_pipe_maximum: DWORD, + wki502_cache_file_timeout: DWORD, + wki502_dormant_file_limit: DWORD, + wki502_read_ahead_throughput: DWORD, + wki502_num_mailslot_buffers: DWORD, + wki502_num_srv_announce_buffers: DWORD, + wki502_max_illegal_datagram_events: DWORD, + wki502_illegal_datagram_event_reset_frequency: DWORD, + wki502_log_election_packets: BOOL, + wki502_use_opportunistic_locking: BOOL, + wki502_use_unlock_behind: BOOL, + wki502_use_close_behind: BOOL, + wki502_buf_named_pipes: BOOL, + wki502_use_lock_read_unlock: BOOL, + wki502_utilize_nt_caching: BOOL, + wki502_use_raw_read: BOOL, + wki502_use_raw_write: BOOL, + wki502_use_write_raw_data: BOOL, + wki502_use_encryption: BOOL, + wki502_buf_files_deny_write: BOOL, + wki502_buf_read_only_files: BOOL, + wki502_force_core_create_mode: BOOL, + wki502_use_512_byte_max_transfer: BOOL, +}} +pub type PWKSTA_INFO_502 = *mut WKSTA_INFO_502; +pub type LPWKSTA_INFO_502 = *mut WKSTA_INFO_502; +STRUCT!{struct WKSTA_INFO_1010 { + wki1010_char_wait: DWORD, +}} +pub type PWKSTA_INFO_1010 = *mut WKSTA_INFO_1010; +pub type LPWKSTA_INFO_1010 = *mut WKSTA_INFO_1010; +STRUCT!{struct WKSTA_INFO_1011 { + wki1011_collection_time: DWORD, +}} +pub type PWKSTA_INFO_1011 = *mut WKSTA_INFO_1011; +pub type LPWKSTA_INFO_1011 = *mut WKSTA_INFO_1011; +STRUCT!{struct WKSTA_INFO_1012 { + wki1012_maximum_collection_count: DWORD, +}} +pub type PWKSTA_INFO_1012 = *mut WKSTA_INFO_1012; +pub type LPWKSTA_INFO_1012 = *mut WKSTA_INFO_1012; +STRUCT!{struct WKSTA_INFO_1027 { + wki1027_errlog_sz: DWORD, +}} +pub type PWKSTA_INFO_1027 = *mut WKSTA_INFO_1027; +pub type LPWKSTA_INFO_1027 = *mut WKSTA_INFO_1027; +STRUCT!{struct WKSTA_INFO_1028 { + wki1028_print_buf_time: DWORD, +}} +pub type PWKSTA_INFO_1028 = *mut WKSTA_INFO_1028; +pub type LPWKSTA_INFO_1028 = *mut WKSTA_INFO_1028; +STRUCT!{struct WKSTA_INFO_1032 { + wki1032_wrk_heuristics: DWORD, +}} +pub type PWKSTA_INFO_1032 = *mut WKSTA_INFO_1032; +pub type LPWKSTA_INFO_1032 = *mut WKSTA_INFO_1032; +STRUCT!{struct WKSTA_INFO_1013 { + wki1013_keep_conn: DWORD, +}} +pub type PWKSTA_INFO_1013 = *mut WKSTA_INFO_1013; +pub type LPWKSTA_INFO_1013 = *mut WKSTA_INFO_1013; +STRUCT!{struct WKSTA_INFO_1018 { + wki1018_sess_timeout: DWORD, +}} +pub type PWKSTA_INFO_1018 = *mut WKSTA_INFO_1018; +pub type LPWKSTA_INFO_1018 = *mut WKSTA_INFO_1018; +STRUCT!{struct WKSTA_INFO_1023 { + wki1023_siz_char_buf: DWORD, +}} +pub type PWKSTA_INFO_1023 = *mut WKSTA_INFO_1023; +pub type LPWKSTA_INFO_1023 = *mut WKSTA_INFO_1023; +STRUCT!{struct WKSTA_INFO_1033 { + wki1033_max_threads: DWORD, +}} +pub type PWKSTA_INFO_1033 = *mut WKSTA_INFO_1033; +pub type LPWKSTA_INFO_1033 = *mut WKSTA_INFO_1033; +STRUCT!{struct WKSTA_INFO_1041 { + wki1041_lock_quota: DWORD, +}} +pub type PWKSTA_INFO_1041 = *mut WKSTA_INFO_1041; +pub type LPWKSTA_INFO_1041 = *mut WKSTA_INFO_1041; +STRUCT!{struct WKSTA_INFO_1042 { + wki1042_lock_increment: DWORD, +}} +pub type PWKSTA_INFO_1042 = *mut WKSTA_INFO_1042; +pub type LPWKSTA_INFO_1042 = *mut WKSTA_INFO_1042; +STRUCT!{struct WKSTA_INFO_1043 { + wki1043_lock_maximum: DWORD, +}} +pub type PWKSTA_INFO_1043 = *mut WKSTA_INFO_1043; +pub type LPWKSTA_INFO_1043 = *mut WKSTA_INFO_1043; +STRUCT!{struct WKSTA_INFO_1044 { + wki1044_pipe_increment: DWORD, +}} +pub type PWKSTA_INFO_1044 = *mut WKSTA_INFO_1044; +pub type LPWKSTA_INFO_1044 = *mut WKSTA_INFO_1044; +STRUCT!{struct WKSTA_INFO_1045 { + wki1045_pipe_maximum: DWORD, +}} +pub type PWKSTA_INFO_1045 = *mut WKSTA_INFO_1045; +pub type LPWKSTA_INFO_1045 = *mut WKSTA_INFO_1045; +STRUCT!{struct WKSTA_INFO_1046 { + wki1046_dormant_file_limit: DWORD, +}} +pub type PWKSTA_INFO_1046 = *mut WKSTA_INFO_1046; +pub type LPWKSTA_INFO_1046 = *mut WKSTA_INFO_1046; +STRUCT!{struct WKSTA_INFO_1047 { + wki1047_cache_file_timeout: DWORD, +}} +pub type PWKSTA_INFO_1047 = *mut WKSTA_INFO_1047; +pub type LPWKSTA_INFO_1047 = *mut WKSTA_INFO_1047; +STRUCT!{struct WKSTA_INFO_1048 { + wki1048_use_opportunistic_locking: BOOL, +}} +pub type PWKSTA_INFO_1048 = *mut WKSTA_INFO_1048; +pub type LPWKSTA_INFO_1048 = *mut WKSTA_INFO_1048; +STRUCT!{struct WKSTA_INFO_1049 { + wki1049_use_unlock_behind: BOOL, +}} +pub type PWKSTA_INFO_1049 = *mut WKSTA_INFO_1049; +pub type LPWKSTA_INFO_1049 = *mut WKSTA_INFO_1049; +STRUCT!{struct WKSTA_INFO_1050 { + wki1050_use_close_behind: BOOL, +}} +pub type PWKSTA_INFO_1050 = *mut WKSTA_INFO_1050; +pub type LPWKSTA_INFO_1050 = *mut WKSTA_INFO_1050; +STRUCT!{struct WKSTA_INFO_1051 { + wki1051_buf_named_pipes: BOOL, +}} +pub type PWKSTA_INFO_1051 = *mut WKSTA_INFO_1051; +pub type LPWKSTA_INFO_1051 = *mut WKSTA_INFO_1051; +STRUCT!{struct WKSTA_INFO_1052 { + wki1052_use_lock_read_unlock: BOOL, +}} +pub type PWKSTA_INFO_1052 = *mut WKSTA_INFO_1052; +pub type LPWKSTA_INFO_1052 = *mut WKSTA_INFO_1052; +STRUCT!{struct WKSTA_INFO_1053 { + wki1053_utilize_nt_caching: BOOL, +}} +pub type PWKSTA_INFO_1053 = *mut WKSTA_INFO_1053; +pub type LPWKSTA_INFO_1053 = *mut WKSTA_INFO_1053; +STRUCT!{struct WKSTA_INFO_1054 { + wki1054_use_raw_read: BOOL, +}} +pub type PWKSTA_INFO_1054 = *mut WKSTA_INFO_1054; +pub type LPWKSTA_INFO_1054 = *mut WKSTA_INFO_1054; +STRUCT!{struct WKSTA_INFO_1055 { + wki1055_use_raw_write: BOOL, +}} +pub type PWKSTA_INFO_1055 = *mut WKSTA_INFO_1055; +pub type LPWKSTA_INFO_1055 = *mut WKSTA_INFO_1055; +STRUCT!{struct WKSTA_INFO_1056 { + wki1056_use_write_raw_data: BOOL, +}} +pub type PWKSTA_INFO_1056 = *mut WKSTA_INFO_1056; +pub type LPWKSTA_INFO_1056 = *mut WKSTA_INFO_1056; +STRUCT!{struct WKSTA_INFO_1057 { + wki1057_use_encryption: BOOL, +}} +pub type PWKSTA_INFO_1057 = *mut WKSTA_INFO_1057; +pub type LPWKSTA_INFO_1057 = *mut WKSTA_INFO_1057; +STRUCT!{struct WKSTA_INFO_1058 { + wki1058_buf_files_deny_write: BOOL, +}} +pub type PWKSTA_INFO_1058 = *mut WKSTA_INFO_1058; +pub type LPWKSTA_INFO_1058 = *mut WKSTA_INFO_1058; +STRUCT!{struct WKSTA_INFO_1059 { + wki1059_buf_read_only_files: BOOL, +}} +pub type PWKSTA_INFO_1059 = *mut WKSTA_INFO_1059; +pub type LPWKSTA_INFO_1059 = *mut WKSTA_INFO_1059; +STRUCT!{struct WKSTA_INFO_1060 { + wki1060_force_core_create_mode: BOOL, +}} +pub type PWKSTA_INFO_1060 = *mut WKSTA_INFO_1060; +pub type LPWKSTA_INFO_1060 = *mut WKSTA_INFO_1060; +STRUCT!{struct WKSTA_INFO_1061 { + wki1061_use_512_byte_max_transfer: BOOL, +}} +pub type PWKSTA_INFO_1061 = *mut WKSTA_INFO_1061; +pub type LPWKSTA_INFO_1061 = *mut WKSTA_INFO_1061; +STRUCT!{struct WKSTA_INFO_1062 { + wki1062_read_ahead_throughput: DWORD, +}} +pub type PWKSTA_INFO_1062 = *mut WKSTA_INFO_1062; +pub type LPWKSTA_INFO_1062 = *mut WKSTA_INFO_1062; +STRUCT!{struct WKSTA_USER_INFO_0 { + wkui0_username: LMSTR, +}} +pub type PWKSTA_USER_INFO_0 = *mut WKSTA_USER_INFO_0; +pub type LPWKSTA_USER_INFO_0 = *mut WKSTA_USER_INFO_0; +STRUCT!{struct WKSTA_USER_INFO_1 { + wkui1_username: LMSTR, + wkui1_logon_domain: LMSTR, + wkui1_oth_domains: LMSTR, + wkui1_logon_server: LMSTR, +}} +pub type PWKSTA_USER_INFO_1 = *mut WKSTA_USER_INFO_1; +pub type LPWKSTA_USER_INFO_1 = *mut WKSTA_USER_INFO_1; +STRUCT!{struct WKSTA_USER_INFO_1101 { + wkui1101_oth_domains: LMSTR, +}} +pub type PWKSTA_USER_INFO_1101 = *mut WKSTA_USER_INFO_1101; +pub type LPWKSTA_USER_INFO_1101 = *mut WKSTA_USER_INFO_1101; +STRUCT!{struct WKSTA_TRANSPORT_INFO_0 { + wkti0_quality_of_service: DWORD, + wkti0_number_of_vcs: DWORD, + wkti0_transport_name: LMSTR, + wkti0_transport_address: LMSTR, + wkti0_wan_ish: BOOL, +}} +pub type PWKSTA_TRANSPORT_INFO_0 = *mut WKSTA_TRANSPORT_INFO_0; +pub type LPWKSTA_TRANSPORT_INFO_0 = *mut WKSTA_TRANSPORT_INFO_0; +pub const WKSTA_PLATFORM_ID_PARMNUM: DWORD = 100; +pub const WKSTA_COMPUTERNAME_PARMNUM: DWORD = 1; +pub const WKSTA_LANGROUP_PARMNUM: DWORD = 2; +pub const WKSTA_VER_MAJOR_PARMNUM: DWORD = 4; +pub const WKSTA_VER_MINOR_PARMNUM: DWORD = 5; +pub const WKSTA_LOGGED_ON_USERS_PARMNUM: DWORD = 6; +pub const WKSTA_LANROOT_PARMNUM: DWORD = 7; +pub const WKSTA_LOGON_DOMAIN_PARMNUM: DWORD = 8; +pub const WKSTA_LOGON_SERVER_PARMNUM: DWORD = 9; +pub const WKSTA_CHARWAIT_PARMNUM: DWORD = 10; +pub const WKSTA_CHARTIME_PARMNUM: DWORD = 11; +pub const WKSTA_CHARCOUNT_PARMNUM: DWORD = 12; +pub const WKSTA_KEEPCONN_PARMNUM: DWORD = 13; +pub const WKSTA_KEEPSEARCH_PARMNUM: DWORD = 14; +pub const WKSTA_MAXCMDS_PARMNUM: DWORD = 15; +pub const WKSTA_NUMWORKBUF_PARMNUM: DWORD = 16; +pub const WKSTA_MAXWRKCACHE_PARMNUM: DWORD = 17; +pub const WKSTA_SESSTIMEOUT_PARMNUM: DWORD = 18; +pub const WKSTA_SIZERROR_PARMNUM: DWORD = 19; +pub const WKSTA_NUMALERTS_PARMNUM: DWORD = 20; +pub const WKSTA_NUMSERVICES_PARMNUM: DWORD = 21; +pub const WKSTA_NUMCHARBUF_PARMNUM: DWORD = 22; +pub const WKSTA_SIZCHARBUF_PARMNUM: DWORD = 23; +pub const WKSTA_ERRLOGSZ_PARMNUM: DWORD = 27; +pub const WKSTA_PRINTBUFTIME_PARMNUM: DWORD = 28; +pub const WKSTA_SIZWORKBUF_PARMNUM: DWORD = 29; +pub const WKSTA_MAILSLOTS_PARMNUM: DWORD = 30; +pub const WKSTA_NUMDGRAMBUF_PARMNUM: DWORD = 31; +pub const WKSTA_WRKHEURISTICS_PARMNUM: DWORD = 32; +pub const WKSTA_MAXTHREADS_PARMNUM: DWORD = 33; +pub const WKSTA_LOCKQUOTA_PARMNUM: DWORD = 41; +pub const WKSTA_LOCKINCREMENT_PARMNUM: DWORD = 42; +pub const WKSTA_LOCKMAXIMUM_PARMNUM: DWORD = 43; +pub const WKSTA_PIPEINCREMENT_PARMNUM: DWORD = 44; +pub const WKSTA_PIPEMAXIMUM_PARMNUM: DWORD = 45; +pub const WKSTA_DORMANTFILELIMIT_PARMNUM: DWORD = 46; +pub const WKSTA_CACHEFILETIMEOUT_PARMNUM: DWORD = 47; +pub const WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM: DWORD = 48; +pub const WKSTA_USEUNLOCKBEHIND_PARMNUM: DWORD = 49; +pub const WKSTA_USECLOSEBEHIND_PARMNUM: DWORD = 50; +pub const WKSTA_BUFFERNAMEDPIPES_PARMNUM: DWORD = 51; +pub const WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM: DWORD = 52; +pub const WKSTA_UTILIZENTCACHING_PARMNUM: DWORD = 53; +pub const WKSTA_USERAWREAD_PARMNUM: DWORD = 54; +pub const WKSTA_USERAWWRITE_PARMNUM: DWORD = 55; +pub const WKSTA_USEWRITERAWWITHDATA_PARMNUM: DWORD = 56; +pub const WKSTA_USEENCRYPTION_PARMNUM: DWORD = 57; +pub const WKSTA_BUFFILESWITHDENYWRITE_PARMNUM: DWORD = 58; +pub const WKSTA_BUFFERREADONLYFILES_PARMNUM: DWORD = 59; +pub const WKSTA_FORCECORECREATEMODE_PARMNUM: DWORD = 60; +pub const WKSTA_USE512BYTESMAXTRANSFER_PARMNUM: DWORD = 61; +pub const WKSTA_READAHEADTHRUPUT_PARMNUM: DWORD = 62; +pub const WKSTA_OTH_DOMAINS_PARMNUM: DWORD = 101; +pub const TRANSPORT_QUALITYOFSERVICE_PARMNUM: DWORD = 201; +pub const TRANSPORT_NAME_PARMNUM: DWORD = 202; diff --git a/winapi/src/um/lowlevelmonitorconfigurationapi.rs b/winapi/src/um/lowlevelmonitorconfigurationapi.rs new file mode 100644 index 000000000..fe73214b5 --- /dev/null +++ b/winapi/src/um/lowlevelmonitorconfigurationapi.rs @@ -0,0 +1,49 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BYTE, DWORD, LPDWORD}; +use um::physicalmonitorenumerationapi::_BOOL; +use um::winnt::{HANDLE, LPSTR}; +STRUCT!{#[repr(packed)] struct MC_TIMING_REPORT { + dwHorizontalFrequencyInHZ: DWORD, + dwVerticalFrequencyInHZ: DWORD, + bTimingStatusByte: BYTE, +}} +pub type LPMC_TIMING_REPORT = *mut MC_TIMING_REPORT; +ENUM!{enum MC_VCP_CODE_TYPE { + MC_MOMENTARY, + MC_SET_PARAMETER, +}} +pub type LPMC_VCP_CODE_TYPE = *mut MC_VCP_CODE_TYPE; +extern "system" { + pub fn GetVCPFeatureAndVCPFeatureReply( + hMonitor: HANDLE, + bVCPCode: BYTE, + pvct: LPMC_VCP_CODE_TYPE, + pdwCurrentValue: LPDWORD, + pdwMaximumValue: LPDWORD, + ) -> _BOOL; + pub fn SetVCPFeature( + hMonitor: HANDLE, + bVCPCode: BYTE, + dwNewValue: DWORD, + ) -> _BOOL; + pub fn SaveCurrentSettings( + hMonitor: HANDLE, + ) -> _BOOL; + pub fn GetCapabilitiesStringLength( + hMonitor: HANDLE, + pdwCapabilitiesStringLengthInCharacters: LPDWORD, + ) -> _BOOL; + pub fn CapabilitiesRequestAndCapabilitiesReply( + hMonitor: HANDLE, + pszASCIICapabilitiesString: LPSTR, + dwCapabilitiesStringLengthInCharacters: DWORD, + ) -> _BOOL; + pub fn GetTimingReport( + hMonitor: HANDLE, + pmtrMonitorTimingReport: LPMC_TIMING_REPORT, + ) -> _BOOL; +} diff --git a/winapi/src/um/lsalookup.rs b/winapi/src/um/lsalookup.rs new file mode 100644 index 000000000..95a6b62b7 --- /dev/null +++ b/winapi/src/um/lsalookup.rs @@ -0,0 +1,109 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! LSA Policy Lookup API +use shared::guiddef::GUID; +use shared::minwindef::{ULONG, USHORT}; +use shared::ntdef::NTSTATUS; +use um::winnt::{ACCESS_MASK, HANDLE, LONG, PCHAR, PSID, PVOID, PWSTR, SID_NAME_USE}; +STRUCT!{struct LSA_UNICODE_STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PWSTR, +}} +pub type PLSA_UNICODE_STRING = *mut LSA_UNICODE_STRING; +STRUCT!{struct LSA_STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PCHAR, +}} +pub type PLSA_STRING = *mut LSA_STRING; +STRUCT!{struct LSA_OBJECT_ATTRIBUTES { + Length: ULONG, + RootDirectory: HANDLE, + ObjectName: PLSA_UNICODE_STRING, + Attributes: ULONG, + SecurityDescriptor: PVOID, + SecurityQualityOfService: PVOID, +}} +pub type PLSA_OBJECT_ATTRIBUTES = *mut LSA_OBJECT_ATTRIBUTES; +STRUCT!{struct LSA_TRUST_INFORMATION { + Name: LSA_UNICODE_STRING, + Sid: PSID, +}} +pub type PLSA_TRUST_INFORMATION = *mut LSA_TRUST_INFORMATION; +STRUCT!{struct LSA_REFERENCED_DOMAIN_LIST { + Entries: ULONG, + Domains: PLSA_TRUST_INFORMATION, +}} +pub type PLSA_REFERENCED_DOMAIN_LIST = *mut LSA_REFERENCED_DOMAIN_LIST; +STRUCT!{struct LSA_TRANSLATED_SID2 { + Use: SID_NAME_USE, + Sid: PSID, + DomainIndex: LONG, + Flags: ULONG, +}} +pub type PLSA_TRANSLATED_SID2 = *mut LSA_TRANSLATED_SID2; +STRUCT!{struct LSA_TRANSLATED_NAME { + Use: SID_NAME_USE, + Name: LSA_UNICODE_STRING, + DomainIndex: LONG, +}} +pub type PLSA_TRANSLATED_NAME = *mut LSA_TRANSLATED_NAME; +STRUCT!{struct POLICY_ACCOUNT_DOMAIN_INFO { + DomainName: LSA_UNICODE_STRING, + DomainSid: PSID, +}} +pub type PPOLICY_ACCOUNT_DOMAIN_INFO = *mut POLICY_ACCOUNT_DOMAIN_INFO; +STRUCT!{struct POLICY_DNS_DOMAIN_INFO { + Name: LSA_UNICODE_STRING, + DnsDomainName: LSA_UNICODE_STRING, + DnsForestName: LSA_UNICODE_STRING, + DomainGuid: GUID, + Sid: PSID, +}} +pub type PPOLICY_DNS_DOMAIN_INFO = *mut POLICY_DNS_DOMAIN_INFO; +pub const LOOKUP_VIEW_LOCAL_INFORMATION: ACCESS_MASK = 0x00000001; +pub const LOOKUP_TRANSLATE_NAMES: ACCESS_MASK = 0x00000800; +ENUM!{enum LSA_LOOKUP_DOMAIN_INFO_CLASS { + AccountDomainInformation = 5, + DnsDomainInformation = 12, +}} +pub type PLSA_LOOKUP_DOMAIN_INFO_CLASS = *mut LSA_LOOKUP_DOMAIN_INFO_CLASS; +pub type LSA_LOOKUP_HANDLE = PVOID; +pub type PLSA_LOOKUP_HANDLE = *mut PVOID; +extern "C" { + pub fn LsaLookupOpenLocalPolicy( + ObjectAttributes: PLSA_OBJECT_ATTRIBUTES, + AccessMask: ACCESS_MASK, + PolicyHandle: PLSA_LOOKUP_HANDLE, + ) -> NTSTATUS; + pub fn LsaLookupClose( + ObjectHandle: LSA_LOOKUP_HANDLE, + ) -> NTSTATUS; + pub fn LsaLookupTranslateSids( + PolicyHandle: LSA_LOOKUP_HANDLE, + Count: ULONG, + Sids: *mut PSID, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Names: *mut PLSA_TRANSLATED_NAME, + ) -> NTSTATUS; + pub fn LsaLookupTranslateNames( + PolicyHandle: LSA_LOOKUP_HANDLE, + Flags: ULONG, + Count: ULONG, + Names: PLSA_UNICODE_STRING, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Sids: *mut PLSA_TRANSLATED_SID2, + ) -> NTSTATUS; + pub fn LsaLookupGetDomainInfo( + PolicyHandle: LSA_LOOKUP_HANDLE, + DomainInfoClass: LSA_LOOKUP_DOMAIN_INFO_CLASS, + DomainInfo: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaLookupFreeMemory( + Buffer: PVOID, + ) -> NTSTATUS; +} diff --git a/winapi/src/um/memoryapi.rs b/winapi/src/um/memoryapi.rs new file mode 100644 index 000000000..5bf5bd01c --- /dev/null +++ b/winapi/src/um/memoryapi.rs @@ -0,0 +1,390 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-memory-l1-1-0 +use ctypes::c_void; +use shared::basetsd::{PSIZE_T, PULONG_PTR, SIZE_T, ULONG64, ULONG_PTR}; +use shared::minwindef::{ + BOOL, DWORD, LPCVOID, LPDWORD, LPVOID, PBOOL, PDWORD, PULONG, UINT, ULONG, +}; +use um::minwinbase::{LPSECURITY_ATTRIBUTES, PSECURITY_ATTRIBUTES}; +use um::winnt::{ + HANDLE, LPCWSTR, PCWSTR, PMEMORY_BASIC_INFORMATION, PVOID, SECTION_ALL_ACCESS, + SECTION_MAP_EXECUTE_EXPLICIT, SECTION_MAP_READ, SECTION_MAP_WRITE, +}; +pub const FILE_MAP_WRITE: DWORD = SECTION_MAP_WRITE; +pub const FILE_MAP_READ: DWORD = SECTION_MAP_READ; +pub const FILE_MAP_ALL_ACCESS: DWORD = SECTION_ALL_ACCESS; +pub const FILE_MAP_EXECUTE: DWORD = SECTION_MAP_EXECUTE_EXPLICIT; +pub const FILE_MAP_COPY: DWORD = 0x00000001; +pub const FILE_MAP_RESERVE: DWORD = 0x80000000; +pub const FILE_MAP_TARGETS_INVALID: DWORD = 0x40000000; +pub const FILE_MAP_LARGE_PAGES: DWORD = 0x20000000; +extern "system" { + pub fn VirtualAlloc( + lpAddress: LPVOID, + dwSize: SIZE_T, + flAllocationType: DWORD, + flProtect: DWORD, + ) -> LPVOID; + pub fn VirtualProtect( + lpAddress: LPVOID, + dwSize: SIZE_T, + flNewProtect: DWORD, + lpflOldProtect: PDWORD, + ) -> BOOL; + pub fn VirtualFree( + lpAddress: LPVOID, + dwSize: SIZE_T, + dwFreeType: DWORD, + ) -> BOOL; + pub fn VirtualQuery( + lpAddress: LPCVOID, + lpBuffer: PMEMORY_BASIC_INFORMATION, + dwLength: SIZE_T, + ) -> SIZE_T; + pub fn VirtualAllocEx( + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + flAllocationType: DWORD, + flProtect: DWORD, + ) -> LPVOID; + pub fn VirtualFreeEx( + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + dwFreeType: DWORD, + ) -> BOOL; + pub fn VirtualProtectEx( + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + flNewProtect: DWORD, + lpflOldProtect: PDWORD, + ) -> BOOL; + pub fn VirtualQueryEx( + hProcess: HANDLE, + lpAddress: LPCVOID, + lpBuffer: PMEMORY_BASIC_INFORMATION, + dwLength: SIZE_T, + ) -> SIZE_T; + pub fn ReadProcessMemory( + hProcess: HANDLE, + lpBaseAddress: LPCVOID, + lpBuffer: LPVOID, + nSize: SIZE_T, + lpNumberOfBytesRead: *mut SIZE_T, + ) -> BOOL; + pub fn WriteProcessMemory( + hProcess: HANDLE, + lpBaseAddress: LPVOID, + lpBuffer: LPCVOID, + nSize: SIZE_T, + lpNumberOfBytesWritten: *mut SIZE_T, + ) -> BOOL; + pub fn CreateFileMappingW( + hFile: HANDLE, + lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn OpenFileMappingW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn MapViewOfFile( + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, + dwNumberOfBytesToMap: SIZE_T, + ) -> LPVOID; + pub fn MapViewOfFileEx( + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, + dwNumberOfBytesToMap: SIZE_T, + lpBaseAddress: LPVOID, + ) -> LPVOID; + pub fn FlushViewOfFile( + lpBaseAddress: LPCVOID, + dwNumberOfBytesToFlush: SIZE_T, + ) -> BOOL; + pub fn UnmapViewOfFile( + lpBaseAddress: LPCVOID, + ) -> BOOL; + pub fn GetLargePageMinimum() -> SIZE_T; + pub fn GetProcessWorkingSetSizeEx( + hProcess: HANDLE, + lpMinimumWorkingSetSize: PSIZE_T, + lpMaximumWorkingSetSize: PSIZE_T, + Flags: PDWORD, + ) -> BOOL; + pub fn SetProcessWorkingSetSizeEx( + hProcess: HANDLE, + dwMinimumWorkingSetSize: SIZE_T, + dwMaximumWorkingSetSize: SIZE_T, + Flags: DWORD, + ) -> BOOL; + pub fn VirtualLock( + lpAddress: LPVOID, + dwSize: SIZE_T, + ) -> BOOL; + pub fn VirtualUnlock( + lpAddress: LPVOID, + dwSize: SIZE_T, + ) -> BOOL; + pub fn GetWriteWatch( + dwFlags: DWORD, + lpBaseAddress: PVOID, + dwRegionSize: SIZE_T, + lpAddresses: *mut PVOID, + lpdwCount: *mut ULONG_PTR, + lpdwGranularity: LPDWORD, + ) -> UINT; + pub fn ResetWriteWatch( + lpBaseAddress: LPVOID, + dwRegionSize: SIZE_T, + ) -> UINT; +} +ENUM!{enum MEMORY_RESOURCE_NOTIFICATION_TYPE { + LowMemoryResourceNotification, + HighMemoryResourceNotification, +}} +extern "system" { + pub fn CreateMemoryResourceNotification( + NotificationType: MEMORY_RESOURCE_NOTIFICATION_TYPE, + ) -> HANDLE; + pub fn QueryMemoryResourceNotification( + ResourceNotificationHandle: HANDLE, + ResourceState: PBOOL, + ) -> BOOL; +} +pub const FILE_CACHE_MAX_HARD_ENABLE: DWORD = 0x00000001; +pub const FILE_CACHE_MAX_HARD_DISABLE: DWORD = 0x00000002; +pub const FILE_CACHE_MIN_HARD_ENABLE: DWORD = 0x00000004; +pub const FILE_CACHE_MIN_HARD_DISABLE: DWORD = 0x00000008; +extern "system" { + pub fn GetSystemFileCacheSize( + lpMinimumFileCacheSize: PSIZE_T, + lpMaximumFileCacheSize: PSIZE_T, + lpFlags: PDWORD, + ) -> BOOL; + pub fn SetSystemFileCacheSize( + MinimumFileCacheSize: SIZE_T, + MaximumFileCacheSize: SIZE_T, + Flags: DWORD, + ) -> BOOL; + pub fn CreateFileMappingNumaW( + hFile: HANDLE, + lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCWSTR, + nndPreferred: DWORD, + ) -> HANDLE; +} +STRUCT!{struct WIN32_MEMORY_RANGE_ENTRY { + VirtualAddress: PVOID, + NumberOfBytes: SIZE_T, +}} +pub type PWIN32_MEMORY_RANGE_ENTRY = *mut WIN32_MEMORY_RANGE_ENTRY; +extern "system" { + pub fn PrefetchVirtualMemory( + hProcess: HANDLE, + NumberOfEntries: ULONG_PTR, + VirtualAddresses: PWIN32_MEMORY_RANGE_ENTRY, + Flags: ULONG, + ) -> BOOL; + pub fn CreateFileMappingFromApp( + hFile: HANDLE, + SecurityAttributes: PSECURITY_ATTRIBUTES, + PageProtection: ULONG, + MaximumSize: ULONG64, + Name: PCWSTR, + ) -> HANDLE; + pub fn MapViewOfFileFromApp( + hFileMappingObject: HANDLE, + DesiredAccess: ULONG, + FileOffset: ULONG64, + NumberOfBytesToMap: SIZE_T, + ) -> PVOID; + pub fn UnmapViewOfFileEx( + BaseAddress: PVOID, + UnmapFlags: ULONG, + ) -> BOOL; + pub fn AllocateUserPhysicalPages( + hProcess: HANDLE, + NumberOfPages: PULONG_PTR, + PageArray: PULONG_PTR, + ) -> BOOL; + pub fn FreeUserPhysicalPages( + hProcess: HANDLE, + NumberOfPages: PULONG_PTR, + PageArray: PULONG_PTR, + ) -> BOOL; + pub fn MapUserPhysicalPages( + VirtualAddress: PVOID, + NumberOfPages: ULONG_PTR, + PageArray: PULONG_PTR, + ) -> BOOL; + pub fn AllocateUserPhysicalPagesNuma( + hProcess: HANDLE, + NumberOfPages: PULONG_PTR, + PageArray: PULONG_PTR, + nndPreferred: DWORD, + ) -> BOOL; + pub fn VirtualAllocExNuma( + hProcess: HANDLE, + lpAddress: LPVOID, + dwSize: SIZE_T, + flAllocationType: DWORD, + flProtect: DWORD, + nndPreferred: DWORD, + ) -> LPVOID; +} +pub const MEHC_PATROL_SCRUBBER_PRESENT: ULONG = 0x1; +extern "system" { + pub fn GetMemoryErrorHandlingCapabilities( + Capabilities: PULONG, + ) -> BOOL; +} +FN!{stdcall PBAD_MEMORY_CALLBACK_ROUTINE() -> ()} +extern "system" { + pub fn RegisterBadMemoryNotification( + Callback: PBAD_MEMORY_CALLBACK_ROUTINE, + ) -> PVOID; + pub fn UnregisterBadMemoryNotification( + RegistrationHandle: PVOID, + ) -> BOOL; +} +ENUM!{enum OFFER_PRIORITY { + VmOfferPriorityVeryLow = 1, + VmOfferPriorityLow, + VmOfferPriorityBelowNormal, + VmOfferPriorityNormal, +}} +extern "system" { + pub fn OfferVirtualMemory( + VirtualAddress: PVOID, + Size: SIZE_T, + Priority: OFFER_PRIORITY, + ) -> DWORD; + pub fn ReclaimVirtualMemory( + VirtualAddress: *const c_void, + Size: SIZE_T, + ) -> DWORD; + pub fn DiscardVirtualMemory( + VirtualAddress: PVOID, + Size: SIZE_T, + ) -> DWORD; +// TODO: Needs winnt::PCFG_CALL_TARGET_INFO. +/* pub fn SetProcessValidCallTargets( + hProcess: HANDLE, + VirtualAddress: PVOID, + RegionSize: SIZE_T, + NumberOfOffsets: ULONG, + OffsetInformation: PCFG_CALL_TARGET_INFO, + ) -> BOOL; */ + pub fn VirtualAllocFromApp( + BaseAddress: PVOID, + Size: SIZE_T, + AllocationType: ULONG, + Protection: ULONG, + ) -> PVOID; + pub fn VirtualProtectFromApp( + Address: PVOID, + Size: SIZE_T, + NewProtection: ULONG, + OldProtection: PULONG, + ) -> BOOL; + pub fn OpenFileMappingFromApp( + DesiredAccess: ULONG, + InheritHandle: BOOL, + Name: PCWSTR, + ) -> HANDLE; +} +// TODO: Under WINAPI_PARTITION_APP, define CreateFileMappingW, MapViewOfFile, VirtualAlloc, +// VirtualProtect, and OpenFileMappingW as wrappers around the *FromApp functions. +ENUM!{enum WIN32_MEMORY_INFORMATION_CLASS { + MemoryRegionInfo, +}} +STRUCT!{struct WIN32_MEMORY_REGION_INFORMATION { + AllocationBase: PVOID, + AllocationProtect: ULONG, + u: WIN32_MEMORY_REGION_INFORMATION_u, + RegionSize: SIZE_T, + CommitSize: SIZE_T, +}} +UNION!{union WIN32_MEMORY_REGION_INFORMATION_u { + [u32; 1], + Flags Flags_mut: ULONG, + s s_mut: WIN32_MEMORY_REGION_INFORMATION_u_s, +}} +STRUCT!{struct WIN32_MEMORY_REGION_INFORMATION_u_s { + Bitfield: ULONG, +}} +BITFIELD!{WIN32_MEMORY_REGION_INFORMATION_u_s Bitfield: ULONG [ + Private set_Private[0..1], + MappedDataFile set_MappedDataFile[1..2], + MappedImage set_MappedImage[2..3], + MappedPageFile set_MappedPageFile[3..4], + MappedPhysical set_MappedPhysical[4..5], + DirectMapped set_DirectMapped[5..6], + Reserved set_Reserved[6..32], +]} +// TODO: Need to resolve issue #323 first. +/*extern "system" { + pub fn QueryVirtualMemoryInformation( + Process: HANDLE, + VirtualAddress: *const VOID, + MemoryInformationClass: WIN32_MEMORY_INFORMATION_CLASS, + MemoryInformation: PVOID, + MemoryInformationSize: SIZE_T, + ReturnSize: PSIZE_T, + ) -> BOOL; + pub fn MapViewOfFileNuma2( + FileMappingHandle: HANDLE, + ProcessHandle: HANDLE, + Offset: ULONG64, + BaseAddress: PVOID, + ViewSize: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, + PreferredNode: ULONG, + ) -> PVOID; +} +#[inline] +pub unsafe fn MapViewOfFile2( + FileMappingHandle: HANDLE, + ProcessHandle: HANDLE, + Offset: ULONG64, + BaseAddress: PVOID, + ViewSize: SIZE_T, + AllocationType: ULONG, + PageProtection: ULONG, +) -> PVOID { + MapViewOfFileNuma2(FileMappingHandle, + ProcessHandle, + Offset, + BaseAddress, + ViewSize, + AllocationType, + PageProtection, + NUMA_NO_PREFERRED_NODE) +}*/ +extern "system" { + pub fn UnmapViewOfFile2( + ProcessHandle: HANDLE, + BaseAddress: PVOID, + UnmapFlags: ULONG, + ) -> BOOL; +} diff --git a/winapi/src/um/minschannel.rs b/winapi/src/um/minschannel.rs new file mode 100644 index 000000000..ba3ca4f29 --- /dev/null +++ b/winapi/src/um/minschannel.rs @@ -0,0 +1,58 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Public Definitions for MIN SCHANNEL Security Provider +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD}; +use um::wincrypt::ALG_ID; +use um::winnt::LPWSTR; +pub const SECPKG_ATTR_ISSUER_LIST: DWORD = 0x50; +pub const SECPKG_ATTR_REMOTE_CRED: DWORD = 0x51; +pub const SECPKG_ATTR_LOCAL_CRED: DWORD = 0x52; +pub const SECPKG_ATTR_REMOTE_CERT_CONTEXT: DWORD = 0x53; +pub const SECPKG_ATTR_LOCAL_CERT_CONTEXT: DWORD = 0x54; +pub const SECPKG_ATTR_ROOT_STORE: DWORD = 0x55; +pub const SECPKG_ATTR_SUPPORTED_ALGS: DWORD = 0x56; +pub const SECPKG_ATTR_CIPHER_STRENGTHS: DWORD = 0x57; +pub const SECPKG_ATTR_SUPPORTED_PROTOCOLS: DWORD = 0x58; +pub const SECPKG_ATTR_ISSUER_LIST_EX: DWORD = 0x59; +pub const SECPKG_ATTR_CONNECTION_INFO: DWORD = 0x5a; +pub const SECPKG_ATTR_EAP_KEY_BLOCK: DWORD = 0x5b; +pub const SECPKG_ATTR_MAPPED_CRED_ATTR: DWORD = 0x5c; +pub const SECPKG_ATTR_SESSION_INFO: DWORD = 0x5d; +pub const SECPKG_ATTR_APP_DATA: DWORD = 0x5e; +pub const SECPKG_ATTR_REMOTE_CERTIFICATES: DWORD = 0x5F; +pub const SECPKG_ATTR_CLIENT_CERT_POLICY: DWORD = 0x60; +pub const SECPKG_ATTR_CC_POLICY_RESULT: DWORD = 0x61; +pub const SECPKG_ATTR_USE_NCRYPT: DWORD = 0x62; +pub const SECPKG_ATTR_LOCAL_CERT_INFO: DWORD = 0x63; +pub const SECPKG_ATTR_CIPHER_INFO: DWORD = 0x64; +pub const SECPKG_ATTR_EAP_PRF_INFO: DWORD = 0x65; +pub const SECPKG_ATTR_SUPPORTED_SIGNATURES: DWORD = 0x66; +pub const SECPKG_ATTR_REMOTE_CERT_CHAIN: DWORD = 0x67; +pub const SECPKG_ATTR_UI_INFO: DWORD = 0x68; +pub const SECPKG_ATTR_EARLY_START: DWORD = 0x69; +STRUCT!{struct SecPkgCred_SupportedAlgs { + cSupportedAlgs: DWORD, + palgSupportedAlgs: *mut ALG_ID, +}} +STRUCT!{struct SecPkgCred_CipherStrengths { + dwMinimumCipherStrength: DWORD, + dwMaximumCipherStrength: DWORD, +}} +STRUCT!{struct SecPkgCred_SupportedProtocols { + grbitProtocol: DWORD, +}} +STRUCT!{struct SecPkgCred_ClientCertPolicy { + dwFlags: DWORD, + guidPolicyId: GUID, + dwCertFlags: DWORD, + dwUrlRetrievalTimeout: DWORD, + fCheckRevocationFreshnessTime: BOOL, + dwRevocationFreshnessTime: DWORD, + fOmitUsageCheck: BOOL, + pwszSslCtlStoreName: LPWSTR, + pwszSslCtlIdentifier: LPWSTR, +}} diff --git a/winapi/src/um/minwinbase.rs b/winapi/src/um/minwinbase.rs new file mode 100644 index 000000000..b414af1ba --- /dev/null +++ b/winapi/src/um/minwinbase.rs @@ -0,0 +1,337 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! This module defines the 32-Bit Windows Base APIs +use shared::basetsd::ULONG_PTR; +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, HMODULE, LPVOID, MAX_PATH, UINT, ULONG, WORD}; +use shared::ntstatus::{ + STATUS_ACCESS_VIOLATION, STATUS_ARRAY_BOUNDS_EXCEEDED, STATUS_BREAKPOINT, + STATUS_CONTROL_C_EXIT, STATUS_DATATYPE_MISALIGNMENT, STATUS_FLOAT_DENORMAL_OPERAND, + STATUS_FLOAT_DIVIDE_BY_ZERO, STATUS_FLOAT_INEXACT_RESULT, STATUS_FLOAT_INVALID_OPERATION, + STATUS_FLOAT_OVERFLOW, STATUS_FLOAT_STACK_CHECK, STATUS_FLOAT_UNDERFLOW, + STATUS_GUARD_PAGE_VIOLATION, STATUS_ILLEGAL_INSTRUCTION, STATUS_INTEGER_DIVIDE_BY_ZERO, + STATUS_INTEGER_OVERFLOW, STATUS_INVALID_DISPOSITION, STATUS_INVALID_HANDLE, + STATUS_IN_PAGE_ERROR, STATUS_NONCONTINUABLE_EXCEPTION, STATUS_PENDING, + STATUS_POSSIBLE_DEADLOCK, STATUS_PRIVILEGED_INSTRUCTION, STATUS_SINGLE_STEP, + STATUS_STACK_OVERFLOW, +}; +use um::winnt::{ + CHAR, EXCEPTION_RECORD, HANDLE, LPSTR, LPWSTR, PCONTEXT, PRTL_CRITICAL_SECTION, + PRTL_CRITICAL_SECTION_DEBUG, PVOID, RTL_CRITICAL_SECTION, RTL_CRITICAL_SECTION_DEBUG, WCHAR, +}; +//MoveMemory +//CopyMemory +//FillMemory +//ZeroMemory +STRUCT!{struct SECURITY_ATTRIBUTES { + nLength: DWORD, + lpSecurityDescriptor: LPVOID, + bInheritHandle: BOOL, +}} +pub type PSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; +STRUCT!{struct OVERLAPPED_u_s { + Offset: DWORD, + OffsetHigh: DWORD, +}} +UNION!{union OVERLAPPED_u { + [u32; 2] [u64; 1], + s s_mut: OVERLAPPED_u_s, + Pointer Pointer_mut: PVOID, +}} +STRUCT!{struct OVERLAPPED { + Internal: ULONG_PTR, + InternalHigh: ULONG_PTR, + u: OVERLAPPED_u, + hEvent: HANDLE, +}} +pub type LPOVERLAPPED = *mut OVERLAPPED; +STRUCT!{struct OVERLAPPED_ENTRY { + lpCompletionKey: ULONG_PTR, + lpOverlapped: LPOVERLAPPED, + Internal: ULONG_PTR, + dwNumberOfBytesTransferred: DWORD, +}} +pub type LPOVERLAPPED_ENTRY = *mut OVERLAPPED_ENTRY; +STRUCT!{struct SYSTEMTIME { + wYear: WORD, + wMonth: WORD, + wDayOfWeek: WORD, + wDay: WORD, + wHour: WORD, + wMinute: WORD, + wSecond: WORD, + wMilliseconds: WORD, +}} +pub type PSYSTEMTIME = *mut SYSTEMTIME; +pub type LPSYSTEMTIME = *mut SYSTEMTIME; +STRUCT!{struct WIN32_FIND_DATAA { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + dwReserved0: DWORD, + dwReserved1: DWORD, + cFileName: [CHAR; MAX_PATH], + cAlternateFileName: [CHAR; 14], +}} +pub type PWIN32_FIND_DATAA = *mut WIN32_FIND_DATAA; +pub type LPWIN32_FIND_DATAA = *mut WIN32_FIND_DATAA; +STRUCT!{struct WIN32_FIND_DATAW { + dwFileAttributes: DWORD, + ftCreationTime: FILETIME, + ftLastAccessTime: FILETIME, + ftLastWriteTime: FILETIME, + nFileSizeHigh: DWORD, + nFileSizeLow: DWORD, + dwReserved0: DWORD, + dwReserved1: DWORD, + cFileName: [WCHAR; MAX_PATH], + cAlternateFileName: [WCHAR; 14], +}} +pub type PWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; +pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; +ENUM!{enum FINDEX_INFO_LEVELS { + FindExInfoStandard, + FindExInfoBasic, + FindExInfoMaxInfoLevel, +}} +pub const FIND_FIRST_EX_CASE_SENSITIVE: DWORD = 0x00000001; +pub const FIND_FIRST_EX_LARGE_FETCH: DWORD = 0x00000002; +ENUM!{enum FINDEX_SEARCH_OPS { + FindExSearchNameMatch, + FindExSearchLimitToDirectories, + FindExSearchLimitToDevices, + FindExSearchMaxSearchOp, +}} +ENUM!{enum GET_FILEEX_INFO_LEVELS { + GetFileExInfoStandard, + GetFileExMaxInfoLevel, +}} +ENUM!{enum FILE_INFO_BY_HANDLE_CLASS { + FileBasicInfo, + FileStandardInfo, + FileNameInfo, + FileRenameInfo, + FileDispositionInfo, + FileAllocationInfo, + FileEndOfFileInfo, + FileStreamInfo, + FileCompressionInfo, + FileAttributeTagInfo, + FileIdBothDirectoryInfo, + FileIdBothDirectoryRestartInfo, + FileIoPriorityHintInfo, + FileRemoteProtocolInfo, + FileFullDirectoryInfo, + FileFullDirectoryRestartInfo, + FileStorageInfo, + FileAlignmentInfo, + FileIdInfo, + FileIdExtdDirectoryInfo, + FileIdExtdDirectoryRestartInfo, + FileDispositionInfoEx, + FileRenameInfoEx, + MaximumFileInfoByHandleClass, +}} +pub type PFILE_INFO_BY_HANDLE_CLASS = *mut FILE_INFO_BY_HANDLE_CLASS; +pub type CRITICAL_SECTION = RTL_CRITICAL_SECTION; +pub type PCRITICAL_SECTION = PRTL_CRITICAL_SECTION; +pub type LPCRITICAL_SECTION = PRTL_CRITICAL_SECTION; +pub type CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG; +pub type PCRITICAL_SECTION_DEBUG = PRTL_CRITICAL_SECTION_DEBUG; +pub type LPCRITICAL_SECTION_DEBUG = PRTL_CRITICAL_SECTION_DEBUG; +FN!{stdcall LPOVERLAPPED_COMPLETION_ROUTINE( + dwErrorCode: DWORD, + dwNumberOfBytesTransfered: DWORD, + lpOverlapped: LPOVERLAPPED, +) -> ()} +pub const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001; +pub const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002; +STRUCT!{struct PROCESS_HEAP_ENTRY_Block { + hMem: HANDLE, + dwReserved: [DWORD; 3], +}} +STRUCT!{struct PROCESS_HEAP_ENTRY_Region { + dwCommittedSize: DWORD, + dwUnCommittedSize: DWORD, + lpFirstBlock: LPVOID, + lpLastBlock: LPVOID, +}} +UNION!{union PROCESS_HEAP_ENTRY_u { + [u32; 4] [u64; 3], + Block Block_mut: PROCESS_HEAP_ENTRY_Block, + Region Region_mut: PROCESS_HEAP_ENTRY_Region, +}} +STRUCT!{struct PROCESS_HEAP_ENTRY { + lpData: PVOID, + cbData: DWORD, + cbOverhead: BYTE, + iRegionIndex: BYTE, + wFlags: WORD, + u: PROCESS_HEAP_ENTRY_u, +}} +pub type LPPROCESS_HEAP_ENTRY = *mut PROCESS_HEAP_ENTRY; +pub type PPROCESS_HEAP_ENTRY = *mut PROCESS_HEAP_ENTRY; +pub const PROCESS_HEAP_REGION: WORD = 0x0001; +pub const PROCESS_HEAP_UNCOMMITTED_RANGE: WORD = 0x0002; +pub const PROCESS_HEAP_ENTRY_BUSY: WORD = 0x0004; +pub const PROCESS_HEAP_SEG_ALLOC: WORD = 0x0008; +pub const PROCESS_HEAP_ENTRY_MOVEABLE: WORD = 0x0010; +pub const PROCESS_HEAP_ENTRY_DDESHARE: WORD = 0x0020; +STRUCT!{struct REASON_CONTEXT_Detailed { + LocalizedReasonModule: HMODULE, + LocalizedReasonId: ULONG, + ReasonStringCount: ULONG, + ReasonStrings: *mut LPWSTR, +}} +UNION!{union REASON_CONTEXT_Reason { + [u32; 4] [u64; 3], + Detailed Detailed_mut: REASON_CONTEXT_Detailed, + SimpleReasonString SimpleReasonString_mut: LPWSTR, +}} +STRUCT!{struct REASON_CONTEXT { + Version: ULONG, + Flags: DWORD, + Reason: REASON_CONTEXT_Reason, +}} +pub type PREASON_CONTEXT = *mut REASON_CONTEXT; +pub const EXCEPTION_DEBUG_EVENT: DWORD = 1; +pub const CREATE_THREAD_DEBUG_EVENT: DWORD = 2; +pub const CREATE_PROCESS_DEBUG_EVENT: DWORD = 3; +pub const EXIT_THREAD_DEBUG_EVENT: DWORD = 4; +pub const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; +pub const LOAD_DLL_DEBUG_EVENT: DWORD = 6; +pub const UNLOAD_DLL_DEBUG_EVENT: DWORD = 7; +pub const OUTPUT_DEBUG_STRING_EVENT: DWORD = 8; +pub const RIP_EVENT: DWORD = 9; +FN!{stdcall PTHREAD_START_ROUTINE( + lpThreadParameter: LPVOID, +) -> DWORD} +pub type LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; +FN!{stdcall PENCLAVE_ROUTINE( + lpThreadParameter: LPVOID, +) -> DWORD} +pub type LPENCLAVE_ROUTINE = PENCLAVE_ROUTINE; +STRUCT!{struct EXCEPTION_DEBUG_INFO { + ExceptionRecord: EXCEPTION_RECORD, + dwFirstChance: DWORD, +}} +pub type LPEXCEPTION_DEBUG_INFO = *mut EXCEPTION_DEBUG_INFO; +STRUCT!{struct CREATE_THREAD_DEBUG_INFO { + hThread: HANDLE, + lpThreadLocalBase: LPVOID, + lpStartAddress: LPTHREAD_START_ROUTINE, +}} +pub type LPCREATE_THREAD_DEBUG_INFO = *mut CREATE_THREAD_DEBUG_INFO; +STRUCT!{struct CREATE_PROCESS_DEBUG_INFO { + hFile: HANDLE, + hProcess: HANDLE, + hThread: HANDLE, + lpBaseOfImage: LPVOID, + dwDebugInfoFileOffset: DWORD, + nDebugInfoSize: DWORD, + lpThreadLocalBase: LPVOID, + lpStartAddress: LPTHREAD_START_ROUTINE, + lpImageName: LPVOID, + fUnicode: WORD, +}} +pub type LPCREATE_PROCESS_DEBUG_INFO = *mut CREATE_PROCESS_DEBUG_INFO; +STRUCT!{struct EXIT_THREAD_DEBUG_INFO { + dwExitCode: DWORD, +}} +pub type LPEXIT_THREAD_DEBUG_INFO = *mut EXIT_THREAD_DEBUG_INFO; +STRUCT!{struct EXIT_PROCESS_DEBUG_INFO { + dwExitCode: DWORD, +}} +pub type LPEXIT_PROCESS_DEBUG_INFO = *mut EXIT_PROCESS_DEBUG_INFO; +STRUCT!{struct LOAD_DLL_DEBUG_INFO { + hFile: HANDLE, + lpBaseOfDll: LPVOID, + dwDebugInfoFileOffset: DWORD, + nDebugInfoSize: DWORD, + lpImageName: LPVOID, + fUnicode: WORD, +}} +pub type LPLOAD_DLL_DEBUG_INFO = *mut LOAD_DLL_DEBUG_INFO; +STRUCT!{struct UNLOAD_DLL_DEBUG_INFO { + lpBaseOfDll: LPVOID, +}} +pub type LPUNLOAD_DLL_DEBUG_INFO = *mut UNLOAD_DLL_DEBUG_INFO; +STRUCT!{struct OUTPUT_DEBUG_STRING_INFO { + lpDebugStringData: LPSTR, + fUnicode: WORD, + nDebugStringLength: WORD, +}} +pub type LPOUTPUT_DEBUG_STRING_INFO = *mut OUTPUT_DEBUG_STRING_INFO; +STRUCT!{struct RIP_INFO { + dwError: DWORD, + dwType: DWORD, +}} +pub type LPRIP_INFO = *mut RIP_INFO; +UNION!{union DEBUG_EVENT_u { + [u32; 21] [u64; 20], + Exception Exception_mut: EXCEPTION_DEBUG_INFO, + CreateThread CreateThread_mut: CREATE_THREAD_DEBUG_INFO, + CreateProcessInfo CreateProcessInfo_mut: CREATE_PROCESS_DEBUG_INFO, + ExitThread ExitThread_mut: EXIT_THREAD_DEBUG_INFO, + ExitProcess ExitProcess_mut: EXIT_PROCESS_DEBUG_INFO, + LoadDll LoadDll_mut: LOAD_DLL_DEBUG_INFO, + UnloadDll UnloadDll_mut: UNLOAD_DLL_DEBUG_INFO, + DebugString DebugString_mut: OUTPUT_DEBUG_STRING_INFO, + RipInfo RipInfo_mut: RIP_INFO, +}} +STRUCT!{struct DEBUG_EVENT { + dwDebugEventCode: DWORD, + dwProcessId: DWORD, + dwThreadId: DWORD, + u: DEBUG_EVENT_u, +}} +pub type LPDEBUG_EVENT = *mut DEBUG_EVENT; +pub type LPCONTEXT = PCONTEXT; +pub const STILL_ACTIVE: DWORD = STATUS_PENDING as u32; +pub const EXCEPTION_ACCESS_VIOLATION: DWORD = STATUS_ACCESS_VIOLATION as u32; +pub const EXCEPTION_DATATYPE_MISALIGNMENT: DWORD = STATUS_DATATYPE_MISALIGNMENT as u32; +pub const EXCEPTION_BREAKPOINT: DWORD = STATUS_BREAKPOINT as u32; +pub const EXCEPTION_SINGLE_STEP: DWORD = STATUS_SINGLE_STEP as u32; +pub const EXCEPTION_ARRAY_BOUNDS_EXCEEDED: DWORD = STATUS_ARRAY_BOUNDS_EXCEEDED as u32; +pub const EXCEPTION_FLT_DENORMAL_OPERAND: DWORD = STATUS_FLOAT_DENORMAL_OPERAND as u32; +pub const EXCEPTION_FLT_DIVIDE_BY_ZERO: DWORD = STATUS_FLOAT_DIVIDE_BY_ZERO as u32; +pub const EXCEPTION_FLT_INEXACT_RESULT: DWORD = STATUS_FLOAT_INEXACT_RESULT as u32; +pub const EXCEPTION_FLT_INVALID_OPERATION: DWORD = STATUS_FLOAT_INVALID_OPERATION as u32; +pub const EXCEPTION_FLT_OVERFLOW: DWORD = STATUS_FLOAT_OVERFLOW as u32; +pub const EXCEPTION_FLT_STACK_CHECK: DWORD = STATUS_FLOAT_STACK_CHECK as u32; +pub const EXCEPTION_FLT_UNDERFLOW: DWORD = STATUS_FLOAT_UNDERFLOW as u32; +pub const EXCEPTION_INT_DIVIDE_BY_ZERO: DWORD = STATUS_INTEGER_DIVIDE_BY_ZERO as u32; +pub const EXCEPTION_INT_OVERFLOW: DWORD = STATUS_INTEGER_OVERFLOW as u32; +pub const EXCEPTION_PRIV_INSTRUCTION: DWORD = STATUS_PRIVILEGED_INSTRUCTION as u32; +pub const EXCEPTION_IN_PAGE_ERROR: DWORD = STATUS_IN_PAGE_ERROR as u32; +pub const EXCEPTION_ILLEGAL_INSTRUCTION: DWORD = STATUS_ILLEGAL_INSTRUCTION as u32; +pub const EXCEPTION_NONCONTINUABLE_EXCEPTION: DWORD = STATUS_NONCONTINUABLE_EXCEPTION as u32; +pub const EXCEPTION_STACK_OVERFLOW: DWORD = STATUS_STACK_OVERFLOW as u32; +pub const EXCEPTION_INVALID_DISPOSITION: DWORD = STATUS_INVALID_DISPOSITION as u32; +pub const EXCEPTION_GUARD_PAGE: DWORD = STATUS_GUARD_PAGE_VIOLATION as u32; +pub const EXCEPTION_INVALID_HANDLE: DWORD = STATUS_INVALID_HANDLE as u32; +pub const EXCEPTION_POSSIBLE_DEADLOCK: DWORD = STATUS_POSSIBLE_DEADLOCK as u32; +pub const CONTROL_C_EXIT: DWORD = STATUS_CONTROL_C_EXIT as u32; +pub const LMEM_FIXED: UINT = 0x0000; +pub const LMEM_MOVEABLE: UINT = 0x0002; +pub const LMEM_NOCOMPACT: UINT = 0x0010; +pub const LMEM_NODISCARD: UINT = 0x0020; +pub const LMEM_ZEROINIT: UINT = 0x0040; +pub const LMEM_MODIFY: UINT = 0x0080; +pub const LMEM_DISCARDABLE: UINT = 0x0F00; +pub const LMEM_VALID_FLAGS: UINT = 0x0F72; +pub const LMEM_INVALID_HANDLE: UINT = 0x8000; +pub const LHND: UINT = LMEM_MOVEABLE | LMEM_ZEROINIT; +pub const LPTR: UINT = LMEM_FIXED | LMEM_ZEROINIT; +pub const NONZEROLHND: UINT = LMEM_MOVEABLE; +pub const NONZEROLPTR: UINT = LMEM_FIXED; +//LocalDiscard +pub const LMEM_DISCARDED: UINT = 0x4000; +pub const LMEM_LOCKCOUNT: UINT = 0x00FF; +pub const NUMA_NO_PREFERRED_NODE: DWORD = -1i32 as u32; diff --git a/winapi/src/um/mmdeviceapi.rs b/winapi/src/um/mmdeviceapi.rs new file mode 100644 index 000000000..7965bf105 --- /dev/null +++ b/winapi/src/um/mmdeviceapi.rs @@ -0,0 +1,218 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! this ALWAYS GENERATED file contains the definitions for the interfaces +use ctypes::c_void; +use shared::guiddef::{GUID, REFIID}; +use shared::minwindef::{DWORD, LPARAM, LPVOID, UINT}; +// use shared::winerror::{ERROR_NOT_FOUND, ERROR_UNSUPPORTED_TYPE, HRESULT_FROM_WIN32}; +use shared::wtypes::PROPERTYKEY; +use um::propidl::PROPVARIANT; +use um::propsys::IPropertyStore; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR}; +// pub const E_NOTFOUND: HRESULT = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +// pub const E_UNSUPPORTED_TYPE: HRESULT = HRESULT_FROM_WIN32(ERROR_UNSUPPORTED_TYPE); +pub const DEVICE_STATE_ACTIVE: DWORD = 0x00000001; +pub const DEVICE_STATE_DISABLED: DWORD = 0x00000002; +pub const DEVICE_STATE_NOTPRESENT: DWORD = 0x00000004; +pub const DEVICE_STATE_UNPLUGGED: DWORD = 0x00000008; +pub const DEVICE_STATEMASK_ALL: DWORD = 0x0000000F; +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_FormFactor, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 0} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_ControlPanelPageProvider, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 1} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_Association, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 2} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_PhysicalSpeakers, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 3} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_GUID, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 4} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_Disable_SysFx, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 5} +pub const ENDPOINT_SYSFX_ENABLED: DWORD = 0x00000000; +pub const ENDPOINT_SYSFX_DISABLED: DWORD = 0x00000001; +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_FullRangeSpeakers, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 6} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_Supports_EventDriven_Mode, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 7} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_JackSubType, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 8} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpoint_Default_VolumeInDb, + 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, 9} +DEFINE_PROPERTYKEY!{PKEY_AudioEngine_DeviceFormat, + 0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, 0} +DEFINE_PROPERTYKEY!{PKEY_AudioEngine_OEMFormat, + 0xe4870e26, 0x3cc5, 0x4cd2, 0xba, 0x46, 0xca, 0xa, 0x9a, 0x70, 0xed, 0x4, 3} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpointLogo_IconEffects, + 0xf1ab780d, 0x2010, 0x4ed3, 0xa3, 0xa6, 0x8b, 0x87, 0xf0, 0xf0, 0xc4, 0x76, 0} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpointLogo_IconPath, + 0xf1ab780d, 0x2010, 0x4ed3, 0xa3, 0xa6, 0x8b, 0x87, 0xf0, 0xf0, 0xc4, 0x76, 1} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpointSettings_MenuText, + 0x14242002, 0x0320, 0x4de4, 0x95, 0x55, 0xa7, 0xd8, 0x2b, 0x73, 0xc2, 0x86, 0} +DEFINE_PROPERTYKEY!{PKEY_AudioEndpointSettings_LaunchContract, + 0x14242002, 0x0320, 0x4de4, 0x95, 0x55, 0xa7, 0xd8, 0x2b, 0x73, 0xc2, 0x86, 1} +STRUCT!{struct DIRECTX_AUDIO_ACTIVATION_PARAMS { + cbDirectXAudioActivationParams: DWORD, + guidAudioSession: GUID, + dwAudioStreamFlags: DWORD, +}} +pub type PDIRECTX_AUDIO_ACTIVATION_PARAMS = *mut DIRECTX_AUDIO_ACTIVATION_PARAMS; +ENUM!{enum EDataFlow { + eRender, + eCapture, + eAll, + EDataFlow_enum_count, +}} +ENUM!{enum ERole { + eConsole, + eMultimedia, + eCommunications, + ERole_enum_count, +}} +ENUM!{enum EndpointFormFactor { + RemoteNetworkDevice, + Speakers, + LineLevel, + Headphones, + Microphone, + Headset, + Handset, + UnknownDigitalPassthrough, + SPDIF, + DigitalAudioDisplayDevice, + UnknownFormFactor, + EndpointFormFactor_enum_count, +}} +pub const HDMI: EndpointFormFactor = DigitalAudioDisplayDevice; +DEFINE_GUID!{DEVINTERFACE_AUDIO_RENDER, + 0xe6327cad, 0xdcec, 0x4949, 0xae, 0x8a, 0x99, 0x1e, 0x97, 0x6a, 0x79, 0xd2} +DEFINE_GUID!{DEVINTERFACE_AUDIO_CAPTURE, + 0x2eef81be, 0x33fa, 0x4800, 0x96, 0x70, 0x1c, 0xd4, 0x74, 0x97, 0x2c, 0x3f} +DEFINE_GUID!{DEVINTERFACE_MIDI_OUTPUT, + 0x6dc23320, 0xab33, 0x4ce4, 0x80, 0xd4, 0xbb, 0xb3, 0xeb, 0xbf, 0x28, 0x14} +DEFINE_GUID!{DEVINTERFACE_MIDI_INPUT, + 0x504be32c, 0xccf6, 0x4d2c, 0xb7, 0x3f, 0x6f, 0x8b, 0x37, 0x47, 0xe2, 0x2b} +RIDL!{#[uuid(0x7991eec9, 0x7e89, 0x4d85, 0x83, 0x90, 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0)] +interface IMMNotificationClient(IMMNotificationClientVtbl): IUnknown(IUnknownVtbl) { + fn OnDeviceStateChanged( + pwstrDeviceId: LPCWSTR, + dwNewState: DWORD, + ) -> HRESULT, + fn OnDeviceAdded( + pwstrDeviceId: LPCWSTR, + ) -> HRESULT, + fn OnDeviceRemoved( + pwstrDeviceId: LPCWSTR, + ) -> HRESULT, + fn OnDefaultDeviceChanged( + flow: EDataFlow, + role: ERole, + pwstrDefaultDeviceId: LPCWSTR, + ) -> HRESULT, + fn OnPropertyValueChanged( + pwstrDeviceId: LPCWSTR, + key: PROPERTYKEY, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd666063f, 0x1587, 0x4e43, 0x81, 0xf1, 0xb9, 0x48, 0xe8, 0x07, 0x36, 0x3f)] +interface IMMDevice(IMMDeviceVtbl): IUnknown(IUnknownVtbl) { + fn Activate( + iid: REFIID, + dwClsCtx: DWORD, + pActivationParams: *mut PROPVARIANT, + ppInterface: *mut LPVOID, + ) -> HRESULT, + fn OpenPropertyStore( + stgmAccess: DWORD, + ppProperties: *mut *mut IPropertyStore, + ) -> HRESULT, + fn GetId( + ppstrId: *mut LPWSTR, + ) -> HRESULT, + fn GetState( + pdwState: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0bd7a1be, 0x7a1a, 0x44db, 0x83, 0x97, 0xcc, 0x53, 0x92, 0x38, 0x7b, 0x5e)] +interface IMMDeviceCollection(IMMDeviceCollectionVtbl): IUnknown(IUnknownVtbl) { + fn GetCount( + pcDevices: *const UINT, + ) -> HRESULT, + fn Item( + nDevice: UINT, + ppDevice: *mut *mut IMMDevice, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1be09788, 0x6894, 0x4089, 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5)] +interface IMMEndpoint(IMMEndpointVtbl): IUnknown(IUnknownVtbl) { + fn GetDataFlow( + pDataFlow: *mut EDataFlow, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6)] +interface IMMDeviceEnumerator(IMMDeviceEnumeratorVtbl): IUnknown(IUnknownVtbl) { + fn EnumAudioEndpoints( + dataFlow: EDataFlow, + dwStateMask: DWORD, + ppDevices: *mut *mut IMMDeviceCollection, + ) -> HRESULT, + fn GetDefaultAudioEndpoint( + dataFlow: EDataFlow, + role: ERole, + ppEndpoint: *mut *mut IMMDevice, + ) -> HRESULT, + fn GetDevice( + pwstrId: LPCWSTR, + ppDevices: *mut *mut IMMDevice, + ) -> HRESULT, + fn RegisterEndpointNotificationCallback( + pClient: *mut IMMNotificationClient, + ) -> HRESULT, + fn UnregisterEndpointNotificationCallback( + pClient: *mut IMMNotificationClient, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b0d0ea4, 0xd0a9, 0x4b0e, 0x93, 0x5b, 0x09, 0x51, 0x67, 0x46, 0xfa, 0xc0)] +interface IMMDeviceActivator(IMMDeviceActivatorVtbl): IUnknown(IUnknownVtbl) { + fn Activate( + iid: REFIID, + pDevice: *mut IMMDevice, + pActivationParams: *mut PROPVARIANT, + ppInterface: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x41d949ab, 0x9862, 0x444a, 0x80, 0xf6, 0xc2, 0x61, 0x33, 0x4d, 0xa5, 0xeb)] +interface IActivateAudioInterfaceCompletionHandler(IActivateAudioInterfaceCompletionHandlerVtbl): + IUnknown(IUnknownVtbl) { + fn ActivateCompleted( + activateOperation: *mut IActivateAudioInterfaceAsyncOperation, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x72a22d78, 0xcde4, 0x431d, 0xb8, 0xcc, 0x84, 0x3a, 0x71, 0x19, 0x9b, 0x6d)] +interface IActivateAudioInterfaceAsyncOperation(IActivateAudioInterfaceAsyncOperationVtbl): + IUnknown(IUnknownVtbl) { + fn GetActivateResult( + activateResult: *mut HRESULT, + activatedInterface: *mut *mut IUnknown, + ) -> HRESULT, +}} +extern "system" { + pub fn ActivateAudioInterfaceAsync( + deviceInterfacePath: LPCWSTR, + riid: REFIID, + activationParams: *mut PROPVARIANT, + completionHandler: *mut IActivateAudioInterfaceCompletionHandler, + activationOperation: *mut *mut IActivateAudioInterfaceAsyncOperation, + ) -> HRESULT; +} +STRUCT!{struct AudioExtensionParams { + AddPageParam: LPARAM, + pEndpoint: *mut IMMDevice, + pPnpInterface: *mut IMMDevice, + pPnpDevnode: *mut IMMDevice, +}} +DEFINE_GUID!{CLSID_MMDeviceEnumerator, + 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E} diff --git a/winapi/src/um/mmeapi.rs b/winapi/src/um/mmeapi.rs new file mode 100644 index 000000000..cc5153b3b --- /dev/null +++ b/winapi/src/um/mmeapi.rs @@ -0,0 +1,336 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{DWORD_PTR, UINT_PTR}; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, LPWORD, PDWORD, UINT}; +use um::imm::LPUINT; +use um::mmsystem::{ + HMIDI, HMIDIIN, HMIDIOUT, HMIDISTRM, HWAVEIN, HWAVEOUT, LPCWAVEFORMATEX, LPHMIDIIN, LPHMIDIOUT, + LPHMIDISTRM, LPHWAVEIN, LPHWAVEOUT, LPMIDIHDR, LPMIDIINCAPSW, LPMIDIOUTCAPSW, LPMMTIME, + LPWAVEHDR, LPWAVEINCAPSW, LPWAVEOUTCAPSW, MMRESULT +}; +use um::winnt::{LPWSTR, PVOID}; +extern "system" { + pub fn waveOutGetNumDevs() -> UINT; + // pub fn waveOutGetDevCapsA(); + pub fn waveOutGetDevCapsW( + uDeviceID: UINT_PTR, + pwoc: LPWAVEOUTCAPSW, + cbwoc: UINT, + ) -> MMRESULT; + pub fn waveOutGetVolume( + hwo: HWAVEOUT, + pdwVolume: LPDWORD, + ) -> MMRESULT; + pub fn waveOutSetVolume( + hwo: HWAVEOUT, + dwVolume: DWORD, + ) -> MMRESULT; + // pub fn waveOutGetErrorTextA(); + pub fn waveOutGetErrorTextW( + mmrError: MMRESULT, + pszText: LPWSTR, + cchText: UINT, + ) -> MMRESULT; + pub fn waveOutOpen( + phwo: LPHWAVEOUT, + uDeviceID: UINT, + pwfx: LPCWAVEFORMATEX, + dwCallback: DWORD_PTR, + dwInstance: DWORD_PTR, + fdwOpen: DWORD, + ) -> MMRESULT; + pub fn waveOutClose( + hwo: HWAVEOUT, + ) -> MMRESULT; + pub fn waveOutPrepareHeader( + hwo: HWAVEOUT, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveOutUnprepareHeader( + hwo: HWAVEOUT, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveOutWrite( + hwo: HWAVEOUT, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveOutPause( + hwo: HWAVEOUT, + ) -> MMRESULT; + pub fn waveOutRestart( + hwo: HWAVEOUT, + ) -> MMRESULT; + pub fn waveOutReset( + hwo: HWAVEOUT, + ) -> MMRESULT; + pub fn waveOutBreakLoop( + hwo: HWAVEOUT, + ) -> MMRESULT; + pub fn waveOutGetPosition( + hwo: HWAVEOUT, + pmmt: LPMMTIME, + cbmmt: UINT, + ) -> MMRESULT; + pub fn waveOutGetPitch( + hwo: HWAVEOUT, + pdwPitch: LPDWORD, + ) -> MMRESULT; + pub fn waveOutSetPitch( + hwo: HWAVEOUT, + dwPitch: DWORD, + ) -> MMRESULT; + pub fn waveOutGetPlaybackRate( + hwo: HWAVEOUT, + pdwRate: LPDWORD, + ) -> MMRESULT; + pub fn waveOutSetPlaybackRate( + hwo: HWAVEOUT, + dwRate: DWORD, + ) -> MMRESULT; + // pub fn waveOutGetID(); + pub fn waveOutMessage( + hwo: HWAVEOUT, + uMsg: UINT, + dw1: DWORD_PTR, + dw2: DWORD_PTR, + ) -> MMRESULT; + pub fn waveInGetNumDevs() -> UINT; + // pub fn waveInGetDevCapsA(); + pub fn waveInGetDevCapsW( + uDeviceID: UINT_PTR, + pwic: LPWAVEINCAPSW, + cbwic: UINT, + ) -> MMRESULT; + // pub fn waveInGetErrorTextA(); + pub fn waveInGetErrorTextW( + mmrError: MMRESULT, + pszText: LPWSTR, + cchText: UINT, + ) -> MMRESULT; + pub fn waveInOpen( + phwi: LPHWAVEIN, + uDeviceID: UINT, + pwfx: LPCWAVEFORMATEX, + dwCallback: DWORD_PTR, + dwInstance: DWORD_PTR, + fdwOpen: DWORD, + ) -> MMRESULT; + pub fn waveInClose( + hwi: HWAVEIN, + ) -> MMRESULT; + pub fn waveInPrepareHeader( + hwi: HWAVEIN, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveInUnprepareHeader( + hwi: HWAVEIN, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveInAddBuffer( + hwi: HWAVEIN, + pwh: LPWAVEHDR, + cbwh: UINT, + ) -> MMRESULT; + pub fn waveInStart( + hwi: HWAVEIN, + ) -> MMRESULT; + pub fn waveInStop( + hwi: HWAVEIN, + ) -> MMRESULT; + pub fn waveInReset( + hwi: HWAVEIN, + ) -> MMRESULT; + pub fn waveInGetPosition( + hwi: HWAVEIN, + pmmt: LPMMTIME, + cbmmt: UINT, + ) -> MMRESULT; + // pub fn waveInGetID(); + pub fn waveInMessage( + hwi: HWAVEIN, + uMsg: UINT, + dw1: DWORD_PTR, + dw2: DWORD_PTR, + ) -> MMRESULT; + pub fn midiOutGetNumDevs() -> UINT; + pub fn midiStreamOpen( + lphStream: LPHMIDISTRM, + puDeviceID: LPUINT, + cMidi: DWORD, + dwCallback: DWORD_PTR, + dwInstance: DWORD_PTR, + fdwOpen: DWORD, + ) -> MMRESULT; + pub fn midiStreamClose( + hStream: HMIDISTRM, + ) -> MMRESULT; + pub fn midiStreamProperty( + hm: HMIDISTRM, + lppropdata: LPBYTE, + dwProperty: DWORD, + ) -> MMRESULT; + pub fn midiStreamPosition( + hms: HMIDISTRM, + pmmt: LPMMTIME, + cbmmt: UINT, + ) -> MMRESULT; + pub fn midiStreamOut( + hMidiStream: HMIDISTRM, + lpMidiHdr: LPMIDIHDR, + cbMidiHdr: UINT, + ) -> MMRESULT; + pub fn midiStreamPause( + hms: HMIDISTRM, + ) -> MMRESULT; + pub fn midiStreamRestart( + hms: HMIDISTRM, + ) -> MMRESULT; + pub fn midiStreamStop( + hms: HMIDISTRM, + ) -> MMRESULT; + pub fn midiConnect( + hMidi: HMIDI, + hmo: HMIDIOUT, + pReserved: PVOID, + ) -> MMRESULT; + pub fn midiDisconnect( + hMidi: HMIDI, + hmo: HMIDIOUT, + pReserved: PVOID, + ) -> MMRESULT; + pub fn midiOutGetDevCapsW( + uDeviceID: UINT_PTR, + lpMidiOutCaps: LPMIDIOUTCAPSW, + cbMidiOutCaps: UINT, + ) -> MMRESULT; + pub fn midiOutGetVolume( + hmo: HMIDIOUT, + lpdwVolume: PDWORD, + ) -> MMRESULT; + pub fn midiOutSetVolume( + hmo: HMIDIOUT, + dwVolume: DWORD, + ) -> MMRESULT; + pub fn midiOutGetErrorTextW( + mmrError: MMRESULT, + lpText: LPWSTR, + cchText: UINT, + ) -> MMRESULT; + pub fn midiOutOpen( + lphmo: LPHMIDIOUT, + uDeviceID: UINT, + dwCallback: DWORD_PTR, + dwCallbackInstance: DWORD_PTR, + dwFlags: DWORD, + ) -> MMRESULT; + pub fn midiOutClose( + hmo: HMIDIOUT, + ) -> MMRESULT; + pub fn midiOutPrepareHeader( + hmo: HMIDIOUT, + lpMidiOutHdr: LPMIDIHDR, + cbMidiOutHdr: UINT, + ) -> MMRESULT; + pub fn midiOutUnprepareHeader( + hmo: HMIDIOUT, + lpMidiOutHdr: LPMIDIHDR, + cbMidiOutHdr: UINT, + ) -> MMRESULT; + pub fn midiOutShortMsg( + hmo: HMIDIOUT, + dwMsg: DWORD, + ) -> MMRESULT; + pub fn midiOutLongMsg( + hmo: HMIDIOUT, + lpMidiOutHdr: LPMIDIHDR, + cbMidiOutHdr: UINT, + ) -> MMRESULT; + pub fn midiOutReset( + hmo: HMIDIOUT, + ) -> MMRESULT; + pub fn midiOutCachePatches( + hmo: HMIDIOUT, + wBank: UINT, + lpPatchArray: LPWORD, + wFlags: UINT, + ) -> MMRESULT; + pub fn midiOutCacheDrumPatches( + hmo: HMIDIOUT, + wPatch: UINT, + lpKeyArray: LPWORD, + wFlags: UINT, + ) -> MMRESULT; + pub fn midiOutGetID( + hmo: HMIDIOUT, + puDeviceID: LPUINT, + ) -> MMRESULT; + pub fn midiOutMessage( + deviceID: HMIDIOUT, + msg: UINT, + dw1: DWORD_PTR, + dw2: DWORD_PTR, + ) -> MMRESULT; + pub fn midiInGetNumDevs() -> UINT; + pub fn midiInGetDevCapsW( + uDeviceID: UINT_PTR, + lpMidiInCaps: LPMIDIINCAPSW, + cbMidiInCaps: UINT, + ) -> MMRESULT; + pub fn midiInGetErrorTextW( + wError: MMRESULT, + lpText: LPWSTR, + cchText: UINT, + ) -> MMRESULT; + pub fn midiInOpen( + lphMidiIn: LPHMIDIIN, + uDeviceID: UINT, + dwCallback: DWORD_PTR, + dwCallbackInstance: DWORD_PTR, + dwFlags: DWORD, + ) -> MMRESULT; + pub fn midiInClose( + hMidiIn: HMIDIIN, + ) -> MMRESULT; + pub fn midiInPrepareHeader( + hMidiIn: HMIDIIN, + lpMidiInHdr: LPMIDIHDR, + cbMidiInHdr: UINT, + ) -> MMRESULT; + pub fn midiInUnprepareHeader( + hMidiIn: HMIDIIN, + lpMidiInHdr: LPMIDIHDR, + cbMidiInHdr: UINT, + ) -> MMRESULT; + pub fn midiInAddBuffer( + hMidiIn: HMIDIIN, + lpMidiInHdr: LPMIDIHDR, + cbMidiInHdr: UINT, + ) -> MMRESULT; + pub fn midiInStart( + hMidiIn: HMIDIIN, + ) -> MMRESULT; + pub fn midiInStop( + hMidiIn: HMIDIIN, + ) -> MMRESULT; + pub fn midiInReset( + hMidiIn: HMIDIIN, + ) -> MMRESULT; + pub fn midiInGetID( + hmi: HMIDIIN, + puDeviceID: LPUINT, + ) -> MMRESULT; + pub fn midiInMessage( + deviceID: HMIDIIN, + msg: UINT, + dw1: DWORD_PTR, + dw2: DWORD_PTR, + ) -> MMRESULT; +} diff --git a/winapi/src/um/mmsystem.rs b/winapi/src/um/mmsystem.rs new file mode 100644 index 000000000..657ba5f4e --- /dev/null +++ b/winapi/src/um/mmsystem.rs @@ -0,0 +1,266 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! MM procedure declarations, constant definitions and macros +use shared::basetsd::DWORD_PTR; +use shared::minwindef::{BYTE, DWORD, UINT, WORD}; +use shared::mmreg::WAVEFORMATEX; +use um::winnt::{LPSTR, WCHAR}; +//109 (Win 7 SDK) +pub type MMVERSION = UINT; +pub type MMRESULT = UINT; +STRUCT!{#[repr(packed)] struct MMTIME_smpte { + hour: BYTE, + min: BYTE, + sec: BYTE, + frame: BYTE, + fps: BYTE, + dummy: BYTE, + pad: [BYTE; 2], +}} +STRUCT!{#[repr(packed)] struct MMTIME_midi { + songptrpos: DWORD, +}} +UNION!{#[repr(packed)] union MMTIME_u { + [u32; 2], + ms ms_mut: DWORD, + sample sample_mut: DWORD, + cb cb_mut: DWORD, + ticks ticks_mut: DWORD, + smpte smpte_mut: MMTIME_smpte, + midi midi_mut: MMTIME_midi, +}} +STRUCT!{#[repr(packed)] struct MMTIME { + wType: UINT, + u: MMTIME_u, +}} +pub type PMMTIME = *mut MMTIME; +pub type NPMMTIME = *mut MMTIME; +pub type LPMMTIME = *mut MMTIME; +pub const TIME_MS: UINT = 0x0001; +pub const TIME_SAMPLES: UINT = 0x0002; +pub const TIME_BYTES: UINT = 0x0004; +pub const TIME_SMPTE: UINT = 0x0008; +pub const TIME_MIDI: UINT = 0x0010; +pub const TIME_TICKS: UINT = 0x0020; +pub const MM_JOY1MOVE: UINT = 0x3A0; +pub const MM_JOY2MOVE: UINT = 0x3A1; +pub const MM_JOY1ZMOVE: UINT = 0x3A2; +pub const MM_JOY2ZMOVE: UINT = 0x3A3; +pub const MM_JOY1BUTTONDOWN: UINT = 0x3B5; +pub const MM_JOY2BUTTONDOWN: UINT = 0x3B6; +pub const MM_JOY1BUTTONUP: UINT = 0x3B7; +pub const MM_JOY2BUTTONUP: UINT = 0x3B8; +pub const MM_MCINOTIFY: UINT = 0x3B9; +pub const MM_WOM_OPEN: UINT = 0x3BB; +pub const MM_WOM_CLOSE: UINT = 0x3BC; +pub const MM_WOM_DONE: UINT = 0x3BD; +pub const MM_WIM_OPEN: UINT = 0x3BE; +pub const MM_WIM_CLOSE: UINT = 0x3BF; +pub const MM_WIM_DATA: UINT = 0x3C0; +pub const MM_MIM_OPEN: UINT = 0x3C1; +pub const MM_MIM_CLOSE: UINT = 0x3C2; +pub const MM_MIM_DATA: UINT = 0x3C3; +pub const MM_MIM_LONGDATA: UINT = 0x3C4; +pub const MM_MIM_ERROR: UINT = 0x3C5; +pub const MM_MIM_LONGERROR: UINT = 0x3C6; +pub const MM_MOM_OPEN: UINT = 0x3C7; +pub const MM_MOM_CLOSE: UINT = 0x3C8; +pub const MM_MOM_DONE: UINT = 0x3C9; +pub const MMSYSERR_BASE: MMRESULT = 0; +pub const WAVERR_BASE: MMRESULT = 32; +pub const MIDIERR_BASE: MMRESULT = 64; +pub const TIMERR_BASE: MMRESULT = 96; +pub const JOYERR_BASE: MMRESULT = 160; +pub const MCIERR_BASE: MMRESULT = 256; +pub const MIXERR_BASE: MMRESULT = 1024; +pub const MMSYSERR_NOERROR: MMRESULT = 0; +pub const MMSYSERR_ERROR: MMRESULT = MMSYSERR_BASE + 1; +pub const MMSYSERR_BADDEVICEID: MMRESULT = MMSYSERR_BASE + 2; +pub const MMSYSERR_NOTENABLED: MMRESULT = MMSYSERR_BASE + 3; +pub const MMSYSERR_ALLOCATED: MMRESULT = MMSYSERR_BASE + 4; +pub const MMSYSERR_INVALHANDLE: MMRESULT = MMSYSERR_BASE + 5; +pub const MMSYSERR_NODRIVER: MMRESULT = MMSYSERR_BASE + 6; +pub const MMSYSERR_NOMEM: MMRESULT = MMSYSERR_BASE + 7; +pub const MMSYSERR_NOTSUPPORTED: MMRESULT = MMSYSERR_BASE + 8; +pub const MMSYSERR_BADERRNUM: MMRESULT = MMSYSERR_BASE + 9; +pub const MMSYSERR_INVALFLAG: MMRESULT = MMSYSERR_BASE + 10; +pub const MMSYSERR_INVALPARAM: MMRESULT = MMSYSERR_BASE + 11; +pub const MMSYSERR_HANDLEBUSY: MMRESULT = MMSYSERR_BASE + 12; +pub const MMSYSERR_INVALIDALIAS: MMRESULT = MMSYSERR_BASE + 13; +pub const MMSYSERR_BADDB: MMRESULT = MMSYSERR_BASE + 14; +pub const MMSYSERR_KEYNOTFOUND: MMRESULT = MMSYSERR_BASE + 15; +pub const MMSYSERR_READERROR: MMRESULT = MMSYSERR_BASE + 16; +pub const MMSYSERR_WRITEERROR: MMRESULT = MMSYSERR_BASE + 17; +pub const MMSYSERR_DELETEERROR: MMRESULT = MMSYSERR_BASE + 18; +pub const MMSYSERR_VALNOTFOUND: MMRESULT = MMSYSERR_BASE + 19; +pub const MMSYSERR_NODRIVERCB: MMRESULT = MMSYSERR_BASE + 20; +pub const MMSYSERR_MOREDATA: MMRESULT = MMSYSERR_BASE + 21; +pub const MMSYSERR_LASTERROR: MMRESULT = MMSYSERR_BASE + 21; +pub const MIDIERR_UNPREPARED: MMRESULT = MIDIERR_BASE + 0; +pub const MIDIERR_STILLPLAYING: MMRESULT = MIDIERR_BASE + 1; +pub const MIDIERR_NOMAP: MMRESULT = MIDIERR_BASE + 2; +pub const MIDIERR_NOTREADY: MMRESULT = MIDIERR_BASE + 3; +pub const MIDIERR_NODEVICE: MMRESULT = MIDIERR_BASE + 4; +pub const MIDIERR_INVALIDSETUP: MMRESULT = MIDIERR_BASE + 5; +pub const MIDIERR_BADOPENMODE: MMRESULT = MIDIERR_BASE + 6; +pub const MIDIERR_DONT_CONTINUE: MMRESULT = MIDIERR_BASE + 7; +pub const MIDIERR_LASTERROR: MMRESULT = MIDIERR_BASE + 7; +pub const CALLBACK_TYPEMASK: DWORD = 0x00070000; +pub const CALLBACK_NULL: DWORD = 0x00000000; +pub const CALLBACK_WINDOW: DWORD = 0x00010000; +pub const CALLBACK_TASK: DWORD = 0x00020000; +pub const CALLBACK_FUNCTION: DWORD = 0x00030000; +pub const CALLBACK_THREAD: DWORD = CALLBACK_TASK; +pub const CALLBACK_EVENT: DWORD = 0x00050000; +//497 (Win 7 SDK) +pub const WAVERR_BADFORMAT: MMRESULT = WAVERR_BASE + 0; +pub const WAVERR_STILLPLAYING: MMRESULT = WAVERR_BASE + 1; +pub const WAVERR_UNPREPARED: MMRESULT = WAVERR_BASE + 2; +pub const WAVERR_SYNC: MMRESULT = WAVERR_BASE + 3; +pub const WAVERR_LASTERROR: MMRESULT = WAVERR_BASE + 3; +DECLARE_HANDLE!{HWAVEIN, HWAVEIN__} +DECLARE_HANDLE!{HWAVEOUT, HWAVEOUT__} +pub type LPHWAVEIN = *mut HWAVEIN; +pub type LPHWAVEOUT = *mut HWAVEOUT; +pub const WOM_OPEN: UINT = MM_WOM_OPEN; +pub const WOM_CLOSE: UINT = MM_WOM_CLOSE; +pub const WOM_DONE: UINT = MM_WOM_DONE; +pub const WIM_OPEN: UINT = MM_WIM_OPEN; +pub const WIM_CLOSE: UINT = MM_WIM_CLOSE; +pub const WIM_DATA: UINT = MM_WIM_DATA; +pub const WAVE_MAPPER: UINT = 0xFFFFFFFF; +pub const WAVE_FORMAT_QUERY: DWORD = 0x0001; +pub const WAVE_ALLOWSYNC: DWORD = 0x0002; +pub const WAVE_MAPPED: DWORD = 0x0004; +pub const WAVE_FORMAT_DIRECT: DWORD = 0x0008; +pub const WAVE_FORMAT_DIRECT_QUERY: DWORD = WAVE_FORMAT_QUERY | WAVE_FORMAT_DIRECT; +pub const WAVE_MAPPED_DEFAULT_COMMUNICATION_DEVICE: DWORD = 0x0010; +STRUCT!{#[repr(packed)] struct WAVEHDR { + lpData: LPSTR, + dwBufferLength: DWORD, + dwBytesRecorded: DWORD, + dwUser: DWORD_PTR, + dwFlags: DWORD, + dwLoops: DWORD, + lpNext: *mut WAVEHDR, + reserved: DWORD_PTR, +}} +pub type PWAVEHDR = *mut WAVEHDR; +pub type NPWAVEHDR = *mut WAVEHDR; +pub type LPWAVEHDR = *mut WAVEHDR; +STRUCT!{#[repr(packed)] struct WAVEOUTCAPSW { + wMid: WORD, + wPid: WORD, + vDriverVersion: MMVERSION, + szPname: [WCHAR; 32], + dwFormats: DWORD, + wChannels: WORD, + wReserved1: WORD, + dwSupport: DWORD, +}} +pub type PWAVEOUTCAPSW = *mut WAVEOUTCAPSW; +pub type NPWAVEOUTCAPSW = *mut WAVEOUTCAPSW; +pub type LPWAVEOUTCAPSW = *mut WAVEOUTCAPSW; +STRUCT!{#[repr(packed)] struct WAVEINCAPSW { + wMid: WORD, + wPid: WORD, + vDriverVersion: MMVERSION, + szPname: [WCHAR; 32], + dwFormats: DWORD, + wChannels: WORD, + wReserved1: WORD, +}} +pub type PWAVEINCAPSW = *mut WAVEINCAPSW; +pub type NPWAVEINCAPSW = *mut WAVEINCAPSW; +pub type LPWAVEINCAPSW = *mut WAVEINCAPSW; +pub const WAVE_INVALIDFORMAT: DWORD = 0x00000000; +pub const WAVE_FORMAT_1M08: DWORD = 0x00000001; +pub const WAVE_FORMAT_1S08: DWORD = 0x00000002; +pub const WAVE_FORMAT_1M16: DWORD = 0x00000004; +pub const WAVE_FORMAT_1S16: DWORD = 0x00000008; +pub const WAVE_FORMAT_2M08: DWORD = 0x00000010; +pub const WAVE_FORMAT_2S08: DWORD = 0x00000020; +pub const WAVE_FORMAT_2M16: DWORD = 0x00000040; +pub const WAVE_FORMAT_2S16: DWORD = 0x00000080; +pub const WAVE_FORMAT_4M08: DWORD = 0x00000100; +pub const WAVE_FORMAT_4S08: DWORD = 0x00000200; +pub const WAVE_FORMAT_4M16: DWORD = 0x00000400; +pub const WAVE_FORMAT_4S16: DWORD = 0x00000800; +pub const WAVE_FORMAT_44M08: DWORD = 0x00000100; +pub const WAVE_FORMAT_44S08: DWORD = 0x00000200; +pub const WAVE_FORMAT_44M16: DWORD = 0x00000400; +pub const WAVE_FORMAT_44S16: DWORD = 0x00000800; +pub const WAVE_FORMAT_48M08: DWORD = 0x00001000; +pub const WAVE_FORMAT_48S08: DWORD = 0x00002000; +pub const WAVE_FORMAT_48M16: DWORD = 0x00004000; +pub const WAVE_FORMAT_48S16: DWORD = 0x00008000; +pub const WAVE_FORMAT_96M08: DWORD = 0x00010000; +pub const WAVE_FORMAT_96S08: DWORD = 0x00020000; +pub const WAVE_FORMAT_96M16: DWORD = 0x00040000; +pub const WAVE_FORMAT_96S16: DWORD = 0x00080000; +//782 (Win 7 SDK) +pub type PWAVEFORMATEX = *mut WAVEFORMATEX; +pub type NPWAVEFORMATEX = *mut WAVEFORMATEX; +pub type LPWAVEFORMATEX = *mut WAVEFORMATEX; +pub type LPCWAVEFORMATEX = *const WAVEFORMATEX; +//2170 (Win 7 SDK) +pub const TIMERR_NOERROR: MMRESULT = 0; +pub const TIMERR_NOCANDO: MMRESULT = TIMERR_BASE + 1; +pub const TIMERR_STRUCT: MMRESULT = TIMERR_BASE + 33; +//2198 (Win 7 SDK) +STRUCT!{#[repr(packed)] struct TIMECAPS { + wPeriodMin: UINT, + wPeriodMax: UINT, +}} +pub type PTIMECAPS = *mut TIMECAPS; +pub type NPTIMECAPS = *mut TIMECAPS; +pub type LPTIMECAPS = *mut TIMECAPS; +STRUCT!{#[repr(packed)] struct MIDIHDR { + lpData: LPSTR, + dwBufferLength: DWORD, + dwBytesRecorded: DWORD, + dwUser: DWORD_PTR, + dwFlags: DWORD, + lpNext: *mut MIDIHDR, + reserved: DWORD_PTR, + dwOffset: DWORD, + dwReserved: [DWORD_PTR; 8], +}} +pub type PMIDIHDR = *mut MIDIHDR; +pub type NPMIDIHDR = *mut MIDIHDR; +pub type LPMIDIHDR = *mut MIDIHDR; +STRUCT!{#[repr(packed)] struct MIDIINCAPSW { + wMid: WORD, + wPid: WORD, + vDriverVersion: MMVERSION, + szPname: [WCHAR; 32], + dwSupport: DWORD, +}} +pub type PMIDIINCAPSW = *mut MIDIINCAPSW; +pub type NPMIDIINCAPSW = *mut MIDIINCAPSW; +pub type LPMIDIINCAPSW = *mut MIDIINCAPSW; +STRUCT!{#[repr(packed)] struct MIDIOUTCAPSW { + wMid: WORD, + wPid: WORD, + vDriverVersion: MMVERSION, + szPname: [WCHAR; 32], + wTechnology: WORD, + wVoices: WORD, + wNotes: WORD, + wChannelMask: WORD, + dwSupport: DWORD, +}} +pub type PMIDIOUTCAPSW = *mut MIDIOUTCAPSW; +pub type NPMIDIOUTCAPSW = *mut MIDIOUTCAPSW; +pub type LPMIDIOUTCAPSW = *mut MIDIOUTCAPSW; +DECLARE_HANDLE!{HMIDIIN, HMIDIIN__} +DECLARE_HANDLE!{HMIDIOUT, HMIDIOUT__} +pub type LPHMIDIIN = *mut HMIDIIN; +pub type LPHMIDIOUT = *mut HMIDIOUT; +DECLARE_HANDLE!{HMIDISTRM, HMIDISTRM__} +DECLARE_HANDLE!{HMIDI, HMIDI__} +pub type LPHMIDISTRM = *mut HMIDISTRM; +pub type LPHMIDI = *mut HMIDI; diff --git a/winapi/src/um/mod.rs b/winapi/src/um/mod.rs new file mode 100644 index 000000000..af20c7c69 --- /dev/null +++ b/winapi/src/um/mod.rs @@ -0,0 +1,281 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Headers for user mode only +pub mod gl; +#[cfg(feature = "accctrl")] pub mod accctrl; +#[cfg(feature = "aclapi")] pub mod aclapi; +#[cfg(feature = "appmgmt")] pub mod appmgmt; +#[cfg(feature = "audioclient")] pub mod audioclient; +#[cfg(feature = "audiosessiontypes")] pub mod audiosessiontypes; +#[cfg(feature = "avrt")] pub mod avrt; +#[cfg(feature = "bits")] pub mod bits; +#[cfg(feature = "bits10_1")] pub mod bits10_1; +#[cfg(feature = "bits1_5")] pub mod bits1_5; +#[cfg(feature = "bits2_0")] pub mod bits2_0; +#[cfg(feature = "bits2_5")] pub mod bits2_5; +#[cfg(feature = "bits3_0")] pub mod bits3_0; +#[cfg(feature = "bits4_0")] pub mod bits4_0; +#[cfg(feature = "bits5_0")] pub mod bits5_0; +#[cfg(feature = "bitscfg")] pub mod bitscfg; +#[cfg(feature = "bitsmsg")] pub mod bitsmsg; +#[cfg(feature = "cfgmgr32")] pub mod cfgmgr32; +#[cfg(feature = "cguid")] pub mod cguid; +#[cfg(feature = "combaseapi")] pub mod combaseapi; +#[cfg(feature = "coml2api")] pub mod coml2api; +#[cfg(feature = "commapi")] pub mod commapi; +#[cfg(feature = "commctrl")] pub mod commctrl; +#[cfg(feature = "commdlg")] pub mod commdlg; +#[cfg(feature = "commoncontrols")] pub mod commoncontrols; +#[cfg(feature = "consoleapi")] pub mod consoleapi; +#[cfg(feature = "corsym")] pub mod corsym; +#[cfg(feature = "d2d1")] pub mod d2d1; +#[cfg(feature = "d2d1_1")] pub mod d2d1_1; +#[cfg(feature = "d2d1_2")] pub mod d2d1_2; +#[cfg(feature = "d2d1_3")] pub mod d2d1_3; +#[cfg(feature = "d2d1effectauthor")] pub mod d2d1effectauthor; +#[cfg(feature = "d2d1effects")] pub mod d2d1effects; +#[cfg(feature = "d2d1effects_1")] pub mod d2d1effects_1; +#[cfg(feature = "d2d1effects_2")] pub mod d2d1effects_2; +#[cfg(feature = "d2d1svg")] pub mod d2d1svg; +#[cfg(feature = "d2dbasetypes")] pub mod d2dbasetypes; +#[cfg(feature = "d3d")] pub mod d3d; +#[cfg(feature = "d3d10")] pub mod d3d10; +#[cfg(feature = "d3d10_1")] pub mod d3d10_1; +#[cfg(feature = "d3d10_1shader")] pub mod d3d10_1shader; +#[cfg(feature = "d3d10effect")] pub mod d3d10effect; +#[cfg(feature = "d3d10misc")] pub mod d3d10misc; +#[cfg(feature = "d3d10sdklayers")] pub mod d3d10sdklayers; +#[cfg(feature = "d3d10shader")] pub mod d3d10shader; +#[cfg(feature = "d3d11")] pub mod d3d11; +#[cfg(feature = "d3d11_1")] pub mod d3d11_1; +#[cfg(feature = "d3d11_2")] pub mod d3d11_2; +#[cfg(feature = "d3d11_3")] pub mod d3d11_3; +#[cfg(feature = "d3d11_4")] pub mod d3d11_4; +#[cfg(feature = "d3d11on12")] pub mod d3d11on12; +#[cfg(feature = "d3d11sdklayers")] pub mod d3d11sdklayers; +#[cfg(feature = "d3d11shader")] pub mod d3d11shader; +#[cfg(feature = "d3d11tokenizedprogramformat")] pub mod d3d11tokenizedprogramformat; +#[cfg(feature = "d3d12")] pub mod d3d12; +#[cfg(feature = "d3d12sdklayers")] pub mod d3d12sdklayers; +#[cfg(feature = "d3d12shader")] pub mod d3d12shader; +#[cfg(feature = "d3dcommon")] pub mod d3dcommon; +#[cfg(feature = "d3dcompiler")] pub mod d3dcompiler; +#[cfg(feature = "d3dcsx")] pub mod d3dcsx; +#[cfg(feature = "d3dx10core")] pub mod d3dx10core; +#[cfg(feature = "d3dx10math")] pub mod d3dx10math; +#[cfg(feature = "d3dx10mesh")] pub mod d3dx10mesh; +#[cfg(feature = "datetimeapi")] pub mod datetimeapi; +#[cfg(feature = "davclnt")] pub mod davclnt; +#[cfg(feature = "dbghelp")] pub mod dbghelp; +#[cfg(feature = "dbt")] pub mod dbt; +#[cfg(feature = "dcommon")] pub mod dcommon; +#[cfg(feature = "dcomp")] pub mod dcomp; +#[cfg(feature = "dcompanimation")] pub mod dcompanimation; +#[cfg(feature = "dde")] pub mod dde; +#[cfg(feature = "ddraw")] pub mod ddraw; +#[cfg(feature = "ddrawi")] pub mod ddrawi; +#[cfg(feature = "ddrawint")] pub mod ddrawint; +#[cfg(feature = "debugapi")] pub mod debugapi; +#[cfg(feature = "devicetopology")] pub mod devicetopology; +#[cfg(feature = "dinput")] pub mod dinput; +#[cfg(feature = "dispex")] pub mod dispex; +#[cfg(feature = "dmksctl")] pub mod dmksctl; +#[cfg(feature = "dmusicc")] pub mod dmusicc; +#[cfg(feature = "docobj")] pub mod docobj; +#[cfg(feature = "documenttarget")] pub mod documenttarget; +#[cfg(feature = "dpa_dsa")] pub mod dpa_dsa; +#[cfg(feature = "dpapi")] pub mod dpapi; +#[cfg(feature = "dsgetdc")] pub mod dsgetdc; +#[cfg(feature = "dsound")] pub mod dsound; +#[cfg(feature = "dsrole")] pub mod dsrole; +#[cfg(feature = "dvp")] pub mod dvp; +#[cfg(feature = "dwmapi")] pub mod dwmapi; +#[cfg(feature = "dwrite")] pub mod dwrite; +#[cfg(feature = "dwrite_1")] pub mod dwrite_1; +#[cfg(feature = "dwrite_2")] pub mod dwrite_2; +#[cfg(feature = "dwrite_3")] pub mod dwrite_3; +#[cfg(feature = "dxdiag")] pub mod dxdiag; +#[cfg(feature = "dxfile")] pub mod dxfile; +#[cfg(feature = "dxgidebug")] pub mod dxgidebug; +#[cfg(feature = "dxva2api")] pub mod dxva2api; +#[cfg(feature = "dxvahd")] pub mod dxvahd; +#[cfg(feature = "enclaveapi")] pub mod enclaveapi; +#[cfg(feature = "endpointvolume")] pub mod endpointvolume; +#[cfg(feature = "errhandlingapi")] pub mod errhandlingapi; +#[cfg(feature = "evntcons")] pub mod evntcons; +#[cfg(feature = "exdisp")] pub mod exdisp; +#[cfg(feature = "fibersapi")] pub mod fibersapi; +#[cfg(feature = "fileapi")] pub mod fileapi; +#[cfg(feature = "handleapi")] pub mod handleapi; +#[cfg(feature = "heapapi")] pub mod heapapi; +#[cfg(feature = "highlevelmonitorconfigurationapi")] pub mod highlevelmonitorconfigurationapi; +#[cfg(feature = "http")] pub mod http; +#[cfg(feature = "imm")] pub mod imm; +#[cfg(feature = "interlockedapi")] pub mod interlockedapi; +#[cfg(feature = "ioapiset")] pub mod ioapiset; +#[cfg(feature = "jobapi")] pub mod jobapi; +#[cfg(feature = "jobapi2")] pub mod jobapi2; +#[cfg(feature = "knownfolders")] pub mod knownfolders; +#[cfg(feature = "ktmw32")] pub mod ktmw32; +#[cfg(feature = "libloaderapi")] pub mod libloaderapi; +#[cfg(feature = "lmaccess")] pub mod lmaccess; +#[cfg(feature = "lmalert")] pub mod lmalert; +#[cfg(feature = "lmapibuf")] pub mod lmapibuf; +#[cfg(feature = "lmat")] pub mod lmat; +#[cfg(feature = "lmdfs")] pub mod lmdfs; +#[cfg(feature = "lmerrlog")] pub mod lmerrlog; +#[cfg(feature = "lmjoin")] pub mod lmjoin; +#[cfg(feature = "lmmsg")] pub mod lmmsg; +#[cfg(feature = "lmremutl")] pub mod lmremutl; +#[cfg(feature = "lmrepl")] pub mod lmrepl; +#[cfg(feature = "lmserver")] pub mod lmserver; +#[cfg(feature = "lmshare")] pub mod lmshare; +#[cfg(feature = "lmstats")] pub mod lmstats; +#[cfg(feature = "lmsvc")] pub mod lmsvc; +#[cfg(feature = "lmuse")] pub mod lmuse; +#[cfg(feature = "lmwksta")] pub mod lmwksta; +#[cfg(feature = "lowlevelmonitorconfigurationapi")] pub mod lowlevelmonitorconfigurationapi; +#[cfg(feature = "lsalookup")] pub mod lsalookup; +#[cfg(feature = "memoryapi")] pub mod memoryapi; +#[cfg(feature = "minschannel")] pub mod minschannel; +#[cfg(feature = "minwinbase")] pub mod minwinbase; +#[cfg(feature = "mmdeviceapi")] pub mod mmdeviceapi; +#[cfg(feature = "mmeapi")] pub mod mmeapi; +#[cfg(feature = "mmsystem")] pub mod mmsystem; +#[cfg(feature = "msaatext")] pub mod msaatext; +#[cfg(feature = "mscat")] pub mod mscat; +#[cfg(feature = "mschapp")] pub mod mschapp; +#[cfg(feature = "mssip")] pub mod mssip; +#[cfg(feature = "mswsock")] pub mod mswsock; +#[cfg(feature = "namedpipeapi")] pub mod namedpipeapi; +#[cfg(feature = "namespaceapi")] pub mod namespaceapi; +#[cfg(feature = "nb30")] pub mod nb30; +#[cfg(feature = "ncrypt")] pub mod ncrypt; +#[cfg(feature = "ntlsa")] pub mod ntlsa; +#[cfg(feature = "ntsecapi")] pub mod ntsecapi; +#[cfg(feature = "oaidl")] pub mod oaidl; +#[cfg(feature = "objbase")] pub mod objbase; +#[cfg(feature = "objidl")] pub mod objidl; +#[cfg(feature = "objidlbase")] pub mod objidlbase; +#[cfg(feature = "ocidl")] pub mod ocidl; +#[cfg(feature = "ole2")] pub mod ole2; +#[cfg(feature = "oleauto")] pub mod oleauto; +#[cfg(feature = "olectl")] pub mod olectl; +#[cfg(feature = "oleidl")] pub mod oleidl; +#[cfg(feature = "opmapi")] pub mod opmapi; +#[cfg(feature = "pdh")] pub mod pdh; +#[cfg(feature = "perflib")] pub mod perflib; +#[cfg(feature = "physicalmonitorenumerationapi")] pub mod physicalmonitorenumerationapi; +#[cfg(feature = "playsoundapi")] pub mod playsoundapi; +#[cfg(feature = "portabledevice")] pub mod portabledevice; +#[cfg(feature = "portabledeviceapi")] pub mod portabledeviceapi; +#[cfg(feature = "portabledevicetypes")] pub mod portabledevicetypes; +#[cfg(feature = "powerbase")] pub mod powerbase; +#[cfg(feature = "powersetting")] pub mod powersetting; +#[cfg(feature = "powrprof")] pub mod powrprof; +#[cfg(feature = "processenv")] pub mod processenv; +#[cfg(feature = "processsnapshot")] pub mod processsnapshot; +#[cfg(feature = "processthreadsapi")] pub mod processthreadsapi; +#[cfg(feature = "processtopologyapi")] pub mod processtopologyapi; +#[cfg(feature = "profileapi")] pub mod profileapi; +#[cfg(feature = "propidl")] pub mod propidl; +#[cfg(feature = "propkeydef")] pub mod propkeydef; +#[cfg(feature = "propsys")] pub mod propsys; +#[cfg(feature = "prsht")] pub mod prsht; +#[cfg(feature = "psapi")] pub mod psapi; +#[cfg(feature = "realtimeapiset")] pub mod realtimeapiset; +#[cfg(feature = "reason")] pub mod reason; +#[cfg(feature = "restartmanager")] pub mod restartmanager; +#[cfg(feature = "restrictederrorinfo")] pub mod restrictederrorinfo; +#[cfg(feature = "rmxfguid")] pub mod rmxfguid; +#[cfg(feature = "sapi")] pub mod sapi; +#[cfg(feature = "sapi51")] pub mod sapi51; +#[cfg(feature = "sapi53")] pub mod sapi53; +#[cfg(feature = "sapiddk")] pub mod sapiddk; +#[cfg(feature = "sapiddk51")] pub mod sapiddk51; +#[cfg(feature = "schannel")] pub mod schannel; +#[cfg(feature = "securityappcontainer")] pub mod securityappcontainer; +#[cfg(feature = "securitybaseapi")] pub mod securitybaseapi; +#[cfg(feature = "servprov")] pub mod servprov; +#[cfg(feature = "setupapi")] pub mod setupapi; +#[cfg(feature = "shellapi")] pub mod shellapi; +#[cfg(feature = "shellscalingapi")] pub mod shellscalingapi; +#[cfg(feature = "shlobj")] pub mod shlobj; +#[cfg(feature = "shobjidl")] pub mod shobjidl; +#[cfg(feature = "shobjidl_core")] pub mod shobjidl_core; +#[cfg(feature = "shtypes")] pub mod shtypes; +#[cfg(feature = "spapidef")] pub mod spapidef; +#[cfg(feature = "spellcheck")] pub mod spellcheck; +#[cfg(feature = "sporder")] pub mod sporder; +#[cfg(feature = "sql")] pub mod sql; +#[cfg(feature = "sqlext")] pub mod sqlext; +#[cfg(feature = "sqltypes")] pub mod sqltypes; +#[cfg(feature = "sqlucode")] pub mod sqlucode; +#[cfg(feature = "sspi")] pub mod sspi; +#[cfg(feature = "stringapiset")] pub mod stringapiset; +#[cfg(feature = "strmif")] pub mod strmif; +#[cfg(feature = "subauth")] pub mod subauth; +#[cfg(feature = "synchapi")] pub mod synchapi; +#[cfg(feature = "sysinfoapi")] pub mod sysinfoapi; +#[cfg(feature = "systemtopologyapi")] pub mod systemtopologyapi; +#[cfg(feature = "taskschd")] pub mod taskschd; +#[cfg(feature = "textstor")] pub mod textstor; +#[cfg(feature = "threadpoolapiset")] pub mod threadpoolapiset; +#[cfg(feature = "threadpoollegacyapiset")] pub mod threadpoollegacyapiset; +#[cfg(feature = "timeapi")] pub mod timeapi; +#[cfg(feature = "timezoneapi")] pub mod timezoneapi; +#[cfg(feature = "tlhelp32")] pub mod tlhelp32; +#[cfg(feature = "unknwnbase")] pub mod unknwnbase; +#[cfg(feature = "urlhist")] pub mod urlhist; +#[cfg(feature = "urlmon")] pub mod urlmon; +#[cfg(feature = "userenv")] pub mod userenv; +#[cfg(feature = "usp10")] pub mod usp10; +#[cfg(feature = "utilapiset")] pub mod utilapiset; +#[cfg(feature = "uxtheme")] pub mod uxtheme; +#[cfg(feature = "vsbackup")] pub mod vsbackup; +#[cfg(feature = "vss")] pub mod vss; +#[cfg(feature = "vsserror")] pub mod vsserror; +#[cfg(feature = "vswriter")] pub mod vswriter; +#[cfg(feature = "wbemads")] pub mod wbemads; +#[cfg(feature = "wbemcli")] pub mod wbemcli; +#[cfg(feature = "wbemdisp")] pub mod wbemdisp; +#[cfg(feature = "wbemprov")] pub mod wbemprov; +#[cfg(feature = "wbemtran")] pub mod wbemtran; +#[cfg(feature = "wct")] pub mod wct; +#[cfg(feature = "werapi")] pub mod werapi; +#[cfg(feature = "winbase")] pub mod winbase; +#[cfg(feature = "wincodec")] pub mod wincodec; +#[cfg(feature = "wincodecsdk")] pub mod wincodecsdk; +#[cfg(feature = "wincon")] pub mod wincon; +#[cfg(feature = "wincontypes")] pub mod wincontypes; +#[cfg(feature = "wincred")] pub mod wincred; +#[cfg(feature = "wincrypt")] pub mod wincrypt; +#[cfg(feature = "windowsceip")] pub mod windowsceip; +#[cfg(feature = "winefs")] pub mod winefs; +#[cfg(feature = "winevt")] pub mod winevt; +#[cfg(feature = "wingdi")] pub mod wingdi; +#[cfg(feature = "winhttp")] pub mod winhttp; +#[cfg(feature = "wininet")] pub mod wininet; +#[cfg(feature = "winineti")] pub mod winineti; +#[cfg(feature = "winioctl")] pub mod winioctl; +#[cfg(feature = "winnetwk")] pub mod winnetwk; +#[cfg(feature = "winnls")] pub mod winnls; +#[cfg(feature = "winnt")] pub mod winnt; +#[cfg(feature = "winreg")] pub mod winreg; +#[cfg(feature = "winsafer")] pub mod winsafer; +#[cfg(feature = "winscard")] pub mod winscard; +#[cfg(feature = "winsmcrd")] pub mod winsmcrd; +#[cfg(feature = "winsock2")] pub mod winsock2; +#[cfg(feature = "winspool")] pub mod winspool; +#[cfg(feature = "winsvc")] pub mod winsvc; +#[cfg(feature = "winusb")] pub mod winusb; +#[cfg(feature = "winuser")] pub mod winuser; +#[cfg(feature = "winver")] pub mod winver; +#[cfg(feature = "wow64apiset")] pub mod wow64apiset; +#[cfg(feature = "wpdmtpextensions")] pub mod wpdmtpextensions; +#[cfg(feature = "ws2spi")] pub mod ws2spi; +#[cfg(feature = "ws2tcpip")] pub mod ws2tcpip; +#[cfg(feature = "xinput")] pub mod xinput; diff --git a/winapi/src/um/msaatext.rs b/winapi/src/um/msaatext.rs new file mode 100644 index 000000000..238ca2c13 --- /dev/null +++ b/winapi/src/um/msaatext.rs @@ -0,0 +1,59 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{IID_ITfMSAAControl, + 0xb5f8fb3b, 0x393f, 0x4f7c, 0x84, 0xcb, 0x50, 0x49, 0x24, 0xc2, 0x70, 0x5a} +DEFINE_GUID!{IID_IInternalDocWrap, + 0xe1aa6466, 0x9db4, 0x40ba, 0xbe, 0x03, 0x77, 0xc3, 0x8e, 0x8e, 0x60, 0xb2} +DEFINE_GUID!{IID_ITextStoreACPEx, + 0xa2de3bc2, 0x3d8e, 0x11d3, 0x81, 0xa9, 0xf7, 0x53, 0xfb, 0xe6, 0x1a, 0x00} +DEFINE_GUID!{IID_ITextStoreAnchorEx, + 0xa2de3bc1, 0x3d8e, 0x11d3, 0x81, 0xa9, 0xf7, 0x53, 0xfb, 0xe6, 0x1a, 0x00} +DEFINE_GUID!{IID_ITextStoreACPSinkEx, + 0x2bdf9464, 0x41e2, 0x43e3, 0x95, 0x0c, 0xa6, 0x86, 0x5b, 0xa2, 0x5c, 0xd4} +DEFINE_GUID!{IID_ITextStoreSinkAnchorEx, + 0x25642426, 0x028d, 0x4474, 0x97, 0x7b, 0x11, 0x1b, 0xb1, 0x14, 0xfe, 0x3e} +DEFINE_GUID!{IID_IAccDictionary, + 0x1dc4cb5f, 0xd737, 0x474d, 0xad, 0xe9, 0x5c, 0xcf, 0xc9, 0xbc, 0x1c, 0xc9} +DEFINE_GUID!{IID_IVersionInfo, + 0x401518ec, 0xdb00, 0x4611, 0x9b, 0x29, 0x2a, 0x0e, 0x4b, 0x9a, 0xfa, 0x85} +DEFINE_GUID!{IID_ICoCreateLocally, + 0x03de00aa, 0xf272, 0x41e3, 0x99, 0xcb, 0x03, 0xc5, 0xe8, 0x11, 0x4e, 0xa0} +DEFINE_GUID!{IID_ICoCreatedLocally, + 0x0a53eb6c, 0x1908, 0x4742, 0x8c, 0xff, 0x2c, 0xee, 0x2e, 0x93, 0xf9, 0x4c} +DEFINE_GUID!{IID_IAccStore, + 0xe2cd4a63, 0x2b72, 0x4d48, 0xb7, 0x39, 0x95, 0xe4, 0x76, 0x51, 0x95, 0xba} +DEFINE_GUID!{IID_IAccServerDocMgr, + 0xad7c73cf, 0x6dd5, 0x4855, 0xab, 0xc2, 0xb0, 0x4b, 0xad, 0x5b, 0x91, 0x53} +DEFINE_GUID!{IID_IAccClientDocMgr, + 0x4c896039, 0x7b6d, 0x49e6, 0xa8, 0xc1, 0x45, 0x11, 0x6a, 0x98, 0x29, 0x2b} +DEFINE_GUID!{IID_IDocWrap, + 0xdcd285fe, 0x0be0, 0x43bd, 0x99, 0xc9, 0xaa, 0xae, 0xc5, 0x13, 0xc5, 0x55} +DEFINE_GUID!{IID_IClonableWrapper, + 0xb33e75ff, 0xe84c, 0x4dca, 0xa2, 0x5c, 0x33, 0xb8, 0xdc, 0x00, 0x33, 0x74} +DEFINE_GUID!{LIBID_MSAATEXTLib, + 0x150e2d7a, 0xdac1, 0x4582, 0x94, 0x7d, 0x2a, 0x8f, 0xd7, 0x8b, 0x82, 0xcd} +DEFINE_GUID!{CLSID_MSAAControl, + 0x08cd963f, 0x7a3e, 0x4f5c, 0x9b, 0xd8, 0xd6, 0x92, 0xbb, 0x04, 0x3c, 0x5b} +DEFINE_GUID!{CLSID_AccStore, + 0x5440837f, 0x4bff, 0x4ae5, 0xa1, 0xb1, 0x77, 0x22, 0xec, 0xc6, 0x33, 0x2a} +DEFINE_GUID!{CLSID_AccDictionary, + 0x6572ee16, 0x5fe5, 0x4331, 0xbb, 0x6d, 0x76, 0xa4, 0x9c, 0x56, 0xe4, 0x23} +DEFINE_GUID!{CLSID_AccServerDocMgr, + 0x6089a37e, 0xeb8a, 0x482d, 0xbd, 0x6f, 0xf9, 0xf4, 0x69, 0x04, 0xd1, 0x6d} +DEFINE_GUID!{CLSID_AccClientDocMgr, + 0xfc48cc30, 0x4f3e, 0x4fa1, 0x80, 0x3b, 0xad, 0x0e, 0x19, 0x6a, 0x83, 0xb1} +DEFINE_GUID!{CLSID_DocWrap, + 0xbf426f7e, 0x7a5e, 0x44d6, 0x83, 0x0c, 0xa3, 0x90, 0xea, 0x94, 0x62, 0xa3} +DEFINE_GUID!{IID_ITextStoreACP, + 0x28888fe3, 0xc2a0, 0x483a, 0xa3, 0xea, 0x8c, 0xb1, 0xce, 0x51, 0xff, 0x3d} +DEFINE_GUID!{IID_ITextStoreAnchor, + 0x9b2077b0, 0x5f18, 0x4dec, 0xbe, 0xe9, 0x3c, 0xc7, 0x22, 0xf5, 0xdf, 0xe0} +DEFINE_GUID!{IID_IAnchor, + 0x0feb7e34, 0x5a60, 0x4356, 0x8e, 0xf7, 0xab, 0xde, 0xc2, 0xff, 0x7c, 0xf8} +DEFINE_GUID!{IID_ITextStoreAnchorSink, + 0xaa80e905, 0x2021, 0x11d2, 0x93, 0xe0, 0x00, 0x60, 0xb0, 0x67, 0xb8, 0x6e} +DEFINE_GUID!{IID_ITextStoreACPSink, + 0x22d44c94, 0xa419, 0x4542, 0xa2, 0x72, 0xae, 0x26, 0x09, 0x3e, 0xce, 0xcf} diff --git a/winapi/src/um/mscat.rs b/winapi/src/um/mscat.rs new file mode 100644 index 000000000..fca635fcb --- /dev/null +++ b/winapi/src/um/mscat.rs @@ -0,0 +1,36 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Microsoft Internet Security Catalog API Prototypes and Definitions +use shared::guiddef::GUID; +use shared::minwindef::DWORD; +use um::mssip::SIP_INDIRECT_DATA; +use um::wincrypt::{CRYPT_ATTR_BLOB, HCRYPTMSG, HCRYPTPROV}; +use um::winnt::{HANDLE, LPWSTR}; +STRUCT!{struct CRYPTCATSTORE { + cbStruct: DWORD, + dwPublicVersion: DWORD, + pwszP7File: LPWSTR, + hProv: HCRYPTPROV, + dwEncodingType: DWORD, + fdwStoreFlags: DWORD, + hReserved: HANDLE, + hAttrs: HANDLE, + hCryptMsg: HCRYPTMSG, + hSorted: HANDLE, +}} +STRUCT!{struct CRYPTCATMEMBER { + cbStruct: DWORD, + pwszReferenceTag: LPWSTR, + pwszFileName: LPWSTR, + gSubjectType: GUID, + fdwMemberFlags: DWORD, + pIndirectData: *mut SIP_INDIRECT_DATA, + dwCertVersion: DWORD, + dwReserved: DWORD, + hReserved: HANDLE, + sEncodedIndirectData: CRYPT_ATTR_BLOB, + sEncodedMemberInfo: CRYPT_ATTR_BLOB, +}} diff --git a/winapi/src/um/mschapp.rs b/winapi/src/um/mschapp.rs new file mode 100644 index 000000000..103b54c9f --- /dev/null +++ b/winapi/src/um/mschapp.rs @@ -0,0 +1,48 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::SIZE_T; +use shared::minwindef::{DWORD, UCHAR}; +use um::winnt::{BOOLEAN, CHAR, PWSTR}; +pub const CYPHER_BLOCK_LENGTH: SIZE_T = 8; +STRUCT!{struct CYPHER_BLOCK { + data: [CHAR; CYPHER_BLOCK_LENGTH], +}} +STRUCT!{struct LM_OWF_PASSWORD { + data: [CYPHER_BLOCK; 2], +}} +pub type PLM_OWF_PASSWORD = *mut LM_OWF_PASSWORD; +pub type NT_OWF_PASSWORD = LM_OWF_PASSWORD; +pub type PNT_OWF_PASSWORD = *mut NT_OWF_PASSWORD; +STRUCT!{struct SAMPR_ENCRYPTED_USER_PASSWORD { + Buffer: [UCHAR; (256 * 2) + 4], +}} +pub type PSAMPR_ENCRYPTED_USER_PASSWORD = *mut SAMPR_ENCRYPTED_USER_PASSWORD; +STRUCT!{struct ENCRYPTED_LM_OWF_PASSWORD { + data: [CYPHER_BLOCK; 2], +}} +pub type PENCRYPTED_LM_OWF_PASSWORD = *mut ENCRYPTED_LM_OWF_PASSWORD; +pub type ENCRYPTED_NT_OWF_PASSWORD = ENCRYPTED_LM_OWF_PASSWORD; +pub type PENCRYPTED_NT_OWF_PASSWORD = *mut ENCRYPTED_NT_OWF_PASSWORD; +extern "system" { + pub fn MSChapSrvChangePassword( + ServerName: PWSTR, + UserName: PWSTR, + LmOldPresent: BOOLEAN, + LmOldOwfPassword: PLM_OWF_PASSWORD, + LmNewOwfPassword: PLM_OWF_PASSWORD, + NtOldOwfPassword: PNT_OWF_PASSWORD, + NtNewOwfPassword: PNT_OWF_PASSWORD, + ) -> DWORD; + pub fn MSChapSrvChangePassword2( + ServerName: PWSTR, + UserName: PWSTR, + NewPasswordEncryptedWithOldNt: PSAMPR_ENCRYPTED_USER_PASSWORD, + OldNtOwfPasswordEncryptedWithNewNt: PENCRYPTED_NT_OWF_PASSWORD, + LmPresent: BOOLEAN, + NewPasswordEncryptedWithOldLm: PSAMPR_ENCRYPTED_USER_PASSWORD, + OldLmOwfPasswordEncryptedWithNewLmOrNt: PENCRYPTED_LM_OWF_PASSWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/mssip.rs b/winapi/src/um/mssip.rs new file mode 100644 index 000000000..f8cd6e407 --- /dev/null +++ b/winapi/src/um/mssip.rs @@ -0,0 +1,255 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Microsoft SIP Provider Prototypes and Definitions +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, BYTE, DWORD, LPVOID}; +use um::mscat::{CRYPTCATMEMBER, CRYPTCATSTORE}; +use um::wincrypt::{ + CRYPT_ALGORITHM_IDENTIFIER, CRYPT_ATTRIBUTE_TYPE_VALUE, CRYPT_HASH_BLOB, HCRYPTPROV, +}; +use um::winnt::{HANDLE, LPCWSTR, PWSTR, WCHAR}; +pub type CRYPT_DIGEST_DATA = CRYPT_HASH_BLOB; +pub const MSSIP_FLAGS_PROHIBIT_RESIZE_ON_CREATE: DWORD = 0x00010000; +pub const MSSIP_FLAGS_USE_CATALOG: DWORD = 0x00020000; +pub const MSSIP_FLAGS_MULTI_HASH: DWORD = 0x00040000; +pub const SPC_INC_PE_RESOURCES_FLAG: DWORD = 0x80; +pub const SPC_INC_PE_DEBUG_INFO_FLAG: DWORD = 0x40; +pub const SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG: DWORD = 0x20; +pub const SPC_EXC_PE_PAGE_HASHES_FLAG: DWORD = 0x10; +pub const SPC_INC_PE_PAGE_HASHES_FLAG: DWORD = 0x100; +pub const SPC_DIGEST_GENERATE_FLAG: DWORD = 0x200; +pub const SPC_DIGEST_SIGN_FLAG: DWORD = 0x400; +pub const SPC_RELAXED_PE_MARKER_CHECK: DWORD = 0x800; +pub const SPC_MARKER_CHECK_SKIP_SIP_INDIRECT_DATA_FLAG: DWORD = 0x00000001; +pub const SPC_MARKER_CHECK_CURRENTLY_SUPPORTED_FLAGS: DWORD + = SPC_MARKER_CHECK_SKIP_SIP_INDIRECT_DATA_FLAG; +pub const MSSIP_ADDINFO_NONE: DWORD = 0; +pub const MSSIP_ADDINFO_FLAT: DWORD = 1; +pub const MSSIP_ADDINFO_CATMEMBER: DWORD = 2; +pub const MSSIP_ADDINFO_BLOB: DWORD = 3; +pub const MSSIP_ADDINFO_NONMSSIP: DWORD = 500; +UNION!{union SIP_SUBJECTINFO_u { + [usize; 1], + psFlat psFlat_mut: *mut MS_ADDINFO_FLAT, + psCatMember psCatMember_mut: *mut MS_ADDINFO_CATALOGMEMBER, + psBlob psBlob_mut: *mut MS_ADDINFO_BLOB, +}} +STRUCT!{struct SIP_SUBJECTINFO { + cbSize: DWORD, + pgSubjectType: *mut GUID, + hFile: HANDLE, + pwsFileName: LPCWSTR, + pwsDisplayName: LPCWSTR, + dwReserved1: DWORD, + dwIntVersion: DWORD, + hProv: HCRYPTPROV, + DigestAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + dwFlags: DWORD, + dwEncodingType: DWORD, + dwReserved2: DWORD, + fdwCAPISettings: DWORD, + fdwSecuritySettings: DWORD, + dwIndex: DWORD, + dwUnionChoice: DWORD, + u: SIP_SUBJECTINFO_u, + pClientData: LPVOID, +}} +pub type LPSIP_SUBJECTINFO = *mut SIP_SUBJECTINFO; +STRUCT!{struct MS_ADDINFO_FLAT { + cbStruct: DWORD, + pIndirectData: *mut SIP_INDIRECT_DATA, +}} +pub type PMS_ADDINFO_FLAT = *mut MS_ADDINFO_FLAT; +STRUCT!{struct MS_ADDINFO_CATALOGMEMBER { + cbStruct: DWORD, + pStore: *mut CRYPTCATSTORE, + pMember: *mut CRYPTCATMEMBER, +}} +pub type PMS_ADDINFO_CATALOGMEMBER = *mut MS_ADDINFO_CATALOGMEMBER; +STRUCT!{struct MS_ADDINFO_BLOB { + cbStruct: DWORD, + cbMemObject: DWORD, + pbMemObject: *mut BYTE, + cbMemSignedMsg: DWORD, + pbMemSignedMsg: *mut BYTE, +}} +pub type PMS_ADDINFO_BLOB = *mut MS_ADDINFO_BLOB; +STRUCT!{struct SIP_CAP_SET_V2 { + cbSize: DWORD, + dwVersion: DWORD, + isMultiSign: BOOL, + dwReserved: DWORD, +}} +pub type PSIP_CAP_SET_V2 = *mut SIP_CAP_SET_V2; +UNION!{union SIP_CAP_SET_V3_u { + [u32; 1], + dwFlags dwFlags_mut: DWORD, + dwReserved dwReserved_mut: DWORD, +}} +STRUCT!{struct SIP_CAP_SET_V3 { + cbSize: DWORD, + dwVersion: DWORD, + isMultiSign: BOOL, + u: SIP_CAP_SET_V3_u, +}} +pub type PSIP_CAP_SET_V3 = *mut SIP_CAP_SET_V3; +pub type SIP_CAP_SET = SIP_CAP_SET_V3; +pub type PSIP_CAP_SET = PSIP_CAP_SET_V3; +pub const SIP_CAP_SET_VERSION_2: DWORD = 2; +pub const SIP_CAP_SET_VERSION_3: DWORD = 3; +pub const SIP_CAP_SET_CUR_VER: DWORD = 3; +pub const SIP_CAP_FLAG_SEALING: DWORD = 0x00000001; +STRUCT!{struct SIP_INDIRECT_DATA { + Data: CRYPT_ATTRIBUTE_TYPE_VALUE, + DigestAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Digest: CRYPT_HASH_BLOB, +}} +pub type PSIP_INDIRECT_DATA = *mut SIP_INDIRECT_DATA; +extern "system" { + pub fn CryptSIPGetSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pdwEncodingType: *mut DWORD, + dwIndex: DWORD, + pcbSignedDataMsg: *mut DWORD, + pbSignedDataMsg: *mut BYTE, + ) -> BOOL; +} +FN!{stdcall pCryptSIPGetSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pdwEncodingType: *mut DWORD, + dwIndex: DWORD, + pcbSignedDataMsg: *mut DWORD, + pbSignedDataMsg: *mut BYTE, +) -> BOOL} +extern "system" { + pub fn CryptSIPPutSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + dwEncodingType: DWORD, + pdwIndex: *mut DWORD, + cbSignedDataMsg: DWORD, + pbSignedDataMsg: *mut BYTE, + ) -> BOOL; +} +FN!{stdcall pCryptSIPPutSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + dwEncodingType: DWORD, + pdwIndex: *mut DWORD, + cbSignedDataMsg: DWORD, + pbSignedDataMsg: *mut BYTE, +) -> BOOL} +extern "system" { + pub fn CryptSIPCreateIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pcbIndirectData: *mut DWORD, + pIndirectData: *mut SIP_INDIRECT_DATA, + ) -> BOOL; +} +FN!{stdcall pCryptSIPCreateIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pcbIndirectData: *mut DWORD, + pIndirectData: *mut SIP_INDIRECT_DATA, +) -> BOOL} +extern "system" { + pub fn CryptSIPVerifyIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pIndirectData: *mut SIP_INDIRECT_DATA, + ) -> BOOL; +} +FN!{stdcall pCryptSIPVerifyIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pIndirectData: *mut SIP_INDIRECT_DATA, +) -> BOOL} +extern "system" { + pub fn CryptSIPRemoveSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + dwIndex: DWORD, + ) -> BOOL; +} +FN!{stdcall pCryptSIPRemoveSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, + dwIndex: DWORD, +) -> BOOL} +STRUCT!{struct SIP_DISPATCH_INFO { + cbSize: DWORD, + hSIP: HANDLE, + pfGet: pCryptSIPGetSignedDataMsg, + pfPut: pCryptSIPPutSignedDataMsg, + pfCreate: pCryptSIPCreateIndirectData, + pfVerify: pCryptSIPVerifyIndirectData, + pfRemove: pCryptSIPRemoveSignedDataMsg, +}} +pub type LPSIP_DISPATCH_INFO = *mut SIP_DISPATCH_INFO; +FN!{stdcall pfnIsFileSupported( + hFile: HANDLE, + pgSubject: *mut GUID, +) -> BOOL} +FN!{stdcall pfnIsFileSupportedName( + pwszFileName: *mut WCHAR, + pgSubject: *mut GUID, +) -> BOOL} +STRUCT!{struct SIP_ADD_NEWPROVIDER { + cbStruct: DWORD, + pgSubject: *mut GUID, + pwszDLLFileName: *mut WCHAR, + pwszMagicNumber: *mut WCHAR, + pwszIsFunctionName: *mut WCHAR, + pwszGetFuncName: *mut WCHAR, + pwszPutFuncName: *mut WCHAR, + pwszCreateFuncName: *mut WCHAR, + pwszVerifyFuncName: *mut WCHAR, + pwszRemoveFuncName: *mut WCHAR, + pwszIsFunctionNameFmt2: *mut WCHAR, + pwszGetCapFuncName: PWSTR, +}} +pub type PSIP_ADD_NEWPROVIDER = *mut SIP_ADD_NEWPROVIDER; +pub const SIP_MAX_MAGIC_NUMBER: DWORD = 4; +extern "system" { + pub fn CryptSIPLoad( + pgSubject: *const GUID, + dwFlags: DWORD, + pSipDispatch: *mut SIP_DISPATCH_INFO, + ) -> BOOL; + pub fn CryptSIPRetrieveSubjectGuid( + FileName: LPCWSTR, + hFileIn: HANDLE, + pgSubject: *mut GUID, + ) -> BOOL; + pub fn CryptSIPRetrieveSubjectGuidForCatalogFile( + FileName: LPCWSTR, + hFileIn: HANDLE, + pgSubject: *mut GUID, + ) -> BOOL; + pub fn CryptSIPAddProvider( + psNewProv: *mut SIP_ADD_NEWPROVIDER, + ) -> BOOL; + pub fn CryptSIPRemoveProvider( + pgProv: *mut GUID, + ) -> BOOL; + pub fn CryptSIPGetCaps( + pSubjInfo: *mut SIP_SUBJECTINFO, + pCaps: *mut SIP_CAP_SET, + ) -> BOOL; +} +FN!{stdcall pCryptSIPGetCaps( + pSubjInfo: *mut SIP_SUBJECTINFO, + pCaps: *mut SIP_CAP_SET, +) -> BOOL} +extern "system" { + pub fn CryptSIPGetSealedDigest( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pSig: *const BYTE, + dwSig: DWORD, + pbDigest: *mut BYTE, + pcbDigest: *mut DWORD, + ) -> BOOL; +} +FN!{stdcall pCryptSIPGetSealedDigest( + pSubjectInfo: *mut SIP_SUBJECTINFO, + pSig: *const BYTE, + dwSig: DWORD, + pbDigest: *mut BYTE, + pcbDigest: *mut DWORD, +) -> BOOL} diff --git a/winapi/src/um/mswsock.rs b/winapi/src/um/mswsock.rs new file mode 100644 index 000000000..cbbe19135 --- /dev/null +++ b/winapi/src/um/mswsock.rs @@ -0,0 +1,413 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, c_int}; +use shared::minwindef::{BOOL, DWORD, INT, LPDWORD, LPINT, LPVOID, ULONG}; +use shared::mswsockdef::{PRIORESULT, PRIO_BUF, RIO_BUFFERID, RIO_CQ, RIO_RQ}; +use shared::ws2def::{IOC_VENDOR, IOC_WS2, LPWSAMSG, SOCKADDR}; +use um::minwinbase::LPOVERLAPPED; +use um::winnt::{CHAR, HANDLE, LARGE_INTEGER, PCHAR, PVOID, WCHAR}; +use um::winsock2::{ + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE, LPWSAPOLLFD, SOCKET, WSAESETSERVICEOP, + WSAPOLLFD, +}; +pub const SO_CONNDATA: c_int = 0x7000; +pub const SO_CONNOPT: c_int = 0x7001; +pub const SO_DISCDATA: c_int = 0x7002; +pub const SO_DISCOPT: c_int = 0x7003; +pub const SO_CONNDATALEN: c_int = 0x7004; +pub const SO_CONNOPTLEN: c_int = 0x7005; +pub const SO_DISCDATALEN: c_int = 0x7006; +pub const SO_DISCOPTLEN: c_int = 0x7007; +pub const SO_OPENTYPE: c_int = 0x7008; +pub const SO_SYNCHRONOUS_ALERT: DWORD = 0x10; +pub const SO_SYNCHRONOUS_NONALERT: DWORD = 0x20; +pub const SO_MAXDG: c_int = 0x7009; +pub const SO_MAXPATHDG: c_int = 0x700A; +pub const SO_UPDATE_ACCEPT_CONTEXT: c_int = 0x700B; +pub const SO_CONNECT_TIME: c_int = 0x700C; +pub const SO_UPDATE_CONNECT_CONTEXT: c_int = 0x7010; +pub const TCP_BSDURGENT: c_int = 0x7000; +pub const SIO_UDP_CONNRESET: DWORD = _WSAIOW!(IOC_VENDOR, 12); +pub const SIO_SOCKET_CLOSE_NOTIFY: DWORD = _WSAIOW!(IOC_VENDOR, 13); +pub const SIO_UDP_NETRESET: DWORD = _WSAIOW!(IOC_VENDOR, 15); +extern "system" { + pub fn WSARecvEx( + s: SOCKET, + buf: *mut c_char, + len: c_int, + flags: *mut c_int, + ) -> c_int; +} +STRUCT!{struct TRANSMIT_FILE_BUFFERS { + Head: LPVOID, + HeadLength: DWORD, + Tail: LPVOID, + TailLength: DWORD, +}} +pub type PTRANSMIT_FILE_BUFFERS = *mut TRANSMIT_FILE_BUFFERS; +pub type LPTRANSMIT_FILE_BUFFERS = *mut TRANSMIT_FILE_BUFFERS; +pub const TF_DISCONNECT: DWORD = 0x01; +pub const TF_REUSE_SOCKET: DWORD = 0x02; +pub const TF_WRITE_BEHIND: DWORD = 0x04; +pub const TF_USE_DEFAULT_WORKER: DWORD = 0x00; +pub const TF_USE_SYSTEM_THREAD: DWORD = 0x10; +pub const TF_USE_KERNEL_APC: DWORD = 0x20; +extern "system" { + pub fn TransmitFile( + hSocket: SOCKET, + hFile: HANDLE, + nNumberOfBytesToWrite: DWORD, + nNumberOfBytesPerSend: DWORD, + lpOverlapped: LPOVERLAPPED, + lpTransmitBuffers: LPTRANSMIT_FILE_BUFFERS, + dwReserved: DWORD, + ) -> BOOL; + pub fn AcceptEx( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + lpdwBytesReceived: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn GetAcceptExSockaddrs( + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + LocalSockaddr: *mut *mut SOCKADDR, + LocalSockaddrLength: LPINT, + RemoteSockaddr: *mut *mut SOCKADDR, + RemoteSockaddrLength: LPINT, + ); +} +FN!{stdcall LPFN_TRANSMITFILE( + hSocket: SOCKET, + hFile: HANDLE, + nNumberOfBytesToWrite: DWORD, + nNumberOfBytesPerSend: DWORD, + lpOverlapped: LPOVERLAPPED, + lpTransmitBuffers: LPTRANSMIT_FILE_BUFFERS, + dwReserved: DWORD, +) -> BOOL} +DEFINE_GUID!{WSAID_TRANSMITFILE, + 0xb5367df0, 0xcbac, 0x11cf, 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} +FN!{stdcall LPFN_ACCEPTEX( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + lpdwBytesReceived: LPDWORD, + lpOverlapped: LPOVERLAPPED, +) -> BOOL} +DEFINE_GUID!{WSAID_ACCEPTEX, + 0xb5367df1, 0xcbac, 0x11cf, 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} +FN!{stdcall LPFN_GETACCEPTEXSOCKADDRS( + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + LocalSockaddr: *mut *mut SOCKADDR, + LocalSockaddrLength: LPINT, + RemoteSockaddr: *mut *mut SOCKADDR, + RemoteSockaddrLength: LPINT, +) -> ()} +DEFINE_GUID!{WSAID_GETACCEPTEXSOCKADDRS, + 0xb5367df2, 0xcbac, 0x11cf, 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92} +pub const TP_ELEMENT_MEMORY: ULONG = 1; +pub const TP_ELEMENT_FILE: ULONG = 2; +pub const TP_ELEMENT_EOP: ULONG = 4; +STRUCT!{struct TRANSMIT_PACKETS_ELEMENT_u_s { + nFileOffset: LARGE_INTEGER, + hFile: HANDLE, +}} +UNION!{union TRANSMIT_PACKETS_ELEMENT_u { + [u64; 2], + s s_mut: TRANSMIT_PACKETS_ELEMENT_u_s, + pBuffer pBuffer_mut: PVOID, +}} +STRUCT!{struct TRANSMIT_PACKETS_ELEMENT { + dwElFlags: ULONG, + cLength: ULONG, + u: TRANSMIT_PACKETS_ELEMENT_u, +}} +pub type PTRANSMIT_PACKETS_ELEMENT = *mut TRANSMIT_PACKETS_ELEMENT; +pub type LPTRANSMIT_PACKETS_ELEMENT = *mut TRANSMIT_PACKETS_ELEMENT; +pub const TP_DISCONNECT: DWORD = TF_DISCONNECT; +pub const TP_REUSE_SOCKET: DWORD = TF_REUSE_SOCKET; +pub const TP_USE_DEFAULT_WORKER: DWORD = TF_USE_DEFAULT_WORKER; +pub const TP_USE_SYSTEM_THREAD: DWORD = TF_USE_SYSTEM_THREAD; +pub const TP_USE_KERNEL_APC: DWORD = TF_USE_KERNEL_APC; +FN!{stdcall LPFN_TRANSMITPACKETS( + hSocket: SOCKET, + lpPacketArray: LPTRANSMIT_PACKETS_ELEMENT, + nElementCount: DWORD, + nSendSize: DWORD, + lpOverlapped: LPOVERLAPPED, + dwFlags: DWORD, +) -> BOOL} +DEFINE_GUID!{WSAID_TRANSMITPACKETS, + 0xd9689da0, 0x1f90, 0x11d3, 0x99, 0x71, 0x00, 0xc0, 0x4f, 0x68, 0xc8, 0x76} +FN!{stdcall LPFN_CONNECTEX( + s: SOCKET, + name: *const SOCKADDR, + namelen: c_int, + lpSendBuffer: PVOID, + dwSendDataLength: DWORD, + lpdwBytesSent: LPDWORD, + lpOverlapped: LPOVERLAPPED, +) -> BOOL} +DEFINE_GUID!{WSAID_CONNECTEX, + 0x25a207b9, 0xddf3, 0x4660, 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e} +FN!{stdcall LPFN_DISCONNECTEX( + s: SOCKET, + lpOverlapped: LPOVERLAPPED, + dwFlags: DWORD, + dwReserved: DWORD, +) -> BOOL} +DEFINE_GUID!{WSAID_DISCONNECTEX, + 0x7fda2e11, 0x8630, 0x436f, 0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57} +pub const DE_REUSE_SOCKET: DWORD = TF_REUSE_SOCKET; +DEFINE_GUID!{NLA_NAMESPACE_GUID, + 0x6642243a, 0x3ba8, 0x4aa6, 0xba, 0xa5, 0x2e, 0xb, 0xd7, 0x1f, 0xdd, 0x83} +DEFINE_GUID!{NLA_SERVICE_CLASS_GUID, + 0x37e515, 0xb5c9, 0x4a43, 0xba, 0xda, 0x8b, 0x48, 0xa8, 0x7a, 0xd2, 0x39} +pub const NLA_ALLUSERS_NETWORK: WSAESETSERVICEOP = 0x00000001; +pub const NLA_FRIENDLY_NAME: WSAESETSERVICEOP = 0x00000002; +ENUM!{enum NLA_BLOB_DATA_TYPE { + NLA_RAW_DATA = 0, + NLA_INTERFACE = 1, + NLA_802_1X_LOCATION = 2, + NLA_CONNECTIVITY = 3, + NLA_ICS = 4, +}} +pub type PNLA_BLOB_DATA_TYPE = *mut NLA_BLOB_DATA_TYPE; +ENUM!{enum NLA_CONNECTIVITY_TYPE { + NLA_NETWORK_AD_HOC = 0, + NLA_NETWORK_MANAGED = 1, + NLA_NETWORK_UNMANAGED = 2, + NLA_NETWORK_UNKNOWN = 3, +}} +pub type PNLA_CONNECTIVITY_TYPE = *mut NLA_CONNECTIVITY_TYPE; +ENUM!{enum NLA_INTERNET { + NLA_INTERNET_UNKNOWN = 0, + NLA_INTERNET_NO = 1, + NLA_INTERNET_YES = 2, +}} +pub type PNLA_INTERNET = *mut NLA_INTERNET; +STRUCT!{struct NLA_BLOB_s { + type_: NLA_BLOB_DATA_TYPE, + dwSize: DWORD, + nextOffset: DWORD, +}} +STRUCT!{struct NLA_BLOB_u_s1 { + dwType: DWORD, + dwSpeed: DWORD, + adapterName: [CHAR; 1], +}} +STRUCT!{struct NLA_BLOB_u_s2 { + information: [CHAR; 1], +}} +STRUCT!{struct NLA_BLOB_u_s3 { + type_: NLA_CONNECTIVITY_TYPE, + internet: NLA_INTERNET, +}} +STRUCT!{struct NLA_BLOB_u_s4_s { + speed: DWORD, + type_: DWORD, + state: DWORD, + machineName: [WCHAR; 256], + sharedAdapterName: [WCHAR; 256], +}} +STRUCT!{struct NLA_BLOB_u_s4 { + remote: NLA_BLOB_u_s4_s, +}} +UNION!{union NLA_BLOB_u { + [u32; 259], + rawData rawData_mut: [CHAR; 1], + interfaceData interfaceData_mut: NLA_BLOB_u_s1, + locationData locationData_mut: NLA_BLOB_u_s2, + connectivity connectivity_mut: NLA_BLOB_u_s3, + ICS ICS_mut: NLA_BLOB_u_s4, +}} +STRUCT!{struct NLA_BLOB { + header: NLA_BLOB_s, + data: NLA_BLOB_u, +}} +pub type PNLA_BLOB = *mut NLA_BLOB; +pub type LPNLA_BLOB = *mut NLA_BLOB; +FN!{stdcall LPFN_WSARECVMSG( + s: SOCKET, + lpMsg: LPWSAMSG, + lpdwNumberOfBytesRecvd: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) -> INT} +DEFINE_GUID!{WSAID_WSARECVMSG, + 0xf689d7c8, 0x6f1f, 0x436b, 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22} +pub const SIO_BSP_HANDLE: DWORD = _WSAIOR!(IOC_WS2, 27); +pub const SIO_BSP_HANDLE_SELECT: DWORD = _WSAIOR!(IOC_WS2, 28); +pub const SIO_BSP_HANDLE_POLL: DWORD = _WSAIOR!(IOC_WS2, 29); +pub const SIO_BASE_HANDLE: DWORD = _WSAIOR!(IOC_WS2, 34); +pub const SIO_EXT_SELECT: DWORD = _WSAIORW!(IOC_WS2, 30); +pub const SIO_EXT_POLL: DWORD = _WSAIORW!(IOC_WS2, 31); +pub const SIO_EXT_SENDMSG: DWORD = _WSAIORW!(IOC_WS2, 32); +STRUCT!{struct WSAPOLLDATA { + result: c_int, + fds: ULONG, + timeout: INT, + fdArray: *mut WSAPOLLFD, +}} +pub type LPWSAPOLLDATA = *mut WSAPOLLDATA; +STRUCT!{struct WSASENDMSG { + lpMsg: LPWSAMSG, + dwFlags: DWORD, + lpNumberOfBytesSent: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, +}} +pub type LPWSASENDMSG = *mut WSASENDMSG; +FN!{stdcall LPFN_WSASENDMSG( + s: SOCKET, + lpMsg: LPWSAMSG, + dwFlags: DWORD, + lpNumberOfBytesSent: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, +) -> INT} +DEFINE_GUID!{WSAID_WSASENDMSG, + 0xa441e712, 0x754f, 0x43ca, 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d} +FN!{stdcall LPFN_WSAPOLL( + fdarray: LPWSAPOLLFD, + nfds: ULONG, + timeout: INT, +) -> INT} +DEFINE_GUID!{WSAID_WSAPOLL, + 0x18C76F85, 0xDC66, 0x4964, 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B} +FN!{stdcall LPFN_RIORECEIVE( + SocketQueue: RIO_RQ, + pData: PRIO_BUF, + DataBufferCount: ULONG, + Flags: DWORD, + RequestContext: PVOID, +) -> BOOL} +FN!{stdcall LPFN_RIORECEIVEEX( + SocketQueue: RIO_RQ, + pData: PRIO_BUF, + DataBufferCount: ULONG, + pLocalAddress: PRIO_BUF, + pRemoteAddress: PRIO_BUF, + pControlContext: PRIO_BUF, + pFlags: PRIO_BUF, + Flags: DWORD, + RequestContext: PVOID, +) -> c_int} +FN!{stdcall LPFN_RIOSEND( + SocketQueue: RIO_RQ, + pData: PRIO_BUF, + DataBufferCount: ULONG, + Flags: DWORD, + RequestContext: PVOID, +) -> BOOL} +FN!{stdcall LPFN_RIOSENDEX( + SocketQueue: RIO_RQ, + pData: PRIO_BUF, + DataBufferCount: ULONG, + pLocalAddress: PRIO_BUF, + pRemoteAddress: PRIO_BUF, + pControlContext: PRIO_BUF, + pFlags: PRIO_BUF, + Flags: DWORD, + RequestContext: PVOID, +) -> BOOL} +FN!{stdcall LPFN_RIOCLOSECOMPLETIONQUEUE( + CQ: RIO_CQ, +) -> ()} +ENUM!{enum RIO_NOTIFICATION_COMPLETION_TYPE { + RIO_EVENT_COMPLETION = 1, + RIO_IOCP_COMPLETION = 2, +}} +pub type PRIO_NOTIFICATION_COMPLETION_TYPE = *mut RIO_NOTIFICATION_COMPLETION_TYPE; +STRUCT!{struct RIO_NOTIFICATION_COMPLETION_u_s1 { + EventHandle: HANDLE, + NotifyReset: BOOL, +}} +STRUCT!{struct RIO_NOTIFICATION_COMPLETION_u_s2 { + IocpHandle: HANDLE, + CompletionKey: PVOID, + Overlapped: PVOID, +}} +UNION!{union RIO_NOTIFICATION_COMPLETION_u { + [u32; 3] [u64; 3], + Event Event_mut: RIO_NOTIFICATION_COMPLETION_u_s1, + Iocp Iocp_mut: RIO_NOTIFICATION_COMPLETION_u_s2, +}} +STRUCT!{struct RIO_NOTIFICATION_COMPLETION { + Type: RIO_NOTIFICATION_COMPLETION_TYPE, + u: RIO_NOTIFICATION_COMPLETION_u, +}} +pub type PRIO_NOTIFICATION_COMPLETION = *mut RIO_NOTIFICATION_COMPLETION; +FN!{stdcall LPFN_RIOCREATECOMPLETIONQUEUE( + QueueSize: DWORD, + NotificationCompletion: PRIO_NOTIFICATION_COMPLETION, +) -> RIO_CQ} +FN!{stdcall LPFN_RIOCREATEREQUESTQUEUE( + Socket: SOCKET, + MaxOutstandingReceive: ULONG, + MaxReceiveDataBuffers: ULONG, + MaxOutstandingSend: ULONG, + MaxSendDataBuffers: ULONG, + ReceiveCQ: RIO_CQ, + SendCQ: RIO_CQ, + SocketContext: PVOID, +) -> RIO_RQ} +FN!{stdcall LPFN_RIODEQUEUECOMPLETION( + CQ: RIO_CQ, + Array: PRIORESULT, + ArraySize: ULONG, +) -> ULONG} +FN!{stdcall LPFN_RIODEREGISTERBUFFER( + BufferId: RIO_BUFFERID, +) -> ()} +FN!{stdcall LPFN_RIONOTIFY( + CQ: RIO_CQ, +) -> INT} +FN!{stdcall LPFN_RIOREGISTERBUFFER( + DataBuffer: PCHAR, + DataLength: DWORD, +) -> RIO_BUFFERID} +FN!{stdcall LPFN_RIORESIZECOMPLETIONQUEUE( + CQ: RIO_CQ, + QueueSize: DWORD, +) -> BOOL} +FN!{stdcall LPFN_RIORESIZEREQUESTQUEUE( + RQ: RIO_RQ, + MaxOutstandingReceive: DWORD, + MaxOutstandingSend: DWORD, +) -> BOOL} +STRUCT!{struct RIO_EXTENSION_FUNCTION_TABLE { + cbSize: DWORD, + RIOReceive: LPFN_RIORECEIVE, + RIOReceiveEx: LPFN_RIORECEIVEEX, + RIOSend: LPFN_RIOSEND, + RIOSendEx: LPFN_RIOSENDEX, + RIOCloseCompletionQueue: LPFN_RIOCLOSECOMPLETIONQUEUE, + RIOCreateCompletionQueue: LPFN_RIOCREATECOMPLETIONQUEUE, + RIOCreateRequestQueue: LPFN_RIOCREATEREQUESTQUEUE, + RIODequeueCompletion: LPFN_RIODEQUEUECOMPLETION, + RIODeregisterBuffer: LPFN_RIODEREGISTERBUFFER, + RIONotify: LPFN_RIONOTIFY, + RIORegisterBuffer: LPFN_RIOREGISTERBUFFER, + RIOResizeCompletionQueue: LPFN_RIORESIZECOMPLETIONQUEUE, + RIOResizeRequestQueue: LPFN_RIORESIZEREQUESTQUEUE, +}} +pub type PRIO_EXTENSION_FUNCTION_TABLE = *mut RIO_EXTENSION_FUNCTION_TABLE; +DEFINE_GUID!{WSAID_MULTIPLE_RIO, + 0x8509e081, 0x96dd, 0x4005, 0xb1, 0x65, 0x9e, 0x2e, 0xe8, 0xc7, 0x9e, 0x3f} diff --git a/winapi/src/um/namedpipeapi.rs b/winapi/src/um/namedpipeapi.rs new file mode 100644 index 000000000..7c7447f1e --- /dev/null +++ b/winapi/src/um/namedpipeapi.rs @@ -0,0 +1,93 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, ULONG}; +use um::minwinbase::{LPOVERLAPPED, LPSECURITY_ATTRIBUTES}; +use um::winnt::{HANDLE, LPCWSTR, LPWSTR, PHANDLE}; +extern "system" { + pub fn CreatePipe( + hReadPipe: PHANDLE, + hWritePipe: PHANDLE, + lpPipeAttributes: LPSECURITY_ATTRIBUTES, + nSize: DWORD, + ) -> BOOL; + pub fn ConnectNamedPipe( + hNamedPipe: HANDLE, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn DisconnectNamedPipe( + hNamedPipe: HANDLE, + ) -> BOOL; + pub fn SetNamedPipeHandleState( + hNamedPipe: HANDLE, + lpMode: LPDWORD, + lpMaxCollectionCount: LPDWORD, + lpCollectDataTimeout: LPDWORD, + ) -> BOOL; + pub fn PeekNamedPipe( + hNamedPipe: HANDLE, + lpBuffer: LPVOID, + nBufferSize: DWORD, + lpBytesRead: LPDWORD, + lpTotalBytesAvail: LPDWORD, + lpBytesLeftThisMessage: LPDWORD, + ) -> BOOL; + pub fn TransactNamedPipe( + hNamedPipe: HANDLE, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesRead: LPDWORD, + lpOverlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn CreateNamedPipeW( + lpName: LPCWSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE; + pub fn WaitNamedPipeW( + lpNamedPipeName: LPCWSTR, + nTimeOut: DWORD, + ) -> BOOL; + pub fn GetNamedPipeClientComputerNameW( + Pipe: HANDLE, + ClientComputerName: LPWSTR, + ClientComputerNameLength: ULONG, + ) -> BOOL; + pub fn ImpersonateNamedPipeClient( + hNamedPipe: HANDLE, + ) -> BOOL; + pub fn GetNamedPipeInfo( + hNamedPipe: HANDLE, + lpFlags: LPDWORD, + lpOutBufferSize: LPDWORD, + lpInBufferSize: LPDWORD, + lpMaxInstances: LPDWORD, + ) -> BOOL; + pub fn GetNamedPipeHandleStateW( + hNamedPipe: HANDLE, + lpState: LPDWORD, + lpCurInstances: LPDWORD, + lpMaxCollectionCount: LPDWORD, + lpCollectDataTimeout: LPDWORD, + lpUserName: LPWSTR, + nMaxUserNameSize: DWORD, + ) -> BOOL; + pub fn CallNamedPipeW( + lpNamedPipeName: LPCWSTR, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesRead: LPDWORD, + nTimeOut: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/namespaceapi.rs b/winapi/src/um/namespaceapi.rs new file mode 100644 index 000000000..cfdb80572 --- /dev/null +++ b/winapi/src/um/namespaceapi.rs @@ -0,0 +1,36 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +use shared::minwindef::{BOOL, LPVOID, ULONG}; +use shared::ntdef::{BOOLEAN, HANDLE, LPCWSTR}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::winnt::PSID; +pub const PRIVATE_NAMESPACE_FLAG_DESTROY: ULONG = 0x00000001; +extern "system" { + pub fn CreatePrivateNamespaceW( + lpPrivateNamespaceAttributes: LPSECURITY_ATTRIBUTES, + lpBoundaryDescriptor: LPVOID, + lpAliasPrefix: LPCWSTR, + ) -> HANDLE; + pub fn OpenPrivateNamespaceW( + lpBoundaryDescriptor: LPVOID, + lpAliasPrefix: LPCWSTR, + ) -> HANDLE; + pub fn ClosePrivateNamespace( + Handle: HANDLE, + Flags: ULONG, + ) -> BOOLEAN; + pub fn CreateBoundaryDescriptorW( + Name: LPCWSTR, + Flags: ULONG, + ) -> HANDLE; + pub fn AddSIDToBoundaryDescriptor( + BoundaryDescriptor: *mut HANDLE, + RequiredSid: PSID, + ) -> BOOL; + pub fn DeleteBoundaryDescriptor( + BoundaryDescriptor: HANDLE, + ) -> (); +} diff --git a/winapi/src/um/nb30.rs b/winapi/src/um/nb30.rs new file mode 100644 index 000000000..81dfddfb7 --- /dev/null +++ b/winapi/src/um/nb30.rs @@ -0,0 +1,214 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module contains the definitions for portable NetBIOS 3.0 support. +use shared::minwindef::{DWORD, PUCHAR, UCHAR, ULONG, USHORT, WORD}; +use um::winnt::HANDLE; +pub const NCBNAMSZ: usize = 16; +pub const MAX_LANA: usize = 254; +FN!{stdcall PFPOST( + *mut NCB, +) -> ()} +#[cfg(target_pointer_width = "64")] +STRUCT!{struct NCB { + ncb_command: UCHAR, + ncb_retcode: UCHAR, + ncb_lsn: UCHAR, + ncb_num: UCHAR, + ncb_buffer: PUCHAR, + ncb_length: WORD, + ncb_callname: [UCHAR; NCBNAMSZ], + ncb_name: [UCHAR; NCBNAMSZ], + ncb_rto: UCHAR, + ncb_sto: UCHAR, + ncb_post: PFPOST, + ncb_lana_num: UCHAR, + ncb_cmd_cplt: UCHAR, + ncb_reserve: [UCHAR; 18], + ncb_event: HANDLE, +}} +#[cfg(target_arch = "x86")] +STRUCT!{struct NCB { + ncb_command: UCHAR, + ncb_retcode: UCHAR, + ncb_lsn: UCHAR, + ncb_num: UCHAR, + ncb_buffer: PUCHAR, + ncb_length: WORD, + ncb_callname: [UCHAR; NCBNAMSZ], + ncb_name: [UCHAR; NCBNAMSZ], + ncb_rto: UCHAR, + ncb_sto: UCHAR, + ncb_post: PFPOST, + ncb_lana_num: UCHAR, + ncb_cmd_cplt: UCHAR, + ncb_reserve: [UCHAR; 10], + ncb_event: HANDLE, +}} +pub type PNCB = *mut NCB; +STRUCT!{struct ADAPTER_STATUS { + adapter_address: [UCHAR; 6], + rev_major: UCHAR, + reserved0: UCHAR, + adapter_type: UCHAR, + rev_minor: UCHAR, + duration: WORD, + frmr_recv: WORD, + frmr_xmit: WORD, + iframe_recv_err: WORD, + xmit_aborts: WORD, + xmit_success: DWORD, + recv_success: DWORD, + iframe_xmit_err: WORD, + recv_buff_unavail: WORD, + t1_timeouts: WORD, + ti_timeouts: WORD, + reserved1: DWORD, + free_ncbs: WORD, + max_cfg_ncbs: WORD, + max_ncbs: WORD, + xmit_buf_unavail: WORD, + max_dgram_size: WORD, + pending_sess: WORD, + max_cfg_sess: WORD, + max_sess: WORD, + max_sess_pkt_size: WORD, + name_count: WORD, +}} +pub type PADAPTER_STATUS = *mut ADAPTER_STATUS; +STRUCT!{struct NAME_BUFFER { + name: [UCHAR; NCBNAMSZ], + name_num: UCHAR, + name_flags: UCHAR, +}} +pub type PNAME_BUFFER = *mut NAME_BUFFER; +pub const NAME_FLAGS_MASK: UCHAR = 0x87; +pub const GROUP_NAME: UCHAR = 0x80; +pub const UNIQUE_NAME: UCHAR = 0x00; +pub const REGISTERING: UCHAR = 0x00; +pub const REGISTERED: UCHAR = 0x04; +pub const DEREGISTERED: UCHAR = 0x05; +pub const DUPLICATE: UCHAR = 0x06; +pub const DUPLICATE_DEREG: UCHAR = 0x07; +STRUCT!{struct SESSION_HEADER { + sess_name: UCHAR, + num_sess: UCHAR, + rcv_dg_outstanding: UCHAR, + rcv_any_outstanding: UCHAR, +}} +pub type PSESSION_HEADER = *mut SESSION_HEADER; +STRUCT!{struct SESSION_BUFFER { + lsn: UCHAR, + state: UCHAR, + local_name: [UCHAR; NCBNAMSZ], + remote_name: [UCHAR; NCBNAMSZ], + rcvs_outstanding: UCHAR, + sends_outstanding: UCHAR, +}} +pub type PSESSION_BUFFER = *mut SESSION_BUFFER; +pub const LISTEN_OUTSTANDING: UCHAR = 0x01; +pub const CALL_PENDING: UCHAR = 0x02; +pub const SESSION_ESTABLISHED: UCHAR = 0x03; +pub const HANGUP_PENDING: UCHAR = 0x04; +pub const HANGUP_COMPLETE: UCHAR = 0x05; +pub const SESSION_ABORTED: UCHAR = 0x06; +STRUCT!{struct LANA_ENUM { + length: UCHAR, + lana: [UCHAR; MAX_LANA + 1], +}} +pub type PLANA_ENUM = *mut LANA_ENUM; +STRUCT!{struct FIND_NAME_HEADER { + node_count: WORD, + reserved: UCHAR, + unique_group: UCHAR, +}} +pub type PFIND_NAME_HEADER = *mut FIND_NAME_HEADER; +STRUCT!{struct FIND_NAME_BUFFER { + length: UCHAR, + access_control: UCHAR, + frame_control: UCHAR, + destination_addr: [UCHAR; 6], + source_addr: [UCHAR; 6], + routing_info: [UCHAR; 18], +}} +pub type PFIND_NAME_BUFFER = *mut FIND_NAME_BUFFER; +STRUCT!{struct ACTION_HEADER { + transport_id: ULONG, + action_code: USHORT, + reserved: USHORT, +}} +pub type PACTION_HEADER = *mut ACTION_HEADER; +pub const ALL_TRANSPORTS: ULONG = 0x0000004d; +pub const MS_NBF: ULONG = 0x46424e4d; +pub const NCBCALL: UCHAR = 0x10; +pub const NCBLISTEN: UCHAR = 0x11; +pub const NCBHANGUP: UCHAR = 0x12; +pub const NCBSEND: UCHAR = 0x14; +pub const NCBRECV: UCHAR = 0x15; +pub const NCBRECVANY: UCHAR = 0x16; +pub const NCBCHAINSEND: UCHAR = 0x17; +pub const NCBDGSEND: UCHAR = 0x20; +pub const NCBDGRECV: UCHAR = 0x21; +pub const NCBDGSENDBC: UCHAR = 0x22; +pub const NCBADDNAME: UCHAR = 0x30; +pub const NCBDELNAME: UCHAR = 0x31; +pub const NCBRESET: UCHAR = 0x32; +pub const NCBASTAT: UCHAR = 0x33; +pub const NCBSSTAT: UCHAR = 0x34; +pub const NCBCANCEL: UCHAR = 0x35; +pub const NCBADDGRNAME: UCHAR = 0x36; +pub const NCBENUM: UCHAR = 0x37; +pub const NCBUNLINK: UCHAR = 0x70; +pub const NCBSENDNA: UCHAR = 0x71; +pub const NCBCHAINSENDNA: UCHAR = 0x72; +pub const NCBLANSTALERT: UCHAR = 0x73; +pub const NCBACTION: UCHAR = 0x77; +pub const NCBFINDNAME: UCHAR = 0x78; +pub const NCBTRACE: UCHAR = 0x79; +pub const ASYNCH: UCHAR = 0x80; +pub const NRC_GOODRET: UCHAR = 0x00; +pub const NRC_BUFLEN: UCHAR = 0x01; +pub const NRC_ILLCMD: UCHAR = 0x03; +pub const NRC_CMDTMO: UCHAR = 0x05; +pub const NRC_INCOMP: UCHAR = 0x06; +pub const NRC_BADDR: UCHAR = 0x07; +pub const NRC_SNUMOUT: UCHAR = 0x08; +pub const NRC_NORES: UCHAR = 0x09; +pub const NRC_SCLOSED: UCHAR = 0x0a; +pub const NRC_CMDCAN: UCHAR = 0x0b; +pub const NRC_DUPNAME: UCHAR = 0x0d; +pub const NRC_NAMTFUL: UCHAR = 0x0e; +pub const NRC_ACTSES: UCHAR = 0x0f; +pub const NRC_LOCTFUL: UCHAR = 0x11; +pub const NRC_REMTFUL: UCHAR = 0x12; +pub const NRC_ILLNN: UCHAR = 0x13; +pub const NRC_NOCALL: UCHAR = 0x14; +pub const NRC_NOWILD: UCHAR = 0x15; +pub const NRC_INUSE: UCHAR = 0x16; +pub const NRC_NAMERR: UCHAR = 0x17; +pub const NRC_SABORT: UCHAR = 0x18; +pub const NRC_NAMCONF: UCHAR = 0x19; +pub const NRC_IFBUSY: UCHAR = 0x21; +pub const NRC_TOOMANY: UCHAR = 0x22; +pub const NRC_BRIDGE: UCHAR = 0x23; +pub const NRC_CANOCCR: UCHAR = 0x24; +pub const NRC_CANCEL: UCHAR = 0x26; +pub const NRC_DUPENV: UCHAR = 0x30; +pub const NRC_ENVNOTDEF: UCHAR = 0x34; +pub const NRC_OSRESNOTAV: UCHAR = 0x35; +pub const NRC_MAXAPPS: UCHAR = 0x36; +pub const NRC_NOSAPS: UCHAR = 0x37; +pub const NRC_NORESOURCES: UCHAR = 0x38; +pub const NRC_INVADDRESS: UCHAR = 0x39; +pub const NRC_INVDDID: UCHAR = 0x3B; +pub const NRC_LOCKFAIL: UCHAR = 0x3C; +pub const NRC_OPENERR: UCHAR = 0x3f; +pub const NRC_SYSTEM: UCHAR = 0x40; +pub const NRC_PENDING: UCHAR = 0xff; +extern "system" { + pub fn Netbios( + pncb: PNCB, + ) -> UCHAR; +} diff --git a/winapi/src/um/ncrypt.rs b/winapi/src/um/ncrypt.rs new file mode 100644 index 000000000..5f5431e21 --- /dev/null +++ b/winapi/src/um/ncrypt.rs @@ -0,0 +1,88 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{SIZE_T, ULONG_PTR}; +use shared::bcrypt::{BCRYPT_NO_KEY_VALIDATION, BCryptBufferDesc}; +use shared::minwindef::{DWORD, LPVOID, PBYTE}; +use um::winnt::{LONG, LPCWSTR, VOID}; +pub type SECURITY_STATUS = LONG; +pub type HCRYPTPROV = ULONG_PTR; +pub type HCRYPTKEY = ULONG_PTR; +pub type HCRYPTHASH = ULONG_PTR; +FN!{stdcall PFN_NCRYPT_ALLOC( + cbSize: SIZE_T, +) -> LPVOID} +FN!{stdcall PFN_NCRYPT_FREE( + pv: LPVOID, +) -> VOID} +STRUCT!{struct NCRYPT_ALLOC_PARA { + cbSize: DWORD, + pfnAlloc: PFN_NCRYPT_ALLOC, + pfnFree: PFN_NCRYPT_FREE, +}} +pub type NCryptBufferDesc = BCryptBufferDesc; +pub type NCRYPT_HANDLE = ULONG_PTR; +pub type NCRYPT_PROV_HANDLE = ULONG_PTR; +pub type NCRYPT_KEY_HANDLE = ULONG_PTR; +pub type NCRYPT_HASH_HANDLE = ULONG_PTR; +pub type NCRYPT_SECRET_HANDLE = ULONG_PTR; +pub const NCRYPT_NO_PADDING_FLAG: DWORD = 0x00000001; +pub const NCRYPT_PAD_PKCS1_FLAG: DWORD = 0x00000002; +pub const NCRYPT_PAD_OAEP_FLAG: DWORD = 0x00000004; +pub const NCRYPT_PAD_PSS_FLAG: DWORD = 0x00000008; +pub const NCRYPT_PAD_CIPHER_FLAG: DWORD = 0x00000010; +pub const NCRYPT_ATTESTATION_FLAG: DWORD = 0x00000020; +pub const NCRYPT_SEALING_FLAG: DWORD = 0x00000100; +pub const NCRYPT_REGISTER_NOTIFY_FLAG: DWORD = 0x00000001; +pub const NCRYPT_UNREGISTER_NOTIFY_FLAG: DWORD = 0x00000002; +pub const NCRYPT_NO_KEY_VALIDATION: DWORD = BCRYPT_NO_KEY_VALIDATION; +pub const NCRYPT_MACHINE_KEY_FLAG: DWORD = 0x00000020; +pub const NCRYPT_SILENT_FLAG: DWORD = 0x00000040; +pub const NCRYPT_OVERWRITE_KEY_FLAG: DWORD = 0x00000080; +pub const NCRYPT_WRITE_KEY_TO_LEGACY_STORE_FLAG: DWORD = 0x00000200; +pub const NCRYPT_DO_NOT_FINALIZE_FLAG: DWORD = 0x00000400; +pub const NCRYPT_EXPORT_LEGACY_FLAG: DWORD = 0x00000800; +pub const NCRYPT_IGNORE_DEVICE_STATE_FLAG: DWORD = 0x00001000; +pub const NCRYPT_TREAT_NIST_AS_GENERIC_ECC_FLAG: DWORD = 0x00002000; +pub const NCRYPT_NO_CACHED_PASSWORD: DWORD = 0x00004000; +pub const NCRYPT_PROTECT_TO_LOCAL_SYSTEM: DWORD = 0x00008000; +pub const NCRYPT_PERSIST_ONLY_FLAG: DWORD = 0x40000000; +pub const NCRYPT_PERSIST_FLAG: DWORD = 0x80000000; +pub const NCRYPT_PREFER_VIRTUAL_ISOLATION_FLAG: DWORD = 0x00010000; +pub const NCRYPT_USE_VIRTUAL_ISOLATION_FLAG: DWORD = 0x00020000; +pub const NCRYPT_USE_PER_BOOT_KEY_FLAG: DWORD = 0x00040000; +extern "system" { + pub fn NCryptOpenStorageProvider( + phProvider: *mut NCRYPT_PROV_HANDLE, + pszProviderName: LPCWSTR, + dwFlags: DWORD, + ) -> SECURITY_STATUS; +} +pub const NCRYPT_ALLOW_EXPORT_FLAG: DWORD = 0x00000001; +pub const NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG: DWORD = 0x00000002; +pub const NCRYPT_ALLOW_ARCHIVING_FLAG: DWORD = 0x00000004; +pub const NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG: DWORD = 0x00000008; +extern "system" { + pub fn NCryptSetProperty( + hObject: NCRYPT_HANDLE, + pszProperty: LPCWSTR, + pbInput: PBYTE, + cbInput: DWORD, + dwFlags: DWORD, + ) -> SECURITY_STATUS; + pub fn NCryptImportKey( + hProvider: NCRYPT_PROV_HANDLE, + hImportKey: NCRYPT_KEY_HANDLE, + pszBlobType: LPCWSTR, + pParameterList: *const NCryptBufferDesc, + phKey: *mut NCRYPT_KEY_HANDLE, + pbData: PBYTE, + cbData: DWORD, + dwFlags: DWORD, + ) -> SECURITY_STATUS; + pub fn NCryptFreeObject( + hObject: NCRYPT_HANDLE, + ) -> SECURITY_STATUS; +} diff --git a/winapi/src/um/ntlsa.rs b/winapi/src/um/ntlsa.rs new file mode 100644 index 000000000..901c0acf1 --- /dev/null +++ b/winapi/src/um/ntlsa.rs @@ -0,0 +1,1530 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{SIZE_T, ULONG_PTR}; +use shared::guiddef::GUID; +use shared::minwindef::{PUCHAR, PULONG, UCHAR, ULONG, USHORT}; +use shared::ntdef::{NTSTATUS, PNTSTATUS}; +use um::lsalookup::{ + LSA_TRUST_INFORMATION, LSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, + PLSA_REFERENCED_DOMAIN_LIST, PLSA_STRING, PLSA_TRANSLATED_NAME, PLSA_TRANSLATED_SID2, + PLSA_TRUST_INFORMATION, PLSA_UNICODE_STRING, +}; +use um::ntsecapi::PLSA_HANDLE; +use um::subauth::{PUNICODE_STRING, UNICODE_STRING}; +use um::winnt::{ + ACCESS_MASK, ANYSIZE_ARRAY, BOOLEAN, HANDLE, LARGE_INTEGER, LONG, LUID, PBOOLEAN, + PCLAIMS_BLOB, PHANDLE, PLARGE_INTEGER, PLUID, PPRIVILEGE_SET, PQUOTA_LIMITS, + PSECURITY_DESCRIPTOR, PSHORT, PSID, PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_SOURCE, PVOID, + PWSTR, QUOTA_LIMITS, SECURITY_INFORMATION, SID_NAME_USE, STANDARD_RIGHTS_EXECUTE, + STANDARD_RIGHTS_READ, STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_WRITE, TOKEN_DEFAULT_DACL, + TOKEN_DEVICE_CLAIMS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_USER, TOKEN_USER_CLAIMS, +}; +pub type LSA_OPERATIONAL_MODE = ULONG; +pub type PLSA_OPERATIONAL_MODE = *mut LSA_OPERATIONAL_MODE; +pub const LSA_MODE_PASSWORD_PROTECTED: ULONG = 0x00000001; +pub const LSA_MODE_INDIVIDUAL_ACCOUNTS: ULONG = 0x00000002; +pub const LSA_MODE_MANDATORY_ACCESS: ULONG = 0x00000004; +pub const LSA_MODE_LOG_FULL: ULONG = 0x00000008; +pub const LSA_MAXIMUM_SID_COUNT: SIZE_T = 0x00000100; +pub const LSA_MAXIMUM_ENUMERATION_LENGTH: SIZE_T = 32000; +pub const LSA_CALL_LICENSE_SERVER: ULONG = 0x80000000; +ENUM!{enum SECURITY_LOGON_TYPE { + UndefinedLogonType = 0, + Interactive = 2, + Network, + Batch, + Service, + Proxy, + Unlock, + NetworkCleartext, + NewCredentials, + RemoteInteractive, + CachedInteractive, + CachedRemoteInteractive, + CachedUnlock, +}} +pub type PSECURITY_LOGON_TYPE = *mut SECURITY_LOGON_TYPE; +pub const SECURITY_ACCESS_INTERACTIVE_LOGON: ULONG = 0x00000001; +pub const SECURITY_ACCESS_NETWORK_LOGON: ULONG = 0x00000002; +pub const SECURITY_ACCESS_BATCH_LOGON: ULONG = 0x00000004; +pub const SECURITY_ACCESS_SERVICE_LOGON: ULONG = 0x00000010; +pub const SECURITY_ACCESS_PROXY_LOGON: ULONG = 0x00000020; +pub const SECURITY_ACCESS_DENY_INTERACTIVE_LOGON: ULONG = 0x00000040; +pub const SECURITY_ACCESS_DENY_NETWORK_LOGON: ULONG = 0x00000080; +pub const SECURITY_ACCESS_DENY_BATCH_LOGON: ULONG = 0x00000100; +pub const SECURITY_ACCESS_DENY_SERVICE_LOGON: ULONG = 0x00000200; +pub const SECURITY_ACCESS_REMOTE_INTERACTIVE_LOGON: ULONG = 0x00000400; +pub const SECURITY_ACCESS_DENY_REMOTE_INTERACTIVE_LOGON: ULONG = 0x00000800; +ENUM!{enum SE_ADT_PARAMETER_TYPE { + SeAdtParmTypeNone = 0, + SeAdtParmTypeString, + SeAdtParmTypeFileSpec, + SeAdtParmTypeUlong, + SeAdtParmTypeSid, + SeAdtParmTypeLogonId, + SeAdtParmTypeNoLogonId, + SeAdtParmTypeAccessMask, + SeAdtParmTypePrivs, + SeAdtParmTypeObjectTypes, + SeAdtParmTypeHexUlong, + SeAdtParmTypePtr, + SeAdtParmTypeTime, + SeAdtParmTypeGuid, + SeAdtParmTypeLuid, + SeAdtParmTypeHexInt64, + SeAdtParmTypeStringList, + SeAdtParmTypeSidList, + SeAdtParmTypeDuration, + SeAdtParmTypeUserAccountControl, + SeAdtParmTypeNoUac, + SeAdtParmTypeMessage, + SeAdtParmTypeDateTime, + SeAdtParmTypeSockAddr, + SeAdtParmTypeSD, + SeAdtParmTypeLogonHours, + SeAdtParmTypeLogonIdNoSid, + SeAdtParmTypeUlongNoConv, + SeAdtParmTypeSockAddrNoPort, + SeAdtParmTypeAccessReason, + SeAdtParmTypeStagingReason, + SeAdtParmTypeResourceAttribute, + SeAdtParmTypeClaims, + SeAdtParmTypeLogonIdAsSid, + SeAdtParmTypeMultiSzString, + SeAdtParmTypeLogonIdEx, +}} +pub type PSE_ADT_PARAMETER_TYPE = *mut SE_ADT_PARAMETER_TYPE; +pub const SE_ADT_OBJECT_ONLY: USHORT = 0x1; +STRUCT!{struct SE_ADT_OBJECT_TYPE { + ObjectType: GUID, + Flags: USHORT, + Level: USHORT, + AccessMask: ACCESS_MASK, +}} +pub type PSE_ADT_OBJECT_TYPE = *mut SE_ADT_OBJECT_TYPE; +STRUCT!{struct SE_ADT_PARAMETER_ARRAY_ENTRY { + Type: SE_ADT_PARAMETER_TYPE, + Length: ULONG, + Data: [ULONG_PTR; 2], + Address: PVOID, +}} +pub type PSE_ADT_PARAMETER_ARRAY_ENTRY = *mut SE_ADT_PARAMETER_ARRAY_ENTRY; +STRUCT!{struct SE_ADT_ACCESS_REASON { + AccessMask: ACCESS_MASK, + AccessReasons: [ULONG; 32], + ObjectTypeIndex: ULONG, + AccessGranted: ULONG, + SecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PSE_ADT_ACCESS_REASON = *mut SE_ADT_ACCESS_REASON; +STRUCT!{struct SE_ADT_CLAIMS { + Length: ULONG, + Claims: PCLAIMS_BLOB, +}} +pub type PSE_ADT_CLAIMS = *mut SE_ADT_CLAIMS; +pub const SE_MAX_AUDIT_PARAMETERS: SIZE_T = 32; +pub const SE_MAX_GENERIC_AUDIT_PARAMETERS: SIZE_T = 28; +STRUCT!{struct SE_ADT_PARAMETER_ARRAY { + CategoryId: ULONG, + AuditId: ULONG, + ParameterCount: ULONG, + Length: ULONG, + FlatSubCategoryId: USHORT, + Type: USHORT, + Flags: ULONG, + Parameters: [SE_ADT_PARAMETER_ARRAY_ENTRY; SE_MAX_AUDIT_PARAMETERS], +}} +pub type PSE_ADT_PARAMETER_ARRAY = *mut SE_ADT_PARAMETER_ARRAY; +STRUCT!{struct SE_ADT_PARAMETER_ARRAY_EX { + CategoryId: ULONG, + AuditId: ULONG, + Version: ULONG, + ParameterCount: ULONG, + Length: ULONG, + FlatSubCategoryId: USHORT, + Type: USHORT, + Flags: ULONG, + Parameters: [SE_ADT_PARAMETER_ARRAY_ENTRY; SE_MAX_AUDIT_PARAMETERS], +}} +pub type PSE_ADT_PARAMETER_ARRAY_EX = *mut SE_ADT_PARAMETER_ARRAY_EX; +pub const SE_ADT_PARAMETERS_SELF_RELATIVE: ULONG = 0x00000001; +pub const SE_ADT_PARAMETERS_SEND_TO_LSA: ULONG = 0x00000002; +pub const SE_ADT_PARAMETER_EXTENSIBLE_AUDIT: ULONG = 0x00000004; +pub const SE_ADT_PARAMETER_GENERIC_AUDIT: ULONG = 0x00000008; +pub const SE_ADT_PARAMETER_WRITE_SYNCHRONOUS: ULONG = 0x00000010; +#[cfg(target_arch = "x86")] +#[inline] +pub fn LSAP_SE_ADT_PARAMETER_ARRAY_TRUE_SIZE( + AuditParameters: SE_ADT_PARAMETER_ARRAY, +) -> SIZE_T { + 664 // FIXME: sizeof::<SE_ADT_PARAMETER_ARRAY>() + - (20 // FIXME: sizeof::<SE_ADT_PARAMETER_ARRAY_ENTRY>() + * (SE_MAX_AUDIT_PARAMETERS - AuditParameters.ParameterCount as SIZE_T)) +} +#[cfg(target_arch = "x86_64")] +#[inline] +pub fn LSAP_SE_ADT_PARAMETER_ARRAY_TRUE_SIZE( + AuditParameters: SE_ADT_PARAMETER_ARRAY, +) -> SIZE_T { + 1048 // FIXME: sizeof::<SE_ADT_PARAMETER_ARRAY>() + - (32 // FIXME: sizeof::<SE_ADT_PARAMETER_ARRAY_ENTRY>() + * (SE_MAX_AUDIT_PARAMETERS - AuditParameters.ParameterCount as SIZE_T)) +} +STRUCT!{struct LSA_ADT_STRING_LIST_ENTRY { + Flags: ULONG, + String: UNICODE_STRING, +}} +pub type PLSA_ADT_STRING_LIST_ENTRY = *mut LSA_ADT_STRING_LIST_ENTRY; +STRUCT!{struct LSA_ADT_STRING_LIST { + cStrings: ULONG, + String: PLSA_ADT_STRING_LIST_ENTRY, +}} +pub type PLSA_ADT_STRING_LIST = *mut LSA_ADT_STRING_LIST; +STRUCT!{struct LSA_ADT_SID_LIST_ENTRY { + Flags: ULONG, + Sid: PSID, +}} +pub type PLSA_ADT_SID_LIST_ENTRY = *mut LSA_ADT_SID_LIST_ENTRY; +STRUCT!{struct LSA_ADT_SID_LIST { + cSids: ULONG, + Sid: PLSA_ADT_SID_LIST_ENTRY, +}} +pub type PLSA_ADT_SID_LIST = *mut LSA_ADT_SID_LIST; +pub const LSA_ADT_SECURITY_SOURCE_NAME: &'static str = "Microsoft-Windows-Security-Auditing"; +pub const LSA_ADT_LEGACY_SECURITY_SOURCE_NAME: &'static str = "Security"; +pub const SE_ADT_POLICY_AUDIT_EVENT_TYPE_EX_BEGIN: ULONG = 100; +ENUM!{enum POLICY_AUDIT_EVENT_TYPE_EX { + iSystem_SecurityStateChange = SE_ADT_POLICY_AUDIT_EVENT_TYPE_EX_BEGIN, + iSystem_SecuritySubsystemExtension, + iSystem_Integrity, + iSystem_IPSecDriverEvents, + iSystem_Others, + iLogon_Logon, + iLogon_Logoff, + iLogon_AccountLockout, + iLogon_IPSecMainMode, + iLogon_SpecialLogon, + iLogon_IPSecQuickMode, + iLogon_IPSecUsermode, + iLogon_Others, + iLogon_NPS, + iLogon_Claims, + iLogon_Groups, + iObjectAccess_FileSystem, + iObjectAccess_Registry, + iObjectAccess_Kernel, + iObjectAccess_Sam, + iObjectAccess_Other, + iObjectAccess_CertificationAuthority, + iObjectAccess_ApplicationGenerated, + iObjectAccess_HandleBasedAudits, + iObjectAccess_Share, + iObjectAccess_FirewallPacketDrops, + iObjectAccess_FirewallConnection, + iObjectAccess_DetailedFileShare, + iObjectAccess_RemovableStorage, + iObjectAccess_CbacStaging, + iPrivilegeUse_Sensitive, + iPrivilegeUse_NonSensitive, + iPrivilegeUse_Others, + iDetailedTracking_ProcessCreation, + iDetailedTracking_ProcessTermination, + iDetailedTracking_DpapiActivity, + iDetailedTracking_RpcCall, + iDetailedTracking_PnpActivity, + iDetailedTracking_TokenRightAdjusted, + iPolicyChange_AuditPolicy, + iPolicyChange_AuthenticationPolicy, + iPolicyChange_AuthorizationPolicy, + iPolicyChange_MpsscvRulePolicy, + iPolicyChange_WfpIPSecPolicy, + iPolicyChange_Others, + iAccountManagement_UserAccount, + iAccountManagement_ComputerAccount, + iAccountManagement_SecurityGroup, + iAccountManagement_DistributionGroup, + iAccountManagement_ApplicationGroup, + iAccountManagement_Others, + iDSAccess_DSAccess, + iDSAccess_AdAuditChanges, + iDS_Replication, + iDS_DetailedReplication, + iAccountLogon_CredentialValidation, + iAccountLogon_Kerberos, + iAccountLogon_Others, + iAccountLogon_KerbCredentialValidation, + iUnknownSubCategory = 999, +}} +pub type PPOLICY_AUDIT_EVENT_TYPE_EX = *mut POLICY_AUDIT_EVENT_TYPE_EX; +ENUM!{enum POLICY_AUDIT_EVENT_TYPE { + AuditCategorySystem = 0, + AuditCategoryLogon, + AuditCategoryObjectAccess, + AuditCategoryPrivilegeUse, + AuditCategoryDetailedTracking, + AuditCategoryPolicyChange, + AuditCategoryAccountManagement, + AuditCategoryDirectoryServiceAccess, + AuditCategoryAccountLogon, +}} +pub type PPOLICY_AUDIT_EVENT_TYPE = *mut POLICY_AUDIT_EVENT_TYPE; +pub const POLICY_AUDIT_EVENT_UNCHANGED: ULONG = 0x00000000; +pub const POLICY_AUDIT_EVENT_SUCCESS: ULONG = 0x00000001; +pub const POLICY_AUDIT_EVENT_FAILURE: ULONG = 0x00000002; +pub const POLICY_AUDIT_EVENT_NONE: ULONG = 0x00000004; +pub const POLICY_AUDIT_EVENT_MASK: ULONG = POLICY_AUDIT_EVENT_SUCCESS | POLICY_AUDIT_EVENT_FAILURE + | POLICY_AUDIT_EVENT_UNCHANGED | POLICY_AUDIT_EVENT_NONE; +#[inline] +pub fn LSA_SUCCESS(Error: NTSTATUS) -> bool { + (Error as LONG) >= 0 +} +extern "system" { + pub fn LsaRegisterLogonProcess( + LogonProcessName: PLSA_STRING, + LsaHandle: PHANDLE, + SecurityMode: PLSA_OPERATIONAL_MODE, + ) -> NTSTATUS; + pub fn LsaLogonUser( + LsaHandle: HANDLE, + OriginName: PLSA_STRING, + LogonType: SECURITY_LOGON_TYPE, + AuthenticationPackage: ULONG, + AuthenticationInformation: PVOID, + AuthenticationInformationLength: ULONG, + LocalGroups: PTOKEN_GROUPS, + SourceContext: PTOKEN_SOURCE, + ProfileBuffer: *mut PVOID, + ProfileBufferLength: PULONG, + LogonId: PLUID, + Token: PHANDLE, + Quotas: PQUOTA_LIMITS, + SubStatus: PNTSTATUS, + ) -> NTSTATUS; + pub fn LsaLookupAuthenticationPackage( + LsaHandle: HANDLE, + PackageName: PLSA_STRING, + AuthenticationPackage: PULONG, + ) -> NTSTATUS; + pub fn LsaFreeReturnBuffer( + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaCallAuthenticationPackage( + LsaHandle: HANDLE, + AuthenticationPackage: ULONG, + ProtocolSubmitBuffer: PVOID, + SubmitBufferLength: ULONG, + ProtocolReturnBuffer: *mut PVOID, + ReturnBufferLength: PULONG, + ProtocolStatus: PNTSTATUS, + ) -> NTSTATUS; + pub fn LsaDeregisterLogonProcess( + LsaHandle: HANDLE, + ) -> NTSTATUS; + pub fn LsaConnectUntrusted( + LsaHandle: PHANDLE, + ) -> NTSTATUS; +} +extern "C" { + pub fn LsaInsertProtectedProcessAddress( + BufferAddress: PVOID, + BufferSize: ULONG, + ) -> NTSTATUS; + pub fn LsaRemoveProtectedProcessAddress( + BufferAddress: PVOID, + BufferSize: ULONG, + ) -> NTSTATUS; +} +FN!{stdcall PFN_LSA_CALL_AUTH_PKG( + LsaHandle: HANDLE, + AuthenticationPackage: ULONG, + ProtocolSubmitBuffer: PVOID, + SubmitBufferLength: ULONG, + ProtocolReturnBuffer: *mut PVOID, + ReturnBufferLength: PULONG, + ProtocolStatus: PNTSTATUS, +) -> NTSTATUS} +FN!{stdcall PFN_LSA_DEREGISTER_PROC( + LsaHandle: HANDLE, +) -> NTSTATUS} +FN!{stdcall PFN_LSA_FREE_BUFFER( + Buffer: PVOID, +) -> NTSTATUS} +FN!{stdcall PFN_LSA_LOGON_USER( + LsaHandle: HANDLE, + OriginName: PLSA_STRING, + LogonType: SECURITY_LOGON_TYPE, + AuthenticationPackage: ULONG, + AuthenticationInformation: PVOID, + AuthenticationInformationLength: ULONG, + LocalGroups: PTOKEN_GROUPS, + SourceContext: PTOKEN_SOURCE, + ProfileBuffer: *mut PVOID, + ProfileBufferLength: PULONG, + LogonId: PLUID, + Token: PHANDLE, + Quotas: PQUOTA_LIMITS, + SubStatus: PNTSTATUS, +) -> NTSTATUS} +FN!{stdcall PFN_LOOKUP_AUTH_PKG( + LsaHandle: HANDLE, + PackageName: PLSA_STRING, + AuthenticationPackage: PULONG, +) -> NTSTATUS} +FN!{stdcall PFN_LSA_REGISTER_PROC( + LogonProcessName: PLSA_STRING, + LsaHandle: PHANDLE, + SecurityMode: PLSA_OPERATIONAL_MODE, +) -> NTSTATUS} +STRUCT!{struct LSA_AUTH_CALLBACKS { + LsaCallAuthPkgFn: PFN_LSA_CALL_AUTH_PKG, + LsaDeregisterProcFn: PFN_LSA_DEREGISTER_PROC, + LsaFreeReturnBufferFn: PFN_LSA_FREE_BUFFER, + LsaLogonUserFn: PFN_LSA_LOGON_USER, + LsaLookupAuthPkgFn: PFN_LOOKUP_AUTH_PKG, + LsaRegisterProcFn: PFN_LSA_REGISTER_PROC, +}} +pub type PLSA_AUTH_CALLBACKS = *mut LSA_AUTH_CALLBACKS; +pub type PCLSA_AUTH_CALLBACKS = *const LSA_AUTH_CALLBACKS; +pub type PLSA_CLIENT_REQUEST = *mut PVOID; +ENUM!{enum LSA_TOKEN_INFORMATION_TYPE { + LsaTokenInformationNull, + LsaTokenInformationV1, + LsaTokenInformationV2, + LsaTokenInformationV3, +}} +pub type PLSA_TOKEN_INFORMATION_TYPE = *mut LSA_TOKEN_INFORMATION_TYPE; +STRUCT!{struct LSA_TOKEN_INFORMATION_NULL { + ExpirationTime: LARGE_INTEGER, + Groups: PTOKEN_GROUPS, +}} +pub type PLSA_TOKEN_INFORMATION_NULL = *mut LSA_TOKEN_INFORMATION_NULL; +STRUCT!{struct LSA_TOKEN_INFORMATION_V1 { + ExpirationTime: LARGE_INTEGER, + User: TOKEN_USER, + Groups: PTOKEN_GROUPS, + PrimaryGroup: TOKEN_PRIMARY_GROUP, + Privileges: PTOKEN_PRIVILEGES, + Owner: TOKEN_OWNER, + DefaultDacl: TOKEN_DEFAULT_DACL, +}} +pub type PLSA_TOKEN_INFORMATION_V1 = *mut LSA_TOKEN_INFORMATION_V1; +pub type LSA_TOKEN_INFORMATION_V2 = LSA_TOKEN_INFORMATION_V1; +pub type PLSA_TOKEN_INFORMATION_V2 = *mut LSA_TOKEN_INFORMATION_V2; +STRUCT!{struct LSA_TOKEN_INFORMATION_V3 { + ExpirationTime: LARGE_INTEGER, + User: TOKEN_USER, + Groups: PTOKEN_GROUPS, + PrimaryGroup: TOKEN_PRIMARY_GROUP, + Privileges: PTOKEN_PRIVILEGES, + Owner: TOKEN_OWNER, + DefaultDacl: TOKEN_DEFAULT_DACL, + UserClaims: TOKEN_USER_CLAIMS, + DeviceClaims: TOKEN_DEVICE_CLAIMS, + DeviceGroups: PTOKEN_GROUPS, +}} +pub type PLSA_TOKEN_INFORMATION_V3 = *mut LSA_TOKEN_INFORMATION_V3; +FN!{stdcall PLSA_CREATE_LOGON_SESSION( + LogonId: PLUID, +) -> NTSTATUS} +FN!{stdcall PLSA_DELETE_LOGON_SESSION( + LogonId: PLUID, +) -> NTSTATUS} +FN!{stdcall PLSA_ADD_CREDENTIAL( + LogonId: PLUID, + AuthenticationPackage: ULONG, + PrimaryKeyValue: PLSA_STRING, + Credentials: PLSA_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_GET_CREDENTIALS( + LogonId: PLUID, + AuthenticationPackage: ULONG, + QueryContext: PULONG, + RetrieveAllCredentials: BOOLEAN, + PrimaryKeyValue: PLSA_STRING, + PrimaryKeyLength: PULONG, + Credentials: PLSA_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_DELETE_CREDENTIAL( + LogonId: PLUID, + AuthenticationPackage: ULONG, + PrimaryKeyValue: PLSA_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_ALLOCATE_LSA_HEAP( + Length: ULONG, +) -> PVOID} +FN!{stdcall PLSA_FREE_LSA_HEAP( + Base: PVOID, +) -> ()} +FN!{stdcall PLSA_ALLOCATE_PRIVATE_HEAP( + Length: SIZE_T, +) -> PVOID} +FN!{stdcall PLSA_FREE_PRIVATE_HEAP( + Base: PVOID, +) -> ()} +FN!{stdcall PLSA_ALLOCATE_CLIENT_BUFFER( + ClientRequest: PLSA_CLIENT_REQUEST, + LengthRequired: ULONG, + ClientBaseAddress: *mut PVOID, +) -> NTSTATUS} +FN!{stdcall PLSA_FREE_CLIENT_BUFFER( + ClientRequest: PLSA_CLIENT_REQUEST, + ClientBaseAddress: PVOID, +) -> NTSTATUS} +FN!{stdcall PLSA_COPY_TO_CLIENT_BUFFER( + ClientRequest: PLSA_CLIENT_REQUEST, + Length: ULONG, + ClientBaseAddress: PVOID, + BufferToCopy: PVOID, +) -> NTSTATUS} +FN!{stdcall PLSA_COPY_FROM_CLIENT_BUFFER( + ClientRequest: PLSA_CLIENT_REQUEST, + Length: ULONG, + BufferToCopy: PVOID, + ClientBaseAddress: PVOID, +) -> NTSTATUS} +STRUCT!{struct LSA_DISPATCH_TABLE { + CreateLogonSession: PLSA_CREATE_LOGON_SESSION, + DeleteLogonSession: PLSA_DELETE_LOGON_SESSION, + AddCredential: PLSA_ADD_CREDENTIAL, + GetCredentials: PLSA_GET_CREDENTIALS, + DeleteCredential: PLSA_DELETE_CREDENTIAL, + AllocateLsaHeap: PLSA_ALLOCATE_LSA_HEAP, + FreeLsaHeap: PLSA_FREE_LSA_HEAP, + AllocateClientBuffer: PLSA_ALLOCATE_CLIENT_BUFFER, + FreeClientBuffer: PLSA_FREE_CLIENT_BUFFER, + CopyToClientBuffer: PLSA_COPY_TO_CLIENT_BUFFER, + CopyFromClientBuffer: PLSA_COPY_FROM_CLIENT_BUFFER, +}} +pub type PLSA_DISPATCH_TABLE = *mut LSA_DISPATCH_TABLE; +pub const LSA_AP_NAME_INITIALIZE_PACKAGE: &'static str = "LsaApInitializePackage"; +pub const LSA_AP_NAME_LOGON_USER: &'static str = "LsaApLogonUser"; +pub const LSA_AP_NAME_LOGON_USER_EX: &'static str = "LsaApLogonUserEx"; +pub const LSA_AP_NAME_CALL_PACKAGE: &'static str = "LsaApCallPackage"; +pub const LSA_AP_NAME_LOGON_TERMINATED: &'static str = "LsaApLogonTerminated"; +pub const LSA_AP_NAME_CALL_PACKAGE_UNTRUSTED: &'static str = "LsaApCallPackageUntrusted"; +pub const LSA_AP_NAME_CALL_PACKAGE_PASSTHROUGH: &'static str = "LsaApCallPackagePassthrough"; +FN!{stdcall PLSA_AP_INITIALIZE_PACKAGE( + AuthenticationPackageId: ULONG, + LsaDispatchTable: PLSA_DISPATCH_TABLE, + Database: PLSA_STRING, + Confidentiality: PLSA_STRING, + AuthenticationPackageName: *mut PLSA_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_AP_LOGON_USER( + ClientRequest: PLSA_CLIENT_REQUEST, + LogonType: SECURITY_LOGON_TYPE, + AuthenticationInformation: PVOID, + ClientAuthentication: PVOID, + AuthenticationInformationLength: ULONG, + ProfileBuffer: *mut PVOID, + ProfileBufferLength: PULONG, + LogonId: PLUID, + SubStatus: PNTSTATUS, + TokenInformationType: PLSA_TOKEN_INFORMATION_TYPE, + TokenInformation: *mut PVOID, + AccountName: *mut PLSA_UNICODE_STRING, + AuthenticatingAutority: *mut PLSA_UNICODE_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_AP_LOGON_USER_EX( + ClientRequest: PLSA_CLIENT_REQUEST, + LogonType: SECURITY_LOGON_TYPE, + AuthenticationInformation: PVOID, + ClientAuthentication: PVOID, + AuthenticationInformationLength: ULONG, + ProfileBuffer: *mut PVOID, + ProfileBufferLength: PULONG, + LogonId: PLUID, + SubStatus: PNTSTATUS, + TokenInformationType: PLSA_TOKEN_INFORMATION_TYPE, + TokenInformation: *mut PVOID, + AccountName: *mut PLSA_UNICODE_STRING, + AuthenticatingAutority: *mut PLSA_UNICODE_STRING, + MachineName: *mut PUNICODE_STRING, +) -> NTSTATUS} +FN!{stdcall PLSA_AP_CALL_PACKAGE( + ClientRequest: PLSA_CLIENT_REQUEST, + ProtocolSubmitBuffer: PVOID, + ClientBufferBase: PVOID, + SubmitBufferLength: ULONG, + ProtocolReturnBuffer: *mut PVOID, + ReturnBufferLength: PULONG, + ProtocolStatus: PNTSTATUS, +) -> NTSTATUS} +FN!{stdcall PLSA_AP_CALL_PACKAGE_PASSTHROUGH( + ClientRequest: PLSA_CLIENT_REQUEST, + ProtocolSubmitBuffer: PVOID, + ClientBufferBase: PVOID, + SubmitBufferLength: ULONG, + ProtocolReturnBuffer: *mut PVOID, + ReturnBufferLength: PULONG, + ProtocolStatus: PNTSTATUS, +) -> NTSTATUS} +FN!{stdcall PLSA_AP_LOGON_TERMINATED( + LogonId: PLUID, +) -> ()} +pub const POLICY_VIEW_LOCAL_INFORMATION: ULONG = 0x00000001; +pub const POLICY_VIEW_AUDIT_INFORMATION: ULONG = 0x00000002; +pub const POLICY_GET_PRIVATE_INFORMATION: ULONG = 0x00000004; +pub const POLICY_TRUST_ADMIN: ULONG = 0x00000008; +pub const POLICY_CREATE_ACCOUNT: ULONG = 0x00000010; +pub const POLICY_CREATE_SECRET: ULONG = 0x00000020; +pub const POLICY_CREATE_PRIVILEGE: ULONG = 0x00000040; +pub const POLICY_SET_DEFAULT_QUOTA_LIMITS: ULONG = 0x00000080; +pub const POLICY_SET_AUDIT_REQUIREMENTS: ULONG = 0x00000100; +pub const POLICY_AUDIT_LOG_ADMIN: ULONG = 0x00000200; +pub const POLICY_SERVER_ADMIN: ULONG = 0x00000400; +pub const POLICY_LOOKUP_NAMES: ULONG = 0x00000800; +pub const POLICY_NOTIFICATION: ULONG = 0x00001000; +pub const POLICY_ALL_ACCESS: ULONG = STANDARD_RIGHTS_REQUIRED | POLICY_VIEW_LOCAL_INFORMATION + | POLICY_VIEW_AUDIT_INFORMATION | POLICY_GET_PRIVATE_INFORMATION | POLICY_TRUST_ADMIN + | POLICY_CREATE_ACCOUNT | POLICY_CREATE_SECRET | POLICY_CREATE_PRIVILEGE + | POLICY_SET_DEFAULT_QUOTA_LIMITS | POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN + | POLICY_SERVER_ADMIN | POLICY_LOOKUP_NAMES; +pub const POLICY_READ: ULONG = STANDARD_RIGHTS_READ | POLICY_VIEW_AUDIT_INFORMATION + | POLICY_GET_PRIVATE_INFORMATION; +pub const POLICY_WRITE: ULONG = STANDARD_RIGHTS_WRITE | POLICY_TRUST_ADMIN | POLICY_CREATE_ACCOUNT + | POLICY_CREATE_SECRET | POLICY_CREATE_PRIVILEGE | POLICY_SET_DEFAULT_QUOTA_LIMITS + | POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN | POLICY_SERVER_ADMIN; +pub const POLICY_EXECUTE: ULONG = STANDARD_RIGHTS_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION + | POLICY_LOOKUP_NAMES; +STRUCT!{struct LSA_TRANSLATED_SID { + Use: SID_NAME_USE, + RelativeId: ULONG, + DomainIndex: LONG, +}} +pub type PLSA_TRANSLATED_SID = *mut LSA_TRANSLATED_SID; +pub type POLICY_SYSTEM_ACCESS_MODE = ULONG; +pub type PPOLICY_SYSTEM_ACCESS_MODE = *mut POLICY_SYSTEM_ACCESS_MODE; +pub const POLICY_MODE_INTERACTIVE: ULONG = SECURITY_ACCESS_INTERACTIVE_LOGON; +pub const POLICY_MODE_NETWORK: ULONG = SECURITY_ACCESS_NETWORK_LOGON; +pub const POLICY_MODE_BATCH: ULONG = SECURITY_ACCESS_BATCH_LOGON; +pub const POLICY_MODE_SERVICE: ULONG = SECURITY_ACCESS_SERVICE_LOGON; +pub const POLICY_MODE_PROXY: ULONG = SECURITY_ACCESS_PROXY_LOGON; +pub const POLICY_MODE_DENY_INTERACTIVE: ULONG = SECURITY_ACCESS_DENY_INTERACTIVE_LOGON; +pub const POLICY_MODE_DENY_NETWORK: ULONG = SECURITY_ACCESS_DENY_NETWORK_LOGON; +pub const POLICY_MODE_DENY_BATCH: ULONG = SECURITY_ACCESS_DENY_BATCH_LOGON; +pub const POLICY_MODE_DENY_SERVICE: ULONG = SECURITY_ACCESS_DENY_SERVICE_LOGON; +pub const POLICY_MODE_REMOTE_INTERACTIVE: ULONG = SECURITY_ACCESS_REMOTE_INTERACTIVE_LOGON; +pub const POLICY_MODE_DENY_REMOTE_INTERACTIVE: ULONG = + SECURITY_ACCESS_DENY_REMOTE_INTERACTIVE_LOGON; +pub const POLICY_MODE_ALL: ULONG = POLICY_MODE_INTERACTIVE | POLICY_MODE_NETWORK + | POLICY_MODE_BATCH | POLICY_MODE_SERVICE | POLICY_MODE_PROXY | POLICY_MODE_DENY_INTERACTIVE + | POLICY_MODE_DENY_NETWORK | SECURITY_ACCESS_DENY_BATCH_LOGON + | SECURITY_ACCESS_DENY_SERVICE_LOGON | POLICY_MODE_REMOTE_INTERACTIVE + | POLICY_MODE_DENY_REMOTE_INTERACTIVE ; +pub const POLICY_MODE_ALL_NT4: ULONG = POLICY_MODE_INTERACTIVE | POLICY_MODE_NETWORK + | POLICY_MODE_BATCH | POLICY_MODE_SERVICE; +ENUM!{enum POLICY_LSA_SERVER_ROLE { + PolicyServerRoleBackup = 2, + PolicyServerRolePrimary, +}} +pub type PPOLICY_LSA_SERVER_ROLE = *mut POLICY_LSA_SERVER_ROLE; +ENUM!{enum POLICY_SERVER_ENABLE_STATE { + PolicyServerEnabled = 2, + PolicyServerDisabled, +}} +pub type PPOLICY_SERVER_ENABLE_STATE = *mut POLICY_SERVER_ENABLE_STATE; +pub type POLICY_AUDIT_EVENT_OPTIONS = ULONG; +pub type PPOLICY_AUDIT_EVENT_OPTIONS = *mut POLICY_AUDIT_EVENT_OPTIONS; +STRUCT!{struct POLICY_PRIVILEGE_DEFINITION { + Name: LSA_UNICODE_STRING, + LocalValue: LUID, +}} +pub type PPOLICY_PRIVILEGE_DEFINITION = *mut POLICY_PRIVILEGE_DEFINITION; +pub const LSA_LOOKUP_ISOLATED_AS_LOCAL: ULONG = 0x80000000; +pub const LSA_LOOKUP_DISALLOW_CONNECTED_ACCOUNT_INTERNET_SID: ULONG = 0x80000000; +pub const LSA_LOOKUP_PREFER_INTERNET_NAMES: ULONG = 0x40000000; +ENUM!{enum POLICY_INFORMATION_CLASS { + PolicyAuditLogInformation = 1, + PolicyAuditEventsInformation, + PolicyPrimaryDomainInformation, + PolicyPdAccountInformation, + PolicyAccountDomainInformation, + PolicyLsaServerRoleInformation, + PolicyReplicaSourceInformation, + PolicyDefaultQuotaInformation, + PolicyModificationInformation, + PolicyAuditFullSetInformation, + PolicyAuditFullQueryInformation, + PolicyDnsDomainInformation, + PolicyDnsDomainInformationInt, + PolicyLocalAccountDomainInformation, + PolicyLastEntry, +}} +pub type PPOLICY_INFORMATION_CLASS = *mut POLICY_INFORMATION_CLASS; +STRUCT!{struct POLICY_AUDIT_LOG_INFO { + AuditLogPercentFull: ULONG, + MaximumLogSize: ULONG, + AuditRetentionPeriod: LARGE_INTEGER, + AuditLogFullShutdownInProgress: BOOLEAN, + TimeToShutdown: LARGE_INTEGER, + NextAuditRecordId: ULONG, +}} +pub type PPOLICY_AUDIT_LOG_INFO = *mut POLICY_AUDIT_LOG_INFO; +STRUCT!{struct POLICY_AUDIT_EVENTS_INFO { + AuditingMode: BOOLEAN, + EventAuditingOptions: PPOLICY_AUDIT_EVENT_OPTIONS, + MaximumAuditEventCount: ULONG, +}} +pub type PPOLICY_AUDIT_EVENTS_INFO = *mut POLICY_AUDIT_EVENTS_INFO; +STRUCT!{struct POLICY_AUDIT_SUBCATEGORIES_INFO { + MaximumSubCategoryCount: ULONG, + EventAuditingOptions: PPOLICY_AUDIT_EVENT_OPTIONS, +}} +pub type PPOLICY_AUDIT_SUBCATEGORIES_INFO = *mut POLICY_AUDIT_SUBCATEGORIES_INFO; +STRUCT!{struct POLICY_AUDIT_CATEGORIES_INFO { + MaximumCategoryCount: ULONG, + SubCategoriesInfo: PPOLICY_AUDIT_SUBCATEGORIES_INFO, +}} +pub type PPOLICY_AUDIT_CATEGORIES_INFO = *mut POLICY_AUDIT_CATEGORIES_INFO; +pub const PER_USER_POLICY_UNCHANGED: UCHAR = 0x00; +pub const PER_USER_AUDIT_SUCCESS_INCLUDE: UCHAR = 0x01; +pub const PER_USER_AUDIT_SUCCESS_EXCLUDE: UCHAR = 0x02; +pub const PER_USER_AUDIT_FAILURE_INCLUDE: UCHAR = 0x04; +pub const PER_USER_AUDIT_FAILURE_EXCLUDE: UCHAR = 0x08; +pub const PER_USER_AUDIT_NONE: UCHAR = 0x10; +pub const VALID_PER_USER_AUDIT_POLICY_FLAG: UCHAR = PER_USER_AUDIT_SUCCESS_INCLUDE + | PER_USER_AUDIT_SUCCESS_EXCLUDE | PER_USER_AUDIT_FAILURE_INCLUDE + | PER_USER_AUDIT_FAILURE_EXCLUDE | PER_USER_AUDIT_NONE; +STRUCT!{struct POLICY_PRIMARY_DOMAIN_INFO { + Name: LSA_UNICODE_STRING, + Sid: PSID, +}} +pub type PPOLICY_PRIMARY_DOMAIN_INFO = *mut POLICY_PRIMARY_DOMAIN_INFO; +STRUCT!{struct POLICY_PD_ACCOUNT_INFO { + Name: LSA_UNICODE_STRING, +}} +pub type PPOLICY_PD_ACCOUNT_INFO = *mut POLICY_PD_ACCOUNT_INFO; +STRUCT!{struct POLICY_LSA_SERVER_ROLE_INFO { + LsaServerRole: POLICY_LSA_SERVER_ROLE, +}} +pub type PPOLICY_LSA_SERVER_ROLE_INFO = *mut POLICY_LSA_SERVER_ROLE_INFO; +STRUCT!{struct POLICY_REPLICA_SOURCE_INFO { + ReplicaSource: LSA_UNICODE_STRING, + ReplicaAccountName: LSA_UNICODE_STRING, +}} +pub type PPOLICY_REPLICA_SOURCE_INFO = *mut POLICY_REPLICA_SOURCE_INFO; +STRUCT!{struct POLICY_DEFAULT_QUOTA_INFO { + QuotaLimits: QUOTA_LIMITS, +}} +pub type PPOLICY_DEFAULT_QUOTA_INFO = *mut POLICY_DEFAULT_QUOTA_INFO; +STRUCT!{struct POLICY_MODIFICATION_INFO { + ModifiedId: LARGE_INTEGER, + DatabaseCreationTime: LARGE_INTEGER, +}} +pub type PPOLICY_MODIFICATION_INFO = *mut POLICY_MODIFICATION_INFO; +STRUCT!{struct POLICY_AUDIT_FULL_SET_INFO { + ShutDownOnFull: BOOLEAN, +}} +pub type PPOLICY_AUDIT_FULL_SET_INFO = *mut POLICY_AUDIT_FULL_SET_INFO; +STRUCT!{struct POLICY_AUDIT_FULL_QUERY_INFO { + ShutDownOnFull: BOOLEAN, + LogIsFull: BOOLEAN, +}} +pub type PPOLICY_AUDIT_FULL_QUERY_INFO = *mut POLICY_AUDIT_FULL_QUERY_INFO; +ENUM!{enum POLICY_DOMAIN_INFORMATION_CLASS { + PolicyDomainEfsInformation = 2, + PolicyDomainKerberosTicketInformation, +}} +pub type PPOLICY_DOMAIN_INFORMATION_CLASS = *mut POLICY_DOMAIN_INFORMATION_CLASS; +pub const POLICY_QOS_SCHANNEL_REQUIRED: ULONG = 0x00000001; +pub const POLICY_QOS_OUTBOUND_INTEGRITY: ULONG = 0x00000002; +pub const POLICY_QOS_OUTBOUND_CONFIDENTIALITY: ULONG = 0x00000004; +pub const POLICY_QOS_INBOUND_INTEGRITY: ULONG = 0x00000008; +pub const POLICY_QOS_INBOUND_CONFIDENTIALITY: ULONG = 0x00000010; +pub const POLICY_QOS_ALLOW_LOCAL_ROOT_CERT_STORE: ULONG = 0x00000020; +pub const POLICY_QOS_RAS_SERVER_ALLOWED: ULONG = 0x00000040; +pub const POLICY_QOS_DHCP_SERVER_ALLOWED: ULONG = 0x00000080; +STRUCT!{struct POLICY_DOMAIN_EFS_INFO { + InfoLength: ULONG, + EfsBlob: PUCHAR, +}} +pub type PPOLICY_DOMAIN_EFS_INFO = *mut POLICY_DOMAIN_EFS_INFO; +pub const POLICY_KERBEROS_VALIDATE_CLIENT: ULONG = 0x00000080; +STRUCT!{struct POLICY_DOMAIN_KERBEROS_TICKET_INFO { + AuthenticationOptions: ULONG, + MaxServiceTicketAge: LARGE_INTEGER, + MaxTicketAge: LARGE_INTEGER, + MaxRenewAge: LARGE_INTEGER, + MaxClockSkew: LARGE_INTEGER, + Reserved: LARGE_INTEGER, +}} +pub type PPOLICY_DOMAIN_KERBEROS_TICKET_INFO = *mut POLICY_DOMAIN_KERBEROS_TICKET_INFO; +ENUM!{enum POLICY_NOTIFICATION_INFORMATION_CLASS { + PolicyNotifyAuditEventsInformation = 1, + PolicyNotifyAccountDomainInformation, + PolicyNotifyServerRoleInformation, + PolicyNotifyDnsDomainInformation, + PolicyNotifyDomainEfsInformation, + PolicyNotifyDomainKerberosTicketInformation, + PolicyNotifyMachineAccountPasswordInformation, + PolicyNotifyGlobalSaclInformation, + PolicyNotifyMax, +}} +pub type PPOLICY_NOTIFICATION_INFORMATION_CLASS = *mut POLICY_NOTIFICATION_INFORMATION_CLASS; +pub const ACCOUNT_VIEW: ULONG = 0x00000001; +pub const ACCOUNT_ADJUST_PRIVILEGES: ULONG = 0x00000002; +pub const ACCOUNT_ADJUST_QUOTAS: ULONG = 0x00000004; +pub const ACCOUNT_ADJUST_SYSTEM_ACCESS: ULONG = 0x00000008; +pub const ACCOUNT_ALL_ACCESS: ULONG = STANDARD_RIGHTS_REQUIRED | ACCOUNT_VIEW + | ACCOUNT_ADJUST_PRIVILEGES | ACCOUNT_ADJUST_QUOTAS | ACCOUNT_ADJUST_SYSTEM_ACCESS; +pub const ACCOUNT_READ: ULONG = STANDARD_RIGHTS_READ | ACCOUNT_VIEW; +pub const ACCOUNT_WRITE: ULONG = STANDARD_RIGHTS_WRITE | ACCOUNT_ADJUST_PRIVILEGES + | ACCOUNT_ADJUST_QUOTAS | ACCOUNT_ADJUST_SYSTEM_ACCESS; +pub const ACCOUNT_EXECUTE: ULONG = STANDARD_RIGHTS_EXECUTE; +DECLARE_HANDLE!{LSA_HANDLE, __LSA_HANDLE} +pub const TRUSTED_QUERY_DOMAIN_NAME: ULONG = 0x00000001; +pub const TRUSTED_QUERY_CONTROLLERS: ULONG = 0x00000002; +pub const TRUSTED_SET_CONTROLLERS: ULONG = 0x00000004; +pub const TRUSTED_QUERY_POSIX: ULONG = 0x00000008; +pub const TRUSTED_SET_POSIX: ULONG = 0x00000010; +pub const TRUSTED_SET_AUTH: ULONG = 0x00000020; +pub const TRUSTED_QUERY_AUTH: ULONG = 0x00000040; +pub const TRUSTED_ALL_ACCESS: ULONG = STANDARD_RIGHTS_REQUIRED | TRUSTED_QUERY_DOMAIN_NAME + | TRUSTED_QUERY_CONTROLLERS | TRUSTED_SET_CONTROLLERS | TRUSTED_QUERY_POSIX | TRUSTED_SET_POSIX + | TRUSTED_SET_AUTH | TRUSTED_QUERY_AUTH; +pub const TRUSTED_READ: ULONG = STANDARD_RIGHTS_READ | TRUSTED_QUERY_DOMAIN_NAME; +pub const TRUSTED_WRITE: ULONG = STANDARD_RIGHTS_WRITE | TRUSTED_SET_CONTROLLERS + | TRUSTED_SET_POSIX | TRUSTED_SET_AUTH; +pub const TRUSTED_EXECUTE: ULONG = STANDARD_RIGHTS_EXECUTE | TRUSTED_QUERY_CONTROLLERS + | TRUSTED_QUERY_POSIX; +ENUM!{enum TRUSTED_INFORMATION_CLASS { + TrustedDomainNameInformation = 1, + TrustedControllersInformation, + TrustedPosixOffsetInformation, + TrustedPasswordInformation, + TrustedDomainInformationBasic, + TrustedDomainInformationEx, + TrustedDomainAuthInformation, + TrustedDomainFullInformation, + TrustedDomainAuthInformationInternal, + TrustedDomainFullInformationInternal, + TrustedDomainInformationEx2Internal, + TrustedDomainFullInformation2Internal, + TrustedDomainSupportedEncryptionTypes, +}} +pub type PTRUSTED_INFORMATION_CLASS = *mut TRUSTED_INFORMATION_CLASS; +STRUCT!{struct TRUSTED_DOMAIN_NAME_INFO { + Name: LSA_UNICODE_STRING, +}} +pub type PTRUSTED_DOMAIN_NAME_INFO = *mut TRUSTED_DOMAIN_NAME_INFO; +STRUCT!{struct TRUSTED_CONTROLLERS_INFO { + Entries: ULONG, + Names: PLSA_UNICODE_STRING, +}} +pub type PTRUSTED_CONTROLLERS_INFO = *mut TRUSTED_CONTROLLERS_INFO; +STRUCT!{struct TRUSTED_POSIX_OFFSET_INFO { + Offset: ULONG, +}} +pub type PTRUSTED_POSIX_OFFSET_INFO = *mut TRUSTED_POSIX_OFFSET_INFO; +STRUCT!{struct TRUSTED_PASSWORD_INFO { + Password: LSA_UNICODE_STRING, + OldPassword: LSA_UNICODE_STRING, +}} +pub type PTRUSTED_PASSWORD_INFO = *mut TRUSTED_PASSWORD_INFO; +pub type TRUSTED_DOMAIN_INFORMATION_BASIC = LSA_TRUST_INFORMATION; +pub type PTRUSTED_DOMAIN_INFORMATION_BASIC = PLSA_TRUST_INFORMATION; +// NOTE: Ignoring Win XP constants +pub const TRUST_DIRECTION_DISABLED: ULONG = 0x00000000; +pub const TRUST_DIRECTION_INBOUND: ULONG = 0x00000001; +pub const TRUST_DIRECTION_OUTBOUND: ULONG = 0x00000002; +pub const TRUST_DIRECTION_BIDIRECTIONAL: ULONG = TRUST_DIRECTION_INBOUND + | TRUST_DIRECTION_OUTBOUND; +pub const TRUST_TYPE_DOWNLEVEL: ULONG = 0x00000001; +pub const TRUST_TYPE_UPLEVEL: ULONG = 0x00000002; +pub const TRUST_TYPE_MIT: ULONG = 0x00000003; +pub const TRUST_ATTRIBUTE_NON_TRANSITIVE: ULONG = 0x00000001; +pub const TRUST_ATTRIBUTE_UPLEVEL_ONLY: ULONG = 0x00000002; +pub const TRUST_ATTRIBUTE_QUARANTINED_DOMAIN: ULONG = 0x00000004; +pub const TRUST_ATTRIBUTE_FOREST_TRANSITIVE: ULONG = 0x00000008; +pub const TRUST_ATTRIBUTE_CROSS_ORGANIZATION: ULONG = 0x00000010; +pub const TRUST_ATTRIBUTE_WITHIN_FOREST: ULONG = 0x00000020; +pub const TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL: ULONG = 0x00000040; +pub const TRUST_ATTRIBUTE_TRUST_USES_RC4_ENCRYPTION: ULONG = 0x00000080; +pub const TRUST_ATTRIBUTE_TRUST_USES_AES_KEYS: ULONG = 0x00000100; +pub const TRUST_ATTRIBUTE_CROSS_ORGANIZATION_NO_TGT_DELEGATION: ULONG = 0x00000200; +pub const TRUST_ATTRIBUTE_PIM_TRUST: ULONG = 0x00000400; +pub const TRUST_ATTRIBUTES_VALID: ULONG = 0xFF03FFFF; +pub const TRUST_ATTRIBUTES_USER: ULONG = 0xFF000000; +STRUCT!{struct TRUSTED_DOMAIN_INFORMATION_EX { + Name: LSA_UNICODE_STRING, + FlatName: LSA_UNICODE_STRING, + Sid: PSID, + TrustDirection: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, +}} +pub type PTRUSTED_DOMAIN_INFORMATION_EX = *mut TRUSTED_DOMAIN_INFORMATION_EX; +STRUCT!{struct TRUSTED_DOMAIN_INFORMATION_EX2 { + Name: LSA_UNICODE_STRING, + FlatName: LSA_UNICODE_STRING, + Sid: PSID, + TrustDirection: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, + ForestTrustLength: ULONG, + ForestTrustInfo: PUCHAR, +}} +pub type PTRUSTED_DOMAIN_INFORMATION_EX2 = *mut TRUSTED_DOMAIN_INFORMATION_EX2; +pub const TRUST_AUTH_TYPE_NONE: ULONG = 0; +pub const TRUST_AUTH_TYPE_NT4OWF: ULONG = 1; +pub const TRUST_AUTH_TYPE_CLEAR: ULONG = 2; +pub const TRUST_AUTH_TYPE_VERSION: ULONG = 3; +STRUCT!{struct LSA_AUTH_INFORMATION { + LastUpdateTime: LARGE_INTEGER, + AuthType: ULONG, + AuthInfoLength: ULONG, + AuthInfo: PUCHAR, +}} +pub type PLSA_AUTH_INFORMATION = *mut LSA_AUTH_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_AUTH_INFORMATION { + IncomingAuthInfos: ULONG, + IncomingAuthenticationInformation: PLSA_AUTH_INFORMATION, + IncomingPreviousAuthenticationInformation: PLSA_AUTH_INFORMATION, + OutgoingAuthInfos: ULONG, + OutgoingAuthenticationInformation: PLSA_AUTH_INFORMATION, + OutgoingPreviousAuthenticationInformation: PLSA_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_AUTH_INFORMATION = *mut TRUSTED_DOMAIN_AUTH_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_FULL_INFORMATION { + Information: TRUSTED_DOMAIN_INFORMATION_EX, + PosixOffset: TRUSTED_POSIX_OFFSET_INFO, + AuthInformation: TRUSTED_DOMAIN_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_FULL_INFORMATION = *mut TRUSTED_DOMAIN_FULL_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_FULL_INFORMATION2 { + Information: TRUSTED_DOMAIN_INFORMATION_EX2, + PosixOffset: TRUSTED_POSIX_OFFSET_INFO, + AuthInformation: TRUSTED_DOMAIN_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_FULL_INFORMATION2 = *mut TRUSTED_DOMAIN_FULL_INFORMATION2; +STRUCT!{struct TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES { + SupportedEncryptionTypes: ULONG, +}} +pub type PTRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES = + *mut TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES; +ENUM!{enum LSA_FOREST_TRUST_RECORD_TYPE { + ForestTrustTopLevelName, + ForestTrustTopLevelNameEx, + ForestTrustDomainInfo, + ForestTrustRecordTypeLast = ForestTrustDomainInfo, +}} +pub const LSA_FTRECORD_DISABLED_REASONS: ULONG = 0x0000FFFF; +pub const LSA_TLN_DISABLED_NEW: ULONG = 0x00000001; +pub const LSA_TLN_DISABLED_ADMIN: ULONG = 0x00000002; +pub const LSA_TLN_DISABLED_CONFLICT: ULONG = 0x00000004; +pub const LSA_SID_DISABLED_ADMIN: ULONG = 0x00000001; +pub const LSA_SID_DISABLED_CONFLICT: ULONG = 0x00000002; +pub const LSA_NB_DISABLED_ADMIN: ULONG = 0x00000004; +pub const LSA_NB_DISABLED_CONFLICT: ULONG = 0x00000008; +STRUCT!{struct LSA_FOREST_TRUST_DOMAIN_INFO { + Sid: PSID, + DnsName: LSA_UNICODE_STRING, + NetbiosName: LSA_UNICODE_STRING, +}} +pub type PLSA_FOREST_TRUST_DOMAIN_INFO = *mut LSA_FOREST_TRUST_DOMAIN_INFO; +pub const MAX_FOREST_TRUST_BINARY_DATA_SIZE: SIZE_T = 128 * 1024; +STRUCT!{struct LSA_FOREST_TRUST_BINARY_DATA { + Length: ULONG, + Buffer: PUCHAR, +}} +pub type PLSA_FOREST_TRUST_BINARY_DATA = *mut LSA_FOREST_TRUST_BINARY_DATA; +UNION!{union LSA_FOREST_TRUST_RECORD_FORESTTRUSTDATA { + [u32; 5] [u64; 5], + TopLevelName TopLevelName_mut: LSA_UNICODE_STRING, + DomainInfo DomainInfo_mut: LSA_FOREST_TRUST_DOMAIN_INFO, + Data Data_mut: LSA_FOREST_TRUST_BINARY_DATA, +}} +STRUCT!{struct LSA_FOREST_TRUST_RECORD { + Flags: ULONG, + ForestTrustType: LSA_FOREST_TRUST_RECORD_TYPE, + Time: LARGE_INTEGER, + ForestTrustData: LSA_FOREST_TRUST_RECORD_FORESTTRUSTDATA, +}} +pub type PLSA_FOREST_TRUST_RECORD = *mut LSA_FOREST_TRUST_RECORD; +pub const MAX_RECORDS_IN_FOREST_TRUST_INFO: SIZE_T = 4000; +STRUCT!{struct LSA_FOREST_TRUST_INFORMATION { + RecordCount: ULONG, + Entries: *mut PLSA_FOREST_TRUST_RECORD, +}} +pub type PLSA_FOREST_TRUST_INFORMATION = LSA_FOREST_TRUST_INFORMATION; +ENUM!{enum LSA_FOREST_TRUST_COLLISION_RECORD_TYPE { + CollisionTdo, + CollisionXref, + CollisionOther, +}} +STRUCT!{struct LSA_FOREST_TRUST_COLLISION_RECORD { + Index: ULONG, + Type: LSA_FOREST_TRUST_COLLISION_RECORD_TYPE, + Flags: ULONG, + Name: LSA_UNICODE_STRING, +}} +pub type PLSA_FOREST_TRUST_COLLISION_RECORD = *mut LSA_FOREST_TRUST_COLLISION_RECORD; +STRUCT!{struct LSA_FOREST_TRUST_COLLISION_INFORMATION { + RecordCount: ULONG, + Entries: *mut PLSA_FOREST_TRUST_COLLISION_RECORD, +}} +pub type PLSA_FOREST_TRUST_COLLISION_INFORMATION = *mut LSA_FOREST_TRUST_COLLISION_INFORMATION; +pub const SECRET_SET_VALUE: ULONG = 0x00000001; +pub const SECRET_QUERY_VALUE: ULONG = 0x00000002; +pub const SECRET_ALL_ACCESS: ULONG = STANDARD_RIGHTS_REQUIRED | SECRET_SET_VALUE + | SECRET_QUERY_VALUE; +pub const SECRET_READ: ULONG = STANDARD_RIGHTS_READ | SECRET_QUERY_VALUE; +pub const SECRET_WRITE: ULONG = STANDARD_RIGHTS_WRITE | SECRET_SET_VALUE; +pub const SECRET_EXECUTE: ULONG = STANDARD_RIGHTS_EXECUTE; +pub const LSA_GLOBAL_SECRET_PREFIX: &'static str = "G$"; +pub const LSA_GLOBAL_SECRET_PREFIX_LENGTH: SIZE_T = 2; +pub const LSA_LOCAL_SECRET_PREFIX: &'static str = "L$"; +pub const LSA_LOCAL_SECRET_PREFIX_LENGTH: SIZE_T = 2; +pub const LSA_MACHINE_SECRET_PREFIX: &'static str = "M$"; +pub const LSA_MACHINE_SECRET_PREFIX_LENGTH: SIZE_T = 2; +pub const LSA_SECRET_MAXIMUM_COUNT: SIZE_T = 0x00001000; +pub const LSA_SECRET_MAXIMUM_LENGTH: SIZE_T = 0x00000200; +DECLARE_HANDLE!{LSA_ENUMERATION_HANDLE, __LSA_ENUMERATION_HANDLE} +pub type PLSA_ENUMERATION_HANDLE = *mut LSA_ENUMERATION_HANDLE; +STRUCT!{struct LSA_ENUMERATION_INFORMATION { + Sid: PSID, +}} +pub type PLSA_ENUMERATION_INFORMATION = *mut LSA_ENUMERATION_INFORMATION; +extern "system" { + pub fn LsaFreeMemory( + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaClose( + ObjectHandle: LSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaDelete( + ObjectHandle: LSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaQuerySecurityObject( + ObjectHandle: LSA_HANDLE, + SecurityInformation: SECURITY_INFORMATION, + SecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> NTSTATUS; + pub fn LsaSetSecurityObject( + ObjectHandle: LSA_HANDLE, + SecurityInformation: SECURITY_INFORMATION, + SecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> NTSTATUS; + pub fn LsaChangePassword( + ServerName: PLSA_UNICODE_STRING, + DomainName: PLSA_UNICODE_STRING, + AccountName: PLSA_UNICODE_STRING, + OldPassword: PLSA_UNICODE_STRING, + NewPassword: PLSA_UNICODE_STRING, + ) -> NTSTATUS; +} +STRUCT!{struct LSA_LAST_INTER_LOGON_INFO { + LastSuccessfulLogon: LARGE_INTEGER, + LastFailedLogon: LARGE_INTEGER, + FailedAttemptCountSinceLastSuccessfulLogon: ULONG, +}} +pub type PLSA_LAST_INTER_LOGON_INFO = *mut LSA_LAST_INTER_LOGON_INFO; +STRUCT!{struct SECURITY_LOGON_SESSION_DATA { + Size: ULONG, + LogonId: LUID, + UserName: LSA_UNICODE_STRING, + LogonDomain: LSA_UNICODE_STRING, + AuthenticationPackage: LSA_UNICODE_STRING, + LogonType: ULONG, + Session: ULONG, + Sid: PSID, + LogonTime: LARGE_INTEGER, + LogonServer: LSA_UNICODE_STRING, + DnsDomainName: LSA_UNICODE_STRING, + Upn: LSA_UNICODE_STRING, + UserFlags: ULONG, + LastLogonInfo: LSA_LAST_INTER_LOGON_INFO, + LogonScript: LSA_UNICODE_STRING, + ProfilePath: LSA_UNICODE_STRING, + HomeDirectory: LSA_UNICODE_STRING, + HomeDirectoryDrive: LSA_UNICODE_STRING, + LogoffTime: LARGE_INTEGER, + KickOffTime: LARGE_INTEGER, + PasswordLastSet: LARGE_INTEGER, + PasswordCanChange: LARGE_INTEGER, + PasswordMustChange: LARGE_INTEGER, +}} +pub type PSECURITY_LOGON_SESSION_DATA = *mut SECURITY_LOGON_SESSION_DATA; +extern "system" { + pub fn LsaEnumerateLogonSessions( + LogonSessionCount: PULONG, + LogonSessionList: *mut PLUID, + ) -> NTSTATUS; + pub fn LsaGetLogonSessionData( + LogonId: PLUID, + ppLogonSessionData: *mut PSECURITY_LOGON_SESSION_DATA, + ) -> NTSTATUS; + pub fn LsaOpenPolicy( + SystemName: PLSA_UNICODE_STRING, + ObjectAttributes: PLSA_OBJECT_ATTRIBUTES, + DesiredAccess: ACCESS_MASK, + PolicyHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaOpenPolicySce( + SystemName: PLSA_UNICODE_STRING, + ObjectAttributes: PLSA_OBJECT_ATTRIBUTES, + DesiredAccess: ACCESS_MASK, + PolicyHandle: PLSA_HANDLE, + ) -> NTSTATUS; +} +pub const MAXIMUM_CAPES_PER_CAP: SIZE_T = 0x7F; +pub const CENTRAL_ACCESS_POLICY_OWNER_RIGHTS_PRESENT_FLAG: ULONG = 0x00000001; +pub const CENTRAL_ACCESS_POLICY_STAGED_OWNER_RIGHTS_PRESENT_FLAG: ULONG = 0x00000100; +#[inline] +pub fn STAGING_FLAG(Effective: ULONG) -> ULONG { + (Effective & 0xF) << 8 +} +pub const CENTRAL_ACCESS_POLICY_STAGED_FLAG: ULONG = 0x00010000; +pub const CENTRAL_ACCESS_POLICY_VALID_FLAG_MASK: ULONG = + CENTRAL_ACCESS_POLICY_OWNER_RIGHTS_PRESENT_FLAG + | CENTRAL_ACCESS_POLICY_STAGED_OWNER_RIGHTS_PRESENT_FLAG | CENTRAL_ACCESS_POLICY_STAGED_FLAG; +pub const LSASETCAPS_RELOAD_FLAG: ULONG = 0x00000001; +pub const LSASETCAPS_VALID_FLAG_MASK: ULONG = LSASETCAPS_RELOAD_FLAG; +STRUCT!{struct CENTRAL_ACCESS_POLICY_ENTRY { + Name: LSA_UNICODE_STRING, + Description: LSA_UNICODE_STRING, + ChangeId: LSA_UNICODE_STRING, + LengthAppliesTo: ULONG, + AppliesTo: PUCHAR, + LengthSD: ULONG, + SD: PSECURITY_DESCRIPTOR, + LengthStagedSD: ULONG, + StagedSD: PSECURITY_DESCRIPTOR, + Flags: ULONG, +}} +pub type PCENTRAL_ACCESS_POLICY_ENTRY = *mut CENTRAL_ACCESS_POLICY_ENTRY; +pub type PCCENTRAL_ACCESS_POLICY_ENTRY = *const CENTRAL_ACCESS_POLICY_ENTRY; +STRUCT!{struct CENTRAL_ACCESS_POLICY { + CAPID: PSID, + Name: LSA_UNICODE_STRING, + Description: LSA_UNICODE_STRING, + ChangeId: LSA_UNICODE_STRING, + Flags: ULONG, + CAPECount: ULONG, + CAPEs: *mut PCENTRAL_ACCESS_POLICY_ENTRY, +}} +pub type PCENTRAL_ACCESS_POLICY = *mut CENTRAL_ACCESS_POLICY; +pub type PCCENTRAL_ACCESS_POLICY = *const CENTRAL_ACCESS_POLICY; +extern "system" { + pub fn LsaSetCAPs( + CAPDNs: PLSA_UNICODE_STRING, + CAPDNCount: ULONG, + Flags: ULONG, + ) -> NTSTATUS; + pub fn LsaGetAppliedCAPIDs( + SystemName: PLSA_UNICODE_STRING, + CAPIDs: *mut *mut PSID, + CAPIDCount: PULONG, + ) -> NTSTATUS; + pub fn LsaQueryCAPs( + CAPIDs: *mut PSID, + CAPIDCount: ULONG, + CAPs: *mut PCENTRAL_ACCESS_POLICY, + CAPCount: PULONG, + ) -> NTSTATUS; + pub fn LsaQueryInformationPolicy( + PolicyHandle: LSA_HANDLE, + InformationClass: POLICY_INFORMATION_CLASS, + Buffer: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaSetInformationPolicy( + PolicyHandle: LSA_HANDLE, + InformationClass: POLICY_INFORMATION_CLASS, + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaQueryDomainInformationPolicy( + PolicyHandle: LSA_HANDLE, + InformationClass: POLICY_DOMAIN_INFORMATION_CLASS, + Buffer: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaSetDomainInformationPolicy( + PolicyHandle: LSA_HANDLE, + InformationClass: POLICY_DOMAIN_INFORMATION_CLASS, + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaRegisterPolicyChangeNotification( + InformationClass: POLICY_NOTIFICATION_INFORMATION_CLASS, + NotifcationEventHandle: HANDLE, + ) -> NTSTATUS; + pub fn LsaUnregisterPolicyChangeNotification( + InformationClass: POLICY_NOTIFICATION_INFORMATION_CLASS, + NotifcationEventHandle: HANDLE, + ) -> NTSTATUS; + pub fn LsaClearAuditLog( + PolicyHandle: LSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaCreateAccount( + PolicyHandle: LSA_HANDLE, + AccountSid: PSID, + DesiredAccess: ACCESS_MASK, + AccountHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaEnumerateAccounts( + PolicyHandle: LSA_HANDLE, + EnumerationContext: PLSA_ENUMERATION_HANDLE, + Buffer: *mut PVOID, + PreferredMaximumLength: ULONG, + CountReturned: PULONG, + ) -> NTSTATUS; + pub fn LsaCreateTrustedDomain( + PolicyHandle: LSA_HANDLE, + TrustedDomainInformation: PLSA_TRUST_INFORMATION, + DesiredAccess: ACCESS_MASK, + TrustedDomainHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaEnumerateTrustedDomains( + PolicyHandle: LSA_HANDLE, + EnumerationContext: PLSA_ENUMERATION_HANDLE, + Buffer: *mut PVOID, + PreferredMaximumLength: ULONG, + CountReturned: PULONG, + ) -> NTSTATUS; + pub fn LsaEnumeratePrivileges( + PolicyHandle: LSA_HANDLE, + EnumerationContext: PLSA_ENUMERATION_HANDLE, + Buffer: *mut PVOID, + PreferredMaximumLength: ULONG, + CountReturned: PULONG, + ) -> NTSTATUS; + pub fn LsaLookupNames( + PolicyHandle: LSA_HANDLE, + Count: ULONG, + Names: PLSA_UNICODE_STRING, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Sids: *mut PLSA_TRANSLATED_SID, + ) -> NTSTATUS; + pub fn LsaLookupNames2( + PolicyHandle: LSA_HANDLE, + Flags: ULONG, + Count: ULONG, + Names: PLSA_UNICODE_STRING, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Sids: *mut PLSA_TRANSLATED_SID2, + ) -> NTSTATUS; + pub fn LsaLookupSids( + PolicyHandle: LSA_HANDLE, + Count: ULONG, + Sids: *mut PSID, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Names: *mut PLSA_TRANSLATED_NAME, + ) -> NTSTATUS; + pub fn LsaLookupSids2( + PolicyHandle: LSA_HANDLE, + LookupOptions: ULONG, + Count: ULONG, + Sids: *mut PSID, + ReferencedDomains: *mut PLSA_REFERENCED_DOMAIN_LIST, + Names: *mut PLSA_TRANSLATED_NAME, + ) -> NTSTATUS; + pub fn LsaCreateSecret( + PolicyHandle: LSA_HANDLE, + SecretName: PLSA_UNICODE_STRING, + DesiredAccess: ACCESS_MASK, + SecretHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaOpenAccount( + PolicyHandle: LSA_HANDLE, + AccountSid: PSID, + DesiredAccess: ACCESS_MASK, + AccountHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaEnumeratePrivilegesOfAccount( + AccountHandle: LSA_HANDLE, + Privileges: *mut PPRIVILEGE_SET, + ) -> NTSTATUS; + pub fn LsaAddPrivilegesToAccount( + AccountHandle: LSA_HANDLE, + Privileges: PPRIVILEGE_SET, + ) -> NTSTATUS; + pub fn LsaRemovePrivilegesFromAccount( + AccountHandle: LSA_HANDLE, + AllPrivileges: BOOLEAN, + Privileges: PPRIVILEGE_SET, + ) -> NTSTATUS; + pub fn LsaGetQuotasForAccount( + AccountHandle: LSA_HANDLE, + QuotaLimits: PQUOTA_LIMITS, + ) -> NTSTATUS; + pub fn LsaSetQuotasForAccount( + AccountHandle: LSA_HANDLE, + QuotaLimits: PQUOTA_LIMITS, + ) -> NTSTATUS; + pub fn LsaGetSystemAccessAccount( + AccountHandle: LSA_HANDLE, + SystemAccess: PULONG, + ) -> NTSTATUS; + pub fn LsaSetSystemAccessAccount( + AccountHandle: LSA_HANDLE, + SystemAccess: ULONG, + ) -> NTSTATUS; + pub fn LsaOpenTrustedDomain( + PolicyHandle: LSA_HANDLE, + TrustedDomainSid: PSID, + DesiredAccess: ACCESS_MASK, + TrustedDomainHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaQueryInfoTrustedDomain( + TrustedDomainHandle: LSA_HANDLE, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaSetInformationTrustedDomain( + TrustedDomainHandle: LSA_HANDLE, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaOpenSecret( + PolicyHandle: LSA_HANDLE, + SecretName: PLSA_UNICODE_STRING, + DesiredAccess: ACCESS_MASK, + SecretHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaSetSecret( + SecretHandle: LSA_HANDLE, + CurrentValue: PLSA_UNICODE_STRING, + OldValue: PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaQuerySecret( + SecretHandle: LSA_HANDLE, + CurrentValue: *mut PLSA_UNICODE_STRING, + CurrentValueSetTime: PLARGE_INTEGER, + OldValue: *mut PLSA_UNICODE_STRING, + OldValueSetTime: PLARGE_INTEGER, + ) -> NTSTATUS; + pub fn LsaLookupPrivilegeValue( + PolicyHandle: LSA_HANDLE, + Name: PLSA_UNICODE_STRING, + Value: PLUID, + ) -> NTSTATUS; + pub fn LsaLookupPrivilegeName( + PolicyHandle: LSA_HANDLE, + Value: PLUID, + Name: *mut PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaLookupPrivilegeDisplayName( + PolicyHandle: LSA_HANDLE, + Name: PLSA_UNICODE_STRING, + DisplayName: *mut PLSA_UNICODE_STRING, + LanguageReturned: PSHORT, + ) -> NTSTATUS; +} +extern "C" { + pub fn LsaGetUserName( + UserName: *mut PLSA_UNICODE_STRING, + DomainName: *mut PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaGetRemoteUserName( + SystemName: PLSA_UNICODE_STRING, + UserName: *mut PLSA_UNICODE_STRING, + DomainName: *mut PLSA_UNICODE_STRING, + ) -> NTSTATUS; +} +pub const SE_INTERACTIVE_LOGON_NAME: &'static str = "SeInteractiveLogonRight"; +pub const SE_NETWORK_LOGON_NAME: &'static str = "SeNetworkLogonRight"; +pub const SE_BATCH_LOGON_NAME: &'static str = "SeBatchLogonRight"; +pub const SE_SERVICE_LOGON_NAME: &'static str = "SeServiceLogonRight"; +pub const SE_DENY_INTERACTIVE_LOGON_NAME: &'static str = "SeDenyInteractiveLogonRight"; +pub const SE_DENY_NETWORK_LOGON_NAME: &'static str = "SeDenyNetworkLogonRight"; +pub const SE_DENY_BATCH_LOGON_NAME: &'static str = "SeDenyBatchLogonRight"; +pub const SE_DENY_SERVICE_LOGON_NAME: &'static str = "SeDenyServiceLogonRight"; +pub const SE_REMOTE_INTERACTIVE_LOGON_NAME: &'static str = "SeRemoteInteractiveLogonRight"; +pub const SE_DENY_REMOTE_INTERACTIVE_LOGON_NAME: &'static str = + "SeDenyRemoteInteractiveLogonRight"; +extern "system" { + pub fn LsaEnumerateAccountsWithUserRight( + PolictHandle: LSA_HANDLE, + UserRights: PLSA_UNICODE_STRING, + EnumerationBuffer: *mut PVOID, + CountReturned: PULONG, + ) -> NTSTATUS; + pub fn LsaEnumerateAccountRights( + PolicyHandle: LSA_HANDLE, + AccountSid: PSID, + UserRights: *mut PLSA_UNICODE_STRING, + CountOfRights: PULONG, + ) -> NTSTATUS; + pub fn LsaAddAccountRights( + PolicyHandle: LSA_HANDLE, + AccountSid: PSID, + UserRights: PLSA_UNICODE_STRING, + CountOfRights: ULONG, + ) -> NTSTATUS; + pub fn LsaRemoveAccountRights( + PolicyHandle: LSA_HANDLE, + AccountSid: PSID, + AllRights: BOOLEAN, + UserRights: PLSA_UNICODE_STRING, + CountOfRights: ULONG, + ) -> NTSTATUS; + pub fn LsaOpenTrustedDomainByName( + PolicyHandle: LSA_HANDLE, + TrustedDomainName: PLSA_UNICODE_STRING, + DesiredAccess: ACCESS_MASK, + TrustedDomainHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaQueryTrustedDomainInfo( + PolicyHandle: LSA_HANDLE, + TrustedDomainSid: PSID, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaSetTrustedDomainInformation( + PolicyHandle: LSA_HANDLE, + TrustedDomainSid: PSID, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaDeleteTrustedDomain( + PolicyHandle: LSA_HANDLE, + TrustedDomainSid: PSID, + ) -> NTSTATUS; + pub fn LsaQueryTrustedDomainInfoByName( + PolicyHandle: LSA_HANDLE, + TrustedDomainName: PLSA_UNICODE_STRING, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: *mut PVOID, + ) -> NTSTATUS; + pub fn LsaSetTrustedDomainInfoByName( + PolicyHandle: LSA_HANDLE, + TrustedDomainName: PLSA_UNICODE_STRING, + InformationClass: TRUSTED_INFORMATION_CLASS, + Buffer: PVOID, + ) -> NTSTATUS; + pub fn LsaEnumerateTrustedDomainsEx( + PolicyHandle: LSA_HANDLE, + EnumerationContext: PLSA_ENUMERATION_HANDLE, + Buffer: *mut PVOID, + PreferredMaximumLength: ULONG, + CountReturned: PULONG, + ) -> NTSTATUS; + pub fn LsaCreateTrustedDomainEx( + PolicyHandle: LSA_HANDLE, + TrustedDomainInformation: PTRUSTED_DOMAIN_INFORMATION_EX, + AuthenticationInformation: PTRUSTED_DOMAIN_AUTH_INFORMATION, + DesiredAccess: ACCESS_MASK, + TrustedDomainHandle: PLSA_HANDLE, + ) -> NTSTATUS; + pub fn LsaQueryForestTrustInformation( + PolicyHandle: LSA_HANDLE, + TrustedDomainName: PLSA_UNICODE_STRING, + ForestTrustInfo: *mut PLSA_FOREST_TRUST_INFORMATION, + ) -> NTSTATUS; + pub fn LsaSetForestTrustInformation( + PolicyHandle: LSA_HANDLE, + TrustedDomainName: PLSA_UNICODE_STRING, + ForestTrustInfo: PLSA_FOREST_TRUST_INFORMATION, + CheckOnly: BOOLEAN, + CollisionInfo: *mut PLSA_FOREST_TRUST_COLLISION_INFORMATION, + ) -> NTSTATUS; + pub fn LsaForestTrustFindMatch( + PolicyHandle: LSA_HANDLE, + Type: ULONG, + Name: PLSA_UNICODE_STRING, + Match: *mut PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaStorePrivateData( + PolicyHandle: LSA_HANDLE, + KeyName: PLSA_UNICODE_STRING, + PrivateData: PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaRetrievePrivateData( + PolicyHandle: LSA_HANDLE, + KeyName: PLSA_UNICODE_STRING, + PrivateData: *mut PLSA_UNICODE_STRING, + ) -> NTSTATUS; + pub fn LsaNtStatusToWinError( + Status: NTSTATUS, + ) -> ULONG; +} +ENUM!{enum NEGOTIATE_MESSAGES { + NegEnumPackagePrefixes = 0, + NegGetCallerName = 1, + NegTransferCredentials = 2, + NegEnumPackageNames = 3, + NegCallPackageMax, +}} +pub const NEGOTIATE_MAX_PREFIX: SIZE_T = 32; +STRUCT!{struct NEGOTIATE_PACKAGE_PREFIX { + PackageId: ULONG_PTR, + PackageDataA: PVOID, + PackageDataW: PVOID, + PrefixLen: ULONG_PTR, + Prefix: [UCHAR; NEGOTIATE_MAX_PREFIX], +}} +pub type PNEGOTIATE_PACKAGE_PREFIX = *mut NEGOTIATE_PACKAGE_PREFIX; +STRUCT!{struct NEGOTIATE_PACKAGE_PREFIXES { + MessageType: ULONG, + PrefixCount: ULONG, + Offset: ULONG, + Pad: ULONG, +}} +pub type PNEGOTIATE_PACKAGE_PREFIXES = *mut NEGOTIATE_PACKAGE_PREFIXES; +STRUCT!{struct NEGOTIATE_CALLER_NAME_REQUEST { + MessageType: ULONG, + LogonId: LUID, +}} +pub type PNEGOTIATE_CALLER_NAME_REQUEST = *mut NEGOTIATE_CALLER_NAME_REQUEST; +STRUCT!{struct NEGOTIATE_CALLER_NAME_RESPONSE { + Messagetype: ULONG, + CallerName: PWSTR, +}} +pub type PNEGOTIATE_CALLER_NAME_RESPONSE = *mut NEGOTIATE_CALLER_NAME_RESPONSE; +STRUCT!{struct NEGOTIATE_PACKAGE_NAMES { + NamesCount: ULONG, + Names: [UNICODE_STRING; ANYSIZE_ARRAY], +}} +pub type PNEGOTIATE_PACKAGE_NAMES = *mut NEGOTIATE_PACKAGE_NAMES; +pub const NEGOTIATE_ALLOW_NTLM: ULONG = 0x10000000; +pub const NEGOTIATE_NEG_NTLM: ULONG = 0x20000000; +STRUCT!{struct NEGOTIATE_PACKAGE_PREFIX_WOW { + PackageId: ULONG, + PackageDataA: ULONG, + PackageDataW: ULONG, + PrefixLen: ULONG, + Prefix: [UCHAR; NEGOTIATE_MAX_PREFIX], +}} +pub type PNEGOTIATE_PACKAGE_PREFIX_WOW = *mut NEGOTIATE_PACKAGE_PREFIX_WOW; +STRUCT!{struct NEGOTIATE_CALLER_NAME_RESPONSE_WOW { + MessageType: ULONG, + CallerName: ULONG, +}} +pub type PNEGOTIATE_CALLER_NAME_RESPONSE_WOW = *mut NEGOTIATE_CALLER_NAME_RESPONSE_WOW; +extern "system" { + pub fn LsaSetPolicyReplicationHandle( + PolicyHandle: PLSA_HANDLE, + ) -> NTSTATUS; +} +pub const MAX_USER_RECORDS: SIZE_T = 1000; +STRUCT!{struct LSA_USER_REGISTRATION_INFO { + Sid: LSA_UNICODE_STRING, + DeviceId: LSA_UNICODE_STRING, + Username: LSA_UNICODE_STRING, + Thumbprint: LSA_UNICODE_STRING, + RegistrationTime: LARGE_INTEGER, +}} +pub type PLSA_USER_REGISTRATION_INFO = *mut LSA_USER_REGISTRATION_INFO; +STRUCT!{struct LSA_REGISTRATION_INFO { + RegisteredCount: ULONG, + UserRegistrationInfo: *mut PLSA_USER_REGISTRATION_INFO, +}} +pub type PLSA_REGISTRATION_INFO = *mut LSA_REGISTRATION_INFO; +extern "system" { + pub fn LsaGetDeviceRegistrationInfo( + RegistrationInfo: *mut PLSA_REGISTRATION_INFO, + ) -> NTSTATUS; +} +ENUM!{enum LSA_CREDENTIAL_KEY_SOURCE_TYPE { + eFromPrecomputed = 1, + eFromClearPassword, + eFromNtOwf, +}} +pub type PLSA_CREDENTIAL_KEY_SOURCE_TYPE = *mut LSA_CREDENTIAL_KEY_SOURCE_TYPE; +extern "C" { + pub fn SeciIsProtectedUser( + ProtectedUser: PBOOLEAN, + ) -> NTSTATUS; +} diff --git a/winapi/src/um/ntsecapi.rs b/winapi/src/um/ntsecapi.rs new file mode 100644 index 000000000..cf30ea929 --- /dev/null +++ b/winapi/src/um/ntsecapi.rs @@ -0,0 +1,1728 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the Local Security Authority APIs. +use shared::basetsd::{ULONG64, ULONG_PTR}; +use shared::guiddef::GUID; +use shared::minwindef::{PUCHAR, PULONG, UCHAR, ULONG, USHORT}; +use shared::ntdef::NTSTATUS; +use shared::sspi::SecHandle; +use um::lsalookup::{ + LSA_TRUST_INFORMATION, LSA_UNICODE_STRING, PLSA_TRUST_INFORMATION, PLSA_UNICODE_STRING +}; +use um::subauth::{PUNICODE_STRING, STRING, UNICODE_STRING}; +use um::winnt::{ + ACCESS_MASK, ANYSIZE_ARRAY, BOOLEAN, HANDLE, LARGE_INTEGER, LONG, LUID, PACL, PCSTR, PCWSTR, + PSECURITY_DESCRIPTOR, PSID, PSTR, PVOID, PWSTR, QUOTA_LIMITS, SECURITY_INFORMATION, SHORT, SID, + SID_NAME_USE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_READ, STANDARD_RIGHTS_REQUIRED, + STANDARD_RIGHTS_WRITE, ULONGLONG +}; +DEFINE_GUID!{Audit_System_SecurityStateChange, + 0x0cce9210, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_System_SecuritySubsystemExtension, + 0x0cce9211, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_System_Integrity, + 0x0cce9212, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_System_IPSecDriverEvents, + 0x0cce9213, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_System_Others, + 0x0cce9214, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_Logon, + 0x0cce9215, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_Logoff, + 0x0cce9216, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_AccountLockout, + 0x0cce9217, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_IPSecMainMode, + 0x0cce9218, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_IPSecQuickMode, + 0x0cce9219, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_IPSecUserMode, + 0x0cce921a, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_SpecialLogon, + 0x0cce921b, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_Others, + 0x0cce921c, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_FileSystem, + 0x0cce921d, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Registry, + 0x0cce921e, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Kernel, + 0x0cce921f, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Sam, + 0x0cce9220, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_CertificationServices, + 0x0cce9221, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_ApplicationGenerated, + 0x0cce9222, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Handle, + 0x0cce9223, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Share, + 0x0cce9224, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_FirewallPacketDrops, + 0x0cce9225, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_FirewallConnection, + 0x0cce9226, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_Other, + 0x0cce9227, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PrivilegeUse_Sensitive, + 0x0cce9228, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PrivilegeUse_NonSensitive, + 0x0cce9229, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PrivilegeUse_Others, + 0x0cce922a, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DetailedTracking_ProcessCreation, + 0x0cce922b, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DetailedTracking_ProcessTermination, + 0x0cce922c, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DetailedTracking_DpapiActivity, + 0x0cce922d, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DetailedTracking_RpcCall, + 0x0cce922e, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_AuditPolicy, + 0x0cce922f, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_AuthenticationPolicy, + 0x0cce9230, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_AuthorizationPolicy, + 0x0cce9231, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_MpsscvRulePolicy, + 0x0cce9232, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_WfpIPSecPolicy, + 0x0cce9233, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange_Others, + 0x0cce9234, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_UserAccount, + 0x0cce9235, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_ComputerAccount, + 0x0cce9236, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_SecurityGroup, + 0x0cce9237, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_DistributionGroup, + 0x0cce9238, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_ApplicationGroup, + 0x0cce9239, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement_Others, + 0x0cce923a, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DSAccess_DSAccess, + 0x0cce923b, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DsAccess_AdAuditChanges, + 0x0cce923c, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Ds_Replication, + 0x0cce923d, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Ds_DetailedReplication, + 0x0cce923e, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountLogon_CredentialValidation, + 0x0cce923f, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountLogon_Kerberos, + 0x0cce9240, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountLogon_Others, + 0x0cce9241, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountLogon_KerbCredentialValidation, + 0x0cce9242, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_NPS, + 0x0cce9243, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_DetailedFileShare, + 0x0cce9244, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_RemovableStorage, + 0x0cce9245, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess_CbacStaging, + 0x0cce9246, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon_Claims, + 0x0cce9247, 0x69ae, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_System, + 0x69979848, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_Logon, + 0x69979849, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_ObjectAccess, + 0x6997984a, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PrivilegeUse, + 0x6997984b, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DetailedTracking, + 0x6997984c, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_PolicyChange, + 0x6997984d, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountManagement, + 0x6997984e, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_DirectoryServiceAccess, + 0x6997984f, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +DEFINE_GUID!{Audit_AccountLogon, + 0x69979850, 0x797a, 0x11d9, 0xbe, 0xd3, 0x50, 0x50, 0x54, 0x50, 0x30, 0x30} +ENUM!{enum POLICY_AUDIT_EVENT_TYPE { + AuditCategorySystem = 0, + AuditCategoryLogon, + AuditCategoryObjectAccess, + AuditCategoryPrivilegeUse, + AuditCategoryDetailedTracking, + AuditCategoryPolicyChange, + AuditCategoryAccountManagement, + AuditCategoryDirectoryServiceAccess, + AuditCategoryAccountLogon, +}} +pub type PPOLICY_AUDIT_EVENT_TYPE = *mut POLICY_AUDIT_EVENT_TYPE; +pub const POLICY_AUDIT_EVENT_UNCHANGED: POLICY_AUDIT_EVENT_OPTIONS = 0x00000000; +pub const POLICY_AUDIT_EVENT_SUCCESS: POLICY_AUDIT_EVENT_OPTIONS = 0x00000001; +pub const POLICY_AUDIT_EVENT_FAILURE: POLICY_AUDIT_EVENT_OPTIONS = 0x00000002; +pub const POLICY_AUDIT_EVENT_NONE: POLICY_AUDIT_EVENT_OPTIONS = 0x00000004; +pub const POLICY_AUDIT_EVENT_MASK: POLICY_AUDIT_EVENT_OPTIONS = POLICY_AUDIT_EVENT_SUCCESS + | POLICY_AUDIT_EVENT_FAILURE | POLICY_AUDIT_EVENT_UNCHANGED | POLICY_AUDIT_EVENT_NONE; +pub const POLICY_VIEW_LOCAL_INFORMATION: ACCESS_MASK = 0x00000001; +pub const POLICY_VIEW_AUDIT_INFORMATION: ACCESS_MASK = 0x00000002; +pub const POLICY_GET_PRIVATE_INFORMATION: ACCESS_MASK = 0x00000004; +pub const POLICY_TRUST_ADMIN: ACCESS_MASK = 0x00000008; +pub const POLICY_CREATE_ACCOUNT: ACCESS_MASK = 0x00000010; +pub const POLICY_CREATE_SECRET: ACCESS_MASK = 0x00000020; +pub const POLICY_CREATE_PRIVILEGE: ACCESS_MASK = 0x00000040; +pub const POLICY_SET_DEFAULT_QUOTA_LIMITS: ACCESS_MASK = 0x00000080; +pub const POLICY_SET_AUDIT_REQUIREMENTS: ACCESS_MASK = 0x00000100; +pub const POLICY_AUDIT_LOG_ADMIN: ACCESS_MASK = 0x00000200; +pub const POLICY_SERVER_ADMIN: ACCESS_MASK = 0x00000400; +pub const POLICY_LOOKUP_NAMES: ACCESS_MASK = 0x00000800; +pub const POLICY_NOTIFICATION: ACCESS_MASK = 0x00001000; +pub const POLICY_ALL_ACCESS: ACCESS_MASK = STANDARD_RIGHTS_REQUIRED + | POLICY_VIEW_LOCAL_INFORMATION | POLICY_VIEW_AUDIT_INFORMATION + | POLICY_GET_PRIVATE_INFORMATION | POLICY_TRUST_ADMIN | POLICY_CREATE_ACCOUNT + | POLICY_CREATE_SECRET | POLICY_CREATE_PRIVILEGE | POLICY_SET_DEFAULT_QUOTA_LIMITS + | POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN | POLICY_SERVER_ADMIN + | POLICY_LOOKUP_NAMES; +pub const POLICY_READ: ACCESS_MASK = STANDARD_RIGHTS_READ | POLICY_VIEW_AUDIT_INFORMATION + | POLICY_GET_PRIVATE_INFORMATION; +pub const POLICY_WRITE: ACCESS_MASK = STANDARD_RIGHTS_WRITE | POLICY_TRUST_ADMIN + | POLICY_CREATE_ACCOUNT | POLICY_CREATE_SECRET | POLICY_CREATE_PRIVILEGE + | POLICY_SET_DEFAULT_QUOTA_LIMITS | POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN + | POLICY_SERVER_ADMIN; +pub const POLICY_EXECUTE: ACCESS_MASK = STANDARD_RIGHTS_EXECUTE + | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES; +STRUCT!{struct LSA_TRANSLATED_SID { + Use: SID_NAME_USE, + RelativeId: ULONG, + DomainIndex: LONG, +}} +pub type PLSA_TRANSLATED_SID = *mut LSA_TRANSLATED_SID; +ENUM!{enum POLICY_LSA_SERVER_ROLE { + PolicyServerRoleBackup = 2, + PolicyServerRolePrimary, +}} +pub type PPOLICY_LSA_SERVER_ROLE = *mut POLICY_LSA_SERVER_ROLE; +pub type POLICY_AUDIT_EVENT_OPTIONS = ULONG; +pub type PPOLICY_AUDIT_EVENT_OPTIONS = *mut ULONG; +ENUM!{enum POLICY_INFORMATION_CLASS { + PolicyAuditLogInformation = 1, + PolicyAuditEventsInformation, + PolicyPrimaryDomainInformation, + PolicyPdAccountInformation, + PolicyAccountDomainInformation, + PolicyLsaServerRoleInformation, + PolicyReplicaSourceInformation, + PolicyDefaultQuotaInformation, + PolicyModificationInformation, + PolicyAuditFullSetInformation, + PolicyAuditFullQueryInformation, + PolicyDnsDomainInformation, + PolicyDnsDomainInformationInt, + PolicyLocalAccountDomainInformation, + PolicyLastEntry, +}} +pub type PPOLICY_INFORMATION_CLASS = *mut POLICY_INFORMATION_CLASS; +STRUCT!{struct POLICY_AUDIT_LOG_INFO { + AuditLogPercentFull: ULONG, + MaximumLogSize: ULONG, + AuditRetentionPeriod: LARGE_INTEGER, + AuditLogFullShutdownInProgress: BOOLEAN, + TimeToShutdown: LARGE_INTEGER, + NextAuditRecordId: ULONG, +}} +pub type PPOLICY_AUDIT_LOG_INFO = *mut POLICY_AUDIT_LOG_INFO; +STRUCT!{struct POLICY_AUDIT_EVENTS_INFO { + AuditingMode: BOOLEAN, + EventAuditingOptions: PPOLICY_AUDIT_EVENT_OPTIONS, + MaximumAuditEventCount: ULONG, +}} +pub type PPOLICY_AUDIT_EVENTS_INFO = *mut POLICY_AUDIT_EVENTS_INFO; +STRUCT!{struct POLICY_AUDIT_SUBCATEGORIES_INFO { + MaximumSubCategoryCount: ULONG, + EventAuditingOptions: PPOLICY_AUDIT_EVENT_OPTIONS, +}} +pub type PPOLICY_AUDIT_SUBCATEGORIES_INFO = *mut POLICY_AUDIT_SUBCATEGORIES_INFO; +STRUCT!{struct POLICY_AUDIT_CATEGORIES_INFO { + MaximumSubCategoryCount: ULONG, + SubCategoriesInfo: PPOLICY_AUDIT_SUBCATEGORIES_INFO, +}} +pub type PPOLICY_AUDIT_CATEGORIES_INFO = *mut POLICY_AUDIT_CATEGORIES_INFO; +pub const PER_USER_POLICY_UNCHANGED: ULONG = 0x00; +pub const PER_USER_AUDIT_SUCCESS_INCLUDE: ULONG = 0x01; +pub const PER_USER_AUDIT_SUCCESS_EXCLUDE: ULONG = 0x02; +pub const PER_USER_AUDIT_FAILURE_INCLUDE: ULONG = 0x04; +pub const PER_USER_AUDIT_FAILURE_EXCLUDE: ULONG = 0x08; +pub const PER_USER_AUDIT_NONE: ULONG = 0x10; +pub const VALID_PER_USER_AUDIT_POLICY_FLAG: ULONG = PER_USER_AUDIT_SUCCESS_INCLUDE + | PER_USER_AUDIT_SUCCESS_EXCLUDE | PER_USER_AUDIT_FAILURE_INCLUDE + | PER_USER_AUDIT_FAILURE_EXCLUDE | PER_USER_AUDIT_NONE; +STRUCT!{struct POLICY_PRIMARY_DOMAIN_INFO { + Name: LSA_UNICODE_STRING, + Sid: PSID, +}} +pub type PPOLICY_PRIMARY_DOMAIN_INFO = *mut POLICY_PRIMARY_DOMAIN_INFO; +STRUCT!{struct POLICY_PD_ACCOUNT_INFO { + Name: LSA_UNICODE_STRING, +}} +pub type PPOLICY_PD_ACCOUNT_INFO = *mut POLICY_PD_ACCOUNT_INFO; +STRUCT!{struct POLICY_LSA_SERVER_ROLE_INFO { + LsaServerRole: POLICY_LSA_SERVER_ROLE, +}} +pub type PPOLICY_LSA_SERVER_ROLE_INFO = *mut POLICY_LSA_SERVER_ROLE_INFO; +STRUCT!{struct POLICY_REPLICA_SOURCE_INFO { + ReplicaSource: LSA_UNICODE_STRING, + ReplicaAccountName: LSA_UNICODE_STRING, +}} +pub type PPOLICY_REPLICA_SOURCE_INFO = *mut POLICY_REPLICA_SOURCE_INFO; +STRUCT!{struct POLICY_DEFAULT_QUOTA_INFO { + QuotaLimits: QUOTA_LIMITS, +}} +pub type PPOLICY_DEFAULT_QUOTA_INFO = *mut POLICY_DEFAULT_QUOTA_INFO; +STRUCT!{struct POLICY_MODIFICATION_INFO { + ModifiedId: LARGE_INTEGER, + DatabaseCreationTime: LARGE_INTEGER, +}} +pub type PPOLICY_MODIFICATION_INFO = *mut POLICY_MODIFICATION_INFO; +STRUCT!{struct POLICY_AUDIT_FULL_SET_INFO { + ShutDownOnFull: BOOLEAN, +}} +pub type PPOLICY_AUDIT_FULL_SET_INFO = *mut POLICY_AUDIT_FULL_SET_INFO; +STRUCT!{struct POLICY_AUDIT_FULL_QUERY_INFO { + ShutDownOnFull: BOOLEAN, + LogIsFull: BOOLEAN, +}} +pub type PPOLICY_AUDIT_FULL_QUERY_INFO = *mut POLICY_AUDIT_FULL_QUERY_INFO; +ENUM!{enum POLICY_DOMAIN_INFORMATION_CLASS { + PolicyDomainEfsInformation = 2, + PolicyDomainKerberosTicketInformation, +}} +pub type PPOLICY_DOMAIN_INFORMATION_CLASS = *mut POLICY_DOMAIN_INFORMATION_CLASS; +STRUCT!{struct POLICY_DOMAIN_EFS_INFO { + InfoLength: ULONG, + EfsBlob: PUCHAR, +}} +pub type PPOLICY_DOMAIN_EFS_INFO = *mut POLICY_DOMAIN_EFS_INFO; +STRUCT!{struct POLICY_DOMAIN_KERBEROS_TICKET_INFO { + AuthenticationOptions: ULONG, + MaxServiceTicketAge: LARGE_INTEGER, + MaxTicketAge: LARGE_INTEGER, + MaxRenewAge: LARGE_INTEGER, + MaxClockSkew: LARGE_INTEGER, + Reserved: LARGE_INTEGER, +}} +pub type PPOLICY_DOMAIN_KERBEROS_TICKET_INFO = *mut POLICY_DOMAIN_KERBEROS_TICKET_INFO; +ENUM!{enum POLICY_NOTIFICATION_INFORMATION_CLASS { + PolicyNotifyAuditEventsInformation = 1, + PolicyNotifyAccountDomainInformation, + PolicyNotifyServerRoleInformation, + PolicyNotifyDnsDomainInformation, + PolicyNotifyDomainEfsInformation, + PolicyNotifyDomainKerberosTicketInformation, + PolicyNotifyMachineAccountPasswordInformation, + PolicyNotifyGlobalSaclInformation, + PolicyNotifyMax, +}} +pub type PPOLICY_NOTIFICATION_INFORMATION_CLASS = *mut POLICY_NOTIFICATION_INFORMATION_CLASS; +pub type LSA_HANDLE = PVOID; +pub type PLSA_HANDLE = *mut PVOID; +ENUM!{enum TRUSTED_INFORMATION_CLASS { + TrustedDomainNameInformation = 1, + TrustedControllersInformation, + TrustedPosixOffsetInformation, + TrustedPasswordInformation, + TrustedDomainInformationBasic, + TrustedDomainInformationEx, + TrustedDomainAuthInformation, + TrustedDomainFullInformation, + TrustedDomainAuthInformationInternal, + TrustedDomainFullInformationInternal, + TrustedDomainInformationEx2Internal, + TrustedDomainFullInformation2Internal, + TrustedDomainSupportedEncryptionTypes, +}} +pub type PTRUSTED_INFORMATION_CLASS = *mut TRUSTED_INFORMATION_CLASS; +STRUCT!{struct TRUSTED_DOMAIN_NAME_INFO { + Name: LSA_UNICODE_STRING, +}} +pub type PTRUSTED_DOMAIN_NAME_INFO = *mut TRUSTED_DOMAIN_NAME_INFO; +STRUCT!{struct TRUSTED_CONTROLLERS_INFO { + Entries: ULONG, + Names: PLSA_UNICODE_STRING, +}} +pub type PTRUSTED_CONTROLLERS_INFO = *mut TRUSTED_CONTROLLERS_INFO; +STRUCT!{struct TRUSTED_POSIX_OFFSET_INFO { + Offset: ULONG, +}} +pub type PTRUSTED_POSIX_OFFSET_INFO = *mut TRUSTED_POSIX_OFFSET_INFO; +STRUCT!{struct TRUSTED_PASSWORD_INFO { + Password: LSA_UNICODE_STRING, + OldPassword: LSA_UNICODE_STRING, +}} +pub type PTRUSTED_PASSWORD_INFO = *mut TRUSTED_PASSWORD_INFO; +pub type TRUSTED_DOMAIN_INFORMATION_BASIC = LSA_TRUST_INFORMATION; +pub type PTRUSTED_DOMAIN_INFORMATION_BASIC = PLSA_TRUST_INFORMATION; +pub const TRUST_DIRECTION_DISABLED: ULONG = 0x00000000; +pub const TRUST_DIRECTION_INBOUND: ULONG = 0x00000001; +pub const TRUST_DIRECTION_OUTBOUND: ULONG = 0x00000002; +pub const TRUST_DIRECTION_BIDIRECTIONAL: ULONG = TRUST_DIRECTION_INBOUND + | TRUST_DIRECTION_OUTBOUND; +pub const TRUST_TYPE_DOWNLEVEL: ULONG = 0x00000001; +pub const TRUST_TYPE_UPLEVEL: ULONG = 0x00000002; +pub const TRUST_TYPE_MIT: ULONG = 0x00000003; +pub const TRUST_ATTRIBUTE_NON_TRANSITIVE: ULONG = 0x00000001; +pub const TRUST_ATTRIBUTE_UPLEVEL_ONLY: ULONG = 0x00000002; +pub const TRUST_ATTRIBUTE_QUARANTINED_DOMAIN: ULONG = 0x00000004; +pub const TRUST_ATTRIBUTE_FOREST_TRANSITIVE: ULONG = 0x00000008; +pub const TRUST_ATTRIBUTE_CROSS_ORGANIZATION: ULONG = 0x00000010; +pub const TRUST_ATTRIBUTE_WITHIN_FOREST: ULONG = 0x00000020; +pub const TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL: ULONG = 0x00000040; +pub const TRUST_ATTRIBUTE_TRUST_USES_RC4_ENCRYPTION: ULONG = 0x00000080; +pub const TRUST_ATTRIBUTE_TRUST_USES_AES_KEYS: ULONG = 0x00000100; +pub const TRUST_ATTRIBUTE_CROSS_ORGANIZATION_NO_TGT_DELEGATION: ULONG = 0x00000200; +pub const TRUST_ATTRIBUTES_VALID: ULONG = 0xFF03FFFF; +pub const TRUST_ATTRIBUTES_USER: ULONG = 0xFF000000; +STRUCT!{struct TRUSTED_DOMAIN_INFORMATION_EX { + Name: LSA_UNICODE_STRING, + FlatName: LSA_UNICODE_STRING, + Sid: PSID, + TrustDirection: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, +}} +pub type PTRUSTED_DOMAIN_INFORMATION_EX = *mut TRUSTED_DOMAIN_INFORMATION_EX; +STRUCT!{struct TRUSTED_DOMAIN_INFORMATION_EX2 { + Name: LSA_UNICODE_STRING, + FlatName: LSA_UNICODE_STRING, + Sid: PSID, + TrustDirection: ULONG, + TrustType: ULONG, + TrustAttributes: ULONG, + ForestTrustLength: ULONG, + ForestTrustInfo: PUCHAR, +}} +pub type PTRUSTED_DOMAIN_INFORMATION_EX2 = *mut TRUSTED_DOMAIN_INFORMATION_EX2; +pub const TRUST_AUTH_TYPE_NONE: ULONG = 0; +pub const TRUST_AUTH_TYPE_NT4OWF: ULONG = 1; +pub const TRUST_AUTH_TYPE_CLEAR: ULONG = 2; +pub const TRUST_AUTH_TYPE_VERSION: ULONG = 3; +STRUCT!{struct LSA_AUTH_INFORMATION { + LastUpdateTime: LARGE_INTEGER, + AuthType: ULONG, + AuthInfoLength: ULONG, + AuthInfo: PUCHAR, +}} +pub type PLSA_AUTH_INFORMATION = *mut LSA_AUTH_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_AUTH_INFORMATION { + IncomingAuthInfos: ULONG, + IncomingAuthenticationInformation: PLSA_AUTH_INFORMATION, + IncomingPreviousAuthenticationInformation: PLSA_AUTH_INFORMATION, + OutgoingAuthInfos: ULONG, + OutgoingAuthenticationInformation: PLSA_AUTH_INFORMATION, + OutgoingPreviousAuthenticationInformation: PLSA_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_AUTH_INFORMATION = *mut TRUSTED_DOMAIN_AUTH_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_FULL_INFORMATION { + Information: TRUSTED_DOMAIN_INFORMATION_EX, + PosixOffset: TRUSTED_POSIX_OFFSET_INFO, + AuthInformation: TRUSTED_DOMAIN_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_FULL_INFORMATION = *mut TRUSTED_DOMAIN_FULL_INFORMATION; +STRUCT!{struct TRUSTED_DOMAIN_FULL_INFORMATION2 { + Information: TRUSTED_DOMAIN_INFORMATION_EX2, + PosixOffset: TRUSTED_POSIX_OFFSET_INFO, + AuthInformation: TRUSTED_DOMAIN_AUTH_INFORMATION, +}} +pub type PTRUSTED_DOMAIN_FULL_INFORMATION2 = *mut TRUSTED_DOMAIN_FULL_INFORMATION2; +STRUCT!{struct TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES { + SupportedEncryptionTypes: ULONG, +}} +pub type PTRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES = + *mut TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES; +ENUM!{enum LSA_FOREST_TRUST_RECORD_TYPE { + ForestTrustTopLevelName, + ForestTrustTopLevelNameEx, + ForestTrustDomainInfo, + ForestTrustRecordTypeLast, // = ForestTrustDomainInfo, +}} +pub const LSA_FTRECORD_DISABLED_REASONS: ULONG = 0x0000FFFF; +pub const LSA_TLN_DISABLED_NEW: ULONG = 0x00000001; +pub const LSA_TLN_DISABLED_ADMIN: ULONG = 0x00000002; +pub const LSA_TLN_DISABLED_CONFLICT: ULONG = 0x00000004; +pub const LSA_SID_DISABLED_ADMIN: ULONG = 0x00000001; +pub const LSA_SID_DISABLED_CONFLICT: ULONG = 0x00000002; +pub const LSA_NB_DISABLED_ADMIN: ULONG = 0x00000004; +pub const LSA_NB_DISABLED_CONFLICT: ULONG = 0x00000008; +STRUCT!{struct LSA_FOREST_TRUST_DOMAIN_INFO { + Sid: PSID, + DnsName: LSA_UNICODE_STRING, + NetbiosName: LSA_UNICODE_STRING, +}} +pub type PLSA_FOREST_TRUST_DOMAIN_INFO = *mut LSA_FOREST_TRUST_DOMAIN_INFO; +pub const MAX_FOREST_TRUST_BINARY_DATA_SIZE: ULONG = 128 * 1024; +STRUCT!{struct LSA_FOREST_TRUST_BINARY_DATA { + Length: ULONG, + Buffer: PUCHAR, +}} +pub type PLSA_FOREST_TRUST_BINARY_DATA = *mut LSA_FOREST_TRUST_BINARY_DATA; +UNION!{union LSA_FOREST_TRUST_RECORD_ForestTrustData { + [usize; 5], + TopLevelName TopLevelName_mut: LSA_UNICODE_STRING, + DomainInfo DomainInfo_mut: LSA_FOREST_TRUST_DOMAIN_INFO, + Data Data_mut: LSA_FOREST_TRUST_BINARY_DATA, +}} +STRUCT!{struct LSA_FOREST_TRUST_RECORD { + Flags: ULONG, + ForestTrustType: LSA_FOREST_TRUST_RECORD_TYPE, + Time: LARGE_INTEGER, + ForestTrustData: LSA_FOREST_TRUST_RECORD_ForestTrustData, +}} +pub type PLSA_FOREST_TRUST_RECORD = *mut LSA_FOREST_TRUST_RECORD; +pub const MAX_RECORDS_IN_FOREST_TRUST_INFO: ULONG = 4000; +STRUCT!{struct LSA_FOREST_TRUST_INFORMATION { + RecordCount: ULONG, + Entries: *mut PLSA_FOREST_TRUST_RECORD, +}} +pub type PLSA_FOREST_TRUST_INFORMATION = *mut LSA_FOREST_TRUST_INFORMATION; +ENUM!{enum LSA_FOREST_TRUST_COLLISION_RECORD_TYPE { + CollisionTdo, + CollisionXref, + CollisionOther, +}} +STRUCT!{struct LSA_FOREST_TRUST_COLLISION_RECORD { + Index: ULONG, + Type: LSA_FOREST_TRUST_COLLISION_RECORD_TYPE, + Flags: ULONG, + Name: LSA_UNICODE_STRING, +}} +pub type PLSA_FOREST_TRUST_COLLISION_RECORD = *mut LSA_FOREST_TRUST_COLLISION_RECORD; +STRUCT!{struct LSA_FOREST_TRUST_COLLISION_INFORMATION { + RecordCount: ULONG, + Entries: *mut PLSA_FOREST_TRUST_COLLISION_RECORD, +}} +pub type PLSA_FOREST_TRUST_COLLISION_INFORMATION = *mut LSA_FOREST_TRUST_COLLISION_INFORMATION; +pub type LSA_ENUMERATION_HANDLE = ULONG; +pub type PLSA_ENUMERATION_HANDLE = *mut ULONG; +STRUCT!{struct LSA_ENUMERATION_INFORMATION { + Sid: PSID, +}} +pub type PLSA_ENUMERATION_INFORMATION = *mut LSA_ENUMERATION_INFORMATION; +STRUCT!{struct LSA_LAST_INTER_LOGON_INFO { + LastSuccessfulLogon: LARGE_INTEGER, + LastFailedLogon: LARGE_INTEGER, + FailedAttemptCountSinceLastSuccessfulLogon: ULONG, +}} +pub type PLSA_LAST_INTER_LOGON_INFO = *mut LSA_LAST_INTER_LOGON_INFO; +STRUCT!{struct SECURITY_LOGON_SESSION_DATA { + Size: ULONG, + LogonId: LUID, + UserName: LSA_UNICODE_STRING, + LogonDomain: LSA_UNICODE_STRING, + AuthenticationPackage: LSA_UNICODE_STRING, + LogonType: ULONG, + Session: ULONG, + Sid: PSID, + LogonTime: LARGE_INTEGER, + LogonServer: LSA_UNICODE_STRING, + DnsDomainName: LSA_UNICODE_STRING, + Upn: LSA_UNICODE_STRING, + UserFlags: ULONG, + LastLogonInfo: LSA_LAST_INTER_LOGON_INFO, + LogonScript: LSA_UNICODE_STRING, + ProfilePath: LSA_UNICODE_STRING, + HomeDirectory: LSA_UNICODE_STRING, + HomeDirectoryDrive: LSA_UNICODE_STRING, + LogoffTime: LARGE_INTEGER, + KickOffTime: LARGE_INTEGER, + PasswordLastSet: LARGE_INTEGER, + PasswordCanChange: LARGE_INTEGER, + PasswordMustChange: LARGE_INTEGER, +}} +pub type PSECURITY_LOGON_SESSION_DATA = *mut SECURITY_LOGON_SESSION_DATA; +pub const CENTRAL_ACCESS_POLICY_OWNER_RIGHTS_PRESENT_FLAG: ULONG = 0x00000001; +pub const CENTRAL_ACCESS_POLICY_STAGED_OWNER_RIGHTS_PRESENT_FLAG: ULONG = 0x00000100; +pub const CENTRAL_ACCESS_POLICY_STAGED_FLAG: ULONG = 0x00010000; +pub const CENTRAL_ACCESS_POLICY_VALID_FLAG_MASK: ULONG = + CENTRAL_ACCESS_POLICY_OWNER_RIGHTS_PRESENT_FLAG + | CENTRAL_ACCESS_POLICY_STAGED_OWNER_RIGHTS_PRESENT_FLAG + | CENTRAL_ACCESS_POLICY_STAGED_FLAG; +pub const LSASETCAPS_RELOAD_FLAG: ULONG = 0x00000001; +pub const LSASETCAPS_VALID_FLAG_MASK: ULONG = LSASETCAPS_RELOAD_FLAG; +STRUCT!{struct CENTRAL_ACCESS_POLICY_ENTRY { + Name: LSA_UNICODE_STRING, + Description: LSA_UNICODE_STRING, + ChangeId: LSA_UNICODE_STRING, + LengthAppliesTo: ULONG, + AppliesTo: PUCHAR, + LengthSD: ULONG, + SD: PSECURITY_DESCRIPTOR, + LengthStagedSD: ULONG, + StagedSD: PSECURITY_DESCRIPTOR, + Flags: ULONG, +}} +pub type PCENTRAL_ACCESS_POLICY_ENTRY = *mut CENTRAL_ACCESS_POLICY_ENTRY; +pub type PCCENTRAL_ACCESS_POLICY_ENTRY = *const CENTRAL_ACCESS_POLICY_ENTRY; +STRUCT!{struct CENTRAL_ACCESS_POLICY { + CAPID: PSID, + Name: LSA_UNICODE_STRING, + Description: LSA_UNICODE_STRING, + ChangeId: LSA_UNICODE_STRING, + Flags: ULONG, + CAPECount: ULONG, + CAPEs: *mut PCENTRAL_ACCESS_POLICY_ENTRY, +}} +pub type PCENTRAL_ACCESS_POLICY = *mut CENTRAL_ACCESS_POLICY; +pub type PCCENTRAL_ACCESS_POLICY = *const CENTRAL_ACCESS_POLICY; +ENUM!{enum NEGOTIATE_MESSAGES { + NegEnumPackagePrefixes = 0, + NegGetCallerName = 1, + NegTransferCredentials = 2, + NegCallPackageMax, +}} +pub const NEGOTIATE_MAX_PREFIX: usize = 32; +STRUCT!{struct NEGOTIATE_PACKAGE_PREFIX { + PackageId: ULONG_PTR, + PackageDataA: PVOID, + PackageDataW: PVOID, + PrefixLen: ULONG_PTR, + Prefix: [UCHAR; NEGOTIATE_MAX_PREFIX], +}} +pub type PNEGOTIATE_PACKAGE_PREFIX = *mut NEGOTIATE_PACKAGE_PREFIX; +STRUCT!{struct NEGOTIATE_PACKAGE_PREFIXES { + MessageType: ULONG, + PrefixCount: ULONG, + Offset: ULONG, + Pad: ULONG, +}} +pub type PNEGOTIATE_PACKAGE_PREFIXES = *mut NEGOTIATE_PACKAGE_PREFIXES; +STRUCT!{struct NEGOTIATE_CALLER_NAME_REQUEST { + MessageType: ULONG, + LogonId: LUID, +}} +pub type PNEGOTIATE_CALLER_NAME_REQUEST = *mut NEGOTIATE_CALLER_NAME_REQUEST; +STRUCT!{struct NEGOTIATE_CALLER_NAME_RESPONSE { + MessageType: ULONG, + CallerName: PWSTR, +}} +pub type PNEGOTIATE_CALLER_NAME_RESPONSE = *mut NEGOTIATE_CALLER_NAME_RESPONSE; +STRUCT!{struct DOMAIN_PASSWORD_INFORMATION { + MinPasswordLength: USHORT, + PasswordHistoryLength: USHORT, + PasswordProperties: ULONG, + MaxPasswordAge: LARGE_INTEGER, + MinPasswordAge: LARGE_INTEGER, +}} +pub type PDOMAIN_PASSWORD_INFORMATION = *mut DOMAIN_PASSWORD_INFORMATION; +pub const DOMAIN_PASSWORD_COMPLEX: ULONG = 0x00000001; +pub const DOMAIN_PASSWORD_NO_ANON_CHANGE: ULONG = 0x00000002; +pub const DOMAIN_PASSWORD_NO_CLEAR_CHANGE: ULONG = 0x00000004; +pub const DOMAIN_LOCKOUT_ADMINS: ULONG = 0x00000008; +pub const DOMAIN_PASSWORD_STORE_CLEARTEXT: ULONG = 0x00000010; +pub const DOMAIN_REFUSE_PASSWORD_CHANGE: ULONG = 0x00000020; +pub const DOMAIN_NO_LM_OWF_CHANGE: ULONG = 0x00000040; +FN!{stdcall PSAM_PASSWORD_NOTIFICATION_ROUTINE( + UserName: PUNICODE_STRING, + RelativeId: ULONG, + NewPassword: PUNICODE_STRING, +) -> NTSTATUS} +FN!{stdcall PSAM_INIT_NOTIFICATION_ROUTINE() -> BOOLEAN} +FN!{stdcall PSAM_PASSWORD_FILTER_ROUTINE( + AccountName: PUNICODE_STRING, + FullName: PUNICODE_STRING, + Password: PUNICODE_STRING, + SetOperation: BOOLEAN, +) -> BOOLEAN} +ENUM!{enum MSV1_0_LOGON_SUBMIT_TYPE { + MsV1_0InteractiveLogon = 2, + MsV1_0Lm20Logon, + MsV1_0NetworkLogon, + MsV1_0SubAuthLogon, + MsV1_0WorkstationUnlockLogon = 7, + MsV1_0S4ULogon = 12, + MsV1_0VirtualLogon = 82, + MsV1_0NoElevationLogon = 83, + MsV1_0LuidLogon = 84, +}} +pub type PMSV1_0_LOGON_SUBMIT_TYPE = *mut MSV1_0_LOGON_SUBMIT_TYPE; +ENUM!{enum MSV1_0_PROFILE_BUFFER_TYPE { + MsV1_0InteractiveProfile = 2, + MsV1_0Lm20LogonProfile, + MsV1_0SmartCardProfile, +}} +pub type PMSV1_0_PROFILE_BUFFER_TYPE = *mut MSV1_0_PROFILE_BUFFER_TYPE; +STRUCT!{struct MSV1_0_INTERACTIVE_LOGON { + MessageType: MSV1_0_LOGON_SUBMIT_TYPE, + LogonDomainName: UNICODE_STRING, + UserName: UNICODE_STRING, + Password: UNICODE_STRING, +}} +pub type PMSV1_0_INTERACTIVE_LOGON = *mut MSV1_0_INTERACTIVE_LOGON; +STRUCT!{struct MSV1_0_INTERACTIVE_PROFILE { + MessageType: MSV1_0_PROFILE_BUFFER_TYPE, + LogonCount: USHORT, + BadPasswordCount: USHORT, + LogonTime: LARGE_INTEGER, + LogoffTime: LARGE_INTEGER, + KickOffTime: LARGE_INTEGER, + PasswordLastSet: LARGE_INTEGER, + PasswordCanChange: LARGE_INTEGER, + PasswordMustChange: LARGE_INTEGER, + LogonScript: UNICODE_STRING, + HomeDirectory: UNICODE_STRING, + FullName: UNICODE_STRING, + ProfilePath: UNICODE_STRING, + HomeDirectoryDrive: UNICODE_STRING, + LogonServer: UNICODE_STRING, + UserFlags: ULONG, +}} +pub type PMSV1_0_INTERACTIVE_PROFILE = *mut MSV1_0_INTERACTIVE_PROFILE; +pub const MSV1_0_CHALLENGE_LENGTH: usize = 8; +pub const MSV1_0_USER_SESSION_KEY_LENGTH: usize = 16; +pub const MSV1_0_LANMAN_SESSION_KEY_LENGTH: usize = 8; +pub const MSV1_0_CLEARTEXT_PASSWORD_ALLOWED: ULONG = 0x02; +pub const MSV1_0_UPDATE_LOGON_STATISTICS: ULONG = 0x04; +pub const MSV1_0_RETURN_USER_PARAMETERS: ULONG = 0x08; +pub const MSV1_0_DONT_TRY_GUEST_ACCOUNT: ULONG = 0x10; +pub const MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT: ULONG = 0x20; +pub const MSV1_0_RETURN_PASSWORD_EXPIRY: ULONG = 0x40; +pub const MSV1_0_USE_CLIENT_CHALLENGE: ULONG = 0x80; +pub const MSV1_0_TRY_GUEST_ACCOUNT_ONLY: ULONG = 0x100; +pub const MSV1_0_RETURN_PROFILE_PATH: ULONG = 0x200; +pub const MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY: ULONG = 0x400; +pub const MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT: ULONG = 0x800; +pub const MSV1_0_DISABLE_PERSONAL_FALLBACK: ULONG = 0x00001000; +pub const MSV1_0_ALLOW_FORCE_GUEST: ULONG = 0x00002000; +pub const MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED: ULONG = 0x00004000; +pub const MSV1_0_USE_DOMAIN_FOR_ROUTING_ONLY: ULONG = 0x00008000; +pub const MSV1_0_SUBAUTHENTICATION_DLL_EX: ULONG = 0x00100000; +pub const MSV1_0_ALLOW_MSVCHAPV2: ULONG = 0x00010000; +pub const MSV1_0_S4U2SELF: ULONG = 0x00020000; +pub const MSV1_0_CHECK_LOGONHOURS_FOR_S4U: ULONG = 0x00040000; +pub const MSV1_0_INTERNET_DOMAIN: ULONG = 0x00080000; +pub const MSV1_0_SUBAUTHENTICATION_DLL: ULONG = 0xFF000000; +pub const MSV1_0_SUBAUTHENTICATION_DLL_SHIFT: ULONG = 24; +pub const MSV1_0_MNS_LOGON: ULONG = 0x01000000; +pub const MSV1_0_SUBAUTHENTICATION_DLL_RAS: ULONG = 2; +pub const MSV1_0_SUBAUTHENTICATION_DLL_IIS: ULONG = 132; +STRUCT!{struct MSV1_0_LM20_LOGON { + MessageType: MSV1_0_LOGON_SUBMIT_TYPE, + LogonDomainName: UNICODE_STRING, + UserName: UNICODE_STRING, + Workstation: UNICODE_STRING, + ChallengeToClient: [UCHAR; MSV1_0_CHALLENGE_LENGTH], + CaseSensitiveChallengeResponse: STRING, + CaseInsensitiveChallengeResponse: STRING, + ParameterControl: ULONG, +}} +pub type PMSV1_0_LM20_LOGON = *mut MSV1_0_LM20_LOGON; +STRUCT!{struct MSV1_0_SUBAUTH_LOGON { + MessageType: MSV1_0_LOGON_SUBMIT_TYPE, + LogonDomainName: UNICODE_STRING, + UserName: UNICODE_STRING, + Workstation: UNICODE_STRING, + ChallengeToClient: [UCHAR; MSV1_0_CHALLENGE_LENGTH], + AuthenticationInfo1: STRING, + AuthenticationInfo2: STRING, + ParameterControl: ULONG, + SubAuthPackageId: ULONG, +}} +pub type PMSV1_0_SUBAUTH_LOGON = *mut MSV1_0_SUBAUTH_LOGON; +STRUCT!{struct MSV1_0_S4U_LOGON { + MessageType: MSV1_0_LOGON_SUBMIT_TYPE, + MSV1_0_LOGON_SUBMIT_TYPE: ULONG, + UserPrincipalName: UNICODE_STRING, + DomainName: UNICODE_STRING, +}} +pub type PMSV1_0_S4U_LOGON = *mut MSV1_0_S4U_LOGON; +pub const LOGON_GUEST: ULONG = 0x01; +pub const LOGON_NOENCRYPTION: ULONG = 0x02; +pub const LOGON_CACHED_ACCOUNT: ULONG = 0x04; +pub const LOGON_USED_LM_PASSWORD: ULONG = 0x08; +pub const LOGON_EXTRA_SIDS: ULONG = 0x20; +pub const LOGON_SUBAUTH_SESSION_KEY: ULONG = 0x40; +pub const LOGON_SERVER_TRUST_ACCOUNT: ULONG = 0x80; +pub const LOGON_NTLMV2_ENABLED: ULONG = 0x100; +pub const LOGON_RESOURCE_GROUPS: ULONG = 0x200; +pub const LOGON_PROFILE_PATH_RETURNED: ULONG = 0x400; +pub const LOGON_NT_V2: ULONG = 0x800; +pub const LOGON_LM_V2: ULONG = 0x1000; +pub const LOGON_NTLM_V2: ULONG = 0x2000; +pub const LOGON_OPTIMIZED: ULONG = 0x4000; +pub const LOGON_WINLOGON: ULONG = 0x8000; +pub const LOGON_PKINIT: ULONG = 0x10000; +pub const LOGON_NO_OPTIMIZED: ULONG = 0x20000; +pub const LOGON_NO_ELEVATION: ULONG = 0x40000; +pub const LOGON_MANAGED_SERVICE: ULONG = 0x80000; +pub const LOGON_GRACE_LOGON: ULONG = 0x01000000; +STRUCT!{struct MSV1_0_LM20_LOGON_PROFILE { + MessageType: MSV1_0_PROFILE_BUFFER_TYPE, + KickOffTime: LARGE_INTEGER, + LogoffTime: LARGE_INTEGER, + UserFlags: ULONG, + UserSessionKey: [UCHAR; MSV1_0_USER_SESSION_KEY_LENGTH], + LogonDomainName: UNICODE_STRING, + LanmanSessionKey: [UCHAR; MSV1_0_LANMAN_SESSION_KEY_LENGTH], + LogonServer: UNICODE_STRING, + UserParameters: UNICODE_STRING, +}} +pub type PMSV1_0_LM20_LOGON_PROFILE = *mut MSV1_0_LM20_LOGON_PROFILE; +pub const MSV1_0_OWF_PASSWORD_LENGTH: usize = 16; +STRUCT!{struct MSV1_0_SUPPLEMENTAL_CREDENTIAL { + Version: ULONG, + Flags: ULONG, + LmPassword: [UCHAR; MSV1_0_OWF_PASSWORD_LENGTH], + NtPassword: [UCHAR; MSV1_0_OWF_PASSWORD_LENGTH], +}} +pub type PMSV1_0_SUPPLEMENTAL_CREDENTIAL = *mut MSV1_0_SUPPLEMENTAL_CREDENTIAL; +pub const MSV1_0_NTLM3_RESPONSE_LENGTH: usize = 16; +pub const MSV1_0_NTLM3_OWF_LENGTH: usize = 16; +STRUCT!{struct MSV1_0_NTLM3_RESPONSE { + Response: [UCHAR; MSV1_0_NTLM3_RESPONSE_LENGTH], + RespType: UCHAR, + HiRespType: UCHAR, + Flags: USHORT, + MsgWord: ULONG, + TimeStamp: ULONGLONG, + ChallengeFromClient: [UCHAR; MSV1_0_CHALLENGE_LENGTH], + AvPairsOff: ULONG, + Buffer: [UCHAR; 1], +}} +pub type PMSV1_0_NTLM3_RESPONSE = *mut MSV1_0_NTLM3_RESPONSE; +ENUM!{enum MSV1_0_AVID { + MsvAvEOL, + MsvAvNbComputerName, + MsvAvNbDomainName, + MsvAvDnsComputerName, + MsvAvDnsDomainName, + MsvAvDnsTreeName, + MsvAvFlags, + MsvAvTimestamp, + MsvAvRestrictions, + MsvAvTargetName, + MsvAvChannelBindings, +}} +STRUCT!{struct MSV1_0_AV_PAIR { + AvId: USHORT, + AvLen: USHORT, +}} +pub type PMSV1_0_AV_PAIR = *mut MSV1_0_AV_PAIR; +ENUM!{enum MSV1_0_PROTOCOL_MESSAGE_TYPE { + MsV1_0Lm20ChallengeRequest = 0, + MsV1_0Lm20GetChallengeResponse, + MsV1_0EnumerateUsers, + MsV1_0GetUserInfo, + MsV1_0ReLogonUsers, + MsV1_0ChangePassword, + MsV1_0ChangeCachedPassword, + MsV1_0GenericPassthrough, + MsV1_0CacheLogon, + MsV1_0SubAuth, + MsV1_0DeriveCredential, + MsV1_0CacheLookup, + MsV1_0SetProcessOption, + MsV1_0ConfigLocalAliases, + MsV1_0ClearCachedCredentials, + MsV1_0LookupToken, + MsV1_0ValidateAuth, + MsV1_0CacheLookupEx, + MsV1_0GetCredentialKey, + MsV1_0SetThreadOption, +}} +pub type PMSV1_0_PROTOCOL_MESSAGE_TYPE = *mut MSV1_0_PROTOCOL_MESSAGE_TYPE; +STRUCT!{struct MSV1_0_CHANGEPASSWORD_REQUEST { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + DomainName: UNICODE_STRING, + AccountName: UNICODE_STRING, + OldPassword: UNICODE_STRING, + NewPassword: UNICODE_STRING, + Impersonating: BOOLEAN, +}} +pub type PMSV1_0_CHANGEPASSWORD_REQUEST = *mut MSV1_0_CHANGEPASSWORD_REQUEST; +STRUCT!{struct MSV1_0_CHANGEPASSWORD_RESPONSE { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + PasswordInfoValid: BOOLEAN, + DomainPasswordInfo: DOMAIN_PASSWORD_INFORMATION, +}} +pub type PMSV1_0_CHANGEPASSWORD_RESPONSE = *mut MSV1_0_CHANGEPASSWORD_RESPONSE; +STRUCT!{struct MSV1_0_PASSTHROUGH_REQUEST { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + DomainName: UNICODE_STRING, + PackageName: UNICODE_STRING, + DataLength: ULONG, + LogonData: PUCHAR, + Pad: ULONG, +}} +pub type PMSV1_0_PASSTHROUGH_REQUEST = *mut MSV1_0_PASSTHROUGH_REQUEST; +STRUCT!{struct MSV1_0_PASSTHROUGH_RESPONSE { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + Pad: ULONG, + DataLength: ULONG, + ValidationData: PUCHAR, +}} +pub type PMSV1_0_PASSTHROUGH_RESPONSE = *mut MSV1_0_PASSTHROUGH_RESPONSE; +STRUCT!{struct MSV1_0_SUBAUTH_REQUEST { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + SubAuthPackageId: ULONG, + SubAuthInfoLength: ULONG, + SubAuthSubmitBuffer: PUCHAR, +}} +pub type PMSV1_0_SUBAUTH_REQUEST = *mut MSV1_0_SUBAUTH_REQUEST; +STRUCT!{struct MSV1_0_SUBAUTH_RESPONSE { + MessageType: MSV1_0_PROTOCOL_MESSAGE_TYPE, + SubAuthInfoLength: ULONG, + SubAuthReturnBuffer: PUCHAR, +}} +pub type PMSV1_0_SUBAUTH_RESPONSE = *mut MSV1_0_SUBAUTH_RESPONSE; +pub use self::SystemFunction036 as RtlGenRandom; +pub use self::SystemFunction040 as RtlEncryptMemory; +pub use self::SystemFunction041 as RtlDecryptMemory; +extern "system" { + pub fn SystemFunction036( + RandomBuffer: PVOID, + RandomBufferLength: ULONG, + ) -> BOOLEAN; +} +pub const RTL_ENCRYPT_MEMORY_SIZE: ULONG = 8; +pub const RTL_ENCRYPT_OPTION_CROSS_PROCESS: ULONG = 0x01; +pub const RTL_ENCRYPT_OPTION_SAME_LOGON: ULONG = 0x02; +extern "system" { + pub fn SystemFunction040( + Memory: PVOID, + MemorySize: ULONG, + OptionFlags: ULONG, + ) -> NTSTATUS; + pub fn SystemFunction041( + Memory: PVOID, + MemorySize: ULONG, + OptionFlags: ULONG, + ) -> NTSTATUS; +} +pub const KERBEROS_VERSION: ULONG = 5; +pub const KERBEROS_REVISION: ULONG = 6; +pub const KERB_ETYPE_NULL: LONG = 0; +pub const KERB_ETYPE_DES_CBC_CRC: LONG = 1; +pub const KERB_ETYPE_DES_CBC_MD4: LONG = 2; +pub const KERB_ETYPE_DES_CBC_MD5: LONG = 3; +pub const KERB_ETYPE_AES128_CTS_HMAC_SHA1_96: LONG = 17; +pub const KERB_ETYPE_AES256_CTS_HMAC_SHA1_96: LONG = 18; +pub const KERB_ETYPE_RC4_MD4: LONG = -128; +pub const KERB_ETYPE_RC4_PLAIN2: LONG = -129; +pub const KERB_ETYPE_RC4_LM: LONG = -130; +pub const KERB_ETYPE_RC4_SHA: LONG = -131; +pub const KERB_ETYPE_DES_PLAIN: LONG = -132; +pub const KERB_ETYPE_RC4_HMAC_OLD: LONG = -133; +pub const KERB_ETYPE_RC4_PLAIN_OLD: LONG = -134; +pub const KERB_ETYPE_RC4_HMAC_OLD_EXP: LONG = -135; +pub const KERB_ETYPE_RC4_PLAIN_OLD_EXP: LONG = -136; +pub const KERB_ETYPE_RC4_PLAIN: LONG = -140; +pub const KERB_ETYPE_RC4_PLAIN_EXP: LONG = -141; +pub const KERB_ETYPE_AES128_CTS_HMAC_SHA1_96_PLAIN: LONG = -148; +pub const KERB_ETYPE_AES256_CTS_HMAC_SHA1_96_PLAIN: LONG = -149; +pub const KERB_ETYPE_DSA_SHA1_CMS: LONG = 9; +pub const KERB_ETYPE_RSA_MD5_CMS: LONG = 10; +pub const KERB_ETYPE_RSA_SHA1_CMS: LONG = 11; +pub const KERB_ETYPE_RC2_CBC_ENV: LONG = 12; +pub const KERB_ETYPE_RSA_ENV: LONG = 13; +pub const KERB_ETYPE_RSA_ES_OEAP_ENV: LONG = 14; +pub const KERB_ETYPE_DES_EDE3_CBC_ENV: LONG = 15; +pub const KERB_ETYPE_DSA_SIGN: LONG = 8; +pub const KERB_ETYPE_RSA_PRIV: LONG = 9; +pub const KERB_ETYPE_RSA_PUB: LONG = 10; +pub const KERB_ETYPE_RSA_PUB_MD5: LONG = 11; +pub const KERB_ETYPE_RSA_PUB_SHA1: LONG = 12; +pub const KERB_ETYPE_PKCS7_PUB: LONG = 13; +pub const KERB_ETYPE_DES3_CBC_MD5: LONG = 5; +pub const KERB_ETYPE_DES3_CBC_SHA1: LONG = 7; +pub const KERB_ETYPE_DES3_CBC_SHA1_KD: LONG = 16; +pub const KERB_ETYPE_DES_CBC_MD5_NT: LONG = 20; +pub const KERB_ETYPE_RC4_HMAC_NT: LONG = 23; +pub const KERB_ETYPE_RC4_HMAC_NT_EXP: LONG = 24; +pub const KERB_CHECKSUM_NONE: LONG = 0; +pub const KERB_CHECKSUM_CRC32: LONG = 1; +pub const KERB_CHECKSUM_MD4: LONG = 2; +pub const KERB_CHECKSUM_KRB_DES_MAC: LONG = 4; +pub const KERB_CHECKSUM_KRB_DES_MAC_K: LONG = 5; +pub const KERB_CHECKSUM_MD5: LONG = 7; +pub const KERB_CHECKSUM_MD5_DES: LONG = 8; +pub const KERB_CHECKSUM_SHA1_NEW: LONG = 14; +pub const KERB_CHECKSUM_HMAC_SHA1_96_AES128: LONG = 15; +pub const KERB_CHECKSUM_HMAC_SHA1_96_AES256: LONG = 16; +pub const KERB_CHECKSUM_LM: LONG = -130; +pub const KERB_CHECKSUM_SHA1: LONG = -131; +pub const KERB_CHECKSUM_REAL_CRC32: LONG = -132; +pub const KERB_CHECKSUM_DES_MAC: LONG = -133; +pub const KERB_CHECKSUM_DES_MAC_MD5: LONG = -134; +pub const KERB_CHECKSUM_MD25: LONG = -135; +pub const KERB_CHECKSUM_RC4_MD5: LONG = -136; +pub const KERB_CHECKSUM_MD5_HMAC: LONG = -137; +pub const KERB_CHECKSUM_HMAC_MD5: LONG = -138; +pub const KERB_CHECKSUM_HMAC_SHA1_96_AES128_Ki: LONG = -150; +pub const KERB_CHECKSUM_HMAC_SHA1_96_AES256_Ki: LONG = -151; +pub const KERB_TICKET_FLAGS_reserved: ULONG = 0x80000000; +pub const KERB_TICKET_FLAGS_forwardable: ULONG = 0x40000000; +pub const KERB_TICKET_FLAGS_forwarded: ULONG = 0x20000000; +pub const KERB_TICKET_FLAGS_proxiable: ULONG = 0x10000000; +pub const KERB_TICKET_FLAGS_proxy: ULONG = 0x08000000; +pub const KERB_TICKET_FLAGS_may_postdate: ULONG = 0x04000000; +pub const KERB_TICKET_FLAGS_postdated: ULONG = 0x02000000; +pub const KERB_TICKET_FLAGS_invalid: ULONG = 0x01000000; +pub const KERB_TICKET_FLAGS_renewable: ULONG = 0x00800000; +pub const KERB_TICKET_FLAGS_initial: ULONG = 0x00400000; +pub const KERB_TICKET_FLAGS_pre_authent: ULONG = 0x00200000; +pub const KERB_TICKET_FLAGS_hw_authent: ULONG = 0x00100000; +pub const KERB_TICKET_FLAGS_ok_as_delegate: ULONG = 0x00040000; +pub const KERB_TICKET_FLAGS_name_canonicalize: ULONG = 0x00010000; +pub const KERB_TICKET_FLAGS_cname_in_pa_data: ULONG = 0x00040000; +pub const KERB_TICKET_FLAGS_enc_pa_rep: ULONG = 0x00010000; +pub const KERB_TICKET_FLAGS_reserved1: ULONG = 0x00000001; +pub const KRB_NT_UNKNOWN: LONG = 0; +pub const KRB_NT_PRINCIPAL: LONG = 1; +pub const KRB_NT_PRINCIPAL_AND_ID: LONG = -131; +pub const KRB_NT_SRV_INST: LONG = 2; +pub const KRB_NT_SRV_INST_AND_ID: LONG = -132; +pub const KRB_NT_SRV_HST: LONG = 3; +pub const KRB_NT_SRV_XHST: LONG = 4; +pub const KRB_NT_UID: LONG = 5; +pub const KRB_NT_ENTERPRISE_PRINCIPAL: LONG = 10; +pub const KRB_NT_WELLKNOWN: LONG = 11; +pub const KRB_NT_ENT_PRINCIPAL_AND_ID: LONG = -130; +pub const KRB_NT_MS_PRINCIPAL: LONG = -128; +pub const KRB_NT_MS_PRINCIPAL_AND_ID: LONG = -129; +pub const KRB_NT_MS_BRANCH_ID: LONG = -133; +pub const KRB_NT_X500_PRINCIPAL: LONG = 6; +pub const KERB_WRAP_NO_ENCRYPT: ULONG = 0x80000001; +ENUM!{enum KERB_LOGON_SUBMIT_TYPE { + KerbInteractiveLogon = 2, + KerbSmartCardLogon = 6, + KerbWorkstationUnlockLogon = 7, + KerbSmartCardUnlockLogon = 8, + KerbProxyLogon = 9, + KerbTicketLogon = 10, + KerbTicketUnlockLogon = 11, + KerbS4ULogon = 12, + KerbCertificateLogon = 13, + KerbCertificateS4ULogon = 14, + KerbCertificateUnlockLogon = 15, + KerbNoElevationLogon = 83, + KerbLuidLogon = 84, +}} +pub type PKERB_LOGON_SUBMIT_TYPE = *mut KERB_LOGON_SUBMIT_TYPE; +STRUCT!{struct KERB_INTERACTIVE_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + LogonDomainName: UNICODE_STRING, + UserName: UNICODE_STRING, + Password: UNICODE_STRING, +}} +pub type PKERB_INTERACTIVE_LOGON = *mut KERB_INTERACTIVE_LOGON; +STRUCT!{struct KERB_INTERACTIVE_UNLOCK_LOGON { + Logon: KERB_INTERACTIVE_LOGON, + LogonId: LUID, +}} +pub type PKERB_INTERACTIVE_UNLOCK_LOGON = *mut KERB_INTERACTIVE_UNLOCK_LOGON; +STRUCT!{struct KERB_SMART_CARD_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + Pin: UNICODE_STRING, + CspDataLength: ULONG, + CspData: PUCHAR, +}} +pub type PKERB_SMART_CARD_LOGON = *mut KERB_SMART_CARD_LOGON; +STRUCT!{struct KERB_SMART_CARD_UNLOCK_LOGON { + Logon: KERB_SMART_CARD_LOGON, + LogonId: LUID, +}} +pub type PKERB_SMART_CARD_UNLOCK_LOGON = *mut KERB_SMART_CARD_UNLOCK_LOGON; +pub const KERB_CERTIFICATE_LOGON_FLAG_CHECK_DUPLICATES: ULONG = 0x1; +pub const KERB_CERTIFICATE_LOGON_FLAG_USE_CERTIFICATE_INFO: ULONG = 0x2; +STRUCT!{struct KERB_CERTIFICATE_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + DomainName: UNICODE_STRING, + UserName: UNICODE_STRING, + Pin: UNICODE_STRING, + Flags: ULONG, + CspDataLength: ULONG, + CspData: PUCHAR, +}} +pub type PKERB_CERTIFICATE_LOGON = *mut KERB_CERTIFICATE_LOGON; +STRUCT!{struct KERB_CERTIFICATE_UNLOCK_LOGON { + Logon: KERB_CERTIFICATE_LOGON, + LogonId: LUID, +}} +pub type PKERB_CERTIFICATE_UNLOCK_LOGON = *mut KERB_CERTIFICATE_UNLOCK_LOGON; +pub const KERB_CERTIFICATE_S4U_LOGON_FLAG_CHECK_DUPLICATES: ULONG = 0x1; +pub const KERB_CERTIFICATE_S4U_LOGON_FLAG_CHECK_LOGONHOURS: ULONG = 0x2; +pub const KERB_CERTIFICATE_S4U_LOGON_FLAG_FAIL_IF_NT_AUTH_POLICY_REQUIRED: ULONG = 0x4; +pub const KERB_CERTIFICATE_S4U_LOGON_FLAG_IDENTIFY: ULONG = 0x8; +STRUCT!{struct KERB_CERTIFICATE_S4U_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + Flags: ULONG, + UserPrincipalName: UNICODE_STRING, + DomainName: UNICODE_STRING, + CertificateLength: ULONG, + Certificate: PUCHAR, +}} +pub type PKERB_CERTIFICATE_S4U_LOGON = *mut KERB_CERTIFICATE_S4U_LOGON; +STRUCT!{struct KERB_TICKET_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + Flags: ULONG, + ServiceTicketLength: ULONG, + TicketGrantingTicketLength: ULONG, + ServiceTicket: PUCHAR, + TicketGrantingTicket: PUCHAR, +}} +pub type PKERB_TICKET_LOGON = *mut KERB_TICKET_LOGON; +STRUCT!{struct KERB_TICKET_UNLOCK_LOGON { + Logon: KERB_TICKET_LOGON, + LogonId: LUID, +}} +pub type PKERB_TICKET_UNLOCK_LOGON = *mut KERB_TICKET_UNLOCK_LOGON; +pub const KERB_S4U_LOGON_FLAG_CHECK_LOGONHOURS: ULONG = 0x2; +pub const KERB_S4U_LOGON_FLAG_IDENTIFY: ULONG = 0x8; +STRUCT!{struct KERB_S4U_LOGON { + MessageType: KERB_LOGON_SUBMIT_TYPE, + Flags: ULONG, + ClientUpn: UNICODE_STRING, + ClientRealm: UNICODE_STRING, +}} +pub type PKERB_S4U_LOGON = *mut KERB_S4U_LOGON; +ENUM!{enum KERB_PROFILE_BUFFER_TYPE { + KerbInteractiveProfile = 2, + KerbSmartCardProfile = 4, + KerbTicketProfile = 6, +}} +pub type PKERB_PROFILE_BUFFER_TYPE = *mut KERB_PROFILE_BUFFER_TYPE; +STRUCT!{struct KERB_INTERACTIVE_PROFILE { + MessageType: KERB_PROFILE_BUFFER_TYPE, + LogonCount: USHORT, + BadPasswordCount: USHORT, + LogonTime: LARGE_INTEGER, + LogoffTime: LARGE_INTEGER, + KickOffTime: LARGE_INTEGER, + PasswordLastSet: LARGE_INTEGER, + PasswordCanChange: LARGE_INTEGER, + PasswordMustChange: LARGE_INTEGER, + LogonScript: UNICODE_STRING, + HomeDirectory: UNICODE_STRING, + FullName: UNICODE_STRING, + ProfilePath: UNICODE_STRING, + HomeDirectoryDrive: UNICODE_STRING, + LogonServer: UNICODE_STRING, + UserFlags: ULONG, +}} +pub type PKERB_INTERACTIVE_PROFILE = *mut KERB_INTERACTIVE_PROFILE; +STRUCT!{struct KERB_SMART_CARD_PROFILE { + Profile: KERB_INTERACTIVE_PROFILE, + CertificateSize: ULONG, + CertificateData: PUCHAR, +}} +pub type PKERB_SMART_CARD_PROFILE = *mut KERB_SMART_CARD_PROFILE; +STRUCT!{struct KERB_CRYPTO_KEY { + KeyType: LONG, + Length: ULONG, + Value: PUCHAR, +}} +pub type PKERB_CRYPTO_KEY = *mut KERB_CRYPTO_KEY; +STRUCT!{struct KERB_CRYPTO_KEY32 { + KeyType: LONG, + Length: ULONG, + Offset: ULONG, +}} +pub type PKERB_CRYPTO_KEY32 = *mut KERB_CRYPTO_KEY32; +STRUCT!{struct KERB_TICKET_PROFILE { + Profile: KERB_INTERACTIVE_PROFILE, + SessionKey: KERB_CRYPTO_KEY, +}} +pub type PKERB_TICKET_PROFILE = *mut KERB_TICKET_PROFILE; +ENUM!{enum KERB_PROTOCOL_MESSAGE_TYPE { + KerbDebugRequestMessage = 0, + KerbQueryTicketCacheMessage, + KerbChangeMachinePasswordMessage, + KerbVerifyPacMessage, + KerbRetrieveTicketMessage, + KerbUpdateAddressesMessage, + KerbPurgeTicketCacheMessage, + KerbChangePasswordMessage, + KerbRetrieveEncodedTicketMessage, + KerbDecryptDataMessage, + KerbAddBindingCacheEntryMessage, + KerbSetPasswordMessage, + KerbSetPasswordExMessage, + KerbVerifyCredentialsMessage, + KerbQueryTicketCacheExMessage, + KerbPurgeTicketCacheExMessage, + KerbRefreshSmartcardCredentialsMessage, + KerbAddExtraCredentialsMessage, + KerbQuerySupplementalCredentialsMessage, + KerbTransferCredentialsMessage, + KerbQueryTicketCacheEx2Message, + KerbSubmitTicketMessage, + KerbAddExtraCredentialsExMessage, + KerbQueryKdcProxyCacheMessage, + KerbPurgeKdcProxyCacheMessage, + KerbQueryTicketCacheEx3Message, + KerbCleanupMachinePkinitCredsMessage, + KerbAddBindingCacheEntryExMessage, + KerbQueryBindingCacheMessage, + KerbPurgeBindingCacheMessage, + KerbPinKdcMessage, + KerbUnpinAllKdcsMessage, + KerbQueryDomainExtendedPoliciesMessage, + KerbQueryS4U2ProxyCacheMessage, +}} +pub type PKERB_PROTOCOL_MESSAGE_TYPE = *mut KERB_PROTOCOL_MESSAGE_TYPE; +STRUCT!{struct KERB_QUERY_TKT_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, +}} +pub type PKERB_QUERY_TKT_CACHE_REQUEST = *mut KERB_QUERY_TKT_CACHE_REQUEST; +STRUCT!{struct KERB_TICKET_CACHE_INFO { + ServerName: UNICODE_STRING, + RealmName: UNICODE_STRING, + StartTime: LARGE_INTEGER, + EndTime: LARGE_INTEGER, + RenewTime: LARGE_INTEGER, + EncryptionType: LONG, + TicketFlags: ULONG, +}} +pub type PKERB_TICKET_CACHE_INFO = *mut KERB_TICKET_CACHE_INFO; +STRUCT!{struct KERB_TICKET_CACHE_INFO_EX { + ClientName: UNICODE_STRING, + ClientRealm: UNICODE_STRING, + ServerName: UNICODE_STRING, + ServerRealm: UNICODE_STRING, + StartTime: LARGE_INTEGER, + EndTime: LARGE_INTEGER, + RenewTime: LARGE_INTEGER, + EncryptionType: LONG, + TicketFlags: ULONG, +}} +pub type PKERB_TICKET_CACHE_INFO_EX = *mut KERB_TICKET_CACHE_INFO_EX; +STRUCT!{struct KERB_TICKET_CACHE_INFO_EX2 { + ClientName: UNICODE_STRING, + ClientRealm: UNICODE_STRING, + ServerName: UNICODE_STRING, + ServerRealm: UNICODE_STRING, + StartTime: LARGE_INTEGER, + EndTime: LARGE_INTEGER, + RenewTime: LARGE_INTEGER, + EncryptionType: LONG, + TicketFlags: ULONG, + SessionKeyType: ULONG, + BranchId: ULONG, +}} +pub type PKERB_TICKET_CACHE_INFO_EX2 = *mut KERB_TICKET_CACHE_INFO_EX2; +STRUCT!{struct KERB_TICKET_CACHE_INFO_EX3 { + ClientName: UNICODE_STRING, + ClientRealm: UNICODE_STRING, + ServerName: UNICODE_STRING, + ServerRealm: UNICODE_STRING, + StartTime: LARGE_INTEGER, + EndTime: LARGE_INTEGER, + RenewTime: LARGE_INTEGER, + EncryptionType: LONG, + TicketFlags: ULONG, + SessionKeyType: ULONG, + BranchId: ULONG, + CacheFlags: ULONG, + KdcCalled: UNICODE_STRING, +}} +pub type PKERB_TICKET_CACHE_INFO_EX3 = *mut KERB_TICKET_CACHE_INFO_EX3; +STRUCT!{struct KERB_QUERY_TKT_CACHE_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfTickets: ULONG, + Tickets: [KERB_TICKET_CACHE_INFO; ANYSIZE_ARRAY], +}} +pub type PKERB_QUERY_TKT_CACHE_RESPONSE = *mut KERB_QUERY_TKT_CACHE_RESPONSE; +STRUCT!{struct KERB_QUERY_TKT_CACHE_EX_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfTickets: ULONG, + Tickets: [KERB_TICKET_CACHE_INFO_EX; ANYSIZE_ARRAY], +}} +pub type PKERB_QUERY_TKT_CACHE_EX_RESPONSE = *mut KERB_QUERY_TKT_CACHE_EX_RESPONSE; +STRUCT!{struct KERB_QUERY_TKT_CACHE_EX2_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfTickets: ULONG, + Tickets: [KERB_TICKET_CACHE_INFO_EX2; ANYSIZE_ARRAY], +}} +pub type PKERB_QUERY_TKT_CACHE_EX2_RESPONSE = *mut KERB_QUERY_TKT_CACHE_EX2_RESPONSE; +STRUCT!{struct KERB_QUERY_TKT_CACHE_EX3_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfTickets: ULONG, + Tickets: [KERB_TICKET_CACHE_INFO_EX3; ANYSIZE_ARRAY], +}} +pub type PKERB_QUERY_TKT_CACHE_EX3_RESPONSE = *mut KERB_QUERY_TKT_CACHE_EX3_RESPONSE; +pub const KERB_USE_DEFAULT_TICKET_FLAGS: ULONG = 0x0; +pub const KERB_RETRIEVE_TICKET_DEFAULT: ULONG = 0x0; +pub const KERB_RETRIEVE_TICKET_DONT_USE_CACHE: ULONG = 0x1; +pub const KERB_RETRIEVE_TICKET_USE_CACHE_ONLY: ULONG = 0x2; +pub const KERB_RETRIEVE_TICKET_USE_CREDHANDLE: ULONG = 0x4; +pub const KERB_RETRIEVE_TICKET_AS_KERB_CRED: ULONG = 0x8; +pub const KERB_RETRIEVE_TICKET_WITH_SEC_CRED: ULONG = 0x10; +pub const KERB_RETRIEVE_TICKET_CACHE_TICKET: ULONG = 0x20; +pub const KERB_RETRIEVE_TICKET_MAX_LIFETIME: ULONG = 0x40; +STRUCT!{struct KERB_AUTH_DATA { + Type: ULONG, + Length: ULONG, + Data: PUCHAR, +}} +pub type PKERB_AUTH_DATA = *mut KERB_AUTH_DATA; +STRUCT!{struct KERB_NET_ADDRESS { + Family: ULONG, + Length: ULONG, + Address: PUCHAR, +}} +pub type PKERB_NET_ADDRESS = *mut KERB_NET_ADDRESS; +STRUCT!{struct KERB_NET_ADDRESSES { + Number: ULONG, + Addresses: [KERB_NET_ADDRESS; ANYSIZE_ARRAY], +}} +pub type PKERB_NET_ADDRESSES = *mut KERB_NET_ADDRESSES; +STRUCT!{struct KERB_EXTERNAL_NAME { + NameType: SHORT, + NameCount: USHORT, + Names: [UNICODE_STRING; ANYSIZE_ARRAY], +}} +pub type PKERB_EXTERNAL_NAME = *mut KERB_EXTERNAL_NAME; +STRUCT!{struct KERB_EXTERNAL_TICKET { + ServiceName: PKERB_EXTERNAL_NAME, + TargetName: PKERB_EXTERNAL_NAME, + ClientName: PKERB_EXTERNAL_NAME, + DomainName: UNICODE_STRING, + TargetDomainName: UNICODE_STRING, + AltTargetDomainName: UNICODE_STRING, + SessionKey: KERB_CRYPTO_KEY, + TicketFlags: ULONG, + Flags: ULONG, + KeyExpirationTime: LARGE_INTEGER, + StartTime: LARGE_INTEGER, + EndTime: LARGE_INTEGER, + RenewUntil: LARGE_INTEGER, + TimeSkew: LARGE_INTEGER, + EncodedTicketSize: ULONG, + EncodedTicket: PUCHAR, +}} +pub type PKERB_EXTERNAL_TICKET = *mut KERB_EXTERNAL_TICKET; +STRUCT!{struct KERB_RETRIEVE_TKT_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + TargetName: UNICODE_STRING, + TicketFlags: ULONG, + CacheOptions: ULONG, + EncryptionType: LONG, + CredentialsHandle: SecHandle, +}} +pub type PKERB_RETRIEVE_TKT_REQUEST = *mut KERB_RETRIEVE_TKT_REQUEST; +STRUCT!{struct KERB_RETRIEVE_TKT_RESPONSE { + Ticket: KERB_EXTERNAL_TICKET, +}} +pub type PKERB_RETRIEVE_TKT_RESPONSE = *mut KERB_RETRIEVE_TKT_RESPONSE; +STRUCT!{struct KERB_PURGE_TKT_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + ServerName: UNICODE_STRING, + RealmName: UNICODE_STRING, +}} +pub type PKERB_PURGE_TKT_CACHE_REQUEST = *mut KERB_PURGE_TKT_CACHE_REQUEST; +pub const KERB_PURGE_ALL_TICKETS: ULONG = 1; +STRUCT!{struct KERB_PURGE_TKT_CACHE_EX_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + Flags: ULONG, + TicketTemplate: KERB_TICKET_CACHE_INFO_EX, +}} +pub type PKERB_PURGE_TKT_CACHE_EX_REQUEST = *mut KERB_PURGE_TKT_CACHE_EX_REQUEST; +STRUCT!{struct KERB_SUBMIT_TKT_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + Flags: ULONG, + Key: KERB_CRYPTO_KEY32, + KerbCredSize: ULONG, + KerbCredOffset: ULONG, +}} +pub type PKERB_SUBMIT_TKT_REQUEST = *mut KERB_SUBMIT_TKT_REQUEST; +STRUCT!{struct KERB_QUERY_KDC_PROXY_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + Flags: ULONG, + LogonId: LUID, +}} +pub type PKERB_QUERY_KDC_PROXY_CACHE_REQUEST = *mut KERB_QUERY_KDC_PROXY_CACHE_REQUEST; +STRUCT!{struct KDC_PROXY_CACHE_ENTRY_DATA { + SinceLastUsed: ULONG64, + DomainName: UNICODE_STRING, + ProxyServerName: UNICODE_STRING, + ProxyServerVdir: UNICODE_STRING, + ProxyServerPort: USHORT, + LogonId: LUID, + CredUserName: UNICODE_STRING, + CredDomainName: UNICODE_STRING, + GlobalCache: BOOLEAN, +}} +pub type PKDC_PROXY_CACHE_ENTRY_DATA = *mut KDC_PROXY_CACHE_ENTRY_DATA; +STRUCT!{struct KERB_QUERY_KDC_PROXY_CACHE_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfEntries: ULONG, + Entries: PKDC_PROXY_CACHE_ENTRY_DATA, +}} +pub type PKERB_QUERY_KDC_PROXY_CACHE_RESPONSE = *mut KERB_QUERY_KDC_PROXY_CACHE_RESPONSE; +STRUCT!{struct KERB_PURGE_KDC_PROXY_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + Flags: ULONG, + LogonId: LUID, +}} +pub type PKERB_PURGE_KDC_PROXY_CACHE_REQUEST = *mut KERB_PURGE_KDC_PROXY_CACHE_REQUEST; +STRUCT!{struct KERB_PURGE_KDC_PROXY_CACHE_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfPurged: ULONG, +}} +pub type PKERB_PURGE_KDC_PROXY_CACHE_RESPONSE = *mut KERB_PURGE_KDC_PROXY_CACHE_RESPONSE; +pub const KERB_S4U2PROXY_CACHE_ENTRY_INFO_FLAG_NEGATIVE: ULONG = 0x1; +STRUCT!{struct KERB_S4U2PROXY_CACHE_ENTRY_INFO { + ServerName: UNICODE_STRING, + Flags: ULONG, + LastStatus: NTSTATUS, + Expiry: LARGE_INTEGER, +}} +pub type PKERB_S4U2PROXY_CACHE_ENTRY_INFO = *mut KERB_S4U2PROXY_CACHE_ENTRY_INFO; +pub const KERB_S4U2PROXY_CRED_FLAG_NEGATIVE: ULONG = 0x1; +STRUCT!{struct KERB_S4U2PROXY_CRED { + UserName: UNICODE_STRING, + DomainName: UNICODE_STRING, + Flags: ULONG, + LastStatus: NTSTATUS, + Expiry: LARGE_INTEGER, + CountOfEntries: ULONG, + Entries: PKERB_S4U2PROXY_CACHE_ENTRY_INFO, +}} +pub type PKERB_S4U2PROXY_CRED = *mut KERB_S4U2PROXY_CRED; +STRUCT!{struct KERB_QUERY_S4U2PROXY_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + Flags: ULONG, + LogonId: LUID, +}} +pub type PKERB_QUERY_S4U2PROXY_CACHE_REQUEST = *mut KERB_QUERY_S4U2PROXY_CACHE_REQUEST; +STRUCT!{struct KERB_QUERY_S4U2PROXY_CACHE_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfCreds: ULONG, + Creds: PKERB_S4U2PROXY_CRED, +}} +pub type PKERB_QUERY_S4U2PROXY_CACHE_RESPONSE = *mut KERB_QUERY_S4U2PROXY_CACHE_RESPONSE; +STRUCT!{struct KERB_CHANGEPASSWORD_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + DomainName: UNICODE_STRING, + AccountName: UNICODE_STRING, + OldPassword: UNICODE_STRING, + NewPassword: UNICODE_STRING, + Impersonating: BOOLEAN, +}} +pub type PKERB_CHANGEPASSWORD_REQUEST = *mut KERB_CHANGEPASSWORD_REQUEST; +STRUCT!{struct KERB_SETPASSWORD_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + CredentialsHandle: SecHandle, + Flags: ULONG, + DomainName: UNICODE_STRING, + AccountName: UNICODE_STRING, + Password: UNICODE_STRING, +}} +pub type PKERB_SETPASSWORD_REQUEST = *mut KERB_SETPASSWORD_REQUEST; +STRUCT!{struct KERB_SETPASSWORD_EX_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + CredentialsHandle: SecHandle, + Flags: ULONG, + AccountRealm: UNICODE_STRING, + AccountName: UNICODE_STRING, + Password: UNICODE_STRING, + ClientRealm: UNICODE_STRING, + ClientName: UNICODE_STRING, + Impersonating: BOOLEAN, + KdcAddress: UNICODE_STRING, + KdcAddressType: ULONG, +}} +pub type PKERB_SETPASSWORD_EX_REQUEST = *mut KERB_SETPASSWORD_EX_REQUEST; +pub const DS_UNKNOWN_ADDRESS_TYPE: ULONG = 0; +pub const KERB_SETPASS_USE_LOGONID: ULONG = 1; +pub const KERB_SETPASS_USE_CREDHANDLE: ULONG = 2; +STRUCT!{struct KERB_DECRYPT_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, + Flags: ULONG, + CryptoType: LONG, + KeyUsage: LONG, + Key: KERB_CRYPTO_KEY, + EncryptedDataSize: ULONG, + InitialVectorSize: ULONG, + InitialVector: PUCHAR, + EncryptedData: PUCHAR, +}} +pub type PKERB_DECRYPT_REQUEST = *mut KERB_DECRYPT_REQUEST; +pub const KERB_DECRYPT_FLAG_DEFAULT_KEY: ULONG = 0x00000001; +STRUCT!{struct KERB_DECRYPT_RESPONSE { + DecryptedData: [UCHAR; ANYSIZE_ARRAY], +}} +pub type PKERB_DECRYPT_RESPONSE = *mut KERB_DECRYPT_RESPONSE; +STRUCT!{struct KERB_ADD_BINDING_CACHE_ENTRY_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + RealmName: UNICODE_STRING, + KdcAddress: UNICODE_STRING, + AddressType: ULONG, +}} +pub type PKERB_ADD_BINDING_CACHE_ENTRY_REQUEST = *mut KERB_ADD_BINDING_CACHE_ENTRY_REQUEST; +STRUCT!{struct KERB_REFRESH_SCCRED_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CredentialBlob: UNICODE_STRING, + LogonId: LUID, + Flags: ULONG, +}} +pub type PKERB_REFRESH_SCCRED_REQUEST = *mut KERB_REFRESH_SCCRED_REQUEST; +pub const KERB_REFRESH_SCCRED_RELEASE: ULONG = 0x0; +pub const KERB_REFRESH_SCCRED_GETTGT: ULONG = 0x1; +STRUCT!{struct KERB_ADD_CREDENTIALS_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + UserName: UNICODE_STRING, + DomainName: UNICODE_STRING, + Password: UNICODE_STRING, + LogonId: LUID, + Flags: ULONG, +}} +pub type PKERB_ADD_CREDENTIALS_REQUEST = *mut KERB_ADD_CREDENTIALS_REQUEST; +pub const KERB_REQUEST_ADD_CREDENTIAL: ULONG = 1; +pub const KERB_REQUEST_REPLACE_CREDENTIAL: ULONG = 2; +pub const KERB_REQUEST_REMOVE_CREDENTIAL: ULONG = 4; +STRUCT!{struct KERB_ADD_CREDENTIALS_REQUEST_EX { + Credentials: KERB_ADD_CREDENTIALS_REQUEST, + PrincipalNameCount: ULONG, + PrincipalNames: [UNICODE_STRING; ANYSIZE_ARRAY], +}} +pub type PKERB_ADD_CREDENTIALS_REQUEST_EX = *mut KERB_ADD_CREDENTIALS_REQUEST_EX; +STRUCT!{struct KERB_TRANSFER_CRED_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + OriginLogonId: LUID, + DestinationLogonId: LUID, + Flags: ULONG, +}} +pub type PKERB_TRANSFER_CRED_REQUEST = *mut KERB_TRANSFER_CRED_REQUEST; +pub const KERB_TRANSFER_CRED_WITH_TICKETS: ULONG = 0x1; +pub const KERB_TRANSFER_CRED_CLEANUP_CREDENTIALS: ULONG = 0x2; +STRUCT!{struct KERB_CLEANUP_MACHINE_PKINIT_CREDS_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + LogonId: LUID, +}} +pub type PKERB_CLEANUP_MACHINE_PKINIT_CREDS_REQUEST = + *mut KERB_CLEANUP_MACHINE_PKINIT_CREDS_REQUEST; +STRUCT!{struct KERB_BINDING_CACHE_ENTRY_DATA { + DiscoveryTime: ULONG64, + RealmName: UNICODE_STRING, + KdcAddress: UNICODE_STRING, + AddressType: ULONG, + Flags: ULONG, + DcFlags: ULONG, + CacheFlags: ULONG, + KdcName: UNICODE_STRING, +}} +pub type PKERB_BINDING_CACHE_ENTRY_DATA = *mut KERB_BINDING_CACHE_ENTRY_DATA; +STRUCT!{struct KERB_QUERY_BINDING_CACHE_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + CountOfEntries: ULONG, + Entries: PKERB_BINDING_CACHE_ENTRY_DATA, +}} +pub type PKERB_QUERY_BINDING_CACHE_RESPONSE = *mut KERB_QUERY_BINDING_CACHE_RESPONSE; +STRUCT!{struct KERB_ADD_BINDING_CACHE_ENTRY_EX_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + RealmName: UNICODE_STRING, + KdcAddress: UNICODE_STRING, + AddressType: ULONG, + DcFlags: ULONG, +}} +pub type PKERB_ADD_BINDING_CACHE_ENTRY_EX_REQUEST = *mut KERB_ADD_BINDING_CACHE_ENTRY_EX_REQUEST; +STRUCT!{struct KERB_QUERY_BINDING_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, +}} +pub type PKERB_QUERY_BINDING_CACHE_REQUEST = *mut KERB_QUERY_BINDING_CACHE_REQUEST; +STRUCT!{struct KERB_PURGE_BINDING_CACHE_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, +}} +pub type PKERB_PURGE_BINDING_CACHE_REQUEST = *mut KERB_PURGE_BINDING_CACHE_REQUEST; +STRUCT!{struct KERB_QUERY_DOMAIN_EXTENDED_POLICIES_REQUEST { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + Flags: ULONG, + DomainName: UNICODE_STRING, +}} +pub type PKERB_QUERY_DOMAIN_EXTENDED_POLICIES_REQUEST = + *mut KERB_QUERY_DOMAIN_EXTENDED_POLICIES_REQUEST; +STRUCT!{struct KERB_QUERY_DOMAIN_EXTENDED_POLICIES_RESPONSE { + MessageType: KERB_PROTOCOL_MESSAGE_TYPE, + Flags: ULONG, + ExtendedPolicies: ULONG, + DsFlags: ULONG, +}} +pub type PKERB_QUERY_DOMAIN_EXTENDED_POLICIES_RESPONSE = + *mut KERB_QUERY_DOMAIN_EXTENDED_POLICIES_RESPONSE; +ENUM!{enum KERB_CERTIFICATE_INFO_TYPE { + CertHashInfo = 1, +}} +pub type PKERB_CERTIFICATE_INFO_TYPE = *mut KERB_CERTIFICATE_INFO_TYPE; +STRUCT!{struct KERB_CERTIFICATE_HASHINFO { + StoreNameLength: USHORT, + HashLength: USHORT, +}} +pub type PKERB_CERTIFICATE_HASHINFO = *mut KERB_CERTIFICATE_HASHINFO; +STRUCT!{struct KERB_CERTIFICATE_INFO { + CertInfoSize: ULONG, + InfoType: ULONG, +}} +pub type PKERB_CERTIFICATE_INFO = *mut KERB_CERTIFICATE_INFO; +STRUCT!{struct POLICY_AUDIT_SID_ARRAY { + UsersCount: ULONG, + UserSidArray: *mut PSID, +}} +pub type PPOLICY_AUDIT_SID_ARRAY = *mut POLICY_AUDIT_SID_ARRAY; +STRUCT!{struct AUDIT_POLICY_INFORMATION { + AuditSubCategoryGuid: GUID, + AuditingInformation: ULONG, + AuditCategoryGuid: GUID, +}} +pub type PAUDIT_POLICY_INFORMATION = *mut AUDIT_POLICY_INFORMATION; +pub type LPAUDIT_POLICY_INFORMATION = PAUDIT_POLICY_INFORMATION; +pub type PCAUDIT_POLICY_INFORMATION = *const AUDIT_POLICY_INFORMATION; +pub const AUDIT_SET_SYSTEM_POLICY: ULONG = 0x0001; +pub const AUDIT_QUERY_SYSTEM_POLICY: ULONG = 0x0002; +pub const AUDIT_SET_USER_POLICY: ULONG = 0x0004; +pub const AUDIT_QUERY_USER_POLICY: ULONG = 0x0008; +pub const AUDIT_ENUMERATE_USERS: ULONG = 0x0010; +pub const AUDIT_SET_MISC_POLICY: ULONG = 0x0020; +pub const AUDIT_QUERY_MISC_POLICY: ULONG = 0x0040; +pub const AUDIT_GENERIC_ALL: ULONG = STANDARD_RIGHTS_REQUIRED | AUDIT_SET_SYSTEM_POLICY + | AUDIT_QUERY_SYSTEM_POLICY | AUDIT_SET_USER_POLICY | AUDIT_QUERY_USER_POLICY + | AUDIT_ENUMERATE_USERS | AUDIT_SET_MISC_POLICY | AUDIT_QUERY_MISC_POLICY; +pub const AUDIT_GENERIC_READ: ULONG = STANDARD_RIGHTS_READ | AUDIT_QUERY_SYSTEM_POLICY + | AUDIT_QUERY_USER_POLICY | AUDIT_ENUMERATE_USERS | AUDIT_QUERY_MISC_POLICY; +pub const AUDIT_GENERIC_WRITE: ULONG = STANDARD_RIGHTS_WRITE | AUDIT_SET_USER_POLICY + | AUDIT_SET_MISC_POLICY | AUDIT_SET_SYSTEM_POLICY; +pub const AUDIT_GENERIC_EXECUTE: ULONG = STANDARD_RIGHTS_EXECUTE; +extern "system" { + pub fn AuditSetSystemPolicy( + pAuditPolicy: PCAUDIT_POLICY_INFORMATION, + PolicyCount: ULONG, + ) -> BOOLEAN; + pub fn AuditSetPerUserPolicy( + pSid: *const SID, + pAuditPolicy: PCAUDIT_POLICY_INFORMATION, + PolicyCount: ULONG, + ) -> BOOLEAN; + pub fn AuditQuerySystemPolicy( + pSubCategoryGuids: *const GUID, + PolicyCount: ULONG, + ppAuditPolicy: *mut PAUDIT_POLICY_INFORMATION, + ) -> BOOLEAN; + pub fn AuditQueryPerUserPolicy( + pSid: *const SID, + pSubCategoryGuids: *const GUID, + PolicyCount: ULONG, + ppAuditPolicy: *mut PAUDIT_POLICY_INFORMATION, + ) -> BOOLEAN; + pub fn AuditEnumeratePerUserPolicy( + ppAuditSidArray: *mut PPOLICY_AUDIT_SID_ARRAY, + ) -> BOOLEAN; + pub fn AuditComputeEffectivePolicyBySid( + pSid: *const SID, + pSubCategoryGuids: *const GUID, + dwPolicyCount: ULONG, + ppAuditPolicy: *mut PAUDIT_POLICY_INFORMATION, + ) -> BOOLEAN; + pub fn AuditComputeEffectivePolicyByToken( + hTokenHandle: HANDLE, + pSubCategoryGuids: *const GUID, + dwPolicyCount: ULONG, + ppAuditPolicy: *mut PAUDIT_POLICY_INFORMATION, + ) -> BOOLEAN; + pub fn AuditEnumerateCategories( + ppAuditCategoriesArray: *mut *mut GUID, + pdwCountReturned: PULONG, + ) -> BOOLEAN; + pub fn AuditEnumerateSubCategories( + pAuditCategoryGuid: *const GUID, + bRetrieveAllSubCategories: BOOLEAN, + ppAuditSubCategoriesArray: *mut *mut GUID, + pdwCountReturned: PULONG, + ) -> BOOLEAN; + pub fn AuditLookupCategoryNameW( + pAuditCategoryGuid: *const GUID, + ppszCategoryName: *mut PWSTR, + ) -> BOOLEAN; + pub fn AuditLookupCategoryNameA( + pAuditCategoryGuid: *const GUID, + ppszCategoryName: *mut PSTR, + ) -> BOOLEAN; + pub fn AuditLookupSubCategoryNameW( + pAuditSubCategoryGuid: *const GUID, + ppszSubCategoryName: *mut PWSTR, + ) -> BOOLEAN; + pub fn AuditLookupSubCategoryNameA( + pAuditSubCategoryGuid: *const GUID, + ppszSubCategoryName: *mut PSTR, + ) -> BOOLEAN; + pub fn AuditLookupCategoryIdFromCategoryGuid( + pAuditCategoryGuid: *const GUID, + pAuditCategoryId: PPOLICY_AUDIT_EVENT_TYPE, + ) -> BOOLEAN; + pub fn AuditLookupCategoryGuidFromCategoryId( + AuditCategoryId: POLICY_AUDIT_EVENT_TYPE, + pAuditCategoryGuid: *mut GUID, + ) -> BOOLEAN; + pub fn AuditSetSecurity( + SecurityInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> BOOLEAN; + pub fn AuditQuerySecurity( + SecurityInformation: SECURITY_INFORMATION, + ppSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> BOOLEAN; + pub fn AuditSetGlobalSaclW( + ObjectTypeName: PCWSTR, + Acl: PACL, + ) -> BOOLEAN; + pub fn AuditSetGlobalSaclA( + ObjectTypeName: PCSTR, + Acl: PACL, + ) -> BOOLEAN; + pub fn AuditQueryGlobalSaclW( + ObjectTypeName: PCWSTR, + Acl: *mut PACL, + ) -> BOOLEAN; + pub fn AuditQueryGlobalSaclA( + ObjectTypeName: PCSTR, + Acl: *mut PACL, + ) -> BOOLEAN; + pub fn AuditFree( + Buffer: PVOID, + ); +} +STRUCT!{struct PKU2U_CERT_BLOB { + CertOffset: ULONG, + CertLength: USHORT, +}} +pub type PPKU2U_CERT_BLOB = *mut PKU2U_CERT_BLOB; +pub const PKU2U_CREDUI_CONTEXT_VERSION: ULONG64 = 0x4154414454524543; +STRUCT!{struct PKU2U_CREDUI_CONTEXT { + Version: ULONG64, + cbHeaderLength: USHORT, + cbStructureLength: ULONG, + CertArrayCount: USHORT, + CertArrayOffset: ULONG, +}} +pub type PPKU2U_CREDUI_CONTEXT = *mut PKU2U_CREDUI_CONTEXT; +ENUM!{enum PKU2U_LOGON_SUBMIT_TYPE { + Pku2uCertificateS4ULogon = 14, +}} +pub type PPKU2U_LOGON_SUBMIT_TYPE = *mut PKU2U_LOGON_SUBMIT_TYPE; +STRUCT!{struct PKU2U_CERTIFICATE_S4U_LOGON { + MessageType: PKU2U_LOGON_SUBMIT_TYPE, + Flags: ULONG, + UserPrincipalName: UNICODE_STRING, + DomainName: UNICODE_STRING, + CertificateLength: ULONG, + Certificate: PUCHAR, +}} +pub type PPKU2U_CERTIFICATE_S4U_LOGON = *mut PKU2U_CERTIFICATE_S4U_LOGON; diff --git a/winapi/src/um/oaidl.rs b/winapi/src/um/oaidl.rs new file mode 100644 index 000000000..a3f6decd7 --- /dev/null +++ b/winapi/src/um/oaidl.rs @@ -0,0 +1,879 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of OAIdl.h +use shared::basetsd::ULONG_PTR; +use shared::guiddef::{GUID, IID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, UINT, ULONG, USHORT, WORD}; +use shared::rpcndr::byte; +use shared::wtypes::{ + BSTR, CY, DATE, DECIMAL, VARIANT_BOOL, VARTYPE, VT_BSTR, VT_DISPATCH, VT_ERROR, + VT_I1, VT_I2, VT_I4, VT_I8, VT_RECORD, VT_RESERVED, VT_UNKNOWN, VT_VARIANT, + wireBSTR +}; +use shared::wtypesbase::{ + BYTE_SIZEDARR, DOUBLE, DWORD_SIZEDARR, HYPER_SIZEDARR, LPCOLESTR, LPOLESTR, SCODE, + WORD_SIZEDARR +}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{CHAR, HRESULT, LCID, LONG, LONGLONG, PVOID, SHORT, ULONGLONG}; +pub type CURRENCY = CY; +STRUCT!{struct SAFEARRAYBOUND { + cElements: ULONG, + lLbound: LONG, +}} +pub type LPSAFEARRAYBOUND = *mut SAFEARRAYBOUND; +pub type wireBRECORD = *mut _wireBRECORD; +pub type wireVARIANT = *mut _wireVARIANT; +STRUCT!{struct SAFEARR_BSTR { + Size: ULONG, + aBstr: *mut wireBSTR, +}} +STRUCT!{struct SAFEARR_UNKNOWN { + Size: ULONG, + apUnknown: *mut *mut IUnknown, +}} +STRUCT!{struct SAFEARR_DISPATCH { + Size: ULONG, + apDispatch: *mut *mut IDispatch, +}} +STRUCT!{struct SAFEARR_VARIANT { + Size: ULONG, + aVariant: *mut wireVARIANT, +}} +STRUCT!{struct SAFEARR_BRECORD { + Size: ULONG, + aRecord: *mut wireBRECORD, +}} +STRUCT!{struct SAFEARR_HAVEIID { + Size: ULONG, + apUnknown: *mut *mut IUnknown, + iid: IID, +}} +ENUM!{enum SF_TYPE { + SF_ERROR = VT_ERROR, + SF_I1 = VT_I1, + SF_I2 = VT_I2, + SF_I4 = VT_I4, + SF_I8 = VT_I8, + SF_BSTR = VT_BSTR, + SF_UNKNOWN = VT_UNKNOWN, + SF_DISPATCH = VT_DISPATCH, + SF_VARIANT = VT_VARIANT, + SF_RECORD = VT_RECORD, + SF_HAVEIID = VT_UNKNOWN | VT_RESERVED, +}} +#[cfg(target_arch = "x86")] +UNION!{union __MIDL_IOleAutomationTypes_0001 { + [u32; 6], + BstrStr BstrStr_mut: SAFEARR_BSTR, + UnknownStr UnknownStr_mut: SAFEARR_UNKNOWN, + DispatchStr DispatchStr_mut: SAFEARR_DISPATCH, + VariantStr VariantStr_mut: SAFEARR_VARIANT, + RecordStr RecordStr_mut: SAFEARR_BRECORD, + HaveIidStr HaveIidStr_mut: SAFEARR_HAVEIID, + ByteStr ByteStr_mut: BYTE_SIZEDARR, + WordStr WordStr_mut: WORD_SIZEDARR, + LongStr LongStr_mut: DWORD_SIZEDARR, + HyperStr HyperStr_mut: HYPER_SIZEDARR, +}} +#[cfg(target_pointer_width = "64")] +UNION!{union __MIDL_IOleAutomationTypes_0001 { + [u64; 4], + BstrStr BstrStr_mut: SAFEARR_BSTR, + UnknownStr UnknownStr_mut: SAFEARR_UNKNOWN, + DispatchStr DispatchStr_mut: SAFEARR_DISPATCH, + VariantStr VariantStr_mut: SAFEARR_VARIANT, + RecordStr RecordStr_mut: SAFEARR_BRECORD, + HaveIidStr HaveIidStr_mut: SAFEARR_HAVEIID, + ByteStr ByteStr_mut: BYTE_SIZEDARR, + WordStr WordStr_mut: WORD_SIZEDARR, + LongStr LongStr_mut: DWORD_SIZEDARR, + HyperStr HyperStr_mut: HYPER_SIZEDARR, +}} +STRUCT!{struct SAFEARRAYUNION { + sfType: ULONG, + u: __MIDL_IOleAutomationTypes_0001, +}} +STRUCT!{struct _wireSAFEARRAY { + cDims: USHORT, + fFeatures: USHORT, + cbElements: ULONG, + cLocks: ULONG, + uArrayStructs: SAFEARRAYUNION, + rgsaBound: [SAFEARRAYBOUND; 1], +}} +pub type wireSAFEARRAY = *mut _wireSAFEARRAY; +pub type wirePSAFEARRAY = *mut wireSAFEARRAY; +STRUCT!{struct SAFEARRAY { + cDims: USHORT, + fFeatures: USHORT, + cbElements: ULONG, + cLocks: ULONG, + pvData: PVOID, + rgsabound: [SAFEARRAYBOUND; 1], +}} +pub type LPSAFEARRAY = *mut SAFEARRAY; +pub const FADF_AUTO: DWORD = 0x1; +pub const FADF_STATIC: DWORD = 0x2; +pub const FADF_EMBEDDED: DWORD = 0x4; +pub const FADF_FIXEDSIZE: DWORD = 0x10; +pub const FADF_RECORD: DWORD = 0x20; +pub const FADF_HAVEIID: DWORD = 0x40; +pub const FADF_HAVEVARTYPE: DWORD = 0x80; +pub const FADF_BSTR: DWORD = 0x100; +pub const FADF_UNKNOWN: DWORD = 0x200; +pub const FADF_DISPATCH: DWORD = 0x400; +pub const FADF_VARIANT: DWORD = 0x800; +pub const FADF_RESERVED: DWORD = 0xf008; +STRUCT!{struct __tagBRECORD { + pvRecord: PVOID, + pRecInfo: *mut IRecordInfo, +}} +UNION!{union VARIANT_n3 { + [u64; 1] [u64; 2], + llVal llVal_mut: LONGLONG, + lVal lVal_mut: LONG, + bVal bVal_mut: BYTE, + iVal iVal_mut: SHORT, + fltVal fltVal_mut: FLOAT, + dblVal dblVal_mut: DOUBLE, + boolVal boolVal_mut: VARIANT_BOOL, + scode scode_mut: SCODE, + cyVal cyVal_mut: CY, + date date_mut: DATE, + bstrVal bstrVal_mut: BSTR, + punkVal punkVal_mut: *mut IUnknown, + pdispVal pdispVal_mut: *mut IDispatch, + parray parray_mut: *mut SAFEARRAY, + pbVal pbVal_mut: *mut BYTE, + piVal piVal_mut: *mut SHORT, + plVal plVal_mut: *mut LONG, + pllVal pllVal_mut: *mut LONGLONG, + pfltVal pfltVal_mut: *mut FLOAT, + pdblVal pdblVal_mut: *mut DOUBLE, + pboolVal pboolVal_mut: *mut VARIANT_BOOL, + pscode pscode_mut: *mut SCODE, + pcyVal pcyVal_mut: *mut CY, + pdate pdate_mut: *mut DATE, + pbstrVal pbstrVal_mut: *mut BSTR, + ppunkVal ppunkVal_mut: *mut *mut IUnknown, + ppdispVal ppdispVal_mut: *mut *mut IDispatch, + pparray pparray_mut: *mut *mut SAFEARRAY, + pvarVal pvarVal_mut: *mut VARIANT, + byref byref_mut: PVOID, + cVal cVal_mut: CHAR, + uiVal uiVal_mut: USHORT, + ulVal ulVal_mut: ULONG, + ullVal ullVal_mut: ULONGLONG, + intVal intVal_mut: INT, + uintVal uintVal_mut: UINT, + pdecVal pdecVal_mut: *mut DECIMAL, + pcVal pcVal_mut: *mut CHAR, + puiVal puiVal_mut: *mut USHORT, + pulVal pulVal_mut: *mut ULONG, + pullVal pullVal_mut: *mut ULONGLONG, + pintVal pintVal_mut: *mut INT, + puintVal puintVal_mut: *mut UINT, + n4 n4_mut: __tagBRECORD, +}} +STRUCT!{struct __tagVARIANT { + vt: VARTYPE, + wReserved1: WORD, + wReserved2: WORD, + wReserved3: WORD, + n3: VARIANT_n3, +}} +UNION!{union VARIANT_n1 { + [u64; 2] [u64; 3], + n2 n2_mut: __tagVARIANT, + decVal decVal_mut: DECIMAL, +}} +STRUCT!{struct VARIANT { + n1: VARIANT_n1, +}} +pub type LPVARIANT = *mut VARIANT; +pub type VARIANTARG = VARIANT; +pub type LPVARIANTARG = *mut VARIANT; +pub type REFVARIANT = *const VARIANT; +STRUCT!{struct _wireBRECORD { + fFlags: ULONG, + clSize: ULONG, + pRecInfo: *mut IRecordInfo, + pRecord: *mut byte, +}} +UNION!{union _wireVARIANT_u { + [u64; 2], + llVal llVal_mut: LONGLONG, + lVal lVal_mut: LONG, + bVal bVal_mut: BYTE, + iVal iVal_mut: SHORT, + fltVal fltVal_mut: FLOAT, + dblVal dblVal_mut: DOUBLE, + boolVal boolVal_mut: VARIANT_BOOL, + scode scode_mut: SCODE, + cyVal cyVal_mut: CY, + date date_mut: DATE, + bstrVal bstrVal_mut: wireBSTR, + punkVal punkVal_mut: *mut IUnknown, + pdispVal pdispVal_mut: *mut IDispatch, + parray parray_mut: wirePSAFEARRAY, + brecVal brecVal_mut: wireBRECORD, + pbVal pbVal_mut: *mut BYTE, + piVal piVal_mut: *mut SHORT, + plVal plVal_mut: *mut LONG, + pllVal pllVal_mut: *mut LONGLONG, + pfltVal pfltVal_mut: *mut FLOAT, + pdblVal pdblVal_mut: *mut DOUBLE, + pboolVal pboolVal_mut: *mut VARIANT_BOOL, + pscode pscode_mut: *mut SCODE, + pcyVal pcyVal_mut: *mut CY, + pdate pdate_mut: *mut DATE, + pbstrVal pbstrVal_mut: *mut wireBSTR, + ppunkVal ppunkVal_mut: *mut *mut IUnknown, + ppdispVal ppdispVal_mut: *mut *mut IDispatch, + pparray pparray_mut: *mut wirePSAFEARRAY, + pvarVal pvarVal_mut: *mut wireVARIANT, + cVal cVal_mut: CHAR, + uiVal uiVal_mut: USHORT, + ulVal ulVal_mut: ULONG, + ullVal ullVal_mut: ULONGLONG, + intVal intVal_mut: INT, + uintVal uintVal_mut: UINT, + decVal decVal_mut: DECIMAL, + pdecVal pdecVal_mut: *mut DECIMAL, + pcVal pcVal_mut: *mut CHAR, + puiVal puiVal_mut: *mut USHORT, + pulVal pulVal_mut: *mut ULONG, + pullVal pullVal_mut: *mut ULONGLONG, + pintVal pintVal_mut: *mut INT, + puintVal puintVal_mut: *mut UINT, +}} +STRUCT!{struct _wireVARIANT { + clSize: DWORD, + rpcReserved: DWORD, + vt: USHORT, + wReserved1: USHORT, + wReserved2: USHORT, + wReserved3: USHORT, + u: _wireVARIANT_u, +}} +pub type DISPID = LONG; +pub type MEMBERID = DISPID; +pub type HREFTYPE = DWORD; +ENUM!{enum TYPEKIND { + TKIND_ENUM = 0, + TKIND_RECORD, + TKIND_MODULE, + TKIND_INTERFACE, + TKIND_DISPATCH, + TKIND_COCLASS, + TKIND_ALIAS, + TKIND_UNION, + TKIND_MAX, +}} +UNION!{union TYPEDESC_u { + [usize; 1], + lptdesc lptdesc_mut: *mut TYPEDESC, + lpadesc lpadesc_mut: *mut ARRAYDESC, + hreftype hreftype_mut: HREFTYPE, +}} +STRUCT!{struct TYPEDESC { + u: TYPEDESC_u, + vt: VARTYPE, +}} +STRUCT!{struct ARRAYDESC { + tdescElem: TYPEDESC, + cDims: USHORT, + rgbounds: [SAFEARRAYBOUND; 1], +}} +STRUCT!{struct PARAMDESCEX { + cBytes: ULONG, + varDefaultValue: VARIANTARG, +}} +pub type LPPARAMDESCEX = *mut PARAMDESCEX; +STRUCT!{struct PARAMDESC { + pparamdescex: LPPARAMDESCEX, + wParamFlags: USHORT, +}} +pub type LPPARAMDESC = *mut PARAMDESC; +pub const PARAMFLAG_NONE: DWORD = 0; +pub const PARAMFLAG_FIN: DWORD = 0x1; +pub const PARAMFLAG_FOUT: DWORD = 0x2; +pub const PARAMFLAG_FLCID: DWORD = 0x4; +pub const PARAMFLAG_FRETVAL: DWORD = 0x8; +pub const PARAMFLAG_FOPT: DWORD = 0x10; +pub const PARAMFLAG_FHASDEFAULT: DWORD = 0x20; +pub const PARAMFLAG_FHASCUSTDATA: DWORD = 0x40; +STRUCT!{struct IDLDESC { + dwReserved: ULONG_PTR, + wIDLFlags: USHORT, +}} +pub type LPIDLDESC = *mut IDLDESC; +pub const IDLFLAG_NONE: DWORD = PARAMFLAG_NONE; +pub const IDLFLAG_FIN: DWORD = PARAMFLAG_FIN; +pub const IDLFLAG_FOUT: DWORD = PARAMFLAG_FOUT; +pub const IDLFLAG_FLCID: DWORD = PARAMFLAG_FLCID; +pub const IDLFLAG_FRETVAL: DWORD = PARAMFLAG_FRETVAL; +UNION!{union ELEMDESC_u { + [usize; 2], + idldesc idldesc_mut: IDLDESC, + paramdesc paramdesc_mut: PARAMDESC, +}} +STRUCT!{struct ELEMDESC { + tdesc: TYPEDESC, + u: ELEMDESC_u, +}} +pub type LPELEMDESC = *mut ELEMDESC; +STRUCT!{struct TYPEATTR { + guid: GUID, + lcid: LCID, + dwReserved: DWORD, + memidConstructor: MEMBERID, + memidDestructor: MEMBERID, + lpstrSchema: LPOLESTR, + cbSizeInstance: ULONG, + typekind: TYPEKIND, + cFuncs: WORD, + cVars: WORD, + cImplTypes: WORD, + cbSizeVft: WORD, + cbAlignment: WORD, + wTypeFlags: WORD, + wMajorVerNum: WORD, + wMinorVerNum: WORD, + tdescAlias: TYPEDESC, + idldescType: IDLDESC, +}} +pub type LPTYPEATTR = *mut TYPEATTR; +STRUCT!{struct DISPPARAMS { + rgvarg: *mut VARIANTARG, + rgdispidNamedArgs: *mut DISPID, + cArgs: UINT, + cNamedArgs: UINT, +}} +STRUCT!{struct EXCEPINFO { + wCode: WORD, + wReserved: WORD, + bstrSource: BSTR, + bstrDescription: BSTR, + bstrHelpFile: BSTR, + dwHelpContext: DWORD, + pvReserved: PVOID, + pfnDeferredFillIn: Option<unsafe extern "system" fn( + einfo: *mut EXCEPINFO, + ) -> HRESULT>, + scode: SCODE, +}} +ENUM!{enum CALLCONV { + CC_FASTCALL = 0, + CC_CDECL = 1, + CC_MSCPASCAL, + CC_PASCAL, + CC_MACPASCAL, + CC_STDCALL, + CC_FPFASTCALL, + CC_SYSCALL, + CC_MPWCDECL, + CC_MPWPASCAL, + CC_MAX, +}} +ENUM!{enum FUNCKIND { + FUNC_VIRTUAL = 0, + FUNC_PUREVIRTUAL, + FUNC_NONVIRTUAL, + FUNC_STATIC, + FUNC_DISPATCH, +}} +ENUM!{enum INVOKEKIND { + INVOKE_FUNC = 1, + INVOKE_PROPERTYGET = 2, + INVOKE_PROPERTYPUT = 4, + INVOKE_PROPERTYPUTREF = 8, +}} +STRUCT!{struct FUNCDESC { + memid: MEMBERID, + lprgscode: *mut SCODE, + lprgelemdescParam: *mut ELEMDESC, + funckind: FUNCKIND, + invkind: INVOKEKIND, + callconv: CALLCONV, + cParams: SHORT, + cParamsOpt: SHORT, + oVft: SHORT, + cScodes: SHORT, + elemdescFunc: ELEMDESC, + wFuncFlags: WORD, +}} +pub type LPFUNCDESC = *mut FUNCDESC; +ENUM!{enum VARKIND { + VAR_PERINSTANCE = 0, + VAR_STATIC, + VAR_CONST, + VAR_DISPATCH, +}} +pub const IMPLTYPEFLAG_FDEFAULT: DWORD = 0x1; +pub const IMPLTYPEFLAG_FSOURCE: DWORD = 0x2; +pub const IMPLTYPEFLAG_FRESTRICTED: DWORD = 0x4; +pub const IMPLTYPEFLAG_FDEFAULTVTABLE: DWORD = 0x8; +UNION!{union VARDESC_u { + [usize; 1], + oInst oInst_mut: ULONG, + lpvarValue lpvarValue_mut: *mut VARIANT, +}} +STRUCT!{struct VARDESC { + memid: MEMBERID, + lpstrSchema: LPOLESTR, + u: VARDESC_u, + elemdescVar: ELEMDESC, + wVarFlags: WORD, + varkind: VARKIND, +}} +pub type LPVARDESC = *mut VARDESC; +ENUM!{enum TYPEFLAGS { + TYPEFLAG_FAPPOBJECT = 0x1, + TYPEFLAG_FCANCREATE = 0x2, + TYPEFLAG_FLICENSED = 0x4, + TYPEFLAG_FPREDECLID = 0x8, + TYPEFLAG_FHIDDEN = 0x10, + TYPEFLAG_FCONTROL = 0x20, + TYPEFLAG_FDUAL = 0x40, + TYPEFLAG_FNONEXTENSIBLE = 0x80, + TYPEFLAG_FOLEAUTOMATION = 0x100, + TYPEFLAG_FRESTRICTED = 0x200, + TYPEFLAG_FAGGREGATABLE = 0x400, + TYPEFLAG_FREPLACEABLE = 0x800, + TYPEFLAG_FDISPATCHABLE = 0x1000, + TYPEFLAG_FREVERSEBIND = 0x2000, + TYPEFLAG_FPROXY = 0x4000, +}} +ENUM!{enum FUNCFLAGS { + FUNCFLAG_FRESTRICTED = 0x1, + FUNCFLAG_FSOURCE = 0x2, + FUNCFLAG_FBINDABLE = 0x4, + FUNCFLAG_FREQUESTEDIT = 0x8, + FUNCFLAG_FDISPLAYBIND = 0x10, + FUNCFLAG_FDEFAULTBIND = 0x20, + FUNCFLAG_FHIDDEN = 0x40, + FUNCFLAG_FUSESGETLASTERROR = 0x80, + FUNCFLAG_FDEFAULTCOLLELEM = 0x100, + FUNCFLAG_FUIDEFAULT = 0x200, + FUNCFLAG_FNONBROWSABLE = 0x400, + FUNCFLAG_FREPLACEABLE = 0x800, + FUNCFLAG_FIMMEDIATEBIND = 0x1000, +}} +ENUM!{enum VARFLAGS { + VARFLAG_FREADONLY = 0x1, + VARFLAG_FSOURCE = 0x2, + VARFLAG_FBINDABLE = 0x4, + VARFLAG_FREQUESTEDIT = 0x8, + VARFLAG_FDISPLAYBIND = 0x10, + VARFLAG_FDEFAULTBIND = 0x20, + VARFLAG_FHIDDEN = 0x40, + VARFLAG_FRESTRICTED = 0x80, + VARFLAG_FDEFAULTCOLLELEM = 0x100, + VARFLAG_FUIDEFAULT = 0x200, + VARFLAG_FNONBROWSABLE = 0x400, + VARFLAG_FREPLACEABLE = 0x800, + VARFLAG_FIMMEDIATEBIND = 0x1000, +}} +STRUCT!{struct CLEANLOCALSTORAGE { + pInterface: *mut IUnknown, + pStorage: PVOID, + flags: DWORD, +}} +STRUCT!{struct CUSTDATAITEM { + guid: GUID, + varValue: VARIANTARG, +}} +pub type LPCUSTDATAITEM = *mut CUSTDATAITEM; +STRUCT!{struct CUSTDATA { + cCustData: DWORD, + prgCustData: LPCUSTDATAITEM, +}} +pub type LPCUSTDATA = *mut CUSTDATA; +pub type LPCREATETYPEINFO = *mut ICreateTypeInfo; +RIDL!{#[uuid(0x00020405, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ICreateTypeInfo(ICreateTypeInfoVtbl): IUnknown(IUnknownVtbl) { + fn SetGuid( + guid: REFGUID, + ) -> HRESULT, + fn SetTypeFlags( + uTypeFlags: UINT, + ) -> HRESULT, + fn SetDocString( + pStrDoc: LPOLESTR, + ) -> HRESULT, + fn SetHelpContext( + dwHelpContext: DWORD, + ) -> HRESULT, + fn SetVersion( + wMajorVerNum: WORD, + wMinorVerNum: WORD, + ) -> HRESULT, + fn AddRefTypeInfo( + pTInfo: *mut ITypeInfo, + ) -> HRESULT, + fn AddFuncDesc( + index: UINT, + pFuncDesc: *mut FUNCDESC, + ) -> HRESULT, + fn SetImplTypeFlags( + index: UINT, + implTypeFlags: INT, + ) -> HRESULT, + fn SetAlignment( + cbAlignment: WORD, + ) -> HRESULT, + fn SetSchema( + pStrSchema: LPOLESTR, + ) -> HRESULT, + fn AddVarDesc( + index: UINT, + pVarDesc: *mut VARDESC, + ) -> HRESULT, + fn SetFuncAndParamNames( + index: UINT, + rgszNames: *mut LPOLESTR, + cNames: UINT, + ) -> HRESULT, + fn SetVarName( + index: UINT, + szName: LPOLESTR, + ) -> HRESULT, + fn SetTypeDescAlias( + pTDescAlias: *mut TYPEDESC, + ) -> HRESULT, + fn DefineFuncAsDllEntry( + index: UINT, + szDllName: LPOLESTR, + szProcName: LPOLESTR, + ) -> HRESULT, + fn SetFuncDocString( + index: UINT, + szDocString: LPOLESTR, + ) -> HRESULT, + fn SetVarDocString( + index: UINT, + szDocString: LPOLESTR, + ) -> HRESULT, + fn SetFuncHelpContext( + index: UINT, + dwHelpContext: DWORD, + ) -> HRESULT, + fn SetVarHelpContext( + index: UINT, + dwHelpContext: DWORD, + ) -> HRESULT, + fn SetMops( + index: UINT, + bstrMops: BSTR, + ) -> HRESULT, + fn SetTypeIdldesc( + pIdlDesc: *mut IDLDESC, + ) -> HRESULT, + fn LayOut() -> HRESULT, +}} +// LPCREATETYPEINFO2 +// ICreateTypeInfo2 +// LPCREATETYPELIB +// ICreateTypeLib +// LPCREATETYPELIB2 +// ICreateTypeLib2 +pub type LPDISPATCH = *mut IDispatch; +pub const DISPID_UNKNOWN: INT = -1; +pub const DISPID_VALUE: INT = 0; +pub const DISPID_PROPERTYPUT: INT = -3; +pub const DISPID_NEWENUM: INT = -4; +pub const DISPID_EVALUATE: INT = -5; +pub const DISPID_CONSTRUCTOR: INT = -6; +pub const DISPID_DESTRUCTOR: INT = -7; +pub const DISPID_COLLECT: INT = -8; +RIDL!{#[uuid(0x00020400, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IDispatch(IDispatchVtbl): IUnknown(IUnknownVtbl) { + fn GetTypeInfoCount( + pctinfo: *mut UINT, + ) -> HRESULT, + fn GetTypeInfo( + iTInfo: UINT, + lcid: LCID, + ppTInfo: *mut *mut ITypeInfo, + ) -> HRESULT, + fn GetIDsOfNames( + riid: REFIID, + rgszNames: *mut LPOLESTR, + cNames: UINT, + lcid: LCID, + rgDispId: *mut DISPID, + ) -> HRESULT, + fn Invoke( + dispIdMember: DISPID, + riid: REFIID, + lcid: LCID, + wFlags: WORD, + pDispParams: *mut DISPPARAMS, + pVarResult: *mut VARIANT, + pExcepInfo: *mut EXCEPINFO, + puArgErr: *mut UINT, + ) -> HRESULT, +}} +// IDispatch_RemoteInvoke_Proxy +// IDispatch_RemoteInvoke_Stub +// LPENUMVARIANT +// IEnumVARIANT +// IEnumVARIANT_RemoteNext_Proxy +// IEnumVARIANT_RemoteNext_Stub +RIDL!{#[uuid(0x0000002F, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IRecordInfo(IRecordInfoVtbl): IUnknown(IUnknownVtbl) { + fn RecordInit( + pvNew: PVOID, + ) -> HRESULT, + fn RecordClear( + pvExisting: PVOID, + ) -> HRESULT, + fn RecordCopy( + pvExisting: PVOID, + pvNew: PVOID, + ) -> HRESULT, + fn GetGuid( + pguid: *mut GUID, + ) -> HRESULT, + fn GetName( + pbstrName: *mut BSTR, + ) -> HRESULT, + fn GetSize( + pcbSize: *mut ULONG, + ) -> HRESULT, + fn GetTypeInfo( + ppTypeInfo: *mut *mut ITypeInfo, + ) -> HRESULT, + fn GetField( + pvData: PVOID, + szFieldName: LPCOLESTR, + pvarField: *mut VARIANT, + ) -> HRESULT, + fn GetFieldNoCopy( + pvData: PVOID, + szFieldName: LPCOLESTR, + pvarField: *mut VARIANT, + ppvDataCArray: *mut PVOID, + ) -> HRESULT, + fn PutField( + wFlags: ULONG, + pvData: PVOID, + szFieldName: LPCOLESTR, + pvarField: *mut VARIANT, + ) -> HRESULT, + fn PutFieldNoCopy( + wFlags: ULONG, + pvData: PVOID, + szFieldName: LPCOLESTR, + pvarField: *mut VARIANT, + ) -> HRESULT, + fn GetFieldNames( + pcNames: *mut ULONG, + rgBstrNames: *mut BSTR, + ) -> HRESULT, + fn IsMatchingType( + pRecordInfo: *mut IRecordInfo, + ) -> BOOL, + fn RecordCreate() -> PVOID, + fn RecordCreateCopy( + pvSource: PVOID, + ppvDest: *mut PVOID, + ) -> HRESULT, + fn RecordDestroy( + pvRecord: PVOID, + ) -> HRESULT, +}} +pub type LPTYPECOMP = *mut ITypeComp; +ENUM!{enum DESCKIND { + DESCKIND_NONE = 0, + DESCKIND_FUNCDESC = DESCKIND_NONE + 1, + DESCKIND_VARDESC = DESCKIND_FUNCDESC + 1, + DESCKIND_TYPECOMP = DESCKIND_VARDESC + 1, + DESCKIND_IMPLICITAPPOBJ = DESCKIND_TYPECOMP + 1, + DESCKIND_MAX = DESCKIND_IMPLICITAPPOBJ + 1, +}} +UNION!{union BINDPTR { + [usize; 1], + lpfuncdesc lpfuncdesc_mut: *mut FUNCDESC, + lpvardesc lpvardesc_mut: *mut VARDESC, + lptcomp lptcomp_mut: *mut ITypeComp, +}} +pub type LPBINDPTR = *mut BINDPTR; +RIDL!{#[uuid(0x00020403, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ITypeComp(ITypeCompVtbl): IUnknown(IUnknownVtbl) { + fn Bind( + szName: LPOLESTR, + lHashVal: ULONG, + wFlags: WORD, + ppTInfo: *mut *mut ITypeInfo, + pDescKind: *mut DESCKIND, + pBindPtr: *mut BINDPTR, + ) -> HRESULT, + fn BindType( + szName: LPOLESTR, + lHashVal: ULONG, + ppTInfo: *mut *mut ITypeInfo, + ppTComp: *mut *mut ITypeComp, + ) -> HRESULT, +}} +ENUM!{enum SYSKIND { + SYS_WIN16 = 0, + SYS_WIN32, + SYS_MAC, + SYS_WIN64, +}} +STRUCT!{struct TLIBATTR { + guid: GUID, + lcid: LCID, + syskind: SYSKIND, + wMajorVerNum: WORD, + wMinorVerNum: WORD, + wLibFlags: WORD, +}} +RIDL!{#[uuid(0x00020402, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ITypeLib(ITypeLibVtbl): IUnknown(IUnknownVtbl) { + fn GetTypeInfoCount() -> UINT, + fn GetTypeInfo( + index: UINT, + ppTInfo: *mut *mut ITypeInfo, + ) -> HRESULT, + fn GetTypeInfoType( + index: UINT, + pTKind: *mut TYPEKIND, + ) -> HRESULT, + fn GetTypeInfoOfGuid( + guid: REFGUID, + ppTInfo: *mut *mut ITypeInfo, + ) -> HRESULT, + fn GetLibAttr( + ppTLibAttr: *mut *mut TLIBATTR, + ) -> HRESULT, + fn GetTypeComp( + ppTComp: *mut *mut ITypeComp, + ) -> HRESULT, + fn GetDocumentation( + index: INT, + pbstrName: *mut BSTR, + pBstrDocString: *mut BSTR, + pdwHelpContext: *mut DWORD, + pBstrHelpFile: *mut BSTR, + ) -> HRESULT, + fn IsName( + szNameBuf: LPOLESTR, + lHashVal: ULONG, + pfName: *mut BOOL, + ) -> HRESULT, + fn FindName( + szNameBuf: LPOLESTR, + lHashVal: ULONG, + ppTInfo: *mut *mut ITypeInfo, + rgMemId: *mut MEMBERID, + pcFound: *mut USHORT, + ) -> HRESULT, + fn ReleaseTLibAttr( + pTLibAttr: *const TLIBATTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00020401, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ITypeInfo(ITypeInfoVtbl): IUnknown(IUnknownVtbl) { + fn GetTypeAttr( + ppTypeAttr: *mut *mut TYPEATTR, + ) -> HRESULT, + fn GetTypeComp( + ppTComp: *mut *mut ITypeComp, + ) -> HRESULT, + fn GetFuncDesc( + index: UINT, + ppFunDesc: *mut *mut FUNCDESC, + ) -> HRESULT, + fn GetVarDesc( + index: UINT, + pPVarDesc: *mut *mut VARDESC, + ) -> HRESULT, + fn GetNames( + memid: MEMBERID, + rgBstrNames: *mut BSTR, + cMaxNames: UINT, + pcNames: *mut UINT, + ) -> HRESULT, + fn GetRefTypeOfImplType( + index: UINT, + pRefType: *mut HREFTYPE, + ) -> HRESULT, + fn GetImplTypeFlags( + index: UINT, + pImplTypeFlags: *mut INT, + ) -> HRESULT, + fn GetIDsOfNames( + rgszNames: *mut LPOLESTR, + cNames: UINT, + pMemId: *mut MEMBERID, + ) -> HRESULT, + fn Invoke( + pvInstance: PVOID, + memid: MEMBERID, + wFlags: WORD, + pDispParams: *mut DISPPARAMS, + pVarResult: *mut VARIANT, + pExcepInfo: *mut EXCEPINFO, + puArgErr: *mut UINT, + ) -> HRESULT, + fn GetDocumentation( + memid: MEMBERID, + pBstrName: *mut BSTR, + pBstrDocString: *mut BSTR, + pdwHelpContext: *mut DWORD, + pBstrHelpFile: *mut BSTR, + ) -> HRESULT, + fn GetDllEntry( + memid: MEMBERID, + invKind: INVOKEKIND, + pBstrDllName: *mut BSTR, + pBstrName: *mut BSTR, + pwOrdinal: *mut WORD, + ) -> HRESULT, + fn GetRefTypeInfo( + hRefType: HREFTYPE, + ppTInfo: *mut *mut ITypeInfo, + ) -> HRESULT, + fn AddressOfMember( + memid: MEMBERID, + invKind: INVOKEKIND, + ppv: *mut PVOID, + ) -> HRESULT, + fn CreateInstance( + pUnkOuter: *mut IUnknown, + riid: REFIID, + ppvObj: *mut PVOID, + ) -> HRESULT, + fn GetMops( + memid: MEMBERID, + pBstrMops: *mut BSTR, + ) -> HRESULT, + fn GetContainingTypeLib( + ppTLib: *mut *mut ITypeLib, + pIndex: *mut UINT, + ) -> HRESULT, + fn ReleaseTypeAttr( + pTypeAttr: *mut TYPEATTR, + ) -> (), + fn ReleaseFuncDesc( + pFuncDesc: *mut FUNCDESC, + ) -> (), + fn ReleaseVarDesc( + pVarDesc: *mut VARDESC, + ) -> (), +}} +RIDL!{#[uuid(0x3127ca40, 0x446e, 0x11ce, 0x81, 0x35, 0x00, 0xaa, 0x00, 0x4b, 0xb8, 0x51)] +interface IErrorLog(IErrorLogVtbl): IUnknown(IUnknownVtbl) { + fn AddError( + pszPropName: LPCOLESTR, + pExcepInfo: *const EXCEPINFO, + ) -> HRESULT, +}} +pub type LPERRORLOG = *mut IErrorLog; diff --git a/winapi/src/um/objbase.rs b/winapi/src/um/objbase.rs new file mode 100644 index 000000000..7cafface2 --- /dev/null +++ b/winapi/src/um/objbase.rs @@ -0,0 +1,64 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Component object model defintions +use shared::minwindef::LPVOID; +use um::combaseapi::COINITBASE_MULTITHREADED; +use um::winnt::HRESULT; +ENUM!{enum COINIT { + COINIT_APARTMENTTHREADED = 0x2, + COINIT_MULTITHREADED = COINITBASE_MULTITHREADED, + COINIT_DISABLE_OLE1DDE = 0x4, + COINIT_SPEED_OVER_MEMORY = 0x8, +}} + // pub fn CoBuildVersion(); +extern "system" { + pub fn CoInitialize( + pvReserved: LPVOID, + ) -> HRESULT; +} + // pub fn CoRegisterMallocSpy(); + // pub fn CoRevokeMallocSpy(); + // pub fn CoRegisterInitializeSpy(); + // pub fn CoRevokeInitializeSpy(); + // pub fn CoGetSystemSecurityPermissions(); + // pub fn CoLoadLibrary(); + // pub fn CoFreeLibrary(); + // pub fn CoFreeAllLibraries(); + // pub fn CoGetInstanceFromFile(); + // pub fn CoGetInstanceFromIStorage(); + // pub fn CoAllowSetForegroundWindow(); + // pub fn DcomChannelSetHResult(); + // pub fn CoIsOle1Class(); + // pub fn CLSIDFromProgIDEx(); + // pub fn CoFileTimeToDosDateTime(); + // pub fn CoDosDateTimeToFileTime(); + // pub fn CoFileTimeNow(); + // pub fn CoRegisterMessageFilter(); + // pub fn CoRegisterChannelHook(); + // pub fn CoTreatAsClass(); + // pub fn CreateDataAdviseHolder(); + // pub fn CreateDataCache(); + // pub fn StgOpenAsyncDocfileOnIFillLockBytes(); + // pub fn StgGetIFillLockBytesOnILockBytes(); + // pub fn StgGetIFillLockBytesOnFile(); + // pub fn StgOpenLayoutDocfile(); + // pub fn CoInstall(); + // pub fn BindMoniker(); + // pub fn CoGetObject(); + // pub fn MkParseDisplayName(); + // pub fn MonikerRelativePathTo(); + // pub fn MonikerCommonPrefixWith(); + // pub fn CreateBindCtx(); + // pub fn CreateGenericComposite(); + // pub fn GetClassFile(); + // pub fn CreateClassMoniker(); + // pub fn CreateFileMoniker(); + // pub fn CreateItemMoniker(); + // pub fn CreateAntiMoniker(); + // pub fn CreatePointerMoniker(); + // pub fn CreateObjrefMoniker(); + // pub fn GetRunningObjectTable(); + // pub fn CreateStdProgressIndicator(); diff --git a/winapi/src/um/objidl.rs b/winapi/src/um/objidl.rs new file mode 100644 index 000000000..f3f0b27aa --- /dev/null +++ b/winapi/src/um/objidl.rs @@ -0,0 +1,507 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! this ALWAYS GENERATED file contains the definitions for the interfaces +use ctypes::c_void; +use shared::basetsd::UINT64; +use shared::guiddef::{CLSID, IID, REFCLSID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, HGLOBAL, ULONG, WORD}; +use shared::ntdef::LONG; +use shared::windef::{HBITMAP, HENHMETAFILE}; +use shared::wtypes::{CLIPFORMAT, HMETAFILEPICT}; +use shared::wtypesbase::{LPOLESTR, OLECHAR}; +use um::objidlbase::{IEnumString, IStream, STATSTG}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, ULARGE_INTEGER}; +//8402 +STRUCT!{struct BIND_OPTS { + cbStruct: DWORD, + grfFlags: DWORD, + grfMode: DWORD, + dwTickCountDeadline: DWORD, +}} +pub type LPBIND_OPTS = *mut BIND_OPTS; +//8479 +RIDL!{#[uuid(0x0000000e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IBindCtx(IBindCtxVtbl): IUnknown(IUnknownVtbl) { + fn RegisterObjectBound( + punk: *mut IUnknown, + ) -> HRESULT, + fn RevokeObjectBound( + punk: *mut IUnknown, + ) -> HRESULT, + fn ReleaseBoundObjects() -> HRESULT, + fn SetBindOptions( + pbindopts: *mut BIND_OPTS, + ) -> HRESULT, + fn GetBindOptions( + pbindopts: *mut BIND_OPTS, + ) -> HRESULT, + fn GetRunningObjectTable( + pprot: *mut *mut IRunningObjectTable, + ) -> HRESULT, + fn RegisterObjectParam( + pszKey: LPOLESTR, + punk: *mut IUnknown, + ) -> HRESULT, + fn GetObjectParam( + pszKey: LPOLESTR, + ppunk: *mut *mut IUnknown, + ) -> HRESULT, + fn EnumObjectParam( + ppenum: *mut *mut IEnumString, + ) -> HRESULT, + fn RevokeObjectParam( + pszKey: LPOLESTR, + ) -> HRESULT, +}} +//8681 +RIDL!{#[uuid(0x00000102, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumMoniker(IEnumMonikerVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IMoniker, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumMoniker, + ) -> HRESULT, +}} +//8958 +RIDL!{#[uuid(0x00000010, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IRunningObjectTable(IRunningObjectTableVtbl): IUnknown(IUnknownVtbl) { + fn Register( + grfFlags: DWORD, + punkObject: *mut IUnknown, + pmkObjectName: *mut IMoniker, + pdwRegister: *mut DWORD, + ) -> HRESULT, + fn Revoke( + dwRegister: DWORD, + ) -> HRESULT, + fn IsRunning( + pmkObjectName: *mut IMoniker, + ) -> HRESULT, + fn GetObject( + pmkObjectName: *mut IMoniker, + ppunkObject: *mut *mut IUnknown, + ) -> HRESULT, + fn NoteChangeTime( + dwRegister: DWORD, + pfiletime: *mut FILETIME, + ) -> HRESULT, + fn GetTimeOfLastChange( + pmkObjectName: *mut IMoniker, + pfiletime: *mut FILETIME, + ) -> HRESULT, + fn EnumRunning( + ppenumMoniker: *mut *mut IEnumMoniker, + ) -> HRESULT, +}} +//9125 +RIDL!{#[uuid(0x0000010c, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IPersist(IPersistVtbl): IUnknown(IUnknownVtbl) { + fn GetClassID( + pClassID: *mut CLSID, + ) -> HRESULT, +}} +//9207 +RIDL!{#[uuid(0x00000109, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IPersistStream(IPersistStreamVtbl): IPersist(IPersistVtbl) { + fn IsDirty() -> HRESULT, + fn Load( + pStm: *mut IStream, + ) -> HRESULT, + fn Save( + pStm: *mut IStream, + fClearDirty: BOOL, + ) -> HRESULT, + fn GetSizeMax( + pcbSize: *mut ULARGE_INTEGER, + ) -> HRESULT, +}} +//9350 +RIDL!{#[uuid(0x0000000f, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMoniker(IMonikerVtbl): IPersistStream(IPersistStreamVtbl) { + fn BindToObject( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + riidResult: REFIID, + ppvResult: *mut *mut c_void, + ) -> HRESULT, + fn BindToStorage( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + riid: REFIID, + ppvObj: *mut *mut c_void, + ) -> HRESULT, + fn Reduce( + pbc: *mut IBindCtx, + dwReduceHowFar: DWORD, + ppmkToLeft: *mut *mut IMoniker, + ppmkReduced: *mut *mut IMoniker, + ) -> HRESULT, + fn ComposeWith( + pmkRight: *mut IMoniker, + fOnlyIfNotGeneric: BOOL, + ppmkComposite: *mut *mut IMoniker, + ) -> HRESULT, + fn Enum( + fForward: BOOL, + ppenumMoniker: *mut *mut IEnumMoniker, + ) -> HRESULT, + fn IsEqual( + pmkOtherMoniker: *mut IMoniker, + ) -> HRESULT, + fn Hash( + pdwHash: *mut DWORD, + ) -> HRESULT, + fn IsRunning( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + pmkNewlyRunning: *mut IMoniker, + ) -> HRESULT, + fn GetTimeOfLastChange( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + pFileTime: *mut FILETIME, + ) -> HRESULT, + fn Inverse( + ppmk: *mut *mut IMoniker, + ) -> HRESULT, + fn CommonPrefixWith( + pmkOther: *mut IMoniker, + ppmkPrefix: *mut *mut IMoniker, + ) -> HRESULT, + fn RelativePathTo( + pmkOther: *mut IMoniker, + ppmkRelPath: *mut *mut IMoniker, + ) -> HRESULT, + fn GetDisplayName( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + ppszDisplayName: *mut LPOLESTR, + ) -> HRESULT, + fn ParseDisplayName( + pbc: *mut IBindCtx, + pmkToLeft: *mut IMoniker, + pszDisplayName: LPOLESTR, + pchEaten: *mut ULONG, + ppmkOut: *mut *mut IMoniker, + ) -> HRESULT, + fn IsSystemMoniker( + pdwMksys: *mut DWORD, + ) -> HRESULT, +}} +ENUM!{enum EOLE_AUTHENTICATION_CAPABILITIES { + EOAC_NONE = 0, + EOAC_MUTUAL_AUTH = 0x1, + EOAC_STATIC_CLOAKING = 0x20, + EOAC_DYNAMIC_CLOAKING = 0x40, + EOAC_ANY_AUTHORITY = 0x80, + EOAC_MAKE_FULLSIC = 0x100, + EOAC_DEFAULT = 0x800, + EOAC_SECURE_REFS = 0x2, + EOAC_ACCESS_CONTROL = 0x4, + EOAC_APPID = 0x8, + EOAC_DYNAMIC = 0x10, + EOAC_REQUIRE_FULLSIC = 0x200, + EOAC_AUTO_IMPERSONATE = 0x400, + EOAC_NO_CUSTOM_MARSHAL = 0x2000, + EOAC_DISABLE_AAA = 0x1000, +}} +STRUCT!{struct SOLE_AUTHENTICATION_SERVICE { + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pPrincipalName: *mut OLECHAR, + hr: HRESULT, +}} +RIDL!{#[uuid(0x0000000d, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumSTATSTG(IEnumSTATSTGVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut STATSTG, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSTATSTG, + ) -> HRESULT, +}} +pub type SNB = *const *const OLECHAR; +RIDL!{#[uuid(0x0000000b, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IStorage(IStorageVtbl): IUnknown(IUnknownVtbl) { + fn CreateStream( + pwcsName: *const OLECHAR, + grfMode: DWORD, + reserved1: DWORD, + reserved2: DWORD, + ppstm: *mut *mut IStream, + ) -> HRESULT, + fn OpenStream( + pwcsName: *const OLECHAR, + reserved1: *const c_void, + grfMode: DWORD, + reserved2: DWORD, + ppstm: *mut *mut IStream, + ) -> HRESULT, + fn CreateStorage( + pwcsName: *const OLECHAR, + grfMode: DWORD, + reserved1: DWORD, + reserved2: DWORD, + ppstg: *mut *mut IStorage, + ) -> HRESULT, + fn OpenStorage( + pwcsName: *const OLECHAR, + pstgPriority: IStorage, + grfMode: DWORD, + snbExclude: SNB, + reserved: DWORD, + ppstg: *mut *mut IStorage, + ) -> HRESULT, + fn CopyTo( + ciidExclude: DWORD, + rgiidExclude: *const IID, + snbExclude: SNB, + pstgDest: *const IStorage, + ) -> HRESULT, + fn MoveElementTo( + pwcsName: *const OLECHAR, + pstgDest: *const IStorage, + pwcsNewName: *const OLECHAR, + grfFlags: DWORD, + ) -> HRESULT, + fn Commit( + grfCommitFlags: DWORD, + ) -> HRESULT, + fn Revert() -> HRESULT, + fn EnumElements( + reserved1: DWORD, + reserved2: *const c_void, + reserved3: DWORD, + ppenum: *mut *mut IEnumSTATSTG, + ) -> HRESULT, + fn DestroyElement( + pwcsName: *const OLECHAR, + ) -> HRESULT, + fn RenameElement( + pwcsOldName: *const OLECHAR, + pwcsNewName: *const OLECHAR, + ) -> HRESULT, + fn SetElementTimes( + pwcsName: *const OLECHAR, + pctime: *const FILETIME, + patime: *const FILETIME, + pmtime: *const FILETIME, + ) -> HRESULT, + fn SetClass( + clsid: REFCLSID, + ) -> HRESULT, + fn SetStateBits( + grfStateBits: DWORD, + grfMask: DWORD, + ) -> HRESULT, + fn Stat( + pstatstg: *mut STATSTG, + grfStatFlag: DWORD, + ) -> HRESULT, +}} +STRUCT!{struct DVTARGETDEVICE { + tdSize: DWORD, + tdDriverNameOffset: WORD, + tdDeviceNameOffset: WORD, + tdPortNameOffset: WORD, + tdExtDevmodeOFfset: WORD, + tdData: [BYTE; 1], +}} +STRUCT!{struct FORMATETC { + cfFormat: CLIPFORMAT, + ptd: *const DVTARGETDEVICE, + dwAspect: DWORD, + lindex: LONG, + tymed: DWORD, +}} +RIDL!{#[uuid(0x00000103, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumFORMATETC(IEnumFORMATETCVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut FORMATETC, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumFORMATETC, + ) -> HRESULT, +}} +ENUM!{enum ADVF { + ADVF_NODATA = 1, + ADVF_PRIMEFIRST = 2, + ADVF_ONLYONCE = 4, + ADVF_DATAONSTOP = 64, + ADVFCACHE_NOHANDLER = 8, + ADVFCACHE_FORCEBUILTIN = 16, + ADVFCACHE_ONSAVE = 32, +}} +STRUCT!{struct STATDATA { + formatetc: FORMATETC, + advf: DWORD, + pAdvSInk: *mut IAdviseSink, + dwConnection: DWORD, +}} +RIDL!{#[uuid(0x00000105, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumSTATDATA(IEnumSTATDATAVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut STATDATA, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSTATDATA, + ) -> HRESULT, +}} +ENUM!{enum TYMED { + TYMED_HGLOBAL = 1, + TYMED_FILE = 2, + TYMED_ISTREAM = 4, + TYMED_ISTORAGE = 8, + TYMED_GDI = 16, + TYMED_MFPICT = 32, + TYMED_ENHMF = 64, + TYMED_NULL = 0, +}} +UNION!{union STGMEDIUM_u { + [u64; 7], //TODO: I guessed to move on + hBitmap hBitmap_mut: HBITMAP, + hMetaFilePict hMetaFilePict_mut: HMETAFILEPICT, + hEnhMetaFile hEnhMetaFile_mut: HENHMETAFILE, + hGlobal hGlobal_mut: HGLOBAL, + lpszFileName lpszFileName_mut: LPOLESTR, + pstm pstm_mut: *mut IStream, + pstg pstg_mut: *mut IStorage, +}} +STRUCT!{struct STGMEDIUM { + tymed: DWORD, + u: *mut STGMEDIUM_u, + pUnkForRelease: *mut IUnknown, +}} +RIDL!{#[uuid(0x0000010f, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IAdviseSink(IAdviseSinkVtbl): IUnknown(IUnknownVtbl) { + fn OnDataChange( + pformatetc: *mut FORMATETC, + pStgmed: *mut STGMEDIUM, + ) -> c_void, + fn OnViewChange( + dwAspect: DWORD, + lindex: LONG, + ) -> c_void, + fn OnRename( + pmk: *mut IMoniker, + ) -> c_void, + fn OnSave() -> c_void, + fn OnClose() -> c_void, +}} +ENUM!{enum DATADIR { + DATADIR_GET = 1, + DATADIR_SET = 2, +}} +pub type LPDATAOBJECT = *mut IDataObject; +RIDL!{#[uuid(0x0000010e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IDataObject(IDataObjectVtbl): IUnknown(IUnknownVtbl) { + fn GetData( + pformatetcIn: *const FORMATETC, + pmedium: *mut STGMEDIUM, + ) -> HRESULT, + fn GetDataHere( + pformatetc: *const FORMATETC, + pmedium: *mut STGMEDIUM, + ) -> HRESULT, + fn QueryGetData( + pformatetc: *const FORMATETC, + ) -> HRESULT, + fn GetCanonicalFormatEtc( + pformatetcIn: *const FORMATETC, + pformatetcOut: *mut FORMATETC, + ) -> HRESULT, + fn SetData( + pformatetc: *const FORMATETC, + pformatetcOut: *const FORMATETC, + fRelease: BOOL, + ) -> HRESULT, + fn EnumFormatEtc( + dwDirection: DWORD, + ppenumFormatEtc: *mut *mut IEnumFORMATETC, + ) -> HRESULT, + fn DAdvise( + pformatetc: *const FORMATETC, + advf: DWORD, + pAdvSInk: *const IAdviseSink, + pdwConnection: *mut DWORD, + ) -> HRESULT, + fn DUnadvise( + dwConnection: DWORD, + ) -> HRESULT, + fn EnumDAdvise( + ppenumAdvise: *const *const IEnumSTATDATA, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa2f05a09, 0x27a2, 0x42b5, 0xbc, 0x0e, 0xac, 0x16, 0x3e, 0xf4, 0x9d, 0x9b)] +interface IApartmentShutdown(IApartmentShutdownVtbl): IUnknown(IUnknownVtbl) { + fn OnUninitialize( + ui64ApartmentIdentifier: UINT64, + ) -> (), +}} +RIDL!{#[uuid(0x00000003, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMarshal(IMarshalVtbl): IUnknown(IUnknownVtbl) { + fn GetUnmarshalClass( + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + pCid: *mut CLSID, + ) -> HRESULT, + fn GetMarshalSizeMax( + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + pSize: *mut DWORD, + ) -> HRESULT, + fn MarshalInterface( + pStm: *mut IStream, + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + ) -> HRESULT, + fn UnmarshalInterface( + pStm: *mut IStream, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseMarshalData( + pStm: *mut IStream, + ) -> HRESULT, + fn DisconnectObject( + dwReserved: DWORD, + ) -> HRESULT, +}} diff --git a/winapi/src/um/objidlbase.rs b/winapi/src/um/objidlbase.rs new file mode 100644 index 000000000..9984480ea --- /dev/null +++ b/winapi/src/um/objidlbase.rs @@ -0,0 +1,952 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_int, c_void}; +use shared::basetsd::{SIZE_T, ULONG_PTR}; +use shared::guiddef::{CLSID, GUID, IID, REFCLSID, REFGUID, REFIID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, ULONG}; +use shared::wtypesbase::{COAUTHINFO, DOUBLE, LPOLESTR, OLECHAR}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LARGE_INTEGER, LONG, LPWSTR, ULARGE_INTEGER}; +STRUCT!{struct COSERVERINFO { + dwReserved1: DWORD, + pwszName: LPWSTR, + pAuthInfo: *mut COAUTHINFO, + dwReserved2: DWORD, +}} +pub type LPMARSHAL = *mut IMarshal; +RIDL!{#[uuid(0x00000003, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMarshal(IMarshalVtbl): IUnknown(IUnknownVtbl) { + fn GetUnmarshalClass( + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + pCid: *mut CLSID, + ) -> HRESULT, + fn GetMarshalSizeMax( + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + pSize: *mut DWORD, + ) -> HRESULT, + fn MarshalInterface( + pStm: *mut IStream, + riid: REFIID, + pv: *mut c_void, + dwDestContext: DWORD, + pvDestContext: *mut c_void, + mshlflags: DWORD, + ) -> HRESULT, + fn UnmarshalInterface( + pStm: *mut IStream, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn ReleaseMarshalData( + pStm: *mut IStream, + ) -> HRESULT, + fn DisconnectObject( + dwReserved: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xecc8691b, 0xc1db, 0x4dc0, 0x85, 0x5e, 0x65, 0xf6, 0xc5, 0x51, 0xaf, 0x49)] +interface INoMarshal(INoMarshalVtbl): IUnknown(IUnknownVtbl) {}} +RIDL!{#[uuid(0x94ea2b94, 0xe9cc, 0x49e0, 0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90)] +interface IAgileObject(IAgileObjectVtbl): IUnknown(IUnknownVtbl) {}} +ENUM!{enum ACTIVATIONTYPE { + ACTIVATIONTYPE_UNCATEGORIZED = 0, + ACTIVATIONTYPE_FROM_MONIKER = 0x1, + ACTIVATIONTYPE_FROM_DATA = 0x2, + ACTIVATIONTYPE_FROM_STORAGE = 0x4, + ACTIVATIONTYPE_FROM_STREAM = 0x8, + ACTIVATIONTYPE_FROM_FILE = 0x10, +}} +RIDL!{#[uuid(0x00000017, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IActivationFilter(IActivationFilterVtbl): IUnknown(IUnknownVtbl) { + fn HandleActivation( + dwActivationType: DWORD, + rclsid: REFCLSID, + pReplacementClsId: *mut CLSID, + ) -> HRESULT, +}} +pub type LPMARSHAL2 = *mut IMarshal2; +RIDL!{#[uuid(0x000001cf, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMarshal2(IMarshal2Vtbl): IMarshal(IMarshalVtbl) {}} +pub type LPMALLOC = *mut IMalloc; +RIDL!{#[uuid(0x00000002, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMalloc(IMallocVtbl): IUnknown(IUnknownVtbl) { + fn Alloc( + cb: SIZE_T, + ) -> *mut c_void, + fn Realloc( + pv: *mut c_void, + cb: SIZE_T, + ) -> *mut c_void, + fn Free( + pv: *mut c_void, + ) -> (), + fn GetSize( + pv: *mut c_void, + ) -> SIZE_T, + fn DidAlloc( + pv: *mut c_void, + ) -> c_int, + fn HeapMinimize() -> (), +}} +pub type LPSTDMARSHALINFO = IStdMarshalInfo; +RIDL!{#[uuid(0x00000018, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IStdMarshalInfo(IStdMarshalInfoVtbl): IUnknown(IUnknownVtbl) { + fn GetClassForHandler( + dwDestContext: DWORD, + pvDestContext: *mut c_void, + pClsid: *mut CLSID, + ) -> HRESULT, +}} +ENUM!{enum EXTCONN { + EXTCONN_STRONG = 0x1, + EXTCONN_WEAK = 0x2, + EXTCONN_CALLABLE = 0x4, +}} +RIDL!{#[uuid(0x00000019, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IExternalConnection(IExternalConnectionVtbl): IUnknown(IUnknownVtbl) { + fn AddConnection( + extconn: DWORD, + reserved: DWORD, + ) -> DWORD, + fn ReleaseConnection( + extconn: DWORD, + reserved: DWORD, + fLastReleaseCloses: BOOL, + ) -> DWORD, +}} +pub type LPMULTIQI = *mut IMultiQI; +STRUCT!{struct MULTI_QI { + pIID: *const IID, + pItf: *mut IUnknown, + hr: HRESULT, +}} +RIDL!{#[uuid(0x00000020, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IMultiQI(IMultiQIVtbl): IUnknown(IUnknownVtbl) { + fn QueryMultipleInterfaces( + cMQIs: ULONG, + pMQIs: *mut MULTI_QI, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x000e0020, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface AsyncIMultiQI(AsyncIMultiQIVtbl): IUnknown(IUnknownVtbl) { + fn Begin_QueryMultipleInterfaces( + cMQIs: ULONG, + pMQIs: *mut MULTI_QI, + ) -> HRESULT, + fn Finish_QueryMultipleInterfaces( + pMQIs: *mut MULTI_QI, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000021, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IInternalUnknown(IInternalUnknownVtbl): IUnknown(IUnknownVtbl) { + fn QueryInternalInterface( + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000100, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumUnknown(IEnumUnknownVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut IUnknown, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000101, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumString(IEnumStringVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut LPOLESTR, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumString, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0c733a30, 0x2a1c, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d)] +interface ISequentialStream(ISequentialStreamVtbl): IUnknown(IUnknownVtbl) { + fn Read( + pv: *mut c_void, + cb: ULONG, + pcbRead: *mut ULONG, + ) -> HRESULT, + fn Write( + pv: *const c_void, + cb: ULONG, + pcbWritten: *mut ULONG, + ) -> HRESULT, +}} +STRUCT!{struct STATSTG { + pwcsName: LPOLESTR, + type_: DWORD, + cbSize: ULARGE_INTEGER, + mtime: FILETIME, + ctime: FILETIME, + atime: FILETIME, + grfMode: DWORD, + grfLocksSupported: DWORD, + clsid: CLSID, + grfStateBits: DWORD, + reserved: DWORD, +}} +ENUM!{enum STGTY { + STGTY_STORAGE = 1, + STGTY_STREAM = 2, + STGTY_LOCKBYTES = 3, + STGTY_PROPERTY = 4, +}} +ENUM!{enum STREAM_SEEK { + STREAM_SEEK_SET = 0, + STREAM_SEEK_CUR = 1, + STREAM_SEEK_END = 2, +}} +ENUM!{enum LOCKTYPE { + LOCK_WRITE = 1, + LOCK_EXCLUSIVE = 2, + LOCK_ONLYONCE = 4, +}} +pub type LPSTREAM = *mut IStream; +RIDL!{#[uuid(0x0000000c, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IStream(IStreamVtbl): ISequentialStream(ISequentialStreamVtbl) { + fn Seek( + dlibMove: LARGE_INTEGER, + dwOrigin: DWORD, + plibNewPosition: *mut ULARGE_INTEGER, + ) -> HRESULT, + fn SetSize( + libNewSize: ULARGE_INTEGER, + ) -> HRESULT, + fn CopyTo( + pstm: *mut IStream, + cb: ULARGE_INTEGER, + pcbRead: *mut ULARGE_INTEGER, + pcbWritten: *mut ULARGE_INTEGER, + ) -> HRESULT, + fn Commit( + grfCommitFlags: DWORD, + ) -> HRESULT, + fn Revert() -> HRESULT, + fn LockRegion( + libOffset: ULARGE_INTEGER, + cb: ULARGE_INTEGER, + dwLockType: DWORD, + ) -> HRESULT, + fn UnlockRegion( + libOffset: ULARGE_INTEGER, + cb: ULARGE_INTEGER, + dwLockType: DWORD, + ) -> HRESULT, + fn Stat( + pstatstg: *mut STATSTG, + grfStatFlag: DWORD, + ) -> HRESULT, + fn Clone( + ppstm: *mut *mut IStream, + ) -> HRESULT, +}} +pub type RPCOLEDATAREP = ULONG; +STRUCT!{struct RPCOLEMESSAGE { + reserved1: *mut c_void, + dataRepresentation: RPCOLEDATAREP, + Buffer: *mut c_void, + cbBuffer: ULONG, + iMethod: ULONG, + reserved2: [*mut c_void; 5], + rpcFlags: ULONG, +}} +pub type PRPCOLEMESSAGE = *mut RPCOLEMESSAGE; +RIDL!{#[uuid(0xd5f56b60, 0x593b, 0x101a, 0xb5, 0x69, 0x08, 0x00, 0x2b, 0x2d, 0xbf, 0x7a)] +interface IRpcChannelBuffer(IRpcChannelBufferVtbl): IUnknown(IUnknownVtbl) { + fn GetBuffer( + pMessage: *mut RPCOLEMESSAGE, + riid: REFIID, + ) -> HRESULT, + fn SendReceive( + pMessage: *mut RPCOLEMESSAGE, + pStatus: *mut ULONG, + ) -> HRESULT, + fn FreeBuffer( + pMessage: *mut RPCOLEMESSAGE, + ) -> HRESULT, + fn GetDestCtx( + pdwDestContext: *mut DWORD, + ppvDestContext: *mut *mut c_void, + ) -> HRESULT, + fn IsConnected() -> HRESULT, +}} +RIDL!{#[uuid(0x594f31d0, 0x7f19, 0x11d0, 0xb1, 0x94, 0x00, 0xa0, 0xc9, 0x0d, 0xc8, 0xbf)] +interface IRpcChannelBuffer2(IRpcChannelBuffer2Vtbl): IRpcChannelBuffer(IRpcChannelBufferVtbl) { + fn GetProtocolVersion( + pdwVersion: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa5029fb6, 0x3c34, 0x11d1, 0x9c, 0x99, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xaa)] +interface IAsyncRpcChannelBuffer(IAsyncRpcChannelBufferVtbl): + IRpcChannelBuffer2(IRpcChannelBuffer2Vtbl) { + fn Send( + pMsg: *mut RPCOLEMESSAGE, + pSync: *mut ISynchronize, + pulStatus: *mut ULONG, + ) -> HRESULT, + fn Receive( + pMsg: *mut RPCOLEMESSAGE, + pulStatus: *mut ULONG, + ) -> HRESULT, + fn GetDestCtxEx( + pMsg: *mut RPCOLEMESSAGE, + pdwDestContext: *mut DWORD, + ppvDestContext: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x25b15600, 0x0115, 0x11d0, 0xbf, 0x0d, 0x00, 0xaa, 0x00, 0xb8, 0xdf, 0xd2)] +interface IRpcChannelBuffer3(IRpcChannelBuffer3Vtbl): IRpcChannelBuffer2(IRpcChannelBuffer2Vtbl) { + fn Send( + pMsg: *mut RPCOLEMESSAGE, + pulStatus: *mut ULONG, + ) -> HRESULT, + fn Receive( + pMsg: *mut RPCOLEMESSAGE, + ulSize: ULONG, + pulStatus: *mut ULONG, + ) -> HRESULT, + fn Cancel( + pMsg: *mut RPCOLEMESSAGE, + ) -> HRESULT, + fn GetCallContext( + pMsg: *mut RPCOLEMESSAGE, + riid: REFIID, + pInterface: *mut *mut c_void, + ) -> HRESULT, + fn GetDestCtxEx( + pMsg: *mut RPCOLEMESSAGE, + pdwDestContext: *mut DWORD, + ppvDestContext: *mut *mut c_void, + ) -> HRESULT, + fn GetState( + pMsg: *mut RPCOLEMESSAGE, + pState: *mut DWORD, + ) -> HRESULT, + fn RegisterAsync( + pMsg: *mut RPCOLEMESSAGE, + pAsyncMgr: *mut IAsyncManager, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x58a08519, 0x24c8, 0x4935, 0xb4, 0x82, 0x3f, 0xd8, 0x23, 0x33, 0x3a, 0x4f)] +interface IRpcSyntaxNegotiate(IRpcSyntaxNegotiateVtbl): IUnknown(IUnknownVtbl) { + fn NegotiateSyntax( + pMsg: *mut RPCOLEMESSAGE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd5f56a34, 0x593b, 0x101a, 0xb5, 0x69, 0x08, 0x00, 0x2b, 0x2d, 0xbf, 0x7a)] +interface IRpcProxyBuffer(IRpcProxyBufferVtbl): IUnknown(IUnknownVtbl) { + fn Connect( + pRpcChannelBuffer: *mut IRpcChannelBuffer, + ) -> HRESULT, + fn Disconnect() -> (), +}} +RIDL!{#[uuid(0xd5f56afc, 0x593b, 0x101a, 0xb5, 0x69, 0x08, 0x00, 0x2b, 0x2d, 0xbf, 0x7a)] +interface IRpcStubBuffer(IRpcStubBufferVtbl): IUnknown(IUnknownVtbl) { + fn Connect( + pUnkServer: *mut IUnknown, + ) -> HRESULT, + fn Disconnect() -> (), + fn Invoke( + _prpcmsg: *mut RPCOLEMESSAGE, + _pRpcChannelBuffer: *mut IRpcChannelBuffer, + ) -> HRESULT, + fn IsIIDSupported( + riid: REFIID, + ) -> *mut IRpcStubBuffer, + fn CountRefs() -> ULONG, + fn DebugServerQueryInterface( + ppv: *mut *mut c_void, + ) -> HRESULT, + fn DebugServerRelease( + pv: *mut c_void, + ) -> (), +}} +RIDL!{#[uuid(0xd5f569d0, 0x593b, 0x101a, 0xb5, 0x69, 0x08, 0x00, 0x2b, 0x2d, 0xbf, 0x7a)] +interface IPSFactoryBuffer(IPSFactoryBufferVtbl): IUnknown(IUnknownVtbl) { + fn CreateProxy( + pUnkOuter: *mut IUnknown, + riid: REFIID, + ppProxy: *mut *mut IRpcProxyBuffer, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn CreateStub( + riid: REFIID, + pUnkServer: *mut *mut IUnknown, + ppStub: *mut *mut IRpcStubBuffer, + ) -> HRESULT, +}} +STRUCT!{struct SChannelHookCallInfo { + iid: IID, + cbSize: DWORD, + uCausality: GUID, + dwServerPid: DWORD, + iMethod: DWORD, + pObject: *mut c_void, +}} +RIDL!{#[uuid(0x1008c4a0, 0x7613, 0x11cf, 0x9a, 0xf1, 0x00, 0x20, 0xaf, 0x6e, 0x72, 0xf4)] +interface IChannelHook(IChannelHookVtbl): IUnknown(IUnknownVtbl) { + fn ClientGetSize( + uExtent: REFGUID, + riid: REFIID, + pDataSize: *mut ULONG, + ) -> (), + fn ClientFillBuffer( + uExtent: REFGUID, + riid: REFIID, + pDataSize: *mut ULONG, + pDataBuffer: *mut c_void, + ) -> (), + fn ClientNotify( + uExtent: REFGUID, + riid: REFIID, + cbDataSize: ULONG, + pDataBuffer: *mut c_void, + lDataRep: DWORD, + hrFault: HRESULT, + ) -> (), + fn ServerNotify( + uExtent: REFGUID, + riid: REFIID, + cbDataSize: ULONG, + pDataBuffer: *mut c_void, + lDataRep: DWORD, + ) -> (), + fn ServerGetSize( + uExtent: REFGUID, + riid: REFIID, + hrFault: HRESULT, + pDataSize: *mut ULONG, + ) -> (), + fn ServerFillBuffer( + uExtent: REFGUID, + riid: REFIID, + pDataSize: *mut ULONG, + pDataBuffer: *mut c_void, + hrFault: HRESULT, + ) -> (), +}} +STRUCT!{struct SOLE_AUTHENTICATION_SERVICE { + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pPrincipalName: *mut OLECHAR, + hr: HRESULT, +}} +pub type PSOLE_AUTHENTICATION_SERVICE = *mut SOLE_AUTHENTICATION_SERVICE; +ENUM!{enum EOLE_AUTHENTICATION_CAPABILITIES { + EOAC_NONE = 0, + EOAC_MUTUAL_AUTH = 0x1, + EOAC_STATIC_CLOAKING = 0x20, + EOAC_DYNAMIC_CLOAKING = 0x40, + EOAC_ANY_AUTHORITY = 0x80, + EOAC_MAKE_FULLSIC = 0x100, + EOAC_DEFAULT = 0x800, + EOAC_SECURE_REFS = 0x2, + EOAC_ACCESS_CONTROL = 0x4, + EOAC_APPID = 0x8, + EOAC_DYNAMIC = 0x10, + EOAC_REQUIRE_FULLSIC = 0x200, + EOAC_AUTO_IMPERSONATE = 0x400, + EOAC_DISABLE_AAA = 0x1000, + EOAC_NO_CUSTOM_MARSHAL = 0x2000, + EOAC_RESERVED1 = 0x4000, +}} +pub const COLE_DEFAULT_PRINCIPAL: *mut OLECHAR = -1isize as *mut OLECHAR; +pub const COLE_DEFAULT_AUTHINFO: *mut c_void = -1isize as *mut c_void; +STRUCT!{struct SOLE_AUTHENTICATION_INFO { + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pAuthInfo: *mut c_void, +}} +pub type PSOLE_AUTHENTICATION_INFO = *mut SOLE_AUTHENTICATION_INFO; +STRUCT!{struct SOLE_AUTHENTICATION_LIST { + cAuthInfo: DWORD, + aAuthInfo: *mut SOLE_AUTHENTICATION_INFO, +}} +pub type PSOLE_AUTHENTICATION_LIST = *mut SOLE_AUTHENTICATION_LIST; +RIDL!{#[uuid(0x0000013d, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IClientSecurity(IClientSecurityVtbl): IUnknown(IUnknownVtbl) { + fn QueryBlanket( + pProxy: *mut IUnknown, + pAuthnSvc: *mut DWORD, + pAuthzSvc: *mut DWORD, + pServerPrincName: *mut *mut OLECHAR, + pAuthnLevel: *mut DWORD, + pImpLevel: *mut DWORD, + pAuthInfo: *mut *mut c_void, + pCapabilities: *mut DWORD, + ) -> HRESULT, + fn SetBlanket( + pProxy: *mut IUnknown, + dwAuthnSvc: DWORD, + dwAuthzSvc: DWORD, + pServerPrincName: *mut OLECHAR, + dwAuthnLevel: DWORD, + dwImpLevel: DWORD, + pAuthInfo: *mut c_void, + dwCapabilities: DWORD, + ) -> HRESULT, + fn CopyProxy( + pProxy: *mut IUnknown, + ppCopy: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0000013e, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IServerSecurity(IServerSecurityVtbl): IUnknown(IUnknownVtbl) { + fn QueryBlanket( + pAuthnSvc: *mut DWORD, + pAuthzSvc: *mut DWORD, + pServerPrincName: *mut *mut OLECHAR, + pAuthnLevel: *mut DWORD, + pImpLevel: *mut DWORD, + pPrivs: *mut *mut c_void, + pCapabilities: *mut DWORD, + ) -> HRESULT, + fn ImpersonateClient() -> HRESULT, + fn RevertToSelf() -> HRESULT, + fn IsImpersonating() -> BOOL, +}} +ENUM!{enum RPCOPT_PROPERTIES { + COMBND_RPCTIMEOUT = 0x1, + COMBND_SERVER_LOCALITY = 0x2, + COMBND_RESERVED1 = 0x4, + COMBND_RESERVED2 = 0x5, + COMBND_RESERVED3 = 0x8, + COMBND_RESERVED4 = 0x10, +}} +ENUM!{enum RPCOPT_SERVER_LOCALITY_VALUES { + SERVER_LOCALITY_PROCESS_LOCAL = 0, + SERVER_LOCALITY_MACHINE_LOCAL = 1, + SERVER_LOCALITY_REMOTE = 2, +}} +RIDL!{#[uuid(0x00000144, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IRpcOptions(IRpcOptionsVtbl): IUnknown(IUnknownVtbl) { + fn Set( + pPrx: *mut IUnknown, + dwProperty: RPCOPT_PROPERTIES, + dwValue: ULONG_PTR, + ) -> HRESULT, + fn Query( + pPrx: *mut IUnknown, + dwProperty: RPCOPT_PROPERTIES, + pdwValue: *mut ULONG_PTR, + ) -> HRESULT, +}} +ENUM!{enum GLOBALOPT_PROPERTIES { + COMGLB_EXCEPTION_HANDLING = 1, + COMGLB_APPID = 2, + COMGLB_RPC_THREADPOOL_SETTING = 3, + COMGLB_RO_SETTINGS = 4, + COMGLB_UNMARSHALING_POLICY = 5, + COMGLB_PROPERTIES_RESERVED1 = 6, +}} +ENUM!{enum GLOBALOPT_EH_VALUES { + COMGLB_EXCEPTION_HANDLE = 0, + COMGLB_EXCEPTION_DONOT_HANDLE_FATAL = 1, + COMGLB_EXCEPTION_DONOT_HANDLE = COMGLB_EXCEPTION_DONOT_HANDLE_FATAL, + COMGLB_EXCEPTION_DONOT_HANDLE_ANY = 2, +}} +ENUM!{enum GLOBALOPT_RPCTP_VALUES { + COMGLB_RPC_THREADPOOL_SETTING_DEFAULT_POOL = 0, + COMGLB_RPC_THREADPOOL_SETTING_PRIVATE_POOL = 1, +}} +ENUM!{enum GLOBALOPT_RO_FLAGS { + COMGLB_STA_MODALLOOP_REMOVE_TOUCH_MESSAGES = 0x1, + COMGLB_STA_MODALLOOP_SHARED_QUEUE_REMOVE_INPUT_MESSAGES = 0x2, + COMGLB_STA_MODALLOOP_SHARED_QUEUE_DONOT_REMOVE_INPUT_MESSAGES = 0x4, + COMGLB_FAST_RUNDOWN = 0x8, + COMGLB_RESERVED1 = 0x10, + COMGLB_RESERVED2 = 0x20, + COMGLB_RESERVED3 = 0x40, + COMGLB_STA_MODALLOOP_SHARED_QUEUE_REORDER_POINTER_MESSAGES = 0x80, + COMGLB_RESERVED4 = 0x100, + COMGLB_RESERVED5 = 0x200, + COMGLB_RESERVED6 = 0x400, +}} +ENUM!{enum GLOBALOPT_UNMARSHALING_POLICY_VALUES { + COMGLB_UNMARSHALING_POLICY_NORMAL = 0, + COMGLB_UNMARSHALING_POLICY_STRONG = 1, + COMGLB_UNMARSHALING_POLICY_HYBRID = 2, +}} +RIDL!{#[uuid(0x0000015b, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IGlobalOptions(IGlobalOptionsVtbl): IUnknown(IUnknownVtbl) { + fn Set( + dwProperty: GLOBALOPT_PROPERTIES, + dwValue: ULONG_PTR, + ) -> HRESULT, + fn Query( + dwProperty: GLOBALOPT_PROPERTIES, + pdwValue: *mut ULONG_PTR, + ) -> HRESULT, +}} +pub type LPSURROGATE = *mut ISurrogate; +RIDL!{#[uuid(0x00000022, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISurrogate(ISurrogateVtbl): IUnknown(IUnknownVtbl) { + fn LoadDllServer( + Clsid: REFCLSID, + ) -> HRESULT, + fn FreeSurrogate() -> HRESULT, +}} +pub type LPGLOBALINTERFACETABLE = *mut IGlobalInterfaceTable; +RIDL!{#[uuid(0x00000146, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IGlobalInterfaceTable(IGlobalInterfaceTableVtbl): IUnknown(IUnknownVtbl) { + fn RegisterInterfaceInGlobal( + pUnk: *mut IUnknown, + riid: REFIID, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn RevokeInterfaceFromGlobal( + dwCookie: DWORD, + ) -> HRESULT, + fn GetInterfaceFromGlobal( + dwCookie: DWORD, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000030, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISynchronize(ISynchronizeVtbl): IUnknown(IUnknownVtbl) { + fn Wait( + dwFlags: DWORD, + dwMilliseconds: DWORD, + ) -> HRESULT, + fn Signal() -> HRESULT, + fn Reset() -> HRESULT, +}} +RIDL!{#[uuid(0x00000031, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISynchronizeHandle(ISynchronizeHandleVtbl): IUnknown(IUnknownVtbl) { + fn GetHandle( + ph: *mut HANDLE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000032, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISynchronizeEvent(ISynchronizeEventVtbl): ISynchronizeHandle(ISynchronizeHandleVtbl) { + fn SetEventHandle( + ph: *mut HANDLE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000033, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISynchronizeContainer(ISynchronizeContainerVtbl): IUnknown(IUnknownVtbl) { + fn AddSynchronize( + pSync: *mut ISynchronize, + ) -> HRESULT, + fn WaitMultiple( + dwFlags: DWORD, + dwTimeOut: DWORD, + ppSync: *mut *mut ISynchronize, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000025, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ISynchronizeMutex(ISynchronizeMutexVtbl): ISynchronize(ISynchronizeVtbl) { + fn ReleaseMutex() -> HRESULT, +}} +pub type LPCANCELMETHODCALLS = *mut ICancelMethodCalls; +RIDL!{#[uuid(0x00000029, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface ICancelMethodCalls(ICancelMethodCallsVtbl): IUnknown(IUnknownVtbl) { + fn Cancel( + ulSeconds: ULONG, + ) -> HRESULT, + fn TestCancel() -> HRESULT, +}} +ENUM!{enum DCOM_CALL_STATE { + DCOM_NONE = 0, + DCOM_CALL_COMPLETE = 0x1, + DCOM_CALL_CANCELED = 0x2, +}} +RIDL!{#[uuid(0x0000002a, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IAsyncManager(IAsyncManagerVtbl): IUnknown(IUnknownVtbl) { + fn CompleteCall( + Result: HRESULT, + ) -> HRESULT, + fn GetCallContext( + riid: REFIID, + pInterface: *mut *mut c_void, + ) -> HRESULT, + fn GetState( + pulStateFlags: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1c733a30, 0x2a1c, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d)] +interface ICallFactory(ICallFactoryVtbl): IUnknown(IUnknownVtbl) { + fn CreateCall( + riid: REFIID, + pCtrlUnk: *mut IUnknown, + riid2: REFIID, + ppv: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000149, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IRpcHelper(IRpcHelperVtbl): IUnknown(IUnknownVtbl) { + fn GetDCOMProtocolVersion( + pComVersion: *mut DWORD, + ) -> HRESULT, + fn GetIIDFromOBJREF( + pObjRef: *mut c_void, + piid: *mut *mut IID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xeb0cb9e8, 0x7996, 0x11d2, 0x87, 0x2e, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x59)] +interface IReleaseMarshalBuffers(IReleaseMarshalBuffersVtbl): IUnknown(IUnknownVtbl) { + fn ReleaseMarshalBuffer( + pMsg: *mut RPCOLEMESSAGE, + dwFlags: DWORD, + pChnl: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0000002b, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IWaitMultiple(IWaitMultipleVtbl): IUnknown(IUnknownVtbl) { + fn WaitMultiple( + timeout: DWORD, + pSync: *mut *mut ISynchronize, + ) -> HRESULT, + fn AddSynchronize( + pSync: *mut ISynchronize, + ) -> HRESULT, +}} +pub type LPADDRTRACKINGCONTROL = *mut IAddrTrackingControl; +RIDL!{#[uuid(0x00000147, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IAddrTrackingControl(IAddrTrackingControlVtbl): IUnknown(IUnknownVtbl) { + fn EnableCOMDynamicAddrTracking() -> HRESULT, + fn DisableCOMDynamicAddrTracking() -> HRESULT, +}} +pub type LPADDREXCLUSIONCONTROL = *mut IAddrExclusionControl; +RIDL!{#[uuid(0x00000148, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IAddrExclusionControl(IAddrExclusionControlVtbl): IUnknown(IUnknownVtbl) { + fn GetCurrentAddrExclusionList( + riid: REFIID, + ppEnumerator: *mut *mut c_void, + ) -> HRESULT, + fn UpdateAddrExclusionList( + pEnumerator: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3aca, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface IPipeByte(IPipeByteVtbl): IUnknown(IUnknownVtbl) { + fn Pull( + buf: *mut BYTE, + cRequest: ULONG, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Push( + buf: *mut BYTE, + cSent: ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3acb, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface AsyncIPipeByte(AsyncIPipeByteVtbl): IUnknown(IUnknownVtbl) { + fn Begin_Pull( + cRequest: ULONG, + ) -> HRESULT, + fn Finish_Pull( + buf: *mut BYTE, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Begin_Push( + buf: *mut BYTE, + cSent: ULONG, + ) -> HRESULT, + fn Finish_Push() -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3acc, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface IPipeLong(IPipeLongVtbl): IUnknown(IUnknownVtbl) { + fn Pull( + buf: *mut LONG, + cRequest: ULONG, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Push( + buf: *mut LONG, + cSent: ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3acd, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface AsyncIPipeLong(AsyncIPipeLongVtbl): IUnknown(IUnknownVtbl) { + fn Begin_Pull( + cRequest: ULONG, + ) -> HRESULT, + fn Finish_Pull( + buf: *mut LONG, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Begin_Push( + buf: *mut LONG, + cSent: ULONG, + ) -> HRESULT, + fn Finish_Push() -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3ace, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface IPipeDouble(IPipeDoubleVtbl): IUnknown(IUnknownVtbl) { + fn Pull( + buf: *mut DOUBLE, + cRequest: ULONG, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Push( + buf: *mut DOUBLE, + cSent: ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdb2f3acf, 0x2f86, 0x11d1, 0x8e, 0x04, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0x9a)] +interface AsyncIPipeDouble(AsyncIPipeDoubleVtbl): IUnknown(IUnknownVtbl) { + fn Begin_Pull( + cRequest: ULONG, + ) -> HRESULT, + fn Finish_Pull( + buf: *mut DOUBLE, + pcReturned: *mut ULONG, + ) -> HRESULT, + fn Begin_Push( + buf: *mut DOUBLE, + cSent: ULONG, + ) -> HRESULT, + fn Finish_Push() -> HRESULT, +}} +pub type CPFLAGS = DWORD; +STRUCT!{struct ContextProperty { + policyId: GUID, + flags: CPFLAGS, + pUnk: *mut IUnknown, +}} +pub type LPENUMCONTEXTPROPS = *mut IEnumContextProps; +RIDL!{#[uuid(0x000001c1, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IEnumContextProps(IEnumContextPropsVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + pContextProperties: *mut ContextProperty, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppEnumContextProps: *mut *mut IEnumContextProps, + ) -> HRESULT, + fn Count( + pcelt: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x000001c0, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IContext(IContextVtbl): IUnknown(IUnknownVtbl) { + fn SetProperty( + rpolicyId: REFGUID, + flags: CPFLAGS, + pUnk: *mut IUnknown, + ) -> HRESULT, + fn RemoveProperty( + rPolicyId: REFGUID, + ) -> HRESULT, + fn GetProperty( + policyId: REFGUID, + pFlags: *mut CPFLAGS, + ppUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn EnumContextProps( + ppEnumContextProps: *mut *mut IEnumContextProps, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x000001c6, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IObjContext(IObjContextVtbl): IContext(IContextVtbl) { + fn Reserved1() -> (), + fn Reserved2() -> (), + fn Reserved3() -> (), + fn Reserved4() -> (), + fn Reserved5() -> (), + fn Reserved6() -> (), + fn Reserved7() -> (), +}} +ENUM!{enum APTTYPEQUALIFIER { + APTTYPEQUALIFIER_NONE = 0, + APTTYPEQUALIFIER_IMPLICIT_MTA = 1, + APTTYPEQUALIFIER_NA_ON_MTA = 2, + APTTYPEQUALIFIER_NA_ON_STA = 3, + APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA = 4, + APTTYPEQUALIFIER_NA_ON_MAINSTA = 5, + APTTYPEQUALIFIER_APPLICATION_STA= 6, +}} +ENUM!{enum APTTYPE { + APTTYPE_CURRENT = -1i32 as u32, + APTTYPE_STA = 0, + APTTYPE_MTA = 1, + APTTYPE_NA = 2, + APTTYPE_MAINSTA = 3, +}} +ENUM!{enum THDTYPE { + THDTYPE_BLOCKMESSAGES = 0, + THDTYPE_PROCESSMESSAGES = 1, +}} +pub type APARTMENTID = DWORD; +RIDL!{#[uuid(0x000001ce, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IComThreadingInfo(IComThreadingInfoVtbl): IUnknown(IUnknownVtbl) { + fn GetCurrentApartmentType( + pAptType: *mut APTTYPE, + ) -> HRESULT, + fn GetCurrentThreadType( + pThreadType: *mut THDTYPE, + ) -> HRESULT, + fn GetCurrentLogicalThreadId( + pguidLogicalThreadId: *mut GUID, + ) -> HRESULT, + fn SetCurrentLogicalThreadId( + rguid: REFGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x72380d55, 0x8d2b, 0x43a3, 0x85, 0x13, 0x2b, 0x6e, 0xf3, 0x14, 0x34, 0xe9)] +interface IProcessInitControl(IProcessInitControlVtbl): IUnknown(IUnknownVtbl) { + fn ResetInitializerTimeout( + dwSecondsRemaining: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000040, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IFastRundown(IFastRundownVtbl): IUnknown(IUnknownVtbl) {}} +ENUM!{enum CO_MARSHALING_CONTEXT_ATTRIBUTES { + CO_MARSHALING_SOURCE_IS_APP_CONTAINER = 0, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_1 = 0x80000000, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_2 = 0x80000001, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_3 = 0x80000002, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_4 = 0x80000003, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_5 = 0x80000004, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_6 = 0x80000005, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_7 = 0x80000006, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_8 = 0x80000007, + CO_MARSHALING_CONTEXT_ATTRIBUTE_RESERVED_9 = 0x80000008, +}} +RIDL!{#[uuid(0xd8f2f5e6, 0x6102, 0x4863, 0x9f, 0x26, 0x38, 0x9a, 0x46, 0x76, 0xef, 0xde)] +interface IMarshalingStream(IMarshalingStreamVtbl): IStream(IStreamVtbl) { + fn GetMarshalingContextAttribute( + attribute: CO_MARSHALING_CONTEXT_ATTRIBUTES, + pAttributeValue: *mut ULONG_PTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc03f6a43, 0x65a4, 0x9818, 0x98, 0x7e, 0xe0, 0xb8, 0x10, 0xd2, 0xa6, 0xf2)] +interface IAgileReference(IAgileReferenceVtbl): IUnknown(IUnknownVtbl) { + fn Resolve( + riid: REFIID, + ppvObjectReference: *mut *mut c_void, + ) -> HRESULT, +}} diff --git a/winapi/src/um/ocidl.rs b/winapi/src/um/ocidl.rs new file mode 100644 index 000000000..07ec0d4ba --- /dev/null +++ b/winapi/src/um/ocidl.rs @@ -0,0 +1,68 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +// TODO:It is a minimal implementation. +use shared::guiddef::CLSID; +use shared::minwindef::{DWORD, ULONG}; +use shared::ntdef::HRESULT; +use shared::wtypes::{CLIPFORMAT, VARTYPE}; +use shared::wtypesbase::{LPCOLESTR, LPOLESTR}; +use um::oaidl::{IErrorLog, VARIANT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +ENUM!{enum READYSTATE { + READYSTATE_UNINITIALIZED = 0, + READYSTATE_LOADING = 1, + READYSTATE_LOADED = 2, + READYSTATE_INTERACTIVE = 3, + READYSTATE_COMPLETE = 4, +}} +ENUM!{enum PROPBAG2_TYPE { + PROPBAG2_TYPE_UNDEFINED = 0, + PROPBAG2_TYPE_DATA = 1, + PROPBAG2_TYPE_URL = 2, + PROPBAG2_TYPE_OBJECT = 3, + PROPBAG2_TYPE_STREAM = 4, + PROPBAG2_TYPE_STORAGE = 5, + PROPBAG2_TYPE_MONIKER = 6, +}} +STRUCT!{struct PROPBAG2 { + dwType: DWORD, + vt: VARTYPE, + cfType: CLIPFORMAT, + dwHint: DWORD, + pstrName: LPOLESTR, + clsid: CLSID, +}} +RIDL!{#[uuid(0x22f55882, 0x280b, 0x11d0, 0xa8, 0xa9, 0x00, 0xa0, 0xc9, 0x0c, 0x20, 0x04)] +interface IPropertyBag2(IPropertyBag2Vtbl): IUnknown(IUnknownVtbl) { + fn Read( + cProperties: ULONG, + pPropBag: *const PROPBAG2, + pErrLog: *const IErrorLog, + pvarValue: *mut VARIANT, + phrError: *mut HRESULT, + ) -> HRESULT, + fn Write( + cProperties: ULONG, + pPropBag: *const PROPBAG2, + pvarValue: *const VARIANT, + ) -> HRESULT, + fn CountProperties( + pcProperties: *mut ULONG, + ) -> HRESULT, + fn GetPropertyInfo( + iProperty: ULONG, + cProperties: ULONG, + pPropBag: *mut PROPBAG2, + pcProperties: *mut ULONG, + ) -> HRESULT, + fn LoadObject( + pstrName: LPCOLESTR, + dwHint: DWORD, + pUnkObject: *const IUnknown, + pErrLog: *const IErrorLog, + ) -> HRESULT, +}} +pub type LPPROPERTYBAG2 = *mut IPropertyBag2; diff --git a/winapi/src/um/ole2.rs b/winapi/src/um/ole2.rs new file mode 100644 index 000000000..66c168964 --- /dev/null +++ b/winapi/src/um/ole2.rs @@ -0,0 +1,21 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::LPVOID; +use shared::windef::HWND; +use um::oleidl::LPDROPTARGET; +use um::winnt::HRESULT; +extern "system" { + pub fn OleInitialize( + pvReserved: LPVOID, + ) -> HRESULT; + pub fn RegisterDragDrop( + hwnd: HWND, + pDropTarget: LPDROPTARGET, + ) -> HRESULT; + pub fn RevokeDragDrop( + hwnd: HWND, + ) -> HRESULT; +} diff --git a/winapi/src/um/oleauto.rs b/winapi/src/um/oleauto.rs new file mode 100644 index 000000000..7d4edba46 --- /dev/null +++ b/winapi/src/um/oleauto.rs @@ -0,0 +1,836 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of OleAuto.h +use ctypes::{c_double, c_float, c_int, c_uint, c_void}; +use shared::basetsd::{LONG64, ULONG64}; +use shared::minwindef::{BYTE, DWORD, FLOAT, UINT, ULONG, USHORT, WORD}; +use shared::wtypes::{BSTR, DATE, DECIMAL, LPBSTR, LPDECIMAL, VARTYPE}; +use shared::wtypesbase::{DOUBLE, LPCOLESTR, LPOLESTR, OLECHAR}; +use um::minwinbase::LPSYSTEMTIME; +use um::oaidl::{DISPID_UNKNOWN, ITypeLib, SAFEARRAY, VARIANT, VARIANTARG}; +use um::winnt::{CHAR, HRESULT, INT, LCID, LONG, LPCSTR, SHORT}; +extern "system" { + pub fn SysAllocString( + psz: *const OLECHAR, + ) -> BSTR; + pub fn SysReAllocString( + pbstr: *mut BSTR, + psz: *const OLECHAR, + ) -> INT; + pub fn SysAllocStringLen( + strIn: *const OLECHAR, + ui: UINT, + ) -> BSTR; + pub fn SysReAllocStringLen( + pbstr: *mut BSTR, + psz: *const OLECHAR, + len: c_uint, + ) -> INT; + pub fn SysFreeString( + bstrString: BSTR, + ); + pub fn SysStringLen( + pbstr: BSTR, + ) -> UINT; + pub fn SysStringByteLen( + bstr: BSTR, + ) -> UINT; + pub fn SysAllocStringByteLen( + psz: LPCSTR, + len: UINT, + ) -> BSTR; + pub fn DosDateTimeToVariantTime( + wDosDate: USHORT, + wDosTime: USHORT, + pvtime: *mut DOUBLE, + ) -> INT; + pub fn VariantTimeToDosDateTime( + vtime: DOUBLE, + pwDosDate: *mut USHORT, + pwDosTime: *mut USHORT, + ) -> INT; + pub fn SystemTimeToVariantTime( + lpSystemTime: LPSYSTEMTIME, + pvtime: *mut DOUBLE, + ) -> INT; + pub fn VariantTimeToSystemTime( + vtime: DOUBLE, + lpSystemTime: LPSYSTEMTIME, + ) -> INT; + pub fn SafeArrayAccessData( + psa: *mut SAFEARRAY, + ppvData: *mut *mut c_void, + ) -> HRESULT; + pub fn SafeArrayUnaccessData( + psa: *mut SAFEARRAY, + ) -> HRESULT; + pub fn SafeArrayCreateVector( + vt: VARTYPE, + lLbound: LONG, + cElements: ULONG, + ) -> *mut SAFEARRAY; + pub fn SafeArrayGetLBound( + psa: *mut SAFEARRAY, + nDim: UINT, + plLbound: *mut LONG + ) -> HRESULT; + pub fn SafeArrayGetUBound( + psa: *mut SAFEARRAY, + nDim: UINT, + plUbound: *mut LONG + ) -> HRESULT; + pub fn SafeArrayDestroy( + psa: *mut SAFEARRAY + ) -> HRESULT; + pub fn VariantInit( + pvarg: *mut VARIANTARG, + ); + pub fn VariantClear( + pvarg: *mut VARIANTARG, + ) -> HRESULT; + pub fn VariantCopy( + pvargDest: *mut VARIANTARG, + pvargSrc: *const VARIANTARG, + ) -> HRESULT; + pub fn VariantCopyInd( + pvarDest: *mut VARIANT, + pvargSrc: *const VARIANTARG, + ) -> HRESULT; + pub fn VariantChangeType( + pvargDest: *mut VARIANTARG, + pvarSrc: *const VARIANTARG, + wFlags: USHORT, + vt: VARTYPE, + ) -> HRESULT; + pub fn VariantChangeTypeEx( + pvargDest: *mut VARIANTARG, + pvarSrc: *const VARIANTARG, + lcid: LCID, + wFlags: USHORT, + vt: VARTYPE, + ) -> HRESULT; + pub fn VarUI1FromI2( + sIn: SHORT, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromI4( + lIn: LONG, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromI8( + i64In: LONG64, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromR4( + fltIn: FLOAT, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromR8( + dblIn: DOUBLE, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromDate( + dateIn: DATE, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromI1( + cIn: CHAR, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromUI2( + uiIn: USHORT, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromUI4( + ulIn: ULONG, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromUI8( + ui64In: ULONG64, + pbOut: *mut BYTE, + ); + pub fn VarUI1FromDec( + pdecIn: *const DECIMAL, + pbOut: *mut BYTE, + ); + pub fn VarI2FromUI1( + bIn: BYTE, + psOut: *mut SHORT, + ); + pub fn VarI2FromI4( + lIn: LONG, + psOut: *mut SHORT, + ); + pub fn VarI2FromI8( + i64In: LONG64, + psOut: *mut SHORT, + ); + pub fn VarI2FromR4( + fltIn: FLOAT, + psOut: *mut SHORT, + ); + pub fn VarI2FromR8( + dblIn: DOUBLE, + psOut: *mut SHORT, + ); + pub fn VarI2FromDate( + dateIn: DATE, + psOut: *mut SHORT, + ); + pub fn VarI2FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + psOut: *mut SHORT, + ); + pub fn VarI2FromI1( + cIn: CHAR, + psOut: *mut SHORT, + ); + pub fn VarI2FromUI2( + uiIn: USHORT, + psOut: *mut SHORT, + ); + pub fn VarI2FromUI4( + ulIn: ULONG, + psOut: *mut SHORT, + ); + pub fn VarI2FromUI8( + ui64In: ULONG64, + psOut: *mut SHORT, + ); + pub fn VarI2FromDec( + pdecIn: *const DECIMAL, + psOut: *mut SHORT, + ); + pub fn VarI4FromUI1( + bIn: BYTE, + plOut: *mut LONG, + ); + pub fn VarI4FromI2( + sIn: SHORT, + plOut: *mut LONG, + ); + pub fn VarI4FromI8( + i64In: LONG64, + plOut: *mut LONG, + ); + pub fn VarI4FromR4( + fltIn: FLOAT, + plOut: *mut LONG, + ); + pub fn VarI4FromR8( + dblIn: DOUBLE, + plOut: *mut LONG, + ); + pub fn VarI4FromDate( + dateIn: DATE, + plOut: *mut LONG, + ); + pub fn VarI4FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + plOut: *mut LONG, + ); + pub fn VarI4FromI1( + cIn: CHAR, + plOut: *mut LONG, + ); + pub fn VarI4FromUI2( + uiIn: USHORT, + plOut: *mut LONG, + ); + pub fn VarI4FromUI4( + ulIn: ULONG, + plOut: *mut LONG, + ); + pub fn VarI4FromUI8( + ui64In: ULONG64, + plOut: *mut LONG, + ); + pub fn VarI4FromDec( + pdecIn: *const DECIMAL, + plOut: *mut LONG, + ); + pub fn VarI8FromUI1( + bIn: BYTE, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromI2( + sIn: SHORT, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromR4( + fltIn: FLOAT, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromR8( + dblIn: DOUBLE, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromDate( + dateIn: DATE, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromI1( + cIn: CHAR, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromUI2( + uiIn: USHORT, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromUI4( + ulIn: ULONG, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromUI8( + ui64In: ULONG64, + pi64Out: *mut LONG64, + ); + pub fn VarI8FromDec( + pdecIn: *const DECIMAL, + pi64Out: *mut LONG64, + ); + pub fn VarR4FromUI1( + bIn: BYTE, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromI2( + sIn: SHORT, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromI4( + lIn: LONG, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromI8( + i64In: LONG64, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromR8( + dblIn: DOUBLE, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromDate( + dateIn: DATE, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromI1( + cIn: CHAR, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromUI2( + uiIn: USHORT, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromUI4( + ulIn: ULONG, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromUI8( + ui64In: ULONG64, + pfltOut: *mut FLOAT, + ); + pub fn VarR4FromDec( + pdecIn: *const DECIMAL, + pfltOut: *mut FLOAT, + ); + pub fn VarR8FromUI1( + bIn: BYTE, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromI2( + sIn: SHORT, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromI4( + lIn: LONG, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromI8( + i64In: LONG64, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromR4( + fltIn: FLOAT, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromDate( + dateIn: DATE, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromI1( + cIn: CHAR, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromUI2( + uiIn: USHORT, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromUI4( + ulIn: ULONG, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromUI8( + ui64In: ULONG64, + pdblOut: *mut DOUBLE, + ); + pub fn VarR8FromDec( + pdecIn: *const DECIMAL, + pdblOut: *mut DOUBLE, + ); + pub fn VarDateFromUI1( + bIn: BYTE, + pdateOut: *mut DATE, + ); + pub fn VarDateFromI2( + sIn: SHORT, + pdateOut: *mut DATE, + ); + pub fn VarDateFromI4( + lIn: LONG, + pdateOut: *mut DATE, + ); + pub fn VarDateFromI8( + i64In: LONG64, + pdateOut: *mut DATE, + ); + pub fn VarDateFromR4( + fltIn: FLOAT, + pdateOut: *mut DATE, + ); + pub fn VarDateFromR8( + dblIn: DOUBLE, + pdateOut: *mut DATE, + ); + pub fn VarDateFromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pdateOut: *mut DATE, + ); + pub fn VarDateFromI1( + cIn: CHAR, + pdateOut: *mut DATE, + ); + pub fn VarDateFromUI2( + uiIn: USHORT, + pdateOut: *mut DATE, + ); + pub fn VarDateFromUI4( + ulIn: ULONG, + pdateOut: *mut DATE, + ); + pub fn VarDateFromUI8( + ui64In: ULONG64, + pdateOut: *mut DATE, + ); + pub fn VarDateFromDec( + pdecIn: *const DECIMAL, + pdateOut: *mut DATE, + ); + pub fn VarBstrFromUI1( + bVal: BYTE, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromI2( + iVal: SHORT, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromI4( + lIn: LONG, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromI8( + i64In: LONG64, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromR4( + fltIn: FLOAT, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromR8( + dblIn: DOUBLE, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromDate( + dateIn: DATE, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromI1( + cIn: CHAR, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromUI2( + uiIn: USHORT, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromUI4( + ulIn: ULONG, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromUI8( + ui64In: ULONG64, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarBstrFromDec( + pdecIn: *const DECIMAL, + lcid: LCID, + dwFlags: ULONG, + pbstrOut: *mut BSTR, + ); + pub fn VarUI2FromUI1( + bIn: BYTE, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromI2( + uiIn: SHORT, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromI4( + lIn: LONG, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromI8( + i64In: LONG64, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromR4( + fltIn: FLOAT, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromR8( + dblIn: DOUBLE, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromDate( + dateIn: DATE, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromI1( + cIn: CHAR, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromUI4( + ulIn: ULONG, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromUI8( + i64In: ULONG64, + puiOut: *mut USHORT, + ); + pub fn VarUI2FromDec( + pdecIn: *const DECIMAL, + puiOut: *mut USHORT, + ); + pub fn VarUI4FromUI1( + bIn: BYTE, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromI2( + uiIn: SHORT, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromI4( + lIn: LONG, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromI8( + i64In: LONG64, + plOut: *mut ULONG, + ); + pub fn VarUI4FromR4( + fltIn: FLOAT, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromR8( + dblIn: DOUBLE, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromDate( + dateIn: DATE, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromI1( + cIn: CHAR, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromUI2( + uiIn: USHORT, + pulOut: *mut ULONG, + ); + pub fn VarUI4FromUI8( + ui64In: ULONG64, + plOut: *mut ULONG, + ); + pub fn VarUI4FromDec( + pdecIn: *const DECIMAL, + pulOut: *mut ULONG, + ); + pub fn VarUI8FromUI1( + bIn: BYTE, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromI2( + sIn: SHORT, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromI4( + lIn: LONG, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromI8( + ui64In: LONG64, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromR4( + fltIn: FLOAT, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromR8( + dblIn: DOUBLE, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromDate( + dateIn: DATE, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromI1( + cIn: CHAR, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromUI2( + uiIn: USHORT, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromUI4( + ulIn: ULONG, + pi64Out: *mut ULONG64, + ); + pub fn VarUI8FromDec( + pdecIn: *const DECIMAL, + pi64Out: *mut ULONG64, + ); + pub fn VarDecFromUI1( + bIn: BYTE, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromI2( + uiIn: SHORT, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromI4( + lIn: LONG, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromI8( + i64In: LONG64, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromR4( + fltIn: FLOAT, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromR8( + dblIn: DOUBLE, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromDate( + dateIn: DATE, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromStr( + strIn: LPCOLESTR, + lcid: LCID, + dwFlags: ULONG, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromI1( + cIn: CHAR, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromUI2( + uiIn: USHORT, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromUI4( + ulIn: ULONG, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecFromUI8( + ui64In: ULONG64, + pdecOut: *mut DECIMAL, + ); + pub fn VarDecAdd( + pdecLeft: LPDECIMAL, + pdecRight: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecDiv( + pdecLeft: LPDECIMAL, + pdecRight: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecMul( + pdecLeft: LPDECIMAL, + pdecRight: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecSub( + pdecLeft: LPDECIMAL, + pdecRight: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecAbs( + pdecIn: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecFix( + pdecIn: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecInt( + pdecIn: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecNeg( + pdecIn: LPDECIMAL, + pdecResult: LPDECIMAL, + ); + pub fn VarDecRound( + pdecIn: LPDECIMAL, + cDecimals: c_int, + pdecResult: LPDECIMAL, + ); + pub fn VarDecCmp( + pdecLeft: LPDECIMAL, + pdecRight: LPDECIMAL, + ); + pub fn VarDecCmpR8( + pdecLeft: LPDECIMAL, + dblRight: c_double, + ); + pub fn VarBstrCat( + bstrLeft: BSTR, + bstrRight: BSTR, + pbstrResult: LPBSTR, + ); + pub fn VarBstrCmp( + bstrLeft: BSTR, + bstrRight: BSTR, + lcid: LCID, + dwFlags: ULONG, + ); + pub fn VarR8Pow( + dblLeft: c_double, + dblRight: c_double, + pdblResult: *mut c_double, + ); + pub fn VarR4CmpR8( + fltLeft: c_float, + dblRight: c_double, + ); + pub fn VarR8Round( + dblIn: c_double, + cDecimals: c_int, + pdblResult: *mut c_double, + ); + pub fn GetAltMonthNames( + lcid: LCID, + prgp: *mut LPOLESTR, + ); +} +pub type DISPID = LONG; +pub type MEMBERID = DISPID; +pub const MEMBERID_NIL: MEMBERID = DISPID_UNKNOWN; +pub const DISPATCH_METHOD: WORD = 0x1; +pub const DISPATCH_PROPERTYGET: WORD = 0x2; +pub const DISPATCH_PROPERTYPUT: WORD = 0x4; +pub const DISPATCH_PROPERTYPUTREF: WORD = 0x8; +ENUM!{enum REGKIND { + REGKIND_DEFAULT = 0, + REGKIND_REGISTER, + REGKIND_NONE, +}} +extern "system" { + pub fn LoadTypeLibEx( + szFile: LPCOLESTR, + regkind: REGKIND, + pptlib: *mut *mut ITypeLib, + ) -> HRESULT; + pub fn RevokeActiveObject( + dwRegister: DWORD, + pvReserved: *mut c_void, + ); + pub fn OaBuildVersion() -> ULONG; + pub fn OaEnablePerUserTLibRegistration(); +} diff --git a/winapi/src/um/olectl.rs b/winapi/src/um/olectl.rs new file mode 100644 index 000000000..4a9ccdf9d --- /dev/null +++ b/winapi/src/um/olectl.rs @@ -0,0 +1,14 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! OLE Control interfaces +use shared::winerror::{FACILITY_ITF, SEVERITY_ERROR, SEVERITY_SUCCESS}; +use um::winnt::HRESULT; +pub const SELFREG_E_FIRST: HRESULT = MAKE_SCODE!(SEVERITY_ERROR, FACILITY_ITF, 0x0200); +pub const SELFREG_E_LAST: HRESULT = MAKE_SCODE!(SEVERITY_ERROR, FACILITY_ITF, 0x020F); +pub const SELFREG_S_FIRST: HRESULT = MAKE_SCODE!(SEVERITY_SUCCESS, FACILITY_ITF, 0x0200); +pub const SELFREG_S_LAST: HRESULT = MAKE_SCODE!(SEVERITY_SUCCESS, FACILITY_ITF, 0x020F); +pub const SELFREG_E_TYPELIB: HRESULT = SELFREG_E_FIRST + 0; +pub const SELFREG_E_CLASS: HRESULT = SELFREG_E_FIRST + 1; diff --git a/winapi/src/um/oleidl.rs b/winapi/src/um/oleidl.rs new file mode 100644 index 000000000..39b8c309e --- /dev/null +++ b/winapi/src/um/oleidl.rs @@ -0,0 +1,43 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::DWORD; +use shared::ntdef::HRESULT; +use shared::windef::POINTL; +use um::objidl::IDataObject; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +pub const MK_ALT: DWORD = 20; +pub const DROPEFFECT_NONE: DWORD = 0; +pub const DROPEFFECT_COPY: DWORD = 1; +pub const DROPEFFECT_MOVE: DWORD = 2; +pub const DROPEFFECT_LINK: DWORD = 4; +pub const DROPEFFECT_SCROLL: DWORD = 0x80000000; +pub const DD_DEFSCROLLINSET: DWORD = 11; +pub const DD_DEFSCROLLDELAY: DWORD = 50; +pub const DD_DEFSCROLLINTERVAL: DWORD = 50; +pub const DD_DEFDRAGDELAY: DWORD = 200; +pub const DD_DEFDRAGMINDIST: DWORD = 2; +pub type LPDROPTARGET = *mut IDropTarget; +RIDL!{#[uuid(0x00000122, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IDropTarget(IDropTargetVtbl): IUnknown(IUnknownVtbl) { + fn DragEnter( + pDataObj: *const IDataObject, + grfKeyState: DWORD, + pt: *const POINTL, + pdwEffect: *mut DWORD, + ) -> HRESULT, + fn DragOver( + grfKeyState: DWORD, + pt: *const POINTL, + pdwEffect: *mut DWORD, + ) -> HRESULT, + fn DragLeave() -> HRESULT, + fn Drop( + pDataObj: *const IDataObject, + grfKeyState: DWORD, + pt: *const POINTL, + pdwEffect: *mut DWORD, + ) -> HRESULT, +}} diff --git a/winapi/src/um/opmapi.rs b/winapi/src/um/opmapi.rs new file mode 100644 index 000000000..a8e5de87a --- /dev/null +++ b/winapi/src/um/opmapi.rs @@ -0,0 +1,362 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::UINT64; +use shared::d3d9::IDirect3DDevice9; +use shared::d3d9types::D3DFORMAT; +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, DWORD, ULONG}; +use shared::windef::HMONITOR; +use um::dxva2api::DXVA2_SampleFormat; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LUID}; +DEFINE_GUID!{OPM_GET_CURRENT_HDCP_SRM_VERSION, + 0x99c5ceff, 0x5f1d, 0x4879, 0x81, 0xc1, 0xc5, 0x24, 0x43, 0xc9, 0x48, 0x2b} +DEFINE_GUID!{OPM_GET_CONNECTED_HDCP_DEVICE_INFORMATION, + 0x0db59d74, 0xa992, 0x492e, 0xa0, 0xbd, 0xc2, 0x3f, 0xda, 0x56, 0x4e, 0x00} +DEFINE_GUID!{OPM_GET_ACP_AND_CGMSA_SIGNALING, + 0x6629a591, 0x3b79, 0x4cf3, 0x92, 0x4a, 0x11, 0xe8, 0xe7, 0x81, 0x16, 0x71} +DEFINE_GUID!{OPM_GET_CONNECTOR_TYPE, + 0x81d0bfd5, 0x6afe, 0x48c2, 0x99, 0xc0, 0x95, 0xa0, 0x8f, 0x97, 0xc5, 0xda} +DEFINE_GUID!{OPM_GET_SUPPORTED_PROTECTION_TYPES, + 0x38f2a801, 0x9a6c, 0x48bb, 0x91, 0x07, 0xb6, 0x69, 0x6e, 0x6f, 0x17, 0x97} +DEFINE_GUID!{OPM_GET_VIRTUAL_PROTECTION_LEVEL, + 0xb2075857, 0x3eda, 0x4d5d, 0x88, 0xdb, 0x74, 0x8f, 0x8c, 0x1a, 0x05, 0x49} +DEFINE_GUID!{OPM_GET_ACTUAL_PROTECTION_LEVEL, + 0x1957210a, 0x7766, 0x452a, 0xb9, 0x9a, 0xd2, 0x7a, 0xed, 0x54, 0xf0, 0x3a} +DEFINE_GUID!{OPM_GET_ACTUAL_OUTPUT_FORMAT, + 0xd7bf1ba3, 0xad13, 0x4f8e, 0xaf, 0x98, 0x0d, 0xcb, 0x3c, 0xa2, 0x04, 0xcc} +DEFINE_GUID!{OPM_GET_ADAPTER_BUS_TYPE, + 0xc6f4d673, 0x6174, 0x4184, 0x8e, 0x35, 0xf6, 0xdb, 0x52, 0x0, 0xbc, 0xba} +DEFINE_GUID!{OPM_GET_OUTPUT_ID, + 0x72cb6df3, 0x244f, 0x40ce, 0xb0, 0x9e, 0x20, 0x50, 0x6a, 0xf6, 0x30, 0x2f} +DEFINE_GUID!{OPM_GET_DVI_CHARACTERISTICS, + 0xa470b3bb, 0x5dd7, 0x4172, 0x83, 0x9c, 0x3d, 0x37, 0x76, 0xe0, 0xeb, 0xf5} +DEFINE_GUID!{OPM_GET_CODEC_INFO, + 0x4f374491, 0x8f5f, 0x4445, 0x9d, 0xba, 0x95, 0x58, 0x8f, 0x6b, 0x58, 0xb4} +DEFINE_GUID!{OPM_GET_OUTPUT_HARDWARE_PROTECTION_SUPPORT, + 0x3b129589, 0x2af8, 0x4ef0, 0x96, 0xa2, 0x70, 0x4a, 0x84, 0x5a, 0x21, 0x8e} +DEFINE_GUID!{OPM_SET_PROTECTION_LEVEL, + 0x9bb9327c, 0x4eb5, 0x4727, 0x9f, 0x00, 0xb4, 0x2b, 0x09, 0x19, 0xc0, 0xda} +DEFINE_GUID!{OPM_SET_ACP_AND_CGMSA_SIGNALING, + 0x09a631a5, 0xd684, 0x4c60, 0x8e, 0x4d, 0xd3, 0xbb, 0x0f, 0x0b, 0xe3, 0xee} +DEFINE_GUID!{OPM_SET_HDCP_SRM, + 0x8b5ef5d1, 0xc30d, 0x44ff, 0x84, 0xa5, 0xea, 0x71, 0xdc, 0xe7, 0x8f, 0x13} +DEFINE_GUID!{OPM_SET_PROTECTION_LEVEL_ACCORDING_TO_CSS_DVD, + 0x39ce333e, 0x4cc0, 0x44ae, 0xbf, 0xcc, 0xda, 0x50, 0xb5, 0xf8, 0x2e, 0x72} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0001 { + OPM_OMAC_SIZE = 16, + OPM_128_BIT_RANDOM_NUMBER_SIZE = 16, + OPM_ENCRYPTED_INITIALIZATION_PARAMETERS_SIZE = 256, + OPM_CONFIGURE_SETTING_DATA_SIZE = 4056, + OPM_GET_INFORMATION_PARAMETERS_SIZE = 4056, + OPM_REQUESTED_INFORMATION_SIZE = 4076, + OPM_HDCP_KEY_SELECTION_VECTOR_SIZE = 5, + OPM_PROTECTION_TYPE_SIZE = 4, + OPM_BUS_TYPE_MASK = 0xffff, + OPM_BUS_IMPLEMENTATION_MODIFIER_MASK = 0x7fff, +}} +ENUM!{enum OPM_VIDEO_OUTPUT_SEMANTICS { + OPM_VOS_COPP_SEMANTICS = 0, + OPM_VOS_OPM_SEMANTICS = 1, + OPM_VOS_OPM_INDIRECT_DISPLAY = 2, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0002 { + OPM_HDCP_FLAG_NONE = 0, + OPM_HDCP_FLAG_REPEATER = 0x1, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0003 { + OPM_STATUS_NORMAL = 0, + OPM_STATUS_LINK_LOST = 0x1, + OPM_STATUS_RENEGOTIATION_REQUIRED = 0x2, + OPM_STATUS_TAMPERING_DETECTED = 0x4, + OPM_STATUS_REVOKED_HDCP_DEVICE_ATTACHED = 0x8, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0004 { + OPM_CONNECTOR_TYPE_OTHER = -1i32 as u32, + OPM_CONNECTOR_TYPE_VGA = 0, + OPM_CONNECTOR_TYPE_SVIDEO = 1, + OPM_CONNECTOR_TYPE_COMPOSITE_VIDEO = 2, + OPM_CONNECTOR_TYPE_COMPONENT_VIDEO = 3, + OPM_CONNECTOR_TYPE_DVI = 4, + OPM_CONNECTOR_TYPE_HDMI = 5, + OPM_CONNECTOR_TYPE_LVDS = 6, + OPM_CONNECTOR_TYPE_D_JPN = 8, + OPM_CONNECTOR_TYPE_SDI = 9, + OPM_CONNECTOR_TYPE_DISPLAYPORT_EXTERNAL = 10, + OPM_CONNECTOR_TYPE_DISPLAYPORT_EMBEDDED = 11, + OPM_CONNECTOR_TYPE_UDI_EXTERNAL = 12, + OPM_CONNECTOR_TYPE_UDI_EMBEDDED = 13, + OPM_CONNECTOR_TYPE_RESERVED = 14, + OPM_CONNECTOR_TYPE_MIRACAST = 15, + OPM_CONNECTOR_TYPE_TRANSPORT_AGNOSTIC_DIGITAL_MODE_A = 16, + OPM_CONNECTOR_TYPE_TRANSPORT_AGNOSTIC_DIGITAL_MODE_B = 17, + OPM_COPP_COMPATIBLE_CONNECTOR_TYPE_INTERNAL = 0x80000000, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0005 { + OPM_DVI_CHARACTERISTIC_1_0 = 1, + OPM_DVI_CHARACTERISTIC_1_1_OR_ABOVE = 2, +}} +ENUM!{enum OPM_OUTPUT_HARDWARE_PROTECTION { + OPM_OUTPUT_HARDWARE_PROTECTION_NOT_SUPPORTED = 0, + OPM_OUTPUT_HARDWARE_PROTECTION_SUPPORTED = 0x1, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0006 { + OPM_BUS_TYPE_OTHER = 0, + OPM_BUS_TYPE_PCI = 0x1, + OPM_BUS_TYPE_PCIX = 0x2, + OPM_BUS_TYPE_PCIEXPRESS = 0x3, + OPM_BUS_TYPE_AGP = 0x4, + OPM_BUS_IMPLEMENTATION_MODIFIER_INSIDE_OF_CHIPSET = 0x10000, + OPM_BUS_IMPLEMENTATION_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_CHIP = 0x20000, + OPM_BUS_IMPLEMENTATION_MODIFIER_TRACKS_ON_MOTHER_BOARD_TO_SOCKET = 0x30000, + OPM_BUS_IMPLEMENTATION_MODIFIER_DAUGHTER_BOARD_CONNECTOR = 0x40000, + OPM_BUS_IMPLEMENTATION_MODIFIER_DAUGHTER_BOARD_CONNECTOR_INSIDE_OF_NUAE = 0x50000, + OPM_BUS_IMPLEMENTATION_MODIFIER_NON_STANDARD = 0x80000000, + OPM_COPP_COMPATIBLE_BUS_TYPE_INTEGRATED = 0x80000000, +}} +ENUM!{enum OPM_DPCP_PROTECTION_LEVEL { + OPM_DPCP_OFF = 0, + OPM_DPCP_ON = 1, + OPM_DPCP_FORCE_ULONG = 0x7fffffff, +}} +ENUM!{enum OPM_HDCP_PROTECTION_LEVEL { + OPM_HDCP_OFF = 0, + OPM_HDCP_ON = 1, + OPM_HDCP_FORCE_ULONG = 0x7fffffff, +}} +ENUM!{enum OPM_TYPE_ENFORCEMENT_HDCP_PROTECTION_LEVEL { + OPM_TYPE_ENFORCEMENT_HDCP_OFF = OPM_HDCP_OFF, + OPM_TYPE_ENFORCEMENT_HDCP_ON_WITH_NO_TYPE_RESTRICTION = OPM_HDCP_ON, + OPM_TYPE_ENFORCEMENT_HDCP_ON_WITH_TYPE1_RESTRICTION = OPM_HDCP_ON + 1, + OPM_TYPE_ENFORCEMENT_HDCP_FORCE_ULONG = 0x7fffffff, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0007 { + OPM_CGMSA_OFF = 0, + OPM_CGMSA_COPY_FREELY = 0x1, + OPM_CGMSA_COPY_NO_MORE = 0x2, + OPM_CGMSA_COPY_ONE_GENERATION = 0x3, + OPM_CGMSA_COPY_NEVER = 0x4, + OPM_CGMSA_REDISTRIBUTION_CONTROL_REQUIRED = 0x8, +}} +ENUM!{enum OPM_ACP_PROTECTION_LEVEL { + OPM_ACP_OFF = 0, + OPM_ACP_LEVEL_ONE = 1, + OPM_ACP_LEVEL_TWO = 2, + OPM_ACP_LEVEL_THREE = 3, + OPM_ACP_FORCE_ULONG = 0x7fffffff, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0008 { + OPM_PROTECTION_TYPE_OTHER = 0x80000000, + OPM_PROTECTION_TYPE_NONE = 0, + OPM_PROTECTION_TYPE_COPP_COMPATIBLE_HDCP = 0x1, + OPM_PROTECTION_TYPE_ACP = 0x2, + OPM_PROTECTION_TYPE_CGMSA = 0x4, + OPM_PROTECTION_TYPE_HDCP = 0x8, + OPM_PROTECTION_TYPE_DPCP = 0x10, + OPM_PROTECTION_TYPE_TYPE_ENFORCEMENT_HDCP = 0x20, +}} +ENUM!{enum __MIDL___MIDL_itf_opmapi_0000_0000_0009 { + OPM_PROTECTION_STANDARD_OTHER = 0x80000000, + OPM_PROTECTION_STANDARD_NONE = 0, + OPM_PROTECTION_STANDARD_IEC61880_525I = 0x1, + OPM_PROTECTION_STANDARD_IEC61880_2_525I = 0x2, + OPM_PROTECTION_STANDARD_IEC62375_625P = 0x4, + OPM_PROTECTION_STANDARD_EIA608B_525 = 0x8, + OPM_PROTECTION_STANDARD_EN300294_625I = 0x10, + OPM_PROTECTION_STANDARD_CEA805A_TYPEA_525P = 0x20, + OPM_PROTECTION_STANDARD_CEA805A_TYPEA_750P = 0x40, + OPM_PROTECTION_STANDARD_CEA805A_TYPEA_1125I = 0x80, + OPM_PROTECTION_STANDARD_CEA805A_TYPEB_525P = 0x100, + OPM_PROTECTION_STANDARD_CEA805A_TYPEB_750P = 0x200, + OPM_PROTECTION_STANDARD_CEA805A_TYPEB_1125I = 0x400, + OPM_PROTECTION_STANDARD_ARIBTRB15_525I = 0x800, + OPM_PROTECTION_STANDARD_ARIBTRB15_525P = 0x1000, + OPM_PROTECTION_STANDARD_ARIBTRB15_750P = 0x2000, + OPM_PROTECTION_STANDARD_ARIBTRB15_1125I = 0x4000, +}} +ENUM!{enum OPM_IMAGE_ASPECT_RATIO_EN300294 { + OPM_ASPECT_RATIO_EN300294_FULL_FORMAT_4_BY_3 = 0, + OPM_ASPECT_RATIO_EN300294_BOX_14_BY_9_CENTER = 1, + OPM_ASPECT_RATIO_EN300294_BOX_14_BY_9_TOP = 2, + OPM_ASPECT_RATIO_EN300294_BOX_16_BY_9_CENTER = 3, + OPM_ASPECT_RATIO_EN300294_BOX_16_BY_9_TOP = 4, + OPM_ASPECT_RATIO_EN300294_BOX_GT_16_BY_9_CENTER = 5, + OPM_ASPECT_RATIO_EN300294_FULL_FORMAT_4_BY_3_PROTECTED_CENTER = 6, + OPM_ASPECT_RATIO_EN300294_FULL_FORMAT_16_BY_9_ANAMORPHIC = 7, + OPM_ASPECT_RATIO_FORCE_ULONG = 0x7fffffff, +}} +STRUCT!{#[repr(packed)] struct OPM_RANDOM_NUMBER { + abRandomNumber: [BYTE; 16], +}} +STRUCT!{#[repr(packed)] struct OPM_OMAC { + abOMAC: [BYTE; 16], +}} +STRUCT!{#[repr(packed)] struct OPM_ENCRYPTED_INITIALIZATION_PARAMETERS { + abEncryptedInitializationParameters: [BYTE; 256], +}} +STRUCT!{#[repr(packed)] struct OPM_GET_INFO_PARAMETERS { + omac: OPM_OMAC, + rnRandomNumber: OPM_RANDOM_NUMBER, + guidInformation: GUID, + ulSequenceNumber: ULONG, + cbParametersSize: ULONG, + abParameters: [BYTE; 4056], +}} +STRUCT!{#[repr(packed)] struct OPM_COPP_COMPATIBLE_GET_INFO_PARAMETERS { + rnRandomNumber: OPM_RANDOM_NUMBER, + guidInformation: GUID, + ulSequenceNumber: ULONG, + cbParametersSize: ULONG, + abParameters: [BYTE; 4056], +}} +STRUCT!{#[repr(packed)] struct OPM_HDCP_KEY_SELECTION_VECTOR { + abKeySelectionVector: [BYTE; 5], +}} +STRUCT!{#[repr(packed)] struct OPM_CONNECTED_HDCP_DEVICE_INFORMATION { + rnRandomNumber: OPM_RANDOM_NUMBER, + ulStatusFlags: ULONG, + ulHDCPFlags: ULONG, + ksvB: OPM_HDCP_KEY_SELECTION_VECTOR, + Reserved: [BYTE; 11], + Reserved2: [BYTE; 16], + Reserved3: [BYTE; 16], +}} +STRUCT!{#[repr(packed)] struct OPM_REQUESTED_INFORMATION { + omac: OPM_OMAC, + cbRequestedInformationSize: ULONG, + abRequestedInformation: [BYTE; 4076], +}} +STRUCT!{#[repr(packed)] struct OPM_STANDARD_INFORMATION { + rnRandomNumber: OPM_RANDOM_NUMBER, + ulStatusFlags: ULONG, + ulInformation: ULONG, + ulReserved: ULONG, + ulReserved2: ULONG, +}} +STRUCT!{#[repr(packed)] struct OPM_ACTUAL_OUTPUT_FORMAT { + rnRandomNumber: OPM_RANDOM_NUMBER, + ulStatusFlags: ULONG, + ulDisplayWidth: ULONG, + ulDisplayHeight: ULONG, + dsfSampleInterleaveFormat: DXVA2_SampleFormat, + d3dFormat: D3DFORMAT, + ulFrequencyNumerator: ULONG, + ulFrequencyDenominator: ULONG, +}} +STRUCT!{#[repr(packed)] struct OPM_ACP_AND_CGMSA_SIGNALING { + rnRandomNumber: OPM_RANDOM_NUMBER, + ulStatusFlags: ULONG, + ulAvailableTVProtectionStandards: ULONG, + ulActiveTVProtectionStandard: ULONG, + ulReserved: ULONG, + ulAspectRatioValidMask1: ULONG, + ulAspectRatioData1: ULONG, + ulAspectRatioValidMask2: ULONG, + ulAspectRatioData2: ULONG, + ulAspectRatioValidMask3: ULONG, + ulAspectRatioData3: ULONG, + ulReserved2: [ULONG; 4], + ulReserved3: [ULONG; 4], +}} +STRUCT!{#[repr(packed)] struct OPM_OUTPUT_ID_DATA { + rnRandomNumber: OPM_RANDOM_NUMBER, + ulStatusFlags: ULONG, + OutputId: UINT64, +}} +STRUCT!{#[repr(packed)] struct OPM_CONFIGURE_PARAMETERS { + omac: OPM_OMAC, + guidSetting: GUID, + ulSequenceNumber: ULONG, + cbParametersSize: ULONG, + abParameters: [BYTE; 4056], +}} +STRUCT!{#[repr(packed)] struct OPM_SET_PROTECTION_LEVEL_PARAMETERS { + ulProtectionType: ULONG, + ulProtectionLevel: ULONG, + Reserved: ULONG, + Reserved2: ULONG, +}} +STRUCT!{#[repr(packed)] struct OPM_SET_ACP_AND_CGMSA_SIGNALING_PARAMETERS { + ulNewTVProtectionStandard: ULONG, + ulAspectRatioChangeMask1: ULONG, + ulAspectRatioData1: ULONG, + ulAspectRatioChangeMask2: ULONG, + ulAspectRatioData2: ULONG, + ulAspectRatioChangeMask3: ULONG, + ulAspectRatioData3: ULONG, + ulReserved: [ULONG; 4], + ulReserved2: [ULONG; 4], + ulReserved3: ULONG, +}} +STRUCT!{#[repr(packed)] struct OPM_SET_HDCP_SRM_PARAMETERS { + ulSRMVersion: ULONG, +}} +STRUCT!{#[repr(packed)] struct OPM_GET_CODEC_INFO_PARAMETERS { + cbVerifier: DWORD, + Verifier: [BYTE; 4052], +}} +STRUCT!{#[repr(packed)] struct OPM_GET_CODEC_INFO_INFORMATION { + rnRandomNumber: OPM_RANDOM_NUMBER, + Merit: DWORD, +}} +DEFINE_GUID!{IID_IOPMVideoOutput, + 0x0a15159d, 0x41c7, 0x4456, 0x93, 0xe1, 0x28, 0x4c, 0xd6, 0x1d, 0x4e, 0x8d} +RIDL!{#[uuid(0x0a15159d, 0x41c7, 0x4456, 0x93, 0xe1, 0x28, 0x4c, 0xd6, 0x1d, 0x4e, 0x8d)] +interface IOPMVideoOutput(IOPMVideoOutputVtbl): IUnknown(IUnknownVtbl) { + fn StartInitialization( + prnRandomNumber: *mut OPM_RANDOM_NUMBER, + ppbCertificate: *mut *mut BYTE, + pulCertificateLength: *mut ULONG, + ) -> HRESULT, + fn FinishInitialization( + pParameters: *const OPM_ENCRYPTED_INITIALIZATION_PARAMETERS, + ) -> HRESULT, + fn GetInformation( + pParameters: *const OPM_GET_INFO_PARAMETERS, + pRequestedInformation: *mut OPM_REQUESTED_INFORMATION, + ) -> HRESULT, + fn COPPCompatibleGetInformation( + pParameters: *const OPM_COPP_COMPATIBLE_GET_INFO_PARAMETERS, + pRequestedInformation: *mut OPM_REQUESTED_INFORMATION, + ) -> HRESULT, + fn Configure( + pParameters: *const OPM_CONFIGURE_PARAMETERS, + ulAdditionalParametersSize: ULONG, + pbAdditionalParameters: *const BYTE, + ) -> HRESULT, +}} +#[inline] +pub fn GetBusType(ulBusTypeAndImplementation: ULONG) -> ULONG { + ulBusTypeAndImplementation & OPM_BUS_TYPE_MASK +} +#[inline] +pub fn GetBusImplementation(ulBusTypeAndImplementation: ULONG) -> ULONG { + (ulBusTypeAndImplementation & OPM_BUS_IMPLEMENTATION_MODIFIER_MASK) >> 16 +} +#[inline] +pub fn IsNonStandardBusImplementation(ulBusTypeAndImplementation: ULONG) -> ULONG { + ulBusTypeAndImplementation & OPM_BUS_IMPLEMENTATION_MODIFIER_NON_STANDARD +} +extern "system" { + pub fn OPMGetVideoOutputsFromHMONITOR( + hMonitor: HMONITOR, + vos: OPM_VIDEO_OUTPUT_SEMANTICS, + pulNumVideoOutputs: *mut ULONG, + pppOPMVideoOutputArray: *mut *mut *mut IOPMVideoOutput, + ) -> HRESULT; + pub fn OPMGetVideoOutputForTarget( + pAdapterLuid: *mut LUID, + VidPnTarget: ULONG, + vos: OPM_VIDEO_OUTPUT_SEMANTICS, + ppOPMVideoOutput: *mut *mut IOPMVideoOutput, + ) -> HRESULT; + pub fn OPMGetVideoOutputsFromIDirect3DDevice9Object( + pDirect3DDevice9: *mut IDirect3DDevice9, + vos: OPM_VIDEO_OUTPUT_SEMANTICS, + pulNumVideoOutputs: *mut ULONG, + pppOPMVideoOutputArray: *mut *mut *mut IOPMVideoOutput, + ) -> HRESULT; +} diff --git a/winapi/src/um/pdh.rs b/winapi/src/um/pdh.rs new file mode 100644 index 000000000..9ef4ee74a --- /dev/null +++ b/winapi/src/um/pdh.rs @@ -0,0 +1,806 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Common Performance Data Helper definitions +use ctypes::c_double; +use shared::basetsd::DWORD_PTR; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, FILETIME, LPDWORD, UCHAR}; +use shared::windef::HWND; +use um::winnt::{BOOLEAN, HANDLE, LONG, LONGLONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR}; +pub const PDH_FMT_RAW: DWORD = 0x00000010; +pub const PDH_FMT_ANSI: DWORD = 0x00000020; +pub const PDH_FMT_UNICODE: DWORD = 0x00000040; +pub const PDH_FMT_LONG: DWORD = 0x00000100; +pub const PDH_FMT_DOUBLE: DWORD = 0x00000200; +pub const PDH_FMT_LARGE: DWORD = 0x00000400; +pub const PDH_FMT_NOSCALE: DWORD = 0x00001000; +pub const PDH_FMT_1000: DWORD = 0x00002000; +pub const PDH_FMT_NODATA: DWORD = 0x00004000; +pub const PDH_FMT_NOCAP100: DWORD = 0x00008000; +pub const PERF_DETAIL_COSTLY: DWORD = 0x00010000; +pub const PERF_DETAIL_STANDARD: DWORD = 0x0000FFFF; +pub type PDH_STATUS = LONG; +pub type PDH_HQUERY = HANDLE; +pub type HQUERY = PDH_HQUERY; +pub type PDH_HCOUNTER = HANDLE; +pub type HCOUNTER = PDH_HCOUNTER; +pub type PPDH_BROWSE_DLG_CONFIG_A = *mut PDH_BROWSE_DLG_CONFIG_A; +pub type PPDH_BROWSE_DLG_CONFIG_W = *mut PDH_BROWSE_DLG_CONFIG_W; +pub type PDH_HLOG = HANDLE; +pub type PPDH_RAW_LOG_RECORD = *mut PDH_RAW_LOG_RECORD; +pub type PPDH_TIME_INFO = *mut PDH_TIME_INFO; +pub type PPDH_RAW_COUNTER = *mut PDH_RAW_COUNTER; +pub type PPDH_COUNTER_INFO_A = *mut PDH_COUNTER_INFO_A; +pub type PPDH_COUNTER_INFO_W = *mut PDH_COUNTER_INFO_W; +pub type PPDH_STATISTICS = *mut PDH_STATISTICS; +pub type PPDH_FMT_COUNTERVALUE_ITEM_A = *mut PDH_FMT_COUNTERVALUE_ITEM_A; +pub type PPDH_FMT_COUNTERVALUE_ITEM_W = *mut PDH_FMT_COUNTERVALUE_ITEM_W; +pub type PPDH_DATA_ITEM_PATH_ELEMENTS_A = *mut PDH_DATA_ITEM_PATH_ELEMENTS_A; +pub type PPDH_DATA_ITEM_PATH_ELEMENTS_W = *mut PDH_DATA_ITEM_PATH_ELEMENTS_W; +pub type PPDH_FMT_COUNTERVALUE = *mut PDH_FMT_COUNTERVALUE; +FN!{stdcall CounterPathCallBack( + DWORD_PTR, +) -> PDH_STATUS} +pub type PPDH_COUNTER_PATH_ELEMENTS_A = *mut PDH_COUNTER_PATH_ELEMENTS_A; +pub type PPDH_COUNTER_PATH_ELEMENTS_W = *mut PDH_COUNTER_PATH_ELEMENTS_W; +pub type PPDH_BROWSE_DLG_CONFIG_HA = *mut PDH_BROWSE_DLG_CONFIG_HA; +pub type PPDH_BROWSE_DLG_CONFIG_HW = *mut PDH_BROWSE_DLG_CONFIG_HW; +UNION!{union PDH_FMT_COUNTERVALUE_u { + [u64; 1], + longValue longValue_mut: LONG, + doubleValue doubleValue_mut: c_double, + largeValue largeValue_mut: LONGLONG, + AnsiStringValue AnsiStringValue_mut: LPCSTR, + WideStringValue WideStringValue_mut: LPCWSTR, +}} +STRUCT!{struct PDH_FMT_COUNTERVALUE { + CStatus: DWORD, + u: PDH_FMT_COUNTERVALUE_u, +}} +STRUCT!{struct PDH_RAW_LOG_RECORD { + dwStructureSize: DWORD, + dwRecordType: DWORD, + dwItems: DWORD, + RawBytes: UCHAR, +}} +STRUCT!{struct PDH_TIME_INFO { + StartTime: LONGLONG, + EndTime: LONGLONG, + SampleCount: DWORD, +}} +STRUCT!{struct PDH_RAW_COUNTER { + CStatus: DWORD, + TimeStamp: FILETIME, + FirstValue: LONGLONG, + SecondValue: LONGLONG, + MultiCount: DWORD, +}} +STRUCT!{struct PDH_STATISTICS { + dwFormat: DWORD, + count: DWORD, + min: PDH_FMT_COUNTERVALUE, + max: PDH_FMT_COUNTERVALUE, + mean: PDH_FMT_COUNTERVALUE, +}} +STRUCT!{struct PDH_FMT_COUNTERVALUE_ITEM_A { + szName: LPSTR, + FmtValue: PDH_FMT_COUNTERVALUE, +}} +STRUCT!{struct PDH_FMT_COUNTERVALUE_ITEM_W { + szName: LPWSTR, + FmtValue: PDH_FMT_COUNTERVALUE, +}} +STRUCT!{struct PDH_BROWSE_DLG_CONFIG_A { + flags: DWORD, + hWndOwner: HWND, + szDataSource: LPSTR, + szReturnPathBuffer: LPSTR, + cchReturnPathLength: DWORD, + pCallBack: CounterPathCallBack, + dwCallBackArg: DWORD_PTR, + CallBackStatus: PDH_STATUS, + dwDefaultDetailLevel: DWORD, + szDialogBoxCaption: LPSTR, +}} +BITFIELD!{PDH_BROWSE_DLG_CONFIG_A flags: DWORD [ + IncludeInstanceIndex set_IncludeInstanceIndex[0..1], + SingleCounterPerAdd set_SingleCounterPerAdd[1..2], + SingleCounterPerDialog set_SingleCounterPerDialog[2..3], + LocalCountersOnly set_LocalCountersOnly[3..4], + WildCardInstances set_WildCardInstances[4..5], + HideDetailBox set_HideDetailBox[5..6], + InitializePath set_InitializePath[6..7], + DisableMachineSelection set_DisableMachineSelection[7..8], + IncludeCostlyObjects set_IncludeCostlyObjects[8..9], + ShowObjectBrowser set_ShowObjectBrowser[9..10], +]} +STRUCT!{struct PDH_BROWSE_DLG_CONFIG_W { + flags: DWORD, + hWndOwner: HWND, + szDataSource: LPWSTR, + szReturnPathBuffer: LPWSTR, + cchReturnPathLength: DWORD, + pCallBack: CounterPathCallBack, + dwCallBackArg: DWORD_PTR, + CallBackStatus: PDH_STATUS, + dwDefaultDetailLevel: DWORD, + szDialogBoxCaption: LPWSTR, +}} +BITFIELD!{PDH_BROWSE_DLG_CONFIG_W flags: DWORD [ + IncludeInstanceIndex set_IncludeInstanceIndex[0..1], + SingleCounterPerAdd set_SingleCounterPerAdd[1..2], + SingleCounterPerDialog set_SingleCounterPerDialog[2..3], + LocalCountersOnly set_LocalCountersOnly[3..4], + WildCardInstances set_WildCardInstances[4..5], + HideDetailBox set_HideDetailBox[5..6], + InitializePath set_InitializePath[6..7], + DisableMachineSelection set_DisableMachineSelection[7..8], + IncludeCostlyObjects set_IncludeCostlyObjects[8..9], + ShowObjectBrowser set_ShowObjectBrowser[9..10], +]} +STRUCT!{struct PDH_COUNTER_PATH_ELEMENTS_A { + szMachineName: LPSTR, + szObjectName: LPSTR, + szInstanceName: LPSTR, + szParentInstance: LPSTR, + dwInstanceIndex: DWORD, + szCounterName: LPSTR, +}} +STRUCT!{struct PDH_COUNTER_PATH_ELEMENTS_W { + szMachineName: LPWSTR, + szObjectName: LPWSTR, + szInstanceName: LPWSTR, + szParentInstance: LPWSTR, + dwInstanceIndex: DWORD, + szCounterName: LPWSTR, +}} +STRUCT!{struct PDH_DATA_ITEM_PATH_ELEMENTS_A { + szMachineName: LPSTR, + ObjectGUID: GUID, + dwItemId: DWORD, + szInstanceName: LPSTR, +}} +STRUCT!{struct PDH_DATA_ITEM_PATH_ELEMENTS_W { + szMachineName: LPWSTR, + ObjectGUID: GUID, + dwItemId: DWORD, + szInstanceName: LPWSTR, +}} +STRUCT!{struct PDH_COUNTER_INFO_A_u_s { + szMachineName: LPSTR, + szObjectName: LPSTR, + szInstanceName: LPSTR, + szParentInstance: LPSTR, + dwInstanceIndex: DWORD, + szCounterName: LPSTR, +}} +UNION!{union PDH_COUNTER_INFO_A_u { + [u32; 7] [u64; 6], + DataItemPath DataItemPath_mut: PDH_DATA_ITEM_PATH_ELEMENTS_A, + CounterPath CounterPath_mut: PDH_COUNTER_PATH_ELEMENTS_A, + s s_mut: PDH_COUNTER_INFO_A_u_s, +}} +STRUCT!{struct PDH_COUNTER_INFO_A { + dwLength: DWORD, + dwType: DWORD, + CVersion: DWORD, + CStatus: DWORD, + lScale: LONG, + lDefaultScale: LONG, + dwUserData: DWORD_PTR, + dwQueryUserData: DWORD_PTR, + szFullPath: LPSTR, + u: PDH_COUNTER_INFO_A_u, + szExplainText: LPSTR, + DataBuffer: [DWORD; 1], +}} +STRUCT!{struct PDH_COUNTER_INFO_W_u_s { + szMachineName: LPWSTR, + szObjectName: LPWSTR, + szInstanceName: LPWSTR, + szParentInstance: LPWSTR, + dwInstanceIndex: DWORD, + szCounterName: LPWSTR, +}} +UNION!{union PDH_COUNTER_INFO_W_u { + [u32; 7] [u64; 6], + DataItemPath DataItemPath_mut: PDH_DATA_ITEM_PATH_ELEMENTS_W, + CounterPath CounterPath_mut: PDH_COUNTER_PATH_ELEMENTS_W, + s s_mut: PDH_COUNTER_INFO_W_u_s, +}} +STRUCT!{struct PDH_COUNTER_INFO_W { + dwLength: DWORD, + dwType: DWORD, + CVersion: DWORD, + CStatus: DWORD, + lScale: LONG, + lDefaultScale: LONG, + dwUserData: DWORD_PTR, + dwQueryUserData: DWORD_PTR, + szFullPath: LPWSTR, + u: PDH_COUNTER_INFO_W_u, + szExplainText: LPWSTR, + DataBuffer: [DWORD; 1], +}} +STRUCT!{struct PDH_BROWSE_DLG_CONFIG_HA { + flags: DWORD, + hWndOwner: HWND, + hDataSource: PDH_HLOG, + szReturnPathBuffer: LPSTR, + cchReturnPathLength: DWORD, + pCallBack: CounterPathCallBack, + dwCallBackArg: DWORD_PTR, + CallBackStatus: PDH_STATUS, + dwDefaultDetailLevel: DWORD, + szDialogBoxCaption: LPSTR, +}} +BITFIELD!{PDH_BROWSE_DLG_CONFIG_HA flags: DWORD [ + IncludeInstanceIndex set_IncludeInstanceIndex[0..1], + SingleCounterPerAdd set_SingleCounterPerAdd[1..2], + SingleCounterPerDialog set_SingleCounterPerDialog[2..3], + LocalCountersOnly set_LocalCountersOnly[3..4], + WildCardInstances set_WildCardInstances[4..5], + HideDetailBox set_HideDetailBox[5..6], + InitializePath set_InitializePath[6..7], + DisableMachineSelection set_DisableMachineSelection[7..8], + IncludeCostlyObjects set_IncludeCostlyObjects[8..9], + ShowObjectBrowser set_ShowObjectBrowser[9..10], +]} +STRUCT!{struct PDH_BROWSE_DLG_CONFIG_HW { + flags: DWORD, + hWndOwner: HWND, + hDataSource: PDH_HLOG, + szReturnPathBuffer: LPWSTR, + cchReturnPathLength: DWORD, + pCallBack: CounterPathCallBack, + dwCallBackArg: DWORD_PTR, + CallBackStatus: PDH_STATUS, + dwDefaultDetailLevel: DWORD, + szDialogBoxCaption: LPWSTR, +}} +BITFIELD!{PDH_BROWSE_DLG_CONFIG_HW flags: DWORD [ + IncludeInstanceIndex set_IncludeInstanceIndex[0..1], + SingleCounterPerAdd set_SingleCounterPerAdd[1..2], + SingleCounterPerDialog set_SingleCounterPerDialog[2..3], + LocalCountersOnly set_LocalCountersOnly[3..4], + WildCardInstances set_WildCardInstances[4..5], + HideDetailBox set_HideDetailBox[5..6], + InitializePath set_InitializePath[6..7], + DisableMachineSelection set_DisableMachineSelection[7..8], + IncludeCostlyObjects set_IncludeCostlyObjects[8..9], + ShowObjectBrowser set_ShowObjectBrowser[9..10], +]} +extern "system" { + pub fn PdhGetDllVersion( + lpdwVersion: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhOpenQueryW( + szDataSource: LPCWSTR, + dwUserData: DWORD_PTR, + phQuery: *mut PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhOpenQueryA( + szDataSource: LPCSTR, + dwUserData: DWORD_PTR, + phQuery: *mut PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhAddCounterW( + hQuery: PDH_HQUERY, + szFullCounterPath: LPCWSTR, + dwUserData: DWORD_PTR, + phCounter: *mut PDH_HCOUNTER, + ) -> PDH_STATUS; + pub fn PdhAddCounterA( + hQuery: PDH_HQUERY, + szFullCounterPath: LPCSTR, + dwUserData: DWORD_PTR, + phCounter: *mut PDH_HCOUNTER, + ) -> PDH_STATUS; + pub fn PdhAddEnglishCounterW( + hQuery: PDH_HQUERY, + szFullCounterPath: LPCWSTR, + dwUserData: DWORD_PTR, + phCounter: *mut PDH_HCOUNTER, + ) -> PDH_STATUS; + pub fn PdhAddEnglishCounterA( + hQuery: PDH_HQUERY, + szFullCounterPath: LPCSTR, + dwUserData: DWORD_PTR, + phCounter: *mut PDH_HCOUNTER, + ) -> PDH_STATUS; + pub fn PdhCollectQueryDataWithTime( + hQuery: PDH_HQUERY, + pllTimeStamp: *mut LONGLONG, + ) -> PDH_STATUS; + pub fn PdhValidatePathExW( + hDataSource: PDH_HLOG, + szFullPathBuffer: LPCWSTR, + ) -> PDH_STATUS; + pub fn PdhValidatePathExA( + hDataSource: PDH_HLOG, + szFullPathBuffer: LPCSTR, + ) -> PDH_STATUS; + pub fn PdhRemoveCounter( + hCounter: PDH_HCOUNTER, + ) -> PDH_STATUS; + pub fn PdhCollectQueryData( + hQuery: PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhCloseQuery( + hQuery: PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhGetFormattedCounterValue( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + lpdwType: LPDWORD, + pValue: PPDH_FMT_COUNTERVALUE, + ) -> PDH_STATUS; + pub fn PdhGetFormattedCounterArrayA( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + lpdwBufferSize: LPDWORD, + lpdwBufferCount: LPDWORD, + ItemBuffer: PPDH_FMT_COUNTERVALUE_ITEM_A, + ) -> PDH_STATUS; + pub fn PdhGetFormattedCounterArrayW( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + lpdwBufferSize: LPDWORD, + lpdwBufferCount: LPDWORD, + ItemBuffer: PPDH_FMT_COUNTERVALUE_ITEM_W, + ) -> PDH_STATUS; + pub fn PdhGetRawCounterValue( + hCounter: PDH_HCOUNTER, + lpdwType: LPDWORD, + pValue: PPDH_RAW_COUNTER, + ) -> PDH_STATUS; + pub fn PdhGetRawCounterArrayA( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + lpdwBufferSize: LPDWORD, + lpdwBufferCount: LPDWORD, + ItemBuffer: PPDH_FMT_COUNTERVALUE_ITEM_A, + ) -> PDH_STATUS; + pub fn PdhGetRawCounterArrayW( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + lpdwBufferSize: LPDWORD, + lpdwBufferCount: LPDWORD, + ItemBuffer: PPDH_FMT_COUNTERVALUE_ITEM_W, + ) -> PDH_STATUS; + pub fn PdhCalculateCounterFromRawValue( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + rawValue1: PPDH_RAW_COUNTER, + rawValue2: PPDH_RAW_COUNTER, + fmtValue: PPDH_FMT_COUNTERVALUE, + ) -> PDH_STATUS; + pub fn PdhComputeCounterStatistics( + hCounter: PDH_HCOUNTER, + dwFormat: DWORD, + dwFirstEntry: DWORD, + dwNumEntries: DWORD, + lpRawValueArray: PPDH_RAW_COUNTER, + data: PPDH_STATISTICS, + ) -> PDH_STATUS; + pub fn PdhGetCounterInfoW( + hCounter: PDH_HCOUNTER, + bRetrieveExplainText: BOOLEAN, + pdwBufferSize: LPDWORD, + lpBuffer: PPDH_COUNTER_INFO_W, + ) -> PDH_STATUS; + pub fn PdhGetCounterInfoA( + hCounter: PDH_HCOUNTER, + bRetrieveExplainText: BOOLEAN, + pdwBufferSize: LPDWORD, + lpBuffer: PPDH_COUNTER_INFO_A, + ) -> PDH_STATUS; + pub fn PdhSetCounterScaleFactor( + hCounter: PDH_HCOUNTER, + lFactor: LONG, + ) -> PDH_STATUS; + pub fn PdhConnectMachineW( + szMachineName: LPCWSTR, + ) -> PDH_STATUS; + pub fn PdhConnectMachineA( + szMachineName: LPCSTR, + ) -> PDH_STATUS; + pub fn PdhEnumMachinesW( + szDataSource: LPCWSTR, + mszMachineNameList: LPWSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhEnumMachinesA( + szDataSource: LPCSTR, + mszMachineNameList: LPSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhEnumObjectsW( + szDataSource: LPCWSTR, + szMachineName: LPCWSTR, + mszObjectList: LPWSTR, + pcchBufferLength: LPDWORD, + dwDetailLevel: DWORD, + bRefresh: BOOL, + ) -> PDH_STATUS; + pub fn PdhEnumObjectsA( + szDataSource: LPCSTR, + szMachineName: LPCSTR, + mszObjectList: LPSTR, + pcchBufferLength: LPDWORD, + dwDetailLevel: DWORD, + bRefresh: BOOL, + ) -> PDH_STATUS; + pub fn PdhEnumObjectItemsW( + szDataSource: LPCWSTR, + szMachineName: LPCWSTR, + szObjectName: LPCWSTR, + mszCounterList: LPWSTR, + pcchCounterListLength: LPDWORD, + mszInstanceList: LPWSTR, + pcchInstanceListLength: LPDWORD, + dwDetailLevel: DWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhEnumObjectItemsA( + szDataSource: LPCSTR, + szMachineName: LPCSTR, + szObjectName: LPCSTR, + mszCounterList: LPSTR, + pcchCounterListLength: LPDWORD, + mszInstanceList: LPSTR, + pcchInstanceListLength: LPDWORD, + dwDetailLevel: DWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhMakeCounterPathW( + pCounterPathElements: PPDH_COUNTER_PATH_ELEMENTS_W, + szFullPathBuffer: LPWSTR, + pcchBufferSize: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhMakeCounterPathA( + pCounterPathElements: PPDH_COUNTER_PATH_ELEMENTS_A, + szFullPathBuffer: LPSTR, + pcchBufferSize: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhParseCounterPathW( + szFullPathBuffer: LPCWSTR, + pCounterPathElements: *mut PDH_COUNTER_PATH_ELEMENTS_W, + pcchBufferSize: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhParseCounterPathA( + szFullPathBuffer: LPCSTR, + pCounterPathElements: *mut PDH_COUNTER_PATH_ELEMENTS_A, + pcchBufferSize: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhParseInstanceNameW( + szInstanceString: LPCWSTR, + szInstanceName: LPWSTR, + pcchInstanceNameLength: LPDWORD, + szParentName: LPWSTR, + pcchParentNameLength: LPDWORD, + lpIndex: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhParseInstanceNameA( + szInstanceString: LPCSTR, + szInstanceName: LPSTR, + pcchInstanceNameLength: LPDWORD, + szParentName: LPSTR, + pcchParentNameLength: LPDWORD, + lpIndex: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhValidatePathW( + szFullCounterPath: LPCWSTR, + ) -> PDH_STATUS; + pub fn PdhValidatePathA( + szFullCounterPath: LPCSTR, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfObjectW( + szDataSource: LPCWSTR, + szMachineName: LPCWSTR, + szDefaultObjectName: LPWSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfObjectA( + szDataSource: LPCSTR, + szMachineName: LPCSTR, + szDefaultObjectName: LPSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfCounterW( + szDataSource: LPCWSTR, + szMachineName: LPCWSTR, + szObjectName: LPCWSTR, + szDefaultCounterName: LPWSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfCounterA( + szDataSource: LPCSTR, + szMachineName: LPCSTR, + szObjectName: LPCSTR, + szDefaultCounterName: LPSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhBrowseCountersW( + pBrowseDlgData: PPDH_BROWSE_DLG_CONFIG_W, + ) -> PDH_STATUS; + pub fn PdhBrowseCountersA( + pBrowseDlgData: PPDH_BROWSE_DLG_CONFIG_A, + ) -> PDH_STATUS; + pub fn PdhExpandCounterPathW( + szWildCardPath: LPCWSTR, + mszExpandedPathList: LPWSTR, + pcchPathListLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhExpandCounterPathA( + szWildCardPath: LPCSTR, + mszExpandedPathList: LPSTR, + pcchPathListLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhLookupPerfNameByIndexW( + szMachineName: LPCWSTR, + dwNameIndex: DWORD, + szNameBuffer: LPWSTR, + pcchNameBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhLookupPerfNameByIndexA( + szMachineName: LPCSTR, + dwNameIndex: DWORD, + szNameBuffer: LPSTR, + pcchNameBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhLookupPerfIndexByNameW( + szMachineName: LPCWSTR, + szNameBuffer: LPCWSTR, + pdwIndex: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhLookupPerfIndexByNameA( + szMachineName: LPCSTR, + szNameBuffer: LPCSTR, + pdwIndex: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhExpandWildCardPathW( + szDataSource: LPCWSTR, + szWildCardPath: LPCWSTR, + mszExpandedPathList: LPWSTR, + pcchPathListLength: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhExpandWildCardPathA( + szDataSource: LPCSTR, + szWildCardPath: LPCSTR, + mszExpandedPathList: LPSTR, + pcchPathListLength: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhOpenLogW( + szLogFileName: LPCWSTR, + dwAccessFlags: DWORD, + lpdwLogType: LPDWORD, + hQuery: PDH_HQUERY, + dwMaxSize: DWORD, + szUserCaption: LPCWSTR, + phLog: *mut PDH_HLOG, + ) -> PDH_STATUS; + pub fn PdhOpenLogA( + szLogFileName: LPCSTR, + dwAccessFlags: DWORD, + lpdwLogType: LPDWORD, + hQuery: PDH_HQUERY, + dwMaxSize: DWORD, + szUserCaption: LPCSTR, + phLog: *mut PDH_HLOG, + ) -> PDH_STATUS; + pub fn PdhUpdateLogW( + hLog: PDH_HLOG, + szUserString: LPCWSTR, + ) -> PDH_STATUS; + pub fn PdhUpdateLogA( + hLog: PDH_HLOG, + szUserString: LPCSTR, + ) -> PDH_STATUS; + pub fn PdhUpdateLogFileCatalog( + hLog: PDH_HLOG, + ) -> PDH_STATUS; + pub fn PdhGetLogFileSize( + hLog: PDH_HLOG, + llSize: *mut LONGLONG, + ) -> PDH_STATUS; + pub fn PdhCloseLog( + hLog: PDH_HLOG, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhSelectDataSourceW( + hWndOwner: HWND, + dwFlags: DWORD, + szDataSource: LPWSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhSelectDataSourceA( + hWndOwner: HWND, + dwFlags: DWORD, + szDataSource: LPSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhIsRealTimeQuery( + hQuery: PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhSetQueryTimeRange( + hQuery: PDH_HQUERY, + pInfo: PPDH_TIME_INFO, + ) -> PDH_STATUS; + pub fn PdhGetDataSourceTimeRangeW( + szDataSource: LPCWSTR, + pdwNumEntries: LPDWORD, + pInfo: PPDH_TIME_INFO, + pdwBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDataSourceTimeRangeA( + szDataSource: LPCSTR, + pdwNumEntries: LPDWORD, + pInfo: PPDH_TIME_INFO, + pdwBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhCollectQueryDataEx( + hQuery: PDH_HQUERY, + dwIntervalTime: DWORD, + hNewDataEvent: HANDLE, + ) -> PDH_STATUS; + pub fn PdhFormatFromRawValue( + dwCounterType: DWORD, + dwFormat: DWORD, + pTimeBase: *mut LONGLONG, + rawValue1: PPDH_RAW_COUNTER, + rawValue2: PPDH_RAW_COUNTER, + fmtValue: PPDH_FMT_COUNTERVALUE, + ) -> PDH_STATUS; + pub fn PdhGetCounterTimeBase( + hCounter: PDH_HCOUNTER, + pTimeBase: *mut LONGLONG, + ) -> PDH_STATUS; + pub fn PdhReadRawLogRecord( + hLog: PDH_HLOG, + ftRecord: FILETIME, + pRawLogRecord: PPDH_RAW_LOG_RECORD, + pdwBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhSetDefaultRealTimeDataSource( + dwDataSourceId: DWORD, + ) -> PDH_STATUS; + pub fn PdhBindInputDataSourceW( + phDataSource: *mut PDH_HLOG, + szLogFileNameList: LPCWSTR, + ) -> PDH_STATUS; + pub fn PdhBindInputDataSourceA( + phDataSource: *mut PDH_HLOG, + szLogFileNameList: LPCSTR, + ) -> PDH_STATUS; + pub fn PdhOpenQueryH( + hDataSource: PDH_HLOG, + dwUserData: DWORD_PTR, + phQuery: *mut PDH_HQUERY, + ) -> PDH_STATUS; + pub fn PdhEnumMachinesHW( + hDataSource: PDH_HLOG, + mszMachineNameList: LPWSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhEnumMachinesHA( + hDataSource: PDH_HLOG, + mszMachineNameList: LPSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhEnumObjectsHW( + hDataSource: PDH_HLOG, + szMachineName: LPCWSTR, + mszObjectList: LPWSTR, + pcchBufferLength: LPDWORD, + dwDetailLevel: DWORD, + bRefresh: BOOL, + ) -> PDH_STATUS; + pub fn PdhEnumObjectsHA( + hDataSource: PDH_HLOG, + szMachineName: LPCSTR, + mszObjectList: LPSTR, + pcchBufferLength: LPDWORD, + dwDetailLevel: DWORD, + bRefresh: BOOL, + ) -> PDH_STATUS; + pub fn PdhEnumObjectItemsHW( + hDataSource: PDH_HLOG, + szMachineName: LPCWSTR, + szObjectName: LPCWSTR, + mszCounterList: LPWSTR, + pcchCounterListLength: LPDWORD, + mszInstanceList: LPWSTR, + pcchInstanceListLength: LPDWORD, + dwDetailLevel: DWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhEnumObjectItemsHA( + hDataSource: PDH_HLOG, + szMachineName: LPCSTR, + szObjectName: LPCSTR, + mszCounterList: LPSTR, + pcchCounterListLength: LPDWORD, + mszInstanceList: LPSTR, + pcchInstanceListLength: LPDWORD, + dwDetailLevel: DWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhExpandWildCardPathHW( + hDataSource: PDH_HLOG, + szWildCardPath: LPCWSTR, + mszExpandedPathList: LPWSTR, + pcchPathListLength: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhExpandWildCardPathHA( + hDataSource: PDH_HLOG, + szWildCardPath: LPCSTR, + mszExpandedPathList: LPSTR, + pcchPathListLength: LPDWORD, + dwFlags: DWORD, + ) -> PDH_STATUS; + pub fn PdhGetDataSourceTimeRangeH( + hDataSource: PDH_HLOG, + pdwNumEntries: LPDWORD, + pInfo: PPDH_TIME_INFO, + pdwBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfObjectHW( + hDataSource: PDH_HLOG, + szMachineName: LPCWSTR, + szDefaultObjectName: LPWSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfObjectHA( + hDataSource: PDH_HLOG, + szMachineName: LPCSTR, + szDefaultObjectName: LPSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfCounterHW( + hDataSource: PDH_HLOG, + szMachineName: LPCWSTR, + szObjectName: LPCWSTR, + szDefaultCounterName: LPWSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhGetDefaultPerfCounterHA( + hDataSource: PDH_HLOG, + szMachineName: LPCSTR, + szObjectName: LPCSTR, + szDefaultCounterName: LPSTR, + pcchBufferSize: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhBrowseCountersHW( + pBrowseDlgData: PPDH_BROWSE_DLG_CONFIG_HW, + ) -> PDH_STATUS; + pub fn PdhBrowseCountersHA( + pBrowseDlgData: PPDH_BROWSE_DLG_CONFIG_HA, + ) -> PDH_STATUS; + pub fn PdhEnumLogSetNamesW( + szDataSource: LPCWSTR, + mszLogSetNameList: LPWSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; + pub fn PdhEnumLogSetNamesA( + szDataSource: LPCSTR, + mszLogSetNameList: LPSTR, + pcchBufferLength: LPDWORD, + ) -> PDH_STATUS; +} +// pub fn PdhVerifySQLDBW() -> PDH_STATUS; +// pub fn PdhVerifySQLDBA() -> PDH_STATUS; +// pub fn PdhCreateSQLTablesW() -> PDH_STATUS; +// pub fn PdhCreateSQLTablesA() -> PDH_STATUS; +//pub fn PdhGetLogSetGUID() -> PDH_STATUS; +// pub fn PdhSetLogSetRunID() -> PDH_STATUS; diff --git a/winapi/src/um/perflib.rs b/winapi/src/um/perflib.rs new file mode 100644 index 000000000..aea3bde94 --- /dev/null +++ b/winapi/src/um/perflib.rs @@ -0,0 +1,331 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::SIZE_T; +use shared::guiddef::{GUID, LPCGUID, LPGUID}; +use shared::minwindef::{DWORD, LPBYTE, LPDWORD, LPVOID, ULONG}; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{HANDLE, LONG, LONGLONG, LPCWSTR, PCWSTR, PHANDLE, PVOID, ULONGLONG}; +pub const PERF_PROVIDER_USER_MODE: ULONG = 0; +pub const PERF_PROVIDER_KERNEL_MODE: ULONG = 1; +pub const PERF_PROVIDER_DRIVER: ULONG = 2; +pub const PERF_COUNTERSET_FLAG_MULTIPLE: ULONG = 2; +pub const PERF_COUNTERSET_FLAG_AGGREGATE: ULONG = 4; +pub const PERF_COUNTERSET_FLAG_HISTORY: ULONG = 8; +pub const PERF_COUNTERSET_FLAG_INSTANCE: ULONG = 16; +pub const PERF_COUNTERSET_SINGLE_INSTANCE: ULONG = 0; +pub const PERF_COUNTERSET_MULTI_INSTANCES: ULONG = PERF_COUNTERSET_FLAG_MULTIPLE; +pub const PERF_COUNTERSET_SINGLE_AGGREGATE: ULONG = PERF_COUNTERSET_FLAG_AGGREGATE; +pub const PERF_COUNTERSET_MULTI_AGGREGATE: ULONG = PERF_COUNTERSET_FLAG_AGGREGATE + | PERF_COUNTERSET_FLAG_MULTIPLE; +pub const PERF_COUNTERSET_SINGLE_AGGREGATE_HISTORY: ULONG = PERF_COUNTERSET_FLAG_HISTORY + | PERF_COUNTERSET_SINGLE_AGGREGATE; +pub const PERF_COUNTERSET_INSTANCE_AGGREGATE: ULONG = PERF_COUNTERSET_MULTI_AGGREGATE + | PERF_COUNTERSET_FLAG_INSTANCE; +pub const PERF_AGGREGATE_UNDEFINED: ULONG = 0; +pub const PERF_AGGREGATE_TOTAL: ULONG = 1; +pub const PERF_AGGREGATE_AVG: ULONG = 2; +pub const PERF_AGGREGATE_MIN: ULONG = 3; +pub const PERF_AGGREGATE_MAX: ULONG = 4; +pub const PERF_ATTRIB_BY_REFERENCE: ULONGLONG = 0x0000000000000001; +pub const PERF_ATTRIB_NO_DISPLAYABLE: ULONGLONG = 0x0000000000000002; +pub const PERF_ATTRIB_NO_GROUP_SEPARATOR: ULONGLONG = 0x0000000000000004; +pub const PERF_ATTRIB_DISPLAY_AS_REAL: ULONGLONG = 0x0000000000000008; +pub const PERF_ATTRIB_DISPLAY_AS_HEX: ULONGLONG = 0x0000000000000010; +STRUCT!{struct PERF_COUNTERSET_INFO { + CounterSetGuid: GUID, + ProviderGuid: GUID, + NumCounters: ULONG, + InstanceType: ULONG, +}} +pub type PPERF_COUNTERSET_INFO = *mut PERF_COUNTERSET_INFO; +STRUCT!{struct PERF_COUNTER_INFO { + CounterId: ULONG, + Type: ULONG, + Attrib: ULONGLONG, + Size: ULONG, + DetailLevel: ULONG, + Scale: LONG, + Offset: LONG, +}} +pub type PPERF_COUNTER_INFO = *mut PERF_COUNTER_INFO; +STRUCT!{struct PERF_COUNTERSET_INSTANCE { + CounterSetGuid: GUID, + dwSize: ULONG, + InstanceId: ULONG, + InstanceNameOffset: ULONG, + InstanceNameSize: ULONG, +}} +pub type PPERF_COUNTERSET_INSTANCE = *mut PERF_COUNTERSET_INSTANCE; +STRUCT!{struct PERF_COUNTER_IDENTITY { + CounterSetGuid: GUID, + BufferSize: ULONG, + CounterId: ULONG, + InstanceId: ULONG, + MachineOffset: ULONG, + NameOffset: ULONG, + Reserved: ULONG, +}} +pub type PPERF_COUNTER_IDENTITY = *mut PERF_COUNTER_IDENTITY; +pub const PERF_WILDCARD_COUNTER: ULONG = 0xFFFFFFFF; +pub const PERF_WILDCARD_INSTANCE: &'static str = "*"; +pub const PERF_AGGREGATE_INSTANCE: &'static str = "_Total"; +pub const PERF_MAX_INSTANCE_NAME: ULONG = 1024; +pub const PERF_ADD_COUNTER: ULONG = 1; +pub const PERF_REMOVE_COUNTER: ULONG = 2; +pub const PERF_ENUM_INSTANCES: ULONG = 3; +pub const PERF_COLLECT_START: ULONG = 5; +pub const PERF_COLLECT_END: ULONG = 6; +pub const PERF_FILTER: ULONG = 9; +FN!{stdcall PERFLIBREQUEST( + RequestCode: ULONG, + Buffer: PVOID, + BufferSize: ULONG, +) -> ULONG} +FN!{stdcall PERF_MEM_ALLOC( + AllocSize: SIZE_T, + pContext: LPVOID, +) -> LPVOID} +FN!{stdcall PERF_MEM_FREE( + pBuffer: LPVOID, + pContext: LPVOID, +) -> ()} +STRUCT!{struct PERF_PROVIDER_CONTEXT { + ContextSize: DWORD, + Reserved: DWORD, + ControlCallback: PERFLIBREQUEST, + MemAllocRoutine: PERF_MEM_ALLOC, + MemFreeRoutine: PERF_MEM_FREE, + pMemContext: LPVOID, +}} +pub type PPERF_PROVIDER_CONTEXT = *mut PERF_PROVIDER_CONTEXT; +extern "system" { + pub fn PerfStartProviderEx( + ProviderGuid: LPGUID, + ProviderContext: PPERF_PROVIDER_CONTEXT, + Provider: PHANDLE, + ) -> ULONG; + pub fn PerfStartProvider( + ProviderGuid: LPGUID, + ControlCallback: PERFLIBREQUEST, + Provider: PHANDLE, + ) -> ULONG; + pub fn PerfStopProvider( + ProviderHandle: HANDLE, + ) -> ULONG; + pub fn PerfSetCounterSetInfo( + ProviderHandle: HANDLE, + Template: PPERF_COUNTERSET_INFO, + TemplateSize: ULONG, + ) -> ULONG; + pub fn PerfCreateInstance( + ProviderHandle: HANDLE, + CounterSetGuid: LPCGUID, + Name: PCWSTR, + Id: ULONG, + ) -> PPERF_COUNTERSET_INSTANCE; + pub fn PerfDeleteInstance( + Provider: HANDLE, + InstanceBlock: PPERF_COUNTERSET_INSTANCE, + ) -> ULONG; + pub fn PerfQueryInstance( + ProviderHandle: HANDLE, + CounterSetGuid: LPCGUID, + Name: LPCWSTR, + Id: ULONG, + ) -> PPERF_COUNTERSET_INSTANCE; + pub fn PerfSetCounterRefValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Address: PVOID, + ) -> ULONG; + pub fn PerfSetULongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONG, + ) -> ULONG; + pub fn PerfSetULongLongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONGLONG, + ) -> ULONG; + pub fn PerfIncrementULongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONG, + ) -> ULONG; + pub fn PerfIncrementULongLongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONGLONG, + ) -> ULONG; + pub fn PerfDecrementULongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONG, + ) -> ULONG; + pub fn PerfDecrementULongLongCounterValue( + Provider: HANDLE, + Instance: PPERF_COUNTERSET_INSTANCE, + CounterId: ULONG, + Value: ULONGLONG, + ) -> ULONG; +} +STRUCT!{struct PERF_INSTANCE_HEADER { + Size: ULONG, + InstanceId: ULONG, +}} +pub type PPERF_INSTANCE_HEADER = *mut PERF_INSTANCE_HEADER; +ENUM!{enum PerfRegInfoType { + PERF_REG_COUNTERSET_STRUCT = 1, + PERF_REG_COUNTER_STRUCT, + PERF_REG_COUNTERSET_NAME_STRING, + PERF_REG_COUNTERSET_HELP_STRING, + PERF_REG_COUNTER_NAME_STRINGS, + PERF_REG_COUNTER_HELP_STRINGS, + PERF_REG_PROVIDER_NAME, + PERF_REG_PROVIDER_GUID, + PERF_REG_COUNTERSET_ENGLISH_NAME, + PERF_REG_COUNTER_ENGLISH_NAMES, +}} +STRUCT!{struct PERF_COUNTERSET_REG_INFO { + CounterSetGuid: GUID, + CounterSetType: ULONG, + DetailLevel: ULONG, + NumCounters: ULONG, + InstanceType: ULONG, +}} +pub type PPERF_COUNTERSET_REG_INFO = *mut PERF_COUNTERSET_REG_INFO; +STRUCT!{struct PERF_COUNTER_REG_INFO { + CounterId: ULONG, + Type: ULONG, + Attrib: ULONGLONG, + DetailLevel: ULONG, + DefaultScale: LONG, + BaseCounterId: ULONG, + PerfTimeId: ULONG, + PerfFreqId: ULONG, + MultiId: ULONG, + AggregateFinc: ULONG, + Reserved: ULONG, +}} +pub type PPERF_COUNTER_REG_INFO = *mut PERF_COUNTER_REG_INFO; +STRUCT!{struct PERF_STRING_BUFFER_HEADER { + dwSize: DWORD, + dwCounters: DWORD, +}} +pub type PPERF_STRING_BUFFER_HEADER = *mut PERF_STRING_BUFFER_HEADER; +STRUCT!{struct PERF_STRING_COUNTER_HEADER { + dwCounterId: DWORD, + dwOffset: DWORD, +}} +pub type PPERF_STRING_COUNTER_HEADER = *mut PERF_STRING_COUNTER_HEADER; +STRUCT!{struct PERF_COUNTER_IDENTIFIER { + CounterSetGuid: GUID, + Status: ULONG, + Size: ULONG, + CounterId: ULONG, + InstanceId: ULONG, + Index: ULONG, + Reserved: ULONG, +}} +pub type PPERF_COUNTER_IDENTIFIER = *mut PERF_COUNTER_IDENTIFIER; +STRUCT!{struct PERF_DATA_HEADER { + dwTotalSize: ULONG, + dwNumCounters: ULONG, + PerfTimeStamp: LONGLONG, + PerfTime100NSec: LONGLONG, + PrefFreq: LONGLONG, + SystemTime: SYSTEMTIME, +}} +pub type PPERF_DATA_HEADER = *mut PERF_DATA_HEADER; +ENUM!{enum PerfCounterDataType { + PERF_ERROR_RETURN = 0, + PERF_SINGLE_COUNTER = 1, + PERF_MULTIPLE_COUNTERS = 2, + PERF_MULTIPLE_INSTANCES = 4, + PERF_COUNTERSET = 6, +}} +STRUCT!{struct PERF_COUNTER_HEADER { + dwStatus: ULONG, + dwType: PerfCounterDataType, + dwSize: ULONG, + Reserved: ULONG, +}} +pub type PPERF_COUNTER_HEADER = *mut PERF_COUNTER_HEADER; +STRUCT!{struct PERF_MULTI_INSTANCES { + dwTotalSize: ULONG, + dwInstances: ULONG, +}} +pub type PPERF_MULTI_INSTANCES = *mut PERF_MULTI_INSTANCES; +STRUCT!{struct PERF_MULTI_COUNTERS { + dwSize: ULONG, + dwCounters: ULONG, +}} +pub type PPERF_MULTI_COUNTERS = *mut PERF_MULTI_COUNTERS; +STRUCT!{struct PERF_COUNTER_DATA { + dwDataSize: ULONG, + dwSize: ULONG, +}} +pub type PPERF_COUNTER_DATA = *mut PERF_COUNTER_DATA; +extern "system" { + pub fn PerfEnumerateCounterSet( + szMachine: LPCWSTR, + pCounterSetIds: LPGUID, + cCounterSetIds: DWORD, + pcCounterSetIdsActual: LPDWORD, + ) -> ULONG; + pub fn PerfEnumerateCounterSetInstances( + szMachine: LPCWSTR, + pCounterSetIds: LPCGUID, + pInstances: PPERF_INSTANCE_HEADER, + cbInstances: DWORD, + pcbInstancesActual: LPDWORD, + ) -> ULONG; + pub fn PerfQueryCounterSetRegistrationInfo( + szMachine: LPCWSTR, + pCounterSetId: LPCGUID, + requestCode: PerfRegInfoType, + requestLangId: DWORD, + pbRegInfo: LPBYTE, + cbRegInfo: DWORD, + pcbRegInfoActual: LPDWORD, + ) -> ULONG; + pub fn PerfOpenQueryHandle( + szMachine: LPCWSTR, + hQuery: *mut HANDLE, + ) -> ULONG; + pub fn PerfCloseQueryHandle( + hQuery: HANDLE, + ) -> ULONG; + pub fn PerfQueryCounterInfo( + hQuery: HANDLE, + pCounters: PPERF_COUNTER_IDENTIFIER, + cbCounters: DWORD, + pcbCountersActual: LPDWORD, + ) -> ULONG; + pub fn PerfQueryCounterData( + hQuery: HANDLE, + pCounterBlock: PPERF_DATA_HEADER, + cbCounterBlock: DWORD, + pcbCounterBlockActual: LPDWORD, + ) -> ULONG; + pub fn PerfAddCounters( + hQuery: HANDLE, + pCounters: PPERF_COUNTER_IDENTIFIER, + cbCounters: DWORD, + ) -> ULONG; + pub fn PerfDeleteCounters( + hQuery: HANDLE, + pCounters: PPERF_COUNTER_IDENTIFIER, + cbCounters: DWORD, + ) -> ULONG; +} diff --git a/winapi/src/um/physicalmonitorenumerationapi.rs b/winapi/src/um/physicalmonitorenumerationapi.rs new file mode 100644 index 000000000..b61ff7e00 --- /dev/null +++ b/winapi/src/um/physicalmonitorenumerationapi.rs @@ -0,0 +1,43 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::d3d9::IDirect3DDevice9; +use shared::minwindef::{BOOL, DWORD, LPDWORD}; +use shared::windef::HMONITOR; +use um::winnt::{HANDLE, HRESULT, WCHAR}; +pub type _BOOL = BOOL; +pub const PHYSICAL_MONITOR_DESCRIPTION_SIZE: usize = 128; +STRUCT!{#[repr(packed)] struct PHYSICAL_MONITOR { + hPhysicalMonitor: HANDLE, + szPhysicalMonitorDescription: [WCHAR; PHYSICAL_MONITOR_DESCRIPTION_SIZE], +}} +pub type LPPHYSICAL_MONITOR = *mut PHYSICAL_MONITOR; +extern "system" { + pub fn GetNumberOfPhysicalMonitorsFromHMONITOR( + hMonitor: HMONITOR, + pdwNumberOfPhysicalMonitor: LPDWORD, + ) -> _BOOL; + pub fn GetNumberOfPhysicalMonitorsFromIDirect3DDevice9( + pDirect3DDevice9: *mut IDirect3DDevice9, + pdwNumberOfPhysicalMonitor: LPDWORD, + ) -> HRESULT; + pub fn GetPhysicalMonitorsFromHMONITOR( + hMonitor: HMONITOR, + dwPhysicalMonitorArraySize: DWORD, + pPhysicalMonitorArray: LPPHYSICAL_MONITOR, + ) -> _BOOL; + pub fn GetPhysicalMonitorsFromIDirect3DDevice9( + pDirect3DDevice9: IDirect3DDevice9, + dwPhysicalMonitorArraySize: DWORD, + pPhysicalMonitorArray: LPPHYSICAL_MONITOR, + ) -> HRESULT; + pub fn DestroyPhysicalMonitor( + hMonitor: HANDLE, + ) -> _BOOL; + pub fn DestroyPhysicalMonitors( + dwPhysicalMonitorArraySize: DWORD, + pPhysicalMonitorArray: LPPHYSICAL_MONITOR, + ) -> _BOOL; +} diff --git a/winapi/src/um/playsoundapi.rs b/winapi/src/um/playsoundapi.rs new file mode 100644 index 000000000..9b0d0d50a --- /dev/null +++ b/winapi/src/um/playsoundapi.rs @@ -0,0 +1,46 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-mm-playsound-l1-1-0 +use shared::minwindef::{BOOL, DWORD, HMODULE, UINT}; +use um::winnt::{LPCSTR, LPCWSTR}; +extern "system" { + pub fn sndPlaySoundA( + pszSound: LPCSTR, + fuSound: UINT, + ) -> BOOL; + pub fn sndPlaySoundW( + pszSound: LPCWSTR, + fuSound: UINT, + ) -> BOOL; +} +pub const SND_SYNC: DWORD = 0x0000; +pub const SND_ASYNC: DWORD = 0x0001; +pub const SND_NODEFAULT: DWORD = 0x0002; +pub const SND_MEMORY: DWORD = 0x0004; +pub const SND_LOOP: DWORD = 0x0008; +pub const SND_NOSTOP: DWORD = 0x0010; +pub const SND_NOWAIT: DWORD = 0x00002000; +pub const SND_ALIAS: DWORD = 0x00010000; +pub const SND_ALIAS_ID: DWORD = 0x00110000; +pub const SND_FILENAME: DWORD = 0x00020000; +pub const SND_RESOURCE: DWORD = 0x00040004; +pub const SND_PURGE: DWORD = 0x0040; +pub const SND_APPLICATION: DWORD = 0x0080; +pub const SND_SENTRY: DWORD = 0x00080000; +pub const SND_RING: DWORD = 0x00100000; +pub const SND_SYSTEM: DWORD = 0x00200000; +extern "system" { + pub fn PlaySoundA( + pszSound: LPCSTR, + hmod: HMODULE, + fdwSound: DWORD, + ) -> BOOL; + pub fn PlaySoundW( + pszSound: LPCWSTR, + hmod: HMODULE, + fdwSound: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/portabledevice.rs b/winapi/src/um/portabledevice.rs new file mode 100644 index 000000000..c191423f1 --- /dev/null +++ b/winapi/src/um/portabledevice.rs @@ -0,0 +1,162 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of PortableDevice.h +use shared::basetsd::ULONG_PTR; +DEFINE_GUID!{GUID_DEVINTERFACE_WPD, + 0x6AC27878, 0xA6FA, 0x4155, 0xBA, 0x85, 0xF9, 0x8F, 0x49, 0x1D, 0x4F, 0x33} +DEFINE_GUID!{GUID_DEVINTERFACE_WPD_PRIVATE, + 0xBA0C718F, 0x4DED, 0x49B7, 0xBD, 0xD3, 0xFA, 0xBE, 0x28, 0x66, 0x12, 0x11} +DEFINE_GUID!{GUID_DEVINTERFACE_WPD_SERVICE, + 0x9EF44F80, 0x3D64, 0x4246, 0xA6, 0xAA, 0x20, 0x6F, 0x32, 0x8D, 0x1E, 0xDC} +//51 +pub const WPD_DEVICE_OBJECT_ID: &'static str = "DEVICE"; +pub const WMDRMDEVICEAPP_USE_WPD_DEVICE_PTR: ULONG_PTR = -1isize as ULONG_PTR; +pub const PORTABLE_DEVICE_TYPE: &'static str = "PortableDeviceType"; +pub const PORTABLE_DEVICE_ICON: &'static str = "Icons"; +pub const PORTABLE_DEVICE_NAMESPACE_TIMEOUT: &'static str = "PortableDeviceNameSpaceTimeout"; +pub const PORTABLE_DEVICE_NAMESPACE_EXCLUDE_FROM_SHELL: &'static str + = "PortableDeviceNameSpaceExcludeFromShell"; +pub const PORTABLE_DEVICE_NAMESPACE_THUMBNAIL_CONTENT_TYPES: &'static str + = "PortableDeviceNameSpaceThumbnailContentTypes"; +pub const PORTABLE_DEVICE_IS_MASS_STORAGE: &'static str = "PortableDeviceIsMassStorage"; +pub const PORTABLE_DEVICE_DRM_SCHEME_WMDRM10_PD: &'static str = "WMDRM10-PD"; +pub const PORTABLE_DEVICE_DRM_SCHEME_PDDRM: &'static str = "PDDRM"; +//101 +ENUM!{enum WPD_DEVICE_TYPES { + WPD_DEVICE_TYPE_GENERIC = 0, + WPD_DEVICE_TYPE_CAMERA = 1, + WPD_DEVICE_TYPE_MEDIA_PLAYER = 2, + WPD_DEVICE_TYPE_PHONE = 3, + WPD_DEVICE_TYPE_VIDEO = 4, + WPD_DEVICE_TYPE_PERSONAL_INFORMATION_MANAGER = 5, + WPD_DEVICE_TYPE_AUDIO_RECORDER = 6, +}} +//133 +ENUM!{enum WPD_DEVICE_TRANSPORTS { + WPD_DEVICE_TRANSPORT_UNSPECIFIED = 0, + WPD_DEVICE_TRANSPORT_USB = 1, + WPD_DEVICE_TRANSPORT_IP = 2, + WPD_DEVICE_TRANSPORT_BLUETOOTH = 3, +}} +//175 +ENUM!{enum WPD_POWER_SOURCES { + WPD_POWER_SOURCE_BATTERY = 0, + WPD_POWER_SOURCE_EXTERNAL = 1, +}} +//696 +DEFINE_GUID!{WPD_FUNCTIONAL_OBJECT_PROPERTIES_V1, + 0x8F052D93, 0xABCA, 0x4FC5, 0xA5, 0xAC, 0xB0, 0x1D, 0xF4, 0xDB, 0xE5, 0x98} +DEFINE_PROPERTYKEY!{WPD_FUNCTIONAL_OBJECT_CATEGORY, + 0x8F052D93, 0xABCA, 0x4FC5, 0xA5, 0xAC, 0xB0, 0x1D, 0xF4, 0xDB, 0xE5, 0x98, 2} +//1140 +DEFINE_GUID!{WPD_DEVICE_PROPERTIES_V1, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC} +DEFINE_PROPERTYKEY!{WPD_DEVICE_SYNC_PARTNER, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 2} +DEFINE_PROPERTYKEY!{WPD_DEVICE_FIRMWARE_VERSION, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 3} +DEFINE_PROPERTYKEY!{WPD_DEVICE_POWER_LEVEL, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 4} +DEFINE_PROPERTYKEY!{WPD_DEVICE_POWER_SOURCE, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 5} +DEFINE_PROPERTYKEY!{WPD_DEVICE_PROTOCOL, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 6} +DEFINE_PROPERTYKEY!{WPD_DEVICE_MANUFACTURER, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 7} +DEFINE_PROPERTYKEY!{WPD_DEVICE_MODEL, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 8} +DEFINE_PROPERTYKEY!{WPD_DEVICE_SERIAL_NUMBER, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 9} +DEFINE_PROPERTYKEY!{WPD_DEVICE_SUPPORTS_NON_CONSUMABLE, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 10} +DEFINE_PROPERTYKEY!{WPD_DEVICE_DATETIME, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 11} +DEFINE_PROPERTYKEY!{WPD_DEVICE_FRIENDLY_NAME, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 12} +DEFINE_PROPERTYKEY!{WPD_DEVICE_SUPPORTED_DRM_SCHEMES, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 13} +DEFINE_PROPERTYKEY!{WPD_DEVICE_SUPPORTED_FORMATS_ARE_ORDERED, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 14} +DEFINE_PROPERTYKEY!{WPD_DEVICE_TYPE, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 15} +DEFINE_PROPERTYKEY!{WPD_DEVICE_NETWORK_IDENTIFIER, + 0x26D4979A, 0xE643, 0x4626, 0x9E, 0x2B, 0x73, 0x6D, 0xC0, 0xC9, 0x2F, 0xDC, 16} +DEFINE_GUID!{WPD_DEVICE_PROPERTIES_V2, + 0x463DD662, 0x7FC4, 0x4291, 0x91, 0x1C, 0x7F, 0x4C, 0x9C, 0xCA, 0x97, 0x99} +DEFINE_PROPERTYKEY!{WPD_DEVICE_FUNCTIONAL_UNIQUE_ID, + 0x463DD662, 0x7FC4, 0x4291, 0x91, 0x1C, 0x7F, 0x4C, 0x9C, 0xCA, 0x97, 0x99, 2} +DEFINE_PROPERTYKEY!{WPD_DEVICE_MODEL_UNIQUE_ID, + 0x463DD662, 0x7FC4, 0x4291, 0x91, 0x1C, 0x7F, 0x4C, 0x9C, 0xCA, 0x97, 0x99, 3} +DEFINE_PROPERTYKEY!{WPD_DEVICE_TRANSPORT, + 0x463DD662, 0x7FC4, 0x4291, 0x91, 0x1C, 0x7F, 0x4C, 0x9C, 0xCA, 0x97, 0x99, 4} +DEFINE_PROPERTYKEY!{WPD_DEVICE_USE_DEVICE_STAGE, + 0x463DD662, 0x7FC4, 0x4291, 0x91, 0x1C, 0x7F, 0x4C, 0x9C, 0xCA, 0x97, 0x99, 5} +DEFINE_GUID!{WPD_DEVICE_PROPERTIES_V3, + 0x6C2B878C, 0xC2EC, 0x490D, 0xB4, 0x25, 0xD7, 0xA7, 0x5E, 0x23, 0xE5, 0xED} +DEFINE_PROPERTYKEY!{WPD_DEVICE_EDP_IDENTITY, + 0x6C2B878C, 0xC2EC, 0x490D, 0xB4, 0x25, 0xD7, 0xA7, 0x5E, 0x23, 0xE5, 0xED, 1} +//1488 +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_COMMAND_CATEGORY, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1001} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_COMMAND_ID, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1002} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_HRESULT, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1003} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_DRIVER_ERROR_CODE, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1004} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_COMMAND_TARGET, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1006} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_PERSISTENT_UNIQUE_IDS, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1007} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_OBJECT_IDS, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1008} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_CLIENT_INFORMATION, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1009} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_CLIENT_INFORMATION_CONTEXT, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1010} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_COMMON_ACTIVITY_ID, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 1011} +DEFINE_PROPERTYKEY!{WPD_OPTION_VALID_OBJECT_IDS, + 0xF0422A9C, 0x5DC8, 0x4440, 0xB5, 0xBD, 0x5D, 0xF2, 0x88, 0x35, 0x65, 0x8A, 5001} +//3440 +DEFINE_PROPERTYKEY!{WPD_OBJECT_ID, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 2} +DEFINE_PROPERTYKEY!{WPD_OBJECT_PARENT_ID, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 3} +DEFINE_PROPERTYKEY!{WPD_OBJECT_NAME, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 4} +DEFINE_PROPERTYKEY!{WPD_OBJECT_PERSISTENT_UNIQUE_ID, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 5} +DEFINE_PROPERTYKEY!{WPD_OBJECT_FORMAT, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 6} +DEFINE_PROPERTYKEY!{WPD_OBJECT_ISHIDDEN, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 9} +DEFINE_PROPERTYKEY!{WPD_OBJECT_ISSYSTEM, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 10} +DEFINE_PROPERTYKEY!{WPD_OBJECT_SIZE, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 11} +DEFINE_PROPERTYKEY!{WPD_OBJECT_ORIGINAL_FILE_NAME, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 12} +DEFINE_PROPERTYKEY!{WPD_OBJECT_NON_CONSUMABLE, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 13} +DEFINE_PROPERTYKEY!{WPD_OBJECT_KEYWORDS, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 15} +DEFINE_PROPERTYKEY!{WPD_OBJECT_SYNC_ID, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 16} +DEFINE_PROPERTYKEY!{WPD_OBJECT_IS_DRM_PROTECTED, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 17} +DEFINE_PROPERTYKEY!{WPD_OBJECT_DATE_CREATED, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 18} +DEFINE_PROPERTYKEY!{WPD_OBJECT_DATE_MODIFIED, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 19} +DEFINE_PROPERTYKEY!{WPD_OBJECT_DATE_AUTHORED, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 20} +DEFINE_PROPERTYKEY!{WPD_OBJECT_BACK_REFERENCES, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 21} +DEFINE_PROPERTYKEY!{WPD_OBJECT_CAN_DELETE, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 26} +DEFINE_PROPERTYKEY!{WPD_OBJECT_LANGUAGE_LOCALE, + 0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C, 27} diff --git a/winapi/src/um/portabledeviceapi.rs b/winapi/src/um/portabledeviceapi.rs new file mode 100644 index 000000000..a694e7e2d --- /dev/null +++ b/winapi/src/um/portabledeviceapi.rs @@ -0,0 +1,288 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of PortableDeviceApi.h +use shared::guiddef::REFGUID; +use shared::minwindef::{BYTE, DWORD, ULONG}; +use um::objidlbase::IStream; +use um::portabledevicetypes::{ + IPortableDeviceKeyCollection, IPortableDevicePropVariantCollection, IPortableDeviceValues, +}; +use um::propkeydef::REFPROPERTYKEY; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, WCHAR}; +// 328 +RIDL!{#[uuid(0xa1567595, 0x4c2f, 0x4574, 0xa6, 0xfa, 0xec, 0xef, 0x91, 0x7b, 0x9a, 0x40)] +interface IPortableDeviceManager(IPortableDeviceManagerVtbl): IUnknown(IUnknownVtbl) { + fn GetDevices( + pPnPDeviceIDs: *mut LPWSTR, + pcPnPDeviceIDs: *mut DWORD, + ) -> HRESULT, + fn RefreshDeviceList() -> HRESULT, + fn GetDeviceFriendlyName( + pszPnPDeviceID: LPCWSTR, + pDeviceFriendlyName: *mut WCHAR, + pcchDeviceFriendlyName: *mut DWORD, + ) -> HRESULT, + fn GetDeviceDescription( + pszPnPDeviceID: LPCWSTR, + pDeviceDescription: *mut WCHAR, + pcchDeviceDescription: *mut DWORD, + ) -> HRESULT, + fn GetDeviceManufacturer( + pszPnPDeviceID: LPCWSTR, + pDeviceManufacturer: *mut WCHAR, + pcchDeviceManufacturer: *mut DWORD, + ) -> HRESULT, + fn GetDeviceProperty( + pszPnPDeviceID: LPCWSTR, + pszDevicePropertyName: LPCWSTR, + pData: *mut BYTE, + pcbData: *mut DWORD, + pdwType: *mut DWORD, + ) -> HRESULT, + fn GetPrivateDevices( + pPnPDeviceIDs: *mut LPWSTR, + pcPnPDeviceIDs: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x625e2df8, 0x6392, 0x4cf0, 0x9a, 0xd1, 0x3c, 0xfa, 0x5f, 0x17, 0x77, 0x5c)] +interface IPortableDevice(IPortableDeviceVtbl): IUnknown(IUnknownVtbl) { + fn Open( + pszPnPDeviceID: LPCWSTR, + pClientInfo: *mut IPortableDeviceValues, + ) -> HRESULT, + fn SendCommand( + dwFlags: DWORD, + pParameters: *mut IPortableDeviceValues, + ppResults: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn Content( + ppContent: *mut *mut IPortableDeviceContent, + ) -> HRESULT, + fn Capabilities( + ppCapabilities: *mut *mut IPortableDeviceCapabilities, + ) -> HRESULT, + fn Cancel() -> HRESULT, + fn Close() -> HRESULT, + fn Advise( + dwFlags: DWORD, + pCallback: *mut IPortableDeviceEventCallback, + pParameters: *mut IPortableDeviceValues, + ppszCookie: *mut LPWSTR, + ) -> HRESULT, + fn Unadvise( + pszCookie: LPCWSTR, + ) -> HRESULT, + fn GetPnPDeviceID( + ppszPnPDeviceID: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6a96ed84, 0x7c73, 0x4480, 0x99, 0x38, 0xbf, 0x5a, 0xf4, 0x77, 0xd4, 0x26)] +interface IPortableDeviceContent(IPortableDeviceContentVtbl): IUnknown(IUnknownVtbl) { + fn EnumObjects( + dwFlags: DWORD, + pszParentObjectID: LPCWSTR, + pFilter: *mut IPortableDeviceValues, + ppEnum: *mut *mut IEnumPortableDeviceObjectIDs, + ) -> HRESULT, + fn Properties( + ppProperties: *mut *mut IPortableDeviceProperties, + ) -> HRESULT, + fn Transfer( + ppResources: *mut *mut IPortableDeviceResources, + ) -> HRESULT, + fn CreateObjectWithPropertiesOnly( + pValues: *mut IPortableDeviceValues, + ppszObjectID: *mut LPWSTR, + ) -> HRESULT, + fn CreateObjectWithPropertiesAndData( + pValues: *mut IPortableDeviceValues, + ppData: *mut *mut IStream, + pdwOptimalWriteBufferSize: *mut DWORD, + ppszCookie: *mut LPWSTR, + ) -> HRESULT, + fn Delete( + dwOptions: DWORD, + pObjectIDs: *mut IPortableDevicePropVariantCollection, + ppResults: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetObjectIDsFromPersistentUniqueIDs( + pPersistentUniqueIDs: *mut IPortableDevicePropVariantCollection, + ppObjectIDs: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn Cancel() -> HRESULT, + fn Move( + pObjectIDs: *mut IPortableDevicePropVariantCollection, + pszDestinationFolderObjectID: LPCWSTR, + ppResults: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn Copy( + pObjectIDs: *mut IPortableDevicePropVariantCollection, + pszDestinationFolderObjectID: LPCWSTR, + ppResults: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9b4add96, 0xf6bf, 0x4034, 0x87, 0x08, 0xec, 0xa7, 0x2b, 0xf1, 0x05, 0x54)] +interface IPortableDeviceContent2(IPortableDeviceContent2Vtbl): + IPortableDeviceContent(IPortableDeviceContentVtbl) { + fn UpdateObjectWithPropertiesAndData( + pszObjectID: LPCWSTR, + pProperties: *mut IPortableDeviceValues, + ppData: *mut *mut IStream, + pdwOptimalWriteBufferSize: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x10ece955, 0xcf41, 0x4728, 0xbf, 0xa0, 0x41, 0xee, 0xdf, 0x1b, 0xbf, 0x19)] +interface IEnumPortableDeviceObjectIDs(IEnumPortableDeviceObjectIDsVtbl): IUnknown(IUnknownVtbl) { + fn Next( + cObjects: ULONG, + pObjIDs: *mut LPWSTR, + pcFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + cObjects: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppEnum: *mut *mut IEnumPortableDeviceObjectIDs, + ) -> HRESULT, + fn Cancel() -> HRESULT, +}} +RIDL!{#[uuid(0x7f6d695c, 0x03df, 0x4439, 0xa8, 0x09, 0x59, 0x26, 0x6b, 0xee, 0xe3, 0xa6)] +interface IPortableDeviceProperties(IPortableDevicePropertiesVtbl): IUnknown(IUnknownVtbl) { + fn GetSupportedProperties( + pszObjectID: LPCWSTR, + ppKeys: *mut *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn GetPropertyAttributes( + pszObjectID: LPCWSTR, + Key: REFPROPERTYKEY, + ppAttributes: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn GetValues( + pszObjectID: LPCWSTR, + pKeys: *mut IPortableDeviceKeyCollection, + ppValues: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn SetValues( + pszObjectID: LPCWSTR, + pValues: *mut IPortableDeviceValues, + ppResults: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn Delete( + pszObjectID: LPCWSTR, + pKeys: *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn Cancel() -> HRESULT, +}} +RIDL!{#[uuid(0xfd8878ac, 0xd841, 0x4d17, 0x89, 0x1c, 0xe6, 0x82, 0x9c, 0xdb, 0x69, 0x34)] +interface IPortableDeviceResources(IPortableDeviceResourcesVtbl): IUnknown(IUnknownVtbl) { + fn GetSupportedResources( + pszObjectID: LPCWSTR, + ppKeys: *mut *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn GetResourceAttributes( + pszObjectID: LPCWSTR, + Key: REFPROPERTYKEY, + ppResourceAttributes: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn GetStream( + pszObjectID: LPCWSTR, + Key: REFPROPERTYKEY, + dwMode: DWORD, + pdwOptimalBufferSize: *mut DWORD, + ppStream: *mut *mut IStream, + ) -> HRESULT, + fn Delete( + pszObjectID: LPCWSTR, + pKeys: *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn Cancel() -> HRESULT, + fn CreateResource( + pResourceAttributes: *mut IPortableDeviceValues, + ppData: *mut *mut IStream, + pdwOptimalWriteBufferSize: *mut DWORD, + ppszCookie: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2c8c6dbf, 0xe3dc, 0x4061, 0xbe, 0xcc, 0x85, 0x42, 0xe8, 0x10, 0xd1, 0x26)] +interface IPortableDeviceCapabilities(IPortableDeviceCapabilitiesVtbl): IUnknown(IUnknownVtbl) { + fn GetSupportedCommands( + ppCommands: *mut *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn GetCommandOptions( + Command: REFPROPERTYKEY, + ppOptions: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn GetFunctionalCategories( + ppCategories: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetFunctionalObjects( + Category: REFGUID, + ppObjectIDs: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetSupportedContentTypes( + Category: REFGUID, + ppContentTypes: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetSupportedFormats( + ContentType: REFGUID, + ppFormats: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetSupportedFormatProperties( + Format: REFGUID, + ppKeys: *mut *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn GetFixedPropertyAttributes( + Format: REFGUID, + Key: REFPROPERTYKEY, + ppAttributes: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn Cancel() -> HRESULT, + fn GetSupportedEvents( + ppEvents: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetEventOptions( + Event: REFGUID, + ppOptions: *mut *mut IPortableDeviceValues, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa8792a31, 0xf385, 0x493c, 0xa8, 0x93, 0x40, 0xf6, 0x4e, 0xb4, 0x5f, 0x6e)] +interface IPortableDeviceEventCallback(IPortableDeviceEventCallbackVtbl): IUnknown(IUnknownVtbl) { + fn OnEvent( + pEventParameters: *mut IPortableDeviceValues, + ) -> HRESULT, +}} +DEFINE_GUID!{LIBID_PortableDeviceApiLib, + 0x1f001332, 0x1a57, 0x4934, 0xbe, 0x31, 0xaf, 0xfc, 0x99, 0xf4, 0xee, 0x0a} +DEFINE_GUID!{CLSID_PortableDevice, + 0x728a21c5, 0x3d9e, 0x48d7, 0x98, 0x10, 0x86, 0x48, 0x48, 0xf0, 0xf4, 0x04} +RIDL!{#[uuid(0x728a21c5, 0x3d9e, 0x48d7, 0x98, 0x10, 0x86, 0x48, 0x48, 0xf0, 0xf4, 0x04)] +class PortableDevice;} +DEFINE_GUID!{CLSID_PortableDeviceManager, + 0x0af10cec, 0x2ecd, 0x4b92, 0x95, 0x81, 0x34, 0xf6, 0xae, 0x06, 0x37, 0xf3} +RIDL!{#[uuid(0x0af10cec, 0x2ecd, 0x4b92, 0x95, 0x81, 0x34, 0xf6, 0xae, 0x06, 0x37, 0xf3)] +class PortableDeviceManager;} +DEFINE_GUID!{CLSID_PortableDeviceService, + 0xef5db4c2, 0x9312, 0x422c, 0x91, 0x52, 0x41, 0x1c, 0xd9, 0xc4, 0xdd, 0x84} +RIDL!{#[uuid(0xef5db4c2, 0x9312, 0x422c, 0x91, 0x52, 0x41, 0x1c, 0xd9, 0xc4, 0xdd, 0x84)] +class PortableDeviceService;} +DEFINE_GUID!{CLSID_PortableDeviceDispatchFactory, + 0x43232233, 0x8338, 0x4658, 0xae, 0x01, 0x0b, 0x4a, 0xe8, 0x30, 0xb6, 0xb0} +RIDL!{#[uuid(0x43232233, 0x8338, 0x4658, 0xae, 0x01, 0x0b, 0x4a, 0xe8, 0x30, 0xb6, 0xb0)] +class PortableDeviceDispatchFactory;} +DEFINE_GUID!{CLSID_PortableDeviceFTM, + 0xf7c0039a, 0x4762, 0x488a, 0xb4, 0xb3, 0x76, 0x0e, 0xf9, 0xa1, 0xba, 0x9b} +RIDL!{#[uuid(0xf7c0039a, 0x4762, 0x488a, 0xb4, 0xb3, 0x76, 0x0e, 0xf9, 0xa1, 0xba, 0x9b)] +class PortableDeviceFTM;} +DEFINE_GUID!{CLSID_PortableDeviceServiceFTM, + 0x1649b154, 0xc794, 0x497a, 0x9b, 0x03, 0xf3, 0xf0, 0x12, 0x13, 0x02, 0xf3} +RIDL!{#[uuid(0x1649b154, 0xc794, 0x497a, 0x9b, 0x03, 0xf3, 0xf0, 0x12, 0x13, 0x02, 0xf3)] +class PortableDeviceServiceFTM;} +DEFINE_GUID!{CLSID_PortableDeviceWebControl, + 0x186dd02c, 0x2dec, 0x41b5, 0xa7, 0xd4, 0xb5, 0x90, 0x56, 0xfa, 0xde, 0x51} +RIDL!{#[uuid(0x186dd02c, 0x2dec, 0x41b5, 0xa7, 0xd4, 0xb5, 0x90, 0x56, 0xfa, 0xde, 0x51)] +class PortableDeviceWebControl;} diff --git a/winapi/src/um/portabledevicetypes.rs b/winapi/src/um/portabledevicetypes.rs new file mode 100644 index 000000000..f6c13d3ec --- /dev/null +++ b/winapi/src/um/portabledevicetypes.rs @@ -0,0 +1,255 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of PortableDeviceTypes.h +use shared::guiddef::{GUID, REFGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, ULONG}; +use shared::wtypes::{PROPERTYKEY, VARTYPE}; +use um::propidl::PROPVARIANT; +use um::propkeydef::REFPROPERTYKEY; +use um::propsys::IPropertyStore; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LONG, LONGLONG, LPCWSTR, LPWSTR, ULONGLONG}; +//330 +RIDL!{#[uuid(0x6848f6f2, 0x3155, 0x4f86, 0xb6, 0xf5, 0x26, 0x3e, 0xee, 0xab, 0x31, 0x43)] +interface IPortableDeviceValues(IPortableDeviceValuesVtbl): IUnknown(IUnknownVtbl) { + fn GetCount( + pcelt: *mut DWORD, + ) -> HRESULT, + fn GetAt( + index: DWORD, + pKey: *mut PROPERTYKEY, + pValue: *mut PROPVARIANT, + ) -> HRESULT, + fn SetValue( + key: REFPROPERTYKEY, + pValue: *const PROPVARIANT, + ) -> HRESULT, + fn GetValue( + key: REFPROPERTYKEY, + pValue: *mut PROPVARIANT, + ) -> HRESULT, + fn SetStringValue( + key: REFPROPERTYKEY, + Value: LPCWSTR, + ) -> HRESULT, + fn GetStringValue( + key: REFPROPERTYKEY, + pValue: *mut LPWSTR, + ) -> HRESULT, + fn SetUnsignedIntegerValue( + key: REFPROPERTYKEY, + Value: ULONG, + ) -> HRESULT, + fn GetUnsignedIntegerValue( + key: REFPROPERTYKEY, + pValue: *mut ULONG, + ) -> HRESULT, + fn SetSignedIntegerValue( + key: REFPROPERTYKEY, + Value: LONG, + ) -> HRESULT, + fn GetSignedIntegerValue( + key: REFPROPERTYKEY, + pValue: *mut LONG, + ) -> HRESULT, + fn SetUnsignedLargeIntegerValue( + key: REFPROPERTYKEY, + Value: ULONGLONG, + ) -> HRESULT, + fn GetUnsignedLargeIntegerValue( + key: REFPROPERTYKEY, + pValue: *mut ULONGLONG, + ) -> HRESULT, + fn SetSignedLargeIntegerValue( + key: REFPROPERTYKEY, + Value: LONGLONG, + ) -> HRESULT, + fn GetSignedLargeIntegerValue( + key: REFPROPERTYKEY, + pValue: *mut LONGLONG, + ) -> HRESULT, + fn SetFloatValue( + key: REFPROPERTYKEY, + Value: FLOAT, + ) -> HRESULT, + fn GetFloatValue( + key: REFPROPERTYKEY, + pValue: *mut FLOAT, + ) -> HRESULT, + fn SetErrorValue( + key: REFPROPERTYKEY, + Value: HRESULT, + ) -> HRESULT, + fn GetErrorValue( + key: REFPROPERTYKEY, + pValue: *mut HRESULT, + ) -> HRESULT, + fn SetKeyValue( + key: REFPROPERTYKEY, + Value: REFPROPERTYKEY, + ) -> HRESULT, + fn GetKeyValue( + key: REFPROPERTYKEY, + pValue: *mut PROPERTYKEY, + ) -> HRESULT, + fn SetBoolValue( + key: REFPROPERTYKEY, + Value: BOOL, + ) -> HRESULT, + fn GetBoolValue( + key: REFPROPERTYKEY, + pValue: *mut BOOL, + ) -> HRESULT, + fn SetIUnknownValue( + key: REFPROPERTYKEY, + pValue: *mut IUnknown, + ) -> HRESULT, + fn GetIUnknownValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut IUnknown, + ) -> HRESULT, + fn SetGuidValue( + key: REFPROPERTYKEY, + Value: REFGUID, + ) -> HRESULT, + fn GetGuidValue( + key: REFPROPERTYKEY, + pValue: *mut GUID, + ) -> HRESULT, + fn SetBufferValue( + key: REFPROPERTYKEY, + pValue: *mut BYTE, + cbValue: DWORD, + ) -> HRESULT, + fn GetBufferValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut BYTE, + pcbValue: *mut DWORD, + ) -> HRESULT, + fn SetIPortableDeviceValuesValue( + key: REFPROPERTYKEY, + pValue: *mut IPortableDeviceValues, + ) -> HRESULT, + fn GetIPortableDeviceValuesValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn SetIPortableDevicePropVariantCollectionValue( + key: REFPROPERTYKEY, + pValue: *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn GetIPortableDevicePropVariantCollectionValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut IPortableDevicePropVariantCollection, + ) -> HRESULT, + fn SetIPortableDeviceKeyCollectionValue( + key: REFPROPERTYKEY, + pValue: *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn GetIPortableDeviceKeyCollectionValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut IPortableDeviceKeyCollection, + ) -> HRESULT, + fn SetIPortableDeviceValuesCollectionValue( + key: REFPROPERTYKEY, + pValue: *mut IPortableDeviceValuesCollection, + ) -> HRESULT, + fn GetIPortableDeviceValuesCollectionValue( + key: REFPROPERTYKEY, + ppValue: *mut *mut IPortableDeviceValuesCollection, + ) -> HRESULT, + fn RemoveValue( + key: REFPROPERTYKEY, + ) -> HRESULT, + fn CopyValuesFromPropertyStore( + pStore: *mut IPropertyStore, + ) -> HRESULT, + fn CopyValuesToPropertyStore( + pStore: *mut IPropertyStore, + ) -> HRESULT, + fn Clear() -> HRESULT, +}} +RIDL!{#[uuid(0xdada2357, 0xe0ad, 0x492e, 0x98, 0xdb, 0xdd, 0x61, 0xc5, 0x3b, 0xa3, 0x53)] +interface IPortableDeviceKeyCollection(IPortableDeviceKeyCollectionVtbl): IUnknown(IUnknownVtbl) { + fn GetCount( + pcElems: *mut DWORD, + ) -> HRESULT, + fn GetAt( + dwIndex: DWORD, + pKey: *mut PROPERTYKEY, + ) -> HRESULT, + fn Add( + Key: REFPROPERTYKEY, + ) -> HRESULT, + fn Clear() -> HRESULT, + fn RemoveAt( + dwIndex: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x89b2e422, 0x4f1b, 0x4316, 0xbc, 0xef, 0xa4, 0x4a, 0xfe, 0xa8, 0x3e, 0xb3)] +interface IPortableDevicePropVariantCollection(IPortableDevicePropVariantCollectionVtbl): + IUnknown(IUnknownVtbl) { + fn GetCount( + pcElems: *mut DWORD, + ) -> HRESULT, + fn GetAt( + dwIndex: DWORD, + pValue: *mut PROPVARIANT, + ) -> HRESULT, + fn Add( + pValue: *const PROPVARIANT, + ) -> HRESULT, + fn GetType( + pvt: *mut VARTYPE, + ) -> HRESULT, + fn ChangeType( + vt: VARTYPE, + ) -> HRESULT, + fn Clear() -> HRESULT, + fn RemoveAt( + dwIndex: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6e3f2d79, 0x4e07, 0x48c4, 0x82, 0x08, 0xd8, 0xc2, 0xe5, 0xaf, 0x4a, 0x99)] +interface IPortableDeviceValuesCollection(IPortableDeviceValuesCollectionVtbl): + IUnknown(IUnknownVtbl) { + fn GetCount( + pcElems: *mut DWORD, + ) -> HRESULT, + fn GetAt( + dwIndex: DWORD, + ppValues: *mut *mut IPortableDeviceValues, + ) -> HRESULT, + fn Add( + pValues: *mut IPortableDeviceValues, + ) -> HRESULT, + fn Clear() -> HRESULT, + fn RemoveAt( + dwIndex: DWORD, + ) -> HRESULT, +}} +DEFINE_GUID!{LIBID_PortableDeviceTypesLib, + 0x2B00BA2F, 0xE750, 0x4beb, 0x92, 0x35, 0x97, 0x14, 0x2E, 0xDE, 0x1D, 0x3E} +DEFINE_GUID!{CLSID_WpdSerializer, + 0x0b91a74b, 0xad7c, 0x4a9d, 0xb5, 0x63, 0x29, 0xee, 0xf9, 0x16, 0x71, 0x72} +RIDL!{#[uuid(0x0b91a74b, 0xad7c, 0x4a9d, 0xb5, 0x63, 0x29, 0xee, 0xf9, 0x16, 0x71, 0x72)] +class WpdSerializer;} +DEFINE_GUID!{CLSID_PortableDeviceValues, + 0x0c15d503, 0xd017, 0x47ce, 0x90, 0x16, 0x7b, 0x3f, 0x97, 0x87, 0x21, 0xcc} +RIDL!{#[uuid(0x0c15d503, 0xd017, 0x47ce, 0x90, 0x16, 0x7b, 0x3f, 0x97, 0x87, 0x21, 0xcc)] +class PortableDeviceValues;} +DEFINE_GUID!{CLSID_PortableDeviceKeyCollection, + 0xde2d022d, 0x2480, 0x43be, 0x97, 0xf0, 0xd1, 0xfa, 0x2c, 0xf9, 0x8f, 0x4f} +RIDL!{#[uuid(0xde2d022d, 0x2480, 0x43be, 0x97, 0xf0, 0xd1, 0xfa, 0x2c, 0xf9, 0x8f, 0x4f)] +class PortableDeviceKeyCollection;} +DEFINE_GUID!{CLSID_PortableDevicePropVariantCollection, + 0x08a99e2f, 0x6d6d, 0x4b80, 0xaf, 0x5a, 0xba, 0xf2, 0xbc, 0xbe, 0x4c, 0xb9} +RIDL!{#[uuid(0x08a99e2f, 0x6d6d, 0x4b80, 0xaf, 0x5a, 0xba, 0xf2, 0xbc, 0xbe, 0x4c, 0xb9)] +class PortableDevicePropVariantCollection;} +DEFINE_GUID!{CLSID_PortableDeviceValuesCollection, + 0x3882134d, 0x14cf, 0x4220, 0x9c, 0xb4, 0x43, 0x5f, 0x86, 0xd8, 0x3f, 0x60} +RIDL!{#[uuid(0x3882134d, 0x14cf, 0x4220, 0x9c, 0xb4, 0x43, 0x5f, 0x86, 0xd8, 0x3f, 0x60)] +class PortableDeviceValuesCollection;} diff --git a/winapi/src/um/powerbase.rs b/winapi/src/um/powerbase.rs new file mode 100644 index 000000000..f856fddf8 --- /dev/null +++ b/winapi/src/um/powerbase.rs @@ -0,0 +1,35 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, ULONG}; +use um::winnt::{ + BOOLEAN, HANDLE, LONG, POWER_INFORMATION_LEVEL, POWER_PLATFORM_ROLE, + PSYSTEM_POWER_CAPABILITIES, PVOID, +}; +use um::winuser::{HPOWERNOTIFY, PHPOWERNOTIFY}; +pub type NTSTATUS = LONG; +extern "system" { + pub fn CallNtPowerInformation( + InformationLevel: POWER_INFORMATION_LEVEL, + InputBuffer: PVOID, + InputBufferLength: ULONG, + OutputBuffer: PVOID, + OutputBufferLength: ULONG, + ) -> NTSTATUS; + pub fn GetPwrCapabilities( + lpspc: PSYSTEM_POWER_CAPABILITIES, + ) -> BOOLEAN; + pub fn PowerDeterminePlatformRoleEx( + Version: ULONG, + ) -> POWER_PLATFORM_ROLE; + pub fn PowerRegisterSuspendResumeNotification( + Flags: DWORD, + Recipient: HANDLE, + RegistrationHandle: PHPOWERNOTIFY, + ) -> DWORD; + pub fn PowerUnregisterSuspendResumeNotification( + RegistrationHandle: HPOWERNOTIFY, + ) -> DWORD; +} diff --git a/winapi/src/um/powersetting.rs b/winapi/src/um/powersetting.rs new file mode 100644 index 000000000..88b0c6fa6 --- /dev/null +++ b/winapi/src/um/powersetting.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::{GUID, LPCGUID}; +use shared::minwindef::{DWORD, HKEY, LPBYTE, LPDWORD, PUCHAR, PULONG}; +use um::winnt::HANDLE; +use um::winuser::{HPOWERNOTIFY, PHPOWERNOTIFY}; +extern "system" { + pub fn PowerReadACValue( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Type: PULONG, + Buffer: LPBYTE, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadDCValue( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Type: PULONG, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerWriteACValueIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + AcValueIndex: DWORD, + ) -> DWORD; + pub fn PowerWriteDCValueIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + DcValueIndex: DWORD, + ) -> DWORD; + pub fn PowerGetActiveScheme( + UserRootPowerKey: HKEY, + ActivePolicyGuid: *mut *mut GUID, + ) -> DWORD; + pub fn PowerSetActiveScheme( + UserRootPowerKey: HKEY, + SchemeGuid: *const GUID, + ) -> DWORD; + pub fn PowerSettingRegisterNotification( + SettingGuid: LPCGUID, + Flags: DWORD, + Recipient: HANDLE, + RegistrationHandle: PHPOWERNOTIFY, + ) -> DWORD; + pub fn PowerSettingUnregisterNotification( + RegistrationHandle: HPOWERNOTIFY, + ) -> DWORD; +} diff --git a/winapi/src/um/powrprof.rs b/winapi/src/um/powrprof.rs new file mode 100644 index 000000000..d2d365f87 --- /dev/null +++ b/winapi/src/um/powrprof.rs @@ -0,0 +1,550 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Interface for powrprof.dll, the power policy applicator +use shared::guiddef::GUID; +use shared::minwindef::{ + BOOL, DWORD, HKEY, LPARAM, LPDWORD, PBYTE, PUCHAR, PUINT, PULONG, UCHAR, UINT, ULONG, +}; +use um::winnt::{ + BOOLEAN, LPCWSTR, LPWSTR, NUM_DISCHARGE_POLICIES, PADMINISTRATOR_POWER_POLICY, + POWER_ACTION_POLICY, POWER_PLATFORM_ROLE, PROCESSOR_POWER_POLICY, PVOID, SYSTEM_POWER_LEVEL, + SYSTEM_POWER_STATE, +}; +use um::winreg::REGSAM; +STRUCT!{struct GLOBAL_MACHINE_POWER_POLICY { + Revision: ULONG, + LidOpenWakeAc: SYSTEM_POWER_STATE, + LidOpenWakeDc: SYSTEM_POWER_STATE, + BroadcastCapacityResolution: ULONG, +}} +pub type PGLOBAL_MACHINE_POWER_POLICY = *mut GLOBAL_MACHINE_POWER_POLICY; +STRUCT!{struct GLOBAL_USER_POWER_POLICY { + Revision: ULONG, + PowerButtonAc: POWER_ACTION_POLICY, + PowerButtonDc: POWER_ACTION_POLICY, + SleepButtonAc: POWER_ACTION_POLICY, + SleepButtonDc: POWER_ACTION_POLICY, + LidCloseAc: POWER_ACTION_POLICY, + LidCloseDc: POWER_ACTION_POLICY, + DischargePolicy: [SYSTEM_POWER_LEVEL; NUM_DISCHARGE_POLICIES], + GlobalFlags: ULONG, +}} +pub type PGLOBAL_USER_POWER_POLICY = *mut GLOBAL_USER_POWER_POLICY; +STRUCT!{struct GLOBAL_POWER_POLICY { + user: GLOBAL_USER_POWER_POLICY, + mach: GLOBAL_MACHINE_POWER_POLICY, +}} +pub type PGLOBAL_POWER_POLICY = *mut GLOBAL_POWER_POLICY; +STRUCT!{struct MACHINE_POWER_POLICY { + Revision: ULONG, + MinSleepAc: SYSTEM_POWER_STATE, + MinSleepDc: SYSTEM_POWER_STATE, + ReducedLatencySleepAc: SYSTEM_POWER_STATE, + ReducedLatencySleepDc: SYSTEM_POWER_STATE, + DozeTimeoutAc: ULONG, + DozeTimeoutDc: ULONG, + DozeS4TimeoutAc: ULONG, + DozeS4TimeoutDc: ULONG, + MinThrottleAc: UCHAR, + MinThrottleDc: UCHAR, + pad1: [UCHAR; 2], + OverThrottledAc: POWER_ACTION_POLICY, + OverThrottledDc: POWER_ACTION_POLICY, +}} +pub type PMACHINE_POWER_POLICY = *mut MACHINE_POWER_POLICY; +STRUCT!{struct MACHINE_PROCESSOR_POWER_POLICY { + Revision: ULONG, + ProcessorPolicyAc: PROCESSOR_POWER_POLICY, + ProcessorPolicyDc: PROCESSOR_POWER_POLICY, +}} +pub type PMACHINE_PROCESSOR_POWER_POLICY = *mut MACHINE_PROCESSOR_POWER_POLICY; +STRUCT!{struct USER_POWER_POLICY { + Revision: ULONG, + IdleAc: POWER_ACTION_POLICY, + IdleDc: POWER_ACTION_POLICY, + IdleTimeoutAc: ULONG, + IdleTimeoutDc: ULONG, + IdleSensitivityAc: UCHAR, + IdleSensitivityDc: UCHAR, + ThrottlePolicyAc: UCHAR, + ThrottlePolicyDc: UCHAR, + MaxSleepAc: SYSTEM_POWER_STATE, + MaxSleepDc: SYSTEM_POWER_STATE, + Reserved: [ULONG; 2], + VideoTimeoutAc: ULONG, + VideoTimeoutDc: ULONG, + SpindownTimeoutAc: ULONG, + SpindownTimeoutDc: ULONG, + OptimizeForPowerAc: BOOLEAN, + OptimizeForPowerDc: BOOLEAN, + FanThrottleToleranceAc: UCHAR, + FanThrottleToleranceDc: UCHAR, + ForcedThrottleAc: UCHAR, + ForcedThrottleDc: UCHAR, +}} +pub type PUSER_POWER_POLICY = *mut USER_POWER_POLICY; +STRUCT!{struct POWER_POLICY { + user: USER_POWER_POLICY, + mach: MACHINE_POWER_POLICY, +}} +pub type PPOWER_POLICY = *mut POWER_POLICY; +pub const EnableSysTrayBatteryMeter: ULONG = 0x01; +pub const EnableMultiBatteryDisplay: ULONG = 0x02; +pub const EnablePasswordLogon: ULONG = 0x04; +pub const EnableWakeOnRing: ULONG = 0x08; +pub const EnableVideoDimDisplay: ULONG = 0x10; +pub const POWER_ATTRIBUTE_HIDE: ULONG = 0x00000001; +pub const POWER_ATTRIBUTE_SHOW_AOAC: ULONG = 0x00000002; +pub const NEWSCHEME: UINT = -1i32 as u32; +FN!{stdcall PWRSCHEMESENUMPROC_V1( + Index: UINT, + NameSize: DWORD, + Name: LPWSTR, + DescriptionSize: DWORD, + Description: LPWSTR, + Policy: PPOWER_POLICY, + Context: LPARAM, +) -> BOOLEAN} +FN!{stdcall PWRSCHEMESENUMPROC_V2( + Index: UINT, + NameSize: DWORD, + Name: LPWSTR, + DescriptionSize: DWORD, + Description: LPWSTR, + Policy: PPOWER_POLICY, + Context: LPARAM, +) -> BOOLEAN} +pub type PWRSCHEMESENUMPROC = *mut PWRSCHEMESENUMPROC_V2; +extern "system" { + pub fn GetPwrDiskSpindownRange( + puiMax: PUINT, + puiMin: PUINT, + ) -> BOOLEAN; + pub fn EnumPwrSchemes( + lpfn: PWRSCHEMESENUMPROC, + lParam: LPARAM, + ) -> BOOLEAN; + pub fn ReadGlobalPwrPolicy( + pGlobalPowerPolicy: PGLOBAL_POWER_POLICY, + ) -> BOOLEAN; + pub fn ReadPwrScheme( + uiID: UINT, + pPowerPolicy: PPOWER_POLICY, + ) -> BOOLEAN; + pub fn WritePwrScheme( + puiID: PUINT, + lpszSchemeName: LPCWSTR, + lpszDescription: LPCWSTR, + lpScheme: PPOWER_POLICY, + ) -> BOOLEAN; + pub fn WriteGlobalPwrPolicy( + pGlobalPowerPolicy: PGLOBAL_POWER_POLICY, + ) -> BOOLEAN; + pub fn DeletePwrScheme( + uiID: UINT, + ) -> BOOLEAN; + pub fn GetActivePwrScheme( + puiID: PUINT, + ) -> BOOLEAN; + pub fn SetActivePwrScheme( + uiID: UINT, + pGlobalPowerPolicy: PGLOBAL_POWER_POLICY, + pPowerPolicy: PPOWER_POLICY, + ) -> BOOLEAN; + pub fn IsPwrSuspendAllowed() -> BOOLEAN; + pub fn IsPwrHibernateAllowed() -> BOOLEAN; + pub fn IsPwrShutdownAllowed() -> BOOLEAN; + pub fn IsAdminOverrideActive( + papp: PADMINISTRATOR_POWER_POLICY, + ) -> BOOLEAN; + pub fn SetSuspendState( + bHibernate: BOOLEAN, + bForce: BOOLEAN, + bWakeupEventsDisabled: BOOLEAN, + ) -> BOOLEAN; + pub fn GetCurrentPowerPolicies( + pGlobalPowerPolicy: PGLOBAL_POWER_POLICY, + pPowerPolicy: PPOWER_POLICY, + ) -> BOOLEAN; + pub fn CanUserWritePwrScheme() -> BOOLEAN; + pub fn ReadProcessorPwrScheme( + uiID: UINT, + pMachineProcessorPowerPolicy: PMACHINE_PROCESSOR_POWER_POLICY, + ) -> BOOLEAN; + pub fn WriteProcessorPwrScheme( + uiID: UINT, + pMachineProcessorPowerPolicy: PMACHINE_PROCESSOR_POWER_POLICY, + ) -> BOOLEAN; + pub fn ValidatePowerPolicies( + pGlobalPowerPolicy: PGLOBAL_POWER_POLICY, + pPowerPolicy: PPOWER_POLICY, + ) -> BOOLEAN; +} +ENUM!{enum POWER_DATA_ACCESSOR { + ACCESS_AC_POWER_SETTING_INDEX = 0, + ACCESS_DC_POWER_SETTING_INDEX, + ACCESS_FRIENDLY_NAME, + ACCESS_DESCRIPTION, + ACCESS_POSSIBLE_POWER_SETTING, + ACCESS_POSSIBLE_POWER_SETTING_FRIENDLY_NAME, + ACCESS_POSSIBLE_POWER_SETTING_DESCRIPTION, + ACCESS_DEFAULT_AC_POWER_SETTING, + ACCESS_DEFAULT_DC_POWER_SETTING, + ACCESS_POSSIBLE_VALUE_MIN, + ACCESS_POSSIBLE_VALUE_MAX, + ACCESS_POSSIBLE_VALUE_INCREMENT, + ACCESS_POSSIBLE_VALUE_UNITS, + ACCESS_ICON_RESOURCE, + ACCESS_DEFAULT_SECURITY_DESCRIPTOR, + ACCESS_ATTRIBUTES, + ACCESS_SCHEME, + ACCESS_SUBGROUP, + ACCESS_INDIVIDUAL_SETTING, + ACCESS_ACTIVE_SCHEME, + ACCESS_CREATE_SCHEME, + ACCESS_AC_POWER_SETTING_MAX, + ACCESS_DC_POWER_SETTING_MAX, + ACCESS_AC_POWER_SETTING_MIN, + ACCESS_DC_POWER_SETTING_MIN, + ACCESS_PROFILE, + ACCESS_OVERLAY_SCHEME, + ACCESS_ACTIVE_OVERLAY_SCHEME, +}} +pub type PPOWER_DATA_ACCESSOR = *mut POWER_DATA_ACCESSOR; +pub const DEVICE_NOTIFY_CALLBACK: ULONG = 2; +FN!{stdcall DEVICE_NOTIFY_CALLBACK_ROUTINE( + Context: PVOID, + Type: ULONG, + Setting: PVOID, +) -> ULONG} +pub type PDEVICE_NOTIFY_CALLBACK_ROUTINE = *mut DEVICE_NOTIFY_CALLBACK_ROUTINE; +STRUCT!{struct DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { + Callback: PDEVICE_NOTIFY_CALLBACK_ROUTINE, + Context: PVOID, +}} +pub type PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS = *mut DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS; +extern "system" { + pub fn PowerIsSettingRangeDefined( + SubKeyGuid: *const GUID, + SettingGuid: *const GUID, + ) -> BOOLEAN; + pub fn PowerSettingAccessCheckEx( + AccessFlags: POWER_DATA_ACCESSOR, + PowerGuid: *const GUID, + AccessType: REGSAM, + ) -> DWORD; + pub fn PowerSettingAccessCheck( + AccessFlags: POWER_DATA_ACCESSOR, + PowerGuid: *const GUID, + ) -> DWORD; + pub fn PowerReadACValueIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + AcValueIndex: LPDWORD, + ) -> DWORD; + pub fn PowerReadDCValueIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + DcValueIndex: LPDWORD, + ) -> DWORD; + pub fn PowerReadFriendlyName( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadDescription( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadPossibleValue( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Type: PULONG, + PossibleSettingIndex: ULONG, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadPossibleFriendlyName( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + PossibleSettingIndex: ULONG, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadPossibleDescription( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + PossibleSettingIndex: ULONG, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadValueMin( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueMinimum: LPDWORD, + ) -> DWORD; + pub fn PowerReadValueMax( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueMaximum: LPDWORD, + ) -> DWORD; + pub fn PowerReadValueIncrement( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueIncrement: LPDWORD, + ) -> DWORD; + pub fn PowerReadValueUnitsSpecifier( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: *mut UCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadACDefaultIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + AcDefaultIndex: LPDWORD, + ) -> DWORD; + pub fn PowerReadDCDefaultIndex( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + DcDefaultIndex: LPDWORD, + ) -> DWORD; + pub fn PowerReadIconResourceSpecifier( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: PUCHAR, + BufferSize: LPDWORD, + ) -> DWORD; + pub fn PowerReadSettingAttributes( + SubGroupGuid: *const GUID, + PowerSettingGuid: *const GUID, + ) -> DWORD; + pub fn PowerWriteFriendlyName( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWriteDescription( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWritePossibleValue( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Type: ULONG, + PossibleSettingIndex: ULONG, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWritePossibleFriendlyName( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + PossibleSettingIndex: ULONG, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWritePossibleDescription( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + PossibleSettingIndex: ULONG, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWriteValueMin( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueMinimum: DWORD, + ) -> DWORD; + pub fn PowerWriteValueMax( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueMaximum: DWORD, + ) -> DWORD; + pub fn PowerWriteValueIncrement( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ValueIncrement: DWORD, + ) -> DWORD; + pub fn PowerWriteValueUnitsSpecifier( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWriteACDefaultIndex( + RootSystemPowerKey: HKEY, + SchemePersonalityGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + DefaultAcIndex: DWORD, + ) -> DWORD; + pub fn PowerWriteDCDefaultIndex( + RootSystemPowerKey: HKEY, + SchemePersonalityGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + DefaultDcIndex: DWORD, + ) -> DWORD; + pub fn PowerWriteIconResourceSpecifier( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + Buffer: *mut UCHAR, + BufferSize: DWORD, + ) -> DWORD; + pub fn PowerWriteSettingAttributes( + SubGroupGuid: *const GUID, + PowerSettingGuid: *const GUID, + Attributes: DWORD, + ) -> DWORD; + pub fn PowerDuplicateScheme( + RootPowerKey: HKEY, + SourceSchemeGuid: *const GUID, + DestinationSchemeGuid: *mut *mut GUID, + ) -> DWORD; + pub fn PowerImportPowerScheme( + RootPowerKey: HKEY, + ImportFileNamePath: LPCWSTR, + DestinationSchemeGuid: *mut *mut GUID, + ) -> DWORD; + pub fn PowerDeleteScheme( + RootPowerKey: HKEY, + SchemeGuid: *mut GUID, + ) -> DWORD; + pub fn PowerRemovePowerSetting( + PowerSettingSubKeyGuid: *const GUID, + PowerSettingGuid: *const GUID, + ) -> DWORD; + pub fn PowerCreateSetting( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + ) -> DWORD; + pub fn PowerCreatePossibleSetting( + RootPowerKey: HKEY, + SubGroupOfPowerSettingsGuid: *const GUID, + PowerSettingGuid: *const GUID, + PossibleSettingIndex: ULONG, + ) -> DWORD; + pub fn PowerEnumerate( + RootPowerKey: HKEY, + SchemeGuid: *const GUID, + SubGroupOfPowerSettingsGuid: *const GUID, + AccessFlags: POWER_DATA_ACCESSOR, + Index: ULONG, + Buffer: *mut UCHAR, + BufferSize: *mut DWORD, + ) -> DWORD; + pub fn PowerOpenUserPowerKey( + phUserPowerKey: *mut HKEY, + Access: REGSAM, + OpenExisting: BOOL, + ) -> DWORD; + pub fn PowerOpenSystemPowerKey( + phSystemPowerKey: *mut HKEY, + Access: REGSAM, + OpenExisting: BOOL, + ) -> DWORD; + pub fn PowerCanRestoreIndividualDefaultPowerScheme( + SchemeGuid: *const GUID, + ) -> DWORD; + pub fn PowerRestoreIndividualDefaultPowerScheme( + SchemeGuid: *const GUID, + ) -> DWORD; + pub fn PowerRestoreDefaultPowerSchemes() -> DWORD; + pub fn PowerReplaceDefaultPowerSchemes() -> DWORD; + pub fn PowerDeterminePlatformRole() -> POWER_PLATFORM_ROLE; +} +pub const DEVICEPOWER_HARDWAREID: ULONG = 0x80000000; +pub const DEVICEPOWER_AND_OPERATION: ULONG = 0x40000000; +pub const DEVICEPOWER_FILTER_DEVICES_PRESENT: ULONG = 0x20000000; +pub const DEVICEPOWER_FILTER_HARDWARE: ULONG = 0x10000000; +pub const DEVICEPOWER_FILTER_WAKEENABLED: ULONG = 0x08000000; +pub const DEVICEPOWER_FILTER_WAKEPROGRAMMABLE: ULONG = 0x04000000; +pub const DEVICEPOWER_FILTER_ON_NAME: ULONG = 0x02000000; +pub const DEVICEPOWER_SET_WAKEENABLED: ULONG = 0x00000001; +pub const DEVICEPOWER_CLEAR_WAKEENABLED: ULONG = 0x00000002; +pub const PDCAP_S0_SUPPORTED: ULONG = 0x00010000; +pub const PDCAP_S1_SUPPORTED: ULONG = 0x00020000; +pub const PDCAP_S2_SUPPORTED: ULONG = 0x00040000; +pub const PDCAP_S3_SUPPORTED: ULONG = 0x00080000; +pub const PDCAP_WAKE_FROM_S0_SUPPORTED: ULONG = 0x00100000; +pub const PDCAP_WAKE_FROM_S1_SUPPORTED: ULONG = 0x00200000; +pub const PDCAP_WAKE_FROM_S2_SUPPORTED: ULONG = 0x00400000; +pub const PDCAP_WAKE_FROM_S3_SUPPORTED: ULONG = 0x00800000; +pub const PDCAP_S4_SUPPORTED: ULONG = 0x01000000; +pub const PDCAP_S5_SUPPORTED: ULONG = 0x02000000; +extern "system" { + pub fn DevicePowerEnumDevices( + QueryIndex: ULONG, + QueryInterpretationFlags: ULONG, + QueryFlags: ULONG, + pReturnBuffer: PBYTE, + pBufferSize: PULONG, + ) -> BOOLEAN; + pub fn DevicePowerSetDeviceState( + DeviceDescription: LPCWSTR, + SetFlags: ULONG, + SetData: PVOID, + ) -> DWORD; + pub fn DevicePowerOpen( + DebugMask: ULONG, + ) -> BOOLEAN; + pub fn DevicePowerClose() -> BOOLEAN; +} +STRUCT!{struct THERMAL_EVENT { + Version: ULONG, + Size: ULONG, + Type: ULONG, + Temperature: ULONG, + TripPointTemperature: ULONG, + Initiator: LPWSTR, +}} +pub type PTHERMAL_EVENT = *mut THERMAL_EVENT; +extern "system" { + pub fn PowerReportThermalEvent( + Event: PTHERMAL_EVENT, + ) -> DWORD; +} diff --git a/winapi/src/um/processenv.rs b/winapi/src/um/processenv.rs new file mode 100644 index 000000000..8ecb5e0e9 --- /dev/null +++ b/winapi/src/um/processenv.rs @@ -0,0 +1,98 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD}; +use um::winnt::{HANDLE, LPCH, LPCSTR, LPCWSTR, LPSTR, LPWCH, LPWSTR, PHANDLE}; +extern "system" { + pub fn GetEnvironmentStrings() -> LPCH; + pub fn GetEnvironmentStringsW() -> LPWCH; + pub fn SetEnvironmentStringsW( + NewEnvironment: LPWCH, + ) -> BOOL; + pub fn FreeEnvironmentStringsA( + penv: LPCH, + ) -> BOOL; + pub fn FreeEnvironmentStringsW( + penv: LPWCH, + ) -> BOOL; + pub fn GetStdHandle( + nStdHandle: DWORD, + ) -> HANDLE; + pub fn SetStdHandle( + nStdHandle: DWORD, + hHandle: HANDLE, + ) -> BOOL; + pub fn SetStdHandleEx( + nStdHandle: DWORD, + hHandle: HANDLE, + phPrevValue: PHANDLE, + ) -> BOOL; + pub fn GetCommandLineA() -> LPSTR; + pub fn GetCommandLineW() -> LPWSTR; + pub fn GetEnvironmentVariableA( + lpName: LPCSTR, + lpBuffer: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetEnvironmentVariableW( + lpName: LPCWSTR, + lpBuffer: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn SetEnvironmentVariableA( + lpName: LPCSTR, + lpValue: LPCSTR, + ) -> BOOL; + pub fn SetEnvironmentVariableW( + lpName: LPCWSTR, + lpValue: LPCWSTR, + ) -> BOOL; + pub fn ExpandEnvironmentStringsA( + lpSrc: LPCSTR, + lpDst: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn ExpandEnvironmentStringsW( + lpSrc: LPCWSTR, + lpDst: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn SetCurrentDirectoryA( + lpPathName: LPCSTR, + ) -> BOOL; + pub fn SetCurrentDirectoryW( + lpPathName: LPCWSTR, + ) -> BOOL; + pub fn GetCurrentDirectoryA( + nBufferLength: DWORD, + lpBuffer: LPSTR, + ) -> DWORD; + pub fn GetCurrentDirectoryW( + nBufferLength: DWORD, + lpBuffer: LPWSTR, + ) -> DWORD; + pub fn SearchPathW( + lpPath: LPCWSTR, + lpFileName: LPCWSTR, + lpExtension: LPCWSTR, + nBufferLength: DWORD, + lpBuffer: LPWSTR, + lpFilePart: *mut LPWSTR, + ) -> DWORD; + pub fn SearchPathA( + lpPath: LPCSTR, + lpFileName: LPCSTR, + lpExtension: LPCSTR, + nBufferLength: DWORD, + lpBuffer: LPSTR, + lpFilePart: *mut LPSTR, + ) -> DWORD; + pub fn NeedCurrentDirectoryForExePathA( + ExeName: LPCSTR, + ) -> BOOL; + pub fn NeedCurrentDirectoryForExePathW( + ExeName: LPCWSTR, + ) -> BOOL; +} diff --git a/winapi/src/um/processsnapshot.rs b/winapi/src/um/processsnapshot.rs new file mode 100644 index 000000000..c49aac6a9 --- /dev/null +++ b/winapi/src/um/processsnapshot.rs @@ -0,0 +1,120 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Defines the process snapshot API +use ctypes::c_void; +use shared::basetsd::ULONG_PTR; +use shared::minwindef::DWORD; +use um::winnt::HANDLE; +ENUM!{enum PSS_CAPTURE_FLAGS { + PSS_CAPTURE_NONE = 0x00000000, + PSS_CAPTURE_VA_CLONE = 0x00000001, + PSS_CAPTURE_RESERVED_00000002 = 0x00000002, + PSS_CAPTURE_HANDLES = 0x00000004, + PSS_CAPTURE_HANDLE_NAME_INFORMATION = 0x00000008, + PSS_CAPTURE_HANDLE_BASIC_INFORMATION = 0x00000010, + PSS_CAPTURE_HANDLE_TYPE_SPECIFIC_INFORMATION = 0x00000020, + PSS_CAPTURE_HANDLE_TRACE = 0x00000040, + PSS_CAPTURE_THREADS = 0x00000080, + PSS_CAPTURE_THREAD_CONTEXT = 0x00000100, + PSS_CAPTURE_THREAD_CONTEXT_EXTENDED = 0x00000200, + PSS_CAPTURE_RESERVED_00000400 = 0x00000400, + PSS_CAPTURE_VA_SPACE = 0x00000800, + PSS_CAPTURE_VA_SPACE_SECTION_INFORMATION = 0x00001000, + PSS_CREATE_BREAKAWAY_OPTIONAL = 0x04000000, + PSS_CREATE_BREAKAWAY = 0x08000000, + PSS_CREATE_FORCE_BREAKAWAY = 0x10000000, + PSS_CREATE_USE_VM_ALLOCATIONS = 0x20000000, + PSS_CREATE_MEASURE_PERFORMANCE = 0x40000000, + PSS_CREATE_RELEASE_SECTION = 0x80000000, +}} +ENUM!{enum PSS_QUERY_INFORMATION_CLASS { + PSS_QUERY_PROCESS_INFORMATION = 0, + PSS_QUERY_VA_CLONE_INFORMATION = 1, + PSS_QUERY_AUXILIARY_PAGES_INFORMATION = 2, + PSS_QUERY_VA_SPACE_INFORMATION = 3, + PSS_QUERY_HANDLE_INFORMATION = 4, + PSS_QUERY_THREAD_INFORMATION = 5, + PSS_QUERY_HANDLE_TRACE_INFORMATION = 6, + PSS_QUERY_PERFORMANCE_COUNTERS = 7, +}} +ENUM!{enum PSS_WALK_INFORMATION_CLASS { + PSS_WALK_AUXILIARY_PAGES = 0, + PSS_WALK_VA_SPACE = 1, + PSS_WALK_HANDLES = 2, + PSS_WALK_THREADS = 3, +}} +ENUM!{enum PSS_DUPLICATE_FLAGS { + PSS_DUPLICATE_NONE = 0x00, + PSS_DUPLICATE_CLOSE_SOURCE = 0x01, +}} +DECLARE_HANDLE!{HPSS, HPSS__} +DECLARE_HANDLE!{HPSSWALK, HPSSWALK__} +FN!{stdcall pAllocRoutine( + Context: *mut c_void, + Size: DWORD, +) -> *mut c_void} +FN!{stdcall pFreeRoutine( + Context: *mut c_void, + Address: *mut c_void, +) -> ()} +STRUCT!{struct PSS_ALLOCATOR { + Context: *mut c_void, + AllocRoutine: pAllocRoutine, + FreeRoutine: pFreeRoutine, +}} +extern "system" { + pub fn PssCaptureSnapshot( + ProcessHandle: HANDLE, + CaptureFlags: PSS_CAPTURE_FLAGS, + ThreadContextFlags: DWORD, + SnapshotHandle: *mut HPSS, + ) -> DWORD; + pub fn PssDuplicateSnapshot( + SourceProcessHandle: HANDLE, + SnapshotHandle: HPSS, + TargetProcessHandle: HANDLE, + TargetSnapshotHandle: *mut HPSS, + Flags: PSS_DUPLICATE_FLAGS, + ) -> DWORD; + pub fn PssFreeSnapshot( + ProcessHandle: HANDLE, + SnapshotHandle: HPSS, + ) -> DWORD; + pub fn PssQuerySnapshot( + SnapshotHandle: HPSS, + InformationClass: PSS_QUERY_INFORMATION_CLASS, + Buffer: *mut c_void, + BufferLength: DWORD, + ) -> DWORD; + pub fn PssWalkMarkerCreate( + Allocator: *const PSS_ALLOCATOR, + WalkMarkerHandle: *mut HPSSWALK, + ) -> DWORD; + pub fn PssWalkMarkerFree( + WalkMarkerHandle: HPSSWALK, + ) -> DWORD; + pub fn PssWalkMarkerGetPosition( + WalkMarkerHandle: HPSSWALK, + Position: *mut ULONG_PTR, + ) -> DWORD; + // pub fn PssWalkMarkerRewind(); + // pub fn PssWalkMarkerSeek(); + pub fn PssWalkMarkerSeekToBeginning( + WalkMarkerHandle: HPSS, + ) -> DWORD; + pub fn PssWalkMarkerSetPosition( + WalkMarkerHandle: HPSSWALK, + Position: ULONG_PTR, + ) -> DWORD; + // pub fn PssWalkMarkerTell(); + pub fn PssWalkSnapshot( + SnapshotHandle: HPSS, + InformationClass: PSS_WALK_INFORMATION_CLASS, + WalkMarkerHandle: HPSSWALK, + Buffer: *mut c_void, + BufferLength: DWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/processthreadsapi.rs b/winapi/src/um/processthreadsapi.rs new file mode 100644 index 000000000..9629ee865 --- /dev/null +++ b/winapi/src/um/processthreadsapi.rs @@ -0,0 +1,441 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! ApiSet Contract for api-ms-win-core-processthreads-l1 +use ctypes::{c_int, c_void}; +use shared::basetsd::{DWORD_PTR, PSIZE_T, PULONG_PTR, SIZE_T, ULONG_PTR}; +use shared::guiddef::LPCGUID; +use shared::minwindef::{ + BOOL, DWORD, LPBYTE, LPCVOID, LPDWORD, LPFILETIME, LPVOID, PBOOL, PDWORD, PULONG, UINT, WORD +}; +use um::minwinbase::{LPCONTEXT, LPSECURITY_ATTRIBUTES, LPTHREAD_START_ROUTINE}; +use um::winnt::{ + CONTEXT, HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PAPCFUNC, PHANDLE, PPROCESSOR_NUMBER, + PROCESS_MITIGATION_POLICY, PVOID +}; +STRUCT!{struct PROCESS_INFORMATION { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD, +}} +pub type PPROCESS_INFORMATION = *mut PROCESS_INFORMATION; +pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; +STRUCT!{struct STARTUPINFOA { + cb: DWORD, + lpReserved: LPSTR, + lpDesktop: LPSTR, + lpTitle: LPSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountChars: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE, +}} +pub type LPSTARTUPINFOA = *mut STARTUPINFOA; +STRUCT!{struct STARTUPINFOW { + cb: DWORD, + lpReserved: LPWSTR, + lpDesktop: LPWSTR, + lpTitle: LPWSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountChars: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE, +}} +pub type LPSTARTUPINFOW = *mut STARTUPINFOW; +extern "system" { + pub fn QueueUserAPC( + pfnAPC: PAPCFUNC, + hThread: HANDLE, + dwData: ULONG_PTR, + ) -> DWORD; + pub fn GetProcessTimes( + hProcess: HANDLE, + lpCreationTime: LPFILETIME, + lpExitTime: LPFILETIME, + lpKernelTime: LPFILETIME, + lpUserTime: LPFILETIME, + ) -> BOOL; + pub fn GetCurrentProcess() -> HANDLE; + pub fn GetCurrentProcessId() -> DWORD; + pub fn ExitProcess( + uExitCode: UINT, + ); + pub fn TerminateProcess( + hProcess: HANDLE, + uExitCode: UINT, + ) -> BOOL; + pub fn GetExitCodeProcess( + hProcess: HANDLE, + lpExitCode: LPDWORD, + ) -> BOOL; + pub fn SwitchToThread() -> BOOL; + pub fn CreateThread( + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + dwStackSize: SIZE_T, + lpStartAddress: LPTHREAD_START_ROUTINE, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpThreadId: LPDWORD, + ) -> HANDLE; + pub fn CreateRemoteThread( + hProcess: HANDLE, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + dwStackSize: SIZE_T, + lpStartAddress: LPTHREAD_START_ROUTINE, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpThreadId: LPDWORD, + ) -> HANDLE; + pub fn GetCurrentThread() -> HANDLE; + pub fn GetCurrentThreadId() -> DWORD; + pub fn OpenThread( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwThreadId: DWORD, + ) -> HANDLE; + pub fn SetThreadPriority( + hThread: HANDLE, + nPriority: c_int, + ) -> BOOL; + pub fn SetThreadPriorityBoost( + hThread: HANDLE, + bDisablePriorityBoost: BOOL, + ) -> BOOL; + pub fn GetThreadPriorityBoost( + hThread: HANDLE, + pDisablePriorityBoost: PBOOL, + ) -> BOOL; + pub fn GetThreadPriority( + hThread: HANDLE, + ) -> c_int; + pub fn ExitThread( + dwExitCode: DWORD, + ); + pub fn TerminateThread( + hThread: HANDLE, + dwExitCode: DWORD, + ) -> BOOL; + pub fn GetExitCodeThread( + hThread: HANDLE, + lpExitCode: LPDWORD, + ) -> BOOL; + pub fn SuspendThread( + hThread: HANDLE, + ) -> DWORD; + pub fn ResumeThread( + hThread: HANDLE, + ) -> DWORD; +} +pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; +extern "system" { + pub fn TlsAlloc() -> DWORD; + pub fn TlsGetValue( + dwTlsIndex: DWORD, + ) -> LPVOID; + pub fn TlsSetValue( + dwTlsIndex: DWORD, + lpTlsValue: LPVOID, + ) -> BOOL; + pub fn TlsFree( + dwTlsIndex: DWORD, + ) -> BOOL; + pub fn CreateProcessA( + lpApplicationName: LPCSTR, + lpCommandLine: LPSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCSTR, + lpStartupInfo: LPSTARTUPINFOA, + lpProcessInformation: LPPROCESS_INFORMATION, + ) -> BOOL; + pub fn CreateProcessW( + lpApplicationName: LPCWSTR, + lpCommandLine: LPWSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCWSTR, + lpStartupInfo: LPSTARTUPINFOW, + lpProcessInformation: LPPROCESS_INFORMATION, + ) -> BOOL; + pub fn SetProcessShutdownParameters( + dwLevel: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn GetProcessVersion( + ProcessId: DWORD, + ) -> DWORD; + pub fn GetStartupInfoW( + lpStartupInfo: LPSTARTUPINFOW, + ); + pub fn CreateProcessAsUserW( + hToken: HANDLE, + lpApplicationName: LPCWSTR, + lpCommandLine: LPWSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCWSTR, + lpStartupInfo: LPSTARTUPINFOW, + lpProcessInformation: LPPROCESS_INFORMATION, + ) -> BOOL; + // pub fn GetCurrentProcessToken(); + // pub fn GetCurrentThreadToken(); + // pub fn GetCurrentThreadEffectiveToken(); + pub fn SetThreadToken( + Thread: PHANDLE, + Token: HANDLE, + ) -> BOOL; + pub fn OpenProcessToken( + ProcessHandle: HANDLE, + DesiredAccess: DWORD, + TokenHandle: PHANDLE, + ) -> BOOL; + pub fn OpenThreadToken( + ThreadHandle: HANDLE, + DesiredAccess: DWORD, + OpenAsSelf: BOOL, + TokenHandle: PHANDLE, + ) -> BOOL; + pub fn SetPriorityClass( + hProcess: HANDLE, + dwPriorityClass: DWORD, + ) -> BOOL; + pub fn SetThreadStackGuarantee( + StackSizeInBytes: PULONG, + ) -> BOOL; + pub fn GetPriorityClass( + hProcess: HANDLE, + ) -> DWORD; + pub fn ProcessIdToSessionId( + dwProcessId: DWORD, + pSessionId: *mut DWORD, + ) -> BOOL; + pub fn GetProcessId( + Process: HANDLE, + ) -> DWORD; +} +STRUCT!{struct PROC_THREAD_ATTRIBUTE_LIST { + dummy: *mut c_void, +}} +pub type PPROC_THREAD_ATTRIBUTE_LIST = *mut PROC_THREAD_ATTRIBUTE_LIST; +pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut PROC_THREAD_ATTRIBUTE_LIST; +extern "system" { + pub fn GetThreadId( + Thread: HANDLE, + ) -> DWORD; + pub fn FlushProcessWriteBuffers(); + pub fn GetProcessIdOfThread( + Thread: HANDLE, + ) -> DWORD; + pub fn InitializeProcThreadAttributeList( + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, + dwAttributeCount: DWORD, + dwFlags: DWORD, + lpSize: PSIZE_T, + ) -> BOOL; + pub fn DeleteProcThreadAttributeList( + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, + ); + pub fn SetProcessAffinityUpdateMode( + hProcess: HANDLE, + dwFlags: DWORD, + ) -> BOOL; + pub fn QueryProcessAffinityUpdateMode( + hProcess: HANDLE, + lpdwFlags: LPDWORD, + ) -> BOOL; + pub fn UpdateProcThreadAttribute( + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, + dwFlags: DWORD, + Attribute: DWORD_PTR, + lpValue: PVOID, + cbSize: SIZE_T, + lpPreviousValue: PVOID, + lpReturnSize: PSIZE_T, + ) -> BOOL; + pub fn CreateRemoteThreadEx( + hProcess: HANDLE, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + dwStackSize: SIZE_T, + lpStartAddress: LPTHREAD_START_ROUTINE, + lpParameter: LPVOID, + dwCreationFlags: DWORD, + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, + lpThreadId: LPDWORD, + ) -> HANDLE; + pub fn GetCurrentThreadStackLimits( + LowLimit: PULONG_PTR, + HighLimit: PULONG_PTR, + ); + pub fn GetThreadContext( + hThread: HANDLE, + lpContext: LPCONTEXT, + ) -> BOOL; + pub fn SetThreadContext( + hThread: HANDLE, + lpContext: *const CONTEXT, + ) -> BOOL; + pub fn SetProcessMitigationPolicy( + MitigationPolicy: PROCESS_MITIGATION_POLICY, + lpBuffer: PVOID, + dwLength: SIZE_T, + ) -> BOOL; + pub fn GetProcessMitigationPolicy( + hProcess: HANDLE, + MitigationPolicy: PROCESS_MITIGATION_POLICY, + lpBuffer: PVOID, + dwLength: SIZE_T, + ) -> BOOL; + pub fn FlushInstructionCache( + hProcess: HANDLE, + lpBaseAddress: LPCVOID, + dwSize: SIZE_T, + ) -> BOOL; + pub fn GetThreadTimes( + hThread: HANDLE, + lpCreationTime: LPFILETIME, + lpExitTime: LPFILETIME, + lpKernelTime: LPFILETIME, + lpUserTime: LPFILETIME, + ) -> BOOL; + pub fn OpenProcess( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD, + ) -> HANDLE; + pub fn IsProcessorFeaturePresent( + ProcessorFeature: DWORD, + ) -> BOOL; + pub fn GetProcessHandleCount( + hProcess: HANDLE, + pdwHandleCount: PDWORD, + ) -> BOOL; + pub fn GetCurrentProcessorNumber() -> DWORD; + pub fn SetThreadIdealProcessorEx( + hThread: HANDLE, + lpIdealProcessor: PPROCESSOR_NUMBER, + lpPreviousIdealProcessor: PPROCESSOR_NUMBER, + ) -> BOOL; + pub fn GetThreadIdealProcessorEx( + hThread: HANDLE, + lpIdealProcessor: PPROCESSOR_NUMBER, + ) -> BOOL; + pub fn GetCurrentProcessorNumberEx( + ProcNumber: PPROCESSOR_NUMBER, + ); + pub fn GetProcessPriorityBoost( + hProcess: HANDLE, + pDisablePriorityBoost: PBOOL, + ) -> BOOL; + pub fn SetProcessPriorityBoost( + hProcess: HANDLE, + bDisablePriorityBoost: BOOL, + ) -> BOOL; + pub fn GetThreadIOPendingFlag( + hThread: HANDLE, + lpIOIsPending: PBOOL, + ) -> BOOL; + pub fn GetSystemTimes( + lpIdleTime: LPFILETIME, + lpKernelTime: LPFILETIME, + lpUserTime: LPFILETIME, + ) -> BOOL; +} +ENUM!{enum THREAD_INFORMATION_CLASS { + ThreadMemoryPriority, + ThreadAbsoluteCpuPriority, + ThreadInformationClassMax, +}} +// MEMORY_PRIORITY_INFORMATION +extern "system" { + pub fn GetThreadInformation( + hThread: HANDLE, + ThreadInformationClass: THREAD_INFORMATION_CLASS, + ThreadInformation: LPVOID, + ThreadInformationSize: DWORD, + ) -> BOOL; + pub fn SetThreadInformation( + hThread: HANDLE, + ThreadInformationClass: THREAD_INFORMATION_CLASS, + ThreadInformation: LPVOID, + ThreadInformationSize: DWORD, + ) -> BOOL; + pub fn IsProcessCritical( + hProcess: HANDLE, + Critical: PBOOL, + ) -> BOOL; + pub fn SetProtectedPolicy( + PolicyGuid: LPCGUID, + PolicyValue: ULONG_PTR, + OldPolicyValue: PULONG_PTR, + ) -> BOOL; + pub fn QueryProtectedPolicy( + PolicyGuid: LPCGUID, + PolicyValue: PULONG_PTR, + ) -> BOOL; + pub fn SetThreadIdealProcessor( + hThread: HANDLE, + dwIdealProcessor: DWORD, + ) -> DWORD; +} +ENUM!{enum PROCESS_INFORMATION_CLASS { + ProcessMemoryPriority, + ProcessInformationClassMax, +}} +extern "system" { + pub fn SetProcessInformation( + hProcess: HANDLE, + ProcessInformationClass: PROCESS_INFORMATION_CLASS, + ProcessInformation: LPVOID, + ProcessInformationSize: DWORD, + ) -> BOOL; + pub fn GetProcessInformation( + hProcess: HANDLE, + ProcessInformationClass: PROCESS_INFORMATION_CLASS, + ProcessInformation: LPVOID, + ProcessInformationSize: DWORD, + ) -> BOOL; + // pub fn GetSystemCpuSetInformation(); + // pub fn GetProcessDefaultCpuSets(); + // pub fn SetProcessDefaultCpuSets(); + // pub fn GetThreadSelectedCpuSets(); + // pub fn SetThreadSelectedCpuSets(); + // pub fn CreateProcessAsUserA(); + pub fn GetProcessShutdownParameters( + lpdwLevel: LPDWORD, + lpdwFlags: LPDWORD, + ) -> BOOL; + // pub fn SetThreadDescription(); + // pub fn GetThreadDescription(); +} diff --git a/winapi/src/um/processtopologyapi.rs b/winapi/src/um/processtopologyapi.rs new file mode 100644 index 000000000..694f0762a --- /dev/null +++ b/winapi/src/um/processtopologyapi.rs @@ -0,0 +1,23 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, PUSHORT}; +use um::winnt::{GROUP_AFFINITY, HANDLE, PGROUP_AFFINITY}; +extern "system" { + pub fn GetProcessGroupAffinity( + hProcess: HANDLE, + GroupCount: PUSHORT, + GroupArray: PUSHORT, + ) -> BOOL; + pub fn GetThreadGroupAffinity( + hThread: HANDLE, + GroupAffinity: PGROUP_AFFINITY, + ) -> BOOL; + pub fn SetThreadGroupAffinity( + hThread: HANDLE, + GroupAffinity: *const GROUP_AFFINITY, + PreviousGroupAffinity: PGROUP_AFFINITY, + ) -> BOOL; +} diff --git a/winapi/src/um/profileapi.rs b/winapi/src/um/profileapi.rs new file mode 100644 index 000000000..908457592 --- /dev/null +++ b/winapi/src/um/profileapi.rs @@ -0,0 +1,15 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::BOOL; +use um::winnt::LARGE_INTEGER; +extern "system" { + pub fn QueryPerformanceCounter( + lpPerformanceCount: *mut LARGE_INTEGER, + ) -> BOOL; + pub fn QueryPerformanceFrequency( + lpFrequency: *mut LARGE_INTEGER, + ) -> BOOL; +} diff --git a/winapi/src/um/propidl.rs b/winapi/src/um/propidl.rs new file mode 100644 index 000000000..233c0f28b --- /dev/null +++ b/winapi/src/um/propidl.rs @@ -0,0 +1,15 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::WORD; +use shared::wtypes::VARTYPE; +STRUCT!{struct PROPVARIANT { + vt: VARTYPE, + wReserved1: WORD, + wReserved2: WORD, + wReserved3: WORD, + data: [u8; 16], +}} +pub type REFPROPVARIANT = *const PROPVARIANT; diff --git a/winapi/src/um/propkeydef.rs b/winapi/src/um/propkeydef.rs new file mode 100644 index 000000000..bc0924c76 --- /dev/null +++ b/winapi/src/um/propkeydef.rs @@ -0,0 +1,13 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +use shared::guiddef::IsEqualIID; +use shared::wtypes::{PROPERTYKEY, PROPID}; +pub const PID_FIRST_USABLE: PROPID = 2; +pub type REFPROPERTYKEY = *const PROPERTYKEY; +#[inline] +pub fn IsEqualPropertyKey(a: &PROPERTYKEY, b: &PROPERTYKEY) -> bool { + (a.pid == b.pid) && IsEqualIID(&a.fmtid, &b.fmtid) +} diff --git a/winapi/src/um/propsys.rs b/winapi/src/um/propsys.rs new file mode 100644 index 000000000..9a4f6a0ff --- /dev/null +++ b/winapi/src/um/propsys.rs @@ -0,0 +1,46 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::DWORD; +use shared::wtypes::PROPERTYKEY; +use um::propidl::{PROPVARIANT, REFPROPVARIANT}; +use um::propkeydef::REFPROPERTYKEY; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +pub type IPropertyDescriptionList = IUnknown; // TODO +RIDL!{#[uuid(0x886d8eeb, 0x8cf2, 0x4446, 0x8d, 0x02, 0xcd, 0xba, 0x1d, 0xbd, 0xcf, 0x99)] +interface IPropertyStore(IPropertyStoreVtbl): IUnknown(IUnknownVtbl) { + fn GetCount( + cProps: *mut DWORD, + ) -> HRESULT, + fn GetAt( + iProp: DWORD, + pkey: *mut PROPERTYKEY, + ) -> HRESULT, + fn GetValue( + key: REFPROPERTYKEY, + pv: *mut PROPVARIANT, + ) -> HRESULT, + fn SetValue( + key: REFPROPERTYKEY, + propvar: REFPROPVARIANT, + ) -> HRESULT, + fn Commit() -> HRESULT, +}} +ENUM!{enum GETPROPERTYSTOREFLAGS { + GPS_DEFAULT = 0, + GPS_HANDLERPROPERTIESONLY = 0x1, + GPS_READWRITE = 0x2, + GPS_TEMPORARY = 0x4, + GPS_FASTPROPERTIESONLY = 0x8, + GPS_OPENSLOWITEM = 0x10, + GPS_DELAYCREATION = 0x20, + GPS_BESTEFFORT = 0x40, + GPS_NO_OPLOCK = 0x80, + GPS_PREFERQUERYPROPERTIES = 0x100, + GPS_EXTRINSICPROPERTIES = 0x200, + GPS_EXTRINSICPROPERTIESONLY = 0x400, + GPS_MASK_VALID = 0x7ff, +}} diff --git a/winapi/src/um/prsht.rs b/winapi/src/um/prsht.rs new file mode 100644 index 000000000..25cb9262d --- /dev/null +++ b/winapi/src/um/prsht.rs @@ -0,0 +1,361 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Interface for the Windows Property Sheet Pages +use ctypes::{c_int, c_short}; +use shared::basetsd::INT_PTR; +use shared::minwindef::{BOOL, DWORD, HINSTANCE, LPARAM, LPVOID, LRESULT, UINT, WPARAM}; +use shared::windef::{HBITMAP, HICON, HPALETTE, HWND}; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR}; +use um::winuser::{DLGPROC, LPCDLGTEMPLATEA, NMHDR, WM_USER}; +pub enum PSP {} +pub type HPROPSHEETPAGE = *mut PSP; +FN!{stdcall LPFNPSPCALLBACKA( + hwnd: HWND, + uMsg: UINT, + ppsp: *mut PROPSHEETPAGEA, +) -> UINT} +FN!{stdcall LPFNPSPCALLBACKW( + hwnd: HWND, + uMsg: UINT, + ppsp: *mut PROPSHEETPAGEW, +) -> UINT} +pub const PSP_DEFAULT: DWORD = 0x00000000; +pub const PSP_DLGINDIRECT: DWORD = 0x00000001; +pub const PSP_USEHICON: DWORD = 0x00000002; +pub const PSP_USEICONID: DWORD = 0x00000004; +pub const PSP_USETITLE: DWORD = 0x00000008; +pub const PSP_RTLREADING: DWORD = 0x00000010; +pub const PSP_HASHELP: DWORD = 0x00000020; +pub const PSP_USEREFPARENT: DWORD = 0x00000040; +pub const PSP_USECALLBACK: DWORD = 0x00000080; +pub const PSP_PREMATURE: DWORD = 0x00000400; +pub const PSP_HIDEHEADER: DWORD = 0x00000800; +pub const PSP_USEHEADERTITLE: DWORD = 0x00001000; +pub const PSP_USEHEADERSUBTITLE: DWORD = 0x00002000; +pub const PSP_USEFUSIONCONTEXT: DWORD = 0x00004000; +pub const PSPCB_ADDREF: UINT = 0; +pub const PSPCB_RELEASE: UINT = 1; +pub const PSPCB_CREATE: UINT = 2; +pub type PROPSHEETPAGE_RESOURCE = LPCDLGTEMPLATEA; +UNION!{union PROPSHEETPAGEA_V1_u1 { + [usize; 1], + pszTemplate pszTemplate_mut: LPCSTR, + pResource pResource_mut: PROPSHEETPAGE_RESOURCE, +}} +UNION!{union PROPSHEETPAGEA_V1_u2 { + [usize; 1], + hIcon hIcon_mut: HICON, + pszIcon pszIcon_mut: LPCSTR, +}} +UNION!{union PROPSHEETPAGEA_V4_u3 { + [usize; 1], + hbmHeader hbmHeader_mut: HBITMAP, + pszbmHeader pszbmHeader_mut: LPCSTR, +}} +STRUCT!{struct PROPSHEETPAGEA_V4 { + dwSize: DWORD, + dwFlags: DWORD, + hInstance: HINSTANCE, + u1: PROPSHEETPAGEA_V1_u1, + u2: PROPSHEETPAGEA_V1_u2, + pszTitle: LPCSTR, + pfnDlgProc: DLGPROC, + lParam: LPARAM, + pfnCallback: LPFNPSPCALLBACKA, + pcRefParent: *mut UINT, + pszHeaderTitle: LPCSTR, + pszHeaderSubTitle: LPCSTR, + hActCtx: HANDLE, + u3: PROPSHEETPAGEA_V4_u3, +}} +pub type LPPROPSHEETPAGEA_V4 = *mut PROPSHEETPAGEA_V4; +pub type LPCPROPSHEETPAGEA_V4 = *const PROPSHEETPAGEA_V4; +UNION!{union PROPSHEETPAGEW_V1_u1 { + [usize; 1], + pszTemplate pszTemplate_mut: LPCWSTR, + pResource pResource_mut: PROPSHEETPAGE_RESOURCE, +}} +UNION!{union PROPSHEETPAGEW_V1_u2 { + [usize; 1], + hIcon hIcon_mut: HICON, + pszIcon pszIcon_mut: LPCWSTR, +}} +UNION!{union PROPSHEETPAGEW_V4_u3 { + [usize; 1], + hbmHeader hbmHeader_mut: HBITMAP, + pszbmHeader pszbmHeader_mut: LPCWSTR, +}} +STRUCT!{struct PROPSHEETPAGEW_V4 { + dwSize: DWORD, + dwFlags: DWORD, + hInstance: HINSTANCE, + u1: PROPSHEETPAGEW_V1_u1, + u2: PROPSHEETPAGEW_V1_u2, + pszTitle: LPCWSTR, + pfnDlgProc: DLGPROC, + lParam: LPARAM, + pfnCallback: LPFNPSPCALLBACKW, + pcRefParent: *mut UINT, + pszHeaderTitle: LPCWSTR, + pszHeaderSubTitle: LPCWSTR, + hActCtx: HANDLE, + u3: PROPSHEETPAGEW_V4_u3, +}} +pub type LPPROPSHEETPAGEW_V4 = *mut PROPSHEETPAGEW_V4; +pub type LPCPROPSHEETPAGEW_V4 = *const PROPSHEETPAGEW_V4; +pub type PROPSHEETPAGEA_LATEST = PROPSHEETPAGEA_V4; +pub type PROPSHEETPAGEW_LATEST = PROPSHEETPAGEW_V4; +pub type LPPROPSHEETPAGEA_LATEST = LPPROPSHEETPAGEA_V4; +pub type LPPROPSHEETPAGEW_LATEST = LPPROPSHEETPAGEW_V4; +pub type LPCPROPSHEETPAGEA_LATEST = LPCPROPSHEETPAGEA_V4; +pub type LPCPROPSHEETPAGEW_LATEST = LPCPROPSHEETPAGEW_V4; +pub type PROPSHEETPAGEA = PROPSHEETPAGEA_V4; +pub type PROPSHEETPAGEW = PROPSHEETPAGEW_V4; +pub type LPPROPSHEETPAGEA = LPPROPSHEETPAGEA_V4; +pub type LPPROPSHEETPAGEW = LPPROPSHEETPAGEW_V4; +pub type LPCPROPSHEETPAGEA = LPCPROPSHEETPAGEA_V4; +pub type LPCPROPSHEETPAGEW = LPCPROPSHEETPAGEW_V4; +pub const PSH_DEFAULT: DWORD = 0x00000000; +pub const PSH_PROPTITLE: DWORD = 0x00000001; +pub const PSH_USEHICON: DWORD = 0x00000002; +pub const PSH_USEICONID: DWORD = 0x00000004; +pub const PSH_PROPSHEETPAGE: DWORD = 0x00000008; +pub const PSH_WIZARDHASFINISH: DWORD = 0x00000010; +pub const PSH_WIZARD: DWORD = 0x00000020; +pub const PSH_USEPSTARTPAGE: DWORD = 0x00000040; +pub const PSH_NOAPPLYNOW: DWORD = 0x00000080; +pub const PSH_USECALLBACK: DWORD = 0x00000100; +pub const PSH_HASHELP: DWORD = 0x00000200; +pub const PSH_MODELESS: DWORD = 0x00000400; +pub const PSH_RTLREADING: DWORD = 0x00000800; +pub const PSH_WIZARDCONTEXTHELP: DWORD = 0x00001000; +pub const PSH_WIZARD97: DWORD = 0x01000000; +pub const PSH_WATERMARK: DWORD = 0x00008000; +pub const PSH_USEHBMWATERMARK: DWORD = 0x00010000; +pub const PSH_USEHPLWATERMARK: DWORD = 0x00020000; +pub const PSH_STRETCHWATERMARK: DWORD = 0x00040000; +pub const PSH_HEADER: DWORD = 0x00080000; +pub const PSH_USEHBMHEADER: DWORD = 0x00100000; +pub const PSH_USEPAGELANG: DWORD = 0x00200000; +pub const PSH_WIZARD_LITE: DWORD = 0x00400000; +pub const PSH_NOCONTEXTHELP: DWORD = 0x02000000; +pub const PSH_AEROWIZARD: DWORD = 0x00004000; +pub const PSH_RESIZABLE: DWORD = 0x04000000; +pub const PSH_HEADERBITMAP: DWORD = 0x08000000; +pub const PSH_NOMARGIN: DWORD = 0x10000000; +FN!{stdcall PFNPROPSHEETCALLBACK( + HWND, + UINT, + LPARAM, +) -> c_int} +UNION!{union PROPSHEETHEADERA_V1_u1 { + [usize; 1], + hIcon hIcon_mut: HICON, + pszIcon pszIcon_mut: LPCSTR, +}} +UNION!{union PROPSHEETHEADERA_V1_u2 { + [usize; 1], + nStartPage nStartPage_mut: UINT, + pStartPage pStartPage_mut: LPCSTR, +}} +UNION!{union PROPSHEETHEADERA_V1_u3 { + [usize; 1], + ppsp ppsp_mut: LPCPROPSHEETPAGEA, + phpage phpage_mut: *mut HPROPSHEETPAGE, +}} +UNION!{union PROPSHEETHEADERA_V2_u4 { + [usize; 1], + hbmWatermark hbmWatermark_mut: HBITMAP, + pszbmWatermark pszbmWatermark_mut: LPCSTR, +}} +UNION!{union PROPSHEETHEADERA_V2_u5 { + [usize; 1], + hbmHeader hbmHeader_mut: HBITMAP, + pszbmHeader pszbmHeader_mut: LPCSTR, +}} +STRUCT!{struct PROPSHEETHEADERA_V2 { + dwSize: DWORD, + dwFlags: DWORD, + hwndParent: HWND, + hInstance: HINSTANCE, + u1: PROPSHEETHEADERA_V1_u1, + pszCaption: LPCSTR, + nPages: UINT, + u2: PROPSHEETHEADERA_V1_u2, + u3: PROPSHEETHEADERA_V1_u3, + pfnCallback: PFNPROPSHEETCALLBACK, + u4: PROPSHEETHEADERA_V2_u4, + hplWatermark: HPALETTE, + u5: PROPSHEETHEADERA_V2_u5, +}} +pub type LPPROPSHEETHEADERA_V2 = *mut PROPSHEETHEADERA_V2; +pub type LPCPROPSHEETHEADERA_V2 = *const PROPSHEETHEADERA_V2; +UNION!{union PROPSHEETHEADERW_V1_u1 { + [usize; 1], + hIcon hIcon_mut: HICON, + pszIcon pszIcon_mut: LPCWSTR, +}} +UNION!{union PROPSHEETHEADERW_V1_u2 { + [usize; 1], + nStartPage nStartPage_mut: UINT, + pStartPage pStartPage_mut: LPCWSTR, +}} +UNION!{union PROPSHEETHEADERW_V1_u3 { + [usize; 1], + ppsp ppsp_mut: LPCPROPSHEETPAGEW, + phpage phpage_mut: *mut HPROPSHEETPAGE, +}} +UNION!{union PROPSHEETHEADERW_V2_u4 { + [usize; 1], + hbmWatermark hbmWatermark_mut: HBITMAP, + pszbmWatermark pszbmWatermark_mut: LPCWSTR, +}} +UNION!{union PROPSHEETHEADERW_V2_u5 { + [usize; 1], + hbmHeader hbmHeader_mut: HBITMAP, + pszbmHeader pszbmHeader_mut: LPCWSTR, +}} +STRUCT!{struct PROPSHEETHEADERW_V2 { + dwSize: DWORD, + dwFlags: DWORD, + hwndParent: HWND, + hInstance: HINSTANCE, + u1: PROPSHEETHEADERW_V1_u1, + pszCaption: LPCWSTR, + nPages: UINT, + u2: PROPSHEETHEADERW_V1_u2, + u3: PROPSHEETHEADERW_V1_u3, + pfnCallback: PFNPROPSHEETCALLBACK, + u4: PROPSHEETHEADERW_V2_u4, + hplWatermark: HPALETTE, + u5: PROPSHEETHEADERW_V2_u5, +}} +pub type LPPROPSHEETHEADERW_V2 = *mut PROPSHEETHEADERW_V2; +pub type LPCPROPSHEETHEADERW_V2 = *const PROPSHEETHEADERW_V2; +pub type PROPSHEETHEADERA = PROPSHEETHEADERA_V2; +pub type PROPSHEETHEADERW = PROPSHEETHEADERW_V2; +pub type LPPROPSHEETHEADERA = LPPROPSHEETHEADERA_V2; +pub type LPPROPSHEETHEADERW = LPPROPSHEETHEADERW_V2; +pub type LPCPROPSHEETHEADERA = LPCPROPSHEETHEADERA_V2; +pub type LPCPROPSHEETHEADERW = LPCPROPSHEETHEADERW_V2; +pub const PSCB_INITIALIZED: UINT = 1; +pub const PSCB_PRECREATE: UINT = 2; +pub const PSCB_BUTTONPRESSED: UINT = 3; +extern "system" { + pub fn CreatePropertySheetPageA( + constPropSheetPagePointer: LPCPROPSHEETPAGEA, + ) -> HPROPSHEETPAGE; + pub fn CreatePropertySheetPageW( + constPropSheetPagePointer: LPCPROPSHEETPAGEW, + ) -> HPROPSHEETPAGE; + pub fn DestroyPropertySheetPage( + hPSPage: HPROPSHEETPAGE, + ) -> BOOL; + pub fn PropertySheetA( + lppsph: LPCPROPSHEETHEADERA, + ) -> INT_PTR; + pub fn PropertySheetW( + lppsph: LPCPROPSHEETHEADERW, + ) -> INT_PTR; +} +FN!{stdcall LPFNADDPROPSHEETPAGE( + HPROPSHEETPAGE, + LPARAM, +) -> BOOL} +FN!{stdcall LPFNADDPROPSHEETPAGES( + LPVOID, + LPFNADDPROPSHEETPAGE, + LPARAM, +) -> BOOL} +STRUCT!{struct PSHNOTIFY { + hdr: NMHDR, + lParam: LPARAM, +}} +pub type LPPSHNOTIFY = *mut PSHNOTIFY; +pub const PSN_FIRST: UINT = -200i32 as u32; +pub const PSN_LAST: UINT = -299i32 as u32; +pub const PSN_SETACTIVE: UINT = PSN_FIRST - 0; +pub const PSN_KILLACTIVE: UINT = PSN_FIRST - 1; +pub const PSN_APPLY: UINT = PSN_FIRST - 2; +pub const PSN_RESET: UINT = PSN_FIRST - 3; +pub const PSN_HELP: UINT = PSN_FIRST - 5; +pub const PSN_WIZBACK: UINT = PSN_FIRST - 6; +pub const PSN_WIZNEXT: UINT = PSN_FIRST - 7; +pub const PSN_WIZFINISH: UINT = PSN_FIRST - 8; +pub const PSN_QUERYCANCEL: UINT = PSN_FIRST - 9; +pub const PSN_GETOBJECT: UINT = PSN_FIRST - 10; +pub const PSN_TRANSLATEACCELERATOR: UINT = PSN_FIRST - 12; +pub const PSN_QUERYINITIALFOCUS: UINT = PSN_FIRST - 13; +pub const PSNRET_NOERROR: LRESULT = 0; +pub const PSNRET_INVALID: LRESULT = 1; +pub const PSNRET_INVALID_NOCHANGEPAGE: LRESULT = 2; +pub const PSNRET_MESSAGEHANDLED: LRESULT = 3; +pub const PSM_SETCURSEL: UINT = WM_USER + 101; +pub const PSM_REMOVEPAGE: UINT = WM_USER + 102; +pub const PSM_ADDPAGE: UINT = WM_USER + 103; +pub const PSM_CHANGED: UINT = WM_USER + 104; +pub const PSM_RESTARTWINDOWS: UINT = WM_USER + 105; +pub const PSM_REBOOTSYSTEM: UINT = WM_USER + 106; +pub const PSM_CANCELTOCLOSE: UINT = WM_USER + 107; +pub const PSM_QUERYSIBLINGS: UINT = WM_USER + 108; +pub const PSM_UNCHANGED: UINT = WM_USER + 109; +pub const PSM_APPLY: UINT = WM_USER + 110; +pub const PSM_SETTITLEA: UINT = WM_USER + 111; +pub const PSM_SETTITLEW: UINT = WM_USER + 120; +pub const PSM_SETWIZBUTTONS: UINT = WM_USER + 112; +pub const PSWIZB_BACK: DWORD = 0x00000001; +pub const PSWIZB_NEXT: DWORD = 0x00000002; +pub const PSWIZB_FINISH: DWORD = 0x00000004; +pub const PSWIZB_DISABLEDFINISH: DWORD = 0x00000008; +pub const PSWIZBF_ELEVATIONREQUIRED: WPARAM = 0x00000001; +pub const PSWIZB_CANCEL: DWORD = 0x00000010; +pub const PSM_PRESSBUTTON: UINT = WM_USER + 113; +pub const PSBTN_BACK: c_int = 0; +pub const PSBTN_NEXT: c_int = 1; +pub const PSBTN_FINISH: c_int = 2; +pub const PSBTN_OK: c_int = 3; +pub const PSBTN_APPLYNOW: c_int = 4; +pub const PSBTN_CANCEL: c_int = 5; +pub const PSBTN_HELP: c_int = 6; +pub const PSBTN_MAX: c_int = 6; +pub const PSM_SETCURSELID: UINT = WM_USER + 114; +pub const PSM_SETFINISHTEXTA: UINT = WM_USER + 115; +pub const PSM_SETFINISHTEXTW: UINT = WM_USER + 121; +pub const PSM_GETTABCONTROL: UINT = WM_USER + 116; +pub const PSM_ISDIALOGMESSAGE: UINT = WM_USER + 117; +pub const PSM_GETCURRENTPAGEHWND: UINT = WM_USER + 118; +pub const PSM_INSERTPAGE: UINT = WM_USER + 119; +pub const PSM_SETHEADERTITLEA: UINT = WM_USER + 125; +pub const PSM_SETHEADERTITLEW: UINT = WM_USER + 126; +pub const PSWIZF_SETCOLOR: UINT = -1i32 as u32; +pub const PSM_SETHEADERSUBTITLEA: UINT = WM_USER + 127; +pub const PSM_SETHEADERSUBTITLEW: UINT = WM_USER + 128; +pub const PSM_HWNDTOINDEX: UINT = WM_USER + 129; +pub const PSM_INDEXTOHWND: UINT = WM_USER + 130; +pub const PSM_PAGETOINDEX: UINT = WM_USER + 131; +pub const PSM_INDEXTOPAGE: UINT = WM_USER + 132; +pub const PSM_IDTOINDEX: UINT = WM_USER + 133; +pub const PSM_INDEXTOID: UINT = WM_USER + 134; +pub const PSM_GETRESULT: UINT = WM_USER + 135; +pub const PSM_RECALCPAGESIZES: UINT = WM_USER + 136; +pub const PSM_SETNEXTTEXTW: UINT = WM_USER + 137; +pub const PSM_SHOWWIZBUTTONS: UINT = WM_USER + 138; +pub const PSM_ENABLEWIZBUTTONS: UINT = WM_USER + 139; +pub const PSM_SETBUTTONTEXTW: UINT = WM_USER + 140; +pub const PSM_SETBUTTONTEXT: UINT = PSM_SETBUTTONTEXTW; +pub const ID_PSRESTARTWINDOWS: INT_PTR = 0x2; +pub const ID_PSREBOOTSYSTEM: INT_PTR = ID_PSRESTARTWINDOWS | 0x1; +pub const WIZ_CXDLG: DWORD = 276; +pub const WIZ_CYDLG: DWORD = 140; +pub const WIZ_CXBMP: DWORD = 80; +pub const WIZ_BODYX: DWORD = 92; +pub const WIZ_BODYCX: DWORD = 184; +pub const PROP_SM_CXDLG: c_short = 212; +pub const PROP_SM_CYDLG: c_short = 188; +pub const PROP_MED_CXDLG: c_short = 227; +pub const PROP_MED_CYDLG: c_short = 215; +pub const PROP_LG_CXDLG: c_short = 252; +pub const PROP_LG_CYDLG: c_short = 218; diff --git a/winapi/src/um/psapi.rs b/winapi/src/um/psapi.rs new file mode 100644 index 000000000..eb1adb803 --- /dev/null +++ b/winapi/src/um/psapi.rs @@ -0,0 +1,422 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! FFI bindings to psapi. +use shared::basetsd::{SIZE_T, ULONG_PTR}; +use shared::minwindef::{BOOL, DWORD, HMODULE, LPDWORD, LPVOID, PDWORD}; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PVOID}; +pub const LIST_MODULES_DEFAULT: DWORD = 0x0; +pub const LIST_MODULES_32BIT: DWORD = 0x01; +pub const LIST_MODULES_64BIT: DWORD = 0x02; +pub const LIST_MODULES_ALL: DWORD = LIST_MODULES_32BIT | LIST_MODULES_64BIT; +extern "system" { + pub fn K32EnumProcesses( + lpidProcess: *mut DWORD, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn K32EnumProcessModules( + hProcess: HANDLE, + lphModule: *mut HMODULE, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn K32EnumProcessModulesEx( + hProcess: HANDLE, + lphModule: *mut HMODULE, + cb: DWORD, + lpcbNeeded: LPDWORD, + dwFilterFlag: DWORD, + ) -> BOOL; + pub fn K32GetModuleBaseNameA( + hProcess: HANDLE, + hModule: HMODULE, + lpBaseName: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetModuleBaseNameW( + hProcess: HANDLE, + hModule: HMODULE, + lpBaseName: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetModuleFileNameExA( + hProcess: HANDLE, + hModule: HMODULE, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetModuleFileNameExW( + hProcess: HANDLE, + hModule: HMODULE, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32EmptyWorkingSet( + hProcess: HANDLE, + ) -> BOOL; + pub fn K32QueryWorkingSet( + hProcess: HANDLE, + pv: PVOID, + cb: DWORD, + ) -> BOOL; + pub fn K32QueryWorkingSetEx( + hProcess: HANDLE, + pv: PVOID, + cb: DWORD, + ) -> BOOL; + pub fn K32InitializeProcessForWsWatch( + hProcess: HANDLE, + ) -> BOOL; + pub fn K32GetWsChanges( + hProcess: HANDLE, + lpWatchInfo: PPSAPI_WS_WATCH_INFORMATION, + cb: DWORD, + ) -> BOOL; + pub fn K32GetWsChangesEx( + hProcess: HANDLE, + lpWatchInfoEx: PPSAPI_WS_WATCH_INFORMATION_EX, + cb: PDWORD, + ) -> BOOL; + pub fn K32GetMappedFileNameW( + hProcess: HANDLE, + lpv: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetMappedFileNameA( + hProcess: HANDLE, + lpv: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32EnumDeviceDrivers( + lpImageBase: *mut LPVOID, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn K32GetDeviceDriverBaseNameA( + ImageBase: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetDeviceDriverBaseNameW( + ImageBase: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetDeviceDriverFileNameA( + ImageBase: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetDeviceDriverFileNameW( + ImageBase: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetPerformanceInfo( + pPerformanceInformation: PPERFORMANCE_INFORMATION, + cb: DWORD, + ) -> BOOL; + pub fn K32EnumPageFilesW( + pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKW, + pContext: LPVOID, + ) -> BOOL; + pub fn K32EnumPageFilesA( + pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKA, + pContext: LPVOID, + ) -> BOOL; + pub fn K32GetProcessImageFileNameA( + hProcess: HANDLE, + lpImageFileName: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn K32GetProcessImageFileNameW( + hProcess: HANDLE, + lpImageFileName: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn EnumProcesses( + lpidProcess: *mut DWORD, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn K32GetProcessMemoryInfo( + Process: HANDLE, + ppsmemCounters: PPROCESS_MEMORY_COUNTERS, + cb: DWORD, + ) -> BOOL; + pub fn K32GetModuleInformation( + hProcess: HANDLE, + hModule: HMODULE, + lpmodinfo: LPMODULEINFO, + cb: DWORD, + ) -> BOOL; +} +pub type LPMODULEINFO = *mut MODULEINFO; +pub type PPSAPI_WORKING_SET_INFORMATION = *mut PSAPI_WORKING_SET_INFORMATION; +pub type PPSAPI_WORKING_SET_EX_INFORMATION = *mut PSAPI_WORKING_SET_EX_INFORMATION; +pub type PPSAPI_WS_WATCH_INFORMATION = *mut PSAPI_WS_WATCH_INFORMATION; +pub type PPSAPI_WS_WATCH_INFORMATION_EX = *mut PSAPI_WS_WATCH_INFORMATION_EX; +pub type PENUM_PAGE_FILE_INFORMATION = *mut ENUM_PAGE_FILE_INFORMATION; +pub type PPERFORMANCE_INFORMATION = *mut PERFORMANCE_INFORMATION; +pub type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS; +pub type PPROCESS_MEMORY_COUNTERS_EX = *mut PROCESS_MEMORY_COUNTERS_EX; +FN!{stdcall PENUM_PAGE_FILE_CALLBACKA( + pContext: LPVOID, + pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, + lpFilename: LPCSTR, +) -> BOOL} +FN!{stdcall PENUM_PAGE_FILE_CALLBACKW( + pContext: LPVOID, + pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, + lpFilename: LPCWSTR, +) -> BOOL} +STRUCT!{struct MODULEINFO { + lpBaseOfDll: LPVOID, + SizeOfImage: DWORD, + EntryPoint: LPVOID, +}} +STRUCT!{struct ENUM_PAGE_FILE_INFORMATION { + cb: DWORD, + Reserved: DWORD, + TotalSize: SIZE_T, + TotalInUse: SIZE_T, + PeakUsage: SIZE_T, +}} +STRUCT!{struct PERFORMANCE_INFORMATION { + cb: DWORD, + CommitTotal: SIZE_T, + CommitLimit: SIZE_T, + CommitPeak: SIZE_T, + PhysicalTotal: SIZE_T, + PhysicalAvailable: SIZE_T, + SystemCache: SIZE_T, + KernelTotal: SIZE_T, + KernelPaged: SIZE_T, + KernelNonpaged: SIZE_T, + PageSize: SIZE_T, + HandleCount: DWORD, + ProcessCount: DWORD, + ThreadCount: DWORD, +}} +STRUCT!{struct PROCESS_MEMORY_COUNTERS { + cb: DWORD, + PageFaultCount: DWORD, + PeakWorkingSetSize: SIZE_T, + WorkingSetSize: SIZE_T, + QuotaPeakPagedPoolUsage: SIZE_T, + QuotaPagedPoolUsage: SIZE_T, + QuotaPeakNonPagedPoolUsage: SIZE_T, + QuotaNonPagedPoolUsage: SIZE_T, + PagefileUsage: SIZE_T, + PeakPagefileUsage: SIZE_T, +}} +STRUCT!{struct PROCESS_MEMORY_COUNTERS_EX { + cb: DWORD, + PageFaultCount: DWORD, + PeakWorkingSetSize: SIZE_T, + WorkingSetSize: SIZE_T, + QuotaPeakPagedPoolUsage: SIZE_T, + QuotaPagedPoolUsage: SIZE_T, + QuotaPeakNonPagedPoolUsage: SIZE_T, + QuotaNonPagedPoolUsage: SIZE_T, + PagefileUsage: SIZE_T, + PeakPagefileUsage: SIZE_T, + PrivateUsage: SIZE_T, +}} +STRUCT!{struct PSAPI_WORKING_SET_BLOCK { + Flags: ULONG_PTR, +}} +BITFIELD!{PSAPI_WORKING_SET_BLOCK Flags: ULONG_PTR [ + Protection set_Protection[0..5], + ShareCount set_ShareCount[5..8], + Shared set_Shared[8..9], + Reserved set_Reserved[9..12], + VirtualPage set_VirtualPage[12..32], +]} +pub type PPSAPI_WORKING_SET_BLOCK = *mut PSAPI_WORKING_SET_BLOCK; +STRUCT!{struct PSAPI_WORKING_SET_EX_BLOCK { + Flags: ULONG_PTR, +}} +#[cfg(not(target_arch="x86_64"))] +BITFIELD!{PSAPI_WORKING_SET_EX_BLOCK Flags: ULONG_PTR [ + Valid set_Valid[0..1], + ShareCount set_ShareCount[1..4], + Win32Protection set_Win32Protection[4..15], + Shared set_Shared[15..16], + Node set_Node[16..22], + Locked set_Locked[22..23], + LargePage set_LargePage[23..24], + Reserved set_Reserved[24..31], + Bad set_Bad[31..32], +]} +#[cfg(target_arch="x86_64")] +BITFIELD!{PSAPI_WORKING_SET_EX_BLOCK Flags: ULONG_PTR [ + Valid set_Valid[0..1], + ShareCount set_ShareCount[1..4], + Win32Protection set_Win32Protection[4..15], + Shared set_Shared[15..16], + Node set_Node[16..22], + Locked set_Locked[22..23], + LargePage set_LargePage[23..24], + Reserved set_Reserved[24..31], + Bad set_Bad[31..32], + ReservedUlong set_ReservedULong[32..64], +]} +pub type PPSAPI_WORKING_SET_EX_BLOCK = *mut PSAPI_WORKING_SET_EX_BLOCK; +STRUCT!{struct PSAPI_WORKING_SET_INFORMATION { + NumberOfEntries: ULONG_PTR, + WorkingSetInfo: [PSAPI_WORKING_SET_BLOCK; 1], +}} +STRUCT!{struct PSAPI_WORKING_SET_EX_INFORMATION { + VirtualAddress: PVOID, + VirtualAttributes: PSAPI_WORKING_SET_EX_BLOCK, +}} +STRUCT!{struct PSAPI_WS_WATCH_INFORMATION { + FaultingPc: LPVOID, + FaultingVa: LPVOID, +}} +STRUCT!{struct PSAPI_WS_WATCH_INFORMATION_EX { + BasicInfo: PSAPI_WS_WATCH_INFORMATION, + FaultingThreadId: ULONG_PTR, + Flags: ULONG_PTR, +}} +extern "system" { + pub fn EmptyWorkingSet( + hProcess: HANDLE, + ) -> BOOL; + pub fn EnumDeviceDrivers( + lpImageBase: *mut LPVOID, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn EnumPageFilesA( + pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKA, + pContext: LPVOID, + ) -> BOOL; + pub fn EnumPageFilesW( + pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKW, + pContext: LPVOID, + ) -> BOOL; + pub fn EnumProcessModules( + hProcess: HANDLE, + lphModule: *mut HMODULE, + cb: DWORD, + lpcbNeeded: LPDWORD, + ) -> BOOL; + pub fn EnumProcessModulesEx( + hProcess: HANDLE, + lphModule: *mut HMODULE, + cb: DWORD, + lpcbNeeded: LPDWORD, + dwFilterFlag: DWORD, + ) -> BOOL; + pub fn GetDeviceDriverBaseNameA( + ImageBase: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetDeviceDriverBaseNameW( + ImageBase: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetDeviceDriverFileNameA( + ImageBase: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetDeviceDriverFileNameW( + ImageBase: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetMappedFileNameA( + hProcess: HANDLE, + lpv: LPVOID, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetMappedFileNameW( + hProcess: HANDLE, + lpv: LPVOID, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleBaseNameA( + hProcess: HANDLE, + hModule: HMODULE, + lpBaseName: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleBaseNameW( + hProcess: HANDLE, + hModule: HMODULE, + lpBaseName: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleFileNameExA( + hProcess: HANDLE, + hModule: HMODULE, + lpFilename: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleFileNameExW( + hProcess: HANDLE, + hModule: HMODULE, + lpFilename: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetModuleInformation( + hProcess: HANDLE, + hModule: HMODULE, + lpmodinfo: LPMODULEINFO, + cb: DWORD, + ) -> BOOL; + pub fn GetPerformanceInfo( + pPerformanceInformation: PPERFORMANCE_INFORMATION, + cb: DWORD, + ) -> BOOL; + pub fn GetProcessImageFileNameA( + hProcess: HANDLE, + lpImageFileName: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetProcessImageFileNameW( + hProcess: HANDLE, + lpImageFileName: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetProcessMemoryInfo( + hProcess: HANDLE, + ppsmemCounters: PPROCESS_MEMORY_COUNTERS, + cb: DWORD, + ) -> BOOL; + pub fn GetWsChanges( + hProcess: HANDLE, + lpWatchInfo: PPSAPI_WS_WATCH_INFORMATION, + cb: DWORD, + ) -> BOOL; + pub fn GetWsChangesEx( + hProcess: HANDLE, + lpWatchInfoEx: PPSAPI_WS_WATCH_INFORMATION_EX, + cb: PDWORD, + ) -> BOOL; + pub fn InitializeProcessForWsWatch( + hProcess: HANDLE, + ) -> BOOL; + pub fn QueryWorkingSet( + hProcess: HANDLE, + pv: PVOID, + cb: DWORD, + ) -> BOOL; + pub fn QueryWorkingSetEx( + hProcess: HANDLE, + pv: PVOID, + cb: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/realtimeapiset.rs b/winapi/src/um/realtimeapiset.rs new file mode 100644 index 000000000..5f63dbe19 --- /dev/null +++ b/winapi/src/um/realtimeapiset.rs @@ -0,0 +1,30 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::PULONG64; +use shared::minwindef::{BOOL, PULONG, USHORT}; +use um::winnt::{HANDLE, PULONGLONG}; +extern "system" { + pub fn QueryThreadCycleTime( + ThreadHandle: HANDLE, + CycleTime: PULONG64, + ) -> BOOL; + pub fn QueryProcessCycleTime( + ProcessHandle: HANDLE, + CycleTime: PULONG64, + ) -> BOOL; + pub fn QueryIdleProcessorCycleTime( + BufferLength: PULONG, + ProcessorIdleCycleTime: PULONG64, + ) -> BOOL; + pub fn QueryIdleProcessorCycleTimeEx( + Group: USHORT, + BufferLength: PULONG, + ProcessorIdleCycleTime: PULONG64, + ) -> BOOL; + pub fn QueryUnbiasedInterruptTime( + UnbiasedTime: PULONGLONG, + ) -> BOOL; +} diff --git a/winapi/src/um/reason.rs b/winapi/src/um/reason.rs new file mode 100644 index 000000000..609c295a5 --- /dev/null +++ b/winapi/src/um/reason.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::DWORD; +pub const SHTDN_REASON_FLAG_COMMENT_REQUIRED: DWORD = 0x01000000; +pub const SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED: DWORD = 0x02000000; +pub const SHTDN_REASON_FLAG_CLEAN_UI: DWORD = 0x04000000; +pub const SHTDN_REASON_FLAG_DIRTY_UI: DWORD = 0x08000000; +pub const SHTDN_REASON_FLAG_USER_DEFINED: DWORD = 0x40000000; +pub const SHTDN_REASON_FLAG_PLANNED: DWORD = 0x80000000; +pub const SHTDN_REASON_MAJOR_OTHER: DWORD = 0x00000000; +pub const SHTDN_REASON_MAJOR_NONE: DWORD = 0x00000000; +pub const SHTDN_REASON_MAJOR_HARDWARE: DWORD = 0x00010000; +pub const SHTDN_REASON_MAJOR_OPERATINGSYSTEM: DWORD = 0x00020000; +pub const SHTDN_REASON_MAJOR_SOFTWARE: DWORD = 0x00030000; +pub const SHTDN_REASON_MAJOR_APPLICATION: DWORD = 0x00040000; +pub const SHTDN_REASON_MAJOR_SYSTEM: DWORD = 0x00050000; +pub const SHTDN_REASON_MAJOR_POWER: DWORD = 0x00060000; +pub const SHTDN_REASON_MAJOR_LEGACY_API: DWORD = 0x00070000; +pub const SHTDN_REASON_MINOR_OTHER: DWORD = 0x00000000; +pub const SHTDN_REASON_MINOR_NONE: DWORD = 0x000000ff; +pub const SHTDN_REASON_MINOR_MAINTENANCE: DWORD = 0x00000001; +pub const SHTDN_REASON_MINOR_INSTALLATION: DWORD = 0x00000002; +pub const SHTDN_REASON_MINOR_UPGRADE: DWORD = 0x00000003; +pub const SHTDN_REASON_MINOR_RECONFIG: DWORD = 0x00000004; +pub const SHTDN_REASON_MINOR_HUNG: DWORD = 0x00000005; +pub const SHTDN_REASON_MINOR_UNSTABLE: DWORD = 0x00000006; +pub const SHTDN_REASON_MINOR_DISK: DWORD = 0x00000007; +pub const SHTDN_REASON_MINOR_PROCESSOR: DWORD = 0x00000008; +pub const SHTDN_REASON_MINOR_NETWORKCARD: DWORD = 0x00000009; +pub const SHTDN_REASON_MINOR_POWER_SUPPLY: DWORD = 0x0000000a; +pub const SHTDN_REASON_MINOR_CORDUNPLUGGED: DWORD = 0x0000000b; +pub const SHTDN_REASON_MINOR_ENVIRONMENT: DWORD = 0x0000000c; +pub const SHTDN_REASON_MINOR_HARDWARE_DRIVER: DWORD = 0x0000000d; +pub const SHTDN_REASON_MINOR_OTHERDRIVER: DWORD = 0x0000000e; +pub const SHTDN_REASON_MINOR_BLUESCREEN: DWORD = 0x0000000F; +pub const SHTDN_REASON_MINOR_SERVICEPACK: DWORD = 0x00000010; +pub const SHTDN_REASON_MINOR_HOTFIX: DWORD = 0x00000011; +pub const SHTDN_REASON_MINOR_SECURITYFIX: DWORD = 0x00000012; +pub const SHTDN_REASON_MINOR_SECURITY: DWORD = 0x00000013; +pub const SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY: DWORD = 0x00000014; +pub const SHTDN_REASON_MINOR_WMI: DWORD = 0x00000015; +pub const SHTDN_REASON_MINOR_SERVICEPACK_UNINSTALL: DWORD = 0x00000016; +pub const SHTDN_REASON_MINOR_HOTFIX_UNINSTALL: DWORD = 0x00000017; +pub const SHTDN_REASON_MINOR_SECURITYFIX_UNINSTALL: DWORD = 0x00000018; +pub const SHTDN_REASON_MINOR_MMC: DWORD = 0x00000019; +pub const SHTDN_REASON_MINOR_SYSTEMRESTORE: DWORD = 0x0000001a; +pub const SHTDN_REASON_MINOR_TERMSRV: DWORD = 0x00000020; +pub const SHTDN_REASON_MINOR_DC_PROMOTION: DWORD = 0x00000021; +pub const SHTDN_REASON_MINOR_DC_DEMOTION: DWORD = 0x00000022; +pub const SHTDN_REASON_UNKNOWN: DWORD = SHTDN_REASON_MINOR_NONE; +pub const SHTDN_REASON_LEGACY_API: DWORD = SHTDN_REASON_MAJOR_LEGACY_API + | SHTDN_REASON_FLAG_PLANNED; +pub const SHTDN_REASON_VALID_BIT_MASK: DWORD = 0xc0ffffff; +pub const PCLEANUI: DWORD = SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_FLAG_CLEAN_UI; +pub const UCLEANUI: DWORD = SHTDN_REASON_FLAG_CLEAN_UI; +pub const PDIRTYUI: DWORD = SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_FLAG_DIRTY_UI; +pub const UDIRTYUI: DWORD = SHTDN_REASON_FLAG_DIRTY_UI; diff --git a/winapi/src/um/restartmanager.rs b/winapi/src/um/restartmanager.rs new file mode 100644 index 000000000..3f4af64f5 --- /dev/null +++ b/winapi/src/um/restartmanager.rs @@ -0,0 +1,150 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! RestartManager include file +use shared::minwindef::{BOOL, DWORD, FILETIME, LPDWORD, PBYTE, UINT, ULONG}; +use um::winnt::{LPCWSTR, LPWSTR, WCHAR}; +pub const RM_SESSION_KEY_LEN: usize = 16; // mem::size_of::<GUID>() +pub const CCH_RM_SESSION_KEY: usize = RM_SESSION_KEY_LEN * 2; +pub const CCH_RM_MAX_APP_NAME: usize = 255; +pub const CCH_RM_MAX_SVC_NAME: usize = 63; +pub const RM_INVALID_TS_SESSION: DWORD = -1i32 as u32; +pub const RM_INVALID_PROCESS: DWORD = -1i32 as u32; +ENUM!{enum RM_APP_TYPE { + RmUnknownApp = 0, + RmMainWindow = 1, + RmOtherWindow = 2, + RmService = 3, + RmExplorer = 4, + RmConsole = 5, + RmCritical = 1000, +}} +ENUM!{enum RM_SHUTDOWN_TYPE { + RmForceShutdown = 0x1, + RmShutdownOnlyRegistered = 0x10, +}} +ENUM!{enum RM_APP_STATUS { + RmStatusUnknown = 0x0, + RmStatusRunning = 0x1, + RmStatusStopped = 0x2, + RmStatusStoppedOther = 0x4, + RmStatusRestarted = 0x8, + RmStatusErrorOnStop = 0x10, + RmStatusErrorOnRestart = 0x20, + RmStatusShutdownMasked = 0x40, + RmStatusRestartMasked = 0x80, +}} +ENUM!{enum RM_REBOOT_REASON { + RmRebootReasonNone = 0x0, + RmRebootReasonPermissionDenied = 0x1, + RmRebootReasonSessionMismatch = 0x2, + RmRebootReasonCriticalProcess = 0x4, + RmRebootReasonCriticalService = 0x8, + RmRebootReasonDetectedSelf = 0x10, +}} +STRUCT!{struct RM_UNIQUE_PROCESS { + dwProcessId: DWORD, + ProcessStartTime: FILETIME, +}} +pub type PRM_UNIQUE_PROCESS = *mut RM_UNIQUE_PROCESS; +STRUCT!{struct RM_PROCESS_INFO { + Process: RM_UNIQUE_PROCESS, + strAppName: [WCHAR; CCH_RM_MAX_APP_NAME + 1], + strServiceShortName: [WCHAR; CCH_RM_MAX_SVC_NAME + 1], + ApplicationType: RM_APP_TYPE, + AppStatus: ULONG, + TSSessionId: DWORD, + bRestartable: BOOL, +}} +pub type PRM_PROCESS_INFO = *mut RM_PROCESS_INFO; +ENUM!{enum RM_FILTER_TRIGGER { + RmFilterTriggerInvalid = 0, + RmFilterTriggerFile, + RmFilterTriggerProcess, + RmFilterTriggerService, +}} +ENUM!{enum RM_FILTER_ACTION { + RmInvalidFilterAction = 0, + RmNoRestart = 1, + RmNoShutdown = 2, +}} +UNION!{union RM_FILTER_INFO_u { + [u32; 3] [u64; 2], + strFilename strFilename_mut: LPWSTR, + Process Process_mut: RM_UNIQUE_PROCESS, + strServiceShortName strServiceShortName_mut: LPWSTR, +}} +STRUCT!{struct RM_FILTER_INFO { + FilterAction: RM_FILTER_ACTION, + FilterTrigger: RM_FILTER_TRIGGER, + cbNextOffset: DWORD, + u: RM_FILTER_INFO_u, +}} +pub type PRM_FILTER_INFO = *mut RM_FILTER_INFO; +FN!{cdecl RM_WRITE_STATUS_CALLBACK( + nPercentComplete: u32, +) -> ()} +extern "system" { + pub fn RmStartSession( + pSessionHandle: *mut DWORD, + dwSessionFlags: DWORD, + strSessionKey: *mut WCHAR, + ) -> DWORD; + pub fn RmJoinSession( + pSessionHandle: *mut DWORD, + strSessionKey: *const WCHAR, + ) -> DWORD; + pub fn RmEndSession( + dwSessionHandle: DWORD, + ) -> DWORD; + pub fn RmRegisterResources( + dwSessionHandle: DWORD, + nFiles: UINT, + rgsFileNames: *mut LPCWSTR, + nApplications: UINT, + rgApplications: *mut RM_UNIQUE_PROCESS, + nServices: UINT, + rgsServiceNames: *mut LPCWSTR, + ) -> DWORD; + pub fn RmGetList( + dwSessionHandle: DWORD, + pnProcInfoNeeded: *mut UINT, + pnProcInfo: *mut UINT, + rgAffectedApps: *mut RM_PROCESS_INFO, + lpdwRebootReasons: LPDWORD, + ) -> DWORD; + pub fn RmShutdown( + dwSessionHandle: DWORD, + lActionFlags: ULONG, + fnStatus: RM_WRITE_STATUS_CALLBACK, + ) -> DWORD; + pub fn RmRestart( + dwSessionHandle: DWORD, + dwRestartFlags: DWORD, + fnStatus: RM_WRITE_STATUS_CALLBACK, + ) -> DWORD; + pub fn RmCancelCurrentTask( + dwSessionHandle: DWORD, + ) -> DWORD; + pub fn RmAddFilter( + dwSessionHandle: DWORD, + strModuleName: LPCWSTR, + pProcess: *mut RM_UNIQUE_PROCESS, + strServiceShortName: LPCWSTR, + FilterAction: RM_FILTER_ACTION, + ) -> DWORD; + pub fn RmRemoveFilter( + dwSessionHandle: DWORD, + strModuleName: LPCWSTR, + pProcess: *mut RM_UNIQUE_PROCESS, + strServiceShortName: LPCWSTR, + ) -> DWORD; + pub fn RmGetFilterList( + dwSessionHandle: DWORD, + pbFilterBuf: PBYTE, + cbFilterBuf: DWORD, + cbFilterBufNeeded: LPDWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/restrictederrorinfo.rs b/winapi/src/um/restrictederrorinfo.rs new file mode 100644 index 000000000..9c5db989b --- /dev/null +++ b/winapi/src/um/restrictederrorinfo.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::wtypes::BSTR; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +RIDL!{#[uuid(0x82ba7092, 0x4c88, 0x427d, 0xa7, 0xbc, 0x16, 0xdd, 0x93, 0xfe, 0xb6, 0x7e)] +interface IRestrictedErrorInfo(IRestrictedErrorInfoVtbl): IUnknown(IUnknownVtbl) { + fn GetErrorDetails( + description: *mut BSTR, + error: *mut HRESULT, + restrictedDescription: *mut BSTR, + capabilitySid: *mut BSTR, + ) -> HRESULT, + fn GetReference( + reference: *mut BSTR, + ) -> HRESULT, +}} diff --git a/winapi/src/um/rmxfguid.rs b/winapi/src/um/rmxfguid.rs new file mode 100644 index 000000000..97c3814c1 --- /dev/null +++ b/winapi/src/um/rmxfguid.rs @@ -0,0 +1,67 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{TID_D3DRMInfo, + 0x2b957100, 0x9e9a, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMMesh, + 0x3d82ab44, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMVector, + 0x3d82ab5e, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMMeshFace, + 0x3d82ab5f, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMMaterial, + 0x3d82ab4d, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMMaterialArray, + 0x35ff44e1, 0x6c7c, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMFrame, + 0x3d82ab46, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMFrameTransformMatrix, + 0xf6f23f41, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMeshMaterialList, + 0xf6f23f42, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMeshTextureCoords, + 0xf6f23f40, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMeshNormals, + 0xf6f23f43, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMCoords2d, + 0xf6f23f44, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMatrix4x4, + 0xf6f23f45, 0x7686, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMAnimation, + 0x3d82ab4f, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMAnimationSet, + 0x3d82ab50, 0x62da, 0x11cf, 0xab, 0x39, 0x00, 0x20, 0xaf, 0x71, 0xe4, 0x33} +DEFINE_GUID!{TID_D3DRMAnimationKey, + 0x10dd46a8, 0x775b, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMFloatKeys, + 0x10dd46a9, 0x775b, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialAmbientColor, + 0x01411840, 0x7786, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialDiffuseColor, + 0x01411841, 0x7786, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialSpecularColor, + 0x01411842, 0x7786, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialEmissiveColor, + 0xd3e16e80, 0x7835, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialPower, + 0x01411843, 0x7786, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMColorRGBA, + 0x35ff44e0, 0x6c7c, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMColorRGB, + 0xd3e16e81, 0x7835, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMGuid, + 0xa42790e0, 0x7810, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMTextureFilename, + 0xa42790e1, 0x7810, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMTextureReference, + 0xa42790e2, 0x7810, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMIndexedColor, + 0x1630b820, 0x7842, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMeshVertexColors, + 0x1630b821, 0x7842, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMMaterialWrap, + 0x4885ae60, 0x78e8, 0x11cf, 0x8f, 0x52, 0x00, 0x40, 0x33, 0x35, 0x94, 0xa3} +DEFINE_GUID!{TID_D3DRMBoolean, + 0x537da6a0, 0xca37, 0x11d0, 0x94, 0x1c, 0x00, 0x80, 0xc8, 0x0c, 0xfa, 0x7b} diff --git a/winapi/src/um/sapi.rs b/winapi/src/um/sapi.rs new file mode 100644 index 000000000..2a2cf375a --- /dev/null +++ b/winapi/src/um/sapi.rs @@ -0,0 +1,1388 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! SAPI 5.4 definitions +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, ULONG, WORD}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPWSTR, ULONGLONG}; +pub use um::sapi53::{ + SPDATAKEYLOCATION, + SPDKL_DefaultLocation, + SPDKL_CurrentUser, + SPDKL_LocalMachine, + SPDKL_CurrentConfig, + SPDUI_EngineProperties, + SPDUI_AddRemoveWord, + SPDUI_UserTraining, + SPDUI_MicTraining, + SPDUI_RecoProfileProperties, + SPDUI_AudioProperties, + SPDUI_AudioVolume, + SPDUI_UserEnrollment, + SPDUI_ShareData, + SPDUI_Tutorial, + SPSTREAMFORMAT, + SPSF_Default, + SPSF_NoAssignedFormat, + SPSF_Text, + SPSF_NonStandardFormat, + SPSF_ExtendedAudioFormat, + SPSF_8kHz8BitMono, + SPSF_8kHz8BitStereo, + SPSF_8kHz16BitMono, + SPSF_8kHz16BitStereo, + SPSF_11kHz8BitMono, + SPSF_11kHz8BitStereo, + SPSF_11kHz16BitMono, + SPSF_11kHz16BitStereo, + SPSF_12kHz8BitMono, + SPSF_12kHz8BitStereo, + SPSF_12kHz16BitMono, + SPSF_12kHz16BitStereo, + SPSF_16kHz8BitMono, + SPSF_16kHz8BitStereo, + SPSF_16kHz16BitMono, + SPSF_16kHz16BitStereo, + SPSF_22kHz8BitMono, + SPSF_22kHz8BitStereo, + SPSF_22kHz16BitMono, + SPSF_22kHz16BitStereo, + SPSF_24kHz8BitMono, + SPSF_24kHz8BitStereo, + SPSF_24kHz16BitMono, + SPSF_24kHz16BitStereo, + SPSF_32kHz8BitMono, + SPSF_32kHz8BitStereo, + SPSF_32kHz16BitMono, + SPSF_32kHz16BitStereo, + SPSF_44kHz8BitMono, + SPSF_44kHz8BitStereo, + SPSF_44kHz16BitMono, + SPSF_44kHz16BitStereo, + SPSF_48kHz8BitMono, + SPSF_48kHz8BitStereo, + SPSF_48kHz16BitMono, + SPSF_48kHz16BitStereo, + SPSF_TrueSpeech_8kHz1BitMono, + SPSF_CCITT_ALaw_8kHzMono, + SPSF_CCITT_ALaw_8kHzStereo, + SPSF_CCITT_ALaw_11kHzMono, + SPSF_CCITT_ALaw_11kHzStereo, + SPSF_CCITT_ALaw_22kHzMono, + SPSF_CCITT_ALaw_22kHzStereo, + SPSF_CCITT_ALaw_44kHzMono, + SPSF_CCITT_ALaw_44kHzStereo, + SPSF_CCITT_uLaw_8kHzMono, + SPSF_CCITT_uLaw_8kHzStereo, + SPSF_CCITT_uLaw_11kHzMono, + SPSF_CCITT_uLaw_11kHzStereo, + SPSF_CCITT_uLaw_22kHzMono, + SPSF_CCITT_uLaw_22kHzStereo, + SPSF_CCITT_uLaw_44kHzMono, + SPSF_CCITT_uLaw_44kHzStereo, + SPSF_ADPCM_8kHzMono, + SPSF_ADPCM_8kHzStereo, + SPSF_ADPCM_11kHzMono, + SPSF_ADPCM_11kHzStereo, + SPSF_ADPCM_22kHzMono, + SPSF_ADPCM_22kHzStereo, + SPSF_ADPCM_44kHzMono, + SPSF_ADPCM_44kHzStereo, + SPSF_GSM610_8kHzMono, + SPSF_GSM610_11kHzMono, + SPSF_GSM610_22kHzMono, + SPSF_GSM610_44kHzMono, + SPSF_NUM_FORMATS, + SPDFID_Text, + SPDFID_WaveFormatEx, + SPREG_USER_ROOT, + SPREG_LOCAL_MACHINE_ROOT, + SPCAT_AUDIOOUT, + SPCAT_AUDIOIN, + SPCAT_VOICES, + SPCAT_RECOGNIZERS, + SPCAT_APPLEXICONS, + SPCAT_PHONECONVERTERS, + SPCAT_TEXTNORMALIZERS, + SPCAT_RECOPROFILES, + SPMMSYS_AUDIO_IN_TOKEN_ID, + SPMMSYS_AUDIO_OUT_TOKEN_ID, + SPCURRENT_USER_LEXICON_TOKEN_ID, + SPTOKENVALUE_CLSID, + SPTOKENKEY_FILES, + SPTOKENKEY_UI, + SPTOKENKEY_ATTRIBUTES, + SPTOKENKEY_RETAINEDAUDIO, + SPTOKENKEY_AUDIO_LATENCY_WARNING, + SPTOKENKEY_AUDIO_LATENCY_TRUNCATE, + SPTOKENKEY_AUDIO_LATENCY_UPDATE_INTERVAL, + SPVOICECATEGORY_TTSRATE, + SPPROP_RESOURCE_USAGE, + SPPROP_HIGH_CONFIDENCE_THRESHOLD, + SPPROP_NORMAL_CONFIDENCE_THRESHOLD, + SPPROP_LOW_CONFIDENCE_THRESHOLD, + SPPROP_RESPONSE_SPEED, + SPPROP_COMPLEX_RESPONSE_SPEED, + SPPROP_ADAPTATION_ON, + SPPROP_PERSISTED_BACKGROUND_ADAPTATION, + SPPROP_PERSISTED_LANGUAGE_MODEL_ADAPTATION, + SPPROP_UX_IS_LISTENING, + SPTOPIC_SPELLING, + SPWILDCARD, + SPDICTATION, + SPREG_SAFE_USER_TOKENS, + SPINFDICTATION, + SP_LOW_CONFIDENCE, + SP_NORMAL_CONFIDENCE, + SP_HIGH_CONFIDENCE, + DEFAULT_WEIGHT, + SP_MAX_WORD_LENGTH, + SP_MAX_PRON_LENGTH, + SP_EMULATE_RESULT, + ISpNotifyCallback, + SPNOTIFYCALLBACK, + ISpNotifySource, ISpNotifySourceVtbl, + ISpNotifySink, ISpNotifySinkVtbl, + ISpNotifyTranslator, ISpNotifyTranslatorVtbl, + ISpDataKey, ISpDataKeyVtbl, + ISpRegDataKey, ISpRegDataKeyVtbl, + ISpObjectTokenCategory, ISpObjectTokenCategoryVtbl, + ISpObjectToken, ISpObjectTokenVtbl, + ISpObjectTokenInit, ISpObjectTokenInitVtbl, + IEnumSpObjectTokens, IEnumSpObjectTokensVtbl, + ISpObjectWithToken, ISpObjectWithTokenVtbl, + ISpResourceManager, ISpResourceManagerVtbl, + SPEVENTLPARAMTYPE, + SPET_LPARAM_IS_UNDEFINED, + SPET_LPARAM_IS_TOKEN, + SPET_LPARAM_IS_OBJECT, + SPET_LPARAM_IS_POINTER, + SPET_LPARAM_IS_STRING, + SPEVENTENUM, + SPEI_UNDEFINED, + SPEI_START_INPUT_STREAM, + SPEI_END_INPUT_STREAM, + SPEI_VOICE_CHANGE, + SPEI_TTS_BOOKMARK, + SPEI_WORD_BOUNDARY, + SPEI_PHONEME, + SPEI_SENTENCE_BOUNDARY, + SPEI_VISEME, + SPEI_TTS_AUDIO_LEVEL, + SPEI_TTS_PRIVATE, + SPEI_MIN_TTS, + SPEI_MAX_TTS, + SPEI_END_SR_STREAM, + SPEI_SOUND_START, + SPEI_SOUND_END, + SPEI_PHRASE_START, + SPEI_RECOGNITION, + SPEI_HYPOTHESIS, + SPEI_SR_BOOKMARK, + SPEI_PROPERTY_NUM_CHANGE, + SPEI_PROPERTY_STRING_CHANGE, + SPEI_FALSE_RECOGNITION, + SPEI_INTERFERENCE, + SPEI_REQUEST_UI, + SPEI_RECO_STATE_CHANGE, + SPEI_ADAPTATION, + SPEI_START_SR_STREAM, + SPEI_RECO_OTHER_CONTEXT, + SPEI_SR_AUDIO_LEVEL, + SPEI_SR_RETAINEDAUDIO, + SPEI_SR_PRIVATE, +}; +pub const ACTIVE_CATEGORY_CHANGED: SPEVENTENUM = 53; +pub use um::sapi53::{ + SPEI_RESERVED5, + SPEI_RESERVED6, + SPEI_MIN_SR, + SPEI_MAX_SR, + SPEI_RESERVED1, + SPEI_RESERVED2, + SPEI_RESERVED3, + SPFEI_FLAGCHECK, + SPFEI_ALL_TTS_EVENTS, + SPFEI_ALL_SR_EVENTS, + SPFEI_ALL_EVENTS, + SPFEI, + SPEVENT, + SPSERIALIZEDEVENT, + SPSERIALIZEDEVENT64, + SPEVENTEX, + SPINTERFERENCE, + SPINTERFERENCE_NONE, + SPINTERFERENCE_NOISE, + SPINTERFERENCE_NOSIGNAL, + SPINTERFERENCE_TOOLOUD, + SPINTERFERENCE_TOOQUIET, + SPINTERFERENCE_TOOFAST, + SPINTERFERENCE_TOOSLOW, + SPINTERFERENCE_LATENCY_WARNING, + SPINTERFERENCE_LATENCY_TRUNCATE_BEGIN, + SPINTERFERENCE_LATENCY_TRUNCATE_END, + SPENDSRSTREAMFLAGS, + SPESF_NONE, + SPESF_STREAM_RELEASED, + SPESF_EMULATED, + SPVFEATURE, + SPVFEATURE_STRESSED, + SPVFEATURE_EMPHASIS, + SPVISEMES, + SP_VISEME_0, + SP_VISEME_1, + SP_VISEME_2, + SP_VISEME_3, + SP_VISEME_4, + SP_VISEME_5, + SP_VISEME_6, + SP_VISEME_7, + SP_VISEME_8, + SP_VISEME_9, + SP_VISEME_10, + SP_VISEME_11, + SP_VISEME_12, + SP_VISEME_13, + SP_VISEME_14, + SP_VISEME_15, + SP_VISEME_16, + SP_VISEME_17, + SP_VISEME_18, + SP_VISEME_19, + SP_VISEME_20, + SP_VISEME_21, + SPEVENTSOURCEINFO, + ISpEventSource, ISpEventSourceVtbl, + ISpEventSource2, ISpEventSource2Vtbl, + ISpEventSink, ISpEventSinkVtbl, + ISpStreamFormat, ISpStreamFormatVtbl, + SPFILEMODE, + SPFM_OPEN_READONLY, + SPFM_OPEN_READWRITE, + SPFM_CREATE, + SPFM_CREATE_ALWAYS, + SPFM_NUM_MODES, + ISpStream, ISpStreamVtbl, + ISpStreamFormatConverter, ISpStreamFormatConverterVtbl, + SPAUDIOSTATE, + SPAS_CLOSED, + SPAS_STOP, + SPAS_PAUSE, + SPAS_RUN, + SPAUDIOSTATUS, + SPAUDIOBUFFERINFO, + ISpAudio, ISpAudioVtbl, + ISpMMSysAudio, ISpMMSysAudioVtbl, + ISpTranscript, ISpTranscriptVtbl, + SPDISPLAYATTRIBUTES, + SPAF_ONE_TRAILING_SPACE, + SPAF_TWO_TRAILING_SPACES, + SPAF_CONSUME_LEADING_SPACES, + SPAF_BUFFER_POSITION, + SPAF_ALL, + SPAF_USER_SPECIFIED, + SPPHONEID, + PSPPHONEID, + PCSPPHONEID, + SPPHRASEELEMENT, + SPPHRASERULE, + SPPHRASEPROPERTYUNIONTYPE, + SPPPUT_UNUSED, + SPPPUT_ARRAY_INDEX, + SPPHRASEPROPERTY, + SPPHRASEREPLACEMENT, + SPSEMANTICERRORINFO, + SPSEMANTICFORMAT, + SPPHRASE_50, +// SPPHRASESIZE_500, +}; +pub use um::sapi53::SPPHRASE as SPPHRASE_53; +STRUCT!{struct SPPHRASE { + cbSize: ULONG, + LangID: WORD, + wHomophoneGroupId: WORD, + ullGrammarID: ULONGLONG, + ftStartTime: ULONGLONG, + ullAudioStreamPosition: ULONGLONG, + ulAudioSizeBytes: ULONG, + ulRetainedSizeBytes: ULONG, + ulAudioSizeTime: ULONG, + Rule: SPPHRASERULE, + pProperties: *const SPPHRASEPROPERTY, + pElements: *const SPPHRASEELEMENT, + cReplacements: ULONG, + pReplacements: *const SPPHRASEREPLACEMENT, + SREngineID: GUID, + ulSREnginePrivateDataSize: ULONG, + pSREnginePrivateData: *const BYTE, + pSML: LPWSTR, + pSemanticErrorInfo: *mut SPSEMANTICERRORINFO, + SemanticTagFormat: SPSEMANTICFORMAT, +}} +pub use um::sapi53::{ + SPSERIALIZEDPHRASE, + SPRULE, + SPVALUETYPE, + SPDF_PROPERTY, + SPDF_REPLACEMENT, + SPDF_RULE, + SPDF_DISPLAYTEXT, + SPDF_LEXICALFORM , + SPDF_PRONUNCIATION, + SPDF_AUDIO, + SPDF_ALTERNATES, + SPDF_ALL, + SPBINARYGRAMMAR, + SPPHRASERNG, + SPPR_ALL_ELEMENTS, + SP_GETWHOLEPHRASE, + SPRR_ALL_ELEMENTS, + SPSTATEHANDLE, + SPRECOEVENTFLAGS, + SPREF_AutoPause, + SPREF_Emulated, + SPREF_SMLTimeout, + SPREF_ExtendableParse, + SPREF_ReSent, + SPREF_Hypothesis, + SPREF_FalseRecognition, + SPPARTOFSPEECH, + SPPS_NotOverriden, + SPPS_Unknown, + SPPS_Noun, + SPPS_Verb, + SPPS_Modifier, + SPPS_Function, + SPPS_Interjection, + SPPS_Noncontent, + SPPS_LMA, + SPPS_SuppressWord, + SPLEXICONTYPE, + eLEXTYPE_USER, + eLEXTYPE_APP, + eLEXTYPE_VENDORLEXICON, + eLEXTYPE_LETTERTOSOUND, + eLEXTYPE_MORPHOLOGY, + eLEXTYPE_RESERVED4, + eLEXTYPE_USER_SHORTCUT, + eLEXTYPE_RESERVED6, + eLEXTYPE_RESERVED7, + eLEXTYPE_RESERVED8, + eLEXTYPE_RESERVED9, + eLEXTYPE_RESERVED10, + eLEXTYPE_PRIVATE1, + eLEXTYPE_PRIVATE2, + eLEXTYPE_PRIVATE3, + eLEXTYPE_PRIVATE4, + eLEXTYPE_PRIVATE5, + eLEXTYPE_PRIVATE6, + eLEXTYPE_PRIVATE7, + eLEXTYPE_PRIVATE8, + eLEXTYPE_PRIVATE9, + eLEXTYPE_PRIVATE10, + eLEXTYPE_PRIVATE11, + eLEXTYPE_PRIVATE12, + eLEXTYPE_PRIVATE13, + eLEXTYPE_PRIVATE14, + eLEXTYPE_PRIVATE15, + eLEXTYPE_PRIVATE16, + eLEXTYPE_PRIVATE17, + eLEXTYPE_PRIVATE18, + eLEXTYPE_PRIVATE19, + eLEXTYPE_PRIVATE20, + SPWORDTYPE, + eWORDTYPE_ADDED, + eWORDTYPE_DELETED, + SPPRONUNCIATIONFLAGS, + ePRONFLAG_USED, + SPWORDPRONUNCIATION, + SPWORDPRONUNCIATIONLIST, + SPWORD, + SPWORDLIST, + ISpLexicon, ISpLexiconVtbl, + ISpContainerLexicon, ISpContainerLexiconVtbl, + SPSHORTCUTTYPE, + SPSHT_NotOverriden, + SPSHT_Unknown, + SPSHT_EMAIL, + SPSHT_OTHER, + SPPS_RESERVED1, + SPPS_RESERVED2, + SPPS_RESERVED3, + SPPS_RESERVED4, + SPSHORTCUTPAIR, + SPSHORTCUTPAIRLIST, + ISpShortcut, ISpShortcutVtbl, + ISpPhoneConverter, ISpPhoneConverterVtbl, + ISpPhoneticAlphabetConverter, ISpPhoneticAlphabetConverterVtbl, + ISpPhoneticAlphabetSelection, ISpPhoneticAlphabetSelectionVtbl, + SPVPITCH, + SPVACTIONS, + SPVA_Speak, + SPVA_Silence, + SPVA_Pronounce, + SPVA_Bookmark, + SPVA_SpellOut, + SPVA_Section, + SPVA_ParseUnknownTag, + SPVCONTEXT, + SPVSTATE, + SPRUNSTATE, + SPRS_DONE, + SPRS_IS_SPEAKING, + SPVLIMITS, + SPMIN_VOLUME, + SPMAX_VOLUME, + SPMIN_RATE, + SPMAX_RATE, + SPVPRIORITY, + SPVPRI_NORMAL, + SPVPRI_ALERT, + SPVPRI_OVER, + SPVOICESTATUS, + SPEAKFLAGS, + SPF_DEFAULT, + SPF_ASYNC, + SPF_PURGEBEFORESPEAK, + SPF_IS_FILENAME, + SPF_IS_XML, + SPF_IS_NOT_XML, + SPF_PERSIST_XML, + SPF_NLP_SPEAK_PUNC, + SPF_PARSE_SAPI, + SPF_PARSE_SSML, + SPF_PARSE_AUTODETECT, + SPF_NLP_MASK, + SPF_PARSE_MASK, + SPF_VOICE_MASK, + SPF_UNUSED_FLAGS, + ISpVoice, ISpVoiceVtbl, + ISpPhrase, ISpPhraseVtbl, + ISpPhraseAlt, ISpPhraseAltVtbl, + SPXMLRESULTOPTIONS, + SPXRO_SML, + SPXRO_Alternates_SML, + ISpPhrase2, ISpPhrase2Vtbl, + SPRECORESULTTIMES, + SPSERIALIZEDRESULT, + ISpRecoResult, ISpRecoResultVtbl, + SPCOMMITFLAGS, + SPCF_NONE, + SPCF_ADD_TO_USER_LEXICON, + SPCF_DEFINITE_CORRECTION, + ISpRecoResult2, ISpRecoResult2Vtbl, + ISpXMLRecoResult, ISpXMLRecoResultVtbl, + SPTEXTSELECTIONINFO, + SPWORDPRONOUNCEABLE, + SPWP_UNKNOWN_WORD_UNPRONOUNCEABLE, + SPWP_UNKNOWN_WORD_PRONOUNCEABLE, + SPWP_KNOWN_WORD_PRONOUNCEABLE, + SPGRAMMARSTATE, + SPGS_DISABLED, + SPGS_ENABLED, + SPGS_EXCLUSIVE, + SPCONTEXTSTATE, + SPCS_DISABLED, + SPCS_ENABLED, + SPRULESTATE, + SPRS_INACTIVE, + SPRS_ACTIVE, + SPRS_ACTIVE_WITH_AUTO_PAUSE, + SPWT_LEXICAL_NO_SPECIAL_CHARS, + SPPROPERTYINFO, + SPCFGRULEATTRIBUTES, + SPRAF_TopLevel, + SPRAF_Active, + SPRAF_Export, + SPRAF_Import, + SPRAF_Interpreter, + SPRAF_Dynamic, + SPRAF_Root, + SPRAF_AutoPause, + SPRAF_UserDelimited, + ISpGrammarBuilder, ISpGrammarBuilderVtbl, + SPLOADOPTIONS, + SPLO_STATIC, + SPLO_DYNAMIC, + ISpRecoGrammar, ISpRecoGrammarVtbl, + SPMATCHINGMODE, + AllWords, + Subsequence, + OrderedSubset, + SubsequenceContentRequired, + OrderedSubsetContentRequired, + PHONETICALPHABET, + PA_Ipa, + PA_Ups, + PA_Sapi, + ISpGrammarBuilder2, ISpGrammarBuilder2Vtbl, + SPRP_NORMAL, + ISpRecoGrammar2, ISpRecoGrammar2Vtbl, + ISpeechResourceLoader, ISpeechResourceLoaderVtbl, + SPRECOCONTEXTSTATUS, + SPBOOKMARKOPTIONS, + SPBO_NONE, + SPBO_PAUSE, + SPBO_AHEAD, + SPBO_TIME_UNITS, + SPAUDIOOPTIONS, + SPAO_NONE, + SPAO_RETAIN_AUDIO, + ISpRecoContext, ISpRecoContextVtbl, + SPGRAMMAROPTIONS, + SPGO_SAPI, + SPGO_SRGS, + SPGO_UPS, + SPGO_SRGS_MS_SCRIPT, + SPGO_SRGS_W3C_SCRIPT, + SPGO_SRGS_STG_SCRIPT, + SPGO_SRGS_SCRIPT, + SPGO_FILE, + SPGO_HTTP, + SPGO_RES, + SPGO_OBJECT, + SPGO_DEFAULT, + SPGO_ALL, + SPADAPTATIONSETTINGS, + SPADS_Default, + SPADS_CurrentRecognizer, + SPADS_RecoProfile, + SPADS_Immediate, + SPADS_Reset, + SPADS_HighVolumeDataSource, + SPADAPTATIONRELEVANCE, + SPAR_Unknown, + SPAR_Low, + SPAR_Medium, + SPAR_High, + ISpRecoContext2, ISpRecoContext2Vtbl, + ISpProperties, ISpPropertiesVtbl, + SP_MAX_LANGIDS, + SPRECOGNIZERSTATUS, + SPWAVEFORMATTYPE, + SPWF_INPUT, + SPWF_SRENGINE, + SPSTREAMFORMATTYPE, + SPRECOSTATE, + SPRST_INACTIVE, + SPRST_ACTIVE, + SPRST_ACTIVE_ALWAYS, + SPRST_INACTIVE_WITH_PURGE, + SPRST_NUM_STATES, + ISpRecognizer, ISpRecognizerVtbl, + ISpSerializeState, ISpSerializeStateVtbl, + ISpRecognizer2, ISpRecognizer2Vtbl, +}; +ENUM!{enum SPCATEGORYTYPE { + SPCT_COMMAND, + SPCT_DICTATION, + SPCT_SLEEP, + SPCT_SUB_COMMAND, + SPCT_SUB_DICTATION, +}} +RIDL!{#[uuid(0xda0cd0f9, 0x14a2, 0x4f09, 0x8c, 0x2a, 0x85, 0xcc, 0x48, 0x97, 0x93, 0x45)] +interface ISpRecoCategory(ISpRecoCategoryVtbl): IUnknown(IUnknownVtbl) { + fn GetType( + peCategoryType: *mut SPCATEGORYTYPE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdf1b943c, 0x5838, 0x4aa2, 0x87, 0x06, 0xd7, 0xcd, 0x5b, 0x33, 0x34, 0x99)] +interface ISpRecognizer3(ISpRecognizer3Vtbl): IUnknown(IUnknownVtbl) { + fn GetCategory( + categoryType: SPCATEGORYTYPE, + ppCategory: *mut *mut ISpRecoCategory, + ) -> HRESULT, + fn SetActiveCategory( + pCategory: *mut ISpRecoCategory, + ) -> HRESULT, + fn GetActiveCategory( + ppCategory: *mut *mut ISpRecoCategory, + ) -> HRESULT, +}} +pub use um::sapi53::{ + SPNORMALIZATIONLIST, + ISpEnginePronunciation, ISpEnginePronunciationVtbl, + SPDISPLAYTOKEN, + SPDISPLAYPHRASE, + ISpDisplayAlternates, ISpDisplayAlternatesVtbl, + SpeechLanguageId, + DISPID_SpeechDataKey, + DISPID_SDKSetBinaryValue, + DISPID_SDKGetBinaryValue, + DISPID_SDKSetStringValue, + DISPID_SDKGetStringValue, + DISPID_SDKSetLongValue, + DISPID_SDKGetlongValue, + DISPID_SDKOpenKey, + DISPID_SDKCreateKey, + DISPID_SDKDeleteKey, + DISPID_SDKDeleteValue, + DISPID_SDKEnumKeys, + DISPID_SDKEnumValues, + DISPID_SpeechObjectToken, + DISPID_SOTId, + DISPID_SOTDataKey, + DISPID_SOTCategory, + DISPID_SOTGetDescription, + DISPID_SOTSetId, + DISPID_SOTGetAttribute, + DISPID_SOTCreateInstance, + DISPID_SOTRemove, + DISPID_SOTGetStorageFileName, + DISPID_SOTRemoveStorageFileName, + DISPID_SOTIsUISupported, + DISPID_SOTDisplayUI, + DISPID_SOTMatchesAttributes, + SpeechDataKeyLocation, + SDKLDefaultLocation, + SDKLCurrentUser, + SDKLLocalMachine, + SDKLCurrentConfig, + SpeechTokenContext, + STCInprocServer, + STCInprocHandler , + STCLocalServer, + STCRemoteServer, + STCAll, + SpeechTokenShellFolder, + STSF_AppData, + STSF_LocalAppData, + STSF_CommonAppData, + STSF_FlagCreate, + DISPID_SpeechObjectTokens, + DISPID_SOTsCount, + DISPID_SOTsItem, + DISPID_SOTs_NewEnum, + DISPID_SpeechObjectTokenCategory, + DISPID_SOTCId, + DISPID_SOTCDefault, + DISPID_SOTCSetId, + DISPID_SOTCGetDataKey, + DISPID_SOTCEnumerateTokens, + SpeechAudioFormatType, + SAFTDefault, + SAFTNoAssignedFormat, + SAFTText, + SAFTNonStandardFormat, + SAFTExtendedAudioFormat, + SAFT8kHz8BitMono, + SAFT8kHz8BitStereo, + SAFT8kHz16BitMono, + SAFT8kHz16BitStereo, + SAFT11kHz8BitMono, + SAFT11kHz8BitStereo, + SAFT11kHz16BitMono, + SAFT11kHz16BitStereo, + SAFT12kHz8BitMono, + SAFT12kHz8BitStereo, + SAFT12kHz16BitMono, + SAFT12kHz16BitStereo, + SAFT16kHz8BitMono, + SAFT16kHz8BitStereo, + SAFT16kHz16BitMono, + SAFT16kHz16BitStereo, + SAFT22kHz8BitMono, + SAFT22kHz8BitStereo, + SAFT22kHz16BitMono, + SAFT22kHz16BitStereo, + SAFT24kHz8BitMono, + SAFT24kHz8BitStereo, + SAFT24kHz16BitMono, + SAFT24kHz16BitStereo, + SAFT32kHz8BitMono, + SAFT32kHz8BitStereo, + SAFT32kHz16BitMono, + SAFT32kHz16BitStereo, + SAFT44kHz8BitMono, + SAFT44kHz8BitStereo, + SAFT44kHz16BitMono, + SAFT44kHz16BitStereo, + SAFT48kHz8BitMono, + SAFT48kHz8BitStereo, + SAFT48kHz16BitMono, + SAFT48kHz16BitStereo, + SAFTTrueSpeech_8kHz1BitMono, + SAFTCCITT_ALaw_8kHzMono, + SAFTCCITT_ALaw_8kHzStereo, + SAFTCCITT_ALaw_11kHzMono, + SAFTCCITT_ALaw_11kHzStereo, + SAFTCCITT_ALaw_22kHzMono, + SAFTCCITT_ALaw_22kHzStereo, + SAFTCCITT_ALaw_44kHzMono, + SAFTCCITT_ALaw_44kHzStereo, + SAFTCCITT_uLaw_8kHzMono, + SAFTCCITT_uLaw_8kHzStereo, + SAFTCCITT_uLaw_11kHzMono, + SAFTCCITT_uLaw_11kHzStereo, + SAFTCCITT_uLaw_22kHzMono, + SAFTCCITT_uLaw_22kHzStereo, + SAFTCCITT_uLaw_44kHzMono, + SAFTCCITT_uLaw_44kHzStereo, + SAFTADPCM_8kHzMono, + SAFTADPCM_8kHzStereo, + SAFTADPCM_11kHzMono, + SAFTADPCM_11kHzStereo, + SAFTADPCM_22kHzMono, + SAFTADPCM_22kHzStereo, + SAFTADPCM_44kHzMono, + SAFTADPCM_44kHzStereo, + SAFTGSM610_8kHzMono, + SAFTGSM610_11kHzMono, + SAFTGSM610_22kHzMono, + SAFTGSM610_44kHzMono, + DISPID_SpeechAudioFormat, + DISPID_SAFType, + DISPID_SAFGuid, + DISPID_SAFGetWaveFormatEx, + DISPID_SAFSetWaveFormatEx, + DISPID_SpeechBaseStream, + DISPID_SBSFormat, + DISPID_SBSRead, + DISPID_SBSWrite, + DISPID_SBSSeek, + SpeechStreamSeekPositionType, + SSSPTRelativeToStart, + SSSPTRelativeToCurrentPosition, + SSSPTRelativeToEnd, + DISPID_SpeechAudio, + DISPID_SAStatus, + DISPID_SABufferInfo, + DISPID_SADefaultFormat, + DISPID_SAVolume, + DISPID_SABufferNotifySize, + DISPID_SAEventHandle, + DISPID_SASetState, + SpeechAudioState, + SASClosed, + SASStop, + SASPause, + SASRun, + DISPID_SpeechMMSysAudio, + DISPID_SMSADeviceId, + DISPID_SMSALineId, + DISPID_SMSAMMHandle, + DISPID_SpeechFileStream, + DISPID_SFSOpen, + DISPID_SFSClose, + SpeechStreamFileMode, + SSFMOpenForRead, + SSFMOpenReadWrite, + SSFMCreate, + SSFMCreateForWrite, + DISPID_SpeechCustomStream, + DISPID_SCSBaseStream, + DISPID_SpeechMemoryStream, + DISPID_SMSSetData, + DISPID_SMSGetData, + DISPID_SpeechAudioStatus, + DISPID_SASFreeBufferSpace, + DISPID_SASNonBlockingIO, + DISPID_SASState, + DISPID_SASCurrentSeekPosition, + DISPID_SASCurrentDevicePosition, + DISPID_SpeechAudioBufferInfo, + DISPID_SABIMinNotification, + DISPID_SABIBufferSize, + DISPID_SABIEventBias, + DISPID_SpeechWaveFormatEx, + DISPID_SWFEFormatTag, + DISPID_SWFEChannels, + DISPID_SWFESamplesPerSec, + DISPID_SWFEAvgBytesPerSec, + DISPID_SWFEBlockAlign, + DISPID_SWFEBitsPerSample, + DISPID_SWFEExtraData, + DISPID_SpeechVoice, + DISPID_SVStatus, + DISPID_SVVoice, + DISPID_SVAudioOutput, + DISPID_SVAudioOutputStream, + DISPID_SVRate, + DISPID_SVVolume, + DISPID_SVAllowAudioOuputFormatChangesOnNextSet, + DISPID_SVEventInterests, + DISPID_SVPriority, + DISPID_SVAlertBoundary, + DISPID_SVSyncronousSpeakTimeout, + DISPID_SVSpeak, + DISPID_SVSpeakStream, + DISPID_SVPause, + DISPID_SVResume, + DISPID_SVSkip, + DISPID_SVGetVoices, + DISPID_SVGetAudioOutputs, + DISPID_SVWaitUntilDone, + DISPID_SVSpeakCompleteEvent, + DISPID_SVIsUISupported, + DISPID_SVDisplayUI, + SpeechVoicePriority, + SVPNormal, + SVPAlert, + SVPOver, + SpeechVoiceSpeakFlags, + SVSFDefault, + SVSFlagsAsync, + SVSFPurgeBeforeSpeak, + SVSFIsFilename, + SVSFIsXML, + SVSFIsNotXML, + SVSFPersistXML, + SVSFNLPSpeakPunc, + SVSFParseSapi, + SVSFParseSsml, + SVSFParseAutodetect, + SVSFNLPMask, + SVSFParseMask, + SVSFVoiceMask, + SVSFUnusedFlags, + SpeechVoiceEvents, + SVEStartInputStream, + SVEEndInputStream, + SVEVoiceChange, + SVEBookmark, + SVEWordBoundary, + SVEPhoneme, + SVESentenceBoundary, + SVEViseme, + SVEAudioLevel, + SVEPrivate, + SVEAllEvents, + DISPID_SpeechVoiceStatus, + DISPID_SVSCurrentStreamNumber, + DISPID_SVSLastStreamNumberQueued, + DISPID_SVSLastResult, + DISPID_SVSRunningState, + DISPID_SVSInputWordPosition, + DISPID_SVSInputWordLength, + DISPID_SVSInputSentencePosition, + DISPID_SVSInputSentenceLength, + DISPID_SVSLastBookmark, + DISPID_SVSLastBookmarkId, + DISPID_SVSPhonemeId, + DISPID_SVSVisemeId, + SpeechRunState, + SRSEDone, + SRSEIsSpeaking, + SpeechVisemeType, + SVP_0, + SVP_1, + SVP_2, + SVP_3, + SVP_4, + SVP_5, + SVP_6, + SVP_7, + SVP_8, + SVP_9, + SVP_10, + SVP_11, + SVP_12, + SVP_13, + SVP_14, + SVP_15, + SVP_16, + SVP_17, + SVP_18, + SVP_19, + SVP_20, + SVP_21, + SpeechVisemeFeature, + SVF_None, + SVF_Stressed, + SVF_Emphasis, + DISPID_SpeechVoiceEvent, + DISPID_SVEStreamStart, + DISPID_SVEStreamEnd, + DISPID_SVEVoiceChange, + DISPID_SVEBookmark, + DISPID_SVEWord, + DISPID_SVEPhoneme, + DISPID_SVESentenceBoundary, + DISPID_SVEViseme, + DISPID_SVEAudioLevel, + DISPID_SVEEnginePrivate, + DISPID_SpeechRecognizer, + DISPID_SRRecognizer, + DISPID_SRAllowAudioInputFormatChangesOnNextSet, + DISPID_SRAudioInput, + DISPID_SRAudioInputStream, + DISPID_SRIsShared, + DISPID_SRState, + DISPID_SRStatus, + DISPID_SRProfile, + DISPID_SREmulateRecognition, + DISPID_SRCreateRecoContext, + DISPID_SRGetFormat, + DISPID_SRSetPropertyNumber, + DISPID_SRGetPropertyNumber, + DISPID_SRSetPropertyString, + DISPID_SRGetPropertyString, + DISPID_SRIsUISupported, + DISPID_SRDisplayUI, + DISPID_SRGetRecognizers, + DISPID_SVGetAudioInputs, + DISPID_SVGetProfiles, + SpeechRecognizerState, + SRSInactive, + SRSActive, + SRSActiveAlways, + SRSInactiveWithPurge, + SpeechDisplayAttributes, + SDA_No_Trailing_Space, + SDA_One_Trailing_Space, + SDA_Two_Trailing_Spaces, + SDA_Consume_Leading_Spaces, + SpeechFormatType, + SFTInput, + SFTSREngine, + SpeechEmulationCompareFlags, + SECFIgnoreCase, + SECFIgnoreKanaType, + SECFIgnoreWidth, + SECFNoSpecialChars, + SECFEmulateResult, + SECFDefault, + DISPID_SpeechRecognizerStatus, + DISPID_SRSAudioStatus, + DISPID_SRSCurrentStreamPosition, + DISPID_SRSCurrentStreamNumber, + DISPID_SRSNumberOfActiveRules, + DISPID_SRSClsidEngine, + DISPID_SRSSupportedLanguages, + DISPID_SpeechRecoContext, + DISPID_SRCRecognizer, + DISPID_SRCAudioInInterferenceStatus, + DISPID_SRCRequestedUIType, + DISPID_SRCVoice, + DISPID_SRAllowVoiceFormatMatchingOnNextSet, + DISPID_SRCVoicePurgeEvent, + DISPID_SRCEventInterests, + DISPID_SRCCmdMaxAlternates, + DISPID_SRCState, + DISPID_SRCRetainedAudio, + DISPID_SRCRetainedAudioFormat, + DISPID_SRCPause, + DISPID_SRCResume, + DISPID_SRCCreateGrammar, + DISPID_SRCCreateResultFromMemory, + DISPID_SRCBookmark, + DISPID_SRCSetAdaptationData, + SpeechRetainedAudioOptions, + SRAONone, + SRAORetainAudio, + SpeechBookmarkOptions, + SBONone, + SBOPause, + SpeechInterference, + SINone, + SINoise, + SINoSignal, + SITooLoud, + SITooQuiet, + SITooFast, + SITooSlow, + SpeechRecoEvents, + SREStreamEnd, + SRESoundStart, + SRESoundEnd, + SREPhraseStart, + SRERecognition, + SREHypothesis, + SREBookmark, + SREPropertyNumChange, + SREPropertyStringChange, + SREFalseRecognition, + SREInterference, + SRERequestUI, + SREStateChange, + SREAdaptation, + SREStreamStart, + SRERecoOtherContext, + SREAudioLevel, + SREPrivate, + SREAllEvents, + SpeechRecoContextState, + SRCS_Disabled, + SRCS_Enabled, + DISPIDSPRG, + DISPID_SRGId, + DISPID_SRGRecoContext, + DISPID_SRGState, + DISPID_SRGRules, + DISPID_SRGReset, + DISPID_SRGCommit, + DISPID_SRGCmdLoadFromFile, + DISPID_SRGCmdLoadFromObject, + DISPID_SRGCmdLoadFromResource, + DISPID_SRGCmdLoadFromMemory, + DISPID_SRGCmdLoadFromProprietaryGrammar, + DISPID_SRGCmdSetRuleState, + DISPID_SRGCmdSetRuleIdState, + DISPID_SRGDictationLoad, + DISPID_SRGDictationUnload, + DISPID_SRGDictationSetState, + DISPID_SRGSetWordSequenceData, + DISPID_SRGSetTextSelection, + DISPID_SRGIsPronounceable, + SpeechLoadOption, + SLOStatic, + SLODynamic, + SpeechWordPronounceable, + SWPUnknownWordUnpronounceable, + SWPUnknownWordPronounceable, + SWPKnownWordPronounceable, + SpeechGrammarState, + SGSEnabled, + SGSDisabled, + SGSExclusive, + SpeechRuleState, + SGDSInactive, + SGDSActive, + SGDSActiveWithAutoPause, + SGDSActiveUserDelimited, + SpeechRuleAttributes, + SRATopLevel, + SRADefaultToActive, + SRAExport, + SRAImport, + SRAInterpreter, + SRADynamic, + SRARoot, + SpeechGrammarWordType, + SGDisplay, + SGLexical, + SGPronounciation, + SGLexicalNoSpecialChars, + DISPID_SpeechRecoContextEvents, + DISPID_SRCEStartStream, + DISPID_SRCEEndStream, + DISPID_SRCEBookmark, + DISPID_SRCESoundStart, + DISPID_SRCESoundEnd, + DISPID_SRCEPhraseStart, + DISPID_SRCERecognition, + DISPID_SRCEHypothesis, + DISPID_SRCEPropertyNumberChange, + DISPID_SRCEPropertyStringChange, + DISPID_SRCEFalseRecognition, + DISPID_SRCEInterference, + DISPID_SRCERequestUI, + DISPID_SRCERecognizerStateChange, + DISPID_SRCEAdaptation, + DISPID_SRCERecognitionForOtherContext, + DISPID_SRCEAudioLevel, + DISPID_SRCEEnginePrivate, + SpeechRecognitionType, + SRTStandard, + SRTAutopause, + SRTEmulated, + SRTSMLTimeout, + SRTExtendableParse, + SRTReSent, + DISPID_SpeechGrammarRule, + DISPID_SGRAttributes, + DISPID_SGRInitialState, + DISPID_SGRName, + DISPID_SGRId, + DISPID_SGRClear, + DISPID_SGRAddResource, + DISPID_SGRAddState, + DISPID_SpeechGrammarRules, + DISPID_SGRsCount, + DISPID_SGRsDynamic, + DISPID_SGRsAdd, + DISPID_SGRsCommit, + DISPID_SGRsCommitAndSave, + DISPID_SGRsFindRule, + DISPID_SGRsItem, + DISPID_SGRs_NewEnum, + DISPID_SpeechGrammarRuleState, + DISPID_SGRSRule, + DISPID_SGRSTransitions, + DISPID_SGRSAddWordTransition, + DISPID_SGRSAddRuleTransition, + DISPID_SGRSAddSpecialTransition, + SpeechSpecialTransitionType, + SSTTWildcard, + SSTTDictation, + SSTTTextBuffer, + DISPID_SpeechGrammarRuleStateTransitions, + DISPID_SGRSTsCount, + DISPID_SGRSTsItem, + DISPID_SGRSTs_NewEnum, + DISPID_SpeechGrammarRuleStateTransition, + DISPID_SGRSTType, + DISPID_SGRSTText, + DISPID_SGRSTRule, + DISPID_SGRSTWeight, + DISPID_SGRSTPropertyName, + DISPID_SGRSTPropertyId, + DISPID_SGRSTPropertyValue, + DISPID_SGRSTNextState, + SpeechGrammarRuleStateTransitionType, + SGRSTTEpsilon, + SGRSTTWord, + SGRSTTRule, + SGRSTTDictation, + SGRSTTWildcard, + SGRSTTTextBuffer, + DISPIDSPTSI, + DISPIDSPTSI_ActiveOffset, + DISPIDSPTSI_ActiveLength, + DISPIDSPTSI_SelectionOffset, + DISPIDSPTSI_SelectionLength, + DISPID_SpeechRecoResult, + DISPID_SRRRecoContext, + DISPID_SRRTimes, + DISPID_SRRAudioFormat, + DISPID_SRRPhraseInfo, + DISPID_SRRAlternates, + DISPID_SRRAudio, + DISPID_SRRSpeakAudio, + DISPID_SRRSaveToMemory, + DISPID_SRRDiscardResultInfo, + SpeechDiscardType, + SDTProperty, + SDTReplacement, + SDTRule, + SDTDisplayText, + SDTLexicalForm, + SDTPronunciation, + SDTAudio, + SDTAlternates, + SDTAll, + DISPID_SpeechXMLRecoResult, + DISPID_SRRGetXMLResult, + DISPID_SRRGetXMLErrorInfo, + DISPID_SpeechRecoResult2, + DISPID_SRRSetTextFeedback, + DISPID_SpeechPhraseBuilder, + DISPID_SPPBRestorePhraseFromMemory, + DISPID_SpeechRecoResultTimes, + DISPID_SRRTStreamTime, + DISPID_SRRTLength, + DISPID_SRRTTickCount, + DISPID_SRRTOffsetFromStart, + DISPID_SpeechPhraseAlternate, + DISPID_SPARecoResult, + DISPID_SPAStartElementInResult, + DISPID_SPANumberOfElementsInResult, + DISPID_SPAPhraseInfo, + DISPID_SPACommit, + DISPID_SpeechPhraseAlternates, + DISPID_SPAsCount, + DISPID_SPAsItem, + DISPID_SPAs_NewEnum, + DISPID_SpeechPhraseInfo, + DISPID_SPILanguageId, + DISPID_SPIGrammarId, + DISPID_SPIStartTime, + DISPID_SPIAudioStreamPosition, + DISPID_SPIAudioSizeBytes, + DISPID_SPIRetainedSizeBytes, + DISPID_SPIAudioSizeTime, + DISPID_SPIRule, + DISPID_SPIProperties, + DISPID_SPIElements, + DISPID_SPIReplacements, + DISPID_SPIEngineId, + DISPID_SPIEnginePrivateData, + DISPID_SPISaveToMemory, + DISPID_SPIGetText, + DISPID_SPIGetDisplayAttributes, + DISPID_SpeechPhraseElement, + DISPID_SPEAudioTimeOffset, + DISPID_SPEAudioSizeTime, + DISPID_SPEAudioStreamOffset, + DISPID_SPEAudioSizeBytes, + DISPID_SPERetainedStreamOffset, + DISPID_SPERetainedSizeBytes, + DISPID_SPEDisplayText, + DISPID_SPELexicalForm, + DISPID_SPEPronunciation, + DISPID_SPEDisplayAttributes, + DISPID_SPERequiredConfidence, + DISPID_SPEActualConfidence, + DISPID_SPEEngineConfidence, + SpeechEngineConfidence, + SECLowConfidence, + SECNormalConfidence, + SECHighConfidence, + DISPID_SpeechPhraseElements, + DISPID_SPEsCount, + DISPID_SPEsItem, + DISPID_SPEs_NewEnum, + DISPID_SpeechPhraseReplacement, + DISPID_SPRDisplayAttributes, + DISPID_SPRText, + DISPID_SPRFirstElement, + DISPID_SPRNumberOfElements, + DISPID_SpeechPhraseReplacements, + DISPID_SPRsCount, + DISPID_SPRsItem, + DISPID_SPRs_NewEnum, + DISPID_SpeechPhraseProperty, + DISPID_SPPName, + DISPID_SPPId, + DISPID_SPPValue, + DISPID_SPPFirstElement, + DISPID_SPPNumberOfElements, + DISPID_SPPEngineConfidence, + DISPID_SPPConfidence, + DISPID_SPPParent, + DISPID_SPPChildren, + DISPID_SpeechPhraseProperties, + DISPID_SPPsCount, + DISPID_SPPsItem, + DISPID_SPPs_NewEnum, + DISPID_SpeechPhraseRule, + DISPID_SPRuleName, + DISPID_SPRuleId, + DISPID_SPRuleFirstElement, + DISPID_SPRuleNumberOfElements, + DISPID_SPRuleParent, + DISPID_SPRuleChildren, + DISPID_SPRuleConfidence, + DISPID_SPRuleEngineConfidence, + DISPID_SpeechPhraseRules, + DISPID_SPRulesCount, + DISPID_SPRulesItem, + DISPID_SPRules_NewEnum, + DISPID_SpeechLexicon, + DISPID_SLGenerationId, + DISPID_SLGetWords, + DISPID_SLAddPronunciation, + DISPID_SLAddPronunciationByPhoneIds, + DISPID_SLRemovePronunciation, + DISPID_SLRemovePronunciationByPhoneIds, + DISPID_SLGetPronunciations, + DISPID_SLGetGenerationChange, + SpeechLexiconType, + SLTUser, + SLTApp, + SpeechPartOfSpeech, + SPSNotOverriden, + SPSUnknown, + SPSNoun, + SPSVerb, + SPSModifier, + SPSFunction, + SPSInterjection, + SPSLMA, + SPSSuppressWord, + DISPID_SpeechLexiconWords, + DISPID_SLWsCount, + DISPID_SLWsItem, + DISPID_SLWs_NewEnum, + SpeechWordType, + SWTAdded, + SWTDeleted, + DISPID_SpeechLexiconWord, + DISPID_SLWLangId, + DISPID_SLWType, + DISPID_SLWWord, + DISPID_SLWPronunciations, + DISPID_SpeechLexiconProns, + DISPID_SLPsCount, + DISPID_SLPsItem, + DISPID_SLPs_NewEnum, + DISPID_SpeechLexiconPronunciation, + DISPID_SLPType, + DISPID_SLPLangId, + DISPID_SLPPartOfSpeech, + DISPID_SLPPhoneIds, + DISPID_SLPSymbolic, + DISPID_SpeechPhoneConverter, + DISPID_SPCLangId, + DISPID_SPCPhoneToId, + DISPID_SPCIdToPhone, + LIBID_SpeechLib, + ISpeechDataKey, ISpeechDataKeyVtbl, + ISpeechObjectToken, ISpeechObjectTokenVtbl, + ISpeechObjectTokens, ISpeechObjectTokensVtbl, + ISpeechObjectTokenCategory, ISpeechObjectTokenCategoryVtbl, + ISpeechAudioBufferInfo, ISpeechAudioBufferInfoVtbl, + ISpeechAudioStatus, ISpeechAudioStatusVtbl, + ISpeechAudioFormat, ISpeechAudioFormatVtbl, + ISpeechWaveFormatEx, ISpeechWaveFormatExVtbl, + ISpeechBaseStream, ISpeechBaseStreamVtbl, + ISpeechFileStream, ISpeechFileStreamVtbl, + ISpeechMemoryStream, ISpeechMemoryStreamVtbl, + ISpeechCustomStream, ISpeechCustomStreamVtbl, + ISpeechAudio, ISpeechAudioVtbl, + ISpeechMMSysAudio, ISpeechMMSysAudioVtbl, + ISpeechVoice, ISpeechVoiceVtbl, + ISpeechVoiceStatus, ISpeechVoiceStatusVtbl, + _ISpeechVoiceEvents, _ISpeechVoiceEventsVtbl, + ISpeechRecognizer, ISpeechRecognizerVtbl, + ISpeechRecognizerStatus, ISpeechRecognizerStatusVtbl, + ISpeechRecoContext, ISpeechRecoContextVtbl, + ISpeechRecoGrammar, ISpeechRecoGrammarVtbl, + _ISpeechRecoContextEvents, _ISpeechRecoContextEventsVtbl, + ISpeechGrammarRule, ISpeechGrammarRuleVtbl, + ISpeechGrammarRules, ISpeechGrammarRulesVtbl, + ISpeechGrammarRuleState, ISpeechGrammarRuleStateVtbl, + ISpeechGrammarRuleStateTransition, ISpeechGrammarRuleStateTransitionVtbl, + ISpeechGrammarRuleStateTransitions, ISpeechGrammarRuleStateTransitionsVtbl, + ISpeechTextSelectionInformation, ISpeechTextSelectionInformationVtbl, + ISpeechRecoResult, ISpeechRecoResultVtbl, + ISpeechRecoResult2, ISpeechRecoResult2Vtbl, + ISpeechRecoResultTimes, ISpeechRecoResultTimesVtbl, + ISpeechPhraseAlternate, ISpeechPhraseAlternateVtbl, + ISpeechPhraseAlternates, ISpeechPhraseAlternatesVtbl, + ISpeechPhraseInfo, ISpeechPhraseInfoVtbl, + ISpeechPhraseElement, ISpeechPhraseElementVtbl, + ISpeechPhraseElements, ISpeechPhraseElementsVtbl, + ISpeechPhraseReplacement, ISpeechPhraseReplacementVtbl, + ISpeechPhraseReplacements, ISpeechPhraseReplacementsVtbl, + ISpeechPhraseProperty, ISpeechPhrasePropertyVtbl, + ISpeechPhraseProperties, ISpeechPhrasePropertiesVtbl, + ISpeechPhraseRule, ISpeechPhraseRuleVtbl, + ISpeechPhraseRules, ISpeechPhraseRulesVtbl, + ISpeechLexicon, ISpeechLexiconVtbl, + ISpeechLexiconWords, ISpeechLexiconWordsVtbl, + ISpeechLexiconWord, ISpeechLexiconWordVtbl, + ISpeechLexiconPronunciations, ISpeechLexiconPronunciationsVtbl, + ISpeechLexiconPronunciation, ISpeechLexiconPronunciationVtbl, + Speech_Default_Weight, + Speech_Max_Word_Length, + Speech_Max_Pron_Length, + Speech_StreamPos_Asap, + Speech_StreamPos_RealTime, + SpeechAllElements, + ISpeechXMLRecoResult, ISpeechXMLRecoResultVtbl, + ISpeechRecoResultDispatch, ISpeechRecoResultDispatchVtbl, + ISpeechPhraseInfoBuilder, ISpeechPhraseInfoBuilderVtbl, + ISpeechPhoneConverter, ISpeechPhoneConverterVtbl, + CLSID_SpNotifyTranslator, + CLSID_SpObjectTokenCategory, + CLSID_SpObjectToken, + CLSID_SpResourceManager, + CLSID_SpStreamFormatConverter, + CLSID_SpMMAudioEnum, + CLSID_SpMMAudioIn, + CLSID_SpMMAudioOut, + CLSID_SpStream, + CLSID_SpVoice, + CLSID_SpSharedRecoContext, + CLSID_SpInprocRecognizer, + CLSID_SpSharedRecognizer, + CLSID_SpLexicon, + CLSID_SpUnCompressedLexicon, + CLSID_SpCompressedLexicon, + CLSID_SpShortcut, + CLSID_SpPhoneConverter, + CLSID_SpPhoneticAlphabetConverter, + CLSID_SpNullPhoneConverter, + CLSID_SpTextSelectionInformation, + CLSID_SpPhraseInfoBuilder, + CLSID_SpAudioFormat, + CLSID_SpWaveFormatEx, + CLSID_SpInProcRecoContext, + CLSID_SpCustomStream, + CLSID_SpFileStream, + CLSID_SpMemoryStream, +}; diff --git a/winapi/src/um/sapi51.rs b/winapi/src/um/sapi51.rs new file mode 100644 index 000000000..db1d46438 --- /dev/null +++ b/winapi/src/um/sapi51.rs @@ -0,0 +1,3726 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! SAPI 5.1 definitions +use ctypes::{c_char, c_float, c_long, c_short, c_ushort, c_void}; +use shared::guiddef::{CLSID, GUID, IID, REFCLSID, REFGUID, REFIID}; +use shared::minwindef::{ + BOOL, BYTE, DWORD, FILETIME, HKEY, HMODULE, LPARAM, UINT, ULONG, USHORT, WORD, WPARAM +}; +use shared::mmreg::WAVEFORMATEX; +use shared::rpcndr::byte; +use shared::windef::HWND; +use shared::wtypes::{BSTR, VARIANT_BOOL}; +use shared::wtypesbase::{ + CLSCTX_INPROC_HANDLER, CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, CLSCTX_REMOTE_SERVER +}; +use um::oaidl::{DISPID_NEWENUM, DISPID_VALUE, IDispatch, IDispatchVtbl, VARIANT}; +use um::objidlbase::{IStream, IStreamVtbl, STREAM_SEEK_CUR, STREAM_SEEK_END, STREAM_SEEK_SET}; +use um::servprov::{IServiceProvider, IServiceProviderVtbl}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LONG, LONGLONG, LPCWSTR, LPWSTR, ULONGLONG, WCHAR}; +ENUM!{enum SPDATAKEYLOCATION { + SPDKL_DefaultLocation = 0, + SPDKL_CurrentUser = 1, + SPDKL_LocalMachine = 2, + SPDKL_CurrentConfig = 5, +}} +pub const SPDUI_EngineProperties: &'static str = "EngineProperties"; +pub const SPDUI_AddRemoveWord: &'static str = "AddRemoveWord"; +pub const SPDUI_UserTraining: &'static str = "UserTraining"; +pub const SPDUI_MicTraining: &'static str = "MicTraining"; +pub const SPDUI_RecoProfileProperties: &'static str = "RecoProfileProperties"; +pub const SPDUI_AudioProperties: &'static str = "AudioProperties"; +pub const SPDUI_AudioVolume: &'static str = "AudioVolume"; +pub const SPDUI_UserEnrollment: &'static str = "UserEnrollment"; +pub const SPDUI_ShareData: &'static str = "ShareData"; +pub const SPDUI_Tutorial: &'static str = "Tutorial"; +ENUM!{enum SPSTREAMFORMAT { + SPSF_Default = -1i32 as u32, + SPSF_NoAssignedFormat = 0, + SPSF_Text = 1, + SPSF_NonStandardFormat = 2, + SPSF_ExtendedAudioFormat = 3, + SPSF_8kHz8BitMono = 4, + SPSF_8kHz8BitStereo = 5, + SPSF_8kHz16BitMono = 6, + SPSF_8kHz16BitStereo = 7, + SPSF_11kHz8BitMono = 8, + SPSF_11kHz8BitStereo = 9, + SPSF_11kHz16BitMono = 10, + SPSF_11kHz16BitStereo = 11, + SPSF_12kHz8BitMono = 12, + SPSF_12kHz8BitStereo = 13, + SPSF_12kHz16BitMono = 14, + SPSF_12kHz16BitStereo = 15, + SPSF_16kHz8BitMono = 16, + SPSF_16kHz8BitStereo = 17, + SPSF_16kHz16BitMono = 18, + SPSF_16kHz16BitStereo = 19, + SPSF_22kHz8BitMono = 20, + SPSF_22kHz8BitStereo = 21, + SPSF_22kHz16BitMono = 22, + SPSF_22kHz16BitStereo = 23, + SPSF_24kHz8BitMono = 24, + SPSF_24kHz8BitStereo = 25, + SPSF_24kHz16BitMono = 26, + SPSF_24kHz16BitStereo = 27, + SPSF_32kHz8BitMono = 28, + SPSF_32kHz8BitStereo = 29, + SPSF_32kHz16BitMono = 30, + SPSF_32kHz16BitStereo = 31, + SPSF_44kHz8BitMono = 32, + SPSF_44kHz8BitStereo = 33, + SPSF_44kHz16BitMono = 34, + SPSF_44kHz16BitStereo = 35, + SPSF_48kHz8BitMono = 36, + SPSF_48kHz8BitStereo = 37, + SPSF_48kHz16BitMono = 38, + SPSF_48kHz16BitStereo = 39, + SPSF_TrueSpeech_8kHz1BitMono = 40, + SPSF_CCITT_ALaw_8kHzMono = 41, + SPSF_CCITT_ALaw_8kHzStereo = 42, + SPSF_CCITT_ALaw_11kHzMono = 43, + SPSF_CCITT_ALaw_11kHzStereo = 44, + SPSF_CCITT_ALaw_22kHzMono = 45, + SPSF_CCITT_ALaw_22kHzStereo = 46, + SPSF_CCITT_ALaw_44kHzMono = 47, + SPSF_CCITT_ALaw_44kHzStereo = 48, + SPSF_CCITT_uLaw_8kHzMono = 49, + SPSF_CCITT_uLaw_8kHzStereo = 50, + SPSF_CCITT_uLaw_11kHzMono = 51, + SPSF_CCITT_uLaw_11kHzStereo = 52, + SPSF_CCITT_uLaw_22kHzMono = 53, + SPSF_CCITT_uLaw_22kHzStereo = 54, + SPSF_CCITT_uLaw_44kHzMono = 55, + SPSF_CCITT_uLaw_44kHzStereo = 56, + SPSF_ADPCM_8kHzMono = 57, + SPSF_ADPCM_8kHzStereo = 58, + SPSF_ADPCM_11kHzMono = 59, + SPSF_ADPCM_11kHzStereo = 60, + SPSF_ADPCM_22kHzMono = 61, + SPSF_ADPCM_22kHzStereo = 62, + SPSF_ADPCM_44kHzMono = 63, + SPSF_ADPCM_44kHzStereo = 64, + SPSF_GSM610_8kHzMono = 65, + SPSF_GSM610_11kHzMono = 66, + SPSF_GSM610_22kHzMono = 67, + SPSF_GSM610_44kHzMono = 68, + SPSF_NUM_FORMATS = 69, +}} +extern { + pub static SPDFID_Text: GUID; + pub static SPDFID_WaveFormatEx: GUID; +} +pub const SPREG_USER_ROOT: &'static str = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Speech"; +pub const SPREG_LOCAL_MACHINE_ROOT: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech"; +pub const SPCAT_AUDIOOUT: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AudioOutput"; +pub const SPCAT_AUDIOIN: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AudioInput"; +pub const SPCAT_VOICES: &'static str = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices"; +pub const SPCAT_RECOGNIZERS: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Recognizers"; +pub const SPCAT_APPLEXICONS: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AppLexicons"; +pub const SPCAT_PHONECONVERTERS: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\PhoneConverters"; +pub const SPCAT_TEXTNORMALIZERS: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\TextNormalizers"; +pub const SPCAT_RECOPROFILES: &'static str + = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Speech\\RecoProfiles"; +pub const SPMMSYS_AUDIO_IN_TOKEN_ID: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AudioInput\\TokenEnums\\MMAudioIn\\"; +pub const SPMMSYS_AUDIO_OUT_TOKEN_ID: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AudioOutput\\TokenEnums\\MMAudioOut\\"; +pub const SPCURRENT_USER_LEXICON_TOKEN_ID: &'static str + = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Speech\\CurrentUserLexicon"; +pub const SPCURRENT_USER_SHORTCUT_TOKEN_ID: &'static str + = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Speech\\CurrentUserShortcut"; +pub const SPTOKENVALUE_CLSID: &'static str = "CLSID"; +pub const SPTOKENKEY_FILES: &'static str = "Files"; +pub const SPTOKENKEY_UI: &'static str = "UI"; +pub const SPTOKENKEY_ATTRIBUTES: &'static str = "Attributes"; +pub const SPVOICECATEGORY_TTSRATE: &'static str = "DefaultTTSRate"; +pub const SPPROP_RESOURCE_USAGE: &'static str = "ResourceUsage"; +pub const SPPROP_HIGH_CONFIDENCE_THRESHOLD: &'static str = "HighConfidenceThreshold"; +pub const SPPROP_NORMAL_CONFIDENCE_THRESHOLD: &'static str = "NormalConfidenceThreshold"; +pub const SPPROP_LOW_CONFIDENCE_THRESHOLD: &'static str = "LowConfidenceThreshold"; +pub const SPPROP_RESPONSE_SPEED: &'static str = "ResponseSpeed"; +pub const SPPROP_COMPLEX_RESPONSE_SPEED: &'static str = "ComplexResponseSpeed"; +pub const SPPROP_ADAPTATION_ON: &'static str = "AdaptationOn"; +pub const SPPROP_PERSISTED_BACKGROUND_ADAPTATION: &'static str = "PersistedBackgroundAdaptation"; +pub const SPPROP_PERSISTED_LANGUAGE_MODEL_ADAPTATION: &'static str + = "PersistedLanguageModelAdaptation"; +pub const SPPROP_UX_IS_LISTENING: &'static str = "UXIsListening"; +pub const SPTOPIC_SPELLING: &'static str = "Spelling"; +pub const SPWILDCARD: &'static str = "..."; +pub const SPDICTATION: &'static str = "*"; +pub const SPINFDICTATION: &'static str = "*+"; +pub const SP_LOW_CONFIDENCE: c_char = -1; +pub const SP_NORMAL_CONFIDENCE: c_char = 0; +pub const SP_HIGH_CONFIDENCE: c_char = 1; +pub const DEFAULT_WEIGHT: c_float = 1.0; +pub const SP_MAX_WORD_LENGTH: ULONG = 128; +pub const SP_MAX_PRON_LENGTH: ULONG = 384; +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface ISpNotifyCallback(ISpNotifyCallbackVtbl) { + fn NotifyCallback( + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, +}} +FN!{stdcall SPNOTIFYCALLBACK( + wParam: WPARAM, + lParam: LPARAM, +) -> ()} +RIDL!{#[uuid(0x5eff4aef, 0x8487, 0x11d2, 0x96, 0x1c, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0x28)] +interface ISpNotifySource(ISpNotifySourceVtbl): IUnknown(IUnknownVtbl) { + fn SetNotifySink( + pNotifySink: *mut ISpNotifySink, + ) -> HRESULT, + fn SetNotifyWindowMessage( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn SetNotifyCallbackFunction( + pfnCallback: SPNOTIFYCALLBACK, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn SetNotifyCallbackInterface( + pSpCallback: *mut ISpNotifyCallback, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn SetNotifyWin32Event() -> HRESULT, + fn WaitForNotifyEvent( + dwMilliseconds: DWORD, + ) -> HRESULT, + fn GetNotifyEventHandle() -> HANDLE, +}} +RIDL!{#[uuid(0x259684dc, 0x37c3, 0x11d2, 0x96, 0x03, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0x28)] +interface ISpNotifySink(ISpNotifySinkVtbl): IUnknown(IUnknownVtbl) { + fn Notify() -> HRESULT, +}} +RIDL!{#[uuid(0xaca16614, 0x5d3d, 0x11d2, 0x96, 0x0e, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0x28)] +interface ISpNotifyTranslator(ISpNotifyTranslatorVtbl): ISpNotifySink(ISpNotifySinkVtbl) { + fn InitWindowMessage( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn InitCallback( + pfnCallback: SPNOTIFYCALLBACK, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn InitSpNotifyCallback( + pSpCallback: *mut ISpNotifyCallback, + wParam: WPARAM, + lParam: LPARAM, + ) -> HRESULT, + fn InitWin32Event( + hEvent: HANDLE, + fCloseHandleOnRelease: BOOL, + ) -> HRESULT, + fn Wait( + dwMilliseconds: DWORD, + ) -> HRESULT, + fn GetEventHandle() -> HANDLE, +}} +RIDL!{#[uuid(0x14056581, 0xe16c, 0x11d2, 0xbb, 0x90, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpDataKey(ISpDataKeyVtbl): IUnknown(IUnknownVtbl) { + fn SetData( + pszValueName: LPCWSTR, + cbData: ULONG, + pData: *const BYTE, + ) -> HRESULT, + fn GetData( + pszValueName: LPCWSTR, + pcbData: *mut ULONG, + pData: *mut BYTE, + ) -> HRESULT, + fn SetStringValue( + pszValueName: LPCWSTR, + pszValue: LPCWSTR, + ) -> HRESULT, + fn GetStringValue( + pszValueName: LPCWSTR, + ppszValue: *mut LPWSTR, + ) -> HRESULT, + fn SetDWORD( + pszValueName: LPCWSTR, + dwValue: DWORD, + ) -> HRESULT, + fn GetDWORD( + pszValueName: LPCWSTR, + pdwValue: *mut DWORD, + ) -> HRESULT, + fn OpenKey( + pszSubKeyName: LPCWSTR, + ppSubKey: *mut *mut ISpDataKey, + ) -> HRESULT, + fn CreateKey( + pszSubKey: LPCWSTR, + ppSubKey: *mut *mut ISpDataKey, + ) -> HRESULT, + fn DeleteKey( + pszSubKey: LPCWSTR, + ) -> HRESULT, + fn DeleteValue( + pszValueName: LPCWSTR, + ) -> HRESULT, + fn EnumKeys( + Index: ULONG, + ppszSubKeyName: *mut LPWSTR, + ) -> HRESULT, + fn EnumValues( + Index: ULONG, + ppszValueName: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x92a66e2b, 0xc830, 0x4149, 0x83, 0xdf, 0x6f, 0xc2, 0xba, 0x1e, 0x7a, 0x5b)] +interface ISpRegDataKey(ISpRegDataKeyVtbl): ISpDataKey(ISpDataKeyVtbl) { + fn SetKey( + hkey: HKEY, + fReadOnly: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2d3d3845, 0x39af, 0x4850, 0xbb, 0xf9, 0x40, 0xb4, 0x97, 0x80, 0x01, 0x1d)] +interface ISpObjectTokenCategory(ISpObjectTokenCategoryVtbl): ISpDataKey(ISpDataKeyVtbl) { + fn SetId( + pszCategoryId: LPCWSTR, + fCreateIfNotExist: BOOL, + ) -> HRESULT, + fn GetId( + ppszCoMemCategoryId: *mut LPWSTR, + ) -> HRESULT, + fn GetDataKey( + spdkl: SPDATAKEYLOCATION, + pppDataKey: *mut *mut ISpDataKey, + ) -> HRESULT, + fn EnumTokens( + pzsReqAttribs: LPCWSTR, + pszOptAttribs: LPCWSTR, + ppEnum: *mut *mut IEnumSpObjectTokens, + ) -> HRESULT, + fn SetDefaultTokenId( + pszTokenId: LPCWSTR, + ) -> HRESULT, + fn GetDefaultTokenId( + ppszCoMemTokenId: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x14056589, 0xe16c, 0x11d2, 0xbb, 0x90, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpObjectToken(ISpObjectTokenVtbl): ISpDataKey(ISpDataKeyVtbl) { + fn SetId( + pszCategoryId: LPCWSTR, + pszTokenId: LPCWSTR, + fCreateIfNotExist: BOOL, + ) -> HRESULT, + fn GetId( + ppszCoMemTokenId: *mut LPWSTR, + ) -> HRESULT, + fn GetCategory( + ppTokenCategory: *mut *mut ISpObjectTokenCategory, + ) -> HRESULT, + fn CreateInstance( + pUnkOuter: *mut IUnknown, + dwClsContext: DWORD, + riid: REFIID, + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn GetStorageFileName( + clsidCaller: REFCLSID, + pszValueName: LPCWSTR, + pszFileNameSpecifier: LPCWSTR, + nFolder: ULONG, + ppszFilePath: *mut LPWSTR, + ) -> HRESULT, + fn RemoveStorageFileName( + pszKeyName: LPCWSTR, + fDeleteFile: BOOL, + ) -> HRESULT, + fn Remove( + pclsidCaller: *const CLSID, + ) -> HRESULT, + fn IsUISupported( + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + punkObject: *mut IUnknown, + pfSupported: *mut BOOL, + ) -> HRESULT, + fn DisplayUI( + hwndParent: HWND, + pszTitle: LPCWSTR, + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + punkObject: *mut IUnknown, + ) -> HRESULT, + fn MatchesAttributes( + pszAttributes: LPCWSTR, + pfMatches: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb8aab0cf, 0x346f, 0x49d8, 0x94, 0x99, 0xc8, 0xb0, 0x3f, 0x16, 0x1d, 0x51)] +interface ISpObjectTokenInit(ISpObjectTokenInitVtbl): ISpObjectToken(ISpObjectTokenVtbl) { + fn InitFromDataKey( + pszCategoryId: LPCWSTR, + pszTokenId: LPCWSTR, + pDataKey: *mut ISpDataKey, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x06b64f9e, 0x7fda, 0x11d2, 0xb4, 0xf2, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96)] +interface IEnumSpObjectTokens(IEnumSpObjectTokensVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + pelt: *mut *mut ISpObjectToken, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppEnum: *mut *mut IEnumSpObjectTokens, + ) -> HRESULT, + fn Item( + Index: ULONG, + ppToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn GetCount( + pCount: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5b559f40, 0xe952, 0x11d2, 0xbb, 0x91, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpObjectWithToken(ISpObjectWithTokenVtbl): IUnknown(IUnknownVtbl) { + fn SetObjectToken( + pToken: *mut ISpObjectToken, + ) -> HRESULT, + fn GetObjectToken( + ppToken: *mut *mut ISpObjectToken, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x93384e18, 0x5014, 0x43d5, 0xad, 0xbb, 0xa7, 0x8e, 0x05, 0x59, 0x26, 0xbd)] +interface ISpResourceManager(ISpResourceManagerVtbl): IServiceProvider(IServiceProviderVtbl) { + fn SetObject( + guidServiceId: REFGUID, + pUnkObject: *mut IUnknown, + ) -> HRESULT, + fn GetObject( + guidServiceId: REFGUID, + ObjectCLSID: REFCLSID, + ObjectIID: REFIID, + fReleaseWhenLastExternalRefReleased: BOOL, + ppObject: *mut *mut c_void, + ) -> HRESULT, +}} +ENUM!{enum SPEVENTLPARAMTYPE { + SPET_LPARAM_IS_UNDEFINED = 0, + SPET_LPARAM_IS_TOKEN, + SPET_LPARAM_IS_OBJECT, + SPET_LPARAM_IS_POINTER, + SPET_LPARAM_IS_STRING, +}} +ENUM!{enum SPEVENTENUM { + SPEI_UNDEFINED = 0, + SPEI_START_INPUT_STREAM = 1, + SPEI_END_INPUT_STREAM = 2, + SPEI_VOICE_CHANGE = 3, + SPEI_TTS_BOOKMARK = 4, + SPEI_WORD_BOUNDARY = 5, + SPEI_PHONEME = 6, + SPEI_SENTENCE_BOUNDARY = 7, + SPEI_VISEME = 8, + SPEI_TTS_AUDIO_LEVEL = 9, + SPEI_TTS_PRIVATE = 15, + SPEI_MIN_TTS = 1, + SPEI_MAX_TTS = 15, + SPEI_END_SR_STREAM = 34, + SPEI_SOUND_START = 35, + SPEI_SOUND_END = 36, + SPEI_PHRASE_START = 37, + SPEI_RECOGNITION = 38, + SPEI_HYPOTHESIS = 39, + SPEI_SR_BOOKMARK = 40, + SPEI_PROPERTY_NUM_CHANGE = 41, + SPEI_PROPERTY_STRING_CHANGE = 42, + SPEI_FALSE_RECOGNITION = 43, + SPEI_INTERFERENCE = 44, + SPEI_REQUEST_UI = 45, + SPEI_RECO_STATE_CHANGE = 46, + SPEI_ADAPTATION = 47, + SPEI_START_SR_STREAM = 48, + SPEI_RECO_OTHER_CONTEXT = 49, + SPEI_SR_AUDIO_LEVEL = 50, + SPEI_SR_PRIVATE = 52, + SPEI_MIN_SR = 34, + SPEI_MAX_SR = 52, + SPEI_RESERVED1 = 30, + SPEI_RESERVED2 = 33, + SPEI_RESERVED3 = 63, +}} +pub const SPFEI_FLAGCHECK: ULONGLONG = (1 << SPEI_RESERVED1) | (1 << SPEI_RESERVED2); +pub const SPFEI_ALL_TTS_EVENTS: ULONGLONG = 0x000000000000FFFE | SPFEI_FLAGCHECK; +pub const SPFEI_ALL_SR_EVENTS: ULONGLONG = 0x003FFFFC00000000 | SPFEI_FLAGCHECK; +pub const SPFEI_ALL_EVENTS: ULONGLONG = 0xEFFFFFFFFFFFFFFF; +#[inline] +pub fn SPFEI( + SPEI_ord: SPEVENTENUM, + ) -> ULONGLONG { + (1 << SPEI_ord) | SPFEI_FLAGCHECK +} +STRUCT!{struct SPEVENT { + bitfields: DWORD, + ulStreamNum: ULONG, + ullAudioStreamOffset: ULONGLONG, + wParam: WPARAM, + lParam: LPARAM, +}} +BITFIELD!{SPEVENT bitfields: SPEVENTENUM [ eEventId set_eEventId[0..16], ]} +BITFIELD!{SPEVENT bitfields: SPEVENTLPARAMTYPE [ elParamType set_elParamType[16..32], ]} +STRUCT!{struct SPSERIALIZEDEVENT { + bitfields: DWORD, + ulStreamNum: ULONG, + ullAudioStreamOffset: ULONGLONG, + SerializedwParam: ULONG, + SerializedlParam: LONG, +}} +BITFIELD!{SPSERIALIZEDEVENT bitfields: SPEVENTENUM [ eEventId set_eEventId[0..16], ]} +BITFIELD!{SPSERIALIZEDEVENT bitfields: SPEVENTLPARAMTYPE [ elParamType set_elParamType[16..32], ]} +STRUCT!{struct SPSERIALIZEDEVENT64 { + bitfields: DWORD, + ulStreamNum: ULONG, + ullAudioStreamOffset: ULONGLONG, + SerializedwParam: ULONGLONG, + SerializedlParam: LONGLONG, +}} +BITFIELD!{SPSERIALIZEDEVENT64 bitfields: SPEVENTENUM [ + eEventId set_eEventId[0..16], +]} +BITFIELD!{SPSERIALIZEDEVENT64 bitfields: SPEVENTLPARAMTYPE [ + elParamType set_elParamType[16..32], +]} +ENUM!{enum SPINTERFERENCE { + SPINTERFERENCE_NONE = 0, + SPINTERFERENCE_NOISE, + SPINTERFERENCE_NOSIGNAL, + SPINTERFERENCE_TOOLOUD, + SPINTERFERENCE_TOOQUIET, + SPINTERFERENCE_TOOFAST, + SPINTERFERENCE_TOOSLOW, + SPINTERFERENCE_LATENCY_WARNING, + SPINTERFERENCE_LATENCY_TRUNCATE_BEGIN , + SPINTERFERENCE_LATENCY_TRUNCATE_END, +}} +ENUM!{enum SPENDSRSTREAMFLAGS { + SPESF_NONE = 0, + SPESF_STREAM_RELEASED = 1 << 0, + SPESF_EMULATED = 1 << 1, +}} +ENUM!{enum SPVFEATURE { + SPVFEATURE_STRESSED = 1 << 0, + SPVFEATURE_EMPHASIS = 1 << 1, +}} +ENUM!{enum SPVISEMES { + SP_VISEME_0 = 0, + SP_VISEME_1, + SP_VISEME_2, + SP_VISEME_3, + SP_VISEME_4, + SP_VISEME_5, + SP_VISEME_6, + SP_VISEME_7, + SP_VISEME_8, + SP_VISEME_9, + SP_VISEME_10, + SP_VISEME_11, + SP_VISEME_12, + SP_VISEME_13, + SP_VISEME_14, + SP_VISEME_15, + SP_VISEME_16, + SP_VISEME_17, + SP_VISEME_18, + SP_VISEME_19, + SP_VISEME_20, + SP_VISEME_21, +}} +STRUCT!{struct SPEVENTSOURCEINFO { + ullEventInterest: ULONGLONG, + ullQueuedInterest: ULONGLONG, + ulCount: ULONG, +}} +RIDL!{#[uuid(0xbe7a9cce, 0x5f9e, 0x11d2, 0x96, 0x0f, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0x28)] +interface ISpEventSource(ISpEventSourceVtbl): ISpNotifySource(ISpNotifySourceVtbl) { + fn SetInterest( + ullEventInterest: ULONGLONG, + ullQueuedInterest: ULONGLONG, + ) -> HRESULT, + fn GetEvents( + ulCount: ULONG, + pEventArray: *mut SPEVENT, + pulFetched: *mut ULONG, + ) -> HRESULT, + fn GetInfo( + pInfo: *mut SPEVENTSOURCEINFO, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbe7a9cc9, 0x5f9e, 0x11d2, 0x96, 0x0f, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0x28)] +interface ISpEventSink(ISpEventSinkVtbl): IUnknown(IUnknownVtbl) { + fn AddEvents( + pEventArray: *const SPEVENT, + ulCount: ULONG, + ) -> HRESULT, + fn GetEventInterest( + pullEventInterest: *mut ULONGLONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbed530be, 0x2606, 0x4f4d, 0xa1, 0xc0, 0x54, 0xc5, 0xcd, 0xa5, 0x56, 0x6f)] +interface ISpStreamFormat(ISpStreamFormatVtbl): IStream(IStreamVtbl) { + fn GetFormat( + pguidFormatId: *mut GUID, + ppCoMemWaveFormatEx: *mut *mut WAVEFORMATEX, + ) -> HRESULT, +}} +ENUM!{enum SPFILEMODE { + SPFM_OPEN_READONLY, + SPFM_OPEN_READWRITE, + SPFM_CREATE, + SPFM_CREATE_ALWAYS, + SPFM_NUM_MODES, +}} +RIDL!{#[uuid(0x12e3cca9, 0x7518, 0x44c5, 0xa5, 0xe7, 0xba, 0x5a, 0x79, 0xcb, 0x92, 0x9e)] +interface ISpStream(ISpStreamVtbl): ISpStreamFormat(ISpStreamFormatVtbl) { + fn SetBaseStream( + pStream: *mut IStream, + rguidFormat: REFGUID, + pWaveFormatEx: *const WAVEFORMATEX, + ) -> HRESULT, + fn GetBaseStream( + ppStream: *mut *mut IStream, + ) -> HRESULT, + fn BindToFile( + pszFileName: LPCWSTR, + eMode: SPFILEMODE, + pFormatId: *const GUID, + pWaveFormatEx: *const WAVEFORMATEX, + ullEventInterest: ULONGLONG, + ) -> HRESULT, + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0x678a932c, 0xea71, 0x4446, 0x9b, 0x41, 0x78, 0xfd, 0xa6, 0x28, 0x0a, 0x29)] +interface ISpStreamFormatConverter(ISpStreamFormatConverterVtbl): + ISpStreamFormat(ISpStreamFormatVtbl) { + fn SetBaseStream( + pStream: *mut ISpStreamFormat, + fSetFormatToBaseStreamFormat: BOOL, + fWriteToBaseStream: BOOL, + ) -> HRESULT, + fn GetBaseStream( + ppStream: *mut *mut ISpStreamFormat, + ) -> HRESULT, + fn SetFormat( + rguidFormatIdOfConvertedStream: REFGUID, + pWaveFormatExOfConvertedStream: *const WAVEFORMATEX, + ) -> HRESULT, + fn ResetSeekPosition() -> HRESULT, + fn ScaleConvertedToBaseOffset( + ullOffsetConvertedStream: ULONGLONG, + pullOffsetBaseStream: *mut ULONGLONG, + ) -> HRESULT, + fn ScaleBaseToConvertedOffset( + ullOffsetBaseStream: ULONGLONG, + pullOffsetConvertedStream: *mut ULONGLONG, + ) -> HRESULT, +}} +ENUM!{enum SPAUDIOSTATE { + SPAS_CLOSED, + SPAS_STOP, + SPAS_PAUSE, + SPAS_RUN, +}} +STRUCT!{struct SPAUDIOSTATUS { + cbFreeBuffSpace: c_long, + cbNonBlockingIO: ULONG, + State: SPAUDIOSTATE, + CurSeekPos: ULONGLONG, + CurDevicePos: ULONGLONG, + dwAudioLevel: DWORD, + dwReserved2: DWORD, +}} +STRUCT!{struct SPAUDIOBUFFERINFO { + ulMsMinNotification: ULONG, + ulMsBufferSize: ULONG, + ulMsEventBias: ULONG, +}} +RIDL!{#[uuid(0xc05c768f, 0xfae8, 0x4ec2, 0x8e, 0x07, 0x33, 0x83, 0x21, 0xc1, 0x24, 0x52)] +interface ISpAudio(ISpAudioVtbl): ISpStreamFormat(ISpStreamFormatVtbl) { + fn SetState( + NewState: SPAUDIOSTATE, + ullReserved: ULONGLONG, + ) -> HRESULT, + fn SetFormat( + rguidFmtId: REFGUID, + pWaveFormatEx: *const WAVEFORMATEX, + ) -> HRESULT, + fn GetStatus( + pStatus: *mut SPAUDIOSTATUS, + ) -> HRESULT, + fn SetBufferInfo( + pBuffInfo: *const SPAUDIOBUFFERINFO, + ) -> HRESULT, + fn GetBufferInfo( + pBuffInfo: *mut SPAUDIOBUFFERINFO, + ) -> HRESULT, + fn GetDefaultFormat( + pFormatId: *mut GUID, + ppCoMemWaveFormatEx: *mut *mut WAVEFORMATEX, + ) -> HRESULT, + fn EventHandle() -> HANDLE, + fn GetVolumeLevel( + pLevel: *mut ULONG, + ) -> HRESULT, + fn SetVolumeLevel( + Level: ULONG, + ) -> HRESULT, + fn GetBufferNotifySize( + pcbSize: *mut ULONG, + ) -> HRESULT, + fn SetBufferNotifySize( + cbSize: ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x15806f6e, 0x1d70, 0x4b48, 0x98, 0xe6, 0x3b, 0x1a, 0x00, 0x75, 0x09, 0xab)] +interface ISpMMSysAudio(ISpMMSysAudioVtbl): ISpAudio(ISpAudioVtbl) { + fn GetDeviceId( + puDeviceId: *mut UINT, + ) -> HRESULT, + fn SetDeviceId( + uDeviceId: UINT, + ) -> HRESULT, + fn GetMMHandle( + pHandle: *mut *mut c_void, + ) -> HRESULT, + fn GetLineId( + puLineId: *mut UINT, + ) -> HRESULT, + fn SetLineId( + uLineId: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x10f63bce, 0x201a, 0x11d3, 0xac, 0x70, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpTranscript(ISpTranscriptVtbl): IUnknown(IUnknownVtbl) { + fn GetTranscript( + ppszTranscript: *mut LPWSTR, + ) -> HRESULT, + fn AppendTranscript( + pszTranscript: LPCWSTR, + ) -> HRESULT, +}} +ENUM!{enum SPDISPLAYATTRIBUTES { + SPAF_ONE_TRAILING_SPACE = 0x2, + SPAF_TWO_TRAILING_SPACES = 0x4, + SPAF_CONSUME_LEADING_SPACES = 0x8, + SPAF_ALL = 0xf, +}} +pub type SPPHONEID = WCHAR; +pub type PSPPHONEID = LPWSTR; +pub type PCSPPHONEID = LPCWSTR; +STRUCT!{struct SPPHRASEELEMENT { + ulAudioTimeOffset: ULONG, + ulAudioSizeTime: ULONG, + ulAudioStreamOffset: ULONG, + ulAudioSizeBytes: ULONG, + ulRetainedStreamOffset: ULONG, + ulRetainedSizeBytes: ULONG, + pszDisplayText: LPCWSTR, + pszLexicalForm: LPCWSTR, + pszPronunciation: *const SPPHONEID, + bDisplayAttributes: BYTE, + RequiredConfidence: c_char, + ActualConfidence: c_char, + Reserved: BYTE, + SREngineConfidence: c_float, +}} +STRUCT!{struct SPPHRASERULE { + pszName: LPCWSTR, + ulId: ULONG, + ulFirstElement: ULONG, + ulCountOfElements: ULONG, + pNextSibling: *const SPPHRASERULE, + pFirstChild: *const SPPHRASERULE, + SREngineConfidence: c_float, + Confidence: c_char, +}} +ENUM!{enum SPPHRASEPROPERTYUNIONTYPE { + SPPPUT_UNUSED = 0, + SPPPUT_ARRAY_INDEX, +}} +STRUCT!{struct SPPHRASEPROPERTY_u_s { + bType: byte, + bReserved: byte, + usArrayIndex: c_ushort, +}} +UNION!{union SPPHRASEPROPERTY_u { + [u32; 1], + ulId ulId_mut: ULONG, + s s_mut: SPPHRASEPROPERTY_u_s, +}} +STRUCT!{struct SPPHRASEPROPERTY { + pszName: LPCWSTR, + u: SPPHRASEPROPERTY_u_s, + pszValue: LPCWSTR, + vValue: VARIANT, + ulFirstElement: ULONG, + ulCountOfElements: ULONG, + pNextSibling: *const SPPHRASEPROPERTY, + pFirstChild: *const SPPHRASEPROPERTY, + SREngineConfidence: c_float, + Confidence: c_char, +}} +STRUCT!{struct SPPHRASEREPLACEMENT { + bDisplayAttributes: BYTE, + pszReplacementText: LPCWSTR, + ulFirstElement: ULONG, + ulCountOfElements: ULONG, +}} +STRUCT!{struct SPPHRASE { + cbSize: ULONG, + LangID: WORD, + wHomophoneGroupId: WORD, + ullGrammarID: ULONGLONG, + ftStartTime: ULONGLONG, + ullAudioStreamPosition: ULONGLONG, + ulAudioSizeBytes: ULONG, + ulRetainedSizeBytes: ULONG, + ulAudioSizeTime: ULONG, + Rule: SPPHRASERULE, + pProperties: *const SPPHRASEPROPERTY, + pElements: *const SPPHRASEELEMENT, + cReplacements: ULONG, + pReplacements: *const SPPHRASEREPLACEMENT, + SREngineID: GUID, + ulSREnginePrivateDataSize: ULONG, + pSREnginePrivateData: *const BYTE, +}} +STRUCT!{struct SPSERIALIZEDPHRASE { + ulSerializedSize: ULONG, +}} +ENUM!{enum SPVALUETYPE { + SPDF_PROPERTY = 0x1, + SPDF_REPLACEMENT = 0x2, + SPDF_RULE = 0x4, + SPDF_DISPLAYTEXT = 0x8, + SPDF_LEXICALFORM = 0x10, + SPDF_PRONUNCIATION = 0x20, + SPDF_AUDIO = 0x40, + SPDF_ALTERNATES = 0x80, + SPDF_ALL = 0xff, +}} +STRUCT!{struct SPBINARYGRAMMAR { + ulTotalSerializedSize: ULONG, +}} +ENUM!{enum SPPHRASERNG { + SPPR_ALL_ELEMENTS = -1i32 as u32, +}} +pub const SP_GETWHOLEPHRASE: SPPHRASERNG = SPPR_ALL_ELEMENTS; +pub const SPRR_ALL_ELEMENTS: SPPHRASERNG = SPPR_ALL_ELEMENTS; +DECLARE_HANDLE!{SPSTATEHANDLE, SPSTATEHANDLE__} +ENUM!{enum SPRECOEVENTFLAGS { + SPREF_AutoPause = 1 << 0, + SPREF_Emulated = 1 << 1, +}} +ENUM!{enum SPPARTOFSPEECH { + SPPS_NotOverriden = -1i32 as u32, + SPPS_Unknown = 0, + SPPS_Noun = 0x1000, + SPPS_Verb = 0x2000, + SPPS_Modifier = 0x3000, + SPPS_Function = 0x4000, + SPPS_Interjection = 0x5000, +}} +ENUM!{enum SPLEXICONTYPE { + eLEXTYPE_USER = 1 << 0, + eLEXTYPE_APP = 1 << 1, + eLEXTYPE_VENDORLEXICON = 1 << 2, + eLEXTYPE_LETTERTOSOUND = 1 << 3, + eLEXTYPE_MORPHOLOGY = 1 << 4, + eLEXTYPE_RESERVED4 = 1 << 5, + eLEXTYPE_USER_SHORTCUT = 1 << 6, + eLEXTYPE_RESERVED6 = 1 << 7, + eLEXTYPE_RESERVED7 = 1 << 8, + eLEXTYPE_RESERVED8 = 1 << 9, + eLEXTYPE_RESERVED9 = 1 << 10, + eLEXTYPE_RESERVED10 = 1 << 11, + eLEXTYPE_PRIVATE1 = 1 << 12, + eLEXTYPE_PRIVATE2 = 1 << 13, + eLEXTYPE_PRIVATE3 = 1 << 14, + eLEXTYPE_PRIVATE4 = 1 << 15, + eLEXTYPE_PRIVATE5 = 1 << 16, + eLEXTYPE_PRIVATE6 = 1 << 17, + eLEXTYPE_PRIVATE7 = 1 << 18, + eLEXTYPE_PRIVATE8 = 1 << 19, + eLEXTYPE_PRIVATE9 = 1 << 20, + eLEXTYPE_PRIVATE10 = 1 << 21, + eLEXTYPE_PRIVATE11 = 1 << 22, + eLEXTYPE_PRIVATE12 = 1 << 23, + eLEXTYPE_PRIVATE13 = 1 << 24, + eLEXTYPE_PRIVATE14 = 1 << 25, + eLEXTYPE_PRIVATE15 = 1 << 26, + eLEXTYPE_PRIVATE16 = 1 << 27, + eLEXTYPE_PRIVATE17 = 1 << 28, + eLEXTYPE_PRIVATE18 = 1 << 29, + eLEXTYPE_PRIVATE19 = 1 << 30, + eLEXTYPE_PRIVATE20 = 1 << 31, +}} +ENUM!{enum SPWORDTYPE { + eWORDTYPE_ADDED = 1 << 0, + eWORDTYPE_DELETED = 1 << 1, +}} +STRUCT!{struct SPWORDPRONUNCIATION { + pNextWordPronunciation: *mut SPWORDPRONUNCIATION, + eLexiconType: SPLEXICONTYPE, + LangID: WORD, + wPronunciationFlags: WORD, + ePartOfSpeech: SPPARTOFSPEECH, + szPronunciation: [SPPHONEID; 1], +}} +STRUCT!{struct SPWORDPRONUNCIATIONLIST { + ulSize: ULONG, + pvBuffer: *mut BYTE, + pFirstWordPronunciation: *mut SPWORDPRONUNCIATION, +}} +STRUCT!{struct SPWORD { + pNextWord: *mut SPWORD, + LangID: WORD, + wReserved: WORD, + eWordType: SPWORDTYPE, + pszWord: LPWSTR, + pFirstWordPronunciation: *mut SPWORDPRONUNCIATION, +}} +STRUCT!{struct SPWORDLIST { + ulSize: ULONG, + pvBuffer: *mut BYTE, + pFirstWord: *mut SPWORD, +}} +RIDL!{#[uuid(0xda41a7c2, 0x5383, 0x4db2, 0x91, 0x6b, 0x6c, 0x17, 0x19, 0xe3, 0xdb, 0x58)] +interface ISpLexicon(ISpLexiconVtbl): IUnknown(IUnknownVtbl) { + fn GetPronunciations( + pszWord: LPCWSTR, + LangID: WORD, + dwFlags: DWORD, + pWordPronunciationList: *mut SPWORDPRONUNCIATIONLIST, + ) -> HRESULT, + fn AddPronunciation( + pszWord: LPCWSTR, + LangID: WORD, + ePartOfSpeech: SPPARTOFSPEECH, + pszPronunciation: PCSPPHONEID, + ) -> HRESULT, + fn RemovePronunciation( + pszWord: LPCWSTR, + LangID: WORD, + ePartOfSpeech: SPPARTOFSPEECH, + pszPronunciation: PCSPPHONEID, + ) -> HRESULT, + fn GetGeneration( + pdwGeneration: *mut DWORD, + ) -> HRESULT, + fn GetGenerationChange( + dwFlags: DWORD, + pdwGeneration: *mut DWORD, + pWordList: *mut SPWORDLIST, + ) -> HRESULT, + fn GetWords( + dwFlags: DWORD, + pdwGeneration: *mut DWORD, + pdwCookie: *mut DWORD, + pWordList: *mut SPWORDLIST, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8565572f, 0xc094, 0x41cc, 0xb5, 0x6e, 0x10, 0xbd, 0x9c, 0x3f, 0xf0, 0x44)] +interface ISpContainerLexicon(ISpContainerLexiconVtbl): ISpLexicon(ISpLexiconVtbl) { + fn AddLexicon( + pAddLexicon: *mut ISpLexicon, + dwFlags: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8445c581, 0x0cac, 0x4a38, 0xab, 0xfe, 0x9b, 0x2c, 0xe2, 0x82, 0x64, 0x55)] +interface ISpPhoneConverter(ISpPhoneConverterVtbl): ISpObjectWithToken(ISpObjectWithTokenVtbl) { + fn PhoneToId( + pszPhone: LPCWSTR, + pId: *mut SPPHONEID, + ) -> HRESULT, + fn IdToPhone( + pId: PCSPPHONEID, + pszPhone: *mut WCHAR, + ) -> HRESULT, +}} +STRUCT!{struct SPVPITCH { + MiddleAdj: c_long, + RangeAdj: c_long, +}} +ENUM!{enum SPVACTIONS { + SPVA_Speak = 0, + SPVA_Silence, + SPVA_Pronounce, + SPVA_Bookmark, + SPVA_SpellOut, + SPVA_Section, + SPVA_ParseUnknownTag, +}} +STRUCT!{struct SPVCONTEXT { + pCategory: LPCWSTR, + pBefore: LPCWSTR, + pAfter: LPCWSTR, +}} +STRUCT!{struct SPVSTATE { + eAction: SPVACTIONS, + LangID: WORD, + wReserved: WORD, + EmphAdj: c_long, + RateAdj: c_long, + Volume: ULONG, + PitchAdj: SPVPITCH, + SilenceMSecs: ULONG, + pPhoneIds: *mut SPPHONEID, + ePartOfSpeech: SPPARTOFSPEECH, + Context: SPVCONTEXT, +}} +ENUM!{enum SPRUNSTATE { + SPRS_DONE = 1 << 0, + SPRS_IS_SPEAKING = 1 << 1, +}} +ENUM!{enum SPVLIMITS { + SPMIN_VOLUME = 0, + SPMAX_VOLUME = 100, + SPMIN_RATE = -10i32 as u32, + SPMAX_RATE = 10, +}} +ENUM!{enum SPVPRIORITY { + SPVPRI_NORMAL = 0, + SPVPRI_ALERT = 1 << 0, + SPVPRI_OVER = 1 << 1, +}} +STRUCT!{struct SPVOICESTATUS { + ulCurrentStream: ULONG, + ulLastStreamQueued: ULONG, + hrLastResult: HRESULT, + dwRunningState: DWORD, + ulInputWordPos: ULONG, + ulInputWordLen: ULONG, + ulInputSentPos: ULONG, + ulInputSentLen: ULONG, + lBookmarkId: LONG, + PhonemeId: SPPHONEID, + VisemeId: SPVISEMES, + dwReserved1: DWORD, + dwReserved2: DWORD, +}} +ENUM!{enum SPEAKFLAGS { + SPF_DEFAULT = 0, + SPF_ASYNC = 1 << 0, + SPF_PURGEBEFORESPEAK = 1 << 1, + SPF_IS_FILENAME = 1 << 2, + SPF_IS_XML = 1 << 3, + SPF_IS_NOT_XML = 1 << 4, + SPF_PERSIST_XML = 1 << 5, + SPF_NLP_SPEAK_PUNC = 1 << 6, + SPF_NLP_MASK = SPF_NLP_SPEAK_PUNC, + SPF_VOICE_MASK = SPF_ASYNC | SPF_PURGEBEFORESPEAK + | SPF_IS_FILENAME | SPF_IS_XML | SPF_IS_NOT_XML + | SPF_NLP_MASK | SPF_PERSIST_XML, + SPF_UNUSED_FLAGS = !SPF_VOICE_MASK, +}} +RIDL!{#[uuid(0x6c44df74, 0x72b9, 0x4992, 0xa1, 0xec, 0xef, 0x99, 0x6e, 0x04, 0x22, 0xd4)] +interface ISpVoice(ISpVoiceVtbl): ISpEventSource(ISpEventSourceVtbl) { + fn SetOutput( + pUnkOutput: *mut IUnknown, + fAllowFormatChanges: BOOL, + ) -> HRESULT, + fn GetOutputObjectToken( + ppObjectToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn GetOutputStream( + ppStream: *mut *mut ISpStreamFormat, + ) -> HRESULT, + fn Pause() -> HRESULT, + fn Resume() -> HRESULT, + fn SetVoice( + pToken: *mut ISpObjectToken, + ) -> HRESULT, + fn GetVoice( + ppToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn Speak( + pwcs: LPCWSTR, + dwFlags: DWORD, + pulStreamNumber: *mut ULONG, + ) -> HRESULT, + fn SpeakStream( + pStream: *mut IStream, + dwFlags: DWORD, + pulStreamNumber: *mut ULONG, + ) -> HRESULT, + fn GetStatus( + pStatus: *mut SPVOICESTATUS, + ppszLastBookmark: *mut LPWSTR, + ) -> HRESULT, + fn Skip( + pItemType: LPCWSTR, + lNumItems: c_long, + pulNumSkipped: *mut ULONG, + ) -> HRESULT, + fn SetPriority( + ePriority: SPVPRIORITY, + ) -> HRESULT, + fn GetPriority( + pePriority: *mut SPVPRIORITY, + ) -> HRESULT, + fn SetAlertBoundary( + eBoundary: SPEVENTENUM, + ) -> HRESULT, + fn GetAlertBoundary( + peBoundary: *mut SPEVENTENUM, + ) -> HRESULT, + fn SetRate( + RateAdjust: c_long, + ) -> HRESULT, + fn GetRate( + pRateAdjust: *mut c_long, + ) -> HRESULT, + fn SetVolume( + usVolume: USHORT, + ) -> HRESULT, + fn GetVolume( + pusVolume: *mut USHORT, + ) -> HRESULT, + fn WaitUntilDone( + msTimeout: ULONG, + ) -> HRESULT, + fn SetSyncSpeakTimeout( + msTimeout: ULONG, + ) -> HRESULT, + fn GetSyncSpeakTimeout( + pmsTimeout: *mut ULONG, + ) -> HRESULT, + fn SpeakCompleteEvent() -> HANDLE, + fn IsUISupported( + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + pfSupported: *mut BOOL, + ) -> HRESULT, + fn DisplayUI( + hwndParent: HWND, + pszTitle: LPCWSTR, + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1a5c0354, 0xb621, 0x4b5a, 0x87, 0x91, 0xd3, 0x06, 0xed, 0x37, 0x9e, 0x53)] +interface ISpPhrase(ISpPhraseVtbl): IUnknown(IUnknownVtbl) { + fn GetPhrase( + ppCoMemPhrase: *mut *mut SPPHRASE, + ) -> HRESULT, + fn GetSerializedPhrase( + ppCoMemPhrase: *mut *mut SPSERIALIZEDPHRASE, + ) -> HRESULT, + fn GetText( + ulStart: ULONG, + ulCount: ULONG, + fUseTextReplacements: BOOL, + ppszCoMemText: *mut LPWSTR, + pbDisplayAttributes: *mut BYTE, + ) -> HRESULT, + fn Discard( + dwValueTypes: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8fcebc98, 0x4e49, 0x4067, 0x9c, 0x6c, 0xd8, 0x6a, 0x0e, 0x09, 0x2e, 0x3d)] +interface ISpPhraseAlt(ISpPhraseAltVtbl): ISpPhrase(ISpPhraseVtbl) { + fn GetAltInfo( + pParent: *mut *mut ISpPhrase, + pulStartElementInParent: *mut ULONG, + pcElementsInParent: *mut ULONG, + pcElementsInAlt: *mut ULONG, + ) -> HRESULT, + fn Commit() -> HRESULT, +}} +STRUCT!{struct SPRECORESULTTIMES { + ftStreamTime: FILETIME, + ullLength: ULONGLONG, + dwTickCount: DWORD, + ullStart: ULONGLONG, +}} +STRUCT!{struct SPSERIALIZEDRESULT { + ulSerializedSize: ULONG, +}} +RIDL!{#[uuid(0x20b053be, 0xe235, 0x43cd, 0x9a, 0x2a, 0x8d, 0x17, 0xa4, 0x8b, 0x78, 0x42)] +interface ISpRecoResult(ISpRecoResultVtbl): ISpPhrase(ISpPhraseVtbl) { + fn GetResultTimes( + pTimes: *mut SPRECORESULTTIMES, + ) -> HRESULT, + fn GetAlternates( + ulStartElement: ULONG, + cElements: ULONG, + ulRequestCount: ULONG, + ppPhrases: *mut *mut ISpPhraseAlt, + pcPhrasesReturned: *mut ULONG, + ) -> HRESULT, + fn GetAudio( + ulStartElement: ULONG, + cElements: ULONG, + ppStream: *mut *mut ISpStreamFormat, + ) -> HRESULT, + fn SpeakAudio( + ulStartElement: ULONG, + cElements: ULONG, + dwFlags: DWORD, + pulStreamNumber: *mut ULONG, + ) -> HRESULT, + fn Serialize( + ppCoMemSerializedResult: *mut *mut SPSERIALIZEDRESULT, + ) -> HRESULT, + fn ScaleAudio( + pAudioFormatId: *const GUID, + pWaveFormatEx: *const WAVEFORMATEX, + ) -> HRESULT, + fn GetRecoContext( + ppRecoContext: *mut *mut ISpRecoContext, + ) -> HRESULT, +}} +STRUCT!{struct SPTEXTSELECTIONINFO { + ulStartActiveOffset: ULONG, + cchActiveChars: ULONG, + ulStartSelection: ULONG, + cchSelection: ULONG, +}} +ENUM!{enum SPWORDPRONOUNCEABLE { + SPWP_UNKNOWN_WORD_UNPRONOUNCEABLE = 0, + SPWP_UNKNOWN_WORD_PRONOUNCEABLE = 1, + SPWP_KNOWN_WORD_PRONOUNCEABLE = 2, +}} +ENUM!{enum SPGRAMMARSTATE { + SPGS_DISABLED = 0, + SPGS_ENABLED = 1, + SPGS_EXCLUSIVE = 3, +}} +ENUM!{enum SPCONTEXTSTATE { + SPCS_DISABLED = 0, + SPCS_ENABLED = 1, +}} +ENUM!{enum SPRULESTATE { + SPRS_INACTIVE = 0, + SPRS_ACTIVE = 1, + SPRS_ACTIVE_WITH_AUTO_PAUSE = 3, +}} +pub const SP_STREAMPOS_ASAP: ULONGLONG = 0; +pub const SP_STREAMPOS_REALTIME: ULONGLONG = -1i64 as u64; +pub const SPRULETRANS_TEXTBUFFER: SPSTATEHANDLE = -1isize as SPSTATEHANDLE; +pub const SPRULETRANS_WILDCARD: SPSTATEHANDLE = -2isize as SPSTATEHANDLE; +pub const SPRULETRANS_DICTATION: SPSTATEHANDLE = -3isize as SPSTATEHANDLE; +ENUM!{enum SPGRAMMARWORDTYPE { + SPWT_DISPLAY, + SPWT_LEXICAL, + SPWT_PRONUNCIATION, + SPWT_LEXICAL_NO_SPECIAL_CHARS, +}} +STRUCT!{struct SPPROPERTYINFO { + pszName: LPCWSTR, + ulId: ULONG, + pszValue: LPCWSTR, + vValue: VARIANT, +}} +ENUM!{enum SPCFGRULEATTRIBUTES { + SPRAF_TopLevel = 1 << 0, + SPRAF_Active = 1 << 1, + SPRAF_Export = 1 << 2, + SPRAF_Import = 1 << 3, + SPRAF_Interpreter = 1 << 4, + SPRAF_Dynamic = 1 << 5, + SPRAF_AutoPause = 1 << 16, +}} +RIDL!{#[uuid(0x8137828f, 0x591a, 0x4a42, 0xbe, 0x58, 0x49, 0xea, 0x7e, 0xba, 0xac, 0x68)] +interface ISpGrammarBuilder(ISpGrammarBuilderVtbl): IUnknown(IUnknownVtbl) { + fn ResetGrammar( + NewLanguage: WORD, + ) -> HRESULT, + fn GetRule( + pszRuleName: LPCWSTR, + dwRuleId: DWORD, + dwAttributes: DWORD, + fCreateIfNotExist: BOOL, + phInitialState: *mut SPSTATEHANDLE, + ) -> HRESULT, + fn ClearRule( + hState: SPSTATEHANDLE, + ) -> HRESULT, + fn CreateNewState( + hState: SPSTATEHANDLE, + phState: *mut SPSTATEHANDLE, + ) -> HRESULT, + fn AddWordTransition( + hFromState: SPSTATEHANDLE, + hToState: SPSTATEHANDLE, + psz: LPCWSTR, + pszSeparators: LPCWSTR, + eWordType: SPGRAMMARWORDTYPE, + Weight: c_float, + pPropInfo: *const SPPROPERTYINFO, + ) -> HRESULT, + fn AddRuleTransition( + hFromState: SPSTATEHANDLE, + hToState: SPSTATEHANDLE, + hRule: SPSTATEHANDLE, + Weight: c_float, + pPropInfo: *const SPPROPERTYINFO, + ) -> HRESULT, + fn AddResource( + hRuleState: SPSTATEHANDLE, + pszResourceName: LPCWSTR, + pszResourceValue: LPCWSTR, + ) -> HRESULT, + fn Commit( + dwReserved: DWORD, + ) -> HRESULT, +}} +ENUM!{enum SPLOADOPTIONS { + SPLO_STATIC = 0, + SPLO_DYNAMIC = 1, +}} +RIDL!{#[uuid(0x2177db29, 0x7f45, 0x47d0, 0x85, 0x54, 0x06, 0x7e, 0x91, 0xc8, 0x05, 0x02)] +interface ISpRecoGrammar(ISpRecoGrammarVtbl): ISpGrammarBuilder(ISpGrammarBuilderVtbl) { + fn GetGrammarId( + pullGrammarId: *mut ULONGLONG, + ) -> HRESULT, + fn GetRecoContext( + ppRecoCtxt: *mut *mut ISpRecoContext, + ) -> HRESULT, + fn LoadCmdFromFile( + pszFileName: LPCWSTR, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn LoadCmdFromObject( + rcid: REFCLSID, + pszGrammarName: LPCWSTR, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn LoadCmdFromResource( + hModule: HMODULE, + pszResourceName: LPCWSTR, + pszResourceType: LPCWSTR, + wLanguage: WORD, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn LoadCmdFromMemory( + pGrammar: *const SPBINARYGRAMMAR, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn LoadCmdFromProprietaryGrammar( + rguidParam: REFGUID, + pszStringParam: LPCWSTR, + pvDataPrarm: *const c_void, + cbDataSize: ULONG, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn SetRuleState( + pszName: LPCWSTR, + pReserved: *mut c_void, + NewState: SPRULESTATE, + ) -> HRESULT, + fn SetRuleIdState( + ulRuleId: ULONG, + NewState: SPRULESTATE, + ) -> HRESULT, + fn LoadDictation( + pszTopicName: LPCWSTR, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn UnloadDictation() -> HRESULT, + fn SetDictationState( + NewState: SPRULESTATE, + ) -> HRESULT, + fn SetWordSequenceData( + pText: *const WCHAR, + cchText: ULONG, + pInfo: *const SPTEXTSELECTIONINFO, + ) -> HRESULT, + fn SetTextSelection( + pInfo: *const SPTEXTSELECTIONINFO, + ) -> HRESULT, + fn IsPronounceable( + pszWord: LPCWSTR, + pWordPronounceable: *mut SPWORDPRONOUNCEABLE, + ) -> HRESULT, + fn SetGrammarState( + eGrammarState: SPGRAMMARSTATE, + ) -> HRESULT, + fn SaveCmd( + pStream: *mut IStream, + ppszCoMemErrorText: *mut LPWSTR, + ) -> HRESULT, + fn GetGrammarState( + peGrammarState: *mut SPGRAMMARSTATE, + ) -> HRESULT, +}} +STRUCT!{struct SPRECOCONTEXTSTATUS { + eInterference: SPINTERFERENCE, + szRequestTypeOfUI: [WCHAR; 255], + dwReserved1: DWORD, + dwReserved2: DWORD, +}} +ENUM!{enum SPBOOKMARKOPTIONS { + SPBO_NONE = 0, + SPBO_PAUSE = 1 << 0, +}} +ENUM!{enum SPAUDIOOPTIONS { + SPAO_NONE = 0, + SPAO_RETAIN_AUDIO = 1 << 0, +}} +RIDL!{#[uuid(0xf740a62f, 0x7c15, 0x489e, 0x82, 0x34, 0x94, 0x0a, 0x33, 0xd9, 0x27, 0x2d)] +interface ISpRecoContext(ISpRecoContextVtbl): ISpEventSource(ISpEventSourceVtbl) { + fn GetRecognizer( + ppRecognizer: *mut *mut ISpRecognizer, + ) -> HRESULT, + fn CreateGrammer( + ullGrammarId: ULONGLONG, + ppGrammar: *mut *mut ISpRecoGrammar, + ) -> HRESULT, + fn GetStatus( + pState: *mut SPRECOCONTEXTSTATUS, + ) -> HRESULT, + fn GetMaxAlternates( + pcAlternates: *mut ULONG, + ) -> HRESULT, + fn SetMaxAlternates( + cAlternates: ULONG, + ) -> HRESULT, + fn SetAudioOptions( + Options: SPAUDIOOPTIONS, + pAudioFormatId: *const GUID, + pWaveFormatEx: *const WAVEFORMATEX, + ) -> HRESULT, + fn GetAudioOptions( + pOptions: *mut SPAUDIOOPTIONS, + pAudioFormatId: *mut GUID, + ppCoMemWFEX: *mut *mut WAVEFORMATEX, + ) -> HRESULT, + fn DeserializeResult( + pSerializedResult: *const SPSERIALIZEDRESULT, + ppResult: *mut *mut ISpRecoResult, + ) -> HRESULT, + fn Bookmark( + Options: SPBOOKMARKOPTIONS, + ullStreamPosition: ULONGLONG, + lparamEvent: LPARAM, + ) -> HRESULT, + fn SetAdaptionData( + pAdaptionData: LPCWSTR, + cch: ULONG, + ) -> HRESULT, + fn Pause( + dwReserved: DWORD, + ) -> HRESULT, + fn Resume( + dwReserved: DWORD, + ) -> HRESULT, + fn SetVoice( + pVoice: *mut ISpVoice, + fAllowFormatChanges: BOOL, + ) -> HRESULT, + fn GetVoice( + ppVoice: *mut *mut ISpVoice, + ) -> HRESULT, + fn SetVoicePurgeEvent( + ullEventIntereset: ULONGLONG, + ) -> HRESULT, + fn GetVoicePurgeEvent( + pullEventIntereset: *mut ULONGLONG, + ) -> HRESULT, + fn SetContextState( + eContextState: SPCONTEXTSTATE, + ) -> HRESULT, + fn GetContextState( + peContextState: *mut SPCONTEXTSTATE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5b4fb971, 0xb115, 0x4de1, 0xad, 0x97, 0xe4, 0x82, 0xe3, 0xbf, 0x6e, 0xe4)] +interface ISpProperties(ISpPropertiesVtbl): IUnknown(IUnknownVtbl) { + fn SetPropertyNum( + pName: LPCWSTR, + lValue: LONG, + ) -> HRESULT, + fn GetPropertyNum( + pName: LPCWSTR, + plValue: *mut LONG, + ) -> HRESULT, + fn SetPropertyString( + pName: LPCWSTR, + pValue: LPCWSTR, + ) -> HRESULT, + fn GetPropertyString( + pName: LPCWSTR, + ppCoMemValue: *mut LPWSTR, + ) -> HRESULT, +}} +pub const SP_MAX_LANGIDS: usize = 20; +STRUCT!{struct SPRECOGNIZERSTATUS { + AudioStatus: SPAUDIOSTATUS, + ullRecognitionStreamPos: ULONGLONG, + ulStreamNumber: ULONG, + ulNumActive: ULONG, + clsidEngine: CLSID, + cLangIDs: ULONG, + aLangID: [WORD; SP_MAX_LANGIDS], + ullRecognitionStreamTime: ULONGLONG, +}} +ENUM!{enum SPWAVEFORMATTYPE { + SPWF_INPUT, + SPWF_SRENGINE, +}} +pub type SPSTREAMFORMATTYPE = SPWAVEFORMATTYPE; +ENUM!{enum SPRECOSTATE { + SPRST_INACTIVE, + SPRST_ACTIVE, + SPRST_ACTIVE_ALWAYS, + SPRST_INACTIVE_WITH_PURGE, + SPRST_NUM_STATES, +}} +RIDL!{#[uuid(0xc2b5f241, 0xdaa0, 0x4507, 0x9e, 0x16, 0x5a, 0x1e, 0xaa, 0x2b, 0x7a, 0x5c)] +interface ISpRecognizer(ISpRecognizerVtbl): ISpProperties(ISpPropertiesVtbl) { + fn SetRecognizer( + pRecognizer: *mut ISpObjectToken, + ) -> HRESULT, + fn GetRecognizer( + ppRecognizer: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn SetInput( + pUnkInput: *mut IUnknown, + fAllowFormatChanges: BOOL, + ) -> HRESULT, + fn GetInputObjectToken( + ppToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn GetInputStream( + ppStream: *mut *mut ISpStreamFormat, + ) -> HRESULT, + fn CreateRecoContext( + ppNewCtxt: *mut *mut ISpRecoContext, + ) -> HRESULT, + fn GetRecoProfile( + ppToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn SetRecoProfile( + pToken: *mut ISpObjectToken, + ) -> HRESULT, + fn IsSharedInstance() -> HRESULT, + fn GetRecoState( + pState: *mut SPRECOSTATE, + ) -> HRESULT, + fn SetRecoState( + NewState: SPRECOSTATE, + ) -> HRESULT, + fn GetStatus( + pStatus: *mut SPRECOGNIZERSTATUS, + ) -> HRESULT, + fn GetFormat( + WaveFormatType: SPSTREAMFORMATTYPE, + pFormatId: *mut GUID, + ppCoMemWFEX: *mut WAVEFORMATEX, + ) -> HRESULT, + fn IsUISupported( + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + pfSupported: *mut BOOL, + ) -> HRESULT, + fn DisplayUI( + hwndParent: HWND, + pszTitle: LPCWSTR, + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + ) -> HRESULT, + fn EmulateRecognition( + pPhrase: *mut ISpPhrase, + ) -> HRESULT, +}} +pub type SpeechLanguageId = c_long; +ENUM!{enum DISPID_SpeechDataKey { + DISPID_SDKSetBinaryValue = 1, + DISPID_SDKGetBinaryValue, + DISPID_SDKSetStringValue, + DISPID_SDKGetStringValue, + DISPID_SDKSetLongValue, + DISPID_SDKGetlongValue, + DISPID_SDKOpenKey, + DISPID_SDKCreateKey, + DISPID_SDKDeleteKey, + DISPID_SDKDeleteValue, + DISPID_SDKEnumKeys, + DISPID_SDKEnumValues, +}} +ENUM!{enum DISPID_SpeechObjectToken { + DISPID_SOTId = 1, + DISPID_SOTDataKey, + DISPID_SOTCategory, + DISPID_SOTGetDescription, + DISPID_SOTSetId, + DISPID_SOTGetAttribute, + DISPID_SOTCreateInstance, + DISPID_SOTRemove, + DISPID_SOTGetStorageFileName, + DISPID_SOTRemoveStorageFileName, + DISPID_SOTIsUISupported, + DISPID_SOTDisplayUI, + DISPID_SOTMatchesAttributes, +}} +ENUM!{enum SpeechDataKeyLocation { + SDKLDefaultLocation = SPDKL_DefaultLocation, + SDKLCurrentUser = SPDKL_CurrentUser, + SDKLLocalMachine = SPDKL_LocalMachine, + SDKLCurrentConfig = SPDKL_CurrentConfig, +}} +ENUM!{enum SpeechTokenContext { + STCInprocServer = CLSCTX_INPROC_SERVER, + STCInprocHandler = CLSCTX_INPROC_HANDLER, + STCLocalServer = CLSCTX_LOCAL_SERVER, + STCRemoteServer = CLSCTX_REMOTE_SERVER, + STCAll = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER + | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, +}} +ENUM!{enum SpeechTokenShellFolder { + STSF_AppData = 0x1a, + STSF_LocalAppData = 0x1c, + STSF_CommonAppData = 0x23, + STSF_FlagCreate = 0x8000, +}} +ENUM!{enum DISPID_SpeechObjectTokens { + DISPID_SOTsCount = 1, + DISPID_SOTsItem = DISPID_VALUE as u32, + DISPID_SOTs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechObjectTokenCategory { + DISPID_SOTCId = 1, + DISPID_SOTCDefault, + DISPID_SOTCSetId, + DISPID_SOTCGetDataKey, + DISPID_SOTCEnumerateTokens, +}} +ENUM!{enum SpeechAudioFormatType { + SAFTDefault = -1i32 as u32, + SAFTNoAssignedFormat = 0, + SAFTText = 1, + SAFTNonStandardFormat = 2, + SAFTExtendedAudioFormat = 3, + SAFT8kHz8BitMono = 4, + SAFT8kHz8BitStereo = 5, + SAFT8kHz16BitMono = 6, + SAFT8kHz16BitStereo = 7, + SAFT11kHz8BitMono = 8, + SAFT11kHz8BitStereo = 9, + SAFT11kHz16BitMono = 10, + SAFT11kHz16BitStereo = 11, + SAFT12kHz8BitMono = 12, + SAFT12kHz8BitStereo = 13, + SAFT12kHz16BitMono = 14, + SAFT12kHz16BitStereo = 15, + SAFT16kHz8BitMono = 16, + SAFT16kHz8BitStereo = 17, + SAFT16kHz16BitMono = 18, + SAFT16kHz16BitStereo = 19, + SAFT22kHz8BitMono = 20, + SAFT22kHz8BitStereo = 21, + SAFT22kHz16BitMono = 22, + SAFT22kHz16BitStereo = 23, + SAFT24kHz8BitMono = 24, + SAFT24kHz8BitStereo = 25, + SAFT24kHz16BitMono = 26, + SAFT24kHz16BitStereo = 27, + SAFT32kHz8BitMono = 28, + SAFT32kHz8BitStereo = 29, + SAFT32kHz16BitMono = 30, + SAFT32kHz16BitStereo = 31, + SAFT44kHz8BitMono = 32, + SAFT44kHz8BitStereo = 33, + SAFT44kHz16BitMono = 34, + SAFT44kHz16BitStereo = 35, + SAFT48kHz8BitMono = 36, + SAFT48kHz8BitStereo = 37, + SAFT48kHz16BitMono = 38, + SAFT48kHz16BitStereo = 39, + SAFTTrueSpeech_8kHz1BitMono = 40, + SAFTCCITT_ALaw_8kHzMono = 41, + SAFTCCITT_ALaw_8kHzStereo = 42, + SAFTCCITT_ALaw_11kHzMono = 43, + SAFTCCITT_ALaw_11kHzStereo = 44, + SAFTCCITT_ALaw_22kHzMono = 45, + SAFTCCITT_ALaw_22kHzStereo = 46, + SAFTCCITT_ALaw_44kHzMono = 47, + SAFTCCITT_ALaw_44kHzStereo = 48, + SAFTCCITT_uLaw_8kHzMono = 49, + SAFTCCITT_uLaw_8kHzStereo = 50, + SAFTCCITT_uLaw_11kHzMono = 51, + SAFTCCITT_uLaw_11kHzStereo = 52, + SAFTCCITT_uLaw_22kHzMono = 53, + SAFTCCITT_uLaw_22kHzStereo = 54, + SAFTCCITT_uLaw_44kHzMono = 55, + SAFTCCITT_uLaw_44kHzStereo = 56, + SAFTADPCM_8kHzMono = 57, + SAFTADPCM_8kHzStereo = 58, + SAFTADPCM_11kHzMono = 59, + SAFTADPCM_11kHzStereo = 60, + SAFTADPCM_22kHzMono = 61, + SAFTADPCM_22kHzStereo = 62, + SAFTADPCM_44kHzMono = 63, + SAFTADPCM_44kHzStereo = 64, + SAFTGSM610_8kHzMono = 65, + SAFTGSM610_11kHzMono = 66, + SAFTGSM610_22kHzMono = 67, + SAFTGSM610_44kHzMono = 68, +}} +ENUM!{enum DISPID_SpeechAudioFormat { + DISPID_SAFType = 1, + DISPID_SAFGuid, + DISPID_SAFGetWaveFormatEx, + DISPID_SAFSetWaveFormatEx, +}} +ENUM!{enum DISPID_SpeechBaseStream { + DISPID_SBSFormat = 1, + DISPID_SBSRead, + DISPID_SBSWrite, + DISPID_SBSSeek, +}} +ENUM!{enum SpeechStreamSeekPositionType { + SSSPTRelativeToStart = STREAM_SEEK_SET, + SSSPTRelativeToCurrentPosition = STREAM_SEEK_CUR, + SSSPTRelativeToEnd = STREAM_SEEK_END, +}} +ENUM!{enum DISPID_SpeechAudio { + DISPID_SAStatus = 200, + DISPID_SABufferInfo, + DISPID_SADefaultFormat, + DISPID_SAVolume, + DISPID_SABufferNotifySize, + DISPID_SAEventHandle, + DISPID_SASetState, +}} +ENUM!{enum SpeechAudioState { + SASClosed = SPAS_CLOSED, + SASStop = SPAS_STOP, + SASPause = SPAS_PAUSE, + SASRun = SPAS_RUN, +}} +ENUM!{enum DISPID_SpeechMMSysAudio { + DISPID_SMSADeviceId = 300, + DISPID_SMSALineId, + DISPID_SMSAMMHandle, +}} +ENUM!{enum DISPID_SpeechFileStream { + DISPID_SFSOpen = 100, + DISPID_SFSClose, +}} +ENUM!{enum SpeechStreamFileMode { + SSFMOpenForRead = SPFM_OPEN_READONLY, + SSFMOpenReadWrite = SPFM_OPEN_READWRITE, + SSFMCreate = SPFM_CREATE, + SSFMCreateForWrite = SPFM_CREATE_ALWAYS, +}} +ENUM!{enum DISPID_SpeechCustomStream { + DISPID_SCSBaseStream = 100, +}} +ENUM!{enum DISPID_SpeechMemoryStream { + DISPID_SMSSetData = 100, + DISPID_SMSGetData, +}} +ENUM!{enum DISPID_SpeechAudioStatus { + DISPID_SASFreeBufferSpace = 1, + DISPID_SASNonBlockingIO, + DISPID_SASState, + DISPID_SASCurrentSeekPosition, + DISPID_SASCurrentDevicePosition, +}} +ENUM!{enum DISPID_SpeechAudioBufferInfo { + DISPID_SABIMinNotification = 1, + DISPID_SABIBufferSize, + DISPID_SABIEventBias, +}} +ENUM!{enum DISPID_SpeechWaveFormatEx { + DISPID_SWFEFormatTag = 1, + DISPID_SWFEChannels, + DISPID_SWFESamplesPerSec, + DISPID_SWFEAvgBytesPerSec, + DISPID_SWFEBlockAlign, + DISPID_SWFEBitsPerSample, + DISPID_SWFEExtraData, +}} +ENUM!{enum DISPID_SpeechVoice { + DISPID_SVStatus = 1, + DISPID_SVVoice, + DISPID_SVAudioOutput, + DISPID_SVAudioOutputStream, + DISPID_SVRate, + DISPID_SVVolume, + DISPID_SVAllowAudioOuputFormatChangesOnNextSet, + DISPID_SVEventInterests, + DISPID_SVPriority, + DISPID_SVAlertBoundary, + DISPID_SVSyncronousSpeakTimeout, + DISPID_SVSpeak, + DISPID_SVSpeakStream, + DISPID_SVPause, + DISPID_SVResume, + DISPID_SVSkip, + DISPID_SVGetVoices, + DISPID_SVGetAudioOutputs, + DISPID_SVWaitUntilDone, + DISPID_SVSpeakCompleteEvent, + DISPID_SVIsUISupported, + DISPID_SVDisplayUI, +}} +ENUM!{enum SpeechVoicePriority { + SVPNormal = SPVPRI_NORMAL, + SVPAlert = SPVPRI_ALERT, + SVPOver = SPVPRI_OVER, +}} +ENUM!{enum SpeechVoiceSpeakFlags { + SVSFDefault = SPF_DEFAULT, + SVSFlagsAsync = SPF_ASYNC, + SVSFPurgeBeforeSpeak = SPF_PURGEBEFORESPEAK, + SVSFIsFilename = SPF_IS_FILENAME, + SVSFIsXML = SPF_IS_XML, + SVSFIsNotXML = SPF_IS_NOT_XML, + SVSFPersistXML = SPF_PERSIST_XML, + SVSFNLPSpeakPunc = SPF_NLP_SPEAK_PUNC, + SVSFNLPMask = SPF_NLP_MASK, + SVSFVoiceMask = SPF_VOICE_MASK as u32, + SVSFUnusedFlags = SPF_UNUSED_FLAGS as u32, +}} +ENUM!{enum SpeechVoiceEvents { + SVEStartInputStream = 1 << 1, + SVEEndInputStream = 1 << 2, + SVEVoiceChange = 1 << 3, + SVEBookmark = 1 << 4, + SVEWordBoundary = 1 << 5, + SVEPhoneme = 1 << 6, + SVESentenceBoundary = 1 << 7, + SVEViseme = 1 << 8, + SVEAudioLevel = 1 << 9, + SVEPrivate = 1 << 15, + SVEAllEvents = 0x83fe, +}} +ENUM!{enum DISPID_SpeechVoiceStatus { + DISPID_SVSCurrentStreamNumber = 1, + DISPID_SVSLastStreamNumberQueued, + DISPID_SVSLastResult, + DISPID_SVSRunningState, + DISPID_SVSInputWordPosition, + DISPID_SVSInputWordLength, + DISPID_SVSInputSentencePosition, + DISPID_SVSInputSentenceLength, + DISPID_SVSLastBookmark, + DISPID_SVSLastBookmarkId, + DISPID_SVSPhonemeId, + DISPID_SVSVisemeId, +}} +ENUM!{enum SpeechRunState { + SRSEDone = SPRS_DONE, + SRSEIsSpeaking = SPRS_IS_SPEAKING, +}} +ENUM!{enum SpeechVisemeType { + SVP_0 = 0, + SVP_1, + SVP_2, + SVP_3, + SVP_4, + SVP_5, + SVP_6, + SVP_7, + SVP_8, + SVP_9, + SVP_10, + SVP_11, + SVP_12, + SVP_13, + SVP_14, + SVP_15, + SVP_16, + SVP_17, + SVP_18, + SVP_19, + SVP_20, + SVP_21, +}} +ENUM!{enum SpeechVisemeFeature { + SVF_None = 0, + SVF_Stressed = SPVFEATURE_STRESSED, + SVF_Emphasis = SPVFEATURE_EMPHASIS, +}} +ENUM!{enum DISPID_SpeechVoiceEvent { + DISPID_SVEStreamStart = 1, + DISPID_SVEStreamEnd, + DISPID_SVEVoiceChange, + DISPID_SVEBookmark, + DISPID_SVEWord, + DISPID_SVEPhoneme, + DISPID_SVESentenceBoundary, + DISPID_SVEViseme, + DISPID_SVEAudioLevel, + DISPID_SVEEnginePrivate, +}} +ENUM!{enum DISPID_SpeechRecognizer { + DISPID_SRRecognizer = 1, + DISPID_SRAllowAudioInputFormatChangesOnNextSet, + DISPID_SRAudioInput, + DISPID_SRAudioInputStream, + DISPID_SRIsShared, + DISPID_SRState, + DISPID_SRStatus, + DISPID_SRProfile, + DISPID_SREmulateRecognition, + DISPID_SRCreateRecoContext, + DISPID_SRGetFormat, + DISPID_SRSetPropertyNumber, + DISPID_SRGetPropertyNumber, + DISPID_SRSetPropertyString, + DISPID_SRGetPropertyString, + DISPID_SRIsUISupported, + DISPID_SRDisplayUI, + DISPID_SRGetRecognizers, + DISPID_SVGetAudioInputs, + DISPID_SVGetProfiles, +}} +ENUM!{enum SpeechRecognizerState { + SRSInactive = SPRST_INACTIVE, + SRSActive = SPRST_ACTIVE, + SRSActiveAlways = SPRST_ACTIVE_ALWAYS, + SRSInactiveWithPurge = SPRST_INACTIVE_WITH_PURGE, +}} +ENUM!{enum SpeechDisplayAttributes { + SDA_No_Trailing_Space = 0, + SDA_One_Trailing_Space = SPAF_ONE_TRAILING_SPACE, + SDA_Two_Trailing_Spaces = SPAF_TWO_TRAILING_SPACES, + SDA_Consume_Leading_Spaces = SPAF_CONSUME_LEADING_SPACES, +}} +ENUM!{enum SpeechFormatType { + SFTInput = SPWF_INPUT, + SFTSREngine = SPWF_SRENGINE, +}} +ENUM!{enum DISPID_SpeechRecognizerStatus { + DISPID_SRSAudioStatus = 1, + DISPID_SRSCurrentStreamPosition, + DISPID_SRSCurrentStreamNumber, + DISPID_SRSNumberOfActiveRules, + DISPID_SRSClsidEngine, + DISPID_SRSSupportedLanguages, +}} +ENUM!{enum DISPID_SpeechRecoContext { + DISPID_SRCRecognizer = 1, + DISPID_SRCAudioInInterferenceStatus, + DISPID_SRCRequestedUIType, + DISPID_SRCVoice, + DISPID_SRAllowVoiceFormatMatchingOnNextSet, + DISPID_SRCVoicePurgeEvent, + DISPID_SRCEventInterests, + DISPID_SRCCmdMaxAlternates, + DISPID_SRCState, + DISPID_SRCRetainedAudio, + DISPID_SRCRetainedAudioFormat, + DISPID_SRCPause, + DISPID_SRCResume, + DISPID_SRCCreateGrammar, + DISPID_SRCCreateResultFromMemory, + DISPID_SRCBookmark, + DISPID_SRCSetAdaptationData, +}} +ENUM!{enum SpeechRetainedAudioOptions { + SRAONone = SPAO_NONE, + SRAORetainAudio = SPAO_RETAIN_AUDIO, +}} +ENUM!{enum SpeechBookmarkOptions { + SBONone = SPBO_NONE, + SBOPause = SPBO_PAUSE, +}} +ENUM!{enum SpeechInterference { + SINone = SPINTERFERENCE_NONE, + SINoise = SPINTERFERENCE_NOISE, + SINoSignal = SPINTERFERENCE_NOSIGNAL, + SITooLoud = SPINTERFERENCE_TOOLOUD, + SITooQuiet = SPINTERFERENCE_TOOQUIET, + SITooFast = SPINTERFERENCE_TOOFAST, + SITooSlow = SPINTERFERENCE_TOOSLOW, +}} +ENUM!{enum SpeechRecoEvents { + SREStreamEnd = 1 << 0, + SRESoundStart = 1 << 1, + SRESoundEnd = 1 << 2, + SREPhraseStart = 1 << 3, + SRERecognition = 1 << 4, + SREHypothesis = 1 << 5, + SREBookmark = 1 << 6, + SREPropertyNumChange = 1 << 7, + SREPropertyStringChange = 1 << 8, + SREFalseRecognition = 1 << 9, + SREInterference = 1 << 10, + SRERequestUI = 1 << 11, + SREStateChange = 1 << 12, + SREAdaptation = 1 << 13, + SREStreamStart = 1 << 14, + SRERecoOtherContext = 1 << 15, + SREAudioLevel = 1 << 16, + SREPrivate = 1 << 18, + SREAllEvents = 0x5ffff, +}} +ENUM!{enum SpeechRecoContextState { + SRCS_Disabled = SPCS_DISABLED, + SRCS_Enabled = SPCS_ENABLED, +}} +ENUM!{enum DISPIDSPRG { + DISPID_SRGId = 1, + DISPID_SRGRecoContext, + DISPID_SRGState, + DISPID_SRGRules, + DISPID_SRGReset, + DISPID_SRGCommit, + DISPID_SRGCmdLoadFromFile, + DISPID_SRGCmdLoadFromObject, + DISPID_SRGCmdLoadFromResource, + DISPID_SRGCmdLoadFromMemory, + DISPID_SRGCmdLoadFromProprietaryGrammar, + DISPID_SRGCmdSetRuleState, + DISPID_SRGCmdSetRuleIdState, + DISPID_SRGDictationLoad, + DISPID_SRGDictationUnload, + DISPID_SRGDictationSetState, + DISPID_SRGSetWordSequenceData, + DISPID_SRGSetTextSelection, + DISPID_SRGIsPronounceable, +}} +ENUM!{enum SpeechLoadOption { + SLOStatic = SPLO_STATIC, + SLODynamic = SPLO_DYNAMIC, +}} +ENUM!{enum SpeechWordPronounceable { + SWPUnknownWordUnpronounceable = SPWP_UNKNOWN_WORD_UNPRONOUNCEABLE, + SWPUnknownWordPronounceable = SPWP_UNKNOWN_WORD_PRONOUNCEABLE, + SWPKnownWordPronounceable = SPWP_KNOWN_WORD_PRONOUNCEABLE, +}} +ENUM!{enum SpeechGrammarState { + SGSEnabled = SPGS_ENABLED, + SGSDisabled = SPGS_DISABLED, + SGSExclusive = SPGS_EXCLUSIVE, +}} +ENUM!{enum SpeechRuleState { + SGDSInactive = SPRS_INACTIVE, + SGDSActive = SPRS_ACTIVE, + SGDSActiveWithAutoPause = SPRS_ACTIVE_WITH_AUTO_PAUSE, +}} +ENUM!{enum SpeechRuleAttributes { + SRATopLevel = SPRAF_TopLevel, + SRADefaultToActive = SPRAF_Active, + SRAExport = SPRAF_Export, + SRAImport = SPRAF_Import, + SRAInterpreter = SPRAF_Interpreter, + SRADynamic = SPRAF_Dynamic, +}} +ENUM!{enum SpeechGrammarWordType { + SGDisplay = SPWT_DISPLAY, + SGLexical = SPWT_LEXICAL, + SGPronounciation = SPWT_PRONUNCIATION, +}} +ENUM!{enum DISPID_SpeechRecoContextEvents { + DISPID_SRCEStartStream = 1, + DISPID_SRCEEndStream, + DISPID_SRCEBookmark, + DISPID_SRCESoundStart, + DISPID_SRCESoundEnd, + DISPID_SRCEPhraseStart, + DISPID_SRCERecognition, + DISPID_SRCEHypothesis, + DISPID_SRCEPropertyNumberChange, + DISPID_SRCEPropertyStringChange, + DISPID_SRCEFalseRecognition, + DISPID_SRCEInterference, + DISPID_SRCERequestUI, + DISPID_SRCERecognizerStateChange, + DISPID_SRCEAdaptation, + DISPID_SRCERecognitionForOtherContext, + DISPID_SRCEAudioLevel, + DISPID_SRCEEnginePrivate, +}} +ENUM!{enum SpeechRecognitionType { + SRTStandard = 0, + SRTAutopause = SPREF_AutoPause, + SRTEmulated = SPREF_Emulated, +}} +ENUM!{enum DISPID_SpeechGrammarRule { + DISPID_SGRAttributes = 1, + DISPID_SGRInitialState, + DISPID_SGRName, + DISPID_SGRId, + DISPID_SGRClear, + DISPID_SGRAddResource, + DISPID_SGRAddState, +}} +ENUM!{enum DISPID_SpeechGrammarRules { + DISPID_SGRsCount = 1, + DISPID_SGRsDynamic, + DISPID_SGRsAdd, + DISPID_SGRsCommit, + DISPID_SGRsCommitAndSave, + DISPID_SGRsFindRule, + DISPID_SGRsItem = DISPID_VALUE as u32, + DISPID_SGRs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechGrammarRuleState { + DISPID_SGRSRule = 1, + DISPID_SGRSTransitions, + DISPID_SGRSAddWordTransition, + DISPID_SGRSAddRuleTransition, + DISPID_SGRSAddSpecialTransition, +}} +ENUM!{enum SpeechSpecialTransitionType { + SSTTWildcard = 1, + SSTTDictation, + SSTTTextBuffer, +}} +ENUM!{enum DISPID_SpeechGrammarRuleStateTransitions { + DISPID_SGRSTsCount = 1, + DISPID_SGRSTsItem = DISPID_VALUE as u32, + DISPID_SGRSTs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechGrammarRuleStateTransition { + DISPID_SGRSTType = 1, + DISPID_SGRSTText, + DISPID_SGRSTRule, + DISPID_SGRSTWeight, + DISPID_SGRSTPropertyName, + DISPID_SGRSTPropertyId, + DISPID_SGRSTPropertyValue, + DISPID_SGRSTNextState, +}} +ENUM!{enum SpeechGrammarRuleStateTransitionType { + SGRSTTEpsilon = 0, + SGRSTTWord, + SGRSTTRule, + SGRSTTDictation, + SGRSTTWildcard, + SGRSTTTextBuffer, +}} +ENUM!{enum DISPIDSPTSI { + DISPIDSPTSI_ActiveOffset = 1, + DISPIDSPTSI_ActiveLength, + DISPIDSPTSI_SelectionOffset, + DISPIDSPTSI_SelectionLength, +}} +ENUM!{enum DISPID_SpeechRecoResult { + DISPID_SRRRecoContext = 1, + DISPID_SRRTimes, + DISPID_SRRAudioFormat, + DISPID_SRRPhraseInfo, + DISPID_SRRAlternates, + DISPID_SRRAudio, + DISPID_SRRSpeakAudio, + DISPID_SRRSaveToMemory, + DISPID_SRRDiscardResultInfo, +}} +ENUM!{enum SpeechDiscardType { + SDTProperty = SPDF_PROPERTY, + SDTReplacement = SPDF_REPLACEMENT, + SDTRule = SPDF_RULE, + SDTDisplayText = SPDF_DISPLAYTEXT, + SDTLexicalForm = SPDF_LEXICALFORM, + SDTPronunciation = SPDF_PRONUNCIATION, + SDTAudio = SPDF_AUDIO, + SDTAlternates = SPDF_ALTERNATES, + SDTAll = SPDF_ALL, +}} +ENUM!{enum DISPID_SpeechPhraseBuilder { + DISPID_SPPBRestorePhraseFromMemory = 1, +}} +ENUM!{enum DISPID_SpeechRecoResultTimes { + DISPID_SRRTStreamTime = 1, + DISPID_SRRTLength, + DISPID_SRRTTickCount, + DISPID_SRRTOffsetFromStart, +}} +ENUM!{enum DISPID_SpeechPhraseAlternate { + DISPID_SPARecoResult = 1, + DISPID_SPAStartElementInResult, + DISPID_SPANumberOfElementsInResult, + DISPID_SPAPhraseInfo, + DISPID_SPACommit, +}} +ENUM!{enum DISPID_SpeechPhraseAlternates { + DISPID_SPAsCount = 1, + DISPID_SPAsItem = DISPID_VALUE as u32, + DISPID_SPAs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechPhraseInfo { + DISPID_SPILanguageId = 1, + DISPID_SPIGrammarId, + DISPID_SPIStartTime, + DISPID_SPIAudioStreamPosition, + DISPID_SPIAudioSizeBytes, + DISPID_SPIRetainedSizeBytes, + DISPID_SPIAudioSizeTime, + DISPID_SPIRule, + DISPID_SPIProperties, + DISPID_SPIElements, + DISPID_SPIReplacements, + DISPID_SPIEngineId, + DISPID_SPIEnginePrivateData, + DISPID_SPISaveToMemory, + DISPID_SPIGetText, + DISPID_SPIGetDisplayAttributes, +}} +ENUM!{enum DISPID_SpeechPhraseElement { + DISPID_SPEAudioTimeOffset = 1, + DISPID_SPEAudioSizeTime, + DISPID_SPEAudioStreamOffset, + DISPID_SPEAudioSizeBytes, + DISPID_SPERetainedStreamOffset, + DISPID_SPERetainedSizeBytes, + DISPID_SPEDisplayText, + DISPID_SPELexicalForm, + DISPID_SPEPronunciation, + DISPID_SPEDisplayAttributes, + DISPID_SPERequiredConfidence, + DISPID_SPEActualConfidence, + DISPID_SPEEngineConfidence, +}} +ENUM!{enum SpeechEngineConfidence { + SECLowConfidence = -1i32 as u32, + SECNormalConfidence = 0, + SECHighConfidence = 1, +}} +ENUM!{enum DISPID_SpeechPhraseElements { + DISPID_SPEsCount = 1, + DISPID_SPEsItem = DISPID_VALUE as u32, + DISPID_SPEs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechPhraseReplacement { + DISPID_SPRDisplayAttributes = 1, + DISPID_SPRText, + DISPID_SPRFirstElement, + DISPID_SPRNumberOfElements, +}} +ENUM!{enum DISPID_SpeechPhraseReplacements { + DISPID_SPRsCount = 1, + DISPID_SPRsItem = DISPID_VALUE as u32, + DISPID_SPRs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechPhraseProperty { + DISPID_SPPName = 1, + DISPID_SPPId, + DISPID_SPPValue, + DISPID_SPPFirstElement, + DISPID_SPPNumberOfElements, + DISPID_SPPEngineConfidence, + DISPID_SPPConfidence, + DISPID_SPPParent, + DISPID_SPPChildren, +}} +ENUM!{enum DISPID_SpeechPhraseProperties { + DISPID_SPPsCount = 1, + DISPID_SPPsItem = DISPID_VALUE as u32, + DISPID_SPPs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechPhraseRule { + DISPID_SPRuleName = 1, + DISPID_SPRuleId, + DISPID_SPRuleFirstElement, + DISPID_SPRuleNumberOfElements, + DISPID_SPRuleParent, + DISPID_SPRuleChildren, + DISPID_SPRuleConfidence, + DISPID_SPRuleEngineConfidence, +}} +ENUM!{enum DISPID_SpeechPhraseRules { + DISPID_SPRulesCount = 1, + DISPID_SPRulesItem = DISPID_VALUE as u32, + DISPID_SPRules_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechLexicon { + DISPID_SLGenerationId = 1, + DISPID_SLGetWords, + DISPID_SLAddPronunciation, + DISPID_SLAddPronunciationByPhoneIds, + DISPID_SLRemovePronunciation, + DISPID_SLRemovePronunciationByPhoneIds, + DISPID_SLGetPronunciations, + DISPID_SLGetGenerationChange, +}} +ENUM!{enum SpeechLexiconType { + SLTUser = eLEXTYPE_USER, + SLTApp = eLEXTYPE_APP, +}} +ENUM!{enum SpeechPartOfSpeech { + SPSNotOverriden = SPPS_NotOverriden, + SPSUnknown = SPPS_Unknown, + SPSNoun = SPPS_Noun, + SPSVerb = SPPS_Verb, + SPSModifier = SPPS_Modifier, + SPSFunction = SPPS_Function, + SPSInterjection = SPPS_Interjection, +}} +ENUM!{enum DISPID_SpeechLexiconWords { + DISPID_SLWsCount = 1, + DISPID_SLWsItem = DISPID_VALUE as u32, + DISPID_SLWs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum SpeechWordType { + SWTAdded = eWORDTYPE_ADDED, + SWTDeleted = eWORDTYPE_DELETED, +}} +ENUM!{enum DISPID_SpeechLexiconWord { + DISPID_SLWLangId = 1, + DISPID_SLWType, + DISPID_SLWWord, + DISPID_SLWPronunciations, +}} +ENUM!{enum DISPID_SpeechLexiconProns { + DISPID_SLPsCount = 1, + DISPID_SLPsItem = DISPID_VALUE as u32, + DISPID_SLPs_NewEnum = DISPID_NEWENUM as u32, +}} +ENUM!{enum DISPID_SpeechLexiconPronunciation { + DISPID_SLPType = 1, + DISPID_SLPLangId, + DISPID_SLPPartOfSpeech, + DISPID_SLPPhoneIds, + DISPID_SLPSymbolic, +}} +ENUM!{enum DISPID_SpeechPhoneConverter { + DISPID_SPCLangId = 1, + DISPID_SPCPhoneToId, + DISPID_SPCIdToPhone, +}} +extern { + pub static LIBID_SpeechLib: IID; +} +RIDL!{#[uuid(0xce17c09b, 0x4efa, 0x44d5, 0xa4, 0xc9, 0x59, 0xd9, 0x58, 0x5a, 0xb0, 0xcd)] +interface ISpeechDataKey(ISpeechDataKeyVtbl): IDispatch(IDispatchVtbl) { + fn SetBinaryValue( + ValueName: BSTR, + Value: VARIANT, + ) -> HRESULT, + fn GetBinaryValue( + ValueName: BSTR, + Value: *mut VARIANT, + ) -> HRESULT, + fn SetStringValue( + ValueName: BSTR, + Value: BSTR, + ) -> HRESULT, + fn GetStringValue( + ValueName: BSTR, + Value: *mut BSTR, + ) -> HRESULT, + fn SetLongValue( + ValueName: BSTR, + Value: c_long, + ) -> HRESULT, + fn GetLongValue( + ValueName: BSTR, + Value: *mut c_long, + ) -> HRESULT, + fn OpenKey( + SubKeyName: BSTR, + SubKey: *mut *mut ISpeechDataKey, + ) -> HRESULT, + fn CreateKey( + SubKeyName: BSTR, + SubKey: *mut *mut ISpeechDataKey, + ) -> HRESULT, + fn DeleteKey( + SubKeyName: BSTR, + ) -> HRESULT, + fn DeleteValue( + ValueName: BSTR, + ) -> HRESULT, + fn EnumKeys( + Index: c_long, + SubKeyName: *mut BSTR, + ) -> HRESULT, + fn EnumValues( + Index: c_long, + ValueName: *mut BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc74a3adc, 0xb727, 0x4500, 0xa8, 0x4a, 0xb5, 0x26, 0x72, 0x1c, 0x8b, 0x8c)] +interface ISpeechObjectToken(ISpeechObjectTokenVtbl): IDispatch(IDispatchVtbl) { + fn get_Id( + ObjectId: *mut BSTR, + ) -> HRESULT, + fn get_DataKey( + DataKey: *mut *mut ISpeechDataKey, + ) -> HRESULT, + fn get_Category( + Category: *mut *mut ISpeechObjectTokenCategory, + ) -> HRESULT, + fn GetDescription( + Locale: c_long, + Description: *mut BSTR, + ) -> HRESULT, + fn SetId( + Id: BSTR, + CategoryId: BSTR, + CreateIfNotExist: VARIANT_BOOL, + ) -> HRESULT, + fn GetAttribute( + AttributeName: BSTR, + AttributeValue: *mut BSTR, + ) -> HRESULT, + fn CreateInstance( + pUnkOuter: *mut IUnknown, + ClsContext: SpeechTokenContext, + Object: *mut *mut IUnknown, + ) -> HRESULT, + fn Remove( + ObjectStorageCLSID: BSTR, + ) -> HRESULT, + fn GetStorageFileName( + ObjectStorageCLSID: BSTR, + KeyName: BSTR, + FileName: BSTR, + Folder: BSTR, + FilePath: *mut BSTR, + ) -> HRESULT, + fn RemoveStorageFileName( + ObjectStorageCLSID: BSTR, + KeyName: BSTR, + DeleteFile: VARIANT_BOOL, + ) -> HRESULT, + fn IsUISupported( + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + Object: *mut IUnknown, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn DisplayUI( + hWnd: c_long, + Title: BSTR, + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + Object: *mut IUnknown, + ) -> HRESULT, + fn MatchesAttributes( + Attributes: BSTR, + Matches: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9285b776, 0x2e7b, 0x4bc0, 0xb5, 0x3e, 0x58, 0x0e, 0xb6, 0xfa, 0x96, 0x7f)] +interface ISpeechObjectTokens(ISpeechObjectTokensVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Token: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn get__NewEnum( + ppEnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xca7eac50, 0x2d01, 0x4145, 0x86, 0xd4, 0x5a, 0xe7, 0xd7, 0x0f, 0x44, 0x69)] +interface ISpeechObjectTokenCategory(ISpeechObjectTokenCategoryVtbl): IDispatch(IDispatchVtbl) { + fn get_Id( + Id: *mut BSTR, + ) -> HRESULT, + fn put_Default( + TokenId: BSTR, + ) -> HRESULT, + fn get_Default( + TokenId: *mut BSTR, + ) -> HRESULT, + fn SetId( + Id: BSTR, + CreateIfNotExist: VARIANT_BOOL, + ) -> HRESULT, + fn GetDataKey( + Location: SpeechDataKeyLocation, + DataKey: *mut *mut ISpeechDataKey, + ) -> HRESULT, + fn EnumerateTokens( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + Tokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x11b103d8, 0x1142, 0x4edf, 0xa0, 0x93, 0x82, 0xfb, 0x39, 0x15, 0xf8, 0xcc)] +interface ISpeechAudioBufferInfo(ISpeechAudioBufferInfoVtbl): IDispatch(IDispatchVtbl) { + fn get_MinNotification( + MinNotification: *mut c_long, + ) -> HRESULT, + fn put_MinNotification( + MinNotification: c_long, + ) -> HRESULT, + fn get_BufferSize( + BufferSize: *mut c_long, + ) -> HRESULT, + fn put_BufferSize( + BufferSize: c_long, + ) -> HRESULT, + fn get_EventBias( + EventBias: *mut c_long, + ) -> HRESULT, + fn put_EventBias( + EventBias: c_long, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc62d9c91, 0x7458, 0x47f6, 0x86, 0x2d, 0x1e, 0xf8, 0x6f, 0xb0, 0xb2, 0x78)] +interface ISpeechAudioStatus(ISpeechAudioStatusVtbl): IDispatch(IDispatchVtbl) { + fn get_FreeBufferSpace( + FreeBufferSpace: *mut c_long, + ) -> HRESULT, + fn get_NonBlockingIO( + NonBlockingIO: *mut c_long, + ) -> HRESULT, + fn get_State( + State: *mut SpeechAudioState, + ) -> HRESULT, + fn get_CurrentSeekPosition( + CurrentSeekPosition: *mut VARIANT, + ) -> HRESULT, + fn get_CurrentDevicePosition( + CurrentDevicePosition: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe6e9c590, 0x3e18, 0x40e3, 0x82, 0x99, 0x06, 0x1f, 0x98, 0xbd, 0xe7, 0xc7)] +interface ISpeechAudioFormat(ISpeechAudioFormatVtbl): IDispatch(IDispatchVtbl) { + fn get_Type( + AudioFormat: *mut SpeechAudioFormatType, + ) -> HRESULT, + fn put_Type( + AudioFormat: SpeechAudioFormatType, + ) -> HRESULT, + fn get_Guid( + Guid: *mut BSTR, + ) -> HRESULT, + fn put_Guid( + Guid: BSTR, + ) -> HRESULT, + fn GetWaveFormatEx( + SpeechWaveFormatEx: *mut *mut ISpeechWaveFormatEx, + ) -> HRESULT, + fn SetWaveFormatEx( + SpeechWaveFormatEx: *mut ISpeechWaveFormatEx, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7a1ef0d5, 0x1581, 0x4741, 0x88, 0xe4, 0x20, 0x9a, 0x49, 0xf1, 0x1a, 0x10)] +interface ISpeechWaveFormatEx(ISpeechWaveFormatExVtbl): IDispatch(IDispatchVtbl) { + fn get_FormatTag( + FormatTag: *mut c_short, + ) -> HRESULT, + fn put_FormatTag( + FormatTag: c_short, + ) -> HRESULT, + fn get_Channels( + Channels: *mut c_short, + ) -> HRESULT, + fn put_Channels( + Channels: c_short, + ) -> HRESULT, + fn get_SamplesPerSec( + SamplesPerSec: *mut c_long, + ) -> HRESULT, + fn put_SamplesPerSec( + SamplesPerSec: c_long, + ) -> HRESULT, + fn get_AvgBytesPerSec( + AvgBytesPerSec: *mut c_long, + ) -> HRESULT, + fn put_AvgBytesPerSec( + AvgBytesPerSec: c_long, + ) -> HRESULT, + fn get_BlockAlign( + BlockAlign: *mut c_short, + ) -> HRESULT, + fn put_BlockAlign( + BlockAlign: c_short, + ) -> HRESULT, + fn get_BitsPerSample( + BitsPerSample: *mut c_short, + ) -> HRESULT, + fn put_BitsPerSample( + BitsPerSample: c_short, + ) -> HRESULT, + fn get_ExtraData( + ExtraData: *mut VARIANT, + ) -> HRESULT, + fn put_ExtraData( + ExtraData: VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6450336f, 0x7d49, 0x4ced, 0x80, 0x97, 0x49, 0xd6, 0xde, 0xe3, 0x72, 0x94)] +interface ISpeechBaseStream(ISpeechBaseStreamVtbl): IDispatch(IDispatchVtbl) { + fn get_Format( + AudioFormat: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn putref_Format( + AudioFormat: *mut ISpeechAudioFormat, + ) -> HRESULT, + fn Read( + Buffer: *mut VARIANT, + NumberOfBytes: c_long, + BytesRead: *mut c_long, + ) -> HRESULT, + fn Write( + Buffer: VARIANT, + BytesWritten: *mut c_long, + ) -> HRESULT, + fn Seek( + Position: VARIANT, + Origin: SpeechStreamSeekPositionType, + NewPosition: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xaf67f125, 0xab39, 0x4e93, 0xb4, 0xa2, 0xcc, 0x2e, 0x66, 0xe1, 0x82, 0xa7)] +interface ISpeechFileStream(ISpeechFileStreamVtbl): ISpeechBaseStream(ISpeechBaseStreamVtbl) { + fn Open( + FileName: BSTR, + FileMode: SpeechStreamFileMode, + DoEvents: VARIANT_BOOL, + ) -> HRESULT, + fn Close() -> HRESULT, +}} +RIDL!{#[uuid(0xeeb14b68, 0x808b, 0x4abe, 0xa5, 0xea, 0xb5, 0x1d, 0xa7, 0x58, 0x80, 0x08)] +interface ISpeechMemoryStream(ISpeechMemoryStreamVtbl): ISpeechBaseStream(ISpeechBaseStreamVtbl) { + fn SetData( + Data: VARIANT, + ) -> HRESULT, + fn GetData( + pData: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x1a9e9f4f, 0x104f, 0x4db8, 0xa1, 0x15, 0xef, 0xd7, 0xfd, 0x0c, 0x97, 0xae)] +interface ISpeechCustomStream(ISpeechCustomStreamVtbl): ISpeechBaseStream(ISpeechBaseStreamVtbl) { + fn get_BaseStream( + ppUnkStream: *mut *mut IUnknown, + ) -> HRESULT, + fn putref_BaseStream( + pUnkStream: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xcff8e175, 0x019e, 0x11d3, 0xa0, 0x8e, 0x00, 0xc0, 0x4f, 0x8e, 0xf9, 0xb5)] +interface ISpeechAudio(ISpeechAudioVtbl): ISpeechBaseStream(ISpeechBaseStreamVtbl) { + fn get_Status( + Status: *mut *mut ISpeechAudioStatus, + ) -> HRESULT, + fn get_BufferInfo( + BufferInfo: *mut *mut ISpeechAudioBufferInfo, + ) -> HRESULT, + fn get_DefaultFormat( + StreamFormat: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_Volume( + Volume: *mut c_long, + ) -> HRESULT, + fn put_Volume( + Volume: c_long, + ) -> HRESULT, + fn get_BufferNotifySize( + BufferNotifySize: *mut c_long, + ) -> HRESULT, + fn put_BufferNotifySize( + BufferNotifySize: c_long, + ) -> HRESULT, + fn get_EventHandle( + EventHandle: *mut c_long, + ) -> HRESULT, + fn SetState( + State: SpeechAudioState, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3c76af6d, 0x1fd7, 0x4831, 0x81, 0xd1, 0x3b, 0x71, 0xd5, 0xa1, 0x3c, 0x44)] +interface ISpeechMMSysAudio(ISpeechMMSysAudioVtbl): ISpeechAudio(ISpeechAudioVtbl) { + fn get_DeviceId( + DeviceId: *mut c_long, + ) -> HRESULT, + fn put_DeviceId( + DeviceId: c_long, + ) -> HRESULT, + fn get_LineId( + LineId: *mut c_long, + ) -> HRESULT, + fn put_LineId( + LineId: c_long, + ) -> HRESULT, + fn get_MMHandle( + Handle: *mut c_long, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x269316d8, 0x57bd, 0x11d2, 0x9e, 0xee, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96)] +interface ISpeechVoice(ISpeechVoiceVtbl): IDispatch(IDispatchVtbl) { + fn get_Status( + Status: *mut *mut ISpeechVoiceStatus, + ) -> HRESULT, + fn get_Voice( + Voice: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn putref_Voice( + Voice: *mut ISpeechObjectToken, + ) -> HRESULT, + fn get_AudioOutput( + AudioOutput: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn putref_AudioOutput( + AudioOutput: *mut ISpeechObjectToken, + ) -> HRESULT, + fn get_AudioOutputStream( + AudioOutputStream: *mut *mut ISpeechBaseStream, + ) -> HRESULT, + fn putref_AudioOutputStream( + AudioOutputStream: *mut ISpeechBaseStream, + ) -> HRESULT, + fn get_Rate( + Rate: *mut c_long, + ) -> HRESULT, + fn put_Rate( + Rate: c_long, + ) -> HRESULT, + fn get_Volume( + Volume: *mut c_long, + ) -> HRESULT, + fn put_Volume( + Volume: c_long, + ) -> HRESULT, + fn put_AllowAudioOutputFormatChangesOnNextSet( + Allow: VARIANT_BOOL, + ) -> HRESULT, + fn get_AllowAudioOutputFormatChangesOnNextSet( + Allow: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_EventInterests( + EventInterestFlags: *mut SpeechVoiceEvents, + ) -> HRESULT, + fn put_EventInterests( + EventInterestFlags: SpeechVoiceEvents, + ) -> HRESULT, + fn put_Priority( + Priority: SpeechVoicePriority, + ) -> HRESULT, + fn get_Priority( + Priority: *mut SpeechVoicePriority, + ) -> HRESULT, + fn put_AlertBoundary( + Boundary: SpeechVoiceEvents, + ) -> HRESULT, + fn get_AlertBoundary( + Boundary: *mut SpeechVoiceEvents, + ) -> HRESULT, + fn put_SynchronousSpeakTimeout( + msTimeout: c_long, + ) -> HRESULT, + fn get_SynchronousSpeakTimeout( + msTimeOut: *mut c_long, + ) -> HRESULT, + fn Speak( + Text: BSTR, + Flags: SpeechVoiceSpeakFlags, + StreamNumber: *mut c_long, + ) -> HRESULT, + fn SpeakStream( + Stream: *mut ISpeechBaseStream, + Flags: SpeechVoiceSpeakFlags, + StreamNumber: *mut c_long, + ) -> HRESULT, + fn Pause() -> HRESULT, + fn Resume() -> HRESULT, + fn Skip( + Type: BSTR, + NumItems: c_long, + NumSkipped: c_long, + ) -> HRESULT, + fn GetVoices( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + ObjectTokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, + fn GetAudioOutputs( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + ObjectTokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, + fn WaitUntilDone( + msTimeout: c_long, + Done: *mut VARIANT_BOOL, + ) -> HRESULT, + fn SpeakCompleteEvent( + Handle: *mut c_long, + ) -> HRESULT, + fn IsUISupported( + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn DisplayUI( + hWndParent: c_long, + Title: BSTR, + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8be47b07, 0x57f6, 0x11d2, 0x9e, 0xee, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96)] +interface ISpeechVoiceStatus(ISpeechVoiceStatusVtbl): IDispatch(IDispatchVtbl) { + fn get_CurrentStreamNumber( + StreamNumber: *mut c_long, + ) -> HRESULT, + fn get_LastStreamNumberQueued( + StreamNumber: *mut c_long, + ) -> HRESULT, + fn get_LastHResult( + HResult: *mut c_long, + ) -> HRESULT, + fn get_RunningState( + State: *mut SpeechRunState, + ) -> HRESULT, + fn get_InputWordPosition( + Position: *mut c_long, + ) -> HRESULT, + fn get_InputWordLength( + Length: *mut c_long, + ) -> HRESULT, + fn get_InputSentencePosition( + Position: *mut c_long, + ) -> HRESULT, + fn get_InputSentenceLength( + Length: *mut c_long, + ) -> HRESULT, + fn get_LastBookmark( + Bookmark: *mut BSTR, + ) -> HRESULT, + fn get_LastBookmarkId( + BookmarkId: *mut c_long, + ) -> HRESULT, + fn get_PhonemeId( + PhoneId: *mut c_short, + ) -> HRESULT, + fn get_VisemeId( + VisemeId: *mut c_short, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa372acd1, 0x3bef, 0x4bbd, 0x8f, 0xfb, 0xcb, 0x3e, 0x2b, 0x41, 0x6a, 0xf8)] +interface _ISpeechVoiceEvents(_ISpeechVoiceEventsVtbl): IDispatch(IDispatchVtbl) {}} +RIDL!{#[uuid(0x2d5f1c0c, 0xbd75, 0x4b08, 0x94, 0x78, 0x3b, 0x11, 0xfe, 0xa2, 0x58, 0x6c)] +interface ISpeechRecognizer(ISpeechRecognizerVtbl): IDispatch(IDispatchVtbl) { + fn putref_Recognizer( + Recognizer: *mut ISpeechObjectToken, + ) -> HRESULT, + fn get_Recognizer( + Recognizer: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn put_AllowAudioInputFormatChangesOnNextSet( + Allow: VARIANT_BOOL, + ) -> HRESULT, + fn get_AllowAudioInputFormatChangesOnNextSet( + Allow: *mut VARIANT_BOOL, + ) -> HRESULT, + fn putref_AudioInput( + AudioInput: *mut ISpeechObjectToken, + ) -> HRESULT, + fn get_AudioInput( + AudioInput: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn putref_AudioInputStream( + AudioInputStream: *mut ISpeechBaseStream, + ) -> HRESULT, + fn get_AudioInputStream( + AudioInputStream: *mut *mut ISpeechBaseStream, + ) -> HRESULT, + fn get_IsShared( + Shared: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_State( + State: SpeechRecognizerState, + ) -> HRESULT, + fn get_State( + State: *mut SpeechRecognizerState, + ) -> HRESULT, + fn get_Status( + Status: *mut *mut ISpeechRecognizerStatus, + ) -> HRESULT, + fn putref_Profile( + Profile: *mut ISpeechObjectToken, + ) -> HRESULT, + fn get_Profile( + Profile: *mut *mut ISpeechObjectToken, + ) -> HRESULT, + fn EmulateRecognition( + TextElements: VARIANT, + ElementDisplayAttributes: *mut VARIANT, + LanguageId: c_long, + ) -> HRESULT, + fn CreateRecoContext( + NewContext: *mut *mut ISpeechRecoContext, + ) -> HRESULT, + fn GetFormat( + Type: SpeechFormatType, + Format: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn SetPropertyNumber( + Name: BSTR, + Value: c_long, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn GetPropertyNumber( + Name: BSTR, + Value: *mut c_long, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn SetPropertyString( + Name: BSTR, + Value: BSTR, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn GetPropertyString( + Name: BSTR, + Value: *mut BSTR, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn IsUISupported( + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + Supported: *mut VARIANT_BOOL, + ) -> HRESULT, + fn DisplayUI( + hWndParent: c_long, + Title: BSTR, + TypeOfUI: BSTR, + ExtraData: *const VARIANT, + ) -> HRESULT, + fn GetRecognizers( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + ObjectTokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, + fn GetAudioInputs( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + ObjectTokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, + fn GetProfiles( + RequiredAttributes: BSTR, + OptionalAttributes: BSTR, + ObjectTokens: *mut *mut ISpeechObjectTokens, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbff9e781, 0x53ec, 0x484e, 0xbb, 0x8a, 0x0e, 0x1b, 0x55, 0x51, 0xe3, 0x5c)] +interface ISpeechRecognizerStatus(ISpeechRecognizerStatusVtbl): IDispatch(IDispatchVtbl) { + fn get_AudioStatus( + AudioStatus: *mut *mut ISpeechAudioStatus, + ) -> HRESULT, + fn get_CurrentStreamPosition( + pCurrentStreamPos: *mut VARIANT, + ) -> HRESULT, + fn get_CurrentStreamNumber( + StreamNumber: *mut c_long, + ) -> HRESULT, + fn get_NumberOfActiveRules( + NumberOfActiveRules: *mut c_long, + ) -> HRESULT, + fn get_ClsidEngine( + ClsidEngine: *mut BSTR, + ) -> HRESULT, + fn get_SupportedLanguages( + SupportedLanguages: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x580aa49d, 0x7e1e, 0x4809, 0xb8, 0xe2, 0x57, 0xda, 0x80, 0x61, 0x04, 0xb8)] +interface ISpeechRecoContext(ISpeechRecoContextVtbl): IDispatch(IDispatchVtbl) { + fn get_Recognizer( + Recognizer: *mut *mut ISpeechRecognizer, + ) -> HRESULT, + fn get_AudioInputInterferenceStatus( + Interference: *mut SpeechInterference, + ) -> HRESULT, + fn get_RequestedUIType( + UIType: *mut BSTR, + ) -> HRESULT, + fn putref_Voice( + Voice: *mut ISpeechVoice, + ) -> HRESULT, + fn get_Voice( + Voice: *mut *mut ISpeechVoice, + ) -> HRESULT, + fn put_AllowVoiceFormatMatchingOnNextSet( + Allow: VARIANT_BOOL, + ) -> HRESULT, + fn get_AllowVoiceFormatMatchingOnNextSet( + Allow: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_VoicePurgeEvent( + EventInterest: SpeechRecoEvents, + ) -> HRESULT, + fn get_VoicePurgeEvent( + EventInterest: *mut SpeechRecoEvents, + ) -> HRESULT, + fn put_EventInterests( + EventInterest: SpeechRecoEvents, + ) -> HRESULT, + fn get_EventInterests( + EventInterest: *mut SpeechRecoEvents, + ) -> HRESULT, + fn put_CmdMaxAlternates( + MaxAlternates: c_long, + ) -> HRESULT, + fn get_CmdMaxAlternates( + MaxAlternates: *mut c_long, + ) -> HRESULT, + fn put_State( + State: SpeechRecoContextState, + ) -> HRESULT, + fn get_State( + State: *mut SpeechRecoContextState, + ) -> HRESULT, + fn put_RetainedAudio( + Option: SpeechRetainedAudioOptions, + ) -> HRESULT, + fn get_RetainedAudio( + Option: *mut SpeechRetainedAudioOptions, + ) -> HRESULT, + fn putref_RetainedAudioFormat( + Format: *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_RetainedAudioFormat( + Format: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn Pause() -> HRESULT, + fn Resume() -> HRESULT, + fn CreateGrammar( + GrammarId: VARIANT, + Grammar: *mut *mut ISpeechRecoGrammar, + ) -> HRESULT, + fn CreateResultFromMemory( + ResultBlock: *mut VARIANT, + Result: *mut *mut ISpeechRecoResult, + ) -> HRESULT, + fn Bookmark( + Options: SpeechBookmarkOptions, + StreamPos: VARIANT, + BookmarkId: VARIANT, + ) -> HRESULT, + fn SetAdaptationData( + AdaptationString: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb6d6f79f, 0x2158, 0x4e50, 0xb5, 0xbc, 0x9a, 0x9c, 0xcd, 0x85, 0x2a, 0x09)] +interface ISpeechRecoGrammar(ISpeechRecoGrammarVtbl): IDispatch(IDispatchVtbl) { + fn get_Id( + Id: *mut VARIANT, + ) -> HRESULT, + fn get_RecoContext( + RecoContext: *mut *mut ISpeechRecoContext, + ) -> HRESULT, + fn put_State( + State: SpeechGrammarState, + ) -> HRESULT, + fn get_State( + State: *mut SpeechGrammarState, + ) -> HRESULT, + fn get_Rules( + Rules: *mut *mut ISpeechGrammarRules, + ) -> HRESULT, + fn Reset( + NewLanguage: SpeechLanguageId, + ) -> HRESULT, + fn CmdLoadFromFile( + FileName: BSTR, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn CmdLoadFromObject( + ClassId: BSTR, + GrammarName: BSTR, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn CmdLoadFromResource( + hModule: c_long, + ResourceName: VARIANT, + ResourceType: VARIANT, + LanguageId: SpeechLanguageId, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn CmdLoadFromMemory( + GrammarData: VARIANT, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn CmdLoadFromProprietaryGrammar( + ProprietaryGuid: BSTR, + PriorietaryString: BSTR, + ProprietaryData: VARIANT, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn CmdSetRuleState( + Name: BSTR, + State: SpeechRuleState, + ) -> HRESULT, + fn CmdSetRuleIdState( + RuleId: c_long, + State: SpeechRuleState, + ) -> HRESULT, + fn DictationLoad( + TopicName: BSTR, + LoadOption: SpeechLoadOption, + ) -> HRESULT, + fn DictationUnload() -> HRESULT, + fn DictationSetState( + State: SpeechRuleState, + ) -> HRESULT, + fn SetWordSequenceData( + Text: BSTR, + TextLength: c_long, + Info: *mut ISpeechTextSelectionInformation, + ) -> HRESULT, + fn SetTextSelection( + Info: *mut ISpeechTextSelectionInformation, + ) -> HRESULT, + fn IsPronounceable( + Word: BSTR, + WordPronounceable: *mut SpeechWordPronounceable, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7b8fcb42, 0x0e9d, 0x4f00, 0xa0, 0x48, 0x7b, 0x04, 0xd6, 0x17, 0x9d, 0x3d)] +interface _ISpeechRecoContextEvents(_ISpeechRecoContextEventsVtbl): IDispatch(IDispatchVtbl) {}} +RIDL!{#[uuid(0xafe719cf, 0x5dd1, 0x44f2, 0x99, 0x9c, 0x7a, 0x39, 0x9f, 0x1c, 0xfc, 0xcc)] +interface ISpeechGrammarRule(ISpeechGrammarRuleVtbl): IDispatch(IDispatchVtbl) { + fn get_Attributes( + Attributes: *mut SpeechRuleAttributes, + ) -> HRESULT, + fn get_InitialState( + State: *mut *mut ISpeechGrammarRuleState, + ) -> HRESULT, + fn get_Name( + Name: *mut BSTR, + ) -> HRESULT, + fn get_Id( + Id: *mut c_long, + ) -> HRESULT, + fn Clear() -> HRESULT, + fn AddResource( + ResourceName: BSTR, + ResourceValue: BSTR, + ) -> HRESULT, + fn AddState( + State: *mut *mut ISpeechGrammarRuleState, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6ffa3b44, 0xfc2d, 0x40d1, 0x8a, 0xfc, 0x32, 0x91, 0x1c, 0x7f, 0x1a, 0xd1)] +interface ISpeechGrammarRules(ISpeechGrammarRulesVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn FindRule( + RuleNameOrId: VARIANT, + Rule: *mut *mut ISpeechGrammarRule, + ) -> HRESULT, + fn Item( + Index: c_long, + Rule: *mut *mut ISpeechGrammarRule, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, + fn get_Dynamic( + Dynamic: *mut VARIANT_BOOL, + ) -> HRESULT, + fn Add( + RuleName: BSTR, + Attributes: SpeechRuleAttributes, + RuleId: c_long, + Rule: *mut *mut ISpeechGrammarRule, + ) -> HRESULT, + fn Commit() -> HRESULT, + fn CommitAndSave( + ErrorText: *mut BSTR, + SaveStream: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd4286f2c, 0xee67, 0x45ae, 0xb9, 0x28, 0x28, 0xd6, 0x95, 0x36, 0x2e, 0xda)] +interface ISpeechGrammarRuleState(ISpeechGrammarRuleStateVtbl): IDispatch(IDispatchVtbl) { + fn get_Rule( + Rule: *mut *mut ISpeechGrammarRule, + ) -> HRESULT, + fn get_Transitions( + Transitions: *mut *mut ISpeechGrammarRuleStateTransitions, + ) -> HRESULT, + fn AddWordTransition( + DestState: *mut ISpeechGrammarRuleState, + Words: BSTR, + Separators: BSTR, + Type: SpeechGrammarWordType, + PropertyName: BSTR, + PropertyId: c_long, + PropertyValue: *mut VARIANT, + Weight: c_float, + ) -> HRESULT, + fn AddRuleTransition( + DestinationState: *mut ISpeechGrammarRuleState, + Rule: *mut ISpeechGrammarRule, + PropertyName: BSTR, + PropertyId: c_long, + PropertyValue: *mut VARIANT, + Weight: c_float, + ) -> HRESULT, + fn AddSpecialTransition( + DestinationState: *mut ISpeechGrammarRuleState, + Type: SpeechSpecialTransitionType, + PropertyName: BSTR, + PropertyId: c_long, + PropertyValue: *mut VARIANT, + Weight: c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xcafd1db1, 0x41d1, 0x4a06, 0x98, 0x63, 0xe2, 0xe8, 0x1d, 0xa1, 0x7a, 0x9a)] +interface ISpeechGrammarRuleStateTransition(ISpeechGrammarRuleStateTransitionVtbl): + IDispatch(IDispatchVtbl) { + fn get_Type( + Type: *mut SpeechGrammarRuleStateTransitionType, + ) -> HRESULT, + fn get_Text( + Text: *mut BSTR, + ) -> HRESULT, + fn get_Rule( + Rule: *mut *mut ISpeechGrammarRule, + ) -> HRESULT, + fn get_Weight( + Weight: *mut VARIANT, + ) -> HRESULT, + fn get_PropertyName( + PropertyName: *mut BSTR, + ) -> HRESULT, + fn get_PropertyId( + PropertyId: *mut c_long, + ) -> HRESULT, + fn get_PropertyValue( + PropertyValue: *mut VARIANT, + ) -> HRESULT, + fn get_NextState( + NextState: *mut *mut ISpeechGrammarRuleState, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xeabce657, 0x75bc, 0x44a2, 0xaa, 0x7f, 0xc5, 0x64, 0x76, 0x74, 0x29, 0x63)] +interface ISpeechGrammarRuleStateTransitions(ISpeechGrammarRuleStateTransitionsVtbl): + IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Transition: *mut *mut ISpeechGrammarRuleStateTransition, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b9c7e7a, 0x6eee, 0x4ded, 0x90, 0x92, 0x11, 0x65, 0x72, 0x79, 0xad, 0xbe)] +interface ISpeechTextSelectionInformation(ISpeechTextSelectionInformationVtbl): + IDispatch(IDispatchVtbl) { + fn put_ActiveOffset( + ActiveOffset: c_long, + ) -> HRESULT, + fn get_ActiveOffset( + ActiveOffset: *mut c_long, + ) -> HRESULT, + fn put_ActiveLength( + ActiveLength: c_long, + ) -> HRESULT, + fn get_ActiveLength( + ActiveLength: *mut c_long, + ) -> HRESULT, + fn put_SelectionOffset( + SelectionOffset: c_long, + ) -> HRESULT, + fn get_SelectionOffset( + SelectionOffset: *mut c_long, + ) -> HRESULT, + fn put_SelectionLength( + SelectionLength: c_long, + ) -> HRESULT, + fn get_SelectionLength( + SelectionLength: *mut c_long, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xed2879cf, 0xced9, 0x4ee6, 0xa5, 0x34, 0xde, 0x01, 0x91, 0xd5, 0x46, 0x8d)] +interface ISpeechRecoResult(ISpeechRecoResultVtbl): IDispatch(IDispatchVtbl) { + fn get_RecoContext( + RecoContext: *mut *mut ISpeechRecoContext, + ) -> HRESULT, + fn get_Times( + Times: *mut *mut ISpeechRecoResultTimes, + ) -> HRESULT, + fn putref_AudioFormat( + Format: *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_AudioFormat( + Format: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_PhraseInfo( + PhraseInfo: *mut *mut ISpeechPhraseInfo, + ) -> HRESULT, + fn Alternates( + RequestCount: c_long, + StartElement: c_long, + Elements: c_long, + Alternates: *mut *mut ISpeechPhraseAlternates, + ) -> HRESULT, + fn Audio( + StartElement: c_long, + Elements: c_long, + Stream: *mut *mut ISpeechMemoryStream, + ) -> HRESULT, + fn SpeakAudio( + StartElement: c_long, + Elements: c_long, + Flags: SpeechVoiceSpeakFlags, + StreamNumber: *mut c_long, + ) -> HRESULT, + fn SaveToMemory( + ResultBlock: *mut VARIANT, + ) -> HRESULT, + fn DiscardResultInfo( + ValueTypes: SpeechDiscardType, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x62b3b8fb, 0xf6e7, 0x41be, 0xbd, 0xcb, 0x05, 0x6b, 0x1c, 0x29, 0xef, 0xc0)] +interface ISpeechRecoResultTimes(ISpeechRecoResultTimesVtbl): IDispatch(IDispatchVtbl) { + fn get_StreamTime( + Time: *mut VARIANT, + ) -> HRESULT, + fn get_Length( + Length: *mut VARIANT, + ) -> HRESULT, + fn get_TickCount( + TickCount: *mut c_long, + ) -> HRESULT, + fn get_OffsetFromStart( + OffsetFromStart: *mut VARIANT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x27864a2a, 0x2b9f, 0x4cb8, 0x92, 0xd3, 0x0d, 0x27, 0x22, 0xfd, 0x1e, 0x73)] +interface ISpeechPhraseAlternate(ISpeechPhraseAlternateVtbl): IDispatch(IDispatchVtbl) { + fn get_RecoResult( + RecoResult: *mut *mut ISpeechRecoResult, + ) -> HRESULT, + fn get_StartElementInResult( + StartElement: *mut c_long, + ) -> HRESULT, + fn get_NumberOfElementsInResult( + NumberOfElements: *mut c_long, + ) -> HRESULT, + fn get_PhraseInfo( + PhraseInfo: *mut *mut ISpeechPhraseInfo, + ) -> HRESULT, + fn Commit() -> HRESULT, +}} +RIDL!{#[uuid(0xb238b6d5, 0xf276, 0x4c3d, 0xa6, 0xc1, 0x29, 0x74, 0x80, 0x1c, 0x3c, 0xc2)] +interface ISpeechPhraseAlternates(ISpeechPhraseAlternatesVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + PhraseAlternate: *mut *mut ISpeechPhraseAlternate, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x961559cf, 0x4e67, 0x4662, 0x8b, 0xf0, 0xd9, 0x3f, 0x1f, 0xcd, 0x61, 0xb3)] +interface ISpeechPhraseInfo(ISpeechPhraseInfoVtbl): IDispatch(IDispatchVtbl) { + fn get_LanguageId( + LanguageId: *mut c_long, + ) -> HRESULT, + fn get_GrammarId( + GrammarId: *mut VARIANT, + ) -> HRESULT, + fn get_StartTime( + StartTime: *mut VARIANT, + ) -> HRESULT, + fn get_AudioStreamPosition( + AudioStreamPosition: *mut VARIANT, + ) -> HRESULT, + fn get_AudioSizeBytes( + pAudioSizeBytes: *mut c_long, + ) -> HRESULT, + fn get_RetainedSizeBytes( + RetainedSizeBytes: *mut c_long, + ) -> HRESULT, + fn get_AudioSizeTime( + AudioSizeTime: *mut c_long, + ) -> HRESULT, + fn get_Rule( + Rule: *mut *mut ISpeechPhraseRule, + ) -> HRESULT, + fn get_Properties( + Properties: *mut *mut ISpeechPhraseProperties, + ) -> HRESULT, + fn get_Elements( + Elements: *mut *mut ISpeechPhraseElements, + ) -> HRESULT, + fn get_Replacements( + Replacements: *mut *mut ISpeechPhraseReplacements, + ) -> HRESULT, + fn get_EngineId( + EngineIdGuid: *mut BSTR, + ) -> HRESULT, + fn get_EnginePrivateData( + PrivateData: *mut VARIANT, + ) -> HRESULT, + fn SaveToMemory( + PhraseBlock: *mut VARIANT, + ) -> HRESULT, + fn GetText( + StartElement: c_long, + Elements: c_long, + UseReplacements: VARIANT_BOOL, + Text: *mut BSTR, + ) -> HRESULT, + fn GetDisplayAttributes( + StartElement: c_long, + Elements: c_long, + UseReplacements: VARIANT_BOOL, + DisplayAttributes: *mut SpeechDisplayAttributes, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe6176f96, 0xe373, 0x4801, 0xb2, 0x23, 0x3b, 0x62, 0xc0, 0x68, 0xc0, 0xb4)] +interface ISpeechPhraseElement(ISpeechPhraseElementVtbl): IDispatch(IDispatchVtbl) { + fn get_AudioTimeOffset( + AudioTimeOffset: *mut c_long, + ) -> HRESULT, + fn get_AudioSizeTime( + AudioSizeTime: *mut c_long, + ) -> HRESULT, + fn get_AudioStreamOffset( + AudioStreamOffset: *mut c_long, + ) -> HRESULT, + fn get_AudioSizeBytes( + AudioSizeBytes: *mut c_long, + ) -> HRESULT, + fn get_RetainedStreamOffset( + RetainedStreamOffset: *mut c_long, + ) -> HRESULT, + fn get_RetainedSizeBytes( + RetainedSizeBytes: *mut c_long, + ) -> HRESULT, + fn get_DisplayText( + DisplayText: *mut BSTR, + ) -> HRESULT, + fn get_LexicalForm( + LexicalForm: *mut BSTR, + ) -> HRESULT, + fn get_Pronunciation( + Pronunciation: *mut VARIANT, + ) -> HRESULT, + fn get_DisplayAttributes( + DisplayAttributes: *mut SpeechDisplayAttributes, + ) -> HRESULT, + fn get_RequiredConfidence( + RequiredConfidence: *mut SpeechEngineConfidence, + ) -> HRESULT, + fn get_ActualConfidence( + ActualConfidence: *mut SpeechEngineConfidence, + ) -> HRESULT, + fn get_EngineConfidence( + EngineConfident: *mut c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0626b328, 0x3478, 0x467d, 0xa0, 0xb3, 0xd0, 0x85, 0x3b, 0x93, 0xdd, 0xa3)] +interface ISpeechPhraseElements(ISpeechPhraseElementsVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Element: *mut *mut ISpeechPhraseElement, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2890a410, 0x53a7, 0x4fb5, 0x94, 0xec, 0x06, 0xd4, 0x99, 0x8e, 0x3d, 0x02)] +interface ISpeechPhraseReplacement(ISpeechPhraseReplacementVtbl): IDispatch(IDispatchVtbl) { + fn get_DisplayAttributes( + DisplayAttributes: *mut SpeechDisplayAttributes, + ) -> HRESULT, + fn get_Text( + Text: *mut BSTR, + ) -> HRESULT, + fn get_FirstElement( + FirstElement: *mut c_long, + ) -> HRESULT, + fn get_NumberOfElements( + NumberOfElements: *mut c_long, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x38bc662f, 0x2257, 0x4525, 0x95, 0x9e, 0x20, 0x69, 0xd2, 0x59, 0x6c, 0x05)] +interface ISpeechPhraseReplacements(ISpeechPhraseReplacementsVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Reps: *mut *mut ISpeechPhraseReplacement, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xce563d48, 0x961e, 0x4732, 0xa2, 0xe1, 0x37, 0x8a, 0x42, 0xb4, 0x30, 0xbe)] +interface ISpeechPhraseProperty(ISpeechPhrasePropertyVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + Name: *mut BSTR, + ) -> HRESULT, + fn get_Id( + Id: *mut c_long, + ) -> HRESULT, + fn get_Value( + Value: *mut VARIANT, + ) -> HRESULT, + fn get_FirstElement( + FirstElement: *mut c_long, + ) -> HRESULT, + fn get_NumberOfElements( + NumberOfElements: *mut c_long, + ) -> HRESULT, + fn get_EngineConfidence( + Confidence: *mut c_float, + ) -> HRESULT, + fn get_Confidence( + Confidence: *mut SpeechEngineConfidence, + ) -> HRESULT, + fn get_Parent( + ParentProperty: *mut *mut ISpeechPhraseProperty, + ) -> HRESULT, + fn get_Children( + Children: *mut *mut ISpeechPhraseProperties, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x08166b47, 0x102e, 0x4b23, 0xa5, 0x99, 0xbd, 0xb9, 0x8d, 0xbf, 0xd1, 0xf4)] +interface ISpeechPhraseProperties(ISpeechPhrasePropertiesVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Property: *mut *mut ISpeechPhraseProperty, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa7bfe112, 0xa4a0, 0x48d9, 0xb6, 0x02, 0xc3, 0x13, 0x84, 0x3f, 0x69, 0x64)] +interface ISpeechPhraseRule(ISpeechPhraseRuleVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + Name: *mut BSTR, + ) -> HRESULT, + fn get_Id( + Id: *mut c_long, + ) -> HRESULT, + fn get_FirstElement( + FirstElement: *mut c_long, + ) -> HRESULT, + fn get_NumberOfElements( + NumberOfElements: *mut c_long, + ) -> HRESULT, + fn get_Parent( + Parent: *mut *mut ISpeechPhraseRule, + ) -> HRESULT, + fn get_Children( + Children: *mut *mut ISpeechPhraseRules, + ) -> HRESULT, + fn get_Confidence( + ActualConfidence: *mut SpeechEngineConfidence, + ) -> HRESULT, + fn get_EngineConfidence( + Confidence: *mut c_float, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9047d593, 0x01dd, 0x4b72, 0x81, 0xa3, 0xe4, 0xa0, 0xca, 0x69, 0xf4, 0x07)] +interface ISpeechPhraseRules(ISpeechPhraseRulesVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Rule: *mut *mut ISpeechPhraseRule, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3da7627a, 0xc7ae, 0x4b23, 0x87, 0x08, 0x63, 0x8c, 0x50, 0x36, 0x2c, 0x25)] +interface ISpeechLexicon(ISpeechLexiconVtbl): IDispatch(IDispatchVtbl) { + fn get_GenerationId( + GenerationId: *mut c_long, + ) -> HRESULT, + fn GetWords( + Flags: SpeechLexiconType, + GenerationID: *mut c_long, + Words: *mut *mut ISpeechLexiconWords, + ) -> HRESULT, + fn AddPronunciation( + bstrWord: BSTR, + LangId: SpeechLanguageId, + PartOfSpeech: SpeechPartOfSpeech, + bstrPronunciation: BSTR, + ) -> HRESULT, + fn AddPronunciationByPhoneIds( + bstrWord: BSTR, + LangId: SpeechLanguageId, + PartOfSpeech: SpeechPartOfSpeech, + PhoneIds: *mut VARIANT, + ) -> HRESULT, + fn RemovePronunciation( + bstrWord: BSTR, + LangId: SpeechLanguageId, + PartOfSpeech: SpeechPartOfSpeech, + bstrPronunciation: BSTR, + ) -> HRESULT, + fn RemovePronunciationByPhoneIds( + bstrWord: BSTR, + LangId: SpeechLanguageId, + PartOfSpeech: SpeechPartOfSpeech, + PhoneIds: *mut VARIANT, + ) -> HRESULT, + fn GetPronunciations( + bstrWord: BSTR, + LangId: SpeechLanguageId, + TypeFlags: SpeechLexiconType, + ppPronunciations: *mut *mut ISpeechLexiconPronunciations, + ) -> HRESULT, + fn GetGenerationChange( + GenerationID: *mut c_long, + ppWords: *mut *mut ISpeechLexiconWords, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8d199862, 0x415e, 0x47d5, 0xac, 0x4f, 0xfa, 0xa6, 0x08, 0xb4, 0x24, 0xe6)] +interface ISpeechLexiconWords(ISpeechLexiconWordsVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Word: *mut *mut ISpeechLexiconWord, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4e5b933c, 0xc9be, 0x48ed, 0x88, 0x42, 0x1e, 0xe5, 0x1b, 0xb1, 0xd4, 0xff)] +interface ISpeechLexiconWord(ISpeechLexiconWordVtbl): IDispatch(IDispatchVtbl) { + fn get_LangId( + LangId: *mut SpeechLanguageId, + ) -> HRESULT, + fn get_Type( + WordType: *mut SpeechWordType, + ) -> HRESULT, + fn get_Word( + Word: *mut BSTR, + ) -> HRESULT, + fn get_Pronunciations( + Pronunciations: *mut *mut ISpeechLexiconPronunciations, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x72829128, 0x5682, 0x4704, 0xa0, 0xd4, 0x3e, 0x2b, 0xb6, 0xf2, 0xea, 0xd3)] +interface ISpeechLexiconPronunciations(ISpeechLexiconPronunciationsVtbl): + IDispatch(IDispatchVtbl) { + fn get_Count( + Count: *mut c_long, + ) -> HRESULT, + fn Item( + Index: c_long, + Pronunciation: *mut *mut ISpeechLexiconPronunciation, + ) -> HRESULT, + fn get__NewEnum( + EnumVARIANT: *mut *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x95252c5d, 0x9e43, 0x4f4a, 0x98, 0x99, 0x48, 0xee, 0x73, 0x35, 0x2f, 0x9f)] +interface ISpeechLexiconPronunciation(ISpeechLexiconPronunciationVtbl): IDispatch(IDispatchVtbl) { + fn get_Type( + LexiconType: *mut SpeechLexiconType, + ) -> HRESULT, + fn get_LangId( + LangId: *mut SpeechLanguageId, + ) -> HRESULT, + fn get_PartOfSpeech( + PartOfSpeech: *mut SpeechPartOfSpeech, + ) -> HRESULT, + fn get_PhoneIds( + PhoneIds: *mut VARIANT, + ) -> HRESULT, + fn get_Symbolic( + Symbolic: *mut BSTR, + ) -> HRESULT, +}} +pub const Speech_Default_Weight: c_float = DEFAULT_WEIGHT; +pub const Speech_Max_Word_Length: LONG = SP_MAX_WORD_LENGTH as i32; +pub const Speech_Max_Pron_Length: LONG = SP_MAX_PRON_LENGTH as i32; +pub const Speech_StreamPos_Asap: LONG = SP_STREAMPOS_ASAP as i32; +pub const Speech_StreamPos_RealTime: LONG = SP_STREAMPOS_REALTIME as i32; +pub const SpeechAllElements: LONG = SPPR_ALL_ELEMENTS as i32; +RIDL!{#[uuid(0x3b151836, 0xdf3a, 0x4e0a, 0x84, 0x6c, 0xd2, 0xad, 0xc9, 0x33, 0x43, 0x33)] +interface ISpeechPhraseInfoBuilder(ISpeechPhraseInfoBuilderVtbl): IDispatch(IDispatchVtbl) { + fn RestorePhraseFromMemory( + PhraseInMemory: *mut VARIANT, + PhraseInfo: *mut *mut ISpeechPhraseInfo, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc3e4f353, 0x433f, 0x43d6, 0x89, 0xa1, 0x6a, 0x62, 0xa7, 0x05, 0x4c, 0x3d)] +interface ISpeechPhoneConverter(ISpeechPhoneConverterVtbl): IDispatch(IDispatchVtbl) { + fn get_LanguageId( + LanguageId: *mut SpeechLanguageId, + ) -> HRESULT, + fn put_LanguageId( + LanguageId: SpeechLanguageId, + ) -> HRESULT, + fn PhoneToId( + Phonemes: BSTR, + IdArray: *mut VARIANT, + ) -> HRESULT, + fn IdToPhone( + IdArray: VARIANT, + Phonemes: *mut BSTR, + ) -> HRESULT, +}} +extern { + pub static CLSID_SpNotifyTranslator: CLSID; + pub static CLSID_SpObjectTokenCategory: CLSID; + pub static CLSID_SpObjectToken: CLSID; + pub static CLSID_SpResourceManager: CLSID; + pub static CLSID_SpStreamFormatConverter: CLSID; + pub static CLSID_SpMMAudioEnum: CLSID; + pub static CLSID_SpMMAudioIn: CLSID; + pub static CLSID_SpMMAudioOut: CLSID; + pub static CLSID_SpStream: CLSID; + pub static CLSID_SpVoice: CLSID; + pub static CLSID_SpSharedRecoContext: CLSID; + pub static CLSID_SpInprocRecognizer: CLSID; + pub static CLSID_SpSharedRecognizer: CLSID; + pub static CLSID_SpLexicon: CLSID; + pub static CLSID_SpUnCompressedLexicon: CLSID; + pub static CLSID_SpCompressedLexicon: CLSID; + pub static CLSID_SpPhoneConverter: CLSID; + pub static CLSID_SpNullPhoneConverter: CLSID; + pub static CLSID_SpTextSelectionInformation: CLSID; + pub static CLSID_SpPhraseInfoBuilder: CLSID; + pub static CLSID_SpAudioFormat: CLSID; + pub static CLSID_SpWaveFormatEx: CLSID; + pub static CLSID_SpInProcRecoContext: CLSID; + pub static CLSID_SpCustomStream: CLSID; + pub static CLSID_SpFileStream: CLSID; + pub static CLSID_SpMemoryStream: CLSID; +} diff --git a/winapi/src/um/sapi53.rs b/winapi/src/um/sapi53.rs new file mode 100644 index 000000000..7121191d8 --- /dev/null +++ b/winapi/src/um/sapi53.rs @@ -0,0 +1,1823 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! SAPI 5.3 definitions +use ctypes::{c_float, c_int, c_long}; +use shared::guiddef::{CLSID, GUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, LPARAM, UINT, ULONG, WORD, WPARAM}; +use shared::wtypes::{BSTR, VARIANT_BOOL}; +use um::oaidl::{IDispatch, IDispatchVtbl, VARIANT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::urlmon::IInternetSecurityManager; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, ULONGLONG, WCHAR}; +pub use um::sapi51::{ + SPDATAKEYLOCATION, + SPDKL_DefaultLocation, + SPDKL_CurrentUser, + SPDKL_LocalMachine, + SPDKL_CurrentConfig, + SPDUI_EngineProperties, + SPDUI_AddRemoveWord, + SPDUI_UserTraining, + SPDUI_MicTraining, + SPDUI_RecoProfileProperties, + SPDUI_AudioProperties, + SPDUI_AudioVolume, + SPDUI_UserEnrollment, + SPDUI_ShareData, + SPDUI_Tutorial, + SPSTREAMFORMAT, + SPSF_Default, + SPSF_NoAssignedFormat, + SPSF_Text, + SPSF_NonStandardFormat, + SPSF_ExtendedAudioFormat, + SPSF_8kHz8BitMono, + SPSF_8kHz8BitStereo, + SPSF_8kHz16BitMono, + SPSF_8kHz16BitStereo, + SPSF_11kHz8BitMono, + SPSF_11kHz8BitStereo, + SPSF_11kHz16BitMono, + SPSF_11kHz16BitStereo, + SPSF_12kHz8BitMono, + SPSF_12kHz8BitStereo, + SPSF_12kHz16BitMono, + SPSF_12kHz16BitStereo, + SPSF_16kHz8BitMono, + SPSF_16kHz8BitStereo, + SPSF_16kHz16BitMono, + SPSF_16kHz16BitStereo, + SPSF_22kHz8BitMono, + SPSF_22kHz8BitStereo, + SPSF_22kHz16BitMono, + SPSF_22kHz16BitStereo, + SPSF_24kHz8BitMono, + SPSF_24kHz8BitStereo, + SPSF_24kHz16BitMono, + SPSF_24kHz16BitStereo, + SPSF_32kHz8BitMono, + SPSF_32kHz8BitStereo, + SPSF_32kHz16BitMono, + SPSF_32kHz16BitStereo, + SPSF_44kHz8BitMono, + SPSF_44kHz8BitStereo, + SPSF_44kHz16BitMono, + SPSF_44kHz16BitStereo, + SPSF_48kHz8BitMono, + SPSF_48kHz8BitStereo, + SPSF_48kHz16BitMono, + SPSF_48kHz16BitStereo, + SPSF_TrueSpeech_8kHz1BitMono, + SPSF_CCITT_ALaw_8kHzMono, + SPSF_CCITT_ALaw_8kHzStereo, + SPSF_CCITT_ALaw_11kHzMono, + SPSF_CCITT_ALaw_11kHzStereo, + SPSF_CCITT_ALaw_22kHzMono, + SPSF_CCITT_ALaw_22kHzStereo, + SPSF_CCITT_ALaw_44kHzMono, + SPSF_CCITT_ALaw_44kHzStereo, + SPSF_CCITT_uLaw_8kHzMono, + SPSF_CCITT_uLaw_8kHzStereo, + SPSF_CCITT_uLaw_11kHzMono, + SPSF_CCITT_uLaw_11kHzStereo, + SPSF_CCITT_uLaw_22kHzMono, + SPSF_CCITT_uLaw_22kHzStereo, + SPSF_CCITT_uLaw_44kHzMono, + SPSF_CCITT_uLaw_44kHzStereo, + SPSF_ADPCM_8kHzMono, + SPSF_ADPCM_8kHzStereo, + SPSF_ADPCM_11kHzMono, + SPSF_ADPCM_11kHzStereo, + SPSF_ADPCM_22kHzMono, + SPSF_ADPCM_22kHzStereo, + SPSF_ADPCM_44kHzMono, + SPSF_ADPCM_44kHzStereo, + SPSF_GSM610_8kHzMono, + SPSF_GSM610_11kHzMono, + SPSF_GSM610_22kHzMono, + SPSF_GSM610_44kHzMono, + SPSF_NUM_FORMATS, + SPDFID_Text, + SPDFID_WaveFormatEx, + SPREG_USER_ROOT, + SPREG_LOCAL_MACHINE_ROOT, + SPCAT_AUDIOOUT, + SPCAT_AUDIOIN, + SPCAT_VOICES, + SPCAT_RECOGNIZERS, + SPCAT_APPLEXICONS, + SPCAT_PHONECONVERTERS, + SPCAT_TEXTNORMALIZERS, + SPCAT_RECOPROFILES, + SPMMSYS_AUDIO_IN_TOKEN_ID, + SPMMSYS_AUDIO_OUT_TOKEN_ID, + SPCURRENT_USER_LEXICON_TOKEN_ID, + SPTOKENVALUE_CLSID, + SPTOKENKEY_FILES, + SPTOKENKEY_UI, + SPTOKENKEY_ATTRIBUTES +}; +pub const SPTOKENKEY_RETAINEDAUDIO: &'static str = "SecondsPerRetainedAudioEvent"; +pub const SPTOKENKEY_AUDIO_LATENCY_WARNING: &'static str = "LatencyWarningThreshold"; +pub const SPTOKENKEY_AUDIO_LATENCY_TRUNCATE: &'static str = "LatencyTruncateThreshold"; +pub const SPTOKENKEY_AUDIO_LATENCY_UPDATE_INTERVAL: &'static str = "LatencyUpdateInterval"; +pub use um::sapi51::{ + SPVOICECATEGORY_TTSRATE, + SPPROP_RESOURCE_USAGE, + SPPROP_HIGH_CONFIDENCE_THRESHOLD, + SPPROP_NORMAL_CONFIDENCE_THRESHOLD, + SPPROP_LOW_CONFIDENCE_THRESHOLD, + SPPROP_RESPONSE_SPEED, + SPPROP_COMPLEX_RESPONSE_SPEED, + SPPROP_ADAPTATION_ON, + SPPROP_PERSISTED_BACKGROUND_ADAPTATION, + SPPROP_PERSISTED_LANGUAGE_MODEL_ADAPTATION, + SPPROP_UX_IS_LISTENING, + SPTOPIC_SPELLING, + SPWILDCARD, + SPDICTATION +}; +pub const SPREG_SAFE_USER_TOKENS: &'static str + = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\UserTokens"; +pub use um::sapi51::{ + SPINFDICTATION, + SP_LOW_CONFIDENCE, + SP_NORMAL_CONFIDENCE, + SP_HIGH_CONFIDENCE, + DEFAULT_WEIGHT, + SP_MAX_WORD_LENGTH, + SP_MAX_PRON_LENGTH +}; +pub const SP_EMULATE_RESULT: ULONG = 0x40000000; +pub use um::sapi51::{ + ISpNotifyCallback, + SPNOTIFYCALLBACK, + ISpNotifySource, ISpNotifySourceVtbl, + ISpNotifySink, ISpNotifySinkVtbl, + ISpNotifyTranslator, ISpNotifyTranslatorVtbl, + ISpDataKey, ISpDataKeyVtbl, + ISpRegDataKey, ISpRegDataKeyVtbl, + ISpObjectTokenCategory, ISpObjectTokenCategoryVtbl, + ISpObjectToken, ISpObjectTokenVtbl, + ISpObjectTokenInit, ISpObjectTokenInitVtbl, + IEnumSpObjectTokens, IEnumSpObjectTokensVtbl, + ISpObjectWithToken, ISpObjectWithTokenVtbl, + ISpResourceManager, ISpResourceManagerVtbl, + SPEVENTLPARAMTYPE, + SPET_LPARAM_IS_UNDEFINED, + SPET_LPARAM_IS_TOKEN, + SPET_LPARAM_IS_OBJECT, + SPET_LPARAM_IS_POINTER, + SPET_LPARAM_IS_STRING, + SPEVENTENUM, + SPEI_UNDEFINED, + SPEI_START_INPUT_STREAM, + SPEI_END_INPUT_STREAM, + SPEI_VOICE_CHANGE, + SPEI_TTS_BOOKMARK, + SPEI_WORD_BOUNDARY, + SPEI_PHONEME, + SPEI_SENTENCE_BOUNDARY, + SPEI_VISEME, + SPEI_TTS_AUDIO_LEVEL, + SPEI_TTS_PRIVATE, + SPEI_MIN_TTS, + SPEI_MAX_TTS, + SPEI_END_SR_STREAM, + SPEI_SOUND_START, + SPEI_SOUND_END, + SPEI_PHRASE_START, + SPEI_RECOGNITION, + SPEI_HYPOTHESIS, + SPEI_SR_BOOKMARK, + SPEI_PROPERTY_NUM_CHANGE, + SPEI_PROPERTY_STRING_CHANGE, + SPEI_FALSE_RECOGNITION, + SPEI_INTERFERENCE, + SPEI_REQUEST_UI, + SPEI_RECO_STATE_CHANGE, + SPEI_ADAPTATION, + SPEI_START_SR_STREAM, + SPEI_RECO_OTHER_CONTEXT, + SPEI_SR_AUDIO_LEVEL +}; +pub const SPEI_SR_RETAINEDAUDIO: SPEVENTENUM = 51; +pub use um::sapi51::SPEI_SR_PRIVATE; +pub const SPEI_RESERVED4: SPEVENTENUM = 53; +pub const SPEI_RESERVED5: SPEVENTENUM = 54; +pub const SPEI_RESERVED6: SPEVENTENUM = 55; +pub use um::sapi51::SPEI_MIN_SR; +pub const SPEI_MAX_SR: SPEVENTENUM = 55; +pub use um::sapi51::{ + SPEI_RESERVED1, + SPEI_RESERVED2, + SPEI_RESERVED3, + SPFEI_FLAGCHECK, + SPFEI_ALL_TTS_EVENTS, + SPFEI_ALL_SR_EVENTS, + SPFEI_ALL_EVENTS, + SPFEI, + SPEVENT, + SPSERIALIZEDEVENT, + SPSERIALIZEDEVENT64 +}; +STRUCT!{struct SPEVENTEX { + eEventId: WORD, + elParamType: WORD, + ulStreamNum: ULONG, + ullAudioStreamOffset: ULONGLONG, + wParam: WPARAM, + lParam: LPARAM, + ullAudioTimeOffset: ULONGLONG, +}} +pub use um::sapi51::{ + SPINTERFERENCE, + SPINTERFERENCE_NONE, + SPINTERFERENCE_NOISE, + SPINTERFERENCE_NOSIGNAL, + SPINTERFERENCE_TOOLOUD, + SPINTERFERENCE_TOOQUIET, + SPINTERFERENCE_TOOFAST, + SPINTERFERENCE_TOOSLOW, + SPINTERFERENCE_LATENCY_WARNING, + SPINTERFERENCE_LATENCY_TRUNCATE_BEGIN, + SPINTERFERENCE_LATENCY_TRUNCATE_END, + SPENDSRSTREAMFLAGS, + SPESF_NONE, + SPESF_STREAM_RELEASED +}; +pub const SPESF_EMULATED: SPENDSRSTREAMFLAGS = 1 << 1; +pub use um::sapi51::{ + SPVFEATURE, + SPVFEATURE_STRESSED, + SPVFEATURE_EMPHASIS, + SPVISEMES, + SP_VISEME_0, + SP_VISEME_1, + SP_VISEME_2, + SP_VISEME_3, + SP_VISEME_4, + SP_VISEME_5, + SP_VISEME_6, + SP_VISEME_7, + SP_VISEME_8, + SP_VISEME_9, + SP_VISEME_10, + SP_VISEME_11, + SP_VISEME_12, + SP_VISEME_13, + SP_VISEME_14, + SP_VISEME_15, + SP_VISEME_16, + SP_VISEME_17, + SP_VISEME_18, + SP_VISEME_19, + SP_VISEME_20, + SP_VISEME_21, + SPEVENTSOURCEINFO, + ISpEventSource, ISpEventSourceVtbl, +}; +RIDL!{#[uuid(0x2373a435, 0x6a4b, 0x429e, 0xa6, 0xac, 0xd4, 0x23, 0x1a, 0x61, 0x97, 0x5b)] +interface ISpEventSource2(ISpEventSource2Vtbl): ISpEventSource(ISpEventSourceVtbl) { + fn GetEventsEx( + ulCount: ULONG, + pEventArray: *mut SPEVENTEX, + pulFetched: *mut ULONG, + ) -> HRESULT, +}} +pub use um::sapi51::{ + ISpEventSink, ISpEventSinkVtbl, + ISpStreamFormat, ISpStreamFormatVtbl, + SPFILEMODE, + SPFM_OPEN_READONLY, + SPFM_OPEN_READWRITE, + SPFM_CREATE, + SPFM_CREATE_ALWAYS, + SPFM_NUM_MODES, + ISpStream, ISpStreamVtbl, + ISpStreamFormatConverter, ISpStreamFormatConverterVtbl, + SPAUDIOSTATE, + SPAS_CLOSED, + SPAS_STOP, + SPAS_PAUSE, + SPAS_RUN, + SPAUDIOSTATUS, + SPAUDIOBUFFERINFO, + ISpAudio, ISpAudioVtbl, + ISpMMSysAudio, ISpMMSysAudioVtbl, + ISpTranscript, ISpTranscriptVtbl, + SPDISPLAYATTRIBUTES, + SPAF_ONE_TRAILING_SPACE, + SPAF_TWO_TRAILING_SPACES, + SPAF_CONSUME_LEADING_SPACES +}; +pub const SPAF_BUFFER_POSITION: SPDISPLAYATTRIBUTES = 0x10; +pub const SPAF_ALL: SPDISPLAYATTRIBUTES = 0x1f; +pub const SPAF_USER_SPECIFIED: SPDISPLAYATTRIBUTES = 0x80; +pub use um::sapi51::{ + SPPHONEID, + PSPPHONEID, + PCSPPHONEID, + SPPHRASEELEMENT, + SPPHRASERULE, + SPPHRASEPROPERTYUNIONTYPE, + SPPPUT_UNUSED, + SPPPUT_ARRAY_INDEX, + SPPHRASEPROPERTY, + SPPHRASEREPLACEMENT +}; +STRUCT!{struct SPSEMANTICERRORINFO { + ulLineNumber: ULONG, + pszScriptLine: LPWSTR, + pszSource: LPWSTR, + pszDescription: LPWSTR, + hrResultCode: HRESULT, +}} +ENUM!{enum SPSEMANTICFORMAT { + SPSMF_SAPI_PROPERTIES = 0, + SPSMF_SRGS_SEMANTICINTERPRETATION_MS = 1, + SPSMF_SRGS_SAPIPROPERTIES = 2, + SPSMF_UPS = 4, + SPSMF_SRGS_SEMANTICINTERPRETATION_W3C = 8, +}} +pub use um::sapi51::SPPHRASE as SPPHRASE_50; +// TODO: pub const SP_SPPHRASESIZE_500: usize = mem::size_of::<SPPHRASE_50>(); +STRUCT!{struct SPPHRASE { + cbSize: ULONG, + LangID: WORD, + wHomophoneGroupId: WORD, + ullGrammarID: ULONGLONG, + ftStartTime: ULONGLONG, + ullAudioStreamPosition: ULONGLONG, + ulAudioSizeBytes: ULONG, + ulRetainedSizeBytes: ULONG, + ulAudioSizeTime: ULONG, + Rule: SPPHRASERULE, + pProperties: *const SPPHRASEPROPERTY, + pElements: *const SPPHRASEELEMENT, + cReplacements: ULONG, + pReplacements: *const SPPHRASEREPLACEMENT, + SREngineID: GUID, + ulSREnginePrivateDataSize: ULONG, + pSREnginePrivateData: *const BYTE, + pSML: LPWSTR, + pSemanticErrorInfo: *mut SPSEMANTICERRORINFO, +}} +pub use um::sapi51::SPSERIALIZEDPHRASE; +STRUCT!{struct SPRULE { + pszRuleName: LPCWSTR, + ulRuleId: ULONG, + dwAttributes: DWORD, +}} +pub use um::sapi51::{ + SPVALUETYPE, + SPDF_PROPERTY, + SPDF_REPLACEMENT, + SPDF_RULE, + SPDF_DISPLAYTEXT, + SPDF_LEXICALFORM , + SPDF_PRONUNCIATION, + SPDF_AUDIO, + SPDF_ALTERNATES, + SPDF_ALL, + SPBINARYGRAMMAR, + SPPHRASERNG, + SPPR_ALL_ELEMENTS, + SP_GETWHOLEPHRASE, + SPRR_ALL_ELEMENTS, + SPSTATEHANDLE, + SPRECOEVENTFLAGS, + SPREF_AutoPause, + SPREF_Emulated +}; +pub const SPREF_SMLTimeout: SPRECOEVENTFLAGS = 1 << 2; +pub const SPREF_ExtendableParse: SPRECOEVENTFLAGS = 1 << 3; +pub const SPREF_ReSent: SPRECOEVENTFLAGS = 1 << 4; +pub const SPREF_Hypothesis: SPRECOEVENTFLAGS = 1 << 5; +pub const SPREF_FalseRecognition: SPRECOEVENTFLAGS = 1 << 6; +pub use um::sapi51::{ + SPPARTOFSPEECH, + SPPS_NotOverriden, + SPPS_Unknown, + SPPS_Noun, + SPPS_Verb, + SPPS_Modifier, + SPPS_Function, + SPPS_Interjection +}; +pub const SPPS_Noncontent: SPPARTOFSPEECH = 0x6000; +pub const SPPS_LMA: SPPARTOFSPEECH = 0x7000; +pub const SPPS_SuppressWord: SPPARTOFSPEECH = 0xf000; +pub use um::sapi51::{ + SPLEXICONTYPE, + eLEXTYPE_USER, + eLEXTYPE_APP, + eLEXTYPE_VENDORLEXICON, + eLEXTYPE_LETTERTOSOUND, + eLEXTYPE_MORPHOLOGY, + eLEXTYPE_RESERVED4, + eLEXTYPE_USER_SHORTCUT, + eLEXTYPE_RESERVED6, + eLEXTYPE_RESERVED7, + eLEXTYPE_RESERVED8, + eLEXTYPE_RESERVED9, + eLEXTYPE_RESERVED10, + eLEXTYPE_PRIVATE1, + eLEXTYPE_PRIVATE2, + eLEXTYPE_PRIVATE3, + eLEXTYPE_PRIVATE4, + eLEXTYPE_PRIVATE5, + eLEXTYPE_PRIVATE6, + eLEXTYPE_PRIVATE7, + eLEXTYPE_PRIVATE8, + eLEXTYPE_PRIVATE9, + eLEXTYPE_PRIVATE10, + eLEXTYPE_PRIVATE11, + eLEXTYPE_PRIVATE12, + eLEXTYPE_PRIVATE13, + eLEXTYPE_PRIVATE14, + eLEXTYPE_PRIVATE15, + eLEXTYPE_PRIVATE16, + eLEXTYPE_PRIVATE17, + eLEXTYPE_PRIVATE18, + eLEXTYPE_PRIVATE19, + eLEXTYPE_PRIVATE20, + SPWORDTYPE, + eWORDTYPE_ADDED, + eWORDTYPE_DELETED +}; +ENUM!{enum SPPRONUNCIATIONFLAGS { + ePRONFLAG_USED = 1 << 0, +}} +pub use um::sapi51::{ + SPWORDPRONUNCIATION, + SPWORDPRONUNCIATIONLIST, + SPWORD, + SPWORDLIST, + ISpLexicon, ISpLexiconVtbl, + ISpContainerLexicon, ISpContainerLexiconVtbl, +}; +ENUM!{enum SPSHORTCUTTYPE { + SPSHT_NotOverriden = -1i32 as u32, + SPSHT_Unknown = 0, + SPSHT_EMAIL = 0x1000, + SPSHT_OTHER = 0x2000, + SPPS_RESERVED1 = 0x3000, + SPPS_RESERVED2 = 0x4000, + SPPS_RESERVED3 = 0x5000, + SPPS_RESERVED4 = 0xf000, +}} +STRUCT!{struct SPSHORTCUTPAIR { + pNextSHORTCUTPAIR: *mut SPSHORTCUTPAIR, + LangID: WORD, + shType: SPSHORTCUTTYPE, + pszDisplay: LPWSTR, + pszSpoken: LPWSTR, +}} +STRUCT!{struct SPSHORTCUTPAIRLIST { + ulSize: ULONG, + pvBuffer: *mut BYTE, + pFirstShortcutPair: *mut SPSHORTCUTPAIR, +}} +RIDL!{#[uuid(0x3df681e2, 0xea56, 0x11d9, 0x8b, 0xde, 0xf6, 0x6b, 0xad, 0x1e, 0x3f, 0x3a)] +interface ISpShortcut(ISpShortcutVtbl): IUnknown(IUnknownVtbl) { + fn AddShortcut( + pszDisplay: LPCWSTR, + LangID: WORD, + pszSpoken: LPCWSTR, + shType: SPSHORTCUTTYPE, + ) -> HRESULT, + fn RemoveShortcut( + pszDisplay: LPCWSTR, + LangID: WORD, + pszSpoken: LPCWSTR, + shType: SPSHORTCUTTYPE, + ) -> HRESULT, + fn GetShortcuts( + LangId: WORD, + pShortcutpairList: *mut SPSHORTCUTPAIRLIST, + ) -> HRESULT, + fn GetGeneration( + pdwGeneration: *mut DWORD, + ) -> HRESULT, + fn GetWordsFromGenerationChange( + pdwGeneration: *mut DWORD, + pWordList: *mut SPWORDLIST, + ) -> HRESULT, + fn GetWords( + pdwGeneration: *mut DWORD, + pdwCookie: *mut DWORD, + pWordList: *mut SPWORDLIST, + ) -> HRESULT, + fn GetShortcutsForGeneration( + pdwGeneration: *mut DWORD, + pdwCookie: *mut DWORD, + pShortcutpairList: *mut SPSHORTCUTPAIRLIST, + ) -> HRESULT, + fn GetGenerationChange( + pdwGeneration: *mut DWORD, + pShortcutpairList: *mut SPSHORTCUTPAIRLIST, + ) -> HRESULT, +}} +pub use um::sapi51::{ISpPhoneConverter, ISpPhoneConverterVtbl}; +RIDL!{#[uuid(0x133adcd4, 0x19b4, 0x4020, 0x9f, 0xdc, 0x84, 0x2e, 0x78, 0x25, 0x3b, 0x17)] +interface ISpPhoneticAlphabetConverter(ISpPhoneticAlphabetConverterVtbl): IUnknown(IUnknownVtbl) { + fn GetLangId( + pLangID: *mut WORD, + ) -> HRESULT, + fn SetLangId( + LangID: WORD, + ) -> HRESULT, + fn SAPI2UPS( + pszSAPIId: *const SPPHONEID, + pszUPSId: *mut SPPHONEID, + cMaxLength: DWORD, + ) -> HRESULT, + fn UPS2SAPI( + pszUPSId: *const SPPHONEID, + pszSAPIId: *mut SPPHONEID, + cMaxLength: DWORD, + ) -> HRESULT, + fn GetMaxConvertLength( + cSrcLength: DWORD, + bSAPI2UPS: BOOL, + pcMaxDestLength: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb2745efd, 0x42ce, 0x48ca, 0x81, 0xf1, 0xa9, 0x6e, 0x02, 0x53, 0x8a, 0x90)] +interface ISpPhoneticAlphabetSelection(ISpPhoneticAlphabetSelectionVtbl): IUnknown(IUnknownVtbl) { + fn IsAlphabetUPS( + pfIsUPS: *mut BOOL, + ) -> HRESULT, + fn SetAlphabetToUPS( + fForceUPS: BOOL, + ) -> HRESULT, +}} +pub use um::sapi51::{ + SPVPITCH, + SPVACTIONS, + SPVA_Speak, + SPVA_Silence, + SPVA_Pronounce, + SPVA_Bookmark, + SPVA_SpellOut, + SPVA_Section, + SPVA_ParseUnknownTag, + SPVCONTEXT, + SPVSTATE, + SPRUNSTATE, + SPRS_DONE, + SPRS_IS_SPEAKING, + SPVLIMITS, + SPMIN_VOLUME, + SPMAX_VOLUME, + SPMIN_RATE, + SPMAX_RATE, + SPVPRIORITY, + SPVPRI_NORMAL, + SPVPRI_ALERT, + SPVPRI_OVER, + SPVOICESTATUS, + SPEAKFLAGS, + SPF_DEFAULT, + SPF_ASYNC, + SPF_PURGEBEFORESPEAK, + SPF_IS_FILENAME, + SPF_IS_XML, + SPF_IS_NOT_XML, + SPF_PERSIST_XML, + SPF_NLP_SPEAK_PUNC, +}; +pub const SPF_PARSE_SAPI: SPEAKFLAGS = 1 << 7; +pub const SPF_PARSE_SSML: SPEAKFLAGS = 1 << 8; +pub const SPF_PARSE_AUTODETECT: SPEAKFLAGS = 0; +pub use um::sapi51::SPF_NLP_MASK; +pub const SPF_PARSE_MASK: SPEAKFLAGS = SPF_PARSE_SAPI | SPF_PARSE_SSML; +pub const SPF_VOICE_MASK: SPEAKFLAGS = ::um::sapi51::SPF_VOICE_MASK | SPF_PARSE_MASK; +pub const SPF_UNUSED_FLAGS: SPEAKFLAGS = !SPF_VOICE_MASK; +pub use um::sapi51::{ + ISpVoice, ISpVoiceVtbl, + ISpPhrase, ISpPhraseVtbl, + ISpPhraseAlt, ISpPhraseAltVtbl, +}; +ENUM!{enum SPXMLRESULTOPTIONS { + SPXRO_SML = 0, + SPXRO_Alternates_SML = 1, +}} +RIDL!{#[uuid(0xf264da52, 0xe457, 0x4696, 0xb8, 0x56, 0xa7, 0x37, 0xb7, 0x17, 0xaf, 0x79)] +interface ISpPhrase2(ISpPhrase2Vtbl): ISpPhrase(ISpPhraseVtbl) { + fn GetXMLResult( + ppszCoMemXMLResult: *mut LPWSTR, + Options: SPXMLRESULTOPTIONS, + ) -> HRESULT, + fn GetXMLErrorInfo( + pSemanticErrorInfo: *mut SPSEMANTICERRORINFO, + ) -> HRESULT, + fn GetAudio( + ulStartElement: ULONG, + cElements: ULONG, + ppStream: *mut *mut ISpStreamFormat, + ) -> HRESULT, +}} +pub use um::sapi51::{ + SPRECORESULTTIMES, + SPSERIALIZEDRESULT, + ISpRecoResult, ISpRecoResultVtbl, +}; +ENUM!{enum SPCOMMITFLAGS { + SPCF_NONE = 0, + SPCF_ADD_TO_USER_LEXICON = 1 << 0, + SPCF_DEFINITE_CORRECTION = 1 << 1, +}} +RIDL!{#[uuid(0x27cac6c4, 0x88f2, 0x41f2, 0x88, 0x17, 0x0c, 0x95, 0xe5, 0x9f, 0x1e, 0x6e)] +interface ISpRecoResult2(ISpRecoResult2Vtbl): ISpRecoResult(ISpRecoResultVtbl) { + fn CommitAlternate( + pPhraseAlt: *mut ISpPhraseAlt, + ppNewResult: *mut *mut ISpRecoResult, + ) -> HRESULT, + fn CommitText( + ulStartElement: ULONG, + cElements: ULONG, + pszCorrectedData: LPCWSTR, + eCommitFlags: DWORD, + ) -> HRESULT, + fn SetTextFeedback( + pszFeedback: LPCWSTR, + fSuccessful: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xae39362b, 0x45a8, 0x4074, 0x9b, 0x9e, 0xcc, 0xf4, 0x9a, 0xa2, 0xd0, 0xb6)] +interface ISpXMLRecoResult(ISpXMLRecoResultVtbl): ISpRecoResult(ISpRecoResultVtbl) { + fn GetXMLResult( + ppszCoMemXMLResult: *mut LPWSTR, + Options: SPXMLRESULTOPTIONS, + ) -> HRESULT, + fn GetXMLErrorInfo( + pSemanticErrorInfo: *mut SPSEMANTICERRORINFO, + ) -> HRESULT, +}} +pub use um::sapi51::{ + SPTEXTSELECTIONINFO, + SPWORDPRONOUNCEABLE, + SPWP_UNKNOWN_WORD_UNPRONOUNCEABLE, + SPWP_UNKNOWN_WORD_PRONOUNCEABLE, + SPWP_KNOWN_WORD_PRONOUNCEABLE, + SPGRAMMARSTATE, + SPGS_DISABLED, + SPGS_ENABLED, + SPGS_EXCLUSIVE, + SPCONTEXTSTATE, + SPCS_DISABLED, + SPCS_ENABLED, + SPRULESTATE, + SPRS_INACTIVE, + SPRS_ACTIVE, + SPRS_ACTIVE_WITH_AUTO_PAUSE, +}; +pub const SPRS_ACTIVE_USER_DELIMITED: SPRULESTATE = 4; +pub use um::sapi51::{ + SP_STREAMPOS_ASAP, + SP_STREAMPOS_REALTIME, + SPRULETRANS_TEXTBUFFER, + SPRULETRANS_WILDCARD, + SPRULETRANS_DICTATION, + SPGRAMMARWORDTYPE, + SPWT_DISPLAY, + SPWT_LEXICAL, + SPWT_PRONUNCIATION, +}; +pub const SPWT_LEXICAL_NO_SPECIAL_CHARS: SPGRAMMARWORDTYPE = SPWT_PRONUNCIATION + 1; +pub use um::sapi51::{ + SPPROPERTYINFO, + SPCFGRULEATTRIBUTES, + SPRAF_TopLevel, + SPRAF_Active, + SPRAF_Export, + SPRAF_Import, + SPRAF_Interpreter, + SPRAF_Dynamic, +}; +pub const SPRAF_Root: SPCFGRULEATTRIBUTES = 1 << 6; +pub use um::sapi51::SPRAF_AutoPause; +pub const SPRAF_UserDelimited: SPCFGRULEATTRIBUTES = 1 << 17; +pub use um::sapi51::{ + ISpGrammarBuilder, ISpGrammarBuilderVtbl, + SPLOADOPTIONS, + SPLO_STATIC, + SPLO_DYNAMIC, + ISpRecoGrammar, ISpRecoGrammarVtbl, +}; +ENUM!{enum SPMATCHINGMODE { + AllWords = 0, + Subsequence = 1, + OrderedSubset = 3, + SubsequenceContentRequired = 5, + OrderedSubsetContentRequired = 7, +}} +ENUM!{enum PHONETICALPHABET { + PA_Ipa = 0, + PA_Ups = 1, + PA_Sapi = 2, +}} +RIDL!{#[uuid(0x8ab10026, 0x20cc, 0x4b20, 0x8c, 0x22, 0xa4, 0x9c, 0x9b, 0xa7, 0x8f, 0x60)] +interface ISpGrammarBuilder2(ISpGrammarBuilder2Vtbl): IUnknown(IUnknownVtbl) { + fn AddTextSubset( + hFromState: SPSTATEHANDLE, + hToState: SPSTATEHANDLE, + psz: LPCWSTR, + eMatchMode: SPMATCHINGMODE, + ) -> HRESULT, + fn SetPhoneticAlphabet( + phoneticALphabet: PHONETICALPHABET, + ) -> HRESULT, +}} +pub const SPRP_NORMAL: i32 = 0; // TODO: Unknown purpose and type +RIDL!{#[uuid(0x4b37bc9e, 0x9ed6, 0x44a3, 0x93, 0xd3, 0x18, 0xf0, 0x22, 0xb7, 0x9e, 0xc3)] +interface ISpRecoGrammar2(ISpRecoGrammar2Vtbl): IUnknown(IUnknownVtbl) { + fn GetRules( + ppCoMemRules: *mut *mut SPRULE, + puNumRules: *mut UINT, + ) -> HRESULT, + fn LoadCmdFromFile2( + pszFileName: LPCWSTR, + Options: SPLOADOPTIONS, + pszSharingUri: LPCWSTR, + pszBaseUri: LPCWSTR, + ) -> HRESULT, + fn LoadCmdFromMemory2( + pGrammar: *const SPBINARYGRAMMAR, + Options: SPLOADOPTIONS, + pszSharingUri: LPCWSTR, + pszBaseUri: LPCWSTR, + ) -> HRESULT, + fn SetRulePriority( + pszRuleName: LPCWSTR, + ulRuleId: ULONG, + nRulePriority: c_int, + ) -> HRESULT, + fn SetRuleWeight( + pszRuleName: LPCWSTR, + ulRuleId: ULONG, + flWeight: c_float, + ) -> HRESULT, + fn SetDictationWeight( + flWeight: c_float, + ) -> HRESULT, + fn SetGrammarLoader( + pLoader: *mut ISpeechResourceLoader, + ) -> HRESULT, + fn SetSMLSecurityManager( + pSMLSecurityManager: *mut IInternetSecurityManager, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb9ac5783, 0xfcd0, 0x4b21, 0xb1, 0x19, 0xb4, 0xf8, 0xda, 0x8f, 0xd2, 0xc3)] +interface ISpeechResourceLoader(ISpeechResourceLoaderVtbl): IDispatch(IDispatchVtbl) { + fn LoadResource( + bstrResourceUri: BSTR, + fAlwaysReload: VARIANT_BOOL, + pStream: *mut *mut IUnknown, + pbstrMIMEType: *mut BSTR, + pfModified: *mut VARIANT_BOOL, + pbstrRedirectUrl: *mut BSTR, + ) -> HRESULT, + fn GetLocalCopy( + bstrResourceUri: BSTR, + pbstrLocalPath: *mut BSTR, + pbstrMIMEType: *mut BSTR, + pbstrRedirectUrl: *mut BSTR, + ) -> HRESULT, + fn ReleaseLocalCopy( + pbstrLocalPath: BSTR, + ) -> HRESULT, +}} +pub use um::sapi51::{ + SPRECOCONTEXTSTATUS, + SPBOOKMARKOPTIONS, + SPBO_NONE, + SPBO_PAUSE, +}; +pub const SPBO_AHEAD: SPBOOKMARKOPTIONS = 1 << 1; +pub const SPBO_TIME_UNITS: SPBOOKMARKOPTIONS = 1 << 2; +pub use um::sapi51::{ + SPAUDIOOPTIONS, + SPAO_NONE, + SPAO_RETAIN_AUDIO, + ISpRecoContext, ISpRecoContextVtbl, +}; +ENUM!{enum SPGRAMMAROPTIONS { + SPGO_SAPI = 0x1, + SPGO_SRGS = 0x2, + SPGO_UPS = 0x4, + SPGO_SRGS_MS_SCRIPT = 0x8, + SPGO_SRGS_W3C_SCRIPT = 0x100, + SPGO_SRGS_STG_SCRIPT = 0x200, + SPGO_SRGS_SCRIPT = SPGO_SRGS | SPGO_SRGS_MS_SCRIPT + | SPGO_SRGS_W3C_SCRIPT | SPGO_SRGS_STG_SCRIPT, + SPGO_FILE = 0x10, + SPGO_HTTP = 0x20, + SPGO_RES = 0x40, + SPGO_OBJECT = 0x80, + SPGO_DEFAULT = 0x3fb, + SPGO_ALL = 0x3ff, +}} +ENUM!{enum SPADAPTATIONSETTINGS { + SPADS_Default = 0, + SPADS_CurrentRecognizer = 0x1, + SPADS_RecoProfile = 0x2, + SPADS_Immediate = 0x4, + SPADS_Reset = 0x8, + SPADS_HighVolumeDataSource = 0x10, +}} +ENUM!{enum SPADAPTATIONRELEVANCE { + SPAR_Unknown = 0, + SPAR_Low = 1, + SPAR_Medium = 2, + SPAR_High = 3, +}} +RIDL!{#[uuid(0xbead311c, 0x52ff, 0x437f, 0x94, 0x64, 0x6b, 0x21, 0x05, 0x4c, 0xa7, 0x3d)] +interface ISpRecoContext2(ISpRecoContext2Vtbl): IUnknown(IUnknownVtbl) { + fn SetGrammarOptions( + eGrammarOptions: DWORD, + ) -> HRESULT, + fn GetGrammarOptions( + peGrammarOptions: *mut DWORD, + ) -> HRESULT, + fn SetAdaptationData2( + pAdaptationData: LPCWSTR, + cch: ULONG, + pTopicName: LPCWSTR, + eAdaptationSettings: DWORD, + eRelevance: SPADAPTATIONRELEVANCE, + ) -> HRESULT, +}} +pub use um::sapi51::{ + ISpProperties, ISpPropertiesVtbl, + SP_MAX_LANGIDS, + SPRECOGNIZERSTATUS, + SPWAVEFORMATTYPE, + SPWF_INPUT, + SPWF_SRENGINE, + SPSTREAMFORMATTYPE, + SPRECOSTATE, + SPRST_INACTIVE, + SPRST_ACTIVE, + SPRST_ACTIVE_ALWAYS, + SPRST_INACTIVE_WITH_PURGE, + SPRST_NUM_STATES, + ISpRecognizer, ISpRecognizerVtbl, +}; +RIDL!{#[uuid(0x21b501a0, 0x0ec7, 0x46c9, 0x92, 0xc3, 0xa2, 0xbc, 0x78, 0x4c, 0x54, 0xb9)] +interface ISpSerializeState(ISpSerializeStateVtbl): IUnknown(IUnknownVtbl) { + fn GetSerializedState( + ppbData: *mut *mut BYTE, + pulSize: *mut ULONG, + dwReserved: DWORD, + ) -> HRESULT, + fn SetSerializedState( + pbData: *mut BYTE, + ulSize: ULONG, + dwReserved: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8fc6d974, 0xc81e, 0x4098, 0x93, 0xc5, 0x01, 0x47, 0xf6, 0x1e, 0xd4, 0xd3)] +interface ISpRecognizer2(ISpRecognizer2Vtbl): IUnknown(IUnknownVtbl) { + fn EmulateRecognitionEx( + pPhrase: *mut ISpPhrase, + dwCompareFlags: DWORD, + ) -> HRESULT, + fn SetTrainingState( + fDoingTraining: BOOL, + fAdaptFromTrainingData: BOOL, + ) -> HRESULT, + fn ResetAcousticModelAdaptation() -> HRESULT, +}} +STRUCT!{struct SPNORMALIZATIONLIST { + ulSize: ULONG, + ppszzNormalizedList: *mut *mut WCHAR, +}} +RIDL!{#[uuid(0xc360ce4b, 0x76d1, 0x4214, 0xad, 0x68, 0x52, 0x65, 0x7d, 0x50, 0x83, 0xda)] +interface ISpEnginePronunciation(ISpEnginePronunciationVtbl): IUnknown(IUnknownVtbl) { + fn Normalize( + pszWord: LPCWSTR, + pszLeftContext: LPCWSTR, + pszRightContext: LPCWSTR, + LangID: WORD, + pNormalizationList: *mut SPNORMALIZATIONLIST, + ) -> HRESULT, + fn GetPronunciations( + pszWord: LPCWSTR, + pszLeftContext: LPCWSTR, + pszRightContext: LPCWSTR, + LangID: WORD, + pEnginePronunciationList: *mut SPWORDPRONUNCIATIONLIST, + ) -> HRESULT, +}} +STRUCT!{struct SPDISPLAYTOKEN { + pszLexical: *const WCHAR, + pszDisplay: *const WCHAR, + bDisplayAttributes: BYTE, +}} +STRUCT!{struct SPDISPLAYPHRASE { + ulNumTokens: ULONG, + pTokens: *mut SPDISPLAYTOKEN, +}} +RIDL!{#[uuid(0xc8d7c7e2, 0x0dde, 0x44b7, 0xaf, 0xe3, 0xb0, 0xc9, 0x91, 0xfb, 0xeb, 0x5e)] +interface ISpDisplayAlternates(ISpDisplayAlternatesVtbl): IUnknown(IUnknownVtbl) { + fn GetDisplayAlternates( + pPhrase: *const SPDISPLAYPHRASE, + cRequestCount: ULONG, + ppCoMemPhrases: *mut *mut SPDISPLAYPHRASE, + pcPhrasesReturned: *mut ULONG, + ) -> HRESULT, + fn SetFullStopTrailSpace( + ulTrailSpace: ULONG, + ) -> HRESULT, +}} +pub use um::sapi51::{ + SpeechLanguageId, + DISPID_SpeechDataKey, + DISPID_SDKSetBinaryValue, + DISPID_SDKGetBinaryValue, + DISPID_SDKSetStringValue, + DISPID_SDKGetStringValue, + DISPID_SDKSetLongValue, + DISPID_SDKGetlongValue, + DISPID_SDKOpenKey, + DISPID_SDKCreateKey, + DISPID_SDKDeleteKey, + DISPID_SDKDeleteValue, + DISPID_SDKEnumKeys, + DISPID_SDKEnumValues, + DISPID_SpeechObjectToken, + DISPID_SOTId, + DISPID_SOTDataKey, + DISPID_SOTCategory, + DISPID_SOTGetDescription, + DISPID_SOTSetId, + DISPID_SOTGetAttribute, + DISPID_SOTCreateInstance, + DISPID_SOTRemove, + DISPID_SOTGetStorageFileName, + DISPID_SOTRemoveStorageFileName, + DISPID_SOTIsUISupported, + DISPID_SOTDisplayUI, + DISPID_SOTMatchesAttributes, + SpeechDataKeyLocation, + SDKLDefaultLocation, + SDKLCurrentUser, + SDKLLocalMachine, + SDKLCurrentConfig, + SpeechTokenContext, + STCInprocServer, + STCInprocHandler , + STCLocalServer, + STCRemoteServer, + STCAll, + SpeechTokenShellFolder, + STSF_AppData, + STSF_LocalAppData, + STSF_CommonAppData, + STSF_FlagCreate, + DISPID_SpeechObjectTokens, + DISPID_SOTsCount, + DISPID_SOTsItem, + DISPID_SOTs_NewEnum, + DISPID_SpeechObjectTokenCategory, + DISPID_SOTCId, + DISPID_SOTCDefault, + DISPID_SOTCSetId, + DISPID_SOTCGetDataKey, + DISPID_SOTCEnumerateTokens, + SpeechAudioFormatType, + SAFTDefault, + SAFTNoAssignedFormat, + SAFTText, + SAFTNonStandardFormat, + SAFTExtendedAudioFormat, + SAFT8kHz8BitMono, + SAFT8kHz8BitStereo, + SAFT8kHz16BitMono, + SAFT8kHz16BitStereo, + SAFT11kHz8BitMono, + SAFT11kHz8BitStereo, + SAFT11kHz16BitMono, + SAFT11kHz16BitStereo, + SAFT12kHz8BitMono, + SAFT12kHz8BitStereo, + SAFT12kHz16BitMono, + SAFT12kHz16BitStereo, + SAFT16kHz8BitMono, + SAFT16kHz8BitStereo, + SAFT16kHz16BitMono, + SAFT16kHz16BitStereo, + SAFT22kHz8BitMono, + SAFT22kHz8BitStereo, + SAFT22kHz16BitMono, + SAFT22kHz16BitStereo, + SAFT24kHz8BitMono, + SAFT24kHz8BitStereo, + SAFT24kHz16BitMono, + SAFT24kHz16BitStereo, + SAFT32kHz8BitMono, + SAFT32kHz8BitStereo, + SAFT32kHz16BitMono, + SAFT32kHz16BitStereo, + SAFT44kHz8BitMono, + SAFT44kHz8BitStereo, + SAFT44kHz16BitMono, + SAFT44kHz16BitStereo, + SAFT48kHz8BitMono, + SAFT48kHz8BitStereo, + SAFT48kHz16BitMono, + SAFT48kHz16BitStereo, + SAFTTrueSpeech_8kHz1BitMono, + SAFTCCITT_ALaw_8kHzMono, + SAFTCCITT_ALaw_8kHzStereo, + SAFTCCITT_ALaw_11kHzMono, + SAFTCCITT_ALaw_11kHzStereo, + SAFTCCITT_ALaw_22kHzMono, + SAFTCCITT_ALaw_22kHzStereo, + SAFTCCITT_ALaw_44kHzMono, + SAFTCCITT_ALaw_44kHzStereo, + SAFTCCITT_uLaw_8kHzMono, + SAFTCCITT_uLaw_8kHzStereo, + SAFTCCITT_uLaw_11kHzMono, + SAFTCCITT_uLaw_11kHzStereo, + SAFTCCITT_uLaw_22kHzMono, + SAFTCCITT_uLaw_22kHzStereo, + SAFTCCITT_uLaw_44kHzMono, + SAFTCCITT_uLaw_44kHzStereo, + SAFTADPCM_8kHzMono, + SAFTADPCM_8kHzStereo, + SAFTADPCM_11kHzMono, + SAFTADPCM_11kHzStereo, + SAFTADPCM_22kHzMono, + SAFTADPCM_22kHzStereo, + SAFTADPCM_44kHzMono, + SAFTADPCM_44kHzStereo, + SAFTGSM610_8kHzMono, + SAFTGSM610_11kHzMono, + SAFTGSM610_22kHzMono, + SAFTGSM610_44kHzMono, + DISPID_SpeechAudioFormat, + DISPID_SAFType, + DISPID_SAFGuid, + DISPID_SAFGetWaveFormatEx, + DISPID_SAFSetWaveFormatEx, + DISPID_SpeechBaseStream, + DISPID_SBSFormat, + DISPID_SBSRead, + DISPID_SBSWrite, + DISPID_SBSSeek, + SpeechStreamSeekPositionType, + SSSPTRelativeToStart, + SSSPTRelativeToCurrentPosition, + SSSPTRelativeToEnd, + DISPID_SpeechAudio, + DISPID_SAStatus, + DISPID_SABufferInfo, + DISPID_SADefaultFormat, + DISPID_SAVolume, + DISPID_SABufferNotifySize, + DISPID_SAEventHandle, + DISPID_SASetState, + SpeechAudioState, + SASClosed, + SASStop, + SASPause, + SASRun, + DISPID_SpeechMMSysAudio, + DISPID_SMSADeviceId, + DISPID_SMSALineId, + DISPID_SMSAMMHandle, + DISPID_SpeechFileStream, + DISPID_SFSOpen, + DISPID_SFSClose, + SpeechStreamFileMode, + SSFMOpenForRead, + SSFMOpenReadWrite, + SSFMCreate, + SSFMCreateForWrite, + DISPID_SpeechCustomStream, + DISPID_SCSBaseStream, + DISPID_SpeechMemoryStream, + DISPID_SMSSetData, + DISPID_SMSGetData, + DISPID_SpeechAudioStatus, + DISPID_SASFreeBufferSpace, + DISPID_SASNonBlockingIO, + DISPID_SASState, + DISPID_SASCurrentSeekPosition, + DISPID_SASCurrentDevicePosition, + DISPID_SpeechAudioBufferInfo, + DISPID_SABIMinNotification, + DISPID_SABIBufferSize, + DISPID_SABIEventBias, + DISPID_SpeechWaveFormatEx, + DISPID_SWFEFormatTag, + DISPID_SWFEChannels, + DISPID_SWFESamplesPerSec, + DISPID_SWFEAvgBytesPerSec, + DISPID_SWFEBlockAlign, + DISPID_SWFEBitsPerSample, + DISPID_SWFEExtraData, + DISPID_SpeechVoice, + DISPID_SVStatus, + DISPID_SVVoice, + DISPID_SVAudioOutput, + DISPID_SVAudioOutputStream, + DISPID_SVRate, + DISPID_SVVolume, + DISPID_SVAllowAudioOuputFormatChangesOnNextSet, + DISPID_SVEventInterests, + DISPID_SVPriority, + DISPID_SVAlertBoundary, + DISPID_SVSyncronousSpeakTimeout, + DISPID_SVSpeak, + DISPID_SVSpeakStream, + DISPID_SVPause, + DISPID_SVResume, + DISPID_SVSkip, + DISPID_SVGetVoices, + DISPID_SVGetAudioOutputs, + DISPID_SVWaitUntilDone, + DISPID_SVSpeakCompleteEvent, + DISPID_SVIsUISupported, + DISPID_SVDisplayUI, + SpeechVoicePriority, + SVPNormal, + SVPAlert, + SVPOver, + SpeechVoiceSpeakFlags, + SVSFDefault, + SVSFlagsAsync, + SVSFPurgeBeforeSpeak, + SVSFIsFilename, + SVSFIsXML, + SVSFIsNotXML, + SVSFPersistXML, + SVSFNLPSpeakPunc, +}; +pub const SVSFParseSapi: SpeechVoiceSpeakFlags = SPF_PARSE_SAPI; +pub const SVSFParseSsml: SpeechVoiceSpeakFlags = SPF_PARSE_SSML; +pub const SVSFParseAutodetect: SpeechVoiceSpeakFlags = SPF_PARSE_AUTODETECT; +pub use um::sapi51::SVSFNLPMask; +pub const SVSFParseMask: SpeechVoiceSpeakFlags = SPF_PARSE_MASK as u32; +pub use um::sapi51::{ + SVSFVoiceMask, + SVSFUnusedFlags, + SpeechVoiceEvents, + SVEStartInputStream, + SVEEndInputStream, + SVEVoiceChange, + SVEBookmark, + SVEWordBoundary, + SVEPhoneme, + SVESentenceBoundary, + SVEViseme, + SVEAudioLevel, + SVEPrivate, + SVEAllEvents, + DISPID_SpeechVoiceStatus, + DISPID_SVSCurrentStreamNumber, + DISPID_SVSLastStreamNumberQueued, + DISPID_SVSLastResult, + DISPID_SVSRunningState, + DISPID_SVSInputWordPosition, + DISPID_SVSInputWordLength, + DISPID_SVSInputSentencePosition, + DISPID_SVSInputSentenceLength, + DISPID_SVSLastBookmark, + DISPID_SVSLastBookmarkId, + DISPID_SVSPhonemeId, + DISPID_SVSVisemeId, + SpeechRunState, + SRSEDone, + SRSEIsSpeaking, + SpeechVisemeType, + SVP_0, + SVP_1, + SVP_2, + SVP_3, + SVP_4, + SVP_5, + SVP_6, + SVP_7, + SVP_8, + SVP_9, + SVP_10, + SVP_11, + SVP_12, + SVP_13, + SVP_14, + SVP_15, + SVP_16, + SVP_17, + SVP_18, + SVP_19, + SVP_20, + SVP_21, + SpeechVisemeFeature, + SVF_None, + SVF_Stressed, + SVF_Emphasis, + DISPID_SpeechVoiceEvent, + DISPID_SVEStreamStart, + DISPID_SVEStreamEnd, + DISPID_SVEVoiceChange, + DISPID_SVEBookmark, + DISPID_SVEWord, + DISPID_SVEPhoneme, + DISPID_SVESentenceBoundary, + DISPID_SVEViseme, + DISPID_SVEAudioLevel, + DISPID_SVEEnginePrivate, + DISPID_SpeechRecognizer, + DISPID_SRRecognizer, + DISPID_SRAllowAudioInputFormatChangesOnNextSet, + DISPID_SRAudioInput, + DISPID_SRAudioInputStream, + DISPID_SRIsShared, + DISPID_SRState, + DISPID_SRStatus, + DISPID_SRProfile, + DISPID_SREmulateRecognition, + DISPID_SRCreateRecoContext, + DISPID_SRGetFormat, + DISPID_SRSetPropertyNumber, + DISPID_SRGetPropertyNumber, + DISPID_SRSetPropertyString, + DISPID_SRGetPropertyString, + DISPID_SRIsUISupported, + DISPID_SRDisplayUI, + DISPID_SRGetRecognizers, + DISPID_SVGetAudioInputs, + DISPID_SVGetProfiles, + SpeechRecognizerState, + SRSInactive, + SRSActive, + SRSActiveAlways, + SRSInactiveWithPurge, + SpeechDisplayAttributes, + SDA_No_Trailing_Space, + SDA_One_Trailing_Space, + SDA_Two_Trailing_Spaces, + SDA_Consume_Leading_Spaces, + SpeechFormatType, + SFTInput, + SFTSREngine, +}; +ENUM!{enum SpeechEmulationCompareFlags { + SECFIgnoreCase = 0x1, + SECFIgnoreKanaType = 0x10000, + SECFIgnoreWidth = 0x20000, + SECFNoSpecialChars = 0x20000000, + SECFEmulateResult = 0x40000000, + SECFDefault = SECFIgnoreCase | SECFIgnoreKanaType | SECFIgnoreWidth, +}} +pub use um::sapi51::{ + DISPID_SpeechRecognizerStatus, + DISPID_SRSAudioStatus, + DISPID_SRSCurrentStreamPosition, + DISPID_SRSCurrentStreamNumber, + DISPID_SRSNumberOfActiveRules, + DISPID_SRSClsidEngine, + DISPID_SRSSupportedLanguages, + DISPID_SpeechRecoContext, + DISPID_SRCRecognizer, + DISPID_SRCAudioInInterferenceStatus, + DISPID_SRCRequestedUIType, + DISPID_SRCVoice, + DISPID_SRAllowVoiceFormatMatchingOnNextSet, + DISPID_SRCVoicePurgeEvent, + DISPID_SRCEventInterests, + DISPID_SRCCmdMaxAlternates, + DISPID_SRCState, + DISPID_SRCRetainedAudio, + DISPID_SRCRetainedAudioFormat, + DISPID_SRCPause, + DISPID_SRCResume, + DISPID_SRCCreateGrammar, + DISPID_SRCCreateResultFromMemory, + DISPID_SRCBookmark, + DISPID_SRCSetAdaptationData, + SpeechRetainedAudioOptions, + SRAONone, + SRAORetainAudio, + SpeechBookmarkOptions, + SBONone, + SBOPause, + SpeechInterference, + SINone, + SINoise, + SINoSignal, + SITooLoud, + SITooQuiet, + SITooFast, + SITooSlow, + SpeechRecoEvents, + SREStreamEnd, + SRESoundStart, + SRESoundEnd, + SREPhraseStart, + SRERecognition, + SREHypothesis, + SREBookmark, + SREPropertyNumChange, + SREPropertyStringChange, + SREFalseRecognition, + SREInterference, + SRERequestUI, + SREStateChange, + SREAdaptation, + SREStreamStart, + SRERecoOtherContext, + SREAudioLevel, + SREPrivate, + SREAllEvents, + SpeechRecoContextState, + SRCS_Disabled, + SRCS_Enabled, + DISPIDSPRG, + DISPID_SRGId, + DISPID_SRGRecoContext, + DISPID_SRGState, + DISPID_SRGRules, + DISPID_SRGReset, + DISPID_SRGCommit, + DISPID_SRGCmdLoadFromFile, + DISPID_SRGCmdLoadFromObject, + DISPID_SRGCmdLoadFromResource, + DISPID_SRGCmdLoadFromMemory, + DISPID_SRGCmdLoadFromProprietaryGrammar, + DISPID_SRGCmdSetRuleState, + DISPID_SRGCmdSetRuleIdState, + DISPID_SRGDictationLoad, + DISPID_SRGDictationUnload, + DISPID_SRGDictationSetState, + DISPID_SRGSetWordSequenceData, + DISPID_SRGSetTextSelection, + DISPID_SRGIsPronounceable, + SpeechLoadOption, + SLOStatic, + SLODynamic, + SpeechWordPronounceable, + SWPUnknownWordUnpronounceable, + SWPUnknownWordPronounceable, + SWPKnownWordPronounceable, + SpeechGrammarState, + SGSEnabled, + SGSDisabled, + SGSExclusive, + SpeechRuleState, + SGDSInactive, + SGDSActive, + SGDSActiveWithAutoPause, +}; +pub const SGDSActiveUserDelimited: SpeechRuleState = SPRS_ACTIVE_USER_DELIMITED; +pub use um::sapi51::{ + SpeechRuleAttributes, + SRATopLevel, + SRADefaultToActive, + SRAExport, + SRAImport, + SRAInterpreter, + SRADynamic, +}; +pub const SRARoot: SpeechRuleAttributes = SPRAF_Root; +pub use um::sapi51::{ + SpeechGrammarWordType, + SGDisplay, + SGLexical, + SGPronounciation, +}; +pub const SGLexicalNoSpecialChars: SpeechGrammarWordType = SPWT_LEXICAL_NO_SPECIAL_CHARS; +pub use um::sapi51::{ + DISPID_SpeechRecoContextEvents, + DISPID_SRCEStartStream, + DISPID_SRCEEndStream, + DISPID_SRCEBookmark, + DISPID_SRCESoundStart, + DISPID_SRCESoundEnd, + DISPID_SRCEPhraseStart, + DISPID_SRCERecognition, + DISPID_SRCEHypothesis, + DISPID_SRCEPropertyNumberChange, + DISPID_SRCEPropertyStringChange, + DISPID_SRCEFalseRecognition, + DISPID_SRCEInterference, + DISPID_SRCERequestUI, + DISPID_SRCERecognizerStateChange, + DISPID_SRCEAdaptation, + DISPID_SRCERecognitionForOtherContext, + DISPID_SRCEAudioLevel, + DISPID_SRCEEnginePrivate, + SpeechRecognitionType, + SRTStandard, + SRTAutopause, + SRTEmulated, +}; +pub const SRTSMLTimeout: SpeechRecognitionType = SPREF_SMLTimeout; +pub const SRTExtendableParse: SpeechRecognitionType = SPREF_ExtendableParse; +pub const SRTReSent: SpeechRecognitionType = SPREF_ReSent; +pub use um::sapi51::{ + DISPID_SpeechGrammarRule, + DISPID_SGRAttributes, + DISPID_SGRInitialState, + DISPID_SGRName, + DISPID_SGRId, + DISPID_SGRClear, + DISPID_SGRAddResource, + DISPID_SGRAddState, + DISPID_SpeechGrammarRules, + DISPID_SGRsCount, + DISPID_SGRsDynamic, + DISPID_SGRsAdd, + DISPID_SGRsCommit, + DISPID_SGRsCommitAndSave, + DISPID_SGRsFindRule, + DISPID_SGRsItem, + DISPID_SGRs_NewEnum, + DISPID_SpeechGrammarRuleState, + DISPID_SGRSRule, + DISPID_SGRSTransitions, + DISPID_SGRSAddWordTransition, + DISPID_SGRSAddRuleTransition, + DISPID_SGRSAddSpecialTransition, + SpeechSpecialTransitionType, + SSTTWildcard, + SSTTDictation, + SSTTTextBuffer, + DISPID_SpeechGrammarRuleStateTransitions, + DISPID_SGRSTsCount, + DISPID_SGRSTsItem, + DISPID_SGRSTs_NewEnum, + DISPID_SpeechGrammarRuleStateTransition, + DISPID_SGRSTType, + DISPID_SGRSTText, + DISPID_SGRSTRule, + DISPID_SGRSTWeight, + DISPID_SGRSTPropertyName, + DISPID_SGRSTPropertyId, + DISPID_SGRSTPropertyValue, + DISPID_SGRSTNextState, + SpeechGrammarRuleStateTransitionType, + SGRSTTEpsilon, + SGRSTTWord, + SGRSTTRule, + SGRSTTDictation, + SGRSTTWildcard, + SGRSTTTextBuffer, + DISPIDSPTSI, + DISPIDSPTSI_ActiveOffset, + DISPIDSPTSI_ActiveLength, + DISPIDSPTSI_SelectionOffset, + DISPIDSPTSI_SelectionLength, + DISPID_SpeechRecoResult, + DISPID_SRRRecoContext, + DISPID_SRRTimes, + DISPID_SRRAudioFormat, + DISPID_SRRPhraseInfo, + DISPID_SRRAlternates, + DISPID_SRRAudio, + DISPID_SRRSpeakAudio, + DISPID_SRRSaveToMemory, + DISPID_SRRDiscardResultInfo, + SpeechDiscardType, + SDTProperty, + SDTReplacement, + SDTRule, + SDTDisplayText, + SDTLexicalForm, + SDTPronunciation, + SDTAudio, + SDTAlternates, + SDTAll, +}; +ENUM!{enum DISPID_SpeechXMLRecoResult { + DISPID_SRRGetXMLResult, + DISPID_SRRGetXMLErrorInfo, +}} +ENUM!{enum DISPID_SpeechRecoResult2 { + DISPID_SRRSetTextFeedback, +}} +pub use um::sapi51::{ + DISPID_SpeechPhraseBuilder, + DISPID_SPPBRestorePhraseFromMemory, + DISPID_SpeechRecoResultTimes, + DISPID_SRRTStreamTime, + DISPID_SRRTLength, + DISPID_SRRTTickCount, + DISPID_SRRTOffsetFromStart, + DISPID_SpeechPhraseAlternate, + DISPID_SPARecoResult, + DISPID_SPAStartElementInResult, + DISPID_SPANumberOfElementsInResult, + DISPID_SPAPhraseInfo, + DISPID_SPACommit, + DISPID_SpeechPhraseAlternates, + DISPID_SPAsCount, + DISPID_SPAsItem, + DISPID_SPAs_NewEnum, + DISPID_SpeechPhraseInfo, + DISPID_SPILanguageId, + DISPID_SPIGrammarId, + DISPID_SPIStartTime, + DISPID_SPIAudioStreamPosition, + DISPID_SPIAudioSizeBytes, + DISPID_SPIRetainedSizeBytes, + DISPID_SPIAudioSizeTime, + DISPID_SPIRule, + DISPID_SPIProperties, + DISPID_SPIElements, + DISPID_SPIReplacements, + DISPID_SPIEngineId, + DISPID_SPIEnginePrivateData, + DISPID_SPISaveToMemory, + DISPID_SPIGetText, + DISPID_SPIGetDisplayAttributes, + DISPID_SpeechPhraseElement, + DISPID_SPEAudioTimeOffset, + DISPID_SPEAudioSizeTime, + DISPID_SPEAudioStreamOffset, + DISPID_SPEAudioSizeBytes, + DISPID_SPERetainedStreamOffset, + DISPID_SPERetainedSizeBytes, + DISPID_SPEDisplayText, + DISPID_SPELexicalForm, + DISPID_SPEPronunciation, + DISPID_SPEDisplayAttributes, + DISPID_SPERequiredConfidence, + DISPID_SPEActualConfidence, + DISPID_SPEEngineConfidence, + SpeechEngineConfidence, + SECLowConfidence, + SECNormalConfidence, + SECHighConfidence, + DISPID_SpeechPhraseElements, + DISPID_SPEsCount, + DISPID_SPEsItem, + DISPID_SPEs_NewEnum, + DISPID_SpeechPhraseReplacement, + DISPID_SPRDisplayAttributes, + DISPID_SPRText, + DISPID_SPRFirstElement, + DISPID_SPRNumberOfElements, + DISPID_SpeechPhraseReplacements, + DISPID_SPRsCount, + DISPID_SPRsItem, + DISPID_SPRs_NewEnum, + DISPID_SpeechPhraseProperty, + DISPID_SPPName, + DISPID_SPPId, + DISPID_SPPValue, + DISPID_SPPFirstElement, + DISPID_SPPNumberOfElements, + DISPID_SPPEngineConfidence, + DISPID_SPPConfidence, + DISPID_SPPParent, + DISPID_SPPChildren, + DISPID_SpeechPhraseProperties, + DISPID_SPPsCount, + DISPID_SPPsItem, + DISPID_SPPs_NewEnum, + DISPID_SpeechPhraseRule, + DISPID_SPRuleName, + DISPID_SPRuleId, + DISPID_SPRuleFirstElement, + DISPID_SPRuleNumberOfElements, + DISPID_SPRuleParent, + DISPID_SPRuleChildren, + DISPID_SPRuleConfidence, + DISPID_SPRuleEngineConfidence, + DISPID_SpeechPhraseRules, + DISPID_SPRulesCount, + DISPID_SPRulesItem, + DISPID_SPRules_NewEnum, + DISPID_SpeechLexicon, + DISPID_SLGenerationId, + DISPID_SLGetWords, + DISPID_SLAddPronunciation, + DISPID_SLAddPronunciationByPhoneIds, + DISPID_SLRemovePronunciation, + DISPID_SLRemovePronunciationByPhoneIds, + DISPID_SLGetPronunciations, + DISPID_SLGetGenerationChange, + SpeechLexiconType, + SLTUser, + SLTApp, + SpeechPartOfSpeech, + SPSNotOverriden, + SPSUnknown, + SPSNoun, + SPSVerb, + SPSModifier, + SPSFunction, + SPSInterjection, +}; +pub const SPSLMA: SpeechPartOfSpeech = SPPS_LMA; +pub const SPSSuppressWord: SpeechPartOfSpeech = SPPS_SuppressWord; +pub use um::sapi51::{ + DISPID_SpeechLexiconWords, + DISPID_SLWsCount, + DISPID_SLWsItem, + DISPID_SLWs_NewEnum, + SpeechWordType, + SWTAdded, + SWTDeleted, + DISPID_SpeechLexiconWord, + DISPID_SLWLangId, + DISPID_SLWType, + DISPID_SLWWord, + DISPID_SLWPronunciations, + DISPID_SpeechLexiconProns, + DISPID_SLPsCount, + DISPID_SLPsItem, + DISPID_SLPs_NewEnum, + DISPID_SpeechLexiconPronunciation, + DISPID_SLPType, + DISPID_SLPLangId, + DISPID_SLPPartOfSpeech, + DISPID_SLPPhoneIds, + DISPID_SLPSymbolic, + DISPID_SpeechPhoneConverter, + DISPID_SPCLangId, + DISPID_SPCPhoneToId, + DISPID_SPCIdToPhone, + LIBID_SpeechLib, + ISpeechDataKey, ISpeechDataKeyVtbl, + ISpeechObjectToken, ISpeechObjectTokenVtbl, + ISpeechObjectTokens, ISpeechObjectTokensVtbl, + ISpeechObjectTokenCategory, ISpeechObjectTokenCategoryVtbl, + ISpeechAudioBufferInfo, ISpeechAudioBufferInfoVtbl, + ISpeechAudioStatus, ISpeechAudioStatusVtbl, + ISpeechAudioFormat, ISpeechAudioFormatVtbl, + ISpeechWaveFormatEx, ISpeechWaveFormatExVtbl, + ISpeechBaseStream, ISpeechBaseStreamVtbl, + ISpeechFileStream, ISpeechFileStreamVtbl, + ISpeechMemoryStream, ISpeechMemoryStreamVtbl, + ISpeechCustomStream, ISpeechCustomStreamVtbl, + ISpeechAudio, ISpeechAudioVtbl, + ISpeechMMSysAudio, ISpeechMMSysAudioVtbl, + ISpeechVoice, ISpeechVoiceVtbl, + ISpeechVoiceStatus, ISpeechVoiceStatusVtbl, + _ISpeechVoiceEvents, _ISpeechVoiceEventsVtbl, + ISpeechRecognizer, ISpeechRecognizerVtbl, + ISpeechRecognizerStatus, ISpeechRecognizerStatusVtbl, + ISpeechRecoContext, ISpeechRecoContextVtbl, + ISpeechRecoGrammar, ISpeechRecoGrammarVtbl, + _ISpeechRecoContextEvents, _ISpeechRecoContextEventsVtbl, + ISpeechGrammarRule, ISpeechGrammarRuleVtbl, + ISpeechGrammarRules, ISpeechGrammarRulesVtbl, + ISpeechGrammarRuleState, ISpeechGrammarRuleStateVtbl, + ISpeechGrammarRuleStateTransition, ISpeechGrammarRuleStateTransitionVtbl, + ISpeechGrammarRuleStateTransitions, ISpeechGrammarRuleStateTransitionsVtbl, + ISpeechTextSelectionInformation, ISpeechTextSelectionInformationVtbl, + ISpeechRecoResult, ISpeechRecoResultVtbl, +}; +RIDL!{#[uuid(0x8e0a246d, 0xd3c8, 0x45de, 0x86, 0x57, 0x04, 0x29, 0x0c, 0x45, 0x8c, 0x3c)] +interface ISpeechRecoResult2(ISpeechRecoResult2Vtbl): ISpeechRecoResult(ISpeechRecoResultVtbl) { + fn SetTextFeedback( + Feedback: BSTR, + WasSuccessful: VARIANT_BOOL, + ) -> HRESULT, +}} +pub use um::sapi51::{ + ISpeechRecoResultTimes, ISpeechRecoResultTimesVtbl, + ISpeechPhraseAlternate, ISpeechPhraseAlternateVtbl, + ISpeechPhraseAlternates, ISpeechPhraseAlternatesVtbl, + ISpeechPhraseInfo, ISpeechPhraseInfoVtbl, + ISpeechPhraseElement, ISpeechPhraseElementVtbl, + ISpeechPhraseElements, ISpeechPhraseElementsVtbl, + ISpeechPhraseReplacement, ISpeechPhraseReplacementVtbl, + ISpeechPhraseReplacements, ISpeechPhraseReplacementsVtbl, + ISpeechPhraseProperty, ISpeechPhrasePropertyVtbl, + ISpeechPhraseProperties, ISpeechPhrasePropertiesVtbl, + ISpeechPhraseRule, ISpeechPhraseRuleVtbl, + ISpeechPhraseRules, ISpeechPhraseRulesVtbl, + ISpeechLexicon, ISpeechLexiconVtbl, + ISpeechLexiconWords, ISpeechLexiconWordsVtbl, + ISpeechLexiconWord, ISpeechLexiconWordVtbl, + ISpeechLexiconPronunciations, ISpeechLexiconPronunciationsVtbl, + ISpeechLexiconPronunciation, ISpeechLexiconPronunciationVtbl, + Speech_Default_Weight, + Speech_Max_Word_Length, + Speech_Max_Pron_Length, + Speech_StreamPos_Asap, + Speech_StreamPos_RealTime, + SpeechAllElements, +}; +RIDL!{#[uuid(0xaaec54af, 0x8f85, 0x4924, 0x94, 0x4d, 0xb7, 0x9d, 0x39, 0xd7, 0x2e, 0x19)] +interface ISpeechXMLRecoResult(ISpeechXMLRecoResultVtbl): + ISpeechRecoResult(ISpeechRecoResultVtbl) { + fn GetXMLResult( + Options: SPXMLRESULTOPTIONS, + pResult: *mut BSTR, + ) -> HRESULT, + fn GetXMLErrorInfo( + LineNumber: *mut c_long, + ScriptLine: *mut BSTR, + Source: *mut BSTR, + Description: *mut BSTR, + ResultCode: *mut c_long, + IsError: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6d60eb64, 0xaced, 0x40a6, 0xbb, 0xf3, 0x4e, 0x55, 0x7f, 0x71, 0xde, 0xe2)] +interface ISpeechRecoResultDispatch(ISpeechRecoResultDispatchVtbl): IDispatch(IDispatchVtbl) { + fn get_RecoContext( + RecoContext: *mut ISpeechRecoContext, + ) -> HRESULT, + fn get_Times( + Times: *mut ISpeechRecoResultTimes, + ) -> HRESULT, + fn putref_AudioFormat( + Format: *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_AudioFormat( + Format: *mut *mut ISpeechAudioFormat, + ) -> HRESULT, + fn get_PhraseInfo( + PhraseInfo: *mut *mut ISpeechPhraseInfo, + ) -> HRESULT, + fn Alternates( + RequestCount: c_long, + StartElement: c_long, + Elements: c_long, + Alternates: *mut *mut ISpeechPhraseAlternates, + ) -> HRESULT, + fn Audio( + StartElement: c_long, + Elements: c_long, + Stream: *mut *mut ISpeechMemoryStream, + ) -> HRESULT, + fn SpeakAudio( + StartElement: c_long, + Elements: c_long, + Flags: SpeechVoiceSpeakFlags, + StreamNumber: *mut c_long, + ) -> HRESULT, + fn SaveToMemory( + ResultBlock: *mut VARIANT, + ) -> HRESULT, + fn DiscardResultInfo( + ValueTypes: SpeechDiscardType, + ) -> HRESULT, + fn GetXMLResult( + Options: SPXMLRESULTOPTIONS, + pResult: *mut BSTR, + ) -> HRESULT, + fn GetXMLErrorInfo( + LineNumber: *mut c_long, + ScriptLine: *mut BSTR, + Source: *mut BSTR, + Description: *mut BSTR, + ResultCode: *mut HRESULT, + IsError: *mut VARIANT_BOOL, + ) -> HRESULT, + fn SetTextFeedback( + Feedback: BSTR, + WasSuccessful: VARIANT_BOOL, + ) -> HRESULT, +}} +pub use um::sapi51::{ + ISpeechPhraseInfoBuilder, ISpeechPhraseInfoBuilderVtbl, + ISpeechPhoneConverter, ISpeechPhoneConverterVtbl, + CLSID_SpNotifyTranslator, + CLSID_SpObjectTokenCategory, + CLSID_SpObjectToken, + CLSID_SpResourceManager, + CLSID_SpStreamFormatConverter, + CLSID_SpMMAudioEnum, + CLSID_SpMMAudioIn, + CLSID_SpMMAudioOut, + CLSID_SpStream, + CLSID_SpVoice, + CLSID_SpSharedRecoContext, + CLSID_SpInprocRecognizer, + CLSID_SpSharedRecognizer, + CLSID_SpLexicon, + CLSID_SpUnCompressedLexicon, + CLSID_SpCompressedLexicon, +}; +extern { + pub static CLSID_SpShortcut: CLSID; +} +pub use um::sapi51::CLSID_SpPhoneConverter; +extern { + pub static CLSID_SpPhoneticAlphabetConverter: CLSID; +} +pub use um::sapi51::{ + CLSID_SpNullPhoneConverter, + CLSID_SpTextSelectionInformation, + CLSID_SpPhraseInfoBuilder, + CLSID_SpAudioFormat, + CLSID_SpWaveFormatEx, + CLSID_SpInProcRecoContext, + CLSID_SpCustomStream, + CLSID_SpFileStream, + CLSID_SpMemoryStream, +}; diff --git a/winapi/src/um/sapiddk.rs b/winapi/src/um/sapiddk.rs new file mode 100644 index 000000000..8ff59b523 --- /dev/null +++ b/winapi/src/um/sapiddk.rs @@ -0,0 +1,238 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_float, c_int, c_void}; +use shared::guiddef::CLSID; +use shared::minwindef::{BOOL, DWORD, ULONG}; +use um::sapi::*; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, ULONGLONG, WCHAR}; +pub use um::sapiddk51::{ + SPRECOEXTENSION, + SPALTERNATESCLSID, +}; +pub const SR_LOCALIZED_DESCRIPTION: &'static str = "Description"; +pub use um::sapiddk51::{ + ISpTokenUI, ISpTokenUIVtbl, + ISpObjectTokenEnumBuilder, ISpObjectTokenEnumBuilderVtbl, + SPWORDHANDLE, + SPRULEHANDLE, + SPGRAMMARHANDLE, + SPRECOCONTEXTHANDLE, + SPPHRASERULEHANDLE, + SPPHRASEPROPERTYHANDLE, + SPTRANSITIONID, + ISpErrorLog, ISpErrorLogVtbl, + ISpGrammarCompiler, ISpGrammarCompilerVtbl, + ISpGramCompBackend, ISpGramCompBackendVtbl, + ISpITNProcessor, ISpITNProcessorVtbl, + ISpPhraseBuilder, ISpPhraseBuilderVtbl, + ISpTask, + ISpThreadTask, + ISpThreadControl, ISpThreadControlVtbl, + SPTMTHREADINFO, + ISpTaskManager, ISpTaskManagerVtbl, + SPVSKIPTYPE, + SPVST_SENTENCE, + SPVESACTIONS, + SPVES_CONTINUE, + SPVES_ABORT, + SPVES_SKIP, + SPVES_RATE, + SPVES_VOLUME, + ISpTTSEngineSite, ISpTTSEngineSiteVtbl, + SPVTEXTFRAG, + ISpTTSEngine, ISpTTSEngineVtbl, + SPWORDENTRY, + SPRULEENTRY, + SPTRANSITIONTYPE, + SPTRANSEPSILON, + SPTRANSWORD, + SPTRANSRULE, + SPTRANSTEXTBUF, + SPTRANSWILDCARD, + SPTRANSDICTATION, + SPTRANSITIONENTRY, + SPTRANSITIONPROPERTY, + SPSTATEINFO, + SPPATHENTRY, + ISpCFGInterpreterSite, ISpCFGInterpreterSiteVtbl, + ISpCFGInterpreter, ISpCFGInterpreterVtbl, + SPCFGNOTIFY, + SPCFGN_ADD, + SPCFGN_REMOVE, + SPCFGN_INVALIDATE, + SPCFGN_ACTIVATE, + SPCFGN_DEACTIVATE, + SPRESULTTYPE, + SPRT_CFG, + SPRT_SLM, + SPRT_PROPRIETARY, + SPRT_FALSE_RECOGNITION, +}; +pub const SPRT_TYPE_MASK: SPRESULTTYPE = 3; +pub const SPRT_EMULATED: SPRESULTTYPE = 1 << 3; +pub const SPRT_EXTENDABLE_PARSE: SPRESULTTYPE = 1 << 4; +pub use um::sapiddk51::{ + SPPHRASEALT, + SPRECORESULTINFO, +}; +STRUCT!{struct SPRECORESULTINFOEX { + cbSize: ULONG, + eResultType: SPRESULTTYPE, + fHypothesis: BOOL, + fProprietaryAutoPause: BOOL, + ullStreamPosStart: ULONGLONG, + ullStreamPosEnd: ULONGLONG, + hGrammar: SPGRAMMARHANDLE, + ulSizeEngineData: ULONG, + pvEngineData: *mut c_void, + pPhrase: *mut ISpPhraseBuilder, + aPhraseAlts: *mut SPPHRASEALT, + ulNumAlts: ULONG, + ullStreamTimeStart: ULONGLONG, + ullStreamTimeEnd: ULONGLONG, +}} +pub use um::sapiddk51::{ + SPWORDINFOOPT, + SPWIO_NONE, + SPWIO_WANT_TEXT, + SPRULEINFOOPT, + SPRIO_NONE, + SPPARSEINFO, + ISpSREngineSite, ISpSREngineSiteVtbl, +}; +RIDL!{#[uuid(0x7bc6e012, 0x684a, 0x493e, 0xbd, 0xd4, 0x2b, 0xf5, 0xfb, 0xf4, 0x8c, 0xfe)] +interface ISpSREngineSite2(ISpSREngineSite2Vtbl): ISpSREngineSite(ISpSREngineSiteVtbl) { + fn AddEventEx( + pEvent: *const SPEVENTEX, + hSAPIRecoContext: SPRECOCONTEXTHANDLE, + ) -> HRESULT, + fn UpdateRecoPosEx( + ullCurrentRecoPos: ULONGLONG, + ullCurrentRecoTime: ULONGLONG, + ) -> HRESULT, + fn GetRuleTransition( + ulGrammarID: ULONG, + RuleIndex: ULONG, + pTrans: *mut SPTRANSITIONENTRY, + ) -> HRESULT, + fn RecognitionEx( + pResultInfo: *const SPRECORESULTINFOEX, + ) -> HRESULT, +}} +pub use um::sapiddk51::{ + SPPROPSRC, + SPPROPSRC_RECO_INST, + SPPROPSRC_RECO_CTX, + SPPROPSRC_RECO_GRAMMAR, + ISpSREngine, ISpSREngineVtbl, +}; +RIDL!{#[uuid(0x7ba627d8, 0x33f9, 0x4375, 0x90, 0xc5, 0x99, 0x85, 0xae, 0xe5, 0xed, 0xe5)] +interface ISpSREngine2(ISpSREngine2Vtbl): ISpSREngine(ISpSREngineVtbl) { + fn PrivateCallImmediate( + pvEngineContext: *mut c_void, + pInCallFrame: *const c_void, + ulInCallFrameSize: ULONG, + ppvCoMemResponse: *mut *mut c_void, + pulResponseSize: *mut ULONG, + ) -> HRESULT, + fn SetAdaptationData2( + pvEngineContext: *mut c_void, + pAdaptationData: *const WCHAR, + cch: ULONG, + pTopicName: LPCWSTR, + eSettings: SPADAPTATIONSETTINGS, + eRelevance: SPADAPTATIONRELEVANCE, + ) -> HRESULT, + fn SetGrammarPrefix( + pvEngineGrammar: *mut c_void, + pszPrefix: LPCWSTR, + fIsPrefixRequired: BOOL, + ) -> HRESULT, + fn SetRulePriority( + hRule: SPRULEHANDLE, + pvClientRuleContext: *mut c_void, + nRulePriority: c_int, + ) -> HRESULT, + fn EmulateRecognition( + pPhrase: *mut ISpPhrase, + dwCompareFlags: DWORD, + ) -> HRESULT, + fn SetSLMWeight( + pvEngineGrammar: *mut c_void, + flWeight: c_float, + ) -> HRESULT, + fn SetRuleWeight( + hRule: SPRULEHANDLE, + pvClientRuleContext: *mut c_void, + flWeight: c_float, + ) -> HRESULT, + fn SetTrainingState( + fDoingTraining: BOOL, + fAdaptFromTrainingData: BOOL, + ) -> HRESULT, + fn ResetAcousticModelAdaptation() -> HRESULT, + fn OnLoadCFG( + pvEngineGrammar: *mut c_void, + pvGrammarData: *const SPBINARYGRAMMAR, + ulGrammarID: ULONG, + ) -> HRESULT, + fn OnUnloadCFG( + pvEngineGrammar: *mut c_void, + ulGrammarID: ULONG, + ) -> HRESULT, +}} +pub use um::sapiddk51::SPPHRASEALTREQUEST; +RIDL!{#[uuid(0xfece8294, 0x2be1, 0x408f, 0x8e, 0x68, 0x2d, 0xe3, 0x77, 0x09, 0x2f, 0x0e)] +interface ISpSRAlternates(ISpSRAlternatesVtbl): IUnknown(IUnknownVtbl) { + fn GetAlternates( + pAltRequest: *mut SPPHRASEALTREQUEST, + ppAlts: *mut *mut SPPHRASEALT, + pcAlts: *mut ULONG, + ) -> HRESULT, + fn Commit( + pAltRequest: *mut SPPHRASEALTREQUEST, + pAlt: *mut SPPHRASEALT, + ppvResultExtra: *mut c_void, + pcbResultExtra: *mut ULONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf338f437, 0xcb33, 0x4020, 0x9c, 0xab, 0xc7, 0x1f, 0xf9, 0xce, 0x12, 0xd3)] +interface ISpSRAlternates2(ISpSRAlternates2Vtbl): ISpSRAlternates(ISpSRAlternatesVtbl) { + fn CommitText( + pAltRequest: *mut SPPHRASEALTREQUEST, + pcszNewText: LPCWSTR, + commitFlags: SPCOMMITFLAGS, + ) -> HRESULT, +}} +pub use um::sapiddk51::{_ISpPrivateEngineCall, _ISpPrivateEngineCallVtbl}; +RIDL!{#[uuid(0xdefd682a, 0xfe0a, 0x42b9, 0xbf, 0xa1, 0x56, 0xd3, 0xd6, 0xce, 0xcf, 0xaf)] +interface ISpPrivateEngineCallEx(ISpPrivateEngineCallExVtbl): IUnknown(IUnknownVtbl) { + fn CallEngineSynchronize( + pInFrame: *const c_void, + ulInFrameSize: ULONG, + ppCoMemOutFrame: *mut *mut c_void, + pulOutFrameSize: *mut ULONG, + ) -> HRESULT, + fn CallEngineImmediate( + pInFrame: *const c_void, + ulInFrameSize: ULONG, + ppCoMemOutFrame: *mut *mut c_void, + pulOutFrameSize: *mut ULONG, + ) -> HRESULT, +}} +pub use um::sapiddk51::{ + LIBID_SpeechDDKLib, + CLSID_SpDataKey, + CLSID_SpObjectTokenEnum, + CLSID_SpPhraseBuilder, + CLSID_SpITNProcessor, + CLSID_SpGrammarCompiler, +}; +extern { + pub static CLSID_SpW3CGrammarCompiler: CLSID; +} +pub use um::sapiddk51::CLSID_SpGramCompBackend; diff --git a/winapi/src/um/sapiddk51.rs b/winapi/src/um/sapiddk51.rs new file mode 100644 index 000000000..0607cebfb --- /dev/null +++ b/winapi/src/um/sapiddk51.rs @@ -0,0 +1,651 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_char, c_float, c_long, c_void}; +use shared::guiddef::{CLSID, GUID, IID, REFGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, ULONG, USHORT, WORD}; +use shared::mmreg::WAVEFORMATEX; +use shared::windef::HWND; +use um::oaidl::VARIANT; +use um::objidlbase::IStream; +use um::sapi::*; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, HRESULT, LONG, LPCWSTR, LPWSTR, PVOID, ULONGLONG, WCHAR}; +pub const SPRECOEXTENSION: &'static str = "RecoExtension"; +pub const SPALTERNATESCLSID: &'static str = "AlternatesCLSID"; +RIDL!{#[uuid(0xf8e690f0, 0x39cb, 0x4843, 0xb8, 0xd7, 0xc8, 0x46, 0x96, 0xe1, 0x11, 0x9d)] +interface ISpTokenUI(ISpTokenUIVtbl): IUnknown(IUnknownVtbl) { + fn IsUISupported( + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + punkObject: *mut IUnknown, + pfSupported: *mut BOOL, + ) -> HRESULT, + fn DisplayUI( + hwndParent: HWND, + pszTitle: LPCWSTR, + pszTypeOfUI: LPCWSTR, + pvExtraData: *mut c_void, + cbExtraData: ULONG, + pToken: *mut ISpObjectToken, + punkObject: *mut IUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x06b64f9f, 0x7fda, 0x11d2, 0xb4, 0xf2, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96)] +interface ISpObjectTokenEnumBuilder(ISpObjectTokenEnumBuilderVtbl): + IEnumSpObjectTokens(IEnumSpObjectTokensVtbl) { + fn SetAttribs( + pszReqAttribs: LPCWSTR, + pszOptAttribs: LPCWSTR, + ) -> HRESULT, + fn AddTokens( + cTokens: ULONG, + pToken: *mut *mut ISpObjectToken, + ) -> HRESULT, + fn AddTokensFromDataKey( + pDataKey: *mut ISpDataKey, + pszSubKey: LPCWSTR, + pszCategoryId: LPCWSTR, + ) -> HRESULT, + fn AddTokensFromTokenEnum( + pTokenEnum: *mut IEnumSpObjectTokens, + ) -> HRESULT, + fn Sort( + pszTokenIdToListFirst: LPCWSTR, + ) -> HRESULT, +}} +DECLARE_HANDLE!{SPWORDHANDLE, SPWORDHANDLE__} +DECLARE_HANDLE!{SPRULEHANDLE, SPRULEHANDLE__} +DECLARE_HANDLE!{SPGRAMMARHANDLE, SPGRAMMARHANDLE__} +DECLARE_HANDLE!{SPRECOCONTEXTHANDLE, SPRECOCONTEXTHANDLE__} +DECLARE_HANDLE!{SPPHRASERULEHANDLE, SPPHRASERULEHANDLE__} +DECLARE_HANDLE!{SPPHRASEPROPERTYHANDLE, SPPHRASEPROPERTYHANDLE__} +DECLARE_HANDLE!{SPTRANSITIONID, SPTRANSITIONID__} +RIDL!{#[uuid(0xf4711347, 0xe608, 0x11d2, 0xa0, 0x86, 0x00, 0xc0, 0x4f, 0x8e, 0xf9, 0xb5)] +interface ISpErrorLog(ISpErrorLogVtbl): IUnknown(IUnknownVtbl) { + fn AddError( + lLineNumber: c_long, + hr: HRESULT, + pszDescription: LPCWSTR, + pszHelpFile: LPCWSTR, + dwHelpContext: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb1e29d58, 0xa675, 0x11d2, 0x83, 0x02, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpGrammarCompiler(ISpGrammarCompilerVtbl): IUnknown(IUnknownVtbl) { + fn CompileStream( + pSource: *mut IStream, + pDest: *mut IStream, + pHeader: *mut IStream, + pReserved: *mut IUnknown, + pErrorLog: *mut ISpErrorLog, + dwFlags: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3ddca27c, 0x665c, 0x4786, 0x9f, 0x97, 0x8c, 0x90, 0xc3, 0x48, 0x8b, 0x61)] +interface ISpGramCompBackend(ISpGramCompBackendVtbl): ISpGrammarBuilder(ISpGrammarBuilderVtbl) { + fn SetSaveObjects( + pStream: *mut IStream, + pErrorLog: *mut ISpErrorLog, + ) -> HRESULT, + fn InitFromBinaryGrammar( + pBinaryData: *const SPBINARYGRAMMAR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x12d7360f, 0xa1c9, 0x11d3, 0xbc, 0x90, 0x00, 0xc0, 0x4f, 0x72, 0xdf, 0x9f)] +interface ISpITNProcessor(ISpITNProcessorVtbl): IUnknown(IUnknownVtbl) { + fn LoadITNGrammar( + pszCLSID: LPWSTR, + ) -> HRESULT, + fn ITNPhrase( + pPhrase: *mut ISpPhraseBuilder, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x88a3342a, 0x0bed, 0x4834, 0x92, 0x2b, 0x88, 0xd4, 0x31, 0x73, 0x16, 0x2f)] +interface ISpPhraseBuilder(ISpPhraseBuilderVtbl): ISpPhrase(ISpPhraseVtbl) { + fn InitFromPhrase( + pPhrase: *const SPPHRASE, + ) -> HRESULT, + fn InitFromSerializedPhrase( + pPhrase: *const SPSERIALIZEDPHRASE, + ) -> HRESULT, + fn AddElements( + cElements: ULONG, + pElement: *const SPPHRASEELEMENT, + ) -> HRESULT, + fn AddRules( + hParent: SPPHRASERULEHANDLE, + pRule: *const SPPHRASERULE, + phNewRule: *mut SPPHRASERULEHANDLE, + ) -> HRESULT, + fn AddProperties( + hParent: SPPHRASEPROPERTYHANDLE, + pProperty: *const SPPHRASEPROPERTY, + phNewProperty: *mut SPPHRASEPROPERTYHANDLE, + ) -> HRESULT, + fn AddReplacements( + cReplacements: ULONG, + pReplacements: *const SPPHRASEREPLACEMENT, + ) -> HRESULT, +}} +pub type ISpTask = *mut c_void; +pub type ISpThreadTask = *mut c_void; +RIDL!{#[uuid(0xa6be4d73, 0x4403, 0x4358, 0xb2, 0x2d, 0x03, 0x46, 0xe2, 0x3b, 0x17, 0x64)] +interface ISpThreadControl(ISpThreadControlVtbl): ISpNotifySink(ISpNotifySinkVtbl) { + fn StartThread( + dwFlags: DWORD, + phwnd: *mut HWND, + ) -> HRESULT, + fn WaitForThreadDone( + fForceStop: BOOL, + phrThreadResult: *mut HRESULT, + msTimeOut: ULONG, + ) -> HRESULT, + fn TerminateThread() -> HRESULT, + fn ThreadHandle() -> HANDLE, + fn ThreadId() -> DWORD, + fn NotifyEvent() -> HANDLE, + fn WindowHandle() -> HWND, + fn ThreadCompleteEvent() -> HANDLE, + fn ExitThreadEvent() -> HANDLE, +}} +STRUCT!{struct SPTMTHREADINFO { + lPoolSize: c_long, + lPriority: c_long, + ulConcurrencyLimit: ULONG, + ulMaxQuickAllocThreads: ULONG, +}} +RIDL!{#[uuid(0x2baeef81, 0x2ca3, 0x4331, 0x98, 0xf3, 0x26, 0xec, 0x5a, 0xbe, 0xfb, 0x03)] +interface ISpTaskManager(ISpTaskManagerVtbl): IUnknown(IUnknownVtbl) { + fn SetThreadPoolInfo( + pPoolInfo: *const SPTMTHREADINFO, + ) -> HRESULT, + fn GetThreadPoolInfo( + pPoolInfo: *mut SPTMTHREADINFO, + ) -> HRESULT, + fn QueueTask( + pTask: *mut ISpTask, + pvTaskData: *mut c_void, + hCompEvent: HANDLE, + pdwGroupId: *mut DWORD, + pTaskID: *mut DWORD, + ) -> HRESULT, + fn CreateReoccurringTask( + pTask: *mut ISpTask, + pvTaskData: *mut c_void, + hCompEvent: HANDLE, + ppTaskCtrl: *mut *mut ISpNotifySink, + ) -> HRESULT, + fn CreateThreadControl( + pTask: *mut ISpThreadTask, + pvTaskData: *mut c_void, + nPriority: c_long, + ppTaskCtrl: *mut *mut ISpThreadControl, + ) -> HRESULT, + fn TerminateTask( + dwGroupId: DWORD, + ulWaitPeriod: ULONG, + ) -> HRESULT, +}} +ENUM!{enum SPVSKIPTYPE { + SPVST_SENTENCE = 1 << 0, +}} +ENUM!{enum SPVESACTIONS { + SPVES_CONTINUE = 0, + SPVES_ABORT = 1 << 0, + SPVES_SKIP = 1 << 1, + SPVES_RATE = 1 << 2, + SPVES_VOLUME = 1 << 3, +}} +RIDL!{#[uuid(0x9880499b, 0xcce9, 0x11d2, 0xb5, 0x03, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96)] +interface ISpTTSEngineSite(ISpTTSEngineSiteVtbl): ISpEventSink(ISpEventSinkVtbl) { + fn GetActions() -> DWORD, + fn Write( + pBuff: *const c_void, + cb: ULONG, + pcbWritten: *mut ULONG, + ) -> HRESULT, + fn GetRate( + pRateAdjust: *mut c_long, + ) -> HRESULT, + fn GetVolume(pusVolume: *mut USHORT, + ) -> HRESULT, + fn GetSkipInfo( + peType: *mut SPVSKIPTYPE, + plNumItems: *mut c_long, + ) -> HRESULT, + fn CompleteSkip( + ulNumSkipped: c_long, + ) -> HRESULT, +}} +STRUCT!{struct SPVTEXTFRAG { + pNext: *mut SPVTEXTFRAG, + State: SPVSTATE, + pTextStart: LPCWSTR, + ulTextLen: ULONG, + ulTextSrcOffset: ULONG, +}} +RIDL!{#[uuid(0xa74d7c8e, 0x4cc5, 0x4f2f, 0xa6, 0xeb, 0x80, 0x4d, 0xee, 0x18, 0x50, 0x0e)] +interface ISpTTSEngine(ISpTTSEngineVtbl): IUnknown(IUnknownVtbl) { + fn Speak( + dwSpeakFlags: DWORD, + rguidFormatId: REFGUID, + pWaveFormatEx: *const WAVEFORMATEX, + pTextFragList: *const SPVTEXTFRAG, + pOutputSite: *mut ISpTTSEngineSite, + ) -> HRESULT, + fn GetOutputFormat( + pTargetFmtId: *const GUID, + pTargetWaveFormatEx: *const WAVEFORMATEX, + pOutputFormatId: *mut GUID, + ppCoMemOutputWaveFormatEx: *mut WAVEFORMATEX, + ) -> HRESULT, +}} +STRUCT!{struct SPWORDENTRY { + hWord: SPWORDHANDLE, + LangID: WORD, + pszDisplayText: *mut WCHAR, + pszLexicalForm: *mut WCHAR, + aPhoneId: *mut SPPHONEID, + pvClientContext: *mut c_void, +}} +STRUCT!{struct SPRULEENTRY { + hRule: SPRULEHANDLE, + hInitialState: SPSTATEHANDLE, + Attributes: DWORD, + pvClientRuleContext: *mut c_void, + pvClientGrammarContext: *mut c_void, +}} +ENUM!{enum SPTRANSITIONTYPE { + SPTRANSEPSILON = 0, + SPTRANSWORD, + SPTRANSRULE, + SPTRANSTEXTBUF, + SPTRANSWILDCARD, + SPTRANSDICTATION, +}} +STRUCT!{struct SPTRANSITIONENTRY_u_s1 { + hRuleInitialState: SPSTATEHANDLE, + hRule: SPRULEHANDLE, + pvClientRuleContext: *mut c_void, +}} +STRUCT!{struct SPTRANSITIONENTRY_u_s2 { + hWord: SPWORDHANDLE, + pvClientWordContext: *mut c_void, +}} +UNION!{union SPTRANSITIONENTRY_u { + [usize; 3], + s1 s1_mut: SPTRANSITIONENTRY_u_s1, + s2 s2_mut: SPTRANSITIONENTRY_u_s2, + pvGrammarCookie pvGrammarCookie_mut: *mut c_void, +}} +STRUCT!{struct SPTRANSITIONENTRY { + ID: SPTRANSITIONID, + hNextState: SPSTATEHANDLE, + Type: BYTE, + RequiredConfidence: c_char, + fHasProperty: DWORD, + Weight: c_float, + u: SPTRANSITIONENTRY_u, +}} +STRUCT!{struct SPTRANSITIONPROPERTY { + pszName: LPCWSTR, + ulId: ULONG, + pszValue: LPCWSTR, + vValue: VARIANT, +}} +STRUCT!{struct SPSTATEINFO { + cAllocatedEntries: ULONG, + pTransitions: *mut SPTRANSITIONENTRY, + cEpsilons: ULONG, + cRules: ULONG, + cWords: ULONG, + cSpecialTransitions: ULONG, +}} +STRUCT!{struct SPPATHENTRY { + hTransition: SPTRANSITIONID, + elem: SPPHRASEELEMENT, +}} +RIDL!{#[uuid(0x6a6ffad8, 0x78b6, 0x473d, 0xb8, 0x44, 0x98, 0x15, 0x2e, 0x4f, 0xb1, 0x6b)] +interface ISpCFGInterpreterSite(ISpCFGInterpreterSiteVtbl): IUnknown(IUnknownVtbl) { + fn AddTextReplacement( + pReplace: *mut SPPHRASEREPLACEMENT, + ) -> HRESULT, + fn AddProperty( + pProperty: *const SPPHRASEPROPERTY, + ) -> HRESULT, + fn GetResourceValue( + pszResourceName: LPCWSTR, + ppCoMemResource: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf3d3f926, 0x11fc, 0x11d3, 0xbb, 0x97, 0x00, 0xc0, 0x4f, 0x8e, 0xe6, 0xc0)] +interface ISpCFGInterpreter(ISpCFGInterpreterVtbl): IUnknown(IUnknownVtbl) { + fn InitGrammar( + pszGrammarName: LPCWSTR, + pvGrammarData: *mut *const c_void, + ) -> HRESULT, + fn Interpret( + pPhrase: *mut ISpPhraseBuilder, + ulFirstElement: *const ULONG, + ulCountOfElements: *const ULONG, + pSite: *mut ISpCFGInterpreterSite, + ) -> HRESULT, +}} +ENUM!{enum SPCFGNOTIFY { + SPCFGN_ADD, + SPCFGN_REMOVE, + SPCFGN_INVALIDATE, + SPCFGN_ACTIVATE, + SPCFGN_DEACTIVATE, +}} +ENUM!{enum SPRESULTTYPE { + SPRT_CFG = 0, + SPRT_SLM = 1, + SPRT_PROPRIETARY = 2, + SPRT_FALSE_RECOGNITION = 1 << 2, +}} +STRUCT!{struct SPPHRASEALT { + pPhrase: *mut ISpPhraseBuilder, + ulStartElementInParent: ULONG, + cElementsInParent: ULONG, + cElementsInAlternate: ULONG, + pvAltExtra: *mut c_void, + cbAltExtra: ULONG, +}} +STRUCT!{struct SPRECORESULTINFO { + cbSize: ULONG, + eResultType: SPRESULTTYPE, + fHypothesis: BOOL, + fProprietaryAutoPause: BOOL, + ullStreamPosStart: ULONGLONG, + ullStreamPosEnd: ULONGLONG, + hGrammar: SPGRAMMARHANDLE, + ulSizeEngineData: ULONG, + pvEngineData: *mut c_void, + pPhrase: *mut ISpPhraseBuilder, + aPhraseAlts: *mut SPPHRASEALT, + ulNumAlts: ULONG, +}} +ENUM!{enum SPWORDINFOOPT { + SPWIO_NONE = 0, + SPWIO_WANT_TEXT = 1, +}} +ENUM!{enum SPRULEINFOOPT { + SPRIO_NONE = 0, +}} +STRUCT!{struct SPPARSEINFO { + cbSize: ULONG, + hRule: SPRULEHANDLE, + ullAudioStreamPosition: ULONGLONG, + ulAudioSize: ULONG, + cTransitions: ULONG, + pPath: *mut SPPATHENTRY, + SREngineID: GUID, + ulSREnginePrivateDataSize: ULONG, + pSREnginePrivateData: *const BYTE, + fHypothesis: BOOL, +}} +RIDL!{#[uuid(0x3b414aec, 0x720c, 0x4883, 0xb9, 0xef, 0x17, 0x8c, 0xd3, 0x94, 0xfb, 0x3a)] +interface ISpSREngineSite(ISpSREngineSiteVtbl): IUnknown(IUnknownVtbl) { + fn Read( + pv: *mut c_void, + cb: ULONG, + pcbRead: *mut ULONG, + ) -> HRESULT, + fn DataAvailable( + pcb: *mut ULONG, + ) -> HRESULT, + fn SetBufferNotifySize( + cbSize: ULONG, + ) -> HRESULT, + fn ParseFromTransitions( + pParseInfo: *const SPPARSEINFO, + ppNewPhrase: *mut *mut ISpPhraseBuilder, + ) -> HRESULT, + fn Recognition( + pResultInfo: *const SPRECORESULTINFO, + ) -> HRESULT, + fn AddEvent( + pEvent: *const SPEVENT, + hSAPIRecoContext: SPRECOCONTEXTHANDLE, + ) -> HRESULT, + fn Synchronize( + ullProcessedThruPos: ULONGLONG, + ) -> HRESULT, + fn GetWordInfo( + pWordEntry: *mut SPWORDENTRY, + Options: SPWORDINFOOPT, + ) -> HRESULT, + fn SetWordClientContext( + hWord: SPWORDHANDLE, + pvClientContext: *mut c_void, + ) -> HRESULT, + fn GetRuleInfo( + pRuleEntry: *mut SPRULEENTRY, + Options: SPRULEINFOOPT, + ) -> HRESULT, + fn SetRuleClientContext( + hRule: SPRULEHANDLE, + pvClientContext: *mut c_void, + ) -> HRESULT, + fn GetStateInfo( + hState: SPSTATEHANDLE, + pStateInfo: *mut SPSTATEINFO, + ) -> HRESULT, + fn GetResource( + hRule: SPRULEHANDLE, + pszResourceName: LPCWSTR, + ppCoMemResource: *mut LPWSTR, + ) -> HRESULT, + fn GetTransitionProperty( + ID: SPTRANSITIONID, + ppCoMemProperty: *mut *mut SPTRANSITIONPROPERTY, + ) -> HRESULT, + fn IsAlternate( + hRule: SPRULEHANDLE, + hAltRule: SPRULEHANDLE, + ) -> HRESULT, + fn GetMaxAlternates( + hRule: SPRULEHANDLE, + pulNumAlts: *mut ULONG, + ) -> HRESULT, + fn GetContextMaxAlternates( + hContext: SPRECOCONTEXTHANDLE, + pulNumAlts: *mut ULONG, + ) -> HRESULT, + fn UpdateRecoPos( + ullCurrentRecoPos: ULONGLONG, + ) -> HRESULT, +}} +ENUM!{enum SPPROPSRC { + SPPROPSRC_RECO_INST, + SPPROPSRC_RECO_CTX, + SPPROPSRC_RECO_GRAMMAR, +}} +RIDL!{#[uuid(0x2f472991, 0x854b, 0x4465, 0xb6, 0x13, 0xfb, 0xaf, 0xb3, 0xad, 0x8e, 0xd8)] +interface ISpSREngine(ISpSREngineVtbl): IUnknown(IUnknownVtbl) { + fn SetSite( + pSite: *mut ISpSREngineSite, + ) -> HRESULT, + fn GetInputAudioFormat( + pguidSourceFormatId: *const GUID, + pSourceWaveFormatEx: *const WAVEFORMATEX, + pguidDesiredFormatId: *mut GUID, + ppCoMemDesiredWaveFormatEx: *mut WAVEFORMATEX, + ) -> HRESULT, + fn RecognizeStream( + rguidFmtId: REFGUID, + pWaveFormatEx: *const WAVEFORMATEX, + hRequestSync: HANDLE, + hDataAvailable: HANDLE, + hExit: HANDLE, + fNewAudioStream: BOOL, + fRealTimeAudio: BOOL, + pAudioObjectToken: *mut ISpObjectToken, + ) -> HRESULT, + fn SetRecoProfile( + pProfile: *mut ISpObjectToken, + ) -> HRESULT, + fn OnCreateGrammar( + pvEngineRecoContext: *mut c_void, + hSAPIGrammar: SPGRAMMARHANDLE, + ppvEngineGrammarContext: *mut *mut c_void, + ) -> HRESULT, + fn OnDeleteGrammar( + pvEngineGrammar: *mut c_void, + ) -> HRESULT, + fn LoadProprietaryGrammar( + pvEngineGrammar: *mut c_void, + rguidParam: REFGUID, + pszStringParam: LPCWSTR, + pvDataParam: *const c_void, + ulDataSize: ULONG, + Options: SPLOADOPTIONS, + ) -> HRESULT, + fn UnloadProprietaryGrammar( + pvEngineGrammar: *mut c_void, + ) -> HRESULT, + fn SetProprietaryRuleState( + pvEngineGrammar: *mut c_void, + pszName: LPCWSTR, + pReserved: *mut c_void, + NewState: SPRULESTATE, + pcRulesChanged: *mut ULONG, + ) -> HRESULT, + fn SetProprietaryRuleIdState( + pvEngineGrammar: *mut c_void, + dwRuleId: DWORD, + NewState: SPRULESTATE, + ) -> HRESULT, + fn LoadSLM( + pvEngineGrammar: *mut c_void, + pszTopicName: LPCWSTR, + ) -> HRESULT, + fn UnloadSLM( + pvEngineGrammar: *mut c_void, + ) -> HRESULT, + fn SetSLMState( + pvEngineGrammar: *mut c_void, + NewState: SPRULESTATE, + ) -> HRESULT, + fn SetWordSequenceData( + pvEngineGrammar: *mut c_void, + pText: *const WCHAR, + cchText: ULONG, + pInfo: *const SPTEXTSELECTIONINFO, + ) -> HRESULT, + fn SetTextSelection( + pvEngineGrammar: *mut c_void, + pInfo: *const SPTEXTSELECTIONINFO, + ) -> HRESULT, + fn IsPronounceable( + pvEngineGrammar: *mut c_void, + pszWord: LPCWSTR, + pWordPronounceable: *mut SPWORDPRONOUNCEABLE, + ) -> HRESULT, + fn OnCreateRecoContext( + hSAPIRecoContext: SPRECOCONTEXTHANDLE, + ppvEngineContext: *mut *mut c_void, + ) -> HRESULT, + fn OnDeleteRecoContext( + pvEngineContext: *mut c_void, + ) -> HRESULT, + fn OnPrivateCall( + pvEngineContext: *mut c_void, + pCallFrame: PVOID, + ulCallFrameSize: ULONG, + ) -> HRESULT, + fn SetAdaptationData( + pvEngineContext: *mut c_void, + pAdaptationData: *const WCHAR, + cch: ULONG, + ) -> HRESULT, + fn SetPropertyNum( + eSrc: SPPROPSRC, + pvSrcObj: *mut c_void, + pName: *const WCHAR, + lValue: LONG, + ) -> HRESULT, + fn GetPropertyNum( + eSrc: SPPROPSRC, + pvSrcObj: *mut c_void, + pName: *const WCHAR, + lValue: *mut LONG, + ) -> HRESULT, + fn SetPropertyString( + eSrc: SPPROPSRC, + pvSrcObj: *mut c_void, + pName: LPCWSTR, + pValue: LPCWSTR, + ) -> HRESULT, + fn GetPropertyString( + eSrc: SPPROPSRC, + pvSrcObj: *mut c_void, + pName: LPCWSTR, + ppCoMemValue: *mut LPWSTR, + ) -> HRESULT, + fn SetGrammarState( + pvEngineGrammar: *mut c_void, + eGrammarState: SPGRAMMARSTATE, + ) -> HRESULT, + fn WordNotify( + Action: SPCFGNOTIFY, + cWords: ULONG, + pWords: *const SPWORDENTRY, + ) -> HRESULT, + fn RuleNotify( + Action: SPCFGNOTIFY, + cRules: ULONG, + pRules: *const SPRULEENTRY, + ) -> HRESULT, + fn PrivateCallEx( + pvEngineContext: *mut c_void, + pInCallFrame: *const c_void, + ulInCallFrameSize: ULONG, + ppvCoMemResponse: *mut *mut c_void, + pulResponseSize: *mut ULONG, + ) -> HRESULT, + fn SetContextState( + pvEngineContext: *mut c_void, + eContextState: SPCONTEXTSTATE, + ) -> HRESULT, +}} +STRUCT!{struct SPPHRASEALTREQUEST { + ulStartElement: ULONG, + cElements: ULONG, + ulRequestAltCount: ULONG, + pvResultExtra: *mut c_void, + cbResultExtra: ULONG, + pPhrase: *mut ISpPhrase, + pRecoContext: *mut ISpRecoContext, +}} +RIDL!{#[uuid(0x8e7c791e, 0x4467, 0x11d3, 0x97, 0x23, 0x00, 0xc0, 0x4f, 0x72, 0xdb, 0x08)] +interface _ISpPrivateEngineCall(_ISpPrivateEngineCallVtbl): IUnknown(IUnknownVtbl) { + fn CallEngine( + pCallFrame: *mut c_void, + ulCallFrameSize: ULONG, + ) -> HRESULT, + fn CallEngineEx( + pInFrame: *const c_void, + ulInFrameSize: ULONG, + ppCoMemOutFrame: *mut *mut c_void, + pulOutFrameSize: *mut ULONG, + ) -> HRESULT, +}} +extern { + pub static LIBID_SpeechDDKLib: IID; + pub static CLSID_SpDataKey: CLSID; +} +RIDL!{#[uuid(0xd9f6ee60, 0x58c9, 0x458b, 0x88, 0xe1, 0x2f, 0x90, 0x8f, 0xd7, 0xf8, 0x7c)] +class SpDataKey;} +extern { + pub static CLSID_SpObjectTokenEnum: CLSID; + pub static CLSID_SpPhraseBuilder: CLSID; + pub static CLSID_SpITNProcessor: CLSID; + pub static CLSID_SpGrammarCompiler: CLSID; + pub static CLSID_SpGramCompBackend: CLSID; +} diff --git a/winapi/src/um/schannel.rs b/winapi/src/um/schannel.rs new file mode 100644 index 000000000..5ec1ac008 --- /dev/null +++ b/winapi/src/um/schannel.rs @@ -0,0 +1,339 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Public Definitions for SCHANNEL Security Provider +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, DWORD, PBYTE, WORD}; +use shared::windef::HWND; +use um::wincrypt::{ALG_ID, HCERTSTORE, HCRYPTPROV, PCCERT_CONTEXT, PCERT_NAME_BLOB}; +use um::winnt::{HRESULT, LPWSTR, PVOID, WCHAR}; +pub const UNISP_NAME: &'static str = "Microsoft Unified Security Protocol Provider"; +pub const SSL2SP_NAME: &'static str = "Microsoft SSL 2.0"; +pub const SSL3SP_NAME: &'static str = "Microsoft SSL 3.0"; +pub const TLS1SP_NAME: &'static str = "Microsoft TLS 1.0"; +pub const PCT1SP_NAME: &'static str = "Microsoft PCT 1.0"; +pub const SCHANNEL_NAME: &'static str = "Schannel"; +ENUM!{enum eTlsSignatureAlgorithm { + TlsSignatureAlgorithm_Anonymous = 0, + TlsSignatureAlgorithm_Rsa = 1, + TlsSignatureAlgorithm_Dsa = 2, + TlsSignatureAlgorithm_Ecdsa = 3, +}} +ENUM!{enum eTlsHashAlgorithm { + TlsHashAlgorithm_None = 0, + TlsHashAlgorithm_Md5 = 1, + TlsHashAlgorithm_Sha1 = 2, + TlsHashAlgorithm_Sha224 = 3, + TlsHashAlgorithm_Sha256 = 4, + TlsHashAlgorithm_Sha384 = 5, + TlsHashAlgorithm_Sha512 = 6, +}} +pub const UNISP_RPC_ID: DWORD = 14; +STRUCT!{struct SecPkgContext_RemoteCredentialInfo { + cbCertificateChain: DWORD, + pbCertificateChain: PBYTE, + cCertificates: DWORD, + fFlags: DWORD, + dwBits: DWORD, +}} +pub type PSecPkgContext_RemoteCredentialInfo = *mut SecPkgContext_RemoteCredentialInfo; +pub type SecPkgContext_RemoteCredenitalInfo = SecPkgContext_RemoteCredentialInfo; +pub type PSecPkgContext_RemoteCredenitalInfo = *mut SecPkgContext_RemoteCredentialInfo; +pub const RCRED_STATUS_NOCRED: DWORD = 0x00000000; +pub const RCRED_CRED_EXISTS: DWORD = 0x00000001; +pub const RCRED_STATUS_UNKNOWN_ISSUER: DWORD = 0x00000002; +STRUCT!{struct SecPkgContext_LocalCredentialInfo { + cbCertificateChain: DWORD, + pbCertificateChain: PBYTE, + cCertificates: DWORD, + fFlags: DWORD, + dwBits: DWORD, +}} +pub type PSecPkgContext_LocalCredentialInfo = *mut SecPkgContext_LocalCredentialInfo; +pub type SecPkgContext_LocalCredenitalInfo = SecPkgContext_LocalCredentialInfo; +pub type PSecPkgContext_LocalCredenitalInfo = *mut SecPkgContext_LocalCredentialInfo; +pub const LCRED_STATUS_NOCRED: DWORD = 0x00000000; +pub const LCRED_CRED_EXISTS: DWORD = 0x00000001; +pub const LCRED_STATUS_UNKNOWN_ISSUER: DWORD = 0x00000002; +STRUCT!{struct SecPkgContext_ClientCertPolicyResult { + dwPolicyResult: HRESULT, + guidPolicyId: GUID, +}} +pub type PSecPkgContext_ClientCertPolicyResult = *mut SecPkgContext_ClientCertPolicyResult; +STRUCT!{struct SecPkgContext_IssuerListInfoEx { + aIssuers: PCERT_NAME_BLOB, + cIssuers: DWORD, +}} +pub type PSecPkgContext_IssuerListInfoEx = *mut SecPkgContext_IssuerListInfoEx; +STRUCT!{struct SecPkgContext_ConnectionInfo { + dwProtocol: DWORD, + aiCipher: ALG_ID, + dwCipherStrength: DWORD, + aiHash: ALG_ID, + dwHashStrength: DWORD, + aiExch: ALG_ID, + dwExchStrength: DWORD, +}} +pub type PSecPkgContext_ConnectionInfo = *mut SecPkgContext_ConnectionInfo; +pub const SZ_ALG_MAX_SIZE: usize = 64; +pub const SECPKGCONTEXT_CIPHERINFO_V1: DWORD = 1; +STRUCT!{struct SecPkgContext_CipherInfo { + dwVersion: DWORD, + dwProtocol: DWORD, + dwCipherSuite: DWORD, + dwBaseCipherSuite: DWORD, + szCipherSuite: [WCHAR; SZ_ALG_MAX_SIZE], + szCipher: [WCHAR; SZ_ALG_MAX_SIZE], + dwCipherLen: DWORD, + dwCipherBlockLen: DWORD, + szHash: [WCHAR; SZ_ALG_MAX_SIZE], + dwHashLen: DWORD, + szExchange: [WCHAR; SZ_ALG_MAX_SIZE], + dwMinExchangeLen: DWORD, + dwMaxExchangeLen: DWORD, + szCertificate: [WCHAR; SZ_ALG_MAX_SIZE], + dwKeyType: DWORD, +}} +pub type PSecPkgContext_CipherInfo = *mut SecPkgContext_CipherInfo; +STRUCT!{struct SecPkgContext_EapKeyBlock { + rgbKeys: [BYTE; 128], + rgbIVs: [BYTE; 64], +}} +pub type PSecPkgContext_EapKeyBlock = *mut SecPkgContext_EapKeyBlock; +STRUCT!{struct SecPkgContext_MappedCredAttr { + dwAttribute: DWORD, + pvBuffer: PVOID, +}} +pub type PSecPkgContext_MappedCredAttr = *mut SecPkgContext_MappedCredAttr; +pub const SSL_SESSION_RECONNECT: DWORD = 1; +STRUCT!{struct SecPkgContext_SessionInfo { + dwFlags: DWORD, + cbSessionId: DWORD, + rgbSessionId: [BYTE; 32], +}} +pub type PSecPkgContext_SessionInfo = *mut SecPkgContext_SessionInfo; +STRUCT!{struct SecPkgContext_SessionAppData { + dwFlags: DWORD, + cbAppData: DWORD, + pbAppData: PBYTE, +}} +pub type PSecPkgContext_SessionAppData = *mut SecPkgContext_SessionAppData; +STRUCT!{struct SecPkgContext_EapPrfInfo { + dwVersion: DWORD, + cbPrfData: DWORD, + pbPrfData: PBYTE, +}} +pub type PSecPkgContext_EapPrfInfo = *mut SecPkgContext_EapPrfInfo; +STRUCT!{struct SecPkgContext_SupportedSignatures { + cSignatureAndHashAlgorithms: WORD, + pSignatureAndHashAlgorithms: *mut WORD, +}} +pub type PSecPkgContext_SupportedSignatures = *mut SecPkgContext_SupportedSignatures; +STRUCT!{struct SecPkgContext_Certificates { + cCertificates: DWORD, + cbCertificateChain: DWORD, + pbCertificateChain: PBYTE, +}} +pub type PSecPkgContext_Certificates = *mut SecPkgContext_Certificates; +STRUCT!{struct SecPkgContext_CertInfo { + dwVersion: DWORD, + cbSubjectName: DWORD, + pwszSubjectName: LPWSTR, + cbIssuerName: DWORD, + pwszIssuerName: LPWSTR, + dwKeySize: DWORD, +}} +pub type PSecPkgContext_CertInfo = *mut SecPkgContext_CertInfo; +pub const KERN_CONTEXT_CERT_INFO_V1: DWORD = 0x00000000; +STRUCT!{struct SecPkgContext_UiInfo { + hParentWindow: HWND, +}} +pub type PSecPkgContext_UiInfo = *mut SecPkgContext_UiInfo; +STRUCT!{struct SecPkgContext_EarlyStart { + dwEarlyStartFlags: DWORD, +}} +pub type PSecPkgContext_EarlyStart = *mut SecPkgContext_EarlyStart; +pub const ENABLE_TLS_CLIENT_EARLY_START: DWORD = 0x00000001; +pub const SCH_CRED_V1: DWORD = 0x00000001; +pub const SCH_CRED_V2: DWORD = 0x00000002; +pub const SCH_CRED_VERSION: DWORD = 0x00000002; +pub const SCH_CRED_V3: DWORD = 0x00000003; +pub const SCHANNEL_CRED_VERSION: DWORD = 0x00000004; +pub const SCHANNEL_SECRET_TYPE_CAPI: DWORD = 0x00000001; +pub const SCHANNEL_SECRET_PRIVKEY: DWORD = 0x00000002; +pub const SCH_CRED_X509_CERTCHAIN: DWORD = 0x00000001; +pub const SCH_CRED_X509_CAPI: DWORD = 0x00000002; +pub const SCH_CRED_CERT_CONTEXT: DWORD = 0x00000003; +pub enum _HMAPPER {} +STRUCT!{struct SCHANNEL_CRED { + dwVersion: DWORD, + cCreds: DWORD, + paCred: *mut PCCERT_CONTEXT, + hRootStore: HCERTSTORE, + cMappers: DWORD, + aphMappers: *mut *mut _HMAPPER, + cSupportedAlgs: DWORD, + palgSupportedAlgs: *mut ALG_ID, + grbitEnabledProtocols: DWORD, + dwMinimumCipherStrength: DWORD, + dwMaximumCipherStrength: DWORD, + dwSessionLifespan: DWORD, + dwFlags: DWORD, + dwCredFormat: DWORD, +}} +pub type PSCHANNEL_CRED = *mut SCHANNEL_CRED; +pub const SCH_CRED_FORMAT_CERT_CONTEXT: DWORD = 0x00000000; +pub const SCH_CRED_FORMAT_CERT_HASH: DWORD = 0x00000001; +pub const SCH_CRED_FORMAT_CERT_HASH_STORE: DWORD = 0x00000002; +pub const SCH_CRED_MAX_STORE_NAME_SIZE: usize = 128; +pub const SCH_CRED_MAX_SUPPORTED_ALGS: DWORD = 256; +pub const SCH_CRED_MAX_SUPPORTED_CERTS: DWORD = 100; +STRUCT!{struct SCHANNEL_CERT_HASH { + dwLength: DWORD, + dwFlags: DWORD, + hProv: HCRYPTPROV, + ShaHash: [BYTE; 20], +}} +pub type PSCHANNEL_CERT_HASH = *mut SCHANNEL_CERT_HASH; +STRUCT!{struct SCHANNEL_CERT_HASH_STORE { + dwLength: DWORD, + dwFlags: DWORD, + hProv: HCRYPTPROV, + ShaHash: [BYTE; 20], + pwszStoreName: [WCHAR; SCH_CRED_MAX_STORE_NAME_SIZE], +}} +pub type PSCHANNEL_CERT_HASH_STORE = *mut SCHANNEL_CERT_HASH_STORE; +pub const SCH_MACHINE_CERT_HASH: DWORD = 0x00000001; +pub const SCH_CRED_NO_SYSTEM_MAPPER: DWORD = 0x00000002; +pub const SCH_CRED_NO_SERVERNAME_CHECK: DWORD = 0x00000004; +pub const SCH_CRED_MANUAL_CRED_VALIDATION: DWORD = 0x00000008; +pub const SCH_CRED_NO_DEFAULT_CREDS: DWORD = 0x00000010; +pub const SCH_CRED_AUTO_CRED_VALIDATION: DWORD = 0x00000020; +pub const SCH_CRED_USE_DEFAULT_CREDS: DWORD = 0x00000040; +pub const SCH_CRED_DISABLE_RECONNECTS: DWORD = 0x00000080; +pub const SCH_CRED_REVOCATION_CHECK_END_CERT: DWORD = 0x00000100; +pub const SCH_CRED_REVOCATION_CHECK_CHAIN: DWORD = 0x00000200; +pub const SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT: DWORD = 0x00000400; +pub const SCH_CRED_IGNORE_NO_REVOCATION_CHECK: DWORD = 0x00000800; +pub const SCH_CRED_IGNORE_REVOCATION_OFFLINE: DWORD = 0x00001000; +pub const SCH_CRED_RESTRICTED_ROOTS: DWORD = 0x00002000; +pub const SCH_CRED_REVOCATION_CHECK_CACHE_ONLY: DWORD = 0x00004000; +pub const SCH_CRED_CACHE_ONLY_URL_RETRIEVAL: DWORD = 0x00008000; +pub const SCH_CRED_MEMORY_STORE_CERT: DWORD = 0x00010000; +pub const SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE: DWORD = 0x00020000; +pub const SCH_SEND_ROOT_CERT: DWORD = 0x00040000; +pub const SCH_CRED_SNI_CREDENTIAL: DWORD = 0x00080000; +pub const SCH_CRED_SNI_ENABLE_OCSP: DWORD = 0x00100000; +pub const SCH_SEND_AUX_RECORD: DWORD = 0x00200000; +pub const SCH_USE_STRONG_CRYPTO: DWORD = 0x00400000; +pub const SCHANNEL_RENEGOTIATE: DWORD = 0; +pub const SCHANNEL_SHUTDOWN: DWORD = 1; +pub const SCHANNEL_ALERT: DWORD = 2; +pub const SCHANNEL_SESSION: DWORD = 3; +STRUCT!{struct SCHANNEL_ALERT_TOKEN { + dwTokenType: DWORD, + dwAlertType: DWORD, + dwAlertNumber: DWORD, +}} +pub const TLS1_ALERT_WARNING: DWORD = 1; +pub const TLS1_ALERT_FATAL: DWORD = 2; +pub const TLS1_ALERT_CLOSE_NOTIFY: DWORD = 0; +pub const TLS1_ALERT_UNEXPECTED_MESSAGE: DWORD = 10; +pub const TLS1_ALERT_BAD_RECORD_MAC: DWORD = 20; +pub const TLS1_ALERT_DECRYPTION_FAILED: DWORD = 21; +pub const TLS1_ALERT_RECORD_OVERFLOW: DWORD = 22; +pub const TLS1_ALERT_DECOMPRESSION_FAIL: DWORD = 30; +pub const TLS1_ALERT_HANDSHAKE_FAILURE: DWORD = 40; +pub const TLS1_ALERT_BAD_CERTIFICATE: DWORD = 42; +pub const TLS1_ALERT_UNSUPPORTED_CERT: DWORD = 43; +pub const TLS1_ALERT_CERTIFICATE_REVOKED: DWORD = 44; +pub const TLS1_ALERT_CERTIFICATE_EXPIRED: DWORD = 45; +pub const TLS1_ALERT_CERTIFICATE_UNKNOWN: DWORD = 46; +pub const TLS1_ALERT_ILLEGAL_PARAMETER: DWORD = 47; +pub const TLS1_ALERT_UNKNOWN_CA: DWORD = 48; +pub const TLS1_ALERT_ACCESS_DENIED: DWORD = 49; +pub const TLS1_ALERT_DECODE_ERROR: DWORD = 50; +pub const TLS1_ALERT_DECRYPT_ERROR: DWORD = 51; +pub const TLS1_ALERT_EXPORT_RESTRICTION: DWORD = 60; +pub const TLS1_ALERT_PROTOCOL_VERSION: DWORD = 70; +pub const TLS1_ALERT_INSUFFIENT_SECURITY: DWORD = 71; +pub const TLS1_ALERT_INTERNAL_ERROR: DWORD = 80; +pub const TLS1_ALERT_USER_CANCELED: DWORD = 90; +pub const TLS1_ALERT_NO_RENEGOTIATION: DWORD = 100; +pub const TLS1_ALERT_UNSUPPORTED_EXT: DWORD = 110; +pub const TLS1_ALERT_NO_APP_PROTOCOL: DWORD = 120; +pub const SSL_SESSION_ENABLE_RECONNECTS: DWORD = 1; +pub const SSL_SESSION_DISABLE_RECONNECTS: DWORD = 2; +STRUCT!{struct SCHANNEL_SESSION_TOKEN { + dwTokenType: DWORD, + dwFlags: DWORD, +}} +STRUCT!{struct SCHANNEL_CLIENT_SIGNATURE { + cbLength: DWORD, + aiHash: ALG_ID, + cbHash: DWORD, + HashValue: [BYTE; 36], + CertThumbprint: [BYTE; 20], +}} +pub type PSCHANNEL_CLIENT_SIGNATURE = *mut SCHANNEL_CLIENT_SIGNATURE; +pub const SP_PROT_PCT1_SERVER: DWORD = 0x00000001; +pub const SP_PROT_PCT1_CLIENT: DWORD = 0x00000002; +pub const SP_PROT_PCT1: DWORD = SP_PROT_PCT1_SERVER | SP_PROT_PCT1_CLIENT; +pub const SP_PROT_SSL2_SERVER: DWORD = 0x00000004; +pub const SP_PROT_SSL2_CLIENT: DWORD = 0x00000008; +pub const SP_PROT_SSL2: DWORD = SP_PROT_SSL2_SERVER | SP_PROT_SSL2_CLIENT; +pub const SP_PROT_SSL3_SERVER: DWORD = 0x00000010; +pub const SP_PROT_SSL3_CLIENT: DWORD = 0x00000020; +pub const SP_PROT_SSL3: DWORD = SP_PROT_SSL3_SERVER | SP_PROT_SSL3_CLIENT; +pub const SP_PROT_TLS1_SERVER: DWORD = 0x00000040; +pub const SP_PROT_TLS1_CLIENT: DWORD = 0x00000080; +pub const SP_PROT_TLS1: DWORD = SP_PROT_TLS1_SERVER | SP_PROT_TLS1_CLIENT; +pub const SP_PROT_SSL3TLS1_CLIENTS: DWORD = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT; +pub const SP_PROT_SSL3TLS1_SERVERS: DWORD = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER; +pub const SP_PROT_SSL3TLS1: DWORD = SP_PROT_SSL3 | SP_PROT_TLS1; +pub const SP_PROT_UNI_SERVER: DWORD = 0x40000000; +pub const SP_PROT_UNI_CLIENT: DWORD = 0x80000000; +pub const SP_PROT_UNI: DWORD = SP_PROT_UNI_SERVER | SP_PROT_UNI_CLIENT; +pub const SP_PROT_ALL: DWORD = 0xffffffff; +pub const SP_PROT_NONE: DWORD = 0; +pub const SP_PROT_CLIENTS: DWORD = SP_PROT_PCT1_CLIENT | SP_PROT_SSL2_CLIENT + | SP_PROT_SSL3_CLIENT | SP_PROT_UNI_CLIENT | SP_PROT_TLS1_CLIENT; +pub const SP_PROT_SERVERS: DWORD = SP_PROT_PCT1_SERVER | SP_PROT_SSL2_SERVER + | SP_PROT_SSL3_SERVER | SP_PROT_UNI_SERVER | SP_PROT_TLS1_SERVER; +pub const SP_PROT_TLS1_0_SERVER: DWORD = SP_PROT_TLS1_SERVER; +pub const SP_PROT_TLS1_0_CLIENT: DWORD = SP_PROT_TLS1_CLIENT; +pub const SP_PROT_TLS1_0: DWORD = SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_0_CLIENT; +pub const SP_PROT_TLS1_1_SERVER: DWORD = 0x00000100; +pub const SP_PROT_TLS1_1_CLIENT: DWORD = 0x00000200; +pub const SP_PROT_TLS1_1: DWORD = SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_1_CLIENT; +pub const SP_PROT_TLS1_2_SERVER: DWORD = 0x00000400; +pub const SP_PROT_TLS1_2_CLIENT: DWORD = 0x00000800; +pub const SP_PROT_TLS1_2: DWORD = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_2_CLIENT; +pub const SP_PROT_DTLS_SERVER: DWORD = 0x00010000; +pub const SP_PROT_DTLS_CLIENT: DWORD = 0x00020000; +pub const SP_PROT_DTLS: DWORD = SP_PROT_DTLS_SERVER | SP_PROT_DTLS_CLIENT; +pub const SP_PROT_DTLS1_0_SERVER: DWORD = SP_PROT_DTLS_SERVER; +pub const SP_PROT_DTLS1_0_CLIENT: DWORD = SP_PROT_DTLS_CLIENT; +pub const SP_PROT_DTLS1_0: DWORD = SP_PROT_DTLS1_0_SERVER | SP_PROT_DTLS1_0_CLIENT; +pub const SP_PROT_DTLS1_X_SERVER: DWORD = SP_PROT_DTLS1_0_SERVER; +pub const SP_PROT_DTLS1_X_CLIENT: DWORD = SP_PROT_DTLS1_0_CLIENT; +pub const SP_PROT_DTLS1_X: DWORD = SP_PROT_DTLS1_X_SERVER | SP_PROT_DTLS1_X_CLIENT; +pub const SP_PROT_TLS1_1PLUS_SERVER: DWORD = SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER; +pub const SP_PROT_TLS1_1PLUS_CLIENT: DWORD = SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; +pub const SP_PROT_TLS1_1PLUS: DWORD = SP_PROT_TLS1_1PLUS_SERVER | SP_PROT_TLS1_1PLUS_CLIENT; +pub const SP_PROT_TLS1_X_SERVER: DWORD = SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_1_SERVER + | SP_PROT_TLS1_2_SERVER; +pub const SP_PROT_TLS1_X_CLIENT: DWORD = SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT + | SP_PROT_TLS1_2_CLIENT; +pub const SP_PROT_TLS1_X: DWORD = SP_PROT_TLS1_X_SERVER | SP_PROT_TLS1_X_CLIENT; +pub const SP_PROT_SSL3TLS1_X_CLIENTS: DWORD = SP_PROT_TLS1_X_CLIENT | SP_PROT_SSL3_CLIENT; +pub const SP_PROT_SSL3TLS1_X_SERVERS: DWORD = SP_PROT_TLS1_X_SERVER | SP_PROT_SSL3_SERVER; +pub const SP_PROT_SSL3TLS1_X: DWORD = SP_PROT_SSL3 | SP_PROT_TLS1_X; +pub const SP_PROT_X_CLIENTS: DWORD = SP_PROT_CLIENTS | SP_PROT_TLS1_X_CLIENT + | SP_PROT_DTLS1_X_CLIENT; +pub const SP_PROT_X_SERVERS: DWORD = SP_PROT_SERVERS | SP_PROT_TLS1_X_SERVER + | SP_PROT_DTLS1_X_SERVER; +pub const SSL_CRACK_CERTIFICATE_NAME: &'static str = "SslCrackCertificate"; +pub const SSL_FREE_CERTIFICATE_NAME: &'static str = "SslFreeCertificate"; diff --git a/winapi/src/um/securityappcontainer.rs b/winapi/src/um/securityappcontainer.rs new file mode 100644 index 000000000..02d862938 --- /dev/null +++ b/winapi/src/um/securityappcontainer.rs @@ -0,0 +1,16 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, PULONG, ULONG}; +use um::winnt::{HANDLE, LPWSTR, PSID}; +extern "system" { + pub fn GetAppContainerNamedObjectPath( + Token: HANDLE, + AppContainerSid: PSID, + ObjectPathLength: ULONG, + ObjectPath: LPWSTR, + ReturnLength: PULONG, + ) -> BOOL; +} diff --git a/winapi/src/um/securitybaseapi.rs b/winapi/src/um/securitybaseapi.rs new file mode 100644 index 000000000..81bfd18ff --- /dev/null +++ b/winapi/src/um/securitybaseapi.rs @@ -0,0 +1,690 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! FFI bindings to psapi. +use shared::guiddef::GUID; +use shared::minwindef::{ + BOOL, BYTE, DWORD, LPBOOL, LPDWORD, LPVOID, PBOOL, PDWORD, PUCHAR, PULONG, UCHAR, ULONG +}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::winnt::{ + ACL_INFORMATION_CLASS, AUDIT_EVENT_TYPE, BOOLEAN, HANDLE, LONG, LPCWSTR, LPWSTR, PACL, + PCLAIM_SECURITY_ATTRIBUTES_INFORMATION, PCWSTR, PGENERIC_MAPPING, PHANDLE, PLUID, + PLUID_AND_ATTRIBUTES, POBJECT_TYPE_LIST, PPRIVILEGE_SET, PSECURITY_DESCRIPTOR, + PSECURITY_DESCRIPTOR_CONTROL, PSID, PSID_AND_ATTRIBUTES, PSID_IDENTIFIER_AUTHORITY, + PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PVOID, SECURITY_DESCRIPTOR_CONTROL, + SECURITY_IMPERSONATION_LEVEL, SECURITY_INFORMATION, TOKEN_INFORMATION_CLASS, TOKEN_TYPE, + WELL_KNOWN_SID_TYPE +}; +extern "system" { + pub fn AccessCheck( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ClientToken: HANDLE, + DesiredAccess: DWORD, + GenericMapping: PGENERIC_MAPPING, + PrivilegeSet: PPRIVILEGE_SET, + PrivilegeSetLength: LPDWORD, + GrantedAccess: LPDWORD, + AccessStatus: LPBOOL, + ) -> BOOL; + pub fn AccessCheckAndAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ObjectTypeName: LPWSTR, + ObjectName: LPWSTR, + SecurityDescriptor: PSECURITY_DESCRIPTOR, + DesiredAccess: DWORD, + GenericMapping: PGENERIC_MAPPING, + ObjectCreation: BOOL, + GrantedAccess: LPDWORD, + AccessStatus: LPBOOL, + pfGenerateOnClose: LPBOOL, + ) -> BOOL; + pub fn AccessCheckByType( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + PrincipalSelfSid: PSID, + ClientToken: HANDLE, + DesiredAccess: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, + ObjectTypeListLength: DWORD, + GenericMapping: PGENERIC_MAPPING, + PrivilegeSet: PPRIVILEGE_SET, + PrivilegeSetLength: LPDWORD, + GrantedAccess: LPDWORD, + AccessStatus: LPBOOL, + ) -> BOOL; + pub fn AccessCheckByTypeResultList( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + PrincipalSelfSid: PSID, + ClientToken: HANDLE, + DesiredAccess: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, + ObjectTypeListLength: DWORD, + GenericMapping: PGENERIC_MAPPING, + PrivilegeSet: PPRIVILEGE_SET, + PrivilegeSetLength: LPDWORD, + GrantedAccessList: LPDWORD, + AccessStatusList: LPDWORD, + ) -> BOOL; + pub fn AccessCheckByTypeAndAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ObjectTypeName: LPWSTR, + ObjectName: LPCWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + PrincipalSelfSid: PSID, + DesiredAccess: DWORD, + AuditType: AUDIT_EVENT_TYPE, + Flags: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, + ObjectTypeListLength: DWORD, + GenericMapping: PGENERIC_MAPPING, + ObjectCreation: BOOL, + GrantedAccess: LPDWORD, + AccessStatus: LPBOOL, + pfGenerateOnClose: LPBOOL, + ) -> BOOL; + pub fn AccessCheckByTypeResultListAndAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ObjectTypeName: LPCWSTR, + ObjectName: LPCWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + PrincipalSelfSid: PSID, + DesiredAccess: DWORD, + AuditType: AUDIT_EVENT_TYPE, + Flags: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, + ObjectTypeListLength: DWORD, + GenericMapping: PGENERIC_MAPPING, + ObjectCreation: BOOL, + GrantedAccess: LPDWORD, + AccessStatusList: LPDWORD, + pfGenerateOnClose: LPBOOL, + ) -> BOOL; + pub fn AccessCheckByTypeResultListAndAuditAlarmByHandleW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ClientToken: HANDLE, + ObjectTypeName: LPCWSTR, + ObjectName: LPCWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + PrincipalSelfSid: PSID, + DesiredAccess: DWORD, + AuditType: AUDIT_EVENT_TYPE, + Flags: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, + ObjectTypeListLength: DWORD, + GenericMapping: PGENERIC_MAPPING, + ObjectCreation: BOOL, + GrantedAccess: LPDWORD, + AccessStatusList: LPDWORD, + pfGenerateOnClose: LPBOOL, + ) -> BOOL; + pub fn AddAccessAllowedAce( + pAcl: PACL, + dwAceRevision: DWORD, + AccessMask: DWORD, + pSid: PSID, + ) -> BOOL; + pub fn AddAccessAllowedAceEx( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + pSid: PSID, + ) -> BOOL; + pub fn AddAccessAllowedObjectAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + ObjectTypeGuid: *mut GUID, + InheritedObjectTypeGuid: *mut GUID, + pSid: PSID, + ) -> BOOL; + pub fn AddAccessDeniedAce( + pAcl: PACL, + dwAceRevision: DWORD, + AccessMask: DWORD, + pSid: PSID, + ) -> BOOL; + pub fn AddAccessDeniedAceEx( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + pSid: PSID, + ) -> BOOL; + pub fn AddAccessDeniedObjectAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + ObjectTypeGuid: *mut GUID, + InheritedObjectTypeGuid: *mut GUID, + pSid: PSID, + ) -> BOOL; + pub fn AddAce( + pAcl: PACL, + dwAceRevision: DWORD, + dwStartingAceIndex: DWORD, + pAceList: LPVOID, + nAceListLength: DWORD, + ) -> BOOL; + pub fn AddAuditAccessAce( + pAcl: PACL, + dwAceRevision: DWORD, + dwAccessMask: DWORD, + pSid: PSID, + bAuditSuccess: BOOL, + bAuditFailure: BOOL, + ) -> BOOL; + pub fn AddAuditAccessAceEx( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + dwAccessMask: DWORD, + pSid: PSID, + bAuditSuccess: BOOL, + bAuditFailure: BOOL, + ) -> BOOL; + pub fn AddAuditAccessObjectAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + ObjectTypeGuid: *mut GUID, + InheritedObjectTypeGuid: *mut GUID, + pSid: PSID, + bAuditSuccess: BOOL, + bAuditFailure: BOOL, + ) -> BOOL; + pub fn AddMandatoryAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + MandatoryPolicy: DWORD, + pLabelSid: PSID, + ) -> BOOL; + pub fn AddResourceAttributeAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + pSid: PSID, + pAttributeInfo: PCLAIM_SECURITY_ATTRIBUTES_INFORMATION, + pReturnLength: PDWORD, + ) -> BOOL; + pub fn AddScopedPolicyIDAce( + pAcl: PACL, + dwAceRevision: DWORD, + AceFlags: DWORD, + AccessMask: DWORD, + pSid: PSID, + ) -> BOOL; + pub fn AdjustTokenGroups( + TokenHandle: HANDLE, + ResetToDefault: BOOL, + NewState: PTOKEN_GROUPS, + BufferLength: DWORD, + PreviousState: PTOKEN_GROUPS, + ReturnLength: PDWORD, + ) -> BOOL; + pub fn AdjustTokenPrivileges( + TokenHandle: HANDLE, + DisableAllPrivileges: BOOL, + NewState: PTOKEN_PRIVILEGES, + BufferLength: DWORD, + PreviousState: PTOKEN_PRIVILEGES, + ReturnLength: PDWORD, + ) -> BOOL; + pub fn AllocateAndInitializeSid( + pIdentifierAuthoirity: PSID_IDENTIFIER_AUTHORITY, + nSubAuthorityCount: BYTE, + dwSubAuthority0: DWORD, + dwSubAuthority1: DWORD, + dwSubAuthority2: DWORD, + dwSubAuthority3: DWORD, + dwSubAuthority4: DWORD, + dwSubAuthority5: DWORD, + dwSubAuthority6: DWORD, + dwSubAuthority7: DWORD, + pSid: *mut PSID, + ) -> BOOL; + pub fn AllocateLocallyUniqueId( + Luid: PLUID, + ) -> BOOL; + pub fn AreAllAccessesGranted( + GrantedAccess: DWORD, + DesiredAccess: DWORD, + ) -> BOOL; + pub fn AreAnyAccessesGranted( + GrantedAccess: DWORD, + DesiredAccess: DWORD, + ) -> BOOL; + pub fn CheckTokenMembership( + TokenHandle: HANDLE, + SidToCheck: PSID, + IsMember: PBOOL, + ) -> BOOL; + pub fn CheckTokenCapability( + TokenHandle: HANDLE, + CapabilitySidToCheck: PSID, + HasCapability: PBOOL, + ) -> BOOL; + pub fn GetAppContainerAce( + Acl: PACL, + StartingAceIndex: DWORD, + AppContainerAce: *mut PVOID, + AppContainerAceIndex: *mut DWORD, + ) -> BOOL; + pub fn CheckTokenMembershipEx( + TokenHandle: HANDLE, + SidToCheck: PSID, + Flags: DWORD, + IsMember: PBOOL, + ) -> BOOL; + pub fn ConvertToAutoInheritPrivateObjectSecurity( + ParentDescriptor: PSECURITY_DESCRIPTOR, + CurrentSecurityDescriptor: PSECURITY_DESCRIPTOR, + NewSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ObjectType: *mut GUID, + IsDirectoryObject: BOOLEAN, + GenericMapping: PGENERIC_MAPPING, + ) -> BOOL; + pub fn CopySid( + nDestinationSidLength: DWORD, + pDestinationSid: PSID, + pSourceSid: PSID, + ) -> BOOL; + pub fn CreatePrivateObjectSecurity( + ParentDescriptor: PSECURITY_DESCRIPTOR, + CreatorDescriptor: PSECURITY_DESCRIPTOR, + NewDescriptor: *mut PSECURITY_DESCRIPTOR, + IsDirectoryObject: BOOL, + Token: HANDLE, + GenericMapping: PGENERIC_MAPPING, + ) -> BOOL; + pub fn CreatePrivateObjectSecurityEx( + ParentDescriptor: PSECURITY_DESCRIPTOR, + CreatorDescriptor: PSECURITY_DESCRIPTOR, + NewSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ObjectType: *mut GUID, + IsContainerObject: BOOL, + AutoInheritFlags: ULONG, + Token: HANDLE, + GenericMapping: PGENERIC_MAPPING, + ) -> BOOL; + pub fn CreatePrivateObjectSecurityWithMultipleInheritance( + ParentDescriptor: PSECURITY_DESCRIPTOR, + CreatorDescriptor: PSECURITY_DESCRIPTOR, + NewSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + ObjectTypes: *mut *mut GUID, + GuidCount: ULONG, + IsContainerObject: BOOL, + AutoInheritFlags: ULONG, + Token: HANDLE, + GenericMapping: PGENERIC_MAPPING, + ) -> BOOL; + pub fn CreateRestrictedToken( + ExistingTokenHandle: HANDLE, + Flags: DWORD, + DisableSidCount: DWORD, + SidsToDisable: PSID_AND_ATTRIBUTES, + DeletePrivilegeCount: DWORD, + PrivilegesToDelete: PLUID_AND_ATTRIBUTES, + RestrictedSidCount: DWORD, + SidsToRestrict: PSID_AND_ATTRIBUTES, + NewTokenHandle: PHANDLE, + ) -> BOOL; + pub fn CreateWellKnownSid( + WellKnownSidType: WELL_KNOWN_SID_TYPE, + DomainSid: PSID, + pSid: PSID, + cbSid: *mut DWORD, + ) -> BOOL; + pub fn EqualDomainSid( + pSid1: PSID, + pSid2: PSID, + pfEqual: *mut BOOL, + ) -> BOOL; + pub fn DeleteAce( + pAcl: PACL, + dwAceIndex: DWORD, + ) -> BOOL; + pub fn DestroyPrivateObjectSecurity( + ObjectDescriptor: *mut PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn DuplicateToken( + ExistingTokenHandle: HANDLE, + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + DuplicateTokenHandle: PHANDLE, + ) -> BOOL; + pub fn DuplicateTokenEx( + hExistingToken: HANDLE, + dwDesiredAccess: DWORD, + lpTokenAttributes: LPSECURITY_ATTRIBUTES, + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + TokenType: TOKEN_TYPE, + phNewToken: PHANDLE, + ) -> BOOL; + pub fn EqualPrefixSid( + pSid1: PSID, + pSid2: PSID, + ) -> BOOL; + pub fn EqualSid( + pSid1: PSID, + pSid2: PSID, + ) -> BOOL; + pub fn FindFirstFreeAce( + pAcl: PACL, + pAce: *mut LPVOID, + ) -> BOOL; + pub fn FreeSid( + pSid: PSID, + ) -> PVOID; + pub fn GetAce( + pAcl: PACL, + dwAceIndex: DWORD, + pAce: *mut LPVOID, + ) -> BOOL; + pub fn GetAclInformation( + pAcl: PACL, + pAclInformtion: LPVOID, + nAclInformationLength: DWORD, + dwAclInformationClass: ACL_INFORMATION_CLASS, + ) -> BOOL; + pub fn GetFileSecurityW( + lpFileName: LPCWSTR, + RequestedInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + nLength: DWORD, + lpnLengthNeeded: LPDWORD, + ) -> BOOL; + pub fn GetKernelObjectSecurity( + Handle: HANDLE, + RequestedInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + nLength: DWORD, + lpnLengthNeeded: LPDWORD, + ) -> BOOL; + pub fn GetLengthSid( + pSid: PSID, + ) -> DWORD; + pub fn GetPrivateObjectSecurity( + ObjectDescriptor: PSECURITY_DESCRIPTOR, + SecurityInformation: SECURITY_INFORMATION, + ResultantDescriptor: PSECURITY_DESCRIPTOR, + DescriptorLength: DWORD, + ReturnLength: PDWORD, + ) -> BOOL; + pub fn GetSecurityDescriptorControl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + pControl: PSECURITY_DESCRIPTOR_CONTROL, + lpdwRevision: LPDWORD, + ) -> BOOL; + pub fn GetSecurityDescriptorDacl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + lpbDaclPresent: LPBOOL, + pDacl: *mut PACL, + lpbDaclDefaulted: LPBOOL, + ) -> BOOL; + pub fn GetSecurityDescriptorGroup( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + pGroup: *mut PSID, + lpbGroupDefaulted: LPBOOL, + ) -> BOOL; + pub fn GetSecurityDescriptorLength( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> DWORD; + pub fn GetSecurityDescriptorOwner( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + pOwner: *mut PSID, + lpbOwnerDefaulted: LPBOOL, + ) -> BOOL; + pub fn GetSecurityDescriptorRMControl( + SecurityDescriptor: PSECURITY_DESCRIPTOR, + RMControl: PUCHAR, + ) -> DWORD; + pub fn GetSecurityDescriptorSacl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + lpbSaclPresent: LPBOOL, + pSacl: *mut PACL, + lpbSaclDefaulted: LPBOOL, + ) -> BOOL; + pub fn GetSidIdentifierAuthority( + pSid: PSID, + ) -> PSID_IDENTIFIER_AUTHORITY; + pub fn GetSidLengthRequired( + nSubAuthorityCount: UCHAR, + ) -> DWORD; + pub fn GetSidSubAuthority( + pSid: PSID, + nSubAuthority: DWORD, + ) -> PDWORD; + pub fn GetSidSubAuthorityCount( + pSid: PSID, + ) -> PUCHAR; + pub fn GetTokenInformation( + TokenHandle: HANDLE, + TokenInformationClass: TOKEN_INFORMATION_CLASS, + TokenInformation: LPVOID, + TokenInformationLength: DWORD, + ReturnLength: PDWORD, + ) -> BOOL; + pub fn GetWindowsAccountDomainSid( + pSid: PSID, + pDomainSid: PSID, + cbDomainSid: *mut DWORD, + ) -> BOOL; + pub fn ImpersonateAnonymousToken( + ThreadHandle: HANDLE, + ) -> BOOL; + pub fn ImpersonateLoggedOnUser( + hToken: HANDLE, + ) -> BOOL; + pub fn ImpersonateSelf( + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + ) -> BOOL; + pub fn InitializeAcl( + pAcl: PACL, + nAclLength: DWORD, + dwAclRevision: DWORD, + ) -> BOOL; + pub fn InitializeSecurityDescriptor( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + dwRevision: DWORD, + ) -> BOOL; + pub fn InitializeSid( + Sid: PSID, + pIdentifierAuthority: PSID_IDENTIFIER_AUTHORITY, + nSubAuthorityCount: BYTE, + ) -> BOOL; + pub fn IsTokenRestricted( + TokenHandle: HANDLE, + ) -> BOOL; + pub fn IsValidAcl( + pAcl: PACL, + ) -> BOOL; + pub fn IsValidSecurityDescriptor( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn IsValidSid( + pSid: PSID, + ) -> BOOL; + pub fn IsWellKnownSid( + pSid: PSID, + WellKnownSidType: WELL_KNOWN_SID_TYPE, + ) -> BOOL; + pub fn MakeAbsoluteSD( + pSelfRelativeSD: PSECURITY_DESCRIPTOR, + pAbsoluteSD: PSECURITY_DESCRIPTOR, + lpdwAbsoluteSDSize: LPDWORD, + pDacl: PACL, + lpdwDaclSize: LPDWORD, + pSacl: PACL, + lpdwSaclSize: LPDWORD, + pOwner: PSID, + lpdwOwnerSize: LPDWORD, + pPrimaryGroup: PSID, + lpdwPrimaryGroupSize: LPDWORD, + ) -> BOOL; + pub fn MakeSelfRelativeSD( + pAbsoluteSD: PSECURITY_DESCRIPTOR, + pSelfRelativeSD: PSECURITY_DESCRIPTOR, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn MapGenericMask( + AccessMask: PDWORD, + GenericMapping: PGENERIC_MAPPING, + ); + pub fn ObjectCloseAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + GenerateOnClose: BOOL, + ) -> BOOL; + pub fn ObjectDeleteAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + GenerateOnClose: BOOL, + ) -> BOOL; + pub fn ObjectOpenAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ObjectTypeName: LPWSTR, + ObjectName: LPWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ClientToken: HANDLE, + DesiredAccess: DWORD, + GrantedAccess: DWORD, + Privileges: PPRIVILEGE_SET, + ObjectCreation: BOOL, + AccessGranted: BOOL, + GenerateOnClose: LPBOOL, + ) -> BOOL; + pub fn ObjectPrivilegeAuditAlarmW( + SubsystemName: LPCWSTR, + HandleId: LPVOID, + ClientToken: HANDLE, + DesiredAccess: DWORD, + Privileges: PPRIVILEGE_SET, + AccessGranted: BOOL, + ) -> BOOL; + pub fn PrivilegeCheck( + ClientToken: HANDLE, + RequiredPrivileges: PPRIVILEGE_SET, + pfResult: LPBOOL, + ) -> BOOL; + pub fn PrivilegedServiceAuditAlarmW( + SubsystemName: LPCWSTR, + ServiceName: LPCWSTR, + ClientToken: HANDLE, + Privileges: PPRIVILEGE_SET, + AccessGranted: BOOL, + ) -> BOOL; + pub fn QuerySecurityAccessMask( + SecurityInformation: SECURITY_INFORMATION, + DesiredAccess: LPDWORD, + ); + pub fn RevertToSelf() -> BOOL; + pub fn SetAclInformation( + pAcl: PACL, + pAclInformation: LPVOID, + nAclInformationLength: DWORD, + dwAclInfomrationClass: ACL_INFORMATION_CLASS, + ) -> BOOL; + pub fn SetFileSecurityW( + lpFileName: LPCWSTR, + SecurityInformation: SECURITY_INFORMATION, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn SetKernelObjectSecurity( + Handle: HANDLE, + SecurityInformation: SECURITY_INFORMATION, + SecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn SetPrivateObjectSecurity( + SecurityInformation: SECURITY_INFORMATION, + ModificationDescriptor: PSECURITY_DESCRIPTOR, + ObjectsSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + GenericMapping: PGENERIC_MAPPING, + Token: HANDLE, + ) -> BOOL; + pub fn SetPrivateObjectSecurityEx( + SecurityInformation: SECURITY_INFORMATION, + ModificationDescriptor: PSECURITY_DESCRIPTOR, + ObjectsSecurityDescriptor: *mut PSECURITY_DESCRIPTOR, + AutoInheritFlags: ULONG, + GenericMapping: PGENERIC_MAPPING, + Token: HANDLE, + ) -> BOOL; + pub fn SetSecurityAccessMask( + SecurityInformation: SECURITY_INFORMATION, + DesiredAccess: LPDWORD, + ); + pub fn SetSecurityDescriptorControl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + ControlBitsOfInterest: SECURITY_DESCRIPTOR_CONTROL, + ControlBitsToSet: SECURITY_DESCRIPTOR_CONTROL, + ) -> BOOL; + pub fn SetSecurityDescriptorDacl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + bDaclPresent: BOOL, + pDacl: PACL, + bDaclDefaulted: BOOL, + ) -> BOOL; + pub fn SetSecurityDescriptorGroup( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + pGroup: PSID, + bGroupDefaulted: BOOL, + ) -> BOOL; + pub fn SetSecurityDescriptorOwner( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + pOwner: PSID, + bOwnerDefaulted: BOOL, + ) -> BOOL; + pub fn SetSecurityDescriptorRMControl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + RMControl: PUCHAR, + ) -> DWORD; + pub fn SetSecurityDescriptorSacl( + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + bSaclPresent: BOOL, + pSacl: PACL, + bSaclDefaulted: BOOL, + ) -> BOOL; + pub fn SetTokenInformation( + TokenHandle: HANDLE, + TokenInformationClass: TOKEN_INFORMATION_CLASS, + TokenInformation: LPVOID, + TokenInformationLength: DWORD, + ) -> BOOL; + pub fn SetCachedSigningLevel( + SourceFiles: PHANDLE, + SourceFileCount: ULONG, + Flags: ULONG, + TargetFile: HANDLE, + ) -> BOOL; + pub fn GetCachedSigningLevel( + File: HANDLE, + Flags: PULONG, + SigningLevel: PULONG, + Thumbprint: PUCHAR, + ThumbprintSize: PULONG, + ThumbprintAlgorithm: PULONG, + ) -> BOOL; + pub fn CveEventWrite( + CveId: PCWSTR, + AdditionalDetails: PCWSTR, + ) -> LONG; + pub fn DeriveCapabilitySidsFromName( + CapName: LPCWSTR, + CapabilityGroupSids: *mut *mut PSID, + CapabilityGroupSidCount: *mut DWORD, + CapabilitySids: *mut *mut PSID, + CapabilitySidCount: *mut DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/servprov.rs b/winapi/src/um/servprov.rs new file mode 100644 index 000000000..aeb382dbc --- /dev/null +++ b/winapi/src/um/servprov.rs @@ -0,0 +1,23 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::guiddef::{REFGUID, REFIID}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +pub type LPSERVICEPROVIDER = *mut IServiceProvider; +RIDL!{#[uuid(0x6d5140c1, 0x7436, 0x11ce, 0x80, 0x34, 0x00, 0xaa, 0x00, 0x60, 0x09, 0xfa)] +interface IServiceProvider(IServiceProviderVtbl): IUnknown(IUnknownVtbl) { + fn QueryService( + guidService: REFGUID, + riid: REFIID, + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn RemoteQueryService( + guidService: REFGUID, + riid: REFIID, + ppvObject: *mut *mut IUnknown, + ) -> HRESULT, +}} diff --git a/winapi/src/um/setupapi.rs b/winapi/src/um/setupapi.rs new file mode 100644 index 000000000..d716fc56c --- /dev/null +++ b/winapi/src/um/setupapi.rs @@ -0,0 +1,3571 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Public header file for Windows NT Setup and Device Installer services Dll. +use ctypes::c_int; +use shared::basetsd::{DWORD_PTR, UINT_PTR, ULONG_PTR}; +use shared::devpropdef::{DEVPROPKEY, DEVPROPTYPE}; +use shared::guiddef::{GUID, LPGUID}; +use shared::minwindef::{ + BOOL, BYTE, DWORD, FILETIME, HINSTANCE, HKEY, INT, LPARAM, LPCVOID, LPDWORD, MAX_PATH, PBOOL, + PBYTE, PDWORD, PINT, PUINT, UINT, USHORT, WORD, +}; +use shared::windef::{HDC, HICON, HWND, RECT}; +use um::commctrl::HIMAGELIST; +use um::prsht::{HPROPSHEETPAGE, LPPROPSHEETHEADERA, LPPROPSHEETHEADERW}; +use um::spapidef::SP_LOG_TOKEN; +use um::winnt::{ + ANYSIZE_ARRAY, APPLICATION_ERROR_MASK, CHAR, DWORDLONG, ERROR_SEVERITY_ERROR, HANDLE, LONG, + LONGLONG, LPCSTR, LPCWSTR, PCSTR, PCWSTR, PSTR, PVOID, PWSTR, WCHAR, +}; +use um::winreg::REGSAM; +pub const LINE_LEN: usize = 256; +pub const MAX_INF_STRING_LENGTH: usize = 4096; +pub const MAX_INF_SECTION_NAME_LENGTH: usize = 255; +pub const MAX_TITLE_LEN: usize = 60; +pub const MAX_INSTRUCTION_LEN: usize = 256; +pub const MAX_LABEL_LEN: usize = 30; +pub const MAX_SERVICE_NAME_LEN: usize = 256; +pub const MAX_SUBTITLE_LEN: usize = 256; +pub const SP_MAX_MACHINENAME_LENGTH: usize = MAX_PATH + 3; +pub type HINF = PVOID; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct INFCONTEXT { + Inf: PVOID, + CurrentInf: PVOID, + Section: UINT, + Line: UINT, +}} +pub type PINFCONTEXT = *mut INFCONTEXT; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INF_INFORMATION { + InfStyle: DWORD, + InfCount: DWORD, + VersionData: [BYTE; ANYSIZE_ARRAY], +}} +pub type PSP_INF_INFORMATION = *mut SP_INF_INFORMATION; +UNION!{#[cfg_attr(target_arch = "x86", repr(packed))] union SP_ALTPLATFORM_INFO_V3_u { + [u16; 1], + Reserved Reserved_mut: WORD, + Flags Flags_mut: WORD, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ALTPLATFORM_INFO_V3 { + cbSize: DWORD, + Platform: DWORD, + MajorVersion: DWORD, + MinorVersion: DWORD, + ProcessorArchitecture: WORD, + u: SP_ALTPLATFORM_INFO_V3_u, + FirstValidatedMajorVersion: DWORD, + FirstValidatedMinorVersion: DWORD, + ProductType: BYTE, + SuiteMask: WORD, + BuildNumber: DWORD, +}} +pub type PSP_ALTPLATFORM_INFO_V3 = *mut SP_ALTPLATFORM_INFO_V3; +UNION!{#[cfg_attr(target_arch = "x86", repr(packed))] union SP_ALTPLATFORM_INFO_V2_u { + [u16; 1], + Reserved Reserved_mut: WORD, + Flags Flags_mut: WORD, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ALTPLATFORM_INFO_V2 { + cbSize: DWORD, + Platform: DWORD, + MajorVersion: DWORD, + MinorVersion: DWORD, + ProcessorArchitecture: WORD, + u: SP_ALTPLATFORM_INFO_V2_u, + FirstValidatedMajorVersion: DWORD, + FirstValidatedMinorVersion: DWORD, +}} +pub type PSP_ALTPLATFORM_INFO_V2 = *mut SP_ALTPLATFORM_INFO_V2; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ALTPLATFORM_INFO_V1 { + cbSize: DWORD, + Platform: DWORD, + MajorVersion: DWORD, + MinorVersion: DWORD, + ProcessorArchitecture: WORD, + Reserved: WORD, +}} +pub type PSP_ALTPLATFORM_INFO_V1 = *mut SP_ALTPLATFORM_INFO_V1; +pub type SP_ALTPLATFORM_INFO = SP_ALTPLATFORM_INFO_V2; +pub type PSP_ALTPLATFORM_INFO = PSP_ALTPLATFORM_INFO_V2; +pub const SP_ALTPLATFORM_FLAGS_VERSION_RANGE: WORD = 0x0001; +pub const SP_ALTPLATFORM_FLAGS_SUITE_MASK: WORD = 0x0002; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ORIGINAL_FILE_INFO_A { + cbSize: DWORD, + OriginalInfName: [CHAR; MAX_PATH], + OriginalCatalogName: [CHAR; MAX_PATH], +}} +pub type PSP_ORIGINAL_FILE_INFO_A = *mut SP_ORIGINAL_FILE_INFO_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ORIGINAL_FILE_INFO_W { + cbSize: DWORD, + OriginalInfName: [WCHAR; MAX_PATH], + OriginalCatalogName: [WCHAR; MAX_PATH], +}} +pub type PSP_ORIGINAL_FILE_INFO_W = *mut SP_ORIGINAL_FILE_INFO_W; +pub const INF_STYLE_NONE: DWORD = 0x00000000; +pub const INF_STYLE_OLDNT: DWORD = 0x00000001; +pub const INF_STYLE_WIN4: DWORD = 0x00000002; +pub const INF_STYLE_CACHE_ENABLE: DWORD = 0x00000010; +pub const INF_STYLE_CACHE_DISABLE: DWORD = 0x00000020; +pub const INF_STYLE_CACHE_IGNORE: DWORD = 0x00000040; +pub const DIRID_ABSOLUTE: DWORD = -1i32 as u32; +pub const DIRID_ABSOLUTE_16BIT: DWORD = 0xffff; +pub const DIRID_NULL: DWORD = 0; +pub const DIRID_SRCPATH: DWORD = 1; +pub const DIRID_WINDOWS: DWORD = 10; +pub const DIRID_SYSTEM: DWORD = 11; +pub const DIRID_DRIVERS: DWORD = 12; +pub const DIRID_IOSUBSYS: DWORD = DIRID_DRIVERS; +pub const DIRID_DRIVER_STORE: DWORD = 13; +pub const DIRID_INF: DWORD = 17; +pub const DIRID_HELP: DWORD = 18; +pub const DIRID_FONTS: DWORD = 20; +pub const DIRID_VIEWERS: DWORD = 21; +pub const DIRID_COLOR: DWORD = 23; +pub const DIRID_APPS: DWORD = 24; +pub const DIRID_SHARED: DWORD = 25; +pub const DIRID_BOOT: DWORD = 30; +pub const DIRID_SYSTEM16: DWORD = 50; +pub const DIRID_SPOOL: DWORD = 51; +pub const DIRID_SPOOLDRIVERS: DWORD = 52; +pub const DIRID_USERPROFILE: DWORD = 53; +pub const DIRID_LOADER: DWORD = 54; +pub const DIRID_PRINTPROCESSOR: DWORD = 55; +pub const DIRID_DEFAULT: DWORD = DIRID_SYSTEM; +pub const DIRID_COMMON_STARTMENU: DWORD = 16406; +pub const DIRID_COMMON_PROGRAMS: DWORD = 16407; +pub const DIRID_COMMON_STARTUP: DWORD = 16408; +pub const DIRID_COMMON_DESKTOPDIRECTORY: DWORD = 16409; +pub const DIRID_COMMON_FAVORITES: DWORD = 16415; +pub const DIRID_COMMON_APPDATA: DWORD = 16419; +pub const DIRID_PROGRAM_FILES: DWORD = 16422; +pub const DIRID_SYSTEM_X86: DWORD = 16425; +pub const DIRID_PROGRAM_FILES_X86: DWORD = 16426; +pub const DIRID_PROGRAM_FILES_COMMON: DWORD = 16427; +pub const DIRID_PROGRAM_FILES_COMMONX86: DWORD = 16428; +pub const DIRID_COMMON_TEMPLATES: DWORD = 16429; +pub const DIRID_COMMON_DOCUMENTS: DWORD = 16430; +pub const DIRID_USER: DWORD = 0x8000; +FN!{stdcall PSP_FILE_CALLBACK_A( + Context: PVOID, + Notification: UINT, + Param1: UINT_PTR, + Param2: UINT_PTR, +) -> UINT} +FN!{stdcall PSP_FILE_CALLBACK_W( + Context: PVOID, + Notification: UINT, + Param1: UINT_PTR, + Param2: UINT_PTR, +) -> UINT} +pub const SPFILENOTIFY_STARTQUEUE: UINT = 0x00000001; +pub const SPFILENOTIFY_ENDQUEUE: UINT = 0x00000002; +pub const SPFILENOTIFY_STARTSUBQUEUE: UINT = 0x00000003; +pub const SPFILENOTIFY_ENDSUBQUEUE: UINT = 0x00000004; +pub const SPFILENOTIFY_STARTDELETE: UINT = 0x00000005; +pub const SPFILENOTIFY_ENDDELETE: UINT = 0x00000006; +pub const SPFILENOTIFY_DELETEERROR: UINT = 0x00000007; +pub const SPFILENOTIFY_STARTRENAME: UINT = 0x00000008; +pub const SPFILENOTIFY_ENDRENAME: UINT = 0x00000009; +pub const SPFILENOTIFY_RENAMEERROR: UINT = 0x0000000a; +pub const SPFILENOTIFY_STARTCOPY: UINT = 0x0000000b; +pub const SPFILENOTIFY_ENDCOPY: UINT = 0x0000000c; +pub const SPFILENOTIFY_COPYERROR: UINT = 0x0000000d; +pub const SPFILENOTIFY_NEEDMEDIA: UINT = 0x0000000e; +pub const SPFILENOTIFY_QUEUESCAN: UINT = 0x0000000f; +pub const SPFILENOTIFY_CABINETINFO: UINT = 0x00000010; +pub const SPFILENOTIFY_FILEINCABINET: UINT = 0x00000011; +pub const SPFILENOTIFY_NEEDNEWCABINET: UINT = 0x00000012; +pub const SPFILENOTIFY_FILEEXTRACTED: UINT = 0x00000013; +pub const SPFILENOTIFY_FILEOPDELAYED: UINT = 0x00000014; +pub const SPFILENOTIFY_STARTBACKUP: UINT = 0x00000015; +pub const SPFILENOTIFY_BACKUPERROR: UINT = 0x00000016; +pub const SPFILENOTIFY_ENDBACKUP: UINT = 0x00000017; +pub const SPFILENOTIFY_QUEUESCAN_EX: UINT = 0x00000018; +pub const SPFILENOTIFY_STARTREGISTRATION: UINT = 0x00000019; +pub const SPFILENOTIFY_ENDREGISTRATION: UINT = 0x00000020; +pub const SPFILENOTIFY_QUEUESCAN_SIGNERINFO: UINT = 0x00000040; +pub const SPFILENOTIFY_LANGMISMATCH: UINT = 0x00010000; +pub const SPFILENOTIFY_TARGETEXISTS: UINT = 0x00020000; +pub const SPFILENOTIFY_TARGETNEWER: UINT = 0x00040000; +pub const FILEOP_COPY: UINT = 0; +pub const FILEOP_RENAME: UINT = 1; +pub const FILEOP_DELETE: UINT = 2; +pub const FILEOP_BACKUP: UINT = 3; +pub const FILEOP_ABORT: UINT = 0; +pub const FILEOP_DOIT: UINT = 1; +pub const FILEOP_SKIP: UINT = 2; +pub const FILEOP_RETRY: UINT = FILEOP_DOIT; +pub const FILEOP_NEWPATH: UINT = 4; +pub const COPYFLG_WARN_IF_SKIP: UINT = 0x00000001; +pub const COPYFLG_NOSKIP: UINT = 0x00000002; +pub const COPYFLG_NOVERSIONCHECK: UINT = 0x00000004; +pub const COPYFLG_FORCE_FILE_IN_USE: UINT = 0x00000008; +pub const COPYFLG_NO_OVERWRITE: UINT = 0x00000010; +pub const COPYFLG_NO_VERSION_DIALOG: UINT = 0x00000020; +pub const COPYFLG_OVERWRITE_OLDER_ONLY: UINT = 0x00000040; +pub const COPYFLG_PROTECTED_WINDOWS_DRIVER_FILE: UINT = 0x00000100; +pub const COPYFLG_REPLACEONLY: UINT = 0x00000400; +pub const COPYFLG_NODECOMP: UINT = 0x00000800; +pub const COPYFLG_REPLACE_BOOT_FILE: UINT = 0x00001000; +pub const COPYFLG_NOPRUNE: UINT = 0x00002000; +pub const COPYFLG_IN_USE_TRY_RENAME: UINT = 0x00004000; +pub const DELFLG_IN_USE: UINT = 0x00000001; +pub const DELFLG_IN_USE1: UINT = 0x00010000; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILEPATHS_A { + Target: PCSTR, + Source: PCSTR, + Win32Error: UINT, + Flags: DWORD, +}} +pub type PFILEPATHS_A = *mut FILEPATHS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILEPATHS_W { + Target: PCWSTR, + Source: PCWSTR, + Win32Error: UINT, + Flags: DWORD, +}} +pub type PFILEPATHS_W = *mut FILEPATHS_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILEPATHS_SIGNERINFO_A { + Target: PCSTR, + Source: PCSTR, + Win32Error: UINT, + Flags: DWORD, + DigitalSigner: PCSTR, + Version: PCSTR, + CatalogFile: PCSTR, +}} +pub type PFILEPATHS_SIGNERINFO_A = *mut FILEPATHS_SIGNERINFO_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILEPATHS_SIGNERINFO_W { + Target: PCWSTR, + Source: PCWSTR, + Win32Error: UINT, + Flags: DWORD, + DigitalSigner: PCWSTR, + Version: PCWSTR, + CatalogFile: PCWSTR, +}} +pub type PFILEPATHS_SIGNERINFO_W = *mut FILEPATHS_SIGNERINFO_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SOURCE_MEDIA_A { + Reserved: PCSTR, + Tagfile: PCSTR, + Description: PCSTR, + SourcePath: PCSTR, + SourceFile: PCSTR, + Flags: DWORD, +}} +pub type PSOURCE_MEDIA_A = *mut SOURCE_MEDIA_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SOURCE_MEDIA_W { + Reserved: PCWSTR, + Tagfile: PCWSTR, + Description: PCWSTR, + SourcePath: PCWSTR, + SourceFile: PCWSTR, + Flags: DWORD, +}} +pub type PSOURCE_MEDIA_W = *mut SOURCE_MEDIA_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CABINET_INFO_A { + CabinetPath: PCSTR, + CabinetFile: PCSTR, + DiskName: PCSTR, + SetId: USHORT, + CabinetNumber: USHORT, +}} +pub type PCABINET_INFO_A = *mut CABINET_INFO_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct CABINET_INFO_W { + CabinetPath: PCWSTR, + CabinetFile: PCWSTR, + DiskName: PCWSTR, + SetId: USHORT, + CabinetNumber: USHORT, +}} +pub type PCABINET_INFO_W = *mut CABINET_INFO_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILE_IN_CABINET_INFO_A { + NameInCabinet: PCSTR, + FileSize: DWORD, + Win32Error: DWORD, + DosDate: WORD, + DosTime: WORD, + DosAttribs: WORD, + FullTargetName: [CHAR; MAX_PATH], +}} +pub type PFILE_IN_CABINET_INFO_A = *mut FILE_IN_CABINET_INFO_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct FILE_IN_CABINET_INFO_W { + NameInCabinet: PCWSTR, + FileSize: DWORD, + Win32Error: DWORD, + DosDate: WORD, + DosTime: WORD, + DosAttribs: WORD, + FullTargetName: [WCHAR; MAX_PATH], +}} +pub type PFILE_IN_CABINET_INFO_W = *mut FILE_IN_CABINET_INFO_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_REGISTER_CONTROL_STATUSA { + cbSize: DWORD, + FileName: PCSTR, + Win32Error: DWORD, + FailureCode: DWORD, +}} +pub type PSP_REGISTER_CONTROL_STATUSA = *mut SP_REGISTER_CONTROL_STATUSA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_REGISTER_CONTROL_STATUSW { + cbSize: DWORD, + FileName: PCWSTR, + Win32Error: DWORD, + FailureCode: DWORD, +}} +pub type PSP_REGISTER_CONTROL_STATUSW = *mut SP_REGISTER_CONTROL_STATUSW; +pub const SPREG_SUCCESS: DWORD = 0x00000000; +pub const SPREG_LOADLIBRARY: DWORD = 0x00000001; +pub const SPREG_GETPROCADDR: DWORD = 0x00000002; +pub const SPREG_REGSVR: DWORD = 0x00000003; +pub const SPREG_DLLINSTALL: DWORD = 0x00000004; +pub const SPREG_TIMEOUT: DWORD = 0x00000005; +pub const SPREG_UNKNOWN: DWORD = 0xFFFFFFFF; +pub type HSPFILEQ = PVOID; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_FILE_COPY_PARAMS_A { + cbSize: DWORD, + QueueHandle: HSPFILEQ, + SourceRootPath: PCSTR, + SourcePath: PCSTR, + SourceFilename: PCSTR, + SourceDescription: PCSTR, + SourceTagfile: PCSTR, + TargetDirectory: PCSTR, + TargetFilename: PCSTR, + CopyStyle: DWORD, + LayoutInf: HINF, + SecurityDescriptor: PCSTR, +}} +pub type PSP_FILE_COPY_PARAMS_A = *mut SP_FILE_COPY_PARAMS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_FILE_COPY_PARAMS_W { + cbSize: DWORD, + QueueHandle: HSPFILEQ, + SourceRootPath: PCWSTR, + SourcePath: PCWSTR, + SourceFilename: PCWSTR, + SourceDescription: PCWSTR, + SourceTagfile: PCWSTR, + TargetDirectory: PCWSTR, + TargetFilename: PCWSTR, + CopyStyle: DWORD, + LayoutInf: HINF, + SecurityDescriptor: PCWSTR, +}} +pub type PSP_FILE_COPY_PARAMS_W = *mut SP_FILE_COPY_PARAMS_W; +pub type HDSKSPC = PVOID; +pub type HDEVINFO = PVOID; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVINFO_DATA { + cbSize: DWORD, + ClassGuid: GUID, + DevInst: DWORD, + Reserved: ULONG_PTR, +}} +pub type PSP_DEVINFO_DATA = *mut SP_DEVINFO_DATA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVICE_INTERFACE_DATA { + cbSize: DWORD, + InterfaceClassGuid: GUID, + Flags: DWORD, + Reserved: ULONG_PTR, +}} +pub type PSP_DEVICE_INTERFACE_DATA = *mut SP_DEVICE_INTERFACE_DATA; +pub const SPINT_ACTIVE: DWORD = 0x00000001; +pub const SPINT_DEFAULT: DWORD = 0x00000002; +pub const SPINT_REMOVED: DWORD = 0x00000004; +pub type SP_INTERFACE_DEVICE_DATA = SP_DEVICE_INTERFACE_DATA; +pub type PSP_INTERFACE_DEVICE_DATA = PSP_DEVICE_INTERFACE_DATA; +pub const SPID_ACTIVE: DWORD = SPINT_ACTIVE; +pub const SPID_DEFAULT: DWORD = SPINT_DEFAULT; +pub const SPID_REMOVED: DWORD = SPINT_REMOVED; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVICE_INTERFACE_DETAIL_DATA_A { + cbSize: DWORD, + DevicePath: [CHAR; ANYSIZE_ARRAY], +}} +pub type PSP_DEVICE_INTERFACE_DETAIL_DATA_A = *mut SP_DEVICE_INTERFACE_DETAIL_DATA_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVICE_INTERFACE_DETAIL_DATA_W { + cbSize: DWORD, + DevicePath: [WCHAR; ANYSIZE_ARRAY], +}} +pub type PSP_DEVICE_INTERFACE_DETAIL_DATA_W = *mut SP_DEVICE_INTERFACE_DETAIL_DATA_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVINFO_LIST_DETAIL_DATA_A { + cbSize: DWORD, + ClassGuid: GUID, + RemoteMachineHandle: HANDLE, + RemoteMachineName: [CHAR; SP_MAX_MACHINENAME_LENGTH], +}} +pub type PSP_DEVINFO_LIST_DETAIL_DATA_A = *mut SP_DEVINFO_LIST_DETAIL_DATA_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVINFO_LIST_DETAIL_DATA_W { + cbSize: DWORD, + ClassGuid: GUID, + RemoteMachineHandle: HANDLE, + RemoteMachineName: [WCHAR; SP_MAX_MACHINENAME_LENGTH], +}} +pub type PSP_DEVINFO_LIST_DETAIL_DATA_W = *mut SP_DEVINFO_LIST_DETAIL_DATA_W; +pub const DIF_SELECTDEVICE: DI_FUNCTION = 0x00000001; +pub const DIF_INSTALLDEVICE: DI_FUNCTION = 0x00000002; +pub const DIF_ASSIGNRESOURCES: DI_FUNCTION = 0x00000003; +pub const DIF_PROPERTIES: DI_FUNCTION = 0x00000004; +pub const DIF_REMOVE: DI_FUNCTION = 0x00000005; +pub const DIF_FIRSTTIMESETUP: DI_FUNCTION = 0x00000006; +pub const DIF_FOUNDDEVICE: DI_FUNCTION = 0x00000007; +pub const DIF_SELECTCLASSDRIVERS: DI_FUNCTION = 0x00000008; +pub const DIF_VALIDATECLASSDRIVERS: DI_FUNCTION = 0x00000009; +pub const DIF_INSTALLCLASSDRIVERS: DI_FUNCTION = 0x0000000A; +pub const DIF_CALCDISKSPACE: DI_FUNCTION = 0x0000000B; +pub const DIF_DESTROYPRIVATEDATA: DI_FUNCTION = 0x0000000C; +pub const DIF_VALIDATEDRIVER: DI_FUNCTION = 0x0000000D; +pub const DIF_DETECT: DI_FUNCTION = 0x0000000F; +pub const DIF_INSTALLWIZARD: DI_FUNCTION = 0x00000010; +pub const DIF_DESTROYWIZARDDATA: DI_FUNCTION = 0x00000011; +pub const DIF_PROPERTYCHANGE: DI_FUNCTION = 0x00000012; +pub const DIF_ENABLECLASS: DI_FUNCTION = 0x00000013; +pub const DIF_DETECTVERIFY: DI_FUNCTION = 0x00000014; +pub const DIF_INSTALLDEVICEFILES: DI_FUNCTION = 0x00000015; +pub const DIF_UNREMOVE: DI_FUNCTION = 0x00000016; +pub const DIF_SELECTBESTCOMPATDRV: DI_FUNCTION = 0x00000017; +pub const DIF_ALLOW_INSTALL: DI_FUNCTION = 0x00000018; +pub const DIF_REGISTERDEVICE: DI_FUNCTION = 0x00000019; +pub const DIF_NEWDEVICEWIZARD_PRESELECT: DI_FUNCTION = 0x0000001A; +pub const DIF_NEWDEVICEWIZARD_SELECT: DI_FUNCTION = 0x0000001B; +pub const DIF_NEWDEVICEWIZARD_PREANALYZE: DI_FUNCTION = 0x0000001C; +pub const DIF_NEWDEVICEWIZARD_POSTANALYZE: DI_FUNCTION = 0x0000001D; +pub const DIF_NEWDEVICEWIZARD_FINISHINSTALL: DI_FUNCTION = 0x0000001E; +pub const DIF_UNUSED1: DI_FUNCTION = 0x0000001F; +pub const DIF_INSTALLINTERFACES: DI_FUNCTION = 0x00000020; +pub const DIF_DETECTCANCEL: DI_FUNCTION = 0x00000021; +pub const DIF_REGISTER_COINSTALLERS: DI_FUNCTION = 0x00000022; +pub const DIF_ADDPROPERTYPAGE_ADVANCED: DI_FUNCTION = 0x00000023; +pub const DIF_ADDPROPERTYPAGE_BASIC: DI_FUNCTION = 0x00000024; +pub const DIF_RESERVED1: DI_FUNCTION = 0x00000025; +pub const DIF_TROUBLESHOOTER: DI_FUNCTION = 0x00000026; +pub const DIF_POWERMESSAGEWAKE: DI_FUNCTION = 0x00000027; +pub const DIF_ADDREMOTEPROPERTYPAGE_ADVANCED: DI_FUNCTION = 0x00000028; +pub const DIF_UPDATEDRIVER_UI: DI_FUNCTION = 0x00000029; +pub const DIF_FINISHINSTALL_ACTION: DI_FUNCTION = 0x0000002A; +pub const DIF_RESERVED2: DI_FUNCTION = 0x00000030; +pub const DIF_MOVEDEVICE: DI_FUNCTION = 0x0000000E; +pub type DI_FUNCTION = UINT; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVINSTALL_PARAMS_A { + cbSize: DWORD, + Flags: DWORD, + FlagsEx: DWORD, + hwndParent: HWND, + InstallMsgHandler: PSP_FILE_CALLBACK_A, + InstallMsgHandlerContext: PVOID, + FileQueue: HSPFILEQ, + ClassInstallReserved: ULONG_PTR, + Reserved: DWORD, + DriverPath: [CHAR; MAX_PATH], +}} +pub type PSP_DEVINSTALL_PARAMS_A = *mut SP_DEVINSTALL_PARAMS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DEVINSTALL_PARAMS_W { + cbSize: DWORD, + Flags: DWORD, + FlagsEx: DWORD, + hwndParent: HWND, + InstallMsgHandler: PSP_FILE_CALLBACK_W, + InstallMsgHandlerContext: PVOID, + FileQueue: HSPFILEQ, + ClassInstallReserved: ULONG_PTR, + Reserved: DWORD, + DriverPath: [WCHAR; MAX_PATH], +}} +pub type PSP_DEVINSTALL_PARAMS_W = *mut SP_DEVINSTALL_PARAMS_W; +pub const DI_SHOWOEM: DWORD = 0x00000001; +pub const DI_SHOWCOMPAT: DWORD = 0x00000002; +pub const DI_SHOWCLASS: DWORD = 0x00000004; +pub const DI_SHOWALL: DWORD = 0x00000007; +pub const DI_NOVCP: DWORD = 0x00000008; +pub const DI_DIDCOMPAT: DWORD = 0x00000010; +pub const DI_DIDCLASS: DWORD = 0x00000020; +pub const DI_AUTOASSIGNRES: DWORD = 0x00000040; +pub const DI_NEEDRESTART: DWORD = 0x00000080; +pub const DI_NEEDREBOOT: DWORD = 0x00000100; +pub const DI_NOBROWSE: DWORD = 0x00000200; +pub const DI_MULTMFGS: DWORD = 0x00000400; +pub const DI_DISABLED: DWORD = 0x00000800; +pub const DI_GENERALPAGE_ADDED: DWORD = 0x00001000; +pub const DI_RESOURCEPAGE_ADDED: DWORD = 0x00002000; +pub const DI_PROPERTIES_CHANGE: DWORD = 0x00004000; +pub const DI_INF_IS_SORTED: DWORD = 0x00008000; +pub const DI_ENUMSINGLEINF: DWORD = 0x00010000; +pub const DI_DONOTCALLCONFIGMG: DWORD = 0x00020000; +pub const DI_INSTALLDISABLED: DWORD = 0x00040000; +pub const DI_COMPAT_FROM_CLASS: DWORD = 0x00080000; +pub const DI_CLASSINSTALLPARAMS: DWORD = 0x00100000; +pub const DI_NODI_DEFAULTACTION: DWORD = 0x00200000; +pub const DI_QUIETINSTALL: DWORD = 0x00800000; +pub const DI_NOFILECOPY: DWORD = 0x01000000; +pub const DI_FORCECOPY: DWORD = 0x02000000; +pub const DI_DRIVERPAGE_ADDED: DWORD = 0x04000000; +pub const DI_USECI_SELECTSTRINGS: DWORD = 0x08000000; +pub const DI_OVERRIDE_INFFLAGS: DWORD = 0x10000000; +pub const DI_PROPS_NOCHANGEUSAGE: DWORD = 0x20000000; +pub const DI_NOSELECTICONS: DWORD = 0x40000000; +pub const DI_NOWRITE_IDS: DWORD = 0x80000000; +pub const DI_FLAGSEX_RESERVED2: DWORD = 0x00000001; +pub const DI_FLAGSEX_RESERVED3: DWORD = 0x00000002; +pub const DI_FLAGSEX_CI_FAILED: DWORD = 0x00000004; +pub const DI_FLAGSEX_FINISHINSTALL_ACTION: DWORD = 0x00000008; +pub const DI_FLAGSEX_DIDINFOLIST: DWORD = 0x00000010; +pub const DI_FLAGSEX_DIDCOMPATINFO: DWORD = 0x00000020; +pub const DI_FLAGSEX_FILTERCLASSES: DWORD = 0x00000040; +pub const DI_FLAGSEX_SETFAILEDINSTALL: DWORD = 0x00000080; +pub const DI_FLAGSEX_DEVICECHANGE: DWORD = 0x00000100; +pub const DI_FLAGSEX_ALWAYSWRITEIDS: DWORD = 0x00000200; +pub const DI_FLAGSEX_PROPCHANGE_PENDING: DWORD = 0x00000400; +pub const DI_FLAGSEX_ALLOWEXCLUDEDDRVS: DWORD = 0x00000800; +pub const DI_FLAGSEX_NOUIONQUERYREMOVE: DWORD = 0x00001000; +pub const DI_FLAGSEX_USECLASSFORCOMPAT: DWORD = 0x00002000; +pub const DI_FLAGSEX_RESERVED4: DWORD = 0x00004000; +pub const DI_FLAGSEX_NO_DRVREG_MODIFY: DWORD = 0x00008000; +pub const DI_FLAGSEX_IN_SYSTEM_SETUP: DWORD = 0x00010000; +pub const DI_FLAGSEX_INET_DRIVER: DWORD = 0x00020000; +pub const DI_FLAGSEX_APPENDDRIVERLIST: DWORD = 0x00040000; +pub const DI_FLAGSEX_PREINSTALLBACKUP: DWORD = 0x00080000; +pub const DI_FLAGSEX_BACKUPONREPLACE: DWORD = 0x00100000; +pub const DI_FLAGSEX_DRIVERLIST_FROM_URL: DWORD = 0x00200000; +pub const DI_FLAGSEX_RESERVED1: DWORD = 0x00400000; +pub const DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS: DWORD = 0x00800000; +pub const DI_FLAGSEX_POWERPAGE_ADDED: DWORD = 0x01000000; +pub const DI_FLAGSEX_FILTERSIMILARDRIVERS: DWORD = 0x02000000; +pub const DI_FLAGSEX_INSTALLEDDRIVER: DWORD = 0x04000000; +pub const DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE: DWORD = 0x08000000; +pub const DI_FLAGSEX_ALTPLATFORM_DRVSEARCH: DWORD = 0x10000000; +pub const DI_FLAGSEX_RESTART_DEVICE_ONLY: DWORD = 0x20000000; +pub const DI_FLAGSEX_RECURSIVESEARCH: DWORD = 0x40000000; +pub const DI_FLAGSEX_SEARCH_PUBLISHED_INFS: DWORD = 0x80000000; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_CLASSINSTALL_HEADER { + cbSize: DWORD, + InstallFunction: DI_FUNCTION, +}} +pub type PSP_CLASSINSTALL_HEADER = *mut SP_CLASSINSTALL_HEADER; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_ENABLECLASS_PARAMS { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + ClassGuid: GUID, + EnableMessage: DWORD, +}} +pub type PSP_ENABLECLASS_PARAMS = *mut SP_ENABLECLASS_PARAMS; +pub const ENABLECLASS_QUERY: DWORD = 0; +pub const ENABLECLASS_SUCCESS: DWORD = 1; +pub const ENABLECLASS_FAILURE: DWORD = 2; +pub const DICS_ENABLE: DWORD = 0x00000001; +pub const DICS_DISABLE: DWORD = 0x00000002; +pub const DICS_PROPCHANGE: DWORD = 0x00000003; +pub const DICS_START: DWORD = 0x00000004; +pub const DICS_STOP: DWORD = 0x00000005; +pub const DICS_FLAG_GLOBAL: DWORD = 0x00000001; +pub const DICS_FLAG_CONFIGSPECIFIC: DWORD = 0x00000002; +pub const DICS_FLAG_CONFIGGENERAL: DWORD = 0x00000004; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_PROPCHANGE_PARAMS { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + StateChange: DWORD, + Scope: DWORD, + HwProfile: DWORD, +}} +pub type PSP_PROPCHANGE_PARAMS = *mut SP_PROPCHANGE_PARAMS; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_REMOVEDEVICE_PARAMS { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Scope: DWORD, + HwProfile: DWORD, +}} +pub type PSP_REMOVEDEVICE_PARAMS = *mut SP_REMOVEDEVICE_PARAMS; +pub const DI_REMOVEDEVICE_GLOBAL: DWORD = 0x00000001; +pub const DI_REMOVEDEVICE_CONFIGSPECIFIC: DWORD = 0x00000002; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_UNREMOVEDEVICE_PARAMS { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Scope: DWORD, + HwProfile: DWORD, +}} +pub type PSP_UNREMOVEDEVICE_PARAMS = *mut SP_UNREMOVEDEVICE_PARAMS; +pub const DI_UNREMOVEDEVICE_CONFIGSPECIFIC: DWORD = 0x00000002; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_SELECTDEVICE_PARAMS_A { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Title: [CHAR; MAX_TITLE_LEN], + Instructions: [CHAR; MAX_INSTRUCTION_LEN], + ListLabel: [CHAR; MAX_LABEL_LEN], + SubTitle: [CHAR; MAX_SUBTITLE_LEN], + Reserved: [BYTE; 2], +}} +pub type PSP_SELECTDEVICE_PARAMS_A = *mut SP_SELECTDEVICE_PARAMS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_SELECTDEVICE_PARAMS_W { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Title: [WCHAR; MAX_TITLE_LEN], + Instructions: [WCHAR; MAX_INSTRUCTION_LEN], + ListLabel: [WCHAR; MAX_LABEL_LEN], + SubTitle: [WCHAR; MAX_SUBTITLE_LEN], +}} +pub type PSP_SELECTDEVICE_PARAMS_W = *mut SP_SELECTDEVICE_PARAMS_W; +FN!{stdcall PDETECT_PROGRESS_NOTIFY( + ProgressNotifyParam: PVOID, + DetectComplete: DWORD, +) -> BOOL} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DETECTDEVICE_PARAMS { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + DetectProgressNotify: PDETECT_PROGRESS_NOTIFY, + ProgressNotifyParam: PVOID, +}} +pub type PSP_DETECTDEVICE_PARAMS = *mut SP_DETECTDEVICE_PARAMS; +pub const MAX_INSTALLWIZARD_DYNAPAGES: usize = 20; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INSTALLWIZARD_DATA { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Flags: DWORD, + DynamicPages: [HPROPSHEETPAGE; MAX_INSTALLWIZARD_DYNAPAGES], + NumDynamicPages: DWORD, + DynamicPageFlags: DWORD, + PrivateFlags: DWORD, + PrivateData: LPARAM, + hwndWizardDlg: HWND, +}} +pub type PSP_INSTALLWIZARD_DATA = *mut SP_INSTALLWIZARD_DATA; +pub const NDW_INSTALLFLAG_DIDFACTDEFS: DWORD = 0x00000001; +pub const NDW_INSTALLFLAG_HARDWAREALLREADYIN: DWORD = 0x00000002; +pub const NDW_INSTALLFLAG_NEEDRESTART: DWORD = DI_NEEDRESTART; +pub const NDW_INSTALLFLAG_NEEDREBOOT: DWORD = DI_NEEDREBOOT; +pub const NDW_INSTALLFLAG_NEEDSHUTDOWN: DWORD = 0x00000200; +pub const NDW_INSTALLFLAG_EXPRESSINTRO: DWORD = 0x00000400; +pub const NDW_INSTALLFLAG_SKIPISDEVINSTALLED: DWORD = 0x00000800; +pub const NDW_INSTALLFLAG_NODETECTEDDEVS: DWORD = 0x00001000; +pub const NDW_INSTALLFLAG_INSTALLSPECIFIC: DWORD = 0x00002000; +pub const NDW_INSTALLFLAG_SKIPCLASSLIST: DWORD = 0x00004000; +pub const NDW_INSTALLFLAG_CI_PICKED_OEM: DWORD = 0x00008000; +pub const NDW_INSTALLFLAG_PCMCIAMODE: DWORD = 0x00010000; +pub const NDW_INSTALLFLAG_PCMCIADEVICE: DWORD = 0x00020000; +pub const NDW_INSTALLFLAG_USERCANCEL: DWORD = 0x00040000; +pub const NDW_INSTALLFLAG_KNOWNCLASS: DWORD = 0x00080000; +pub const DYNAWIZ_FLAG_PAGESADDED: DWORD = 0x00000001; +pub const DYNAWIZ_FLAG_ANALYZE_HANDLECONFLICT: DWORD = 0x00000008; +pub const DYNAWIZ_FLAG_INSTALLDET_NEXT: DWORD = 0x00000002; +pub const DYNAWIZ_FLAG_INSTALLDET_PREV: DWORD = 0x00000004; +pub const MIN_IDD_DYNAWIZ_RESOURCE_ID: c_int = 10000; +pub const MAX_IDD_DYNAWIZ_RESOURCE_ID: c_int = 11000; +pub const IDD_DYNAWIZ_FIRSTPAGE: c_int = 10000; +pub const IDD_DYNAWIZ_SELECT_PREVPAGE: c_int = 10001; +pub const IDD_DYNAWIZ_SELECT_NEXTPAGE: c_int = 10002; +pub const IDD_DYNAWIZ_ANALYZE_PREVPAGE: c_int = 10003; +pub const IDD_DYNAWIZ_ANALYZE_NEXTPAGE: c_int = 10004; +pub const IDD_DYNAWIZ_SELECTDEV_PAGE: c_int = 10009; +pub const IDD_DYNAWIZ_ANALYZEDEV_PAGE: c_int = 10010; +pub const IDD_DYNAWIZ_INSTALLDETECTEDDEVS_PAGE: c_int = 10011; +pub const IDD_DYNAWIZ_SELECTCLASS_PAGE: c_int = 10012; +pub const IDD_DYNAWIZ_INSTALLDETECTED_PREVPAGE: c_int = 10006; +pub const IDD_DYNAWIZ_INSTALLDETECTED_NEXTPAGE: c_int = 10007; +pub const IDD_DYNAWIZ_INSTALLDETECTED_NODEVS: c_int = 10008; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_NEWDEVICEWIZARD_DATA { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + Flags: DWORD, + DynamicPages: [HPROPSHEETPAGE; MAX_INSTALLWIZARD_DYNAPAGES], + NumDynamicPages: DWORD, + hwndWizardDlg: HWND, +}} +pub type PSP_NEWDEVICEWIZARD_DATA = *mut SP_NEWDEVICEWIZARD_DATA; +pub type SP_ADDPROPERTYPAGE_DATA = SP_NEWDEVICEWIZARD_DATA; +pub type PSP_ADDPROPERTYPAGE_DATA = PSP_NEWDEVICEWIZARD_DATA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_TROUBLESHOOTER_PARAMS_A { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + ChmFile: [CHAR; MAX_PATH], + HtmlTroubleShooter: [CHAR; MAX_PATH], +}} +pub type PSP_TROUBLESHOOTER_PARAMS_A = *mut SP_TROUBLESHOOTER_PARAMS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_TROUBLESHOOTER_PARAMS_W { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + ChmFile: [WCHAR; MAX_PATH], + HtmlTroubleShooter: [WCHAR; MAX_PATH], +}} +pub type PSP_TROUBLESHOOTER_PARAMS_W = *mut SP_TROUBLESHOOTER_PARAMS_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_POWERMESSAGEWAKE_PARAMS_A { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + PowerMessageWake: [CHAR; LINE_LEN * 2], +}} +pub type PSP_POWERMESSAGEWAKE_PARAMS_A = *mut SP_POWERMESSAGEWAKE_PARAMS_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_POWERMESSAGEWAKE_PARAMS_W { + ClassInstallHeader: SP_CLASSINSTALL_HEADER, + PowerMessageWake: [WCHAR; LINE_LEN * 2], +}} +pub type PSP_POWERMESSAGEWAKE_PARAMS_W = *mut SP_POWERMESSAGEWAKE_PARAMS_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DATA_V2_A { + cbSize: DWORD, + DriverType: DWORD, + Reserved: ULONG_PTR, + Description: [CHAR; LINE_LEN], + MfgName: [CHAR; LINE_LEN], + ProviderName: [CHAR; LINE_LEN], + DriverDate: FILETIME, + DriverVersion: DWORDLONG, +}} +pub type PSP_DRVINFO_DATA_V2_A = *mut SP_DRVINFO_DATA_V2_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DATA_V2_W { + cbSize: DWORD, + DriverType: DWORD, + Reserved: ULONG_PTR, + Description: [WCHAR; LINE_LEN], + MfgName: [WCHAR; LINE_LEN], + ProviderName: [WCHAR; LINE_LEN], + DriverDate: FILETIME, + DriverVersion: DWORDLONG, +}} +pub type PSP_DRVINFO_DATA_V2_W = *mut SP_DRVINFO_DATA_V2_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DATA_V1_A { + cbSize: DWORD, + DriverType: DWORD, + Reserved: ULONG_PTR, + Description: [CHAR; LINE_LEN], + MfgName: [CHAR; LINE_LEN], + ProviderName: [CHAR; LINE_LEN], +}} +pub type PSP_DRVINFO_DATA_V1_A = *mut SP_DRVINFO_DATA_V1_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DATA_V1_W { + cbSize: DWORD, + DriverType: DWORD, + Reserved: ULONG_PTR, + Description: [WCHAR; LINE_LEN], + MfgName: [WCHAR; LINE_LEN], + ProviderName: [WCHAR; LINE_LEN], +}} +pub type PSP_DRVINFO_DATA_V1_W = *mut SP_DRVINFO_DATA_V1_W; +pub type SP_DRVINFO_DATA_A = SP_DRVINFO_DATA_V2_A; +pub type PSP_DRVINFO_DATA_A = PSP_DRVINFO_DATA_V2_A; +pub type SP_DRVINFO_DATA_W = SP_DRVINFO_DATA_V2_W; +pub type PSP_DRVINFO_DATA_W = PSP_DRVINFO_DATA_V2_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DETAIL_DATA_A { + cbSize: DWORD, + InfDate: FILETIME, + CompatIDsOffset: DWORD, + CompatIDsLength: DWORD, + Reserved: ULONG_PTR, + SectionName: [CHAR; LINE_LEN], + InfFileName: [CHAR; MAX_PATH], + DrvDescription: [CHAR; LINE_LEN], + HardwareID: [CHAR; ANYSIZE_ARRAY], +}} +pub type PSP_DRVINFO_DETAIL_DATA_A = *mut SP_DRVINFO_DETAIL_DATA_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINFO_DETAIL_DATA_W { + cbSize: DWORD, + InfDate: FILETIME, + CompatIDsOffset: DWORD, + CompatIDsLength: DWORD, + Reserved: ULONG_PTR, + SectionName: [WCHAR; LINE_LEN], + InfFileName: [WCHAR; MAX_PATH], + DrvDescription: [WCHAR; LINE_LEN], + HardwareID: [WCHAR; ANYSIZE_ARRAY], +}} +pub type PSP_DRVINFO_DETAIL_DATA_W = *mut SP_DRVINFO_DETAIL_DATA_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_DRVINSTALL_PARAMS { + cbSize: DWORD, + Rank: DWORD, + Flags: DWORD, + PrivateData: DWORD_PTR, + Reserved: DWORD, +}} +pub type PSP_DRVINSTALL_PARAMS = *mut SP_DRVINSTALL_PARAMS; +pub const DNF_DUPDESC: DWORD = 0x00000001; +pub const DNF_OLDDRIVER: DWORD = 0x00000002; +pub const DNF_EXCLUDEFROMLIST: DWORD = 0x00000004; +pub const DNF_NODRIVER: DWORD = 0x00000008; +pub const DNF_LEGACYINF: DWORD = 0x00000010; +pub const DNF_CLASS_DRIVER: DWORD = 0x00000020; +pub const DNF_COMPATIBLE_DRIVER: DWORD = 0x00000040; +pub const DNF_INET_DRIVER: DWORD = 0x00000080; +pub const DNF_UNUSED1: DWORD = 0x00000100; +pub const DNF_UNUSED2: DWORD = 0x00000200; +pub const DNF_OLD_INET_DRIVER: DWORD = 0x00000400; +pub const DNF_BAD_DRIVER: DWORD = 0x00000800; +pub const DNF_DUPPROVIDER: DWORD = 0x00001000; +pub const DNF_INF_IS_SIGNED: DWORD = 0x00002000; +pub const DNF_OEM_F6_INF: DWORD = 0x00004000; +pub const DNF_DUPDRIVERVER: DWORD = 0x00008000; +pub const DNF_BASIC_DRIVER: DWORD = 0x00010000; +pub const DNF_AUTHENTICODE_SIGNED: DWORD = 0x00020000; +pub const DNF_INSTALLEDDRIVER: DWORD = 0x00040000; +pub const DNF_ALWAYSEXCLUDEFROMLIST: DWORD = 0x00080000; +pub const DNF_INBOX_DRIVER: DWORD = 0x00100000; +pub const DNF_REQUESTADDITIONALSOFTWARE: DWORD = 0x00200000; +pub const DNF_UNUSED_22: DWORD = 0x00400000; +pub const DNF_UNUSED_23: DWORD = 0x00800000; +pub const DNF_UNUSED_24: DWORD = 0x01000000; +pub const DNF_UNUSED_25: DWORD = 0x02000000; +pub const DNF_UNUSED_26: DWORD = 0x04000000; +pub const DNF_UNUSED_27: DWORD = 0x08000000; +pub const DNF_UNUSED_28: DWORD = 0x10000000; +pub const DNF_UNUSED_29: DWORD = 0x20000000; +pub const DNF_UNUSED_30: DWORD = 0x40000000; +pub const DNF_UNUSED_31: DWORD = 0x80000000; +pub const DRIVER_HARDWAREID_RANK: DWORD = 0x00000FFF; +pub const DRIVER_HARDWAREID_MASK: DWORD = 0x80000FFF; +pub const DRIVER_UNTRUSTED_RANK: DWORD = 0x80000000; +pub const DRIVER_W9X_SUSPECT_RANK: DWORD = 0xC0000000; +FN!{stdcall PSP_DETSIG_CMPPROC( + DeviceInfoSet: HDEVINFO, + NewDeviceData: PSP_DEVINFO_DATA, + ExistingDeviceData: PSP_DEVINFO_DATA, + CompareContext: PVOID, +) -> DWORD} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct COINSTALLER_CONTEXT_DATA { + PostProcessing: BOOL, + InstallResult: DWORD, + PrivateData: PVOID, +}} +pub type PCOINSTALLER_CONTEXT_DATA = *mut COINSTALLER_CONTEXT_DATA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_CLASSIMAGELIST_DATA { + cbSize: DWORD, + ImageList: HIMAGELIST, + Reserved: ULONG_PTR, +}} +pub type PSP_CLASSIMAGELIST_DATA = *mut SP_CLASSIMAGELIST_DATA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_PROPSHEETPAGE_REQUEST { + cbSize: DWORD, + PageRequested: DWORD, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, +}} +pub type PSP_PROPSHEETPAGE_REQUEST = *mut SP_PROPSHEETPAGE_REQUEST; +pub const SPPSR_SELECT_DEVICE_RESOURCES: DWORD = 1; +pub const SPPSR_ENUM_BASIC_DEVICE_PROPERTIES: DWORD = 2; +pub const SPPSR_ENUM_ADV_DEVICE_PROPERTIES: DWORD = 3; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_BACKUP_QUEUE_PARAMS_V2_A { + cbSize: DWORD, + FullInfPath: [CHAR; MAX_PATH], + FilenameOffset: INT, + ReinstallInstance: [CHAR; MAX_PATH], +}} +pub type PSP_BACKUP_QUEUE_PARAMS_V2_A = *mut SP_BACKUP_QUEUE_PARAMS_V2_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_BACKUP_QUEUE_PARAMS_V2_W { + cbSize: DWORD, + FullInfPath: [WCHAR; MAX_PATH], + FilenameOffset: INT, + ReinstallInstance: [WCHAR; MAX_PATH], +}} +pub type PSP_BACKUP_QUEUE_PARAMS_V2_W = *mut SP_BACKUP_QUEUE_PARAMS_V2_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_BACKUP_QUEUE_PARAMS_V1_A { + cbSize: DWORD, + FullInfPath: [CHAR; MAX_PATH], + FilenameOffset: INT, +}} +pub type PSP_BACKUP_QUEUE_PARAMS_V1_A = *mut SP_BACKUP_QUEUE_PARAMS_V1_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_BACKUP_QUEUE_PARAMS_V1_W { + cbSize: DWORD, + FullInfPath: [WCHAR; MAX_PATH], + FilenameOffset: INT, +}} +pub type PSP_BACKUP_QUEUE_PARAMS_V1_W = *mut SP_BACKUP_QUEUE_PARAMS_V1_W; +pub type SP_BACKUP_QUEUE_PARAMS_A = SP_BACKUP_QUEUE_PARAMS_V2_A; +pub type PSP_BACKUP_QUEUE_PARAMS_A = PSP_BACKUP_QUEUE_PARAMS_V2_A; +pub type SP_BACKUP_QUEUE_PARAMS_W = SP_BACKUP_QUEUE_PARAMS_V2_W; +pub type PSP_BACKUP_QUEUE_PARAMS_W = PSP_BACKUP_QUEUE_PARAMS_V2_W; +pub const ERROR_EXPECTED_SECTION_NAME: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0; +pub const ERROR_BAD_SECTION_NAME_LINE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 1; +pub const ERROR_SECTION_NAME_TOO_LONG: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 2; +pub const ERROR_GENERAL_SYNTAX: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 3; +pub const ERROR_WRONG_INF_STYLE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x100; +pub const ERROR_SECTION_NOT_FOUND: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x101; +pub const ERROR_LINE_NOT_FOUND: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x102; +pub const ERROR_NO_BACKUP: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x103; +pub const ERROR_NO_ASSOCIATED_CLASS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x200; +pub const ERROR_CLASS_MISMATCH: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x201; +pub const ERROR_DUPLICATE_FOUND: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x202; +pub const ERROR_NO_DRIVER_SELECTED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x203; +pub const ERROR_KEY_DOES_NOT_EXIST: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x204; +pub const ERROR_INVALID_DEVINST_NAME: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x205; +pub const ERROR_INVALID_CLASS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x206; +pub const ERROR_DEVINST_ALREADY_EXISTS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x207; +pub const ERROR_DEVINFO_NOT_REGISTERED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x208; +pub const ERROR_INVALID_REG_PROPERTY: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x209; +pub const ERROR_NO_INF: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20A; +pub const ERROR_NO_SUCH_DEVINST: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20B; +pub const ERROR_CANT_LOAD_CLASS_ICON: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x20C; +pub const ERROR_INVALID_CLASS_INSTALLER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x20D; +pub const ERROR_DI_DO_DEFAULT: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20E; +pub const ERROR_DI_NOFILECOPY: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x20F; +pub const ERROR_INVALID_HWPROFILE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x210; +pub const ERROR_NO_DEVICE_SELECTED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x211; +pub const ERROR_DEVINFO_LIST_LOCKED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x212; +pub const ERROR_DEVINFO_DATA_LOCKED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x213; +pub const ERROR_DI_BAD_PATH: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x214; +pub const ERROR_NO_CLASSINSTALL_PARAMS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x215; +pub const ERROR_FILEQUEUE_LOCKED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x216; +pub const ERROR_BAD_SERVICE_INSTALLSECT: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x217; +pub const ERROR_NO_CLASS_DRIVER_LIST: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x218; +pub const ERROR_NO_ASSOCIATED_SERVICE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x219; +pub const ERROR_NO_DEFAULT_DEVICE_INTERFACE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21A; +pub const ERROR_DEVICE_INTERFACE_ACTIVE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21B; +pub const ERROR_DEVICE_INTERFACE_REMOVED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21C; +pub const ERROR_BAD_INTERFACE_INSTALLSECT: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21D; +pub const ERROR_NO_SUCH_INTERFACE_CLASS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21E; +pub const ERROR_INVALID_REFERENCE_STRING: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x21F; +pub const ERROR_INVALID_MACHINENAME: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x220; +pub const ERROR_REMOTE_COMM_FAILURE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x221; +pub const ERROR_MACHINE_UNAVAILABLE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x222; +pub const ERROR_NO_CONFIGMGR_SERVICES: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x223; +pub const ERROR_INVALID_PROPPAGE_PROVIDER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x224; +pub const ERROR_NO_SUCH_DEVICE_INTERFACE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x225; +pub const ERROR_DI_POSTPROCESSING_REQUIRED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x226; +pub const ERROR_INVALID_COINSTALLER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x227; +pub const ERROR_NO_COMPAT_DRIVERS: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x228; +pub const ERROR_NO_DEVICE_ICON: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x229; +pub const ERROR_INVALID_INF_LOGCONFIG: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x22A; +pub const ERROR_DI_DONT_INSTALL: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22B; +pub const ERROR_INVALID_FILTER_DRIVER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x22C; +pub const ERROR_NON_WINDOWS_NT_DRIVER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x22D; +pub const ERROR_NON_WINDOWS_DRIVER: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x22E; +pub const ERROR_NO_CATALOG_FOR_OEM_INF: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x22F; +pub const ERROR_DEVINSTALL_QUEUE_NONNATIVE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x230; +pub const ERROR_NOT_DISABLEABLE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x231; +pub const ERROR_CANT_REMOVE_DEVINST: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x232; +pub const ERROR_INVALID_TARGET: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x233; +pub const ERROR_DRIVER_NONNATIVE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x234; +pub const ERROR_IN_WOW64: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x235; +pub const ERROR_SET_SYSTEM_RESTORE_POINT: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x236; +pub const ERROR_SCE_DISABLED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x238; +pub const ERROR_UNKNOWN_EXCEPTION: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x239; +pub const ERROR_PNP_REGISTRY_ERROR: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x23A; +pub const ERROR_REMOTE_REQUEST_UNSUPPORTED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x23B; +pub const ERROR_NOT_AN_INSTALLED_OEM_INF: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x23C; +pub const ERROR_INF_IN_USE_BY_DEVICES: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x23D; +pub const ERROR_DI_FUNCTION_OBSOLETE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x23E; +pub const ERROR_NO_AUTHENTICODE_CATALOG: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x23F; +pub const ERROR_AUTHENTICODE_DISALLOWED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x240; +pub const ERROR_AUTHENTICODE_TRUSTED_PUBLISHER: DWORD = APPLICATION_ERROR_MASK + | ERROR_SEVERITY_ERROR | 0x241; +pub const ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED: DWORD = APPLICATION_ERROR_MASK + | ERROR_SEVERITY_ERROR | 0x242; +pub const ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED: DWORD = APPLICATION_ERROR_MASK + | ERROR_SEVERITY_ERROR | 0x243; +pub const ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH: DWORD = APPLICATION_ERROR_MASK + | ERROR_SEVERITY_ERROR | 0x244; +pub const ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE: DWORD = APPLICATION_ERROR_MASK + | ERROR_SEVERITY_ERROR | 0x245; +pub const ERROR_DEVICE_INSTALLER_NOT_READY: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x246; +pub const ERROR_DRIVER_STORE_ADD_FAILED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x247; +pub const ERROR_DEVICE_INSTALL_BLOCKED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x248; +pub const ERROR_DRIVER_INSTALL_BLOCKED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x249; +pub const ERROR_WRONG_INF_TYPE: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR | 0x24A; +pub const ERROR_FILE_HASH_NOT_IN_CATALOG: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x24B; +pub const ERROR_DRIVER_STORE_DELETE_FAILED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x24C; +pub const ERROR_UNRECOVERABLE_STACK_OVERFLOW: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x300; +pub const EXCEPTION_SPAPI_UNRECOVERABLE_STACK_OVERFLOW: DWORD = ERROR_UNRECOVERABLE_STACK_OVERFLOW; +pub const ERROR_NO_DEFAULT_INTERFACE_DEVICE: DWORD = ERROR_NO_DEFAULT_DEVICE_INTERFACE; +pub const ERROR_INTERFACE_DEVICE_ACTIVE: DWORD = ERROR_DEVICE_INTERFACE_ACTIVE; +pub const ERROR_INTERFACE_DEVICE_REMOVED: DWORD = ERROR_DEVICE_INTERFACE_REMOVED; +pub const ERROR_NO_SUCH_INTERFACE_DEVICE: DWORD = ERROR_NO_SUCH_DEVICE_INTERFACE; +pub const ERROR_NOT_INSTALLED: DWORD = APPLICATION_ERROR_MASK | ERROR_SEVERITY_ERROR + | 0x1000; +extern "system" { + pub fn SetupGetInfInformationA( + InfSpec: LPCVOID, + SearchControl: DWORD, + ReturnBuffer: PSP_INF_INFORMATION, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfInformationW( + InfSpec: LPCVOID, + SearchControl: DWORD, + ReturnBuffer: PSP_INF_INFORMATION, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub const INFINFO_INF_SPEC_IS_HINF: DWORD = 1; +pub const INFINFO_INF_NAME_IS_ABSOLUTE: DWORD = 2; +pub const INFINFO_DEFAULT_SEARCH: DWORD = 3; +pub const INFINFO_REVERSE_DEFAULT_SEARCH: DWORD = 4; +pub const INFINFO_INF_PATH_LIST_SEARCH: DWORD = 5; +extern "system" { + pub fn SetupQueryInfFileInformationA( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQueryInfFileInformationW( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQueryInfOriginalFileInformationA( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + OriginalFileInfo: PSP_ORIGINAL_FILE_INFO_A, + ) -> BOOL; + pub fn SetupQueryInfOriginalFileInformationW( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + OriginalFileInfo: PSP_ORIGINAL_FILE_INFO_W, + ) -> BOOL; + pub fn SetupQueryInfVersionInformationA( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + Key: PCSTR, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQueryInfVersionInformationW( + InfInformation: PSP_INF_INFORMATION, + InfIndex: UINT, + Key: PCWSTR, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfDriverStoreLocationA( + FileName: PCSTR, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + LocaleName: PCSTR, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfDriverStoreLocationW( + FileName: PCWSTR, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + LocaleName: PCWSTR, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfPublishedNameA( + DriverStoreLocation: PCSTR, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfPublishedNameW( + DriverStoreLocation: PCWSTR, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfFileListA( + DirectoryPath: PCSTR, + InfStyle: DWORD, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetInfFileListW( + DirectoryPath: PCWSTR, + InfStyle: DWORD, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupOpenInfFileW( + FileName: PCWSTR, + InfClass: PCWSTR, + InfStyle: DWORD, + ErrorLine: PUINT, + ) -> HINF; + pub fn SetupOpenInfFileA( + FileName: PCSTR, + InfClass: PCSTR, + InfStyle: DWORD, + ErrorLine: PUINT, + ) -> HINF; + pub fn SetupOpenMasterInf() -> HINF; + pub fn SetupOpenAppendInfFileW( + FileName: PCWSTR, + InfHandle: HINF, + ErrorLine: PUINT, + ) -> BOOL; + pub fn SetupOpenAppendInfFileA( + FileName: PCSTR, + InfHandle: HINF, + ErrorLine: PUINT, + ) -> BOOL; + pub fn SetupCloseInfFile( + InfHandle: HINF, + ) -> (); + pub fn SetupFindFirstLineA( + InfHandle: HINF, + Section: PCSTR, + Key: PCSTR, + Context: PINFCONTEXT, + ) -> BOOL; + pub fn SetupFindFirstLineW( + InfHandle: HINF, + Section: PCWSTR, + Key: PCWSTR, + Context: PINFCONTEXT, + ) -> BOOL; + pub fn SetupFindNextLine( + ContextIn: PINFCONTEXT, + ContextOut: PINFCONTEXT, + ) -> BOOL; + pub fn SetupFindNextMatchLineA( + ContextIn: PINFCONTEXT, + Key: PCSTR, + ContextOut: PINFCONTEXT, + ) -> BOOL; + pub fn SetupFindNextMatchLineW( + ContextIn: PINFCONTEXT, + Key: PCWSTR, + ContextOut: PINFCONTEXT, + ) -> BOOL; + pub fn SetupGetLineByIndexA( + InfHandle: HINF, + Section: PCSTR, + Index: DWORD, + Context: PINFCONTEXT, + ) -> BOOL; + pub fn SetupGetLineByIndexW( + InfHandle: HINF, + Section: PCWSTR, + Index: DWORD, + Context: PINFCONTEXT, + ) -> BOOL; + pub fn SetupGetLineCountA( + InfHandle: HINF, + Section: PCSTR, + ) -> LONG; + pub fn SetupGetLineCountW( + InfHandle: HINF, + Section: PCWSTR, + ) -> LONG; + pub fn SetupGetLineTextA( + Context: PINFCONTEXT, + InfHandle: HINF, + Section: PCSTR, + Key: PCSTR, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + ReturnBufferSize: PDWORD, + ) -> BOOL; + pub fn SetupGetLineTextW( + Context: PINFCONTEXT, + InfHandle: HINF, + Section: PCWSTR, + Key: PCWSTR, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + ReturnBufferSize: PDWORD, + ) -> BOOL; + pub fn SetupGetFieldCount( + Context: PINFCONTEXT, + ) -> DWORD; + pub fn SetupGetStringFieldA( + Context: PINFCONTEXT, + FieldIndex: DWORD, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetStringFieldW( + Context: PINFCONTEXT, + FieldIndex: DWORD, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetIntField( + Context: PINFCONTEXT, + FieldIndex: DWORD, + IntegerValue: PINT, + ) -> BOOL; + pub fn SetupGetMultiSzFieldA( + Context: PINFCONTEXT, + FieldIndex: DWORD, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: LPDWORD, + ) -> BOOL; + pub fn SetupGetMultiSzFieldW( + Context: PINFCONTEXT, + FieldIndex: DWORD, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: LPDWORD, + ) -> BOOL; + pub fn SetupGetBinaryField( + Context: PINFCONTEXT, + FieldIndex: DWORD, + ReturnBuffer: PBYTE, + ReturnBufferSize: DWORD, + RequiredSize: LPDWORD, + ) -> BOOL; + pub fn SetupGetFileCompressionInfoA( + SourceFileName: PCSTR, + ActualSourceFileName: *mut PSTR, + SourceFileSize: PDWORD, + TargetFileSize: PDWORD, + CompressionType: PUINT, + ) -> DWORD; + pub fn SetupGetFileCompressionInfoW( + SourceFileName: PCWSTR, + ActualSourceFileName: *mut PWSTR, + SourceFileSize: PDWORD, + TargetFileSize: PDWORD, + CompressionType: PUINT, + ) -> DWORD; + pub fn SetupGetFileCompressionInfoExA( + SourceFileName: PCSTR, + ActualSourceFileNameBuffer: PSTR, + ActualSourceFileNameBufferLen: DWORD, + RequiredBufferLen: PDWORD, + SourceFileSize: PDWORD, + TargetFileSize: PDWORD, + CompressionType: PUINT, + ) -> BOOL; + pub fn SetupGetFileCompressionInfoExW( + SourceFileName: PCWSTR, + ActualSourceFileNameBuffer: PWSTR, + ActualSourceFileNameBufferLen: DWORD, + RequiredBufferLen: PDWORD, + SourceFileSize: PDWORD, + TargetFileSize: PDWORD, + CompressionType: PUINT, + ) -> BOOL; +} +pub const FILE_COMPRESSION_NONE: UINT = 0; +pub const FILE_COMPRESSION_WINLZA: UINT = 1; +pub const FILE_COMPRESSION_MSZIP: UINT = 2; +pub const FILE_COMPRESSION_NTCAB: UINT = 3; +extern "system" { + pub fn SetupDecompressOrCopyFileA( + SourceFileName: PCSTR, + TargetFileName: PCSTR, + CompressionType: PUINT, + ) -> DWORD; + pub fn SetupDecompressOrCopyFileW( + SourceFileName: PCWSTR, + TargetFileName: PCWSTR, + CompressionType: PUINT, + ) -> DWORD; + pub fn SetupGetSourceFileLocationA( + InfHandle: HINF, + InfContext: PINFCONTEXT, + FileName: PCSTR, + SourceId: PUINT, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetSourceFileLocationW( + InfHandle: HINF, + InfContext: PINFCONTEXT, + FileName: PCWSTR, + SourceId: PUINT, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetSourceFileSizeA( + InfHandle: HINF, + InfContext: PINFCONTEXT, + FileName: PCSTR, + Section: PCSTR, + FileSize: PDWORD, + RoundingFactor: UINT, + ) -> BOOL; + pub fn SetupGetSourceFileSizeW( + InfHandle: HINF, + InfContext: PINFCONTEXT, + FileName: PCWSTR, + Section: PCWSTR, + FileSize: PDWORD, + RoundingFactor: UINT, + ) -> BOOL; + pub fn SetupGetTargetPathA( + InfHandle: HINF, + InfContext: PINFCONTEXT, + Section: PCSTR, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetTargetPathW( + InfHandle: HINF, + InfContext: PINFCONTEXT, + Section: PCWSTR, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub const SRCLIST_TEMPORARY: DWORD = 0x00000001; +pub const SRCLIST_NOBROWSE: DWORD = 0x00000002; +pub const SRCLIST_SYSTEM: DWORD = 0x00000010; +pub const SRCLIST_USER: DWORD = 0x00000020; +pub const SRCLIST_SYSIFADMIN: DWORD = 0x00000040; +pub const SRCLIST_SUBDIRS: DWORD = 0x00000100; +pub const SRCLIST_APPEND: DWORD = 0x00000200; +pub const SRCLIST_NOSTRIPPLATFORM: DWORD = 0x00000400; +extern "system" { + pub fn SetupSetSourceListA( + Flags: DWORD, + SourceList: *mut PCSTR, + SourceCount: UINT, + ) -> BOOL; + pub fn SetupSetSourceListW( + Flags: DWORD, + SourceList: *mut PCWSTR, + SourceCount: UINT, + ) -> BOOL; + pub fn SetupCancelTemporarySourceList() -> BOOL; + pub fn SetupAddToSourceListA( + Flags: DWORD, + Source: PCSTR, + ) -> BOOL; + pub fn SetupAddToSourceListW( + Flags: DWORD, + Source: PCWSTR, + ) -> BOOL; + pub fn SetupRemoveFromSourceListA( + Flags: DWORD, + Source: PCSTR, + ) -> BOOL; + pub fn SetupRemoveFromSourceListW( + Flags: DWORD, + Source: PCWSTR, + ) -> BOOL; + pub fn SetupQuerySourceListA( + Flags: DWORD, + List: *mut *mut PCSTR, + Count: PUINT, + ) -> BOOL; + pub fn SetupQuerySourceListW( + Flags: DWORD, + List: *mut *mut PCWSTR, + Count: PUINT, + ) -> BOOL; + pub fn SetupFreeSourceListA( + List: *mut *mut PCSTR, + Count: UINT, + ) -> BOOL; + pub fn SetupFreeSourceListW( + List: *mut *mut PCWSTR, + Count: UINT, + ) -> BOOL; + pub fn SetupPromptForDiskA( + hwndParent: HWND, + DialogTitle: PCSTR, + DiskName: PCSTR, + PathToSource: PCSTR, + FileSought: PCSTR, + TagFile: PCSTR, + DiskPromptStyle: DWORD, + PathBuffer: PSTR, + PathBufferSize: DWORD, + PathRequiredSize: PDWORD, + ) -> UINT; + pub fn SetupPromptForDiskW( + hwndParent: HWND, + DialogTitle: PCWSTR, + DiskName: PCWSTR, + PathToSource: PCWSTR, + FileSought: PCWSTR, + TagFile: PCWSTR, + DiskPromptStyle: DWORD, + PathBuffer: PWSTR, + PathBufferSize: DWORD, + PathRequiredSize: PDWORD, + ) -> UINT; + pub fn SetupCopyErrorA( + hwndParent: HWND, + DialogTitle: PCSTR, + DiskName: PCSTR, + PathToSource: PCSTR, + SourceFile: PCSTR, + TargetPathFile: PCSTR, + Win32ErrorCode: UINT, + Style: DWORD, + PathBuffer: PSTR, + PathBufferSize: DWORD, + PathRequiredSize: PDWORD, + ) -> UINT; + pub fn SetupCopyErrorW( + hwndParent: HWND, + DialogTitle: PCWSTR, + DiskName: PCWSTR, + PathToSource: PCWSTR, + SourceFile: PCWSTR, + TargetPathFile: PCWSTR, + Win32ErrorCode: UINT, + Style: DWORD, + PathBuffer: PWSTR, + PathBufferSize: DWORD, + PathRequiredSize: PDWORD, + ) -> UINT; + pub fn SetupRenameErrorA( + hwndParent: HWND, + DialogTitle: PCSTR, + SourceFile: PCSTR, + TargetFile: PCSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; + pub fn SetupRenameErrorW( + hwndParent: HWND, + DialogTitle: PCWSTR, + SourceFile: PCWSTR, + TargetFile: PCWSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; + pub fn SetupDeleteErrorA( + hwndParent: HWND, + DialogTitle: PCSTR, + File: PCSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; + pub fn SetupDeleteErrorW( + hwndParent: HWND, + DialogTitle: PCWSTR, + File: PCWSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; + pub fn SetupBackupErrorA( + hwndParent: HWND, + DialogTitle: PCSTR, + SourceFile: PCSTR, + TargetFile: PCSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; + pub fn SetupBackupErrorW( + hwndParent: HWND, + DialogTitle: PCWSTR, + SourceFile: PCWSTR, + TargetFile: PCWSTR, + Win32ErrorCode: UINT, + Style: DWORD, + ) -> UINT; +} +pub const IDF_NOBROWSE: DWORD = 0x00000001; +pub const IDF_NOSKIP: DWORD = 0x00000002; +pub const IDF_NODETAILS: DWORD = 0x00000004; +pub const IDF_NOCOMPRESSED: DWORD = 0x00000008; +pub const IDF_CHECKFIRST: DWORD = 0x00000100; +pub const IDF_NOBEEP: DWORD = 0x00000200; +pub const IDF_NOFOREGROUND: DWORD = 0x00000400; +pub const IDF_WARNIFSKIP: DWORD = 0x00000800; +pub const IDF_NOREMOVABLEMEDIAPROMPT: DWORD = 0x00001000; +pub const IDF_USEDISKNAMEASPROMPT: DWORD = 0x00002000; +pub const IDF_OEMDISK: DWORD = 0x80000000; +pub const DPROMPT_SUCCESS: UINT = 0; +pub const DPROMPT_CANCEL: UINT = 1; +pub const DPROMPT_SKIPFILE: UINT = 2; +pub const DPROMPT_BUFFERTOOSMALL: UINT = 3; +pub const DPROMPT_OUTOFMEMORY: UINT = 4; +extern "system" { + pub fn SetupSetDirectoryIdA( + InfHandle: HINF, + Id: DWORD, + Directory: PCSTR, + ) -> BOOL; + pub fn SetupSetDirectoryIdW( + InfHandle: HINF, + Id: DWORD, + Directory: PCWSTR, + ) -> BOOL; + pub fn SetupSetDirectoryIdExA( + InfHandle: HINF, + Id: DWORD, + Directory: PCSTR, + Flags: DWORD, + Reserved1: DWORD, + Reserved2: PVOID, + ) -> BOOL; + pub fn SetupSetDirectoryIdExW( + InfHandle: HINF, + Id: DWORD, + Directory: PCWSTR, + Flags: DWORD, + Reserved1: DWORD, + Reserved2: PVOID, + ) -> BOOL; +} +pub const SETDIRID_NOT_FULL_PATH: DWORD = 0x00000001; +extern "system" { + pub fn SetupGetSourceInfoA( + InfHandle: HINF, + SourceId: UINT, + InfoDesired: UINT, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupGetSourceInfoW( + InfHandle: HINF, + SourceId: UINT, + InfoDesired: UINT, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub const SRCINFO_PATH: UINT = 1; +pub const SRCINFO_TAGFILE: UINT = 2; +pub const SRCINFO_DESCRIPTION: UINT = 3; +pub const SRCINFO_FLAGS: UINT = 4; +pub const SRCINFO_TAGFILE2: UINT = 4; +pub const SRC_FLAGS_CABFILE: UINT = 0x0010; +extern "system" { + pub fn SetupInstallFileA( + InfHandle: HINF, + InfContext: PINFCONTEXT, + SourceFile: PCSTR, + SourcePathRoot: PCSTR, + DestinationName: PCSTR, + CopyStyle: DWORD, + CopyMsgHandler: PSP_FILE_CALLBACK_A, + Context: PVOID, + ) -> BOOL; + pub fn SetupInstallFileW( + InfHandle: HINF, + InfContext: PINFCONTEXT, + SourceFile: PCWSTR, + SourcePathRoot: PCWSTR, + DestinationName: PCWSTR, + CopyStyle: DWORD, + CopyMsgHandler: PSP_FILE_CALLBACK_W, + Context: PVOID, + ) -> BOOL; + pub fn SetupInstallFileExA( + InfHandle: HINF, + InfContext: PINFCONTEXT, + SourceFile: PCSTR, + SourcePathRoot: PCSTR, + DestinationName: PCSTR, + CopyStyle: DWORD, + CopyMsgHandler: PSP_FILE_CALLBACK_A, + Context: PVOID, + FileWasInUse: PBOOL, + ) -> BOOL; + pub fn SetupInstallFileExW( + InfHandle: HINF, + InfContext: PINFCONTEXT, + SourceFile: PCWSTR, + SourcePathRoot: PCWSTR, + DestinationName: PCWSTR, + CopyStyle: DWORD, + CopyMsgHandler: PSP_FILE_CALLBACK_W, + Context: PVOID, + FileWasInUse: PBOOL, + ) -> BOOL; +} +pub const SP_COPY_DELETESOURCE: DWORD = 0x0000001; +pub const SP_COPY_REPLACEONLY: DWORD = 0x0000002; +pub const SP_COPY_NEWER: DWORD = 0x0000004; +pub const SP_COPY_NEWER_OR_SAME: DWORD = SP_COPY_NEWER; +pub const SP_COPY_NOOVERWRITE: DWORD = 0x0000008; +pub const SP_COPY_NODECOMP: DWORD = 0x0000010; +pub const SP_COPY_LANGUAGEAWARE: DWORD = 0x0000020; +pub const SP_COPY_SOURCE_ABSOLUTE: DWORD = 0x0000040; +pub const SP_COPY_SOURCEPATH_ABSOLUTE: DWORD = 0x0000080; +pub const SP_COPY_IN_USE_NEEDS_REBOOT: DWORD = 0x0000100; +pub const SP_COPY_FORCE_IN_USE: DWORD = 0x0000200; +pub const SP_COPY_NOSKIP: DWORD = 0x0000400; +pub const SP_FLAG_CABINETCONTINUATION: DWORD = 0x0000800; +pub const SP_COPY_FORCE_NOOVERWRITE: DWORD = 0x0001000; +pub const SP_COPY_FORCE_NEWER: DWORD = 0x0002000; +pub const SP_COPY_WARNIFSKIP: DWORD = 0x0004000; +pub const SP_COPY_NOBROWSE: DWORD = 0x0008000; +pub const SP_COPY_NEWER_ONLY: DWORD = 0x0010000; +pub const SP_COPY_RESERVED: DWORD = 0x0020000; +pub const SP_COPY_OEMINF_CATALOG_ONLY: DWORD = 0x0040000; +pub const SP_COPY_REPLACE_BOOT_FILE: DWORD = 0x0080000; +pub const SP_COPY_NOPRUNE: DWORD = 0x0100000; +pub const SP_COPY_OEM_F6_INF: DWORD = 0x0200000; +pub const SP_COPY_ALREADYDECOMP: DWORD = 0x0400000; +pub const SP_COPY_WINDOWS_SIGNED: DWORD = 0x1000000; +pub const SP_COPY_PNPLOCKED: DWORD = 0x2000000; +pub const SP_COPY_IN_USE_TRY_RENAME: DWORD = 0x4000000; +pub const SP_COPY_INBOX_INF: DWORD = 0x8000000; +pub const SP_COPY_HARDLINK: DWORD = 0x10000000; +pub const SP_BACKUP_BACKUPPASS: DWORD = 0x00000001; +pub const SP_BACKUP_DEMANDPASS: DWORD = 0x00000002; +pub const SP_BACKUP_SPECIAL: DWORD = 0x00000004; +pub const SP_BACKUP_BOOTFILE: DWORD = 0x00000008; +extern "system" { + pub fn SetupOpenFileQueue() -> HSPFILEQ; + pub fn SetupCloseFileQueue( + QueueHandle: HSPFILEQ, + ) -> BOOL; + pub fn SetupSetFileQueueAlternatePlatformA( + QueueHandle: HSPFILEQ, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + AlternateDefaultCatalogFile: PCSTR, + ) -> BOOL; + pub fn SetupSetFileQueueAlternatePlatformW( + QueueHandle: HSPFILEQ, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + AlternateDefaultCatalogFile: PCWSTR, + ) -> BOOL; + pub fn SetupSetPlatformPathOverrideA( + Override: PCSTR, + ) -> BOOL; + pub fn SetupSetPlatformPathOverrideW( + Override: PCWSTR, + ) -> BOOL; + pub fn SetupQueueCopyA( + QueueHandle: HSPFILEQ, + SourceRootPath: PCSTR, + SourcePath: PCSTR, + SourceFilename: PCSTR, + SourceDescription: PCSTR, + SourceTagfile: PCSTR, + TargetDirectory: PCSTR, + TargetFilename: PCSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueCopyW( + QueueHandle: HSPFILEQ, + SourceRootPath: PCWSTR, + SourcePath: PCWSTR, + SourceFilename: PCWSTR, + SourceDescription: PCWSTR, + SourceTagfile: PCWSTR, + TargetDirectory: PCWSTR, + TargetFilename: PCWSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueCopyIndirectA( + CopyParams: PSP_FILE_COPY_PARAMS_A, + ) -> BOOL; + pub fn SetupQueueCopyIndirectW( + CopyParams: PSP_FILE_COPY_PARAMS_W, + ) -> BOOL; + pub fn SetupQueueDefaultCopyA( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + SourceRootPath: PCSTR, + SourceFilename: PCSTR, + TargetFilename: PCSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueDefaultCopyW( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + SourceRootPath: PCWSTR, + SourceFilename: PCWSTR, + TargetFilename: PCWSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueCopySectionA( + QueueHandle: HSPFILEQ, + SourceRootPath: PCSTR, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueCopySectionW( + QueueHandle: HSPFILEQ, + SourceRootPath: PCWSTR, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCWSTR, + CopyStyle: DWORD, + ) -> BOOL; + pub fn SetupQueueDeleteA( + QueueHandle: HSPFILEQ, + PathPart1: PCSTR, + PathPart2: PCSTR, + ) -> BOOL; + pub fn SetupQueueDeleteW( + QueueHandle: HSPFILEQ, + PathPart1: PCWSTR, + PathPart2: PCWSTR, + ) -> BOOL; + pub fn SetupQueueDeleteSectionA( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCSTR, + ) -> BOOL; + pub fn SetupQueueDeleteSectionW( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCWSTR, + ) -> BOOL; + pub fn SetupQueueRenameA( + QueueHandle: HSPFILEQ, + SourcePath: PCSTR, + SourceFilename: PCSTR, + TargetPath: PCSTR, + TargetFilename: PCSTR, + ) -> BOOL; + pub fn SetupQueueRenameW( + QueueHandle: HSPFILEQ, + SourcePath: PCWSTR, + SourceFilename: PCWSTR, + TargetPath: PCWSTR, + TargetFilename: PCWSTR, + ) -> BOOL; + pub fn SetupQueueRenameSectionA( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCSTR, + ) -> BOOL; + pub fn SetupQueueRenameSectionW( + QueueHandle: HSPFILEQ, + InfHandle: HINF, + ListInfHandle: HINF, + Section: PCWSTR, + ) -> BOOL; + pub fn SetupCommitFileQueueA( + Owner: HWND, + QueueHandle: HSPFILEQ, + MsgHandler: PSP_FILE_CALLBACK_A, + Context: PVOID, + ) -> BOOL; + pub fn SetupCommitFileQueueW( + Owner: HWND, + QueueHandle: HSPFILEQ, + MsgHandler: PSP_FILE_CALLBACK_W, + Context: PVOID, + ) -> BOOL; + pub fn SetupScanFileQueueA( + FileQueue: HSPFILEQ, + Flags: DWORD, + Window: HWND, + CallbackRoutine: PSP_FILE_CALLBACK_A, + CallbackContext: PVOID, + Result: PDWORD, + ) -> BOOL; + pub fn SetupScanFileQueueW( + FileQueue: HSPFILEQ, + Flags: DWORD, + Window: HWND, + CallbackRoutine: PSP_FILE_CALLBACK_W, + CallbackContext: PVOID, + Result: PDWORD, + ) -> BOOL; +} +pub const SPQ_SCAN_FILE_PRESENCE: DWORD = 0x00000001; +pub const SPQ_SCAN_FILE_VALIDITY: DWORD = 0x00000002; +pub const SPQ_SCAN_USE_CALLBACK: DWORD = 0x00000004; +pub const SPQ_SCAN_USE_CALLBACKEX: DWORD = 0x00000008; +pub const SPQ_SCAN_INFORM_USER: DWORD = 0x00000010; +pub const SPQ_SCAN_PRUNE_COPY_QUEUE: DWORD = 0x00000020; +pub const SPQ_SCAN_USE_CALLBACK_SIGNERINFO: DWORD = 0x00000040; +pub const SPQ_SCAN_PRUNE_DELREN: DWORD = 0x00000080; +pub const SPQ_SCAN_FILE_PRESENCE_WITHOUT_SOURCE: DWORD = 0x00000100; +pub const SPQ_SCAN_FILE_COMPARISON: DWORD = 0x00000200; +pub const SPQ_SCAN_ACTIVATE_DRP: DWORD = 0x00000400; +pub const SPQ_DELAYED_COPY: DWORD = 0x00000001; +extern "system" { + pub fn SetupGetFileQueueCount( + FileQueue: HSPFILEQ, + SubQueueFileOp: UINT, + NumOperations: PUINT, + ) -> BOOL; + pub fn SetupGetFileQueueFlags( + FileQueue: HSPFILEQ, + Flags: PDWORD, + ) -> BOOL; + pub fn SetupSetFileQueueFlags( + FileQueue: HSPFILEQ, + FlagMask: DWORD, + Flags: DWORD, + ) -> BOOL; +} +pub const SPQ_FLAG_BACKUP_AWARE: DWORD = 0x00000001; +pub const SPQ_FLAG_ABORT_IF_UNSIGNED: DWORD = 0x00000002; +pub const SPQ_FLAG_FILES_MODIFIED: DWORD = 0x00000004; +pub const SPQ_FLAG_DO_SHUFFLEMOVE: DWORD = 0x00000008; +pub const SPQ_FLAG_VALID: DWORD = 0x0000000F; +pub const SPOST_NONE: DWORD = 0; +pub const SPOST_PATH: DWORD = 1; +pub const SPOST_URL: DWORD = 2; +pub const SPOST_MAX: DWORD = 3; +extern "system" { + pub fn SetupCopyOEMInfA( + SourceInfFileName: PCSTR, + OEMSourceMediaLocation: PCSTR, + OEMSourceMediaType: DWORD, + CopyStyle: DWORD, + DestinationInfFileName: PSTR, + DestinationInfFileNameSize: DWORD, + RequiredSize: PDWORD, + DestinationInfFileNameComponent: *mut PSTR, + ) -> BOOL; + pub fn SetupCopyOEMInfW( + SourceInfFileName: PCWSTR, + OEMSourceMediaLocation: PCWSTR, + OEMSourceMediaType: DWORD, + CopyStyle: DWORD, + DestinationInfFileName: PWSTR, + DestinationInfFileNameSize: DWORD, + RequiredSize: PDWORD, + DestinationInfFileNameComponent: *mut PWSTR, + ) -> BOOL; +} +pub const SUOI_FORCEDELETE: DWORD = 0x00000001; +pub const SUOI_INTERNAL1: DWORD = 0x00000002; +extern "system" { + pub fn SetupUninstallOEMInfA( + InfFileName: PCSTR, + Flags: DWORD, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupUninstallOEMInfW( + InfFileName: PCWSTR, + Flags: DWORD, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupUninstallNewlyCopiedInfs( + FileQueue: HSPFILEQ, + Flags: DWORD, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupCreateDiskSpaceListA( + Reserved1: PVOID, + Reserved2: DWORD, + Flags: UINT, + ) -> HDSKSPC; + pub fn SetupCreateDiskSpaceListW( + Reserved1: PVOID, + Reserved2: DWORD, + Flags: UINT, + ) -> HDSKSPC; +} +pub const SPDSL_IGNORE_DISK: UINT = 0x00000001; +pub const SPDSL_DISALLOW_NEGATIVE_ADJUST: UINT = 0x00000002; +extern "system" { + pub fn SetupDuplicateDiskSpaceListA( + DiskSpace: HDSKSPC, + Reserved1: PVOID, + Reserved2: DWORD, + Flags: UINT, + ) -> HDSKSPC; + pub fn SetupDuplicateDiskSpaceListW( + DiskSpace: HDSKSPC, + Reserved1: PVOID, + Reserved2: DWORD, + Flags: UINT, + ) -> HDSKSPC; + pub fn SetupDestroyDiskSpaceList( + DiskSpace: HDSKSPC, + ) -> BOOL; + pub fn SetupQueryDrivesInDiskSpaceListA( + DiskSpace: HDSKSPC, + ReturnBuffer: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQueryDrivesInDiskSpaceListW( + DiskSpace: HDSKSPC, + ReturnBuffer: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQuerySpaceRequiredOnDriveA( + DiskSpace: HDSKSPC, + DriveSpec: PCSTR, + SpaceRequired: *mut LONGLONG, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupQuerySpaceRequiredOnDriveW( + DiskSpace: HDSKSPC, + DriveSpec: PCWSTR, + SpaceRequired: *mut LONGLONG, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAdjustDiskSpaceListA( + DiskSpace: HDSKSPC, + DriveRoot: LPCSTR, + Amount: LONGLONG, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAdjustDiskSpaceListW( + DiskSpace: HDSKSPC, + DriveRoot: LPCWSTR, + Amount: LONGLONG, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddToDiskSpaceListA( + DiskSpace: HDSKSPC, + TargetFilespec: PCSTR, + FileSize: LONGLONG, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddToDiskSpaceListW( + DiskSpace: HDSKSPC, + TargetFilespec: PCWSTR, + FileSize: LONGLONG, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddSectionToDiskSpaceListA( + DiskSpace: HDSKSPC, + InfHandle: HINF, + ListInfHandle: HINF, + SectionName: PCSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddSectionToDiskSpaceListW( + DiskSpace: HDSKSPC, + InfHandle: HINF, + ListInfHandle: HINF, + SectionName: PCWSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddInstallSectionToDiskSpaceListA( + DiskSpace: HDSKSPC, + InfHandle: HINF, + LayoutInfHandle: HINF, + SectionName: PCSTR, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupAddInstallSectionToDiskSpaceListW( + DiskSpace: HDSKSPC, + InfHandle: HINF, + LayoutInfHandle: HINF, + SectionName: PCWSTR, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveFromDiskSpaceListA( + DiskSpace: HDSKSPC, + TargetFilespec: PCSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveFromDiskSpaceListW( + DiskSpace: HDSKSPC, + TargetFilespec: PCWSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveSectionFromDiskSpaceListA( + DiskSpace: HDSKSPC, + InfHandle: HINF, + ListInfHandle: HINF, + SectionName: PCSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveSectionFromDiskSpaceListW( + DiskSpace: HDSKSPC, + InfHandle: HINF, + ListInfHandle: HINF, + SectionName: PCWSTR, + Operation: UINT, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveInstallSectionFromDiskSpaceListA( + DiskSpace: HDSKSPC, + InfHandle: HINF, + LayoutInfHandle: HINF, + SectionName: PCSTR, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupRemoveInstallSectionFromDiskSpaceListW( + DiskSpace: HDSKSPC, + InfHandle: HINF, + LayoutInfHandle: HINF, + SectionName: PCWSTR, + Reserved1: PVOID, + Reserved2: UINT, + ) -> BOOL; + pub fn SetupIterateCabinetA( + CabinetFile: PCSTR, + Reserved: DWORD, + MsgHandler: PSP_FILE_CALLBACK_A, + Context: PVOID, + ) -> BOOL; + pub fn SetupIterateCabinetW( + CabinetFile: PCWSTR, + Reserved: DWORD, + MsgHandler: PSP_FILE_CALLBACK_W, + Context: PVOID, + ) -> BOOL; + pub fn SetupPromptReboot( + FileQueue: HSPFILEQ, + Owner: HWND, + ScanOnly: BOOL, + ) -> INT; +} +pub const SPFILEQ_FILE_IN_USE: INT = 0x00000001; +pub const SPFILEQ_REBOOT_RECOMMENDED: INT = 0x00000002; +pub const SPFILEQ_REBOOT_IN_PROGRESS: INT = 0x00000004; +extern "system" { + pub fn SetupInitDefaultQueueCallback( + OwnerWindow: HWND, + ) -> PVOID; + pub fn SetupInitDefaultQueueCallbackEx( + OwnerWindow: HWND, + AlternateProgressWindow: HWND, + ProgressMessage: UINT, + Reserved1: DWORD, + Reserved2: PVOID, + ) -> PVOID; + pub fn SetupTermDefaultQueueCallback( + Context: PVOID, + ) -> (); + pub fn SetupDefaultQueueCallbackA( + Context: PVOID, + Notification: UINT, + Param1: UINT_PTR, + Param2: UINT_PTR, + ) -> UINT; + pub fn SetupDefaultQueueCallbackW( + Context: PVOID, + Notification: UINT, + Param1: UINT_PTR, + Param2: UINT_PTR, + ) -> UINT; +} +pub const FLG_ADDREG_DELREG_BIT: DWORD = 0x00008000; +pub const FLG_ADDREG_BINVALUETYPE: DWORD = 0x00000001; +pub const FLG_ADDREG_NOCLOBBER: DWORD = 0x00000002; +pub const FLG_ADDREG_DELVAL: DWORD = 0x00000004; +pub const FLG_ADDREG_APPEND: DWORD = 0x00000008; +pub const FLG_ADDREG_KEYONLY: DWORD = 0x00000010; +pub const FLG_ADDREG_OVERWRITEONLY: DWORD = 0x00000020; +pub const FLG_ADDREG_64BITKEY: DWORD = 0x00001000; +pub const FLG_ADDREG_KEYONLY_COMMON: DWORD = 0x00002000; +pub const FLG_ADDREG_32BITKEY: DWORD = 0x00004000; +pub const FLG_ADDREG_TYPE_MASK: DWORD = 0xFFFF0000 | FLG_ADDREG_BINVALUETYPE; +pub const FLG_ADDREG_TYPE_SZ: DWORD = 0x00000000; +pub const FLG_ADDREG_TYPE_MULTI_SZ: DWORD = 0x00010000; +pub const FLG_ADDREG_TYPE_EXPAND_SZ: DWORD = 0x00020000; +pub const FLG_ADDREG_TYPE_BINARY: DWORD = 0x00000000 | FLG_ADDREG_BINVALUETYPE; +pub const FLG_ADDREG_TYPE_DWORD: DWORD = 0x00010000 | FLG_ADDREG_BINVALUETYPE; +pub const FLG_ADDREG_TYPE_NONE: DWORD = 0x00020000 | FLG_ADDREG_BINVALUETYPE; +pub const FLG_DELREG_VALUE: DWORD = 0x00000000; +pub const FLG_DELREG_TYPE_MASK: DWORD = FLG_ADDREG_TYPE_MASK; +pub const FLG_DELREG_TYPE_SZ: DWORD = FLG_ADDREG_TYPE_SZ; +pub const FLG_DELREG_TYPE_MULTI_SZ: DWORD = FLG_ADDREG_TYPE_MULTI_SZ; +pub const FLG_DELREG_TYPE_EXPAND_SZ: DWORD = FLG_ADDREG_TYPE_EXPAND_SZ; +pub const FLG_DELREG_TYPE_BINARY: DWORD = FLG_ADDREG_TYPE_BINARY; +pub const FLG_DELREG_TYPE_DWORD: DWORD = FLG_ADDREG_TYPE_DWORD; +pub const FLG_DELREG_TYPE_NONE: DWORD = FLG_ADDREG_TYPE_NONE; +pub const FLG_DELREG_64BITKEY: DWORD = FLG_ADDREG_64BITKEY; +pub const FLG_DELREG_KEYONLY_COMMON: DWORD = FLG_ADDREG_KEYONLY_COMMON; +pub const FLG_DELREG_32BITKEY: DWORD = FLG_ADDREG_32BITKEY; +pub const FLG_DELREG_OPERATION_MASK: DWORD = 0x000000FE; +pub const FLG_DELREG_MULTI_SZ_DELSTRING: DWORD = FLG_DELREG_TYPE_MULTI_SZ | FLG_ADDREG_DELREG_BIT + | 0x00000002; +pub const FLG_BITREG_CLEARBITS: DWORD = 0x00000000; +pub const FLG_BITREG_SETBITS: DWORD = 0x00000001; +pub const FLG_BITREG_64BITKEY: DWORD = 0x00001000; +pub const FLG_BITREG_32BITKEY: DWORD = 0x00004000; +pub const FLG_INI2REG_64BITKEY: DWORD = 0x00001000; +pub const FLG_INI2REG_32BITKEY: DWORD = 0x00004000; +pub const FLG_REGSVR_DLLREGISTER: DWORD = 0x00000001; +pub const FLG_REGSVR_DLLINSTALL: DWORD = 0x00000002; +pub const FLG_PROFITEM_CURRENTUSER: DWORD = 0x00000001; +pub const FLG_PROFITEM_DELETE: DWORD = 0x00000002; +pub const FLG_PROFITEM_GROUP: DWORD = 0x00000004; +pub const FLG_PROFITEM_CSIDL: DWORD = 0x00000008; +pub const FLG_ADDPROPERTY_NOCLOBBER: DWORD = 0x00000001; +pub const FLG_ADDPROPERTY_OVERWRITEONLY: DWORD = 0x00000002; +pub const FLG_ADDPROPERTY_APPEND: DWORD = 0x00000004; +pub const FLG_ADDPROPERTY_OR: DWORD = 0x00000008; +pub const FLG_ADDPROPERTY_AND: DWORD = 0x00000010; +pub const FLG_DELPROPERTY_MULTI_SZ_DELSTRING: DWORD = 0x00000001; +extern "system" { + pub fn SetupInstallFromInfSectionA( + Owner: HWND, + InfHandle: HINF, + SectionName: PCSTR, + Flags: UINT, + RelativeKeyRoot: HKEY, + SourceRootPath: PCSTR, + CopyFlags: UINT, + MsgHandler: PSP_FILE_CALLBACK_A, + Context: PVOID, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupInstallFromInfSectionW( + Owner: HWND, + InfHandle: HINF, + SectionName: PCWSTR, + Flags: UINT, + RelativeKeyRoot: HKEY, + SourceRootPath: PCWSTR, + CopyFlags: UINT, + MsgHandler: PSP_FILE_CALLBACK_W, + Context: PVOID, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; +} +pub const SPINST_LOGCONFIG: UINT = 0x00000001; +pub const SPINST_INIFILES: UINT = 0x00000002; +pub const SPINST_REGISTRY: UINT = 0x00000004; +pub const SPINST_INI2REG: UINT = 0x00000008; +pub const SPINST_FILES: UINT = 0x00000010; +pub const SPINST_BITREG: UINT = 0x00000020; +pub const SPINST_REGSVR: UINT = 0x00000040; +pub const SPINST_UNREGSVR: UINT = 0x00000080; +pub const SPINST_PROFILEITEMS: UINT = 0x00000100; +pub const SPINST_COPYINF: UINT = 0x00000200; +pub const SPINST_PROPERTIES: UINT = 0x00000400; +pub const SPINST_ALL: UINT = 0x000007ff; +pub const SPINST_SINGLESECTION: UINT = 0x00010000; +pub const SPINST_LOGCONFIG_IS_FORCED: UINT = 0x00020000; +pub const SPINST_LOGCONFIGS_ARE_OVERRIDES: UINT = 0x00040000; +pub const SPINST_REGISTERCALLBACKAWARE: UINT = 0x00080000; +pub const SPINST_DEVICEINSTALL: UINT = 0x00100000; +extern "system" { + pub fn SetupInstallFilesFromInfSectionA( + InfHandle: HINF, + LayoutInfHandle: HINF, + FileQueue: HSPFILEQ, + SectionName: PCSTR, + SourceRootPath: PCSTR, + CopyFlags: UINT, + ) -> BOOL; + pub fn SetupInstallFilesFromInfSectionW( + InfHandle: HINF, + LayoutInfHandle: HINF, + FileQueue: HSPFILEQ, + SectionName: PCWSTR, + SourceRootPath: PCWSTR, + CopyFlags: UINT, + ) -> BOOL; +} +pub const SPSVCINST_TAGTOFRONT: DWORD = 0x00000001; +pub const SPSVCINST_ASSOCSERVICE: DWORD = 0x00000002; +pub const SPSVCINST_DELETEEVENTLOGENTRY: DWORD = 0x00000004; +pub const SPSVCINST_NOCLOBBER_DISPLAYNAME: DWORD = 0x00000008; +pub const SPSVCINST_NOCLOBBER_STARTTYPE: DWORD = 0x00000010; +pub const SPSVCINST_NOCLOBBER_ERRORCONTROL: DWORD = 0x00000020; +pub const SPSVCINST_NOCLOBBER_LOADORDERGROUP: DWORD = 0x00000040; +pub const SPSVCINST_NOCLOBBER_DEPENDENCIES: DWORD = 0x00000080; +pub const SPSVCINST_NOCLOBBER_DESCRIPTION: DWORD = 0x00000100; +pub const SPSVCINST_STOPSERVICE: DWORD = 0x00000200; +pub const SPSVCINST_CLOBBER_SECURITY: DWORD = 0x00000400; +pub const SPSVCINST_STARTSERVICE: DWORD = 0x00000800; +pub const SPSVCINST_NOCLOBBER_REQUIREDPRIVILEGES: DWORD = 0x00001000; +extern "system" { + pub fn SetupInstallServicesFromInfSectionA( + InfHandle: HINF, + SectionName: PCSTR, + Flags: DWORD, + ) -> BOOL; + pub fn SetupInstallServicesFromInfSectionW( + InfHandle: HINF, + SectionName: PCWSTR, + Flags: DWORD, + ) -> BOOL; + pub fn SetupInstallServicesFromInfSectionExA( + InfHandle: HINF, + SectionName: PCSTR, + Flags: DWORD, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Reserved1: PVOID, + Reserved2: PVOID, + ) -> BOOL; + pub fn SetupInstallServicesFromInfSectionExW( + InfHandle: HINF, + SectionName: PCWSTR, + Flags: DWORD, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Reserved1: PVOID, + Reserved2: PVOID, + ) -> BOOL; + pub fn InstallHinfSectionA( + Window: HWND, + ModuleHandle: HINSTANCE, + CommandLine: PCSTR, + ShowCommand: INT, + ) -> (); + pub fn InstallHinfSectionW( + Window: HWND, + ModuleHandle: HINSTANCE, + CommandLine: PCWSTR, + ShowCommand: INT, + ) -> (); +} +pub type HSPFILELOG = PVOID; +extern "system" { + pub fn SetupInitializeFileLogA( + LogFileName: PCSTR, + Flags: DWORD, + ) -> HSPFILELOG; + pub fn SetupInitializeFileLogW( + LogFileName: PCWSTR, + Flags: DWORD, + ) -> HSPFILELOG; +} +pub const SPFILELOG_SYSTEMLOG: DWORD = 0x00000001; +pub const SPFILELOG_FORCENEW: DWORD = 0x00000002; +pub const SPFILELOG_QUERYONLY: DWORD = 0x00000004; +extern "system" { + pub fn SetupTerminateFileLog( + FileLogHandle: HSPFILELOG, + ) -> BOOL; + pub fn SetupLogFileA( + FileLogHandle: HSPFILELOG, + LogSectionName: PCSTR, + SourceFilename: PCSTR, + TargetFilename: PCSTR, + Checksum: DWORD, + DiskTagfile: PCSTR, + DiskDescription: PCSTR, + OtherInfo: PCSTR, + Flags: DWORD, + ) -> BOOL; + pub fn SetupLogFileW( + FileLogHandle: HSPFILELOG, + LogSectionName: PCWSTR, + SourceFilename: PCWSTR, + TargetFilename: PCWSTR, + Checksum: DWORD, + DiskTagfile: PCWSTR, + DiskDescription: PCWSTR, + OtherInfo: PCWSTR, + Flags: DWORD, + ) -> BOOL; +} +pub const SPFILELOG_OEMFILE: DWORD = 0x00000001; +extern "system" { + pub fn SetupRemoveFileLogEntryA( + FileLogHandle: HSPFILELOG, + LogSectionName: PCSTR, + TargetFilename: PCSTR, + ) -> BOOL; + pub fn SetupRemoveFileLogEntryW( + FileLogHandle: HSPFILELOG, + LogSectionName: PCWSTR, + TargetFilename: PCWSTR, + ) -> BOOL; +} +ENUM!{enum SetupFileLogInfo { + SetupFileLogSourceFilename, + SetupFileLogChecksum, + SetupFileLogDiskTagfile, + SetupFileLogDiskDescription, + SetupFileLogOtherInfo, + SetupFileLogMax, +}} +extern "system" { + pub fn SetupQueryFileLogA( + FileLogHandle: HSPFILELOG, + LogSectionName: PCSTR, + TargetFilename: PCSTR, + DesiredInfo: SetupFileLogInfo, + DataOut: PSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupQueryFileLogW( + FileLogHandle: HSPFILELOG, + LogSectionName: PCWSTR, + TargetFilename: PCWSTR, + DesiredInfo: SetupFileLogInfo, + DataOut: PWSTR, + ReturnBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub type LogSeverity = DWORD; +pub const LogSevInformation: LogSeverity = 0x00000000; +pub const LogSevWarning: LogSeverity = 0x00000001; +pub const LogSevError: LogSeverity = 0x00000002; +pub const LogSevFatalError: LogSeverity = 0x00000003; +pub const LogSevMaximum: LogSeverity = 0x00000004; +extern "system" { + pub fn SetupOpenLog( + Erase: BOOL, + ) -> BOOL; + pub fn SetupLogErrorA( + MessageString: LPCSTR, + Severity: LogSeverity, + ) -> BOOL; + pub fn SetupLogErrorW( + MessageString: LPCWSTR, + Severity: LogSeverity, + ) -> BOOL; + pub fn SetupCloseLog() -> (); + pub fn SetupGetThreadLogToken() -> SP_LOG_TOKEN; + pub fn SetupSetThreadLogToken( + LogToken: SP_LOG_TOKEN, + ) -> (); +} +//pub fn SetupWriteTextLog() -> (); +//pub fn SetupWriteTextLogError() -> (); +extern "system" { + pub fn SetupWriteTextLogInfLine( + LogToken: SP_LOG_TOKEN, + Flags: DWORD, + InfHandle: HINF, + Context: PINFCONTEXT, + ) -> (); + pub fn SetupGetBackupInformationA( + QueueHandle: HSPFILEQ, + BackupParams: PSP_BACKUP_QUEUE_PARAMS_A, + ) -> BOOL; + pub fn SetupGetBackupInformationW( + QueueHandle: HSPFILEQ, + BackupParams: PSP_BACKUP_QUEUE_PARAMS_W, + ) -> BOOL; + pub fn SetupPrepareQueueForRestoreA( + QueueHandle: HSPFILEQ, + BackupPath: PCSTR, + RestoreFlags: DWORD, + ) -> BOOL; + pub fn SetupPrepareQueueForRestoreW( + QueueHandle: HSPFILEQ, + BackupPath: PCWSTR, + RestoreFlags: DWORD, + ) -> BOOL; + pub fn SetupSetNonInteractiveMode( + NonInteractiveFlag: BOOL, + ) -> BOOL; + pub fn SetupGetNonInteractiveMode() -> BOOL; + pub fn SetupDiCreateDeviceInfoList( + ClassGuid: *const GUID, + hwndParent: HWND, + ) -> HDEVINFO; + pub fn SetupDiCreateDeviceInfoListExA( + ClassGuid: *const GUID, + hwndParent: HWND, + MachineName: PCSTR, + Reserved: PVOID, + ) -> HDEVINFO; + pub fn SetupDiCreateDeviceInfoListExW( + ClassGuid: *const GUID, + hwndParent: HWND, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> HDEVINFO; + pub fn SetupDiGetDeviceInfoListClass( + DeviceInfoSet: HDEVINFO, + ClassGuid: LPGUID, + ) -> BOOL; + pub fn SetupDiGetDeviceInfoListDetailA( + DeviceInfoSet: HDEVINFO, + DeviceInfoSetDetailData: PSP_DEVINFO_LIST_DETAIL_DATA_A, + ) -> BOOL; + pub fn SetupDiGetDeviceInfoListDetailW( + DeviceInfoSet: HDEVINFO, + DeviceInfoSetDetailData: PSP_DEVINFO_LIST_DETAIL_DATA_W, + ) -> BOOL; +} +pub const DICD_GENERATE_ID: DWORD = 0x00000001; +pub const DICD_INHERIT_CLASSDRVS: DWORD = 0x00000002; +extern "system" { + pub fn SetupDiCreateDeviceInfoA( + DeviceInfoSet: HDEVINFO, + DeviceName: PCSTR, + ClassGuid: *const GUID, + DeviceDescription: PCSTR, + hwndParent: HWND, + CreationFlags: DWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiCreateDeviceInfoW( + DeviceInfoSet: HDEVINFO, + DeviceName: PCWSTR, + ClassGuid: *const GUID, + DeviceDescription: PCWSTR, + hwndParent: HWND, + CreationFlags: DWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; +} +pub const DIOD_INHERIT_CLASSDRVS: DWORD = 0x00000002; +pub const DIOD_CANCEL_REMOVE: DWORD = 0x00000004; +extern "system" { + pub fn SetupDiOpenDeviceInfoA( + DeviceInfoSet: HDEVINFO, + DeviceInstanceId: PCSTR, + hwndParent: HWND, + OpenFlags: DWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiOpenDeviceInfoW( + DeviceInfoSet: HDEVINFO, + DeviceInstanceId: PCWSTR, + hwndParent: HWND, + OpenFlags: DWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiGetDeviceInstanceIdA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstanceId: PSTR, + DeviceInstanceIdSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetDeviceInstanceIdW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstanceId: PWSTR, + DeviceInstanceIdSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiDeleteDeviceInfo( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiEnumDeviceInfo( + DeviceInfoSet: HDEVINFO, + MemberIndex: DWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiDestroyDeviceInfoList( + DeviceInfoSet: HDEVINFO, + ) -> BOOL; + pub fn SetupDiEnumDeviceInterfaces( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + InterfaceClassGuid: *const GUID, + MemberIndex: DWORD, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiCreateDeviceInterfaceA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + InterfaceClassGuid: *const GUID, + ReferenceString: PCSTR, + CreationFlags: DWORD, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiCreateDeviceInterfaceW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + InterfaceClassGuid: *const GUID, + ReferenceString: PCWSTR, + CreationFlags: DWORD, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; +} +pub const DIODI_NO_ADD: DWORD = 0x00000001; +extern "system" { + pub fn SetupDiOpenDeviceInterfaceA( + DeviceInfoSet: HDEVINFO, + DevicePath: PCSTR, + OpenFlags: DWORD, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiOpenDeviceInterfaceW( + DeviceInfoSet: HDEVINFO, + DevicePath: PCWSTR, + OpenFlags: DWORD, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiGetDeviceInterfaceAlias( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + AliasInterfaceClassGuid: *const GUID, + AliasDeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiDeleteDeviceInterfaceData( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiRemoveDeviceInterface( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + ) -> BOOL; + pub fn SetupDiGetDeviceInterfaceDetailA( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + DeviceInterfaceDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA_A, + DeviceInterfaceDetailDataSize: DWORD, + RequiredSize: PDWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiGetDeviceInterfaceDetailW( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + DeviceInterfaceDetailData: PSP_DEVICE_INTERFACE_DETAIL_DATA_W, + DeviceInterfaceDetailDataSize: DWORD, + RequiredSize: PDWORD, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiInstallDeviceInterfaces( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiSetDeviceInterfaceDefault( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Flags: DWORD, + Reserved: PVOID, + ) -> BOOL; +} +pub const SPRDI_FIND_DUPS: DWORD = 0x00000001; +extern "system" { + pub fn SetupDiRegisterDeviceInfo( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Flags: DWORD, + CompareProc: PSP_DETSIG_CMPPROC, + CompareContext: PVOID, + DupDeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; +} +pub const SPDIT_NODRIVER: DWORD = 0x00000000; +pub const SPDIT_CLASSDRIVER: DWORD = 0x00000001; +pub const SPDIT_COMPATDRIVER: DWORD = 0x00000002; +extern "system" { + pub fn SetupDiBuildDriverInfoList( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverType: DWORD, + ) -> BOOL; + pub fn SetupDiCancelDriverInfoSearch( + DeviceInfoSet: HDEVINFO, + ) -> BOOL; + pub fn SetupDiEnumDriverInfoA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverType: DWORD, + MemberIndex: DWORD, + DriverInfoData: PSP_DRVINFO_DATA_A, + ) -> BOOL; + pub fn SetupDiEnumDriverInfoW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverType: DWORD, + MemberIndex: DWORD, + DriverInfoData: PSP_DRVINFO_DATA_W, + ) -> BOOL; + pub fn SetupDiGetSelectedDriverA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_A, + ) -> BOOL; + pub fn SetupDiGetSelectedDriverW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_W, + ) -> BOOL; + pub fn SetupDiSetSelectedDriverA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_A, + ) -> BOOL; + pub fn SetupDiSetSelectedDriverW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_W, + ) -> BOOL; + pub fn SetupDiGetDriverInfoDetailA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_A, + DriverInfoDetailData: PSP_DRVINFO_DETAIL_DATA_A, + DriverInfoDetailDataSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetDriverInfoDetailW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_W, + DriverInfoDetailData: PSP_DRVINFO_DETAIL_DATA_W, + DriverInfoDetailDataSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiDestroyDriverInfoList( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverType: DWORD, + ) -> BOOL; +} +pub const DIGCF_DEFAULT: DWORD = 0x00000001; +pub const DIGCF_PRESENT: DWORD = 0x00000002; +pub const DIGCF_ALLCLASSES: DWORD = 0x00000004; +pub const DIGCF_PROFILE: DWORD = 0x00000008; +pub const DIGCF_DEVICEINTERFACE: DWORD = 0x00000010; +extern "system" { + pub fn SetupDiGetClassDevsA( + ClassGuid: *const GUID, + Enumerator: PCSTR, + hwndParent: HWND, + Flags: DWORD, + ) -> HDEVINFO; + pub fn SetupDiGetClassDevsW( + ClassGuid: *const GUID, + Enumerator: PCWSTR, + hwndParent: HWND, + Flags: DWORD, + ) -> HDEVINFO; + pub fn SetupDiGetClassDevsExA( + ClassGuid: *const GUID, + Enumerator: PCSTR, + hwndParent: HWND, + Flags: DWORD, + DeviceInfoSet: HDEVINFO, + MachineName: PCSTR, + Reserved: PVOID, + ) -> HDEVINFO; + pub fn SetupDiGetClassDevsExW( + ClassGuid: *const GUID, + Enumerator: PCWSTR, + hwndParent: HWND, + Flags: DWORD, + DeviceInfoSet: HDEVINFO, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> HDEVINFO; + pub fn SetupDiGetINFClassA( + InfName: PCSTR, + ClassGuid: LPGUID, + ClassName: PSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetINFClassW( + InfName: PCWSTR, + ClassGuid: LPGUID, + ClassName: PWSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub const DIBCI_NOINSTALLCLASS: DWORD = 0x00000001; +pub const DIBCI_NODISPLAYCLASS: DWORD = 0x00000002; +extern "system" { + pub fn SetupDiBuildClassInfoList( + Flags: DWORD, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiBuildClassInfoListExA( + Flags: DWORD, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiBuildClassInfoListExW( + Flags: DWORD, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassDescriptionA( + ClassGuid: *const GUID, + ClassDescription: PSTR, + ClassDescriptionSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetClassDescriptionW( + ClassGuid: *const GUID, + ClassDescription: PWSTR, + ClassDescriptionSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetClassDescriptionExA( + ClassGuid: *const GUID, + ClassDescription: PSTR, + ClassDescriptionSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassDescriptionExW( + ClassGuid: *const GUID, + ClassDescription: PWSTR, + ClassDescriptionSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiCallClassInstaller( + InstallFunction: DI_FUNCTION, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiSelectDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiSelectBestCompatDrv( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiInstallDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiInstallDriverFiles( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiRegisterCoDeviceInstallers( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiRemoveDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiUnremoveDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiRestartDevices( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiChangeState( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiInstallClassA( + hwndParent: HWND, + InfFileName: PCSTR, + Flags: DWORD, + FileQueue: HSPFILEQ, + ) -> BOOL; + pub fn SetupDiInstallClassW( + hwndParent: HWND, + InfFileName: PCWSTR, + Flags: DWORD, + FileQueue: HSPFILEQ, + ) -> BOOL; + pub fn SetupDiInstallClassExA( + hwndParent: HWND, + InfFileName: PCSTR, + Flags: DWORD, + FileQueue: HSPFILEQ, + InterfaceClassGuid: *const GUID, + Reserved1: PVOID, + Reserved2: PVOID, + ) -> BOOL; + pub fn SetupDiInstallClassExW( + hwndParent: HWND, + InfFileName: PCWSTR, + Flags: DWORD, + FileQueue: HSPFILEQ, + InterfaceClassGuid: *const GUID, + Reserved1: PVOID, + Reserved2: PVOID, + ) -> BOOL; + pub fn SetupDiOpenClassRegKey( + ClassGuid: *const GUID, + samDesired: REGSAM, + ) -> HKEY; +} +pub const DIOCR_INSTALLER: DWORD = 0x00000001; +pub const DIOCR_INTERFACE: DWORD = 0x00000002; +extern "system" { + pub fn SetupDiOpenClassRegKeyExA( + ClassGuid: *const GUID, + samDesired: REGSAM, + Flags: DWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> HKEY; + pub fn SetupDiOpenClassRegKeyExW( + ClassGuid: *const GUID, + samDesired: REGSAM, + Flags: DWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> HKEY; + pub fn SetupDiCreateDeviceInterfaceRegKeyA( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + Reserved: DWORD, + samDesired: REGSAM, + InfHandle: HINF, + InfSectionName: PCSTR, + ) -> HKEY; + pub fn SetupDiCreateDeviceInterfaceRegKeyW( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + Reserved: DWORD, + samDesired: REGSAM, + InfHandle: HINF, + InfSectionName: PCWSTR, + ) -> HKEY; + pub fn SetupDiOpenDeviceInterfaceRegKey( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + Reserved: DWORD, + samDesired: REGSAM, + ) -> HKEY; + pub fn SetupDiDeleteDeviceInterfaceRegKey( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + Reserved: DWORD, + ) -> BOOL; +} +pub const DIREG_DEV: DWORD = 0x00000001; +pub const DIREG_DRV: DWORD = 0x00000002; +pub const DIREG_BOTH: DWORD = 0x00000004; +extern "system" { + pub fn SetupDiCreateDevRegKeyA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Scope: DWORD, + HwProfile: DWORD, + KeyType: DWORD, + InfHandle: HINF, + InfSectionName: PCSTR, + ) -> HKEY; + pub fn SetupDiCreateDevRegKeyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Scope: DWORD, + HwProfile: DWORD, + KeyType: DWORD, + InfHandle: HINF, + InfSectionName: PCWSTR, + ) -> HKEY; + pub fn SetupDiOpenDevRegKey( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Scope: DWORD, + HwProfile: DWORD, + KeyType: DWORD, + samDesired: REGSAM, + ) -> HKEY; + pub fn SetupDiDeleteDevRegKey( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Scope: DWORD, + HwProfile: DWORD, + KeyType: DWORD, + ) -> BOOL; + pub fn SetupDiGetHwProfileList( + HwProfileList: PDWORD, + HwProfileListSize: DWORD, + RequiredSize: PDWORD, + CurrentlyActiveIndex: PDWORD, + ) -> BOOL; + pub fn SetupDiGetHwProfileListExA( + HwProfileList: PDWORD, + HwProfileListSize: DWORD, + RequiredSize: PDWORD, + CurrentlyActiveIndex: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetHwProfileListExW( + HwProfileList: PDWORD, + HwProfileListSize: DWORD, + RequiredSize: PDWORD, + CurrentlyActiveIndex: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetDevicePropertyKeys( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + PropertyKeyArray: *mut DEVPROPKEY, + PropertyKeyCount: DWORD, + RequiredPropertyKeyCount: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiGetDevicePropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiSetDevicePropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + PropertyKey: *const DEVPROPKEY, + PropertyType: DEVPROPTYPE, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiGetDeviceInterfacePropertyKeys( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + PropertyKeyArray: *mut DEVPROPKEY, + PropertyKeyCount: DWORD, + RequiredPropertyKeyCount: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiGetDeviceInterfacePropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiSetDeviceInterfacePropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInterfaceData: PSP_DEVICE_INTERFACE_DATA, + PropertyKey: *const DEVPROPKEY, + PropertyType: DEVPROPTYPE, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + Flags: DWORD, + ) -> BOOL; +} +pub const DICLASSPROP_INSTALLER: DWORD = 0x00000001; +pub const DICLASSPROP_INTERFACE: DWORD = 0x00000002; +extern "system" { + pub fn SetupDiGetClassPropertyKeys( + ClassGuid: *const GUID, + PropertyKeyArray: *mut DEVPROPKEY, + PropertyKeyCount: DWORD, + RequiredPropertyKeyCount: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiGetClassPropertyKeysExW( + ClassGuid: *const GUID, + PropertyKeyArray: *mut DEVPROPKEY, + PropertyKeyCount: DWORD, + RequiredPropertyKeyCount: PDWORD, + Flags: DWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassPropertyW( + ClassGuid: *const GUID, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiGetClassPropertyExW( + ClassGuid: *const GUID, + PropertyKey: *const DEVPROPKEY, + PropertyType: *mut DEVPROPTYPE, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + Flags: DWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiSetClassPropertyW( + ClassGuid: *const GUID, + PropertyKey: *const DEVPROPKEY, + PropertyType: DEVPROPTYPE, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetupDiSetClassPropertyExW( + ClassGuid: *const GUID, + PropertyKey: *const DEVPROPKEY, + PropertyType: DEVPROPTYPE, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + Flags: DWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; +} +pub const SPDRP_DEVICEDESC: DWORD = 0x00000000; +pub const SPDRP_HARDWAREID: DWORD = 0x00000001; +pub const SPDRP_COMPATIBLEIDS: DWORD = 0x00000002; +pub const SPDRP_UNUSED0: DWORD = 0x00000003; +pub const SPDRP_SERVICE: DWORD = 0x00000004; +pub const SPDRP_UNUSED1: DWORD = 0x00000005; +pub const SPDRP_UNUSED2: DWORD = 0x00000006; +pub const SPDRP_CLASS: DWORD = 0x00000007; +pub const SPDRP_CLASSGUID: DWORD = 0x00000008; +pub const SPDRP_DRIVER: DWORD = 0x00000009; +pub const SPDRP_CONFIGFLAGS: DWORD = 0x0000000A; +pub const SPDRP_MFG: DWORD = 0x0000000B; +pub const SPDRP_FRIENDLYNAME: DWORD = 0x0000000C; +pub const SPDRP_LOCATION_INFORMATION: DWORD = 0x0000000D; +pub const SPDRP_PHYSICAL_DEVICE_OBJECT_NAME: DWORD = 0x0000000E; +pub const SPDRP_CAPABILITIES: DWORD = 0x0000000F; +pub const SPDRP_UI_NUMBER: DWORD = 0x00000010; +pub const SPDRP_UPPERFILTERS: DWORD = 0x00000011; +pub const SPDRP_LOWERFILTERS: DWORD = 0x00000012; +pub const SPDRP_BUSTYPEGUID: DWORD = 0x00000013; +pub const SPDRP_LEGACYBUSTYPE: DWORD = 0x00000014; +pub const SPDRP_BUSNUMBER: DWORD = 0x00000015; +pub const SPDRP_ENUMERATOR_NAME: DWORD = 0x00000016; +pub const SPDRP_SECURITY: DWORD = 0x00000017; +pub const SPDRP_SECURITY_SDS: DWORD = 0x00000018; +pub const SPDRP_DEVTYPE: DWORD = 0x00000019; +pub const SPDRP_EXCLUSIVE: DWORD = 0x0000001A; +pub const SPDRP_CHARACTERISTICS: DWORD = 0x0000001B; +pub const SPDRP_ADDRESS: DWORD = 0x0000001C; +pub const SPDRP_UI_NUMBER_DESC_FORMAT: DWORD = 0x0000001D; +pub const SPDRP_DEVICE_POWER_DATA: DWORD = 0x0000001E; +pub const SPDRP_REMOVAL_POLICY: DWORD = 0x0000001F; +pub const SPDRP_REMOVAL_POLICY_HW_DEFAULT: DWORD = 0x00000020; +pub const SPDRP_REMOVAL_POLICY_OVERRIDE: DWORD = 0x00000021; +pub const SPDRP_INSTALL_STATE: DWORD = 0x00000022; +pub const SPDRP_LOCATION_PATHS: DWORD = 0x00000023; +pub const SPDRP_BASE_CONTAINERID: DWORD = 0x00000024; +pub const SPDRP_MAXIMUM_PROPERTY: DWORD = 0x00000025; +pub const SPCRP_UPPERFILTERS: DWORD = 0x00000011; +pub const SPCRP_LOWERFILTERS: DWORD = 0x00000012; +pub const SPCRP_SECURITY: DWORD = 0x00000017; +pub const SPCRP_SECURITY_SDS: DWORD = 0x00000018; +pub const SPCRP_DEVTYPE: DWORD = 0x00000019; +pub const SPCRP_EXCLUSIVE: DWORD = 0x0000001A; +pub const SPCRP_CHARACTERISTICS: DWORD = 0x0000001B; +pub const SPCRP_MAXIMUM_PROPERTY: DWORD = 0x0000001C; +extern "system" { + pub fn SetupDiGetDeviceRegistryPropertyA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Property: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetDeviceRegistryPropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Property: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetClassRegistryPropertyA( + ClassGuid: *const GUID, + Property: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassRegistryPropertyW( + ClassGuid: *const GUID, + Property: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiSetDeviceRegistryPropertyA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Property: DWORD, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + ) -> BOOL; + pub fn SetupDiSetDeviceRegistryPropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + Property: DWORD, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + ) -> BOOL; + pub fn SetupDiSetClassRegistryPropertyA( + ClassGuid: *const GUID, + Property: DWORD, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiSetClassRegistryPropertyW( + ClassGuid: *const GUID, + Property: DWORD, + PropertyBuffer: *const BYTE, + PropertyBufferSize: DWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetDeviceInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstallParams: PSP_DEVINSTALL_PARAMS_A, + ) -> BOOL; + pub fn SetupDiGetDeviceInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstallParams: PSP_DEVINSTALL_PARAMS_W, + ) -> BOOL; + pub fn SetupDiGetClassInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ClassInstallParams: PSP_CLASSINSTALL_HEADER, + ClassInstallParamsSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetClassInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ClassInstallParams: PSP_CLASSINSTALL_HEADER, + ClassInstallParamsSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiSetDeviceInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstallParams: PSP_DEVINSTALL_PARAMS_A, + ) -> BOOL; + pub fn SetupDiSetDeviceInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DeviceInstallParams: PSP_DEVINSTALL_PARAMS_W, + ) -> BOOL; + pub fn SetupDiSetClassInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ClassInstallParams: PSP_CLASSINSTALL_HEADER, + ClassInstallParamsSize: DWORD, + ) -> BOOL; + pub fn SetupDiSetClassInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ClassInstallParams: PSP_CLASSINSTALL_HEADER, + ClassInstallParamsSize: DWORD, + ) -> BOOL; + pub fn SetupDiGetDriverInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_A, + DriverInstallParams: PSP_DRVINSTALL_PARAMS, + ) -> BOOL; + pub fn SetupDiGetDriverInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_W, + DriverInstallParams: PSP_DRVINSTALL_PARAMS, + ) -> BOOL; + pub fn SetupDiSetDriverInstallParamsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_A, + DriverInstallParams: PSP_DRVINSTALL_PARAMS, + ) -> BOOL; + pub fn SetupDiSetDriverInstallParamsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + DriverInfoData: PSP_DRVINFO_DATA_W, + DriverInstallParams: PSP_DRVINSTALL_PARAMS, + ) -> BOOL; + pub fn SetupDiLoadClassIcon( + ClassGuid: *const GUID, + LargeIcon: *mut HICON, + MiniIconIndex: PINT, + ) -> BOOL; + pub fn SetupDiLoadDeviceIcon( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + cxIcon: UINT, + cyIcon: UINT, + Flags: DWORD, + hIcon: *mut HICON, + ) -> BOOL; +} +pub const DMI_MASK: DWORD = 0x00000001; +pub const DMI_BKCOLOR: DWORD = 0x00000002; +pub const DMI_USERECT: DWORD = 0x00000004; +extern "system" { + pub fn SetupDiDrawMiniIcon( + hdc: HDC, + rc: RECT, + MiniIconIndex: INT, + Flags: DWORD, + ) -> INT; + pub fn SetupDiGetClassBitmapIndex( + ClassGuid: *const GUID, + MiniIconIndex: PINT, + ) -> BOOL; + pub fn SetupDiGetClassImageList( + ClassImageListData: PSP_CLASSIMAGELIST_DATA, + ) -> BOOL; + pub fn SetupDiGetClassImageListExA( + ClassImageListData: PSP_CLASSIMAGELIST_DATA, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassImageListExW( + ClassImageListData: PSP_CLASSIMAGELIST_DATA, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetClassImageIndex( + ClassImageListData: PSP_CLASSIMAGELIST_DATA, + ClassGuid: *const GUID, + ImageIndex: PINT, + ) -> BOOL; + pub fn SetupDiDestroyClassImageList( + ClassImageListData: PSP_CLASSIMAGELIST_DATA, + ) -> BOOL; +} +pub const DIGCDP_FLAG_BASIC: DWORD = 0x00000001; +pub const DIGCDP_FLAG_ADVANCED: DWORD = 0x00000002; +pub const DIGCDP_FLAG_REMOTE_BASIC: DWORD = 0x00000003; +pub const DIGCDP_FLAG_REMOTE_ADVANCED: DWORD = 0x00000004; +extern "system" { + pub fn SetupDiGetClassDevPropertySheetsA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + PropertySheetHeader: LPPROPSHEETHEADERA, + PropertySheetHeaderPageListSize: DWORD, + RequiredSize: PDWORD, + PropertySheetType: DWORD, + ) -> BOOL; + pub fn SetupDiGetClassDevPropertySheetsW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + PropertySheetHeader: LPPROPSHEETHEADERW, + PropertySheetHeaderPageListSize: DWORD, + RequiredSize: PDWORD, + PropertySheetType: DWORD, + ) -> BOOL; +} +pub const IDI_RESOURCEFIRST: c_int = 159; +pub const IDI_RESOURCE: c_int = 159; +pub const IDI_RESOURCELAST: c_int = 161; +pub const IDI_RESOURCEOVERLAYFIRST: c_int = 161; +pub const IDI_RESOURCEOVERLAYLAST: c_int = 161; +pub const IDI_CONFLICT: c_int = 161; +pub const IDI_CLASSICON_OVERLAYFIRST: c_int = 500; +pub const IDI_CLASSICON_OVERLAYLAST: c_int = 502; +pub const IDI_PROBLEM_OVL: c_int = 500; +pub const IDI_DISABLED_OVL: c_int = 501; +pub const IDI_FORCED_OVL: c_int = 502; +extern "system" { + pub fn SetupDiAskForOEMDisk( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiSelectOEMDrv( + hwndParent: HWND, + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiClassNameFromGuidA( + ClassGuid: *const GUID, + ClassName: PSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiClassNameFromGuidW( + ClassGuid: *const GUID, + ClassName: PWSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiClassNameFromGuidExA( + ClassGuid: *const GUID, + ClassName: PSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiClassNameFromGuidExW( + ClassGuid: *const GUID, + ClassName: PWSTR, + ClassNameSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiClassGuidsFromNameA( + ClassName: PCSTR, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiClassGuidsFromNameW( + ClassName: PCWSTR, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiClassGuidsFromNameExA( + ClassName: PCSTR, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiClassGuidsFromNameExW( + ClassName: PCWSTR, + ClassGuidList: LPGUID, + ClassGuidListSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetHwProfileFriendlyNameA( + HwProfile: DWORD, + FriendlyName: PSTR, + FriendlyNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetHwProfileFriendlyNameW( + HwProfile: DWORD, + FriendlyName: PWSTR, + FriendlyNameSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetHwProfileFriendlyNameExA( + HwProfile: DWORD, + FriendlyName: PSTR, + FriendlyNameSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetHwProfileFriendlyNameExW( + HwProfile: DWORD, + FriendlyName: PWSTR, + FriendlyNameSize: DWORD, + RequiredSize: PDWORD, + MachineName: PCWSTR, + Reserved: PVOID, + ) -> BOOL; +} +pub const SPWPT_SELECTDEVICE: DWORD = 0x00000001; +pub const SPWP_USE_DEVINFO_DATA: DWORD = 0x00000001; +extern "system" { + pub fn SetupDiGetWizardPage( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + InstallWizardData: PSP_INSTALLWIZARD_DATA, + PageType: DWORD, + Flags: DWORD, + ) -> HPROPSHEETPAGE; + pub fn SetupDiGetSelectedDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiSetSelectedDevice( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + ) -> BOOL; + pub fn SetupDiGetActualModelsSectionA( + Context: PINFCONTEXT, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + InfSectionWithExt: PSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetActualModelsSectionW( + Context: PINFCONTEXT, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + InfSectionWithExt: PWSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetActualSectionToInstallA( + InfHandle: HINF, + InfSectionName: PCSTR, + InfSectionWithExt: PSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Extension: *mut PSTR, + ) -> BOOL; + pub fn SetupDiGetActualSectionToInstallW( + InfHandle: HINF, + InfSectionName: PCWSTR, + InfSectionWithExt: PWSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Extension: *mut PWSTR, + ) -> BOOL; + pub fn SetupDiGetActualSectionToInstallExA( + InfHandle: HINF, + InfSectionName: PCSTR, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + InfSectionWithExt: PSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Extension: *mut PSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupDiGetActualSectionToInstallExW( + InfHandle: HINF, + InfSectionName: PCWSTR, + AlternatePlatformInfo: PSP_ALTPLATFORM_INFO, + InfSectionWithExt: PWSTR, + InfSectionWithExtSize: DWORD, + RequiredSize: PDWORD, + Extension: *mut PWSTR, + Reserved: PVOID, + ) -> BOOL; + pub fn SetupEnumInfSectionsA( + InfHandle: HINF, + Index: UINT, + Buffer: PSTR, + Size: UINT, + SizeNeeded: *mut UINT, + ) -> BOOL; + pub fn SetupEnumInfSectionsW( + InfHandle: HINF, + Index: UINT, + Buffer: PWSTR, + Size: UINT, + SizeNeeded: *mut UINT, + ) -> BOOL; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INF_SIGNER_INFO_V1_A { + cbSize: DWORD, + CatalogFile: [CHAR; MAX_PATH], + DigitalSigner: [CHAR; MAX_PATH], + DigitalSignerVersion: [CHAR; MAX_PATH], +}} +pub type PSP_INF_SIGNER_INFO_V1_A = *mut SP_INF_SIGNER_INFO_V1_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INF_SIGNER_INFO_V1_W { + cbSize: DWORD, + CatalogFile: [WCHAR; MAX_PATH], + DigitalSigner: [WCHAR; MAX_PATH], + DigitalSignerVersion: [WCHAR; MAX_PATH], +}} +pub type PSP_INF_SIGNER_INFO_V1_W = *mut SP_INF_SIGNER_INFO_V1_W; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INF_SIGNER_INFO_V2_A { + cbSize: DWORD, + CatalogFile: [CHAR; MAX_PATH], + DigitalSigner: [CHAR; MAX_PATH], + DigitalSignerVersion: [CHAR; MAX_PATH], + SignerScore: DWORD, +}} +pub type PSP_INF_SIGNER_INFO_V2_A = *mut SP_INF_SIGNER_INFO_V2_A; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SP_INF_SIGNER_INFO_V2_W { + cbSize: DWORD, + CatalogFile: [WCHAR; MAX_PATH], + DigitalSigner: [WCHAR; MAX_PATH], + DigitalSignerVersion: [WCHAR; MAX_PATH], + SignerScore: DWORD, +}} +pub type PSP_INF_SIGNER_INFO_V2_W = *mut SP_INF_SIGNER_INFO_V2_W; +pub const SIGNERSCORE_UNKNOWN: DWORD = 0xFF000000; +pub const SIGNERSCORE_W9X_SUSPECT: DWORD = 0xC0000000; +pub const SIGNERSCORE_UNSIGNED: DWORD = 0x80000000; +pub const SIGNERSCORE_AUTHENTICODE: DWORD = 0x0F000000; +pub const SIGNERSCORE_WHQL: DWORD = 0x0D000005; +pub const SIGNERSCORE_UNCLASSIFIED: DWORD = 0x0D000004; +pub const SIGNERSCORE_INBOX: DWORD = 0x0D000003; +pub const SIGNERSCORE_LOGO_STANDARD: DWORD = 0x0D000002; +pub const SIGNERSCORE_LOGO_PREMIUM: DWORD = 0x0D000001; +pub const SIGNERSCORE_MASK: DWORD = 0xFF000000; +pub const SIGNERSCORE_SIGNED_MASK: DWORD = 0xF0000000; +pub type SP_INF_SIGNER_INFO_A = SP_INF_SIGNER_INFO_V2_A; +pub type PSP_INF_SIGNER_INFO_A = PSP_INF_SIGNER_INFO_V2_A; +pub type SP_INF_SIGNER_INFO_W = SP_INF_SIGNER_INFO_V2_W; +pub type PSP_INF_SIGNER_INFO_W = PSP_INF_SIGNER_INFO_V2_W; +extern "system" { + pub fn SetupVerifyInfFileA( + InfName: PCSTR, + AltPlatformInfo: PSP_ALTPLATFORM_INFO, + InfSignerInfo: PSP_INF_SIGNER_INFO_A, + ) -> BOOL; + pub fn SetupVerifyInfFileW( + InfName: PCWSTR, + AltPlatformInfo: PSP_ALTPLATFORM_INFO, + InfSignerInfo: PSP_INF_SIGNER_INFO_W, + ) -> BOOL; +} +pub const DICUSTOMDEVPROP_MERGE_MULTISZ: DWORD = 0x00000001; +extern "system" { + pub fn SetupDiGetCustomDevicePropertyA( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + CustomPropertyName: PCSTR, + Flags: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; + pub fn SetupDiGetCustomDevicePropertyW( + DeviceInfoSet: HDEVINFO, + DeviceInfoData: PSP_DEVINFO_DATA, + CustomPropertyName: PCWSTR, + Flags: DWORD, + PropertyRegDataType: PDWORD, + PropertyBuffer: PBYTE, + PropertyBufferSize: DWORD, + RequiredSize: PDWORD, + ) -> BOOL; +} +pub const SCWMI_CLOBBER_SECURITY: DWORD = 0x00000001; +extern "system" { + pub fn SetupConfigureWmiFromInfSectionA( + InfHandle: HINF, + SectionName: PCSTR, + Flags: DWORD, + ) -> BOOL; + pub fn SetupConfigureWmiFromInfSectionW( + InfHandle: HINF, + SectionName: PCWSTR, + Flags: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/shellapi.rs b/winapi/src/um/shellapi.rs new file mode 100644 index 000000000..2c961c4c5 --- /dev/null +++ b/winapi/src/um/shellapi.rs @@ -0,0 +1,923 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! SHELL.DLL functions, types, and definitions +use ctypes::{__int64, c_int, c_void}; +use shared::basetsd::{DWORD_PTR, UINT_PTR}; +use shared::guiddef::{GUID, REFIID}; +use shared::minwindef::{ + BOOL, DWORD, FILETIME, HINSTANCE, HKEY, INT, LPARAM, LPVOID, MAX_PATH, UINT, ULONG, WORD, +}; +use shared::windef::{HICON, HWND, POINT, RECT}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::processthreadsapi::{LPPROCESS_INFORMATION, LPSTARTUPINFOW}; +use um::winnt::{ + CHAR, HANDLE, HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCSTR, PCWSTR, PCZZSTR, PCZZWSTR, PWSTR, + PZZSTR, PZZWSTR, ULARGE_INTEGER, WCHAR, +}; +use um::winuser::WM_USER; +DECLARE_HANDLE!{HDROP, HDROP__} +extern "system" { + pub fn DragQueryFileA( + hDrop: HDROP, + iFile: UINT, + lpszFile: LPSTR, + cch: UINT, + ) -> UINT; + pub fn DragQueryFileW( + hDrop: HDROP, + iFile: UINT, + lpszFile: LPWSTR, + cch: UINT, + ) -> UINT; + pub fn DragQueryPoint( + hDrop: HDROP, + lppt: *mut POINT, + ) -> BOOL; + pub fn DragFinish( + hDrop: HDROP, + ); + pub fn DragAcceptFiles( + hWnd: HWND, + fAccept: BOOL, + ); + pub fn ShellExecuteA( + hwnd: HWND, + lpOperation: LPCSTR, + lpFile: LPCSTR, + lpParameters: LPCSTR, + lpDirectory: LPCSTR, + nShowCmd: c_int, + ) -> HINSTANCE; + pub fn ShellExecuteW( + hwnd: HWND, + lpOperation: LPCWSTR, + lpFile: LPCWSTR, + lpParameters: LPCWSTR, + lpDirectory: LPCWSTR, + nShowCmd: c_int, + ) -> HINSTANCE; + pub fn FindExecutableA( + lpFile: LPCSTR, + lpDirectory: LPCSTR, + lpResult: LPSTR, + ) -> HINSTANCE; + pub fn FindExecutableW( + lpFile: LPCWSTR, + lpDirectory: LPCWSTR, + lpResult: LPWSTR, + ) -> HINSTANCE; + pub fn CommandLineToArgvW( + lpCmdLine: LPCWSTR, + pNumArgs: *mut c_int, + ) -> *mut LPWSTR; + pub fn ShellAboutA( + hWnd: HWND, + szApp: LPCSTR, + szOtherStuff: LPCSTR, + hIcon: HICON, + ) -> INT; + pub fn ShellAboutW( + hWnd: HWND, + szApp: LPCWSTR, + szOtherStuff: LPCWSTR, + hIcon: HICON, + ) -> INT; + pub fn DuplicateIcon( + hInst: HINSTANCE, + hIcon: HICON, + ) -> HICON; + pub fn ExtractAssociatedIconA( + hInst: HINSTANCE, + pszIconPath: LPSTR, + piIcon: *mut WORD, + ) -> HICON; + pub fn ExtractAssociatedIconW( + hInst: HINSTANCE, + pszIconPath: LPWSTR, + piIcon: *mut WORD, + ) -> HICON; + pub fn ExtractAssociatedIconExA( + hInst: HINSTANCE, + pszIconPath: LPSTR, + piIconIndex: *mut WORD, + piIconId: *mut WORD, + ) -> HICON; + pub fn ExtractAssociatedIconExW( + hInst: HINSTANCE, + pszIconPath: LPWSTR, + piIconIndex: *mut WORD, + piIconId: *mut WORD, + ) -> HICON; + pub fn ExtractIconA( + hInst: HINSTANCE, + pszExeFileName: LPCSTR, + nIconIndex: UINT, + ) -> HICON; + pub fn ExtractIconW( + hInst: HINSTANCE, + pszExeFileName: LPCWSTR, + nIconIndex: UINT, + ) -> HICON; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct DRAGINFOA { + uSize: UINT, + pt: POINT, + fNC: BOOL, + lpFileList: PZZSTR, + grfKeyState: DWORD, +}} +pub type LPDRAGINFOA = *mut DRAGINFOA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct DRAGINFOW { + uSize: UINT, + pt: POINT, + fNC: BOOL, + lpFileList: PZZWSTR, + grfKeyState: DWORD, +}} +pub type LPDRAGINFOW = *mut DRAGINFOW; +pub const ABM_NEW: DWORD = 0x00000000; +pub const ABM_REMOVE: DWORD = 0x00000001; +pub const ABM_QUERYPOS: DWORD = 0x00000002; +pub const ABM_SETPOS: DWORD = 0x00000003; +pub const ABM_GETSTATE: DWORD = 0x00000004; +pub const ABM_GETTASKBARPOS: DWORD = 0x00000005; +pub const ABM_ACTIVATE: DWORD = 0x00000006; +pub const ABM_GETAUTOHIDEBAR: DWORD = 0x00000007; +pub const ABM_SETAUTOHIDEBAR: DWORD = 0x00000008; +pub const ABM_WINDOWPOSCHANGED: DWORD = 0x0000009; +pub const ABM_SETSTATE: DWORD = 0x0000000a; +pub const ABM_GETAUTOHIDEBAREX: DWORD = 0x0000000b; +pub const ABM_SETAUTOHIDEBAREX: DWORD = 0x0000000c; +pub const ABN_STATECHANGE: DWORD = 0x0000000; +pub const ABN_POSCHANGED: DWORD = 0x0000001; +pub const ABN_FULLSCREENAPP: DWORD = 0x0000002; +pub const ABN_WINDOWARRANGE: DWORD = 0x0000003; +pub const ABS_AUTOHIDE: UINT = 0x0000001; +pub const ABS_ALWAYSONTOP: UINT = 0x0000002; +pub const ABE_LEFT: UINT = 0; +pub const ABE_TOP: UINT = 1; +pub const ABE_RIGHT: UINT = 2; +pub const ABE_BOTTOM: UINT = 3; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct APPBARDATA { + cbSize: DWORD, + hWnd: HWND, + uCallbackMessage: UINT, + uEdge: UINT, + rc: RECT, + lParam: LPARAM, +}} +pub type PAPPBARDATA = *mut APPBARDATA; +extern "system" { + pub fn SHAppBarMessage( + dwMessage: DWORD, + pData: PAPPBARDATA, + ) -> UINT_PTR; + pub fn DoEnvironmentSubstA( + pszSrc: LPSTR, + cchSrc: UINT, + ) -> DWORD; + pub fn DoEnvironmentSubstW( + pszSrc: LPWSTR, + cchSrc: UINT, + ) -> DWORD; + pub fn ExtractIconExA( + lpszFile: LPCSTR, + nIconIndex: c_int, + phiconLarge: *mut HICON, + phiconSmall: *mut HICON, + nIcons: UINT, + ) -> UINT; + pub fn ExtractIconExW( + lpszFile: LPCWSTR, + nIconIndex: c_int, + phiconLarge: *mut HICON, + phiconSmall: *mut HICON, + nIcons: UINT, + ) -> UINT; +} +pub const FO_MOVE: WORD = 0x0001; +pub const FO_COPY: WORD = 0x0002; +pub const FO_DELETE: WORD = 0x0003; +pub const FO_RENAME: WORD = 0x0004; +pub const FOF_MULTIDESTFILES: WORD = 0x0001; +pub const FOF_CONFIRMMOUSE: WORD = 0x0002; +pub const FOF_SILENT: WORD = 0x0004; +pub const FOF_RENAMEONCOLLISION: WORD = 0x0008; +pub const FOF_NOCONFIRMATION: WORD = 0x0010; +pub const FOF_WANTMAPPINGHANDLE: WORD = 0x0020; +pub const FOF_ALLOWUNDO: WORD = 0x0040; +pub const FOF_FILESONLY: WORD = 0x0080; +pub const FOF_SIMPLEPROGRESS: WORD = 0x0100; +pub const FOF_NOCONFIRMMKDIR: WORD = 0x0200; +pub const FOF_NOERRORUI: WORD = 0x0400; +pub const FOF_NOCOPYSECURITYATTRIBS: WORD = 0x0800; +pub const FOF_NORECURSION: WORD = 0x1000; +pub const FOF_NO_CONNECTED_ELEMENTS: WORD = 0x2000; +pub const FOF_WANTNUKEWARNING: WORD = 0x4000; +pub const FOF_NORECURSEREPARSE: WORD = 0x8000; +pub const FOF_NO_UI: WORD = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR; +pub type FILEOP_FLAGS = WORD; +pub const PO_DELETE: WORD = 0x0013; +pub const PO_RENAME: WORD = 0x0014; +pub const PO_PORTCHANGE: WORD = 0x0020; +pub const PO_REN_PORT: WORD = 0x0034; +pub type PRINTEROP_FLAGS = WORD; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHFILEOPSTRUCTA { + hwnd: HWND, + wFunc: UINT, + pFrom: PCZZSTR, + pTo: PCZZSTR, + fFlags: FILEOP_FLAGS, + fAnyOperationsAborted: BOOL, + hNameMappings: LPVOID, + lpszProgressTitle: PCSTR, +}} +pub type LPSHFILEOPSTRUCTA = *mut SHFILEOPSTRUCTA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHFILEOPSTRUCTW { + hwnd: HWND, + wFunc: UINT, + pFrom: PCZZWSTR, + pTo: PCZZWSTR, + fFlags: FILEOP_FLAGS, + fAnyOperationsAborted: BOOL, + hNameMappings: LPVOID, + lpszProgressTitle: PCWSTR, +}} +pub type LPSHFILEOPSTRUCTW = *mut SHFILEOPSTRUCTW; +extern "system" { + pub fn SHFileOperationA( + lpFileOp: LPSHFILEOPSTRUCTA, + ) -> c_int; + pub fn SHFileOperationW( + lpFileOp: LPSHFILEOPSTRUCTW, + ) -> c_int; + pub fn SHFreeNameMappings( + hNameMappings: HANDLE, + ); +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHNAMEMAPPINGA { + pszOldPath: LPSTR, + pszNewPath: LPSTR, + cchOldPath: c_int, + cchNewPath: c_int, +}} +pub type LPSHNAMEMAPPINGA = *mut SHNAMEMAPPINGA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHNAMEMAPPINGW { + pszOldPath: LPWSTR, + pszNewPath: LPWSTR, + cchOldPath: c_int, + cchNewPath: c_int, +}} +pub type LPSHNAMEMAPPINGW = *mut SHNAMEMAPPINGW; +pub const SE_ERR_FNF: DWORD = 2; +pub const SE_ERR_PNF: DWORD = 3; +pub const SE_ERR_ACCESSDENIED: DWORD = 5; +pub const SE_ERR_OOM: DWORD = 8; +pub const SE_ERR_DLLNOTFOUND: DWORD = 32; +pub const SE_ERR_SHARE: DWORD = 26; +pub const SE_ERR_ASSOCINCOMPLETE: DWORD = 27; +pub const SE_ERR_DDETIMEOUT: DWORD = 28; +pub const SE_ERR_DDEFAIL: DWORD = 29; +pub const SE_ERR_DDEBUSY: DWORD = 30; +pub const SE_ERR_NOASSOC: DWORD = 31; +pub const SEE_MASK_DEFAULT: DWORD = 0x00000000; +pub const SEE_MASK_CLASSNAME: DWORD = 0x00000001; +pub const SEE_MASK_CLASSKEY: DWORD = 0x00000003; +pub const SEE_MASK_IDLIST: DWORD = 0x00000004; +pub const SEE_MASK_INVOKEIDLIST: DWORD = 0x0000000c; +pub const SEE_MASK_ICON: DWORD = 0x00000010; +pub const SEE_MASK_HOTKEY: DWORD = 0x00000020; +pub const SEE_MASK_NOCLOSEPROCESS: DWORD = 0x00000040; +pub const SEE_MASK_CONNECTNETDRV: DWORD = 0x00000080; +pub const SEE_MASK_NOASYNC: DWORD = 0x00000100; +pub const SEE_MASK_FLAG_DDEWAIT: DWORD = SEE_MASK_NOASYNC; +pub const SEE_MASK_DOENVSUBST: DWORD = 0x00000200; +pub const SEE_MASK_FLAG_NO_UI: DWORD = 0x00000400; +pub const SEE_MASK_UNICODE: DWORD = 0x00004000; +pub const SEE_MASK_NO_CONSOLE: DWORD = 0x00008000; +pub const SEE_MASK_ASYNCOK: DWORD = 0x00100000; +pub const SEE_MASK_HMONITOR: DWORD = 0x00200000; +pub const SEE_MASK_NOZONECHECKS: DWORD = 0x00800000; +pub const SEE_MASK_NOQUERYCLASSSTORE: DWORD = 0x01000000; +pub const SEE_MASK_WAITFORINPUTIDLE: DWORD = 0x02000000; +pub const SEE_MASK_FLAG_LOG_USAGE: DWORD = 0x04000000; +pub const SEE_MASK_FLAG_HINST_IS_SITE: DWORD = 0x08000000; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHELLEXECUTEINFOA { + cbSize: DWORD, + fMask: ULONG, + hwnd: HWND, + lpVerb: LPCSTR, + lpFile: LPCSTR, + lpParameters: LPCSTR, + lpDirectory: LPCSTR, + nShow: c_int, + hInstApp: HINSTANCE, + lpIDList: *mut c_void, + lpClass: LPCSTR, + hkeyClass: HKEY, + dwHotKey: DWORD, + hMonitor: HANDLE, + hProcess: HANDLE, +}} +pub type LPSHELLEXECUTEINFOA = *mut SHELLEXECUTEINFOA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHELLEXECUTEINFOW { + cbSize: DWORD, + fMask: ULONG, + hwnd: HWND, + lpVerb: LPCWSTR, + lpFile: LPCWSTR, + lpParameters: LPCWSTR, + lpDirectory: LPCWSTR, + nShow: c_int, + hInstApp: HINSTANCE, + lpIDList: *mut c_void, + lpClass: LPCWSTR, + hkeyClass: HKEY, + dwHotKey: DWORD, + hMonitor: HANDLE, + hProcess: HANDLE, +}} +pub type LPSHELLEXECUTEINFOW = *mut SHELLEXECUTEINFOW; +extern "system" { + pub fn ShellExecuteExA( + pExecInfo: *mut SHELLEXECUTEINFOA, + ) -> BOOL; + pub fn ShellExecuteExW( + pExecInfo: *mut SHELLEXECUTEINFOW, + ) -> BOOL; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHCREATEPROCESSINFOW { + cbSize: DWORD, + fMask: ULONG, + hwnd: HWND, + pszFile: LPCWSTR, + pszParameters: LPCWSTR, + pszCurrentDirectory: LPCWSTR, + hUserToken: HANDLE, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpStartupInfo: LPSTARTUPINFOW, + lpProcessInformation: LPPROCESS_INFORMATION, +}} +pub type PSHCREATEPROCESSINFOW = *mut SHCREATEPROCESSINFOW; +extern "system" { + pub fn SHCreateProcessAsUserW( + pscpi: PSHCREATEPROCESSINFOW, + ) -> BOOL; + pub fn SHEvaluateSystemCommandTemplate( + pszCmdTemplate: PCWSTR, + ppszApplication: *mut PWSTR, + ppszCommandLine: *mut PWSTR, + ppszParameters: *mut PWSTR, + ) -> HRESULT; +} +ENUM!{enum ASSOCCLASS { + ASSOCCLASS_SHELL_KEY = 0, + ASSOCCLASS_PROGID_KEY, + ASSOCCLASS_PROGID_STR, + ASSOCCLASS_CLSID_KEY, + ASSOCCLASS_CLSID_STR, + ASSOCCLASS_APP_KEY, + ASSOCCLASS_APP_STR, + ASSOCCLASS_SYSTEM_STR, + ASSOCCLASS_FOLDER, + ASSOCCLASS_STAR, + ASSOCCLASS_FIXED_PROGID_STR, + ASSOCCLASS_PROTOCOL_STR, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct ASSOCIATIONELEMENT { + ac: ASSOCCLASS, + hkClass: HKEY, + pszClass: PCWSTR, +}} +extern "system" { + pub fn AssocCreateForClasses( + rgClasses: *const ASSOCIATIONELEMENT, + cClasses: ULONG, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHQUERYRBINFO { + cbSize: DWORD, + i64Size: __int64, + i64NumItems: __int64, +}} +pub type LPSHQUERYRBINFO = *mut SHQUERYRBINFO; +pub const SHERB_NOCONFIRMATION: DWORD = 0x00000001; +pub const SHERB_NOPROGRESSUI: DWORD = 0x00000002; +pub const SHERB_NOSOUND: DWORD = 0x00000004; +extern "system" { + pub fn SHQueryRecycleBinA( + pszRootPath: LPCSTR, + pSHQueryRBInfo: LPSHQUERYRBINFO, + ) -> HRESULT; + pub fn SHQueryRecycleBinW( + pszRootPath: LPCWSTR, + pSHQueryRBInfo: LPSHQUERYRBINFO, + ) -> HRESULT; + pub fn SHEmptyRecycleBinA( + hwnd: HWND, + pszRootPath: LPCSTR, + dwFlags: DWORD, + ) -> HRESULT; + pub fn SHEmptyRecycleBinW( + hwnd: HWND, + pszRootPath: LPCWSTR, + dwFlags: DWORD, + ) -> HRESULT; +} +ENUM!{enum QUERY_USER_NOTIFICATION_STATE { + QUNS_NOT_PRESENT = 1, + QUNS_BUSY = 2, + QUNS_RUNNING_D3D_FULL_SCREEN = 3, + QUNS_PRESENTATION_MODE = 4, + QUNS_ACCEPTS_NOTIFICATIONS = 5, + QUNS_QUIET_TIME = 6, + QUNS_APP = 7, +}} +extern "system" { + pub fn SHQueryUserNotificationState( + pquns: *mut QUERY_USER_NOTIFICATION_STATE, + ) -> HRESULT; + pub fn SHGetPropertyStoreForWindow( + hwnd: HWND, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; +} +UNION!{#[cfg_attr(target_arch = "x86", repr(packed))] union NOTIFYICONDATAA_u { + [u32; 1], + uTimeout uTimeout_mut: UINT, + uVersion uVersion_mut: UINT, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct NOTIFYICONDATAA { + cbSize: DWORD, + hWnd: HWND, + uID: UINT, + uFlags: UINT, + uCallbackMessage: UINT, + hIcon: HICON, + szTip: [CHAR; 128], + dwState: DWORD, + dwStateMask: DWORD, + szInfo: [CHAR; 256], + u: NOTIFYICONDATAA_u, + szInfoTitle: [CHAR; 64], + dwInfoFlags: DWORD, + guidItem: GUID, + hBalloonIcon: HICON, +}} +pub type PNOTIFYICONDATAA = *mut NOTIFYICONDATAA; +UNION!{#[cfg_attr(target_arch = "x86", repr(packed))] union NOTIFYICONDATAW_u { + [u32; 1], + uTimeout uTimeout_mut: UINT, + uVersion uVersion_mut: UINT, +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct NOTIFYICONDATAW { + cbSize: DWORD, + hWnd: HWND, + uID: UINT, + uFlags: UINT, + uCallbackMessage: UINT, + hIcon: HICON, + szTip: [WCHAR; 128], + dwState: DWORD, + dwStateMask: DWORD, + szInfo: [WCHAR; 256], + u: NOTIFYICONDATAW_u, + szInfoTitle: [WCHAR; 64], + dwInfoFlags: DWORD, + guidItem: GUID, + hBalloonIcon: HICON, +}} +pub type PNOTIFYICONDATAW = *mut NOTIFYICONDATAW; +pub const NIN_SELECT: DWORD = WM_USER + 0; +pub const NINF_KEY: DWORD = 0x1; +pub const NIN_KEYSELECT: DWORD = NIN_SELECT | NINF_KEY; +pub const NIN_BALLOONSHOW: DWORD = WM_USER + 2; +pub const NIN_BALLOONHIDE: DWORD = WM_USER + 3; +pub const NIN_BALLOONTIMEOUT: DWORD = WM_USER + 4; +pub const NIN_BALLOONUSERCLICK: DWORD = WM_USER + 5; +pub const NIN_POPUPOPEN: DWORD = WM_USER + 6; +pub const NIN_POPUPCLOSE: DWORD = WM_USER + 7; +pub const NIM_ADD: DWORD = 0x00000000; +pub const NIM_MODIFY: DWORD = 0x00000001; +pub const NIM_DELETE: DWORD = 0x00000002; +pub const NIM_SETFOCUS: DWORD = 0x00000003; +pub const NIM_SETVERSION: DWORD = 0x00000004; +pub const NOTIFYICON_VERSION: DWORD = 3; +pub const NOTIFYICON_VERSION_4: DWORD = 4; +pub const NIF_MESSAGE: DWORD = 0x00000001; +pub const NIF_ICON: DWORD = 0x00000002; +pub const NIF_TIP: DWORD = 0x00000004; +pub const NIF_STATE: DWORD = 0x00000008; +pub const NIF_INFO: DWORD = 0x00000010; +pub const NIF_GUID: DWORD = 0x00000020; +pub const NIF_REALTIME: DWORD = 0x00000040; +pub const NIF_SHOWTIP: DWORD = 0x00000080; +pub const NIS_HIDDEN: DWORD = 0x00000001; +pub const NIS_SHAREDICON: DWORD = 0x00000002; +pub const NIIF_NONE: DWORD = 0x00000000; +pub const NIIF_INFO: DWORD = 0x00000001; +pub const NIIF_WARNING: DWORD = 0x00000002; +pub const NIIF_ERROR: DWORD = 0x00000003; +pub const NIIF_USER: DWORD = 0x00000004; +pub const NIIF_ICON_MASK: DWORD = 0x0000000F; +pub const NIIF_NOSOUND: DWORD = 0x00000010; +pub const NIIF_LARGE_ICON: DWORD = 0x00000020; +pub const NIIF_RESPECT_QUIET_TIME: DWORD = 0x00000080; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct NOTIFYICONIDENTIFIER { + cbSize: DWORD, + hWnd: HWND, + uID: UINT, + guidItem: GUID, +}} +pub type PNOTIFYICONIDENTIFIER = *mut NOTIFYICONIDENTIFIER; +extern "system" { + pub fn Shell_NotifyIconA( + dwMessage: DWORD, + lpData: PNOTIFYICONDATAA, + ) -> BOOL; + pub fn Shell_NotifyIconW( + dwMessage: DWORD, + lpData: PNOTIFYICONDATAW, + ) -> BOOL; + pub fn Shell_NotifyIconGetRect( + identifier: *const NOTIFYICONIDENTIFIER, + iconLocation: *mut RECT, + ) -> HRESULT; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHFILEINFOA { + hIcon: HICON, + iIcon: c_int, + dwAttributes: DWORD, + szDisplayName: [CHAR; MAX_PATH], + szTypeName: [CHAR; 80], +}} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHFILEINFOW { + hIcon: HICON, + iIcon: c_int, + dwAttributes: DWORD, + szDisplayName: [WCHAR; MAX_PATH], + szTypeName: [WCHAR; 80], +}} +pub const SHGFI_ICON: DWORD = 0x000000100; +pub const SHGFI_DISPLAYNAME: DWORD = 0x000000200; +pub const SHGFI_TYPENAME: DWORD = 0x000000400; +pub const SHGFI_ATTRIBUTES: DWORD = 0x000000800; +pub const SHGFI_ICONLOCATION: DWORD = 0x000001000; +pub const SHGFI_EXETYPE: DWORD = 0x000002000; +pub const SHGFI_SYSICONINDEX: DWORD = 0x000004000; +pub const SHGFI_LINKOVERLAY: DWORD = 0x000008000; +pub const SHGFI_SELECTED: DWORD = 0x000010000; +pub const SHGFI_ATTR_SPECIFIED: DWORD = 0x000020000; +pub const SHGFI_LARGEICON: DWORD = 0x000000000; +pub const SHGFI_SMALLICON: DWORD = 0x000000001; +pub const SHGFI_OPENICON: DWORD = 0x000000002; +pub const SHGFI_SHELLICONSIZE: DWORD = 0x000000004; +pub const SHGFI_PIDL: DWORD = 0x000000008; +pub const SHGFI_USEFILEATTRIBUTES: DWORD = 0x000000010; +pub const SHGFI_ADDOVERLAYS: DWORD = 0x000000020; +pub const SHGFI_OVERLAYINDEX: DWORD = 0x000000040; +extern "system" { + pub fn SHGetFileInfoA( + pszPath: LPCSTR, + dwFileAttributes: DWORD, + psfi: *mut SHFILEINFOA, + cbFileInfo: UINT, + uFlags: UINT, + ) -> DWORD_PTR; + pub fn SHGetFileInfoW( + pszPath: LPCWSTR, + dwFileAttributes: DWORD, + psfi: *mut SHFILEINFOW, + cbFileInfo: UINT, + uFlags: UINT, + ) -> DWORD_PTR; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct SHSTOCKICONINFO { + cbSize: DWORD, + hIcon: HICON, + iSysImageIndex: c_int, + iIcon: c_int, + szPath: [WCHAR; MAX_PATH], +}} +pub const SHGSI_ICONLOCATION: DWORD = 0; +pub const SHGSI_ICON: DWORD = SHGFI_ICON; +pub const SHGSI_SYSICONINDEX: DWORD = SHGFI_SYSICONINDEX; +pub const SHGSI_LINKOVERLAY: DWORD = SHGFI_LINKOVERLAY; +pub const SHGSI_SELECTED: DWORD = SHGFI_SELECTED; +pub const SHGSI_LARGEICON: DWORD = SHGFI_LARGEICON; +pub const SHGSI_SMALLICON: DWORD = SHGFI_SMALLICON; +pub const SHGSI_SHELLICONSIZE: DWORD = SHGFI_SHELLICONSIZE; +ENUM!{enum SHSTOCKICONID { + SIID_DOCNOASSOC = 0, + SIID_DOCASSOC = 1, + SIID_APPLICATION = 2, + SIID_FOLDER = 3, + SIID_FOLDEROPEN = 4, + SIID_DRIVE525 = 5, + SIID_DRIVE35 = 6, + SIID_DRIVEREMOVE = 7, + SIID_DRIVEFIXED = 8, + SIID_DRIVENET = 9, + SIID_DRIVENETDISABLED = 10, + SIID_DRIVECD = 11, + SIID_DRIVERAM = 12, + SIID_WORLD = 13, + SIID_SERVER = 15, + SIID_PRINTER = 16, + SIID_MYNETWORK = 17, + SIID_FIND = 22, + SIID_HELP = 23, + SIID_SHARE = 28, + SIID_LINK = 29, + SIID_SLOWFILE = 30, + SIID_RECYCLER = 31, + SIID_RECYCLERFULL = 32, + SIID_MEDIACDAUDIO = 40, + SIID_LOCK = 47, + SIID_AUTOLIST = 49, + SIID_PRINTERNET = 50, + SIID_SERVERSHARE = 51, + SIID_PRINTERFAX = 52, + SIID_PRINTERFAXNET = 53, + SIID_PRINTERFILE = 54, + SIID_STACK = 55, + SIID_MEDIASVCD = 56, + SIID_STUFFEDFOLDER = 57, + SIID_DRIVEUNKNOWN = 58, + SIID_DRIVEDVD = 59, + SIID_MEDIADVD = 60, + SIID_MEDIADVDRAM = 61, + SIID_MEDIADVDRW = 62, + SIID_MEDIADVDR = 63, + SIID_MEDIADVDROM = 64, + SIID_MEDIACDAUDIOPLUS = 65, + SIID_MEDIACDRW = 66, + SIID_MEDIACDR = 67, + SIID_MEDIACDBURN = 68, + SIID_MEDIABLANKCD = 69, + SIID_MEDIACDROM = 70, + SIID_AUDIOFILES = 71, + SIID_IMAGEFILES = 72, + SIID_VIDEOFILES = 73, + SIID_MIXEDFILES = 74, + SIID_FOLDERBACK = 75, + SIID_FOLDERFRONT = 76, + SIID_SHIELD = 77, + SIID_WARNING = 78, + SIID_INFO = 79, + SIID_ERROR = 80, + SIID_KEY = 81, + SIID_SOFTWARE = 82, + SIID_RENAME = 83, + SIID_DELETE = 84, + SIID_MEDIAAUDIODVD = 85, + SIID_MEDIAMOVIEDVD = 86, + SIID_MEDIAENHANCEDCD = 87, + SIID_MEDIAENHANCEDDVD = 88, + SIID_MEDIAHDDVD = 89, + SIID_MEDIABLURAY = 90, + SIID_MEDIAVCD = 91, + SIID_MEDIADVDPLUSR = 92, + SIID_MEDIADVDPLUSRW = 93, + SIID_DESKTOPPC = 94, + SIID_MOBILEPC = 95, + SIID_USERS = 96, + SIID_MEDIASMARTMEDIA = 97, + SIID_MEDIACOMPACTFLASH = 98, + SIID_DEVICECELLPHONE = 99, + SIID_DEVICECAMERA = 100, + SIID_DEVICEVIDEOCAMERA = 101, + SIID_DEVICEAUDIOPLAYER = 102, + SIID_NETWORKCONNECT = 103, + SIID_INTERNET = 104, + SIID_ZIPFILE = 105, + SIID_SETTINGS = 106, + SIID_DRIVEHDDVD = 132, + SIID_DRIVEBD = 133, + SIID_MEDIAHDDVDROM = 134, + SIID_MEDIAHDDVDR = 135, + SIID_MEDIAHDDVDRAM = 136, + SIID_MEDIABDROM = 137, + SIID_MEDIABDR = 138, + SIID_MEDIABDRE = 139, + SIID_CLUSTEREDDRIVE = 140, + SIID_MAX_ICONS = 181, +}} +pub const SIID_INVALID: SHSTOCKICONID = -1i32 as u32; +extern "system" { + pub fn SHGetStockIconInfo( + siid: SHSTOCKICONID, + uFlags: UINT, + psii: *mut SHSTOCKICONINFO, + ) -> HRESULT; + pub fn SHGetDiskFreeSpaceExA( + pszDirectoryName: LPCSTR, + pulFreeBytesAvailableToCaller: *mut ULARGE_INTEGER, + pulTotalNumberOfBytes: *mut ULARGE_INTEGER, + pulTotalNumberOfFreeBytes: *mut ULARGE_INTEGER, + ) -> BOOL; + pub fn SHGetDiskFreeSpaceExW( + pszDirectoryName: LPCWSTR, + pulFreeBytesAvailableToCaller: *mut ULARGE_INTEGER, + pulTotalNumberOfBytes: *mut ULARGE_INTEGER, + pulTotalNumberOfFreeBytes: *mut ULARGE_INTEGER, + ) -> BOOL; + pub fn SHGetNewLinkInfoA( + pszLinkTo: LPCSTR, + pszDir: LPCSTR, + pszName: LPSTR, + pfMustCopy: *mut BOOL, + uFlags: UINT, + ) -> BOOL; + pub fn SHGetNewLinkInfoW( + pszLinkTo: LPCWSTR, + pszDir: LPCWSTR, + pszName: LPWSTR, + pfMustCopy: *mut BOOL, + uFlags: UINT, + ) -> BOOL; +} +pub const SHGNLI_PIDL: DWORD = 0x000000001; +pub const SHGNLI_PREFIXNAME: DWORD = 0x000000002; +pub const SHGNLI_NOUNIQUE: DWORD = 0x000000004; +pub const SHGNLI_NOLNK: DWORD = 0x000000008; +pub const SHGNLI_NOLOCNAME: DWORD = 0x000000010; +pub const SHGNLI_USEURLEXT: DWORD = 0x000000020; +pub const PRINTACTION_OPEN: DWORD = 0; +pub const PRINTACTION_PROPERTIES: DWORD = 1; +pub const PRINTACTION_NETINSTALL: DWORD = 2; +pub const PRINTACTION_NETINSTALLLINK: DWORD = 3; +pub const PRINTACTION_TESTPAGE: DWORD = 4; +pub const PRINTACTION_OPENNETPRN: DWORD = 5; +pub const PRINTACTION_DOCUMENTDEFAULTS: DWORD = 6; +pub const PRINTACTION_SERVERPROPERTIES: DWORD = 7; +extern "system" { + pub fn SHInvokePrinterCommandA( + hwnd: HWND, + uAction: UINT, + lpBuf1: LPCSTR, + lpBuf2: LPCSTR, + fModal: BOOL, + ) -> BOOL; + pub fn SHInvokePrinterCommandW( + hwnd: HWND, + uAction: UINT, + lpBuf1: LPCWSTR, + lpBuf2: LPCWSTR, + fModal: BOOL, + ) -> BOOL; +} +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPEN_PRINTER_PROPS_INFOA { + dwSize: DWORD, + pszSheetName: LPSTR, + uSheetIndex: UINT, + dwFlags: DWORD, + bModal: BOOL, +}} +pub type POPEN_PRINTER_PROPS_INFOA = *mut OPEN_PRINTER_PROPS_INFOA; +STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct OPEN_PRINTER_PROPS_INFOW { + dwSize: DWORD, + pszSheetName: LPWSTR, + uSheetIndex: UINT, + dwFlags: DWORD, + bModal: BOOL, +}} +pub type POPEN_PRINTER_PROPS_INFOW = *mut OPEN_PRINTER_PROPS_INFOW; +pub const PRINT_PROP_FORCE_NAME: DWORD = 0x01; +extern "system" { + pub fn SHLoadNonloadedIconOverlayIdentifiers() -> HRESULT; + pub fn SHIsFileAvailableOffline( + pwszPath: PCWSTR, + pdwStatus: *mut DWORD, + ) -> HRESULT; +} +pub const OFFLINE_STATUS_LOCAL: DWORD = 0x0001; +pub const OFFLINE_STATUS_REMOTE: DWORD = 0x0002; +pub const OFFLINE_STATUS_INCOMPLETE: DWORD = 0x0004; +extern "system" { + pub fn SHSetLocalizedName( + pszPath: PCWSTR, + pszResModule: PCWSTR, + idsRes: c_int, + ) -> HRESULT; + pub fn SHRemoveLocalizedName( + pszPath: PCWSTR, + ) -> HRESULT; + pub fn SHGetLocalizedName( + pszPath: PCWSTR, + pszResModule: PWSTR, + cch: UINT, + pidsRes: *mut c_int, + ) -> HRESULT; +} +extern "C" { + pub fn ShellMessageBoxA( + hAppInst: HINSTANCE, + hWnd: HWND, + lpcText: LPCSTR, + lpcTitle: LPCSTR, + fuStyle: UINT, + ... + ) -> c_int; + pub fn ShellMessageBoxW( + hAppInst: HINSTANCE, + hWnd: HWND, + lpcText: LPCWSTR, + lpcTitle: LPCWSTR, + fuStyle: UINT, + ... + ) -> c_int; +} +extern "system" { + pub fn IsLFNDriveA( + pszPath: LPCSTR, + ) -> BOOL; + pub fn IsLFNDriveW( + pszPath: LPCWSTR, + ) -> BOOL; + pub fn SHEnumerateUnreadMailAccountsA( + hKeyUser: HKEY, + dwIndex: DWORD, + pszMailAddress: LPSTR, + cchMailAddress: c_int, + ) -> HRESULT; + pub fn SHEnumerateUnreadMailAccountsW( + hKeyUser: HKEY, + dwIndex: DWORD, + pszMailAddress: LPWSTR, + cchMailAddress: c_int, + ) -> HRESULT; + pub fn SHGetUnreadMailCountA( + hKeyUser: HKEY, + pszMailAddress: LPCSTR, + pdwCount: *mut DWORD, + pFileTime: *mut FILETIME, + pszShellExecuteCommand: LPSTR, + cchShellExecuteCommand: c_int, + ) -> HRESULT; + pub fn SHGetUnreadMailCountW( + hKeyUser: HKEY, + pszMailAddress: LPCWSTR, + pdwCount: *mut DWORD, + pFileTime: *mut FILETIME, + pszShellExecuteCommand: LPWSTR, + cchShellExecuteCommand: c_int, + ) -> HRESULT; + pub fn SHSetUnreadMailCountA( + pszMailAddress: LPCSTR, + dwCount: DWORD, + pszShellExecuteCommand: LPCSTR, + ) -> HRESULT; + pub fn SHSetUnreadMailCountW( + pszMailAddress: LPCWSTR, + dwCount: DWORD, + pszShellExecuteCommand: LPCWSTR, + ) -> HRESULT; + pub fn SHTestTokenMembership( + hToken: HANDLE, + ulRID: ULONG, + ) -> BOOL; + pub fn SHGetImageList( + iImageList: c_int, + riid: REFIID, + ppvObj: *mut *mut c_void, + ) -> HRESULT; +} +pub const SHIL_LARGE: DWORD = 0; +pub const SHIL_SMALL: DWORD = 1; +pub const SHIL_EXTRALARGE: DWORD = 2; +pub const SHIL_SYSSMALL: DWORD = 3; +pub const SHIL_JUMBO: DWORD = 4; +pub const SHIL_LAST: DWORD = SHIL_JUMBO; +FN!{stdcall PFNCANSHAREFOLDERW( + pszPath: PCWSTR, +) -> HRESULT} +FN!{stdcall PFNSHOWSHAREFOLDERUIW( + hwndParent: HWND, + pszPath: PCWSTR, +) -> HRESULT} +pub const WC_NETADDRESS: &'static str = "msctls_netaddress"; +extern "system" { + pub fn InitNetworkAddressControl() -> BOOL; +} +// STRUCT!{struct NC_ADDRESS { +// pAddrInfo: *mut NET_ADDRESS_INFO, +// PortNumber: USHORT, +// PrefixLength: BYTE, +// }} +// pub type PNC_ADDRESS = *mut NC_ADDRESS; +extern "system" { + pub fn SHGetDriveMedia( + pszDrive: PCWSTR, + pdwMediaContent: *mut DWORD, + ) -> HRESULT; +} diff --git a/winapi/src/um/shellscalingapi.rs b/winapi/src/um/shellscalingapi.rs new file mode 100644 index 000000000..4db4ff6fe --- /dev/null +++ b/winapi/src/um/shellscalingapi.rs @@ -0,0 +1,44 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::UINT; +use shared::windef::HMONITOR; +use um::winnt::{HANDLE, HRESULT}; +ENUM!{enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2, +}} +ENUM!{enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI, +}} +extern "system" { + pub fn SetProcessDpiAwareness( + value: PROCESS_DPI_AWARENESS, + ) -> HRESULT; + pub fn GetProcessDpiAwareness( + hProcess: HANDLE, + value: *mut PROCESS_DPI_AWARENESS, + ) -> HRESULT; + pub fn GetDpiForMonitor( + hmonitor: HMONITOR, + dpiType: MONITOR_DPI_TYPE, + dpiX: *mut UINT, + dpiY: *mut UINT, + ) -> HRESULT; +} +ENUM!{enum SHELL_UI_COMPONENT { + SHELL_UI_COMPONENT_TASKBARS = 0, + SHELL_UI_COMPONENT_NOTIFICATIONAREA = 1, + SHELL_UI_COMPONENT_DESKBAND = 2, +}} +extern "system" { + pub fn GetDpiForShellUIComponent( + component: SHELL_UI_COMPONENT, + ) -> UINT; +} diff --git a/winapi/src/um/shlobj.rs b/winapi/src/um/shlobj.rs new file mode 100644 index 000000000..f652c6c2d --- /dev/null +++ b/winapi/src/um/shlobj.rs @@ -0,0 +1,260 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_int, c_void}; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, DWORD, UINT}; +use shared::windef::HWND; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::shtypes::{PCIDLIST_ABSOLUTE, PCUITEMID_CHILD_ARRAY, PIDLIST_ABSOLUTE, REFKNOWNFOLDERID}; +use um::winnt::{HANDLE, HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCWSTR, PWSTR}; +pub const IDO_SHGIOI_SHARE: c_int = 0x0FFFFFFF; +pub const IDO_SHGIOI_LINK: c_int = 0x0FFFFFFE; +// Yes, these values are supposed to be 9 digits +pub const IDO_SHGIOI_SLOWFILE: c_int = 0x0FFFFFFFD; +pub const IDO_SHGIOI_DEFAULT: c_int = 0x0FFFFFFFC; +extern "system" { + pub fn SHGetIconOverlayIndexA( + pszIconPath: LPCSTR, + iIconIndex: c_int, + ) -> c_int; + pub fn SHGetIconOverlayIndexW( + pszIconPath: LPCWSTR, + iIconIndex: c_int, + ) -> c_int; +} +pub const GPFIDL_DEFAULT: GPFIDL_FLAGS = 0x0000; +pub const GPFIDL_ALTNAME: GPFIDL_FLAGS = 0x0001; +pub const GPFIDL_UNCPRINTER: GPFIDL_FLAGS = 0x0002; +pub type GPFIDL_FLAGS = c_int; +extern "system" { + pub fn SHGetPathFromIDListEx( + pidl: PCIDLIST_ABSOLUTE, + pszPath: PWSTR, + cchPath: DWORD, + uOpts: GPFIDL_FLAGS, + ) -> BOOL; + pub fn SHGetPathFromIDListA( + pidl: PCIDLIST_ABSOLUTE, + pszPath: LPSTR, + ) -> BOOL; + pub fn SHGetPathFromIDListW( + pidl: PCIDLIST_ABSOLUTE, + pszPath: LPWSTR, + ) -> BOOL; + pub fn SHCreateDirectory( + hwnd: HWND, + pszPath: PCWSTR, + ) -> c_int; + pub fn SHCreateDirectoryExA( + hwnd: HWND, + pszPath: LPCSTR, + psa: *const SECURITY_ATTRIBUTES, + ) -> c_int; + pub fn SHCreateDirectoryExW( + hwnd: HWND, + pszPath: LPCWSTR, + psa: *const SECURITY_ATTRIBUTES, + ) -> c_int; +} +pub const OFASI_EDIT: DWORD = 0x0001; +pub const OFASI_OPENDESKTOP: DWORD = 0x0002; +extern "system" { + pub fn SHOpenFolderAndSelectItems( + pidlFolder: PCIDLIST_ABSOLUTE, + cidl: UINT, + apidl: PCUITEMID_CHILD_ARRAY, + dwFlags: DWORD, + ) -> HRESULT; + //pub fn SHCreateShellItem( + // pidlParent: PCIDLIST_ABSOLUTE, + // psfParent: *mut IShellFolder, + // pidl: PCUITEMID_CHILD, + // ppsi: *mut *mut IShellItem, + //) -> HRESULT; +} +pub const CSIDL_DESKTOP: c_int = 0x0000; +pub const CSIDL_INTERNET: c_int = 0x0001; +pub const CSIDL_PROGRAMS: c_int = 0x0002; +pub const CSIDL_CONTROLS: c_int = 0x0003; +pub const CSIDL_PRINTERS: c_int = 0x0004; +pub const CSIDL_PERSONAL: c_int = 0x0005; +pub const CSIDL_FAVORITES: c_int = 0x0006; +pub const CSIDL_STARTUP: c_int = 0x0007; +pub const CSIDL_RECENT: c_int = 0x0008; +pub const CSIDL_SENDTO: c_int = 0x0009; +pub const CSIDL_BITBUCKET: c_int = 0x000a; +pub const CSIDL_STARTMENU: c_int = 0x000b; +pub const CSIDL_MYDOCUMENTS: c_int = CSIDL_PERSONAL; +pub const CSIDL_MYMUSIC: c_int = 0x000d; +pub const CSIDL_MYVIDEO: c_int = 0x000e; +pub const CSIDL_DESKTOPDIRECTORY: c_int = 0x0010; +pub const CSIDL_DRIVES: c_int = 0x0011; +pub const CSIDL_NETWORK: c_int = 0x0012; +pub const CSIDL_NETHOOD: c_int = 0x0013; +pub const CSIDL_FONTS: c_int = 0x0014; +pub const CSIDL_TEMPLATES: c_int = 0x0015; +pub const CSIDL_COMMON_STARTMENU: c_int = 0x0016; +pub const CSIDL_COMMON_PROGRAMS: c_int = 0x0017; +pub const CSIDL_COMMON_STARTUP: c_int = 0x0018; +pub const CSIDL_COMMON_DESKTOPDIRECTORY: c_int = 0x0019; +pub const CSIDL_APPDATA: c_int = 0x001a; +pub const CSIDL_PRINTHOOD: c_int = 0x001b; +pub const CSIDL_LOCAL_APPDATA: c_int = 0x001c; +pub const CSIDL_ALTSTARTUP: c_int = 0x001d; +pub const CSIDL_COMMON_ALTSTARTUP: c_int = 0x001e; +pub const CSIDL_COMMON_FAVORITES: c_int = 0x001f; +pub const CSIDL_INTERNET_CACHE: c_int = 0x0020; +pub const CSIDL_COOKIES: c_int = 0x0021; +pub const CSIDL_HISTORY: c_int = 0x0022; +pub const CSIDL_COMMON_APPDATA: c_int = 0x0023; +pub const CSIDL_WINDOWS: c_int = 0x0024; +pub const CSIDL_SYSTEM: c_int = 0x0025; +pub const CSIDL_PROGRAM_FILES: c_int = 0x0026; +pub const CSIDL_MYPICTURES: c_int = 0x0027; +pub const CSIDL_PROFILE: c_int = 0x0028; +pub const CSIDL_SYSTEMX86: c_int = 0x0029; +pub const CSIDL_PROGRAM_FILESX86: c_int = 0x002a; +pub const CSIDL_PROGRAM_FILES_COMMON: c_int = 0x002b; +pub const CSIDL_PROGRAM_FILES_COMMONX86: c_int = 0x002c; +pub const CSIDL_COMMON_TEMPLATES: c_int = 0x002d; +pub const CSIDL_COMMON_DOCUMENTS: c_int = 0x002e; +pub const CSIDL_COMMON_ADMINTOOLS: c_int = 0x002f; +pub const CSIDL_ADMINTOOLS: c_int = 0x0030; +pub const CSIDL_CONNECTIONS: c_int = 0x0031; +pub const CSIDL_COMMON_MUSIC: c_int = 0x0035; +pub const CSIDL_COMMON_PICTURES: c_int = 0x0036; +pub const CSIDL_COMMON_VIDEO: c_int = 0x0037; +pub const CSIDL_RESOURCES: c_int = 0x0038; +pub const CSIDL_RESOURCES_LOCALIZED: c_int = 0x0039; +pub const CSIDL_COMMON_OEM_LINKS: c_int = 0x003a; +pub const CSIDL_CDBURN_AREA: c_int = 0x003b; +pub const CSIDL_COMPUTERSNEARME: c_int = 0x003d; +pub const CSIDL_FLAG_CREATE: c_int = 0x8000; +pub const CSIDL_FLAG_DONT_VERIFY: c_int = 0x4000; +pub const CSIDL_FLAG_DONT_UNEXPAND: c_int = 0x2000; +pub const CSIDL_FLAG_NO_ALIAS: c_int = 0x1000; +pub const CSIDL_FLAG_PER_USER_INIT: c_int = 0x0800; +pub const CSIDL_FLAG_MASK: c_int = 0xff00; +extern "system" { + pub fn SHGetSpecialFolderLocation( + hwnd: HWND, + csidl: c_int, + ppidl: *mut PIDLIST_ABSOLUTE, + ) -> HRESULT; + pub fn SHCloneSpecialIDList( + hwnd: HWND, + csidl: c_int, + fCreate: BOOL, + ) -> PIDLIST_ABSOLUTE; + pub fn SHGetSpecialFolderPathA( + hwnd: HWND, + pszPath: LPSTR, + csidl: c_int, + fCreate: BOOL, + ) -> BOOL; + pub fn SHGetSpecialFolderPathW( + hwnd: HWND, + pszPath: LPWSTR, + csidl: c_int, + fCreate: BOOL, + ) -> BOOL; + pub fn SHFlushSFCache(); +} +ENUM!{enum SHGFP_TYPE { + SHGFP_TYPE_CURRENT = 0, + SHGFP_TYPE_DEFAULT = 1, +}} +extern "system" { + pub fn SHGetFolderPathA( + hwnd: HWND, + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszPath: LPSTR, + ) -> HRESULT; + pub fn SHGetFolderPathW( + hwnd: HWND, + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszPath: LPWSTR, + ) -> HRESULT; + pub fn SHGetFolderLocation( + hwnd: HWND, + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + ppidl: *mut PIDLIST_ABSOLUTE, + ) -> HRESULT; + pub fn SHSetFolderPathA( + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszPath: LPCSTR, + ) -> HRESULT; + pub fn SHSetFolderPathW( + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszPath: LPCWSTR, + ) -> HRESULT; + pub fn SHGetFolderPathAndSubDirA( + hwnd: HWND, + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszSubDir: LPCSTR, + pszPath: LPSTR, + ) -> HRESULT; + pub fn SHGetFolderPathAndSubDirW( + hwnd: HWND, + csidl: c_int, + hToken: HANDLE, + dwFlags: DWORD, + pszSubDir: LPCWSTR, + pszPath: LPWSTR, + ) -> HRESULT; +} +ENUM!{enum KNOWN_FOLDER_FLAG { + KF_FLAG_DEFAULT = 0x00000000, + KF_FLAG_NO_APPCONTAINER_REDIRECTION = 0x00010000, + KF_FLAG_CREATE = 0x00008000, + KF_FLAG_DONT_VERIFY = 0x00004000, + KF_FLAG_DONT_UNEXPAND = 0x00002000, + KF_FLAG_NO_ALIAS = 0x00001000, + KF_FLAG_INIT = 0x00000800, + KF_FLAG_DEFAULT_PATH = 0x00000400, + KF_FLAG_NOT_PARENT_RELATIVE = 0x00000200, + KF_FLAG_SIMPLE_IDLIST = 0x00000100, + KF_FLAG_ALIAS_ONLY = 0x80000000, +}} +extern "system" { + pub fn SHGetKnownFolderIDList( + rfid: REFKNOWNFOLDERID, + dwFlags: DWORD, + hToken: HANDLE, + ppidl: *mut PIDLIST_ABSOLUTE, + ) -> HRESULT; + pub fn SHSetKnownFolderPath( + rfid: REFKNOWNFOLDERID, + dwFlags: DWORD, + hToken: HANDLE, + pszPath: PCWSTR, + ) -> HRESULT; + pub fn SHGetKnownFolderPath( + rfid: REFKNOWNFOLDERID, + dwFlags: DWORD, + hToken: HANDLE, + pszPath: *mut PWSTR, + ) -> HRESULT; + pub fn SHGetKnownFolderItem( + rfid: REFKNOWNFOLDERID, + flags: KNOWN_FOLDER_FLAG, + hToken: HANDLE, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT; +} diff --git a/winapi/src/um/shobjidl.rs b/winapi/src/um/shobjidl.rs new file mode 100644 index 000000000..7db441224 --- /dev/null +++ b/winapi/src/um/shobjidl.rs @@ -0,0 +1,373 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::guiddef::{REFGUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, UINT}; +use shared::windef::HWND; +use um::objidl::IBindCtx; +use um::propkeydef::REFPROPERTYKEY; +use um::propsys::{GETPROPERTYSTOREFLAGS, IPropertyDescriptionList, IPropertyStore}; +use um::shobjidl_core::{IModalWindow, IModalWindowVtbl, IShellItem, IShellItemFilter, SFGAOF}; +use um::shtypes::COMDLG_FILTERSPEC; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, WCHAR}; +pub type IFileOperationProgressSink = IUnknown; // TODO +ENUM!{enum SIATTRIBFLAGS { + SIATTRIBFLAGS_AND = 0x1, + SIATTRIBFLAGS_OR = 0x2, + SIATTRIBFLAGS_APPCOMPAT = 0x3, + SIATTRIBFLAGS_MASK = 0x3, + SIATTRIBFLAGS_ALLITEMS = 0x4000, +}} +RIDL!{#[uuid(0xb63ea76d, 0x1f85, 0x456f, 0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b)] +interface IShellItemArray(IShellItemArrayVtbl): IUnknown(IUnknownVtbl) { + fn BindToHandler( + pbc: *mut IBindCtx, + bhid: REFGUID, + riid: REFIID, + ppvOut: *mut *mut c_void, + ) -> HRESULT, + fn GetPropertyStore( + flags: GETPROPERTYSTOREFLAGS, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn GetPropertyDescriptionList( + keyType: REFPROPERTYKEY, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn GetAttributes( + AttribFlags: SIATTRIBFLAGS, + sfgaoMask: SFGAOF, + psfgaoAttribs: *mut SFGAOF, + ) -> HRESULT, + fn GetCount( + pdwNumItems: *mut DWORD, + ) -> HRESULT, + fn GetItemAt( + dwIndex: DWORD, + ppsi: *mut *mut IShellItem, + ) -> HRESULT, + // TODO: Add IEnumShellItems + //fn EnumItems( + // ppenumShellItems: *mut *mut IEnumShellItems, + //) -> HRESULT, +}} +ENUM!{enum FDE_OVERWRITE_RESPONSE { + FDEOR_DEFAULT = 0, + FDEOR_ACCEPT = 1, + FDEOR_REFUSE = 2, +}} +ENUM!{enum FDE_SHAREVIOLATION_RESPONSE { + FDESVR_DEFAULT = 0, + FDESVR_ACCEPT = 1, + FDESVR_REFUSE = 2, +}} +ENUM!{enum FDAP { + FDAP_BOTTOM = 0, + FDAP_TOP = 1, +}} +RIDL!{#[uuid(0x973510db, 0x7d7f, 0x452b, 0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54)] +interface IFileDialogEvents(IFileDialogEventsVtbl): IUnknown(IUnknownVtbl) { + fn OnFileOk( + pfd: *mut IFileDialog, + ) -> HRESULT, + fn OnFolderChanging( + pfd: *mut IFileDialog, + psiFolder: *mut IShellItem, + ) -> HRESULT, + fn OnFolderChange( + pfd: *mut IFileDialog, + ) -> HRESULT, + fn OnSelectionChange( + pfd: *mut IFileDialog, + ) -> HRESULT, + fn OnShareViolation( + pfd: *mut IFileDialog, + psi: *mut IShellItem, + pResponse: *mut FDE_SHAREVIOLATION_RESPONSE, + ) -> HRESULT, + fn OnTypeChange( + pfd: *mut IFileDialog, + ) -> HRESULT, + fn OnOverwrite( + pfd: *mut IFileDialog, + psi: *mut IShellItem, + pResponse: *mut FDE_OVERWRITE_RESPONSE, + ) -> HRESULT, +}} +ENUM!{enum FILEOPENDIALOGOPTIONS { + FOS_OVERWRITEPROMPT = 0x2, + FOS_STRICTFILETYPES = 0x4, + FOS_NOCHANGEDIR = 0x8, + FOS_PICKFOLDERS = 0x20, + FOS_FORCEFILESYSTEM = 0x40, + FOS_ALLNONSTORAGEITEMS = 0x80, + FOS_NOVALIDATE = 0x100, + FOS_ALLOWMULTISELECT = 0x200, + FOS_PATHMUSTEXIST = 0x800, + FOS_FILEMUSTEXIST = 0x1000, + FOS_CREATEPROMPT = 0x2000, + FOS_SHAREAWARE = 0x4000, + FOS_NOREADONLYRETURN = 0x8000, + FOS_NOTESTFILECREATE = 0x10000, + FOS_HIDEMRUPLACES = 0x20000, + FOS_HIDEPINNEDPLACES = 0x40000, + FOS_NODEREFERENCELINKS = 0x100000, + FOS_DONTADDTORECENT = 0x2000000, + FOS_FORCESHOWHIDDEN = 0x10000000, + FOS_DEFAULTNOMINIMODE = 0x20000000, + FOS_FORCEPREVIEWPANEON = 0x40000000, + FOS_SUPPORTSTREAMABLEITEMS = 0x80000000, +}} +RIDL!{#[uuid(0x42f85136, 0xdb7e, 0x439c, 0x85, 0xf1, 0xe4, 0x07, 0x5d, 0x13, 0x5f, 0xc8)] +interface IFileDialog(IFileDialogVtbl): IModalWindow(IModalWindowVtbl) { + fn SetFileTypes( + cFileTypes: UINT, + rgFilterSpec: *const COMDLG_FILTERSPEC, + ) -> HRESULT, + fn SetFileTypeIndex( + iFileType: UINT, + ) -> HRESULT, + fn GetFileTypeIndex( + piFileType: *mut UINT, + ) -> HRESULT, + fn Advise( + pfde: *mut IFileDialogEvents, + pdwCookie: *mut DWORD, + ) -> HRESULT, + fn Unadvise( + dwCookie: DWORD, + ) -> HRESULT, + fn SetOptions( + fos: FILEOPENDIALOGOPTIONS, + ) -> HRESULT, + fn GetOptions( + pfos: *mut FILEOPENDIALOGOPTIONS, + ) -> HRESULT, + fn SetDefaultFolder( + psi: *mut IShellItem, + ) -> HRESULT, + fn SetFolder( + psi: *mut IShellItem, + ) -> HRESULT, + fn GetFolder( + ppsi: *mut *mut IShellItem, + ) -> HRESULT, + fn GetCurrentSelection( + ppsi: *mut *mut IShellItem, + ) -> HRESULT, + fn SetFileName( + pszName: LPCWSTR, + ) -> HRESULT, + fn GetFileName( + pszName: *mut LPWSTR, + ) -> HRESULT, + fn SetTitle( + pszTitle: LPCWSTR, + ) -> HRESULT, + fn SetOkButtonLabel( + pszText: LPCWSTR, + ) -> HRESULT, + fn SetFileNameLabel( + pszLabel: LPCWSTR, + ) -> HRESULT, + fn GetResult( + ppsi: *mut *mut IShellItem, + ) -> HRESULT, + fn AddPlace( + psi: *mut IShellItem, + fdap: FDAP, + ) -> HRESULT, + fn SetDefaultExtension( + pszDefaultExtension: LPCWSTR, + ) -> HRESULT, + fn Close( + hr: HRESULT, + ) -> HRESULT, + fn SetClientGuid( + guid: REFGUID, + ) -> HRESULT, + fn ClearClientData() -> HRESULT, + fn SetFilter( + pFilter: *mut IShellItemFilter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x84bccd23, 0x5fde, 0x4cdb, 0xae, 0xa4, 0xaf, 0x64, 0xb8, 0x3d, 0x78, 0xab)] +interface IFileSaveDialog(IFileSaveDialogVtbl): IFileDialog(IFileDialogVtbl) { + fn SetSaveAsItem( + psi: *mut IShellItem, + ) -> HRESULT, + fn SetProperties( + pStore: *mut IPropertyStore, + ) -> HRESULT, + fn SetCollectedProperties( + pList: *mut IPropertyDescriptionList, + fAppendDefault: BOOL, + ) -> HRESULT, + fn GetProperties( + ppStore: *mut *mut IPropertyStore, + ) -> HRESULT, + fn ApplyProperties( + psi: *mut IShellItem, + pStore: *mut IPropertyStore, + hwnd: HWND, + pSink: *mut IFileOperationProgressSink, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd57c7288, 0xd4ad, 0x4768, 0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60)] +interface IFileOpenDialog(IFileOpenDialogVtbl): IFileDialog(IFileDialogVtbl) { + fn GetResults( + ppenum: *mut *mut IShellItemArray, + ) -> HRESULT, + fn GetSelectedItems( + ppsai: *mut *mut IShellItemArray, + ) -> HRESULT, +}} +ENUM!{enum CDCONTROLSTATEF { + CDCS_INACTIVE = 0, + CDCS_ENABLED = 0x1, + CDCS_VISIBLE = 0x2, + CDCS_ENABLEDVISIBLE = 0x3, +}} +RIDL!{#[uuid(0xe6fdd21a, 0x163f, 0x4975, 0x9c, 0x8c, 0xa6, 0x9f, 0x1b, 0xa3, 0x70, 0x34)] +interface IFileDialogCustomize(IFileDialogCustomizeVtbl): IUnknown(IUnknownVtbl) { + fn EnableOpenDropDown( + dwIDCtl: DWORD, + ) -> HRESULT, + fn AddMenu( + dwIDCtl: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, + fn AddPushButton( + dwIDCtl: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, + fn AddComboBox( + dwIDCtl: DWORD, + ) -> HRESULT, + fn AddRadioButtonList( + dwIDCtl: DWORD, + ) -> HRESULT, + fn AddCheckButton( + dwIDCtl: DWORD, + pszLabel: LPCWSTR, + bChecked: BOOL, + ) -> HRESULT, + fn AddEditBox( + dwIDCtl: DWORD, + pszText: LPCWSTR, + ) -> HRESULT, + fn AddSeparator( + dwIDCtl: DWORD, + ) -> HRESULT, + fn AddText( + dwIDCtl: DWORD, + pszText: LPCWSTR, + ) -> HRESULT, + fn SetControlLabel( + dwIDCtl: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, + fn GetControlState( + dwIDCtl: DWORD, + pdwState: *mut CDCONTROLSTATEF, + ) -> HRESULT, + fn SetControlState( + dwIDCtl: DWORD, + dwState: CDCONTROLSTATEF, + ) -> HRESULT, + fn GetEditBoxText( + dwIDCtl: DWORD, + ppszText: *mut *mut WCHAR, + ) -> HRESULT, + fn SetEditBoxText( + dwIDCtl: DWORD, + pszText: LPCWSTR, + ) -> HRESULT, + fn GetCheckButtonState( + dwIDCtl: DWORD, + pbChecked: *mut BOOL, + ) -> HRESULT, + fn SetCheckButtonState( + dwIDCtl: DWORD, + bChecked: BOOL, + ) -> HRESULT, + fn AddControlItem( + dwIDCtl: DWORD, + dwIDItem: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, + fn RemoveControlItem( + dwIDCtl: DWORD, + dwIDItem: DWORD, + ) -> HRESULT, + fn RemoveAllControlItems( + dwIDCtl: DWORD, + ) -> HRESULT, + fn GetControlItemState( + dwIDCtl: DWORD, + dwIDItem: DWORD, + pdwState: *mut CDCONTROLSTATEF, + ) -> HRESULT, + fn SetControlItemState( + dwIDCtl: DWORD, + dwIDItem: DWORD, + dwState: CDCONTROLSTATEF, + ) -> HRESULT, + fn GetSelectedControlItem( + dwIDCtl: DWORD, + pdwIDItem: *mut DWORD, + ) -> HRESULT, + fn SetSelectedControlItem( + dwIDCtl: DWORD, + dwIDItem: DWORD, + ) -> HRESULT, + fn StartVisualGroup( + dwIDCtl: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, + fn EndVisualGroup() -> HRESULT, + fn MakeProminent( + dwIDCtl: DWORD, + ) -> HRESULT, + fn SetControlItemText( + dwIDCtl: DWORD, + dwIDItem: DWORD, + pszLabel: LPCWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x36116642, 0xd713, 0x4b97, 0x9b, 0x83, 0x74, 0x84, 0xa9, 0xd0, 0x04, 0x33)] +interface IFileDialogControlEvents(IFileDialogControlEventsVtbl): IUnknown(IUnknownVtbl) { + fn OnItemSelected( + pfdc: *mut IFileDialogCustomize, + dwIDCtl: DWORD, + dwIDItem: DWORD, + ) -> HRESULT, + fn OnButtonClicked( + pfdc: *mut IFileDialogCustomize, + dwIDCtl: DWORD, + ) -> HRESULT, + fn OnCheckButtonToggled( + pfdc: *mut IFileDialogCustomize, + dwIDCtl: DWORD, + bChecked: BOOL, + ) -> HRESULT, + fn OnControlActivating( + pfdc: *mut IFileDialogCustomize, + dwIDCtl: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x61744fc7, 0x85b5, 0x4791, 0xa9, 0xb0, 0x27, 0x22, 0x76, 0x30, 0x9b, 0x13)] +interface IFileDialog2(IFileDialog2Vtbl): IFileDialog(IFileDialogVtbl) { + fn SetCancelButtonLabel( + pszLabel: LPCWSTR, + ) -> HRESULT, + fn SetNavigationRoot( + psi: IShellItem, + ) -> HRESULT, +}} diff --git a/winapi/src/um/shobjidl_core.rs b/winapi/src/um/shobjidl_core.rs new file mode 100644 index 000000000..ef17f2295 --- /dev/null +++ b/winapi/src/um/shobjidl_core.rs @@ -0,0 +1,306 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_int, c_void}; +use shared::guiddef::{REFGUID, REFIID}; +use shared::minwindef::{BOOL, DWORD, UINT, ULONG, WORD}; +use shared::windef::{HICON, HWND, RECT}; +use um::commctrl::HIMAGELIST; +use um::objidl::IBindCtx; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR, LPWSTR, ULONGLONG, WCHAR}; +DEFINE_GUID!{CLSID_TaskbarList, + 0x56fdf344, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90} +DEFINE_GUID!{CLSID_FileOpenDialog, + 0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} +DEFINE_GUID!{CLSID_FileSaveDialog, + 0xc0b4e2f3, 0xba21, 0x4773, 0x8d, 0xba, 0x33, 0x5e, 0xc9, 0x46, 0xeb, 0x8b} +//4498 +ENUM!{enum SHCONTF { + SHCONTF_CHECKING_FOR_CHILDREN = 0x10, + SHCONTF_FOLDERS = 0x20, + SHCONTF_NONFOLDERS = 0x40, + SHCONTF_INCLUDEHIDDEN = 0x80, + SHCONTF_INIT_ON_FIRST_NEXT = 0x100, + SHCONTF_NETPRINTERSRCH = 0x200, + SHCONTF_SHAREABLE = 0x400, + SHCONTF_STORAGE = 0x800, + SHCONTF_NAVIGATION_ENUM = 0x1000, + SHCONTF_FASTITEMS = 0x2000, + SHCONTF_FLATLIST = 0x4000, + SHCONTF_ENABLE_ASYNC = 0x8000, + SHCONTF_INCLUDESUPERHIDDEN = 0x10000, +}} +pub type SFGAOF = ULONG; +//9466 +ENUM!{enum SIGDN { + SIGDN_NORMALDISPLAY = 0, + SIGDN_PARENTRELATIVEPARSING = 0x80018001, + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, + SIGDN_PARENTRELATIVEEDITING = 0x80031001, + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, + SIGDN_FILESYSPATH = 0x80058000, + SIGDN_URL = 0x80068000, + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, + SIGDN_PARENTRELATIVE = 0x80080001, + SIGDN_PARENTRELATIVEFORUI = 0x80094001, +}} +ENUM!{enum SICHINTF { + SICHINT_DISPLAY = 0, + SICHINT_ALLFIELDS = 0x80000000, + SICHINT_CANONICAL = 0x10000000, + SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, +}} +RIDL!{#[uuid(0x43826d1e, 0xe718, 0x42ee, 0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe)] +interface IShellItem(IShellItemVtbl): IUnknown(IUnknownVtbl) { + fn BindToHandler( + pbc: *mut IBindCtx, + bhid: REFGUID, + riid: REFIID, + ppv: *mut *mut c_void, + ) -> HRESULT, + fn GetParent( + ppsi: *mut *mut IShellItem, + ) -> HRESULT, + fn GetDisplayName( + sigdnName: SIGDN, + ppszName: *mut LPWSTR, + ) -> HRESULT, + fn GetAttributes( + sfgaoMask: SFGAOF, + psfgaoAttribs: *mut SFGAOF, + ) -> HRESULT, + fn Compare( + psi: *mut IShellItem, + hint: SICHINTF, + piOrder: *mut c_int, + ) -> HRESULT, +}} +//20869 +RIDL!{#[uuid(0xb4db1657, 0x70d7, 0x485e, 0x8e, 0x3e, 0x6f, 0xcb, 0x5a, 0x5c, 0x18, 0x02)] +interface IModalWindow(IModalWindowVtbl): IUnknown(IUnknownVtbl) { + fn Show( + hwndOwner: HWND, + ) -> HRESULT, +}} +//22307 +//27457 +RIDL!{#[uuid(0x2659b475, 0xeeb8, 0x48b7, 0x8f, 0x07, 0xb3, 0x78, 0x81, 0x0f, 0x48, 0xcf)] +interface IShellItemFilter(IShellItemFilterVtbl): IUnknown(IUnknownVtbl) { + fn IncludeItem( + psi: *mut IShellItem, + ) -> HRESULT, + fn GetEnumFlagsForItem( + psi: *mut IShellItem, + pgrfFlags: *mut SHCONTF, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x56fdf342, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90)] +interface ITaskbarList(ITaskbarListVtbl): IUnknown(IUnknownVtbl) { + fn HrInit() -> HRESULT, + fn AddTab( + hwnd: HWND, + ) -> HRESULT, + fn DeleteTab( + hwnd: HWND, + ) -> HRESULT, + fn ActivateTab( + hwnd: HWND, + ) -> HRESULT, + fn SetActiveAlt( + hwnd: HWND, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x602d4995, 0xb13a, 0x429b, 0xa6, 0x6e, 0x19, 0x35, 0xe4, 0x4f, 0x43, 0x17)] +interface ITaskbarList2(ITaskbarList2Vtbl): ITaskbarList(ITaskbarListVtbl) { + fn MarkFullscreenWindow( + hwnd: HWND, + fFullscreen: BOOL, + ) -> HRESULT, +}} +ENUM!{enum THUMBBUTTONFLAGS { + THBF_ENABLED = 0, + THBF_DISABLED = 0x1, + THBF_DISMISSONCLICK = 0x2, + THBF_NOBACKGROUND = 0x4, + THBF_HIDDEN = 0x8, + THBF_NONINTERACTIVE = 0x10, +}} +ENUM!{enum THUMBBUTTONMASK { + THB_BITMAP = 0x1, + THB_ICON = 0x2, + THB_TOOLTIP = 0x4, + THB_FLAGS = 0x8, +}} +STRUCT!{struct THUMBBUTTON { + dwMask: THUMBBUTTONMASK, + iId: UINT, + iBitmap: UINT, + hIcon: HICON, + szTip: [WCHAR; 260], + dwFlags: THUMBBUTTONFLAGS, +}} +pub type LPTHUMBBUTTON = *mut THUMBBUTTON; +pub const THBN_CLICKED: WORD = 0x1800; +ENUM!{enum TBPFLAG { + TBPF_NOPROGRESS = 0, + TBPF_INDETERMINATE = 0x1, + TBPF_NORMAL = 0x2, + TBPF_ERROR = 0x4, + TBPF_PAUSED = 0x8, +}} +RIDL!{#[uuid(0xea1afb91, 0x9e28, 0x4b86, 0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf)] +interface ITaskbarList3(ITaskbarList3Vtbl): ITaskbarList2(ITaskbarList2Vtbl) { + fn SetProgressValue( + hwnd: HWND, + ullCompleted: ULONGLONG, + ullTotal: ULONGLONG, + ) -> HRESULT, + fn SetProgressState( + hwnd: HWND, + tbpFlags: TBPFLAG, + ) -> HRESULT, + fn RegisterTab( + hwndTab: HWND, + hwndMDI: HWND, + ) -> HRESULT, + fn UnregisterTab( + hwndTab: HWND, + ) -> HRESULT, + fn SetTabOrder( + hwndTab: HWND, + hwndInsertBefore: HWND, + ) -> HRESULT, + fn SetTabActive( + hwndTab: HWND, + hwndMDI: HWND, + dwReserved: DWORD, + ) -> HRESULT, + fn ThumbBarAddButtons( + hwnd: HWND, + cButtons: UINT, + pButton: LPTHUMBBUTTON, + ) -> HRESULT, + fn ThumbBarUpdateButtons( + hwnd: HWND, + cButtons: UINT, + pButton: LPTHUMBBUTTON, + ) -> HRESULT, + fn ThumbBarSetImageList( + hwnd: HWND, + himl: HIMAGELIST, + ) -> HRESULT, + fn SetOverlayIcon( + hwnd: HWND, + hIcon: HICON, + pszDescription: LPCWSTR, + ) -> HRESULT, + fn SetThumbnailTooltip( + hwnd: HWND, + pszTip: LPCWSTR, + ) -> HRESULT, + fn SetThumbnailClip( + hwnd: HWND, + prcClip: *mut RECT, + ) -> HRESULT, +}} +ENUM!{enum STPFLAG { + STPF_NONE = 0, + STPF_USEAPPTHUMBNAILALWAYS = 0x1, + STPF_USEAPPTHUMBNAILWHENACTIVE = 0x2, + STPF_USEAPPPEEKALWAYS = 0x4, + STPF_USEAPPPEEKWHENACTIVE = 0x8, +}} +RIDL!{#[uuid(0xc43dc798, 0x95d1, 0x4bea, 0x90, 0x30, 0xbb, 0x99, 0xe2, 0x98, 0x3a, 0x1a)] +interface ITaskbarList4(ITaskbarList4Vtbl): ITaskbarList3(ITaskbarList3Vtbl) { + fn SetTabProperties( + hwndTab: HWND, + stpFlags: STPFLAG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc2cf3110, 0x460e, 0x4fc1, 0xb9, 0xd0, 0x8a, 0x1c, 0x0c, 0x9c, 0xc4, 0xbd)] +class DesktopWallpaper;} +RIDL!{#[uuid(0x00021400, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +class ShellDesktop;} +RIDL!{#[uuid(0xf3364ba0, 0x65b9, 0x11ce, 0xa9, 0xba, 0x00, 0xaa, 0x00, 0x4a, 0xe8, 0x37)] +class ShellFSFolder;} +RIDL!{#[uuid(0x208d2c60, 0x3aea, 0x1069, 0xa2, 0xd7, 0x08, 0x00, 0x2b, 0x30, 0x30, 0x9d)] +class NetworkPlaces;} +RIDL!{#[uuid(0x00021401, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +class ShellLink;} +RIDL!{#[uuid(0x94357b53, 0xca29, 0x4b78, 0x83, 0xae, 0xe8, 0xfe, 0x74, 0x09, 0x13, 0x4f)] +class DriveSizeCategorizer;} +RIDL!{#[uuid(0xb0a8f3cf, 0x4333, 0x4bab, 0x88, 0x73, 0x1c, 0xcb, 0x1c, 0xad, 0xa4, 0x8b)] +class DriveTypeCategorizer;} +RIDL!{#[uuid(0xb5607793, 0x24ac, 0x44c7, 0x82, 0xe2, 0x83, 0x17, 0x26, 0xaa, 0x6c, 0xb7)] +class FreeSpaceCategorizer;} +RIDL!{#[uuid(0x55d7b852, 0xf6d1, 0x42f2, 0xaa, 0x75, 0x87, 0x28, 0xa1, 0xb2, 0xd2, 0x64)] +class SizeCategorizer;} +RIDL!{#[uuid(0xd912f8cf, 0x0396, 0x4915, 0x88, 0x4e, 0xfb, 0x42, 0x5d, 0x32, 0x94, 0x3b)] +class PropertiesUI;} +RIDL!{#[uuid(0x0010890e, 0x8789, 0x413c, 0xad, 0xbc, 0x48, 0xf5, 0xb5, 0x11, 0xb3, 0xaf)] +class UserNotification;} +RIDL!{#[uuid(0x56fdf344, 0xfd6d, 0x11d0, 0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90)] +class TaskbarList;} +RIDL!{#[uuid(0x9ac9fbe1, 0xe0a2, 0x4ad6, 0xb4, 0xee, 0xe2, 0x12, 0x01, 0x3e, 0xa9, 0x17)] +class ShellItem;} +RIDL!{#[uuid(0x72eb61e0, 0x8672, 0x4303, 0x91, 0x75, 0xf2, 0xe4, 0xc6, 0x8b, 0x2e, 0x7c)] +class NamespaceWalker;} +RIDL!{#[uuid(0x3ad05575, 0x8857, 0x4850, 0x92, 0x77, 0x11, 0xb8, 0x5b, 0xdb, 0x8e, 0x09)] +class FileOperation;} +RIDL!{#[uuid(0xdc1c5a9c, 0xe88a, 0x4dde, 0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7)] +class FileOpenDialog;} +RIDL!{#[uuid(0xc0b4e2f3, 0xba21, 0x4773, 0x8d, 0xba, 0x33, 0x5e, 0xc9, 0x46, 0xeb, 0x8b)] +class FileSaveDialog;} +RIDL!{#[uuid(0x4df0c730, 0xdf9d, 0x4ae3, 0x91, 0x53, 0xaa, 0x6b, 0x82, 0xe9, 0x79, 0x5a)] +class KnownFolderManager;} +RIDL!{#[uuid(0x49f371e1, 0x8c5c, 0x4d9c, 0x9a, 0x3b, 0x54, 0xa6, 0x82, 0x7f, 0x51, 0x3c)] +class SharingConfigurationManager;} +RIDL!{#[uuid(0x7007acc7, 0x3202, 0x11d1, 0xaa, 0xd2, 0x00, 0x80, 0x5f, 0xc1, 0x27, 0x0e)] +class NetworkConnections;} +RIDL!{#[uuid(0xd6277990, 0x4c6a, 0x11cf, 0x8d, 0x87, 0x00, 0xaa, 0x00, 0x60, 0xf5, 0xbf)] +class ScheduledTasks;} +RIDL!{#[uuid(0x591209c7, 0x767b, 0x42b2, 0x9f, 0xba, 0x44, 0xee, 0x46, 0x15, 0xf2, 0xc7)] +class ApplicationAssociationRegistration;} +RIDL!{#[uuid(0x14010e02, 0xbbbd, 0x41f0, 0x88, 0xe3, 0xed, 0xa3, 0x71, 0x21, 0x65, 0x84)] +class SearchFolderItemFactory;} +RIDL!{#[uuid(0x06622d85, 0x6856, 0x4460, 0x8d, 0xe1, 0xa8, 0x19, 0x21, 0xb4, 0x1c, 0x4b)] +class OpenControlPanel;} +RIDL!{#[uuid(0x9e56be60, 0xc50f, 0x11cf, 0x9a, 0x2c, 0x00, 0xa0, 0xc9, 0x0a, 0x90, 0xce)] +class MailRecipient;} +RIDL!{#[uuid(0xf02c1a0d, 0xbe21, 0x4350, 0x88, 0xb0, 0x73, 0x67, 0xfc, 0x96, 0xef, 0x3c)] +class NetworkExplorerFolder;} +RIDL!{#[uuid(0x77f10cf0, 0x3db5, 0x4966, 0xb5, 0x20, 0xb7, 0xc5, 0x4f, 0xd3, 0x5e, 0xd6)] +class DestinationList;} +RIDL!{#[uuid(0x86c14003, 0x4d6b, 0x4ef3, 0xa7, 0xb4, 0x05, 0x06, 0x66, 0x3b, 0x2e, 0x68)] +class ApplicationDestinations;} +RIDL!{#[uuid(0x86bec222, 0x30f2, 0x47e0, 0x9f, 0x25, 0x60, 0xd1, 0x1c, 0xd7, 0x5c, 0x28)] +class ApplicationDocumentLists;} +RIDL!{#[uuid(0xde77ba04, 0x3c92, 0x4d11, 0xa1, 0xa5, 0x42, 0x35, 0x2a, 0x53, 0xe0, 0xe3)] +class HomeGroup;} +RIDL!{#[uuid(0xd9b3211d, 0xe57f, 0x4426, 0xaa, 0xef, 0x30, 0xa8, 0x06, 0xad, 0xd3, 0x97)] +class ShellLibrary;} +RIDL!{#[uuid(0x273eb5e7, 0x88b0, 0x4843, 0xbf, 0xef, 0xe2, 0xc8, 0x1d, 0x43, 0xaa, 0xe5)] +class AppStartupLink;} +RIDL!{#[uuid(0x2d3468c1, 0x36a7, 0x43b6, 0xac, 0x24, 0xd3, 0xf0, 0x2f, 0xd9, 0x60, 0x7a)] +class EnumerableObjectCollection;} +RIDL!{#[uuid(0xd5120aa3, 0x46ba, 0x44c5, 0x82, 0x2d, 0xca, 0x80, 0x92, 0xc1, 0xfc, 0x72)] +class FrameworkInputPane;} +RIDL!{#[uuid(0xc63382be, 0x7933, 0x48d0, 0x9a, 0xc8, 0x85, 0xfb, 0x46, 0xbe, 0x2f, 0xdd)] +class DefFolderMenu;} +RIDL!{#[uuid(0x7e5fe3d9, 0x985f, 0x4908, 0x91, 0xf9, 0xee, 0x19, 0xf9, 0xfd, 0x15, 0x14)] +class AppVisibility;} +RIDL!{#[uuid(0x4ed3a719, 0xcea8, 0x4bd9, 0x91, 0x0d, 0xe2, 0x52, 0xf9, 0x97, 0xaf, 0xc2)] +class AppShellVerbHandler;} +RIDL!{#[uuid(0xe44e9428, 0xbdbc, 0x4987, 0xa0, 0x99, 0x40, 0xdc, 0x8f, 0xd2, 0x55, 0xe7)] +class ExecuteUnknown;} +RIDL!{#[uuid(0xb1aec16f, 0x2383, 0x4852, 0xb0, 0xe9, 0x8f, 0x0b, 0x1d, 0xc6, 0x6b, 0x4d)] +class PackageDebugSettings;} +RIDL!{#[uuid(0x6b273fc5, 0x61fd, 0x4918, 0x95, 0xa2, 0xc3, 0xb5, 0xe9, 0xd7, 0xf5, 0x81)] +class SuspensionDependencyManager;} +RIDL!{#[uuid(0x45ba127d, 0x10a8, 0x46ea, 0x8a, 0xb7, 0x56, 0xea, 0x90, 0x78, 0x94, 0x3c)] +class ApplicationActivationManager;} +RIDL!{#[uuid(0x958a6fb5, 0xdcb2, 0x4faf, 0xaa, 0xfd, 0x7f, 0xb0, 0x54, 0xad, 0x1a, 0x3b)] +class ApplicationDesignModeSettings;} diff --git a/winapi/src/um/shtypes.rs b/winapi/src/um/shtypes.rs new file mode 100644 index 000000000..470d79e21 --- /dev/null +++ b/winapi/src/um/shtypes.rs @@ -0,0 +1,44 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! this ALWAYS GENERATED file contains the definitions for the interfaces +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, USHORT}; +use um::winnt::LPCWSTR; +STRUCT!{#[repr(packed)] struct SHITEMID { + cb: USHORT, + abID: [BYTE; 1], +}} +pub type LPSHITEMID = *mut SHITEMID; +pub type LPCSHITEMID = *const SHITEMID; +STRUCT!{#[repr(packed)] struct ITEMIDLIST { + mkid: SHITEMID, +}} +pub type ITEMIDLIST_RELATIVE = ITEMIDLIST; +pub type ITEMID_CHILD = ITEMIDLIST; +pub type ITEMIDLIST_ABSOLUTE = ITEMIDLIST; +pub type LPITEMIDLIST = *mut ITEMIDLIST; +pub type LPCITEMIDLIST = *const ITEMIDLIST; +pub type PIDLIST_ABSOLUTE = *mut ITEMIDLIST_ABSOLUTE; +pub type PCIDLIST_ABSOLUTE = *const ITEMIDLIST_ABSOLUTE; +pub type PCUIDLIST_ABSOLUTE = *const ITEMIDLIST_ABSOLUTE; +pub type PIDLIST_RELATIVE = *mut ITEMIDLIST_RELATIVE; +pub type PCIDLIST_RELATIVE = *const ITEMIDLIST_RELATIVE; +pub type PUIDLIST_RELATIVE = *mut ITEMIDLIST_RELATIVE; +pub type PCUIDLIST_RELATIVE = *const ITEMIDLIST_RELATIVE; +pub type PITEMID_CHILD = *mut ITEMID_CHILD; +pub type PCITEMID_CHILD = *const ITEMID_CHILD; +pub type PUITEMID_CHILD = *mut ITEMID_CHILD; +pub type PCUITEMID_CHILD = *const ITEMID_CHILD; +pub type PCUITEMID_CHILD_ARRAY = *const PCUITEMID_CHILD; +pub type PCUIDLIST_RELATIVE_ARRAY = *const PCUIDLIST_RELATIVE; +pub type PCIDLIST_ABSOLUTE_ARRAY = *const PCIDLIST_ABSOLUTE; +pub type PCUIDLIST_ABSOLUTE_ARRAY = *const PCUIDLIST_ABSOLUTE; +STRUCT!{struct COMDLG_FILTERSPEC { + pszName: LPCWSTR, + pszSpec: LPCWSTR, +}} +pub type KNOWNFOLDERID = GUID; +pub type REFKNOWNFOLDERID = *const KNOWNFOLDERID; diff --git a/winapi/src/um/spapidef.rs b/winapi/src/um/spapidef.rs new file mode 100644 index 000000000..259f4699f --- /dev/null +++ b/winapi/src/um/spapidef.rs @@ -0,0 +1,53 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Public header file for Windows NT Setup and Device Installer services Dlls +use shared::minwindef::DWORD; +use um::winnt::DWORDLONG; +pub type SP_LOG_TOKEN = DWORDLONG; +pub type PSP_LOG_TOKEN = *mut DWORDLONG; +pub const LOGTOKEN_TYPE_MASK: SP_LOG_TOKEN = 3; +pub const LOGTOKEN_UNSPECIFIED: SP_LOG_TOKEN = 0; +pub const LOGTOKEN_NO_LOG: SP_LOG_TOKEN = 1; +pub const LOGTOKEN_SETUPAPI_APPLOG: SP_LOG_TOKEN = 2; +pub const LOGTOKEN_SETUPAPI_DEVLOG: SP_LOG_TOKEN = 3; +pub const TXTLOG_SETUPAPI_DEVLOG: DWORD = 0x00000001; +pub const TXTLOG_SETUPAPI_CMDLINE: DWORD = 0x00000002; +pub const TXTLOG_SETUPAPI_BITS: DWORD = 0x00000003; +pub const TXTLOG_ERROR: DWORD = 0x1; +pub const TXTLOG_WARNING: DWORD = 0x2; +pub const TXTLOG_SYSTEM_STATE_CHANGE: DWORD = 0x3; +pub const TXTLOG_SUMMARY: DWORD = 0x4; +pub const TXTLOG_DETAILS: DWORD = 0x5; +pub const TXTLOG_VERBOSE: DWORD = 0x6; +pub const TXTLOG_VERY_VERBOSE: DWORD = 0x7; +pub const TXTLOG_RESERVED_FLAGS: DWORD = 0x0000FFF0; +pub const TXTLOG_TIMESTAMP: DWORD = 0x00010000; +pub const TXTLOG_DEPTH_INCR: DWORD = 0x00020000; +pub const TXTLOG_DEPTH_DECR: DWORD = 0x00040000; +pub const TXTLOG_TAB_1: DWORD = 0x00080000; +pub const TXTLOG_FLUSH_FILE: DWORD = 0x00100000; +#[inline] +pub fn TXTLOG_LEVEL(flags: DWORD) -> DWORD { + flags & 0xf +} +pub const TXTLOG_DEVINST: DWORD = 0x00000001; +pub const TXTLOG_INF: DWORD = 0x00000002; +pub const TXTLOG_FILEQ: DWORD = 0x00000004; +pub const TXTLOG_COPYFILES: DWORD = 0x00000008; +pub const TXTLOG_SIGVERIF: DWORD = 0x00000020; +pub const TXTLOG_BACKUP: DWORD = 0x00000080; +pub const TXTLOG_UI: DWORD = 0x00000100; +pub const TXTLOG_UTIL: DWORD = 0x00000200; +pub const TXTLOG_INFDB: DWORD = 0x00000400; +pub const TXTLOG_POLICY: DWORD = 0x00800000; +pub const TXTLOG_NEWDEV: DWORD = 0x01000000; +pub const TXTLOG_UMPNPMGR: DWORD = 0x02000000; +pub const TXTLOG_DRIVER_STORE: DWORD = 0x04000000; +pub const TXTLOG_SETUP: DWORD = 0x08000000; +pub const TXTLOG_CMI: DWORD = 0x10000000; +pub const TXTLOG_DEVMGR: DWORD = 0x20000000; +pub const TXTLOG_INSTALLER: DWORD = 0x40000000; +pub const TXTLOG_VENDOR: DWORD = 0x80000000; diff --git a/winapi/src/um/spellcheck.rs b/winapi/src/um/spellcheck.rs new file mode 100644 index 000000000..9254ed52d --- /dev/null +++ b/winapi/src/um/spellcheck.rs @@ -0,0 +1,146 @@ +use shared::minwindef::{BOOL, BYTE, DWORD}; +use shared::ntdef::{LPCWSTR, LPWSTR, ULONG}; +use shared::winerror::HRESULT; +use um::objidlbase::IEnumString; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +ENUM!{enum WORDLIST_TYPE { + WORDLIST_TYPE_IGNORE = 0, + WORDLIST_TYPE_ADD = 1, + WORDLIST_TYPE_EXCLUDE = 2, + WORDLIST_TYPE_AUTOCORRECT = 3, +}} +ENUM!{enum CORRECTIVE_ACTION { + CORRECTIVE_ACTION_NONE = 0, + CORRECTIVE_ACTION_GET_SUGGESTIONS = 1, + CORRECTIVE_ACTION_REPLACE = 2, + CORRECTIVE_ACTION_DELETE = 3, +}} +RIDL!{#[uuid(0xb7c82d61, 0xfbe8, 0x4b47, 0x9b, 0x27, 0x6c, 0x0d, 0x2e, 0x0d, 0xe0, 0xa3)] +interface ISpellingError(ISpellingErrorVtbl): IUnknown(IUnknownVtbl) { + fn get_StartIndex( + value: *mut ULONG, + ) -> HRESULT, + fn get_Length( + value: *mut ULONG, + ) -> HRESULT, + fn get_CorrectiveAction( + value: *mut CORRECTIVE_ACTION, + ) -> HRESULT, + fn get_Replacement( + value: *mut LPWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x803e3bd4, 0x2828, 0x4410, 0x82, 0x90, 0x41, 0x8d, 0x1d, 0x73, 0xc7, 0x62)] +interface IEnumSpellingError(IEnumSpellingErrorVtbl): IUnknown(IUnknownVtbl) { + fn Next( + value: *mut *mut ISpellingError, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x432e5f85, 0x35cf, 0x4606, 0xa8, 0x01, 0x6f, 0x70, 0x27, 0x7e, 0x1d, 0x7a)] +interface IOptionDescription(IOptionDescriptionVtbl): IUnknown(IUnknownVtbl) { + fn Id( + value: *mut LPWSTR, + ) -> HRESULT, + fn Heading( + value: *mut LPWSTR, + ) -> HRESULT, + fn Description( + value: *mut LPWSTR, + ) -> HRESULT, + fn Labels( + value: *mut *mut IEnumString, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0b83a5b0, 0x792f, 0x4eab, 0x97, 0x99, 0xac, 0xf5, 0x2c, 0x5e, 0xd0, 0x8a)] +interface ISpellCheckerChangedEventHandler(ISpellCheckerChangedEventHandlerVtbl): + IUnknown(IUnknownVtbl) { + fn Invoke( + sender: *const ISpellChecker, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb6fd0b71, 0xe2bc, 0x4653, 0x8d, 0x05, 0xf1, 0x97, 0xe4, 0x12, 0x77, 0x0b)] +interface ISpellChecker(ISpellCheckerVtbl): IUnknown(IUnknownVtbl) { + fn get_LanguageTag( + value: *mut LPWSTR, + ) -> HRESULT, + fn Check( + text: LPCWSTR, + value: *mut *mut IEnumSpellingError, + ) -> HRESULT, + fn Suggest( + word: LPCWSTR, + value: *mut *mut IEnumString, + ) -> HRESULT, + fn Add( + word: LPCWSTR, + ) -> HRESULT, + fn Ignore( + word: LPCWSTR, + ) -> HRESULT, + fn AutoCorrect( + from: LPCWSTR, + to: LPCWSTR, + ) -> HRESULT, + fn GetOptionValue( + optionId: LPCWSTR, + value: *mut BYTE, + ) -> HRESULT, + fn Get_OptionIds( + value: *mut *mut IEnumString, + ) -> HRESULT, + fn Get_Id( + value: *mut LPWSTR, + ) -> HRESULT, + fn Get_LocalizedName( + value: *mut LPWSTR, + ) -> HRESULT, + fn add_SpellCheckerChanged( + handler: *const ISpellCheckerChangedEventHandler, + eventCookie: *mut DWORD, + ) -> HRESULT, + fn remove_SpellCheckerChanged( + eventCookie: DWORD, + ) -> HRESULT, + fn GetOptionDescription( + optionId: LPCWSTR, + value: *mut *mut IOptionDescription, + ) -> HRESULT, + fn ComprehensiveCheck( + text: LPCWSTR, + value: *mut *mut IEnumSpellingError, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe7ed1c71, 0x87f7, 0x4378, 0xa8, 0x40, 0xc9, 0x20, 0x0d, 0xac, 0xee, 0x47)] +interface ISpellChecker2(ISpellChecker2Vtbl): ISpellChecker(ISpellCheckerVtbl) { + fn Remove( + word: LPCWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8e018a9d, 0x2415, 0x4677, 0xbf, 0x08, 0x79, 0x4e, 0xa6, 0x1f, 0x94, 0xbb)] +interface ISpellCheckerFactory(ISpellCheckerFactoryVtbl): IUnknown(IUnknownVtbl) { + fn SupportedLanguages( + value: *mut *mut IEnumString, + ) -> HRESULT, + fn IsSupported( + languageTag: LPCWSTR, + value: *mut BOOL, + ) -> HRESULT, + fn CreateSpellChecker( + languageTag: LPCWSTR, + value: *mut *mut ISpellChecker, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xaa176b85, 0x0e12, 0x4844, 0x8e, 0x1a, 0xee, 0xf1, 0xda, 0x77, 0xf5, 0x86)] +interface IUserDictionariesRegistrar(IUserDictionariesRegistrarVtbl): IUnknown(IUnknownVtbl) { + fn RegisterUserDictionary( + dictionaryPath: LPCWSTR, + languageTag: LPCWSTR, + ) -> HRESULT, + fn UnregisterUserDictionary( + dictionaryPath: LPCWSTR, + languageTag: LPCWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7ab36653, 0x1796, 0x484b, 0xbd, 0xfa, 0xe7, 0x4f, 0x1d, 0xb7, 0xc1, 0xdc)] +class SpellCheckerFactory; +} diff --git a/winapi/src/um/sporder.rs b/winapi/src/um/sporder.rs new file mode 100644 index 000000000..84630e3e0 --- /dev/null +++ b/winapi/src/um/sporder.rs @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Service Provider Order +use ctypes::c_int; +use shared::guiddef::LPGUID; +use shared::minwindef::{DWORD, LPDWORD}; +extern "system" { + pub fn WSCWriteProviderOrder( + lpwdCatalogEntryId: LPDWORD, + dwNumberOfEntries: DWORD, + ) -> c_int; +} +FN!{stdcall LPWSCWRITEPROVIDERORDER( + lpwdCatalogEntryId: LPDWORD, + dwNumberOfEntries: DWORD, +) -> c_int} +#[cfg(target_pointer_width = "64")] +extern "system" { + pub fn WSCWriteProviderOrder32( + lpwdCatalogEntryId: LPDWORD, + dwNumberOfEntries: DWORD, + ) -> c_int; + pub fn WSCWriteNameSpaceOrder( + lpProviderId: LPGUID, + dwNumberOfEntries: DWORD, + ) -> c_int; +} +FN!{stdcall LPWSCWRITENAMESPACEORDER( + lpProviderId: LPGUID, + dwNumberOfEntries: DWORD, +) -> c_int} +#[cfg(target_pointer_width = "64")] +extern "system" { + pub fn WSCWriteNameSpaceOrder32( + lpProviderId: LPGUID, + dwNumberOfEntries: DWORD, + ) -> c_int; +} diff --git a/winapi/src/um/sql.rs b/winapi/src/um/sql.rs new file mode 100644 index 000000000..d42a163ed --- /dev/null +++ b/winapi/src/um/sql.rs @@ -0,0 +1,108 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use um::sqltypes::{ + SQLHANDLE, SQLHDBC, SQLHENV, SQLHSTMT, SQLINTEGER, SQLLEN, SQLPOINTER, SQLRETURN, SQLSMALLINT, + SQLUSMALLINT, +}; +pub const SQL_NULL_DATA: SQLLEN = -1; +pub const SQL_DATA_AT_EXEC: SQLLEN = -2; +pub const SQL_SUCCESS: SQLRETURN = 0; +pub const SQL_SUCCESS_WITH_INFO: SQLRETURN = 1; +pub const SQL_NO_DATA: SQLRETURN = 100; +pub const SQL_PARAM_DATA_AVAILABLE: SQLRETURN = 101; +pub const SQL_ERROR: SQLRETURN = -1; +pub const SQL_INVALID_HANDLE: SQLRETURN = -2; +pub const SQL_STILL_EXECUTING: SQLRETURN = 2; +pub const SQL_NEED_DATA: SQLRETURN = 99; +pub const SQL_NTS: SQLSMALLINT = -3; +pub const SQL_MAX_MESSAGE_LENGTH: usize = 512; +pub const SQL_DATE_LEN: usize = 10; +pub const SQL_TIME_LEN: usize = 8; +pub const SQL_TIMESTAMP_LEN: usize = 19; +pub const SQL_HANDLE_ENV: SQLSMALLINT = 1; +pub const SQL_HANDLE_DBC: SQLSMALLINT = 2; +pub const SQL_HANDLE_STMT: SQLSMALLINT = 3; +pub const SQL_HANDLE_DESC: SQLSMALLINT = 4; +pub const SQL_ATTR_OUTPUT_NTS: SQLINTEGER = 10001; +pub const SQL_ATTR_AUTO_IPD: SQLINTEGER = 10001; +pub const SQL_ATTR_METADATA_ID: SQLINTEGER = 10014; +pub const SQL_ATTR_APP_ROW_DESC: SQLINTEGER = 10010; +pub const SQL_ATTR_APP_PARAM_DESC: SQLINTEGER = 10011; +pub const SQL_ATTR_IMP_ROW_DESC: SQLINTEGER = 10012; +pub const SQL_ATTR_IMP_PARAM_DESC: SQLINTEGER = 10013; +pub const SQL_ATTR_CURSOR_SCROLLABLE: SQLINTEGER = -1; +pub const SQL_ATTR_CURSOR_SENSITIVITY: SQLINTEGER = -2; +pub const SQL_UNKNOWN_TYPE: SQLSMALLINT = 0; +pub const SQL_CHAR: SQLSMALLINT = 1; +pub const SQL_NUMERIC: SQLSMALLINT = 2; +pub const SQL_DECIMAL: SQLSMALLINT = 3; +pub const SQL_INTEGER: SQLSMALLINT = 4; +pub const SQL_SMALLINT: SQLSMALLINT = 5; +pub const SQL_FLOAT: SQLSMALLINT = 6; +pub const SQL_REAL: SQLSMALLINT = 7; +pub const SQL_DOUBLE: SQLSMALLINT = 8; +pub const SQL_DATETIME: SQLSMALLINT = 9; +pub const SQL_VARCHAR: SQLSMALLINT = 12; +pub const SQL_TYPE_DATE: SQLSMALLINT = 91; +pub const SQL_TYPE_TIME: SQLSMALLINT = 92; +pub const SQL_TYPE_TIMESTAMP: SQLSMALLINT = 93; +pub const SQL_NO_NULLS: SQLSMALLINT = 0; +pub const SQL_NULLABLE: SQLSMALLINT = 1; +pub const SQL_NULLABLE_UNKNOWN: SQLSMALLINT = 2; +pub const SQL_CLOSE: SQLUSMALLINT = 0; +pub const SQL_DROP: SQLUSMALLINT = 1; +pub const SQL_UNBIND: SQLUSMALLINT = 2; +pub const SQL_RESET_PARAMS: SQLUSMALLINT = 3; +pub const SQL_NULL_HANDLE: SQLHANDLE = 0 as SQLHANDLE; +extern "system" { + pub fn SQLAllocHandle( + handleType: SQLSMALLINT, + inputHandle: SQLHANDLE, + outputHandle: *mut SQLHANDLE, + ) -> SQLRETURN; + pub fn SQLDisconnect( + connectionHandle: SQLHDBC, + ) -> SQLRETURN; + pub fn SQLFetch( + statementHandle: SQLHSTMT, + ) -> SQLRETURN; + pub fn SQLFreeHandle( + handleType: SQLSMALLINT, + handle: SQLHANDLE, + ) -> SQLRETURN; + pub fn SQLFreeStmt( + statementHandle: SQLHSTMT, + option: SQLUSMALLINT, + ) -> SQLRETURN; + pub fn SQLGetData( + statementHandle: SQLHSTMT, + columnNumber: SQLUSMALLINT, + targetType: SQLSMALLINT, + targetValue: SQLPOINTER, + bufferLength: SQLLEN, + strLen_or_IndPtr: *mut SQLLEN, + ) -> SQLRETURN; + pub fn SQLNumResultCols( + statementHandle: SQLHSTMT, + columnCount: *mut SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLRowCount( + statementHandle: SQLHSTMT, + rowCount: *mut SQLLEN, + ) -> SQLRETURN; + pub fn SQLSetConnectAttr( + connectionHandle: SQLHDBC, + attribute: SQLINTEGER, + value: SQLPOINTER, + stringLength: SQLINTEGER, + ) -> SQLRETURN; + pub fn SQLSetEnvAttr( + environmentHandle: SQLHENV, + attribute: SQLINTEGER, + value: SQLPOINTER, + stringLength: SQLINTEGER, + ) -> SQLRETURN; +} diff --git a/winapi/src/um/sqlext.rs b/winapi/src/um/sqlext.rs new file mode 100644 index 000000000..8de50f1b8 --- /dev/null +++ b/winapi/src/um/sqlext.rs @@ -0,0 +1,95 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the SQL extension APIs +use um::sql::{ + SQL_CHAR, SQL_DOUBLE, SQL_INTEGER, SQL_NUMERIC, SQL_REAL, SQL_SMALLINT, SQL_TYPE_DATE, + SQL_TYPE_TIME, SQL_TYPE_TIMESTAMP +}; +use um::sqltypes::{SQLINTEGER, SQLSMALLINT, SQLUSMALLINT}; +pub const SQL_ATTR_ODBC_VERSION: SQLINTEGER = 200; +pub const SQL_ATTR_CONNECTION_POOLING: SQLINTEGER = 201; +pub const SQL_ATTR_CP_MATCH: SQLINTEGER = 202; +pub const SQL_OV_ODBC2: SQLINTEGER = 2; +pub const SQL_OV_ODBC3: SQLINTEGER = 3; +pub const SQL_OV_ODBC3_80: SQLINTEGER = 380; +pub const SQL_ACCESS_MODE: SQLINTEGER = 101; +pub const SQL_AUTOCOMMIT: SQLINTEGER = 102; +pub const SQL_LOGIN_TIMEOUT: SQLINTEGER = 103; +pub const SQL_OPT_TRACE: SQLINTEGER = 104; +pub const SQL_OPT_TRACEFILE: SQLINTEGER = 105; +pub const SQL_TRANSLATE_DLL: SQLINTEGER = 106; +pub const SQL_TRANSLATE_OPTION: SQLINTEGER = 107; +pub const SQL_TXN_ISOLATION: SQLINTEGER = 108; +pub const SQL_CURRENT_QUALIFIER: SQLINTEGER = 109; +pub const SQL_ODBC_CURSORS: SQLINTEGER = 110; +pub const SQL_QUIET_MODE: SQLINTEGER = 111; +pub const SQL_PACKET_SIZE: SQLINTEGER = 112; +pub const SQL_ATTR_ACCESS_MODE: SQLINTEGER = SQL_ACCESS_MODE; +pub const SQL_ATTR_AUTOCOMMIT: SQLINTEGER = SQL_AUTOCOMMIT; +pub const SQL_ATTR_CONNECTION_TIMEOUT: SQLINTEGER = 113; +pub const SQL_ATTR_CURRENT_CATALOG: SQLINTEGER = SQL_CURRENT_QUALIFIER; +pub const SQL_ATTR_DISCONNECT_BEHAVIOR: SQLINTEGER = 114; +pub const SQL_ATTR_ENLIST_IN_DTC: SQLINTEGER = 1207; +pub const SQL_ATTR_ENLIST_IN_XA: SQLINTEGER = 1208; +pub const SQL_ATTR_LOGIN_TIMEOUT: SQLINTEGER = SQL_LOGIN_TIMEOUT; +pub const SQL_ATTR_ODBC_CURSORS: SQLINTEGER = SQL_ODBC_CURSORS; +pub const SQL_ATTR_PACKET_SIZE: SQLINTEGER = SQL_PACKET_SIZE; +pub const SQL_ATTR_QUIET_MODE: SQLINTEGER = SQL_QUIET_MODE; +pub const SQL_ATTR_TRACE: SQLINTEGER = SQL_OPT_TRACE; +pub const SQL_ATTR_TRACEFILE: SQLINTEGER = SQL_OPT_TRACEFILE; +pub const SQL_ATTR_TRANSLATE_LIB: SQLINTEGER = SQL_TRANSLATE_DLL; +pub const SQL_ATTR_TRANSLATE_OPTION: SQLINTEGER = SQL_TRANSLATE_OPTION; +pub const SQL_ATTR_TXN_ISOLATION: SQLINTEGER = SQL_TXN_ISOLATION; +pub const SQL_ATTR_CONNECTION_DEAD: SQLINTEGER = 1209; +pub const SQL_IS_POINTER: SQLINTEGER = -4; +pub const SQL_IS_UINTEGER: SQLINTEGER = -5; +pub const SQL_IS_INTEGER: SQLINTEGER = -6; +pub const SQL_IS_USMALLINT: SQLINTEGER = -7; +pub const SQL_IS_SMALLINT: SQLINTEGER = -8; +pub const SQL_DATE: SQLSMALLINT = 9; +pub const SQL_INTERVAL: SQLSMALLINT = 10; +pub const SQL_TIME: SQLSMALLINT = 10; +pub const SQL_TIMESTAMP: SQLSMALLINT = 11; +pub const SQL_LONGVARCHAR: SQLSMALLINT = -1; +pub const SQL_BINARY: SQLSMALLINT = -2; +pub const SQL_VARBINARY: SQLSMALLINT = -3; +pub const SQL_LONGVARBINARY: SQLSMALLINT = -4; +pub const SQL_BIGINT: SQLSMALLINT = -5; +pub const SQL_TINYINT: SQLSMALLINT = -6; +pub const SQL_BIT: SQLSMALLINT = -7; +pub const SQL_GUID: SQLSMALLINT = -11; +pub const SQL_C_CHAR: SQLSMALLINT = SQL_CHAR; +pub const SQL_C_LONG: SQLSMALLINT = SQL_INTEGER; +pub const SQL_C_SHORT: SQLSMALLINT = SQL_SMALLINT; +pub const SQL_C_FLOAT: SQLSMALLINT = SQL_REAL; +pub const SQL_C_DOUBLE: SQLSMALLINT = SQL_DOUBLE; +pub const SQL_C_NUMERIC: SQLSMALLINT = SQL_NUMERIC; +pub const SQL_C_DEFAULT: SQLSMALLINT = 99; +pub const SQL_SIGNED_OFFSET: SQLSMALLINT = -20; +pub const SQL_UNSIGNED_OFFSET: SQLSMALLINT = -22; +pub const SQL_C_DATE: SQLSMALLINT = SQL_DATE; +pub const SQL_C_TIME: SQLSMALLINT = SQL_TIME; +pub const SQL_C_TIMESTAMP: SQLSMALLINT = SQL_TIMESTAMP; +pub const SQL_C_TYPE_DATE: SQLSMALLINT = SQL_TYPE_DATE; +pub const SQL_C_TYPE_TIME: SQLSMALLINT = SQL_TYPE_TIME; +pub const SQL_C_TYPE_TIMESTAMP: SQLSMALLINT = SQL_TYPE_TIMESTAMP; +pub const SQL_C_BINARY: SQLSMALLINT = SQL_BINARY; +pub const SQL_C_BIT: SQLSMALLINT = SQL_BIT; +pub const SQL_C_SBIGINT: SQLSMALLINT = SQL_BIGINT + SQL_SIGNED_OFFSET; +pub const SQL_C_UBIGINT: SQLSMALLINT = SQL_BIGINT + SQL_UNSIGNED_OFFSET; +pub const SQL_C_TINYINT: SQLSMALLINT = SQL_TINYINT; +pub const SQL_C_SLONG: SQLSMALLINT = SQL_C_LONG + SQL_SIGNED_OFFSET; +pub const SQL_C_SSHORT: SQLSMALLINT = SQL_C_SHORT + SQL_SIGNED_OFFSET; +pub const SQL_C_STINYINT: SQLSMALLINT = SQL_TINYINT + SQL_SIGNED_OFFSET; +pub const SQL_C_ULONG: SQLSMALLINT = SQL_C_LONG + SQL_UNSIGNED_OFFSET; +pub const SQL_C_USHORT: SQLSMALLINT = SQL_C_SHORT + SQL_UNSIGNED_OFFSET; +pub const SQL_C_UTINYINT: SQLSMALLINT = SQL_TINYINT + SQL_UNSIGNED_OFFSET; +pub const SQL_C_GUID: SQLSMALLINT = SQL_GUID; +pub const SQL_TYPE_NULL: SQLSMALLINT = 0; +pub const SQL_DRIVER_NOPROMPT: SQLUSMALLINT = 0; +pub const SQL_DRIVER_COMPLETE: SQLUSMALLINT = 1; +pub const SQL_DRIVER_PROMPT: SQLUSMALLINT = 2; +pub const SQL_DRIVER_COMPLETE_REQUIRED: SQLUSMALLINT = 3; diff --git a/winapi/src/um/sqltypes.rs b/winapi/src/um/sqltypes.rs new file mode 100644 index 000000000..5c9b3020d --- /dev/null +++ b/winapi/src/um/sqltypes.rs @@ -0,0 +1,142 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the types used in ODBC +use ctypes::*; +#[cfg(target_pointer_width = "64")] +use shared::basetsd::{INT64, UINT64}; +use shared::guiddef::GUID; +use shared::windef::HWND; +pub type SQLCHAR = c_uchar; +pub type SQLSCHAR = c_schar; +pub type SQLDATE = c_uchar; +pub type SQLDECIMAL = c_uchar; +pub type SQLDOUBLE = c_double; +pub type SQLFLOAT = c_double; +pub type SQLINTEGER = c_long; +pub type SQLUINTEGER = c_ulong; +#[cfg(target_pointer_width = "64")] +pub type SQLLEN = INT64; +#[cfg(target_pointer_width = "64")] +pub type SQLULEN = UINT64; +#[cfg(target_pointer_width = "64")] +pub type SQLSETPOSIROW = UINT64; +#[cfg(target_arch = "x86")] +pub type SQLLEN = SQLINTEGER; +#[cfg(target_arch = "x86")] +pub type SQLULEN = SQLUINTEGER; +#[cfg(target_arch = "x86")] +pub type SQLSETPOSIROW = SQLUSMALLINT; +pub type SQLROWCOUNT = SQLULEN; +pub type SQLROWSETSIZE = SQLULEN; +pub type SQLTRANSID = SQLULEN; +pub type SQLROWOFFSET = SQLLEN; +pub type SQLNUMERIC = c_uchar; +pub type SQLPOINTER = *mut c_void; +pub type SQLREAL = c_float; +pub type SQLSMALLINT = c_short; +pub type SQLUSMALLINT = c_ushort; +pub type SQLTIME = c_uchar; +pub type SQLTIMESTAMP = c_uchar; +pub type SQLVARCHAR = c_uchar; +pub type SQLRETURN = SQLSMALLINT; +pub type SQLHANDLE = *mut c_void; +pub type SQLHENV = SQLHANDLE; +pub type SQLHDBC = SQLHANDLE; +pub type SQLHSTMT = SQLHANDLE; +pub type SQLHDESC = SQLHANDLE; +//pub type UCHAR = c_uchar; +pub type SCHAR = c_schar; +//pub type SQLSCHAR = SCHAR; +pub type SDWORD = c_long; +pub type SWORD = c_short; +pub type UDWORD = c_ulong; +//pub type UWORD = c_ushort; +//#[cfg(target_arch = "x86")] +//pub type SQLUINTEGER = UDWORD; +pub type SLONG = c_long; +pub type SSHORT = c_short; +//pub type ULONG = c_ulong; +//pub type USHORT = c_ushort; +pub type SDOUBLE = c_double; +pub type LDOUBLE = c_double; +pub type SFLOAT = c_float; +pub type PTR = *mut c_void; +pub type HENV = *mut c_void; +pub type HDBC = *mut c_void; +pub type HSTMT = *mut c_void; +pub type RETCODE = c_short; +pub type SQLHWND = HWND; +STRUCT!{struct DATE_STRUCT { + year: SQLSMALLINT, + month: SQLUSMALLINT, + day: SQLUSMALLINT, +}} +pub type SQL_DATE_STRUCT = DATE_STRUCT; +STRUCT!{struct TIME_STRUCT { + hour: SQLUSMALLINT, + minute: SQLUSMALLINT, + second: SQLUSMALLINT, +}} +pub type SQL_TIME_STRUCT = TIME_STRUCT; +STRUCT!{struct TIMESTAMP_STRUCT { + year: SQLSMALLINT, + month: SQLUSMALLINT, + day: SQLUSMALLINT, + hour: SQLUSMALLINT, + minute: SQLUSMALLINT, + second: SQLUSMALLINT, + fraction: SQLUINTEGER, +}} +pub type SQL_TIMESTAMP_STRUCT = TIMESTAMP_STRUCT; +ENUM!{enum SQLINTERVAL { + SQL_IS_YEAR = 1, + SQL_IS_MONTH = 2, + SQL_IS_DAY = 3, + SQL_IS_HOUR = 4, + SQL_IS_MINUTE = 5, + SQL_IS_SECOND = 6, + SQL_IS_YEAR_TO_MONTH = 7, + SQL_IS_DAY_TO_HOUR = 8, + SQL_IS_DAY_TO_MINUTE = 9, + SQL_IS_DAY_TO_SECOND = 10, + SQL_IS_HOUR_TO_MINUTE = 11, + SQL_IS_HOUR_TO_SECOND = 12, + SQL_IS_MINUTE_TO_SECOND = 13, +}} +STRUCT!{struct SQL_YEAR_MONTH_STRUCT { + year: SQLUINTEGER, + month: SQLUINTEGER, +}} +STRUCT!{struct SQL_DAY_SECOND_STRUCT { + day: SQLUINTEGER, + hour: SQLUINTEGER, + minute: SQLUINTEGER, + second: SQLUINTEGER, + fraction: SQLUINTEGER, +}} +UNION!{union SQL_INTERVAL_STRUCT_intval { + [u32; 5], + year_month year_month_mut: SQL_YEAR_MONTH_STRUCT, + day_second day_second_mut: SQL_DAY_SECOND_STRUCT, +}} +STRUCT!{struct SQL_INTERVAL_STRUCT { + interval_type: SQLINTERVAL, + interval_sign: SQLSMALLINT, + intval: SQL_INTERVAL_STRUCT_intval, +}} +pub type ODBCINT64 = __int64; +pub type SQLBIGINT = ODBCINT64; +pub type SQLUBIGINT = __uint64; +pub const SQL_MAX_NUMERIC_LEN: usize = 16; +STRUCT!{struct SQL_NUMERIC_STRUCT { + precision: SQLCHAR, + scale: SQLSCHAR, + sign: SQLCHAR, + val: [SQLCHAR; SQL_MAX_NUMERIC_LEN], +}} +pub type SQLGUID = GUID; +pub type BOOKMARK = SQLULEN; +pub type SQLWCHAR = wchar_t; diff --git a/winapi/src/um/sqlucode.rs b/winapi/src/um/sqlucode.rs new file mode 100644 index 000000000..b5ed4bfab --- /dev/null +++ b/winapi/src/um/sqlucode.rs @@ -0,0 +1,106 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the ODBC Core unicode functions +use um::sqltypes::{ + SQLCHAR, SQLHANDLE, SQLHDBC, SQLHSTMT, SQLHWND, SQLINTEGER, SQLRETURN, SQLSMALLINT, SQLULEN, + SQLUSMALLINT, SQLWCHAR +}; +pub const SQL_WCHAR: SQLSMALLINT = -8; +pub const SQL_WVARCHAR: SQLSMALLINT = -9; +pub const SQL_WLONGVARCHAR: SQLSMALLINT = -10; +pub const SQL_C_WCHAR: SQLSMALLINT = SQL_WCHAR; +extern "system" { + pub fn SQLConnectW( + connectionHandle: SQLHDBC, + serverName: *const SQLWCHAR, + nameLength1: SQLSMALLINT, + userName: *const SQLWCHAR, + nameLength2: SQLSMALLINT, + authentication: *const SQLWCHAR, + nameLength3: SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLDescribeColW( + statementHandle: SQLHSTMT, + columnNumber: SQLUSMALLINT, + columnName: *mut SQLWCHAR, + bufferLength: SQLSMALLINT, + nameLength: *mut SQLSMALLINT, + dataType: *mut SQLSMALLINT, + columnSize: *mut SQLULEN, + decimalDigits: *mut SQLSMALLINT, + nullable: *mut SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLExecDirectW( + statementHandle: SQLHSTMT, + statementText: *const SQLWCHAR, + textLength: SQLINTEGER, + ) -> SQLRETURN; + pub fn SQLGetDiagRecW( + handleType: SQLSMALLINT, + handle: SQLHANDLE, + recNumber: SQLSMALLINT, + sqlstate: *mut SQLWCHAR, + nativeError: *mut SQLINTEGER, + messageText: *mut SQLWCHAR, + bufferLength: SQLSMALLINT, + textLength: *mut SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLDriverConnectW( + hdbc: SQLHDBC, + hwnd: SQLHWND, + szConnStrIn: *const SQLWCHAR, + cchConnStrIn: SQLSMALLINT, + szConnStrOut: *mut SQLWCHAR, + cchConnStrOutMax: SQLSMALLINT, + pcchConnStrOut: *mut SQLSMALLINT, + fDriverCompletion: SQLUSMALLINT, + ) -> SQLRETURN; + pub fn SQLConnectA( + connectionHandle: SQLHDBC, + serverName: *const SQLCHAR, + nameLength1: SQLSMALLINT, + userName: *const SQLCHAR, + nameLength2: SQLSMALLINT, + authentication: *const SQLCHAR, + nameLength3: SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLDescribeColA( + statementHandle: SQLHSTMT, + columnNumber: SQLUSMALLINT, + columnName: *mut SQLCHAR, + bufferLength: SQLSMALLINT, + nameLength: *mut SQLSMALLINT, + dataType: *mut SQLSMALLINT, + columnSize: *mut SQLULEN, + decimalDigits: *mut SQLSMALLINT, + nullable: *mut SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLExecDirectA( + statementHandle: SQLHSTMT, + statementText: *const SQLCHAR, + textLength: SQLINTEGER, + ) -> SQLRETURN; + pub fn SQLGetDiagRecA( + handleType: SQLSMALLINT, + handle: SQLHANDLE, + recNumber: SQLSMALLINT, + sqlstate: *mut SQLCHAR, + nativeError: *mut SQLINTEGER, + messageText: *mut SQLCHAR, + bufferLength: SQLSMALLINT, + textLength: *mut SQLSMALLINT, + ) -> SQLRETURN; + pub fn SQLDriverConnectA( + hdbc: SQLHDBC, + hwnd: SQLHWND, + szConnStrIn: *const SQLCHAR, + cchConnStrIn: SQLSMALLINT, + szConnStrOut: *mut SQLCHAR, + cchConnStrOutMax: SQLSMALLINT, + pcchConnStrOut: *mut SQLSMALLINT, + fDriverCompletion: SQLUSMALLINT, + ) -> SQLRETURN; +} diff --git a/winapi/src/um/sspi.rs b/winapi/src/um/sspi.rs new file mode 100644 index 000000000..edc0dbc6d --- /dev/null +++ b/winapi/src/um/sspi.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Security Support Provider Interface Prototypes and structure definitions +pub use shared::sspi::*; diff --git a/winapi/src/um/stringapiset.rs b/winapi/src/um/stringapiset.rs new file mode 100644 index 000000000..61560ed14 --- /dev/null +++ b/winapi/src/um/stringapiset.rs @@ -0,0 +1,75 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_int; +use shared::minwindef::{BOOL, DWORD, LPARAM, LPBOOL, LPVOID, LPWORD, UINT}; +use um::winnls::LPNLSVERSIONINFO; +use um::winnt::{LCID, LPCSTR, LPCWCH, LPCWSTR, LPSTR, LPWSTR, PCNZWCH}; +extern "system" { + pub fn CompareStringEx( + lpLocaleName: LPCWSTR, + dwCmpFlags: DWORD, + lpString1: LPCWCH, + cchCount1: c_int, + lpString2: LPCWCH, + cchCount2: c_int, + lpVersionInformation: LPNLSVERSIONINFO, + lpReserved: LPVOID, + lParam: LPARAM, + ) -> c_int; + pub fn CompareStringOrdinal( + lpString1: LPCWCH, + cchCount1: c_int, + lpString2: LPCWCH, + cchCount2: c_int, + bIgnoreCase: BOOL, + ) -> c_int; + pub fn CompareStringW( + Locale: LCID, + dwCmpFlags: DWORD, + lpString1: PCNZWCH, + cchCount1: c_int, + lpString2: PCNZWCH, + cchCount2: c_int, + ) -> c_int; + pub fn FoldStringW( + dwMapFlags: DWORD, + lpSrcStr: LPCWCH, + cchSrc: c_int, + lpDestStr: LPWSTR, + cchDest: c_int, + ) -> c_int; + pub fn GetStringTypeExW( + Locale: LCID, + dwInfoType: DWORD, + lpSrcStr: LPCWCH, + cchSrc: c_int, + lpCharType: LPWORD, + ) -> BOOL; + pub fn GetStringTypeW( + dwInfoType: DWORD, + lpSrcStr: LPCWCH, + cchSrc: c_int, + lpCharType: LPWORD, + ) -> BOOL; + pub fn MultiByteToWideChar( + CodePage: UINT, + dwFlags: DWORD, + lpMultiByteStr: LPCSTR, + cbMultiByte: c_int, + lpWideCharStr: LPWSTR, + cchWideChar: c_int, + ) -> c_int; + pub fn WideCharToMultiByte( + CodePage: UINT, + dwFlags: DWORD, + lpWideCharStr: LPCWSTR, + cchWideChar: c_int, + lpMultiByteStr: LPSTR, + cbMultiByte: c_int, + lpDefaultChar: LPCSTR, + lpUsedDefaultChar: LPBOOL, + ) -> c_int; +} diff --git a/winapi/src/um/strmif.rs b/winapi/src/um/strmif.rs new file mode 100644 index 000000000..db08afd9a --- /dev/null +++ b/winapi/src/um/strmif.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use um::winnt::LONGLONG; +pub type REFERENCE_TIME = LONGLONG; diff --git a/winapi/src/um/subauth.rs b/winapi/src/um/subauth.rs new file mode 100644 index 000000000..b5d539b25 --- /dev/null +++ b/winapi/src/um/subauth.rs @@ -0,0 +1,204 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Types and macros for Subauthentication Packages. +use shared::minwindef::{PUCHAR, ULONG, USHORT}; +use um::winnt::{BOOLEAN, CHAR, LARGE_INTEGER, LONG, PCHAR, PVOID, PWSTR}; +STRUCT!{struct UNICODE_STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PWSTR, +}} +pub type PUNICODE_STRING = *mut UNICODE_STRING; +STRUCT!{struct STRING { + Length: USHORT, + MaximumLength: USHORT, + Buffer: PCHAR, +}} +pub type PSTRING = *mut STRING; +STRUCT!{struct OLD_LARGE_INTEGER { + LowPart: ULONG, + HighPart: LONG, +}} +pub type POLD_LARGE_INTEGER = *mut OLD_LARGE_INTEGER; +pub type SAM_HANDLE = PVOID; +pub type PSAM_HANDLE = *mut PVOID; +pub const USER_ACCOUNT_DISABLED: ULONG = 0x00000001; +pub const USER_HOME_DIRECTORY_REQUIRED: ULONG = 0x00000002; +pub const USER_PASSWORD_NOT_REQUIRED: ULONG = 0x00000004; +pub const USER_TEMP_DUPLICATE_ACCOUNT: ULONG = 0x00000008; +pub const USER_NORMAL_ACCOUNT: ULONG = 0x00000010; +pub const USER_MNS_LOGON_ACCOUNT: ULONG = 0x00000020; +pub const USER_INTERDOMAIN_TRUST_ACCOUNT: ULONG = 0x00000040; +pub const USER_WORKSTATION_TRUST_ACCOUNT: ULONG = 0x00000080; +pub const USER_SERVER_TRUST_ACCOUNT: ULONG = 0x00000100; +pub const USER_DONT_EXPIRE_PASSWORD: ULONG = 0x00000200; +pub const USER_ACCOUNT_AUTO_LOCKED: ULONG = 0x00000400; +pub const USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED: ULONG = 0x00000800; +pub const USER_SMARTCARD_REQUIRED: ULONG = 0x00001000; +pub const USER_TRUSTED_FOR_DELEGATION: ULONG = 0x00002000; +pub const USER_NOT_DELEGATED: ULONG = 0x00004000; +pub const USER_USE_DES_KEY_ONLY: ULONG = 0x00008000; +pub const USER_DONT_REQUIRE_PREAUTH: ULONG = 0x00010000; +pub const USER_PASSWORD_EXPIRED: ULONG = 0x00020000; +pub const USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: ULONG = 0x00040000; +pub const USER_NO_AUTH_DATA_REQUIRED: ULONG = 0x00080000; +pub const USER_PARTIAL_SECRETS_ACCOUNT: ULONG = 0x00100000; +pub const USER_USE_AES_KEYS: ULONG = 0x00200000; +pub const NEXT_FREE_ACCOUNT_CONTROL_BIT: ULONG = USER_USE_AES_KEYS << 1; +pub const USER_MACHINE_ACCOUNT_MASK: ULONG = USER_INTERDOMAIN_TRUST_ACCOUNT + | USER_WORKSTATION_TRUST_ACCOUNT | USER_SERVER_TRUST_ACCOUNT; +pub const USER_ACCOUNT_TYPE_MASK: ULONG = USER_TEMP_DUPLICATE_ACCOUNT | USER_NORMAL_ACCOUNT + | USER_MACHINE_ACCOUNT_MASK; +pub const USER_COMPUTED_ACCOUNT_CONTROL_BITS: ULONG = USER_ACCOUNT_AUTO_LOCKED + | USER_PASSWORD_EXPIRED; +pub const SAM_DAYS_PER_WEEK: USHORT = 7; +pub const SAM_HOURS_PER_WEEK: USHORT = 24 * SAM_DAYS_PER_WEEK; +pub const SAM_MINUTES_PER_WEEK: USHORT = 60 * SAM_HOURS_PER_WEEK; +STRUCT!{struct LOGON_HOURS { + UnitsPerWeek: USHORT, + LogonHours: PUCHAR, +}} +pub type PLOGON_HOURS = *mut LOGON_HOURS; +STRUCT!{struct SR_SECURITY_DESCRIPTOR { + Length: ULONG, + SecurityDescriptor: PUCHAR, +}} +pub type PSR_SECURITY_DESCRIPTOR = *mut SR_SECURITY_DESCRIPTOR; +STRUCT!{struct USER_ALL_INFORMATION { + LastLogon: LARGE_INTEGER, + LastLogoff: LARGE_INTEGER, + PasswordLastSet: LARGE_INTEGER, + AccountExpires: LARGE_INTEGER, + PasswordCanChange: LARGE_INTEGER, + PasswordMustChange: LARGE_INTEGER, + UserName: UNICODE_STRING, + FullName: UNICODE_STRING, + HomeDirectory: UNICODE_STRING, + HomeDirectoryDrive: UNICODE_STRING, + ScriptPath: UNICODE_STRING, + ProfilePath: UNICODE_STRING, + AdminComment: UNICODE_STRING, + WorkStations: UNICODE_STRING, + UserComment: UNICODE_STRING, + Parameters: UNICODE_STRING, + LmPassword: UNICODE_STRING, + NtPassword: UNICODE_STRING, + PrivateData: UNICODE_STRING, + SecurityDescriptor: SR_SECURITY_DESCRIPTOR, + UserId: ULONG, + PrimaryGroupId: ULONG, + UserAccountControl: ULONG, + WhichFields: ULONG, + LogonHours: LOGON_HOURS, + BadPasswordCount: USHORT, + LogonCount: USHORT, + CountryCode: USHORT, + CodePage: USHORT, + LmPasswordPresent: BOOLEAN, + NtPasswordPresent: BOOLEAN, + PasswordExpired: BOOLEAN, + PrivateDataSensitive: BOOLEAN, +}} +pub type PUSER_ALL_INFORMATION = *mut USER_ALL_INFORMATION; +pub const USER_ALL_PARAMETERS: ULONG = 0x00200000; +pub const CLEAR_BLOCK_LENGTH: usize = 8; +STRUCT!{struct CLEAR_BLOCK { + data: [CHAR; CLEAR_BLOCK_LENGTH], +}} +pub type PCLEAR_BLOCK = *mut CLEAR_BLOCK; +pub const CYPHER_BLOCK_LENGTH: usize = 8; +STRUCT!{struct CYPHER_BLOCK { + data: [CHAR; CYPHER_BLOCK_LENGTH], +}} +pub type PCYPHER_BLOCK = *mut CYPHER_BLOCK; +STRUCT!{struct LM_OWF_PASSWORD { + data: [CYPHER_BLOCK; 2], +}} +pub type PLM_OWF_PASSWORD = *mut LM_OWF_PASSWORD; +pub type LM_CHALLENGE = CLEAR_BLOCK; +pub type PLM_CHALLENGE = *mut LM_CHALLENGE; +pub type NT_OWF_PASSWORD = LM_OWF_PASSWORD; +pub type PNT_OWF_PASSWORD = *mut NT_OWF_PASSWORD; +pub type NT_CHALLENGE = LM_CHALLENGE; +pub type PNT_CHALLENGE = *mut NT_CHALLENGE; +pub const USER_SESSION_KEY_LENGTH: usize = CYPHER_BLOCK_LENGTH * 2; +STRUCT!{struct USER_SESSION_KEY { + data: [CYPHER_BLOCK; 2], +}} +pub type PUSER_SESSION_KEY = *mut USER_SESSION_KEY; +ENUM!{enum NETLOGON_LOGON_INFO_CLASS { + NetlogonInteractiveInformation = 1, + NetlogonNetworkInformation, + NetlogonServiceInformation, + NetlogonGenericInformation, + NetlogonInteractiveTransitiveInformation, + NetlogonNetworkTransitiveInformation, + NetlogonServiceTransitiveInformation, +}} +STRUCT!{struct NETLOGON_LOGON_IDENTITY_INFO { + LogonDomainName: UNICODE_STRING, + ParameterControl: ULONG, + LogonId: OLD_LARGE_INTEGER, + UserName: UNICODE_STRING, + Workstation: UNICODE_STRING, +}} +pub type PNETLOGON_LOGON_IDENTITY_INFO = *mut NETLOGON_LOGON_IDENTITY_INFO; +STRUCT!{struct NETLOGON_INTERACTIVE_INFO { + Identity: NETLOGON_LOGON_IDENTITY_INFO, + LmOwfPassword: LM_OWF_PASSWORD, + NtOwfPassword: NT_OWF_PASSWORD, +}} +pub type PNETLOGON_INTERACTIVE_INFO = *mut NETLOGON_INTERACTIVE_INFO; +STRUCT!{struct NETLOGON_SERVICE_INFO { + Identity: NETLOGON_LOGON_IDENTITY_INFO, + LmOwfPassword: LM_OWF_PASSWORD, + NtOwfPassword: NT_OWF_PASSWORD, +}} +pub type PNETLOGON_SERVICE_INFO = *mut NETLOGON_SERVICE_INFO; +STRUCT!{struct NETLOGON_NETWORK_INFO { + Identity: NETLOGON_LOGON_IDENTITY_INFO, + LmChallenge: LM_CHALLENGE, + NtChallengeResponse: STRING, + LmChallengeResponse: STRING, +}} +pub type PNETLOGON_NETWORK_INFO = *mut NETLOGON_NETWORK_INFO; +STRUCT!{struct NETLOGON_GENERIC_INFO { + Identity: NETLOGON_LOGON_IDENTITY_INFO, + PackageName: UNICODE_STRING, + DataLength: ULONG, + LogonData: PUCHAR, +}} +pub type PNETLOGON_GENERIC_INFO = *mut NETLOGON_GENERIC_INFO; +pub const MSV1_0_PASSTHRU: ULONG = 0x01; +pub const MSV1_0_GUEST_LOGON: ULONG = 0x02; +STRUCT!{struct MSV1_0_VALIDATION_INFO { + LogoffTime: LARGE_INTEGER, + KickoffTime: LARGE_INTEGER, + LogonServer: UNICODE_STRING, + LogonDomainName: UNICODE_STRING, + SessionKey: USER_SESSION_KEY, + Authoritative: BOOLEAN, + UserFlags: ULONG, + WhichFields: ULONG, + UserId: ULONG, +}} +pub type PMSV1_0_VALIDATION_INFO = *mut MSV1_0_VALIDATION_INFO; +pub const MSV1_0_VALIDATION_LOGOFF_TIME: ULONG = 0x00000001; +pub const MSV1_0_VALIDATION_KICKOFF_TIME: ULONG = 0x00000002; +pub const MSV1_0_VALIDATION_LOGON_SERVER: ULONG = 0x00000004; +pub const MSV1_0_VALIDATION_LOGON_DOMAIN: ULONG = 0x00000008; +pub const MSV1_0_VALIDATION_SESSION_KEY: ULONG = 0x00000010; +pub const MSV1_0_VALIDATION_USER_FLAGS: ULONG = 0x00000020; +pub const MSV1_0_VALIDATION_USER_ID: ULONG = 0x00000040; +pub const MSV1_0_SUBAUTH_ACCOUNT_DISABLED: ULONG = 0x00000001; +pub const MSV1_0_SUBAUTH_PASSWORD: ULONG = 0x00000002; +pub const MSV1_0_SUBAUTH_WORKSTATIONS: ULONG = 0x00000004; +pub const MSV1_0_SUBAUTH_LOGON_HOURS: ULONG = 0x00000008; +pub const MSV1_0_SUBAUTH_ACCOUNT_EXPIRY: ULONG = 0x00000010; +pub const MSV1_0_SUBAUTH_PASSWORD_EXPIRY: ULONG = 0x00000020; +pub const MSV1_0_SUBAUTH_ACCOUNT_TYPE: ULONG = 0x00000040; +pub const MSV1_0_SUBAUTH_LOCKOUT: ULONG = 0x00000080; +// STATUS_* diff --git a/winapi/src/um/synchapi.rs b/winapi/src/um/synchapi.rs new file mode 100644 index 000000000..205579e66 --- /dev/null +++ b/winapi/src/um/synchapi.rs @@ -0,0 +1,349 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-synch-l1 +use shared::basetsd::SIZE_T; +use shared::minwindef::{BOOL, DWORD, LPLONG, LPVOID, PBOOL, ULONG}; +use um::minwinbase::{ + LPCRITICAL_SECTION, LPSECURITY_ATTRIBUTES, PCRITICAL_SECTION, PREASON_CONTEXT, +}; +use um::winnt::{ + BOOLEAN, HANDLE, LARGE_INTEGER, LONG, LPCSTR, LPCWSTR, PRTL_BARRIER, PRTL_RUN_ONCE, + PVOID, RTL_BARRIER, RTL_CONDITION_VARIABLE, RTL_CONDITION_VARIABLE_INIT, + RTL_RUN_ONCE, RTL_SRWLOCK, RTL_SRWLOCK_INIT, VOID +}; +pub const SRWLOCK_INIT: SRWLOCK = RTL_SRWLOCK_INIT; +pub type SRWLOCK = RTL_SRWLOCK; +pub type PSRWLOCK = *mut RTL_SRWLOCK; +extern "system" { + pub fn InitializeSRWLock( + SRWLock: PSRWLOCK, + ); + pub fn ReleaseSRWLockExclusive( + SRWLock: PSRWLOCK, + ); + pub fn ReleaseSRWLockShared( + SRWLock: PSRWLOCK, + ); + pub fn AcquireSRWLockExclusive( + SRWLock: PSRWLOCK, + ); + pub fn AcquireSRWLockShared( + SRWLock: PSRWLOCK, + ); + pub fn TryAcquireSRWLockExclusive( + SRWLock: PSRWLOCK, + ) -> BOOLEAN; + pub fn TryAcquireSRWLockShared( + SRWLock: PSRWLOCK, + ) -> BOOLEAN; + pub fn InitializeCriticalSection( + lpCriticalSection: LPCRITICAL_SECTION, + ); + pub fn EnterCriticalSection( + lpCriticalSection: LPCRITICAL_SECTION, + ); + pub fn LeaveCriticalSection( + lpCriticalSection: LPCRITICAL_SECTION, + ); + pub fn InitializeCriticalSectionAndSpinCount( + lpCriticalSection: LPCRITICAL_SECTION, + dwSpinCount: DWORD, + ) -> BOOL; + pub fn InitializeCriticalSectionEx( + lpCriticalSection: LPCRITICAL_SECTION, + dwSpinCount: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn SetCriticalSectionSpinCount( + lpCriticalSection: LPCRITICAL_SECTION, + dwSpinCount: DWORD, + ) -> DWORD; + pub fn TryEnterCriticalSection( + lpCriticalSection: LPCRITICAL_SECTION, + ) -> BOOL; + pub fn DeleteCriticalSection( + lpCriticalSection: LPCRITICAL_SECTION, + ); +} +pub type INIT_ONCE = RTL_RUN_ONCE; +pub type PINIT_ONCE = PRTL_RUN_ONCE; +pub type LPINIT_ONCE = PRTL_RUN_ONCE; +//pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = RTL_RUN_ONCE_INIT; +//pub const INIT_ONCE_CHECK_ONLY: ULONG = RTL_RUN_ONCE_CHECK_ONLY; +//pub const INIT_ONCE_ASYNC: ULONG = RTL_RUN_ONCE_ASYNC; +//pub const INIT_ONCE_INIT_FAILED: ULONG = RTL_RUN_ONCE_INIT_FAILED; +//pub const INIT_ONCE_CTX_RESERVED_BITS: usize = RTL_RUN_ONCE_CTX_RESERVED_BITS; +FN!{stdcall PINIT_ONCE_FN( + InitOnce: PINIT_ONCE, + Parameter: PVOID, + Context: *mut PVOID, +) -> BOOL} +extern "system" { + pub fn InitOnceInitialize( + InitOnce: PINIT_ONCE, + ); + pub fn InitOnceExecuteOnce( + InitOnce: PINIT_ONCE, + InitFn: PINIT_ONCE_FN, + Parameter: PVOID, + Context: *mut LPVOID, + ) -> BOOL; + pub fn InitOnceBeginInitialize( + lpInitOnce: LPINIT_ONCE, + dwFlags: DWORD, + fPending: PBOOL, + lpContext: *mut LPVOID, + ) -> BOOL; + pub fn InitOnceComplete( + lpInitOnce: LPINIT_ONCE, + dwFlags: DWORD, + lpContext: LPVOID, + ) -> BOOL; +} +pub type CONDITION_VARIABLE = RTL_CONDITION_VARIABLE; +pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; +pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = RTL_CONDITION_VARIABLE_INIT; +//pub const CONDITION_VARIABLE_LOCKMODE_SHARED: ULONG = RTL_CONDITION_VARIABLE_LOCKMODE_SHARED; +extern "system" { + pub fn InitializeConditionVariable( + ConditionVariable: PCONDITION_VARIABLE, + ); + pub fn WakeConditionVariable( + ConditionVariable: PCONDITION_VARIABLE, + ); + pub fn WakeAllConditionVariable( + ConditionVariable: PCONDITION_VARIABLE, + ); + pub fn SleepConditionVariableCS( + ConditionVariable: PCONDITION_VARIABLE, + CriticalSection: PCRITICAL_SECTION, + dwMilliseconds: DWORD, + ) -> BOOL; + pub fn SleepConditionVariableSRW( + ConditionVariable: PCONDITION_VARIABLE, + SRWLock: PSRWLOCK, + dwMilliseconds: DWORD, + Flags: ULONG, + ) -> BOOL; + pub fn SetEvent( + hEvent: HANDLE, + ) -> BOOL; + pub fn ResetEvent( + hEvent: HANDLE, + ) -> BOOL; + pub fn ReleaseSemaphore( + hSemaphore: HANDLE, + lReleaseCount: LONG, + lpPreviousCount: LPLONG, + ) -> BOOL; + pub fn ReleaseMutex( + hMutex: HANDLE, + ) -> BOOL; + pub fn WaitForSingleObject( + hHandle: HANDLE, + dwMilliseconds: DWORD, + ) -> DWORD; + pub fn SleepEx( + dwMilliseconds: DWORD, + bAlertable: BOOL, + ) -> DWORD; + pub fn WaitForSingleObjectEx( + hHandle: HANDLE, + dwMilliseconds: DWORD, + bAlertable: BOOL, + ) -> DWORD; + pub fn WaitForMultipleObjectsEx( + nCount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD, + bAlertable: BOOL, + ) -> DWORD; +} +//pub const MUTEX_MODIFY_STATE: DWORD = MUTANT_QUERY_STATE; +//pub const MUTEX_ALL_ACCESS: DWORD = MUTANT_ALL_ACCESS; +extern "system" { + pub fn CreateMutexA( + lpMutexAttributes: LPSECURITY_ATTRIBUTES, + bInitialOwner: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateMutexW( + lpMutexAttributes: LPSECURITY_ATTRIBUTES, + bInitialOwner: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn OpenMutexW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn CreateEventA( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateEventW( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn OpenEventA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn OpenEventW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn OpenSemaphoreW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCWSTR, + ) -> HANDLE; +} +FN!{stdcall PTIMERAPCROUTINE( + lpArgToCompletionRoutine: LPVOID, + dwTimerLowValue: DWORD, + dwTimerHighValue: DWORD, +) -> ()} +extern "system" { + pub fn OpenWaitableTimerW( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpTimerName: LPCWSTR, + ) -> HANDLE; + pub fn SetWaitableTimerEx( + hTimer: HANDLE, + lpDueTime: *const LARGE_INTEGER, + lPeriod: LONG, + pfnCompletionRoutine: PTIMERAPCROUTINE, + lpArgToCompletionRoutine: LPVOID, + WakeContext: PREASON_CONTEXT, + TolerableDelay: ULONG, + ) -> BOOL; + pub fn SetWaitableTimer( + hTimer: HANDLE, + lpDueTime: *const LARGE_INTEGER, + lPeriod: LONG, + pfnCompletionRoutine: PTIMERAPCROUTINE, + lpArgToCompletionRoutine: LPVOID, + fResume: BOOL, + ) -> BOOL; + pub fn CancelWaitableTimer( + hTimer: HANDLE, + ) -> BOOL; +} +pub const CREATE_MUTEX_INITIAL_OWNER: DWORD = 0x00000001; +extern "system" { + pub fn CreateMutexExA( + lpMutexAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; + pub fn CreateMutexExW( + lpMutexAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; +} +pub const CREATE_EVENT_MANUAL_RESET: DWORD = 0x00000001; +pub const CREATE_EVENT_INITIAL_SET: DWORD = 0x00000002; +extern "system" { + pub fn CreateEventExA( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; + pub fn CreateEventExW( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; + pub fn CreateSemaphoreExW( + lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES, + lInitialCount: LONG, + lMaximumCount: LONG, + lpName: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; +} +pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: DWORD = 0x00000001; +extern "system" { + pub fn CreateWaitableTimerExW( + lpTimerAttributes: LPSECURITY_ATTRIBUTES, + lpTimerName: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; +} +pub type SYNCHRONIZATION_BARRIER = RTL_BARRIER; +pub type PSYNCHRONIZATION_BARRIER = PRTL_BARRIER; +pub type LPSYNCHRONIZATION_BARRIER = PRTL_BARRIER; +pub const SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY: DWORD = 0x01; +pub const SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY: DWORD = 0x02; +pub const SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE: DWORD = 0x04; +extern "system" { + pub fn EnterSynchronizationBarrier( + lpBarrier: LPSYNCHRONIZATION_BARRIER, + dwFlags: DWORD, + ) -> BOOL; + pub fn InitializeSynchronizationBarrier( + lpBarrier: LPSYNCHRONIZATION_BARRIER, + lTotalThreads: LONG, + lSpinCount: LONG, + ) -> BOOL; + pub fn DeleteSynchronizationBarrier( + lpBarrier: LPSYNCHRONIZATION_BARRIER, + ) -> BOOL; + pub fn Sleep( + dwMilliseconds: DWORD, + ); + pub fn WaitOnAddress( + Address: *mut VOID, + CompareAddress: PVOID, + AddressSize: SIZE_T, + dwMilliseconds: DWORD, + ) -> BOOL; + pub fn WakeByAddressSingle( + Address: PVOID, + ); + pub fn WakeByAddressAll( + Address: PVOID, + ); + pub fn SignalObjectAndWait( + hObjectToSignal: HANDLE, + hObjectToWaitOn: HANDLE, + dwMilliseconds: DWORD, + bAlertable: BOOL, + ) -> DWORD; + pub fn WaitForMultipleObjects( + nCount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD, + ) -> DWORD; + pub fn CreateSemaphoreW( + lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES, + lInitialCount: LONG, + lMaximumCount: LONG, + lpName: LPCWSTR, + ) -> HANDLE; + pub fn CreateWaitableTimerW( + lpTimerAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + lpTimerName: LPCWSTR, + ) -> HANDLE; +} diff --git a/winapi/src/um/sysinfoapi.rs b/winapi/src/um/sysinfoapi.rs new file mode 100644 index 000000000..03bdb47d1 --- /dev/null +++ b/winapi/src/um/sysinfoapi.rs @@ -0,0 +1,217 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-sysinfo-l1. +use shared::basetsd::DWORD_PTR; +use shared::minwindef::{ + BOOL, BYTE, DWORD, LPDWORD, LPFILETIME, LPVOID, PBOOL, PDWORD, UINT, USHORT, WORD, +}; +use um::minwinbase::{LPSYSTEMTIME, SYSTEMTIME}; +use um::winnt::{ + DWORDLONG, HANDLE, LOGICAL_PROCESSOR_RELATIONSHIP, LPCSTR, LPCWSTR, LPOSVERSIONINFOA, + LPOSVERSIONINFOW, LPSTR, LPWSTR, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, + PSYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION, PULONGLONG, PVOID, ULONGLONG, +}; +STRUCT!{struct SYSTEM_INFO_u_s { + wProcessorArchitecture: WORD, + wReserved: WORD, +}} +UNION!{union SYSTEM_INFO_u { + [u32; 1], + dwOemId dwOemId_mut: DWORD, + s s_mut: SYSTEM_INFO_u_s, +}} +STRUCT!{struct SYSTEM_INFO { + u: SYSTEM_INFO_u, + dwPageSize: DWORD, + lpMinimumApplicationAddress: LPVOID, + lpMaximumApplicationAddress: LPVOID, + dwActiveProcessorMask: DWORD_PTR, + dwNumberOfProcessors: DWORD, + dwProcessorType: DWORD, + dwAllocationGranularity: DWORD, + wProcessorLevel: WORD, + wProcessorRevision: WORD, +}} +pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; +STRUCT!{struct MEMORYSTATUSEX { + dwLength: DWORD, + dwMemoryLoad: DWORD, + ullTotalPhys: DWORDLONG, + ullAvailPhys: DWORDLONG, + ullTotalPageFile: DWORDLONG, + ullAvailPageFile: DWORDLONG, + ullTotalVirtual: DWORDLONG, + ullAvailVirtual: DWORDLONG, + ullAvailExtendedVirtual: DWORDLONG, +}} +pub type LPMEMORYSTATUSEX = *mut MEMORYSTATUSEX; +extern "system" { + pub fn GlobalMemoryStatusEx( + lpBuffer: LPMEMORYSTATUSEX, + ) -> BOOL; + pub fn GetSystemInfo( + lpSystemInfo: LPSYSTEM_INFO, + ); + pub fn GetSystemTime( + lpSystemTime: LPSYSTEMTIME, + ); + pub fn GetSystemTimeAsFileTime( + lpSystemTimeAsFileTime: LPFILETIME, + ); + pub fn GetLocalTime( + lpSystemTime: LPSYSTEMTIME, + ); + pub fn GetVersion() -> DWORD; + pub fn SetLocalTime( + lpSystemTime: *const SYSTEMTIME, + ) -> BOOL; + pub fn GetTickCount() -> DWORD; + pub fn GetTickCount64() -> ULONGLONG; + pub fn GetSystemTimeAdjustment( + lpTimeAdjustment: PDWORD, + lpTimeIncrement: PDWORD, + lpTimeAdjustmentDisabled: PBOOL, + ) -> BOOL; + pub fn GetSystemDirectoryA( + lpBuffer: LPSTR, + uSize: UINT, + ) -> UINT; + pub fn GetSystemDirectoryW( + lpBuffer: LPWSTR, + uSize: UINT, + ) -> UINT; + pub fn GetWindowsDirectoryA( + lpBuffer: LPSTR, + uSize: UINT, + ) -> UINT; + pub fn GetWindowsDirectoryW( + lpBuffer: LPWSTR, + uSize: UINT, + ) -> UINT; + pub fn GetSystemWindowsDirectoryA( + lpBuffer: LPSTR, + uSize: UINT, + ) -> UINT; + pub fn GetSystemWindowsDirectoryW( + lpBuffer: LPWSTR, + uSize: UINT, + ) -> UINT; +} +ENUM!{enum COMPUTER_NAME_FORMAT { + ComputerNameNetBIOS, + ComputerNameDnsHostname, + ComputerNameDnsDomain, + ComputerNameDnsFullyQualified, + ComputerNamePhysicalNetBIOS, + ComputerNamePhysicalDnsHostname, + ComputerNamePhysicalDnsDomain, + ComputerNamePhysicalDnsFullyQualified, + ComputerNameMax, +}} +extern "system" { + pub fn GetComputerNameExA( + NameType: COMPUTER_NAME_FORMAT, + lpBuffer: LPSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn GetComputerNameExW( + NameType: COMPUTER_NAME_FORMAT, + lpBuffer: LPWSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn SetComputerNameExW( + NameType: COMPUTER_NAME_FORMAT, + lpBuffer: LPCWSTR, + ) -> BOOL; + pub fn SetSystemTime( + lpSystemTime: *const SYSTEMTIME, + ) -> BOOL; + pub fn GetVersionExA( + lpVersionInformation: LPOSVERSIONINFOA, + ) -> BOOL; + pub fn GetVersionExW( + lpVersionInformation: LPOSVERSIONINFOW, + ) -> BOOL; + pub fn GetLogicalProcessorInformation( + Buffer: PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, + ReturnedLength: PDWORD, + ) -> BOOL; + pub fn GetLogicalProcessorInformationEx( + RelationshipType: LOGICAL_PROCESSOR_RELATIONSHIP, + Buffer: PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, + ReturnedLength: PDWORD, + ) -> BOOL; + pub fn GetNativeSystemInfo( + lpSystemInfo: LPSYSTEM_INFO, + ); + pub fn GetSystemTimePreciseAsFileTime( + lpSystemTimeAsFileTime: LPFILETIME, + ); + pub fn GetProductInfo( + dwOSMajorVersion: DWORD, + dwOSMinorVersion: DWORD, + dwSpMajorVersion: DWORD, + dwSpMinorVersion: DWORD, + pdwReturnedProductType: PDWORD, + ) -> BOOL; + pub fn VerSetConditionMask( + ConditionMask: ULONGLONG, + TypeMask: DWORD, + Condition: BYTE, + ) -> ULONGLONG; + // pub fn GetOsSafeBootMode(); + pub fn EnumSystemFirmwareTables( + FirmwareTableProviderSignature: DWORD, + pFirmwareTableEnumBuffer: PVOID, + BufferSize: DWORD, + ) -> UINT; + pub fn GetSystemFirmwareTable( + FirmwareTableProviderSignature: DWORD, + FirmwareTableID: DWORD, + pFirmwareTableBuffer: PVOID, + BufferSize: DWORD, + ) -> UINT; + pub fn DnsHostnameToComputerNameExW( + Hostname: LPCWSTR, + ComputerName: LPWSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn GetPhysicallyInstalledSystemMemory( + TotalMemoryInKilobytes: PULONGLONG, + ) -> BOOL; +} +pub const SCEX2_ALT_NETBIOS_NAME: DWORD = 0x00000001; +extern "system" { + pub fn SetComputerNameEx2W( + NameType: COMPUTER_NAME_FORMAT, + Flags: DWORD, + lpBuffer: LPCWSTR, + ) -> BOOL; + pub fn SetSystemTimeAdjustment( + dwTimeAdjustment: DWORD, + bTimeAdjustmentDisabled: BOOL, + ) -> BOOL; + pub fn InstallELAMCertificateInfo( + ELAMFile: HANDLE, + ) -> BOOL; + pub fn GetProcessorSystemCycleTime( + Group: USHORT, + Buffer: PSYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION, + ReturnedLength: PDWORD, + ) -> BOOL; + // pub fn GetOsManufacturingMode(); + // pub fn GetIntegratedDisplaySize(); + pub fn SetComputerNameA( + lpComputerName: LPCSTR, + ) -> BOOL; + pub fn SetComputerNameW( + lpComputerName: LPCWSTR, + ) -> BOOL; + pub fn SetComputerNameExA( + NameType: COMPUTER_NAME_FORMAT, + lpBuffer: LPCSTR, + ) -> BOOL; +} diff --git a/winapi/src/um/systemtopologyapi.rs b/winapi/src/um/systemtopologyapi.rs new file mode 100644 index 000000000..8591fac8d --- /dev/null +++ b/winapi/src/um/systemtopologyapi.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, PULONG, PUSHORT, ULONG, USHORT}; +use um::winnt::PGROUP_AFFINITY; +extern "system" { + pub fn GetNumaHighestNodeNumber( + HighestNodeNumber: PULONG, + ) -> BOOL; + pub fn GetNumaNodeProcessorMaskEx( + Node: USHORT, + ProcessorMask: PGROUP_AFFINITY, + ) -> BOOL; + pub fn GetNumaProximityNodeEx( + ProximityId: ULONG, + NodeNumber: PUSHORT, + ) -> BOOL; +} diff --git a/winapi/src/um/taskschd.rs b/winapi/src/um/taskschd.rs new file mode 100644 index 000000000..d73786cd3 --- /dev/null +++ b/winapi/src/um/taskschd.rs @@ -0,0 +1,1233 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_long, c_short}; +use shared::minwindef::{DWORD, INT}; +use shared::wtypes::{BSTR, DATE, VARIANT_BOOL}; +use um::minwinbase::SYSTEMTIME; +use um::oaidl::{IDispatch, IDispatchVtbl, SAFEARRAY, VARIANT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl, LPUNKNOWN}; +use um::winnt::{HRESULT, LONG}; +RIDL!{#[uuid(0x0f87369f, 0xa4e5, 0x4cfc, 0xbd, 0x3e, 0x73, 0xe6, 0x15, 0x45, 0x72, 0xdd)] +class TaskScheduler;} +RIDL!{#[uuid(0xf2a69db7, 0xda2c, 0x4352, 0x90, 0x66, 0x86, 0xfe, 0xe6, 0xda, 0xca, 0xc9)] +class TaskHandlerPS;} +RIDL!{#[uuid(0x9f15266d, 0xd7ba, 0x48f0, 0x93, 0xc1, 0xe6, 0x89, 0x5f, 0x6f, 0xe5, 0xac)] +class TaskHandlerStatusPS;} +RIDL!{#[uuid(0x79184a66, 0x8664, 0x423f, 0x97, 0xf1, 0x63, 0x73, 0x56, 0xa5, 0xd8, 0x12)] +interface ITaskFolderCollection(ITaskFolderCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut LONG, + ) -> HRESULT, + fn get_Item( + index: VARIANT, + ppFolder: *mut *mut ITaskFolder, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8cfac062, 0xa080, 0x4c15, 0x9a, 0x88, 0xaa, 0x7c, 0x2a, 0xf8, 0x0d, 0xfc)] +interface ITaskFolder(ITaskFolderVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + pName: *mut BSTR, + ) -> HRESULT, + fn get_Path( + pPath: *mut BSTR, + ) -> HRESULT, + fn GetFolder( + Path: BSTR, + ppFolder: *mut *mut ITaskFolder, + ) -> HRESULT, + fn GetFolders( + flags: LONG, + ppFolders: *mut *mut ITaskFolderCollection, + ) -> HRESULT, + fn CreateFolder( + subFolderName: BSTR, + sddl: VARIANT, + ppFolder: *mut *mut ITaskFolder, + ) -> HRESULT, + fn DeleteFolder( + subFolderName: BSTR, + flags: LONG, + ) -> HRESULT, + fn GetTask( + Path: BSTR, + ppTask: *mut *mut IRegisteredTask, + ) -> HRESULT, + fn GetTasks( + flags: LONG, + ppTasks: *mut *mut IRegisteredTaskCollection, + ) -> HRESULT, + fn DeleteTask( + Name: BSTR, + flags: LONG, + ) -> HRESULT, + fn RegisterTask( + Path: BSTR, + XmlText: BSTR, + flags: LONG, + UserId: VARIANT, + password: VARIANT, + LogonType: TASK_LOGON_TYPE, + sddl: VARIANT, + ppTask: *mut *mut IRegisteredTask, + ) -> HRESULT, + fn RegisterTaskDefinition( + Path: BSTR, + pDefinition: *const ITaskDefinition, + flags: LONG, + UserId: VARIANT, + password: VARIANT, + LogonType: TASK_LOGON_TYPE, + sddl: VARIANT, + ppTask: *mut *mut IRegisteredTask, + ) -> HRESULT, + fn GetSecurityDescriptor( + securityInformation: LONG, + pSddl: *mut BSTR, + ) -> HRESULT, + fn SetSecurityDescriptor( + sddl: BSTR, + flags: LONG, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9c86f320, 0xdee3, 0x4dd1, 0xb9, 0x72, 0xa3, 0x03, 0xf2, 0x6b, 0x06, 0x1e)] +interface IRegisteredTask(IRegisteredTaskVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + pName: *mut BSTR, + ) -> HRESULT, + fn get_Path( + pPath: *mut BSTR, + ) -> HRESULT, + fn get_State( + pState: *mut TASK_STATE, + ) -> HRESULT, + fn get_Enabled( + pEnabled: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Enabled( + pEnabled: VARIANT_BOOL, + ) -> HRESULT, + fn Run( + params: VARIANT, + ppRunningTask: *mut *mut IRunningTask, + ) -> HRESULT, + fn RunEx( + params: VARIANT, + flags: LONG, + sessionID: LONG, + user: BSTR, + ppRunningTask: *mut *mut IRunningTask, + ) -> HRESULT, + fn GetInstances( + flags: LONG, + ppRunningTasks: *mut *mut IRunningTaskCollection, + ) -> HRESULT, + fn get_LastRunTime( + pLastRunTime: *mut DATE, + ) -> HRESULT, + fn get_LastTaskResult( + pLastTaskResult: *mut LONG, + ) -> HRESULT, + fn get_NumberOfMissedRuns( + pNumberOfMissedRuns: *mut LONG, + ) -> HRESULT, + fn get_NextRunTime( + pNextRunTime: *mut DATE, + ) -> HRESULT, + fn get_Definition( + ppDefinition: *mut *mut ITaskDefinition, + ) -> HRESULT, + fn get_Xml( + pXml: *mut BSTR, + ) -> HRESULT, + fn GetSecurityDescriptor( + securityInformation: LONG, + pSddl: *mut BSTR, + ) -> HRESULT, + fn SetSecurityDescriptor( + sddl: BSTR, + flags: LONG, + ) -> HRESULT, + fn Stop( + flags: LONG, + ) -> HRESULT, + fn GetRunTimes( + pstStart: *const SYSTEMTIME, + pstEnd: *const SYSTEMTIME, + pCount: *mut DWORD, + pRunTimes: *mut *mut SYSTEMTIME, + ) -> HRESULT, +}} +ENUM!{enum TASK_STATE { + TASK_STATE_UNKNOWN = 0, + TASK_STATE_DISABLED = 1, + TASK_STATE_QUEUED = 2, + TASK_STATE_READY = 3, + TASK_STATE_RUNNING = 4, +}} +RIDL!{#[uuid(0x653758fb, 0x7b9a, 0x4f1e, 0xa4, 0x71, 0xbe, 0xeb, 0x8e, 0x9b, 0x83, 0x4e)] +interface IRunningTask(IRunningTaskVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + pName: *mut BSTR, + ) -> HRESULT, + fn get_InstanceGuid( + pGuid: *mut BSTR, + ) -> HRESULT, + fn get_Path( + pPath: *mut BSTR, + ) -> HRESULT, + fn get_State( + pState: *mut TASK_STATE, + ) -> HRESULT, + fn get_CurrentAction( + pName: *mut BSTR, + ) -> HRESULT, + fn Stop() -> HRESULT, + fn Refresh() -> HRESULT, + fn get_EnginePID( + pPID: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6a67614b, 0x6828, 0x4fec, 0xaa, 0x54, 0x6d, 0x52, 0xe8, 0xf1, 0xf2, 0xdb)] +interface IRunningTaskCollection(IRunningTaskCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut LONG, + ) -> HRESULT, + fn get_Item( + index: VARIANT, + ppRunningTask: *mut *mut IRunningTask, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf5bc8fc5, 0x536d, 0x4f77, 0xb8, 0x52, 0xfb, 0xc1, 0x35, 0x6f, 0xde, 0xb6)] +interface ITaskDefinition(ITaskDefinitionVtbl): IDispatch(IDispatchVtbl) { + fn get_RegistrationInfo( + ppRegistrationInfo: *mut *mut IRegistrationInfo, + ) -> HRESULT, + fn put_RegistrationInfo( + ppRegistrationInfo: *const IRegistrationInfo, + ) -> HRESULT, + fn get_Triggers( + ppTriggers: *mut *mut ITriggerCollection, + ) -> HRESULT, + fn put_Triggers( + ppTriggers: *const ITriggerCollection, + ) -> HRESULT, + fn get_Settings( + ppSettings: *mut *mut ITaskSettings, + ) -> HRESULT, + fn put_Settings( + ppSettings: *const ITaskSettings, + ) -> HRESULT, + fn get_Data( + pData: *mut BSTR, + ) -> HRESULT, + fn put_Data( + pData: BSTR, + ) -> HRESULT, + fn get_Principal( + ppPrincipal: *mut *mut IPrincipal, + ) -> HRESULT, + fn put_Principal( + ppPrincipal: *const IPrincipal, + ) -> HRESULT, + fn get_Actions( + ppActions: *mut *mut IActionCollection, + ) -> HRESULT, + fn put_Actions( + ppActions: *const IActionCollection, + ) -> HRESULT, + fn get_XmlText( + pXml: *mut BSTR, + ) -> HRESULT, + fn put_XmlText( + pXml: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x416d8b73, 0xcb41, 0x4ea1, 0x80, 0x5c, 0x9b, 0xe9, 0xa5, 0xac, 0x4a, 0x74)] +interface IRegistrationInfo(IRegistrationInfoVtbl): IDispatch(IDispatchVtbl) { + fn get_Description( + pDescription: *mut BSTR, + ) -> HRESULT, + fn put_Description( + pDescription: BSTR, + ) -> HRESULT, + fn get_Author( + pAuthor: *mut BSTR, + ) -> HRESULT, + fn put_Author( + pAuthor: BSTR, + ) -> HRESULT, + fn get_Version( + pVersion: *mut BSTR, + ) -> HRESULT, + fn put_Version( + pVersion: BSTR, + ) -> HRESULT, + fn get_Date( + pDate: *mut BSTR, + ) -> HRESULT, + fn put_Date( + pDate: BSTR, + ) -> HRESULT, + fn get_Documentation( + pDocumentation: *mut BSTR, + ) -> HRESULT, + fn put_Documentation( + pDocumentation: BSTR, + ) -> HRESULT, + fn get_XmlText( + pText: *mut BSTR, + ) -> HRESULT, + fn put_XmlText( + pText: BSTR, + ) -> HRESULT, + fn get_URI( + pUri: *mut BSTR, + ) -> HRESULT, + fn put_URI( + pUri: BSTR, + ) -> HRESULT, + fn get_SecurityDescriptor( + pSddl: *mut VARIANT, + ) -> HRESULT, + fn put_SecurityDescriptor( + pSddl: VARIANT, + ) -> HRESULT, + fn get_Source( + pSource: *mut BSTR, + ) -> HRESULT, + fn put_Source( + pSource: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x85df5081, 0x1b24, 0x4f32, 0x87, 0x8a, 0xd9, 0xd1, 0x4d, 0xf4, 0xcb, 0x77)] +interface ITriggerCollection(ITriggerCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut c_long, + ) -> HRESULT, + fn get_Item( + index: c_long, + ppTrigger: *mut *mut ITrigger, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, + fn Create( + Type: TASK_TRIGGER_TYPE2, + ppTrigger: *mut *mut ITrigger, + ) -> HRESULT, + fn Remove( + index: VARIANT, + ) -> HRESULT, + fn Clear() -> HRESULT, +}} +RIDL!{#[uuid(0x09941815, 0xea89, 0x4b5b, 0x89, 0xe0, 0x2a, 0x77, 0x38, 0x01, 0xfa, 0xc3)] +interface ITrigger(ITriggerVtbl): IDispatch(IDispatchVtbl) { + fn get_Type( + pType: *mut TASK_TRIGGER_TYPE2, + ) -> HRESULT, + fn get_Id( + pId: *mut BSTR, + ) -> HRESULT, + fn put_Id( + pId: BSTR, + ) -> HRESULT, + fn get_Repetition( + ppRepeat: *mut *mut IRepetitionPattern, + ) -> HRESULT, + fn put_Repetition( + ppRepeat: *const IRepetitionPattern, + ) -> HRESULT, + fn get_ExecutionTimeLimit( + pTimeLimit: *mut BSTR, + ) -> HRESULT, + fn put_ExecutionTimeLimit( + pTimeLimit: BSTR, + ) -> HRESULT, + fn get_StartBoundary( + pStart: *mut BSTR, + ) -> HRESULT, + fn put_StartBoundary( + pStart: BSTR, + ) -> HRESULT, + fn get_EndBoundary( + pEnd: *mut BSTR, + ) -> HRESULT, + fn put_EndBoundary( + pEnd: BSTR, + ) -> HRESULT, + fn get_Enabled( + pEnabled: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Enabled( + pEnabled: VARIANT_BOOL, + ) -> HRESULT, +}} +ENUM!{enum TASK_TRIGGER_TYPE2 { + TASK_TRIGGER_EVENT = 0, + TASK_TRIGGER_TIME = 1, + TASK_TRIGGER_DAILY = 2, + TASK_TRIGGER_WEEKLY = 3, + TASK_TRIGGER_MONTHLY = 4, + TASK_TRIGGER_MONTHLYDOW = 5, + TASK_TRIGGER_IDLE = 6, + TASK_TRIGGER_REGISTRATION = 7, + TASK_TRIGGER_BOOT = 8, + TASK_TRIGGER_LOGON = 9, + TASK_TRIGGER_SESSION_STATE_CHANGE = 11, + TASK_TRIGGER_CUSTOM_TRIGGER_01 = 12, +}} +RIDL!{#[uuid(0x7fb9acf1, 0x26be, 0x400e, 0x85, 0xb5, 0x29, 0x4b, 0x9c, 0x75, 0xdf, 0xd6)] +interface IRepetitionPattern(IRepetitionPatternVtbl): IDispatch(IDispatchVtbl) { + fn get_Interval( + pInterval: *mut BSTR, + ) -> HRESULT, + fn put_Interval( + pInterval: BSTR, + ) -> HRESULT, + fn get_Duration( + pDuration: *mut BSTR, + ) -> HRESULT, + fn put_Duration( + pDuration: BSTR, + ) -> HRESULT, + fn get_StopAtDurationEnd( + pStop: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_StopAtDurationEnd( + pStop: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8fd4711d, 0x2d02, 0x4c8c, 0x87, 0xe3, 0xef, 0xf6, 0x99, 0xde, 0x12, 0x7e)] +interface ITaskSettings(ITaskSettingsVtbl): IDispatch(IDispatchVtbl) { + fn get_AllowDemandStart( + pAllowDemandStart: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_AllowDemandStart( + pAllowDemandStart: VARIANT_BOOL, + ) -> HRESULT, + fn get_RestartInterval( + pRestartInterval: *mut BSTR, + ) -> HRESULT, + fn put_RestartInterval( + pRestartInterval: BSTR, + ) -> HRESULT, + fn get_RestartCount( + pRestartCount: *mut INT, + ) -> HRESULT, + fn put_RestartCount( + pRestartCount: INT, + ) -> HRESULT, + fn get_MultipleInstances( + pPolicy: *mut TASK_INSTANCES_POLICY, + ) -> HRESULT, + fn put_MultipleInstances( + pPolicy: TASK_INSTANCES_POLICY, + ) -> HRESULT, + fn get_StopIfGoingOnBatteries( + pStopIfOnBatteries: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_StopIfGoingOnBatteries( + pStopIfOnBatteries: VARIANT_BOOL, + ) -> HRESULT, + fn get_DisallowStartIfOnBatteries( + pDisallowStart: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_DisallowStartIfOnBatteries( + pDisallowStart: VARIANT_BOOL, + ) -> HRESULT, + fn get_AllowHardTerminate( + pAllowHardTerminate: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_AllowHardTerminate( + pAllowHardTerminate: VARIANT_BOOL, + ) -> HRESULT, + fn get_StartWhenAvailable( + pStartWhenAvailable: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_StartWhenAvailable( + pStartWhenAvailable: VARIANT_BOOL, + ) -> HRESULT, + fn get_XmlText( + pText: *mut BSTR, + ) -> HRESULT, + fn put_XmlText( + pText: BSTR, + ) -> HRESULT, + fn get_RunOnlyIfNetworkAvailable( + pRunOnlyIfNetworkAvailable: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RunOnlyIfNetworkAvailable( + pRunOnlyIfNetworkAvailable: VARIANT_BOOL, + ) -> HRESULT, + fn get_ExecutionTimeLimit( + pExecutionTimeLimit: *mut BSTR, + ) -> HRESULT, + fn put_ExecutionTimeLimit( + pExecutionTimeLimit: BSTR, + ) -> HRESULT, + fn get_Enabled( + pEnabled: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Enabled( + pEnabled: VARIANT_BOOL, + ) -> HRESULT, + fn get_DeleteExpiredTaskAfter( + pExpirationDelay: *mut BSTR, + ) -> HRESULT, + fn put_DeleteExpiredTaskAfter( + pExpirationDelay: BSTR, + ) -> HRESULT, + fn get_Priority( + pPriority: *mut INT, + ) -> HRESULT, + fn put_Priority( + pPriority: INT, + ) -> HRESULT, + fn get_Compatibility( + pCompatLevel: *mut TASK_COMPATIBILITY, + ) -> HRESULT, + fn put_Compatibility( + pCompatLevel: TASK_COMPATIBILITY, + ) -> HRESULT, + fn get_Hidden( + pHidden: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Hidden( + pHidden: VARIANT_BOOL, + ) -> HRESULT, + fn get_IdleSettings( + ppIdleSettings: *mut *mut IIdleSettings, + ) -> HRESULT, + fn put_IdleSettings( + ppIdleSettings: *const IIdleSettings, + ) -> HRESULT, + fn get_RunOnlyIfIdle( + pRunOnlyIfIdle: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RunOnlyIfIdle( + pRunOnlyIfIdle: VARIANT_BOOL, + ) -> HRESULT, + fn get_WakeToRun( + pWake: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_WakeToRun( + pWake: VARIANT_BOOL, + ) -> HRESULT, + fn get_NetworkSettings( + ppNetworkSettings: *mut *mut INetworkSettings, + ) -> HRESULT, + fn put_NetworkSettings( + ppNetworkSettings: *const INetworkSettings, + ) -> HRESULT, +}} +ENUM!{enum TASK_INSTANCES_POLICY { + TASK_INSTANCES_PARALLEL = 0, + TASK_INSTANCES_QUEUE = 1, + TASK_INSTANCES_IGNORE_NEW = 2, + TASK_INSTANCES_STOP_EXISTING = 3, +}} +ENUM!{enum TASK_COMPATIBILITY { + TASK_COMPATIBILITY_AT = 0, + TASK_COMPATIBILITY_V1 = 1, + TASK_COMPATIBILITY_V2 = 2, + TASK_COMPATIBILITY_V2_1 = 3, + TASK_COMPATIBILITY_V2_2 = 4, + TASK_COMPATIBILITY_V2_3 = 5, + TASK_COMPATIBILITY_V2_4 = 6, +}} +RIDL!{#[uuid(0x84594461, 0x0053, 0x4342, 0xa8, 0xfd, 0x08, 0x8f, 0xab, 0xf1, 0x1f, 0x32)] +interface IIdleSettings(IIdleSettingsVtbl): IDispatch(IDispatchVtbl) { + fn get_IdleDuration( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_IdleDuration( + pDelay: BSTR, + ) -> HRESULT, + fn get_WaitTimeout( + pTimeout: *mut BSTR, + ) -> HRESULT, + fn put_WaitTimeout( + pTimeout: BSTR, + ) -> HRESULT, + fn get_StopOnIdleEnd( + pStop: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_StopOnIdleEnd( + pStop: VARIANT_BOOL, + ) -> HRESULT, + fn get_RestartOnIdle( + pRestart: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RestartOnIdle( + pRestart: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9f7dea84, 0xc30b, 0x4245, 0x80, 0xb6, 0x00, 0xe9, 0xf6, 0x46, 0xf1, 0xb4)] +interface INetworkSettings(INetworkSettingsVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + pName: *mut BSTR, + ) -> HRESULT, + fn put_Name( + pName: BSTR, + ) -> HRESULT, + fn get_Id( + pId: *mut BSTR, + ) -> HRESULT, + fn put_Id( + pId: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd98d51e5, 0xc9b4, 0x496a, 0xa9, 0xc1, 0x18, 0x98, 0x02, 0x61, 0xcf, 0x0f)] +interface IPrincipal(IPrincipalVtbl): IDispatch(IDispatchVtbl) { + fn get_Id( + pId: *mut BSTR, + ) -> HRESULT, + fn put_Id( + pId: BSTR, + ) -> HRESULT, + fn get_DisplayName( + pName: *mut BSTR, + ) -> HRESULT, + fn put_DisplayName( + pName: BSTR, + ) -> HRESULT, + fn get_UserId( + pUser: *mut BSTR, + ) -> HRESULT, + fn put_UserId( + pUser: BSTR, + ) -> HRESULT, + fn get_LogonType( + pLogon: *mut TASK_LOGON_TYPE, + ) -> HRESULT, + fn put_LogonType( + pLogon: TASK_LOGON_TYPE, + ) -> HRESULT, + fn get_GroupId( + pGroup: *mut BSTR, + ) -> HRESULT, + fn put_GroupId( + pGroup: BSTR, + ) -> HRESULT, + fn get_RunLevel( + pRunLevel: *mut TASK_RUNLEVEL, + ) -> HRESULT, + fn put_RunLevel( + pRunLevel: TASK_RUNLEVEL, + ) -> HRESULT, +}} +ENUM!{enum TASK_LOGON_TYPE { + TASK_LOGON_NONE = 0, + TASK_LOGON_PASSWORD = 1, + TASK_LOGON_S4U = 2, + TASK_LOGON_INTERACTIVE_TOKEN = 3, + TASK_LOGON_GROUP = 4, + TASK_LOGON_SERVICE_ACCOUNT = 5, + TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6, +}} +ENUM!{enum TASK_RUNLEVEL { + TASK_RUNLEVEL_LUA = 0, + TASK_RUNLEVEL_HIGHEST = 1, +}} +RIDL!{#[uuid(0x02820e19, 0x7b98, 0x4ed2, 0xb2, 0xe8, 0xfd, 0xcc, 0xce, 0xff, 0x61, 0x9b)] +interface IActionCollection(IActionCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut c_long, + ) -> HRESULT, + fn get_Item( + index: c_long, + ppAction: *mut *mut IAction, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, + fn get_XmlText( + pText: *mut BSTR, + ) -> HRESULT, + fn put_XmlText( + pText: BSTR, + ) -> HRESULT, + fn Create( + Type: TASK_ACTION_TYPE, + ppAction: *mut *mut IAction, + ) -> HRESULT, + fn Remove( + index: VARIANT, + ) -> HRESULT, + fn Clear() -> HRESULT, + fn get_Context( + pContext: *mut BSTR, + ) -> HRESULT, + fn put_Context( + pContext: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbae54997, 0x48b1, 0x4cbe, 0x99, 0x65, 0xd6, 0xbe, 0x26, 0x3e, 0xbe, 0xa4)] +interface IAction(IActionVtbl): IDispatch(IDispatchVtbl) { + fn get_Id( + pId: *mut BSTR, + ) -> HRESULT, + fn put_Id( + pId: BSTR, + ) -> HRESULT, + fn get_Type( + pType: *mut TASK_ACTION_TYPE, + ) -> HRESULT, +}} +ENUM!{enum TASK_ACTION_TYPE { + TASK_ACTION_EXEC = 0, + TASK_ACTION_COM_HANDLER = 5, + TASK_ACTION_SEND_EMAIL = 6, + TASK_ACTION_SHOW_MESSAGE = 7, +}} +RIDL!{#[uuid(0x86627eb4, 0x42a7, 0x41e4, 0xa4, 0xd9, 0xac, 0x33, 0xa7, 0x2f, 0x2d, 0x52)] +interface IRegisteredTaskCollection(IRegisteredTaskCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut LONG, + ) -> HRESULT, + fn get_Item( + index: VARIANT, + ppRegisteredTask: *mut *mut IRegisteredTask, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2faba4c7, 0x4da9, 0x4013, 0x96, 0x97, 0x20, 0xcc, 0x3f, 0xd4, 0x0f, 0x85)] +interface ITaskService(ITaskServiceVtbl): IDispatch(IDispatchVtbl) { + fn GetFolder( + Path: BSTR, + ppFolder: *mut *mut ITaskFolder, + ) -> HRESULT, + fn GetRunningTasks( + flags: LONG, + ppRunningTasks: *mut *mut IRunningTaskCollection, + ) -> HRESULT, + fn NewTask( + flags: DWORD, + ppDefinition: *mut *mut ITaskDefinition, + ) -> HRESULT, + fn Connect( + serverName: VARIANT, + user: VARIANT, + domain: VARIANT, + password: VARIANT, + ) -> HRESULT, + fn get_Connected( + pConnected: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_TargetServer( + pServer: *mut BSTR, + ) -> HRESULT, + fn get_ConnectedUser( + pUser: *mut BSTR, + ) -> HRESULT, + fn get_ConnectedDomain( + pDomain: *mut BSTR, + ) -> HRESULT, + fn get_HighestVersion( + pVersion: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x839d7762, 0x5121, 0x4009, 0x92, 0x34, 0x4f, 0x0d, 0x19, 0x39, 0x4f, 0x04)] +interface ITaskHandler(ITaskHandlerVtbl): IUnknown(IUnknownVtbl) { + fn Start( + pHandlerServices: LPUNKNOWN, + Data: BSTR, + ) -> HRESULT, + fn Stop( + pRetCode: *mut HRESULT, + ) -> HRESULT, + fn Pause() -> HRESULT, + fn Resume() -> HRESULT, +}} +RIDL!{#[uuid(0xeaec7a8f, 0x27a0, 0x4ddc, 0x86, 0x75, 0x14, 0x72, 0x6a, 0x01, 0xa3, 0x8a)] +interface ITaskHandlerStatus(ITaskHandlerStatusVtbl): IUnknown(IUnknownVtbl) { + fn UpdateStatus( + percentComplete: c_short, + statusMessage: BSTR, + ) -> HRESULT, + fn TaskCompleted( + taskErrCode: HRESULT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3e4c9351, 0xd966, 0x4b8b, 0xbb, 0x87, 0xce, 0xba, 0x68, 0xbb, 0x01, 0x07)] +interface ITaskVariables(ITaskVariablesVtbl): IUnknown(IUnknownVtbl) { + fn GetInput( + pInput: *mut BSTR, + ) -> HRESULT, + fn SetOutput( + input: BSTR, + ) -> HRESULT, + fn GetContext( + pContext: *mut BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x39038068, 0x2b46, 0x4afd, 0x86, 0x62, 0x7b, 0xb6, 0xf8, 0x68, 0xd2, 0x21)] +interface ITaskNamedValuePair(ITaskNamedValuePairVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + pName: *mut BSTR, + ) -> HRESULT, + fn put_Name( + pName: BSTR, + ) -> HRESULT, + fn get_Value( + pValue: *mut BSTR, + ) -> HRESULT, + fn put_Value( + pValue: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb4ef826b, 0x63c3, 0x46e4, 0xa5, 0x04, 0xef, 0x69, 0xe4, 0xf7, 0xea, 0x4d)] +interface ITaskNamedValueCollection(ITaskNamedValueCollectionVtbl): IDispatch(IDispatchVtbl) { + fn get_Count( + pCount: *mut c_long, + ) -> HRESULT, + fn get_Item( + index: LONG, + ppPair: *mut *mut ITaskNamedValuePair, + ) -> HRESULT, + fn get__NewEnum( + ppEnum: *mut LPUNKNOWN, + ) -> HRESULT, + fn Create( + Name: BSTR, + Value: BSTR, + ppPair: *mut *mut ITaskNamedValuePair, + ) -> HRESULT, + fn Remove( + index: LONG, + ) -> HRESULT, + fn Clear() -> HRESULT, +}} +RIDL!{#[uuid(0xd537d2b0, 0x9fb3, 0x4d34, 0x97, 0x39, 0x1f, 0xf5, 0xce, 0x7b, 0x1e, 0xf3)] +interface IIdleTrigger(IIdleTriggerVtbl): ITrigger(ITriggerVtbl) {}} +RIDL!{#[uuid(0x72dade38, 0xfae4, 0x4b3e, 0xba, 0xf4, 0x5d, 0x00, 0x9a, 0xf0, 0x2b, 0x1c)] +interface ILogonTrigger(ILogonTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_Delay( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_Delay( + pDelay: BSTR, + ) -> HRESULT, + fn get_UserId( + pUser: *mut BSTR, + ) -> HRESULT, + fn put_UserId( + pUser: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x754da71b, 0x4385, 0x4475, 0x9d, 0xd9, 0x59, 0x82, 0x94, 0xfa, 0x36, 0x41)] +interface ISessionStateChangeTrigger(ISessionStateChangeTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_Delay( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_Delay( + pDelay: BSTR, + ) -> HRESULT, + fn get_UserId( + pUser: *mut BSTR, + ) -> HRESULT, + fn put_UserId( + pUser: BSTR, + ) -> HRESULT, + fn get_StateChange( + pType: *mut TASK_SESSION_STATE_CHANGE_TYPE, + ) -> HRESULT, + fn put_StateChange( + pType: TASK_SESSION_STATE_CHANGE_TYPE, + ) -> HRESULT, +}} +ENUM!{enum TASK_SESSION_STATE_CHANGE_TYPE { + TASK_CONSOLE_CONNECT = 1, + TASK_CONSOLE_DISCONNECT = 2, + TASK_REMOTE_CONNECT = 3, + TASK_REMOTE_DISCONNECT = 4, + TASK_SESSION_LOCK = 7, + TASK_SESSION_UNLOCK = 8, +}} +RIDL!{#[uuid(0xd45b0167, 0x9653, 0x4eef, 0xb9, 0x4f, 0x07, 0x32, 0xca, 0x7a, 0xf2, 0x51)] +interface IEventTrigger(IEventTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_Subscription( + pQuery: *mut BSTR, + ) -> HRESULT, + fn put_Subscription( + pQuery: BSTR, + ) -> HRESULT, + fn get_Delay( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_Delay( + pDelay: BSTR, + ) -> HRESULT, + fn get_ValueQueries( + ppNamedXPaths: *mut *mut ITaskNamedValueCollection, + ) -> HRESULT, + fn put_ValueQueries( + ppNamedXPaths: *const ITaskNamedValueCollection, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb45747e0, 0xeba7, 0x4276, 0x9f, 0x29, 0x85, 0xc5, 0xbb, 0x30, 0x00, 0x06)] +interface ITimeTrigger(ITimeTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_RandomDelay( + pRandomDelay: *mut BSTR, + ) -> HRESULT, + fn put_RandomDelay( + pRandomDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x126c5cd8, 0xb288, 0x41d5, 0x8d, 0xbf, 0xe4, 0x91, 0x44, 0x6a, 0xdc, 0x5c)] +interface IDailyTrigger(IDailyTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_DaysInterval( + pDays: *mut c_short, + ) -> HRESULT, + fn put_DaysInterval( + pDays: c_short, + ) -> HRESULT, + fn get_RandomDelay( + pRandomDelay: *mut BSTR, + ) -> HRESULT, + fn put_RandomDelay( + pRandomDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5038fc98, 0x82ff, 0x436d, 0x87, 0x28, 0xa5, 0x12, 0xa5, 0x7c, 0x9d, 0xc1)] +interface IWeeklyTrigger(IWeeklyTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_DaysOfWeek( + pDays: *mut c_short, + ) -> HRESULT, + fn put_DaysOfWeek( + pDays: c_short, + ) -> HRESULT, + fn get_WeeksInterval( + pWeeks: *mut c_short, + ) -> HRESULT, + fn put_WeeksInterval( + pWeeks: c_short, + ) -> HRESULT, + fn get_RandomDelay( + pRandomDelay: *mut BSTR, + ) -> HRESULT, + fn put_RandomDelay( + pRandomDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x97c45ef1, 0x6b02, 0x4a1a, 0x9c, 0x0e, 0x1e, 0xbf, 0xba, 0x15, 0x00, 0xac)] +interface IMonthlyTrigger(IMonthlyTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_DaysOfMonth( + pDays: *mut c_long, + ) -> HRESULT, + fn put_DaysOfMonth( + pDays: c_long, + ) -> HRESULT, + fn get_MonthsOfYear( + pMonths: *mut c_short, + ) -> HRESULT, + fn put_MonthsOfYear( + pMonths: c_short, + ) -> HRESULT, + fn get_RunOnLastDayOfMonth( + pLastDay: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RunOnLastDayOfMonth( + pLastDay: VARIANT_BOOL, + ) -> HRESULT, + fn get_RandomDelay( + pRandomDelay: *mut BSTR, + ) -> HRESULT, + fn put_RandomDelay( + pRandomDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x77d025a3, 0x90fa, 0x43aa, 0xb5, 0x2e, 0xcd, 0xa5, 0x49, 0x9b, 0x94, 0x6a)] +interface IMonthlyDOWTrigger(IMonthlyDOWTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_DaysOfWeek( + pDays: *mut c_short, + ) -> HRESULT, + fn put_DaysOfWeek( + pDays: c_short, + ) -> HRESULT, + fn get_WeeksOfMonth( + pWeeks: *mut c_short, + ) -> HRESULT, + fn put_WeeksOfMonth( + pWeeks: c_short, + ) -> HRESULT, + fn get_MonthsOfYear( + pMonths: *mut c_short, + ) -> HRESULT, + fn put_MonthsOfYear( + pMonths: c_short, + ) -> HRESULT, + fn get_RunOnLastWeekOfMonth( + pLastWeek: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_RunOnLastWeekOfMonth( + pLastWeek: VARIANT_BOOL, + ) -> HRESULT, + fn get_RandomDelay( + pRandomDelay: *mut BSTR, + ) -> HRESULT, + fn put_RandomDelay( + pRandomDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2a9c35da, 0xd357, 0x41f4, 0xbb, 0xc1, 0x20, 0x7a, 0xc1, 0xb1, 0xf3, 0xcb)] +interface IBootTrigger(IBootTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_Delay( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_Delay( + pDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4c8fec3a, 0xc218, 0x4e0c, 0xb2, 0x3d, 0x62, 0x90, 0x24, 0xdb, 0x91, 0xa2)] +interface IRegistrationTrigger(IRegistrationTriggerVtbl): ITrigger(ITriggerVtbl) { + fn get_Delay( + pDelay: *mut BSTR, + ) -> HRESULT, + fn put_Delay( + pDelay: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4c3d624d, 0xfd6b, 0x49a3, 0xb9, 0xb7, 0x09, 0xcb, 0x3c, 0xd3, 0xf0, 0x47)] +interface IExecAction(IExecActionVtbl): IAction(IActionVtbl) { + fn get_Path( + pPath: *mut BSTR, + ) -> HRESULT, + fn put_Path( + pPath: BSTR, + ) -> HRESULT, + fn get_Arguments( + pArgument: *mut BSTR, + ) -> HRESULT, + fn put_Arguments( + pArgument: BSTR, + ) -> HRESULT, + fn get_WorkingDirectory( + pWorkingDirectory: *mut BSTR, + ) -> HRESULT, + fn put_WorkingDirectory( + pWorkingDirectory: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf2a82542, 0xbda5, 0x4e6b, 0x91, 0x43, 0xe2, 0xbf, 0x4f, 0x89, 0x87, 0xb6)] +interface IExecAction2(IExecAction2Vtbl): IExecAction(IExecActionVtbl) { + fn get_HideAppWindow( + pHideAppWindow: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_HideAppWindow( + pHideAppWindow: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x505e9e68, 0xaf89, 0x46b8, 0xa3, 0x0f, 0x56, 0x16, 0x2a, 0x83, 0xd5, 0x37)] +interface IShowMessageAction(IShowMessageActionVtbl): IAction(IActionVtbl) { + fn get_Title( + pTitle: *mut BSTR, + ) -> HRESULT, + fn put_Title( + pTitle: BSTR, + ) -> HRESULT, + fn get_MessageBody( + pMessageBody: *mut BSTR, + ) -> HRESULT, + fn put_MessageBody( + pMessageBody: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x6d2fd252, 0x75c5, 0x4f66, 0x90, 0xba, 0x2a, 0x7d, 0x8c, 0xc3, 0x03, 0x9f)] +interface IComHandlerAction(IComHandlerActionVtbl): IAction(IActionVtbl) { + fn get_ClassId( + pClsid: *mut BSTR, + ) -> HRESULT, + fn put_ClassId( + pClsid: BSTR, + ) -> HRESULT, + fn get_Data( + pData: *mut BSTR, + ) -> HRESULT, + fn put_Data( + pData: BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x10f62c64, 0x7e16, 0x4314, 0xa0, 0xc2, 0x0c, 0x36, 0x83, 0xf9, 0x9d, 0x40)] +interface IEmailAction(IEmailActionVtbl): IAction(IActionVtbl) { + fn get_Server( + pServer: *mut BSTR, + ) -> HRESULT, + fn put_Server( + pServer: BSTR, + ) -> HRESULT, + fn get_Subject( + pSubject: *mut BSTR, + ) -> HRESULT, + fn put_Subject( + pSubject: BSTR, + ) -> HRESULT, + fn get_To( + pTo: *mut BSTR, + ) -> HRESULT, + fn put_To( + pTo: BSTR, + ) -> HRESULT, + fn get_Cc( + pCc: *mut BSTR, + ) -> HRESULT, + fn put_Cc( + pCc: BSTR, + ) -> HRESULT, + fn get_Bcc( + pBcc: *mut BSTR, + ) -> HRESULT, + fn put_Bcc( + pBcc: BSTR, + ) -> HRESULT, + fn get_ReplyTo( + pReplyTo: *mut BSTR, + ) -> HRESULT, + fn put_ReplyTo( + pReplyTo: BSTR, + ) -> HRESULT, + fn get_From( + pFrom: *mut BSTR, + ) -> HRESULT, + fn put_From( + pFrom: BSTR, + ) -> HRESULT, + fn get_HeaderFields( + ppHeaderFields: *mut *mut ITaskNamedValueCollection, + ) -> HRESULT, + fn put_HeaderFields( + ppHeaderFields: *const ITaskNamedValueCollection, + ) -> HRESULT, + fn get_Body( + pBody: *mut BSTR, + ) -> HRESULT, + fn put_Body( + pBody: BSTR, + ) -> HRESULT, + fn get_Attachments( + pAttachements: *mut SAFEARRAY, + ) -> HRESULT, + fn put_Attachments( + pAttachements: SAFEARRAY, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x248919ae, 0xe345, 0x4a6d, 0x8a, 0xeb, 0xe0, 0xd3, 0x16, 0x5c, 0x90, 0x4e)] +interface IPrincipal2(IPrincipal2Vtbl): IDispatch(IDispatchVtbl) { + fn get_ProcessTokenSidType( + pProcessTokenSidType: *mut TASK_PROCESSTOKENSID, + ) -> HRESULT, + fn put_ProcessTokenSidType( + pProcessTokenSidType: TASK_PROCESSTOKENSID, + ) -> HRESULT, + fn get_RequiredPrivilegeCount( + pCount: *mut c_long, + ) -> HRESULT, + fn get_RequiredPrivilege( + index: c_long, + pPrivilege: *mut BSTR, + ) -> HRESULT, + fn AddRequiredPrivilege( + privilege: BSTR, + ) -> HRESULT, +}} +ENUM!{enum TASK_PROCESSTOKENSID { + TASK_PROCESSTOKENSID_NONE = 0, + TASK_PROCESSTOKENSID_UNRESTRICTED = 1, + TASK_PROCESSTOKENSID_DEFAULT = 2, +}} +RIDL!{#[uuid(0x2c05c3f0, 0x6eed, 0x4c05, 0xa1, 0x5f, 0xed, 0x7d, 0x7a, 0x98, 0xa3, 0x69)] +interface ITaskSettings2(ITaskSettings2Vtbl): IDispatch(IDispatchVtbl) { + fn get_DisallowStartOnRemoteAppSession( + pDisallowStart: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_DisallowStartOnRemoteAppSession( + pDisallowStart: VARIANT_BOOL, + ) -> HRESULT, + fn get_UseUnifiedSchedulingEngine( + pUseUnifiedEngine: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_UseUnifiedSchedulingEngine( + pUseUnifiedEngine: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0ad9d0d7, 0x0c7f, 0x4ebb, 0x9a, 0x5f, 0xd1, 0xc6, 0x48, 0xdc, 0xa5, 0x28)] +interface ITaskSettings3(ITaskSettings3Vtbl): ITaskSettings(ITaskSettingsVtbl) { + fn get_DisallowStartOnRemoteAppSession( + pDisallowStart: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_DisallowStartOnRemoteAppSession( + pDisallowStart: VARIANT_BOOL, + ) -> HRESULT, + fn get_UseUnifiedSchedulingEngine( + pUseUnifiedEngine: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_UseUnifiedSchedulingEngine( + pUseUnifiedEngine: VARIANT_BOOL, + ) -> HRESULT, + fn get_MaintenanceSettings( + ppMaintenanceSettings: *mut *mut IMaintenanceSettings, + ) -> HRESULT, + fn put_MaintenanceSettings( + ppMaintenanceSettings: *const IMaintenanceSettings, + ) -> HRESULT, + fn CreateMaintenanceSettings( + ppMaintenanceSettings: *mut *mut IMaintenanceSettings, + ) -> HRESULT, + fn get_Volatile( + pVolatile: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_Volatile( + pVolatile: VARIANT_BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa6024fa8, 0x9652, 0x4adb, 0xa6, 0xbf, 0x5c, 0xfc, 0xd8, 0x77, 0xa7, 0xba)] +interface IMaintenanceSettings(IMaintenanceSettingsVtbl): IDispatch(IDispatchVtbl) { + fn put_Period( + target: BSTR, + ) -> HRESULT, + fn get_Period( + target: *mut BSTR, + ) -> HRESULT, + fn put_Deadline( + target: BSTR, + ) -> HRESULT, + fn get_Deadline( + target: *mut BSTR, + ) -> HRESULT, + fn put_Exclusive( + target: VARIANT_BOOL, + ) -> HRESULT, + fn get_Exclusive( + target: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +ENUM!{enum TASK_RUN_FLAGS { + TASK_RUN_NO_FLAGS = 0, + TASK_RUN_AS_SELF = 1, + TASK_RUN_IGNORE_CONSTRAINTS = 2, + TASK_RUN_USE_SESSION_ID = 4, + TASK_RUN_USER_SID = 8, +}} +ENUM!{enum TASK_ENUM_FLAGS { + TASK_ENUM_HIDDEN = 1, +}} +ENUM!{enum TASK_CREATION { + TASK_VALIDATE_ONLY = 1, + TASK_CREATE = 2, + TASK_UPDATE = 4, + TASK_CREATE_OR_UPDATE = 6, + TASK_DISABLE = 8, + TASK_DONT_ADD_PRINCIPAL_ACE = 16, + TASK_IGNORE_REGISTRATION_TRIGGERS = 32, +}} diff --git a/winapi/src/um/textstor.rs b/winapi/src/um/textstor.rs new file mode 100644 index 000000000..7e2d60218 --- /dev/null +++ b/winapi/src/um/textstor.rs @@ -0,0 +1,11 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{GUID_TS_SERVICE_DATAOBJECT, + 0x6086fbb5, 0xe225, 0x46ce, 0xa7, 0x70, 0xc1, 0xbb, 0xd3, 0xe0, 0x5d, 0x7b} +DEFINE_GUID!{GUID_TS_SERVICE_ACCESSIBLE, + 0xf9786200, 0xa5bf, 0x4a0f, 0x8c, 0x24, 0xfb, 0x16, 0xf5, 0xd1, 0xaa, 0xbb} +DEFINE_GUID!{GUID_TS_SERVICE_ACTIVEX, + 0xea937a50, 0xc9a6, 0x4b7d, 0x89, 0x4a, 0x49, 0xd9, 0x9b, 0x78, 0x48, 0x34} diff --git a/winapi/src/um/threadpoolapiset.rs b/winapi/src/um/threadpoolapiset.rs new file mode 100644 index 000000000..13a1e7a40 --- /dev/null +++ b/winapi/src/um/threadpoolapiset.rs @@ -0,0 +1,171 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-threadpool-l1. +use shared::basetsd::ULONG_PTR; +use shared::minwindef::{BOOL, DWORD, HMODULE, PFILETIME, ULONG}; +use um::minwinbase::PCRITICAL_SECTION; +use um::winnt::{ + HANDLE, PTP_CALLBACK_ENVIRON, PTP_CALLBACK_INSTANCE, PTP_CLEANUP_GROUP, PTP_IO, PTP_POOL, + PTP_POOL_STACK_INFORMATION, PTP_SIMPLE_CALLBACK, PTP_TIMER, PTP_TIMER_CALLBACK, PTP_WAIT, + PTP_WAIT_CALLBACK, PTP_WORK, PTP_WORK_CALLBACK, PVOID, +}; +FN!{stdcall PTP_WIN32_IO_CALLBACK( + Instance: PTP_CALLBACK_INSTANCE, + Context: PVOID, + Overlapped: PVOID, + IoResult: ULONG, + NumberOfBytesTransferred: ULONG_PTR, + Io: PTP_IO, +) -> ()} +extern "system" { + pub fn CreateThreadpool( + reserved: PVOID, + ) -> PTP_POOL; + pub fn SetThreadpoolThreadMaximum( + ptpp: PTP_POOL, + cthrdMost: DWORD, + ) -> (); + pub fn SetThreadpoolThreadMinimum( + ptpp: PTP_POOL, + cthrdMic: DWORD, + ) -> BOOL; + pub fn SetThreadpoolStackInformation( + ptpp: PTP_POOL, + ptpsi: PTP_POOL_STACK_INFORMATION, + ) -> BOOL; + pub fn QueryThreadpoolStackInformation( + ptpp: PTP_POOL, + ptpsi: PTP_POOL_STACK_INFORMATION, + ) -> BOOL; + pub fn CloseThreadpool( + ptpp: PTP_POOL, + ) -> (); + pub fn CreateThreadpoolCleanupGroup() -> PTP_CLEANUP_GROUP; + pub fn CloseThreadpoolCleanupGroupMembers( + ptpcg: PTP_CLEANUP_GROUP, + fCancelPendingCallbacks: BOOL, + pvCleanupContext: PVOID, + ) -> (); + pub fn CloseThreadpoolCleanupGroup( + ptpcg: PTP_CLEANUP_GROUP, + ) -> (); + pub fn SetEventWhenCallbackReturns( + pci: PTP_CALLBACK_INSTANCE, + evt: HANDLE, + ) -> (); + pub fn ReleaseSemaphoreWhenCallbackReturns( + pci: PTP_CALLBACK_INSTANCE, + sem: HANDLE, + crel: DWORD, + ) -> (); + pub fn ReleaseMutexWhenCallbackReturns( + pci: PTP_CALLBACK_INSTANCE, + mut_: HANDLE, + ) -> (); + pub fn LeaveCriticalSectionWhenCallbackReturns( + pci: PTP_CALLBACK_INSTANCE, + pcs: PCRITICAL_SECTION, + ) -> (); + pub fn FreeLibraryWhenCallbackReturns( + pci: PTP_CALLBACK_INSTANCE, + mod_: HMODULE, + ) -> (); + pub fn CallbackMayRunLong( + pci: PTP_CALLBACK_INSTANCE, + ) -> BOOL; + pub fn DisassociateCurrentThreadFromCallback( + pci: PTP_CALLBACK_INSTANCE, + ) -> (); + pub fn TrySubmitThreadpoolCallback( + pfns: PTP_SIMPLE_CALLBACK, + pv: PVOID, + pcbe: PTP_CALLBACK_ENVIRON, + ) -> BOOL; + pub fn CreateThreadpoolWork( + pfnwk: PTP_WORK_CALLBACK, + pv: PVOID, + pcbe: PTP_CALLBACK_ENVIRON, + ) -> PTP_WORK; + pub fn SubmitThreadpoolWork( + pwk: PTP_WORK, + ) -> (); + pub fn WaitForThreadpoolWorkCallbacks( + pwk: PTP_WORK, + fCancelPendingCallbacks: BOOL, + ) -> (); + pub fn CloseThreadpoolWork( + pwk: PTP_WORK, + ) -> (); + pub fn CreateThreadpoolTimer( + pfnti: PTP_TIMER_CALLBACK, + pv: PVOID, + pcbe: PTP_CALLBACK_ENVIRON, + ) -> PTP_TIMER; + pub fn SetThreadpoolTimer( + pti: PTP_TIMER, + pftDueTime: PFILETIME, + msPeriod: DWORD, + msWindowLength: DWORD, + ) -> (); + pub fn IsThreadpoolTimerSet( + pti: PTP_TIMER, + ) -> BOOL; + pub fn WaitForThreadpoolTimerCallbacks( + pti: PTP_TIMER, + fCancelPendingCallbacks: BOOL, + ) -> (); + pub fn CloseThreadpoolTimer( + pti: PTP_TIMER, + ) -> (); + pub fn CreateThreadpoolWait( + pfnwa: PTP_WAIT_CALLBACK, + pv: PVOID, + pcbe: PTP_CALLBACK_ENVIRON, + ) -> PTP_WAIT; + pub fn SetThreadpoolWait( + pwa: PTP_WAIT, + h: HANDLE, + pftTimeout: PFILETIME, + ) -> (); + pub fn WaitForThreadpoolWaitCallbacks( + pwa: PTP_WAIT, + fCancelPendingCallbacks: BOOL, + ) -> (); + pub fn CloseThreadpoolWait( + pwa: PTP_WAIT, + ) -> (); + pub fn CreateThreadpoolIo( + fl: HANDLE, + pfnio: PTP_WIN32_IO_CALLBACK, + pv: PVOID, + pcbe: PTP_CALLBACK_ENVIRON, + ) -> PTP_IO; + pub fn StartThreadpoolIo( + pio: PTP_IO, + ) -> (); + pub fn CancelThreadpoolIo( + pio: PTP_IO, + ) -> (); + pub fn WaitForThreadpoolIoCallbacks( + pio: PTP_IO, + fCancelPendingCallbacks: BOOL, + ) -> (); + pub fn CloseThreadpoolIo( + pio: PTP_IO, + ) -> (); + pub fn SetThreadpoolTimerEx( + pti: PTP_TIMER, + pftDueTime: PFILETIME, + msPeriod: DWORD, + msWindowLength: DWORD, + ) -> BOOL; + pub fn SetThreadpoolWaitEx( + pwa: PTP_WAIT, + h: HANDLE, + pftTimeout: PFILETIME, + Reserved: PVOID, + ) -> BOOL; +} diff --git a/winapi/src/um/threadpoollegacyapiset.rs b/winapi/src/um/threadpoollegacyapiset.rs new file mode 100644 index 000000000..dc306c4e4 --- /dev/null +++ b/winapi/src/um/threadpoollegacyapiset.rs @@ -0,0 +1,44 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD, ULONG}; +use um::minwinbase::LPTHREAD_START_ROUTINE; +use um::winnt::{HANDLE, PHANDLE, PVOID, WAITORTIMERCALLBACK}; +extern "system" { + pub fn QueueUserWorkItem( + Function: LPTHREAD_START_ROUTINE, + Context: PVOID, + Flags: ULONG, + ) -> BOOL; + pub fn UnregisterWaitEx( + WaitHandle: HANDLE, + CompletionEvent: HANDLE, + ) -> BOOL; + pub fn CreateTimerQueue() -> HANDLE; + pub fn CreateTimerQueueTimer( + phNewTimer: PHANDLE, + TimerQueue: HANDLE, + Callback: WAITORTIMERCALLBACK, + Parameter: PVOID, + DueTime: DWORD, + Period: DWORD, + Flags: ULONG, + ) -> BOOL; + pub fn ChangeTimerQueueTimer( + TimerQueue: HANDLE, + Timer: HANDLE, + DueTime: ULONG, + Period: ULONG, + ) -> BOOL; + pub fn DeleteTimerQueueTimer( + TimerQueue: HANDLE, + Timer: HANDLE, + CompletionEvent: HANDLE, + ) -> BOOL; + pub fn DeleteTimerQueueEx( + TimerQueue: HANDLE, + CompletionEvent: HANDLE, + ) -> BOOL; +} diff --git a/winapi/src/um/timeapi.rs b/winapi/src/um/timeapi.rs new file mode 100644 index 000000000..dae647067 --- /dev/null +++ b/winapi/src/um/timeapi.rs @@ -0,0 +1,20 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{DWORD, UINT}; +use um::mmsystem::{LPTIMECAPS, MMRESULT}; +extern "system" { + pub fn timeGetTime() -> DWORD; + pub fn timeGetDevCaps( + ptc: LPTIMECAPS, + cbtc: UINT, + ) -> MMRESULT; + pub fn timeBeginPeriod( + uPeriod: UINT, + ) -> MMRESULT; + pub fn timeEndPeriod( + uPeriod: UINT, + ) -> MMRESULT; +} diff --git a/winapi/src/um/timezoneapi.rs b/winapi/src/um/timezoneapi.rs new file mode 100644 index 000000000..b7d99f778 --- /dev/null +++ b/winapi/src/um/timezoneapi.rs @@ -0,0 +1,89 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! ApiSet Contract for api-ms-win-core-timezone-l1 +use shared::minwindef::{BOOL, DWORD, FILETIME, LPDWORD, LPFILETIME, USHORT}; +use um::minwinbase::{LPSYSTEMTIME, SYSTEMTIME}; +use um::winnt::{BOOLEAN, LONG, WCHAR}; +pub const TIME_ZONE_ID_INVALID: DWORD = 0xFFFFFFFF; +STRUCT!{struct TIME_ZONE_INFORMATION { + Bias: LONG, + StandardName: [WCHAR; 32], + StandardDate: SYSTEMTIME, + StandardBias: LONG, + DaylightName: [WCHAR; 32], + DaylightDate: SYSTEMTIME, + DaylightBias: LONG, +}} +pub type PTIME_ZONE_INFORMATION = *mut TIME_ZONE_INFORMATION; +pub type LPTIME_ZONE_INFORMATION = *mut TIME_ZONE_INFORMATION; +STRUCT!{struct DYNAMIC_TIME_ZONE_INFORMATION { + Bias: LONG, + StandardName: [WCHAR; 32], + StandardDate: SYSTEMTIME, + StandardBias: LONG, + DaylightName: [WCHAR; 32], + DaylightDate: SYSTEMTIME, + DaylightBias: LONG, + TimeZoneKeyName: [WCHAR; 128], + DynamicDaylightTimeDisabled: BOOLEAN, +}} +pub type PDYNAMIC_TIME_ZONE_INFORMATION = *mut DYNAMIC_TIME_ZONE_INFORMATION; +extern "system" { + pub fn SystemTimeToTzSpecificLocalTime( + lpTimeZoneInformation: *const TIME_ZONE_INFORMATION, + lpUniversalTime: *const SYSTEMTIME, + lpLocalTime: LPSYSTEMTIME, + ) -> BOOL; + pub fn TzSpecificLocalTimeToSystemTime( + lpTimeZoneInformation: *const TIME_ZONE_INFORMATION, + lpLocalTime: *const SYSTEMTIME, + lpUniversalTime: LPSYSTEMTIME, + ) -> BOOL; + pub fn FileTimeToSystemTime( + lpFileTime: *const FILETIME, + lpSystemTime: LPSYSTEMTIME, + ) -> BOOL; + pub fn SystemTimeToFileTime( + lpSystemTime: *const SYSTEMTIME, + lpFileTime: LPFILETIME, + ) -> BOOL; + pub fn GetTimeZoneInformation( + lpTimeZoneInformation: LPTIME_ZONE_INFORMATION, + ) -> DWORD; + pub fn SetTimeZoneInformation( + lpTimeZoneInformation: *const TIME_ZONE_INFORMATION, + ) -> BOOL; + pub fn SetDynamicTimeZoneInformation( + lpTimeZoneInformation: *const DYNAMIC_TIME_ZONE_INFORMATION, + ) -> BOOL; + pub fn GetDynamicTimeZoneInformation( + pTimeZoneInformation: PDYNAMIC_TIME_ZONE_INFORMATION, + ) -> DWORD; + pub fn GetTimeZoneInformationForYear( + wYear: USHORT, + pdtzi: PDYNAMIC_TIME_ZONE_INFORMATION, + ptzi: LPTIME_ZONE_INFORMATION, + ) -> BOOL; + pub fn EnumDynamicTimeZoneInformation( + dwIndex: DWORD, + lpTimeZoneInformation: PDYNAMIC_TIME_ZONE_INFORMATION, + ) -> DWORD; + pub fn GetDynamicTimeZoneInformationEffectiveYears( + lpTimeZoneInformation: PDYNAMIC_TIME_ZONE_INFORMATION, + FirstYear: LPDWORD, + LastYear: LPDWORD, + ) -> DWORD; + pub fn SystemTimeToTzSpecificLocalTimeEx( + lpTimeZoneInformation: *const DYNAMIC_TIME_ZONE_INFORMATION, + lpUniversalTime: *const SYSTEMTIME, + lpLocalTime: LPSYSTEMTIME, + ) -> BOOL; + pub fn TzSpecificLocalTimeToSystemTimeEx( + lpTimeZoneInformation: *const DYNAMIC_TIME_ZONE_INFORMATION, + lpLocalTime: *const SYSTEMTIME, + lpUniversalTime: LPSYSTEMTIME, + ) -> BOOL; +} diff --git a/winapi/src/um/tlhelp32.rs b/winapi/src/um/tlhelp32.rs new file mode 100644 index 000000000..f910b9f49 --- /dev/null +++ b/winapi/src/um/tlhelp32.rs @@ -0,0 +1,194 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! WIN32 tool help functions, types, and definitions +use shared::basetsd::{SIZE_T, ULONG_PTR}; +use shared::minwindef::{BOOL, BYTE, DWORD, HMODULE, LPCVOID, LPVOID, MAX_PATH}; +use um::winnt::{CHAR, HANDLE, LONG, WCHAR}; +pub const MAX_MODULE_NAME32: usize = 255; +extern "system" { + pub fn CreateToolhelp32Snapshot( + dwFlags: DWORD, + th32ProcessID: DWORD, + ) -> HANDLE; +} +pub const TH32CS_SNAPHEAPLIST: DWORD = 0x00000001; +pub const TH32CS_SNAPPROCESS: DWORD = 0x00000002; +pub const TH32CS_SNAPTHREAD: DWORD = 0x00000004; +pub const TH32CS_SNAPMODULE: DWORD = 0x00000008; +pub const TH32CS_SNAPMODULE32: DWORD = 0x00000010; +pub const TH32CS_SNAPALL: DWORD = + (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE); +pub const TH32CS_INHERIT: DWORD = 0x80000000; +STRUCT!{struct HEAPLIST32 { + dwSize: SIZE_T, + th32ProcessID: DWORD, + th32HeapID: ULONG_PTR, + dwFlags: DWORD, +}} +pub type PHEAPLIST32 = *mut HEAPLIST32; +pub type LPHEAPLIST32 = *mut HEAPLIST32; +pub const HF32_DEFAULT: DWORD = 1; +pub const HF32_SHARED: DWORD = 2; +extern "system" { + pub fn Heap32ListFirst( + hSnapshot: HANDLE, + lphl: LPHEAPLIST32, + ) -> BOOL; + pub fn Heap32ListNext( + hSnapshot: HANDLE, + lphl: LPHEAPLIST32, + ) -> BOOL; +} +STRUCT!{struct HEAPENTRY32 { + dwSize: SIZE_T, + hHandle: HANDLE, + dwAddress: ULONG_PTR, + dwBlockSize: SIZE_T, + dwFlags: DWORD, + dwLockCount: DWORD, + dwResvd: DWORD, + th32ProcessID: DWORD, + th32HeapID: ULONG_PTR, +}} +pub type PHEAPENTRY32 = *mut HEAPENTRY32; +pub type LPHEAPENTRY32 = *mut HEAPENTRY32; +pub const LF32_FIXED: DWORD = 0x00000001; +pub const LF32_FREE: DWORD = 0x00000002; +pub const LF32_MOVEABLE: DWORD = 0x00000004; +extern "system" { + pub fn Heap32First( + lphe: LPHEAPENTRY32, + th32ProcessID: DWORD, + th32HeapID: ULONG_PTR, + ) -> BOOL; + pub fn Heap32Next( + lphe: LPHEAPENTRY32, + ) -> BOOL; + pub fn Toolhelp32ReadProcessMemory( + th32ProcessID: DWORD, + lpBaseAddress: LPCVOID, + lpBuffer: LPVOID, + cbRead: SIZE_T, + lpNumberOfBytesRead: *mut SIZE_T, + ) -> BOOL; +} +STRUCT!{struct PROCESSENTRY32W { + dwSize: DWORD, + cntUsage: DWORD, + th32ProcessID: DWORD, + th32DefaultHeapID: ULONG_PTR, + th32ModuleID: DWORD, + cntThreads: DWORD, + th32ParentProcessID: DWORD, + pcPriClassBase: LONG, + dwFlags: DWORD, + szExeFile: [WCHAR; MAX_PATH], +}} +pub type PPROCESSENTRY32W = *mut PROCESSENTRY32W; +pub type LPPROCESSENTRY32W = *mut PROCESSENTRY32W; +extern "system" { + pub fn Process32FirstW( + hSnapshot: HANDLE, + lppe: LPPROCESSENTRY32W, + ) -> BOOL; + pub fn Process32NextW( + hSnapshot: HANDLE, + lppe: LPPROCESSENTRY32W, + ) -> BOOL; +} +STRUCT!{struct PROCESSENTRY32 { + dwSize: DWORD, + cntUsage: DWORD, + th32ProcessID: DWORD, + th32DefaultHeapID: ULONG_PTR, + th32ModuleID: DWORD, + cntThreads: DWORD, + th32ParentProcessID: DWORD, + pcPriClassBase: LONG, + dwFlags: DWORD, + szExeFile: [CHAR; MAX_PATH], +}} +pub type PPROCESSENTRY32 = *mut PROCESSENTRY32; +pub type LPPROCESSENTRY32 = *mut PROCESSENTRY32; +extern "system" { + pub fn Process32First( + hSnapshot: HANDLE, + lppe: LPPROCESSENTRY32, + ) -> BOOL; + pub fn Process32Next( + hSnapshot: HANDLE, + lppe: LPPROCESSENTRY32, + ) -> BOOL; +} +STRUCT!{struct THREADENTRY32 { + dwSize: DWORD, + cntUsage: DWORD, + th32ThreadID: DWORD, + th32OwnerProcessID: DWORD, + tpBasePri: LONG, + tpDeltaPri: LONG, + dwFlags: DWORD, +}} +pub type PTHREADENTRY32 = *mut THREADENTRY32; +pub type LPTHREADENTRY32 = *mut THREADENTRY32; +extern "system" { + pub fn Thread32First( + hSnapshot: HANDLE, + lpte: LPTHREADENTRY32, + ) -> BOOL; + pub fn Thread32Next( + hSnapshot: HANDLE, + lpte: LPTHREADENTRY32, + ) -> BOOL; +} +STRUCT!{struct MODULEENTRY32W { + dwSize: DWORD, + th32ModuleID: DWORD, + th32ProcessID: DWORD, + GlblcntUsage: DWORD, + ProccntUsage: DWORD, + modBaseAddr: *mut BYTE, + modBaseSize: DWORD, + hModule: HMODULE, + szModule: [WCHAR; MAX_MODULE_NAME32 + 1], + szExePath: [WCHAR; MAX_PATH], +}} +pub type PMODULEENTRY32W = *mut MODULEENTRY32W; +pub type LPMODULEENTRY32W = *mut MODULEENTRY32W; +extern "system" { + pub fn Module32FirstW( + hSnapshot: HANDLE, + lpme: LPMODULEENTRY32W, + ) -> BOOL; + pub fn Module32NextW( + hSnapshot: HANDLE, + lpme: LPMODULEENTRY32W, + ) -> BOOL; +} +STRUCT!{struct MODULEENTRY32 { + dwSize: DWORD, + th32ModuleID: DWORD, + th32ProcessID: DWORD, + GlblcntUsage: DWORD, + ProccntUsage: DWORD, + modBaseAddr: *mut BYTE, + modBaseSize: DWORD, + hModule: HMODULE, + szModule: [CHAR; MAX_MODULE_NAME32 + 1], + szExePath: [CHAR; MAX_PATH], +}} +pub type PMODULEENTRY32 = *mut MODULEENTRY32; +pub type LPMODULEENTRY32 = *mut MODULEENTRY32; +extern "system" { + pub fn Module32First( + hSnapshot: HANDLE, + lpme: LPMODULEENTRY32, + ) -> BOOL; + pub fn Module32Next( + hSnapshot: HANDLE, + lpme: LPMODULEENTRY32, + ) -> BOOL; +} diff --git a/winapi/src/um/unknwnbase.rs b/winapi/src/um/unknwnbase.rs new file mode 100644 index 000000000..4162fc109 --- /dev/null +++ b/winapi/src/um/unknwnbase.rs @@ -0,0 +1,43 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_void; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, ULONG}; +use um::winnt::HRESULT; +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} +pub type LPUNKNOWN = *mut IUnknown; +RIDL!{#[uuid(0x000e0000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface AsyncIUnknown(AsyncIUnknownVtbl): IUnknown(IUnknownVtbl) { + fn Begin_QueryInterface( + riid: REFIID, + ) -> HRESULT, + fn Finish_QueryInterface( + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn Begin_AddRef() -> HRESULT, + fn Finish_AddRef() -> ULONG, + fn Begin_Release() -> HRESULT, + fn Finish_Release() -> ULONG, +}} +RIDL!{#[uuid(0x00000001, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IClassFactory(IClassFactoryVtbl): IUnknown(IUnknownVtbl) { + fn CreateInstance( + pUnkOuter: *mut IUnknown, + riid: REFIID, + ppvObject: *mut *mut c_void, + ) -> HRESULT, + fn LockServer( + fLock: BOOL, + ) -> HRESULT, +}} diff --git a/winapi/src/um/urlhist.rs b/winapi/src/um/urlhist.rs new file mode 100644 index 000000000..f35e55029 --- /dev/null +++ b/winapi/src/um/urlhist.rs @@ -0,0 +1,97 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Url History Interfaces +use ctypes::c_void; +use shared::guiddef::REFIID; +use shared::minwindef::{BOOL, DWORD, FILETIME, ULONG}; +use shared::wtypesbase::LPCOLESTR; +use um::docobj::{IOleCommandTarget, IOleCommandTargetVtbl}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPWSTR}; +pub const STATURL_QUERYFLAG_ISCACHED: DWORD = 0x00010000; +pub const STATURL_QUERYFLAG_NOURL: DWORD = 0x00020000; +pub const STATURL_QUERYFLAG_NOTITLE: DWORD = 0x00040000; +pub const STATURL_QUERYFLAG_TOPLEVEL: DWORD = 0x00080000; +pub const STATURLFLAG_ISCACHED: DWORD = 0x00000001; +pub const STATURLFLAG_ISTOPLEVEL: DWORD = 0x00000002; +ENUM!{enum ADDURL_FLAG { + ADDURL_FIRST = 0, + ADDURL_ADDTOHISTORYANDCACHE = 0, + ADDURL_ADDTOCACHE = 1, + ADDURL_Max = 2147483647, +}} +pub type LPENUMSTATURL = *mut IEnumSTATURL; +STRUCT!{struct STATURL { + cbSize: DWORD, + pwcsUrl: LPWSTR, + pwcsTitle: LPWSTR, + ftLastVisited: FILETIME, + ftLastUpdated: FILETIME, + ftExpires: FILETIME, + dwFlags: DWORD, +}} +pub type LPSTATURL = *mut STATURL; +RIDL!{#[uuid(0x3c374a42, 0xbae4, 0x11cf, 0xbf, 0x7d, 0x00, 0xaa, 0x00, 0x69, 0x46, 0xee)] +interface IEnumSTATURL(IEnumSTATURLVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: LPSTATURL, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSTATURL, + ) -> HRESULT, + fn SetFilter( + poszFilter: LPCOLESTR, + dwFlags: DWORD, + ) -> HRESULT, +}} +pub type LPURLHISTORYSTG = *mut IUrlHistoryStg; +RIDL!{#[uuid(0x3c374a41, 0xbae4, 0x11cf, 0xbf, 0x7d, 0x00, 0xaa, 0x00, 0x69, 0x46, 0xee)] +interface IUrlHistoryStg(IUrlHistoryStgVtbl): IUnknown(IUnknownVtbl) { + fn AddUrl( + pocsUrl: LPCOLESTR, + ) -> HRESULT, + fn DeleteUrl( + pocsUrl: LPCOLESTR, + dwFlags: DWORD, + ) -> HRESULT, + fn QueryUrl( + pocsUrl: LPCOLESTR, + dwFlags: DWORD, + lpSTATURL: LPSTATURL, + ) -> HRESULT, + fn BindToObject( + pocsUrl: LPCOLESTR, + riid: REFIID, + ppvOut: *mut *mut c_void, + ) -> HRESULT, + fn EnumUrls( + ppEnum: *mut *mut IEnumSTATURL, + ) -> HRESULT, +}} +pub type LPURLHISTORYSTG2 = *mut IUrlHistoryStg2; +RIDL!{#[uuid(0xafa0dc11, 0xc313, 0x11d0, 0x83, 0x1a, 0x00, 0xc0, 0x4f, 0xd5, 0xae, 0x38)] +interface IUrlHistoryStg2(IUrlHistoryStg2Vtbl): IUrlHistoryStg(IUrlHistoryStgVtbl) { + fn AddUrlAndNotify( + pocsUrl: LPCOLESTR, + pocsTitle: LPCOLESTR, + dwFlags: DWORD, + fWriteHistory: BOOL, + poctNotify: *mut IOleCommandTarget, + punkISFolder: *mut IUnknown, + ) -> HRESULT, + fn ClearHistory() -> HRESULT, +}} +pub type LPURLHISTORYNOTIFY = *mut IUrlHistoryNotify; +RIDL!{#[uuid(0xbc40bec1, 0xc493, 0x11d0, 0x83, 0x1b, 0x00, 0xc0, 0x4f, 0xd5, 0xae, 0x38)] +interface IUrlHistoryNotify(IUrlHistoryNotifyVtbl): + IOleCommandTarget(IOleCommandTargetVtbl) {} +} diff --git a/winapi/src/um/urlmon.rs b/winapi/src/um/urlmon.rs new file mode 100644 index 000000000..bdcbada51 --- /dev/null +++ b/winapi/src/um/urlmon.rs @@ -0,0 +1,21 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! URL Moniker interfaces +use shared::minwindef::DWORD; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LPCWSTR}; +RIDL!{#[uuid(0x79eac9ee, 0xbaf9, 0x11ce, 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b)] +interface IInternetSecurityManager(IInternetSecurityManagerVtbl): IUnknown(IUnknownVtbl) { + fn SetSecuritySite() -> HRESULT, + fn GetSecuritySite() -> HRESULT, + fn MapUrlToZone( + pwszUrl: LPCWSTR, + pdwZone: *mut DWORD, + dwFlags: DWORD, + ) -> HRESULT, + // TODO: the rest +}} +// TODO: the rest diff --git a/winapi/src/um/userenv.rs b/winapi/src/um/userenv.rs new file mode 100644 index 000000000..ea0af96ff --- /dev/null +++ b/winapi/src/um/userenv.rs @@ -0,0 +1,159 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Definitions for the user environment API +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, PHKEY}; +use um::winnt::{ + HANDLE, HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCWSTR, PSID, PSID_AND_ATTRIBUTES, PWSTR +}; +use um::winreg::REGSAM; +extern "system" { + // pub fn LoadUserProfileA( + // hToken: HANDLE, + // lpProfileInfo: LPPROFILEINFOA, + // ) -> BOOL; + // pub fn LoadUserProfileW( + // hToken: HANDLE, + // lpProfileInfo: LPPROFILEINFOW, + // ) -> BOOL; + pub fn UnloadUserProfile( + hToken: HANDLE, + hProfile: HANDLE, + ) -> BOOL; + pub fn GetProfilesDirectoryA( + lpProfileDir: LPSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetProfilesDirectoryW( + lpProfileDir: LPWSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetProfileType( + dwFlags: *mut DWORD, + ) -> BOOL; + pub fn DeleteProfileA( + lpSidString: LPCSTR, + lpProfilePath: LPCSTR, + lpComputerName: LPCSTR, + ) -> BOOL; + pub fn DeleteProfileW( + lpSidString: LPCWSTR, + lpProfilePath: LPCWSTR, + lpComputerName: LPCWSTR, + ) -> BOOL; + pub fn CreateProfile( + pszUserSid: LPCWSTR, + pszUserName: LPCWSTR, + pszProfilePath: LPWSTR, + cchProfilePath: DWORD, + ) -> HRESULT; + pub fn GetDefaultUserProfileDirectoryA( + lpProfileDir: LPSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetDefaultUserProfileDirectoryW( + lpProfileDir: LPWSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetAllUsersProfileDirectoryA( + lpProfileDir: LPSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetAllUsersProfileDirectoryW( + lpProfileDir: LPWSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetUserProfileDirectoryA( + hToken: HANDLE, + lpProfileDir: LPSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn GetUserProfileDirectoryW( + hToken: HANDLE, + lpProfileDir: LPWSTR, + lpcchSize: LPDWORD, + ) -> BOOL; + pub fn CreateEnvironmentBlock( + lpEnvironment: *mut LPVOID, + hToken: HANDLE, + bInherit: BOOL, + ) -> BOOL; + pub fn DestroyEnvironmentBlock( + lpEnvironment: LPVOID, + ) -> BOOL; + pub fn ExpandEnvironmentStringsForUserA( + hToken: HANDLE, + lpSrc: LPCSTR, + lpDest: LPSTR, + dwSize: DWORD, + ) -> BOOL; + pub fn ExpandEnvironmentStringsForUserW( + hToken: HANDLE, + lpSrc: LPCWSTR, + lpDest: LPWSTR, + dwSize: DWORD, + ) -> BOOL; + pub fn RefreshPolicy( + bMachine: BOOL, + ) -> BOOL; + pub fn RefreshPolicyEx( + bMachine: BOOL, + dwOptions: DWORD, + ) -> BOOL; + pub fn EnterCriticalPolicySection( + bMachine: BOOL, + ) -> HANDLE; + pub fn LeaveCriticalPolicySection( + hSection: HANDLE, + ) -> BOOL; + pub fn RegisterGPNotification( + hEvent: HANDLE, + bMachine: BOOL, + ) -> BOOL; + pub fn UnregisterGPNotification( + hEvent: HANDLE, + ) -> BOOL; + // pub fn GetGPOListA(); + // pub fn GetGPOListW(); + // pub fn FreeGPOListA(); + // pub fn FreeGPOListW(); + // pub fn GetAppliedGPOListA(); + // pub fn GetAppliedGPOListW(); + // pub fn ProcessGroupPolicyCompleted(); + // pub fn ProcessGroupPolicyCompletedEx(); + // pub fn RsopAccessCheckByType(); + // pub fn RsopFileAccessCheck(); + // pub fn RsopSetPolicySettingStatus(); + // pub fn RsopResetPolicySettingStatus(); + // pub fn GenerateGPNotification(); + pub fn CreateAppContainerProfile( + pszAppContainerName: PCWSTR, + pszDisplayName: PCWSTR, + pszDescription: PCWSTR, + pCapabilities: PSID_AND_ATTRIBUTES, + dwCapabilityCount: DWORD, + ppSidAppContainerSid: *mut PSID, + ) -> HRESULT; + pub fn DeleteAppContainerProfile( + pszAppContainerName: PCWSTR, + ) -> HRESULT; + pub fn GetAppContainerRegistryLocation( + desiredAccess: REGSAM, + phAppContainerKey: PHKEY, + ) -> HRESULT; + pub fn GetAppContainerFolderPath( + pszAppContainerSid: PCWSTR, + ppszPath: *mut PWSTR, + ) -> HRESULT; + pub fn DeriveAppContainerSidFromAppContainerName( + pszAppContainerName: PCWSTR, + ppsidAppContainerSid: *mut PSID, + ) -> HRESULT; + pub fn DeriveRestrictedAppContainerSidFromAppContainerSidAndRestrictedName( + psidAppContainerSid: PSID, + pszRestrictedAppContainerName: PCWSTR, + ppsidRestrictedAppContainerSid: *mut PSID, + ) -> HRESULT; +} diff --git a/winapi/src/um/usp10.rs b/winapi/src/um/usp10.rs new file mode 100644 index 000000000..b2f24be06 --- /dev/null +++ b/winapi/src/um/usp10.rs @@ -0,0 +1,560 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Unicode Complex Script processor API declarations +use ctypes::{c_int, c_long, c_void}; +use shared::minwindef::{BOOL, BYTE, DWORD, UINT, ULONG, WORD}; +use shared::ntdef::LCID; +use shared::windef::{HDC, RECT, SIZE}; +use shared::winerror::{FACILITY_ITF, SEVERITY_ERROR}; +use um::wingdi::ABC; +use um::winnt::{HRESULT, LONG, WCHAR}; +pub const SCRIPT_UNDEFINED: WORD = 0; +pub const USP_E_SCRIPT_NOT_IN_FONT: HRESULT = MAKE_HRESULT!(SEVERITY_ERROR, FACILITY_ITF, 0x200); +DECLARE_HANDLE!{SCRIPT_CACHE, SCRIPT_CACHE__} +extern "system" { + pub fn ScriptFreeCache( + psc: *mut SCRIPT_CACHE, + ) -> HRESULT; +} +STRUCT!{struct SCRIPT_CONTROL { + bit_fields: DWORD, +}} +BITFIELD!{SCRIPT_CONTROL bit_fields: DWORD [ + uDefaultLanguage set_uDefaultLanguage[0..16], + fContextDigits set_fContextDigits[16..17], + fInvertPreBoundDir set_fInvertPreBoundDir[17..18], + fInvertPostBoundDir set_fInvertPostBoundDir[18..19], + fLinkStringBefore set_fLinkStringBefore[19..20], + fLinkStringAfter set_fLinkStringAfter[20..21], + fNeutralOverride set_fNeutralOverride[21..22], + fNumericOverride set_fNumericOverride[22..23], + fLegacyBidiClass set_fLegacyBidiClass[23..24], + fMergeNeutralItems set_fMergeNeutralItems[24..25], + fReserved set_fReserved[25..32], +]} +STRUCT!{struct SCRIPT_STATE { + bit_fields: WORD, +}} +BITFIELD!{SCRIPT_STATE bit_fields: WORD [ + uBidiLevel set_uBidiLevel[0..5], + fOverrideDirection set_fOverrideDirection[5..6], + fInhibitSymSwap set_fInhibitSymSwap[6..7], + fCharShape set_fCharShape[7..8], + fDigitSubstitute set_fDigitSubstitute[8..9], + fInhibitLigate set_fInhibitLigate[9..10], + fDisplayZWG set_fDisplayZWG[10..11], + fArabicNumContext set_fArabicNumContext[11..12], + fGcpClusters set_fGcpClusters[12..13], + fReserved set_fReserved[13..14], + fEngineReserved set_fEngineReserved[14..16], +]} +STRUCT!{struct SCRIPT_ANALYSIS { + bit_fields: WORD, + s: SCRIPT_STATE, +}} +BITFIELD!{SCRIPT_ANALYSIS bit_fields: WORD [ + eScript set_eScript[0..10], + fRTL set_fRTL[10..11], + fLayoutRTL set_fLayoutRTL[11..12], + fLinkBefore set_fLinkBefore[12..13], + fLinkAfter set_fLinkAfter[13..14], + fLogicalOrder set_fLogicalOrder[14..15], + fNoGlyphIndex set_fNoGlyphIndex[15..16], +]} +STRUCT!{struct SCRIPT_ITEM { + iCharPos: c_int, + a: SCRIPT_ANALYSIS, +}} +extern "system" { + pub fn ScriptItemize( + pwcInChars: *const WCHAR, + cInChars: c_int, + cMaxItems: c_int, + psControl: *const SCRIPT_CONTROL, + psState: *const SCRIPT_STATE, + pItems: *mut SCRIPT_ITEM, + pcItems: *mut c_int, + ) -> HRESULT; + pub fn ScriptLayout( + cRuns: c_int, + pbLevel: *const BYTE, + piVisualToLogical: *mut c_int, + piLogicalToVisual: *mut c_int, + ) -> HRESULT; +} +pub const SCRIPT_JUSTIFY_NONE: WORD = 0; +pub const SCRIPT_JUSTIFY_ARABIC_BLANK: WORD = 1; +pub const SCRIPT_JUSTIFY_CHARACTER: WORD = 2; +pub const SCRIPT_JUSTIFY_RESERVED1: WORD = 3; +pub const SCRIPT_JUSTIFY_BLANK: WORD = 4; +pub const SCRIPT_JUSTIFY_RESERVED2: WORD = 5; +pub const SCRIPT_JUSTIFY_RESERVED3: WORD = 6; +pub const SCRIPT_JUSTIFY_ARABIC_NORMAL: WORD = 7; +pub const SCRIPT_JUSTIFY_ARABIC_KASHIDA: WORD = 8; +pub const SCRIPT_JUSTIFY_ARABIC_ALEF: WORD = 9; +pub const SCRIPT_JUSTIFY_ARABIC_HA: WORD = 10; +pub const SCRIPT_JUSTIFY_ARABIC_RA: WORD = 11; +pub const SCRIPT_JUSTIFY_ARABIC_BA: WORD = 12; +pub const SCRIPT_JUSTIFY_ARABIC_BARA: WORD = 13; +pub const SCRIPT_JUSTIFY_ARABIC_SEEN: WORD = 14; +pub const SCRIPT_JUSTIFY_ARABIC_SEEN_M: WORD = 15; +STRUCT!{struct SCRIPT_VISATTR { + bit_fields: WORD, +}} +BITFIELD!{SCRIPT_VISATTR bit_fields: WORD [ + uJustification set_uJustification[0..4], + fClusterStart set_fClusterStart[4..5], + fDiacritic set_fDiacritic[5..6], + fZeroWidth set_fZeroWidth[6..7], + fReserved set_fReserved[7..8], + fShapeReserved set_fShapeReserved[8..16], +]} +extern "system" { + pub fn ScriptShape( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + pwcChars: *const WCHAR, + cChars: c_int, + cMaxGlyphs: c_int, + psa: *mut SCRIPT_ANALYSIS, + pwOutGlyphs: *mut WORD, + pwLogClust: *mut WORD, + psva: *mut SCRIPT_VISATTR, + pcGlyphs: *mut c_int, + ) -> HRESULT; +} +STRUCT!{struct GOFFSET { + du: LONG, + dv: LONG, +}} +extern "system" { + pub fn ScriptPlace( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + pwGlyphs: *const WORD, + cGlyphs: c_int, + psva: *const SCRIPT_VISATTR, + psa: *mut SCRIPT_ANALYSIS, + piAdvance: *mut c_int, + pGoffset: *mut GOFFSET, + pABC: *mut ABC, + ) -> HRESULT; + pub fn ScriptTextOut( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + x: c_int, + y: c_int, + fuOptions: UINT, + lprc: *const RECT, + psa: *const SCRIPT_ANALYSIS, + pwcReserved: *const WCHAR, + iReserved: c_int, + pwGlyphs: *const WORD, + cGlyphs: c_int, + piAdvance: *const c_int, + piJustify: *const c_int, + pGoffset: *const GOFFSET, + ) -> HRESULT; + pub fn ScriptJustify( + psva: *const SCRIPT_VISATTR, + piAdvance: *const c_int, + cGlyphs: c_int, + iDx: c_int, + iMinKashida: c_int, + piJustify: *mut c_int, + ) -> HRESULT; +} +STRUCT!{struct SCRIPT_LOGATTR { + bit_fields: BYTE, +}} +BITFIELD!{SCRIPT_LOGATTR bit_fields: BYTE [ + fSoftBreak set_fSoftBreak[0..1], + fWhiteSpace set_fWhiteSpace[1..2], + fCharStop set_fCharStop[2..3], + fWordStop set_fWordStop[3..4], + fInvalid set_fInvalid[4..5], + fReserved set_fReserved[5..8], +]} +extern "system" { + pub fn ScriptBreak( + pwcChars: *const WCHAR, + cChars: c_int, + psa: *const SCRIPT_ANALYSIS, + psla: *mut SCRIPT_LOGATTR, + ) -> HRESULT; + pub fn ScriptCPtoX( + iCP: c_int, + fTrailing: BOOL, + cChars: c_int, + cGlyphs: c_int, + pwLogClust: *const WORD, + psva: *const SCRIPT_VISATTR, + piAdvance: *const c_int, + psa: *const SCRIPT_ANALYSIS, + piX: *mut c_int, + ) -> HRESULT; + pub fn ScriptXtoCP( + iX: c_int, + cChars: c_int, + cGlyphs: c_int, + pwLogClust: *const WORD, + psva: *const SCRIPT_VISATTR, + piAdvance: *const c_int, + psa: *const SCRIPT_ANALYSIS, + piCP: *mut c_int, + piTrailing: *mut c_int, + ) -> HRESULT; + pub fn ScriptGetLogicalWidths( + psa: *const SCRIPT_ANALYSIS, + cChars: c_int, + cGlyphs: c_int, + piGlyphWidth: *const c_int, + pwLogClust: *const WORD, + psva: *const SCRIPT_VISATTR, + piDx: *mut c_int, + ) -> HRESULT; + pub fn ScriptApplyLogicalWidth( + piDx: *const c_int, + cChars: c_int, + cGlyphs: c_int, + pwLogClust: *const WORD, + psva: *const SCRIPT_VISATTR, + piAdvance: *const c_int, + psa: *const SCRIPT_ANALYSIS, + pABC: *mut ABC, + piJustify: *mut c_int, + ) -> HRESULT; +} +pub const SGCM_RTL: DWORD = 0x00000001; +extern "system" { + pub fn ScriptGetCMap( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + pwcInChars: *const WCHAR, + cChars: c_int, + dwFlags: DWORD, + pwOutGlyphs: *mut WORD, + ) -> HRESULT; + pub fn ScriptGetGlyphABCWidth( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + wGlyph: WORD, + pABC: *mut ABC, + ) -> HRESULT; +} +STRUCT!{struct SCRIPT_PROPERTIES { + bit_fields1: DWORD, + bit_fields2: DWORD, +}} +BITFIELD!{SCRIPT_PROPERTIES bit_fields1: DWORD [ + langid set_langid[0..16], + fNumeric set_fNumeric[16..17], + fComplex set_fComplex[17..18], + fNeedsWordBreaking set_fNeedsWordBreaking[18..19], + fNeedsCaretInfo set_fNeedsCaretInfo[19..20], + bCharSet set_bCharSet[20..28], + fControl set_fControl[28..29], + fPrivateUseArea set_fPrivateUseArea[29..30], + fNeedsCharacterJustify set_fNeedsCharacterJustify[30..31], + fInvalidGlyph set_fInvalidGlyph[31..32], +]} +BITFIELD!{SCRIPT_PROPERTIES bit_fields2: DWORD [ + fInvalidLogAttr set_fInvalidLogAttr[0..1], + fCDM set_fCDM[1..2], + fAmbiguousCharSet set_fAmbiguousCharSet[2..3], + fClusterSizeVaries set_fClusterSizeVaries[3..4], + fRejectInvalid set_fRejectInvalid[4..5], +]} +extern "system" { + pub fn ScriptGetProperties( + ppSp: *mut *mut *const SCRIPT_PROPERTIES, + piNumScripts: *mut c_int, + ) -> HRESULT; +} +STRUCT!{struct SCRIPT_FONTPROPERTIES { + cBytes: c_int, + wgBlank: WORD, + wgDefault: WORD, + wgInvalid: WORD, + wgKashida: WORD, + iKashidaWidth: c_int, +}} +extern "system" { + pub fn ScriptGetFontProperties( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + sfp: *mut SCRIPT_FONTPROPERTIES, + ) -> HRESULT; + pub fn ScriptCacheGetHeight( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + tmHeight: *mut c_long, + ) -> HRESULT; +} +pub const SSA_PASSWORD: DWORD = 0x00000001; +pub const SSA_TAB: DWORD = 0x00000002; +pub const SSA_CLIP: DWORD = 0x00000004; +pub const SSA_FIT: DWORD = 0x00000008; +pub const SSA_DZWG: DWORD = 0x00000010; +pub const SSA_FALLBACK: DWORD = 0x00000020; +pub const SSA_BREAK: DWORD = 0x00000040; +pub const SSA_GLYPHS: DWORD = 0x00000080; +pub const SSA_RTL: DWORD = 0x00000100; +pub const SSA_GCP: DWORD = 0x00000200; +pub const SSA_HOTKEY: DWORD = 0x00000400; +pub const SSA_METAFILE: DWORD = 0x00000800; +pub const SSA_LINK: DWORD = 0x00001000; +pub const SSA_HIDEHOTKEY: DWORD = 0x00002000; +pub const SSA_HOTKEYONLY: DWORD = 0x00002400; +pub const SSA_FULLMEASURE: DWORD = 0x04000000; +pub const SSA_LPKANSIFALLBACK: DWORD = 0x08000000; +pub const SSA_PIDX: DWORD = 0x10000000; +pub const SSA_LAYOUTRTL: DWORD = 0x20000000; +pub const SSA_DONTGLYPH: DWORD = 0x40000000; +pub const SSA_NOKASHIDA: DWORD = 0x80000000; +STRUCT!{struct SCRIPT_TABDEF { + cTabStops: c_int, + iScale: c_int, + pTabStops: *mut c_int, + iTabOrigin: c_int, +}} +DECLARE_HANDLE!{SCRIPT_STRING_ANALYSIS, SCRIPT_STRING_ANALYSIS__} +extern "system" { + pub fn ScriptStringAnalyse( + hdc: HDC, + pString: *const c_void, + cString: c_int, + cGlyphs: c_int, + iCharset: c_int, + dwFlags: DWORD, + iReqWidth: c_int, + psControl: *mut SCRIPT_CONTROL, + psState: *mut SCRIPT_STATE, + piDx: *const c_int, + pTabdef: *mut SCRIPT_TABDEF, + pbInClass: *const BYTE, + pssa: *mut SCRIPT_STRING_ANALYSIS, + ) -> HRESULT; + pub fn ScriptStringFree( + pssa: *mut SCRIPT_STRING_ANALYSIS, + ) -> HRESULT; + pub fn ScriptString_pSize( + ssa: SCRIPT_STRING_ANALYSIS, + ) -> *const SIZE; + pub fn ScriptString_pcOutChars( + ssa: SCRIPT_STRING_ANALYSIS, + ) -> *const c_int; + pub fn ScriptString_pLogAttr( + ssa: SCRIPT_STRING_ANALYSIS, + ) -> *const SCRIPT_LOGATTR; + pub fn ScriptStringGetOrder( + ssa: SCRIPT_STRING_ANALYSIS, + puOrder: *mut UINT, + ) -> HRESULT; + pub fn ScriptStringCPtoX( + ssa: SCRIPT_STRING_ANALYSIS, + icp: c_int, + fTrailing: BOOL, + pX: *mut c_int, + ) -> HRESULT; + pub fn ScriptStringXtoCP( + ssa: SCRIPT_STRING_ANALYSIS, + iX: c_int, + piCh: *mut c_int, + piTrailing: *mut c_int, + ) -> HRESULT; + pub fn ScriptStringGetLogicalWidths( + ssa: SCRIPT_STRING_ANALYSIS, + dpiDx: *mut c_int, + ) -> HRESULT; + pub fn ScriptStringValidate( + ssa: SCRIPT_STRING_ANALYSIS, + ) -> HRESULT; + pub fn ScriptStringOut( + ssa: SCRIPT_STRING_ANALYSIS, + iX: c_int, + iY: c_int, + uOptions: UINT, + prc: *const RECT, + iMinSel: c_int, + iMaxSel: c_int, + fDisabled: BOOL, + ) -> HRESULT; +} +pub const SIC_COMPLEX: DWORD = 1; +pub const SIC_ASCIIDIGIT: DWORD = 2; +pub const SIC_NEUTRAL: DWORD = 4; +extern "system" { + pub fn ScriptIsComplex( + pwcInChars: *const WCHAR, + cInChars: c_int, + dwFlags: DWORD, + ) -> HRESULT; +} +STRUCT!{struct SCRIPT_DIGITSUBSTITUTE { + bit_fields1: DWORD, + bit_fields2: DWORD, + dwReserved: DWORD, +}} +BITFIELD!{SCRIPT_DIGITSUBSTITUTE bit_fields1: DWORD [ + NationalDigitLanguage set_NationalDigitLanguage[0..16], + TraditionalDigitLanguage set_TraditionalDigitLanguage[16..32], +]} +BITFIELD!{SCRIPT_DIGITSUBSTITUTE bit_fields2: DWORD [ + DigitSubstitute set_DigitSubstitute[0..8], +]} +extern "system" { + pub fn ScriptRecordDigitSubstitution( + Locale: LCID, + psds: *mut SCRIPT_DIGITSUBSTITUTE, + ) -> HRESULT; +} +pub const SCRIPT_DIGITSUBSTITUTE_CONTEXT: BYTE = 0; +pub const SCRIPT_DIGITSUBSTITUTE_NONE: BYTE = 1; +pub const SCRIPT_DIGITSUBSTITUTE_NATIONAL: BYTE = 2; +pub const SCRIPT_DIGITSUBSTITUTE_TRADITIONAL: BYTE = 3; +extern "system" { + pub fn ScriptApplyDigitSubstitution( + psds: *const SCRIPT_DIGITSUBSTITUTE, + psc: *mut SCRIPT_CONTROL, + pss: *mut SCRIPT_STATE, + ) -> HRESULT; +} +pub type OPENTYPE_TAG = ULONG; +pub const SCRIPT_TAG_UNKNOWN: OPENTYPE_TAG = 0x00000000; +STRUCT!{struct OPENTYPE_FEATURE_RECORD { + tagFeature: OPENTYPE_TAG, + lParameter: LONG, +}} +STRUCT!{struct TEXTRANGE_PROPERTIES { + potfRecords: *mut OPENTYPE_FEATURE_RECORD, + cotfRecords: c_int, +}} +STRUCT!{struct SCRIPT_CHARPROP { + bit_fields: WORD, +}} +BITFIELD!{SCRIPT_CHARPROP bit_fields: WORD [ + fCanGlyphAlone set_fCanGlyphAlone[0..1], + reserved set_reserved[1..16], +]} +STRUCT!{struct SCRIPT_GLYPHPROP { + sva: SCRIPT_VISATTR, + reserved: WORD, +}} +extern "system" { + pub fn ScriptShapeOpenType( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + rcRangeChars: *mut c_int, + rpRangeProperties: *mut *mut TEXTRANGE_PROPERTIES, + cRanges: c_int, + pwcChars: *const WCHAR, + cChars: c_int, + cMaxGlyphs: c_int, + pwLogClust: *mut WORD, + pCharProps: *mut SCRIPT_CHARPROP, + pwOutGlyphs: *mut WORD, + pOutGlyphProps: *mut SCRIPT_GLYPHPROP, + pcGlyphs: *mut c_int, + ) -> HRESULT; + pub fn ScriptPlaceOpenType( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + rcRangeChars: *mut c_int, + rpRangeProperties: *mut *mut TEXTRANGE_PROPERTIES, + cRanges: c_int, + pwcChars: *const WCHAR, + pwLogClust: *mut WORD, + pCharProps: *mut SCRIPT_CHARPROP, + cChars: c_int, + pwGlyphs: *const WORD, + pGlyphProps: *const SCRIPT_GLYPHPROP, + cGlyphs: c_int, + piAdvance: *mut c_int, + pGoffset: *mut GOFFSET, + pABC: *mut ABC, + ) -> HRESULT; + pub fn ScriptItemizeOpenType( + pwcInChars: *const WCHAR, + cInChars: c_int, + cMaxItems: c_int, + psControl: *const SCRIPT_CONTROL, + psState: *const SCRIPT_STATE, + pItems: *mut SCRIPT_ITEM, + pScriptTags: *mut OPENTYPE_TAG, + pcItems: *mut c_int, + ) -> HRESULT; + pub fn ScriptGetFontScriptTags( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + cMaxTags: c_int, + pScriptTags: *mut OPENTYPE_TAG, + pcTags: *mut c_int, + ) -> HRESULT; + pub fn ScriptGetFontLanguageTags( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + cMaxTags: c_int, + pLangsysTags: *mut OPENTYPE_TAG, + pcTags: *mut c_int, + ) -> HRESULT; + pub fn ScriptGetFontFeatureTags( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + cMaxTags: c_int, + pFeatureTags: *mut OPENTYPE_TAG, + pcTags: *mut c_int, + ) -> HRESULT; + pub fn ScriptGetFontAlternateGlyphs( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + tagFeature: OPENTYPE_TAG, + wGlyphId: WORD, + cMaxAlternates: c_int, + pAlternateGlyphs: *mut WORD, + pcAlternates: *mut c_int, + ) -> HRESULT; + pub fn ScriptSubstituteSingleGlyph( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + tagFeature: OPENTYPE_TAG, + lParameter: LONG, + wGlyphId: WORD, + pwOutGlyphId: *mut WORD, + ) -> HRESULT; + pub fn ScriptPositionSingleGlyph( + hdc: HDC, + psc: *mut SCRIPT_CACHE, + psa: *mut SCRIPT_ANALYSIS, + tagScript: OPENTYPE_TAG, + tagLangSys: OPENTYPE_TAG, + tagFeature: OPENTYPE_TAG, + lParameter: LONG, + wGlyphId: WORD, + iAdvance: c_int, + GOffset: GOFFSET, + piOutAdvance: *mut c_int, + pOutGoffset: *mut GOFFSET, + ) -> HRESULT; +} diff --git a/winapi/src/um/utilapiset.rs b/winapi/src/um/utilapiset.rs new file mode 100644 index 000000000..0ef86e359 --- /dev/null +++ b/winapi/src/um/utilapiset.rs @@ -0,0 +1,25 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, DWORD}; +use shared::ntdef::PVOID; +extern "system" { + pub fn EncodePointer( + Ptr: PVOID, + ) -> PVOID; + pub fn DecodePointer( + Ptr: PVOID, + ) -> PVOID; + pub fn EncodeSystemPointer( + Ptr: PVOID, + ) -> PVOID; + pub fn DecodeSystemPointer( + Ptr: PVOID, + ) -> PVOID; + pub fn Beep( + dwFreq: DWORD, + dwDuration: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/uxtheme.rs b/winapi/src/um/uxtheme.rs new file mode 100644 index 000000000..0e046a356 --- /dev/null +++ b/winapi/src/um/uxtheme.rs @@ -0,0 +1,772 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! theming API +use ctypes::{c_float, c_int, c_void}; +use shared::minwindef::{BOOL, BYTE, DWORD, HINSTANCE, HRGN, LPARAM, UINT, ULONG, WORD}; +use shared::windef::{COLORREF, HBITMAP, HBRUSH, HDC, HWND, LPCRECT, LPRECT, POINT, RECT, SIZE}; +use um::commctrl::HIMAGELIST; +use um::wingdi::{BLENDFUNCTION, LOGFONTW, RGBQUAD, TEXTMETRICW}; +use um::winnt::{HANDLE, HRESULT, LONG, LPCWSTR, LPWSTR, PVOID, VOID}; +pub type HTHEME = HANDLE; +//pub const MAX_THEMECOLOR: u32 = 64; +//pub const MAX_THEMESIZE: u32 = 64; +extern "system" { + pub fn BeginPanningFeedback( + hwnd: HWND, + ) -> BOOL; + pub fn UpdatePanningFeedback( + hwnd: HWND, + lTotalOverpanOffsetX: LONG, + lTotalOverpanOffsetY: LONG, + fInInertia: BOOL, + ) -> BOOL; + pub fn EndPanningFeedback( + hwnd: HWND, + fAnimateBack: BOOL, + ) -> BOOL; +} +ENUM!{enum TA_PROPERTY { + TAP_FLAGS = 0, + TAP_TRANSFORMCOUNT = 1, + TAP_STAGGERDELAY = 2, + TAP_STAGGERDELAYCAP = 3, + TAP_STAGGERDELAYFACTOR = 4, + TAP_ZORDER = 5, +}} +ENUM!{enum TA_PROPERTY_FLAG { + TAPF_NONE = 0x0, + TAPF_HASSTAGGER = 0x1, + TAPF_ISRTLAWARE = 0x2, + TAPF_ALLOWCOLLECTION = 0x4, + TAPF_HASBACKGROUND = 0x8, + TAPF_HASPERSPECTIVE = 0x10, +}} +extern "system" { + pub fn GetThemeAnimationProperty( + hTheme: HTHEME, + iStoryboardId: c_int, + iTargetId: c_int, + eProperty: TA_PROPERTY, + pvProperty: *mut VOID, + cbSize: DWORD, + pcbSizeOut: *mut DWORD, + ) -> HRESULT; +} +ENUM!{enum TA_TRANSFORM_TYPE { + TATT_TRANSLATE_2D = 0, + TATT_SCALE_2D = 1, + TATT_OPACITY = 2, + TATT_CLIP = 3, +}} +ENUM!{enum TA_TRANSFORM_FLAG { + TATF_NONE = 0x0, + TATF_TARGETVALUES_USER = 0x1, + TATF_HASINITIALVALUES = 0x2, + TATF_HASORIGINVALUES = 0x4, +}} +STRUCT!{struct TA_TRANSFORM { + eTransformType: TA_TRANSFORM_TYPE, + dwTimingFunctionId: DWORD, + dwStartTime: DWORD, + dwDurationTime: DWORD, + eFlags: TA_TRANSFORM_FLAG, +}} +pub type PTA_TRANSFORM = *mut TA_TRANSFORM; +STRUCT!{struct TA_TRANSFORM_2D { + header: TA_TRANSFORM, + rX: c_float, + rY: c_float, + rInitialX: c_float, + rInitialY: c_float, + rOriginX: c_float, + rOriginY: c_float, +}} +pub type PTA_TRANSFORM_2D = *mut TA_TRANSFORM_2D; +STRUCT!{struct TA_TRANSFORM_OPACITY { + header: TA_TRANSFORM, + rOpacity: c_float, + rInitialOpacity: c_float, +}} +pub type PTA_TRANSFORM_OPACITY = *mut TA_TRANSFORM_OPACITY; +STRUCT!{struct TA_TRANSFORM_CLIP { + header: TA_TRANSFORM, + rLeft: c_float, + rTop: c_float, + rRight: c_float, + rBottom: c_float, + rInitialLeft: c_float, + rInitialTop: c_float, + rInitialRight: c_float, + rInitialBottom: c_float, +}} +pub type PTA_TRANSFORM_CLIP = *mut TA_TRANSFORM_CLIP; +extern "system" { + pub fn GetThemeAnimationTransform( + hTheme: HTHEME, + iStoryboardId: c_int, + iTargetId: c_int, + dwTransformIndex: DWORD, + pTransform: *mut TA_TRANSFORM, + cbSize: DWORD, + pcbSizeOut: *mut DWORD, + ) -> HRESULT; +} +ENUM!{enum TA_TIMINGFUNCTION_TYPE { + TTFT_UNDEFINED = 0, + TTFT_CUBIC_BEZIER = 1, +}} +STRUCT!{struct TA_TIMINGFUNCTION { + eTimingFunctionType: TA_TIMINGFUNCTION_TYPE, +}} +pub type PTA_TIMINGFUNCTION = *mut TA_TIMINGFUNCTION; +STRUCT!{struct TA_CUBIC_BEZIER { + header: TA_TIMINGFUNCTION, + rX0: c_float, + rY0: c_float, + rX1: c_float, + rY1: c_float, +}} +pub type PTA_CUBIC_BEZIER = *mut TA_CUBIC_BEZIER; +extern "system" { + pub fn GetThemeTimingFunction( + hTheme: HTHEME, + iTimingFunctionId: c_int, + pTimingFunction: *mut TA_TIMINGFUNCTION, + cbSize: DWORD, + pcbSizeOut: *mut DWORD, + ) -> HRESULT; + pub fn OpenThemeData( + hwnd: HWND, + pszClassList: LPCWSTR, + ) -> HTHEME; +} +pub const OTD_FORCE_RECT_SIZING: DWORD = 0x00000001; +pub const OTD_NONCLIENT: DWORD = 0x00000002; +pub const OTD_VALIDBITS: DWORD = OTD_FORCE_RECT_SIZING | OTD_NONCLIENT; +extern "system" { + pub fn OpenThemeDataForDpi( + hwnd: HWND, + pszClassList: LPCWSTR, + dpi: UINT, + ) -> HTHEME; + pub fn OpenThemeDataEx( + hwnd: HWND, + pszClassList: LPCWSTR, + dwFlags: DWORD, + ) -> HTHEME; + pub fn CloseThemeData( + hTheme: HTHEME, + ) -> HRESULT; + pub fn DrawThemeBackground( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pRect: LPCRECT, + pClipRect: LPCRECT, + ) -> HRESULT; +} +pub const DTBG_CLIPRECT: DWORD = 0x00000001; +pub const DTBG_DRAWSOLID: DWORD = 0x00000002; +pub const DTBG_OMITBORDER: DWORD = 0x00000004; +pub const DTBG_OMITCONTENT: DWORD = 0x00000008; +pub const DTBG_COMPUTINGREGION: DWORD = 0x00000010; +pub const DTBG_MIRRORDC: DWORD = 0x00000020; +pub const DTBG_NOMIRROR: DWORD = 0x00000040; +pub const DTBG_VALIDBITS: DWORD = DTBG_CLIPRECT | DTBG_DRAWSOLID | DTBG_OMITBORDER + | DTBG_OMITCONTENT | DTBG_COMPUTINGREGION | DTBG_MIRRORDC | DTBG_NOMIRROR; +STRUCT!{struct DTBGOPTS { + dwSize: DWORD, + dwFlags: DWORD, + rcClip: RECT, +}} +pub type PDTBGOPTS = *mut DTBGOPTS; +extern "system" { + pub fn DrawThemeBackgroundEx( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pRect: LPCRECT, + pOptions: *const DTBGOPTS, + ) -> HRESULT; +} +//pub const DTT_GRAYED: u32 = 0x00000001; +//pub const DTT_FLAGS2VALIDBITS: u32 = DTT_GRAYED; +extern "system" { + pub fn DrawThemeText( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pszText: LPCWSTR, + cchText: c_int, + dwTextFlags: DWORD, + dwTextFlags2: DWORD, + pRect: LPCRECT, + ) -> HRESULT; + pub fn GetThemeBackgroundContentRect( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pBoundingRect: LPCRECT, + pContentRect: LPRECT, + ) -> HRESULT; + pub fn GetThemeBackgroundExtent( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pContentRect: LPCRECT, + pExtentRect: LPRECT, + ) -> HRESULT; + pub fn GetThemeBackgroundRegion( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pRect: LPCRECT, + pRegion: *mut HRGN, + ) -> HRESULT; +} +ENUM!{enum THEMESIZE { + TS_MIN = 0, + TS_TRUE = 1, + TS_DRAW = 2, +}} +extern "system" { + pub fn GetThemePartSize( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + prc: LPCRECT, + eSize: THEMESIZE, + psz: *mut SIZE, + ) -> HRESULT; + pub fn GetThemeTextExtent( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pszText: LPCWSTR, + cchCharCount: c_int, + dwTextFlags: DWORD, + pBoundingRect: LPCRECT, + pExtentRect: LPRECT, + ) -> HRESULT; + pub fn GetThemeTextMetrics( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + ptm: *mut TEXTMETRICW, + ) -> HRESULT; +} +pub const HTTB_BACKGROUNDSEG: DWORD = 0x00000000; +pub const HTTB_FIXEDBORDER: DWORD = 0x00000002; +pub const HTTB_CAPTION: DWORD = 0x00000004; +pub const HTTB_RESIZINGBORDER_LEFT: DWORD = 0x00000010; +pub const HTTB_RESIZINGBORDER_TOP: DWORD = 0x00000020; +pub const HTTB_RESIZINGBORDER_RIGHT: DWORD = 0x00000040; +pub const HTTB_RESIZINGBORDER_BOTTOM: DWORD = 0x00000080; +pub const HTTB_RESIZINGBORDER: DWORD = HTTB_RESIZINGBORDER_LEFT | HTTB_RESIZINGBORDER_TOP + | HTTB_RESIZINGBORDER_RIGHT | HTTB_RESIZINGBORDER_BOTTOM; +pub const HTTB_SIZINGTEMPLATE: DWORD = 0x00000100; +pub const HTTB_SYSTEMSIZINGMARGINS: DWORD = 0x00000200; +extern "system" { + pub fn HitTestThemeBackground( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + dwOptions: DWORD, + pRect: LPCRECT, + hrgn: HRGN, + ptTest: POINT, + pwHitTestCode: *mut WORD, + ) -> HRESULT; + pub fn DrawThemeEdge( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pDestRect: LPCRECT, + uEdge: UINT, + uFlags: UINT, + pContentRect: LPRECT, + ) -> HRESULT; + pub fn DrawThemeIcon( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pRect: LPCRECT, + himl: HIMAGELIST, + iImageIndex: c_int, + ) -> HRESULT; + pub fn IsThemePartDefined( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + ) -> BOOL; + pub fn IsThemeBackgroundPartiallyTransparent( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + ) -> BOOL; + pub fn GetThemeColor( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pColor: *mut COLORREF, + ) -> HRESULT; + pub fn GetThemeMetric( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + piVal: *mut c_int, + ) -> HRESULT; + pub fn GetThemeString( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pszBuff: LPWSTR, + cchMaxBuffChars: c_int, + ) -> HRESULT; + pub fn GetThemeBool( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pfVal: *mut BOOL, + ) -> HRESULT; + pub fn GetThemeInt( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + piVal: *mut c_int, + ) -> HRESULT; + pub fn GetThemeEnumValue( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + piVal: *mut c_int, + ) -> HRESULT; + pub fn GetThemePosition( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pPoint: *mut POINT, + ) -> HRESULT; + pub fn GetThemeFont( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pFont: *mut LOGFONTW, + ) -> HRESULT; + pub fn GetThemeRect( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pRect: LPRECT, + ) -> HRESULT; +} +STRUCT!{struct MARGINS { + cxLeftWidth: c_int, + cxRightWidth: c_int, + cyTopHeight: c_int, + cyBottomHeight: c_int, +}} +pub type PMARGINS = *mut MARGINS; +extern "system" { + pub fn GetThemeMargins( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + prc: LPCRECT, + pMargins: *mut MARGINS, + ) -> HRESULT; +} +pub const MAX_INTLIST_COUNT: usize = 402; +STRUCT!{struct INTLIST { + iValueCount: c_int, + iValues: [c_int; MAX_INTLIST_COUNT], +}} +pub type PINTLIST = *mut INTLIST; +extern "system" { + pub fn GetThemeIntList( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pIntList: *mut INTLIST, + ) -> HRESULT; +} +ENUM!{enum PROPERTYORIGIN { + PO_STATE = 0, + PO_PART = 1, + PO_CLASS = 2, + PO_GLOBAL = 3, + PO_NOTFOUND = 4, +}} +extern "system" { + pub fn GetThemePropertyOrigin( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pOrigin: *mut PROPERTYORIGIN, + ) -> HRESULT; + pub fn SetWindowTheme( + hwnd: HWND, + pszSubAppName: LPCWSTR, + pszSubIdList: LPCWSTR, + ) -> HRESULT; + pub fn GetThemeFilename( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + pszThemeFileName: LPWSTR, + cchMaxBuffChars: c_int, + ) -> HRESULT; + pub fn GetThemeSysColor( + hTheme: HTHEME, + iColorId: c_int, + ) -> COLORREF; + pub fn GetThemeSysColorBrush( + hTheme: HTHEME, + iColorId: c_int, + ) -> HBRUSH; + pub fn GetThemeSysBool( + hTheme: HTHEME, + iBoolId: c_int, + ) -> BOOL; + pub fn GetThemeSysSize( + hTheme: HTHEME, + iSizeId: c_int, + ) -> c_int; + pub fn GetThemeSysFont( + hTheme: HTHEME, + iFontId: c_int, + plf: *mut LOGFONTW, + ) -> HRESULT; + pub fn GetThemeSysString( + hTheme: HTHEME, + iStringId: c_int, + pszStringBuff: LPWSTR, + cchMaxStringChars: c_int, + ) -> HRESULT; + pub fn GetThemeSysInt( + hTheme: HTHEME, + iIntId: c_int, + piValue: *mut c_int, + ) -> HRESULT; + pub fn IsThemeActive() -> BOOL; + pub fn IsAppThemed() -> BOOL; + pub fn GetWindowTheme( + hwnd: HWND, + ) -> HTHEME; +} +pub const ETDT_DISABLE: DWORD = 0x00000001; +pub const ETDT_ENABLE: DWORD = 0x00000002; +pub const ETDT_USETABTEXTURE: DWORD = 0x00000004; +pub const ETDT_ENABLETAB: DWORD = ETDT_ENABLE | ETDT_USETABTEXTURE; +pub const ETDT_USEAEROWIZARDTABTEXTURE: DWORD = 0x00000008; +pub const ETDT_ENABLEAEROWIZARDTAB: DWORD = ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE; +pub const ETDT_VALIDBITS: DWORD = ETDT_DISABLE | ETDT_ENABLE | ETDT_USETABTEXTURE + | ETDT_USEAEROWIZARDTABTEXTURE; +extern "system" { + pub fn EnableThemeDialogTexture( + hwnd: HWND, + dwFlags: DWORD, + ) -> HRESULT; + pub fn IsThemeDialogTextureEnabled( + hwnd: HWND, + ) -> BOOL; +} +pub const STAP_ALLOW_NONCLIENT: DWORD = 1 << 0; +pub const STAP_ALLOW_CONTROLS: DWORD = 1 << 1; +pub const STAP_ALLOW_WEBCONTENT: DWORD = 1 << 2; +pub const STAP_VALIDBITS: DWORD = STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS + | STAP_ALLOW_WEBCONTENT; +extern "system" { + pub fn GetThemeAppProperties() -> DWORD; + pub fn SetThemeAppProperties( + dwFlags: DWORD, + ); + pub fn GetCurrentThemeName( + pszThemeFileName: LPWSTR, + cchMaxNameChars: c_int, + pszColorBuff: LPWSTR, + cchMaxColorChars: c_int, + pszSizeBuff: LPWSTR, + cchMaxSizeChars: c_int, + ) -> HRESULT; +} +pub const SZ_THDOCPROP_DISPLAYNAME: &'static str = "DisplayName"; +pub const SZ_THDOCPROP_CANONICALNAME: &'static str = "ThemeName"; +pub const SZ_THDOCPROP_TOOLTIP: &'static str = "ToolTip"; +pub const SZ_THDOCPROP_AUTHOR: &'static str = "author"; +extern "system" { + pub fn GetThemeDocumentationProperty( + pszThemeName: LPCWSTR, + pszPropertyName: LPCWSTR, + pszValueBuff: LPWSTR, + cchMaxValChars: c_int, + ) -> HRESULT; + pub fn DrawThemeParentBackground( + hwnd: HWND, + hdc: HDC, + prc: *const RECT, + ) -> HRESULT; + pub fn EnableTheming( + fEnable: BOOL, + ) -> HRESULT; +} +pub const GBF_DIRECT: ULONG = 0x00000001; +pub const GBF_COPY: ULONG = 0x00000002; +pub const GBF_VALIDBITS: ULONG = GBF_DIRECT | GBF_COPY; +pub const DTPB_WINDOWDC: DWORD = 0x00000001; +pub const DTPB_USECTLCOLORSTATIC: DWORD = 0x00000002; +pub const DTPB_USEERASEBKGND: DWORD = 0x00000004; +extern "system" { + pub fn DrawThemeParentBackgroundEx( + hwnd: HWND, + hdc: HDC, + dwFlags: DWORD, + prc: *const RECT, + ) -> HRESULT; +} +ENUM!{enum WINDOWTHEMEATTRIBUTETYPE { + WTA_NONCLIENT = 1, +}} +STRUCT!{struct WTA_OPTIONS { + dwFlags: DWORD, + dwMask: DWORD, +}} +pub type PWTA_OPTIONS = *mut WTA_OPTIONS; +pub const WTNCA_NODRAWCAPTION: DWORD = 0x00000001; +pub const WTNCA_NODRAWICON: DWORD = 0x00000002; +pub const WTNCA_NOSYSMENU: DWORD = 0x00000004; +pub const WTNCA_NOMIRRORHELP: DWORD = 0x00000008; +pub const WTNCA_VALIDBITS: DWORD = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU + | WTNCA_NOMIRRORHELP; +extern "system" { + pub fn SetWindowThemeAttribute( + hwnd: HWND, + eAttribute: WINDOWTHEMEATTRIBUTETYPE, + pvAttribute: PVOID, + cbAttribute: DWORD, + ) -> HRESULT; +} +#[inline] +pub unsafe fn SetWindowThemeNonClientAttributes( + hwnd: HWND, + dwMask: DWORD, + dwAttributes: DWORD, +) -> HRESULT { + use core::mem::{size_of, zeroed}; + let mut wta: WTA_OPTIONS = zeroed(); + wta.dwFlags = dwAttributes; + wta.dwMask = dwMask; + SetWindowThemeAttribute( + hwnd, + WTA_NONCLIENT, + &mut wta as *mut WTA_OPTIONS as *mut c_void, + size_of::<WTA_OPTIONS>() as u32, + ) +} +FN!{stdcall DTT_CALLBACK_PROC( + hdc: HDC, + pszText: LPWSTR, + cchText: c_int, + prc: LPRECT, + dwFlags: UINT, + lParam: LPARAM, +) -> c_int} +pub const DTT_TEXTCOLOR: DWORD = 1 << 0; +pub const DTT_BORDERCOLOR: DWORD = 1 << 1; +pub const DTT_SHADOWCOLOR: DWORD = 1 << 2; +pub const DTT_SHADOWTYPE: DWORD = 1 << 3; +pub const DTT_SHADOWOFFSET: DWORD = 1 << 4; +pub const DTT_BORDERSIZE: DWORD = 1 << 5; +pub const DTT_FONTPROP: DWORD = 1 << 6; +pub const DTT_COLORPROP: DWORD = 1 << 7; +pub const DTT_STATEID: DWORD = 1 << 8; +pub const DTT_CALCRECT: DWORD = 1 << 9; +pub const DTT_APPLYOVERLAY: DWORD = 1 << 10; +pub const DTT_GLOWSIZE: DWORD = 1 << 11; +pub const DTT_CALLBACK: DWORD = 1 << 12; +pub const DTT_COMPOSITED: DWORD = 1 << 13; +pub const DTT_VALIDBITS: DWORD = DTT_TEXTCOLOR | DTT_BORDERCOLOR | DTT_SHADOWCOLOR + | DTT_SHADOWTYPE | DTT_SHADOWOFFSET | DTT_BORDERSIZE | DTT_FONTPROP | DTT_COLORPROP + | DTT_STATEID | DTT_CALCRECT | DTT_APPLYOVERLAY | DTT_GLOWSIZE | DTT_COMPOSITED; +STRUCT!{struct DTTOPTS { + dwSize: DWORD, + dwFlags: DWORD, + crText: COLORREF, + crBorder: COLORREF, + crShadow: COLORREF, + iTextShadowType: c_int, + ptShadowOffset: POINT, + iBorderSize: c_int, + iFontPropId: c_int, + iColorPropId: c_int, + iStateId: c_int, + fApplyOverlay: BOOL, + iGlowSize: c_int, + pfnDrawTextCallback: DTT_CALLBACK_PROC, + lParam: LPARAM, +}} +pub type PDTTOPTS = *mut DTTOPTS; +extern "system" { + pub fn DrawThemeTextEx( + hTheme: HTHEME, + hdc: HDC, + iPartId: c_int, + iStateId: c_int, + pszText: LPCWSTR, + cchText: c_int, + dwTextFlags: DWORD, + pRect: LPRECT, + pOptions: *const DTTOPTS, + ) -> HRESULT; + pub fn GetThemeBitmap( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + dwFlags: ULONG, + phBitmap: *mut HBITMAP, + ) -> HRESULT; + pub fn GetThemeStream( + hTheme: HTHEME, + iPartId: c_int, + iStateId: c_int, + iPropId: c_int, + ppvStream: *mut *mut VOID, + pcbStream: *mut DWORD, + hInst: HINSTANCE, + ) -> HRESULT; + pub fn BufferedPaintInit() -> HRESULT; + pub fn BufferedPaintUnInit() -> HRESULT; +} +pub type HPAINTBUFFER = HANDLE; +ENUM!{enum BP_BUFFERFORMAT { + BPBF_COMPATIBLEBITMAP = 0, + BPBF_DIB = 1, + BPBF_TOPDOWNDIB = 2, + BPBF_TOPDOWNMONODIB = 3, +}} +pub const BPBF_COMPOSITED: BP_BUFFERFORMAT = BPBF_TOPDOWNDIB; +ENUM!{enum BP_ANIMATIONSTYLE { + BPAS_NONE = 0, + BPAS_LINEAR = 1, + BPAS_CUBIC = 2, + BPAS_SINE = 3, +}} +STRUCT!{struct BP_ANIMATIONPARAMS { + cbSize: DWORD, + dwFlags: DWORD, + style: BP_ANIMATIONSTYLE, + dwDuration: DWORD, +}} +pub type PBP_ANIMATIONPARAMS = *mut BP_ANIMATIONPARAMS; +pub const BPPF_ERASE: DWORD = 0x0001; +pub const BPPF_NOCLIP: DWORD = 0x0002; +pub const BPPF_NONCLIENT: DWORD = 0x0004; +STRUCT!{struct BP_PAINTPARAMS { + cbSize: DWORD, + dwFlags: DWORD, + prcExclude: *const RECT, + pBlendFunction: *const BLENDFUNCTION, +}} +pub type PBP_PAINTPARAMS = *mut BP_PAINTPARAMS; +extern "system" { + pub fn BeginBufferedPaint( + hdcTarget: HDC, + prcTarget: *const RECT, + dwFormat: BP_BUFFERFORMAT, + pPaintParams: *mut BP_PAINTPARAMS, + phdc: *mut HDC, + ) -> HPAINTBUFFER; + pub fn EndBufferedPaint( + hBufferedPaint: HPAINTBUFFER, + fUpdateTarget: BOOL, + ) -> HRESULT; + pub fn GetBufferedPaintTargetRect( + hBufferedPaint: HPAINTBUFFER, + prc: *mut RECT, + ) -> HRESULT; + pub fn GetBufferedPaintTargetDC( + hBufferedPaint: HPAINTBUFFER, + ) -> HDC; + pub fn GetBufferedPaintDC( + hBufferedPaint: HPAINTBUFFER, + ) -> HDC; + pub fn GetBufferedPaintBits( + hBufferedPaint: HPAINTBUFFER, + ppbBuffer: *mut *mut RGBQUAD, + pcxRow: *mut c_int, + ) -> HRESULT; + pub fn BufferedPaintClear( + hBufferedPaint: HPAINTBUFFER, + prc: *const RECT, + ) -> HRESULT; + pub fn BufferedPaintSetAlpha( + hBufferedPaint: HPAINTBUFFER, + prc: *const RECT, + alpha: BYTE, + ) -> HRESULT; + pub fn BufferedPaintStopAllAnimations( + hwnd: HWND, + ) -> HRESULT; +} +pub type HANIMATIONBUFFER = HANDLE; +extern "system" { + pub fn BeginBufferedAnimation( + hwnd: HWND, + hdcTarget: HDC, + prcTarget: *const RECT, + dwFormat: BP_BUFFERFORMAT, + pPaintParams: *mut BP_PAINTPARAMS, + pAnimationParams: *mut BP_ANIMATIONPARAMS, + phdcFrom: *mut HDC, + phdcTo: *mut HDC, + ) -> HANIMATIONBUFFER; + pub fn EndBufferedAnimation( + hbpAnimation: HANIMATIONBUFFER, + fUpdateTarget: BOOL, + ) -> HRESULT; + pub fn BufferedPaintRenderAnimation( + hwnd: HWND, + hdcTarget: HDC, + ) -> BOOL; + pub fn IsCompositionActive() -> BOOL; + pub fn GetThemeTransitionDuration( + hTheme: HTHEME, + iPartId: c_int, + iStateIdFrom: c_int, + iStateIdTo: c_int, + iPropId: c_int, + pdwDuration: *mut DWORD, + ) -> HRESULT; +} diff --git a/winapi/src/um/vsbackup.rs b/winapi/src/um/vsbackup.rs new file mode 100644 index 000000000..0a7f2602c --- /dev/null +++ b/winapi/src/um/vsbackup.rs @@ -0,0 +1,520 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Declaration of backup interfaces. +use ctypes::c_void; +use shared::guiddef::IID; +use shared::minwindef::{BOOL, BYTE, DWORD, UINT}; +use shared::wtypes::BSTR; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::vss::{ + IVssAsync, IVssEnumObject, VSS_BACKUP_TYPE, VSS_ID, VSS_OBJECT_TYPE, VSS_PWSZ, + VSS_RESTORE_TYPE, VSS_ROLLFORWARD_TYPE, VSS_SNAPSHOT_PROP, VSS_WRITER_STATE +}; +use um::vswriter::{ + IVssWMDependency, IVssWMFiledesc, IVssWriterComponentsVtbl, VSS_COMPONENT_TYPE, + VSS_FILE_RESTORE_STATUS, VSS_RESTOREMETHOD_ENUM, VSS_SOURCE_TYPE, VSS_USAGE_TYPE, + VSS_WRITERRESTORE_ENUM +}; +use um::winnt::{HRESULT, LONG, LPCWSTR}; +DEFINE_GUID!{IID_IVssExamineWriterMetadata, + 0x902fcf7f, 0xb7fd, 0x42f8, 0x81, 0xf1, 0xb2, 0xe4, 0x00, 0xb1, 0xe5, 0xbd} +DEFINE_GUID!{IID_IVssExamineWriterMetadataEx, + 0x0c0e5ec0, 0xca44, 0x472b, 0xb7, 0x02, 0xe6, 0x52, 0xdb, 0x1c, 0x04, 0x51} +DEFINE_GUID!{IID_IVssBackupComponents, + 0x665c1d5f, 0xc218, 0x414d, 0xa0, 0x5d, 0x7f, 0xef, 0x5f, 0x9d, 0x5c, 0x86} +DEFINE_GUID!{IID_IVssBackupComponentsEx, + 0x963f03ad, 0x9e4c, 0x4a34, 0xac, 0x15, 0xe4, 0xb6, 0x17, 0x4e, 0x50, 0x36} +STRUCT!{struct VSS_COMPONENTINFO { + type_: VSS_COMPONENT_TYPE, // type is a keyword in rust + bstrLogicalPath: BSTR, + bstrComponentName: BSTR, + bstrCaption: BSTR, + pbIcon: *mut BYTE, + cbIcon: UINT, + bRestoreMetadata: bool, + bNotifyOnBackupComplete: bool, + bSelectable: bool, + bSelectableForRestore: bool, + dwComponentFlags: DWORD, + cFileCount: UINT, + cDatabases: UINT, + cLogFiles: UINT, + cDependencies: UINT, +}} +pub type PVSSCOMPONENTINFO = *const VSS_COMPONENTINFO; +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface IVssWMComponent(IVssWMComponentVtbl): IUnknown(IUnknownVtbl) { + fn GetComponentInfo( + ppInfo: *mut PVSSCOMPONENTINFO, + ) -> HRESULT, + fn FreeComponentInfo( + pInfo: PVSSCOMPONENTINFO, + ) -> HRESULT, + fn GetFile( + iFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetDatabaseFile( + iDBFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetDatabaseLogFile( + iDbLogFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetDependency( + iDependency: UINT, + ppDependency: *mut *mut IVssWMDependency, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x902fcf7f, 0xb7fd, 0x42f8, 0x81, 0xf1, 0xb2, 0xe4, 0x00, 0xb1, 0xe5, 0xbd)] +interface IVssExamineWriterMetadata(IVssExamineWriterMetadataVtbl): IUnknown(IUnknownVtbl) { + fn GetIdentity( + pidInstance: *mut VSS_ID, + pidWriter: *mut VSS_ID, + pbstrWriterName: *mut BSTR, + pUsage: *mut VSS_USAGE_TYPE, + pSource: *mut VSS_SOURCE_TYPE, + ) -> HRESULT, + fn GetFileCounts( + pcIncludeFiles: *mut UINT, + pcExcludeFiles: *mut UINT, + pcComponents: *mut UINT, + ) -> HRESULT, + fn GetIncludeFile( + iFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetExcludeFile( + iFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetComponent( + iComponent: UINT, + ppComponent: *mut *mut IVssWMComponent, + ) -> HRESULT, + fn GetRestoreMethod( + pMethod: *mut VSS_RESTOREMETHOD_ENUM, + pbstrService: *mut BSTR, + pbstrUserProcedure: *mut BSTR, + pwriterRestore: *mut VSS_WRITERRESTORE_ENUM, + pbRebootRequired: *mut bool, + pcMappings: *mut UINT, + ) -> HRESULT, + fn GetAlternateLocationMapping( + iMapping: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn GetBackupSchema( + pdwSchemaMask: *mut DWORD, + ) -> HRESULT, + fn GetDocument( + pDoc: *mut c_void, + ) -> HRESULT, //TODO IXMLDOMDocument, + fn SaveAsXML( + pbstrXML: *mut BSTR, + ) -> HRESULT, + fn LoadFromXML( + pbstrXML: *mut BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x0c0e5ec0, 0xca44, 0x472b, 0xb7, 0x02, 0xe6, 0x52, 0xdb, 0x1c, 0x04, 0x51)] +interface IVssExamineWriterMetadataEx(IVssExamineWriterMetadataExVtbl): + IVssExamineWriterMetadata(IVssExamineWriterMetadataVtbl) { + fn GetIdentityEx( + pidInstance: *mut VSS_ID, + pidWriter: *mut VSS_ID, + pbstrWriterName: *mut BSTR, + pbstrInstanceName: *mut BSTR, + pUsage: *mut VSS_USAGE_TYPE, + pSource: *mut VSS_SOURCE_TYPE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xce115780, 0xa611, 0x431b, 0xb5, 0x7f, 0xc3, 0x83, 0x03, 0xab, 0x6a, 0xee)] +interface IVssExamineWriterMetadataEx2(IVssExamineWriterMetadataEx2Vtbl): + IVssExamineWriterMetadataEx(IVssExamineWriterMetadataExVtbl) { + fn GetVersion( + pdwMajorVersion: *mut DWORD, + pdwMinorVersion: *mut DWORD, + ) -> HRESULT, + fn GetExcludeFromSnapshotCount( + pcExcludedFromSnapshot: *mut UINT, + ) -> HRESULT, + fn GetExcludeFromSnapshotFile( + iFile: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, +}} +#[repr(C)] +pub struct IVssWriterComponentsExt { + pub lpVtbl: *const IVssWriterComponentsExtVtbl, +} +#[repr(C)] +pub struct IVssWriterComponentsExtVtbl { + pub parent1: IVssWriterComponentsVtbl, + pub parent2: IUnknownVtbl, +} +RIDL!{#[uuid(0x665c1d5f, 0xc218, 0x414d, 0xa0, 0x5d, 0x7f, 0xef, 0x5f, 0x9d, 0x5c, 0x86)] +interface IVssBackupComponents(IVssBackupComponentsVtbl): IUnknown(IUnknownVtbl) { + fn GetWriterComponentsCount( + pcComponents: *mut UINT, + ) -> HRESULT, + fn GetWriterComponents( + iWriter: UINT, + ppWriter: *mut *mut IVssWriterComponentsExt, + ) -> HRESULT, + fn InitializeForBackup( + bstrXML: BSTR, + ) -> HRESULT, + fn SetBackupState( + bSelectComponents: bool, + bBackupBootableSystemState: bool, + backupType: VSS_BACKUP_TYPE, + bPartialFileSupport: bool, + ) -> HRESULT, + fn InitializeForRestore( + bstrXML: BSTR, + ) -> HRESULT, + fn SetRestoreState( + restoreType: VSS_RESTORE_TYPE, + ) -> HRESULT, + fn GatherWriterMetadata( + pAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn GetWriterMetadataCount( + pcWriters: *mut UINT, + ) -> HRESULT, + fn GetWriterMetadata( + iWriter: UINT, + pidInstance: *mut VSS_ID, + ppMetadata: *mut *mut IVssExamineWriterMetadata, + ) -> HRESULT, + fn FreeWriterMetadata() -> HRESULT, + fn AddComponent( + instanceId: VSS_ID, + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + ) -> HRESULT, + fn PrepareForBackup( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn AbortBackup() -> HRESULT, + fn GatherWriterStatus( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn GetWriterStatusCount( + pcWriters: *mut UINT, + ) -> HRESULT, + fn FreeWriterStatus() -> HRESULT, + fn GetWriterStatus( + iWriter: UINT, + pidInstance: *mut VSS_ID, + pidWriter: *mut VSS_ID, + pbstrWriter: *mut BSTR, + pnStatus: *mut VSS_WRITER_STATE, + phResultFailure: *mut HRESULT, + ) -> HRESULT, + fn SetBackupSucceeded( + instanceId: VSS_ID, + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + bSucceded: bool, + ) -> HRESULT, + fn SetBackupOptions( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszBackupOptions: LPCWSTR, + ) -> HRESULT, + fn SetSelectedForRestore( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + bSelectedForRestore: bool, + ) -> HRESULT, + fn SetRestoreOptions( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszRestoreOptions: LPCWSTR, + ) -> HRESULT, + fn SetAdditionalRestores( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + bAdditionalRestores: bool, + ) -> HRESULT, + fn SetPreviousBackupStamp( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszPreviousBackupStamp: LPCWSTR, + ) -> HRESULT, + fn SaveAsXML( + pbstrXML: *mut BSTR, + ) -> HRESULT, + fn BackupComplete( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn AddAlternativeLocationMapping( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: bool, + wszDestination: LPCWSTR, + ) -> HRESULT, + fn AddRestoreSubcomponent( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszSubComponentLogicalPath: LPCWSTR, + wszSubComponentName: LPCWSTR, + bRepair: bool, + ) -> HRESULT, + fn SetFileRestoreStatus( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + status: VSS_FILE_RESTORE_STATUS, + ) -> HRESULT, + fn AddNewTarget( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszPath: LPCWSTR, + wszFileName: LPCWSTR, + bRecursive: bool, + wszAlternatePath: LPCWSTR, + ) -> HRESULT, + fn SetRangesFilePath( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + iPartialFile: UINT, + wszRangesFile: LPCWSTR, + ) -> HRESULT, + fn PreRestore( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn PostRestore( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn SetContext( + lContext: LONG, + ) -> HRESULT, + fn StartSnapshotSet( + pSnapshotSetId: *mut VSS_ID, + ) -> HRESULT, + fn AddToSnapshotSet( + pwszVolumeName: VSS_PWSZ, + ProviderId: VSS_ID, + pidSnapshot: *mut VSS_ID, + ) -> HRESULT, + fn DoSnapshotSet( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn DeleteSnapshots( + SourceObjectId: VSS_ID, + eSourceObjectType: VSS_OBJECT_TYPE, + bForceDelete: BOOL, + plDeletedSnapshots: *mut LONG, + pNondeletedSnapshotID: *mut VSS_ID, + ) -> HRESULT, + fn ImportSnapshots( + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn BreakSnapshotSet( + SnapshotSetId: VSS_ID, + ) -> HRESULT, + fn GetSnapshotProperties( + SnapshotId: VSS_ID, + pProp: *mut VSS_SNAPSHOT_PROP, + ) -> HRESULT, + fn Query( + QueriedObjectId: VSS_ID, + eQueriedObjectType: VSS_OBJECT_TYPE, + eReturnedObjectsType: VSS_OBJECT_TYPE, + ppEnum: *mut *mut IVssEnumObject, + ) -> HRESULT, + fn IsVolumeSupported( + ProviderId: VSS_ID, + pwszVolumeName: VSS_PWSZ, + pbSupportedByThisProvider: *mut BOOL, + ) -> HRESULT, + fn DisableWriterClasses( + rgWriterClassId: *const VSS_ID, + cClassId: UINT, + ) -> HRESULT, + fn EnableWriterClasses( + rgWriterClassId: *const VSS_ID, + cClassId: UINT, + ) -> HRESULT, + fn DisableWriterInstances( + rgWriterInstanceId: *const VSS_ID, + cInstanceId: UINT, + ) -> HRESULT, + fn ExposeSnapshot( + SnapshotId: VSS_ID, + wszPathFromRoot: VSS_PWSZ, + lAttributes: LONG, + wszExpose: VSS_PWSZ, + pwszExposed: VSS_PWSZ, + ) -> HRESULT, + fn RevertToSnapshot( + SnapshotId: VSS_ID, + bForceDismount: BOOL, + ) -> HRESULT, + fn QueryRevertStatus( + pwszVolume: VSS_PWSZ, + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x963f03ad, 0x9e4c, 0x4a34, 0xac, 0x15, 0xe4, 0xb6, 0x17, 0x4e, 0x50, 0x36)] +interface IVssBackupComponentsEx(IVssBackupComponentsExVtbl): + IVssBackupComponents(IVssBackupComponentsVtbl) { + fn GetWriterMetadataEx( + iWriter: UINT, + pidInstance: *mut VSS_ID, + ppMetadata: *mut *mut IVssExamineWriterMetadataEx, + ) -> HRESULT, + fn SetSelectedForRestoreEx( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + bSelectedForRestore: bool, + instanceId: VSS_ID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xacfe2b3a, 0x22c9, 0x4ef8, 0xbd, 0x03, 0x2f, 0x9c, 0xa2, 0x30, 0x08, 0x4e)] +interface IVssBackupComponentsEx2(IVssBackupComponentsEx2Vtbl): + IVssBackupComponentsEx(IVssBackupComponentsExVtbl) { + fn UnexposeSnapshot( + snapshotId: VSS_ID, + ) -> HRESULT, + fn SetAuthoritativeRestore( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + bAuth: bool, + ) -> HRESULT, + fn SetRollForward( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + rollType: VSS_ROLLFORWARD_TYPE, + wszRollForwardPoint: LPCWSTR, + ) -> HRESULT, + fn SetRestoreName( + writerId: VSS_ID, + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszRestoreName: LPCWSTR, + ) -> HRESULT, + fn BreakSnapshotSetEx( + SnapshotSetID: VSS_ID, + dwBreakFlags: DWORD, + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn PreFastRecovery( + SnapshotSetID: VSS_ID, + dwPreFastRecoveryFlags: DWORD, + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn FastRecovery( + SnapshotSetID: VSS_ID, + dwFastRecoveryFlags: DWORD, + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xc191bfbc, 0xb602, 0x4675, 0x8b, 0xd1, 0x67, 0xd6, 0x42, 0xf5, 0x29, 0xd5)] +interface IVssBackupComponentsEx3(IVssBackupComponentsEx3Vtbl): + IVssBackupComponentsEx2(IVssBackupComponentsEx2Vtbl) { + fn GetWriterStatusEx( + iWriter: UINT, + pidInstance: *mut VSS_ID, + pidWriter: *mut VSS_ID, + pbstrWriter: *mut BSTR, + pnStatus: *mut VSS_WRITER_STATE, + phrFailureWriter: *mut HRESULT, + phrApplication: *mut HRESULT, + pbstrApplicationMessage: *mut BSTR, + ) -> HRESULT, + fn AddSnapshotToRecoverySet( + snapshotId: VSS_ID, + dwFlags: DWORD, + pwszDestinationVolume: VSS_PWSZ, + ) -> HRESULT, + fn RecoverSet( + dwFlags: DWORD, + ppAsync: *mut *mut IVssAsync, + ) -> HRESULT, + fn GetSessionId( + idSession: *mut VSS_ID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf434c2fd, 0xb553, 0x4961, 0xa9, 0xf9, 0xa8, 0xe9, 0x0b, 0x67, 0x3e, 0x53)] +interface IVssBackupComponentsEx4(IVssBackupComponentsEx4Vtbl): + IVssBackupComponentsEx3(IVssBackupComponentsEx3Vtbl) { + fn GetRootAndLogicalPrefixPaths( + pwszFilePath: VSS_PWSZ, + ppwszRootPath: *mut VSS_PWSZ, + ppwszLogicalPrefix: *mut VSS_PWSZ, + bNormalizeFQDNforRootPath: BOOL, + ) -> HRESULT, +}} +pub const VSS_SW_BOOTABLE_STATE: DWORD = 1; +extern "system" { + #[link_name="CreateVssBackupComponentsInternal"] + pub fn CreateVssBackupComponents( + ppBackup: *mut *mut IVssBackupComponents, + ) -> HRESULT; + #[link_name="CreateVssExamineWriterMetadataInternal"] + pub fn CreateVssExamineWriterMetadata( + bstrXML: BSTR, + ppMetadata: *mut *mut IVssExamineWriterMetadata, + ) -> HRESULT; + #[link_name="IsVolumeSnapshottedInternal"] + pub fn IsVolumeSnapshotted( + pwszVolumeName: VSS_PWSZ, + pbSnapshotsPresent: *mut BOOL, + plSnapshotCapability: *mut LONG, + ) -> HRESULT; + #[link_name="VssFreeSnapshotPropertiesInternal"] + pub fn VssFreeSnapshotProperties( + pProp: *mut VSS_SNAPSHOT_PROP, + ); + #[link_name="GetProviderMgmtInterfaceInternal"] + pub fn GetProviderMgmtInterface( + ProviderId: VSS_ID, + InterfaceId: IID, + ppItf: *mut *mut IUnknown, + ) -> HRESULT; + #[link_name="ShouldBlockRevertInternal"] + pub fn ShouldBlockRevert( + wszVolumeName: LPCWSTR, + pbBlock: *mut bool, + ) -> HRESULT; +} diff --git a/winapi/src/um/vss.rs b/winapi/src/um/vss.rs new file mode 100644 index 000000000..7038f0376 --- /dev/null +++ b/winapi/src/um/vss.rs @@ -0,0 +1,284 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! VSS header file +use shared::guiddef::{CLSID, GUID}; +use shared::minwindef::{DWORD, INT, ULONG}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HRESULT, LONG, LONGLONG, WCHAR}; +ENUM!{enum VSS_OBJECT_TYPE { + VSS_OBJECT_UNKNOWN = 0, + VSS_OBJECT_NONE = 1, + VSS_OBJECT_SNAPSHOT_SET = 2, + VSS_OBJECT_SNAPSHOT = 3, + VSS_OBJECT_PROVIDER = 4, + VSS_OBJECT_TYPE_COUNT = 5, +}} +pub type PVSS_OBJECT_TYPE = *mut VSS_OBJECT_TYPE; +ENUM!{enum VSS_SNAPSHOT_STATE { + VSS_SS_UNKNOWN = 0x00, + VSS_SS_PREPARING = 0x01, + VSS_SS_PROCESSING_PREPARE = 0x02, + VSS_SS_PREPARED = 0x03, + VSS_SS_PROCESSING_PRECOMMIT = 0x04, + VSS_SS_PRECOMMITTED = 0x05, + VSS_SS_PROCESSING_COMMIT = 0x06, + VSS_SS_COMMITTED = 0x07, + VSS_SS_PROCESSING_POSTCOMMIT = 0x08, + VSS_SS_PROCESSING_PREFINALCOMMIT = 0x09, + VSS_SS_PREFINALCOMMITTED = 0x0a, + VSS_SS_PROCESSING_POSTFINALCOMMIT = 0x0b, + VSS_SS_CREATED = 0x0c, + VSS_SS_ABORTED = 0x0d, + VSS_SS_DELETED = 0x0e, + VSS_SS_POSTCOMMITTED = 0x0f, + VSS_SS_COUNT = 0x10, +}} +pub type PVSS_SNAPSHOT_STATE = *mut VSS_SNAPSHOT_STATE; +ENUM!{enum VSS_VOLUME_SNAPSHOT_ATTRIBUTES { + VSS_VOLSNAP_ATTR_PERSISTENT = 0x00000001, + VSS_VOLSNAP_ATTR_NO_AUTORECOVERY = 0x00000002, + VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE = 0x00000004, + VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE = 0x00000008, + VSS_VOLSNAP_ATTR_NO_WRITERS = 0x00000010, + VSS_VOLSNAP_ATTR_TRANSPORTABLE = 0x00000020, + VSS_VOLSNAP_ATTR_NOT_SURFACED = 0x00000040, + VSS_VOLSNAP_ATTR_NOT_TRANSACTED = 0x00000080, + VSS_VOLSNAP_ATTR_HARDWARE_ASSISTED = 0x00010000, + VSS_VOLSNAP_ATTR_DIFFERENTIAL = 0x00020000, + VSS_VOLSNAP_ATTR_PLEX = 0x00040000, + VSS_VOLSNAP_ATTR_IMPORTED = 0x00080000, + VSS_VOLSNAP_ATTR_EXPOSED_LOCALLY = 0x00100000, + VSS_VOLSNAP_ATTR_EXPOSED_REMOTELY = 0x00200000, + VSS_VOLSNAP_ATTR_AUTORECOVER = 0x00400000, + VSS_VOLSNAP_ATTR_ROLLBACK_RECOVERY = 0x00800000, + VSS_VOLSNAP_ATTR_DELAYED_POSTSNAPSHOT = 0x01000000, + VSS_VOLSNAP_ATTR_TXF_RECOVERY = 0x02000000, + VSS_VOLSNAP_ATTR_FILE_SHARE = 0x04000000, +}} +pub type PVSS_VOLUME_SNAPSHOT_ATTRIBUTES = *mut VSS_VOLUME_SNAPSHOT_ATTRIBUTES; +ENUM!{enum VSS_SNAPSHOT_CONTEXT { + VSS_CTX_BACKUP = 0, + VSS_CTX_FILE_SHARE_BACKUP = VSS_VOLSNAP_ATTR_NO_WRITERS, + VSS_CTX_NAS_ROLLBACK = VSS_VOLSNAP_ATTR_PERSISTENT + | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE | VSS_VOLSNAP_ATTR_NO_WRITERS, + VSS_CTX_APP_ROLLBACK = VSS_VOLSNAP_ATTR_PERSISTENT + | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE, + VSS_CTX_CLIENT_ACCESSIBLE = VSS_VOLSNAP_ATTR_PERSISTENT + | VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE + | VSS_VOLSNAP_ATTR_NO_WRITERS, + VSS_CTX_CLIENT_ACCESSIBLE_WRITERS = VSS_VOLSNAP_ATTR_PERSISTENT + | VSS_VOLSNAP_ATTR_CLIENT_ACCESSIBLE | VSS_VOLSNAP_ATTR_NO_AUTO_RELEASE, + VSS_CTX_ALL = 0xffffffff, +}} +pub type PVSS_SNAPSHOT_CONTEXT = *mut VSS_SNAPSHOT_CONTEXT; +ENUM!{enum VSS_PROVIDER_CAPABILITIES { + VSS_PRV_CAPABILITY_LEGACY = 0x1, + VSS_PRV_CAPABILITY_COMPLIANT = 0x2, + VSS_PRV_CAPABILITY_LUN_REPOINT = 0x4, + VSS_PRV_CAPABILITY_LUN_RESYNC = 0x8, + VSS_PRV_CAPABILITY_OFFLINE_CREATION = 0x10, + VSS_PRV_CAPABILITY_MULTIPLE_IMPORT = 0x20, + VSS_PRV_CAPABILITY_RECYCLING = 0x40, + VSS_PRV_CAPABILITY_PLEX = 0x80, + VSS_PRV_CAPABILITY_DIFFERENTIAL = 0x100, + VSS_PRV_CAPABILITY_CLUSTERED = 0x200, +}} +pub type PVSS_PROVIDER_CAPABILITIES = *mut VSS_PROVIDER_CAPABILITIES; +ENUM!{enum VSS_HARDWARE_OPTIONS { + VSS_BREAKEX_FLAG_MASK_LUNS = 0x1, + VSS_BREAKEX_FLAG_MAKE_READ_WRITE = 0x2, + VSS_BREAKEX_FLAG_REVERT_IDENTITY_ALL = 0x4, + VSS_BREAKEX_FLAG_REVERT_IDENTITY_NONE = 0x8, + VSS_ONLUNSTATECHANGE_NOTIFY_READ_WRITE = 0x100, + VSS_ONLUNSTATECHANGE_NOTIFY_LUN_PRE_RECOVERY = 0x200, + VSS_ONLUNSTATECHANGE_NOTIFY_LUN_POST_RECOVERY = 0x400, + VSS_ONLUNSTATECHANGE_DO_MASK_LUNS = 0x800, +}} +pub type PVSS_HARDWARE_OPTIONS = *mut VSS_HARDWARE_OPTIONS; +ENUM!{enum VSS_RECOVERY_OPTIONS { + VSS_RECOVERY_REVERT_IDENTITY_ALL = 0x00000100, + VSS_RECOVERY_NO_VOLUME_CHECK = 0x00000200, +}} +pub type PVSS_RECOVERY_OPTIONS = *mut VSS_RECOVERY_OPTIONS; +ENUM!{enum VSS_WRITER_STATE { + VSS_WS_UNKNOWN = 0, + VSS_WS_STABLE = 1, + VSS_WS_WAITING_FOR_FREEZE = 2, + VSS_WS_WAITING_FOR_THAW = 3, + VSS_WS_WAITING_FOR_POST_SNAPSHOT = 4, + VSS_WS_WAITING_FOR_BACKUP_COMPLETE = 5, + VSS_WS_FAILED_AT_IDENTIFY = 6, + VSS_WS_FAILED_AT_PREPARE_BACKUP = 7, + VSS_WS_FAILED_AT_PREPARE_SNAPSHOT = 8, + VSS_WS_FAILED_AT_FREEZE = 9, + VSS_WS_FAILED_AT_THAW = 10, + VSS_WS_FAILED_AT_POST_SNAPSHOT = 11, + VSS_WS_FAILED_AT_BACKUP_COMPLETE = 12, + VSS_WS_FAILED_AT_PRE_RESTORE = 13, + VSS_WS_FAILED_AT_POST_RESTORE = 14, + VSS_WS_FAILED_AT_BACKUPSHUTDOWN = 15, + VSS_WS_COUNT = 16, +}} +pub type PVSS_WRITER_STATE = *mut VSS_WRITER_STATE; +ENUM!{enum VSS_BACKUP_TYPE { + VSS_BT_UNDEFINED = 0, + VSS_BT_FULL = 1, + VSS_BT_INCREMENTAL = 2, + VSS_BT_DIFFERENTIAL = 3, + VSS_BT_LOG = 4, + VSS_BT_COPY = 5, + VSS_BT_OTHER = 6, +}} +pub type PVSS_BACKUP_TYPE = *mut VSS_BACKUP_TYPE; +ENUM!{enum VSS_RESTORE_TYPE { + VSS_RTYPE_UNDEFINED = 0, + VSS_RTYPE_BY_COPY = 1, + VSS_RTYPE_IMPORT = 2, + VSS_RTYPE_OTHER = 3, +}} +pub type PVSS_RESTORE_TYPE = *mut VSS_RESTORE_TYPE; +ENUM!{enum VSS_ROLLFORWARD_TYPE { + VSS_RF_UNDEFINED = 0, + VSS_RF_NONE = 1, + VSS_RF_ALL = 2, + VSS_RF_PARTIAL = 3, +}} +pub type PVSS_ROLLFORWARD_TYPE = *mut VSS_ROLLFORWARD_TYPE; +ENUM!{enum VSS_PROVIDER_TYPE { + VSS_PROV_UNKNOWN = 0, + VSS_PROV_SYSTEM = 1, + VSS_PROV_SOFTWARE = 2, + VSS_PROV_HARDWARE = 3, + VSS_PROV_FILESHARE = 4, +}} +pub type PVSS_PROVIDER_TYPE = *mut VSS_PROVIDER_TYPE; +ENUM!{enum VSS_APPLICATION_LEVEL { + VSS_APP_UNKNOWN = 0, + VSS_APP_SYSTEM = 1, + VSS_APP_BACK_END = 2, + VSS_APP_FRONT_END = 3, + VSS_APP_SYSTEM_RM = 4, + VSS_APP_AUTO = -1i32 as u32, +}} +pub type PVSS_APPLICATION_LEVEL = *mut VSS_APPLICATION_LEVEL; +ENUM!{enum _VSS_SNAPSHOT_COMPATIBILITY { + VSS_SC_DISABLE_DEFRAG = 0x1, + VSS_SC_DISABLE_CONTENTINDEX = 0x2, +}} +ENUM!{enum VSS_SNAPSHOT_PROPERTY_ID { + VSS_SPROPID_UNKNOWN = 0, + VSS_SPROPID_SNAPSHOT_ID = 0x1, + VSS_SPROPID_SNAPSHOT_SET_ID = 0x2, + VSS_SPROPID_SNAPSHOTS_COUNT = 0x3, + VSS_SPROPID_SNAPSHOT_DEVICE = 0x4, + VSS_SPROPID_ORIGINAL_VOLUME = 0x5, + VSS_SPROPID_ORIGINATING_MACHINE = 0x6, + VSS_SPROPID_SERVICE_MACHINE = 0x7, + VSS_SPROPID_EXPOSED_NAME = 0x8, + VSS_SPROPID_EXPOSED_PATH = 0x9, + VSS_SPROPID_PROVIDER_ID = 0xa, + VSS_SPROPID_SNAPSHOT_ATTRIBUTES = 0xb, + VSS_SPROPID_CREATION_TIMESTAMP = 0xc, + VSS_SPROPID_STATUS = 0xd, +}} +pub type PVSS_SNAPSHOT_PROPERTY_ID = *mut VSS_SNAPSHOT_PROPERTY_ID; +ENUM!{enum VSS_FILE_SPEC_BACKUP_TYPE { + VSS_FSBT_FULL_BACKUP_REQUIRED = 0x1, + VSS_FSBT_DIFFERENTIAL_BACKUP_REQUIRED = 0x2, + VSS_FSBT_INCREMENTAL_BACKUP_REQUIRED = 0x4, + VSS_FSBT_LOG_BACKUP_REQUIRED = 0x8, + VSS_FSBT_FULL_SNAPSHOT_REQUIRED = 0x100, + VSS_FSBT_DIFFERENTIAL_SNAPSHOT_REQUIRED = 0x200, + VSS_FSBT_INCREMENTAL_SNAPSHOT_REQUIRED = 0x400, + VSS_FSBT_LOG_SNAPSHOT_REQUIRED = 0x800, + VSS_FSBT_CREATED_DURING_BACKUP = 0x10000, + VSS_FSBT_ALL_BACKUP_REQUIRED = 0xf, + VSS_FSBT_ALL_SNAPSHOT_REQUIRED = 0xf00, +}} +pub type PVSS_FILE_SPEC_BACKUP_TYPE = *mut VSS_FILE_SPEC_BACKUP_TYPE; +ENUM!{enum VSS_BACKUP_SCHEMA { + VSS_BS_UNDEFINED = 0, + VSS_BS_DIFFERENTIAL = 0x1, + VSS_BS_INCREMENTAL = 0x2, + VSS_BS_EXCLUSIVE_INCREMENTAL_DIFFERENTIAL = 0x4, + VSS_BS_LOG = 0x8, + VSS_BS_COPY = 0x10, + VSS_BS_TIMESTAMPED = 0x20, + VSS_BS_LAST_MODIFY = 0x40, + VSS_BS_LSN = 0x80, + VSS_BS_WRITER_SUPPORTS_NEW_TARGET = 0x100, + VSS_BS_WRITER_SUPPORTS_RESTORE_WITH_MOVE = 0x200, + VSS_BS_INDEPENDENT_SYSTEM_STATE = 0x400, + VSS_BS_ROLLFORWARD_RESTORE = 0x1000, + VSS_BS_RESTORE_RENAME = 0x2000, + VSS_BS_AUTHORITATIVE_RESTORE = 0x4000, + VSS_BS_WRITER_SUPPORTS_PARALLEL_RESTORES = 0x8000, +}} +pub type PVSS_BACKUP_SCHEMA = *mut VSS_BACKUP_SCHEMA; +pub type VSS_ID = GUID; +pub type VSS_PWSZ = *mut WCHAR; +pub type VSS_TIMESTAMP = LONGLONG; +STRUCT!{struct VSS_SNAPSHOT_PROP { + m_SnapshotId: VSS_ID, + m_SnapshotSetId: VSS_ID, + m_lSnapshotsCount: LONG, + m_pwszSnapshotDeviceObject: VSS_PWSZ, + m_pwszOriginalVolumeName: VSS_PWSZ, + m_pwszOriginatingMachine: VSS_PWSZ, + m_pwszServiceMachine: VSS_PWSZ, + m_pwszExposedName: VSS_PWSZ, + m_pwszExposedPath: VSS_PWSZ, + m_ProviderId: VSS_ID, + m_lSnapshotAttributes: LONG, + m_tsCreationTimestamp: VSS_TIMESTAMP, + m_eStatus: VSS_SNAPSHOT_STATE, +}} +pub type PVSS_SNAPSHOT_PROP = *mut VSS_SNAPSHOT_PROP; +STRUCT!{struct VSS_PROVIDER_PROP { + m_ProviderId: VSS_ID, + m_pwszProviderName: VSS_PWSZ, + m_eProviderType: VSS_PROVIDER_TYPE, + m_pwszProviderVersion: VSS_PWSZ, + m_ProviderVersionId: VSS_ID, + m_ClassId: CLSID, +}} +pub type PVSS_PROVIDER_PROP = *mut VSS_PROVIDER_PROP; +UNION!{union VSS_OBJECT_UNION { + [u64; 12] [u64; 16], + Snap Snap_mut: VSS_SNAPSHOT_PROP, + Prov Prov_mut: VSS_PROVIDER_PROP, +}} +STRUCT!{struct VSS_OBJECT_PROP { + Type: VSS_OBJECT_TYPE, + Obj: VSS_OBJECT_UNION, +}} +pub type PVSS_OBJECT_PROP = *mut VSS_OBJECT_PROP; +RIDL!{#[uuid(0xae1c7110, 0x2f60, 0x11d3, 0x8a, 0x39, 0x00, 0xc0, 0x4f, 0x72, 0xd8, 0xe3)] +interface IVssEnumObject(IVssEnumObjectVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut VSS_OBJECT_PROP, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IVssEnumObject, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x507c37b4, 0xcf5b, 0x4e95, 0xb0, 0xaf, 0x14, 0xeb, 0x97, 0x67, 0x46, 0x7e)] +interface IVssAsync(IVssAsyncVtbl): IUnknown(IUnknownVtbl) { + fn Cancel() -> HRESULT, + fn Wait( + dwMilliseconds: DWORD, + ) -> HRESULT, + fn QueryStatus( + pHrResult: *mut HRESULT, + pReserved: *mut INT, + ) -> HRESULT, +}} diff --git a/winapi/src/um/vsserror.rs b/winapi/src/um/vsserror.rs new file mode 100644 index 000000000..1a295509d --- /dev/null +++ b/winapi/src/um/vsserror.rs @@ -0,0 +1,89 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! VSS Error header file +use um::winnt::HRESULT; +pub const VSS_E_BAD_STATE: HRESULT = 0x80042301; +pub const VSS_E_UNEXPECTED: HRESULT = 0x80042302; +pub const VSS_E_PROVIDER_ALREADY_REGISTERED: HRESULT = 0x80042303; +pub const VSS_E_PROVIDER_NOT_REGISTERED: HRESULT = 0x80042304; +pub const VSS_E_PROVIDER_VETO: HRESULT = 0x80042306; +pub const VSS_E_PROVIDER_IN_USE: HRESULT = 0x80042307; +pub const VSS_E_OBJECT_NOT_FOUND: HRESULT = 0x80042308; +pub const VSS_S_ASYNC_PENDING: HRESULT = 0x00042309; +pub const VSS_S_ASYNC_FINISHED: HRESULT = 0x0004230A; +pub const VSS_S_ASYNC_CANCELLED: HRESULT = 0x0004230B; +pub const VSS_E_VOLUME_NOT_SUPPORTED: HRESULT = 0x8004230C; +pub const VSS_E_VOLUME_NOT_SUPPORTED_BY_PROVIDER: HRESULT = 0x8004230E; +pub const VSS_E_OBJECT_ALREADY_EXISTS: HRESULT = 0x8004230D; +pub const VSS_E_UNEXPECTED_PROVIDER_ERROR: HRESULT = 0x8004230F; +pub const VSS_E_CORRUPT_XML_DOCUMENT: HRESULT = 0x80042310; +pub const VSS_E_INVALID_XML_DOCUMENT: HRESULT = 0x80042311; +pub const VSS_E_MAXIMUM_NUMBER_OF_VOLUMES_REACHED: HRESULT = 0x80042312; +pub const VSS_E_FLUSH_WRITES_TIMEOUT: HRESULT = 0x80042313; +pub const VSS_E_HOLD_WRITES_TIMEOUT: HRESULT = 0x80042314; +pub const VSS_E_UNEXPECTED_WRITER_ERROR: HRESULT = 0x80042315; +pub const VSS_E_SNAPSHOT_SET_IN_PROGRESS: HRESULT = 0x80042316; +pub const VSS_E_MAXIMUM_NUMBER_OF_SNAPSHOTS_REACHED: HRESULT = 0x80042317; +pub const VSS_E_WRITER_INFRASTRUCTURE: HRESULT = 0x80042318; +pub const VSS_E_WRITER_NOT_RESPONDING: HRESULT = 0x80042319; +pub const VSS_E_WRITER_ALREADY_SUBSCRIBED: HRESULT = 0x8004231A; +pub const VSS_E_UNSUPPORTED_CONTEXT: HRESULT = 0x8004231B; +pub const VSS_E_VOLUME_IN_USE: HRESULT = 0x8004231D; +pub const VSS_E_MAXIMUM_DIFFAREA_ASSOCIATIONS_REACHED: HRESULT = 0x8004231E; +pub const VSS_E_INSUFFICIENT_STORAGE: HRESULT = 0x8004231F; +pub const VSS_E_NO_SNAPSHOTS_IMPORTED: HRESULT = 0x80042320; +pub const VSS_S_SOME_SNAPSHOTS_NOT_IMPORTED: HRESULT = 0x00042321; +pub const VSS_E_SOME_SNAPSHOTS_NOT_IMPORTED: HRESULT = 0x80042321; +pub const VSS_E_MAXIMUM_NUMBER_OF_REMOTE_MACHINES_REACHED: HRESULT = 0x80042322; +pub const VSS_E_REMOTE_SERVER_UNAVAILABLE: HRESULT = 0x80042323; +pub const VSS_E_REMOTE_SERVER_UNSUPPORTED: HRESULT = 0x80042324; +pub const VSS_E_REVERT_IN_PROGRESS: HRESULT = 0x80042325; +pub const VSS_E_REVERT_VOLUME_LOST: HRESULT = 0x80042326; +pub const VSS_E_REBOOT_REQUIRED: HRESULT = 0x80042327; +pub const VSS_E_TRANSACTION_FREEZE_TIMEOUT: HRESULT = 0x80042328; +pub const VSS_E_TRANSACTION_THAW_TIMEOUT: HRESULT = 0x80042329; +pub const VSS_E_VOLUME_NOT_LOCAL: HRESULT = 0x8004232D; +pub const VSS_E_CLUSTER_TIMEOUT: HRESULT = 0x8004232E; +pub const VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT: HRESULT = 0x800423F0; +pub const VSS_E_WRITERERROR_OUTOFRESOURCES: HRESULT = 0x800423F1; +pub const VSS_E_WRITERERROR_TIMEOUT: HRESULT = 0x800423F2; +pub const VSS_E_WRITERERROR_RETRYABLE: HRESULT = 0x800423F3; +pub const VSS_E_WRITERERROR_NONRETRYABLE: HRESULT = 0x800423F4; +pub const VSS_E_WRITERERROR_RECOVERY_FAILED: HRESULT = 0x800423F5; +pub const VSS_E_BREAK_REVERT_ID_FAILED: HRESULT = 0x800423F6; +pub const VSS_E_LEGACY_PROVIDER: HRESULT = 0x800423F7; +pub const VSS_E_MISSING_DISK: HRESULT = 0x800423F8; +pub const VSS_E_MISSING_HIDDEN_VOLUME: HRESULT = 0x800423F9; +pub const VSS_E_MISSING_VOLUME: HRESULT = 0x800423FA; +pub const VSS_E_AUTORECOVERY_FAILED: HRESULT = 0x800423FB; +pub const VSS_E_DYNAMIC_DISK_ERROR: HRESULT = 0x800423FC; +pub const VSS_E_NONTRANSPORTABLE_BCD: HRESULT = 0x800423FD; +pub const VSS_E_CANNOT_REVERT_DISKID: HRESULT = 0x800423FE; +pub const VSS_E_RESYNC_IN_PROGRESS: HRESULT = 0x800423FF; +pub const VSS_E_CLUSTER_ERROR: HRESULT = 0x80042400; +pub const VSS_E_UNSELECTED_VOLUME: HRESULT = 0x8004232A; +pub const VSS_E_SNAPSHOT_NOT_IN_SET: HRESULT = 0x8004232B; +pub const VSS_E_NESTED_VOLUME_LIMIT: HRESULT = 0x8004232C; +pub const VSS_E_NOT_SUPPORTED: HRESULT = 0x8004232F; +pub const VSS_E_WRITERERROR_PARTIAL_FAILURE: HRESULT = 0x80042336; +pub const VSS_E_ASRERROR_DISK_ASSIGNMENT_FAILED: HRESULT = 0x80042401; +pub const VSS_E_ASRERROR_DISK_RECREATION_FAILED: HRESULT = 0x80042402; +pub const VSS_E_ASRERROR_NO_ARCPATH: HRESULT = 0x80042403; +pub const VSS_E_ASRERROR_MISSING_DYNDISK: HRESULT = 0x80042404; +pub const VSS_E_ASRERROR_SHARED_CRIDISK: HRESULT = 0x80042405; +pub const VSS_E_ASRERROR_DATADISK_RDISK0: HRESULT = 0x80042406; +pub const VSS_E_ASRERROR_RDISK0_TOOSMALL: HRESULT = 0x80042407; +pub const VSS_E_ASRERROR_CRITICAL_DISKS_TOO_SMALL: HRESULT = 0x80042408; +pub const VSS_E_WRITER_STATUS_NOT_AVAILABLE: HRESULT = 0x80042409; +pub const VSS_E_ASRERROR_DYNAMIC_VHD_NOT_SUPPORTED: HRESULT = 0x8004240A; +pub const VSS_E_CRITICAL_VOLUME_ON_INVALID_DISK: HRESULT = 0x80042411; +pub const VSS_E_ASRERROR_RDISK_FOR_SYSTEM_DISK_NOT_FOUND: HRESULT = 0x80042412; +pub const VSS_E_ASRERROR_NO_PHYSICAL_DISK_AVAILABLE: HRESULT = 0x80042413; +pub const VSS_E_ASRERROR_FIXED_PHYSICAL_DISK_AVAILABLE_AFTER_DISK_EXCLUSION: HRESULT = + 0x80042414; +pub const VSS_E_ASRERROR_CRITICAL_DISK_CANNOT_BE_EXCLUDED: HRESULT = 0x80042415; +pub const VSS_E_ASRERROR_SYSTEM_PARTITION_HIDDEN: HRESULT = 0x80042416; +pub const VSS_E_FSS_TIMEOUT: HRESULT = 0x80042417; diff --git a/winapi/src/um/vswriter.rs b/winapi/src/um/vswriter.rs new file mode 100644 index 000000000..43d6000ec --- /dev/null +++ b/winapi/src/um/vswriter.rs @@ -0,0 +1,397 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Declaration of Writer +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, UINT}; +use shared::wtypes::BSTR; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::vss::{VSS_ID, VSS_ROLLFORWARD_TYPE}; +use um::winnt::{HRESULT, LPCWSTR, VOID}; +ENUM!{enum VSS_USAGE_TYPE { + VSS_UT_UNDEFINED = 0, + VSS_UT_BOOTABLESYSTEMSTATE = 1, + VSS_UT_SYSTEMSERVICE = 2, + VSS_UT_USERDATA = 3, + VSS_UT_OTHER = 4, +}} +ENUM!{enum VSS_SOURCE_TYPE { + VSS_ST_UNDEFINED = 0, + VSS_ST_TRANSACTEDDB = 1, + VSS_ST_NONTRANSACTEDDB = 2, + VSS_ST_OTHER = 3, +}} +ENUM!{enum VSS_RESTOREMETHOD_ENUM { + VSS_RME_UNDEFINED = 0, + VSS_RME_RESTORE_IF_NOT_THERE = 1, + VSS_RME_RESTORE_IF_CAN_REPLACE = 2, + VSS_RME_STOP_RESTORE_START = 3, + VSS_RME_RESTORE_TO_ALTERNATE_LOCATION = 4, + VSS_RME_RESTORE_AT_REBOOT = 5, + VSS_RME_RESTORE_AT_REBOOT_IF_CANNOT_REPLACE = 6, + VSS_RME_CUSTOM = 7, + VSS_RME_RESTORE_STOP_START = 8, +}} +ENUM!{enum VSS_WRITERRESTORE_ENUM { + VSS_WRE_UNDEFINED = 0, + VSS_WRE_NEVER = 1, + VSS_WRE_IF_REPLACE_FAILS = 2, + VSS_WRE_ALWAYS = 3, +}} +ENUM!{enum VSS_COMPONENT_TYPE { + VSS_CT_UNDEFINED = 0, + VSS_CT_DATABASE = 1, + VSS_CT_FILEGROUP = 2, +}} +ENUM!{enum VSS_ALTERNATE_WRITER_STATE { + VSS_AWS_UNDEFINED = 0, + VSS_AWS_NO_ALTERNATE_WRITER = 1, + VSS_AWS_ALTERNATE_WRITER_EXISTS = 2, + VSS_AWS_THIS_IS_ALTERNATE_WRITER = 3, +}} +ENUM!{enum VSS_SUBSCRIBE_MASK { + VSS_SM_POST_SNAPSHOT_FLAG = 0x00000001, + VSS_SM_BACKUP_EVENTS_FLAG = 0x00000002, + VSS_SM_RESTORE_EVENTS_FLAG = 0x00000004, + VSS_SM_IO_THROTTLING_FLAG = 0x00000008, + VSS_SM_ALL_FLAGS = 0xffffffff, +}} +ENUM!{enum VSS_RESTORE_TARGET { + VSS_RT_UNDEFINED = 0, + VSS_RT_ORIGINAL = 1, + VSS_RT_ALTERNATE = 2, + VSS_RT_DIRECTED = 3, + VSS_RT_ORIGINAL_LOCATION = 4, +}} +ENUM!{enum VSS_FILE_RESTORE_STATUS { + VSS_RS_UNDEFINED = 0, + VSS_RS_NONE = 1, + VSS_RS_ALL = 2, + VSS_RS_FAILED = 3, +}} +ENUM!{enum VSS_COMPONENT_FLAGS { + VSS_CF_BACKUP_RECOVERY = 0x00000001, + VSS_CF_APP_ROLLBACK_RECOVERY = 0x00000002, + VSS_CF_NOT_SYSTEM_STATE = 0x00000004, +}} +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface IVssWMFiledesc(IVssWMFiledescVtbl): IUnknown(IUnknownVtbl) { + fn GetPath( + pbstrPath: *mut BSTR, + ) -> HRESULT, + fn GetFilespec( + pbstrFilespec: *mut BSTR, + ) -> HRESULT, + fn GetRecursive( + pbRecursive: *mut bool, + ) -> HRESULT, + fn GetAlternateLocation( + pbstrAlternateLocation: *mut BSTR, + ) -> HRESULT, + fn GetBackupTypeMask( + pdwTypeMask: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface IVssWMDependency(IVssWMDependencyVtbl): IUnknown(IUnknownVtbl) { + fn GetWriterId( + pWriterId: *mut VSS_ID, + ) -> HRESULT, + fn GetLogicalPath( + pbstrLogicalPath: *mut BSTR, + ) -> HRESULT, + fn GetComponentName( + pbstrComponentName: *mut BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd2c72c96, 0xc121, 0x4518, 0xb6, 0x27, 0xe5, 0xa9, 0x3d, 0x01, 0x0e, 0xad)] +interface IVssComponent(IVssComponentVtbl): IUnknown(IUnknownVtbl) { + fn GetLogicalPath( + pbstrPath: *mut BSTR, + ) -> HRESULT, + fn GetComponentType( + pct: *mut VSS_COMPONENT_TYPE, + ) -> HRESULT, + fn GetComponentName( + pbstrName: *mut BSTR, + ) -> HRESULT, + fn GetBackupSucceeded( + pbSucceeded: *mut bool, + ) -> HRESULT, + fn GetAlternateLocationMappingCount( + pcMappings: *mut UINT, + ) -> HRESULT, + fn GetAlternateLocationMapping( + iMapping: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn SetBackupMetadata( + wszData: LPCWSTR, + ) -> HRESULT, + fn GetBackupMetadata( + pbstrData: *mut BSTR, + ) -> HRESULT, + fn AddPartialFile( + wszPath: LPCWSTR, + wszFilename: LPCWSTR, + wszRanges: LPCWSTR, + wszMetadata: LPCWSTR, + ) -> HRESULT, + fn GetPartialFileCount( + pcPartialFiles: *mut UINT, + ) -> HRESULT, + fn GetPartialFile( + iPartialFile: UINT, + pbstrPath: *mut BSTR, + pbstrFilename: *mut BSTR, + pbstrRange: *mut BSTR, + pbstrMetadata: *mut BSTR, + ) -> HRESULT, + fn IsSelectedForRestore( + pbSelectedForRestore: *mut bool, + ) -> HRESULT, + fn GetAdditionalRestores( + pbAdditionalRestores: *mut bool, + ) -> HRESULT, + fn GetNewTargetCount( + pcNewTarget: *mut UINT, + ) -> HRESULT, + fn GetNewTarget( + iNewTarget: UINT, + ppFiledesc: *mut *mut IVssWMFiledesc, + ) -> HRESULT, + fn AddDirectedTarget( + wszSourcePath: LPCWSTR, + wszSourceFilename: LPCWSTR, + wszSourceRangeList: LPCWSTR, + wszDestinationPath: LPCWSTR, + wszDestinationFilename: LPCWSTR, + wszDestinationRangeList: LPCWSTR, + ) -> HRESULT, + fn GetDirectedTargetCount( + pcDirectedTarget: *mut UINT, + ) -> HRESULT, + fn GetDirectedTarget( + iDirectedTarget: UINT, + pbstrSourcePath: *mut BSTR, + pbstrSourceFileName: *mut BSTR, + pbstrSourceRangeList: *mut BSTR, + pbstrDestinationPath: *mut BSTR, + pbstrDestinationFilename: *mut BSTR, + pbstrDestinationRangeList: *mut BSTR, + ) -> HRESULT, + fn SetRestoreMetadata( + wszRestoreMetadata: LPCWSTR, + ) -> HRESULT, + fn GetRestoreMetadata( + pbstrRestoreMetadata: *mut BSTR, + ) -> HRESULT, + fn SetRestoreTarget( + target: VSS_RESTORE_TARGET, + ) -> HRESULT, + fn GetRestoreTarget( + pTarget: *mut VSS_RESTORE_TARGET, + ) -> HRESULT, + fn SetPreRestoreFailureMsg( + wszPreRestoreFailureMsg: LPCWSTR, + ) -> HRESULT, + fn GetPreRestoreFailureMsg( + pbstrPreRestoreFailureMsg: *mut BSTR, + ) -> HRESULT, + fn SetPostRestoreFailureMsg( + wszPostRestoreFailureMsg: LPCWSTR, + ) -> HRESULT, + fn GetPostRestoreFailureMsg( + pbstrPostRestoreFailureMsg: *mut BSTR, + ) -> HRESULT, + fn SetBackupStamp( + wszBackupStamp: LPCWSTR, + ) -> HRESULT, + fn GetBackupStamp( + pbstrBackupStamp: *mut BSTR, + ) -> HRESULT, + fn GetPreviousBackupStamp( + pbstrBackupStamp: *mut BSTR, + ) -> HRESULT, + fn GetBackupOptions( + pbstrBackupOptions: *mut BSTR, + ) -> HRESULT, + fn GetRestoreOptions( + pbstrRestoreOptions: *mut BSTR, + ) -> HRESULT, + fn GetRestoreSubcomponentCount( + pcRestoreSubcomponent: *mut UINT, + ) -> HRESULT, + fn GetRestoreSubcomponent( + iComponent: UINT, + pbstrLogicalPath: *mut BSTR, + pbstrComponentName: *mut BSTR, + pbRepair: *mut bool, + ) -> HRESULT, + fn GetFileRestoreStatus( + pStatus: *mut VSS_FILE_RESTORE_STATUS, + ) -> HRESULT, + fn AddDifferencedFilesByLastModifyTime( + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: BOOL, + ftLastModifyTime: FILETIME, + ) -> HRESULT, + fn AddDifferencedFilesByLastModifyLSN( + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: BOOL, + bstrLsnString: BSTR, + ) -> HRESULT, + fn GetDifferencedFilesCount( + pcDifferencedFiles: *mut UINT, + ) -> HRESULT, + fn GetDifferencedFile( + iDifferencedFile: UINT, + pbstrPath: *mut BSTR, + pbstrFilespec: *mut BSTR, + pbRecursive: *mut BOOL, + pbstrLsnString: *mut BSTR, + pftLastModifyTime: *mut FILETIME, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface IVssWriterComponents(IVssWriterComponentsVtbl) { + fn GetComponentCount( + pcComponents: *mut UINT, + ) -> HRESULT, + fn GetWriterInfo( + pidInstance: *mut VSS_ID, + pidWriter: *mut VSS_ID, + ) -> HRESULT, + fn GetComponent( + iComponent: UINT, + ppComponent: *mut *mut IVssComponent, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x156c8b5e, 0xf131, 0x4bd7, 0x9c, 0x97, 0xd1, 0x92, 0x3b, 0xe7, 0xe1, 0xfa)] +interface IVssComponentEx(IVssComponentExVtbl): IVssComponent(IVssComponentVtbl) { + fn SetPrepareForBackupFailureMsg( + wszFailureMsg: LPCWSTR, + ) -> HRESULT, + fn SetPostSnapshotFailureMsg( + wszFailureMsg: LPCWSTR, + ) -> HRESULT, + fn GetPrepareForBackupFailureMsg( + pbstrFailureMsg: *mut BSTR, + ) -> HRESULT, + fn GetPostSnapshotFailureMsg( + pbstrFailureMsg: *mut BSTR, + ) -> HRESULT, + fn GetAuthoritativeRestore( + pbAuth: *mut bool, + ) -> HRESULT, + fn GetRollForward( + pRollType: *mut VSS_ROLLFORWARD_TYPE, + pbstrPoint: *mut BSTR, + ) -> HRESULT, + fn GetRestoreName( + pbstrName: *mut BSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b5be0f2, 0x07a9, 0x4e4b, 0xbd, 0xd3, 0xcf, 0xdc, 0x8e, 0x2c, 0x0d, 0x2d)] +interface IVssComponentEx2(IVssComponentEx2Vtbl): IVssComponentEx(IVssComponentExVtbl) { + fn SetFailure( + hr: HRESULT, + hrApplication: HRESULT, + wszApplicationMessage: LPCWSTR, + dwReserved: DWORD, + ) -> HRESULT, + fn GetFailure( + phr: *mut HRESULT, + phrApplication: *mut HRESULT, + pbstrApplicationMessage: *mut BSTR, + pdwReserved: *mut DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)] +interface IVssCreateWriterMetadata(IVssCreateWriterMetadataVtbl) { + fn AddIncludeFiles( + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: bool, + wszAlternateLocation: LPCWSTR, + ) -> HRESULT, + fn AddExcludeFiles( + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: bool, + ) -> HRESULT, + fn AddComponent( + ct: VSS_COMPONENT_TYPE, + wszLogicalPath: LPCWSTR, + wszComponentName: LPCWSTR, + wszCaption: LPCWSTR, + pbIcon: *const BYTE, + cbIcon: UINT, + bRestoreMetadata: bool, + bNotifyOnBackupComplete: bool, + bSelectableForRestore: bool, + dwComponentFlags: DWORD, + ) -> HRESULT, + fn AddDatabaseFiles( + wszLogicalPath: LPCWSTR, + wszDatabaseName: LPCWSTR, + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + dwBackupTypeMask: DWORD, + ) -> HRESULT, + fn AddDatabaseLogFiles( + wszLogicalPath: LPCWSTR, + wszDatabaseName: LPCWSTR, + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + dwBackupTypeMask: DWORD, + ) -> HRESULT, + fn AddFilesToFileGroup( + wszLogicalPath: LPCWSTR, + wszGroupName: LPCWSTR, + wszPath: LPCWSTR, + wszFilespec: LPCWSTR, + bRecursive: bool, + wszAlternateLocation: LPCWSTR, + dwBackupTypeMask: DWORD, + ) -> HRESULT, + fn SetRestoreMethod( + method: VSS_RESTOREMETHOD_ENUM, + wszService: LPCWSTR, + wszUserProcedure: LPCWSTR, + writerRestore: VSS_WRITERRESTORE_ENUM, + bRebootRequired: bool, + ) -> HRESULT, + fn AddAlternateLocationMapping( + wszSourcePath: LPCWSTR, + wszSourceFilespec: LPCWSTR, + bRecursive: bool, + wszDestination: LPCWSTR, + ) -> HRESULT, + fn AddComponentDependency( + wszForLogicalPath: LPCWSTR, + wszForComponentName: LPCWSTR, + onWriterId: VSS_ID, + wszOnLogicalPath: LPCWSTR, + wszOnComponentName: LPCWSTR, + ) -> HRESULT, + fn SetBackupSchema( + dwSchemaMask: DWORD, + ) -> HRESULT, + fn GetDocument( + pDoc: *mut *mut VOID, + ) -> HRESULT, //TODO IXMLDOMDocument, + fn SaveAsXML( + pbstrXML: *mut BSTR, + ) -> HRESULT, +}} +//IVssCreateWriterMetadataEx +//IVssWriterImpl +//IVssCreateExpressWriterMetadata +//IVssExpressWriter +//CVssWriter +//CVssWriterEx +//CVssWriterEx2 diff --git a/winapi/src/um/wbemads.rs b/winapi/src/um/wbemads.rs new file mode 100644 index 000000000..5ba09e6eb --- /dev/null +++ b/winapi/src/um/wbemads.rs @@ -0,0 +1,41 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::winerror::HRESULT; +use shared::wtypes::BSTR; +use um::oaidl::{IDispatch, IDispatchVtbl}; +use um::wbemdisp::{ISWbemObject, ISWbemServices}; +// extern RPC_IF_HANDLE __MIDL_itf_wbemads_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemads_0000_0000_v0_0_s_ifspec; +// EXTERN_C const IID LIBID_WMIEXTENSIONLib; +// EXTERN_C const IID IID_IWMIExtension; +DEFINE_GUID!{IID_IWMIExtension, + 0xadc1f06e, 0x5c7e, 0x11d2, 0x8b, 0x74, 0x00, 0x10, 0x4b, 0x2a, 0xfb, 0x41} +RIDL!{#[uuid(0xadc1f06e, 0x5c7e, 0x11d2, 0x8b, 0x74, 0x00, 0x10, 0x4b, 0x2a, 0xfb, 0x41)] +interface IWMIExtension(IWMIExtensionVtbl): IDispatch(IDispatchVtbl) { + fn get_WMIObjectPath( + strWMIObjectPath: *mut BSTR, + ) -> HRESULT, + fn GetWMIObject( + objWMIObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn GetWMIServices( + objWMIServices: *mut *mut ISWbemServices, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_WMIExtension, + 0xf0975afe, 0x5c7f, 0x11d2, 0x8b, 0x74, 0x00, 0x10, 0x4b, 0x2a, 0xfb, 0x41} +// class DECLSPEC_UUID("f0975afe-5c7f-11d2-8b74-00104b2afb41") +// WMIExtension; +// extern RPC_IF_HANDLE __MIDL_itf_wbemads_0000_0002_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemads_0000_0002_v0_0_s_ifspec; +// unsigned long __RPC_USER BSTR_UserSize( __RPC__in unsigned long *, unsigned long , __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree( __RPC__in unsigned long *, __RPC__in BSTR * ); +// unsigned long __RPC_USER BSTR_UserSize64( __RPC__in unsigned long *, unsigned long , __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal64( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal64(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree64( __RPC__in unsigned long *, __RPC__in BSTR * ); diff --git a/winapi/src/um/wbemcli.rs b/winapi/src/um/wbemcli.rs new file mode 100644 index 000000000..f519b0fa6 --- /dev/null +++ b/winapi/src/um/wbemcli.rs @@ -0,0 +1,1174 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{__uint64, c_long, c_uchar}; +use shared::minwindef::{BYTE, DWORD, ULONG}; +use shared::rpcndr::byte; +use shared::winerror::HRESULT; +use shared::wtypes::BSTR; +use um::oaidl::{SAFEARRAY, VARIANT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{LCID, LONG, LPCWSTR, LPWSTR}; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0000_v0_0_s_ifspec; +ENUM!{enum WBEM_GENUS_TYPE { + WBEM_GENUS_CLASS = 1, + WBEM_GENUS_INSTANCE = 2, +}} +ENUM!{enum WBEM_CHANGE_FLAG_TYPE { + WBEM_FLAG_CREATE_OR_UPDATE = 0, + WBEM_FLAG_UPDATE_ONLY = 0x1, + WBEM_FLAG_CREATE_ONLY = 0x2, + WBEM_FLAG_UPDATE_COMPATIBLE = 0, + WBEM_FLAG_UPDATE_SAFE_MODE = 0x20, + WBEM_FLAG_UPDATE_FORCE_MODE = 0x40, + WBEM_MASK_UPDATE_MODE = 0x60, + WBEM_FLAG_ADVISORY = 0x10000, +}} +ENUM!{enum WBEM_GENERIC_FLAG_TYPE { + WBEM_FLAG_RETURN_IMMEDIATELY = 0x10, + WBEM_FLAG_RETURN_WBEM_COMPLETE = 0, + WBEM_FLAG_BIDIRECTIONAL = 0, + WBEM_FLAG_FORWARD_ONLY = 0x20, + WBEM_FLAG_NO_ERROR_OBJECT = 0x40, + WBEM_FLAG_RETURN_ERROR_OBJECT = 0, + WBEM_FLAG_SEND_STATUS = 0x80, + WBEM_FLAG_DONT_SEND_STATUS = 0, + WBEM_FLAG_ENSURE_LOCATABLE = 0x100, + WBEM_FLAG_DIRECT_READ = 0x200, + WBEM_FLAG_SEND_ONLY_SELECTED = 0, + WBEM_RETURN_WHEN_COMPLETE = 0, + WBEM_RETURN_IMMEDIATELY = 0x10, + WBEM_MASK_RESERVED_FLAGS = 0x1f000, + WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x20000, + WBEM_FLAG_STRONG_VALIDATION = 0x100000, +}} +ENUM!{enum WBEM_STATUS_TYPE { + WBEM_STATUS_COMPLETE = 0, + WBEM_STATUS_REQUIREMENTS = 1, + WBEM_STATUS_PROGRESS = 2, + WBEM_STATUS_LOGGING_INFORMATION = 0x100, + WBEM_STATUS_LOGGING_INFORMATION_PROVIDER = 0x200, + WBEM_STATUS_LOGGING_INFORMATION_HOST = 0x400, + WBEM_STATUS_LOGGING_INFORMATION_REPOSITORY = 0x800, + WBEM_STATUS_LOGGING_INFORMATION_ESS = 0x1000, +}} +ENUM!{enum WBEM_TIMEOUT_TYPE { + WBEM_NO_WAIT = 0, + WBEM_INFINITE = 0xffffffff, +}} +ENUM!{enum WBEM_CONDITION_FLAG_TYPE { + WBEM_FLAG_ALWAYS = 0, + WBEM_FLAG_ONLY_IF_TRUE = 0x1, + WBEM_FLAG_ONLY_IF_FALSE = 0x2, + WBEM_FLAG_ONLY_IF_IDENTICAL = 0x3, + WBEM_MASK_PRIMARY_CONDITION = 0x3, + WBEM_FLAG_KEYS_ONLY = 0x4, + WBEM_FLAG_REFS_ONLY = 0x8, + WBEM_FLAG_LOCAL_ONLY = 0x10, + WBEM_FLAG_PROPAGATED_ONLY = 0x20, + WBEM_FLAG_SYSTEM_ONLY = 0x30, + WBEM_FLAG_NONSYSTEM_ONLY = 0x40, + WBEM_MASK_CONDITION_ORIGIN = 0x70, + WBEM_FLAG_CLASS_OVERRIDES_ONLY = 0x100, + WBEM_FLAG_CLASS_LOCAL_AND_OVERRIDES = 0x200, + WBEM_MASK_CLASS_CONDITION = 0x300, +}} +ENUM!{enum WBEM_FLAVOR_TYPE { + WBEM_FLAVOR_DONT_PROPAGATE = 0, + WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE = 0x1, + WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS = 0x2, + WBEM_FLAVOR_MASK_PROPAGATION = 0xf, + WBEM_FLAVOR_OVERRIDABLE = 0, + WBEM_FLAVOR_NOT_OVERRIDABLE = 0x10, + WBEM_FLAVOR_MASK_PERMISSIONS = 0x10, + WBEM_FLAVOR_ORIGIN_LOCAL = 0, + WBEM_FLAVOR_ORIGIN_PROPAGATED = 0x20, + WBEM_FLAVOR_ORIGIN_SYSTEM = 0x40, + WBEM_FLAVOR_MASK_ORIGIN = 0x60, + WBEM_FLAVOR_NOT_AMENDED = 0, + WBEM_FLAVOR_AMENDED = 0x80, + WBEM_FLAVOR_MASK_AMENDED = 0x80, +}} +ENUM!{enum WBEM_QUERY_FLAG_TYPE { + WBEM_FLAG_DEEP = 0, + WBEM_FLAG_SHALLOW = 1, + WBEM_FLAG_PROTOTYPE = 2, +}} +ENUM!{enum WBEM_SECURITY_FLAGS { + WBEM_ENABLE = 1, + WBEM_METHOD_EXECUTE = 2, + WBEM_FULL_WRITE_REP = 4, + WBEM_PARTIAL_WRITE_REP = 8, + WBEM_WRITE_PROVIDER = 0x10, + WBEM_REMOTE_ACCESS = 0x20, + WBEM_RIGHT_SUBSCRIBE = 0x40, + WBEM_RIGHT_PUBLISH = 0x80, +}} +ENUM!{enum WBEM_LIMITATION_FLAG_TYPE { + WBEM_FLAG_EXCLUDE_OBJECT_QUALIFIERS = 0x10, + WBEM_FLAG_EXCLUDE_PROPERTY_QUALIFIERS = 0x20, +}} +ENUM!{enum WBEM_TEXT_FLAG_TYPE { + WBEM_FLAG_NO_FLAVORS = 0x1, +}} +ENUM!{enum WBEM_COMPARISON_FLAG { + WBEM_COMPARISON_INCLUDE_ALL = 0, + WBEM_FLAG_IGNORE_QUALIFIERS = 0x1, + WBEM_FLAG_IGNORE_OBJECT_SOURCE = 0x2, + WBEM_FLAG_IGNORE_DEFAULT_VALUES = 0x4, + WBEM_FLAG_IGNORE_CLASS = 0x8, + WBEM_FLAG_IGNORE_CASE = 0x10, + WBEM_FLAG_IGNORE_FLAVOR = 0x20, +}} +ENUM!{enum WBEM_LOCKING_FLAG_TYPE { + WBEM_FLAG_ALLOW_READ = 0x1, +}} +ENUM!{enum CIMTYPE_ENUMERATION { + CIM_ILLEGAL = 0xfff, + CIM_EMPTY = 0, + CIM_SINT8 = 16, + CIM_UINT8 = 17, + CIM_SINT16 = 2, + CIM_UINT16 = 18, + CIM_SINT32 = 3, + CIM_UINT32 = 19, + CIM_SINT64 = 20, + CIM_UINT64 = 21, + CIM_REAL32 = 4, + CIM_REAL64 = 5, + CIM_BOOLEAN = 11, + CIM_STRING = 8, + CIM_DATETIME = 101, + CIM_REFERENCE = 102, + CIM_CHAR16 = 103, + CIM_OBJECT = 13, + CIM_FLAG_ARRAY = 0x2000, +}} +ENUM!{enum WBEM_BACKUP_RESTORE_FLAGS { + WBEM_FLAG_BACKUP_RESTORE_DEFAULT = 0, + WBEM_FLAG_BACKUP_RESTORE_FORCE_SHUTDOWN = 1, +}} +ENUM!{enum WBEM_REFRESHER_FLAGS { + WBEM_FLAG_REFRESH_AUTO_RECONNECT = 0, + WBEM_FLAG_REFRESH_NO_AUTO_RECONNECT = 1, +}} +ENUM!{enum WBEM_SHUTDOWN_FLAGS { + WBEM_SHUTDOWN_UNLOAD_COMPONENT = 1, + WBEM_SHUTDOWN_WMI = 2, + WBEM_SHUTDOWN_OS = 3, +}} +pub type CIMTYPE = c_long; +ENUM!{enum WBEMSTATUS_FORMAT { + WBEMSTATUS_FORMAT_NEWLINE = 0, + WBEMSTATUS_FORMAT_NO_NEWLINE = 1, +}} +ENUM!{enum WBEM_LIMITS { + WBEM_MAX_IDENTIFIER = 0x1000, + WBEM_MAX_QUERY = 0x4000, + WBEM_MAX_PATH = 0x2000, + WBEM_MAX_OBJECT_NESTING = 64, + WBEM_MAX_USER_PROPERTIES = 1024, +}} +ENUM!{enum WBEMSTATUS { + WBEM_NO_ERROR = 0, + WBEM_S_NO_ERROR = 0, + WBEM_S_SAME = 0, + WBEM_S_FALSE = 1, + WBEM_S_ALREADY_EXISTS = 0x40001, + WBEM_S_RESET_TO_DEFAULT = 0x40002, + WBEM_S_DIFFERENT = 0x40003, + WBEM_S_TIMEDOUT = 0x40004, + WBEM_S_NO_MORE_DATA = 0x40005, + WBEM_S_OPERATION_CANCELLED = 0x40006, + WBEM_S_PENDING = 0x40007, + WBEM_S_DUPLICATE_OBJECTS = 0x40008, + WBEM_S_ACCESS_DENIED = 0x40009, + WBEM_S_PARTIAL_RESULTS = 0x40010, + WBEM_S_SOURCE_NOT_AVAILABLE = 0x40017, + WBEM_E_FAILED = 0x80041001, + WBEM_E_NOT_FOUND = 0x80041002, + WBEM_E_ACCESS_DENIED = 0x80041003, + WBEM_E_PROVIDER_FAILURE = 0x80041004, + WBEM_E_TYPE_MISMATCH = 0x80041005, + WBEM_E_OUT_OF_MEMORY = 0x80041006, + WBEM_E_INVALID_CONTEXT = 0x80041007, + WBEM_E_INVALID_PARAMETER = 0x80041008, + WBEM_E_NOT_AVAILABLE = 0x80041009, + WBEM_E_CRITICAL_ERROR = 0x8004100a, + WBEM_E_INVALID_STREAM = 0x8004100b, + WBEM_E_NOT_SUPPORTED = 0x8004100c, + WBEM_E_INVALID_SUPERCLASS = 0x8004100d, + WBEM_E_INVALID_NAMESPACE = 0x8004100e, + WBEM_E_INVALID_OBJECT = 0x8004100f, + WBEM_E_INVALID_CLASS = 0x80041010, + WBEM_E_PROVIDER_NOT_FOUND = 0x80041011, + WBEM_E_INVALID_PROVIDER_REGISTRATION = 0x80041012, + WBEM_E_PROVIDER_LOAD_FAILURE = 0x80041013, + WBEM_E_INITIALIZATION_FAILURE = 0x80041014, + WBEM_E_TRANSPORT_FAILURE = 0x80041015, + WBEM_E_INVALID_OPERATION = 0x80041016, + WBEM_E_INVALID_QUERY = 0x80041017, + WBEM_E_INVALID_QUERY_TYPE = 0x80041018, + WBEM_E_ALREADY_EXISTS = 0x80041019, + WBEM_E_OVERRIDE_NOT_ALLOWED = 0x8004101a, + WBEM_E_PROPAGATED_QUALIFIER = 0x8004101b, + WBEM_E_PROPAGATED_PROPERTY = 0x8004101c, + WBEM_E_UNEXPECTED = 0x8004101d, + WBEM_E_ILLEGAL_OPERATION = 0x8004101e, + WBEM_E_CANNOT_BE_KEY = 0x8004101f, + WBEM_E_INCOMPLETE_CLASS = 0x80041020, + WBEM_E_INVALID_SYNTAX = 0x80041021, + WBEM_E_NONDECORATED_OBJECT = 0x80041022, + WBEM_E_READ_ONLY = 0x80041023, + WBEM_E_PROVIDER_NOT_CAPABLE = 0x80041024, + WBEM_E_CLASS_HAS_CHILDREN = 0x80041025, + WBEM_E_CLASS_HAS_INSTANCES = 0x80041026, + WBEM_E_QUERY_NOT_IMPLEMENTED = 0x80041027, + WBEM_E_ILLEGAL_NULL = 0x80041028, + WBEM_E_INVALID_QUALIFIER_TYPE = 0x80041029, + WBEM_E_INVALID_PROPERTY_TYPE = 0x8004102a, + WBEM_E_VALUE_OUT_OF_RANGE = 0x8004102b, + WBEM_E_CANNOT_BE_SINGLETON = 0x8004102c, + WBEM_E_INVALID_CIM_TYPE = 0x8004102d, + WBEM_E_INVALID_METHOD = 0x8004102e, + WBEM_E_INVALID_METHOD_PARAMETERS = 0x8004102f, + WBEM_E_SYSTEM_PROPERTY = 0x80041030, + WBEM_E_INVALID_PROPERTY = 0x80041031, + WBEM_E_CALL_CANCELLED = 0x80041032, + WBEM_E_SHUTTING_DOWN = 0x80041033, + WBEM_E_PROPAGATED_METHOD = 0x80041034, + WBEM_E_UNSUPPORTED_PARAMETER = 0x80041035, + WBEM_E_MISSING_PARAMETER_ID = 0x80041036, + WBEM_E_INVALID_PARAMETER_ID = 0x80041037, + WBEM_E_NONCONSECUTIVE_PARAMETER_IDS = 0x80041038, + WBEM_E_PARAMETER_ID_ON_RETVAL = 0x80041039, + WBEM_E_INVALID_OBJECT_PATH = 0x8004103a, + WBEM_E_OUT_OF_DISK_SPACE = 0x8004103b, + WBEM_E_BUFFER_TOO_SMALL = 0x8004103c, + WBEM_E_UNSUPPORTED_PUT_EXTENSION = 0x8004103d, + WBEM_E_UNKNOWN_OBJECT_TYPE = 0x8004103e, + WBEM_E_UNKNOWN_PACKET_TYPE = 0x8004103f, + WBEM_E_MARSHAL_VERSION_MISMATCH = 0x80041040, + WBEM_E_MARSHAL_INVALID_SIGNATURE = 0x80041041, + WBEM_E_INVALID_QUALIFIER = 0x80041042, + WBEM_E_INVALID_DUPLICATE_PARAMETER = 0x80041043, + WBEM_E_TOO_MUCH_DATA = 0x80041044, + WBEM_E_SERVER_TOO_BUSY = 0x80041045, + WBEM_E_INVALID_FLAVOR = 0x80041046, + WBEM_E_CIRCULAR_REFERENCE = 0x80041047, + WBEM_E_UNSUPPORTED_CLASS_UPDATE = 0x80041048, + WBEM_E_CANNOT_CHANGE_KEY_INHERITANCE = 0x80041049, + WBEM_E_CANNOT_CHANGE_INDEX_INHERITANCE = 0x80041050, + WBEM_E_TOO_MANY_PROPERTIES = 0x80041051, + WBEM_E_UPDATE_TYPE_MISMATCH = 0x80041052, + WBEM_E_UPDATE_OVERRIDE_NOT_ALLOWED = 0x80041053, + WBEM_E_UPDATE_PROPAGATED_METHOD = 0x80041054, + WBEM_E_METHOD_NOT_IMPLEMENTED = 0x80041055, + WBEM_E_METHOD_DISABLED = 0x80041056, + WBEM_E_REFRESHER_BUSY = 0x80041057, + WBEM_E_UNPARSABLE_QUERY = 0x80041058, + WBEM_E_NOT_EVENT_CLASS = 0x80041059, + WBEM_E_MISSING_GROUP_WITHIN = 0x8004105a, + WBEM_E_MISSING_AGGREGATION_LIST = 0x8004105b, + WBEM_E_PROPERTY_NOT_AN_OBJECT = 0x8004105c, + WBEM_E_AGGREGATING_BY_OBJECT = 0x8004105d, + WBEM_E_UNINTERPRETABLE_PROVIDER_QUERY = 0x8004105f, + WBEM_E_BACKUP_RESTORE_WINMGMT_RUNNING = 0x80041060, + WBEM_E_QUEUE_OVERFLOW = 0x80041061, + WBEM_E_PRIVILEGE_NOT_HELD = 0x80041062, + WBEM_E_INVALID_OPERATOR = 0x80041063, + WBEM_E_LOCAL_CREDENTIALS = 0x80041064, + WBEM_E_CANNOT_BE_ABSTRACT = 0x80041065, + WBEM_E_AMENDED_OBJECT = 0x80041066, + WBEM_E_CLIENT_TOO_SLOW = 0x80041067, + WBEM_E_NULL_SECURITY_DESCRIPTOR = 0x80041068, + WBEM_E_TIMED_OUT = 0x80041069, + WBEM_E_INVALID_ASSOCIATION = 0x8004106a, + WBEM_E_AMBIGUOUS_OPERATION = 0x8004106b, + WBEM_E_QUOTA_VIOLATION = 0x8004106c, + WBEM_E_RESERVED_001 = 0x8004106d, + WBEM_E_RESERVED_002 = 0x8004106e, + WBEM_E_UNSUPPORTED_LOCALE = 0x8004106f, + WBEM_E_HANDLE_OUT_OF_DATE = 0x80041070, + WBEM_E_CONNECTION_FAILED = 0x80041071, + WBEM_E_INVALID_HANDLE_REQUEST = 0x80041072, + WBEM_E_PROPERTY_NAME_TOO_WIDE = 0x80041073, + WBEM_E_CLASS_NAME_TOO_WIDE = 0x80041074, + WBEM_E_METHOD_NAME_TOO_WIDE = 0x80041075, + WBEM_E_QUALIFIER_NAME_TOO_WIDE = 0x80041076, + WBEM_E_RERUN_COMMAND = 0x80041077, + WBEM_E_DATABASE_VER_MISMATCH = 0x80041078, + WBEM_E_VETO_DELETE = 0x80041079, + WBEM_E_VETO_PUT = 0x8004107a, + WBEM_E_INVALID_LOCALE = 0x80041080, + WBEM_E_PROVIDER_SUSPENDED = 0x80041081, + WBEM_E_SYNCHRONIZATION_REQUIRED = 0x80041082, + WBEM_E_NO_SCHEMA = 0x80041083, + WBEM_E_PROVIDER_ALREADY_REGISTERED = 0x80041084, + WBEM_E_PROVIDER_NOT_REGISTERED = 0x80041085, + WBEM_E_FATAL_TRANSPORT_ERROR = 0x80041086, + WBEM_E_ENCRYPTED_CONNECTION_REQUIRED = 0x80041087, + WBEM_E_PROVIDER_TIMED_OUT = 0x80041088, + WBEM_E_NO_KEY = 0x80041089, + WBEM_E_PROVIDER_DISABLED = 0x8004108a, + WBEMESS_E_REGISTRATION_TOO_BROAD = 0x80042001, + WBEMESS_E_REGISTRATION_TOO_PRECISE = 0x80042002, + WBEMESS_E_AUTHZ_NOT_PRIVILEGED = 0x80042003, + WBEMMOF_E_EXPECTED_QUALIFIER_NAME = 0x80044001, + WBEMMOF_E_EXPECTED_SEMI = 0x80044002, + WBEMMOF_E_EXPECTED_OPEN_BRACE = 0x80044003, + WBEMMOF_E_EXPECTED_CLOSE_BRACE = 0x80044004, + WBEMMOF_E_EXPECTED_CLOSE_BRACKET = 0x80044005, + WBEMMOF_E_EXPECTED_CLOSE_PAREN = 0x80044006, + WBEMMOF_E_ILLEGAL_CONSTANT_VALUE = 0x80044007, + WBEMMOF_E_EXPECTED_TYPE_IDENTIFIER = 0x80044008, + WBEMMOF_E_EXPECTED_OPEN_PAREN = 0x80044009, + WBEMMOF_E_UNRECOGNIZED_TOKEN = 0x8004400a, + WBEMMOF_E_UNRECOGNIZED_TYPE = 0x8004400b, + WBEMMOF_E_EXPECTED_PROPERTY_NAME = 0x8004400c, + WBEMMOF_E_TYPEDEF_NOT_SUPPORTED = 0x8004400d, + WBEMMOF_E_UNEXPECTED_ALIAS = 0x8004400e, + WBEMMOF_E_UNEXPECTED_ARRAY_INIT = 0x8004400f, + WBEMMOF_E_INVALID_AMENDMENT_SYNTAX = 0x80044010, + WBEMMOF_E_INVALID_DUPLICATE_AMENDMENT = 0x80044011, + WBEMMOF_E_INVALID_PRAGMA = 0x80044012, + WBEMMOF_E_INVALID_NAMESPACE_SYNTAX = 0x80044013, + WBEMMOF_E_EXPECTED_CLASS_NAME = 0x80044014, + WBEMMOF_E_TYPE_MISMATCH = 0x80044015, + WBEMMOF_E_EXPECTED_ALIAS_NAME = 0x80044016, + WBEMMOF_E_INVALID_CLASS_DECLARATION = 0x80044017, + WBEMMOF_E_INVALID_INSTANCE_DECLARATION = 0x80044018, + WBEMMOF_E_EXPECTED_DOLLAR = 0x80044019, + WBEMMOF_E_CIMTYPE_QUALIFIER = 0x8004401a, + WBEMMOF_E_DUPLICATE_PROPERTY = 0x8004401b, + WBEMMOF_E_INVALID_NAMESPACE_SPECIFICATION = 0x8004401c, + WBEMMOF_E_OUT_OF_RANGE = 0x8004401d, + WBEMMOF_E_INVALID_FILE = 0x8004401e, + WBEMMOF_E_ALIASES_IN_EMBEDDED = 0x8004401f, + WBEMMOF_E_NULL_ARRAY_ELEM = 0x80044020, + WBEMMOF_E_DUPLICATE_QUALIFIER = 0x80044021, + WBEMMOF_E_EXPECTED_FLAVOR_TYPE = 0x80044022, + WBEMMOF_E_INCOMPATIBLE_FLAVOR_TYPES = 0x80044023, + WBEMMOF_E_MULTIPLE_ALIASES = 0x80044024, + WBEMMOF_E_INCOMPATIBLE_FLAVOR_TYPES2 = 0x80044025, + WBEMMOF_E_NO_ARRAYS_RETURNED = 0x80044026, + WBEMMOF_E_MUST_BE_IN_OR_OUT = 0x80044027, + WBEMMOF_E_INVALID_FLAGS_SYNTAX = 0x80044028, + WBEMMOF_E_EXPECTED_BRACE_OR_BAD_TYPE = 0x80044029, + WBEMMOF_E_UNSUPPORTED_CIMV22_QUAL_VALUE = 0x8004402a, + WBEMMOF_E_UNSUPPORTED_CIMV22_DATA_TYPE = 0x8004402b, + WBEMMOF_E_INVALID_DELETEINSTANCE_SYNTAX = 0x8004402c, + WBEMMOF_E_INVALID_QUALIFIER_SYNTAX = 0x8004402d, + WBEMMOF_E_QUALIFIER_USED_OUTSIDE_SCOPE = 0x8004402e, + WBEMMOF_E_ERROR_CREATING_TEMP_FILE = 0x8004402f, + WBEMMOF_E_ERROR_INVALID_INCLUDE_FILE = 0x80044030, + WBEMMOF_E_INVALID_DELETECLASS_SYNTAX = 0x80044031, +}} +// EXTERN_C const IID LIBID_WbemClient_v1; +// EXTERN_C const IID IID_IWbemClassObject; +DEFINE_GUID!{IID_IWbemClassObject, + 0xdc12a681, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} +RIDL!{#[uuid(0xdc12a681, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)] +interface IWbemClassObject(IWbemClassObjectVtbl): IUnknown(IUnknownVtbl) { + fn GetQualifierSet( + ppQualSet: *mut *mut IWbemQualifierSet, + ) -> HRESULT, + fn Get( + wszName: LPCWSTR, + lFlags: c_long, + pVal: *mut VARIANT, + pType: *mut CIMTYPE, + plFlavor: *mut c_long, + ) -> HRESULT, + fn Put( + wszName: LPCWSTR, + lFlags: c_long, + pVal: *mut VARIANT, + Type: CIMTYPE, + ) -> HRESULT, + fn Delete( + wszName: LPCWSTR, + ) -> HRESULT, + fn GetNames( + wszQualifierName: LPCWSTR, + lFlags: c_long, + pQualifierVal: *mut VARIANT, + pNames: *mut *mut SAFEARRAY, + ) -> HRESULT, + fn BeginEnumeration( + lEnumFlags: c_long, + ) -> HRESULT, + fn Next( + lFlags: c_long, + strName: *mut BSTR, + pVal: *mut VARIANT, + pType: *mut CIMTYPE, + plFlavor: *mut c_long, + ) -> HRESULT, + fn EndEnumeration() -> HRESULT, + fn GetPropertyQualifierSet( + wszProperty: LPCWSTR, + ppQualSet: *mut *mut IWbemQualifierSet, + ) -> HRESULT, + fn Clone( + ppCopy: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn GetObjectText( + lFlags: c_long, + pstrObjectText: *mut BSTR, + ) -> HRESULT, + fn SpawnDerivedClass( + lFlags: c_long, + ppNewClass: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn SpawnInstance( + lFlags: c_long, + ppNewInstance: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn CompareTo( + lFlags: c_long, + pCompareTo: *mut IWbemClassObject, + ) -> HRESULT, + fn GetPropertyOrigin( + wszName: LPCWSTR, + pstrClassName: *mut BSTR, + ) -> HRESULT, + fn InheritsFrom( + strAncestor: LPCWSTR, + ) -> HRESULT, + fn GetMethod( + wszName: LPCWSTR, + lFlags: c_long, + ppInSignature: *mut *mut IWbemClassObject, + ppOutSignature: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn PutMethod( + wszName: LPCWSTR, + lFlags: c_long, + pInSignature: *mut IWbemClassObject, + pOutSignature: *mut IWbemClassObject, + ) -> HRESULT, + fn DeleteMethod( + wszName: LPCWSTR, + ) -> HRESULT, + fn BeginMethodEnumeration( + lEnumFlags: c_long, + ) -> HRESULT, + fn NextMethod( + lFlags: c_long, + pstrName: *mut BSTR, + ppInSignature: *mut *mut IWbemClassObject, + ppOutSignature: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn EndMethodEnumeration() -> HRESULT, + fn GetMethodQualifierSet( + wszMethod: LPCWSTR, + ppQualSet: *mut *mut IWbemQualifierSet, + ) -> HRESULT, + fn GetMethodOrigin( + wszMethodName: LPCWSTR, + pstrClassName: *mut BSTR, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemObjectAccess; +DEFINE_GUID!{IID_IWbemObjectAccess, + 0x49353c9a, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x49353c9a, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemObjectAccess(IWbemObjectAccessVtbl): IWbemClassObject(IWbemClassObjectVtbl) { + fn GetPropertyHandle( + wszPropertyName: LPCWSTR, + pType: *mut CIMTYPE, + plHandle: *mut c_long, + ) -> HRESULT, + fn WritePropertyValue( + lHandle: c_long, + lNumBytes: c_long, + aData: *const byte, + ) -> HRESULT, + fn ReadPropertyValue( + lHandle: c_long, + lBufferSize: c_long, + plNumBytes: *mut c_long, + aData: *mut byte, + ) -> HRESULT, + fn ReadDWORD( + lHandle: c_long, + pdw: *mut DWORD, + ) -> HRESULT, + fn WriteDWORD( + lHandle: c_long, + dw: DWORD, + ) -> HRESULT, + fn ReadQWORD( + lHandle: c_long, + pqw: *mut __uint64, + ) -> HRESULT, + fn WriteQWORD( + lHandle: c_long, + pw: __uint64, + ) -> HRESULT, + fn GetPropertyInfoByHandle( + lHandle: c_long, + pstrName: *mut BSTR, + pType: *mut CIMTYPE, + ) -> HRESULT, + fn Lock( + lFlags: c_long, + ) -> HRESULT, + fn Unlock( + lFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemQualifierSet; +DEFINE_GUID!{IID_IWbemQualifierSet, + 0xdc12a680, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} +RIDL!{#[uuid(0xdc12a680, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)] +interface IWbemQualifierSet(IWbemQualifierSetVtbl): IUnknown(IUnknownVtbl) { + fn Get( + wszName: LPCWSTR, + lFlags: c_long, + pVal: *mut VARIANT, + plFlavor: *mut c_long, + ) -> HRESULT, + fn Put( + wszName: LPCWSTR, + pVal: *mut VARIANT, + lFlavor: c_long, + ) -> HRESULT, + fn Delete( + wszName: LPCWSTR, + ) -> HRESULT, + fn GetNames( + lFlags: c_long, + pNames: *mut *mut SAFEARRAY, + ) -> HRESULT, + fn BeginEnumeration( + lFlags: c_long, + ) -> HRESULT, + fn Next( + lFlags: c_long, + pstrName: *mut BSTR, + pVal: *mut VARIANT, + plFlavor: *mut c_long, + ) -> HRESULT, + fn EndEnumeration() -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemServices; +DEFINE_GUID!{IID_IWbemServices, + 0x9556dc99, 0x828c, 0x11cf, 0xa3, 0x7e, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7} +RIDL!{#[uuid(0x9556dc99, 0x828c, 0x11cf, 0xa3, 0x7e, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7)] +interface IWbemServices(IWbemServicesVtbl): IUnknown(IUnknownVtbl) { + fn OpenNamespace( + strNamespace: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppWorkingNamespace: *mut *mut IWbemServices, + ppResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn CancelAsyncCall( + pSink: *mut IWbemObjectSink, + ) -> HRESULT, + fn QueryObjectSink( + lFlags: c_long, + ppResponseHandler: *mut *mut IWbemObjectSink, + ) -> HRESULT, + fn GetObject( + strObjectPath: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppObject: *mut *mut IWbemClassObject, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn GetObjectAsync( + strObjectPath: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn PutClass( + pObject: *mut IWbemClassObject, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn PutClassAsync( + pObject: *mut IWbemClassObject, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn DeleteClass( + strClass: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn DeleteClassAsync( + strClass: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn CreateClassEnum( + strSuperclass: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppEnum: *mut *mut IEnumWbemClassObject, + ) -> HRESULT, + fn CreateClassEnumAsync( + strSuperclass: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn PutInstance( + pInst: *mut IWbemClassObject, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn PutInstanceAsync( + pInst: *mut IWbemClassObject, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn DeleteInstance( + strObjectPath: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn DeleteInstanceAsync( + strObjectPath: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn CreateInstanceEnum( + strFilter: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppEnum: *mut *mut IEnumWbemClassObject, + ) -> HRESULT, + fn CreateInstanceEnumAsync( + strFilter: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn ExecQuery( + strQueryLanguage: BSTR, + strQuery: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppEnum: *mut *mut IEnumWbemClassObject, + ) -> HRESULT, + fn ExecQueryAsync( + strQueryLanguage: BSTR, + strQuery: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn ExecNotificationQuery( + strQueryLanguage: BSTR, + strQuery: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppEnum: *mut *mut IEnumWbemClassObject, + ) -> HRESULT, + fn ExecNotificationQueryAsync( + strQueryLanguage: BSTR, + strQuery: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn ExecMethod( + strObjectPath: BSTR, + strMethodName: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pInParams: *mut IWbemClassObject, + ppOutParams: *mut *mut IWbemClassObject, + ppCallResult: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn ExecMethodAsync( + strObjectPath: BSTR, + strMethodName: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pInParams: *mut IWbemClassObject, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemLocator; +DEFINE_GUID!{IID_IWbemLocator, + 0xdc12a687, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} +RIDL!{#[uuid(0xdc12a687, 0x737f, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)] +interface IWbemLocator(IWbemLocatorVtbl): IUnknown(IUnknownVtbl) { + fn ConnectServer( + strNetworkResource: BSTR, + strUser: BSTR, + strPassword: BSTR, + strLocale: BSTR, + lSecurityFlags: c_long, + strAuthority: BSTR, + pCtx: *mut IWbemContext, + ppNamespace: *mut *mut IWbemServices, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemObjectSink; +DEFINE_GUID!{IID_IWbemObjectSink, + 0x7c857801, 0x7381, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} +RIDL!{#[uuid(0x7c857801, 0x7381, 0x11cf, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24)] +interface IWbemObjectSink(IWbemObjectSinkVtbl): IUnknown(IUnknownVtbl) { + fn Indicate( + lObjectCount: c_long, + apObjArray: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn SetStatus( + lFlags: c_long, + hResult: HRESULT, + strParam: BSTR, + pObjParam: *mut IWbemClassObject, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IEnumWbemClassObject; +DEFINE_GUID!{IID_IEnumWbemClassObject, + 0x027947e1, 0xd731, 0x11ce, 0xa3, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} +RIDL!{#[uuid(0x027947e1, 0xd731, 0x11ce, 0xa3, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)] +interface IEnumWbemClassObject(IEnumWbemClassObjectVtbl): IUnknown(IUnknownVtbl) { + fn Reset() -> HRESULT, + fn Next( + lTimeout: c_long, + uCount: ULONG, + apObjects: *mut *mut IWbemClassObject, + puReturned: *mut ULONG, + ) -> HRESULT, + fn NextAsync( + uCount: ULONG, + pSink: *mut IWbemObjectSink, + ) -> HRESULT, + fn Clone( + ppEnum: *mut *mut IEnumWbemClassObject, + ) -> HRESULT, + fn Skip( + lTimeout: c_long, + nCount: ULONG, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemCallResult; +DEFINE_GUID!{IID_IWbemCallResult, + 0x44aca675, 0xe8fc, 0x11d0, 0xa0, 0x7c, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x44aca675, 0xe8fc, 0x11d0, 0xa0, 0x7c, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemCallResult(IWbemCallResultVtbl): IUnknown(IUnknownVtbl) { + fn GetResultObject( + lTimeout: c_long, + ppResultObject: *mut *mut IWbemClassObject, + ) -> HRESULT, + fn GetResultString( + lTimeout: c_long, + pstrResultString: *mut BSTR, + ) -> HRESULT, + fn GetResultServices( + lTimeout: c_long, + ppServices: *mut *mut IWbemServices, + ) -> HRESULT, + fn GetCallStatus( + lTimeout: c_long, + plStatus: *mut c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemContext; +DEFINE_GUID!{IID_IWbemContext, + 0x44aca674, 0xe8fc, 0x11d0, 0xa0, 0x7c, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x44aca674, 0xe8fc, 0x11d0, 0xa0, 0x7c, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemContext(IWbemContextVtbl): IUnknown(IUnknownVtbl) { + fn Clone( + ppNewCopy: *mut *mut IWbemContext, + ) -> HRESULT, + fn GetNames( + lFlags: c_long, + pNames: *mut *mut SAFEARRAY, + ) -> HRESULT, + fn BeginEnumeration( + lFlags: c_long, + ) -> HRESULT, + fn Next( + lFlags: c_long, + pstrName: *mut BSTR, + pValue: *mut VARIANT, + ) -> HRESULT, + fn EndEnumeration() -> HRESULT, + fn SetValue( + wszName: LPCWSTR, + lFlags: c_long, + pValue: *mut VARIANT, + ) -> HRESULT, + fn GetValue( + wszName: LPCWSTR, + lFlags: c_long, + pValue: *mut VARIANT, + ) -> HRESULT, + fn DeleteValue( + wszName: LPCWSTR, + lFlags: c_long, + ) -> HRESULT, + fn DeleteAll() -> HRESULT, +}} +// EXTERN_C const IID IID_IUnsecuredApartment; +DEFINE_GUID!{IID_IUnsecuredApartment, + 0x1cfaba8c, 0x1523, 0x11d1, 0xad, 0x79, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0x1cfaba8c, 0x1523, 0x11d1, 0xad, 0x79, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IUnsecuredApartment(IUnsecuredApartmentVtbl): IUnknown(IUnknownVtbl) { + fn CreateObjectStub( + pObject: *mut IUnknown, + ppStub: *mut *mut IUnknown, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemUnsecuredApartment; +DEFINE_GUID!{IID_IWbemUnsecuredApartment, + 0x31739d04, 0x3471, 0x4cf4, 0x9a, 0x7c, 0x57, 0xa4, 0x4a, 0xe7, 0x19, 0x56} +RIDL!{#[uuid(0x31739d04, 0x3471, 0x4cf4, 0x9a, 0x7c, 0x57, 0xa4, 0x4a, 0xe7, 0x19, 0x56)] +interface IWbemUnsecuredApartment(IWbemUnsecuredApartmentVtbl): +IUnsecuredApartment(IUnsecuredApartmentVtbl) { + fn CreateSinkStub( + pSink: *mut IWbemObjectSink, + dwFlags: DWORD, + wszReserved: LPCWSTR, + ppStub: *mut *mut IWbemObjectSink, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemStatusCodeText; +DEFINE_GUID!{IID_IWbemStatusCodeText, + 0xeb87e1bc, 0x3233, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0xeb87e1bc, 0x3233, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemStatusCodeText(IWbemStatusCodeTextVtbl): IUnknown(IUnknownVtbl) { + fn GetErrorCodeText( + hRes: HRESULT, + LocaleId: LCID, + lFlags: c_long, + MessageText: *mut BSTR, + ) -> HRESULT, + fn GetFacilityCodeText( + hRes: HRESULT, + LocaleId: LCID, + lFlags: c_long, + MessageText: *mut BSTR, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemBackupRestore; +DEFINE_GUID!{IID_IWbemBackupRestore, + 0xc49e32c7, 0xbc8b, 0x11d2, 0x85, 0xd4, 0x00, 0x10, 0x5a, 0x1f, 0x83, 0x04} +RIDL!{#[uuid(0xc49e32c7, 0xbc8b, 0x11d2, 0x85, 0xd4, 0x00, 0x10, 0x5a, 0x1f, 0x83, 0x04)] +interface IWbemBackupRestore(IWbemBackupRestoreVtbl): IUnknown(IUnknownVtbl) { + fn Backup( + strBackupToFile: LPCWSTR, + lFlags: c_long, + ) -> HRESULT, + fn Restore( + strRestoreFromFile: LPCWSTR, + lFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemBackupRestoreEx; +DEFINE_GUID!{IID_IWbemBackupRestoreEx, + 0xa359dec5, 0xe813, 0x4834, 0x8a, 0x2a, 0xba, 0x7f, 0x1d, 0x77, 0x7d, 0x76} +RIDL!{#[uuid(0xa359dec5, 0xe813, 0x4834, 0x8a, 0x2a, 0xba, 0x7f, 0x1d, 0x77, 0x7d, 0x76)] +interface IWbemBackupRestoreEx(IWbemBackupRestoreExVtbl): +IWbemBackupRestore(IWbemBackupRestoreVtbl) { + fn Pause() -> HRESULT, + fn Resume() -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemRefresher; +DEFINE_GUID!{IID_IWbemRefresher, + 0x49353c99, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x49353c99, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemRefresher(IWbemRefresherVtbl): IUnknown(IUnknownVtbl) { + fn Refresh( + lFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemHiPerfEnum; +DEFINE_GUID!{IID_IWbemHiPerfEnum, + 0x2705c288, 0x79ae, 0x11d2, 0xb3, 0x48, 0x00, 0x10, 0x5a, 0x1f, 0x81, 0x77} +RIDL!{#[uuid(0x2705c288, 0x79ae, 0x11d2, 0xb3, 0x48, 0x00, 0x10, 0x5a, 0x1f, 0x81, 0x77)] +interface IWbemHiPerfEnum(IWbemHiPerfEnumVtbl): IUnknown(IUnknownVtbl) { + fn AddObjects( + lFlags: c_long, + uNumObjects: ULONG, + apIds: *mut c_long, + apObj: *mut *mut IWbemObjectAccess, + ) -> HRESULT, + fn RemoveObjects( + lFlags: c_long, + uNumObjects: ULONG, + apIds: *mut c_long, + ) -> HRESULT, + fn GetObjects( + lFlags: c_long, + uNumObjects: ULONG, + apObj: *mut *mut IWbemObjectAccess, + puReturned: *mut ULONG, + ) -> HRESULT, + fn RemoveAll( + lFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemConfigureRefresher; +DEFINE_GUID!{IID_IWbemConfigureRefresher, + 0x49353c92, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x49353c92, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemConfigureRefresher(IWbemConfigureRefresherVtbl): IUnknown(IUnknownVtbl) { + fn AddObjectByPath( + pNamespace: *mut IWbemServices, + wszPath: LPCWSTR, + lFlags: c_long, + pContext: *mut IWbemContext, + ppRefreshable: *mut *mut IWbemClassObject, + plId: *mut c_long, + ) -> HRESULT, + fn AddObjectByTemplate( + pNamespace: *mut IWbemServices, + pTemplate: *mut IWbemClassObject, + lFlags: c_long, + pContext: *mut IWbemContext, + ppRefreshable: *mut *mut IWbemClassObject, + plId: *mut c_long, + ) -> HRESULT, + fn AddRefresher( + pRefresher: *mut IWbemRefresher, + lFlags: c_long, + plId: *mut c_long, + ) -> HRESULT, + fn Remove( + lId: c_long, + lFlags: c_long, + ) -> HRESULT, + fn AddEnum( + pNamespace: *mut IWbemServices, + wszClassName: LPCWSTR, + lFlags: c_long, + pContext: *mut IWbemContext, + ppEnum: *mut *mut IWbemHiPerfEnum, + plId: *mut c_long, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_WbemLocator, + 0x4590f811, 0x1d3a, 0x11d0, 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24} +// class DECLSPEC_UUID("4590f811-1d3a-11d0-891f-00aa004b2e24") +// WbemLocator; +DEFINE_GUID!{CLSID_WbemContext, + 0x674B6698, 0xEE92, 0x11d0, 0xAD, 0x71, 0x00, 0xC0, 0x4F, 0xD8, 0xFD, 0xFF} +// class DECLSPEC_UUID("674B6698-EE92-11d0-AD71-00C04FD8FDFF") +// WbemContext; +DEFINE_GUID!{CLSID_UnsecuredApartment, + 0x49bd2028, 0x1523, 0x11d1, 0xad, 0x79, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +// class DECLSPEC_UUID("49bd2028-1523-11d1-ad79-00c04fd8fdff") +// UnsecuredApartment; +DEFINE_GUID!{CLSID_WbemClassObject, + 0x9A653086, 0x174F, 0x11d2, 0xB5, 0xF9, 0x00, 0x10, 0x4B, 0x70, 0x3E, 0xFD} +// class DECLSPEC_UUID("9A653086-174F-11d2-B5F9-00104B703EFD") +// WbemClassObject; +DEFINE_GUID!{CLSID_MofCompiler, + 0x6daf9757, 0x2e37, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +// class DECLSPEC_UUID("6daf9757-2e37-11d2-aec9-00c04fb68820") +// MofCompiler; +DEFINE_GUID!{CLSID_WbemStatusCodeText, + 0xeb87e1bd, 0x3233, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +// class DECLSPEC_UUID("eb87e1bd-3233-11d2-aec9-00c04fb68820") +// WbemStatusCodeText; +DEFINE_GUID!{CLSID_WbemBackupRestore, + 0xC49E32C6, 0xBC8B, 0x11d2, 0x85, 0xD4, 0x00, 0x10, 0x5A, 0x1F, 0x83, 0x04} +// class DECLSPEC_UUID("C49E32C6-BC8B-11d2-85D4-00105A1F8304") +// WbemBackupRestore; +DEFINE_GUID!{CLSID_WbemRefresher, + 0xc71566f2, 0x561e, 0x11d1, 0xad, 0x87, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +// class DECLSPEC_UUID("c71566f2-561e-11d1-ad87-00c04fd8fdff") +// WbemRefresher; +DEFINE_GUID!{CLSID_WbemObjectTextSrc, + 0x8D1C559D, 0x84F0, 0x4bb3, 0xA7, 0xD5, 0x56, 0xA7, 0x43, 0x5A, 0x9B, 0xA6} +// class DECLSPEC_UUID("8D1C559D-84F0-4bb3-A7D5-56A7435A9BA6") +// WbemObjectTextSrc; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0001_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0001_v0_0_s_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0003_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0003_v0_0_s_ifspec; +// EXTERN_C const IID IID_IWbemObjectSinkEx; +DEFINE_GUID!{IID_IWbemObjectSinkEx, + 0xe7d35cfa, 0x348b, 0x485e, 0xb5, 0x24, 0x25, 0x27, 0x25, 0xd6, 0x97, 0xca} +RIDL!{#[uuid(0xe7d35cfa, 0x348b, 0x485e, 0xb5, 0x24, 0x25, 0x27, 0x25, 0xd6, 0x97, 0xca)] +interface IWbemObjectSinkEx(IWbemObjectSinkExVtbl): IWbemObjectSink(IWbemObjectSinkVtbl) { + fn WriteMessage( + uChannel: ULONG, + strMessage: BSTR, + ) -> HRESULT, + fn WriteError( + pObjError: *mut IWbemClassObject, + puReturned: *mut c_uchar, + ) -> HRESULT, + fn PromptUser( + strMessage: BSTR, + uPromptType: c_uchar, + puReturned: *mut c_uchar, + ) -> HRESULT, + fn WriteProgress( + strActivity: BSTR, + strCurrentOperation: BSTR, + strStatusDescription: BSTR, + uPercentComplete: ULONG, + uSecondsRemaining: ULONG, + ) -> HRESULT, + fn WriteStreamParameter( + strName: BSTR, + vtValue: *mut VARIANT, + ulType: ULONG, + ulFlags: ULONG, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemShutdown; +DEFINE_GUID!{IID_IWbemShutdown, + 0xb7b31df9, 0xd515, 0x11d3, 0xa1, 0x1c, 0x00, 0x10, 0x5a, 0x1f, 0x51, 0x5a} +RIDL!{#[uuid(0xb7b31df9, 0xd515, 0x11d3, 0xa1, 0x1c, 0x00, 0x10, 0x5a, 0x1f, 0x51, 0x5a)] +interface IWbemShutdown(IWbemShutdownVtbl): IUnknown(IUnknownVtbl) { + fn Shutdown( + uReason: LONG, + uMaxMilliseconds: ULONG, + pCtx: *mut IWbemContext, + ) -> HRESULT, +}} +ENUM!{enum WMI_OBJ_TEXT { + WMI_OBJ_TEXT_CIM_DTD_2_0 = 1, + WMI_OBJ_TEXT_WMI_DTD_2_0 = 2, + WMI_OBJ_TEXT_WMI_EXT1 = 3, + WMI_OBJ_TEXT_WMI_EXT2 = 4, + WMI_OBJ_TEXT_WMI_EXT3 = 5, + WMI_OBJ_TEXT_WMI_EXT4 = 6, + WMI_OBJ_TEXT_WMI_EXT5 = 7, + WMI_OBJ_TEXT_WMI_EXT6 = 8, + WMI_OBJ_TEXT_WMI_EXT7 = 9, + WMI_OBJ_TEXT_WMI_EXT8 = 10, + WMI_OBJ_TEXT_WMI_EXT9 = 11, + WMI_OBJ_TEXT_WMI_EXT10 = 12, + WMI_OBJ_TEXT_LAST = 13, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0011_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0011_v0_0_s_ifspec; +// EXTERN_C const IID IID_IWbemObjectTextSrc; +DEFINE_GUID!{IID_IWbemObjectTextSrc, + 0xbfbf883a, 0xcad7, 0x11d3, 0xa1, 0x1b, 0x00, 0x10, 0x5a, 0x1f, 0x51, 0x5a} +RIDL!{#[uuid(0xbfbf883a, 0xcad7, 0x11d3, 0xa1, 0x1b, 0x00, 0x10, 0x5a, 0x1f, 0x51, 0x5a)] +interface IWbemObjectTextSrc(IWbemObjectTextSrcVtbl): IUnknown(IUnknownVtbl) { + fn GetText( + lFlags: c_long, + pObj: *mut IWbemClassObject, + uObjTextFormat: ULONG, + pCtx: *mut IWbemContext, + strText: *mut BSTR, + ) -> HRESULT, + fn CreateFromText( + lFlags: c_long, + strText: BSTR, + uObjTextFormat: ULONG, + pCtx: *mut IWbemContext, + pNewObj: *mut *mut IWbemClassObject, + ) -> HRESULT, +}} +STRUCT!{struct WBEM_COMPILE_STATUS_INFO { + lPhaseError: c_long, + hRes: HRESULT, + ObjectNum: c_long, + FirstLine: c_long, + LastLine: c_long, + dwOutFlags: DWORD, +}} +ENUM!{enum WBEM_COMPILER_OPTIONS { + WBEM_FLAG_CHECK_ONLY = 0x1, + WBEM_FLAG_AUTORECOVER = 0x2, + WBEM_FLAG_WMI_CHECK = 0x4, + WBEM_FLAG_CONSOLE_PRINT = 0x8, + WBEM_FLAG_DONT_ADD_TO_LIST = 0x10, + WBEM_FLAG_SPLIT_FILES = 0x20, + WBEM_FLAG_STORE_FILE = 0x100, +}} +ENUM!{enum WBEM_CONNECT_OPTIONS { + WBEM_FLAG_CONNECT_REPOSITORY_ONLY = 0x40, + WBEM_FLAG_CONNECT_USE_MAX_WAIT = 0x80, + WBEM_FLAG_CONNECT_PROVIDERS = 0x100, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0013_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0013_v0_0_s_ifspec; +// EXTERN_C const IID IID_IMofCompiler; +DEFINE_GUID!{IID_IMofCompiler, + 0x6daf974e, 0x2e37, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x6daf974e, 0x2e37, 0x11d2, 0xae, 0xc9, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IMofCompiler(IMofCompilerVtbl): IUnknown(IUnknownVtbl) { + fn CompileFile( + FileName: LPWSTR, + ServerAndNamespace: LPWSTR, + User: LPWSTR, + Authority: LPWSTR, + Password: LPWSTR, + lOptionFlags: LONG, + lClassFlags: LONG, + lInstanceFlags: LONG, + pInfo: *mut WBEM_COMPILE_STATUS_INFO, + ) -> HRESULT, + fn CompileBuffer( + BuffSize: c_long, + pBuffer: *mut BYTE, + ServerAndNamespace: LPWSTR, + User: LPWSTR, + Authority: LPWSTR, + Password: LPWSTR, + lOptionFlags: LONG, + lClassFlags: LONG, + lInstanceFlags: LONG, + pInfo: *mut WBEM_COMPILE_STATUS_INFO, + ) -> HRESULT, + fn CreateBMOF( + TextFileName: LPWSTR, + BMOFFileName: LPWSTR, + ServerAndNamespace: LPWSTR, + lOptionFlags: LONG, + lClassFlags: LONG, + lInstanceFlags: LONG, + pInfo: *mut WBEM_COMPILE_STATUS_INFO, + ) -> HRESULT, +}} +ENUM!{enum WBEM_UNSECAPP_FLAG_TYPE { + WBEM_FLAG_UNSECAPP_DEFAULT_CHECK_ACCESS = 0, + WBEM_FLAG_UNSECAPP_CHECK_ACCESS = 1, + WBEM_FLAG_UNSECAPP_DONT_CHECK_ACCESS = 2, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0015_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0015_v0_0_s_ifspec; +ENUM!{enum WBEM_INFORMATION_FLAG_TYPE { + WBEM_FLAG_SHORT_NAME = 0x1, + WBEM_FLAG_LONG_NAME = 0x2, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0016_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0016_v0_0_s_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0022_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemcli_0000_0022_v0_0_s_ifspec; +// unsigned c_long __RPC_USER BSTR_UserSize( __RPC__in unsigned c_long *, unsigned c_long , __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree( __RPC__in unsigned c_long *, __RPC__in BSTR * ); +// unsigned c_long __RPC_USER VARIANT_UserSize( __RPC__in unsigned c_long *, unsigned c_long , __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree( __RPC__in unsigned c_long *, __RPC__in VARIANT * ); +// unsigned c_long __RPC_USER BSTR_UserSize64( __RPC__in unsigned c_long *, unsigned c_long , __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal64( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal64(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree64( __RPC__in unsigned c_long *, __RPC__in BSTR * ); +// unsigned c_long __RPC_USER VARIANT_UserSize64( __RPC__in unsigned c_long *, unsigned c_long , __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal64( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal64(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree64( __RPC__in unsigned c_long *, __RPC__in VARIANT * ); diff --git a/winapi/src/um/wbemdisp.rs b/winapi/src/um/wbemdisp.rs new file mode 100644 index 000000000..8e3ec7736 --- /dev/null +++ b/winapi/src/um/wbemdisp.rs @@ -0,0 +1,1344 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_long; +use shared::winerror::HRESULT; +use shared::wtypes::{BSTR, DATE, VARIANT_BOOL}; +use um::oaidl::{DISPID, IDispatch, IDispatchVtbl, VARIANT}; +use um::unknwnbase::IUnknown; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0000_v0_0_s_ifspec; +ENUM!{enum WbemChangeFlagEnum { + wbemChangeFlagCreateOrUpdate = 0, + wbemChangeFlagUpdateOnly = 0x1, + wbemChangeFlagCreateOnly = 0x2, + wbemChangeFlagUpdateCompatible = 0, + wbemChangeFlagUpdateSafeMode = 0x20, + wbemChangeFlagUpdateForceMode = 0x40, + wbemChangeFlagStrongValidation = 0x80, + wbemChangeFlagAdvisory = 0x10000, +}} +ENUM!{enum WbemFlagEnum { + wbemFlagReturnImmediately = 0x10, + wbemFlagReturnWhenComplete = 0, + wbemFlagBidirectional = 0, + wbemFlagForwardOnly = 0x20, + wbemFlagNoErrorObject = 0x40, + wbemFlagReturnErrorObject = 0, + wbemFlagSendStatus = 0x80, + wbemFlagDontSendStatus = 0, + wbemFlagEnsureLocatable = 0x100, + wbemFlagDirectRead = 0x200, + wbemFlagSendOnlySelected = 0, + wbemFlagUseAmendedQualifiers = 0x20000, + wbemFlagGetDefault = 0, + wbemFlagSpawnInstance = 0x1, + wbemFlagUseCurrentTime = 0x1, +}} +ENUM!{enum WbemQueryFlagEnum { + wbemQueryFlagDeep = 0, + wbemQueryFlagShallow = 1, + wbemQueryFlagPrototype = 2, +}} +ENUM!{enum WbemTextFlagEnum { + wbemTextFlagNoFlavors = 0x1, +}} +ENUM!{enum WbemTimeout { + wbemTimeoutInfinite = 0xffffffff, +}} +ENUM!{enum WbemComparisonFlagEnum { + wbemComparisonFlagIncludeAll = 0, + wbemComparisonFlagIgnoreQualifiers = 0x1, + wbemComparisonFlagIgnoreObjectSource = 0x2, + wbemComparisonFlagIgnoreDefaultValues = 0x4, + wbemComparisonFlagIgnoreClass = 0x8, + wbemComparisonFlagIgnoreCase = 0x10, + wbemComparisonFlagIgnoreFlavor = 0x20, +}} +ENUM!{enum WbemCimtypeEnum { + wbemCimtypeSint8 = 16, + wbemCimtypeUint8 = 17, + wbemCimtypeSint16 = 2, + wbemCimtypeUint16 = 18, + wbemCimtypeSint32 = 3, + wbemCimtypeUint32 = 19, + wbemCimtypeSint64 = 20, + wbemCimtypeUint64 = 21, + wbemCimtypeReal32 = 4, + wbemCimtypeReal64 = 5, + wbemCimtypeBoolean = 11, + wbemCimtypeString = 8, + wbemCimtypeDatetime = 101, + wbemCimtypeReference = 102, + wbemCimtypeChar16 = 103, + wbemCimtypeObject = 13, +}} +ENUM!{enum WbemErrorEnum { + wbemNoErr = 0, + wbemErrFailed = 0x80041001, + wbemErrNotFound = 0x80041002, + wbemErrAccessDenied = 0x80041003, + wbemErrProviderFailure = 0x80041004, + wbemErrTypeMismatch = 0x80041005, + wbemErrOutOfMemory = 0x80041006, + wbemErrInvalidContext = 0x80041007, + wbemErrInvalidParameter = 0x80041008, + wbemErrNotAvailable = 0x80041009, + wbemErrCriticalError = 0x8004100a, + wbemErrInvalidStream = 0x8004100b, + wbemErrNotSupported = 0x8004100c, + wbemErrInvalidSuperclass = 0x8004100d, + wbemErrInvalidNamespace = 0x8004100e, + wbemErrInvalidObject = 0x8004100f, + wbemErrInvalidClass = 0x80041010, + wbemErrProviderNotFound = 0x80041011, + wbemErrInvalidProviderRegistration = 0x80041012, + wbemErrProviderLoadFailure = 0x80041013, + wbemErrInitializationFailure = 0x80041014, + wbemErrTransportFailure = 0x80041015, + wbemErrInvalidOperation = 0x80041016, + wbemErrInvalidQuery = 0x80041017, + wbemErrInvalidQueryType = 0x80041018, + wbemErrAlreadyExists = 0x80041019, + wbemErrOverrideNotAllowed = 0x8004101a, + wbemErrPropagatedQualifier = 0x8004101b, + wbemErrPropagatedProperty = 0x8004101c, + wbemErrUnexpected = 0x8004101d, + wbemErrIllegalOperation = 0x8004101e, + wbemErrCannotBeKey = 0x8004101f, + wbemErrIncompleteClass = 0x80041020, + wbemErrInvalidSyntax = 0x80041021, + wbemErrNondecoratedObject = 0x80041022, + wbemErrReadOnly = 0x80041023, + wbemErrProviderNotCapable = 0x80041024, + wbemErrClassHasChildren = 0x80041025, + wbemErrClassHasInstances = 0x80041026, + wbemErrQueryNotImplemented = 0x80041027, + wbemErrIllegalNull = 0x80041028, + wbemErrInvalidQualifierType = 0x80041029, + wbemErrInvalidPropertyType = 0x8004102a, + wbemErrValueOutOfRange = 0x8004102b, + wbemErrCannotBeSingleton = 0x8004102c, + wbemErrInvalidCimType = 0x8004102d, + wbemErrInvalidMethod = 0x8004102e, + wbemErrInvalidMethodParameters = 0x8004102f, + wbemErrSystemProperty = 0x80041030, + wbemErrInvalidProperty = 0x80041031, + wbemErrCallCancelled = 0x80041032, + wbemErrShuttingDown = 0x80041033, + wbemErrPropagatedMethod = 0x80041034, + wbemErrUnsupportedParameter = 0x80041035, + wbemErrMissingParameter = 0x80041036, + wbemErrInvalidParameterId = 0x80041037, + wbemErrNonConsecutiveParameterIds = 0x80041038, + wbemErrParameterIdOnRetval = 0x80041039, + wbemErrInvalidObjectPath = 0x8004103a, + wbemErrOutOfDiskSpace = 0x8004103b, + wbemErrBufferTooSmall = 0x8004103c, + wbemErrUnsupportedPutExtension = 0x8004103d, + wbemErrUnknownObjectType = 0x8004103e, + wbemErrUnknownPacketType = 0x8004103f, + wbemErrMarshalVersionMismatch = 0x80041040, + wbemErrMarshalInvalidSignature = 0x80041041, + wbemErrInvalidQualifier = 0x80041042, + wbemErrInvalidDuplicateParameter = 0x80041043, + wbemErrTooMuchData = 0x80041044, + wbemErrServerTooBusy = 0x80041045, + wbemErrInvalidFlavor = 0x80041046, + wbemErrCircularReference = 0x80041047, + wbemErrUnsupportedClassUpdate = 0x80041048, + wbemErrCannotChangeKeyInheritance = 0x80041049, + wbemErrCannotChangeIndexInheritance = 0x80041050, + wbemErrTooManyProperties = 0x80041051, + wbemErrUpdateTypeMismatch = 0x80041052, + wbemErrUpdateOverrideNotAllowed = 0x80041053, + wbemErrUpdatePropagatedMethod = 0x80041054, + wbemErrMethodNotImplemented = 0x80041055, + wbemErrMethodDisabled = 0x80041056, + wbemErrRefresherBusy = 0x80041057, + wbemErrUnparsableQuery = 0x80041058, + wbemErrNotEventClass = 0x80041059, + wbemErrMissingGroupWithin = 0x8004105a, + wbemErrMissingAggregationList = 0x8004105b, + wbemErrPropertyNotAnObject = 0x8004105c, + wbemErrAggregatingByObject = 0x8004105d, + wbemErrUninterpretableProviderQuery = 0x8004105f, + wbemErrBackupRestoreWinmgmtRunning = 0x80041060, + wbemErrQueueOverflow = 0x80041061, + wbemErrPrivilegeNotHeld = 0x80041062, + wbemErrInvalidOperator = 0x80041063, + wbemErrLocalCredentials = 0x80041064, + wbemErrCannotBeAbstract = 0x80041065, + wbemErrAmendedObject = 0x80041066, + wbemErrClientTooSlow = 0x80041067, + wbemErrNullSecurityDescriptor = 0x80041068, + wbemErrTimeout = 0x80041069, + wbemErrInvalidAssociation = 0x8004106a, + wbemErrAmbiguousOperation = 0x8004106b, + wbemErrQuotaViolation = 0x8004106c, + wbemErrTransactionConflict = 0x8004106d, + wbemErrForcedRollback = 0x8004106e, + wbemErrUnsupportedLocale = 0x8004106f, + wbemErrHandleOutOfDate = 0x80041070, + wbemErrConnectionFailed = 0x80041071, + wbemErrInvalidHandleRequest = 0x80041072, + wbemErrPropertyNameTooWide = 0x80041073, + wbemErrClassNameTooWide = 0x80041074, + wbemErrMethodNameTooWide = 0x80041075, + wbemErrQualifierNameTooWide = 0x80041076, + wbemErrRerunCommand = 0x80041077, + wbemErrDatabaseVerMismatch = 0x80041078, + wbemErrVetoPut = 0x80041079, + wbemErrVetoDelete = 0x8004107a, + wbemErrInvalidLocale = 0x80041080, + wbemErrProviderSuspended = 0x80041081, + wbemErrSynchronizationRequired = 0x80041082, + wbemErrNoSchema = 0x80041083, + wbemErrProviderAlreadyRegistered = 0x80041084, + wbemErrProviderNotRegistered = 0x80041085, + wbemErrFatalTransportError = 0x80041086, + wbemErrEncryptedConnectionRequired = 0x80041087, + wbemErrRegistrationTooBroad = 0x80042001, + wbemErrRegistrationTooPrecise = 0x80042002, + wbemErrTimedout = 0x80043001, + wbemErrResetToDefault = 0x80043002, +}} +ENUM!{enum WbemAuthenticationLevelEnum { + wbemAuthenticationLevelDefault = 0, + wbemAuthenticationLevelNone = 1, + wbemAuthenticationLevelConnect = 2, + wbemAuthenticationLevelCall = 3, + wbemAuthenticationLevelPkt = 4, + wbemAuthenticationLevelPktIntegrity = 5, + wbemAuthenticationLevelPktPrivacy = 6, +}} +ENUM!{enum WbemImpersonationLevelEnum { + wbemImpersonationLevelAnonymous = 1, + wbemImpersonationLevelIdentify = 2, + wbemImpersonationLevelImpersonate = 3, + wbemImpersonationLevelDelegate = 4, +}} +ENUM!{enum WbemPrivilegeEnum { + wbemPrivilegeCreateToken = 1, + wbemPrivilegePrimaryToken = 2, + wbemPrivilegeLockMemory = 3, + wbemPrivilegeIncreaseQuota = 4, + wbemPrivilegeMachineAccount = 5, + wbemPrivilegeTcb = 6, + wbemPrivilegeSecurity = 7, + wbemPrivilegeTakeOwnership = 8, + wbemPrivilegeLoadDriver = 9, + wbemPrivilegeSystemProfile = 10, + wbemPrivilegeSystemtime = 11, + wbemPrivilegeProfileSingleProcess = 12, + wbemPrivilegeIncreaseBasePriority = 13, + wbemPrivilegeCreatePagefile = 14, + wbemPrivilegeCreatePermanent = 15, + wbemPrivilegeBackup = 16, + wbemPrivilegeRestore = 17, + wbemPrivilegeShutdown = 18, + wbemPrivilegeDebug = 19, + wbemPrivilegeAudit = 20, + wbemPrivilegeSystemEnvironment = 21, + wbemPrivilegeChangeNotify = 22, + wbemPrivilegeRemoteShutdown = 23, + wbemPrivilegeUndock = 24, + wbemPrivilegeSyncAgent = 25, + wbemPrivilegeEnableDelegation = 26, + wbemPrivilegeManageVolume = 27, +}} +ENUM!{enum WbemObjectTextFormatEnum { + wbemObjectTextFormatCIMDTD20 = 1, + wbemObjectTextFormatWMIDTD20 = 2, +}} +ENUM!{enum WbemConnectOptionsEnum { + wbemConnectFlagUseMaxWait = 0x80, +}} +// EXTERN_C const IID LIBID_WbemScripting; +// EXTERN_C const IID IID_ISWbemServices; +DEFINE_GUID!{IID_ISWbemServices, + 0x76a6415c, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x76a6415c, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemServices(ISWbemServicesVtbl): IDispatch(IDispatchVtbl) { + fn Get( + strObjectPath: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn GetAsync( + objWbemSink: *mut IDispatch, + strObjectPath: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Delete( + strObjectPath: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + ) -> HRESULT, + fn DeleteAsync( + objWbemSink: *mut IDispatch, + strObjectPath: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn InstancesOf( + strClass: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn InstancesOfAsync( + objWbemSink: *mut IDispatch, + strClass: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn SubclassesOf( + strSuperclass: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn SubclassesOfAsync( + objWbemSink: *mut IDispatch, + strSuperclass: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn ExecQuery( + strQuery: BSTR, + strQueryLanguage: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn ExecQueryAsync( + objWbemSink: *mut IDispatch, + strQuery: BSTR, + strQueryLanguage: BSTR, + lFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn AssociatorsOf( + strObjectPath: BSTR, + strAssocClass: BSTR, + strResultClass: BSTR, + strResultRole: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredAssocQualifier: BSTR, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn AssociatorsOfAsync( + objWbemSink: *mut IDispatch, + strObjectPath: BSTR, + strAssocClass: BSTR, + strResultClass: BSTR, + strResultRole: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredAssocQualifier: BSTR, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn ReferencesTo( + strObjectPath: BSTR, + strResultClass: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn ReferencesToAsync( + objWbemSink: *mut IDispatch, + strObjectPath: BSTR, + strResultClass: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn ExecNotificationQuery( + strQuery: BSTR, + strQueryLanguage: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemEventSource: *mut *mut ISWbemEventSource, + ) -> HRESULT, + fn ExecNotificationQueryAsync( + objWbemSink: *mut IDispatch, + strQuery: BSTR, + strQueryLanguage: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn ExecMethod( + strObjectPath: BSTR, + strMethodName: BSTR, + objWbemInParameters: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemOutParameters: *mut *mut ISWbemObject, + ) -> HRESULT, + fn ExecMethodAsync( + objWbemSink: *mut IDispatch, + strObjectPath: BSTR, + strMethodName: BSTR, + objWbemInParameters: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemLocator; +DEFINE_GUID!{IID_ISWbemLocator, + 0x76a6415b, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x76a6415b, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemLocator(ISWbemLocatorVtbl): IDispatch(IDispatchVtbl) { + fn ConnectServer( + strServer: BSTR, + strNamespace: BSTR, + strUser: BSTR, + strPassword: BSTR, + strLocale: BSTR, + strAuthority: BSTR, + iSecurityFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemServices: *mut *mut ISWbemServices, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, +}} +pub const WBEMS_DISPID_DERIVATION: DISPID = 23; +// EXTERN_C const IID IID_ISWbemObject; +DEFINE_GUID!{IID_ISWbemObject, + 0x76a6415a, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x76a6415a, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemObject(ISWbemObjectVtbl): IDispatch(IDispatchVtbl) { + fn Put_( + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectPath: *mut *mut ISWbemObjectPath, + ) -> HRESULT, + fn PutAsync_( + objWbemSink: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Delete_( + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + ) -> HRESULT, + fn DeleteAsync_( + objWbemSink: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Instances_( + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn InstancesAsync_( + objWbemSink: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Subclasses_( + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn SubclassesAsync_( + objWbemSink: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Associators_( + strAssocClass: BSTR, + strResultClass: BSTR, + strResultRole: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredAssocQualifier: BSTR, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn AssociatorsAsync_( + objWbemSink: *mut IDispatch, + strAssocClass: BSTR, + strResultClass: BSTR, + strResultRole: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredAssocQualifier: BSTR, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn References_( + strResultClass: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn ReferencesAsync_( + objWbemSink: *mut IDispatch, + strResultClass: BSTR, + strRole: BSTR, + bClassesOnly: VARIANT_BOOL, + bSchemaOnly: VARIANT_BOOL, + strRequiredQualifier: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn ExecMethod_( + strMethodName: BSTR, + objWbemInParameters: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemOutParameters: *mut *mut ISWbemObject, + ) -> HRESULT, + fn ExecMethodAsync_( + objWbemSink: *mut IDispatch, + strMethodName: BSTR, + objWbemInParameters: *mut IDispatch, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, + fn Clone_( + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn GetObjectText_( + iFlags: c_long, + strObjectText: *mut BSTR, + ) -> HRESULT, + fn SpawnDerivedClass_( + iFlags: c_long, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn SpawnInstance_( + iFlags: c_long, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn CompareTo_( + objWbemObject: *mut IDispatch, + iFlags: c_long, + bResult: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_Qualifiers_( + objWbemQualifierSet: *mut *mut ISWbemQualifierSet, + ) -> HRESULT, + fn get_Properties_( + objWbemPropertySet: *mut *mut ISWbemPropertySet, + ) -> HRESULT, + fn get_Methods_( + objWbemMethodSet: *mut *mut ISWbemMethodSet, + ) -> HRESULT, + fn get_Derivation_( + strClassNameArray: *mut VARIANT, + ) -> HRESULT, + fn get_Path_( + objWbemObjectPath: *mut *mut ISWbemObjectPath, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemObjectSet; +DEFINE_GUID!{IID_ISWbemObjectSet, + 0x76a6415f, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x76a6415f, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemObjectSet(ISWbemObjectSetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + strObjectPath: BSTR, + iFlags: c_long, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, + fn ItemIndex( + lIndex: c_long, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemNamedValue; +DEFINE_GUID!{IID_ISWbemNamedValue, + 0x76a64164, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x76a64164, 0xcb41, 0x11d1, 0x8b, 0x02, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemNamedValue(ISWbemNamedValueVtbl): IDispatch(IDispatchVtbl) { + fn get_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn put_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn get_Name( + strName: *mut BSTR, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemNamedValueSet; +DEFINE_GUID!{IID_ISWbemNamedValueSet, + 0xcf2376ea, 0xce8c, 0x11d1, 0x8b, 0x05, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0xcf2376ea, 0xce8c, 0x11d1, 0x8b, 0x05, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemNamedValueSet(ISWbemNamedValueSetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + strName: BSTR, + iFlags: c_long, + objWbemNamedValue: *mut *mut ISWbemNamedValue, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn Add( + strName: BSTR, + varValue: *mut VARIANT, + iFlags: c_long, + objWbemNamedValue: *mut *mut ISWbemNamedValue, + ) -> HRESULT, + fn Remove( + strName: BSTR, + iFlags: c_long, + ) -> HRESULT, + fn Clone( + objWbemNamedValueSet: *mut *mut ISWbemNamedValueSet, + ) -> HRESULT, + fn DeleteAll() -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemQualifier; +DEFINE_GUID!{IID_ISWbemQualifier, + 0x79b05932, 0xd3b7, 0x11d1, 0x8b, 0x06, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x79b05932, 0xd3b7, 0x11d1, 0x8b, 0x06, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemQualifier(ISWbemQualifierVtbl): IDispatch(IDispatchVtbl) { + fn get_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn put_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn get_Name( + strName: *mut BSTR, + ) -> HRESULT, + fn get_IsLocal( + bIsLocal: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_PropagatesToSubclass( + bPropagatesToSubclass: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_PropagatesToSubclass( + bPropagatesToSubclass: VARIANT_BOOL, + ) -> HRESULT, + fn get_PropagatesToInstance( + bPropagatesToInstance: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_PropagatesToInstance( + bPropagatesToInstance: VARIANT_BOOL, + ) -> HRESULT, + fn get_IsOverridable( + bIsOverridable: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_IsOverridable( + bIsOverridable: VARIANT_BOOL, + ) -> HRESULT, + fn get_IsAmended( + bIsAmended: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemQualifierSet; +DEFINE_GUID!{IID_ISWbemQualifierSet, + 0x9b16ed16, 0xd3df, 0x11d1, 0x8b, 0x08, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x9b16ed16, 0xd3df, 0x11d1, 0x8b, 0x08, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemQualifierSet(ISWbemQualifierSetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + name: BSTR, + iFlags: c_long, + objWbemQualifier: *mut *mut ISWbemQualifier, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn Add( + strName: BSTR, + varVal: *mut VARIANT, + bPropagatesToSubclass: VARIANT_BOOL, + bPropagatesToInstance: VARIANT_BOOL, + bIsOverridable: VARIANT_BOOL, + iFlags: c_long, + objWbemQualifier: *mut *mut ISWbemQualifier, + ) -> HRESULT, + fn Remove( + strName: BSTR, + iFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemProperty; +DEFINE_GUID!{IID_ISWbemProperty, + 0x1a388f98, 0xd4ba, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x1a388f98, 0xd4ba, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemProperty(ISWbemPropertyVtbl): IDispatch(IDispatchVtbl) { + fn get_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn put_Value( + varValue: *mut VARIANT, + ) -> HRESULT, + fn get_Name( + strName: *mut BSTR, + ) -> HRESULT, + fn get_IsLocal( + bIsLocal: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_Origin( + strOrigin: *mut BSTR, + ) -> HRESULT, + fn get_CIMType( + iCimType: *mut WbemCimtypeEnum, + ) -> HRESULT, + fn get_Qualifiers_( + objWbemQualifierSet: *mut *mut ISWbemQualifierSet, + ) -> HRESULT, + fn get_IsArray( + bIsArray: *mut VARIANT_BOOL, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemPropertySet; +DEFINE_GUID!{IID_ISWbemPropertySet, + 0xdea0a7b2, 0xd4ba, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0xdea0a7b2, 0xd4ba, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemPropertySet(ISWbemPropertySetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + strName: BSTR, + iFlags: c_long, + objWbemProperty: *mut *mut ISWbemProperty, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn Add( + strName: BSTR, + iCIMType: WbemCimtypeEnum, + bIsArray: VARIANT_BOOL, + iFlags: c_long, + objWbemProperty: *mut *mut ISWbemProperty, + ) -> HRESULT, + fn Remove( + strName: BSTR, + iFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemMethod; +DEFINE_GUID!{IID_ISWbemMethod, + 0x422e8e90, 0xd955, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x422e8e90, 0xd955, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemMethod(ISWbemMethodVtbl): IDispatch(IDispatchVtbl) { + fn get_Name( + strName: *mut BSTR, + ) -> HRESULT, + fn get_Origin( + strOrigin: *mut BSTR, + ) -> HRESULT, + fn get_InParameters( + objWbemInParameters: *mut *mut ISWbemObject, + ) -> HRESULT, + fn get_OutParameters( + objWbemOutParameters: *mut *mut ISWbemObject, + ) -> HRESULT, + fn get_Qualifiers_( + objWbemQualifierSet: *mut *mut ISWbemQualifierSet, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemMethodSet; +DEFINE_GUID!{IID_ISWbemMethodSet, + 0xc93ba292, 0xd955, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0xc93ba292, 0xd955, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemMethodSet(ISWbemMethodSetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + strName: BSTR, + iFlags: c_long, + objWbemMethod: *mut *mut ISWbemMethod, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemEventSource; +DEFINE_GUID!{IID_ISWbemEventSource, + 0x27d54d92, 0x0ebe, 0x11d2, 0x8b, 0x22, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x27d54d92, 0x0ebe, 0x11d2, 0x8b, 0x22, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemEventSource(ISWbemEventSourceVtbl): IDispatch(IDispatchVtbl) { + fn NextEvent( + iTimeoutMs: c_long, + objWbemObject: *mut *mut ISWbemObject, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemObjectPath; +DEFINE_GUID!{IID_ISWbemObjectPath, + 0x5791bc27, 0xce9c, 0x11d1, 0x97, 0xbf, 0x00, 0x00, 0xf8, 0x1e, 0x84, 0x9c} +RIDL!{#[uuid(0x5791bc27, 0xce9c, 0x11d1, 0x97, 0xbf, 0x00, 0x00, 0xf8, 0x1e, 0x84, 0x9c)] +interface ISWbemObjectPath(ISWbemObjectPathVtbl): IDispatch(IDispatchVtbl) { + fn get_Path( + strPath: *mut BSTR, + ) -> HRESULT, + fn put_Path( + strPath: BSTR, + ) -> HRESULT, + fn get_RelPath( + strRelPath: *mut BSTR, + ) -> HRESULT, + fn put_RelPath( + strRelPath: BSTR, + ) -> HRESULT, + fn get_Server( + strServer: *mut BSTR, + ) -> HRESULT, + fn put_Server( + strServer: BSTR, + ) -> HRESULT, + fn get_Namespace( + strNamespace: *mut BSTR, + ) -> HRESULT, + fn put_Namespace( + strNamespace: BSTR, + ) -> HRESULT, + fn get_ParentNamespace( + strParentNamespace: *mut BSTR, + ) -> HRESULT, + fn get_DisplayName( + strDisplayName: *mut BSTR, + ) -> HRESULT, + fn put_DisplayName( + strDisplayName: BSTR, + ) -> HRESULT, + fn get_Class( + strClass: *mut BSTR, + ) -> HRESULT, + fn put_Class( + strClass: BSTR, + ) -> HRESULT, + fn get_IsClass( + bIsClass: *mut VARIANT_BOOL, + ) -> HRESULT, + fn SetAsClass() -> HRESULT, + fn get_IsSingleton( + bIsSingleton: *mut VARIANT_BOOL, + ) -> HRESULT, + fn SetAsSingleton() -> HRESULT, + fn get_Keys( + objWbemNamedValueSet: *mut *mut ISWbemNamedValueSet, + ) -> HRESULT, + fn get_Security_( + objWbemSecurity: *mut *mut ISWbemSecurity, + ) -> HRESULT, + fn get_Locale( + strLocale: *mut BSTR, + ) -> HRESULT, + fn put_Locale( + strLocale: BSTR, + ) -> HRESULT, + fn get_Authority( + strAuthority: *mut BSTR, + ) -> HRESULT, + fn put_Authority( + strAuthority: BSTR, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemLastError; +DEFINE_GUID!{IID_ISWbemLastError, + 0xd962db84, 0xd4bb, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0xd962db84, 0xd4bb, 0x11d1, 0x8b, 0x09, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemLastError(ISWbemLastErrorVtbl): ISWbemObject(ISWbemObjectVtbl) {}} +// EXTERN_C const IID DIID_ISWbemSinkEvents; +DEFINE_GUID!{IID_ISWbemSinkEvents, + 0x75718ca0, 0xf029, 0x11d1, 0xa1, 0xac, 0x00, 0xc0, 0x4f, 0xb6, 0xc2, 0x23} +RIDL!{#[uuid(0x75718ca0, 0xf029, 0x11d1, 0xa1, 0xac, 0x00, 0xc0, 0x4f, 0xb6, 0xc2, 0x23)] +interface ISWbemSinkEvents(ISWbemSinkEventsVtbl): IDispatch(IDispatchVtbl) {}} +// EXTERN_C const IID IID_ISWbemSink; +DEFINE_GUID!{IID_ISWbemSink, + 0x75718c9f, 0xf029, 0x11d1, 0xa1, 0xac, 0x00, 0xc0, 0x4f, 0xb6, 0xc2, 0x23} +RIDL!{#[uuid(0x75718c9f, 0xf029, 0x11d1, 0xa1, 0xac, 0x00, 0xc0, 0x4f, 0xb6, 0xc2, 0x23)] +interface ISWbemSink(ISWbemSinkVtbl): IDispatch(IDispatchVtbl) { + fn Cancel() -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemSecurity; +DEFINE_GUID!{IID_ISWbemSecurity, + 0xb54d66e6, 0x2287, 0x11d2, 0x8b, 0x33, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0xb54d66e6, 0x2287, 0x11d2, 0x8b, 0x33, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemSecurity(ISWbemSecurityVtbl): IDispatch(IDispatchVtbl) { + fn get_ImpersonationLevel( + iImpersonationLevel: *mut WbemImpersonationLevelEnum, + ) -> HRESULT, + fn put_ImpersonationLevel( + iImpersonationLevel: WbemImpersonationLevelEnum, + ) -> HRESULT, + fn get_AuthenticationLevel( + iAuthenticationLevel: *mut WbemAuthenticationLevelEnum, + ) -> HRESULT, + fn put_AuthenticationLevel( + iAuthenticationLevel: WbemAuthenticationLevelEnum, + ) -> HRESULT, + fn get_Privileges( + objWbemPrivilegeSet: *mut *mut ISWbemPrivilegeSet, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemPrivilege; +DEFINE_GUID!{IID_ISWbemPrivilege, + 0x26ee67bd, 0x5804, 0x11d2, 0x8b, 0x4a, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x26ee67bd, 0x5804, 0x11d2, 0x8b, 0x4a, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemPrivilege(ISWbemPrivilegeVtbl): IDispatch(IDispatchVtbl) { + fn get_IsEnabled( + bIsEnabled: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_IsEnabled( + bIsEnabled: VARIANT_BOOL, + ) -> HRESULT, + fn get_Name( + strDisplayName: *mut BSTR, + ) -> HRESULT, + fn get_DisplayName( + strDisplayName: *mut BSTR, + ) -> HRESULT, + fn get_Identifier( + iPrivilege: *mut WbemPrivilegeEnum, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemPrivilegeSet; +DEFINE_GUID!{IID_ISWbemPrivilegeSet, + 0x26ee67bf, 0x5804, 0x11d2, 0x8b, 0x4a, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6} +RIDL!{#[uuid(0x26ee67bf, 0x5804, 0x11d2, 0x8b, 0x4a, 0x00, 0x60, 0x08, 0x06, 0xd9, 0xb6)] +interface ISWbemPrivilegeSet(ISWbemPrivilegeSetVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + iPrivilege: WbemPrivilegeEnum, + objWbemPrivilege: *mut *mut ISWbemPrivilege, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn Add( + iPrivilege: WbemPrivilegeEnum, + bIsEnabled: VARIANT_BOOL, + objWbemPrivilege: *mut *mut ISWbemPrivilege, + ) -> HRESULT, + fn Remove( + iPrivilege: WbemPrivilegeEnum, + ) -> HRESULT, + fn DeleteAll() -> HRESULT, + fn AddAsString( + strPrivilege: BSTR, + bIsEnabled: VARIANT_BOOL, + objWbemPrivilege: *mut *mut ISWbemPrivilege, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemServicesEx; +DEFINE_GUID!{IID_ISWbemServicesEx, + 0xd2f68443, 0x85dc, 0x427e, 0x91, 0xd8, 0x36, 0x65, 0x54, 0xcc, 0x75, 0x4c} +RIDL!{#[uuid(0xd2f68443, 0x85dc, 0x427e, 0x91, 0xd8, 0x36, 0x65, 0x54, 0xcc, 0x75, 0x4c)] +interface ISWbemServicesEx(ISWbemServicesExVtbl): ISWbemServices(ISWbemServicesVtbl) { + fn Put( + objWbemObject: *mut ISWbemObjectEx, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemObjectPath: *mut *mut ISWbemObjectPath, + ) -> HRESULT, + fn PutAsync( + objWbemSink: *mut ISWbemSink, + objWbemObject: *mut ISWbemObjectEx, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemAsyncContext: *mut IDispatch, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemObjectEx; +DEFINE_GUID!{IID_ISWbemObjectEx, + 0x269ad56a, 0x8a67, 0x4129, 0xbc, 0x8c, 0x05, 0x06, 0xdc, 0xfe, 0x98, 0x80} +RIDL!{#[uuid(0x269ad56a, 0x8a67, 0x4129, 0xbc, 0x8c, 0x05, 0x06, 0xdc, 0xfe, 0x98, 0x80)] +interface ISWbemObjectEx(ISWbemObjectExVtbl): ISWbemObject(ISWbemObjectVtbl) { + fn Refresh_( + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + ) -> HRESULT, + fn get_SystemProperties_( + objWbemPropertySet: *mut *mut ISWbemPropertySet, + ) -> HRESULT, + fn GetText_( + iObjectTextFormat: WbemObjectTextFormatEnum, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + bsText: *mut BSTR, + ) -> HRESULT, + fn SetFromText_( + bsText: BSTR, + iObjectTextFormat: WbemObjectTextFormatEnum, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemDateTime; +DEFINE_GUID!{IID_ISWbemDateTime, + 0x5e97458a, 0xcf77, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a} +RIDL!{#[uuid(0x5e97458a, 0xcf77, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a)] +interface ISWbemDateTime(ISWbemDateTimeVtbl): IDispatch(IDispatchVtbl) { + fn get_Value( + strValue: *mut BSTR, + ) -> HRESULT, + fn put_Value( + strValue: BSTR, + ) -> HRESULT, + fn get_Year( + iYear: *mut c_long, + ) -> HRESULT, + fn put_Year( + iYear: c_long, + ) -> HRESULT, + fn get_YearSpecified( + bYearSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_YearSpecified( + bYearSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Month( + iMonth: *mut c_long, + ) -> HRESULT, + fn put_Month( + iMonth: c_long, + ) -> HRESULT, + fn get_MonthSpecified( + bMonthSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_MonthSpecified( + bMonthSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Day( + iDay: *mut c_long, + ) -> HRESULT, + fn put_Day( + iDay: c_long, + ) -> HRESULT, + fn get_DaySpecified( + bDaySpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_DaySpecified( + bDaySpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Hours( + iHours: *mut c_long, + ) -> HRESULT, + fn put_Hours( + iHours: c_long, + ) -> HRESULT, + fn get_HoursSpecified( + bHoursSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_HoursSpecified( + bHoursSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Minutes( + iMinutes: *mut c_long, + ) -> HRESULT, + fn put_Minutes( + iMinutes: c_long, + ) -> HRESULT, + fn get_MinutesSpecified( + bMinutesSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_MinutesSpecified( + bMinutesSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Seconds( + iSeconds: *mut c_long, + ) -> HRESULT, + fn put_Seconds( + iSeconds: c_long, + ) -> HRESULT, + fn get_SecondsSpecified( + bSecondsSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_SecondsSpecified( + bSecondsSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_Microseconds( + iMicroseconds: *mut c_long, + ) -> HRESULT, + fn put_Microseconds( + iMicroseconds: c_long, + ) -> HRESULT, + fn get_MicrosecondsSpecified( + bMicrosecondsSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_MicrosecondsSpecified( + bMicrosecondsSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_UTC( + iUTC: *mut c_long, + ) -> HRESULT, + fn put_UTC( + iUTC: c_long, + ) -> HRESULT, + fn get_UTCSpecified( + bUTCSpecified: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_UTCSpecified( + bUTCSpecified: VARIANT_BOOL, + ) -> HRESULT, + fn get_IsInterval( + bIsInterval: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_IsInterval( + bIsInterval: VARIANT_BOOL, + ) -> HRESULT, + fn GetVarDate( + bIsLocal: VARIANT_BOOL, + dVarDate: *mut DATE, + ) -> HRESULT, + fn SetVarDate( + dVarDate: DATE, + bIsLocal: VARIANT_BOOL, + ) -> HRESULT, + fn GetFileTime( + bIsLocal: VARIANT_BOOL, + strFileTime: *mut BSTR, + ) -> HRESULT, + fn SetFileTime( + strFileTime: BSTR, + bIsLocal: VARIANT_BOOL, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemRefresher; +DEFINE_GUID!{IID_ISWbemRefresher, + 0x14d8250e, 0xd9c2, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a} +RIDL!{#[uuid(0x14d8250e, 0xd9c2, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a)] +interface ISWbemRefresher(ISWbemRefresherVtbl): IDispatch(IDispatchVtbl) { + fn get__NewEnum( + pUnk: *mut *mut IUnknown, + ) -> HRESULT, + fn Item( + iIndex: c_long, + objWbemRefreshableItem: *mut *mut ISWbemRefreshableItem, + ) -> HRESULT, + fn get_Count( + iCount: *mut c_long, + ) -> HRESULT, + fn Add( + objWbemServices: *mut ISWbemServicesEx, + bsInstancePath: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemRefreshableItem: *mut *mut ISWbemRefreshableItem, + ) -> HRESULT, + fn AddEnum( + objWbemServices: *mut ISWbemServicesEx, + bsClassName: BSTR, + iFlags: c_long, + objWbemNamedValueSet: *mut IDispatch, + objWbemRefreshableItem: *mut *mut ISWbemRefreshableItem, + ) -> HRESULT, + fn Remove( + iIndex: c_long, + iFlags: c_long, + ) -> HRESULT, + fn Refresh( + iFlags: c_long, + ) -> HRESULT, + fn get_AutoReconnect( + bCount: *mut VARIANT_BOOL, + ) -> HRESULT, + fn put_AutoReconnect( + bCount: VARIANT_BOOL, + ) -> HRESULT, + fn DeleteAll() -> HRESULT, +}} +// EXTERN_C const IID IID_ISWbemRefreshableItem; +DEFINE_GUID!{IID_ISWbemRefreshableItem, + 0x5ad4bf92, 0xdaab, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a} +RIDL!{#[uuid(0x5ad4bf92, 0xdaab, 0x11d3, 0xb3, 0x8f, 0x00, 0x10, 0x5a, 0x1f, 0x47, 0x3a)] +interface ISWbemRefreshableItem(ISWbemRefreshableItemVtbl): IDispatch(IDispatchVtbl) { + fn get_Index( + iIndex: *mut c_long, + ) -> HRESULT, + fn get_Refresher( + objWbemRefresher: *mut *mut ISWbemRefresher, + ) -> HRESULT, + fn get_IsSet( + bIsSet: *mut VARIANT_BOOL, + ) -> HRESULT, + fn get_Object( + objWbemObject: *mut *mut ISWbemObjectEx, + ) -> HRESULT, + fn get_ObjectSet( + objWbemObjectSet: *mut *mut ISWbemObjectSet, + ) -> HRESULT, + fn Remove( + iFlags: c_long, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_SWbemLocator, + 0x76A64158, 0xCB41, 0x11d1, 0x8B, 0x02, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("76A64158-CB41-11d1-8B02-00600806D9B6") +// SWbemLocator; +DEFINE_GUID!{CLSID_SWbemNamedValueSet, + 0x9AED384E, 0xCE8B, 0x11d1, 0x8B, 0x05, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("9AED384E-CE8B-11d1-8B05-00600806D9B6") +// SWbemNamedValueSet; +DEFINE_GUID!{CLSID_SWbemObjectPath, + 0x5791BC26, 0xCE9C, 0x11d1, 0x97, 0xBF, 0x00, 0x00, 0xF8, 0x1E, 0x84, 0x9C} +// class DECLSPEC_UUID("5791BC26-CE9C-11d1-97BF-0000F81E849C") +// SWbemObjectPath; +DEFINE_GUID!{CLSID_SWbemLastError, + 0xC2FEEEAC, 0xCFCD, 0x11d1, 0x8B, 0x05, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("C2FEEEAC-CFCD-11d1-8B05-00600806D9B6") +// SWbemLastError; +DEFINE_GUID!{CLSID_SWbemSink, + 0x75718C9A, 0xF029, 0x11d1, 0xA1, 0xAC, 0x00, 0xC0, 0x4F, 0xB6, 0xC2, 0x23} +// class DECLSPEC_UUID("75718C9A-F029-11d1-A1AC-00C04FB6C223") +// SWbemSink; +DEFINE_GUID!{CLSID_SWbemDateTime, + 0x47DFBE54, 0xCF76, 0x11d3, 0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A} +// class DECLSPEC_UUID("47DFBE54-CF76-11d3-B38F-00105A1F473A") +// SWbemDateTime; +DEFINE_GUID!{CLSID_SWbemRefresher, + 0xD269BF5C, 0xD9C1, 0x11d3, 0xB3, 0x8F, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A} +// class DECLSPEC_UUID("D269BF5C-D9C1-11d3-B38F-00105A1F473A") +// SWbemRefresher; +DEFINE_GUID!{CLSID_SWbemServices, + 0x04B83D63, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D63-21AE-11d2-8B33-00600806D9B6") +// SWbemServices; +DEFINE_GUID!{CLSID_SWbemServicesEx, + 0x62E522DC, 0x8CF3, 0x40a8, 0x8B, 0x2E, 0x37, 0xD5, 0x95, 0x65, 0x1E, 0x40} +// class DECLSPEC_UUID("62E522DC-8CF3-40a8-8B2E-37D595651E40") +// SWbemServicesEx; +DEFINE_GUID!{CLSID_SWbemObject, + 0x04B83D62, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D62-21AE-11d2-8B33-00600806D9B6") +// SWbemObject; +DEFINE_GUID!{CLSID_SWbemObjectEx, + 0xD6BDAFB2, 0x9435, 0x491f, 0xBB, 0x87, 0x6A, 0xA0, 0xF0, 0xBC, 0x31, 0xA2} +// class DECLSPEC_UUID("D6BDAFB2-9435-491f-BB87-6AA0F0BC31A2") +// SWbemObjectEx; +DEFINE_GUID!{CLSID_SWbemObjectSet, + 0x04B83D61, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D61-21AE-11d2-8B33-00600806D9B6") +// SWbemObjectSet; +DEFINE_GUID!{CLSID_SWbemNamedValue, + 0x04B83D60, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D60-21AE-11d2-8B33-00600806D9B6") +// SWbemNamedValue; +DEFINE_GUID!{CLSID_SWbemQualifier, + 0x04B83D5F, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5F-21AE-11d2-8B33-00600806D9B6") +// SWbemQualifier; +DEFINE_GUID!{CLSID_SWbemQualifierSet, + 0x04B83D5E, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5E-21AE-11d2-8B33-00600806D9B6") +// SWbemQualifierSet; +DEFINE_GUID!{CLSID_SWbemProperty, + 0x04B83D5D, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5D-21AE-11d2-8B33-00600806D9B6") +// SWbemProperty; +DEFINE_GUID!{CLSID_SWbemPropertySet, + 0x04B83D5C, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5C-21AE-11d2-8B33-00600806D9B6") +// SWbemPropertySet; +DEFINE_GUID!{CLSID_SWbemMethod, + 0x04B83D5B, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5B-21AE-11d2-8B33-00600806D9B6") +// SWbemMethod; +DEFINE_GUID!{CLSID_SWbemMethodSet, + 0x04B83D5A, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D5A-21AE-11d2-8B33-00600806D9B6") +// SWbemMethodSet; +DEFINE_GUID!{CLSID_SWbemEventSource, + 0x04B83D58, 0x21AE, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("04B83D58-21AE-11d2-8B33-00600806D9B6") +// SWbemEventSource; +DEFINE_GUID!{CLSID_SWbemSecurity, + 0xB54D66E9, 0x2287, 0x11d2, 0x8B, 0x33, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("B54D66E9-2287-11d2-8B33-00600806D9B6") +// SWbemSecurity; +DEFINE_GUID!{CLSID_SWbemPrivilege, + 0x26EE67BC, 0x5804, 0x11d2, 0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("26EE67BC-5804-11d2-8B4A-00600806D9B6") +// SWbemPrivilege; +DEFINE_GUID!{CLSID_SWbemPrivilegeSet, + 0x26EE67BE, 0x5804, 0x11d2, 0x8B, 0x4A, 0x00, 0x60, 0x08, 0x06, 0xD9, 0xB6} +// class DECLSPEC_UUID("26EE67BE-5804-11d2-8B4A-00600806D9B6") +// SWbemPrivilegeSet; +DEFINE_GUID!{CLSID_SWbemRefreshableItem, + 0x8C6854BC, 0xDE4B, 0x11d3, 0xB3, 0x90, 0x00, 0x10, 0x5A, 0x1F, 0x47, 0x3A} +// class DECLSPEC_UUID("8C6854BC-DE4B-11d3-B390-00105A1F473A") +// SWbemRefreshableItem; +pub const WBEMS_DISPID_OBJECT_READY: DISPID = 1; +pub const WBEMS_DISPID_COMPLETED: DISPID = 2; +pub const WBEMS_DISPID_PROGRESS: DISPID = 3; +pub const WBEMS_DISPID_OBJECT_PUT: DISPID = 4; +pub const WBEMS_DISPID_CONNECTION_READY: DISPID = 5; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0018_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0018_v0_0_s_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0026_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemdisp_0000_0026_v0_0_s_ifspec; diff --git a/winapi/src/um/wbemprov.rs b/winapi/src/um/wbemprov.rs new file mode 100644 index 000000000..4ba60eedc --- /dev/null +++ b/winapi/src/um/wbemprov.rs @@ -0,0 +1,302 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_long, c_ulong}; +use shared::minwindef::{BYTE, DWORD}; +use shared::winerror::HRESULT; +use shared::wtypes::BSTR; +use um::oaidl::{VARIANT}; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wbemcli::{ + IWbemClassObject, IWbemContext, IWbemHiPerfEnum, IWbemObjectAccess, IWbemObjectSink, + IWbemObjectSinkVtbl, IWbemRefresher, IWbemServices +}; +use um::winnt::{LONG, LPCWSTR, LPWSTR, WCHAR}; +pub type WBEM_VARIANT = VARIANT; +pub type WBEM_WSTR = LPWSTR; +pub type WBEM_CWSTR = LPCWSTR; +ENUM!{enum WBEM_PROVIDER_REQUIREMENTS_TYPE { + WBEM_REQUIREMENTS_START_POSTFILTER = 0, + WBEM_REQUIREMENTS_STOP_POSTFILTER = 1, + WBEM_REQUIREMENTS_RECHECK_SUBSCRIPTIONS = 2, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0000_v0_0_s_ifspec; +// EXTERN_C const IID LIBID_WbemProviders_v1; +// EXTERN_C const IID IID_IWbemPropertyProvider; +DEFINE_GUID!{IID_IWbemPropertyProvider, + 0xce61e841, 0x65bc, 0x11d0, 0xb6, 0xbd, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7} +RIDL!{#[uuid(0xce61e841, 0x65bc, 0x11d0, 0xb6, 0xbd, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7)] +interface IWbemPropertyProvider(IWbemPropertyProviderVtbl): IUnknown(IUnknownVtbl) { + fn GetProperty( + lFlags: c_long, + strLocale: BSTR, + strClassMapping: BSTR, + strInstMapping: BSTR, + strPropMapping: BSTR, + pvValue: *mut VARIANT, + ) -> HRESULT, + fn PutProperty( + lFlags: c_long, + strLocale: BSTR, + strClassMapping: BSTR, + strInstMapping: BSTR, + strPropMapping: BSTR, + pvValue: *const VARIANT, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemUnboundObjectSink; +DEFINE_GUID!{IID_IWbemUnboundObjectSink, + 0xe246107b, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0xe246107b, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IWbemUnboundObjectSink(IWbemUnboundObjectSinkVtbl): IUnknown(IUnknownVtbl) { + fn IndicateToConsumer( + pLogicalConsumer: *mut IWbemClassObject, + lNumObjects: c_long, + apObjects: *mut *mut IWbemClassObject, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemEventProvider; +DEFINE_GUID!{IID_IWbemEventProvider, + 0xe245105b, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0xe245105b, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IWbemEventProvider(IWbemEventProviderVtbl): IUnknown(IUnknownVtbl) { + fn ProvideEvents( + pSink: *mut IWbemObjectSink, + lFlags: c_long, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemEventProviderQuerySink; +DEFINE_GUID!{IID_IWbemEventProviderQuerySink, + 0x580acaf8, 0xfa1c, 0x11d0, 0xad, 0x72, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0x580acaf8, 0xfa1c, 0x11d0, 0xad, 0x72, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IWbemEventProviderQuerySink(IWbemEventProviderQuerySinkVtbl): IUnknown(IUnknownVtbl) { + fn NewQuery( + dwId: c_ulong, + wszQueryLanguage: WBEM_WSTR, + wszQuery: WBEM_WSTR, + ) -> HRESULT, + fn CancelQuery( + dwId: c_ulong, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemEventProviderSecurity; +DEFINE_GUID!{IID_IWbemEventProviderSecurity, + 0x631f7d96, 0xd993, 0x11d2, 0xb3, 0x39, 0x00, 0x10, 0x5a, 0x1f, 0x4a, 0xaf} +RIDL!{#[uuid(0x631f7d96, 0xd993, 0x11d2, 0xb3, 0x39, 0x00, 0x10, 0x5a, 0x1f, 0x4a, 0xaf)] +interface IWbemEventProviderSecurity(IWbemEventProviderSecurityVtbl): IUnknown(IUnknownVtbl) { + fn AccessCheck( + wszQueryLanguage: WBEM_CWSTR, + wszQuery: WBEM_CWSTR, + lSidLength: c_long, + pSid: *const BYTE, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemEventConsumerProvider; +DEFINE_GUID!{IID_IWbemEventConsumerProvider, + 0xe246107a, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0xe246107a, 0xb06e, 0x11d0, 0xad, 0x61, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IWbemEventConsumerProvider(IWbemEventConsumerProviderVtbl): IUnknown(IUnknownVtbl) { + fn FindConsumer( + pLogicalConsumer: *mut IWbemClassObject, + ppConsumer: *mut *mut IWbemUnboundObjectSink, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemProviderInitSink; +DEFINE_GUID!{IID_IWbemProviderInitSink, + 0x1be41571, 0x91dd, 0x11d1, 0xae, 0xb2, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x1be41571, 0x91dd, 0x11d1, 0xae, 0xb2, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemProviderInitSink(IWbemProviderInitSinkVtbl): IUnknown(IUnknownVtbl) { + fn SetStatus( + lStatus: LONG, + lFlags: LONG, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemProviderInit; +DEFINE_GUID!{IID_IWbemProviderInit, + 0x1be41572, 0x91dd, 0x11d1, 0xae, 0xb2, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x1be41572, 0x91dd, 0x11d1, 0xae, 0xb2, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemProviderInit(IWbemProviderInitVtbl): IUnknown(IUnknownVtbl) { + fn Initialize( + wszUser: LPWSTR, + lFlags: LONG, + wszNamespace: LPWSTR, + wszLocale: LPWSTR, + pNamespace: *mut IWbemServices, + pCtx: *mut IWbemContext, + pInitSink: *mut IWbemProviderInitSink, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemHiPerfProvider; +DEFINE_GUID!{IID_IWbemHiPerfProvider, + 0x49353c93, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0x49353c93, 0x516b, 0x11d1, 0xae, 0xa6, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemHiPerfProvider(IWbemHiPerfProviderVtbl): IUnknown(IUnknownVtbl) { + fn QueryInstances( + pNamespace: *mut IWbemServices, + wszClass: *mut WCHAR, + lFlags: c_long, + pCtx: *mut IWbemContext, + pSink: *mut IWbemObjectSink, + ) -> HRESULT, + fn CreateRefresher( + pNamespace: *mut IWbemServices, + lFlags: c_long, + ppRefresher: *mut *mut IWbemRefresher, + ) -> HRESULT, + fn CreateRefreshableObject( + pNamespace: *mut IWbemServices, + pTemplate: *mut IWbemObjectAccess, + pRefresher: *mut IWbemRefresher, + lFlags: c_long, + pContext: *mut IWbemContext, + ppRefreshable: *mut *mut IWbemObjectAccess, + plId: *mut c_long, + ) -> HRESULT, + fn StopRefreshing( + pRefresher: *mut IWbemRefresher, + lId: c_long, + lFlags: c_long, + ) -> HRESULT, + fn CreateRefreshableEnum( + pNamespace: *mut IWbemServices, + wszClass: LPCWSTR, + pRefresher: *mut IWbemRefresher, + lFlags: c_long, + pContext: *mut IWbemContext, + pHiPerfEnum: *mut IWbemHiPerfEnum, + plId: *mut c_long, + ) -> HRESULT, + fn GetObjects( + pNamespace: *mut IWbemServices, + lNumObjects: c_long, + apObj: *mut *mut IWbemObjectAccess, + lFlags: c_long, + pContext: *mut IWbemContext, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemDecoupledRegistrar; +DEFINE_GUID!{IID_IWbemDecoupledRegistrar, + 0x1005cbcf, 0xe64f, 0x4646, 0xbc, 0xd3, 0x3a, 0x08, 0x9d, 0x8a, 0x84, 0xb4} +RIDL!{#[uuid(0x1005cbcf, 0xe64f, 0x4646, 0xbc, 0xd3, 0x3a, 0x08, 0x9d, 0x8a, 0x84, 0xb4)] +interface IWbemDecoupledRegistrar(IWbemDecoupledRegistrarVtbl): IUnknown(IUnknownVtbl) { + fn Register( + a_Flags: c_long, + a_Context: *mut IWbemContext, + a_User: LPCWSTR, + a_Locale: LPCWSTR, + a_Scope: LPCWSTR, + a_Registration: LPCWSTR, + pIUnknown: *mut IUnknown, + ) -> HRESULT, + fn UnRegister() -> HRESULT, +}} +DEFINE_GUID!{CLSID_WbemAdministrativeLocator, + 0xcb8555cc, 0x9128, 0x11d1, 0xad, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +// class DECLSPEC_UUID("cb8555cc-9128-11d1-ad9b-00c04fd8fdff") +// WbemAdministrativeLocator; +DEFINE_GUID!{CLSID_WbemAuthenticatedLocator, + 0xcd184336, 0x9128, 0x11d1, 0xad, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +// class DECLSPEC_UUID("cd184336-9128-11d1-ad9b-00c04fd8fdff") +// WbemAuthenticatedLocator; +DEFINE_GUID!{CLSID_WbemUnauthenticatedLocator, + 0x443E7B79, 0xDE31, 0x11d2, 0xB3, 0x40, 0x00, 0x10, 0x4B, 0xCC, 0x4B, 0x4A} +// class DECLSPEC_UUID("443E7B79-DE31-11d2-B340-00104BCC4B4A") +// WbemUnauthenticatedLocator; +DEFINE_GUID!{CLSID_WbemDecoupledRegistrar, + 0x4cfc7932, 0x0f9d, 0x4bef, 0x9c, 0x32, 0x8e, 0xa2, 0xa6, 0xb5, 0x6f, 0xcb} +// class DECLSPEC_UUID("4cfc7932-0f9d-4bef-9c32-8ea2a6b56fcb") +// WbemDecoupledRegistrar; +DEFINE_GUID!{CLSID_WbemDecoupledBasicEventProvider, + 0xf5f75737, 0x2843, 0x4f22, 0x93, 0x3d, 0xc7, 0x6a, 0x97, 0xcd, 0xa6, 0x2f} +// class DECLSPEC_UUID("f5f75737-2843-4f22-933d-c76a97cda62f") +// WbemDecoupledBasicEventProvider; +// EXTERN_C const IID IID_IWbemProviderIdentity; +DEFINE_GUID!{IID_IWbemProviderIdentity, + 0x631f7d97, 0xd993, 0x11d2, 0xb3, 0x39, 0x00, 0x10, 0x5a, 0x1f, 0x4a, 0xaf} +RIDL!{#[uuid(0x631f7d97, 0xd993, 0x11d2, 0xb3, 0x39, 0x00, 0x10, 0x5a, 0x1f, 0x4a, 0xaf)] +interface IWbemProviderIdentity(IWbemProviderIdentityVtbl): IUnknown(IUnknownVtbl) { + fn SetRegistrationObject( + lFlags: c_long, + pProvReg: *mut IWbemClassObject, + ) -> HRESULT, +}} +ENUM!{enum WBEM_EXTRA_RETURN_CODES { + WBEM_S_INITIALIZED = 0, + WBEM_S_LIMITED_SERVICE = 0x43001, + WBEM_S_INDIRECTLY_UPDATED = WBEM_S_LIMITED_SERVICE + 1, + WBEM_S_SUBJECT_TO_SDS = WBEM_S_INDIRECTLY_UPDATED + 1, + WBEM_E_RETRY_LATER = 0x80043001, + WBEM_E_RESOURCE_CONTENTION = WBEM_E_RETRY_LATER + 1, +}} +ENUM!{enum WBEM_PROVIDER_FLAGS { + WBEM_FLAG_OWNER_UPDATE = 0x10000, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0008_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0008_v0_0_s_ifspec; +// EXTERN_C const IID IID_IWbemDecoupledBasicEventProvider; +DEFINE_GUID!{IID_IWbemDecoupledBasicEventProvider, + 0x86336d20, 0xca11, 0x4786, 0x9e, 0xf1, 0xbc, 0x8a, 0x94, 0x6b, 0x42, 0xfc} +RIDL!{#[uuid(0x86336d20, 0xca11, 0x4786, 0x9e, 0xf1, 0xbc, 0x8a, 0x94, 0x6b, 0x42, 0xfc)] +interface IWbemDecoupledBasicEventProvider(IWbemDecoupledBasicEventProviderVtbl): + IWbemDecoupledRegistrar(IWbemDecoupledRegistrarVtbl) { + fn GetSink( + a_Flags: c_long, + a_Context: *mut IWbemContext, + a_Sink: *mut *mut IWbemObjectSink, + ) -> HRESULT, + fn GetService( + a_Flags: c_long, + a_Context: *mut IWbemContext, + a_Service: *mut *mut IWbemServices, + ) -> HRESULT, +}} +ENUM!{enum WBEM_BATCH_TYPE { + WBEM_FLAG_BATCH_IF_NEEDED = 0, + WBEM_FLAG_MUST_BATCH = 0x1, + WBEM_FLAG_MUST_NOT_BATCH = 0x2, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0013_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0013_v0_0_s_ifspec; +// EXTERN_C const IID IID_IWbemEventSink; +DEFINE_GUID!{IID_IWbemEventSink, + 0x3ae0080a, 0x7e3a, 0x4366, 0xbf, 0x89, 0x0f, 0xee, 0xdc, 0x93, 0x16, 0x59} +RIDL!{#[uuid(0x3ae0080a, 0x7e3a, 0x4366, 0xbf, 0x89, 0x0f, 0xee, 0xdc, 0x93, 0x16, 0x59)] +interface IWbemEventSink(IWbemEventSinkVtbl): IWbemObjectSink(IWbemObjectSinkVtbl) { + fn SetSinkSecurity( + lSDLength: c_long, + pSD: *mut BYTE, + ) -> HRESULT, + fn IsActive() -> HRESULT, + fn GetRestrictedSink( + lNumQueries: c_long, + awszQueries: *const LPCWSTR, + pCallback: *mut IUnknown, + ppSink: *mut *mut IWbemEventSink, + ) -> HRESULT, + fn SetBatchingParameters( + lFlags: LONG, + dwMaxBufferSize: DWORD, + dwMaxSendLatency: DWORD, + ) -> HRESULT, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0014_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemprov_0000_0014_v0_0_s_ifspec; +// unsigned c_long __RPC_USER BSTR_UserSize( __RPC__in unsigned c_long *, unsigned c_long, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree( __RPC__in unsigned c_long *, __RPC__in BSTR * ); +// unsigned c_long __RPC_USER VARIANT_UserSize( __RPC__in unsigned c_long *, unsigned c_long, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree( __RPC__in unsigned c_long *, __RPC__in VARIANT * ); +// unsigned c_long __RPC_USER BSTR_UserSize64( __RPC__in unsigned c_long *, unsigned c_long, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserMarshal64( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * ); +// unsigned char * __RPC_USER BSTR_UserUnmarshal64(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * ); +// void __RPC_USER BSTR_UserFree64( __RPC__in unsigned c_long *, __RPC__in BSTR * ); +// unsigned c_long __RPC_USER VARIANT_UserSize64( __RPC__in unsigned c_long *, unsigned c_long, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserMarshal64( __RPC__in unsigned c_long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * ); +// unsigned char * __RPC_USER VARIANT_UserUnmarshal64(__RPC__in unsigned c_long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * ); +// void __RPC_USER VARIANT_UserFree64( __RPC__in unsigned c_long *, __RPC__in VARIANT * ); diff --git a/winapi/src/um/wbemtran.rs b/winapi/src/um/wbemtran.rs new file mode 100644 index 000000000..6f9d4a6ed --- /dev/null +++ b/winapi/src/um/wbemtran.rs @@ -0,0 +1,184 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_long, c_void}; +use shared::guiddef::REFIID; +use shared::minwindef::{BYTE, DWORD}; +use shared::winerror::HRESULT; +use shared::wtypes::BSTR; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wbemcli::{IWbemCallResult, IWbemContext, IWbemObjectSink, IWbemServices}; +use um::winnt::{LPCWSTR, LPWSTR}; +// extern RPC_IF_HANDLE __MIDL_itf_wbemtran_0000_0000_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemtran_0000_0000_v0_0_s_ifspec; +ENUM!{enum WBEM_LOGIN_TYPE { + WBEM_FLAG_INPROC_LOGIN = 0, + WBEM_FLAG_LOCAL_LOGIN = 1, + WBEM_FLAG_REMOTE_LOGIN = 2, + WBEM_AUTHENTICATION_METHOD_MASK = 0xf, + WBEM_FLAG_USE_MULTIPLE_CHALLENGES = 0x10, +}} +pub type WBEM_128BITS = *mut BYTE; +// EXTERN_C const IID LIBID_WbemTransports_v1; +// EXTERN_C const IID IID_IWbemTransport; +DEFINE_GUID!{IID_IWbemTransport, + 0x553fe584, 0x2156, 0x11d0, 0xb6, 0xae, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7} +RIDL!{#[uuid(0x553fe584, 0x2156, 0x11d0, 0xb6, 0xae, 0x00, 0xaa, 0x00, 0x32, 0x40, 0xc7)] +interface IWbemTransport(IWbemTransportVtbl): IUnknown(IUnknownVtbl) { + fn Initialize() -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemLevel1Login; +DEFINE_GUID!{IID_IWbemLevel1Login, + 0xf309ad18, 0xd86a, 0x11d0, 0xa0, 0x75, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20} +RIDL!{#[uuid(0xf309ad18, 0xd86a, 0x11d0, 0xa0, 0x75, 0x00, 0xc0, 0x4f, 0xb6, 0x88, 0x20)] +interface IWbemLevel1Login(IWbemLevel1LoginVtbl): IUnknown(IUnknownVtbl) { + fn EstablishPosition( + wszLocaleList: LPWSTR, + dwNumLocales: DWORD, + reserved: *mut DWORD, + ) -> HRESULT, + fn RequestChallenge( + wszNetworkResource: LPWSTR, + wszUser: LPWSTR, + Nonce: WBEM_128BITS, + ) -> HRESULT, + fn WBEMLogin( + wszPreferredLocale: LPWSTR, + AccessToken: WBEM_128BITS, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppNamespace: *mut *mut IWbemServices, + ) -> HRESULT, + fn NTLMLogin( + wszNetworkResource: LPWSTR, + wszPreferredLocale: LPWSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + ppNamespace: *mut *mut IWbemServices, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemConnectorLogin; +DEFINE_GUID!{IID_IWbemConnectorLogin, + 0xd8ec9cb1, 0xb135, 0x4f10, 0x8b, 0x1b, 0xc7, 0x18, 0x8b, 0xb0, 0xd1, 0x86} +RIDL!{#[uuid(0xd8ec9cb1, 0xb135, 0x4f10, 0x8b, 0x1b, 0xc7, 0x18, 0x8b, 0xb0, 0xd1, 0x86)] +interface IWbemConnectorLogin(IWbemConnectorLoginVtbl): IUnknown(IUnknownVtbl) { + fn ConnectorLogin( + wszNetworkResource: LPWSTR, + wszPreferredLocale: LPWSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + riid: REFIID, + pInterface: *mut *mut c_void, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemAddressResolution; +DEFINE_GUID!{IID_IWbemAddressResolution, + 0xf7ce2e12, 0x8c90, 0x11d1, 0x9e, 0x7b, 0x00, 0xc0, 0x4f, 0xc3, 0x24, 0xa8} +RIDL!{#[uuid(0xf7ce2e12, 0x8c90, 0x11d1, 0x9e, 0x7b, 0x00, 0xc0, 0x4f, 0xc3, 0x24, 0xa8)] +interface IWbemAddressResolution(IWbemAddressResolutionVtbl): IUnknown(IUnknownVtbl) { + fn Resolve( + wszNamespacePath: LPWSTR, + wszAddressType: LPWSTR, + pdwAddressLength: *mut DWORD, + pabBinaryAddress: *mut *mut BYTE, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_WbemLevel1Login, + 0x8BC3F05E, 0xD86B, 0x11d0, 0xA0, 0x75, 0x00, 0xC0, 0x4F, 0xB6, 0x88, 0x20} +// class DECLSPEC_UUID("8BC3F05E-D86B-11d0-A075-00C04FB68820") +// WbemLevel1Login; +DEFINE_GUID!{CLSID_WbemLocalAddrRes, + 0xA1044801, 0x8F7E, 0x11d1, 0x9E, 0x7C, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8} +// class DECLSPEC_UUID("A1044801-8F7E-11d1-9E7C-00C04FC324A8") +// WbemLocalAddrRes; +DEFINE_GUID!{CLSID_WbemUninitializedClassObject, + 0x7a0227f6, 0x7108, 0x11d1, 0xad, 0x90, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +// class DECLSPEC_UUID("7a0227f6-7108-11d1-ad90-00c04fd8fdff") +// WbemUninitializedClassObject; +// EXTERN_C const IID IID_IWbemClientTransport; +DEFINE_GUID!{IID_IWbemClientTransport, + 0xf7ce2e11, 0x8c90, 0x11d1, 0x9e, 0x7b, 0x00, 0xc0, 0x4f, 0xc3, 0x24, 0xa8} +RIDL!{#[uuid(0xf7ce2e11, 0x8c90, 0x11d1, 0x9e, 0x7b, 0x00, 0xc0, 0x4f, 0xc3, 0x24, 0xa8)] +interface IWbemClientTransport(IWbemClientTransportVtbl): IUnknown(IUnknownVtbl) { + fn ConnectServer( + strAddressType: BSTR, + dwBinaryAddressLength: DWORD, + abBinaryAddress: *mut BYTE, + strNetworkResource: BSTR, + strUser: BSTR, + strPassword: BSTR, + strLocale: BSTR, + lSecurityFlags: c_long, + strAuthority: BSTR, + pCtx: *mut IWbemContext, + ppNamespace: *mut *mut IWbemServices, + ) -> HRESULT, +}} +// EXTERN_C const IID IID_IWbemClientConnectionTransport; +DEFINE_GUID!{IID_IWbemClientConnectionTransport, + 0xa889c72a, 0xfcc1, 0x4a9e, 0xaf, 0x61, 0xed, 0x07, 0x13, 0x33, 0xfb, 0x5b} +RIDL!{#[uuid(0xa889c72a, 0xfcc1, 0x4a9e, 0xaf, 0x61, 0xed, 0x07, 0x13, 0x33, 0xfb, 0x5b)] +interface IWbemClientConnectionTransport(IWbemClientConnectionTransportVtbl): + IUnknown(IUnknownVtbl) { + fn Open( + strAddressType: BSTR, + dwBinaryAddressLength: DWORD, + abBinaryAddress: *mut BYTE, + strObject: BSTR, + strUser: BSTR, + strPassword: BSTR, + strLocale: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + riid: REFIID, + pInterface: *mut *mut c_void, + pCallRes: *mut *mut IWbemCallResult, + ) -> HRESULT, + fn OpenAsync( + strAddressType: BSTR, + dwBinaryAddressLength: DWORD, + abBinaryAddress: *mut BYTE, + strObject: BSTR, + strUser: BSTR, + strPassword: BSTR, + strLocale: BSTR, + lFlags: c_long, + pCtx: *mut IWbemContext, + riid: REFIID, + pResponseHandler: *mut IWbemObjectSink, + ) -> HRESULT, + fn Cancel( + lFlags: c_long, + pHandler: *mut IWbemObjectSink, + ) -> HRESULT, +}} +DEFINE_GUID!{CLSID_WbemDCOMTransport, + 0xF7CE2E13, 0x8C90, 0x11d1, 0x9E, 0x7B, 0x00, 0xC0, 0x4F, 0xC3, 0x24, 0xA8} +// class DECLSPEC_UUID("F7CE2E13-8C90-11d1-9E7B-00C04FC324A8") +// WbemDCOMTransport; +// EXTERN_C const IID IID_IWbemConstructClassObject; +DEFINE_GUID!{IID_IWbemConstructClassObject, + 0x9ef76194, 0x70d5, 0x11d1, 0xad, 0x90, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff} +RIDL!{#[uuid(0x9ef76194, 0x70d5, 0x11d1, 0xad, 0x90, 0x00, 0xc0, 0x4f, 0xd8, 0xfd, 0xff)] +interface IWbemConstructClassObject(IWbemConstructClassObjectVtbl): IUnknown(IUnknownVtbl) { + fn SetInheritanceChain( + lNumAntecedents: c_long, + awszAntecedents: *mut LPWSTR, + ) -> HRESULT, + fn SetPropertyOrigin( + wszPropertyName: LPCWSTR, + lOriginIndex: c_long, + ) -> HRESULT, + fn SetMethodOrigin( + wszMethodName: LPCWSTR, + lOriginIndex: c_long, + ) -> HRESULT, + fn SetServerNamespace( + wszServer: LPCWSTR, + wszNamespace: LPCWSTR, + ) -> HRESULT, +}} +// extern RPC_IF_HANDLE __MIDL_itf_wbemtran_0000_0008_v0_0_c_ifspec; +// extern RPC_IF_HANDLE __MIDL_itf_wbemtran_0000_0008_v0_0_s_ifspec; diff --git a/winapi/src/um/wct.rs b/winapi/src/um/wct.rs new file mode 100644 index 000000000..0c3fae910 --- /dev/null +++ b/winapi/src/um/wct.rs @@ -0,0 +1,114 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_int; +use shared::basetsd::{DWORD_PTR, SIZE_T}; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, LPBOOL, LPDWORD, PULONG}; +use um::winnt::{HRESULT, LARGE_INTEGER, WCHAR}; +ENUM!{enum WCT_OBJECT_TYPE { + WctCriticalSectionType = 1, + WctSendMessageType, + WctMutexType, + WctAlpcType, + WctComType, + WctThreadWaitType, + WctProcessWaitType, + WctThreadType, + WctComActivationType, + WctUnknownType, + WctSocketIoType, + WctSmbIoType, + WctMaxType, +}} +ENUM!{enum WCT_OBJECT_STATUS { + WctStatusNoAccess = 1, + WctStatusRunning, + WctStatusBlocked, + WctStatusPidOnly, + WctStatusPidOnlyRpcss, + WctStatusOwned, + WctStatusNotOwned, + WctStatusAbandoned, + WctStatusUnknown, + WctStatusError, + WctStatusMax, +}} +pub const WCT_MAX_NODE_COUNT: SIZE_T = 16; +pub const WCT_OBJNAME_LENGTH: SIZE_T = 128; +STRUCT!{struct WAITCHAIN_NODE_INFO_LOCK_OBJECT { + ObjectName: [WCHAR; WCT_OBJNAME_LENGTH], + Timeout: LARGE_INTEGER, + Alertable: BOOL, +}} +STRUCT!{struct WAITCHAIN_NODE_INFO_THREAD_OBJECT { + ProcessId: DWORD, + ThreadId: DWORD, + WaitTime: DWORD, + ContextSwitches: DWORD, +}} +UNION!{union WAITCHAIN_NODE_INFO_u { + [u64; 34], + LockObject LockObject_mut: WAITCHAIN_NODE_INFO_LOCK_OBJECT, + ThreadObject ThreadObject_mut: WAITCHAIN_NODE_INFO_THREAD_OBJECT, +}} +STRUCT!{struct WAITCHAIN_NODE_INFO { + ObjectType: WCT_OBJECT_TYPE, + ObjectStatus: WCT_OBJECT_STATUS, + u: WAITCHAIN_NODE_INFO_u, +}} +pub type PWAITCHAIN_NODE_INFO = *mut WAITCHAIN_NODE_INFO; +DECLARE_HANDLE!{HWCT, HWCT__} +FN!{cdecl PWAITCHAINCALLBACK( + WctHandle: HWCT, + Context: DWORD_PTR, + CallbackStatus: DWORD, + NodeCount: LPDWORD, + NodeInfoArray: PWAITCHAIN_NODE_INFO, + IsCycle: LPBOOL, +) -> ()} +pub const WCT_ASYNC_OPEN_FLAG: DWORD = 1; +pub const WCTP_OPEN_ALL_FLAGS: DWORD = WCT_ASYNC_OPEN_FLAG; +extern "system" { + pub fn OpenThreadWaitChainSession( + Flags: DWORD, + callback: PWAITCHAINCALLBACK, + ) -> HWCT; + pub fn CloseThreadWaitChainSession( + WctHandle: HWCT, + ); +} +pub const WCT_OUT_OF_PROC_FLAG: DWORD = 0x1; +pub const WCT_OUT_OF_PROC_COM_FLAG: DWORD = 0x2; +pub const WCT_OUT_OF_PROC_CS_FLAG: DWORD = 0x4; +pub const WCT_NETWORK_IO_FLAG: DWORD = 0x8; +pub const WCTP_GETINFO_ALL_FLAGS: DWORD = WCT_OUT_OF_PROC_FLAG | WCT_OUT_OF_PROC_COM_FLAG + | WCT_OUT_OF_PROC_CS_FLAG; +extern "system" { + pub fn GetThreadWaitChain( + WctHandle: HWCT, + Context: DWORD_PTR, + Flags: DWORD, + ThreadId: DWORD, + NodeCount: LPDWORD, + NodeInfoArray: PWAITCHAIN_NODE_INFO, + IsCycle: LPBOOL, + ) -> BOOL; +} +FN!{cdecl PCOGETCALLSTATE( + c_int, + PULONG, +) -> HRESULT} +FN!{cdecl PCOGETACTIVATIONSTATE( + GUID, + DWORD, + *mut DWORD, +) -> HRESULT} +extern "system" { + pub fn RegisterWaitChainCOMCallback( + CallStateCallback: PCOGETCALLSTATE, + ActivationStateCallback: PCOGETACTIVATIONSTATE, + ); +} diff --git a/winapi/src/um/werapi.rs b/winapi/src/um/werapi.rs new file mode 100644 index 000000000..6eae64e90 --- /dev/null +++ b/winapi/src/um/werapi.rs @@ -0,0 +1,53 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Function prototypes for Windows Error Reporting (WER) +use shared::minwindef::{BOOL, DWORD, PDWORD}; +use um::winnt::{HANDLE, HRESULT, PCWSTR, PVOID}; +ENUM!{enum WER_REGISTER_FILE_TYPE { + WerRegFileTypeUserDocument = 1, + WerRegFileTypeOther = 2, + WerRegFileTypeMax, +}} +extern "system" { + pub fn WerRegisterFile( + pwzFile: PCWSTR, + regFileType: WER_REGISTER_FILE_TYPE, + dwFlags: DWORD, + ) -> HRESULT; + pub fn WerUnregisterFile( + pwzFilePath: PCWSTR, + ) -> HRESULT; + pub fn WerRegisterMemoryBlock( + pvAddress: PVOID, + dwSize: DWORD, + ) -> HRESULT; + pub fn WerUnregisterMemoryBlock( + pvAddress: PVOID, + ) -> HRESULT; + pub fn WerSetFlags( + dwFlags: DWORD, + ) -> HRESULT; + pub fn WerGetFlags( + hProcess: HANDLE, + pdwFlags: PDWORD, + ) -> HRESULT; + pub fn WerAddExcludedApplication( + pwzExeName: PCWSTR, + bAllUsers: BOOL, + ) -> HRESULT; + pub fn WerRemoveExcludedApplication( + pwzExeName: PCWSTR, + bAllUsers: BOOL, + ) -> HRESULT; + pub fn WerRegisterRuntimeExceptionModule( + pwszOutOfProcessCallbackDll: PCWSTR, + pContext: PVOID, + ) -> HRESULT; + pub fn WerUnregisterRuntimeExceptionModule( + pwszOutOfProcessCallbackDll: PCWSTR, + pContext: PVOID, + ) -> HRESULT; +} diff --git a/winapi/src/um/winbase.rs b/winapi/src/um/winbase.rs new file mode 100644 index 000000000..22db22a9b --- /dev/null +++ b/winapi/src/um/winbase.rs @@ -0,0 +1,2825 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the 32-Bit Windows Base APIs +use ctypes::{c_char, c_int, c_long, c_void}; +use shared::basetsd::{ + DWORD64, DWORD_PTR, LONG_PTR, PDWORD64, PDWORD_PTR, PSIZE_T, PULONG_PTR, SIZE_T, UINT_PTR, + ULONG_PTR, +}; +use shared::guiddef::GUID; +use shared::minwindef::{ + ATOM, BOOL, BYTE, DWORD, FARPROC, FILETIME, HFILE, HGLOBAL, HLOCAL, HMODULE, HRSRC, LPBOOL, + LPBYTE, LPCVOID, LPDWORD, LPFILETIME, LPVOID, LPWORD, PBOOL, PDWORD, PUCHAR, PULONG, PUSHORT, + UCHAR, UINT, ULONG, USHORT, WORD, +}; +use shared::windef::HWND; +use um::cfgmgr32::MAX_PROFILE_LEN; +use um::fileapi::STREAM_INFO_LEVELS; +use um::libloaderapi::{ + ENUMRESLANGPROCA, ENUMRESLANGPROCW, ENUMRESNAMEPROCA, ENUMRESTYPEPROCA, ENUMRESTYPEPROCW, +}; +use um::minwinbase::{ + FILE_INFO_BY_HANDLE_CLASS, FINDEX_INFO_LEVELS, FINDEX_SEARCH_OPS, GET_FILEEX_INFO_LEVELS, + LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE, LPSECURITY_ATTRIBUTES, PREASON_CONTEXT, +}; +use um::processthreadsapi::{ + LPPROC_THREAD_ATTRIBUTE_LIST, LPSTARTUPINFOA, STARTUPINFOA, STARTUPINFOW, +}; +use um::winnt::{ + BOOLEAN, CHAR, DWORDLONG, EXECUTION_STATE, FILE_ID_128, HANDLE, HRESULT, INT, LANGID, + LARGE_INTEGER, LATENCY_TIME, LONG, LPCCH, LPCH, LPCSTR, LPCWSTR, LPOSVERSIONINFOEXA, + LPOSVERSIONINFOEXW, LPSTR, LPWSTR, MAXLONG, PBOOLEAN, PCONTEXT, PCWSTR, PFIRMWARE_TYPE, + PHANDLE, PIO_COUNTERS, PJOB_SET_ARRAY, PLUID, POWER_REQUEST_TYPE, PPERFORMANCE_DATA, + PPROCESSOR_NUMBER, PQUOTA_LIMITS, PRTL_UMS_SCHEDULER_ENTRY_POINT, + PSECURE_MEMORY_CACHE_CALLBACK, PSID, PSID_NAME_USE, PULONGLONG, PVOID, PWOW64_CONTEXT, + PWOW64_LDT_ENTRY, PWSTR, RTL_UMS_THREAD_INFO_CLASS, STATUS_ABANDONED_WAIT_0, STATUS_USER_APC, + STATUS_WAIT_0, SecurityAnonymous, SecurityDelegation, SecurityIdentification, + SecurityImpersonation, THREAD_BASE_PRIORITY_IDLE, THREAD_BASE_PRIORITY_LOWRT, + THREAD_BASE_PRIORITY_MAX, THREAD_BASE_PRIORITY_MIN, ULARGE_INTEGER, VOID, WAITORTIMERCALLBACK, + WCHAR, WOW64_CONTEXT, +}; +#[cfg(target_arch = "x86")] +use um::winnt::PLDT_ENTRY; +use vc::vadefs::va_list; +pub const FILE_BEGIN: DWORD = 0; +pub const FILE_CURRENT: DWORD = 1; +pub const FILE_END: DWORD = 2; +pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; +pub const WAIT_OBJECT_0: DWORD = STATUS_WAIT_0 as u32; +pub const WAIT_ABANDONED: DWORD = STATUS_ABANDONED_WAIT_0 as u32; +pub const WAIT_ABANDONED_0: DWORD = STATUS_ABANDONED_WAIT_0 as u32; +pub const WAIT_IO_COMPLETION: DWORD = STATUS_USER_APC as u32; +pub const FILE_FLAG_WRITE_THROUGH: DWORD = 0x80000000; +pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000; +pub const FILE_FLAG_NO_BUFFERING: DWORD = 0x20000000; +pub const FILE_FLAG_RANDOM_ACCESS: DWORD = 0x10000000; +pub const FILE_FLAG_SEQUENTIAL_SCAN: DWORD = 0x08000000; +pub const FILE_FLAG_DELETE_ON_CLOSE: DWORD = 0x04000000; +pub const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; +pub const FILE_FLAG_POSIX_SEMANTICS: DWORD = 0x01000000; +pub const FILE_FLAG_SESSION_AWARE: DWORD = 0x00800000; +pub const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; +pub const FILE_FLAG_OPEN_NO_RECALL: DWORD = 0x00100000; +pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000; +pub const FILE_FLAG_OPEN_REQUIRING_OPLOCK: DWORD = 0x00040000; +pub const PROGRESS_CONTINUE: DWORD = 0; +pub const PROGRESS_CANCEL: DWORD = 1; +pub const PROGRESS_STOP: DWORD = 2; +pub const PROGRESS_QUIET: DWORD = 3; +pub const CALLBACK_CHUNK_FINISHED: DWORD = 0x00000000; +pub const CALLBACK_STREAM_SWITCH: DWORD = 0x00000001; +pub const COPY_FILE_FAIL_IF_EXISTS: DWORD = 0x00000001; +pub const COPY_FILE_RESTARTABLE: DWORD = 0x00000002; +pub const COPY_FILE_OPEN_SOURCE_FOR_WRITE: DWORD = 0x00000004; +pub const COPY_FILE_ALLOW_DECRYPTED_DESTINATION: DWORD = 0x00000008; +pub const COPY_FILE_COPY_SYMLINK: DWORD = 0x00000800; +pub const COPY_FILE_NO_BUFFERING: DWORD = 0x00001000; +pub const COPY_FILE_REQUEST_SECURITY_PRIVILEGES: DWORD = 0x00002000; +pub const COPY_FILE_RESUME_FROM_PAUSE: DWORD = 0x00004000; +pub const COPY_FILE_NO_OFFLOAD: DWORD = 0x00040000; +pub const COPY_FILE_IGNORE_EDP_BLOCK: DWORD = 0x00400000; +pub const COPY_FILE_IGNORE_SOURCE_ENCRYPTION: DWORD = 0x00800000; +pub const REPLACEFILE_WRITE_THROUGH: DWORD = 0x00000001; +pub const REPLACEFILE_IGNORE_MERGE_ERRORS: DWORD = 0x00000002; +pub const REPLACEFILE_IGNORE_ACL_ERRORS: DWORD = 0x00000004; +pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001; +pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002; +pub const PIPE_ACCESS_DUPLEX: DWORD = 0x00000003; +pub const PIPE_CLIENT_END: DWORD = 0x00000000; +pub const PIPE_SERVER_END: DWORD = 0x00000001; +pub const PIPE_WAIT: DWORD = 0x00000000; +pub const PIPE_NOWAIT: DWORD = 0x00000001; +pub const PIPE_READMODE_BYTE: DWORD = 0x00000000; +pub const PIPE_READMODE_MESSAGE: DWORD = 0x00000002; +pub const PIPE_TYPE_BYTE: DWORD = 0x00000000; +pub const PIPE_TYPE_MESSAGE: DWORD = 0x00000004; +pub const PIPE_ACCEPT_REMOTE_CLIENTS: DWORD = 0x00000000; +pub const PIPE_REJECT_REMOTE_CLIENTS: DWORD = 0x00000008; +pub const PIPE_UNLIMITED_INSTANCES: DWORD = 255; +pub const SECURITY_ANONYMOUS: DWORD = SecurityAnonymous << 16; +pub const SECURITY_IDENTIFICATION: DWORD = SecurityIdentification << 16; +pub const SECURITY_IMPERSONATION: DWORD = SecurityImpersonation << 16; +pub const SECURITY_DELEGATION: DWORD = SecurityDelegation << 16; +pub const SECURITY_CONTEXT_TRACKING: DWORD = 0x00040000; +pub const SECURITY_EFFECTIVE_ONLY: DWORD = 0x00080000; +pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000; +pub const SECURITY_VALID_SQOS_FLAGS: DWORD = 0x001F0000; +FN!{stdcall PFIBER_START_ROUTINE( + lpFiberParameter: LPVOID, +) -> ()} +pub type LPFIBER_START_ROUTINE = PFIBER_START_ROUTINE; +FN!{stdcall PFIBER_CALLOUT_ROUTINE( + lpParameter: LPVOID, +) -> LPVOID} +// FAIL_FAST_* +#[cfg(target_arch = "x86")] +pub type LPLDT_ENTRY = PLDT_ENTRY; +#[cfg(not(target_arch = "x86"))] +pub type LPLDT_ENTRY = LPVOID; // TODO - fix this for 32-bit +//SP_SERIALCOMM +//PST_* +// PCF_* +// SP_* +// BAUD_* +// DATABITS_* +// STOPBITS_* +// PARITY_* +STRUCT!{struct COMMPROP { + wPacketLength: WORD, + wPacketVersion: WORD, + dwServiceMask: DWORD, + dwReserved1: DWORD, + dwMaxTxQueue: DWORD, + dwMaxRxQueue: DWORD, + dwMaxBaud: DWORD, + dwProvSubType: DWORD, + dwProvCapabilities: DWORD, + dwSettableParams: DWORD, + dwSettableBaud: DWORD, + wSettableData: WORD, + wSettableStopParity: WORD, + dwCurrentTxQueue: DWORD, + dwCurrentRxQueue: DWORD, + dwProvSpec1: DWORD, + dwProvSpec2: DWORD, + wcProvChar: [WCHAR; 1], +}} +pub type LPCOMMPROP = *mut COMMPROP; +STRUCT!{struct COMSTAT { + BitFields: DWORD, + cbInQue: DWORD, + cbOutQue: DWORD, +}} +BITFIELD!{COMSTAT BitFields: DWORD [ + fCtsHold set_fCtsHold[0..1], + fDsrHold set_fDsrHold[1..2], + fRlsdHold set_fRlsdHold[2..3], + fXoffHold set_fXoffHold[3..4], + fXoffSent set_fXoffSent[4..5], + fEof set_fEof[5..6], + fTxim set_fTxim[6..7], + fReserved set_fReserved[7..32], +]} +pub type LPCOMSTAT = *mut COMSTAT; +pub const DTR_CONTROL_DISABLE: DWORD = 0x00; +pub const DTR_CONTROL_ENABLE: DWORD = 0x01; +pub const DTR_CONTROL_HANDSHAKE: DWORD = 0x02; +pub const RTS_CONTROL_DISABLE: DWORD = 0x00; +pub const RTS_CONTROL_ENABLE: DWORD = 0x01; +pub const RTS_CONTROL_HANDSHAKE: DWORD = 0x02; +pub const RTS_CONTROL_TOGGLE: DWORD = 0x03; +STRUCT!{struct DCB { + DCBlength: DWORD, + BaudRate: DWORD, + BitFields: DWORD, + wReserved: WORD, + XonLim: WORD, + XoffLim: WORD, + ByteSize: BYTE, + Parity: BYTE, + StopBits: BYTE, + XonChar: c_char, + XoffChar: c_char, + ErrorChar: c_char, + EofChar: c_char, + EvtChar: c_char, + wReserved1: WORD, +}} +BITFIELD!{DCB BitFields: DWORD [ + fBinary set_fBinary[0..1], + fParity set_fParity[1..2], + fOutxCtsFlow set_fOutxCtsFlow[2..3], + fOutxDsrFlow set_fOutxDsrFlow[3..4], + fDtrControl set_fDtrControl[4..6], + fDsrSensitivity set_fDsrSensitivity[6..7], + fTXContinueOnXoff set_fTXContinueOnXoff[7..8], + fOutX set_fOutX[8..9], + fInX set_fInX[9..10], + fErrorChar set_fErrorChar[10..11], + fNull set_fNull[11..12], + fRtsControl set_fRtsControl[12..14], + fAbortOnError set_fAbortOnError[14..15], + fDummy2 set_fDummy2[15..32], +]} +pub type LPDCB = *mut DCB; +STRUCT!{struct COMMTIMEOUTS { + ReadIntervalTimeout: DWORD, + ReadTotalTimeoutMultiplier: DWORD, + ReadTotalTimeoutConstant: DWORD, + WriteTotalTimeoutMultiplier: DWORD, + WriteTotalTimeoutConstant: DWORD, +}} +pub type LPCOMMTIMEOUTS = *mut COMMTIMEOUTS; +STRUCT!{struct COMMCONFIG { + dwSize: DWORD, + wVersion: WORD, + wReserved: WORD, + dcb: DCB, + dwProviderSubType: DWORD, + dwProviderOffset: DWORD, + dwProviderSize: DWORD, + wcProviderData: [WCHAR; 1], +}} +pub type LPCOMMCONFIG = *mut COMMCONFIG; +pub const GMEM_FIXED: UINT = 0x0000; +pub const GMEM_MOVEABLE: UINT = 0x0002; +pub const GMEM_NOCOMPACT: UINT = 0x0010; +pub const GMEM_NODISCARD: UINT = 0x0020; +pub const GMEM_ZEROINIT: UINT = 0x0040; +pub const GMEM_MODIFY: UINT = 0x0080; +pub const GMEM_DISCARDABLE: UINT = 0x0100; +pub const GMEM_NOT_BANKED: UINT = 0x1000; +pub const GMEM_SHARE: UINT = 0x2000; +pub const GMEM_DDESHARE: UINT = 0x2000; +pub const GMEM_NOTIFY: UINT = 0x4000; +pub const GMEM_LOWER: UINT = GMEM_NOT_BANKED; +pub const GMEM_VALID_FLAGS: UINT = 0x7F72; +pub const GMEM_INVALID_HANDLE: UINT = 0x8000; +pub const GHND: UINT = GMEM_MOVEABLE | GMEM_ZEROINIT; +pub const GPTR: UINT = GMEM_FIXED | GMEM_ZEROINIT; +pub const GMEM_DISCARDED: UINT = 0x4000; +pub const GMEM_LOCKCOUNT: UINT = 0x00FF; +STRUCT!{struct MEMORYSTATUS { + dwLength: DWORD, + dwMemoryLoad: DWORD, + dwTotalPhys: SIZE_T, + dwAvailPhys: SIZE_T, + dwTotalPageFile: SIZE_T, + dwAvailPageFile: SIZE_T, + dwTotalVirtual: SIZE_T, + dwAvailVirtual: SIZE_T, +}} +pub type LPMEMORYSTATUS = *mut MEMORYSTATUS; +// NUMA_NO_PREFERRED_NODE +pub const DEBUG_PROCESS: DWORD = 0x00000001; +pub const DEBUG_ONLY_THIS_PROCESS: DWORD = 0x00000002; +pub const CREATE_SUSPENDED: DWORD = 0x00000004; +pub const DETACHED_PROCESS: DWORD = 0x00000008; +pub const CREATE_NEW_CONSOLE: DWORD = 0x00000010; +pub const NORMAL_PRIORITY_CLASS: DWORD = 0x00000020; +pub const IDLE_PRIORITY_CLASS: DWORD = 0x00000040; +pub const HIGH_PRIORITY_CLASS: DWORD = 0x00000080; +pub const REALTIME_PRIORITY_CLASS: DWORD = 0x00000100; +pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; +pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; +pub const CREATE_SEPARATE_WOW_VDM: DWORD = 0x00000800; +pub const CREATE_SHARED_WOW_VDM: DWORD = 0x00001000; +pub const CREATE_FORCEDOS: DWORD = 0x00002000; +pub const BELOW_NORMAL_PRIORITY_CLASS: DWORD = 0x00004000; +pub const ABOVE_NORMAL_PRIORITY_CLASS: DWORD = 0x00008000; +pub const INHERIT_PARENT_AFFINITY: DWORD = 0x00010000; +pub const INHERIT_CALLER_PRIORITY: DWORD = 0x00020000; +pub const CREATE_PROTECTED_PROCESS: DWORD = 0x00040000; +pub const EXTENDED_STARTUPINFO_PRESENT: DWORD = 0x00080000; +pub const PROCESS_MODE_BACKGROUND_BEGIN: DWORD = 0x00100000; +pub const PROCESS_MODE_BACKGROUND_END: DWORD = 0x00200000; +pub const CREATE_BREAKAWAY_FROM_JOB: DWORD = 0x01000000; +pub const CREATE_PRESERVE_CODE_AUTHZ_LEVEL: DWORD = 0x02000000; +pub const CREATE_DEFAULT_ERROR_MODE: DWORD = 0x04000000; +pub const CREATE_NO_WINDOW: DWORD = 0x08000000; +pub const PROFILE_USER: DWORD = 0x10000000; +pub const PROFILE_KERNEL: DWORD = 0x20000000; +pub const PROFILE_SERVER: DWORD = 0x40000000; +pub const CREATE_IGNORE_SYSTEM_DEFAULT: DWORD = 0x80000000; +// STACK_SIZE_PARAM_IS_A_RESERVATION +pub const THREAD_PRIORITY_LOWEST: DWORD = THREAD_BASE_PRIORITY_MIN; +pub const THREAD_PRIORITY_BELOW_NORMAL: DWORD = THREAD_PRIORITY_LOWEST + 1; +pub const THREAD_PRIORITY_NORMAL: DWORD = 0; +pub const THREAD_PRIORITY_HIGHEST: DWORD = THREAD_BASE_PRIORITY_MAX; +pub const THREAD_PRIORITY_ABOVE_NORMAL: DWORD = THREAD_PRIORITY_HIGHEST - 1; +pub const THREAD_PRIORITY_ERROR_RETURN: DWORD = MAXLONG as u32; +pub const THREAD_PRIORITY_TIME_CRITICAL: DWORD = THREAD_BASE_PRIORITY_LOWRT; +pub const THREAD_PRIORITY_IDLE: DWORD = THREAD_BASE_PRIORITY_IDLE; +pub const THREAD_MODE_BACKGROUND_BEGIN: DWORD = 0x00010000; +pub const THREAD_MODE_BACKGROUND_END: DWORD = 0x00020000; +pub const VOLUME_NAME_DOS: DWORD = 0x0; +// VOLUME_NAME_* +// FILE_NAME_* +// JIT_DEBUG_* +pub const DRIVE_UNKNOWN: DWORD = 0; +pub const DRIVE_NO_ROOT_DIR: DWORD = 1; +pub const DRIVE_REMOVABLE: DWORD = 2; +pub const DRIVE_FIXED: DWORD = 3; +pub const DRIVE_REMOTE: DWORD = 4; +pub const DRIVE_CDROM: DWORD = 5; +pub const DRIVE_RAMDISK: DWORD = 6; +// pub fn GetFreeSpace(); +pub const FILE_TYPE_UNKNOWN: DWORD = 0x0000; +pub const FILE_TYPE_DISK: DWORD = 0x0001; +pub const FILE_TYPE_CHAR: DWORD = 0x0002; +pub const FILE_TYPE_PIPE: DWORD = 0x0003; +pub const FILE_TYPE_REMOTE: DWORD = 0x8000; +pub const STD_INPUT_HANDLE: DWORD = -10i32 as u32; +pub const STD_OUTPUT_HANDLE: DWORD = -11i32 as u32; +pub const STD_ERROR_HANDLE: DWORD = -12i32 as u32; +pub const NOPARITY: BYTE = 0; +pub const ODDPARITY: BYTE = 1; +pub const EVENPARITY: BYTE = 2; +pub const MARKPARITY: BYTE = 3; +pub const SPACEPARITY: BYTE = 4; +pub const ONESTOPBIT: BYTE = 0; +pub const ONE5STOPBITS: BYTE = 1; +pub const TWOSTOPBITS: BYTE = 2; +pub const IGNORE: DWORD = 0; +pub const INFINITE: DWORD = 0xFFFFFFFF; +pub const CBR_110: DWORD = 110; +pub const CBR_300: DWORD = 300; +pub const CBR_600: DWORD = 600; +pub const CBR_1200: DWORD = 1200; +pub const CBR_2400: DWORD = 2400; +pub const CBR_4800: DWORD = 4800; +pub const CBR_9600: DWORD = 9600; +pub const CBR_14400: DWORD = 14400; +pub const CBR_19200: DWORD = 19200; +pub const CBR_38400: DWORD = 38400; +pub const CBR_56000: DWORD = 56000; +pub const CBR_57600: DWORD = 57600; +pub const CBR_115200: DWORD = 115200; +pub const CBR_128000: DWORD = 128000; +pub const CBR_256000: DWORD = 256000; +// CE_* +// IE_* +// EV_* +pub const SETXOFF: DWORD = 1; +pub const SETXON: DWORD = 2; +pub const SETRTS: DWORD = 3; +pub const CLRRTS: DWORD = 4; +pub const SETDTR: DWORD = 5; +pub const CLRDTR: DWORD = 6; +pub const RESETDEV: DWORD = 7; +pub const SETBREAK: DWORD = 8; +pub const CLRBREAK: DWORD = 9; +pub const PURGE_TXABORT: DWORD = 0x0001; +pub const PURGE_RXABORT: DWORD = 0x0002; +pub const PURGE_TXCLEAR: DWORD = 0x0004; +pub const PURGE_RXCLEAR: DWORD = 0x0008; +pub const MS_CTS_ON: DWORD = 0x0010; +pub const MS_DSR_ON: DWORD = 0x0020; +pub const MS_RING_ON: DWORD = 0x0040; +pub const MS_RLSD_ON: DWORD = 0x0080; +// S_* +// NMPWAIT_* +// FS_* +// OF_* +pub const OFS_MAXPATHNAME: usize = 128; +STRUCT!{struct OFSTRUCT { + cBytes: BYTE, + fFixedDisk: BYTE, + nErrCode: WORD, + Reserved1: WORD, + Reserved2: WORD, + szPathName: [CHAR; OFS_MAXPATHNAME], +}} +pub type POFSTRUCT = *mut OFSTRUCT; +pub type LPOFSTRUCT = *mut OFSTRUCT; +extern "system" { + pub fn GlobalAlloc( + uFlags: UINT, + dwBytes: SIZE_T, + ) -> HGLOBAL; + pub fn GlobalReAlloc( + hMem: HGLOBAL, + dwBytes: SIZE_T, + uFlags: UINT, + ) -> HGLOBAL; + pub fn GlobalSize( + hMem: HGLOBAL, + ) -> SIZE_T; + pub fn GlobalFlags( + hMem: HGLOBAL, + ) -> UINT; + pub fn GlobalLock( + hMem: HGLOBAL, + ) -> LPVOID; + pub fn GlobalHandle( + pMem: LPCVOID, + ) -> HGLOBAL; + pub fn GlobalUnlock( + hMem: HGLOBAL, + ) -> BOOL; + pub fn GlobalFree( + hMem: HGLOBAL, + ) -> HGLOBAL; + pub fn GlobalCompact( + dwMinFree: DWORD, + ) -> SIZE_T; + pub fn GlobalFix( + hMem: HGLOBAL, + ); + pub fn GlobalUnfix( + hMem: HGLOBAL, + ); + pub fn GlobalWire( + hMem: HGLOBAL, + ) -> LPVOID; + pub fn GlobalUnWire( + hMem: HGLOBAL, + ) -> BOOL; + pub fn GlobalMemoryStatus( + lpBuffer: LPMEMORYSTATUS, + ); + pub fn LocalAlloc( + uFlags: UINT, + uBytes: SIZE_T, + ) -> HLOCAL; + pub fn LocalReAlloc( + hMem: HLOCAL, + uBytes: SIZE_T, + uFlags: UINT, + ) -> HLOCAL; + pub fn LocalLock( + hMem: HLOCAL, + ) -> LPVOID; + pub fn LocalHandle( + pMem: LPCVOID, + ) -> HLOCAL; + pub fn LocalUnlock( + hMem: HLOCAL, + ) -> BOOL; + pub fn LocalSize( + hMem: HLOCAL, + ) -> SIZE_T; + pub fn LocalFlags( + hMem: HLOCAL, + ) -> UINT; + pub fn LocalFree( + hMem: HLOCAL, + ) -> HLOCAL; + pub fn LocalShrink( + hMem: HLOCAL, + cbNewSize: UINT, + ) -> SIZE_T; + pub fn LocalCompact( + uMinFree: UINT, + ) -> SIZE_T; +} +// SCS_* +extern "system" { + pub fn GetBinaryTypeA( + lpApplicationName: LPCSTR, + lpBinaryType: LPDWORD, + ) -> BOOL; + pub fn GetBinaryTypeW( + lpApplicationName: LPCWSTR, + lpBinaryType: LPDWORD, + ) -> BOOL; + pub fn GetShortPathNameA( + lpszLongPath: LPCSTR, + lpszShortPath: LPSTR, + cchBuffer: DWORD, + ) -> DWORD; + pub fn GetLongPathNameTransactedA( + lpszShortPath: LPCSTR, + lpszLongPath: LPSTR, + cchBuffer: DWORD, + hTransaction: HANDLE, + ) -> DWORD; + pub fn GetLongPathNameTransactedW( + lpszShortPath: LPCWSTR, + lpszLongPath: LPWSTR, + cchBuffer: DWORD, + hTransaction: HANDLE, + ) -> DWORD; + pub fn GetProcessAffinityMask( + hProcess: HANDLE, + lpProcessAffinityMask: PDWORD_PTR, + lpSystemAffinityMask: PDWORD_PTR, + ) -> BOOL; + pub fn SetProcessAffinityMask( + hProcess: HANDLE, + dwProcessAffinityMask: DWORD, + ) -> BOOL; + pub fn GetProcessIoCounters( + hProcess: HANDLE, + lpIoCounters: PIO_COUNTERS, + ) -> BOOL; + pub fn GetProcessWorkingSetSize( + hProcess: HANDLE, + lpMinimumWorkingSetSize: PSIZE_T, + lpMaximumWorkingSetSize: PSIZE_T, + ) -> BOOL; + pub fn SetProcessWorkingSetSize( + hProcess: HANDLE, + dwMinimumWorkingSetSize: SIZE_T, + dwMaximumWorkingSetSize: SIZE_T, + ) -> BOOL; + pub fn FatalExit( + ExitCode: c_int, + ); + pub fn SetEnvironmentStringsA( + NewEnvironment: LPCH, + ) -> BOOL; + pub fn SwitchToFiber( + lpFiber: LPVOID, + ); + pub fn DeleteFiber( + lpFiber: LPVOID, + ); + pub fn ConvertFiberToThread() -> BOOL; + pub fn CreateFiberEx( + dwStackCommitSize: SIZE_T, + dwStackReserveSize: SIZE_T, + dwFlags: DWORD, + lpStartAddress: LPFIBER_START_ROUTINE, + lpParameter: LPVOID, + ) -> LPVOID; + pub fn ConvertThreadToFiberEx( + lpParameter: LPVOID, + dwFlags: DWORD, + ) -> LPVOID; + pub fn CreateFiber( + dwStackSize: SIZE_T, + lpStartAddress: LPFIBER_START_ROUTINE, + lpParameter: LPVOID, + ) -> LPVOID; + pub fn ConvertThreadToFiber( + lpParameter: LPVOID, + ) -> LPVOID; +} +pub type PUMS_CONTEXT = *mut c_void; +pub type PUMS_COMPLETION_LIST = *mut c_void; +pub type UMS_THREAD_INFO_CLASS = RTL_UMS_THREAD_INFO_CLASS; +pub type PUMS_THREAD_INFO_CLASS = *mut UMS_THREAD_INFO_CLASS; +pub type PUMS_SCHEDULER_ENTRY_POINT = PRTL_UMS_SCHEDULER_ENTRY_POINT; +STRUCT!{struct UMS_SCHEDULER_STARTUP_INFO { + UmsVersion: ULONG, + CompletionList: PUMS_COMPLETION_LIST, + SchedulerProc: PUMS_SCHEDULER_ENTRY_POINT, + SchedulerParam: PVOID, +}} +pub type PUMS_SCHEDULER_STARTUP_INFO = *mut UMS_SCHEDULER_STARTUP_INFO; +STRUCT!{struct UMS_SYSTEM_THREAD_INFORMATION { + UmsVersion: ULONG, + ThreadUmsFlags: ULONG, +}} +BITFIELD!{UMS_SYSTEM_THREAD_INFORMATION ThreadUmsFlags: ULONG [ + IsUmsSchedulerThread set_IsUmsSchedulerThread[0..1], + IsUmsWorkerThread set_IsUmsWorkerThread[1..2], +]} +pub type PUMS_SYSTEM_THREAD_INFORMATION = *mut UMS_SYSTEM_THREAD_INFORMATION; +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn CreateUmsCompletionList( + UmsCompletionList: *mut PUMS_COMPLETION_LIST, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn DequeueUmsCompletionListItems( + UmsCompletionList: PUMS_COMPLETION_LIST, + WaitTimeOut: DWORD, + UmsThreadList: *mut PUMS_CONTEXT, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn GetUmsCompletionListEvent( + UmsCompletionList: PUMS_COMPLETION_LIST, + UmsCompletionEvent: PHANDLE, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn ExecuteUmsThread( + UmsThread: PUMS_CONTEXT, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn UmsThreadYield( + SchedulerParam: PVOID, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn DeleteUmsCompletionList( + UmsCompletionList: PUMS_COMPLETION_LIST, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn GetCurrentUmsThread() -> PUMS_CONTEXT; + #[cfg(target_pointer_width = "64")] + pub fn GetNextUmsListItem( + UmsContext: PUMS_CONTEXT, + ) -> PUMS_CONTEXT; + #[cfg(target_pointer_width = "64")] + pub fn QueryUmsThreadInformation( + UmsThread: PUMS_CONTEXT, + UmsThreadInfoClass: UMS_THREAD_INFO_CLASS, + UmsThreadInformation: PVOID, + UmsThreadInformationLength: ULONG, + ReturnLength: PULONG, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn SetUmsThreadInformation( + UmsThread: PUMS_CONTEXT, + UmsThreadInfoClass: UMS_THREAD_INFO_CLASS, + UmsThreadInformation: PVOID, + UmsThreadInformationLength: ULONG, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn DeleteUmsThreadContext( + UmsThread: PUMS_CONTEXT, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn CreateUmsThreadContext( + lpUmsThread: *mut PUMS_CONTEXT, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn EnterUmsSchedulingMode( + SchedulerStartupInfo: PUMS_SCHEDULER_STARTUP_INFO, + ) -> BOOL; + #[cfg(target_pointer_width = "64")] + pub fn GetUmsSystemThreadInformation( + ThreadHandle: HANDLE, + SystemThreadInfo: PUMS_SYSTEM_THREAD_INFORMATION, + ) -> BOOL; + pub fn SetThreadAffinityMask( + hThread: HANDLE, + dwThreadAffinityMask: DWORD_PTR, + ) -> DWORD_PTR; + pub fn SetProcessDEPPolicy( + dwFlags: DWORD, + ) -> BOOL; + pub fn GetProcessDEPPolicy( + hProcess: HANDLE, + lpFlags: LPDWORD, + lpPermanent: PBOOL, + ) -> BOOL; + pub fn RequestWakeupLatency( + latency: LATENCY_TIME, + ) -> BOOL; + pub fn IsSystemResumeAutomatic() -> BOOL; + pub fn GetThreadSelectorEntry( + hThread: HANDLE, + dwSelector: DWORD, + lpSelectorEntry: LPLDT_ENTRY, + ) -> BOOL; + pub fn SetThreadExecutionState( + esFlags: EXECUTION_STATE, + ) -> EXECUTION_STATE; + pub fn PowerCreateRequest( + Context: PREASON_CONTEXT, + ) -> HANDLE; + pub fn PowerSetRequest( + PowerRequest: HANDLE, + RequestType: POWER_REQUEST_TYPE, + ) -> BOOL; + pub fn PowerClearRequest( + PowerRequest: HANDLE, + RequestType: POWER_REQUEST_TYPE, + ) -> BOOL; + pub fn RestoreLastError( + dwErrCode: DWORD, + ); +} +pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS: UCHAR = 0x1; +pub const FILE_SKIP_SET_EVENT_ON_HANDLE: UCHAR = 0x2; +extern "system" { + pub fn SetFileCompletionNotificationModes( + FileHandle: HANDLE, + Flags: UCHAR, + ) -> BOOL; +} +pub const SEM_FAILCRITICALERRORS: UINT = 0x0001; +pub const SEM_NOGPFAULTERRORBOX: UINT = 0x0002; +pub const SEM_NOALIGNMENTFAULTEXCEPT: UINT = 0x0004; +pub const SEM_NOOPENFILEERRORBOX: UINT = 0x8000; +extern "system" { + pub fn Wow64GetThreadContext( + hThread: HANDLE, + lpContext: PWOW64_CONTEXT, + ) -> BOOL; + pub fn Wow64SetThreadContext( + hThread: HANDLE, + lpContext: *const WOW64_CONTEXT, + ) -> BOOL; + pub fn Wow64GetThreadSelectorEntry( + hThread: HANDLE, + dwSelector: DWORD, + lpSelectorEntry: PWOW64_LDT_ENTRY, + ) -> BOOL; + pub fn Wow64SuspendThread( + hThread: HANDLE, + ) -> DWORD; + pub fn DebugSetProcessKillOnExit( + KillOnExit: BOOL, + ) -> BOOL; + pub fn DebugBreakProcess( + Process: HANDLE, + ) -> BOOL; + pub fn PulseEvent( + hEvent: HANDLE, + ) -> BOOL; + pub fn GlobalDeleteAtom( + nAtom: ATOM, + ) -> ATOM; + pub fn InitAtomTable( + nSize: DWORD, + ) -> BOOL; + pub fn DeleteAtom( + nAtom: ATOM, + ) -> ATOM; + pub fn SetHandleCount( + uNumber: UINT, + ) -> UINT; + pub fn RequestDeviceWakeup( + hDevice: HANDLE, + ) -> BOOL; + pub fn CancelDeviceWakeupRequest( + hDevice: HANDLE, + ) -> BOOL; + pub fn GetDevicePowerState( + hDevice: HANDLE, + pfOn: *mut BOOL, + ) -> BOOL; + pub fn SetMessageWaitingIndicator( + hMsgIndicator: HANDLE, + ulMsgCount: ULONG, + ) -> BOOL; + pub fn SetFileShortNameA( + hFile: HANDLE, + lpShortName: LPCSTR, + ) -> BOOL; + pub fn SetFileShortNameW( + hFile: HANDLE, + lpShortName: LPCWSTR, + ) -> BOOL; +} +pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; +pub const HANDLE_FLAG_PROTECT_FROM_CLOSE: DWORD = 0x00000002; +extern "system" { + pub fn LoadModule( + lpModuleName: LPCSTR, + lpParameterBlock: LPVOID, + ) -> DWORD; + pub fn WinExec( + lpCmdLine: LPCSTR, + uCmdShow: UINT, + ) -> UINT; + // ClearCommBreak + // ClearCommError + // SetupComm + // EscapeCommFunction + // GetCommConfig + // GetCommMask + // GetCommProperties + // GetCommModemStatus + // GetCommState + // GetCommTimeouts + // PurgeComm + // SetCommBreak + // SetCommConfig + // SetCommMask + // SetCommState + // SetCommTimeouts + // TransmitCommChar + // WaitCommEvent + pub fn SetTapePosition( + hDevice: HANDLE, + dwPositionMethod: DWORD, + dwPartition: DWORD, + dwOffsetLow: DWORD, + dwOffsetHigh: DWORD, + bImmediate: BOOL, + ) -> DWORD; + pub fn GetTapePosition( + hDevice: HANDLE, + dwPositionType: DWORD, + lpdwPartition: LPDWORD, + lpdwOffsetLow: LPDWORD, + lpdwOffsetHigh: LPDWORD, + ) -> DWORD; + pub fn PrepareTape( + hDevice: HANDLE, + dwOperation: DWORD, + bImmediate: BOOL, + ) -> DWORD; + pub fn EraseTape( + hDevice: HANDLE, + dwEraseType: DWORD, + bImmediate: BOOL, + ) -> DWORD; + pub fn CreateTapePartition( + hDevice: HANDLE, + dwPartitionMethod: DWORD, + dwCount: DWORD, + dwSize: DWORD, + ) -> DWORD; + pub fn WriteTapemark( + hDevice: HANDLE, + dwTapemarkType: DWORD, + dwTapemarkCount: DWORD, + bImmediate: BOOL, + ) -> DWORD; + pub fn GetTapeStatus( + hDevice: HANDLE, + ) -> DWORD; + pub fn GetTapeParameters( + hDevice: HANDLE, + dwOperation: DWORD, + lpdwSize: LPDWORD, + lpTapeInformation: LPVOID, + ) -> DWORD; + pub fn SetTapeParameters( + hDevice: HANDLE, + dwOperation: DWORD, + lpTapeInformation: LPVOID, + ) -> DWORD; + pub fn MulDiv( + nNumber: c_int, + nNumerator: c_int, + nDenominator: c_int, + ) -> c_int; +} +ENUM!{enum DEP_SYSTEM_POLICY_TYPE { + DEPPolicyAlwaysOff = 0, + DEPPolicyAlwaysOn, + DEPPolicyOptIn, + DEPPolicyOptOut, + DEPTotalPolicyCount, +}} +extern "system" { + pub fn GetSystemDEPPolicy() -> DEP_SYSTEM_POLICY_TYPE; + pub fn GetSystemRegistryQuota( + pdwQuotaAllowed: PDWORD, + pdwQuotaUsed: PDWORD, + ) -> BOOL; + pub fn FileTimeToDosDateTime( + lpFileTime: *const FILETIME, + lpFatDate: LPWORD, + lpFatTime: LPWORD, + ) -> BOOL; + pub fn DosDateTimeToFileTime( + wFatDate: WORD, + wFatTime: WORD, + lpFileTime: LPFILETIME, + ) -> BOOL; + pub fn FormatMessageA( + dwFlags: DWORD, + lpSource: LPCVOID, + dwMessageId: DWORD, + dwLanguageId: DWORD, + lpBuffer: LPSTR, + nSize: DWORD, + Arguments: *mut va_list, + ) -> DWORD; + pub fn FormatMessageW( + dwFlags: DWORD, + lpSource: LPCVOID, + dwMessageId: DWORD, + dwLanguageId: DWORD, + lpBuffer: LPWSTR, + nSize: DWORD, + Arguments: *mut va_list, + ) -> DWORD; +} +pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; +pub const FORMAT_MESSAGE_FROM_STRING: DWORD = 0x00000400; +pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; +pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; +pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: DWORD = 0x00002000; +pub const FORMAT_MESSAGE_MAX_WIDTH_MASK: DWORD = 0x000000FF; +pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: DWORD = 0x00000100; +extern "system" { + pub fn CreateMailslotA( + lpName: LPCSTR, + nMaxMessageSize: DWORD, + lReadTimeout: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE; + pub fn CreateMailslotW( + lpName: LPCWSTR, + nMaxMessageSize: DWORD, + lReadTimeout: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE; + pub fn GetMailslotInfo( + hMailslot: HANDLE, + lpMaxMessageSize: LPDWORD, + lpNextSize: LPDWORD, + lpMessageCount: LPDWORD, + lpReadTimeout: LPDWORD, + ) -> BOOL; + pub fn SetMailslotInfo( + hMailslot: HANDLE, + lReadTimeout: DWORD, + ) -> BOOL; + // pub fn EncryptFileA(); + // pub fn EncryptFileW(); + // pub fn DecryptFileA(); + // pub fn DecryptFileW(); + // pub fn FileEncryptionStatusA(); + // pub fn FileEncryptionStatusW(); + // pub fn OpenEncryptedFileRawA(); + // pub fn OpenEncryptedFileRawW(); + // pub fn ReadEncryptedFileRaw(); + // pub fn WriteEncryptedFileRaw(); + // pub fn CloseEncryptedFileRaw(); + pub fn lstrcmpA( + lpString1: LPCSTR, + lpString2: LPCSTR, + ) -> c_int; + pub fn lstrcmpW( + lpString1: LPCWSTR, + lpString2: LPCWSTR, + ) -> c_int; + pub fn lstrcmpiA( + lpString1: LPCSTR, + lpString2: LPCSTR, + ) -> c_int; + pub fn lstrcmpiW( + lpString1: LPCWSTR, + lpString2: LPCWSTR, + ) -> c_int; + pub fn lstrcpynA( + lpString1: LPSTR, + lpString2: LPCSTR, + iMaxLength: c_int, + ) -> LPSTR; + pub fn lstrcpynW( + lpString1: LPWSTR, + lpString2: LPCWSTR, + iMaxLength: c_int, + ) -> LPWSTR; + pub fn lstrcpyA( + lpString1: LPSTR, + lpString2: LPCSTR, + ) -> LPSTR; + pub fn lstrcpyW( + lpString1: LPWSTR, + lpString2: LPCWSTR, + ) -> LPWSTR; + pub fn lstrcatA( + lpString1: LPSTR, + lpString2: LPCSTR, + ) -> LPSTR; + pub fn lstrcatW( + lpString1: LPWSTR, + lpString2: LPCWSTR, + ) -> LPWSTR; + pub fn lstrlenA( + lpString: LPCSTR, + ) -> c_int; + pub fn lstrlenW( + lpString: LPCWSTR, + ) -> c_int; + pub fn OpenFile( + lpFileName: LPCSTR, + lpReOpenBuff: LPOFSTRUCT, + uStyle: UINT, + ) -> HFILE; + pub fn _lopen( + lpPathName: LPCSTR, + iReadWrite: c_int, + ) -> HFILE; + pub fn _lcreat( + lpPathName: LPCSTR, + iAttrubute: c_int, + ) -> HFILE; + pub fn _lread( + hFile: HFILE, + lpBuffer: LPVOID, + uBytes: UINT, + ) -> UINT; + pub fn _lwrite( + hFile: HFILE, + lpBuffer: LPCCH, + uBytes: UINT, + ) -> UINT; + pub fn _hread( + hFile: HFILE, + lpBuffer: LPVOID, + lBytes: c_long, + ) -> c_long; + pub fn _hwrite( + hFile: HFILE, + lpBuffer: LPCCH, + lBytes: c_long, + ) -> c_long; + pub fn _lclose( + hFile: HFILE, + ) -> HFILE; + pub fn _llseek( + hFile: HFILE, + lOffset: LONG, + iOrigin: c_int, + ) -> LONG; + // pub fn IsTextUnicode(); + // pub fn SignalObjectAndWait(); + pub fn BackupRead( + hFile: HANDLE, + lpBuffer: LPBYTE, + nNumberOfBytesToRead: DWORD, + lpNumberOfBytesRead: LPDWORD, + bAbort: BOOL, + bProcessSecurity: BOOL, + lpContext: *mut LPVOID, + ) -> BOOL; + pub fn BackupSeek( + hFile: HANDLE, + dwLowBytesToSeek: DWORD, + dwHighBytesToSeek: DWORD, + lpdwLowByteSeeked: LPDWORD, + lpdwHighByteSeeked: LPDWORD, + lpContext: *mut LPVOID, + ) -> BOOL; + pub fn BackupWrite( + hFile: HANDLE, + lpBuffer: LPBYTE, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + bAbort: BOOL, + bProcessSecurity: BOOL, + lpContext: *mut LPVOID, + ) -> BOOL; +} +//2886 +pub const STARTF_USESHOWWINDOW: DWORD = 0x00000001; +pub const STARTF_USESIZE: DWORD = 0x00000002; +pub const STARTF_USEPOSITION: DWORD = 0x00000004; +pub const STARTF_USECOUNTCHARS: DWORD = 0x00000008; +pub const STARTF_USEFILLATTRIBUTE: DWORD = 0x00000010; +pub const STARTF_RUNFULLSCREEN: DWORD = 0x00000020; +pub const STARTF_FORCEONFEEDBACK: DWORD = 0x00000040; +pub const STARTF_FORCEOFFFEEDBACK: DWORD = 0x00000080; +pub const STARTF_USESTDHANDLES: DWORD = 0x00000100; +pub const STARTF_USEHOTKEY: DWORD = 0x00000200; +pub const STARTF_TITLEISLINKNAME: DWORD = 0x00000800; +pub const STARTF_TITLEISAPPID: DWORD = 0x00001000; +pub const STARTF_PREVENTPINNING: DWORD = 0x00002000; +pub const STARTF_UNTRUSTEDSOURCE: DWORD = 0x00008000; +STRUCT!{struct STARTUPINFOEXA { + StartupInfo: STARTUPINFOA, + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, +}} +pub type LPSTARTUPINFOEXA = *mut STARTUPINFOEXA; +STRUCT!{struct STARTUPINFOEXW { + StartupInfo: STARTUPINFOW, + lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, +}} +pub type LPSTARTUPINFOEXW = *mut STARTUPINFOEXW; +extern "system" { + pub fn OpenMutexA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateSemaphoreA( + lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES, + lInitialCount: LONG, + lMaximumCount: LONG, + lpName: LPCSTR, + ) -> HANDLE; + pub fn OpenSemaphoreA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateWaitableTimerA( + lpTimerAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + lpTimerName: LPCSTR, + ) -> HANDLE; + pub fn OpenWaitableTimerA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpTimerName: LPCSTR, + ) -> HANDLE; + pub fn CreateSemaphoreExA( + lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES, + lInitialCount: LONG, + lMaximumCount: LONG, + lpName: LPCSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; + pub fn CreateWaitableTimerExA( + lpTimerAttributes: LPSECURITY_ATTRIBUTES, + lpTimerName: LPCSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE; + pub fn CreateFileMappingA( + hFile: HANDLE, + lpAttributes: LPSECURITY_ATTRIBUTES, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateFileMappingNumaA( + hFile: HANDLE, + lpFileMappingAttributes: LPSECURITY_ATTRIBUTES, + flProtect: DWORD, + dwMaximumSizeHigh: DWORD, + dwMaximumSizeLow: DWORD, + lpName: LPCSTR, + nndPreferred: DWORD, + ) -> HANDLE; + pub fn OpenFileMappingA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn GetLogicalDriveStringsA( + nBufferLength: DWORD, + lpBuffer: LPSTR, + ) -> DWORD; + pub fn LoadPackagedLibrary( + lpwLibFileName: LPCWSTR, + Reserved: DWORD, + ) -> HMODULE; + pub fn QueryFullProcessImageNameA( + hProcess: HANDLE, + dwFlags: DWORD, + lpExeName: LPSTR, + lpdwSize: PDWORD, + ) -> BOOL; + pub fn QueryFullProcessImageNameW( + hProcess: HANDLE, + dwFlags: DWORD, + lpExeName: LPWSTR, + lpdwSize: PDWORD, + ) -> BOOL; +} +//3233 +extern "system" { + pub fn GetStartupInfoA( + lpStartupInfo: LPSTARTUPINFOA, + ); + pub fn GetFirmwareEnvironmentVariableA( + lpName: LPCSTR, + lpGuid: LPCSTR, + pBuffer: PVOID, + nSize: DWORD, + ) -> DWORD; + pub fn GetFirmwareEnvironmentVariableW( + lpName: LPCWSTR, + lpGuid: LPCWSTR, + pBuffer: PVOID, + nSize: DWORD, + ) -> DWORD; + pub fn GetFirmwareEnvironmentVariableExA( + lpName: LPCSTR, + lpGuid: LPCSTR, + pBuffer: PVOID, + nSize: DWORD, + pdwAttribubutes: PDWORD, + ) -> DWORD; + pub fn GetFirmwareEnvironmentVariableExW( + lpName: LPCWSTR, + lpGuid: LPCWSTR, + pBuffer: PVOID, + nSize: DWORD, + pdwAttribubutes: PDWORD, + ) -> DWORD; + pub fn SetFirmwareEnvironmentVariableA( + lpName: LPCSTR, + lpGuid: LPCSTR, + pValue: PVOID, + nSize: DWORD, + ) -> BOOL; + pub fn SetFirmwareEnvironmentVariableW( + lpName: LPCWSTR, + lpGuid: LPCWSTR, + pValue: PVOID, + nSize: DWORD, + ) -> BOOL; + pub fn SetFirmwareEnvironmentVariableExA( + lpName: LPCSTR, + lpGuid: LPCSTR, + pValue: PVOID, + nSize: DWORD, + dwAttributes: DWORD, + ) -> BOOL; + pub fn SetFirmwareEnvironmentVariableExW( + lpName: LPCWSTR, + lpGuid: LPCWSTR, + pValue: PVOID, + nSize: DWORD, + dwAttributes: DWORD, + ) -> BOOL; + pub fn GetFirmwareType( + FirmwareType: PFIRMWARE_TYPE, + ) -> BOOL; + pub fn IsNativeVhdBoot( + NativeVhdBoot: PBOOL, + ) -> BOOL; + pub fn FindResourceA( + hModule: HMODULE, + lpName: LPCSTR, + lpType: LPCSTR, + ) -> HRSRC; + pub fn FindResourceExA( + hModule: HMODULE, + lpName: LPCSTR, + lpType: LPCSTR, + wLanguage: WORD, + ) -> HRSRC; + pub fn EnumResourceTypesA( + hModule: HMODULE, + lpEnumFunc: ENUMRESTYPEPROCA, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumResourceTypesW( + hModule: HMODULE, + lpEnumFunc: ENUMRESTYPEPROCW, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumResourceNamesA( + hModule: HMODULE, + lpType: LPCSTR, + lpEnumFunc: ENUMRESNAMEPROCA, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumResourceLanguagesA( + hModule: HMODULE, + lpType: LPCSTR, + lpName: LPCSTR, + lpEnumFunc: ENUMRESLANGPROCA, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumResourceLanguagesW( + hModule: HMODULE, + lpType: LPCWSTR, + lpName: LPCWSTR, + lpEnumFunc: ENUMRESLANGPROCW, + lParam: LONG_PTR, + ) -> BOOL; + pub fn BeginUpdateResourceA( + pFileName: LPCSTR, + bDeleteExistingResources: BOOL, + ) -> HANDLE; + pub fn BeginUpdateResourceW( + pFileName: LPCWSTR, + bDeleteExistingResources: BOOL, + ) -> HANDLE; + pub fn UpdateResourceA( + hUpdate: HANDLE, + lpType: LPCSTR, + lpName: LPCSTR, + wLanguage: WORD, + lpData: LPVOID, + cb: DWORD, + ) -> BOOL; + pub fn UpdateResourceW( + hUpdate: HANDLE, + lpType: LPCWSTR, + lpName: LPCWSTR, + wLanguage: WORD, + lpData: LPVOID, + cb: DWORD, + ) -> BOOL; + pub fn EndUpdateResourceA( + hUpdate: HANDLE, + fDiscard: BOOL, + ) -> BOOL; + pub fn EndUpdateResourceW( + hUpdate: HANDLE, + fDiscard: BOOL, + ) -> BOOL; + pub fn GlobalAddAtomA( + lpString: LPCSTR, + ) -> ATOM; + pub fn GlobalAddAtomW( + lpString: LPCWSTR, + ) -> ATOM; + pub fn GlobalAddAtomExA( + lpString: LPCSTR, + Flags: DWORD, + ) -> ATOM; + pub fn GlobalAddAtomExW( + lpString: LPCWSTR, + Flags: DWORD, + ) -> ATOM; + pub fn GlobalFindAtomA( + lpString: LPCSTR, + ) -> ATOM; + pub fn GlobalFindAtomW( + lpString: LPCWSTR, + ) -> ATOM; + pub fn GlobalGetAtomNameA( + nAtom: ATOM, + lpBuffer: LPSTR, + nSize: c_int, + ) -> UINT; + pub fn GlobalGetAtomNameW( + nAtom: ATOM, + lpBuffer: LPWSTR, + nSize: c_int, + ) -> UINT; + pub fn AddAtomA( + lpString: LPCSTR, + ) -> ATOM; + pub fn AddAtomW( + lpString: LPCWSTR, + ) -> ATOM; + pub fn FindAtomA( + lpString: LPCSTR, + ) -> ATOM; + pub fn FindAtomW( + lpString: LPCWSTR, + ) -> ATOM; + pub fn GetAtomNameA( + nAtom: ATOM, + lpBuffer: LPSTR, + nSize: c_int, + ) -> UINT; + pub fn GetAtomNameW( + nAtom: ATOM, + lpBuffer: LPWSTR, + nSize: c_int, + ) -> UINT; + pub fn GetProfileIntA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + nDefault: INT, + ) -> UINT; + pub fn GetProfileIntW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + nDefault: INT, + ) -> UINT; + pub fn GetProfileStringA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + lpDefault: LPCSTR, + lpReturnedString: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetProfileStringW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + lpDefault: LPCWSTR, + lpReturnedString: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn WriteProfileStringA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + lpString: LPCSTR, + ) -> BOOL; + pub fn WriteProfileStringW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + lpString: LPCWSTR, + ) -> BOOL; + pub fn GetProfileSectionA( + lpAppName: LPCSTR, + lpReturnedString: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetProfileSectionW( + lpAppName: LPCWSTR, + lpReturnedString: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn WriteProfileSectionA( + lpAppName: LPCSTR, + lpString: LPCSTR, + ) -> BOOL; + pub fn WriteProfileSectionW( + lpAppName: LPCWSTR, + lpString: LPCWSTR, + ) -> BOOL; + pub fn GetPrivateProfileIntA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + nDefault: INT, + lpFileName: LPCSTR, + ) -> UINT; + pub fn GetPrivateProfileIntW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + nDefault: INT, + lpFileName: LPCWSTR, + ) -> UINT; + pub fn GetPrivateProfileStringA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + lpDefault: LPCSTR, + lpReturnedString: LPSTR, + nSize: DWORD, + lpFileName: LPCSTR, + ) -> DWORD; + pub fn GetPrivateProfileStringW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + lpDefault: LPCWSTR, + lpReturnedString: LPWSTR, + nSize: DWORD, + lpFileName: LPCWSTR, + ) -> DWORD; + pub fn WritePrivateProfileStringA( + lpAppName: LPCSTR, + lpKeyName: LPCSTR, + lpString: LPCSTR, + lpFileName: LPCSTR, + ) -> BOOL; + pub fn WritePrivateProfileStringW( + lpAppName: LPCWSTR, + lpKeyName: LPCWSTR, + lpString: LPCWSTR, + lpFileName: LPCWSTR, + ) -> BOOL; + pub fn GetPrivateProfileSectionA( + lpAppName: LPCSTR, + lpReturnedString: LPSTR, + nSize: DWORD, + lpFileName: LPCSTR, + ) -> DWORD; + pub fn GetPrivateProfileSectionW( + lpAppName: LPCWSTR, + lpReturnedString: LPWSTR, + nSize: DWORD, + lpFileName: LPCWSTR, + ) -> DWORD; + pub fn WritePrivateProfileSectionA( + lpAppName: LPCSTR, + lpString: LPCSTR, + lpFileName: LPCSTR, + ) -> BOOL; + pub fn WritePrivateProfileSectionW( + lpAppName: LPCWSTR, + lpString: LPCWSTR, + lpFileName: LPCWSTR, + ) -> BOOL; + pub fn GetPrivateProfileSectionNamesA( + lpszReturnBuffer: LPSTR, + nSize: DWORD, + lpFileName: LPCSTR, + ) -> DWORD; + pub fn GetPrivateProfileSectionNamesW( + lpszReturnBuffer: LPWSTR, + nSize: DWORD, + lpFileName: LPCWSTR, + ) -> DWORD; + pub fn GetPrivateProfileStructA( + lpszSection: LPCSTR, + lpszKey: LPCSTR, + lpStruct: LPVOID, + uSizeStruct: UINT, + szFile: LPCSTR, + ) -> BOOL; + pub fn GetPrivateProfileStructW( + lpszSection: LPCWSTR, + lpszKey: LPCWSTR, + lpStruct: LPVOID, + uSizeStruct: UINT, + szFile: LPCWSTR, + ) -> BOOL; + pub fn WritePrivateProfileStructA( + lpszSection: LPCSTR, + lpszKey: LPCSTR, + lpStruct: LPVOID, + uSizeStruct: UINT, + szFile: LPCSTR, + ) -> BOOL; + pub fn WritePrivateProfileStructW( + lpszSection: LPCWSTR, + lpszKey: LPCWSTR, + lpStruct: LPVOID, + uSizeStruct: UINT, + szFile: LPCWSTR, + ) -> BOOL; + pub fn Wow64EnableWow64FsRedirection( + Wow64FsEnableRedirection: BOOLEAN, + ) -> BOOLEAN; + pub fn SetDllDirectoryA( + lpPathName: LPCSTR, + ) -> BOOL; + pub fn SetDllDirectoryW( + lpPathName: LPCWSTR, + ) -> BOOL; + pub fn GetDllDirectoryA( + nBufferLength: DWORD, + lpBuffer: LPSTR, + ) -> DWORD; + pub fn GetDllDirectoryW( + nBufferLength: DWORD, + lpBuffer: LPWSTR, + ) -> DWORD; + pub fn SetSearchPathMode( + Flags: DWORD, + ) -> BOOL; + pub fn CreateDirectoryExA( + lpTemplateDirectory: LPCSTR, + lpNewDirectory: LPCSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateDirectoryExW( + lpTemplateDirectory: LPCWSTR, + lpNewDirectory: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateDirectoryTransactedA( + lpTemplateDirectory: LPCSTR, + lpNewDirectory: LPCSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + hTransaction: HANDLE, + ) -> BOOL; + pub fn CreateDirectoryTransactedW( + lpTemplateDirectory: LPCWSTR, + lpNewDirectory: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + hTransaction: HANDLE, + ) -> BOOL; + pub fn RemoveDirectoryTransactedA( + lpPathName: LPCSTR, + hTransaction: HANDLE, + ) -> BOOL; + pub fn RemoveDirectoryTransactedW( + lpPathName: LPCWSTR, + hTransaction: HANDLE, + ) -> BOOL; + pub fn GetFullPathNameTransactedA( + lpFileName: LPCSTR, + nBufferLength: DWORD, + lpBuffer: LPSTR, + lpFilePart: *mut LPSTR, + hTransaction: HANDLE, + ) -> DWORD; + pub fn GetFullPathNameTransactedW( + lpFileName: LPCWSTR, + nBufferLength: DWORD, + lpBuffer: LPWSTR, + lpFilePart: *mut LPWSTR, + hTransaction: HANDLE, + ); + pub fn DefineDosDeviceA( + dwFlags: DWORD, + lpDeviceName: LPCSTR, + lpTargetPath: LPCSTR, + ) -> BOOL; + pub fn QueryDosDeviceA( + lpDeviceName: LPCSTR, + lpTargetPath: LPSTR, + ucchMax: DWORD, + ) -> DWORD; + pub fn CreateFileTransactedA( + lpFileName: LPCSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + hTransaction: HANDLE, + pusMiniVersion: PUSHORT, + lpExtendedParameter: PVOID, + ) -> HANDLE; + pub fn CreateFileTransactedW( + lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE, + hTransaction: HANDLE, + pusMiniVersion: PUSHORT, + lpExtendedParameter: PVOID, + ) -> HANDLE; + pub fn ReOpenFile( + hOriginalFile: HANDLE, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + dwFlags: DWORD, + ) -> HANDLE; + pub fn SetFileAttributesTransactedA( + lpFileName: LPCSTR, + dwFileAttributes: DWORD, + hTransaction: HANDLE, + ) -> BOOL; + pub fn SetFileAttributesTransactedW( + lpFileName: LPCWSTR, + dwFileAttributes: DWORD, + hTransaction: HANDLE, + ) -> BOOL; + pub fn GetFileAttributesTransactedA( + lpFileName: LPCSTR, + fInfoLevelId: GET_FILEEX_INFO_LEVELS, + lpFileInformation: LPVOID, + hTransaction: HANDLE, + ) -> BOOL; + pub fn GetFileAttributesTransactedW( + lpFileName: LPCWSTR, + fInfoLevelId: GET_FILEEX_INFO_LEVELS, + lpFileInformation: LPVOID, + hTransaction: HANDLE, + ) -> BOOL; + pub fn GetCompressedFileSizeTransactedA( + lpFileName: LPCSTR, + lpFileSizeHigh: LPDWORD, + hTransaction: HANDLE, + ) -> DWORD; + pub fn GetCompressedFileSizeTransactedW( + lpFileName: LPCWSTR, + lpFileSizeHigh: LPDWORD, + hTransaction: HANDLE, + ); + pub fn DeleteFileTransactedA( + lpFileName: LPCSTR, + hTransaction: HANDLE, + ) -> BOOL; + pub fn DeleteFileTransactedW( + lpFileName: LPCWSTR, + hTransaction: HANDLE, + ) -> BOOL; + pub fn CheckNameLegalDOS8Dot3A( + lpName: LPCSTR, + lpOemName: LPSTR, + OemNameSize: DWORD, + pbNameContainsSpaces: PBOOL, + pbNameLegal: PBOOL, + ) -> BOOL; + pub fn CheckNameLegalDOS8Dot3W( + lpName: LPCWSTR, + lpOemName: LPSTR, + OemNameSize: DWORD, + pbNameContainsSpaces: PBOOL, + pbNameLegal: PBOOL, + ) -> BOOL; + pub fn FindFirstFileTransactedA( + lpFileName: LPCSTR, + fInfoLevelId: FINDEX_INFO_LEVELS, + lpFindFileData: LPVOID, + fSearchOp: FINDEX_SEARCH_OPS, + lpSearchFilter: LPVOID, + dwAdditionalFlags: DWORD, + hTransaction: HANDLE, + ) -> HANDLE; + pub fn FindFirstFileTransactedW( + lpFileName: LPCWSTR, + fInfoLevelId: FINDEX_INFO_LEVELS, + lpFindFileData: LPVOID, + fSearchOp: FINDEX_SEARCH_OPS, + lpSearchFilter: LPVOID, + dwAdditionalFlags: DWORD, + hTransaction: HANDLE, + ) -> HANDLE; + pub fn CopyFileA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + bFailIfExists: BOOL, + ) -> BOOL; + pub fn CopyFileW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + bFailIfExists: BOOL, + ) -> BOOL; +} +FN!{stdcall LPPROGRESS_ROUTINE( + TotalFileSize: LARGE_INTEGER, + TotalBytesTransferred: LARGE_INTEGER, + StreamSize: LARGE_INTEGER, + StreamBytesTransferred: LARGE_INTEGER, + dwStreamNumber: DWORD, + dwCallbackReason: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + lpData: LPVOID, +) -> DWORD} +extern "system" { + pub fn CopyFileExA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + ) -> BOOL; + pub fn CopyFileExW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + ) -> BOOL; + pub fn CopyFileTransactedA( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOL; + pub fn CopyFileTransactedW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOL; +} +ENUM!{enum COPYFILE2_MESSAGE_TYPE { + COPYFILE2_CALLBACK_NONE = 0, + COPYFILE2_CALLBACK_CHUNK_STARTED, + COPYFILE2_CALLBACK_CHUNK_FINISHED, + COPYFILE2_CALLBACK_STREAM_STARTED, + COPYFILE2_CALLBACK_STREAM_FINISHED, + COPYFILE2_CALLBACK_POLL_CONTINUE, + COPYFILE2_CALLBACK_ERROR, + COPYFILE2_CALLBACK_MAX, +}} +ENUM!{enum COPYFILE2_MESSAGE_ACTION { + COPYFILE2_PROGRESS_CONTINUE = 0, + COPYFILE2_PROGRESS_CANCEL, + COPYFILE2_PROGRESS_STOP, + COPYFILE2_PROGRESS_QUIET, + COPYFILE2_PROGRESS_PAUSE, +}} +ENUM!{enum COPYFILE2_COPY_PHASE { + COPYFILE2_PHASE_NONE = 0, + COPYFILE2_PHASE_PREPARE_SOURCE, + COPYFILE2_PHASE_PREPARE_DEST, + COPYFILE2_PHASE_READ_SOURCE, + COPYFILE2_PHASE_WRITE_DESTINATION, + COPYFILE2_PHASE_SERVER_COPY, + COPYFILE2_PHASE_NAMEGRAFT_COPY, + COPYFILE2_PHASE_MAX, +}} +STRUCT!{struct COPYFILE2_MESSAGE_ChunkStarted { + dwStreamNumber: DWORD, + dwReserved: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + uliChunkNumber: ULARGE_INTEGER, + uliChunkSize: ULARGE_INTEGER, + uliStreamSize: ULARGE_INTEGER, + uliTotalFileSize: ULARGE_INTEGER, +}} +STRUCT!{struct COPYFILE2_MESSAGE_ChunkFinished { + dwStreamNumber: DWORD, + dwFlags: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + uliChunkNumber: ULARGE_INTEGER, + uliChunkSize: ULARGE_INTEGER, + uliStreamSize: ULARGE_INTEGER, + uliStreamBytesTransferred: ULARGE_INTEGER, + uliTotalFileSize: ULARGE_INTEGER, + uliTotalBytesTransferred: ULARGE_INTEGER, +}} +STRUCT!{struct COPYFILE2_MESSAGE_StreamStarted { + dwStreamNumber: DWORD, + dwReserved: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + uliStreamSize: ULARGE_INTEGER, + uliTotalFileSize: ULARGE_INTEGER, +}} +STRUCT!{struct COPYFILE2_MESSAGE_StreamFinished { + dwStreamNumber: DWORD, + dwReserved: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + uliStreamSize: ULARGE_INTEGER, + uliStreamBytesTransferred: ULARGE_INTEGER, + uliTotalFileSize: ULARGE_INTEGER, + uliTotalBytesTransferred: ULARGE_INTEGER, +}} +STRUCT!{struct COPYFILE2_MESSAGE_PollContinue { + dwReserved: DWORD, +}} +STRUCT!{struct COPYFILE2_MESSAGE_Error { + CopyPhase: COPYFILE2_COPY_PHASE, + dwStreamNumber: DWORD, + hrFailure: HRESULT, + dwReserved: DWORD, + uliChunkNumber: ULARGE_INTEGER, + uliStreamSize: ULARGE_INTEGER, + uliStreamBytesTransferred: ULARGE_INTEGER, + uliTotalFileSize: ULARGE_INTEGER, + uliTotalBytesTransferred: ULARGE_INTEGER, +}} +UNION!{union COPYFILE2_MESSAGE_Info { + [u64; 8] [u64; 9], + ChunkStarted ChunkStarted_mut: COPYFILE2_MESSAGE_ChunkStarted, + ChunkFinished ChunkFinished_mut: COPYFILE2_MESSAGE_ChunkFinished, + StreamStarted StreamStarted_mut: COPYFILE2_MESSAGE_StreamStarted, + StreamFinished StreamFinished_mut: COPYFILE2_MESSAGE_StreamFinished, + PollContinue PollContinue_mut: COPYFILE2_MESSAGE_PollContinue, + Error Error_mut: COPYFILE2_MESSAGE_Error, +}} +STRUCT!{struct COPYFILE2_MESSAGE { + Type: COPYFILE2_MESSAGE_TYPE, + dwPadding: DWORD, + Info: COPYFILE2_MESSAGE_Info, +}} +FN!{stdcall PCOPYFILE2_PROGRESS_ROUTINE( + pMessage: *const COPYFILE2_MESSAGE, + pvCallbackContext: PVOID, +) -> COPYFILE2_MESSAGE_ACTION} +STRUCT!{struct COPYFILE2_EXTENDED_PARAMETERS { + dwSize: DWORD, + dwCopyFlags: DWORD, + pfCancel: *mut BOOL, + pProgressRoutine: PCOPYFILE2_PROGRESS_ROUTINE, + pvCallbackContext: PVOID, +}} +extern "system" { + pub fn CopyFile2( + pwszExistingFileName: PCWSTR, + pwszNewFileName: PCWSTR, + pExtendedParameters: *mut COPYFILE2_EXTENDED_PARAMETERS, + ) -> HRESULT; + pub fn MoveFileA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + ) -> BOOL; + pub fn MoveFileW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + ) -> BOOL; + pub fn MoveFileExA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + dwFlags: DWORD, + ) -> BOOL; + pub fn MoveFileExW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + dwFlags: DWORD, + ) -> BOOL; + pub fn MoveFileWithProgressA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + dwFlags: DWORD, + ) -> BOOL; + pub fn MoveFileWithProgressW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + dwFlags: DWORD, + ) -> BOOL; + pub fn MoveFileTransactedA( + lpExistingFileName: LPCSTR, + lpNewFileName: LPCSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + dwFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOL; + pub fn MoveFileTransactedW( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: LPVOID, + dwFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOL; +} +pub const MOVEFILE_REPLACE_EXISTING: DWORD = 0x00000001; +pub const MOVEFILE_COPY_ALLOWED: DWORD = 0x00000002; +pub const MOVEFILE_DELAY_UNTIL_REBOOT: DWORD = 0x00000004; +pub const MOVEFILE_WRITE_THROUGH: DWORD = 0x00000008; +pub const MOVEFILE_CREATE_HARDLINK: DWORD = 0x00000010; +pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE: DWORD = 0x00000020; +extern "system" { + pub fn ReplaceFileA( + lpReplacedFileName: LPCSTR, + lpReplacementFileName: LPCSTR, + lpBackupFileName: LPCSTR, + dwReplaceFlags: DWORD, + lpExclude: LPVOID, + lpReserved: LPVOID, + ); + pub fn ReplaceFileW( + lpReplacedFileName: LPCWSTR, + lpReplacementFileName: LPCWSTR, + lpBackupFileName: LPCWSTR, + dwReplaceFlags: DWORD, + lpExclude: LPVOID, + lpReserved: LPVOID, + ); + pub fn CreateHardLinkA( + lpFileName: LPCSTR, + lpExistingFileName: LPCSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateHardLinkW( + lpFileName: LPCWSTR, + lpExistingFileName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn CreateHardLinkTransactedA( + lpFileName: LPCSTR, + lpExistingFileName: LPCSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + hTransaction: HANDLE, + ) -> BOOL; + pub fn CreateHardLinkTransactedW( + lpFileName: LPCWSTR, + lpExistingFileName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + hTransaction: HANDLE, + ); + pub fn FindFirstStreamTransactedW( + lpFileName: LPCWSTR, + InfoLevel: STREAM_INFO_LEVELS, + lpFindStreamData: LPVOID, + dwFlags: DWORD, + hTransaction: HANDLE, + ) -> HANDLE; + pub fn FindFirstFileNameTransactedW( + lpFileName: LPCWSTR, + dwFlags: DWORD, + StringLength: LPDWORD, + LinkName: PWSTR, + hTransaction: HANDLE, + ) -> HANDLE; + pub fn CreateNamedPipeA( + lpName: LPCSTR, + dwOpenMode: DWORD, + dwPipeMode: DWORD, + nMaxInstances: DWORD, + nOutBufferSize: DWORD, + nInBufferSize: DWORD, + nDefaultTimeOut: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> HANDLE; + pub fn GetNamedPipeHandleStateA( + hNamedPipe: HANDLE, + lpState: LPDWORD, + lpCurInstances: LPDWORD, + lpMaxCollectionCount: LPDWORD, + lpCollectDataTimeout: LPDWORD, + lpUserName: LPSTR, + nMaxUserNameSize: DWORD, + ) -> BOOL; + pub fn CallNamedPipeA( + lpNamedPipeName: LPCSTR, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesRead: LPDWORD, + nTimeOut: DWORD, + ) -> BOOL; + pub fn WaitNamedPipeA( + lpNamedPipeName: LPCSTR, + nTimeOut: DWORD, + ) -> BOOL; + pub fn GetNamedPipeClientComputerNameA( + Pipe: HANDLE, + ClientComputerName: LPSTR, + ClientComputerNameLength: ULONG, + ) -> BOOL; + pub fn GetNamedPipeClientProcessId( + Pipe: HANDLE, + ClientProcessId: PULONG, + ) -> BOOL; + pub fn GetNamedPipeClientSessionId( + Pipe: HANDLE, + ClientSessionId: PULONG, + ) -> BOOL; + pub fn GetNamedPipeServerProcessId( + Pipe: HANDLE, + ServerProcessId: PULONG, + ) -> BOOL; + pub fn GetNamedPipeServerSessionId( + Pipe: HANDLE, + ServerSessionId: PULONG, + ) -> BOOL; + pub fn SetVolumeLabelA( + lpRootPathName: LPCSTR, + lpVolumeName: LPCSTR, + ) -> BOOL; + pub fn SetVolumeLabelW( + lpRootPathName: LPCWSTR, + lpVolumeName: LPCWSTR, + ) -> BOOL; + pub fn SetFileBandwidthReservation( + hFile: HANDLE, + nPeriodMilliseconds: DWORD, + nBytesPerPeriod: DWORD, + bDiscardable: BOOL, + lpTransferSize: LPDWORD, + lpNumOutstandingRequests: LPDWORD, + ) -> BOOL; + pub fn GetFileBandwidthReservation( + hFile: HANDLE, + lpPeriodMilliseconds: LPDWORD, + lpBytesPerPeriod: LPDWORD, + pDiscardable: LPBOOL, + lpTransferSize: LPDWORD, + lpNumOutstandingRequests: LPDWORD, + ) -> BOOL; + // pub fn ClearEventLogA(); + // pub fn ClearEventLogW(); + // pub fn BackupEventLogA(); + // pub fn BackupEventLogW(); + // pub fn CloseEventLog(); + pub fn DeregisterEventSource( + hEventLog: HANDLE, + ) -> BOOL; + // pub fn NotifyChangeEventLog(); + // pub fn GetNumberOfEventLogRecords(); + // pub fn GetOldestEventLogRecord(); + // pub fn OpenEventLogA(); + // pub fn OpenEventLogW(); + pub fn RegisterEventSourceA( + lpUNCServerName: LPCSTR, + lpSourceName: LPCSTR, + ) -> HANDLE; + pub fn RegisterEventSourceW( + lpUNCServerName: LPCWSTR, + lpSourceName: LPCWSTR, + ) -> HANDLE; + // pub fn OpenBackupEventLogA(); + // pub fn OpenBackupEventLogW(); + // pub fn ReadEventLogA(); + // pub fn ReadEventLogW(); + pub fn ReportEventA( + hEventLog: HANDLE, + wType: WORD, + wCategory: WORD, + dwEventID: DWORD, + lpUserSid: PSID, + wNumStrings: WORD, + dwDataSize: DWORD, + lpStrings: *mut LPCSTR, + lpRawData: LPVOID, + ) -> BOOL; + pub fn ReportEventW( + hEventLog: HANDLE, + wType: WORD, + wCategory: WORD, + dwEventID: DWORD, + lpUserSid: PSID, + wNumStrings: WORD, + dwDataSize: DWORD, + lpStrings: *mut LPCWSTR, + lpRawData: LPVOID, + ) -> BOOL; + // pub fn GetEventLogInformation(); + // pub fn OperationStart(); + // pub fn OperationEnd(); + // pub fn AccessCheckAndAuditAlarmA(); + // pub fn AccessCheckByTypeAndAuditAlarmA(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmA(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmByHandleA(); + // pub fn ObjectOpenAuditAlarmA(); + // pub fn ObjectPrivilegeAuditAlarmA(); + // pub fn ObjectCloseAuditAlarmA(); + // pub fn ObjectDeleteAuditAlarmA(); + // pub fn PrivilegedServiceAuditAlarmA(); + // pub fn AddConditionalAce(); + // pub fn SetFileSecurityA(); + // pub fn GetFileSecurityA(); + pub fn ReadDirectoryChangesW( + hDirectory: HANDLE, + lpBuffer: LPVOID, + nBufferLength: DWORD, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, + ) -> BOOL; + pub fn MapViewOfFileExNuma( + hFileMappingObject: HANDLE, + dwDesiredAccess: DWORD, + dwFileOffsetHigh: DWORD, + dwFileOffsetLow: DWORD, + dwNumberOfBytesToMap: SIZE_T, + lpBaseAddress: LPVOID, + nndPreferred: DWORD, + ) -> LPVOID; + pub fn IsBadReadPtr( + lp: *const VOID, + ucb: UINT_PTR, + ) -> BOOL; + pub fn IsBadWritePtr( + lp: LPVOID, + ucb: UINT_PTR, + ) -> BOOL; + pub fn IsBadHugeReadPtr( + lp: *const VOID, + ucb: UINT_PTR, + ) -> BOOL; + pub fn IsBadHugeWritePtr( + lp: LPVOID, + ucb: UINT_PTR, + ) -> BOOL; + pub fn IsBadCodePtr( + lpfn: FARPROC, + ) -> BOOL; + pub fn IsBadStringPtrA( + lpsz: LPCSTR, + ucchMax: UINT_PTR, + ) -> BOOL; + pub fn IsBadStringPtrW( + lpsz: LPCWSTR, + ucchMax: UINT_PTR, + ) -> BOOL; + pub fn LookupAccountSidA( + lpSystemName: LPCSTR, + Sid: PSID, + Name: LPSTR, + cchName: LPDWORD, + ReferencedDomainName: LPSTR, + cchReferencedDomainName: LPDWORD, + peUse: PSID_NAME_USE, + ) -> BOOL; + pub fn LookupAccountSidW( + lpSystemName: LPCWSTR, + Sid: PSID, + Name: LPWSTR, + cchName: LPDWORD, + ReferencedDomainName: LPWSTR, + cchReferencedDomainName: LPDWORD, + peUse: PSID_NAME_USE, + ) -> BOOL; + pub fn LookupAccountNameA( + lpSystemName: LPCSTR, + lpAccountName: LPCSTR, + Sid: PSID, + cbSid: LPDWORD, + ReferencedDomainName: LPCSTR, + cchReferencedDomainName: LPDWORD, + peUse: PSID_NAME_USE, + ) -> BOOL; + pub fn LookupAccountNameW( + lpSystemName: LPCWSTR, + lpAccountName: LPCWSTR, + Sid: PSID, + cbSid: LPDWORD, + ReferencedDomainName: LPCWSTR, + cchReferencedDomainName: LPDWORD, + peUse: PSID_NAME_USE, + ) -> BOOL; + // pub fn LookupAccountNameLocalA(); + // pub fn LookupAccountNameLocalW(); + // pub fn LookupAccountSidLocalA(); + // pub fn LookupAccountSidLocalW(); + pub fn LookupPrivilegeValueA( + lpSystemName: LPCSTR, + lpName: LPCSTR, + lpLuid: PLUID, + ) -> BOOL; + pub fn LookupPrivilegeValueW( + lpSystemName: LPCWSTR, + lpName: LPCWSTR, + lpLuid: PLUID, + ) -> BOOL; + pub fn LookupPrivilegeNameA( + lpSystemName: LPCSTR, + lpLuid: PLUID, + lpName: LPSTR, + cchName: LPDWORD, + ) -> BOOL; + pub fn LookupPrivilegeNameW( + lpSystemName: LPCWSTR, + lpLuid: PLUID, + lpName: LPWSTR, + cchName: LPDWORD, + ) -> BOOL; + // pub fn LookupPrivilegeDisplayNameA(); + // pub fn LookupPrivilegeDisplayNameW(); + pub fn BuildCommDCBA( + lpDef: LPCSTR, + lpDCB: LPDCB, + ) -> BOOL; + pub fn BuildCommDCBW( + lpDef: LPCWSTR, + lpDCB: LPDCB, + ) -> BOOL; + pub fn BuildCommDCBAndTimeoutsA( + lpDef: LPCSTR, + lpDCB: LPDCB, + lpCommTimeouts: LPCOMMTIMEOUTS, + ) -> BOOL; + pub fn BuildCommDCBAndTimeoutsW( + lpDef: LPCWSTR, + lpDCB: LPDCB, + lpCommTimeouts: LPCOMMTIMEOUTS, + ) -> BOOL; + pub fn CommConfigDialogA( + lpszName: LPCSTR, + hWnd: HWND, + lpCC: LPCOMMCONFIG, + ) -> BOOL; + pub fn CommConfigDialogW( + lpszName: LPCWSTR, + hWnd: HWND, + lpCC: LPCOMMCONFIG, + ) -> BOOL; + pub fn GetDefaultCommConfigA( + lpszName: LPCSTR, + lpCC: LPCOMMCONFIG, + lpdwSize: LPDWORD, + ) -> BOOL; + pub fn GetDefaultCommConfigW( + lpszName: LPCWSTR, + lpCC: LPCOMMCONFIG, + lpdwSize: LPDWORD, + ) -> BOOL; + pub fn SetDefaultCommConfigA( + lpszName: LPCSTR, + lpCC: LPCOMMCONFIG, + dwSize: DWORD, + ) -> BOOL; + pub fn SetDefaultCommConfigW( + lpszName: LPCWSTR, + lpCC: LPCOMMCONFIG, + dwSize: DWORD, + ) -> BOOL; + pub fn GetComputerNameA( + lpBuffer: LPSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn GetComputerNameW( + lpBuffer: LPWSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn DnsHostnameToComputerNameA( + Hostname: LPCSTR, + ComputerName: LPCSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn DnsHostnameToComputerNameW( + Hostname: LPCWSTR, + ComputerName: LPWSTR, + nSize: LPDWORD, + ) -> BOOL; + pub fn GetUserNameA( + lpBuffer: LPSTR, + pcbBuffer: LPDWORD, + ) -> BOOL; + pub fn GetUserNameW( + lpBuffer: LPWSTR, + pcbBuffer: LPDWORD, + ) -> BOOL; +} +pub const LOGON32_LOGON_INTERACTIVE: DWORD = 2; +pub const LOGON32_LOGON_NETWORK: DWORD = 3; +pub const LOGON32_LOGON_BATCH: DWORD = 4; +pub const LOGON32_LOGON_SERVICE: DWORD = 5; +pub const LOGON32_LOGON_UNLOCK: DWORD = 7; +pub const LOGON32_LOGON_NETWORK_CLEARTEXT: DWORD = 8; +pub const LOGON32_LOGON_NEW_CREDENTIALS: DWORD = 9; +pub const LOGON32_PROVIDER_DEFAULT: DWORD = 0; +pub const LOGON32_PROVIDER_WINNT35: DWORD = 1; +pub const LOGON32_PROVIDER_WINNT40: DWORD = 2; +pub const LOGON32_PROVIDER_WINNT50: DWORD = 3; +pub const LOGON32_PROVIDER_VIRTUAL: DWORD = 4; +extern "system" { + pub fn LogonUserA( + lpUsername: LPCSTR, + lpDomain: LPCSTR, + lpPassword: LPCSTR, + dwLogonType: DWORD, + dwLogonProvider: DWORD, + phToken: PHANDLE, + ) -> BOOL; + pub fn LogonUserW( + lpUsername: LPCWSTR, + lpDomain: LPCWSTR, + lpPassword: LPCWSTR, + dwLogonType: DWORD, + dwLogonProvider: DWORD, + phToken: PHANDLE, + ) -> BOOL; + pub fn LogonUserExA( + lpUsername: LPCSTR, + lpDomain: LPCSTR, + lpPassword: LPCSTR, + dwLogonType: DWORD, + dwLogonProvider: DWORD, + phToken: PHANDLE, + ppLogonSid: *mut PSID, + ppProfileBuffer: *mut PVOID, + pdwProfileLength: LPDWORD, + pQuotaLimits: PQUOTA_LIMITS, + ) -> BOOL; + pub fn LogonUserExW( + lpUsername: LPCWSTR, + lpDomain: LPCWSTR, + lpPassword: LPCWSTR, + dwLogonType: DWORD, + dwLogonProvider: DWORD, + phToken: PHANDLE, + ppLogonSid: *mut PSID, + ppProfileBuffer: *mut PVOID, + pdwProfileLength: LPDWORD, + pQuotaLimits: PQUOTA_LIMITS, + ) -> BOOL; + // pub fn CreateProcessWithLogonW(); + // pub fn CreateProcessWithTokenW(); + // pub fn IsTokenUntrusted(); + pub fn RegisterWaitForSingleObject( + phNewWaitObject: PHANDLE, + hObject: HANDLE, + Callback: WAITORTIMERCALLBACK, + Context: PVOID, + dwMilliseconds: ULONG, + dwFlags: ULONG, + ) -> BOOL; + pub fn UnregisterWait( + WaitHandle: HANDLE, + ) -> BOOL; + pub fn BindIoCompletionCallback( + FileHandle: HANDLE, + Function: LPOVERLAPPED_COMPLETION_ROUTINE, + Flags: ULONG, + ) -> BOOL; + pub fn SetTimerQueueTimer( + TimerQueue: HANDLE, + Callback: WAITORTIMERCALLBACK, + Parameter: PVOID, + DueTime: DWORD, + Period: DWORD, + PreferIo: BOOL, + ) -> HANDLE; + pub fn CancelTimerQueueTimer( + TimerQueue: HANDLE, + Timer: HANDLE, + ) -> BOOL; + pub fn DeleteTimerQueue( + TimerQueue: HANDLE, + ) -> BOOL; + // pub fn InitializeThreadpoolEnvironment(); + // pub fn SetThreadpoolCallbackPool(); + // pub fn SetThreadpoolCallbackCleanupGroup(); + // pub fn SetThreadpoolCallbackRunsLong(); + // pub fn SetThreadpoolCallbackLibrary(); + // pub fn SetThreadpoolCallbackPriority(); + // pub fn DestroyThreadpoolEnvironment(); + // pub fn SetThreadpoolCallbackPersistent(); + pub fn CreatePrivateNamespaceA( + lpPrivateNamespaceAttributes: LPSECURITY_ATTRIBUTES, + lpBoundaryDescriptor: LPVOID, + lpAliasPrefix: LPCSTR, + ) -> HANDLE; + pub fn OpenPrivateNamespaceA( + lpBoundaryDescriptor: LPVOID, + lpAliasPrefix: LPCSTR, + ) -> HANDLE; + pub fn CreateBoundaryDescriptorA( + Name: LPCSTR, + Flags: ULONG, + ) -> HANDLE; + pub fn AddIntegrityLabelToBoundaryDescriptor( + BoundaryDescriptor: *mut HANDLE, + IntegrityLabel: PSID, + ) -> BOOL; +} +pub const HW_PROFILE_GUIDLEN: usize = 39; +// MAX_PROFILE_LEN +pub const DOCKINFO_UNDOCKED: DWORD = 0x1; +pub const DOCKINFO_DOCKED: DWORD = 0x2; +pub const DOCKINFO_USER_SUPPLIED: DWORD = 0x4; +pub const DOCKINFO_USER_UNDOCKED: DWORD = DOCKINFO_USER_SUPPLIED | DOCKINFO_UNDOCKED; +pub const DOCKINFO_USER_DOCKED: DWORD = DOCKINFO_USER_SUPPLIED | DOCKINFO_DOCKED; +STRUCT!{struct HW_PROFILE_INFOA { + dwDockInfo: DWORD, + szHwProfileGuid: [CHAR; HW_PROFILE_GUIDLEN], + szHwProfileName: [CHAR; MAX_PROFILE_LEN], +}} +pub type LPHW_PROFILE_INFOA = *mut HW_PROFILE_INFOA; +STRUCT!{struct HW_PROFILE_INFOW { + dwDockInfo: DWORD, + szHwProfileGuid: [WCHAR; HW_PROFILE_GUIDLEN], + szHwProfileName: [WCHAR; MAX_PROFILE_LEN], +}} +pub type LPHW_PROFILE_INFOW = *mut HW_PROFILE_INFOW; +extern "system" { + pub fn GetCurrentHwProfileA( + lpHwProfileInfo: LPHW_PROFILE_INFOA, + ) -> BOOL; + pub fn GetCurrentHwProfileW( + lpHwProfileInfo: LPHW_PROFILE_INFOW, + ) -> BOOL; + pub fn VerifyVersionInfoA( + lpVersionInformation: LPOSVERSIONINFOEXA, + dwTypeMask: DWORD, + dwlConditionMask: DWORDLONG, + ) -> BOOL; + pub fn VerifyVersionInfoW( + lpVersionInformation: LPOSVERSIONINFOEXW, + dwTypeMask: DWORD, + dwlConditionMask: DWORDLONG, + ) -> BOOL; +} +STRUCT!{struct SYSTEM_POWER_STATUS { + ACLineStatus: BYTE, + BatteryFlag: BYTE, + BatteryLifePercent: BYTE, + Reserved1: BYTE, + BatteryLifeTime: DWORD, + BatteryFullLifeTime: DWORD, +}} +pub type LPSYSTEM_POWER_STATUS = *mut SYSTEM_POWER_STATUS; +extern "system" { + pub fn GetSystemPowerStatus( + lpSystemPowerStatus: LPSYSTEM_POWER_STATUS, + ) -> BOOL; + pub fn SetSystemPowerState( + fSuspend: BOOL, + fForce: BOOL, + ) -> BOOL; + pub fn MapUserPhysicalPagesScatter( + VirtualAddresses: *mut PVOID, + NumberOfPages: ULONG_PTR, + PageArray: PULONG_PTR, + ) -> BOOL; + pub fn CreateJobObjectA( + lpJobAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCSTR, + ) -> HANDLE; + pub fn OpenJobObjectA( + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + lpName: LPCSTR, + ) -> HANDLE; + pub fn CreateJobSet( + NumJob: ULONG, + UserJobSet: PJOB_SET_ARRAY, + Flags: ULONG, + ) -> BOOL; + pub fn FindFirstVolumeA( + lpszVolumeName: LPSTR, + cchBufferLength: DWORD, + ) -> HANDLE; + pub fn FindNextVolumeA( + hFindVolume: HANDLE, + lpszVolumeName: LPSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn FindFirstVolumeMountPointA( + lpszRootPathName: LPCSTR, + lpszVolumeMountPoint: LPSTR, + cchBufferLength: DWORD, + ) -> HANDLE; + pub fn FindFirstVolumeMountPointW( + lpszRootPathName: LPCWSTR, + lpszVolumeMountPoint: LPWSTR, + cchBufferLength: DWORD, + ) -> HANDLE; + pub fn FindNextVolumeMountPointA( + hFindVolumeMountPoint: HANDLE, + lpszVolumeMountPoint: LPSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn FindNextVolumeMountPointW( + hFindVolumeMountPoint: HANDLE, + lpszVolumeMountPoint: LPWSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn FindVolumeMountPointClose( + hFindVolumeMountPoint: HANDLE, + ) -> BOOL; + pub fn SetVolumeMountPointA( + lpszVolumeMountPoint: LPCSTR, + lpszVolumeName: LPCSTR, + ) -> BOOL; + pub fn SetVolumeMountPointW( + lpszVolumeMountPoint: LPCWSTR, + lpszVolumeName: LPCWSTR, + ) -> BOOL; + pub fn DeleteVolumeMountPointA( + lpszVolumeMountPoint: LPCSTR, + ) -> BOOL; + pub fn GetVolumeNameForVolumeMountPointA( + lpszVolumeMountPoint: LPCSTR, + lpszVolumeName: LPSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn GetVolumePathNameA( + lpszFileName: LPCSTR, + lpszVolumePathName: LPSTR, + cchBufferLength: DWORD, + ) -> BOOL; + pub fn GetVolumePathNamesForVolumeNameA( + lpszVolumeName: LPCSTR, + lpszVolumePathNames: LPCH, + cchBufferLength: DWORD, + lpcchReturnLength: PDWORD, + ) -> BOOL; +} +// ACTCTX_FLAG_* +STRUCT!{struct ACTCTXA { + cbSize: ULONG, + dwFlags: DWORD, + lpSource: LPCSTR, + wProcessorArchitecture: USHORT, + wLangId: LANGID, + lpAssemblyDirectory: LPCSTR, + lpResourceName: LPCSTR, + lpApplicationName: LPCSTR, + hModule: HMODULE, +}} +pub type PACTCTXA = *mut ACTCTXA; +STRUCT!{struct ACTCTXW { + cbSize: ULONG, + dwFlags: DWORD, + lpSource: LPCWSTR, + wProcessorArchitecture: USHORT, + wLangId: LANGID, + lpAssemblyDirectory: LPCWSTR, + lpResourceName: LPCWSTR, + lpApplicationName: LPCWSTR, + hModule: HMODULE, +}} +pub type PACTCTXW = *mut ACTCTXW; +pub type PCACTCTXA = *const ACTCTXA; +pub type PCACTCTXW = *const ACTCTXW; +extern "system" { + pub fn CreateActCtxA( + pActCtx: PCACTCTXA, + ) -> HANDLE; + pub fn CreateActCtxW( + pActCtx: PCACTCTXW, + ) -> HANDLE; + pub fn AddRefActCtx( + hActCtx: HANDLE, + ); + pub fn ReleaseActCtx( + hActCtx: HANDLE, + ); + pub fn ZombifyActCtx( + hActCtx: HANDLE, + ) -> BOOL; + pub fn ActivateActCtx( + hActCtx: HANDLE, + lpCookie: *mut ULONG_PTR, + ) -> BOOL; + pub fn DeactivateActCtx( + dwFlags: DWORD, + ulCookie: ULONG_PTR, + ) -> BOOL; + pub fn GetCurrentActCtx( + lphActCtx: *mut HANDLE, + ) -> BOOL; +} +STRUCT!{struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { + lpInformation: PVOID, + lpSectionBase: PVOID, + ulSectionLength: ULONG, + lpSectionGlobalDataBase: PVOID, + ulSectionGlobalDataLength: ULONG, +}} +pub type PACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA = + *mut ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; +pub type PCACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA = + *const ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA; +STRUCT!{struct ACTCTX_SECTION_KEYED_DATA { + cbSize: ULONG, + ulDataFormatVersion: ULONG, + lpData: PVOID, + ulLength: ULONG, + lpSectionGlobalData: PVOID, + ulSectionGlobalDataLength: ULONG, + lpSectionBase: PVOID, + ulSectionTotalLength: ULONG, + hActCtx: HANDLE, + ulAssemblyRosterIndex: ULONG, + ulFlags: ULONG, + AssemblyMetadata: ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA, +}} +pub type PACTCTX_SECTION_KEYED_DATA = *mut ACTCTX_SECTION_KEYED_DATA; +pub type PCACTCTX_SECTION_KEYED_DATA = *const ACTCTX_SECTION_KEYED_DATA; +extern "system" { + pub fn FindActCtxSectionStringA( + dwFlags: DWORD, + lpExtensionGuid: *const GUID, + ulSectionId: ULONG, + lpStringToFind: LPCSTR, + ReturnedData: PACTCTX_SECTION_KEYED_DATA, + ) -> BOOL; + pub fn FindActCtxSectionStringW( + dwFlags: DWORD, + lpExtensionGuid: *const GUID, + ulSectionId: ULONG, + lpStringToFind: LPCWSTR, + ReturnedData: PACTCTX_SECTION_KEYED_DATA, + ) -> BOOL; + pub fn FindActCtxSectionGuid( + dwFlags: DWORD, + lpExtensionGuid: *const GUID, + ulSectionId: ULONG, + lpGuidToFind: *const GUID, + ReturnedData: PACTCTX_SECTION_KEYED_DATA, + ) -> BOOL; + pub fn QueryActCtxW( + dwFlags: DWORD, + hActCtx: HANDLE, + pvSubInstance: PVOID, + ulInfoClass: ULONG, + pvBuffer: PVOID, + cbBuffer: SIZE_T, + pcbWrittenOrRequired: *mut SIZE_T, + ) -> BOOL; + pub fn WTSGetActiveConsoleSessionId() -> DWORD; + // pub fn WTSGetServiceSessionId(); + // pub fn WTSIsServerContainer(); + pub fn GetActiveProcessorGroupCount() -> WORD; + pub fn GetMaximumProcessorGroupCount() -> WORD; + pub fn GetActiveProcessorCount( + GroupNumber: WORD, + ) -> DWORD; + pub fn GetMaximumProcessorCount( + GroupNumber: WORD, + ) -> DWORD; + pub fn GetNumaProcessorNode( + Processor: UCHAR, + NodeNumber: PUCHAR, + ) -> BOOL; + pub fn GetNumaNodeNumberFromHandle( + hFile: HANDLE, + NodeNumber: PUSHORT, + ) -> BOOL; + pub fn GetNumaProcessorNodeEx( + Processor: PPROCESSOR_NUMBER, + NodeNumber: PUSHORT, + ) -> BOOL; + pub fn GetNumaNodeProcessorMask( + Node: UCHAR, + ProcessorMask: PULONGLONG, + ) -> BOOL; + pub fn GetNumaAvailableMemoryNode( + Node: UCHAR, + AvailableBytes: PULONGLONG, + ) -> BOOL; + pub fn GetNumaAvailableMemoryNodeEx( + Node: USHORT, + AvailableBytes: PULONGLONG, + ) -> BOOL; + pub fn GetNumaProximityNode( + ProximityId: ULONG, + NodeNumber: PUCHAR, + ) -> BOOL; +} +FN!{stdcall APPLICATION_RECOVERY_CALLBACK( + pvParameter: PVOID, +) -> DWORD} +// RESTART_* +// RECOVERY_* +extern "system" { + pub fn RegisterApplicationRecoveryCallback( + pRecoveyCallback: APPLICATION_RECOVERY_CALLBACK, + pvParameter: PVOID, + dwPingInterval: DWORD, + dwFlags: DWORD, + ) -> HRESULT; + pub fn UnregisterApplicationRecoveryCallback() -> HRESULT; + pub fn RegisterApplicationRestart( + pwzCommandline: PCWSTR, + dwFlags: DWORD, + ) -> HRESULT; + pub fn UnregisterApplicationRestart() -> HRESULT; + pub fn GetApplicationRecoveryCallback( + hProcess: HANDLE, + pRecoveryCallback: *mut APPLICATION_RECOVERY_CALLBACK, + ppvParameter: *mut PVOID, + pdwPingInterval: PDWORD, + pdwFlags: PDWORD, + ) -> HRESULT; + pub fn GetApplicationRestartSettings( + hProcess: HANDLE, + pwzCommandline: PWSTR, + pcchSize: PDWORD, + pdwFlags: PDWORD, + ) -> HRESULT; + pub fn ApplicationRecoveryInProgress( + pbCancelled: PBOOL, + ) -> HRESULT; + pub fn ApplicationRecoveryFinished( + bSuccess: BOOL, + ); +} +// FILE_BASIC_INFO, etc. +extern "system" { + pub fn GetFileInformationByHandleEx( + hFile: HANDLE, + FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; +} +ENUM!{enum FILE_ID_TYPE { + FileIdType, + ObjectIdType, + ExtendedFileIdType, + MaximumFileIdType, +}} +UNION!{union FILE_ID_DESCRIPTOR_u { + [u64; 2], + FileId FileId_mut: LARGE_INTEGER, + ObjectId ObjectId_mut: GUID, + ExtendedFileId ExtendedFileId_mut: FILE_ID_128, +}} +STRUCT!{struct FILE_ID_DESCRIPTOR { + dwSize: DWORD, + Type: FILE_ID_TYPE, + u: FILE_ID_DESCRIPTOR_u, +}} +pub type LPFILE_ID_DESCRIPTOR = *mut FILE_ID_DESCRIPTOR; +extern "system" { + pub fn OpenFileById( + hVolumeHint: HANDLE, + lpFileId: LPFILE_ID_DESCRIPTOR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwFlagsAndAttributes: DWORD, + ) -> HANDLE; + pub fn CreateSymbolicLinkA( + lpSymlinkFileName: LPCSTR, + lpTargetFileName: LPCSTR, + dwFlags: DWORD, + ) -> BOOLEAN; + pub fn CreateSymbolicLinkW( + lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + dwFlags: DWORD, + ) -> BOOLEAN; + pub fn QueryActCtxSettingsW( + dwFlags: DWORD, + hActCtx: HANDLE, + settingsNameSpace: PCWSTR, + settingName: PCWSTR, + pvBuffer: PWSTR, + dwBuffer: SIZE_T, + pdwWrittenOrRequired: *mut SIZE_T, + ) -> BOOL; + pub fn CreateSymbolicLinkTransactedA( + lpSymlinkFileName: LPCSTR, + lpTargetFileName: LPCSTR, + dwFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOLEAN; + pub fn CreateSymbolicLinkTransactedW( + lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + dwFlags: DWORD, + hTransaction: HANDLE, + ) -> BOOLEAN; + pub fn ReplacePartitionUnit( + TargetPartition: PWSTR, + SparePartition: PWSTR, + Flags: ULONG, + ) -> BOOL; + pub fn AddSecureMemoryCacheCallback( + pfnCallBack: PSECURE_MEMORY_CACHE_CALLBACK, + ) -> BOOL; + pub fn RemoveSecureMemoryCacheCallback( + pfnCallBack: PSECURE_MEMORY_CACHE_CALLBACK, + ) -> BOOL; + pub fn CopyContext( + Destination: PCONTEXT, + ContextFlags: DWORD, + Source: PCONTEXT, + ) -> BOOL; + pub fn InitializeContext( + Buffer: PVOID, + ContextFlags: DWORD, + Context: *mut PCONTEXT, + ContextLength: PDWORD, + ) -> BOOL; + pub fn GetEnabledXStateFeatures() -> DWORD64; + pub fn GetXStateFeaturesMask( + Context: PCONTEXT, + FeatureMask: PDWORD64, + ) -> BOOL; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn LocateXStateFeature( + Context: PCONTEXT, + FeatureId: DWORD, + Length: PDWORD, + ) -> PVOID; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn SetXStateFeaturesMask( + Context: PCONTEXT, + FeatureMask: DWORD64, + ) -> BOOL; + pub fn EnableThreadProfiling( + ThreadHandle: HANDLE, + Flags: DWORD, + HardwareCounters: DWORD64, + PerformanceDataHandle: *mut HANDLE, + ) -> BOOL; + pub fn DisableThreadProfiling( + PerformanceDataHandle: HANDLE, + ) -> DWORD; + pub fn QueryThreadProfiling( + ThreadHandle: HANDLE, + Enabled: PBOOLEAN, + ) -> DWORD; + pub fn ReadThreadProfilingData( + PerformanceDataHandle: HANDLE, + Flags: DWORD, + PerformanceData: PPERFORMANCE_DATA, + ) -> DWORD; + // intrinsic InterlockedIncrement + // intrinsic InterlockedDecrement + // intrinsic InterlockedExchange + // intrinsic InterlockedExchangeAdd + // intrinsic InterlockedExchangeSubtract + // intrinsic InterlockedCompareExchange + // intrinsic InterlockedAnd + // intrinsic InterlockedOr + // intrinsic InterlockedXor +} diff --git a/winapi/src/um/wincodec.rs b/winapi/src/um/wincodec.rs new file mode 100644 index 000000000..dbe8a4456 --- /dev/null +++ b/winapi/src/um/wincodec.rs @@ -0,0 +1,1861 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Mappings for the contents of wincodec.h +use ctypes::c_double; +use shared::basetsd::{UINT32, ULONG_PTR}; +use shared::dxgiformat::DXGI_FORMAT; +use shared::dxgitype::{ + DXGI_JPEG_AC_HUFFMAN_TABLE, DXGI_JPEG_DC_HUFFMAN_TABLE, + DXGI_JPEG_QUANTIZATION_TABLE +}; +use shared::guiddef::{CLSID, GUID, REFCLSID, REFGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, FLOAT, INT, LPVOID, UINT, ULONG}; +use shared::ntdef::{LPCWSTR, LPWSTR, PCWSTR, WCHAR}; +use shared::windef::{HBITMAP, HICON, HPALETTE}; +use shared::winerror::{ + E_ABORT, E_ACCESSDENIED, E_FAIL, E_INVALIDARG, E_NOTIMPL, E_OUTOFMEMORY, HRESULT, + SEVERITY_ERROR +}; +use um::d2d1::ID2D1Image; +use um::d2d1_1::ID2D1Device; +use um::dcommon::D2D1_PIXEL_FORMAT; +use um::objidlbase::{IEnumString, IEnumUnknown, IStream, IStreamVtbl}; +use um::ocidl::IPropertyBag2; +use um::propidl::PROPVARIANT; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::{HANDLE, ULARGE_INTEGER}; +DEFINE_GUID!{CLSID_WICImagingFactory, + 0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa} +DEFINE_GUID!{CLSID_WICImagingFactory1, + 0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa} +DEFINE_GUID!{CLSID_WICImagingFactory2, + 0x317d06e8, 0x5f24, 0x433d, 0xbd, 0xf7, 0x79, 0xce, 0x68, 0xd8, 0xab, 0xc2} +DEFINE_GUID!{GUID_VendorMicrosoft, + 0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b} +DEFINE_GUID!{GUID_VendorMicrosoftBuiltIn, + 0x257a30fd, 0x6b6, 0x462b, 0xae, 0xa4, 0x63, 0xf7, 0xb, 0x86, 0xe5, 0x33} +DEFINE_GUID!{CLSID_WICPngDecoder, + 0x389ea17b, 0x5078, 0x4cde, 0xb6, 0xef, 0x25, 0xc1, 0x51, 0x75, 0xc7, 0x51} +DEFINE_GUID!{CLSID_WICPngDecoder1, + 0x389ea17b, 0x5078, 0x4cde, 0xb6, 0xef, 0x25, 0xc1, 0x51, 0x75, 0xc7, 0x51} +DEFINE_GUID!{CLSID_WICPngDecoder2, + 0xe018945b, 0xaa86, 0x4008, 0x9b, 0xd4, 0x67, 0x77, 0xa1, 0xe4, 0x0c, 0x11} +DEFINE_GUID!{CLSID_WICBmpDecoder, + 0x6b462062, 0x7cbf, 0x400d, 0x9f, 0xdb, 0x81, 0x3d, 0xd1, 0x0f, 0x27, 0x78} +DEFINE_GUID!{CLSID_WICIcoDecoder, + 0xc61bfcdf, 0x2e0f, 0x4aad, 0xa8, 0xd7, 0xe0, 0x6b, 0xaf, 0xeb, 0xcd, 0xfe} +DEFINE_GUID!{CLSID_WICJpegDecoder, + 0x9456a480, 0xe88b, 0x43ea, 0x9e, 0x73, 0x0b, 0x2d, 0x9b, 0x71, 0xb1, 0xca} +DEFINE_GUID!{CLSID_WICGifDecoder, + 0x381dda3c, 0x9ce9, 0x4834, 0xa2, 0x3e, 0x1f, 0x98, 0xf8, 0xfc, 0x52, 0xbe} +DEFINE_GUID!{CLSID_WICTiffDecoder, + 0xb54e85d9, 0xfe23, 0x499f, 0x8b, 0x88, 0x6a, 0xce, 0xa7, 0x13, 0x75, 0x2b} +DEFINE_GUID!{CLSID_WICWmpDecoder, + 0xa26cec36, 0x234c, 0x4950, 0xae, 0x16, 0xe3, 0x4a, 0xac, 0xe7, 0x1d, 0x0d} +DEFINE_GUID!{CLSID_WICDdsDecoder, + 0x9053699f, 0xa341, 0x429d, 0x9e, 0x90, 0xee, 0x43, 0x7c, 0xf8, 0x0c, 0x73} +DEFINE_GUID!{CLSID_WICBmpEncoder, + 0x69be8bb4, 0xd66d, 0x47c8, 0x86, 0x5a, 0xed, 0x15, 0x89, 0x43, 0x37, 0x82} +DEFINE_GUID!{CLSID_WICPngEncoder, + 0x27949969, 0x876a, 0x41d7, 0x94, 0x47, 0x56, 0x8f, 0x6a, 0x35, 0xa4, 0xdc} +DEFINE_GUID!{CLSID_WICJpegEncoder, + 0x1a34f5c1, 0x4a5a, 0x46dc, 0xb6, 0x44, 0x1f, 0x45, 0x67, 0xe7, 0xa6, 0x76} +DEFINE_GUID!{CLSID_WICGifEncoder, + 0x114f5598, 0x0b22, 0x40a0, 0x86, 0xa1, 0xc8, 0x3e, 0xa4, 0x95, 0xad, 0xbd} +DEFINE_GUID!{CLSID_WICTiffEncoder, + 0x0131be10, 0x2001, 0x4c5f, 0xa9, 0xb0, 0xcc, 0x88, 0xfa, 0xb6, 0x4c, 0xe8} +DEFINE_GUID!{CLSID_WICWmpEncoder, + 0xac4ce3cb, 0xe1c1, 0x44cd, 0x82, 0x15, 0x5a, 0x16, 0x65, 0x50, 0x9e, 0xc2} +DEFINE_GUID!{CLSID_WICDdsEncoder, + 0xa61dde94, 0x66ce, 0x4ac1, 0x88, 0x1b, 0x71, 0x68, 0x05, 0x88, 0x89, 0x5e} +DEFINE_GUID!{CLSID_WICAdngDecoder, + 0x981d9411, 0x909e, 0x42a7, 0x8f, 0x5d, 0xa7, 0x47, 0xff, 0x05, 0x2e, 0xdb} +DEFINE_GUID!{CLSID_WICJpegQualcommPhoneEncoder, + 0x68ed5c62, 0xf534, 0x4979, 0xb2, 0xb3, 0x68, 0x6a, 0x12, 0xb2, 0xb3, 0x4c} +DEFINE_GUID!{GUID_ContainerFormatBmp, + 0x0af1d87e, 0xfcfe, 0x4188, 0xbd, 0xeb, 0xa7, 0x90, 0x64, 0x71, 0xcb, 0xe3} +DEFINE_GUID!{GUID_ContainerFormatPng, + 0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf} +DEFINE_GUID!{GUID_ContainerFormatIco, + 0xa3a860c4, 0x338f, 0x4c17, 0x91, 0x9a, 0xfb, 0xa4, 0xb5, 0x62, 0x8f, 0x21} +DEFINE_GUID!{GUID_ContainerFormatJpeg, + 0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57} +DEFINE_GUID!{GUID_ContainerFormatTiff, + 0x163bcc30, 0xe2e9, 0x4f0b, 0x96, 0x1d, 0xa3, 0xe9, 0xfd, 0xb7, 0x88, 0xa3} +DEFINE_GUID!{GUID_ContainerFormatGif, + 0x1f8a5601, 0x7d4d, 0x4cbd, 0x9c, 0x82, 0x1b, 0xc8, 0xd4, 0xee, 0xb9, 0xa5} +DEFINE_GUID!{GUID_ContainerFormatWmp, + 0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b} +DEFINE_GUID!{GUID_ContainerFormatDds, + 0x9967cb95, 0x2e85, 0x4ac8, 0x8c, 0xa2, 0x83, 0xd7, 0xcc, 0xd4, 0x25, 0xc9} +DEFINE_GUID!{GUID_ContainerFormatAdng, + 0xf3ff6d0d, 0x38c0, 0x41c4, 0xb1, 0xfe, 0x1f, 0x38, 0x24, 0xf1, 0x7b, 0x84} +DEFINE_GUID!{CLSID_WICImagingCategories, + 0xfae3d380, 0xfea4, 0x4623, 0x8c, 0x75, 0xc6, 0xb6, 0x11, 0x10, 0xb6, 0x81} +DEFINE_GUID!{CATID_WICBitmapDecoders, + 0x7ed96837, 0x96f0, 0x4812, 0xb2, 0x11, 0xf1, 0x3c, 0x24, 0x11, 0x7e, 0xd3} +DEFINE_GUID!{CATID_WICBitmapEncoders, + 0xac757296, 0x3522, 0x4e11, 0x98, 0x62, 0xc1, 0x7b, 0xe5, 0xa1, 0x76, 0x7e} +DEFINE_GUID!{CATID_WICPixelFormats, + 0x2b46e70f, 0xcda7, 0x473e, 0x89, 0xf6, 0xdc, 0x96, 0x30, 0xa2, 0x39, 0x0b} +DEFINE_GUID!{CATID_WICFormatConverters, + 0x7835eae8, 0xbf14, 0x49d1, 0x93, 0xce, 0x53, 0x3a, 0x40, 0x7b, 0x22, 0x48} +DEFINE_GUID!{CATID_WICMetadataReader, + 0x05af94d8, 0x7174, 0x4cd2, 0xbe, 0x4a, 0x41, 0x24, 0xb8, 0x0e, 0xe4, 0xb8} +DEFINE_GUID!{CATID_WICMetadataWriter, + 0xabe3b9a4, 0x257d, 0x4b97, 0xbd, 0x1a, 0x29, 0x4a, 0xf4, 0x96, 0x22, 0x2e} +DEFINE_GUID!{CLSID_WICDefaultFormatConverter, + 0x1a3f11dc, 0xb514, 0x4b17, 0x8c, 0x5f, 0x21, 0x54, 0x51, 0x38, 0x52, 0xf1} +DEFINE_GUID!{CLSID_WICFormatConverterHighColor, + 0xac75d454, 0x9f37, 0x48f8, 0xb9, 0x72, 0x4e, 0x19, 0xbc, 0x85, 0x60, 0x11} +DEFINE_GUID!{CLSID_WICFormatConverterNChannel, + 0xc17cabb2, 0xd4a3, 0x47d7, 0xa5, 0x57, 0x33, 0x9b, 0x2e, 0xfb, 0xd4, 0xf1} +DEFINE_GUID!{CLSID_WICFormatConverterWMPhoto, + 0x9cb5172b, 0xd600, 0x46ba, 0xab, 0x77, 0x77, 0xbb, 0x7e, 0x3a, 0x00, 0xd9} +DEFINE_GUID!{CLSID_WICPlanarFormatConverter, + 0x184132b8, 0x32f8, 0x4784, 0x91, 0x31, 0xdd, 0x72, 0x24, 0xb2, 0x34, 0x38} +pub type WICColor = UINT32; +STRUCT!{struct WICRect { + X: INT, + Y: INT, + Width: INT, + Height: INT, +}} +pub type WICInProcPointer = *mut BYTE; +ENUM!{enum WICColorContextType { + WICColorContextUninitialized = 0x00000000, + WICColorContextProfile = 0x00000001, + WICColorContextExifColorSpace = 0x00000002, +}} +pub const CODEC_FORCE_DWORD: DWORD = 0x7FFFFFFF; +pub const WIC_JPEG_MAX_COMPONENT_COUNT: UINT = 4; +pub const WIC_JPEG_MAX_TABLE_INDEX: UINT = 3; +pub const WIC_JPEG_SAMPLE_FACTORS_ONE: DWORD = 0x00000011; +pub const WIC_JPEG_SAMPLE_FACTORS_THREE_420: DWORD = 0x00111122; +pub const WIC_JPEG_SAMPLE_FACTORS_THREE_422: DWORD = 0x00111121; +pub const WIC_JPEG_SAMPLE_FACTORS_THREE_440: DWORD = 0x00111112; +pub const WIC_JPEG_SAMPLE_FACTORS_THREE_444: DWORD = 0x00111111; +pub const WIC_JPEG_QUANTIZATION_BASELINE_ONE: DWORD = 0x00000000; +pub const WIC_JPEG_QUANTIZATION_BASELINE_THREE: DWORD = 0x00010100; +pub const WIC_JPEG_HUFFMAN_BASELINE_ONE: DWORD = 0x00000000; +pub const WIC_JPEG_HUFFMAN_BASELINE_THREE: DWORD = 0x00111100; +pub type REFWICPixelFormatGUID = REFGUID; +pub type WICPixelFormatGUID = GUID; +DEFINE_GUID!{GUID_WICPixelFormatDontCare, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00} +DEFINE_GUID!{GUID_WICPixelFormat1bppIndexed, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01} +DEFINE_GUID!{GUID_WICPixelFormat2bppIndexed, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02} +DEFINE_GUID!{GUID_WICPixelFormat4bppIndexed, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03} +DEFINE_GUID!{GUID_WICPixelFormat8bppIndexed, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04} +DEFINE_GUID!{GUID_WICPixelFormatBlackWhite, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05} +DEFINE_GUID!{GUID_WICPixelFormat2bppGray, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06} +DEFINE_GUID!{GUID_WICPixelFormat4bppGray, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07} +DEFINE_GUID!{GUID_WICPixelFormat8bppGray, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08} +DEFINE_GUID!{GUID_WICPixelFormat8bppAlpha, + 0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85, 0x27, 0xdd, 0x9f, 0xb3, 0xa8, 0x95} +DEFINE_GUID!{GUID_WICPixelFormat16bppBGR555, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09} +DEFINE_GUID!{GUID_WICPixelFormat16bppBGR565, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a} +DEFINE_GUID!{GUID_WICPixelFormat16bppBGRA5551, + 0x05ec7c2b, 0xf1e6, 0x4961, 0xad, 0x46, 0xe1, 0xcc, 0x81, 0x0a, 0x87, 0xd2} +DEFINE_GUID!{GUID_WICPixelFormat16bppGray, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b} +DEFINE_GUID!{GUID_WICPixelFormat24bppBGR, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c} +DEFINE_GUID!{GUID_WICPixelFormat24bppRGB, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d} +DEFINE_GUID!{GUID_WICPixelFormat32bppBGR, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e} +DEFINE_GUID!{GUID_WICPixelFormat32bppBGRA, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f} +DEFINE_GUID!{GUID_WICPixelFormat32bppPBGRA, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10} +DEFINE_GUID!{GUID_WICPixelFormat32bppGrayFloat, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11} +DEFINE_GUID!{GUID_WICPixelFormat32bppRGB, + 0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1} +DEFINE_GUID!{GUID_WICPixelFormat32bppRGBA, + 0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9} +DEFINE_GUID!{GUID_WICPixelFormat32bppPRGBA, + 0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba} +DEFINE_GUID!{GUID_WICPixelFormat48bppRGB, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15} +DEFINE_GUID!{GUID_WICPixelFormat48bppBGR, + 0xe605a384, 0xb468, 0x46ce, 0xbb, 0x2e, 0x36, 0xf1, 0x80, 0xe6, 0x43, 0x13} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGB, + 0xa1182111, 0x186d, 0x4d42, 0xbc, 0x6a, 0x9c, 0x83, 0x03, 0xa8, 0xdf, 0xf9} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGBA, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16} +DEFINE_GUID!{GUID_WICPixelFormat64bppBGRA, + 0x1562ff7c, 0xd352, 0x46f9, 0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46} +DEFINE_GUID!{GUID_WICPixelFormat64bppPRGBA, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17} +DEFINE_GUID!{GUID_WICPixelFormat64bppPBGRA, + 0x8c518e8e, 0xa4ec, 0x468b, 0xae, 0x70, 0xc9, 0xa3, 0x5a, 0x9c, 0x55, 0x30} +DEFINE_GUID!{GUID_WICPixelFormat16bppGrayFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13} +DEFINE_GUID!{GUID_WICPixelFormat32bppBGR101010, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14} +DEFINE_GUID!{GUID_WICPixelFormat48bppRGBFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12} +DEFINE_GUID!{GUID_WICPixelFormat48bppBGRFixedPoint, + 0x49ca140e, 0xcab6, 0x493b, 0x9d, 0xdf, 0x60, 0x18, 0x7c, 0x37, 0x53, 0x2a} +DEFINE_GUID!{GUID_WICPixelFormat96bppRGBFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18} +DEFINE_GUID!{GUID_WICPixelFormat96bppRGBFloat, + 0xe3fed78f, 0xe8db, 0x4acf, 0x84, 0xc1, 0xe9, 0x7f, 0x61, 0x36, 0xb3, 0x27} +DEFINE_GUID!{GUID_WICPixelFormat128bppRGBAFloat, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19} +DEFINE_GUID!{GUID_WICPixelFormat128bppPRGBAFloat, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a} +DEFINE_GUID!{GUID_WICPixelFormat128bppRGBFloat, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b} +DEFINE_GUID!{GUID_WICPixelFormat32bppCMYK, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGBAFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d} +DEFINE_GUID!{GUID_WICPixelFormat64bppBGRAFixedPoint, + 0x356de33c, 0x54d2, 0x4a23, 0xbb, 0x4, 0x9b, 0x7b, 0xf9, 0xb1, 0xd4, 0x2d} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGBFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40} +DEFINE_GUID!{GUID_WICPixelFormat128bppRGBAFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e} +DEFINE_GUID!{GUID_WICPixelFormat128bppRGBFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGBAHalf, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a} +DEFINE_GUID!{GUID_WICPixelFormat64bppPRGBAHalf, + 0x58ad26c2, 0xc623, 0x4d9d, 0xb3, 0x20, 0x38, 0x7e, 0x49, 0xf8, 0xc4, 0x42} +DEFINE_GUID!{GUID_WICPixelFormat64bppRGBHalf, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42} +DEFINE_GUID!{GUID_WICPixelFormat48bppRGBHalf, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b} +DEFINE_GUID!{GUID_WICPixelFormat32bppRGBE, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d} +DEFINE_GUID!{GUID_WICPixelFormat16bppGrayHalf, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e} +DEFINE_GUID!{GUID_WICPixelFormat32bppGrayFixedPoint, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f} +DEFINE_GUID!{GUID_WICPixelFormat32bppRGBA1010102, + 0x25238D72, 0xFCF9, 0x4522, 0xb5, 0x14, 0x55, 0x78, 0xe5, 0xad, 0x55, 0xe0} +DEFINE_GUID!{GUID_WICPixelFormat32bppRGBA1010102XR, + 0x00DE6B9A, 0xC101, 0x434b, 0xb5, 0x02, 0xd0, 0x16, 0x5e, 0xe1, 0x12, 0x2c} +DEFINE_GUID!{GUID_WICPixelFormat64bppCMYK, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f} +DEFINE_GUID!{GUID_WICPixelFormat24bpp3Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20} +DEFINE_GUID!{GUID_WICPixelFormat32bpp4Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21} +DEFINE_GUID!{GUID_WICPixelFormat40bpp5Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22} +DEFINE_GUID!{GUID_WICPixelFormat48bpp6Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23} +DEFINE_GUID!{GUID_WICPixelFormat56bpp7Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24} +DEFINE_GUID!{GUID_WICPixelFormat64bpp8Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25} +DEFINE_GUID!{GUID_WICPixelFormat48bpp3Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26} +DEFINE_GUID!{GUID_WICPixelFormat64bpp4Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27} +DEFINE_GUID!{GUID_WICPixelFormat80bpp5Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28} +DEFINE_GUID!{GUID_WICPixelFormat96bpp6Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29} +DEFINE_GUID!{GUID_WICPixelFormat112bpp7Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a} +DEFINE_GUID!{GUID_WICPixelFormat128bpp8Channels, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b} +DEFINE_GUID!{GUID_WICPixelFormat40bppCMYKAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c} +DEFINE_GUID!{GUID_WICPixelFormat80bppCMYKAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d} +DEFINE_GUID!{GUID_WICPixelFormat32bpp3ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e} +DEFINE_GUID!{GUID_WICPixelFormat40bpp4ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f} +DEFINE_GUID!{GUID_WICPixelFormat48bpp5ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30} +DEFINE_GUID!{GUID_WICPixelFormat56bpp6ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31} +DEFINE_GUID!{GUID_WICPixelFormat64bpp7ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32} +DEFINE_GUID!{GUID_WICPixelFormat72bpp8ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33} +DEFINE_GUID!{GUID_WICPixelFormat64bpp3ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34} +DEFINE_GUID!{GUID_WICPixelFormat80bpp4ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35} +DEFINE_GUID!{GUID_WICPixelFormat96bpp5ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36} +DEFINE_GUID!{GUID_WICPixelFormat112bpp6ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37} +DEFINE_GUID!{GUID_WICPixelFormat128bpp7ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38} +DEFINE_GUID!{GUID_WICPixelFormat144bpp8ChannelsAlpha, + 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39} +DEFINE_GUID!{GUID_WICPixelFormat8bppY, + 0x91B4DB54, 0x2DF9, 0x42F0, 0xB4, 0x49, 0x29, 0x09, 0xBB, 0x3D, 0xF8, 0x8E} +DEFINE_GUID!{GUID_WICPixelFormat8bppCb, + 0x1339F224, 0x6BFE, 0x4C3E, 0x93, 0x02, 0xE4, 0xF3, 0xA6, 0xD0, 0xCA, 0x2A} +DEFINE_GUID!{GUID_WICPixelFormat8bppCr, + 0xB8145053, 0x2116, 0x49F0, 0x88, 0x35, 0xED, 0x84, 0x4B, 0x20, 0x5C, 0x51} +DEFINE_GUID!{GUID_WICPixelFormat16bppCbCr, + 0xFF95BA6E, 0x11E0, 0x4263, 0xBB, 0x45, 0x01, 0x72, 0x1F, 0x34, 0x60, 0xA4} +DEFINE_GUID!{GUID_WICPixelFormat16bppYQuantizedDctCoefficients, + 0xA355F433, 0x48E8, 0x4A42, 0x84, 0xD8, 0xE2, 0xAA, 0x26, 0xCA, 0x80, 0xA4} +DEFINE_GUID!{GUID_WICPixelFormat16bppCbQuantizedDctCoefficients, + 0xD2C4FF61, 0x56A5, 0x49C2, 0x8B, 0x5C, 0x4C, 0x19, 0x25, 0x96, 0x48, 0x37} +DEFINE_GUID!{GUID_WICPixelFormat16bppCrQuantizedDctCoefficients, + 0x2FE354F0, 0x1680, 0x42D8, 0x92, 0x31, 0xE7, 0x3C, 0x05, 0x65, 0xBF, 0xC1} +ENUM!{enum WICBitmapCreateCacheOption { + WICBitmapNoCache = 0x00000000, + WICBitmapCacheOnDemand = 0x00000001, + WICBitmapCacheOnLoad = 0x00000002, + WICBITMAPCREATECACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICDecodeOptions { + WICDecodeMetadataCacheOnDemand = 0x00000000, + WICDecodeMetadataCacheOnLoad = 0x00000001, + WICMETADATACACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapEncoderCacheOption { + WICBitmapEncoderCacheInMemory = 0x00000000, + WICBitmapEncoderCacheTempFile = 0x00000001, + WICBitmapEncoderNoCache = 0x00000002, + WICBITMAPENCODERCACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICComponentType { + WICDecoder = 0x00000001, + WICEncoder = 0x00000002, + WICPixelFormatConverter = 0x00000004, + WICMetadataReader = 0x00000008, + WICMetadataWriter = 0x00000010, + WICPixelFormat = 0x00000020, + WICAllComponents = 0x0000003F, + WICCOMPONENTTYPE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICComponentEnumerateOptions { + WICComponentEnumerateDefault = 0x00000000, + WICComponentEnumerateRefresh = 0x00000001, + WICComponentEnumerateDisabled = 0x80000000, + WICComponentEnumerateUnsigned = 0x40000000, + WICComponentEnumerateBuiltInOnly = 0x20000000, + WICCOMPONENTENUMERATEOPTIONS_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +STRUCT!{struct WICBitmapPattern { + Position: ULARGE_INTEGER, + Length: ULONG, + Pattern: *mut BYTE, + Mask: *mut BYTE, + EndOfStream: BOOL, +}} +ENUM!{enum WICBitmapInterpolationMode { + WICBitmapInterpolationModeNearestNeighbor = 0x00000000, + WICBitmapInterpolationModeLinear = 0x00000001, + WICBitmapInterpolationModeCubic = 0x00000002, + WICBitmapInterpolationModeFant = 0x00000003, + WICBitmapInterpolationModeHighQualityCubic = 0x00000004, + WICBITMAPINTERPOLATIONMODE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapPaletteType { + WICBitmapPaletteTypeCustom = 0x00000000, + WICBitmapPaletteTypeMedianCut = 0x00000001, + WICBitmapPaletteTypeFixedBW = 0x00000002, + WICBitmapPaletteTypeFixedHalftone8 = 0x00000003, + WICBitmapPaletteTypeFixedHalftone27 = 0x00000004, + WICBitmapPaletteTypeFixedHalftone64 = 0x00000005, + WICBitmapPaletteTypeFixedHalftone125 = 0x00000006, + WICBitmapPaletteTypeFixedHalftone216 = 0x00000007, + WICBitmapPaletteTypeFixedWebPalette = WICBitmapPaletteTypeFixedHalftone216, + WICBitmapPaletteTypeFixedHalftone252 = 0x00000008, + WICBitmapPaletteTypeFixedHalftone256 = 0x00000009, + WICBitmapPaletteTypeFixedGray4 = 0x0000000A, + WICBitmapPaletteTypeFixedGray16 = 0x0000000B, + WICBitmapPaletteTypeFixedGray256 = 0x0000000C, + WICBITMAPPALETTETYPE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapDitherType { + WICBitmapDitherTypeNone = 0x00000000, + WICBitmapDitherTypeSolid = 0x00000000, + WICBitmapDitherTypeOrdered4x4 = 0x00000001, + WICBitmapDitherTypeOrdered8x8 = 0x00000002, + WICBitmapDitherTypeOrdered16x16 = 0x00000003, + WICBitmapDitherTypeSpiral4x4 = 0x00000004, + WICBitmapDitherTypeSpiral8x8 = 0x00000005, + WICBitmapDitherTypeDualSpiral4x4 = 0x00000006, + WICBitmapDitherTypeDualSpiral8x8 = 0x00000007, + WICBitmapDitherTypeErrorDiffusion = 0x00000008, + WICBITMAPDITHERTYPE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapAlphaChannelOption { + WICBitmapUseAlpha = 0x00000000, + WICBitmapUsePremultipliedAlpha = 0x00000001, + WICBitmapIgnoreAlpha = 0x00000002, + WICBITMAPALPHACHANNELOPTIONS_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapTransformOptions { + WICBitmapTransformRotate0 = 0x00000000, + WICBitmapTransformRotate90 = 0x00000001, + WICBitmapTransformRotate180 = 0x00000002, + WICBitmapTransformRotate270 = 0x00000003, + WICBitmapTransformFlipHorizontal = 0x00000008, + WICBitmapTransformFlipVertical = 0x00000010, + WICBITMAPTRANSFORMOPTIONS_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapLockFlags { + WICBitmapLockRead = 0x00000001, + WICBitmapLockWrite = 0x00000002, + WICBITMAPLOCKFLAGS_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICBitmapDecoderCapabilities { + WICBitmapDecoderCapabilitySameEncoder = 0x00000001, + WICBitmapDecoderCapabilityCanDecodeAllImages = 0x00000002, + WICBitmapDecoderCapabilityCanDecodeSomeImages = 0x00000004, + WICBitmapDecoderCapabilityCanEnumerateMetadata = 0x00000008, + WICBitmapDecoderCapabilityCanDecodeThumbnail = 0x00000010, + WICBITMAPDECODERCAPABILITIES_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICProgressOperation { + WICProgressOperationCopyPixels = 0x00000001, + WICProgressOperationWritePixels = 0x00000002, + WICProgressOperationAll = 0x0000FFFF, + WICPROGRESSOPERATION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICProgressNotification { + WICProgressNotificationBegin = 0x00010000, + WICProgressNotificationEnd = 0x00020000, + WICProgressNotificationFrequent = 0x00040000, + WICProgressNotificationAll = 0xFFFF0000, + WICPROGRESSNOTIFICATION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICComponentSigning { + WICComponentSigned = 0x00000001, + WICComponentUnsigned = 0x00000002, + WICComponentSafe = 0x00000004, + WICComponentDisabled = 0x80000000, + WICCOMPONENTSIGNING_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICGifLogicalScreenDescriptorProperties { + WICGifLogicalScreenSignature = 0x00000001, + WICGifLogicalScreenDescriptorWidth = 0x00000002, + WICGifLogicalScreenDescriptorHeight = 0x00000003, + WICGifLogicalScreenDescriptorGlobalColorTableFlag = 0x00000004, + WICGifLogicalScreenDescriptorColorResolution = 0x00000005, + WICGifLogicalScreenDescriptorSortFlag = 0x00000006, + WICGifLogicalScreenDescriptorGlobalColorTableSize = 0x00000007, + WICGifLogicalScreenDescriptorBackgroundColorIndex = 0x00000008, + WICGifLogicalScreenDescriptorPixelAspectRatio = 0x00000009, + WICGifLogicalScreenDescriptorProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICGifImageDescriptorProperties { + WICGifImageDescriptorLeft = 0x00000001, + WICGifImageDescriptorTop = 0x00000002, + WICGifImageDescriptorWidth = 0x00000003, + WICGifImageDescriptorHeight = 0x00000004, + WICGifImageDescriptorLocalColorTableFlag = 0x00000005, + WICGifImageDescriptorInterlaceFlag = 0x00000006, + WICGifImageDescriptorSortFlag = 0x00000007, + WICGifImageDescriptorLocalColorTableSize = 0x00000008, + WICGifImageDescriptorProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICGifGraphicControlExtensionProperties { + WICGifGraphicControlExtensionDisposal = 0x00000001, + WICGifGraphicControlExtensionUserInputFlag = 0x00000002, + WICGifGraphicControlExtensionTransparencyFlag = 0x00000003, + WICGifGraphicControlExtensionDelay = 0x00000004, + WICGifGraphicControlExtensionTransparentColorIndex = 0x00000005, + WICGifGraphicControlExtensionProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICGifApplicationExtensionProperties { + WICGifApplicationExtensionApplication = 0x00000001, + WICGifApplicationExtensionData = 0x00000002, + WICGifApplicationExtensionProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICGifCommentExtensionProperties { + WICGifCommentExtensionText = 0x00000001, + WICGifCommentExtensionProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegCommentProperties { + WICJpegCommentText = 0x00000001, + WICJpegCommentProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegLuminanceProperties { + WICJpegLuminanceTable = 0x00000001, + WICJpegLuminanceProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegChrominanceProperties { + WICJpegChrominanceTable = 0x00000001, + WICJpegChrominanceProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WIC8BIMIptcProperties { + WIC8BIMIptcPString = 0x00000000, + WIC8BIMIptcEmbeddedIPTC = 0x00000001, + WIC8BIMIptcProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WIC8BIMResolutionInfoProperties { + WIC8BIMResolutionInfoPString = 0x00000001, + WIC8BIMResolutionInfoHResolution = 0x00000002, + WIC8BIMResolutionInfoHResolutionUnit = 0x00000003, + WIC8BIMResolutionInfoWidthUnit = 0x00000004, + WIC8BIMResolutionInfoVResolution = 0x00000005, + WIC8BIMResolutionInfoVResolutionUnit = 0x00000006, + WIC8BIMResolutionInfoHeightUnit = 0x00000007, + WIC8BIMResolutionInfoProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WIC8BIMIptcDigestProperties { + WIC8BIMIptcDigestPString = 0x00000001, + WIC8BIMIptcDigestIptcDigest = 0x00000002, + WIC8BIMIptcDigestProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngGamaProperties { + WICPngGamaGamma = 0x00000001, + WICPngGamaProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngBkgdProperties { + WICPngBkgdBackgroundColor = 0x00000001, + WICPngBkgdProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngItxtProperties { + WICPngItxtKeyword = 0x00000001, + WICPngItxtCompressionFlag = 0x00000002, + WICPngItxtLanguageTag = 0x00000003, + WICPngItxtTranslatedKeyword = 0x00000004, + WICPngItxtText = 0x00000005, + WICPngItxtProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngChrmProperties { + WICPngChrmWhitePointX = 0x00000001, + WICPngChrmWhitePointY = 0x00000002, + WICPngChrmRedX = 0x00000003, + WICPngChrmRedY = 0x00000004, + WICPngChrmGreenX = 0x00000005, + WICPngChrmGreenY = 0x00000006, + WICPngChrmBlueX = 0x00000007, + WICPngChrmBlueY = 0x0000008, + WICPngChrmProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngHistProperties { + WICPngHistFrequencies = 0x00000001, + WICPngHistProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngIccpProperties { + WICPngIccpProfileName = 0x00000001, + WICPngIccpProfileData = 0x00000002, + WICPngIccpProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngSrgbProperties { + WICPngSrgbRenderingIntent = 0x00000001, + WICPngSrgbProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngTimeProperties { + WICPngTimeYear = 0x00000001, + WICPngTimeMonth = 0x00000002, + WICPngTimeDay = 0x00000003, + WICPngTimeHour = 0x00000004, + WICPngTimeMinute = 0x00000005, + WICPngTimeSecond = 0x00000006, + WICPngTimeProperties_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICSectionAccessLevel { + WICSectionAccessLevelRead = 0x00000001, + WICSectionAccessLevelReadWrite = 0x00000003, + WICSectionAccessLevel_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPixelFormatNumericRepresentation { + WICPixelFormatNumericRepresentationUnspecified = 0x00000000, + WICPixelFormatNumericRepresentationIndexed = 0x00000001, + WICPixelFormatNumericRepresentationUnsignedInteger = 0x00000002, + WICPixelFormatNumericRepresentationSignedInteger = 0x00000003, + WICPixelFormatNumericRepresentationFixed = 0x00000004, + WICPixelFormatNumericRepresentationFloat = 0x00000005, + WICPixelFormatNumericRepresentation_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPlanarOptions { + WICPlanarOptionsDefault = 0x00000000, + WICPlanarOptionsPreserveSubsampling = 0x00000001, + WICPLANAROPTIONS_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegIndexingOptions { + WICJpegIndexingOptionsGenerateOnDemand = 0x00000000, + WICJpegIndexingOptionsGenerateOnLoad = 0x00000001, + WICJpegIndexingOptions_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegTransferMatrix { + WICJpegTransferMatrixIdentity = 0x00000000, + WICJpegTransferMatrixBT601 = 0x00000001, + WICJpegTransferMatrix_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegScanType { + WICJpegScanTypeInterleaved = 0x00000000, + WICJpegScanTypePlanarComponents = 0x00000001, + WICJpegScanTypeProgressive = 0x00000002, + WICJpegScanType_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +STRUCT!{struct WICImageParameters { + PixelFormat: D2D1_PIXEL_FORMAT, + DpiX: FLOAT, + DpiY: FLOAT, + Top: FLOAT, + Left: FLOAT, + PixelWidth: UINT32, + PixelHeight: UINT32, +}} +STRUCT!{struct WICBitmapPlaneDescription { + Format: WICPixelFormatGUID, + Width: UINT, + Height: UINT, +}} +STRUCT!{struct WICBitmapPlane { + Format: WICPixelFormatGUID, + pbBuffer: *mut BYTE, + cbStride: UINT, + cbBufferSize: UINT, +}} +STRUCT!{struct WICJpegFrameHeader { + Width: UINT, + Height: UINT, + TransferMatrix: WICJpegTransferMatrix, + ScanType: WICJpegScanType, + cComponents: UINT, + ComponentIdentifiers: DWORD, + SampleFactors: DWORD, + QuantizationTableIndices: DWORD, +}} +STRUCT!{struct WICJpegScanHeader { + cComponents: UINT, + RestartInterval: UINT, + ComponentSelectors: DWORD, + HuffmanTableIndices: DWORD, + StartSpectralSelection: BYTE, + EndSpectralSelection: BYTE, + SuccessiveApproximationHigh: BYTE, + SuccessiveApproximationLow: BYTE, +}} +RIDL!{#[uuid(0x00000040, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICPalette(IWICPaletteVtbl): IUnknown(IUnknownVtbl) { + fn InitializePredefined( + ePaletteType: WICBitmapPaletteType, + fAddTransparentColor: BOOL, + ) -> HRESULT, + fn InitializeCustom( + pColors: *const WICColor, + cCount: UINT, + ) -> HRESULT, + fn InitializeFromBitmap( + pISurface: *const IWICBitmapSource, + cCount: UINT, + fAddTransparentColor: BOOL, + ) -> HRESULT, + fn InitializeFromPalette( + pIPalette: *const IWICPalette, + ) -> HRESULT, + fn GetType( + pePaletteType: *mut WICBitmapPaletteType, + ) -> HRESULT, + fn GetColorCount( + pcCount: *mut UINT, + ) -> HRESULT, + fn GetColors( + cCount: UINT, + pColors: *mut WICColor, + pcActualColors: *mut UINT, + ) -> HRESULT, + fn IsBlackWhite( + pfIsBlackWhite: *mut BOOL, + ) -> HRESULT, + fn IsGrayscale( + pfIsGrayscale: *mut BOOL, + ) -> HRESULT, + fn HasAlpha( + pfHasAlpha: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000120, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmapSource(IWICBitmapSourceVtbl): IUnknown(IUnknownVtbl) { + fn GetSize( + puiWidth: *mut UINT, + puiHeight: *mut UINT, + ) -> HRESULT, + fn GetPixelFormat( + pPixelFormat: *mut WICPixelFormatGUID, + ) -> HRESULT, + fn GetResolution( + pDpiX: *mut c_double, + pDpiY: *mut c_double, + ) -> HRESULT, + fn CopyPalette( + pIPalette: *mut IWICPalette, + ) -> HRESULT, + fn CopyPixels( + prc: *const WICRect, + cbStride: UINT, + cbBufferSize: UINT, + pbBuffer: *mut BYTE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000301, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICFormatConverter(IWICFormatConverterVtbl): IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + pISource: *const IWICBitmapSource, + dstFormat: REFWICPixelFormatGUID, + dither: WICBitmapDitherType, + pIPalette: *const IWICPalette, + alphaThresholdPercent: c_double, + paletteTranslate: WICBitmapPaletteType, + ) -> HRESULT, + fn CanConvert( + srcPixelFormat: REFWICPixelFormatGUID, + dstPixelFormat: REFWICPixelFormatGUID, + pfCanConvert: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xbebee9cb, 0x83b0, 0x4dcc, 0x81, 0x32, 0xb0, 0xaa, 0xa5, 0x5e, 0xac, 0x96)] +interface IWICPlanarFormatConverter(IWICPlanarFormatConverterVtbl): + IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + ppPlanes: *const *const IWICBitmapSource, + cPlanes: UINT, + dstFormat: REFWICPixelFormatGUID, + dither: WICBitmapDitherType, + pIPalette: *const IWICPalette, + alphaThresholdPercent: c_double, + paletteTranslate: WICBitmapPaletteType, + ) -> HRESULT, + fn CanConvert( + pSrcPixelFormats: *const WICPixelFormatGUID, + cSrcPlanes: UINT, + dstPixelFormat: REFWICPixelFormatGUID, + pfCanConvert: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000302, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmapScaler(IWICBitmapScalerVtbl): IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + pISource: *const IWICBitmapSource, + uiWidth: UINT, + uiHeight: UINT, + mode: WICBitmapInterpolationMode, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe4fbcf03, 0x223d, 0x4e81, 0x93, 0x33, 0xd6, 0x35, 0x55, 0x6d, 0xd1, 0xb5)] +interface IWICBitmapClipper(IWICBitmapClipperVtbl): IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + pISource: *const IWICBitmapSource, + prc: *const WICRect, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5009834f, 0x2d6a, 0x41ce, 0x9e, 0x1b, 0x17, 0xc5, 0xaf, 0xf7, 0xa7, 0x82)] +interface IWICBitmapFlipRotator(IWICBitmapFlipRotatorVtbl): + IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + pISource: *const IWICBitmapSource, + options: WICBitmapTransformOptions, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000123, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmapLock(IWICBitmapLockVtbl): IUnknown(IUnknownVtbl) { + fn GetSize( + puiWidth: *mut UINT, + puiHeight: *mut UINT, + ) -> HRESULT, + fn GetStride( + pcbStride: *mut UINT, + ) -> HRESULT, + fn GetDataPointer( + pcbBufferSize: *mut UINT, + ppbData: *mut WICInProcPointer, + ) -> HRESULT, + fn GetPixelFormat( + pPixelFormat: *mut WICPixelFormatGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000121, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmap(IWICBitmapVtbl): IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Lock( + prcLock: *const WICRect, + flags: DWORD, + ppILock: *mut *mut IWICBitmapLock, + ) -> HRESULT, + fn SetPalette( + pIPalette: *const IWICPalette, + ) -> HRESULT, + fn SetResolution( + dpiX: c_double, + dpiY: c_double, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3c613a02, 0x34b2, 0x44ea, 0x9a, 0x7c, 0x45, 0xae, 0xa9, 0xc6, 0xfd, 0x6d)] +interface IWICColorContext(IWICColorContextVtbl): IUnknown(IUnknownVtbl) { + fn InitializeFromFilename( + wzFilename: LPCWSTR, + ) -> HRESULT, + fn InitializeFromMemory( + pbBuffer: *const BYTE, + cbBufferSize: UINT, + ) -> HRESULT, + fn InitializeFromExifColorSpace( + value: UINT, + ) -> HRESULT, + fn GetType( + pType: *mut WICColorContextType, + ) -> HRESULT, + fn GetProfileBytes( + cbBuffer: UINT, + pbBuffer: *mut BYTE, + pcbActual: *mut UINT, + ) -> HRESULT, + fn GetExifColorSpace( + pValue: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb66f034f, 0xd0e2, 0x40ab, 0xb4, 0x36, 0x6d, 0xe3, 0x9e, 0x32, 0x1a, 0x94)] +interface IWICColorTransform(IWICColorTransformVtbl): IWICBitmapSource(IWICBitmapSourceVtbl) { + fn Initialize( + pIBitmapSource: *const IWICBitmapSource, + pIContextSource: *const IWICColorContext, + pIContextDest: *const IWICColorContext, + pixelFmtDest: REFWICPixelFormatGUID, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xb84e2c09, 0x78c9, 0x4ac4, 0x8b, 0xd3, 0x52, 0x4a, 0xe1, 0x66, 0x3a, 0x2f)] +interface IWICFastMetadataEncoder(IWICFastMetadataEncoderVtbl): IUnknown(IUnknownVtbl) { + fn Commit() -> HRESULT, + fn GetMetadataQueryWriter( + ppIMetadataQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x135ff860, 0x22b7, 0x4ddf, 0xb0, 0xf6, 0x21, 0x8f, 0x4f, 0x29, 0x9a, 0x43)] +interface IWICStream(IWICStreamVtbl): IStream(IStreamVtbl) { + fn InitializeFromIStream( + pIStream: *const IStream, + ) -> HRESULT, + fn InitializeFromFilename( + wzFileName: LPCWSTR, + dwDesiredAccess: DWORD, + ) -> HRESULT, + fn InitializeFromMemory( + pbBuffer: WICInProcPointer, + cbBufferSize: DWORD, + ) -> HRESULT, + fn InitializeFromIStreamRegion( + pIStream: *const IStream, + ulOffset: ULARGE_INTEGER, + ulMaxSize: ULARGE_INTEGER, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdc2bb46d, 0x3f07, 0x481e, 0x86, 0x25, 0x22, 0x0c, 0x4a, 0xed, 0xbb, 0x33)] +interface IWICEnumMetadataItem(IWICEnumMetadataItemVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgeltSchema: *mut PROPVARIANT, + rgeltId: *mut PROPVARIANT, + rgeltValue: *mut PROPVARIANT, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppIEnumMetadataItem: *mut *mut IWICEnumMetadataItem, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x30989668, 0xe1c9, 0x4597, 0xb3, 0x95, 0x45, 0x8e, 0xed, 0xb8, 0x08, 0xdf)] +interface IWICMetadataQueryReader(IWICMetadataQueryReaderVtbl): IUnknown(IUnknownVtbl) { + fn GetContainerFormat( + pguidContainerFormat: *mut GUID, + ) -> HRESULT, + fn GetLocation( + cchMaxLength: UINT, + wzNamespace: *mut WCHAR, + pcchActualLength: *mut UINT, + ) -> HRESULT, + fn GetMetadataByName( + wzName: LPCWSTR, + pvarValue: *mut PROPVARIANT, + ) -> HRESULT, + fn GetEnumerator( + ppIEnumString: *mut *mut IEnumString, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa721791a, 0x0def, 0x4d06, 0xbd, 0x91, 0x21, 0x18, 0xbf, 0x1d, 0xb1, 0x0b)] +interface IWICMetadataQueryWriter(IWICMetadataQueryWriterVtbl): + IWICMetadataQueryReader(IWICMetadataQueryReaderVtbl) { + fn SetMetadataByName( + wzName: LPCWSTR, + pvarValue: *const PROPVARIANT, + ) -> HRESULT, + fn RemoveMetadataByName( + wzName: LPCWSTR, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000103, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmapEncoder(IWICBitmapEncoderVtbl): IUnknown(IUnknownVtbl) { + fn Initialize( + pIStream: *const IStream, + cacheOption: WICBitmapEncoderCacheOption, + ) -> HRESULT, + fn GetContainerFormat( + pguidContainerFormat: *mut GUID, + ) -> HRESULT, + fn GetEncoderInfo( + ppIEncoderInfo: *mut *mut IWICBitmapEncoderInfo, + ) -> HRESULT, + fn SetColorContexts( + cCount: UINT, + ppIColorContext: *const *const IWICColorContext, + ) -> HRESULT, + fn SetPalette( + pIPalette: *const IWICPalette, + ) -> HRESULT, + fn SetThumbnail( + pIThumbnail: *const IWICBitmapSource, + ) -> HRESULT, + fn SetPreview( + pIPreview: *const IWICBitmapSource, + ) -> HRESULT, + fn CreateNewFrame( + ppIFrameEncode: *mut *mut IWICBitmapFrameEncode, + ppIEncoderOptions: *mut *mut IPropertyBag2, + ) -> HRESULT, + fn Commit() -> HRESULT, + fn GetMetadataQueryWriter( + ppIMetadataQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x00000105, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94)] +interface IWICBitmapFrameEncode(IWICBitmapFrameEncodeVtbl): IUnknown(IUnknownVtbl) { + fn Initialize( + pIEncoderOptions: *const IPropertyBag2, + ) -> HRESULT, + fn SetSize( + uiWidth: UINT, + uiHeight: UINT, + ) -> HRESULT, + fn SetResolution( + dpiX: c_double, + dpiY: c_double, + ) -> HRESULT, + fn SetPixelFormat( + pPixelFormat: *mut WICPixelFormatGUID, + ) -> HRESULT, + fn SetColorContexts( + cCount: UINT, + ppIColorContext: *const *const IWICColorContext, + ) -> HRESULT, + fn SetPalette( + pIPalette: *const IWICPalette, + ) -> HRESULT, + fn SetThumbnail( + pIThumbnail: *const IWICBitmapSource, + ) -> HRESULT, + fn WritePixels( + lineCount: UINT, + cbStride: UINT, + cbBufferSize: UINT, + pbPixels: *const BYTE, + ) -> HRESULT, + fn WriteSource( + pIBitmapSource: *const IWICBitmapSource, + prc: *const WICRect, + ) -> HRESULT, + fn Commit() -> HRESULT, + fn GetMetadataQueryWriter( + ppIMetadataQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf928b7b8, 0x2221, 0x40c1, 0xb7, 0x2e, 0x7e, 0x82, 0xf1, 0x97, 0x4d, 0x1a)] +interface IWICPlanarBitmapFrameEncode(IWICPlanarBitmapFrameEncodeVtbl): IUnknown(IUnknownVtbl) { + fn WritePixels( + lineCount: UINT, + pPlanes: *const WICBitmapPlane, + cPlanes: UINT, + ) -> HRESULT, + fn WriteSource( + ppPlanes: *const *const IWICBitmapSource, + cPlanes: UINT, + prcSource: *const WICRect, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x04c75bf8, 0x3ce1, 0x473b, 0xac, 0xc5, 0x3c, 0xc4, 0xf5, 0xe9, 0x49, 0x99)] +interface IWICImageEncoder(IWICImageEncoderVtbl): IUnknown(IUnknownVtbl) { + fn WriteFrame( + pImage: *const ID2D1Image, + pFrameEncode: *const IWICBitmapFrameEncode, + pImageParameters: *const WICImageParameters, + ) -> HRESULT, + fn WriteFrameThumbnail( + pImage: *const ID2D1Image, + pFrameEncode: *const IWICBitmapFrameEncode, + pImageParameters: *const WICImageParameters, + ) -> HRESULT, + fn WriteThumbnail( + pImage: *const ID2D1Image, + pEncoder: *const IWICBitmapEncoder, + pImageParameters: *const WICImageParameters, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9edde9e7, 0x8dee, 0x47ea, 0x99, 0xdf, 0xe6, 0xfa, 0xf2, 0xed, 0x44, 0xbf)] +interface IWICBitmapDecoder(IWICBitmapDecoderVtbl): IUnknown(IUnknownVtbl) { + fn QueryCapability( + pIStream: *const IStream, + pdwCapability: *mut DWORD, + ) -> HRESULT, + fn Initialize( + pIStream: *const IStream, + cacheOptions: WICDecodeOptions, + ) -> HRESULT, + fn GetContainerFormat( + pguidContainerFormat: *mut GUID, + ) -> HRESULT, + fn GetDecoderInfo( + ppIDecoderInfo: *mut *mut IWICBitmapDecoderInfo, + ) -> HRESULT, + fn CopyPalette( + pIPalette: *const IWICPalette, + ) -> HRESULT, + fn GetMetadataQueryReader( + ppIMetadataQueryReader: *mut *mut IWICMetadataQueryReader, + ) -> HRESULT, + fn GetPreview( + ppIBitmapSource: *mut *mut IWICBitmapSource, + ) -> HRESULT, + fn GetColorContexts( + cCount: UINT, + ppIColorContexts: *mut *mut IWICColorContext, + pcActualCount: *mut UINT, + ) -> HRESULT, + fn GetThumbnail( + ppIThumbnail: *mut *mut IWICBitmapSource, + ) -> HRESULT, + fn GetFrameCount( + pCount: *mut UINT, + ) -> HRESULT, + fn GetFrame( + index: UINT, + ppIBitmapFrame: *mut *mut IWICBitmapFrameDecode, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b16811b, 0x6a43, 0x4ec9, 0xb7, 0x13, 0x3d, 0x5a, 0x0c, 0x13, 0xb9, 0x40)] +interface IWICBitmapSourceTransform(IWICBitmapSourceTransformVtbl): IUnknown(IUnknownVtbl) { + fn CopyPixels( + prc: *const WICRect, + uiWidth: UINT, + uiHeight: UINT, + pguidDstFormat: *const WICPixelFormatGUID, + dstTransform: WICBitmapTransformOptions, + nStride: UINT, + cbBufferSize: UINT, + pbBuffer: *mut BYTE, + ) -> HRESULT, + fn GetClosestSize( + puiWidth: *mut UINT, + puiHeight: *mut UINT, + ) -> HRESULT, + fn GetClosestPixelFormat( + pguidDstFormat: *mut WICPixelFormatGUID, + ) -> HRESULT, + fn DoesSupportTransform( + dstTransform: WICBitmapTransformOptions, + pfIsSupported: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3aff9cce, 0xbe95, 0x4303, 0xb9, 0x27, 0xe7, 0xd1, 0x6f, 0xf4, 0xa6, 0x13)] +interface IWICPlanarBitmapSourceTransform(IWICPlanarBitmapSourceTransformVtbl): + IUnknown(IUnknownVtbl) { + fn DoesSupportTransform( + puiWidth: *mut UINT, + puiHeight: *mut UINT, + dstTransform: WICBitmapTransformOptions, + dstPlanarOptions: WICPlanarOptions, + pguidDstFormats: *const WICPixelFormatGUID, + pPlaneDescriptions: *mut WICBitmapPlaneDescription, + cPlanes: UINT, + pfIsSupported: *mut BOOL, + ) -> HRESULT, + fn CopyPixels( + prcSource: *const WICRect, + uiWidth: UINT, + uiHeight: UINT, + dstTransform: WICBitmapTransformOptions, + dstPlanarOptions: WICPlanarOptions, + pDstPlanes: *const WICBitmapPlane, + cPlanes: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x3b16811b, 0x6a43, 0x4ec9, 0xa8, 0x13, 0x3d, 0x93, 0x0c, 0x13, 0xb9, 0x40)] +interface IWICBitmapFrameDecode(IWICBitmapFrameDecodeVtbl): + IWICBitmapSource(IWICBitmapSourceVtbl) { + fn GetMetadataQueryReader( + ppIMetadataQueryReader: *mut *mut IWICMetadataQueryReader, + ) -> HRESULT, + fn GetColorContexts( + cCount: UINT, + ppIColorContexts: *mut *mut IWICColorContext, + pcActualCount: *mut UINT, + ) -> HRESULT, + fn GetThumbnail( + ppIThumbnail: *mut *mut IWICBitmapSource, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xdaac296f, 0x7aa5, 0x4dbf, 0x8d, 0x15, 0x22, 0x5c, 0x59, 0x76, 0xf8, 0x91)] +interface IWICProgressiveLevelControl(IWICProgressiveLevelControlVtbl): IUnknown(IUnknownVtbl) { + fn GetLevelCount( + pcLevels: *mut UINT, + ) -> HRESULT, + fn GetCurrentLevel( + pnLevel: *mut UINT, + ) -> HRESULT, + fn SetCurrentLevel( + nLevel: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x4776f9cd, 0x9517, 0x45fa, 0xbf, 0x24, 0xe8, 0x9c, 0x5e, 0xc5, 0xc6, 0x0c)] +interface IWICProgressCallback(IWICProgressCallbackVtbl): IUnknown(IUnknownVtbl) { + fn Notify( + uFrameNum: ULONG, + operation: WICProgressOperation, + dblProgress: c_double, + ) -> HRESULT, +}} +FN!{stdcall PFNProgressNotification( + pvData: LPVOID, + uFrameNum: ULONG, + operation: WICProgressOperation, + dblProgress: c_double, +) -> HRESULT} +RIDL!{#[uuid(0x64c1024e, 0xc3cf, 0x4462, 0x80, 0x78, 0x88, 0xc2, 0xb1, 0x1c, 0x46, 0xd9)] +interface IWICBitmapCodecProgressNotification(IWICBitmapCodecProgressNotificationVtbl): + IUnknown(IUnknownVtbl) { + fn RegisterProgressNotification( + pfnProgressNotification: PFNProgressNotification, + pvData: LPVOID, + dwProgressFlags: DWORD, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x23bc3f0a, 0x698b, 0x4357, 0x88, 0x6b, 0xf2, 0x4d, 0x50, 0x67, 0x13, 0x34)] +interface IWICComponentInfo(IWICComponentInfoVtbl): IUnknown(IUnknownVtbl) { + fn GetComponentType( + pType: *mut WICComponentType, + ) -> HRESULT, + fn GetCLSID( + pclsid: *mut CLSID, + ) -> HRESULT, + fn GetSigningStatus( + pStatus: *mut DWORD, + ) -> HRESULT, + fn GetAuthor( + cchAuthor: UINT, + wzAuthor: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetVendorGUID( + pguidVendor: *mut GUID, + ) -> HRESULT, + fn GetVersion( + cchVersion: UINT, + wzVersion: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetSpecVersion( + cchSpecVersion: UINT, + wzSpecVersion: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetFriendlyName( + cchFriendlyName: UINT, + wzFriendlyName: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9f34fb65, 0x13f4, 0x4f15, 0xbc, 0x57, 0x37, 0x26, 0xb5, 0xe5, 0x3d, 0x9f)] +interface IWICFormatConverterInfo(IWICFormatConverterInfoVtbl): + IWICComponentInfo(IWICComponentInfoVtbl) { + fn GetPixelFormats( + cFormats: UINT, + pPixelFormatGUIDs: *mut WICPixelFormatGUID, + pcActual: *mut UINT, + ) -> HRESULT, + fn CreateInstance( + ppIConverter: *mut *mut IWICFormatConverter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe87a44c4, 0xb76e, 0x4c47, 0x8b, 0x09, 0x29, 0x8e, 0xb1, 0x2a, 0x27, 0x14)] +interface IWICBitmapCodecInfo(IWICBitmapCodecInfoVtbl): IWICComponentInfo(IWICComponentInfoVtbl) { + fn GetContainerFormat( + pguidContainerFormat: *mut GUID, + ) -> HRESULT, + fn GetPixelFormats( + cFormats: UINT, + pguidPixelFormats: *mut GUID, + pcActual: *mut UINT, + ) -> HRESULT, + fn GetColorManagementVersion( + cchColorManagementVersion: UINT, + wzColorManagementVersion: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetDeviceManufacturer( + cchDeviceManufacturer: UINT, + wzDeviceManufacturer: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetDeviceModels( + cchDeviceModels: UINT, + wzDeviceModels: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetMimeTypes( + cchMimeTypes: UINT, + wzMimeTypes: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetFileExtensions( + cchFileExtensions: UINT, + wzFileExtensions: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn DoesSupportAnimation( + pfSupportAnimation: *mut BOOL, + ) -> HRESULT, + fn DoesSupportChromakey( + pfSupportChromakey: *mut BOOL, + ) -> HRESULT, + fn DoesSupportLossless( + pfSupportLossless: *mut BOOL, + ) -> HRESULT, + fn DoesSupportMultiframe( + pfSupportMultiframe: *mut BOOL, + ) -> HRESULT, + fn MatchesMimeType( + wzMimeType: LPCWSTR, + pfMatches: *mut BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x94c9b4ee, 0xa09f, 0x4f92, 0x8a, 0x1e, 0x4a, 0x9b, 0xce, 0x7e, 0x76, 0xfb)] +interface IWICBitmapEncoderInfo(IWICBitmapEncoderInfoVtbl): + IWICBitmapCodecInfo(IWICBitmapCodecInfoVtbl) { + fn CreateInstance( + ppIBitmapEncoder: *mut *mut IWICBitmapEncoder, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xd8cd007f, 0xd08f, 0x4191, 0x9b, 0xfc, 0x23, 0x6e, 0xa7, 0xf0, 0xe4, 0xb5)] +interface IWICBitmapDecoderInfo(IWICBitmapDecoderInfoVtbl): + IWICBitmapCodecInfo(IWICBitmapCodecInfoVtbl) { + fn GetPatterns( + cbSizePatterns: UINT, + pPatterns: *mut WICBitmapPattern, + pcPatterns: *mut UINT, + pcbPatternsActual: *mut UINT, + ) -> HRESULT, + fn MatchesPattern( + pIStream: *const IStream, + pfMatches: *mut BOOL, + ) -> HRESULT, + fn CreateInstance( + ppIBitmapDecoder: *mut *mut IWICBitmapDecoder, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xe8eda601, 0x3d48, 0x431a, 0xab, 0x44, 0x69, 0x05, 0x9b, 0xe8, 0x8b, 0xbe)] +interface IWICPixelFormatInfo(IWICPixelFormatInfoVtbl): IWICComponentInfo(IWICComponentInfoVtbl) { + fn GetFormatGUID( + pFormat: *mut GUID, + ) -> HRESULT, + fn GetColorContext( + ppIColorContext: *mut *mut IWICColorContext, + ) -> HRESULT, + fn GetBitsPerPixel( + puiBitsPerPixel: *mut UINT, + ) -> HRESULT, + fn GetChannelCount( + puiChannelCount: *mut UINT, + ) -> HRESULT, + fn GetChannelMask( + uiChannelIndex: UINT, + cbMaskBuffer: UINT, + pbMaskBuffer: *mut BYTE, + pcbActual: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xa9db33a2, 0xaf5f, 0x43c7, 0xb6, 0x79, 0x74, 0xf5, 0x98, 0x4b, 0x5a, 0xa4)] +interface IWICPixelFormatInfo2(IWICPixelFormatInfo2Vtbl): + IWICPixelFormatInfo(IWICPixelFormatInfoVtbl) { + fn SupportsTransparency( + pfSupportsTransparency: *mut BOOL, + ) -> HRESULT, + fn GetNumericRepresentation( + pNumericRepresentation: *mut WICPixelFormatNumericRepresentation, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70)] +interface IWICImagingFactory(IWICImagingFactoryVtbl): IUnknown(IUnknownVtbl) { + fn CreateDecoderFromFilename( + wzFilename: LPCWSTR, + pguidVendor: *const GUID, + dwDesiredAccess: DWORD, + metadataOptions: WICDecodeOptions, + ppIDecoder: *mut *mut IWICBitmapDecoder, + ) -> HRESULT, + fn CreateDecoderFromStream( + pIStream: *const IStream, + pguidVendor: *const GUID, + metadataOptions: WICDecodeOptions, + ppIDecoder: *mut *mut IWICBitmapDecoder, + ) -> HRESULT, + fn CreateDecoderFromFileHandle( + hFile: ULONG_PTR, + pguidVendor: *const GUID, + metadataOptions: WICDecodeOptions, + ppIDecoder: *mut *mut IWICBitmapDecoder, + ) -> HRESULT, + fn CreateComponentInfo( + clsidComponent: REFCLSID, + ppIInfo: *mut *mut IWICComponentInfo, + ) -> HRESULT, + fn CreateDecoder( + guidContainerFormat: REFGUID, + pguidVendor: *const GUID, + ppIDecoder: *mut *mut IWICBitmapDecoder, + ) -> HRESULT, + fn CreateEncoder( + guidContainerFormat: REFGUID, + pguidVendor: *const GUID, + ppIEncoder: *mut *mut IWICBitmapEncoder, + ) -> HRESULT, + fn CreatePalette( + ppIPalette: *mut *mut IWICPalette, + ) -> HRESULT, + fn CreateFormatConverter( + ppIFormatConverter: *mut *mut IWICFormatConverter, + ) -> HRESULT, + fn CreateBitmapScaler( + ppIBitmapScaler: *mut *mut IWICBitmapScaler, + ) -> HRESULT, + fn CreateBitmapClipper( + ppIBitmapClipper: *mut *mut IWICBitmapClipper, + ) -> HRESULT, + fn CreateBitmapFlipRotator( + ppIBitmapFlipRotator: *mut *mut IWICBitmapFlipRotator, + ) -> HRESULT, + fn CreateStream( + ppIWICStream: *mut *mut IWICStream, + ) -> HRESULT, + fn CreateColorContext( + ppIWICColorContext: *mut *mut IWICColorContext, + ) -> HRESULT, + fn CreateColorTransformer( + ppIWICColorTransform: *mut *mut IWICColorTransform, + ) -> HRESULT, + fn CreateBitmap( + uiWidth: UINT, + uiHeight: UINT, + pixelFormat: REFWICPixelFormatGUID, + option: WICBitmapCreateCacheOption, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateBitmapFromSource( + pIBitmapSource: *const IWICBitmapSource, + option: WICBitmapCreateCacheOption, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateBitmapFromSourceRect( + pIBitmapSource: *const IWICBitmapSource, + x: UINT, + y: UINT, + width: UINT, + height: UINT, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateBitmapFromMemory( + uiWidth: UINT, + uiHeight: UINT, + pixelFormat: REFWICPixelFormatGUID, + cbStride: UINT, + cbBufferSize: UINT, + pbBuffer: *const BYTE, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateBitmapFromHBITMAP( + hBitmap: HBITMAP, + hPalette: HPALETTE, + options: WICBitmapAlphaChannelOption, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateBitmapFromHICON( + hIcon: HICON, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT, + fn CreateComponentEnumerator( + componentTypes: DWORD, + options: DWORD, + ppIEnumUnknown: *mut *mut IEnumUnknown, + ) -> HRESULT, + fn CreateFastMetadataEncoderFromDecoder( + pIDecoder: *const IWICBitmapDecoder, + ppIFastEncoder: *mut *mut IWICFastMetadataEncoder, + ) -> HRESULT, + fn CreateFastMetadataEncoderFromFrameDecode( + pIFrameDecoder: *const IWICBitmapFrameDecode, + ppIFastEncoder: *mut *mut IWICFastMetadataEncoder, + ) -> HRESULT, + fn CreateQueryWriter( + guidMetadataFormat: REFGUID, + pguidVendor: *const GUID, + ppIQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, + fn CreateQueryWriterFromReader( + pIQueryReader: *const IWICMetadataQueryReader, + pguidVendor: *const GUID, + ppIQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x7b816b45, 0x1996, 0x4476, 0xb1, 0x32, 0xde, 0x9e, 0x24, 0x7c, 0x8a, 0xf0)] +interface IWICImagingFactory2(IWICImagingFactory2Vtbl): + IWICImagingFactory(IWICImagingFactoryVtbl) { + fn CreateImageEncoder( + pD2DDevice: *const ID2D1Device, + ppWICImageEncoder: *mut *mut IWICImageEncoder, + ) -> HRESULT, +}} +extern "system" { + pub fn WICConvertBitmapSource( + dstFormat: REFWICPixelFormatGUID, + pISrc: *const IWICBitmapSource, + ppIDst: *mut *mut IWICBitmapSource, + ) -> HRESULT; + pub fn WICCreateBitmapFromSection( + width: UINT, + height: UINT, + pixelFormat: REFWICPixelFormatGUID, + hSection: HANDLE, + stride: UINT, + offset: UINT, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT; + pub fn WICCreateBitmapFromSectionEx( + width: UINT, + height: UINT, + pixelFormat: REFWICPixelFormatGUID, + hSection: HANDLE, + stride: UINT, + offset: UINT, + desiredAccessLevel: WICSectionAccessLevel, + ppIBitmap: *mut *mut IWICBitmap, + ) -> HRESULT; + pub fn WICMapGuidToShortName( + guid: REFGUID, + cchName: UINT, + wzName: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT; + pub fn WICMapShortNameToGuid( + wzName: PCWSTR, + pguid: *mut GUID, + ) -> HRESULT; + pub fn WICMapSchemaToName( + guidMetadataFormat: REFGUID, + pwzSchema: LPWSTR, + cchName: UINT, + wzName: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT; +} +pub const FACILITY_WINCODEC_ERR: HRESULT = 0x898; +pub const WINCODEC_ERR_BASE: HRESULT = 0x2000; +/// intsafe.h, 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW +pub const INTSAFE_E_ARITHMETIC_OVERFLOW: HRESULT = 0x80070216; +#[inline] +pub fn MAKE_WINCODECHR(severity: HRESULT, code: HRESULT) -> HRESULT { + MAKE_HRESULT!(severity, FACILITY_WINCODEC_ERR, WINCODEC_ERR_BASE + code) +} +#[inline] +pub fn MAKE_WINCODECHR_ERR(code: HRESULT) -> HRESULT { + MAKE_WINCODECHR(SEVERITY_ERROR, code) +} +pub const WINCODEC_ERR_GENERIC_ERROR: HRESULT = E_FAIL; +pub const WINCODEC_ERR_INVALIDPARAMETER: HRESULT = E_INVALIDARG; +pub const WINCODEC_ERR_OUTOFMEMORY: HRESULT = E_OUTOFMEMORY; +pub const WINCODEC_ERR_NOTIMPLEMENTED: HRESULT = E_NOTIMPL; +pub const WINCODEC_ERR_ABORTED: HRESULT = E_ABORT; +pub const WINCODEC_ERR_ACCESSDENIED: HRESULT = E_ACCESSDENIED; +pub const WINCODEC_ERR_VALUEOVERFLOW: HRESULT = INTSAFE_E_ARITHMETIC_OVERFLOW; +ENUM!{enum WICTiffCompressionOption { + WICTiffCompressionDontCare = 0x00000000, + WICTiffCompressionNone = 0x00000001, + WICTiffCompressionCCITT3 = 0x00000002, + WICTiffCompressionCCITT4 = 0x00000003, + WICTiffCompressionLZW = 0x00000004, + WICTiffCompressionRLE = 0x00000005, + WICTiffCompressionZIP = 0x00000006, + WICTiffCompressionLZWHDifferencing = 0x00000007, + WICTIFFCOMPRESSIONOPTION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICJpegYCrCbSubsamplingOption { + WICJpegYCrCbSubsamplingDefault = 0x00000000, + WICJpegYCrCbSubsampling420 = 0x00000001, + WICJpegYCrCbSubsampling422 = 0x00000002, + WICJpegYCrCbSubsampling444 = 0x00000003, + WICJpegYCrCbSubsampling440 = 0x00000004, + WICJPEGYCRCBSUBSAMPLING_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICPngFilterOption { + WICPngFilterUnspecified = 0x00000000, + WICPngFilterNone = 0x00000001, + WICPngFilterSub = 0x00000002, + WICPngFilterUp = 0x00000003, + WICPngFilterAverage = 0x00000004, + WICPngFilterPaeth = 0x00000005, + WICPngFilterAdaptive = 0x00000006, + WICPNGFILTEROPTION_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICNamedWhitePoint { + WICWhitePointDefault = 0x00000001, + WICWhitePointDaylight = 0x00000002, + WICWhitePointCloudy = 0x00000004, + WICWhitePointShade = 0x00000008, + WICWhitePointTungsten = 0x00000010, + WICWhitePointFluorescent = 0x00000020, + WICWhitePointFlash = 0x00000040, + WICWhitePointUnderwater = 0x00000080, + WICWhitePointCustom = 0x00000100, + WICWhitePointAutoWhiteBalance = 0x00000200, + WICWhitePointAsShot = WICWhitePointDefault, + WICNAMEDWHITEPOINT_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICRawCapabilities { + WICRawCapabilityNotSupported = 0x00000000, + WICRawCapabilityGetSupported = 0x00000001, + WICRawCapabilityFullySupported = 0x00000002, + WICRAWCAPABILITIES_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICRawRotationCapabilities { + WICRawRotationCapabilityNotSupported = 0x00000000, + WICRawRotationCapabilityGetSupported = 0x00000001, + WICRawRotationCapabilityNinetyDegreesSupported = 0x00000002, + WICRawRotationCapabilityFullySupported = 0x00000003, + WICRAWROTATIONCAPABILITIES_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +STRUCT!{struct WICRawCapabilitiesInfo { + cbSize: UINT, + CodecMajorVersion: UINT, + CodecMinorVersion: UINT, + ExposureCompensationSupport: WICRawCapabilities, + ContrastSupport: WICRawCapabilities, + RGBWhitePointSupport: WICRawCapabilities, + NamedWhitePointSupport: WICRawCapabilities, + NamedWhitePointSupportMask: UINT, + KelvinWhitePointSupport: WICRawCapabilities, + GammaSupport: WICRawCapabilities, + TintSupport: WICRawCapabilities, + SaturationSupport: WICRawCapabilities, + SharpnessSupport: WICRawCapabilities, + NoiseReductionSupport: WICRawCapabilities, + DestinationColorProfileSupport: WICRawCapabilities, + ToneCurveSupport: WICRawCapabilities, + RotationSupport: WICRawRotationCapabilities, + RenderModeSupport: WICRawCapabilities, +}} +ENUM!{enum WICRawParameterSet { + WICAsShotParameterSet = 0x00000001, + WICUserAdjustedParameterSet = 0x00000002, + WICAutoAdjustedParameterSet = 0x00000003, + WICRAWPARAMETERSET_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICRawRenderMode { + WICRawRenderModeDraft = 0x00000001, + WICRawRenderModeNormal = 0x00000002, + WICRawRenderModeBestQuality = 0x00000003, + WICRAWRENDERMODE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +STRUCT!{struct WICRawToneCurvePoint { + Input: c_double, + Output: c_double, +}} +STRUCT!{struct WICRawToneCurve { + cPoints: UINT, + aPoints: [WICRawToneCurvePoint; 1], +}} +pub const WICRawChangeNotification_ExposureCompensation: UINT = 0x00000001; +pub const WICRawChangeNotification_NamedWhitePoint: UINT = 0x00000002; +pub const WICRawChangeNotification_KelvinWhitePoint: UINT = 0x00000004; +pub const WICRawChangeNotification_RGBWhitePoint: UINT = 0x00000008; +pub const WICRawChangeNotification_Contrast: UINT = 0x00000010; +pub const WICRawChangeNotification_Gamma: UINT = 0x00000020; +pub const WICRawChangeNotification_Sharpness: UINT = 0x00000040; +pub const WICRawChangeNotification_Saturation: UINT = 0x00000080; +pub const WICRawChangeNotification_Tint: UINT = 0x00000100; +pub const WICRawChangeNotification_NoiseReduction: UINT = 0x00000200; +pub const WICRawChangeNotification_DestinationColorContext: UINT = 0x00000400; +pub const WICRawChangeNotification_ToneCurve: UINT = 0x00000800; +pub const WICRawChangeNotification_Rotation: UINT = 0x00001000; +pub const WICRawChangeNotification_RenderMode: UINT = 0x00002000; +RIDL!{#[uuid(0x95c75a6e, 0x3e8c, 0x4ec2, 0x85, 0xa8, 0xae, 0xbc, 0xc5, 0x51, 0xe5, 0x9b)] +interface IWICDevelopRawNotificationCallback(IWICDevelopRawNotificationCallbackVtbl): + IUnknown(IUnknownVtbl) { + fn Notify( + NotificationMask: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xfbec5e44, 0xf7be, 0x4b65, 0xb7, 0xf8, 0xc0, 0xc8, 0x1f, 0xef, 0x02, 0x6d)] +interface IWICDevelopRaw(IWICDevelopRawVtbl): IWICBitmapFrameDecode(IWICBitmapFrameDecodeVtbl) { + fn QueryRawCapabilitiesInfo( + pInfo: *mut WICRawCapabilitiesInfo, + ) -> HRESULT, + fn LoadParameterSet( + ParameterSet: WICRawParameterSet, + ) -> HRESULT, + fn GetCurrentParameterSet( + ppCurrentParameterSet: *mut *mut IPropertyBag2, + ) -> HRESULT, + fn SetExposureCompensation( + ev: c_double, + ) -> HRESULT, + fn GetExposureCompensation( + pEV: *mut c_double, + ) -> HRESULT, + fn SetWhitePointRGB( + Red: UINT, + Green: UINT, + Blue: UINT, + ) -> HRESULT, + fn GetWhitePointRGB( + pRed: *mut UINT, + pGreen: *mut UINT, + pBlue: *mut UINT, + ) -> HRESULT, + fn SetNamedWhitePoint( + WhitePoint: WICNamedWhitePoint, + ) -> HRESULT, + fn GetNamedWhitePoint( + pWhitePoint: *mut WICNamedWhitePoint, + ) -> HRESULT, + fn SetWhitePointKelvin( + WhitePointKelvin: UINT, + ) -> HRESULT, + fn GetWhitePointKelvin( + pWhitePointKelvin: *mut UINT, + ) -> HRESULT, + fn GetKelvinRangeInfo( + pMinKelvinTemp: *mut UINT, + pMaxKelvinTemp: *mut UINT, + pKelvinTempStepValue: *mut UINT, + ) -> HRESULT, + fn SetContrast( + Contrast: c_double, + ) -> HRESULT, + fn GetContrast( + pContrast: *mut c_double, + ) -> HRESULT, + fn SetGamma( + Gamma: c_double, + ) -> HRESULT, + fn GetGamma( + pGamma: *mut c_double, + ) -> HRESULT, + fn SetSharpness( + Sharpness: c_double, + ) -> HRESULT, + fn GetSharpness( + pSharpness: *mut c_double, + ) -> HRESULT, + fn SetSaturation( + Saturation: c_double, + ) -> HRESULT, + fn GetSaturation( + pSaturation: *mut c_double, + ) -> HRESULT, + fn SetTint( + Tint: c_double, + ) -> HRESULT, + fn GetTint( + pTint: *mut c_double, + ) -> HRESULT, + fn SetNoiseReduction( + NoiseReduction: c_double, + ) -> HRESULT, + fn GetNoiseReduction( + pNoiseReduction: *mut c_double, + ) -> HRESULT, + fn SetDestinationColorContext( + pColorContext: *const IWICColorContext, + ) -> HRESULT, + fn SetToneCurve( + cbToneCurveSize: UINT, + pToneCurve: *const WICRawToneCurve, + ) -> HRESULT, + fn GetToneCurve( + cbToneCurveBufferSize: UINT, + pToneCurve: *mut WICRawToneCurve, + pcbActualToneCurveBufferSize: *mut UINT, + ) -> HRESULT, + fn SetRotation( + Rotation: c_double, + ) -> HRESULT, + fn GetRotation( + pRotation: *mut c_double, + ) -> HRESULT, + fn SetRenderMode( + RenderMode: WICRawRenderMode, + ) -> HRESULT, + fn GetRenderMode( + pRenderMode: *mut WICRawRenderMode, + ) -> HRESULT, + fn SetNotificationCallback( + pCallback: *const IWICDevelopRawNotificationCallback, + ) -> HRESULT, +}} +ENUM!{enum WICDdsDimension { + WICDdsTexture1D = 0x00000000, + WICDdsTexture2D = 0x00000001, + WICDdsTexture3D = 0x00000002, + WICDdsTextureCube = 0x00000003, + WICDDSTEXTURE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +ENUM!{enum WICDdsAlphaMode { + WICDdsAlphaModeUnknown = 0x00000000, + WICDdsAlphaModeStraight = 0x00000001, + WICDdsAlphaModePremultiplied = 0x00000002, + WICDdsAlphaModeOpaque = 0x00000003, + WICDdsAlphaModeCustom = 0x00000004, + WICDDSALPHAMODE_FORCE_DWORD = CODEC_FORCE_DWORD, +}} +STRUCT!{struct WICDdsParameters { + Width: UINT, + Height: UINT, + Depth: UINT, + MipLevels: UINT, + ArraySize: UINT, + DxgiFormat: DXGI_FORMAT, + Dimension: WICDdsDimension, + AlphaMode: WICDdsAlphaMode, +}} +RIDL!{#[uuid(0x409cd537, 0x8532, 0x40cb, 0x97, 0x74, 0xe2, 0xfe, 0xb2, 0xdf, 0x4e, 0x9c)] +interface IWICDdsDecoder(IWICDdsDecoderVtbl): IUnknown(IUnknownVtbl) { + fn GetParameters( + pParameters: *mut WICDdsParameters, + ) -> HRESULT, + fn GetFrame( + arrayIndex: UINT, + mipLevel: UINT, + sliceIndex: UINT, + ppIBitmapFrame: *mut *mut IWICBitmapFrameDecode, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x5cacdb4c, 0x407e, 0x41b3, 0xb9, 0x36, 0xd0, 0xf0, 0x10, 0xcd, 0x67, 0x32)] +interface IWICDdsEncoder(IWICDdsEncoderVtbl): IUnknown(IUnknownVtbl) { + fn SetParameters( + pParameters: *const WICDdsParameters, + ) -> HRESULT, + fn GetParameters( + pParameters: *mut WICDdsParameters, + ) -> HRESULT, + fn CreateNewFrame( + ppIFrameEncode: *mut *mut IWICBitmapFrameEncode, + pArrayIndex: *mut UINT, + pMipLevel: *mut UINT, + pSliceIndex: *mut UINT, + ) -> HRESULT, +}} +STRUCT!{struct WICDdsFormatInfo { + DxgiFormat: DXGI_FORMAT, + BytesPerBlock: UINT, + BlockWidth: UINT, + BlockHeight: UINT, +}} +RIDL!{#[uuid(0x3d4c0c61, 0x18a4, 0x41e4, 0xbd, 0x80, 0x48, 0x1a, 0x4f, 0xc9, 0xf4, 0x64)] +interface IWICDdsFrameDecode(IWICDdsFrameDecodeVtbl): IUnknown(IUnknownVtbl) { + fn GetSizeInBlocks( + pWidthInBlocks: *mut UINT, + pHeightInBlocks: *mut UINT, + ) -> HRESULT, + fn GetFormatInfo( + pFormatInfo: *mut WICDdsFormatInfo, + ) -> HRESULT, + fn CopyBlocks( + prcBoundsInBlocks: *const WICRect, + cbStride: UINT, + cbBufferSize: UINT, + pbBuffer: *mut BYTE, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x8939f66e, 0xc46a, 0x4c21, 0xa9, 0xd1, 0x98, 0xb3, 0x27, 0xce, 0x16, 0x79)] +interface IWICJpegFrameDecode(IWICJpegFrameDecodeVtbl): IUnknown(IUnknownVtbl) { + fn DoesSupportIndexing( + pfIndexingSupported: *mut BOOL, + ) -> HRESULT, + fn SetIndexing( + options: WICJpegIndexingOptions, + horizontalIntervalSize: UINT, + ) -> HRESULT, + fn ClearIndexing() -> HRESULT, + fn GetAcHuffmanTable( + scanIndex: UINT, + tableIndex: UINT, + pAcHuffmanTable: *mut DXGI_JPEG_AC_HUFFMAN_TABLE, + ) -> HRESULT, + fn GetDcHuffmanTable( + scanIndex: UINT, + tableIndex: UINT, + pDcHuffmanTable: *mut DXGI_JPEG_DC_HUFFMAN_TABLE, + ) -> HRESULT, + fn GetQuantizationTable( + scanIndex: UINT, + tableIndex: UINT, + pQuantizationTable: *mut DXGI_JPEG_QUANTIZATION_TABLE, + ) -> HRESULT, + fn GetFrameHeader( + pFrameHeader: *mut WICJpegFrameHeader, + ) -> HRESULT, + fn GetScanHeader( + scanIndex: UINT, + pScanHeader: *mut WICJpegScanHeader, + ) -> HRESULT, + fn CopyScan( + scanIndex: UINT, + scanOffset: UINT, + cbScanData: UINT, + pbScanData: *mut BYTE, + pcbScanDataActual: *mut UINT, + ) -> HRESULT, + fn CopyMinimalStream( + streamOffset: UINT, + cbStreamData: UINT, + pbStreamData: *mut BYTE, + pcbStreamDataActual: *mut UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x2f0c601f, 0xd2c6, 0x468c, 0xab, 0xfa, 0x49, 0x49, 0x5d, 0x98, 0x3e, 0xd1)] +interface IWICJpegFrameEncode(IWICJpegFrameEncodeVtbl): IUnknown(IUnknownVtbl) { + fn GetAcHuffmanTable( + scanIndex: UINT, + tableIndex: UINT, + pAcHuffmanTable: *mut DXGI_JPEG_AC_HUFFMAN_TABLE, + ) -> HRESULT, + fn GetDcHuffmanTable( + scanIndex: UINT, + tableIndex: UINT, + pDcHuffmanTable: *mut DXGI_JPEG_DC_HUFFMAN_TABLE, + ) -> HRESULT, + fn GetQuantizationTable( + scanIndex: UINT, + tableIndex: UINT, + pQuantizationTable: *mut DXGI_JPEG_QUANTIZATION_TABLE, + ) -> HRESULT, + fn WriteScan( + cbScanData: UINT, + pbScanData: *const BYTE, + ) -> HRESULT, +}} diff --git a/winapi/src/um/wincodecsdk.rs b/winapi/src/um/wincodecsdk.rs new file mode 100644 index 000000000..f71bf72aa --- /dev/null +++ b/winapi/src/um/wincodecsdk.rs @@ -0,0 +1,564 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::{c_uchar, c_ulong}; +use shared::guiddef::{GUID, REFGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, UINT, ULONG}; +use shared::wtypes::{BSTR, CLIPFORMAT}; +use um::oaidl::LPSAFEARRAY; +use um::objidl::{IPersistStream, IPersistStreamVtbl}; +use um::objidlbase::{IEnumUnknown, IStream}; +use um::ocidl::{IPropertyBag2, PROPBAG2}; +use um::propidl::PROPVARIANT; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::wincodec::{ + IWICComponentInfo, IWICComponentInfoVtbl, IWICEnumMetadataItem, IWICImagingFactory, + IWICImagingFactoryVtbl, IWICMetadataQueryReader, IWICMetadataQueryWriter, +}; +use um::winnt::{HRESULT, ULARGE_INTEGER, WCHAR}; +DEFINE_GUID!{GUID_MetadataFormatUnknown, + 0xa45e592f, 0x9078, 0x4a7c, 0xad, 0xb5, 0x4e, 0xdc, 0x4f, 0xd6, 0x1b, 0x1f} +DEFINE_GUID!{GUID_MetadataFormatIfd, + 0x537396c6, 0x2d8a, 0x4bb6, 0x9b, 0xf8, 0x2f, 0x0a, 0x8e, 0x2a, 0x3a, 0xdf} +DEFINE_GUID!{GUID_MetadataFormatSubIfd, + 0x58a2e128, 0x2db9, 0x4e57, 0xbb, 0x14, 0x51, 0x77, 0x89, 0x1e, 0xd3, 0x31} +DEFINE_GUID!{GUID_MetadataFormatExif, + 0x1c3c4f9d, 0xb84a, 0x467d, 0x94, 0x93, 0x36, 0xcf, 0xbd, 0x59, 0xea, 0x57} +DEFINE_GUID!{GUID_MetadataFormatGps, + 0x7134ab8a, 0x9351, 0x44ad, 0xaf, 0x62, 0x44, 0x8d, 0xb6, 0xb5, 0x02, 0xec} +DEFINE_GUID!{GUID_MetadataFormatInterop, + 0xed686f8e, 0x681f, 0x4c8b, 0xbd, 0x41, 0xa8, 0xad, 0xdb, 0xf6, 0xb3, 0xfc} +DEFINE_GUID!{GUID_MetadataFormatApp0, + 0x79007028, 0x268d, 0x45d6, 0xa3, 0xc2, 0x35, 0x4e, 0x6a, 0x50, 0x4b, 0xc9} +DEFINE_GUID!{GUID_MetadataFormatApp1, + 0x8fd3dfc3, 0xf951, 0x492b, 0x81, 0x7f, 0x69, 0xc2, 0xe6, 0xd9, 0xa5, 0xb0} +DEFINE_GUID!{GUID_MetadataFormatApp13, + 0x326556a2, 0xf502, 0x4354, 0x9c, 0xc0, 0x8e, 0x3f, 0x48, 0xea, 0xf6, 0xb5} +DEFINE_GUID!{GUID_MetadataFormatIPTC, + 0x4fab0914, 0xe129, 0x4087, 0xa1, 0xd1, 0xbc, 0x81, 0x2d, 0x45, 0xa7, 0xb5} +DEFINE_GUID!{GUID_MetadataFormatIRB, + 0x16100d66, 0x8570, 0x4bb9, 0xb9, 0x2d, 0xfd, 0xa4, 0xb2, 0x3e, 0xce, 0x67} +DEFINE_GUID!{GUID_MetadataFormat8BIMIPTC, + 0x0010568c, 0x0852, 0x4e6a, 0xb1, 0x91, 0x5c, 0x33, 0xac, 0x5b, 0x04, 0x30} +DEFINE_GUID!{GUID_MetadataFormat8BIMResolutionInfo, + 0x739f305d, 0x81db, 0x43cb, 0xac, 0x5e, 0x55, 0x01, 0x3e, 0xf9, 0xf0, 0x03} +DEFINE_GUID!{GUID_MetadataFormat8BIMIPTCDigest, + 0x1ca32285, 0x9ccd, 0x4786, 0x8b, 0xd8, 0x79, 0x53, 0x9d, 0xb6, 0xa0, 0x06} +DEFINE_GUID!{GUID_MetadataFormatXMP, + 0xbb5acc38, 0xf216, 0x4cec, 0xa6, 0xc5, 0x5f, 0x6e, 0x73, 0x97, 0x63, 0xa9} +DEFINE_GUID!{GUID_MetadataFormatThumbnail, + 0x243dcee9, 0x8703, 0x40ee, 0x8e, 0xf0, 0x22, 0xa6, 0x00, 0xb8, 0x05, 0x8c} +DEFINE_GUID!{GUID_MetadataFormatChunktEXt, + 0x568d8936, 0xc0a9, 0x4923, 0x90, 0x5d, 0xdf, 0x2b, 0x38, 0x23, 0x8f, 0xbc} +DEFINE_GUID!{GUID_MetadataFormatXMPStruct, + 0x22383cf1, 0xed17, 0x4e2e, 0xaf, 0x17, 0xd8, 0x5b, 0x8f, 0x6b, 0x30, 0xd0} +DEFINE_GUID!{GUID_MetadataFormatXMPBag, + 0x833cca5f, 0xdcb7, 0x4516, 0x80, 0x6f, 0x65, 0x96, 0xab, 0x26, 0xdc, 0xe4} +DEFINE_GUID!{GUID_MetadataFormatXMPSeq, + 0x63e8df02, 0xeb6c, 0x456c, 0xa2, 0x24, 0xb2, 0x5e, 0x79, 0x4f, 0xd6, 0x48} +DEFINE_GUID!{GUID_MetadataFormatXMPAlt, + 0x7b08a675, 0x91aa, 0x481b, 0xa7, 0x98, 0x4d, 0xa9, 0x49, 0x08, 0x61, 0x3b} +DEFINE_GUID!{GUID_MetadataFormatLSD, + 0xe256031e, 0x6299, 0x4929, 0xb9, 0x8d, 0x5a, 0xc8, 0x84, 0xaf, 0xba, 0x92} +DEFINE_GUID!{GUID_MetadataFormatIMD, + 0xbd2bb086, 0x4d52, 0x48dd, 0x96, 0x77, 0xdb, 0x48, 0x3e, 0x85, 0xae, 0x8f} +DEFINE_GUID!{GUID_MetadataFormatGCE, + 0x2a25cad8, 0xdeeb, 0x4c69, 0xa7, 0x88, 0x0e, 0xc2, 0x26, 0x6d, 0xca, 0xfd} +DEFINE_GUID!{GUID_MetadataFormatAPE, + 0x2e043dc2, 0xc967, 0x4e05, 0x87, 0x5e, 0x61, 0x8b, 0xf6, 0x7e, 0x85, 0xc3} +DEFINE_GUID!{GUID_MetadataFormatJpegChrominance, + 0xf73d0dcf, 0xcec6, 0x4f85, 0x9b, 0x0e, 0x1c, 0x39, 0x56, 0xb1, 0xbe, 0xf7} +DEFINE_GUID!{GUID_MetadataFormatJpegLuminance, + 0x86908007, 0xedfc, 0x4860, 0x8d, 0x4b, 0x4e, 0xe6, 0xe8, 0x3e, 0x60, 0x58} +DEFINE_GUID!{GUID_MetadataFormatJpegComment, + 0x220e5f33, 0xafd3, 0x474e, 0x9d, 0x31, 0x7d, 0x4f, 0xe7, 0x30, 0xf5, 0x57} +DEFINE_GUID!{GUID_MetadataFormatGifComment, + 0xc4b6e0e0, 0xcfb4, 0x4ad3, 0xab, 0x33, 0x9a, 0xad, 0x23, 0x55, 0xa3, 0x4a} +DEFINE_GUID!{GUID_MetadataFormatChunkgAMA, + 0xf00935a5, 0x1d5d, 0x4cd1, 0x81, 0xb2, 0x93, 0x24, 0xd7, 0xec, 0xa7, 0x81} +DEFINE_GUID!{GUID_MetadataFormatChunkbKGD, + 0xe14d3571, 0x6b47, 0x4dea, 0xb6, 0x0a, 0x87, 0xce, 0x0a, 0x78, 0xdf, 0xb7} +DEFINE_GUID!{GUID_MetadataFormatChunkiTXt, + 0xc2bec729, 0x0b68, 0x4b77, 0xaa, 0x0e, 0x62, 0x95, 0xa6, 0xac, 0x18, 0x14} +DEFINE_GUID!{GUID_MetadataFormatChunkcHRM, + 0x9db3655b, 0x2842, 0x44b3, 0x80, 0x67, 0x12, 0xe9, 0xb3, 0x75, 0x55, 0x6a} +DEFINE_GUID!{GUID_MetadataFormatChunkhIST, + 0xc59a82da, 0xdb74, 0x48a4, 0xbd, 0x6a, 0xb6, 0x9c, 0x49, 0x31, 0xef, 0x95} +DEFINE_GUID!{GUID_MetadataFormatChunkiCCP, + 0xeb4349ab, 0xb685, 0x450f, 0x91, 0xb5, 0xe8, 0x02, 0xe8, 0x92, 0x53, 0x6c} +DEFINE_GUID!{GUID_MetadataFormatChunksRGB, + 0xc115fd36, 0xcc6f, 0x4e3f, 0x83, 0x63, 0x52, 0x4b, 0x87, 0xc6, 0xb0, 0xd9} +DEFINE_GUID!{GUID_MetadataFormatChunktIME, + 0x6b00ae2d, 0xe24b, 0x460a, 0x98, 0xb6, 0x87, 0x8b, 0xd0, 0x30, 0x72, 0xfd} +DEFINE_GUID!{GUID_MetadataFormatDds, + 0x4a064603, 0x8c33, 0x4e60, 0x9c, 0x29, 0x13, 0x62, 0x31, 0x70, 0x2d, 0x08} +DEFINE_GUID!{CLSID_WICUnknownMetadataReader, + 0x699745c2, 0x5066, 0x4b82, 0xa8, 0xe3, 0xd4, 0x04, 0x78, 0xdb, 0xec, 0x8c} +DEFINE_GUID!{CLSID_WICUnknownMetadataWriter, + 0xa09cca86, 0x27ba, 0x4f39, 0x90, 0x53, 0x12, 0x1f, 0xa4, 0xdc, 0x08, 0xfc} +DEFINE_GUID!{CLSID_WICApp0MetadataWriter, + 0xf3c633a2, 0x46c8, 0x498e, 0x8f, 0xbb, 0xcc, 0x6f, 0x72, 0x1b, 0xbc, 0xde} +DEFINE_GUID!{CLSID_WICApp0MetadataReader, + 0x43324b33, 0xa78f, 0x480f, 0x91, 0x11, 0x96, 0x38, 0xaa, 0xcc, 0xc8, 0x32} +DEFINE_GUID!{CLSID_WICApp1MetadataWriter, + 0xee366069, 0x1832, 0x420f, 0xb3, 0x81, 0x04, 0x79, 0xad, 0x06, 0x6f, 0x19} +DEFINE_GUID!{CLSID_WICApp1MetadataReader, + 0xdde33513, 0x774e, 0x4bcd, 0xae, 0x79, 0x02, 0xf4, 0xad, 0xfe, 0x62, 0xfc} +DEFINE_GUID!{CLSID_WICApp13MetadataWriter, + 0x7b19a919, 0xa9d6, 0x49e5, 0xbd, 0x45, 0x02, 0xc3, 0x4e, 0x4e, 0x4c, 0xd5} +DEFINE_GUID!{CLSID_WICApp13MetadataReader, + 0xaa7e3c50, 0x864c, 0x4604, 0xbc, 0x04, 0x8b, 0x0b, 0x76, 0xe6, 0x37, 0xf6} +DEFINE_GUID!{CLSID_WICIfdMetadataReader, + 0x8f914656, 0x9d0a, 0x4eb2, 0x90, 0x19, 0x0b, 0xf9, 0x6d, 0x8a, 0x9e, 0xe6} +DEFINE_GUID!{CLSID_WICIfdMetadataWriter, + 0xb1ebfc28, 0xc9bd, 0x47a2, 0x8d, 0x33, 0xb9, 0x48, 0x76, 0x97, 0x77, 0xa7} +DEFINE_GUID!{CLSID_WICSubIfdMetadataReader, + 0x50d42f09, 0xecd1, 0x4b41, 0xb6, 0x5d, 0xda, 0x1f, 0xda, 0xa7, 0x56, 0x63} +DEFINE_GUID!{CLSID_WICSubIfdMetadataWriter, + 0x8ade5386, 0x8e9b, 0x4f4c, 0xac, 0xf2, 0xf0, 0x00, 0x87, 0x06, 0xb2, 0x38} +DEFINE_GUID!{CLSID_WICExifMetadataReader, + 0xd9403860, 0x297f, 0x4a49, 0xbf, 0x9b, 0x77, 0x89, 0x81, 0x50, 0xa4, 0x42} +DEFINE_GUID!{CLSID_WICExifMetadataWriter, + 0xc9a14cda, 0xc339, 0x460b, 0x90, 0x78, 0xd4, 0xde, 0xbc, 0xfa, 0xbe, 0x91} +DEFINE_GUID!{CLSID_WICGpsMetadataReader, + 0x3697790b, 0x223b, 0x484e, 0x99, 0x25, 0xc4, 0x86, 0x92, 0x18, 0xf1, 0x7a} +DEFINE_GUID!{CLSID_WICGpsMetadataWriter, + 0xcb8c13e4, 0x62b5, 0x4c96, 0xa4, 0x8b, 0x6b, 0xa6, 0xac, 0xe3, 0x9c, 0x76} +DEFINE_GUID!{CLSID_WICInteropMetadataReader, + 0xb5c8b898, 0x0074, 0x459f, 0xb7, 0x00, 0x86, 0x0d, 0x46, 0x51, 0xea, 0x14} +DEFINE_GUID!{CLSID_WICInteropMetadataWriter, + 0x122ec645, 0xcd7e, 0x44d8, 0xb1, 0x86, 0x2c, 0x8c, 0x20, 0xc3, 0xb5, 0x0f} +DEFINE_GUID!{CLSID_WICThumbnailMetadataReader, + 0xfb012959, 0xf4f6, 0x44d7, 0x9d, 0x09, 0xda, 0xa0, 0x87, 0xa9, 0xdb, 0x57} +DEFINE_GUID!{CLSID_WICThumbnailMetadataWriter, + 0xd049b20c, 0x5dd0, 0x44fe, 0xb0, 0xb3, 0x8f, 0x92, 0xc8, 0xe6, 0xd0, 0x80} +DEFINE_GUID!{CLSID_WICIPTCMetadataReader, + 0x03012959, 0xf4f6, 0x44d7, 0x9d, 0x09, 0xda, 0xa0, 0x87, 0xa9, 0xdb, 0x57} +DEFINE_GUID!{CLSID_WICIPTCMetadataWriter, + 0x1249b20c, 0x5dd0, 0x44fe, 0xb0, 0xb3, 0x8f, 0x92, 0xc8, 0xe6, 0xd0, 0x80} +DEFINE_GUID!{CLSID_WICIRBMetadataReader, + 0xd4dcd3d7, 0xb4c2, 0x47d9, 0xa6, 0xbf, 0xb8, 0x9b, 0xa3, 0x96, 0xa4, 0xa3} +DEFINE_GUID!{CLSID_WICIRBMetadataWriter, + 0x5c5c1935, 0x0235, 0x4434, 0x80, 0xbc, 0x25, 0x1b, 0xc1, 0xec, 0x39, 0xc6} +DEFINE_GUID!{CLSID_WIC8BIMIPTCMetadataReader, + 0x0010668c, 0x0801, 0x4da6, 0xa4, 0xa4, 0x82, 0x65, 0x22, 0xb6, 0xd2, 0x8f} +DEFINE_GUID!{CLSID_WIC8BIMIPTCMetadataWriter, + 0x00108226, 0xee41, 0x44a2, 0x9e, 0x9c, 0x4b, 0xe4, 0xd5, 0xb1, 0xd2, 0xcd} +DEFINE_GUID!{CLSID_WIC8BIMResolutionInfoMetadataReader, + 0x5805137a, 0xe348, 0x4f7c, 0xb3, 0xcc, 0x6d, 0xb9, 0x96, 0x5a, 0x05, 0x99} +DEFINE_GUID!{CLSID_WIC8BIMResolutionInfoMetadataWriter, + 0x4ff2fe0e, 0xe74a, 0x4b71, 0x98, 0xc4, 0xab, 0x7d, 0xc1, 0x67, 0x07, 0xba} +DEFINE_GUID!{CLSID_WIC8BIMIPTCDigestMetadataReader, + 0x02805f1e, 0xd5aa, 0x415b, 0x82, 0xc5, 0x61, 0xc0, 0x33, 0xa9, 0x88, 0xa6} +DEFINE_GUID!{CLSID_WIC8BIMIPTCDigestMetadataWriter, + 0x2db5e62b, 0x0d67, 0x495f, 0x8f, 0x9d, 0xc2, 0xf0, 0x18, 0x86, 0x47, 0xac} +DEFINE_GUID!{CLSID_WICPngTextMetadataReader, + 0x4b59afcc, 0xb8c3, 0x408a, 0xb6, 0x70, 0x89, 0xe5, 0xfa, 0xb6, 0xfd, 0xa7} +DEFINE_GUID!{CLSID_WICPngTextMetadataWriter, + 0xb5ebafb9, 0x253e, 0x4a72, 0xa7, 0x44, 0x07, 0x62, 0xd2, 0x68, 0x56, 0x83} +DEFINE_GUID!{CLSID_WICXMPMetadataReader, + 0x72b624df, 0xae11, 0x4948, 0xa6, 0x5c, 0x35, 0x1e, 0xb0, 0x82, 0x94, 0x19} +DEFINE_GUID!{CLSID_WICXMPMetadataWriter, + 0x1765e14e, 0x1bd4, 0x462e, 0xb6, 0xb1, 0x59, 0x0b, 0xf1, 0x26, 0x2a, 0xc6} +DEFINE_GUID!{CLSID_WICXMPStructMetadataReader, + 0x01b90d9a, 0x8209, 0x47f7, 0x9c, 0x52, 0xe1, 0x24, 0x4b, 0xf5, 0x0c, 0xed} +DEFINE_GUID!{CLSID_WICXMPStructMetadataWriter, + 0x22c21f93, 0x7ddb, 0x411c, 0x9b, 0x17, 0xc5, 0xb7, 0xbd, 0x06, 0x4a, 0xbc} +DEFINE_GUID!{CLSID_WICXMPBagMetadataReader, + 0xe7e79a30, 0x4f2c, 0x4fab, 0x8d, 0x00, 0x39, 0x4f, 0x2d, 0x6b, 0xbe, 0xbe} +DEFINE_GUID!{CLSID_WICXMPBagMetadataWriter, + 0xed822c8c, 0xd6be, 0x4301, 0xa6, 0x31, 0x0e, 0x14, 0x16, 0xba, 0xd2, 0x8f} +DEFINE_GUID!{CLSID_WICXMPSeqMetadataReader, + 0x7f12e753, 0xfc71, 0x43d7, 0xa5, 0x1d, 0x92, 0xf3, 0x59, 0x77, 0xab, 0xb5} +DEFINE_GUID!{CLSID_WICXMPSeqMetadataWriter, + 0x6d68d1de, 0xd432, 0x4b0f, 0x92, 0x3a, 0x09, 0x11, 0x83, 0xa9, 0xbd, 0xa7} +DEFINE_GUID!{CLSID_WICXMPAltMetadataReader, + 0xaa94dcc2, 0xb8b0, 0x4898, 0xb8, 0x35, 0x00, 0x0a, 0xab, 0xd7, 0x43, 0x93} +DEFINE_GUID!{CLSID_WICXMPAltMetadataWriter, + 0x076c2a6c, 0xf78f, 0x4c46, 0xa7, 0x23, 0x35, 0x83, 0xe7, 0x08, 0x76, 0xea} +DEFINE_GUID!{CLSID_WICLSDMetadataReader, + 0x41070793, 0x59e4, 0x479a, 0xa1, 0xf7, 0x95, 0x4a, 0xdc, 0x2e, 0xf5, 0xfc} +DEFINE_GUID!{CLSID_WICLSDMetadataWriter, + 0x73c037e7, 0xe5d9, 0x4954, 0x87, 0x6a, 0x6d, 0xa8, 0x1d, 0x6e, 0x57, 0x68} +DEFINE_GUID!{CLSID_WICGCEMetadataReader, + 0xb92e345d, 0xf52d, 0x41f3, 0xb5, 0x62, 0x08, 0x1b, 0xc7, 0x72, 0xe3, 0xb9} +DEFINE_GUID!{CLSID_WICGCEMetadataWriter, + 0xaf95dc76, 0x16b2, 0x47f4, 0xb3, 0xea, 0x3c, 0x31, 0x79, 0x66, 0x93, 0xe7} +DEFINE_GUID!{CLSID_WICIMDMetadataReader, + 0x7447a267, 0x0015, 0x42c8, 0xa8, 0xf1, 0xfb, 0x3b, 0x94, 0xc6, 0x83, 0x61} +DEFINE_GUID!{CLSID_WICIMDMetadataWriter, + 0x8c89071f, 0x452e, 0x4e95, 0x96, 0x82, 0x9d, 0x10, 0x24, 0x62, 0x71, 0x72} +DEFINE_GUID!{CLSID_WICAPEMetadataReader, + 0x1767b93a, 0xb021, 0x44ea, 0x92, 0x0f, 0x86, 0x3c, 0x11, 0xf4, 0xf7, 0x68} +DEFINE_GUID!{CLSID_WICAPEMetadataWriter, + 0xbd6edfca, 0x2890, 0x482f, 0xb2, 0x33, 0x8d, 0x73, 0x39, 0xa1, 0xcf, 0x8d} +DEFINE_GUID!{CLSID_WICJpegChrominanceMetadataReader, + 0x50b1904b, 0xf28f, 0x4574, 0x93, 0xf4, 0x0b, 0xad, 0xe8, 0x2c, 0x69, 0xe9} +DEFINE_GUID!{CLSID_WICJpegChrominanceMetadataWriter, + 0x3ff566f0, 0x6e6b, 0x49d4, 0x96, 0xe6, 0xb7, 0x88, 0x86, 0x69, 0x2c, 0x62} +DEFINE_GUID!{CLSID_WICJpegLuminanceMetadataReader, + 0x356f2f88, 0x05a6, 0x4728, 0xb9, 0xa4, 0x1b, 0xfb, 0xce, 0x04, 0xd8, 0x38} +DEFINE_GUID!{CLSID_WICJpegLuminanceMetadataWriter, + 0x1d583abc, 0x8a0e, 0x4657, 0x99, 0x82, 0xa3, 0x80, 0xca, 0x58, 0xfb, 0x4b} +DEFINE_GUID!{CLSID_WICJpegCommentMetadataReader, + 0x9f66347c, 0x60c4, 0x4c4d, 0xab, 0x58, 0xd2, 0x35, 0x86, 0x85, 0xf6, 0x07} +DEFINE_GUID!{CLSID_WICJpegCommentMetadataWriter, + 0xe573236f, 0x55b1, 0x4eda, 0x81, 0xea, 0x9f, 0x65, 0xdb, 0x02, 0x90, 0xd3} +DEFINE_GUID!{CLSID_WICGifCommentMetadataReader, + 0x32557d3b, 0x69dc, 0x4f95, 0x83, 0x6e, 0xf5, 0x97, 0x2b, 0x2f, 0x61, 0x59} +DEFINE_GUID!{CLSID_WICGifCommentMetadataWriter, + 0xa02797fc, 0xc4ae, 0x418c, 0xaf, 0x95, 0xe6, 0x37, 0xc7, 0xea, 0xd2, 0xa1} +DEFINE_GUID!{CLSID_WICPngGamaMetadataReader, + 0x3692ca39, 0xe082, 0x4350, 0x9e, 0x1f, 0x37, 0x04, 0xcb, 0x08, 0x3c, 0xd5} +DEFINE_GUID!{CLSID_WICPngGamaMetadataWriter, + 0xff036d13, 0x5d4b, 0x46dd, 0xb1, 0x0f, 0x10, 0x66, 0x93, 0xd9, 0xfe, 0x4f} +DEFINE_GUID!{CLSID_WICPngBkgdMetadataReader, + 0x0ce7a4a6, 0x03e8, 0x4a60, 0x9d, 0x15, 0x28, 0x2e, 0xf3, 0x2e, 0xe7, 0xda} +DEFINE_GUID!{CLSID_WICPngBkgdMetadataWriter, + 0x68e3f2fd, 0x31ae, 0x4441, 0xbb, 0x6a, 0xfd, 0x70, 0x47, 0x52, 0x5f, 0x90} +DEFINE_GUID!{CLSID_WICPngItxtMetadataReader, + 0xaabfb2fa, 0x3e1e, 0x4a8f, 0x89, 0x77, 0x55, 0x56, 0xfb, 0x94, 0xea, 0x23} +DEFINE_GUID!{CLSID_WICPngItxtMetadataWriter, + 0x31879719, 0xe751, 0x4df8, 0x98, 0x1d, 0x68, 0xdf, 0xf6, 0x77, 0x04, 0xed} +DEFINE_GUID!{CLSID_WICPngChrmMetadataReader, + 0xf90b5f36, 0x367b, 0x402a, 0x9d, 0xd1, 0xbc, 0x0f, 0xd5, 0x9d, 0x8f, 0x62} +DEFINE_GUID!{CLSID_WICPngChrmMetadataWriter, + 0xe23ce3eb, 0x5608, 0x4e83, 0xbc, 0xef, 0x27, 0xb1, 0x98, 0x7e, 0x51, 0xd7} +DEFINE_GUID!{CLSID_WICPngHistMetadataReader, + 0x877a0bb7, 0xa313, 0x4491, 0x87, 0xb5, 0x2e, 0x6d, 0x05, 0x94, 0xf5, 0x20} +DEFINE_GUID!{CLSID_WICPngHistMetadataWriter, + 0x8a03e749, 0x672e, 0x446e, 0xbf, 0x1f, 0x2c, 0x11, 0xd2, 0x33, 0xb6, 0xff} +DEFINE_GUID!{CLSID_WICPngIccpMetadataReader, + 0xf5d3e63b, 0xcb0f, 0x4628, 0xa4, 0x78, 0x6d, 0x82, 0x44, 0xbe, 0x36, 0xb1} +DEFINE_GUID!{CLSID_WICPngIccpMetadataWriter, + 0x16671e5f, 0x0ce6, 0x4cc4, 0x97, 0x68, 0xe8, 0x9f, 0xe5, 0x01, 0x8a, 0xde} +DEFINE_GUID!{CLSID_WICPngSrgbMetadataReader, + 0xfb40360c, 0x547e, 0x4956, 0xa3, 0xb9, 0xd4, 0x41, 0x88, 0x59, 0xba, 0x66} +DEFINE_GUID!{CLSID_WICPngSrgbMetadataWriter, + 0xa6ee35c6, 0x87ec, 0x47df, 0x9f, 0x22, 0x1d, 0x5a, 0xad, 0x84, 0x0c, 0x82} +DEFINE_GUID!{CLSID_WICPngTimeMetadataReader, + 0xd94edf02, 0xefe5, 0x4f0d, 0x85, 0xc8, 0xf5, 0xa6, 0x8b, 0x30, 0x00, 0xb1} +DEFINE_GUID!{CLSID_WICPngTimeMetadataWriter, + 0x1ab78400, 0xb5a3, 0x4d91, 0x8a, 0xce, 0x33, 0xfc, 0xd1, 0x49, 0x9b, 0xe6} +DEFINE_GUID!{CLSID_WICDdsMetadataReader, + 0x276c88ca, 0x7533, 0x4a86, 0xb6, 0x76, 0x66, 0xb3, 0x60, 0x80, 0xd4, 0x84} +DEFINE_GUID!{CLSID_WICDdsMetadataWriter, + 0xfd688bbd, 0x31ed, 0x4db7, 0xa7, 0x23, 0x93, 0x49, 0x27, 0xd3, 0x83, 0x67} +ENUM!{enum WICMetadataCreationOptions { + WICMetadataCreationDefault = 0, + WICMetadataCreationAllowUnknown = WICMetadataCreationDefault, + WICMetadataCreationFailUnknown = 0x10000, + WICMetadataCreationMask = 0xffff0000, +}} +ENUM!{enum WICPersistOptions { + WICPersistOptionDefault = 0, + WICPersistOptionLittleEndian = 0, + WICPersistOptionBigEndian = 0x1, + WICPersistOptionStrictFormat = 0x2, + WICPersistOptionNoCacheStream = 0x4, + WICPersistOptionPreferUTF8 = 0x8, + WICPersistOptionMask = 0xffff, +}} +RIDL!{#[uuid(0xfeaa2a8d, 0xb3f3, 0x43e4, 0xb2, 0x5c, 0xd1, 0xde, 0x99, 0x0a, 0x1a, 0xe1)] +interface IWICMetadataBlockReader(IWICMetadataBlockReaderVtbl): IUnknown(IUnknownVtbl) { + fn GetContainerFormat( + pguidContainerFormat: *mut GUID, + ) -> HRESULT, + fn GetCount( + pcCount: *mut UINT, + ) -> HRESULT, + fn GetReaderByIndex( + ppIMetadataReader: *mut *mut IWICMetadataReader, + ) -> HRESULT, + fn GetEnumerator( + ppIEnumMetadata: *mut IEnumUnknown, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x08fb9676, 0xb444, 0x41e8, 0x8d, 0xbe, 0x6a, 0x53, 0xa5, 0x42, 0xbf, 0xf1)] +interface IWICMetadataBlockWriter(IWICMetadataBlockWriterVtbl): + IWICMetadataBlockReader(IWICMetadataBlockReaderVtbl) { + fn InitializeFromBlockReader( + pIMDBlockReader: *mut IWICMetadataBlockReader, + ) -> HRESULT, + fn GetWriterByIndex( + ppIMetadataWriter: *mut *mut IWICMetadataWriter, + ) -> HRESULT, + fn AddWriter( + pIMetadataWriter: *mut IWICMetadataWriter, + ) -> HRESULT, + fn SetWriterByIndex( + pIMetadataWriter: *mut IWICMetadataWriter, + ) -> HRESULT, + fn RemoveWriterByIndex( + nIndex: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x9204fe99, 0xd8fc, 0x4fd5, 0xa0, 0x01, 0x95, 0x36, 0xb0, 0x67, 0xa8, 0x99)] +interface IWICMetadataReader(IWICMetadataReaderVtbl): IUnknown(IUnknownVtbl) { + fn GetMetadataFormat( + pguidMetadataFormat: *mut GUID, + ) -> HRESULT, + fn GetMetadataHandlerInfo( + ppIHandler: *mut *mut IWICMetadataHandlerInfo, + ) -> HRESULT, + fn GetCount( + pcCount: *mut UINT, + ) -> HRESULT, + fn GetValueByIndex( + nIndex: UINT, + pvarSchema: *mut PROPVARIANT, + pvarId: *mut PROPVARIANT, + pvarValue: *mut PROPVARIANT, + ) -> HRESULT, + fn GetValue( + pvarSchema: *const PROPVARIANT, + pvarId: *const PROPVARIANT, + pvarValue: *mut PROPVARIANT, + ) -> HRESULT, + fn GetEnumerator( + ppIEnumMetadata: *mut *mut IWICEnumMetadataItem, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xf7836e16, 0x3be0, 0x470b, 0x86, 0xbb, 0x16, 0x0d, 0x0a, 0xec, 0xd7, 0xde)] +interface IWICMetadataWriter(IWICMetadataWriterVtbl): IWICMetadataReader(IWICMetadataReaderVtbl) { + fn SetValue( + pvarSchema: *const PROPVARIANT, + pvarId: *const PROPVARIANT, + pvarValue: *const PROPVARIANT, + ) -> HRESULT, + fn SetValueByIndex( + nIndex: UINT, + pvarSchema: *const PROPVARIANT, + pvarId: *const PROPVARIANT, + pvarValue: *const PROPVARIANT, + ) -> HRESULT, + fn RemoveValue( + pvarSchema: *const PROPVARIANT, + pvarId: *const PROPVARIANT, + ) -> HRESULT, + fn RemoveValueByIndex( + nIndex: UINT, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x449494bc, 0xb468, 0x4927, 0x96, 0xd7, 0xba, 0x90, 0xd3, 0x1a, 0xb5, 0x05)] +interface IWICStreamProvider(IWICStreamProviderVtbl): IUnknown(IUnknownVtbl) { + fn GetStream( + ppIStream: *mut *mut IStream, + ) -> HRESULT, + fn GetPersistOptions( + pdwPersistOptions: *mut DWORD, + ) -> HRESULT, + fn GetPreferredVendorGUID( + pguidPreferredVendor: *mut GUID, + ) -> HRESULT, + fn RefreshStream() -> HRESULT, +}} +RIDL!{#[uuid(0x00675040, 0x6908, 0x45f8, 0x86, 0xa3, 0x49, 0xc7, 0xdf, 0xd6, 0xd9, 0xad)] +interface IWICPersistStream(IWICPersistStreamVtbl): IPersistStream(IPersistStreamVtbl) { + fn LoadEx( + pIStream: *mut IStream, + pguidPreferredVendor: *const GUID, + dwPersistOptions: DWORD, + ) -> HRESULT, + fn SaveEx( + pIStream: *mut IStream, + dwPersistOptions: DWORD, + fClearDirty: BOOL, + ) -> HRESULT, +}} +RIDL!{#[uuid(0xaba958bf, 0xc672, 0x44d1, 0x8d, 0x61, 0xce, 0x6d, 0xf2, 0xe6, 0x82, 0xc2)] +interface IWICMetadataHandlerInfo(IWICMetadataHandlerInfoVtbl): + IWICComponentInfo(IWICComponentInfoVtbl) { + fn GetMetadataFormat( + pguidMetadataFormat: *mut GUID, + ) -> HRESULT, + fn GetContainerFormats( + cContainerFormats: UINT, + pguidContainerFormats: *mut GUID, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetDeviceManufacturer( + cchDeviceManufacturer: UINT, + wzDeviceManufacturer: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn GetDeviceModels( + cchDeviceModels: UINT, + wzDeviceModels: *mut WCHAR, + pcchActual: *mut UINT, + ) -> HRESULT, + fn DoesRequireFullStream( + pfRequiresFullStream: *mut BOOL, + ) -> HRESULT, + fn DoesSupportPadding( + pfSupportsPadding: *mut BOOL, + ) -> HRESULT, + fn DoesRequireFixedSize( + pfFixedSize: *mut BOOL, + ) -> HRESULT, +}} +STRUCT!{struct WICMetadataPattern { + Position: ULARGE_INTEGER, + Length: ULONG, + Pattern: *mut BYTE, + Mask: *mut BYTE, + DataOffset: ULARGE_INTEGER, +}} +RIDL!{#[uuid(0xeebf1f5b, 0x07c1, 0x4447, 0xa3, 0xab, 0x22, 0xac, 0xaf, 0x78, 0xa8, 0x04)] +interface IWICMetadataReaderInfo(IWICMetadataReaderInfoVtbl): + IWICMetadataHandlerInfo(IWICMetadataHandlerInfoVtbl) { + fn GetPatterns( + guidContainerFormat: REFGUID, + cbSize: UINT, + pPattern: *mut WICMetadataPattern, + pcCount: *mut UINT, + pcbActual: *mut UINT, + ) -> HRESULT, + fn MatchesPattern( + guidContainerFormat: REFGUID, + pIStream: *mut IStream, + pfMatches: *mut BOOL, + ) -> HRESULT, + fn CreateInstance( + ppIReader: *mut *mut IWICMetadataReader, + ) -> HRESULT, +}} +STRUCT!{struct WICMetadataHeader { + Position: ULARGE_INTEGER, + Length: ULONG, + Header: *mut BYTE, + DataOffset: ULARGE_INTEGER, +}} +RIDL!{#[uuid(0xb22e3fba, 0x3925, 0x4323, 0xb5, 0xc1, 0x9e, 0xbf, 0xc4, 0x30, 0xf2, 0x36)] +interface IWICMetadataWriterInfo(IWICMetadataWriterInfoVtbl): + IWICMetadataHandlerInfo(IWICMetadataHandlerInfoVtbl) { + fn GetHeader( + guidContainerFormat: REFGUID, + cbSize: UINT, + pHeader: *mut WICMetadataHeader, + pcbActual: *mut UINT, + ) -> HRESULT, + fn CreateInstance( + ppIWriter: *mut *mut IWICMetadataWriter, + ) -> HRESULT, +}} +RIDL!{#[uuid(0x412d0c3a, 0x9650, 0x44fa, 0xaf, 0x5b, 0xdd, 0x2a, 0x06, 0xc8, 0xe8, 0xfb)] +interface IWICComponentFactory(IWICComponentFactoryVtbl): + IWICImagingFactory(IWICImagingFactoryVtbl) { + fn CreateMetadataReader( + guidMetadataFormat: REFGUID, + pguidVendor: *const GUID, + dwOptions: DWORD, + pIStream: *mut IStream, + ppIReader: *mut *mut IWICMetadataReader, + ) -> HRESULT, + fn CreateMetadataReaderFromContainer( + guidContainerFormat: REFGUID, + pguidVendor: *const GUID, + dwOptions: DWORD, + pIStream: *mut IStream, + ppIReader: *mut *mut IWICMetadataReader, + ) -> HRESULT, + fn CreateMetadataWriter( + guidMetadataFormat: REFGUID, + pguidVendor: *const GUID, + dwMetadataOptions: DWORD, + ppIWriter: *mut *mut IWICMetadataWriter, + ) -> HRESULT, + fn CreateMetadataWriterFromReader( + pIReader: *mut IWICMetadataReader, + pguidVendor: *const GUID, + ppIWriter: *mut *mut IWICMetadataWriter, + ) -> HRESULT, + fn CreateQueryReaderFromBlockReader( + pIBlockReader: *mut IWICMetadataBlockReader, + ppIQueryReader: *mut *mut IWICMetadataQueryReader, + ) -> HRESULT, + fn CreateQueryWriterFromBlockWriter( + pIBlockWriter: *mut IWICMetadataBlockWriter, + ppIQueryWriter: *mut *mut IWICMetadataQueryWriter, + ) -> HRESULT, + fn CreateEncoderPropertyBag( + ppropOptions: *mut PROPBAG2, + cCount: UINT, + ppIPropertyBag: *mut *mut IPropertyBag2, + ) -> HRESULT, +}} +extern "system" { + pub fn WICMatchMetadataContent( + guidContainerFormat: REFGUID, + pguidVendor: *const GUID, + pIStream: *mut IStream, + pguidMetadataFormat: *mut GUID, + ) -> HRESULT; + pub fn WICSerializeMetadataContent( + guidContainerFormat: REFGUID, + pIWriter: *mut IWICMetadataWriter, + dwPersistOptions: DWORD, + pIStream: *mut IStream, + ) -> HRESULT; + pub fn WICGetMetadataContentSize( + guidContainerFormat: REFGUID, + pIWriter: *mut IWICMetadataWriter, + pcbSize: *mut ULARGE_INTEGER, + ) -> HRESULT; + pub fn BSTR_UserSize( + pFlags: *mut c_ulong, + Offset: c_ulong, + pBstr: *mut BSTR, + ) -> c_ulong; + pub fn BSTR_UserMarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserUnmarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut BSTR, + ) -> *mut c_uchar; + pub fn BSTR_UserFree( + pFlags: *mut c_ulong, + pBstr: *mut BSTR, + ); + pub fn CLIPFORMAT_UserSize( + pFlags: *mut c_ulong, + Offset: c_ulong, + pCF: *mut CLIPFORMAT, + ) -> c_ulong; + pub fn CLIPFORMAT_UserMarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pCF: *mut CLIPFORMAT, + ) -> *mut c_uchar; + pub fn CLIPFORMAT_UserUnmarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pCF: *mut CLIPFORMAT, + ) -> *mut c_uchar; + pub fn CLIPFORMAT_UserFree( + pFlags: *mut c_ulong, + pCF: *mut CLIPFORMAT, + ); + pub fn LPSAFEARRAY_UserSize( + pFlags: *mut c_ulong, + Offset: c_ulong, + phBmp: *mut LPSAFEARRAY, + ) -> c_ulong; + pub fn LPSAFEARRAY_UserMarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut LPSAFEARRAY, + ) -> *mut c_uchar; + pub fn LPSAFEARRAY_UserUnmarshal( + pFlags: *mut c_ulong, + pBuffer: *mut c_uchar, + pBstr: *mut LPSAFEARRAY, + ) -> *mut c_uchar; + pub fn LPSAFEARRAY_UserFree( + pFlags: *mut c_ulong, + pBstr: *mut LPSAFEARRAY, + ); +} diff --git a/winapi/src/um/wincon.rs b/winapi/src/um/wincon.rs new file mode 100644 index 000000000..9eb3a2290 --- /dev/null +++ b/winapi/src/um/wincon.rs @@ -0,0 +1,459 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module contains the public data structures, data types, and procedures exported by the NT +//! console subsystem. +use ctypes::c_void; +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPVOID, LPWORD, UINT, ULONG, WORD}; +use shared::windef::{COLORREF, HWND}; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::wingdi::LF_FACESIZE; +use um::winnt::{CHAR, HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, WCHAR}; +// Many definitions in wincontypes used to be defined in this file, so reexport them to avoid +// breakage. For clarity they are imported in the order they are defined in that file rather +// than winapi's usual alphabetical ordering, with some newlines and indentation to match their +// grouping in the file. +pub use um::wincontypes::{ + COORD, PCOORD, + SMALL_RECT, PSMALL_RECT, + KEY_EVENT_RECORD_uChar, KEY_EVENT_RECORD, PKEY_EVENT_RECORD, + RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, SHIFT_PRESSED, + NUMLOCK_ON, SCROLLLOCK_ON, CAPSLOCK_ON, ENHANCED_KEY, NLS_DBCSCHAR, NLS_ALPHANUMERIC, + NLS_KATAKANA, NLS_HIRAGANA, NLS_ROMAN, NLS_IME_CONVERSION, NLS_IME_DISABLE, + MOUSE_EVENT_RECORD, PMOUSE_EVENT_RECORD, + FROM_LEFT_1ST_BUTTON_PRESSED, RIGHTMOST_BUTTON_PRESSED, FROM_LEFT_2ND_BUTTON_PRESSED, + FROM_LEFT_3RD_BUTTON_PRESSED, FROM_LEFT_4TH_BUTTON_PRESSED, MOUSE_MOVED, DOUBLE_CLICK, + MOUSE_WHEELED, MOUSE_HWHEELED, + WINDOW_BUFFER_SIZE_RECORD, PWINDOW_BUFFER_SIZE_RECORD, + MENU_EVENT_RECORD, PMENU_EVENT_RECORD, + FOCUS_EVENT_RECORD, PFOCUS_EVENT_RECORD, + INPUT_RECORD_Event, INPUT_RECORD, PINPUT_RECORD, + KEY_EVENT, MOUSE_EVENT, WINDOW_BUFFER_SIZE_EVENT, MENU_EVENT, FOCUS_EVENT, + CHAR_INFO_Char, CHAR_INFO, PCHAR_INFO, + CONSOLE_FONT_INFO, PCONSOLE_FONT_INFO +}; +pub const FOREGROUND_BLUE: WORD = 0x0001; +pub const FOREGROUND_GREEN: WORD = 0x0002; +pub const FOREGROUND_RED: WORD = 0x0004; +pub const FOREGROUND_INTENSITY: WORD = 0x0008; +pub const BACKGROUND_BLUE: WORD = 0x0010; +pub const BACKGROUND_GREEN: WORD = 0x0020; +pub const BACKGROUND_RED: WORD = 0x0040; +pub const BACKGROUND_INTENSITY: WORD = 0x0080; +pub const COMMON_LVB_LEADING_BYTE: WORD = 0x0100; +pub const COMMON_LVB_TRAILING_BYTE: WORD = 0x0200; +pub const COMMON_LVB_GRID_HORIZONTAL: WORD = 0x0400; +pub const COMMON_LVB_GRID_LVERTICAL: WORD = 0x0800; +pub const COMMON_LVB_GRID_RVERTICAL: WORD = 0x1000; +pub const COMMON_LVB_REVERSE_VIDEO: WORD = 0x4000; +pub const COMMON_LVB_UNDERSCORE: WORD = 0x8000; +pub const COMMON_LVB_SBCSDBCS: WORD = 0x0300; +STRUCT!{struct CONSOLE_SCREEN_BUFFER_INFO { + dwSize: COORD, + dwCursorPosition: COORD, + wAttributes: WORD, + srWindow: SMALL_RECT, + dwMaximumWindowSize: COORD, +}} +pub type PCONSOLE_SCREEN_BUFFER_INFO = *mut CONSOLE_SCREEN_BUFFER_INFO; +STRUCT!{struct CONSOLE_SCREEN_BUFFER_INFOEX { + cbSize: ULONG, + dwSize: COORD, + dwCursorPosition: COORD, + wAttributes: WORD, + srWindow: SMALL_RECT, + dwMaximumWindowSize: COORD, + wPopupAttributes: WORD, + bFullscreenSupported: BOOL, + ColorTable: [COLORREF; 16], +}} +pub type PCONSOLE_SCREEN_BUFFER_INFOEX = *mut CONSOLE_SCREEN_BUFFER_INFOEX; +STRUCT!{struct CONSOLE_CURSOR_INFO { + dwSize: DWORD, + bVisible: BOOL, +}} +pub type PCONSOLE_CURSOR_INFO = *mut CONSOLE_CURSOR_INFO; +STRUCT!{struct CONSOLE_FONT_INFOEX { + cbSize: ULONG, + nFont: DWORD, + dwFontSize: COORD, + FontFamily: UINT, + FontWeight: UINT, + FaceName: [WCHAR; LF_FACESIZE], +}} +pub type PCONSOLE_FONT_INFOEX = *mut CONSOLE_FONT_INFOEX; +pub const HISTORY_NO_DUP_FLAG: DWORD = 0x1; +STRUCT!{struct CONSOLE_HISTORY_INFO { + cbSize: UINT, + HistoryBufferSize: UINT, + NumberOfHistoryBuffers: UINT, + dwFlags: DWORD, +}} +pub type PCONSOLE_HISTORY_INFO = *mut CONSOLE_HISTORY_INFO; +STRUCT!{struct CONSOLE_SELECTION_INFO { + dwFlags: DWORD, + dwSelectionAnchor: COORD, + srSelection: SMALL_RECT, +}} +pub type PCONSOLE_SELECTION_INFO = *mut CONSOLE_SELECTION_INFO; +pub const CONSOLE_NO_SELECTION: DWORD = 0x0000; +pub const CONSOLE_SELECTION_IN_PROGRESS: DWORD = 0x0001; +pub const CONSOLE_SELECTION_NOT_EMPTY: DWORD = 0x0002; +pub const CONSOLE_MOUSE_SELECTION: DWORD = 0x0004; +pub const CONSOLE_MOUSE_DOWN: DWORD = 0x0008; +FN!{stdcall PHANDLER_ROUTINE( + CtrlType: DWORD, +) -> BOOL} +pub const CTRL_C_EVENT: DWORD = 0; +pub const CTRL_BREAK_EVENT: DWORD = 1; +pub const CTRL_CLOSE_EVENT: DWORD = 2; +pub const CTRL_LOGOFF_EVENT: DWORD = 5; +pub const CTRL_SHUTDOWN_EVENT: DWORD = 6; +pub const ENABLE_PROCESSED_INPUT: DWORD = 0x0001; +pub const ENABLE_LINE_INPUT: DWORD = 0x0002; +pub const ENABLE_ECHO_INPUT: DWORD = 0x0004; +pub const ENABLE_WINDOW_INPUT: DWORD = 0x0008; +pub const ENABLE_MOUSE_INPUT: DWORD = 0x0010; +pub const ENABLE_INSERT_MODE: DWORD = 0x0020; +pub const ENABLE_QUICK_EDIT_MODE: DWORD = 0x0040; +pub const ENABLE_EXTENDED_FLAGS: DWORD = 0x0080; +pub const ENABLE_AUTO_POSITION: DWORD = 0x0100; +pub const ENABLE_VIRTUAL_TERMINAL_INPUT: DWORD = 0x0200; +pub const ENABLE_PROCESSED_OUTPUT: DWORD = 0x0001; +pub const ENABLE_WRAP_AT_EOL_OUTPUT: DWORD = 0x0002; +pub const ENABLE_VIRTUAL_TERMINAL_PROCESSING: DWORD = 0x0004; +pub const DISABLE_NEWLINE_AUTO_RETURN: DWORD = 0x0008; +pub const ENABLE_LVB_GRID_WORLDWIDE: DWORD = 0x0010; +extern "system" { + pub fn PeekConsoleInputW( + hConsoleInput: HANDLE, + lpBuffer: PINPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsRead: LPDWORD, + ) -> BOOL; + pub fn WriteConsoleInputA( + hConsoleInput: HANDLE, + lpBuffer: *const INPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsWritten: LPDWORD, + ) -> BOOL; + pub fn WriteConsoleInputW( + hConsoleInput: HANDLE, + lpBuffer: *const INPUT_RECORD, + nLength: DWORD, + lpNumberOfEventsWritten: LPDWORD, + ) -> BOOL; + pub fn ReadConsoleOutputA( + hConsoleOutput: HANDLE, + lpBuffer: PCHAR_INFO, + dwBufferSize: COORD, + dwBufferCoord: COORD, + lpReadRegion: PSMALL_RECT, + ) -> BOOL; + pub fn ReadConsoleOutputW( + hConsoleOutput: HANDLE, + lpBuffer: PCHAR_INFO, + dwBufferSize: COORD, + dwBufferCoord: COORD, + lpReadRegion: PSMALL_RECT, + ) -> BOOL; + pub fn WriteConsoleOutputA( + hConsoleOutput: HANDLE, + lpBuffer: *const CHAR_INFO, + dwBufferSize: COORD, + dwBufferCoord: COORD, + lpWriteRegion: PSMALL_RECT, + ) -> BOOL; + pub fn WriteConsoleOutputW( + hConsoleOutput: HANDLE, + lpBuffer: *const CHAR_INFO, + dwBufferSize: COORD, + dwBufferCoord: COORD, + lpWriteRegion: PSMALL_RECT, + ) -> BOOL; + pub fn ReadConsoleOutputCharacterA( + hConsoleOutput: HANDLE, + lpCharacter: LPSTR, + nLength: DWORD, + dwReadCoord: COORD, + lpNumberOfCharsRead: LPDWORD, + ) -> BOOL; + pub fn ReadConsoleOutputCharacterW( + hConsoleOutput: HANDLE, + lpCharacter: LPWSTR, + nLength: DWORD, + dwReadCoord: COORD, + lpNumberOfCharsRead: LPDWORD, + ) -> BOOL; + pub fn ReadConsoleOutputAttribute( + hConsoleOutput: HANDLE, + lpAttribute: LPWORD, + nLength: DWORD, + dwReadCoord: COORD, + lpNumberOfAttrsRead: LPDWORD, + ) -> BOOL; + pub fn WriteConsoleOutputCharacterA( + hConsoleOutput: HANDLE, + lpCharacter: LPCSTR, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfCharsWritten: LPDWORD, + ) -> BOOL; + pub fn WriteConsoleOutputCharacterW( + hConsoleOutput: HANDLE, + lpCharacter: LPCWSTR, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfCharsWritten: LPDWORD, + ) -> BOOL; + pub fn WriteConsoleOutputAttribute( + hConsoleOutput: HANDLE, + lpAttribute: *const WORD, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfAttrsWritten: LPDWORD, + ) -> BOOL; + pub fn FillConsoleOutputCharacterA( + hConsoleOutput: HANDLE, + cCharacter: CHAR, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfCharsWritten: LPDWORD, + ) -> BOOL; + pub fn FillConsoleOutputCharacterW( + hConsoleOutput: HANDLE, + cCharacter: WCHAR, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfCharsWritten: LPDWORD, + ) -> BOOL; + pub fn FillConsoleOutputAttribute( + hConsoleOutput: HANDLE, + wAttribute: WORD, + nLength: DWORD, + dwWriteCoord: COORD, + lpNumberOfAttrsWritten: LPDWORD, + ) -> BOOL; +} +pub const CONSOLE_REAL_OUTPUT_HANDLE: *mut c_void = -2isize as *mut c_void; +pub const CONSOLE_REAL_INPUT_HANDLE: *mut c_void = -3isize as *mut c_void; +extern "system" { + pub fn GetConsoleScreenBufferInfo( + hConsoleOutput: HANDLE, + lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO, + ) -> BOOL; + pub fn GetConsoleScreenBufferInfoEx( + hConsoleOutput: HANDLE, + lpConsoleScreenBufferInfoEx: PCONSOLE_SCREEN_BUFFER_INFOEX, + ) -> BOOL; + pub fn SetConsoleScreenBufferInfoEx( + hConsoleOutput: HANDLE, + lpConsoleScreenBufferInfoEx: PCONSOLE_SCREEN_BUFFER_INFOEX, + ) -> BOOL; + pub fn GetLargestConsoleWindowSize( + hConsoleOutput: HANDLE, + ) -> COORD; + pub fn GetConsoleCursorInfo( + hConsoleOutput: HANDLE, + lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO, + ) -> BOOL; + pub fn GetCurrentConsoleFont( + hConsoleOutput: HANDLE, + bMaximumWindow: BOOL, + lpConsoleCurrentFont: PCONSOLE_FONT_INFO, + ) -> BOOL; + pub fn GetCurrentConsoleFontEx( + hConsoleOutput: HANDLE, + bMaximumWindow: BOOL, + lpConsoleCurrentFontEx: PCONSOLE_FONT_INFOEX, + ) -> BOOL; + pub fn SetCurrentConsoleFontEx( + hConsoleOutput: HANDLE, + bMaximumWindow: BOOL, + lpConsoleCurrentFontEx: PCONSOLE_FONT_INFOEX, + ) -> BOOL; + pub fn GetConsoleHistoryInfo( + lpConsoleHistoryInfo: PCONSOLE_HISTORY_INFO, + ) -> BOOL; + pub fn SetConsoleHistoryInfo( + lpConsoleHistoryInfo: PCONSOLE_HISTORY_INFO, + ) -> BOOL; + pub fn GetConsoleFontSize( + hConsoleOutput: HANDLE, + nFont: DWORD, + ) -> COORD; + pub fn GetConsoleSelectionInfo( + lpConsoleSelectionInfo: PCONSOLE_SELECTION_INFO, + ) -> BOOL; + pub fn GetNumberOfConsoleMouseButtons( + lpNumberOfMouseButtons: LPDWORD, + ) -> BOOL; + pub fn SetConsoleActiveScreenBuffer( + hConsoleOutput: HANDLE, + ) -> BOOL; + pub fn FlushConsoleInputBuffer( + hConsoleInput: HANDLE, + ) -> BOOL; + pub fn SetConsoleScreenBufferSize( + hConsoleOutput: HANDLE, + dwSize: COORD, + ) -> BOOL; + pub fn SetConsoleCursorPosition( + hConsoleOutput: HANDLE, + dwCursorPosition: COORD, + ) -> BOOL; + pub fn SetConsoleCursorInfo( + hConsoleOutput: HANDLE, + lpConsoleCursorInfo: *const CONSOLE_CURSOR_INFO, + ) -> BOOL; + pub fn ScrollConsoleScreenBufferA( + hConsoleOutput: HANDLE, + lpScrollRectangle: *const SMALL_RECT, + lpClipRectangle: *const SMALL_RECT, + dwDestinationOrigin: COORD, + lpFill: *const CHAR_INFO, + ) -> BOOL; + pub fn ScrollConsoleScreenBufferW( + hConsoleOutput: HANDLE, + lpScrollRectangle: *const SMALL_RECT, + lpClipRectangle: *const SMALL_RECT, + dwDestinationOrigin: COORD, + lpFill: *const CHAR_INFO, + ) -> BOOL; + pub fn SetConsoleWindowInfo( + hConsoleOutput: HANDLE, + bAbsolute: BOOL, + lpConsoleWindow: *const SMALL_RECT, + ) -> BOOL; + pub fn SetConsoleTextAttribute( + hConsoleOutput: HANDLE, + wAttributes: WORD, + ) -> BOOL; + pub fn GenerateConsoleCtrlEvent( + dwCtrlEvent: DWORD, + dwProcessGroupId: DWORD, + ) -> BOOL; + pub fn FreeConsole() -> BOOL; + pub fn AttachConsole( + dwProcessId: DWORD, + ) -> BOOL; +} +pub const ATTACH_PARENT_PROCESS: DWORD = 0xFFFFFFFF; +extern "system" { + pub fn GetConsoleTitleA( + lpConsoleTitle: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetConsoleTitleW( + lpConsoleTitle: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetConsoleOriginalTitleA( + lpConsoleTitle: LPSTR, + nSize: DWORD, + ) -> DWORD; + pub fn GetConsoleOriginalTitleW( + lpConsoleTitle: LPWSTR, + nSize: DWORD, + ) -> DWORD; + pub fn SetConsoleTitleA( + lpConsoleTitle: LPCSTR, + ) -> BOOL; + pub fn SetConsoleTitleW( + lpConsoleTitle: LPCWSTR, + ) -> BOOL; +} +STRUCT!{struct CONSOLE_READCONSOLE_CONTROL { + nLength: ULONG, + nInitialChars: ULONG, + dwCtrlWakeupMask: ULONG, + dwControlKeyState: ULONG, +}} +pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL; +pub const CONSOLE_TEXTMODE_BUFFER: DWORD = 1; +extern "system" { + pub fn CreateConsoleScreenBuffer( + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: *const SECURITY_ATTRIBUTES, + dwFlags: DWORD, + lpScreenBufferData: LPVOID, + ) -> HANDLE; + pub fn SetConsoleCP( + wCodePageID: UINT, + ) -> BOOL; + pub fn SetConsoleOutputCP( + wCodePageID: UINT, + ) -> BOOL; +} +pub const CONSOLE_FULLSCREEN: DWORD = 1; +pub const CONSOLE_FULLSCREEN_HARDWARE: DWORD = 2; +extern "system" { + pub fn GetConsoleDisplayMode( + lpModeFlags: LPDWORD, + ) -> BOOL; +} +pub const CONSOLE_FULLSCREEN_MODE: DWORD = 1; +pub const CONSOLE_WINDOWED_MODE: DWORD = 2; +extern "system" { + pub fn SetConsoleDisplayMode( + hConsoleOutput: HANDLE, + dwFlags: DWORD, + lpNewScreenBufferDimensions: PCOORD, + ) -> BOOL; + pub fn GetConsoleWindow() -> HWND; + pub fn GetConsoleProcessList( + lpdwProcessList: LPDWORD, + dwProcessCount: DWORD, + ) -> DWORD; + pub fn AddConsoleAliasA( + Source: LPSTR, + Target: LPSTR, + ExeName: LPSTR, + ) -> BOOL; + pub fn AddConsoleAliasW( + Source: LPWSTR, + Target: LPWSTR, + ExeName: LPWSTR, + ) -> BOOL; + pub fn GetConsoleAliasA( + Source: LPSTR, + TargetBuffer: LPSTR, + TargetBufferLength: DWORD, + ExeName: LPSTR, + ) -> DWORD; + pub fn GetConsoleAliasW( + Source: LPWSTR, + TargetBuffer: LPWSTR, + TargetBufferLength: DWORD, + ExeName: LPWSTR, + ) -> DWORD; + pub fn GetConsoleAliasesLengthA( + ExeName: LPSTR, + ) -> DWORD; + pub fn GetConsoleAliasesLengthW( + ExeName: LPWSTR, + ) -> DWORD; + pub fn GetConsoleAliasExesLengthA() -> DWORD; + pub fn GetConsoleAliasExesLengthW() -> DWORD; + pub fn GetConsoleAliasesA( + AliasBuffer: LPSTR, + AliasBufferLength: DWORD, + ExeName: LPSTR, + ) -> DWORD; + pub fn GetConsoleAliasesW( + AliasBuffer: LPWSTR, + AliasBufferLength: DWORD, + ExeName: LPWSTR, + ) -> DWORD; + pub fn GetConsoleAliasExesA( + ExeNameBuffer: LPSTR, + ExeNameBufferLength: DWORD, + ) -> DWORD; + pub fn GetConsoleAliasExesW( + ExeNameBuffer: LPWSTR, + ExeNameBufferLength: DWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/wincontypes.rs b/winapi/src/um/wincontypes.rs new file mode 100644 index 000000000..ab37d0201 --- /dev/null +++ b/winapi/src/um/wincontypes.rs @@ -0,0 +1,114 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module contains the public data structures, data types, and procedures exported by the NT +//! console subsystem. +use ctypes::c_void; +use shared::minwindef::{BOOL, DWORD, UINT, WORD}; +use um::winnt::{CHAR, SHORT, WCHAR}; +STRUCT!{struct COORD { + X: SHORT, + Y: SHORT, +}} +pub type PCOORD = *mut COORD; +STRUCT!{struct SMALL_RECT { + Left: SHORT, + Top: SHORT, + Right: SHORT, + Bottom: SHORT, +}} +pub type PSMALL_RECT = *mut SMALL_RECT; +UNION!{union KEY_EVENT_RECORD_uChar { + [u16; 1], + UnicodeChar UnicodeChar_mut: WCHAR, + AsciiChar AsciiChar_mut: CHAR, +}} +STRUCT!{struct KEY_EVENT_RECORD { + bKeyDown: BOOL, + wRepeatCount: WORD, + wVirtualKeyCode: WORD, + wVirtualScanCode: WORD, + uChar: KEY_EVENT_RECORD_uChar, + dwControlKeyState: DWORD, +}} +pub type PKEY_EVENT_RECORD = *mut KEY_EVENT_RECORD; +pub const RIGHT_ALT_PRESSED: DWORD = 0x0001; +pub const LEFT_ALT_PRESSED: DWORD = 0x0002; +pub const RIGHT_CTRL_PRESSED: DWORD = 0x0004; +pub const LEFT_CTRL_PRESSED: DWORD = 0x0008; +pub const SHIFT_PRESSED: DWORD = 0x0010; +pub const NUMLOCK_ON: DWORD = 0x0020; +pub const SCROLLLOCK_ON: DWORD = 0x0040; +pub const CAPSLOCK_ON: DWORD = 0x0080; +pub const ENHANCED_KEY: DWORD = 0x0100; +pub const NLS_DBCSCHAR: DWORD = 0x00010000; +pub const NLS_ALPHANUMERIC: DWORD = 0x00000000; +pub const NLS_KATAKANA: DWORD = 0x00020000; +pub const NLS_HIRAGANA: DWORD = 0x00040000; +pub const NLS_ROMAN: DWORD = 0x00400000; +pub const NLS_IME_CONVERSION: DWORD = 0x00800000; +pub const NLS_IME_DISABLE: DWORD = 0x20000000; +STRUCT!{struct MOUSE_EVENT_RECORD { + dwMousePosition: COORD, + dwButtonState: DWORD, + dwControlKeyState: DWORD, + dwEventFlags: DWORD, +}} +pub type PMOUSE_EVENT_RECORD = *mut MOUSE_EVENT_RECORD; +pub const FROM_LEFT_1ST_BUTTON_PRESSED: DWORD = 0x0001; +pub const RIGHTMOST_BUTTON_PRESSED: DWORD = 0x0002; +pub const FROM_LEFT_2ND_BUTTON_PRESSED: DWORD = 0x0004; +pub const FROM_LEFT_3RD_BUTTON_PRESSED: DWORD = 0x0008; +pub const FROM_LEFT_4TH_BUTTON_PRESSED: DWORD = 0x0010; +pub const MOUSE_MOVED: DWORD = 0x0001; +pub const DOUBLE_CLICK: DWORD = 0x0002; +pub const MOUSE_WHEELED: DWORD = 0x0004; +pub const MOUSE_HWHEELED: DWORD = 0x0008; +STRUCT!{struct WINDOW_BUFFER_SIZE_RECORD { + dwSize: COORD, +}} +pub type PWINDOW_BUFFER_SIZE_RECORD = *mut WINDOW_BUFFER_SIZE_RECORD; +STRUCT!{struct MENU_EVENT_RECORD { + dwCommandId: UINT, +}} +pub type PMENU_EVENT_RECORD = *mut MENU_EVENT_RECORD; +STRUCT!{struct FOCUS_EVENT_RECORD { + bSetFocus: BOOL, +}} +pub type PFOCUS_EVENT_RECORD = *mut FOCUS_EVENT_RECORD; +UNION!{union INPUT_RECORD_Event { + [u32; 4], + KeyEvent KeyEvent_mut: KEY_EVENT_RECORD, + MouseEvent MouseEvent_mut: MOUSE_EVENT_RECORD, + WindowBufferSizeEvent WindowBufferSizeEvent_mut: WINDOW_BUFFER_SIZE_RECORD, + MenuEvent MenuEvent_mut: MENU_EVENT_RECORD, + FocusEvent FocusEvent_mut: FOCUS_EVENT_RECORD, +}} +STRUCT!{struct INPUT_RECORD { + EventType: WORD, + Event: INPUT_RECORD_Event, +}} +pub type PINPUT_RECORD = *mut INPUT_RECORD; +pub const KEY_EVENT: WORD = 0x0001; +pub const MOUSE_EVENT: WORD = 0x0002; +pub const WINDOW_BUFFER_SIZE_EVENT: WORD = 0x0004; +pub const MENU_EVENT: WORD = 0x0008; +pub const FOCUS_EVENT: WORD = 0x0010; +UNION!{union CHAR_INFO_Char { + [u16; 1], + UnicodeChar UnicodeChar_mut: WCHAR, + AsciiChar AsciiChar_mut: CHAR, +}} +STRUCT!{struct CHAR_INFO { + Char: CHAR_INFO_Char, + Attributes: WORD, +}} +pub type PCHAR_INFO = *mut CHAR_INFO; +STRUCT!{struct CONSOLE_FONT_INFO { + nFont: DWORD, + dwFontSize: COORD, +}} +pub type PCONSOLE_FONT_INFO = *mut CONSOLE_FONT_INFO; +pub type HPCON = *mut c_void; diff --git a/winapi/src/um/wincred.rs b/winapi/src/um/wincred.rs new file mode 100644 index 000000000..660837e73 --- /dev/null +++ b/winapi/src/um/wincred.rs @@ -0,0 +1,532 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Authentication API Prototypes and Definitions +use shared::minwindef::{ + BOOL, DWORD, FILETIME, LPBYTE, LPCVOID, LPDWORD, LPVOID, PBOOL, PBYTE, UCHAR, ULONG +}; +use shared::windef::{HBITMAP, HWND}; +use um::sspi::PCtxtHandle; +use um::winnt::{CHAR, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCSTR, PCWSTR, PSTR, PVOID, PWSTR, WCHAR}; +// STATUS_* +pub const NERR_BASE: DWORD = 2100; +pub const NERR_PasswordExpired: DWORD = NERR_BASE + 142; +pub const CRED_MAX_STRING_LENGTH: DWORD = 256; +pub const CRED_MAX_USERNAME_LENGTH: DWORD = 256 + 1 + 256; +pub const CRED_MAX_GENERIC_TARGET_NAME_LENGTH: DWORD = 32767; +pub const CRED_MAX_DOMAIN_TARGET_NAME_LENGTH: DWORD = 256 + 1 + 80; +pub const CRED_MAX_TARGETNAME_NAMESPACE_LENGTH: DWORD = 256; +pub const CRED_MAX_TARGETNAME_ATTRIBUTE_LENGTH: DWORD = 256; +pub const CRED_MAX_VALUE_SIZE: DWORD = 256; +pub const CRED_MAX_ATTRIBUTES: DWORD = 64; +STRUCT!{struct CREDENTIAL_ATTRIBUTEA { + Keyword: LPSTR, + Flags: DWORD, + ValueSize: DWORD, + Value: LPBYTE, +}} +pub type PCREDENTIAL_ATTRIBUTEA = *mut CREDENTIAL_ATTRIBUTEA; +STRUCT!{struct CREDENTIAL_ATTRIBUTEW { + Keyword: LPWSTR, + Flags: DWORD, + ValueSize: DWORD, + Value: LPBYTE, +}} +pub type PCREDENTIAL_ATTRIBUTEW = *mut CREDENTIAL_ATTRIBUTEW; +pub const CRED_LOGON_TYPES_MASK: DWORD = 0xF000; +pub const CRED_FLAGS_PASSWORD_FOR_CERT: DWORD = 0x0001; +pub const CRED_FLAGS_PROMPT_NOW: DWORD = 0x0002; +pub const CRED_FLAGS_USERNAME_TARGET: DWORD = 0x0004; +pub const CRED_FLAGS_OWF_CRED_BLOB: DWORD = 0x0008; +pub const CRED_FLAGS_REQUIRE_CONFIRMATION: DWORD = 0x0010; +pub const CRED_FLAGS_WILDCARD_MATCH: DWORD = 0x0020; +pub const CRED_FLAGS_VALID_FLAGS: DWORD = 0xF03F; +pub const CRED_FLAGS_VALID_INPUT_FLAGS: DWORD = 0xF01F; +pub const CRED_TYPE_GENERIC: DWORD = 1; +pub const CRED_TYPE_DOMAIN_PASSWORD: DWORD = 2; +pub const CRED_TYPE_DOMAIN_CERTIFICATE: DWORD = 3; +pub const CRED_TYPE_DOMAIN_VISIBLE_PASSWORD: DWORD = 4; +pub const CRED_TYPE_GENERIC_CERTIFICATE: DWORD = 5; +pub const CRED_TYPE_DOMAIN_EXTENDED: DWORD = 6; +pub const CRED_TYPE_MAXIMUM: DWORD = 7; +pub const CRED_TYPE_MAXIMUM_EX: DWORD = CRED_TYPE_MAXIMUM + 1000; +pub const CRED_MAX_CREDENTIAL_BLOB_SIZE: DWORD = 5 * 512; +pub const CRED_PERSIST_NONE: DWORD = 0; +pub const CRED_PERSIST_SESSION: DWORD = 1; +pub const CRED_PERSIST_LOCAL_MACHINE: DWORD = 2; +pub const CRED_PERSIST_ENTERPRISE: DWORD = 3; +STRUCT!{struct CREDENTIALA { + Flags: DWORD, + Type: DWORD, + TargetName: LPSTR, + Comment: LPSTR, + LastWritten: FILETIME, + CredentialBlobSize: DWORD, + CredentialBlob: LPBYTE, + Persist: DWORD, + AttributeCount: DWORD, + Attributes: PCREDENTIAL_ATTRIBUTEA, + TargetAlias: LPSTR, + UserName: LPSTR, +}} +pub type PCREDENTIALA = *mut CREDENTIALA; +STRUCT!{struct CREDENTIALW { + Flags: DWORD, + Type: DWORD, + TargetName: LPWSTR, + Comment: LPWSTR, + LastWritten: FILETIME, + CredentialBlobSize: DWORD, + CredentialBlob: LPBYTE, + Persist: DWORD, + AttributeCount: DWORD, + Attributes: PCREDENTIAL_ATTRIBUTEW, + TargetAlias: LPWSTR, + UserName: LPWSTR, +}} +pub type PCREDENTIALW = *mut CREDENTIALW; +pub const CRED_TI_SERVER_FORMAT_UNKNOWN: ULONG = 0x0001; +pub const CRED_TI_DOMAIN_FORMAT_UNKNOWN: ULONG = 0x0002; +pub const CRED_TI_ONLY_PASSWORD_REQUIRED: ULONG = 0x0004; +pub const CRED_TI_USERNAME_TARGET: ULONG = 0x0008; +pub const CRED_TI_CREATE_EXPLICIT_CRED: ULONG = 0x0010; +pub const CRED_TI_WORKGROUP_MEMBER: ULONG = 0x0020; +pub const CRED_TI_VALID_FLAGS: ULONG = 0xF07F; +STRUCT!{struct CREDENTIAL_TARGET_INFORMATIONA { + TargetName: LPSTR, + NetbiosServerName: LPSTR, + DnsServerName: LPSTR, + NetbiosDomainName: LPSTR, + DnsDomainName: LPSTR, + DnsTreeName: LPSTR, + PackageName: LPSTR, + Flags: ULONG, + CredTypeCount: DWORD, + CredTypes: LPDWORD, +}} +pub type PCREDENTIAL_TARGET_INFORMATIONA = *mut CREDENTIAL_TARGET_INFORMATIONA; +STRUCT!{struct CREDENTIAL_TARGET_INFORMATIONW { + TargetName: LPWSTR, + NetbiosServerName: LPWSTR, + DnsServerName: LPWSTR, + NetbiosDomainName: LPWSTR, + DnsDomainName: LPWSTR, + DnsTreeName: LPWSTR, + PackageName: LPWSTR, + Flags: ULONG, + CredTypeCount: DWORD, + CredTypes: LPDWORD, +}} +pub type PCREDENTIAL_TARGET_INFORMATIONW = *mut CREDENTIAL_TARGET_INFORMATIONW; +pub const CERT_HASH_LENGTH: usize = 20; +STRUCT!{struct CERT_CREDENTIAL_INFO { + cbSize: ULONG, + rgbHashOfCert: [UCHAR; CERT_HASH_LENGTH], +}} +pub type PCERT_CREDENTIAL_INFO = *mut CERT_CREDENTIAL_INFO; +STRUCT!{struct USERNAME_TARGET_CREDENTIAL_INFO { + UserName: LPWSTR, +}} +pub type PUSERNAME_TARGET_CREDENTIAL_INFO = *mut USERNAME_TARGET_CREDENTIAL_INFO; +STRUCT!{struct BINARY_BLOB_CREDENTIAL_INFO { + cbBlob: ULONG, + pbBlob: LPBYTE, +}} +pub type PBINARY_BLOB_CREDENTIAL_INFO = *mut BINARY_BLOB_CREDENTIAL_INFO; +ENUM!{enum CRED_MARSHAL_TYPE { + CertCredential = 1, + UsernameTargetCredential, + BinaryBlobCredential, + UsernameForPackedCredentials, +}} +pub type PCRED_MARSHAL_TYPE = *mut CRED_MARSHAL_TYPE; +ENUM!{enum CRED_PROTECTION_TYPE { + CredUnprotected, + CredUserProtection, + CredTrustedProtection, +}} +pub type PCRED_PROTECTION_TYPE = *mut CRED_PROTECTION_TYPE; +pub const CRED_PACK_PROTECTED_CREDENTIALS: DWORD = 0x1; +pub const CRED_PACK_WOW_BUFFER: DWORD = 0x2; +pub const CRED_PACK_GENERIC_CREDENTIALS: DWORD = 0x4; +pub const CRED_PACK_ID_PROVIDER_CREDENTIALS: DWORD = 0x8; +STRUCT!{struct CREDUI_INFOA { + cbSize: DWORD, + hwndParent: HWND, + pszMessageText: PCSTR, + pszCaptionText: PCSTR, + hbmBanner: HBITMAP, +}} +pub type PCREDUI_INFOA = *mut CREDUI_INFOA; +STRUCT!{struct CREDUI_INFOW { + cbSize: DWORD, + hwndParent: HWND, + pszMessageText: PCWSTR, + pszCaptionText: PCWSTR, + hbmBanner: HBITMAP, +}} +pub type PCREDUI_INFOW = *mut CREDUI_INFOW; +pub const CREDUI_MAX_MESSAGE_LENGTH: DWORD = 1024; +pub const CREDUI_MAX_CAPTION_LENGTH: DWORD = 128; +pub const CREDUI_MAX_GENERIC_TARGET_LENGTH: DWORD = CRED_MAX_GENERIC_TARGET_NAME_LENGTH; +pub const CREDUI_MAX_DOMAIN_TARGET_LENGTH: DWORD = CRED_MAX_DOMAIN_TARGET_NAME_LENGTH; +pub const CREDUI_MAX_USERNAME_LENGTH: DWORD = CRED_MAX_USERNAME_LENGTH; +pub const CREDUI_MAX_PASSWORD_LENGTH: DWORD = 512 / 2; +pub const CREDUI_FLAGS_INCORRECT_PASSWORD: DWORD = 0x00001; +pub const CREDUI_FLAGS_DO_NOT_PERSIST: DWORD = 0x00002; +pub const CREDUI_FLAGS_REQUEST_ADMINISTRATOR: DWORD = 0x00004; +pub const CREDUI_FLAGS_EXCLUDE_CERTIFICATES: DWORD = 0x00008; +pub const CREDUI_FLAGS_REQUIRE_CERTIFICATE: DWORD = 0x00010; +pub const CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX: DWORD = 0x00040; +pub const CREDUI_FLAGS_ALWAYS_SHOW_UI: DWORD = 0x00080; +pub const CREDUI_FLAGS_REQUIRE_SMARTCARD: DWORD = 0x00100; +pub const CREDUI_FLAGS_PASSWORD_ONLY_OK: DWORD = 0x00200; +pub const CREDUI_FLAGS_VALIDATE_USERNAME: DWORD = 0x00400; +pub const CREDUI_FLAGS_COMPLETE_USERNAME: DWORD = 0x00800; +pub const CREDUI_FLAGS_PERSIST: DWORD = 0x01000; +pub const CREDUI_FLAGS_SERVER_CREDENTIAL: DWORD = 0x04000; +pub const CREDUI_FLAGS_EXPECT_CONFIRMATION: DWORD = 0x20000; +pub const CREDUI_FLAGS_GENERIC_CREDENTIALS: DWORD = 0x40000; +pub const CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS: DWORD = 0x80000; +pub const CREDUI_FLAGS_KEEP_USERNAME: DWORD = 0x100000; +pub const CREDUI_FLAGS_PROMPT_VALID: DWORD = CREDUI_FLAGS_INCORRECT_PASSWORD + | CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_REQUEST_ADMINISTRATOR + | CREDUI_FLAGS_EXCLUDE_CERTIFICATES | CREDUI_FLAGS_REQUIRE_CERTIFICATE + | CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX | CREDUI_FLAGS_ALWAYS_SHOW_UI + | CREDUI_FLAGS_REQUIRE_SMARTCARD | CREDUI_FLAGS_PASSWORD_ONLY_OK + | CREDUI_FLAGS_VALIDATE_USERNAME | CREDUI_FLAGS_COMPLETE_USERNAME | CREDUI_FLAGS_PERSIST + | CREDUI_FLAGS_SERVER_CREDENTIAL | CREDUI_FLAGS_EXPECT_CONFIRMATION + | CREDUI_FLAGS_GENERIC_CREDENTIALS | CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS + | CREDUI_FLAGS_KEEP_USERNAME; +pub const CREDUIWIN_GENERIC: DWORD = 0x00000001; +pub const CREDUIWIN_CHECKBOX: DWORD = 0x00000002; +pub const CREDUIWIN_AUTHPACKAGE_ONLY: DWORD = 0x00000010; +pub const CREDUIWIN_IN_CRED_ONLY: DWORD = 0x00000020; +pub const CREDUIWIN_ENUMERATE_ADMINS: DWORD = 0x00000100; +pub const CREDUIWIN_ENUMERATE_CURRENT_USER: DWORD = 0x00000200; +pub const CREDUIWIN_SECURE_PROMPT: DWORD = 0x00001000; +pub const CREDUIWIN_PREPROMPTING: DWORD = 0x00002000; +pub const CREDUIWIN_PACK_32_WOW: DWORD = 0x10000000; +pub const CREDUIWIN_VALID_FLAGS: DWORD = CREDUIWIN_GENERIC | CREDUIWIN_CHECKBOX + | CREDUIWIN_AUTHPACKAGE_ONLY | CREDUIWIN_IN_CRED_ONLY | CREDUIWIN_ENUMERATE_ADMINS + | CREDUIWIN_ENUMERATE_CURRENT_USER | CREDUIWIN_SECURE_PROMPT | CREDUIWIN_PREPROMPTING + | CREDUIWIN_PACK_32_WOW; +pub const CRED_PRESERVE_CREDENTIAL_BLOB: DWORD = 0x1; +extern "system" { + pub fn CredWriteW( + Credential: PCREDENTIALW, + Flags: DWORD, + ) -> BOOL; + pub fn CredWriteA( + Credential: PCREDENTIALA, + Flags: DWORD, + ) -> BOOL; + pub fn CredReadW( + TargetName: LPCWSTR, + Type: DWORD, + Flags: DWORD, + Credential: *mut PCREDENTIALW, + ) -> BOOL; + pub fn CredReadA( + TargetName: LPCSTR, + Type: DWORD, + Flags: DWORD, + Credential: *mut PCREDENTIALA, + ) -> BOOL; +} +pub const CRED_ENUMERATE_ALL_CREDENTIALS: DWORD = 0x1; +extern "system" { + pub fn CredEnumerateW( + Filter: LPCWSTR, + Flags: DWORD, + Count: *mut DWORD, + Credential: *mut *mut PCREDENTIALW, + ) -> BOOL; + pub fn CredEnumerateA( + Filter: LPCSTR, + Flags: DWORD, + Count: *mut DWORD, + Credential: *mut *mut PCREDENTIALA, + ) -> BOOL; + pub fn CredWriteDomainCredentialsW( + TargetInfo: PCREDENTIAL_TARGET_INFORMATIONW, + Credential: PCREDENTIALW, + Flags: DWORD, + ) -> BOOL; + pub fn CredWriteDomainCredentialsA( + TargetInfo: PCREDENTIAL_TARGET_INFORMATIONA, + Credential: PCREDENTIALA, + Flags: DWORD, + ) -> BOOL; +} +pub const CRED_CACHE_TARGET_INFORMATION: DWORD = 0x1; +extern "system" { + pub fn CredReadDomainCredentialsW( + TargetInfo: PCREDENTIAL_TARGET_INFORMATIONW, + Flags: DWORD, + Count: *mut DWORD, + Credential: *mut *mut PCREDENTIALW, + ) -> BOOL; + pub fn CredReadDomainCredentialsA( + TargetInfo: PCREDENTIAL_TARGET_INFORMATIONA, + Flags: DWORD, + Count: *mut DWORD, + Credential: *mut *mut PCREDENTIALA, + ) -> BOOL; + pub fn CredDeleteW( + TargetName: LPCWSTR, + Type: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn CredDeleteA( + TargetName: LPCSTR, + Type: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn CredRenameW( + OldTargetName: LPCWSTR, + NewTargetName: LPCWSTR, + Type: DWORD, + Flags: DWORD, + ) -> BOOL; + pub fn CredRenameA( + OldTargetName: LPCSTR, + NewTargetName: LPCSTR, + Type: DWORD, + Flags: DWORD, + ) -> BOOL; +} +pub const CRED_ALLOW_NAME_RESOLUTION: DWORD = 0x1; +extern "system" { + pub fn CredGetTargetInfoW( + TargetName: LPCWSTR, + Flags: DWORD, + TargetInfo: *mut PCREDENTIAL_TARGET_INFORMATIONW, + ) -> BOOL; + pub fn CredGetTargetInfoA( + TargetName: LPCSTR, + Flags: DWORD, + TargetInfo: *mut PCREDENTIAL_TARGET_INFORMATIONA, + ) -> BOOL; + pub fn CredMarshalCredentialW( + CredType: CRED_MARSHAL_TYPE, + Credential: PVOID, + MarhaledCredential: *mut LPWSTR, + ) -> BOOL; + pub fn CredMarshalCredentialA( + CredType: CRED_MARSHAL_TYPE, + Credential: PVOID, + MarhaledCredential: *mut LPSTR, + ) -> BOOL; + pub fn CredUnmarshalCredentialW( + MarshaledCredential: LPCWSTR, + CredType: PCRED_MARSHAL_TYPE, + Credential: *mut PVOID, + ) -> BOOL; + pub fn CredUnmarshalCredentialA( + MarshaledCredential: LPCSTR, + CredType: PCRED_MARSHAL_TYPE, + Credential: *mut PVOID, + ) -> BOOL; + pub fn CredIsMarshaledCredentialW( + MarshaledCredential: LPCWSTR, + ) -> BOOL; + pub fn CredIsMarshaledCredentialA( + MarshaledCredential: LPCSTR, + ) -> BOOL; + pub fn CredUnPackAuthenticationBufferW( + dwFlags: DWORD, + pAuthBuffer: PVOID, + cbAuthBuffer: DWORD, + pszUserName: LPWSTR, + pcchlMaxUserName: *mut DWORD, + pszDomainName: LPWSTR, + pcchMaxDomainName: *mut DWORD, + pszPassword: LPWSTR, + pcchMaxPassword: *mut DWORD, + ) -> BOOL; + pub fn CredUnPackAuthenticationBufferA( + dwFlags: DWORD, + pAuthBuffer: PVOID, + cbAuthBuffer: DWORD, + pszUserName: LPSTR, + pcchlMaxUserName: *mut DWORD, + pszDomainName: LPSTR, + pcchMaxDomainName: *mut DWORD, + pszPassword: LPSTR, + pcchMaxPassword: *mut DWORD, + ) -> BOOL; + pub fn CredPackAuthenticationBufferW( + dwFlags: DWORD, + pszUserName: LPWSTR, + pszPassword: LPWSTR, + pPackedCredentials: PBYTE, + pcbPackedCredentials: *mut DWORD, + ) -> BOOL; + pub fn CredPackAuthenticationBufferA( + dwFlags: DWORD, + pszUserName: LPSTR, + pszPassword: LPSTR, + pPackedCredentials: PBYTE, + pcbPackedCredentials: *mut DWORD, + ) -> BOOL; + pub fn CredProtectW( + fAsSelf: BOOL, + pszCredentials: LPWSTR, + cchCredentials: DWORD, + pszProtectedCredentials: LPWSTR, + pcchMaxChars: *mut DWORD, + ProtectionType: *mut CRED_PROTECTION_TYPE, + ) -> BOOL; + pub fn CredProtectA( + fAsSelf: BOOL, + pszCredentials: LPSTR, + cchCredentials: DWORD, + pszProtectedCredentials: LPSTR, + pcchMaxChars: *mut DWORD, + ProtectionType: *mut CRED_PROTECTION_TYPE, + ) -> BOOL; + pub fn CredUnprotectW( + fAsSelf: BOOL, + pszProtectedCredentials: LPWSTR, + cchCredentials: DWORD, + pszCredentials: LPWSTR, + pcchMaxChars: *mut DWORD, + ) -> BOOL; + pub fn CredUnprotectA( + fAsSelf: BOOL, + pszProtectedCredentials: LPSTR, + cchCredentials: DWORD, + pszCredentials: LPSTR, + pcchMaxChars: *mut DWORD, + ) -> BOOL; + pub fn CredIsProtectedW( + pszProtectedCredentials: LPWSTR, + pProtectionType: *mut CRED_PROTECTION_TYPE, + ) -> BOOL; + pub fn CredIsProtectedA( + pszProtectedCredentials: LPSTR, + pProtectionType: *mut CRED_PROTECTION_TYPE, + ) -> BOOL; + pub fn CredFindBestCredentialW( + TargetName: LPCWSTR, + Type: DWORD, + Flags: DWORD, + Credential: *mut PCREDENTIALW, + ) -> BOOL; + pub fn CredFindBestCredentialA( + TargetName: LPCSTR, + Type: DWORD, + Flags: DWORD, + Credential: *mut PCREDENTIALA, + ) -> BOOL; + pub fn CredGetSessionTypes( + MaximumPersistCount: DWORD, + MaximumPersist: LPDWORD, + ) -> BOOL; + pub fn CredFree( + Buffer: PVOID, + ); + pub fn CredUIPromptForCredentialsW( + pUiInfo: PCREDUI_INFOW, + pszTargetName: PCWSTR, + pContext: PCtxtHandle, + dwAuthError: DWORD, + pszUserName: PWSTR, + ulUserNameBufferSize: ULONG, + pszPassword: PWSTR, + ulPasswordBufferSize: ULONG, + save: *mut BOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUIPromptForCredentialsA( + pUiInfo: PCREDUI_INFOA, + pszTargetName: PCSTR, + pContext: PCtxtHandle, + dwAuthError: DWORD, + pszUserName: PSTR, + ulUserNameBufferSize: ULONG, + pszPassword: PSTR, + ulPasswordBufferSize: ULONG, + save: *mut BOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUIPromptForWindowsCredentialsW( + pUiInfo: PCREDUI_INFOW, + dwAuthError: DWORD, + pulAuthPackage: *mut ULONG, + pvInAuthBuffer: LPCVOID, + ulInAuthBufferSize: ULONG, + ppvOutAuthBuffer: *mut LPVOID, + pulOutAuthBufferSize: *mut ULONG, + pfSave: *mut BOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUIPromptForWindowsCredentialsA( + pUiInfo: PCREDUI_INFOA, + dwAuthError: DWORD, + pulAuthPackage: *mut ULONG, + pvInAuthBuffer: LPCVOID, + ulInAuthBufferSize: ULONG, + ppvOutAuthBuffer: *mut LPVOID, + pulOutAuthBufferSize: *mut ULONG, + pfSave: *mut BOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUIParseUserNameW( + userName: PCWSTR, + user: *mut WCHAR, + userBufferSize: ULONG, + domain: *mut WCHAR, + domainBufferSize: ULONG, + ) -> DWORD; + pub fn CredUIParseUserNameA( + userName: PCSTR, + user: *mut CHAR, + userBufferSize: ULONG, + domain: *mut CHAR, + domainBufferSize: ULONG, + ) -> DWORD; + pub fn CredUICmdLinePromptForCredentialsW( + pszTargetName: PCWSTR, + pContext: PCtxtHandle, + dwAuthError: DWORD, + UserName: PWSTR, + ulUserBufferSize: ULONG, + pszPassword: PWSTR, + ulPasswordBufferSize: ULONG, + pfSave: PBOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUICmdLinePromptForCredentialsA( + pszTargetName: PCSTR, + pContext: PCtxtHandle, + dwAuthError: DWORD, + UserName: PSTR, + ulUserBufferSize: ULONG, + pszPassword: PSTR, + ulPasswordBufferSize: ULONG, + pfSave: PBOOL, + dwFlags: DWORD, + ) -> DWORD; + pub fn CredUIConfirmCredentialsW( + pszTargetName: PCWSTR, + bConfirm: BOOL, + ) -> DWORD; + pub fn CredUIConfirmCredentialsA( + pszTargetName: PCSTR, + bConfirm: BOOL, + ) -> DWORD; + pub fn CredUIStoreSSOCredW( + pszRealm: PCWSTR, + pszUsername: PCWSTR, + pszPassword: PCWSTR, + bPersist: BOOL, + ) -> DWORD; + pub fn CredUIReadSSOCredW( + pszRealm: PCWSTR, + ppszUsername: *mut PWSTR, + ) -> DWORD; +} diff --git a/winapi/src/um/wincrypt.rs b/winapi/src/um/wincrypt.rs new file mode 100644 index 000000000..abc2a9923 --- /dev/null +++ b/winapi/src/um/wincrypt.rs @@ -0,0 +1,7365 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Cryptographic API Prototypes and Definitions +use ctypes::{c_int, c_uchar, c_uint, c_void}; +use shared::basetsd::ULONG_PTR; +use shared::bcrypt::BCRYPT_KEY_HANDLE; +use shared::guiddef::{GUID, LPCGUID}; +use shared::minwindef::{ + BOOL, BYTE, DWORD, FALSE, FILETIME, HKEY, HMODULE, LPFILETIME, LPVOID, PBYTE, PDWORD, + PFILETIME, TRUE, ULONG, WORD, +}; +use um::minwinbase::PSYSTEMTIME; +use um::ncrypt::NCRYPT_KEY_HANDLE; +use um::winnt::{ + CHAR, HANDLE, HRESULT, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PCWSTR, PVOID, PWSTR, WCHAR, +}; +use vc::vcruntime::size_t; +//108 +#[inline] +pub fn GET_ALG_CLASS(x: ALG_ID) -> ALG_ID { + x & (7 << 13) +} +#[inline] +pub fn GET_ALG_TYPE(x: ALG_ID) -> ALG_ID { + x & (15 << 9) +} +#[inline] +pub fn GET_ALG_SID(x: ALG_ID) -> ALG_ID { + x & 511 +} +pub const ALG_CLASS_ANY: ALG_ID = 0; +pub const ALG_CLASS_SIGNATURE: ALG_ID = 1 << 13; +pub const ALG_CLASS_MSG_ENCRYPT: ALG_ID = 2 << 13; +pub const ALG_CLASS_DATA_ENCRYPT: ALG_ID = 3 << 13; +pub const ALG_CLASS_HASH: ALG_ID = 4 << 13; +pub const ALG_CLASS_KEY_EXCHANGE: ALG_ID = 5 << 13; +pub const ALG_CLASS_ALL: ALG_ID = 7 << 13; +pub const ALG_TYPE_ANY: ALG_ID = 0; +pub const ALG_TYPE_DSS: ALG_ID = 1 << 9; +pub const ALG_TYPE_RSA: ALG_ID = 2 << 9; +pub const ALG_TYPE_BLOCK: ALG_ID = 3 << 9; +pub const ALG_TYPE_STREAM: ALG_ID = 4 << 9; +pub const ALG_TYPE_DH: ALG_ID = 5 << 9; +pub const ALG_TYPE_SECURECHANNEL: ALG_ID = 6 << 9; +pub const ALG_TYPE_ECDH: ALG_ID = 7 << 9; +pub const ALG_TYPE_THIRDPARTY: ALG_ID = 8 << 9; +pub const ALG_SID_ANY: ALG_ID = 0; +pub const ALG_SID_THIRDPARTY_ANY: ALG_ID = 0; +pub const ALG_SID_RSA_ANY: ALG_ID = 0; +pub const ALG_SID_RSA_PKCS: ALG_ID = 1; +pub const ALG_SID_RSA_MSATWORK: ALG_ID = 2; +pub const ALG_SID_RSA_ENTRUST: ALG_ID = 3; +pub const ALG_SID_RSA_PGP: ALG_ID = 4; +pub const ALG_SID_DSS_ANY: ALG_ID = 0; +pub const ALG_SID_DSS_PKCS: ALG_ID = 1; +pub const ALG_SID_DSS_DMS: ALG_ID = 2; +pub const ALG_SID_ECDSA: ALG_ID = 3; +pub const ALG_SID_DES: ALG_ID = 1; +pub const ALG_SID_3DES: ALG_ID = 3; +pub const ALG_SID_DESX: ALG_ID = 4; +pub const ALG_SID_IDEA: ALG_ID = 5; +pub const ALG_SID_CAST: ALG_ID = 6; +pub const ALG_SID_SAFERSK64: ALG_ID = 7; +pub const ALG_SID_SAFERSK128: ALG_ID = 8; +pub const ALG_SID_3DES_112: ALG_ID = 9; +pub const ALG_SID_CYLINK_MEK: ALG_ID = 12; +pub const ALG_SID_RC5: ALG_ID = 13; +pub const ALG_SID_AES_128: ALG_ID = 14; +pub const ALG_SID_AES_192: ALG_ID = 15; +pub const ALG_SID_AES_256: ALG_ID = 16; +pub const ALG_SID_AES: ALG_ID = 17; +pub const ALG_SID_SKIPJACK: ALG_ID = 10; +pub const ALG_SID_TEK: ALG_ID = 11; +pub const CRYPT_MODE_CBCI: ALG_ID = 6; +pub const CRYPT_MODE_CFBP: ALG_ID = 7; +pub const CRYPT_MODE_OFBP: ALG_ID = 8; +pub const CRYPT_MODE_CBCOFM: ALG_ID = 9; +pub const CRYPT_MODE_CBCOFMI: ALG_ID = 10; +pub const ALG_SID_RC2: ALG_ID = 2; +pub const ALG_SID_RC4: ALG_ID = 1; +pub const ALG_SID_SEAL: ALG_ID = 2; +pub const ALG_SID_DH_SANDF: ALG_ID = 1; +pub const ALG_SID_DH_EPHEM: ALG_ID = 2; +pub const ALG_SID_AGREED_KEY_ANY: ALG_ID = 3; +pub const ALG_SID_KEA: ALG_ID = 4; +pub const ALG_SID_ECDH: ALG_ID = 5; +pub const ALG_SID_ECDH_EPHEM: ALG_ID = 6; +pub const ALG_SID_MD2: ALG_ID = 1; +pub const ALG_SID_MD4: ALG_ID = 2; +pub const ALG_SID_MD5: ALG_ID = 3; +pub const ALG_SID_SHA: ALG_ID = 4; +pub const ALG_SID_SHA1: ALG_ID = 4; +pub const ALG_SID_MAC: ALG_ID = 5; +pub const ALG_SID_RIPEMD: ALG_ID = 6; +pub const ALG_SID_RIPEMD160: ALG_ID = 7; +pub const ALG_SID_SSL3SHAMD5: ALG_ID = 8; +pub const ALG_SID_HMAC: ALG_ID = 9; +pub const ALG_SID_TLS1PRF: ALG_ID = 10; +pub const ALG_SID_HASH_REPLACE_OWF: ALG_ID = 11; +pub const ALG_SID_SHA_256: ALG_ID = 12; +pub const ALG_SID_SHA_384: ALG_ID = 13; +pub const ALG_SID_SHA_512: ALG_ID = 14; +pub const ALG_SID_SSL3_MASTER: ALG_ID = 1; +pub const ALG_SID_SCHANNEL_MASTER_HASH: ALG_ID = 2; +pub const ALG_SID_SCHANNEL_MAC_KEY: ALG_ID = 3; +pub const ALG_SID_PCT1_MASTER: ALG_ID = 4; +pub const ALG_SID_SSL2_MASTER: ALG_ID = 5; +pub const ALG_SID_TLS1_MASTER: ALG_ID = 6; +pub const ALG_SID_SCHANNEL_ENC_KEY: ALG_ID = 7; +pub const ALG_SID_ECMQV: ALG_ID = 1; +pub const ALG_SID_EXAMPLE: ALG_ID = 80; +pub type ALG_ID = c_uint; +pub const CALG_MD2: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2; +pub const CALG_MD4: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4; +pub const CALG_MD5: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5; +pub const CALG_SHA: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA; +pub const CALG_SHA1: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1; +pub const CALG_MAC: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MAC; +pub const CALG_RSA_SIGN: ALG_ID = ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY; +pub const CALG_DSS_SIGN: ALG_ID = ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY; +pub const CALG_NO_SIGN: ALG_ID = ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY; +pub const CALG_RSA_KEYX: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY; +pub const CALG_DES: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DES; +pub const CALG_3DES_112: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES_112; +pub const CALG_3DES: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES; +pub const CALG_DESX: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DESX; +pub const CALG_RC2: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC2; +pub const CALG_RC4: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_RC4; +pub const CALG_SEAL: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_SEAL; +pub const CALG_DH_SF: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_SANDF; +pub const CALG_DH_EPHEM: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EPHEM; +pub const CALG_AGREEDKEY_ANY: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH + | ALG_SID_AGREED_KEY_ANY; +pub const CALG_KEA_KEYX: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_KEA; +pub const CALG_HUGHES_MD5: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_MD5; +pub const CALG_SKIPJACK: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_SKIPJACK; +pub const CALG_TEK: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_TEK; +pub const CALG_CYLINK_MEK: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_CYLINK_MEK; +pub const CALG_SSL3_SHAMD5: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5; +pub const CALG_SSL3_MASTER: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_SSL3_MASTER; +pub const CALG_SCHANNEL_MASTER_HASH: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_SCHANNEL_MASTER_HASH; +pub const CALG_SCHANNEL_MAC_KEY: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_SCHANNEL_MAC_KEY; +pub const CALG_SCHANNEL_ENC_KEY: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_SCHANNEL_ENC_KEY; +pub const CALG_PCT1_MASTER: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_PCT1_MASTER; +pub const CALG_SSL2_MASTER: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_SSL2_MASTER; +pub const CALG_TLS1_MASTER: ALG_ID = ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL + | ALG_SID_TLS1_MASTER; +pub const CALG_RC5: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC5; +pub const CALG_HMAC: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC; +pub const CALG_TLS1PRF: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF; +pub const CALG_HASH_REPLACE_OWF: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF; +pub const CALG_AES_128: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_128; +pub const CALG_AES_192: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_192; +pub const CALG_AES_256: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256; +pub const CALG_AES: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES; +pub const CALG_SHA_256: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256; +pub const CALG_SHA_384: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384; +pub const CALG_SHA_512: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512; +pub const CALG_ECDH: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH; +pub const CALG_ECDH_EPHEM: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ECDH | ALG_SID_ECDH_EPHEM; +pub const CALG_ECMQV: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV; +pub const CALG_ECDSA: ALG_ID = ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA; +pub const CALG_NULLCIPHER: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_ANY | 0; +pub const CALG_THIRDPARTY_KEY_EXCHANGE: ALG_ID = ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_THIRDPARTY + | ALG_SID_THIRDPARTY_ANY; +pub const CALG_THIRDPARTY_SIGNATURE: ALG_ID = ALG_CLASS_SIGNATURE | ALG_TYPE_THIRDPARTY + | ALG_SID_THIRDPARTY_ANY; +pub const CALG_THIRDPARTY_CIPHER: ALG_ID = ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_THIRDPARTY + | ALG_SID_THIRDPARTY_ANY; +pub const CALG_THIRDPARTY_HASH: ALG_ID = ALG_CLASS_HASH | ALG_TYPE_THIRDPARTY + | ALG_SID_THIRDPARTY_ANY; +pub type HCRYPTPROV = ULONG_PTR; +pub type HCRYPTKEY = ULONG_PTR; +pub type HCRYPTHASH = ULONG_PTR; +pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; +pub const CRYPT_NEWKEYSET: DWORD = 0x00000008; +pub const CRYPT_DELETEKEYSET: DWORD = 0x00000010; +pub const CRYPT_MACHINE_KEYSET: DWORD = 0x00000020; +pub const CRYPT_SILENT: DWORD = 0x00000040; +pub const CRYPT_DEFAULT_CONTAINER_OPTIONAL: DWORD = 0x00000080; +pub const CRYPT_EXPORTABLE: DWORD = 0x00000001; +pub const CRYPT_USER_PROTECTED: DWORD = 0x00000002; +pub const CRYPT_CREATE_SALT: DWORD = 0x00000004; +pub const CRYPT_UPDATE_KEY: DWORD = 0x00000008; +pub const CRYPT_NO_SALT: DWORD = 0x00000010; +pub const CRYPT_PREGEN: DWORD = 0x00000040; +pub const CRYPT_RECIPIENT: DWORD = 0x00000010; +pub const CRYPT_INITIATOR: DWORD = 0x00000040; +pub const CRYPT_ONLINE: DWORD = 0x00000080; +pub const CRYPT_SF: DWORD = 0x00000100; +pub const CRYPT_CREATE_IV: DWORD = 0x00000200; +pub const CRYPT_KEK: DWORD = 0x00000400; +pub const CRYPT_DATA_KEY: DWORD = 0x00000800; +pub const CRYPT_VOLATILE: DWORD = 0x00001000; +pub const CRYPT_SGCKEY: DWORD = 0x00002000; +pub const CRYPT_USER_PROTECTED_STRONG: DWORD = 0x00100000; +pub const CRYPT_ARCHIVABLE: DWORD = 0x00004000; +pub const CRYPT_FORCE_KEY_PROTECTION_HIGH: DWORD = 0x00008000; +pub const RSA1024BIT_KEY: DWORD = 0x04000000; +pub const CRYPT_SERVER: DWORD = 0x00000400; +pub const KEY_LENGTH_MASK: DWORD = 0xFFFF0000; +pub const CRYPT_Y_ONLY: DWORD = 0x00000001; +pub const CRYPT_SSL2_FALLBACK: DWORD = 0x00000002; +pub const CRYPT_DESTROYKEY: DWORD = 0x00000004; +pub const CRYPT_OAEP: DWORD = 0x00000040; +pub const CRYPT_BLOB_VER3: DWORD = 0x00000080; +pub const CRYPT_IPSEC_HMAC_KEY: DWORD = 0x00000100; +pub const CRYPT_DECRYPT_RSA_NO_PADDING_CHECK: DWORD = 0x00000020; +pub const CRYPT_SECRETDIGEST: DWORD = 0x00000001; +pub const CRYPT_OWF_REPL_LM_HASH: DWORD = 0x00000001; +pub const CRYPT_LITTLE_ENDIAN: DWORD = 0x00000001; +pub const CRYPT_NOHASHOID: DWORD = 0x00000001; +pub const CRYPT_TYPE2_FORMAT: DWORD = 0x00000002; +pub const CRYPT_X931_FORMAT: DWORD = 0x00000004; +pub const CRYPT_MACHINE_DEFAULT: DWORD = 0x00000001; +pub const CRYPT_USER_DEFAULT: DWORD = 0x00000002; +pub const CRYPT_DELETE_DEFAULT: DWORD = 0x00000004; +pub const SIMPLEBLOB: DWORD = 0x1; +pub const PUBLICKEYBLOB: DWORD = 0x6; +pub const PRIVATEKEYBLOB: DWORD = 0x7; +pub const PLAINTEXTKEYBLOB: DWORD = 0x8; +pub const OPAQUEKEYBLOB: DWORD = 0x9; +pub const PUBLICKEYBLOBEX: DWORD = 0xA; +pub const SYMMETRICWRAPKEYBLOB: DWORD = 0xB; +pub const KEYSTATEBLOB: DWORD = 0xC; +pub const AT_KEYEXCHANGE: DWORD = 1; +pub const AT_SIGNATURE: DWORD = 2; +pub const CRYPT_USERDATA: DWORD = 1; +pub const KP_IV: DWORD = 1; +pub const KP_SALT: DWORD = 2; +pub const KP_PADDING: DWORD = 3; +pub const KP_MODE: DWORD = 4; +pub const KP_MODE_BITS: DWORD = 5; +pub const KP_PERMISSIONS: DWORD = 6; +pub const KP_ALGID: DWORD = 7; +pub const KP_BLOCKLEN: DWORD = 8; +pub const KP_KEYLEN: DWORD = 9; +pub const KP_SALT_EX: DWORD = 10; +pub const KP_P: DWORD = 11; +pub const KP_G: DWORD = 12; +pub const KP_Q: DWORD = 13; +pub const KP_X: DWORD = 14; +pub const KP_Y: DWORD = 15; +pub const KP_RA: DWORD = 16; +pub const KP_RB: DWORD = 17; +pub const KP_INFO: DWORD = 18; +pub const KP_EFFECTIVE_KEYLEN: DWORD = 19; +pub const KP_SCHANNEL_ALG: DWORD = 20; +pub const KP_CLIENT_RANDOM: DWORD = 21; +pub const KP_SERVER_RANDOM: DWORD = 22; +pub const KP_RP: DWORD = 23; +pub const KP_PRECOMP_MD5: DWORD = 24; +pub const KP_PRECOMP_SHA: DWORD = 25; +pub const KP_CERTIFICATE: DWORD = 26; +pub const KP_CLEAR_KEY: DWORD = 27; +pub const KP_PUB_EX_LEN: DWORD = 28; +pub const KP_PUB_EX_VAL: DWORD = 29; +pub const KP_KEYVAL: DWORD = 30; +pub const KP_ADMIN_PIN: DWORD = 31; +pub const KP_KEYEXCHANGE_PIN: DWORD = 32; +pub const KP_SIGNATURE_PIN: DWORD = 33; +pub const KP_PREHASH: DWORD = 34; +pub const KP_ROUNDS: DWORD = 35; +pub const KP_OAEP_PARAMS: DWORD = 36; +pub const KP_CMS_KEY_INFO: DWORD = 37; +pub const KP_CMS_DH_KEY_INFO: DWORD = 38; +pub const KP_PUB_PARAMS: DWORD = 39; +pub const KP_VERIFY_PARAMS: DWORD = 40; +pub const KP_HIGHEST_VERSION: DWORD = 41; +pub const KP_GET_USE_COUNT: DWORD = 42; +pub const KP_PIN_ID: DWORD = 43; +pub const KP_PIN_INFO: DWORD = 44; +pub const PKCS5_PADDING: DWORD = 1; +pub const RANDOM_PADDING: DWORD = 2; +pub const ZERO_PADDING: DWORD = 3; +pub const CRYPT_MODE_CBC: DWORD = 1; +pub const CRYPT_MODE_ECB: DWORD = 2; +pub const CRYPT_MODE_OFB: DWORD = 3; +pub const CRYPT_MODE_CFB: DWORD = 4; +pub const CRYPT_MODE_CTS: DWORD = 5; +pub const CRYPT_ENCRYPT: DWORD = 0x0001; +pub const CRYPT_DECRYPT: DWORD = 0x0002; +pub const CRYPT_EXPORT: DWORD = 0x0004; +pub const CRYPT_READ: DWORD = 0x0008; +pub const CRYPT_WRITE: DWORD = 0x0010; +pub const CRYPT_MAC: DWORD = 0x0020; +pub const CRYPT_EXPORT_KEY: DWORD = 0x0040; +pub const CRYPT_IMPORT_KEY: DWORD = 0x0080; +pub const CRYPT_ARCHIVE: DWORD = 0x0100; +pub const HP_ALGID: DWORD = 0x0001; +pub const HP_HASHVAL: DWORD = 0x0002; +pub const HP_HASHSIZE: DWORD = 0x0004; +pub const HP_HMAC_INFO: DWORD = 0x0005; +pub const HP_TLS1PRF_LABEL: DWORD = 0x0006; +pub const HP_TLS1PRF_SEED: DWORD = 0x0007; +pub const CRYPT_FAILED: BOOL = FALSE; +pub const CRYPT_SUCCEED: BOOL = TRUE; +#[inline] +pub fn RCRYPT_SUCCEEDED(rt: BOOL) -> bool { + rt == CRYPT_SUCCEED +} +#[inline] +pub fn RCRYPT_FAILED(rt: BOOL) -> bool { + rt == CRYPT_FAILED +} +pub const PP_ENUMALGS: DWORD = 1; +pub const PP_ENUMCONTAINERS: DWORD = 2; +pub const PP_IMPTYPE: DWORD = 3; +pub const PP_NAME: DWORD = 4; +pub const PP_VERSION: DWORD = 5; +pub const PP_CONTAINER: DWORD = 6; +pub const PP_CHANGE_PASSWORD: DWORD = 7; +pub const PP_KEYSET_SEC_DESCR: DWORD = 8; +pub const PP_CERTCHAIN: DWORD = 9; +pub const PP_KEY_TYPE_SUBTYPE: DWORD = 10; +pub const PP_PROVTYPE: DWORD = 16; +pub const PP_KEYSTORAGE: DWORD = 17; +pub const PP_APPLI_CERT: DWORD = 18; +pub const PP_SYM_KEYSIZE: DWORD = 19; +pub const PP_SESSION_KEYSIZE: DWORD = 20; +pub const PP_UI_PROMPT: DWORD = 21; +pub const PP_ENUMALGS_EX: DWORD = 22; +pub const PP_ENUMMANDROOTS: DWORD = 25; +pub const PP_ENUMELECTROOTS: DWORD = 26; +pub const PP_KEYSET_TYPE: DWORD = 27; +pub const PP_ADMIN_PIN: DWORD = 31; +pub const PP_KEYEXCHANGE_PIN: DWORD = 32; +pub const PP_SIGNATURE_PIN: DWORD = 33; +pub const PP_SIG_KEYSIZE_INC: DWORD = 34; +pub const PP_KEYX_KEYSIZE_INC: DWORD = 35; +pub const PP_UNIQUE_CONTAINER: DWORD = 36; +pub const PP_SGC_INFO: DWORD = 37; +pub const PP_USE_HARDWARE_RNG: DWORD = 38; +pub const PP_KEYSPEC: DWORD = 39; +pub const PP_ENUMEX_SIGNING_PROT: DWORD = 40; +pub const PP_CRYPT_COUNT_KEY_USE: DWORD = 41; +pub const PP_USER_CERTSTORE: DWORD = 42; +pub const PP_SMARTCARD_READER: DWORD = 43; +pub const PP_SMARTCARD_GUID: DWORD = 45; +pub const PP_ROOT_CERTSTORE: DWORD = 46; +pub const PP_SMARTCARD_READER_ICON: DWORD = 47; +pub const CRYPT_FIRST: DWORD = 1; +pub const CRYPT_NEXT: DWORD = 2; +pub const CRYPT_SGC_ENUM: DWORD = 4; +pub const CRYPT_IMPL_HARDWARE: DWORD = 1; +pub const CRYPT_IMPL_SOFTWARE: DWORD = 2; +pub const CRYPT_IMPL_MIXED: DWORD = 3; +pub const CRYPT_IMPL_UNKNOWN: DWORD = 4; +pub const CRYPT_IMPL_REMOVABLE: DWORD = 8; +pub const CRYPT_SEC_DESCR: DWORD = 0x00000001; +pub const CRYPT_PSTORE: DWORD = 0x00000002; +pub const CRYPT_UI_PROMPT: DWORD = 0x00000004; +pub const CRYPT_FLAG_PCT1: DWORD = 0x0001; +pub const CRYPT_FLAG_SSL2: DWORD = 0x0002; +pub const CRYPT_FLAG_SSL3: DWORD = 0x0004; +pub const CRYPT_FLAG_TLS1: DWORD = 0x0008; +pub const CRYPT_FLAG_IPSEC: DWORD = 0x0010; +pub const CRYPT_FLAG_SIGNING: DWORD = 0x0020; +pub const CRYPT_SGC: DWORD = 0x0001; +pub const CRYPT_FASTSGC: DWORD = 0x0002; +pub const PP_CLIENT_HWND: DWORD = 1; +pub const PP_CONTEXT_INFO: DWORD = 11; +pub const PP_KEYEXCHANGE_KEYSIZE: DWORD = 12; +pub const PP_SIGNATURE_KEYSIZE: DWORD = 13; +pub const PP_KEYEXCHANGE_ALG: DWORD = 14; +pub const PP_SIGNATURE_ALG: DWORD = 15; +pub const PP_DELETEKEY: DWORD = 24; +pub const PP_PIN_PROMPT_STRING: DWORD = 44; +pub const PP_SECURE_KEYEXCHANGE_PIN: DWORD = 47; +pub const PP_SECURE_SIGNATURE_PIN: DWORD = 48; +pub const PROV_RSA_FULL: DWORD = 1; +pub const PROV_RSA_SIG: DWORD = 2; +pub const PROV_DSS: DWORD = 3; +pub const PROV_FORTEZZA: DWORD = 4; +pub const PROV_MS_EXCHANGE: DWORD = 5; +pub const PROV_SSL: DWORD = 6; +pub const PROV_RSA_SCHANNEL: DWORD = 12; +pub const PROV_DSS_DH: DWORD = 13; +pub const PROV_EC_ECDSA_SIG: DWORD = 14; +pub const PROV_EC_ECNRA_SIG: DWORD = 15; +pub const PROV_EC_ECDSA_FULL: DWORD = 16; +pub const PROV_EC_ECNRA_FULL: DWORD = 17; +pub const PROV_DH_SCHANNEL: DWORD = 18; +pub const PROV_SPYRUS_LYNKS: DWORD = 20; +pub const PROV_RNG: DWORD = 21; +pub const PROV_INTEL_SEC: DWORD = 22; +pub const PROV_REPLACE_OWF: DWORD = 23; +pub const PROV_RSA_AES: DWORD = 24; +pub const MS_DEF_PROV: &'static str = "Microsoft Base Cryptographic Provider v1.0"; +pub const MS_ENHANCED_PROV: &'static str = "Microsoft Enhanced Cryptographic Provider v1.0"; +pub const MS_STRONG_PROV: &'static str = "Microsoft Strong Cryptographic Provider"; +pub const MS_DEF_RSA_SIG_PROV: &'static str = "Microsoft RSA Signature Cryptographic Provider"; +pub const MS_DEF_RSA_SCHANNEL_PROV: &'static str = "Microsoft RSA SChannel Cryptographic Provider"; +pub const MS_DEF_DSS_PROV: &'static str = "Microsoft Base DSS Cryptographic Provider"; +pub const MS_DEF_DSS_DH_PROV: &'static str + = "Microsoft Base DSS and Diffie-Hellman Cryptographic Provider"; +pub const MS_ENH_DSS_DH_PROV: &'static str + = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider"; +pub const MS_DEF_DH_SCHANNEL_PROV: &'static str = "Microsoft DH SChannel Cryptographic Provider"; +pub const MS_SCARD_PROV: &'static str = "Microsoft Base Smart Card Crypto Provider"; +pub const MS_ENH_RSA_AES_PROV: &'static str + = "Microsoft Enhanced RSA and AES Cryptographic Provider"; +pub const MS_ENH_RSA_AES_PROV_XP: &'static str + = "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"; +pub const MAXUIDLEN: usize = 64; +pub const EXPO_OFFLOAD_REG_VALUE: &'static str = "ExpoOffload"; +pub const EXPO_OFFLOAD_FUNC_NAME: &'static str = "OffloadModExpo"; +pub const szKEY_CRYPTOAPI_PRIVATE_KEY_OPTIONS: &'static str + = "Software\\Policies\\Microsoft\\Cryptography"; +pub const szKEY_CACHE_ENABLED: &'static str = "CachePrivateKeys"; +pub const szKEY_CACHE_SECONDS: &'static str = "PrivateKeyLifetimeSeconds"; +pub const szPRIV_KEY_CACHE_MAX_ITEMS: &'static str = "PrivKeyCacheMaxItems"; +pub const cPRIV_KEY_CACHE_MAX_ITEMS_DEFAULT: DWORD = 20; +pub const szPRIV_KEY_CACHE_PURGE_INTERVAL_SECONDS: &'static str + = "PrivKeyCachePurgeIntervalSeconds"; +pub const cPRIV_KEY_CACHE_PURGE_INTERVAL_SECONDS_DEFAULT: DWORD = 86400; +pub const CUR_BLOB_VERSION: DWORD = 2; +STRUCT!{struct CMS_KEY_INFO { + dwVersion: DWORD, + Algid: ALG_ID, + pbOID: *mut BYTE, + cbOID: DWORD, +}} +pub type PCMS_KEY_INFO = *mut CMS_KEY_INFO; +STRUCT!{struct HMAC_INFO { + HashAlgid: ALG_ID, + pbInnerString: *mut BYTE, + cbInnerString: DWORD, + pbOuterString: *mut BYTE, + cbOuterString: DWORD, +}} +pub type PHMAC_INFO = *mut HMAC_INFO; +STRUCT!{struct SCHANNEL_ALG { + dwUse: DWORD, + Algid: ALG_ID, + cBits: DWORD, + dwFlags: DWORD, + dwReserved: DWORD, +}} +pub type PSCHANNEL_ALG = *mut SCHANNEL_ALG; +pub const SCHANNEL_MAC_KEY: DWORD = 0x00000000; +pub const SCHANNEL_ENC_KEY: DWORD = 0x00000001; +pub const INTERNATIONAL_USAGE: DWORD = 0x00000001; +STRUCT!{struct PROV_ENUMALGS { + aiAlgid: ALG_ID, + dwBitLen: DWORD, + dwNameLen: DWORD, + szName: [CHAR; 20], +}} +STRUCT!{struct PROV_ENUMALGS_EX { + aiAlgid: ALG_ID, + dwDefaultLen: DWORD, + dwMinLen: DWORD, + dwMaxLen: DWORD, + dwProtocols: DWORD, + dwNameLen: DWORD, + szName: [CHAR; 20], + dwLongNameLen: DWORD, + szLongName: [CHAR; 40], +}} +STRUCT!{struct BLOBHEADER { + bType: BYTE, + bVersion: BYTE, + reserved: WORD, + aiKeyAlg: ALG_ID, +}} +pub type PUBLICKEYSTRUC = BLOBHEADER; +STRUCT!{struct RSAPUBKEY { + magic: DWORD, + bitlen: DWORD, + pubexp: DWORD, +}} +STRUCT!{struct DHPUBKEY { + magic: DWORD, + bitlen: DWORD, +}} +pub type DSSPUBKEY = DHPUBKEY; +pub type KEAPUBKEY = DHPUBKEY; +pub type TEKPUBKEY = DHPUBKEY; +STRUCT!{struct DSSSEED { + counter: DWORD, + seed: [BYTE; 20], +}} +STRUCT!{struct DHPUBKEY_VER3 { + magic: DWORD, + bitlenP: DWORD, + bitlenQ: DWORD, + bitlenJ: DWORD, + DSSSeed: DSSSEED, +}} +pub type DSSPUBKEY_VER3 = DHPUBKEY_VER3; +STRUCT!{struct DHPRIVKEY_VER3 { + magic: DWORD, + bitlenP: DWORD, + bitlenQ: DWORD, + bitlenJ: DWORD, + bitlenX: DWORD, + DSSSeed: DSSSEED, +}} +pub type DSSPRIVKEY_VER3 = DHPRIVKEY_VER3; +STRUCT!{struct KEY_TYPE_SUBTYPE { + dwKeySpec: DWORD, + Type: GUID, + Subtype: GUID, +}} +pub type PKEY_TYPE_SUBTYPE = *mut KEY_TYPE_SUBTYPE; +STRUCT!{struct CERT_FORTEZZA_DATA_PROP { + SerialNumber: [c_uchar; 8], + CertIndex: c_int, + CertLabel: [c_uchar; 36], +}} +STRUCT!{struct CRYPT_RC4_KEY_STATE { + Key: [c_uchar; 16], + SBox: [c_uchar; 256], + i: c_uchar, + j: c_uchar, +}} +pub type PCRYPT_RC4_KEY_STATE = *mut CRYPT_RC4_KEY_STATE; +STRUCT!{struct CRYPT_DES_KEY_STATE { + Key: [c_uchar; 8], + IV: [c_uchar; 8], + Feedback: [c_uchar; 8], +}} +pub type PCRYPT_DES_KEY_STATE = *mut CRYPT_DES_KEY_STATE; +STRUCT!{struct CRYPT_3DES_KEY_STATE { + Key: [c_uchar; 24], + IV: [c_uchar; 8], + Feedback: [c_uchar; 8], +}} +pub type PCRYPT_3DES_KEY_STATE = *mut CRYPT_3DES_KEY_STATE; +STRUCT!{struct CRYPT_AES_128_KEY_STATE { + Key: [c_uchar; 16], + IV: [c_uchar; 16], + EncryptionState: [[c_uchar; 16]; 11], + DecryptionState: [[c_uchar; 16]; 11], + Feedback: [c_uchar; 16], +}} +pub type PCRYPT_AES_128_KEY_STATE = *mut CRYPT_AES_128_KEY_STATE; +STRUCT!{struct CRYPT_AES_256_KEY_STATE { + Key: [c_uchar; 32], + IV: [c_uchar; 16], + EncryptionState: [[c_uchar; 16]; 15], + DecryptionState: [[c_uchar; 16]; 15], + Feedback: [c_uchar; 16], +}} +pub type PCRYPT_AES_256_KEY_STATE = *mut CRYPT_AES_256_KEY_STATE; +STRUCT!{struct CRYPTOAPI_BLOB { + cbData: DWORD, + pbData: *mut BYTE, +}} +pub type CRYPT_INTEGER_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_INTEGER_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_UINT_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_UINT_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_OBJID_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_OBJID_BLOB = *mut CRYPTOAPI_BLOB; +pub type CERT_NAME_BLOB = CRYPTOAPI_BLOB; +pub type PCERT_NAME_BLOB = *mut CRYPTOAPI_BLOB; +pub type CERT_RDN_VALUE_BLOB = CRYPTOAPI_BLOB; +pub type PCERT_RDN_VALUE_BLOB = *mut CRYPTOAPI_BLOB; +pub type CERT_BLOB = CRYPTOAPI_BLOB; +pub type PCERT_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRL_BLOB = CRYPTOAPI_BLOB; +pub type PCRL_BLOB = *mut CRYPTOAPI_BLOB; +pub type DATA_BLOB = CRYPTOAPI_BLOB; +pub type PDATA_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_DATA_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_DATA_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_HASH_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_HASH_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_DIGEST_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_DIGEST_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_DER_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_DER_BLOB = *mut CRYPTOAPI_BLOB; +pub type CRYPT_ATTR_BLOB = CRYPTOAPI_BLOB; +pub type PCRYPT_ATTR_BLOB = *mut CRYPTOAPI_BLOB; +STRUCT!{struct CMS_DH_KEY_INFO { + dwVersion: DWORD, + Algid: ALG_ID, + pszContentEncObjId: LPSTR, + PubInfo: CRYPT_DATA_BLOB, + pReserved: *mut c_void, +}} +pub type PCMS_DH_KEY_INFO = *mut CMS_DH_KEY_INFO; +extern "system" { + pub fn CryptAcquireContextA( + phProv: *mut HCRYPTPROV, + szContainer: LPCSTR, + szProvider: LPCSTR, + dwProvType: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptAcquireContextW( + phProv: *mut HCRYPTPROV, + szContainer: LPCWSTR, + szProvider: LPCWSTR, + dwProvType: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptReleaseContext( + hProv: HCRYPTPROV, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGenKey( + hProv: HCRYPTPROV, + Algid: ALG_ID, + dwFlags: DWORD, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptDeriveKey( + hProv: HCRYPTPROV, + Algid: ALG_ID, + hBaseData: HCRYPTHASH, + dwFlags: DWORD, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptDestroyKey( + hKey: HCRYPTKEY, + ) -> BOOL; + pub fn CryptSetKeyParam( + hKey: HCRYPTKEY, + dwParam: DWORD, + pbData: *const BYTE, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetKeyParam( + hKey: HCRYPTKEY, + dwParam: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetHashParam( + hHash: HCRYPTHASH, + dwParam: DWORD, + pbData: *const BYTE, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetHashParam( + hHash: HCRYPTHASH, + dwParam: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProvParam( + hProv: HCRYPTPROV, + dwParam: DWORD, + pbData: *const BYTE, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetProvParam( + hProv: HCRYPTPROV, + dwParam: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGenRandom( + hProv: HCRYPTPROV, + dwLen: DWORD, + pbBuffer: *mut BYTE, + ) -> BOOL; + pub fn CryptGetUserKey( + hProv: HCRYPTPROV, + dwKeySpec: DWORD, + phUserKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptExportKey( + hKey: HCRYPTKEY, + hExpKey: HCRYPTKEY, + dwBlobType: DWORD, + dwFlags: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + ) -> BOOL; + pub fn CryptImportKey( + hProv: HCRYPTPROV, + pbData: *const BYTE, + dwDataLen: DWORD, + hPubKey: HCRYPTKEY, + dwFlags: DWORD, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptEncrypt( + hKey: HCRYPTKEY, + hHash: HCRYPTHASH, + Final: BOOL, + dwFlags: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + dwBufLen: DWORD, + ) -> BOOL; + pub fn CryptDecrypt( + hKey: HCRYPTKEY, + hHash: HCRYPTHASH, + Final: BOOL, + dwFlags: DWORD, + pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + ) -> BOOL; + pub fn CryptCreateHash( + hProv: HCRYPTPROV, + Algid: ALG_ID, + hKey: HCRYPTKEY, + dwFlags: DWORD, + phHash: *mut HCRYPTHASH, + ) -> BOOL; + pub fn CryptHashData( + hHash: HCRYPTHASH, + pbData: *const BYTE, + dwDataLen: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptHashSessionKey( + hHash: HCRYPTHASH, + hKey: HCRYPTKEY, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptDestroyHash( + hHash: HCRYPTHASH, + ) -> BOOL; + pub fn CryptSignHashA( + hHash: HCRYPTHASH, + dwKeySpec: DWORD, + szDescription: LPCSTR, + dwFlags: DWORD, + pbSignature: *mut BYTE, + pdwSigLen: *mut DWORD, + ) -> BOOL; + pub fn CryptSignHashW( + hHash: HCRYPTHASH, + dwKeySpec: DWORD, + szDescription: LPCWSTR, + dwFlags: DWORD, + pbSignature: *mut BYTE, + pdwSigLen: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifySignatureA( + hHash: HCRYPTHASH, + pbSignature: *const BYTE, + dwSigLen: DWORD, + hPubKey: HCRYPTKEY, + szDescription: LPCSTR, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptVerifySignatureW( + hHash: HCRYPTHASH, + pbSignature: *const BYTE, + dwSigLen: DWORD, + hPubKey: HCRYPTKEY, + szDescription: LPCWSTR, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProviderA( + pszProvName: LPCSTR, + dwProvType: DWORD, + ) -> BOOL; + pub fn CryptSetProviderW( + pszProvName: LPCWSTR, + dwProvType: DWORD, + ) -> BOOL; + pub fn CryptSetProviderExA( + pszProvName: LPCSTR, + dwProvType: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProviderExW( + pszProvName: LPCWSTR, + dwProvType: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetDefaultProviderA( + dwProvType: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pszProvName: LPSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptGetDefaultProviderW( + dwProvType: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pszProvName: LPWSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProviderTypesA( + dwIndex: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pdwProvType: *mut DWORD, + szTypeName: LPSTR, + pcbTypeName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProviderTypesW( + dwIndex: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pdwProvType: *mut DWORD, + szTypeName: LPWSTR, + pcbTypeName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProvidersA( + dwIndex: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pdwProvType: *mut DWORD, + szProvName: LPSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProvidersW( + dwIndex: DWORD, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + pdwProvType: *mut DWORD, + szProvName: LPWSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptContextAddRef( + hProv: HCRYPTPROV, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptDuplicateKey( + hKey: HCRYPTKEY, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptDuplicateHash( + hHash: HCRYPTHASH, + pdwReserved: *mut DWORD, + dwFlags: DWORD, + phHash: *mut HCRYPTHASH, + ) -> BOOL; +} +extern "C" { + pub fn GetEncSChannel( + pData: *mut *mut BYTE, + dwDecSize: *mut DWORD, + ) -> BOOL; +} +pub type HCRYPTPROV_OR_NCRYPT_KEY_HANDLE = ULONG_PTR; +pub type HCRYPTPROV_LEGACY = ULONG_PTR; +STRUCT!{struct CRYPT_BIT_BLOB { + cbData: DWORD, + pbData: *mut BYTE, + cUnusedBits: DWORD, +}} +pub type PCRYPT_BIT_BLOB = *mut CRYPT_BIT_BLOB; +STRUCT!{struct CRYPT_ALGORITHM_IDENTIFIER { + pszObjId: LPSTR, + Parameters: CRYPT_OBJID_BLOB, +}} +pub type PCRYPT_ALGORITHM_IDENTIFIER = *mut CRYPT_ALGORITHM_IDENTIFIER; +pub const szOID_RSA: &'static str = "1.2.840.113549"; +pub const szOID_PKCS: &'static str = "1.2.840.113549.1"; +pub const szOID_RSA_HASH: &'static str = "1.2.840.113549.2"; +pub const szOID_RSA_ENCRYPT: &'static str = "1.2.840.113549.3"; +pub const szOID_PKCS_1: &'static str = "1.2.840.113549.1.1"; +pub const szOID_PKCS_2: &'static str = "1.2.840.113549.1.2"; +pub const szOID_PKCS_3: &'static str = "1.2.840.113549.1.3"; +pub const szOID_PKCS_4: &'static str = "1.2.840.113549.1.4"; +pub const szOID_PKCS_5: &'static str = "1.2.840.113549.1.5"; +pub const szOID_PKCS_6: &'static str = "1.2.840.113549.1.6"; +pub const szOID_PKCS_7: &'static str = "1.2.840.113549.1.7"; +pub const szOID_PKCS_8: &'static str = "1.2.840.113549.1.8"; +pub const szOID_PKCS_9: &'static str = "1.2.840.113549.1.9"; +pub const szOID_PKCS_10: &'static str = "1.2.840.113549.1.10"; +pub const szOID_PKCS_12: &'static str = "1.2.840.113549.1.12"; +pub const szOID_RSA_RSA: &'static str = "1.2.840.113549.1.1.1"; +pub const szOID_RSA_MD2RSA: &'static str = "1.2.840.113549.1.1.2"; +pub const szOID_RSA_MD4RSA: &'static str = "1.2.840.113549.1.1.3"; +pub const szOID_RSA_MD5RSA: &'static str = "1.2.840.113549.1.1.4"; +pub const szOID_RSA_SHA1RSA: &'static str = "1.2.840.113549.1.1.5"; +pub const szOID_RSA_SETOAEP_RSA: &'static str = "1.2.840.113549.1.1.6"; +pub const szOID_RSAES_OAEP: &'static str = "1.2.840.113549.1.1.7"; +pub const szOID_RSA_MGF1: &'static str = "1.2.840.113549.1.1.8"; +pub const szOID_RSA_PSPECIFIED: &'static str = "1.2.840.113549.1.1.9"; +pub const szOID_RSA_SSA_PSS: &'static str = "1.2.840.113549.1.1.10"; +pub const szOID_RSA_SHA256RSA: &'static str = "1.2.840.113549.1.1.11"; +pub const szOID_RSA_SHA384RSA: &'static str = "1.2.840.113549.1.1.12"; +pub const szOID_RSA_SHA512RSA: &'static str = "1.2.840.113549.1.1.13"; +pub const szOID_RSA_DH: &'static str = "1.2.840.113549.1.3.1"; +pub const szOID_RSA_data: &'static str = "1.2.840.113549.1.7.1"; +pub const szOID_RSA_signedData: &'static str = "1.2.840.113549.1.7.2"; +pub const szOID_RSA_envelopedData: &'static str = "1.2.840.113549.1.7.3"; +pub const szOID_RSA_signEnvData: &'static str = "1.2.840.113549.1.7.4"; +pub const szOID_RSA_digestedData: &'static str = "1.2.840.113549.1.7.5"; +pub const szOID_RSA_hashedData: &'static str = "1.2.840.113549.1.7.5"; +pub const szOID_RSA_encryptedData: &'static str = "1.2.840.113549.1.7.6"; +pub const szOID_RSA_emailAddr: &'static str = "1.2.840.113549.1.9.1"; +pub const szOID_RSA_unstructName: &'static str = "1.2.840.113549.1.9.2"; +pub const szOID_RSA_contentType: &'static str = "1.2.840.113549.1.9.3"; +pub const szOID_RSA_messageDigest: &'static str = "1.2.840.113549.1.9.4"; +pub const szOID_RSA_signingTime: &'static str = "1.2.840.113549.1.9.5"; +pub const szOID_RSA_counterSign: &'static str = "1.2.840.113549.1.9.6"; +pub const szOID_RSA_challengePwd: &'static str = "1.2.840.113549.1.9.7"; +pub const szOID_RSA_unstructAddr: &'static str = "1.2.840.113549.1.9.8"; +pub const szOID_RSA_extCertAttrs: &'static str = "1.2.840.113549.1.9.9"; +pub const szOID_RSA_certExtensions: &'static str = "1.2.840.113549.1.9.14"; +pub const szOID_RSA_SMIMECapabilities: &'static str = "1.2.840.113549.1.9.15"; +pub const szOID_RSA_preferSignedData: &'static str = "1.2.840.113549.1.9.15.1"; +pub const szOID_TIMESTAMP_TOKEN: &'static str = "1.2.840.113549.1.9.16.1.4"; +pub const szOID_RFC3161_counterSign: &'static str = "1.3.6.1.4.1.311.3.3.1"; +pub const szOID_RSA_SMIMEalg: &'static str = "1.2.840.113549.1.9.16.3"; +pub const szOID_RSA_SMIMEalgESDH: &'static str = "1.2.840.113549.1.9.16.3.5"; +pub const szOID_RSA_SMIMEalgCMS3DESwrap: &'static str = "1.2.840.113549.1.9.16.3.6"; +pub const szOID_RSA_SMIMEalgCMSRC2wrap: &'static str = "1.2.840.113549.1.9.16.3.7"; +pub const szOID_RSA_MD2: &'static str = "1.2.840.113549.2.2"; +pub const szOID_RSA_MD4: &'static str = "1.2.840.113549.2.4"; +pub const szOID_RSA_MD5: &'static str = "1.2.840.113549.2.5"; +pub const szOID_RSA_RC2CBC: &'static str = "1.2.840.113549.3.2"; +pub const szOID_RSA_RC4: &'static str = "1.2.840.113549.3.4"; +pub const szOID_RSA_DES_EDE3_CBC: &'static str = "1.2.840.113549.3.7"; +pub const szOID_RSA_RC5_CBCPad: &'static str = "1.2.840.113549.3.9"; +pub const szOID_ANSI_X942: &'static str = "1.2.840.10046"; +pub const szOID_ANSI_X942_DH: &'static str = "1.2.840.10046.2.1"; +pub const szOID_X957: &'static str = "1.2.840.10040"; +pub const szOID_X957_DSA: &'static str = "1.2.840.10040.4.1"; +pub const szOID_X957_SHA1DSA: &'static str = "1.2.840.10040.4.3"; +pub const szOID_ECC_PUBLIC_KEY: &'static str = "1.2.840.10045.2.1"; +pub const szOID_ECC_CURVE_P256: &'static str = "1.2.840.10045.3.1.7"; +pub const szOID_ECC_CURVE_P384: &'static str = "1.3.132.0.34"; +pub const szOID_ECC_CURVE_P521: &'static str = "1.3.132.0.35"; +pub const szOID_ECC_CURVE_BRAINPOOLP160R1: &'static str = "1.3.36.3.3.2.8.1.1.1"; +pub const szOID_ECC_CURVE_BRAINPOOLP160T1: &'static str = "1.3.36.3.3.2.8.1.1.2"; +pub const szOID_ECC_CURVE_BRAINPOOLP192R1: &'static str = "1.3.36.3.3.2.8.1.1.3"; +pub const szOID_ECC_CURVE_BRAINPOOLP192T1: &'static str = "1.3.36.3.3.2.8.1.1.4"; +pub const szOID_ECC_CURVE_BRAINPOOLP224R1: &'static str = "1.3.36.3.3.2.8.1.1.5"; +pub const szOID_ECC_CURVE_BRAINPOOLP224T1: &'static str = "1.3.36.3.3.2.8.1.1.6"; +pub const szOID_ECC_CURVE_BRAINPOOLP256R1: &'static str = "1.3.36.3.3.2.8.1.1.7"; +pub const szOID_ECC_CURVE_BRAINPOOLP256T1: &'static str = "1.3.36.3.3.2.8.1.1.8"; +pub const szOID_ECC_CURVE_BRAINPOOLP320R1: &'static str = "1.3.36.3.3.2.8.1.1.9"; +pub const szOID_ECC_CURVE_BRAINPOOLP320T1: &'static str = "1.3.36.3.3.2.8.1.1.10"; +pub const szOID_ECC_CURVE_BRAINPOOLP384R1: &'static str = "1.3.36.3.3.2.8.1.1.11"; +pub const szOID_ECC_CURVE_BRAINPOOLP384T1: &'static str = "1.3.36.3.3.2.8.1.1.12"; +pub const szOID_ECC_CURVE_BRAINPOOLP512R1: &'static str = "1.3.36.3.3.2.8.1.1.13"; +pub const szOID_ECC_CURVE_BRAINPOOLP512T1: &'static str = "1.3.36.3.3.2.8.1.1.14"; +pub const szOID_ECC_CURVE_EC192WAPI: &'static str = "1.2.156.11235.1.1.2.1"; +pub const szOID_CN_ECDSA_SHA256: &'static str = "1.2.156.11235.1.1.1"; +pub const szOID_ECC_CURVE_NISTP192: &'static str = "1.2.840.10045.3.1.1"; +pub const szOID_ECC_CURVE_NISTP224: &'static str = "1.3.132.0.33"; +pub const szOID_ECC_CURVE_NISTP256: &'static str = szOID_ECC_CURVE_P256; +pub const szOID_ECC_CURVE_NISTP384: &'static str = szOID_ECC_CURVE_P384; +pub const szOID_ECC_CURVE_NISTP521: &'static str = szOID_ECC_CURVE_P521; +pub const szOID_ECC_CURVE_SECP160K1: &'static str = "1.3.132.0.9"; +pub const szOID_ECC_CURVE_SECP160R1: &'static str = "1.3.132.0.8"; +pub const szOID_ECC_CURVE_SECP160R2: &'static str = "1.3.132.0.30"; +pub const szOID_ECC_CURVE_SECP192K1: &'static str = "1.3.132.0.31"; +pub const szOID_ECC_CURVE_SECP192R1: &'static str = szOID_ECC_CURVE_NISTP192; +pub const szOID_ECC_CURVE_SECP224K1: &'static str = "1.3.132.0.32"; +pub const szOID_ECC_CURVE_SECP224R1: &'static str = szOID_ECC_CURVE_NISTP224; +pub const szOID_ECC_CURVE_SECP256K1: &'static str = "1.3.132.0.10"; +pub const szOID_ECC_CURVE_SECP256R1: &'static str = szOID_ECC_CURVE_P256; +pub const szOID_ECC_CURVE_SECP384R1: &'static str = szOID_ECC_CURVE_P384; +pub const szOID_ECC_CURVE_SECP521R1: &'static str = szOID_ECC_CURVE_P521; +pub const szOID_ECC_CURVE_WTLS7: &'static str = szOID_ECC_CURVE_SECP160R2; +pub const szOID_ECC_CURVE_WTLS9: &'static str = "2.23.43.1.4.9"; +pub const szOID_ECC_CURVE_WTLS12: &'static str = szOID_ECC_CURVE_NISTP224; +pub const szOID_ECC_CURVE_X962P192V1: &'static str = "1.2.840.10045.3.1.1"; +pub const szOID_ECC_CURVE_X962P192V2: &'static str = "1.2.840.10045.3.1.2"; +pub const szOID_ECC_CURVE_X962P192V3: &'static str = "1.2.840.10045.3.1.3"; +pub const szOID_ECC_CURVE_X962P239V1: &'static str = "1.2.840.10045.3.1.4"; +pub const szOID_ECC_CURVE_X962P239V2: &'static str = "1.2.840.10045.3.1.5"; +pub const szOID_ECC_CURVE_X962P239V3: &'static str = "1.2.840.10045.3.1.6"; +pub const szOID_ECC_CURVE_X962P256V1: &'static str = szOID_ECC_CURVE_P256; +pub const szOID_ECDSA_SHA1: &'static str = "1.2.840.10045.4.1"; +pub const szOID_ECDSA_SPECIFIED: &'static str = "1.2.840.10045.4.3"; +pub const szOID_ECDSA_SHA256: &'static str = "1.2.840.10045.4.3.2"; +pub const szOID_ECDSA_SHA384: &'static str = "1.2.840.10045.4.3.3"; +pub const szOID_ECDSA_SHA512: &'static str = "1.2.840.10045.4.3.4"; +pub const szOID_NIST_AES128_CBC: &'static str = "2.16.840.1.101.3.4.1.2"; +pub const szOID_NIST_AES192_CBC: &'static str = "2.16.840.1.101.3.4.1.22"; +pub const szOID_NIST_AES256_CBC: &'static str = "2.16.840.1.101.3.4.1.42"; +pub const szOID_NIST_AES128_WRAP: &'static str = "2.16.840.1.101.3.4.1.5"; +pub const szOID_NIST_AES192_WRAP: &'static str = "2.16.840.1.101.3.4.1.25"; +pub const szOID_NIST_AES256_WRAP: &'static str = "2.16.840.1.101.3.4.1.45"; +pub const szOID_DH_SINGLE_PASS_STDDH_SHA1_KDF: &'static str = "1.3.133.16.840.63.0.2"; +pub const szOID_DH_SINGLE_PASS_STDDH_SHA256_KDF: &'static str = "1.3.132.1.11.1"; +pub const szOID_DH_SINGLE_PASS_STDDH_SHA384_KDF: &'static str = "1.3.132.1.11.2"; +pub const szOID_DS: &'static str = "2.5"; +pub const szOID_DSALG: &'static str = "2.5.8"; +pub const szOID_DSALG_CRPT: &'static str = "2.5.8.1"; +pub const szOID_DSALG_HASH: &'static str = "2.5.8.2"; +pub const szOID_DSALG_SIGN: &'static str = "2.5.8.3"; +pub const szOID_DSALG_RSA: &'static str = "2.5.8.1.1"; +pub const szOID_OIW: &'static str = "1.3.14"; +pub const szOID_OIWSEC: &'static str = "1.3.14.3.2"; +pub const szOID_OIWSEC_md4RSA: &'static str = "1.3.14.3.2.2"; +pub const szOID_OIWSEC_md5RSA: &'static str = "1.3.14.3.2.3"; +pub const szOID_OIWSEC_md4RSA2: &'static str = "1.3.14.3.2.4"; +pub const szOID_OIWSEC_desECB: &'static str = "1.3.14.3.2.6"; +pub const szOID_OIWSEC_desCBC: &'static str = "1.3.14.3.2.7"; +pub const szOID_OIWSEC_desOFB: &'static str = "1.3.14.3.2.8"; +pub const szOID_OIWSEC_desCFB: &'static str = "1.3.14.3.2.9"; +pub const szOID_OIWSEC_desMAC: &'static str = "1.3.14.3.2.10"; +pub const szOID_OIWSEC_rsaSign: &'static str = "1.3.14.3.2.11"; +pub const szOID_OIWSEC_dsa: &'static str = "1.3.14.3.2.12"; +pub const szOID_OIWSEC_shaDSA: &'static str = "1.3.14.3.2.13"; +pub const szOID_OIWSEC_mdc2RSA: &'static str = "1.3.14.3.2.14"; +pub const szOID_OIWSEC_shaRSA: &'static str = "1.3.14.3.2.15"; +pub const szOID_OIWSEC_dhCommMod: &'static str = "1.3.14.3.2.16"; +pub const szOID_OIWSEC_desEDE: &'static str = "1.3.14.3.2.17"; +pub const szOID_OIWSEC_sha: &'static str = "1.3.14.3.2.18"; +pub const szOID_OIWSEC_mdc2: &'static str = "1.3.14.3.2.19"; +pub const szOID_OIWSEC_dsaComm: &'static str = "1.3.14.3.2.20"; +pub const szOID_OIWSEC_dsaCommSHA: &'static str = "1.3.14.3.2.21"; +pub const szOID_OIWSEC_rsaXchg: &'static str = "1.3.14.3.2.22"; +pub const szOID_OIWSEC_keyHashSeal: &'static str = "1.3.14.3.2.23"; +pub const szOID_OIWSEC_md2RSASign: &'static str = "1.3.14.3.2.24"; +pub const szOID_OIWSEC_md5RSASign: &'static str = "1.3.14.3.2.25"; +pub const szOID_OIWSEC_sha1: &'static str = "1.3.14.3.2.26"; +pub const szOID_OIWSEC_dsaSHA1: &'static str = "1.3.14.3.2.27"; +pub const szOID_OIWSEC_dsaCommSHA1: &'static str = "1.3.14.3.2.28"; +pub const szOID_OIWSEC_sha1RSASign: &'static str = "1.3.14.3.2.29"; +pub const szOID_OIWDIR: &'static str = "1.3.14.7.2"; +pub const szOID_OIWDIR_CRPT: &'static str = "1.3.14.7.2.1"; +pub const szOID_OIWDIR_HASH: &'static str = "1.3.14.7.2.2"; +pub const szOID_OIWDIR_SIGN: &'static str = "1.3.14.7.2.3"; +pub const szOID_OIWDIR_md2: &'static str = "1.3.14.7.2.2.1"; +pub const szOID_OIWDIR_md2RSA: &'static str = "1.3.14.7.2.3.1"; +pub const szOID_INFOSEC: &'static str = "2.16.840.1.101.2.1"; +pub const szOID_INFOSEC_sdnsSignature: &'static str = "2.16.840.1.101.2.1.1.1"; +pub const szOID_INFOSEC_mosaicSignature: &'static str = "2.16.840.1.101.2.1.1.2"; +pub const szOID_INFOSEC_sdnsConfidentiality: &'static str = "2.16.840.1.101.2.1.1.3"; +pub const szOID_INFOSEC_mosaicConfidentiality: &'static str = "2.16.840.1.101.2.1.1.4"; +pub const szOID_INFOSEC_sdnsIntegrity: &'static str = "2.16.840.1.101.2.1.1.5"; +pub const szOID_INFOSEC_mosaicIntegrity: &'static str = "2.16.840.1.101.2.1.1.6"; +pub const szOID_INFOSEC_sdnsTokenProtection: &'static str = "2.16.840.1.101.2.1.1.7"; +pub const szOID_INFOSEC_mosaicTokenProtection: &'static str = "2.16.840.1.101.2.1.1.8"; +pub const szOID_INFOSEC_sdnsKeyManagement: &'static str = "2.16.840.1.101.2.1.1.9"; +pub const szOID_INFOSEC_mosaicKeyManagement: &'static str = "2.16.840.1.101.2.1.1.10"; +pub const szOID_INFOSEC_sdnsKMandSig: &'static str = "2.16.840.1.101.2.1.1.11"; +pub const szOID_INFOSEC_mosaicKMandSig: &'static str = "2.16.840.1.101.2.1.1.12"; +pub const szOID_INFOSEC_SuiteASignature: &'static str = "2.16.840.1.101.2.1.1.13"; +pub const szOID_INFOSEC_SuiteAConfidentiality: &'static str = "2.16.840.1.101.2.1.1.14"; +pub const szOID_INFOSEC_SuiteAIntegrity: &'static str = "2.16.840.1.101.2.1.1.15"; +pub const szOID_INFOSEC_SuiteATokenProtection: &'static str = "2.16.840.1.101.2.1.1.16"; +pub const szOID_INFOSEC_SuiteAKeyManagement: &'static str = "2.16.840.1.101.2.1.1.17"; +pub const szOID_INFOSEC_SuiteAKMandSig: &'static str = "2.16.840.1.101.2.1.1.18"; +pub const szOID_INFOSEC_mosaicUpdatedSig: &'static str = "2.16.840.1.101.2.1.1.19"; +pub const szOID_INFOSEC_mosaicKMandUpdSig: &'static str = "2.16.840.1.101.2.1.1.20"; +pub const szOID_INFOSEC_mosaicUpdatedInteg: &'static str = "2.16.840.1.101.2.1.1.21"; +pub const szOID_NIST_sha256: &'static str = "2.16.840.1.101.3.4.2.1"; +pub const szOID_NIST_sha384: &'static str = "2.16.840.1.101.3.4.2.2"; +pub const szOID_NIST_sha512: &'static str = "2.16.840.1.101.3.4.2.3"; +STRUCT!{struct CRYPT_OBJID_TABLE { + dwAlgId: DWORD, + pszObjId: LPCSTR, +}} +pub type PCRYPT_OBJID_TABLE = *mut CRYPT_OBJID_TABLE; +STRUCT!{struct CRYPT_HASH_INFO { + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Hash: CRYPT_HASH_BLOB, +}} +pub type PCRYPT_HASH_INFO = *mut CRYPT_HASH_INFO; +STRUCT!{struct CERT_EXTENSION { + pszObjId: LPSTR, + fCritical: BOOL, + Value: CRYPT_OBJID_BLOB, +}} +pub type PCERT_EXTENSION = *mut CERT_EXTENSION; +pub type PCCERT_EXTENSION = *const CERT_EXTENSION; +STRUCT!{struct CRYPT_ATTRIBUTE_TYPE_VALUE { + pszObjId: LPSTR, + Value: CRYPT_OBJID_BLOB, +}} +pub type PCRYPT_ATTRIBUTE_TYPE_VALUE = *mut CRYPT_ATTRIBUTE_TYPE_VALUE; +STRUCT!{struct CRYPT_ATTRIBUTE { + pszObjId: LPSTR, + cValue: DWORD, + rgValue: PCRYPT_ATTR_BLOB, +}} +pub type PCRYPT_ATTRIBUTE = *mut CRYPT_ATTRIBUTE; +STRUCT!{struct CRYPT_ATTRIBUTES { + cAttr: DWORD, + rgAttr: PCRYPT_ATTRIBUTE, +}} +pub type PCRYPT_ATTRIBUTES = *mut CRYPT_ATTRIBUTES; +STRUCT!{struct CERT_RDN_ATTR { + pszObjId: LPSTR, + dwValueType: DWORD, + Value: CERT_RDN_VALUE_BLOB, +}} +pub type PCERT_RDN_ATTR = *mut CERT_RDN_ATTR; +pub const szOID_COMMON_NAME: &'static str = "2.5.4.3"; +pub const szOID_SUR_NAME: &'static str = "2.5.4.4"; +pub const szOID_DEVICE_SERIAL_NUMBER: &'static str = "2.5.4.5"; +pub const szOID_COUNTRY_NAME: &'static str = "2.5.4.6"; +pub const szOID_LOCALITY_NAME: &'static str = "2.5.4.7"; +pub const szOID_STATE_OR_PROVINCE_NAME: &'static str = "2.5.4.8"; +pub const szOID_STREET_ADDRESS: &'static str = "2.5.4.9"; +pub const szOID_ORGANIZATION_NAME: &'static str = "2.5.4.10"; +pub const szOID_ORGANIZATIONAL_UNIT_NAME: &'static str = "2.5.4.11"; +pub const szOID_TITLE: &'static str = "2.5.4.12"; +pub const szOID_DESCRIPTION: &'static str = "2.5.4.13"; +pub const szOID_SEARCH_GUIDE: &'static str = "2.5.4.14"; +pub const szOID_BUSINESS_CATEGORY: &'static str = "2.5.4.15"; +pub const szOID_POSTAL_ADDRESS: &'static str = "2.5.4.16"; +pub const szOID_POSTAL_CODE: &'static str = "2.5.4.17"; +pub const szOID_POST_OFFICE_BOX: &'static str = "2.5.4.18"; +pub const szOID_PHYSICAL_DELIVERY_OFFICE_NAME: &'static str = "2.5.4.19"; +pub const szOID_TELEPHONE_NUMBER: &'static str = "2.5.4.20"; +pub const szOID_TELEX_NUMBER: &'static str = "2.5.4.21"; +pub const szOID_TELETEXT_TERMINAL_IDENTIFIER: &'static str = "2.5.4.22"; +pub const szOID_FACSIMILE_TELEPHONE_NUMBER: &'static str = "2.5.4.23"; +pub const szOID_X21_ADDRESS: &'static str = "2.5.4.24"; +pub const szOID_INTERNATIONAL_ISDN_NUMBER: &'static str = "2.5.4.25"; +pub const szOID_REGISTERED_ADDRESS: &'static str = "2.5.4.26"; +pub const szOID_DESTINATION_INDICATOR: &'static str = "2.5.4.27"; +pub const szOID_PREFERRED_DELIVERY_METHOD: &'static str = "2.5.4.28"; +pub const szOID_PRESENTATION_ADDRESS: &'static str = "2.5.4.29"; +pub const szOID_SUPPORTED_APPLICATION_CONTEXT: &'static str = "2.5.4.30"; +pub const szOID_MEMBER: &'static str = "2.5.4.31"; +pub const szOID_OWNER: &'static str = "2.5.4.32"; +pub const szOID_ROLE_OCCUPANT: &'static str = "2.5.4.33"; +pub const szOID_SEE_ALSO: &'static str = "2.5.4.34"; +pub const szOID_USER_PASSWORD: &'static str = "2.5.4.35"; +pub const szOID_USER_CERTIFICATE: &'static str = "2.5.4.36"; +pub const szOID_CA_CERTIFICATE: &'static str = "2.5.4.37"; +pub const szOID_AUTHORITY_REVOCATION_LIST: &'static str = "2.5.4.38"; +pub const szOID_CERTIFICATE_REVOCATION_LIST: &'static str = "2.5.4.39"; +pub const szOID_CROSS_CERTIFICATE_PAIR: &'static str = "2.5.4.40"; +pub const szOID_GIVEN_NAME: &'static str = "2.5.4.42"; +pub const szOID_INITIALS: &'static str = "2.5.4.43"; +pub const szOID_DN_QUALIFIER: &'static str = "2.5.4.46"; +pub const szOID_DOMAIN_COMPONENT: &'static str = "0.9.2342.19200300.100.1.25"; +pub const szOID_PKCS_12_FRIENDLY_NAME_ATTR: &'static str = "1.2.840.113549.1.9.20"; +pub const szOID_PKCS_12_LOCAL_KEY_ID: &'static str = "1.2.840.113549.1.9.21"; +pub const szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR: &'static str = "1.3.6.1.4.1.311.17.1"; +pub const szOID_LOCAL_MACHINE_KEYSET: &'static str = "1.3.6.1.4.1.311.17.2"; +pub const szOID_PKCS_12_EXTENDED_ATTRIBUTES: &'static str = "1.3.6.1.4.1.311.17.3"; +pub const szOID_PKCS_12_PROTECTED_PASSWORD_SECRET_BAG_TYPE_ID: &'static str + = "1.3.6.1.4.1.311.17.4"; +pub const szOID_KEYID_RDN: &'static str = "1.3.6.1.4.1.311.10.7.1"; +pub const szOID_EV_RDN_LOCALE: &'static str = "1.3.6.1.4.1.311.60.2.1.1"; +pub const szOID_EV_RDN_STATE_OR_PROVINCE: &'static str = "1.3.6.1.4.1.311.60.2.1.2"; +pub const szOID_EV_RDN_COUNTRY: &'static str = "1.3.6.1.4.1.311.60.2.1.3"; +pub const CERT_RDN_ANY_TYPE: DWORD = 0; +pub const CERT_RDN_ENCODED_BLOB: DWORD = 1; +pub const CERT_RDN_OCTET_STRING: DWORD = 2; +pub const CERT_RDN_NUMERIC_STRING: DWORD = 3; +pub const CERT_RDN_PRINTABLE_STRING: DWORD = 4; +pub const CERT_RDN_TELETEX_STRING: DWORD = 5; +pub const CERT_RDN_T61_STRING: DWORD = 5; +pub const CERT_RDN_VIDEOTEX_STRING: DWORD = 6; +pub const CERT_RDN_IA5_STRING: DWORD = 7; +pub const CERT_RDN_GRAPHIC_STRING: DWORD = 8; +pub const CERT_RDN_VISIBLE_STRING: DWORD = 9; +pub const CERT_RDN_ISO646_STRING: DWORD = 9; +pub const CERT_RDN_GENERAL_STRING: DWORD = 10; +pub const CERT_RDN_UNIVERSAL_STRING: DWORD = 11; +pub const CERT_RDN_INT4_STRING: DWORD = 11; +pub const CERT_RDN_BMP_STRING: DWORD = 12; +pub const CERT_RDN_UNICODE_STRING: DWORD = 12; +pub const CERT_RDN_UTF8_STRING: DWORD = 13; +pub const CERT_RDN_TYPE_MASK: DWORD = 0x000000FF; +pub const CERT_RDN_FLAGS_MASK: DWORD = 0xFF000000; +pub const CERT_RDN_ENABLE_T61_UNICODE_FLAG: DWORD = 0x80000000; +pub const CERT_RDN_ENABLE_UTF8_UNICODE_FLAG: DWORD = 0x20000000; +pub const CERT_RDN_FORCE_UTF8_UNICODE_FLAG: DWORD = 0x10000000; +pub const CERT_RDN_DISABLE_CHECK_TYPE_FLAG: DWORD = 0x40000000; +pub const CERT_RDN_DISABLE_IE4_UTF8_FLAG: DWORD = 0x01000000; +pub const CERT_RDN_ENABLE_PUNYCODE_FLAG: DWORD = 0x02000000; +#[inline] +pub fn IS_CERT_RDN_CHAR_STRING(X: DWORD) -> bool { + (X & CERT_RDN_TYPE_MASK) >= CERT_RDN_NUMERIC_STRING +} +STRUCT!{struct CERT_RDN { + cRDNAttr: DWORD, + rgRDNAttr: PCERT_RDN_ATTR, +}} +pub type PCERT_RDN = *mut CERT_RDN; +STRUCT!{struct CERT_NAME_INFO { + cRDN: DWORD, + rgRDN: PCERT_RDN, +}} +pub type PCERT_NAME_INFO = *mut CERT_NAME_INFO; +STRUCT!{struct CERT_NAME_VALUE { + dwValueType: DWORD, + Value: CERT_RDN_VALUE_BLOB, +}} +pub type PCERT_NAME_VALUE = *mut CERT_NAME_VALUE; +STRUCT!{struct CERT_PUBLIC_KEY_INFO { + Algorithm: CRYPT_ALGORITHM_IDENTIFIER, + PublicKey: CRYPT_BIT_BLOB, +}} +pub type PCERT_PUBLIC_KEY_INFO = *mut CERT_PUBLIC_KEY_INFO; +pub const CERT_RSA_PUBLIC_KEY_OBJID: &'static str = szOID_RSA_RSA; +pub const CERT_DEFAULT_OID_PUBLIC_KEY_SIGN: &'static str = szOID_RSA_RSA; +pub const CERT_DEFAULT_OID_PUBLIC_KEY_XCHG: &'static str = szOID_RSA_RSA; +STRUCT!{struct CRYPT_ECC_PRIVATE_KEY_INFO { + dwVersion: DWORD, + PrivateKey: CRYPT_DER_BLOB, + szCurveOid: LPSTR, + PublicKey: CRYPT_BIT_BLOB, +}} +pub type PCRYPT_ECC_PRIVATE_KEY_INFO = *mut CRYPT_ECC_PRIVATE_KEY_INFO; +pub const CRYPT_ECC_PRIVATE_KEY_INFO_v1: DWORD = 1; +STRUCT!{struct CRYPT_PRIVATE_KEY_INFO { + Version: DWORD, + Algorithm: CRYPT_ALGORITHM_IDENTIFIER, + PrivateKey: CRYPT_DER_BLOB, + pAttributes: PCRYPT_ATTRIBUTES, +}} +pub type PCRYPT_PRIVATE_KEY_INFO = *mut CRYPT_PRIVATE_KEY_INFO; +STRUCT!{struct CRYPT_ENCRYPTED_PRIVATE_KEY_INFO { + EncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedPrivateKey: CRYPT_DATA_BLOB, +}} +pub type PCRYPT_ENCRYPTED_PRIVATE_KEY_INFO = *mut CRYPT_ENCRYPTED_PRIVATE_KEY_INFO; +FN!{stdcall PCRYPT_DECRYPT_PRIVATE_KEY_FUNC( + Algorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedPrivateKey: CRYPT_DATA_BLOB, + pbClearTextKey: *mut BYTE, + pcbClearTextKey: *mut DWORD, + pVoidDecryptFunc: LPVOID, +) -> BOOL} +FN!{stdcall PCRYPT_ENCRYPT_PRIVATE_KEY_FUNC( + Algorithm: *mut CRYPT_ALGORITHM_IDENTIFIER, + pClearTextPrivateKey: *mut CRYPT_DATA_BLOB, + pbEncryptedKey: *mut BYTE, + pcbEncryptedKey: *mut DWORD, + pVoidEncryptFunc: LPVOID, +) -> BOOL} +FN!{stdcall PCRYPT_RESOLVE_HCRYPTPROV_FUNC( + pPrivateKeyInfo: *mut CRYPT_PRIVATE_KEY_INFO, + phCryptProv: *mut HCRYPTPROV, + pVoidResolveFunc: LPVOID, +) -> BOOL} +STRUCT!{struct CRYPT_PKCS8_IMPORT_PARAMS { + PrivateKey: CRYPT_DIGEST_BLOB, + pResolvehCryptProvFunc: PCRYPT_RESOLVE_HCRYPTPROV_FUNC, + pVoidResolveFunc: LPVOID, + pDecryptPrivateKeyFunc: PCRYPT_DECRYPT_PRIVATE_KEY_FUNC, + pVoidDecryptFunc: LPVOID, +}} +pub type PCRYPT_PKCS8_IMPORT_PARAMS = *mut CRYPT_PKCS8_IMPORT_PARAMS; +pub type CRYPT_PRIVATE_KEY_BLOB_AND_PARAMS = CRYPT_PKCS8_IMPORT_PARAMS; +pub type PPCRYPT_PRIVATE_KEY_BLOB_AND_PARAMS = *mut CRYPT_PKCS8_IMPORT_PARAMS; +STRUCT!{struct CRYPT_PKCS8_EXPORT_PARAMS { + hCryptProv: HCRYPTPROV, + dwKeySpec: DWORD, + pszPrivateKeyObjId: LPSTR, + pEncryptPrivateKeyFunc: PCRYPT_ENCRYPT_PRIVATE_KEY_FUNC, + pVoidEncryptFunc: LPVOID, +}} +pub type PCRYPT_PKCS8_EXPORT_PARAMS = *mut CRYPT_PKCS8_EXPORT_PARAMS; +STRUCT!{struct CERT_INFO { + dwVersion: DWORD, + SerialNumber: CRYPT_INTEGER_BLOB, + SignatureAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Issuer: CERT_NAME_BLOB, + NotBefore: FILETIME, + NotAfter: FILETIME, + Subject: CERT_NAME_BLOB, + SubjectPublicKeyInfo: CERT_PUBLIC_KEY_INFO, + IssuerUniqueId: CRYPT_BIT_BLOB, + SubjectUniqueId: CRYPT_BIT_BLOB, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCERT_INFO = *mut CERT_INFO; +pub const CERT_V1: DWORD = 0; +pub const CERT_V2: DWORD = 1; +pub const CERT_V3: DWORD = 2; +pub const CERT_INFO_VERSION_FLAG: DWORD = 1; +pub const CERT_INFO_SERIAL_NUMBER_FLAG: DWORD = 2; +pub const CERT_INFO_SIGNATURE_ALGORITHM_FLAG: DWORD = 3; +pub const CERT_INFO_ISSUER_FLAG: DWORD = 4; +pub const CERT_INFO_NOT_BEFORE_FLAG: DWORD = 5; +pub const CERT_INFO_NOT_AFTER_FLAG: DWORD = 6; +pub const CERT_INFO_SUBJECT_FLAG: DWORD = 7; +pub const CERT_INFO_SUBJECT_PUBLIC_KEY_INFO_FLAG: DWORD = 8; +pub const CERT_INFO_ISSUER_UNIQUE_ID_FLAG: DWORD = 9; +pub const CERT_INFO_SUBJECT_UNIQUE_ID_FLAG: DWORD = 10; +pub const CERT_INFO_EXTENSION_FLAG: DWORD = 11; +STRUCT!{struct CRL_ENTRY { + SerialNumber: CRYPT_INTEGER_BLOB, + RevocationDate: FILETIME, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCRL_ENTRY = *mut CRL_ENTRY; +STRUCT!{struct CRL_INFO { + dwVersion: DWORD, + SignatureAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Issuer: CERT_NAME_BLOB, + ThisUpdate: FILETIME, + NextUpdate: FILETIME, + cCRLEntry: DWORD, + rgCRLEntry: PCRL_ENTRY, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCRL_INFO = *mut CRL_INFO; +pub const CRL_V1: DWORD = 0; +pub const CRL_V2: DWORD = 1; +pub const CERT_BUNDLE_CERTIFICATE: DWORD = 0; +pub const CERT_BUNDLE_CRL: DWORD = 1; +STRUCT!{struct CERT_OR_CRL_BLOB { + dwChoice: DWORD, + cbEncoded: DWORD, + pbEncoded: *mut BYTE, +}} +pub type PCERT_OR_CRL_BLOB = *mut CERT_OR_CRL_BLOB; +STRUCT!{struct CERT_OR_CRL_BUNDLE { + cItem: DWORD, + rgItem: PCERT_OR_CRL_BLOB, +}} +pub type PCERT_OR_CRL_BUNDLE = *mut CERT_OR_CRL_BUNDLE; +STRUCT!{struct CERT_REQUEST_INFO { + dwVersion: DWORD, + Subject: CERT_NAME_BLOB, + SubjectPublicKeyInfo: CERT_PUBLIC_KEY_INFO, + cAttribute: DWORD, + rgAttribute: PCRYPT_ATTRIBUTE, +}} +pub type PCERT_REQUEST_INFO = *mut CERT_REQUEST_INFO; +pub const CERT_REQUEST_V1: DWORD = 0; +STRUCT!{struct CERT_KEYGEN_REQUEST_INFO { + dwVersion: DWORD, + SubjectPublicKeyInfo: CERT_PUBLIC_KEY_INFO, + pwszChallengeString: LPWSTR, +}} +pub type PCERT_KEYGEN_REQUEST_INFO = *mut CERT_KEYGEN_REQUEST_INFO; +pub const CERT_KEYGEN_REQUEST_V1: DWORD = 0; +STRUCT!{struct CERT_SIGNED_CONTENT_INFO { + ToBeSigned: CRYPT_DER_BLOB, + SignatureAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Signature: CRYPT_BIT_BLOB, +}} +pub type PCERT_SIGNED_CONTENT_INFO = *mut CERT_SIGNED_CONTENT_INFO; +STRUCT!{struct CTL_USAGE { + cUsageIdentifier: DWORD, + rgpszUsageIdentifier: *mut LPSTR, +}} +pub type PCTL_USAGE = *mut CTL_USAGE; +pub type CERT_ENHKEY_USAGE = CTL_USAGE; +pub type PCERT_ENHKEY_USAGE = *mut CERT_ENHKEY_USAGE; +pub type PCCTL_USAGE = *const CTL_USAGE; +pub type PCCERT_ENHKEY_USAGE = *const CERT_ENHKEY_USAGE; +STRUCT!{struct CTL_ENTRY { + SubjectIdentifier: CRYPT_DATA_BLOB, + cAttribute: DWORD, + rgAttribute: PCRYPT_ATTRIBUTE, +}} +pub type PCTL_ENTRY = *mut CTL_ENTRY; +STRUCT!{struct CTL_INFO { + dwVersion: DWORD, + SubjectUsage: CTL_USAGE, + ListIdentifier: CRYPT_DATA_BLOB, + SequenceNumber: CRYPT_INTEGER_BLOB, + ThisUpdate: FILETIME, + NextUpdate: FILETIME, + SubjectAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + cCTLEntry: DWORD, + rgCTLEntry: PCTL_ENTRY, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCTL_INFO = *mut CTL_INFO; +pub const CTL_V1: DWORD = 0; +STRUCT!{struct CRYPT_TIME_STAMP_REQUEST_INFO { + pszTimeStampAlgorithm: LPSTR, + pszContentType: LPSTR, + Content: CRYPT_OBJID_BLOB, + cAttribute: DWORD, + rgAttribute: PCRYPT_ATTRIBUTE, +}} +pub type PCRYPT_TIME_STAMP_REQUEST_INFO = *mut CRYPT_TIME_STAMP_REQUEST_INFO; +STRUCT!{struct CRYPT_ENROLLMENT_NAME_VALUE_PAIR { + pwszName: LPWSTR, + pwszValue: LPWSTR, +}} +pub type PCRYPT_ENROLLMENT_NAME_VALUE_PAIR = *mut CRYPT_ENROLLMENT_NAME_VALUE_PAIR; +STRUCT!{struct CRYPT_CSP_PROVIDER { + dwKeySpec: DWORD, + pwszProviderName: LPWSTR, + Signature: CRYPT_BIT_BLOB, +}} +pub type PCRYPT_CSP_PROVIDER = *mut CRYPT_CSP_PROVIDER; +pub const CERT_ENCODING_TYPE_MASK: DWORD = 0x0000FFFF; +pub const CMSG_ENCODING_TYPE_MASK: DWORD = 0xFFFF0000; +#[inline] +pub fn GET_CERT_ENCODING_TYPE(X: DWORD) -> DWORD { + X & CERT_ENCODING_TYPE_MASK +} +#[inline] +pub fn GET_CMSG_ENCODING_TYPE(X: DWORD) -> DWORD { + X & CMSG_ENCODING_TYPE_MASK +} +pub const CRYPT_ASN_ENCODING: DWORD = 0x00000001; +pub const CRYPT_NDR_ENCODING: DWORD = 0x00000002; +pub const X509_ASN_ENCODING: DWORD = 0x00000001; +pub const X509_NDR_ENCODING: DWORD = 0x00000002; +pub const PKCS_7_ASN_ENCODING: DWORD = 0x00010000; +pub const PKCS_7_NDR_ENCODING: DWORD = 0x00020000; +extern "system" { + pub fn CryptFormatObject( + dwCertEncodingType: DWORD, + dwFormatType: DWORD, + dwFormatStrType: DWORD, + pFormatStruct: *mut c_void, + lpszStructType: LPCSTR, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + pbFormat: *mut c_void, + pcbFormat: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_FORMAT_STR_MULTI_LINE: DWORD = 0x0001; +pub const CRYPT_FORMAT_STR_NO_HEX: DWORD = 0x0010; +pub const CRYPT_FORMAT_SIMPLE: DWORD = 0x0001; +pub const CRYPT_FORMAT_X509: DWORD = 0x0002; +pub const CRYPT_FORMAT_OID: DWORD = 0x0004; +pub const CRYPT_FORMAT_RDN_SEMICOLON: DWORD = 0x0100; +pub const CRYPT_FORMAT_RDN_CRLF: DWORD = 0x0200; +pub const CRYPT_FORMAT_RDN_UNQUOTE: DWORD = 0x0400; +pub const CRYPT_FORMAT_RDN_REVERSE: DWORD = 0x0800; +pub const CRYPT_FORMAT_COMMA: DWORD = 0x1000; +pub const CRYPT_FORMAT_SEMICOLON: DWORD = CRYPT_FORMAT_RDN_SEMICOLON; +pub const CRYPT_FORMAT_CRLF: DWORD = CRYPT_FORMAT_RDN_CRLF; +FN!{stdcall PFN_CRYPT_ALLOC( + cbSize: size_t, +) -> LPVOID} +FN!{stdcall PFN_CRYPT_FREE( + pv: LPVOID, +) -> ()} +STRUCT!{struct CRYPT_ENCODE_PARA { + cbSize: DWORD, + pfnAlloc: PFN_CRYPT_ALLOC, + pfnFree: PFN_CRYPT_FREE, +}} +pub type PCRYPT_ENCODE_PARA = *mut CRYPT_ENCODE_PARA; +extern "system" { + pub fn CryptEncodeObjectEx( + dwCertEncodingType: DWORD, + lpszStructType: LPCSTR, + pvStructInfo: *const c_void, + dwFlags: DWORD, + pEncodePara: PCRYPT_ENCODE_PARA, + pvEncoded: *mut c_void, + pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptEncodeObject( + dwCertEncodingType: DWORD, + lpszStructType: LPCSTR, + pvStructInfo: *const c_void, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG: DWORD = 0x8; +pub const CRYPT_ENCODE_ALLOC_FLAG: DWORD = 0x8000; +pub const CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG: DWORD + = CERT_RDN_ENABLE_T61_UNICODE_FLAG; +pub const CRYPT_UNICODE_NAME_ENCODE_ENABLE_UTF8_UNICODE_FLAG: DWORD + = CERT_RDN_ENABLE_UTF8_UNICODE_FLAG; +pub const CRYPT_UNICODE_NAME_ENCODE_FORCE_UTF8_UNICODE_FLAG: DWORD + = CERT_RDN_FORCE_UTF8_UNICODE_FLAG; +pub const CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG: DWORD + = CERT_RDN_DISABLE_CHECK_TYPE_FLAG; +pub const CRYPT_SORTED_CTL_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG: DWORD = 0x10000; +pub const CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG: DWORD = 0x20000; +pub const CRYPT_ENCODE_ENABLE_UTF8PERCENT_FLAG: DWORD = 0x40000; +pub const CRYPT_ENCODE_ENABLE_IA5CONVERSION_FLAG: DWORD = CRYPT_ENCODE_ENABLE_PUNYCODE_FLAG + | CRYPT_ENCODE_ENABLE_UTF8PERCENT_FLAG; +STRUCT!{struct CRYPT_DECODE_PARA { + cbSize: DWORD, + pfnAlloc: PFN_CRYPT_ALLOC, + pfnFree: PFN_CRYPT_FREE, +}} +pub type PCRYPT_DECODE_PARA = *mut CRYPT_DECODE_PARA; +extern "system" { + pub fn CryptDecodeObjectEx( + dwCertEncodingType: DWORD, + lpszStructType: LPCSTR, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + dwFlags: DWORD, + pDecodePara: PCRYPT_DECODE_PARA, + pvStructInfo: *mut c_void, + pcbStructInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptDecodeObject( + dwCertEncodingType: DWORD, + lpszStructType: LPCSTR, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + dwFlags: DWORD, + pvStructInfo: *mut c_void, + pcbStructInfo: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_DECODE_NOCOPY_FLAG: DWORD = 0x1; +pub const CRYPT_DECODE_TO_BE_SIGNED_FLAG: DWORD = 0x2; +pub const CRYPT_DECODE_SHARE_OID_STRING_FLAG: DWORD = 0x4; +pub const CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG: DWORD = 0x8; +pub const CRYPT_DECODE_ALLOC_FLAG: DWORD = 0x8000; +pub const CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG: DWORD + = CERT_RDN_DISABLE_IE4_UTF8_FLAG; +pub const CRYPT_DECODE_ENABLE_PUNYCODE_FLAG: DWORD = 0x02000000; +pub const CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG: DWORD = 0x04000000; +pub const CRYPT_DECODE_ENABLE_IA5CONVERSION_FLAG: DWORD = CRYPT_DECODE_ENABLE_PUNYCODE_FLAG + | CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG; +pub const CRYPT_ENCODE_DECODE_NONE: LPCSTR = 0 as LPCSTR; +pub const X509_CERT: LPCSTR = 1 as LPCSTR; +pub const X509_CERT_TO_BE_SIGNED: LPCSTR = 2 as LPCSTR; +pub const X509_CERT_CRL_TO_BE_SIGNED: LPCSTR = 3 as LPCSTR; +pub const X509_CERT_REQUEST_TO_BE_SIGNED: LPCSTR = 4 as LPCSTR; +pub const X509_EXTENSIONS: LPCSTR = 5 as LPCSTR; +pub const X509_NAME_VALUE: LPCSTR = 6 as LPCSTR; +pub const X509_NAME: LPCSTR = 7 as LPCSTR; +pub const X509_PUBLIC_KEY_INFO: LPCSTR = 8 as LPCSTR; +pub const X509_AUTHORITY_KEY_ID: LPCSTR = 9 as LPCSTR; +pub const X509_KEY_ATTRIBUTES: LPCSTR = 10 as LPCSTR; +pub const X509_KEY_USAGE_RESTRICTION: LPCSTR = 11 as LPCSTR; +pub const X509_ALTERNATE_NAME: LPCSTR = 12 as LPCSTR; +pub const X509_BASIC_CONSTRAINTS: LPCSTR = 13 as LPCSTR; +pub const X509_KEY_USAGE: LPCSTR = 14 as LPCSTR; +pub const X509_BASIC_CONSTRAINTS2: LPCSTR = 15 as LPCSTR; +pub const X509_CERT_POLICIES: LPCSTR = 16 as LPCSTR; +pub const PKCS_UTC_TIME: LPCSTR = 17 as LPCSTR; +pub const PKCS_TIME_REQUEST: LPCSTR = 18 as LPCSTR; +pub const RSA_CSP_PUBLICKEYBLOB: LPCSTR = 19 as LPCSTR; +pub const X509_UNICODE_NAME: LPCSTR = 20 as LPCSTR; +pub const X509_KEYGEN_REQUEST_TO_BE_SIGNED: LPCSTR = 21 as LPCSTR; +pub const PKCS_ATTRIBUTE: LPCSTR = 22 as LPCSTR; +pub const PKCS_CONTENT_INFO_SEQUENCE_OF_ANY: LPCSTR = 23 as LPCSTR; +pub const X509_UNICODE_NAME_VALUE: LPCSTR = 24 as LPCSTR; +pub const X509_ANY_STRING: LPCSTR = X509_NAME_VALUE; +pub const X509_UNICODE_ANY_STRING: LPCSTR = X509_UNICODE_NAME_VALUE; +pub const X509_OCTET_STRING: LPCSTR = 25 as LPCSTR; +pub const X509_BITS: LPCSTR = 26 as LPCSTR; +pub const X509_INTEGER: LPCSTR = 27 as LPCSTR; +pub const X509_MULTI_BYTE_INTEGER: LPCSTR = 28 as LPCSTR; +pub const X509_ENUMERATED: LPCSTR = 29 as LPCSTR; +pub const X509_CHOICE_OF_TIME: LPCSTR = 30 as LPCSTR; +pub const X509_AUTHORITY_KEY_ID2: LPCSTR = 31 as LPCSTR; +pub const X509_AUTHORITY_INFO_ACCESS: LPCSTR = 32 as LPCSTR; +pub const X509_SUBJECT_INFO_ACCESS: LPCSTR = X509_AUTHORITY_INFO_ACCESS; +pub const X509_CRL_REASON_CODE: LPCSTR = X509_ENUMERATED; +pub const PKCS_CONTENT_INFO: LPCSTR = 33 as LPCSTR; +pub const X509_SEQUENCE_OF_ANY: LPCSTR = 34 as LPCSTR; +pub const X509_CRL_DIST_POINTS: LPCSTR = 35 as LPCSTR; +pub const X509_ENHANCED_KEY_USAGE: LPCSTR = 36 as LPCSTR; +pub const PKCS_CTL: LPCSTR = 37 as LPCSTR; +pub const X509_MULTI_BYTE_UINT: LPCSTR = 38 as LPCSTR; +pub const X509_DSS_PUBLICKEY: LPCSTR = X509_MULTI_BYTE_UINT; +pub const X509_DSS_PARAMETERS: LPCSTR = 39 as LPCSTR; +pub const X509_DSS_SIGNATURE: LPCSTR = 40 as LPCSTR; +pub const PKCS_RC2_CBC_PARAMETERS: LPCSTR = 41 as LPCSTR; +pub const PKCS_SMIME_CAPABILITIES: LPCSTR = 42 as LPCSTR; +pub const X509_QC_STATEMENTS_EXT: LPCSTR = 42 as LPCSTR; +pub const PKCS_RSA_PRIVATE_KEY: LPCSTR = 43 as LPCSTR; +pub const PKCS_PRIVATE_KEY_INFO: LPCSTR = 44 as LPCSTR; +pub const PKCS_ENCRYPTED_PRIVATE_KEY_INFO: LPCSTR = 45 as LPCSTR; +pub const X509_PKIX_POLICY_QUALIFIER_USERNOTICE: LPCSTR = 46 as LPCSTR; +pub const X509_DH_PUBLICKEY: LPCSTR = X509_MULTI_BYTE_UINT; +pub const X509_DH_PARAMETERS: LPCSTR = 47 as LPCSTR; +pub const PKCS_ATTRIBUTES: LPCSTR = 48 as LPCSTR; +pub const PKCS_SORTED_CTL: LPCSTR = 49 as LPCSTR; +pub const X509_ECC_SIGNATURE: LPCSTR = 47 as LPCSTR; +pub const X942_DH_PARAMETERS: LPCSTR = 50 as LPCSTR; +pub const X509_BITS_WITHOUT_TRAILING_ZEROES: LPCSTR = 51 as LPCSTR; +pub const X942_OTHER_INFO: LPCSTR = 52 as LPCSTR; +pub const X509_CERT_PAIR: LPCSTR = 53 as LPCSTR; +pub const X509_ISSUING_DIST_POINT: LPCSTR = 54 as LPCSTR; +pub const X509_NAME_CONSTRAINTS: LPCSTR = 55 as LPCSTR; +pub const X509_POLICY_MAPPINGS: LPCSTR = 56 as LPCSTR; +pub const X509_POLICY_CONSTRAINTS: LPCSTR = 57 as LPCSTR; +pub const X509_CROSS_CERT_DIST_POINTS: LPCSTR = 58 as LPCSTR; +pub const CMC_DATA: LPCSTR = 59 as LPCSTR; +pub const CMC_RESPONSE: LPCSTR = 60 as LPCSTR; +pub const CMC_STATUS: LPCSTR = 61 as LPCSTR; +pub const CMC_ADD_EXTENSIONS: LPCSTR = 62 as LPCSTR; +pub const CMC_ADD_ATTRIBUTES: LPCSTR = 63 as LPCSTR; +pub const X509_CERTIFICATE_TEMPLATE: LPCSTR = 64 as LPCSTR; +pub const OCSP_SIGNED_REQUEST: LPCSTR = 65 as LPCSTR; +pub const OCSP_REQUEST: LPCSTR = 66 as LPCSTR; +pub const OCSP_RESPONSE: LPCSTR = 67 as LPCSTR; +pub const OCSP_BASIC_SIGNED_RESPONSE: LPCSTR = 68 as LPCSTR; +pub const OCSP_BASIC_RESPONSE: LPCSTR = 69 as LPCSTR; +pub const X509_LOGOTYPE_EXT: LPCSTR = 70 as LPCSTR; +pub const X509_BIOMETRIC_EXT: LPCSTR = 71 as LPCSTR; +pub const CNG_RSA_PUBLIC_KEY_BLOB: LPCSTR = 72 as LPCSTR; +pub const X509_OBJECT_IDENTIFIER: LPCSTR = 73 as LPCSTR; +pub const X509_ALGORITHM_IDENTIFIER: LPCSTR = 74 as LPCSTR; +pub const PKCS_RSA_SSA_PSS_PARAMETERS: LPCSTR = 75 as LPCSTR; +pub const PKCS_RSAES_OAEP_PARAMETERS: LPCSTR = 76 as LPCSTR; +pub const ECC_CMS_SHARED_INFO: LPCSTR = 77 as LPCSTR; +pub const TIMESTAMP_REQUEST: LPCSTR = 78 as LPCSTR; +pub const TIMESTAMP_RESPONSE: LPCSTR = 79 as LPCSTR; +pub const TIMESTAMP_INFO: LPCSTR = 80 as LPCSTR; +pub const X509_CERT_BUNDLE: LPCSTR = 81 as LPCSTR; +pub const X509_ECC_PRIVATE_KEY: LPCSTR = 82 as LPCSTR; +pub const CNG_RSA_PRIVATE_KEY_BLOB: LPCSTR = 83 as LPCSTR; +pub const X509_SUBJECT_DIR_ATTRS: LPCSTR = 84 as LPCSTR; +pub const X509_ECC_PARAMETERS: LPCSTR = 85 as LPCSTR; +pub const PKCS7_SIGNER_INFO: LPCSTR = 500 as LPCSTR; +pub const CMS_SIGNER_INFO: LPCSTR = 501 as LPCSTR; +pub const szOID_AUTHORITY_KEY_IDENTIFIER: &'static str = "2.5.29.1"; +pub const szOID_KEY_ATTRIBUTES: &'static str = "2.5.29.2"; +pub const szOID_CERT_POLICIES_95: &'static str = "2.5.29.3"; +pub const szOID_KEY_USAGE_RESTRICTION: &'static str = "2.5.29.4"; +pub const szOID_SUBJECT_ALT_NAME: &'static str = "2.5.29.7"; +pub const szOID_ISSUER_ALT_NAME: &'static str = "2.5.29.8"; +pub const szOID_BASIC_CONSTRAINTS: &'static str = "2.5.29.10"; +pub const szOID_KEY_USAGE: &'static str = "2.5.29.15"; +pub const szOID_PRIVATEKEY_USAGE_PERIOD: &'static str = "2.5.29.16"; +pub const szOID_BASIC_CONSTRAINTS2: &'static str = "2.5.29.19"; +pub const szOID_CERT_POLICIES: &'static str = "2.5.29.32"; +pub const szOID_ANY_CERT_POLICY: &'static str = "2.5.29.32.0"; +pub const szOID_INHIBIT_ANY_POLICY: &'static str = "2.5.29.54"; +pub const szOID_AUTHORITY_KEY_IDENTIFIER2: &'static str = "2.5.29.35"; +pub const szOID_SUBJECT_KEY_IDENTIFIER: &'static str = "2.5.29.14"; +pub const szOID_SUBJECT_ALT_NAME2: &'static str = "2.5.29.17"; +pub const szOID_ISSUER_ALT_NAME2: &'static str = "2.5.29.18"; +pub const szOID_CRL_REASON_CODE: &'static str = "2.5.29.21"; +pub const szOID_REASON_CODE_HOLD: &'static str = "2.5.29.23"; +pub const szOID_CRL_DIST_POINTS: &'static str = "2.5.29.31"; +pub const szOID_ENHANCED_KEY_USAGE: &'static str = "2.5.29.37"; +pub const szOID_ANY_ENHANCED_KEY_USAGE: &'static str = "2.5.29.37.0"; +pub const szOID_CRL_NUMBER: &'static str = "2.5.29.20"; +pub const szOID_DELTA_CRL_INDICATOR: &'static str = "2.5.29.27"; +pub const szOID_ISSUING_DIST_POINT: &'static str = "2.5.29.28"; +pub const szOID_FRESHEST_CRL: &'static str = "2.5.29.46"; +pub const szOID_NAME_CONSTRAINTS: &'static str = "2.5.29.30"; +pub const szOID_POLICY_MAPPINGS: &'static str = "2.5.29.33"; +pub const szOID_LEGACY_POLICY_MAPPINGS: &'static str = "2.5.29.5"; +pub const szOID_POLICY_CONSTRAINTS: &'static str = "2.5.29.36"; +pub const szOID_RENEWAL_CERTIFICATE: &'static str = "1.3.6.1.4.1.311.13.1"; +pub const szOID_ENROLLMENT_NAME_VALUE_PAIR: &'static str = "1.3.6.1.4.1.311.13.2.1"; +pub const szOID_ENROLLMENT_CSP_PROVIDER: &'static str = "1.3.6.1.4.1.311.13.2.2"; +pub const szOID_OS_VERSION: &'static str = "1.3.6.1.4.1.311.13.2.3"; +pub const szOID_ENROLLMENT_AGENT: &'static str = "1.3.6.1.4.1.311.20.2.1"; +pub const szOID_PKIX: &'static str = "1.3.6.1.5.5.7"; +pub const szOID_PKIX_PE: &'static str = "1.3.6.1.5.5.7.1"; +pub const szOID_AUTHORITY_INFO_ACCESS: &'static str = "1.3.6.1.5.5.7.1.1"; +pub const szOID_SUBJECT_INFO_ACCESS: &'static str = "1.3.6.1.5.5.7.1.11"; +pub const szOID_BIOMETRIC_EXT: &'static str = "1.3.6.1.5.5.7.1.2"; +pub const szOID_QC_STATEMENTS_EXT: &'static str = "1.3.6.1.5.5.7.1.3"; +pub const szOID_LOGOTYPE_EXT: &'static str = "1.3.6.1.5.5.7.1.12"; +pub const szOID_TLS_FEATURES_EXT: &'static str = "1.3.6.1.5.5.7.1.24"; +pub const szOID_CERT_EXTENSIONS: &'static str = "1.3.6.1.4.1.311.2.1.14"; +pub const szOID_NEXT_UPDATE_LOCATION: &'static str = "1.3.6.1.4.1.311.10.2"; +pub const szOID_REMOVE_CERTIFICATE: &'static str = "1.3.6.1.4.1.311.10.8.1"; +pub const szOID_CROSS_CERT_DIST_POINTS: &'static str = "1.3.6.1.4.1.311.10.9.1"; +pub const szOID_CTL: &'static str = "1.3.6.1.4.1.311.10.1"; +pub const szOID_SORTED_CTL: &'static str = "1.3.6.1.4.1.311.10.1.1"; +pub const szOID_SERIALIZED: &'static str = "1.3.6.1.4.1.311.10.3.3.1"; +pub const szOID_NT_PRINCIPAL_NAME: &'static str = "1.3.6.1.4.1.311.20.2.3"; +pub const szOID_INTERNATIONALIZED_EMAIL_ADDRESS: &'static str = "1.3.6.1.4.1.311.20.2.4"; +pub const szOID_PRODUCT_UPDATE: &'static str = "1.3.6.1.4.1.311.31.1"; +pub const szOID_ANY_APPLICATION_POLICY: &'static str = "1.3.6.1.4.1.311.10.12.1"; +pub const szOID_AUTO_ENROLL_CTL_USAGE: &'static str = "1.3.6.1.4.1.311.20.1"; +pub const szOID_ENROLL_CERTTYPE_EXTENSION: &'static str = "1.3.6.1.4.1.311.20.2"; +pub const szOID_CERT_MANIFOLD: &'static str = "1.3.6.1.4.1.311.20.3"; +pub const szOID_CERTSRV_CA_VERSION: &'static str = "1.3.6.1.4.1.311.21.1"; +pub const szOID_CERTSRV_PREVIOUS_CERT_HASH: &'static str = "1.3.6.1.4.1.311.21.2"; +pub const szOID_CRL_VIRTUAL_BASE: &'static str = "1.3.6.1.4.1.311.21.3"; +pub const szOID_CRL_NEXT_PUBLISH: &'static str = "1.3.6.1.4.1.311.21.4"; +pub const szOID_KP_CA_EXCHANGE: &'static str = "1.3.6.1.4.1.311.21.5"; +pub const szOID_KP_PRIVACY_CA: &'static str = "1.3.6.1.4.1.311.21.36"; +pub const szOID_KP_KEY_RECOVERY_AGENT: &'static str = "1.3.6.1.4.1.311.21.6"; +pub const szOID_CERTIFICATE_TEMPLATE: &'static str = "1.3.6.1.4.1.311.21.7"; +pub const szOID_ENTERPRISE_OID_ROOT: &'static str = "1.3.6.1.4.1.311.21.8"; +pub const szOID_RDN_DUMMY_SIGNER: &'static str = "1.3.6.1.4.1.311.21.9"; +pub const szOID_APPLICATION_CERT_POLICIES: &'static str = "1.3.6.1.4.1.311.21.10"; +pub const szOID_APPLICATION_POLICY_MAPPINGS: &'static str = "1.3.6.1.4.1.311.21.11"; +pub const szOID_APPLICATION_POLICY_CONSTRAINTS: &'static str = "1.3.6.1.4.1.311.21.12"; +pub const szOID_ARCHIVED_KEY_ATTR: &'static str = "1.3.6.1.4.1.311.21.13"; +pub const szOID_CRL_SELF_CDP: &'static str = "1.3.6.1.4.1.311.21.14"; +pub const szOID_REQUIRE_CERT_CHAIN_POLICY: &'static str = "1.3.6.1.4.1.311.21.15"; +pub const szOID_ARCHIVED_KEY_CERT_HASH: &'static str = "1.3.6.1.4.1.311.21.16"; +pub const szOID_ISSUED_CERT_HASH: &'static str = "1.3.6.1.4.1.311.21.17"; +pub const szOID_DS_EMAIL_REPLICATION: &'static str = "1.3.6.1.4.1.311.21.19"; +pub const szOID_REQUEST_CLIENT_INFO: &'static str = "1.3.6.1.4.1.311.21.20"; +pub const szOID_ENCRYPTED_KEY_HASH: &'static str = "1.3.6.1.4.1.311.21.21"; +pub const szOID_CERTSRV_CROSSCA_VERSION: &'static str = "1.3.6.1.4.1.311.21.22"; +pub const szOID_NTDS_REPLICATION: &'static str = "1.3.6.1.4.1.311.25.1"; +pub const szOID_SUBJECT_DIR_ATTRS: &'static str = "2.5.29.9"; +pub const szOID_PKIX_KP: &'static str = "1.3.6.1.5.5.7.3"; +pub const szOID_PKIX_KP_SERVER_AUTH: &'static str = "1.3.6.1.5.5.7.3.1"; +pub const szOID_PKIX_KP_CLIENT_AUTH: &'static str = "1.3.6.1.5.5.7.3.2"; +pub const szOID_PKIX_KP_CODE_SIGNING: &'static str = "1.3.6.1.5.5.7.3.3"; +pub const szOID_PKIX_KP_EMAIL_PROTECTION: &'static str = "1.3.6.1.5.5.7.3.4"; +pub const szOID_PKIX_KP_IPSEC_END_SYSTEM: &'static str = "1.3.6.1.5.5.7.3.5"; +pub const szOID_PKIX_KP_IPSEC_TUNNEL: &'static str = "1.3.6.1.5.5.7.3.6"; +pub const szOID_PKIX_KP_IPSEC_USER: &'static str = "1.3.6.1.5.5.7.3.7"; +pub const szOID_PKIX_KP_TIMESTAMP_SIGNING: &'static str = "1.3.6.1.5.5.7.3.8"; +pub const szOID_PKIX_KP_OCSP_SIGNING: &'static str = "1.3.6.1.5.5.7.3.9"; +pub const szOID_PKIX_OCSP_NOCHECK: &'static str = "1.3.6.1.5.5.7.48.1.5"; +pub const szOID_PKIX_OCSP_NONCE: &'static str = "1.3.6.1.5.5.7.48.1.2"; +pub const szOID_IPSEC_KP_IKE_INTERMEDIATE: &'static str = "1.3.6.1.5.5.8.2.2"; +pub const szOID_PKINIT_KP_KDC: &'static str = "1.3.6.1.5.2.3.5"; +pub const szOID_KP_CTL_USAGE_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.1"; +pub const szOID_KP_TIME_STAMP_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.2"; +pub const szOID_SERVER_GATED_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.3"; +pub const szOID_SGC_NETSCAPE: &'static str = "2.16.840.1.113730.4.1"; +pub const szOID_KP_EFS: &'static str = "1.3.6.1.4.1.311.10.3.4"; +pub const szOID_EFS_RECOVERY: &'static str = "1.3.6.1.4.1.311.10.3.4.1"; +pub const szOID_WHQL_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.5"; +pub const szOID_ATTEST_WHQL_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.5.1"; +pub const szOID_NT5_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.6"; +pub const szOID_OEM_WHQL_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.7"; +pub const szOID_EMBEDDED_NT_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.8"; +pub const szOID_ROOT_LIST_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.9"; +pub const szOID_KP_QUALIFIED_SUBORDINATION: &'static str = "1.3.6.1.4.1.311.10.3.10"; +pub const szOID_KP_KEY_RECOVERY: &'static str = "1.3.6.1.4.1.311.10.3.11"; +pub const szOID_KP_DOCUMENT_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.12"; +pub const szOID_KP_LIFETIME_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.13"; +pub const szOID_KP_MOBILE_DEVICE_SOFTWARE: &'static str = "1.3.6.1.4.1.311.10.3.14"; +pub const szOID_KP_SMART_DISPLAY: &'static str = "1.3.6.1.4.1.311.10.3.15"; +pub const szOID_KP_CSP_SIGNATURE: &'static str = "1.3.6.1.4.1.311.10.3.16"; +pub const szOID_KP_FLIGHT_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.27"; +pub const szOID_PLATFORM_MANIFEST_BINARY_ID: &'static str = "1.3.6.1.4.1.311.10.3.28"; +pub const szOID_DRM: &'static str = "1.3.6.1.4.1.311.10.5.1"; +pub const szOID_DRM_INDIVIDUALIZATION: &'static str = "1.3.6.1.4.1.311.10.5.2"; +pub const szOID_LICENSES: &'static str = "1.3.6.1.4.1.311.10.6.1"; +pub const szOID_LICENSE_SERVER: &'static str = "1.3.6.1.4.1.311.10.6.2"; +pub const szOID_KP_SMARTCARD_LOGON: &'static str = "1.3.6.1.4.1.311.20.2.2"; +pub const szOID_KP_KERNEL_MODE_CODE_SIGNING: &'static str = "1.3.6.1.4.1.311.61.1.1"; +pub const szOID_KP_KERNEL_MODE_TRUSTED_BOOT_SIGNING: &'static str = "1.3.6.1.4.1.311.61.4.1"; +pub const szOID_REVOKED_LIST_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.19"; +pub const szOID_WINDOWS_KITS_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.20"; +pub const szOID_WINDOWS_RT_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.21"; +pub const szOID_PROTECTED_PROCESS_LIGHT_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.22"; +pub const szOID_WINDOWS_TCB_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.23"; +pub const szOID_PROTECTED_PROCESS_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.24"; +pub const szOID_WINDOWS_THIRD_PARTY_COMPONENT_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.25"; +pub const szOID_WINDOWS_SOFTWARE_EXTENSION_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.26"; +pub const szOID_DISALLOWED_LIST: &'static str = "1.3.6.1.4.1.311.10.3.30"; +pub const szOID_PIN_RULES_SIGNER: &'static str = "1.3.6.1.4.1.311.10.3.31"; +pub const szOID_PIN_RULES_CTL: &'static str = "1.3.6.1.4.1.311.10.3.32"; +pub const szOID_PIN_RULES_EXT: &'static str = "1.3.6.1.4.1.311.10.3.33"; +pub const szOID_PIN_RULES_DOMAIN_NAME: &'static str = "1.3.6.1.4.1.311.10.3.34"; +pub const szOID_PIN_RULES_LOG_END_DATE_EXT: &'static str = "1.3.6.1.4.1.311.10.3.35"; +pub const szOID_IUM_SIGNING: &'static str = "1.3.6.1.4.1.311.10.3.37"; +pub const szOID_EV_WHQL_CRYPTO: &'static str = "1.3.6.1.4.1.311.10.3.39"; +pub const szOID_SYNC_ROOT_CTL_EXT: &'static str = "1.3.6.1.4.1.311.10.3.50"; +pub const szOID_HPKP_DOMAIN_NAME_CTL: &'static str = "1.3.6.1.4.1.311.10.3.60"; +pub const szOID_HPKP_HEADER_VALUE_CTL: &'static str = "1.3.6.1.4.1.311.10.3.61"; +pub const szOID_KP_KERNEL_MODE_HAL_EXTENSION_SIGNING: &'static str = "1.3.6.1.4.1.311.61.5.1"; +pub const szOID_WINDOWS_STORE_SIGNER: &'static str = "1.3.6.1.4.1.311.76.3.1"; +pub const szOID_DYNAMIC_CODE_GEN_SIGNER: &'static str = "1.3.6.1.4.1.311.76.5.1"; +pub const szOID_MICROSOFT_PUBLISHER_SIGNER: &'static str = "1.3.6.1.4.1.311.76.8.1"; +pub const szOID_YESNO_TRUST_ATTR: &'static str = "1.3.6.1.4.1.311.10.4.1"; +pub const szOID_SITE_PIN_RULES_INDEX_ATTR: &'static str = "1.3.6.1.4.1.311.10.4.2"; +pub const szOID_SITE_PIN_RULES_FLAGS_ATTR: &'static str = "1.3.6.1.4.1.311.10.4.3"; +pub const szOID_PKIX_POLICY_QUALIFIER_CPS: &'static str = "1.3.6.1.5.5.7.2.1"; +pub const szOID_PKIX_POLICY_QUALIFIER_USERNOTICE: &'static str = "1.3.6.1.5.5.7.2.2"; +pub const szOID_ROOT_PROGRAM_FLAGS: &'static str = "1.3.6.1.4.1.311.60.1.1"; +pub const CERT_ROOT_PROGRAM_FLAG_ORG: DWORD = 0x80; +pub const CERT_ROOT_PROGRAM_FLAG_LSC: DWORD = 0x40; +pub const CERT_ROOT_PROGRAM_FLAG_SUBJECT_LOGO: DWORD = 0x20; +pub const CERT_ROOT_PROGRAM_FLAG_OU: DWORD = 0x10; +pub const CERT_ROOT_PROGRAM_FLAG_ADDRESS: DWORD = 0x08; +pub const szOID_CERT_POLICIES_95_QUALIFIER1: &'static str = "2.16.840.1.113733.1.7.1.1"; +pub const szOID_RDN_TPM_MANUFACTURER: &'static str = "2.23.133.2.1"; +pub const szOID_RDN_TPM_MODEL: &'static str = "2.23.133.2.2"; +pub const szOID_RDN_TPM_VERSION: &'static str = "2.23.133.2.3"; +pub const szOID_RDN_TCG_PLATFORM_MANUFACTURER: &'static str = "2.23.133.2.4"; +pub const szOID_RDN_TCG_PLATFORM_MODEL: &'static str = "2.23.133.2.5"; +pub const szOID_RDN_TCG_PLATFORM_VERSION: &'static str = "2.23.133.2.6"; +pub const szOID_ENROLL_EK_INFO: &'static str = "1.3.6.1.4.1.311.21.23"; +pub const szOID_ENROLL_AIK_INFO: &'static str = "1.3.6.1.4.1.311.21.39"; +pub const szOID_ENROLL_ATTESTATION_STATEMENT: &'static str = "1.3.6.1.4.1.311.21.24"; +pub const szOID_ENROLL_KSP_NAME: &'static str = "1.3.6.1.4.1.311.21.25"; +pub const szOID_ENROLL_EKPUB_CHALLENGE: &'static str = "1.3.6.1.4.1.311.21.26"; +pub const szOID_ENROLL_CAXCHGCERT_HASH: &'static str = "1.3.6.1.4.1.311.21.27"; +pub const szOID_ENROLL_ATTESTATION_CHALLENGE: &'static str = "1.3.6.1.4.1.311.21.28"; +pub const szOID_ENROLL_ENCRYPTION_ALGORITHM: &'static str = "1.3.6.1.4.1.311.21.29"; +pub const szOID_KP_TPM_EK_CERTIFICATE: &'static str = "2.23.133.8.1"; +pub const szOID_KP_TPM_PLATFORM_CERTIFICATE: &'static str = "2.23.133.8.2"; +pub const szOID_KP_TPM_AIK_CERTIFICATE: &'static str = "2.23.133.8.3"; +pub const szOID_ENROLL_EKVERIFYKEY: &'static str = "1.3.6.1.4.1.311.21.30"; +pub const szOID_ENROLL_EKVERIFYCERT: &'static str = "1.3.6.1.4.1.311.21.31"; +pub const szOID_ENROLL_EKVERIFYCREDS: &'static str = "1.3.6.1.4.1.311.21.32"; +pub const szOID_ENROLL_SCEP_ERROR: &'static str = "1.3.6.1.4.1.311.21.33"; +pub const szOID_ENROLL_SCEP_SERVER_STATE: &'static str = "1.3.6.1.4.1.311.21.34"; +pub const szOID_ENROLL_SCEP_CHALLENGE_ANSWER: &'static str = "1.3.6.1.4.1.311.21.35"; +pub const szOID_ENROLL_SCEP_CLIENT_REQUEST: &'static str = "1.3.6.1.4.1.311.21.37"; +pub const szOID_ENROLL_SCEP_SERVER_MESSAGE: &'static str = "1.3.6.1.4.1.311.21.38"; +pub const szOID_ENROLL_SCEP_SERVER_SECRET: &'static str = "1.3.6.1.4.1.311.21.40"; +pub const szOID_ENROLL_KEY_AFFINITY: &'static str = "1.3.6.1.4.1.311.21.41"; +pub const szOID_ENROLL_SCEP_SIGNER_HASH: &'static str = "1.3.6.1.4.1.311.21.42"; +pub const szOID_ENROLL_EK_CA_KEYID: &'static str = "1.3.6.1.4.1.311.21.43"; +pub const szOID_ATTR_SUPPORTED_ALGORITHMS: &'static str = "2.5.4.52"; +pub const szOID_ATTR_TPM_SPECIFICATION: &'static str = "2.23.133.2.16"; +pub const szOID_ATTR_PLATFORM_SPECIFICATION: &'static str = "2.23.133.2.17"; +pub const szOID_ATTR_TPM_SECURITY_ASSERTIONS: &'static str = "2.23.133.2.18"; +STRUCT!{struct CERT_EXTENSIONS { + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCERT_EXTENSIONS = *mut CERT_EXTENSIONS; +pub const CERT_UNICODE_RDN_ERR_INDEX_MASK: DWORD = 0x3FF; +pub const CERT_UNICODE_RDN_ERR_INDEX_SHIFT: DWORD = 22; +pub const CERT_UNICODE_ATTR_ERR_INDEX_MASK: DWORD = 0x003F; +pub const CERT_UNICODE_ATTR_ERR_INDEX_SHIFT: DWORD = 16; +pub const CERT_UNICODE_VALUE_ERR_INDEX_MASK: DWORD = 0x0000FFFF; +pub const CERT_UNICODE_VALUE_ERR_INDEX_SHIFT: DWORD = 0; +#[inline] +pub fn GET_CERT_UNICODE_RDN_ERR_INDEX(X: DWORD) -> DWORD { + (X >> CERT_UNICODE_RDN_ERR_INDEX_SHIFT) & CERT_UNICODE_RDN_ERR_INDEX_MASK +} +#[inline] +pub fn GET_CERT_UNICODE_ATTR_ERR_INDEX(X: DWORD) -> DWORD { + (X >> CERT_UNICODE_ATTR_ERR_INDEX_SHIFT) & CERT_UNICODE_ATTR_ERR_INDEX_MASK +} +#[inline] +pub fn GET_CERT_UNICODE_VALUE_ERR_INDEX(X: DWORD) -> DWORD { + X & CERT_UNICODE_VALUE_ERR_INDEX_MASK +} +STRUCT!{struct CERT_AUTHORITY_KEY_ID_INFO { + KeyId: CRYPT_DATA_BLOB, + CertIssuer: CERT_NAME_BLOB, + CertSerialNumber: CRYPT_INTEGER_BLOB, +}} +pub type PCERT_AUTHORITY_KEY_ID_INFO = *mut CERT_AUTHORITY_KEY_ID_INFO; +STRUCT!{struct CERT_PRIVATE_KEY_VALIDITY { + NotBefore: FILETIME, + NotAfter: FILETIME, +}} +pub type PCERT_PRIVATE_KEY_VALIDITY = *mut CERT_PRIVATE_KEY_VALIDITY; +STRUCT!{struct CERT_KEY_ATTRIBUTES_INFO { + KeyId: CRYPT_DATA_BLOB, + IntendedKeyUsage: CRYPT_BIT_BLOB, + pPrivateKeyUsagePeriod: PCERT_PRIVATE_KEY_VALIDITY, +}} +pub type PCERT_KEY_ATTRIBUTES_INFO = *mut CERT_KEY_ATTRIBUTES_INFO; +pub const CERT_DIGITAL_SIGNATURE_KEY_USAGE: DWORD = 0x80; +pub const CERT_NON_REPUDIATION_KEY_USAGE: DWORD = 0x40; +pub const CERT_KEY_ENCIPHERMENT_KEY_USAGE: DWORD = 0x20; +pub const CERT_DATA_ENCIPHERMENT_KEY_USAGE: DWORD = 0x10; +pub const CERT_KEY_AGREEMENT_KEY_USAGE: DWORD = 0x08; +pub const CERT_KEY_CERT_SIGN_KEY_USAGE: DWORD = 0x04; +pub const CERT_OFFLINE_CRL_SIGN_KEY_USAGE: DWORD = 0x02; +pub const CERT_CRL_SIGN_KEY_USAGE: DWORD = 0x02; +pub const CERT_ENCIPHER_ONLY_KEY_USAGE: DWORD = 0x01; +pub const CERT_DECIPHER_ONLY_KEY_USAGE: DWORD = 0x80; +STRUCT!{struct CERT_POLICY_ID { + cCertPolicyElementId: DWORD, + rgpszCertPolicyElementId: *mut LPSTR, +}} +pub type PCERT_POLICY_ID = *mut CERT_POLICY_ID; +STRUCT!{struct CERT_KEY_USAGE_RESTRICTION_INFO { + cCertPolicyId: DWORD, + rgCertPolicyId: PCERT_POLICY_ID, + RestrictedKeyUsage: CRYPT_BIT_BLOB, +}} +pub type PCERT_KEY_USAGE_RESTRICTION_INFO = *mut CERT_KEY_USAGE_RESTRICTION_INFO; +STRUCT!{struct CERT_OTHER_NAME { + pszObjId: LPSTR, + Value: CRYPT_OBJID_BLOB, +}} +pub type PCERT_OTHER_NAME = *mut CERT_OTHER_NAME; +UNION!{union CERT_ALT_NAME_ENTRY_u { + [usize; 2], + pOtherName pOtherName_mut: PCERT_OTHER_NAME, + pwszRfc822Name pwszRfc822Name_mut: LPWSTR, + pwszDNSName pwszDNSName_mut: LPWSTR, + DirectoryName DirectoryName_mut: CERT_NAME_BLOB, + pwszURL pwszURL_mut: LPWSTR, + IPAddress IPAddress_mut: CRYPT_DATA_BLOB, + pszRegisteredID pszRegisteredID_mut: LPSTR, +}} +STRUCT!{struct CERT_ALT_NAME_ENTRY { + dwAltNameChoice: DWORD, + u: CERT_ALT_NAME_ENTRY_u, +}} +pub type PCERT_ALT_NAME_ENTRY = *mut CERT_ALT_NAME_ENTRY; +pub const CERT_ALT_NAME_OTHER_NAME: DWORD = 1; +pub const CERT_ALT_NAME_RFC822_NAME: DWORD = 2; +pub const CERT_ALT_NAME_DNS_NAME: DWORD = 3; +pub const CERT_ALT_NAME_X400_ADDRESS: DWORD = 4; +pub const CERT_ALT_NAME_DIRECTORY_NAME: DWORD = 5; +pub const CERT_ALT_NAME_EDI_PARTY_NAME: DWORD = 6; +pub const CERT_ALT_NAME_URL: DWORD = 7; +pub const CERT_ALT_NAME_IP_ADDRESS: DWORD = 8; +pub const CERT_ALT_NAME_REGISTERED_ID: DWORD = 9; +STRUCT!{struct CERT_ALT_NAME_INFO { + cAltEntry: DWORD, + rgAltEntry: PCERT_ALT_NAME_ENTRY, +}} +pub type PCERT_ALT_NAME_INFO = *mut CERT_ALT_NAME_INFO; +pub const CERT_ALT_NAME_ENTRY_ERR_INDEX_MASK: DWORD = 0xFF; +pub const CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT: DWORD = 16; +pub const CERT_ALT_NAME_VALUE_ERR_INDEX_MASK: DWORD = 0x0000FFFF; +pub const CERT_ALT_NAME_VALUE_ERR_INDEX_SHIFT: DWORD = 0; +#[inline] +pub fn GET_CERT_ALT_NAME_ENTRY_ERR_INDEX(X: DWORD) -> DWORD { + (X >> CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT) & CERT_ALT_NAME_ENTRY_ERR_INDEX_MASK +} +#[inline] +pub fn GET_CERT_ALT_NAME_VALUE_ERR_INDEX(X: DWORD) -> DWORD { + X & CERT_ALT_NAME_VALUE_ERR_INDEX_MASK +} +STRUCT!{struct CERT_BASIC_CONSTRAINTS_INFO { + SubjectType: CRYPT_BIT_BLOB, + fPathLenConstraint: BOOL, + dwPathLenConstraint: DWORD, + cSubtreesConstraint: DWORD, + rgSubtreesConstraint: *mut CERT_NAME_BLOB, +}} +pub type PCERT_BASIC_CONSTRAINTS_INFO = *mut CERT_BASIC_CONSTRAINTS_INFO; +pub const CERT_CA_SUBJECT_FLAG: DWORD = 0x80; +pub const CERT_END_ENTITY_SUBJECT_FLAG: DWORD = 0x40; +STRUCT!{struct CERT_BASIC_CONSTRAINTS2_INFO { + fCA: BOOL, + fPathLenConstraint: BOOL, + dwPathLenConstraint: DWORD, +}} +pub type PCERT_BASIC_CONSTRAINTS2_INFO = *mut CERT_BASIC_CONSTRAINTS2_INFO; +STRUCT!{struct CERT_POLICY_QUALIFIER_INFO { + pszPolicyQualifierId: LPSTR, + Qualifier: CRYPT_OBJID_BLOB, +}} +pub type PCERT_POLICY_QUALIFIER_INFO = *mut CERT_POLICY_QUALIFIER_INFO; +STRUCT!{struct CERT_POLICY_INFO { + pszPolicyIdentifier: LPSTR, + cPolicyQualifier: DWORD, + rgPolicyQualifier: *mut CERT_POLICY_QUALIFIER_INFO, +}} +pub type PCERT_POLICY_INFO = *mut CERT_POLICY_INFO; +STRUCT!{struct CERT_POLICIES_INFO { + cPolicyInfo: DWORD, + rgPolicyInfo: *mut CERT_POLICY_INFO, +}} +pub type PCERT_POLICIES_INFO = *mut CERT_POLICIES_INFO; +STRUCT!{struct CERT_POLICY_QUALIFIER_NOTICE_REFERENCE { + pszOrganization: LPSTR, + cNoticeNumbers: DWORD, + rgNoticeNumbers: *mut c_int, +}} +pub type PCERT_POLICY_QUALIFIER_NOTICE_REFERENCE = *mut CERT_POLICY_QUALIFIER_NOTICE_REFERENCE; +STRUCT!{struct CERT_POLICY_QUALIFIER_USER_NOTICE { + pNoticeReference: *mut CERT_POLICY_QUALIFIER_NOTICE_REFERENCE, + pszDisplayText: LPWSTR, +}} +pub type PCERT_POLICY_QUALIFIER_USER_NOTICE = *mut CERT_POLICY_QUALIFIER_USER_NOTICE; +STRUCT!{struct CPS_URLS { + pszURL: LPWSTR, + pAlgorithm: *mut CRYPT_ALGORITHM_IDENTIFIER, + pDigest: *mut CRYPT_DATA_BLOB, +}} +pub type PCPS_URLS = *mut CPS_URLS; +STRUCT!{struct CERT_POLICY95_QUALIFIER1 { + pszPracticesReference: LPWSTR, + pszNoticeIdentifier: LPSTR, + pszNSINoticeIdentifier: LPSTR, + cCPSURLs: DWORD, + rgCPSURLs: *mut CPS_URLS, +}} +pub type PCERT_POLICY95_QUALIFIER1 = *mut CERT_POLICY95_QUALIFIER1; +STRUCT!{struct CERT_POLICY_MAPPING { + pszIssuerDomainPolicy: LPSTR, + pszSubjectDomainPolicy: LPSTR, +}} +pub type PCERT_POLICY_MAPPING = *mut CERT_POLICY_MAPPING; +STRUCT!{struct CERT_POLICY_MAPPINGS_INFO { + cPolicyMapping: DWORD, + rgPolicyMapping: PCERT_POLICY_MAPPING, +}} +pub type PCERT_POLICY_MAPPINGS_INFO = *mut CERT_POLICY_MAPPINGS_INFO; +STRUCT!{struct CERT_POLICY_CONSTRAINTS_INFO { + fRequireExplicitPolicy: BOOL, + dwRequireExplicitPolicySkipCerts: DWORD, + fInhibitPolicyMapping: BOOL, + dwInhibitPolicyMappingSkipCerts: DWORD, +}} +pub type PCERT_POLICY_CONSTRAINTS_INFO = *mut CERT_POLICY_CONSTRAINTS_INFO; +STRUCT!{struct CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY { + pszObjId: LPSTR, + cValue: DWORD, + rgValue: PCRYPT_DER_BLOB, +}} +pub type PCRYPT_CONTENT_INFO_SEQUENCE_OF_ANY = *mut CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY; +STRUCT!{struct CRYPT_CONTENT_INFO { + pszObjId: LPSTR, + Content: CRYPT_DER_BLOB, +}} +pub type PCRYPT_CONTENT_INFO = *mut CRYPT_CONTENT_INFO; +STRUCT!{struct CRYPT_SEQUENCE_OF_ANY { + cValue: DWORD, + rgValue: PCRYPT_DER_BLOB, +}} +pub type PCRYPT_SEQUENCE_OF_ANY = *mut CRYPT_SEQUENCE_OF_ANY; +STRUCT!{struct CERT_AUTHORITY_KEY_ID2_INFO { + KeyId: CRYPT_DATA_BLOB, + AuthorityCertIssuer: CERT_ALT_NAME_INFO, + AuthorityCertSerialNumber: CRYPT_INTEGER_BLOB, +}} +pub type PCERT_AUTHORITY_KEY_ID2_INFO = *mut CERT_AUTHORITY_KEY_ID2_INFO; +STRUCT!{struct CERT_ACCESS_DESCRIPTION { + pszAccessMethod: LPSTR, + AccessLocation: CERT_ALT_NAME_ENTRY, +}} +pub type PCERT_ACCESS_DESCRIPTION = *mut CERT_ACCESS_DESCRIPTION; +STRUCT!{struct CERT_AUTHORITY_INFO_ACCESS { + cAccDescr: DWORD, + rgAccDescr: PCERT_ACCESS_DESCRIPTION, +}} +pub type PCERT_AUTHORITY_INFO_ACCESS = *mut CERT_AUTHORITY_INFO_ACCESS; +pub type CERT_SUBJECT_INFO_ACCESS = CERT_AUTHORITY_INFO_ACCESS; +pub type PCERT_SUBJECT_INFO_ACCESS = *mut CERT_AUTHORITY_INFO_ACCESS; +pub const szOID_PKIX_ACC_DESCR: &'static str = "1.3.6.1.5.5.7.48"; +pub const szOID_PKIX_OCSP: &'static str = "1.3.6.1.5.5.7.48.1"; +pub const szOID_PKIX_CA_ISSUERS: &'static str = "1.3.6.1.5.5.7.48.2"; +pub const szOID_PKIX_TIME_STAMPING: &'static str = "1.3.6.1.5.5.7.48.3"; +pub const szOID_PKIX_CA_REPOSITORY: &'static str = "1.3.6.1.5.5.7.48.5"; +pub const CRL_REASON_UNSPECIFIED: DWORD = 0; +pub const CRL_REASON_KEY_COMPROMISE: DWORD = 1; +pub const CRL_REASON_CA_COMPROMISE: DWORD = 2; +pub const CRL_REASON_AFFILIATION_CHANGED: DWORD = 3; +pub const CRL_REASON_SUPERSEDED: DWORD = 4; +pub const CRL_REASON_CESSATION_OF_OPERATION: DWORD = 5; +pub const CRL_REASON_CERTIFICATE_HOLD: DWORD = 6; +pub const CRL_REASON_REMOVE_FROM_CRL: DWORD = 8; +pub const CRL_REASON_PRIVILEGE_WITHDRAWN: DWORD = 9; +pub const CRL_REASON_AA_COMPROMISE: DWORD = 10; +UNION!{union CRL_DIST_POINT_NAME_u { + [usize; 2], + FullName FullName_mut: CERT_ALT_NAME_INFO, +}} +STRUCT!{struct CRL_DIST_POINT_NAME { + dwDistPointNameChoice: DWORD, + u: CRL_DIST_POINT_NAME_u, +}} +pub type PCRL_DIST_POINT_NAME = *mut CRL_DIST_POINT_NAME; +pub const CRL_DIST_POINT_NO_NAME: DWORD = 0; +pub const CRL_DIST_POINT_FULL_NAME: DWORD = 1; +pub const CRL_DIST_POINT_ISSUER_RDN_NAME: DWORD = 2; +STRUCT!{struct CRL_DIST_POINT { + DistPointName: CRL_DIST_POINT_NAME, + ReasonFlags: CRYPT_BIT_BLOB, + CRLIssuer: CERT_ALT_NAME_INFO, +}} +pub type PCRL_DIST_POINT = *mut CRL_DIST_POINT; +pub const CRL_REASON_UNUSED_FLAG: DWORD = 0x80; +pub const CRL_REASON_KEY_COMPROMISE_FLAG: DWORD = 0x40; +pub const CRL_REASON_CA_COMPROMISE_FLAG: DWORD = 0x20; +pub const CRL_REASON_AFFILIATION_CHANGED_FLAG: DWORD = 0x10; +pub const CRL_REASON_SUPERSEDED_FLAG: DWORD = 0x08; +pub const CRL_REASON_CESSATION_OF_OPERATION_FLAG: DWORD = 0x04; +pub const CRL_REASON_CERTIFICATE_HOLD_FLAG: DWORD = 0x02; +pub const CRL_REASON_PRIVILEGE_WITHDRAWN_FLAG: DWORD = 0x01; +pub const CRL_REASON_AA_COMPROMISE_FLAG: DWORD = 0x80; +STRUCT!{struct CRL_DIST_POINTS_INFO { + cDistPoint: DWORD, + rgDistPoint: PCRL_DIST_POINT, +}} +pub type PCRL_DIST_POINTS_INFO = *mut CRL_DIST_POINTS_INFO; +pub const CRL_DIST_POINT_ERR_INDEX_MASK: DWORD = 0x7F; +pub const CRL_DIST_POINT_ERR_INDEX_SHIFT: DWORD = 24; +#[inline] +pub fn GET_CRL_DIST_POINT_ERR_INDEX(X: DWORD) -> DWORD { + (X >> CRL_DIST_POINT_ERR_INDEX_SHIFT) & CRL_DIST_POINT_ERR_INDEX_MASK +} +pub const CRL_DIST_POINT_ERR_CRL_ISSUER_BIT: DWORD = 0x80000000; +#[inline] +pub fn IS_CRL_DIST_POINT_ERR_CRL_ISSUER(X: DWORD) -> bool { + 0 != (X & CRL_DIST_POINT_ERR_CRL_ISSUER_BIT) +} +STRUCT!{struct CROSS_CERT_DIST_POINTS_INFO { + dwSyncDeltaTime: DWORD, + cDistPoint: DWORD, + rgDistPoint: PCERT_ALT_NAME_INFO, +}} +pub type PCROSS_CERT_DIST_POINTS_INFO = *mut CROSS_CERT_DIST_POINTS_INFO; +pub const CROSS_CERT_DIST_POINT_ERR_INDEX_MASK: DWORD = 0xFF; +pub const CROSS_CERT_DIST_POINT_ERR_INDEX_SHIFT: DWORD = 24; +#[inline] +pub fn GET_CROSS_CERT_DIST_POINT_ERR_INDEX(X: DWORD) -> DWORD { + (X >> CROSS_CERT_DIST_POINT_ERR_INDEX_SHIFT) & CROSS_CERT_DIST_POINT_ERR_INDEX_MASK +} +STRUCT!{struct CERT_PAIR { + Forward: CERT_BLOB, + Reverse: CERT_BLOB, +}} +pub type PCERT_PAIR = *mut CERT_PAIR; +STRUCT!{struct CRL_ISSUING_DIST_POINT { + DistPointName: CRL_DIST_POINT_NAME, + fOnlyContainsUserCerts: BOOL, + fOnlyContainsCACerts: BOOL, + OnlySomeReasonFlags: CRYPT_BIT_BLOB, + fIndirectCRL: BOOL, +}} +pub type PCRL_ISSUING_DIST_POINT = *mut CRL_ISSUING_DIST_POINT; +STRUCT!{struct CERT_GENERAL_SUBTREE { + Base: CERT_ALT_NAME_ENTRY, + dwMinimum: DWORD, + fMaximum: BOOL, + dwMaximum: DWORD, +}} +pub type PCERT_GENERAL_SUBTREE = *mut CERT_GENERAL_SUBTREE; +STRUCT!{struct CERT_NAME_CONSTRAINTS_INFO { + cPermittedSubtree: DWORD, + rgPermittedSubtree: PCERT_GENERAL_SUBTREE, + cExcludedSubtree: DWORD, + rgExcludedSubtree: PCERT_GENERAL_SUBTREE, +}} +pub type PCERT_NAME_CONSTRAINTS_INFO = *mut CERT_NAME_CONSTRAINTS_INFO; +pub const CERT_EXCLUDED_SUBTREE_BIT: DWORD = 0x80000000; +#[inline] +pub fn IS_CERT_EXCLUDED_SUBTREE(X: DWORD) -> bool { + 0 != (X & CERT_EXCLUDED_SUBTREE_BIT) +} +pub const SORTED_CTL_EXT_FLAGS_OFFSET: c_int = 0 * 4; +pub const SORTED_CTL_EXT_COUNT_OFFSET: c_int = 1 * 4; +pub const SORTED_CTL_EXT_MAX_COLLISION_OFFSET: c_int = 2 * 4; +pub const SORTED_CTL_EXT_HASH_BUCKET_OFFSET: c_int = 3 * 4; +pub const SORTED_CTL_EXT_HASHED_SUBJECT_IDENTIFIER_FLAG: DWORD = 0x1; +STRUCT!{struct CERT_DSS_PARAMETERS { + p: CRYPT_UINT_BLOB, + q: CRYPT_UINT_BLOB, + g: CRYPT_UINT_BLOB, +}} +pub type PCERT_DSS_PARAMETERS = *mut CERT_DSS_PARAMETERS; +pub const CERT_DSS_R_LEN: usize = 20; +pub const CERT_DSS_S_LEN: usize = 20; +pub const CERT_DSS_SIGNATURE_LEN: usize = CERT_DSS_R_LEN + CERT_DSS_S_LEN; +pub const CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN: usize = 2 + 2 * (2 + 20 + 1); +STRUCT!{struct CERT_DH_PARAMETERS { + p: CRYPT_UINT_BLOB, + g: CRYPT_UINT_BLOB, +}} +pub type PCERT_DH_PARAMETERS = *mut CERT_DH_PARAMETERS; +STRUCT!{struct CERT_ECC_SIGNATURE { + r: CRYPT_UINT_BLOB, + s: CRYPT_UINT_BLOB, +}} +pub type PCERT_ECC_SIGNATURE = *mut CERT_ECC_SIGNATURE; +STRUCT!{struct CERT_X942_DH_VALIDATION_PARAMS { + seed: CRYPT_BIT_BLOB, + pgenCounter: DWORD, +}} +pub type PCERT_X942_DH_VALIDATION_PARAMS = *mut CERT_X942_DH_VALIDATION_PARAMS; +STRUCT!{struct CERT_X942_DH_PARAMETERS { + p: CRYPT_UINT_BLOB, + g: CRYPT_UINT_BLOB, + q: CRYPT_UINT_BLOB, + j: CRYPT_UINT_BLOB, + pValidationParams: PCERT_X942_DH_VALIDATION_PARAMS, +}} +pub type PCERT_X942_DH_PARAMETERS = *mut CERT_X942_DH_PARAMETERS; +pub const CRYPT_X942_COUNTER_BYTE_LENGTH: usize = 4; +pub const CRYPT_X942_KEY_LENGTH_BYTE_LENGTH: usize = 4; +pub const CRYPT_X942_PUB_INFO_BYTE_LENGTH: usize = 512 / 8; +STRUCT!{struct CRYPT_X942_OTHER_INFO { + pszContentEncryptionObjId: LPSTR, + rgbCounter: [BYTE; CRYPT_X942_COUNTER_BYTE_LENGTH], + rgbKeyLength: [BYTE; CRYPT_X942_KEY_LENGTH_BYTE_LENGTH], + PubInfo: CRYPT_DATA_BLOB, +}} +pub type PCRYPT_X942_OTHER_INFO = *mut CRYPT_X942_OTHER_INFO; +pub const CRYPT_ECC_CMS_SHARED_INFO_SUPPPUBINFO_BYTE_LENGTH: usize = 4; +STRUCT!{struct CRYPT_ECC_CMS_SHARED_INFO { + Algorithm: CRYPT_ALGORITHM_IDENTIFIER, + EntityUInfo: CRYPT_DATA_BLOB, + rgbSuppPubInfo: [BYTE; CRYPT_ECC_CMS_SHARED_INFO_SUPPPUBINFO_BYTE_LENGTH], +}} +pub type PCRYPT_ECC_CMS_SHARED_INFO = *mut CRYPT_ECC_CMS_SHARED_INFO; +STRUCT!{struct CRYPT_RC2_CBC_PARAMETERS { + dwVersion: DWORD, + fIV: BOOL, + rgbIV: [BYTE; 8], +}} +pub type PCRYPT_RC2_CBC_PARAMETERS = *mut CRYPT_RC2_CBC_PARAMETERS; +pub const CRYPT_RC2_40BIT_VERSION: DWORD = 160; +pub const CRYPT_RC2_56BIT_VERSION: DWORD = 52; +pub const CRYPT_RC2_64BIT_VERSION: DWORD = 120; +pub const CRYPT_RC2_128BIT_VERSION: DWORD = 58; +STRUCT!{struct CRYPT_SMIME_CAPABILITY { + pszObjId: LPSTR, + Parameters: CRYPT_OBJID_BLOB, +}} +pub type PCRYPT_SMIME_CAPABILITY = *mut CRYPT_SMIME_CAPABILITY; +STRUCT!{struct CRYPT_SMIME_CAPABILITIES { + cCapability: DWORD, + rgCapability: PCRYPT_SMIME_CAPABILITY, +}} +pub type PCRYPT_SMIME_CAPABILITIES = *mut CRYPT_SMIME_CAPABILITIES; +STRUCT!{struct CERT_QC_STATEMENT { + pszStatementId: LPSTR, + StatementInfo: CRYPT_OBJID_BLOB, +}} +pub type PCERT_QC_STATEMENT = *mut CERT_QC_STATEMENT; +STRUCT!{struct CERT_QC_STATEMENTS_EXT_INFO { + cStatement: DWORD, + rgStatement: PCERT_QC_STATEMENT, +}} +pub type PCERT_QC_STATEMENTS_EXT_INFO = *mut CERT_QC_STATEMENTS_EXT_INFO; +pub const szOID_QC_EU_COMPLIANCE: &'static str = "0.4.0.1862.1.1"; +pub const szOID_QC_SSCD: &'static str = "0.4.0.1862.1.4"; +STRUCT!{struct CRYPT_MASK_GEN_ALGORITHM { + pszObjId: LPSTR, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, +}} +pub type PCRYPT_MASK_GEN_ALGORITHM = *mut CRYPT_MASK_GEN_ALGORITHM; +STRUCT!{struct CRYPT_RSA_SSA_PSS_PARAMETERS { + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + MaskGenAlgorithm: CRYPT_MASK_GEN_ALGORITHM, + dwSaltLength: DWORD, + dwTrailerField: DWORD, +}} +pub type PCRYPT_RSA_SSA_PSS_PARAMETERS = *mut CRYPT_RSA_SSA_PSS_PARAMETERS; +pub const PKCS_RSA_SSA_PSS_TRAILER_FIELD_BC: DWORD = 1; +STRUCT!{struct CRYPT_PSOURCE_ALGORITHM { + pszObjId: LPSTR, + EncodingParameters: CRYPT_DATA_BLOB, +}} +pub type PCRYPT_PSOURCE_ALGORITHM = *mut CRYPT_PSOURCE_ALGORITHM; +STRUCT!{struct CRYPT_RSAES_OAEP_PARAMETERS { + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + MaskGenAlgorithm: CRYPT_MASK_GEN_ALGORITHM, + PSourceAlgorithm: CRYPT_PSOURCE_ALGORITHM, +}} +pub type PCRYPT_RSAES_OAEP_PARAMETERS = *mut CRYPT_RSAES_OAEP_PARAMETERS; +pub const szOID_VERISIGN_PRIVATE_6_9: &'static str = "2.16.840.1.113733.1.6.9"; +pub const szOID_VERISIGN_ONSITE_JURISDICTION_HASH: &'static str = "2.16.840.1.113733.1.6.11"; +pub const szOID_VERISIGN_BITSTRING_6_13: &'static str = "2.16.840.1.113733.1.6.13"; +pub const szOID_VERISIGN_ISS_STRONG_CRYPTO: &'static str = "2.16.840.1.113733.1.8.1"; +pub const szOIDVerisign_MessageType: &'static str = "2.16.840.1.113733.1.9.2"; +pub const szOIDVerisign_PkiStatus: &'static str = "2.16.840.1.113733.1.9.3"; +pub const szOIDVerisign_FailInfo: &'static str = "2.16.840.1.113733.1.9.4"; +pub const szOIDVerisign_SenderNonce: &'static str = "2.16.840.1.113733.1.9.5"; +pub const szOIDVerisign_RecipientNonce: &'static str = "2.16.840.1.113733.1.9.6"; +pub const szOIDVerisign_TransactionID: &'static str = "2.16.840.1.113733.1.9.7"; +pub const szOID_NETSCAPE: &'static str = "2.16.840.1.113730"; +pub const szOID_NETSCAPE_CERT_EXTENSION: &'static str = "2.16.840.1.113730.1"; +pub const szOID_NETSCAPE_CERT_TYPE: &'static str = "2.16.840.1.113730.1.1"; +pub const szOID_NETSCAPE_BASE_URL: &'static str = "2.16.840.1.113730.1.2"; +pub const szOID_NETSCAPE_REVOCATION_URL: &'static str = "2.16.840.1.113730.1.3"; +pub const szOID_NETSCAPE_CA_REVOCATION_URL: &'static str = "2.16.840.1.113730.1.4"; +pub const szOID_NETSCAPE_CERT_RENEWAL_URL: &'static str = "2.16.840.1.113730.1.7"; +pub const szOID_NETSCAPE_CA_POLICY_URL: &'static str = "2.16.840.1.113730.1.8"; +pub const szOID_NETSCAPE_SSL_SERVER_NAME: &'static str = "2.16.840.1.113730.1.12"; +pub const szOID_NETSCAPE_COMMENT: &'static str = "2.16.840.1.113730.1.13"; +pub const szOID_NETSCAPE_DATA_TYPE: &'static str = "2.16.840.1.113730.2"; +pub const szOID_NETSCAPE_CERT_SEQUENCE: &'static str = "2.16.840.1.113730.2.5"; +pub const NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE: DWORD = 0x80; +pub const NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE: DWORD = 0x40; +pub const NETSCAPE_SMIME_CERT_TYPE: DWORD = 0x20; +pub const NETSCAPE_SIGN_CERT_TYPE: DWORD = 0x10; +pub const NETSCAPE_SSL_CA_CERT_TYPE: DWORD = 0x04; +pub const NETSCAPE_SMIME_CA_CERT_TYPE: DWORD = 0x02; +pub const NETSCAPE_SIGN_CA_CERT_TYPE: DWORD = 0x01; +pub const szOID_CT_PKI_DATA: &'static str = "1.3.6.1.5.5.7.12.2"; +pub const szOID_CT_PKI_RESPONSE: &'static str = "1.3.6.1.5.5.7.12.3"; +pub const szOID_PKIX_NO_SIGNATURE: &'static str = "1.3.6.1.5.5.7.6.2"; +pub const szOID_CMC: &'static str = "1.3.6.1.5.5.7.7"; +pub const szOID_CMC_STATUS_INFO: &'static str = "1.3.6.1.5.5.7.7.1"; +pub const szOID_CMC_IDENTIFICATION: &'static str = "1.3.6.1.5.5.7.7.2"; +pub const szOID_CMC_IDENTITY_PROOF: &'static str = "1.3.6.1.5.5.7.7.3"; +pub const szOID_CMC_DATA_RETURN: &'static str = "1.3.6.1.5.5.7.7.4"; +pub const szOID_CMC_TRANSACTION_ID: &'static str = "1.3.6.1.5.5.7.7.5"; +pub const szOID_CMC_SENDER_NONCE: &'static str = "1.3.6.1.5.5.7.7.6"; +pub const szOID_CMC_RECIPIENT_NONCE: &'static str = "1.3.6.1.5.5.7.7.7"; +pub const szOID_CMC_ADD_EXTENSIONS: &'static str = "1.3.6.1.5.5.7.7.8"; +pub const szOID_CMC_ENCRYPTED_POP: &'static str = "1.3.6.1.5.5.7.7.9"; +pub const szOID_CMC_DECRYPTED_POP: &'static str = "1.3.6.1.5.5.7.7.10"; +pub const szOID_CMC_LRA_POP_WITNESS: &'static str = "1.3.6.1.5.5.7.7.11"; +pub const szOID_CMC_GET_CERT: &'static str = "1.3.6.1.5.5.7.7.15"; +pub const szOID_CMC_GET_CRL: &'static str = "1.3.6.1.5.5.7.7.16"; +pub const szOID_CMC_REVOKE_REQUEST: &'static str = "1.3.6.1.5.5.7.7.17"; +pub const szOID_CMC_REG_INFO: &'static str = "1.3.6.1.5.5.7.7.18"; +pub const szOID_CMC_RESPONSE_INFO: &'static str = "1.3.6.1.5.5.7.7.19"; +pub const szOID_CMC_QUERY_PENDING: &'static str = "1.3.6.1.5.5.7.7.21"; +pub const szOID_CMC_ID_POP_LINK_RANDOM: &'static str = "1.3.6.1.5.5.7.7.22"; +pub const szOID_CMC_ID_POP_LINK_WITNESS: &'static str = "1.3.6.1.5.5.7.7.23"; +pub const szOID_CMC_ID_CONFIRM_CERT_ACCEPTANCE: &'static str = "1.3.6.1.5.5.7.7.24"; +pub const szOID_CMC_ADD_ATTRIBUTES: &'static str = "1.3.6.1.4.1.311.10.10.1"; +STRUCT!{struct CMC_TAGGED_ATTRIBUTE { + dwBodyPartID: DWORD, + Attribute: CRYPT_ATTRIBUTE, +}} +pub type PCMC_TAGGED_ATTRIBUTE = *mut CMC_TAGGED_ATTRIBUTE; +STRUCT!{struct CMC_TAGGED_CERT_REQUEST { + dwBodyPartID: DWORD, + SignedCertRequest: CRYPT_DER_BLOB, +}} +pub type PCMC_TAGGED_CERT_REQUEST = *mut CMC_TAGGED_CERT_REQUEST; +UNION!{union CMC_TAGGED_REQUEST_u { + [usize; 1], + pTaggedCertRequest pTaggedCertRequest_mut: PCMC_TAGGED_CERT_REQUEST, +}} +STRUCT!{struct CMC_TAGGED_REQUEST { + dwTaggedRequestChoice: DWORD, + u: CMC_TAGGED_REQUEST_u, +}} +pub type PCMC_TAGGED_REQUEST = *mut CMC_TAGGED_REQUEST; +STRUCT!{struct CMC_TAGGED_CONTENT_INFO { + dwBodyPartID: DWORD, + EncodedContentInfo: CRYPT_DER_BLOB, +}} +pub type PCMC_TAGGED_CONTENT_INFO = *mut CMC_TAGGED_CONTENT_INFO; +STRUCT!{struct CMC_TAGGED_OTHER_MSG { + dwBodyPartID: DWORD, + pszObjId: LPSTR, + Value: CRYPT_OBJID_BLOB, +}} +pub type PCMC_TAGGED_OTHER_MSG = *mut CMC_TAGGED_OTHER_MSG; +STRUCT!{struct CMC_DATA_INFO { + cTaggedAttribute: DWORD, + rgTaggedAttribute: PCMC_TAGGED_ATTRIBUTE, + cTaggedRequest: DWORD, + rgTaggedRequest: PCMC_TAGGED_REQUEST, + cTaggedContentInfo: DWORD, + rgTaggedContentInfo: PCMC_TAGGED_CONTENT_INFO, + cTaggedOtherMsg: DWORD, + rgTaggedOtherMsg: PCMC_TAGGED_OTHER_MSG, +}} +pub type PCMC_DATA_INFO = *mut CMC_DATA_INFO; +STRUCT!{struct CMC_RESPONSE_INFO { + cTaggedAttribute: DWORD, + rgTaggedAttribute: PCMC_TAGGED_ATTRIBUTE, + cTaggedContentInfo: DWORD, + rgTaggedContentInfo: PCMC_TAGGED_CONTENT_INFO, + cTaggedOtherMsg: DWORD, + rgTaggedOtherMsg: PCMC_TAGGED_OTHER_MSG, +}} +pub type PCMC_RESPONSE_INFO = *mut CMC_RESPONSE_INFO; +STRUCT!{struct CMC_PEND_INFO { + PendToken: CRYPT_DATA_BLOB, + PendTime: FILETIME, +}} +pub type PCMC_PEND_INFO = *mut CMC_PEND_INFO; +UNION!{union CMC_STATUS_INFO_u { + [usize; 1], + dwFailInfo dwFailInfo_mut: DWORD, + pPendInfo pPendInfo_mut: PCMC_PEND_INFO, +}} +STRUCT!{struct CMC_STATUS_INFO { + dwStatus: DWORD, + cBodyList: DWORD, + rgdwBodyList: *mut DWORD, + pwszStatusString: LPWSTR, + dwOtherInfoChoice: DWORD, + u: CMC_STATUS_INFO_u, +}} +pub type PCMC_STATUS_INFO = *mut CMC_STATUS_INFO; +pub const CMC_OTHER_INFO_NO_CHOICE: DWORD = 0; +pub const CMC_OTHER_INFO_FAIL_CHOICE: DWORD = 1; +pub const CMC_OTHER_INFO_PEND_CHOICE: DWORD = 2; +pub const CMC_STATUS_SUCCESS: DWORD = 0; +pub const CMC_STATUS_FAILED: DWORD = 2; +pub const CMC_STATUS_PENDING: DWORD = 3; +pub const CMC_STATUS_NO_SUPPORT: DWORD = 4; +pub const CMC_STATUS_CONFIRM_REQUIRED: DWORD = 5; +pub const CMC_FAIL_BAD_ALG: DWORD = 0; +pub const CMC_FAIL_BAD_MESSAGE_CHECK: DWORD = 1; +pub const CMC_FAIL_BAD_REQUEST: DWORD = 2; +pub const CMC_FAIL_BAD_TIME: DWORD = 3; +pub const CMC_FAIL_BAD_CERT_ID: DWORD = 4; +pub const CMC_FAIL_UNSUPORTED_EXT: DWORD = 5; +pub const CMC_FAIL_MUST_ARCHIVE_KEYS: DWORD = 6; +pub const CMC_FAIL_BAD_IDENTITY: DWORD = 7; +pub const CMC_FAIL_POP_REQUIRED: DWORD = 8; +pub const CMC_FAIL_POP_FAILED: DWORD = 9; +pub const CMC_FAIL_NO_KEY_REUSE: DWORD = 10; +pub const CMC_FAIL_INTERNAL_CA_ERROR: DWORD = 11; +pub const CMC_FAIL_TRY_LATER: DWORD = 12; +STRUCT!{struct CMC_ADD_EXTENSIONS_INFO { + dwCmcDataReference: DWORD, + cCertReference: DWORD, + rgdwCertReference: *mut DWORD, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCMC_ADD_EXTENSIONS_INFO = *mut CMC_ADD_EXTENSIONS_INFO; +STRUCT!{struct CMC_ADD_ATTRIBUTES_INFO { + dwCmcDataReference: DWORD, + cCertReference: DWORD, + rgdwCertReference: *mut DWORD, + cAttribute: DWORD, + rgAttribute: PCRYPT_ATTRIBUTE, +}} +pub type PCMC_ADD_ATTRIBUTES_INFO = *mut CMC_ADD_ATTRIBUTES_INFO; +STRUCT!{struct CERT_TEMPLATE_EXT { + pszObjId: LPSTR, + dwMajorVersion: DWORD, + fMinorVersion: BOOL, + dwMinorVersion: DWORD, +}} +pub type PCERT_TEMPLATE_EXT = *mut CERT_TEMPLATE_EXT; +STRUCT!{struct CERT_HASHED_URL { + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Hash: CRYPT_HASH_BLOB, + pwszUrl: LPWSTR, +}} +pub type PCERT_HASHED_URL = *mut CERT_HASHED_URL; +STRUCT!{struct CERT_LOGOTYPE_DETAILS { + pwszMimeType: LPWSTR, + cHashedUrl: DWORD, + rgHashedUrl: PCERT_HASHED_URL, +}} +pub type PCERT_LOGOTYPE_DETAILS = *mut CERT_LOGOTYPE_DETAILS; +STRUCT!{struct CERT_LOGOTYPE_REFERENCE { + cHashedUrl: DWORD, + rgHashedUrl: PCERT_HASHED_URL, +}} +pub type PCERT_LOGOTYPE_REFERENCE = *mut CERT_LOGOTYPE_REFERENCE; +UNION!{union CERT_LOGOTYPE_IMAGE_INFO_u { + [u32; 1], + dwNumBits dwNumBits_mut: DWORD, + dwTableSize dwTableSize_mut: DWORD, +}} +STRUCT!{struct CERT_LOGOTYPE_IMAGE_INFO { + dwLogotypeImageInfoChoice: DWORD, + dwFileSize: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwLogotypeImageResolutionChoice: DWORD, + u: CERT_LOGOTYPE_IMAGE_INFO_u, + pwszLanguage: LPWSTR, +}} +pub type PCERT_LOGOTYPE_IMAGE_INFO = *mut CERT_LOGOTYPE_IMAGE_INFO; +pub const CERT_LOGOTYPE_GRAY_SCALE_IMAGE_INFO_CHOICE: DWORD = 1; +pub const CERT_LOGOTYPE_COLOR_IMAGE_INFO_CHOICE: DWORD = 2; +pub const CERT_LOGOTYPE_NO_IMAGE_RESOLUTION_CHOICE: DWORD = 0; +pub const CERT_LOGOTYPE_BITS_IMAGE_RESOLUTION_CHOICE: DWORD = 1; +pub const CERT_LOGOTYPE_TABLE_SIZE_IMAGE_RESOLUTION_CHOICE: DWORD = 2; +STRUCT!{struct CERT_LOGOTYPE_IMAGE { + LogotypeDetails: CERT_LOGOTYPE_DETAILS, + pLogotypeImageInfo: PCERT_LOGOTYPE_IMAGE_INFO, +}} +pub type PCERT_LOGOTYPE_IMAGE = *mut CERT_LOGOTYPE_IMAGE; +STRUCT!{struct CERT_LOGOTYPE_AUDIO_INFO { + dwFileSize: DWORD, + dwPlayTime: DWORD, + dwChannels: DWORD, + dwSampleRate: DWORD, + pwszLanguage: LPWSTR, +}} +pub type PCERT_LOGOTYPE_AUDIO_INFO = *mut CERT_LOGOTYPE_AUDIO_INFO; +STRUCT!{struct CERT_LOGOTYPE_AUDIO { + LogotypeDetails: CERT_LOGOTYPE_DETAILS, + pLogotypeAudioInfo: PCERT_LOGOTYPE_AUDIO_INFO, +}} +pub type PCERT_LOGOTYPE_AUDIO = *mut CERT_LOGOTYPE_AUDIO; +STRUCT!{struct CERT_LOGOTYPE_DATA { + cLogotypeImage: DWORD, + rgLogotypeImage: PCERT_LOGOTYPE_IMAGE, + cLogotypeAudio: DWORD, + rgLogotypeAudio: PCERT_LOGOTYPE_AUDIO, +}} +pub type PCERT_LOGOTYPE_DATA = *mut CERT_LOGOTYPE_DATA; +UNION!{union CERT_LOGOTYPE_INFO_u { + [usize; 1], + pLogotypeDirectInfo pLogotypeDirectInfo_mut: PCERT_LOGOTYPE_DATA, + pLogotypeIndirectInfo pLogotypeIndirectInfo__mut: PCERT_LOGOTYPE_REFERENCE, +}} +STRUCT!{struct CERT_LOGOTYPE_INFO { + dwLogotypeInfoChoice: DWORD, + u: CERT_LOGOTYPE_INFO_u, +}} +pub type PCERT_LOGOTYPE_INFO = *mut CERT_LOGOTYPE_INFO; +pub const CERT_LOGOTYPE_DIRECT_INFO_CHOICE: DWORD = 1; +pub const CERT_LOGOTYPE_INDIRECT_INFO_CHOICE: DWORD = 2; +STRUCT!{struct CERT_OTHER_LOGOTYPE_INFO { + pszObjId: LPSTR, + LogotypeInfo: CERT_LOGOTYPE_INFO, +}} +pub type PCERT_OTHER_LOGOTYPE_INFO = *mut CERT_OTHER_LOGOTYPE_INFO; +pub const szOID_LOYALTY_OTHER_LOGOTYPE: &'static str = "1.3.6.1.5.5.7.20.1"; +pub const szOID_BACKGROUND_OTHER_LOGOTYPE: &'static str = "1.3.6.1.5.5.7.20.2"; +STRUCT!{struct CERT_LOGOTYPE_EXT_INFO { + cCommunityLogo: DWORD, + rgCommunityLogo: PCERT_LOGOTYPE_INFO, + pIssuerLogo: PCERT_LOGOTYPE_INFO, + pSubjectLogo: PCERT_LOGOTYPE_INFO, + cOtherLogo: DWORD, + rgOtherLogo: PCERT_OTHER_LOGOTYPE_INFO, +}} +pub type PCERT_LOGOTYPE_EXT_INFO = *mut CERT_LOGOTYPE_EXT_INFO; +UNION!{union CERT_BIOMETRIC_DATA_u { + [usize; 1], + dwPredefined dwPredefined_mut: DWORD, + pszObjId pszObjId_mut: LPSTR, +}} +STRUCT!{struct CERT_BIOMETRIC_DATA { + dwTypeOfBiometricDataChoice: DWORD, + u: CERT_BIOMETRIC_DATA_u, + HashedUrl: CERT_HASHED_URL, +}} +pub type PCERT_BIOMETRIC_DATA = *mut CERT_BIOMETRIC_DATA; +pub const CERT_BIOMETRIC_PREDEFINED_DATA_CHOICE: DWORD = 1; +pub const CERT_BIOMETRIC_OID_DATA_CHOICE: DWORD = 2; +pub const CERT_BIOMETRIC_PICTURE_TYPE: DWORD = 0; +pub const CERT_BIOMETRIC_SIGNATURE_TYPE: DWORD = 1; +STRUCT!{struct CERT_BIOMETRIC_EXT_INFO { + cBiometricData: DWORD, + rgBiometricData: PCERT_BIOMETRIC_DATA, +}} +pub type PCERT_BIOMETRIC_EXT_INFO = *mut CERT_BIOMETRIC_EXT_INFO; +STRUCT!{struct OCSP_SIGNATURE_INFO { + SignatureAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + Signature: CRYPT_BIT_BLOB, + cCertEncoded: DWORD, + rgCertEncoded: PCERT_BLOB, +}} +pub type POCSP_SIGNATURE_INFO = *mut OCSP_SIGNATURE_INFO; +STRUCT!{struct OCSP_SIGNED_REQUEST_INFO { + ToBeSigned: CRYPT_DER_BLOB, + pOptionalSignatureInfo: POCSP_SIGNATURE_INFO, +}} +pub type POCSP_SIGNED_REQUEST_INFO = *mut OCSP_SIGNED_REQUEST_INFO; +STRUCT!{struct OCSP_CERT_ID { + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + IssuerNameHash: CRYPT_HASH_BLOB, + IssuerKeyHash: CRYPT_HASH_BLOB, + SerialNumber: CRYPT_INTEGER_BLOB, +}} +pub type POCSP_CERT_ID = *mut OCSP_CERT_ID; +STRUCT!{struct OCSP_REQUEST_ENTRY { + CertId: OCSP_CERT_ID, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type POCSP_REQUEST_ENTRY = *mut OCSP_REQUEST_ENTRY; +STRUCT!{struct OCSP_REQUEST_INFO { + dwVersion: DWORD, + pRequestorName: PCERT_ALT_NAME_ENTRY, + cRequestEntry: DWORD, + rgRequestEntry: POCSP_REQUEST_ENTRY, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type POCSP_REQUEST_INFO = *mut OCSP_REQUEST_INFO; +pub const OCSP_REQUEST_V1: DWORD = 0; +STRUCT!{struct OCSP_RESPONSE_INFO { + dwStatus: DWORD, + pszObjId: LPSTR, + Value: CRYPT_OBJID_BLOB, +}} +pub type POCSP_RESPONSE_INFO = *mut OCSP_RESPONSE_INFO; +pub const OCSP_SUCCESSFUL_RESPONSE: DWORD = 0; +pub const OCSP_MALFORMED_REQUEST_RESPONSE: DWORD = 1; +pub const OCSP_INTERNAL_ERROR_RESPONSE: DWORD = 2; +pub const OCSP_TRY_LATER_RESPONSE: DWORD = 3; +pub const OCSP_SIG_REQUIRED_RESPONSE: DWORD = 5; +pub const OCSP_UNAUTHORIZED_RESPONSE: DWORD = 6; +pub const szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE: &'static str = "1.3.6.1.5.5.7.48.1.1"; +STRUCT!{struct OCSP_BASIC_SIGNED_RESPONSE_INFO { + ToBeSigned: CRYPT_DER_BLOB, + SignatureInfo: OCSP_SIGNATURE_INFO, +}} +pub type POCSP_BASIC_SIGNED_RESPONSE_INFO = *mut OCSP_BASIC_SIGNED_RESPONSE_INFO; +STRUCT!{struct OCSP_BASIC_REVOKED_INFO { + RevocationDate: FILETIME, + dwCrlReasonCode: DWORD, +}} +pub type POCSP_BASIC_REVOKED_INFO = *mut OCSP_BASIC_REVOKED_INFO; +UNION!{union OCSP_BASIC_RESPONSE_ENTRY_u { + [usize; 1], + pRevokedInfo pRevokedInfo_mut: POCSP_BASIC_REVOKED_INFO, +}} +STRUCT!{struct OCSP_BASIC_RESPONSE_ENTRY { + CertId: OCSP_CERT_ID, + dwCertStatus: DWORD, + u: OCSP_BASIC_RESPONSE_ENTRY_u, + ThisUpdate: FILETIME, + NextUpdate: FILETIME, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type POCSP_BASIC_RESPONSE_ENTRY = *mut OCSP_BASIC_RESPONSE_ENTRY; +pub const OCSP_BASIC_GOOD_CERT_STATUS: DWORD = 0; +pub const OCSP_BASIC_REVOKED_CERT_STATUS: DWORD = 1; +pub const OCSP_BASIC_UNKNOWN_CERT_STATUS: DWORD = 2; +UNION!{union OCSP_BASIC_RESPONSE_INFO_u { + [usize; 2], + ByNameResponderId ByNameResponderId_mut: CERT_NAME_BLOB, + ByKeyResponderId ByKeyResponderId_mut: CRYPT_HASH_BLOB, +}} +STRUCT!{struct OCSP_BASIC_RESPONSE_INFO { + dwVersion: DWORD, + dwResponderIdChoice: DWORD, + u: OCSP_BASIC_RESPONSE_INFO_u, + ProducedAt: FILETIME, + cResponseEntry: DWORD, + rgResponseEntry: POCSP_BASIC_RESPONSE_ENTRY, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type POCSP_BASIC_RESPONSE_INFO = *mut OCSP_BASIC_RESPONSE_INFO; +pub const OCSP_BASIC_RESPONSE_V1: DWORD = 0; +pub const OCSP_BASIC_BY_NAME_RESPONDER_ID: DWORD = 1; +pub const OCSP_BASIC_BY_KEY_RESPONDER_ID: DWORD = 2; +STRUCT!{struct CERT_SUPPORTED_ALGORITHM_INFO { + Algorithm: CRYPT_ALGORITHM_IDENTIFIER, + IntendedKeyUsage: CRYPT_BIT_BLOB, + IntendedCertPolicies: CERT_POLICIES_INFO, +}} +pub type PCERT_SUPPORTED_ALGORITHM_INFO = *mut CERT_SUPPORTED_ALGORITHM_INFO; +STRUCT!{struct CERT_TPM_SPECIFICATION_INFO { + pwszFamily: LPWSTR, + dwLevel: DWORD, + dwRevision: DWORD, +}} +pub type PCERT_TPM_SPECIFICATION_INFO = *mut CERT_TPM_SPECIFICATION_INFO; +pub type HCRYPTOIDFUNCSET = *mut c_void; +pub type HCRYPTOIDFUNCADDR = *mut c_void; +pub const CRYPT_OID_ENCODE_OBJECT_FUNC: &'static str = "CryptDllEncodeObject"; +pub const CRYPT_OID_DECODE_OBJECT_FUNC: &'static str = "CryptDllDecodeObject"; +pub const CRYPT_OID_ENCODE_OBJECT_EX_FUNC: &'static str = "CryptDllEncodeObjectEx"; +pub const CRYPT_OID_DECODE_OBJECT_EX_FUNC: &'static str = "CryptDllDecodeObjectEx"; +pub const CRYPT_OID_CREATE_COM_OBJECT_FUNC: &'static str = "CryptDllCreateCOMObject"; +pub const CRYPT_OID_VERIFY_REVOCATION_FUNC: &'static str = "CertDllVerifyRevocation"; +pub const CRYPT_OID_VERIFY_CTL_USAGE_FUNC: &'static str = "CertDllVerifyCTLUsage"; +pub const CRYPT_OID_FORMAT_OBJECT_FUNC: &'static str = "CryptDllFormatObject"; +pub const CRYPT_OID_FIND_OID_INFO_FUNC: &'static str = "CryptDllFindOIDInfo"; +pub const CRYPT_OID_FIND_LOCALIZED_NAME_FUNC: &'static str = "CryptDllFindLocalizedName"; +pub const CRYPT_OID_REGPATH: &'static str = "Software\\Microsoft\\Cryptography\\OID"; +pub const CRYPT_OID_REG_ENCODING_TYPE_PREFIX: &'static str = "EncodingType "; +pub const CRYPT_OID_REG_DLL_VALUE_NAME: &'static str = "Dll"; +pub const CRYPT_OID_REG_FUNC_NAME_VALUE_NAME: &'static str = "FuncName"; +pub const CRYPT_OID_REG_FLAGS_VALUE_NAME: &'static str = "CryptFlags"; +pub const CRYPT_DEFAULT_OID: &'static str = "DEFAULT"; +STRUCT!{struct CRYPT_OID_FUNC_ENTRY { + pszOID: LPCSTR, + pvFuncAddr: *mut c_void, +}} +pub type PCRYPT_OID_FUNC_ENTRY = *mut CRYPT_OID_FUNC_ENTRY; +pub const CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG: DWORD = 1; +extern "system" { + pub fn CryptInstallOIDFunctionAddress( + hModule: HMODULE, + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + cFuncEntry: DWORD, + rgFuncEntry: *const CRYPT_OID_FUNC_ENTRY, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptInitOIDFunctionSet( + pszFuncName: LPCSTR, + dwFlags: DWORD, + ) -> HCRYPTOIDFUNCSET; + pub fn CryptGetOIDFunctionAddress( + hFuncSet: HCRYPTOIDFUNCSET, + dwEncodingType: DWORD, + pszOID: LPCSTR, + dwFlags: DWORD, + ppvFuncAddr: *mut *mut c_void, + phFuncAddr: *mut HCRYPTOIDFUNCADDR, + ) -> BOOL; +} +pub const CRYPT_GET_INSTALLED_OID_FUNC_FLAG: DWORD = 0x1; +extern "system" { + pub fn CryptGetDefaultOIDDllList( + hFuncSet: HCRYPTOIDFUNCSET, + dwEncodingType: DWORD, + pwszDllList: *mut WCHAR, + pcchDllList: *mut DWORD, + ) -> BOOL; + pub fn CryptGetDefaultOIDFunctionAddress( + hFuncSet: HCRYPTOIDFUNCSET, + dwEncodingType: DWORD, + pwszDll: LPCWSTR, + dwFlags: DWORD, + ppvFuncAddr: *mut *mut c_void, + phFuncAddr: *mut HCRYPTOIDFUNCADDR, + ) -> BOOL; + pub fn CryptFreeOIDFunctionAddress( + hFuncAddr: HCRYPTOIDFUNCADDR, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptRegisterOIDFunction( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + pwszDll: LPCWSTR, + pszOverrideFuncName: LPCSTR, + ) -> BOOL; + pub fn CryptUnregisterOIDFunction( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + ) -> BOOL; + pub fn CryptRegisterDefaultOIDFunction( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + dwIndex: DWORD, + pwszDll: LPCWSTR, + ) -> BOOL; +} +pub const CRYPT_REGISTER_FIRST_INDEX: DWORD = 0; +pub const CRYPT_REGISTER_LAST_INDEX: DWORD = 0xFFFFFFFF; +extern "system" { + pub fn CryptUnregisterDefaultOIDFunction( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pwszDll: LPCWSTR, + ) -> BOOL; + pub fn CryptSetOIDFunctionValue( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + pwszValueName: LPCWSTR, + dwValueType: DWORD, + pbValueData: *const BYTE, + cbValueData: DWORD, + ) -> BOOL; + pub fn CryptGetOIDFunctionValue( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + pwszValueName: LPCWSTR, + pdwValueType: *mut DWORD, + pbValueData: *mut BYTE, + pcbValueData: *mut DWORD, + ) -> BOOL; +} +FN!{stdcall PFN_CRYPT_ENUM_OID_FUNC( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + cValue: DWORD, + rgdwValueType: *const DWORD, + rgpwszValueName: *const LPCWSTR, + rgpbValueData: *const *const BYTE, + rgcbValueData: *const DWORD, + pvArg: *mut c_void, +) -> BOOL} +extern "system" { + pub fn CryptEnumOIDFunction( + dwEncodingType: DWORD, + pszFuncName: LPCSTR, + pszOID: LPCSTR, + dwFlags: DWORD, + pvArg: *mut c_void, + pfnEnumOIDFunc: PFN_CRYPT_ENUM_OID_FUNC, + ) -> BOOL; +} +pub const CRYPT_MATCH_ANY_ENCODING_TYPE: DWORD = 0xFFFFFFFF; +pub const CALG_OID_INFO_CNG_ONLY: ALG_ID = 0xFFFFFFFF; +pub const CALG_OID_INFO_PARAMETERS: ALG_ID = 0xFFFFFFFE; +#[inline] +pub fn IS_SPECIAL_OID_INFO_ALGID(Algid: ALG_ID) -> bool { + Algid >= CALG_OID_INFO_PARAMETERS +} +pub const CRYPT_OID_INFO_HASH_PARAMETERS_ALGORITHM: &'static str = "CryptOIDInfoHashParameters"; +pub const CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM: &'static str = "CryptOIDInfoECCParameters"; +pub const CRYPT_OID_INFO_MGF1_PARAMETERS_ALGORITHM: &'static str = "CryptOIDInfoMgf1Parameters"; +pub const CRYPT_OID_INFO_NO_SIGN_ALGORITHM: &'static str = "CryptOIDInfoNoSign"; +pub const CRYPT_OID_INFO_OAEP_PARAMETERS_ALGORITHM: &'static str = "CryptOIDInfoOAEPParameters"; +pub const CRYPT_OID_INFO_ECC_WRAP_PARAMETERS_ALGORITHM: &'static str + = "CryptOIDInfoECCWrapParameters"; +pub const CRYPT_OID_INFO_NO_PARAMETERS_ALGORITHM: &'static str = "CryptOIDInfoNoParameters"; +UNION!{union CRYPT_OID_INFO_u { + [u32; 1], + dwValue dwValue_mut: DWORD, + Algid Algid_mut: ALG_ID, + dwLength dwLength_mut: DWORD, +}} +STRUCT!{struct CRYPT_OID_INFO { + cbSize: DWORD, + oszOID: LPCSTR, + pwszName: LPCWSTR, + dwGroupId: DWORD, + u: CRYPT_OID_INFO_u, + ExtraInfo: CRYPT_DATA_BLOB, + pwszCNGAlgid: LPCWSTR, + pwszCNGExtraAlgid: LPCWSTR, +}} +pub type PCRYPT_OID_INFO = *mut CRYPT_OID_INFO; +pub type PCCRYPT_OID_INFO = *const CRYPT_OID_INFO; +pub const CRYPT_HASH_ALG_OID_GROUP_ID: DWORD = 1; +pub const CRYPT_ENCRYPT_ALG_OID_GROUP_ID: DWORD = 2; +pub const CRYPT_PUBKEY_ALG_OID_GROUP_ID: DWORD = 3; +pub const CRYPT_SIGN_ALG_OID_GROUP_ID: DWORD = 4; +pub const CRYPT_RDN_ATTR_OID_GROUP_ID: DWORD = 5; +pub const CRYPT_EXT_OR_ATTR_OID_GROUP_ID: DWORD = 6; +pub const CRYPT_ENHKEY_USAGE_OID_GROUP_ID: DWORD = 7; +pub const CRYPT_POLICY_OID_GROUP_ID: DWORD = 8; +pub const CRYPT_TEMPLATE_OID_GROUP_ID: DWORD = 9; +pub const CRYPT_KDF_OID_GROUP_ID: DWORD = 10; +pub const CRYPT_LAST_OID_GROUP_ID: DWORD = 10; +pub const CRYPT_FIRST_ALG_OID_GROUP_ID: DWORD = CRYPT_HASH_ALG_OID_GROUP_ID; +pub const CRYPT_LAST_ALG_OID_GROUP_ID: DWORD = CRYPT_SIGN_ALG_OID_GROUP_ID; +pub const CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG: DWORD = 0x00000001; +pub const CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG: DWORD = 0x00000002; +pub const CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG: DWORD = 0x00000004; +pub const CRYPT_OID_PUBKEY_SIGN_ONLY_FLAG: DWORD = 0x80000000; +pub const CRYPT_OID_PUBKEY_ENCRYPT_ONLY_FLAG: DWORD = 0x40000000; +pub const CRYPT_OID_USE_CURVE_NAME_FOR_ENCODE_FLAG: DWORD = 0x20000000; +pub const CRYPT_OID_USE_CURVE_PARAMETERS_FOR_ENCODE_FLAG: DWORD = 0x10000000; +extern "system" { + pub fn CryptFindOIDInfo( + dwKeyType: DWORD, + pvKey: *mut c_void, + dwGroupId: DWORD, + ) -> PCCRYPT_OID_INFO; +} +pub const CRYPT_OID_INFO_OID_KEY: DWORD = 1; +pub const CRYPT_OID_INFO_NAME_KEY: DWORD = 2; +pub const CRYPT_OID_INFO_ALGID_KEY: DWORD = 3; +pub const CRYPT_OID_INFO_SIGN_KEY: DWORD = 4; +pub const CRYPT_OID_INFO_CNG_ALGID_KEY: DWORD = 5; +pub const CRYPT_OID_INFO_CNG_SIGN_KEY: DWORD = 6; +pub const CRYPT_OID_INFO_OID_KEY_FLAGS_MASK: DWORD = 0xFFFF0000; +pub const CRYPT_OID_INFO_PUBKEY_SIGN_KEY_FLAG: DWORD = 0x80000000; +pub const CRYPT_OID_INFO_PUBKEY_ENCRYPT_KEY_FLAG: DWORD = 0x40000000; +pub const CRYPT_OID_DISABLE_SEARCH_DS_FLAG: DWORD = 0x80000000; +pub const CRYPT_OID_PREFER_CNG_ALGID_FLAG: DWORD = 0x40000000; +pub const CRYPT_OID_INFO_OID_GROUP_BIT_LEN_MASK: DWORD = 0x0FFF0000; +pub const CRYPT_OID_INFO_OID_GROUP_BIT_LEN_SHIFT: DWORD = 16; +extern "system" { + pub fn CryptRegisterOIDInfo( + pInfo: PCCRYPT_OID_INFO, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptUnregisterOIDInfo( + pInfo: PCCRYPT_OID_INFO, + ) -> BOOL; +} +FN!{stdcall PFN_CRYPT_ENUM_OID_INFO( + pInfo: PCCRYPT_OID_INFO, + pvArg: *mut c_void, +) -> BOOL} +extern "system" { + pub fn CryptEnumOIDInfo( + dwGroupId: DWORD, + dwFlags: DWORD, + pvArg: *mut c_void, + pfnEnumOIDInfo: PFN_CRYPT_ENUM_OID_INFO, + ) -> BOOL; + pub fn CryptFindLocalizedName( + pwszCryptName: LPCWSTR, + ) -> LPCWSTR; +} +pub const CRYPT_LOCALIZED_NAME_ENCODING_TYPE: DWORD = 0; +pub const CRYPT_LOCALIZED_NAME_OID: &'static str = "LocalizedNames"; +STRUCT!{struct CERT_STRONG_SIGN_SERIALIZED_INFO { + dwFlags: DWORD, + pwszCNGSignHashAlgids: LPWSTR, + pwszCNGPubKeyMinBitLengths: LPWSTR, +}} +pub type PCERT_STRONG_SIGN_SERIALIZED_INFO = *mut CERT_STRONG_SIGN_SERIALIZED_INFO; +pub const CERT_STRONG_SIGN_ECDSA_ALGORITHM: &'static str = "ECDSA"; +UNION!{union CERT_STRONG_SIGN_PARA_u { + [usize; 1], + pvInfo pvInfo_mut: *mut c_void, + pSerializedInfo pSerializedInfo_mut: PCERT_STRONG_SIGN_SERIALIZED_INFO, + pszOID pszOID_mut: LPSTR, +}} +STRUCT!{struct CERT_STRONG_SIGN_PARA { + cbSize: DWORD, + dwInfoChoice: DWORD, + u: CERT_STRONG_SIGN_PARA_u, +}} +pub type PCERT_STRONG_SIGN_PARA = *mut CERT_STRONG_SIGN_PARA; +pub type PCCERT_STRONG_SIGN_PARA = *const CERT_STRONG_SIGN_PARA; +pub const CERT_STRONG_SIGN_SERIALIZED_INFO_CHOICE: DWORD = 1; +pub const CERT_STRONG_SIGN_OID_INFO_CHOICE: DWORD = 2; +pub const CERT_STRONG_SIGN_ENABLE_CRL_CHECK: DWORD = 0x1; +pub const CERT_STRONG_SIGN_ENABLE_OCSP_CHECK: DWORD = 0x2; +pub const szOID_CERT_STRONG_SIGN_OS_PREFIX: &'static str = "1.3.6.1.4.1.311.72.1."; +pub const szOID_CERT_STRONG_SIGN_OS_1: &'static str = "1.3.6.1.4.1.311.72.1.1"; +pub const szOID_CERT_STRONG_SIGN_OS_CURRENT: &'static str = szOID_CERT_STRONG_SIGN_OS_1; +pub const szOID_CERT_STRONG_KEY_OS_PREFIX: &'static str = "1.3.6.1.4.1.311.72.2."; +pub const szOID_CERT_STRONG_KEY_OS_1: &'static str = "1.3.6.1.4.1.311.72.2.1"; +pub const szOID_CERT_STRONG_KEY_OS_CURRENT: &'static str = szOID_CERT_STRONG_KEY_OS_1; +pub type HCRYPTMSG = *mut c_void; +pub const szOID_PKCS_7_DATA: &'static str = "1.2.840.113549.1.7.1"; +pub const szOID_PKCS_7_SIGNED: &'static str = "1.2.840.113549.1.7.2"; +pub const szOID_PKCS_7_ENVELOPED: &'static str = "1.2.840.113549.1.7.3"; +pub const szOID_PKCS_7_SIGNEDANDENVELOPED: &'static str = "1.2.840.113549.1.7.4"; +pub const szOID_PKCS_7_DIGESTED: &'static str = "1.2.840.113549.1.7.5"; +pub const szOID_PKCS_7_ENCRYPTED: &'static str = "1.2.840.113549.1.7.6"; +pub const szOID_PKCS_9_CONTENT_TYPE: &'static str = "1.2.840.113549.1.9.3"; +pub const szOID_PKCS_9_MESSAGE_DIGEST: &'static str = "1.2.840.113549.1.9.4"; +pub const CMSG_DATA: DWORD = 1; +pub const CMSG_SIGNED: DWORD = 2; +pub const CMSG_ENVELOPED: DWORD = 3; +pub const CMSG_SIGNED_AND_ENVELOPED: DWORD = 4; +pub const CMSG_HASHED: DWORD = 5; +pub const CMSG_ENCRYPTED: DWORD = 6; +pub const CMSG_ALL_FLAGS: DWORD = !0; +pub const CMSG_DATA_FLAG: DWORD = 1 << CMSG_DATA; +pub const CMSG_SIGNED_FLAG: DWORD = 1 << CMSG_SIGNED; +pub const CMSG_ENVELOPED_FLAG: DWORD = 1 << CMSG_ENVELOPED; +pub const CMSG_SIGNED_AND_ENVELOPED_FLAG: DWORD = 1 << CMSG_SIGNED_AND_ENVELOPED; +pub const CMSG_HASHED_FLAG: DWORD = 1 << CMSG_HASHED; +pub const CMSG_ENCRYPTED_FLAG: DWORD = 1 << CMSG_ENCRYPTED; +STRUCT!{struct CERT_ISSUER_SERIAL_NUMBER { + Issuer: CERT_NAME_BLOB, + SerialNumber: CRYPT_INTEGER_BLOB, +}} +pub type PCERT_ISSUER_SERIAL_NUMBER = *mut CERT_ISSUER_SERIAL_NUMBER; +UNION!{union CERT_ID_u { + [usize; 4], + IssuerSerialNumber IssuerSerialNumber_mut: CERT_ISSUER_SERIAL_NUMBER, + KeyId KeyId_mut: CRYPT_HASH_BLOB, + HashId HashId_mut: CRYPT_HASH_BLOB, +}} +STRUCT!{struct CERT_ID { + dwIdChoice: DWORD, + u: CERT_ID_u, +}} +pub type PCERT_ID = *mut CERT_ID; +pub const CERT_ID_ISSUER_SERIAL_NUMBER: DWORD = 1; +pub const CERT_ID_KEY_IDENTIFIER: DWORD = 2; +pub const CERT_ID_SHA1_HASH: DWORD = 3; +UNION!{union CMSG_SIGNER_ENCODE_INFO_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, + hBCryptKey hBCryptKey_mut: BCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CMSG_SIGNER_ENCODE_INFO { + cbSize: DWORD, + pCertInfo: PCERT_INFO, + u: CMSG_SIGNER_ENCODE_INFO_u, + dwKeySpec: DWORD, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *mut c_void, + cAuthAttr: DWORD, + rgAuthAttr: PCRYPT_ATTRIBUTE, + cUnauthAttr: DWORD, + rgUnauthAttr: PCRYPT_ATTRIBUTE, + SignerId: CERT_ID, + HashEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashEncryptionAuxInfo: *mut c_void, +}} +pub type PCMSG_SIGNER_ENCODE_INFO = *mut CMSG_SIGNER_ENCODE_INFO; +STRUCT!{struct CMSG_SIGNED_ENCODE_INFO { + cbSize: DWORD, + cSigners: DWORD, + rgSigners: PCMSG_SIGNER_ENCODE_INFO, + cCertEncoded: DWORD, + rgCertEncoded: PCERT_BLOB, + cCrlEncoded: DWORD, + rgCrlEncoded: PCRL_BLOB, + cAttrCertEncoded: DWORD, + rgAttrCertEncoded: PCERT_BLOB, +}} +pub type PCMSG_SIGNED_ENCODE_INFO = *mut CMSG_SIGNED_ENCODE_INFO; +pub type PCMSG_RECIPIENT_ENCODE_INFO = *mut CMSG_RECIPIENT_ENCODE_INFO; +STRUCT!{struct CMSG_ENVELOPED_ENCODE_INFO { + cbSize: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + ContentEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvEncryptionAuxInfo: *mut c_void, + cRecipients: DWORD, + rgpRecipients: *mut PCERT_INFO, + rgCmsRecipients: PCMSG_RECIPIENT_ENCODE_INFO, + cCertEncoded: DWORD, + rgCertEncoded: PCERT_BLOB, + cCrlEncoded: DWORD, + rgCrlEncoded: PCRL_BLOB, + cAttrCertEncoded: DWORD, + rgAttrCertEncoded: PCERT_BLOB, + cUnprotectedAttr: DWORD, + rgUnprotectedAttr: PCRYPT_ATTRIBUTE, +}} +pub type PCMSG_ENVELOPED_ENCODE_INFO = *mut CMSG_ENVELOPED_ENCODE_INFO; +STRUCT!{struct CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO { + cbSize: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvKeyEncryptionAuxInfo: *mut c_void, + hCryptProv: HCRYPTPROV_LEGACY, + RecipientPublicKey: CRYPT_BIT_BLOB, + RecipientId: CERT_ID, +}} +pub type PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO = *mut CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO; +STRUCT!{struct CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO { + cbSize: DWORD, + RecipientPublicKey: CRYPT_BIT_BLOB, + RecipientId: CERT_ID, + Date: FILETIME, + pOtherAttr: PCRYPT_ATTRIBUTE_TYPE_VALUE, +}} +pub type PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO = *mut CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO; +UNION!{union CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO_u { + [usize; 1], + pEphemeralAlgorithm pEphemeralAlgorithm_mut: PCRYPT_ALGORITHM_IDENTIFIER, + pSenderId pSenderId_mut: PCERT_ID, +}} +STRUCT!{struct CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO { + cbSize: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvKeyEncryptionAuxInfo: *mut c_void, + KeyWrapAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvKeyWrapAuxInfo: *mut c_void, + hCryptProv: HCRYPTPROV_LEGACY, + dwKeySpec: DWORD, + dwKeyChoice: DWORD, + u: CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO_u, + UserKeyingMaterial: CRYPT_DATA_BLOB, + cRecipientEncryptedKeys: DWORD, + rgpRecipientEncryptedKeys: *mut PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO, +}} +pub type PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO = *mut CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO; +pub const CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE: DWORD = 1; +pub const CMSG_KEY_AGREE_STATIC_KEY_CHOICE: DWORD = 2; +UNION!{union CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO_u { + [usize; 1], + hKeyEncryptionKey hKeyEncryptionKey_mut: HCRYPTKEY, + pvKeyEncryptionKey pvKeyEncryptionKey_mut: *mut c_void, +}} +STRUCT!{struct CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO { + cbSize: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvKeyEncryptionAuxInfo: *mut c_void, + hCryptProv: HCRYPTPROV, + dwKeyChoice: DWORD, + u: CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO_u, + KeyId: CRYPT_DATA_BLOB, + Date: FILETIME, + pOtherAttr: PCRYPT_ATTRIBUTE_TYPE_VALUE, +}} +pub type PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO = *mut CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO; +pub const CMSG_MAIL_LIST_HANDLE_KEY_CHOICE: DWORD = 1; +UNION!{union CMSG_RECIPIENT_ENCODE_INFO_u { + [usize; 1], + pKeyTrans pKeyTrans_mut: PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO, + pKeyAgree pKeyAgree_mut: PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO, + pMailList pMailList_mut: PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO, +}} +STRUCT!{struct CMSG_RECIPIENT_ENCODE_INFO { + dwRecipientChoice: DWORD, + u: CMSG_RECIPIENT_ENCODE_INFO_u, +}} +pub const CMSG_KEY_TRANS_RECIPIENT: DWORD = 1; +pub const CMSG_KEY_AGREE_RECIPIENT: DWORD = 2; +pub const CMSG_MAIL_LIST_RECIPIENT: DWORD = 3; +STRUCT!{struct CMSG_RC2_AUX_INFO { + cbSize: DWORD, + dwBitLen: DWORD, +}} +pub type PCMSG_RC2_AUX_INFO = *mut CMSG_RC2_AUX_INFO; +STRUCT!{struct CMSG_SP3_COMPATIBLE_AUX_INFO { + cbSize: DWORD, + dwFlags: DWORD, +}} +pub type PCMSG_SP3_COMPATIBLE_AUX_INFO = *mut CMSG_SP3_COMPATIBLE_AUX_INFO; +pub const CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG: DWORD = 0x80000000; +STRUCT!{struct CMSG_RC4_AUX_INFO { + cbSize: DWORD, + dwBitLen: DWORD, +}} +pub type PCMSG_RC4_AUX_INFO = *mut CMSG_RC4_AUX_INFO; +pub const CMSG_RC4_NO_SALT_FLAG: DWORD = 0x40000000; +STRUCT!{struct CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO { + cbSize: DWORD, + SignedInfo: CMSG_SIGNED_ENCODE_INFO, + EnvelopedInfo: CMSG_ENVELOPED_ENCODE_INFO, +}} +pub type PCMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO = *mut CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO; +STRUCT!{struct CMSG_HASHED_ENCODE_INFO { + cbSize: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *mut c_void, +}} +pub type PCMSG_HASHED_ENCODE_INFO = *mut CMSG_HASHED_ENCODE_INFO; +STRUCT!{struct CMSG_ENCRYPTED_ENCODE_INFO { + cbSize: DWORD, + ContentEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvEncryptionAuxInfo: *mut c_void, +}} +pub type PCMSG_ENCRYPTED_ENCODE_INFO = *mut CMSG_ENCRYPTED_ENCODE_INFO; +FN!{stdcall PFN_CMSG_STREAM_OUTPUT( + pvArg: *const c_void, + pbData: *mut BYTE, + cbData: DWORD, + fFinal: BOOL, +) -> BOOL} +pub const CMSG_INDEFINITE_LENGTH: DWORD = 0xFFFFFFFF; +STRUCT!{struct CMSG_STREAM_INFO { + cbContent: DWORD, + pfnStreamOutput: PFN_CMSG_STREAM_OUTPUT, + pvArg: *mut c_void, +}} +pub type PCMSG_STREAM_INFO = *mut CMSG_STREAM_INFO; +pub const CMSG_BARE_CONTENT_FLAG: DWORD = 0x00000001; +pub const CMSG_LENGTH_ONLY_FLAG: DWORD = 0x00000002; +pub const CMSG_DETACHED_FLAG: DWORD = 0x00000004; +pub const CMSG_AUTHENTICATED_ATTRIBUTES_FLAG: DWORD = 0x00000008; +pub const CMSG_CONTENTS_OCTETS_FLAG: DWORD = 0x00000010; +pub const CMSG_MAX_LENGTH_FLAG: DWORD = 0x00000020; +pub const CMSG_CMS_ENCAPSULATED_CONTENT_FLAG: DWORD = 0x00000040; +pub const CMSG_SIGNED_DATA_NO_SIGN_FLAG: DWORD = 0x00000080; +pub const CMSG_CRYPT_RELEASE_CONTEXT_FLAG: DWORD = 0x00008000; +extern "system" { + pub fn CryptMsgOpenToEncode( + dwMsgEncodingType: DWORD, + dwFlags: DWORD, + dwMsgType: DWORD, + pvMsgEncodeInfo: *mut c_void, + pszInnerContentObjID: LPSTR, + pStreamInfo: PCMSG_STREAM_INFO, + ) -> HCRYPTMSG; + pub fn CryptMsgCalculateEncodedLength( + dwMsgEncodingType: DWORD, + dwFlags: DWORD, + dwMsgType: DWORD, + pvMsgEncodeInfo: *const c_void, + pszInnerContentObjID: LPSTR, + cbData: DWORD, + ) -> DWORD; + pub fn CryptMsgOpenToDecode( + dwMsgEncodingType: DWORD, + dwFlags: DWORD, + dwMsgType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + pRecipientInfo: PCERT_INFO, + pStreamInfo: PCMSG_STREAM_INFO, + ) -> HCRYPTMSG; + pub fn CryptMsgDuplicate( + hCryptMsg: HCRYPTMSG, + ) -> HCRYPTMSG; + pub fn CryptMsgClose( + hCryptMsg: HCRYPTMSG, + ) -> BOOL; + pub fn CryptMsgUpdate( + hCryptMsg: HCRYPTMSG, + pbData: *const BYTE, + cbData: DWORD, + fFinal: BOOL, + ) -> BOOL; + pub fn CryptMsgGetParam( + hCryptMsg: HCRYPTMSG, + dwParamType: DWORD, + dwIndex: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; +} +pub const CMSG_TYPE_PARAM: DWORD = 1; +pub const CMSG_CONTENT_PARAM: DWORD = 2; +pub const CMSG_BARE_CONTENT_PARAM: DWORD = 3; +pub const CMSG_INNER_CONTENT_TYPE_PARAM: DWORD = 4; +pub const CMSG_SIGNER_COUNT_PARAM: DWORD = 5; +pub const CMSG_SIGNER_INFO_PARAM: DWORD = 6; +pub const CMSG_SIGNER_CERT_INFO_PARAM: DWORD = 7; +pub const CMSG_SIGNER_HASH_ALGORITHM_PARAM: DWORD = 8; +pub const CMSG_SIGNER_AUTH_ATTR_PARAM: DWORD = 9; +pub const CMSG_SIGNER_UNAUTH_ATTR_PARAM: DWORD = 10; +pub const CMSG_CERT_COUNT_PARAM: DWORD = 11; +pub const CMSG_CERT_PARAM: DWORD = 12; +pub const CMSG_CRL_COUNT_PARAM: DWORD = 13; +pub const CMSG_CRL_PARAM: DWORD = 14; +pub const CMSG_ENVELOPE_ALGORITHM_PARAM: DWORD = 15; +pub const CMSG_RECIPIENT_COUNT_PARAM: DWORD = 17; +pub const CMSG_RECIPIENT_INDEX_PARAM: DWORD = 18; +pub const CMSG_RECIPIENT_INFO_PARAM: DWORD = 19; +pub const CMSG_HASH_ALGORITHM_PARAM: DWORD = 20; +pub const CMSG_HASH_DATA_PARAM: DWORD = 21; +pub const CMSG_COMPUTED_HASH_PARAM: DWORD = 22; +pub const CMSG_ENCRYPT_PARAM: DWORD = 26; +pub const CMSG_ENCRYPTED_DIGEST: DWORD = 27; +pub const CMSG_ENCODED_SIGNER: DWORD = 28; +pub const CMSG_ENCODED_MESSAGE: DWORD = 29; +pub const CMSG_VERSION_PARAM: DWORD = 30; +pub const CMSG_ATTR_CERT_COUNT_PARAM: DWORD = 31; +pub const CMSG_ATTR_CERT_PARAM: DWORD = 32; +pub const CMSG_CMS_RECIPIENT_COUNT_PARAM: DWORD = 33; +pub const CMSG_CMS_RECIPIENT_INDEX_PARAM: DWORD = 34; +pub const CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM: DWORD = 35; +pub const CMSG_CMS_RECIPIENT_INFO_PARAM: DWORD = 36; +pub const CMSG_UNPROTECTED_ATTR_PARAM: DWORD = 37; +pub const CMSG_SIGNER_CERT_ID_PARAM: DWORD = 38; +pub const CMSG_CMS_SIGNER_INFO_PARAM: DWORD = 39; +STRUCT!{struct CMSG_SIGNER_INFO { + dwVersion: DWORD, + Issuer: CERT_NAME_BLOB, + SerialNumber: CRYPT_INTEGER_BLOB, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + HashEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedHash: CRYPT_DATA_BLOB, + AuthAttrs: CRYPT_ATTRIBUTES, + UnauthAttrs: CRYPT_ATTRIBUTES, +}} +pub type PCMSG_SIGNER_INFO = *mut CMSG_SIGNER_INFO; +STRUCT!{struct CMSG_CMS_SIGNER_INFO { + dwVersion: DWORD, + SignerId: CERT_ID, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + HashEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedHash: CRYPT_DATA_BLOB, + AuthAttrs: CRYPT_ATTRIBUTES, + UnauthAttrs: CRYPT_ATTRIBUTES, +}} +pub type PCMSG_CMS_SIGNER_INFO = *mut CMSG_CMS_SIGNER_INFO; +pub type CMSG_ATTR = CRYPT_ATTRIBUTES; +pub type PCMSG_ATTR = *mut CRYPT_ATTRIBUTES; +pub const CMSG_SIGNED_DATA_V1: DWORD = 1; +pub const CMSG_SIGNED_DATA_V3: DWORD = 3; +pub const CMSG_SIGNED_DATA_PKCS_1_5_VERSION: DWORD = CMSG_SIGNED_DATA_V1; +pub const CMSG_SIGNED_DATA_CMS_VERSION: DWORD = CMSG_SIGNED_DATA_V3; +pub const CMSG_SIGNER_INFO_V1: DWORD = 1; +pub const CMSG_SIGNER_INFO_V3: DWORD = 3; +pub const CMSG_SIGNER_INFO_PKCS_1_5_VERSION: DWORD = CMSG_SIGNER_INFO_V1; +pub const CMSG_SIGNER_INFO_CMS_VERSION: DWORD = CMSG_SIGNER_INFO_V3; +pub const CMSG_HASHED_DATA_V0: DWORD = 0; +pub const CMSG_HASHED_DATA_V2: DWORD = 2; +pub const CMSG_HASHED_DATA_PKCS_1_5_VERSION: DWORD = CMSG_HASHED_DATA_V0; +pub const CMSG_HASHED_DATA_CMS_VERSION: DWORD = CMSG_HASHED_DATA_V2; +pub const CMSG_ENVELOPED_DATA_V0: DWORD = 0; +pub const CMSG_ENVELOPED_DATA_V2: DWORD = 2; +pub const CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION: DWORD = CMSG_ENVELOPED_DATA_V0; +pub const CMSG_ENVELOPED_DATA_CMS_VERSION: DWORD = CMSG_ENVELOPED_DATA_V2; +STRUCT!{struct CMSG_KEY_TRANS_RECIPIENT_INFO { + dwVersion: DWORD, + RecipientId: CERT_ID, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedKey: CRYPT_DATA_BLOB, +}} +pub type PCMSG_KEY_TRANS_RECIPIENT_INFO = *mut CMSG_KEY_TRANS_RECIPIENT_INFO; +STRUCT!{struct CMSG_RECIPIENT_ENCRYPTED_KEY_INFO { + RecipientId: CERT_ID, + EncryptedKey: CRYPT_DATA_BLOB, + Date: FILETIME, + pOtherAttr: PCRYPT_ATTRIBUTE_TYPE_VALUE, +}} +pub type PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO = *mut CMSG_RECIPIENT_ENCRYPTED_KEY_INFO; +UNION!{union CMSG_KEY_AGREE_RECIPIENT_INFO_u { + [usize; 6], + OriginatorCertId OriginatorCertId_mut: CERT_ID, + OriginatorPublicKeyInfo OriginatorPublicKeyInfo_mut: CERT_PUBLIC_KEY_INFO, +}} +STRUCT!{struct CMSG_KEY_AGREE_RECIPIENT_INFO { + dwVersion: DWORD, + dwOriginatorChoice: DWORD, + u: CMSG_KEY_AGREE_RECIPIENT_INFO_u, + UserKeyingMaterial: CRYPT_DATA_BLOB, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + cRecipientEncryptedKeys: DWORD, + rgpRecipientEncryptedKeys: *mut PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO, +}} +pub type PCMSG_KEY_AGREE_RECIPIENT_INFO = *mut CMSG_KEY_AGREE_RECIPIENT_INFO; +pub const CMSG_KEY_AGREE_ORIGINATOR_CERT: DWORD = 1; +pub const CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY: DWORD = 2; +STRUCT!{struct CMSG_MAIL_LIST_RECIPIENT_INFO { + dwVersion: DWORD, + KeyId: CRYPT_DATA_BLOB, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedKey: CRYPT_DATA_BLOB, + Date: FILETIME, + pOtherAttr: PCRYPT_ATTRIBUTE_TYPE_VALUE, +}} +pub type PCMSG_MAIL_LIST_RECIPIENT_INFO = *mut CMSG_MAIL_LIST_RECIPIENT_INFO; +UNION!{union CMSG_CMS_RECIPIENT_INFO_u { + [usize; 1], + pKeyTrans pKeyTrans_mut: PCMSG_KEY_TRANS_RECIPIENT_INFO, + pKeyAgree pKeyAgree_mut: PCMSG_KEY_AGREE_RECIPIENT_INFO, + pMailList pMailList_mut: PCMSG_MAIL_LIST_RECIPIENT_INFO, +}} +STRUCT!{struct CMSG_CMS_RECIPIENT_INFO { + dwRecipientChoice: DWORD, + u: CMSG_CMS_RECIPIENT_INFO_u, +}} +pub type PCMSG_CMS_RECIPIENT_INFO = *mut CMSG_CMS_RECIPIENT_INFO; +pub const CMSG_ENVELOPED_RECIPIENT_V0: DWORD = 0; +pub const CMSG_ENVELOPED_RECIPIENT_V2: DWORD = 2; +pub const CMSG_ENVELOPED_RECIPIENT_V3: DWORD = 3; +pub const CMSG_ENVELOPED_RECIPIENT_V4: DWORD = 4; +pub const CMSG_KEY_TRANS_PKCS_1_5_VERSION: DWORD = CMSG_ENVELOPED_RECIPIENT_V0; +pub const CMSG_KEY_TRANS_CMS_VERSION: DWORD = CMSG_ENVELOPED_RECIPIENT_V2; +pub const CMSG_KEY_AGREE_VERSION: DWORD = CMSG_ENVELOPED_RECIPIENT_V3; +pub const CMSG_MAIL_LIST_VERSION: DWORD = CMSG_ENVELOPED_RECIPIENT_V4; +extern "system" { + pub fn CryptMsgControl( + hCryptMsg: HCRYPTMSG, + dwFlags: DWORD, + dwCtrlType: DWORD, + pvCtrlPara: *const c_void, + ) -> BOOL; +} +pub const CMSG_CTRL_VERIFY_SIGNATURE: DWORD = 1; +pub const CMSG_CTRL_DECRYPT: DWORD = 2; +pub const CMSG_CTRL_VERIFY_HASH: DWORD = 5; +pub const CMSG_CTRL_ADD_SIGNER: DWORD = 6; +pub const CMSG_CTRL_DEL_SIGNER: DWORD = 7; +pub const CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR: DWORD = 8; +pub const CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR: DWORD = 9; +pub const CMSG_CTRL_ADD_CERT: DWORD = 10; +pub const CMSG_CTRL_DEL_CERT: DWORD = 11; +pub const CMSG_CTRL_ADD_CRL: DWORD = 12; +pub const CMSG_CTRL_DEL_CRL: DWORD = 13; +pub const CMSG_CTRL_ADD_ATTR_CERT: DWORD = 14; +pub const CMSG_CTRL_DEL_ATTR_CERT: DWORD = 15; +pub const CMSG_CTRL_KEY_TRANS_DECRYPT: DWORD = 16; +pub const CMSG_CTRL_KEY_AGREE_DECRYPT: DWORD = 17; +pub const CMSG_CTRL_MAIL_LIST_DECRYPT: DWORD = 18; +pub const CMSG_CTRL_VERIFY_SIGNATURE_EX: DWORD = 19; +pub const CMSG_CTRL_ADD_CMS_SIGNER_INFO: DWORD = 20; +pub const CMSG_CTRL_ENABLE_STRONG_SIGNATURE: DWORD = 21; +STRUCT!{struct CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA { + cbSize: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + dwSignerIndex: DWORD, + dwSignerType: DWORD, + pvSigner: *mut c_void, +}} +pub type PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA = *mut CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA; +pub const CMSG_VERIFY_SIGNER_PUBKEY: DWORD = 1; +pub const CMSG_VERIFY_SIGNER_CERT: DWORD = 2; +pub const CMSG_VERIFY_SIGNER_CHAIN: DWORD = 3; +pub const CMSG_VERIFY_SIGNER_NULL: DWORD = 4; +UNION!{union CMSG_CTRL_DECRYPT_PARA_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CMSG_CTRL_DECRYPT_PARA { + cbSize: DWORD, + u: CMSG_CTRL_DECRYPT_PARA_u, + dwKeySpec: DWORD, + dwRecipientIndex: DWORD, +}} +pub type PCMSG_CTRL_DECRYPT_PARA = *mut CMSG_CTRL_DECRYPT_PARA; +UNION!{union CMSG_CTRL_KEY_TRANS_DECRYPT_PARA_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CMSG_CTRL_KEY_TRANS_DECRYPT_PARA { + cbSize: DWORD, + u: CMSG_CTRL_KEY_TRANS_DECRYPT_PARA_u, + dwKeySpec: DWORD, + pKeyTrans: PCMSG_KEY_TRANS_RECIPIENT_INFO, + dwRecipientIndex: DWORD, +}} +pub type PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA = *mut CMSG_CTRL_KEY_TRANS_DECRYPT_PARA; +UNION!{union CMSG_CTRL_KEY_AGREE_DECRYPT_PARA_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CMSG_CTRL_KEY_AGREE_DECRYPT_PARA { + cbSize: DWORD, + u: CMSG_CTRL_KEY_AGREE_DECRYPT_PARA_u, + dwKeySpec: DWORD, + pKeyAgree: PCMSG_KEY_AGREE_RECIPIENT_INFO, + dwRecipientIndex: DWORD, + dwRecipientEncryptedKeyIndex: DWORD, + OriginatorPublicKey: CRYPT_BIT_BLOB, +}} +pub type PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA = *mut CMSG_CTRL_KEY_AGREE_DECRYPT_PARA; +UNION!{union CMSG_CTRL_MAIL_LIST_DECRYPT_PARA_u { + [usize; 1], + hKeyEncryptionKey hKeyEncryptionKey_mut: HCRYPTKEY, + pvKeyEncryptionKey pvKeyEncryptionKey_mut: *mut c_void, +}} +STRUCT!{struct CMSG_CTRL_MAIL_LIST_DECRYPT_PARA { + cbSize: DWORD, + hCryptProv: HCRYPTPROV, + pMailList: PCMSG_MAIL_LIST_RECIPIENT_INFO, + dwRecipientIndex: DWORD, + dwKeyChoice: DWORD, + u: CMSG_CTRL_MAIL_LIST_DECRYPT_PARA_u, +}} +pub type PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA = *mut CMSG_CTRL_MAIL_LIST_DECRYPT_PARA; +STRUCT!{struct CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA { + cbSize: DWORD, + dwSignerIndex: DWORD, + blob: CRYPT_DATA_BLOB, +}} +pub type PCMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA = *mut CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA; +STRUCT!{struct CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA { + cbSize: DWORD, + dwSignerIndex: DWORD, + dwUnauthAttrIndex: DWORD, +}} +pub type PCMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA = *mut CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA; +extern "system" { + pub fn CryptMsgVerifyCountersignatureEncoded( + hCryptProv: HCRYPTPROV_LEGACY, + dwEncodingType: DWORD, + pbSignerInfo: PBYTE, + cbSignerInfo: DWORD, + pbSignerInfoCountersignature: PBYTE, + cbSignerInfoCountersignature: DWORD, + pciCountersigner: PCERT_INFO, + ) -> BOOL; + pub fn CryptMsgVerifyCountersignatureEncodedEx( + hCryptProv: HCRYPTPROV_LEGACY, + dwEncodingType: DWORD, + pbSignerInfo: PBYTE, + cbSignerInfo: DWORD, + pbSignerInfoCountersignature: PBYTE, + cbSignerInfoCountersignature: DWORD, + dwSignerType: DWORD, + pvSigner: *mut c_void, + dwFlags: DWORD, + pvExtra: *mut c_void, + ) -> BOOL; +} +pub const CMSG_VERIFY_COUNTER_SIGN_ENABLE_STRONG_FLAG: DWORD = 0x00000001; +extern "system" { + pub fn CryptMsgCountersign( + hCryptMsg: HCRYPTMSG, + dwIndex: DWORD, + cCountersigners: DWORD, + rgCountersigners: PCMSG_SIGNER_ENCODE_INFO, + ) -> BOOL; + pub fn CryptMsgCountersignEncoded( + dwEncodingType: DWORD, + pbSignerInfo: PBYTE, + cbSignerInfo: DWORD, + cCountersigners: DWORD, + rgCountersigners: PCMSG_SIGNER_ENCODE_INFO, + pbCountersignature: PBYTE, + pcbCountersignature: PDWORD, + ) -> BOOL; +} +FN!{stdcall PFN_CMSG_ALLOC( + cb: size_t, +) -> ()} +FN!{stdcall PFN_CMSG_FREE( + pv: *mut c_void, +) -> ()} +pub const CMSG_OID_GEN_ENCRYPT_KEY_FUNC: &'static str = "CryptMsgDllGenEncryptKey"; +FN!{stdcall PFN_CMSG_GEN_ENCRYPT_KEY( + phCryptProv: *mut HCRYPTPROV, + paiEncrypt: PCRYPT_ALGORITHM_IDENTIFIER, + pvEncryptAuxInfo: PVOID, + pPublicKeyInfo: PCERT_PUBLIC_KEY_INFO, + pfnAlloc: PFN_CMSG_ALLOC, + phEncryptKey: *mut HCRYPTKEY, + ppbEncryptParameters: *mut PBYTE, + pcbEncryptParameters: PDWORD, +) -> BOOL} +pub const CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC: &'static str = "CryptMsgDllExportEncryptKey"; +FN!{stdcall PFN_CMSG_EXPORT_ENCRYPT_KEY( + hCryptProv: HCRYPTPROV, + hEncryptKey: HCRYPTKEY, + pPublicKeyInfo: PCERT_PUBLIC_KEY_INFO, + pbData: PBYTE, + pcbData: PDWORD, +) -> BOOL} +pub const CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC: &'static str = "CryptMsgDllImportEncryptKey"; +FN!{stdcall PFN_CMSG_IMPORT_ENCRYPT_KEY( + hCryptProv: HCRYPTPROV, + dwKeySpec: DWORD, + paiEncrypt: PCRYPT_ALGORITHM_IDENTIFIER, + paiPubKey: PCRYPT_ALGORITHM_IDENTIFIER, + pbEncodedKey: PBYTE, + cbEncodedKey: DWORD, + phEncryptKey: *mut HCRYPTKEY, +) -> BOOL} +pub const CMSG_DEFAULT_INSTALLABLE_FUNC_OID: LPCSTR = 1 as LPCSTR; +UNION!{union CMSG_CONTENT_ENCRYPT_INFO_u { + [usize; 1], + hContentEncryptKey hContentEncryptKey_mut: HCRYPTKEY, + hCNGContentEncryptKey hCNGContentEncryptKey_mut: BCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CMSG_CONTENT_ENCRYPT_INFO { + cbSize: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + ContentEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvEncryptionAuxInfo: *mut c_void, + cRecipients: DWORD, + rgCmsRecipients: PCMSG_RECIPIENT_ENCODE_INFO, + pfnAlloc: PFN_CMSG_ALLOC, + pfnFree: PFN_CMSG_FREE, + dwEncryptFlags: DWORD, + u: CMSG_CONTENT_ENCRYPT_INFO_u, + dwFlags: DWORD, + fCNG: BOOL, + pbCNGContentEncryptKeyObject: *mut BYTE, + pbContentEncryptKey: *mut BYTE, + cbContentEncryptKey: DWORD, +}} +pub type PCMSG_CONTENT_ENCRYPT_INFO = *mut CMSG_CONTENT_ENCRYPT_INFO; +pub const CMSG_CONTENT_ENCRYPT_PAD_ENCODED_LEN_FLAG: DWORD = 0x00000001; +pub const CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG: DWORD = 0x00000001; +pub const CMSG_CONTENT_ENCRYPT_FREE_OBJID_FLAG: DWORD = 0x00000002; +pub const CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG: DWORD = 0x00008000; +pub const CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC: &'static str = "CryptMsgDllGenContentEncryptKey"; +pub const CMSG_OID_CAPI1_GEN_CONTENT_ENCRYPT_KEY_FUNC: &'static str + = CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC; +FN!{stdcall PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY( + pContentEncryptInfo: PCMSG_CONTENT_ENCRYPT_INFO, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_CNG_GEN_CONTENT_ENCRYPT_KEY_FUNC: &'static str + = "CryptMsgDllCNGGenContentEncryptKey"; +STRUCT!{struct CMSG_KEY_TRANS_ENCRYPT_INFO { + cbSize: DWORD, + dwRecipientIndex: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedKey: CRYPT_DATA_BLOB, + dwFlags: DWORD, +}} +pub type PCMSG_KEY_TRANS_ENCRYPT_INFO = *mut CMSG_KEY_TRANS_ENCRYPT_INFO; +pub const CMSG_KEY_TRANS_ENCRYPT_FREE_PARA_FLAG: DWORD = 0x00000001; +pub const CMSG_KEY_TRANS_ENCRYPT_FREE_OBJID_FLAG: DWORD = 0x00000002; +pub const CMSG_OID_EXPORT_KEY_TRANS_FUNC: &'static str = "CryptMsgDllExportKeyTrans"; +pub const CMSG_OID_CAPI1_EXPORT_KEY_TRANS_FUNC: &'static str = CMSG_OID_EXPORT_KEY_TRANS_FUNC; +FN!{stdcall PFN_CMSG_EXPORT_KEY_TRANS( + pContentEncryptInfo: PCMSG_CONTENT_ENCRYPT_INFO, + pKeyTransEncodeInfo: PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO, + pKeyTransEncryptInfo: PCMSG_KEY_TRANS_ENCRYPT_INFO, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_CNG_EXPORT_KEY_TRANS_FUNC: &'static str = "CryptMsgDllCNGExportKeyTrans"; +STRUCT!{struct CMSG_KEY_AGREE_KEY_ENCRYPT_INFO { + cbSize: DWORD, + EncryptedKey: CRYPT_DATA_BLOB, +}} +pub type PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO = *mut CMSG_KEY_AGREE_KEY_ENCRYPT_INFO; +UNION!{union CMSG_KEY_AGREE_ENCRYPT_INFO_u { + [usize; 6], + OriginatorCertId OriginatorCertId_mut: CERT_ID, + OriginatorPublicKeyInfo OriginatorPublicKeyInfo_mut: CERT_PUBLIC_KEY_INFO, +}} +STRUCT!{struct CMSG_KEY_AGREE_ENCRYPT_INFO { + cbSize: DWORD, + dwRecipientIndex: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + UserKeyingMaterial: CRYPT_DATA_BLOB, + dwOriginatorChoice: DWORD, + u: CMSG_KEY_AGREE_ENCRYPT_INFO_u, + cKeyAgreeKeyEncryptInfo: DWORD, + rgpKeyAgreeKeyEncryptInfo: *mut PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO, + dwFlags: DWORD, +}} +pub type PCMSG_KEY_AGREE_ENCRYPT_INFO = *mut CMSG_KEY_AGREE_ENCRYPT_INFO; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_PARA_FLAG: DWORD = 0x00000001; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_MATERIAL_FLAG: DWORD = 0x00000002; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_ALG_FLAG: DWORD = 0x00000004; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_PARA_FLAG: DWORD = 0x00000008; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_BITS_FLAG: DWORD = 0x00000010; +pub const CMSG_KEY_AGREE_ENCRYPT_FREE_OBJID_FLAG: DWORD = 0x00000020; +pub const CMSG_OID_EXPORT_KEY_AGREE_FUNC: &'static str = "CryptMsgDllExportKeyAgree"; +pub const CMSG_OID_CAPI1_EXPORT_KEY_AGREE_FUNC: &'static str = CMSG_OID_EXPORT_KEY_AGREE_FUNC; +FN!{stdcall PFN_CMSG_EXPORT_KEY_AGREE( + pContentEncryptInfo: PCMSG_CONTENT_ENCRYPT_INFO, + pKeyAgreeEncodeInfo: PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO, + pKeyAgreeEncryptInfo: PCMSG_KEY_AGREE_ENCRYPT_INFO, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_CNG_EXPORT_KEY_AGREE_FUNC: &'static str = "CryptMsgDllCNGExportKeyAgree"; +STRUCT!{struct CMSG_MAIL_LIST_ENCRYPT_INFO { + cbSize: DWORD, + dwRecipientIndex: DWORD, + KeyEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + EncryptedKey: CRYPT_DATA_BLOB, + dwFlags: DWORD, +}} +pub type PCMSG_MAIL_LIST_ENCRYPT_INFO = *mut CMSG_MAIL_LIST_ENCRYPT_INFO; +pub const CMSG_MAIL_LIST_ENCRYPT_FREE_PARA_FLAG: DWORD = 0x00000001; +pub const CMSG_MAIL_LIST_ENCRYPT_FREE_OBJID_FLAG: DWORD = 0x00000002; +pub const CMSG_OID_EXPORT_MAIL_LIST_FUNC: &'static str = "CryptMsgDllExportMailList"; +pub const CMSG_OID_CAPI1_EXPORT_MAIL_LIST_FUNC: &'static str = CMSG_OID_EXPORT_MAIL_LIST_FUNC; +FN!{stdcall PFN_CMSG_EXPORT_MAIL_LIST( + pContentEncryptInfo: PCMSG_CONTENT_ENCRYPT_INFO, + pMailListEncodeInfo: PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO, + pMailListEncryptInfo: PCMSG_MAIL_LIST_ENCRYPT_INFO, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_IMPORT_KEY_TRANS_FUNC: &'static str = "CryptMsgDllImportKeyTrans"; +pub const CMSG_OID_CAPI1_IMPORT_KEY_TRANS_FUNC: &'static str = CMSG_OID_IMPORT_KEY_TRANS_FUNC; +FN!{stdcall PFN_CMSG_IMPORT_KEY_TRANS( + pContentEncryptionAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pKeyTransDecryptPara: PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA, + dwFlags: DWORD, + pvReserved: *mut c_void, + phContentEncryptKey: *mut HCRYPTKEY, +) -> BOOL} +pub const CMSG_OID_IMPORT_KEY_AGREE_FUNC: &'static str = "CryptMsgDllImportKeyAgree"; +pub const CMSG_OID_CAPI1_IMPORT_KEY_AGREE_FUNC: &'static str = CMSG_OID_IMPORT_KEY_AGREE_FUNC; +FN!{stdcall PFN_CMSG_IMPORT_KEY_AGREE( + pContentEncryptionAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pKeyAgreeDecryptPara: PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA, + dwFlags: DWORD, + pvReserved: *mut c_void, + phContentEncryptKey: *mut HCRYPTKEY, +) -> BOOL} +pub const CMSG_OID_IMPORT_MAIL_LIST_FUNC: &'static str = "CryptMsgDllImportMailList"; +pub const CMSG_OID_CAPI1_IMPORT_MAIL_LIST_FUNC: &'static str = CMSG_OID_IMPORT_MAIL_LIST_FUNC; +FN!{stdcall PFN_CMSG_IMPORT_MAIL_LIST( + pContentEncryptionAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pMailListDecryptPara: PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA, + dwFlags: DWORD, + pvReserved: *mut c_void, + phContentEncryptKey: *mut HCRYPTKEY, +) -> BOOL} +STRUCT!{struct CMSG_CNG_CONTENT_DECRYPT_INFO { + cbSize: DWORD, + ContentEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pfnAlloc: PFN_CMSG_ALLOC, + pfnFree: PFN_CMSG_FREE, + hNCryptKey: NCRYPT_KEY_HANDLE, + pbContentEncryptKey: *mut BYTE, + cbContentEncryptKey: DWORD, + hCNGContentEncryptKey: BCRYPT_KEY_HANDLE, + pbCNGContentEncryptKeyObject: *mut BYTE, +}} +pub type PCMSG_CNG_CONTENT_DECRYPT_INFO = *mut CMSG_CNG_CONTENT_DECRYPT_INFO; +pub const CMSG_OID_CNG_IMPORT_KEY_TRANS_FUNC: &'static str = "CryptMsgDllCNGImportKeyTrans"; +FN!{stdcall PFN_CMSG_CNG_IMPORT_KEY_TRANS( + pCNGContentDecryptInfo: PCMSG_CNG_CONTENT_DECRYPT_INFO, + pKeyTransDecryptPara: PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_CNG_IMPORT_KEY_AGREE_FUNC: &'static str = "CryptMsgDllCNGImportKeyAgree"; +FN!{stdcall PFN_CMSG_CNG_IMPORT_KEY_AGREE( + pCNGContentDecryptInfo: PCMSG_CNG_CONTENT_DECRYPT_INFO, + pKeyAgreeDecryptPara: PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub const CMSG_OID_CNG_IMPORT_CONTENT_ENCRYPT_KEY_FUNC: &'static str + = "CryptMsgDllCNGImportContentEncryptKey"; +FN!{stdcall PFN_CMSG_CNG_IMPORT_CONTENT_ENCRYPT_KEY( + pCNGContentDecryptInfo: PCMSG_CNG_CONTENT_DECRYPT_INFO, + dwFlags: DWORD, + pvReserved: *mut c_void, +) -> BOOL} +pub type HCERTSTORE = *mut c_void; +STRUCT!{struct CERT_CONTEXT { + dwCertEncodingType: DWORD, + pbCertEncoded: *mut BYTE, + cbCertEncoded: DWORD, + pCertInfo: PCERT_INFO, + hCertStore: HCERTSTORE, +}} +pub type PCERT_CONTEXT = *mut CERT_CONTEXT; +pub type PCCERT_CONTEXT = *const CERT_CONTEXT; +STRUCT!{struct CRL_CONTEXT { + dwCertEncodingType: DWORD, + pbCrlEncoded: *mut BYTE, + cbCrlEncoded: DWORD, + pCrlInfo: PCRL_INFO, + hCertStore: HCERTSTORE, +}} +pub type PCRL_CONTEXT = *mut CRL_CONTEXT; +pub type PCCRL_CONTEXT = *const CRL_CONTEXT; +STRUCT!{struct CTL_CONTEXT { + dwMsgAndCertEncodingType: DWORD, + pbCtlEncoded: *mut BYTE, + cbCtlEncoded: DWORD, + pCtlInfo: PCTL_INFO, + hCertStore: HCERTSTORE, + hCryptMsg: HCRYPTMSG, + pbCtlContent: *mut BYTE, + cbCtlContent: DWORD, +}} +pub type PCTL_CONTEXT = *mut CTL_CONTEXT; +pub type PCCTL_CONTEXT = *const CTL_CONTEXT; +pub const CERT_KEY_PROV_HANDLE_PROP_ID: DWORD = 1; +pub const CERT_KEY_PROV_INFO_PROP_ID: DWORD = 2; +pub const CERT_SHA1_HASH_PROP_ID: DWORD = 3; +pub const CERT_MD5_HASH_PROP_ID: DWORD = 4; +pub const CERT_HASH_PROP_ID: DWORD = CERT_SHA1_HASH_PROP_ID; +pub const CERT_KEY_CONTEXT_PROP_ID: DWORD = 5; +pub const CERT_KEY_SPEC_PROP_ID: DWORD = 6; +pub const CERT_IE30_RESERVED_PROP_ID: DWORD = 7; +pub const CERT_PUBKEY_HASH_RESERVED_PROP_ID: DWORD = 8; +pub const CERT_ENHKEY_USAGE_PROP_ID: DWORD = 9; +pub const CERT_CTL_USAGE_PROP_ID: DWORD = CERT_ENHKEY_USAGE_PROP_ID; +pub const CERT_NEXT_UPDATE_LOCATION_PROP_ID: DWORD = 10; +pub const CERT_FRIENDLY_NAME_PROP_ID: DWORD = 11; +pub const CERT_PVK_FILE_PROP_ID: DWORD = 12; +pub const CERT_DESCRIPTION_PROP_ID: DWORD = 13; +pub const CERT_ACCESS_STATE_PROP_ID: DWORD = 14; +pub const CERT_SIGNATURE_HASH_PROP_ID: DWORD = 15; +pub const CERT_SMART_CARD_DATA_PROP_ID: DWORD = 16; +pub const CERT_EFS_PROP_ID: DWORD = 17; +pub const CERT_FORTEZZA_DATA_PROP_ID: DWORD = 18; +pub const CERT_ARCHIVED_PROP_ID: DWORD = 19; +pub const CERT_KEY_IDENTIFIER_PROP_ID: DWORD = 20; +pub const CERT_AUTO_ENROLL_PROP_ID: DWORD = 21; +pub const CERT_PUBKEY_ALG_PARA_PROP_ID: DWORD = 22; +pub const CERT_CROSS_CERT_DIST_POINTS_PROP_ID: DWORD = 23; +pub const CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: DWORD = 24; +pub const CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID: DWORD = 25; +pub const CERT_ENROLLMENT_PROP_ID: DWORD = 26; +pub const CERT_DATE_STAMP_PROP_ID: DWORD = 27; +pub const CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: DWORD = 28; +pub const CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: DWORD = 29; +pub const CERT_EXTENDED_ERROR_INFO_PROP_ID: DWORD = 30; +pub const CERT_RENEWAL_PROP_ID: DWORD = 64; +pub const CERT_ARCHIVED_KEY_HASH_PROP_ID: DWORD = 65; +pub const CERT_AUTO_ENROLL_RETRY_PROP_ID: DWORD = 66; +pub const CERT_AIA_URL_RETRIEVED_PROP_ID: DWORD = 67; +pub const CERT_AUTHORITY_INFO_ACCESS_PROP_ID: DWORD = 68; +pub const CERT_BACKED_UP_PROP_ID: DWORD = 69; +pub const CERT_OCSP_RESPONSE_PROP_ID: DWORD = 70; +pub const CERT_REQUEST_ORIGINATOR_PROP_ID: DWORD = 71; +pub const CERT_SOURCE_LOCATION_PROP_ID: DWORD = 72; +pub const CERT_SOURCE_URL_PROP_ID: DWORD = 73; +pub const CERT_NEW_KEY_PROP_ID: DWORD = 74; +pub const CERT_OCSP_CACHE_PREFIX_PROP_ID: DWORD = 75; +pub const CERT_SMART_CARD_ROOT_INFO_PROP_ID: DWORD = 76; +pub const CERT_NO_AUTO_EXPIRE_CHECK_PROP_ID: DWORD = 77; +pub const CERT_NCRYPT_KEY_HANDLE_PROP_ID: DWORD = 78; +pub const CERT_HCRYPTPROV_OR_NCRYPT_KEY_HANDLE_PROP_ID: DWORD = 79; +pub const CERT_SUBJECT_INFO_ACCESS_PROP_ID: DWORD = 80; +pub const CERT_CA_OCSP_AUTHORITY_INFO_ACCESS_PROP_ID: DWORD = 81; +pub const CERT_CA_DISABLE_CRL_PROP_ID: DWORD = 82; +pub const CERT_ROOT_PROGRAM_CERT_POLICIES_PROP_ID: DWORD = 83; +pub const CERT_ROOT_PROGRAM_NAME_CONSTRAINTS_PROP_ID: DWORD = 84; +pub const CERT_SUBJECT_OCSP_AUTHORITY_INFO_ACCESS_PROP_ID: DWORD = 85; +pub const CERT_SUBJECT_DISABLE_CRL_PROP_ID: DWORD = 86; +pub const CERT_CEP_PROP_ID: DWORD = 87; +pub const CERT_SIGN_HASH_CNG_ALG_PROP_ID: DWORD = 89; +pub const CERT_SCARD_PIN_ID_PROP_ID: DWORD = 90; +pub const CERT_SCARD_PIN_INFO_PROP_ID: DWORD = 91; +pub const CERT_SUBJECT_PUB_KEY_BIT_LENGTH_PROP_ID: DWORD = 92; +pub const CERT_PUB_KEY_CNG_ALG_BIT_LENGTH_PROP_ID: DWORD = 93; +pub const CERT_ISSUER_PUB_KEY_BIT_LENGTH_PROP_ID: DWORD = 94; +pub const CERT_ISSUER_CHAIN_SIGN_HASH_CNG_ALG_PROP_ID: DWORD = 95; +pub const CERT_ISSUER_CHAIN_PUB_KEY_CNG_ALG_BIT_LENGTH_PROP_ID: DWORD = 96; +pub const CERT_NO_EXPIRE_NOTIFICATION_PROP_ID: DWORD = 97; +pub const CERT_AUTH_ROOT_SHA256_HASH_PROP_ID: DWORD = 98; +pub const CERT_NCRYPT_KEY_HANDLE_TRANSFER_PROP_ID: DWORD = 99; +pub const CERT_HCRYPTPROV_TRANSFER_PROP_ID: DWORD = 100; +pub const CERT_SMART_CARD_READER_PROP_ID: DWORD = 101; +pub const CERT_SEND_AS_TRUSTED_ISSUER_PROP_ID: DWORD = 102; +pub const CERT_KEY_REPAIR_ATTEMPTED_PROP_ID: DWORD = 103; +pub const CERT_DISALLOWED_FILETIME_PROP_ID: DWORD = 104; +pub const CERT_ROOT_PROGRAM_CHAIN_POLICIES_PROP_ID: DWORD = 105; +pub const CERT_SMART_CARD_READER_NON_REMOVABLE_PROP_ID: DWORD = 106; +pub const CERT_SHA256_HASH_PROP_ID: DWORD = 107; +pub const CERT_SCEP_SERVER_CERTS_PROP_ID: DWORD = 108; +pub const CERT_SCEP_RA_SIGNATURE_CERT_PROP_ID: DWORD = 109; +pub const CERT_SCEP_RA_ENCRYPTION_CERT_PROP_ID: DWORD = 110; +pub const CERT_SCEP_CA_CERT_PROP_ID: DWORD = 111; +pub const CERT_SCEP_SIGNER_CERT_PROP_ID: DWORD = 112; +pub const CERT_SCEP_NONCE_PROP_ID: DWORD = 113; +pub const CERT_SCEP_ENCRYPT_HASH_CNG_ALG_PROP_ID: DWORD = 114; +pub const CERT_SCEP_FLAGS_PROP_ID: DWORD = 115; +pub const CERT_SCEP_GUID_PROP_ID: DWORD = 116; +pub const CERT_SERIALIZABLE_KEY_CONTEXT_PROP_ID: DWORD = 117; +pub const CERT_ISOLATED_KEY_PROP_ID: DWORD = 118; +pub const CERT_SERIAL_CHAIN_PROP_ID: DWORD = 119; +pub const CERT_KEY_CLASSIFICATION_PROP_ID: DWORD = 120; +pub const CERT_OCSP_MUST_STAPLE_PROP_ID: DWORD = 121; +pub const CERT_DISALLOWED_ENHKEY_USAGE_PROP_ID: DWORD = 122; +pub const CERT_NONCOMPLIANT_ROOT_URL_PROP_ID: DWORD = 123; +pub const CERT_PIN_SHA256_HASH_PROP_ID: DWORD = 124; +pub const CERT_CLR_DELETE_KEY_PROP_ID: DWORD = 125; +pub const CERT_NOT_BEFORE_FILETIME_PROP_ID: DWORD = 126; +pub const CERT_NOT_BEFORE_ENHKEY_USAGE_PROP_ID: DWORD = 127; +pub const CERT_FIRST_RESERVED_PROP_ID: DWORD = 128; +pub const CERT_LAST_RESERVED_PROP_ID: DWORD = 0x00007FFF; +pub const CERT_FIRST_USER_PROP_ID: DWORD = 0x00008000; +pub const CERT_LAST_USER_PROP_ID: DWORD = 0x0000FFFF; +ENUM!{enum CertKeyType { + KeyTypeOther = 0, + KeyTypeVirtualSmartCard = 1, + KeyTypePhysicalSmartCard = 2, + KeyTypePassport = 3, + KeyTypePassportRemote = 4, + KeyTypePassportSmartCard = 5, + KeyTypeHardware = 6, + KeyTypeSoftware = 7, + KeyTypeSelfSigned = 8, +}} +#[inline] +pub fn IS_CERT_HASH_PROP_ID(X: DWORD) -> bool { + CERT_SHA1_HASH_PROP_ID == X || CERT_MD5_HASH_PROP_ID == X || CERT_SHA256_HASH_PROP_ID == X + || CERT_SIGNATURE_HASH_PROP_ID == X +} +#[inline] +pub fn IS_PUBKEY_HASH_PROP_ID(X: DWORD) -> bool { + CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID == X || CERT_PIN_SHA256_HASH_PROP_ID == X + || CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID == X +} +#[inline] +pub fn IS_CHAIN_HASH_PROP_ID(X: DWORD) -> bool { + CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID == X || CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID == X + || CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID == X || CERT_SUBJECT_NAME_MD5_HASH_PROP_ID == X +} +#[inline] +pub fn IS_STRONG_SIGN_PROP_ID(X: DWORD) -> bool { + CERT_SIGN_HASH_CNG_ALG_PROP_ID == X || CERT_SUBJECT_PUB_KEY_BIT_LENGTH_PROP_ID == X + || CERT_PUB_KEY_CNG_ALG_BIT_LENGTH_PROP_ID == X +} +pub const szOID_CERT_PROP_ID_PREFIX: &'static str = "1.3.6.1.4.1.311.10.11."; +pub const szOID_CERT_KEY_IDENTIFIER_PROP_ID: &'static str = "1.3.6.1.4.1.311.10.11.20"; +pub const szOID_CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID: &'static str + = "1.3.6.1.4.1.311.10.11.28"; +pub const szOID_CERT_SUBJECT_NAME_MD5_HASH_PROP_ID: &'static str = "1.3.6.1.4.1.311.10.11.29"; +pub const szOID_CERT_MD5_HASH_PROP_ID: &'static str = "1.3.6.1.4.1.311.10.11.4"; +pub const szOID_CERT_SIGNATURE_HASH_PROP_ID: &'static str = "1.3.6.1.4.1.311.10.11.15"; +pub const szOID_DISALLOWED_HASH: &'static str = szOID_CERT_SIGNATURE_HASH_PROP_ID; +pub const szOID_CERT_DISALLOWED_FILETIME_PROP_ID: &'static str = "1.3.6.1.4.1.311.10.11.104"; +pub const CERT_ACCESS_STATE_WRITE_PERSIST_FLAG: DWORD = 0x1; +pub const CERT_ACCESS_STATE_SYSTEM_STORE_FLAG: DWORD = 0x2; +pub const CERT_ACCESS_STATE_LM_SYSTEM_STORE_FLAG: DWORD = 0x4; +pub const CERT_ACCESS_STATE_GP_SYSTEM_STORE_FLAG: DWORD = 0x8; +pub const CERT_ACCESS_STATE_SHARED_USER_FLAG: DWORD = 0x10; +pub const szOID_ROOT_PROGRAM_AUTO_UPDATE_CA_REVOCATION: &'static str = "1.3.6.1.4.1.311.60.3.1"; +pub const szOID_ROOT_PROGRAM_AUTO_UPDATE_END_REVOCATION: &'static str = "1.3.6.1.4.1.311.60.3.2"; +pub const szOID_ROOT_PROGRAM_NO_OCSP_FAILOVER_TO_CRL: &'static str = "1.3.6.1.4.1.311.60.3.3"; +STRUCT!{struct CRYPT_KEY_PROV_PARAM { + dwParam: DWORD, + pbData: *mut BYTE, + cbData: DWORD, + dwFlags: DWORD, +}} +pub type PCRYPT_KEY_PROV_PARAM = *mut CRYPT_KEY_PROV_PARAM; +STRUCT!{struct CRYPT_KEY_PROV_INFO { + pwszContainerName: LPWSTR, + pwszProvName: LPWSTR, + dwProvType: DWORD, + dwFlags: DWORD, + cProvParam: DWORD, + rgProvParam: PCRYPT_KEY_PROV_PARAM, + dwKeySpec: DWORD, +}} +pub type PCRYPT_KEY_PROV_INFO = *mut CRYPT_KEY_PROV_INFO; +pub const CERT_SET_KEY_PROV_HANDLE_PROP_ID: DWORD = 0x00000001; +pub const CERT_SET_KEY_CONTEXT_PROP_ID: DWORD = 0x00000001; +pub const CERT_NCRYPT_KEY_SPEC: DWORD = 0xFFFFFFFF; +UNION!{union CERT_KEY_CONTEXT_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CERT_KEY_CONTEXT { + cbSize: DWORD, + u: CERT_KEY_CONTEXT_u, + dwKeySpec: DWORD, +}} +pub type PCERT_KEY_CONTEXT = *mut CERT_KEY_CONTEXT; +STRUCT!{struct ROOT_INFO_LUID { + LowPart: DWORD, + HighPart: LONG, +}} +pub type PROOT_INFO_LUID = *mut ROOT_INFO_LUID; +STRUCT!{struct CRYPT_SMART_CARD_ROOT_INFO { + rgbCardID: [BYTE; 16], + luid: ROOT_INFO_LUID, +}} +pub type PCRYPT_SMART_CARD_ROOT_INFO = *mut CRYPT_SMART_CARD_ROOT_INFO; +pub const CERT_STORE_PROV_MSG: LPCSTR = 1 as LPCSTR; +pub const CERT_STORE_PROV_MEMORY: LPCSTR = 2 as LPCSTR; +pub const CERT_STORE_PROV_FILE: LPCSTR = 3 as LPCSTR; +pub const CERT_STORE_PROV_REG: LPCSTR = 4 as LPCSTR; +pub const CERT_STORE_PROV_PKCS7: LPCSTR = 5 as LPCSTR; +pub const CERT_STORE_PROV_SERIALIZED: LPCSTR = 6 as LPCSTR; +pub const CERT_STORE_PROV_FILENAME_A: LPCSTR = 7 as LPCSTR; +pub const CERT_STORE_PROV_FILENAME_W: LPCSTR = 8 as LPCSTR; +pub const CERT_STORE_PROV_FILENAME: LPCSTR = CERT_STORE_PROV_FILENAME_W; +pub const CERT_STORE_PROV_SYSTEM_A: LPCSTR = 9 as LPCSTR; +pub const CERT_STORE_PROV_SYSTEM_W: LPCSTR = 10 as LPCSTR; +pub const CERT_STORE_PROV_SYSTEM: LPCSTR = CERT_STORE_PROV_SYSTEM_W; +pub const CERT_STORE_PROV_COLLECTION: LPCSTR = 11 as LPCSTR; +pub const CERT_STORE_PROV_SYSTEM_REGISTRY_A: LPCSTR = 12 as LPCSTR; +pub const CERT_STORE_PROV_SYSTEM_REGISTRY_W: LPCSTR = 13 as LPCSTR; +pub const CERT_STORE_PROV_SYSTEM_REGISTRY: LPCSTR = CERT_STORE_PROV_SYSTEM_REGISTRY_W; +pub const CERT_STORE_PROV_PHYSICAL_W: LPCSTR = 14 as LPCSTR; +pub const CERT_STORE_PROV_PHYSICAL: LPCSTR = CERT_STORE_PROV_PHYSICAL_W; +pub const CERT_STORE_PROV_SMART_CARD_W: LPCSTR = 15 as LPCSTR; +pub const CERT_STORE_PROV_SMART_CARD: LPCSTR = CERT_STORE_PROV_SMART_CARD_W; +pub const CERT_STORE_PROV_LDAP_W: LPCSTR = 16 as LPCSTR; +pub const CERT_STORE_PROV_LDAP: LPCSTR = CERT_STORE_PROV_LDAP_W; +pub const CERT_STORE_PROV_PKCS12: LPCSTR = 17 as LPCSTR; +pub const sz_CERT_STORE_PROV_MEMORY: &'static str = "Memory"; +pub const sz_CERT_STORE_PROV_FILENAME_W: &'static str = "File"; +pub const sz_CERT_STORE_PROV_FILENAME: &'static str = sz_CERT_STORE_PROV_FILENAME_W; +pub const sz_CERT_STORE_PROV_SYSTEM_W: &'static str = "System"; +pub const sz_CERT_STORE_PROV_SYSTEM: &'static str = sz_CERT_STORE_PROV_SYSTEM_W; +pub const sz_CERT_STORE_PROV_PKCS7: &'static str = "PKCS7"; +pub const sz_CERT_STORE_PROV_PKCS12: &'static str = "PKCS12"; +pub const sz_CERT_STORE_PROV_SERIALIZED: &'static str = "Serialized"; +pub const sz_CERT_STORE_PROV_COLLECTION: &'static str = "Collection"; +pub const sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W: &'static str = "SystemRegistry"; +pub const sz_CERT_STORE_PROV_SYSTEM_REGISTRY: &'static str = sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W; +pub const sz_CERT_STORE_PROV_PHYSICAL_W: &'static str = "Physical"; +pub const sz_CERT_STORE_PROV_PHYSICAL: &'static str = sz_CERT_STORE_PROV_PHYSICAL_W; +pub const sz_CERT_STORE_PROV_SMART_CARD_W: &'static str = "SmartCard"; +pub const sz_CERT_STORE_PROV_SMART_CARD: &'static str = sz_CERT_STORE_PROV_SMART_CARD_W; +pub const sz_CERT_STORE_PROV_LDAP_W: &'static str = "Ldap"; +pub const sz_CERT_STORE_PROV_LDAP: &'static str = sz_CERT_STORE_PROV_LDAP_W; +pub const CERT_STORE_SIGNATURE_FLAG: DWORD = 0x00000001; +pub const CERT_STORE_TIME_VALIDITY_FLAG: DWORD = 0x00000002; +pub const CERT_STORE_REVOCATION_FLAG: DWORD = 0x00000004; +pub const CERT_STORE_NO_CRL_FLAG: DWORD = 0x00010000; +pub const CERT_STORE_NO_ISSUER_FLAG: DWORD = 0x00020000; +pub const CERT_STORE_BASE_CRL_FLAG: DWORD = 0x00000100; +pub const CERT_STORE_DELTA_CRL_FLAG: DWORD = 0x00000200; +pub const CERT_STORE_NO_CRYPT_RELEASE_FLAG: DWORD = 0x00000001; +pub const CERT_STORE_SET_LOCALIZED_NAME_FLAG: DWORD = 0x00000002; +pub const CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG: DWORD = 0x00000004; +pub const CERT_STORE_DELETE_FLAG: DWORD = 0x00000010; +pub const CERT_STORE_SHARE_STORE_FLAG: DWORD = 0x00000040; +pub const CERT_STORE_SHARE_CONTEXT_FLAG: DWORD = 0x00000080; +pub const CERT_STORE_MANIFOLD_FLAG: DWORD = 0x00000100; +pub const CERT_STORE_ENUM_ARCHIVED_FLAG: DWORD = 0x00000200; +pub const CERT_STORE_UPDATE_KEYID_FLAG: DWORD = 0x00000400; +pub const CERT_STORE_BACKUP_RESTORE_FLAG: DWORD = 0x00000800; +pub const CERT_STORE_READONLY_FLAG: DWORD = 0x00008000; +pub const CERT_STORE_OPEN_EXISTING_FLAG: DWORD = 0x00004000; +pub const CERT_STORE_CREATE_NEW_FLAG: DWORD = 0x00002000; +pub const CERT_STORE_MAXIMUM_ALLOWED_FLAG: DWORD = 0x00001000; +pub const CERT_SYSTEM_STORE_MASK: DWORD = 0xFFFF0000; +pub const CERT_SYSTEM_STORE_RELOCATE_FLAG: DWORD = 0x80000000; +UNION!{union CERT_SYSTEM_STORE_RELOCATE_PARA_u1 { + [usize; 1], + hKeyBase hKeyBase_mut: HKEY, + pvBase pvBase_mut: *mut c_void, +}} +UNION!{union CERT_SYSTEM_STORE_RELOCATE_PARA_u2 { + [usize; 1], + pvSystemStore pvSystemStore__mut: *mut c_void, + pszSystemStore pszSystemStore_mut: LPCSTR, + pwszSystemStore pwszSystemStore_mut: LPCWSTR, +}} +STRUCT!{struct CERT_SYSTEM_STORE_RELOCATE_PARA { + u1: CERT_SYSTEM_STORE_RELOCATE_PARA_u1, + u2: CERT_SYSTEM_STORE_RELOCATE_PARA_u2, +}} +pub type PCERT_SYSTEM_STORE_RELOCATE_PARA = *mut CERT_SYSTEM_STORE_RELOCATE_PARA; +pub const CERT_SYSTEM_STORE_UNPROTECTED_FLAG: DWORD = 0x40000000; +pub const CERT_SYSTEM_STORE_LOCATION_MASK: DWORD = 0x00FF0000; +pub const CERT_SYSTEM_STORE_LOCATION_SHIFT: DWORD = 16; +pub const CERT_SYSTEM_STORE_CURRENT_USER_ID: DWORD = 1; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE_ID: DWORD = 2; +pub const CERT_SYSTEM_STORE_CURRENT_SERVICE_ID: DWORD = 4; +pub const CERT_SYSTEM_STORE_SERVICES_ID: DWORD = 5; +pub const CERT_SYSTEM_STORE_USERS_ID: DWORD = 6; +pub const CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID: DWORD = 7; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID: DWORD = 8; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID: DWORD = 9; +pub const CERT_SYSTEM_STORE_CURRENT_USER: DWORD = CERT_SYSTEM_STORE_CURRENT_USER_ID + << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE: DWORD = CERT_SYSTEM_STORE_LOCAL_MACHINE_ID + << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_CURRENT_SERVICE: DWORD = CERT_SYSTEM_STORE_CURRENT_SERVICE_ID + << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_SERVICES: DWORD = CERT_SYSTEM_STORE_SERVICES_ID + << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_USERS: DWORD = CERT_SYSTEM_STORE_USERS_ID + << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY: DWORD + = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY: DWORD + = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE: DWORD + = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT; +pub const CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates"; +pub const CERT_EFSBLOB_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates\\EFS"; +pub const CERT_EFSBLOB_VALUE_NAME: &'static str = "EFSBlob"; +pub const CERT_PROT_ROOT_FLAGS_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates\\Root\\ProtectedRoots"; +pub const CERT_PROT_ROOT_FLAGS_VALUE_NAME: &'static str = "Flags"; +pub const CERT_PROT_ROOT_DISABLE_CURRENT_USER_FLAG: DWORD = 0x1; +pub const CERT_PROT_ROOT_INHIBIT_ADD_AT_INIT_FLAG: DWORD = 0x2; +pub const CERT_PROT_ROOT_INHIBIT_PURGE_LM_FLAG: DWORD = 0x4; +pub const CERT_PROT_ROOT_DISABLE_LM_AUTH_FLAG: DWORD = 0x8; +pub const CERT_PROT_ROOT_ONLY_LM_GPT_FLAG: DWORD = 0x8; +pub const CERT_PROT_ROOT_DISABLE_NT_AUTH_REQUIRED_FLAG: DWORD = 0x10; +pub const CERT_PROT_ROOT_DISABLE_NOT_DEFINED_NAME_CONSTRAINT_FLAG: DWORD = 0x20; +pub const CERT_PROT_ROOT_DISABLE_PEER_TRUST: DWORD = 0x10000; +pub const CERT_PROT_ROOT_PEER_USAGES_VALUE_NAME: &'static str = "PeerUsages"; +pub const CERT_PROT_ROOT_PEER_USAGES_VALUE_NAME_A: &'static str = "PeerUsages"; +pub const CERT_PROT_ROOT_PEER_USAGES_DEFAULT_A: &'static str + = "1.3.6.1.5.5.7.3.2\01.3.6.1.5.5.7.3.4\01.3.6.1.4.1.311.10.3.4\0"; +pub const CERT_TRUST_PUB_SAFER_GROUP_POLICY_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates\\TrustedPublisher\\Safer"; +pub const CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH: &'static str + = "Software\\Microsoft\\SystemCertificates"; +pub const CERT_TRUST_PUB_SAFER_LOCAL_MACHINE_REGPATH: &'static str + = "Software\\Microsoft\\SystemCertificates\\TrustedPublisher\\Safer"; +pub const CERT_TRUST_PUB_AUTHENTICODE_FLAGS_VALUE_NAME: &'static str = "AuthenticodeFlags"; +pub const CERT_TRUST_PUB_ALLOW_TRUST_MASK: DWORD = 0x00000003; +pub const CERT_TRUST_PUB_ALLOW_END_USER_TRUST: DWORD = 0x00000000; +pub const CERT_TRUST_PUB_ALLOW_MACHINE_ADMIN_TRUST: DWORD = 0x00000001; +pub const CERT_TRUST_PUB_ALLOW_ENTERPRISE_ADMIN_TRUST: DWORD = 0x00000002; +pub const CERT_TRUST_PUB_CHECK_PUBLISHER_REV_FLAG: DWORD = 0x00000100; +pub const CERT_TRUST_PUB_CHECK_TIMESTAMP_REV_FLAG: DWORD = 0x00000200; +pub const CERT_OCM_SUBCOMPONENTS_LOCAL_MACHINE_REGPATH: &'static str + = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\OC Manager\\Subcomponents"; +pub const CERT_OCM_SUBCOMPONENTS_ROOT_AUTO_UPDATE_VALUE_NAME: &'static str = "RootAutoUpdate"; +pub const CERT_DISABLE_ROOT_AUTO_UPDATE_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates\\AuthRoot"; +pub const CERT_DISABLE_ROOT_AUTO_UPDATE_VALUE_NAME: &'static str = "DisableRootAutoUpdate"; +pub const CERT_ENABLE_DISALLOWED_CERT_AUTO_UPDATE_VALUE_NAME: &'static str + = "EnableDisallowedCertAutoUpdate"; +pub const CERT_DISABLE_PIN_RULES_AUTO_UPDATE_VALUE_NAME: &'static str + = "DisablePinRulesAutoUpdate"; +pub const CERT_AUTO_UPDATE_LOCAL_MACHINE_REGPATH: &'static str + = "Software\\Microsoft\\SystemCertificates\\AuthRoot\\AutoUpdate"; +pub const CERT_AUTO_UPDATE_ROOT_DIR_URL_VALUE_NAME: &'static str = "RootDirUrl"; +pub const CERT_AUTO_UPDATE_SYNC_FROM_DIR_URL_VALUE_NAME: &'static str = "SyncFromDirUrl"; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_LOCAL_MACHINE_REGPATH: &'static str + = CERT_AUTO_UPDATE_LOCAL_MACHINE_REGPATH; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_ROOT_DIR_URL_VALUE_NAME: &'static str + = CERT_AUTO_UPDATE_ROOT_DIR_URL_VALUE_NAME; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_SYNC_DELTA_TIME_VALUE_NAME: &'static str = "SyncDeltaTime"; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_FLAGS_VALUE_NAME: &'static str = "Flags"; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_UNTRUSTED_ROOT_LOGGING_FLAG: DWORD = 0x1; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_PARTIAL_CHAIN_LOGGING_FLAG: DWORD = 0x2; +pub const CERT_AUTO_UPDATE_DISABLE_RANDOM_QUERY_STRING_FLAG: DWORD = 0x4; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_LAST_SYNC_TIME_VALUE_NAME: &'static str = "LastSyncTime"; +pub const CERT_AUTH_ROOT_AUTO_UPDATE_ENCODED_CTL_VALUE_NAME: &'static str = "EncodedCt"; +pub const CERT_AUTH_ROOT_CTL_FILENAME: &'static str = "authroot.st"; +pub const CERT_AUTH_ROOT_CTL_FILENAME_A: &'static str = "authroot.st"; +pub const CERT_AUTH_ROOT_CAB_FILENAME: &'static str = "authrootstl.cab"; +pub const CERT_AUTH_ROOT_SEQ_FILENAME: &'static str = "authrootseq.txt"; +pub const CERT_AUTH_ROOT_CERT_EXT: &'static str = ".crt"; +pub const CERT_DISALLOWED_CERT_AUTO_UPDATE_SYNC_DELTA_TIME_VALUE_NAME: &'static str + = "DisallowedCertSyncDeltaTime"; +pub const CERT_DISALLOWED_CERT_AUTO_UPDATE_LAST_SYNC_TIME_VALUE_NAME: &'static str + = "DisallowedCertLastSyncTime"; +pub const CERT_DISALLOWED_CERT_AUTO_UPDATE_ENCODED_CTL_VALUE_NAME: &'static str + = "DisallowedCertEncodedCt"; +pub const CERT_DISALLOWED_CERT_CTL_FILENAME: &'static str = "disallowedcert.st"; +pub const CERT_DISALLOWED_CERT_CTL_FILENAME_A: &'static str = "disallowedcert.st"; +pub const CERT_DISALLOWED_CERT_CAB_FILENAME: &'static str = "disallowedcertstl.cab"; +pub const CERT_DISALLOWED_CERT_AUTO_UPDATE_LIST_IDENTIFIER: &'static str + = "DisallowedCert_AutoUpdate_1"; +pub const CERT_PIN_RULES_AUTO_UPDATE_SYNC_DELTA_TIME_VALUE_NAME: &'static str + = "PinRulesSyncDeltaTime"; +pub const CERT_PIN_RULES_AUTO_UPDATE_LAST_SYNC_TIME_VALUE_NAME: &'static str + = "PinRulesLastSyncTime"; +pub const CERT_PIN_RULES_AUTO_UPDATE_ENCODED_CTL_VALUE_NAME: &'static str = "PinRulesEncodedCt"; +pub const CERT_PIN_RULES_CTL_FILENAME: &'static str = "pinrules.st"; +pub const CERT_PIN_RULES_CTL_FILENAME_A: &'static str = "pinrules.st"; +pub const CERT_PIN_RULES_CAB_FILENAME: &'static str = "pinrulesstl.cab"; +pub const CERT_PIN_RULES_AUTO_UPDATE_LIST_IDENTIFIER: &'static str = "PinRules_AutoUpdate_1"; +pub const CERT_REGISTRY_STORE_REMOTE_FLAG: DWORD = 0x10000; +pub const CERT_REGISTRY_STORE_SERIALIZED_FLAG: DWORD = 0x20000; +pub const CERT_REGISTRY_STORE_CLIENT_GPT_FLAG: DWORD = 0x80000000; +pub const CERT_REGISTRY_STORE_LM_GPT_FLAG: DWORD = 0x01000000; +STRUCT!{struct CERT_REGISTRY_STORE_CLIENT_GPT_PARA { + hKeyBase: HKEY, + pwszRegPath: LPWSTR, +}} +pub type PCERT_REGISTRY_STORE_CLIENT_GPT_PARA = *mut CERT_REGISTRY_STORE_CLIENT_GPT_PARA; +pub const CERT_REGISTRY_STORE_ROAMING_FLAG: DWORD = 0x40000; +STRUCT!{struct CERT_REGISTRY_STORE_ROAMING_PARA { + hKeyBase: HKEY, + pwszStoreDirectory: LPWSTR, +}} +pub type PCERT_REGISTRY_STORE_ROAMING_PARA = *mut CERT_REGISTRY_STORE_ROAMING_PARA; +pub const CERT_REGISTRY_STORE_MY_IE_DIRTY_FLAG: DWORD = 0x80000; +pub const CERT_REGISTRY_STORE_EXTERNAL_FLAG: DWORD = 0x100000; +pub const CERT_IE_DIRTY_FLAGS_REGPATH: &'static str + = "Software\\Microsoft\\Cryptography\\IEDirtyFlags"; +pub const CERT_FILE_STORE_COMMIT_ENABLE_FLAG: DWORD = 0x10000; +pub const CERT_LDAP_STORE_SIGN_FLAG: DWORD = 0x10000; +pub const CERT_LDAP_STORE_AREC_EXCLUSIVE_FLAG: DWORD = 0x20000; +pub const CERT_LDAP_STORE_OPENED_FLAG: DWORD = 0x40000; +STRUCT!{struct CERT_LDAP_STORE_OPENED_PARA { + pvLdapSessionHandle: *mut c_void, + pwszLdapUrl: LPCWSTR, +}} +pub type PCERT_LDAP_STORE_OPENED_PARA = *mut CERT_LDAP_STORE_OPENED_PARA; +pub const CERT_LDAP_STORE_UNBIND_FLAG: DWORD = 0x80000; +extern "system" { + pub fn CertOpenStore( + lpszStoreProvider: LPCSTR, + dwEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + dwFlags: DWORD, + pvPara: *const c_void, + ) -> HCERTSTORE; +} +pub type HCERTSTOREPROV = *mut c_void; +pub const CRYPT_OID_OPEN_STORE_PROV_FUNC: &'static str = "CertDllOpenStoreProv"; +STRUCT!{struct CERT_STORE_PROV_INFO { + cbSize: DWORD, + cStoreProvFunc: DWORD, + rgpvStoreProvFunc: *mut *mut c_void, + hStoreProv: HCERTSTOREPROV, + dwStoreProvFlags: DWORD, + hStoreProvFuncAddr2: HCRYPTOIDFUNCADDR, +}} +pub type PCERT_STORE_PROV_INFO = *mut CERT_STORE_PROV_INFO; +FN!{stdcall PFN_CERT_DLL_OPEN_STORE_PROV_FUNC( + lpszStoreProvider: LPCSTR, + dwEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + dwFlags: DWORD, + pvPara: *const c_void, + hCertStore: HCERTSTORE, + pStoreProvInfo: PCERT_STORE_PROV_INFO, +) -> BOOL} +pub const CERT_STORE_PROV_EXTERNAL_FLAG: DWORD = 0x1; +pub const CERT_STORE_PROV_DELETED_FLAG: DWORD = 0x2; +pub const CERT_STORE_PROV_NO_PERSIST_FLAG: DWORD = 0x4; +pub const CERT_STORE_PROV_SYSTEM_STORE_FLAG: DWORD = 0x8; +pub const CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG: DWORD = 0x10; +pub const CERT_STORE_PROV_GP_SYSTEM_STORE_FLAG: DWORD = 0x20; +pub const CERT_STORE_PROV_SHARED_USER_FLAG: DWORD = 0x40; +pub const CERT_STORE_PROV_CLOSE_FUNC: DWORD = 0; +pub const CERT_STORE_PROV_READ_CERT_FUNC: DWORD = 1; +pub const CERT_STORE_PROV_WRITE_CERT_FUNC: DWORD = 2; +pub const CERT_STORE_PROV_DELETE_CERT_FUNC: DWORD = 3; +pub const CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC: DWORD = 4; +pub const CERT_STORE_PROV_READ_CRL_FUNC: DWORD = 5; +pub const CERT_STORE_PROV_WRITE_CRL_FUNC: DWORD = 6; +pub const CERT_STORE_PROV_DELETE_CRL_FUNC: DWORD = 7; +pub const CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC: DWORD = 8; +pub const CERT_STORE_PROV_READ_CTL_FUNC: DWORD = 9; +pub const CERT_STORE_PROV_WRITE_CTL_FUNC: DWORD = 10; +pub const CERT_STORE_PROV_DELETE_CTL_FUNC: DWORD = 11; +pub const CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC: DWORD = 12; +pub const CERT_STORE_PROV_CONTROL_FUNC: DWORD = 13; +pub const CERT_STORE_PROV_FIND_CERT_FUNC: DWORD = 14; +pub const CERT_STORE_PROV_FREE_FIND_CERT_FUNC: DWORD = 15; +pub const CERT_STORE_PROV_GET_CERT_PROPERTY_FUNC: DWORD = 16; +pub const CERT_STORE_PROV_FIND_CRL_FUNC: DWORD = 17; +pub const CERT_STORE_PROV_FREE_FIND_CRL_FUNC: DWORD = 18; +pub const CERT_STORE_PROV_GET_CRL_PROPERTY_FUNC: DWORD = 19; +pub const CERT_STORE_PROV_FIND_CTL_FUNC: DWORD = 20; +pub const CERT_STORE_PROV_FREE_FIND_CTL_FUNC: DWORD = 21; +pub const CERT_STORE_PROV_GET_CTL_PROPERTY_FUNC: DWORD = 22; +FN!{stdcall PFN_CERT_STORE_PROV_CLOSE( + hStoreProv: HCERTSTOREPROV, + dwFlags: DWORD, +) -> ()} +FN!{stdcall PFN_CERT_STORE_PROV_READ_CERT( + hStoreProv: HCERTSTOREPROV, + pStoreCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, + ppProvCertContext: *mut PCCERT_CONTEXT, +) -> BOOL} +pub const CERT_STORE_PROV_WRITE_ADD_FLAG: DWORD = 0x1; +FN!{stdcall PFN_CERT_STORE_PROV_WRITE_CERT( + hStoreProv: HCERTSTOREPROV, + pCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_DELETE_CERT( + hStoreProv: HCERTSTOREPROV, + pCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_SET_CERT_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCertContext: PCCERT_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_READ_CRL( + hStoreProv: HCERTSTOREPROV, + pStoreCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, + ppProvCrlContext: *mut PCCRL_CONTEXT, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_WRITE_CRL( + hStoreProv: HCERTSTOREPROV, + pCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_DELETE_CRL( + hStoreProv: HCERTSTOREPROV, + pCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_SET_CRL_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCrlContext: PCCRL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_READ_CTL( + hStoreProv: HCERTSTOREPROV, + pStoreCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, + ppProvCtlContext: *mut PCCTL_CONTEXT, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_WRITE_CTL( + hStoreProv: HCERTSTOREPROV, + pCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_DELETE_CTL( + hStoreProv: HCERTSTOREPROV, + pCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_SET_CTL_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCtlContext: PCCTL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_CONTROL( + hStoreProv: HCERTSTOREPROV, + dwFlags: DWORD, + dwCtrlType: DWORD, + pvCtrlPara: *const c_void, +) -> BOOL} +STRUCT!{struct CERT_STORE_PROV_FIND_INFO { + cbSize: DWORD, + dwMsgAndCertEncodingType: DWORD, + dwFindFlags: DWORD, + dwFindType: DWORD, + pvFindPara: *const c_void, +}} +pub type PCERT_STORE_PROV_FIND_INFO = *mut CERT_STORE_PROV_FIND_INFO; +pub type CCERT_STORE_PROV_FIND_INFO = CERT_STORE_PROV_FIND_INFO; +pub type PCCERT_STORE_PROV_FIND_INFO = *const CERT_STORE_PROV_FIND_INFO; +FN!{stdcall PFN_CERT_STORE_PROV_FIND_CERT( + hStoreProv: HCERTSTOREPROV, + pFindInfo: PCCERT_STORE_PROV_FIND_INFO, + pPrevCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, + ppvStoreProvFindInfo: *mut *mut c_void, + ppProvCertContext: *mut PCCERT_CONTEXT, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_FREE_FIND_CERT( + hStoreProv: HCERTSTOREPROV, + pCertContext: PCCERT_CONTEXT, + pvStoreProvFindInfo: *mut c_void, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_GET_CERT_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCertContext: PCCERT_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_FIND_CRL( + hStoreProv: HCERTSTOREPROV, + pFindInfo: PCCERT_STORE_PROV_FIND_INFO, + pPrevCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, + ppvStoreProvFindInfo: *mut *mut c_void, + ppProvCrlContext: *mut PCCRL_CONTEXT, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_FREE_FIND_CRL( + hStoreProv: HCERTSTOREPROV, + pCrlContext: PCCRL_CONTEXT, + pvStoreProvFindInfo: *mut c_void, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_GET_CRL_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCrlContext: PCCRL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_FIND_CTL( + hStoreProv: HCERTSTOREPROV, + pFindInfo: PCCERT_STORE_PROV_FIND_INFO, + pPrevCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, + ppvStoreProvFindInfo: *mut *mut c_void, + ppProvCtlContext: *mut PCCTL_CONTEXT, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_FREE_FIND_CTL( + hStoreProv: HCERTSTOREPROV, + pCtlContext: PCCTL_CONTEXT, + pvStoreProvFindInfo: *mut c_void, + dwFlags: DWORD, +) -> BOOL} +FN!{stdcall PFN_CERT_STORE_PROV_GET_CTL_PROPERTY( + hStoreProv: HCERTSTOREPROV, + pCtlContext: PCCTL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, +) -> BOOL} +extern "system" { + pub fn CertDuplicateStore( + hCertStore: HCERTSTORE, + ) -> HCERTSTORE; +} +pub const CERT_STORE_SAVE_AS_STORE: DWORD = 1; +pub const CERT_STORE_SAVE_AS_PKCS7: DWORD = 2; +pub const CERT_STORE_SAVE_AS_PKCS12: DWORD = 3; +pub const CERT_STORE_SAVE_TO_FILE: DWORD = 1; +pub const CERT_STORE_SAVE_TO_MEMORY: DWORD = 2; +pub const CERT_STORE_SAVE_TO_FILENAME_A: DWORD = 3; +pub const CERT_STORE_SAVE_TO_FILENAME_W: DWORD = 4; +pub const CERT_STORE_SAVE_TO_FILENAME: DWORD = CERT_STORE_SAVE_TO_FILENAME_W; +extern "system" { + pub fn CertSaveStore( + hCertStore: HCERTSTORE, + dwEncodingType: DWORD, + dwSaveAs: DWORD, + dwSaveTo: DWORD, + pvSaveToPara: *mut c_void, + dwFlags: DWORD, + ) -> BOOL; +} +pub const CERT_CLOSE_STORE_FORCE_FLAG: DWORD = 0x00000001; +pub const CERT_CLOSE_STORE_CHECK_FLAG: DWORD = 0x00000002; +extern "system" { + pub fn CertCloseStore( + hCertStore: HCERTSTORE, + dwFlags: DWORD, + ) -> BOOL; + pub fn CertGetSubjectCertificateFromStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + pCertId: PCERT_INFO, + ) -> PCCERT_CONTEXT; + pub fn CertEnumCertificatesInStore( + hCertStore: HCERTSTORE, + pPrevCertContext: PCCERT_CONTEXT, + ) -> PCCERT_CONTEXT; + pub fn CertFindCertificateInStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + dwFindFlags: DWORD, + dwFindType: DWORD, + pvFindPara: *const c_void, + pPrevCertContext: PCCERT_CONTEXT, + ) -> PCCERT_CONTEXT; +} +pub const CERT_COMPARE_MASK: DWORD = 0xFFFF; +pub const CERT_COMPARE_SHIFT: DWORD = 16; +pub const CERT_COMPARE_ANY: DWORD = 0; +pub const CERT_COMPARE_SHA1_HASH: DWORD = 1; +pub const CERT_COMPARE_NAME: DWORD = 2; +pub const CERT_COMPARE_ATTR: DWORD = 3; +pub const CERT_COMPARE_MD5_HASH: DWORD = 4; +pub const CERT_COMPARE_PROPERTY: DWORD = 5; +pub const CERT_COMPARE_PUBLIC_KEY: DWORD = 6; +pub const CERT_COMPARE_HASH: DWORD = CERT_COMPARE_SHA1_HASH; +pub const CERT_COMPARE_NAME_STR_A: DWORD = 7; +pub const CERT_COMPARE_NAME_STR_W: DWORD = 8; +pub const CERT_COMPARE_KEY_SPEC: DWORD = 9; +pub const CERT_COMPARE_ENHKEY_USAGE: DWORD = 10; +pub const CERT_COMPARE_CTL_USAGE: DWORD = CERT_COMPARE_ENHKEY_USAGE; +pub const CERT_COMPARE_SUBJECT_CERT: DWORD = 11; +pub const CERT_COMPARE_ISSUER_OF: DWORD = 12; +pub const CERT_COMPARE_EXISTING: DWORD = 13; +pub const CERT_COMPARE_SIGNATURE_HASH: DWORD = 14; +pub const CERT_COMPARE_KEY_IDENTIFIER: DWORD = 15; +pub const CERT_COMPARE_CERT_ID: DWORD = 16; +pub const CERT_COMPARE_CROSS_CERT_DIST_POINTS: DWORD = 17; +pub const CERT_COMPARE_PUBKEY_MD5_HASH: DWORD = 18; +pub const CERT_COMPARE_SUBJECT_INFO_ACCESS: DWORD = 19; +pub const CERT_COMPARE_HASH_STR: DWORD = 20; +pub const CERT_COMPARE_HAS_PRIVATE_KEY: DWORD = 21; +pub const CERT_FIND_ANY: DWORD = CERT_COMPARE_ANY << CERT_COMPARE_SHIFT; +pub const CERT_FIND_SHA1_HASH: DWORD = CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT; +pub const CERT_FIND_MD5_HASH: DWORD = CERT_COMPARE_MD5_HASH << CERT_COMPARE_SHIFT; +pub const CERT_FIND_SIGNATURE_HASH: DWORD = CERT_COMPARE_SIGNATURE_HASH << CERT_COMPARE_SHIFT; +pub const CERT_FIND_KEY_IDENTIFIER: DWORD = CERT_COMPARE_KEY_IDENTIFIER << CERT_COMPARE_SHIFT; +pub const CERT_FIND_HASH: DWORD = CERT_FIND_SHA1_HASH; +pub const CERT_FIND_PROPERTY: DWORD = CERT_COMPARE_PROPERTY << CERT_COMPARE_SHIFT; +pub const CERT_FIND_PUBLIC_KEY: DWORD = CERT_COMPARE_PUBLIC_KEY << CERT_COMPARE_SHIFT; +pub const CERT_FIND_SUBJECT_NAME: DWORD = (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT) + | CERT_INFO_SUBJECT_FLAG; +pub const CERT_FIND_SUBJECT_ATTR: DWORD = (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT) + | CERT_INFO_SUBJECT_FLAG; +pub const CERT_FIND_ISSUER_NAME: DWORD = (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT) + | CERT_INFO_ISSUER_FLAG; +pub const CERT_FIND_ISSUER_ATTR: DWORD = (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT) + | CERT_INFO_ISSUER_FLAG; +pub const CERT_FIND_SUBJECT_STR_A: DWORD = (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT) + | CERT_INFO_SUBJECT_FLAG; +pub const CERT_FIND_SUBJECT_STR_W: DWORD = (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT) + | CERT_INFO_SUBJECT_FLAG; +pub const CERT_FIND_SUBJECT_STR: DWORD = CERT_FIND_SUBJECT_STR_W; +pub const CERT_FIND_ISSUER_STR_A: DWORD = (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT) + | CERT_INFO_ISSUER_FLAG; +pub const CERT_FIND_ISSUER_STR_W: DWORD = (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT) + | CERT_INFO_ISSUER_FLAG; +pub const CERT_FIND_ISSUER_STR: DWORD = CERT_FIND_ISSUER_STR_W; +pub const CERT_FIND_KEY_SPEC: DWORD = CERT_COMPARE_KEY_SPEC << CERT_COMPARE_SHIFT; +pub const CERT_FIND_ENHKEY_USAGE: DWORD = CERT_COMPARE_ENHKEY_USAGE << CERT_COMPARE_SHIFT; +pub const CERT_FIND_CTL_USAGE: DWORD = CERT_FIND_ENHKEY_USAGE; +pub const CERT_FIND_SUBJECT_CERT: DWORD = CERT_COMPARE_SUBJECT_CERT << CERT_COMPARE_SHIFT; +pub const CERT_FIND_ISSUER_OF: DWORD = CERT_COMPARE_ISSUER_OF << CERT_COMPARE_SHIFT; +pub const CERT_FIND_EXISTING: DWORD = CERT_COMPARE_EXISTING << CERT_COMPARE_SHIFT; +pub const CERT_FIND_CERT_ID: DWORD = CERT_COMPARE_CERT_ID << CERT_COMPARE_SHIFT; +pub const CERT_FIND_CROSS_CERT_DIST_POINTS: DWORD = CERT_COMPARE_CROSS_CERT_DIST_POINTS + << CERT_COMPARE_SHIFT; +pub const CERT_FIND_PUBKEY_MD5_HASH: DWORD = CERT_COMPARE_PUBKEY_MD5_HASH << CERT_COMPARE_SHIFT; +pub const CERT_FIND_SUBJECT_INFO_ACCESS: DWORD = CERT_COMPARE_SUBJECT_INFO_ACCESS + << CERT_COMPARE_SHIFT; +pub const CERT_FIND_HASH_STR: DWORD = CERT_COMPARE_HASH_STR << CERT_COMPARE_SHIFT; +pub const CERT_FIND_HAS_PRIVATE_KEY: DWORD = CERT_COMPARE_HAS_PRIVATE_KEY << CERT_COMPARE_SHIFT; +pub const CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG: DWORD = 0x1; +pub const CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG: DWORD = 0x2; +pub const CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG: DWORD = 0x4; +pub const CERT_FIND_NO_ENHKEY_USAGE_FLAG: DWORD = 0x8; +pub const CERT_FIND_OR_ENHKEY_USAGE_FLAG: DWORD = 0x10; +pub const CERT_FIND_VALID_ENHKEY_USAGE_FLAG: DWORD = 0x20; +pub const CERT_FIND_OPTIONAL_CTL_USAGE_FLAG: DWORD = CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG; +pub const CERT_FIND_EXT_ONLY_CTL_USAGE_FLAG: DWORD = CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG; +pub const CERT_FIND_PROP_ONLY_CTL_USAGE_FLAG: DWORD = CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG; +pub const CERT_FIND_NO_CTL_USAGE_FLAG: DWORD = CERT_FIND_NO_ENHKEY_USAGE_FLAG; +pub const CERT_FIND_OR_CTL_USAGE_FLAG: DWORD = CERT_FIND_OR_ENHKEY_USAGE_FLAG; +pub const CERT_FIND_VALID_CTL_USAGE_FLAG: DWORD = CERT_FIND_VALID_ENHKEY_USAGE_FLAG; +extern "system" { + pub fn CertGetIssuerCertificateFromStore( + hCertStore: HCERTSTORE, + pSubjectContext: PCCERT_CONTEXT, + pPrevIssuerContext: PCCERT_CONTEXT, + pdwFlags: *mut DWORD, + ) -> PCCERT_CONTEXT; + pub fn CertVerifySubjectCertificateContext( + pSubject: PCCERT_CONTEXT, + pIssuer: PCCERT_CONTEXT, + pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CertDuplicateCertificateContext( + pCertContext: PCCERT_CONTEXT, + ) -> PCCERT_CONTEXT; + pub fn CertCreateCertificateContext( + dwCertEncodingType: DWORD, + pbCertEncoded: *const BYTE, + cbCertEncoded: DWORD, + ) -> PCCERT_CONTEXT; + pub fn CertFreeCertificateContext( + pCertContext: PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertSetCertificateContextProperty( + pCertContext: PCCERT_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, + ) -> BOOL; +} +pub const CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG: DWORD = 0x80000000; +pub const CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG: DWORD = 0x40000000; +extern "system" { + pub fn CertGetCertificateContextProperty( + pCertContext: PCCERT_CONTEXT, + dwPropId: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertEnumCertificateContextProperties( + pCertContext: PCCERT_CONTEXT, + dwPropId: DWORD, + ) -> DWORD; + pub fn CertCreateCTLEntryFromCertificateContextProperties( + pCertContext: PCCERT_CONTEXT, + cOptAttr: DWORD, + rgOptAttr: PCRYPT_ATTRIBUTE, + dwFlags: DWORD, + pvReserved: *mut c_void, + pCtlEntry: PCTL_ENTRY, + pcbCtlEntry: *mut DWORD, + ) -> BOOL; + pub fn CertSetCertificateContextPropertiesFromCTLEntry( + pCertContext: PCCERT_CONTEXT, + pCtlEntry: PCTL_ENTRY, + dwFlags: DWORD, + ) -> BOOL; + pub fn CertGetCRLFromStore( + hCertStore: HCERTSTORE, + pIssuerContext: PCCERT_CONTEXT, + pPrevCrlContext: PCCRL_CONTEXT, + pdwFlags: *mut DWORD, + ) -> PCCRL_CONTEXT; + pub fn CertEnumCRLsInStore( + hCertStore: HCERTSTORE, + pPrevCrlContext: PCCRL_CONTEXT, + ) -> PCCRL_CONTEXT; + pub fn CertFindCRLInStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + dwFindFlags: DWORD, + dwFindType: DWORD, + pvFindPara: *const c_void, + pPrevCrlContext: PCCRL_CONTEXT, + ) -> PCCRL_CONTEXT; +} +pub const CRL_FIND_ANY: DWORD = 0; +pub const CRL_FIND_ISSUED_BY: DWORD = 1; +pub const CRL_FIND_EXISTING: DWORD = 2; +pub const CRL_FIND_ISSUED_FOR: DWORD = 3; +pub const CRL_FIND_ISSUED_BY_AKI_FLAG: DWORD = 0x1; +pub const CRL_FIND_ISSUED_BY_SIGNATURE_FLAG: DWORD = 0x2; +pub const CRL_FIND_ISSUED_BY_DELTA_FLAG: DWORD = 0x4; +pub const CRL_FIND_ISSUED_BY_BASE_FLAG: DWORD = 0x8; +STRUCT!{struct CRL_FIND_ISSUED_FOR_PARA { + pSubjectCert: PCCERT_CONTEXT, + pIssuerCert: PCCERT_CONTEXT, +}} +pub type PCRL_FIND_ISSUED_FOR_PARA = *mut CRL_FIND_ISSUED_FOR_PARA; +pub const CRL_FIND_ISSUED_FOR_SET_STRONG_PROPERTIES_FLAG: DWORD = 0x10; +extern "system" { + pub fn CertDuplicateCRLContext( + pCrlContext: PCCRL_CONTEXT, + ) -> PCCRL_CONTEXT; + pub fn CertCreateCRLContext( + dwCertEncodingType: DWORD, + pbCrlEncoded: *const BYTE, + cbCrlEncoded: DWORD, + ) -> PCCRL_CONTEXT; + pub fn CertFreeCRLContext( + pCrlContext: PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertSetCRLContextProperty( + pCrlContext: PCCRL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, + ) -> BOOL; + pub fn CertGetCRLContextProperty( + pCrlContext: PCCRL_CONTEXT, + dwPropId: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertEnumCRLContextProperties( + pCrlContext: PCCRL_CONTEXT, + dwPropId: DWORD, + ) -> DWORD; + pub fn CertFindCertificateInCRL( + pCert: PCCERT_CONTEXT, + pCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, + pvReserved: *mut c_void, + ppCrlEntry: *mut PCRL_ENTRY, + ) -> BOOL; + pub fn CertIsValidCRLForCertificate( + pCert: PCCERT_CONTEXT, + pCrl: PCCRL_CONTEXT, + dwFlags: DWORD, + pvReserved: *mut c_void, + ) -> BOOL; +} +pub const CERT_STORE_ADD_NEW: DWORD = 1; +pub const CERT_STORE_ADD_USE_EXISTING: DWORD = 2; +pub const CERT_STORE_ADD_REPLACE_EXISTING: DWORD = 3; +pub const CERT_STORE_ADD_ALWAYS: DWORD = 4; +pub const CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: DWORD = 5; +pub const CERT_STORE_ADD_NEWER: DWORD = 6; +pub const CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES: DWORD = 7; +extern "system" { + pub fn CertAddEncodedCertificateToStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + pbCertEncoded: *const BYTE, + cbCertEncoded: DWORD, + dwAddDisposition: DWORD, + ppCertContext: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddCertificateContextToStore( + hCertStore: HCERTSTORE, + pCertContext: PCCERT_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCERT_CONTEXT, + ) -> BOOL; +} +pub const CERT_STORE_CERTIFICATE_CONTEXT: DWORD = 1; +pub const CERT_STORE_CRL_CONTEXT: DWORD = 2; +pub const CERT_STORE_CTL_CONTEXT: DWORD = 3; +pub const CERT_STORE_ALL_CONTEXT_FLAG: DWORD = !0; +pub const CERT_STORE_CERTIFICATE_CONTEXT_FLAG: DWORD = 1 << CERT_STORE_CERTIFICATE_CONTEXT; +pub const CERT_STORE_CRL_CONTEXT_FLAG: DWORD = 1 << CERT_STORE_CRL_CONTEXT; +pub const CERT_STORE_CTL_CONTEXT_FLAG: DWORD = 1 << CERT_STORE_CTL_CONTEXT; +extern "system" { + pub fn CertAddSerializedElementToStore( + hCertStore: HCERTSTORE, + pbElement: *const BYTE, + cbElement: DWORD, + dwAddDisposition: DWORD, + dwFlags: DWORD, + dwContextTypeFlags: DWORD, + pdwContextType: *mut DWORD, + ppvContext: *mut *const c_void, + ) -> BOOL; + pub fn CertDeleteCertificateFromStore( + pCertContext: PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddEncodedCRLToStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + pbCrlEncoded: *const BYTE, + cbCrlEncoded: DWORD, + dwAddDisposition: DWORD, + ppCrlContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertAddCRLContextToStore( + hCertStore: HCERTSTORE, + pCrlContext: PCCRL_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertDeleteCRLFromStore( + pCrlContext: PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertSerializeCertificateStoreElement( + pCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, + pbElement: *mut BYTE, + pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertSerializeCRLStoreElement( + pCrlContext: PCCRL_CONTEXT, + dwFlags: DWORD, + pbElement: *mut BYTE, + pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertDuplicateCTLContext( + pCtlContext: PCCTL_CONTEXT, + ) -> PCCTL_CONTEXT; + pub fn CertCreateCTLContext( + dwMsgAndCertEncodingType: DWORD, + pbCtlEncoded: *const BYTE, + cbCtlEncoded: DWORD, + ) -> PCCTL_CONTEXT; + pub fn CertFreeCTLContext( + pCtlContext: PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertSetCTLContextProperty( + pCtlContext: PCCTL_CONTEXT, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, + ) -> BOOL; + pub fn CertGetCTLContextProperty( + pCtlContext: PCCTL_CONTEXT, + dwPropId: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertEnumCTLContextProperties( + pCtlContext: PCCTL_CONTEXT, + dwPropId: DWORD, + ) -> DWORD; + pub fn CertEnumCTLsInStore( + hCertStore: HCERTSTORE, + pPrevCtlContext: PCCTL_CONTEXT, + ) -> PCCTL_CONTEXT; + pub fn CertFindSubjectInCTL( + dwEncodingType: DWORD, + dwSubjectType: DWORD, + pvSubject: *mut c_void, + pCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, + ) -> PCTL_ENTRY; +} +pub const CTL_ANY_SUBJECT_TYPE: DWORD = 1; +pub const CTL_CERT_SUBJECT_TYPE: DWORD = 2; +STRUCT!{struct CTL_ANY_SUBJECT_INFO { + SubjectAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + SubjectIdentifier: CRYPT_DATA_BLOB, +}} +pub type PCTL_ANY_SUBJECT_INFO = *mut CTL_ANY_SUBJECT_INFO; +extern "system" { + pub fn CertFindCTLInStore( + hCertStore: HCERTSTORE, + dwMsgAndCertEncodingType: DWORD, + dwFindFlags: DWORD, + dwFindType: DWORD, + pvFindPara: *const c_void, + pPrevCtlContext: PCCTL_CONTEXT, + ) -> PCCTL_CONTEXT; +} +pub const CTL_FIND_ANY: DWORD = 0; +pub const CTL_FIND_SHA1_HASH: DWORD = 1; +pub const CTL_FIND_MD5_HASH: DWORD = 2; +pub const CTL_FIND_USAGE: DWORD = 3; +pub const CTL_FIND_SUBJECT: DWORD = 4; +pub const CTL_FIND_EXISTING: DWORD = 5; +STRUCT!{struct CTL_FIND_USAGE_PARA { + cbSize: DWORD, + SubjectUsage: CTL_USAGE, + ListIdentifier: CRYPT_DATA_BLOB, + pSigner: PCERT_INFO, +}} +pub type PCTL_FIND_USAGE_PARA = *mut CTL_FIND_USAGE_PARA; +pub const CTL_FIND_NO_LIST_ID_CBDATA: DWORD = 0xFFFFFFFF; +pub const CTL_FIND_NO_SIGNER_PTR: PCERT_INFO = -1isize as PCERT_INFO; +pub const CTL_FIND_SAME_USAGE_FLAG: DWORD = 0x1; +STRUCT!{struct CTL_FIND_SUBJECT_PARA { + cbSize: DWORD, + pUsagePara: PCTL_FIND_USAGE_PARA, + dwSubjectType: DWORD, + pvSubject: *mut c_void, +}} +pub type PCTL_FIND_SUBJECT_PARA = *mut CTL_FIND_SUBJECT_PARA; +extern "system" { + pub fn CertAddEncodedCTLToStore( + hCertStore: HCERTSTORE, + dwMsgAndCertEncodingType: DWORD, + pbCtlEncoded: *const BYTE, + cbCtlEncoded: DWORD, + dwAddDisposition: DWORD, + ppCtlContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddCTLContextToStore( + hCertStore: HCERTSTORE, + pCtlContext: PCCTL_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertSerializeCTLStoreElement( + pCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, + pbElement: *mut BYTE, + pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertDeleteCTLFromStore( + pCtlContext: PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddCertificateLinkToStore( + hCertStore: HCERTSTORE, + pCertContext: PCCERT_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddCRLLinkToStore( + hCertStore: HCERTSTORE, + pCrlContext: PCCRL_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertAddCTLLinkToStore( + hCertStore: HCERTSTORE, + pCtlContext: PCCTL_CONTEXT, + dwAddDisposition: DWORD, + ppStoreContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddStoreToCollection( + hCollectionStore: HCERTSTORE, + hSiblingStore: HCERTSTORE, + dwUpdateFlags: DWORD, + dwPriority: DWORD, + ) -> BOOL; + pub fn CertRemoveStoreFromCollection( + hCollectionStore: HCERTSTORE, + hSiblingStore: HCERTSTORE, + ); + pub fn CertControlStore( + hCertStore: HCERTSTORE, + dwFlags: DWORD, + dwCtrlType: DWORD, + pvCtrlPara: *const c_void, + ) -> BOOL; +} +pub const CERT_STORE_CTRL_RESYNC: DWORD = 1; +pub const CERT_STORE_CTRL_NOTIFY_CHANGE: DWORD = 2; +pub const CERT_STORE_CTRL_COMMIT: DWORD = 3; +pub const CERT_STORE_CTRL_AUTO_RESYNC: DWORD = 4; +pub const CERT_STORE_CTRL_CANCEL_NOTIFY: DWORD = 5; +pub const CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG: DWORD = 0x1; +pub const CERT_STORE_CTRL_COMMIT_FORCE_FLAG: DWORD = 0x1; +pub const CERT_STORE_CTRL_COMMIT_CLEAR_FLAG: DWORD = 0x2; +pub const CERT_STORE_LOCALIZED_NAME_PROP_ID: DWORD = 0x1000; +extern "system" { + pub fn CertSetStoreProperty( + hCertStore: HCERTSTORE, + dwPropId: DWORD, + dwFlags: DWORD, + pvData: *const c_void, + ) -> BOOL; + pub fn CertGetStoreProperty( + hCertStore: HCERTSTORE, + dwPropId: DWORD, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; +} +FN!{stdcall PFN_CERT_CREATE_CONTEXT_SORT_FUNC( + cbTotalEncoded: DWORD, + cbRemainEncoded: DWORD, + cEntry: DWORD, + pvSort: *mut c_void, +) -> BOOL} +STRUCT!{struct CERT_CREATE_CONTEXT_PARA { + cbSize: DWORD, + pfnFree: PFN_CRYPT_FREE, + pvFree: *mut c_void, + pfnSort: PFN_CERT_CREATE_CONTEXT_SORT_FUNC, + pvSort: *mut c_void, +}} +pub type PCERT_CREATE_CONTEXT_PARA = *mut CERT_CREATE_CONTEXT_PARA; +extern "system" { + pub fn CertCreateContext( + dwContextType: DWORD, + dwEncodingType: DWORD, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + dwFlags: DWORD, + pCreatePara: PCERT_CREATE_CONTEXT_PARA, + ) -> *const c_void; +} +pub const CERT_CREATE_CONTEXT_NOCOPY_FLAG: DWORD = 0x1; +pub const CERT_CREATE_CONTEXT_SORTED_FLAG: DWORD = 0x2; +pub const CERT_CREATE_CONTEXT_NO_HCRYPTMSG_FLAG: DWORD = 0x4; +pub const CERT_CREATE_CONTEXT_NO_ENTRY_FLAG: DWORD = 0x8; +STRUCT!{struct CERT_SYSTEM_STORE_INFO { + cbSize: DWORD, +}} +pub type PCERT_SYSTEM_STORE_INFO = *mut CERT_SYSTEM_STORE_INFO; +STRUCT!{struct CERT_PHYSICAL_STORE_INFO { + cbSize: DWORD, + pszOpenStoreProvider: LPSTR, + dwOpenEncodingType: DWORD, + dwOpenFlags: DWORD, + OpenParameters: CRYPT_DATA_BLOB, + dwFlags: DWORD, + dwPriority: DWORD, +}} +pub type PCERT_PHYSICAL_STORE_INFO = *mut CERT_PHYSICAL_STORE_INFO; +pub const CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG: DWORD = 0x1; +pub const CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG: DWORD = 0x2; +pub const CERT_PHYSICAL_STORE_REMOTE_OPEN_DISABLE_FLAG: DWORD = 0x4; +pub const CERT_PHYSICAL_STORE_INSERT_COMPUTER_NAME_ENABLE_FLAG: DWORD = 0x8; +extern "system" { + pub fn CertRegisterSystemStore( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pStoreInfo: PCERT_SYSTEM_STORE_INFO, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CertRegisterPhysicalStore( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pwszStoreName: LPCWSTR, + pStoreInfo: PCERT_PHYSICAL_STORE_INFO, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CertUnregisterSystemStore( + pvSystemStore: *const c_void, + dwFlags: DWORD, + ) -> BOOL; + pub fn CertUnregisterPhysicalStore( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pwszStoreName: LPCWSTR, + ) -> BOOL; +} +FN!{stdcall PFN_CERT_ENUM_SYSTEM_STORE_LOCATION( + pwszStoreLocation: LPCWSTR, + dwFlags: DWORD, + pvReserved: *mut c_void, + pvArg: *mut c_void, +) -> BOOL} +FN!{stdcall PFN_CERT_ENUM_SYSTEM_STORE( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pStoreInfo: PCERT_SYSTEM_STORE_INFO, + pvReserved: *mut c_void, + pvArg: *mut c_void, +) -> BOOL} +FN!{stdcall PFN_CERT_ENUM_PHYSICAL_STORE( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pwszStoreName: LPCWSTR, + pStoreInfo: PCERT_PHYSICAL_STORE_INFO, + pvReserved: *mut c_void, + pvArg: *mut c_void, +) -> BOOL} +pub const CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG: DWORD = 0x1; +pub const CERT_PHYSICAL_STORE_DEFAULT_NAME: &'static str = ".Default"; +pub const CERT_PHYSICAL_STORE_GROUP_POLICY_NAME: &'static str = ".GroupPolicy"; +pub const CERT_PHYSICAL_STORE_LOCAL_MACHINE_NAME: &'static str = ".LocalMachine"; +pub const CERT_PHYSICAL_STORE_DS_USER_CERTIFICATE_NAME: &'static str = ".UserCertificate"; +pub const CERT_PHYSICAL_STORE_LOCAL_MACHINE_GROUP_POLICY_NAME: &'static str + = ".LocalMachineGroupPolicy"; +pub const CERT_PHYSICAL_STORE_ENTERPRISE_NAME: &'static str = ".Enterprise"; +pub const CERT_PHYSICAL_STORE_AUTH_ROOT_NAME: &'static str = ".AuthRoot"; +pub const CERT_PHYSICAL_STORE_SMART_CARD_NAME: &'static str = ".SmartCard"; +extern "system" { + pub fn CertEnumSystemStoreLocation( + dwFlags: DWORD, + pvArg: *mut c_void, + pfnEnum: PFN_CERT_ENUM_SYSTEM_STORE_LOCATION, + ) -> BOOL; + pub fn CertEnumSystemStore( + dwFlags: DWORD, + pvSystemStoreLocationPara: *mut c_void, + pvArg: *mut c_void, + pfnEnum: PFN_CERT_ENUM_SYSTEM_STORE, + ) -> BOOL; + pub fn CertEnumPhysicalStore( + pvSystemStore: *const c_void, + dwFlags: DWORD, + pvArg: *mut c_void, + pfnEnum: PFN_CERT_ENUM_PHYSICAL_STORE, + ) -> BOOL; +} +pub const CRYPT_OID_OPEN_SYSTEM_STORE_PROV_FUNC: &'static str = "CertDllOpenSystemStoreProv"; +pub const CRYPT_OID_REGISTER_SYSTEM_STORE_FUNC: &'static str = "CertDllRegisterSystemStore"; +pub const CRYPT_OID_UNREGISTER_SYSTEM_STORE_FUNC: &'static str = "CertDllUnregisterSystemStore"; +pub const CRYPT_OID_ENUM_SYSTEM_STORE_FUNC: &'static str = "CertDllEnumSystemStore"; +pub const CRYPT_OID_REGISTER_PHYSICAL_STORE_FUNC: &'static str = "CertDllRegisterPhysicalStore"; +pub const CRYPT_OID_UNREGISTER_PHYSICAL_STORE_FUNC: &'static str + = "CertDllUnregisterPhysicalStore"; +pub const CRYPT_OID_ENUM_PHYSICAL_STORE_FUNC: &'static str = "CertDllEnumPhysicalStore"; +pub const CRYPT_OID_SYSTEM_STORE_LOCATION_VALUE_NAME: &'static str = "SystemStoreLocation"; +extern "system" { + pub fn CertGetEnhancedKeyUsage( + pCertContext: PCCERT_CONTEXT, + dwFlags: DWORD, + pUsage: PCERT_ENHKEY_USAGE, + pcbUsage: *mut DWORD, + ) -> BOOL; + pub fn CertSetEnhancedKeyUsage( + pCertContext: PCCERT_CONTEXT, + pUsage: PCERT_ENHKEY_USAGE, + ) -> BOOL; + pub fn CertAddEnhancedKeyUsageIdentifier( + pCertContext: PCCERT_CONTEXT, + pszUsageIdentifier: LPCSTR, + ) -> BOOL; + pub fn CertRemoveEnhancedKeyUsageIdentifier( + pCertContext: PCCERT_CONTEXT, + pszUsageIdentifier: LPCSTR, + ) -> BOOL; + pub fn CertGetValidUsages( + cCerts: DWORD, + rghCerts: *mut PCCERT_CONTEXT, + cNumOIDs: *mut c_int, + rghOIDs: *mut LPSTR, + pcbOIDs: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgGetAndVerifySigner( + hCryptMsg: HCRYPTMSG, + cSignerStore: DWORD, + rghSignerStore: *mut HCERTSTORE, + dwFlags: DWORD, + ppSigner: *mut PCCERT_CONTEXT, + pdwSignerIndex: *mut DWORD, + ) -> BOOL; +} +pub const CMSG_TRUSTED_SIGNER_FLAG: DWORD = 0x1; +pub const CMSG_SIGNER_ONLY_FLAG: DWORD = 0x2; +pub const CMSG_USE_SIGNER_INDEX_FLAG: DWORD = 0x4; +extern "system" { + pub fn CryptMsgSignCTL( + dwMsgEncodingType: DWORD, + pbCtlContent: *mut BYTE, + cbCtlContent: DWORD, + pSignInfo: PCMSG_SIGNED_ENCODE_INFO, + dwFlags: DWORD, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgEncodeAndSignCTL( + dwMsgEncodingType: DWORD, + pCtlInfo: PCTL_INFO, + pSignInfo: PCMSG_SIGNED_ENCODE_INFO, + dwFlags: DWORD, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ) -> BOOL; +} +pub const CMSG_ENCODE_SORTED_CTL_FLAG: DWORD = 0x1; +pub const CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG: DWORD = 0x2; +extern "system" { + pub fn CertFindSubjectInSortedCTL( + pSubjectIdentifier: PCRYPT_DATA_BLOB, + pCtlContext: PCCTL_CONTEXT, + dwFlags: DWORD, + pvReserved: *mut c_void, + pEncodedAttributes: PCRYPT_DER_BLOB, + ) -> BOOL; + pub fn CertEnumSubjectInSortedCTL( + pCtlContext: PCCTL_CONTEXT, + ppvNextSubject: *mut *mut c_void, + pSubjectIdentifier: PCRYPT_DER_BLOB, + pEncodedAttributes: PCRYPT_DER_BLOB, + ) -> BOOL; +} +STRUCT!{struct CTL_VERIFY_USAGE_PARA { + cbSize: DWORD, + ListIdentifier: CRYPT_DATA_BLOB, + cCtlStore: DWORD, + rghCtlStore: *mut HCERTSTORE, + cSignerStore: DWORD, + rghSignerStore: *mut HCERTSTORE, +}} +pub type PCTL_VERIFY_USAGE_PARA = *mut CTL_VERIFY_USAGE_PARA; +STRUCT!{struct CTL_VERIFY_USAGE_STATUS { + cbSize: DWORD, + dwError: DWORD, + dwFlags: DWORD, + ppCtl: *mut PCCTL_CONTEXT, + dwCtlEntryIndex: DWORD, + ppSigner: *mut PCCERT_CONTEXT, + dwSignerIndex: DWORD, +}} +pub type PCTL_VERIFY_USAGE_STATUS = *mut CTL_VERIFY_USAGE_STATUS; +pub const CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG: DWORD = 0x1; +pub const CERT_VERIFY_TRUSTED_SIGNERS_FLAG: DWORD = 0x2; +pub const CERT_VERIFY_NO_TIME_CHECK_FLAG: DWORD = 0x4; +pub const CERT_VERIFY_ALLOW_MORE_USAGE_FLAG: DWORD = 0x8; +pub const CERT_VERIFY_UPDATED_CTL_FLAG: DWORD = 0x1; +extern "system" { + pub fn CertVerifyCTLUsage( + dwEncodingType: DWORD, + dwSubjectType: DWORD, + pvSubject: *mut c_void, + pSubjectUsage: PCTL_USAGE, + dwFlags: DWORD, + pVerifyUsagePara: PCTL_VERIFY_USAGE_PARA, + pVerifyUsageStatus: PCTL_VERIFY_USAGE_STATUS, + ) -> BOOL; +} +STRUCT!{struct CERT_REVOCATION_CRL_INFO { + cbSize: DWORD, + pBaseCrlContext: PCCRL_CONTEXT, + pDeltaCrlContext: PCCRL_CONTEXT, + pCrlEntry: PCRL_ENTRY, + fDeltaCrlEntry: BOOL, +}} +pub type PCERT_REVOCATION_CRL_INFO = *mut CERT_REVOCATION_CRL_INFO; +pub type PCERT_REVOCATION_CHAIN_PARA = *mut CERT_REVOCATION_CHAIN_PARA; +STRUCT!{struct CERT_REVOCATION_PARA { + cbSize: DWORD, + pIssuerCert: PCCERT_CONTEXT, + cCertStore: DWORD, + rgCertStore: *mut HCERTSTORE, + hCrlStore: HCERTSTORE, + pftTimeToUse: LPFILETIME, + dwUrlRetrievalTimeout: DWORD, + fCheckFreshnessTime: BOOL, + dwFreshnessTime: DWORD, + pftCurrentTime: LPFILETIME, + pCrlInfo: PCERT_REVOCATION_CRL_INFO, + pftCacheResync: LPFILETIME, + pChainPara: PCERT_REVOCATION_CHAIN_PARA, +}} +pub type PCERT_REVOCATION_PARA = *mut CERT_REVOCATION_PARA; +STRUCT!{struct CERT_REVOCATION_STATUS { + cbSize: DWORD, + dwIndex: DWORD, + dwError: DWORD, + dwReason: DWORD, + fHasFreshnessTime: BOOL, + dwFreshnessTime: DWORD, +}} +pub type PCERT_REVOCATION_STATUS = *mut CERT_REVOCATION_STATUS; +extern "system" { + pub fn CertVerifyRevocation( + dwEncodingType: DWORD, + dwRevType: DWORD, + cContext: DWORD, + rgpvContext: *mut PVOID, + dwFlags: DWORD, + pRevPara: PCERT_REVOCATION_PARA, + pRevStatus: PCERT_REVOCATION_STATUS, + ) -> BOOL; +} +pub const CERT_CONTEXT_REVOCATION_TYPE: DWORD = 1; +pub const CERT_VERIFY_REV_CHAIN_FLAG: DWORD = 0x00000001; +pub const CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION: DWORD = 0x00000002; +pub const CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG: DWORD = 0x00000004; +pub const CERT_VERIFY_REV_SERVER_OCSP_FLAG: DWORD = 0x00000008; +pub const CERT_VERIFY_REV_NO_OCSP_FAILOVER_TO_CRL_FLAG: DWORD = 0x00000010; +extern "system" { + pub fn CertCompareIntegerBlob( + pInt1: PCRYPT_INTEGER_BLOB, + pInt2: PCRYPT_INTEGER_BLOB, + ) -> BOOL; + pub fn CertCompareCertificate( + dwCertEncodingType: DWORD, + pCertId1: PCERT_INFO, + pCertId2: PCERT_INFO, + ) -> BOOL; + pub fn CertCompareCertificateName( + dwCertEncodingType: DWORD, + pCertName1: PCERT_NAME_BLOB, + pCertName2: PCERT_NAME_BLOB, + ) -> BOOL; + pub fn CertIsRDNAttrsInCertificateName( + dwCertEncodingType: DWORD, + dwFlags: DWORD, + pCertName: PCERT_NAME_BLOB, + pRDN: PCERT_RDN, + ) -> BOOL; + pub fn CertComparePublicKeyInfo( + dwCertEncodingType: DWORD, + pPublicKey1: PCERT_PUBLIC_KEY_INFO, + pPublicKey2: PCERT_PUBLIC_KEY_INFO, + ) -> BOOL; + pub fn CertGetPublicKeyLength( + dwCertEncodingType: DWORD, + pPublicKey: PCERT_PUBLIC_KEY_INFO, + ) -> DWORD; + pub fn CryptVerifyCertificateSignature( + hCryptProv: HCRYPTPROV_LEGACY, + dwCertEncodingType: DWORD, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + pPublicKey: PCERT_PUBLIC_KEY_INFO, + ) -> BOOL; + pub fn CryptVerifyCertificateSignatureEx( + hCryptProv: HCRYPTPROV_LEGACY, + dwCertEncodingType: DWORD, + dwSubjectType: DWORD, + pvSubject: *mut c_void, + dwIssuerType: DWORD, + pvIssuer: *mut c_void, + dwFlags: DWORD, + pvExtra: *mut c_void, + ) -> BOOL; +} +pub const CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB: DWORD = 1; +pub const CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT: DWORD = 2; +pub const CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL: DWORD = 3; +pub const CRYPT_VERIFY_CERT_SIGN_SUBJECT_OCSP_BASIC_SIGNED_RESPONSE: DWORD = 4; +pub const CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY: DWORD = 1; +pub const CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT: DWORD = 2; +pub const CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: DWORD = 3; +pub const CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL: DWORD = 4; +pub const CRYPT_VERIFY_CERT_SIGN_DISABLE_MD2_MD4_FLAG: DWORD = 0x00000001; +pub const CRYPT_VERIFY_CERT_SIGN_SET_STRONG_PROPERTIES_FLAG: DWORD = 0x00000002; +pub const CRYPT_VERIFY_CERT_SIGN_RETURN_STRONG_PROPERTIES_FLAG: DWORD = 0x00000004; +STRUCT!{struct CRYPT_VERIFY_CERT_SIGN_STRONG_PROPERTIES_INFO { + CertSignHashCNGAlgPropData: CRYPT_DATA_BLOB, + CertIssuerPubKeyBitLengthPropData: CRYPT_DATA_BLOB, +}} +pub type PCRYPT_VERIFY_CERT_SIGN_STRONG_PROPERTIES_INFO + = *mut CRYPT_VERIFY_CERT_SIGN_STRONG_PROPERTIES_INFO; +STRUCT!{struct CRYPT_VERIFY_CERT_SIGN_WEAK_HASH_INFO { + cCNGHashAlgid: DWORD, + rgpwszCNGHashAlgid: *mut PCWSTR, + dwWeakIndex: DWORD, +}} +pub type PCRYPT_VERIFY_CERT_SIGN_WEAK_HASH_INFO = *mut CRYPT_VERIFY_CERT_SIGN_WEAK_HASH_INFO; +extern "system" { + pub fn CertIsStrongHashToSign( + pStrongSignPara: PCCERT_STRONG_SIGN_PARA, + pwszCNGHashAlgid: LPCWSTR, + pSigningCert: PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptHashToBeSigned( + hCryptProv: HCRYPTPROV_LEGACY, + dwCertEncodingType: DWORD, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashCertificate( + hCryptProv: HCRYPTPROV_LEGACY, + Algid: ALG_ID, + dwFlags: DWORD, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashCertificate2( + pwszCNGHashAlgid: LPCWSTR, + dwFlags: DWORD, + pvReserved: *mut c_void, + pbEncoded: *const BYTE, + cbEncoded: DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptSignCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + dwKeySpec: DWORD, + dwCertEncodingType: DWORD, + pbEncodedToBeSigned: *const BYTE, + cbEncodedToBeSigned: DWORD, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *const c_void, + pbSignature: *mut BYTE, + pcbSignature: *mut DWORD, + ) -> BOOL; + pub fn CryptSignAndEncodeCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + dwKeySpec: DWORD, + dwCertEncodingType: DWORD, + lpszStructType: LPCSTR, + pvStructInfo: *const c_void, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *const c_void, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_OID_EXTRACT_ENCODED_SIGNATURE_PARAMETERS_FUNC: &'static str + = "CryptDllExtractEncodedSignatureParameters"; +FN!{stdcall PFN_CRYPT_EXTRACT_ENCODED_SIGNATURE_PARAMETERS_FUNC( + dwCertEncodingType: DWORD, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + ppvDecodedSignPara: *mut *mut c_void, + ppwszCNGHashAlgid: LPWSTR, +) -> BOOL} +pub const CRYPT_OID_SIGN_AND_ENCODE_HASH_FUNC: &'static str = "CryptDllSignAndEncodeHash"; +FN!{stdcall PFN_CRYPT_SIGN_AND_ENCODE_HASH_FUNC( + hKey: NCRYPT_KEY_HANDLE, + dwCertEncodingType: DWORD, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pvDecodedSignPara: *mut c_void, + pwszCNGPubKeyAlgid: LPCWSTR, + pwszCNGHashAlgid: LPCWSTR, + pbComputedHash: *mut BYTE, + cbComputedHash: DWORD, + pbSignature: *mut BYTE, + pcbSignature: *mut DWORD, +) -> BOOL} +pub const CRYPT_OID_VERIFY_ENCODED_SIGNATURE_FUNC: &'static str = "CryptDllVerifyEncodedSignature"; +FN!{stdcall PFN_CRYPT_VERIFY_ENCODED_SIGNATURE_FUNC( + dwCertEncodingType: DWORD, + pPubKeyInfo: PCERT_PUBLIC_KEY_INFO, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pvDecodedSignPara: *mut c_void, + pwszCNGPubKeyAlgid: LPCWSTR, + pwszCNGHashAlgid: LPCWSTR, + pbComputedHash: *mut BYTE, + cbComputedHash: DWORD, + pbSignature: *mut BYTE, + cbSignature: DWORD, +) -> BOOL} +extern "system" { + pub fn CertVerifyTimeValidity( + pTimeToVerify: LPFILETIME, + pCertInfo: PCERT_INFO, + ) -> LONG; + pub fn CertVerifyCRLTimeValidity( + pTimeToVerify: LPFILETIME, + pCrlInfo: PCRL_INFO, + ) -> LONG; + pub fn CertVerifyValidityNesting( + pSubjectInfo: PCERT_INFO, + pIssuerInfo: PCERT_INFO, + ) -> BOOL; + pub fn CertVerifyCRLRevocation( + dwCertEncodingType: DWORD, + pCertId: PCERT_INFO, + cCrlInfo: DWORD, + rgpCrlInfo: *mut PCRL_INFO, + ) -> BOOL; + pub fn CertAlgIdToOID( + dwAlgId: DWORD, + ) -> LPCSTR; + pub fn CertOIDToAlgId( + pszObjId: LPCSTR, + ) -> DWORD; + pub fn CertFindExtension( + pszObjId: LPCSTR, + cExtensions: DWORD, + rgExtensions: *mut CERT_EXTENSION, + ) -> PCERT_EXTENSION; + pub fn CertFindAttribute( + pszObjId: LPCSTR, + cAttr: DWORD, + rgAttr: *mut CRYPT_ATTRIBUTE, + ) -> PCRYPT_ATTRIBUTE; + pub fn CertFindRDNAttr( + pszObjId: LPCSTR, + pName: PCERT_NAME_INFO, + ) -> PCERT_RDN_ATTR; + pub fn CertGetIntendedKeyUsage( + dwCertEncodingType: DWORD, + pCertInfo: PCERT_INFO, + pbKeyUsage: *mut BYTE, + cbKeyUsage: DWORD, + ) -> BOOL; +} +pub type HCRYPTDEFAULTCONTEXT = *mut c_void; +extern "system" { + pub fn CryptInstallDefaultContext( + hCryptProv: HCRYPTPROV, + dwDefaultType: DWORD, + pvDefaultPara: *const c_void, + dwFlags: DWORD, + pvReserved: *mut c_void, + phDefaultContext: *mut HCRYPTDEFAULTCONTEXT, + ) -> BOOL; +} +pub const CRYPT_DEFAULT_CONTEXT_AUTO_RELEASE_FLAG: DWORD = 0x00000001; +pub const CRYPT_DEFAULT_CONTEXT_PROCESS_FLAG: DWORD = 0x00000002; +pub const CRYPT_DEFAULT_CONTEXT_CERT_SIGN_OID: DWORD = 1; +pub const CRYPT_DEFAULT_CONTEXT_MULTI_CERT_SIGN_OID: DWORD = 2; +STRUCT!{struct CRYPT_DEFAULT_CONTEXT_MULTI_OID_PARA { + cOID: DWORD, + rgpszOID: *mut LPSTR, +}} +pub type PCRYPT_DEFAULT_CONTEXT_MULTI_OID_PARA = *mut CRYPT_DEFAULT_CONTEXT_MULTI_OID_PARA; +extern "system" { + pub fn CryptUninstallDefaultContext( + hDefaultContext: HCRYPTDEFAULTCONTEXT, + dwFlags: DWORD, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CryptExportPublicKeyInfo( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + dwKeySpec: DWORD, + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + pcbInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptExportPublicKeyInfoEx( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + dwKeySpec: DWORD, + dwCertEncodingType: DWORD, + pszPublicKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pInfo: PCERT_PUBLIC_KEY_INFO, + pcbInfo: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC: &'static str = "CryptDllExportPublicKeyInfoEx"; +pub const CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_EX2_FUNC: &'static str + = "CryptDllExportPublicKeyInfoEx2"; +FN!{stdcall PFN_CRYPT_EXPORT_PUBLIC_KEY_INFO_EX2_FUNC( + hNCryptKey: NCRYPT_KEY_HANDLE, + dwCertEncodingType: DWORD, + pszPublicKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pInfo: PCERT_PUBLIC_KEY_INFO, + pcbInfo: *mut DWORD, +) -> BOOL} +extern "system" { + pub fn CryptExportPublicKeyInfoFromBCryptKeyHandle( + hBCryptKey: BCRYPT_KEY_HANDLE, + dwCertEncodingType: DWORD, + pszPublicKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pInfo: PCERT_PUBLIC_KEY_INFO, + pcbInfo: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FROM_BCRYPT_HANDLE_FUNC: &'static str + = "CryptDllExportPublicKeyInfoFromBCryptKeyHandle"; +FN!{stdcall PFN_CRYPT_EXPORT_PUBLIC_KEY_INFO_FROM_BCRYPT_HANDLE_FUNC( + hBCryptKey: BCRYPT_KEY_HANDLE, + dwCertEncodingType: DWORD, + pszPublicKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pInfo: PCERT_PUBLIC_KEY_INFO, + pcbInfo: *mut DWORD, +) -> BOOL} +extern "system" { + pub fn CryptImportPublicKeyInfo( + hCryptProv: HCRYPTPROV, + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + phKey: *mut HCRYPTKEY, + ) -> BOOL; +} +pub const CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC: &'static str = "CryptDllImportPublicKeyInfoEx"; +extern "system" { + pub fn CryptImportPublicKeyInfoEx( + hCryptProv: HCRYPTPROV, + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + aiKeyAlg: ALG_ID, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptImportPublicKeyInfoEx2( + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + phKey: *mut BCRYPT_KEY_HANDLE, + ) -> BOOL; +} +pub const CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_EX2_FUNC: &'static str + = "CryptDllImportPublicKeyInfoEx2"; +FN!{stdcall PFN_IMPORT_PUBLIC_KEY_INFO_EX2_FUNC( + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + phKey: *mut BCRYPT_KEY_HANDLE, +) -> BOOL} +extern "system" { + pub fn CryptAcquireCertificatePrivateKey( + pCert: PCCERT_CONTEXT, + dwFlags: DWORD, + pvParameters: *mut c_void, + phCryptProvOrNCryptKey: *mut HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + pdwKeySpec: *mut DWORD, + pfCallerFreeProvOrNCryptKey: *mut BOOL, + ) -> BOOL; +} +pub const CRYPT_ACQUIRE_CACHE_FLAG: DWORD = 0x00000001; +pub const CRYPT_ACQUIRE_USE_PROV_INFO_FLAG: DWORD = 0x00000002; +pub const CRYPT_ACQUIRE_COMPARE_KEY_FLAG: DWORD = 0x00000004; +pub const CRYPT_ACQUIRE_NO_HEALING: DWORD = 0x00000008; +pub const CRYPT_ACQUIRE_SILENT_FLAG: DWORD = 0x00000040; +pub const CRYPT_ACQUIRE_WINDOW_HANDLE_FLAG: DWORD = 0x00000080; +pub const CRYPT_ACQUIRE_NCRYPT_KEY_FLAGS_MASK: DWORD = 0x00070000; +pub const CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG: DWORD = 0x00010000; +pub const CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG: DWORD = 0x00020000; +pub const CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG: DWORD = 0x00040000; +extern "system" { + pub fn CryptFindCertificateKeyProvInfo( + pCert: PCCERT_CONTEXT, + dwFlags: DWORD, + pvReserved: *mut c_void, + ) -> BOOL; +} +pub const CRYPT_FIND_USER_KEYSET_FLAG: DWORD = 0x00000001; +pub const CRYPT_FIND_MACHINE_KEYSET_FLAG: DWORD = 0x00000002; +pub const CRYPT_FIND_SILENT_KEYSET_FLAG: DWORD = 0x00000040; +FN!{stdcall PFN_IMPORT_PRIV_KEY_FUNC( + hCryptProv: HCRYPTPROV, + pPrivateKeyInfo: *mut CRYPT_PRIVATE_KEY_INFO, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, +) -> BOOL} +pub const CRYPT_OID_IMPORT_PRIVATE_KEY_INFO_FUNC: &'static str = "CryptDllImportPrivateKeyInfoEx"; +extern "system" { + pub fn CryptImportPKCS8( + sPrivateKeyAndParams: CRYPT_PKCS8_IMPORT_PARAMS, + dwFlags: DWORD, + phCryptProv: *mut HCRYPTPROV, + pvAuxInfo: *mut c_void, + ) -> BOOL; +} +FN!{stdcall PFN_EXPORT_PRIV_KEY_FUNC( + hCryptProv: HCRYPTPROV, + dwKeySpec: DWORD, + pszPrivateKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pPrivateKeyInfo: *mut CRYPT_PRIVATE_KEY_INFO, + pcbPrivateKeyInfo: *mut DWORD, +) -> BOOL} +pub const CRYPT_OID_EXPORT_PRIVATE_KEY_INFO_FUNC: &'static str = "CryptDllExportPrivateKeyInfoEx"; +pub const CRYPT_DELETE_KEYSET: DWORD = CRYPT_DELETEKEYSET; +extern "system" { + pub fn CryptExportPKCS8( + hCryptProv: HCRYPTPROV, + dwKeySpec: DWORD, + pszPrivateKeyObjId: LPSTR, + dwFlags: DWORD, + pvAuxInfo: *mut c_void, + pbPrivateKeyBlob: *mut BYTE, + pcbPrivateKeyBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptExportPKCS8Ex( + psExportParams: CRYPT_PKCS8_EXPORT_PARAMS, + dwKeySpec: DWORD, + pvAuxInfo: *mut c_void, + pbPrivateKeyBlob: *mut BYTE, + pcbPrivateKeyBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptHashPublicKeyInfo( + hCryptProv: HCRYPTPROV_LEGACY, + Algid: ALG_ID, + dwFlags: DWORD, + dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CertRDNValueToStrA( + dwValueType: DWORD, + pValue: PCERT_RDN_VALUE_BLOB, + psz: LPSTR, + csz: DWORD, + ) -> DWORD; + pub fn CertRDNValueToStrW( + dwValueType: DWORD, + pValue: PCERT_RDN_VALUE_BLOB, + psz: LPWSTR, + csz: DWORD, + ) -> DWORD; + pub fn CertNameToStrA( + dwCertEncodingType: DWORD, + pName: PCERT_NAME_BLOB, + dwStrType: DWORD, + psz: LPSTR, + csz: DWORD, + ) -> DWORD; + pub fn CertNameToStrW( + dwCertEncodingType: DWORD, + pName: PCERT_NAME_BLOB, + dwStrType: DWORD, + psz: LPWSTR, + csz: DWORD, + ) -> DWORD; +} +pub const CERT_SIMPLE_NAME_STR: DWORD = 1; +pub const CERT_OID_NAME_STR: DWORD = 2; +pub const CERT_X500_NAME_STR: DWORD = 3; +pub const CERT_XML_NAME_STR: DWORD = 4; +pub const CERT_NAME_STR_SEMICOLON_FLAG: DWORD = 0x40000000; +pub const CERT_NAME_STR_NO_PLUS_FLAG: DWORD = 0x20000000; +pub const CERT_NAME_STR_NO_QUOTING_FLAG: DWORD = 0x10000000; +pub const CERT_NAME_STR_CRLF_FLAG: DWORD = 0x08000000; +pub const CERT_NAME_STR_COMMA_FLAG: DWORD = 0x04000000; +pub const CERT_NAME_STR_REVERSE_FLAG: DWORD = 0x02000000; +pub const CERT_NAME_STR_FORWARD_FLAG: DWORD = 0x01000000; +pub const CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG: DWORD = 0x00010000; +pub const CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG: DWORD = 0x00020000; +pub const CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG: DWORD = 0x00040000; +pub const CERT_NAME_STR_FORCE_UTF8_DIR_STR_FLAG: DWORD = 0x00080000; +pub const CERT_NAME_STR_DISABLE_UTF8_DIR_STR_FLAG: DWORD = 0x00100000; +pub const CERT_NAME_STR_ENABLE_PUNYCODE_FLAG: DWORD = 0x00200000; +extern "system" { + pub fn CertStrToNameA( + dwCertEncodingType: DWORD, + pszX500: LPCSTR, + dwStrType: DWORD, + pvReserved: *mut c_void, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ppszError: *mut LPCSTR, + ) -> BOOL; + pub fn CertStrToNameW( + dwCertEncodingType: DWORD, + pszX500: LPCWSTR, + dwStrType: DWORD, + pvReserved: *mut c_void, + pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ppszError: *mut LPCWSTR, + ) -> BOOL; + pub fn CertGetNameStringA( + pCertContext: PCCERT_CONTEXT, + dwType: DWORD, + dwFlags: DWORD, + pvTypePara: *mut c_void, + pszNameString: LPSTR, + cchNameString: DWORD, + ) -> DWORD; + pub fn CertGetNameStringW( + pCertContext: PCCERT_CONTEXT, + dwType: DWORD, + dwFlags: DWORD, + pvTypePara: *mut c_void, + pszNameString: LPWSTR, + cchNameString: DWORD, + ) -> DWORD; +} +pub const CERT_NAME_EMAIL_TYPE: DWORD = 1; +pub const CERT_NAME_RDN_TYPE: DWORD = 2; +pub const CERT_NAME_ATTR_TYPE: DWORD = 3; +pub const CERT_NAME_SIMPLE_DISPLAY_TYPE: DWORD = 4; +pub const CERT_NAME_FRIENDLY_DISPLAY_TYPE: DWORD = 5; +pub const CERT_NAME_DNS_TYPE: DWORD = 6; +pub const CERT_NAME_URL_TYPE: DWORD = 7; +pub const CERT_NAME_UPN_TYPE: DWORD = 8; +pub const CERT_NAME_ISSUER_FLAG: DWORD = 0x1; +pub const CERT_NAME_DISABLE_IE4_UTF8_FLAG: DWORD = 0x00010000; +pub const CERT_NAME_SEARCH_ALL_NAMES_FLAG: DWORD = 0x2; +FN!{stdcall PFN_CRYPT_GET_SIGNER_CERTIFICATE( + pvGetArg: *mut c_void, + dwCertEncodingType: DWORD, + pSignerId: PCERT_INFO, + hMsgCertStore: HCERTSTORE, +) -> PCCERT_CONTEXT} +STRUCT!{struct CRYPT_SIGN_MESSAGE_PARA { + cbSize: DWORD, + dwMsgEncodingType: DWORD, + pSigningCert: PCCERT_CONTEXT, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *mut c_void, + cMsgCert: DWORD, + rgpMsgCert: *mut PCCERT_CONTEXT, + cMsgCrl: DWORD, + rgpMsgCrl: *mut PCCRL_CONTEXT, + cAuthAttr: DWORD, + rgAuthAttr: PCRYPT_ATTRIBUTE, + cUnauthAttr: DWORD, + rgUnauthAttr: PCRYPT_ATTRIBUTE, + dwFlags: DWORD, + dwInnerContentType: DWORD, + HashEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashEncryptionAuxInfo: *mut c_void, +}} +pub type PCRYPT_SIGN_MESSAGE_PARA = *mut CRYPT_SIGN_MESSAGE_PARA; +pub const CRYPT_MESSAGE_BARE_CONTENT_OUT_FLAG: DWORD = 0x00000001; +pub const CRYPT_MESSAGE_ENCAPSULATED_CONTENT_OUT_FLAG: DWORD = 0x00000002; +pub const CRYPT_MESSAGE_KEYID_SIGNER_FLAG: DWORD = 0x00000004; +pub const CRYPT_MESSAGE_SILENT_KEYSET_FLAG: DWORD = 0x00000040; +STRUCT!{struct CRYPT_VERIFY_MESSAGE_PARA { + cbSize: DWORD, + dwMsgAndCertEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + pfnGetSignerCertificate: PFN_CRYPT_GET_SIGNER_CERTIFICATE, + pvGetArg: *mut c_void, + pStrongSignPara: PCCERT_STRONG_SIGN_PARA, +}} +pub type PCRYPT_VERIFY_MESSAGE_PARA = *mut CRYPT_VERIFY_MESSAGE_PARA; +STRUCT!{struct CRYPT_ENCRYPT_MESSAGE_PARA { + cbSize: DWORD, + dwMsgEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + ContentEncryptionAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvEncryptionAuxInfo: *mut c_void, + dwFlags: DWORD, + dwInnerContentType: DWORD, +}} +pub type PCRYPT_ENCRYPT_MESSAGE_PARA = *mut CRYPT_DECRYPT_MESSAGE_PARA; +pub const CRYPT_MESSAGE_KEYID_RECIPIENT_FLAG: DWORD = 0x4; +STRUCT!{struct CRYPT_DECRYPT_MESSAGE_PARA { + cbSize: DWORD, + dwMsgAndCertEncodingType: DWORD, + cCertStore: DWORD, + rghCertStore: *mut HCERTSTORE, + dwFlags: DWORD, +}} +pub type PCRYPT_DECRYPT_MESSAGE_PARA = *mut CRYPT_DECRYPT_MESSAGE_PARA; +STRUCT!{struct CRYPT_HASH_MESSAGE_PARA { + cbSize: DWORD, + dwMsgEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *mut c_void, +}} +pub type PCRYPT_HASH_MESSAGE_PARA = *mut CRYPT_HASH_MESSAGE_PARA; +UNION!{union CRYPT_KEY_SIGN_MESSAGE_PARA_u { + [usize; 1], + hCryptProv hCryptProv_mut: HCRYPTPROV, + hNCryptKey hNCryptKey_mut: NCRYPT_KEY_HANDLE, +}} +STRUCT!{struct CRYPT_KEY_SIGN_MESSAGE_PARA { + cbSize: DWORD, + dwMsgAndCertEncodingType: DWORD, + u: CRYPT_KEY_SIGN_MESSAGE_PARA_u, + dwKeySpec: DWORD, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + pvHashAuxInfo: *mut c_void, + PubKeyAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, +}} +pub type PCRYPT_KEY_SIGN_MESSAGE_PARA = *mut CRYPT_KEY_SIGN_MESSAGE_PARA; +STRUCT!{struct CRYPT_KEY_VERIFY_MESSAGE_PARA { + cbSize: DWORD, + dwMsgEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, +}} +pub type PCRYPT_KEY_VERIFY_MESSAGE_PARA = *mut CRYPT_KEY_VERIFY_MESSAGE_PARA; +extern "system" { + pub fn CryptSignMessage( + pSignPara: PCRYPT_SIGN_MESSAGE_PARA, + fDetachedSignature: BOOL, + cToBeSigned: DWORD, + rgpbToBeSigned: *mut *const BYTE, + rgcbToBeSigned: *mut DWORD, + pbSignedBlob: *mut BYTE, + pcbSignedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyMessageSignature( + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, + dwSignerIndex: DWORD, + pbSignedBlob: *const BYTE, + cbSignedBlob: DWORD, + pbDecoded: *mut BYTE, + pcbDecoded: *mut DWORD, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptGetMessageSignerCount( + dwMsgEncodingType: DWORD, + pbSignedBlob: *const BYTE, + cbSignedBlob: DWORD, + ) -> LONG; + pub fn CryptGetMessageCertificates( + dwMsgAndCertEncodingType: DWORD, + hCryptProv: HCRYPTPROV_LEGACY, + dwFlags: DWORD, + pbSignedBlob: *const BYTE, + cbSignedBlob: DWORD, + ) -> HCERTSTORE; + pub fn CryptVerifyDetachedMessageSignature( + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, + dwSignerIndex: DWORD, + pbDetachedSignBlob: *const BYTE, + cbDetachedSignBlob: DWORD, + cToBeSigned: DWORD, + rgpbToBeSigned: *mut *const BYTE, + rgcbToBeSigned: *mut DWORD, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptEncryptMessage( + pEncryptPara: PCRYPT_ENCRYPT_MESSAGE_PARA, + cRecipientCert: DWORD, + rgpRecipientCert: *mut PCCERT_CONTEXT, + pbToBeEncrypted: *const BYTE, + cbToBeEncrypted: DWORD, + pbEncryptedBlob: *mut BYTE, + pcbEncryptedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptDecryptMessage( + pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, + pbEncryptedBlob: *const BYTE, + cbEncryptedBlob: DWORD, + pbDecrypted: *mut BYTE, + pcbDecrypted: *mut DWORD, + ppXchgCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptSignAndEncryptMessage( + pSignPara: PCRYPT_SIGN_MESSAGE_PARA, + pEncryptPara: PCRYPT_ENCRYPT_MESSAGE_PARA, + cRecipientCert: DWORD, + rgpRecipientCert: *mut PCCERT_CONTEXT, + pbToBeSignedAndEncrypted: *const BYTE, + cbToBeSignedAndEncrypted: DWORD, + pbSignedAndEncryptedBlob: *mut BYTE, + pcbSignedAndEncryptedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptDecryptAndVerifyMessageSignature( + pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, + dwSignerIndex: DWORD, + pbEncryptedBlob: *const BYTE, + cbEncryptedBlob: DWORD, + pbDecrypted: *mut BYTE, + pcbDecrypted: *mut DWORD, + ppXchgCert: *mut PCCERT_CONTEXT, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptDecodeMessage( + dwMsgTypeFlags: DWORD, + pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, + dwSignerIndex: DWORD, + pbEncodedBlob: *const BYTE, + cbEncodedBlob: DWORD, + dwPrevInnerContentType: DWORD, + pdwMsgType: *mut DWORD, + pdwInnerContentType: *mut DWORD, + pbDecoded: *mut BYTE, + pcbDecoded: *mut DWORD, + ppXchgCert: *mut PCCERT_CONTEXT, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptHashMessage( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, + fDetachedHash: BOOL, + cToBeHashed: DWORD, + rgpbToBeHashed: *mut *const BYTE, + rgcbToBeHashed: *mut DWORD, + pbHashedBlob: *mut BYTE, + pcbHashedBlob: *mut DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyMessageHash( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, + pbHashedBlob: *mut BYTE, + cbHashedBlob: DWORD, + pbToBeHashed: *mut BYTE, + pcbToBeHashed: *mut DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyDetachedMessageHash( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, + pbDetachedHashBlob: *mut BYTE, + cbDetachedHashBlob: DWORD, + cToBeHashed: DWORD, + rgpbToBeHashed: *mut *const BYTE, + rgcbToBeHashed: *mut DWORD, + pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptSignMessageWithKey( + pSignPara: PCRYPT_KEY_SIGN_MESSAGE_PARA, + pbToBeSigned: *const BYTE, + cbToBeSigned: DWORD, + pbSignedBlob: *mut BYTE, + pcbSignedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyMessageSignatureWithKey( + pVerifyPara: PCRYPT_KEY_VERIFY_MESSAGE_PARA, + pPublicKeyInfo: PCERT_PUBLIC_KEY_INFO, + pbSignedBlob: *const BYTE, + cbSignedBlob: DWORD, + pbDecoded: *mut BYTE, + pcbDecoded: *mut DWORD, + ) -> BOOL; + pub fn CertOpenSystemStoreA( + hProv: HCRYPTPROV_LEGACY, + szSubsystemProtocol: LPCSTR, + ) -> HCERTSTORE; + pub fn CertOpenSystemStoreW( + hProv: HCRYPTPROV_LEGACY, + szSubsystemProtocol: LPCWSTR, + ) -> HCERTSTORE; + pub fn CertAddEncodedCertificateToSystemStoreA( + szCertStoreName: LPCSTR, + pbCertEncoded: *const BYTE, + cbCertEncoded: DWORD, + ) -> BOOL; + pub fn CertAddEncodedCertificateToSystemStoreW( + szCertStoreName: LPCWSTR, + pbCertEncoded: *const BYTE, + cbCertEncoded: DWORD, + ) -> BOOL; +} +STRUCT!{struct CERT_CHAIN { + cCerts: DWORD, + certs: PCERT_BLOB, + keyLocatorInfo: CRYPT_KEY_PROV_INFO, +}} +pub type PCERT_CHAIN = *mut CERT_CHAIN; +extern "system" { + pub fn FindCertsByIssuer( + pCertChains: PCERT_CHAIN, + pcbCertChains: *mut DWORD, + pcCertChains: *mut DWORD, + pbEncodedIssuerName: *mut BYTE, + cbEncodedIssuerName: DWORD, + pwszPurpose: LPCWSTR, + dwKeySpec: DWORD, + ) -> HRESULT; + pub fn CryptQueryObject( + dwObjectType: DWORD, + pvObject: *const c_void, + dwExpectedContentTypeFlags: DWORD, + dwExpectedFormatTypeFlags: DWORD, + dwFlags: DWORD, + pdwMsgAndCertEncodingType: *mut DWORD, + pdwContentType: *mut DWORD, + pdwFormatType: *mut DWORD, + phCertStore: *mut HCERTSTORE, + phMsg: *mut HCRYPTMSG, + ppvContext: *mut *const c_void, + ) -> BOOL; +} +pub const CERT_QUERY_OBJECT_FILE: DWORD = 0x00000001; +pub const CERT_QUERY_OBJECT_BLOB: DWORD = 0x00000002; +pub const CERT_QUERY_CONTENT_CERT: DWORD = 1; +pub const CERT_QUERY_CONTENT_CTL: DWORD = 2; +pub const CERT_QUERY_CONTENT_CRL: DWORD = 3; +pub const CERT_QUERY_CONTENT_SERIALIZED_STORE: DWORD = 4; +pub const CERT_QUERY_CONTENT_SERIALIZED_CERT: DWORD = 5; +pub const CERT_QUERY_CONTENT_SERIALIZED_CTL: DWORD = 6; +pub const CERT_QUERY_CONTENT_SERIALIZED_CRL: DWORD = 7; +pub const CERT_QUERY_CONTENT_PKCS7_SIGNED: DWORD = 8; +pub const CERT_QUERY_CONTENT_PKCS7_UNSIGNED: DWORD = 9; +pub const CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED: DWORD = 10; +pub const CERT_QUERY_CONTENT_PKCS10: DWORD = 11; +pub const CERT_QUERY_CONTENT_PFX: DWORD = 12; +pub const CERT_QUERY_CONTENT_CERT_PAIR: DWORD = 13; +pub const CERT_QUERY_CONTENT_PFX_AND_LOAD: DWORD = 14; +pub const CERT_QUERY_CONTENT_FLAG_CERT: DWORD = 1 << CERT_QUERY_CONTENT_CERT; +pub const CERT_QUERY_CONTENT_FLAG_CTL: DWORD = 1 << CERT_QUERY_CONTENT_CTL; +pub const CERT_QUERY_CONTENT_FLAG_CRL: DWORD = 1 << CERT_QUERY_CONTENT_CRL; +pub const CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE: DWORD + = 1<< CERT_QUERY_CONTENT_SERIALIZED_STORE; +pub const CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT: DWORD = 1 << CERT_QUERY_CONTENT_SERIALIZED_CERT; +pub const CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL: DWORD = 1 << CERT_QUERY_CONTENT_SERIALIZED_CTL; +pub const CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL: DWORD = 1 << CERT_QUERY_CONTENT_SERIALIZED_CRL; +pub const CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED: DWORD = 1 << CERT_QUERY_CONTENT_PKCS7_SIGNED; +pub const CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED: DWORD = 1 << CERT_QUERY_CONTENT_PKCS7_UNSIGNED; +pub const CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED: DWORD + = 1 << CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED; +pub const CERT_QUERY_CONTENT_FLAG_PKCS10: DWORD = 1 << CERT_QUERY_CONTENT_PKCS10; +pub const CERT_QUERY_CONTENT_FLAG_PFX: DWORD = 1 << CERT_QUERY_CONTENT_PFX; +pub const CERT_QUERY_CONTENT_FLAG_CERT_PAIR: DWORD = 1 << CERT_QUERY_CONTENT_CERT_PAIR; +pub const CERT_QUERY_CONTENT_FLAG_PFX_AND_LOAD: DWORD = 1 << CERT_QUERY_CONTENT_PFX_AND_LOAD; +pub const CERT_QUERY_CONTENT_FLAG_ALL: DWORD = CERT_QUERY_CONTENT_FLAG_CERT + | CERT_QUERY_CONTENT_FLAG_CTL | CERT_QUERY_CONTENT_FLAG_CRL + | CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT + | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL + | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED + | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | CERT_QUERY_CONTENT_FLAG_PKCS10 + | CERT_QUERY_CONTENT_FLAG_PFX | CERT_QUERY_CONTENT_FLAG_CERT_PAIR; +pub const CERT_QUERY_CONTENT_FLAG_ALL_ISSUER_CERT: DWORD = CERT_QUERY_CONTENT_FLAG_CERT + | CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT + | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED; +pub const CERT_QUERY_FORMAT_BINARY: DWORD = 1; +pub const CERT_QUERY_FORMAT_BASE64_ENCODED: DWORD = 2; +pub const CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED: DWORD = 3; +pub const CERT_QUERY_FORMAT_FLAG_BINARY: DWORD = 1 << CERT_QUERY_FORMAT_BINARY; +pub const CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED: DWORD = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED; +pub const CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED: DWORD + = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED; +pub const CERT_QUERY_FORMAT_FLAG_ALL: DWORD = CERT_QUERY_FORMAT_FLAG_BINARY + | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED; +extern "system" { + pub fn CryptMemAlloc( + cbSize: ULONG, + ) -> LPVOID; + pub fn CryptMemRealloc( + pv: LPVOID, + cbSize: ULONG, + ) -> LPVOID; + pub fn CryptMemFree( + pv: LPVOID, + ); +} +pub type HCRYPTASYNC = HANDLE; +pub type PHCRYPTASYNC = *mut HANDLE; +FN!{stdcall PFN_CRYPT_ASYNC_PARAM_FREE_FUNC( + pszParamOid: LPSTR, + pvParam: LPVOID, +) -> ()} +extern "system" { + pub fn CryptCreateAsyncHandle( + dwFlags: DWORD, + phAsync: PHCRYPTASYNC, + ) -> BOOL; + pub fn CryptSetAsyncParam( + hAsync: HCRYPTASYNC, + pszParamOid: LPSTR, + pvParam: LPVOID, + pfnFree: PFN_CRYPT_ASYNC_PARAM_FREE_FUNC, + ) -> BOOL; + pub fn CryptGetAsyncParam( + hAsync: HCRYPTASYNC, + pszParamOid: LPSTR, + ppvParam: *mut LPVOID, + ppfnFree: *mut PFN_CRYPT_ASYNC_PARAM_FREE_FUNC, + ) -> BOOL; + pub fn CryptCloseAsyncHandle( + hAsync: HCRYPTASYNC, + ) -> BOOL; +} +STRUCT!{struct CRYPT_BLOB_ARRAY { + cBlob: DWORD, + rgBlob: PCRYPT_DATA_BLOB, +}} +pub type PCRYPT_BLOB_ARRAY = *mut CRYPT_BLOB_ARRAY; +STRUCT!{struct CRYPT_CREDENTIALS { + cbSize: DWORD, + pszCredentialsOid: LPCSTR, + pvCredentials: LPVOID, +}} +pub type PCRYPT_CREDENTIALS = *mut CRYPT_CREDENTIALS; +pub const CREDENTIAL_OID_PASSWORD_CREDENTIALS_A: LPCSTR = 1 as LPCSTR; +pub const CREDENTIAL_OID_PASSWORD_CREDENTIALS_W: LPCSTR = 2 as LPCSTR; +STRUCT!{struct CRYPT_PASSWORD_CREDENTIALSA { + cbSize: DWORD, + pszUsername: LPSTR, + pszPassword: LPSTR, +}} +pub type PCRYPT_PASSWORD_CREDENTIALSA = *mut CRYPT_PASSWORD_CREDENTIALSA; +STRUCT!{struct CRYPT_PASSWORD_CREDENTIALSW { + cbSize: DWORD, + pszUsername: LPWSTR, + pszPassword: LPWSTR, +}} +pub type PCRYPT_PASSWORD_CREDENTIALSW = *mut CRYPT_PASSWORD_CREDENTIALSW; +pub const SCHEME_OID_RETRIEVE_ENCODED_OBJECT_FUNC: &'static str = "SchemeDllRetrieveEncodedObject"; +pub const SCHEME_OID_RETRIEVE_ENCODED_OBJECTW_FUNC: &'static str + = "SchemeDllRetrieveEncodedObjectW"; +FN!{stdcall PFN_FREE_ENCODED_OBJECT_FUNC( + pszObjectOid: LPCSTR, + pObject: PCRYPT_BLOB_ARRAY, + pvFreeContext: LPVOID, +) -> ()} +pub const CONTEXT_OID_CREATE_OBJECT_CONTEXT_FUNC: &'static str = "ContextDllCreateObjectContext"; +pub const CONTEXT_OID_CERTIFICATE: LPCSTR = 1 as LPCSTR; +pub const CONTEXT_OID_CRL: LPCSTR = 2 as LPCSTR; +pub const CONTEXT_OID_CTL: LPCSTR = 3 as LPCSTR; +pub const CONTEXT_OID_PKCS7: LPCSTR = 4 as LPCSTR; +pub const CONTEXT_OID_CAPI2_ANY: LPCSTR = 5 as LPCSTR; +pub const CONTEXT_OID_OCSP_RESP: LPCSTR = 6 as LPCSTR; +pub const CRYPT_RETRIEVE_MULTIPLE_OBJECTS: DWORD = 0x00000001; +pub const CRYPT_CACHE_ONLY_RETRIEVAL: DWORD = 0x00000002; +pub const CRYPT_WIRE_ONLY_RETRIEVAL: DWORD = 0x00000004; +pub const CRYPT_DONT_CACHE_RESULT: DWORD = 0x00000008; +pub const CRYPT_ASYNC_RETRIEVAL: DWORD = 0x00000010; +pub const CRYPT_STICKY_CACHE_RETRIEVAL: DWORD = 0x00001000; +pub const CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL: DWORD = 0x00002000; +pub const CRYPT_OFFLINE_CHECK_RETRIEVAL: DWORD = 0x00004000; +pub const CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE: DWORD = 0x00008000; +pub const CRYPT_LDAP_SIGN_RETRIEVAL: DWORD = 0x00010000; +pub const CRYPT_NO_AUTH_RETRIEVAL: DWORD = 0x00020000; +pub const CRYPT_LDAP_AREC_EXCLUSIVE_RETRIEVAL: DWORD = 0x00040000; +pub const CRYPT_AIA_RETRIEVAL: DWORD = 0x00080000; +pub const CRYPT_HTTP_POST_RETRIEVAL: DWORD = 0x00100000; +pub const CRYPT_PROXY_CACHE_RETRIEVAL: DWORD = 0x00200000; +pub const CRYPT_NOT_MODIFIED_RETRIEVAL: DWORD = 0x00400000; +pub const CRYPT_ENABLE_SSL_REVOCATION_RETRIEVAL: DWORD = 0x00800000; +pub const CRYPT_RANDOM_QUERY_STRING_RETRIEVAL: DWORD = 0x04000000; +pub const CRYPT_ENABLE_FILE_RETRIEVAL: DWORD = 0x08000000; +pub const CRYPT_CREATE_NEW_FLUSH_ENTRY: DWORD = 0x10000000; +pub const CRYPT_VERIFY_CONTEXT_SIGNATURE: DWORD = 0x00000020; +pub const CRYPT_VERIFY_DATA_HASH: DWORD = 0x00000040; +pub const CRYPT_KEEP_TIME_VALID: DWORD = 0x00000080; +pub const CRYPT_DONT_VERIFY_SIGNATURE: DWORD = 0x00000100; +pub const CRYPT_DONT_CHECK_TIME_VALIDITY: DWORD = 0x00000200; +pub const CRYPT_CHECK_FRESHNESS_TIME_VALIDITY: DWORD = 0x00000400; +pub const CRYPT_ACCUMULATIVE_TIMEOUT: DWORD = 0x00000800; +pub const CRYPT_OCSP_ONLY_RETRIEVAL: DWORD = 0x01000000; +pub const CRYPT_NO_OCSP_FAILOVER_TO_CRL_RETRIEVAL: DWORD = 0x02000000; +STRUCT!{struct CRYPTNET_URL_CACHE_PRE_FETCH_INFO { + cbSize: DWORD, + dwObjectType: DWORD, + dwError: DWORD, + dwReserved: DWORD, + ThisUpdateTime: FILETIME, + NextUpdateTime: FILETIME, + PublishTime: FILETIME, +}} +pub type PCRYPTNET_URL_CACHE_PRE_FETCH_INFO = *mut CRYPTNET_URL_CACHE_PRE_FETCH_INFO; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_NONE: DWORD = 0; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_BLOB: DWORD = 1; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_CRL: DWORD = 2; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_OCSP: DWORD = 3; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_AUTOROOT_CAB: DWORD = 5; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_DISALLOWED_CERT_CAB: DWORD = 6; +pub const CRYPTNET_URL_CACHE_PRE_FETCH_PIN_RULES_CAB: DWORD = 7; +STRUCT!{struct CRYPTNET_URL_CACHE_FLUSH_INFO { + cbSize: DWORD, + dwExemptSeconds: DWORD, + ExpireTime: FILETIME, +}} +pub type PCRYPTNET_URL_CACHE_FLUSH_INFO = *mut CRYPTNET_URL_CACHE_FLUSH_INFO; +pub const CRYPTNET_URL_CACHE_DEFAULT_FLUSH: DWORD = 0; +pub const CRYPTNET_URL_CACHE_DISABLE_FLUSH: DWORD = 0xFFFFFFFF; +STRUCT!{struct CRYPTNET_URL_CACHE_RESPONSE_INFO { + cbSize: DWORD, + wResponseType: WORD, + wResponseFlags: WORD, + LastModifiedTime: FILETIME, + dwMaxAge: DWORD, + pwszETag: LPCWSTR, + dwProxyId: DWORD, +}} +pub type PCRYPTNET_URL_CACHE_RESPONSE_INFO = *mut CRYPTNET_URL_CACHE_RESPONSE_INFO; +pub const CRYPTNET_URL_CACHE_RESPONSE_NONE: WORD = 0; +pub const CRYPTNET_URL_CACHE_RESPONSE_HTTP: WORD = 1; +pub const CRYPTNET_URL_CACHE_RESPONSE_VALIDATED: WORD = 0x8000; +STRUCT!{struct CRYPT_RETRIEVE_AUX_INFO { + cbSize: DWORD, + pLastSyncTime: *mut FILETIME, + dwMaxUrlRetrievalByteCount: DWORD, + pPreFetchInfo: PCRYPTNET_URL_CACHE_PRE_FETCH_INFO, + pFlushInfo: PCRYPTNET_URL_CACHE_FLUSH_INFO, + ppResponseInfo: *mut PCRYPTNET_URL_CACHE_RESPONSE_INFO, + pwszCacheFileNamePrefix: LPWSTR, + pftCacheResync: LPFILETIME, + fProxyCacheRetrieval: BOOL, + dwHttpStatusCode: DWORD, + ppwszErrorResponseHeaders: *mut LPWSTR, + ppErrorContentBlob: *mut PCRYPT_DATA_BLOB, +}} +pub type PCRYPT_RETRIEVE_AUX_INFO = *mut CRYPT_RETRIEVE_AUX_INFO; +pub const CRYPT_RETRIEVE_MAX_ERROR_CONTENT_LENGTH: DWORD = 0x1000; +extern "system" { + pub fn CryptRetrieveObjectByUrlA( + pszUrl: LPCSTR, + pszObjectOid: LPCSTR, + dwRetrievalFlags: DWORD, + dwTimeout: DWORD, + ppvObject: *mut LPVOID, + hAsyncRetrieve: HCRYPTASYNC, + pCredentials: PCRYPT_CREDENTIALS, + pvVerify: LPVOID, + pAuxInfo: PCRYPT_RETRIEVE_AUX_INFO, + ) -> BOOL; + pub fn CryptRetrieveObjectByUrlW( + pszUrl: LPCWSTR, + pszObjectOid: LPCSTR, + dwRetrievalFlags: DWORD, + dwTimeout: DWORD, + ppvObject: *mut LPVOID, + hAsyncRetrieve: HCRYPTASYNC, + pCredentials: PCRYPT_CREDENTIALS, + pvVerify: LPVOID, + pAuxInfo: PCRYPT_RETRIEVE_AUX_INFO, + ) -> BOOL; +} +FN!{stdcall PFN_CRYPT_CANCEL_RETRIEVAL( + dwFlags: DWORD, + pvArg: *mut c_void, +) -> BOOL} +extern "system" { + pub fn CryptInstallCancelRetrieval( + pfnCancel: PFN_CRYPT_CANCEL_RETRIEVAL, + pvArg: *const c_void, + dwFlags: DWORD, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CryptUninstallCancelRetrieval( + dwFlags: DWORD, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CryptCancelAsyncRetrieval( + hAsyncRetrieval: HCRYPTASYNC, + ) -> BOOL; +} +pub const CRYPT_PARAM_ASYNC_RETRIEVAL_COMPLETION: LPCSTR = 1 as LPCSTR; +FN!{stdcall PFN_CRYPT_ASYNC_RETRIEVAL_COMPLETION_FUNC( + pvCompletion: LPVOID, + dwCompletionCode: DWORD, + pszUrl: LPCSTR, + pszObjectOid: LPSTR, + pvObject: LPVOID, +) -> ()} +STRUCT!{struct CRYPT_ASYNC_RETRIEVAL_COMPLETION { + pfnCompletion: PFN_CRYPT_ASYNC_RETRIEVAL_COMPLETION_FUNC, + pvCompletion: LPVOID, +}} +pub type PCRYPT_ASYNC_RETRIEVAL_COMPLETION = *mut CRYPT_ASYNC_RETRIEVAL_COMPLETION; +pub const CRYPT_PARAM_CANCEL_ASYNC_RETRIEVAL: LPCSTR = 2 as LPCSTR; +FN!{stdcall PFN_CANCEL_ASYNC_RETRIEVAL_FUNC( + hAsyncRetrieve: HCRYPTASYNC, +) -> BOOL} +pub const CRYPT_GET_URL_FROM_PROPERTY: DWORD = 0x00000001; +pub const CRYPT_GET_URL_FROM_EXTENSION: DWORD = 0x00000002; +pub const CRYPT_GET_URL_FROM_UNAUTH_ATTRIBUTE: DWORD = 0x00000004; +pub const CRYPT_GET_URL_FROM_AUTH_ATTRIBUTE: DWORD = 0x00000008; +STRUCT!{struct CRYPT_URL_ARRAY { + cUrl: DWORD, + rgwszUrl: *mut LPWSTR, +}} +pub type PCRYPT_URL_ARRAY = *mut CRYPT_URL_ARRAY; +STRUCT!{struct CRYPT_URL_INFO { + cbSize: DWORD, + dwSyncDeltaTime: DWORD, + cGroup: DWORD, + rgcGroupEntry: *mut DWORD, +}} +pub type PCRYPT_URL_INFO = *mut CRYPT_URL_INFO; +extern "system" { + pub fn CryptGetObjectUrl( + pszUrlOid: LPCSTR, + pvPara: LPVOID, + dwFlags: DWORD, + pUrlArray: PCRYPT_URL_ARRAY, + pcbUrlArray: *mut DWORD, + pUrlInfo: PCRYPT_URL_INFO, + pcbUrlInfo: *mut DWORD, + pvReserved: LPVOID, + ) -> BOOL; +} +pub const URL_OID_GET_OBJECT_URL_FUNC: &'static str = "UrlDllGetObjectUrl"; +pub const URL_OID_CERTIFICATE_ISSUER: LPCSTR = 1 as LPCSTR; +pub const URL_OID_CERTIFICATE_CRL_DIST_POINT: LPCSTR = 2 as LPCSTR; +pub const URL_OID_CTL_ISSUER: LPCSTR = 3 as LPCSTR; +pub const URL_OID_CTL_NEXT_UPDATE: LPCSTR = 4 as LPCSTR; +pub const URL_OID_CRL_ISSUER: LPCSTR = 5 as LPCSTR; +pub const URL_OID_CERTIFICATE_FRESHEST_CRL: LPCSTR = 6 as LPCSTR; +pub const URL_OID_CRL_FRESHEST_CRL: LPCSTR = 7 as LPCSTR; +pub const URL_OID_CROSS_CERT_DIST_POINT: LPCSTR = 8 as LPCSTR; +pub const URL_OID_CERTIFICATE_OCSP: LPCSTR = 9 as LPCSTR; +pub const URL_OID_CERTIFICATE_OCSP_AND_CRL_DIST_POINT: LPCSTR = 10 as LPCSTR; +pub const URL_OID_CERTIFICATE_CRL_DIST_POINT_AND_OCSP: LPCSTR = 11 as LPCSTR; +pub const URL_OID_CROSS_CERT_SUBJECT_INFO_ACCESS: LPCSTR = 12 as LPCSTR; +pub const URL_OID_CERTIFICATE_ONLY_OCSP: LPCSTR = 13 as LPCSTR; +STRUCT!{struct CERT_CRL_CONTEXT_PAIR { + pCertContext: PCCERT_CONTEXT, + pCrlContext: PCCRL_CONTEXT, +}} +pub type PCERT_CRL_CONTEXT_PAIR = *mut CERT_CRL_CONTEXT_PAIR; +pub type PCCERT_CRL_CONTEXT_PAIR = *const CERT_CRL_CONTEXT_PAIR; +STRUCT!{struct CRYPT_GET_TIME_VALID_OBJECT_EXTRA_INFO { + cbSize: DWORD, + iDeltaCrlIndicator: c_int, + pftCacheResync: LPFILETIME, + pLastSyncTime: LPFILETIME, + pMaxAgeTime: LPFILETIME, + pChainPara: PCERT_REVOCATION_CHAIN_PARA, + pDeltaCrlIndicator: PCRYPT_INTEGER_BLOB, +}} +pub type PCRYPT_GET_TIME_VALID_OBJECT_EXTRA_INFO = *mut CRYPT_GET_TIME_VALID_OBJECT_EXTRA_INFO; +extern "system" { + pub fn CryptGetTimeValidObject( + pszTimeValidOid: LPCSTR, + pvPara: LPVOID, + pIssuer: PCCERT_CONTEXT, + pftValidFor: LPFILETIME, + dwFlags: DWORD, + dwTimeout: DWORD, + ppvObject: *mut LPVOID, + pCredentials: PCRYPT_CREDENTIALS, + pExtraInfo: PCRYPT_GET_TIME_VALID_OBJECT_EXTRA_INFO, + ) -> BOOL; +} +pub const TIME_VALID_OID_GET_OBJECT_FUNC: &'static str = "TimeValidDllGetObject"; +pub const TIME_VALID_OID_GET_CTL: LPCSTR = 1 as LPCSTR; +pub const TIME_VALID_OID_GET_CRL: LPCSTR = 2 as LPCSTR; +pub const TIME_VALID_OID_GET_CRL_FROM_CERT: LPCSTR = 3 as LPCSTR; +pub const TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CERT: LPCSTR = 4 as LPCSTR; +pub const TIME_VALID_OID_GET_FRESHEST_CRL_FROM_CRL: LPCSTR = 5 as LPCSTR; +extern "system" { + pub fn CryptFlushTimeValidObject( + pszFlushTimeValidOid: LPCSTR, + pvPara: LPVOID, + pIssuer: PCCERT_CONTEXT, + dwFlags: DWORD, + pvReserved: LPVOID, + ) -> BOOL; +} +pub const TIME_VALID_OID_FLUSH_OBJECT_FUNC: &'static str = "TimeValidDllFlushObject"; +pub const TIME_VALID_OID_FLUSH_CTL: LPCSTR = 1 as LPCSTR; +pub const TIME_VALID_OID_FLUSH_CRL: LPCSTR = 2 as LPCSTR; +pub const TIME_VALID_OID_FLUSH_CRL_FROM_CERT: LPCSTR = 3 as LPCSTR; +pub const TIME_VALID_OID_FLUSH_FRESHEST_CRL_FROM_CERT: LPCSTR = 4 as LPCSTR; +pub const TIME_VALID_OID_FLUSH_FRESHEST_CRL_FROM_CRL: LPCSTR = 5 as LPCSTR; +extern "system" { + pub fn CertCreateSelfSignCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, + pSubjectIssuerBlob: PCERT_NAME_BLOB, + dwFlags: DWORD, + pKeyProvInfo: PCRYPT_KEY_PROV_INFO, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, + pStartTime: PSYSTEMTIME, + pEndTime: PSYSTEMTIME, + pExtensions: PCERT_EXTENSIONS, + ) -> PCCERT_CONTEXT; +} +pub const CERT_CREATE_SELFSIGN_NO_SIGN: DWORD = 1; +pub const CERT_CREATE_SELFSIGN_NO_KEY_INFO: DWORD = 2; +extern "system" { + pub fn CryptGetKeyIdentifierProperty( + pKeyIdentifier: *const CRYPT_HASH_BLOB, + dwPropId: DWORD, + dwFlags: DWORD, + pwszComputerName: LPCWSTR, + pvReserved: *mut c_void, + pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_KEYID_MACHINE_FLAG: DWORD = 0x00000020; +pub const CRYPT_KEYID_ALLOC_FLAG: DWORD = 0x00008000; +extern "system" { + pub fn CryptSetKeyIdentifierProperty( + pKeyIdentifier: *const CRYPT_HASH_BLOB, + dwPropId: DWORD, + dwFlags: DWORD, + pwszComputerName: LPCWSTR, + pvReserved: *mut c_void, + pvData: *const c_void, + ) -> BOOL; +} +pub const CRYPT_KEYID_DELETE_FLAG: DWORD = 0x00000010; +pub const CRYPT_KEYID_SET_NEW_FLAG: DWORD = 0x00002000; +FN!{stdcall PFN_CRYPT_ENUM_KEYID_PROP( + pKeyIdentifier: *const CRYPT_HASH_BLOB, + dwFlags: DWORD, + pvReserved: *mut c_void, + pvArg: *mut c_void, + cProp: DWORD, + rgdwPropId: *mut DWORD, + rgpvData: *mut *mut c_void, + rgcbData: *mut DWORD, +) -> BOOL} +extern "system" { + pub fn CryptEnumKeyIdentifierProperties( + pKeyIdentifier: *const CRYPT_HASH_BLOB, + dwPropId: DWORD, + dwFlags: DWORD, + pwszComputerName: LPCWSTR, + pvReserved: *mut c_void, + pvArg: *mut c_void, + pfnEnum: PFN_CRYPT_ENUM_KEYID_PROP, + ) -> BOOL; + pub fn CryptCreateKeyIdentifierFromCSP( + dwCertEncodingType: DWORD, + pszPubKeyOID: LPCSTR, + pPubKeyStruc: *const PUBLICKEYSTRUC, + cbPubKeyStruc: DWORD, + dwFlags: DWORD, + pvReserved: *mut c_void, + pbHash: *mut BYTE, + pcbHash: *mut DWORD, + ) -> BOOL; +} +pub const CERT_CHAIN_CONFIG_REGPATH: &'static str + = "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CertDllCreateCertificateChainEngine\\Config"; +pub const CERT_CHAIN_MAX_URL_RETRIEVAL_BYTE_COUNT_VALUE_NAME: &'static str + = "MaxUrlRetrievalByteCount"; +pub const CERT_CHAIN_MAX_URL_RETRIEVAL_BYTE_COUNT_DEFAULT: DWORD = 100 * 1024 * 1024; +pub const CERT_CHAIN_CACHE_RESYNC_FILETIME_VALUE_NAME: &'static str = "ChainCacheResyncFiletime"; +pub const CERT_CHAIN_DISABLE_MANDATORY_BASIC_CONSTRAINTS_VALUE_NAME: &'static str + = "DisableMandatoryBasicConstraints"; +pub const CERT_CHAIN_DISABLE_CA_NAME_CONSTRAINTS_VALUE_NAME: &'static str + = "DisableCANameConstraints"; +pub const CERT_CHAIN_DISABLE_UNSUPPORTED_CRITICAL_EXTENSIONS_VALUE_NAME: &'static str + = "DisableUnsupportedCriticalExtensions"; +pub const CERT_CHAIN_MAX_AIA_URL_COUNT_IN_CERT_VALUE_NAME: &'static str = "MaxAIAUrlCountInCert"; +pub const CERT_CHAIN_MAX_AIA_URL_COUNT_IN_CERT_DEFAULT: DWORD = 5; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_COUNT_PER_CHAIN_VALUE_NAME: &'static str + = "MaxAIAUrlRetrievalCountPerChain"; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_COUNT_PER_CHAIN_DEFAULT: DWORD = 3; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_BYTE_COUNT_VALUE_NAME: &'static str + = "MaxAIAUrlRetrievalByteCount"; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_BYTE_COUNT_DEFAULT: DWORD = 100000; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_CERT_COUNT_VALUE_NAME: &'static str + = "MaxAIAUrlRetrievalCertCount"; +pub const CERT_CHAIN_MAX_AIA_URL_RETRIEVAL_CERT_COUNT_DEFAULT: DWORD = 10; +pub const CERT_CHAIN_OCSP_VALIDITY_SECONDS_VALUE_NAME: &'static str + = "OcspValiditySeconds"; +pub const CERT_CHAIN_OCSP_VALIDITY_SECONDS_DEFAULT: DWORD = 12 * 60 * 60; +pub const CERT_CHAIN_DISABLE_SERIAL_CHAIN_VALUE_NAME: &'static str = "DisableSerialChain"; +pub const CERT_CHAIN_SERIAL_CHAIN_LOG_FILE_NAME_VALUE_NAME: &'static str + = "SerialChainLogFileName"; +pub const CERT_CHAIN_DISABLE_SYNC_WITH_SSL_TIME_VALUE_NAME: &'static str + = "DisableSyncWithSslTime"; +pub const CERT_CHAIN_MAX_SSL_TIME_UPDATED_EVENT_COUNT_VALUE_NAME: &'static str + = "MaxSslTimeUpdatedEventCount"; +pub const CERT_CHAIN_MAX_SSL_TIME_UPDATED_EVENT_COUNT_DEFAULT: DWORD = 5; +pub const CERT_CHAIN_MAX_SSL_TIME_UPDATED_EVENT_COUNT_DISABLE: DWORD = 0xFFFFFFFF; +pub const CERT_CHAIN_SSL_HANDSHAKE_LOG_FILE_NAME_VALUE_NAME: &'static str + = "SslHandshakeLogFileName"; +pub const CERT_CHAIN_ENABLE_WEAK_SIGNATURE_FLAGS_VALUE_NAME: &'static str + = "EnableWeakSignatureFlags"; +pub const CERT_CHAIN_ENABLE_MD2_MD4_FLAG: DWORD = 0x00000001; +pub const CERT_CHAIN_ENABLE_WEAK_RSA_ROOT_FLAG: DWORD = 0x00000002; +pub const CERT_CHAIN_ENABLE_WEAK_LOGGING_FLAG: DWORD = 0x00000004; +pub const CERT_CHAIN_ENABLE_ONLY_WEAK_LOGGING_FLAG: DWORD = 0x00000008; +pub const CERT_CHAIN_MIN_RSA_PUB_KEY_BIT_LENGTH_VALUE_NAME: &'static str = "MinRsaPubKeyBitLength"; +pub const CERT_CHAIN_MIN_RSA_PUB_KEY_BIT_LENGTH_DEFAULT: DWORD = 1023; +pub const CERT_CHAIN_MIN_RSA_PUB_KEY_BIT_LENGTH_DISABLE: DWORD = 0xFFFFFFFF; +pub const CERT_CHAIN_WEAK_RSA_PUB_KEY_TIME_VALUE_NAME: &'static str = "WeakRsaPubKeyTime"; +pub const CERT_CHAIN_WEAK_RSA_PUB_KEY_TIME_DEFAULT: u64 = 0x01CA8A755C6E0000; +pub const CERT_CHAIN_WEAK_SIGNATURE_LOG_DIR_VALUE_NAME: &'static str = "WeakSignatureLogDir"; +pub const CERT_CHAIN_DEFAULT_CONFIG_SUBDIR: &'static str = "Default"; +pub const CERT_CHAIN_WEAK_PREFIX_NAME: &'static str = "Weak"; +pub const CERT_CHAIN_WEAK_THIRD_PARTY_CONFIG_NAME: &'static str = "ThirdParty"; +pub const CERT_CHAIN_WEAK_ALL_CONFIG_NAME: &'static str = "Al"; +pub const CERT_CHAIN_WEAK_FLAGS_NAME: &'static str = "Flags"; +pub const CERT_CHAIN_WEAK_HYGIENE_NAME: &'static str = "Hygiene"; +pub const CERT_CHAIN_WEAK_AFTER_TIME_NAME: &'static str = "AfterTime"; +pub const CERT_CHAIN_WEAK_FILE_HASH_AFTER_TIME_NAME: &'static str = "FileHashAfterTime"; +pub const CERT_CHAIN_WEAK_TIMESTAMP_HASH_AFTER_TIME_NAME: &'static str = "TimestampHashAfterTime"; +pub const CERT_CHAIN_WEAK_MIN_BIT_LENGTH_NAME: &'static str = "MinBitLength"; +pub const CERT_CHAIN_WEAK_SHA256_ALLOW_NAME: &'static str = "Sha256Allow"; +pub const CERT_CHAIN_MIN_PUB_KEY_BIT_LENGTH_DISABLE: DWORD = 0xFFFFFFFF; +pub const CERT_CHAIN_ENABLE_WEAK_SETTINGS_FLAG: DWORD = 0x80000000; +pub const CERT_CHAIN_DISABLE_ALL_EKU_WEAK_FLAG: DWORD = 0x00010000; +pub const CERT_CHAIN_ENABLE_ALL_EKU_HYGIENE_FLAG: DWORD = 0x00020000; +pub const CERT_CHAIN_DISABLE_OPT_IN_SERVER_AUTH_WEAK_FLAG: DWORD = 0x00040000; +pub const CERT_CHAIN_DISABLE_SERVER_AUTH_WEAK_FLAG: DWORD = 0x00100000; +pub const CERT_CHAIN_ENABLE_SERVER_AUTH_HYGIENE_FLAG: DWORD = 0x00200000; +pub const CERT_CHAIN_DISABLE_CODE_SIGNING_WEAK_FLAG: DWORD = 0x00400000; +pub const CERT_CHAIN_DISABLE_MOTW_CODE_SIGNING_WEAK_FLAG: DWORD = 0x00800000; +pub const CERT_CHAIN_ENABLE_CODE_SIGNING_HYGIENE_FLAG: DWORD = 0x01000000; +pub const CERT_CHAIN_ENABLE_MOTW_CODE_SIGNING_HYGIENE_FLAG: DWORD = 0x02000000; +pub const CERT_CHAIN_DISABLE_TIMESTAMP_WEAK_FLAG: DWORD = 0x04000000; +pub const CERT_CHAIN_DISABLE_MOTW_TIMESTAMP_WEAK_FLAG: DWORD = 0x08000000; +pub const CERT_CHAIN_ENABLE_TIMESTAMP_HYGIENE_FLAG: DWORD = 0x10000000; +pub const CERT_CHAIN_ENABLE_MOTW_TIMESTAMP_HYGIENE_FLAG: DWORD = 0x20000000; +pub const CERT_CHAIN_MOTW_IGNORE_AFTER_TIME_WEAK_FLAG: DWORD = 0x40000000; +pub const CERT_CHAIN_DISABLE_FILE_HASH_WEAK_FLAG: DWORD = 0x00001000; +pub const CERT_CHAIN_DISABLE_MOTW_FILE_HASH_WEAK_FLAG: DWORD = 0x00002000; +pub const CERT_CHAIN_DISABLE_TIMESTAMP_HASH_WEAK_FLAG: DWORD = 0x00004000; +pub const CERT_CHAIN_DISABLE_MOTW_TIMESTAMP_HASH_WEAK_FLAG: DWORD = 0x00008000; +pub const CERT_CHAIN_DISABLE_WEAK_FLAGS: DWORD = CERT_CHAIN_DISABLE_ALL_EKU_WEAK_FLAG + | CERT_CHAIN_DISABLE_SERVER_AUTH_WEAK_FLAG | CERT_CHAIN_DISABLE_OPT_IN_SERVER_AUTH_WEAK_FLAG + | CERT_CHAIN_DISABLE_CODE_SIGNING_WEAK_FLAG | CERT_CHAIN_DISABLE_MOTW_CODE_SIGNING_WEAK_FLAG + | CERT_CHAIN_DISABLE_TIMESTAMP_WEAK_FLAG | CERT_CHAIN_DISABLE_MOTW_TIMESTAMP_WEAK_FLAG; +pub const CERT_CHAIN_DISABLE_FILE_HASH_WEAK_FLAGS: DWORD = CERT_CHAIN_DISABLE_FILE_HASH_WEAK_FLAG + | CERT_CHAIN_DISABLE_MOTW_FILE_HASH_WEAK_FLAG; +pub const CERT_CHAIN_DISABLE_TIMESTAMP_HASH_WEAK_FLAGS: DWORD + = CERT_CHAIN_DISABLE_TIMESTAMP_HASH_WEAK_FLAG + | CERT_CHAIN_DISABLE_MOTW_TIMESTAMP_HASH_WEAK_FLAG; +pub const CERT_CHAIN_ENABLE_HYGIENE_FLAGS: DWORD = CERT_CHAIN_ENABLE_ALL_EKU_HYGIENE_FLAG + | CERT_CHAIN_ENABLE_SERVER_AUTH_HYGIENE_FLAG | CERT_CHAIN_ENABLE_CODE_SIGNING_HYGIENE_FLAG + | CERT_CHAIN_ENABLE_MOTW_CODE_SIGNING_HYGIENE_FLAG | CERT_CHAIN_ENABLE_TIMESTAMP_HYGIENE_FLAG + | CERT_CHAIN_ENABLE_MOTW_TIMESTAMP_HYGIENE_FLAG; +pub const CERT_CHAIN_MOTW_WEAK_FLAGS: DWORD = CERT_CHAIN_DISABLE_MOTW_CODE_SIGNING_WEAK_FLAG + | CERT_CHAIN_DISABLE_MOTW_TIMESTAMP_WEAK_FLAG + | CERT_CHAIN_ENABLE_MOTW_CODE_SIGNING_HYGIENE_FLAG + | CERT_CHAIN_ENABLE_MOTW_TIMESTAMP_HYGIENE_FLAG | CERT_CHAIN_MOTW_IGNORE_AFTER_TIME_WEAK_FLAG; +pub const CERT_CHAIN_OPT_IN_WEAK_FLAGS: DWORD = CERT_CHAIN_DISABLE_OPT_IN_SERVER_AUTH_WEAK_FLAG; +pub const CERT_CHAIN_AUTO_CURRENT_USER: DWORD = 1; +pub const CERT_CHAIN_AUTO_LOCAL_MACHINE: DWORD = 2; +pub const CERT_CHAIN_AUTO_IMPERSONATED: DWORD = 3; +pub const CERT_CHAIN_AUTO_PROCESS_INFO: DWORD = 4; +pub const CERT_CHAIN_AUTO_PINRULE_INFO: DWORD = 5; +pub const CERT_CHAIN_AUTO_NETWORK_INFO: DWORD = 6; +pub const CERT_CHAIN_AUTO_SERIAL_LOCAL_MACHINE: DWORD = 7; +pub const CERT_CHAIN_AUTO_HPKP_RULE_INFO: DWORD = 8; +pub const CERT_CHAIN_AUTO_FLAGS_VALUE_NAME: &'static str = "AutoFlags"; +pub const CERT_CHAIN_AUTO_FLUSH_DISABLE_FLAG: DWORD = 0x00000001; +pub const CERT_CHAIN_AUTO_LOG_CREATE_FLAG: DWORD = 0x00000002; +pub const CERT_CHAIN_AUTO_LOG_FREE_FLAG: DWORD = 0x00000004; +pub const CERT_CHAIN_AUTO_LOG_FLUSH_FLAG: DWORD = 0x00000008; +pub const CERT_CHAIN_AUTO_LOG_FLAGS: DWORD = CERT_CHAIN_AUTO_LOG_CREATE_FLAG + | CERT_CHAIN_AUTO_LOG_FREE_FLAG | CERT_CHAIN_AUTO_LOG_FLUSH_FLAG; +pub const CERT_CHAIN_AUTO_FLUSH_FIRST_DELTA_SECONDS_VALUE_NAME: &'static str + = "AutoFlushFirstDeltaSeconds"; +pub const CERT_CHAIN_AUTO_FLUSH_FIRST_DELTA_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CERT_CHAIN_AUTO_FLUSH_NEXT_DELTA_SECONDS_VALUE_NAME: &'static str + = "AutoFlushNextDeltaSeconds"; +pub const CERT_CHAIN_AUTO_FLUSH_NEXT_DELTA_SECONDS_DEFAULT: DWORD = 30 * 60; +pub const CERT_CHAIN_AUTO_LOG_FILE_NAME_VALUE_NAME: &'static str = "AutoLogFileName"; +pub const CERT_CHAIN_DISABLE_AUTO_FLUSH_PROCESS_NAME_LIST_VALUE_NAME: &'static str + = "DisableAutoFlushProcessNameList"; +pub const CERT_SRV_OCSP_RESP_MIN_VALIDITY_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMinValiditySeconds"; +pub const CERT_SRV_OCSP_RESP_MIN_VALIDITY_SECONDS_DEFAULT: DWORD = 10 * 60; +pub const CERT_SRV_OCSP_RESP_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_VALUE_NAME: &'static str + = "SrvOcspRespUrlRetrievalTimeoutMilliseconds"; +pub const CERT_SRV_OCSP_RESP_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_DEFAULT: DWORD = 15 * 1000; +pub const CERT_SRV_OCSP_RESP_MAX_BEFORE_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMaxBeforeNextUpdateSeconds"; +pub const CERT_SRV_OCSP_RESP_MAX_BEFORE_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 4 * 60 * 60; +pub const CERT_SRV_OCSP_RESP_MIN_BEFORE_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMinBeforeNextUpdateSeconds"; +pub const CERT_SRV_OCSP_RESP_MIN_BEFORE_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 2 * 60; +pub const CERT_SRV_OCSP_RESP_MIN_AFTER_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMinAfterNextUpdateSeconds"; +pub const CERT_SRV_OCSP_RESP_MIN_AFTER_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 1 * 60; +pub const CERT_SRV_OCSP_RESP_MIN_SYNC_CERT_FILE_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMinSyncCertFileSeconds"; +pub const CERT_SRV_OCSP_RESP_MIN_SYNC_CERT_FILE_SECONDS_DEFAULT: DWORD = 5; +pub const CERT_SRV_OCSP_RESP_MAX_SYNC_CERT_FILE_SECONDS_VALUE_NAME: &'static str + = "SrvOcspRespMaxSyncCertFileSeconds"; +pub const CERT_SRV_OCSP_RESP_MAX_SYNC_CERT_FILE_SECONDS_DEFAULT: DWORD = 1 * 60 * 60; +pub const CRYPTNET_MAX_CACHED_OCSP_PER_CRL_COUNT_VALUE_NAME: &'static str + = "CryptnetMaxCachedOcspPerCrlCount"; +pub const CRYPTNET_MAX_CACHED_OCSP_PER_CRL_COUNT_DEFAULT: DWORD = 500; +pub const CRYPTNET_OCSP_AFTER_CRL_DISABLE: DWORD = 0xFFFFFFFF; +pub const CRYPTNET_URL_CACHE_DEFAULT_FLUSH_EXEMPT_SECONDS_VALUE_NAME: &'static str + = "CryptnetDefaultFlushExemptSeconds"; +pub const CRYPTNET_URL_CACHE_DEFAULT_FLUSH_EXEMPT_SECONDS_DEFAULT: DWORD = 28 * 24 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_MIN_MAX_AGE_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchMinMaxAgeSeconds"; +pub const CRYPTNET_PRE_FETCH_MIN_MAX_AGE_SECONDS_DEFAULT: DWORD = 1 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_MAX_MAX_AGE_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchMaxMaxAgeSeconds"; +pub const CRYPTNET_PRE_FETCH_MAX_MAX_AGE_SECONDS_DEFAULT: DWORD = 14 * 24 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_MIN_OCSP_VALIDITY_PERIOD_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchMinOcspValidityPeriodSeconds"; +pub const CRYPTNET_PRE_FETCH_MIN_OCSP_VALIDITY_PERIOD_SECONDS_DEFAULT: DWORD = 14 * 24 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_AFTER_PUBLISH_PRE_FETCH_DIVISOR_VALUE_NAME: &'static str + = "CryptnetPreFetchAfterPublishPreFetchDivisor"; +pub const CRYPTNET_PRE_FETCH_AFTER_PUBLISH_PRE_FETCH_DIVISOR_DEFAULT: DWORD = 10; +pub const CRYPTNET_PRE_FETCH_BEFORE_NEXT_UPDATE_PRE_FETCH_DIVISOR_VALUE_NAME: &'static str + = "CryptnetPreFetchBeforeNextUpdatePreFetchDivisor"; +pub const CRYPTNET_PRE_FETCH_BEFORE_NEXT_UPDATE_PRE_FETCH_DIVISOR_DEFAULT: DWORD = 20; +pub const CRYPTNET_PRE_FETCH_MIN_BEFORE_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_VALUE_NAME: + &'static str = "CryptnetPreFetchMinBeforeNextUpdatePreFetchSeconds"; +pub const CRYPTNET_PRE_FETCH_MIN_BEFORE_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_DEFAULT: DWORD + = 1 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_VALIDITY_PERIOD_AFTER_NEXT_UPDATE_PRE_FETCH_DIVISOR_VALUE_NAME: + &'static str = "CryptnetPreFetchValidityPeriodAfterNextUpdatePreFetchDivisor"; +pub const CRYPTNET_PRE_FETCH_VALIDITY_PERIOD_AFTER_NEXT_UPDATE_PRE_FETCH_DIVISOR_DEFAULT: DWORD + = 10; +pub const CRYPTNET_PRE_FETCH_MAX_AFTER_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_VALUE_NAME: + &'static str = "CryptnetPreFetchMaxAfterNextUpdatePreFetchPeriodSeconds"; +pub const CRYPTNET_PRE_FETCH_MAX_AFTER_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_DEFAULT: DWORD + = 4 * 60 * 60; +pub const CRYPTNET_PRE_FETCH_MIN_AFTER_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_VALUE_NAME: + &'static str = "CryptnetPreFetchMinAfterNextUpdatePreFetchPeriodSeconds"; +pub const CRYPTNET_PRE_FETCH_MIN_AFTER_NEXT_UPDATE_PRE_FETCH_PERIOD_SECONDS_DEFAULT: DWORD + = 30 * 60; +pub const CRYPTNET_PRE_FETCH_AFTER_CURRENT_TIME_PRE_FETCH_PERIOD_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchAfterCurrentTimePreFetchPeriodSeconds"; +pub const CRYPTNET_PRE_FETCH_AFTER_CURRENT_TIME_PRE_FETCH_PERIOD_SECONDS_DEFAULT: DWORD + = 30 * 60; +pub const CRYPTNET_PRE_FETCH_TRIGGER_PERIOD_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchTriggerPeriodSeconds"; +pub const CRYPTNET_PRE_FETCH_TRIGGER_PERIOD_SECONDS_DEFAULT: DWORD = 10 * 60; +pub const CRYPTNET_PRE_FETCH_TRIGGER_DISABLE: DWORD = 0xFFFFFFFF; +pub const CRYPTNET_PRE_FETCH_SCAN_AFTER_TRIGGER_DELAY_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchScanAfterTriggerDelaySeconds"; +pub const CRYPTNET_PRE_FETCH_SCAN_AFTER_TRIGGER_DELAY_SECONDS_DEFAULT: DWORD = 60; +pub const CRYPTNET_PRE_FETCH_RETRIEVAL_TIMEOUT_SECONDS_VALUE_NAME: &'static str + = "CryptnetPreFetchRetrievalTimeoutSeconds"; +pub const CRYPTNET_PRE_FETCH_RETRIEVAL_TIMEOUT_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_CONFIG_REGPATH: &'static str + = "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CertDllCreateCertificateChainEngine\\Config\\CrlPreFetch"; +pub const CRYPTNET_CRL_PRE_FETCH_PROCESS_NAME_LIST_VALUE_NAME: &'static str = "ProcessNameList"; +pub const CRYPTNET_CRL_PRE_FETCH_URL_LIST_VALUE_NAME: &'static str = "PreFetchUrlList"; +pub const CRYPTNET_CRL_PRE_FETCH_DISABLE_INFORMATION_EVENTS_VALUE_NAME: &'static str + = "DisableInformationEvents"; +pub const CRYPTNET_CRL_PRE_FETCH_LOG_FILE_NAME_VALUE_NAME: &'static str = "LogFileName"; +pub const CRYPTNET_CRL_PRE_FETCH_TIMEOUT_SECONDS_VALUE_NAME: &'static str = "TimeoutSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_TIMEOUT_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_MAX_AGE_SECONDS_VALUE_NAME: &'static str = "MaxAgeSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_MAX_AGE_SECONDS_DEFAULT: DWORD = 2 * 60 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_MAX_AGE_SECONDS_MIN: DWORD = 5 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_PUBLISH_BEFORE_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "PublishBeforeNextUpdateSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_PUBLISH_BEFORE_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 1 * 60 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_PUBLISH_RANDOM_INTERVAL_SECONDS_VALUE_NAME: &'static str + = "PublishRandomIntervalSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_PUBLISH_RANDOM_INTERVAL_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_MIN_BEFORE_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "MinBeforeNextUpdateSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_MIN_BEFORE_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CRYPTNET_CRL_PRE_FETCH_MIN_AFTER_NEXT_UPDATE_SECONDS_VALUE_NAME: &'static str + = "MinAfterNextUpdateSeconds"; +pub const CRYPTNET_CRL_PRE_FETCH_MIN_AFTER_NEXT_UPDATE_SECONDS_DEFAULT: DWORD = 5 * 60; +pub const CERT_GROUP_POLICY_CHAIN_CONFIG_REGPATH: &'static str + = "Software\\Policies\\Microsoft\\SystemCertificates\\ChainEngine\\Config"; +pub const CERT_CHAIN_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_VALUE_NAME: &'static str + = "ChainUrlRetrievalTimeoutMilliseconds"; +pub const CERT_CHAIN_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_DEFAULT: DWORD = 15 * 1000; +pub const CERT_CHAIN_REV_ACCUMULATIVE_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_VALUE_NAME: &'static str + = "ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds"; +pub const CERT_CHAIN_REV_ACCUMULATIVE_URL_RETRIEVAL_TIMEOUT_MILLISECONDS_DEFAULT: DWORD + = 20 * 1000; +pub const CERT_RETR_BEHAVIOR_INET_AUTH_VALUE_NAME: &'static str = "EnableInetUnknownAuth"; +pub const CERT_RETR_BEHAVIOR_INET_STATUS_VALUE_NAME: &'static str = "EnableInetLocal"; +pub const CERT_RETR_BEHAVIOR_FILE_VALUE_NAME: &'static str = "AllowFileUrlScheme"; +pub const CERT_RETR_BEHAVIOR_LDAP_VALUE_NAME: &'static str = "DisableLDAPSignAndEncrypt"; +pub const CRYPTNET_CACHED_OCSP_SWITCH_TO_CRL_COUNT_VALUE_NAME: &'static str + = "CryptnetCachedOcspSwitchToCrlCount"; +pub const CRYPTNET_CACHED_OCSP_SWITCH_TO_CRL_COUNT_DEFAULT: DWORD = 50; +pub const CRYPTNET_CRL_BEFORE_OCSP_ENABLE: DWORD = 0xFFFFFFFF; +pub const CERT_CHAIN_DISABLE_AIA_URL_RETRIEVAL_VALUE_NAME: &'static str = "DisableAIAUrlRetrieval"; +pub const CERT_CHAIN_OPTIONS_VALUE_NAME: &'static str = "Options"; +pub const CERT_CHAIN_OPTION_DISABLE_AIA_URL_RETRIEVAL: DWORD = 0x2; +pub const CERT_CHAIN_OPTION_ENABLE_SIA_URL_RETRIEVAL: DWORD = 0x4; +pub const CERT_CHAIN_CROSS_CERT_DOWNLOAD_INTERVAL_HOURS_VALUE_NAME: &'static str + = "CrossCertDownloadIntervalHours"; +pub const CERT_CHAIN_CROSS_CERT_DOWNLOAD_INTERVAL_HOURS_DEFAULT: DWORD = 24 * 7; +pub const CERT_CHAIN_CRL_VALIDITY_EXT_PERIOD_HOURS_VALUE_NAME: &'static str + = "CRLValidityExtensionPeriod"; +pub const CERT_CHAIN_CRL_VALIDITY_EXT_PERIOD_HOURS_DEFAULT: DWORD = 12; +pub type HCERTCHAINENGINE = HANDLE; +pub const HCCE_CURRENT_USER: HCERTCHAINENGINE = 0 as HCERTCHAINENGINE; +pub const HCCE_LOCAL_MACHINE: HCERTCHAINENGINE = 0x1 as HCERTCHAINENGINE; +pub const HCCE_SERIAL_LOCAL_MACHINE: HCERTCHAINENGINE = 0x2 as HCERTCHAINENGINE; +pub const CERT_CHAIN_CACHE_END_CERT: DWORD = 0x00000001; +pub const CERT_CHAIN_THREAD_STORE_SYNC: DWORD = 0x00000002; +pub const CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL: DWORD = 0x00000004; +pub const CERT_CHAIN_USE_LOCAL_MACHINE_STORE: DWORD = 0x00000008; +pub const CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE: DWORD = 0x00000010; +pub const CERT_CHAIN_ENABLE_SHARE_STORE: DWORD = 0x00000020; +STRUCT!{struct CERT_CHAIN_ENGINE_CONFIG { + cbSize: DWORD, + hRestrictedRoot: HCERTSTORE, + hRestrictedTrust: HCERTSTORE, + hRestrictedOther: HCERTSTORE, + cAdditionalStore: DWORD, + rghAdditionalStore: *mut HCERTSTORE, + dwFlags: DWORD, + dwUrlRetrievalTimeout: DWORD, + MaximumCachedCertificates: DWORD, + CycleDetectionModulus: DWORD, + hExclusiveRoot: HCERTSTORE, + hExclusiveTrustedPeople: HCERTSTORE, + dwExclusiveFlags: DWORD, +}} +pub type PCERT_CHAIN_ENGINE_CONFIG = *mut CERT_CHAIN_ENGINE_CONFIG; +extern "system" { + pub fn CertCreateCertificateChainEngine( + pConfig: PCERT_CHAIN_ENGINE_CONFIG, + phChainEngine: *mut HCERTCHAINENGINE, + ) -> BOOL; + pub fn CertFreeCertificateChainEngine( + hChainEngine: HCERTCHAINENGINE, + ); + pub fn CertResyncCertificateChainEngine( + hChainEngine: HCERTCHAINENGINE, + ) -> BOOL; +} +STRUCT!{struct CERT_TRUST_STATUS { + dwErrorStatus: DWORD, + dwInfoStatus: DWORD, +}} +pub type PCERT_TRUST_STATUS = *mut CERT_TRUST_STATUS; +pub const CERT_TRUST_NO_ERROR: DWORD = 0x00000000; +pub const CERT_TRUST_IS_NOT_TIME_VALID: DWORD = 0x00000001; +pub const CERT_TRUST_IS_NOT_TIME_NESTED: DWORD = 0x00000002; +pub const CERT_TRUST_IS_REVOKED: DWORD = 0x00000004; +pub const CERT_TRUST_IS_NOT_SIGNATURE_VALID: DWORD = 0x00000008; +pub const CERT_TRUST_IS_NOT_VALID_FOR_USAGE: DWORD = 0x00000010; +pub const CERT_TRUST_IS_UNTRUSTED_ROOT: DWORD = 0x00000020; +pub const CERT_TRUST_REVOCATION_STATUS_UNKNOWN: DWORD = 0x00000040; +pub const CERT_TRUST_IS_CYCLIC: DWORD = 0x00000080; +pub const CERT_TRUST_INVALID_EXTENSION: DWORD = 0x00000100; +pub const CERT_TRUST_INVALID_POLICY_CONSTRAINTS: DWORD = 0x00000200; +pub const CERT_TRUST_INVALID_BASIC_CONSTRAINTS: DWORD = 0x00000400; +pub const CERT_TRUST_INVALID_NAME_CONSTRAINTS: DWORD = 0x00000800; +pub const CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT: DWORD = 0x00001000; +pub const CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT: DWORD = 0x00002000; +pub const CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT: DWORD = 0x00004000; +pub const CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT: DWORD = 0x00008000; +pub const CERT_TRUST_IS_OFFLINE_REVOCATION: DWORD = 0x01000000; +pub const CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY: DWORD = 0x02000000; +pub const CERT_TRUST_IS_PARTIAL_CHAIN: DWORD = 0x00010000; +pub const CERT_TRUST_CTL_IS_NOT_TIME_VALID: DWORD = 0x00020000; +pub const CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID: DWORD = 0x00040000; +pub const CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE: DWORD = 0x00080000; +pub const CERT_TRUST_HAS_EXACT_MATCH_ISSUER: DWORD = 0x00000001; +pub const CERT_TRUST_HAS_KEY_MATCH_ISSUER: DWORD = 0x00000002; +pub const CERT_TRUST_HAS_NAME_MATCH_ISSUER: DWORD = 0x00000004; +pub const CERT_TRUST_IS_SELF_SIGNED: DWORD = 0x00000008; +pub const CERT_TRUST_AUTO_UPDATE_CA_REVOCATION: DWORD = 0x00000010; +pub const CERT_TRUST_AUTO_UPDATE_END_REVOCATION: DWORD = 0x00000020; +pub const CERT_TRUST_NO_OCSP_FAILOVER_TO_CRL: DWORD = 0x00000040; +pub const CERT_TRUST_IS_KEY_ROLLOVER: DWORD = 0x00000080; +pub const CERT_TRUST_SSL_HANDSHAKE_OCSP: DWORD = 0x00040000; +pub const CERT_TRUST_SSL_TIME_VALID_OCSP: DWORD = 0x00080000; +pub const CERT_TRUST_SSL_RECONNECT_OCSP: DWORD = 0x00100000; +pub const CERT_TRUST_HAS_PREFERRED_ISSUER: DWORD = 0x00000100; +pub const CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY: DWORD = 0x00000200; +pub const CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS: DWORD = 0x00000400; +pub const CERT_TRUST_IS_PEER_TRUSTED: DWORD = 0x00000800; +pub const CERT_TRUST_HAS_CRL_VALIDITY_EXTENDED: DWORD = 0x00001000; +pub const CERT_TRUST_IS_FROM_EXCLUSIVE_TRUST_STORE: DWORD = 0x00002000; +pub const CERT_TRUST_IS_CA_TRUSTED: DWORD = 0x00004000; +pub const CERT_TRUST_HAS_AUTO_UPDATE_WEAK_SIGNATURE: DWORD = 0x00008000; +pub const CERT_TRUST_HAS_ALLOW_WEAK_SIGNATURE: DWORD = 0x00020000; +pub const CERT_TRUST_IS_COMPLEX_CHAIN: DWORD = 0x00010000; +pub const CERT_TRUST_SSL_TIME_VALID: DWORD = 0x01000000; +pub const CERT_TRUST_NO_TIME_CHECK: DWORD = 0x02000000; +STRUCT!{struct CERT_REVOCATION_INFO { + cbSize: DWORD, + dwRevocationResult: DWORD, + pszRevocationOid: LPCSTR, + pvOidSpecificInfo: LPVOID, + fHasFreshnessTime: BOOL, + dwFreshnessTime: DWORD, + pCrlInfo: PCERT_REVOCATION_CRL_INFO, +}} +pub type PCERT_REVOCATION_INFO = *mut CERT_REVOCATION_INFO; +STRUCT!{struct CERT_TRUST_LIST_INFO { + cbSize: DWORD, + pCtlEntry: PCTL_ENTRY, + pCtlContext: PCCTL_CONTEXT, +}} +pub type PCERT_TRUST_LIST_INFO = *mut CERT_TRUST_LIST_INFO; +STRUCT!{struct CERT_CHAIN_ELEMENT { + cbSize: DWORD, + pCertContext: PCCERT_CONTEXT, + TrustStatus: CERT_TRUST_STATUS, + pRevocationInfo: PCERT_REVOCATION_INFO, + pIssuanceUsage: PCERT_ENHKEY_USAGE, + pApplicationUsage: PCERT_ENHKEY_USAGE, + pwszExtendedErrorInfo: LPWSTR, +}} +pub type PCERT_CHAIN_ELEMENT = *mut CERT_CHAIN_ELEMENT; +pub type PCCERT_CHAIN_ELEMENT = *const CERT_CHAIN_ELEMENT; +STRUCT!{struct CERT_SIMPLE_CHAIN { + cbSize: DWORD, + TrustStatus: CERT_TRUST_STATUS, + cElement: DWORD, + rgpElement: *mut PCERT_CHAIN_ELEMENT, + pTrustListInfo: PCERT_TRUST_LIST_INFO, + fHasRevocationFreshnessTime: BOOL, + dwRevocationFreshnessTime: DWORD, +}} +pub type PCERT_SIMPLE_CHAIN = *mut CERT_SIMPLE_CHAIN; +pub type PCCERT_SIMPLE_CHAIN = *const CERT_SIMPLE_CHAIN; +pub type PCERT_CHAIN_CONTEXT = *mut CERT_CHAIN_CONTEXT; +pub type PCCERT_CHAIN_CONTEXT = *const CERT_CHAIN_CONTEXT; +STRUCT!{struct CERT_CHAIN_CONTEXT { + cbSize: DWORD, + TrustStatus: CERT_TRUST_STATUS, + cChain: DWORD, + rgpChain: *mut PCERT_SIMPLE_CHAIN, + cLowerQualityChainContext: DWORD, + rgpLowerQualityChainContext: *mut PCCERT_CHAIN_CONTEXT, + fHasRevocationFreshnessTime: BOOL, + dwRevocationFreshnessTime: DWORD, + dwCreateFlags: DWORD, + ChainId: GUID, +}} +pub const USAGE_MATCH_TYPE_AND: DWORD = 0x00000000; +pub const USAGE_MATCH_TYPE_OR: DWORD = 0x00000001; +STRUCT!{struct CERT_USAGE_MATCH { + dwType: DWORD, + Usage: CERT_ENHKEY_USAGE, +}} +pub type PCERT_USAGE_MATCH = *mut CERT_USAGE_MATCH; +STRUCT!{struct CTL_USAGE_MATCH { + dwType: DWORD, + Usage: CTL_USAGE, +}} +pub type PCTL_USAGE_MATCH = *mut CTL_USAGE_MATCH; +STRUCT!{struct CERT_CHAIN_PARA { + cbSize: DWORD, + RequestedUsage: CERT_USAGE_MATCH, + RequestedIssuancePolicy: CERT_USAGE_MATCH, + dwUrlRetrievalTimeout: DWORD, + fCheckRevocationFreshnessTime: BOOL, + dwRevocationFreshnessTime: DWORD, + pftCacheResync: LPFILETIME, + pStrongSignPara: PCCERT_STRONG_SIGN_PARA, + dwStrongSignFlags: DWORD, +}} +pub type PCERT_CHAIN_PARA = *mut CERT_CHAIN_PARA; +pub const CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG: DWORD = 0x00000001; +pub const CERT_CHAIN_REVOCATION_CHECK_END_CERT: DWORD = 0x10000000; +pub const CERT_CHAIN_REVOCATION_CHECK_CHAIN: DWORD = 0x20000000; +pub const CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT: DWORD = 0x40000000; +pub const CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY: DWORD = 0x80000000; +pub const CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT: DWORD = 0x08000000; +pub const CERT_CHAIN_REVOCATION_CHECK_OCSP_CERT: DWORD = 0x04000000; +pub const CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING: DWORD = 0x00000040; +pub const CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS: DWORD = 0x00000080; +pub const CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE: DWORD = 0x00000100; +pub const CERT_CHAIN_TIMESTAMP_TIME: DWORD = 0x00000200; +pub const CERT_CHAIN_ENABLE_PEER_TRUST: DWORD = 0x00000400; +pub const CERT_CHAIN_DISABLE_MY_PEER_TRUST: DWORD = 0x00000800; +pub const CERT_CHAIN_DISABLE_MD2_MD4: DWORD = 0x00001000; +pub const CERT_CHAIN_DISABLE_AIA: DWORD = 0x00002000; +pub const CERT_CHAIN_HAS_MOTW: DWORD = 0x00004000; +pub const CERT_CHAIN_ONLY_ADDITIONAL_AND_AUTH_ROOT: DWORD = 0x00008000; +pub const CERT_CHAIN_OPT_IN_WEAK_SIGNATURE: DWORD = 0x00010000; +extern "system" { + pub fn CertGetCertificateChain( + hChainEngine: HCERTCHAINENGINE, + pCertContext: PCCERT_CONTEXT, + pTime: LPFILETIME, + hAdditionalStore: HCERTSTORE, + pChainPara: PCERT_CHAIN_PARA, + dwFlags: DWORD, + pvReserved: LPVOID, + ppChainContext: *mut PCCERT_CHAIN_CONTEXT, + ) -> BOOL; + pub fn CertFreeCertificateChain( + pChainContext: PCCERT_CHAIN_CONTEXT, + ); + pub fn CertDuplicateCertificateChain( + pChainContext: PCCERT_CHAIN_CONTEXT, + ) -> PCCERT_CHAIN_CONTEXT; +} +STRUCT!{struct CERT_REVOCATION_CHAIN_PARA { + cbSize: DWORD, + hChainEngine: HCERTCHAINENGINE, + hAdditionalStore: HCERTSTORE, + dwChainFlags: DWORD, + dwUrlRetrievalTimeout: DWORD, + pftCurrentTime: LPFILETIME, + pftCacheResync: LPFILETIME, + cbMaxUrlRetrievalByteCount: DWORD, +}} +pub const REVOCATION_OID_CRL_REVOCATION: LPCSTR = 1 as LPCSTR; +STRUCT!{struct CRL_REVOCATION_INFO { + pCrlEntry: PCRL_ENTRY, + pCrlContext: PCCRL_CONTEXT, + pCrlIssuerChain: PCCERT_CHAIN_CONTEXT, +}} +pub type PCRL_REVOCATION_INFO = *mut CRL_REVOCATION_INFO; +extern "system" { + pub fn CertFindChainInStore( + hCertStore: HCERTSTORE, + dwCertEncodingType: DWORD, + dwFindFlags: DWORD, + dwFindType: DWORD, + pvFindPara: *const c_void, + pPrevChainContext: PCCERT_CHAIN_CONTEXT, + ) -> PCCERT_CHAIN_CONTEXT; +} +pub const CERT_CHAIN_FIND_BY_ISSUER: DWORD = 1; +FN!{stdcall PFN_CERT_CHAIN_FIND_BY_ISSUER_CALLBACK( + pCert: PCCERT_CONTEXT, + pvFindArg: *mut c_void, +) -> BOOL} +STRUCT!{struct CERT_CHAIN_FIND_ISSUER_PARA { + cbSize: DWORD, + pszUsageIdentifier: LPCSTR, + dwKeySpec: DWORD, + dwAcquirePrivateKeyFlags: DWORD, + cIssuer: DWORD, + rgIssuer: *mut CERT_NAME_BLOB, + pfnFindCallback: PFN_CERT_CHAIN_FIND_BY_ISSUER_CALLBACK, + pvFindArg: *mut c_void, + pdwIssuerChainIndex: *mut DWORD, + pdwIssuerElementIndex: *mut DWORD, +}} +pub type PCERT_CHAIN_FIND_ISSUER_PARA = *mut CERT_CHAIN_FIND_ISSUER_PARA; +pub type CERT_CHAIN_FIND_BY_ISSUER_PARA = CERT_CHAIN_FIND_ISSUER_PARA; +pub type PCERT_CHAIN_FIND_BY_ISSUER_PARA = *mut CERT_CHAIN_FIND_ISSUER_PARA; +pub const CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG: DWORD = 0x0001; +pub const CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG: DWORD = 0x0002; +pub const CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG: DWORD = 0x0004; +pub const CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG: DWORD = 0x0008; +pub const CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG: DWORD = 0x4000; +pub const CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG: DWORD = 0x8000; +STRUCT!{struct CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwFlags: DWORD, + pvExtraPolicyPara: *mut c_void, +}} +pub type PCERT_CHAIN_POLICY_PARA = *mut CERT_CHAIN_POLICY_PARA; +STRUCT!{struct CERT_CHAIN_POLICY_STATUS { + cbSize: DWORD, + dwError: DWORD, + lChainIndex: LONG, + lElementIndex: LONG, + pvExtraPolicyStatus: *mut c_void, +}} +pub type PCERT_CHAIN_POLICY_STATUS = *mut CERT_CHAIN_POLICY_STATUS; +pub const CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG: DWORD = 0x00000001; +pub const CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG: DWORD = 0x00000002; +pub const CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG: DWORD = 0x00000004; +pub const CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG: DWORD = 0x00000008; +pub const CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS: DWORD + = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG + | CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG + | CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; +pub const CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG: DWORD = 0x00000010; +pub const CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG: DWORD = 0x00000020; +pub const CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG: DWORD = 0x00000040; +pub const CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG: DWORD = 0x00000080; +pub const CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG: DWORD = 0x00000100; +pub const CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG: DWORD = 0x00000200; +pub const CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG: DWORD = 0x00000400; +pub const CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG: DWORD = 0x00000800; +pub const CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS: DWORD + = CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG + | CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG + | CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG + | CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG; +pub const CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG: DWORD = 0x00008000; +pub const CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG: DWORD = 0x00004000; +pub const CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG: DWORD = 0x00002000; +pub const CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG: DWORD = 0x00001000; +pub const CERT_CHAIN_POLICY_IGNORE_WEAK_SIGNATURE_FLAG: DWORD = 0x08000000; +extern "system" { + pub fn CertVerifyCertificateChainPolicy( + pszPolicyOID: LPCSTR, + pChainContext: PCCERT_CHAIN_CONTEXT, + pPolicyPara: PCERT_CHAIN_POLICY_PARA, + pPolicyStatus: PCERT_CHAIN_POLICY_STATUS, + ) -> BOOL; +} +pub const CRYPT_OID_VERIFY_CERTIFICATE_CHAIN_POLICY_FUNC: &'static str + = "CertDllVerifyCertificateChainPolicy"; +pub const CERT_CHAIN_POLICY_BASE: LPCSTR = 1 as LPCSTR; +pub const CERT_CHAIN_POLICY_AUTHENTICODE: LPCSTR = 2 as LPCSTR; +pub const CERT_CHAIN_POLICY_AUTHENTICODE_TS: LPCSTR = 3 as LPCSTR; +pub const CERT_CHAIN_POLICY_SSL: LPCSTR = 4 as LPCSTR; +pub const CERT_CHAIN_POLICY_BASIC_CONSTRAINTS: LPCSTR = 5 as LPCSTR; +pub const CERT_CHAIN_POLICY_NT_AUTH: LPCSTR = 6 as LPCSTR; +pub const CERT_CHAIN_POLICY_MICROSOFT_ROOT: LPCSTR = 7 as LPCSTR; +pub const CERT_CHAIN_POLICY_EV: LPCSTR = 8 as LPCSTR; +pub const CERT_CHAIN_POLICY_SSL_F12: LPCSTR = 9 as LPCSTR; +pub const CERT_CHAIN_POLICY_SSL_HPKP_HEADER: LPCSTR = 10 as LPCSTR; +pub const CERT_CHAIN_POLICY_THIRD_PARTY_ROOT: LPCSTR = 11 as LPCSTR; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN: LPCSTR = 12 as LPCSTR; +STRUCT!{struct AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwRegPolicySettings: DWORD, + pSignerInfo: PCMSG_SIGNER_INFO, +}} +pub type PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA + = *mut AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA; +STRUCT!{struct AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS { + cbSize: DWORD, + fCommercial: BOOL, +}} +pub type PAUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS + = *mut AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS; +STRUCT!{struct AUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwRegPolicySettings: DWORD, + fCommercial: BOOL, +}} +pub type PAUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA + = *mut AUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA; +UNION!{union HTTPSPolicyCallbackData_u { + [u32; 1], + cbStruct cbStruct_mut: DWORD, + cbSize cbSize_mut: DWORD, +}} +STRUCT!{struct HTTPSPolicyCallbackData { + u: HTTPSPolicyCallbackData_u, + dwAuthType: DWORD, + fdwChecks: DWORD, + pwszServerName: *mut WCHAR, +}} +pub type PHTTPSPolicyCallbackData = *mut HTTPSPolicyCallbackData; +pub type SSL_EXTRA_CERT_CHAIN_POLICY_PARA = HTTPSPolicyCallbackData; +pub type PSSL_EXTRA_CERT_CHAIN_POLICY_PARA = *mut HTTPSPolicyCallbackData; +pub const AUTHTYPE_CLIENT: DWORD = 1; +pub const AUTHTYPE_SERVER: DWORD = 2; +pub const BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG: DWORD = 0x80000000; +pub const BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG: DWORD = 0x40000000; +pub const MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG: DWORD = 0x00010000; +pub const MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG: DWORD = 0x00020000; +pub const MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG: DWORD = 0x00040000; +STRUCT!{struct EV_EXTRA_CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwRootProgramQualifierFlags: DWORD, +}} +pub type PEV_EXTRA_CERT_CHAIN_POLICY_PARA = *mut EV_EXTRA_CERT_CHAIN_POLICY_PARA; +STRUCT!{struct EV_EXTRA_CERT_CHAIN_POLICY_STATUS { + cbSize: DWORD, + dwQualifiers: DWORD, + dwIssuanceUsageIndex: DWORD, +}} +pub type PEV_EXTRA_CERT_CHAIN_POLICY_STATUS = *mut EV_EXTRA_CERT_CHAIN_POLICY_STATUS; +pub const SSL_F12_ERROR_TEXT_LENGTH: usize = 256; +STRUCT!{struct SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS { + cbSize: DWORD, + dwErrorLevel: DWORD, + dwErrorCategory: DWORD, + dwReserved: DWORD, + wszErrorText: [WCHAR; SSL_F12_ERROR_TEXT_LENGTH], +}} +pub type PSSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS = *mut SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS; +pub const CERT_CHAIN_POLICY_SSL_F12_SUCCESS_LEVEL: DWORD = 0; +pub const CERT_CHAIN_POLICY_SSL_F12_WARNING_LEVEL: DWORD = 1; +pub const CERT_CHAIN_POLICY_SSL_F12_ERROR_LEVEL: DWORD = 2; +pub const CERT_CHAIN_POLICY_SSL_F12_NONE_CATEGORY: DWORD = 0; +pub const CERT_CHAIN_POLICY_SSL_F12_WEAK_CRYPTO_CATEGORY: DWORD = 1; +pub const CERT_CHAIN_POLICY_SSL_F12_ROOT_PROGRAM_CATEGORY: DWORD = 2; +pub const SSL_HPKP_PKP_HEADER_INDEX: usize = 0; +pub const SSL_HPKP_PKP_RO_HEADER_INDEX: usize = 1; +pub const SSL_HPKP_HEADER_COUNT: usize = 2; +STRUCT!{struct SSL_HPKP_HEADER_EXTRA_CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwReserved: DWORD, + pwszServerName: LPWSTR, + rgpszHpkpValue: [LPSTR; SSL_HPKP_HEADER_COUNT], +}} +pub type PSSL_HPKP_HEADER_EXTRA_CERT_CHAIN_POLICY_PARA + = *mut SSL_HPKP_HEADER_EXTRA_CERT_CHAIN_POLICY_PARA; +STRUCT!{struct SSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_PARA { + cbSize: DWORD, + dwReserved: DWORD, + pwszServerName: PCWSTR, +}} +pub type PSSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_PARA = *mut SSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_PARA; +pub const SSL_KEY_PIN_ERROR_TEXT_LENGTH: usize = 512; +STRUCT!{struct SSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_STATUS { + cbSize: DWORD, + lError: LONG, + wszErrorText: [WCHAR; SSL_KEY_PIN_ERROR_TEXT_LENGTH], +}} +pub type PSSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_STATUS + = *mut SSL_KEY_PIN_EXTRA_CERT_CHAIN_POLICY_STATUS; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN_MISMATCH_ERROR: LONG = -2; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN_MITM_ERROR: LONG = -1; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN_SUCCESS: LONG = 0; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN_MITM_WARNING: LONG = 1; +pub const CERT_CHAIN_POLICY_SSL_KEY_PIN_MISMATCH_WARNING: LONG = 2; +extern "system" { + pub fn CryptStringToBinaryA( + pszString: LPCSTR, + cchString: DWORD, + dwFlags: DWORD, + pbBinary: *mut BYTE, + pcbBinary: *mut DWORD, + pdwSkip: *mut DWORD, + pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CryptStringToBinaryW( + pszString: LPCWSTR, + cchString: DWORD, + dwFlags: DWORD, + pbBinary: *mut BYTE, + pcbBinary: *mut DWORD, + pdwSkip: *mut DWORD, + pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CryptBinaryToStringA( + pbBinary: *const BYTE, + cbBinary: DWORD, + dwFlags: DWORD, + pszString: LPSTR, + pcchString: *mut DWORD, + ) -> BOOL; + pub fn CryptBinaryToStringW( + pbBinary: *const BYTE, + cbBinary: DWORD, + dwFlags: DWORD, + pszString: LPWSTR, + pcchString: *mut DWORD, + ) -> BOOL; +} +pub const CRYPT_STRING_BASE64HEADER: DWORD = 0x00000000; +pub const CRYPT_STRING_BASE64: DWORD = 0x00000001; +pub const CRYPT_STRING_BINARY: DWORD = 0x00000002; +pub const CRYPT_STRING_BASE64REQUESTHEADER: DWORD = 0x00000003; +pub const CRYPT_STRING_HEX: DWORD = 0x00000004; +pub const CRYPT_STRING_HEXASCII: DWORD = 0x00000005; +pub const CRYPT_STRING_BASE64_ANY: DWORD = 0x00000006; +pub const CRYPT_STRING_ANY: DWORD = 0x00000007; +pub const CRYPT_STRING_HEX_ANY: DWORD = 0x00000008; +pub const CRYPT_STRING_BASE64X509CRLHEADER: DWORD = 0x00000009; +pub const CRYPT_STRING_HEXADDR: DWORD = 0x0000000a; +pub const CRYPT_STRING_HEXASCIIADDR: DWORD = 0x0000000b; +pub const CRYPT_STRING_HEXRAW: DWORD = 0x0000000c; +pub const CRYPT_STRING_BASE64URI: DWORD = 0x0000000d; +pub const CRYPT_STRING_ENCODEMASK: DWORD = 0x000000ff; +pub const CRYPT_STRING_RESERVED100: DWORD = 0x00000100; +pub const CRYPT_STRING_RESERVED200: DWORD = 0x00000200; +pub const CRYPT_STRING_PERCENTESCAPE: DWORD = 0x08000000; +pub const CRYPT_STRING_HASHDATA: DWORD = 0x10000000; +pub const CRYPT_STRING_STRICT: DWORD = 0x20000000; +pub const CRYPT_STRING_NOCRLF: DWORD = 0x40000000; +pub const CRYPT_STRING_NOCR: DWORD = 0x80000000; +pub const szOID_PKCS_12_PbeIds: &'static str = "1.2.840.113549.1.12.1"; +pub const szOID_PKCS_12_pbeWithSHA1And128BitRC4: &'static str = "1.2.840.113549.1.12.1.1"; +pub const szOID_PKCS_12_pbeWithSHA1And40BitRC4: &'static str = "1.2.840.113549.1.12.1.2"; +pub const szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES: &'static str = "1.2.840.113549.1.12.1.3"; +pub const szOID_PKCS_12_pbeWithSHA1And2KeyTripleDES: &'static str = "1.2.840.113549.1.12.1.4"; +pub const szOID_PKCS_12_pbeWithSHA1And128BitRC2: &'static str = "1.2.840.113549.1.12.1.5"; +pub const szOID_PKCS_12_pbeWithSHA1And40BitRC2: &'static str = "1.2.840.113549.1.12.1.6"; +STRUCT!{struct CRYPT_PKCS12_PBE_PARAMS { + iIterations: c_int, + cbSalt: ULONG, +}} +extern "system" { + pub fn PFXImportCertStore( + pPFX: *mut CRYPT_DATA_BLOB, + szPassword: LPCWSTR, + dwFlags: DWORD, + ) -> HCERTSTORE; +} +pub const PKCS12_IMPORT_SILENT: DWORD = 0x00000040; +pub const CRYPT_USER_KEYSET: DWORD = 0x00001000; +pub const PKCS12_PREFER_CNG_KSP: DWORD = 0x00000100; +pub const PKCS12_ALWAYS_CNG_KSP: DWORD = 0x00000200; +pub const PKCS12_ONLY_CERTIFICATES: DWORD = 0x00000400; +pub const PKCS12_ONLY_NOT_ENCRYPTED_CERTIFICATES: DWORD = 0x00000800; +pub const PKCS12_ALLOW_OVERWRITE_KEY: DWORD = 0x00004000; +pub const PKCS12_NO_PERSIST_KEY: DWORD = 0x00008000; +pub const PKCS12_IMPORT_RESERVED_MASK: DWORD = 0xffff0000; +pub const PKCS12_OBJECT_LOCATOR_ALL_IMPORT_FLAGS: DWORD = PKCS12_ALWAYS_CNG_KSP + | PKCS12_NO_PERSIST_KEY | PKCS12_IMPORT_SILENT | PKCS12_INCLUDE_EXTENDED_PROPERTIES; +pub const PKCS12_ONLY_CERTIFICATES_PROVIDER_TYPE: DWORD = 0; +pub const PKCS12_ONLY_CERTIFICATES_PROVIDER_NAME: &'static str = "PfxProvider"; +pub const PKCS12_ONLY_CERTIFICATES_CONTAINER_NAME: &'static str = "PfxContainer"; +extern "system" { + pub fn PFXIsPFXBlob( + pPFX: *mut CRYPT_DATA_BLOB, + ) -> BOOL; + pub fn PFXVerifyPassword( + pPFX: *mut CRYPT_DATA_BLOB, + szPassword: LPCWSTR, + dwFlags: DWORD, + ) -> BOOL; + pub fn PFXExportCertStoreEx( + hStore: HCERTSTORE, + pPFX: *mut CRYPT_DATA_BLOB, + szPassword: LPCWSTR, + pvPara: *mut c_void, + dwFlags: DWORD, + ) -> BOOL; +} +pub const REPORT_NO_PRIVATE_KEY: DWORD = 0x0001; +pub const REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY: DWORD = 0x0002; +pub const EXPORT_PRIVATE_KEYS: DWORD = 0x0004; +pub const PKCS12_INCLUDE_EXTENDED_PROPERTIES: DWORD = 0x0010; +pub const PKCS12_PROTECT_TO_DOMAIN_SIDS: DWORD = 0x0020; +pub const PKCS12_EXPORT_SILENT: DWORD = 0x0040; +pub const PKCS12_DISABLE_ENCRYPT_CERTIFICATES: DWORD = 0x0100; +pub const PKCS12_ENCRYPT_CERTIFICATES: DWORD = 0x0200; +pub const PKCS12_EXPORT_ECC_CURVE_PARAMETERS: DWORD = 0x1000; +pub const PKCS12_EXPORT_ECC_CURVE_OID: DWORD = 0x2000; +pub const PKCS12_EXPORT_RESERVED_MASK: DWORD = 0xffff0000; +pub const PKCS12_CONFIG_REGPATH: &'static str + = "Software\\Microsoft\\Windows\\CurrentVersion\\PFX"; +pub const PKCS12_ENCRYPT_CERTIFICATES_VALUE_NAME: &'static str = "EncryptCertificates"; +extern "system" { + pub fn PFXExportCertStore( + hStore: HCERTSTORE, + pPFX: *mut CRYPT_DATA_BLOB, + szPassword: LPCWSTR, + dwFlags: DWORD, + ) -> BOOL; +} +pub type HCERT_SERVER_OCSP_RESPONSE = *mut c_void; +pub type PCERT_SERVER_OCSP_RESPONSE_CONTEXT = *mut CERT_SERVER_OCSP_RESPONSE_CONTEXT; +pub type PCCERT_SERVER_OCSP_RESPONSE_CONTEXT = *const CERT_SERVER_OCSP_RESPONSE_CONTEXT; +STRUCT!{struct CERT_SERVER_OCSP_RESPONSE_CONTEXT { + cbSize: DWORD, + pbEncodedOcspResponse: *mut BYTE, + cbEncodedOcspResponse: DWORD, +}} +FN!{stdcall PFN_CERT_SERVER_OCSP_RESPONSE_UPDATE_CALLBACK( + pChainContext: PCCERT_CHAIN_CONTEXT, + pServerOcspResponseContext: PCCERT_SERVER_OCSP_RESPONSE_CONTEXT, + pNewCrlContext: PCCRL_CONTEXT, + pPrevCrlContext: PCCRL_CONTEXT, + pvArg: PVOID, + dwWriteOcspFileError: DWORD, +) -> ()} +STRUCT!{struct CERT_SERVER_OCSP_RESPONSE_OPEN_PARA { + cbSize: DWORD, + dwFlags: DWORD, + pcbUsedSize: *mut DWORD, + pwszOcspDirectory: PWSTR, + pfnUpdateCallback: PFN_CERT_SERVER_OCSP_RESPONSE_UPDATE_CALLBACK, + pvUpdateCallbackArg: PVOID, +}} +pub type PCERT_SERVER_OCSP_RESPONSE_OPEN_PARA = *mut CERT_SERVER_OCSP_RESPONSE_OPEN_PARA; +pub const CERT_SERVER_OCSP_RESPONSE_OPEN_PARA_READ_FLAG: DWORD = 0x00000001; +pub const CERT_SERVER_OCSP_RESPONSE_OPEN_PARA_WRITE_FLAG: DWORD = 0x00000002; +extern "system" { + pub fn CertOpenServerOcspResponse( + pChainContext: PCCERT_CHAIN_CONTEXT, + dwFlags: DWORD, + pvReserved: LPVOID, + ) -> HCERT_SERVER_OCSP_RESPONSE; +} +pub const CERT_SERVER_OCSP_RESPONSE_ASYNC_FLAG: DWORD = 0x00000001; +extern "system" { + pub fn CertAddRefServerOcspResponse( + hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE, + ); + pub fn CertCloseServerOcspResponse( + hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE, + dwFlags: DWORD, + ); + pub fn CertGetServerOcspResponseContext( + hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE, + dwFlags: DWORD, + pvReserved: LPVOID, + ) -> PCCERT_SERVER_OCSP_RESPONSE_CONTEXT; + pub fn CertAddRefServerOcspResponseContext( + pServerOcspResponseContext: PCCERT_SERVER_OCSP_RESPONSE_CONTEXT, + ); + pub fn CertFreeServerOcspResponseContext( + pServerOcspResponseContext: PCCERT_SERVER_OCSP_RESPONSE_CONTEXT, + ); + pub fn CertRetrieveLogoOrBiometricInfo( + pCertContext: PCCERT_CONTEXT, + lpszLogoOrBiometricType: LPCSTR, + dwRetrievalFlags: DWORD, + dwTimeout: DWORD, + dwFlags: DWORD, + pvReserved: *mut c_void, + ppbData: *mut *mut BYTE, + pcbData: *mut DWORD, + ppwszMimeType: *mut LPWSTR, + ) -> BOOL; +} +pub const CERT_RETRIEVE_ISSUER_LOGO: LPCSTR = 1 as LPCSTR; +pub const CERT_RETRIEVE_SUBJECT_LOGO: LPCSTR = 2 as LPCSTR; +pub const CERT_RETRIEVE_COMMUNITY_LOGO: LPCSTR = 3 as LPCSTR; +pub const CERT_RETRIEVE_BIOMETRIC_PREDEFINED_BASE_TYPE: LPCSTR = 1000 as LPCSTR; +pub const CERT_RETRIEVE_BIOMETRIC_PICTURE_TYPE: LPCSTR + = (1000 + CERT_BIOMETRIC_PICTURE_TYPE) as LPCSTR; +pub const CERT_RETRIEVE_BIOMETRIC_SIGNATURE_TYPE: LPCSTR + = (1000 + CERT_BIOMETRIC_SIGNATURE_TYPE) as LPCSTR; +STRUCT!{struct CERT_SELECT_CHAIN_PARA { + hChainEngine: HCERTCHAINENGINE, + pTime: PFILETIME, + hAdditionalStore: HCERTSTORE, + pChainPara: PCERT_CHAIN_PARA, + dwFlags: DWORD, +}} +pub type PCERT_SELECT_CHAIN_PARA = *mut CERT_SELECT_CHAIN_PARA; +pub type PCCERT_SELECT_CHAIN_PARA = *const CERT_SELECT_CHAIN_PARA; +pub const CERT_SELECT_MAX_PARA: DWORD = 500; +STRUCT!{struct CERT_SELECT_CRITERIA { + dwType: DWORD, + cPara: DWORD, + ppPara: *mut *mut c_void, +}} +pub type PCERT_SELECT_CRITERIA = *mut CERT_SELECT_CRITERIA; +pub type PCCERT_SELECT_CRITERIA = *const CERT_SELECT_CRITERIA; +pub const CERT_SELECT_BY_ENHKEY_USAGE: DWORD = 1; +pub const CERT_SELECT_BY_KEY_USAGE: DWORD = 2; +pub const CERT_SELECT_BY_POLICY_OID: DWORD = 3; +pub const CERT_SELECT_BY_PROV_NAME: DWORD = 4; +pub const CERT_SELECT_BY_EXTENSION: DWORD = 5; +pub const CERT_SELECT_BY_SUBJECT_HOST_NAME: DWORD = 6; +pub const CERT_SELECT_BY_ISSUER_ATTR: DWORD = 7; +pub const CERT_SELECT_BY_SUBJECT_ATTR: DWORD = 8; +pub const CERT_SELECT_BY_ISSUER_NAME: DWORD = 9; +pub const CERT_SELECT_BY_PUBLIC_KEY: DWORD = 10; +pub const CERT_SELECT_BY_TLS_SIGNATURES: DWORD = 11; +pub const CERT_SELECT_BY_ISSUER_DISPLAYNAME: DWORD = 12; +pub const CERT_SELECT_BY_FRIENDLYNAME: DWORD = 13; +pub const CERT_SELECT_BY_THUMBPRINT: DWORD = 14; +pub const CERT_SELECT_LAST: DWORD = CERT_SELECT_BY_TLS_SIGNATURES; +pub const CERT_SELECT_MAX: DWORD = CERT_SELECT_LAST * 3; +pub const CERT_SELECT_ALLOW_EXPIRED: DWORD = 0x00000001; +pub const CERT_SELECT_TRUSTED_ROOT: DWORD = 0x00000002; +pub const CERT_SELECT_DISALLOW_SELFSIGNED: DWORD = 0x00000004; +pub const CERT_SELECT_HAS_PRIVATE_KEY: DWORD = 0x00000008; +pub const CERT_SELECT_HAS_KEY_FOR_SIGNATURE: DWORD = 0x00000010; +pub const CERT_SELECT_HAS_KEY_FOR_KEY_EXCHANGE: DWORD = 0x00000020; +pub const CERT_SELECT_HARDWARE_ONLY: DWORD = 0x00000040; +pub const CERT_SELECT_ALLOW_DUPLICATES: DWORD = 0x00000080; +pub const CERT_SELECT_IGNORE_AUTOSELECT: DWORD = 0x00000100; +extern "system" { + pub fn CertSelectCertificateChains( + pSelectionContext: LPCGUID, + dwFlags: DWORD, + pChainParameters: PCCERT_SELECT_CHAIN_PARA, + cCriteria: DWORD, + rgpCriteria: PCCERT_SELECT_CRITERIA, + hStore: HCERTSTORE, + pcSelection: PDWORD, + pprgpSelection: *mut *mut PCCERT_CHAIN_CONTEXT, + ) -> BOOL; + pub fn CertFreeCertificateChainList( + prgpSelection: *mut PCCERT_CHAIN_CONTEXT, + ); +} +pub const TIMESTAMP_VERSION: DWORD = 1; +STRUCT!{struct CRYPT_TIMESTAMP_REQUEST { + dwVersion: DWORD, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + HashedMessage: CRYPT_DER_BLOB, + pszTSAPolicyId: LPSTR, + Nonce: CRYPT_INTEGER_BLOB, + fCertReq: BOOL, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCRYPT_TIMESTAMP_REQUEST = *mut CRYPT_TIMESTAMP_REQUEST; +STRUCT!{struct CRYPT_TIMESTAMP_RESPONSE { + dwStatus: DWORD, + cFreeText: DWORD, + rgFreeText: *mut LPWSTR, + FailureInfo: CRYPT_BIT_BLOB, + ContentInfo: CRYPT_DER_BLOB, +}} +pub type PCRYPT_TIMESTAMP_RESPONSE = *mut CRYPT_TIMESTAMP_RESPONSE; +pub const TIMESTAMP_STATUS_GRANTED: DWORD = 0; +pub const TIMESTAMP_STATUS_GRANTED_WITH_MODS: DWORD = 1; +pub const TIMESTAMP_STATUS_REJECTED: DWORD = 2; +pub const TIMESTAMP_STATUS_WAITING: DWORD = 3; +pub const TIMESTAMP_STATUS_REVOCATION_WARNING: DWORD = 4; +pub const TIMESTAMP_STATUS_REVOKED: DWORD = 5; +pub const TIMESTAMP_FAILURE_BAD_ALG: DWORD = 0; +pub const TIMESTAMP_FAILURE_BAD_REQUEST: DWORD = 2; +pub const TIMESTAMP_FAILURE_BAD_FORMAT: DWORD = 5; +pub const TIMESTAMP_FAILURE_TIME_NOT_AVAILABLE: DWORD = 14; +pub const TIMESTAMP_FAILURE_POLICY_NOT_SUPPORTED: DWORD = 15; +pub const TIMESTAMP_FAILURE_EXTENSION_NOT_SUPPORTED: DWORD = 16; +pub const TIMESTAMP_FAILURE_INFO_NOT_AVAILABLE: DWORD = 17; +pub const TIMESTAMP_FAILURE_SYSTEM_FAILURE: DWORD = 25; +STRUCT!{struct CRYPT_TIMESTAMP_ACCURACY { + dwSeconds: DWORD, + dwMillis: DWORD, + dwMicros: DWORD, +}} +pub type PCRYPT_TIMESTAMP_ACCURACY = *mut CRYPT_TIMESTAMP_ACCURACY; +STRUCT!{struct CRYPT_TIMESTAMP_INFO { + dwVersion: DWORD, + pszTSAPolicyId: LPSTR, + HashAlgorithm: CRYPT_ALGORITHM_IDENTIFIER, + HashedMessage: CRYPT_DER_BLOB, + SerialNumber: CRYPT_INTEGER_BLOB, + ftTime: FILETIME, + pvAccuracy: PCRYPT_TIMESTAMP_ACCURACY, + fOrdering: BOOL, + Nonce: CRYPT_DER_BLOB, + Tsa: CRYPT_DER_BLOB, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCRYPT_TIMESTAMP_INFO = *mut CRYPT_TIMESTAMP_INFO; +STRUCT!{struct CRYPT_TIMESTAMP_CONTEXT { + cbEncoded: DWORD, + pbEncoded: *mut BYTE, + pTimeStamp: PCRYPT_TIMESTAMP_INFO, +}} +pub type PCRYPT_TIMESTAMP_CONTEXT = *mut CRYPT_TIMESTAMP_CONTEXT; +STRUCT!{struct CRYPT_TIMESTAMP_PARA { + pszTSAPolicyId: LPCSTR, + fRequestCerts: BOOL, + Nonce: CRYPT_INTEGER_BLOB, + cExtension: DWORD, + rgExtension: PCERT_EXTENSION, +}} +pub type PCRYPT_TIMESTAMP_PARA = *mut CRYPT_TIMESTAMP_PARA; +extern "system" { + pub fn CryptRetrieveTimeStamp( + wszUrl: LPCWSTR, + dwRetrievalFlags: DWORD, + dwTimeout: DWORD, + pszHashId: LPCSTR, + pPara: *const CRYPT_TIMESTAMP_PARA, + pbData: *const BYTE, + cbData: DWORD, + ppTsContext: *mut PCRYPT_TIMESTAMP_CONTEXT, + ppTsSigner: *mut PCCERT_CONTEXT, + phStore: *mut HCERTSTORE, + ) -> BOOL; +} +pub const TIMESTAMP_DONT_HASH_DATA: DWORD = 0x00000001; +pub const TIMESTAMP_VERIFY_CONTEXT_SIGNATURE: DWORD = 0x00000020; +pub const TIMESTAMP_NO_AUTH_RETRIEVAL: DWORD = 0x00020000; +extern "system" { + pub fn CryptVerifyTimeStampSignature( + pbTSContentInfo: *const BYTE, + cbTSContentInfo: DWORD, + pbData: *const BYTE, + cbData: DWORD, + hAdditionalStore: HCERTSTORE, + ppTsContext: *mut PCRYPT_TIMESTAMP_CONTEXT, + ppTsSigner: *mut PCCERT_CONTEXT, + phStore: *mut HCERTSTORE, + ) -> BOOL; +} +pub const CRYPT_OBJECT_LOCATOR_SPN_NAME_TYPE: DWORD = 1; +pub const CRYPT_OBJECT_LOCATOR_LAST_RESERVED_NAME_TYPE: DWORD = 32; +pub const CRYPT_OBJECT_LOCATOR_FIRST_RESERVED_USER_NAME_TYPE: DWORD = 33; +pub const CRYPT_OBJECT_LOCATOR_LAST_RESERVED_USER_NAME_TYPE: DWORD = 0x0000FFFF; +pub const SSL_OBJECT_LOCATOR_PFX_FUNC: &'static str = "SslObjectLocatorInitializePfx"; +pub const SSL_OBJECT_LOCATOR_ISSUER_LIST_FUNC: &'static str + = "SslObjectLocatorInitializeIssuerList"; +pub const SSL_OBJECT_LOCATOR_CERT_VALIDATION_CONFIG_FUNC: &'static str + = "SslObjectLocatorInitializeCertValidationConfig"; +pub const CRYPT_OBJECT_LOCATOR_RELEASE_SYSTEM_SHUTDOWN: DWORD = 1; +pub const CRYPT_OBJECT_LOCATOR_RELEASE_SERVICE_STOP: DWORD = 2; +pub const CRYPT_OBJECT_LOCATOR_RELEASE_PROCESS_EXIT: DWORD = 3; +pub const CRYPT_OBJECT_LOCATOR_RELEASE_DLL_UNLOAD: DWORD = 4; +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FLUSH( + pContext: LPVOID, + rgIdentifierOrNameList: *mut PCERT_NAME_BLOB, + dwIdentifierOrNameListCount: DWORD, +) -> BOOL} +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_GET( + pPluginContext: LPVOID, + pIdentifier: PCRYPT_DATA_BLOB, + dwNameType: DWORD, + pNameBlob: PCERT_NAME_BLOB, + ppbContent: *mut PBYTE, + pcbContent: *mut DWORD, + ppwszPassword: *mut PCWSTR, + ppIdentifier: *mut PCRYPT_DATA_BLOB, +) -> BOOL} +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_RELEASE( + dwReason: DWORD, + pPluginContext: LPVOID, +) -> ()} +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE_PASSWORD( + pPluginContext: LPVOID, + pwszPassword: PCWSTR, +) -> ()} +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE( + pPluginContext: LPVOID, + pbData: PBYTE, +) -> ()} +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE_IDENTIFIER( + pPluginContext: LPVOID, + pIdentifier: PCRYPT_DATA_BLOB, +) -> ()} +STRUCT!{struct CRYPT_OBJECT_LOCATOR_PROVIDER_TABLE { + cbSize: DWORD, + pfnGet: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_GET, + pfnRelease: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_RELEASE, + pfnFreePassword: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE_PASSWORD, + pfnFree: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE, + pfnFreeIdentifier: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FREE_IDENTIFIER, +}} +pub type PCRYPT_OBJECT_LOCATOR_PROVIDER_TABLE = *mut CRYPT_OBJECT_LOCATOR_PROVIDER_TABLE; +FN!{stdcall PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_INITIALIZE( + pfnFlush: PFN_CRYPT_OBJECT_LOCATOR_PROVIDER_FLUSH, + pContext: LPVOID, + pdwExpectedObjectCount: *mut DWORD, + ppFuncTable: *mut PCRYPT_OBJECT_LOCATOR_PROVIDER_TABLE, + ppPluginContext: *mut *mut c_void, +) -> BOOL} +extern "system" { + pub fn CertIsWeakHash( + dwHashUseType: DWORD, + pwszCNGHashAlgid: LPCWSTR, + dwChainFlags: DWORD, + pSignerChainContext: PCCERT_CHAIN_CONTEXT, + pTimeStamp: LPFILETIME, + pwszFileName: LPCWSTR, + ) -> BOOL; +} +FN!{stdcall PFN_CERT_IS_WEAK_HASH( + dwHashUseType: DWORD, + pwszCNGHashAlgid: LPCWSTR, + dwChainFlags: DWORD, + pSignerChainContext: PCCERT_CHAIN_CONTEXT, + pTimeStamp: LPFILETIME, + pwszFileName: LPCWSTR, +) -> BOOL} +pub const CERT_FILE_HASH_USE_TYPE: DWORD = 1; +pub const CERT_TIMESTAMP_HASH_USE_TYPE: DWORD = 2; diff --git a/winapi/src/um/windowsceip.rs b/winapi/src/um/windowsceip.rs new file mode 100644 index 000000000..87a59d33c --- /dev/null +++ b/winapi/src/um/windowsceip.rs @@ -0,0 +1,9 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::BOOL; +extern "system" { + pub fn CeipIsOptedIn() -> BOOL; +} diff --git a/winapi/src/um/winefs.rs b/winapi/src/um/winefs.rs new file mode 100644 index 000000000..f4766431b --- /dev/null +++ b/winapi/src/um/winefs.rs @@ -0,0 +1,178 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::SIZE_T; +use shared::minwindef::{BOOL, DWORD, LPVOID, PBYTE, PDWORD, ULONG}; +use um::minwinbase::SECURITY_ATTRIBUTES; +use um::wincrypt::ALG_ID; +use um::winnt::{LPCWSTR, LPWSTR, SID}; +pub const WINEFS_SETUSERKEY_SET_CAPABILITIES: DWORD = 0x00000001; +STRUCT!{struct EFS_CERTIFICATE_BLOB { + dwCertEncodingType: DWORD, + cbData: DWORD, + pbData: PBYTE, +}} +pub type PEFS_CERTIFICATE_BLOB = *mut EFS_CERTIFICATE_BLOB; +STRUCT!{struct EFS_HASH_BLOB { + cbData: DWORD, + pbData: PBYTE, +}} +pub type PEFS_HASH_BLOB = *mut EFS_HASH_BLOB; +STRUCT!{struct EFS_RPC_BLOB { + cbData: DWORD, + pbData: PBYTE, +}} +pub type PEFS_RPC_BLOB = *mut EFS_RPC_BLOB; +STRUCT!{struct EFS_PIN_BLOB { + cbPadding: DWORD, + cbData: DWORD, + pbData: PBYTE, +}} +pub type PEFS_PIN_BLOB = *mut EFS_PIN_BLOB; +STRUCT!{struct EFS_KEY_INFO { + dwVersion: DWORD, + Entropy: ULONG, + Algorithm: ALG_ID, + KeyLength: ULONG, +}} +pub type PEFS_KEY_INFO = *mut EFS_KEY_INFO; +STRUCT!{struct EFS_COMPATIBILITY_INFO { + EfsVersion: DWORD, +}} +pub type PEFS_COMPATIBILITY_INFO = *mut EFS_COMPATIBILITY_INFO; +pub const EFS_COMPATIBILITY_VERSION_NCRYPT_PROTECTOR: DWORD = 5; +pub const EFS_COMPATIBILITY_VERSION_PFILE_PROTECTOR: DWORD = 6; +#[inline] +pub fn EFS_IS_DESCRIPTOR_VERSION(v: DWORD) -> bool { + v == EFS_COMPATIBILITY_VERSION_NCRYPT_PROTECTOR + || v == EFS_COMPATIBILITY_VERSION_PFILE_PROTECTOR +} +pub const EFS_SUBVER_UNKNOWN: DWORD = 0; +pub const EFS_EFS_SUBVER_EFS_CERT: DWORD = 1; +pub const EFS_PFILE_SUBVER_RMS: DWORD = 2; +pub const EFS_PFILE_SUBVER_APPX: DWORD = 3; +STRUCT!{struct EFS_VERSION_INFO { + EfsVersion: DWORD, + SubVersion: DWORD, +}} +pub type PEFS_VERSION_INFO = *mut EFS_VERSION_INFO; +#[inline] +pub fn EFS_IS_APPX_VERSION(v: DWORD, subV: DWORD) -> bool { + v == EFS_COMPATIBILITY_VERSION_PFILE_PROTECTOR && subV == EFS_PFILE_SUBVER_APPX +} +STRUCT!{struct EFS_DECRYPTION_STATUS_INFO { + dwDecryptionError: DWORD, + dwHashOffset: DWORD, + cbHash: DWORD, +}} +pub type PEFS_DECRYPTION_STATUS_INFO = *mut EFS_DECRYPTION_STATUS_INFO; +STRUCT!{struct EFS_ENCRYPTION_STATUS_INFO { + bHasCurrentKey: BOOL, + dwEncryptionError: DWORD, +}} +pub type PEFS_ENCRYPTION_STATUS_INFO = *mut EFS_ENCRYPTION_STATUS_INFO; +STRUCT!{struct ENCRYPTION_CERTIFICATE { + cbTotalLength: DWORD, + pUserSid: *mut SID, + pCertBlob: PEFS_CERTIFICATE_BLOB, +}} +pub type PENCRYPTION_CERTIFICATE = *mut ENCRYPTION_CERTIFICATE; +pub const MAX_SID_SIZE: SIZE_T = 256; +STRUCT!{struct ENCRYPTION_CERTIFICATE_HASH { + cbTotalLength: DWORD, + pUserSid: *mut SID, + pHash: PEFS_HASH_BLOB, + lpDisplayInformation: LPWSTR, +}} +pub type PENCRYPTION_CERTIFICATE_HASH = *mut ENCRYPTION_CERTIFICATE_HASH; +STRUCT!{struct ENCRYPTION_CERTIFICATE_HASH_LIST { + nCert_Hash: DWORD, + pUsers: *mut PENCRYPTION_CERTIFICATE_HASH, +}} +pub type PENCRYPTION_CERTIFICATE_HASH_LIST = *mut ENCRYPTION_CERTIFICATE_HASH_LIST; +STRUCT!{struct ENCRYPTION_CERTIFICATE_LIST { + nUsers: DWORD, + pUsers: *mut PENCRYPTION_CERTIFICATE, +}} +pub type PENCRYPTION_CERTIFICATE_LIST = *mut ENCRYPTION_CERTIFICATE_LIST; +pub const EFS_METADATA_ADD_USER: DWORD = 0x00000001; +pub const EFS_METADATA_REMOVE_USER: DWORD = 0x00000002; +pub const EFS_METADATA_REPLACE_USER: DWORD = 0x00000004; +pub const EFS_METADATA_GENERAL_OP: DWORD = 0x00000008; +STRUCT!{struct ENCRYPTED_FILE_METADATA_SIGNATURE { + dwEfsAccessType: DWORD, + pCertificatesAdded: PENCRYPTION_CERTIFICATE_HASH_LIST, + pEncryptionCertificate: PENCRYPTION_CERTIFICATE, + pEfsStreamSignature: PEFS_RPC_BLOB, +}} +pub type PENCRYPTED_FILE_METADATA_SIGNATURE = *mut ENCRYPTED_FILE_METADATA_SIGNATURE; +STRUCT!{struct ENCRYPTION_PROTECTOR { + cbTotalLength: DWORD, + pUserSid: *mut SID, + lpProtectorDescriptor: LPWSTR, +}} +pub type PENCRYPTION_PROTECTOR = *mut ENCRYPTION_PROTECTOR; +STRUCT!{struct ENCRYPTION_PROTECTOR_LIST { + nProtectors: DWORD, + pProtectors: *mut PENCRYPTION_PROTECTOR, +}} +pub type PENCRYPTION_PROTECTOR_LIST = *mut ENCRYPTION_PROTECTOR_LIST; +extern "system" { + pub fn QueryUsersOnEncryptedFile( + lpFileName: LPCWSTR, + pUsers: *mut PENCRYPTION_CERTIFICATE_HASH_LIST, + ) -> DWORD; + pub fn QueryRecoveryAgentsOnEncryptedFile( + lpFileName: LPCWSTR, + pRecoveryAgents: *mut PENCRYPTION_CERTIFICATE_HASH_LIST, + ) -> DWORD; + pub fn RemoveUsersFromEncryptedFile( + lpFileName: LPCWSTR, + pHashes: PENCRYPTION_CERTIFICATE_HASH_LIST, + ) -> DWORD; + pub fn AddUsersToEncryptedFile( + lpFileName: LPCWSTR, + pEncryptionCertificate: PENCRYPTION_CERTIFICATE_LIST, + ) -> DWORD; + pub fn SetUserFileEncryptionKey( + pEncryptionCertificate: PENCRYPTION_CERTIFICATE, + ) -> DWORD; + pub fn SetUserFileEncryptionKeyEx( + pEncryptionCertificate: PENCRYPTION_CERTIFICATE, + dwCapabilities: DWORD, + dwFlags: DWORD, + pvReserved: LPVOID, + ) -> DWORD; + pub fn FreeEncryptionCertificateHashList( + pUsers: PENCRYPTION_CERTIFICATE_HASH_LIST, + ); + pub fn EncryptionDisable( + DirPath: LPCWSTR, + Disable: BOOL, + ) -> BOOL; + pub fn DuplicateEncryptionInfoFile( + SrcFileName: LPCWSTR, + DstFileName: LPCWSTR, + dwCreationDistribution: DWORD, + dwAttributes: DWORD, + lpSecurityAttributes: *const SECURITY_ATTRIBUTES, + ) -> DWORD; + pub fn GetEncryptedFileMetadata( + lpFileName: LPCWSTR, + pcbMetadata: PDWORD, + ppbMetadata: *mut PBYTE, + ) -> DWORD; + pub fn SetEncryptedFileMetadata( + lpFileName: LPCWSTR, + pbOldMetadata: PBYTE, + pbNewMetadata: PBYTE, + pOwnerHash: PENCRYPTION_CERTIFICATE_HASH, + dwOperation: DWORD, + pCertificatesAdded: PENCRYPTION_CERTIFICATE_HASH_LIST, + ) -> DWORD; + pub fn FreeEncryptedFileMetadata( + pbMetadata: PBYTE, + ); +} diff --git a/winapi/src/um/winevt.rs b/winapi/src/um/winevt.rs new file mode 100644 index 000000000..dce3d27ec --- /dev/null +++ b/winapi/src/um/winevt.rs @@ -0,0 +1,543 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Windows Events API +use ctypes::{c_double, c_float}; +use shared::basetsd::{INT16, INT32, INT64, INT8, UINT16, UINT32, UINT64, UINT8}; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, DWORD, FILETIME, PBYTE, PDWORD}; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{HANDLE, LCID, LONGLONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PSID, PVOID, ULONGLONG}; +use vc::vcruntime::size_t; +pub type EVT_HANDLE = HANDLE; +pub type PEVT_HANDLE = *mut HANDLE; +ENUM!{enum EVT_VARIANT_TYPE { + EvtVarTypeNull = 0, + EvtVarTypeString = 1, + EvtVarTypeAnsiString = 2, + EvtVarTypeSByte = 3, + EvtVarTypeByte = 4, + EvtVarTypeInt16 = 5, + EvtVarTypeUInt16 = 6, + EvtVarTypeInt32 = 7, + EvtVarTypeUInt32 = 8, + EvtVarTypeInt64 = 9, + EvtVarTypeUInt64 = 10, + EvtVarTypeSingle = 11, + EvtVarTypeDouble = 12, + EvtVarTypeBoolean = 13, + EvtVarTypeBinary = 14, + EvtVarTypeGuid = 15, + EvtVarTypeSizeT = 16, + EvtVarTypeFileTime = 17, + EvtVarTypeSysTime = 18, + EvtVarTypeSid = 19, + EvtVarTypeHexInt32 = 20, + EvtVarTypeHexInt64 = 21, + EvtVarTypeEvtHandle = 32, + EvtVarTypeEvtXml = 35, +}} +pub const EVT_VARIANT_TYPE_MASK: DWORD = 0x7f; +pub const EVT_VARIANT_TYPE_ARRAY: DWORD = 128; +UNION!{union EVT_VARIANT_u { + [u64; 1], + BooleanVal BooleanVal_mut: BOOL, + SByteVal SByteVal_mut: INT8, + Int16Val Int16Val_mut: INT16, + Int32Val Int32Val_mut: INT32, + Int64Val Int64Val_mut: INT64, + ByteVal ByteVal_mut: UINT8, + UInt16Val UInt16Val_mut: UINT16, + UInt32Val UInt32Val_mut: UINT32, + UInt64Val UInt64Val_mut: UINT64, + SingleVal SingleVal_mut: c_float, + DoubleVal DoubleVal_mut: c_double, + FileTimeVal FileTimeVal_mut: ULONGLONG, + SysTimeVal SysTimeVal_mut: *mut SYSTEMTIME, + GuidVal GuidVal_mut: *mut GUID, + StringVal StringVal_mut: LPCWSTR, + AnsiStringVal AnsiStringVal_mut: LPCSTR, + BinaryVal BinaryVal_mut: PBYTE, + SidVal SidVal_mut: PSID, + SizeTVal SizeTVal_mut: size_t, + BooleanArr BooleanArr_mut: *mut BOOL, + SByteArr SByteArr_mut: *mut INT8, + Int16Arr Int16Arr_mut: *mut INT16, + Int32Arr Int32Arr_mut: *mut INT32, + Int64Arr Int64Arr_mut: *mut INT64, + ByteArr ByteArr_mut: *mut UINT8, + UInt16Arr UInt16Arr_mut: *mut UINT16, + UInt32Arr UInt32Arr_mut: *mut UINT32, + UInt64Arr UInt64Arr_mut: *mut UINT64, + SingleArr SingleArr_mut: *mut c_float, + DoubleArr DoubleArr_mut: *mut c_double, + FileTimeArr FileTimeArr_mut: *mut FILETIME, + SysTimeArr SysTimeArr_mut: *mut SYSTEMTIME, + GuidArr GuidArr_mut: *mut GUID, + StringArr StringArr_mut: *mut LPWSTR, + AnsiStringArr AnsiStringArr_mut: *mut LPSTR, + SidArr SidArr_mut: *mut PSID, + SizeTArr SizeTArr_mut: *mut size_t, + EvtHandleVal EvtHandleVal_mut: EVT_HANDLE, + XmlVal XmlVal_mut: LPCWSTR, + XmlValArr XmlValArr_mut: *mut LPCWSTR, +}} +STRUCT!{struct EVT_VARIANT { + u: EVT_VARIANT_u, + Count: DWORD, + Type: DWORD, +}} +pub type PEVT_VARIANT = *mut EVT_VARIANT; +ENUM!{enum EVT_LOGIN_CLASS { + EvtRpcLogin = 1, +}} +ENUM!{enum EVT_RPC_LOGIN_FLAGS { + EvtRpcLoginAuthDefault = 0, + EvtRpcLoginAuthNegotiate, + EvtRpcLoginAuthKerberos, + EvtRpcLoginAuthNTLM, +}} +STRUCT!{struct EVT_RPC_LOGIN { + Server: LPWSTR, + User: LPWSTR, + Domain: LPWSTR, + Password: LPWSTR, + Flags: DWORD, +}} +extern "system" { + pub fn EvtOpenSession( + LoginClass: EVT_LOGIN_CLASS, + Login: PVOID, + Timeout: DWORD, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtClose( + Object: EVT_HANDLE, + ) -> BOOL; + pub fn EvtCancel( + Object: EVT_HANDLE, + ) -> BOOL; + pub fn EvtGetExtendedStatus( + BufferSize: DWORD, + Buffer: LPWSTR, + BufferUsed: PDWORD, + ) -> DWORD; +} +ENUM!{enum EVT_QUERY_FLAGS { + EvtQueryChannelPath = 0x1, + EvtQueryFilePath = 0x2, + EvtQueryForwardDirection = 0x100, + EvtQueryReverseDirection = 0x200, + EvtQueryTolerateQueryErrors = 0x1000, +}} +ENUM!{enum EVT_SEEK_FLAGS { + EvtSeekRelativeToFirst = 1, + EvtSeekRelativeToLast = 2, + EvtSeekRelativeToCurrent = 3, + EvtSeekRelativeToBookmark = 4, + EvtSeekOriginMask = 7, + EvtSeekStrict = 0x10000, +}} +extern "system" { + pub fn EvtQuery( + Session: EVT_HANDLE, + Path: LPCWSTR, + Query: LPCWSTR, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtNext( + ResultSet: EVT_HANDLE, + EventsSize: DWORD, + Events: PEVT_HANDLE, + Timeout: DWORD, + Flags: DWORD, + Returned: PDWORD, + ) -> BOOL; + pub fn EvtSeek( + ResultSet: EVT_HANDLE, + Position: LONGLONG, + Bookmark: EVT_HANDLE, + Timeout: DWORD, + Flags: DWORD, + ) -> BOOL; +} +ENUM!{enum EVT_SUBSCRIBE_FLAGS { + EvtSubscribeToFutureEvents = 1, + EvtSubscribeStartAtOldestRecord = 2, + EvtSubscribeStartAfterBookmark = 3, + EvtSubscribeOriginMask = 3, + EvtSubscribeTolerateQueryErrors = 0x1000, + EvtSubscribeStrict = 0x10000, +}} +ENUM!{enum EVT_SUBSCRIBE_NOTIFY_ACTION { + EvtSubscribeActionError = 0, + EvtSubscribeActionDeliver, +}} +FN!{stdcall EVT_SUBSCRIBE_CALLBACK( + Action: EVT_SUBSCRIBE_NOTIFY_ACTION, + UserContext: PVOID, + Event: EVT_HANDLE, +) -> DWORD} +extern "system" { + pub fn EvtSubscribe( + Session: EVT_HANDLE, + SignalEvent: HANDLE, + ChannelPath: LPCWSTR, + Query: LPCWSTR, + Bookmark: EVT_HANDLE, + Context: PVOID, + Callback: EVT_SUBSCRIBE_CALLBACK, + Flags: DWORD, + ) -> EVT_HANDLE; +} +ENUM!{enum EVT_SYSTEM_PROPERTY_ID { + EvtSystemProviderName = 0, + EvtSystemProviderGuid, + EvtSystemEventID, + EvtSystemQualifiers, + EvtSystemLevel, + EvtSystemTask, + EvtSystemOpcode, + EvtSystemKeywords, + EvtSystemTimeCreated, + EvtSystemEventRecordId, + EvtSystemActivityID, + EvtSystemRelatedActivityID, + EvtSystemProcessID, + EvtSystemThreadID, + EvtSystemChannel, + EvtSystemComputer, + EvtSystemUserID, + EvtSystemVersion, + EvtSystemPropertyIdEND, +}} +ENUM!{enum EVT_RENDER_CONTEXT_FLAGS { + EvtRenderContextValues = 0, + EvtRenderContextSystem, + EvtRenderContextUser, +}} +ENUM!{enum EVT_RENDER_FLAGS { + EvtRenderEventValues = 0, + EvtRenderEventXml, + EvtRenderBookmark, +}} +extern "system" { + pub fn EvtCreateRenderContext( + ValuePathsCount: DWORD, + ValuePaths: *mut LPCWSTR, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtRender( + Context: EVT_HANDLE, + Fragment: EVT_HANDLE, + Flags: DWORD, + BufferSize: DWORD, + Buffer: PVOID, + BufferUsed: PDWORD, + PropertyCount: PDWORD, + ) -> BOOL; +} +ENUM!{enum EVT_FORMAT_MESSAGE_FLAGS { + EvtFormatMessageEvent = 1, + EvtFormatMessageLevel, + EvtFormatMessageTask, + EvtFormatMessageOpcode, + EvtFormatMessageKeyword, + EvtFormatMessageChannel, + EvtFormatMessageProvider, + EvtFormatMessageId, + EvtFormatMessageXml, +}} +extern "system" { + pub fn EvtFormatMessage( + PublisherMetadata: EVT_HANDLE, + Event: EVT_HANDLE, + MessageId: DWORD, + ValueCount: DWORD, + Values: PEVT_VARIANT, + Flags: DWORD, + BufferSize: DWORD, + Buffer: LPWSTR, + BufferUsed: PDWORD, + ) -> BOOL; +} +ENUM!{enum EVT_OPEN_LOG_FLAGS { + EvtOpenChannelPath = 0x1, + EvtOpenFilePath = 0x2, +}} +ENUM!{enum EVT_LOG_PROPERTY_ID { + EvtLogCreationTime = 0, + EvtLogLastAccessTime, + EvtLogLastWriteTime, + EvtLogFileSize, + EvtLogAttributes, + EvtLogNumberOfLogRecords, + EvtLogOldestRecordNumber, + EvtLogFull, +}} +extern "system" { + pub fn EvtOpenLog( + Session: EVT_HANDLE, + Path: LPCWSTR, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtGetLogInfo( + Log: EVT_HANDLE, + PropertyId: EVT_LOG_PROPERTY_ID, + PropertyValueBufferSize: DWORD, + PropertyValueBuffer: PEVT_VARIANT, + PropertyValueBufferUsed: PDWORD, + ) -> BOOL; + pub fn EvtClearLog( + Session: EVT_HANDLE, + ChannelPath: LPCWSTR, + TargetFilePath: LPCWSTR, + Flags: DWORD, + ) -> BOOL; +} +ENUM!{enum EVT_EXPORTLOG_FLAGS { + EvtExportLogChannelPath = 0x1, + EvtExportLogFilePath = 0x2, + EvtExportLogTolerateQueryErrors = 0x1000, + EvtExportLogOverwrite = 0x2000, +}} +extern "system" { + pub fn EvtExportLog( + Session: EVT_HANDLE, + Path: LPCWSTR, + Query: LPCWSTR, + TargetFilePath: LPCWSTR, + Flags: DWORD, + ) -> BOOL; + pub fn EvtArchiveExportedLog( + Session: EVT_HANDLE, + LogFilePath: LPCWSTR, + Locale: LCID, + Flags: DWORD, + ) -> BOOL; +} +ENUM!{enum EVT_CHANNEL_CONFIG_PROPERTY_ID { + EvtChannelConfigEnabled = 0, + EvtChannelConfigIsolation, + EvtChannelConfigType, + EvtChannelConfigOwningPublisher, + EvtChannelConfigClassicEventlog, + EvtChannelConfigAccess, + EvtChannelLoggingConfigRetention, + EvtChannelLoggingConfigAutoBackup, + EvtChannelLoggingConfigMaxSize, + EvtChannelLoggingConfigLogFilePath, + EvtChannelPublishingConfigLevel, + EvtChannelPublishingConfigKeywords, + EvtChannelPublishingConfigControlGuid, + EvtChannelPublishingConfigBufferSize, + EvtChannelPublishingConfigMinBuffers, + EvtChannelPublishingConfigMaxBuffers, + EvtChannelPublishingConfigLatency, + EvtChannelPublishingConfigClockType, + EvtChannelPublishingConfigSidType, + EvtChannelPublisherList, + EvtChannelPublishingConfigFileMax, + EvtChannelConfigPropertyIdEND, +}} +ENUM!{enum EVT_CHANNEL_TYPE { + EvtChannelTypeAdmin = 0, + EvtChannelTypeOperational, + EvtChannelTypeAnalytic, + EvtChannelTypeDebug, +}} +ENUM!{enum EVT_CHANNEL_ISOLATION_TYPE { + EvtChannelIsolationTypeApplication = 0, + EvtChannelIsolationTypeSystem, + EvtChannelIsolationTypeCustom, +}} +ENUM!{enum EVT_CHANNEL_CLOCK_TYPE { + EvtChannelClockTypeSystemTime = 0, + EvtChannelClockTypeQPC, +}} +ENUM!{enum EVT_CHANNEL_SID_TYPE { + EvtChannelSidTypeNone = 0, + EvtChannelSidTypePublishing, +}} +extern "system" { + pub fn EvtOpenChannelEnum( + Session: EVT_HANDLE, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtNextChannelPath( + ChannelEnum: EVT_HANDLE, + ChannelPathBufferSize: DWORD, + ChannelPathBuffer: LPWSTR, + ChannelPathBufferUsed: PDWORD, + ) -> BOOL; + pub fn EvtOpenChannelConfig( + Session: EVT_HANDLE, + ChannelPath: LPCWSTR, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtSaveChannelConfig( + ChannelConfig: EVT_HANDLE, + Flags: DWORD, + ) -> BOOL; + pub fn EvtSetChannelConfigProperty( + ChannelConfig: EVT_HANDLE, + PropertyId: EVT_CHANNEL_CONFIG_PROPERTY_ID, + Flags: DWORD, + PropertyValue: PEVT_VARIANT, + ) -> BOOL; + pub fn EvtGetChannelConfigProperty( + ChannelConfig: EVT_HANDLE, + PropertyId: EVT_CHANNEL_CONFIG_PROPERTY_ID, + Flags: DWORD, + PropertyValueBufferSize: DWORD, + PropertyValueBuffer: PEVT_VARIANT, + PropertyValueBufferUsed: PDWORD, + ) -> BOOL; +} +ENUM!{enum EVT_CHANNEL_REFERENCE_FLAGS { + EvtChannelReferenceImported = 0x1, +}} +ENUM!{enum EVT_PUBLISHER_METADATA_PROPERTY_ID { + EvtPublisherMetadataPublisherGuid = 0, + EvtPublisherMetadataResourceFilePath, + EvtPublisherMetadataParameterFilePath, + EvtPublisherMetadataMessageFilePath, + EvtPublisherMetadataHelpLink, + EvtPublisherMetadataPublisherMessageID, + EvtPublisherMetadataChannelReferences, + EvtPublisherMetadataChannelReferencePath, + EvtPublisherMetadataChannelReferenceIndex, + EvtPublisherMetadataChannelReferenceID, + EvtPublisherMetadataChannelReferenceFlags, + EvtPublisherMetadataChannelReferenceMessageID, + EvtPublisherMetadataLevels, + EvtPublisherMetadataLevelName, + EvtPublisherMetadataLevelValue, + EvtPublisherMetadataLevelMessageID, + EvtPublisherMetadataTasks, + EvtPublisherMetadataTaskName, + EvtPublisherMetadataTaskEventGuid, + EvtPublisherMetadataTaskValue, + EvtPublisherMetadataTaskMessageID, + EvtPublisherMetadataOpcodes, + EvtPublisherMetadataOpcodeName, + EvtPublisherMetadataOpcodeValue, + EvtPublisherMetadataOpcodeMessageID, + EvtPublisherMetadataKeywords, + EvtPublisherMetadataKeywordName, + EvtPublisherMetadataKeywordValue, + EvtPublisherMetadataKeywordMessageID, + EvtPublisherMetadataPropertyIdEND, +}} +extern "system" { + pub fn EvtOpenPublisherEnum( + Session: EVT_HANDLE, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtNextPublisherId( + PublisherEnum: EVT_HANDLE, + PublisherIdBufferSize: DWORD, + PublisherIdBuffer: LPWSTR, + PublisherIdBufferUsed: PDWORD, + ) -> BOOL; + pub fn EvtOpenPublisherMetadata( + Session: EVT_HANDLE, + PublisherId: LPCWSTR, + LogFilePath: LPCWSTR, + Locale: LCID, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtGetPublisherMetadataProperty( + PublisherMetadata: EVT_HANDLE, + PropertyId: EVT_PUBLISHER_METADATA_PROPERTY_ID, + Flags: DWORD, + PublisherMetadataPropertyBufferSize: DWORD, + PublisherMetadataPropertyBuffer: PEVT_VARIANT, + PublisherMetadataPropertyBufferUsed: PDWORD, + ) -> BOOL; +} +ENUM!{enum EVT_EVENT_METADATA_PROPERTY_ID { + EventMetadataEventID, + EventMetadataEventVersion, + EventMetadataEventChannel, + EventMetadataEventLevel, + EventMetadataEventOpcode, + EventMetadataEventTask, + EventMetadataEventKeyword, + EventMetadataEventMessageID, + EventMetadataEventTemplate, + EvtEventMetadataPropertyIdEND, +}} +extern "system" { + pub fn EvtOpenEventMetadataEnum( + PublisherMetadata: EVT_HANDLE, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtNextEventMetadata( + EventMetadataEnum: EVT_HANDLE, + Flags: DWORD, + ) -> EVT_HANDLE; + pub fn EvtGetEventMetadataProperty( + EventMetadata: EVT_HANDLE, + PropertyId: EVT_EVENT_METADATA_PROPERTY_ID, + Flags: DWORD, + EventMetadataPropertyBufferSize: DWORD, + EventMetadataPropertyBuffer: PEVT_VARIANT, + EventMetadataPropertyBufferUsed: PDWORD, + ) -> BOOL; +} +pub type EVT_OBJECT_ARRAY_PROPERTY_HANDLE = HANDLE; +extern "system" { + pub fn EvtGetObjectArraySize( + ObjectArray: EVT_OBJECT_ARRAY_PROPERTY_HANDLE, + ObjectArraySize: PDWORD, + ) -> BOOL; + pub fn EvtGetObjectArrayProperty( + ObjectArray: EVT_OBJECT_ARRAY_PROPERTY_HANDLE, + PropertyId: DWORD, + ArrayIndex: DWORD, + Flags: DWORD, + PropertyValueBufferSize: DWORD, + PropertyValueBuffer: PEVT_VARIANT, + PropertyValueBufferUsed: PDWORD, + ) -> BOOL; +} +ENUM!{enum EVT_QUERY_PROPERTY_ID { + EvtQueryNames, + EvtQueryStatuses, + EvtQueryPropertyIdEND, +}} +ENUM!{enum EVT_EVENT_PROPERTY_ID { + EvtEventQueryIDs = 0, + EvtEventPath, + EvtEventPropertyIdEND, +}} +extern "system" { + pub fn EvtGetQueryInfo( + QueryOrSubscription: EVT_HANDLE, + PropertyId: EVT_QUERY_PROPERTY_ID, + PropertyValueBufferSize: DWORD, + PropertyValueBuffer: PEVT_VARIANT, + PropertyValueBufferUsed: PDWORD, + ) -> BOOL; + pub fn EvtCreateBookmark( + BookmarkXml: LPCWSTR, + ) -> EVT_HANDLE; + pub fn EvtUpdateBookmark( + Bookmark: EVT_HANDLE, + Event: EVT_HANDLE, + ) -> BOOL; + pub fn EvtGetEventInfo( + Event: EVT_HANDLE, + PropertyId: EVT_EVENT_PROPERTY_ID, + PropertyValueBufferSize: DWORD, + PropertyValueBuffer: PEVT_VARIANT, + PropertyValueBufferUsed: PDWORD, + ) -> BOOL; +} +pub const EVT_READ_ACCESS: DWORD = 0x1; +pub const EVT_WRITE_ACCESS: DWORD = 0x2; +pub const EVT_CLEAR_ACCESS: DWORD = 0x4; +pub const EVT_ALL_ACCESS: DWORD = 0x7; diff --git a/winapi/src/um/wingdi.rs b/winapi/src/um/wingdi.rs new file mode 100644 index 000000000..4404bee08 --- /dev/null +++ b/winapi/src/um/wingdi.rs @@ -0,0 +1,5591 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! GDI procedure declarations, constant definitions and macros +use ctypes::{c_char, c_int, c_long, c_short, c_ushort, c_void}; +use shared::basetsd::{UINT16, UINT32, UINT64, ULONG_PTR}; +use shared::minwindef::{ + BOOL, BYTE, DWORD, FLOAT, HGLOBAL, HMETAFILE, HMODULE, HRGN, INT, LOBYTE, LPARAM, LPBYTE, + LPDWORD, LPINT, LPVOID, LPWORD, MAX_PATH, PFLOAT, PROC, UINT, ULONG, USHORT, WORD, +}; +use shared::windef::{ + COLORREF, HBITMAP, HBRUSH, HCOLORSPACE, HDC, HENHMETAFILE, HFONT, HGDIOBJ, HGLRC, HPALETTE, + HPEN, HWND, LPPOINT, LPRECT, LPSIZE, POINT, POINTL, POINTS, RECT, RECTL, SIZEL, +}; +use um::winnt::{ + CHAR, HANDLE, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, LUID, PSTR, PVOID, SHORT, VOID, WCHAR, +}; +pub const R2_BLACK: c_int = 1; +pub const R2_NOTMERGEPEN: c_int = 2; +pub const R2_MASKNOTPEN: c_int = 3; +pub const R2_NOTCOPYPEN: c_int = 4; +pub const R2_MASKPENNOT: c_int = 5; +pub const R2_NOT: c_int = 6; +pub const R2_XORPEN: c_int = 7; +pub const R2_NOTMASKPEN: c_int = 8; +pub const R2_MASKPEN: c_int = 9; +pub const R2_NOTXORPEN: c_int = 10; +pub const R2_NOP: c_int = 11; +pub const R2_MERGENOTPEN: c_int = 12; +pub const R2_COPYPEN: c_int = 13; +pub const R2_MERGEPENNOT: c_int = 14; +pub const R2_MERGEPEN: c_int = 15; +pub const R2_WHITE: c_int = 16; +pub const R2_LAST: c_int = 16; +pub const SRCCOPY: DWORD = 0x00CC0020; +pub const SRCPAINT: DWORD = 0x00EE0086; +pub const SRCAND: DWORD = 0x008800C6; +pub const SRCINVERT: DWORD = 0x00660046; +pub const SRCERASE: DWORD = 0x00440328; +pub const NOTSRCCOPY: DWORD = 0x00330008; +pub const NOTSRCERASE: DWORD = 0x001100A6; +pub const MERGECOPY: DWORD = 0x00C000CA; +pub const MERGEPAINT: DWORD = 0x00BB0226; +pub const PATCOPY: DWORD = 0x00F00021; +pub const PATPAINT: DWORD = 0x00FB0A09; +pub const PATINVERT: DWORD = 0x005A0049; +pub const DSTINVERT: DWORD = 0x00550009; +pub const BLACKNESS: DWORD = 0x00000042; +pub const WHITENESS: DWORD = 0x00FF0062; +pub const NOMIRRORBITMAP: DWORD = 0x80000000; +pub const CAPTUREBLT: DWORD = 0x40000000; +#[inline] +pub fn MAKEROP4(fore: DWORD, back: DWORD) -> DWORD { + ((back << 8) & 0xFF000000) | fore +} +pub const GDI_ERROR: ULONG = 0xFFFFFFFF; +pub const HGDI_ERROR: HANDLE = -1isize as HANDLE; +pub const ERROR: c_int = 0; +pub const NULLREGION: c_int = 1; +pub const SIMPLEREGION: c_int = 2; +pub const COMPLEXREGION: c_int = 3; +pub const RGN_ERROR: c_int = ERROR; +pub const RGN_AND: c_int = 1; +pub const RGN_OR: c_int = 2; +pub const RGN_XOR: c_int = 3; +pub const RGN_DIFF: c_int = 4; +pub const RGN_COPY: c_int = 5; +pub const RGN_MIN: c_int = RGN_AND; +pub const RGN_MAX: c_int = RGN_COPY; +pub const BLACKONWHITE: c_int = 1; +pub const WHITEONBLACK: c_int = 2; +pub const COLORONCOLOR: c_int = 3; +pub const HALFTONE: c_int = 4; +pub const MAXSTRETCHBLTMODE: c_int = 4; +pub const STRETCH_ANDSCANS: c_int = BLACKONWHITE; +pub const STRETCH_ORSCANS: c_int = WHITEONBLACK; +pub const STRETCH_DELETESCANS: c_int = COLORONCOLOR; +pub const STRETCH_HALFTONE: c_int = HALFTONE; +pub const ALTERNATE: c_int = 1; +pub const WINDING: c_int = 2; +pub const POLYFILL_LAST: c_int = 2; +pub const LAYOUT_RTL: DWORD = 0x00000001; +pub const LAYOUT_BTT: DWORD = 0x00000002; +pub const LAYOUT_VBH: DWORD = 0x00000004; +pub const LAYOUT_ORIENTATIONMASK: DWORD = (LAYOUT_RTL | LAYOUT_BTT | LAYOUT_VBH); +pub const LAYOUT_BITMAPORIENTATIONPRESERVED: DWORD = 0x00000008; +pub const TA_NOUPDATECP: UINT = 0; +pub const TA_UPDATECP: UINT = 1; +pub const TA_LEFT: UINT = 0; +pub const TA_RIGHT: UINT = 2; +pub const TA_CENTER: UINT = 6; +pub const TA_TOP: UINT = 0; +pub const TA_BOTTOM: UINT = 8; +pub const TA_BASELINE: UINT = 24; +pub const TA_RTLREADING: UINT = 256; +pub const TA_MASK: UINT = TA_BASELINE + TA_CENTER + TA_UPDATECP + TA_RTLREADING; +pub const VTA_BASELINE: UINT = TA_BASELINE; +pub const VTA_LEFT: UINT = TA_BOTTOM; +pub const VTA_RIGHT: UINT = TA_TOP; +pub const VTA_CENTER: UINT = TA_CENTER; +pub const VTA_BOTTOM: UINT = TA_RIGHT; +pub const VTA_TOP: UINT = TA_LEFT; +pub const ETO_OPAQUE: UINT = 0x0002; +pub const ETO_CLIPPED: UINT = 0x0004; +pub const ETO_GLYPH_INDEX: UINT = 0x0010; +pub const ETO_RTLREADING: UINT = 0x0080; +pub const ETO_NUMERICSLOCAL: UINT = 0x0400; +pub const ETO_NUMERICSLATIN: UINT = 0x0800; +pub const ETO_IGNORELANGUAGE: UINT = 0x1000; +pub const ETO_PDY: UINT = 0x2000; +pub const ETO_REVERSE_INDEX_MAP: UINT = 0x10000; +pub const ASPECT_FILTERING: UINT = 0x0001; +pub const DCB_RESET: UINT = 0x0001; +pub const DCB_ACCUMULATE: UINT = 0x0002; +pub const DCB_DIRTY: UINT = DCB_ACCUMULATE; +pub const DCB_SET: UINT = (DCB_RESET | DCB_ACCUMULATE); +pub const DCB_ENABLE: UINT = 0x0004; +pub const DCB_DISABLE: UINT = 0x0008; +pub const META_SETBKCOLOR: WORD = 0x0201; +pub const META_SETBKMODE: WORD = 0x0102; +pub const META_SETMAPMODE: WORD = 0x0103; +pub const META_SETROP2: WORD = 0x0104; +pub const META_SETRELABS: WORD = 0x0105; +pub const META_SETPOLYFILLMODE: WORD = 0x0106; +pub const META_SETSTRETCHBLTMODE: WORD = 0x0107; +pub const META_SETTEXTCHAREXTRA: WORD = 0x0108; +pub const META_SETTEXTCOLOR: WORD = 0x0209; +pub const META_SETTEXTJUSTIFICATION: WORD = 0x020A; +pub const META_SETWINDOWORG: WORD = 0x020B; +pub const META_SETWINDOWEXT: WORD = 0x020C; +pub const META_SETVIEWPORTORG: WORD = 0x020D; +pub const META_SETVIEWPORTEXT: WORD = 0x020E; +pub const META_OFFSETWINDOWORG: WORD = 0x020F; +pub const META_SCALEWINDOWEXT: WORD = 0x0410; +pub const META_OFFSETVIEWPORTORG: WORD = 0x0211; +pub const META_SCALEVIEWPORTEXT: WORD = 0x0412; +pub const META_LINETO: WORD = 0x0213; +pub const META_MOVETO: WORD = 0x0214; +pub const META_EXCLUDECLIPRECT: WORD = 0x0415; +pub const META_INTERSECTCLIPRECT: WORD = 0x0416; +pub const META_ARC: WORD = 0x0817; +pub const META_ELLIPSE: WORD = 0x0418; +pub const META_FLOODFILL: WORD = 0x0419; +pub const META_PIE: WORD = 0x081A; +pub const META_RECTANGLE: WORD = 0x041B; +pub const META_ROUNDRECT: WORD = 0x061C; +pub const META_PATBLT: WORD = 0x061D; +pub const META_SAVEDC: WORD = 0x001E; +pub const META_SETPIXEL: WORD = 0x041F; +pub const META_OFFSETCLIPRGN: WORD = 0x0220; +pub const META_TEXTOUT: WORD = 0x0521; +pub const META_BITBLT: WORD = 0x0922; +pub const META_STRETCHBLT: WORD = 0x0B23; +pub const META_POLYGON: WORD = 0x0324; +pub const META_POLYLINE: WORD = 0x0325; +pub const META_ESCAPE: WORD = 0x0626; +pub const META_RESTOREDC: WORD = 0x0127; +pub const META_FILLREGION: WORD = 0x0228; +pub const META_FRAMEREGION: WORD = 0x0429; +pub const META_INVERTREGION: WORD = 0x012A; +pub const META_PAINTREGION: WORD = 0x012B; +pub const META_SELECTCLIPREGION: WORD = 0x012C; +pub const META_SELECTOBJECT: WORD = 0x012D; +pub const META_SETTEXTALIGN: WORD = 0x012E; +pub const META_CHORD: WORD = 0x0830; +pub const META_SETMAPPERFLAGS: WORD = 0x0231; +pub const META_EXTTEXTOUT: WORD = 0x0a32; +pub const META_SETDIBTODEV: WORD = 0x0d33; +pub const META_SELECTPALETTE: WORD = 0x0234; +pub const META_REALIZEPALETTE: WORD = 0x0035; +pub const META_ANIMATEPALETTE: WORD = 0x0436; +pub const META_SETPALENTRIES: WORD = 0x0037; +pub const META_POLYPOLYGON: WORD = 0x0538; +pub const META_RESIZEPALETTE: WORD = 0x0139; +pub const META_DIBBITBLT: WORD = 0x0940; +pub const META_DIBSTRETCHBLT: WORD = 0x0b41; +pub const META_DIBCREATEPATTERNBRUSH: WORD = 0x0142; +pub const META_STRETCHDIB: WORD = 0x0f43; +pub const META_EXTFLOODFILL: WORD = 0x0548; +pub const META_SETLAYOUT: WORD = 0x0149; +pub const META_DELETEOBJECT: WORD = 0x01f0; +pub const META_CREATEPALETTE: WORD = 0x00f7; +pub const META_CREATEPATTERNBRUSH: WORD = 0x01F9; +pub const META_CREATEPENINDIRECT: WORD = 0x02FA; +pub const META_CREATEFONTINDIRECT: WORD = 0x02FB; +pub const META_CREATEBRUSHINDIRECT: WORD = 0x02FC; +pub const META_CREATEREGION: WORD = 0x06FF; +STRUCT!{struct DRAWPATRECT { + ptPosition: POINT, + ptSize: POINT, + wStyle: WORD, + wPattern: WORD, +}} +pub type PDRAWPATRECT = *mut DRAWPATRECT; +pub const NEWFRAME: c_int = 1; +pub const ABORTDOC: c_int = 2; +pub const NEXTBAND: c_int = 3; +pub const SETCOLORTABLE: c_int = 4; +pub const GETCOLORTABLE: c_int = 5; +pub const FLUSHOUTPUT: c_int = 6; +pub const DRAFTMODE: c_int = 7; +pub const QUERYESCSUPPORT: c_int = 8; +pub const SETABORTPROC: c_int = 9; +pub const STARTDOC: c_int = 10; +pub const ENDDOC: c_int = 11; +pub const GETPHYSPAGESIZE: c_int = 12; +pub const GETPRINTINGOFFSET: c_int = 13; +pub const GETSCALINGFACTOR: c_int = 14; +pub const MFCOMMENT: c_int = 15; +pub const GETPENWIDTH: c_int = 16; +pub const SETCOPYCOUNT: c_int = 17; +pub const SELECTPAPERSOURCE: c_int = 18; +pub const DEVICEDATA: c_int = 19; +pub const PASSTHROUGH: c_int = 19; +pub const GETTECHNOLGY: c_int = 20; +pub const GETTECHNOLOGY: c_int = 20; +pub const SETLINECAP: c_int = 21; +pub const SETLINEJOIN: c_int = 22; +pub const SETMITERLIMIT: c_int = 23; +pub const BANDINFO: c_int = 24; +pub const DRAWPATTERNRECT: c_int = 25; +pub const GETVECTORPENSIZE: c_int = 26; +pub const GETVECTORBRUSHSIZE: c_int = 27; +pub const ENABLEDUPLEX: c_int = 28; +pub const GETSETPAPERBINS: c_int = 29; +pub const GETSETPRINTORIENT: c_int = 30; +pub const ENUMPAPERBINS: c_int = 31; +pub const SETDIBSCALING: c_int = 32; +pub const EPSPRINTING: c_int = 33; +pub const ENUMPAPERMETRICS: c_int = 34; +pub const GETSETPAPERMETRICS: c_int = 35; +pub const POSTSCRIPT_DATA: c_int = 37; +pub const POSTSCRIPT_IGNORE: c_int = 38; +pub const MOUSETRAILS: c_int = 39; +pub const GETDEVICEUNITS: c_int = 42; +pub const GETEXTENDEDTEXTMETRICS: c_int = 256; +pub const GETEXTENTTABLE: c_int = 257; +pub const GETPAIRKERNTABLE: c_int = 258; +pub const GETTRACKKERNTABLE: c_int = 259; +pub const EXTTEXTOUT: c_int = 512; +pub const GETFACENAME: c_int = 513; +pub const DOWNLOADFACE: c_int = 514; +pub const ENABLERELATIVEWIDTHS: c_int = 768; +pub const ENABLEPAIRKERNING: c_int = 769; +pub const SETKERNTRACK: c_int = 770; +pub const SETALLJUSTVALUES: c_int = 771; +pub const SETCHARSET: c_int = 772; +pub const STRETCHBLT: c_int = 2048; +pub const METAFILE_DRIVER: c_int = 2049; +pub const GETSETSCREENPARAMS: c_int = 3072; +pub const QUERYDIBSUPPORT: c_int = 3073; +pub const BEGIN_PATH: c_int = 4096; +pub const CLIP_TO_PATH: c_int = 4097; +pub const END_PATH: c_int = 4098; +pub const EXT_DEVICE_CAPS: c_int = 4099; +pub const RESTORE_CTM: c_int = 4100; +pub const SAVE_CTM: c_int = 4101; +pub const SET_ARC_DIRECTION: c_int = 4102; +pub const SET_BACKGROUND_COLOR: c_int = 4103; +pub const SET_POLY_MODE: c_int = 4104; +pub const SET_SCREEN_ANGLE: c_int = 4105; +pub const SET_SPREAD: c_int = 4106; +pub const TRANSFORM_CTM: c_int = 4107; +pub const SET_CLIP_BOX: c_int = 4108; +pub const SET_BOUNDS: c_int = 4109; +pub const SET_MIRROR_MODE: c_int = 4110; +pub const OPENCHANNEL: c_int = 4110; +pub const DOWNLOADHEADER: c_int = 4111; +pub const CLOSECHANNEL: c_int = 4112; +pub const POSTSCRIPT_PASSTHROUGH: c_int = 4115; +pub const ENCAPSULATED_POSTSCRIPT: c_int = 4116; +pub const POSTSCRIPT_IDENTIFY: c_int = 4117; +pub const POSTSCRIPT_INJECTION: c_int = 4118; +pub const CHECKJPEGFORMAT: c_int = 4119; +pub const CHECKPNGFORMAT: c_int = 4120; +pub const GET_PS_FEATURESETTING: c_int = 4121; +pub const GDIPLUS_TS_QUERYVER: c_int = 4122; +pub const GDIPLUS_TS_RECORD: c_int = 4123; +pub const MILCORE_TS_QUERYVER_RESULT_FALSE: c_int = 0x0; +pub const MILCORE_TS_QUERYVER_RESULT_TRUE: c_int = 0x7FFFFFFF; +pub const SPCLPASSTHROUGH2: c_int = 4568; +pub const PSIDENT_GDICENTRIC: c_int = 0; +pub const PSIDENT_PSCENTRIC: c_int = 1; +STRUCT!{struct PSINJECTDATA { + DataBytes: DWORD, + InjectionPoint: WORD, + PageNumber: WORD, +}} +pub type PPSINJECTDATA = *mut PSINJECTDATA; +pub const PSINJECT_BEGINSTREAM: WORD = 1; +pub const PSINJECT_PSADOBE: WORD = 2; +pub const PSINJECT_PAGESATEND: WORD = 3; +pub const PSINJECT_PAGES: WORD = 4; +pub const PSINJECT_DOCNEEDEDRES: WORD = 5; +pub const PSINJECT_DOCSUPPLIEDRES: WORD = 6; +pub const PSINJECT_PAGEORDER: WORD = 7; +pub const PSINJECT_ORIENTATION: WORD = 8; +pub const PSINJECT_BOUNDINGBOX: WORD = 9; +pub const PSINJECT_DOCUMENTPROCESSCOLORS: WORD = 10; +pub const PSINJECT_COMMENTS: WORD = 11; +pub const PSINJECT_BEGINDEFAULTS: WORD = 12; +pub const PSINJECT_ENDDEFAULTS: WORD = 13; +pub const PSINJECT_BEGINPROLOG: WORD = 14; +pub const PSINJECT_ENDPROLOG: WORD = 15; +pub const PSINJECT_BEGINSETUP: WORD = 16; +pub const PSINJECT_ENDSETUP: WORD = 17; +pub const PSINJECT_TRAILER: WORD = 18; +pub const PSINJECT_EOF: WORD = 19; +pub const PSINJECT_ENDSTREAM: WORD = 20; +pub const PSINJECT_DOCUMENTPROCESSCOLORSATEND: WORD = 21; +pub const PSINJECT_PAGENUMBER: WORD = 100; +pub const PSINJECT_BEGINPAGESETUP: WORD = 101; +pub const PSINJECT_ENDPAGESETUP: WORD = 102; +pub const PSINJECT_PAGETRAILER: WORD = 103; +pub const PSINJECT_PLATECOLOR: WORD = 104; +pub const PSINJECT_SHOWPAGE: WORD = 105; +pub const PSINJECT_PAGEBBOX: WORD = 106; +pub const PSINJECT_ENDPAGECOMMENTS: WORD = 107; +pub const PSINJECT_VMSAVE: WORD = 200; +pub const PSINJECT_VMRESTORE: WORD = 201; +pub const PSINJECT_DLFONT: DWORD = 0xdddddddd; +pub const FEATURESETTING_NUP: WORD = 0; +pub const FEATURESETTING_OUTPUT: WORD = 1; +pub const FEATURESETTING_PSLEVEL: WORD = 2; +pub const FEATURESETTING_CUSTPAPER: WORD = 3; +pub const FEATURESETTING_MIRROR: WORD = 4; +pub const FEATURESETTING_NEGATIVE: WORD = 5; +pub const FEATURESETTING_PROTOCOL: WORD = 6; +pub const FEATURESETTING_PRIVATE_BEGIN: WORD = 0x1000; +pub const FEATURESETTING_PRIVATE_END: WORD = 0x1FFF; +STRUCT!{struct PSFEATURE_OUTPUT { + bPageIndependent: BOOL, + bSetPageDevice: BOOL, +}} +pub type PPSFEATURE_OUTPUT = *mut PSFEATURE_OUTPUT; +STRUCT!{struct PSFEATURE_CUSTPAPER { + lOrientation: LONG, + lWidth: LONG, + lHeight: LONG, + lWidthOffset: LONG, + lHeightOffset: LONG, +}} +pub type PPSFEATURE_CUSTPAPER = *mut PSFEATURE_CUSTPAPER; +pub const PSPROTOCOL_ASCII: c_int = 0; +pub const PSPROTOCOL_BCP: c_int = 1; +pub const PSPROTOCOL_TBCP: c_int = 2; +pub const PSPROTOCOL_BINARY: c_int = 3; +pub const QDI_SETDIBITS: c_int = 1; +pub const QDI_GETDIBITS: c_int = 2; +pub const QDI_DIBTOSCREEN: c_int = 4; +pub const QDI_STRETCHDIB: c_int = 8; +pub const SP_NOTREPORTED: c_int = 0x4000; +pub const SP_ERROR: c_int = -1; +pub const SP_APPABORT: c_int = -2; +pub const SP_USERABORT: c_int = -3; +pub const SP_OUTOFDISK: c_int = -4; +pub const SP_OUTOFMEMORY: c_int = -5; +pub const PR_JOBSTATUS: c_int = 0x0000; +pub const OBJ_PEN: UINT = 1; +pub const OBJ_BRUSH: UINT = 2; +pub const OBJ_DC: UINT = 3; +pub const OBJ_METADC: UINT = 4; +pub const OBJ_PAL: UINT = 5; +pub const OBJ_FONT: UINT = 6; +pub const OBJ_BITMAP: UINT = 7; +pub const OBJ_REGION: UINT = 8; +pub const OBJ_METAFILE: UINT = 9; +pub const OBJ_MEMDC: UINT = 10; +pub const OBJ_EXTPEN: UINT = 11; +pub const OBJ_ENHMETADC: UINT = 12; +pub const OBJ_ENHMETAFILE: UINT = 13; +pub const OBJ_COLORSPACE: UINT = 14; +pub const GDI_OBJ_LAST: UINT = OBJ_COLORSPACE; +pub const MWT_IDENTITY: c_int = 1; +pub const MWT_LEFTMULTIPLY: c_int = 2; +pub const MWT_RIGHTMULTIPLY: c_int = 3; +pub const MWT_MIN: c_int = MWT_IDENTITY; +pub const MWT_MAX: c_int = MWT_RIGHTMULTIPLY; +STRUCT!{struct XFORM { + eM11: FLOAT, + eM12: FLOAT, + eM21: FLOAT, + eM22: FLOAT, + eDx: FLOAT, + eDy: FLOAT, +}} +pub type PXFORM = *mut XFORM; +pub type LPXFORM = *mut XFORM; +STRUCT!{struct BITMAP { + bmType: LONG, + bmWidth: LONG, + bmHeight: LONG, + bmWidthBytes: LONG, + bmPlanes: WORD, + bmBitsPixel: WORD, + bmBits: LPVOID, +}} +pub type PBITMAP = *mut BITMAP; +pub type NPBITMAP = *mut BITMAP; +pub type LPBITMAP = *mut BITMAP; +STRUCT!{#[debug] struct RGBTRIPLE { + rgbtBlue: BYTE, + rgbtGreen: BYTE, + rgbtRed: BYTE, +}} +pub type PRGBTRIPLE = *mut RGBTRIPLE; +pub type NPRGBTRIPLE = *mut RGBTRIPLE; +pub type LPRGBTRIPLE = *mut RGBTRIPLE; +STRUCT!{#[debug] struct RGBQUAD { + rgbBlue: BYTE, + rgbGreen: BYTE, + rgbRed: BYTE, + rgbReserved: BYTE, +}} +pub type LPRGBQUAD = *mut RGBQUAD; +pub const CS_ENABLE: DWORD = 0x00000001; +pub const CS_DISABLE: DWORD = 0x00000002; +pub const CS_DELETE_TRANSFORM: DWORD = 0x00000003; +pub const LCS_SIGNATURE: DWORD = 0x5053_4F43; // 'PSOC' +pub const LCS_sRGB: LCSCSTYPE = 0x7352_4742; // 'sRGB' +pub const LCS_WINDOWS_COLOR_SPACE: LCSCSTYPE = 0x5769_6E20; // 'Win ' +pub type LCSCSTYPE = LONG; +pub const LCS_CALIBRATED_RGB: LCSCSTYPE = 0x00000000; +pub type LCSGAMUTMATCH = LONG; +pub const LCS_GM_BUSINESS: LCSGAMUTMATCH = 0x00000001; +pub const LCS_GM_GRAPHICS: LCSGAMUTMATCH = 0x00000002; +pub const LCS_GM_IMAGES: LCSGAMUTMATCH = 0x00000004; +pub const LCS_GM_ABS_COLORIMETRIC: LCSGAMUTMATCH = 0x00000008; +pub const CM_OUT_OF_GAMUT: BYTE = 255; +pub const CM_IN_GAMUT: BYTE = 0; +pub const ICM_ADDPROFILE: UINT = 1; +pub const ICM_DELETEPROFILE: UINT = 2; +pub const ICM_QUERYPROFILE: UINT = 3; +pub const ICM_SETDEFAULTPROFILE: UINT = 4; +pub const ICM_REGISTERICMATCHER: UINT = 5; +pub const ICM_UNREGISTERICMATCHER: UINT = 6; +pub const ICM_QUERYMATCH: UINT = 7; +#[inline] +pub fn GetKValue(cmyk: COLORREF) -> BYTE { + cmyk as BYTE +} +#[inline] +pub fn GetYValue(cmyk: COLORREF) -> BYTE { + (cmyk >> 8) as BYTE +} +#[inline] +pub fn GetMValue(cmyk: COLORREF) -> BYTE { + (cmyk >> 16) as BYTE +} +#[inline] +pub fn GetCValue(cmyk: COLORREF) -> BYTE { + (cmyk >> 24) as BYTE +} +#[inline] +pub fn CMYK(c: BYTE, m: BYTE, y: BYTE, k: BYTE) -> COLORREF { + (k as COLORREF) | ((y as COLORREF) << 8) | ((m as COLORREF) << 16) | ((c as COLORREF) << 24) +} +pub type FXPT16DOT16 = c_long; +pub type LPFXPT16DOT16 = *mut c_long; +pub type FXPT2DOT30 = c_long; +pub type LPFXPT2DOT30 = *mut c_long; +STRUCT!{#[debug] struct CIEXYZ { + ciexyzX: FXPT2DOT30, + ciexyzY: FXPT2DOT30, + ciexyzZ: FXPT2DOT30, +}} +pub type LPCIEXYZ = *mut CIEXYZ; +STRUCT!{#[debug] struct CIEXYZTRIPLE { + ciexyzRed: CIEXYZ, + ciexyzGreen: CIEXYZ, + ciexyzBlue: CIEXYZ, +}} +pub type LPCIEXYZTRIPLE = *mut CIEXYZTRIPLE; +STRUCT!{struct LOGCOLORSPACEA { + lcsSignature: DWORD, + lcsVersion: DWORD, + lcsSize: DWORD, + lcsCSType: LCSCSTYPE, + lcsIntent: LCSGAMUTMATCH, + lcsEndpoints: CIEXYZTRIPLE, + lcsGammaRed: DWORD, + lcsGammaGreen: DWORD, + lcsGammaBlue: DWORD, + lcsFilename: [CHAR; MAX_PATH], +}} +pub type LPLOGCOLORSPACEA = *mut LOGCOLORSPACEA; +STRUCT!{struct LOGCOLORSPACEW { + lcsSignature: DWORD, + lcsVersion: DWORD, + lcsSize: DWORD, + lcsCSType: LCSCSTYPE, + lcsIntent: LCSGAMUTMATCH, + lcsEndpoints: CIEXYZTRIPLE, + lcsGammaRed: DWORD, + lcsGammaGreen: DWORD, + lcsGammaBlue: DWORD, + lcsFilename: [WCHAR; MAX_PATH], +}} +pub type LPLOGCOLORSPACEW = *mut LOGCOLORSPACEW; +STRUCT!{#[debug] struct BITMAPCOREHEADER { + bcSize: DWORD, + bcWidth: WORD, + bcHeight: WORD, + bcPlanes: WORD, + bcBitCount: WORD, +}} +pub type LPBITMAPCOREHEADER = *mut BITMAPCOREHEADER; +pub type PBITMAPCOREHEADER = *mut BITMAPCOREHEADER; +STRUCT!{#[debug] struct BITMAPINFOHEADER { + biSize: DWORD, + biWidth: LONG, + biHeight: LONG, + biPlanes: WORD, + biBitCount: WORD, + biCompression: DWORD, + biSizeImage: DWORD, + biXPelsPerMeter: LONG, + biYPelsPerMeter: LONG, + biClrUsed: DWORD, + biClrImportant: DWORD, +}} +pub type LPBITMAPINFOHEADER = *mut BITMAPINFOHEADER; +pub type PBITMAPINFOHEADER = *mut BITMAPINFOHEADER; +STRUCT!{#[debug] struct BITMAPV4HEADER { + bV4Size: DWORD, + bV4Width: LONG, + bV4Height: LONG, + bV4Planes: WORD, + bV4BitCount: WORD, + bV4V4Compression: DWORD, + bV4SizeImage: DWORD, + bV4XPelsPerMeter: LONG, + bV4YPelsPerMeter: LONG, + bV4ClrUsed: DWORD, + bV4ClrImportant: DWORD, + bV4RedMask: DWORD, + bV4GreenMask: DWORD, + bV4BlueMask: DWORD, + bV4AlphaMask: DWORD, + bV4CSType: DWORD, + bV4Endpoints: CIEXYZTRIPLE, + bV4GammaRed: DWORD, + bV4GammaGreen: DWORD, + bV4GammaBlue: DWORD, +}} +pub type LPBITMAPV4HEADER = *mut BITMAPV4HEADER; +pub type PBITMAPV4HEADER = *mut BITMAPV4HEADER; +STRUCT!{#[debug] struct BITMAPV5HEADER { + bV5Size: DWORD, + bV5Width: LONG, + bV5Height: LONG, + bV5Planes: WORD, + bV5BitCount: WORD, + bV5Compression: DWORD, + bV5SizeImage: DWORD, + bV5XPelsPerMeter: LONG, + bV5YPelsPerMeter: LONG, + bV5ClrUsed: DWORD, + bV5ClrImportant: DWORD, + bV5RedMask: DWORD, + bV5GreenMask: DWORD, + bV5BlueMask: DWORD, + bV5AlphaMask: DWORD, + bV5CSType: DWORD, + bV5Endpoints: CIEXYZTRIPLE, + bV5GammaRed: DWORD, + bV5GammaGreen: DWORD, + bV5GammaBlue: DWORD, + bV5Intent: DWORD, + bV5ProfileData: DWORD, + bV5ProfileSize: DWORD, + bV5Reserved: DWORD, +}} +pub type LPBITMAPV5HEADER = *mut BITMAPV5HEADER; +pub type PBITMAPV5HEADER = *mut BITMAPV5HEADER; +pub const PROFILE_LINKED: LONG = 0x4C49_4E4B; // 'LINK' +pub const PROFILE_EMBEDDED: LONG = 0x4D42_4544; // 'MBED' +pub const BI_RGB: DWORD = 0; +pub const BI_RLE8: DWORD = 1; +pub const BI_RLE4: DWORD = 2; +pub const BI_BITFIELDS: DWORD = 3; +pub const BI_JPEG: DWORD = 4; +pub const BI_PNG: DWORD = 5; +STRUCT!{#[debug] struct BITMAPINFO { + bmiHeader: BITMAPINFOHEADER, + bmiColors: [RGBQUAD; 1], +}} +pub type LPBITMAPINFO = *mut BITMAPINFO; +pub type PBITMAPINFO = *mut BITMAPINFO; +STRUCT!{#[debug] struct BITMAPCOREINFO { + bmciHeader: BITMAPCOREHEADER, + bmciColors: [RGBTRIPLE; 1], +}} +pub type LPBITMAPCOREINFO = *mut BITMAPCOREINFO; +pub type PBITMAPCOREINFO = *mut BITMAPCOREINFO; +STRUCT!{#[debug] #[repr(packed)] struct BITMAPFILEHEADER { + bfType: WORD, + bfSize: DWORD, + bfReserved1: WORD, + bfReserved2: WORD, + bfOffBits: DWORD, +}} +pub type LPBITMAPFILEHEADER = *mut BITMAPFILEHEADER; +pub type PBITMAPFILEHEADER = *mut BITMAPFILEHEADER; +#[inline] +pub fn MAKEPOINTS(l: DWORD) -> POINTS { + unsafe { ::core::mem::transmute::<DWORD, POINTS>(l) } +} +STRUCT!{#[debug] struct FONTSIGNATURE { + fsUsb: [DWORD; 4], + fsCsb: [DWORD; 2], +}} +pub type LPFONTSIGNATURE = *mut FONTSIGNATURE; +pub type PFONTSIGNATURE = *mut FONTSIGNATURE; +STRUCT!{#[debug] struct CHARSETINFO { + ciCharset: UINT, + ciACP: UINT, + fs: FONTSIGNATURE, +}} +pub type PCHARSETINFO = *mut CHARSETINFO; +pub type NPCHARSETINFO = *mut CHARSETINFO; +pub type LPCHARSETINFO = *mut CHARSETINFO; +pub const TCI_SRCCHARSET: c_int = 1; +pub const TCI_SRCCODEPAGE: c_int = 2; +pub const TCI_SRCFONTSIG: c_int = 3; +pub const TCI_SRCLOCALE: c_int = 0x1000; +STRUCT!{#[debug] struct LOCALESIGNATURE { + lsUsb: [DWORD; 4], + lsCsbDefault: [DWORD; 2], + lsCsbSupported: [DWORD; 2], +}} +pub type PLOCALESIGNATURE = *mut LOCALESIGNATURE; +pub type LPLOCALESIGNATURE = *mut LOCALESIGNATURE; +STRUCT!{struct HANDLETABLE { + objectHandle: [HGDIOBJ; 1], +}} +pub type LPHANDLETABLE = *mut HANDLETABLE; +pub type PHANDLETABLE = *mut HANDLETABLE; +STRUCT!{struct METARECORD { + rdSize: DWORD, + rdFunction: WORD, + rdParm: [WORD; 1], +}} +pub type PMETARECORD = *mut METARECORD; +pub type LPMETARECORD = *mut METARECORD; +STRUCT!{struct METAFILEPICT { + mm: LONG, + xExt: LONG, + yExt: LONG, + hMF: HMETAFILE, +}} +pub type LPMETAFILEPICT = *mut METAFILEPICT; +STRUCT!{struct METAHEADER { + mtType: WORD, + mtHeaderSize: WORD, + mtVersion: WORD, + mtSize: DWORD, + mtNoObjects: WORD, + mtMaxRecord: DWORD, + mtNoParameters: WORD, +}} +pub type PMETAHEADER = *mut METAHEADER; +pub type LPMETAHEADER = *mut METAHEADER; +STRUCT!{struct ENHMETARECORD { + iType: DWORD, + nSize: DWORD, + dParm: [DWORD; 1], +}} +pub type PENHMETARECORD = *mut ENHMETARECORD; +pub type LPENHMETARECORD = *mut ENHMETARECORD; +STRUCT!{struct ENHMETAHEADER { + iType: DWORD, + nSize: DWORD, + rclBounds: RECTL, + rclFrame: RECTL, + dSignature: DWORD, + nVersion: DWORD, + nBytes: DWORD, + nRecords: DWORD, + nHandles: WORD, + sReserved: WORD, + nDescription: DWORD, + offDescription: DWORD, + nPalEntries: DWORD, + szlDevice: SIZEL, + szlMillimeters: SIZEL, + cbPixelFormat: DWORD, + offPixelFormat: DWORD, + bOpenGL: DWORD, + szlMicrometers: SIZEL, +}} +pub type PENHMETAHEADER = *mut ENHMETAHEADER; +pub type LPENHMETAHEADER = *mut ENHMETAHEADER; +pub const TMPF_FIXED_PITCH: BYTE = 0x01; +pub const TMPF_VECTOR: BYTE = 0x02; +pub const TMPF_DEVICE: BYTE = 0x08; +pub const TMPF_TRUETYPE: BYTE = 0x04; +// BCHAR +STRUCT!{struct TEXTMETRICA { + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, + tmDigitizedAspectX: LONG, + tmDigitizedAspectY: LONG, + tmFirstChar: BYTE, + tmLastChar: BYTE, + tmDefaultChar: BYTE, + tmBreakChar: BYTE, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, +}} +pub type PTEXTMETRICA = *mut TEXTMETRICA; +pub type NPTEXTMETRICA = *mut TEXTMETRICA; +pub type LPTEXTMETRICA = *mut TEXTMETRICA; +STRUCT!{struct TEXTMETRICW { + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, + tmDigitizedAspectX: LONG, + tmDigitizedAspectY: LONG, + tmFirstChar: WCHAR, + tmLastChar: WCHAR, + tmDefaultChar: WCHAR, + tmBreakChar: WCHAR, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, +}} +pub type PTEXTMETRICW = *mut TEXTMETRICW; +pub type NPTEXTMETRICW = *mut TEXTMETRICW; +pub type LPTEXTMETRICW = *mut TEXTMETRICW; +pub const NTM_REGULAR: DWORD = 0x00000040; +pub const NTM_BOLD: DWORD = 0x00000020; +pub const NTM_ITALIC: DWORD = 0x00000001; +pub const NTM_NONNEGATIVE_AC: DWORD = 0x00010000; +pub const NTM_PS_OPENTYPE: DWORD = 0x00020000; +pub const NTM_TT_OPENTYPE: DWORD = 0x00040000; +pub const NTM_MULTIPLEMASTER: DWORD = 0x00080000; +pub const NTM_TYPE1: DWORD = 0x00100000; +pub const NTM_DSIG: DWORD = 0x00200000; +STRUCT!{struct NEWTEXTMETRICA { + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, + tmDigitizedAspectX: LONG, + tmDigitizedAspectY: LONG, + tmFirstChar: BYTE, + tmLastChar: BYTE, + tmDefaultChar: BYTE, + tmBreakChar: BYTE, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, + ntmFlags: DWORD, + ntmSizeEM: UINT, + ntmCellHeight: UINT, + ntmAvgWidth: UINT, +}} +pub type PNEWTEXTMETRICA = *mut NEWTEXTMETRICA; +pub type NPNEWTEXTMETRICA = *mut NEWTEXTMETRICA; +pub type LPNEWTEXTMETRICA = *mut NEWTEXTMETRICA; +STRUCT!{struct NEWTEXTMETRICW { + tmHeight: LONG, + tmAscent: LONG, + tmDescent: LONG, + tmInternalLeading: LONG, + tmExternalLeading: LONG, + tmAveCharWidth: LONG, + tmMaxCharWidth: LONG, + tmWeight: LONG, + tmOverhang: LONG, + tmDigitizedAspectX: LONG, + tmDigitizedAspectY: LONG, + tmFirstChar: WCHAR, + tmLastChar: WCHAR, + tmDefaultChar: WCHAR, + tmBreakChar: WCHAR, + tmItalic: BYTE, + tmUnderlined: BYTE, + tmStruckOut: BYTE, + tmPitchAndFamily: BYTE, + tmCharSet: BYTE, + ntmFlags: DWORD, + ntmSizeEM: UINT, + ntmCellHeight: UINT, + ntmAvgWidth: UINT, +}} +pub type PNEWTEXTMETRICW = *mut NEWTEXTMETRICW; +pub type NPNEWTEXTMETRICW = *mut NEWTEXTMETRICW; +pub type LPNEWTEXTMETRICW = *mut NEWTEXTMETRICW; +STRUCT!{struct NEWTEXTMETRICEXA { + ntmTm: NEWTEXTMETRICA, + ntmFontSig: FONTSIGNATURE, +}} +STRUCT!{struct NEWTEXTMETRICEXW { + ntmTm: NEWTEXTMETRICW, + ntmFontSig: FONTSIGNATURE, +}} +STRUCT!{struct PELARRAY { + paXCount: LONG, + paYCount: LONG, + paXExt: LONG, + paYExt: LONG, + paRGBs: BYTE, +}} +pub type PPELARRAY = *mut PELARRAY; +pub type NPPELARRAY = *mut PELARRAY; +pub type LPPELARRAY = *mut PELARRAY; +STRUCT!{struct LOGBRUSH { + lbStyle: UINT, + lbColor: COLORREF, + lbHatch: ULONG_PTR, +}} +pub type PLOGBRUSH = *mut LOGBRUSH; +pub type NPLOGBRUSH = *mut LOGBRUSH; +pub type LPLOGBRUSH = *mut LOGBRUSH; +STRUCT!{struct LOGBRUSH32 { + lbStyle: UINT, + lbColor: COLORREF, + lbHatch: ULONG, +}} +pub type PLOGBRUSH32 = *mut LOGBRUSH32; +pub type NPLOGBRUSH32 = *mut LOGBRUSH32; +pub type LPLOGBRUSH32 = *mut LOGBRUSH32; +pub type PATTERN = LOGBRUSH; +pub type PPATTERN = *mut PATTERN; +pub type NPPATTERN = *mut PATTERN; +pub type LPPATTERN = *mut PATTERN; +STRUCT!{struct LOGPEN { + lopnStyle: UINT, + lopnWidth: POINT, + lopnColor: COLORREF, +}} +pub type PLOGPEN = *mut LOGPEN; +pub type NPLOGPEN = *mut LOGPEN; +pub type LPLOGPEN = *mut LOGPEN; +STRUCT!{struct EXTLOGPEN { + elpPenStyle: DWORD, + elpWidth: DWORD, + elpBrushStyle: UINT, + elpColor: COLORREF, + elpHatch: ULONG_PTR, + elpNumEntries: DWORD, + elpStyleEntry: [DWORD; 1], +}} +pub type PEXTLOGPEN = *mut EXTLOGPEN; +pub type NPEXTLOGPEN = *mut EXTLOGPEN; +pub type LPEXTLOGPEN = *mut EXTLOGPEN; +STRUCT!{struct EXTLOGPEN32 { + elpPenStyle: DWORD, + elpWidth: DWORD, + elpBrushStyle: UINT, + elpColor: COLORREF, + elpHatch: ULONG, + elpNumEntries: DWORD, + elpStyleEntry: [DWORD; 1], +}} +pub type PEXTLOGPEN32 = *mut EXTLOGPEN32; +pub type NPEXTLOGPEN32 = *mut EXTLOGPEN32; +pub type LPEXTLOGPEN32 = *mut EXTLOGPEN32; +STRUCT!{struct PALETTEENTRY { + peRed: BYTE, + peGreen: BYTE, + peBlue: BYTE, + peFlags: BYTE, +}} +pub type PPALETTEENTRY = *mut PALETTEENTRY; +pub type LPPALETTEENTRY = *mut PALETTEENTRY; +STRUCT!{struct LOGPALETTE { + palVersion: WORD, + palNumEntries: WORD, + palPalEntry: [PALETTEENTRY; 1], +}} +pub type PLOGPALETTE = *mut LOGPALETTE; +pub type NPLOGPALETTE = *mut LOGPALETTE; +pub type LPLOGPALETTE = *mut LOGPALETTE; +pub const LF_FACESIZE: usize = 32; +STRUCT!{struct LOGFONTA { + lfHeight: LONG, + lfWidth: LONG, + lfEscapement: LONG, + lfOrientation: LONG, + lfWeight: LONG, + lfItalic: BYTE, + lfUnderline: BYTE, + lfStrikeOut: BYTE, + lfCharSet: BYTE, + lfOutPrecision: BYTE, + lfClipPrecision: BYTE, + lfQuality: BYTE, + lfPitchAndFamily: BYTE, + lfFaceName: [CHAR; LF_FACESIZE], +}} +pub type PLOGFONTA = *mut LOGFONTA; +pub type NPLOGFONTA = *mut LOGFONTA; +pub type LPLOGFONTA = *mut LOGFONTA; +STRUCT!{struct LOGFONTW { + lfHeight: LONG, + lfWidth: LONG, + lfEscapement: LONG, + lfOrientation: LONG, + lfWeight: LONG, + lfItalic: BYTE, + lfUnderline: BYTE, + lfStrikeOut: BYTE, + lfCharSet: BYTE, + lfOutPrecision: BYTE, + lfClipPrecision: BYTE, + lfQuality: BYTE, + lfPitchAndFamily: BYTE, + lfFaceName: [WCHAR; LF_FACESIZE], +}} +pub type PLOGFONTW = *mut LOGFONTW; +pub type NPLOGFONTW = *mut LOGFONTW; +pub type LPLOGFONTW = *mut LOGFONTW; +pub const LF_FULLFACESIZE: usize = 64; +STRUCT!{struct ENUMLOGFONTA { + elfLogFont: LOGFONTA, + elfFullName: [BYTE; LF_FULLFACESIZE], + elfStyle: [BYTE; LF_FACESIZE], +}} +pub type LPENUMLOGFONTA = *mut ENUMLOGFONTA; +STRUCT!{struct ENUMLOGFONTW { + elfLogFont: LOGFONTW, + elfFullName: [WCHAR; LF_FULLFACESIZE], + elfStyle: [WCHAR; LF_FACESIZE], +}} +pub type LPENUMLOGFONTW = *mut ENUMLOGFONTW; +STRUCT!{struct ENUMLOGFONTEXA { + elfLogFont: LOGFONTA, + elfFullName: [BYTE; LF_FULLFACESIZE], + elfStyle: [BYTE; LF_FACESIZE], + elfScript: [BYTE; LF_FACESIZE], +}} +pub type LPENUMLOGFONTEXA = *mut ENUMLOGFONTEXA; +STRUCT!{struct ENUMLOGFONTEXW { + elfLogFont: LOGFONTW, + elfFullName: [WCHAR; LF_FULLFACESIZE], + elfStyle: [WCHAR; LF_FACESIZE], + elfScript: [WCHAR; LF_FACESIZE], +}} +pub type LPENUMLOGFONTEXW = *mut ENUMLOGFONTEXW; +pub const OUT_DEFAULT_PRECIS: DWORD = 0; +pub const OUT_STRING_PRECIS: DWORD = 1; +pub const OUT_CHARACTER_PRECIS: DWORD = 2; +pub const OUT_STROKE_PRECIS: DWORD = 3; +pub const OUT_TT_PRECIS: DWORD = 4; +pub const OUT_DEVICE_PRECIS: DWORD = 5; +pub const OUT_RASTER_PRECIS: DWORD = 6; +pub const OUT_TT_ONLY_PRECIS: DWORD = 7; +pub const OUT_OUTLINE_PRECIS: DWORD = 8; +pub const OUT_SCREEN_OUTLINE_PRECIS: DWORD = 9; +pub const OUT_PS_ONLY_PRECIS: DWORD = 10; +pub const CLIP_DEFAULT_PRECIS: DWORD = 0; +pub const CLIP_CHARACTER_PRECIS: DWORD = 1; +pub const CLIP_STROKE_PRECIS: DWORD = 2; +pub const CLIP_MASK: DWORD = 0xf; +pub const CLIP_LH_ANGLES: DWORD = 1 << 4; +pub const CLIP_TT_ALWAYS: DWORD = 2 << 4; +pub const CLIP_DFA_DISABLE: DWORD = 4 << 4; +pub const CLIP_EMBEDDED: DWORD = 8 << 4; +pub const DEFAULT_QUALITY: DWORD = 0; +pub const DRAFT_QUALITY: DWORD = 1; +pub const PROOF_QUALITY: DWORD = 2; +pub const NONANTIALIASED_QUALITY: DWORD = 3; +pub const ANTIALIASED_QUALITY: DWORD = 4; +pub const CLEARTYPE_QUALITY: DWORD = 5; +pub const CLEARTYPE_NATURAL_QUALITY: DWORD = 6; +pub const DEFAULT_PITCH: DWORD = 0; +pub const FIXED_PITCH: DWORD = 1; +pub const VARIABLE_PITCH: DWORD = 2; +pub const MONO_FONT: DWORD = 8; +pub const ANSI_CHARSET: DWORD = 0; +pub const DEFAULT_CHARSET: DWORD = 1; +pub const SYMBOL_CHARSET: DWORD = 2; +pub const SHIFTJIS_CHARSET: DWORD = 128; +pub const HANGEUL_CHARSET: DWORD = 129; +pub const HANGUL_CHARSET: DWORD = 129; +pub const GB2312_CHARSET: DWORD = 134; +pub const CHINESEBIG5_CHARSET: DWORD = 136; +pub const OEM_CHARSET: DWORD = 255; +pub const JOHAB_CHARSET: DWORD = 130; +pub const HEBREW_CHARSET: DWORD = 177; +pub const ARABIC_CHARSET: DWORD = 178; +pub const GREEK_CHARSET: DWORD = 161; +pub const TURKISH_CHARSET: DWORD = 162; +pub const VIETNAMESE_CHARSET: DWORD = 163; +pub const THAI_CHARSET: DWORD = 222; +pub const EASTEUROPE_CHARSET: DWORD = 238; +pub const RUSSIAN_CHARSET: DWORD = 204; +pub const MAC_CHARSET: DWORD = 77; +pub const BALTIC_CHARSET: DWORD = 186; +pub const FS_LATIN1: DWORD = 0x00000001; +pub const FS_LATIN2: DWORD = 0x00000002; +pub const FS_CYRILLIC: DWORD = 0x00000004; +pub const FS_GREEK: DWORD = 0x00000008; +pub const FS_TURKISH: DWORD = 0x00000010; +pub const FS_HEBREW: DWORD = 0x00000020; +pub const FS_ARABIC: DWORD = 0x00000040; +pub const FS_BALTIC: DWORD = 0x00000080; +pub const FS_VIETNAMESE: DWORD = 0x00000100; +pub const FS_THAI: DWORD = 0x00010000; +pub const FS_JISJAPAN: DWORD = 0x00020000; +pub const FS_CHINESESIMP: DWORD = 0x00040000; +pub const FS_WANSUNG: DWORD = 0x00080000; +pub const FS_CHINESETRAD: DWORD = 0x00100000; +pub const FS_JOHAB: DWORD = 0x00200000; +pub const FS_SYMBOL: DWORD = 0x80000000; +pub const FF_DONTCARE: DWORD = 0 << 4; +pub const FF_ROMAN: DWORD = 1 << 4; +pub const FF_SWISS: DWORD = 2 << 4; +pub const FF_MODERN: DWORD = 3 << 4; +pub const FF_SCRIPT: DWORD = 4 << 4; +pub const FF_DECORATIVE: DWORD = 5 << 4; +pub const FW_DONTCARE: c_int = 0; +pub const FW_THIN: c_int = 100; +pub const FW_EXTRALIGHT: c_int = 200; +pub const FW_LIGHT: c_int = 300; +pub const FW_NORMAL: c_int = 400; +pub const FW_MEDIUM: c_int = 500; +pub const FW_SEMIBOLD: c_int = 600; +pub const FW_BOLD: c_int = 700; +pub const FW_EXTRABOLD: c_int = 800; +pub const FW_HEAVY: c_int = 900; +pub const FW_ULTRALIGHT: c_int = FW_EXTRALIGHT; +pub const FW_REGULAR: c_int = FW_NORMAL; +pub const FW_DEMIBOLD: c_int = FW_SEMIBOLD; +pub const FW_ULTRABOLD: c_int = FW_EXTRABOLD; +pub const FW_BLACK: c_int = FW_HEAVY; +pub const PANOSE_COUNT: DWORD = 10; +pub const PAN_FAMILYTYPE_INDEX: DWORD = 0; +pub const PAN_SERIFSTYLE_INDEX: DWORD = 1; +pub const PAN_WEIGHT_INDEX: DWORD = 2; +pub const PAN_PROPORTION_INDEX: DWORD = 3; +pub const PAN_CONTRAST_INDEX: DWORD = 4; +pub const PAN_STROKEVARIATION_INDEX: DWORD = 5; +pub const PAN_ARMSTYLE_INDEX: DWORD = 6; +pub const PAN_LETTERFORM_INDEX: DWORD = 7; +pub const PAN_MIDLINE_INDEX: DWORD = 8; +pub const PAN_XHEIGHT_INDEX: DWORD = 9; +pub const PAN_CULTURE_LATIN: DWORD = 0; +STRUCT!{struct PANOSE { + bFamilyType: BYTE, + bSerifStyle: BYTE, + bWeight: BYTE, + bProportion: BYTE, + bContrast: BYTE, + bStrokeVariation: BYTE, + bArmStyle: BYTE, + bLetterform: BYTE, + bMidline: BYTE, + bXHeight: BYTE, +}} +pub type LPPANOSE = *mut PANOSE; +pub const PAN_ANY: BYTE = 0; +pub const PAN_NO_FIT: BYTE = 1; +pub const PAN_FAMILY_TEXT_DISPLAY: BYTE = 2; +pub const PAN_FAMILY_SCRIPT: BYTE = 3; +pub const PAN_FAMILY_DECORATIVE: BYTE = 4; +pub const PAN_FAMILY_PICTORIAL: BYTE = 5; +pub const PAN_SERIF_COVE: BYTE = 2; +pub const PAN_SERIF_OBTUSE_COVE: BYTE = 3; +pub const PAN_SERIF_SQUARE_COVE: BYTE = 4; +pub const PAN_SERIF_OBTUSE_SQUARE_COVE: BYTE = 5; +pub const PAN_SERIF_SQUARE: BYTE = 6; +pub const PAN_SERIF_THIN: BYTE = 7; +pub const PAN_SERIF_BONE: BYTE = 8; +pub const PAN_SERIF_EXAGGERATED: BYTE = 9; +pub const PAN_SERIF_TRIANGLE: BYTE = 10; +pub const PAN_SERIF_NORMAL_SANS: BYTE = 11; +pub const PAN_SERIF_OBTUSE_SANS: BYTE = 12; +pub const PAN_SERIF_PERP_SANS: BYTE = 13; +pub const PAN_SERIF_FLARED: BYTE = 14; +pub const PAN_SERIF_ROUNDED: BYTE = 15; +pub const PAN_WEIGHT_VERY_LIGHT: BYTE = 2; +pub const PAN_WEIGHT_LIGHT: BYTE = 3; +pub const PAN_WEIGHT_THIN: BYTE = 4; +pub const PAN_WEIGHT_BOOK: BYTE = 5; +pub const PAN_WEIGHT_MEDIUM: BYTE = 6; +pub const PAN_WEIGHT_DEMI: BYTE = 7; +pub const PAN_WEIGHT_BOLD: BYTE = 8; +pub const PAN_WEIGHT_HEAVY: BYTE = 9; +pub const PAN_WEIGHT_BLACK: BYTE = 10; +pub const PAN_WEIGHT_NORD: BYTE = 11; +pub const PAN_PROP_OLD_STYLE: BYTE = 2; +pub const PAN_PROP_MODERN: BYTE = 3; +pub const PAN_PROP_EVEN_WIDTH: BYTE = 4; +pub const PAN_PROP_EXPANDED: BYTE = 5; +pub const PAN_PROP_CONDENSED: BYTE = 6; +pub const PAN_PROP_VERY_EXPANDED: BYTE = 7; +pub const PAN_PROP_VERY_CONDENSED: BYTE = 8; +pub const PAN_PROP_MONOSPACED: BYTE = 9; +pub const PAN_CONTRAST_NONE: BYTE = 2; +pub const PAN_CONTRAST_VERY_LOW: BYTE = 3; +pub const PAN_CONTRAST_LOW: BYTE = 4; +pub const PAN_CONTRAST_MEDIUM_LOW: BYTE = 5; +pub const PAN_CONTRAST_MEDIUM: BYTE = 6; +pub const PAN_CONTRAST_MEDIUM_HIGH: BYTE = 7; +pub const PAN_CONTRAST_HIGH: BYTE = 8; +pub const PAN_CONTRAST_VERY_HIGH: BYTE = 9; +pub const PAN_STROKE_GRADUAL_DIAG: BYTE = 2; +pub const PAN_STROKE_GRADUAL_TRAN: BYTE = 3; +pub const PAN_STROKE_GRADUAL_VERT: BYTE = 4; +pub const PAN_STROKE_GRADUAL_HORZ: BYTE = 5; +pub const PAN_STROKE_RAPID_VERT: BYTE = 6; +pub const PAN_STROKE_RAPID_HORZ: BYTE = 7; +pub const PAN_STROKE_INSTANT_VERT: BYTE = 8; +pub const PAN_STRAIGHT_ARMS_HORZ: BYTE = 2; +pub const PAN_STRAIGHT_ARMS_WEDGE: BYTE = 3; +pub const PAN_STRAIGHT_ARMS_VERT: BYTE = 4; +pub const PAN_STRAIGHT_ARMS_SINGLE_SERIF: BYTE = 5; +pub const PAN_STRAIGHT_ARMS_DOUBLE_SERIF: BYTE = 6; +pub const PAN_BENT_ARMS_HORZ: BYTE = 7; +pub const PAN_BENT_ARMS_WEDGE: BYTE = 8; +pub const PAN_BENT_ARMS_VERT: BYTE = 9; +pub const PAN_BENT_ARMS_SINGLE_SERIF: BYTE = 10; +pub const PAN_BENT_ARMS_DOUBLE_SERIF: BYTE = 11; +pub const PAN_LETT_NORMAL_CONTACT: BYTE = 2; +pub const PAN_LETT_NORMAL_WEIGHTED: BYTE = 3; +pub const PAN_LETT_NORMAL_BOXED: BYTE = 4; +pub const PAN_LETT_NORMAL_FLATTENED: BYTE = 5; +pub const PAN_LETT_NORMAL_ROUNDED: BYTE = 6; +pub const PAN_LETT_NORMAL_OFF_CENTER: BYTE = 7; +pub const PAN_LETT_NORMAL_SQUARE: BYTE = 8; +pub const PAN_LETT_OBLIQUE_CONTACT: BYTE = 9; +pub const PAN_LETT_OBLIQUE_WEIGHTED: BYTE = 10; +pub const PAN_LETT_OBLIQUE_BOXED: BYTE = 11; +pub const PAN_LETT_OBLIQUE_FLATTENED: BYTE = 12; +pub const PAN_LETT_OBLIQUE_ROUNDED: BYTE = 13; +pub const PAN_LETT_OBLIQUE_OFF_CENTER: BYTE = 14; +pub const PAN_LETT_OBLIQUE_SQUARE: BYTE = 15; +pub const PAN_MIDLINE_STANDARD_TRIMMED: BYTE = 2; +pub const PAN_MIDLINE_STANDARD_POINTED: BYTE = 3; +pub const PAN_MIDLINE_STANDARD_SERIFED: BYTE = 4; +pub const PAN_MIDLINE_HIGH_TRIMMED: BYTE = 5; +pub const PAN_MIDLINE_HIGH_POINTED: BYTE = 6; +pub const PAN_MIDLINE_HIGH_SERIFED: BYTE = 7; +pub const PAN_MIDLINE_CONSTANT_TRIMMED: BYTE = 8; +pub const PAN_MIDLINE_CONSTANT_POINTED: BYTE = 9; +pub const PAN_MIDLINE_CONSTANT_SERIFED: BYTE = 10; +pub const PAN_MIDLINE_LOW_TRIMMED: BYTE = 11; +pub const PAN_MIDLINE_LOW_POINTED: BYTE = 12; +pub const PAN_MIDLINE_LOW_SERIFED: BYTE = 13; +pub const PAN_XHEIGHT_CONSTANT_SMALL: BYTE = 2; +pub const PAN_XHEIGHT_CONSTANT_STD: BYTE = 3; +pub const PAN_XHEIGHT_CONSTANT_LARGE: BYTE = 4; +pub const PAN_XHEIGHT_DUCKING_SMALL: BYTE = 5; +pub const PAN_XHEIGHT_DUCKING_STD: BYTE = 6; +pub const PAN_XHEIGHT_DUCKING_LARGE: BYTE = 7; +pub const ELF_VENDOR_SIZE: usize = 4; +STRUCT!{struct EXTLOGFONTA { + elfLogFont: LOGFONTA, + elfFullName: [BYTE; LF_FULLFACESIZE], + elfStyle: [BYTE; LF_FACESIZE], + elfVersion: DWORD, + elfStyleSize: DWORD, + elfMatch: DWORD, + elfReserved: DWORD, + elfVendorId: [BYTE; ELF_VENDOR_SIZE], + elfCulture: DWORD, + elfPanose: PANOSE, +}} +pub type PEXTLOGFONTA = *mut EXTLOGFONTA; +pub type NPEXTLOGFONTA = *mut EXTLOGFONTA; +pub type LPEXTLOGFONTA = *mut EXTLOGFONTA; +STRUCT!{struct EXTLOGFONTW { + elfLogFont: LOGFONTW, + elfFullNam: [WCHAR; LF_FULLFACESIZE], + elfStyle: [WCHAR; LF_FACESIZE], + elfVersion: DWORD, + elfStyleSize: DWORD, + elfMatch: DWORD, + elfReserved: DWORD, + elfVendorId: [BYTE; ELF_VENDOR_SIZE], + elfCulture: DWORD, + elfPanose: PANOSE, +}} +pub type PEXTLOGFONTW = *mut EXTLOGFONTW; +pub type NPEXTLOGFONTW = *mut EXTLOGFONTW; +pub type LPEXTLOGFONTW = *mut EXTLOGFONTW; +pub const ELF_VERSION: DWORD = 0; +pub const ELF_CULTURE_LATIN: DWORD = 0; +pub const RASTER_FONTTYPE: DWORD = 0x0001; +pub const DEVICE_FONTTYPE: DWORD = 0x0002; +pub const TRUETYPE_FONTTYPE: DWORD = 0x0004; +#[inline] +pub fn RGB(r: BYTE, g: BYTE, b: BYTE) -> COLORREF { + r as COLORREF | ((g as COLORREF) << 8) | ((b as COLORREF) << 16) +} +#[inline] +pub fn PALETTERGB(r: BYTE, g: BYTE, b: BYTE) -> COLORREF { + 0x02000000 | RGB(r, g, b) +} +#[inline] +pub fn PALETTEINDEX(i: WORD) -> COLORREF { + 0x01000000 | i as DWORD +} +pub const PC_RESERVED: DWORD = 0x01; +pub const PC_EXPLICIT: DWORD = 0x02; +pub const PC_NOCOLLAPSE: DWORD = 0x04; +#[inline] +pub fn GetRValue(rgb: COLORREF) -> BYTE { + LOBYTE(rgb as WORD) +} +#[inline] +pub fn GetGValue(rgb: COLORREF) -> BYTE { + LOBYTE((rgb as WORD) >> 8) +} +#[inline] +pub fn GetBValue(rgb: COLORREF) -> BYTE { + LOBYTE((rgb >> 16) as WORD) +} +pub const TRANSPARENT: DWORD = 1; +pub const OPAQUE: DWORD = 2; +pub const BKMODE_LAST: DWORD = 2; +pub const GM_COMPATIBLE: DWORD = 1; +pub const GM_ADVANCED: DWORD = 2; +pub const GM_LAST: DWORD = 2; +pub const PT_CLOSEFIGURE: DWORD = 0x01; +pub const PT_LINETO: DWORD = 0x02; +pub const PT_BEZIERTO: DWORD = 0x04; +pub const PT_MOVETO: DWORD = 0x06; +pub const MM_TEXT: DWORD = 1; +pub const MM_LOMETRIC: DWORD = 2; +pub const MM_HIMETRIC: DWORD = 3; +pub const MM_LOENGLISH: DWORD = 4; +pub const MM_HIENGLISH: DWORD = 5; +pub const MM_TWIPS: DWORD = 6; +pub const MM_ISOTROPIC: DWORD = 7; +pub const MM_ANISOTROPIC: DWORD = 8; +pub const MM_MIN: DWORD = MM_TEXT; +pub const MM_MAX: DWORD = MM_ANISOTROPIC; +pub const MM_MAX_FIXEDSCALE: DWORD = MM_TWIPS; +pub const ABSOLUTE: DWORD = 1; +pub const RELATIVE: DWORD = 2; +pub const WHITE_BRUSH: DWORD = 0; +pub const LTGRAY_BRUSH: DWORD = 1; +pub const GRAY_BRUSH: DWORD = 2; +pub const DKGRAY_BRUSH: DWORD = 3; +pub const BLACK_BRUSH: DWORD = 4; +pub const NULL_BRUSH: DWORD = 5; +pub const HOLLOW_BRUSH: DWORD = NULL_BRUSH; +pub const WHITE_PEN: DWORD = 6; +pub const BLACK_PEN: DWORD = 7; +pub const NULL_PEN: DWORD = 8; +pub const OEM_FIXED_FONT: DWORD = 10; +pub const ANSI_FIXED_FONT: DWORD = 11; +pub const ANSI_VAR_FONT: DWORD = 12; +pub const SYSTEM_FONT: DWORD = 13; +pub const DEVICE_DEFAULT_FONT: DWORD = 14; +pub const DEFAULT_PALETTE: DWORD = 15; +pub const SYSTEM_FIXED_FONT: DWORD = 16; +pub const DEFAULT_GUI_FONT: DWORD = 17; +pub const DC_BRUSH: DWORD = 18; +pub const DC_PEN: DWORD = 19; +pub const STOCK_LAST: DWORD = 19; +pub const CLR_INVALID: COLORREF = 0xFFFFFFFF; +pub const BS_SOLID: DWORD = 0; +pub const BS_NULL: DWORD = 1; +pub const BS_HOLLOW: DWORD = BS_NULL; +pub const BS_HATCHED: DWORD = 2; +pub const BS_PATTERN: DWORD = 3; +pub const BS_INDEXED: DWORD = 4; +pub const BS_DIBPATTERN: DWORD = 5; +pub const BS_DIBPATTERNPT: DWORD = 6; +pub const BS_PATTERN8X8: DWORD = 7; +pub const BS_DIBPATTERN8X8: DWORD = 8; +pub const BS_MONOPATTERN: DWORD = 9; +pub const HS_HORIZONTAL: DWORD = 0; +pub const HS_VERTICAL: DWORD = 1; +pub const HS_FDIAGONAL: DWORD = 2; +pub const HS_BDIAGONAL: DWORD = 3; +pub const HS_CROSS: DWORD = 4; +pub const HS_DIAGCROSS: DWORD = 5; +pub const HS_API_MAX: DWORD = 12; +pub const PS_SOLID: DWORD = 0; +pub const PS_DASH: DWORD = 1; +pub const PS_DOT: DWORD = 2; +pub const PS_DASHDOT: DWORD = 3; +pub const PS_DASHDOTDOT: DWORD = 4; +pub const PS_NULL: DWORD = 5; +pub const PS_INSIDEFRAME: DWORD = 6; +pub const PS_USERSTYLE: DWORD = 7; +pub const PS_ALTERNATE: DWORD = 8; +pub const PS_STYLE_MASK: DWORD = 0x0000000F; +pub const PS_ENDCAP_ROUND: DWORD = 0x00000000; +pub const PS_ENDCAP_SQUARE: DWORD = 0x00000100; +pub const PS_ENDCAP_FLAT: DWORD = 0x00000200; +pub const PS_ENDCAP_MASK: DWORD = 0x00000F00; +pub const PS_JOIN_ROUND: DWORD = 0x00000000; +pub const PS_JOIN_BEVEL: DWORD = 0x00001000; +pub const PS_JOIN_MITER: DWORD = 0x00002000; +pub const PS_JOIN_MASK: DWORD = 0x0000F000; +pub const PS_COSMETIC: DWORD = 0x00000000; +pub const PS_GEOMETRIC: DWORD = 0x00010000; +pub const PS_TYPE_MASK: DWORD = 0x000F0000; +pub const AD_COUNTERCLOCKWISE: DWORD = 1; +pub const AD_CLOCKWISE: DWORD = 2; +pub const DRIVERVERSION: c_int = 0; +pub const TECHNOLOGY: c_int = 2; +pub const HORZSIZE: c_int = 4; +pub const VERTSIZE: c_int = 6; +pub const HORZRES: c_int = 8; +pub const VERTRES: c_int = 10; +pub const BITSPIXEL: c_int = 12; +pub const PLANES: c_int = 14; +pub const NUMBRUSHES: c_int = 16; +pub const NUMPENS: c_int = 18; +pub const NUMMARKERS: c_int = 20; +pub const NUMFONTS: c_int = 22; +pub const NUMCOLORS: c_int = 24; +pub const PDEVICESIZE: c_int = 26; +pub const CURVECAPS: c_int = 28; +pub const LINECAPS: c_int = 30; +pub const POLYGONALCAPS: c_int = 32; +pub const TEXTCAPS: c_int = 34; +pub const CLIPCAPS: c_int = 36; +pub const RASTERCAPS: c_int = 38; +pub const ASPECTX: c_int = 40; +pub const ASPECTY: c_int = 42; +pub const ASPECTXY: c_int = 44; +pub const LOGPIXELSX: c_int = 88; +pub const LOGPIXELSY: c_int = 90; +pub const SIZEPALETTE: c_int = 104; +pub const NUMRESERVED: c_int = 106; +pub const COLORRES: c_int = 108; +pub const PHYSICALWIDTH: c_int = 110; +pub const PHYSICALHEIGHT: c_int = 111; +pub const PHYSICALOFFSETX: c_int = 112; +pub const PHYSICALOFFSETY: c_int = 113; +pub const SCALINGFACTORX: c_int = 114; +pub const SCALINGFACTORY: c_int = 115; +pub const VREFRESH: c_int = 116; +pub const DESKTOPVERTRES: c_int = 117; +pub const DESKTOPHORZRES: c_int = 118; +pub const BLTALIGNMENT: c_int = 119; +pub const SHADEBLENDCAPS: c_int = 120; +pub const COLORMGMTCAPS: c_int = 121; +pub const DT_PLOTTER: DWORD = 0; +pub const DT_RASDISPLAY: DWORD = 1; +pub const DT_RASPRINTER: DWORD = 2; +pub const DT_RASCAMERA: DWORD = 3; +pub const DT_CHARSTREAM: DWORD = 4; +pub const DT_METAFILE: DWORD = 5; +pub const DT_DISPFILE: DWORD = 6; +pub const CC_NONE: DWORD = 0; +pub const CC_CIRCLES: DWORD = 1; +pub const CC_PIE: DWORD = 2; +pub const CC_CHORD: DWORD = 4; +pub const CC_ELLIPSES: DWORD = 8; +pub const CC_WIDE: DWORD = 16; +pub const CC_STYLED: DWORD = 32; +pub const CC_WIDESTYLED: DWORD = 64; +pub const CC_INTERIORS: DWORD = 128; +pub const CC_ROUNDRECT: DWORD = 256; +pub const LC_NONE: DWORD = 0; +pub const LC_POLYLINE: DWORD = 2; +pub const LC_MARKER: DWORD = 4; +pub const LC_POLYMARKER: DWORD = 8; +pub const LC_WIDE: DWORD = 16; +pub const LC_STYLED: DWORD = 32; +pub const LC_WIDESTYLED: DWORD = 64; +pub const LC_INTERIORS: DWORD = 128; +pub const PC_NONE: DWORD = 0; +pub const PC_POLYGON: DWORD = 1; +pub const PC_RECTANGLE: DWORD = 2; +pub const PC_WINDPOLYGON: DWORD = 4; +pub const PC_TRAPEZOID: DWORD = 4; +pub const PC_SCANLINE: DWORD = 8; +pub const PC_WIDE: DWORD = 16; +pub const PC_STYLED: DWORD = 32; +pub const PC_WIDESTYLED: DWORD = 64; +pub const PC_INTERIORS: DWORD = 128; +pub const PC_POLYPOLYGON: DWORD = 256; +pub const PC_PATHS: DWORD = 512; +pub const CP_NONE: DWORD = 0; +pub const CP_RECTANGLE: DWORD = 1; +pub const CP_REGION: DWORD = 2; +pub const TC_OP_CHARACTER: DWORD = 0x00000001; +pub const TC_OP_STROKE: DWORD = 0x00000002; +pub const TC_CP_STROKE: DWORD = 0x00000004; +pub const TC_CR_90: DWORD = 0x00000008; +pub const TC_CR_ANY: DWORD = 0x00000010; +pub const TC_SF_X_YINDEP: DWORD = 0x00000020; +pub const TC_SA_DOUBLE: DWORD = 0x00000040; +pub const TC_SA_INTEGER: DWORD = 0x00000080; +pub const TC_SA_CONTIN: DWORD = 0x00000100; +pub const TC_EA_DOUBLE: DWORD = 0x00000200; +pub const TC_IA_ABLE: DWORD = 0x00000400; +pub const TC_UA_ABLE: DWORD = 0x00000800; +pub const TC_SO_ABLE: DWORD = 0x00001000; +pub const TC_RA_ABLE: DWORD = 0x00002000; +pub const TC_VA_ABLE: DWORD = 0x00004000; +pub const TC_RESERVED: DWORD = 0x00008000; +pub const TC_SCROLLBLT: DWORD = 0x00010000; +pub const RC_BITBLT: DWORD = 1; +pub const RC_BANDING: DWORD = 2; +pub const RC_SCALING: DWORD = 4; +pub const RC_BITMAP64: DWORD = 8; +pub const RC_GDI20_OUTPUT: DWORD = 0x0010; +pub const RC_GDI20_STATE: DWORD = 0x0020; +pub const RC_SAVEBITMAP: DWORD = 0x0040; +pub const RC_DI_BITMAP: DWORD = 0x0080; +pub const RC_PALETTE: DWORD = 0x0100; +pub const RC_DIBTODEV: DWORD = 0x0200; +pub const RC_BIGFONT: DWORD = 0x0400; +pub const RC_STRETCHBLT: DWORD = 0x0800; +pub const RC_FLOODFILL: DWORD = 0x1000; +pub const RC_STRETCHDIB: DWORD = 0x2000; +pub const RC_OP_DX_OUTPUT: DWORD = 0x4000; +pub const RC_DEVBITS: DWORD = 0x8000; +pub const SB_NONE: DWORD = 0x00000000; +pub const SB_CONST_ALPHA: DWORD = 0x00000001; +pub const SB_PIXEL_ALPHA: DWORD = 0x00000002; +pub const SB_PREMULT_ALPHA: DWORD = 0x00000004; +pub const SB_GRAD_RECT: DWORD = 0x00000010; +pub const SB_GRAD_TRI: DWORD = 0x00000020; +pub const CM_NONE: DWORD = 0x00000000; +pub const CM_DEVICE_ICM: DWORD = 0x00000001; +pub const CM_GAMMA_RAMP: DWORD = 0x00000002; +pub const CM_CMYK_COLOR: DWORD = 0x00000004; +pub const DIB_RGB_COLORS: DWORD = 0; +pub const DIB_PAL_COLORS: DWORD = 1; +pub const SYSPAL_ERROR: DWORD = 0; +pub const SYSPAL_STATIC: DWORD = 1; +pub const SYSPAL_NOSTATIC: DWORD = 2; +pub const SYSPAL_NOSTATIC256: DWORD = 3; +pub const CBM_INIT: DWORD = 0x04; +pub const FLOODFILLBORDER: DWORD = 0; +pub const FLOODFILLSURFACE: DWORD = 1; +pub const CCHDEVICENAME: usize = 32; +pub const CCHFORMNAME: usize = 32; +STRUCT!{struct DEVMODE_u1_s1 { + dmOrientation: c_short, + dmPaperSize: c_short, + dmPaperLength: c_short, + dmPaperWidth: c_short, + dmScale: c_short, + dmCopies: c_short, + dmDefaultSource: c_short, + dmPrintQuality: c_short, +}} +STRUCT!{struct DEVMODE_u1_s2 { + dmPosition: POINTL, + dmDisplayOrientation: DWORD, + dmDisplayFixedOutput: DWORD, +}} +UNION!{union DEVMODE_u1 { + [u32; 4], + s1 s1_mut: DEVMODE_u1_s1, + s2 s2_mut: DEVMODE_u1_s2, +}} +UNION!{union DEVMODE_u2 { + [u32; 1], + dmDisplayFlags dmDisplayFlags_mut: DWORD, + dmNup dmNup_mut: DWORD, +}} +STRUCT!{struct DEVMODEA { + dmDeviceName: [CHAR; CCHDEVICENAME], + dmSpecVersion: WORD, + dmDriverVersion: WORD, + dmSize: WORD, + dmDriverExtra: WORD, + dmFields: DWORD, + u1: DEVMODE_u1, + dmColor: c_short, + dmDuplex: c_short, + dmYResolution: c_short, + dmTTOption: c_short, + dmCollate: c_short, + dmFormName: [CHAR; CCHFORMNAME], + dmLogPixels: WORD, + dmBitsPerPel: DWORD, + dmPelsWidth: DWORD, + dmPelsHeight: DWORD, + u2: DEVMODE_u2, + dmDisplayFrequency: DWORD, + dmICMMethod: DWORD, + dmICMIntent: DWORD, + dmMediaType: DWORD, + dmDitherType: DWORD, + dmReserved1: DWORD, + dmReserved2: DWORD, + dmPanningWidth: DWORD, + dmPanningHeight: DWORD, +}} +pub type PDEVMODEA = *mut DEVMODEA; +pub type NPDEVMODEA = *mut DEVMODEA; +pub type LPDEVMODEA = *mut DEVMODEA; +STRUCT!{struct DEVMODEW { + dmDeviceName: [WCHAR; CCHDEVICENAME], + dmSpecVersion: WORD, + dmDriverVersion: WORD, + dmSize: WORD, + dmDriverExtra: WORD, + dmFields: DWORD, + u1: DEVMODE_u1, + dmColor: c_short, + dmDuplex: c_short, + dmYResolution: c_short, + dmTTOption: c_short, + dmCollate: c_short, + dmFormName: [WCHAR; CCHFORMNAME], + dmLogPixels: WORD, + dmBitsPerPel: DWORD, + dmPelsWidth: DWORD, + dmPelsHeight: DWORD, + u2: DEVMODE_u2, + dmDisplayFrequency: DWORD, + dmICMMethod: DWORD, + dmICMIntent: DWORD, + dmMediaType: DWORD, + dmDitherType: DWORD, + dmReserved1: DWORD, + dmReserved2: DWORD, + dmPanningWidth: DWORD, + dmPanningHeight: DWORD, +}} +pub type PDEVMODEW = *mut DEVMODEW; +pub type NPDEVMODEW = *mut DEVMODEW; +pub type LPDEVMODEW = *mut DEVMODEW; +pub const DM_SPECVERSION: DWORD = 0x0401; +pub const DM_ORIENTATION: DWORD = 0x00000001; +pub const DM_PAPERSIZE: DWORD = 0x00000002; +pub const DM_PAPERLENGTH: DWORD = 0x00000004; +pub const DM_PAPERWIDTH: DWORD = 0x00000008; +pub const DM_SCALE: DWORD = 0x00000010; +pub const DM_POSITION: DWORD = 0x00000020; +pub const DM_NUP: DWORD = 0x00000040; +pub const DM_DISPLAYORIENTATION: DWORD = 0x00000080; +pub const DM_COPIES: DWORD = 0x00000100; +pub const DM_DEFAULTSOURCE: DWORD = 0x00000200; +pub const DM_PRINTQUALITY: DWORD = 0x00000400; +pub const DM_COLOR: DWORD = 0x00000800; +pub const DM_DUPLEX: DWORD = 0x00001000; +pub const DM_YRESOLUTION: DWORD = 0x00002000; +pub const DM_TTOPTION: DWORD = 0x00004000; +pub const DM_COLLATE: DWORD = 0x00008000; +pub const DM_FORMNAME: DWORD = 0x00010000; +pub const DM_LOGPIXELS: DWORD = 0x00020000; +pub const DM_BITSPERPEL: DWORD = 0x00040000; +pub const DM_PELSWIDTH: DWORD = 0x00080000; +pub const DM_PELSHEIGHT: DWORD = 0x00100000; +pub const DM_DISPLAYFLAGS: DWORD = 0x00200000; +pub const DM_DISPLAYFREQUENCY: DWORD = 0x00400000; +pub const DM_ICMMETHOD: DWORD = 0x00800000; +pub const DM_ICMINTENT: DWORD = 0x01000000; +pub const DM_MEDIATYPE: DWORD = 0x02000000; +pub const DM_DITHERTYPE: DWORD = 0x04000000; +pub const DM_PANNINGWIDTH: DWORD = 0x08000000; +pub const DM_PANNINGHEIGHT: DWORD = 0x10000000; +pub const DM_DISPLAYFIXEDOUTPUT: DWORD = 0x20000000; +pub const DMORIENT_PORTRAIT: DWORD = 1; +pub const DMORIENT_LANDSCAPE: DWORD = 2; +pub const DMPAPER_FIRST: DWORD = DMPAPER_LETTER; +pub const DMPAPER_LETTER: DWORD = 1; +pub const DMPAPER_LETTERSMALL: DWORD = 2; +pub const DMPAPER_TABLOID: DWORD = 3; +pub const DMPAPER_LEDGER: DWORD = 4; +pub const DMPAPER_LEGAL: DWORD = 5; +pub const DMPAPER_STATEMENT: DWORD = 6; +pub const DMPAPER_EXECUTIVE: DWORD = 7; +pub const DMPAPER_A3: DWORD = 8; +pub const DMPAPER_A4: DWORD = 9; +pub const DMPAPER_A4SMALL: DWORD = 10; +pub const DMPAPER_A5: DWORD = 11; +pub const DMPAPER_B4: DWORD = 12; +pub const DMPAPER_B5: DWORD = 13; +pub const DMPAPER_FOLIO: DWORD = 14; +pub const DMPAPER_QUARTO: DWORD = 15; +pub const DMPAPER_10X14: DWORD = 16; +pub const DMPAPER_11X17: DWORD = 17; +pub const DMPAPER_NOTE: DWORD = 18; +pub const DMPAPER_ENV_9: DWORD = 19; +pub const DMPAPER_ENV_10: DWORD = 20; +pub const DMPAPER_ENV_11: DWORD = 21; +pub const DMPAPER_ENV_12: DWORD = 22; +pub const DMPAPER_ENV_14: DWORD = 23; +pub const DMPAPER_CSHEET: DWORD = 24; +pub const DMPAPER_DSHEET: DWORD = 25; +pub const DMPAPER_ESHEET: DWORD = 26; +pub const DMPAPER_ENV_DL: DWORD = 27; +pub const DMPAPER_ENV_C5: DWORD = 28; +pub const DMPAPER_ENV_C3: DWORD = 29; +pub const DMPAPER_ENV_C4: DWORD = 30; +pub const DMPAPER_ENV_C6: DWORD = 31; +pub const DMPAPER_ENV_C65: DWORD = 32; +pub const DMPAPER_ENV_B4: DWORD = 33; +pub const DMPAPER_ENV_B5: DWORD = 34; +pub const DMPAPER_ENV_B6: DWORD = 35; +pub const DMPAPER_ENV_ITALY: DWORD = 36; +pub const DMPAPER_ENV_MONARCH: DWORD = 37; +pub const DMPAPER_ENV_PERSONAL: DWORD = 38; +pub const DMPAPER_FANFOLD_US: DWORD = 39; +pub const DMPAPER_FANFOLD_STD_GERMAN: DWORD = 40; +pub const DMPAPER_FANFOLD_LGL_GERMAN: DWORD = 41; +pub const DMPAPER_ISO_B4: DWORD = 42; +pub const DMPAPER_JAPANESE_POSTCARD: DWORD = 43; +pub const DMPAPER_9X11: DWORD = 44; +pub const DMPAPER_10X11: DWORD = 45; +pub const DMPAPER_15X11: DWORD = 46; +pub const DMPAPER_ENV_INVITE: DWORD = 47; +pub const DMPAPER_RESERVED_48: DWORD = 48; +pub const DMPAPER_RESERVED_49: DWORD = 49; +pub const DMPAPER_LETTER_EXTRA: DWORD = 50; +pub const DMPAPER_LEGAL_EXTRA: DWORD = 51; +pub const DMPAPER_TABLOID_EXTRA: DWORD = 52; +pub const DMPAPER_A4_EXTRA: DWORD = 53; +pub const DMPAPER_LETTER_TRANSVERSE: DWORD = 54; +pub const DMPAPER_A4_TRANSVERSE: DWORD = 55; +pub const DMPAPER_LETTER_EXTRA_TRANSVERSE: DWORD = 56; +pub const DMPAPER_A_PLUS: DWORD = 57; +pub const DMPAPER_B_PLUS: DWORD = 58; +pub const DMPAPER_LETTER_PLUS: DWORD = 59; +pub const DMPAPER_A4_PLUS: DWORD = 60; +pub const DMPAPER_A5_TRANSVERSE: DWORD = 61; +pub const DMPAPER_B5_TRANSVERSE: DWORD = 62; +pub const DMPAPER_A3_EXTRA: DWORD = 63; +pub const DMPAPER_A5_EXTRA: DWORD = 64; +pub const DMPAPER_B5_EXTRA: DWORD = 65; +pub const DMPAPER_A2: DWORD = 66; +pub const DMPAPER_A3_TRANSVERSE: DWORD = 67; +pub const DMPAPER_A3_EXTRA_TRANSVERSE: DWORD = 68; +pub const DMPAPER_DBL_JAPANESE_POSTCARD: DWORD = 69; +pub const DMPAPER_A6: DWORD = 70; +pub const DMPAPER_JENV_KAKU2: DWORD = 71; +pub const DMPAPER_JENV_KAKU3: DWORD = 72; +pub const DMPAPER_JENV_CHOU3: DWORD = 73; +pub const DMPAPER_JENV_CHOU4: DWORD = 74; +pub const DMPAPER_LETTER_ROTATED: DWORD = 75; +pub const DMPAPER_A3_ROTATED: DWORD = 76; +pub const DMPAPER_A4_ROTATED: DWORD = 77; +pub const DMPAPER_A5_ROTATED: DWORD = 78; +pub const DMPAPER_B4_JIS_ROTATED: DWORD = 79; +pub const DMPAPER_B5_JIS_ROTATED: DWORD = 80; +pub const DMPAPER_JAPANESE_POSTCARD_ROTATED: DWORD = 81; +pub const DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED: DWORD = 82; +pub const DMPAPER_A6_ROTATED: DWORD = 83; +pub const DMPAPER_JENV_KAKU2_ROTATED: DWORD = 84; +pub const DMPAPER_JENV_KAKU3_ROTATED: DWORD = 85; +pub const DMPAPER_JENV_CHOU3_ROTATED: DWORD = 86; +pub const DMPAPER_JENV_CHOU4_ROTATED: DWORD = 87; +pub const DMPAPER_B6_JIS: DWORD = 88; +pub const DMPAPER_B6_JIS_ROTATED: DWORD = 89; +pub const DMPAPER_12X11: DWORD = 90; +pub const DMPAPER_JENV_YOU4: DWORD = 91; +pub const DMPAPER_JENV_YOU4_ROTATED: DWORD = 92; +pub const DMPAPER_P16K: DWORD = 93; +pub const DMPAPER_P32K: DWORD = 94; +pub const DMPAPER_P32KBIG: DWORD = 95; +pub const DMPAPER_PENV_1: DWORD = 96; +pub const DMPAPER_PENV_2: DWORD = 97; +pub const DMPAPER_PENV_3: DWORD = 98; +pub const DMPAPER_PENV_4: DWORD = 99; +pub const DMPAPER_PENV_5: DWORD = 100; +pub const DMPAPER_PENV_6: DWORD = 101; +pub const DMPAPER_PENV_7: DWORD = 102; +pub const DMPAPER_PENV_8: DWORD = 103; +pub const DMPAPER_PENV_9: DWORD = 104; +pub const DMPAPER_PENV_10: DWORD = 105; +pub const DMPAPER_P16K_ROTATED: DWORD = 106; +pub const DMPAPER_P32K_ROTATED: DWORD = 107; +pub const DMPAPER_P32KBIG_ROTATED: DWORD = 108; +pub const DMPAPER_PENV_1_ROTATED: DWORD = 109; +pub const DMPAPER_PENV_2_ROTATED: DWORD = 110; +pub const DMPAPER_PENV_3_ROTATED: DWORD = 111; +pub const DMPAPER_PENV_4_ROTATED: DWORD = 112; +pub const DMPAPER_PENV_5_ROTATED: DWORD = 113; +pub const DMPAPER_PENV_6_ROTATED: DWORD = 114; +pub const DMPAPER_PENV_7_ROTATED: DWORD = 115; +pub const DMPAPER_PENV_8_ROTATED: DWORD = 116; +pub const DMPAPER_PENV_9_ROTATED: DWORD = 117; +pub const DMPAPER_PENV_10_ROTATED: DWORD = 118; +pub const DMPAPER_LAST: DWORD = DMPAPER_PENV_10_ROTATED; +pub const DMPAPER_USER: DWORD = 256; +pub const DMBIN_FIRST: DWORD = DMBIN_UPPER; +pub const DMBIN_UPPER: DWORD = 1; +pub const DMBIN_ONLYONE: DWORD = 1; +pub const DMBIN_LOWER: DWORD = 2; +pub const DMBIN_MIDDLE: DWORD = 3; +pub const DMBIN_MANUAL: DWORD = 4; +pub const DMBIN_ENVELOPE: DWORD = 5; +pub const DMBIN_ENVMANUAL: DWORD = 6; +pub const DMBIN_AUTO: DWORD = 7; +pub const DMBIN_TRACTOR: DWORD = 8; +pub const DMBIN_SMALLFMT: DWORD = 9; +pub const DMBIN_LARGEFMT: DWORD = 10; +pub const DMBIN_LARGECAPACITY: DWORD = 11; +pub const DMBIN_CASSETTE: DWORD = 14; +pub const DMBIN_FORMSOURCE: DWORD = 15; +pub const DMBIN_LAST: DWORD = DMBIN_FORMSOURCE; +pub const DMBIN_USER: DWORD = 256; +pub const DMRES_DRAFT: c_int = -1; +pub const DMRES_LOW: c_int = -2; +pub const DMRES_MEDIUM: c_int = -3; +pub const DMRES_HIGH: c_int = -4; +pub const DMCOLOR_MONOCHROME: DWORD = 1; +pub const DMCOLOR_COLOR: DWORD = 2; +pub const DMDUP_SIMPLEX: DWORD = 1; +pub const DMDUP_VERTICAL: DWORD = 2; +pub const DMDUP_HORIZONTAL: DWORD = 3; +pub const DMTT_BITMAP: DWORD = 1; +pub const DMTT_DOWNLOAD: DWORD = 2; +pub const DMTT_SUBDEV: DWORD = 3; +pub const DMTT_DOWNLOAD_OUTLINE: DWORD = 4; +pub const DMCOLLATE_FALSE: DWORD = 0; +pub const DMCOLLATE_TRUE: DWORD = 1; +pub const DMDO_DEFAULT: DWORD = 0; +pub const DMDO_90: DWORD = 1; +pub const DMDO_180: DWORD = 2; +pub const DMDO_270: DWORD = 3; +pub const DMDFO_DEFAULT: DWORD = 0; +pub const DMDFO_STRETCH: DWORD = 1; +pub const DMDFO_CENTER: DWORD = 2; +pub const DM_INTERLACED: DWORD = 0x00000002; +pub const DMDISPLAYFLAGS_TEXTMODE: DWORD = 0x00000004; +pub const DMNUP_SYSTEM: DWORD = 1; +pub const DMNUP_ONEUP: DWORD = 2; +pub const DMICMMETHOD_NONE: DWORD = 1; +pub const DMICMMETHOD_SYSTEM: DWORD = 2; +pub const DMICMMETHOD_DRIVER: DWORD = 3; +pub const DMICMMETHOD_DEVICE: DWORD = 4; +pub const DMICMMETHOD_USER: DWORD = 256; +pub const DMICM_SATURATE: DWORD = 1; +pub const DMICM_CONTRAST: DWORD = 2; +pub const DMICM_COLORIMETRIC: DWORD = 3; +pub const DMICM_ABS_COLORIMETRIC: DWORD = 4; +pub const DMICM_USER: DWORD = 256; +pub const DMMEDIA_STANDARD: DWORD = 1; +pub const DMMEDIA_TRANSPARENCY: DWORD = 2; +pub const DMMEDIA_GLOSSY: DWORD = 3; +pub const DMMEDIA_USER: DWORD = 256; +pub const DMDITHER_NONE: DWORD = 1; +pub const DMDITHER_COARSE: DWORD = 2; +pub const DMDITHER_FINE: DWORD = 3; +pub const DMDITHER_LINEART: DWORD = 4; +pub const DMDITHER_ERRORDIFFUSION: DWORD = 5; +pub const DMDITHER_RESERVED6: DWORD = 6; +pub const DMDITHER_RESERVED7: DWORD = 7; +pub const DMDITHER_RESERVED8: DWORD = 8; +pub const DMDITHER_RESERVED9: DWORD = 9; +pub const DMDITHER_GRAYSCALE: DWORD = 10; +pub const DMDITHER_USER: DWORD = 256; +STRUCT!{struct DISPLAY_DEVICEA { + cb: DWORD, + DeviceName: [CHAR; 32], + DeviceString: [CHAR; 128], + StateFlags: DWORD, + DeviceID: [CHAR; 128], + DeviceKey: [CHAR; 128], +}} +pub type PDISPLAY_DEVICEA = *mut DISPLAY_DEVICEA; +pub type LPDISPLAY_DEVICEA = *mut DISPLAY_DEVICEA; +STRUCT!{struct DISPLAY_DEVICEW { + cb: DWORD, + DeviceName: [WCHAR; 32], + DeviceString: [WCHAR; 128], + StateFlags: DWORD, + DeviceID: [WCHAR; 128], + DeviceKey: [WCHAR; 128], +}} +pub type PDISPLAY_DEVICEW = *mut DISPLAY_DEVICEW; +pub type LPDISPLAY_DEVICEW = *mut DISPLAY_DEVICEW; +pub const DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: DWORD = 0x00000001; +pub const DISPLAY_DEVICE_MULTI_DRIVER: DWORD = 0x00000002; +pub const DISPLAY_DEVICE_PRIMARY_DEVICE: DWORD = 0x00000004; +pub const DISPLAY_DEVICE_MIRRORING_DRIVER: DWORD = 0x00000008; +pub const DISPLAY_DEVICE_VGA_COMPATIBLE: DWORD = 0x00000010; +pub const DISPLAY_DEVICE_REMOVABLE: DWORD = 0x00000020; +pub const DISPLAY_DEVICE_ACC_DRIVER: DWORD = 0x00000040; +pub const DISPLAY_DEVICE_MODESPRUNED: DWORD = 0x08000000; +pub const DISPLAY_DEVICE_RDPUDD: DWORD = 0x01000000; +pub const DISPLAY_DEVICE_REMOTE: DWORD = 0x04000000; +pub const DISPLAY_DEVICE_DISCONNECT: DWORD = 0x02000000; +pub const DISPLAY_DEVICE_TS_COMPATIBLE: DWORD = 0x00200000; +pub const DISPLAY_DEVICE_UNSAFE_MODES_ON: DWORD = 0x00080000; +pub const DISPLAY_DEVICE_ACTIVE: DWORD = 0x00000001; +pub const DISPLAY_DEVICE_ATTACHED: DWORD = 0x00000002; +pub const DISPLAYCONFIG_MAXPATH: usize = 1024; +STRUCT!{struct DISPLAYCONFIG_RATIONAL { + Numerator: UINT32, + Denominator: UINT32, +}} +ENUM!{enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY { + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1i32 as u32, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF, +}} +ENUM!{enum DISPLAYCONFIG_SCANLINE_ORDERING { + DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, + DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, + DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF, +}} +STRUCT!{struct DISPLAYCONFIG_2DREGION { + cx: UINT32, + cy: UINT32, +}} +STRUCT!{struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO_AdditionalSignalInfo { + bitfield: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_VIDEO_SIGNAL_INFO_AdditionalSignalInfo bitfield: UINT32 [ + videoStandard set_videoStandard[0..16], + vSyncFreqDivider set_vSyncFreqDivider[16..22], +]} +UNION!{union DISPLAYCONFIG_VIDEO_SIGNAL_INFO_u { + [u32; 1], + AdditionalSignalInfo AdditionalSignalInfo_mut: + DISPLAYCONFIG_VIDEO_SIGNAL_INFO_AdditionalSignalInfo, + videoStandard videoStandard_mut: UINT32, +}} +STRUCT!{struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO { + pixelRate: UINT64, + hSyncFreq: DISPLAYCONFIG_RATIONAL, + vSyncFreq: DISPLAYCONFIG_RATIONAL, + activeSize: DISPLAYCONFIG_2DREGION, + totalSize: DISPLAYCONFIG_2DREGION, + u: DISPLAYCONFIG_VIDEO_SIGNAL_INFO_u, + scanLineOrdering: DISPLAYCONFIG_SCANLINE_ORDERING, +}} +ENUM!{enum DISPLAYCONFIG_SCALING { + DISPLAYCONFIG_SCALING_IDENTITY = 1, + DISPLAYCONFIG_SCALING_CENTERED = 2, + DISPLAYCONFIG_SCALING_STRETCHED = 3, + DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, + DISPLAYCONFIG_SCALING_CUSTOM = 5, + DISPLAYCONFIG_SCALING_PREFERRED = 128, + DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF, +}} +ENUM!{enum DISPLAYCONFIG_ROTATION { + DISPLAYCONFIG_ROTATION_IDENTITY = 1, + DISPLAYCONFIG_ROTATION_ROTATE90 = 2, + DISPLAYCONFIG_ROTATION_ROTATE180 = 3, + DISPLAYCONFIG_ROTATION_ROTATE270 = 4, + DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF, +}} +ENUM!{enum DISPLAYCONFIG_MODE_INFO_TYPE { + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, + DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, + DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3, + DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF, +}} +ENUM!{enum DISPLAYCONFIG_PIXELFORMAT { + DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, + DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, + DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, + DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, + DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, + DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff, +}} +STRUCT!{struct DISPLAYCONFIG_SOURCE_MODE { + width: UINT32, + height: UINT32, + pixelFormat: DISPLAYCONFIG_PIXELFORMAT, + position: POINTL, +}} +STRUCT!{struct DISPLAYCONFIG_TARGET_MODE { + targetVideoSignalInfo: DISPLAYCONFIG_VIDEO_SIGNAL_INFO, +}} +STRUCT!{struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO { + PathSourceSize: POINTL, + DesktopImageRegion: RECTL, + DesktopImageClip: RECTL, +}} +UNION!{union DISPLAYCONFIG_MODE_INFO_u { + [u64; 6], + targetMode targetMode_mut: DISPLAYCONFIG_TARGET_MODE, + sourceMode sourceMode_mut: DISPLAYCONFIG_SOURCE_MODE, + desktopImageInfo desktopImageInfo_mut: DISPLAYCONFIG_DESKTOP_IMAGE_INFO, +}} +STRUCT!{struct DISPLAYCONFIG_MODE_INFO { + infoType: DISPLAYCONFIG_MODE_INFO_TYPE, + id: UINT32, + adapterId: LUID, + u: DISPLAYCONFIG_MODE_INFO_u, +}} +pub const DISPLAYCONFIG_PATH_MODE_IDX_INVALID: DWORD = 0xffffffff; +pub const DISPLAYCONFIG_PATH_TARGET_MODE_IDX_INVALID: DWORD = 0xffff; +pub const DISPLAYCONFIG_PATH_DESKTOP_IMAGE_IDX_INVALID: DWORD = 0xffff; +pub const DISPLAYCONFIG_PATH_SOURCE_MODE_IDX_INVALID: DWORD = 0xffff; +pub const DISPLAYCONFIG_PATH_CLONE_GROUP_INVALID: DWORD = 0xffff; +STRUCT!{struct DISPLAYCONFIG_PATH_SOURCE_INFO { + adapterId: LUID, + id: UINT32, + modeInfoIdx: UINT32, + statusFlags: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_PATH_SOURCE_INFO modeInfoIdx: UINT32 [ + cloneGroupId set_cloneGroupId[0..16], + sourceModeInfoIdx set_sourceModeInfoIdx[16..32], +]} +pub const DISPLAYCONFIG_SOURCE_IN_USE: DWORD = 0x00000001; +STRUCT!{struct DISPLAYCONFIG_PATH_TARGET_INFO { + adapterId: LUID, + id: UINT32, + modeInfoIdx: UINT32, + outputTechnology: DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, + rotation: DISPLAYCONFIG_ROTATION, + scaling: DISPLAYCONFIG_SCALING, + refreshRate: DISPLAYCONFIG_RATIONAL, + scanLineOrdering: DISPLAYCONFIG_SCANLINE_ORDERING, + targetAvailable: BOOL, + statusFlags: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_PATH_TARGET_INFO modeInfoIdx: UINT32 [ + desktopModeInfoIdx set_desktopModeInfoIdx[0..16], + targetModeInfoIdx set_targetModeInfoIdx[16..32], +]} +pub const DISPLAYCONFIG_TARGET_IN_USE: DWORD = 0x00000001; +pub const DISPLAYCONFIG_TARGET_FORCIBLE: DWORD = 0x00000002; +pub const DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT: DWORD = 0x00000004; +pub const DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH: DWORD = 0x00000008; +pub const DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM: DWORD = 0x00000010; +pub const DISPLAYCONFIG_TARGET_IS_HMD: DWORD = 0x00000020; +STRUCT!{struct DISPLAYCONFIG_PATH_INFO { + sourceInfo: DISPLAYCONFIG_PATH_SOURCE_INFO, + targetInfo: DISPLAYCONFIG_PATH_TARGET_INFO, + flags: UINT32, +}} +pub const DISPLAYCONFIG_PATH_ACTIVE: DWORD = 0x00000001; +pub const DISPLAYCONFIG_PATH_PREFERRED_UNSCALED: DWORD = 0x00000004; +pub const DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE: DWORD = 0x00000008; +pub const DISPLAYCONFIG_PATH_VALID_FLAGS: DWORD = 0x0000000D; +ENUM!{enum DISPLAYCONFIG_TOPOLOGY_ID { + DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001, + DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002, + DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004, + DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008, + DISPLAYCONFIG_TOPOLOGY_FORCE_UINT32 = 0xFFFFFFFF, +}} +ENUM!{enum DISPLAYCONFIG_DEVICE_INFO_TYPE { + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, + DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, + DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, + DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7, + DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8, + DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9, + DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10, + DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF, +}} +STRUCT!{struct DISPLAYCONFIG_DEVICE_INFO_HEADER { + _type: DISPLAYCONFIG_DEVICE_INFO_TYPE, + size: UINT32, + adapterId: LUID, + id: UINT32, +}} +STRUCT!{struct DISPLAYCONFIG_SOURCE_DEVICE_NAME { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + viewGdiDeviceName: [WCHAR; CCHDEVICENAME], +}} +STRUCT!{struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS { + value: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS value: UINT32 [ + friendlyNameFromEdid set_friendlyNameFromEdid[0..1], + friendlyNameForced set_friendlyNameForced[1..2], + edidIdsValid set_edidIdsValid[2..3], +]} +STRUCT!{struct DISPLAYCONFIG_TARGET_DEVICE_NAME { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + flags: DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS, + outputTechnology: DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, + edidManufactureId: UINT16, + edidProductCodeId: UINT16, + connectorInstance: UINT32, + monitorFriendlyDeviceName: [WCHAR; 64], + monitorDevicePath: [WCHAR; 128], +}} +STRUCT!{struct DISPLAYCONFIG_TARGET_PREFERRED_MODE { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + width: UINT32, + height: UINT32, + targetMode: DISPLAYCONFIG_TARGET_MODE, +}} +STRUCT!{struct DISPLAYCONFIG_ADAPTER_NAME { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + adapterDevicePath: [WCHAR; 128], +}} +STRUCT!{struct DISPLAYCONFIG_TARGET_BASE_TYPE { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + baseOutputTechnology: DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, +}} +STRUCT!{struct DISPLAYCONFIG_SET_TARGET_PERSISTENCE { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + value: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_SET_TARGET_PERSISTENCE value: UINT32 [ + bootPersistenceOn set_bootPersistenceOn[0..1], +]} +STRUCT!{struct DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + value: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION value: UINT32 [ + disableMonitorVirtualResolution set_disableMonitorVirtualResolution[0..1], +]} +ENUM!{enum DISPLAYCONFIG_COLOR_ENCODING { + DISPLAYCONFIG_COLOR_ENCODING_RGB = 0, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR422 = 2, + DISPLAYCONFIG_COLOR_ENCODING_YCBCR420 = 3, + DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4, + DISPLAYCONFIG_COLOR_ENCODING_FORCE_UINT32 = 0xFFFFFFFF, +}} +STRUCT!{struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + value: UINT32, + colorEncoding: DISPLAYCONFIG_COLOR_ENCODING, + bitsPerColorChannel: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO value: UINT32 [ + advancedColorSupported set_advancedColorSupported[0..1], + advancedColorEnabled set_advancedColorEnabled[1..2], + reserved set_reserved[2..32], +]} +STRUCT!{struct DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE { + header: DISPLAYCONFIG_DEVICE_INFO_HEADER, + value: UINT32, +}} +BITFIELD!{DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE value: UINT32 [ + enableAdvancedColor set_enableAdvancedColor[0..1], + reserved set_reserved[1..32], +]} +pub const QDC_ALL_PATHS: DWORD = 0x00000001; +pub const QDC_ONLY_ACTIVE_PATHS: DWORD = 0x00000002; +pub const QDC_DATABASE_CURRENT: DWORD = 0x00000004; +pub const QDC_VIRTUAL_MODE_AWARE: DWORD = 0x00000010; +pub const QDC_INCLUDE_HMD: DWORD = 0x00000020; +pub const SDC_TOPOLOGY_INTERNAL: DWORD = 0x00000001; +pub const SDC_TOPOLOGY_CLONE: DWORD = 0x00000002; +pub const SDC_TOPOLOGY_EXTEND: DWORD = 0x00000004; +pub const SDC_TOPOLOGY_EXTERNAL: DWORD = 0x00000008; +pub const SDC_TOPOLOGY_SUPPLIED: DWORD = 0x00000010; +pub const SDC_USE_DATABASE_CURRENT: DWORD = SDC_TOPOLOGY_INTERNAL | SDC_TOPOLOGY_CLONE + | SDC_TOPOLOGY_EXTEND | SDC_TOPOLOGY_EXTERNAL; +pub const SDC_USE_SUPPLIED_DISPLAY_CONFIG: DWORD = 0x00000020; +pub const SDC_VALIDATE: DWORD = 0x00000040; +pub const SDC_APPLY: DWORD = 0x00000080; +pub const SDC_NO_OPTIMIZATION: DWORD = 0x00000100; +pub const SDC_SAVE_TO_DATABASE: DWORD = 0x00000200; +pub const SDC_ALLOW_CHANGES: DWORD = 0x00000400; +pub const SDC_PATH_PERSIST_IF_REQUIRED: DWORD = 0x00000800; +pub const SDC_FORCE_MODE_ENUMERATION: DWORD = 0x00001000; +pub const SDC_ALLOW_PATH_ORDER_CHANGES: DWORD = 0x00002000; +pub const SDC_VIRTUAL_MODE_AWARE: DWORD = 0x00008000; +pub const RDH_RECTANGLES: DWORD = 1; +STRUCT!{struct RGNDATAHEADER { + dwSize: DWORD, + iType: DWORD, + nCount: DWORD, + nRgnSize: DWORD, + rcBound: RECT, +}} +pub type PRGNDATAHEADER = *mut RGNDATAHEADER; +STRUCT!{struct RGNDATA { + rdh: RGNDATAHEADER, + Buffer: [c_char; 1], +}} +pub type PRGNDATA = *mut RGNDATA; +pub type NPRGNDATA = *mut RGNDATA; +pub type LPRGNDATA = *mut RGNDATA; +pub const SYSRGN: INT = 4; +STRUCT!{struct ABC { + abcA: c_int, + abcB: UINT, + abcC: c_int, +}} +pub type PABC = *mut ABC; +pub type NPABC = *mut ABC; +pub type LPABC = *mut ABC; +STRUCT!{struct ABCFLOAT { + abcfA: FLOAT, + abcfB: FLOAT, + abcfC: FLOAT, +}} +pub type PABCFLOAT = *mut ABCFLOAT; +pub type NPABCFLOAT = *mut ABCFLOAT; +pub type LPABCFLOAT = *mut ABCFLOAT; +STRUCT!{struct OUTLINETEXTMETRICA { + otmSize: UINT, + otmTextMetrics: TEXTMETRICA, + otmFiller: BYTE, + otmPanoseNumber: PANOSE, + otmfsSelection: UINT, + otmfsType: UINT, + otmsCharSlopeRise: c_int, + otmsCharSlopeRun: c_int, + otmItalicAngle: c_int, + otmEMSquare: UINT, + otmAscent: c_int, + otmDescent: c_int, + otmLineGap: UINT, + otmsCapEmHeight: UINT, + otmsXHeight: UINT, + otmrcFontBox: RECT, + otmMacAscent: c_int, + otmMacDescent: c_int, + otmMacLineGap: UINT, + otmusMinimumPPEM: UINT, + otmptSubscriptSize: POINT, + otmptSubscriptOffset: POINT, + otmptSuperscriptSize: POINT, + otmptSuperscriptOffset: POINT, + otmsStrikeoutSize: UINT, + otmsStrikeoutPosition: c_int, + otmsUnderscoreSize: c_int, + otmsUnderscorePosition: c_int, + otmpFamilyName: PSTR, + otmpFaceName: PSTR, + otmpStyleName: PSTR, + otmpFullName: PSTR, +}} +pub type POUTLINETEXTMETRICA = *mut OUTLINETEXTMETRICA; +pub type NPOUTLINETEXTMETRICA = *mut OUTLINETEXTMETRICA; +pub type LPOUTLINETEXTMETRICA = *mut OUTLINETEXTMETRICA; +STRUCT!{struct OUTLINETEXTMETRICW { + otmSize: UINT, + otmTextMetrics: TEXTMETRICW, + otmFiller: BYTE, + otmPanoseNumber: PANOSE, + otmfsSelection: UINT, + otmfsType: UINT, + otmsCharSlopeRise: c_int, + otmsCharSlopeRun: c_int, + otmItalicAngle: c_int, + otmEMSquare: UINT, + otmAscent: c_int, + otmDescent: c_int, + otmLineGap: UINT, + otmsCapEmHeight: UINT, + otmsXHeight: UINT, + otmrcFontBox: RECT, + otmMacAscent: c_int, + otmMacDescent: c_int, + otmMacLineGap: UINT, + otmusMinimumPPEM: UINT, + otmptSubscriptSize: POINT, + otmptSubscriptOffset: POINT, + otmptSuperscriptSize: POINT, + otmptSuperscriptOffset: POINT, + otmsStrikeoutSize: UINT, + otmsStrikeoutPosition: c_int, + otmsUnderscoreSize: c_int, + otmsUnderscorePosition: c_int, + otmpFamilyName: PSTR, + otmpFaceName: PSTR, + otmpStyleName: PSTR, + otmpFullName: PSTR, +}} +pub type POUTLINETEXTMETRICW = *mut OUTLINETEXTMETRICW; +pub type NPOUTLINETEXTMETRICW = *mut OUTLINETEXTMETRICW; +pub type LPOUTLINETEXTMETRICW = *mut OUTLINETEXTMETRICW; +STRUCT!{struct POLYTEXTA { + x: c_int, + y: c_int, + n: UINT, + lpstr: LPCSTR, + uiFlags: UINT, + rcl: RECT, + pdx: *mut c_int, +}} +pub type PPOLYTEXTA = *mut POLYTEXTA; +pub type NPPOLYTEXTA = *mut POLYTEXTA; +pub type LPPOLYTEXTA = *mut POLYTEXTA; +STRUCT!{struct POLYTEXTW { + x: c_int, + y: c_int, + n: UINT, + lpstr: LPCWSTR, + uiFlags: UINT, + rcl: RECT, + pdx: *mut c_int, +}} +pub type PPOLYTEXTW = *mut POLYTEXTW; +pub type NPPOLYTEXTW = *mut POLYTEXTW; +pub type LPPOLYTEXTW = *mut POLYTEXTW; +STRUCT!{struct FIXED { + fract: WORD, + value: c_short, +}} +STRUCT!{struct MAT2 { + eM11: FIXED, + eM12: FIXED, + eM21: FIXED, + eM22: FIXED, +}} +pub type LPMAT2 = *mut MAT2; +STRUCT!{struct GLYPHMETRICS { + gmBlackBoxX: UINT, + gmBlackBoxY: UINT, + gmptGlyphOrigin: POINT, + gmCellIncX: c_short, + gmCellIncY: c_short, +}} +pub type LPGLYPHMETRICS = *mut GLYPHMETRICS; +pub const GGO_METRICS: DWORD = 0; +pub const GGO_BITMAP: DWORD = 1; +pub const GGO_NATIVE: DWORD = 2; +pub const GGO_BEZIER: DWORD = 3; +pub const GGO_GRAY2_BITMAP: DWORD = 4; +pub const GGO_GRAY4_BITMAP: DWORD = 5; +pub const GGO_GRAY8_BITMAP: DWORD = 6; +pub const GGO_GLYPH_INDEX: DWORD = 0x0080; +pub const GGO_UNHINTED: DWORD = 0x0100; +pub const TT_POLYGON_TYPE: DWORD = 24; +pub const TT_PRIM_LINE: DWORD = 1; +pub const TT_PRIM_QSPLINE: DWORD = 2; +pub const TT_PRIM_CSPLINE: DWORD = 3; +STRUCT!{struct POINTFX { + x: FIXED, + y: FIXED, +}} +pub type LPPOINTFX = *mut POINTFX; +STRUCT!{struct TTPOLYCURVE { + wType: WORD, + cpfx: WORD, + apfx: [POINTFX; 1], +}} +pub type LPTTPOLYCURVE = *mut TTPOLYCURVE; +STRUCT!{struct TTPOLYGONHEADER { + cb: DWORD, + dwType: DWORD, + pfxStart: POINTFX, +}} +pub type LPTTPOLYGONHEADER = *mut TTPOLYGONHEADER; +pub const GCP_DBCS: DWORD = 0x0001; +pub const GCP_REORDER: DWORD = 0x0002; +pub const GCP_USEKERNING: DWORD = 0x0008; +pub const GCP_GLYPHSHAPE: DWORD = 0x0010; +pub const GCP_LIGATE: DWORD = 0x0020; +pub const GCP_DIACRITIC: DWORD = 0x0100; +pub const GCP_KASHIDA: DWORD = 0x0400; +pub const GCP_ERROR: DWORD = 0x8000; +pub const FLI_MASK: DWORD = 0x103B; +pub const GCP_JUSTIFY: DWORD = 0x00010000; +pub const FLI_GLYPHS: DWORD = 0x00040000; +pub const GCP_CLASSIN: DWORD = 0x00080000; +pub const GCP_MAXEXTENT: DWORD = 0x00100000; +pub const GCP_JUSTIFYIN: DWORD = 0x00200000; +pub const GCP_DISPLAYZWG: DWORD = 0x00400000; +pub const GCP_SYMSWAPOFF: DWORD = 0x00800000; +pub const GCP_NUMERICOVERRIDE: DWORD = 0x01000000; +pub const GCP_NEUTRALOVERRIDE: DWORD = 0x02000000; +pub const GCP_NUMERICSLATIN: DWORD = 0x04000000; +pub const GCP_NUMERICSLOCAL: DWORD = 0x08000000; +pub const GCPCLASS_LATIN: DWORD = 1; +pub const GCPCLASS_HEBREW: DWORD = 2; +pub const GCPCLASS_ARABIC: DWORD = 2; +pub const GCPCLASS_NEUTRAL: DWORD = 3; +pub const GCPCLASS_LOCALNUMBER: DWORD = 4; +pub const GCPCLASS_LATINNUMBER: DWORD = 5; +pub const GCPCLASS_LATINNUMERICTERMINATOR: DWORD = 6; +pub const GCPCLASS_LATINNUMERICSEPARATOR: DWORD = 7; +pub const GCPCLASS_NUMERICSEPARATOR: DWORD = 8; +pub const GCPCLASS_PREBOUNDLTR: DWORD = 0x80; +pub const GCPCLASS_PREBOUNDRTL: DWORD = 0x40; +pub const GCPCLASS_POSTBOUNDLTR: DWORD = 0x20; +pub const GCPCLASS_POSTBOUNDRTL: DWORD = 0x10; +pub const GCPGLYPH_LINKBEFORE: DWORD = 0x8000; +pub const GCPGLYPH_LINKAFTER: DWORD = 0x4000; +STRUCT!{struct GCP_RESULTSA { + lStructSize: DWORD, + lpOutString: LPSTR, + lpOrder: *mut UINT, + lpDx: *mut c_int, + lpCaretPos: *mut c_int, + lpClass: LPSTR, + lpGlyphs: LPWSTR, + nGlyphs: UINT, + nMaxFit: c_int, +}} +pub type LPGCP_RESULTSA = *mut GCP_RESULTSA; +STRUCT!{struct GCP_RESULTSW { + lStructSize: DWORD, + lpOutString: LPWSTR, + lpOrder: *mut UINT, + lpDx: *mut c_int, + lpCaretPos: *mut c_int, + lpClass: LPSTR, + lpGlyphs: LPWSTR, + nGlyphs: UINT, + nMaxFit: c_int, +}} +pub type LPGCP_RESULTSW = *mut GCP_RESULTSW; +STRUCT!{struct RASTERIZER_STATUS { + nSize: c_short, + wFlags: c_short, + nLanguageID: c_short, +}} +pub type LPRASTERIZER_STATUS = *mut RASTERIZER_STATUS; +pub const TT_AVAILABLE: DWORD = 0x0001; +pub const TT_ENABLED: DWORD = 0x0002; +STRUCT!{struct PIXELFORMATDESCRIPTOR { + nSize: WORD, + nVersion: WORD, + dwFlags: DWORD, + iPixelType: BYTE, + cColorBits: BYTE, + cRedBits: BYTE, + cRedShift: BYTE, + cGreenBits: BYTE, + cGreenShift: BYTE, + cBlueBits: BYTE, + cBlueShift: BYTE, + cAlphaBits: BYTE, + cAlphaShift: BYTE, + cAccumBits: BYTE, + cAccumRedBits: BYTE, + cAccumGreenBits: BYTE, + cAccumBlueBits: BYTE, + cAccumAlphaBits: BYTE, + cDepthBits: BYTE, + cStencilBits: BYTE, + cAuxBuffers: BYTE, + iLayerType: BYTE, + bReserved: BYTE, + dwLayerMask: DWORD, + dwVisibleMask: DWORD, + dwDamageMask: DWORD, +}} +pub type PPIXELFORMATDESCRIPTOR = *mut PIXELFORMATDESCRIPTOR; +pub type LPPIXELFORMATDESCRIPTOR = *mut PIXELFORMATDESCRIPTOR; +pub const PFD_TYPE_RGBA: BYTE = 0; +pub const PFD_TYPE_COLORINDEX: BYTE = 1; +pub const PFD_MAIN_PLANE: BYTE = 0; +pub const PFD_OVERLAY_PLANE: BYTE = 1; +pub const PFD_UNDERLAY_PLANE: BYTE = -1i8 as u8; +pub const PFD_DOUBLEBUFFER: DWORD = 0x00000001; +pub const PFD_STEREO: DWORD = 0x00000002; +pub const PFD_DRAW_TO_WINDOW: DWORD = 0x00000004; +pub const PFD_DRAW_TO_BITMAP: DWORD = 0x00000008; +pub const PFD_SUPPORT_GDI: DWORD = 0x00000010; +pub const PFD_SUPPORT_OPENGL: DWORD = 0x00000020; +pub const PFD_GENERIC_FORMAT: DWORD = 0x00000040; +pub const PFD_NEED_PALETTE: DWORD = 0x00000080; +pub const PFD_NEED_SYSTEM_PALETTE: DWORD = 0x00000100; +pub const PFD_SWAP_EXCHANGE: DWORD = 0x00000200; +pub const PFD_SWAP_COPY: DWORD = 0x00000400; +pub const PFD_SWAP_LAYER_BUFFERS: DWORD = 0x00000800; +pub const PFD_GENERIC_ACCELERATED: DWORD = 0x00001000; +pub const PFD_SUPPORT_DIRECTDRAW: DWORD = 0x00002000; +pub const PFD_DIRECT3D_ACCELERATED: DWORD = 0x00004000; +pub const PFD_SUPPORT_COMPOSITION: DWORD = 0x00008000; +pub const PFD_DEPTH_DONTCARE: DWORD = 0x20000000; +pub const PFD_DOUBLEBUFFER_DONTCARE: DWORD = 0x40000000; +pub const PFD_STEREO_DONTCARE: DWORD = 0x80000000; +FN!{stdcall OLDFONTENUMPROCA( + *const LOGFONTA, + *const TEXTMETRICA, + DWORD, + LPARAM, +) -> c_int} +FN!{stdcall OLDFONTENUMPROCW( + *const LOGFONTW, + *const TEXTMETRICW, + DWORD, + LPARAM, +) -> c_int} +pub type FONTENUMPROCA = OLDFONTENUMPROCA; +pub type FONTENUMPROCW = OLDFONTENUMPROCW; +FN!{stdcall GOBJENUMPROC( + LPVOID, + LPARAM, +) -> c_int} +FN!{stdcall LINEDDAPROC( + c_int, + c_int, + LPARAM, +) -> ()} +extern "system" { + pub fn AddFontResourceA( + _: LPCSTR, + ) -> c_int; + pub fn AddFontResourceW( + _: LPCWSTR, + ) -> c_int; + pub fn AnimatePalette( + hPal: HPALETTE, + iStartIndex: UINT, + cEntries: UINT, + ppe: *const PALETTEENTRY, + ) -> BOOL; + pub fn Arc( + hdc: HDC, + x1: c_int, + y1: c_int, + x2: c_int, + y2: c_int, + x3: c_int, + y3: c_int, + x4: c_int, + y4: c_int, + ) -> BOOL; + pub fn BitBlt( + hdc: HDC, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + hdcSrc: HDC, + x1: c_int, + y1: c_int, + rop: DWORD, + ) -> BOOL; + pub fn CancelDC( + hdc: HDC, + ) -> BOOL; + pub fn Chord( + hdc: HDC, + x1: c_int, + y1: c_int, + x2: c_int, + y2: c_int, + x3: c_int, + y3: c_int, + x4: c_int, + y4: c_int, + ) -> BOOL; + pub fn ChoosePixelFormat( + hdc: HDC, + ppfd: *const PIXELFORMATDESCRIPTOR, + ) -> c_int; + pub fn CloseMetaFile( + hdc: HDC, + ) -> HMETAFILE; + pub fn CombineRgn( + hrgnDst: HRGN, + hrgnSrc1: HRGN, + hrgnSrc2: HRGN, + iMode: c_int, + ) -> c_int; + pub fn CopyMetaFileA( + _: HMETAFILE, + _: LPCSTR, + ) -> HMETAFILE; + pub fn CopyMetaFileW( + _: HMETAFILE, + _: LPCWSTR, + ) -> HMETAFILE; + pub fn CreateBitmap( + nWidth: c_int, + nHeight: c_int, + nPlanes: UINT, + nBitCount: UINT, + lpBits: *const c_void, + ) -> HBITMAP; + pub fn CreateBitmapIndirect( + pbm: *const BITMAP, + ) -> HBITMAP; + pub fn CreateBrushIndirect( + plbrush: *const LOGBRUSH, + ) -> HBRUSH; + pub fn CreateCompatibleBitmap( + hdc: HDC, + cx: c_int, + cy: c_int, + ) -> HBITMAP; + pub fn CreateDiscardableBitmap( + hdc: HDC, + cx: c_int, + cy: c_int, + ) -> HBITMAP; + pub fn CreateCompatibleDC( + hdc: HDC, + ) -> HDC; + pub fn CreateDCA( + pwszDriver: LPCSTR, + pwszDevice: LPCSTR, + pszPort: LPCSTR, + pdm: *const DEVMODEA, + ) -> HDC; + pub fn CreateDCW( + pwszDriver: LPCWSTR, + pwszDevice: LPCWSTR, + pszPort: LPCWSTR, + pdm: *const DEVMODEW, + ) -> HDC; + pub fn CreateDIBitmap( + hdc: HDC, + pbmih: *const BITMAPINFOHEADER, + flInit: DWORD, + pjBits: *const c_void, + pbmi: *const BITMAPINFO, + iUsage: UINT, + ) -> HBITMAP; + pub fn CreateDIBPatternBrush( + h: HGLOBAL, + iUsage: UINT, + ) -> HBRUSH; + pub fn CreateDIBPatternBrushPt( + lpPackedDIB: *const c_void, + iUsage: UINT, + ) -> HBRUSH; + pub fn CreateEllipticRgn( + x1: c_int, + y1: c_int, + x2: c_int, + y2: c_int, + ) -> HRGN; + pub fn CreateEllipticRgnIndirect( + lprect: *const RECT, + ) -> HRGN; + pub fn CreateFontIndirectA( + lplf: *const LOGFONTA, + ) -> HFONT; + pub fn CreateFontIndirectW( + lplf: *const LOGFONTW, + ) -> HFONT; + pub fn CreateFontA( + cHeight: c_int, + cWidth: c_int, + cEscapement: c_int, + cOrientation: c_int, + cWeight: c_int, + bItalic: DWORD, + bUnderline: DWORD, + bStrikeOut: DWORD, + iCharSet: DWORD, + iOutPrecision: DWORD, + iClipPrecision: DWORD, + iQuality: DWORD, + iPitchAndFamily: DWORD, + pszFaceName: LPCSTR, + ) -> HFONT; + pub fn CreateFontW( + cHeight: c_int, + cWidth: c_int, + cEscapement: c_int, + cOrientation: c_int, + cWeight: c_int, + bItalic: DWORD, + bUnderline: DWORD, + bStrikeOut: DWORD, + iCharSet: DWORD, + iOutPrecision: DWORD, + iClipPrecision: DWORD, + iQuality: DWORD, + iPitchAndFamily: DWORD, + pszFaceName: LPCWSTR, + ) -> HFONT; + pub fn CreateHatchBrush( + iHatch: c_int, + color: COLORREF, + ) -> HBRUSH; + pub fn CreateICA( + pszDriver: LPCSTR, + pszDevice: LPCSTR, + pszPort: LPCSTR, + pdm: *const DEVMODEA, + ) -> HDC; + pub fn CreateICW( + pszDriver: LPCWSTR, + pszDevice: LPCWSTR, + pszPort: LPCWSTR, + pdm: *const DEVMODEW, + ) -> HDC; + pub fn CreateMetaFileA( + pszFile: LPCSTR, + ) -> HDC; + pub fn CreateMetaFileW( + pszFile: LPCWSTR, + ) -> HDC; + pub fn CreatePalette( + plpal: *const LOGPALETTE, + ) -> HPALETTE; + pub fn CreatePen( + iStyle: c_int, + cWidth: c_int, + color: COLORREF, + ) -> HPEN; + pub fn CreatePenIndirect( + plpen: *const LOGPEN, + ) -> HPEN; + pub fn CreatePolyPolygonRgn( + pptl: *const POINT, + pc: *const INT, + cPoly: c_int, + iMode: c_int, + ) -> HRGN; + pub fn CreatePatternBrush( + hbm: HBITMAP, + ) -> HBRUSH; + pub fn CreateRectRgn( + x1: c_int, + y1: c_int, + x2: c_int, + y2: c_int, + ) -> HRGN; + pub fn CreateRectRgnIndirect( + lprect: *const RECT, + ) -> HRGN; + pub fn CreateRoundRectRgn( + x1: c_int, + y1: c_int, + x2: c_int, + y2: c_int, + w: c_int, + h: c_int, + ) -> HRGN; + pub fn CreateScalableFontResourceA( + fdwHidden: DWORD, + lpszFont: LPCSTR, + lpszFile: LPCSTR, + lpszPath: LPCSTR, + ) -> BOOL; + pub fn CreateScalableFontResourceW( + fdwHidden: DWORD, + lpszFont: LPCWSTR, + lpszFile: LPCWSTR, + lpszPath: LPCWSTR, + ) -> BOOL; + pub fn CreateSolidBrush( + color: COLORREF, + ) -> HBRUSH; + pub fn DeleteDC( + hdc: HDC, + ) -> BOOL; + pub fn DeleteMetaFile( + hmf: HMETAFILE, + ) -> BOOL; + pub fn DeleteObject( + ho: HGDIOBJ, + ) -> BOOL; + pub fn DescribePixelFormat( + hdc: HDC, + iPixelFormat: c_int, + nBytes: UINT, + ppfd: LPPIXELFORMATDESCRIPTOR, + ) -> c_int; +} +FN!{stdcall LPFNDEVMODE( + HWND, + HMODULE, + LPDEVMODEA, + LPSTR, + LPSTR, + LPDEVMODEA, + LPSTR, + UINT, +) -> UINT} +FN!{stdcall LPFNDEVCAPS( + LPSTR, + LPSTR, + UINT, + LPSTR, + LPDEVMODEA, +) -> DWORD} +pub const DM_UPDATE: DWORD = 1; +pub const DM_COPY: DWORD = 2; +pub const DM_PROMPT: DWORD = 4; +pub const DM_MODIFY: DWORD = 8; +pub const DM_IN_BUFFER: DWORD = DM_MODIFY; +pub const DM_IN_PROMPT: DWORD = DM_PROMPT; +pub const DM_OUT_BUFFER: DWORD = DM_COPY; +pub const DM_OUT_DEFAULT: DWORD = DM_UPDATE; +pub const DC_FIELDS: WORD = 1; +pub const DC_PAPERS: WORD = 2; +pub const DC_PAPERSIZE: WORD = 3; +pub const DC_MINEXTENT: WORD = 4; +pub const DC_MAXEXTENT: WORD = 5; +pub const DC_BINS: WORD = 6; +pub const DC_DUPLEX: WORD = 7; +pub const DC_SIZE: WORD = 8; +pub const DC_EXTRA: WORD = 9; +pub const DC_VERSION: WORD = 10; +pub const DC_DRIVER: WORD = 11; +pub const DC_BINNAMES: WORD = 12; +pub const DC_ENUMRESOLUTIONS: WORD = 13; +pub const DC_FILEDEPENDENCIES: WORD = 14; +pub const DC_TRUETYPE: WORD = 15; +pub const DC_PAPERNAMES: WORD = 16; +pub const DC_ORIENTATION: WORD = 17; +pub const DC_COPIES: WORD = 18; +pub const DC_BINADJUST: WORD = 19; +pub const DC_EMF_COMPLIANT: WORD = 20; +pub const DC_DATATYPE_PRODUCED: WORD = 21; +pub const DC_COLLATE: WORD = 22; +pub const DC_MANUFACTURER: WORD = 23; +pub const DC_MODEL: WORD = 24; +pub const DC_PERSONALITY: WORD = 25; +pub const DC_PRINTRATE: WORD = 26; +pub const DC_PRINTRATEUNIT: WORD = 27; +pub const PRINTRATEUNIT_PPM: WORD = 1; +pub const PRINTRATEUNIT_CPS: WORD = 2; +pub const PRINTRATEUNIT_LPM: WORD = 3; +pub const PRINTRATEUNIT_IPM: WORD = 4; +pub const DC_PRINTERMEM: WORD = 28; +pub const DC_MEDIAREADY: WORD = 29; +pub const DC_STAPLE: WORD = 30; +pub const DC_PRINTRATEPPM: WORD = 31; +pub const DC_COLORDEVICE: WORD = 32; +pub const DC_NUP: WORD = 33; +pub const DC_MEDIATYPENAMES: WORD = 34; +pub const DC_MEDIATYPES: WORD = 35; +pub const DCTT_BITMAP: DWORD = 0x0000001; +pub const DCTT_DOWNLOAD: DWORD = 0x0000002; +pub const DCTT_SUBDEV: DWORD = 0x0000004; +pub const DCTT_DOWNLOAD_OUTLINE: DWORD = 0x0000008; +pub const DCBA_FACEUPNONE: DWORD = 0x0000; +pub const DCBA_FACEUPCENTER: DWORD = 0x0001; +pub const DCBA_FACEUPLEFT: DWORD = 0x0002; +pub const DCBA_FACEUPRIGHT: DWORD = 0x0003; +pub const DCBA_FACEDOWNNONE: DWORD = 0x0100; +pub const DCBA_FACEDOWNCENTER: DWORD = 0x0101; +pub const DCBA_FACEDOWNLEFT: DWORD = 0x0102; +pub const DCBA_FACEDOWNRIGHT: DWORD = 0x0103; +extern "system" { + pub fn DeviceCapabilitiesA( + pDevice: LPCSTR, + pPort: LPCSTR, + fwCapability: WORD, + pOutput: LPSTR, + pDevMode: *const DEVMODEA, + ) -> c_int; + pub fn DeviceCapabilitiesW( + pDevice: LPCWSTR, + pPort: LPCWSTR, + fwCapability: WORD, + pOutput: LPWSTR, + pDevMode: *const DEVMODEW, + ) -> c_int; + pub fn DrawEscape( + hdc: HDC, + iEscape: c_int, + cjIn: c_int, + lpIn: LPCSTR, + ) -> c_int; + pub fn Ellipse( + hdc: HDC, + left: c_int, + top: c_int, + right: c_int, + bottom: c_int, + ) -> BOOL; + pub fn EnumFontFamiliesExA( + hdc: HDC, + lpLogfont: LPLOGFONTA, + lpProc: FONTENUMPROCA, + lParam: LPARAM, + dwFlags: DWORD, + ) -> c_int; + pub fn EnumFontFamiliesExW( + hdc: HDC, + lpLogfont: LPLOGFONTW, + lpProc: FONTENUMPROCW, + lParam: LPARAM, + dwFlags: DWORD, + ) -> c_int; + pub fn EnumFontFamiliesA( + hdc: HDC, + lpLogfont: LPCSTR, + lpProc: FONTENUMPROCA, + lParam: LPARAM, + ) -> c_int; + pub fn EnumFontFamiliesW( + hdc: HDC, + lpLogfont: LPCWSTR, + lpProc: FONTENUMPROCW, + lParam: LPARAM, + ) -> c_int; + pub fn EnumFontsA( + hdc: HDC, + lpLogfont: LPCSTR, + lpProc: FONTENUMPROCA, + lParam: LPARAM, + ) -> c_int; + pub fn EnumFontsW( + hdc: HDC, + lpLogfont: LPCWSTR, + lpProc: FONTENUMPROCW, + lParam: LPARAM, + ) -> c_int; + pub fn EnumObjects( + hdc: HDC, + nType: c_int, + lpFunc: GOBJENUMPROC, + lParam: LPARAM, + ) -> c_int; + pub fn EqualRgn( + hrgn1: HRGN, + hrgn2: HRGN, + ) -> BOOL; + pub fn Escape( + hdc: HDC, + iEscape: c_int, + cjIn: c_int, + pvIn: LPCSTR, + pvOut: LPVOID, + ) -> c_int; + pub fn ExtEscape( + hdc: HDC, + iEscape: c_int, + cjInput: c_int, + lpInData: LPCSTR, + cjOutput: c_int, + lpOutData: LPSTR, + ) -> c_int; + pub fn ExcludeClipRect( + hdc: HDC, + left: c_int, + top: c_int, + right: c_int, + bottom: c_int, + ) -> c_int; + pub fn ExtCreateRegion( + lpx: *const XFORM, + nCount: DWORD, + lpData: *const RGNDATA, + ) -> HRGN; + pub fn ExtFloodFill( + hdc: HDC, + x: c_int, + y: c_int, + color: COLORREF, + utype: UINT, + ) -> BOOL; + pub fn FillRgn( + hdc: HDC, + hrgn: HRGN, + hbr: HBRUSH, + ) -> BOOL; + pub fn FloodFill( + hdc: HDC, + x: c_int, + y: c_int, + color: COLORREF, + ) -> BOOL; + pub fn FrameRgn( + hdc: HDC, + hrgn: HRGN, + hbr: HBRUSH, + w: c_int, + h: c_int, + ) -> BOOL; + pub fn GetROP2( + hdc: HDC, + ) -> c_int; + pub fn GetAspectRatioFilterEx( + hdc: HDC, + lpsize: LPSIZE, + ) -> BOOL; + pub fn GetBkColor( + hdc: HDC, + ) -> COLORREF; + pub fn GetDCBrushColor( + hdc: HDC, + ) -> COLORREF; + pub fn GetDCPenColor( + hdc: HDC, + ) -> COLORREF; + pub fn GetBkMode( + hdc: HDC, + ) -> c_int; + pub fn GetBitmapBits( + hbit: HBITMAP, + cb: LONG, + lpvBits: LPVOID, + ) -> LONG; + pub fn GetBitmapDimensionEx( + hbit: HBITMAP, + lpsize: LPSIZE, + ) -> BOOL; + pub fn GetBoundsRect( + hdc: HDC, + lprect: LPRECT, + flags: UINT, + ) -> UINT; + pub fn GetBrushOrgEx( + hdc: HDC, + lppt: LPPOINT, + ) -> BOOL; + pub fn GetCharWidthA( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: LPINT, + ) -> BOOL; + pub fn GetCharWidthW( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: LPINT, + ) -> BOOL; + pub fn GetCharWidth32A( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: LPINT, + ) -> BOOL; + pub fn GetCharWidth32W( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: LPINT, + ) -> BOOL; + pub fn GetCharWidthFloatA( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: PFLOAT, + ) -> BOOL; + pub fn GetCharWidthFloatW( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpBuffer: PFLOAT, + ) -> BOOL; + pub fn GetCharABCWidthsA( + hdc: HDC, + wFirst: UINT, + wLast: UINT, + lpABC: LPABC, + ) -> BOOL; + pub fn GetCharABCWidthsW( + hdc: HDC, + wFirst: UINT, + wLast: UINT, + lpABC: LPABC, + ) -> BOOL; + pub fn GetCharABCWidthsFloatA( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpABC: LPABCFLOAT, + ) -> BOOL; + pub fn GetCharABCWidthsFloatW( + hdc: HDC, + iFirst: UINT, + iLast: UINT, + lpABC: LPABCFLOAT, + ) -> BOOL; + pub fn GetClipBox( + hdc: HDC, + lprect: LPRECT, + ) -> c_int; + pub fn GetClipRgn( + hdc: HDC, + hrgn: HRGN, + ) -> c_int; + pub fn GetMetaRgn( + hdc: HDC, + hrgn: HRGN, + ) -> c_int; + pub fn GetCurrentObject( + hdc: HDC, + tp: UINT, + ) -> HGDIOBJ; + pub fn GetCurrentPositionEx( + hdc: HDC, + lppt: LPPOINT, + ) -> BOOL; + pub fn GetDeviceCaps( + hdc: HDC, + nIndex: c_int, + ) -> c_int; + pub fn GetDIBits( + hdc: HDC, + hbm: HBITMAP, + start: UINT, + cLines: UINT, + lpvBits: LPVOID, + lpbmi: LPBITMAPINFO, + usage: UINT, + ) -> c_int; + pub fn GetFontData( + hdc: HDC, + dwTable: DWORD, + dwOffset: DWORD, + pvBuffer: PVOID, + cjBuffer: DWORD, + ) -> DWORD; + pub fn GetGlyphOutlineA( + hdc: HDC, + uChar: UINT, + fuFormat: UINT, + lpgm: LPGLYPHMETRICS, + cjBuffer: DWORD, + pvBuffer: LPVOID, + lpmat2: *const MAT2, + ) -> DWORD; + pub fn GetGlyphOutlineW( + hdc: HDC, + uChar: UINT, + fuFormat: UINT, + lpgm: LPGLYPHMETRICS, + cjBuffer: DWORD, + pvBuffer: LPVOID, + lpmat2: *const MAT2, + ) -> DWORD; + pub fn GetGraphicsMode( + hdc: HDC, + ) -> c_int; + pub fn GetMapMode( + hdc: HDC, + ) -> c_int; + pub fn GetMetaFileBitsEx( + hMF: HMETAFILE, + cbBuffer: UINT, + lpData: LPVOID, + ) -> UINT; + pub fn GetMetaFileA( + lpName: LPCSTR, + ) -> HMETAFILE; + pub fn GetMetaFileW( + lpName: LPCWSTR, + ) -> HMETAFILE; + pub fn GetNearestColor( + hdc: HDC, + color: COLORREF, + ) -> COLORREF; + pub fn GetNearestPaletteIndex( + h: HPALETTE, + color: COLORREF, + ) -> UINT; + pub fn GetObjectType( + h: HGDIOBJ, + ) -> DWORD; + pub fn GetOutlineTextMetricsA( + hdc: HDC, + cjCopy: UINT, + potm: LPOUTLINETEXTMETRICA, + ) -> UINT; + pub fn GetOutlineTextMetricsW( + hdc: HDC, + cjCopy: UINT, + potm: LPOUTLINETEXTMETRICW, + ) -> UINT; + pub fn GetPaletteEntries( + hpal: HPALETTE, + iStart: UINT, + cEntries: UINT, + pPalEntries: LPPALETTEENTRY, + ) -> UINT; + pub fn GetPixel( + hdc: HDC, + x: c_int, + y: c_int, + ) -> COLORREF; + pub fn GetPixelFormat( + hdc: HDC, + ) -> c_int; + pub fn GetPolyFillMode( + hdc: HDC, + ) -> c_int; + pub fn GetRasterizerCaps( + lpraststat: LPRASTERIZER_STATUS, + cjBytes: UINT, + ) -> BOOL; + pub fn GetRandomRgn ( + hdc: HDC, + hrgn: HRGN, + i: INT, + ) -> c_int; + pub fn GetRegionData( + hrgn: HRGN, + nCount: DWORD, + lpRgnData: LPRGNDATA, + ) -> DWORD; + pub fn GetRgnBox( + hrgn: HRGN, + lprc: LPRECT, + ) -> c_int; + pub fn GetStockObject( + i: c_int, + ) -> HGDIOBJ; + pub fn GetStretchBltMode( + hdc: HDC, + ) -> c_int; + pub fn GetSystemPaletteEntries( + hdc: HDC, + iStart: UINT, + cEntries: UINT, + pPalEntries: LPPALETTEENTRY, + ) -> UINT; + pub fn GetSystemPaletteUse( + hdc: HDC, + ) -> UINT; + pub fn GetTextCharacterExtra( + hdc: HDC, + ) -> c_int; + pub fn GetTextAlign( + hdc: HDC, + ) -> UINT; + pub fn GetTextColor( + hdc: HDC, + ) -> COLORREF; + pub fn GetTextExtentPointA( + hdc: HDC, + lpString: LPCSTR, + c: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentPointW( + hdc: HDC, + lpString: LPCWSTR, + c: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentPoint32A( + hdc: HDC, + lpString: LPCSTR, + c: c_int, + psizl: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentPoint32W( + hdc: HDC, + lpString: LPCWSTR, + c: c_int, + psizl: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentExPointA( + hdc: HDC, + lpszString: LPCSTR, + cchString: c_int, + nMaxExtent: c_int, + lpnFit: LPINT, + lpnDx: LPINT, + lpSize: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentExPointW( + hdc: HDC, + lpszString: LPCWSTR, + cchString: c_int, + nMaxExtent: c_int, + lpnFit: LPINT, + lpnDx: LPINT, + lpSize: LPSIZE, + ) -> BOOL; + pub fn GetTextCharset( + hdc: HDC, + ) -> c_int; + pub fn GetTextCharsetInfo( + hdc: HDC, + lpSig: LPFONTSIGNATURE, + dwFlags: DWORD, + ) -> c_int; + pub fn TranslateCharsetInfo( + lpSrc: *const DWORD, + lpCs: LPCHARSETINFO, + dwFlags: DWORD, + ) -> BOOL; + pub fn GetFontLanguageInfo( + hdc: HDC, + ) -> DWORD; + pub fn GetCharacterPlacementA( + hdc: HDC, + lpString: LPCSTR, + nCount: c_int, + nMexExtent: c_int, + lpResults: LPGCP_RESULTSA, + dwFlags: DWORD, + ) -> DWORD; + pub fn GetCharacterPlacementW( + hdc: HDC, + lpString: LPCWSTR, + nCount: c_int, + nMexExtent: c_int, + lpResults: LPGCP_RESULTSW, + dwFlags: DWORD, + ) -> DWORD; +} +STRUCT!{struct WCRANGE { + wcLow: WCHAR, + cGlyphs: USHORT, +}} +pub type PWCRANGE = *mut WCRANGE; +pub type LPWCRANGE = *mut WCRANGE; +STRUCT!{struct GLYPHSET { + cbThis: DWORD, + flAccel: DWORD, + cGlyphsSupported: DWORD, + cRanges: DWORD, + ranges: [WCRANGE;1], +}} +pub type PGLYPHSET = *mut GLYPHSET; +pub type LPGLYPHSET = *mut GLYPHSET; +pub const GS_8BIT_INDICES: DWORD = 0x00000001; +pub const GGI_MARK_NONEXISTING_GLYPHS: DWORD = 0x0001; +extern "system" { + pub fn GetFontUnicodeRanges( + hdc: HDC, + lpgs: LPGLYPHSET, + ) -> DWORD; + pub fn GetGlyphIndicesA( + hdc: HDC, + lpstr: LPCSTR, + c: c_int, + pgi: LPWORD, + fl: DWORD, + ) -> DWORD; + pub fn GetGlyphIndicesW( + hdc: HDC, + lpstr: LPCWSTR, + c: c_int, + pgi: LPWORD, + fl: DWORD, + ) -> DWORD; + pub fn GetTextExtentPointI( + hdc: HDC, + pgiIn: LPWORD, + cgi: c_int, + psize: LPSIZE, + ) -> BOOL; + pub fn GetTextExtentExPointI( + hdc: HDC, + lpwszString: LPWORD, + cwchString: c_int, + nMaxExtent: c_int, + lpnFit: LPINT, + lpnDx: LPINT, + lpSize: LPSIZE, + ) -> BOOL; + pub fn GetCharWidthI( + hdc: HDC, + giFirst: UINT, + cgi: UINT, + pgi: LPWORD, + piWidths: LPINT, + ) -> BOOL; + pub fn GetCharABCWidthsI( + hdc: HDC, + giFirst: UINT, + cgi: UINT, + pgi: LPWORD, + pabc: LPABC, + ) -> BOOL; +} +pub const STAMP_DESIGNVECTOR: DWORD = 0x8000000 + 0x64 + (0x76 << 8); +pub const STAMP_AXESLIST: DWORD = 0x8000000 + 0x61 + (0x6c << 8); +pub const STAMP_TRUETYPE_VARIATION: DWORD = 0x8000000 + 0x74 + (0x76 << 8); +pub const MM_MAX_NUMAXES: usize = 16; +STRUCT!{struct DESIGNVECTOR { + dvReserved: DWORD, + dvNumAxes: DWORD, + dvValues: [LONG; MM_MAX_NUMAXES], +}} +pub type PDESIGNVECTOR = *mut DESIGNVECTOR; +pub type LPDESIGNVECTOR = *mut DESIGNVECTOR; +extern "system" { + pub fn AddFontResourceExA( + lpszFilename: LPCSTR, + fl: DWORD, + pdv: PVOID, + ) -> c_int; + pub fn AddFontResourceExW( + lpszFilename: LPCWSTR, + fl: DWORD, + pdv: PVOID, + ) -> c_int; + pub fn RemoveFontResourceExA( + name: LPCSTR, + fl: DWORD, + pdv: PVOID, + ) -> BOOL; + pub fn RemoveFontResourceExW( + name: LPCWSTR, + fl: DWORD, + pdv: PVOID, + ) -> BOOL; + pub fn AddFontMemResourceEx( + pbFont: PVOID, + cbSize: DWORD, + pdv: PVOID, + pcFonts: *mut DWORD, + ) -> HANDLE; + pub fn RemoveFontMemResourceEx( + h: HANDLE, + ) -> BOOL; +} +pub const FR_PRIVATE: DWORD = 0x10; +pub const FR_NOT_ENUM: DWORD = 0x20; +pub const MM_MAX_AXES_NAMELEN: usize = 16; +STRUCT!{struct AXISINFOA { + axMinValue: LONG, + axMaxValue: LONG, + axAxisName: [BYTE; MM_MAX_AXES_NAMELEN], +}} +pub type PAXISINFOA = *mut AXISINFOA; +pub type LPAXISINFOA = *mut AXISINFOA; +STRUCT!{struct AXISINFOW { + axMinValue: LONG, + axMaxValue: LONG, + axAxisName: [WCHAR; MM_MAX_AXES_NAMELEN], +}} +pub type PAXISINFOW = *mut AXISINFOW; +pub type LPAXISINFOW = *mut AXISINFOW; +STRUCT!{struct AXESLISTA { + axlReserved: DWORD, + axlNumAxes: DWORD, + axlAxisInfo: [AXISINFOA; MM_MAX_AXES_NAMELEN], +}} +pub type PAXESLISTA = *mut AXESLISTA; +pub type LPAXESLISTA = *mut AXESLISTA; +STRUCT!{struct AXESLISTW { + axlReserved: DWORD, + axlNumAxes: DWORD, + axlAxisInfo: [AXISINFOW; MM_MAX_AXES_NAMELEN], +}} +pub type PAXESLISTW = *mut AXESLISTW; +pub type LPAXESLISTW = *mut AXESLISTW; +STRUCT!{struct ENUMLOGFONTEXDVA { + elfEnumLogfontEx: ENUMLOGFONTEXA, + elfDesignVector: DESIGNVECTOR, +}} +pub type PENUMLOGFONTEXDVA = *mut ENUMLOGFONTEXDVA; +pub type LPENUMLOGFONTEXDVA = *mut ENUMLOGFONTEXDVA; +STRUCT!{struct ENUMLOGFONTEXDVW { + elfEnumLogfontEx: ENUMLOGFONTEXW, + elfDesignVector: DESIGNVECTOR, +}} +pub type PENUMLOGFONTEXDVW = *mut ENUMLOGFONTEXDVW; +pub type LPENUMLOGFONTEXDVW = *mut ENUMLOGFONTEXDVW; +extern "system" { + pub fn CreateFontIndirectExA( + penumlfex: *const ENUMLOGFONTEXDVA, + ) -> HFONT; + pub fn CreateFontIndirectExW( + penumlfex: *const ENUMLOGFONTEXDVW, + ) -> HFONT; +} +STRUCT!{struct ENUMTEXTMETRICA { + etmNewTextMetricEx: NEWTEXTMETRICEXA, + etmAxesList: AXESLISTA, +}} +pub type PENUMTEXTMETRICA = *mut ENUMTEXTMETRICA; +pub type LPENUMTEXTMETRICA = *mut ENUMTEXTMETRICA; +STRUCT!{struct ENUMTEXTMETRICW { + etmNewTextMetricEx: NEWTEXTMETRICEXW, + etmAxesList: AXESLISTW, +}} +pub type PENUMTEXTMETRICW = *mut ENUMTEXTMETRICW; +pub type LPENUMTEXTMETRICW = *mut ENUMTEXTMETRICW; +extern "system" { + pub fn GetViewportExtEx( + hdc: HDC, + lpsize: LPSIZE, + ) -> BOOL; + pub fn GetViewportOrgEx( + hdc: HDC, + lppoint: LPPOINT, + ) -> BOOL; + pub fn GetWindowExtEx( + hdc: HDC, + lpsize: LPSIZE, + ) -> BOOL; + pub fn GetWindowOrgEx( + hdc: HDC, + lppoint: LPPOINT, + ) -> BOOL; + pub fn IntersectClipRect( + hdc: HDC, + left: c_int, + top: c_int, + right: c_int, + bottom: c_int, + ) -> c_int; + pub fn InvertRgn( + hdc: HDC, + hrgn: HRGN, + ) -> BOOL; + pub fn LineDDA( + nXStart: c_int, + nYStart: c_int, + nXEnd: c_int, + nYEnd: c_int, + lpLineFunc: LINEDDAPROC, + lpData: LPARAM, + ) -> BOOL; + pub fn LineTo( + hdc: HDC, + nXEnd: c_int, + nYEnd: c_int, + ) -> BOOL; + pub fn MaskBlt( + hdcDest: HDC, + xDest: c_int, + yDest: c_int, + width: c_int, + height: c_int, + hdcSrc: HDC, + xSrc: c_int, + ySrc: c_int, + hbmMask: HBITMAP, + xMask: c_int, + yMask: c_int, + rop: DWORD, + ) -> BOOL; + pub fn PlgBlt( + hdcDest: HDC, + lpPoint: *const POINT, + hdcSrc: HDC, + xSrc: c_int, + ySrc: c_int, + width: c_int, + height: c_int, + hbmMask: HBITMAP, + xMask: c_int, + yMask: c_int, + ) -> BOOL; + pub fn OffsetClipRgn( + hdc: HDC, + x: c_int, + y: c_int, + ) -> c_int; + pub fn OffsetRgn( + hrgn: HRGN, + x: c_int, + y: c_int, + ) -> c_int; + pub fn PatBlt( + hdc: HDC, + nXLeft: c_int, + nYLeft: c_int, + nWidth: c_int, + nHeight: c_int, + dwRop: DWORD, + ) -> BOOL; + pub fn Pie( + hdc: HDC, + nLeftRect: c_int, + nTopRect: c_int, + nRightRect: c_int, + nBottomRect: c_int, + nXRadial1: c_int, + nYRadial1: c_int, + nXRadial2: c_int, + nYRadial2: c_int, + ) -> BOOL; + pub fn PlayMetaFile( + hdc: HDC, + hmf: HMETAFILE, + ) -> BOOL; + pub fn PaintRgn( + hdc: HDC, + hrgn: HRGN, + ) -> BOOL; + pub fn PolyPolygon( + hdc: HDC, + lpPoints: *const POINT, + lpPolyCounts: *const INT, + cCount: DWORD, + ) -> BOOL; + pub fn PtInRegion( + hrgn: HRGN, + x: c_int, + y: c_int, + ) -> BOOL; + pub fn PtVisible( + hdc: HDC, + x: c_int, + y: c_int, + ) -> BOOL; + pub fn RectInRegion( + hrgn: HRGN, + lprect: *const RECT, + ) -> BOOL; + pub fn RectVisible( + hdc: HDC, + lprect: *const RECT, + ) -> BOOL; + pub fn Rectangle( + hdc: HDC, + left: c_int, + top: c_int, + right: c_int, + bottom: c_int, + ) -> BOOL; + pub fn RestoreDC( + hdc: HDC, + nSavedDC: c_int, + ) -> BOOL; + pub fn ResetDCA( + hdc: HDC, + lpdm: *const DEVMODEA, + ) -> HDC; + pub fn ResetDCW( + hdc: HDC, + lpdm: *const DEVMODEW, + ) -> HDC; + pub fn RealizePalette( + hdc: HDC, + ) -> UINT; + pub fn RemoveFontResourceA( + lpFileName: LPCSTR, + ) -> BOOL; + pub fn RemoveFontResourceW( + lpFileName: LPCWSTR, + ) -> BOOL; + pub fn RoundRect( + hdc: HDC, + nLeftRect: c_int, + nTopRect: c_int, + nRightRect: c_int, + nBottomRect: c_int, + nWidth: c_int, + nHeight: c_int, + ) -> BOOL; + pub fn ResizePalette( + hpal: HPALETTE, + n: UINT, + ) -> BOOL; + pub fn SaveDC( + hdc: HDC, + ) -> c_int; + pub fn SelectClipRgn( + hdc: HDC, + hrgn: HRGN, + ) -> c_int; + pub fn ExtSelectClipRgn( + hdc: HDC, + hrgn: HRGN, + mode: c_int, + ) -> c_int; + pub fn SetMetaRgn( + hdc: HDC, + ) -> c_int; + pub fn SelectObject( + hdc: HDC, + h: HGDIOBJ, + ) -> HGDIOBJ; + pub fn SelectPalette( + hdc: HDC, + hPal: HPALETTE, + bForceBkgd: BOOL, + ) -> HPALETTE; + pub fn SetBkColor( + hdc: HDC, + color: COLORREF, + ) -> COLORREF; + pub fn SetDCBrushColor( + hdc: HDC, + color: COLORREF, + ) -> COLORREF; + pub fn SetDCPenColor( + hdc: HDC, + color: COLORREF, + ) -> COLORREF; + pub fn SetBkMode( + hdc: HDC, + mode: c_int, + ) -> c_int; + pub fn SetBitmapBits( + hbm: HBITMAP, + cb: DWORD, + pvBits: *const VOID, + ) -> LONG; + pub fn SetBoundsRect( + hdc: HDC, + lprect: *const RECT, + flags: UINT, + ) -> UINT; + pub fn SetDIBits( + hdc: HDC, + hbm: HBITMAP, + start: UINT, + cLines: UINT, + lpBits: *const VOID, + lpbmi: *const BITMAPINFO, + ColorUse: UINT, + ) -> c_int; + pub fn SetDIBitsToDevice( + hdc: HDC, + xDest: c_int, + yDest: c_int, + w: DWORD, + h: DWORD, + xSrc: c_int, + ySrc: c_int, + StartScan: UINT, + cLines: UINT, + lpvBits: *const VOID, + lpbmi: *const BITMAPINFO, + ColorUse: UINT, + ) -> c_int; + pub fn SetMapperFlags( + hdc: HDC, + flags: DWORD, + ) -> DWORD; + pub fn SetGraphicsMode( + hdc: HDC, + iMode: c_int, + ) -> c_int; + pub fn SetMapMode( + hdc: HDC, + mode: c_int, + ) -> c_int; + pub fn SetLayout( + hdc: HDC, + l: DWORD, + ) -> DWORD; + pub fn GetLayout( + hdc: HDC, + ) -> DWORD; + pub fn SetMetaFileBitsEx( + cbBuffer: UINT, + lpData: *const BYTE, + ) -> HMETAFILE; + pub fn SetPaletteEntries( + hpal: HPALETTE, + iStart: UINT, + cEntries: UINT, + pPalEntries: *const PALETTEENTRY, + ) -> UINT; + pub fn SetPixel( + hdc: HDC, + x: c_int, + y: c_int, + color: COLORREF, + ) -> COLORREF; + pub fn SetPixelV( + hdc: HDC, + x: c_int, + y: c_int, + color: COLORREF, + ) -> BOOL; + pub fn SetPixelFormat( + hdc: HDC, + iPixelFormat: c_int, + ppfd: *const PIXELFORMATDESCRIPTOR, + ) -> BOOL; + pub fn SetPolyFillMode( + hdc: HDC, + iPolyFillMode: c_int, + ) -> c_int; + pub fn StretchBlt( + hdcDest: HDC, + xDest: c_int, + yDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xSrc: c_int, + ySrc: c_int, + wSrc: c_int, + hSrc: c_int, + rop: DWORD, + ) -> BOOL; + pub fn SetRectRgn( + hrgn: HRGN, + left: c_int, + top: c_int, + right: c_int, + bottom: c_int, + ) -> BOOL; + pub fn StretchDIBits( + hdc: HDC, + XDest: c_int, + YDest: c_int, + nDestWidth: c_int, + nDestHeight: c_int, + XSrc: c_int, + YSrc: c_int, + nSrcWidth: c_int, + nSrcHeight: c_int, + lpBits: *const VOID, + lpBitsInfo: *const BITMAPINFO, + iUsage: UINT, + dwRop: DWORD, + ) -> c_int; + pub fn SetROP2( + hdc: HDC, + rop2: c_int, + ) -> c_int; + pub fn SetStretchBltMode( + hdc: HDC, + mode: c_int, + ) -> c_int; + pub fn SetSystemPaletteUse( + hdc: HDC, + uuse: UINT, + ) -> UINT; + pub fn SetTextCharacterExtra( + hdc: HDC, + extra: c_int, + ) -> c_int; + pub fn SetTextColor( + hdc: HDC, + color: COLORREF, + ) -> COLORREF; + pub fn SetTextAlign( + hdc: HDC, + align: UINT, + ) -> UINT; + pub fn SetTextJustification( + hdc: HDC, + extra: c_int, + count: c_int, + ) -> BOOL; + pub fn UpdateColors( + hdc: HDC, + ) -> BOOL; +} +pub type COLOR16 = c_ushort; +STRUCT!{struct TRIVERTEX { + x: LONG, + y: LONG, + Red: COLOR16, + Green: COLOR16, + Blue: COLOR16, + Alpha: COLOR16, +}} +pub type PTRIVERTEX = *mut TRIVERTEX; +pub type LPTRIVERTEX = *mut TRIVERTEX; +STRUCT!{struct GRADIENT_RECT { + UpperLeft: ULONG, + LowerRight: ULONG, +}} +pub type PGRADIENT_RECT = *mut GRADIENT_RECT; +pub type LPGRADIENT_RECT = *mut GRADIENT_RECT; +STRUCT!{struct BLENDFUNCTION { + BlendOp: BYTE, + BlendFlags: BYTE, + SourceConstantAlpha: BYTE, + AlphaFormat: BYTE, +}} +pub type PBLENDFUNCTION = *mut BLENDFUNCTION; +pub const AC_SRC_OVER: BYTE = 0x00; +pub const AC_SRC_ALPHA: BYTE = 0x01; +extern "system" { + pub fn AlphaBlend( + hdcDest: HDC, + xoriginDest: c_int, + yoriginDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xoriginSrc: c_int, + yoriginSrc: c_int, + wSrc: c_int, + hSrc: c_int, + ftn: BLENDFUNCTION, + ) -> BOOL; + pub fn TransparentBlt( + hdcDest: HDC, + xoriginDest: c_int, + yoriginDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xoriginSrc: c_int, + yoriginSrc: c_int, + wSrc: c_int, + hSrc: c_int, + crTransparent: UINT, + ) -> BOOL; +} +pub const GRADIENT_FILL_RECT_H: ULONG = 0x00000000; +pub const GRADIENT_FILL_RECT_V: ULONG = 0x00000001; +pub const GRADIENT_FILL_TRIANGLE: ULONG = 0x00000002; +pub const GRADIENT_FILL_OP_FLAG: ULONG = 0x000000ff; +extern "system" { + pub fn GradientFill( + hdc: HDC, + pVertex: PTRIVERTEX, + nVertex: ULONG, + pMesh: PVOID, + nMesh: ULONG, + ulMode: ULONG, + ) -> BOOL; + pub fn GdiAlphaBlend( + hdcDest: HDC, + xoriginDest: c_int, + yoriginDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xoriginSrc: c_int, + yoriginSrc: c_int, + wSrc: c_int, + hSrc: c_int, + ftn: BLENDFUNCTION, + ) -> BOOL; + pub fn GdiTransparentBlt( + hdcDest: HDC, + xoriginDest: c_int, + yoriginDest: c_int, + wDest: c_int, + hDest: c_int, + hdcSrc: HDC, + xoriginSrc: c_int, + yoriginSrc: c_int, + wSrc: c_int, + hSrc: c_int, + crTransparent: UINT, + ) -> BOOL; + pub fn GdiGradientFill( + hdc: HDC, + pVertex: PTRIVERTEX, + nVertex: ULONG, + pMesh: PVOID, + nCount: ULONG, + ulMode: ULONG, + ) -> BOOL; + pub fn PlayMetaFileRecord( + hdc: HDC, + lpHandleTable: LPHANDLETABLE, + lpMR: LPMETARECORD, + noObjs: UINT, + ) -> BOOL; +} +FN!{stdcall MFENUMPROC( + hdc: HDC, + lpht: *mut HANDLETABLE, + lpMR: *mut METARECORD, + nObj: c_int, + param: LPARAM, +) -> c_int} +extern "system" { + pub fn EnumMetaFile( + hdc: HDC, + hmf: HMETAFILE, + mproc: MFENUMPROC, + param: LPARAM, + ) -> BOOL; +} +FN!{stdcall ENHMFENUMPROC( + hdc: HDC, + lpht: *mut HANDLETABLE, + lpmr: *const ENHMETARECORD, + nHandles: c_int, + data: LPARAM, +) -> c_int} +extern "system" { + pub fn CloseEnhMetaFile( + hdc: HDC, + ) -> HENHMETAFILE; + pub fn CopyEnhMetaFileA( + hemfSrc: HENHMETAFILE, + lpszFile: LPCSTR, + ) -> HENHMETAFILE; + pub fn CopyEnhMetaFileW( + hemfSrc: HENHMETAFILE, + lpszFile: LPCWSTR, + ) -> HENHMETAFILE; + pub fn CreateEnhMetaFileA( + hdcRef: HDC, + lpFilename: LPCSTR, + lpRect: *const RECT, + lpDescription: LPCSTR, + ) -> HDC; + pub fn CreateEnhMetaFileW( + hdcRef: HDC, + lpFilename: LPCWSTR, + lpRect: *const RECT, + lpDescription: LPCWSTR, + ) -> HDC; + pub fn DeleteEnhMetaFile( + hmf: HENHMETAFILE, + ) -> BOOL; + pub fn EnumEnhMetaFile( + hdc: HDC, + hmf: HENHMETAFILE, + lpProc: ENHMFENUMPROC, + param: LPVOID, + lpRect: *const RECT, + ) -> BOOL; + pub fn GetEnhMetaFileA( + lpName: LPCSTR, + ) -> HENHMETAFILE; + pub fn GetEnhMetaFileW( + lpName: LPCWSTR, + ) -> HENHMETAFILE; + pub fn GetEnhMetaFileBits( + hEMF: HENHMETAFILE, + nSize: UINT, + lpData: LPBYTE, + ) -> UINT; + pub fn GetEnhMetaFileDescriptionA( + hemf: HENHMETAFILE, + cchBuffer: UINT, + lpDescription: LPSTR, + ) -> UINT; + pub fn GetEnhMetaFileDescriptionW( + hemf: HENHMETAFILE, + cchBuffer: UINT, + lpDescription: LPWSTR, + ) -> UINT; + pub fn GetEnhMetaFileHeader( + hemf: HENHMETAFILE, + nSize: UINT, + lpEnhMetaHeader: LPENHMETAHEADER, + ) -> UINT; + pub fn GetEnhMetaFilePaletteEntries( + hemf: HENHMETAFILE, + nNumEntries: UINT, + lpPaletteEntries: LPPALETTEENTRY, + ) -> UINT; + pub fn GetEnhMetaFilePixelFormat( + hemf: HENHMETAFILE, + cbBuffer: UINT, + ppfd: *mut PIXELFORMATDESCRIPTOR, + ) -> UINT; + pub fn GetWinMetaFileBits( + hemf: HENHMETAFILE, + cbData16: UINT, + pData16: LPBYTE, + iMapMode: INT, + hdcRef: HDC, + ) -> UINT; + pub fn PlayEnhMetaFile( + hdc: HDC, + hmf: HENHMETAFILE, + lprect: *const RECT, + ) -> BOOL; + pub fn PlayEnhMetaFileRecord( + hdc: HDC, + pht: LPHANDLETABLE, + pmr: *const ENHMETARECORD, + cht: UINT, + ) -> BOOL; + pub fn SetEnhMetaFileBits( + nSize: UINT, + pb: *const BYTE, + ) -> HENHMETAFILE; + pub fn SetWinMetaFileBits( + nSize: UINT, + lpMeta16Data: *const BYTE, + hdcRef: HDC, + lpMFP: *const METAFILEPICT, + ) -> HENHMETAFILE; + pub fn GdiComment( + hdc: HDC, + nSize: UINT, + lpData: *const BYTE, + ) -> BOOL; + pub fn GetTextMetricsA( + hdc: HDC, + lptm: LPTEXTMETRICA, + ) -> BOOL; + pub fn GetTextMetricsW( + hdc: HDC, + lptm: *mut TEXTMETRICW, + ) -> BOOL; +} +STRUCT!{struct DIBSECTION { + dsBm: BITMAP, + dsBmih: BITMAPINFOHEADER, + dsBitfields: [DWORD; 3], + dshSection: HANDLE, + dsOffset: DWORD, +}} +pub type PDIBSECTION = *mut DIBSECTION; +pub type LPDIBSECTION = *mut DIBSECTION; +extern "system" { + pub fn AngleArc( + hdc: HDC, + X: c_int, + Y: c_int, + dwRadius: DWORD, + eStartAngle: FLOAT, + eSweepAngle: FLOAT, + ) -> BOOL; + pub fn PolyPolyline( + hdc: HDC, + lppt: *const POINT, + lpdwPolyPoints: *const DWORD, + cCount: DWORD, + ) -> BOOL; + pub fn GetWorldTransform( + hdc: HDC, + lpxf: LPXFORM, + ) -> BOOL; + pub fn SetWorldTransform( + hdc: HDC, + lpxf: *const XFORM, + ) -> BOOL; + pub fn ModifyWorldTransform( + hdc: HDC, + lpxf: *const XFORM, + mode: DWORD, + ) -> BOOL; + pub fn CombineTransform( + lpxformResult: LPXFORM, + lpxform1: *const XFORM, + lpxform2: *const XFORM, + ) -> BOOL; +} +#[inline] +pub fn GDI_WIDTHBYTES(bits: DWORD) -> DWORD { + ((bits + 31) & !31) / 8 +} +#[inline] +pub fn GDI_DIBWIDTHBYTES(bi: &BITMAPINFOHEADER) -> DWORD { + GDI_WIDTHBYTES((bi.biWidth as DWORD) * (bi.biBitCount as DWORD)) +} +#[inline] +pub fn GDI__DIBSIZE(bi: &BITMAPINFOHEADER) -> DWORD { + GDI_DIBWIDTHBYTES(bi) * bi.biHeight as DWORD +} +#[inline] +pub fn GDI_DIBSIZE(bi: &BITMAPINFOHEADER) -> DWORD { + if bi.biHeight < 0 { + GDI__DIBSIZE(bi) * -1i32 as u32 + } else { + GDI__DIBSIZE(bi) + } +} +extern "system" { + pub fn CreateDIBSection( + hdc: HDC, + lpbmi: *const BITMAPINFO, + usage: UINT, + ppvBits: *mut *mut c_void, + hSection: HANDLE, + offset: DWORD, + ) -> HBITMAP; + pub fn GetDIBColorTable( + hdc: HDC, + iStart: UINT, + cEntries: UINT, + prgbq: *mut RGBQUAD, + ) -> UINT; + pub fn SetDIBColorTable( + hdc: HDC, + iStart: UINT, + cEntries: UINT, + prgbq: *const RGBQUAD, + ) -> UINT; +} +pub const CA_NEGATIVE: WORD = 0x0001; +pub const CA_LOG_FILTER: WORD = 0x0002; +pub const ILLUMINANT_DEVICE_DEFAULT: WORD = 0; +pub const ILLUMINANT_A: WORD = 1; +pub const ILLUMINANT_B: WORD = 2; +pub const ILLUMINANT_C: WORD = 3; +pub const ILLUMINANT_D50: WORD = 4; +pub const ILLUMINANT_D55: WORD = 5; +pub const ILLUMINANT_D65: WORD = 6; +pub const ILLUMINANT_D75: WORD = 7; +pub const ILLUMINANT_F2: WORD = 8; +pub const ILLUMINANT_MAX_INDEX: WORD = ILLUMINANT_F2; +pub const ILLUMINANT_TUNGSTEN: WORD = ILLUMINANT_A; +pub const ILLUMINANT_DAYLIGHT: WORD = ILLUMINANT_C; +pub const ILLUMINANT_FLUORESCENT: WORD = ILLUMINANT_F2; +pub const ILLUMINANT_NTSC: WORD = ILLUMINANT_C; +pub const RGB_GAMMA_MIN: WORD = 0o2500; // FIXME It is octal in the headers but are the headers actually right? +pub const RGB_GAMMA_MAX: WORD = 65000; +pub const REFERENCE_WHITE_MIN: WORD = 6000; +pub const REFERENCE_WHITE_MAX: WORD = 10000; +pub const REFERENCE_BLACK_MIN: WORD = 0; +pub const REFERENCE_BLACK_MAX: WORD = 4000; +pub const COLOR_ADJ_MIN: SHORT = -100; +pub const COLOR_ADJ_MAX: SHORT = 100; +STRUCT!{struct COLORADJUSTMENT { + caSize: WORD, + caFlags: WORD, + caIlluminantIndex: WORD, + caRedGamma: WORD, + caGreenGamma: WORD, + caBlueGamma: WORD, + caReferenceBlack: WORD, + caReferenceWhite: WORD, + caContrast: SHORT, + caBrightness: SHORT, + caColorfulness: SHORT, + caRedGreenTint: SHORT, +}} +pub type PCOLORADJUSTMENT = *mut COLORADJUSTMENT; +pub type LPCOLORADJUSTMENT = *mut COLORADJUSTMENT; +extern "system" { + pub fn SetColorAdjustment( + hdc: HDC, + lpca: *const COLORADJUSTMENT, + ) -> BOOL; + pub fn GetColorAdjustment( + hdc: HDC, + lpca: LPCOLORADJUSTMENT, + ) -> BOOL; + pub fn CreateHalftonePalette( + hdc: HDC, + ) -> HPALETTE; +} +FN!{stdcall ABORTPROC( + HDC, + c_int, +) -> BOOL} +STRUCT!{struct DOCINFOA { + cbSize: c_int, + lpszDocName: LPCSTR, + lpszOutput: LPCSTR, + lpszDatatype: LPCSTR, + fwType: DWORD, +}} +pub type LPDOCINFOA = *mut DOCINFOA; +STRUCT!{struct DOCINFOW { + cbSize: c_int, + lpszDocName: LPCWSTR, + lpszOutput: LPCWSTR, + lpszDatatype: LPCWSTR, + fwType: DWORD, +}} +pub type LPDOCINFOW = *mut DOCINFOW; +pub const DI_APPBANDING: DWORD = 0x00000001; +pub const DI_ROPS_READ_DESTINATION: DWORD = 0x00000002; +extern "system" { + pub fn StartDocA( + hdc: HDC, + lpdi: *const DOCINFOA, + ) -> c_int; + pub fn StartDocW( + hdc: HDC, + lpdi: *const DOCINFOW, + ) -> c_int; + pub fn EndDoc( + hdc: HDC, + ) -> c_int; + pub fn StartPage( + hdc: HDC, + ) -> c_int; + pub fn EndPage( + hdc: HDC, + ) -> c_int; + pub fn AbortDoc( + hdc: HDC, + ) -> c_int; + pub fn SetAbortProc( + hdc: HDC, + aproc: ABORTPROC, + ) -> c_int; + pub fn AbortPath( + hdc: HDC, + ) -> BOOL; + pub fn ArcTo( + hdc: HDC, + nLeftRect: c_int, + nTopRect: c_int, + nRightRect: c_int, + nBottomRect: c_int, + nXRadial1: c_int, + nYRadial1: c_int, + nXRadial2: c_int, + nYRadial2: c_int, + ) -> BOOL; + pub fn BeginPath( + hdc: HDC, + ) -> BOOL; + pub fn CloseFigure( + hdc: HDC, + ) -> BOOL; + pub fn EndPath( + hdc: HDC, + ) -> BOOL; + pub fn FillPath( + hdc: HDC, + ) -> BOOL; + pub fn FlattenPath( + hdc: HDC, + ) -> BOOL; + pub fn GetPath( + hdc: HDC, + apt: LPPOINT, + aj: LPBYTE, + cpt: c_int, + ) -> c_int; + pub fn PathToRegion( + hdc: HDC, + ) -> HRGN; + pub fn PolyDraw( + hdc: HDC, + lppt: *const POINT, + lpbTypes: *const BYTE, + cCount: c_int, + ) -> BOOL; + pub fn SelectClipPath( + hdc: HDC, + mode: c_int, + ) -> BOOL; + pub fn SetArcDirection( + hdc: HDC, + ArcDirection: c_int, + ) -> c_int; + pub fn SetMiterLimit( + hdc: HDC, + limit: FLOAT, + old: PFLOAT, + ) -> BOOL; + pub fn StrokeAndFillPath( + hdc: HDC, + ) -> BOOL; + pub fn StrokePath( + hdc: HDC, + ) -> BOOL; + pub fn WidenPath( + hdc: HDC, + ) -> BOOL; + pub fn ExtCreatePen( + iPenStyle: DWORD, + cWidth: DWORD, + plbrush: *const LOGBRUSH, + cStyle: DWORD, + pstyle: *const DWORD, + ) -> HPEN; + pub fn GetMiterLimit( + hdc: HDC, + plimit: PFLOAT, + ) -> BOOL; + pub fn GetArcDirection( + hdc: HDC, + ) -> c_int; + pub fn GetObjectA( + h: HANDLE, + c: c_int, + pv: LPVOID, + ) -> c_int; + pub fn GetObjectW( + h: HANDLE, + c: c_int, + pv: LPVOID, + ) -> c_int; + pub fn MoveToEx( + hdc: HDC, + X: c_int, + Y: c_int, + lpPoint:LPPOINT, + ) -> BOOL; + pub fn TextOutA( + hdc: HDC, + x: c_int, + y: c_int, + lpString: LPCSTR, + c: c_int, + ) -> BOOL; + pub fn TextOutW( + hdc: HDC, + x: c_int, + y: c_int, + lpString: LPCWSTR, + c: c_int, + ) -> BOOL; + pub fn ExtTextOutA( + hdc: HDC, + x: c_int, + y: c_int, + options: UINT, + lprect: *const RECT, + lpString: LPCSTR, + c: UINT, + lpDx: *const INT, + ) -> BOOL; + pub fn ExtTextOutW( + hdc: HDC, + x: c_int, + y: c_int, + options: UINT, + lprect: *const RECT, + lpString: LPCWSTR, + c: UINT, + lpDx: *const INT, + ) -> BOOL; + pub fn PolyTextOutA( + hdc: HDC, + ppt: *const POLYTEXTA, + nstrings: c_int, + ) -> BOOL; + pub fn PolyTextOutW( + hdc: HDC, + ppt: *const POLYTEXTW, + nstrings: c_int, + ) -> BOOL; + pub fn CreatePolygonRgn( + lppt: *const POINT, + cPoints: c_int, + fnPolyFillMode: c_int, + ) -> HRGN; + pub fn DPtoLP( + hdc: HDC, + lppt: *mut POINT, + c: c_int, + ) -> BOOL; + pub fn LPtoDP( + hdc: HDC, + lppt: LPPOINT, + c: c_int, + ) -> BOOL; + pub fn Polygon( + hdc: HDC, + lpPoints: *const POINT, + nCount: c_int, + ) -> BOOL; + pub fn Polyline( + hdc: HDC, + lppt: *const POINT, + cCount: c_int, + ) -> BOOL; + pub fn PolyBezier( + hdc: HDC, + lppt: *const POINT, + cPoints: DWORD, + ) -> BOOL; + pub fn PolyBezierTo( + hdc: HDC, + lppt: *const POINT, + cPoints: DWORD, + ) -> BOOL; + pub fn PolylineTo( + hdc: HDC, + lppt: *const POINT, + cCount: DWORD, + ) -> BOOL; + pub fn SetViewportExtEx( + hdc: HDC, + x: c_int, + y: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn SetViewportOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: *mut POINT, + ) -> BOOL; + pub fn SetWindowExtEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: LPSIZE, + ) -> BOOL; + pub fn SetWindowOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: LPPOINT, + ) -> BOOL; + pub fn OffsetViewportOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: LPPOINT, + ) -> BOOL; + pub fn OffsetWindowOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: LPPOINT, + ) -> BOOL; + pub fn ScaleViewportExtEx( + hdc: HDC,xn: c_int, + dx: c_int, + yn: c_int, + yd: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn ScaleWindowExtEx( + hdc: HDC, + xn: c_int, + xd: c_int, + yn: c_int, + yd: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn SetBitmapDimensionEx( + hbm: HBITMAP, + w: c_int, + h: c_int, + lpsz: LPSIZE, + ) -> BOOL; + pub fn SetBrushOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + lppt: LPPOINT, + ) -> BOOL; + pub fn GetTextFaceA( + hdc: HDC, + c: c_int, + lpName: LPSTR, + ) -> c_int; + pub fn GetTextFaceW( + hdc: HDC, + c: c_int, + lpName: LPWSTR, + ) -> c_int; +} +STRUCT!{struct KERNINGPAIR { + wFirst: WORD, + wSecond: WORD, + iKernAmount: c_int, +}} +pub type LPKERNINGPAIR = *mut KERNINGPAIR; +extern "system" { + pub fn GetKerningPairsA( + hdc: HDC, + nPairs: DWORD, + lpKernPair: LPKERNINGPAIR, + ) -> DWORD; + pub fn GetKerningPairsW( + hdc: HDC, + nPairs: DWORD, + lpKernPair: LPKERNINGPAIR, + ) -> DWORD; + pub fn GetDCOrgEx( + hdc: HDC, + lppt: LPPOINT, + ) -> BOOL; + pub fn FixBrushOrgEx( + hdc: HDC, + x: c_int, + y: c_int, + ptl: LPPOINT, + ) -> BOOL; + pub fn UnrealizeObject( + h: HGDIOBJ, + ) -> BOOL; + pub fn GdiFlush() -> BOOL; + pub fn GdiSetBatchLimit( + dw: DWORD, + ) -> DWORD; + pub fn GdiGetBatchLimit() -> DWORD; +} +pub const ICM_OFF: c_int = 1; +pub const ICM_ON: c_int = 2; +pub const ICM_QUERY: c_int = 3; +pub const ICM_DONE_OUTSIDEDC: c_int = 4; +FN!{stdcall ICMENUMPROCA( + LPSTR, + LPARAM, +) -> c_int} +FN!{stdcall ICMENUMPROCW( + LPWSTR, + LPARAM, +) -> c_int} +extern "system" { + pub fn SetICMMode( + hdc: HDC, + mode: c_int, + ) -> c_int; + pub fn CheckColorsInGamut( + hDC: HDC, + lpRGBTriples: LPVOID, + lpBuffer: LPVOID, + nCount: UINT, + ) -> BOOL; + pub fn GetColorSpace( + hdc: HDC, + ) -> HCOLORSPACE; + pub fn GetLogColorSpaceA( + hColorSpace: HCOLORSPACE, + lpBuffer: LPLOGCOLORSPACEA, + nSize: DWORD, + ) -> BOOL; + pub fn GetLogColorSpaceW( + hColorSpace: HCOLORSPACE, + lpBuffer: LPLOGCOLORSPACEW, + nSize: DWORD, + ) -> BOOL; + pub fn CreateColorSpaceA( + lpLogColorSpace: LPLOGCOLORSPACEA, + ) -> HCOLORSPACE; + pub fn CreateColorSpaceW( + lpLogColorSpace: LPLOGCOLORSPACEW, + ) -> HCOLORSPACE; + pub fn SetColorSpace( + hdc: HDC, + hcs: HCOLORSPACE, + ) -> HCOLORSPACE; + pub fn DeleteColorSpace( + hcs: HCOLORSPACE, + ) -> BOOL; + pub fn GetICMProfileA( + hdc: HDC, + pBufSize: LPDWORD, + pszFilename: LPSTR, + ) -> BOOL; + pub fn GetICMProfileW( + hdc: HDC, + pBufSize: LPDWORD, + pszFilename: LPWSTR, + ) -> BOOL; + pub fn SetICMProfileA( + hdc: HDC, + lpFileName: LPSTR, + ) -> BOOL; + pub fn SetICMProfileW( + hdc: HDC, + lpFileName: LPWSTR, + ) -> BOOL; + pub fn GetDeviceGammaRamp( + hdc: HDC, + lpRamp: LPVOID, + ) -> BOOL; + pub fn SetDeviceGammaRamp( + hdc: HDC, + lpRamp: LPVOID, + ) -> BOOL; + pub fn ColorMatchToTarget( + hDC: HDC, + hdcTarget: HDC, + uiAction: UINT, + ) -> BOOL; + pub fn EnumICMProfilesA( + hdc: HDC, + iproc: ICMENUMPROCA, + param: LPARAM, + ) -> c_int; + pub fn EnumICMProfilesW( + hdc: HDC, + iproc: ICMENUMPROCW, + param: LPARAM, + ) -> c_int; + pub fn UpdateICMRegKeyA( + reserved: DWORD, + lpszCMID: LPSTR, + lpszFileName: LPSTR, + command: UINT, + ) -> BOOL; + pub fn UpdateICMRegKeyW( + reserved: DWORD, + lpszCMID: LPWSTR, + lpszFileName: LPWSTR, + command: UINT, + ) -> BOOL; + pub fn ColorCorrectPalette( + hDC: HDC, + hPalette: HPALETTE, + dwFirstEntry: DWORD, + dwNumOfEntries: DWORD, + ) -> BOOL; +} +pub const ENHMETA_SIGNATURE: DWORD = 0x464D4520; +pub const ENHMETA_STOCK_OBJECT: DWORD = 0x80000000; +pub const EMR_HEADER: DWORD = 1; +pub const EMR_POLYBEZIER: DWORD = 2; +pub const EMR_POLYGON: DWORD = 3; +pub const EMR_POLYLINE: DWORD = 4; +pub const EMR_POLYBEZIERTO: DWORD = 5; +pub const EMR_POLYLINETO: DWORD = 6; +pub const EMR_POLYPOLYLINE: DWORD = 7; +pub const EMR_POLYPOLYGON: DWORD = 8; +pub const EMR_SETWINDOWEXTEX: DWORD = 9; +pub const EMR_SETWINDOWORGEX: DWORD = 10; +pub const EMR_SETVIEWPORTEXTEX: DWORD = 11; +pub const EMR_SETVIEWPORTORGEX: DWORD = 12; +pub const EMR_SETBRUSHORGEX: DWORD = 13; +pub const EMR_EOF: DWORD = 14; +pub const EMR_SETPIXELV: DWORD = 15; +pub const EMR_SETMAPPERFLAGS: DWORD = 16; +pub const EMR_SETMAPMODE: DWORD = 17; +pub const EMR_SETBKMODE: DWORD = 18; +pub const EMR_SETPOLYFILLMODE: DWORD = 19; +pub const EMR_SETROP2: DWORD = 20; +pub const EMR_SETSTRETCHBLTMODE: DWORD = 21; +pub const EMR_SETTEXTALIGN: DWORD = 22; +pub const EMR_SETCOLORADJUSTMENT: DWORD = 23; +pub const EMR_SETTEXTCOLOR: DWORD = 24; +pub const EMR_SETBKCOLOR: DWORD = 25; +pub const EMR_OFFSETCLIPRGN: DWORD = 26; +pub const EMR_MOVETOEX: DWORD = 27; +pub const EMR_SETMETARGN: DWORD = 28; +pub const EMR_EXCLUDECLIPRECT: DWORD = 29; +pub const EMR_INTERSECTCLIPRECT: DWORD = 30; +pub const EMR_SCALEVIEWPORTEXTEX: DWORD = 31; +pub const EMR_SCALEWINDOWEXTEX: DWORD = 32; +pub const EMR_SAVEDC: DWORD = 33; +pub const EMR_RESTOREDC: DWORD = 34; +pub const EMR_SETWORLDTRANSFORM: DWORD = 35; +pub const EMR_MODIFYWORLDTRANSFORM: DWORD = 36; +pub const EMR_SELECTOBJECT: DWORD = 37; +pub const EMR_CREATEPEN: DWORD = 38; +pub const EMR_CREATEBRUSHINDIRECT: DWORD = 39; +pub const EMR_DELETEOBJECT: DWORD = 40; +pub const EMR_ANGLEARC: DWORD = 41; +pub const EMR_ELLIPSE: DWORD = 42; +pub const EMR_RECTANGLE: DWORD = 43; +pub const EMR_ROUNDRECT: DWORD = 44; +pub const EMR_ARC: DWORD = 45; +pub const EMR_CHORD: DWORD = 46; +pub const EMR_PIE: DWORD = 47; +pub const EMR_SELECTPALETTE: DWORD = 48; +pub const EMR_CREATEPALETTE: DWORD = 49; +pub const EMR_SETPALETTEENTRIES: DWORD = 50; +pub const EMR_RESIZEPALETTE: DWORD = 51; +pub const EMR_REALIZEPALETTE: DWORD = 52; +pub const EMR_EXTFLOODFILL: DWORD = 53; +pub const EMR_LINETO: DWORD = 54; +pub const EMR_ARCTO: DWORD = 55; +pub const EMR_POLYDRAW: DWORD = 56; +pub const EMR_SETARCDIRECTION: DWORD = 57; +pub const EMR_SETMITERLIMIT: DWORD = 58; +pub const EMR_BEGINPATH: DWORD = 59; +pub const EMR_ENDPATH: DWORD = 60; +pub const EMR_CLOSEFIGURE: DWORD = 61; +pub const EMR_FILLPATH: DWORD = 62; +pub const EMR_STROKEANDFILLPATH: DWORD = 63; +pub const EMR_STROKEPATH: DWORD = 64; +pub const EMR_FLATTENPATH: DWORD = 65; +pub const EMR_WIDENPATH: DWORD = 66; +pub const EMR_SELECTCLIPPATH: DWORD = 67; +pub const EMR_ABORTPATH: DWORD = 68; +pub const EMR_GDICOMMENT: DWORD = 70; +pub const EMR_FILLRGN: DWORD = 71; +pub const EMR_FRAMERGN: DWORD = 72; +pub const EMR_INVERTRGN: DWORD = 73; +pub const EMR_PAINTRGN: DWORD = 74; +pub const EMR_EXTSELECTCLIPRGN: DWORD = 75; +pub const EMR_BITBLT: DWORD = 76; +pub const EMR_STRETCHBLT: DWORD = 77; +pub const EMR_MASKBLT: DWORD = 78; +pub const EMR_PLGBLT: DWORD = 79; +pub const EMR_SETDIBITSTODEVICE: DWORD = 80; +pub const EMR_STRETCHDIBITS: DWORD = 81; +pub const EMR_EXTCREATEFONTINDIRECTW: DWORD = 82; +pub const EMR_EXTTEXTOUTA: DWORD = 83; +pub const EMR_EXTTEXTOUTW: DWORD = 84; +pub const EMR_POLYBEZIER16: DWORD = 85; +pub const EMR_POLYGON16: DWORD = 86; +pub const EMR_POLYLINE16: DWORD = 87; +pub const EMR_POLYBEZIERTO16: DWORD = 88; +pub const EMR_POLYLINETO16: DWORD = 89; +pub const EMR_POLYPOLYLINE16: DWORD = 90; +pub const EMR_POLYPOLYGON16: DWORD = 91; +pub const EMR_POLYDRAW16: DWORD = 92; +pub const EMR_CREATEMONOBRUSH: DWORD = 93; +pub const EMR_CREATEDIBPATTERNBRUSHPT: DWORD = 94; +pub const EMR_EXTCREATEPEN: DWORD = 95; +pub const EMR_POLYTEXTOUTA: DWORD = 96; +pub const EMR_POLYTEXTOUTW: DWORD = 97; +pub const EMR_SETICMMODE: DWORD = 98; +pub const EMR_CREATECOLORSPACE: DWORD = 99; +pub const EMR_SETCOLORSPACE: DWORD = 100; +pub const EMR_DELETECOLORSPACE: DWORD = 101; +pub const EMR_GLSRECORD: DWORD = 102; +pub const EMR_GLSBOUNDEDRECORD: DWORD = 103; +pub const EMR_PIXELFORMAT: DWORD = 104; +pub const EMR_RESERVED_105: DWORD = 105; +pub const EMR_RESERVED_106: DWORD = 106; +pub const EMR_RESERVED_107: DWORD = 107; +pub const EMR_RESERVED_108: DWORD = 108; +pub const EMR_RESERVED_109: DWORD = 109; +pub const EMR_RESERVED_110: DWORD = 110; +pub const EMR_COLORCORRECTPALETTE: DWORD = 111; +pub const EMR_SETICMPROFILEA: DWORD = 112; +pub const EMR_SETICMPROFILEW: DWORD = 113; +pub const EMR_ALPHABLEND: DWORD = 114; +pub const EMR_SETLAYOUT: DWORD = 115; +pub const EMR_TRANSPARENTBLT: DWORD = 116; +pub const EMR_RESERVED_117: DWORD = 117; +pub const EMR_GRADIENTFILL: DWORD = 118; +pub const EMR_RESERVED_119: DWORD = 119; +pub const EMR_RESERVED_120: DWORD = 120; +pub const EMR_COLORMATCHTOTARGETW: DWORD = 121; +pub const EMR_CREATECOLORSPACEW: DWORD = 122; +pub const EMR_MIN: DWORD = 1; +pub const EMR_MAX: DWORD = 122; +STRUCT!{struct EMR { + iType: DWORD, + nSize: DWORD, +}} +pub type PEMR = *mut EMR; +STRUCT!{struct EMRTEXT { + ptlReference: POINTL, + nChars: DWORD, + offString: DWORD, + fOptions: DWORD, + rcl: RECTL, + offDx: DWORD, +}} +pub type PEMRTEXT = *mut EMRTEXT; +STRUCT!{struct EMRABORTPATH { + emr: EMR, +}} +pub type PEMRABORTPATH = *mut EMRABORTPATH; +pub type EMRBEGINPATH = EMRABORTPATH; +pub type PEMRBEGINPATH = *mut EMRABORTPATH; +pub type EMRENDPATH = EMRABORTPATH; +pub type PEMRENDPATH = *mut EMRABORTPATH; +pub type EMRCLOSEFIGURE = EMRABORTPATH; +pub type PEMRCLOSEFIGURE = *mut EMRABORTPATH; +pub type EMRFLATTENPATH = EMRABORTPATH; +pub type PEMRFLATTENPATH = *mut EMRABORTPATH; +pub type EMRWIDENPATH = EMRABORTPATH; +pub type PEMRWIDENPATH = *mut EMRABORTPATH; +pub type EMRSETMETARGN = EMRABORTPATH; +pub type PEMRSETMETARGN = *mut EMRABORTPATH; +pub type EMRSAVEDC = EMRABORTPATH; +pub type PEMRSAVEDC = *mut EMRABORTPATH; +pub type EMRREALIZEPALETTE = EMRABORTPATH; +pub type PEMRREALIZEPALETTE = *mut EMRABORTPATH; +STRUCT!{struct EMRSELECTCLIPPATH { + emr: EMR, + iMode: DWORD, +}} +pub type PEMRSELECTCLIPPATH = *mut EMRSELECTCLIPPATH; +pub type EMRSETBKMODE = EMRSELECTCLIPPATH; +pub type PEMRSETBKMODE = *mut EMRSELECTCLIPPATH; +pub type EMRSETMAPMODE = EMRSELECTCLIPPATH; +pub type PEMRSETMAPMODE = *mut EMRSELECTCLIPPATH; +pub type EMRSETLAYOUT = EMRSELECTCLIPPATH; +pub type PEMRSETLAYOUT = *mut EMRSELECTCLIPPATH; +pub type EMRSETPOLYFILLMODE = EMRSELECTCLIPPATH; +pub type PEMRSETPOLYFILLMODE = *mut EMRSELECTCLIPPATH; +pub type EMRSETROP2 = EMRSELECTCLIPPATH; +pub type PEMRSETROP2 = *mut EMRSELECTCLIPPATH; +pub type EMRSETSTRETCHBLTMODE = EMRSELECTCLIPPATH; +pub type PEMRSETSTRETCHBLTMODE = *mut EMRSELECTCLIPPATH; +pub type EMRSETICMMODE = EMRSELECTCLIPPATH; +pub type PEMRSETICMMODE = *mut EMRSELECTCLIPPATH; +pub type EMRSETTEXTALIGN = EMRSELECTCLIPPATH; +pub type PEMRSETTEXTALIGN = *mut EMRSELECTCLIPPATH; +STRUCT!{struct EMRSETMITERLIMIT { + emr: EMR, + eMiterLimit: FLOAT, +}} +pub type PEMRSETMITERLIMIT = *mut EMRSETMITERLIMIT; +STRUCT!{struct EMRRESTOREDC { + emr: EMR, + iRelative: LONG, +}} +pub type PEMRRESTOREDC = *mut EMRRESTOREDC; +STRUCT!{struct EMRSETARCDIRECTION { + emr: EMR, + iArcDirection: DWORD, +}} +pub type PEMRSETARCDIRECTION = *mut EMRSETARCDIRECTION; +STRUCT!{struct EMRSETMAPPERFLAGS { + emr: EMR, + dwFlags: DWORD, +}} +pub type PEMRSETMAPPERFLAGS = *mut EMRSETMAPPERFLAGS; +STRUCT!{struct EMRSETBKCOLOR { + emr: EMR, + crColor: COLORREF, +}} +pub type PEMRSETBKCOLOR = *mut EMRSETBKCOLOR; +pub type EMRSETTEXTCOLOR = EMRSETBKCOLOR; +pub type PEMRSETTEXTCOLOR = *mut EMRSETBKCOLOR; +STRUCT!{struct EMRSELECTOBJECT { + emr: EMR, + ihObject: DWORD, +}} +pub type PEMRSELECTOBJECT = *mut EMRSELECTOBJECT; +pub type EMRDELETEOBJECT = EMRSELECTOBJECT; +pub type PEMRDELETEOBJECT = *mut EMRSELECTOBJECT; +STRUCT!{struct EMRSELECTPALETTE { + emr: EMR, + ihPal: DWORD, +}} +pub type PEMRSELECTPALETTE = *mut EMRSELECTPALETTE; +STRUCT!{struct EMRRESIZEPALETTE { + emr: EMR, + ihPal: DWORD, + cEntries: DWORD, +}} +pub type PEMRRESIZEPALETTE = *mut EMRRESIZEPALETTE; +STRUCT!{struct EMRSETPALETTEENTRIES { + emr: EMR, + ihPal: DWORD, + iStart: DWORD, + cEntries: DWORD, + aPalEntries: [PALETTEENTRY; 1], +}} +pub type PEMRSETPALETTEENTRIES = *mut EMRSETPALETTEENTRIES; +STRUCT!{struct EMRSETCOLORADJUSTMENT { + emr: EMR, + ColorAdjustment: COLORADJUSTMENT, +}} +pub type PEMRSETCOLORADJUSTMENT = *mut EMRSETCOLORADJUSTMENT; +STRUCT!{struct EMRGDICOMMENT { + emr: EMR, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRGDICOMMENT = *mut EMRGDICOMMENT; +STRUCT!{struct EMREOF { + emr: EMR, + nPalEntries: DWORD, + offPalEntries: DWORD, + nSizeLast: DWORD, +}} +pub type PEMREOF = *mut EMREOF; +STRUCT!{struct EMRLINETO { + emr: EMR, + ptl: POINTL, +}} +pub type PEMRLINETO = *mut EMRLINETO; +pub type EMRMOVETOEX = EMRLINETO; +pub type PEMRMOVETOEX = *mut EMRLINETO; +STRUCT!{struct EMROFFSETCLIPRGN { + emr: EMR, + ptlOffset: POINTL, +}} +pub type PEMROFFSETCLIPRGN = *mut EMROFFSETCLIPRGN; +STRUCT!{struct EMRFILLPATH { + emr: EMR, + rclBounds: RECTL, +}} +pub type PEMRFILLPATH = *mut EMRFILLPATH; +pub type EMRSTROKEANDFILLPATH = EMRFILLPATH; +pub type PEMRSTROKEANDFILLPATH = *mut EMRFILLPATH; +pub type EMRSTROKEPATH = EMRFILLPATH; +pub type PEMRSTROKEPATH = *mut EMRFILLPATH; +STRUCT!{struct EMREXCLUDECLIPRECT { + emr: EMR, + rclClip: RECTL, +}} +pub type PEMREXCLUDECLIPRECT = *mut EMREXCLUDECLIPRECT; +pub type EMRINTERSECTCLIPRECT = EMREXCLUDECLIPRECT; +pub type PEMRINTERSECTCLIPRECT = *mut EMREXCLUDECLIPRECT; +STRUCT!{struct EMRSETVIEWPORTORGEX { + emr: EMR, + ptlOrigin: POINTL, +}} +pub type PEMRSETVIEWPORTORGEX = *mut EMRSETVIEWPORTORGEX; +pub type EMRSETWINDOWORGEX = EMRSETVIEWPORTORGEX; +pub type PEMRSETWINDOWORGEX = *mut EMRSETVIEWPORTORGEX; +pub type EMRSETBRUSHORGEX = EMRSETVIEWPORTORGEX; +pub type PEMRSETBRUSHORGEX = *mut EMRSETVIEWPORTORGEX; +STRUCT!{struct EMRSETVIEWPORTEXTEX { + emr: EMR, + szlExtent: SIZEL, +}} +pub type PEMRSETVIEWPORTEXTEX = *mut EMRSETVIEWPORTEXTEX; +pub type EMRSETWINDOWEXTEX = EMRSETVIEWPORTEXTEX; +pub type PEMRSETWINDOWEXTEX = *mut EMRSETVIEWPORTEXTEX; +STRUCT!{struct EMRSCALEVIEWPORTEXTEX { + emr: EMR, + xNum: LONG, + xDenom: LONG, + yNum: LONG, + yDenom: LONG, +}} +pub type PEMRSCALEVIEWPORTEXTEX = *mut EMRSCALEVIEWPORTEXTEX; +pub type EMRSCALEWINDOWEXTEX = EMRSCALEVIEWPORTEXTEX; +pub type PEMRSCALEWINDOWEXTEX = *mut EMRSCALEVIEWPORTEXTEX; +STRUCT!{struct EMRSETWORLDTRANSFORM { + emr: EMR, + xform: XFORM, +}} +pub type PEMRSETWORLDTRANSFORM = *mut EMRSETWORLDTRANSFORM; +STRUCT!{struct EMRMODIFYWORLDTRANSFORM { + emr: EMR, + xform: XFORM, + iMode: DWORD, +}} +pub type PEMRMODIFYWORLDTRANSFORM = *mut EMRMODIFYWORLDTRANSFORM; +STRUCT!{struct EMRSETPIXELV { + emr: EMR, + ptlPixel: POINTL, + crColor: COLORREF, +}} +pub type PEMRSETPIXELV = *mut EMRSETPIXELV; +STRUCT!{struct EMREXTFLOODFILL { + emr: EMR, + ptlStart: POINTL, + crColor: COLORREF, + iMode: DWORD, +}} +pub type PEMREXTFLOODFILL = *mut EMREXTFLOODFILL; +STRUCT!{struct EMRELLIPSE { + emr: EMR, + rclBox: RECTL, +}} +pub type PEMRELLIPSE = *mut EMRELLIPSE; +pub type EMRRECTANGLE = EMRELLIPSE; +pub type PEMRRECTANGLE = *mut EMRELLIPSE; +STRUCT!{struct EMRROUNDRECT { + emr: EMR, + rclBox: RECTL, + szlCorner: SIZEL, +}} +pub type PEMRROUNDRECT = *mut EMRROUNDRECT; +STRUCT!{struct EMRARC { + emr: EMR, + rclBox: RECTL, + ptlStart: POINTL, + ptlEnd: POINTL, +}} +pub type PEMRARC = *mut EMRARC; +pub type EMRARCTO = EMRARC; +pub type PEMRARCTO = *mut EMRARC; +pub type EMRCHORD = EMRARC; +pub type PEMRCHORD = *mut EMRARC; +pub type EMRPIE = EMRARC; +pub type PEMRPIE = *mut EMRARC; +STRUCT!{struct EMRANGLEARC { + emr: EMR, + ptlCenter: POINTL, + nRadius: DWORD, + eStartAngle: FLOAT, + eSweepAngle: FLOAT, +}} +pub type PEMRANGLEARC = *mut EMRANGLEARC; +STRUCT!{struct EMRPOLYLINE { + emr: EMR, + rclBounds: RECTL, + cptl: DWORD, + aptl: [POINTL; 1], +}} +pub type PEMRPOLYLINE = *mut EMRPOLYLINE; +pub type EMRPOLYBEZIER = EMRPOLYLINE; +pub type PEMRPOLYBEZIER = *mut EMRPOLYLINE; +pub type EMRPOLYGON = EMRPOLYLINE; +pub type PEMRPOLYGON = *mut EMRPOLYLINE; +pub type EMRPOLYBEZIERTO = EMRPOLYLINE; +pub type PEMRPOLYBEZIERTO = *mut EMRPOLYLINE; +pub type EMRPOLYLINETO = EMRPOLYLINE; +pub type PEMRPOLYLINETO = *mut EMRPOLYLINE; +STRUCT!{struct EMRPOLYLINE16 { + emr: EMR, + rclBounds: RECTL, + cpts: DWORD, + apts: [POINTS; 1], +}} +pub type PEMRPOLYLINE16 = *mut EMRPOLYLINE16; +pub type EMRPOLYBEZIER16 = EMRPOLYLINE16; +pub type PEMRPOLYBEZIER16 = *mut EMRPOLYLINE16; +pub type EMRPOLYGON16 = EMRPOLYLINE16; +pub type PEMRPOLYGON16 = *mut EMRPOLYLINE16; +pub type EMRPOLYBEZIERTO16 = EMRPOLYLINE16; +pub type PEMRPOLYBEZIERTO16 = *mut EMRPOLYLINE16; +pub type EMRPOLYLINETO16 = EMRPOLYLINE16; +pub type PEMRPOLYLINETO16 = *mut EMRPOLYLINE16; +STRUCT!{struct EMRPOLYDRAW { + emr: EMR, + rclBounds: RECTL, + cptl: DWORD, + aptl: [POINTL; 1], + abTypes: [BYTE; 1], +}} +pub type PEMRPOLYDRAW = *mut EMRPOLYDRAW; +STRUCT!{struct EMRPOLYDRAW16 { + emr: EMR, + rclBounds: RECTL, + cpts: DWORD, + apts: [POINTS; 1], + abTypes: [BYTE; 1], +}} +pub type PEMRPOLYDRAW16 = *mut EMRPOLYDRAW16; +STRUCT!{struct EMRPOLYPOLYLINE { + emr: EMR, + rclBounds: RECTL, + nPolys: DWORD, + cptl: DWORD, + aPolyCounts: [DWORD; 1], + aptl: [POINTL; 1], +}} +pub type PEMRPOLYPOLYLINE = *mut EMRPOLYPOLYLINE; +pub type EMRPOLYPOLYGON = EMRPOLYPOLYLINE; +pub type PEMRPOLYPOLYGON = *mut EMRPOLYPOLYLINE; +STRUCT!{struct EMRPOLYPOLYLINE16 { + emr: EMR, + rclBounds: RECTL, + nPolys: DWORD, + cpts: DWORD, + aPolyCounts: [DWORD; 1], + apts: [POINTS; 1], +}} +pub type PEMRPOLYPOLYLINE16 = *mut EMRPOLYPOLYLINE16; +pub type EMRPOLYPOLYGON16 = EMRPOLYPOLYLINE16; +pub type PEMRPOLYPOLYGON16 = *mut EMRPOLYPOLYLINE16; +STRUCT!{struct EMRINVERTRGN { + emr: EMR, + rclBounds: RECTL, + cbRgnData: DWORD, + RgnData: [BYTE; 1], +}} +pub type PEMRINVERTRGN = *mut EMRINVERTRGN; +pub type EMRPAINTRGN = EMRINVERTRGN; +pub type PEMRPAINTRGN = *mut EMRINVERTRGN; +STRUCT!{struct EMRFILLRGN { + emr: EMR, + rclBounds: RECTL, + cbRgnData: DWORD, + ihBrush: DWORD, + RgnData: [BYTE; 1], +}} +pub type PEMRFILLRGN = *mut EMRFILLRGN; +STRUCT!{struct EMRFRAMERGN { + emr: EMR, + rclBounds: RECTL, + cbRgnData: DWORD, + ihBrush: DWORD, + szlStroke: SIZEL, + RgnData: [BYTE; 1], +}} +pub type PEMRFRAMERGN = *mut EMRFRAMERGN; +STRUCT!{struct EMREXTSELECTCLIPRGN { + emr: EMR, + cbRgnData: DWORD, + iMode: DWORD, + RgnData: [BYTE; 1], +}} +pub type PEMREXTSELECTCLIPRGN = *mut EMREXTSELECTCLIPRGN; +STRUCT!{struct EMREXTTEXTOUTA { + emr: EMR, + rclBounds: RECTL, + iGraphicsMode: DWORD, + exScale: FLOAT, + eyScale: FLOAT, + emrtext: EMRTEXT, +}} +pub type PEMREXTTEXTOUTA = *mut EMREXTTEXTOUTA; +pub type EMREXTTEXTOUTW = EMREXTTEXTOUTA; +pub type PEMREXTTEXTOUTW = *mut EMREXTTEXTOUTA; +STRUCT!{struct EMRPOLYTEXTOUTA { + emr: EMR, + rclBounds: RECTL, + iGraphicsMode: DWORD, + exScale: FLOAT, + eyScale: FLOAT, + cStrings: LONG, + aemrtext: [EMRTEXT; 1], +}} +pub type PEMRPOLYTEXTOUTA = *mut EMRPOLYTEXTOUTA; +pub type EMRPOLYTEXTOUTW = EMRPOLYTEXTOUTA; +pub type PEMRPOLYTEXTOUTW = *mut EMRPOLYTEXTOUTA; +STRUCT!{struct EMRBITBLT { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + cxDest: LONG, + cyDest: LONG, + dwRop: DWORD, + xSrc: LONG, + ySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, +}} +pub type PEMRBITBLT = *mut EMRBITBLT; +STRUCT!{struct EMRSTRETCHBLT { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + cxDest: LONG, + cyDest: LONG, + dwRop: DWORD, + xSrc: LONG, + ySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + cxSrc: LONG, + cySrc: LONG, +}} +pub type PEMRSTRETCHBLT = *mut EMRSTRETCHBLT; +STRUCT!{struct EMRMASKBLT { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + cxDest: LONG, + cyDest: LONG, + dwRop: DWORD, + xSrc: LONG, + ySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + xMask: LONG, + yMask: LONG, + iUsageMask: DWORD, + offBmiMask: DWORD, + cbBmiMask: DWORD, + offBitsMask: DWORD, + cbBitsMask: DWORD, +}} +pub type PEMRMASKBLT = *mut EMRMASKBLT; +STRUCT!{struct EMRPLGBLT { + emr: EMR, + rclBounds: RECTL, + aptlDest: [POINTL; 3], + xSrc: LONG, + ySrc: LONG, + cxSrc: LONG, + cySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + xMask: LONG, + yMask: LONG, + iUsageMask: DWORD, + offBmiMask: DWORD, + cbBmiMask: DWORD, + offBitsMask: DWORD, + cbBitsMask: DWORD, +}} +pub type PEMRPLGBLT = *mut EMRPLGBLT; +STRUCT!{struct EMRSETDIBITSTODEVICE { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + xSrc: LONG, + ySrc: LONG, + cxSrc: LONG, + cySrc: LONG, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + iUsageSrc: DWORD, + iStartScan: DWORD, + cScans: DWORD, +}} +pub type PEMRSETDIBITSTODEVICE = *mut EMRSETDIBITSTODEVICE; +STRUCT!{struct EMRSTRETCHDIBITS { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + xSrc: LONG, + ySrc: LONG, + cxSrc: LONG, + cySrc: LONG, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + iUsageSrc: DWORD, + dwRop: DWORD, + cxDest: LONG, + cyDest: LONG, +}} +pub type PEMRSTRETCHDIBITS = *mut EMRSTRETCHDIBITS; +STRUCT!{struct EMREXTCREATEFONTINDIRECTW { + emr: EMR, + ihFont: DWORD, + elfw: EXTLOGFONTW, +}} +pub type PEMREXTCREATEFONTINDIRECTW = *mut EMREXTCREATEFONTINDIRECTW; +STRUCT!{struct EMRCREATEPALETTE { + emr: EMR, + ihPal: DWORD, + lgpl: LOGPALETTE, +}} +pub type PEMRCREATEPALETTE = *mut EMRCREATEPALETTE; +STRUCT!{struct EMRCREATEPEN { + emr: EMR, + ihPen: DWORD, + lopn: LOGPEN, +}} +pub type PEMRCREATEPEN = *mut EMRCREATEPEN; +STRUCT!{struct EMREXTCREATEPEN { + emr: EMR, + ihPen: DWORD, + offBmi: DWORD, + cbBmi: DWORD, + offBits: DWORD, + cbBits: DWORD, + elp: EXTLOGPEN32, +}} +pub type PEMREXTCREATEPEN = *mut EMREXTCREATEPEN; +STRUCT!{struct EMRCREATEBRUSHINDIRECT { + emr: EMR, + ihBrush: DWORD, + lb: LOGBRUSH32, +}} +pub type PEMRCREATEBRUSHINDIRECT = *mut EMRCREATEBRUSHINDIRECT; +STRUCT!{struct EMRCREATEMONOBRUSH { + emr: EMR, + ihBrush: DWORD, + iUsage: DWORD, + offBmi: DWORD, + cbBmi: DWORD, + offBits: DWORD, + cbBits: DWORD, +}} +pub type PEMRCREATEMONOBRUSH = *mut EMRCREATEMONOBRUSH; +STRUCT!{struct EMRCREATEDIBPATTERNBRUSHPT { + emr: EMR, + ihBrush: DWORD, + iUsage: DWORD, + offBmi: DWORD, + cbBmi: DWORD, + offBits: DWORD, + cbBits: DWORD, +}} +pub type PEMRCREATEDIBPATTERNBRUSHPT = *mut EMRCREATEDIBPATTERNBRUSHPT; +STRUCT!{struct EMRFORMAT { + dSignature: DWORD, + nVersion: DWORD, + cbData: DWORD, + offData: DWORD, +}} +pub type PEMRFORMAT = *mut EMRFORMAT; +STRUCT!{struct EMRGLSRECORD { + emr: EMR, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRGLSRECORD = *mut EMRGLSRECORD; +STRUCT!{struct EMRGLSBOUNDEDRECORD { + emr: EMR, + rclBounds: RECTL, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRGLSBOUNDEDRECORD = *mut EMRGLSBOUNDEDRECORD; +STRUCT!{struct EMRPIXELFORMAT { + emr: EMR, + pfd: PIXELFORMATDESCRIPTOR, +}} +pub type PEMRPIXELFORMAT = *mut EMRPIXELFORMAT; +STRUCT!{struct EMRCREATECOLORSPACE { + emr: EMR, + ihCS: DWORD, + lcs: LOGCOLORSPACEA, +}} +pub type PEMRCREATECOLORSPACE = *mut EMRCREATECOLORSPACE; +STRUCT!{struct EMRSETCOLORSPACE { + emr: EMR, + ihCS: DWORD, +}} +pub type PEMRSETCOLORSPACE = *mut EMRSETCOLORSPACE; +pub type EMRSELECTCOLORSPACE = EMRSETCOLORSPACE; +pub type PEMRSELECTCOLORSPACE = *mut EMRSETCOLORSPACE; +pub type EMRDELETECOLORSPACE = EMRSETCOLORSPACE; +pub type PEMRDELETECOLORSPACE = *mut EMRSETCOLORSPACE; +STRUCT!{struct EMREXTESCAPE { + emr: EMR, + iEscape: INT, + cbEscData: INT, + EscData: [BYTE; 1], +}} +pub type PEMREXTESCAPE = *mut EMREXTESCAPE; +pub type EMRDRAWESCAPE = EMREXTESCAPE; +pub type PEMRDRAWESCAPE = *mut EMREXTESCAPE; +STRUCT!{struct EMRNAMEDESCAPE { + emr: EMR, + iEscape: INT, + cbDriver: INT, + cbEscData: INT, + EscData: [BYTE; 1], +}} +pub type PEMRNAMEDESCAPE = *mut EMRNAMEDESCAPE; +pub const SETICMPROFILE_EMBEDED: DWORD = 0x00000001; +STRUCT!{struct EMRSETICMPROFILE { + emr: EMR, + dwFlags: DWORD, + cbName: DWORD, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRSETICMPROFILE = *mut EMRSETICMPROFILE; +pub type EMRSETICMPROFILEA = EMRSETICMPROFILE; +pub type PEMRSETICMPROFILEA = *mut EMRSETICMPROFILE; +pub type EMRSETICMPROFILEW = EMRSETICMPROFILE; +pub type PEMRSETICMPROFILEW = *mut EMRSETICMPROFILE; +pub const CREATECOLORSPACE_EMBEDED: DWORD = 0x00000001; +STRUCT!{struct EMRCREATECOLORSPACEW { + emr: EMR, + ihCS: DWORD, + lcs: LOGCOLORSPACEW, + dwFlags: DWORD, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRCREATECOLORSPACEW = *mut EMRCREATECOLORSPACEW; +pub const COLORMATCHTOTARGET_EMBEDED: DWORD = 0x00000001; +STRUCT!{struct EMRCOLORMATCHTOTARGET { + emr: EMR, + dwAction: DWORD, + dwFlags: DWORD, + cbName: DWORD, + cbData: DWORD, + Data: [BYTE; 1], +}} +pub type PEMRCOLORMATCHTOTARGET = *mut EMRCOLORMATCHTOTARGET; +STRUCT!{struct EMRCOLORCORRECTPALETTE { + emr: EMR, + ihPalette: DWORD, + nFirstEntry: DWORD, + nPalEntries: DWORD, + nReserved: DWORD, +}} +pub type PEMRCOLORCORRECTPALETTE = *mut EMRCOLORCORRECTPALETTE; +STRUCT!{struct EMRALPHABLEND { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + cxDest: LONG, + cyDest: LONG, + dwRop: DWORD, + xSrc: LONG, + ySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + cxSrc: LONG, + cySrc: LONG, +}} +pub type PEMRALPHABLEND = *mut EMRALPHABLEND; +STRUCT!{struct EMRGRADIENTFILL { + emr: EMR, + rclBounds: RECTL, + nVer: DWORD, + nTri: DWORD, + ulMode: ULONG, + Ver: [TRIVERTEX; 1], +}} +pub type PEMRGRADIENTFILL = *mut EMRGRADIENTFILL; +STRUCT!{struct EMRTRANSPARENTBLT { + emr: EMR, + rclBounds: RECTL, + xDest: LONG, + yDest: LONG, + cxDest: LONG, + cyDest: LONG, + dwRop: DWORD, + xSrc: LONG, + ySrc: LONG, + xformSrc: XFORM, + crBkColorSrc: COLORREF, + iUsageSrc: DWORD, + offBmiSrc: DWORD, + cbBmiSrc: DWORD, + offBitsSrc: DWORD, + cbBitsSrc: DWORD, + cxSrc: LONG, + cySrc: LONG, +}} +pub type PEMRTRANSPARENTBLT = *mut EMRTRANSPARENTBLT; +pub const GDICOMMENT_IDENTIFIER: DWORD = 0x43494447; +pub const GDICOMMENT_WINDOWS_METAFILE: DWORD = 0x80000001; +pub const GDICOMMENT_BEGINGROUP: DWORD = 0x00000002; +pub const GDICOMMENT_ENDGROUP: DWORD = 0x00000003; +pub const GDICOMMENT_MULTIFORMATS: DWORD = 0x40000004; +pub const EPS_SIGNATURE: DWORD = 0x46535045; +pub const GDICOMMENT_UNICODE_STRING: DWORD = 0x00000040; +pub const GDICOMMENT_UNICODE_END: DWORD = 0x00000080; +extern "system" { + pub fn wglCopyContext( + hglrcSrc: HGLRC, + hglrcDst: HGLRC, + mask: UINT, + ) -> BOOL; + pub fn wglCreateContext( + hdc: HDC, + ) -> HGLRC; + pub fn wglCreateLayerContext( + hdc: HDC, + iLayerPlane: c_int, + ) -> HGLRC; + pub fn wglDeleteContext( + hglrc: HGLRC, + ) -> BOOL; + pub fn wglGetCurrentContext() -> HGLRC; + pub fn wglGetCurrentDC() -> HDC; + pub fn wglGetProcAddress( + lpszProc: LPCSTR, + ) -> PROC; + pub fn wglMakeCurrent( + hdc: HDC, + hglrc: HGLRC, + ) -> BOOL; + pub fn wglShareLists( + hglrc1: HGLRC, + hglrc2: HGLRC, + ) -> BOOL; + pub fn wglUseFontBitmapsA( + hdc: HDC, + first: DWORD, + count: DWORD, + listBase: DWORD, + ) -> BOOL; + pub fn wglUseFontBitmapsW( + hdc: HDC, + first: DWORD, + count: DWORD, + listBase: DWORD, + ) -> BOOL; + pub fn SwapBuffers( + hdc: HDC, + ) -> BOOL; +} +STRUCT!{struct POINTFLOAT { + x: FLOAT, + y: FLOAT, +}} +pub type PPOINTFLOAT = *mut POINTFLOAT; +STRUCT!{struct GLYPHMETRICSFLOAT { + gmfBlackBoxX: FLOAT, + gmfBlackBoxY: FLOAT, + gmfptGlyphOrigin: POINTFLOAT, + gmfCellIncX: FLOAT, + gmfCellIncY: FLOAT, +}} +pub type PGLYPHMETRICSFLOAT = *mut GLYPHMETRICSFLOAT; +pub type LPGLYPHMETRICSFLOAT = *mut GLYPHMETRICSFLOAT; +pub const WGL_FONT_LINES: DWORD = 0; +pub const WGL_FONT_POLYGONS: DWORD = 1; +extern "system" { + pub fn wglUseFontOutlinesA( + hdc: HDC, + first: DWORD, + count: DWORD, + listBase: DWORD, + deviation: FLOAT, + extrusion: FLOAT, + format: c_int, + lpgmf: LPGLYPHMETRICSFLOAT, + ) -> BOOL; + pub fn wglUseFontOutlinesW( + hdc: HDC, + first: DWORD, + count: DWORD, + listBase: DWORD, + deviation: FLOAT, + extrusion: FLOAT, + format: c_int, + lpgmf: LPGLYPHMETRICSFLOAT, + ) -> BOOL; +} +STRUCT!{struct LAYERPLANEDESCRIPTOR { + nSize: WORD, + nVersion: WORD, + dwFlags: DWORD, + iPixelType: BYTE, + cColorBits: BYTE, + cRedBits: BYTE, + cRedShift: BYTE, + cGreenBits: BYTE, + cGreenShift: BYTE, + cBlueBits: BYTE, + cBlueShift: BYTE, + cAlphaBits: BYTE, + cAlphaShift: BYTE, + cAccumBits: BYTE, + cAccumRedBits: BYTE, + cAccumGreenBits: BYTE, + cAccumBlueBits: BYTE, + cAccumAlphaBits: BYTE, + cDepthBits: BYTE, + cStencilBits: BYTE, + cAuxBuffers: BYTE, + iLayerPlane: BYTE, + bReserved: BYTE, + crTransparent: COLORREF, +}} +pub type PLAYERPLANEDESCRIPTOR = *mut LAYERPLANEDESCRIPTOR; +pub type LPLAYERPLANEDESCRIPTOR = *mut LAYERPLANEDESCRIPTOR; +pub const LPD_DOUBLEBUFFER: DWORD = 0x00000001; +pub const LPD_STEREO: DWORD = 0x00000002; +pub const LPD_SUPPORT_GDI: DWORD = 0x00000010; +pub const LPD_SUPPORT_OPENGL: DWORD = 0x00000020; +pub const LPD_SHARE_DEPTH: DWORD = 0x00000040; +pub const LPD_SHARE_STENCIL: DWORD = 0x00000080; +pub const LPD_SHARE_ACCUM: DWORD = 0x00000100; +pub const LPD_SWAP_EXCHANGE: DWORD = 0x00000200; +pub const LPD_SWAP_COPY: DWORD = 0x00000400; +pub const LPD_TRANSPARENT: DWORD = 0x00001000; +pub const LPD_TYPE_RGBA: BYTE = 0; +pub const LPD_TYPE_COLORINDEX: BYTE = 1; +pub const WGL_SWAP_MAIN_PLANE: UINT = 0x00000001; +pub const WGL_SWAP_OVERLAY1: UINT = 0x00000002; +pub const WGL_SWAP_OVERLAY2: UINT = 0x00000004; +pub const WGL_SWAP_OVERLAY3: UINT = 0x00000008; +pub const WGL_SWAP_OVERLAY4: UINT = 0x00000010; +pub const WGL_SWAP_OVERLAY5: UINT = 0x00000020; +pub const WGL_SWAP_OVERLAY6: UINT = 0x00000040; +pub const WGL_SWAP_OVERLAY7: UINT = 0x00000080; +pub const WGL_SWAP_OVERLAY8: UINT = 0x00000100; +pub const WGL_SWAP_OVERLAY9: UINT = 0x00000200; +pub const WGL_SWAP_OVERLAY10: UINT = 0x00000400; +pub const WGL_SWAP_OVERLAY11: UINT = 0x00000800; +pub const WGL_SWAP_OVERLAY12: UINT = 0x00001000; +pub const WGL_SWAP_OVERLAY13: UINT = 0x00002000; +pub const WGL_SWAP_OVERLAY14: UINT = 0x00004000; +pub const WGL_SWAP_OVERLAY15: UINT = 0x00008000; +pub const WGL_SWAP_UNDERLAY1: UINT = 0x00010000; +pub const WGL_SWAP_UNDERLAY2: UINT = 0x00020000; +pub const WGL_SWAP_UNDERLAY3: UINT = 0x00040000; +pub const WGL_SWAP_UNDERLAY4: UINT = 0x00080000; +pub const WGL_SWAP_UNDERLAY5: UINT = 0x00100000; +pub const WGL_SWAP_UNDERLAY6: UINT = 0x00200000; +pub const WGL_SWAP_UNDERLAY7: UINT = 0x00400000; +pub const WGL_SWAP_UNDERLAY8: UINT = 0x00800000; +pub const WGL_SWAP_UNDERLAY9: UINT = 0x01000000; +pub const WGL_SWAP_UNDERLAY10: UINT = 0x02000000; +pub const WGL_SWAP_UNDERLAY11: UINT = 0x04000000; +pub const WGL_SWAP_UNDERLAY12: UINT = 0x08000000; +pub const WGL_SWAP_UNDERLAY13: UINT = 0x10000000; +pub const WGL_SWAP_UNDERLAY14: UINT = 0x20000000; +pub const WGL_SWAP_UNDERLAY15: UINT = 0x40000000; +extern "system" { + pub fn wglDescribeLayerPlane( + hdc: HDC, + iPixelFormat: c_int, + iLayerPlane: c_int, + nBytes: UINT, + plpd: LPLAYERPLANEDESCRIPTOR, + ) -> BOOL; + pub fn wglSetLayerPaletteEntries( + hdc: HDC, + iLayerPlane: c_int, + iStart: c_int, + cEntries: c_int, + pcr: *const COLORREF, + ) -> c_int; + pub fn wglGetLayerPaletteEntries( + hdc: HDC, + iLayerPlane: c_int, + iStart: c_int, + cEntries: c_int, + pcr: *const COLORREF, + ) -> c_int; + pub fn wglRealizeLayerPalette( + hdc: HDC, + iLayerPlane: c_int, + bRealize: BOOL, + ) -> BOOL; + pub fn wglSwapLayerBuffers( + hdc: HDC, + fuPlanes: UINT, + ) -> BOOL; +} +STRUCT!{struct WGLSWAP { + hdc: HDC, + uiFlags: UINT, +}} +pub type PWGLSWAP = *mut WGLSWAP; +pub type LPWGLSWAP = *mut WGLSWAP; +pub const WGL_SWAPMULTIPLE_MAX: usize = 16; +extern "system" { + pub fn wglSwapMultipleBuffers( + n: UINT, + ps: *const WGLSWAP, + ) -> DWORD; +} diff --git a/winapi/src/um/winhttp.rs b/winapi/src/um/winhttp.rs new file mode 100644 index 000000000..f39c78f51 --- /dev/null +++ b/winapi/src/um/winhttp.rs @@ -0,0 +1,658 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Windows HTTP Services API constant definitions and macros +use ctypes::c_int; +use shared::basetsd::DWORD_PTR; +use shared::minwindef::{BOOL, DWORD, LPCVOID, LPDWORD, LPVOID, USHORT, WORD}; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{LPCWSTR, LPWSTR, PCWSTR, PVOID, PWSTR}; +pub type HINTERNET = LPVOID; +pub type LPHINTERNET = *mut HINTERNET; +pub type INTERNET_PORT = WORD; +pub type LPINTERNET_PORT = *mut INTERNET_PORT; +pub const INTERNET_DEFAULT_PORT: INTERNET_PORT = 0; +pub const INTERNET_DEFAULT_HTTP_PORT: INTERNET_PORT = 80; +pub const INTERNET_DEFAULT_HTTPS_PORT: INTERNET_PORT = 443; +pub const WINHTTP_FLAG_ASYNC: DWORD = 0x10000000; +pub const WINHTTP_FLAG_SECURE: DWORD = 0x00800000; +pub const WINHTTP_FLAG_ESCAPE_PERCENT: DWORD = 0x00000004; +pub const WINHTTP_FLAG_NULL_CODEPAGE: DWORD = 0x00000008; +pub const WINHTTP_FLAG_BYPASS_PROXY_CACHE: DWORD = 0x00000100; +pub const WINHTTP_FLAG_REFRESH: DWORD = WINHTTP_FLAG_BYPASS_PROXY_CACHE; +pub const WINHTTP_FLAG_ESCAPE_DISABLE: DWORD = 0x00000040; +pub const WINHTTP_FLAG_ESCAPE_DISABLE_QUERY: DWORD = 0x00000080; +STRUCT!{struct WINHTTP_ASYNC_RESULT { + dwResult: DWORD_PTR, + dwError: DWORD, +}} +pub type LPWINHTTP_ASYNC_RESULT = *mut WINHTTP_ASYNC_RESULT; +pub type INTERNET_SCHEME = c_int; +pub type LPINTERNET_SCHEME = *mut c_int; +pub const INTERNET_SCHEME_HTTP: INTERNET_SCHEME = 1; +pub const INTERNET_SCHEME_HTTPS: INTERNET_SCHEME = 2; +pub const INTERNET_SCHEME_FTP: INTERNET_SCHEME = 3; +pub const INTERNET_SCHEME_SOCKS: INTERNET_SCHEME = 4; +STRUCT!{struct URL_COMPONENTS { + dwStructSize: DWORD, + lpszScheme: LPWSTR, + dwSchemeLength: DWORD, + nScheme: INTERNET_SCHEME, + lpszHostName: LPWSTR, + dwHostNameLength: DWORD, + nPort: INTERNET_PORT, + lpszUserName: LPWSTR, + dwUserNameLength: DWORD, + lpszPassword: LPWSTR, + dwPasswordLength: DWORD, + lpszUrlPath: LPWSTR, + dwUrlPathLength: DWORD, + lpszExtraInfo: LPWSTR, + dwExtraInfoLength: DWORD, +}} +pub type LPURL_COMPONENTS = *mut URL_COMPONENTS; +pub type URL_COMPONENTSW = URL_COMPONENTS; +pub type LPURL_COMPONENTSW = LPURL_COMPONENTS; +STRUCT!{struct WINHTTP_PROXY_INFO { + dwAccessType: DWORD, + lpszProxy: LPWSTR, + lpszProxyBypass: LPWSTR, +}} +pub type LPWINHTTP_PROXY_INFO = *mut WINHTTP_PROXY_INFO; +pub type WINHTTP_PROXY_INFOW = WINHTTP_PROXY_INFO; +pub type LPWINHTTP_PROXY_INFOW = LPWINHTTP_PROXY_INFO; +STRUCT!{struct WINHTTP_AUTOPROXY_OPTIONS { + dwFlags: DWORD, + dwAutoDetectFlags: DWORD, + lpszAutoConfigUrl: LPCWSTR, + lpvReserved: LPVOID, + dwReserved: DWORD, + fAutoLogonIfChallenged: BOOL, +}} +pub const WINHTTP_AUTOPROXY_AUTO_DETECT: DWORD = 0x00000001; +pub const WINHTTP_AUTOPROXY_CONFIG_URL: DWORD = 0x00000002; +pub const WINHTTP_AUTOPROXY_HOST_KEEPCASE: DWORD = 0x00000004; +pub const WINHTTP_AUTOPROXY_HOST_LOWERCASE: DWORD = 0x00000008; +pub const WINHTTP_AUTOPROXY_RUN_INPROCESS: DWORD = 0x00010000; +pub const WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY: DWORD = 0x00020000; +pub const WINHTTP_AUTOPROXY_NO_DIRECTACCESS: DWORD = 0x00040000; +pub const WINHTTP_AUTOPROXY_NO_CACHE_CLIENT: DWORD = 0x00080000; +pub const WINHTTP_AUTOPROXY_NO_CACHE_SVC: DWORD = 0x00100000; +pub const WINHTTP_AUTOPROXY_SORT_RESULTS: DWORD = 0x00400000; +pub const WINHTTP_AUTO_DETECT_TYPE_DHCP: DWORD = 0x00000001; +pub const WINHTTP_AUTO_DETECT_TYPE_DNS_A: DWORD = 0x00000002; +STRUCT!{struct WINHTTP_PROXY_RESULT_ENTRY { + fProxy: BOOL, + fBypass: BOOL, + ProxyScheme: INTERNET_SCHEME, + pwszProxy: PWSTR, + ProxyPort: INTERNET_PORT, +}} +STRUCT!{struct WINHTTP_PROXY_RESULT { + cEntries: DWORD, + pEntries: *mut WINHTTP_PROXY_RESULT_ENTRY, +}} +pub const WINHTTP_FIRST_OPTION: DWORD = WINHTTP_OPTION_CALLBACK; +pub const WINHTTP_OPTION_CALLBACK: DWORD = 1; +pub const WINHTTP_OPTION_RESOLVE_TIMEOUT: DWORD = 2; +pub const WINHTTP_OPTION_CONNECT_TIMEOUT: DWORD = 3; +pub const WINHTTP_OPTION_CONNECT_RETRIES: DWORD = 4; +pub const WINHTTP_OPTION_SEND_TIMEOUT: DWORD = 5; +pub const WINHTTP_OPTION_RECEIVE_TIMEOUT: DWORD = 6; +pub const WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT: DWORD = 7; +pub const WINHTTP_OPTION_HANDLE_TYPE: DWORD = 9; +pub const WINHTTP_OPTION_READ_BUFFER_SIZE: DWORD = 12; +pub const WINHTTP_OPTION_WRITE_BUFFER_SIZE: DWORD = 13; +pub const WINHTTP_OPTION_PARENT_HANDLE: DWORD = 21; +pub const WINHTTP_OPTION_EXTENDED_ERROR: DWORD = 24; +pub const WINHTTP_OPTION_SECURITY_FLAGS: DWORD = 31; +pub const WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT: DWORD = 32; +pub const WINHTTP_OPTION_URL: DWORD = 34; +pub const WINHTTP_OPTION_SECURITY_KEY_BITNESS: DWORD = 36; +pub const WINHTTP_OPTION_PROXY: DWORD = 38; +pub const WINHTTP_OPTION_PROXY_RESULT_ENTRY: DWORD = 39; +pub const WINHTTP_OPTION_USER_AGENT: DWORD = 41; +pub const WINHTTP_OPTION_CONTEXT_VALUE: DWORD = 45; +pub const WINHTTP_OPTION_CLIENT_CERT_CONTEXT: DWORD = 47; +pub const WINHTTP_OPTION_REQUEST_PRIORITY: DWORD = 58; +pub const WINHTTP_OPTION_HTTP_VERSION: DWORD = 59; +pub const WINHTTP_OPTION_DISABLE_FEATURE: DWORD = 63; +pub const WINHTTP_OPTION_CODEPAGE: DWORD = 68; +pub const WINHTTP_OPTION_MAX_CONNS_PER_SERVER: DWORD = 73; +pub const WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: DWORD = 74; +pub const WINHTTP_OPTION_AUTOLOGON_POLICY: DWORD = 77; +pub const WINHTTP_OPTION_SERVER_CERT_CONTEXT: DWORD = 78; +pub const WINHTTP_OPTION_ENABLE_FEATURE: DWORD = 79; +pub const WINHTTP_OPTION_WORKER_THREAD_COUNT: DWORD = 80; +pub const WINHTTP_OPTION_PASSPORT_COBRANDING_TEXT: DWORD = 81; +pub const WINHTTP_OPTION_PASSPORT_COBRANDING_URL: DWORD = 82; +pub const WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH: DWORD = 83; +pub const WINHTTP_OPTION_SECURE_PROTOCOLS: DWORD = 84; +pub const WINHTTP_OPTION_ENABLETRACING: DWORD = 85; +pub const WINHTTP_OPTION_PASSPORT_SIGN_OUT: DWORD = 86; +pub const WINHTTP_OPTION_PASSPORT_RETURN_URL: DWORD = 87; +pub const WINHTTP_OPTION_REDIRECT_POLICY: DWORD = 88; +pub const WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS: DWORD = 89; +pub const WINHTTP_OPTION_MAX_HTTP_STATUS_CONTINUE: DWORD = 90; +pub const WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE: DWORD = 91; +pub const WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE: DWORD = 92; +pub const WINHTTP_OPTION_CONNECTION_INFO: DWORD = 93; +pub const WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST: DWORD = 94; +pub const WINHTTP_OPTION_SPN: DWORD = 96; +pub const WINHTTP_OPTION_GLOBAL_PROXY_CREDS: DWORD = 97; +pub const WINHTTP_OPTION_GLOBAL_SERVER_CREDS: DWORD = 98; +pub const WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: DWORD = 99; +pub const WINHTTP_OPTION_REJECT_USERPWD_IN_URL: DWORD = 100; +pub const WINHTTP_OPTION_USE_GLOBAL_SERVER_CREDENTIALS: DWORD = 101; +pub const WINHTTP_OPTION_RECEIVE_PROXY_CONNECT_RESPONSE: DWORD = 103; +pub const WINHTTP_OPTION_IS_PROXY_CONNECT_RESPONSE: DWORD = 104; +pub const WINHTTP_OPTION_SERVER_SPN_USED: DWORD = 106; +pub const WINHTTP_OPTION_PROXY_SPN_USED: DWORD = 107; +pub const WINHTTP_OPTION_SERVER_CBT: DWORD = 108; +pub const WINHTTP_OPTION_UNSAFE_HEADER_PARSING: DWORD = 110; +pub const WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS: DWORD = 111; +pub const WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET: DWORD = 114; +pub const WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT: DWORD = 115; +pub const WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL: DWORD = 116; +pub const WINHTTP_OPTION_DECOMPRESSION: DWORD = 118; +pub const WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE: DWORD = 122; +pub const WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE: DWORD = 123; +pub const WINHTTP_LAST_OPTION: DWORD = WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE; +pub const WINHTTP_OPTION_USERNAME: DWORD = 0x1000; +pub const WINHTTP_OPTION_PASSWORD: DWORD = 0x1001; +pub const WINHTTP_OPTION_PROXY_USERNAME: DWORD = 0x1002; +pub const WINHTTP_OPTION_PROXY_PASSWORD: DWORD = 0x1003; +//569 +FN!{stdcall WINHTTP_STATUS_CALLBACK( + hInternet: HINTERNET, + dwContext: DWORD_PTR, + dwInternetStatus: DWORD, + lpvStatusInformation: LPVOID, + dwStatusInformationLength: DWORD, +) -> ()} +pub type LPWINHTTP_STATUS_CALLBACK = *mut WINHTTP_STATUS_CALLBACK; +pub const WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: DWORD = 0x00000001; +pub const WINHTTP_CALLBACK_STATUS_NAME_RESOLVED: DWORD = 0x00000002; +pub const WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER: DWORD = 0x00000004; +pub const WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: DWORD = 0x00000008; +pub const WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: DWORD = 0x00000010; +pub const WINHTTP_CALLBACK_STATUS_REQUEST_SENT: DWORD = 0x00000020; +pub const WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: DWORD = 0x00000040; +pub const WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: DWORD = 0x00000080; +pub const WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION: DWORD = 0x00000100; +pub const WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: DWORD = 0x00000200; +pub const WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: DWORD = 0x00000400; +pub const WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: DWORD = 0x00000800; +pub const WINHTTP_CALLBACK_STATUS_DETECTING_PROXY: DWORD = 0x00001000; +pub const WINHTTP_CALLBACK_STATUS_REDIRECT: DWORD = 0x00004000; +pub const WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE: DWORD = 0x00008000; +pub const WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: DWORD = 0x00010000; +pub const WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: DWORD = 0x00020000; +pub const WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: DWORD = 0x00040000; +pub const WINHTTP_CALLBACK_STATUS_READ_COMPLETE: DWORD = 0x00080000; +pub const WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: DWORD = 0x00100000; +pub const WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: DWORD = 0x00200000; +pub const WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: DWORD = 0x00400000; +pub const WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE: DWORD = 0x01000000; +pub const WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE: DWORD = 0x02000000; +pub const WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE: DWORD = 0x04000000; +pub const WINHTTP_CALLBACK_FLAG_RESOLVE_NAME: DWORD = WINHTTP_CALLBACK_STATUS_RESOLVING_NAME + | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED; +pub const WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER: DWORD = + WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER; +pub const WINHTTP_CALLBACK_FLAG_SEND_REQUEST: DWORD = + WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT; +pub const WINHTTP_CALLBACK_FLAG_RECEIVE_RESPONSE: DWORD = + WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE | WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED; +pub const WINHTTP_CALLBACK_FLAG_CLOSE_CONNECTION: DWORD = + WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION | WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED; +pub const WINHTTP_CALLBACK_FLAG_HANDLES: DWORD = + WINHTTP_CALLBACK_STATUS_HANDLE_CREATED | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING; +pub const WINHTTP_CALLBACK_FLAG_DETECTING_PROXY: DWORD = WINHTTP_CALLBACK_STATUS_DETECTING_PROXY; +pub const WINHTTP_CALLBACK_FLAG_REDIRECT: DWORD = WINHTTP_CALLBACK_STATUS_REDIRECT; +pub const WINHTTP_CALLBACK_FLAG_INTERMEDIATE_RESPONSE: DWORD = + WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE; +pub const WINHTTP_CALLBACK_FLAG_SECURE_FAILURE: DWORD = WINHTTP_CALLBACK_STATUS_SECURE_FAILURE; +pub const WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE: DWORD = + WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE; +pub const WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE: DWORD = + WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE; +pub const WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE: DWORD = WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE; +pub const WINHTTP_CALLBACK_FLAG_READ_COMPLETE: DWORD = WINHTTP_CALLBACK_STATUS_READ_COMPLETE; +pub const WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE: DWORD = WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE; +pub const WINHTTP_CALLBACK_FLAG_REQUEST_ERROR: DWORD = WINHTTP_CALLBACK_STATUS_REQUEST_ERROR; +pub const WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE: DWORD = + WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE; +pub const WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS: DWORD = + WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE + | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE + | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR + | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE; +pub const WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS: DWORD = 0xffffffff; +pub const WINHTTP_QUERY_MIME_VERSION: DWORD = 0; +pub const WINHTTP_QUERY_CONTENT_TYPE: DWORD = 1; +pub const WINHTTP_QUERY_CONTENT_TRANSFER_ENCODING: DWORD = 2; +pub const WINHTTP_QUERY_CONTENT_ID: DWORD = 3; +pub const WINHTTP_QUERY_CONTENT_DESCRIPTION: DWORD = 4; +pub const WINHTTP_QUERY_CONTENT_LENGTH: DWORD = 5; +pub const WINHTTP_QUERY_CONTENT_LANGUAGE: DWORD = 6; +pub const WINHTTP_QUERY_ALLOW: DWORD = 7; +pub const WINHTTP_QUERY_PUBLIC: DWORD = 8; +pub const WINHTTP_QUERY_DATE: DWORD = 9; +pub const WINHTTP_QUERY_EXPIRES: DWORD = 10; +pub const WINHTTP_QUERY_LAST_MODIFIED: DWORD = 11; +pub const WINHTTP_QUERY_MESSAGE_ID: DWORD = 12; +pub const WINHTTP_QUERY_URI: DWORD = 13; +pub const WINHTTP_QUERY_DERIVED_FROM: DWORD = 14; +pub const WINHTTP_QUERY_COST: DWORD = 15; +pub const WINHTTP_QUERY_LINK: DWORD = 16; +pub const WINHTTP_QUERY_PRAGMA: DWORD = 17; +pub const WINHTTP_QUERY_VERSION: DWORD = 18; +pub const WINHTTP_QUERY_STATUS_CODE: DWORD = 19; +pub const WINHTTP_QUERY_STATUS_TEXT: DWORD = 20; +pub const WINHTTP_QUERY_RAW_HEADERS: DWORD = 21; +pub const WINHTTP_QUERY_RAW_HEADERS_CRLF: DWORD = 22; +pub const WINHTTP_QUERY_CONNECTION: DWORD = 23; +pub const WINHTTP_QUERY_ACCEPT: DWORD = 24; +pub const WINHTTP_QUERY_ACCEPT_CHARSET: DWORD = 25; +pub const WINHTTP_QUERY_ACCEPT_ENCODING: DWORD = 26; +pub const WINHTTP_QUERY_ACCEPT_LANGUAGE: DWORD = 27; +pub const WINHTTP_QUERY_AUTHORIZATION: DWORD = 28; +pub const WINHTTP_QUERY_CONTENT_ENCODING: DWORD = 29; +pub const WINHTTP_QUERY_FORWARDED: DWORD = 30; +pub const WINHTTP_QUERY_FROM: DWORD = 31; +pub const WINHTTP_QUERY_IF_MODIFIED_SINCE: DWORD = 32; +pub const WINHTTP_QUERY_LOCATION: DWORD = 33; +pub const WINHTTP_QUERY_ORIG_URI: DWORD = 34; +pub const WINHTTP_QUERY_REFERER: DWORD = 35; +pub const WINHTTP_QUERY_RETRY_AFTER: DWORD = 36; +pub const WINHTTP_QUERY_SERVER: DWORD = 37; +pub const WINHTTP_QUERY_TITLE: DWORD = 38; +pub const WINHTTP_QUERY_USER_AGENT: DWORD = 39; +pub const WINHTTP_QUERY_WWW_AUTHENTICATE: DWORD = 40; +pub const WINHTTP_QUERY_PROXY_AUTHENTICATE: DWORD = 41; +pub const WINHTTP_QUERY_ACCEPT_RANGES: DWORD = 42; +pub const WINHTTP_QUERY_SET_COOKIE: DWORD = 43; +pub const WINHTTP_QUERY_COOKIE: DWORD = 44; +pub const WINHTTP_QUERY_REQUEST_METHOD: DWORD = 45; +pub const WINHTTP_QUERY_REFRESH: DWORD = 46; +pub const WINHTTP_QUERY_CONTENT_DISPOSITION: DWORD = 47; +pub const WINHTTP_QUERY_AGE: DWORD = 48; +pub const WINHTTP_QUERY_CACHE_CONTROL: DWORD = 49; +pub const WINHTTP_QUERY_CONTENT_BASE: DWORD = 50; +pub const WINHTTP_QUERY_CONTENT_LOCATION: DWORD = 51; +pub const WINHTTP_QUERY_CONTENT_MD5: DWORD = 52; +pub const WINHTTP_QUERY_CONTENT_RANGE: DWORD = 53; +pub const WINHTTP_QUERY_ETAG: DWORD = 54; +pub const WINHTTP_QUERY_HOST: DWORD = 55; +pub const WINHTTP_QUERY_IF_MATCH: DWORD = 56; +pub const WINHTTP_QUERY_IF_NONE_MATCH: DWORD = 57; +pub const WINHTTP_QUERY_IF_RANGE: DWORD = 58; +pub const WINHTTP_QUERY_IF_UNMODIFIED_SINCE: DWORD = 59; +pub const WINHTTP_QUERY_MAX_FORWARDS: DWORD = 60; +pub const WINHTTP_QUERY_PROXY_AUTHORIZATION: DWORD = 61; +pub const WINHTTP_QUERY_RANGE: DWORD = 62; +pub const WINHTTP_QUERY_TRANSFER_ENCODING: DWORD = 63; +pub const WINHTTP_QUERY_UPGRADE: DWORD = 64; +pub const WINHTTP_QUERY_VARY: DWORD = 65; +pub const WINHTTP_QUERY_VIA: DWORD = 66; +pub const WINHTTP_QUERY_WARNING: DWORD = 67; +pub const WINHTTP_QUERY_EXPECT: DWORD = 68; +pub const WINHTTP_QUERY_PROXY_CONNECTION: DWORD = 69; +pub const WINHTTP_QUERY_UNLESS_MODIFIED_SINCE: DWORD = 70; +pub const WINHTTP_QUERY_PROXY_SUPPORT: DWORD = 75; +pub const WINHTTP_QUERY_AUTHENTICATION_INFO: DWORD = 76; +pub const WINHTTP_QUERY_PASSPORT_URLS: DWORD = 77; +pub const WINHTTP_QUERY_PASSPORT_CONFIG: DWORD = 78; +pub const WINHTTP_QUERY_MAX: DWORD = 78; +pub const WINHTTP_QUERY_CUSTOM: DWORD = 65535; +pub const WINHTTP_QUERY_FLAG_REQUEST_HEADERS: DWORD = 0x80000000; +pub const WINHTTP_QUERY_FLAG_SYSTEMTIME: DWORD = 0x40000000; +pub const WINHTTP_QUERY_FLAG_NUMBER: DWORD = 0x20000000; +pub const HTTP_STATUS_CONTINUE: DWORD = 100; +pub const HTTP_STATUS_SWITCH_PROTOCOLS: DWORD = 101; +pub const HTTP_STATUS_OK: DWORD = 200; +pub const HTTP_STATUS_CREATED: DWORD = 201; +pub const HTTP_STATUS_ACCEPTED: DWORD = 202; +pub const HTTP_STATUS_PARTIAL: DWORD = 203; +pub const HTTP_STATUS_NO_CONTENT: DWORD = 204; +pub const HTTP_STATUS_RESET_CONTENT: DWORD = 205; +pub const HTTP_STATUS_PARTIAL_CONTENT: DWORD = 206; +pub const HTTP_STATUS_WEBDAV_MULTI_STATUS: DWORD = 207; +pub const HTTP_STATUS_AMBIGUOUS: DWORD = 300; +pub const HTTP_STATUS_MOVED: DWORD = 301; +pub const HTTP_STATUS_REDIRECT: DWORD = 302; +pub const HTTP_STATUS_REDIRECT_METHOD: DWORD = 303; +pub const HTTP_STATUS_NOT_MODIFIED: DWORD = 304; +pub const HTTP_STATUS_USE_PROXY: DWORD = 305; +pub const HTTP_STATUS_REDIRECT_KEEP_VERB: DWORD = 307; +pub const HTTP_STATUS_BAD_REQUEST: DWORD = 400; +pub const HTTP_STATUS_DENIED: DWORD = 401; +pub const HTTP_STATUS_PAYMENT_REQ: DWORD = 402; +pub const HTTP_STATUS_FORBIDDEN: DWORD = 403; +pub const HTTP_STATUS_NOT_FOUND: DWORD = 404; +pub const HTTP_STATUS_BAD_METHOD: DWORD = 405; +pub const HTTP_STATUS_NONE_ACCEPTABLE: DWORD = 406; +pub const HTTP_STATUS_PROXY_AUTH_REQ: DWORD = 407; +pub const HTTP_STATUS_REQUEST_TIMEOUT: DWORD = 408; +pub const HTTP_STATUS_CONFLICT: DWORD = 409; +pub const HTTP_STATUS_GONE: DWORD = 410; +pub const HTTP_STATUS_LENGTH_REQUIRED: DWORD = 411; +pub const HTTP_STATUS_PRECOND_FAILED: DWORD = 412; +pub const HTTP_STATUS_REQUEST_TOO_LARGE: DWORD = 413; +pub const HTTP_STATUS_URI_TOO_LONG: DWORD = 414; +pub const HTTP_STATUS_UNSUPPORTED_MEDIA: DWORD = 415; +pub const HTTP_STATUS_RETRY_WITH: DWORD = 449; +pub const HTTP_STATUS_SERVER_ERROR: DWORD = 500; +pub const HTTP_STATUS_NOT_SUPPORTED: DWORD = 501; +pub const HTTP_STATUS_BAD_GATEWAY: DWORD = 502; +pub const HTTP_STATUS_SERVICE_UNAVAIL: DWORD = 503; +pub const HTTP_STATUS_GATEWAY_TIMEOUT: DWORD = 504; +pub const HTTP_STATUS_VERSION_NOT_SUP: DWORD = 505; +pub const HTTP_STATUS_FIRST: DWORD = HTTP_STATUS_CONTINUE; +pub const HTTP_STATUS_LAST: DWORD = HTTP_STATUS_VERSION_NOT_SUP; +pub const WINHTTP_ACCESS_TYPE_DEFAULT_PROXY: DWORD = 0; +pub const WINHTTP_ACCESS_TYPE_NO_PROXY: DWORD = 1; +pub const WINHTTP_ACCESS_TYPE_NAMED_PROXY: DWORD = 3; +pub const WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY: DWORD = 4; +STRUCT!{struct WINHTTP_CURRENT_USER_IE_PROXY_CONFIG { + fAutoDetect: BOOL, + lpszAutoConfigUrl: LPWSTR, + lpszProxy: LPWSTR, + lpszProxyBypass: LPWSTR, +}} +pub const WINHTTP_ERROR_BASE: DWORD = 12000; +pub const ERROR_WINHTTP_OUT_OF_HANDLES: DWORD = WINHTTP_ERROR_BASE + 1; +pub const ERROR_WINHTTP_TIMEOUT: DWORD = WINHTTP_ERROR_BASE + 2; +pub const ERROR_WINHTTP_INTERNAL_ERROR: DWORD = WINHTTP_ERROR_BASE + 4; +pub const ERROR_WINHTTP_INVALID_URL: DWORD = WINHTTP_ERROR_BASE + 5; +pub const ERROR_WINHTTP_UNRECOGNIZED_SCHEME: DWORD = WINHTTP_ERROR_BASE + 6; +pub const ERROR_WINHTTP_NAME_NOT_RESOLVED: DWORD = WINHTTP_ERROR_BASE + 7; +pub const ERROR_WINHTTP_INVALID_OPTION: DWORD = WINHTTP_ERROR_BASE + 9; +pub const ERROR_WINHTTP_OPTION_NOT_SETTABLE: DWORD = WINHTTP_ERROR_BASE + 11; +pub const ERROR_WINHTTP_SHUTDOWN: DWORD = WINHTTP_ERROR_BASE + 12; +pub const ERROR_WINHTTP_LOGIN_FAILURE: DWORD = WINHTTP_ERROR_BASE + 15; +pub const ERROR_WINHTTP_OPERATION_CANCELLED: DWORD = WINHTTP_ERROR_BASE + 17; +pub const ERROR_WINHTTP_INCORRECT_HANDLE_TYPE: DWORD = WINHTTP_ERROR_BASE + 18; +pub const ERROR_WINHTTP_INCORRECT_HANDLE_STATE: DWORD = WINHTTP_ERROR_BASE + 19; +pub const ERROR_WINHTTP_CANNOT_CONNECT: DWORD = WINHTTP_ERROR_BASE + 29; +pub const ERROR_WINHTTP_CONNECTION_ERROR: DWORD = WINHTTP_ERROR_BASE + 30; +pub const ERROR_WINHTTP_RESEND_REQUEST: DWORD = WINHTTP_ERROR_BASE + 32; +pub const ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED: DWORD = WINHTTP_ERROR_BASE + 44; +pub const ERROR_WINHTTP_CANNOT_CALL_BEFORE_OPEN: DWORD = WINHTTP_ERROR_BASE + 100; +pub const ERROR_WINHTTP_CANNOT_CALL_BEFORE_SEND: DWORD = WINHTTP_ERROR_BASE + 101; +pub const ERROR_WINHTTP_CANNOT_CALL_AFTER_SEND: DWORD = WINHTTP_ERROR_BASE + 102; +pub const ERROR_WINHTTP_CANNOT_CALL_AFTER_OPEN: DWORD = WINHTTP_ERROR_BASE + 103; +pub const ERROR_WINHTTP_HEADER_NOT_FOUND: DWORD = WINHTTP_ERROR_BASE + 150; +pub const ERROR_WINHTTP_INVALID_SERVER_RESPONSE: DWORD = WINHTTP_ERROR_BASE + 152; +pub const ERROR_WINHTTP_INVALID_HEADER: DWORD = WINHTTP_ERROR_BASE + 153; +pub const ERROR_WINHTTP_INVALID_QUERY_REQUEST: DWORD = WINHTTP_ERROR_BASE + 154; +pub const ERROR_WINHTTP_HEADER_ALREADY_EXISTS: DWORD = WINHTTP_ERROR_BASE + 155; +pub const ERROR_WINHTTP_REDIRECT_FAILED: DWORD = WINHTTP_ERROR_BASE + 156; +pub const ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR: DWORD = WINHTTP_ERROR_BASE + 178; +pub const ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT: DWORD = WINHTTP_ERROR_BASE + 166; +pub const ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT: DWORD = WINHTTP_ERROR_BASE + 167; +pub const ERROR_WINHTTP_UNHANDLED_SCRIPT_TYPE: DWORD = WINHTTP_ERROR_BASE + 176; +pub const ERROR_WINHTTP_SCRIPT_EXECUTION_ERROR: DWORD = WINHTTP_ERROR_BASE + 177; +pub const ERROR_WINHTTP_NOT_INITIALIZED: DWORD = WINHTTP_ERROR_BASE + 172; +pub const ERROR_WINHTTP_SECURE_FAILURE: DWORD = WINHTTP_ERROR_BASE + 175; +pub const ERROR_WINHTTP_SECURE_CERT_DATE_INVALID: DWORD = WINHTTP_ERROR_BASE + 37; +pub const ERROR_WINHTTP_SECURE_CERT_CN_INVALID: DWORD = WINHTTP_ERROR_BASE + 38; +pub const ERROR_WINHTTP_SECURE_INVALID_CA: DWORD = WINHTTP_ERROR_BASE + 45; +pub const ERROR_WINHTTP_SECURE_CERT_REV_FAILED: DWORD = WINHTTP_ERROR_BASE + 57; +pub const ERROR_WINHTTP_SECURE_CHANNEL_ERROR: DWORD = WINHTTP_ERROR_BASE + 157; +pub const ERROR_WINHTTP_SECURE_INVALID_CERT: DWORD = WINHTTP_ERROR_BASE + 169; +pub const ERROR_WINHTTP_SECURE_CERT_REVOKED: DWORD = WINHTTP_ERROR_BASE + 170; +pub const ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE: DWORD = WINHTTP_ERROR_BASE + 179; +pub const ERROR_WINHTTP_AUTODETECTION_FAILED: DWORD = WINHTTP_ERROR_BASE + 180; +pub const ERROR_WINHTTP_HEADER_COUNT_EXCEEDED: DWORD = WINHTTP_ERROR_BASE + 181; +pub const ERROR_WINHTTP_HEADER_SIZE_OVERFLOW: DWORD = WINHTTP_ERROR_BASE + 182; +pub const ERROR_WINHTTP_CHUNKED_ENCODING_HEADER_SIZE_OVERFLOW: DWORD = WINHTTP_ERROR_BASE + 183; +pub const ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW: DWORD = WINHTTP_ERROR_BASE + 184; +pub const ERROR_WINHTTP_CLIENT_CERT_NO_PRIVATE_KEY: DWORD = WINHTTP_ERROR_BASE + 185; +pub const ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY: DWORD = WINHTTP_ERROR_BASE + 186; +pub const WINHTTP_ERROR_LAST: DWORD = WINHTTP_ERROR_BASE + 186; +pub const WINHTTP_RESET_STATE: DWORD = 0x00000001; +pub const WINHTTP_RESET_SWPAD_CURRENT_NETWORK: DWORD = 0x00000002; +pub const WINHTTP_RESET_SWPAD_ALL: DWORD = 0x00000004; +pub const WINHTTP_RESET_SCRIPT_CACHE: DWORD = 0x00000008; +pub const WINHTTP_RESET_ALL: DWORD = 0x0000FFFF; +pub const WINHTTP_RESET_NOTIFY_NETWORK_CHANGED: DWORD = 0x00010000; +pub const WINHTTP_RESET_OUT_OF_PROC: DWORD = 0x00020000; +extern "system" { + pub fn WinHttpSetStatusCallback( + hInternet: HINTERNET, + lpfnInternetCallback: WINHTTP_STATUS_CALLBACK, + dwNotificationFlags: DWORD, + dwReserved: DWORD_PTR, + ) -> WINHTTP_STATUS_CALLBACK; + pub fn WinHttpTimeFromSystemTime( + pst: *const SYSTEMTIME, + pwszTime: LPWSTR, + ) -> BOOL; + pub fn WinHttpTimeToSystemTime( + pwszTime: LPCWSTR, + pst: *mut SYSTEMTIME, + ) -> BOOL; + pub fn WinHttpCrackUrl( + pwszUrl: LPCWSTR, + dwUrlLength: DWORD, + dwFlags: DWORD, + lpUrlComponents: LPURL_COMPONENTS, + ) -> BOOL; + pub fn WinHttpCreateUrl( + lpUrlComponents: LPURL_COMPONENTS, + dwFlags: DWORD, + pwszUrl: LPWSTR, + pdwUrlLength: LPDWORD, + ) -> BOOL; + pub fn WinHttpCheckPlatform() -> BOOL; + pub fn WinHttpGetDefaultProxyConfiguration( + pProxyInfo: *mut WINHTTP_PROXY_INFO, + ) -> BOOL; + pub fn WinHttpSetDefaultProxyConfiguration( + pProxyInfo: *mut WINHTTP_PROXY_INFO, + ) -> BOOL; + pub fn WinHttpOpen( + pszAgentW: LPCWSTR, + dwAccessType: DWORD, + pszProxyW: LPCWSTR, + pszProxyBypassW: LPCWSTR, + dwFlags: DWORD, + ) -> HINTERNET; + pub fn WinHttpCloseHandle( + hInternet: HINTERNET, + ) -> BOOL; + pub fn WinHttpConnect( + hSession: HINTERNET, + pswzServerName: LPCWSTR, + nServerPort: INTERNET_PORT, + dwReserved: DWORD, + ) -> HINTERNET; + pub fn WinHttpReadData( + hRequest: HINTERNET, + lpBuffer: LPVOID, + dwNumberOfBytesToRead: DWORD, + lpdwNumberOfBytesRead: LPDWORD, + ) -> BOOL; + pub fn WinHttpWriteData( + hRequest: HINTERNET, + lpBuffer: LPCVOID, + dwNumberOfBytesToWrite: DWORD, + lpdwNumberOfBytesWritten: LPDWORD, + ) -> BOOL; + pub fn WinHttpQueryDataAvailable( + hRequest: HINTERNET, + lpdwNumberOfBytesAvailable: LPDWORD, + ) -> BOOL; + pub fn WinHttpQueryOption( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn WinHttpSetOption( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + dwBufferLength: DWORD, + ) -> BOOL; + pub fn WinHttpSetTimeouts( + hInternet: HINTERNET, + nResolveTimeout: c_int, + nConnectTimeout: c_int, + nSendTimeout: c_int, + nReceiveTimeout: c_int, + ) -> BOOL; + pub fn WinHttpOpenRequest( + hConnect: HINTERNET, + pwszVerb: LPCWSTR, + pwszObjectName: LPCWSTR, + pwszVersion: LPCWSTR, + pwszReferrer: LPCWSTR, + ppwszAcceptTypes: *mut LPCWSTR, + dwFlags: DWORD, + ) -> HINTERNET; + pub fn WinHttpAddRequestHeaders( + hRequest: HINTERNET, + lpszHeaders: LPCWSTR, + dwHeadersLength: DWORD, + dwModifiers: DWORD, + ) -> BOOL; + pub fn WinHttpSendRequest( + hRequest: HINTERNET, + lpszHeaders: LPCWSTR, + dwHeadersLength: DWORD, + lpOptional: LPVOID, + dwOptionalLength: DWORD, + dwTotalLength: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn WinHttpSetCredentials( + hRequest: HINTERNET, + AuthTargets: DWORD, + AuthScheme: DWORD, + pwszUserName: LPCWSTR, + pwszPassword: LPCWSTR, + pAuthParams: LPVOID, + ) -> BOOL; + pub fn WinHttpQueryAuthSchemes( + hRequest: HINTERNET, + lpdwSupportedSchemes: LPDWORD, + lpdwFirstScheme: LPDWORD, + pdwAuthTarget: LPDWORD, + ) -> BOOL; + pub fn WinHttpReceiveResponse( + hRequest: HINTERNET, + lpReserved: LPVOID, + ) -> BOOL; + pub fn WinHttpQueryHeaders( + hRequest: HINTERNET, + dwInfoLevel: DWORD, + pwszName: LPCWSTR, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + lpdwIndex: LPDWORD, + ) -> BOOL; + pub fn WinHttpDetectAutoProxyConfigUrl( + dwAutoDetectFlags: DWORD, + ppwstrAutoConfigUrl: *mut LPWSTR, + ) -> BOOL; + pub fn WinHttpGetProxyForUrl( + hSession: HINTERNET, + lpcwszUrl: LPCWSTR, + pAutoProxyOptions: *mut WINHTTP_AUTOPROXY_OPTIONS, + pProxyInfo: *mut WINHTTP_PROXY_INFO, + ) -> BOOL; + pub fn WinHttpCreateProxyResolver( + hSession: HINTERNET, + phResolver: *mut HINTERNET, + ) -> DWORD; + pub fn WinHttpGetProxyForUrlEx( + hResolver: HINTERNET, + pcwszUrl: PCWSTR, + pAutoProxyOptions: *mut WINHTTP_AUTOPROXY_OPTIONS, + pContext: DWORD_PTR, + ) -> DWORD; + pub fn WinHttpGetProxyResult( + hResolver: HINTERNET, + pProxyResult: *mut WINHTTP_PROXY_RESULT, + ) -> DWORD; + pub fn WinHttpFreeProxyResult( + pProxyResult: *mut WINHTTP_PROXY_RESULT, + ); + pub fn WinHttpResetAutoProxy( + hSession: HINTERNET, + dwFlags: DWORD, + ) -> DWORD; + pub fn WinHttpGetIEProxyConfigForCurrentUser( + pProxyConfig: *mut WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, + ) -> BOOL; +} +ENUM!{enum WINHTTP_WEB_SOCKET_OPERATION { + WINHTTP_WEB_SOCKET_SEND_OPERATION = 0, + WINHTTP_WEB_SOCKET_RECEIVE_OPERATION = 1, + WINHTTP_WEB_SOCKET_CLOSE_OPERATION = 2, + WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION = 3, +}} +ENUM!{enum WINHTTP_WEB_SOCKET_BUFFER_TYPE { + WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE = 0, + WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE = 1, + WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE = 2, + WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE = 3, + WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE = 4, +}} +ENUM!{enum WINHTTP_WEB_SOCKET_CLOSE_STATUS { + WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000, + WINHTTP_WEB_SOCKET_ENDPOINT_TERMINATED_CLOSE_STATUS = 1001, + WINHTTP_WEB_SOCKET_PROTOCOL_ERROR_CLOSE_STATUS = 1002, + WINHTTP_WEB_SOCKET_INVALID_DATA_TYPE_CLOSE_STATUS = 1003, + WINHTTP_WEB_SOCKET_EMPTY_CLOSE_STATUS = 1005, + WINHTTP_WEB_SOCKET_ABORTED_CLOSE_STATUS = 1006, + WINHTTP_WEB_SOCKET_INVALID_PAYLOAD_CLOSE_STATUS = 1007, + WINHTTP_WEB_SOCKET_POLICY_VIOLATION_CLOSE_STATUS = 1008, + WINHTTP_WEB_SOCKET_MESSAGE_TOO_BIG_CLOSE_STATUS = 1009, + WINHTTP_WEB_SOCKET_UNSUPPORTED_EXTENSIONS_CLOSE_STATUS = 1010, + WINHTTP_WEB_SOCKET_SERVER_ERROR_CLOSE_STATUS = 1011, + WINHTTP_WEB_SOCKET_SECURE_HANDSHAKE_ERROR_CLOSE_STATUS = 1015, +}} +extern "system" { + pub fn WinHttpWebSocketCompleteUpgrade( + hRequest: HINTERNET, + pContext: DWORD_PTR, + ) -> HINTERNET; + pub fn WinHttpWebSocketSend( + hWebSocket: HINTERNET, + eBufferType: WINHTTP_WEB_SOCKET_BUFFER_TYPE, + pvBuffer: PVOID, + dwBufferLength: DWORD, + ) -> DWORD; + pub fn WinHttpWebSocketReceive( + hWebSocket: HINTERNET, + pvBuffer: PVOID, + dwBufferLength: DWORD, + pdwBytesRead: *mut DWORD, + peBufferType: *mut WINHTTP_WEB_SOCKET_BUFFER_TYPE, + ) -> DWORD; + pub fn WinHttpWebSocketShutdown( + hWebSocket: HINTERNET, + usStatus: USHORT, + pvReason: PVOID, + dwReasonLength: DWORD, + ) -> DWORD; + pub fn WinHttpWebSocketClose( + hWebSocket: HINTERNET, + usStatus: USHORT, + pvReason: PVOID, + dwReasonLength: DWORD, + ) -> DWORD; + pub fn WinHttpWebSocketQueryCloseStatus( + hWebSocket: HINTERNET, + pusStatus: *mut USHORT, + pvReason: PVOID, + dwReasonLength: DWORD, + pdwReasonLengthConsumed: *mut DWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/wininet.rs b/winapi/src/um/wininet.rs new file mode 100644 index 000000000..9a83d6a5d --- /dev/null +++ b/winapi/src/um/wininet.rs @@ -0,0 +1,2364 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Windows Internet Services API procedure declarations, types and constants. +use ctypes::c_int; +use shared::basetsd::DWORD_PTR; +use shared::minwindef::{ + BOOL, DWORD, FALSE, FILETIME, INT, LPBYTE, + LPCVOID, LPDWORD, LPVOID, PBYTE, PDWORD, TRUE, WORD, +}; +use shared::ntdef::{LONG, LONGLONG, PLONG}; +use shared::windef::HWND; +use um::minwinbase::{LPWIN32_FIND_DATAA, LPWIN32_FIND_DATAW, SYSTEMTIME}; +use um::winineti::INTERNET_FLAG_BGUPDATE; +use um::winnt::{ + CHAR, DWORDLONG, HANDLE, LPCSTR, LPCWSTR, + LPSTR, LPWSTR, PCWSTR, PSTR, PWSTR, WCHAR, +}; +pub type HINTERNET = LPVOID; +pub type LPHINTERNET = *mut HINTERNET; +pub type INTERNET_PORT = WORD; +pub type LPINTERNET_PORT = *mut INTERNET_PORT; +pub const INTERNET_INVALID_PORT_NUMBER: DWORD = 0; +pub const INTERNET_DEFAULT_FTP_PORT: DWORD = 21; +pub const INTERNET_DEFAULT_GOPHER_PORT: DWORD = 70; +pub const INTERNET_DEFAULT_HTTP_PORT: DWORD = 80; +pub const INTERNET_DEFAULT_HTTPS_PORT: DWORD = 443; +pub const INTERNET_DEFAULT_SOCKS_PORT: DWORD = 1080; +pub const INTERNET_MAX_HOST_NAME_LENGTH: usize = 256; +pub const INTERNET_MAX_USER_NAME_LENGTH: usize = 128; +pub const INTERNET_MAX_PASSWORD_LENGTH: usize = 128; +pub const INTERNET_MAX_PORT_NUMBER_LENGTH: usize = 5; +pub const INTERNET_MAX_PORT_NUMBER_VALUE: DWORD = 65535; +pub const INTERNET_MAX_PATH_LENGTH: usize = 2048; +pub const INTERNET_MAX_SCHEME_LENGTH: usize = 32; +pub const INTERNET_MAX_URL_LENGTH: usize = INTERNET_MAX_SCHEME_LENGTH + 3 + + INTERNET_MAX_PATH_LENGTH; +pub const INTERNET_KEEP_ALIVE_UNKNOWN: DWORD = -1i32 as u32; +pub const INTERNET_KEEP_ALIVE_ENABLED: DWORD = 1; +pub const INTERNET_KEEP_ALIVE_DISABLED: DWORD = 0; +pub const INTERNET_REQFLAG_FROM_CACHE: DWORD = 0x00000001; +pub const INTERNET_REQFLAG_ASYNC: DWORD = 0x00000002; +pub const INTERNET_REQFLAG_VIA_PROXY: DWORD = 0x00000004; +pub const INTERNET_REQFLAG_NO_HEADERS: DWORD = 0x00000008; +pub const INTERNET_REQFLAG_PASSIVE: DWORD = 0x00000010; +pub const INTERNET_REQFLAG_CACHE_WRITE_DISABLED: DWORD = 0x00000040; +pub const INTERNET_REQFLAG_NET_TIMEOUT: DWORD = 0x00000080; +pub const INTERNET_FLAG_IDN_DIRECT: DWORD = 0x00000001; +pub const INTERNET_FLAG_IDN_PROXY: DWORD = 0x00000002; +pub const INTERNET_FLAG_RELOAD: DWORD = 0x80000000; +pub const INTERNET_FLAG_RAW_DATA: DWORD = 0x40000000; +pub const INTERNET_FLAG_EXISTING_CONNECT: DWORD = 0x20000000; +pub const INTERNET_FLAG_ASYNC: DWORD = 0x10000000; +pub const INTERNET_FLAG_PASSIVE: DWORD = 0x08000000; +pub const INTERNET_FLAG_NO_CACHE_WRITE: DWORD = 0x04000000; +pub const INTERNET_FLAG_DONT_CACHE: DWORD = INTERNET_FLAG_NO_CACHE_WRITE; +pub const INTERNET_FLAG_MAKE_PERSISTENT: DWORD = 0x02000000; +pub const INTERNET_FLAG_FROM_CACHE: DWORD = 0x01000000; +pub const INTERNET_FLAG_OFFLINE: DWORD = INTERNET_FLAG_FROM_CACHE; +pub const INTERNET_FLAG_SECURE: DWORD = 0x00800000; +pub const INTERNET_FLAG_KEEP_CONNECTION: DWORD = 0x00400000; +pub const INTERNET_FLAG_NO_AUTO_REDIRECT: DWORD = 0x00200000; +pub const INTERNET_FLAG_READ_PREFETCH: DWORD = 0x00100000; +pub const INTERNET_FLAG_NO_COOKIES: DWORD = 0x00080000; +pub const INTERNET_FLAG_NO_AUTH: DWORD = 0x00040000; +pub const INTERNET_FLAG_RESTRICTED_ZONE: DWORD = 0x00020000; +pub const INTERNET_FLAG_CACHE_IF_NET_FAIL: DWORD = 0x00010000; +pub const INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP: DWORD = 0x00008000; +pub const INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS: DWORD = 0x00004000; +pub const INTERNET_FLAG_IGNORE_CERT_DATE_INVALID: DWORD = 0x00002000; +pub const INTERNET_FLAG_IGNORE_CERT_CN_INVALID: DWORD = 0x00001000; +pub const INTERNET_FLAG_RESYNCHRONIZE: DWORD = 0x00000800; +pub const INTERNET_FLAG_HYPERLINK: DWORD = 0x00000400; +pub const INTERNET_FLAG_NO_UI: DWORD = 0x00000200; +pub const INTERNET_FLAG_PRAGMA_NOCACHE: DWORD = 0x00000100; +pub const INTERNET_FLAG_CACHE_ASYNC: DWORD = 0x00000080; +pub const INTERNET_FLAG_FORMS_SUBMIT: DWORD = 0x00000040; +pub const INTERNET_FLAG_FWD_BACK: DWORD = 0x00000020; +pub const INTERNET_FLAG_NEED_FILE: DWORD = 0x00000010; +pub const INTERNET_FLAG_MUST_CACHE_REQUEST: DWORD = INTERNET_FLAG_NEED_FILE; +pub const INTERNET_FLAG_TRANSFER_ASCII: DWORD = FTP_TRANSFER_TYPE_ASCII; +pub const INTERNET_FLAG_TRANSFER_BINARY: DWORD = FTP_TRANSFER_TYPE_BINARY; +pub const SECURITY_INTERNET_MASK: DWORD = INTERNET_FLAG_IGNORE_CERT_CN_INVALID + | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS + | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; +pub const SECURITY_IGNORE_ERROR_MASK: DWORD = INTERNET_FLAG_IGNORE_CERT_CN_INVALID + | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA + | SECURITY_FLAG_IGNORE_REVOCATION; +pub const INTERNET_FLAGS_MASK: DWORD = INTERNET_FLAG_RELOAD | INTERNET_FLAG_RAW_DATA + | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_ASYNC | INTERNET_FLAG_PASSIVE + | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_MAKE_PERSISTENT | INTERNET_FLAG_FROM_CACHE + | INTERNET_FLAG_SECURE | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTO_REDIRECT + | INTERNET_FLAG_READ_PREFETCH | INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_AUTH + | INTERNET_FLAG_CACHE_IF_NET_FAIL | SECURITY_INTERNET_MASK | INTERNET_FLAG_RESYNCHRONIZE + | INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_NO_UI | INTERNET_FLAG_PRAGMA_NOCACHE + | INTERNET_FLAG_CACHE_ASYNC | INTERNET_FLAG_FORMS_SUBMIT | INTERNET_FLAG_NEED_FILE + | INTERNET_FLAG_RESTRICTED_ZONE | INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_TRANSFER_ASCII + | INTERNET_FLAG_FWD_BACK | INTERNET_FLAG_BGUPDATE; +pub const INTERNET_ERROR_MASK_INSERT_CDROM: DWORD = 0x1; +pub const INTERNET_ERROR_MASK_COMBINED_SEC_CERT: DWORD = 0x2; +pub const INTERNET_ERROR_MASK_NEED_MSN_SSPI_PKG: DWORD = 0x4; +pub const INTERNET_ERROR_MASK_LOGIN_FAILURE_DISPLAY_ENTITY_BODY: DWORD = 0x8; +pub const INTERNET_OPTIONS_MASK: DWORD = !INTERNET_FLAGS_MASK; +pub const WININET_API_FLAG_ASYNC: DWORD = 0x00000001; +pub const WININET_API_FLAG_SYNC: DWORD = 0x00000004; +pub const WININET_API_FLAG_USE_CONTEXT: DWORD = 0x00000008; +pub const INTERNET_NO_CALLBACK: DWORD = 0; +ENUM!{enum INTERNET_SCHEME { + INTERNET_SCHEME_PARTIAL = -2i32 as u32, + INTERNET_SCHEME_UNKNOWN = -1i32 as u32, + INTERNET_SCHEME_DEFAULT = 0, + INTERNET_SCHEME_FTP, + INTERNET_SCHEME_GOPHER, + INTERNET_SCHEME_HTTP, + INTERNET_SCHEME_HTTPS, + INTERNET_SCHEME_FILE, + INTERNET_SCHEME_NEWS, + INTERNET_SCHEME_MAILTO, + INTERNET_SCHEME_SOCKS, + INTERNET_SCHEME_JAVASCRIPT, + INTERNET_SCHEME_VBSCRIPT, + INTERNET_SCHEME_RES, + INTERNET_SCHEME_FIRST = INTERNET_SCHEME_FTP, + INTERNET_SCHEME_LAST = INTERNET_SCHEME_RES, +}} +pub type LPINTERNET_SCHEME = *mut INTERNET_SCHEME; +STRUCT!{struct INTERNET_ASYNC_RESULT { + dwResult: DWORD_PTR, + dwError: DWORD, +}} +pub type LPINTERNET_ASYNC_RESULT = *mut INTERNET_ASYNC_RESULT; +STRUCT!{struct INTERNET_DIAGNOSTIC_SOCKET_INFO { + Socket: DWORD_PTR, + SourcePort: DWORD, + DestPort: DWORD, + Flags: DWORD, +}} +pub type LPINTERNET_DIAGNOSTIC_SOCKET_INFO = *mut INTERNET_DIAGNOSTIC_SOCKET_INFO; +pub const IDSI_FLAG_KEEP_ALIVE: DWORD = 0x00000001; +pub const IDSI_FLAG_SECURE: DWORD = 0x00000002; +pub const IDSI_FLAG_PROXY: DWORD = 0x00000004; +pub const IDSI_FLAG_TUNNEL: DWORD = 0x00000008; +STRUCT!{struct INTERNET_PROXY_INFO { + dwAccessType: DWORD, + lpszProxy: LPCWSTR, + lpszProxyBypass: LPCWSTR, +}} +pub type LPINTERNET_PROXY_INFO = *mut INTERNET_PROXY_INFO; +UNION!{union INTERNET_PER_CONN_OPTIONA_Value { + [u32; 2] [u64; 1], + dwValue dwValue_mut: DWORD, + pszValue pszValue_mut: LPSTR, + ftValue ftValue_mut: FILETIME, +}} +STRUCT!{struct INTERNET_PER_CONN_OPTIONA { + dwOption: DWORD, + Value: INTERNET_PER_CONN_OPTIONA_Value, +}} +pub type LPINTERNET_PER_CONN_OPTIONA = *mut INTERNET_PER_CONN_OPTIONA; +UNION!{union INTERNET_PER_CONN_OPTIONW_Value { + [u32; 2] [u64; 1], + dwValue dwValue_mut: DWORD, + pszValue pszValue_mut: LPWSTR, + ftValue ftValue_mut: FILETIME, +}} +STRUCT!{struct INTERNET_PER_CONN_OPTIONW { + dwOption: DWORD, + Value: INTERNET_PER_CONN_OPTIONW_Value, +}} +pub type LPINTERNET_PER_CONN_OPTIONW = *mut INTERNET_PER_CONN_OPTIONW; +STRUCT!{struct INTERNET_PER_CONN_OPTION_LISTA { + dwSize: DWORD, + pszConnection: LPSTR, + dwOptionCount: DWORD, + dwOptionError: DWORD, + pOptions: LPINTERNET_PER_CONN_OPTIONA, +}} +pub type LPINTERNET_PER_CONN_OPTION_LISTA = *mut INTERNET_PER_CONN_OPTION_LISTA; +STRUCT!{struct INTERNET_PER_CONN_OPTION_LISTW { + dwSize: DWORD, + pszConnection: LPWSTR, + dwOptionCount: DWORD, + dwOptionError: DWORD, + pOptions: LPINTERNET_PER_CONN_OPTIONW, +}} +pub type LPINTERNET_PER_CONN_OPTION_LISTW = *mut INTERNET_PER_CONN_OPTION_LISTW; +pub const INTERNET_PER_CONN_FLAGS: DWORD = 1; +pub const INTERNET_PER_CONN_PROXY_SERVER: DWORD = 2; +pub const INTERNET_PER_CONN_PROXY_BYPASS: DWORD = 3; +pub const INTERNET_PER_CONN_AUTOCONFIG_URL: DWORD = 4; +pub const INTERNET_PER_CONN_AUTODISCOVERY_FLAGS: DWORD = 5; +pub const INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL: DWORD = 6; +pub const INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS: DWORD = 7; +pub const INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME: DWORD = 8; +pub const INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL: DWORD = 9; +pub const INTERNET_PER_CONN_FLAGS_UI: DWORD = 10; +pub const PROXY_TYPE_DIRECT: DWORD = 0x00000001; +pub const PROXY_TYPE_PROXY: DWORD = 0x00000002; +pub const PROXY_TYPE_AUTO_PROXY_URL: DWORD = 0x00000004; +pub const PROXY_TYPE_AUTO_DETECT: DWORD = 0x00000008; +pub const AUTO_PROXY_FLAG_USER_SET: DWORD = 0x00000001; +pub const AUTO_PROXY_FLAG_ALWAYS_DETECT: DWORD = 0x00000002; +pub const AUTO_PROXY_FLAG_DETECTION_RUN: DWORD = 0x00000004; +pub const AUTO_PROXY_FLAG_MIGRATED: DWORD = 0x00000008; +pub const AUTO_PROXY_FLAG_DONT_CACHE_PROXY_RESULT: DWORD = 0x00000010; +pub const AUTO_PROXY_FLAG_CACHE_INIT_RUN: DWORD = 0x00000020; +pub const AUTO_PROXY_FLAG_DETECTION_SUSPECT: DWORD = 0x00000040; +STRUCT!{struct INTERNET_VERSION_INFO { + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, +}} +pub type LPINTERNET_VERSION_INFO = *mut INTERNET_VERSION_INFO; +STRUCT!{struct HTTP_VERSION_INFO { + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, +}} +pub type LPHTTP_VERSION_INFO = *mut HTTP_VERSION_INFO; +STRUCT!{struct INTERNET_CONNECTED_INFO { + dwConnectedState: DWORD, + dwFlags: DWORD, +}} +pub type LPINTERNET_CONNECTED_INFO = *mut INTERNET_CONNECTED_INFO; +pub const ISO_FORCE_DISCONNECTED: DWORD = 0x00000001; +STRUCT!{struct URL_COMPONENTSA { + dwStructSize: DWORD, + lpszScheme: LPSTR, + dwSchemeLength: DWORD, + nScheme: INTERNET_SCHEME, + lpszHostName: LPSTR, + dwHostNameLength: DWORD, + nPort: INTERNET_PORT, + lpszUserName: LPSTR, + dwUserNameLength: DWORD, + lpszPassword: LPSTR, + dwPasswordLength: DWORD, + lpszUrlPath: LPSTR, + dwUrlPathLength: DWORD, + lpszExtraInfo: LPSTR, + dwExtraInfoLength: DWORD, +}} +pub type LPURL_COMPONENTSA = *mut URL_COMPONENTSA; +STRUCT!{struct URL_COMPONENTSW { + dwStructSize: DWORD, + lpszScheme: LPWSTR, + dwSchemeLength: DWORD, + nScheme: INTERNET_SCHEME, + lpszHostName: LPWSTR, + dwHostNameLength: DWORD, + nPort: INTERNET_PORT, + lpszUserName: LPWSTR, + dwUserNameLength: DWORD, + lpszPassword: LPWSTR, + dwPasswordLength: DWORD, + lpszUrlPath: LPWSTR, + dwUrlPathLength: DWORD, + lpszExtraInfo: LPWSTR, + dwExtraInfoLength: DWORD, +}} +pub type LPURL_COMPONENTSW = *mut URL_COMPONENTSW; +STRUCT!{struct INTERNET_CERTIFICATE_INFO { + ftExpiry: FILETIME, + ftStart: FILETIME, + lpszSubjectInfo: LPWSTR, + lpszIssuerInfo: LPWSTR, + lpszProtocolName: LPWSTR, + lpszSignatureAlgName: LPWSTR, + lpszEncryptionAlgName: LPWSTR, + dwKeySize: DWORD, +}} +pub type LPINTERNET_CERTIFICATE_INFO = *mut INTERNET_CERTIFICATE_INFO; +STRUCT!{struct INTERNET_BUFFERSA { + dwStructSize: DWORD, + Next: *mut INTERNET_BUFFERSA, + lpcszHeader: LPCSTR, + dwHeadersLength: DWORD, + dwHeadersTotal: DWORD, + lpvBuffer: LPVOID, + dwBufferLength: DWORD, + dwBufferTotal: DWORD, + dwOffsetLow: DWORD, + dwOffsetHigh: DWORD, +}} +pub type LPINTERNET_BUFFERSA = *mut INTERNET_BUFFERSA; +STRUCT!{struct INTERNET_BUFFERSW { + dwStructSize: DWORD, + Next: *mut INTERNET_BUFFERSW, + lpcszHeader: LPCWSTR, + dwHeadersLength: DWORD, + dwHeadersTotal: DWORD, + lpvBuffer: LPVOID, + dwBufferLength: DWORD, + dwBufferTotal: DWORD, + dwOffsetLow: DWORD, + dwOffsetHigh: DWORD, +}} +pub type LPINTERNET_BUFFERSW = *mut INTERNET_BUFFERSW; +pub const INTERNET_RFC1123_FORMAT: DWORD = 0; +pub const INTERNET_RFC1123_BUFSIZE: DWORD = 30; +pub const ICU_ESCAPE: DWORD = 0x80000000; +pub const ICU_USERNAME: DWORD = 0x40000000; +pub const ICU_NO_ENCODE: DWORD = 0x20000000; +pub const ICU_DECODE: DWORD = 0x10000000; +pub const ICU_NO_META: DWORD = 0x08000000; +pub const ICU_ENCODE_SPACES_ONLY: DWORD = 0x04000000; +pub const ICU_BROWSER_MODE: DWORD = 0x02000000; +pub const ICU_ENCODE_PERCENT: DWORD = 0x00001000; +pub const INTERNET_OPEN_TYPE_PRECONFIG: DWORD = 0; +pub const INTERNET_OPEN_TYPE_DIRECT: DWORD = 1; +pub const INTERNET_OPEN_TYPE_PROXY: DWORD = 3; +pub const INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY: DWORD = 4; +pub const PRE_CONFIG_INTERNET_ACCESS: DWORD = INTERNET_OPEN_TYPE_PRECONFIG; +pub const LOCAL_INTERNET_ACCESS: DWORD = INTERNET_OPEN_TYPE_DIRECT; +pub const CERN_PROXY_INTERNET_ACCESS: DWORD = INTERNET_OPEN_TYPE_PROXY; +pub const INTERNET_SERVICE_FTP: DWORD = 1; +pub const INTERNET_SERVICE_GOPHER: DWORD = 2; +pub const INTERNET_SERVICE_HTTP: DWORD = 3; +pub const IRF_ASYNC: DWORD = WININET_API_FLAG_ASYNC; +pub const IRF_SYNC: DWORD = WININET_API_FLAG_SYNC; +pub const IRF_USE_CONTEXT: DWORD = WININET_API_FLAG_USE_CONTEXT; +pub const IRF_NO_WAIT: DWORD = 0x00000008; +pub const ISO_GLOBAL: DWORD = 0x00000001; +pub const ISO_REGISTRY: DWORD = 0x00000002; +pub const ISO_VALID_FLAGS: DWORD = ISO_GLOBAL | ISO_REGISTRY; +pub const INTERNET_OPTION_CALLBACK: DWORD = 1; +pub const INTERNET_OPTION_CONNECT_TIMEOUT: DWORD = 2; +pub const INTERNET_OPTION_CONNECT_RETRIES: DWORD = 3; +pub const INTERNET_OPTION_CONNECT_BACKOFF: DWORD = 4; +pub const INTERNET_OPTION_SEND_TIMEOUT: DWORD = 5; +pub const INTERNET_OPTION_CONTROL_SEND_TIMEOUT: DWORD = INTERNET_OPTION_SEND_TIMEOUT; +pub const INTERNET_OPTION_RECEIVE_TIMEOUT: DWORD = 6; +pub const INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT: DWORD = INTERNET_OPTION_RECEIVE_TIMEOUT; +pub const INTERNET_OPTION_DATA_SEND_TIMEOUT: DWORD = 7; +pub const INTERNET_OPTION_DATA_RECEIVE_TIMEOUT: DWORD = 8; +pub const INTERNET_OPTION_HANDLE_TYPE: DWORD = 9; +pub const INTERNET_OPTION_LISTEN_TIMEOUT: DWORD = 11; +pub const INTERNET_OPTION_READ_BUFFER_SIZE: DWORD = 12; +pub const INTERNET_OPTION_WRITE_BUFFER_SIZE: DWORD = 13; +pub const INTERNET_OPTION_ASYNC_ID: DWORD = 15; +pub const INTERNET_OPTION_ASYNC_PRIORITY: DWORD = 16; +pub const INTERNET_OPTION_PARENT_HANDLE: DWORD = 21; +pub const INTERNET_OPTION_KEEP_CONNECTION: DWORD = 22; +pub const INTERNET_OPTION_REQUEST_FLAGS: DWORD = 23; +pub const INTERNET_OPTION_EXTENDED_ERROR: DWORD = 24; +pub const INTERNET_OPTION_OFFLINE_MODE: DWORD = 26; +pub const INTERNET_OPTION_CACHE_STREAM_HANDLE: DWORD = 27; +pub const INTERNET_OPTION_USERNAME: DWORD = 28; +pub const INTERNET_OPTION_PASSWORD: DWORD = 29; +pub const INTERNET_OPTION_ASYNC: DWORD = 30; +pub const INTERNET_OPTION_SECURITY_FLAGS: DWORD = 31; +pub const INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: DWORD = 32; +pub const INTERNET_OPTION_DATAFILE_NAME: DWORD = 33; +pub const INTERNET_OPTION_URL: DWORD = 34; +pub const INTERNET_OPTION_SECURITY_CERTIFICATE: DWORD = 35; +pub const INTERNET_OPTION_SECURITY_KEY_BITNESS: DWORD = 36; +pub const INTERNET_OPTION_REFRESH: DWORD = 37; +pub const INTERNET_OPTION_PROXY: DWORD = 38; +pub const INTERNET_OPTION_SETTINGS_CHANGED: DWORD = 39; +pub const INTERNET_OPTION_VERSION: DWORD = 40; +pub const INTERNET_OPTION_USER_AGENT: DWORD = 41; +pub const INTERNET_OPTION_END_BROWSER_SESSION: DWORD = 42; +pub const INTERNET_OPTION_PROXY_USERNAME: DWORD = 43; +pub const INTERNET_OPTION_PROXY_PASSWORD: DWORD = 44; +pub const INTERNET_OPTION_CONTEXT_VALUE: DWORD = 45; +pub const INTERNET_OPTION_CONNECT_LIMIT: DWORD = 46; +pub const INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT: DWORD = 47; +pub const INTERNET_OPTION_POLICY: DWORD = 48; +pub const INTERNET_OPTION_DISCONNECTED_TIMEOUT: DWORD = 49; +pub const INTERNET_OPTION_CONNECTED_STATE: DWORD = 50; +pub const INTERNET_OPTION_IDLE_STATE: DWORD = 51; +pub const INTERNET_OPTION_OFFLINE_SEMANTICS: DWORD = 52; +pub const INTERNET_OPTION_SECONDARY_CACHE_KEY: DWORD = 53; +pub const INTERNET_OPTION_CALLBACK_FILTER: DWORD = 54; +pub const INTERNET_OPTION_CONNECT_TIME: DWORD = 55; +pub const INTERNET_OPTION_SEND_THROUGHPUT: DWORD = 56; +pub const INTERNET_OPTION_RECEIVE_THROUGHPUT: DWORD = 57; +pub const INTERNET_OPTION_REQUEST_PRIORITY: DWORD = 58; +pub const INTERNET_OPTION_HTTP_VERSION: DWORD = 59; +pub const INTERNET_OPTION_RESET_URLCACHE_SESSION: DWORD = 60; +pub const INTERNET_OPTION_ERROR_MASK: DWORD = 62; +pub const INTERNET_OPTION_FROM_CACHE_TIMEOUT: DWORD = 63; +pub const INTERNET_OPTION_BYPASS_EDITED_ENTRY: DWORD = 64; +pub const INTERNET_OPTION_HTTP_DECODING: DWORD = 65; +pub const INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO: DWORD = 67; +pub const INTERNET_OPTION_CODEPAGE: DWORD = 68; +pub const INTERNET_OPTION_CACHE_TIMESTAMPS: DWORD = 69; +pub const INTERNET_OPTION_DISABLE_AUTODIAL: DWORD = 70; +pub const INTERNET_OPTION_MAX_CONNS_PER_SERVER: DWORD = 73; +pub const INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER: DWORD = 74; +pub const INTERNET_OPTION_PER_CONNECTION_OPTION: DWORD = 75; +pub const INTERNET_OPTION_DIGEST_AUTH_UNLOAD: DWORD = 76; +pub const INTERNET_OPTION_IGNORE_OFFLINE: DWORD = 77; +pub const INTERNET_OPTION_IDENTITY: DWORD = 78; +pub const INTERNET_OPTION_REMOVE_IDENTITY: DWORD = 79; +pub const INTERNET_OPTION_ALTER_IDENTITY: DWORD = 80; +pub const INTERNET_OPTION_SUPPRESS_BEHAVIOR: DWORD = 81; +pub const INTERNET_OPTION_AUTODIAL_MODE: DWORD = 82; +pub const INTERNET_OPTION_AUTODIAL_CONNECTION: DWORD = 83; +pub const INTERNET_OPTION_CLIENT_CERT_CONTEXT: DWORD = 84; +pub const INTERNET_OPTION_AUTH_FLAGS: DWORD = 85; +pub const INTERNET_OPTION_COOKIES_3RD_PARTY: DWORD = 86; +pub const INTERNET_OPTION_DISABLE_PASSPORT_AUTH: DWORD = 87; +pub const INTERNET_OPTION_SEND_UTF8_SERVERNAME_TO_PROXY: DWORD = 88; +pub const INTERNET_OPTION_EXEMPT_CONNECTION_LIMIT: DWORD = 89; +pub const INTERNET_OPTION_ENABLE_PASSPORT_AUTH: DWORD = 90; +pub const INTERNET_OPTION_HIBERNATE_INACTIVE_WORKER_THREADS: DWORD = 91; +pub const INTERNET_OPTION_ACTIVATE_WORKER_THREADS: DWORD = 92; +pub const INTERNET_OPTION_RESTORE_WORKER_THREAD_DEFAULTS: DWORD = 93; +pub const INTERNET_OPTION_SOCKET_SEND_BUFFER_LENGTH: DWORD = 94; +pub const INTERNET_OPTION_PROXY_SETTINGS_CHANGED: DWORD = 95; +pub const INTERNET_OPTION_DATAFILE_EXT: DWORD = 96; +pub const INTERNET_OPTION_CODEPAGE_PATH: DWORD = 100; +pub const INTERNET_OPTION_CODEPAGE_EXTRA: DWORD = 101; +pub const INTERNET_OPTION_IDN: DWORD = 102; +pub const INTERNET_OPTION_MAX_CONNS_PER_PROXY: DWORD = 103; +pub const INTERNET_OPTION_SUPPRESS_SERVER_AUTH: DWORD = 104; +pub const INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT: DWORD = 105; +pub const INTERNET_OPTION_ENABLE_REDIRECT_CACHE_READ: DWORD = 122; +pub const INTERNET_OPTION_ENCODE_EXTRA: DWORD = 155; +pub const INTERNET_FIRST_OPTION: DWORD = INTERNET_OPTION_CALLBACK; +pub const INTERNET_LAST_OPTION: DWORD = INTERNET_OPTION_ENCODE_EXTRA; +pub const INTERNET_PRIORITY_FOREGROUND: DWORD = 1000; +pub const INTERNET_HANDLE_TYPE_INTERNET: DWORD = 1; +pub const INTERNET_HANDLE_TYPE_CONNECT_FTP: DWORD = 2; +pub const INTERNET_HANDLE_TYPE_CONNECT_GOPHER: DWORD = 3; +pub const INTERNET_HANDLE_TYPE_CONNECT_HTTP: DWORD = 4; +pub const INTERNET_HANDLE_TYPE_FTP_FIND: DWORD = 5; +pub const INTERNET_HANDLE_TYPE_FTP_FIND_HTML: DWORD = 6; +pub const INTERNET_HANDLE_TYPE_FTP_FILE: DWORD = 7; +pub const INTERNET_HANDLE_TYPE_FTP_FILE_HTML: DWORD = 8; +pub const INTERNET_HANDLE_TYPE_GOPHER_FIND: DWORD = 9; +pub const INTERNET_HANDLE_TYPE_GOPHER_FIND_HTML: DWORD = 10; +pub const INTERNET_HANDLE_TYPE_GOPHER_FILE: DWORD = 11; +pub const INTERNET_HANDLE_TYPE_GOPHER_FILE_HTML: DWORD = 12; +pub const INTERNET_HANDLE_TYPE_HTTP_REQUEST: DWORD = 13; +pub const INTERNET_HANDLE_TYPE_FILE_REQUEST: DWORD = 14; +pub const AUTH_FLAG_DISABLE_NEGOTIATE: DWORD = 0x00000001; +pub const AUTH_FLAG_ENABLE_NEGOTIATE: DWORD = 0x00000002; +pub const AUTH_FLAG_DISABLE_BASIC_CLEARCHANNEL: DWORD = 0x00000004; +pub const AUTH_FLAG_DISABLE_SERVER_AUTH: DWORD = 0x00000008; +pub const SECURITY_FLAG_SECURE: DWORD = 0x00000001; +pub const SECURITY_FLAG_STRENGTH_WEAK: DWORD = 0x10000000; +pub const SECURITY_FLAG_STRENGTH_MEDIUM: DWORD = 0x40000000; +pub const SECURITY_FLAG_STRENGTH_STRONG: DWORD = 0x20000000; +pub const SECURITY_FLAG_UNKNOWNBIT: DWORD = 0x80000000; +pub const SECURITY_FLAG_FORTEZZA: DWORD = 0x08000000; +pub const SECURITY_FLAG_NORMALBITNESS: DWORD = SECURITY_FLAG_STRENGTH_WEAK; +pub const SECURITY_FLAG_SSL: DWORD = 0x00000002; +pub const SECURITY_FLAG_SSL3: DWORD = 0x00000004; +pub const SECURITY_FLAG_PCT: DWORD = 0x00000008; +pub const SECURITY_FLAG_PCT4: DWORD = 0x00000010; +pub const SECURITY_FLAG_IETFSSL4: DWORD = 0x00000020; +pub const SECURITY_FLAG_40BIT: DWORD = SECURITY_FLAG_STRENGTH_WEAK; +pub const SECURITY_FLAG_128BIT: DWORD = SECURITY_FLAG_STRENGTH_STRONG; +pub const SECURITY_FLAG_56BIT: DWORD = SECURITY_FLAG_STRENGTH_MEDIUM; +pub const SECURITY_FLAG_IGNORE_REVOCATION: DWORD = 0x00000080; +pub const SECURITY_FLAG_IGNORE_UNKNOWN_CA: DWORD = 0x00000100; +pub const SECURITY_FLAG_IGNORE_WRONG_USAGE: DWORD = 0x00000200; +pub const SECURITY_FLAG_IGNORE_CERT_CN_INVALID: DWORD = INTERNET_FLAG_IGNORE_CERT_CN_INVALID; +pub const SECURITY_FLAG_IGNORE_CERT_DATE_INVALID: DWORD = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; +pub const SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS: DWORD = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS; +pub const SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP: DWORD = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; +pub const SECURITY_SET_MASK: DWORD = SECURITY_FLAG_IGNORE_REVOCATION + | SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID + | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_WRONG_USAGE; +pub const AUTODIAL_MODE_NEVER: DWORD = 1; +pub const AUTODIAL_MODE_ALWAYS: DWORD = 2; +pub const AUTODIAL_MODE_NO_NETWORK_PRESENT: DWORD = 4; +FN!{stdcall INTERNET_STATUS_CALLBACK( + HINTERNET, + DWORD_PTR, + DWORD, + LPVOID, + DWORD, +) -> ()} +pub type LPINTERNET_STATUS_CALLBACK = *mut INTERNET_STATUS_CALLBACK; +pub const INTERNET_STATUS_RESOLVING_NAME: DWORD = 10; +pub const INTERNET_STATUS_NAME_RESOLVED: DWORD = 11; +pub const INTERNET_STATUS_CONNECTING_TO_SERVER: DWORD = 20; +pub const INTERNET_STATUS_CONNECTED_TO_SERVER: DWORD = 21; +pub const INTERNET_STATUS_SENDING_REQUEST: DWORD = 30; +pub const INTERNET_STATUS_REQUEST_SENT: DWORD = 31; +pub const INTERNET_STATUS_RECEIVING_RESPONSE: DWORD = 40; +pub const INTERNET_STATUS_RESPONSE_RECEIVED: DWORD = 41; +pub const INTERNET_STATUS_CTL_RESPONSE_RECEIVED: DWORD = 42; +pub const INTERNET_STATUS_PREFETCH: DWORD = 43; +pub const INTERNET_STATUS_CLOSING_CONNECTION: DWORD = 50; +pub const INTERNET_STATUS_CONNECTION_CLOSED: DWORD = 51; +pub const INTERNET_STATUS_HANDLE_CREATED: DWORD = 60; +pub const INTERNET_STATUS_HANDLE_CLOSING: DWORD = 70; +pub const INTERNET_STATUS_DETECTING_PROXY: DWORD = 80; +pub const INTERNET_STATUS_REQUEST_COMPLETE: DWORD = 100; +pub const INTERNET_STATUS_REDIRECT: DWORD = 110; +pub const INTERNET_STATUS_INTERMEDIATE_RESPONSE: DWORD = 120; +pub const INTERNET_STATUS_USER_INPUT_REQUIRED: DWORD = 140; +pub const INTERNET_STATUS_STATE_CHANGE: DWORD = 200; +pub const INTERNET_STATUS_COOKIE_SENT: DWORD = 320; +pub const INTERNET_STATUS_COOKIE_RECEIVED: DWORD = 321; +pub const INTERNET_STATUS_PRIVACY_IMPACTED: DWORD = 324; +pub const INTERNET_STATUS_P3P_HEADER: DWORD = 325; +pub const INTERNET_STATUS_P3P_POLICYREF: DWORD = 326; +pub const INTERNET_STATUS_COOKIE_HISTORY: DWORD = 327; +pub const INTERNET_STATE_CONNECTED: DWORD = 0x00000001; +pub const INTERNET_STATE_DISCONNECTED: DWORD = 0x00000002; +pub const INTERNET_STATE_DISCONNECTED_BY_USER: DWORD = 0x00000010; +pub const INTERNET_STATE_IDLE: DWORD = 0x00000100; +pub const INTERNET_STATE_BUSY: DWORD = 0x00000200; +ENUM!{enum InternetCookieState { + COOKIE_STATE_UNKNOWN = 0x0, + COOKIE_STATE_ACCEPT = 0x1, + COOKIE_STATE_PROMPT = 0x2, + COOKIE_STATE_LEASH = 0x3, + COOKIE_STATE_DOWNGRADE = 0x4, + COOKIE_STATE_REJECT = 0x5, + COOKIE_STATE_MAX = COOKIE_STATE_REJECT, +}} +STRUCT!{struct IncomingCookieState { + cSession: c_int, + cPersistent: c_int, + cAccepted: c_int, + cLeashed: c_int, + cDowngraded: c_int, + cBlocked: c_int, + pszLocation: LPCSTR, +}} +STRUCT!{struct OutgoingCookieState { + cSent: c_int, + cSuppressed: c_int, + pszLocation: LPCSTR, +}} +STRUCT!{struct InternetCookieHistory { + fAccepted: BOOL, + fLeashed: BOOL, + fDowngraded: BOOL, + fRejected: BOOL, +}} +STRUCT!{struct CookieDecision { + dwCookieState: DWORD, + fAllowSession: BOOL, +}} +pub const INTERNET_INVALID_STATUS_CALLBACK: usize = -1isize as usize; +pub const FTP_TRANSFER_TYPE_UNKNOWN: DWORD = 0x00000000; +pub const FTP_TRANSFER_TYPE_ASCII: DWORD = 0x00000001; +pub const FTP_TRANSFER_TYPE_BINARY: DWORD = 0x00000002; +pub const FTP_TRANSFER_TYPE_MASK: DWORD = FTP_TRANSFER_TYPE_ASCII | FTP_TRANSFER_TYPE_BINARY; +pub const MAX_GOPHER_DISPLAY_TEXT: usize = 128; +pub const MAX_GOPHER_SELECTOR_TEXT: usize = 256; +pub const MAX_GOPHER_HOST_NAME: usize = INTERNET_MAX_HOST_NAME_LENGTH; +pub const MAX_GOPHER_LOCATOR_LENGTH: usize = 1 + MAX_GOPHER_DISPLAY_TEXT + 1 + + MAX_GOPHER_SELECTOR_TEXT + 1 + MAX_GOPHER_HOST_NAME + 1 + INTERNET_MAX_PORT_NUMBER_LENGTH + + 1 + 1 + 2; +STRUCT!{struct GOPHER_FIND_DATAA { + DisplayString: [CHAR; MAX_GOPHER_DISPLAY_TEXT+ 1], + GopherType: DWORD, + SizeLow: DWORD, + SizeHigh: DWORD, + LastModificationTime: FILETIME, + Locator: [CHAR; MAX_GOPHER_LOCATOR_LENGTH + 1], +}} +pub type LPGOPHER_FIND_DATAA = *mut GOPHER_FIND_DATAA; +STRUCT!{struct GOPHER_FIND_DATAW { + DisplayString: [WCHAR; MAX_GOPHER_DISPLAY_TEXT+ 1], + GopherType: DWORD, + SizeLow: DWORD, + SizeHigh: DWORD, + LastModificationTime: FILETIME, + Locator: [WCHAR; MAX_GOPHER_LOCATOR_LENGTH + 1], +}} +pub type LPGOPHER_FIND_DATAW = *mut GOPHER_FIND_DATAW; +pub const GOPHER_TYPE_TEXT_FILE: DWORD = 0x00000001; +pub const GOPHER_TYPE_DIRECTORY: DWORD = 0x00000002; +pub const GOPHER_TYPE_CSO: DWORD = 0x00000004; +pub const GOPHER_TYPE_ERROR: DWORD = 0x00000008; +pub const GOPHER_TYPE_MAC_BINHEX: DWORD = 0x00000010; +pub const GOPHER_TYPE_DOS_ARCHIVE: DWORD = 0x00000020; +pub const GOPHER_TYPE_UNIX_UUENCODED: DWORD = 0x00000040; +pub const GOPHER_TYPE_INDEX_SERVER: DWORD = 0x00000080; +pub const GOPHER_TYPE_TELNET: DWORD = 0x00000100; +pub const GOPHER_TYPE_BINARY: DWORD = 0x00000200; +pub const GOPHER_TYPE_REDUNDANT: DWORD = 0x00000400; +pub const GOPHER_TYPE_TN3270: DWORD = 0x00000800; +pub const GOPHER_TYPE_GIF: DWORD = 0x00001000; +pub const GOPHER_TYPE_IMAGE: DWORD = 0x00002000; +pub const GOPHER_TYPE_BITMAP: DWORD = 0x00004000; +pub const GOPHER_TYPE_MOVIE: DWORD = 0x00008000; +pub const GOPHER_TYPE_SOUND: DWORD = 0x00010000; +pub const GOPHER_TYPE_HTML: DWORD = 0x00020000; +pub const GOPHER_TYPE_PDF: DWORD = 0x00040000; +pub const GOPHER_TYPE_CALENDAR: DWORD = 0x00080000; +pub const GOPHER_TYPE_INLINE: DWORD = 0x00100000; +pub const GOPHER_TYPE_UNKNOWN: DWORD = 0x20000000; +pub const GOPHER_TYPE_ASK: DWORD = 0x40000000; +pub const GOPHER_TYPE_GOPHER_PLUS: DWORD = 0x80000000; +#[inline] +pub fn IS_GOPHER_FILE(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_FILE_MASK) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_DIRECTORY(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_DIRECTORY) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_PHONE_SERVER(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_CSO) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_ERROR(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_ERROR) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_INDEX_SERVER(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_INDEX_SERVER) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_TELNET_SESSION(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_TELNET) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_BACKUP_SERVER(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_REDUNDANT) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_TN3270_SESSION(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_TN3270) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_ASK(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_ASK) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_PLUS(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_GOPHER_PLUS) != 0 { TRUE } else { FALSE } +} +#[inline] +pub fn IS_GOPHER_TYPE_KNOWN(type_: DWORD) -> BOOL { + if (type_ & GOPHER_TYPE_UNKNOWN) != 0 { FALSE } else { TRUE } +} +pub const GOPHER_TYPE_FILE_MASK: DWORD = GOPHER_TYPE_TEXT_FILE | GOPHER_TYPE_MAC_BINHEX + | GOPHER_TYPE_DOS_ARCHIVE | GOPHER_TYPE_UNIX_UUENCODED | GOPHER_TYPE_BINARY | GOPHER_TYPE_GIF + | GOPHER_TYPE_IMAGE | GOPHER_TYPE_BITMAP | GOPHER_TYPE_MOVIE | GOPHER_TYPE_SOUND + | GOPHER_TYPE_HTML | GOPHER_TYPE_PDF | GOPHER_TYPE_CALENDAR | GOPHER_TYPE_INLINE; +STRUCT!{struct GOPHER_ADMIN_ATTRIBUTE_TYPE { + Comment: LPCWSTR, + EmailAddress: LPCWSTR, +}} +pub type LPGOPHER_ADMIN_ATTRIBUTE_TYPE = *mut GOPHER_ADMIN_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_MOD_DATE_ATTRIBUTE_TYPE { + DateAndTime: FILETIME, +}} +pub type LPGOPHER_MOD_DATE_ATTRIBUTE_TYPE = *mut GOPHER_MOD_DATE_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_TTL_ATTRIBUTE_TYPE { + Ttl: DWORD, +}} +pub type LPGOPHER_TTL_ATTRIBUTE_TYPE = *mut GOPHER_TTL_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_SCORE_ATTRIBUTE_TYPE { + Score: INT, +}} +pub type LPGOPHER_SCORE_ATTRIBUTE_TYPE = *mut GOPHER_SCORE_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE { + LowerBound: INT, + UpperBound: INT, +}} +pub type LPGOPHER_SCORE_RANGE_ATTRIBUTE_TYPE = *mut GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_SITE_ATTRIBUTE_TYPE { + Site: LPCWSTR, +}} +pub type LPGOPHER_SITE_ATTRIBUTE_TYPE = *mut GOPHER_SITE_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_ORGANIZATION_ATTRIBUTE_TYPE { + Organization: LPCWSTR, +}} +pub type LPGOPHER_ORGANIZATION_ATTRIBUTE_TYPE = *mut GOPHER_ORGANIZATION_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_LOCATION_ATTRIBUTE_TYPE { + Location: LPCWSTR, +}} +pub type LPGOPHER_LOCATION_ATTRIBUTE_TYPE = *mut GOPHER_LOCATION_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE { + DegreesNorth: INT, + MinutesNorth: INT, + SecondsNorth: INT, + DegreesEast: INT, + MinutesEast: INT, + SecondsEast: INT, +}} +pub type LPGOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE = + *mut GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_TIMEZONE_ATTRIBUTE_TYPE { + Zone: INT, +}} +pub type LPGOPHER_TIMEZONE_ATTRIBUTE_TYPE = *mut GOPHER_TIMEZONE_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_PROVIDER_ATTRIBUTE_TYPE { + Provider: LPCWSTR, +}} +pub type LPGOPHER_PROVIDER_ATTRIBUTE_TYPE = *mut GOPHER_PROVIDER_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_VERSION_ATTRIBUTE_TYPE { + Version: LPCWSTR, +}} +pub type LPGOPHER_VERSION_ATTRIBUTE_TYPE = *mut GOPHER_VERSION_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_ABSTRACT_ATTRIBUTE_TYPE { + ShortAbstract: LPCWSTR, + AbstractFile: LPCWSTR, +}} +pub type LPGOPHER_ABSTRACT_ATTRIBUTE_TYPE = *mut GOPHER_ABSTRACT_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_VIEW_ATTRIBUTE_TYPE { + ContentType: LPCWSTR, + Language: LPCWSTR, + Size: DWORD, +}} +pub type LPGOPHER_VIEW_ATTRIBUTE_TYPE = *mut GOPHER_VIEW_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_VERONICA_ATTRIBUTE_TYPE { + TreeWalk: BOOL, +}} +pub type LPGOPHER_VERONICA_ATTRIBUTE_TYPE = *mut GOPHER_VERONICA_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_ASK_ATTRIBUTE_TYPE { + QuestionType: LPCWSTR, + QuestionText: LPCWSTR, +}} +pub type LPGOPHER_ASK_ATTRIBUTE_TYPE = *mut GOPHER_ASK_ATTRIBUTE_TYPE; +STRUCT!{struct GOPHER_UNKNOWN_ATTRIBUTE_TYPE { + Text: LPCWSTR, +}} +pub type LPGOPHER_UNKNOWN_ATTRIBUTE_TYPE = *mut GOPHER_UNKNOWN_ATTRIBUTE_TYPE; +UNION!{union GOPHER_ATTRIBUTE_TYPE_AttributeType { + [u32; 6] [u64; 3], + Admin Admin_mut: GOPHER_ADMIN_ATTRIBUTE_TYPE, + ModDate ModDate_mut: GOPHER_MOD_DATE_ATTRIBUTE_TYPE, + Ttl Ttl_mut: GOPHER_TTL_ATTRIBUTE_TYPE, + Score Score_mut: GOPHER_SCORE_ATTRIBUTE_TYPE, + ScoreRange ScoreRange_mut: GOPHER_SCORE_RANGE_ATTRIBUTE_TYPE, + Site Site_mut: GOPHER_SITE_ATTRIBUTE_TYPE, + Organization Organization_mut: GOPHER_ORGANIZATION_ATTRIBUTE_TYPE, + Location Location_mut: GOPHER_LOCATION_ATTRIBUTE_TYPE, + GeographicalLocation GeographicalLocation_mut: GOPHER_GEOGRAPHICAL_LOCATION_ATTRIBUTE_TYPE, + TimeZone TimeZone_mut: GOPHER_TIMEZONE_ATTRIBUTE_TYPE, + Provider Provider_mut: GOPHER_PROVIDER_ATTRIBUTE_TYPE, + Version Version_mut: GOPHER_VERSION_ATTRIBUTE_TYPE, + Abstract Abstract_mut: GOPHER_ABSTRACT_ATTRIBUTE_TYPE, + View View_mut: GOPHER_VIEW_ATTRIBUTE_TYPE, + Veronica Veronica_mut: GOPHER_VERONICA_ATTRIBUTE_TYPE, + Ask Ask_mut: GOPHER_ASK_ATTRIBUTE_TYPE, + Unknown Unknown_mut: GOPHER_UNKNOWN_ATTRIBUTE_TYPE, +}} +STRUCT!{struct GOPHER_ATTRIBUTE_TYPE { + CategoryId: DWORD, + AttributeId: DWORD, + AttributeType: GOPHER_ATTRIBUTE_TYPE_AttributeType, +}} +pub type LPGOPHER_ATTRIBUTE_TYPE = *mut GOPHER_ATTRIBUTE_TYPE; +pub const MAX_GOPHER_CATEGORY_NAME: DWORD = 128; +pub const MAX_GOPHER_ATTRIBUTE_NAME: DWORD = 128; +pub const MIN_GOPHER_ATTRIBUTE_LENGTH: DWORD = 256; +pub const GOPHER_INFO_CATEGORY: &'static str = " + INFO"; +pub const GOPHER_ADMIN_CATEGORY: &'static str = " + ADMIN"; +pub const GOPHER_VIEWS_CATEGORY: &'static str = " + VIEWS"; +pub const GOPHER_ABSTRACT_CATEGORY: &'static str = " + ABSTRACT"; +pub const GOPHER_VERONICA_CATEGORY: &'static str = " + VERONICA"; +pub const GOPHER_ADMIN_ATTRIBUTE: &'static str = "Admin"; +pub const GOPHER_MOD_DATE_ATTRIBUTE: &'static str = "Mod-Date"; +pub const GOPHER_TTL_ATTRIBUTE: &'static str = "TTL"; +pub const GOPHER_SCORE_ATTRIBUTE: &'static str = "Score"; +pub const GOPHER_RANGE_ATTRIBUTE: &'static str = "Score-range"; +pub const GOPHER_SITE_ATTRIBUTE: &'static str = "Site"; +pub const GOPHER_ORG_ATTRIBUTE: &'static str = "Org"; +pub const GOPHER_LOCATION_ATTRIBUTE: &'static str = "Loc"; +pub const GOPHER_GEOG_ATTRIBUTE: &'static str = "Geog"; +pub const GOPHER_TIMEZONE_ATTRIBUTE: &'static str = "TZ"; +pub const GOPHER_PROVIDER_ATTRIBUTE: &'static str = "Provider"; +pub const GOPHER_VERSION_ATTRIBUTE: &'static str = "Version"; +pub const GOPHER_ABSTRACT_ATTRIBUTE: &'static str = "Abstract"; +pub const GOPHER_VIEW_ATTRIBUTE: &'static str = "View"; +pub const GOPHER_TREEWALK_ATTRIBUTE: &'static str = "treewalk"; +pub const GOPHER_ATTRIBUTE_ID_BASE: DWORD = 0xabcccc00; +pub const GOPHER_CATEGORY_ID_ALL: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 1; +pub const GOPHER_CATEGORY_ID_INFO: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 2; +pub const GOPHER_CATEGORY_ID_ADMIN: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 3; +pub const GOPHER_CATEGORY_ID_VIEWS: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 4; +pub const GOPHER_CATEGORY_ID_ABSTRACT: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 5; +pub const GOPHER_CATEGORY_ID_VERONICA: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 6; +pub const GOPHER_CATEGORY_ID_ASK: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 7; +pub const GOPHER_CATEGORY_ID_UNKNOWN: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 8; +pub const GOPHER_ATTRIBUTE_ID_ALL: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 9; +pub const GOPHER_ATTRIBUTE_ID_ADMIN: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 10; +pub const GOPHER_ATTRIBUTE_ID_MOD_DATE: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 11; +pub const GOPHER_ATTRIBUTE_ID_TTL: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 12; +pub const GOPHER_ATTRIBUTE_ID_SCORE: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 13; +pub const GOPHER_ATTRIBUTE_ID_RANGE: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 14; +pub const GOPHER_ATTRIBUTE_ID_SITE: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 15; +pub const GOPHER_ATTRIBUTE_ID_ORG: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 16; +pub const GOPHER_ATTRIBUTE_ID_LOCATION: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 17; +pub const GOPHER_ATTRIBUTE_ID_GEOG: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 18; +pub const GOPHER_ATTRIBUTE_ID_TIMEZONE: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 19; +pub const GOPHER_ATTRIBUTE_ID_PROVIDER: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 20; +pub const GOPHER_ATTRIBUTE_ID_VERSION: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 21; +pub const GOPHER_ATTRIBUTE_ID_ABSTRACT: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 22; +pub const GOPHER_ATTRIBUTE_ID_VIEW: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 23; +pub const GOPHER_ATTRIBUTE_ID_TREEWALK: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 24; +pub const GOPHER_ATTRIBUTE_ID_UNKNOWN: DWORD = GOPHER_ATTRIBUTE_ID_BASE + 25; +FN!{stdcall GOPHER_ATTRIBUTE_ENUMERATOR( + LPGOPHER_ATTRIBUTE_TYPE, + DWORD, +) -> BOOL} +pub const HTTP_MAJOR_VERSION: DWORD = 1; +pub const HTTP_MINOR_VERSION: DWORD = 0; +pub const HTTP_VERSION: &'static str = "HTTP/1.0"; +pub const HTTP_QUERY_MIME_VERSION: DWORD = 0; +pub const HTTP_QUERY_CONTENT_TYPE: DWORD = 1; +pub const HTTP_QUERY_CONTENT_TRANSFER_ENCODING: DWORD = 2; +pub const HTTP_QUERY_CONTENT_ID: DWORD = 3; +pub const HTTP_QUERY_CONTENT_DESCRIPTION: DWORD = 4; +pub const HTTP_QUERY_CONTENT_LENGTH: DWORD = 5; +pub const HTTP_QUERY_CONTENT_LANGUAGE: DWORD = 6; +pub const HTTP_QUERY_ALLOW: DWORD = 7; +pub const HTTP_QUERY_PUBLIC: DWORD = 8; +pub const HTTP_QUERY_DATE: DWORD = 9; +pub const HTTP_QUERY_EXPIRES: DWORD = 10; +pub const HTTP_QUERY_LAST_MODIFIED: DWORD = 11; +pub const HTTP_QUERY_MESSAGE_ID: DWORD = 12; +pub const HTTP_QUERY_URI: DWORD = 13; +pub const HTTP_QUERY_DERIVED_FROM: DWORD = 14; +pub const HTTP_QUERY_COST: DWORD = 15; +pub const HTTP_QUERY_LINK: DWORD = 16; +pub const HTTP_QUERY_PRAGMA: DWORD = 17; +pub const HTTP_QUERY_VERSION: DWORD = 18; +pub const HTTP_QUERY_STATUS_CODE: DWORD = 19; +pub const HTTP_QUERY_STATUS_TEXT: DWORD = 20; +pub const HTTP_QUERY_RAW_HEADERS: DWORD = 21; +pub const HTTP_QUERY_RAW_HEADERS_CRLF: DWORD = 22; +pub const HTTP_QUERY_CONNECTION: DWORD = 23; +pub const HTTP_QUERY_ACCEPT: DWORD = 24; +pub const HTTP_QUERY_ACCEPT_CHARSET: DWORD = 25; +pub const HTTP_QUERY_ACCEPT_ENCODING: DWORD = 26; +pub const HTTP_QUERY_ACCEPT_LANGUAGE: DWORD = 27; +pub const HTTP_QUERY_AUTHORIZATION: DWORD = 28; +pub const HTTP_QUERY_CONTENT_ENCODING: DWORD = 29; +pub const HTTP_QUERY_FORWARDED: DWORD = 30; +pub const HTTP_QUERY_FROM: DWORD = 31; +pub const HTTP_QUERY_IF_MODIFIED_SINCE: DWORD = 32; +pub const HTTP_QUERY_LOCATION: DWORD = 33; +pub const HTTP_QUERY_ORIG_URI: DWORD = 34; +pub const HTTP_QUERY_REFERER: DWORD = 35; +pub const HTTP_QUERY_RETRY_AFTER: DWORD = 36; +pub const HTTP_QUERY_SERVER: DWORD = 37; +pub const HTTP_QUERY_TITLE: DWORD = 38; +pub const HTTP_QUERY_USER_AGENT: DWORD = 39; +pub const HTTP_QUERY_WWW_AUTHENTICATE: DWORD = 40; +pub const HTTP_QUERY_PROXY_AUTHENTICATE: DWORD = 41; +pub const HTTP_QUERY_ACCEPT_RANGES: DWORD = 42; +pub const HTTP_QUERY_SET_COOKIE: DWORD = 43; +pub const HTTP_QUERY_COOKIE: DWORD = 44; +pub const HTTP_QUERY_REQUEST_METHOD: DWORD = 45; +pub const HTTP_QUERY_REFRESH: DWORD = 46; +pub const HTTP_QUERY_CONTENT_DISPOSITION: DWORD = 47; +pub const HTTP_QUERY_AGE: DWORD = 48; +pub const HTTP_QUERY_CACHE_CONTROL: DWORD = 49; +pub const HTTP_QUERY_CONTENT_BASE: DWORD = 50; +pub const HTTP_QUERY_CONTENT_LOCATION: DWORD = 51; +pub const HTTP_QUERY_CONTENT_MD5: DWORD = 52; +pub const HTTP_QUERY_CONTENT_RANGE: DWORD = 53; +pub const HTTP_QUERY_ETAG: DWORD = 54; +pub const HTTP_QUERY_HOST: DWORD = 55; +pub const HTTP_QUERY_IF_MATCH: DWORD = 56; +pub const HTTP_QUERY_IF_NONE_MATCH: DWORD = 57; +pub const HTTP_QUERY_IF_RANGE: DWORD = 58; +pub const HTTP_QUERY_IF_UNMODIFIED_SINCE: DWORD = 59; +pub const HTTP_QUERY_MAX_FORWARDS: DWORD = 60; +pub const HTTP_QUERY_PROXY_AUTHORIZATION: DWORD = 61; +pub const HTTP_QUERY_RANGE: DWORD = 62; +pub const HTTP_QUERY_TRANSFER_ENCODING: DWORD = 63; +pub const HTTP_QUERY_UPGRADE: DWORD = 64; +pub const HTTP_QUERY_VARY: DWORD = 65; +pub const HTTP_QUERY_VIA: DWORD = 66; +pub const HTTP_QUERY_WARNING: DWORD = 67; +pub const HTTP_QUERY_EXPECT: DWORD = 68; +pub const HTTP_QUERY_PROXY_CONNECTION: DWORD = 69; +pub const HTTP_QUERY_UNLESS_MODIFIED_SINCE: DWORD = 70; +pub const HTTP_QUERY_ECHO_REQUEST: DWORD = 71; +pub const HTTP_QUERY_ECHO_REPLY: DWORD = 72; +pub const HTTP_QUERY_ECHO_HEADERS: DWORD = 73; +pub const HTTP_QUERY_ECHO_HEADERS_CRLF: DWORD = 74; +pub const HTTP_QUERY_PROXY_SUPPORT: DWORD = 75; +pub const HTTP_QUERY_AUTHENTICATION_INFO: DWORD = 76; +pub const HTTP_QUERY_PASSPORT_URLS: DWORD = 77; +pub const HTTP_QUERY_PASSPORT_CONFIG: DWORD = 78; +pub const HTTP_QUERY_X_CONTENT_TYPE_OPTIONS: DWORD = 79; +pub const HTTP_QUERY_P3P: DWORD = 80; +pub const HTTP_QUERY_X_P2P_PEERDIST: DWORD = 81; +pub const HTTP_QUERY_TRANSLATE: DWORD = 82; +pub const HTTP_QUERY_X_UA_COMPATIBLE: DWORD = 83; +pub const HTTP_QUERY_DEFAULT_STYLE: DWORD = 84; +pub const HTTP_QUERY_X_FRAME_OPTIONS: DWORD = 85; +pub const HTTP_QUERY_X_XSS_PROTECTION: DWORD = 86; +pub const HTTP_QUERY_SET_COOKIE2: DWORD = 87; +pub const HTTP_QUERY_DO_NOT_TRACK: DWORD = 88; +pub const HTTP_QUERY_KEEP_ALIVE: DWORD = 89; +pub const HTTP_QUERY_MAX: DWORD = 89; +pub const HTTP_QUERY_CUSTOM: DWORD = 65535; +pub const HTTP_QUERY_FLAG_REQUEST_HEADERS: DWORD = 0x80000000; +pub const HTTP_QUERY_FLAG_SYSTEMTIME: DWORD = 0x40000000; +pub const HTTP_QUERY_FLAG_NUMBER: DWORD = 0x20000000; +pub const HTTP_QUERY_FLAG_COALESCE: DWORD = 0x10000000; +pub const HTTP_QUERY_FLAG_NUMBER64: DWORD = 0x08000000; +pub const HTTP_QUERY_MODIFIER_FLAGS_MASK: DWORD = HTTP_QUERY_FLAG_REQUEST_HEADERS + | HTTP_QUERY_FLAG_SYSTEMTIME | HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_FLAG_COALESCE + | HTTP_QUERY_FLAG_NUMBER64; +pub const HTTP_QUERY_HEADER_MASK: DWORD = !HTTP_QUERY_MODIFIER_FLAGS_MASK; +pub const HTTP_STATUS_CONTINUE: DWORD = 100; +pub const HTTP_STATUS_SWITCH_PROTOCOLS: DWORD = 101; +pub const HTTP_STATUS_OK: DWORD = 200; +pub const HTTP_STATUS_CREATED: DWORD = 201; +pub const HTTP_STATUS_ACCEPTED: DWORD = 202; +pub const HTTP_STATUS_PARTIAL: DWORD = 203; +pub const HTTP_STATUS_NO_CONTENT: DWORD = 204; +pub const HTTP_STATUS_RESET_CONTENT: DWORD = 205; +pub const HTTP_STATUS_PARTIAL_CONTENT: DWORD = 206; +pub const HTTP_STATUS_AMBIGUOUS: DWORD = 300; +pub const HTTP_STATUS_MOVED: DWORD = 301; +pub const HTTP_STATUS_REDIRECT: DWORD = 302; +pub const HTTP_STATUS_REDIRECT_METHOD: DWORD = 303; +pub const HTTP_STATUS_NOT_MODIFIED: DWORD = 304; +pub const HTTP_STATUS_USE_PROXY: DWORD = 305; +pub const HTTP_STATUS_REDIRECT_KEEP_VERB: DWORD = 307; +pub const HTTP_STATUS_BAD_REQUEST: DWORD = 400; +pub const HTTP_STATUS_DENIED: DWORD = 401; +pub const HTTP_STATUS_PAYMENT_REQ: DWORD = 402; +pub const HTTP_STATUS_FORBIDDEN: DWORD = 403; +pub const HTTP_STATUS_NOT_FOUND: DWORD = 404; +pub const HTTP_STATUS_BAD_METHOD: DWORD = 405; +pub const HTTP_STATUS_NONE_ACCEPTABLE: DWORD = 406; +pub const HTTP_STATUS_PROXY_AUTH_REQ: DWORD = 407; +pub const HTTP_STATUS_REQUEST_TIMEOUT: DWORD = 408; +pub const HTTP_STATUS_CONFLICT: DWORD = 409; +pub const HTTP_STATUS_GONE: DWORD = 410; +pub const HTTP_STATUS_LENGTH_REQUIRED: DWORD = 411; +pub const HTTP_STATUS_PRECOND_FAILED: DWORD = 412; +pub const HTTP_STATUS_REQUEST_TOO_LARGE: DWORD = 413; +pub const HTTP_STATUS_URI_TOO_LONG: DWORD = 414; +pub const HTTP_STATUS_UNSUPPORTED_MEDIA: DWORD = 415; +pub const HTTP_STATUS_RETRY_WITH: DWORD = 449; +pub const HTTP_STATUS_SERVER_ERROR: DWORD = 500; +pub const HTTP_STATUS_NOT_SUPPORTED: DWORD = 501; +pub const HTTP_STATUS_BAD_GATEWAY: DWORD = 502; +pub const HTTP_STATUS_SERVICE_UNAVAIL: DWORD = 503; +pub const HTTP_STATUS_GATEWAY_TIMEOUT: DWORD = 504; +pub const HTTP_STATUS_VERSION_NOT_SUP: DWORD = 505; +pub const HTTP_STATUS_FIRST: DWORD = HTTP_STATUS_CONTINUE; +pub const HTTP_STATUS_LAST: DWORD = HTTP_STATUS_VERSION_NOT_SUP; +pub const HTTP_ADDREQ_INDEX_MASK: DWORD = 0x0000FFFF; +pub const HTTP_ADDREQ_FLAGS_MASK: DWORD = 0xFFFF0000; +pub const HTTP_ADDREQ_FLAG_ADD_IF_NEW: DWORD = 0x10000000; +pub const HTTP_ADDREQ_FLAG_ADD: DWORD = 0x20000000; +pub const HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA: DWORD = 0x40000000; +pub const HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON: DWORD = 0x01000000; +pub const HTTP_ADDREQ_FLAG_COALESCE: DWORD = HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA; +pub const HTTP_ADDREQ_FLAG_REPLACE: DWORD = 0x80000000; +pub const HSR_ASYNC: DWORD = WININET_API_FLAG_ASYNC; +pub const HSR_SYNC: DWORD = WININET_API_FLAG_SYNC; +pub const HSR_USE_CONTEXT: DWORD = WININET_API_FLAG_USE_CONTEXT; +pub const HSR_INITIATE: DWORD = 0x00000008; +pub const HSR_DOWNLOAD: DWORD = 0x00000010; +pub const HSR_CHUNKED: DWORD = 0x00000020; +STRUCT!{struct INTERNET_COOKIE2 { + pwszName: PWSTR, + pwszValue: PWSTR, + pwszDomain: PWSTR, + pwszPath: PWSTR, + dwFlags: DWORD, + ftExpires: FILETIME, + fExpiresSet: BOOL, +}} +pub const INTERNET_COOKIE_IS_SECURE: DWORD = 0x01; +pub const INTERNET_COOKIE_IS_SESSION: DWORD = 0x02; +pub const INTERNET_COOKIE_THIRD_PARTY: DWORD = 0x10; +pub const INTERNET_COOKIE_PROMPT_REQUIRED: DWORD = 0x20; +pub const INTERNET_COOKIE_EVALUATE_P3P: DWORD = 0x40; +pub const INTERNET_COOKIE_APPLY_P3P: DWORD = 0x80; +pub const INTERNET_COOKIE_P3P_ENABLED: DWORD = 0x100; +pub const INTERNET_COOKIE_IS_RESTRICTED: DWORD = 0x200; +pub const INTERNET_COOKIE_IE6: DWORD = 0x400; +pub const INTERNET_COOKIE_IS_LEGACY: DWORD = 0x800; +pub const INTERNET_COOKIE_NON_SCRIPT: DWORD = 0x00001000; +pub const INTERNET_COOKIE_HTTPONLY: DWORD = 0x00002000; +pub const FLAG_ICC_FORCE_CONNECTION: DWORD = 0x00000001; +pub const FLAGS_ERROR_UI_FILTER_FOR_ERRORS: DWORD = 0x01; +pub const FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS: DWORD = 0x02; +pub const FLAGS_ERROR_UI_FLAGS_GENERATE_DATA: DWORD = 0x04; +pub const FLAGS_ERROR_UI_FLAGS_NO_UI: DWORD = 0x08; +pub const FLAGS_ERROR_UI_SERIALIZE_DIALOGS: DWORD = 0x10; +FN!{stdcall PFN_AUTH_NOTIFY( + DWORD_PTR, + DWORD, + LPVOID, +) -> DWORD} +STRUCT!{struct INTERNET_AUTH_NOTIFY_DATA { + cbStruct: DWORD, + dwOptions: DWORD, + pfnNotify: PFN_AUTH_NOTIFY, + dwContext: DWORD_PTR, +}} +pub const INTERNET_ERROR_BASE: DWORD = 12000; +pub const ERROR_INTERNET_OUT_OF_HANDLES: DWORD = INTERNET_ERROR_BASE + 1; +pub const ERROR_INTERNET_TIMEOUT: DWORD = INTERNET_ERROR_BASE + 2; +pub const ERROR_INTERNET_EXTENDED_ERROR: DWORD = INTERNET_ERROR_BASE + 3; +pub const ERROR_INTERNET_INTERNAL_ERROR: DWORD = INTERNET_ERROR_BASE + 4; +pub const ERROR_INTERNET_INVALID_URL: DWORD = INTERNET_ERROR_BASE + 5; +pub const ERROR_INTERNET_UNRECOGNIZED_SCHEME: DWORD = INTERNET_ERROR_BASE + 6; +pub const ERROR_INTERNET_NAME_NOT_RESOLVED: DWORD = INTERNET_ERROR_BASE + 7; +pub const ERROR_INTERNET_PROTOCOL_NOT_FOUND: DWORD = INTERNET_ERROR_BASE + 8; +pub const ERROR_INTERNET_INVALID_OPTION: DWORD = INTERNET_ERROR_BASE + 9; +pub const ERROR_INTERNET_BAD_OPTION_LENGTH: DWORD = INTERNET_ERROR_BASE + 10; +pub const ERROR_INTERNET_OPTION_NOT_SETTABLE: DWORD = INTERNET_ERROR_BASE + 11; +pub const ERROR_INTERNET_SHUTDOWN: DWORD = INTERNET_ERROR_BASE + 12; +pub const ERROR_INTERNET_INCORRECT_USER_NAME: DWORD = INTERNET_ERROR_BASE + 13; +pub const ERROR_INTERNET_INCORRECT_PASSWORD: DWORD = INTERNET_ERROR_BASE + 14; +pub const ERROR_INTERNET_LOGIN_FAILURE: DWORD = INTERNET_ERROR_BASE + 15; +pub const ERROR_INTERNET_INVALID_OPERATION: DWORD = INTERNET_ERROR_BASE + 16; +pub const ERROR_INTERNET_OPERATION_CANCELLED: DWORD = INTERNET_ERROR_BASE + 17; +pub const ERROR_INTERNET_INCORRECT_HANDLE_TYPE: DWORD = INTERNET_ERROR_BASE + 18; +pub const ERROR_INTERNET_INCORRECT_HANDLE_STATE: DWORD = INTERNET_ERROR_BASE + 19; +pub const ERROR_INTERNET_NOT_PROXY_REQUEST: DWORD = INTERNET_ERROR_BASE + 20; +pub const ERROR_INTERNET_REGISTRY_VALUE_NOT_FOUND: DWORD = INTERNET_ERROR_BASE + 21; +pub const ERROR_INTERNET_BAD_REGISTRY_PARAMETER: DWORD = INTERNET_ERROR_BASE + 22; +pub const ERROR_INTERNET_NO_DIRECT_ACCESS: DWORD = INTERNET_ERROR_BASE + 23; +pub const ERROR_INTERNET_NO_CONTEXT: DWORD = INTERNET_ERROR_BASE + 24; +pub const ERROR_INTERNET_NO_CALLBACK: DWORD = INTERNET_ERROR_BASE + 25; +pub const ERROR_INTERNET_REQUEST_PENDING: DWORD = INTERNET_ERROR_BASE + 26; +pub const ERROR_INTERNET_INCORRECT_FORMAT: DWORD = INTERNET_ERROR_BASE + 27; +pub const ERROR_INTERNET_ITEM_NOT_FOUND: DWORD = INTERNET_ERROR_BASE + 28; +pub const ERROR_INTERNET_CANNOT_CONNECT: DWORD = INTERNET_ERROR_BASE + 29; +pub const ERROR_INTERNET_CONNECTION_ABORTED: DWORD = INTERNET_ERROR_BASE + 30; +pub const ERROR_INTERNET_CONNECTION_RESET: DWORD = INTERNET_ERROR_BASE + 31; +pub const ERROR_INTERNET_FORCE_RETRY: DWORD = INTERNET_ERROR_BASE + 32; +pub const ERROR_INTERNET_INVALID_PROXY_REQUEST: DWORD = INTERNET_ERROR_BASE + 33; +pub const ERROR_INTERNET_NEED_UI: DWORD = INTERNET_ERROR_BASE + 34; +pub const ERROR_INTERNET_HANDLE_EXISTS: DWORD = INTERNET_ERROR_BASE + 36; +pub const ERROR_INTERNET_SEC_CERT_DATE_INVALID: DWORD = INTERNET_ERROR_BASE + 37; +pub const ERROR_INTERNET_SEC_CERT_CN_INVALID: DWORD = INTERNET_ERROR_BASE + 38; +pub const ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR: DWORD = INTERNET_ERROR_BASE + 39; +pub const ERROR_INTERNET_HTTPS_TO_HTTP_ON_REDIR: DWORD = INTERNET_ERROR_BASE + 40; +pub const ERROR_INTERNET_MIXED_SECURITY: DWORD = INTERNET_ERROR_BASE + 41; +pub const ERROR_INTERNET_CHG_POST_IS_NON_SECURE: DWORD = INTERNET_ERROR_BASE + 42; +pub const ERROR_INTERNET_POST_IS_NON_SECURE: DWORD = INTERNET_ERROR_BASE + 43; +pub const ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: DWORD = INTERNET_ERROR_BASE + 44; +pub const ERROR_INTERNET_INVALID_CA: DWORD = INTERNET_ERROR_BASE + 45; +pub const ERROR_INTERNET_CLIENT_AUTH_NOT_SETUP: DWORD = INTERNET_ERROR_BASE + 46; +pub const ERROR_INTERNET_ASYNC_THREAD_FAILED: DWORD = INTERNET_ERROR_BASE + 47; +pub const ERROR_INTERNET_REDIRECT_SCHEME_CHANGE: DWORD = INTERNET_ERROR_BASE + 48; +pub const ERROR_INTERNET_DIALOG_PENDING: DWORD = INTERNET_ERROR_BASE + 49; +pub const ERROR_INTERNET_RETRY_DIALOG: DWORD = INTERNET_ERROR_BASE + 50; +pub const ERROR_INTERNET_HTTPS_HTTP_SUBMIT_REDIR: DWORD = INTERNET_ERROR_BASE + 52; +pub const ERROR_INTERNET_INSERT_CDROM: DWORD = INTERNET_ERROR_BASE + 53; +pub const ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED: DWORD = INTERNET_ERROR_BASE + 54; +pub const ERROR_INTERNET_SEC_CERT_ERRORS: DWORD = INTERNET_ERROR_BASE + 55; +pub const ERROR_INTERNET_SEC_CERT_NO_REV: DWORD = INTERNET_ERROR_BASE + 56; +pub const ERROR_INTERNET_SEC_CERT_REV_FAILED: DWORD = INTERNET_ERROR_BASE + 57; +pub const ERROR_FTP_TRANSFER_IN_PROGRESS: DWORD = INTERNET_ERROR_BASE + 110; +pub const ERROR_FTP_DROPPED: DWORD = INTERNET_ERROR_BASE + 111; +pub const ERROR_FTP_NO_PASSIVE_MODE: DWORD = INTERNET_ERROR_BASE + 112; +pub const ERROR_GOPHER_PROTOCOL_ERROR: DWORD = INTERNET_ERROR_BASE + 130; +pub const ERROR_GOPHER_NOT_FILE: DWORD = INTERNET_ERROR_BASE + 131; +pub const ERROR_GOPHER_DATA_ERROR: DWORD = INTERNET_ERROR_BASE + 132; +pub const ERROR_GOPHER_END_OF_DATA: DWORD = INTERNET_ERROR_BASE + 133; +pub const ERROR_GOPHER_INVALID_LOCATOR: DWORD = INTERNET_ERROR_BASE + 134; +pub const ERROR_GOPHER_INCORRECT_LOCATOR_TYPE: DWORD = INTERNET_ERROR_BASE + 135; +pub const ERROR_GOPHER_NOT_GOPHER_PLUS: DWORD = INTERNET_ERROR_BASE + 136; +pub const ERROR_GOPHER_ATTRIBUTE_NOT_FOUND: DWORD = INTERNET_ERROR_BASE + 137; +pub const ERROR_GOPHER_UNKNOWN_LOCATOR: DWORD = INTERNET_ERROR_BASE + 138; +pub const ERROR_HTTP_HEADER_NOT_FOUND: DWORD = INTERNET_ERROR_BASE + 150; +pub const ERROR_HTTP_DOWNLEVEL_SERVER: DWORD = INTERNET_ERROR_BASE + 151; +pub const ERROR_HTTP_INVALID_SERVER_RESPONSE: DWORD = INTERNET_ERROR_BASE + 152; +pub const ERROR_HTTP_INVALID_HEADER: DWORD = INTERNET_ERROR_BASE + 153; +pub const ERROR_HTTP_INVALID_QUERY_REQUEST: DWORD = INTERNET_ERROR_BASE + 154; +pub const ERROR_HTTP_HEADER_ALREADY_EXISTS: DWORD = INTERNET_ERROR_BASE + 155; +pub const ERROR_HTTP_REDIRECT_FAILED: DWORD = INTERNET_ERROR_BASE + 156; +pub const ERROR_HTTP_NOT_REDIRECTED: DWORD = INTERNET_ERROR_BASE + 160; +pub const ERROR_HTTP_COOKIE_NEEDS_CONFIRMATION: DWORD = INTERNET_ERROR_BASE + 161; +pub const ERROR_HTTP_COOKIE_DECLINED: DWORD = INTERNET_ERROR_BASE + 162; +pub const ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION: DWORD = INTERNET_ERROR_BASE + 168; +pub const ERROR_INTERNET_SECURITY_CHANNEL_ERROR: DWORD = INTERNET_ERROR_BASE + 157; +pub const ERROR_INTERNET_UNABLE_TO_CACHE_FILE: DWORD = INTERNET_ERROR_BASE + 158; +pub const ERROR_INTERNET_TCPIP_NOT_INSTALLED: DWORD = INTERNET_ERROR_BASE + 159; +pub const ERROR_INTERNET_DISCONNECTED: DWORD = INTERNET_ERROR_BASE + 163; +pub const ERROR_INTERNET_SERVER_UNREACHABLE: DWORD = INTERNET_ERROR_BASE + 164; +pub const ERROR_INTERNET_PROXY_SERVER_UNREACHABLE: DWORD = INTERNET_ERROR_BASE + 165; +pub const ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT: DWORD = INTERNET_ERROR_BASE + 166; +pub const ERROR_INTERNET_UNABLE_TO_DOWNLOAD_SCRIPT: DWORD = INTERNET_ERROR_BASE + 167; +pub const ERROR_INTERNET_SEC_INVALID_CERT: DWORD = INTERNET_ERROR_BASE + 169; +pub const ERROR_INTERNET_SEC_CERT_REVOKED: DWORD = INTERNET_ERROR_BASE + 170; +pub const ERROR_INTERNET_FAILED_DUETOSECURITYCHECK: DWORD = INTERNET_ERROR_BASE + 171; +pub const ERROR_INTERNET_NOT_INITIALIZED: DWORD = INTERNET_ERROR_BASE + 172; +pub const ERROR_INTERNET_NEED_MSN_SSPI_PKG: DWORD = INTERNET_ERROR_BASE + 173; +pub const ERROR_INTERNET_LOGIN_FAILURE_DISPLAY_ENTITY_BODY: DWORD = INTERNET_ERROR_BASE + 174; +pub const ERROR_INTERNET_DECODING_FAILED: DWORD = INTERNET_ERROR_BASE + 175; +pub const INTERNET_ERROR_LAST: DWORD = ERROR_INTERNET_DECODING_FAILED; +pub const NORMAL_CACHE_ENTRY: DWORD = 0x00000001; +pub const STICKY_CACHE_ENTRY: DWORD = 0x00000004; +pub const EDITED_CACHE_ENTRY: DWORD = 0x00000008; +pub const TRACK_OFFLINE_CACHE_ENTRY: DWORD = 0x00000010; +pub const TRACK_ONLINE_CACHE_ENTRY: DWORD = 0x00000020; +pub const SPARSE_CACHE_ENTRY: DWORD = 0x00010000; +pub const COOKIE_CACHE_ENTRY: DWORD = 0x00100000; +pub const URLHISTORY_CACHE_ENTRY: DWORD = 0x00200000; +pub const URLCACHE_FIND_DEFAULT_FILTER: DWORD = NORMAL_CACHE_ENTRY | COOKIE_CACHE_ENTRY + | URLHISTORY_CACHE_ENTRY | TRACK_OFFLINE_CACHE_ENTRY | TRACK_ONLINE_CACHE_ENTRY + | STICKY_CACHE_ENTRY; +UNION!{union INTERNET_CACHE_ENTRY_INFOA_u { + [u32; 1], + dwReserved dwReserved_mut: DWORD, + dwExemptDelta dwExemptDelta_mut: DWORD, +}} +STRUCT!{struct INTERNET_CACHE_ENTRY_INFOA { + dwStructSize: DWORD, + lpszSourceUrlName: LPSTR, + lpszLocalFileName: LPSTR, + CacheEntryType: DWORD, + dwUseCount: DWORD, + dwHitRate: DWORD, + dwSizeLow: DWORD, + dwSizeHigh: DWORD, + LastModifiedTime: FILETIME, + ExpireTime: FILETIME, + LastAccessTime: FILETIME, + LastSyncTime: FILETIME, + lpHeaderInfo: LPSTR, + dwHeaderInfoSize: DWORD, + lpszFileExtension: LPSTR, + u: INTERNET_CACHE_ENTRY_INFOA_u, +}} +pub type LPINTERNET_CACHE_ENTRY_INFOA = *mut INTERNET_CACHE_ENTRY_INFOA; +UNION!{union INTERNET_CACHE_ENTRY_INFOW_u { + [u32; 1], + dwReserved dwReserved_mut: DWORD, + dwExemptDelta dwExemptDelta_mut: DWORD, +}} +STRUCT!{struct INTERNET_CACHE_ENTRY_INFOW { + dwStructSize: DWORD, + lpszSourceUrlName: LPWSTR, + lpszLocalFileName: LPWSTR, + CacheEntryType: DWORD, + dwUseCount: DWORD, + dwHitRate: DWORD, + dwSizeLow: DWORD, + dwSizeHigh: DWORD, + LastModifiedTime: FILETIME, + ExpireTime: FILETIME, + LastAccessTime: FILETIME, + LastSyncTime: FILETIME, + lpHeaderInfo: LPWSTR, + dwHeaderInfoSize: DWORD, + lpszFileExtension: LPWSTR, + u: INTERNET_CACHE_ENTRY_INFOW_u, +}} +pub type LPINTERNET_CACHE_ENTRY_INFOW = *mut INTERNET_CACHE_ENTRY_INFOW; +STRUCT!{struct INTERNET_CACHE_TIMESTAMPS { + ftExpires: FILETIME, + ftLastModified: FILETIME, +}} +pub type LPINTERNET_CACHE_TIMESTAMPS = *mut INTERNET_CACHE_TIMESTAMPS; +pub type GROUPID = LONGLONG; +pub const CACHEGROUP_ATTRIBUTE_GET_ALL: DWORD = 0xffffffff; +pub const CACHEGROUP_ATTRIBUTE_BASIC: DWORD = 0x00000001; +pub const CACHEGROUP_ATTRIBUTE_FLAG: DWORD = 0x00000002; +pub const CACHEGROUP_ATTRIBUTE_TYPE: DWORD = 0x00000004; +pub const CACHEGROUP_ATTRIBUTE_QUOTA: DWORD = 0x00000008; +pub const CACHEGROUP_ATTRIBUTE_GROUPNAME: DWORD = 0x00000010; +pub const CACHEGROUP_ATTRIBUTE_STORAGE: DWORD = 0x00000020; +pub const CACHEGROUP_FLAG_NONPURGEABLE: DWORD = 0x00000001; +pub const CACHEGROUP_FLAG_GIDONLY: DWORD = 0x00000004; +pub const CACHEGROUP_FLAG_FLUSHURL_ONDELETE: DWORD = 0x00000002; +pub const CACHEGROUP_SEARCH_ALL: DWORD = 0x00000000; +pub const CACHEGROUP_SEARCH_BYURL: DWORD = 0x00000001; +pub const CACHEGROUP_TYPE_INVALID: DWORD = 0x00000001; +pub const CACHEGROUP_READWRITE_MASK: DWORD = CACHEGROUP_ATTRIBUTE_TYPE + | CACHEGROUP_ATTRIBUTE_QUOTA | CACHEGROUP_ATTRIBUTE_GROUPNAME | CACHEGROUP_ATTRIBUTE_STORAGE; +pub const GROUPNAME_MAX_LENGTH: usize = 120; +pub const GROUP_OWNER_STORAGE_SIZE: usize = 4; +STRUCT!{struct INTERNET_CACHE_GROUP_INFOA { + dwGroupSize: DWORD, + dwGroupFlags: DWORD, + dwGroupType: DWORD, + dwDiskUsage: DWORD, + dwDiskQuota: DWORD, + dwOwnerStorage: [DWORD; GROUP_OWNER_STORAGE_SIZE], + szGroupName: [CHAR; GROUPNAME_MAX_LENGTH], +}} +pub type LPINTERNET_CACHE_GROUP_INFOA = *mut INTERNET_CACHE_GROUP_INFOA; +STRUCT!{struct INTERNET_CACHE_GROUP_INFOW { + dwGroupSize: DWORD, + dwGroupFlags: DWORD, + dwGroupType: DWORD, + dwDiskUsage: DWORD, + dwDiskQuota: DWORD, + dwOwnerStorage: [DWORD; GROUP_OWNER_STORAGE_SIZE], + szGroupName: [WCHAR; GROUPNAME_MAX_LENGTH], +}} +pub type LPINTERNET_CACHE_GROUP_INFOW = *mut INTERNET_CACHE_GROUP_INFOW; +pub const CACHE_ENTRY_ATTRIBUTE_FC: DWORD = 0x00000004; +pub const CACHE_ENTRY_HITRATE_FC: DWORD = 0x00000010; +pub const CACHE_ENTRY_MODTIME_FC: DWORD = 0x00000040; +pub const CACHE_ENTRY_EXPTIME_FC: DWORD = 0x00000080; +pub const CACHE_ENTRY_ACCTIME_FC: DWORD = 0x00000100; +pub const CACHE_ENTRY_SYNCTIME_FC: DWORD = 0x00000200; +pub const CACHE_ENTRY_HEADERINFO_FC: DWORD = 0x00000400; +pub const CACHE_ENTRY_EXEMPT_DELTA_FC: DWORD = 0x00000800; +pub const INTERNET_CACHE_GROUP_ADD: DWORD = 0; +pub const INTERNET_CACHE_GROUP_REMOVE: DWORD = 1; +pub const INTERNET_DIAL_FORCE_PROMPT: DWORD = 0x2000; +pub const INTERNET_DIAL_SHOW_OFFLINE: DWORD = 0x4000; +pub const INTERNET_DIAL_UNATTENDED: DWORD = 0x8000; +pub const INTERENT_GOONLINE_REFRESH: DWORD = 0x00000001; +pub const INTERENT_GOONLINE_NOPROMPT: DWORD = 0x00000002; +pub const INTERENT_GOONLINE_MASK: DWORD = 0x00000003; +pub const INTERNET_AUTODIAL_FORCE_ONLINE: DWORD = 1; +pub const INTERNET_AUTODIAL_FORCE_UNATTENDED: DWORD = 2; +pub const INTERNET_AUTODIAL_FAILIFSECURITYCHECK: DWORD = 4; +pub const INTERNET_AUTODIAL_OVERRIDE_NET_PRESENT: DWORD = 8; +pub const INTERNET_AUTODIAL_FLAGS_MASK: DWORD = INTERNET_AUTODIAL_FORCE_ONLINE + | INTERNET_AUTODIAL_FORCE_UNATTENDED | INTERNET_AUTODIAL_FAILIFSECURITYCHECK + | INTERNET_AUTODIAL_OVERRIDE_NET_PRESENT; +pub const PROXY_AUTO_DETECT_TYPE_DHCP: DWORD = 1; +pub const PROXY_AUTO_DETECT_TYPE_DNS_A: DWORD = 2; +STRUCT!{struct AutoProxyHelperVtbl { + IsResolvable: Option<unsafe extern "system" fn( + lpszHost: LPSTR, + ) -> BOOL>, + GetIPAddress: Option<unsafe extern "system" fn( + lpszIPAddress: LPSTR, + lpdwIPAddressSize: LPDWORD, + ) -> DWORD>, + ResolveHostName: Option<unsafe extern "system" fn( + lpszHostName: LPSTR, + lpszIPAddress: LPSTR, + lpdwIPAddressSize: LPDWORD, + ) -> DWORD>, + IsInNet: Option<unsafe extern "system" fn( + lpszIPAddress: LPSTR, + lpszDest: LPSTR, + lpszMask: LPSTR, + ) -> BOOL>, + IsResolvableEx: Option<unsafe extern "system" fn( + lpszHost: LPSTR, + ) -> BOOL>, + GetIPAddressEx: Option<unsafe extern "system" fn( + lpszIPAddress: LPSTR, + lpdwIPAddressSize: LPDWORD, + ) -> DWORD>, + ResolveHostNameEx: Option<unsafe extern "system" fn( + lpszHostName: LPSTR, + lpszIPAddress: LPSTR, + lpdwIPAddressSize: LPDWORD, + ) -> DWORD>, + IsInNetEx: Option<unsafe extern "system" fn( + lpszIPAddress: LPSTR, + lpszIPPrefix: LPSTR, + ) -> BOOL>, + SortIpList: Option<unsafe extern "system" fn( + lpszIPAddressList: LPSTR, + lpszIPSortedList: LPSTR, + lpdwIPSortedListSize: LPDWORD, + ) -> DWORD>, +}} +STRUCT!{struct AUTO_PROXY_SCRIPT_BUFFER { + dwStructSize: DWORD, + lpszScriptBuffer: LPSTR, + dwScriptBufferSize: DWORD, +}} +pub type LPAUTO_PROXY_SCRIPT_BUFFER = *mut AUTO_PROXY_SCRIPT_BUFFER; +STRUCT!{struct AutoProxyHelperFunctions { + lpVtbl: *const AutoProxyHelperVtbl, +}} +FN!{stdcall pfnInternetInitializeAutoProxyDll( + DWORD, + LPSTR, + LPSTR, + *mut AutoProxyHelperFunctions, + LPAUTO_PROXY_SCRIPT_BUFFER, +) -> BOOL} +FN!{stdcall pfnInternetDeInitializeAutoProxyDll( + LPSTR, + DWORD, +) -> BOOL} +FN!{stdcall pfnInternetGetProxyInfo( + LPCSTR, + DWORD, + LPSTR, + DWORD, + *mut LPSTR, + LPDWORD, +) -> BOOL} +ENUM!{enum WPAD_CACHE_DELETE { + WPAD_CACHE_DELETE_CURRENT = 0x0, + WPAD_CACHE_DELETE_ALL = 0x1, +}} +pub const INTERNET_CONNECTION_MODEM: DWORD = 0x01; +pub const INTERNET_CONNECTION_LAN: DWORD = 0x02; +pub const INTERNET_CONNECTION_PROXY: DWORD = 0x04; +pub const INTERNET_CONNECTION_MODEM_BUSY: DWORD = 0x08; +pub const INTERNET_RAS_INSTALLED: DWORD = 0x10; +pub const INTERNET_CONNECTION_OFFLINE: DWORD = 0x20; +pub const INTERNET_CONNECTION_CONFIGURED: DWORD = 0x40; +FN!{stdcall PFN_DIAL_HANDLER( + HWND, + LPCSTR, + DWORD, + LPDWORD, +) -> DWORD} +pub const INTERNET_CUSTOMDIAL_CONNECT: DWORD = 0; +pub const INTERNET_CUSTOMDIAL_UNATTENDED: DWORD = 1; +pub const INTERNET_CUSTOMDIAL_DISCONNECT: DWORD = 2; +pub const INTERNET_CUSTOMDIAL_SHOWOFFLINE: DWORD = 4; +pub const INTERNET_CUSTOMDIAL_SAFE_FOR_UNATTENDED: DWORD = 1; +pub const INTERNET_CUSTOMDIAL_WILL_SUPPLY_STATE: DWORD = 2; +pub const INTERNET_CUSTOMDIAL_CAN_HANGUP: DWORD = 4; +pub const INTERNET_DIALSTATE_DISCONNECTED: DWORD = 1; +pub const INTERNET_IDENTITY_FLAG_PRIVATE_CACHE: DWORD = 0x01; +pub const INTERNET_IDENTITY_FLAG_SHARED_CACHE: DWORD = 0x02; +pub const INTERNET_IDENTITY_FLAG_CLEAR_DATA: DWORD = 0x04; +pub const INTERNET_IDENTITY_FLAG_CLEAR_COOKIES: DWORD = 0x08; +pub const INTERNET_IDENTITY_FLAG_CLEAR_HISTORY: DWORD = 0x10; +pub const INTERNET_IDENTITY_FLAG_CLEAR_CONTENT: DWORD = 0x20; +pub const INTERNET_SUPPRESS_RESET_ALL: DWORD = 0x00; +pub const INTERNET_SUPPRESS_COOKIE_POLICY: DWORD = 0x01; +pub const INTERNET_SUPPRESS_COOKIE_POLICY_RESET: DWORD = 0x02; +pub const PRIVACY_TEMPLATE_NO_COOKIES: DWORD = 0; +pub const PRIVACY_TEMPLATE_HIGH: DWORD = 1; +pub const PRIVACY_TEMPLATE_MEDIUM_HIGH: DWORD = 2; +pub const PRIVACY_TEMPLATE_MEDIUM: DWORD = 3; +pub const PRIVACY_TEMPLATE_MEDIUM_LOW: DWORD = 4; +pub const PRIVACY_TEMPLATE_LOW: DWORD = 5; +pub const PRIVACY_TEMPLATE_CUSTOM: DWORD = 100; +pub const PRIVACY_TEMPLATE_ADVANCED: DWORD = 101; +pub const PRIVACY_TEMPLATE_MAX: DWORD = PRIVACY_TEMPLATE_LOW; +pub const PRIVACY_TYPE_FIRST_PARTY: DWORD = 0; +pub const PRIVACY_TYPE_THIRD_PARTY: DWORD = 1; +extern "system" { + pub fn CommitUrlCacheEntryA( + lpszUrlName: LPCSTR, + lpszLocalFileName: LPCSTR, + ExpireTime: FILETIME, + LastModifiedTime: FILETIME, + CacheEntryType: DWORD, + lpHeaderInfo: LPBYTE, + cchHeaderInfo: DWORD, + lpszFileExtension: LPCSTR, + lpszOriginalUrl: LPCSTR, + ) -> BOOL; + pub fn CommitUrlCacheEntryW( + lpszUrlName: LPCWSTR, + lpszLocalFileName: LPCWSTR, + ExpireTime: FILETIME, + LastModifiedTime: FILETIME, + CacheEntryType: DWORD, + lpszHeaderInfo: LPWSTR, + cchHeaderInfo: DWORD, + lpszFileExtension: LPCWSTR, + lpszOriginalUrl: LPCWSTR, + ) -> BOOL; + pub fn CreateMD5SSOHash ( + pszChallengeInfo: PWSTR, + pwszRealm: PWSTR, + pwszTarget: PWSTR, + pbHexHash: PBYTE, + ) -> BOOL; + pub fn CreateUrlCacheEntryA( + lpszUrlName: LPCSTR, + dwExpectedFileSize: DWORD, + lpszFileExtension: LPCSTR, + lpszFileName: LPSTR, + dwReserved: DWORD, + ) -> BOOL; + pub fn CreateUrlCacheEntryW( + lpszUrlName: LPCWSTR, + dwExpectedFileSize: DWORD, + lpszFileExtension: LPCWSTR, + lpszFileName: LPWSTR, + dwReserved: DWORD, + ) -> BOOL; + pub fn CreateUrlCacheGroup( + dwFlags: DWORD, + lpReserved: LPVOID, + ) -> GROUPID; + pub fn DeleteUrlCacheEntryA( + lpszUrlName: LPCSTR, + ) -> BOOL; + pub fn DeleteUrlCacheEntryW( + lpszUrlName: LPCWSTR, + ) -> BOOL; + pub fn DeleteUrlCacheGroup( + GroupId: GROUPID, + dwFlags: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn DeleteWpadCacheForNetworks( + arg0: WPAD_CACHE_DELETE, + ) -> BOOL; + pub fn DetectAutoProxyUrl( + pszAutoProxyUrl: PSTR, + cchAutoProxyUrl: DWORD, + dwDetectFlags: DWORD, + ) -> BOOL; + pub fn FindCloseUrlCache( + hEnumHandle: HANDLE, + ) -> BOOL; + pub fn FindFirstUrlCacheEntryA( + lpszUrlSearchPattern: LPCSTR, + lpFirstCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + ) -> HANDLE; + pub fn FindFirstUrlCacheEntryExA( + lpszUrlSearchPattern: LPCSTR, + dwFlags: DWORD, + dwFilter: DWORD, + GroupId: GROUPID, + lpFirstCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + lpGroupAttributes: LPVOID, + lpcbGroupAttributes: LPDWORD, + lpReserved: LPVOID, + ) -> HANDLE; + pub fn FindFirstUrlCacheEntryExW( + lpszUrlSearchPattern: LPCWSTR, + dwFlags: DWORD, + dwFilter: DWORD, + GroupId: GROUPID, + lpFirstCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + lpGroupAttributes: LPVOID, + lpcbGroupAttributes: LPDWORD, + lpReserved: LPVOID, + ) -> HANDLE; + pub fn FindFirstUrlCacheEntryW( + lpszUrlSearchPattern: LPCWSTR, + lpFirstCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + ) -> HANDLE; + pub fn FindFirstUrlCacheGroup( + dwFlags: DWORD, + dwFilter: DWORD, + lpSearchCondition: LPVOID, + dwSearchCondition: DWORD, + lpGroupId: *mut GROUPID, + lpReserved: LPVOID, + ) -> HANDLE; + pub fn FindNextUrlCacheEntryA( + hEnumHandle: HANDLE, + lpNextCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + ) -> BOOL; + pub fn FindNextUrlCacheEntryExA( + hEnumHandle: HANDLE, + lpNextCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + lpGroupAttributes: LPVOID, + lpcbGroupAttributes: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn FindNextUrlCacheEntryExW( + hEnumHandle: HANDLE, + lpNextCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + lpGroupAttributes: LPVOID, + lpcbGroupAttributes: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn FindNextUrlCacheEntryW( + hEnumHandle: HANDLE, + lpNextCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + ) -> BOOL; + pub fn FindNextUrlCacheGroup( + hFind: HANDLE, + lpGroupId: *mut GROUPID, + lpReserved: LPVOID, + ) -> BOOL; + pub fn FtpCommandA( + hConnect: HINTERNET, + fExpectResponse: BOOL, + dwFlags: DWORD, + lpszCommand: LPCSTR, + dwContext: DWORD_PTR, + phFtpCommand: *mut HINTERNET, + ) -> BOOL; + pub fn FtpCommandW( + hConnect: HINTERNET, + fExpectResponse: BOOL, + dwFlags: DWORD, + lpszCommand: LPCWSTR, + dwContext: DWORD_PTR, + phFtpCommand: *mut HINTERNET, + ) -> BOOL; + pub fn FtpCreateDirectoryA( + hConnect: HINTERNET, + lpszDirectory: LPCSTR, + ) -> BOOL; + pub fn FtpCreateDirectoryW( + hConnect: HINTERNET, + lpszDirectory: LPCWSTR, + ) -> BOOL; + pub fn FtpDeleteFileA( + hConnect: HINTERNET, + lpszFileName: LPCSTR, + ) -> BOOL; + pub fn FtpDeleteFileW( + hConnect: HINTERNET, + lpszFileName: LPCWSTR, + ) -> BOOL; + pub fn FtpFindFirstFileA( + hConnect: HINTERNET, + lpszSearchFile: LPCSTR, + lpFindFileData: LPWIN32_FIND_DATAA, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn FtpFindFirstFileW( + hConnect: HINTERNET, + lpszSearchFile: LPCWSTR, + lpFindFileData: LPWIN32_FIND_DATAW, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn FtpGetCurrentDirectoryA( + hConnect: HINTERNET, + lpszCurrentDirectory: LPSTR, + lpdwCurrentDirectory: LPDWORD, + ) -> BOOL; + pub fn FtpGetCurrentDirectoryW( + hConnect: HINTERNET, + lpszCurrentDirectory: LPWSTR, + lpdwCurrentDirectory: LPDWORD, + ) -> BOOL; + pub fn FtpGetFileA( + hConnect: HINTERNET, + lpszRemoteFile: LPCSTR, + lpszNewFile: LPCSTR, + fFailIfExists: BOOL, + dwFlagsAndAttributes: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpGetFileEx( + hFtpSession: HINTERNET, + lpszRemoteFile: LPCSTR, + lpszNewFile: LPCWSTR, + fFailIfExists: BOOL, + dwFlagsAndAttributes: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpGetFileSize( + hFile: HINTERNET, + lpdwFileSizeHigh: LPDWORD, + ) -> DWORD; + pub fn FtpGetFileW( + hConnect: HINTERNET, + lpszRemoteFile: LPCWSTR, + lpszNewFile: LPCWSTR, + fFailIfExists: BOOL, + dwFlagsAndAttributes: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpOpenFileA( + hConnect: HINTERNET, + lpszFileName: LPCSTR, + dwAccess: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn FtpOpenFileW( + hConnect: HINTERNET, + lpszFileName: LPCWSTR, + dwAccess: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn FtpPutFileA( + hConnect: HINTERNET, + lpszLocalFile: LPCSTR, + lpszNewRemoteFile: LPCSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpPutFileEx( + hFtpSession: HINTERNET, + lpszLocalFile: LPCWSTR, + lpszNewRemoteFile: LPCSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpPutFileW( + hConnect: HINTERNET, + lpszLocalFile: LPCWSTR, + lpszNewRemoteFile: LPCWSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn FtpRemoveDirectoryA( + hConnect: HINTERNET, + lpszDirectory: LPCSTR, + ) -> BOOL; + pub fn FtpRemoveDirectoryW( + hConnect: HINTERNET, + lpszDirectory: LPCWSTR, + ) -> BOOL; + pub fn FtpRenameFileA( + hConnect: HINTERNET, + lpszExisting: LPCSTR, + lpszNew: LPCSTR, + ) -> BOOL; + pub fn FtpRenameFileW( + hConnect: HINTERNET, + lpszExisting: LPCWSTR, + lpszNew: LPCWSTR, + ) -> BOOL; + pub fn FtpSetCurrentDirectoryA( + hConnect: HINTERNET, + lpszDirectory: LPCSTR, + ) -> BOOL; + pub fn FtpSetCurrentDirectoryW( + hConnect: HINTERNET, + lpszDirectory: LPCWSTR, + ) -> BOOL; + pub fn GetUrlCacheEntryInfoA( + lpszUrlName: LPCSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + ) -> BOOL; + pub fn GetUrlCacheEntryInfoExA( + lpszUrl: LPCSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + lpszRedirectUrl: LPSTR, + lpcbRedirectUrl: LPDWORD, + lpReserved: LPVOID, + dwFlags: DWORD, + ) -> BOOL; + pub fn GetUrlCacheEntryInfoExW( + lpszUrl: LPCWSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + lpszRedirectUrl: LPWSTR, + lpcbRedirectUrl: LPDWORD, + lpReserved: LPVOID, + dwFlags: DWORD, + ) -> BOOL; + pub fn GetUrlCacheEntryInfoW( + lpszUrlName: LPCWSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + ) -> BOOL; + pub fn GetUrlCacheGroupAttributeA( + gid: GROUPID, + dwFlags: DWORD, + dwAttributes: DWORD, + lpGroupInfo: LPINTERNET_CACHE_GROUP_INFOA, + lpcbGroupInfo: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn GetUrlCacheGroupAttributeW( + gid: GROUPID, + dwFlags: DWORD, + dwAttributes: DWORD, + lpGroupInfo: LPINTERNET_CACHE_GROUP_INFOW, + lpcbGroupInfo: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn GopherCreateLocatorA( + lpszHost: LPCSTR, + nServerPort: INTERNET_PORT, + lpszDisplayString: LPCSTR, + lpszSelectorString: LPCSTR, + dwGopherType: DWORD, + lpszLocator: LPSTR, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn GopherCreateLocatorW( + lpszHost: LPCWSTR, + nServerPort: INTERNET_PORT, + lpszDisplayString: LPCWSTR, + lpszSelectorString: LPCWSTR, + dwGopherType: DWORD, + lpszLocator: LPWSTR, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn GopherFindFirstFileA( + hConnect: HINTERNET, + lpszLocator: LPCSTR, + lpszSearchString: LPCSTR, + lpFindData: LPGOPHER_FIND_DATAA, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn GopherFindFirstFileW( + hConnect: HINTERNET, + lpszLocator: LPCWSTR, + lpszSearchString: LPCWSTR, + lpFindData: LPGOPHER_FIND_DATAW, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn GopherGetAttributeA( + hConnect: HINTERNET, + lpszLocator: LPCSTR, + lpszAttributeName: LPCSTR, + lpBuffer: LPBYTE, + dwBufferLength: DWORD, + lpdwCharactersReturned: LPDWORD, + lpfnEnumerator: GOPHER_ATTRIBUTE_ENUMERATOR, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn GopherGetAttributeW( + hConnect: HINTERNET, + lpszLocator: LPCWSTR, + lpszAttributeName: LPCWSTR, + lpBuffer: LPBYTE, + dwBufferLength: DWORD, + lpdwCharactersReturned: LPDWORD, + lpfnEnumerator: GOPHER_ATTRIBUTE_ENUMERATOR, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn GopherGetLocatorTypeA( + lpszLocator: LPCSTR, + lpdwGopherType: LPDWORD, + ) -> BOOL; + pub fn GopherGetLocatorTypeW( + lpszLocator: LPCWSTR, + lpdwGopherType: LPDWORD, + ) -> BOOL; + pub fn GopherOpenFileA( + hConnect: HINTERNET, + lpszLocator: LPCSTR, + lpszView: LPCSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn GopherOpenFileW( + hConnect: HINTERNET, + lpszLocator: LPCWSTR, + lpszView: LPCWSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn HttpAddRequestHeadersA( + hRequest: HINTERNET, + lpszHeaders: LPCSTR, + dwHeadersLength: DWORD, + dwModifiers: DWORD, + ) -> BOOL; + pub fn HttpAddRequestHeadersW( + hRequest: HINTERNET, + lpszHeaders: LPCWSTR, + dwHeadersLength: DWORD, + dwModifiers: DWORD, + ) -> BOOL; + pub fn HttpEndRequestA( + hRequest: HINTERNET, + lpBuffersOut: LPINTERNET_BUFFERSA, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn HttpEndRequestW( + hRequest: HINTERNET, + lpBuffersOut: LPINTERNET_BUFFERSW, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn HttpOpenRequestA( + hConnect: HINTERNET, + lpszVerb: LPCSTR, + lpszObjectName: LPCSTR, + lpszVersion: LPCSTR, + lpszReferrer: LPCSTR, + lplpszAcceptTypes: *mut LPCSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn HttpOpenRequestW( + hConnect: HINTERNET, + lpszVerb: LPCWSTR, + lpszObjectName: LPCWSTR, + lpszVersion: LPCWSTR, + lpszReferrer: LPCWSTR, + lplpszAcceptTypes: *mut LPCWSTR, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn HttpQueryInfoA( + hRequest: HINTERNET, + dwInfoLevel: DWORD, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + lpdwIndex: LPDWORD, + ) -> BOOL; + pub fn HttpQueryInfoW( + hRequest: HINTERNET, + dwInfoLevel: DWORD, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + lpdwIndex: LPDWORD, + ) -> BOOL; + pub fn HttpSendRequestA( + hRequest: HINTERNET, + lpszHeaders: LPCSTR, + dwHeadersLength: DWORD, + lpOptional: LPVOID, + dwOptionalLength: DWORD, + ) -> BOOL; + pub fn HttpSendRequestExA( + hRequest: HINTERNET, + lpBuffersIn: LPINTERNET_BUFFERSA, + lpBuffersOut: LPINTERNET_BUFFERSA, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn HttpSendRequestExW( + hRequest: HINTERNET, + lpBuffersIn: LPINTERNET_BUFFERSW, + lpBuffersOut: LPINTERNET_BUFFERSW, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn HttpSendRequestW( + hRequest: HINTERNET, + lpszHeaders: LPCWSTR, + dwHeadersLength: DWORD, + lpOptional: LPVOID, + dwOptionalLength: DWORD, + ) -> BOOL; + pub fn InternetAttemptConnect( + dwReserved: DWORD, + ) -> DWORD; + pub fn InternetAutodial( + dwFlags: DWORD, + hwndParent: HWND, + ) -> BOOL; + pub fn InternetAutodialHangup( + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetCanonicalizeUrlA( + lpszUrl: LPCSTR, + lpszBuffer: LPSTR, + lpdwBufferLength: LPDWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetCanonicalizeUrlW( + lpszUrl: LPCWSTR, + lpszBuffer: LPWSTR, + lpdwBufferLength: LPDWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetCheckConnectionA( + lpszUrl: LPCSTR, + dwFlags: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetCheckConnectionW( + lpszUrl: LPCWSTR, + dwFlags: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetClearAllPerSiteCookieDecisions() -> BOOL; + pub fn InternetCloseHandle( + hInternet: HINTERNET, + ) -> BOOL; + pub fn InternetCombineUrlA( + lpszBaseUrl: LPCSTR, + lpszRelativeUrl: LPCSTR, + lpszBuffer: LPSTR, + lpdwBufferLength: LPDWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetCombineUrlW( + lpszBaseUrl: LPCWSTR, + lpszRelativeUrl: LPCWSTR, + lpszBuffer: LPWSTR, + lpdwBufferLength: LPDWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetConfirmZoneCrossingA( + hWnd: HWND, + szUrlPrev: LPSTR, + szUrlNew: LPSTR, + bPost: BOOL, + ) -> DWORD; + pub fn InternetConfirmZoneCrossingW( + hWnd: HWND, + szUrlPrev: LPWSTR, + szUrlNew: LPWSTR, + bPost: BOOL, + ) -> DWORD; + pub fn InternetConnectA( + hInternet: HINTERNET, + lpszServerName: LPCSTR, + nServerPort: INTERNET_PORT, + lpszUserName: LPCSTR, + lpszPassword: LPCSTR, + dwService: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn InternetConnectW( + hInternet: HINTERNET, + lpszServerName: LPCWSTR, + nServerPort: INTERNET_PORT, + lpszUserName: LPCWSTR, + lpszPassword: LPCWSTR, + dwService: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn InternetCrackUrlA( + lpszUrl: LPCSTR, + dwUrlLength: DWORD, + dwFlags: DWORD, + lpUrlComponents: LPURL_COMPONENTSA, + ) -> BOOL; + pub fn InternetCrackUrlW( + lpszUrl: LPCWSTR, + dwUrlLength: DWORD, + dwFlags: DWORD, + lpUrlComponents: LPURL_COMPONENTSW, + ) -> BOOL; + pub fn InternetCreateUrlA( + lpUrlComponents: LPURL_COMPONENTSA, + dwFlags: DWORD, + lpszUrl: LPSTR, + lpdwUrlLength: LPDWORD, + ) -> BOOL; + pub fn InternetCreateUrlW( + lpUrlComponents: LPURL_COMPONENTSW, + dwFlags: DWORD, + lpszUrl: LPWSTR, + lpdwUrlLength: LPDWORD, + ) -> BOOL; + pub fn InternetDialA( + hwndParent: HWND, + lpszConnectoid: LPSTR, + dwFlags: DWORD, + lpdwConnection: *mut DWORD_PTR, + dwReserved: DWORD, + ) -> DWORD; + pub fn InternetDialW( + hwndParent: HWND, + lpszConnectoid: LPWSTR, + dwFlags: DWORD, + lpdwConnection: *mut DWORD_PTR, + dwReserved: DWORD, + ) -> DWORD; + pub fn InternetEnumPerSiteCookieDecisionA( + pszSiteName: LPSTR, + pcSiteNameSize: *mut u32, + pdwDecision: *mut u32, + dwIndex: u32, + ) -> BOOL; + pub fn InternetEnumPerSiteCookieDecisionW( + pszSiteName: LPWSTR, + pcSiteNameSize: *mut u32, + pdwDecision: *mut u32, + dwIndex: u32, + ) -> BOOL; + pub fn InternetErrorDlg( + hWnd: HWND, + hRequest: HINTERNET, + dwError: DWORD, + dwFlags: DWORD, + lppvData: *mut LPVOID, + ) -> DWORD; + pub fn InternetFindNextFileA( + hFind: HINTERNET, + lpvFindData: LPVOID, + ) -> BOOL; + pub fn InternetFindNextFileW( + hFind: HINTERNET, + lpvFindData: LPVOID, + ) -> BOOL; + pub fn InternetFreeCookies( + pCookies: *mut INTERNET_COOKIE2, + dwCookieCount: DWORD, + ) -> (); + pub fn InternetGetConnectedState( + lpdwFlags: LPDWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetGetConnectedStateExA( + lpdwFlags: LPDWORD, + lpszConnectionName: LPSTR, + cchNameLen: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetGetConnectedStateExW( + lpdwFlags: LPDWORD, + lpszConnectionName: LPWSTR, + cchNameLen: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetGetCookieA( + lpszUrl: LPCSTR, + lpszCookieName: LPCSTR, + lpszCookieData: LPSTR, + lpdwSize: LPDWORD, + ) -> BOOL; + pub fn InternetGetCookieEx2( + pcwszUrl: PCWSTR, + pcwszCookieName: PCWSTR, + dwFlags: DWORD, + ppCookies: *mut *mut INTERNET_COOKIE2, + pdwCookieCount: PDWORD, + ) -> DWORD; + pub fn InternetGetCookieExA( + lpszUrl: LPCSTR, + lpszCookieName: LPCSTR, + lpszCookieData: LPSTR, + lpdwSize: LPDWORD, + dwFlags: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn InternetGetCookieExW( + lpszUrl: LPCWSTR, + lpszCookieName: LPCWSTR, + lpszCookieData: LPWSTR, + lpdwSize: LPDWORD, + dwFlags: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn InternetGetCookieW( + lpszUrl: LPCWSTR, + lpszCookieName: LPCWSTR, + lpszCookieData: LPWSTR, + lpdwSize: LPDWORD, + ) -> BOOL; + pub fn InternetGetLastResponseInfoA( + lpdwError: LPDWORD, + lpszBuffer: LPSTR, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn InternetGetLastResponseInfoW( + lpdwError: LPDWORD, + lpszBuffer: LPWSTR, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn InternetGetPerSiteCookieDecisionA( + pchHostName: LPCSTR, + pResult: *mut u32, + ) -> BOOL; + pub fn InternetGetPerSiteCookieDecisionW( + pchHostName: LPCWSTR, + pResult: *mut u32, + ) -> BOOL; + pub fn InternetGoOnlineA( + lpszURL: LPCSTR, + hwndParent: HWND, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetGoOnlineW( + lpszURL: LPCWSTR, + hwndParent: HWND, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetHangUp( + dwConnection: DWORD_PTR, + dwReserved: DWORD, + ) -> DWORD; + pub fn InternetInitializeAutoProxyDll( + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetLockRequestFile( + hInternet: HINTERNET, + lphLockRequestInfo: *mut HANDLE, + ) -> BOOL; + pub fn InternetOpenA( + lpszAgent: LPCSTR, + dwAccessType: DWORD, + lpszProxy: LPCSTR, + lpszProxyBypass: LPCSTR, + dwFlags: DWORD, + ) -> HINTERNET; + pub fn InternetOpenUrlA( + hInternet: HINTERNET, + lpszUrl: LPCSTR, + lpszHeaders: LPCSTR, + dwHeadersLength: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn InternetOpenUrlW( + hInternet: HINTERNET, + lpszUrl: LPCWSTR, + lpszHeaders: LPCWSTR, + dwHeadersLength: DWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> HINTERNET; + pub fn InternetOpenW( + lpszAgent: LPCWSTR, + dwAccessType: DWORD, + lpszProxy: LPCWSTR, + lpszProxyBypass: LPCWSTR, + dwFlags: DWORD, + ) -> HINTERNET; + pub fn InternetQueryDataAvailable( + hFile: HINTERNET, + lpdwNumberOfBytesAvailable: LPDWORD, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn InternetQueryOptionA( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn InternetQueryOptionW( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + lpdwBufferLength: LPDWORD, + ) -> BOOL; + pub fn InternetReadFile( + hFile: HINTERNET, + lpBuffer: LPVOID, + dwNumberOfBytesToRead: DWORD, + lpdwNumberOfBytesRead: LPDWORD, + ) -> BOOL; + pub fn InternetReadFileExA( + hFile: HINTERNET, + lpBuffersOut: LPINTERNET_BUFFERSA, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn InternetReadFileExW( + hFile: HINTERNET, + lpBuffersOut: LPINTERNET_BUFFERSW, + dwFlags: DWORD, + dwContext: DWORD_PTR, + ) -> BOOL; + pub fn InternetSetCookieA( + lpszUrl: LPCSTR, + lpszCookieName: LPCSTR, + lpszCookieData: LPCSTR, + ) -> BOOL; + pub fn InternetSetCookieEx2( + pcwszUrl: PCWSTR, + pCookie: *const INTERNET_COOKIE2, + pcwszP3PPolicy: PCWSTR, + dwFlags: DWORD, + pdwCookieState: PDWORD, + ) -> DWORD; + pub fn InternetSetCookieExA( + lpszUrl: LPCSTR, + lpszCookieName: LPCSTR, + lpszCookieData: LPCSTR, + dwFlags: DWORD, + dwReserved: DWORD_PTR, + ) -> DWORD; + pub fn InternetSetCookieExW( + lpszUrl: LPCWSTR, + lpszCookieName: LPCWSTR, + lpszCookieData: LPCWSTR, + dwFlags: DWORD, + dwReserved: DWORD_PTR, + ) -> DWORD; + pub fn InternetSetCookieW( + lpszUrl: LPCWSTR, + lpszCookieName: LPCWSTR, + lpszCookieData: LPCWSTR, + ) -> BOOL; + pub fn InternetSetDialStateA( + lpszConnectoid: LPCSTR, + dwState: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetSetDialStateW( + lpszConnectoid: LPCWSTR, + dwState: DWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetSetFilePointer( + hFile: HINTERNET, + lDistanceToMove: LONG, + lpDistanceToMoveHigh: PLONG, + dwMoveMethod: DWORD, + dwContext: DWORD_PTR, + ) -> DWORD; + pub fn InternetSetOptionA( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + dwBufferLength: DWORD, + ) -> BOOL; + pub fn InternetSetOptionExA( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + dwBufferLength: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetSetOptionExW( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + dwBufferLength: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn InternetSetOptionW( + hInternet: HINTERNET, + dwOption: DWORD, + lpBuffer: LPVOID, + dwBufferLength: DWORD, + ) -> BOOL; + pub fn InternetSetPerSiteCookieDecisionA( + pchHostName: LPCSTR, + dwDecision: DWORD, + ) -> BOOL; + pub fn InternetSetPerSiteCookieDecisionW( + pchHostName: LPCWSTR, + dwDecision: DWORD, + ) -> BOOL; + pub fn InternetSetStatusCallbackA( + hInternet: HINTERNET, + lpfnInternetCallback: INTERNET_STATUS_CALLBACK, + ) -> INTERNET_STATUS_CALLBACK; + pub fn InternetSetStatusCallbackW( + hInternet: HINTERNET, + lpfnInternetCallback: INTERNET_STATUS_CALLBACK, + ) -> INTERNET_STATUS_CALLBACK; + pub fn InternetTimeFromSystemTimeA( + pst: *const SYSTEMTIME, + dwRFC: DWORD, + lpszTime: LPSTR, + cbTime: DWORD, + ) -> BOOL; + pub fn InternetTimeFromSystemTimeW( + pst: *const SYSTEMTIME, + dwRFC: DWORD, + lpszTime: LPWSTR, + cbTime: DWORD, + ) -> BOOL; + pub fn InternetTimeToSystemTimeA( + lpszTime: LPCSTR, + pst: *mut SYSTEMTIME, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetTimeToSystemTimeW( + lpszTime: LPCWSTR, + pst: *mut SYSTEMTIME, + dwReserved: DWORD, + ) -> BOOL; + pub fn InternetUnlockRequestFile( + hLockRequestInfo: HANDLE, + ) -> BOOL; + pub fn InternetWriteFile( + hFile: HINTERNET, + lpBuffer: LPCVOID, + dwNumberOfBytesToWrite: DWORD, + lpdwNumberOfBytesWritten: LPDWORD, + ) -> BOOL; + pub fn PrivacyGetZonePreferenceW( + dwZone: DWORD, + dwType: DWORD, + pdwTemplate: LPDWORD, + pszBuffer: LPWSTR, + pdwBufferLength: LPDWORD, + ) -> DWORD; + pub fn PrivacySetZonePreferenceW( + dwZone: DWORD, + dwType: DWORD, + dwTemplate: DWORD, + pszPreference: LPCWSTR, + ) -> DWORD; + pub fn ReadUrlCacheEntryStream( + hUrlCacheStream: HANDLE, + dwLocation: DWORD, + lpBuffer: LPVOID, + lpdwLen: LPDWORD, + Reserved: DWORD, + ) -> BOOL; + pub fn ReadUrlCacheEntryStreamEx( + hUrlCacheStream: HANDLE, + qwLocation: DWORDLONG, + lpBuffer: LPVOID, + lpdwLen: LPDWORD, + ) -> BOOL; + pub fn ResumeSuspendedDownload( + hRequest: HINTERNET, + dwResultCode: DWORD, + ) -> BOOL; + pub fn RetrieveUrlCacheEntryFileA( + lpszUrlName: LPCSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn RetrieveUrlCacheEntryFileW( + lpszUrlName: LPCWSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + dwReserved: DWORD, + ) -> BOOL; + pub fn RetrieveUrlCacheEntryStreamA( + lpszUrlName: LPCSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + lpcbCacheEntryInfo: LPDWORD, + fRandomRead: BOOL, + dwReserved: DWORD, + ) -> HANDLE; + pub fn RetrieveUrlCacheEntryStreamW( + lpszUrlName: LPCWSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + lpcbCacheEntryInfo: LPDWORD, + fRandomRead: BOOL, + dwReserved: DWORD, + ) -> HANDLE; + pub fn SetUrlCacheEntryGroupA( + lpszUrlName: LPCSTR, + dwFlags: DWORD, + GroupId: GROUPID, + pbGroupAttributes: LPBYTE, + cbGroupAttributes: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SetUrlCacheEntryGroupW( + lpszUrlName: LPCWSTR, + dwFlags: DWORD, + GroupId: GROUPID, + pbGroupAttributes: LPBYTE, + cbGroupAttributes: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SetUrlCacheEntryInfoA( + lpszUrlName: LPCSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOA, + dwFieldControl: DWORD, + ) -> BOOL; + pub fn SetUrlCacheEntryInfoW( + lpszUrlName: LPCWSTR, + lpCacheEntryInfo: LPINTERNET_CACHE_ENTRY_INFOW, + dwFieldControl: DWORD, + ) -> BOOL; + pub fn SetUrlCacheGroupAttributeA( + gid: GROUPID, + dwFlags: DWORD, + dwAttributes: DWORD, + lpGroupInfo: LPINTERNET_CACHE_GROUP_INFOA, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SetUrlCacheGroupAttributeW( + gid: GROUPID, + dwFlags: DWORD, + dwAttributes: DWORD, + lpGroupInfo: LPINTERNET_CACHE_GROUP_INFOW, + lpReserved: LPVOID, + ) -> BOOL; + pub fn UnlockUrlCacheEntryFileA( + lpszUrlName: LPCSTR, + dwReserved: DWORD, + ) -> BOOL; + pub fn UnlockUrlCacheEntryFileW( + lpszUrlName: LPCWSTR, + dwReserved: DWORD, + ) -> BOOL; + pub fn UnlockUrlCacheEntryStream( + hUrlCacheStream: HANDLE, + Reserved: DWORD, + ) -> BOOL; +} diff --git a/winapi/src/um/winineti.rs b/winapi/src/um/winineti.rs new file mode 100644 index 000000000..c0076c0d0 --- /dev/null +++ b/winapi/src/um/winineti.rs @@ -0,0 +1,142 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Windows Internet Services API procedure declarations, types and constants. +// Currently, this only contains `INTERNET_FLAG_BGUPDATE`, which is needed to correctly define +// `wininet::INTERNET_FLAGS_MASK`. +use shared::minwindef::DWORD; +pub const INTERNET_FLAG_BGUPDATE: DWORD = 0x00000008; +// Functions from wininet.dll that *should* be in this header. +// pub fn AppCacheCheckManifest(); +// pub fn AppCacheCloseHandle(); +// pub fn AppCacheCreateAndCommitFile(); +// pub fn AppCacheDeleteGroup(); +// pub fn AppCacheDeleteIEGroup(); +// pub fn AppCacheDuplicateHandle(); +// pub fn AppCacheFinalize(); +// pub fn AppCacheFreeDownloadList(); +// pub fn AppCacheFreeGroupList(); +// pub fn AppCacheFreeIESpace(); +// pub fn AppCacheFreeSpace(); +// pub fn AppCacheGetDownloadList(); +// pub fn AppCacheGetFallbackUrl(); +// pub fn AppCacheGetGroupList(); +// pub fn AppCacheGetIEGroupList(); +// pub fn AppCacheGetInfo(); +// pub fn AppCacheGetManifestUrl(); +// pub fn AppCacheLookup(); +// pub fn CommitUrlCacheEntryBinaryBlob(); +// pub fn CreateCacheServerRpcBinding(); +// pub fn CreateUrlCacheContainerA(); +// pub fn CreateUrlCacheContainerW(); +// pub fn CreateUrlCacheEntryExW(); +// pub fn DeleteIE3Cache(); +// pub fn DeleteUrlCacheContainerA(); +// pub fn DeleteUrlCacheContainerW(); +// pub fn DoConnectoidsExist(); +// pub fn ExportCookieFileA(); +// pub fn ExportCookieFileW(); +// pub fn FindFirstUrlCacheContainerA(); +// pub fn FindFirstUrlCacheContainerW(); +// pub fn FindNextUrlCacheContainerA(); +// pub fn FindNextUrlCacheContainerW(); +// pub fn FindP3PPolicySymbol(); +// pub fn ForceNexusLookupExW(); +// pub fn FreeP3PObject(); +// pub fn FreeUrlCacheSpaceA(); +// pub fn FreeUrlCacheSpaceW(); +// pub fn GetCacheServerConnection(); +// pub fn GetDiskInfoA(); +// pub fn GetP3PPolicy(); +// pub fn GetP3PRequestStatus(); +// pub fn GetUrlCacheConfigInfoA(); +// pub fn GetUrlCacheConfigInfoW(); +// pub fn GetUrlCacheEntryBinaryBlob(); +// pub fn GetUrlCacheHeaderData(); +// pub fn HttpCheckDavComplianceA(); +// pub fn HttpCheckDavComplianceW(); +// pub fn HttpCloseDependencyHandle(); +// pub fn HttpDuplicateDependencyHandle(); +// pub fn HttpGetServerCredentials(); +// pub fn HttpGetTunnelSocket(); +// pub fn HttpIsHostHstsEnabled(); +// pub fn HttpOpenDependencyHandle(); +// pub fn HttpPushClose(); +// pub fn HttpPushEnable(); +// pub fn HttpPushWait(); +// pub fn HttpWebSocketClose(); +// pub fn HttpWebSocketCompleteUpgrade(); +// pub fn HttpWebSocketQueryCloseStatus(); +// pub fn HttpWebSocketReceive(); +// pub fn HttpWebSocketSend(); +// pub fn HttpWebSocketShutdown(); +// pub fn ImportCookieFileA(); +// pub fn ImportCookieFileW(); +// pub fn IncrementUrlCacheHeaderData(); +// pub fn InternalInternetGetCookie(); +// pub fn InternetAlgIdToStringA(); +// pub fn InternetAlgIdToStringW(); +// pub fn InternetAutodialCallback(); +// pub fn InternetAutoProxyGetProxyForUrl(); +// pub fn InternetAutoProxyOnSendRequestComplete(); +// pub fn InternetFortezzaCommand(); +// pub fn InternetFreeProxyInfoList(); +// pub fn InternetGetCertByURLA(); +// pub fn InternetGetProxyForUrl(); +// pub fn InternetGetSecurityInfoByURLA(); +// pub fn InternetGetSecurityInfoByURLW(); +// pub fn InternetQueryFortezzaStatus(); +// pub fn InternetSecurityProtocolToStringA(); +// pub fn InternetSecurityProtocolToStringW(); +// pub fn InternetShowSecurityInfoByURLA(); +// pub fn InternetShowSecurityInfoByURLW(); +// pub fn InternetWriteFileExA(); +// pub fn InternetWriteFileExW(); +// pub fn IsDialUpConnection(); +// pub fn IsDomainLegalCookieDomainA(); +// pub fn IsDomainLegalCookieDomainW(); +// pub fn IsHostInProxyBypassList(); +// pub fn IsLanConnection(); +// pub fn IsProfilesEnabled(); +// pub fn IsUrlCacheEntryExpiredA(); +// pub fn IsUrlCacheEntryExpiredW(); +// pub fn LoadUrlCacheContent(); +// pub fn MapResourceToPolicy(); +// pub fn ParseX509EncodedCertificateForListBoxEntry(); +// pub fn PerformOperationOverUrlCacheA(); +// pub fn ReadGuidsForConnectedNetworks(); +// pub fn RegisterForNetworkChangeNotification(); +// pub fn RegisterUrlCacheNotification(); +// pub fn RunOnceUrlCache(); +// pub fn SetGlobalJetParameters(); +// pub fn SetUrlCacheConfigInfoA(); +// pub fn SetUrlCacheConfigInfoW(); +// pub fn SetUrlCacheHeaderData(); +// pub fn ShowCertificate(); +// pub fn ShowClientAuthCerts(); +// pub fn ShowSecurityInfo(); +// pub fn ShowX509EncodedCertificate(); +// pub fn UnRegisterNetworkChangeNotification(); +// pub fn UpdateUrlCacheContentPath(); +// pub fn UrlCacheCheckEntriesExist(); +// pub fn UrlCacheCloseEntryHandle(); +// pub fn UrlCacheContainerSetEntryMaximumAge(); +// pub fn UrlCacheCreateContainer(); +// pub fn UrlCacheFindFirstEntry(); +// pub fn UrlCacheFindNextEntry(); +// pub fn UrlCacheFreeEntryInfo(); +// pub fn UrlCacheFreeGlobalSpace(); +// pub fn UrlCacheGetContentPaths(); +// pub fn UrlCacheGetEntryInfo(); +// pub fn UrlCacheGetGlobalCacheSize(); +// pub fn UrlCacheGetGlobalLimit(); +// pub fn UrlCacheReadEntryStream(); +// pub fn UrlCacheReloadSettings(); +// pub fn UrlCacheRetrieveEntryFile(); +// pub fn UrlCacheRetrieveEntryStream(); +// pub fn UrlCacheServer(); +// pub fn UrlCacheSetGlobalLimit(); +// pub fn UrlCacheUpdateEntryExtraData(); +// pub fn UrlZonesDetach(); diff --git a/winapi/src/um/winioctl.rs b/winapi/src/um/winioctl.rs new file mode 100644 index 000000000..4b57b1ed2 --- /dev/null +++ b/winapi/src/um/winioctl.rs @@ -0,0 +1,1076 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the 32-Bit Windows Device I/O control codes. +use shared::basetsd::DWORD64; +use shared::devpropdef::DEVPROPKEY; +use shared::guiddef::GUID; +use shared::minwindef::{BYTE, DWORD, WORD}; +use um::winnt::{ + ANYSIZE_ARRAY, BOOLEAN, FILE_READ_DATA, FILE_WRITE_DATA, HANDLE, LARGE_INTEGER, WCHAR, +}; +DEFINE_GUID!{GUID_DEVINTERFACE_DISK, + 0x53f56307, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_CDROM, + 0x53f56308, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_PARTITION, + 0x53f5630a, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_TAPE, + 0x53f5630b, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_WRITEONCEDISK, + 0x53f5630c, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_VOLUME, + 0x53f5630d, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_MEDIUMCHANGER, + 0x53f56310, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_FLOPPY, + 0x53f56311, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_CDCHANGER, + 0x53f56312, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_STORAGEPORT, + 0x2accfe60, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} +DEFINE_GUID!{GUID_DEVINTERFACE_VMLUN, + 0x6f416619, 0x9f29, 0x42a5, 0xb2, 0x0b, 0x37, 0xe2, 0x19, 0xca, 0x02, 0xb0} +DEFINE_GUID!{GUID_DEVINTERFACE_SES, + 0x1790c9ec, 0x47d5, 0x4df3, 0xb5, 0xaf, 0x9a, 0xdf, 0x3c, 0xf2, 0x3e, 0x48} +DEFINE_GUID!{WDI_STORAGE_PREDICT_FAILURE_DPS_GUID, + 0xe9f2d03a, 0x747c, 0x41c2, 0xbb, 0x9a, 0x02, 0xc6, 0x2b, 0x6d, 0x5f, 0xcb} +DEFINE_GUID!{GUID_DEVINTERFACE_SERVICE_VOLUME, + 0x6ead3d82, 0x25ec, 0x46bc, 0xb7, 0xfd, 0xc1, 0xf0, 0xdf, 0x8f, 0x50, 0x37} +DEFINE_GUID!{GUID_DEVINTERFACE_HIDDEN_VOLUME, + 0x7f108a28, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62} +DEFINE_GUID!{GUID_DEVINTERFACE_UNIFIED_ACCESS_RPMB, + 0x27447c21, 0xbcc3, 0x4d07, 0xa0, 0x5b, 0xa3, 0x39, 0x5b, 0xb4, 0xee, 0xe7} +DEFINE_GUID!{GUID_DEVINTERFACE_SCM_PHYSICAL_DEVICE, + 0x4283609d, 0x4dc2, 0x43be, 0xbb, 0xb4, 0x4f, 0x15, 0xdf, 0xce, 0x2c, 0x61} +DEFINE_GUID!{GUID_SCM_PD_HEALTH_NOTIFICATION, + 0x9da2d386, 0x72f5, 0x4ee3, 0x81, 0x55, 0xec, 0xa0, 0x67, 0x8e, 0x3b, 0x06} +DEFINE_GUID!{GUID_SCM_PD_PASSTHROUGH_INVDIMM, + 0x4309AC30, 0x0D11, 0x11E4, 0x91, 0x91, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66} +DEFINE_GUID!{GUID_DEVINTERFACE_COMPORT, + 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73} +DEFINE_GUID!{GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, + 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18} +//146 +DEFINE_DEVPROPKEY!{DEVPKEY_Storage_Portable, + 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 2} +DEFINE_DEVPROPKEY!{DEVPKEY_Storage_Removable_Media, + 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 3} +DEFINE_DEVPROPKEY!{DEVPKEY_Storage_System_Critical, + 0x4d1ebee8, 0x803, 0x4774, 0x98, 0x42, 0xb7, 0x7d, 0xb5, 0x2, 0x65, 0xe9, 4} +//177 +pub type DEVICE_TYPE = DWORD; +pub const FILE_DEVICE_BEEP: DEVICE_TYPE = 0x00000001; +pub const FILE_DEVICE_CD_ROM: DEVICE_TYPE = 0x00000002; +pub const FILE_DEVICE_CD_ROM_FILE_SYSTEM: DEVICE_TYPE = 0x00000003; +pub const FILE_DEVICE_CONTROLLER: DEVICE_TYPE = 0x00000004; +pub const FILE_DEVICE_DATALINK: DEVICE_TYPE = 0x00000005; +pub const FILE_DEVICE_DFS: DEVICE_TYPE = 0x00000006; +pub const FILE_DEVICE_DISK: DEVICE_TYPE = 0x00000007; +pub const FILE_DEVICE_DISK_FILE_SYSTEM: DEVICE_TYPE = 0x00000008; +pub const FILE_DEVICE_FILE_SYSTEM: DEVICE_TYPE = 0x00000009; +pub const FILE_DEVICE_INPORT_PORT: DEVICE_TYPE = 0x0000000a; +pub const FILE_DEVICE_KEYBOARD: DEVICE_TYPE = 0x0000000b; +pub const FILE_DEVICE_MAILSLOT: DEVICE_TYPE = 0x0000000c; +pub const FILE_DEVICE_MIDI_IN: DEVICE_TYPE = 0x0000000d; +pub const FILE_DEVICE_MIDI_OUT: DEVICE_TYPE = 0x0000000e; +pub const FILE_DEVICE_MOUSE: DEVICE_TYPE = 0x0000000f; +pub const FILE_DEVICE_MULTI_UNC_PROVIDER: DEVICE_TYPE = 0x00000010; +pub const FILE_DEVICE_NAMED_PIPE: DEVICE_TYPE = 0x00000011; +pub const FILE_DEVICE_NETWORK: DEVICE_TYPE = 0x00000012; +pub const FILE_DEVICE_NETWORK_BROWSER: DEVICE_TYPE = 0x00000013; +pub const FILE_DEVICE_NETWORK_FILE_SYSTEM: DEVICE_TYPE = 0x00000014; +pub const FILE_DEVICE_NULL: DEVICE_TYPE = 0x00000015; +pub const FILE_DEVICE_PARALLEL_PORT: DEVICE_TYPE = 0x00000016; +pub const FILE_DEVICE_PHYSICAL_NETCARD: DEVICE_TYPE = 0x00000017; +pub const FILE_DEVICE_PRINTER: DEVICE_TYPE = 0x00000018; +pub const FILE_DEVICE_SCANNER: DEVICE_TYPE = 0x00000019; +pub const FILE_DEVICE_SERIAL_MOUSE_PORT: DEVICE_TYPE = 0x0000001a; +pub const FILE_DEVICE_SERIAL_PORT: DEVICE_TYPE = 0x0000001b; +pub const FILE_DEVICE_SCREEN: DEVICE_TYPE = 0x0000001c; +pub const FILE_DEVICE_SOUND: DEVICE_TYPE = 0x0000001d; +pub const FILE_DEVICE_STREAMS: DEVICE_TYPE = 0x0000001e; +pub const FILE_DEVICE_TAPE: DEVICE_TYPE = 0x0000001f; +pub const FILE_DEVICE_TAPE_FILE_SYSTEM: DEVICE_TYPE = 0x00000020; +pub const FILE_DEVICE_TRANSPORT: DEVICE_TYPE = 0x00000021; +pub const FILE_DEVICE_UNKNOWN: DEVICE_TYPE = 0x00000022; +pub const FILE_DEVICE_VIDEO: DEVICE_TYPE = 0x00000023; +pub const FILE_DEVICE_VIRTUAL_DISK: DEVICE_TYPE = 0x00000024; +pub const FILE_DEVICE_WAVE_IN: DEVICE_TYPE = 0x00000025; +pub const FILE_DEVICE_WAVE_OUT: DEVICE_TYPE = 0x00000026; +pub const FILE_DEVICE_8042_PORT: DEVICE_TYPE = 0x00000027; +pub const FILE_DEVICE_NETWORK_REDIRECTOR: DEVICE_TYPE = 0x00000028; +pub const FILE_DEVICE_BATTERY: DEVICE_TYPE = 0x00000029; +pub const FILE_DEVICE_BUS_EXTENDER: DEVICE_TYPE = 0x0000002a; +pub const FILE_DEVICE_MODEM: DEVICE_TYPE = 0x0000002b; +pub const FILE_DEVICE_VDM: DEVICE_TYPE = 0x0000002c; +pub const FILE_DEVICE_MASS_STORAGE: DEVICE_TYPE = 0x0000002d; +pub const FILE_DEVICE_SMB: DEVICE_TYPE = 0x0000002e; +pub const FILE_DEVICE_KS: DEVICE_TYPE = 0x0000002f; +pub const FILE_DEVICE_CHANGER: DEVICE_TYPE = 0x00000030; +pub const FILE_DEVICE_SMARTCARD: DEVICE_TYPE = 0x00000031; +pub const FILE_DEVICE_ACPI: DEVICE_TYPE = 0x00000032; +pub const FILE_DEVICE_DVD: DEVICE_TYPE = 0x00000033; +pub const FILE_DEVICE_FULLSCREEN_VIDEO: DEVICE_TYPE = 0x00000034; +pub const FILE_DEVICE_DFS_FILE_SYSTEM: DEVICE_TYPE = 0x00000035; +pub const FILE_DEVICE_DFS_VOLUME: DEVICE_TYPE = 0x00000036; +pub const FILE_DEVICE_SERENUM: DEVICE_TYPE = 0x00000037; +pub const FILE_DEVICE_TERMSRV: DEVICE_TYPE = 0x00000038; +pub const FILE_DEVICE_KSEC: DEVICE_TYPE = 0x00000039; +pub const FILE_DEVICE_FIPS: DEVICE_TYPE = 0x0000003A; +pub const FILE_DEVICE_INFINIBAND: DEVICE_TYPE = 0x0000003B; +pub const FILE_DEVICE_VMBUS: DEVICE_TYPE = 0x0000003E; +pub const FILE_DEVICE_CRYPT_PROVIDER: DEVICE_TYPE = 0x0000003F; +pub const FILE_DEVICE_WPD: DEVICE_TYPE = 0x00000040; +pub const FILE_DEVICE_BLUETOOTH: DEVICE_TYPE = 0x00000041; +pub const FILE_DEVICE_MT_COMPOSITE: DEVICE_TYPE = 0x00000042; +pub const FILE_DEVICE_MT_TRANSPORT: DEVICE_TYPE = 0x00000043; +pub const FILE_DEVICE_BIOMETRIC: DEVICE_TYPE = 0x00000044; +pub const FILE_DEVICE_PMI: DEVICE_TYPE = 0x00000045; +pub const FILE_DEVICE_EHSTOR: DEVICE_TYPE = 0x00000046; +pub const FILE_DEVICE_DEVAPI: DEVICE_TYPE = 0x00000047; +pub const FILE_DEVICE_GPIO: DEVICE_TYPE = 0x00000048; +pub const FILE_DEVICE_USBEX: DEVICE_TYPE = 0x00000049; +pub const FILE_DEVICE_CONSOLE: DEVICE_TYPE = 0x00000050; +pub const FILE_DEVICE_NFP: DEVICE_TYPE = 0x00000051; +pub const FILE_DEVICE_SYSENV: DEVICE_TYPE = 0x00000052; +pub const FILE_DEVICE_VIRTUAL_BLOCK: DEVICE_TYPE = 0x00000053; +pub const FILE_DEVICE_POINT_OF_SERVICE: DEVICE_TYPE = 0x00000054; +pub const FILE_DEVICE_STORAGE_REPLICATION: DEVICE_TYPE = 0x00000055; +pub const FILE_DEVICE_TRUST_ENV: DEVICE_TYPE = 0x00000056; +pub const FILE_DEVICE_UCM: DEVICE_TYPE = 0x00000057; +pub const FILE_DEVICE_UCMTCPCI: DEVICE_TYPE = 0x00000058; +#[inline] +pub fn CTL_CODE( + DeviceType: DWORD, + Function: DWORD, + Method: DWORD, + Access: DWORD, +) -> DWORD { + (DeviceType << 16) | (Access << 14) | (Function << 2) | Method +} +//288 +pub const METHOD_BUFFERED: DWORD = 0; +pub const METHOD_IN_DIRECT: DWORD = 1; +pub const METHOD_OUT_DIRECT: DWORD = 2; +pub const METHOD_NEITHER: DWORD = 3; +//317 +pub const FILE_ANY_ACCESS: DWORD = 0; +pub const FILE_SPECIAL_ACCESS: DWORD = FILE_ANY_ACCESS; +pub const FILE_READ_ACCESS: DWORD = 0x0001; +pub const FILE_WRITE_ACCESS: DWORD = 0x0002; +//347 +pub const IOCTL_STORAGE_BASE: DWORD = FILE_DEVICE_MASS_STORAGE; +pub const IOCTL_STORAGE_CHECK_VERIFY: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0200, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_CHECK_VERIFY2: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0200, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_MEDIA_REMOVAL: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0201, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_EJECT_MEDIA: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0202, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_LOAD_MEDIA: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0203, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_LOAD_MEDIA2: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0203, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_RESERVE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_STORAGE_RELEASE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_STORAGE_FIND_NEW_DEVICES: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0206, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_EJECTION_CONTROL: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0250, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_MCN_CONTROL: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0251, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_GET_MEDIA_TYPES: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0300, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_GET_MEDIA_TYPES_EX: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0301, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0304, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_GET_HOTPLUG_INFO: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0305, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_SET_HOTPLUG_INFO: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0306, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_RESET_BUS: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_STORAGE_RESET_DEVICE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0401, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_BREAK_RESERVATION: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0405, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_PERSISTENT_RESERVE_IN: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0406, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0407, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_GET_DEVICE_NUMBER: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0420, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_PREDICT_FAILURE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0440, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_FAILURE_PREDICTION_CONFIG: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0441, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_READ_CAPACITY: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0450, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_GET_DEVICE_TELEMETRY: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0470, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_DEVICE_TELEMETRY_NOTIFY: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0471, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_DEVICE_TELEMETRY_QUERY_CAPS: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, + 0x0472, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_GET_DEVICE_TELEMETRY_RAW: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0473, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_QUERY_PROPERTY: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0500, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0501, + METHOD_BUFFERED, FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_GET_LB_PROVISIONING_MAP_RESOURCES: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, + 0x0502, METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_GET_BC_PROPERTIES: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0600, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_STORAGE_ALLOCATE_BC_STREAM: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0601, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_FREE_BC_STREAM: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0602, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, + 0x0620, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_START_DATA_INTEGRITY_CHECK: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0621, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_STOP_DATA_INTEGRITY_CHECK: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0622, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const OBSOLETE_IOCTL_STORAGE_RESET_BUS: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0400, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const OBSOLETE_IOCTL_STORAGE_RESET_DEVICE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0401, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_STORAGE_ENABLE_IDLE_POWER: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0720, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_GET_IDLE_POWERUP_REASON: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0721, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_POWER_ACTIVE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0722, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_POWER_IDLE: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0723, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_STORAGE_EVENT_NOTIFICATION: DWORD = CTL_CODE!(IOCTL_STORAGE_BASE, 0x0724, + METHOD_BUFFERED, FILE_ANY_ACCESS); +//565 +STRUCT!{struct STORAGE_DEVICE_NUMBER { + DeviceType: DEVICE_TYPE, + DeviceNumber: DWORD, + PartitionNumber: DWORD, +}} +pub type PSTORAGE_DEVICE_NUMBER = *mut STORAGE_DEVICE_NUMBER; +STRUCT!{struct STORAGE_DEVICE_NUMBERS { + NumberOfDevices: DWORD, + Devices: [STORAGE_DEVICE_NUMBER; ANYSIZE_ARRAY], +}} +pub type PSTORAGE_DEVICE_NUMBERS = *mut STORAGE_DEVICE_NUMBERS; +//1040 +ENUM!{enum STORAGE_QUERY_TYPE { + PropertyStandardQuery = 0, + PropertyExistsQuery, + PropertyMaskQuery, + PropertyQueryMaxDefined, +}} +pub type PSTORAGE_QUERY_TYPE = *mut STORAGE_QUERY_TYPE; +ENUM!{enum STORAGE_PROPERTY_ID { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty, + StorageDeviceDeviceTelemetryProperty, + StorageDeviceLBProvisioningProperty, + StorageDevicePowerProperty, + StorageDeviceCopyOffloadProperty, + StorageDeviceResiliencyProperty, + StorageDeviceMediumProductType, + StorageAdapterCryptoProperty, + StorageDeviceIoCapabilityProperty = 48, + StorageAdapterProtocolSpecificProperty, + StorageDeviceProtocolSpecificProperty, + StorageAdapterTemperatureProperty, + StorageDeviceTemperatureProperty, + StorageAdapterPhysicalTopologyProperty, + StorageDevicePhysicalTopologyProperty, + StorageDeviceAttributesProperty, + StorageDeviceManagementStatus, + StorageAdapterSerialNumberProperty, + StorageDeviceLocationProperty, + StorageDeviceNumaProperty, + StorageDeviceZonedDeviceProperty, + StorageDeviceUnsafeShutdownCount, +}} +pub type PSTORAGE_PROPERTY_ID = *mut STORAGE_PROPERTY_ID; +STRUCT!{struct STORAGE_PROPERTY_QUERY { + PropertyId: STORAGE_PROPERTY_ID, + QueryType: STORAGE_QUERY_TYPE, + AdditionalParameters: [BYTE; 1], +}} +pub type PSTORAGE_PROPERTY_QUERY = *mut STORAGE_PROPERTY_QUERY; +//1574 +STRUCT!{struct DEVICE_TRIM_DESCRIPTOR { + Version: DWORD, + Size: DWORD, + TrimEnabled: BOOLEAN, +}} +pub type PDEVICE_TRIM_DESCRIPTOR = *mut DEVICE_TRIM_DESCRIPTOR; +//7540 +pub const IOCTL_DISK_BASE: DWORD = FILE_DEVICE_DISK; +pub const IOCTL_DISK_GET_DRIVE_GEOMETRY: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0000, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_GET_PARTITION_INFO: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0001, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_DISK_SET_PARTITION_INFO: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0002, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_DRIVE_LAYOUT: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0003, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_DISK_SET_DRIVE_LAYOUT: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0004, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_VERIFY: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0005, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_FORMAT_TRACKS: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_REASSIGN_BLOCKS: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0007, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_PERFORMANCE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0008, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_IS_WRITABLE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0009, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_LOGGING: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000a, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_FORMAT_TRACKS_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000b, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_HISTOGRAM_STRUCTURE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000c, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_HISTOGRAM_DATA: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000d, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_HISTOGRAM_RESET: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000e, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_REQUEST_STRUCTURE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x000f, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_REQUEST_DATA: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0010, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_PERFORMANCE_OFF: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0018, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_CONTROLLER_NUMBER: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0011, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const SMART_GET_VERSION: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const SMART_SEND_DRIVE_COMMAND: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0021, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const SMART_RCV_DRIVE_DATA: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0022, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_PARTITION_INFO_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0012, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_SET_PARTITION_INFO_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0013, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_DRIVE_LAYOUT_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0014, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_SET_DRIVE_LAYOUT_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0015, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_CREATE_DISK: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0016, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_LENGTH_INFO: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0028, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_REASSIGN_BLOCKS_EX: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0029, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_UPDATE_DRIVE_SIZE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0032, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GROW_PARTITION: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0034, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_CACHE_INFORMATION: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0035, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_DISK_SET_CACHE_INFORMATION: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0036, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_GET_WRITE_CACHE_STATE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0037, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const OBSOLETE_DISK_GET_WRITE_CACHE_STATE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0037, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_DISK_DELETE_DRIVE_LAYOUT: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0040, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_UPDATE_PROPERTIES: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0050, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_FORMAT_DRIVE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x00f3, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_SENSE_DEVICE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x00f8, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_CHECK_VERIFY: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0200, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_MEDIA_REMOVAL: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0201, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_EJECT_MEDIA: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0202, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_LOAD_MEDIA: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0203, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_RESERVE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0204, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_RELEASE: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0205, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const IOCTL_DISK_FIND_NEW_DEVICES: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0206, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_DISK_GET_MEDIA_TYPES: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0300, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_DISK_GET_DISK_ATTRIBUTES: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x003c, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_DISK_SET_DISK_ATTRIBUTES: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x003d, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_DISK_RESET_SNAPSHOT_INFO: DWORD = CTL_CODE!(IOCTL_DISK_BASE, 0x0084, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +//7810 +ENUM!{enum MEDIA_TYPE { + Unknown, + F5_1Pt2_512, + F3_1Pt44_512, + F3_2Pt88_512, + F3_20Pt8_512, + F3_720_512, + F5_360_512, + F5_320_512, + F5_320_1024, + F5_180_512, + F5_160_512, + RemovableMedia, + FixedMedia, + F3_120M_512, + F3_640_512, + F5_640_512, + F5_720_512, + F3_1Pt2_512, + F3_1Pt23_1024, + F5_1Pt23_1024, + F3_128Mb_512, + F3_230Mb_512, + F8_256_128, + F3_200Mb_512, + F3_240M_512, + F3_32M_512, +}} +pub type PMEDIA_TYPE = *mut MEDIA_TYPE; +//7884 +STRUCT!{struct DISK_GEOMETRY { + Cylinders: LARGE_INTEGER, + MediaType: MEDIA_TYPE, + TracksPerCylinder: DWORD, + SectorsPerTrack: DWORD, + BytesPerSector: DWORD, +}} +pub type PDISK_GEOMETRY = *mut DISK_GEOMETRY; +DEFINE_GUID!{WMI_DISK_GEOMETRY_GUID, + 0x25007f51, 0x57c2, 0x11d1, 0xa5, 0x28, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10} +STRUCT!{struct PARTITION_INFORMATION { + StartingOffset: LARGE_INTEGER, + PartitionLength: LARGE_INTEGER, + HiddenSectors: DWORD, + PartitionNumber: DWORD, + PartitionType: BYTE, + BootIndicator: BOOLEAN, + RecognizedPartition: BOOLEAN, + RewritePartition: BOOLEAN, +}} +pub type PPARTITION_INFORMATION = *mut PARTITION_INFORMATION; +STRUCT!{struct SET_PARTITION_INFORMATION { + PartitionType: BYTE, +}} +pub type PSET_PARTITION_INFORMATION = *mut SET_PARTITION_INFORMATION; +STRUCT!{struct DRIVE_LAYOUT_INFORMATION { + PartitionCount: DWORD, + Signature: DWORD, + PartitionEntry: [PARTITION_INFORMATION; 1], +}} +pub type PDRIVE_LAYOUT_INFORMATION = *mut DRIVE_LAYOUT_INFORMATION; +STRUCT!{struct VERIFY_INFORMATION { + StartingOffset: LARGE_INTEGER, + Length: DWORD, +}} +pub type PVERIFY_INFORMATION = *mut VERIFY_INFORMATION; +STRUCT!{struct REASSIGN_BLOCKS { + Reserved: WORD, + Count: WORD, + BlockNumber: [DWORD; 1], +}} +pub type PREASSIGN_BLOCKS = *mut REASSIGN_BLOCKS; +STRUCT!{#[repr(packed)] struct REASSIGN_BLOCKS_EX { + Reserved: WORD, + Count: WORD, + BlockNumber: [LARGE_INTEGER; 1], +}} +pub type PREASSIGN_BLOCKS_EX = *mut REASSIGN_BLOCKS_EX; +ENUM!{enum PARTITION_STYLE { + PARTITION_STYLE_MBR, + PARTITION_STYLE_GPT, + PARTITION_STYLE_RAW, +}} +STRUCT!{struct PARTITION_INFORMATION_GPT { + PartitionType: GUID, + PartitionId: GUID, + Attributes: DWORD64, + Name: [WCHAR; 36], +}} +pub type PPARTITION_INFORMATION_GPT = *mut PARTITION_INFORMATION_GPT; +//8059 +STRUCT!{struct PARTITION_INFORMATION_MBR { + PartitionType: BYTE, + BootIndicator: BOOLEAN, + RecognizedPartition: BOOLEAN, + HiddenSectors: DWORD, + PartitionId: GUID, +}} +pub type PPARTITION_INFORMATION_MBR = *mut PARTITION_INFORMATION_MBR; +pub type SET_PARTITION_INFORMATION_MBR = SET_PARTITION_INFORMATION; +pub type SET_PARTITION_INFORMATION_GPT = PARTITION_INFORMATION_GPT; +STRUCT!{struct SET_PARTITION_INFORMATION_EX { + PartitionStyle: PARTITION_STYLE, + u: SET_PARTITION_INFORMATION_EX_u, +}} +UNION!{union SET_PARTITION_INFORMATION_EX_u { + [u64; 14], + Mbr Mbr_mut: SET_PARTITION_INFORMATION_MBR, + Gpt Gpt_mut: SET_PARTITION_INFORMATION_GPT, +}} +STRUCT!{struct CREATE_DISK_GPT { + DiskId: GUID, + MaxPartitionCount: DWORD, +}} +pub type PCREATE_DISK_GPT = *mut CREATE_DISK_GPT; +STRUCT!{struct CREATE_DISK_MBR { + Signature: DWORD, +}} +pub type PCREATE_DISK_MBR = *mut CREATE_DISK_MBR; +STRUCT!{struct CREATE_DISK { + PartitionStyle: PARTITION_STYLE, + u: CREATE_DISK_u, +}} +pub type PCREATE_DISK = *mut CREATE_DISK; +UNION!{union CREATE_DISK_u { + [u32; 5], + Mbr Mbr_mut: CREATE_DISK_MBR, + Gpt Gpt_mut: CREATE_DISK_GPT, +}} +STRUCT!{struct GET_LENGTH_INFORMATION { + Length: LARGE_INTEGER, +}} +pub type PGET_LENGTH_INFORMATION = *mut GET_LENGTH_INFORMATION; +STRUCT!{struct PARTITION_INFORMATION_EX { + PartitionStyle: PARTITION_STYLE, + StartingOffset: LARGE_INTEGER, + PartitionLength: LARGE_INTEGER, + PartitionNumber: DWORD, + RewritePartition: BOOLEAN, + u: PARTITION_INFORMATION_EX_u, +}} +pub type PPARTITION_INFORMATION_EX = *mut PARTITION_INFORMATION_EX; +UNION!{union PARTITION_INFORMATION_EX_u { + [u64; 14], + Mbr Mbr_mut: PARTITION_INFORMATION_MBR, + Gpt Gpt_mut: PARTITION_INFORMATION_GPT, +}} +STRUCT!{struct DRIVE_LAYOUT_INFORMATION_GPT { + DiskId: GUID, + StartingUsableOffset: LARGE_INTEGER, + UsableLength: LARGE_INTEGER, + MaxPartitionCount: DWORD, +}} +pub type PDRIVE_LAYOUT_INFORMATION_GPT = *mut DRIVE_LAYOUT_INFORMATION_GPT; +STRUCT!{struct DRIVE_LAYOUT_INFORMATION_MBR { + Signature: DWORD, + CheckSum: DWORD, +}} +pub type PDRIVE_LAYOUT_INFORMATION_MBR = *mut DRIVE_LAYOUT_INFORMATION_MBR; +STRUCT!{struct DRIVE_LAYOUT_INFORMATION_EX { + PartitionStyle: DWORD, + PartitionCount: DWORD, + u: DRIVE_LAYOUT_INFORMATION_EX_u, + PartitionEntry: [PARTITION_INFORMATION_EX; 1], +}} +pub type PDRIVE_LAYOUT_INFORMATION_EX = *mut DRIVE_LAYOUT_INFORMATION_EX; +UNION! {union DRIVE_LAYOUT_INFORMATION_EX_u { + [u64; 5], + Mbr Mbr_mut: DRIVE_LAYOUT_INFORMATION_MBR, + Gpt Gpt_mut: DRIVE_LAYOUT_INFORMATION_GPT, +}} +//8350 +STRUCT!{struct DISK_GEOMETRY_EX { + Geometry: DISK_GEOMETRY, + DiskSize: LARGE_INTEGER, + Data: [BYTE; 1], +}} +//8933 +pub const IOCTL_CHANGER_BASE: DWORD = FILE_DEVICE_CHANGER; +pub const IOCTL_CHANGER_GET_PARAMETERS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0000, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_GET_STATUS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0001, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_GET_PRODUCT_DATA: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0002, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_SET_ACCESS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0004, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_CHANGER_GET_ELEMENT_STATUS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0005, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0006, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_SET_POSITION: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0007, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_EXCHANGE_MEDIUM: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0008, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_MOVE_MEDIUM: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x0009, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_REINITIALIZE_TRANSPORT: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x000A, + METHOD_BUFFERED, FILE_READ_ACCESS); +pub const IOCTL_CHANGER_QUERY_VOLUME_TAGS: DWORD = CTL_CODE!(IOCTL_CHANGER_BASE, 0x000B, + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_SERIAL_LSRMST_INSERT: DWORD = CTL_CODE!(FILE_DEVICE_SERIAL_PORT, 31, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SERENUM_EXPOSE_HARDWARE: DWORD = CTL_CODE!(FILE_DEVICE_SERENUM, 128, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SERENUM_REMOVE_HARDWARE: DWORD = CTL_CODE!(FILE_DEVICE_SERENUM, 129, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SERENUM_PORT_DESC: DWORD = CTL_CODE!(FILE_DEVICE_SERENUM, 130, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SERENUM_GET_PORT_NAME: DWORD = CTL_CODE!(FILE_DEVICE_SERENUM, 131, + METHOD_BUFFERED, FILE_ANY_ACCESS); +//9717 +pub const FSCTL_REQUEST_OPLOCK_LEVEL_1: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 0, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_REQUEST_OPLOCK_LEVEL_2: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 1, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_REQUEST_BATCH_OPLOCK: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 2, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 3, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_OPBATCH_ACK_CLOSE_PENDING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 4, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_OPLOCK_BREAK_NOTIFY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 5, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_LOCK_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_UNLOCK_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_DISMOUNT_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_IS_VOLUME_MOUNTED: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 10, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_IS_PATHNAME_VALID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 11, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_MARK_VOLUME_DIRTY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 12, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_RETRIEVAL_POINTERS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 14, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_GET_COMPRESSION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_SET_COMPRESSION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, + FILE_READ_DATA | FILE_WRITE_DATA); +pub const FSCTL_SET_BOOTLOADER_ACCESSED: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 19, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_MARK_AS_SYSTEM_HIVE: DWORD = FSCTL_SET_BOOTLOADER_ACCESSED; +pub const FSCTL_OPLOCK_BREAK_ACK_NO_2: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 20, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_INVALIDATE_VOLUMES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 21, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_FAT_BPB: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_REQUEST_FILTER_OPLOCK: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 23, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_FILESYSTEM_GET_STATISTICS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 24, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_GET_NTFS_VOLUME_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 25, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_GET_NTFS_FILE_RECORD: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 26, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_GET_VOLUME_BITMAP: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 27, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_GET_RETRIEVAL_POINTERS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 28, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_MOVE_FILE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 29, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_IS_VOLUME_DIRTY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 30, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_ALLOW_EXTENDED_DASD_IO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 32, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_FIND_FILES_BY_SID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 35, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_SET_OBJECT_ID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 38, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_GET_OBJECT_ID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 39, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_DELETE_OBJECT_ID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 40, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_SET_REPARSE_POINT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 41, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_GET_REPARSE_POINT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 42, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_DELETE_REPARSE_POINT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 43, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_ENUM_USN_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 44, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_SECURITY_ID_CHECK: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 45, METHOD_NEITHER, + FILE_READ_DATA); +pub const FSCTL_READ_USN_JOURNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 46, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_SET_OBJECT_ID_EXTENDED: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 47, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_CREATE_OR_GET_OBJECT_ID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 48, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SET_SPARSE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_SET_ZERO_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_QUERY_ALLOCATED_RANGES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 51, + METHOD_NEITHER, FILE_READ_DATA); +pub const FSCTL_ENABLE_UPGRADE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 52, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_SET_ENCRYPTION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 53, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_ENCRYPTION_FSCTL_IO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 54, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_WRITE_RAW_ENCRYPTED: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 55, + METHOD_NEITHER, FILE_SPECIAL_ACCESS); +pub const FSCTL_READ_RAW_ENCRYPTED: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 56, + METHOD_NEITHER, FILE_SPECIAL_ACCESS); +pub const FSCTL_CREATE_USN_JOURNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 57, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_READ_FILE_USN_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 58, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_WRITE_USN_CLOSE_RECORD: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 59, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_EXTEND_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_QUERY_USN_JOURNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 61, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_DELETE_USN_JOURNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 62, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_MARK_HANDLE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 63, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_SIS_COPYFILE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 64, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_SIS_LINK_FILES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 65, METHOD_BUFFERED, + FILE_READ_DATA | FILE_WRITE_DATA); +pub const FSCTL_RECALL_FILE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 69, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_READ_FROM_PLEX: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 71, METHOD_OUT_DIRECT, + FILE_READ_DATA); +pub const FSCTL_FILE_PREFETCH: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 72, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_MAKE_MEDIA_COMPATIBLE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 76, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_SET_DEFECT_MANAGEMENT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 77, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_QUERY_SPARING_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 78, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_ON_DISK_VOLUME_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 79, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SET_VOLUME_COMPRESSION_STATE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 80, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_TXFS_MODIFY_RM: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 81, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_TXFS_QUERY_RM_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 82, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_TXFS_ROLLFORWARD_REDO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 84, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_ROLLFORWARD_UNDO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 85, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_START_RM: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 86, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_TXFS_SHUTDOWN_RM: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 87, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_TXFS_READ_BACKUP_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 88, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_TXFS_WRITE_BACKUP_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 89, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_CREATE_SECONDARY_RM: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 90, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_GET_METADATA_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 91, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_TXFS_GET_TRANSACTED_VERSION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 92, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_TXFS_SAVEPOINT_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 94, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_CREATE_MINIVERSION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 95, + METHOD_BUFFERED, FILE_WRITE_DATA); +pub const FSCTL_TXFS_TRANSACTION_ACTIVE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 99, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_SET_ZERO_ON_DEALLOCATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 101, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_SET_REPAIR: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 102, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_GET_REPAIR: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 103, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_WAIT_FOR_REPAIR: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 104, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_INITIATE_REPAIR: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 106, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_CSC_INTERNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_SHRINK_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 108, METHOD_BUFFERED, + FILE_SPECIAL_ACCESS); +pub const FSCTL_SET_SHORT_NAME_BEHAVIOR: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 109, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_DFSR_SET_GHOST_HANDLE_STATE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 110, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, + 120, METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_TXFS_LIST_TRANSACTIONS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 121, + METHOD_BUFFERED, FILE_READ_DATA); +pub const FSCTL_QUERY_PAGEFILE_ENCRYPTION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 122, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_RESET_VOLUME_ALLOCATION_HINTS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 123, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_DEPENDENT_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 124, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SD_GLOBAL_CHANGE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 125, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_TXFS_READ_BACKUP_INFORMATION2: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 126, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_LOOKUP_STREAM_FROM_CLUSTER: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 127, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_TXFS_WRITE_BACKUP_INFORMATION2: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 128, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_FILE_TYPE_NOTIFICATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 129, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_FILE_LEVEL_TRIM: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 130, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_GET_BOOT_AREA_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 140, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_GET_RETRIEVAL_POINTER_BASE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 141, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SET_PERSISTENT_VOLUME_STATE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 142, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_PERSISTENT_VOLUME_STATE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 143, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_REQUEST_OPLOCK: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 144, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_CSV_TUNNEL_REQUEST: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 145, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_IS_CSV_FILE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 146, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_QUERY_FILE_SYSTEM_RECOGNITION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 147, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_GET_VOLUME_PATH_NAME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 148, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_GET_VOLUME_NAME_FOR_VOLUME_MOUNT_POINT: DWORD = CTL_CODE!( + FILE_DEVICE_FILE_SYSTEM, 149, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_GET_VOLUME_PATH_NAMES_FOR_VOLUME_NAME: DWORD = CTL_CODE!( + FILE_DEVICE_FILE_SYSTEM, 150, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_IS_FILE_ON_CSV_VOLUME: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 151, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CORRUPTION_HANDLING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 152, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_OFFLOAD_READ: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 153, METHOD_BUFFERED, + FILE_READ_ACCESS); +pub const FSCTL_OFFLOAD_WRITE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 154, METHOD_BUFFERED, + FILE_WRITE_ACCESS); +pub const FSCTL_CSV_INTERNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 155, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_SET_PURGE_FAILURE_MODE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 156, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_FILE_LAYOUT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 157, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_IS_VOLUME_OWNED_BYCSVFS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 158, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_GET_INTEGRITY_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 159, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SET_INTEGRITY_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 160, + METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA); +pub const FSCTL_QUERY_FILE_REGIONS: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 161, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_DEDUP_FILE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 165, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_DEDUP_QUERY_FILE_HASHES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 166, + METHOD_NEITHER, FILE_READ_DATA); +pub const FSCTL_DEDUP_QUERY_RANGE_STATE: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 167, + METHOD_NEITHER, FILE_READ_DATA); +pub const FSCTL_DEDUP_QUERY_REPARSE_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 168, + METHOD_NEITHER, FILE_ANY_ACCESS); +pub const FSCTL_RKF_INTERNAL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 171, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_SCRUB_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 172, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_REPAIR_COPIES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 173, METHOD_BUFFERED, + FILE_READ_DATA | FILE_WRITE_DATA); +pub const FSCTL_DISABLE_LOCAL_BUFFERING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 174, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_MGMT_LOCK: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 175, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_CSV_QUERY_DOWN_LEVEL_FILE_SYSTEM_CHARACTERISTICS: DWORD = CTL_CODE!( + FILE_DEVICE_FILE_SYSTEM, 176, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_ADVANCE_FILE_ID: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 177, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_CSV_SYNC_TUNNEL_REQUEST: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 178, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_QUERY_VETO_FILE_DIRECT_IO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 179, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_WRITE_USN_REASON: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 180, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_CONTROL: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 181, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const FSCTL_GET_REFS_VOLUME_DATA: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 182, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_CSV_H_BREAKING_SYNC_TUNNEL_REQUEST: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, + 185, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_STORAGE_CLASSES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 187, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_REGION_INFO: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 188, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_USN_TRACK_MODIFIED_RANGES: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 189, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, + 192, METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SVHDX_SYNC_TUNNEL_REQUEST: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 193, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SVHDX_SET_INITIATOR_INFORMATION: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 194, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_SET_EXTERNAL_BACKING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 195, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_GET_EXTERNAL_BACKING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 196, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_DELETE_EXTERNAL_BACKING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 197, + METHOD_BUFFERED, FILE_SPECIAL_ACCESS); +pub const FSCTL_ENUM_EXTERNAL_BACKING: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 198, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const FSCTL_ENUM_OVERLAY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 199, METHOD_NEITHER, + FILE_ANY_ACCESS); +pub const FSCTL_ADD_OVERLAY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 204, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_REMOVE_OVERLAY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 205, METHOD_BUFFERED, + FILE_WRITE_DATA); +pub const FSCTL_UPDATE_OVERLAY: DWORD = CTL_CODE!(FILE_DEVICE_FILE_SYSTEM, 206, METHOD_BUFFERED, + FILE_WRITE_DATA); +// FILE_DEVICE_AVIO is defined nowhere +//pub const IOCTL_AVIO_ALLOCATE_STREAM: DWORD = CTL_CODE!(FILE_DEVICE_AVIO, 1, METHOD_BUFFERED, +// FILE_SPECIAL_ACCESS); +//pub const IOCTL_AVIO_FREE_STREAM: DWORD = CTL_CODE!(FILE_DEVICE_AVIO, 2, METHOD_BUFFERED, +// FILE_SPECIAL_ACCESS); +//pub const IOCTL_AVIO_MODIFY_STREAM: DWORD = CTL_CODE!(FILE_DEVICE_AVIO, 3, METHOD_BUFFERED, +// FILE_SPECIAL_ACCESS); +STRUCT!{struct PATHNAME_BUFFER { + PathNameLength: DWORD, + Name: [WCHAR; 1], +}} +pub type PPATHNAME_BUFFER = *mut PATHNAME_BUFFER; +STRUCT!{struct FSCTL_QUERY_FAT_BPB_BUFFER { + First0x24BytesOfBootSector: [BYTE; 0x24], +}} +pub type PFSCTL_QUERY_FAT_BPB_BUFFER = *mut FSCTL_QUERY_FAT_BPB_BUFFER; +STRUCT!{struct NTFS_VOLUME_DATA_BUFFER { + VolumeSerialNumber: LARGE_INTEGER, + NumberSectors: LARGE_INTEGER, + TotalClusters: LARGE_INTEGER, + FreeClusters: LARGE_INTEGER, + TotalReserved: LARGE_INTEGER, + BytesPerSector: DWORD, + BytesPerCluster: DWORD, + BytesPerFileRecordSegment: DWORD, + ClustersPerFileRecordSegment: DWORD, + MftValidDataLength: LARGE_INTEGER, + MftStartLcn: LARGE_INTEGER, + Mft2StartLcn: LARGE_INTEGER, + MftZoneStart: LARGE_INTEGER, + MftZoneEnd: LARGE_INTEGER, +}} +pub type PNTFS_VOLUME_DATA_BUFFER = *mut NTFS_VOLUME_DATA_BUFFER; +STRUCT!{struct NTFS_EXTENDED_VOLUME_DATA { + ByteCount: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + BytesPerPhysicalSector: DWORD, + LfsMajorVersion: WORD, + LfsMinorVersion: WORD, + MaxDeviceTrimExtentCount: DWORD, + MaxDeviceTrimByteCount: DWORD, + MaxVolumeTrimExtentCount: DWORD, + MaxVolumeTrimByteCount: DWORD, +}} +pub type PNTFS_EXTENDED_VOLUME_DATA = *mut NTFS_EXTENDED_VOLUME_DATA; +STRUCT!{struct REFS_VOLUME_DATA_BUFFER { + ByteCount: DWORD, + MajorVersion: DWORD, + MinorVersion: DWORD, + BytesPerPhysicalSector: DWORD, + VolumeSerialNumber: LARGE_INTEGER, + NumberSectors: LARGE_INTEGER, + TotalClusters: LARGE_INTEGER, + FreeClusters: LARGE_INTEGER, + TotalReserved: LARGE_INTEGER, + BytesPerSector: DWORD, + BytesPerCluster: DWORD, + MaximumSizeOfResidentFile: LARGE_INTEGER, + Reserved: [LARGE_INTEGER; 10], +}} +pub type PREFS_VOLUME_DATA_BUFFER = *mut REFS_VOLUME_DATA_BUFFER; +STRUCT!{struct STARTING_LCN_INPUT_BUFFER { + StartingLcn: LARGE_INTEGER, +}} +pub type PSTARTING_LCN_INPUT_BUFFER = *mut STARTING_LCN_INPUT_BUFFER; +STRUCT!{struct VOLUME_BITMAP_BUFFER { + StartingLcn: LARGE_INTEGER, + BitmapSize: LARGE_INTEGER, + Buffer: [BYTE; 1], +}} +pub type PVOLUME_BITMAP_BUFFER = *mut VOLUME_BITMAP_BUFFER; +STRUCT!{struct STARTING_VCN_INPUT_BUFFER { + StartingVcn: LARGE_INTEGER, +}} +pub type PSTARTING_VCN_INPUT_BUFFER = *mut STARTING_VCN_INPUT_BUFFER; +STRUCT!{struct RETRIEVAL_POINTERS_BUFFER_INTERNAL { + NextVcn: LARGE_INTEGER, + Lcn: LARGE_INTEGER, +}} +STRUCT!{struct RETRIEVAL_POINTERS_BUFFER { + ExtentCount: DWORD, + StartingVcn: LARGE_INTEGER, + Extents: [RETRIEVAL_POINTERS_BUFFER_INTERNAL; 1], +}} +pub type PRETRIEVAL_POINTERS_BUFFER = *mut RETRIEVAL_POINTERS_BUFFER; +STRUCT!{struct NTFS_FILE_RECORD_INPUT_BUFFER { + FileReferenceNumber: LARGE_INTEGER, +}} +pub type PNTFS_FILE_RECORD_INPUT_BUFFER = *mut NTFS_FILE_RECORD_INPUT_BUFFER; +STRUCT!{struct NTFS_FILE_RECORD_OUTPUT_BUFFER { + FileReferenceNumber: LARGE_INTEGER, + FileRecordLength: DWORD, + FileRecordBuffer: [BYTE; 1], +}} +pub type PNTFS_FILE_RECORD_OUTPUT_BUFFER = *mut NTFS_FILE_RECORD_OUTPUT_BUFFER; +STRUCT!{struct MOVE_FILE_DATA { + FileHandle: HANDLE, + StartingVcn: LARGE_INTEGER, + StartingLcn: LARGE_INTEGER, + ClusterCount: DWORD, +}} +pub type PMOVE_FILE_DATA = *mut MOVE_FILE_DATA; +STRUCT!{struct MOVE_FILE_RECORD_DATA { + FileHandle: HANDLE, + SourceFileRecord: LARGE_INTEGER, + TargetFileRecord: LARGE_INTEGER, +}} +pub type PMOVE_FILE_RECORD_DATA = *mut MOVE_FILE_RECORD_DATA; +//15468 +pub const IOCTL_VOLUME_BASE: DWORD = 0x00000056; +pub const IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: DWORD = CTL_CODE!(IOCTL_VOLUME_BASE, 0, + METHOD_BUFFERED, FILE_ANY_ACCESS); +STRUCT!{struct DISK_EXTENT { + DiskNumber: DWORD, + StartingOffset: LARGE_INTEGER, + ExtentLength: LARGE_INTEGER, +}} +pub type PDISK_EXTENT = *mut DISK_EXTENT; +STRUCT!{struct VOLUME_DISK_EXTENTS { + NumberOfDiskExtents: DWORD, + Extents: [DISK_EXTENT; ANYSIZE_ARRAY], +}} +pub type PVOLUME_DISK_EXTENTS = *mut VOLUME_DISK_EXTENTS; +pub const IOCTL_VOLUME_ONLINE: DWORD = CTL_CODE!(IOCTL_VOLUME_BASE, 2, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_VOLUME_OFFLINE: DWORD = CTL_CODE!(IOCTL_VOLUME_BASE, 3, METHOD_BUFFERED, + FILE_READ_ACCESS | FILE_WRITE_ACCESS); +pub const IOCTL_VOLUME_IS_CLUSTERED: DWORD = CTL_CODE!(IOCTL_VOLUME_BASE, 12, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_VOLUME_GET_GPT_ATTRIBUTES: DWORD = CTL_CODE!(IOCTL_VOLUME_BASE, 14, + METHOD_BUFFERED, FILE_ANY_ACCESS); diff --git a/winapi/src/um/winnetwk.rs b/winapi/src/um/winnetwk.rs new file mode 100644 index 000000000..5680da124 --- /dev/null +++ b/winapi/src/um/winnetwk.rs @@ -0,0 +1,446 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Standard WINNET Header File for WIN32 +use shared::basetsd::ULONG_PTR; +use shared::minwindef::{BOOL, DWORD, LPDWORD, LPHANDLE, LPVOID, WORD}; +use shared::windef::HWND; +use shared::winerror::{ + ERROR_ACCESS_DENIED, ERROR_ALREADY_ASSIGNED, ERROR_ALREADY_INITIALIZED, ERROR_BAD_DEVICE, + ERROR_BAD_DEV_TYPE, ERROR_BAD_NET_NAME, ERROR_BAD_PROFILE, ERROR_BAD_PROVIDER, + ERROR_BAD_USERNAME, ERROR_BUSY, ERROR_CANCELLED, ERROR_CANNOT_OPEN_PROFILE, + ERROR_CONNECTED_OTHER_PASSWORD, ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT, + ERROR_CONNECTION_UNAVAIL, ERROR_DEVICE_ALREADY_REMEMBERED, ERROR_DEVICE_IN_USE, + ERROR_EXTENDED_ERROR, ERROR_GEN_FAILURE, ERROR_INVALID_ADDRESS, ERROR_INVALID_HANDLE, + ERROR_INVALID_LEVEL, ERROR_INVALID_PARAMETER, ERROR_INVALID_PASSWORD, ERROR_MORE_DATA, + ERROR_NOT_AUTHENTICATED, ERROR_NOT_CONNECTED, ERROR_NOT_CONTAINER, ERROR_NOT_ENOUGH_MEMORY, + ERROR_NOT_LOGGED_ON, ERROR_NOT_SUPPORTED, ERROR_NO_LOGON_SERVERS, ERROR_NO_MORE_DEVICES, + ERROR_NO_MORE_ITEMS, ERROR_NO_NETWORK, ERROR_NO_NET_OR_BAD_PATH, ERROR_OPEN_FILES, ERROR_RETRY, + ERROR_UNEXP_NET_ERR, NO_ERROR +}; +use um::winnt::{HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR}; +pub const RESOURCE_CONNECTED: DWORD = 0x00000001; +pub const RESOURCE_GLOBALNET: DWORD = 0x00000002; +pub const RESOURCE_REMEMBERED: DWORD = 0x00000003; +pub const RESOURCE_RECENT: DWORD = 0x00000004; +pub const RESOURCE_CONTEXT: DWORD = 0x00000005; +pub const RESOURCETYPE_ANY: DWORD = 0x00000000; +pub const RESOURCETYPE_DISK: DWORD = 0x00000001; +pub const RESOURCETYPE_PRINT: DWORD = 0x00000002; +pub const RESOURCETYPE_RESERVED: DWORD = 0x00000008; +pub const RESOURCETYPE_UNKNOWN: DWORD = 0xFFFFFFFF; +pub const RESOURCEUSAGE_CONNECTABLE: DWORD = 0x00000001; +pub const RESOURCEUSAGE_CONTAINER: DWORD = 0x00000002; +pub const RESOURCEUSAGE_NOLOCALDEVICE: DWORD = 0x00000004; +pub const RESOURCEUSAGE_SIBLING: DWORD = 0x00000008; +pub const RESOURCEUSAGE_ATTACHED: DWORD = 0x00000010; +pub const RESOURCEUSAGE_ALL: DWORD = RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER + | RESOURCEUSAGE_ATTACHED; +pub const RESOURCEUSAGE_RESERVED: DWORD = 0x80000000; +pub const RESOURCEDISPLAYTYPE_GENERIC: DWORD = 0x00000000; +pub const RESOURCEDISPLAYTYPE_DOMAIN: DWORD = 0x00000001; +pub const RESOURCEDISPLAYTYPE_SERVER: DWORD = 0x00000002; +pub const RESOURCEDISPLAYTYPE_SHARE: DWORD = 0x00000003; +pub const RESOURCEDISPLAYTYPE_FILE: DWORD = 0x00000004; +pub const RESOURCEDISPLAYTYPE_GROUP: DWORD = 0x00000005; +pub const RESOURCEDISPLAYTYPE_NETWORK: DWORD = 0x00000006; +pub const RESOURCEDISPLAYTYPE_ROOT: DWORD = 0x00000007; +pub const RESOURCEDISPLAYTYPE_SHAREADMIN: DWORD = 0x00000008; +pub const RESOURCEDISPLAYTYPE_DIRECTORY: DWORD = 0x00000009; +pub const RESOURCEDISPLAYTYPE_TREE: DWORD = 0x0000000A; +pub const RESOURCEDISPLAYTYPE_NDSCONTAINER: DWORD = 0x0000000B; +STRUCT!{struct NETRESOURCEA { + dwScope: DWORD, + dwType: DWORD, + dwDisplayType: DWORD, + dwUsage: DWORD, + lpLocalName: LPSTR, + lpRemoteName: LPSTR, + lpComment: LPSTR, + lpProvider: LPSTR, +}} +pub type LPNETRESOURCEA = *mut NETRESOURCEA; +STRUCT!{struct NETRESOURCEW { + dwScope: DWORD, + dwType: DWORD, + dwDisplayType: DWORD, + dwUsage: DWORD, + lpLocalName: LPWSTR, + lpRemoteName: LPWSTR, + lpComment: LPWSTR, + lpProvider: LPWSTR, +}} +pub type LPNETRESOURCEW = *mut NETRESOURCEW; +pub const NETPROPERTY_PERSISTENT: DWORD = 1; +pub const CONNECT_UPDATE_PROFILE: DWORD = 0x00000001; +pub const CONNECT_UPDATE_RECENT: DWORD = 0x00000002; +pub const CONNECT_TEMPORARY: DWORD = 0x00000004; +pub const CONNECT_INTERACTIVE: DWORD = 0x00000008; +pub const CONNECT_PROMPT: DWORD = 0x00000010; +pub const CONNECT_NEED_DRIVE: DWORD = 0x00000020; +pub const CONNECT_REFCOUNT: DWORD = 0x00000040; +pub const CONNECT_REDIRECT: DWORD = 0x00000080; +pub const CONNECT_LOCALDRIVE: DWORD = 0x00000100; +pub const CONNECT_CURRENT_MEDIA: DWORD = 0x00000200; +pub const CONNECT_DEFERRED: DWORD = 0x00000400; +pub const CONNECT_RESERVED: DWORD = 0xFF000000; +pub const CONNECT_COMMANDLINE: DWORD = 0x00000800; +pub const CONNECT_CMD_SAVECRED: DWORD = 0x00001000; +pub const CONNECT_CRED_RESET: DWORD = 0x00002000; +extern "system" { + pub fn WNetAddConnection2A( + lpNetResource: LPNETRESOURCEA, + lpPassword: LPCSTR, + lpUsername: LPCSTR, + dwFlags: DWORD, + ) -> DWORD; + pub fn WNetAddConnection2W( + lpNetResource: LPNETRESOURCEW, + lpPassword: LPCWSTR, + lpUsername: LPCWSTR, + dwFlags: DWORD, + ) -> DWORD; + pub fn WNetAddConnection3A( + hwndOwner: HWND, + lpNetResource: LPNETRESOURCEA, + lpPassword: LPCSTR, + lpUsername: LPCSTR, + dwFlags: DWORD, + ) -> DWORD; + pub fn WNetAddConnection3W( + hwndOwner: HWND, + lpNetResource: LPNETRESOURCEW, + lpPassword: LPCWSTR, + lpUsername: LPCWSTR, + dwFlags: DWORD, + ) -> DWORD; + pub fn WNetCancelConnectionA( + lpName: LPCSTR, + fForce: BOOL, + ) -> DWORD; + pub fn WNetCancelConnectionW( + lpName: LPCWSTR, + fForce: BOOL, + ) -> DWORD; + pub fn WNetCancelConnection2A( + lpName: LPCSTR, + dwFlags: DWORD, + fForce: BOOL, + ) -> DWORD; + pub fn WNetCancelConnection2W( + lpName: LPCWSTR, + dwFlags: DWORD, + fForce: BOOL, + ) -> DWORD; + pub fn WNetGetConnectionA( + lpLocalName: LPCSTR, + lpRemoteName: LPSTR, + lpnLength: LPDWORD, + ) -> DWORD; + pub fn WNetGetConnectionW( + lpLocalName: LPCWSTR, + lpRemoteName: LPWSTR, + lpnLength: LPDWORD, + ) -> DWORD; + pub fn WNetUseConnectionA( + hwndOwner: HWND, + lpNetResource: LPNETRESOURCEA, + lpPassword: LPCSTR, + lpUserId: LPCSTR, + dwFlags: DWORD, + lpAccessName: LPSTR, + lpBufferSize: LPDWORD, + lpResult: LPDWORD, + ) -> DWORD; + pub fn WNetUseConnectionW( + hwndOwner: HWND, + lpNetResource: LPNETRESOURCEW, + lpPassword: LPCWSTR, + lpUserId: LPCWSTR, + dwFlags: DWORD, + lpAccessName: LPWSTR, + lpBufferSize: LPDWORD, + lpResult: LPDWORD, + ) -> DWORD; + pub fn WNetConnectionDialog( + hwnd: HWND, + dwType: DWORD, + ) -> DWORD; + pub fn WNetDisconnectDialog( + hwnd: HWND, + dwType: DWORD, + ) -> DWORD; +} +STRUCT!{struct CONNECTDLGSTRUCTA { + cbStructure: DWORD, + hwndOwner: HWND, + lpConnRes: LPNETRESOURCEA, + dwFlags: DWORD, + dwDevNum: DWORD, +}} +pub type LPCONNECTDLGSTRUCTA = *mut CONNECTDLGSTRUCTA; +STRUCT!{struct CONNECTDLGSTRUCTW { + cbStructure: DWORD, + hwndOwner: HWND, + lpConnRes: LPNETRESOURCEW, + dwFlags: DWORD, + dwDevNum: DWORD, +}} +pub type LPCONNECTDLGSTRUCTW = *mut CONNECTDLGSTRUCTW; +pub const CONNDLG_RO_PATH: DWORD = 0x00000001; +pub const CONNDLG_CONN_POINT: DWORD = 0x00000002; +pub const CONNDLG_USE_MRU: DWORD = 0x00000004; +pub const CONNDLG_HIDE_BOX: DWORD = 0x00000008; +pub const CONNDLG_PERSIST: DWORD = 0x00000010; +pub const CONNDLG_NOT_PERSIST: DWORD = 0x00000020; +extern "system" { + pub fn WNetConnectionDialog1A( + lpConnDlgStruct: LPCONNECTDLGSTRUCTA, + ) -> DWORD; + pub fn WNetConnectionDialog1W( + lpConnDlgStruct: LPCONNECTDLGSTRUCTW, + ) -> DWORD; +} +STRUCT!{struct DISCDLGSTRUCTA { + cbStructure: DWORD, + hwndOwner: HWND, + lpLocalName: LPSTR, + lpRemoteName: LPSTR, + dwFlags: DWORD, +}} +pub type LPDISCDLGSTRUCTA = *mut DISCDLGSTRUCTA; +STRUCT!{struct DISCDLGSTRUCTW { + cbStructure: DWORD, + hwndOwner: HWND, + lpLocalName: LPWSTR, + lpRemoteName: LPWSTR, + dwFlags: DWORD, +}} +pub type LPDISCDLGSTRUCTW = *mut DISCDLGSTRUCTW; +pub const DISC_UPDATE_PROFILE: DWORD = 0x00000001; +pub const DISC_NO_FORCE: DWORD = 0x00000040; +extern "system" { + pub fn WNetDisconnectDialog1A( + lpConnDlgStruct: LPDISCDLGSTRUCTA, + ) -> DWORD; + pub fn WNetDisconnectDialog1W( + lpConnDlgStruct: LPDISCDLGSTRUCTW, + ) -> DWORD; + pub fn WNetOpenEnumA( + dwScope: DWORD, + dwType: DWORD, + dwUsage: DWORD, + lpNetResource: LPNETRESOURCEA, + lphEnum: LPHANDLE, + ) -> DWORD; + pub fn WNetOpenEnumW( + dwScope: DWORD, + dwType: DWORD, + dwUsage: DWORD, + lpNetResource: LPNETRESOURCEW, + lphEnum: LPHANDLE, + ) -> DWORD; + pub fn WNetEnumResourceA( + hEnum: HANDLE, + lpcCount: LPDWORD, + lpBuffer: LPVOID, + lpBufferSize: LPDWORD, + ) -> DWORD; + pub fn WNetEnumResourceW( + hEnum: HANDLE, + lpcCount: LPDWORD, + lpBuffer: LPVOID, + lpBufferSize: LPDWORD, + ) -> DWORD; + pub fn WNetCloseEnum( + hEnum: HANDLE, + ) -> DWORD; + pub fn WNetGetResourceParentA( + lpNetResource: LPNETRESOURCEA, + lpBuffer: LPVOID, + lpcbBuffer: LPDWORD, + ) -> DWORD; + pub fn WNetGetResourceParentW( + lpNetResource: LPNETRESOURCEW, + lpBuffer: LPVOID, + lpcbBuffer: LPDWORD, + ) -> DWORD; + pub fn WNetGetResourceInformationA( + lpNetResource: LPNETRESOURCEA, + lpBuffer: LPVOID, + lpcbBuffer: LPDWORD, + lplpSystem: *mut LPSTR, + ) -> DWORD; + pub fn WNetGetResourceInformationW( + lpNetResource: LPNETRESOURCEW, + lpBuffer: LPVOID, + lpcbBuffer: LPDWORD, + lplpSystem: *mut LPWSTR, + ) -> DWORD; +} +pub const UNIVERSAL_NAME_INFO_LEVEL: DWORD = 0x00000001; +pub const REMOTE_NAME_INFO_LEVEL: DWORD = 0x00000002; +STRUCT!{struct UNIVERSAL_NAME_INFOA { + lpUniversalName: LPSTR, +}} +pub type LPUNIVERSAL_NAME_INFOA = *mut UNIVERSAL_NAME_INFOA; +STRUCT!{struct UNIVERSAL_NAME_INFOW { + lpUniversalName: LPWSTR, +}} +pub type LPUNIVERSAL_NAME_INFOW = *mut UNIVERSAL_NAME_INFOW; +STRUCT!{struct REMOTE_NAME_INFOA { + lpUniversalName: LPSTR, + lpConnectionName: LPSTR, + lpRemainingPath: LPSTR, +}} +pub type LPREMOTE_NAME_INFOA = *mut REMOTE_NAME_INFOA; +STRUCT!{struct REMOTE_NAME_INFOW { + lpUniversalName: LPWSTR, + lpConnectionName: LPWSTR, + lpRemainingPath: LPWSTR, +}} +pub type LPREMOTE_NAME_INFOW = *mut REMOTE_NAME_INFOW; +extern "system" { + pub fn WNetGetUniversalNameA( + lpLocalPath: LPCSTR, + dwInfoLevel: DWORD, + lpBuffer: LPVOID, + lpBufferSize: LPDWORD, + ) -> DWORD; + pub fn WNetGetUniversalNameW( + lpLocalPath: LPCWSTR, + dwInfoLevel: DWORD, + lpBuffer: LPVOID, + lpBufferSize: LPDWORD, + ) -> DWORD; + pub fn WNetGetUserA( + lpName: LPCSTR, + lpUserName: LPSTR, + lpnLength: LPDWORD, + ) -> DWORD; + pub fn WNetGetUserW( + lpName: LPCWSTR, + lpUserName: LPWSTR, + lpnLength: LPDWORD, + ) -> DWORD; +} +pub const WNFMT_MULTILINE: DWORD = 0x01; +pub const WNFMT_ABBREVIATED: DWORD = 0x02; +pub const WNFMT_INENUM: DWORD = 0x10; +pub const WNFMT_CONNECTION: DWORD = 0x20; +extern "system" { + pub fn WNetGetProviderNameA( + dwNetType: DWORD, + lpProviderName: LPSTR, + lpBufferSize: LPDWORD, + ) -> DWORD; + pub fn WNetGetProviderNameW( + dwNetType: DWORD, + lpProviderName: LPWSTR, + lpBufferSize: LPDWORD, + ) -> DWORD; +} +STRUCT!{struct NETINFOSTRUCT { + cbStructure: DWORD, + dwProviderVersion: DWORD, + dwStatus: DWORD, + dwCharacteristics: DWORD, + dwHandle: ULONG_PTR, + wNetType: WORD, + dwPrinters: DWORD, + dwDrives: DWORD, +}} +pub type LPNETINFOSTRUCT = *mut NETINFOSTRUCT; +pub const NETINFO_DLL16: DWORD = 0x00000001; +pub const NETINFO_DISKRED: DWORD = 0x00000004; +pub const NETINFO_PRINTERRED: DWORD = 0x00000008; +extern "system" { + pub fn WNetGetNetworkInformationA( + lpProvider: LPCSTR, + lpNetInfoStruct: LPNETINFOSTRUCT, + ) -> DWORD; + pub fn WNetGetNetworkInformationW( + lpProvider: LPCWSTR, + lpNetInfoStruct: LPNETINFOSTRUCT, + ) -> DWORD; + pub fn WNetGetLastErrorA( + lpError: LPDWORD, + lpErrorBuf: LPSTR, + nErrorBufSize: DWORD, + lpNameBuf: LPSTR, + nNameBufSize: DWORD, + ) -> DWORD; + pub fn WNetGetLastErrorW( + lpError: LPDWORD, + lpErrorBuf: LPWSTR, + nErrorBufSize: DWORD, + lpNameBuf: LPWSTR, + nNameBufSize: DWORD, + ) -> DWORD; +} +pub const WN_SUCCESS: DWORD = NO_ERROR; +pub const WN_NO_ERROR: DWORD = NO_ERROR; +pub const WN_NOT_SUPPORTED: DWORD = ERROR_NOT_SUPPORTED; +pub const WN_CANCEL: DWORD = ERROR_CANCELLED; +pub const WN_RETRY: DWORD = ERROR_RETRY; +pub const WN_NET_ERROR: DWORD = ERROR_UNEXP_NET_ERR; +pub const WN_MORE_DATA: DWORD = ERROR_MORE_DATA; +pub const WN_BAD_POINTER: DWORD = ERROR_INVALID_ADDRESS; +pub const WN_BAD_VALUE: DWORD = ERROR_INVALID_PARAMETER; +pub const WN_BAD_USER: DWORD = ERROR_BAD_USERNAME; +pub const WN_BAD_PASSWORD: DWORD = ERROR_INVALID_PASSWORD; +pub const WN_ACCESS_DENIED: DWORD = ERROR_ACCESS_DENIED; +pub const WN_FUNCTION_BUSY: DWORD = ERROR_BUSY; +pub const WN_WINDOWS_ERROR: DWORD = ERROR_UNEXP_NET_ERR; +pub const WN_OUT_OF_MEMORY: DWORD = ERROR_NOT_ENOUGH_MEMORY; +pub const WN_NO_NETWORK: DWORD = ERROR_NO_NETWORK; +pub const WN_EXTENDED_ERROR: DWORD = ERROR_EXTENDED_ERROR; +pub const WN_BAD_LEVEL: DWORD = ERROR_INVALID_LEVEL; +pub const WN_BAD_HANDLE: DWORD = ERROR_INVALID_HANDLE; +pub const WN_NOT_INITIALIZING: DWORD = ERROR_ALREADY_INITIALIZED; +pub const WN_NO_MORE_DEVICES: DWORD = ERROR_NO_MORE_DEVICES; +pub const WN_NOT_CONNECTED: DWORD = ERROR_NOT_CONNECTED; +pub const WN_OPEN_FILES: DWORD = ERROR_OPEN_FILES; +pub const WN_DEVICE_IN_USE: DWORD = ERROR_DEVICE_IN_USE; +pub const WN_BAD_NETNAME: DWORD = ERROR_BAD_NET_NAME; +pub const WN_BAD_LOCALNAME: DWORD = ERROR_BAD_DEVICE; +pub const WN_ALREADY_CONNECTED: DWORD = ERROR_ALREADY_ASSIGNED; +pub const WN_DEVICE_ERROR: DWORD = ERROR_GEN_FAILURE; +pub const WN_CONNECTION_CLOSED: DWORD = ERROR_CONNECTION_UNAVAIL; +pub const WN_NO_NET_OR_BAD_PATH: DWORD = ERROR_NO_NET_OR_BAD_PATH; +pub const WN_BAD_PROVIDER: DWORD = ERROR_BAD_PROVIDER; +pub const WN_CANNOT_OPEN_PROFILE: DWORD = ERROR_CANNOT_OPEN_PROFILE; +pub const WN_BAD_PROFILE: DWORD = ERROR_BAD_PROFILE; +pub const WN_BAD_DEV_TYPE: DWORD = ERROR_BAD_DEV_TYPE; +pub const WN_DEVICE_ALREADY_REMEMBERED: DWORD = ERROR_DEVICE_ALREADY_REMEMBERED; +pub const WN_CONNECTED_OTHER_PASSWORD: DWORD = ERROR_CONNECTED_OTHER_PASSWORD; +pub const WN_CONNECTED_OTHER_PASSWORD_DEFAULT: DWORD = ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT; +pub const WN_NO_MORE_ENTRIES: DWORD = ERROR_NO_MORE_ITEMS; +pub const WN_NOT_CONTAINER: DWORD = ERROR_NOT_CONTAINER; +pub const WN_NOT_AUTHENTICATED: DWORD = ERROR_NOT_AUTHENTICATED; +pub const WN_NOT_LOGGED_ON: DWORD = ERROR_NOT_LOGGED_ON; +pub const WN_NOT_VALIDATED: DWORD = ERROR_NO_LOGON_SERVERS; +STRUCT!{struct NETCONNECTINFOSTRUCT { + cbStructure: DWORD, + dwFlags: DWORD, + dwSpeed: DWORD, + dwDelay: DWORD, + dwOptDataSize: DWORD, +}} +pub type LPNETCONNECTINFOSTRUCT = *mut NETCONNECTINFOSTRUCT; +pub const WNCON_FORNETCARD: DWORD = 0x00000001; +pub const WNCON_NOTROUTED: DWORD = 0x00000002; +pub const WNCON_SLOWLINK: DWORD = 0x00000004; +pub const WNCON_DYNAMIC: DWORD = 0x00000008; +extern "system" { + pub fn MultinetGetConnectionPerformanceA( + lpNetResource: LPNETRESOURCEA, + lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT, + ) -> DWORD; + pub fn MultinetGetConnectionPerformanceW( + lpNetResource: LPNETRESOURCEW, + lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT, + ) -> DWORD; +} diff --git a/winapi/src/um/winnls.rs b/winapi/src/um/winnls.rs new file mode 100644 index 000000000..fd68a2354 --- /dev/null +++ b/winapi/src/um/winnls.rs @@ -0,0 +1,817 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Procedure declarations, constant definitions, and macros for the NLS component. +use ctypes::c_int; +use shared::basetsd::LONG_PTR; +use shared::guiddef::GUID; +use shared::minwindef::{ + BOOL, BYTE, DWORD, INT, LPARAM, LPDWORD, LPINT, LPVOID, LPWORD, MAX_PATH, PDWORD, PULONG, + UINT, +}; +use um::minwinbase::SYSTEMTIME; +use um::winnt::{ + CHAR, LANGID, LCID, LONG, LPCSTR, LPCWCH, LPCWSTR, LPSTR, LPWSTR, PCNZCH, PCNZWCH, PCWSTR, + PCZZWSTR, PULONGLONG, PWSTR, PZZWSTR, ULONGLONG, WCHAR, +}; +pub const MAX_LEADBYTES: usize = 12; +pub const MAX_DEFAULTCHAR: usize = 2; +pub const MB_PRECOMPOSED: DWORD = 0x00000001; +pub const MB_COMPOSITE: DWORD = 0x00000002; +pub const MB_USEGLYPHCHARS: DWORD = 0x00000004; +pub const MB_ERR_INVALID_CHARS: DWORD = 0x00000008; +pub const WC_COMPOSITECHECK: DWORD = 0x00000200; +pub const WC_DISCARDNS: DWORD = 0x00000010; +pub const WC_SEPCHARS: DWORD = 0x00000020; +pub const WC_DEFAULTCHAR: DWORD = 0x00000040; +pub const WC_ERR_INVALID_CHARS: DWORD = 0x00000080; +pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; +pub const CP_ACP: DWORD = 0; +pub const CP_OEMCP: DWORD = 1; +pub const CP_MACCP: DWORD = 2; +pub const CP_THREAD_ACP: DWORD = 3; +pub const CP_SYMBOL: DWORD = 42; +pub const CP_UTF7: DWORD = 65000; +pub const CP_UTF8: DWORD = 65001; +pub type LGRPID = DWORD; +pub type LCTYPE = DWORD; +pub type CALTYPE = DWORD; +pub type CALID = DWORD; +STRUCT!{struct CPINFO { + MaxCharSize: UINT, + DefaultChar: [BYTE; MAX_DEFAULTCHAR], + LeadByte: [BYTE; MAX_LEADBYTES], +}} +pub type LPCPINFO = *mut CPINFO; +STRUCT!{struct CPINFOEXA { + MaxCharSize: UINT, + DefaultChar: [BYTE; MAX_DEFAULTCHAR], + LeadByte: [BYTE; MAX_LEADBYTES], + UnicodeDefaultChar: WCHAR, + CodePage: UINT, + CodePageName: [CHAR; MAX_PATH], +}} +pub type LPCPINFOEXA = *mut CPINFOEXA; +STRUCT!{struct CPINFOEXW { + MaxCharSize: UINT, + DefaultChar: [BYTE; MAX_DEFAULTCHAR], + LeadByte: [BYTE; MAX_LEADBYTES], + UnicodeDefaultChar: WCHAR, + CodePage: UINT, + CodePageName: [WCHAR; MAX_PATH], +}} +pub type LPCPINFOEXW = *mut CPINFOEXW; +STRUCT!{struct NUMBERFMTA { + NumDigits: UINT, + LeadingZero: UINT, + Grouping: UINT, + lpDecimalSep: LPSTR, + lpThousandSep: LPSTR, + NegativeOrder: UINT, +}} +pub type LPNUMBERFMTA = *mut NUMBERFMTA; +STRUCT!{struct NUMBERFMTW { + NumDigits: UINT, + LeadingZero: UINT, + Grouping: UINT, + lpDecimalSep: LPWSTR, + lpThousandSep: LPWSTR, + NegativeOrder: UINT, +}} +pub type LPNUMBERFMTW = *mut NUMBERFMTW; +STRUCT!{struct CURRENCYFMTA { + NumDigits: UINT, + LeadingZero: UINT, + Grouping: UINT, + lpDecimalSep: LPSTR, + lpThousandSep: LPSTR, + NegativeOrder: UINT, + PositiveOrder: UINT, + lpCurrencySymbol: LPSTR, +}} +pub type LPCURRENCYFMTA = *mut CURRENCYFMTA; +STRUCT!{struct CURRENCYFMTW { + NumDigits: UINT, + LeadingZero: UINT, + Grouping: UINT, + lpDecimalSep: LPWSTR, + lpThousandSep: LPWSTR, + NegativeOrder: UINT, + PositiveOrder: UINT, + lpCurrencySymbol: LPWSTR, +}} +pub type LPCURRENCYFMTW = *mut CURRENCYFMTW; +pub type NLS_FUNCTION = DWORD; +STRUCT!{struct NLSVERSIONINFO { + dwNLSVersionInfoSize: DWORD, + dwNLSVersion: DWORD, + dwDefinedVersion: DWORD, + dwEffectiveId: DWORD, + guidCustomVersion: GUID, +}} +pub type LPNLSVERSIONINFO = *mut NLSVERSIONINFO; +STRUCT!{struct NLSVERSIONINFOEX { + dwNLSVersionInfoSize: DWORD, + dwNLSVersion: DWORD, + dwDefinedVersion: DWORD, + dwEffectiveId: DWORD, + guidCustomVersion: GUID, +}} +pub type LPNLSVERSIONINFOEX = *mut NLSVERSIONINFOEX; +pub type GEOID = LONG; +pub type GEOTYPE = DWORD; +pub type GEOCLASS = DWORD; +ENUM!{enum NORM_FORM { + NormalizationOther = 0, + NormalizationC = 0x1, + NormalizationD = 0x2, + NormalizationKC = 0x5, + NormalizationKD = 0x6, +}} +FN!{stdcall LANGUAGEGROUP_ENUMPROCA( + LGRPID, + LPSTR, + LPSTR, + DWORD, + LONG_PTR, +) -> BOOL} +FN!{stdcall LANGGROUPLOCALE_ENUMPROCA( + LGRPID, + LCID, + LPSTR, + LONG_PTR, +) -> BOOL} +FN!{stdcall UILANGUAGE_ENUMPROCA( + LPSTR, + LONG_PTR, +) -> BOOL} +FN!{stdcall CODEPAGE_ENUMPROCA( + LPSTR, +) -> BOOL} +FN!{stdcall DATEFMT_ENUMPROCA( + LPSTR, +) -> BOOL} +FN!{stdcall DATEFMT_ENUMPROCEXA( + LPSTR, + CALID, +) -> BOOL} +FN!{stdcall TIMEFMT_ENUMPROCA( + LPSTR, +) -> BOOL} +FN!{stdcall CALINFO_ENUMPROCA( + LPSTR, +) -> BOOL} +FN!{stdcall CALINFO_ENUMPROCEXA( + LPSTR, + CALID, +) -> BOOL} +FN!{stdcall LOCALE_ENUMPROCA( + LPSTR, +) -> BOOL} +FN!{stdcall LOCALE_ENUMPROCW( + LPWSTR, +) -> BOOL} +FN!{stdcall LANGUAGEGROUP_ENUMPROCW( + LGRPID, + LPWSTR, + LPWSTR, + DWORD, + LONG_PTR, +) -> BOOL} +FN!{stdcall LANGGROUPLOCALE_ENUMPROCW( + LGRPID, + LCID, + LPWSTR, + LONG_PTR, +) -> BOOL} +FN!{stdcall UILANGUAGE_ENUMPROCW( + LPWSTR, + LONG_PTR, +) -> BOOL} +FN!{stdcall CODEPAGE_ENUMPROCW( + LPWSTR, +) -> BOOL} +FN!{stdcall DATEFMT_ENUMPROCW( + LPWSTR, +) -> BOOL} +FN!{stdcall DATEFMT_ENUMPROCEXW( + LPWSTR, + CALID, +) -> BOOL} +FN!{stdcall TIMEFMT_ENUMPROCW( + LPWSTR, +) -> BOOL} +FN!{stdcall CALINFO_ENUMPROCW( + LPWSTR, +) -> BOOL} +FN!{stdcall CALINFO_ENUMPROCEXW( + LPWSTR, + CALID, +) -> BOOL} +FN!{stdcall GEO_ENUMPROC( + GEOID, +) -> BOOL} +STRUCT!{struct FILEMUIINFO { + dwSize: DWORD, + dwVersion: DWORD, + dwFileType: DWORD, + pChecksum: [BYTE; 16], + pServiceChecksum: [BYTE; 16], + dwLanguageNameOffset: DWORD, + dwTypeIDMainSize: DWORD, + dwTypeIDMainOffset: DWORD, + dwTypeNameMainOffset: DWORD, + dwTypeIDMUISize: DWORD, + dwTypeIDMUIOffset: DWORD, + dwTypeNameMUIOffset: DWORD, + abBuffer: [BYTE; 8], +}} +pub type PFILEMUIINFO = *mut FILEMUIINFO; +FN!{stdcall CALINFO_ENUMPROCEXEX( + LPWSTR, + CALID, + LPWSTR, + LPARAM, +) -> BOOL} +FN!{stdcall DATEFMT_ENUMPROCEXEX( + LPWSTR, + CALID, + LPARAM, +) -> BOOL} +FN!{stdcall TIMEFMT_ENUMPROCEX( + LPWSTR, + LPARAM, +) -> BOOL} +FN!{stdcall LOCALE_ENUMPROCEX( + LPWSTR, + DWORD, + LPARAM, +) -> BOOL} +extern "system" { + pub fn CompareStringA( + Locale: LCID, + dwCmpFlags: DWORD, + lpString1: PCNZCH, + cchCount1: c_int, + lpString2: PCNZCH, + cchCount2: c_int, + ) -> c_int; + pub fn CompareStringEx( + lpLocaleName: LPCWSTR, + dwCmpFlags: DWORD, + lpString1: LPCWCH, + cchCount1: c_int, + lpString2: LPCWCH, + cchCount2: c_int, + lpVersionInformation: LPNLSVERSIONINFO, + lpReserved: LPVOID, + lParam: LPARAM, + ) -> c_int; + pub fn CompareStringW( + Locale: LCID, + dwCmpFlags: DWORD, + lpString1: PCNZWCH, + cchCount1: c_int, + lpString2: PCNZWCH, + cchCount2: c_int, + ) -> c_int; + pub fn ConvertDefaultLocale(Locale: LCID) -> LCID; + pub fn EnumCalendarInfoA( + lpCalInfoEnumProc: CALINFO_ENUMPROCA, + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + ) -> BOOL; + pub fn EnumCalendarInfoExA( + lpCalInfoEnumProcEx: CALINFO_ENUMPROCEXA, + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + ) -> BOOL; + pub fn EnumCalendarInfoExEx( + pCalInfoEnumProcExEx: CALINFO_ENUMPROCEXEX, + lpLocaleName: LPCWSTR, + Calendar: CALID, + lpReserved: LPCWSTR, + CalType: CALTYPE, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumCalendarInfoExW( + lpCalInfoEnumProcEx: CALINFO_ENUMPROCEXW, + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + ) -> BOOL; + pub fn EnumCalendarInfoW( + lpCalInfoEnumProc: CALINFO_ENUMPROCW, + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + ) -> BOOL; + pub fn EnumDateFormatsA( + lpDateFmtEnumProc: DATEFMT_ENUMPROCA, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDateFormatsExA( + lpDateFmtEnumProcEx: DATEFMT_ENUMPROCEXA, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDateFormatsExEx( + lpDateFmtEnumProcExEx: DATEFMT_ENUMPROCEXEX, + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumDateFormatsExW( + lpDateFmtEnumProcEx: DATEFMT_ENUMPROCEXW, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDateFormatsW( + lpDateFmtEnumProc: DATEFMT_ENUMPROCW, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumLanguageGroupLocalesA( + lpLangGroupLocaleEnumProc: LANGGROUPLOCALE_ENUMPROCA, + LanguageGroup: LGRPID, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumLanguageGroupLocalesW( + lpLangGroupLocaleEnumProc: LANGGROUPLOCALE_ENUMPROCW, + LanguageGroup: LGRPID, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumSystemCodePagesA( + lpCodePageEnumProc: CODEPAGE_ENUMPROCA, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumSystemCodePagesW( + lpCodePageEnumProc: CODEPAGE_ENUMPROCW, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumSystemGeoID( + GeoClass: GEOCLASS, + ParentGeoId: GEOID, + lpGeoEnumProc: GEO_ENUMPROC, + ) -> BOOL; + pub fn EnumSystemLanguageGroupsA( + lpLanguageGroupEnumProc: LANGUAGEGROUP_ENUMPROCA, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumSystemLanguageGroupsW( + lpLanguageGroupEnumProc: LANGUAGEGROUP_ENUMPROCW, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumSystemLocalesA( + lpLocaleEnumProc: LOCALE_ENUMPROCA, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumSystemLocalesEx( + lpLocaleEnumProcEx: LOCALE_ENUMPROCEX, + dwFlags: DWORD, + lParam: LPARAM, + lpReserved: LPVOID, + ) -> BOOL; + pub fn EnumSystemLocalesW( + lpLocaleEnumProc: LOCALE_ENUMPROCW, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumTimeFormatsA( + lpTimeFmtEnumProc: TIMEFMT_ENUMPROCA, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumTimeFormatsEx( + lpTimeFmtEnumProcEx: TIMEFMT_ENUMPROCEX, + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumTimeFormatsW( + lpTimeFmtEnumProc: TIMEFMT_ENUMPROCW, + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumUILanguagesA( + lpUILanguageEnumProc: UILANGUAGE_ENUMPROCA, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn EnumUILanguagesW( + lpUILanguageEnumProc: UILANGUAGE_ENUMPROCW, + dwFlags: DWORD, + lParam: LONG_PTR, + ) -> BOOL; + pub fn FindNLSString( + Locale: LCID, + dwFindNLSStringFlags: DWORD, + lpStringSource: LPCWSTR, + cchSource: c_int, + lpStringValue: LPCWSTR, + cchValue: c_int, + pcchFound: LPINT, + ) -> c_int; + pub fn FindNLSStringEx( + lpLocaleName: LPCWSTR, + dwFindNLSStringFlags: DWORD, + lpStringSource: LPCWSTR, + cchSource: c_int, + lpStringValue: LPCWSTR, + cchValue: c_int, + pcchFound: LPINT, + lpVersionInformation: LPNLSVERSIONINFO, + lpReserved: LPVOID, + sortHandle: LPARAM, + ) -> c_int; + pub fn FoldStringA( + dwMapFlags: DWORD, + lpSrcStr: LPCSTR, + cchSrc: c_int, + lpDestStr: LPSTR, + cchDest: c_int, + ) -> c_int; + pub fn GetACP() -> UINT; + pub fn GetCPInfo( + CodePage: UINT, + lpCPInfo: LPCPINFO, + ) -> BOOL; + pub fn GetCPInfoExA( + CodePage: UINT, + dwFlags: DWORD, + lpCPInfoEx: LPCPINFOEXA, + ) -> BOOL; + pub fn GetCPInfoExW( + CodePage: UINT, + dwFlags: DWORD, + lpCPInfoEx: LPCPINFOEXW, + ) -> BOOL; + pub fn GetCalendarInfoA( + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + lpCalData: LPSTR, + cchData: c_int, + lpValue: LPDWORD, + ) -> c_int; + pub fn GetCalendarInfoEx( + lpLocaleName: LPCWSTR, + Calendar: CALID, + lpReserved: LPCWSTR, + CalType: CALTYPE, + lpCalData: LPWSTR, + cchData: c_int, + lpValue: LPDWORD, + ) -> c_int; + pub fn GetCalendarInfoW( + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + lpCalData: LPWSTR, + cchData: c_int, + lpValue: LPDWORD, + ) -> c_int; + pub fn GetCurrencyFormatA( + Locale: LCID, + dwFlags: DWORD, + lpValue: LPCSTR, + lpFormat: *const CURRENCYFMTA, + lpCurrencyStr: LPSTR, + cchCurrency: c_int, + ) -> c_int; + pub fn GetCurrencyFormatEx( + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lpValue: LPCWSTR, + lpFormat: *const CURRENCYFMTW, + lpCurrencyStr: LPWSTR, + cchCurrency: c_int, + ) -> c_int; + pub fn GetCurrencyFormatW( + Locale: LCID, + dwFlags: DWORD, + lpValue: LPCWSTR, + lpFormat: *const CURRENCYFMTW, + lpCurrencyStr: LPWSTR, + cchCurrency: c_int, + ) -> c_int; + pub fn GetDurationFormat( + Locale: LCID, + dwFlags: DWORD, + lpDuration: *const SYSTEMTIME, + ullDuration: ULONGLONG, + lpFormat: LPCWSTR, + lpDurationStr: LPWSTR, + cchDuration: c_int, + ) -> c_int; + pub fn GetDurationFormatEx( + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lpDuration: *const SYSTEMTIME, + ullDuration: ULONGLONG, + lpFormat: LPCWSTR, + lpDurationStr: LPWSTR, + cchDuration: c_int, + ) -> c_int; + pub fn GetFileMUIInfo( + dwFlags: DWORD, + pcwszFilePath: PCWSTR, + pFileMUIInfo: PFILEMUIINFO, + pcbFileMUIInfo: *mut DWORD, + ) -> BOOL; + pub fn GetFileMUIPath( + dwFlags: DWORD, + pcwszFilePath: PCWSTR, + pwszLanguage: PWSTR, + pcchLanguage: PULONG, + pwszFileMUIPath: PWSTR, + pcchFileMUIPath: PULONG, + pululEnumerator: PULONGLONG, + ) -> BOOL; + pub fn GetGeoInfoA( + Location: GEOID, + GeoType: GEOTYPE, + lpGeoData: LPSTR, + cchData: c_int, + LangId: LANGID, + ) -> c_int; + pub fn GetGeoInfoW( + Location: GEOID, + GeoType: GEOTYPE, + lpGeoData: LPWSTR, + cchData: c_int, + LangId: LANGID, + ) -> c_int; + pub fn GetLocaleInfoA( + Locale: LCID, + LCType: LCTYPE, + lpLCData: LPSTR, + cchData: c_int, + ) -> c_int; + pub fn GetLocaleInfoEx( + lpLocaleName: LPCWSTR, + LCType: LCTYPE, + lpLCData: LPWSTR, + cchData: c_int, + ) -> c_int; + pub fn GetLocaleInfoW( + Locale: LCID, + LCType: LCTYPE, + lpLCData: LPWSTR, + cchData: c_int, + ) -> c_int; + pub fn GetNLSVersion( + Function: NLS_FUNCTION, + Locale: LCID, + lpVersionInformation: LPNLSVERSIONINFO, + ) -> BOOL; + pub fn GetNLSVersionEx( + function: NLS_FUNCTION, + lpLocaleName: LPCWSTR, + lpVersionInformation: LPNLSVERSIONINFOEX, + ) -> BOOL; + pub fn GetNumberFormatA( + Locale: LCID, + dwFlags: DWORD, + lpValue: LPCSTR, + lpFormat: *const NUMBERFMTA, + lpNumberStr: LPSTR, + cchNumber: c_int, + ) -> c_int; + pub fn GetNumberFormatEx( + lpLocaleName: LPCWSTR, + dwFlags: DWORD, + lpValue: LPCWSTR, + lpFormat: *const NUMBERFMTW, + lpNumberStr: LPWSTR, + cchNumber: c_int, + ) -> c_int; + pub fn GetNumberFormatW( + Locale: LCID, + dwFlags: DWORD, + lpValue: LPCWSTR, + lpFormat: *const NUMBERFMTW, + lpNumberStr: LPWSTR, + cchNumber: c_int, + ) -> c_int; + pub fn GetOEMCP() -> UINT; + pub fn GetProcessPreferredUILanguages( + dwFlags: DWORD, + pulNumLanguages: PULONG, + pwszLanguagesBuffer: PZZWSTR, + pcchLanguagesBuffer: PULONG, + ) -> BOOL; + pub fn GetStringScripts( + dwFlags: DWORD, + lpString: LPCWSTR, + cchString: c_int, + lpScripts: LPWSTR, + cchScripts: c_int, + ) -> c_int; + pub fn GetStringTypeA( + Locale: LCID, + dwInfoType: DWORD, + lpSrcStr: LPCSTR, + cchSrc: c_int, + lpCharType: LPWORD, + ) -> BOOL; + pub fn GetStringTypeExA( + Locale: LCID, + dwInfoType: DWORD, + lpSrcStr: LPCSTR, + cchSrc: c_int, + lpCharType: LPWORD, + ) -> BOOL; + pub fn GetStringTypeW( + dwInfoType: DWORD, + lpSrcStr: LPCWCH, + cchSrc: c_int, + lpCharType: LPWORD, + ) -> BOOL; + pub fn GetSystemDefaultLCID() -> LCID; + pub fn GetSystemDefaultLangID() -> LANGID; + pub fn GetSystemDefaultLocaleName( + lpLocaleName: LPWSTR, + cchLocaleName: c_int, + ) -> c_int; + pub fn GetSystemDefaultUILanguage() -> LANGID; + pub fn GetSystemPreferredUILanguages( + dwFlags: DWORD, + pulNumLanguages: PULONG, + pwszLanguagesBuffer: PZZWSTR, + pcchLanguagesBuffer: PULONG, + ) -> BOOL; + pub fn GetThreadLocale() -> LCID; + pub fn GetThreadPreferredUILanguages( + dwFlags: DWORD, + pulNumLanguages: PULONG, + pwszLanguagesBuffer: PZZWSTR, + pcchLanguagesBuffer: PULONG, + ) -> BOOL; + pub fn GetThreadUILanguage() -> LANGID; + pub fn GetUILanguageInfo( + dwFlags: DWORD, + pwmszLanguage: PCZZWSTR, + pwszFallbackLanguages: PZZWSTR, + pcchFallbackLanguages: PDWORD, + pAttributes: PDWORD, + ) -> BOOL; + pub fn GetUserDefaultLCID() -> LCID; + pub fn GetUserDefaultLangID() -> LANGID; + pub fn GetUserDefaultLocaleName( + lpLocaleName: LPWSTR, + cchLocaleName: c_int, + ) -> c_int; + pub fn GetUserDefaultUILanguage() -> LANGID; + pub fn GetUserGeoID(GeoClass: GEOCLASS) -> GEOID; + pub fn GetUserPreferredUILanguages( + dwFlags: DWORD, + pulNumLanguages: PULONG, + pwszLanguagesBuffer: PZZWSTR, + pcchLanguagesBuffer: PULONG, + ) -> BOOL; + pub fn IsDBCSLeadByte( + TestChar: BYTE, + ) -> BOOL; + pub fn IsDBCSLeadByteEx( + CodePage: UINT, + TestChar: BYTE, + ) -> BOOL; + pub fn IsNLSDefinedString( + Function: NLS_FUNCTION, + dwFlags: DWORD, + lpVersionInformation: LPNLSVERSIONINFO, + lpString: LPCWSTR, + cchStr: INT, + ) -> BOOL; + pub fn IsNormalizedString( + NormForm: NORM_FORM, + lpString: LPCWSTR, + cwLength: c_int, + ) -> BOOL; + pub fn IsValidCodePage( + CodePage: UINT, + ) -> BOOL; + pub fn IsValidLanguageGroup( + LanguageGroup: LGRPID, + dwFlags: DWORD, + ) -> BOOL; + pub fn IsValidLocale( + Locale: LCID, + dwFlags: DWORD, + ) -> BOOL; + pub fn IsValidLocaleName( + lpLocaleName: LPCWSTR, + ) -> BOOL; + pub fn IsValidNLSVersion( + function: NLS_FUNCTION, + lpLocaleName: LPCWSTR, + lpVersionInformation: LPNLSVERSIONINFOEX, + ) -> BOOL; + pub fn LCIDToLocaleName( + Locale: LCID, + lpName: LPWSTR, + cchName: c_int, + dwFlags: DWORD, + ) -> c_int; + pub fn LCMapStringA( + Locale: LCID, + dwMapFlags: DWORD, + lpSrcStr: LPCSTR, + cchSrc: c_int, + lpDestStr: LPSTR, + cchDest: c_int, + ) -> c_int; + pub fn LCMapStringEx( + lpLocaleName: LPCWSTR, + dwMapFlags: DWORD, + lpSrcStr: LPCWSTR, + cchSrc: c_int, + lpDestStr: LPWSTR, + cchDest: c_int, + lpVersionInformation: LPNLSVERSIONINFO, + lpReserved: LPVOID, + sortHandle: LPARAM, + ) -> c_int; + pub fn LCMapStringW( + Locale: LCID, + dwMapFlags: DWORD, + lpSrcStr: LPCWSTR, + cchSrc: c_int, + lpDestStr: LPWSTR, + cchDest: c_int, + ) -> c_int; + pub fn LocaleNameToLCID( + lpName: LPCWSTR, + dwFlags: DWORD, + ) -> LCID; + pub fn NormalizeString( + NormForm: NORM_FORM, + lpSrcString: LPCWSTR, + cwSrcLength: c_int, + lpDstString: LPWSTR, + cwDstLength: c_int, + ) -> c_int; + pub fn NotifyUILanguageChange( + dwFlags: DWORD, + pcwstrNewLanguage: PCWSTR, + pcwstrPreviousLanguage: PCWSTR, + dwReserved: DWORD, + pdwStatusRtrn: PDWORD, + ) -> BOOL; + pub fn ResolveLocaleName( + lpNameToResolve: LPCWSTR, + lpLocaleName: LPWSTR, + cchLocaleName: c_int, + ) -> c_int; + pub fn SetCalendarInfoA( + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + lpCalData: LPCSTR, + ) -> BOOL; + pub fn SetCalendarInfoW( + Locale: LCID, + Calendar: CALID, + CalType: CALTYPE, + lpCalData: LPCWSTR, + ) -> BOOL; + pub fn SetLocaleInfoA( + Locale: LCID, + LCType: LCTYPE, + lpLCData: LPCSTR, + ) -> BOOL; + pub fn SetLocaleInfoW( + Locale: LCID, + LCType: LCTYPE, + lpLCData: LPCWSTR, + ) -> BOOL; + pub fn SetProcessPreferredUILanguages( + dwFlags: DWORD, + pwszLanguagesBuffer: PCZZWSTR, + pulNumLanguages: PULONG, + ) -> BOOL; + pub fn SetThreadLocale(Locale: LCID) -> BOOL; + pub fn SetThreadPreferredUILanguages( + dwFlags: DWORD, + pwszLanguagesBuffer: PCZZWSTR, + pulNumLanguages: PULONG, + ) -> BOOL; + pub fn SetThreadUILanguage(LangId: LANGID) -> LANGID; + pub fn SetUserGeoID(GeoId: GEOID) -> BOOL; + pub fn VerifyScripts( + dwFlags: DWORD, + lpLocaleScripts: LPCWSTR, + cchLocaleScripts: c_int, + lpTestScripts: LPCWSTR, + cchTestScripts: c_int, + ) -> BOOL; +} diff --git a/winapi/src/um/winnt.rs b/winapi/src/um/winnt.rs new file mode 100644 index 000000000..ecf7bea04 --- /dev/null +++ b/winapi/src/um/winnt.rs @@ -0,0 +1,8622 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This module defines the 32-Bit Windows types and constants that are defined by NT, but exposed +//! through the Win32 API. +use ctypes::{__int64, __uint64, c_char, c_int, c_long, c_short, c_uint, c_ulong, c_void, wchar_t}; +use shared::basetsd::{ + DWORD64, KAFFINITY, LONG64, LONG_PTR, PDWORD64, PLONG64, SIZE_T, ULONG64, ULONG_PTR, +}; +use shared::guiddef::{CLSID, GUID}; +use shared::ktmtypes::UOW; +use shared::minwindef::{BYTE, DWORD, FALSE, PDWORD, TRUE, ULONG, USHORT, WORD}; +#[cfg(target_arch = "aarch64")] +use shared::minwindef::PBYTE; +use vc::excpt::EXCEPTION_DISPOSITION; +use vc::vcruntime::size_t; +pub const ANYSIZE_ARRAY: usize = 1; +#[cfg(target_arch = "x86")] +IFDEF!{ +pub const MAX_NATURAL_ALIGNMENT: usize = 4; +pub const MEMORY_ALLOCATION_ALIGNMENT: usize = 8; +} +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub const MAX_NATURAL_ALIGNMENT: usize = 8; +pub const MEMORY_ALLOCATION_ALIGNMENT: usize = 16; +} +pub const SYSTEM_CACHE_ALIGNMENT_SIZE: usize = 64; +pub type PVOID = *mut c_void; +pub type PVOID64 = u64; // This is a 64-bit pointer, even when in 32-bit +pub type VOID = c_void; +pub type CHAR = c_char; +pub type SHORT = c_short; +pub type LONG = c_long; +pub type INT = c_int; +pub type WCHAR = wchar_t; +pub type PWCHAR = *mut WCHAR; +pub type LPWCH = *mut WCHAR; +pub type PWCH = *mut WCHAR; +pub type LPCWCH = *const WCHAR; +pub type PCWCH = *const WCHAR; +pub type NWPSTR = *mut WCHAR; +pub type LPWSTR = *mut WCHAR; +pub type PWSTR = *mut WCHAR; +pub type PZPWSTR = *mut PWSTR; +pub type PCZPWSTR = *const PWSTR; +pub type LPUWSTR = *mut WCHAR; // Unaligned pointer +pub type PUWSTR = *mut WCHAR; // Unaligned pointer +pub type LPCWSTR = *const WCHAR; +pub type PCWSTR = *const WCHAR; +pub type PZPCWSTR = *mut PCWSTR; +pub type PCZPCWSTR = *const PCWSTR; +pub type LPCUWSTR = *const WCHAR; // Unaligned pointer +pub type PCUWSTR = *const WCHAR; // Unaligned pointer +pub type PZZWSTR = *mut WCHAR; +pub type PCZZWSTR = *const WCHAR; +pub type PUZZWSTR = *mut WCHAR; // Unaligned pointer +pub type PCUZZWSTR = *const WCHAR; // Unaligned pointer +pub type PNZWCH = *mut WCHAR; +pub type PCNZWCH = *const WCHAR; +pub type PUNZWCH = *mut WCHAR; // Unaligned pointer +pub type PCUNZWCH = *const WCHAR; // Unaligned pointer +pub type LPCWCHAR = *const WCHAR; +pub type PCWCHAR = *const WCHAR; +pub type LPCUWCHAR = *const WCHAR; // Unaligned pointer +pub type PCUWCHAR = *const WCHAR; // Unaligned pointer +pub type UCSCHAR = c_ulong; +pub const UCSCHAR_INVALID_CHARACTER: UCSCHAR = 0xffffffff; +pub const MIN_UCSCHAR: UCSCHAR = 0; +pub const MAX_UCSCHAR: UCSCHAR = 0x0010FFFF; +pub type PUCSCHAR = *mut UCSCHAR; +pub type PCUCSCHAR = *const UCSCHAR; +pub type PUCSSTR = *mut UCSCHAR; +pub type PUUCSSTR = *mut UCSCHAR; // Unaligned pointer +pub type PCUCSSTR = *const UCSCHAR; +pub type PCUUCSSTR = *const UCSCHAR; // Unaligned pointer +pub type PUUCSCHAR = *mut UCSCHAR; // Unaligned pointer +pub type PCUUCSCHAR = *const UCSCHAR; // Unaligned pointer +pub type PCHAR = *mut CHAR; +pub type LPCH = *mut CHAR; +pub type PCH = *mut CHAR; +pub type LPCCH = *const CHAR; +pub type PCCH = *const CHAR; +pub type NPSTR = *mut CHAR; +pub type LPSTR = *mut CHAR; +pub type PSTR = *mut CHAR; +pub type PZPSTR = *mut PSTR; +pub type PCZPSTR = *const PSTR; +pub type LPCSTR = *const CHAR; +pub type PCSTR = *const CHAR; +pub type PZPCSTR = *mut PCSTR; +pub type PCZPCSTR = *const PCSTR; +pub type PZZSTR = *mut CHAR; +pub type PCZZSTR = *const CHAR; +pub type PNZCH = *mut CHAR; +pub type PCNZCH = *const CHAR; +// Skipping TCHAR things +pub type PSHORT = *mut SHORT; +pub type PLONG = *mut LONG; +pub const ALL_PROCESSOR_GROUPS: WORD = 0xffff; +STRUCT!{struct PROCESSOR_NUMBER { + Group: WORD, + Number: BYTE, + Reserved: BYTE, +}} +pub type PPROCESSOR_NUMBER = *mut PROCESSOR_NUMBER; +STRUCT!{struct GROUP_AFFINITY { + Mask: KAFFINITY, + Group: WORD, + Reserved: [WORD; 3], +}} +pub type PGROUP_AFFINITY = *mut GROUP_AFFINITY; +#[cfg(target_arch = "x86")] +pub const MAXIMUM_PROC_PER_GROUP: BYTE = 32; +#[cfg(target_pointer_width = "64")] +pub const MAXIMUM_PROC_PER_GROUP: BYTE = 64; +pub const MAXIMUM_PROCESSORS: BYTE = MAXIMUM_PROC_PER_GROUP; +pub type HANDLE = *mut c_void; +pub type PHANDLE = *mut HANDLE; +pub type FCHAR = BYTE; +pub type FSHORT = WORD; +pub type FLONG = DWORD; +pub type HRESULT = c_long; +pub type CCHAR = c_char; +pub type LCID = DWORD; +pub type PLCID = PDWORD; +pub type LANGID = WORD; +ENUM!{enum COMPARTMENT_ID { + UNSPECIFIED_COMPARTMENT_ID = 0, + DEFAULT_COMPARTMENT_ID, +}} +pub type PCOMPARTMENT_ID = *mut COMPARTMENT_ID; +pub const APPLICATION_ERROR_MASK: DWORD = 0x20000000; +pub const ERROR_SEVERITY_SUCCESS: DWORD = 0x00000000; +pub const ERROR_SEVERITY_INFORMATIONAL: DWORD = 0x40000000; +pub const ERROR_SEVERITY_WARNING: DWORD = 0x80000000; +pub const ERROR_SEVERITY_ERROR: DWORD = 0xC0000000; +STRUCT!{struct FLOAT128 { + LowPart: __int64, + HighPart: __int64, +}} +pub type PFLOAT128 = *mut FLOAT128; +pub type LONGLONG = __int64; +pub type ULONGLONG = __uint64; +pub const MAXLONGLONG: LONGLONG = 0x7fffffffffffffff; +pub type PLONGLONG = *mut LONGLONG; +pub type PULONGLONG = *mut ULONGLONG; +pub type USN = LONGLONG; +STRUCT!{struct LARGE_INTEGER_u { + LowPart: DWORD, + HighPart: LONG, +}} +UNION!{union LARGE_INTEGER { + [u64; 1], + QuadPart QuadPart_mut: LONGLONG, + u u_mut: LARGE_INTEGER_u, +}} +pub type PLARGE_INTEGER = *mut LARGE_INTEGER; +STRUCT!{struct ULARGE_INTEGER_u { + LowPart: DWORD, + HighPart: LONG, +}} +UNION!{union ULARGE_INTEGER { + [u64; 1], + QuadPart QuadPart_mut: ULONGLONG, + u u_mut: ULARGE_INTEGER_u, +}} +pub type PULARGE_INTEGER = *mut ULARGE_INTEGER; +pub type RTL_REFERENCE_COUNT = LONG_PTR; +pub type PRTL_REFERENCE_COUNT = *mut LONG_PTR; +pub type RTL_REFERENCE_COUNT32 = LONG; +pub type PRTL_REFERENCE_COUNT32 = *mut LONG; +pub use shared::ntdef::LUID; +pub type PLUID = *mut LUID; +pub type DWORDLONG = ULONGLONG; +pub type PDWORDLONG = *mut DWORDLONG; +pub const ANSI_NULL: CHAR = 0; +pub const UNICODE_NULL: WCHAR = 0; +pub const UNICODE_STRING_MAX_BYTES: WORD = 65534; +pub const UNICODE_STRING_MAX_CHARS: WORD = 32767; +pub type BOOLEAN = BYTE; +pub type PBOOLEAN = *mut BOOLEAN; +STRUCT!{struct LIST_ENTRY { + Flink: *mut LIST_ENTRY, + Blink: *mut LIST_ENTRY, +}} +pub type PLIST_ENTRY = *mut LIST_ENTRY; +pub type PRLIST_ENTRY = *mut LIST_ENTRY; // Restricted pointer +STRUCT!{struct SINGLE_LIST_ENTRY { + Next: *mut SINGLE_LIST_ENTRY, +}} +pub type PSINGLE_LIST_ENTRY = *mut SINGLE_LIST_ENTRY; +STRUCT!{struct LIST_ENTRY32 { + Flink: DWORD, + Blink: DWORD, +}} +pub type PLIST_ENTRY32 = *mut LIST_ENTRY32; +STRUCT!{struct LIST_ENTRY64 { + Flink: ULONGLONG, + Blink: ULONGLONG, +}} +pub type PLIST_ENTRY64 = *mut LIST_ENTRY64; +STRUCT!{struct OBJECTID { + Lineage: GUID, + Uniquifier: DWORD, +}} +pub const MINCHAR: CHAR = 0x80; +pub const MAXCHAR: CHAR = 0x7f; +pub const MINSHORT: SHORT = 0x8000; +pub const MAXSHORT: SHORT = 0x7fff; +pub const MINLONG: LONG = 0x80000000; +pub const MAXLONG: LONG = 0x7fffffff; +pub const MAXBYTE: BYTE = 0xff; +pub const MAXWORD: WORD = 0xffff; +pub const MAXDWORD: DWORD = 0xffffffff; +FN!{stdcall PEXCEPTION_ROUTINE( + ExceptionRecord: *mut EXCEPTION_RECORD, + EstablisherFrame: PVOID, + ContextRecord: *mut CONTEXT, + DispatcherContext: PVOID, +) -> EXCEPTION_DISPOSITION} +pub const VER_SERVER_NT: DWORD = 0x80000000; +pub const VER_WORKSTATION_NT: DWORD = 0x40000000; +pub const VER_SUITE_SMALLBUSINESS: DWORD = 0x00000001; +pub const VER_SUITE_ENTERPRISE: DWORD = 0x00000002; +pub const VER_SUITE_BACKOFFICE: DWORD = 0x00000004; +pub const VER_SUITE_COMMUNICATIONS: DWORD = 0x00000008; +pub const VER_SUITE_TERMINAL: DWORD = 0x00000010; +pub const VER_SUITE_SMALLBUSINESS_RESTRICTED: DWORD = 0x00000020; +pub const VER_SUITE_EMBEDDEDNT: DWORD = 0x00000040; +pub const VER_SUITE_DATACENTER: DWORD = 0x00000080; +pub const VER_SUITE_SINGLEUSERTS: DWORD = 0x00000100; +pub const VER_SUITE_PERSONAL: DWORD = 0x00000200; +pub const VER_SUITE_BLADE: DWORD = 0x00000400; +pub const VER_SUITE_EMBEDDED_RESTRICTED: DWORD = 0x00000800; +pub const VER_SUITE_SECURITY_APPLIANCE: DWORD = 0x00001000; +pub const VER_SUITE_STORAGE_SERVER: DWORD = 0x00002000; +pub const VER_SUITE_COMPUTE_SERVER: DWORD = 0x00004000; +pub const VER_SUITE_WH_SERVER: DWORD = 0x00008000; +pub const PRODUCT_UNDEFINED: DWORD = 0x00000000; +pub const PRODUCT_ULTIMATE: DWORD = 0x00000001; +pub const PRODUCT_HOME_BASIC: DWORD = 0x00000002; +pub const PRODUCT_HOME_PREMIUM: DWORD = 0x00000003; +pub const PRODUCT_ENTERPRISE: DWORD = 0x00000004; +pub const PRODUCT_HOME_BASIC_N: DWORD = 0x00000005; +pub const PRODUCT_BUSINESS: DWORD = 0x00000006; +pub const PRODUCT_STANDARD_SERVER: DWORD = 0x00000007; +pub const PRODUCT_DATACENTER_SERVER: DWORD = 0x00000008; +pub const PRODUCT_SMALLBUSINESS_SERVER: DWORD = 0x00000009; +pub const PRODUCT_ENTERPRISE_SERVER: DWORD = 0x0000000A; +pub const PRODUCT_STARTER: DWORD = 0x0000000B; +pub const PRODUCT_DATACENTER_SERVER_CORE: DWORD = 0x0000000C; +pub const PRODUCT_STANDARD_SERVER_CORE: DWORD = 0x0000000D; +pub const PRODUCT_ENTERPRISE_SERVER_CORE: DWORD = 0x0000000E; +pub const PRODUCT_ENTERPRISE_SERVER_IA64: DWORD = 0x0000000F; +pub const PRODUCT_BUSINESS_N: DWORD = 0x00000010; +pub const PRODUCT_WEB_SERVER: DWORD = 0x00000011; +pub const PRODUCT_CLUSTER_SERVER: DWORD = 0x00000012; +pub const PRODUCT_HOME_SERVER: DWORD = 0x00000013; +pub const PRODUCT_STORAGE_EXPRESS_SERVER: DWORD = 0x00000014; +pub const PRODUCT_STORAGE_STANDARD_SERVER: DWORD = 0x00000015; +pub const PRODUCT_STORAGE_WORKGROUP_SERVER: DWORD = 0x00000016; +pub const PRODUCT_STORAGE_ENTERPRISE_SERVER: DWORD = 0x00000017; +pub const PRODUCT_SERVER_FOR_SMALLBUSINESS: DWORD = 0x00000018; +pub const PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: DWORD = 0x00000019; +pub const PRODUCT_HOME_PREMIUM_N: DWORD = 0x0000001A; +pub const PRODUCT_ENTERPRISE_N: DWORD = 0x0000001B; +pub const PRODUCT_ULTIMATE_N: DWORD = 0x0000001C; +pub const PRODUCT_WEB_SERVER_CORE: DWORD = 0x0000001D; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: DWORD = 0x0000001E; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: DWORD = 0x0000001F; +pub const PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: DWORD = 0x00000020; +pub const PRODUCT_SERVER_FOUNDATION: DWORD = 0x00000021; +pub const PRODUCT_HOME_PREMIUM_SERVER: DWORD = 0x00000022; +pub const PRODUCT_SERVER_FOR_SMALLBUSINESS_V: DWORD = 0x00000023; +pub const PRODUCT_STANDARD_SERVER_V: DWORD = 0x00000024; +pub const PRODUCT_DATACENTER_SERVER_V: DWORD = 0x00000025; +pub const PRODUCT_ENTERPRISE_SERVER_V: DWORD = 0x00000026; +pub const PRODUCT_DATACENTER_SERVER_CORE_V: DWORD = 0x00000027; +pub const PRODUCT_STANDARD_SERVER_CORE_V: DWORD = 0x00000028; +pub const PRODUCT_ENTERPRISE_SERVER_CORE_V: DWORD = 0x00000029; +pub const PRODUCT_HYPERV: DWORD = 0x0000002A; +pub const PRODUCT_STORAGE_EXPRESS_SERVER_CORE: DWORD = 0x0000002B; +pub const PRODUCT_STORAGE_STANDARD_SERVER_CORE: DWORD = 0x0000002C; +pub const PRODUCT_STORAGE_WORKGROUP_SERVER_CORE: DWORD = 0x0000002D; +pub const PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE: DWORD = 0x0000002E; +pub const PRODUCT_STARTER_N: DWORD = 0x0000002F; +pub const PRODUCT_PROFESSIONAL: DWORD = 0x00000030; +pub const PRODUCT_PROFESSIONAL_N: DWORD = 0x00000031; +pub const PRODUCT_SB_SOLUTION_SERVER: DWORD = 0x00000032; +pub const PRODUCT_SERVER_FOR_SB_SOLUTIONS: DWORD = 0x00000033; +pub const PRODUCT_STANDARD_SERVER_SOLUTIONS: DWORD = 0x00000034; +pub const PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE: DWORD = 0x00000035; +pub const PRODUCT_SB_SOLUTION_SERVER_EM: DWORD = 0x00000036; +pub const PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM: DWORD = 0x00000037; +pub const PRODUCT_SOLUTION_EMBEDDEDSERVER: DWORD = 0x00000038; +pub const PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE: DWORD = 0x00000039; +pub const PRODUCT_PROFESSIONAL_EMBEDDED: DWORD = 0x0000003A; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT: DWORD = 0x0000003B; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL: DWORD = 0x0000003C; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC: DWORD = 0x0000003D; +pub const PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC: DWORD = 0x0000003E; +pub const PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: DWORD = 0x0000003F; +pub const PRODUCT_CLUSTER_SERVER_V: DWORD = 0x00000040; +pub const PRODUCT_EMBEDDED: DWORD = 0x00000041; +pub const PRODUCT_STARTER_E: DWORD = 0x00000042; +pub const PRODUCT_HOME_BASIC_E: DWORD = 0x00000043; +pub const PRODUCT_HOME_PREMIUM_E: DWORD = 0x00000044; +pub const PRODUCT_PROFESSIONAL_E: DWORD = 0x00000045; +pub const PRODUCT_ENTERPRISE_E: DWORD = 0x00000046; +pub const PRODUCT_ULTIMATE_E: DWORD = 0x00000047; +pub const PRODUCT_ENTERPRISE_EVALUATION: DWORD = 0x00000048; +pub const PRODUCT_MULTIPOINT_STANDARD_SERVER: DWORD = 0x0000004C; +pub const PRODUCT_MULTIPOINT_PREMIUM_SERVER: DWORD = 0x0000004D; +pub const PRODUCT_STANDARD_EVALUATION_SERVER: DWORD = 0x0000004F; +pub const PRODUCT_DATACENTER_EVALUATION_SERVER: DWORD = 0x00000050; +pub const PRODUCT_ENTERPRISE_N_EVALUATION: DWORD = 0x00000054; +pub const PRODUCT_EMBEDDED_AUTOMOTIVE: DWORD = 0x00000055; +pub const PRODUCT_EMBEDDED_INDUSTRY_A: DWORD = 0x00000056; +pub const PRODUCT_THINPC: DWORD = 0x00000057; +pub const PRODUCT_EMBEDDED_A: DWORD = 0x00000058; +pub const PRODUCT_EMBEDDED_INDUSTRY: DWORD = 0x00000059; +pub const PRODUCT_EMBEDDED_E: DWORD = 0x0000005A; +pub const PRODUCT_EMBEDDED_INDUSTRY_E: DWORD = 0x0000005B; +pub const PRODUCT_EMBEDDED_INDUSTRY_A_E: DWORD = 0x0000005C; +pub const PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER: DWORD = 0x0000005F; +pub const PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER: DWORD = 0x00000060; +pub const PRODUCT_CORE_ARM: DWORD = 0x00000061; +pub const PRODUCT_CORE_N: DWORD = 0x00000062; +pub const PRODUCT_CORE_COUNTRYSPECIFIC: DWORD = 0x00000063; +pub const PRODUCT_CORE_SINGLELANGUAGE: DWORD = 0x00000064; +pub const PRODUCT_CORE: DWORD = 0x00000065; +pub const PRODUCT_PROFESSIONAL_WMC: DWORD = 0x00000067; +pub const PRODUCT_MOBILE_CORE: DWORD = 0x00000068; +pub const PRODUCT_EMBEDDED_INDUSTRY_EVAL: DWORD = 0x00000069; +pub const PRODUCT_EMBEDDED_INDUSTRY_E_EVAL: DWORD = 0x0000006A; +pub const PRODUCT_EMBEDDED_EVAL: DWORD = 0x0000006B; +pub const PRODUCT_EMBEDDED_E_EVAL: DWORD = 0x0000006C; +pub const PRODUCT_NANO_SERVER: DWORD = 0x0000006D; +pub const PRODUCT_CLOUD_STORAGE_SERVER: DWORD = 0x0000006E; +pub const PRODUCT_CORE_CONNECTED: DWORD = 0x0000006F; +pub const PRODUCT_PROFESSIONAL_STUDENT: DWORD = 0x00000070; +pub const PRODUCT_CORE_CONNECTED_N: DWORD = 0x00000071; +pub const PRODUCT_PROFESSIONAL_STUDENT_N: DWORD = 0x00000072; +pub const PRODUCT_CORE_CONNECTED_SINGLELANGUAGE: DWORD = 0x00000073; +pub const PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC: DWORD = 0x00000074; +pub const PRODUCT_CONNECTED_CAR: DWORD = 0x00000075; +pub const PRODUCT_INDUSTRY_HANDHELD: DWORD = 0x00000076; +pub const PRODUCT_PPI_PRO: DWORD = 0x00000077; +pub const PRODUCT_ARM64_SERVER: DWORD = 0x00000078; +pub const PRODUCT_EDUCATION: DWORD = 0x00000079; +pub const PRODUCT_EDUCATION_N: DWORD = 0x0000007A; +pub const PRODUCT_IOTUAP: DWORD = 0x0000007B; +pub const PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER: DWORD = 0x0000007C; +pub const PRODUCT_ENTERPRISE_S: DWORD = 0x0000007D; +pub const PRODUCT_ENTERPRISE_S_N: DWORD = 0x0000007E; +pub const PRODUCT_PROFESSIONAL_S: DWORD = 0x0000007F; +pub const PRODUCT_PROFESSIONAL_S_N: DWORD = 0x00000080; +pub const PRODUCT_ENTERPRISE_S_EVALUATION: DWORD = 0x00000081; +pub const PRODUCT_ENTERPRISE_S_N_EVALUATION: DWORD = 0x00000082; +pub const PRODUCT_HOLOGRAPHIC: DWORD = 0x00000087; +pub const PRODUCT_PRO_SINGLE_LANGUAGE: DWORD = 0x0000008A; +pub const PRODUCT_PRO_CHINA: DWORD = 0x0000008B; +pub const PRODUCT_ENTERPRISE_SUBSCRIPTION: DWORD = 0x0000008C; +pub const PRODUCT_ENTERPRISE_SUBSCRIPTION_N: DWORD = 0x0000008D; +pub const PRODUCT_DATACENTER_NANO_SERVER: DWORD = 0x0000008F; +pub const PRODUCT_STANDARD_NANO_SERVER: DWORD = 0x00000090; +pub const PRODUCT_DATACENTER_A_SERVER_CORE: DWORD = 0x00000091; +pub const PRODUCT_STANDARD_A_SERVER_CORE: DWORD = 0x00000092; +pub const PRODUCT_DATACENTER_WS_SERVER_CORE: DWORD = 0x00000093; +pub const PRODUCT_STANDARD_WS_SERVER_CORE: DWORD = 0x00000094; +pub const PRODUCT_UTILITY_VM: DWORD = 0x00000095; +pub const PRODUCT_DATACENTER_EVALUATION_SERVER_CORE: DWORD = 0x0000009F; +pub const PRODUCT_STANDARD_EVALUATION_SERVER_CORE: DWORD = 0x000000A0; +pub const PRODUCT_PRO_WORKSTATION: DWORD = 0x000000A1; +pub const PRODUCT_PRO_WORKSTATION_N: DWORD = 0x000000A2; +pub const PRODUCT_PRO_FOR_EDUCATION: DWORD = 0x000000A4; +pub const PRODUCT_PRO_FOR_EDUCATION_N: DWORD = 0x000000A5; +pub const PRODUCT_AZURE_SERVER_CORE: DWORD = 0x000000A8; +pub const PRODUCT_AZURE_NANO_SERVER: DWORD = 0x000000A9; +pub const PRODUCT_ENTERPRISEG: DWORD = 0x000000AB; +pub const PRODUCT_ENTERPRISEGN: DWORD = 0x000000AC; +pub const PRODUCT_CLOUD: DWORD = 0x000000B2; +pub const PRODUCT_CLOUDN: DWORD = 0x000000B3; +pub const PRODUCT_UNLICENSED: DWORD = 0xABCDABCD; +pub const LANG_NEUTRAL: WORD = 0x00; +pub const LANG_INVARIANT: WORD = 0x7f; +pub const LANG_AFRIKAANS: WORD = 0x36; +pub const LANG_ALBANIAN: WORD = 0x1c; +pub const LANG_ALSATIAN: WORD = 0x84; +pub const LANG_AMHARIC: WORD = 0x5e; +pub const LANG_ARABIC: WORD = 0x01; +pub const LANG_ARMENIAN: WORD = 0x2b; +pub const LANG_ASSAMESE: WORD = 0x4d; +pub const LANG_AZERI: WORD = 0x2c; +pub const LANG_AZERBAIJANI: WORD = 0x2c; +pub const LANG_BANGLA: WORD = 0x45; +pub const LANG_BASHKIR: WORD = 0x6d; +pub const LANG_BASQUE: WORD = 0x2d; +pub const LANG_BELARUSIAN: WORD = 0x23; +pub const LANG_BENGALI: WORD = 0x45; +pub const LANG_BRETON: WORD = 0x7e; +pub const LANG_BOSNIAN: WORD = 0x1a; +pub const LANG_BOSNIAN_NEUTRAL: WORD = 0x781a; +pub const LANG_BULGARIAN: WORD = 0x02; +pub const LANG_CATALAN: WORD = 0x03; +pub const LANG_CENTRAL_KURDISH: WORD = 0x92; +pub const LANG_CHEROKEE: WORD = 0x5c; +pub const LANG_CHINESE: WORD = 0x04; +pub const LANG_CHINESE_SIMPLIFIED: WORD = 0x04; +pub const LANG_CHINESE_TRADITIONAL: WORD = 0x7c04; +pub const LANG_CORSICAN: WORD = 0x83; +pub const LANG_CROATIAN: WORD = 0x1a; +pub const LANG_CZECH: WORD = 0x05; +pub const LANG_DANISH: WORD = 0x06; +pub const LANG_DARI: WORD = 0x8c; +pub const LANG_DIVEHI: WORD = 0x65; +pub const LANG_DUTCH: WORD = 0x13; +pub const LANG_ENGLISH: WORD = 0x09; +pub const LANG_ESTONIAN: WORD = 0x25; +pub const LANG_FAEROESE: WORD = 0x38; +pub const LANG_FARSI: WORD = 0x29; +pub const LANG_FILIPINO: WORD = 0x64; +pub const LANG_FINNISH: WORD = 0x0b; +pub const LANG_FRENCH: WORD = 0x0c; +pub const LANG_FRISIAN: WORD = 0x62; +pub const LANG_FULAH: WORD = 0x67; +pub const LANG_GALICIAN: WORD = 0x56; +pub const LANG_GEORGIAN: WORD = 0x37; +pub const LANG_GERMAN: WORD = 0x07; +pub const LANG_GREEK: WORD = 0x08; +pub const LANG_GREENLANDIC: WORD = 0x6f; +pub const LANG_GUJARATI: WORD = 0x47; +pub const LANG_HAUSA: WORD = 0x68; +pub const LANG_HAWAIIAN: WORD = 0x75; +pub const LANG_HEBREW: WORD = 0x0d; +pub const LANG_HINDI: WORD = 0x39; +pub const LANG_HUNGARIAN: WORD = 0x0e; +pub const LANG_ICELANDIC: WORD = 0x0f; +pub const LANG_IGBO: WORD = 0x70; +pub const LANG_INDONESIAN: WORD = 0x21; +pub const LANG_INUKTITUT: WORD = 0x5d; +pub const LANG_IRISH: WORD = 0x3c; +pub const LANG_ITALIAN: WORD = 0x10; +pub const LANG_JAPANESE: WORD = 0x11; +pub const LANG_KANNADA: WORD = 0x4b; +pub const LANG_KASHMIRI: WORD = 0x60; +pub const LANG_KAZAK: WORD = 0x3f; +pub const LANG_KHMER: WORD = 0x53; +pub const LANG_KICHE: WORD = 0x86; +pub const LANG_KINYARWANDA: WORD = 0x87; +pub const LANG_KONKANI: WORD = 0x57; +pub const LANG_KOREAN: WORD = 0x12; +pub const LANG_KYRGYZ: WORD = 0x40; +pub const LANG_LAO: WORD = 0x54; +pub const LANG_LATVIAN: WORD = 0x26; +pub const LANG_LITHUANIAN: WORD = 0x27; +pub const LANG_LOWER_SORBIAN: WORD = 0x2e; +pub const LANG_LUXEMBOURGISH: WORD = 0x6e; +pub const LANG_MACEDONIAN: WORD = 0x2f; +pub const LANG_MALAY: WORD = 0x3e; +pub const LANG_MALAYALAM: WORD = 0x4c; +pub const LANG_MALTESE: WORD = 0x3a; +pub const LANG_MANIPURI: WORD = 0x58; +pub const LANG_MAORI: WORD = 0x81; +pub const LANG_MAPUDUNGUN: WORD = 0x7a; +pub const LANG_MARATHI: WORD = 0x4e; +pub const LANG_MOHAWK: WORD = 0x7c; +pub const LANG_MONGOLIAN: WORD = 0x50; +pub const LANG_NEPALI: WORD = 0x61; +pub const LANG_NORWEGIAN: WORD = 0x14; +pub const LANG_OCCITAN: WORD = 0x82; +pub const LANG_ODIA: WORD = 0x48; +pub const LANG_ORIYA: WORD = 0x48; +pub const LANG_PASHTO: WORD = 0x63; +pub const LANG_PERSIAN: WORD = 0x29; +pub const LANG_POLISH: WORD = 0x15; +pub const LANG_PORTUGUESE: WORD = 0x16; +pub const LANG_PULAR: WORD = 0x67; +pub const LANG_PUNJABI: WORD = 0x46; +pub const LANG_QUECHUA: WORD = 0x6b; +pub const LANG_ROMANIAN: WORD = 0x18; +pub const LANG_ROMANSH: WORD = 0x17; +pub const LANG_RUSSIAN: WORD = 0x19; +pub const LANG_SAKHA: WORD = 0x85; +pub const LANG_SAMI: WORD = 0x3b; +pub const LANG_SANSKRIT: WORD = 0x4f; +pub const LANG_SCOTTISH_GAELIC: WORD = 0x91; +pub const LANG_SERBIAN: WORD = 0x1a; +pub const LANG_SERBIAN_NEUTRAL: WORD = 0x7c1a; +pub const LANG_SINDHI: WORD = 0x59; +pub const LANG_SINHALESE: WORD = 0x5b; +pub const LANG_SLOVAK: WORD = 0x1b; +pub const LANG_SLOVENIAN: WORD = 0x24; +pub const LANG_SOTHO: WORD = 0x6c; +pub const LANG_SPANISH: WORD = 0x0a; +pub const LANG_SWAHILI: WORD = 0x41; +pub const LANG_SWEDISH: WORD = 0x1d; +pub const LANG_SYRIAC: WORD = 0x5a; +pub const LANG_TAJIK: WORD = 0x28; +pub const LANG_TAMAZIGHT: WORD = 0x5f; +pub const LANG_TAMIL: WORD = 0x49; +pub const LANG_TATAR: WORD = 0x44; +pub const LANG_TELUGU: WORD = 0x4a; +pub const LANG_THAI: WORD = 0x1e; +pub const LANG_TIBETAN: WORD = 0x51; +pub const LANG_TIGRIGNA: WORD = 0x73; +pub const LANG_TIGRINYA: WORD = 0x73; +pub const LANG_TSWANA: WORD = 0x32; +pub const LANG_TURKISH: WORD = 0x1f; +pub const LANG_TURKMEN: WORD = 0x42; +pub const LANG_UIGHUR: WORD = 0x80; +pub const LANG_UKRAINIAN: WORD = 0x22; +pub const LANG_UPPER_SORBIAN: WORD = 0x2e; +pub const LANG_URDU: WORD = 0x20; +pub const LANG_UZBEK: WORD = 0x43; +pub const LANG_VALENCIAN: WORD = 0x03; +pub const LANG_VIETNAMESE: WORD = 0x2a; +pub const LANG_WELSH: WORD = 0x52; +pub const LANG_WOLOF: WORD = 0x88; +pub const LANG_XHOSA: WORD = 0x34; +pub const LANG_YAKUT: WORD = 0x85; +pub const LANG_YI: WORD = 0x78; +pub const LANG_YORUBA: WORD = 0x6a; +pub const LANG_ZULU: WORD = 0x35; +pub const SUBLANG_NEUTRAL: WORD = 0x00; +pub const SUBLANG_DEFAULT: WORD = 0x01; +pub const SUBLANG_SYS_DEFAULT: WORD = 0x02; +pub const SUBLANG_CUSTOM_DEFAULT: WORD = 0x03; +pub const SUBLANG_CUSTOM_UNSPECIFIED: WORD = 0x04; +pub const SUBLANG_UI_CUSTOM_DEFAULT: WORD = 0x05; +pub const SUBLANG_AFRIKAANS_SOUTH_AFRICA: WORD = 0x01; +pub const SUBLANG_ALBANIAN_ALBANIA: WORD = 0x01; +pub const SUBLANG_ALSATIAN_FRANCE: WORD = 0x01; +pub const SUBLANG_AMHARIC_ETHIOPIA: WORD = 0x01; +pub const SUBLANG_ARABIC_SAUDI_ARABIA: WORD = 0x01; +pub const SUBLANG_ARABIC_IRAQ: WORD = 0x02; +pub const SUBLANG_ARABIC_EGYPT: WORD = 0x03; +pub const SUBLANG_ARABIC_LIBYA: WORD = 0x04; +pub const SUBLANG_ARABIC_ALGERIA: WORD = 0x05; +pub const SUBLANG_ARABIC_MOROCCO: WORD = 0x06; +pub const SUBLANG_ARABIC_TUNISIA: WORD = 0x07; +pub const SUBLANG_ARABIC_OMAN: WORD = 0x08; +pub const SUBLANG_ARABIC_YEMEN: WORD = 0x09; +pub const SUBLANG_ARABIC_SYRIA: WORD = 0x0a; +pub const SUBLANG_ARABIC_JORDAN: WORD = 0x0b; +pub const SUBLANG_ARABIC_LEBANON: WORD = 0x0c; +pub const SUBLANG_ARABIC_KUWAIT: WORD = 0x0d; +pub const SUBLANG_ARABIC_UAE: WORD = 0x0e; +pub const SUBLANG_ARABIC_BAHRAIN: WORD = 0x0f; +pub const SUBLANG_ARABIC_QATAR: WORD = 0x10; +pub const SUBLANG_ARMENIAN_ARMENIA: WORD = 0x01; +pub const SUBLANG_ASSAMESE_INDIA: WORD = 0x01; +pub const SUBLANG_AZERI_LATIN: WORD = 0x01; +pub const SUBLANG_AZERI_CYRILLIC: WORD = 0x02; +pub const SUBLANG_AZERBAIJANI_AZERBAIJAN_LATIN: WORD = 0x01; +pub const SUBLANG_AZERBAIJANI_AZERBAIJAN_CYRILLIC: WORD = 0x02; +pub const SUBLANG_BANGLA_INDIA: WORD = 0x01; +pub const SUBLANG_BANGLA_BANGLADESH: WORD = 0x02; +pub const SUBLANG_BASHKIR_RUSSIA: WORD = 0x01; +pub const SUBLANG_BASQUE_BASQUE: WORD = 0x01; +pub const SUBLANG_BELARUSIAN_BELARUS: WORD = 0x01; +pub const SUBLANG_BENGALI_INDIA: WORD = 0x01; +pub const SUBLANG_BENGALI_BANGLADESH: WORD = 0x02; +pub const SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN: WORD = 0x05; +pub const SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC: WORD = 0x08; +pub const SUBLANG_BRETON_FRANCE: WORD = 0x01; +pub const SUBLANG_BULGARIAN_BULGARIA: WORD = 0x01; +pub const SUBLANG_CATALAN_CATALAN: WORD = 0x01; +pub const SUBLANG_CENTRAL_KURDISH_IRAQ: WORD = 0x01; +pub const SUBLANG_CHEROKEE_CHEROKEE: WORD = 0x01; +pub const SUBLANG_CHINESE_TRADITIONAL: WORD = 0x01; +pub const SUBLANG_CHINESE_SIMPLIFIED: WORD = 0x02; +pub const SUBLANG_CHINESE_HONGKONG: WORD = 0x03; +pub const SUBLANG_CHINESE_SINGAPORE: WORD = 0x04; +pub const SUBLANG_CHINESE_MACAU: WORD = 0x05; +pub const SUBLANG_CORSICAN_FRANCE: WORD = 0x01; +pub const SUBLANG_CZECH_CZECH_REPUBLIC: WORD = 0x01; +pub const SUBLANG_CROATIAN_CROATIA: WORD = 0x01; +pub const SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN: WORD = 0x04; +pub const SUBLANG_DANISH_DENMARK: WORD = 0x01; +pub const SUBLANG_DARI_AFGHANISTAN: WORD = 0x01; +pub const SUBLANG_DIVEHI_MALDIVES: WORD = 0x01; +pub const SUBLANG_DUTCH: WORD = 0x01; +pub const SUBLANG_DUTCH_BELGIAN: WORD = 0x02; +pub const SUBLANG_ENGLISH_US: WORD = 0x01; +pub const SUBLANG_ENGLISH_UK: WORD = 0x02; +pub const SUBLANG_ENGLISH_AUS: WORD = 0x03; +pub const SUBLANG_ENGLISH_CAN: WORD = 0x04; +pub const SUBLANG_ENGLISH_NZ: WORD = 0x05; +pub const SUBLANG_ENGLISH_EIRE: WORD = 0x06; +pub const SUBLANG_ENGLISH_SOUTH_AFRICA: WORD = 0x07; +pub const SUBLANG_ENGLISH_JAMAICA: WORD = 0x08; +pub const SUBLANG_ENGLISH_CARIBBEAN: WORD = 0x09; +pub const SUBLANG_ENGLISH_BELIZE: WORD = 0x0a; +pub const SUBLANG_ENGLISH_TRINIDAD: WORD = 0x0b; +pub const SUBLANG_ENGLISH_ZIMBABWE: WORD = 0x0c; +pub const SUBLANG_ENGLISH_PHILIPPINES: WORD = 0x0d; +pub const SUBLANG_ENGLISH_INDIA: WORD = 0x10; +pub const SUBLANG_ENGLISH_MALAYSIA: WORD = 0x11; +pub const SUBLANG_ENGLISH_SINGAPORE: WORD = 0x12; +pub const SUBLANG_ESTONIAN_ESTONIA: WORD = 0x01; +pub const SUBLANG_FAEROESE_FAROE_ISLANDS: WORD = 0x01; +pub const SUBLANG_FILIPINO_PHILIPPINES: WORD = 0x01; +pub const SUBLANG_FINNISH_FINLAND: WORD = 0x01; +pub const SUBLANG_FRENCH: WORD = 0x01; +pub const SUBLANG_FRENCH_BELGIAN: WORD = 0x02; +pub const SUBLANG_FRENCH_CANADIAN: WORD = 0x03; +pub const SUBLANG_FRENCH_SWISS: WORD = 0x04; +pub const SUBLANG_FRENCH_LUXEMBOURG: WORD = 0x05; +pub const SUBLANG_FRENCH_MONACO: WORD = 0x06; +pub const SUBLANG_FRISIAN_NETHERLANDS: WORD = 0x01; +pub const SUBLANG_FULAH_SENEGAL: WORD = 0x02; +pub const SUBLANG_GALICIAN_GALICIAN: WORD = 0x01; +pub const SUBLANG_GEORGIAN_GEORGIA: WORD = 0x01; +pub const SUBLANG_GERMAN: WORD = 0x01; +pub const SUBLANG_GERMAN_SWISS: WORD = 0x02; +pub const SUBLANG_GERMAN_AUSTRIAN: WORD = 0x03; +pub const SUBLANG_GERMAN_LUXEMBOURG: WORD = 0x04; +pub const SUBLANG_GERMAN_LIECHTENSTEIN: WORD = 0x05; +pub const SUBLANG_GREEK_GREECE: WORD = 0x01; +pub const SUBLANG_GREENLANDIC_GREENLAND: WORD = 0x01; +pub const SUBLANG_GUJARATI_INDIA: WORD = 0x01; +pub const SUBLANG_HAUSA_NIGERIA_LATIN: WORD = 0x01; +pub const SUBLANG_HAWAIIAN_US: WORD = 0x01; +pub const SUBLANG_HEBREW_ISRAEL: WORD = 0x01; +pub const SUBLANG_HINDI_INDIA: WORD = 0x01; +pub const SUBLANG_HUNGARIAN_HUNGARY: WORD = 0x01; +pub const SUBLANG_ICELANDIC_ICELAND: WORD = 0x01; +pub const SUBLANG_IGBO_NIGERIA: WORD = 0x01; +pub const SUBLANG_INDONESIAN_INDONESIA: WORD = 0x01; +pub const SUBLANG_INUKTITUT_CANADA: WORD = 0x01; +pub const SUBLANG_INUKTITUT_CANADA_LATIN: WORD = 0x02; +pub const SUBLANG_IRISH_IRELAND: WORD = 0x02; +pub const SUBLANG_ITALIAN: WORD = 0x01; +pub const SUBLANG_ITALIAN_SWISS: WORD = 0x02; +pub const SUBLANG_JAPANESE_JAPAN: WORD = 0x01; +pub const SUBLANG_KANNADA_INDIA: WORD = 0x01; +pub const SUBLANG_KASHMIRI_SASIA: WORD = 0x02; +pub const SUBLANG_KASHMIRI_INDIA: WORD = 0x02; +pub const SUBLANG_KAZAK_KAZAKHSTAN: WORD = 0x01; +pub const SUBLANG_KHMER_CAMBODIA: WORD = 0x01; +pub const SUBLANG_KICHE_GUATEMALA: WORD = 0x01; +pub const SUBLANG_KINYARWANDA_RWANDA: WORD = 0x01; +pub const SUBLANG_KONKANI_INDIA: WORD = 0x01; +pub const SUBLANG_KOREAN: WORD = 0x01; +pub const SUBLANG_KYRGYZ_KYRGYZSTAN: WORD = 0x01; +pub const SUBLANG_LAO_LAO: WORD = 0x01; +pub const SUBLANG_LATVIAN_LATVIA: WORD = 0x01; +pub const SUBLANG_LITHUANIAN: WORD = 0x01; +pub const SUBLANG_LOWER_SORBIAN_GERMANY: WORD = 0x02; +pub const SUBLANG_LUXEMBOURGISH_LUXEMBOURG: WORD = 0x01; +pub const SUBLANG_MACEDONIAN_MACEDONIA: WORD = 0x01; +pub const SUBLANG_MALAY_MALAYSIA: WORD = 0x01; +pub const SUBLANG_MALAY_BRUNEI_DARUSSALAM: WORD = 0x02; +pub const SUBLANG_MALAYALAM_INDIA: WORD = 0x01; +pub const SUBLANG_MALTESE_MALTA: WORD = 0x01; +pub const SUBLANG_MAORI_NEW_ZEALAND: WORD = 0x01; +pub const SUBLANG_MAPUDUNGUN_CHILE: WORD = 0x01; +pub const SUBLANG_MARATHI_INDIA: WORD = 0x01; +pub const SUBLANG_MOHAWK_MOHAWK: WORD = 0x01; +pub const SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA: WORD = 0x01; +pub const SUBLANG_MONGOLIAN_PRC: WORD = 0x02; +pub const SUBLANG_NEPALI_INDIA: WORD = 0x02; +pub const SUBLANG_NEPALI_NEPAL: WORD = 0x01; +pub const SUBLANG_NORWEGIAN_BOKMAL: WORD = 0x01; +pub const SUBLANG_NORWEGIAN_NYNORSK: WORD = 0x02; +pub const SUBLANG_OCCITAN_FRANCE: WORD = 0x01; +pub const SUBLANG_ODIA_INDIA: WORD = 0x01; +pub const SUBLANG_ORIYA_INDIA: WORD = 0x01; +pub const SUBLANG_PASHTO_AFGHANISTAN: WORD = 0x01; +pub const SUBLANG_PERSIAN_IRAN: WORD = 0x01; +pub const SUBLANG_POLISH_POLAND: WORD = 0x01; +pub const SUBLANG_PORTUGUESE: WORD = 0x02; +pub const SUBLANG_PORTUGUESE_BRAZILIAN: WORD = 0x01; +pub const SUBLANG_PULAR_SENEGAL: WORD = 0x02; +pub const SUBLANG_PUNJABI_INDIA: WORD = 0x01; +pub const SUBLANG_PUNJABI_PAKISTAN: WORD = 0x02; +pub const SUBLANG_QUECHUA_BOLIVIA: WORD = 0x01; +pub const SUBLANG_QUECHUA_ECUADOR: WORD = 0x02; +pub const SUBLANG_QUECHUA_PERU: WORD = 0x03; +pub const SUBLANG_ROMANIAN_ROMANIA: WORD = 0x01; +pub const SUBLANG_ROMANSH_SWITZERLAND: WORD = 0x01; +pub const SUBLANG_RUSSIAN_RUSSIA: WORD = 0x01; +pub const SUBLANG_SAKHA_RUSSIA: WORD = 0x01; +pub const SUBLANG_SAMI_NORTHERN_NORWAY: WORD = 0x01; +pub const SUBLANG_SAMI_NORTHERN_SWEDEN: WORD = 0x02; +pub const SUBLANG_SAMI_NORTHERN_FINLAND: WORD = 0x03; +pub const SUBLANG_SAMI_LULE_NORWAY: WORD = 0x04; +pub const SUBLANG_SAMI_LULE_SWEDEN: WORD = 0x05; +pub const SUBLANG_SAMI_SOUTHERN_NORWAY: WORD = 0x06; +pub const SUBLANG_SAMI_SOUTHERN_SWEDEN: WORD = 0x07; +pub const SUBLANG_SAMI_SKOLT_FINLAND: WORD = 0x08; +pub const SUBLANG_SAMI_INARI_FINLAND: WORD = 0x09; +pub const SUBLANG_SANSKRIT_INDIA: WORD = 0x01; +pub const SUBLANG_SCOTTISH_GAELIC: WORD = 0x01; +pub const SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN: WORD = 0x06; +pub const SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC: WORD = 0x07; +pub const SUBLANG_SERBIAN_MONTENEGRO_LATIN: WORD = 0x0b; +pub const SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC: WORD = 0x0c; +pub const SUBLANG_SERBIAN_SERBIA_LATIN: WORD = 0x09; +pub const SUBLANG_SERBIAN_SERBIA_CYRILLIC: WORD = 0x0a; +pub const SUBLANG_SERBIAN_CROATIA: WORD = 0x01; +pub const SUBLANG_SERBIAN_LATIN: WORD = 0x02; +pub const SUBLANG_SERBIAN_CYRILLIC: WORD = 0x03; +pub const SUBLANG_SINDHI_INDIA: WORD = 0x01; +pub const SUBLANG_SINDHI_PAKISTAN: WORD = 0x02; +pub const SUBLANG_SINDHI_AFGHANISTAN: WORD = 0x02; +pub const SUBLANG_SINHALESE_SRI_LANKA: WORD = 0x01; +pub const SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA: WORD = 0x01; +pub const SUBLANG_SLOVAK_SLOVAKIA: WORD = 0x01; +pub const SUBLANG_SLOVENIAN_SLOVENIA: WORD = 0x01; +pub const SUBLANG_SPANISH: WORD = 0x01; +pub const SUBLANG_SPANISH_MEXICAN: WORD = 0x02; +pub const SUBLANG_SPANISH_MODERN: WORD = 0x03; +pub const SUBLANG_SPANISH_GUATEMALA: WORD = 0x04; +pub const SUBLANG_SPANISH_COSTA_RICA: WORD = 0x05; +pub const SUBLANG_SPANISH_PANAMA: WORD = 0x06; +pub const SUBLANG_SPANISH_DOMINICAN_REPUBLIC: WORD = 0x07; +pub const SUBLANG_SPANISH_VENEZUELA: WORD = 0x08; +pub const SUBLANG_SPANISH_COLOMBIA: WORD = 0x09; +pub const SUBLANG_SPANISH_PERU: WORD = 0x0a; +pub const SUBLANG_SPANISH_ARGENTINA: WORD = 0x0b; +pub const SUBLANG_SPANISH_ECUADOR: WORD = 0x0c; +pub const SUBLANG_SPANISH_CHILE: WORD = 0x0d; +pub const SUBLANG_SPANISH_URUGUAY: WORD = 0x0e; +pub const SUBLANG_SPANISH_PARAGUAY: WORD = 0x0f; +pub const SUBLANG_SPANISH_BOLIVIA: WORD = 0x10; +pub const SUBLANG_SPANISH_EL_SALVADOR: WORD = 0x11; +pub const SUBLANG_SPANISH_HONDURAS: WORD = 0x12; +pub const SUBLANG_SPANISH_NICARAGUA: WORD = 0x13; +pub const SUBLANG_SPANISH_PUERTO_RICO: WORD = 0x14; +pub const SUBLANG_SPANISH_US: WORD = 0x15; +pub const SUBLANG_SWAHILI_KENYA: WORD = 0x01; +pub const SUBLANG_SWEDISH: WORD = 0x01; +pub const SUBLANG_SWEDISH_FINLAND: WORD = 0x02; +pub const SUBLANG_SYRIAC_SYRIA: WORD = 0x01; +pub const SUBLANG_TAJIK_TAJIKISTAN: WORD = 0x01; +pub const SUBLANG_TAMAZIGHT_ALGERIA_LATIN: WORD = 0x02; +pub const SUBLANG_TAMAZIGHT_MOROCCO_TIFINAGH: WORD = 0x04; +pub const SUBLANG_TAMIL_INDIA: WORD = 0x01; +pub const SUBLANG_TAMIL_SRI_LANKA: WORD = 0x02; +pub const SUBLANG_TATAR_RUSSIA: WORD = 0x01; +pub const SUBLANG_TELUGU_INDIA: WORD = 0x01; +pub const SUBLANG_THAI_THAILAND: WORD = 0x01; +pub const SUBLANG_TIBETAN_PRC: WORD = 0x01; +pub const SUBLANG_TIGRIGNA_ERITREA: WORD = 0x02; +pub const SUBLANG_TIGRINYA_ERITREA: WORD = 0x02; +pub const SUBLANG_TIGRINYA_ETHIOPIA: WORD = 0x01; +pub const SUBLANG_TSWANA_BOTSWANA: WORD = 0x02; +pub const SUBLANG_TSWANA_SOUTH_AFRICA: WORD = 0x01; +pub const SUBLANG_TURKISH_TURKEY: WORD = 0x01; +pub const SUBLANG_TURKMEN_TURKMENISTAN: WORD = 0x01; +pub const SUBLANG_UIGHUR_PRC: WORD = 0x01; +pub const SUBLANG_UKRAINIAN_UKRAINE: WORD = 0x01; +pub const SUBLANG_UPPER_SORBIAN_GERMANY: WORD = 0x01; +pub const SUBLANG_URDU_PAKISTAN: WORD = 0x01; +pub const SUBLANG_URDU_INDIA: WORD = 0x02; +pub const SUBLANG_UZBEK_LATIN: WORD = 0x01; +pub const SUBLANG_UZBEK_CYRILLIC: WORD = 0x02; +pub const SUBLANG_VALENCIAN_VALENCIA: WORD = 0x02; +pub const SUBLANG_VIETNAMESE_VIETNAM: WORD = 0x01; +pub const SUBLANG_WELSH_UNITED_KINGDOM: WORD = 0x01; +pub const SUBLANG_WOLOF_SENEGAL: WORD = 0x01; +pub const SUBLANG_XHOSA_SOUTH_AFRICA: WORD = 0x01; +pub const SUBLANG_YAKUT_RUSSIA: WORD = 0x01; +pub const SUBLANG_YI_PRC: WORD = 0x01; +pub const SUBLANG_YORUBA_NIGERIA: WORD = 0x01; +pub const SUBLANG_ZULU_SOUTH_AFRICA: WORD = 0x01; +pub const SORT_DEFAULT: WORD = 0x0; +pub const SORT_INVARIANT_MATH: WORD = 0x1; +pub const SORT_JAPANESE_XJIS: WORD = 0x0; +pub const SORT_JAPANESE_UNICODE: WORD = 0x1; +pub const SORT_JAPANESE_RADICALSTROKE: WORD = 0x4; +pub const SORT_CHINESE_BIG5: WORD = 0x0; +pub const SORT_CHINESE_PRCP: WORD = 0x0; +pub const SORT_CHINESE_UNICODE: WORD = 0x1; +pub const SORT_CHINESE_PRC: WORD = 0x2; +pub const SORT_CHINESE_BOPOMOFO: WORD = 0x3; +pub const SORT_CHINESE_RADICALSTROKE: WORD = 0x4; +pub const SORT_KOREAN_KSC: WORD = 0x0; +pub const SORT_KOREAN_UNICODE: WORD = 0x1; +pub const SORT_GERMAN_PHONE_BOOK: WORD = 0x1; +pub const SORT_HUNGARIAN_DEFAULT: WORD = 0x0; +pub const SORT_HUNGARIAN_TECHNICAL: WORD = 0x1; +pub const SORT_GEORGIAN_TRADITIONAL: WORD = 0x0; +pub const SORT_GEORGIAN_MODERN: WORD = 0x1; +macro_rules! MAKELANGID { ($p:expr, $s:expr) => (($s << 10) | $p) } +#[inline] +pub fn MAKELANGID(p: WORD, s: WORD) -> LANGID { + (s << 10) | p +} +#[inline] +pub fn PRIMARYLANGID(lgid: LANGID) -> WORD { + lgid & 0x3ff +} +#[inline] +pub fn SUBLANGID(lgid: LANGID) -> WORD { + lgid >> 10 +} +pub const NLS_VALID_LOCALE_MASK: DWORD = 0x000fffff; +macro_rules! MAKELCID { + ($lgid:expr, $srtid:expr) => ((($srtid as DWORD) << 16) | ($lgid as DWORD)) +} +#[inline] +pub fn MAKELCID(lgid: LANGID, srtid: WORD) -> LCID { + ((srtid as DWORD) << 16) | (lgid as DWORD) +} +#[inline] +pub fn MAKESORTLCID(lgid: LANGID, srtid: WORD, ver: WORD) -> LCID { + MAKELCID(lgid, srtid) | ((ver as DWORD) << 20) +} +#[inline] +pub fn LANGIDFROMLCID(lcid: LCID) -> LANGID { + lcid as LANGID +} +#[inline] +pub fn SORTIDFROMLCID(lcid: LCID) -> WORD { + ((lcid >> 16) & 0xf) as WORD +} +#[inline] +pub fn SORTVERSIONFROMLCID(lcid: LCID) -> WORD { + ((lcid >> 16) & 0xf) as WORD +} +pub const LOCALE_NAME_MAX_LENGTH: usize = 85; +pub const LANG_SYSTEM_DEFAULT: LANGID = MAKELANGID!(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT); +pub const LANG_USER_DEFAULT: LANGID = MAKELANGID!(LANG_NEUTRAL, SUBLANG_DEFAULT); +pub const LOCALE_SYSTEM_DEFAULT: LCID = MAKELCID!(LANG_SYSTEM_DEFAULT, SORT_DEFAULT); +pub const LOCALE_USER_DEFAULT: LCID = MAKELCID!(LANG_USER_DEFAULT, SORT_DEFAULT); +pub const LOCALE_CUSTOM_DEFAULT: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), SORT_DEFAULT); +pub const LOCALE_CUSTOM_UNSPECIFIED: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED), SORT_DEFAULT); +pub const LOCALE_CUSTOM_UI_DEFAULT: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT), SORT_DEFAULT); +pub const LOCALE_NEUTRAL: LCID + = MAKELCID!(MAKELANGID!(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT); +pub const LOCALE_INVARIANT: LCID + = MAKELCID!(MAKELANGID!(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT); +pub const LOCALE_TRANSIENT_KEYBOARD1: LCID = 0x2000; +pub const LOCALE_TRANSIENT_KEYBOARD2: LCID = 0x2400; +pub const LOCALE_TRANSIENT_KEYBOARD3: LCID = 0x2800; +pub const LOCALE_TRANSIENT_KEYBOARD4: LCID = 0x2c00; +pub const LOCALE_UNASSIGNED_LCID: LCID = LOCALE_CUSTOM_UNSPECIFIED; +pub const STATUS_WAIT_0: DWORD = 0x00000000; +pub const STATUS_ABANDONED_WAIT_0: DWORD = 0x00000080; +pub const STATUS_USER_APC: DWORD = 0x000000C0; +pub const STATUS_TIMEOUT: DWORD = 0x00000102; +pub const STATUS_PENDING: DWORD = 0x00000103; +pub const DBG_EXCEPTION_HANDLED: DWORD = 0x00010001; +pub const DBG_CONTINUE: DWORD = 0x00010002; +pub const STATUS_SEGMENT_NOTIFICATION: DWORD = 0x40000005; +pub const STATUS_FATAL_APP_EXIT: DWORD = 0x40000015; +pub const DBG_REPLY_LATER: DWORD = 0x40010001; +pub const DBG_TERMINATE_THREAD: DWORD = 0x40010003; +pub const DBG_TERMINATE_PROCESS: DWORD = 0x40010004; +pub const DBG_CONTROL_C: DWORD = 0x40010005; +pub const DBG_PRINTEXCEPTION_C: DWORD = 0x40010006; +pub const DBG_RIPEXCEPTION: DWORD = 0x40010007; +pub const DBG_CONTROL_BREAK: DWORD = 0x40010008; +pub const DBG_COMMAND_EXCEPTION: DWORD = 0x40010009; +pub const DBG_PRINTEXCEPTION_WIDE_C: DWORD = 0x4001000A; +pub const STATUS_GUARD_PAGE_VIOLATION: DWORD = 0x80000001; +pub const STATUS_DATATYPE_MISALIGNMENT: DWORD = 0x80000002; +pub const STATUS_BREAKPOINT: DWORD = 0x80000003; +pub const STATUS_SINGLE_STEP: DWORD = 0x80000004; +pub const STATUS_LONGJUMP: DWORD = 0x80000026; +pub const STATUS_UNWIND_CONSOLIDATE: DWORD = 0x80000029; +pub const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; +pub const STATUS_ACCESS_VIOLATION: DWORD = 0xC0000005; +pub const STATUS_IN_PAGE_ERROR: DWORD = 0xC0000006; +pub const STATUS_INVALID_HANDLE: DWORD = 0xC0000008; +pub const STATUS_INVALID_PARAMETER: DWORD = 0xC000000D; +pub const STATUS_NO_MEMORY: DWORD = 0xC0000017; +pub const STATUS_ILLEGAL_INSTRUCTION: DWORD = 0xC000001D; +pub const STATUS_NONCONTINUABLE_EXCEPTION: DWORD = 0xC0000025; +pub const STATUS_INVALID_DISPOSITION: DWORD = 0xC0000026; +pub const STATUS_ARRAY_BOUNDS_EXCEEDED: DWORD = 0xC000008C; +pub const STATUS_FLOAT_DENORMAL_OPERAND: DWORD = 0xC000008D; +pub const STATUS_FLOAT_DIVIDE_BY_ZERO: DWORD = 0xC000008E; +pub const STATUS_FLOAT_INEXACT_RESULT: DWORD = 0xC000008F; +pub const STATUS_FLOAT_INVALID_OPERATION: DWORD = 0xC0000090; +pub const STATUS_FLOAT_OVERFLOW: DWORD = 0xC0000091; +pub const STATUS_FLOAT_STACK_CHECK: DWORD = 0xC0000092; +pub const STATUS_FLOAT_UNDERFLOW: DWORD = 0xC0000093; +pub const STATUS_INTEGER_DIVIDE_BY_ZERO: DWORD = 0xC0000094; +pub const STATUS_INTEGER_OVERFLOW: DWORD = 0xC0000095; +pub const STATUS_PRIVILEGED_INSTRUCTION: DWORD = 0xC0000096; +pub const STATUS_STACK_OVERFLOW: DWORD = 0xC00000FD; +pub const STATUS_DLL_NOT_FOUND: DWORD = 0xC0000135; +pub const STATUS_ORDINAL_NOT_FOUND: DWORD = 0xC0000138; +pub const STATUS_ENTRYPOINT_NOT_FOUND: DWORD = 0xC0000139; +pub const STATUS_CONTROL_C_EXIT: DWORD = 0xC000013A; +pub const STATUS_DLL_INIT_FAILED: DWORD = 0xC0000142; +pub const STATUS_FLOAT_MULTIPLE_FAULTS: DWORD = 0xC00002B4; +pub const STATUS_FLOAT_MULTIPLE_TRAPS: DWORD = 0xC00002B5; +pub const STATUS_REG_NAT_CONSUMPTION: DWORD = 0xC00002C9; +pub const STATUS_HEAP_CORRUPTION: DWORD = 0xC0000374; +pub const STATUS_STACK_BUFFER_OVERRUN: DWORD = 0xC0000409; +pub const STATUS_INVALID_CRUNTIME_PARAMETER: DWORD = 0xC0000417; +pub const STATUS_ASSERTION_FAILURE: DWORD = 0xC0000420; +pub const STATUS_SXS_EARLY_DEACTIVATION: DWORD = 0xC015000F; +pub const STATUS_SXS_INVALID_DEACTIVATION: DWORD = 0xC0150010; +pub const MAXIMUM_WAIT_OBJECTS: DWORD = 64; +pub const MAXIMUM_SUSPEND_COUNT: CHAR = MAXCHAR; +pub type KSPIN_LOCK = ULONG_PTR; +pub type PKSPIN_LOCK = *mut KSPIN_LOCK; +STRUCT!{struct M128A { // FIXME align 16 + Low: ULONGLONG, + High: LONGLONG, +}} +pub type PM128A = *mut M128A; +#[cfg(target_arch = "x86")] +STRUCT!{struct XSAVE_FORMAT { // FIXME align 16 + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, + FloatRegisters: [M128A; 8], + XmmRegisters: [M128A; 8], + Reserved4: [BYTE; 224], +}} +#[cfg(target_arch = "x86_64")] +STRUCT!{struct XSAVE_FORMAT { // FIXME align 16 + ControlWord: WORD, + StatusWord: WORD, + TagWord: BYTE, + Reserved1: BYTE, + ErrorOpcode: WORD, + ErrorOffset: DWORD, + ErrorSelector: WORD, + Reserved2: WORD, + DataOffset: DWORD, + DataSelector: WORD, + Reserved3: WORD, + MxCsr: DWORD, + MxCsr_Mask: DWORD, + FloatRegisters: [M128A; 8], + XmmRegisters: [M128A; 16], + Reserved4: [BYTE; 96], +}} +#[cfg(target_arch = "x86")] +STRUCT!{struct XSTATE_CONTEXT { + Mask: DWORD64, + Length: DWORD, + Reserved1: DWORD, + Area: PXSAVE_AREA, + Reserved2: DWORD, + Buffer: PVOID, + Reserved3: DWORD, +}} +#[cfg(target_arch = "x86_64")] +STRUCT!{struct XSTATE_CONTEXT { + Mask: DWORD64, + Length: DWORD, + Reserved1: DWORD, + Area: PXSAVE_AREA, + Buffer: PVOID, +}} +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +IFDEF!{ +pub type PXSAVE_FORMAT = *mut XSAVE_FORMAT; +STRUCT!{struct XSAVE_AREA_HEADER { // FIXME align 8 + Mask: DWORD64, + CompactionMask: DWORD64, + Reserved2: [DWORD64; 6], +}} +pub type PXSAVE_AREA_HEADER = *mut XSAVE_AREA_HEADER; +STRUCT!{struct XSAVE_AREA { // FIXME align 16 + LegacyState: XSAVE_FORMAT, + Header: XSAVE_AREA_HEADER, +}} +pub type PXSAVE_AREA = *mut XSAVE_AREA; +pub type PXSTATE_CONTEXT = *mut XSTATE_CONTEXT; +} +STRUCT!{struct SCOPE_TABLE_AMD64 { + Count: DWORD, + ScopeRecord: [SCOPE_TABLE_AMD64_ScopeRecord; 1], +}} +STRUCT!{struct SCOPE_TABLE_AMD64_ScopeRecord { + BeginAddress: DWORD, + EndAddress: DWORD, + HandlerAddress: DWORD, + JumpTarget: DWORD, +}} +pub type PSCOPE_TABLE_AMD64 = *mut SCOPE_TABLE_AMD64; +STRUCT!{struct SCOPE_TABLE_ARM64 { + Count: DWORD, + ScopeRecord: [SCOPE_TABLE_ARM64_ScopeRecord; 1], +}} +STRUCT!{struct SCOPE_TABLE_ARM64_ScopeRecord { + BeginAddress: DWORD, + EndAddress: DWORD, + HandlerAddress: DWORD, + JumpTarget: DWORD, +}} +pub type PSCOPE_TABLE_ARM64 = *mut SCOPE_TABLE_ARM64; +// Skip interlocked and bit manipulation stuff because it is all intrinsics +// Use the native Rust equivalents instead +#[cfg(target_arch = "x86_64")] +IFDEF!{ +pub const EXCEPTION_READ_FAULT: DWORD = 0; +pub const EXCEPTION_WRITE_FAULT: DWORD = 1; +pub const EXCEPTION_EXECUTE_FAULT: DWORD = 8; +pub const CONTEXT_AMD64: DWORD = 0x00100000; +pub const CONTEXT_CONTROL: DWORD = CONTEXT_AMD64 | 0x00000001; +pub const CONTEXT_INTEGER: DWORD = CONTEXT_AMD64 | 0x00000002; +pub const CONTEXT_SEGMENTS: DWORD = CONTEXT_AMD64 | 0x00000004; +pub const CONTEXT_FLOATING_POINT: DWORD = CONTEXT_AMD64 | 0x00000008; +pub const CONTEXT_DEBUG_REGISTERS: DWORD = CONTEXT_AMD64 | 0x00000010; +pub const CONTEXT_FULL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; +pub const CONTEXT_ALL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS + | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS; +pub const CONTEXT_XSTATE: DWORD = CONTEXT_AMD64 | 0x00000040; +pub const CONTEXT_EXCEPTION_ACTIVE: DWORD = 0x08000000; +pub const CONTEXT_SERVICE_ACTIVE: DWORD = 0x10000000; +pub const CONTEXT_EXCEPTION_REQUEST: DWORD = 0x40000000; +pub const CONTEXT_EXCEPTION_REPORTING: DWORD = 0x80000000; +pub const INITIAL_MXCSR: DWORD = 0x1f80; +pub const INITIAL_FPCSR: DWORD = 0x027f; +pub type XMM_SAVE_AREA32 = XSAVE_FORMAT; +pub type PXMM_SAVE_AREA32 = *mut XSAVE_FORMAT; +STRUCT!{struct CONTEXT_u_s { + Header: [M128A; 2], + Legacy: [M128A; 8], + Xmm0: M128A, + Xmm1: M128A, + Xmm2: M128A, + Xmm3: M128A, + Xmm4: M128A, + Xmm5: M128A, + Xmm6: M128A, + Xmm7: M128A, + Xmm8: M128A, + Xmm9: M128A, + Xmm10: M128A, + Xmm11: M128A, + Xmm12: M128A, + Xmm13: M128A, + Xmm14: M128A, + Xmm15: M128A, +}} +UNION!{union CONTEXT_u { + [u64; 64], + FltSave FltSave_mut: XMM_SAVE_AREA32, + s s_mut: CONTEXT_u_s, +}} +STRUCT!{struct CONTEXT { // FIXME align 16 + P1Home: DWORD64, + P2Home: DWORD64, + P3Home: DWORD64, + P4Home: DWORD64, + P5Home: DWORD64, + P6Home: DWORD64, + ContextFlags: DWORD, + MxCsr: DWORD, + SegCs: WORD, + SegDs: WORD, + SegEs: WORD, + SegFs: WORD, + SegGs: WORD, + SegSs: WORD, + EFlags: DWORD, + Dr0: DWORD64, + Dr1: DWORD64, + Dr2: DWORD64, + Dr3: DWORD64, + Dr6: DWORD64, + Dr7: DWORD64, + Rax: DWORD64, + Rcx: DWORD64, + Rdx: DWORD64, + Rbx: DWORD64, + Rsp: DWORD64, + Rbp: DWORD64, + Rsi: DWORD64, + Rdi: DWORD64, + R8: DWORD64, + R9: DWORD64, + R10: DWORD64, + R11: DWORD64, + R12: DWORD64, + R13: DWORD64, + R14: DWORD64, + R15: DWORD64, + Rip: DWORD64, + u: CONTEXT_u, + VectorRegister: [M128A; 26], + VectorControl: DWORD64, + DebugControl: DWORD64, + LastBranchToRip: DWORD64, + LastBranchFromRip: DWORD64, + LastExceptionToRip: DWORD64, + LastExceptionFromRip: DWORD64, +}} +pub type PCONTEXT = *mut CONTEXT; +pub type RUNTIME_FUNCTION = IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type PRUNTIME_FUNCTION = *mut IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type SCOPE_TABLE = SCOPE_TABLE_AMD64; +pub type PSCOPE_TABLE = *mut SCOPE_TABLE_AMD64; +pub const RUNTIME_FUNCTION_INDIRECT: DWORD = 0x1; +pub const UNW_FLAG_NHANDLER: DWORD = 0x0; +pub const UNW_FLAG_EHANDLER: DWORD = 0x1; +pub const UNW_FLAG_UHANDLER: DWORD = 0x2; +pub const UNW_FLAG_CHAININFO: DWORD = 0x4; +pub const UNW_FLAG_NO_EPILOGUE: DWORD = 0x80000000; +pub const UNWIND_HISTORY_TABLE_SIZE: usize = 12; +STRUCT!{struct UNWIND_HISTORY_TABLE_ENTRY { + ImageBase: DWORD64, + FunctionEntry: PRUNTIME_FUNCTION, +}} +pub type PUNWIND_HISTORY_TABLE_ENTRY = *mut UNWIND_HISTORY_TABLE_ENTRY; +STRUCT!{struct UNWIND_HISTORY_TABLE { + Count: DWORD, + LocalHint: BYTE, + GlobalHint: BYTE, + Search: BYTE, + Once: BYTE, + LowAddress: DWORD64, + HighAddress: DWORD64, + Entry: [UNWIND_HISTORY_TABLE_ENTRY; UNWIND_HISTORY_TABLE_SIZE], +}} +pub type PUNWIND_HISTORY_TABLE = *mut UNWIND_HISTORY_TABLE; +FN!{cdecl PGET_RUNTIME_FUNCTION_CALLBACK( + ControlPc: DWORD64, + Context: PVOID, +) -> PRUNTIME_FUNCTION} +FN!{cdecl POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK( + Process: HANDLE, + TableAddress: PVOID, + Entries: PDWORD, + Functions: *mut PRUNTIME_FUNCTION, +) -> DWORD} +pub const OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME: &'static str + = "OutOfProcessFunctionTableCallback"; +STRUCT!{struct DISPATCHER_CONTEXT { + ControlPc: DWORD64, + ImageBase: DWORD64, + FunctionEntry: PRUNTIME_FUNCTION, + EstablisherFrame: DWORD64, + TargetIp: DWORD64, + ContextRecord: PCONTEXT, + LanguageHandler: PEXCEPTION_ROUTINE, + HandlerData: PVOID, + HistoryTable: PUNWIND_HISTORY_TABLE, + ScopeIndex: DWORD, + Fill0: DWORD, +}} +pub type PDISPATCHER_CONTEXT = *mut DISPATCHER_CONTEXT; +FN!{cdecl PEXCEPTION_FILTER( + ExceptionPointers: *mut EXCEPTION_POINTERS, + EstablisherFrame: PVOID, +) -> LONG} +FN!{cdecl PTERMINATION_HANDLER( + AbnormalTermination: BOOLEAN, + EstablisherFrame: PVOID, +) -> ()} +STRUCT!{struct KNONVOLATILE_CONTEXT_POINTERS_u1_s { + Xmm0: PM128A, + Xmm1: PM128A, + Xmm2: PM128A, + Xmm3: PM128A, + Xmm4: PM128A, + Xmm5: PM128A, + Xmm6: PM128A, + Xmm7: PM128A, + Xmm8: PM128A, + Xmm9: PM128A, + Xmm10: PM128A, + Xmm11: PM128A, + Xmm12: PM128A, + Xmm13: PM128A, + Xmm14: PM128A, + Xmm15: PM128A, +}} +UNION!{union KNONVOLATILE_CONTEXT_POINTERS_u1 { + [u64; 16], + FloatingContext FloatingContext_mut: [PM128A; 16], + s s_mut: KNONVOLATILE_CONTEXT_POINTERS_u1_s, +}} +STRUCT!{struct KNONVOLATILE_CONTEXT_POINTERS_u2_s { + Rax: PDWORD64, + Rcx: PDWORD64, + Rdx: PDWORD64, + Rbx: PDWORD64, + Rsp: PDWORD64, + Rbp: PDWORD64, + Rsi: PDWORD64, + Rdi: PDWORD64, + R8: PDWORD64, + R9: PDWORD64, + R10: PDWORD64, + R11: PDWORD64, + R12: PDWORD64, + R13: PDWORD64, + R14: PDWORD64, + R15: PDWORD64, +}} +UNION!{union KNONVOLATILE_CONTEXT_POINTERS_u2 { + [u64; 16], + IntegerContext IntegerContext_mut: [PDWORD64; 16], + s s_mut: KNONVOLATILE_CONTEXT_POINTERS_u2_s, +}} +STRUCT!{struct KNONVOLATILE_CONTEXT_POINTERS { + u1: KNONVOLATILE_CONTEXT_POINTERS_u1, + u2: KNONVOLATILE_CONTEXT_POINTERS_u2, +}} +pub type PKNONVOLATILE_CONTEXT_POINTERS = *mut KNONVOLATILE_CONTEXT_POINTERS; +} // IFDEF(x86_64) +#[cfg(target_arch = "x86")] +IFDEF!{ +pub const EXCEPTION_READ_FAULT: DWORD = 0; +pub const EXCEPTION_WRITE_FAULT: DWORD = 1; +pub const EXCEPTION_EXECUTE_FAULT: DWORD = 8; +pub const SIZE_OF_80387_REGISTERS: usize = 80; +pub const CONTEXT_i386: DWORD = 0x00010000; +pub const CONTEXT_i486: DWORD = 0x00010000; +pub const CONTEXT_CONTROL: DWORD = CONTEXT_i386 | 0x00000001; +pub const CONTEXT_INTEGER: DWORD = CONTEXT_i386 | 0x00000002; +pub const CONTEXT_SEGMENTS: DWORD = CONTEXT_i386 | 0x00000004; +pub const CONTEXT_FLOATING_POINT: DWORD = CONTEXT_i386 | 0x00000008; +pub const CONTEXT_DEBUG_REGISTERS: DWORD = CONTEXT_i386 | 0x00000010; +pub const CONTEXT_EXTENDED_REGISTERS: DWORD = CONTEXT_i386 | 0x00000020; +pub const CONTEXT_FULL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; +pub const CONTEXT_ALL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS + | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS; +pub const CONTEXT_XSTATE: DWORD = CONTEXT_i386 | 0x00000040; +pub const CONTEXT_EXCEPTION_ACTIVE: DWORD = 0x08000000; +pub const CONTEXT_SERVICE_ACTIVE: DWORD = 0x10000000; +pub const CONTEXT_EXCEPTION_REQUEST: DWORD = 0x40000000; +pub const CONTEXT_EXCEPTION_REPORTING: DWORD = 0x80000000; +STRUCT!{struct FLOATING_SAVE_AREA { + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, + ErrorSelector: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [BYTE; SIZE_OF_80387_REGISTERS], + Spare0: DWORD, +}} +pub type PFLOATING_SAVE_AREA = *mut FLOATING_SAVE_AREA; +pub const MAXIMUM_SUPPORTED_EXTENSION: usize = 512; +STRUCT!{struct CONTEXT { + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, + ExtendedRegisters: [BYTE; MAXIMUM_SUPPORTED_EXTENSION], +}} +pub type PCONTEXT = *mut CONTEXT; +} // IFDEF(x86) +STRUCT!{struct LDT_ENTRY_Bytes { + BaseMid: BYTE, + Flags1: BYTE, + Flags2: BYTE, + BaseHi: BYTE, +}} +STRUCT!{struct LDT_ENTRY_Bits { + Bitfield: DWORD, +}} +BITFIELD!{LDT_ENTRY_Bits Bitfield: DWORD [ + BaseMid set_BaseMid[0..8], + Type set_Type[8..13], + Dpl set_Dpl[13..15], + Pres set_Pres[15..16], + LimitHi set_LimitHi[16..20], + Sys set_Sys[20..21], + Reserved_0 set_Reserved_0[21..22], + Default_Big set_Default_Big[22..23], + Granularity set_Granularity[23..24], + BaseHi set_BaseHi[24..32], +]} +UNION!{union LDT_ENTRY_HighWord { + [u32; 1], + Bytes Bytes_mut: LDT_ENTRY_Bytes, + Bits Bits_mut: LDT_ENTRY_Bits, +}} +STRUCT!{struct LDT_ENTRY { + LimitLow: WORD, + BaseLow: WORD, + HighWord: LDT_ENTRY_HighWord, +}} +pub type PLDT_ENTRY = *mut LDT_ENTRY; +#[cfg(target_arch = "aarch64")] +IFDEF!{ +pub const ARM64_MAX_BREAKPOINTS: usize = 8; +pub const ARM64_MAX_WATCHPOINTS: usize = 2; +pub const EXCEPTION_READ_FAULT: DWORD = 0; +pub const EXCEPTION_WRITE_FAULT: DWORD = 1; +pub const EXCEPTION_EXECUTE_FAULT: DWORD = 8; +pub const CONTEXT_ARM64: DWORD = 0x00400000; +pub const CONTEXT_CONTROL: DWORD = CONTEXT_ARM64 | 0x00000001; +pub const CONTEXT_INTEGER: DWORD = CONTEXT_ARM64 | 0x00000002; +pub const CONTEXT_FLOATING_POINT: DWORD = CONTEXT_ARM64 | 0x00000004; +pub const CONTEXT_DEBUG_REGISTERS: DWORD = CONTEXT_ARM64 | 0x00000008; +pub const CONTEXT_X18: DWORD = CONTEXT_ARM64 | 0x00000010; +pub const CONTEXT_FULL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; +pub const CONTEXT_ALL: DWORD = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT + | CONTEXT_DEBUG_REGISTERS | CONTEXT_X18; +pub const CONTEXT_EXCEPTION_ACTIVE: DWORD = 0x08000000; +pub const CONTEXT_SERVICE_ACTIVE: DWORD = 0x10000000; +pub const CONTEXT_EXCEPTION_REQUEST: DWORD = 0x40000000; +pub const CONTEXT_EXCEPTION_REPORTING: DWORD = 0x80000000; +STRUCT!{struct CONTEXT_u_s { + X0: DWORD64, + X1: DWORD64, + X2: DWORD64, + X3: DWORD64, + X4: DWORD64, + X5: DWORD64, + X6: DWORD64, + X7: DWORD64, + X8: DWORD64, + X9: DWORD64, + X10: DWORD64, + X11: DWORD64, + X12: DWORD64, + X13: DWORD64, + X14: DWORD64, + X15: DWORD64, + X16: DWORD64, + X17: DWORD64, + X18: DWORD64, + X19: DWORD64, + X20: DWORD64, + X21: DWORD64, + X22: DWORD64, + X23: DWORD64, + X24: DWORD64, + X25: DWORD64, + X26: DWORD64, + X27: DWORD64, + X28: DWORD64, + Fp: DWORD64, + Lr: DWORD64, +}} +UNION!{union CONTEXT_u { + [u64; 31], + s s_mut: CONTEXT_u_s, +}} +STRUCT!{struct ARM64_NT_NEON128_s { + Low: ULONGLONG, + High: LONGLONG, +}} +UNION!{union ARM64_NT_NEON128 { + [u64; 2], + s s_mut: ARM64_NT_NEON128_s, + D D_mut: [f64; 2], + S S_mut: [f32; 4], + H H_mut: [WORD; 8], + B B_mut: [BYTE; 16], +}} +STRUCT!{struct CONTEXT { // FIXME align 16 + ContextFlags: DWORD, + Cpsr: DWORD, + u: CONTEXT_u, + Sp: DWORD64, + Pc: DWORD64, + V: [ARM64_NT_NEON128; 32], + Fpcr: DWORD, + Fpsr: DWORD, + Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], + Bvr: [DWORD64; ARM64_MAX_BREAKPOINTS], + Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], + Wvr: [DWORD64; ARM64_MAX_WATCHPOINTS], +}} +pub type PCONTEXT = *mut CONTEXT; +pub type RUNTIME_FUNCTION = IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type PRUNTIME_FUNCTION = *mut IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type SCOPE_TABLE = SCOPE_TABLE_ARM64; +pub type PSCOPE_TABLE = *mut SCOPE_TABLE_ARM64; +pub const RUNTIME_FUNCTION_INDIRECT: DWORD = 0x1; +pub const UNW_FLAG_NHANDLER: DWORD = 0x0; +pub const UNW_FLAG_EHANDLER: DWORD = 0x1; +pub const UNW_FLAG_UHANDLER: DWORD = 0x2; +pub const UNWIND_HISTORY_TABLE_SIZE: usize = 12; +STRUCT!{struct UNWIND_HISTORY_TABLE_ENTRY { + ImageBase: DWORD64, + FunctionEntry: PRUNTIME_FUNCTION, +}} +pub type PUNWIND_HISTORY_TABLE_ENTRY = *mut UNWIND_HISTORY_TABLE_ENTRY; +STRUCT!{struct UNWIND_HISTORY_TABLE { + Count: DWORD, + LocalHint: BYTE, + GlobalHint: BYTE, + Search: BYTE, + Once: BYTE, + LowAddress: DWORD64, + HighAddress: DWORD64, + Entry: [UNWIND_HISTORY_TABLE_ENTRY; UNWIND_HISTORY_TABLE_SIZE], +}} +pub type PUNWIND_HISTORY_TABLE = *mut UNWIND_HISTORY_TABLE; +FN!{cdecl PGET_RUNTIME_FUNCTION_CALLBACK( + ControlPc: DWORD64, + Context: PVOID, +) -> PRUNTIME_FUNCTION} +FN!{cdecl POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK( + Process: HANDLE, + TableAddress: PVOID, + Entries: PDWORD, + Functions: *mut PRUNTIME_FUNCTION, +) -> DWORD} +pub const OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME: &'static str + = "OutOfProcessFunctionTableCallback"; +STRUCT!{struct DISPATCHER_CONTEXT { + ControlPc: ULONG_PTR, + ImageBase: ULONG_PTR, + FunctionEntry: PRUNTIME_FUNCTION, + EstablisherFrame: ULONG_PTR, + TargetPc: ULONG_PTR, + ContextRecord: PCONTEXT, + LanguageHandler: PEXCEPTION_ROUTINE, + HandlerData: PVOID, + HistoryTable: PUNWIND_HISTORY_TABLE, + ScopeIndex: DWORD, + ControlPcIsUnwound: BOOLEAN, + NonVolatileRegisters: PBYTE, +}} +pub type PDISPATCHER_CONTEXT = *mut DISPATCHER_CONTEXT; +FN!{cdecl PEXCEPTION_FILTER( + ExceptionPointers: *mut EXCEPTION_POINTERS, + EstablisherFrame: DWORD64, +) -> LONG} +FN!{cdecl PTERMINATION_HANDLER( + AbnormalTermination: BOOLEAN, + EstablisherFrame: DWORD64, +) -> ()} +STRUCT!{struct KNONVOLATILE_CONTEXT_POINTERS { + X19: PDWORD64, + X20: PDWORD64, + X21: PDWORD64, + X22: PDWORD64, + X23: PDWORD64, + X24: PDWORD64, + X25: PDWORD64, + X26: PDWORD64, + X27: PDWORD64, + X28: PDWORD64, + Fp: PDWORD64, + Lr: PDWORD64, + D8: PDWORD64, + D9: PDWORD64, + D10: PDWORD64, + D11: PDWORD64, + D12: PDWORD64, + D13: PDWORD64, + D14: PDWORD64, + D15: PDWORD64, +}} +pub type PKNONVOLATILE_CONTEXT_POINTERS = *mut KNONVOLATILE_CONTEXT_POINTERS; +} // IFDEF(aarch64) +pub const WOW64_CONTEXT_i386: DWORD = 0x00010000; +pub const WOW64_CONTEXT_i486: DWORD = 0x00010000; +pub const WOW64_CONTEXT_CONTROL: DWORD = WOW64_CONTEXT_i386 | 0x00000001; +pub const WOW64_CONTEXT_INTEGER: DWORD = WOW64_CONTEXT_i386 | 0x00000002; +pub const WOW64_CONTEXT_SEGMENTS: DWORD = WOW64_CONTEXT_i386 | 0x00000004; +pub const WOW64_CONTEXT_FLOATING_POINT: DWORD = WOW64_CONTEXT_i386 | 0x00000008; +pub const WOW64_CONTEXT_DEBUG_REGISTERS: DWORD = WOW64_CONTEXT_i386 | 0x00000010; +pub const WOW64_CONTEXT_EXTENDED_REGISTERS: DWORD = WOW64_CONTEXT_i386 | 0x00000020; +pub const WOW64_CONTEXT_FULL: DWORD = WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER + | WOW64_CONTEXT_SEGMENTS; +pub const WOW64_CONTEXT_ALL: DWORD = WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_INTEGER + | WOW64_CONTEXT_SEGMENTS | WOW64_CONTEXT_FLOATING_POINT | WOW64_CONTEXT_DEBUG_REGISTERS + | WOW64_CONTEXT_EXTENDED_REGISTERS; +pub const WOW64_CONTEXT_XSTATE: DWORD = WOW64_CONTEXT_i386 | 0x00000040; +pub const WOW64_CONTEXT_EXCEPTION_ACTIVE: DWORD = 0x08000000; +pub const WOW64_CONTEXT_SERVICE_ACTIVE: DWORD = 0x10000000; +pub const WOW64_CONTEXT_EXCEPTION_REQUEST: DWORD = 0x40000000; +pub const WOW64_CONTEXT_EXCEPTION_REPORTING: DWORD = 0x80000000; +pub const WOW64_SIZE_OF_80387_REGISTERS: usize = 80; +pub const WOW64_MAXIMUM_SUPPORTED_EXTENSION: usize = 512; +STRUCT!{struct WOW64_FLOATING_SAVE_AREA { + ControlWord: DWORD, + StatusWord: DWORD, + TagWord: DWORD, + ErrorOffset: DWORD, + ErrorSelector: DWORD, + DataOffset: DWORD, + DataSelector: DWORD, + RegisterArea: [BYTE; WOW64_SIZE_OF_80387_REGISTERS], + Cr0NpxState: DWORD, +}} +pub type PWOW64_FLOATING_SAVE_AREA = *mut WOW64_FLOATING_SAVE_AREA; +STRUCT!{struct WOW64_CONTEXT { + ContextFlags: DWORD, + Dr0: DWORD, + Dr1: DWORD, + Dr2: DWORD, + Dr3: DWORD, + Dr6: DWORD, + Dr7: DWORD, + FloatSave: WOW64_FLOATING_SAVE_AREA, + SegGs: DWORD, + SegFs: DWORD, + SegEs: DWORD, + SegDs: DWORD, + Edi: DWORD, + Esi: DWORD, + Ebx: DWORD, + Edx: DWORD, + Ecx: DWORD, + Eax: DWORD, + Ebp: DWORD, + Eip: DWORD, + SegCs: DWORD, + EFlags: DWORD, + Esp: DWORD, + SegSs: DWORD, + ExtendedRegisters: [BYTE; WOW64_MAXIMUM_SUPPORTED_EXTENSION], +}} +pub type PWOW64_CONTEXT = *mut WOW64_CONTEXT; +STRUCT!{struct WOW64_LDT_ENTRY_Bytes { + BaseMid: BYTE, + Flags1: BYTE, + Flags2: BYTE, + BaseHi: BYTE, +}} +STRUCT!{struct WOW64_LDT_ENTRY_Bits { + BitFields: DWORD, +}} +BITFIELD!{WOW64_LDT_ENTRY_Bits BitFields: DWORD [ + BaseMid set_BaseMid[0..8], + Type set_Type[8..13], + Dpl set_Dpl[13..15], + Pres set_Pres[15..16], + LimitHi set_LimitHi[16..20], + Sys set_Sys[20..21], + Reserved_0 set_Reserved_0[21..22], + Default_Big set_Default_Big[22..23], + Granularity set_Granularity[23..24], + BaseHi set_BaseHi[24..32], +]} +UNION!{union WOW64_LDT_ENTRY_HighWord { + [u32; 1], + Bytes Bytes_mut: WOW64_LDT_ENTRY_Bytes, + Bits Bits_mut: WOW64_LDT_ENTRY_Bits, +}} +STRUCT!{struct WOW64_LDT_ENTRY { + LimitLow: WORD, + BaseLow: WORD, + HighWord: WOW64_LDT_ENTRY_HighWord, +}} +pub type PWOW64_LDT_ENTRY = *mut WOW64_LDT_ENTRY; +STRUCT!{struct WOW64_DESCRIPTOR_TABLE_ENTRY { + Selector: DWORD, + Descriptor: WOW64_LDT_ENTRY, +}} +pub type PWOW64_DESCRIPTOR_TABLE_ENTRY = *mut WOW64_DESCRIPTOR_TABLE_ENTRY; +pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; +pub const EXCEPTION_UNWINDING: DWORD = 0x2; +pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; +pub const EXCEPTION_STACK_INVALID: DWORD = 0x8; +pub const EXCEPTION_NESTED_CALL: DWORD = 0x10; +pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; +pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; +pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND + | EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND; +#[inline] +pub fn IS_UNWINDING(Flag: DWORD) -> bool { + (Flag & EXCEPTION_UNWIND) != 0 +} +#[inline] +pub fn IS_DISPATCHING(Flag: DWORD) -> bool { + (Flag & EXCEPTION_UNWIND) == 0 +} +#[inline] +pub fn IS_TARGET_UNWIND(Flag: DWORD) -> bool { + (Flag & EXCEPTION_TARGET_UNWIND) != 0 +} +pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; +STRUCT!{struct EXCEPTION_RECORD { + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: *mut EXCEPTION_RECORD, + ExceptionAddress: PVOID, + NumberParameters: DWORD, + ExceptionInformation: [ULONG_PTR; EXCEPTION_MAXIMUM_PARAMETERS], +}} +pub type PEXCEPTION_RECORD = *mut EXCEPTION_RECORD; +STRUCT!{struct EXCEPTION_RECORD32 { + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: DWORD, + ExceptionAddress: DWORD, + NumberParameters: DWORD, + ExceptionInformation: [DWORD; EXCEPTION_MAXIMUM_PARAMETERS], +}} +pub type PEXCEPTION_RECORD32 = *mut EXCEPTION_RECORD32; +STRUCT!{struct EXCEPTION_RECORD64 { + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: DWORD64, + ExceptionAddress: DWORD64, + NumberParameters: DWORD, + __unusedAlignment: DWORD, + ExceptionInformation: [DWORD64; EXCEPTION_MAXIMUM_PARAMETERS], +}} +pub type PEXCEPTION_RECORD64 = *mut EXCEPTION_RECORD64; +STRUCT!{struct EXCEPTION_POINTERS { + ExceptionRecord: PEXCEPTION_RECORD, + ContextRecord: PCONTEXT, +}} +pub type PEXCEPTION_POINTERS = *mut EXCEPTION_POINTERS; +pub type PACCESS_TOKEN = PVOID; +pub type PSECURITY_DESCRIPTOR = PVOID; +pub type PSID = PVOID; +pub type PCLAIMS_BLOB = PVOID; +pub type ACCESS_MASK = DWORD; +pub type PACCESS_MASK = *mut ACCESS_MASK; +pub const DELETE: DWORD = 0x00010000; +pub const READ_CONTROL: DWORD = 0x00020000; +pub const WRITE_DAC: DWORD = 0x00040000; +pub const WRITE_OWNER: DWORD = 0x00080000; +pub const SYNCHRONIZE: DWORD = 0x00100000; +pub const STANDARD_RIGHTS_REQUIRED: DWORD = 0x000F0000; +pub const STANDARD_RIGHTS_READ: DWORD = READ_CONTROL; +pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL; +pub const STANDARD_RIGHTS_EXECUTE: DWORD = READ_CONTROL; +pub const STANDARD_RIGHTS_ALL: DWORD = 0x001F0000; +pub const SPECIFIC_RIGHTS_ALL: DWORD = 0x0000FFFF; +pub const ACCESS_SYSTEM_SECURITY: DWORD = 0x01000000; +pub const MAXIMUM_ALLOWED: DWORD = 0x02000000; +pub const GENERIC_READ: DWORD = 0x80000000; +pub const GENERIC_WRITE: DWORD = 0x40000000; +pub const GENERIC_EXECUTE: DWORD = 0x20000000; +pub const GENERIC_ALL: DWORD = 0x10000000; +STRUCT!{struct GENERIC_MAPPING { + GenericRead: ACCESS_MASK, + GenericWrite: ACCESS_MASK, + GenericExecute: ACCESS_MASK, + GenericAll: ACCESS_MASK, +}} +pub type PGENERIC_MAPPING = *mut GENERIC_MAPPING; +STRUCT!{struct LUID_AND_ATTRIBUTES { + Luid: LUID, + Attributes: DWORD, +}} +pub type PLUID_AND_ATTRIBUTES = *mut LUID_AND_ATTRIBUTES; +pub type LUID_AND_ATTRIBUTES_ARRAY = LUID_AND_ATTRIBUTES; +pub type PLUID_AND_ATTRIBUTES_ARRAY = *mut LUID_AND_ATTRIBUTES; +STRUCT!{struct SID_IDENTIFIER_AUTHORITY { + Value: [BYTE; 6], +}} +pub type PSID_IDENTIFIER_AUTHORITY = *mut SID_IDENTIFIER_AUTHORITY; +STRUCT!{struct SID { + Revision: BYTE, + SubAuthorityCount: BYTE, + IdentifierAuthority: SID_IDENTIFIER_AUTHORITY, + SubAuthority: [DWORD; 1], +}} +pub type PISID = *mut SID; +pub const SID_REVISION: BYTE = 1; +pub const SID_MAX_SUB_AUTHORITIES: BYTE = 15; +pub const SID_RECOMMENDED_SUB_AUTHORITIES: BYTE = 1; +pub const SECURITY_MAX_SID_SIZE: usize = 12 - 4 + (SID_MAX_SUB_AUTHORITIES as usize * 4); +pub const SECURITY_MAX_SID_STRING_CHARACTERS: BYTE = 2 + 4 + 15 + (11 * SID_MAX_SUB_AUTHORITIES) + + 1; +UNION!{union SE_SID { + [u32; 17], + Sid Sid_mut: SID, + Buffer Buffer_mut: [BYTE; SECURITY_MAX_SID_SIZE], +}} +pub type PSE_SID = *mut SE_SID; +ENUM!{enum SID_NAME_USE { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown, + SidTypeComputer, + SidTypeLabel, + SidTypeLogonSession, +}} +pub type PSID_NAME_USE = *mut SID_NAME_USE; +STRUCT!{struct SID_AND_ATTRIBUTES { + Sid: PSID, + Attributes: DWORD, +}} +pub type PSID_AND_ATTRIBUTES = *mut SID_AND_ATTRIBUTES; +pub type SID_AND_ATTRIBUTES_ARRAY = SID_AND_ATTRIBUTES; +pub type PSID_AND_ATTRIBUTES_ARRAY = *mut SID_AND_ATTRIBUTES; +pub const SID_HASH_SIZE: usize = 32; +pub type SID_HASH_ENTRY = ULONG_PTR; +pub type PSID_HASH_ENTRY = *mut ULONG_PTR; +STRUCT!{struct SID_AND_ATTRIBUTES_HASH { + SidCount: DWORD, + SidAttr: PSID_AND_ATTRIBUTES, + Hash: [SID_HASH_ENTRY; SID_HASH_SIZE], +}} +pub type PSID_AND_ATTRIBUTES_HASH = *mut SID_AND_ATTRIBUTES_HASH; +pub const SECURITY_NULL_SID_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 0]; +pub const SECURITY_WORLD_SID_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 1]; +pub const SECURITY_LOCAL_SID_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 2]; +pub const SECURITY_CREATOR_SID_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 3]; +pub const SECURITY_NON_UNIQUE_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 4]; +pub const SECURITY_RESOURCE_MANAGER_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 9]; +pub const SECURITY_NULL_RID: DWORD = 0x00000000; +pub const SECURITY_WORLD_RID: DWORD = 0x00000000; +pub const SECURITY_LOCAL_RID: DWORD = 0x00000000; +pub const SECURITY_LOCAL_LOGON_RID: DWORD = 0x00000001; +pub const SECURITY_CREATOR_OWNER_RID: DWORD = 0x00000000; +pub const SECURITY_CREATOR_GROUP_RID: DWORD = 0x00000001; +pub const SECURITY_CREATOR_OWNER_SERVER_RID: DWORD = 0x00000002; +pub const SECURITY_CREATOR_GROUP_SERVER_RID: DWORD = 0x00000003; +pub const SECURITY_CREATOR_OWNER_RIGHTS_RID: DWORD = 0x00000004; +pub const SECURITY_NT_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 5]; +pub const SECURITY_DIALUP_RID: DWORD = 0x00000001; +pub const SECURITY_NETWORK_RID: DWORD = 0x00000002; +pub const SECURITY_BATCH_RID: DWORD = 0x00000003; +pub const SECURITY_INTERACTIVE_RID: DWORD = 0x00000004; +pub const SECURITY_LOGON_IDS_RID: DWORD = 0x00000005; +pub const SECURITY_LOGON_IDS_RID_COUNT: DWORD = 3; +pub const SECURITY_SERVICE_RID: DWORD = 0x00000006; +pub const SECURITY_ANONYMOUS_LOGON_RID: DWORD = 0x00000007; +pub const SECURITY_PROXY_RID: DWORD = 0x00000008; +pub const SECURITY_ENTERPRISE_CONTROLLERS_RID: DWORD = 0x00000009; +pub const SECURITY_SERVER_LOGON_RID: DWORD = SECURITY_ENTERPRISE_CONTROLLERS_RID; +pub const SECURITY_PRINCIPAL_SELF_RID: DWORD = 0x0000000A; +pub const SECURITY_AUTHENTICATED_USER_RID: DWORD = 0x0000000B; +pub const SECURITY_RESTRICTED_CODE_RID: DWORD = 0x0000000C; +pub const SECURITY_TERMINAL_SERVER_RID: DWORD = 0x0000000D; +pub const SECURITY_REMOTE_LOGON_RID: DWORD = 0x0000000E; +pub const SECURITY_THIS_ORGANIZATION_RID: DWORD = 0x0000000F; +pub const SECURITY_IUSER_RID: DWORD = 0x00000011; +pub const SECURITY_LOCAL_SYSTEM_RID: DWORD = 0x00000012; +pub const SECURITY_LOCAL_SERVICE_RID: DWORD = 0x00000013; +pub const SECURITY_NETWORK_SERVICE_RID: DWORD = 0x00000014; +pub const SECURITY_NT_NON_UNIQUE: DWORD = 0x00000015; +pub const SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT: DWORD = 3; +pub const SECURITY_ENTERPRISE_READONLY_CONTROLLERS_RID: DWORD = 0x00000016; +pub const SECURITY_BUILTIN_DOMAIN_RID: DWORD = 0x00000020; +pub const SECURITY_WRITE_RESTRICTED_CODE_RID: DWORD = 0x00000021; +pub const SECURITY_PACKAGE_BASE_RID: DWORD = 0x00000040; +pub const SECURITY_PACKAGE_RID_COUNT: DWORD = 2; +pub const SECURITY_PACKAGE_NTLM_RID: DWORD = 0x0000000A; +pub const SECURITY_PACKAGE_SCHANNEL_RID: DWORD = 0x0000000E; +pub const SECURITY_PACKAGE_DIGEST_RID: DWORD = 0x00000015; +pub const SECURITY_CRED_TYPE_BASE_RID: DWORD = 0x00000041; +pub const SECURITY_CRED_TYPE_RID_COUNT: DWORD = 2; +pub const SECURITY_CRED_TYPE_THIS_ORG_CERT_RID: DWORD = 0x00000001; +pub const SECURITY_MIN_BASE_RID: DWORD = 0x00000050; +pub const SECURITY_SERVICE_ID_BASE_RID: DWORD = 0x00000050; +pub const SECURITY_SERVICE_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_RESERVED_ID_BASE_RID: DWORD = 0x00000051; +pub const SECURITY_APPPOOL_ID_BASE_RID: DWORD = 0x00000052; +pub const SECURITY_APPPOOL_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_VIRTUALSERVER_ID_BASE_RID: DWORD = 0x00000053; +pub const SECURITY_VIRTUALSERVER_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_USERMODEDRIVERHOST_ID_BASE_RID: DWORD = 0x00000054; +pub const SECURITY_USERMODEDRIVERHOST_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_CLOUD_INFRASTRUCTURE_SERVICES_ID_BASE_RID: DWORD = 0x00000055; +pub const SECURITY_CLOUD_INFRASTRUCTURE_SERVICES_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_WMIHOST_ID_BASE_RID: DWORD = 0x00000056; +pub const SECURITY_WMIHOST_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_TASK_ID_BASE_RID: DWORD = 0x00000057; +pub const SECURITY_NFS_ID_BASE_RID: DWORD = 0x00000058; +pub const SECURITY_COM_ID_BASE_RID: DWORD = 0x00000059; +pub const SECURITY_WINDOW_MANAGER_BASE_RID: DWORD = 0x0000005A; +pub const SECURITY_RDV_GFX_BASE_RID: DWORD = 0x0000005B; +pub const SECURITY_DASHOST_ID_BASE_RID: DWORD = 0x0000005C; +pub const SECURITY_DASHOST_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_USERMANAGER_ID_BASE_RID: DWORD = 0x0000005D; +pub const SECURITY_USERMANAGER_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_WINRM_ID_BASE_RID: DWORD = 0x0000005E; +pub const SECURITY_WINRM_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_CCG_ID_BASE_RID: DWORD = 0x0000005F; +pub const SECURITY_UMFD_BASE_RID: DWORD = 0x00000060; +pub const SECURITY_VIRTUALACCOUNT_ID_RID_COUNT: DWORD = 6; +pub const SECURITY_MAX_BASE_RID: DWORD = 0x0000006F; +pub const SECURITY_MAX_ALWAYS_FILTERED: DWORD = 0x000003E7; +pub const SECURITY_MIN_NEVER_FILTERED: DWORD = 0x000003E8; +pub const SECURITY_OTHER_ORGANIZATION_RID: DWORD = 0x000003E8; +pub const SECURITY_WINDOWSMOBILE_ID_BASE_RID: DWORD = 0x00000070; +pub const SECURITY_INSTALLER_GROUP_CAPABILITY_BASE: DWORD = 0x20; +pub const SECURITY_INSTALLER_GROUP_CAPABILITY_RID_COUNT: DWORD = 9; +pub const SECURITY_INSTALLER_CAPABILITY_RID_COUNT: DWORD = 10; +pub const SECURITY_LOCAL_ACCOUNT_RID: DWORD = 0x00000071; +pub const SECURITY_LOCAL_ACCOUNT_AND_ADMIN_RID: DWORD = 0x00000072; +pub const DOMAIN_GROUP_RID_AUTHORIZATION_DATA_IS_COMPOUNDED: DWORD = 0x000001F0; +pub const DOMAIN_GROUP_RID_AUTHORIZATION_DATA_CONTAINS_CLAIMS: DWORD = 0x000001F1; +pub const DOMAIN_GROUP_RID_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS: DWORD = 0x000001F2; +pub const FOREST_USER_RID_MAX: DWORD = 0x000001F3; +pub const DOMAIN_USER_RID_ADMIN: DWORD = 0x000001F4; +pub const DOMAIN_USER_RID_GUEST: DWORD = 0x000001F5; +pub const DOMAIN_USER_RID_KRBTGT: DWORD = 0x000001F6; +pub const DOMAIN_USER_RID_DEFAULT_ACCOUNT: DWORD = 0x000001F7; +pub const DOMAIN_USER_RID_MAX: DWORD = 0x000003E7; +pub const DOMAIN_GROUP_RID_ADMINS: DWORD = 0x00000200; +pub const DOMAIN_GROUP_RID_USERS: DWORD = 0x00000201; +pub const DOMAIN_GROUP_RID_GUESTS: DWORD = 0x00000202; +pub const DOMAIN_GROUP_RID_COMPUTERS: DWORD = 0x00000203; +pub const DOMAIN_GROUP_RID_CONTROLLERS: DWORD = 0x00000204; +pub const DOMAIN_GROUP_RID_CERT_ADMINS: DWORD = 0x00000205; +pub const DOMAIN_GROUP_RID_SCHEMA_ADMINS: DWORD = 0x00000206; +pub const DOMAIN_GROUP_RID_ENTERPRISE_ADMINS: DWORD = 0x00000207; +pub const DOMAIN_GROUP_RID_POLICY_ADMINS: DWORD = 0x00000208; +pub const DOMAIN_GROUP_RID_READONLY_CONTROLLERS: DWORD = 0x00000209; +pub const DOMAIN_GROUP_RID_CLONEABLE_CONTROLLERS: DWORD = 0x0000020A; +pub const DOMAIN_GROUP_RID_CDC_RESERVED: DWORD = 0x0000020C; +pub const DOMAIN_GROUP_RID_PROTECTED_USERS: DWORD = 0x0000020D; +pub const DOMAIN_GROUP_RID_KEY_ADMINS: DWORD = 0x0000020E; +pub const DOMAIN_GROUP_RID_ENTERPRISE_KEY_ADMINS: DWORD = 0x0000020F; +pub const DOMAIN_ALIAS_RID_ADMINS: DWORD = 0x00000220; +pub const DOMAIN_ALIAS_RID_USERS: DWORD = 0x00000221; +pub const DOMAIN_ALIAS_RID_GUESTS: DWORD = 0x00000222; +pub const DOMAIN_ALIAS_RID_POWER_USERS: DWORD = 0x00000223; +pub const DOMAIN_ALIAS_RID_ACCOUNT_OPS: DWORD = 0x00000224; +pub const DOMAIN_ALIAS_RID_SYSTEM_OPS: DWORD = 0x00000225; +pub const DOMAIN_ALIAS_RID_PRINT_OPS: DWORD = 0x00000226; +pub const DOMAIN_ALIAS_RID_BACKUP_OPS: DWORD = 0x00000227; +pub const DOMAIN_ALIAS_RID_REPLICATOR: DWORD = 0x00000228; +pub const DOMAIN_ALIAS_RID_RAS_SERVERS: DWORD = 0x00000229; +pub const DOMAIN_ALIAS_RID_PREW2KCOMPACCESS: DWORD = 0x0000022A; +pub const DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS: DWORD = 0x0000022B; +pub const DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS: DWORD = 0x0000022C; +pub const DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS: DWORD = 0x0000022D; +pub const DOMAIN_ALIAS_RID_MONITORING_USERS: DWORD = 0x0000022E; +pub const DOMAIN_ALIAS_RID_LOGGING_USERS: DWORD = 0x0000022F; +pub const DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS: DWORD = 0x00000230; +pub const DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS: DWORD = 0x00000231; +pub const DOMAIN_ALIAS_RID_DCOM_USERS: DWORD = 0x00000232; +pub const DOMAIN_ALIAS_RID_IUSERS: DWORD = 0x00000238; +pub const DOMAIN_ALIAS_RID_CRYPTO_OPERATORS: DWORD = 0x00000239; +pub const DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP: DWORD = 0x0000023B; +pub const DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP: DWORD = 0x0000023C; +pub const DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP: DWORD = 0x0000023D; +pub const DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP: DWORD = 0x0000023E; +pub const DOMAIN_ALIAS_RID_RDS_REMOTE_ACCESS_SERVERS: DWORD = 0x0000023F; +pub const DOMAIN_ALIAS_RID_RDS_ENDPOINT_SERVERS: DWORD = 0x00000240; +pub const DOMAIN_ALIAS_RID_RDS_MANAGEMENT_SERVERS: DWORD = 0x00000241; +pub const DOMAIN_ALIAS_RID_HYPER_V_ADMINS: DWORD = 0x00000242; +pub const DOMAIN_ALIAS_RID_ACCESS_CONTROL_ASSISTANCE_OPS: DWORD = 0x00000243; +pub const DOMAIN_ALIAS_RID_REMOTE_MANAGEMENT_USERS: DWORD = 0x00000244; +pub const DOMAIN_ALIAS_RID_DEFAULT_ACCOUNT: DWORD = 0x00000245; +pub const DOMAIN_ALIAS_RID_STORAGE_REPLICA_ADMINS: DWORD = 0x00000246; +pub const SECURITY_APP_PACKAGE_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 15]; +pub const SECURITY_APP_PACKAGE_BASE_RID: DWORD = 0x00000002; +pub const SECURITY_BUILTIN_APP_PACKAGE_RID_COUNT: DWORD = 2; +pub const SECURITY_APP_PACKAGE_RID_COUNT: DWORD = 8; +pub const SECURITY_CAPABILITY_BASE_RID: DWORD = 0x00000003; +pub const SECURITY_CAPABILITY_APP_RID: DWORD = 0x00000040; +pub const SECURITY_BUILTIN_CAPABILITY_RID_COUNT: DWORD = 2; +pub const SECURITY_CAPABILITY_RID_COUNT: DWORD = 5; +pub const SECURITY_PARENT_PACKAGE_RID_COUNT: DWORD = SECURITY_APP_PACKAGE_RID_COUNT; +pub const SECURITY_CHILD_PACKAGE_RID_COUNT: DWORD = 12; +pub const SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE: DWORD = 0x00000001; +pub const SECURITY_BUILTIN_PACKAGE_ANY_RESTRICTED_PACKAGE: DWORD = 0x00000002; +pub const SECURITY_CAPABILITY_INTERNET_CLIENT: DWORD = 0x00000001; +pub const SECURITY_CAPABILITY_INTERNET_CLIENT_SERVER: DWORD = 0x00000002; +pub const SECURITY_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER: DWORD = 0x00000003; +pub const SECURITY_CAPABILITY_PICTURES_LIBRARY: DWORD = 0x00000004; +pub const SECURITY_CAPABILITY_VIDEOS_LIBRARY: DWORD = 0x00000005; +pub const SECURITY_CAPABILITY_MUSIC_LIBRARY: DWORD = 0x00000006; +pub const SECURITY_CAPABILITY_DOCUMENTS_LIBRARY: DWORD = 0x00000007; +pub const SECURITY_CAPABILITY_ENTERPRISE_AUTHENTICATION: DWORD = 0x00000008; +pub const SECURITY_CAPABILITY_SHARED_USER_CERTIFICATES: DWORD = 0x00000009; +pub const SECURITY_CAPABILITY_REMOVABLE_STORAGE: DWORD = 0x0000000A; +pub const SECURITY_CAPABILITY_APPOINTMENTS: DWORD = 0x0000000B; +pub const SECURITY_CAPABILITY_CONTACTS: DWORD = 0x0000000C; +pub const SECURITY_CAPABILITY_INTERNET_EXPLORER: DWORD = 0x00001000; +pub const SECURITY_MANDATORY_LABEL_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 16]; +pub const SECURITY_MANDATORY_UNTRUSTED_RID: DWORD = 0x00000000; +pub const SECURITY_MANDATORY_LOW_RID: DWORD = 0x00001000; +pub const SECURITY_MANDATORY_MEDIUM_RID: DWORD = 0x00002000; +pub const SECURITY_MANDATORY_MEDIUM_PLUS_RID: DWORD = SECURITY_MANDATORY_MEDIUM_RID + 0x10; +pub const SECURITY_MANDATORY_HIGH_RID: DWORD = 0x00003000; +pub const SECURITY_MANDATORY_SYSTEM_RID: DWORD = 0x00004000; +pub const SECURITY_MANDATORY_MAXIMUM_USER_RID: DWORD = SECURITY_MANDATORY_SYSTEM_RID; +#[inline] +pub fn MANDATORY_LEVEL_TO_MANDATORY_RID(IL: DWORD) -> DWORD { + IL * 0x1000 +} +pub const SECURITY_SCOPED_POLICY_ID_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 17]; +pub const SECURITY_AUTHENTICATION_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 18]; +pub const SECURITY_AUTHENTICATION_AUTHORITY_RID_COUNT: DWORD = 1; +pub const SECURITY_AUTHENTICATION_AUTHORITY_ASSERTED_RID: DWORD = 0x00000001; +pub const SECURITY_AUTHENTICATION_SERVICE_ASSERTED_RID: DWORD = 0x00000002; +pub const SECURITY_AUTHENTICATION_FRESH_KEY_AUTH_RID: DWORD = 0x00000003; +pub const SECURITY_AUTHENTICATION_KEY_TRUST_RID: DWORD = 0x00000004; +pub const SECURITY_AUTHENTICATION_KEY_PROPERTY_MFA_RID: DWORD = 0x00000005; +pub const SECURITY_AUTHENTICATION_KEY_PROPERTY_ATTESTATION_RID: DWORD = 0x00000006; +pub const SECURITY_PROCESS_TRUST_AUTHORITY: [BYTE; 6] = [0, 0, 0, 0, 0, 19]; +pub const SECURITY_PROCESS_TRUST_AUTHORITY_RID_COUNT: DWORD = 2; +pub const SECURITY_PROCESS_PROTECTION_TYPE_FULL_RID: DWORD = 0x00000400; +pub const SECURITY_PROCESS_PROTECTION_TYPE_LITE_RID: DWORD = 0x00000200; +pub const SECURITY_PROCESS_PROTECTION_TYPE_NONE_RID: DWORD = 0x00000000; +pub const SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID: DWORD = 0x00002000; +pub const SECURITY_PROCESS_PROTECTION_LEVEL_WINDOWS_RID: DWORD = 0x00001000; +pub const SECURITY_PROCESS_PROTECTION_LEVEL_APP_RID: DWORD = 0x00000800; +pub const SECURITY_PROCESS_PROTECTION_LEVEL_NONE_RID: DWORD = 0x00000000; +pub const SECURITY_TRUSTED_INSTALLER_RID1: DWORD = 95600888; +pub const SECURITY_TRUSTED_INSTALLER_RID2: DWORD = 341852264; +pub const SECURITY_TRUSTED_INSTALLER_RID3: DWORD = 183103804; +pub const SECURITY_TRUSTED_INSTALLER_RID4: DWORD = 185329263; +pub const SECURITY_TRUSTED_INSTALLER_RID5: DWORD = 227147846; +ENUM!{enum WELL_KNOWN_SID_TYPE { + WinNullSid = 0, + WinWorldSid = 1, + WinLocalSid = 2, + WinCreatorOwnerSid = 3, + WinCreatorGroupSid = 4, + WinCreatorOwnerServerSid = 5, + WinCreatorGroupServerSid = 6, + WinNtAuthoritySid = 7, + WinDialupSid = 8, + WinNetworkSid = 9, + WinBatchSid = 10, + WinInteractiveSid = 11, + WinServiceSid = 12, + WinAnonymousSid = 13, + WinProxySid = 14, + WinEnterpriseControllersSid = 15, + WinSelfSid = 16, + WinAuthenticatedUserSid = 17, + WinRestrictedCodeSid = 18, + WinTerminalServerSid = 19, + WinRemoteLogonIdSid = 20, + WinLogonIdsSid = 21, + WinLocalSystemSid = 22, + WinLocalServiceSid = 23, + WinNetworkServiceSid = 24, + WinBuiltinDomainSid = 25, + WinBuiltinAdministratorsSid = 26, + WinBuiltinUsersSid = 27, + WinBuiltinGuestsSid = 28, + WinBuiltinPowerUsersSid = 29, + WinBuiltinAccountOperatorsSid = 30, + WinBuiltinSystemOperatorsSid = 31, + WinBuiltinPrintOperatorsSid = 32, + WinBuiltinBackupOperatorsSid = 33, + WinBuiltinReplicatorSid = 34, + WinBuiltinPreWindows2000CompatibleAccessSid = 35, + WinBuiltinRemoteDesktopUsersSid = 36, + WinBuiltinNetworkConfigurationOperatorsSid = 37, + WinAccountAdministratorSid = 38, + WinAccountGuestSid = 39, + WinAccountKrbtgtSid = 40, + WinAccountDomainAdminsSid = 41, + WinAccountDomainUsersSid = 42, + WinAccountDomainGuestsSid = 43, + WinAccountComputersSid = 44, + WinAccountControllersSid = 45, + WinAccountCertAdminsSid = 46, + WinAccountSchemaAdminsSid = 47, + WinAccountEnterpriseAdminsSid = 48, + WinAccountPolicyAdminsSid = 49, + WinAccountRasAndIasServersSid = 50, + WinNTLMAuthenticationSid = 51, + WinDigestAuthenticationSid = 52, + WinSChannelAuthenticationSid = 53, + WinThisOrganizationSid = 54, + WinOtherOrganizationSid = 55, + WinBuiltinIncomingForestTrustBuildersSid = 56, + WinBuiltinPerfMonitoringUsersSid = 57, + WinBuiltinPerfLoggingUsersSid = 58, + WinBuiltinAuthorizationAccessSid = 59, + WinBuiltinTerminalServerLicenseServersSid = 60, + WinBuiltinDCOMUsersSid = 61, + WinBuiltinIUsersSid = 62, + WinIUserSid = 63, + WinBuiltinCryptoOperatorsSid = 64, + WinUntrustedLabelSid = 65, + WinLowLabelSid = 66, + WinMediumLabelSid = 67, + WinHighLabelSid = 68, + WinSystemLabelSid = 69, + WinWriteRestrictedCodeSid = 70, + WinCreatorOwnerRightsSid = 71, + WinCacheablePrincipalsGroupSid = 72, + WinNonCacheablePrincipalsGroupSid = 73, + WinEnterpriseReadonlyControllersSid = 74, + WinAccountReadonlyControllersSid = 75, + WinBuiltinEventLogReadersGroup = 76, + WinNewEnterpriseReadonlyControllersSid = 77, + WinBuiltinCertSvcDComAccessGroup = 78, + WinMediumPlusLabelSid = 79, + WinLocalLogonSid = 80, + WinConsoleLogonSid = 81, + WinThisOrganizationCertificateSid = 82, + WinApplicationPackageAuthoritySid = 83, + WinBuiltinAnyPackageSid = 84, + WinCapabilityInternetClientSid = 85, + WinCapabilityInternetClientServerSid = 86, + WinCapabilityPrivateNetworkClientServerSid = 87, + WinCapabilityPicturesLibrarySid = 88, + WinCapabilityVideosLibrarySid = 89, + WinCapabilityMusicLibrarySid = 90, + WinCapabilityDocumentsLibrarySid = 91, + WinCapabilitySharedUserCertificatesSid = 92, + WinCapabilityEnterpriseAuthenticationSid = 93, + WinCapabilityRemovableStorageSid = 94, + WinBuiltinRDSRemoteAccessServersSid = 95, + WinBuiltinRDSEndpointServersSid = 96, + WinBuiltinRDSManagementServersSid = 97, + WinUserModeDriversSid = 98, + WinBuiltinHyperVAdminsSid = 99, + WinAccountCloneableControllersSid = 100, + WinBuiltinAccessControlAssistanceOperatorsSid = 101, + WinBuiltinRemoteManagementUsersSid = 102, + WinAuthenticationAuthorityAssertedSid = 103, + WinAuthenticationServiceAssertedSid = 104, + WinLocalAccountSid = 105, + WinLocalAccountAndAdministratorSid = 106, + WinAccountProtectedUsersSid = 107, + WinCapabilityAppointmentsSid = 108, + WinCapabilityContactsSid = 109, + WinAccountDefaultSystemManagedSid = 110, + WinBuiltinDefaultSystemManagedGroupSid = 111, + WinBuiltinStorageReplicaAdminsSid = 112, + WinAccountKeyAdminsSid = 113, + WinAccountEnterpriseKeyAdminsSid = 114, + WinAuthenticationKeyTrustSid = 115, + WinAuthenticationKeyPropertyMFASid = 116, + WinAuthenticationKeyPropertyAttestationSid = 117, + WinAuthenticationFreshKeyAuthSid = 118, +}} +pub const SYSTEM_LUID: LUID = LUID { LowPart: 0x3e7, HighPart: 0x0 }; +pub const ANONYMOUS_LOGON_LUID: LUID = LUID { LowPart: 0x3e6, HighPart: 0x0 }; +pub const LOCALSERVICE_LUID: LUID = LUID { LowPart: 0x3e5, HighPart: 0x0 }; +pub const NETWORKSERVICE_LUID: LUID = LUID { LowPart: 0x3e4, HighPart: 0x0 }; +pub const IUSER_LUID: LUID = LUID { LowPart: 0x3e3, HighPart: 0x0 }; +pub const SE_GROUP_MANDATORY: DWORD = 0x00000001; +pub const SE_GROUP_ENABLED_BY_DEFAULT: DWORD = 0x00000002; +pub const SE_GROUP_ENABLED: DWORD = 0x00000004; +pub const SE_GROUP_OWNER: DWORD = 0x00000008; +pub const SE_GROUP_USE_FOR_DENY_ONLY: DWORD = 0x00000010; +pub const SE_GROUP_INTEGRITY: DWORD = 0x00000020; +pub const SE_GROUP_INTEGRITY_ENABLED: DWORD = 0x00000040; +pub const SE_GROUP_LOGON_ID: DWORD = 0xC0000000; +pub const SE_GROUP_RESOURCE: DWORD = 0x20000000; +pub const SE_GROUP_VALID_ATTRIBUTES: DWORD = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT + | SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_USE_FOR_DENY_ONLY | SE_GROUP_LOGON_ID + | SE_GROUP_RESOURCE | SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED; +pub const ACL_REVISION: BYTE = 2; +pub const ACL_REVISION_DS: BYTE = 4; +pub const ACL_REVISION1: BYTE = 1; +pub const MIN_ACL_REVISION: BYTE = ACL_REVISION2; +pub const ACL_REVISION2: BYTE = 2; +pub const ACL_REVISION3: BYTE = 3; +pub const ACL_REVISION4: BYTE = 4; +pub const MAX_ACL_REVISION: BYTE = ACL_REVISION4; +STRUCT!{struct ACL { + AclRevision: BYTE, + Sbz1: BYTE, + AclSize: WORD, + AceCount: WORD, + Sbz2: WORD, +}} +pub type PACL = *mut ACL; +STRUCT!{struct ACE_HEADER { + AceType: BYTE, + AceFlags: BYTE, + AceSize: WORD, +}} +pub type PACE_HEADER = *mut ACE_HEADER; +pub const ACCESS_MIN_MS_ACE_TYPE: BYTE = 0x0; +pub const ACCESS_ALLOWED_ACE_TYPE: BYTE = 0x0; +pub const ACCESS_DENIED_ACE_TYPE: BYTE = 0x1; +pub const SYSTEM_AUDIT_ACE_TYPE: BYTE = 0x2; +pub const SYSTEM_ALARM_ACE_TYPE: BYTE = 0x3; +pub const ACCESS_MAX_MS_V2_ACE_TYPE: BYTE = 0x3; +pub const ACCESS_ALLOWED_COMPOUND_ACE_TYPE: BYTE = 0x4; +pub const ACCESS_MAX_MS_V3_ACE_TYPE: BYTE = 0x4; +pub const ACCESS_MIN_MS_OBJECT_ACE_TYPE: BYTE = 0x5; +pub const ACCESS_ALLOWED_OBJECT_ACE_TYPE: BYTE = 0x5; +pub const ACCESS_DENIED_OBJECT_ACE_TYPE: BYTE = 0x6; +pub const SYSTEM_AUDIT_OBJECT_ACE_TYPE: BYTE = 0x7; +pub const SYSTEM_ALARM_OBJECT_ACE_TYPE: BYTE = 0x8; +pub const ACCESS_MAX_MS_OBJECT_ACE_TYPE: BYTE = 0x8; +pub const ACCESS_MAX_MS_V4_ACE_TYPE: BYTE = 0x8; +pub const ACCESS_MAX_MS_ACE_TYPE: BYTE = 0x8; +pub const ACCESS_ALLOWED_CALLBACK_ACE_TYPE: BYTE = 0x9; +pub const ACCESS_DENIED_CALLBACK_ACE_TYPE: BYTE = 0xA; +pub const ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: BYTE = 0xB; +pub const ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE: BYTE = 0xC; +pub const SYSTEM_AUDIT_CALLBACK_ACE_TYPE: BYTE = 0xD; +pub const SYSTEM_ALARM_CALLBACK_ACE_TYPE: BYTE = 0xE; +pub const SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE: BYTE = 0xF; +pub const SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE: BYTE = 0x10; +pub const SYSTEM_MANDATORY_LABEL_ACE_TYPE: BYTE = 0x11; +pub const SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE: BYTE = 0x12; +pub const SYSTEM_SCOPED_POLICY_ID_ACE_TYPE: BYTE = 0x13; +pub const SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE: BYTE = 0x14; +pub const SYSTEM_ACCESS_FILTER_ACE_TYPE: BYTE = 0x15; +pub const ACCESS_MAX_MS_V5_ACE_TYPE: BYTE = 0x15; +pub const OBJECT_INHERIT_ACE: BYTE = 0x1; +pub const CONTAINER_INHERIT_ACE: BYTE = 0x2; +pub const NO_PROPAGATE_INHERIT_ACE: BYTE = 0x4; +pub const INHERIT_ONLY_ACE: BYTE = 0x8; +pub const INHERITED_ACE: BYTE = 0x10; +pub const VALID_INHERIT_FLAGS: BYTE = 0x1F; +pub const SUCCESSFUL_ACCESS_ACE_FLAG: BYTE = 0x40; +pub const FAILED_ACCESS_ACE_FLAG: BYTE = 0x80; +pub const TRUST_PROTECTED_FILTER_ACE_FLAG: BYTE = 0x40; +STRUCT!{struct ACCESS_ALLOWED_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PACCESS_ALLOWED_ACE = *mut ACCESS_ALLOWED_ACE; +STRUCT!{struct ACCESS_DENIED_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PACCESS_DENIED_ACE = *mut ACCESS_DENIED_ACE; +STRUCT!{struct SYSTEM_AUDIT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_AUDIT_ACE = *mut SYSTEM_AUDIT_ACE; +STRUCT!{struct SYSTEM_ALARM_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_ALARM_ACE = *mut SYSTEM_ALARM_ACE; +STRUCT!{struct SYSTEM_RESOURCE_ATTRIBUTE_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_RESOURCE_ATTRIBUTE_ACE = *mut SYSTEM_RESOURCE_ATTRIBUTE_ACE; +STRUCT!{struct SYSTEM_SCOPED_POLICY_ID_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_SCOPED_POLICY_ID_ACE = *mut SYSTEM_SCOPED_POLICY_ID_ACE; +STRUCT!{struct SYSTEM_MANDATORY_LABEL_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_MANDATORY_LABEL_ACE = *mut SYSTEM_MANDATORY_LABEL_ACE; +STRUCT!{struct SYSTEM_PROCESS_TRUST_LABEL_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_PROCESS_TRUST_LABEL_ACE = *mut SYSTEM_PROCESS_TRUST_LABEL_ACE; +STRUCT!{struct SYSTEM_ACCESS_FILTER_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_ACCESS_FILTER_ACE = *mut SYSTEM_ACCESS_FILTER_ACE; +pub const SYSTEM_MANDATORY_LABEL_NO_WRITE_UP: ACCESS_MASK = 0x1; +pub const SYSTEM_MANDATORY_LABEL_NO_READ_UP: ACCESS_MASK = 0x2; +pub const SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP: ACCESS_MASK = 0x4; +pub const SYSTEM_MANDATORY_LABEL_VALID_MASK: ACCESS_MASK = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP + | SYSTEM_MANDATORY_LABEL_NO_READ_UP | SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP; +pub const SYSTEM_PROCESS_TRUST_LABEL_VALID_MASK: ACCESS_MASK = 0x00ffffff; +pub const SYSTEM_PROCESS_TRUST_NOCONSTRAINT_MASK: ACCESS_MASK = 0xffffffff; +pub const SYSTEM_ACCESS_FILTER_VALID_MASK: ACCESS_MASK = 0x00ffffff; +pub const SYSTEM_ACCESS_FILTER_NOCONSTRAINT_MASK: ACCESS_MASK = 0xffffffff; +STRUCT!{struct ACCESS_ALLOWED_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PACCESS_ALLOWED_OBJECT_ACE = *mut ACCESS_ALLOWED_OBJECT_ACE; +STRUCT!{struct ACCESS_DENIED_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PACCESS_DENIED_OBJECT_ACE = *mut ACCESS_DENIED_OBJECT_ACE; +STRUCT!{struct SYSTEM_AUDIT_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PSYSTEM_AUDIT_OBJECT_ACE = *mut SYSTEM_AUDIT_OBJECT_ACE; +STRUCT!{struct SYSTEM_ALARM_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PSYSTEM_ALARM_OBJECT_ACE = *mut SYSTEM_ALARM_OBJECT_ACE; +STRUCT!{struct ACCESS_ALLOWED_CALLBACK_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PACCESS_ALLOWED_CALLBACK_ACE = *mut ACCESS_ALLOWED_CALLBACK_ACE; +STRUCT!{struct ACCESS_DENIED_CALLBACK_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PACCESS_DENIED_CALLBACK_ACE = *mut ACCESS_DENIED_CALLBACK_ACE; +STRUCT!{struct SYSTEM_AUDIT_CALLBACK_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_AUDIT_CALLBACK_ACE = *mut SYSTEM_AUDIT_CALLBACK_ACE; +STRUCT!{struct SYSTEM_ALARM_CALLBACK_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + SidStart: DWORD, +}} +pub type PSYSTEM_ALARM_CALLBACK_ACE = *mut SYSTEM_ALARM_CALLBACK_ACE; +STRUCT!{struct ACCESS_ALLOWED_CALLBACK_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PACCESS_ALLOWED_CALLBACK_OBJECT_ACE = *mut ACCESS_ALLOWED_CALLBACK_OBJECT_ACE; +STRUCT!{struct ACCESS_DENIED_CALLBACK_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PACCESS_DENIED_CALLBACK_OBJECT_ACE = *mut ACCESS_DENIED_CALLBACK_OBJECT_ACE; +STRUCT!{struct SYSTEM_AUDIT_CALLBACK_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PSYSTEM_AUDIT_CALLBACK_OBJECT_ACE = *mut SYSTEM_AUDIT_CALLBACK_OBJECT_ACE; +STRUCT!{struct SYSTEM_ALARM_CALLBACK_OBJECT_ACE { + Header: ACE_HEADER, + Mask: ACCESS_MASK, + Flags: DWORD, + ObjectType: GUID, + InheritedObjectType: GUID, + SidStart: DWORD, +}} +pub type PSYSTEM_ALARM_CALLBACK_OBJECT_ACE = *mut SYSTEM_ALARM_CALLBACK_OBJECT_ACE; +pub const ACE_OBJECT_TYPE_PRESENT: DWORD = 0x1; +pub const ACE_INHERITED_OBJECT_TYPE_PRESENT: DWORD = 0x2; +ENUM!{enum ACL_INFORMATION_CLASS { + AclRevisionInformation = 1, + AclSizeInformation, +}} +STRUCT!{struct ACL_REVISION_INFORMATION { + AclRevision: DWORD, +}} +pub type PACL_REVISION_INFORMATION = *mut ACL_REVISION_INFORMATION; +STRUCT!{struct ACL_SIZE_INFORMATION { + AceCount: DWORD, + AclBytesInUse: DWORD, + AclBytesFree: DWORD, +}} +pub type PACL_SIZE_INFORMATION = *mut ACL_SIZE_INFORMATION; +pub const SECURITY_DESCRIPTOR_REVISION: DWORD = 1; +pub const SECURITY_DESCRIPTOR_REVISION1: DWORD = 1; +#[cfg(target_pointer_width = "64")] +pub const SECURITY_DESCRIPTOR_MIN_LENGTH: usize = 40; +#[cfg(target_arch = "x86")] +pub const SECURITY_DESCRIPTOR_MIN_LENGTH: usize = 20; +pub type SECURITY_DESCRIPTOR_CONTROL = WORD; +pub type PSECURITY_DESCRIPTOR_CONTROL = *mut WORD; +pub const SE_OWNER_DEFAULTED: SECURITY_DESCRIPTOR_CONTROL = 0x0001; +pub const SE_GROUP_DEFAULTED: SECURITY_DESCRIPTOR_CONTROL = 0x0002; +pub const SE_DACL_PRESENT: SECURITY_DESCRIPTOR_CONTROL = 0x0004; +pub const SE_DACL_DEFAULTED: SECURITY_DESCRIPTOR_CONTROL = 0x0008; +pub const SE_SACL_PRESENT: SECURITY_DESCRIPTOR_CONTROL = 0x0010; +pub const SE_SACL_DEFAULTED: SECURITY_DESCRIPTOR_CONTROL = 0x0020; +pub const SE_DACL_AUTO_INHERIT_REQ: SECURITY_DESCRIPTOR_CONTROL = 0x0100; +pub const SE_SACL_AUTO_INHERIT_REQ: SECURITY_DESCRIPTOR_CONTROL = 0x0200; +pub const SE_DACL_AUTO_INHERITED: SECURITY_DESCRIPTOR_CONTROL = 0x0400; +pub const SE_SACL_AUTO_INHERITED: SECURITY_DESCRIPTOR_CONTROL = 0x0800; +pub const SE_DACL_PROTECTED: SECURITY_DESCRIPTOR_CONTROL = 0x1000; +pub const SE_SACL_PROTECTED: SECURITY_DESCRIPTOR_CONTROL = 0x2000; +pub const SE_RM_CONTROL_VALID: SECURITY_DESCRIPTOR_CONTROL = 0x4000; +pub const SE_SELF_RELATIVE: SECURITY_DESCRIPTOR_CONTROL = 0x8000; +STRUCT!{struct SECURITY_DESCRIPTOR_RELATIVE { + Revision: BYTE, + Sbz1: BYTE, + Control: SECURITY_DESCRIPTOR_CONTROL, + Owner: DWORD, + Group: DWORD, + Sacl: DWORD, + Dacl: DWORD, +}} +pub type PISECURITY_DESCRIPTOR_RELATIVE = *mut SECURITY_DESCRIPTOR_RELATIVE; +STRUCT!{struct SECURITY_DESCRIPTOR { + Revision: BYTE, + Sbz1: BYTE, + Control: SECURITY_DESCRIPTOR_CONTROL, + Owner: PSID, + Group: PSID, + Sacl: PACL, + Dacl: PACL, +}} +pub type PISECURITY_DESCRIPTOR = *mut SECURITY_DESCRIPTOR; +STRUCT!{struct SECURITY_OBJECT_AI_PARAMS { + Size: DWORD, + ConstraintMask: DWORD, +}} +pub type PSECURITY_OBJECT_AI_PARAMS = *mut SECURITY_OBJECT_AI_PARAMS; +STRUCT!{struct OBJECT_TYPE_LIST { + Level: WORD, + Sbz: WORD, + ObjectType: *mut GUID, +}} +pub type POBJECT_TYPE_LIST = *mut OBJECT_TYPE_LIST; +pub const ACCESS_OBJECT_GUID: WORD = 0; +pub const ACCESS_PROPERTY_SET_GUID: WORD = 1; +pub const ACCESS_PROPERTY_GUID: WORD = 2; +pub const ACCESS_MAX_LEVEL: WORD = 4; +ENUM!{enum AUDIT_EVENT_TYPE { + AuditEventObjectAccess, + AuditEventDirectoryServiceAccess, +}} +pub const AUDIT_ALLOW_NO_PRIVILEGE: DWORD = 0x1; +pub const ACCESS_DS_SOURCE: &'static str = "DS"; +pub const ACCESS_DS_OBJECT_TYPE_NAME: &'static str = "Directory Service Object"; +pub const SE_PRIVILEGE_ENABLED_BY_DEFAULT: DWORD = 0x00000001; +pub const SE_PRIVILEGE_ENABLED: DWORD = 0x00000002; +pub const SE_PRIVILEGE_REMOVED: DWORD = 0x00000004; +pub const SE_PRIVILEGE_USED_FOR_ACCESS: DWORD = 0x80000000; +pub const SE_PRIVILEGE_VALID_ATTRIBUTES: DWORD = SE_PRIVILEGE_ENABLED_BY_DEFAULT + | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS; +pub const PRIVILEGE_SET_ALL_NECESSARY: DWORD = 1; +STRUCT!{struct PRIVILEGE_SET { + PrivilegeCount: DWORD, + Control: DWORD, + Privilege: [LUID_AND_ATTRIBUTES; ANYSIZE_ARRAY], +}} +pub type PPRIVILEGE_SET = *mut PRIVILEGE_SET; +pub const ACCESS_REASON_TYPE_MASK: ACCESS_REASON = 0x00ff0000; +pub const ACCESS_REASON_DATA_MASK: ACCESS_REASON = 0x0000ffff; +pub const ACCESS_REASON_STAGING_MASK: ACCESS_REASON = 0x80000000; +pub const ACCESS_REASON_EXDATA_MASK: ACCESS_REASON = 0x7f000000; +ENUM!{enum ACCESS_REASON_TYPE { + AccessReasonNone = 0x00000000, + AccessReasonAllowedAce = 0x00010000, + AccessReasonDeniedAce = 0x00020000, + AccessReasonAllowedParentAce = 0x00030000, + AccessReasonDeniedParentAce = 0x00040000, + AccessReasonNotGrantedByCape = 0x00050000, + AccessReasonNotGrantedByParentCape = 0x00060000, + AccessReasonNotGrantedToAppContainer = 0x00070000, + AccessReasonMissingPrivilege = 0x00100000, + AccessReasonFromPrivilege = 0x00200000, + AccessReasonIntegrityLevel = 0x00300000, + AccessReasonOwnership = 0x00400000, + AccessReasonNullDacl = 0x00500000, + AccessReasonEmptyDacl = 0x00600000, + AccessReasonNoSD = 0x00700000, + AccessReasonNoGrant = 0x00800000, + AccessReasonTrustLabel = 0x00900000, + AccessReasonFilterAce = 0x00a00000, +}} +pub type ACCESS_REASON = DWORD; +STRUCT!{struct ACCESS_REASONS { + Data: [ACCESS_REASON; 32], +}} +pub type PACCESS_REASONS = *mut ACCESS_REASONS; +pub const SE_SECURITY_DESCRIPTOR_FLAG_NO_OWNER_ACE: DWORD = 0x00000001; +pub const SE_SECURITY_DESCRIPTOR_FLAG_NO_LABEL_ACE: DWORD = 0x00000002; +pub const SE_SECURITY_DESCRIPTOR_FLAG_NO_ACCESS_FILTER_ACE: DWORD = 0x00000004; +pub const SE_SECURITY_DESCRIPTOR_VALID_FLAGS: DWORD = 0x00000007; +STRUCT!{struct SE_SECURITY_DESCRIPTOR { + Size: DWORD, + Flags: DWORD, + SecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PSE_SECURITY_DESCRIPTOR = *mut SE_SECURITY_DESCRIPTOR; +STRUCT!{struct SE_ACCESS_REQUEST { + Size: DWORD, + SeSecurityDescriptor: PSE_SECURITY_DESCRIPTOR, + DesiredAccess: ACCESS_MASK, + PreviouslyGrantedAccess: ACCESS_MASK, + PrincipalSelfSid: PSID, + GenericMapping: PGENERIC_MAPPING, + ObjectTypeListCount: DWORD, + ObjectTypeList: POBJECT_TYPE_LIST, +}} +pub type PSE_ACCESS_REQUEST = *mut SE_ACCESS_REQUEST; +STRUCT!{struct SE_ACCESS_REPLY { + Size: DWORD, + ResultListCount: DWORD, + GrantedAccess: PACCESS_MASK, + AccessStatus: PDWORD, + AccessReason: PACCESS_REASONS, + Privileges: *mut PPRIVILEGE_SET, +}} +pub type PSE_ACCESS_REPLY = *mut SE_ACCESS_REPLY; +pub const SE_CREATE_TOKEN_NAME: &'static str = "SeCreateTokenPrivilege"; +pub const SE_ASSIGNPRIMARYTOKEN_NAME: &'static str = "SeAssignPrimaryTokenPrivilege"; +pub const SE_LOCK_MEMORY_NAME: &'static str = "SeLockMemoryPrivilege"; +pub const SE_INCREASE_QUOTA_NAME: &'static str = "SeIncreaseQuotaPrivilege"; +pub const SE_UNSOLICITED_INPUT_NAME: &'static str = "SeUnsolicitedInputPrivilege"; +pub const SE_MACHINE_ACCOUNT_NAME: &'static str = "SeMachineAccountPrivilege"; +pub const SE_TCB_NAME: &'static str = "SeTcbPrivilege"; +pub const SE_SECURITY_NAME: &'static str = "SeSecurityPrivilege"; +pub const SE_TAKE_OWNERSHIP_NAME: &'static str = "SeTakeOwnershipPrivilege"; +pub const SE_LOAD_DRIVER_NAME: &'static str = "SeLoadDriverPrivilege"; +pub const SE_SYSTEM_PROFILE_NAME: &'static str = "SeSystemProfilePrivilege"; +pub const SE_SYSTEMTIME_NAME: &'static str = "SeSystemtimePrivilege"; +pub const SE_PROF_SINGLE_PROCESS_NAME: &'static str = "SeProfileSingleProcessPrivilege"; +pub const SE_INC_BASE_PRIORITY_NAME: &'static str = "SeIncreaseBasePriorityPrivilege"; +pub const SE_CREATE_PAGEFILE_NAME: &'static str = "SeCreatePagefilePrivilege"; +pub const SE_CREATE_PERMANENT_NAME: &'static str = "SeCreatePermanentPrivilege"; +pub const SE_BACKUP_NAME: &'static str = "SeBackupPrivilege"; +pub const SE_RESTORE_NAME: &'static str = "SeRestorePrivilege"; +pub const SE_SHUTDOWN_NAME: &'static str = "SeShutdownPrivilege"; +pub const SE_DEBUG_NAME: &'static str = "SeDebugPrivilege"; +pub const SE_AUDIT_NAME: &'static str = "SeAuditPrivilege"; +pub const SE_SYSTEM_ENVIRONMENT_NAME: &'static str = "SeSystemEnvironmentPrivilege"; +pub const SE_CHANGE_NOTIFY_NAME: &'static str = "SeChangeNotifyPrivilege"; +pub const SE_REMOTE_SHUTDOWN_NAME: &'static str = "SeRemoteShutdownPrivilege"; +pub const SE_UNDOCK_NAME: &'static str = "SeUndockPrivilege"; +pub const SE_SYNC_AGENT_NAME: &'static str = "SeSyncAgentPrivilege"; +pub const SE_ENABLE_DELEGATION_NAME: &'static str = "SeEnableDelegationPrivilege"; +pub const SE_MANAGE_VOLUME_NAME: &'static str = "SeManageVolumePrivilege"; +pub const SE_IMPERSONATE_NAME: &'static str = "SeImpersonatePrivilege"; +pub const SE_CREATE_GLOBAL_NAME: &'static str = "SeCreateGlobalPrivilege"; +pub const SE_TRUSTED_CREDMAN_ACCESS_NAME: &'static str = "SeTrustedCredManAccessPrivilege"; +pub const SE_RELABEL_NAME: &'static str = "SeRelabelPrivilege"; +pub const SE_INC_WORKING_SET_NAME: &'static str = "SeIncreaseWorkingSetPrivilege"; +pub const SE_TIME_ZONE_NAME: &'static str = "SeTimeZonePrivilege"; +pub const SE_CREATE_SYMBOLIC_LINK_NAME: &'static str = "SeCreateSymbolicLinkPrivilege"; +pub const SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME: &'static str + = "SeDelegateSessionUserImpersonatePrivilege"; +pub const SE_ACTIVATE_AS_USER_CAPABILITY: &'static str = "activateAsUser"; +pub const SE_CONSTRAINED_IMPERSONATION_CAPABILITY: &'static str = "constrainedImpersonation"; +pub const SE_SESSION_IMPERSONATION_CAPABILITY: &'static str = "sessionImpersonation"; +pub const SE_MUMA_CAPABILITY: &'static str = "muma"; +pub const SE_DEVELOPMENT_MODE_NETWORK_CAPABILITY: &'static str = "developmentModeNetwork"; +ENUM!{enum SECURITY_IMPERSONATION_LEVEL { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation, +}} +pub type PSECURITY_IMPERSONATION_LEVEL = *mut SECURITY_IMPERSONATION_LEVEL; +pub const SECURITY_MAX_IMPERSONATION_LEVEL: SECURITY_IMPERSONATION_LEVEL = SecurityDelegation; +pub const SECURITY_MIN_IMPERSONATION_LEVEL: SECURITY_IMPERSONATION_LEVEL = SecurityAnonymous; +pub const DEFAULT_IMPERSONATION_LEVEL: SECURITY_IMPERSONATION_LEVEL = SecurityImpersonation; +#[inline] +pub fn VALID_IMPERSONATION_LEVEL(L: SECURITY_IMPERSONATION_LEVEL) -> bool { + (L >= SECURITY_MIN_IMPERSONATION_LEVEL) && (L <= SECURITY_MAX_IMPERSONATION_LEVEL) +} +pub const TOKEN_ASSIGN_PRIMARY: DWORD = 0x0001; +pub const TOKEN_DUPLICATE: DWORD = 0x0002; +pub const TOKEN_IMPERSONATE: DWORD = 0x0004; +pub const TOKEN_QUERY: DWORD = 0x0008; +pub const TOKEN_QUERY_SOURCE: DWORD = 0x0010; +pub const TOKEN_ADJUST_PRIVILEGES: DWORD = 0x0020; +pub const TOKEN_ADJUST_GROUPS: DWORD = 0x0040; +pub const TOKEN_ADJUST_DEFAULT: DWORD = 0x0080; +pub const TOKEN_ADJUST_SESSIONID: DWORD = 0x0100; +pub const TOKEN_ALL_ACCESS_P: DWORD = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY + | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE + | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT; +pub const TOKEN_ALL_ACCESS: DWORD = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID; +pub const TOKEN_READ: DWORD = STANDARD_RIGHTS_READ | TOKEN_QUERY; +pub const TOKEN_WRITE: DWORD = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES + | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT; +pub const TOKEN_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE; +pub const TOKEN_TRUST_CONSTRAINT_MASK: DWORD = STANDARD_RIGHTS_READ | TOKEN_QUERY + | TOKEN_QUERY_SOURCE; +pub const TOKEN_ACCESS_PSEUDO_HANDLE_WIN8: DWORD = TOKEN_QUERY | TOKEN_QUERY_SOURCE; +pub const TOKEN_ACCESS_PSEUDO_HANDLE: DWORD = TOKEN_ACCESS_PSEUDO_HANDLE_WIN8; +ENUM!{enum TOKEN_TYPE { + TokenPrimary = 1, + TokenImpersonation, +}} +pub type PTOKEN_TYPE = *mut TOKEN_TYPE; +ENUM!{enum TOKEN_ELEVATION_TYPE { + TokenElevationTypeDefault = 1, + TokenElevationTypeFull, + TokenElevationTypeLimited, +}} +pub type PTOKEN_ELEVATION_TYPE = *mut TOKEN_ELEVATION_TYPE; +ENUM!{enum TOKEN_INFORMATION_CLASS { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + TokenIsAppContainer, + TokenCapabilities, + TokenAppContainerSid, + TokenAppContainerNumber, + TokenUserClaimAttributes, + TokenDeviceClaimAttributes, + TokenRestrictedUserClaimAttributes, + TokenRestrictedDeviceClaimAttributes, + TokenDeviceGroups, + TokenRestrictedDeviceGroups, + TokenSecurityAttributes, + TokenIsRestricted, + TokenProcessTrustLevel, + TokenPrivateNameSpace, + TokenSingletonAttributes, + TokenBnoIsolation, + MaxTokenInfoClass, +}} +pub type PTOKEN_INFORMATION_CLASS = *mut TOKEN_INFORMATION_CLASS; +STRUCT!{struct TOKEN_USER { + User: SID_AND_ATTRIBUTES, +}} +pub type PTOKEN_USER = *mut TOKEN_USER; +UNION!{union SE_TOKEN_USER_u1 { + [usize; 2], + TokenUser TokenUser_mut: TOKEN_USER, + User User_mut: SID_AND_ATTRIBUTES, +}} +UNION!{union SE_TOKEN_USER_u2 { + [u32; 17], + Sid Sid_mut: SID, + Buffer Buffer_mut: [BYTE; SECURITY_MAX_SID_SIZE], +}} +STRUCT!{struct SE_TOKEN_USER { + u1: SE_TOKEN_USER_u1, + u2: SE_TOKEN_USER_u2, +}} +pub type PSE_TOKEN_USER = *mut SE_TOKEN_USER; +STRUCT!{struct TOKEN_GROUPS { + GroupCount: DWORD, + Groups: [SID_AND_ATTRIBUTES; ANYSIZE_ARRAY], +}} +pub type PTOKEN_GROUPS = *mut TOKEN_GROUPS; +STRUCT!{struct TOKEN_PRIVILEGES { + PrivilegeCount: DWORD, + Privileges: [LUID_AND_ATTRIBUTES; ANYSIZE_ARRAY], +}} +pub type PTOKEN_PRIVILEGES = *mut TOKEN_PRIVILEGES; +STRUCT!{struct TOKEN_OWNER { + Owner: PSID, +}} +pub type PTOKEN_OWNER = *mut TOKEN_OWNER; +STRUCT!{struct TOKEN_PRIMARY_GROUP { + PrimaryGroup: PSID, +}} +pub type PTOKEN_PRIMARY_GROUP = *mut TOKEN_PRIMARY_GROUP; +STRUCT!{struct TOKEN_DEFAULT_DACL { + DefaultDacl: PACL, +}} +pub type PTOKEN_DEFAULT_DACL = *mut TOKEN_DEFAULT_DACL; +STRUCT!{struct TOKEN_USER_CLAIMS { + UserClaims: PCLAIMS_BLOB, +}} +pub type PTOKEN_USER_CLAIMS = *mut TOKEN_USER_CLAIMS; +STRUCT!{struct TOKEN_DEVICE_CLAIMS { + DeviceClaims: PCLAIMS_BLOB, +}} +pub type PTOKEN_DEVICE_CLAIMS = *mut TOKEN_DEVICE_CLAIMS; +STRUCT!{struct TOKEN_GROUPS_AND_PRIVILEGES { + SidCount: DWORD, + SidLength: DWORD, + Sids: PSID_AND_ATTRIBUTES, + RestrictedSidCount: DWORD, + RestrictedSidLength: DWORD, + RestrictedSids: PSID_AND_ATTRIBUTES, + PrivilegeCount: DWORD, + PrivilegeLength: DWORD, + Privileges: PLUID_AND_ATTRIBUTES, + AuthenticationId: LUID, +}} +pub type PTOKEN_GROUPS_AND_PRIVILEGES = *mut TOKEN_GROUPS_AND_PRIVILEGES; +STRUCT!{struct TOKEN_LINKED_TOKEN { + LinkedToken: HANDLE, +}} +pub type PTOKEN_LINKED_TOKEN = *mut TOKEN_LINKED_TOKEN; +STRUCT!{struct TOKEN_ELEVATION { + TokenIsElevated: DWORD, +}} +pub type PTOKEN_ELEVATION = *mut TOKEN_ELEVATION; +STRUCT!{struct TOKEN_MANDATORY_LABEL { + Label: SID_AND_ATTRIBUTES, +}} +pub type PTOKEN_MANDATORY_LABEL = *mut TOKEN_MANDATORY_LABEL; +pub const TOKEN_MANDATORY_POLICY_OFF: DWORD = 0x0; +pub const TOKEN_MANDATORY_POLICY_NO_WRITE_UP: DWORD = 0x1; +pub const TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN: DWORD = 0x2; +pub const TOKEN_MANDATORY_POLICY_VALID_MASK: DWORD = TOKEN_MANDATORY_POLICY_NO_WRITE_UP + | TOKEN_MANDATORY_POLICY_NEW_PROCESS_MIN; +STRUCT!{struct TOKEN_MANDATORY_POLICY { + Policy: DWORD, +}} +pub type PTOKEN_MANDATORY_POLICY = *mut TOKEN_MANDATORY_POLICY; +pub type PSECURITY_ATTRIBUTES_OPAQUE = PVOID; +STRUCT!{struct TOKEN_ACCESS_INFORMATION { + SidHash: PSID_AND_ATTRIBUTES_HASH, + RestrictedSidHash: PSID_AND_ATTRIBUTES_HASH, + Privileges: PTOKEN_PRIVILEGES, + AuthenticationId: LUID, + TokenType: TOKEN_TYPE, + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + MandatoryPolicy: TOKEN_MANDATORY_POLICY, + Flags: DWORD, + AppContainerNumber: DWORD, + PackageSid: PSID, + CapabilitiesHash: PSID_AND_ATTRIBUTES_HASH, + TrustLevelSid: PSID, + SecurityAttributes: PSECURITY_ATTRIBUTES_OPAQUE, +}} +pub type PTOKEN_ACCESS_INFORMATION = *mut TOKEN_ACCESS_INFORMATION; +pub const POLICY_AUDIT_SUBCATEGORY_COUNT: usize = 59; +STRUCT!{struct TOKEN_AUDIT_POLICY { + PerUserPolicy: [BYTE; (POLICY_AUDIT_SUBCATEGORY_COUNT >> 1) + 1], +}} +pub type PTOKEN_AUDIT_POLICY = *mut TOKEN_AUDIT_POLICY; +pub const TOKEN_SOURCE_LENGTH: usize = 8; +STRUCT!{struct TOKEN_SOURCE { + SourceName: [CHAR; TOKEN_SOURCE_LENGTH], + SourceIdentifier: LUID, +}} +pub type PTOKEN_SOURCE = *mut TOKEN_SOURCE; +STRUCT!{struct TOKEN_STATISTICS { + TokenId: LUID, + AuthenticationId: LUID, + ExpirationTime: LARGE_INTEGER, + TokenType: TOKEN_TYPE, + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + DynamicCharged: DWORD, + DynamicAvailable: DWORD, + GroupCount: DWORD, + PrivilegeCount: DWORD, + ModifiedId: LUID, +}} +pub type PTOKEN_STATISTICS = *mut TOKEN_STATISTICS; +STRUCT!{struct TOKEN_CONTROL { + TokenId: LUID, + AuthenticationId: LUID, + ModifiedId: LUID, + TokenSource: TOKEN_SOURCE, +}} +pub type PTOKEN_CONTROL = *mut TOKEN_CONTROL; +STRUCT!{struct TOKEN_ORIGIN { + OriginatingLogonSession: LUID, +}} +pub type PTOKEN_ORIGIN = *mut TOKEN_ORIGIN; +ENUM!{enum MANDATORY_LEVEL { + MandatoryLevelUntrusted = 0, + MandatoryLevelLow, + MandatoryLevelMedium, + MandatoryLevelHigh, + MandatoryLevelSystem, + MandatoryLevelSecureProcess, + MandatoryLevelCount, +}} +pub type PMANDATORY_LEVEL = *mut MANDATORY_LEVEL; +STRUCT!{struct TOKEN_APPCONTAINER_INFORMATION { + TokenAppContainer: PSID, +}} +pub type PTOKEN_APPCONTAINER_INFORMATION = *mut TOKEN_APPCONTAINER_INFORMATION; +STRUCT!{struct TOKEN_SID_INFORMATION { + Sid: PSID, +}} +pub type PTOKEN_SID_INFORMATION = *mut TOKEN_SID_INFORMATION; +STRUCT!{struct TOKEN_BNO_ISOLATION_INFORMATION { + IsolationPrefix: PWSTR, + IsolationEnabled: BOOLEAN, +}} +pub type PTOKEN_BNO_ISOLATION_INFORMATION = *mut TOKEN_BNO_ISOLATION_INFORMATION; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_INVALID: WORD = 0x00; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64: WORD = 0x01; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64: WORD = 0x02; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING: WORD = 0x03; +STRUCT!{struct CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE { + Version: DWORD64, + Name: PWSTR, +}} +pub type PCLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE = *mut CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN: WORD = 0x04; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_SID: WORD = 0x05; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN: WORD = 0x06; +STRUCT!{struct CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE { + pValue: PVOID, + ValueLength: DWORD, +}} +pub type PCLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE = + *mut CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE; +pub const CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING: WORD = 0x10; +pub const CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE: DWORD = 0x0001; +pub const CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE: DWORD = 0x0002; +pub const CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY: DWORD = 0x0004; +pub const CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT: DWORD = 0x0008; +pub const CLAIM_SECURITY_ATTRIBUTE_DISABLED: DWORD = 0x0010; +pub const CLAIM_SECURITY_ATTRIBUTE_MANDATORY: DWORD = 0x0020; +pub const CLAIM_SECURITY_ATTRIBUTE_VALID_FLAGS: DWORD = CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE + | CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE | CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY + | CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT | CLAIM_SECURITY_ATTRIBUTE_DISABLED + | CLAIM_SECURITY_ATTRIBUTE_MANDATORY; +pub const CLAIM_SECURITY_ATTRIBUTE_CUSTOM_FLAGS: DWORD = 0xFFFF0000; +UNION!{union CLAIM_SECURITY_ATTRIBUTE_V1_Values { + [usize; 1], + pInt64 pInt64_mut: PLONG64, + pUint64 pUint64_mut: PDWORD64, + ppString ppString_mut: PWSTR, + pFqbn pFqbn_mut: PCLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE, + pOctetString pOctetString_mut: PCLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, +}} +STRUCT!{struct CLAIM_SECURITY_ATTRIBUTE_V1 { + Name: PWSTR, + ValueType: WORD, + Reserved: WORD, + Flags: DWORD, + ValueCount: DWORD, + Values: CLAIM_SECURITY_ATTRIBUTE_V1_Values, +}} +pub type PCLAIM_SECURITY_ATTRIBUTE_V1 = *mut CLAIM_SECURITY_ATTRIBUTE_V1; +UNION!{union CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1_Values { + [u32; 1], + pInt64 pInt64_mut: [DWORD; ANYSIZE_ARRAY], + pUint64 pUint64_mut: [DWORD; ANYSIZE_ARRAY], + ppString ppString_mut: [DWORD; ANYSIZE_ARRAY], + pFqbn pFqbn_mut: [DWORD; ANYSIZE_ARRAY], + pOctetString pOctetString_mut: [DWORD; ANYSIZE_ARRAY], +}} +STRUCT!{struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 { + Name: DWORD, + ValueType: WORD, + Reserved: WORD, + Flags: DWORD, + ValueCount: DWORD, + Values: CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1_Values, +}} +pub type PCLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 = *mut CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1; +pub const CLAIM_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1: WORD = 1; +pub const CLAIM_SECURITY_ATTRIBUTES_INFORMATION_VERSION: WORD = + CLAIM_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1; +UNION!{union CLAIM_SECURITY_ATTRIBUTES_INFORMATION_Attribute { + [usize; 1], + pAttributeV1 pAttributeV1_mut: PCLAIM_SECURITY_ATTRIBUTE_V1, +}} +STRUCT!{struct CLAIM_SECURITY_ATTRIBUTES_INFORMATION { + Version: WORD, + Reserved: WORD, + AttributeCount: DWORD, + Attribute: CLAIM_SECURITY_ATTRIBUTES_INFORMATION_Attribute, +}} +pub type PCLAIM_SECURITY_ATTRIBUTES_INFORMATION = *mut CLAIM_SECURITY_ATTRIBUTES_INFORMATION; +pub const SECURITY_DYNAMIC_TRACKING: BOOLEAN = TRUE as u8; +pub const SECURITY_STATIC_TRACKING: BOOLEAN = FALSE as u8; +pub type SECURITY_CONTEXT_TRACKING_MODE = BOOLEAN; +pub type PSECURITY_CONTEXT_TRACKING_MODE = *mut BOOLEAN; +STRUCT!{struct SECURITY_QUALITY_OF_SERVICE { + Length: DWORD, + ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL, + ContextTrackingMode: SECURITY_CONTEXT_TRACKING_MODE, + EffectiveOnly: BOOLEAN, +}} +pub type PSECURITY_QUALITY_OF_SERVICE = *mut SECURITY_QUALITY_OF_SERVICE; +STRUCT!{struct SE_IMPERSONATION_STATE { + Token: PACCESS_TOKEN, + CopyOnOpen: BOOLEAN, + EffectiveOnly: BOOLEAN, + Level: SECURITY_IMPERSONATION_LEVEL, +}} +pub type PSE_IMPERSONATION_STATE = *mut SE_IMPERSONATION_STATE; +pub const DISABLE_MAX_PRIVILEGE: DWORD = 0x1; +pub const SANDBOX_INERT: DWORD = 0x2; +pub const LUA_TOKEN: DWORD = 0x4; +pub const WRITE_RESTRICTED: DWORD = 0x8; +pub type SECURITY_INFORMATION = DWORD; +pub type PSECURITY_INFORMATION = *mut DWORD; +pub const OWNER_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000001; +pub const GROUP_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000002; +pub const DACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000004; +pub const SACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000008; +pub const LABEL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000010; +pub const ATTRIBUTE_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000020; +pub const SCOPE_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000040; +pub const PROCESS_TRUST_LABEL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000080; +pub const ACCESS_FILTER_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00000100; +pub const BACKUP_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x00010000; +pub const PROTECTED_DACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x80000000; +pub const PROTECTED_SACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x40000000; +pub const UNPROTECTED_DACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x20000000; +pub const UNPROTECTED_SACL_SECURITY_INFORMATION: SECURITY_INFORMATION = 0x10000000; +pub type SE_SIGNING_LEVEL = BYTE; +pub type PSE_SIGNING_LEVEL = *mut BYTE; +pub const SE_SIGNING_LEVEL_UNCHECKED: BYTE = 0x00000000; +pub const SE_SIGNING_LEVEL_UNSIGNED: BYTE = 0x00000001; +pub const SE_SIGNING_LEVEL_ENTERPRISE: BYTE = 0x00000002; +pub const SE_SIGNING_LEVEL_CUSTOM_1: BYTE = 0x00000003; +pub const SE_SIGNING_LEVEL_AUTHENTICODE: BYTE = 0x00000004; +pub const SE_SIGNING_LEVEL_CUSTOM_2: BYTE = 0x00000005; +pub const SE_SIGNING_LEVEL_STORE: BYTE = 0x00000006; +pub const SE_SIGNING_LEVEL_CUSTOM_3: BYTE = 0x00000007; +pub const SE_SIGNING_LEVEL_ANTIMALWARE: BYTE = SE_SIGNING_LEVEL_CUSTOM_3; +pub const SE_SIGNING_LEVEL_MICROSOFT: BYTE = 0x00000008; +pub const SE_SIGNING_LEVEL_CUSTOM_4: BYTE = 0x00000009; +pub const SE_SIGNING_LEVEL_CUSTOM_5: BYTE = 0x0000000A; +pub const SE_SIGNING_LEVEL_DYNAMIC_CODEGEN: BYTE = 0x0000000B; +pub const SE_SIGNING_LEVEL_WINDOWS: BYTE = 0x0000000C; +pub const SE_SIGNING_LEVEL_CUSTOM_7: BYTE = 0x0000000D; +pub const SE_SIGNING_LEVEL_WINDOWS_TCB: BYTE = 0x0000000E; +pub const SE_SIGNING_LEVEL_CUSTOM_6: BYTE = 0x0000000F; +ENUM!{enum SE_IMAGE_SIGNATURE_TYPE { + SeImageSignatureNone = 0, + SeImageSignatureEmbedded, + SeImageSignatureCache, + SeImageSignatureCatalogCached, + SeImageSignatureCatalogNotCached, + SeImageSignatureCatalogHint, + SeImageSignaturePackageCatalog, +}} +pub type PSE_IMAGE_SIGNATURE_TYPE = *mut SE_IMAGE_SIGNATURE_TYPE; +ENUM!{enum SE_LEARNING_MODE_DATA_TYPE { + SeLearningModeInvalidType = 0, + SeLearningModeSettings, + SeLearningModeMax, +}} +STRUCT!{struct SECURITY_CAPABILITIES { + AppContainerSid: PSID, + Capabilities: PSID_AND_ATTRIBUTES, + CapabilityCount: DWORD, + Reserved: DWORD, +}} +pub type PSECURITY_CAPABILITIES = *mut SECURITY_CAPABILITIES; +pub type LPSECURITY_CAPABILITIES = *mut SECURITY_CAPABILITIES; +pub const PROCESS_TERMINATE: DWORD = 0x0001; +pub const PROCESS_CREATE_THREAD: DWORD = 0x0002; +pub const PROCESS_SET_SESSIONID: DWORD = 0x0004; +pub const PROCESS_VM_OPERATION: DWORD = 0x0008; +pub const PROCESS_VM_READ: DWORD = 0x0010; +pub const PROCESS_VM_WRITE: DWORD = 0x0020; +pub const PROCESS_DUP_HANDLE: DWORD = 0x0040; +pub const PROCESS_CREATE_PROCESS: DWORD = 0x0080; +pub const PROCESS_SET_QUOTA: DWORD = 0x0100; +pub const PROCESS_SET_INFORMATION: DWORD = 0x0200; +pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; +pub const PROCESS_SUSPEND_RESUME: DWORD = 0x0800; +pub const PROCESS_QUERY_LIMITED_INFORMATION: DWORD = 0x1000; +pub const PROCESS_SET_LIMITED_INFORMATION: DWORD = 0x2000; +pub const PROCESS_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF; +pub const THREAD_TERMINATE: DWORD = 0x0001; +pub const THREAD_SUSPEND_RESUME: DWORD = 0x0002; +pub const THREAD_GET_CONTEXT: DWORD = 0x0008; +pub const THREAD_SET_CONTEXT: DWORD = 0x0010; +pub const THREAD_QUERY_INFORMATION: DWORD = 0x0040; +pub const THREAD_SET_INFORMATION: DWORD = 0x0020; +pub const THREAD_SET_THREAD_TOKEN: DWORD = 0x0080; +pub const THREAD_IMPERSONATE: DWORD = 0x0100; +pub const THREAD_DIRECT_IMPERSONATION: DWORD = 0x0200; +pub const THREAD_SET_LIMITED_INFORMATION: DWORD = 0x0400; +pub const THREAD_QUERY_LIMITED_INFORMATION: DWORD = 0x0800; +pub const THREAD_RESUME: DWORD = 0x1000; +pub const THREAD_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF; +pub const JOB_OBJECT_ASSIGN_PROCESS: DWORD = 0x0001; +pub const JOB_OBJECT_SET_ATTRIBUTES: DWORD = 0x0002; +pub const JOB_OBJECT_QUERY: DWORD = 0x0004; +pub const JOB_OBJECT_TERMINATE: DWORD = 0x0008; +pub const JOB_OBJECT_SET_SECURITY_ATTRIBUTES: DWORD = 0x0010; +pub const JOB_OBJECT_IMPERSONATE: DWORD = 0x0020; +pub const JOB_OBJECT_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3F; +STRUCT!{struct JOB_SET_ARRAY { + JobHandle: HANDLE, + MemberLevel: DWORD, + Flags: DWORD, +}} +pub type PJOB_SET_ARRAY = *mut JOB_SET_ARRAY; +pub const FLS_MAXIMUM_AVAILABLE: DWORD = 128; +pub const TLS_MINIMUM_AVAILABLE: DWORD = 64; +STRUCT!{struct EXCEPTION_REGISTRATION_RECORD { + Next: *mut EXCEPTION_REGISTRATION_RECORD, + Handler: PEXCEPTION_ROUTINE, +}} +pub type PEXCEPTION_REGISTRATION_RECORD = *mut EXCEPTION_REGISTRATION_RECORD; +UNION!{union NT_TIB_u { + [usize; 1], + FiberData FiberData_mut: PVOID, + Version Version_mut: DWORD, +}} +STRUCT!{struct NT_TIB { + ExceptionList: *mut EXCEPTION_REGISTRATION_RECORD, + StackBase: PVOID, + StackLimit: PVOID, + SubSystemTib: PVOID, + u: NT_TIB_u, + ArbitraryUserPointer: PVOID, + _Self: *mut NT_TIB, +}} +pub type PNT_TIB = *mut NT_TIB; +UNION!{union NT_TIB32_u { + [u32; 1], + FiberData FiberData_mut: DWORD, + Version Version_mut: DWORD, +}} +STRUCT!{struct NT_TIB32 { + ExceptionList: DWORD, + StackBase: DWORD, + StackLimit: DWORD, + SubSystemTib: DWORD, + u: NT_TIB32_u, + ArbitraryUserPointer: DWORD, + Self_: DWORD, +}} +pub type PNT_TIB32 = *mut NT_TIB32; +UNION!{union NT_TIB64_u { + [u64; 1], + FiberData FiberData_mut: DWORD64, + Version Version_mut: DWORD, +}} +STRUCT!{struct NT_TIB64 { + ExceptionList: DWORD64, + StackBase: DWORD64, + StackLimit: DWORD64, + SubSystemTib: DWORD64, + u: NT_TIB64_u, + ArbitraryUserPointer: DWORD64, + _Self: DWORD64, +}} +pub type PNT_TIB64 = *mut NT_TIB64; +pub const THREAD_DYNAMIC_CODE_ALLOW: DWORD = 1; +pub const THREAD_BASE_PRIORITY_LOWRT: DWORD = 15; +pub const THREAD_BASE_PRIORITY_MAX: DWORD = 2; +pub const THREAD_BASE_PRIORITY_MIN: DWORD = -2i32 as u32; +pub const THREAD_BASE_PRIORITY_IDLE: DWORD = -15i32 as u32; +STRUCT!{struct UMS_CREATE_THREAD_ATTRIBUTES { + UmsVersion: DWORD, + UmsContext: PVOID, + UmsCompletionList: PVOID, +}} +pub type PUMS_CREATE_THREAD_ATTRIBUTES = *mut UMS_CREATE_THREAD_ATTRIBUTES; +STRUCT!{struct WOW64_ARCHITECTURE_INFORMATION { + BitFields: DWORD, +}} +pub type PWOW64_ARCHITECTURE_INFORMATION = *mut WOW64_ARCHITECTURE_INFORMATION; +BITFIELD!{WOW64_ARCHITECTURE_INFORMATION BitFields: DWORD [ + Machine set_Machine[0..16], + KernelMode set_KernelMode[16..17], + UserMode set_UserMode[17..18], + Native set_Native[18..19], + Process set_Process[19..20], + ReservedZero0 set_ReservedZero0[20..32], +]} +pub const MEMORY_PRIORITY_LOWEST: ULONG = 0; +pub const MEMORY_PRIORITY_VERY_LOW: ULONG = 1; +pub const MEMORY_PRIORITY_LOW: ULONG = 2; +pub const MEMORY_PRIORITY_MEDIUM: ULONG = 3; +pub const MEMORY_PRIORITY_BELOW_NORMAL: ULONG = 4; +pub const MEMORY_PRIORITY_NORMAL: ULONG = 5; +STRUCT!{struct QUOTA_LIMITS { + PagedPoolLimit: SIZE_T, + NonPagedPoolLimit: SIZE_T, + MinimumWorkingSetSize: SIZE_T, + MaximumWorkingSetSize: SIZE_T, + PagefileLimit: SIZE_T, + TimeLimit: LARGE_INTEGER, +}} +pub type PQUOTA_LIMITS = *mut QUOTA_LIMITS; +pub const QUOTA_LIMITS_HARDWS_MIN_ENABLE: DWORD = 0x00000001; +pub const QUOTA_LIMITS_HARDWS_MIN_DISABLE: DWORD = 0x00000002; +pub const QUOTA_LIMITS_HARDWS_MAX_ENABLE: DWORD = 0x00000004; +pub const QUOTA_LIMITS_HARDWS_MAX_DISABLE: DWORD = 0x00000008; +pub const QUOTA_LIMITS_USE_DEFAULT_LIMITS: DWORD = 0x00000010; +STRUCT!{struct RATE_QUOTA_LIMIT { + RateData: DWORD, +}} +BITFIELD!{RATE_QUOTA_LIMIT RateData: DWORD [ + RatePercent set_RatePercent[0..7], + Reserved0 set_Reserved0[7..32], +]} +pub type PRATE_QUOTA_LIMIT = *mut RATE_QUOTA_LIMIT; +STRUCT!{struct QUOTA_LIMITS_EX { + PagedPoolLimit: SIZE_T, + NonPagedPoolLimit: SIZE_T, + MinimumWorkingSetSize: SIZE_T, + MaximumWorkingSetSize: SIZE_T, + PagefileLimit: SIZE_T, + TimeLimit: LARGE_INTEGER, + WorkingSetLimit: SIZE_T, + Reserved2: SIZE_T, + Reserved3: SIZE_T, + Reserved4: SIZE_T, + Flags: DWORD, + CpuRateLimit: RATE_QUOTA_LIMIT, +}} +pub type PQUOTA_LIMITS_EX = *mut QUOTA_LIMITS_EX; +STRUCT!{struct IO_COUNTERS { + ReadOperationCount: ULONGLONG, + WriteOperationCount: ULONGLONG, + OtherOperationCount: ULONGLONG, + ReadTransferCount: ULONGLONG, + WriteTransferCount: ULONGLONG, + OtherTransferCount: ULONGLONG, +}} +pub type PIO_COUNTERS = *mut IO_COUNTERS; +pub const MAX_HW_COUNTERS: usize = 16; +pub const THREAD_PROFILING_FLAG_DISPATCH: DWORD = 0x00000001; +ENUM!{enum HARDWARE_COUNTER_TYPE { + PMCCounter, + MaxHardwareCounterType, +}} +pub type PHARDWARE_COUNTER_TYPE = *mut HARDWARE_COUNTER_TYPE; +ENUM!{enum PROCESS_MITIGATION_POLICY { + ProcessDEPPolicy, + ProcessASLRPolicy, + ProcessDynamicCodePolicy, + ProcessStrictHandleCheckPolicy, + ProcessSystemCallDisablePolicy, + ProcessMitigationOptionsMask, + ProcessExtensionPointDisablePolicy, + ProcessControlFlowGuardPolicy, + ProcessSignaturePolicy, + ProcessFontDisablePolicy, + ProcessImageLoadPolicy, + MaxProcessMitigationPolicy, +}} +pub type PPROCESS_MITIGATION_POLICY = *mut PROCESS_MITIGATION_POLICY; +STRUCT!{struct PROCESS_MITIGATION_ASLR_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_ASLR_POLICY Flags: DWORD [ + EnableBottomUpRandomization set_EnableBottomUpRandomization[0..1], + EnableForceRelocateImages set_EnableForceRelocateImages[1..2], + EnableHighEntropy set_EnableHighEntropy[2..3], + DisallowStrippedImages set_DisallowStrippedImages[3..4], + ReservedFlags set_ReservedFlags[4..32], +]} +pub type PPROCESS_MITIGATION_ASLR_POLICY = *mut PROCESS_MITIGATION_ASLR_POLICY; +STRUCT!{struct PROCESS_MITIGATION_DEP_POLICY { + Flags: DWORD, + Permanent: BOOLEAN, +}} +BITFIELD!{PROCESS_MITIGATION_DEP_POLICY Flags: DWORD [ + Enable set_Enable[0..1], + DisableAtlThunkEmulation set_DisableAtlThunkEmulation[1..2], + ReservedFlags set_ReservedFlags[2..32], +]} +pub type PPROCESS_MITIGATION_DEP_POLICY = *mut PROCESS_MITIGATION_DEP_POLICY; +STRUCT!{struct PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY Flags: DWORD [ + RaiseExceptionOnInvalidHandleReference set_RaiseExceptionOnInvalidHandleReference[0..1], + HandleExceptionsPermanentlyEnabled set_HandleExceptionsPermanentlyEnabled[1..2], + ReservedFlags set_ReservedFlags[2..32], +]} +pub type PPROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY + = *mut PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY; +STRUCT!{struct PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY Flags: DWORD [ + DisallowWin32kSystemCalls set_DisallowWin32kSystemCalls[0..1], + ReservedFlags set_ReservedFlags[1..32], +]} +pub type PPROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY + = *mut PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY; +STRUCT!{struct PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY Flags: DWORD [ + DisableExtensionPoints set_DisableExtensionPoints[0..1], + ReservedFlags set_ReservedFlags[1..32], +]} +pub type PPROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY + = *mut PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY; +STRUCT!{struct PROCESS_MITIGATION_DYNAMIC_CODE_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_DYNAMIC_CODE_POLICY Flags: DWORD [ + ProhibitDynamicCode set_ProhibitDynamicCode[0..1], + AllowThreadOptOut set_AllowThreadOptOut[1..2], + AllowRemoteDowngrade set_AllowRemoteDowngrade[2..3], + ReservedFlags set_ReservedFlags[3..32], +]} +pub type PPROCESS_MITIGATION_DYNAMIC_CODE_POLICY = *mut PROCESS_MITIGATION_DYNAMIC_CODE_POLICY; +STRUCT!{struct PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY Flags: DWORD [ + EnableControlFlowGuard set_EnableControlFlowGuard[0..1], + EnableExportSuppression set_EnableExportSuppression[1..2], + StrictMode set_StrictMode[2..3], + ReservedFlags set_ReservedFlags[3..32], +]} +pub type PPROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY + = *mut PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY; +STRUCT!{struct PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY Flags: DWORD [ + MicrosoftSignedOnly set_MicrosoftSignedOnly[0..1], + StoreSignedOnly set_StoreSignedOnly[1..2], + MitigationOptIn set_MitigationOptIn[2..3], + ReservedFlags set_ReservedFlags[3..32], +]} +pub type PPROCESS_MITIGATION_BINARY_SIGNATURE_POLICY + = *mut PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY; +STRUCT!{struct PROCESS_MITIGATION_FONT_DISABLE_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_FONT_DISABLE_POLICY Flags: DWORD [ + DisableNonSystemFonts set_DisableNonSystemFonts[0..1], + AuditNonSystemFontLoading set_AuditNonSystemFontLoading[1..2], + ReservedFlags set_ReservedFlags[2..32], +]} +pub type PPROCESS_MITIGATION_FONT_DISABLE_POLICY = *mut PROCESS_MITIGATION_FONT_DISABLE_POLICY; +STRUCT!{struct PROCESS_MITIGATION_IMAGE_LOAD_POLICY { + Flags: DWORD, +}} +BITFIELD!{PROCESS_MITIGATION_IMAGE_LOAD_POLICY Flags: DWORD [ + NoRemoteImages set_NoRemoteImages[0..1], + NoLowMandatoryLabelImages set_NoLowMandatoryLabelImages[1..2], + PreferSystem32Images set_PreferSystem32Images[2..3], + ReservedFlags set_ReservedFlags[3..32], +]} +pub type PPROCESS_MITIGATION_IMAGE_LOAD_POLICY = *mut PROCESS_MITIGATION_IMAGE_LOAD_POLICY; +STRUCT!{struct PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY { + Flags: DWORD, +}} +pub type PPPROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY = + *mut PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY; +BITFIELD!{PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY Flags: DWORD [ + FilterId set_FilterId[0..4], + ReservedFlags set_ReservedFlags[4..32], +]} +STRUCT!{struct PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY { + Flags: DWORD, +}} +pub type PPROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY = + *mut PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY; +BITFIELD!{PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY Flags: DWORD [ + EnableExportAddressFilter set_EnableExportAddressFilter[0..1], + AuditExportAddressFilter set_AuditExportAddressFilter[1..2], + EnableExportAddressFilterPlus set_EnableExportAddressFilterPlus[2..3], + AuditExportAddressFilterPlus set_AuditExportAddressFilterPlus[3..4], + EnableImportAddressFilter set_EnableImportAddressFilter[4..5], + AuditImportAddressFilter set_AuditImportAddressFilter[5..6], + EnableRopStackPivot set_EnableRopStackPivot[6..7], + AuditRopStackPivot set_AuditRopStackPivot[7..8], + EnableRopCallerCheck set_EnableRopCallerCheck[8..9], + AuditRopCallerCheck set_AuditRopCallerCheck[9..10], + EnableRopSimExec set_EnableRopSimExec[10..11], + AuditRopSimExec set_AuditRopSimExec[11..12], + ReservedFlags set_ReservedFlags[12..32], +]} +STRUCT!{struct PROCESS_MITIGATION_CHILD_PROCESS_POLICY { + Flags: DWORD, +}} +pub type PPROCESS_MITIGATION_CHILD_PROCESS_POLICY = *mut PROCESS_MITIGATION_CHILD_PROCESS_POLICY; +BITFIELD!{PROCESS_MITIGATION_CHILD_PROCESS_POLICY Flags: DWORD [ + NoChildProcessCreation set_NoChildProcessCreation[0..1], + AuditNoChildProcessCreation set_AuditNoChildProcessCreation[1..2], + AllowSecureProcessCreation set_AllowSecureProcessCreation[2..3], + ReservedFlags set_ReservedFlags[3..32], +]} +STRUCT!{struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { + TotalUserTime: LARGE_INTEGER, + TotalKernelTime: LARGE_INTEGER, + ThisPeriodTotalUserTime: LARGE_INTEGER, + ThisPeriodTotalKernelTime: LARGE_INTEGER, + TotalPageFaultCount: DWORD, + TotalProcesses: DWORD, + ActiveProcesses: DWORD, + TotalTerminatedProcesses: DWORD, +}} +pub type PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION = *mut JOBOBJECT_BASIC_ACCOUNTING_INFORMATION; +STRUCT!{struct JOBOBJECT_BASIC_LIMIT_INFORMATION { + PerProcessUserTimeLimit: LARGE_INTEGER, + PerJobUserTimeLimit: LARGE_INTEGER, + LimitFlags: DWORD, + MinimumWorkingSetSize: SIZE_T, + MaximumWorkingSetSize: SIZE_T, + ActiveProcessLimit: DWORD, + Affinity: ULONG_PTR, + PriorityClass: DWORD, + SchedulingClass: DWORD, +}} +pub type PJOBOBJECT_BASIC_LIMIT_INFORMATION = *mut JOBOBJECT_BASIC_LIMIT_INFORMATION; +STRUCT!{struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + BasicLimitInformation: JOBOBJECT_BASIC_LIMIT_INFORMATION, + IoInfo: IO_COUNTERS, + ProcessMemoryLimit: SIZE_T, + JobMemoryLimit: SIZE_T, + PeakProcessMemoryUsed: SIZE_T, + PeakJobMemoryUsed: SIZE_T, +}} +pub type PJOBOBJECT_EXTENDED_LIMIT_INFORMATION = *mut JOBOBJECT_EXTENDED_LIMIT_INFORMATION; +STRUCT!{struct JOBOBJECT_BASIC_PROCESS_ID_LIST { + NumberOfAssignedProcesses: DWORD, + NumberOfProcessIdsInList: DWORD, + ProcessIdList: [ULONG_PTR; 1], +}} +pub type PJOBOBJECT_BASIC_PROCESS_ID_LIST = *mut JOBOBJECT_BASIC_PROCESS_ID_LIST; +STRUCT!{struct JOBOBJECT_BASIC_UI_RESTRICTIONS { + UIRestrictionsClass: DWORD, +}} +pub type PJOBOBJECT_BASIC_UI_RESTRICTIONS = *mut JOBOBJECT_BASIC_UI_RESTRICTIONS; +STRUCT!{struct JOBOBJECT_SECURITY_LIMIT_INFORMATION { + SecurityLimitFlags: DWORD, + JobToken: HANDLE, + SidsToDisable: PTOKEN_GROUPS, + PrivilegesToDelete: PTOKEN_PRIVILEGES, + RestrictedSids: PTOKEN_GROUPS, +}} +pub type PJOBOBJECT_SECURITY_LIMIT_INFORMATION = *mut JOBOBJECT_SECURITY_LIMIT_INFORMATION; +STRUCT!{struct JOBOBJECT_END_OF_JOB_TIME_INFORMATION { + EndOfJobTimeAction: DWORD, +}} +pub type PJOBOBJECT_END_OF_JOB_TIME_INFORMATION = *mut JOBOBJECT_END_OF_JOB_TIME_INFORMATION; +STRUCT!{struct JOBOBJECT_ASSOCIATE_COMPLETION_PORT { + CompletionKey: PVOID, + CompletionPort: HANDLE, +}} +pub type PJOBOBJECT_ASSOCIATE_COMPLETION_PORT = *mut JOBOBJECT_ASSOCIATE_COMPLETION_PORT; +STRUCT!{struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION { + BasicInfo: JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, + IoInfo: IO_COUNTERS, +}} +pub type PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION + = *mut JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION; +STRUCT!{struct JOBOBJECT_JOBSET_INFORMATION { + MemberLevel: DWORD, +}} +pub type PJOBOBJECT_JOBSET_INFORMATION = *mut JOBOBJECT_JOBSET_INFORMATION; +ENUM!{enum JOBOBJECT_RATE_CONTROL_TOLERANCE { + ToleranceLow = 1, + ToleranceMedium, + ToleranceHigh, +}} +pub type PJOBOBJECT_RATE_CONTROL_TOLERANCE = *mut JOBOBJECT_RATE_CONTROL_TOLERANCE; +ENUM!{enum JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL { + ToleranceIntervalShort = 1, + ToleranceIntervalMedium, + ToleranceIntervalLong, +}} +pub type PJOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL + = *mut JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL; +STRUCT!{struct JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION { + IoReadBytesLimit: DWORD64, + IoWriteBytesLimit: DWORD64, + PerJobUserTimeLimit: LARGE_INTEGER, + JobMemoryLimit: DWORD64, + RateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + RateControlToleranceInterval: JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL, + LimitFlags: DWORD, +}} +pub type PJOBOBJECT_NOTIFICATION_LIMIT_INFORMATION = *mut JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION; +UNION!{union JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u1 { + [u64; 1], + JobHighMemoryLimit JobHighMemoryLimit_mut: DWORD64, + JobMemoryLimit JobMemoryLimit_mut: DWORD64, +}} +UNION!{union JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u2 { + [u32; 1], + RateControlTolerance RateControlTolerance_mut: JOBOBJECT_RATE_CONTROL_TOLERANCE, + CpuRateControlTolerance CpuRateControlTolerance_mut: JOBOBJECT_RATE_CONTROL_TOLERANCE, +}} +UNION!{union JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u3 { + [u32; 1], + RateControlToleranceInterval RateControlToleranceInterval_mut: + JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL, + CpuRateControlToleranceInterval CpuRateControlToleranceInterval_mut: + JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL, +}} +STRUCT!{struct JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2 { + IoReadBytesLimit: DWORD64, + IoWriteBytesLimit: DWORD64, + PerJobUserTimeLimit: LARGE_INTEGER, + u1: JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u1, + u2: JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u2, + u3: JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2_u3, + LimitFlags: DWORD, + IoRateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + JobLowMemoryLimit: DWORD64, + IoRateControlToleranceInterval: JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL, + NetRateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + NetRateControlToleranceInterval: JOBOBJECT_RATE_CONTROL_TOLERANCE_INTERVAL, +}} +STRUCT!{struct JOBOBJECT_LIMIT_VIOLATION_INFORMATION { + LimitFlags: DWORD, + ViolationLimitFlags: DWORD, + IoReadBytes: DWORD64, + IoReadBytesLimit: DWORD64, + IoWriteBytes: DWORD64, + IoWriteBytesLimit: DWORD64, + PerJobUserTime: LARGE_INTEGER, + PerJobUserTimeLimit: LARGE_INTEGER, + JobMemory: DWORD64, + JobMemoryLimit: DWORD64, + RateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + RateControlToleranceLimit: JOBOBJECT_RATE_CONTROL_TOLERANCE, +}} +pub type PJOBOBJECT_LIMIT_VIOLATION_INFORMATION = *mut JOBOBJECT_LIMIT_VIOLATION_INFORMATION; +UNION!{union JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u1 { + [u64; 1], + JobHighMemoryLimit JobHighMemoryLimit_mut: DWORD64, + JobMemoryLimit JobMemoryLimit_mut: DWORD64, +}} +UNION!{union JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u2 { + [u32; 1], + RateControlTolerance RateControlTolerance_mut: JOBOBJECT_RATE_CONTROL_TOLERANCE, + CpuRateControlTolerance CpuRateControlTolerance_mut: JOBOBJECT_RATE_CONTROL_TOLERANCE, +}} +UNION!{union JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u3 { + [u32; 1], + RateControlToleranceLimit RateControlToleranceLimit_mut: JOBOBJECT_RATE_CONTROL_TOLERANCE, + CpuRateControlToleranceLimit CpuRateControlToleranceLimit_mut: + JOBOBJECT_RATE_CONTROL_TOLERANCE, +}} +STRUCT!{struct JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2 { + LimitFlags: DWORD, + ViolationLimitFlags: DWORD, + IoReadBytes: DWORD64, + IoReadBytesLimit: DWORD64, + IoWriteBytes: DWORD64, + IoWriteBytesLimit: DWORD64, + PerJobUserTime: LARGE_INTEGER, + PerJobUserTimeLimit: LARGE_INTEGER, + JobMemory: DWORD64, + u1: JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u1, + u2: JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u2, + u3: JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2_u3, + JobLowMemoryLimit: DWORD64, + IoRateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + IoRateControlToleranceLimit: JOBOBJECT_RATE_CONTROL_TOLERANCE, + NetRateControlTolerance: JOBOBJECT_RATE_CONTROL_TOLERANCE, + NetRateControlToleranceLimit: JOBOBJECT_RATE_CONTROL_TOLERANCE, +}} +STRUCT!{struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION_u_s { + MinRate: WORD, + MaxRate: WORD, +}} +UNION!{union JOBOBJECT_CPU_RATE_CONTROL_INFORMATION_u { + [u32; 1], + CpuRate CpuRate_mut: DWORD, + Weight Weight_mut: DWORD, + s s_mut: JOBOBJECT_CPU_RATE_CONTROL_INFORMATION_u_s, +}} +STRUCT!{struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION { + ControlFlags: DWORD, + u: JOBOBJECT_CPU_RATE_CONTROL_INFORMATION_u, +}} +pub type PJOBOBJECT_CPU_RATE_CONTROL_INFORMATION = *mut JOBOBJECT_CPU_RATE_CONTROL_INFORMATION; +ENUM!{enum JOB_OBJECT_NET_RATE_CONTROL_FLAGS { + JOB_OBJECT_NET_RATE_CONTROL_ENABLE = 0x1, + JOB_OBJECT_NET_RATE_CONTROL_MAX_BANDWIDTH = 0x2, + JOB_OBJECT_NET_RATE_CONTROL_DSCP_TAG = 0x4, + JOB_OBJECT_NET_RATE_CONTROL_VALID_FLAGS = 0x7, +}} +pub const JOB_OBJECT_NET_RATE_CONTROL_MAX_DSCP_TAG: DWORD = 64; +STRUCT!{struct JOBOBJECT_NET_RATE_CONTROL_INFORMATION { + MaxBandwidth: DWORD64, + ControlFlags: JOB_OBJECT_NET_RATE_CONTROL_FLAGS, + DscpTag: BYTE, +}} +ENUM!{enum JOB_OBJECT_IO_RATE_CONTROL_FLAGS { + JOB_OBJECT_IO_RATE_CONTROL_ENABLE = 0x1, + JOB_OBJECT_IO_RATE_CONTROL_STANDALONE_VOLUME = 0x2, + JOB_OBJECT_IO_RATE_CONTROL_VALID_FLAGS = JOB_OBJECT_IO_RATE_CONTROL_ENABLE + | JOB_OBJECT_IO_RATE_CONTROL_STANDALONE_VOLUME, +}} +STRUCT!{struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE { + MaxIops: LONG64, + MaxBandwidth: LONG64, + ReservationIops: LONG64, + VolumeName: PWSTR, + BaseIoSize: DWORD, + ControlFlags: JOB_OBJECT_IO_RATE_CONTROL_FLAGS, + VolumeNameLength: WORD, +}} +pub type JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V1 + = JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE; +STRUCT!{struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V2 { + MaxIops: LONG64, + MaxBandwidth: LONG64, + ReservationIops: LONG64, + VolumeName: PWSTR, + BaseIoSize: DWORD, + ControlFlags: JOB_OBJECT_IO_RATE_CONTROL_FLAGS, + VolumeNameLength: WORD, + CriticalReservationIops: LONG64, + ReservationBandwidth: LONG64, + CriticalReservationBandwidth: LONG64, + MaxTimePercent: LONG64, + ReservationTimePercent: LONG64, + CriticalReservationTimePercent: LONG64, +}} +STRUCT!{struct JOBOBJECT_IO_RATE_CONTROL_INFORMATION_NATIVE_V3 { + MaxIops: LONG64, + MaxBandwidth: LONG64, + ReservationIops: LONG64, + VolumeName: PWSTR, + BaseIoSize: DWORD, + ControlFlags: JOB_OBJECT_IO_RATE_CONTROL_FLAGS, + VolumeNameLength: WORD, + CriticalReservationIops: LONG64, + ReservationBandwidth: LONG64, + CriticalReservationBandwidth: LONG64, + MaxTimePercent: LONG64, + ReservationTimePercent: LONG64, + CriticalReservationTimePercent: LONG64, + SoftMaxIops: LONG64, + SoftMaxBandwidth: LONG64, + SoftMaxTimePercent: LONG64, + LimitExcessNotifyIops: LONG64, + LimitExcessNotifyBandwidth: LONG64, + LimitExcessNotifyTimePercent: LONG64, +}} +ENUM!{enum JOBOBJECT_IO_ATTRIBUTION_CONTROL_FLAGS { + JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE = 0x1, + JOBOBJECT_IO_ATTRIBUTION_CONTROL_DISABLE = 0x2, + JOBOBJECT_IO_ATTRIBUTION_CONTROL_VALID_FLAGS = 0x3, +}} +STRUCT!{struct JOBOBJECT_IO_ATTRIBUTION_STATS { + IoCount: ULONG_PTR, + TotalNonOverlappedQueueTime: ULONGLONG, + TotalNonOverlappedServiceTime: ULONGLONG, + TotalSize: ULONGLONG, +}} +pub type PJOBOBJECT_IO_ATTRIBUTION_STATS = *mut JOBOBJECT_IO_ATTRIBUTION_STATS; +STRUCT!{struct JOBOBJECT_IO_ATTRIBUTION_INFORMATION { + ControlFlags: DWORD, + ReadStats: JOBOBJECT_IO_ATTRIBUTION_STATS, + WriteStats: JOBOBJECT_IO_ATTRIBUTION_STATS, +}} +pub type PJOBOBJECT_IO_ATTRIBUTION_INFORMATION = *mut JOBOBJECT_IO_ATTRIBUTION_INFORMATION; +pub const JOB_OBJECT_TERMINATE_AT_END_OF_JOB: DWORD = 0; +pub const JOB_OBJECT_POST_AT_END_OF_JOB: DWORD = 1; +pub const JOB_OBJECT_MSG_END_OF_JOB_TIME: DWORD = 1; +pub const JOB_OBJECT_MSG_END_OF_PROCESS_TIME: DWORD = 2; +pub const JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: DWORD = 3; +pub const JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: DWORD = 4; +pub const JOB_OBJECT_MSG_NEW_PROCESS: DWORD = 6; +pub const JOB_OBJECT_MSG_EXIT_PROCESS: DWORD = 7; +pub const JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: DWORD = 8; +pub const JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: DWORD = 9; +pub const JOB_OBJECT_MSG_JOB_MEMORY_LIMIT: DWORD = 10; +pub const JOB_OBJECT_MSG_NOTIFICATION_LIMIT: DWORD = 11; +pub const JOB_OBJECT_MSG_JOB_CYCLE_TIME_LIMIT: DWORD = 12; +pub const JOB_OBJECT_MSG_SILO_TERMINATED: DWORD = 13; +pub const JOB_OBJECT_MSG_MINIMUM: DWORD = 1; +pub const JOB_OBJECT_MSG_MAXIMUM: DWORD = 13; +pub const JOB_OBJECT_VALID_COMPLETION_FILTER: DWORD = ((1 << (JOB_OBJECT_MSG_MAXIMUM + 1)) - 1) + - ((1 << JOB_OBJECT_MSG_MINIMUM) - 1); +pub const JOB_OBJECT_LIMIT_WORKINGSET: DWORD = 0x00000001; +pub const JOB_OBJECT_LIMIT_PROCESS_TIME: DWORD = 0x00000002; +pub const JOB_OBJECT_LIMIT_JOB_TIME: DWORD = 0x00000004; +pub const JOB_OBJECT_LIMIT_ACTIVE_PROCESS: DWORD = 0x00000008; +pub const JOB_OBJECT_LIMIT_AFFINITY: DWORD = 0x00000010; +pub const JOB_OBJECT_LIMIT_PRIORITY_CLASS: DWORD = 0x00000020; +pub const JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME: DWORD = 0x00000040; +pub const JOB_OBJECT_LIMIT_SCHEDULING_CLASS: DWORD = 0x00000080; +pub const JOB_OBJECT_LIMIT_PROCESS_MEMORY: DWORD = 0x00000100; +pub const JOB_OBJECT_LIMIT_JOB_MEMORY: DWORD = 0x00000200; +pub const JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH: DWORD = JOB_OBJECT_LIMIT_JOB_MEMORY; +pub const JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION: DWORD = 0x00000400; +pub const JOB_OBJECT_LIMIT_BREAKAWAY_OK: DWORD = 0x00000800; +pub const JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK: DWORD = 0x00001000; +pub const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: DWORD = 0x00002000; +pub const JOB_OBJECT_LIMIT_SUBSET_AFFINITY: DWORD = 0x00004000; +pub const JOB_OBJECT_LIMIT_JOB_MEMORY_LOW: DWORD = 0x00008000; +pub const JOB_OBJECT_LIMIT_JOB_READ_BYTES: DWORD = 0x00010000; +pub const JOB_OBJECT_LIMIT_JOB_WRITE_BYTES: DWORD = 0x00020000; +pub const JOB_OBJECT_LIMIT_RATE_CONTROL: DWORD = 0x00040000; +pub const JOB_OBJECT_LIMIT_CPU_RATE_CONTROL: DWORD = JOB_OBJECT_LIMIT_RATE_CONTROL; +pub const JOB_OBJECT_LIMIT_IO_RATE_CONTROL: DWORD = 0x00008000; +pub const JOB_OBJECT_LIMIT_NET_RATE_CONTROL: DWORD = 0x00010000; +pub const JOB_OBJECT_LIMIT_VALID_FLAGS: DWORD = 0x0007ffff; +pub const JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS: DWORD = 0x000000ff; +pub const JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS: DWORD = 0x00007fff; +pub const JOB_OBJECT_NOTIFICATION_LIMIT_VALID_FLAGS: DWORD = JOB_OBJECT_LIMIT_JOB_READ_BYTES + | JOB_OBJECT_LIMIT_JOB_WRITE_BYTES | JOB_OBJECT_LIMIT_JOB_TIME + | JOB_OBJECT_LIMIT_JOB_MEMORY_LOW | JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH + | JOB_OBJECT_LIMIT_CPU_RATE_CONTROL | JOB_OBJECT_LIMIT_IO_RATE_CONTROL + | JOB_OBJECT_LIMIT_NET_RATE_CONTROL; +pub const JOB_OBJECT_UILIMIT_NONE: DWORD = 0x00000000; +pub const JOB_OBJECT_UILIMIT_HANDLES: DWORD = 0x00000001; +pub const JOB_OBJECT_UILIMIT_READCLIPBOARD: DWORD = 0x00000002; +pub const JOB_OBJECT_UILIMIT_WRITECLIPBOARD: DWORD = 0x00000004; +pub const JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS: DWORD = 0x00000008; +pub const JOB_OBJECT_UILIMIT_DISPLAYSETTINGS: DWORD = 0x00000010; +pub const JOB_OBJECT_UILIMIT_GLOBALATOMS: DWORD = 0x00000020; +pub const JOB_OBJECT_UILIMIT_DESKTOP: DWORD = 0x00000040; +pub const JOB_OBJECT_UILIMIT_EXITWINDOWS: DWORD = 0x00000080; +pub const JOB_OBJECT_UILIMIT_ALL: DWORD = 0x000000FF; +pub const JOB_OBJECT_UI_VALID_FLAGS: DWORD = 0x000000FF; +pub const JOB_OBJECT_SECURITY_NO_ADMIN: DWORD = 0x00000001; +pub const JOB_OBJECT_SECURITY_RESTRICTED_TOKEN: DWORD = 0x00000002; +pub const JOB_OBJECT_SECURITY_ONLY_TOKEN: DWORD = 0x00000004; +pub const JOB_OBJECT_SECURITY_FILTER_TOKENS: DWORD = 0x00000008; +pub const JOB_OBJECT_SECURITY_VALID_FLAGS: DWORD = 0x0000000f; +pub const JOB_OBJECT_CPU_RATE_CONTROL_ENABLE: DWORD = 0x1; +pub const JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED: DWORD = 0x2; +pub const JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP: DWORD = 0x4; +pub const JOB_OBJECT_CPU_RATE_CONTROL_NOTIFY: DWORD = 0x8; +pub const JOB_OBJECT_CPU_RATE_CONTROL_MIN_MAX_RATE: DWORD = 0x10; +pub const JOB_OBJECT_CPU_RATE_CONTROL_VALID_FLAGS: DWORD = 0x1f; +ENUM!{enum JOBOBJECTINFOCLASS { + JobObjectBasicAccountingInformation = 1, + JobObjectBasicLimitInformation, + JobObjectBasicProcessIdList, + JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation, + JobObjectEndOfJobTimeInformation, + JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation, + JobObjectExtendedLimitInformation, + JobObjectJobSetInformation, + JobObjectGroupInformation, + JobObjectNotificationLimitInformation, + JobObjectLimitViolationInformation, + JobObjectGroupInformationEx, + JobObjectCpuRateControlInformation, + JobObjectCompletionFilter, + JobObjectCompletionCounter, + JobObjectReserved1Information = 18, + JobObjectReserved2Information, + JobObjectReserved3Information, + JobObjectReserved4Information, + JobObjectReserved5Information, + JobObjectReserved6Information, + JobObjectReserved7Information, + JobObjectReserved8Information, + JobObjectReserved9Information, + JobObjectReserved10Information, + JobObjectReserved11Information, + JobObjectReserved12Information, + JobObjectReserved13Information, + JobObjectReserved14Information = 31, + JobObjectNetRateControlInformation, + JobObjectNotificationLimitInformation2, + JobObjectLimitViolationInformation2, + JobObjectCreateSilo, + JobObjectSiloBasicInformation, + JobObjectReserved15Information = 37, + JobObjectReserved16Information = 38, + JobObjectReserved17Information = 39, + JobObjectReserved18Information = 40, + JobObjectReserved19Information = 41, + JobObjectReserved20Information = 42, + JobObjectReserved21Information = 43, + JobObjectReserved22Information = 44, + JobObjectReserved23Information = 45, + JobObjectReserved24Information = 46, + JobObjectReserved25Information = 47, + MaxJobObjectInfoClass, +}} +STRUCT!{struct SILOOBJECT_BASIC_INFORMATION { + SiloId: DWORD, + SiloParentId: DWORD, + NumberOfProcesses: DWORD, + IsInServerSilo: BOOLEAN, + Reserved: [BYTE; 3], +}} +pub type PSILOOBJECT_BASIC_INFORMATION = *mut SILOOBJECT_BASIC_INFORMATION; +ENUM!{enum SERVERSILO_STATE { + SERVERSILO_INITING = 0, + SERVERSILO_STARTED, + SERVERSILO_SHUTTING_DOWN, + SERVERSILO_TERMINATING, + SERVERSILO_TERMINATED, +}} +pub type PSERVERSILO_STATE = *mut SERVERSILO_STATE; +STRUCT!{struct SERVERSILO_BASIC_INFORMATION { + ServiceSessionId: DWORD, + State: SERVERSILO_STATE, + ExitStatus: DWORD, +}} +pub type PSERVERSILO_BASIC_INFORMATION = *mut SERVERSILO_BASIC_INFORMATION; +ENUM!{enum FIRMWARE_TYPE { + FirmwareTypeUnknown, + FirmwareTypeBios, + FirmwareTypeUefi, + FirmwareTypeMax, +}} +pub type PFIRMWARE_TYPE = *mut FIRMWARE_TYPE; +pub const EVENT_MODIFY_STATE: DWORD = 0x0002; +pub const EVENT_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3; +pub const MUTANT_QUERY_STATE: DWORD = 0x0001; +pub const MUTANT_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE; +pub const SEMAPHORE_MODIFY_STATE: DWORD = 0x0002; +pub const SEMAPHORE_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3; +pub const TIMER_QUERY_STATE: DWORD = 0x0001; +pub const TIMER_MODIFY_STATE: DWORD = 0x0002; +pub const TIMER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | TIMER_QUERY_STATE + | TIMER_MODIFY_STATE; +pub const TIME_ZONE_ID_UNKNOWN: DWORD = 0; +pub const TIME_ZONE_ID_STANDARD: DWORD = 1; +pub const TIME_ZONE_ID_DAYLIGHT: DWORD = 2; +ENUM!{enum LOGICAL_PROCESSOR_RELATIONSHIP { + RelationProcessorCore, + RelationNumaNode, + RelationCache, + RelationProcessorPackage, + RelationGroup, + RelationAll = 0xffff, +}} +pub const LTP_PC_SMT: BYTE = 0x1; +ENUM!{enum PROCESSOR_CACHE_TYPE { + CacheUnified, + CacheInstruction, + CacheData, + CacheTrace, +}} +pub const CACHE_FULLY_ASSOCIATIVE: BYTE = 0xFF; +STRUCT!{struct CACHE_DESCRIPTOR { + Level: BYTE, + Associativity: BYTE, + LineSize: WORD, + Size: DWORD, + Type: PROCESSOR_CACHE_TYPE, +}} +pub type PCACHE_DESCRIPTOR = *mut CACHE_DESCRIPTOR; +STRUCT!{struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_ProcessorCore { + Flags: BYTE, +}} +STRUCT!{struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_NumaNode { + NodeNumber: DWORD, +}} +UNION!{union SYSTEM_LOGICAL_PROCESSOR_INFORMATION_u { + [u64; 2], + ProcessorCore ProcessorCore_mut: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_ProcessorCore, + NumaNode NumaNode_mut: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_NumaNode, + Cache Cache_mut: CACHE_DESCRIPTOR, + Reserved Reserved_mut: [ULONGLONG; 2], +}} +STRUCT!{struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION { + ProcessorMask: ULONG_PTR, + Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, + u: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_u, +}} +pub type PSYSTEM_LOGICAL_PROCESSOR_INFORMATION = *mut SYSTEM_LOGICAL_PROCESSOR_INFORMATION; +STRUCT!{struct PROCESSOR_RELATIONSHIP { + Flags: BYTE, + EfficiencyClass: BYTE, + Reserved: [BYTE; 20], + GroupCount: WORD, + GroupMask: [GROUP_AFFINITY; ANYSIZE_ARRAY], +}} +pub type PPROCESSOR_RELATIONSHIP = *mut PROCESSOR_RELATIONSHIP; +STRUCT!{struct NUMA_NODE_RELATIONSHIP { + NodeNumber: DWORD, + Reserved: [BYTE; 20], + GroupMask: GROUP_AFFINITY, +}} +pub type PNUMA_NODE_RELATIONSHIP = *mut NUMA_NODE_RELATIONSHIP; +STRUCT!{struct CACHE_RELATIONSHIP { + Level: BYTE, + Associativity: BYTE, + LineSize: WORD, + CacheSize: DWORD, + Type: PROCESSOR_CACHE_TYPE, + Reserved: [BYTE; 20], + GroupMask: GROUP_AFFINITY, +}} +pub type PCACHE_RELATIONSHIP = *mut CACHE_RELATIONSHIP; +STRUCT!{struct PROCESSOR_GROUP_INFO { + MaximumProcessorCount: BYTE, + ActiveProcessorCount: BYTE, + Reserved: [BYTE; 38], + ActiveProcessorMask: KAFFINITY, +}} +pub type PPROCESSOR_GROUP_INFO = *mut PROCESSOR_GROUP_INFO; +STRUCT!{struct GROUP_RELATIONSHIP { + MaximumGroupCount: WORD, + ActiveGroupCount: WORD, + Reserved: [BYTE; 20], + GroupInfo: [PROCESSOR_GROUP_INFO; ANYSIZE_ARRAY], +}} +pub type PGROUP_RELATIONSHIP = *mut GROUP_RELATIONSHIP; +UNION!{union SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_u { + [u32; 17] [u64; 9], + Processor Processor_mut: PROCESSOR_RELATIONSHIP, + NumaNode NumaNode_mut: NUMA_NODE_RELATIONSHIP, + Cache Cache_mut: CACHE_RELATIONSHIP, + Group Group_mut: GROUP_RELATIONSHIP, +}} +STRUCT!{struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX { + Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, + Size: DWORD, + u: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_u, +}} +pub type PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX = *mut SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX; +ENUM!{enum CPU_SET_INFORMATION_TYPE { + CpuSetInformation, +}} +pub type PCPU_SET_INFORMATION_TYPE = *mut CPU_SET_INFORMATION_TYPE; +pub const SYSTEM_CPU_SET_INFORMATION_PARKED: BYTE = 0x1; +pub const SYSTEM_CPU_SET_INFORMATION_ALLOCATED: BYTE = 0x2; +pub const SYSTEM_CPU_SET_INFORMATION_ALLOCATED_TO_TARGET_PROCESS: BYTE = 0x4; +pub const SYSTEM_CPU_SET_INFORMATION_REALTIME: BYTE = 0x8; +STRUCT!{struct SYSTEM_CPU_SET_INFORMATION_CpuSet { + Id: DWORD, + Group: WORD, + LogicalProcessorIndex: BYTE, + CoreIndex: BYTE, + LastLevelCacheIndex: BYTE, + NumaNodeIndex: BYTE, + EfficiencyClass: BYTE, + AllFlags: BYTE, + Reserved: DWORD, + AllocationTag: DWORD64, +}} +BITFIELD!{SYSTEM_CPU_SET_INFORMATION_CpuSet AllFlags: BYTE [ + Parked set_Parked[0..1], + Allocated set_Allocated[1..2], + AllocatedToTargetProcess set_AllocatedToTargetProcess[2..3], + RealTime set_RealTime[3..4], + ReservedFlags set_ReservedFlags[4..8], +]} +STRUCT!{struct SYSTEM_CPU_SET_INFORMATION { + Size: DWORD, + Type: CPU_SET_INFORMATION_TYPE, + CpuSet: SYSTEM_CPU_SET_INFORMATION_CpuSet, +}} +pub type PSYSTEM_CPU_SET_INFORMATION = *mut SYSTEM_CPU_SET_INFORMATION; +STRUCT!{struct SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION { + CycleTime: DWORD64, +}} +pub type PSYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION = *mut SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION; +pub const PROCESSOR_INTEL_386: DWORD = 386; +pub const PROCESSOR_INTEL_486: DWORD = 486; +pub const PROCESSOR_INTEL_PENTIUM: DWORD = 586; +pub const PROCESSOR_INTEL_IA64: DWORD = 2200; +pub const PROCESSOR_AMD_X8664: DWORD = 8664; +pub const PROCESSOR_MIPS_R4000: DWORD = 4000; +pub const PROCESSOR_ALPHA_21064: DWORD = 21064; +pub const PROCESSOR_PPC_601: DWORD = 601; +pub const PROCESSOR_PPC_603: DWORD = 603; +pub const PROCESSOR_PPC_604: DWORD = 604; +pub const PROCESSOR_PPC_620: DWORD = 620; +pub const PROCESSOR_HITACHI_SH3: DWORD = 10003; +pub const PROCESSOR_HITACHI_SH3E: DWORD = 10004; +pub const PROCESSOR_HITACHI_SH4: DWORD = 10005; +pub const PROCESSOR_MOTOROLA_821: DWORD = 821; +pub const PROCESSOR_SHx_SH3: DWORD = 103; +pub const PROCESSOR_SHx_SH4: DWORD = 104; +pub const PROCESSOR_STRONGARM: DWORD = 2577; +pub const PROCESSOR_ARM720: DWORD = 1824; +pub const PROCESSOR_ARM820: DWORD = 2080; +pub const PROCESSOR_ARM920: DWORD = 2336; +pub const PROCESSOR_ARM_7TDMI: DWORD = 70001; +pub const PROCESSOR_OPTIL: DWORD = 0x494f; +pub const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0; +pub const PROCESSOR_ARCHITECTURE_MIPS: WORD = 1; +pub const PROCESSOR_ARCHITECTURE_ALPHA: WORD = 2; +pub const PROCESSOR_ARCHITECTURE_PPC: WORD = 3; +pub const PROCESSOR_ARCHITECTURE_SHX: WORD = 4; +pub const PROCESSOR_ARCHITECTURE_ARM: WORD = 5; +pub const PROCESSOR_ARCHITECTURE_IA64: WORD = 6; +pub const PROCESSOR_ARCHITECTURE_ALPHA64: WORD = 7; +pub const PROCESSOR_ARCHITECTURE_MSIL: WORD = 8; +pub const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9; +pub const PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: WORD = 10; +pub const PROCESSOR_ARCHITECTURE_NEUTRAL: WORD = 11; +pub const PROCESSOR_ARCHITECTURE_ARM64: WORD = 12; +pub const PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64: WORD = 13; +pub const PROCESSOR_ARCHITECTURE_IA32_ON_ARM64: WORD = 14; +pub const PROCESSOR_ARCHITECTURE_UNKNOWN: WORD = 0xFFFF; +pub const PF_FLOATING_POINT_PRECISION_ERRATA: DWORD = 0; +pub const PF_FLOATING_POINT_EMULATED: DWORD = 1; +pub const PF_COMPARE_EXCHANGE_DOUBLE: DWORD = 2; +pub const PF_MMX_INSTRUCTIONS_AVAILABLE: DWORD = 3; +pub const PF_PPC_MOVEMEM_64BIT_OK: DWORD = 4; +pub const PF_ALPHA_BYTE_INSTRUCTIONS: DWORD = 5; +pub const PF_XMMI_INSTRUCTIONS_AVAILABLE: DWORD = 6; +pub const PF_3DNOW_INSTRUCTIONS_AVAILABLE: DWORD = 7; +pub const PF_RDTSC_INSTRUCTION_AVAILABLE: DWORD = 8; +pub const PF_PAE_ENABLED: DWORD = 9; +pub const PF_XMMI64_INSTRUCTIONS_AVAILABLE: DWORD = 10; +pub const PF_SSE_DAZ_MODE_AVAILABLE: DWORD = 11; +pub const PF_NX_ENABLED: DWORD = 12; +pub const PF_SSE3_INSTRUCTIONS_AVAILABLE: DWORD = 13; +pub const PF_COMPARE_EXCHANGE128: DWORD = 14; +pub const PF_COMPARE64_EXCHANGE128: DWORD = 15; +pub const PF_CHANNELS_ENABLED: DWORD = 16; +pub const PF_XSAVE_ENABLED: DWORD = 17; +pub const PF_ARM_VFP_32_REGISTERS_AVAILABLE: DWORD = 18; +pub const PF_ARM_NEON_INSTRUCTIONS_AVAILABLE: DWORD = 19; +pub const PF_SECOND_LEVEL_ADDRESS_TRANSLATION: DWORD = 20; +pub const PF_VIRT_FIRMWARE_ENABLED: DWORD = 21; +pub const PF_RDWRFSGSBASE_AVAILABLE: DWORD = 22; +pub const PF_FASTFAIL_AVAILABLE: DWORD = 23; +pub const PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE: DWORD = 24; +pub const PF_ARM_64BIT_LOADSTORE_ATOMIC: DWORD = 25; +pub const PF_ARM_EXTERNAL_CACHE_AVAILABLE: DWORD = 26; +pub const PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE: DWORD = 27; +pub const PF_RDRAND_INSTRUCTION_AVAILABLE: DWORD = 28; +pub const PF_ARM_V8_INSTRUCTIONS_AVAILABLE: DWORD = 29; +pub const PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE: DWORD = 30; +pub const PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE: DWORD = 31; +pub const PF_RDTSCP_INSTRUCTION_AVAILABLE: DWORD = 32; +pub const XSTATE_LEGACY_FLOATING_POINT: ULONG64 = 0; +pub const XSTATE_LEGACY_SSE: ULONG64 = 1; +pub const XSTATE_GSSE: ULONG64 = 2; +pub const XSTATE_AVX: ULONG64 = XSTATE_GSSE; +pub const XSTATE_MPX_BNDREGS: ULONG64 = 3; +pub const XSTATE_MPX_BNDCSR: ULONG64 = 4; +pub const XSTATE_AVX512_KMASK: ULONG64 = 5; +pub const XSTATE_AVX512_ZMM_H: ULONG64 = 6; +pub const XSTATE_AVX512_ZMM: ULONG64 = 7; +pub const XSTATE_IPT: ULONG64 = 8; +pub const XSTATE_LWP: ULONG64 = 62; +pub const MAXIMUM_XSTATE_FEATURES: usize = 64; +pub const XSTATE_MASK_LEGACY_FLOATING_POINT: ULONG64 = 1 << XSTATE_LEGACY_FLOATING_POINT; +pub const XSTATE_MASK_LEGACY_SSE: ULONG64 = 1 << XSTATE_LEGACY_SSE; +pub const XSTATE_MASK_LEGACY: ULONG64 = XSTATE_MASK_LEGACY_FLOATING_POINT | XSTATE_MASK_LEGACY_SSE; +pub const XSTATE_MASK_GSSE: ULONG64 = 1 << XSTATE_GSSE; +pub const XSTATE_MASK_AVX: ULONG64 = XSTATE_MASK_GSSE; +pub const XSTATE_MASK_MPX: ULONG64 = (1 << XSTATE_MPX_BNDREGS) | (1 << XSTATE_MPX_BNDCSR); +pub const XSTATE_MASK_AVX512: ULONG64 = (1 << XSTATE_AVX512_KMASK) | (1 << XSTATE_AVX512_ZMM_H) + | (1 << XSTATE_AVX512_ZMM); +pub const XSTATE_MASK_IPT: ULONG64 = 1 << XSTATE_IPT; +pub const XSTATE_MASK_LWP: ULONG64 = 1 << XSTATE_LWP; +pub const XSTATE_MASK_ALLOWED: ULONG64 = XSTATE_MASK_LEGACY | XSTATE_MASK_AVX | XSTATE_MASK_MPX + | XSTATE_MASK_AVX512 | XSTATE_MASK_IPT | XSTATE_MASK_LWP; +pub const XSTATE_MASK_PERSISTENT: ULONG64 = (1 << XSTATE_MPX_BNDCSR) | XSTATE_MASK_LWP; +pub const XSTATE_COMPACTION_ENABLE: ULONG64 = 63; +pub const XSTATE_COMPACTION_ENABLE_MASK: ULONG64 = 1 << XSTATE_COMPACTION_ENABLE; +pub const XSTATE_ALIGN_BIT: ULONG64 = 1; +pub const XSTATE_ALIGN_MASK: ULONG64 = 1 << XSTATE_ALIGN_BIT; +pub const XSTATE_CONTROLFLAG_XSAVEOPT_MASK: ULONG64 = 1; +pub const XSTATE_CONTROLFLAG_XSAVEC_MASK: ULONG64 = 2; +pub const XSTATE_CONTROLFLAG_VALID_MASK: ULONG64 = XSTATE_CONTROLFLAG_XSAVEOPT_MASK + | XSTATE_CONTROLFLAG_XSAVEC_MASK; +STRUCT!{struct XSTATE_FEATURE { + Offset: DWORD, + Size: DWORD, +}} +pub type PXSTATE_FEATURE = *mut XSTATE_FEATURE; +STRUCT!{struct XSTATE_CONFIGURATION { + EnabledFeatures: DWORD64, + EnabledVolatileFeatures: DWORD64, + Size: DWORD, + ControlFlags: DWORD, + Features: [XSTATE_FEATURE; MAXIMUM_XSTATE_FEATURES], + EnabledSupervisorFeatures: DWORD64, + AlignedFeatures: DWORD64, + AllFeatureSize: DWORD, + AllFeatures: [DWORD; MAXIMUM_XSTATE_FEATURES], +}} +BITFIELD!{XSTATE_CONFIGURATION ControlFlags: DWORD [ + OptimizedSave set_OptimizedSave[0..1], + CompactionEnabled set_CompactionEnabled[1..2], +]} +pub type PXSTATE_CONFIGURATION = *mut XSTATE_CONFIGURATION; +STRUCT!{struct MEMORY_BASIC_INFORMATION { + BaseAddress: PVOID, + AllocationBase: PVOID, + AllocationProtect: DWORD, + RegionSize: SIZE_T, + State: DWORD, + Protect: DWORD, + Type: DWORD, +}} +pub type PMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION; +STRUCT!{struct MEMORY_BASIC_INFORMATION32 { + BaseAddress: DWORD, + AllocationBase: DWORD, + AllocationProtect: DWORD, + RegionSize: DWORD, + State: DWORD, + Protect: DWORD, + Type: DWORD, +}} +pub type PMEMORY_BASIC_INFORMATION32 = *mut MEMORY_BASIC_INFORMATION32; +STRUCT!{struct MEMORY_BASIC_INFORMATION64 { // FIXME: align 16 + BaseAddress: ULONGLONG, + AllocationBase: ULONGLONG, + AllocationProtect: DWORD, + __alignment1: DWORD, + RegionSize: ULONGLONG, + State: DWORD, + Protect: DWORD, + Type: DWORD, + __alignment2: DWORD, +}} +pub type PMEMORY_BASIC_INFORMATION64 = *mut MEMORY_BASIC_INFORMATION64; +pub const CFG_CALL_TARGET_VALID: ULONG_PTR = 0x00000001; +pub const CFG_CALL_TARGET_PROCESSED: ULONG_PTR = 0x00000002; +pub const CFG_CALL_TARGET_CONVERT_EXPORT_SUPPRESSED_TO_VALID: ULONG_PTR = 0x00000004; +STRUCT!{struct CFG_CALL_TARGET_INFO { + Offset: ULONG_PTR, + Flags: ULONG_PTR, +}} +pub type PCFG_CALL_TARGET_INFO = *mut CFG_CALL_TARGET_INFO; +pub const SECTION_QUERY: DWORD = 0x0001; +pub const SECTION_MAP_WRITE: DWORD = 0x0002; +pub const SECTION_MAP_READ: DWORD = 0x0004; +pub const SECTION_MAP_EXECUTE: DWORD = 0x0008; +pub const SECTION_EXTEND_SIZE: DWORD = 0x0010; +pub const SECTION_MAP_EXECUTE_EXPLICIT: DWORD = 0x0020; +pub const SECTION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY + | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE; +pub const SESSION_QUERY_ACCESS: DWORD = 0x0001; +pub const SESSION_MODIFY_ACCESS: DWORD = 0x0002; +pub const SESSION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SESSION_QUERY_ACCESS + | SESSION_MODIFY_ACCESS; +pub const MEMORY_PARTITION_QUERY_ACCESS: DWORD = 0x0001; +pub const MEMORY_PARTITION_MODIFY_ACCESS: DWORD = 0x0002; +pub const MEMORY_PARTITION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE + | MEMORY_PARTITION_QUERY_ACCESS | MEMORY_PARTITION_MODIFY_ACCESS; +pub const PAGE_NOACCESS: DWORD = 0x01; +pub const PAGE_READONLY: DWORD = 0x02; +pub const PAGE_READWRITE: DWORD = 0x04; +pub const PAGE_WRITECOPY: DWORD = 0x08; +pub const PAGE_EXECUTE: DWORD = 0x10; +pub const PAGE_EXECUTE_READ: DWORD = 0x20; +pub const PAGE_EXECUTE_READWRITE: DWORD = 0x40; +pub const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80; +pub const PAGE_GUARD: DWORD = 0x100; +pub const PAGE_NOCACHE: DWORD = 0x200; +pub const PAGE_WRITECOMBINE: DWORD = 0x400; +pub const PAGE_ENCLAVE_THREAD_CONTROL: DWORD = 0x80000000; +pub const PAGE_REVERT_TO_FILE_MAP: DWORD = 0x80000000; +pub const PAGE_TARGETS_NO_UPDATE: DWORD = 0x40000000; +pub const PAGE_TARGETS_INVALID: DWORD = 0x40000000; +pub const PAGE_ENCLAVE_UNVALIDATED: DWORD = 0x20000000; +pub const PAGE_ENCLAVE_DECOMMIT: DWORD = 0x10000000; +pub const MEM_COMMIT: DWORD = 0x1000; +pub const MEM_RESERVE: DWORD = 0x2000; +pub const MEM_DECOMMIT: DWORD = 0x4000; +pub const MEM_RELEASE: DWORD = 0x8000; +pub const MEM_FREE: DWORD = 0x10000; +pub const MEM_PRIVATE: DWORD = 0x20000; +pub const MEM_MAPPED: DWORD = 0x40000; +pub const MEM_RESET: DWORD = 0x80000; +pub const MEM_TOP_DOWN: DWORD = 0x100000; +pub const MEM_WRITE_WATCH: DWORD = 0x200000; +pub const MEM_PHYSICAL: DWORD = 0x400000; +pub const MEM_ROTATE: DWORD = 0x800000; +pub const MEM_DIFFERENT_IMAGE_BASE_OK: DWORD = 0x800000; +pub const MEM_RESET_UNDO: DWORD = 0x1000000; +pub const MEM_LARGE_PAGES: DWORD = 0x20000000; +pub const MEM_4MB_PAGES: DWORD = 0x80000000; +pub const MEM_64K_PAGES: DWORD = MEM_LARGE_PAGES | MEM_PHYSICAL; +pub const SEC_64K_PAGES: DWORD = 0x00080000; +pub const SEC_FILE: DWORD = 0x800000; +pub const SEC_IMAGE: DWORD = 0x1000000; +pub const SEC_PROTECTED_IMAGE: DWORD = 0x2000000; +pub const SEC_RESERVE: DWORD = 0x4000000; +pub const SEC_COMMIT: DWORD = 0x8000000; +pub const SEC_NOCACHE: DWORD = 0x10000000; +pub const SEC_WRITECOMBINE: DWORD = 0x40000000; +pub const SEC_LARGE_PAGES: DWORD = 0x80000000; +pub const SEC_IMAGE_NO_EXECUTE: DWORD = (SEC_IMAGE | SEC_NOCACHE); +pub const MEM_IMAGE: DWORD = SEC_IMAGE; +pub const WRITE_WATCH_FLAG_RESET: DWORD = 0x01; +pub const MEM_UNMAP_WITH_TRANSIENT_BOOST: DWORD = 0x01; +pub const ENCLAVE_TYPE_SGX: DWORD = 0x00000001; +pub const ENCLAVE_TYPE_SGX2: DWORD = 0x00000002; +STRUCT!{struct ENCLAVE_CREATE_INFO_SGX { + Secs: [BYTE; 4096], +}} +pub type PENCLAVE_CREATE_INFO_SGX = *mut ENCLAVE_CREATE_INFO_SGX; +STRUCT!{struct ENCLAVE_INIT_INFO_SGX { + SigStruct: [BYTE; 1808], + Reserved1: [BYTE; 240], + EInitToken: [BYTE; 304], + Reserved2: [BYTE; 1744], +}} +pub type PENCLAVE_INIT_INFO_SGX = *mut ENCLAVE_INIT_INFO_SGX; +pub const FILE_READ_DATA: DWORD = 0x0001; +pub const FILE_LIST_DIRECTORY: DWORD = 0x0001; +pub const FILE_WRITE_DATA: DWORD = 0x0002; +pub const FILE_ADD_FILE: DWORD = 0x0002; +pub const FILE_APPEND_DATA: DWORD = 0x0004; +pub const FILE_ADD_SUBDIRECTORY: DWORD = 0x0004; +pub const FILE_CREATE_PIPE_INSTANCE: DWORD = 0x0004; +pub const FILE_READ_EA: DWORD = 0x0008; +pub const FILE_WRITE_EA: DWORD = 0x0010; +pub const FILE_EXECUTE: DWORD = 0x0020; +pub const FILE_TRAVERSE: DWORD = 0x0020; +pub const FILE_DELETE_CHILD: DWORD = 0x0040; +pub const FILE_READ_ATTRIBUTES: DWORD = 0x0080; +pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x0100; +pub const FILE_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF; +pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA + | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE; +pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE; +pub const FILE_GENERIC_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES + | FILE_EXECUTE | SYNCHRONIZE; +pub const FILE_SHARE_READ: DWORD = 0x00000001; +pub const FILE_SHARE_WRITE: DWORD = 0x00000002; +pub const FILE_SHARE_DELETE: DWORD = 0x00000004; +pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x00000001; +pub const FILE_ATTRIBUTE_HIDDEN: DWORD = 0x00000002; +pub const FILE_ATTRIBUTE_SYSTEM: DWORD = 0x00000004; +pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x00000010; +pub const FILE_ATTRIBUTE_ARCHIVE: DWORD = 0x00000020; +pub const FILE_ATTRIBUTE_DEVICE: DWORD = 0x00000040; +pub const FILE_ATTRIBUTE_NORMAL: DWORD = 0x00000080; +pub const FILE_ATTRIBUTE_TEMPORARY: DWORD = 0x00000100; +pub const FILE_ATTRIBUTE_SPARSE_FILE: DWORD = 0x00000200; +pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x00000400; +pub const FILE_ATTRIBUTE_COMPRESSED: DWORD = 0x00000800; +pub const FILE_ATTRIBUTE_OFFLINE: DWORD = 0x00001000; +pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: DWORD = 0x00002000; +pub const FILE_ATTRIBUTE_ENCRYPTED: DWORD = 0x00004000; +pub const FILE_ATTRIBUTE_INTEGRITY_STREAM: DWORD = 0x00008000; +pub const FILE_ATTRIBUTE_VIRTUAL: DWORD = 0x00010000; +pub const FILE_ATTRIBUTE_NO_SCRUB_DATA: DWORD = 0x00020000; +pub const FILE_ATTRIBUTE_EA: DWORD = 0x00040000; +pub const FILE_ATTRIBUTE_PINNED: DWORD = 0x00080000; +pub const FILE_ATTRIBUTE_UNPINNED: DWORD = 0x00100000; +pub const FILE_ATTRIBUTE_RECALL_ON_OPEN: DWORD = 0x00040000; +pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: DWORD = 0x00400000; +pub const FILE_NOTIFY_CHANGE_FILE_NAME: DWORD = 0x00000001; +pub const FILE_NOTIFY_CHANGE_DIR_NAME: DWORD = 0x00000002; +pub const FILE_NOTIFY_CHANGE_ATTRIBUTES: DWORD = 0x00000004; +pub const FILE_NOTIFY_CHANGE_SIZE: DWORD = 0x00000008; +pub const FILE_NOTIFY_CHANGE_LAST_WRITE: DWORD = 0x00000010; +pub const FILE_NOTIFY_CHANGE_LAST_ACCESS: DWORD = 0x00000020; +pub const FILE_NOTIFY_CHANGE_CREATION: DWORD = 0x00000040; +pub const FILE_NOTIFY_CHANGE_SECURITY: DWORD = 0x00000100; +pub const FILE_ACTION_ADDED: DWORD = 0x00000001; +pub const FILE_ACTION_REMOVED: DWORD = 0x00000002; +pub const FILE_ACTION_MODIFIED: DWORD = 0x00000003; +pub const FILE_ACTION_RENAMED_OLD_NAME: DWORD = 0x00000004; +pub const FILE_ACTION_RENAMED_NEW_NAME: DWORD = 0x00000005; +pub const MAILSLOT_NO_MESSAGE: DWORD = 0xFFFFFFFF; +pub const MAILSLOT_WAIT_FOREVER: DWORD = 0xFFFFFFFF; +pub const FILE_CASE_SENSITIVE_SEARCH: DWORD = 0x00000001; +pub const FILE_CASE_PRESERVED_NAMES: DWORD = 0x00000002; +pub const FILE_UNICODE_ON_DISK: DWORD = 0x00000004; +pub const FILE_PERSISTENT_ACLS: DWORD = 0x00000008; +pub const FILE_FILE_COMPRESSION: DWORD = 0x00000010; +pub const FILE_VOLUME_QUOTAS: DWORD = 0x00000020; +pub const FILE_SUPPORTS_SPARSE_FILES: DWORD = 0x00000040; +pub const FILE_SUPPORTS_REPARSE_POINTS: DWORD = 0x00000080; +pub const FILE_SUPPORTS_REMOTE_STORAGE: DWORD = 0x00000100; +pub const FILE_RETURNS_CLEANUP_RESULT_INFO: DWORD = 0x00000200; +pub const FILE_VOLUME_IS_COMPRESSED: DWORD = 0x00008000; +pub const FILE_SUPPORTS_OBJECT_IDS: DWORD = 0x00010000; +pub const FILE_SUPPORTS_ENCRYPTION: DWORD = 0x00020000; +pub const FILE_NAMED_STREAMS: DWORD = 0x00040000; +pub const FILE_READ_ONLY_VOLUME: DWORD = 0x00080000; +pub const FILE_SEQUENTIAL_WRITE_ONCE: DWORD = 0x00100000; +pub const FILE_SUPPORTS_TRANSACTIONS: DWORD = 0x00200000; +pub const FILE_SUPPORTS_HARD_LINKS: DWORD = 0x00400000; +pub const FILE_SUPPORTS_EXTENDED_ATTRIBUTES: DWORD = 0x00800000; +pub const FILE_SUPPORTS_OPEN_BY_FILE_ID: DWORD = 0x01000000; +pub const FILE_SUPPORTS_USN_JOURNAL: DWORD = 0x02000000; +pub const FILE_SUPPORTS_INTEGRITY_STREAMS: DWORD = 0x04000000; +pub const FILE_SUPPORTS_BLOCK_REFCOUNTING: DWORD = 0x08000000; +pub const FILE_SUPPORTS_SPARSE_VDL: DWORD = 0x10000000; +pub const FILE_DAX_VOLUME: DWORD = 0x20000000; +pub const FILE_SUPPORTS_GHOSTING: DWORD = 0x40000000; +pub const FILE_INVALID_FILE_ID: LONGLONG = -1; +STRUCT!{struct FILE_ID_128 { + Identifier: [BYTE; 16], +}} +pub type PFILE_ID_128 = *mut FILE_ID_128; +STRUCT!{struct FILE_NOTIFY_INFORMATION { + NextEntryOffset: DWORD, + Action: DWORD, + FileNameLength: DWORD, + FileName: [WCHAR; 1], +}} +UNION!{union FILE_SEGMENT_ELEMENT { + [u64; 1], + Buffer Buffer_mut: PVOID64, + Alignment Alignment_mut: ULONGLONG, +}} +pub type PFILE_SEGMENT_ELEMENT = *mut FILE_SEGMENT_ELEMENT; +pub const FLUSH_FLAGS_FILE_DATA_ONLY: ULONG = 0x00000001; +pub const FLUSH_FLAGS_NO_SYNC: ULONG = 0x00000002; +pub const FLUSH_FLAGS_FILE_DATA_SYNC_ONLY: ULONG = 0x00000004; +STRUCT!{struct REPARSE_GUID_DATA_BUFFER_GenericReparseBuffer { + DataBuffer: [BYTE; 1], +}} +STRUCT!{struct REPARSE_GUID_DATA_BUFFER { + ReparseTag: DWORD, + ReparseDataLength: WORD, + Reserved: WORD, + ReparseGuid: GUID, + GenericReparseBuffer: REPARSE_GUID_DATA_BUFFER_GenericReparseBuffer, +}} +pub type PREPARSE_GUID_DATA_BUFFER = *mut REPARSE_GUID_DATA_BUFFER; +pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: DWORD = 16 * 1024; +pub const IO_REPARSE_TAG_RESERVED_ZERO: DWORD = 0; +pub const IO_REPARSE_TAG_RESERVED_ONE: DWORD = 1; +pub const IO_REPARSE_TAG_RESERVED_TWO: DWORD = 2; +pub const IO_REPARSE_TAG_RESERVED_RANGE: DWORD = IO_REPARSE_TAG_RESERVED_TWO; +#[inline] +pub fn IsReparseTagMicrosoft(_tag: DWORD) -> bool { + (_tag & 0x80000000) != 0 +} +#[inline] +pub fn IsReparseTagNameSurrogate(_tag: DWORD) -> bool { + (_tag & 0x20000000) != 0 +} +#[inline] +pub fn IsReparseTagDirectory(_tag: DWORD) -> bool { + (_tag & 0x10000000) != 0 +} +pub const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xA0000003; +pub const IO_REPARSE_TAG_HSM: DWORD = 0xC0000004; +pub const IO_REPARSE_TAG_HSM2: DWORD = 0x80000006; +pub const IO_REPARSE_TAG_SIS: DWORD = 0x80000007; +pub const IO_REPARSE_TAG_WIM: DWORD = 0x80000008; +pub const IO_REPARSE_TAG_CSV: DWORD = 0x80000009; +pub const IO_REPARSE_TAG_DFS: DWORD = 0x8000000A; +pub const IO_REPARSE_TAG_SYMLINK: DWORD = 0xA000000C; +pub const IO_REPARSE_TAG_DFSR: DWORD = 0x80000012; +pub const IO_REPARSE_TAG_DEDUP: DWORD = 0x80000013; +pub const IO_REPARSE_TAG_NFS: DWORD = 0x80000014; +pub const IO_REPARSE_TAG_FILE_PLACEHOLDER: DWORD = 0x80000015; +pub const IO_REPARSE_TAG_WOF: DWORD = 0x80000017; +pub const IO_REPARSE_TAG_WCI: DWORD = 0x80000018; +pub const IO_REPARSE_TAG_GLOBAL_REPARSE: DWORD = 0xA0000019; +pub const IO_REPARSE_TAG_CLOUD: DWORD = 0x9000001A; +pub const IO_REPARSE_TAG_CLOUD_ROOT: DWORD = 0x9000101A; +pub const IO_REPARSE_TAG_CLOUD_ON_DEMAND: DWORD = 0x9000201A; +pub const IO_REPARSE_TAG_CLOUD_ROOT_ON_DEMAND: DWORD = 0x9000301A; +pub const IO_REPARSE_TAG_APPEXECLINK: DWORD = 0x8000001B; +pub const IO_REPARSE_TAG_GVFS: DWORD = 0x9000001C; +pub const IO_REPARSE_TAG_WCI_TOMBSTONE: DWORD = 0xA000001F; +pub const IO_REPARSE_TAG_UNHANDLED: DWORD = 0x80000020; +pub const IO_REPARSE_TAG_ONEDRIVE: DWORD = 0x80000021; +pub const IO_REPARSE_TAG_GVFS_TOMBSTONE: DWORD = 0xA0000022; +pub const SCRUB_DATA_INPUT_FLAG_RESUME: DWORD = 0x00000001; +pub const SCRUB_DATA_INPUT_FLAG_SKIP_IN_SYNC: DWORD = 0x00000002; +pub const SCRUB_DATA_INPUT_FLAG_SKIP_NON_INTEGRITY_DATA: DWORD = 0x00000004; +pub const SCRUB_DATA_OUTPUT_FLAG_INCOMPLETE: DWORD = 0x00000001; +pub const SCRUB_DATA_OUTPUT_FLAG_NON_USER_DATA_RANGE: DWORD = 0x00010000; +pub const SCRUB_DATA_OUTPUT_FLAG_PARITY_EXTENT_DATA_RETURNED: DWORD = 0x00020000; +pub const SCRUB_DATA_OUTPUT_FLAG_RESUME_CONTEXT_LENGTH_SPECIFIED: DWORD = 0x00040000; +STRUCT!{struct SCRUB_DATA_INPUT { + Size: DWORD, + Flags: DWORD, + MaximumIos: DWORD, + Reserved: [DWORD; 17], + ResumeContext: [BYTE; 816], +}} +pub type PSCRUB_DATA_INPUT = *mut SCRUB_DATA_INPUT; +STRUCT!{struct SCRUB_PARITY_EXTENT { + Offset: LONGLONG, + Length: ULONGLONG, +}} +pub type PSCRUB_PARITY_EXTENT = *mut SCRUB_PARITY_EXTENT; +STRUCT!{struct SCRUB_PARITY_EXTENT_DATA { + Size: WORD, + Flags: WORD, + NumberOfParityExtents: WORD, + MaximumNumberOfParityExtents: WORD, + ParityExtents: [SCRUB_PARITY_EXTENT; ANYSIZE_ARRAY], +}} +pub type PSCRUB_PARITY_EXTENT_DATA = *mut SCRUB_PARITY_EXTENT_DATA; +STRUCT!{struct SCRUB_DATA_OUTPUT { + Size: DWORD, + Flags: DWORD, + Status: DWORD, + ErrorFileOffset: ULONGLONG, + ErrorLength: ULONGLONG, + NumberOfBytesRepaired: ULONGLONG, + NumberOfBytesFailed: ULONGLONG, + InternalFileReference: ULONGLONG, + ResumeContextLength: WORD, + ParityExtentDataOffset: WORD, + Reserved: [DWORD; 5], + ResumeContext: [BYTE; 816], +}} +pub type PSCRUB_DATA_OUTPUT = *mut SCRUB_DATA_OUTPUT; +ENUM!{enum SharedVirtualDiskSupportType { + SharedVirtualDisksUnsupported = 0, + SharedVirtualDisksSupported = 1, + SharedVirtualDiskSnapshotsSupported = 3, + SharedVirtualDiskCDPSnapshotsSupported = 7, +}} +ENUM!{enum SharedVirtualDiskHandleState { + SharedVirtualDiskHandleStateNone = 0, + SharedVirtualDiskHandleStateFileShared = 1, + SharedVirtualDiskHandleStateHandleShared = 3, +}} +STRUCT!{struct SHARED_VIRTUAL_DISK_SUPPORT { + SharedVirtualDiskSupport: SharedVirtualDiskSupportType, + HandleState: SharedVirtualDiskHandleState, +}} +pub type PSHARED_VIRTUAL_DISK_SUPPORT = *mut SHARED_VIRTUAL_DISK_SUPPORT; +#[inline] +pub fn IsVirtualDiskFileShared(HandleState: SharedVirtualDiskHandleState) -> bool { + (HandleState & SharedVirtualDiskHandleStateFileShared) != 0 +} +pub const IO_COMPLETION_MODIFY_STATE: DWORD = 0x0002; +pub const IO_COMPLETION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3; +pub const IO_QOS_MAX_RESERVATION: DWORD64 = 1000000000; +pub const SMB_CCF_APP_INSTANCE_EA_NAME: &'static str = "ClusteredApplicationInstance"; +pub const NETWORK_APP_INSTANCE_CSV_FLAGS_VALID_ONLY_IF_CSV_COORDINATOR: DWORD = 0x00000001; +STRUCT!{struct NETWORK_APP_INSTANCE_EA { + AppInstanceID: GUID, + CsvFlags: DWORD, +}} +pub type PNETWORK_APP_INSTANCE_EA = *mut NETWORK_APP_INSTANCE_EA; +pub const DUPLICATE_CLOSE_SOURCE: DWORD = 0x00000001; +pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; +DEFINE_GUID!{GUID_MAX_POWER_SAVINGS, + 0xa1841308, 0x3541, 0x4fab, 0xbc, 0x81, 0xf7, 0x15, 0x56, 0xf2, 0x0b, 0x4a} +DEFINE_GUID!{GUID_MIN_POWER_SAVINGS, + 0x8c5e7fda, 0xe8bf, 0x4a96, 0x9a, 0x85, 0xa6, 0xe2, 0x3a, 0x8c, 0x63, 0x5c} +DEFINE_GUID!{GUID_TYPICAL_POWER_SAVINGS, + 0x381b4222, 0xf694, 0x41f0, 0x96, 0x85, 0xff, 0x5b, 0xb2, 0x60, 0xdf, 0x2e} +DEFINE_GUID!{NO_SUBGROUP_GUID, + 0xfea3413e, 0x7e05, 0x4911, 0x9a, 0x71, 0x70, 0x03, 0x31, 0xf1, 0xc2, 0x94} +DEFINE_GUID!{ALL_POWERSCHEMES_GUID, + 0x68a1e95e, 0x13ea, 0x41e1, 0x80, 0x11, 0x0c, 0x49, 0x6c, 0xa4, 0x90, 0xb0} +DEFINE_GUID!{GUID_POWERSCHEME_PERSONALITY, + 0x245d8541, 0x3943, 0x4422, 0xb0, 0x25, 0x13, 0xa7, 0x84, 0xf6, 0x79, 0xb7} +DEFINE_GUID!{GUID_ACTIVE_POWERSCHEME, + 0x31f9f286, 0x5084, 0x42fe, 0xb7, 0x20, 0x2b, 0x02, 0x64, 0x99, 0x37, 0x63} +DEFINE_GUID!{GUID_IDLE_RESILIENCY_SUBGROUP, + 0x2e601130, 0x5351, 0x4d9d, 0x8e, 0x4, 0x25, 0x29, 0x66, 0xba, 0xd0, 0x54} +DEFINE_GUID!{GUID_IDLE_RESILIENCY_PERIOD, + 0xc42b79aa, 0xaa3a, 0x484b, 0xa9, 0x8f, 0x2c, 0xf3, 0x2a, 0xa9, 0xa, 0x28} +DEFINE_GUID!{GUID_DEEP_SLEEP_ENABLED, + 0xd502f7ee, 0x1dc7, 0x4efd, 0xa5, 0x5d, 0xf0, 0x4b, 0x6f, 0x5c, 0x5, 0x45} +DEFINE_GUID!{GUID_DEEP_SLEEP_PLATFORM_STATE, + 0xd23f2fb8, 0x9536, 0x4038, 0x9c, 0x94, 0x1c, 0xe0, 0x2e, 0x5c, 0x21, 0x52} +DEFINE_GUID!{GUID_DISK_COALESCING_POWERDOWN_TIMEOUT, + 0xc36f0eb4, 0x2988, 0x4a70, 0x8e, 0xee, 0x8, 0x84, 0xfc, 0x2c, 0x24, 0x33} +DEFINE_GUID!{GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT, + 0x3166bc41, 0x7e98, 0x4e03, 0xb3, 0x4e, 0xec, 0xf, 0x5f, 0x2b, 0x21, 0x8e} +DEFINE_GUID!{GUID_VIDEO_SUBGROUP, + 0x7516b95f, 0xf776, 0x4464, 0x8c, 0x53, 0x06, 0x16, 0x7f, 0x40, 0xcc, 0x99} +DEFINE_GUID!{GUID_VIDEO_POWERDOWN_TIMEOUT, + 0x3c0bc021, 0xc8a8, 0x4e07, 0xa9, 0x73, 0x6b, 0x14, 0xcb, 0xcb, 0x2b, 0x7e} +DEFINE_GUID!{GUID_VIDEO_ANNOYANCE_TIMEOUT, + 0x82dbcf2d, 0xcd67, 0x40c5, 0xbf, 0xdc, 0x9f, 0x1a, 0x5c, 0xcd, 0x46, 0x63} +DEFINE_GUID!{GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE, + 0xeed904df, 0xb142, 0x4183, 0xb1, 0x0b, 0x5a, 0x11, 0x97, 0xa3, 0x78, 0x64} +DEFINE_GUID!{GUID_VIDEO_DIM_TIMEOUT, + 0x17aaa29b, 0x8b43, 0x4b94, 0xaa, 0xfe, 0x35, 0xf6, 0x4d, 0xaa, 0xf1, 0xee} +DEFINE_GUID!{GUID_VIDEO_ADAPTIVE_POWERDOWN, + 0x90959d22, 0xd6a1, 0x49b9, 0xaf, 0x93, 0xbc, 0xe8, 0x85, 0xad, 0x33, 0x5b} +DEFINE_GUID!{GUID_MONITOR_POWER_ON, + 0x02731015, 0x4510, 0x4526, 0x99, 0xe6, 0xe5, 0xa1, 0x7e, 0xbd, 0x1a, 0xea} +DEFINE_GUID!{GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS, + 0xaded5e82, 0xb909, 0x4619, 0x99, 0x49, 0xf5, 0xd7, 0x1d, 0xac, 0x0b, 0xcb} +DEFINE_GUID!{GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS, + 0xf1fbfde2, 0xa960, 0x4165, 0x9f, 0x88, 0x50, 0x66, 0x79, 0x11, 0xce, 0x96} +DEFINE_GUID!{GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS, + 0x8ffee2c6, 0x2d01, 0x46be, 0xad, 0xb9, 0x39, 0x8a, 0xdd, 0xc5, 0xb4, 0xff} +DEFINE_GUID!{GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS, + 0xfbd9aa66, 0x9553, 0x4097, 0xba, 0x44, 0xed, 0x6e, 0x9d, 0x65, 0xea, 0xb8} +DEFINE_GUID!{GUID_CONSOLE_DISPLAY_STATE, + 0x6fe69556, 0x704a, 0x47a0, 0x8f, 0x24, 0xc2, 0x8d, 0x93, 0x6f, 0xda, 0x47} +DEFINE_GUID!{GUID_ALLOW_DISPLAY_REQUIRED, + 0xa9ceb8da, 0xcd46, 0x44fb, 0xa9, 0x8b, 0x02, 0xaf, 0x69, 0xde, 0x46, 0x23} +DEFINE_GUID!{GUID_VIDEO_CONSOLE_LOCK_TIMEOUT, + 0x8ec4b3a5, 0x6868, 0x48c2, 0xbe, 0x75, 0x4f, 0x30, 0x44, 0xbe, 0x88, 0xa7} +DEFINE_GUID!{GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP, + 0x8619b916, 0xe004, 0x4dd8, 0x9b, 0x66, 0xda, 0xe8, 0x6f, 0x80, 0x66, 0x98} +DEFINE_GUID!{GUID_NON_ADAPTIVE_INPUT_TIMEOUT, + 0x5adbbfbc, 0x74e, 0x4da1, 0xba, 0x38, 0xdb, 0x8b, 0x36, 0xb2, 0xc8, 0xf3} +DEFINE_GUID!{GUID_ADAPTIVE_INPUT_CONTROLLER_STATE, + 0xe98fae9, 0xf45a, 0x4de1, 0xa7, 0x57, 0x60, 0x31, 0xf1, 0x97, 0xf6, 0xea} +DEFINE_GUID!{GUID_DISK_SUBGROUP, + 0x0012ee47, 0x9041, 0x4b5d, 0x9b, 0x77, 0x53, 0x5f, 0xba, 0x8b, 0x14, 0x42} +DEFINE_GUID!{GUID_DISK_MAX_POWER, + 0x51dea550, 0xbb38, 0x4bc4, 0x99, 0x1b, 0xea, 0xcf, 0x37, 0xbe, 0x5e, 0xc8} +DEFINE_GUID!{GUID_DISK_POWERDOWN_TIMEOUT, + 0x6738e2c4, 0xe8a5, 0x4a42, 0xb1, 0x6a, 0xe0, 0x40, 0xe7, 0x69, 0x75, 0x6e} +DEFINE_GUID!{GUID_DISK_IDLE_TIMEOUT, + 0x58e39ba8, 0xb8e6, 0x4ef6, 0x90, 0xd0, 0x89, 0xae, 0x32, 0xb2, 0x58, 0xd6} +DEFINE_GUID!{GUID_DISK_BURST_IGNORE_THRESHOLD, + 0x80e3c60e, 0xbb94, 0x4ad8, 0xbb, 0xe0, 0x0d, 0x31, 0x95, 0xef, 0xc6, 0x63} +DEFINE_GUID!{GUID_DISK_ADAPTIVE_POWERDOWN, + 0x396a32e1, 0x499a, 0x40b2, 0x91, 0x24, 0xa9, 0x6a, 0xfe, 0x70, 0x76, 0x67} +DEFINE_GUID!{GUID_SLEEP_SUBGROUP, + 0x238c9fa8, 0x0aad, 0x41ed, 0x83, 0xf4, 0x97, 0xbe, 0x24, 0x2c, 0x8f, 0x20} +DEFINE_GUID!{GUID_SLEEP_IDLE_THRESHOLD, + 0x81cd32e0, 0x7833, 0x44f3, 0x87, 0x37, 0x70, 0x81, 0xf3, 0x8d, 0x1f, 0x70} +DEFINE_GUID!{GUID_STANDBY_TIMEOUT, + 0x29f6c1db, 0x86da, 0x48c5, 0x9f, 0xdb, 0xf2, 0xb6, 0x7b, 0x1f, 0x44, 0xda} +DEFINE_GUID!{GUID_UNATTEND_SLEEP_TIMEOUT, + 0x7bc4a2f9, 0xd8fc, 0x4469, 0xb0, 0x7b, 0x33, 0xeb, 0x78, 0x5a, 0xac, 0xa0} +DEFINE_GUID!{GUID_HIBERNATE_TIMEOUT, + 0x9d7815a6, 0x7ee4, 0x497e, 0x88, 0x88, 0x51, 0x5a, 0x05, 0xf0, 0x23, 0x64} +DEFINE_GUID!{GUID_HIBERNATE_FASTS4_POLICY, + 0x94ac6d29, 0x73ce, 0x41a6, 0x80, 0x9f, 0x63, 0x63, 0xba, 0x21, 0xb4, 0x7e} +DEFINE_GUID!{GUID_CRITICAL_POWER_TRANSITION, + 0xb7a27025, 0xe569, 0x46c2, 0xa5, 0x04, 0x2b, 0x96, 0xca, 0xd2, 0x25, 0xa1} +DEFINE_GUID!{GUID_SYSTEM_AWAYMODE, + 0x98a7f580, 0x01f7, 0x48aa, 0x9c, 0x0f, 0x44, 0x35, 0x2c, 0x29, 0xe5, 0xc0} +DEFINE_GUID!{GUID_ALLOW_AWAYMODE, + 0x25dfa149, 0x5dd1, 0x4736, 0xb5, 0xab, 0xe8, 0xa3, 0x7b, 0x5b, 0x81, 0x87} +DEFINE_GUID!{GUID_USER_PRESENCE_PREDICTION, + 0x82011705, 0xfb95, 0x4d46, 0x8d, 0x35, 0x40, 0x42, 0xb1, 0xd2, 0xd, 0xef} +DEFINE_GUID!{GUID_STANDBY_BUDGET_GRACE_PERIOD, + 0x60c07fe1, 0x0556, 0x45cf, 0x99, 0x03, 0xd5, 0x6e, 0x32, 0x21, 0x2, 0x42} +DEFINE_GUID!{GUID_STANDBY_BUDGET_PERCENT, + 0x9fe527be, 0x1b70, 0x48da, 0x93, 0x0d, 0x7b, 0xcf, 0x17, 0xb4, 0x49, 0x90} +DEFINE_GUID!{GUID_STANDBY_RESERVE_GRACE_PERIOD, + 0xc763ee92, 0x71e8, 0x4127, 0x84, 0xeb, 0xf6, 0xed, 0x04, 0x3a, 0x3e, 0x3d} +DEFINE_GUID!{GUID_STANDBY_RESERVE_TIME, + 0x468fe7e5, 0x1158, 0x46ec, 0x88, 0xbc, 0x5b, 0x96, 0xc9, 0xe4, 0x4f, 0xd0} +DEFINE_GUID!{GUID_STANDBY_RESET_PERCENT, + 0x49cb11a5, 0x56e2, 0x4afb, 0x9d, 0x38, 0x3d, 0xf4, 0x78, 0x72, 0xe2, 0x1b} +DEFINE_GUID!{GUID_ALLOW_STANDBY_STATES, + 0xabfc2519, 0x3608, 0x4c2a, 0x94, 0xea, 0x17, 0x1b, 0x0e, 0xd5, 0x46, 0xab} +DEFINE_GUID!{GUID_ALLOW_RTC_WAKE, + 0xbd3b718a, 0x0680, 0x4d9d, 0x8a, 0xb2, 0xe1, 0xd2, 0xb4, 0xac, 0x80, 0x6d} +DEFINE_GUID!{GUID_ALLOW_SYSTEM_REQUIRED, + 0xa4b195f5, 0x8225, 0x47d8, 0x80, 0x12, 0x9d, 0x41, 0x36, 0x97, 0x86, 0xe2} +DEFINE_GUID!{GUID_POWER_SAVING_STATUS, + 0xe00958c0, 0xc213, 0x4ace, 0xac, 0x77, 0xfe, 0xcc, 0xed, 0x2e, 0xee, 0xa5} +DEFINE_GUID!{GUID_ENERGY_SAVER_SUBGROUP, + 0xde830923, 0xa562, 0x41af, 0xa0, 0x86, 0xe3, 0xa2, 0xc6, 0xba, 0xd2, 0xda} +DEFINE_GUID!{GUID_ENERGY_SAVER_BATTERY_THRESHOLD, + 0xe69653ca, 0xcf7f, 0x4f05, 0xaa, 0x73, 0xcb, 0x83, 0x3f, 0xa9, 0x0a, 0xd4} +DEFINE_GUID!{GUID_ENERGY_SAVER_BRIGHTNESS, + 0x13d09884, 0xf74e, 0x474a, 0xa8, 0x52, 0xb6, 0xbd, 0xe8, 0xad, 0x03, 0xa8} +DEFINE_GUID!{GUID_ENERGY_SAVER_POLICY, + 0x5c5bb349, 0xad29, 0x4ee2, 0x9d, 0xb, 0x2b, 0x25, 0x27, 0xf, 0x7a, 0x81} +DEFINE_GUID!{GUID_SYSTEM_BUTTON_SUBGROUP, + 0x4f971e89, 0xeebd, 0x4455, 0xa8, 0xde, 0x9e, 0x59, 0x04, 0x0e, 0x73, 0x47} +pub const POWERBUTTON_ACTION_INDEX_NOTHING: DWORD = 0; +pub const POWERBUTTON_ACTION_INDEX_SLEEP: DWORD = 1; +pub const POWERBUTTON_ACTION_INDEX_HIBERNATE: DWORD = 2; +pub const POWERBUTTON_ACTION_INDEX_SHUTDOWN: DWORD = 3; +pub const POWERBUTTON_ACTION_INDEX_TURN_OFF_THE_DISPLAY: DWORD = 4; +pub const POWERBUTTON_ACTION_VALUE_NOTHING: DWORD = 0; +pub const POWERBUTTON_ACTION_VALUE_SLEEP: DWORD = 2; +pub const POWERBUTTON_ACTION_VALUE_HIBERNATE: DWORD = 3; +pub const POWERBUTTON_ACTION_VALUE_SHUTDOWN: DWORD = 6; +pub const POWERBUTTON_ACTION_VALUE_TURN_OFF_THE_DISPLAY: DWORD = 8; +DEFINE_GUID!{GUID_POWERBUTTON_ACTION, + 0x7648efa3, 0xdd9c, 0x4e3e, 0xb5, 0x66, 0x50, 0xf9, 0x29, 0x38, 0x62, 0x80} +DEFINE_GUID!{GUID_SLEEPBUTTON_ACTION, + 0x96996bc0, 0xad50, 0x47ec, 0x92, 0x3b, 0x6f, 0x41, 0x87, 0x4d, 0xd9, 0xeb} +DEFINE_GUID!{GUID_USERINTERFACEBUTTON_ACTION, + 0xa7066653, 0x8d6c, 0x40a8, 0x91, 0x0e, 0xa1, 0xf5, 0x4b, 0x84, 0xc7, 0xe5} +DEFINE_GUID!{GUID_LIDCLOSE_ACTION, + 0x5ca83367, 0x6e45, 0x459f, 0xa2, 0x7b, 0x47, 0x6b, 0x1d, 0x01, 0xc9, 0x36} +DEFINE_GUID!{GUID_LIDOPEN_POWERSTATE, + 0x99ff10e7, 0x23b1, 0x4c07, 0xa9, 0xd1, 0x5c, 0x32, 0x06, 0xd7, 0x41, 0xb4} +DEFINE_GUID!{GUID_BATTERY_SUBGROUP, + 0xe73a048d, 0xbf27, 0x4f12, 0x97, 0x31, 0x8b, 0x20, 0x76, 0xe8, 0x89, 0x1f} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_ACTION_0, + 0x637ea02f, 0xbbcb, 0x4015, 0x8e, 0x2c, 0xa1, 0xc7, 0xb9, 0xc0, 0xb5, 0x46} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_LEVEL_0, + 0x9a66d8d7, 0x4ff7, 0x4ef9, 0xb5, 0xa2, 0x5a, 0x32, 0x6c, 0xa2, 0xa4, 0x69} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_FLAGS_0, + 0x5dbb7c9f, 0x38e9, 0x40d2, 0x97, 0x49, 0x4f, 0x8a, 0x0e, 0x9f, 0x64, 0x0f} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_ACTION_1, + 0xd8742dcb, 0x3e6a, 0x4b3c, 0xb3, 0xfe, 0x37, 0x46, 0x23, 0xcd, 0xcf, 0x06} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_LEVEL_1, + 0x8183ba9a, 0xe910, 0x48da, 0x87, 0x69, 0x14, 0xae, 0x6d, 0xc1, 0x17, 0x0a} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_FLAGS_1, + 0xbcded951, 0x187b, 0x4d05, 0xbc, 0xcc, 0xf7, 0xe5, 0x19, 0x60, 0xc2, 0x58} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_ACTION_2, + 0x421cba38, 0x1a8e, 0x4881, 0xac, 0x89, 0xe3, 0x3a, 0x8b, 0x04, 0xec, 0xe4} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_LEVEL_2, + 0x07a07ca2, 0xadaf, 0x40d7, 0xb0, 0x77, 0x53, 0x3a, 0xad, 0xed, 0x1b, 0xfa} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_FLAGS_2, + 0x7fd2f0c4, 0xfeb7, 0x4da3, 0x81, 0x17, 0xe3, 0xfb, 0xed, 0xc4, 0x65, 0x82} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_ACTION_3, + 0x80472613, 0x9780, 0x455e, 0xb3, 0x08, 0x72, 0xd3, 0x00, 0x3c, 0xf2, 0xf8} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_LEVEL_3, + 0x58afd5a6, 0xc2dd, 0x47d2, 0x9f, 0xbf, 0xef, 0x70, 0xcc, 0x5c, 0x59, 0x65} +DEFINE_GUID!{GUID_BATTERY_DISCHARGE_FLAGS_3, + 0x73613ccf, 0xdbfa, 0x4279, 0x83, 0x56, 0x49, 0x35, 0xf6, 0xbf, 0x62, 0xf3} +DEFINE_GUID!{GUID_PROCESSOR_SETTINGS_SUBGROUP, + 0x54533251, 0x82be, 0x4824, 0x96, 0xc1, 0x47, 0xb6, 0x0b, 0x74, 0x0d, 0x00} +DEFINE_GUID!{GUID_PROCESSOR_THROTTLE_POLICY, + 0x57027304, 0x4af6, 0x4104, 0x92, 0x60, 0xe3, 0xd9, 0x52, 0x48, 0xfc, 0x36} +pub const PERFSTATE_POLICY_CHANGE_IDEAL: DWORD = 0; +pub const PERFSTATE_POLICY_CHANGE_SINGLE: DWORD = 1; +pub const PERFSTATE_POLICY_CHANGE_ROCKET: DWORD = 2; +pub const PERFSTATE_POLICY_CHANGE_IDEAL_AGGRESSIVE: DWORD = 3; +pub const PERFSTATE_POLICY_CHANGE_DECREASE_MAX: DWORD = PERFSTATE_POLICY_CHANGE_ROCKET; +pub const PERFSTATE_POLICY_CHANGE_INCREASE_MAX: DWORD = PERFSTATE_POLICY_CHANGE_IDEAL_AGGRESSIVE; +DEFINE_GUID!{GUID_PROCESSOR_THROTTLE_MAXIMUM, + 0xbc5038f7, 0x23e0, 0x4960, 0x96, 0xda, 0x33, 0xab, 0xaf, 0x59, 0x35, 0xec} +DEFINE_GUID!{GUID_PROCESSOR_THROTTLE_MAXIMUM_1, + 0xbc5038f7, 0x23e0, 0x4960, 0x96, 0xda, 0x33, 0xab, 0xaf, 0x59, 0x35, 0xed} +DEFINE_GUID!{GUID_PROCESSOR_THROTTLE_MINIMUM, + 0x893dee8e, 0x2bef, 0x41e0, 0x89, 0xc6, 0xb5, 0x5d, 0x09, 0x29, 0x96, 0x4c} +DEFINE_GUID!{GUID_PROCESSOR_THROTTLE_MINIMUM_1, + 0x893dee8e, 0x2bef, 0x41e0, 0x89, 0xc6, 0xb5, 0x5d, 0x09, 0x29, 0x96, 0x4d} +DEFINE_GUID!{GUID_PROCESSOR_FREQUENCY_LIMIT, + 0x75b0ae3f, 0xbce0, 0x45a7, 0x8c, 0x89, 0xc9, 0x61, 0x1c, 0x25, 0xe1, 0x00} +DEFINE_GUID!{GUID_PROCESSOR_FREQUENCY_LIMIT_1, + 0x75b0ae3f, 0xbce0, 0x45a7, 0x8c, 0x89, 0xc9, 0x61, 0x1c, 0x25, 0xe1, 0x01} +DEFINE_GUID!{GUID_PROCESSOR_ALLOW_THROTTLING, + 0x3b04d4fd, 0x1cc7, 0x4f23, 0xab, 0x1c, 0xd1, 0x33, 0x78, 0x19, 0xc4, 0xbb} +pub const PROCESSOR_THROTTLE_DISABLED: DWORD = 0; +pub const PROCESSOR_THROTTLE_ENABLED: DWORD = 1; +pub const PROCESSOR_THROTTLE_AUTOMATIC: DWORD = 2; +DEFINE_GUID!{GUID_PROCESSOR_IDLESTATE_POLICY, + 0x68f262a7, 0xf621, 0x4069, 0xb9, 0xa5, 0x48, 0x74, 0x16, 0x9b, 0xe2, 0x3c} +DEFINE_GUID!{GUID_PROCESSOR_PERFSTATE_POLICY, + 0xbbdc3814, 0x18e9, 0x4463, 0x8a, 0x55, 0xd1, 0x97, 0x32, 0x7c, 0x45, 0xc0} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_THRESHOLD, + 0x06cadf0e, 0x64ed, 0x448a, 0x89, 0x27, 0xce, 0x7b, 0xf9, 0x0e, 0xb3, 0x5d} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_THRESHOLD_1, + 0x06cadf0e, 0x64ed, 0x448a, 0x89, 0x27, 0xce, 0x7b, 0xf9, 0x0e, 0xb3, 0x5e} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_THRESHOLD, + 0x12a0ab44, 0xfe28, 0x4fa9, 0xb3, 0xbd, 0x4b, 0x64, 0xf4, 0x49, 0x60, 0xa6} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_THRESHOLD_1, + 0x12a0ab44, 0xfe28, 0x4fa9, 0xb3, 0xbd, 0x4b, 0x64, 0xf4, 0x49, 0x60, 0xa7} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_POLICY, + 0x465e1f50, 0xb610, 0x473a, 0xab, 0x58, 0x0, 0xd1, 0x7, 0x7d, 0xc4, 0x18} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_POLICY_1, + 0x465e1f50, 0xb610, 0x473a, 0xab, 0x58, 0x0, 0xd1, 0x7, 0x7d, 0xc4, 0x19} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_POLICY, + 0x40fbefc7, 0x2e9d, 0x4d25, 0xa1, 0x85, 0xc, 0xfd, 0x85, 0x74, 0xba, 0xc6} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_POLICY_1, + 0x40fbefc7, 0x2e9d, 0x4d25, 0xa1, 0x85, 0xc, 0xfd, 0x85, 0x74, 0xba, 0xc7} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_TIME, + 0x984cf492, 0x3bed, 0x4488, 0xa8, 0xf9, 0x42, 0x86, 0xc9, 0x7b, 0xf5, 0xaa} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_TIME_1, + 0x984cf492, 0x3bed, 0x4488, 0xa8, 0xf9, 0x42, 0x86, 0xc9, 0x7b, 0xf5, 0xab} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_TIME, + 0xd8edeb9b, 0x95cf, 0x4f95, 0xa7, 0x3c, 0xb0, 0x61, 0x97, 0x36, 0x93, 0xc8} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_TIME_1, + 0xd8edeb9b, 0x95cf, 0x4f95, 0xa7, 0x3c, 0xb0, 0x61, 0x97, 0x36, 0x93, 0xc9} +DEFINE_GUID!{GUID_PROCESSOR_PERF_TIME_CHECK, + 0x4d2b0152, 0x7d5c, 0x498b, 0x88, 0xe2, 0x34, 0x34, 0x53, 0x92, 0xa2, 0xc5} +DEFINE_GUID!{GUID_PROCESSOR_PERF_BOOST_POLICY, + 0x45bcc044, 0xd885, 0x43e2, 0x86, 0x5, 0xee, 0xe, 0xc6, 0xe9, 0x6b, 0x59} +pub const PROCESSOR_PERF_BOOST_POLICY_DISABLED: DWORD = 0; +pub const PROCESSOR_PERF_BOOST_POLICY_MAX: DWORD = 100; +DEFINE_GUID!{GUID_PROCESSOR_PERF_BOOST_MODE, + 0xbe337238, 0xd82, 0x4146, 0xa9, 0x60, 0x4f, 0x37, 0x49, 0xd4, 0x70, 0xc7} +pub const PROCESSOR_PERF_BOOST_MODE_DISABLED: DWORD = 0; +pub const PROCESSOR_PERF_BOOST_MODE_ENABLED: DWORD = 1; +pub const PROCESSOR_PERF_BOOST_MODE_AGGRESSIVE: DWORD = 2; +pub const PROCESSOR_PERF_BOOST_MODE_EFFICIENT_ENABLED: DWORD = 3; +pub const PROCESSOR_PERF_BOOST_MODE_EFFICIENT_AGGRESSIVE: DWORD = 4; +pub const PROCESSOR_PERF_BOOST_MODE_AGGRESSIVE_AT_GUARANTEED: DWORD = 5; +pub const PROCESSOR_PERF_BOOST_MODE_EFFICIENT_AGGRESSIVE_AT_GUARANTEED: DWORD = 6; +pub const PROCESSOR_PERF_BOOST_MODE_MAX: DWORD + = PROCESSOR_PERF_BOOST_MODE_EFFICIENT_AGGRESSIVE_AT_GUARANTEED; +DEFINE_GUID!{GUID_PROCESSOR_PERF_AUTONOMOUS_MODE, + 0x8baa4a8a, 0x14c6, 0x4451, 0x8e, 0x8b, 0x14, 0xbd, 0xbd, 0x19, 0x75, 0x37} +pub const PROCESSOR_PERF_AUTONOMOUS_MODE_DISABLED: DWORD = 0; +pub const PROCESSOR_PERF_AUTONOMOUS_MODE_ENABLED: DWORD = 1; +DEFINE_GUID!{GUID_PROCESSOR_PERF_ENERGY_PERFORMANCE_PREFERENCE, + 0x36687f9e, 0xe3a5, 0x4dbf, 0xb1, 0xdc, 0x15, 0xeb, 0x38, 0x1c, 0x68, 0x63} +pub const PROCESSOR_PERF_PERFORMANCE_PREFERENCE: DWORD = 0xff; +pub const PROCESSOR_PERF_ENERGY_PREFERENCE: DWORD = 0; +DEFINE_GUID!{GUID_PROCESSOR_PERF_AUTONOMOUS_ACTIVITY_WINDOW, + 0xcfeda3d0, 0x7697, 0x4566, 0xa9, 0x22, 0xa9, 0x8, 0x6c, 0xd4, 0x9d, 0xfa} +pub const PROCESSOR_PERF_MINIMUM_ACTIVITY_WINDOW: DWORD = 0; +pub const PROCESSOR_PERF_MAXIMUM_ACTIVITY_WINDOW: DWORD = 1270000000; +DEFINE_GUID!{GUID_PROCESSOR_DUTY_CYCLING, + 0x4e4450b3, 0x6179, 0x4e91, 0xb8, 0xf1, 0x5b, 0xb9, 0x93, 0x8f, 0x81, 0xa1} +pub const PROCESSOR_DUTY_CYCLING_DISABLED: DWORD = 0; +pub const PROCESSOR_DUTY_CYCLING_ENABLED: DWORD = 1; +DEFINE_GUID!{GUID_PROCESSOR_IDLE_ALLOW_SCALING, + 0x6c2993b0, 0x8f48, 0x481f, 0xbc, 0xc6, 0x0, 0xdd, 0x27, 0x42, 0xaa, 0x6} +DEFINE_GUID!{GUID_PROCESSOR_IDLE_DISABLE, + 0x5d76a2ca, 0xe8c0, 0x402f, 0xa1, 0x33, 0x21, 0x58, 0x49, 0x2d, 0x58, 0xad} +DEFINE_GUID!{GUID_PROCESSOR_IDLE_STATE_MAXIMUM, + 0x9943e905, 0x9a30, 0x4ec1, 0x9b, 0x99, 0x44, 0xdd, 0x3b, 0x76, 0xf7, 0xa2} +DEFINE_GUID!{GUID_PROCESSOR_IDLE_TIME_CHECK, + 0xc4581c31, 0x89ab, 0x4597, 0x8e, 0x2b, 0x9c, 0x9c, 0xab, 0x44, 0xe, 0x6b} +DEFINE_GUID!{GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLD, + 0x4b92d758, 0x5a24, 0x4851, 0xa4, 0x70, 0x81, 0x5d, 0x78, 0xae, 0xe1, 0x19} +DEFINE_GUID!{GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLD, + 0x7b224883, 0xb3cc, 0x4d79, 0x81, 0x9f, 0x83, 0x74, 0x15, 0x2c, 0xbe, 0x7c} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLD, + 0xdf142941, 0x20f3, 0x4edf, 0x9a, 0x4a, 0x9c, 0x83, 0xd3, 0xd7, 0x17, 0xd1} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLD, + 0x68dd2f27, 0xa4ce, 0x4e11, 0x84, 0x87, 0x37, 0x94, 0xe4, 0x13, 0x5d, 0xfa} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICY, + 0xc7be0679, 0x2817, 0x4d69, 0x9d, 0x02, 0x51, 0x9a, 0x53, 0x7e, 0xd0, 0xc6} +pub const CORE_PARKING_POLICY_CHANGE_IDEAL: DWORD = 0; +pub const CORE_PARKING_POLICY_CHANGE_SINGLE: DWORD = 1; +pub const CORE_PARKING_POLICY_CHANGE_ROCKET: DWORD = 2; +pub const CORE_PARKING_POLICY_CHANGE_MULTISTEP: DWORD = 3; +pub const CORE_PARKING_POLICY_CHANGE_MAX: DWORD = CORE_PARKING_POLICY_CHANGE_MULTISTEP; +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICY, + 0x71021b41, 0xc749, 0x4d21, 0xbe, 0x74, 0xa0, 0x0f, 0x33, 0x5d, 0x58, 0x2b} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_MAX_CORES, + 0xea062031, 0x0e34, 0x4ff1, 0x9b, 0x6d, 0xeb, 0x10, 0x59, 0x33, 0x40, 0x28} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_MAX_CORES_1, + 0xea062031, 0x0e34, 0x4ff1, 0x9b, 0x6d, 0xeb, 0x10, 0x59, 0x33, 0x40, 0x29} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_MIN_CORES, + 0x0cc5b647, 0xc1df, 0x4637, 0x89, 0x1a, 0xde, 0xc3, 0x5c, 0x31, 0x85, 0x83} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_MIN_CORES_1, + 0x0cc5b647, 0xc1df, 0x4637, 0x89, 0x1a, 0xde, 0xc3, 0x5c, 0x31, 0x85, 0x84} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_INCREASE_TIME, + 0x2ddd5a84, 0x5a71, 0x437e, 0x91, 0x2a, 0xdb, 0x0b, 0x8c, 0x78, 0x87, 0x32} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_DECREASE_TIME, + 0xdfd10d17, 0xd5eb, 0x45dd, 0x87, 0x7a, 0x9a, 0x34, 0xdd, 0xd1, 0x5c, 0x82} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTOR, + 0x8f7b45e3, 0xc393, 0x480a, 0x87, 0x8c, 0xf6, 0x7a, 0xc3, 0xd0, 0x70, 0x82} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLD, + 0x5b33697b, 0xe89d, 0x4d38, 0xaa, 0x46, 0x9e, 0x7d, 0xfb, 0x7c, 0xd2, 0xf9} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING, + 0xe70867f1, 0xfa2f, 0x4f4e, 0xae, 0xa1, 0x4d, 0x8a, 0x0b, 0xa2, 0x3b, 0x20} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR, + 0x1299023c, 0xbc28, 0x4f0a, 0x81, 0xec, 0xd3, 0x29, 0x5a, 0x8d, 0x81, 0x5d} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD, + 0x9ac18e92, 0xaa3c, 0x4e27, 0xb3, 0x07, 0x01, 0xae, 0x37, 0x30, 0x71, 0x29} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING, + 0x8809c2d8, 0xb155, 0x42d4, 0xbc, 0xda, 0x0d, 0x34, 0x56, 0x51, 0xb1, 0xdb} +DEFINE_GUID!{GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD, + 0x943c8cb6, 0x6f93, 0x4227, 0xad, 0x87, 0xe9, 0xa3, 0xfe, 0xec, 0x08, 0xd1} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_CORE_OVERRIDE, + 0xa55612aa, 0xf624, 0x42c6, 0xa4, 0x43, 0x73, 0x97, 0xd0, 0x64, 0xc0, 0x4f} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_PERF_STATE, + 0x447235c7, 0x6a8d, 0x4cc0, 0x8e, 0x24, 0x9e, 0xaf, 0x70, 0xb9, 0x6e, 0x2b} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_PERF_STATE_1, + 0x447235c7, 0x6a8d, 0x4cc0, 0x8e, 0x24, 0x9e, 0xaf, 0x70, 0xb9, 0x6e, 0x2c} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD, + 0x2430ab6f, 0xa520, 0x44a2, 0x96, 0x01, 0xf7, 0xf2, 0x3b, 0x51, 0x34, 0xb1} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD, + 0xf735a673, 0x2066, 0x4f80, 0xa0, 0xc5, 0xdd, 0xee, 0x0c, 0xf1, 0xbf, 0x5d} +DEFINE_GUID!{GUID_PROCESSOR_PARKING_DISTRIBUTION_THRESHOLD, + 0x4bdaf4e9, 0xd103, 0x46d7, 0xa5, 0xf0, 0x62, 0x80, 0x12, 0x16, 0x16, 0xef} +DEFINE_GUID!{GUID_PROCESSOR_PERF_HISTORY, + 0x7d24baa7, 0x0b84, 0x480f, 0x84, 0x0c, 0x1b, 0x07, 0x43, 0xc0, 0x0f, 0x5f} +DEFINE_GUID!{GUID_PROCESSOR_PERF_HISTORY_1, + 0x7d24baa7, 0x0b84, 0x480f, 0x84, 0x0c, 0x1b, 0x07, 0x43, 0xc0, 0x0f, 0x60} +DEFINE_GUID!{GUID_PROCESSOR_PERF_INCREASE_HISTORY, + 0x99b3ef01, 0x752f, 0x46a1, 0x80, 0xfb, 0x77, 0x30, 0x1, 0x1f, 0x23, 0x54} +DEFINE_GUID!{GUID_PROCESSOR_PERF_DECREASE_HISTORY, + 0x300f6f8, 0xabd6, 0x45a9, 0xb7, 0x4f, 0x49, 0x8, 0x69, 0x1a, 0x40, 0xb5} +DEFINE_GUID!{GUID_PROCESSOR_PERF_CORE_PARKING_HISTORY, + 0x77d7f282, 0x8f1a, 0x42cd, 0x85, 0x37, 0x45, 0x45, 0xa, 0x83, 0x9b, 0xe8} +DEFINE_GUID!{GUID_PROCESSOR_PERF_LATENCY_HINT, + 0x0822df31, 0x9c83, 0x441c, 0xa0, 0x79, 0x0d, 0xe4, 0xcf, 0x00, 0x9c, 0x7b} +DEFINE_GUID!{GUID_PROCESSOR_PERF_LATENCY_HINT_PERF, + 0x619b7505, 0x3b, 0x4e82, 0xb7, 0xa6, 0x4d, 0xd2, 0x9c, 0x30, 0x9, 0x71} +DEFINE_GUID!{GUID_PROCESSOR_PERF_LATENCY_HINT_PERF_1, + 0x619b7505, 0x3b, 0x4e82, 0xb7, 0xa6, 0x4d, 0xd2, 0x9c, 0x30, 0x9, 0x72} +DEFINE_GUID!{GUID_PROCESSOR_LATENCY_HINT_MIN_UNPARK, + 0x616cdaa5, 0x695e, 0x4545, 0x97, 0xad, 0x97, 0xdc, 0x2d, 0x1b, 0xdd, 0x88} +DEFINE_GUID!{GUID_PROCESSOR_LATENCY_HINT_MIN_UNPARK_1, + 0x616cdaa5, 0x695e, 0x4545, 0x97, 0xad, 0x97, 0xdc, 0x2d, 0x1b, 0xdd, 0x89} +DEFINE_GUID!{GUID_PROCESSOR_DISTRIBUTE_UTILITY, + 0xe0007330, 0xf589, 0x42ed, 0xa4, 0x01, 0x5d, 0xdb, 0x10, 0xe7, 0x85, 0xd3} +DEFINE_GUID!{GUID_PROCESSOR_HETEROGENEOUS_POLICY, + 0x7f2f5cfa, 0xf10c, 0x4823, 0xb5, 0xe1, 0xe9, 0x3a, 0xe8, 0x5f, 0x46, 0xb5} +DEFINE_GUID!{GUID_PROCESSOR_HETERO_DECREASE_TIME, + 0x7f2492b6, 0x60b1, 0x45e5, 0xae, 0x55, 0x77, 0x3f, 0x8c, 0xd5, 0xca, 0xec} +DEFINE_GUID!{GUID_PROCESSOR_HETERO_INCREASE_TIME, + 0x4009efa7, 0xe72d, 0x4cba, 0x9e, 0xdf, 0x91, 0x08, 0x4e, 0xa8, 0xcb, 0xc3} +DEFINE_GUID!{GUID_PROCESSOR_HETERO_DECREASE_THRESHOLD, + 0xf8861c27, 0x95e7, 0x475c, 0x86, 0x5b, 0x13, 0xc0, 0xcb, 0x3f, 0x9d, 0x6b} +DEFINE_GUID!{GUID_PROCESSOR_HETERO_INCREASE_THRESHOLD, + 0xb000397d, 0x9b0b, 0x483d, 0x98, 0xc9, 0x69, 0x2a, 0x60, 0x60, 0xcf, 0xbf} +DEFINE_GUID!{GUID_PROCESSOR_CLASS0_FLOOR_PERF, + 0xfddc842b, 0x8364, 0x4edc, 0x94, 0xcf, 0xc1, 0x7f, 0x60, 0xde, 0x1c, 0x80} +DEFINE_GUID!{GUID_PROCESSOR_CLASS1_INITIAL_PERF, + 0x1facfc65, 0xa930, 0x4bc5, 0x9f, 0x38, 0x50, 0x4e, 0xc0, 0x97, 0xbb, 0xc0} +DEFINE_GUID!{GUID_SYSTEM_COOLING_POLICY, + 0x94d3a615, 0xa899, 0x4ac5, 0xae, 0x2b, 0xe4, 0xd8, 0xf6, 0x34, 0x36, 0x7f} +DEFINE_GUID!{GUID_LOCK_CONSOLE_ON_WAKE, + 0x0e796bdb, 0x100d, 0x47d6, 0xa2, 0xd5, 0xf7, 0xd2, 0xda, 0xa5, 0x1f, 0x51} +DEFINE_GUID!{GUID_DEVICE_IDLE_POLICY, + 0x4faab71a, 0x92e5, 0x4726, 0xb5, 0x31, 0x22, 0x45, 0x59, 0x67, 0x2d, 0x19} +pub const POWER_DEVICE_IDLE_POLICY_PERFORMANCE: DWORD = 0; +pub const POWER_DEVICE_IDLE_POLICY_CONSERVATIVE: DWORD = 1; +DEFINE_GUID!{GUID_CONNECTIVITY_IN_STANDBY, + 0xf15576e8, 0x98b7, 0x4186, 0xb9, 0x44, 0xea, 0xfa, 0x66, 0x44, 0x02, 0xd9} +pub const POWER_CONNECTIVITY_IN_STANDBY_DISABLED: DWORD = 0; +pub const POWER_CONNECTIVITY_IN_STANDBY_ENABLED: DWORD = 1; +pub const POWER_CONNECTIVITY_IN_STANDBY_DISABLED_LID_CLOSE: DWORD = 2; +DEFINE_GUID!{GUID_DISCONNECTED_STANDBY_MODE, + 0x68afb2d9, 0xee95, 0x47a8, 0x8f, 0x50, 0x41, 0x15, 0x08, 0x80, 0x73, 0xb1} +pub const POWER_DISCONNECTED_STANDBY_MODE_NORMAL: DWORD = 0; +pub const POWER_DISCONNECTED_STANDBY_MODE_AGGRESSIVE: DWORD = 1; +DEFINE_GUID!{GUID_ACDC_POWER_SOURCE, + 0x5d3e9a59, 0xe9d5, 0x4b00, 0xa6, 0xbd, 0xff, 0x34, 0xff, 0x51, 0x65, 0x48} +DEFINE_GUID!{GUID_LIDSWITCH_STATE_CHANGE, + 0xba3e0f4d, 0xb817, 0x4094, 0xa2, 0xd1, 0xd5, 0x63, 0x79, 0xe6, 0xa0, 0xf3} +DEFINE_GUID!{GUID_BATTERY_PERCENTAGE_REMAINING, + 0xa7ad8041, 0xb45a, 0x4cae, 0x87, 0xa3, 0xee, 0xcb, 0xb4, 0x68, 0xa9, 0xe1} +DEFINE_GUID!{GUID_BATTERY_COUNT, + 0x7d263f15, 0xfca4, 0x49e5, 0x85, 0x4b, 0xa9, 0xf2, 0xbf, 0xbd, 0x5c, 0x24} +DEFINE_GUID!{GUID_GLOBAL_USER_PRESENCE, + 0x786e8a1d, 0xb427, 0x4344, 0x92, 0x7, 0x9, 0xe7, 0xb, 0xdc, 0xbe, 0xa9} +DEFINE_GUID!{GUID_SESSION_DISPLAY_STATUS, + 0x2b84c20e, 0xad23, 0x4ddf, 0x93, 0xdb, 0x5, 0xff, 0xbd, 0x7e, 0xfc, 0xa5} +DEFINE_GUID!{GUID_SESSION_USER_PRESENCE, + 0x3c0f4548, 0xc03f, 0x4c4d, 0xb9, 0xf2, 0x23, 0x7e, 0xde, 0x68, 0x63, 0x76} +DEFINE_GUID!{GUID_IDLE_BACKGROUND_TASK, + 0x515c31d8, 0xf734, 0x163d, 0xa0, 0xfd, 0x11, 0xa0, 0x8c, 0x91, 0xe8, 0xf1} +DEFINE_GUID!{GUID_BACKGROUND_TASK_NOTIFICATION, + 0xcf23f240, 0x2a54, 0x48d8, 0xb1, 0x14, 0xde, 0x15, 0x18, 0xff, 0x05, 0x2e} +DEFINE_GUID!{GUID_APPLAUNCH_BUTTON, + 0x1a689231, 0x7399, 0x4e9a, 0x8f, 0x99, 0xb7, 0x1f, 0x99, 0x9d, 0xb3, 0xfa} +DEFINE_GUID!{GUID_PCIEXPRESS_SETTINGS_SUBGROUP, + 0x501a4d13, 0x42af,0x4429, 0x9f, 0xd1, 0xa8, 0x21, 0x8c, 0x26, 0x8e, 0x20} +DEFINE_GUID!{GUID_PCIEXPRESS_ASPM_POLICY, + 0xee12f906, 0xd277, 0x404b, 0xb6, 0xda, 0xe5, 0xfa, 0x1a, 0x57, 0x6d, 0xf5} +DEFINE_GUID!{GUID_ENABLE_SWITCH_FORCED_SHUTDOWN, + 0x833a6b62, 0xdfa4, 0x46d1, 0x82, 0xf8, 0xe0, 0x9e, 0x34, 0xd0, 0x29, 0xd6} +DEFINE_GUID!{GUID_INTSTEER_SUBGROUP, + 0x48672f38, 0x7a9a, 0x4bb2, 0x8b, 0xf8, 0x3d, 0x85, 0xbe, 0x19, 0xde, 0x4e} +DEFINE_GUID!{GUID_INTSTEER_MODE, + 0x2bfc24f9, 0x5ea2, 0x4801, 0x82, 0x13, 0x3d, 0xba, 0xe0, 0x1a, 0xa3, 0x9d} +DEFINE_GUID!{GUID_INTSTEER_LOAD_PER_PROC_TRIGGER, + 0x73cde64d, 0xd720, 0x4bb2, 0xa8, 0x60, 0xc7, 0x55, 0xaf, 0xe7, 0x7e, 0xf2} +DEFINE_GUID!{GUID_INTSTEER_TIME_UNPARK_TRIGGER, + 0xd6ba4903, 0x386f, 0x4c2c, 0x8a, 0xdb, 0x5c, 0x21, 0xb3, 0x32, 0x8d, 0x25} +ENUM!{enum SYSTEM_POWER_STATE { + PowerSystemUnspecified = 0, + PowerSystemWorking = 1, + PowerSystemSleeping1 = 2, + PowerSystemSleeping2 = 3, + PowerSystemSleeping3 = 4, + PowerSystemHibernate = 5, + PowerSystemShutdown = 6, + PowerSystemMaximum = 7, +}} +pub type PSYSTEM_POWER_STATE = *mut SYSTEM_POWER_STATE; +pub const POWER_SYSTEM_MAXIMUM: usize = 7; +ENUM!{enum POWER_ACTION { + PowerActionNone = 0, + PowerActionReserved, + PowerActionSleep, + PowerActionHibernate, + PowerActionShutdown, + PowerActionShutdownReset, + PowerActionShutdownOff, + PowerActionWarmEject, + PowerActionDisplayOff, +}} +pub type PPOWER_ACTION = *mut POWER_ACTION; +ENUM!{enum DEVICE_POWER_STATE { + PowerDeviceUnspecified = 0, + PowerDeviceD0, + PowerDeviceD1, + PowerDeviceD2, + PowerDeviceD3, + PowerDeviceMaximum, +}} +pub type PDEVICE_POWER_STATE = *mut DEVICE_POWER_STATE; +ENUM!{enum MONITOR_DISPLAY_STATE { + PowerMonitorOff = 0, + PowerMonitorOn, + PowerMonitorDim, +}} +pub type PMONITOR_DISPLAY_STATE = *mut MONITOR_DISPLAY_STATE; +ENUM!{enum USER_ACTIVITY_PRESENCE { + PowerUserPresent = 0, + PowerUserNotPresent, + PowerUserInactive, + PowerUserMaximum, + PowerUserInvalid = PowerUserMaximum, +}} +pub type PUSER_ACTIVITY_PRESENCE = *mut USER_ACTIVITY_PRESENCE; +pub const ES_SYSTEM_REQUIRED: DWORD = 0x00000001; +pub const ES_DISPLAY_REQUIRED: DWORD = 0x00000002; +pub const ES_USER_PRESENT: DWORD = 0x00000004; +pub const ES_AWAYMODE_REQUIRED: DWORD = 0x00000040; +pub const ES_CONTINUOUS: DWORD = 0x80000000; +pub type EXECUTION_STATE = DWORD; +pub type PEXECUTION_STATE = *mut DWORD; +ENUM!{enum LATENCY_TIME { + LT_DONT_CARE, + LT_LOWEST_LATENCY, +}} +pub const DIAGNOSTIC_REASON_VERSION: ULONG = 0; +pub const DIAGNOSTIC_REASON_SIMPLE_STRING: ULONG = 0x00000001; +pub const DIAGNOSTIC_REASON_DETAILED_STRING: ULONG = 0x00000002; +pub const DIAGNOSTIC_REASON_NOT_SPECIFIED: ULONG = 0x80000000; +pub const DIAGNOSTIC_REASON_INVALID_FLAGS: ULONG = !0x80000007; +pub const POWER_REQUEST_CONTEXT_VERSION: ULONG = DIAGNOSTIC_REASON_VERSION; +pub const POWER_REQUEST_CONTEXT_SIMPLE_STRING: ULONG = DIAGNOSTIC_REASON_SIMPLE_STRING; +pub const POWER_REQUEST_CONTEXT_DETAILED_STRING: ULONG = DIAGNOSTIC_REASON_DETAILED_STRING; +ENUM!{enum POWER_REQUEST_TYPE { + PowerRequestDisplayRequired, + PowerRequestSystemRequired, + PowerRequestAwayModeRequired, + PowerRequestExecutionRequired, +}} +pub type PPOWER_REQUEST_TYPE = *mut POWER_REQUEST_TYPE; +pub const PDCAP_D0_SUPPORTED: DWORD = 0x00000001; +pub const PDCAP_D1_SUPPORTED: DWORD = 0x00000002; +pub const PDCAP_D2_SUPPORTED: DWORD = 0x00000004; +pub const PDCAP_D3_SUPPORTED: DWORD = 0x00000008; +pub const PDCAP_WAKE_FROM_D0_SUPPORTED: DWORD = 0x00000010; +pub const PDCAP_WAKE_FROM_D1_SUPPORTED: DWORD = 0x00000020; +pub const PDCAP_WAKE_FROM_D2_SUPPORTED: DWORD = 0x00000040; +pub const PDCAP_WAKE_FROM_D3_SUPPORTED: DWORD = 0x00000080; +pub const PDCAP_WARM_EJECT_SUPPORTED: DWORD = 0x00000100; +STRUCT!{struct CM_POWER_DATA { + PD_Size: DWORD, + PD_MostRecentPowerState: DEVICE_POWER_STATE, + PD_Capabilities: DWORD, + PD_D1Latency: DWORD, + PD_D2Latency: DWORD, + PD_D3Latency: DWORD, + PD_PowerStateMapping: [DEVICE_POWER_STATE; POWER_SYSTEM_MAXIMUM], + PD_DeepestSystemWake: SYSTEM_POWER_STATE, +}} +pub type PCM_POWER_DATA = *mut CM_POWER_DATA; +ENUM!{enum POWER_INFORMATION_LEVEL { + SystemPowerPolicyAc, + SystemPowerPolicyDc, + VerifySystemPolicyAc, + VerifySystemPolicyDc, + SystemPowerCapabilities, + SystemBatteryState, + SystemPowerStateHandler, + ProcessorStateHandler, + SystemPowerPolicyCurrent, + AdministratorPowerPolicy, + SystemReserveHiberFile, + ProcessorInformation, + SystemPowerInformation, + ProcessorStateHandler2, + LastWakeTime, + LastSleepTime, + SystemExecutionState, + SystemPowerStateNotifyHandler, + ProcessorPowerPolicyAc, + ProcessorPowerPolicyDc, + VerifyProcessorPowerPolicyAc, + VerifyProcessorPowerPolicyDc, + ProcessorPowerPolicyCurrent, + SystemPowerStateLogging, + SystemPowerLoggingEntry, + SetPowerSettingValue, + NotifyUserPowerSetting, + PowerInformationLevelUnused0, + SystemMonitorHiberBootPowerOff, + SystemVideoState, + TraceApplicationPowerMessage, + TraceApplicationPowerMessageEnd, + ProcessorPerfStates, + ProcessorIdleStates, + ProcessorCap, + SystemWakeSource, + SystemHiberFileInformation, + TraceServicePowerMessage, + ProcessorLoad, + PowerShutdownNotification, + MonitorCapabilities, + SessionPowerInit, + SessionDisplayState, + PowerRequestCreate, + PowerRequestAction, + GetPowerRequestList, + ProcessorInformationEx, + NotifyUserModeLegacyPowerEvent, + GroupPark, + ProcessorIdleDomains, + WakeTimerList, + SystemHiberFileSize, + ProcessorIdleStatesHv, + ProcessorPerfStatesHv, + ProcessorPerfCapHv, + ProcessorSetIdle, + LogicalProcessorIdling, + UserPresence, + PowerSettingNotificationName, + GetPowerSettingValue, + IdleResiliency, + SessionRITState, + SessionConnectNotification, + SessionPowerCleanup, + SessionLockState, + SystemHiberbootState, + PlatformInformation, + PdcInvocation, + MonitorInvocation, + FirmwareTableInformationRegistered, + SetShutdownSelectedTime, + SuspendResumeInvocation, + PlmPowerRequestCreate, + ScreenOff, + CsDeviceNotification, + PlatformRole, + LastResumePerformance, + DisplayBurst, + ExitLatencySamplingPercentage, + RegisterSpmPowerSettings, + PlatformIdleStates, + ProcessorIdleVeto, + PlatformIdleVeto, + SystemBatteryStatePrecise, + ThermalEvent, + PowerRequestActionInternal, + BatteryDeviceState, + PowerInformationInternal, + ThermalStandby, + SystemHiberFileType, + PhysicalPowerButtonPress, + QueryPotentialDripsConstraint, + EnergyTrackerCreate, + EnergyTrackerQuery, + UpdateBlackBoxRecorder, + PowerInformationLevelMaximum, +}} +ENUM!{enum POWER_USER_PRESENCE_TYPE { + UserNotPresent = 0, + UserPresent = 1, + UserUnknown = 0xff, +}} +pub type PPOWER_USER_PRESENCE_TYPE = *mut POWER_USER_PRESENCE_TYPE; +STRUCT!{struct POWER_USER_PRESENCE { + UserPresence: POWER_USER_PRESENCE_TYPE, +}} +pub type PPOWER_USER_PRESENCE = *mut POWER_USER_PRESENCE; +STRUCT!{struct POWER_SESSION_CONNECT { + Connected: BOOLEAN, + Console: BOOLEAN, +}} +pub type PPOWER_SESSION_CONNECT = *mut POWER_SESSION_CONNECT; +STRUCT!{struct POWER_SESSION_TIMEOUTS { + InputTimeout: DWORD, + DisplayTimeout: DWORD, +}} +pub type PPOWER_SESSION_TIMEOUTS = *mut POWER_SESSION_TIMEOUTS; +STRUCT!{struct POWER_SESSION_RIT_STATE { + Active: BOOLEAN, + LastInputTime: DWORD, +}} +pub type PPOWER_SESSION_RIT_STATE = *mut POWER_SESSION_RIT_STATE; +STRUCT!{struct POWER_SESSION_WINLOGON { + SessionId: DWORD, + Console: BOOLEAN, + Locked: BOOLEAN, +}} +pub type PPOWER_SESSION_WINLOGON = *mut POWER_SESSION_WINLOGON; +STRUCT!{struct POWER_IDLE_RESILIENCY { + CoalescingTimeout: DWORD, + IdleResiliencyPeriod: DWORD, +}} +pub type PPOWER_IDLE_RESILIENCY = *mut POWER_IDLE_RESILIENCY; +ENUM!{enum POWER_MONITOR_REQUEST_REASON { + MonitorRequestReasonUnknown, + MonitorRequestReasonPowerButton, + MonitorRequestReasonRemoteConnection, + MonitorRequestReasonScMonitorpower, + MonitorRequestReasonUserInput, + MonitorRequestReasonAcDcDisplayBurst, + MonitorRequestReasonUserDisplayBurst, + MonitorRequestReasonPoSetSystemState, + MonitorRequestReasonSetThreadExecutionState, + MonitorRequestReasonFullWake, + MonitorRequestReasonSessionUnlock, + MonitorRequestReasonScreenOffRequest, + MonitorRequestReasonIdleTimeout, + MonitorRequestReasonPolicyChange, + MonitorRequestReasonSleepButton, + MonitorRequestReasonLid, + MonitorRequestReasonBatteryCountChange, + MonitorRequestReasonGracePeriod, + MonitorRequestReasonPnP, + MonitorRequestReasonDP, + MonitorRequestReasonSxTransition, + MonitorRequestReasonSystemIdle, + MonitorRequestReasonNearProximity, + MonitorRequestReasonThermalStandby, + MonitorRequestReasonResumePdc, + MonitorRequestReasonResumeS4, + MonitorRequestReasonTerminal, + MonitorRequestReasonPdcSignal, + MonitorRequestReasonAcDcDisplayBurstSuppressed, + MonitorRequestReasonSystemStateEntered, + MonitorRequestReasonWinrt, + MonitorRequestReasonMax, +}} +ENUM!{enum POWER_MONITOR_REQUEST_TYPE { + MonitorRequestTypeOff, + MonitorRequestTypeOnAndPresent, + MonitorRequestTypeToggleOn, +}} +STRUCT!{struct POWER_MONITOR_INVOCATION { + Console: BOOLEAN, + RequestReason: POWER_MONITOR_REQUEST_REASON, +}} +pub type PPOWER_MONITOR_INVOCATION = *mut POWER_MONITOR_INVOCATION; +STRUCT!{struct RESUME_PERFORMANCE { + PostTimeMs: DWORD, + TotalResumeTimeMs: ULONGLONG, + ResumeCompleteTimestamp: ULONGLONG, +}} +pub type PRESUME_PERFORMANCE = *mut RESUME_PERFORMANCE; +ENUM!{enum SYSTEM_POWER_CONDITION { + PoAc, + PoDc, + PoHot, + PoConditionMaximum, +}} +STRUCT!{struct SET_POWER_SETTING_VALUE { + Version: DWORD, + Guid: GUID, + PowerCondition: SYSTEM_POWER_CONDITION, + DataLength: DWORD, + Data: [BYTE; ANYSIZE_ARRAY], +}} +pub type PSET_POWER_SETTING_VALUE = *mut SET_POWER_SETTING_VALUE; +STRUCT!{struct NOTIFY_USER_POWER_SETTING { + Guid: GUID, +}} +pub type PNOTIFY_USER_POWER_SETTING = *mut NOTIFY_USER_POWER_SETTING; +STRUCT!{struct APPLICATIONLAUNCH_SETTING_VALUE { + ActivationTime: LARGE_INTEGER, + Flags: DWORD, + ButtonInstanceID: DWORD, +}} +pub type PAPPLICATIONLAUNCH_SETTING_VALUE = *mut APPLICATIONLAUNCH_SETTING_VALUE; +ENUM!{enum POWER_PLATFORM_ROLE { + PlatformRoleUnspecified = 0, + PlatformRoleDesktop, + PlatformRoleMobile, + PlatformRoleWorkstation, + PlatformRoleEnterpriseServer, + PlatformRoleSOHOServer, + PlatformRoleAppliancePC, + PlatformRolePerformanceServer, + PlatformRoleSlate, + PlatformRoleMaximum, +}} +pub type PPOWER_PLATFORM_ROLE = *mut POWER_PLATFORM_ROLE; +pub const POWER_PLATFORM_ROLE_V1: ULONG = 0x00000001; +pub const POWER_PLATFORM_ROLE_V1_MAX: POWER_PLATFORM_ROLE = PlatformRolePerformanceServer + 1; +pub const POWER_PLATFORM_ROLE_V2: ULONG = 0x00000002; +pub const POWER_PLATFORM_ROLE_V2_MAX: POWER_PLATFORM_ROLE = PlatformRoleSlate + 1; +pub const POWER_PLATFORM_ROLE_VERSION: ULONG = POWER_PLATFORM_ROLE_V2; +pub const POWER_PLATFORM_ROLE_VERSION_MAX: POWER_PLATFORM_ROLE = POWER_PLATFORM_ROLE_V2_MAX; +STRUCT!{struct POWER_PLATFORM_INFORMATION { + AoAc: BOOLEAN, +}} +pub type PPOWER_PLATFORM_INFORMATION = *mut POWER_PLATFORM_INFORMATION; +STRUCT!{struct BATTERY_REPORTING_SCALE { + Granularity: DWORD, + Capacity: DWORD, +}} +pub type PBATTERY_REPORTING_SCALE = *mut BATTERY_REPORTING_SCALE; +STRUCT!{struct PPM_WMI_LEGACY_PERFSTATE { + Frequency: DWORD, + Flags: DWORD, + PercentFrequency: DWORD, +}} +pub type PPPM_WMI_LEGACY_PERFSTATE = *mut PPM_WMI_LEGACY_PERFSTATE; +STRUCT!{struct PPM_WMI_IDLE_STATE { + Latency: DWORD, + Power: DWORD, + TimeCheck: DWORD, + PromotePercent: BYTE, + DemotePercent: BYTE, + StateType: BYTE, + Reserved: BYTE, + StateFlags: DWORD, + Context: DWORD, + IdleHandler: DWORD, + Reserved1: DWORD, +}} +pub type PPPM_WMI_IDLE_STATE = *mut PPM_WMI_IDLE_STATE; +STRUCT!{struct PPM_WMI_IDLE_STATES { + Type: DWORD, + Count: DWORD, + TargetState: DWORD, + OldState: DWORD, + TargetProcessors: DWORD64, + State: [PPM_WMI_IDLE_STATE; ANYSIZE_ARRAY], +}} +pub type PPPM_WMI_IDLE_STATES = *mut PPM_WMI_IDLE_STATES; +STRUCT!{struct PPM_WMI_IDLE_STATES_EX { + Type: DWORD, + Count: DWORD, + TargetState: DWORD, + OldState: DWORD, + TargetProcessors: PVOID, + State: [PPM_WMI_IDLE_STATE; ANYSIZE_ARRAY], +}} +pub type PPPM_WMI_IDLE_STATES_EX = *mut PPM_WMI_IDLE_STATES_EX; +STRUCT!{struct PPM_WMI_PERF_STATE { + Frequency: DWORD, + Power: DWORD, + PercentFrequency: BYTE, + IncreaseLevel: BYTE, + DecreaseLevel: BYTE, + Type: BYTE, + IncreaseTime: DWORD, + DecreaseTime: DWORD, + Control: DWORD64, + Status: DWORD64, + HitCount: DWORD, + Reserved1: DWORD, + Reserved2: DWORD64, + Reserved3: DWORD64, +}} +pub type PPPM_WMI_PERF_STATE = *mut PPM_WMI_PERF_STATE; +STRUCT!{struct PPM_WMI_PERF_STATES { + Count: DWORD, + MaxFrequency: DWORD, + CurrentState: DWORD, + MaxPerfState: DWORD, + MinPerfState: DWORD, + LowestPerfState: DWORD, + ThermalConstraint: DWORD, + BusyAdjThreshold: BYTE, + PolicyType: BYTE, + Type: BYTE, + Reserved: BYTE, + TimerInterval: DWORD, + TargetProcessors: DWORD64, + PStateHandler: DWORD, + PStateContext: DWORD, + TStateHandler: DWORD, + TStateContext: DWORD, + FeedbackHandler: DWORD, + Reserved1: DWORD, + Reserved2: DWORD64, + State: [PPM_WMI_PERF_STATE; ANYSIZE_ARRAY], +}} +pub type PPPM_WMI_PERF_STATES = *mut PPM_WMI_PERF_STATES; +STRUCT!{struct PPM_WMI_PERF_STATES_EX { + Count: DWORD, + MaxFrequency: DWORD, + CurrentState: DWORD, + MaxPerfState: DWORD, + MinPerfState: DWORD, + LowestPerfState: DWORD, + ThermalConstraint: DWORD, + BusyAdjThreshold: BYTE, + PolicyType: BYTE, + Type: BYTE, + Reserved: BYTE, + TimerInterval: DWORD, + TargetProcessors: PVOID, + PStateHandler: DWORD, + PStateContext: DWORD, + TStateHandler: DWORD, + TStateContext: DWORD, + FeedbackHandler: DWORD, + Reserved1: DWORD, + Reserved2: DWORD64, + State: [PPM_WMI_PERF_STATE; ANYSIZE_ARRAY], +}} +pub type PPPM_WMI_PERF_STATES_EX = *mut PPM_WMI_PERF_STATES_EX; +pub const PROC_IDLE_BUCKET_COUNT: usize = 6; +STRUCT!{struct PPM_IDLE_STATE_ACCOUNTING { + IdleTransitions: DWORD, + FailedTransitions: DWORD, + InvalidBucketIndex: DWORD, + TotalTime: DWORD64, + IdleTimeBuckets: [DWORD; PROC_IDLE_BUCKET_COUNT], +}} +pub type PPPM_IDLE_STATE_ACCOUNTING = *mut PPM_IDLE_STATE_ACCOUNTING; +STRUCT!{struct PPM_IDLE_ACCOUNTING { + StateCount: DWORD, + TotalTransitions: DWORD, + ResetCount: DWORD, + StartTime: DWORD64, + State: [PPM_IDLE_STATE_ACCOUNTING; ANYSIZE_ARRAY], +}} +pub type PPPM_IDLE_ACCOUNTING = *mut PPM_IDLE_ACCOUNTING; +pub const PROC_IDLE_BUCKET_COUNT_EX: usize = 16; +STRUCT!{struct PPM_IDLE_STATE_BUCKET_EX { + TotalTimeUs: DWORD64, + MinTimeUs: DWORD, + MaxTimeUs: DWORD, + Count: DWORD, +}} +pub type PPPM_IDLE_STATE_BUCKET_EX = *mut PPM_IDLE_STATE_BUCKET_EX; +STRUCT!{struct PPM_IDLE_STATE_ACCOUNTING_EX { + TotalTime: DWORD64, + IdleTransitions: DWORD, + FailedTransitions: DWORD, + InvalidBucketIndex: DWORD, + MinTimeUs: DWORD, + MaxTimeUs: DWORD, + CancelledTransitions: DWORD, + IdleTimeBuckets: [PPM_IDLE_STATE_BUCKET_EX; PROC_IDLE_BUCKET_COUNT_EX], +}} +pub type PPPM_IDLE_STATE_ACCOUNTING_EX = *mut PPM_IDLE_STATE_ACCOUNTING_EX; +STRUCT!{struct PPM_IDLE_ACCOUNTING_EX { + StateCount: DWORD, + TotalTransitions: DWORD, + ResetCount: DWORD, + AbortCount: DWORD, + StartTime: DWORD64, + State: [PPM_IDLE_STATE_ACCOUNTING_EX; ANYSIZE_ARRAY], +}} +pub type PPPM_IDLE_ACCOUNTING_EX = *mut PPM_IDLE_ACCOUNTING_EX; +pub const ACPI_PPM_SOFTWARE_ALL: DWORD = 0xFC; +pub const ACPI_PPM_SOFTWARE_ANY: DWORD = 0xFD; +pub const ACPI_PPM_HARDWARE_ALL: DWORD = 0xFE; +pub const MS_PPM_SOFTWARE_ALL: DWORD = 0x1; +pub const PPM_FIRMWARE_ACPI1C2: DWORD = 0x00000001; +pub const PPM_FIRMWARE_ACPI1C3: DWORD = 0x00000002; +pub const PPM_FIRMWARE_ACPI1TSTATES: DWORD = 0x00000004; +pub const PPM_FIRMWARE_CST: DWORD = 0x00000008; +pub const PPM_FIRMWARE_CSD: DWORD = 0x00000010; +pub const PPM_FIRMWARE_PCT: DWORD = 0x00000020; +pub const PPM_FIRMWARE_PSS: DWORD = 0x00000040; +pub const PPM_FIRMWARE_XPSS: DWORD = 0x00000080; +pub const PPM_FIRMWARE_PPC: DWORD = 0x00000100; +pub const PPM_FIRMWARE_PSD: DWORD = 0x00000200; +pub const PPM_FIRMWARE_PTC: DWORD = 0x00000400; +pub const PPM_FIRMWARE_TSS: DWORD = 0x00000800; +pub const PPM_FIRMWARE_TPC: DWORD = 0x00001000; +pub const PPM_FIRMWARE_TSD: DWORD = 0x00002000; +pub const PPM_FIRMWARE_PCCH: DWORD = 0x00004000; +pub const PPM_FIRMWARE_PCCP: DWORD = 0x00008000; +pub const PPM_FIRMWARE_OSC: DWORD = 0x00010000; +pub const PPM_FIRMWARE_PDC: DWORD = 0x00020000; +pub const PPM_FIRMWARE_CPC: DWORD = 0x00040000; +pub const PPM_FIRMWARE_LPI: DWORD = 0x00080000; +pub const PPM_PERFORMANCE_IMPLEMENTATION_NONE: DWORD = 0x00000000; +pub const PPM_PERFORMANCE_IMPLEMENTATION_PSTATES: DWORD = 0x00000001; +pub const PPM_PERFORMANCE_IMPLEMENTATION_PCCV1: DWORD = 0x00000002; +pub const PPM_PERFORMANCE_IMPLEMENTATION_CPPC: DWORD = 0x00000003; +pub const PPM_PERFORMANCE_IMPLEMENTATION_PEP: DWORD = 0x00000004; +pub const PPM_IDLE_IMPLEMENTATION_NONE: DWORD = 0x00000000; +pub const PPM_IDLE_IMPLEMENTATION_CSTATES: DWORD = 0x00000001; +pub const PPM_IDLE_IMPLEMENTATION_PEP: DWORD = 0x00000002; +pub const PPM_IDLE_IMPLEMENTATION_MICROPEP: DWORD = 0x00000003; +pub const PPM_IDLE_IMPLEMENTATION_LPISTATES: DWORD = 0x00000004; +DEFINE_GUID!{PPM_PERFSTATE_CHANGE_GUID, + 0xa5b32ddd, 0x7f39, 0x4abc, 0xb8, 0x92, 0x90, 0xe, 0x43, 0xb5, 0x9e, 0xbb} +DEFINE_GUID!{PPM_PERFSTATE_DOMAIN_CHANGE_GUID, + 0x995e6b7f, 0xd653, 0x497a, 0xb9, 0x78, 0x36, 0xa3, 0xc, 0x29, 0xbf, 0x1} +DEFINE_GUID!{PPM_IDLESTATE_CHANGE_GUID, + 0x4838fe4f, 0xf71c, 0x4e51, 0x9e, 0xcc, 0x84, 0x30, 0xa7, 0xac, 0x4c, 0x6c} +DEFINE_GUID!{PPM_PERFSTATES_DATA_GUID, + 0x5708cc20, 0x7d40, 0x4bf4, 0xb4, 0xaa, 0x2b, 0x01, 0x33, 0x8d, 0x01, 0x26} +DEFINE_GUID!{PPM_IDLESTATES_DATA_GUID, + 0xba138e10, 0xe250, 0x4ad7, 0x86, 0x16, 0xcf, 0x1a, 0x7a, 0xd4, 0x10, 0xe7} +DEFINE_GUID!{PPM_IDLE_ACCOUNTING_GUID, + 0xe2a26f78, 0xae07, 0x4ee0, 0xa3, 0x0f, 0xce, 0x54, 0xf5, 0x5a, 0x94, 0xcd} +DEFINE_GUID!{PPM_IDLE_ACCOUNTING_EX_GUID, + 0xd67abd39, 0x81f8, 0x4a5e, 0x81, 0x52, 0x72, 0xe3, 0x1e, 0xc9, 0x12, 0xee} +DEFINE_GUID!{PPM_THERMALCONSTRAINT_GUID, + 0xa852c2c8, 0x1a4c, 0x423b, 0x8c, 0x2c, 0xf3, 0x0d, 0x82, 0x93, 0x1a, 0x88} +DEFINE_GUID!{PPM_PERFMON_PERFSTATE_GUID, + 0x7fd18652, 0xcfe, 0x40d2, 0xb0, 0xa1, 0xb, 0x6, 0x6a, 0x87, 0x75, 0x9e} +DEFINE_GUID!{PPM_THERMAL_POLICY_CHANGE_GUID, + 0x48f377b8, 0x6880, 0x4c7b, 0x8b, 0xdc, 0x38, 0x1, 0x76, 0xc6, 0x65, 0x4d} +STRUCT!{struct PPM_PERFSTATE_EVENT { + State: DWORD, + Status: DWORD, + Latency: DWORD, + Speed: DWORD, + Processor: DWORD, +}} +pub type PPPM_PERFSTATE_EVENT = *mut PPM_PERFSTATE_EVENT; +STRUCT!{struct PPM_PERFSTATE_DOMAIN_EVENT { + State: DWORD, + Latency: DWORD, + Speed: DWORD, + Processors: DWORD64, +}} +pub type PPPM_PERFSTATE_DOMAIN_EVENT = *mut PPM_PERFSTATE_DOMAIN_EVENT; +STRUCT!{struct PPM_IDLESTATE_EVENT { + NewState: DWORD, + OldState: DWORD, + Processors: DWORD64, +}} +pub type PPPM_IDLESTATE_EVENT = *mut PPM_IDLESTATE_EVENT; +STRUCT!{struct PPM_THERMALCHANGE_EVENT { + ThermalConstraint: DWORD, + Processors: DWORD64, +}} +pub type PPPM_THERMALCHANGE_EVENT = *mut PPM_THERMALCHANGE_EVENT; +STRUCT!{struct PPM_THERMAL_POLICY_EVENT { + Mode: BYTE, + Processors: DWORD64, +}} +pub type PPPM_THERMAL_POLICY_EVENT = *mut PPM_THERMAL_POLICY_EVENT; +STRUCT!{struct POWER_ACTION_POLICY { + Action: POWER_ACTION, + Flags: DWORD, + EventCode: DWORD, +}} +pub type PPOWER_ACTION_POLICY = *mut POWER_ACTION_POLICY; +pub const POWER_ACTION_QUERY_ALLOWED: DWORD = 0x00000001; +pub const POWER_ACTION_UI_ALLOWED: DWORD = 0x00000002; +pub const POWER_ACTION_OVERRIDE_APPS: DWORD = 0x00000004; +pub const POWER_ACTION_HIBERBOOT: DWORD = 0x00000008; +pub const POWER_ACTION_USER_NOTIFY: DWORD = 0x00000010; +pub const POWER_ACTION_DOZE_TO_HIBERNATE: DWORD = 0x00000020; +pub const POWER_ACTION_PSEUDO_TRANSITION: DWORD = 0x08000000; +pub const POWER_ACTION_LIGHTEST_FIRST: DWORD = 0x10000000; +pub const POWER_ACTION_LOCK_CONSOLE: DWORD = 0x20000000; +pub const POWER_ACTION_DISABLE_WAKES: DWORD = 0x40000000; +pub const POWER_ACTION_CRITICAL: DWORD = 0x80000000; +pub const POWER_LEVEL_USER_NOTIFY_TEXT: DWORD = 0x00000001; +pub const POWER_LEVEL_USER_NOTIFY_SOUND: DWORD = 0x00000002; +pub const POWER_LEVEL_USER_NOTIFY_EXEC: DWORD = 0x00000004; +pub const POWER_USER_NOTIFY_BUTTON: DWORD = 0x00000008; +pub const POWER_USER_NOTIFY_SHUTDOWN: DWORD = 0x00000010; +pub const POWER_USER_NOTIFY_FORCED_SHUTDOWN: DWORD = 0x00000020; +pub const POWER_FORCE_TRIGGER_RESET: DWORD = 0x80000000; +pub const BATTERY_DISCHARGE_FLAGS_EVENTCODE_MASK: DWORD = 0x00000007; +pub const BATTERY_DISCHARGE_FLAGS_ENABLE: DWORD = 0x80000000; +STRUCT!{struct SYSTEM_POWER_LEVEL { + Enable: BOOLEAN, + Spare: [BYTE; 3], + BatteryLevel: DWORD, + PowerPolicy: POWER_ACTION_POLICY, + MinSystemState: SYSTEM_POWER_STATE, +}} +pub type PSYSTEM_POWER_LEVEL = *mut SYSTEM_POWER_LEVEL; +pub const NUM_DISCHARGE_POLICIES: usize = 4; +pub const DISCHARGE_POLICY_CRITICAL: DWORD = 0; +pub const DISCHARGE_POLICY_LOW: DWORD = 1; +STRUCT!{struct SYSTEM_POWER_POLICY { + Revision: DWORD, + PowerButton: POWER_ACTION_POLICY, + SleepButton: POWER_ACTION_POLICY, + LidClose: POWER_ACTION_POLICY, + LidOpenWake: SYSTEM_POWER_STATE, + Reserved: DWORD, + Idle: POWER_ACTION_POLICY, + IdleTimeout: DWORD, + IdleSensitivity: BYTE, + DynamicThrottle: BYTE, + Spare2: [BYTE; 2], + MinSleep: SYSTEM_POWER_STATE, + MaxSleep: SYSTEM_POWER_STATE, + ReducedLatencySleep: SYSTEM_POWER_STATE, + WinLogonFlags: DWORD, + Spare3: DWORD, + DozeS4Timeout: DWORD, + BroadcastCapacityResolution: DWORD, + DischargePolicy: [SYSTEM_POWER_LEVEL; NUM_DISCHARGE_POLICIES], + VideoTimeout: DWORD, + VideoDimDisplay: BOOLEAN, + VideoReserved: [DWORD; 3], + SpindownTimeout: DWORD, + OptimizeForPower: BOOLEAN, + FanThrottleTolerance: BYTE, + ForcedThrottle: BYTE, + MinThrottle: BYTE, + OverThrottled: POWER_ACTION_POLICY, +}} +pub type PSYSTEM_POWER_POLICY = *mut SYSTEM_POWER_POLICY; +pub const PROCESSOR_IDLESTATE_POLICY_COUNT: usize = 0x3; +STRUCT!{struct PROCESSOR_IDLESTATE_INFO { + TimeCheck: DWORD, + DemotePercent: BYTE, + PromotePercent: BYTE, + Spare: [BYTE; 2], +}} +pub type PPROCESSOR_IDLESTATE_INFO = *mut PROCESSOR_IDLESTATE_INFO; +STRUCT!{struct PROCESSOR_IDLESTATE_POLICY_Flags { + AsWORD: WORD, +}} +BITFIELD!{PROCESSOR_IDLESTATE_POLICY_Flags AsWORD: WORD [ + AllowScaling set_AllowScaling[0..1], + Disabled set_Disabled[1..2], + Reserved set_Reserved[2..16], +]} +STRUCT!{struct PROCESSOR_IDLESTATE_POLICY { + Revision: WORD, + Flags: PROCESSOR_IDLESTATE_POLICY_Flags, + PolicyCount: DWORD, + Policy: [PROCESSOR_IDLESTATE_INFO; PROCESSOR_IDLESTATE_POLICY_COUNT], +}} +pub type PPROCESSOR_IDLESTATE_POLICY = *mut PROCESSOR_IDLESTATE_POLICY; +pub const PO_THROTTLE_NONE: DWORD = 0; +pub const PO_THROTTLE_CONSTANT: DWORD = 1; +pub const PO_THROTTLE_DEGRADE: DWORD = 2; +pub const PO_THROTTLE_ADAPTIVE: DWORD = 3; +pub const PO_THROTTLE_MAXIMUM: DWORD = 4; +STRUCT!{struct PROCESSOR_POWER_POLICY_INFO { + TimeCheck: DWORD, + DemoteLimit: DWORD, + PromoteLimit: DWORD, + DemotePercent: BYTE, + PromotePercent: BYTE, + Spare: [BYTE; 2], + Reserved: DWORD, +}} +BITFIELD!{PROCESSOR_POWER_POLICY_INFO Reserved: DWORD [ + AllowDemotion set_AllowDemotion[0..1], + AllowPromotion set_AllowPromotion[1..2], + Reserved set_Reserved[2..32], +]} +pub type PPROCESSOR_POWER_POLICY_INFO = *mut PROCESSOR_POWER_POLICY_INFO; +STRUCT!{struct PROCESSOR_POWER_POLICY { + Revision: DWORD, + DynamicThrottle: BYTE, + Spare: [BYTE; 3], + BitFields: DWORD, + PolicyCount: DWORD, + Policy: [PROCESSOR_POWER_POLICY_INFO; 3], +}} +BITFIELD!{PROCESSOR_POWER_POLICY BitFields: DWORD [ + DisableCStates set_DisableCStates[0..1], + Reserved set_Reserved[1..32], +]} +pub type PPROCESSOR_POWER_POLICY = *mut PROCESSOR_POWER_POLICY; +STRUCT!{struct PROCESSOR_PERFSTATE_POLICY_u_Flags { + AsBYTE: BYTE, +}} +BITFIELD!{PROCESSOR_PERFSTATE_POLICY_u_Flags AsBYTE: BYTE [ + NoDomainAccounting set_NoDomainAccounting[0..1], + IncreasePolicy set_IncreasePolicy[1..3], + DecreasePolicy set_DecreasePolicy[3..5], + Reserved set_Reserved[5..8], +]} +UNION!{union PROCESSOR_PERFSTATE_POLICY_u { + [u8; 1], + Spare Spare_mut: BYTE, + Flags Flags_mut: PROCESSOR_PERFSTATE_POLICY_u_Flags, +}} +STRUCT!{struct PROCESSOR_PERFSTATE_POLICY { + Revision: DWORD, + MaxThrottle: BYTE, + MinThrottle: BYTE, + BusyAdjThreshold: BYTE, + u: PROCESSOR_PERFSTATE_POLICY_u, + TimeCheck: DWORD, + IncreaseTime: DWORD, + DecreaseTime: DWORD, + IncreasePercent: DWORD, + DecreasePercent: DWORD, +}} +pub type PPROCESSOR_PERFSTATE_POLICY = *mut PROCESSOR_PERFSTATE_POLICY; +STRUCT!{struct ADMINISTRATOR_POWER_POLICY { + MinSleep: SYSTEM_POWER_STATE, + MaxSleep: SYSTEM_POWER_STATE, + MinVideoTimeout: DWORD, + MaxVideoTimeout: DWORD, + MinSpindownTimeout: DWORD, + MaxSpindownTimeout: DWORD, +}} +pub type PADMINISTRATOR_POWER_POLICY = *mut ADMINISTRATOR_POWER_POLICY; +ENUM!{enum HIBERFILE_BUCKET_SIZE { + HiberFileBucket1GB = 0, + HiberFileBucket2GB, + HiberFileBucket4GB, + HiberFileBucket8GB, + HiberFileBucket16GB, + HiberFileBucket32GB, + HiberFileBucketUnlimited, + HiberFileBucketMax, +}} +pub const HIBERFILE_TYPE_NONE: BYTE = 0x00; +pub const HIBERFILE_TYPE_REDUCED: BYTE = 0x01; +pub const HIBERFILE_TYPE_FULL: BYTE = 0x02; +pub const HIBERFILE_TYPE_MAX: usize = 0x03; +STRUCT!{struct HIBERFILE_BUCKET { + MaxPhysicalMemory: DWORD64, + PhysicalMemoryPercent: [DWORD; HIBERFILE_TYPE_MAX], +}} +pub type PHIBERFILE_BUCKET = *mut HIBERFILE_BUCKET; +STRUCT!{struct SYSTEM_POWER_CAPABILITIES { + PowerButtonPresent: BOOLEAN, + SleepButtonPresent: BOOLEAN, + LidPresent: BOOLEAN, + SystemS1: BOOLEAN, + SystemS2: BOOLEAN, + SystemS3: BOOLEAN, + SystemS4: BOOLEAN, + SystemS5: BOOLEAN, + HiberFilePresent: BOOLEAN, + FullWake: BOOLEAN, + VideoDimPresent: BOOLEAN, + ApmPresent: BOOLEAN, + UpsPresent: BOOLEAN, + ThermalControl: BOOLEAN, + ProcessorThrottle: BOOLEAN, + ProcessorMinThrottle: BYTE, + ProcessorMaxThrottle: BYTE, + FastSystemS4: BOOLEAN, + Hiberboot: BOOLEAN, + WakeAlarmPresent: BOOLEAN, + AoAc: BOOLEAN, + DiskSpinDown: BOOLEAN, + HiberFileType: BYTE, + AoAcConnectivitySupported: BOOLEAN, + spare3: [BYTE; 6], + SystemBatteriesPresent: BOOLEAN, + BatteriesAreShortTerm: BOOLEAN, + BatteryScale: [BATTERY_REPORTING_SCALE; 3], + AcOnLineWake: SYSTEM_POWER_STATE, + SoftLidWake: SYSTEM_POWER_STATE, + RtcWake: SYSTEM_POWER_STATE, + MinDeviceWakeState: SYSTEM_POWER_STATE, + DefaultLowLatencyWake: SYSTEM_POWER_STATE, +}} +pub type PSYSTEM_POWER_CAPABILITIES = *mut SYSTEM_POWER_CAPABILITIES; +STRUCT!{struct SYSTEM_BATTERY_STATE { + AcOnLine: BOOLEAN, + BatteryPresent: BOOLEAN, + Charging: BOOLEAN, + Discharging: BOOLEAN, + Spare1: [BOOLEAN; 3], + Tag: BYTE, + MaxCapacity: DWORD, + RemainingCapacity: DWORD, + Rate: DWORD, + EstimatedTime: DWORD, + DefaultAlert1: DWORD, + DefaultAlert2: DWORD, +}} +pub type PSYSTEM_BATTERY_STATE = *mut SYSTEM_BATTERY_STATE; +pub const IMAGE_DOS_SIGNATURE: WORD = 0x5A4D; +pub const IMAGE_OS2_SIGNATURE: WORD = 0x454E; +pub const IMAGE_OS2_SIGNATURE_LE: WORD = 0x454C; +pub const IMAGE_VXD_SIGNATURE: WORD = 0x454C; +pub const IMAGE_NT_SIGNATURE: DWORD = 0x00004550; +STRUCT!{struct IMAGE_DOS_HEADER { + e_magic: WORD, + e_cblp: WORD, + e_cp: WORD, + e_crlc: WORD, + e_cparhdr: WORD, + e_minalloc: WORD, + e_maxalloc: WORD, + e_ss: WORD, + e_sp: WORD, + e_csum: WORD, + e_ip: WORD, + e_cs: WORD, + e_lfarlc: WORD, + e_ovno: WORD, + e_res: [WORD; 4], + e_oemid: WORD, + e_oeminfo: WORD, + e_res2: [WORD; 10], + e_lfanew: LONG, +}} +pub type PIMAGE_DOS_HEADER = *mut IMAGE_DOS_HEADER; +STRUCT!{struct IMAGE_OS2_HEADER { + ne_magic: WORD, + ne_ver: CHAR, + ne_rev: CHAR, + ne_enttab: WORD, + ne_cbenttab: WORD, + ne_crc: LONG, + ne_flags: WORD, + ne_autodata: WORD, + ne_heap: WORD, + ne_stack: WORD, + ne_csip: LONG, + ne_sssp: LONG, + ne_cseg: WORD, + ne_cmod: WORD, + ne_cbnrestab: WORD, + ne_segtab: WORD, + ne_rsrctab: WORD, + ne_restab: WORD, + ne_modtab: WORD, + ne_imptab: WORD, + ne_nrestab: LONG, + ne_cmovent: WORD, + ne_align: WORD, + ne_cres: WORD, + ne_exetyp: BYTE, + ne_flagsothers: BYTE, + ne_pretthunks: WORD, + ne_psegrefbytes: WORD, + ne_swaparea: WORD, + ne_expver: WORD, +}} +pub type PIMAGE_OS2_HEADER = *mut IMAGE_OS2_HEADER; +STRUCT!{struct IMAGE_VXD_HEADER { + e32_magic: WORD, + e32_border: BYTE, + e32_worder: BYTE, + e32_level: DWORD, + e32_cpu: WORD, + e32_os: WORD, + e32_ver: DWORD, + e32_mflags: DWORD, + e32_mpages: DWORD, + e32_startobj: DWORD, + e32_eip: DWORD, + e32_stackobj: DWORD, + e32_esp: DWORD, + e32_pagesize: DWORD, + e32_lastpagesize: DWORD, + e32_fixupsize: DWORD, + e32_fixupsum: DWORD, + e32_ldrsize: DWORD, + e32_ldrsum: DWORD, + e32_objtab: DWORD, + e32_objcnt: DWORD, + e32_objmap: DWORD, + e32_itermap: DWORD, + e32_rsrctab: DWORD, + e32_rsrccnt: DWORD, + e32_restab: DWORD, + e32_enttab: DWORD, + e32_dirtab: DWORD, + e32_dircnt: DWORD, + e32_fpagetab: DWORD, + e32_frectab: DWORD, + e32_impmod: DWORD, + e32_impmodcnt: DWORD, + e32_impproc: DWORD, + e32_pagesum: DWORD, + e32_datapage: DWORD, + e32_preload: DWORD, + e32_nrestab: DWORD, + e32_cbnrestab: DWORD, + e32_nressum: DWORD, + e32_autodata: DWORD, + e32_debuginfo: DWORD, + e32_debuglen: DWORD, + e32_instpreload: DWORD, + e32_instdemand: DWORD, + e32_heapsize: DWORD, + e32_res3: [BYTE; 12], + e32_winresoff: DWORD, + e32_winreslen: DWORD, + e32_devid: WORD, + e32_ddkver: WORD, +}} +pub type PIMAGE_VXD_HEADER = *mut IMAGE_VXD_HEADER; +STRUCT!{struct IMAGE_FILE_HEADER { + Machine: WORD, + NumberOfSections: WORD, + TimeDateStamp: DWORD, + PointerToSymbolTable: DWORD, + NumberOfSymbols: DWORD, + SizeOfOptionalHeader: WORD, + Characteristics: WORD, +}} +pub type PIMAGE_FILE_HEADER = *mut IMAGE_FILE_HEADER; +pub const IMAGE_SIZEOF_FILE_HEADER: usize = 20; +pub const IMAGE_FILE_RELOCS_STRIPPED: WORD = 0x0001; +pub const IMAGE_FILE_EXECUTABLE_IMAGE: WORD = 0x0002; +pub const IMAGE_FILE_LINE_NUMS_STRIPPED: WORD = 0x0004; +pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: WORD = 0x0008; +pub const IMAGE_FILE_AGGRESIVE_WS_TRIM: WORD = 0x0010; +pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: WORD = 0x0020; +pub const IMAGE_FILE_BYTES_REVERSED_LO: WORD = 0x0080; +pub const IMAGE_FILE_32BIT_MACHINE: WORD = 0x0100; +pub const IMAGE_FILE_DEBUG_STRIPPED: WORD = 0x0200; +pub const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP: WORD = 0x0400; +pub const IMAGE_FILE_NET_RUN_FROM_SWAP: WORD = 0x0800; +pub const IMAGE_FILE_SYSTEM: WORD = 0x1000; +pub const IMAGE_FILE_DLL: WORD = 0x2000; +pub const IMAGE_FILE_UP_SYSTEM_ONLY: WORD = 0x4000; +pub const IMAGE_FILE_BYTES_REVERSED_HI: WORD = 0x8000; +pub const IMAGE_FILE_MACHINE_UNKNOWN: WORD = 0; +pub const IMAGE_FILE_MACHINE_TARGET_HOST: WORD = 0x0001; +pub const IMAGE_FILE_MACHINE_I386: WORD = 0x014c; +pub const IMAGE_FILE_MACHINE_R3000: WORD = 0x0162; +pub const IMAGE_FILE_MACHINE_R4000: WORD = 0x0166; +pub const IMAGE_FILE_MACHINE_R10000: WORD = 0x0168; +pub const IMAGE_FILE_MACHINE_WCEMIPSV2: WORD = 0x0169; +pub const IMAGE_FILE_MACHINE_ALPHA: WORD = 0x0184; +pub const IMAGE_FILE_MACHINE_SH3: WORD = 0x01a2; +pub const IMAGE_FILE_MACHINE_SH3DSP: WORD = 0x01a3; +pub const IMAGE_FILE_MACHINE_SH3E: WORD = 0x01a4; +pub const IMAGE_FILE_MACHINE_SH4: WORD = 0x01a6; +pub const IMAGE_FILE_MACHINE_SH5: WORD = 0x01a8; +pub const IMAGE_FILE_MACHINE_ARM: WORD = 0x01c0; +pub const IMAGE_FILE_MACHINE_THUMB: WORD = 0x01c2; +pub const IMAGE_FILE_MACHINE_ARMNT: WORD = 0x01c4; +pub const IMAGE_FILE_MACHINE_AM33: WORD = 0x01d3; +pub const IMAGE_FILE_MACHINE_POWERPC: WORD = 0x01F0; +pub const IMAGE_FILE_MACHINE_POWERPCFP: WORD = 0x01f1; +pub const IMAGE_FILE_MACHINE_IA64: WORD = 0x0200; +pub const IMAGE_FILE_MACHINE_MIPS16: WORD = 0x0266; +pub const IMAGE_FILE_MACHINE_ALPHA64: WORD = 0x0284; +pub const IMAGE_FILE_MACHINE_MIPSFPU: WORD = 0x0366; +pub const IMAGE_FILE_MACHINE_MIPSFPU16: WORD = 0x0466; +pub const IMAGE_FILE_MACHINE_AXP64: WORD = IMAGE_FILE_MACHINE_ALPHA64; +pub const IMAGE_FILE_MACHINE_TRICORE: WORD = 0x0520; +pub const IMAGE_FILE_MACHINE_CEF: WORD = 0x0CEF; +pub const IMAGE_FILE_MACHINE_EBC: WORD = 0x0EBC; +pub const IMAGE_FILE_MACHINE_AMD64: WORD = 0x8664; +pub const IMAGE_FILE_MACHINE_M32R: WORD = 0x9041; +pub const IMAGE_FILE_MACHINE_ARM64: WORD = 0xAA64; +pub const IMAGE_FILE_MACHINE_CEE: WORD = 0xC0EE; +STRUCT!{struct IMAGE_DATA_DIRECTORY { + VirtualAddress: DWORD, + Size: DWORD, +}} +pub type PIMAGE_DATA_DIRECTORY = *mut IMAGE_DATA_DIRECTORY; +pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES: usize = 16; +STRUCT!{struct IMAGE_OPTIONAL_HEADER32 { + Magic: WORD, + MajorLinkerVersion: BYTE, + MinorLinkerVersion: BYTE, + SizeOfCode: DWORD, + SizeOfInitializedData: DWORD, + SizeOfUninitializedData: DWORD, + AddressOfEntryPoint: DWORD, + BaseOfCode: DWORD, + BaseOfData: DWORD, + ImageBase: DWORD, + SectionAlignment: DWORD, + FileAlignment: DWORD, + MajorOperatingSystemVersion: WORD, + MinorOperatingSystemVersion: WORD, + MajorImageVersion: WORD, + MinorImageVersion: WORD, + MajorSubsystemVersion: WORD, + MinorSubsystemVersion: WORD, + Win32VersionValue: DWORD, + SizeOfImage: DWORD, + SizeOfHeaders: DWORD, + CheckSum: DWORD, + Subsystem: WORD, + DllCharacteristics: WORD, + SizeOfStackReserve: DWORD, + SizeOfStackCommit: DWORD, + SizeOfHeapReserve: DWORD, + SizeOfHeapCommit: DWORD, + LoaderFlags: DWORD, + NumberOfRvaAndSizes: DWORD, + DataDirectory: [IMAGE_DATA_DIRECTORY; IMAGE_NUMBEROF_DIRECTORY_ENTRIES], +}} +pub type PIMAGE_OPTIONAL_HEADER32 = *mut IMAGE_OPTIONAL_HEADER32; +STRUCT!{struct IMAGE_ROM_OPTIONAL_HEADER { + Magic: WORD, + MajorLinkerVersion: BYTE, + MinorLinkerVersion: BYTE, + SizeOfCode: DWORD, + SizeOfInitializedData: DWORD, + SizeOfUninitializedData: DWORD, + AddressOfEntryPoint: DWORD, + BaseOfCode: DWORD, + BaseOfData: DWORD, + BaseOfBss: DWORD, + GprMask: DWORD, + CprMask: [DWORD; 4], + GpValue: DWORD, +}} +pub type PIMAGE_ROM_OPTIONAL_HEADER = *mut IMAGE_ROM_OPTIONAL_HEADER; +STRUCT!{struct IMAGE_OPTIONAL_HEADER64 { + Magic: WORD, + MajorLinkerVersion: BYTE, + MinorLinkerVersion: BYTE, + SizeOfCode: DWORD, + SizeOfInitializedData: DWORD, + SizeOfUninitializedData: DWORD, + AddressOfEntryPoint: DWORD, + BaseOfCode: DWORD, + ImageBase: ULONGLONG, + SectionAlignment: DWORD, + FileAlignment: DWORD, + MajorOperatingSystemVersion: WORD, + MinorOperatingSystemVersion: WORD, + MajorImageVersion: WORD, + MinorImageVersion: WORD, + MajorSubsystemVersion: WORD, + MinorSubsystemVersion: WORD, + Win32VersionValue: DWORD, + SizeOfImage: DWORD, + SizeOfHeaders: DWORD, + CheckSum: DWORD, + Subsystem: WORD, + DllCharacteristics: WORD, + SizeOfStackReserve: ULONGLONG, + SizeOfStackCommit: ULONGLONG, + SizeOfHeapReserve: ULONGLONG, + SizeOfHeapCommit: ULONGLONG, + LoaderFlags: DWORD, + NumberOfRvaAndSizes: DWORD, + DataDirectory: [IMAGE_DATA_DIRECTORY; IMAGE_NUMBEROF_DIRECTORY_ENTRIES], +}} +pub type PIMAGE_OPTIONAL_HEADER64 = *mut IMAGE_OPTIONAL_HEADER64; +pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC: WORD = 0x10b; +pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: WORD = 0x20b; +pub const IMAGE_ROM_OPTIONAL_HDR_MAGIC: WORD = 0x107; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub type IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER64; +pub type PIMAGE_OPTIONAL_HEADER = PIMAGE_OPTIONAL_HEADER64; +pub const IMAGE_NT_OPTIONAL_HDR_MAGIC: WORD = IMAGE_NT_OPTIONAL_HDR64_MAGIC; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +pub type IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER32; +pub type PIMAGE_OPTIONAL_HEADER = PIMAGE_OPTIONAL_HEADER32; +pub const IMAGE_NT_OPTIONAL_HDR_MAGIC: WORD = IMAGE_NT_OPTIONAL_HDR32_MAGIC; +} +STRUCT!{struct IMAGE_NT_HEADERS64 { + Signature: DWORD, + FileHeader: IMAGE_FILE_HEADER, + OptionalHeader: IMAGE_OPTIONAL_HEADER64, +}} +pub type PIMAGE_NT_HEADERS64 = *mut IMAGE_NT_HEADERS64; +STRUCT!{struct IMAGE_NT_HEADERS32 { + Signature: DWORD, + FileHeader: IMAGE_FILE_HEADER, + OptionalHeader: IMAGE_OPTIONAL_HEADER32, +}} +pub type PIMAGE_NT_HEADERS32 = *mut IMAGE_NT_HEADERS32; +STRUCT!{struct IMAGE_ROM_HEADERS { + FileHeader: IMAGE_FILE_HEADER, + OptionalHeader: IMAGE_ROM_OPTIONAL_HEADER, +}} +pub type PIMAGE_ROM_HEADERS = *mut IMAGE_ROM_HEADERS; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub type IMAGE_NT_HEADERS = IMAGE_NT_HEADERS64; +pub type PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS64; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +pub type IMAGE_NT_HEADERS = IMAGE_NT_HEADERS32; +pub type PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS32; +} +pub const IMAGE_SUBSYSTEM_UNKNOWN: WORD = 0; +pub const IMAGE_SUBSYSTEM_NATIVE: WORD = 1; +pub const IMAGE_SUBSYSTEM_WINDOWS_GUI: WORD = 2; +pub const IMAGE_SUBSYSTEM_WINDOWS_CUI: WORD = 3; +pub const IMAGE_SUBSYSTEM_OS2_CUI: WORD = 5; +pub const IMAGE_SUBSYSTEM_POSIX_CUI: WORD = 7; +pub const IMAGE_SUBSYSTEM_NATIVE_WINDOWS: WORD = 8; +pub const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: WORD = 9; +pub const IMAGE_SUBSYSTEM_EFI_APPLICATION: WORD = 10; +pub const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: WORD = 11; +pub const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: WORD = 12; +pub const IMAGE_SUBSYSTEM_EFI_ROM: WORD = 13; +pub const IMAGE_SUBSYSTEM_XBOX: WORD = 14; +pub const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: WORD = 16; +pub const IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG: WORD = 17; +pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: WORD = 0x0020; +pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: WORD = 0x0040; +pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: WORD = 0x0080; +pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: WORD = 0x0100; +pub const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION: WORD = 0x0200; +pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: WORD = 0x0400; +pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: WORD = 0x0800; +pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: WORD = 0x1000; +pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: WORD = 0x2000; +pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: WORD = 0x4000; +pub const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE: WORD = 0x8000; +pub const IMAGE_DIRECTORY_ENTRY_EXPORT: WORD = 0; +pub const IMAGE_DIRECTORY_ENTRY_IMPORT: WORD = 1; +pub const IMAGE_DIRECTORY_ENTRY_RESOURCE: WORD = 2; +pub const IMAGE_DIRECTORY_ENTRY_EXCEPTION: WORD = 3; +pub const IMAGE_DIRECTORY_ENTRY_SECURITY: WORD = 4; +pub const IMAGE_DIRECTORY_ENTRY_BASERELOC: WORD = 5; +pub const IMAGE_DIRECTORY_ENTRY_DEBUG: WORD = 6; +pub const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE: WORD = 7; +pub const IMAGE_DIRECTORY_ENTRY_GLOBALPTR: WORD = 8; +pub const IMAGE_DIRECTORY_ENTRY_TLS: WORD = 9; +pub const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: WORD = 10; +pub const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: WORD = 11; +pub const IMAGE_DIRECTORY_ENTRY_IAT: WORD = 12; +pub const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: WORD = 13; +pub const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: WORD = 14; +STRUCT!{struct ANON_OBJECT_HEADER { + Sig1: WORD, + Sig2: WORD, + Version: WORD, + Machine: WORD, + TimeDateStamp: DWORD, + ClassID: CLSID, + SizeOfData: DWORD, +}} +STRUCT!{struct ANON_OBJECT_HEADER_V2 { + Sig1: WORD, + Sig2: WORD, + Version: WORD, + Machine: WORD, + TimeDateStamp: DWORD, + ClassID: CLSID, + SizeOfData: DWORD, + Flags: DWORD, + MetaDataSize: DWORD, + MetaDataOffset: DWORD, +}} +STRUCT!{struct ANON_OBJECT_HEADER_BIGOBJ { + Sig1: WORD, + Sig2: WORD, + Version: WORD, + Machine: WORD, + TimeDateStamp: DWORD, + ClassID: CLSID, + SizeOfData: DWORD, + Flags: DWORD, + MetaDataSize: DWORD, + MetaDataOffset: DWORD, + NumberOfSections: DWORD, + PointerToSymbolTable: DWORD, + NumberOfSymbols: DWORD, +}} +pub const IMAGE_SIZEOF_SHORT_NAME: usize = 8; +UNION!{union IMAGE_SECTION_HEADER_Misc { + [u32; 1], + PhysicalAddress PhysicalAddress_mut: DWORD, + VirtualSize VirtualSize_mut: DWORD, +}} +STRUCT!{struct IMAGE_SECTION_HEADER { + Name: [BYTE; IMAGE_SIZEOF_SHORT_NAME], + Misc: IMAGE_SECTION_HEADER_Misc, + VirtualAddress: DWORD, + SizeOfRawData: DWORD, + PointerToRawData: DWORD, + PointerToRelocations: DWORD, + PointerToLinenumbers: DWORD, + NumberOfRelocations: WORD, + NumberOfLinenumbers: WORD, + Characteristics: DWORD, +}} +pub type PIMAGE_SECTION_HEADER = *mut IMAGE_SECTION_HEADER; +pub const IMAGE_SIZEOF_SECTION_HEADER: usize = 40; +pub const IMAGE_SCN_TYPE_NO_PAD: DWORD = 0x00000008; +pub const IMAGE_SCN_CNT_CODE: DWORD = 0x00000020; +pub const IMAGE_SCN_CNT_INITIALIZED_DATA: DWORD = 0x00000040; +pub const IMAGE_SCN_CNT_UNINITIALIZED_DATA: DWORD = 0x00000080; +pub const IMAGE_SCN_LNK_OTHER: DWORD = 0x00000100; +pub const IMAGE_SCN_LNK_INFO: DWORD = 0x00000200; +pub const IMAGE_SCN_LNK_REMOVE: DWORD = 0x00000800; +pub const IMAGE_SCN_LNK_COMDAT: DWORD = 0x00001000; +pub const IMAGE_SCN_NO_DEFER_SPEC_EXC: DWORD = 0x00004000; +pub const IMAGE_SCN_GPREL: DWORD = 0x00008000; +pub const IMAGE_SCN_MEM_FARDATA: DWORD = 0x00008000; +pub const IMAGE_SCN_MEM_PURGEABLE: DWORD = 0x00020000; +pub const IMAGE_SCN_MEM_16BIT: DWORD = 0x00020000; +pub const IMAGE_SCN_MEM_LOCKED: DWORD = 0x00040000; +pub const IMAGE_SCN_MEM_PRELOAD: DWORD = 0x00080000; +pub const IMAGE_SCN_ALIGN_1BYTES: DWORD = 0x00100000; +pub const IMAGE_SCN_ALIGN_2BYTES: DWORD = 0x00200000; +pub const IMAGE_SCN_ALIGN_4BYTES: DWORD = 0x00300000; +pub const IMAGE_SCN_ALIGN_8BYTES: DWORD = 0x00400000; +pub const IMAGE_SCN_ALIGN_16BYTES: DWORD = 0x00500000; +pub const IMAGE_SCN_ALIGN_32BYTES: DWORD = 0x00600000; +pub const IMAGE_SCN_ALIGN_64BYTES: DWORD = 0x00700000; +pub const IMAGE_SCN_ALIGN_128BYTES: DWORD = 0x00800000; +pub const IMAGE_SCN_ALIGN_256BYTES: DWORD = 0x00900000; +pub const IMAGE_SCN_ALIGN_512BYTES: DWORD = 0x00A00000; +pub const IMAGE_SCN_ALIGN_1024BYTES: DWORD = 0x00B00000; +pub const IMAGE_SCN_ALIGN_2048BYTES: DWORD = 0x00C00000; +pub const IMAGE_SCN_ALIGN_4096BYTES: DWORD = 0x00D00000; +pub const IMAGE_SCN_ALIGN_8192BYTES: DWORD = 0x00E00000; +pub const IMAGE_SCN_ALIGN_MASK: DWORD = 0x00F00000; +pub const IMAGE_SCN_LNK_NRELOC_OVFL: DWORD = 0x01000000; +pub const IMAGE_SCN_MEM_DISCARDABLE: DWORD = 0x02000000; +pub const IMAGE_SCN_MEM_NOT_CACHED: DWORD = 0x04000000; +pub const IMAGE_SCN_MEM_NOT_PAGED: DWORD = 0x08000000; +pub const IMAGE_SCN_MEM_SHARED: DWORD = 0x10000000; +pub const IMAGE_SCN_MEM_EXECUTE: DWORD = 0x20000000; +pub const IMAGE_SCN_MEM_READ: DWORD = 0x40000000; +pub const IMAGE_SCN_MEM_WRITE: DWORD = 0x80000000; +pub const IMAGE_SCN_SCALE_INDEX: DWORD = 0x00000001; +STRUCT!{struct IMAGE_SYMBOL_N_Name { + Short: DWORD, + Long: DWORD, +}} +UNION!{union IMAGE_SYMBOL_N { + [u32; 2], + ShortName ShortName_mut: [BYTE; 8], + Name Name_mut: IMAGE_SYMBOL_N_Name, + LongName LongName_mut: [DWORD; 2], +}} +STRUCT!{struct IMAGE_SYMBOL { + N: IMAGE_SYMBOL_N, + Value: DWORD, + SectionNumber: SHORT, + Type: WORD, + StorageClass: BYTE, + NumberOfAuxSymbols: BYTE, +}} +pub type PIMAGE_SYMBOL = *mut IMAGE_SYMBOL; +pub const IMAGE_SIZEOF_SYMBOL: usize = 18; +STRUCT!{struct IMAGE_SYMBOL_EX_N_Name { + Short: DWORD, + Long: DWORD, +}} +UNION!{union IMAGE_SYMBOL_EX_N { + [u32; 2], + ShortName ShortName_mut: [BYTE; 8], + Name Name_mut: IMAGE_SYMBOL_EX_N_Name, + LongName LongName_mut: [DWORD; 2], +}} +STRUCT!{struct IMAGE_SYMBOL_EX { + N: IMAGE_SYMBOL_EX_N, + Value: DWORD, + SectionNumber: LONG, + Type: WORD, + StorageClass: BYTE, + NumberOfAuxSymbols: BYTE, +}} +pub type PIMAGE_SYMBOL_EX = *mut IMAGE_SYMBOL_EX; +pub const IMAGE_SYM_UNDEFINED: SHORT = 0; +pub const IMAGE_SYM_ABSOLUTE: SHORT = -1; +pub const IMAGE_SYM_DEBUG: SHORT = -2; +pub const IMAGE_SYM_SECTION_MAX: USHORT = 0xFEFF; +pub const IMAGE_SYM_SECTION_MAX_EX: LONG = MAXLONG; +pub const IMAGE_SYM_TYPE_NULL: WORD = 0x0000; +pub const IMAGE_SYM_TYPE_VOID: WORD = 0x0001; +pub const IMAGE_SYM_TYPE_CHAR: WORD = 0x0002; +pub const IMAGE_SYM_TYPE_SHORT: WORD = 0x0003; +pub const IMAGE_SYM_TYPE_INT: WORD = 0x0004; +pub const IMAGE_SYM_TYPE_LONG: WORD = 0x0005; +pub const IMAGE_SYM_TYPE_FLOAT: WORD = 0x0006; +pub const IMAGE_SYM_TYPE_DOUBLE: WORD = 0x0007; +pub const IMAGE_SYM_TYPE_STRUCT: WORD = 0x0008; +pub const IMAGE_SYM_TYPE_UNION: WORD = 0x0009; +pub const IMAGE_SYM_TYPE_ENUM: WORD = 0x000A; +pub const IMAGE_SYM_TYPE_MOE: WORD = 0x000B; +pub const IMAGE_SYM_TYPE_BYTE: WORD = 0x000C; +pub const IMAGE_SYM_TYPE_WORD: WORD = 0x000D; +pub const IMAGE_SYM_TYPE_UINT: WORD = 0x000E; +pub const IMAGE_SYM_TYPE_DWORD: WORD = 0x000F; +pub const IMAGE_SYM_TYPE_PCODE: WORD = 0x8000; +pub const IMAGE_SYM_DTYPE_NULL: WORD = 0; +pub const IMAGE_SYM_DTYPE_POINTER: WORD = 1; +pub const IMAGE_SYM_DTYPE_FUNCTION: WORD = 2; +pub const IMAGE_SYM_DTYPE_ARRAY: WORD = 3; +pub const IMAGE_SYM_CLASS_END_OF_FUNCTION: BYTE = -1i8 as u8; +pub const IMAGE_SYM_CLASS_NULL: BYTE = 0x0000; +pub const IMAGE_SYM_CLASS_AUTOMATIC: BYTE = 0x0001; +pub const IMAGE_SYM_CLASS_EXTERNAL: BYTE = 0x0002; +pub const IMAGE_SYM_CLASS_STATIC: BYTE = 0x0003; +pub const IMAGE_SYM_CLASS_REGISTER: BYTE = 0x0004; +pub const IMAGE_SYM_CLASS_EXTERNAL_DEF: BYTE = 0x0005; +pub const IMAGE_SYM_CLASS_LABEL: BYTE = 0x0006; +pub const IMAGE_SYM_CLASS_UNDEFINED_LABEL: BYTE = 0x0007; +pub const IMAGE_SYM_CLASS_MEMBER_OF_STRUCT: BYTE = 0x0008; +pub const IMAGE_SYM_CLASS_ARGUMENT: BYTE = 0x0009; +pub const IMAGE_SYM_CLASS_STRUCT_TAG: BYTE = 0x000A; +pub const IMAGE_SYM_CLASS_MEMBER_OF_UNION: BYTE = 0x000B; +pub const IMAGE_SYM_CLASS_UNION_TAG: BYTE = 0x000C; +pub const IMAGE_SYM_CLASS_TYPE_DEFINITION: BYTE = 0x000D; +pub const IMAGE_SYM_CLASS_UNDEFINED_STATIC: BYTE = 0x000E; +pub const IMAGE_SYM_CLASS_ENUM_TAG: BYTE = 0x000F; +pub const IMAGE_SYM_CLASS_MEMBER_OF_ENUM: BYTE = 0x0010; +pub const IMAGE_SYM_CLASS_REGISTER_PARAM: BYTE = 0x0011; +pub const IMAGE_SYM_CLASS_BIT_FIELD: BYTE = 0x0012; +pub const IMAGE_SYM_CLASS_FAR_EXTERNAL: BYTE = 0x0044; +pub const IMAGE_SYM_CLASS_BLOCK: BYTE = 0x0064; +pub const IMAGE_SYM_CLASS_FUNCTION: BYTE = 0x0065; +pub const IMAGE_SYM_CLASS_END_OF_STRUCT: BYTE = 0x0066; +pub const IMAGE_SYM_CLASS_FILE: BYTE = 0x0067; +pub const IMAGE_SYM_CLASS_SECTION: BYTE = 0x0068; +pub const IMAGE_SYM_CLASS_WEAK_EXTERNAL: BYTE = 0x0069; +pub const IMAGE_SYM_CLASS_CLR_TOKEN: BYTE = 0x006B; +pub const N_BTMASK: WORD = 0x000F; +pub const N_TMASK: WORD = 0x0030; +pub const N_TMASK1: WORD = 0x00C0; +pub const N_TMASK2: WORD = 0x00F0; +pub const N_BTSHFT: usize = 4; +pub const N_TSHIFT: usize = 2; +#[inline] +pub fn BTYPE(x: WORD) -> bool { + (x & N_BTMASK) != 0 +} +#[inline] +pub fn ISPTR(x: WORD) -> bool { + (x & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) +} +#[inline] +pub fn ISFCN(x: WORD) -> bool { + (x & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT) +} +#[inline] +pub fn ISARY(x: WORD) -> bool { + (x & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT) +} +#[inline] +pub fn ISTAG(x: BYTE) -> bool { + (x == IMAGE_SYM_CLASS_STRUCT_TAG) || (x == IMAGE_SYM_CLASS_UNION_TAG) + || (x == IMAGE_SYM_CLASS_ENUM_TAG) +} +#[inline] +pub fn INCREF(x: WORD) -> WORD { + ((x & !N_BTMASK) << N_TSHIFT) | (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) | (x & N_BTMASK) +} +#[inline] +pub fn DECREF(x: WORD) -> WORD { + ((x >> N_TSHIFT) & !N_BTMASK) | (x & N_BTMASK) +} +STRUCT!{struct IMAGE_AUX_SYMBOL_TOKEN_DEF { + bAuxType: BYTE, + bReserved: BYTE, + SymbolTableIndex: DWORD, + rgbReserved: [BYTE; 12], +}} +pub type PIMAGE_AUX_SYMBOL_TOKEN_DEF = *mut IMAGE_AUX_SYMBOL_TOKEN_DEF; +STRUCT!{struct IMAGE_AUX_SYMBOL_Sym_Misc_LnSz { + Linenumber: WORD, + Size: WORD, +}} +UNION!{union IMAGE_AUX_SYMBOL_Sym_Misc { + [u32; 1], + LnSz LnSz_mut: IMAGE_AUX_SYMBOL_Sym_Misc_LnSz, + TotalSize TotalSize_mut: DWORD, +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_Sym_FcnAry_Function { + PointerToLinenumber: DWORD, + PointerToNextFunction: DWORD, +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_Sym_FcnAry_Array { + Dimension: [WORD; 4], +}} +UNION!{union IMAGE_AUX_SYMBOL_Sym_FcnAry { + [u32; 2], + Function Function_mut: IMAGE_AUX_SYMBOL_Sym_FcnAry_Function, + Array Array_mut: IMAGE_AUX_SYMBOL_Sym_FcnAry_Array, +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_Sym { + TagIndex: DWORD, + Misc: IMAGE_AUX_SYMBOL_Sym_Misc, + FcnAry: IMAGE_AUX_SYMBOL_Sym_FcnAry, + TvIndex: WORD, +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_File { + Name: [BYTE; IMAGE_SIZEOF_SYMBOL], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_Section { + Length: DWORD, + NumberOfRelocations: WORD, + NumberOfLinenumbers: WORD, + CheckSum: DWORD, + Number: SHORT, + Selection: BYTE, + bReserved: BYTE, + HighNumber: SHORT, +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_CRC { + crc: DWORD, + rgbReserved: [BYTE; 14], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL { + Sym: IMAGE_AUX_SYMBOL_Sym, + File: IMAGE_AUX_SYMBOL_File, + Section: IMAGE_AUX_SYMBOL_Section, + TokenDef: IMAGE_AUX_SYMBOL_TOKEN_DEF, + CRC: IMAGE_AUX_SYMBOL_CRC, +}} +pub type PIMAGE_AUX_SYMBOL = *mut IMAGE_AUX_SYMBOL; +STRUCT!{struct IMAGE_AUX_SYMBOL_EX_Sym { + WeakDefaultSymIndex: DWORD, + WeakSearchType: DWORD, + rgbReserved: [BYTE; 12], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_EX_File { + Name: [BYTE; 20], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_EX_Section { + Length: DWORD, + NumberOfRelocations: WORD, + NumberOfLinenumbers: WORD, + CheckSum: DWORD, + Number: SHORT, + Selection: BYTE, + bReserved: BYTE, + HighNumber: SHORT, + rgbReserved: [BYTE; 2], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_EX_s { + TokenDef: IMAGE_AUX_SYMBOL_TOKEN_DEF, + rgbReserved: [BYTE; 2], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_EX_CRC { + crc: DWORD, + rgbReserved: [BYTE; 16], +}} +STRUCT!{struct IMAGE_AUX_SYMBOL_EX { + Sym: IMAGE_AUX_SYMBOL_EX_Sym, + File: IMAGE_AUX_SYMBOL_EX_File, + Section: IMAGE_AUX_SYMBOL_EX_Section, + s: IMAGE_AUX_SYMBOL_EX_s, + CRC: IMAGE_AUX_SYMBOL_EX_CRC, +}} +pub type PIMAGE_AUX_SYMBOL_EX = *mut IMAGE_AUX_SYMBOL_EX; +ENUM!{enum IMAGE_AUX_SYMBOL_TYPE { + IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1, +}} +pub const IMAGE_COMDAT_SELECT_NODUPLICATES: BYTE = 1; +pub const IMAGE_COMDAT_SELECT_ANY: BYTE = 2; +pub const IMAGE_COMDAT_SELECT_SAME_SIZE: BYTE = 3; +pub const IMAGE_COMDAT_SELECT_EXACT_MATCH: BYTE = 4; +pub const IMAGE_COMDAT_SELECT_ASSOCIATIVE: BYTE = 5; +pub const IMAGE_COMDAT_SELECT_LARGEST: BYTE = 6; +pub const IMAGE_COMDAT_SELECT_NEWEST: BYTE = 7; +pub const IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY: BYTE = 1; +pub const IMAGE_WEAK_EXTERN_SEARCH_LIBRARY: BYTE = 2; +pub const IMAGE_WEAK_EXTERN_SEARCH_ALIAS: BYTE = 3; +UNION!{union IMAGE_RELOCATION_u { + [u32; 1], + VirtualAddress VirtualAddress_mut: DWORD, + RelocCount RelocCount_mut: DWORD, +}} +STRUCT!{struct IMAGE_RELOCATION { + u: IMAGE_RELOCATION_u, + SymbolTableIndex: DWORD, + Type: WORD, +}} +pub type PIMAGE_RELOCATION = *mut IMAGE_RELOCATION; +pub const IMAGE_REL_I386_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_I386_DIR16: WORD = 0x0001; +pub const IMAGE_REL_I386_REL16: WORD = 0x0002; +pub const IMAGE_REL_I386_DIR32: WORD = 0x0006; +pub const IMAGE_REL_I386_DIR32NB: WORD = 0x0007; +pub const IMAGE_REL_I386_SEG12: WORD = 0x0009; +pub const IMAGE_REL_I386_SECTION: WORD = 0x000A; +pub const IMAGE_REL_I386_SECREL: WORD = 0x000B; +pub const IMAGE_REL_I386_TOKEN: WORD = 0x000C; +pub const IMAGE_REL_I386_SECREL7: WORD = 0x000D; +pub const IMAGE_REL_I386_REL32: WORD = 0x0014; +pub const IMAGE_REL_MIPS_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_MIPS_REFHALF: WORD = 0x0001; +pub const IMAGE_REL_MIPS_REFWORD: WORD = 0x0002; +pub const IMAGE_REL_MIPS_JMPADDR: WORD = 0x0003; +pub const IMAGE_REL_MIPS_REFHI: WORD = 0x0004; +pub const IMAGE_REL_MIPS_REFLO: WORD = 0x0005; +pub const IMAGE_REL_MIPS_GPREL: WORD = 0x0006; +pub const IMAGE_REL_MIPS_LITERAL: WORD = 0x0007; +pub const IMAGE_REL_MIPS_SECTION: WORD = 0x000A; +pub const IMAGE_REL_MIPS_SECREL: WORD = 0x000B; +pub const IMAGE_REL_MIPS_SECRELLO: WORD = 0x000C; +pub const IMAGE_REL_MIPS_SECRELHI: WORD = 0x000D; +pub const IMAGE_REL_MIPS_TOKEN: WORD = 0x000E; +pub const IMAGE_REL_MIPS_JMPADDR16: WORD = 0x0010; +pub const IMAGE_REL_MIPS_REFWORDNB: WORD = 0x0022; +pub const IMAGE_REL_MIPS_PAIR: WORD = 0x0025; +pub const IMAGE_REL_ALPHA_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_ALPHA_REFLONG: WORD = 0x0001; +pub const IMAGE_REL_ALPHA_REFQUAD: WORD = 0x0002; +pub const IMAGE_REL_ALPHA_GPREL32: WORD = 0x0003; +pub const IMAGE_REL_ALPHA_LITERAL: WORD = 0x0004; +pub const IMAGE_REL_ALPHA_LITUSE: WORD = 0x0005; +pub const IMAGE_REL_ALPHA_GPDISP: WORD = 0x0006; +pub const IMAGE_REL_ALPHA_BRADDR: WORD = 0x0007; +pub const IMAGE_REL_ALPHA_HINT: WORD = 0x0008; +pub const IMAGE_REL_ALPHA_INLINE_REFLONG: WORD = 0x0009; +pub const IMAGE_REL_ALPHA_REFHI: WORD = 0x000A; +pub const IMAGE_REL_ALPHA_REFLO: WORD = 0x000B; +pub const IMAGE_REL_ALPHA_PAIR: WORD = 0x000C; +pub const IMAGE_REL_ALPHA_MATCH: WORD = 0x000D; +pub const IMAGE_REL_ALPHA_SECTION: WORD = 0x000E; +pub const IMAGE_REL_ALPHA_SECREL: WORD = 0x000F; +pub const IMAGE_REL_ALPHA_REFLONGNB: WORD = 0x0010; +pub const IMAGE_REL_ALPHA_SECRELLO: WORD = 0x0011; +pub const IMAGE_REL_ALPHA_SECRELHI: WORD = 0x0012; +pub const IMAGE_REL_ALPHA_REFQ3: WORD = 0x0013; +pub const IMAGE_REL_ALPHA_REFQ2: WORD = 0x0014; +pub const IMAGE_REL_ALPHA_REFQ1: WORD = 0x0015; +pub const IMAGE_REL_ALPHA_GPRELLO: WORD = 0x0016; +pub const IMAGE_REL_ALPHA_GPRELHI: WORD = 0x0017; +pub const IMAGE_REL_PPC_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_PPC_ADDR64: WORD = 0x0001; +pub const IMAGE_REL_PPC_ADDR32: WORD = 0x0002; +pub const IMAGE_REL_PPC_ADDR24: WORD = 0x0003; +pub const IMAGE_REL_PPC_ADDR16: WORD = 0x0004; +pub const IMAGE_REL_PPC_ADDR14: WORD = 0x0005; +pub const IMAGE_REL_PPC_REL24: WORD = 0x0006; +pub const IMAGE_REL_PPC_REL14: WORD = 0x0007; +pub const IMAGE_REL_PPC_TOCREL16: WORD = 0x0008; +pub const IMAGE_REL_PPC_TOCREL14: WORD = 0x0009; +pub const IMAGE_REL_PPC_ADDR32NB: WORD = 0x000A; +pub const IMAGE_REL_PPC_SECREL: WORD = 0x000B; +pub const IMAGE_REL_PPC_SECTION: WORD = 0x000C; +pub const IMAGE_REL_PPC_IFGLUE: WORD = 0x000D; +pub const IMAGE_REL_PPC_IMGLUE: WORD = 0x000E; +pub const IMAGE_REL_PPC_SECREL16: WORD = 0x000F; +pub const IMAGE_REL_PPC_REFHI: WORD = 0x0010; +pub const IMAGE_REL_PPC_REFLO: WORD = 0x0011; +pub const IMAGE_REL_PPC_PAIR: WORD = 0x0012; +pub const IMAGE_REL_PPC_SECRELLO: WORD = 0x0013; +pub const IMAGE_REL_PPC_SECRELHI: WORD = 0x0014; +pub const IMAGE_REL_PPC_GPREL: WORD = 0x0015; +pub const IMAGE_REL_PPC_TOKEN: WORD = 0x0016; +pub const IMAGE_REL_PPC_TYPEMASK: WORD = 0x00FF; +pub const IMAGE_REL_PPC_NEG: WORD = 0x0100; +pub const IMAGE_REL_PPC_BRTAKEN: WORD = 0x0200; +pub const IMAGE_REL_PPC_BRNTAKEN: WORD = 0x0400; +pub const IMAGE_REL_PPC_TOCDEFN: WORD = 0x0800; +pub const IMAGE_REL_SH3_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_SH3_DIRECT16: WORD = 0x0001; +pub const IMAGE_REL_SH3_DIRECT32: WORD = 0x0002; +pub const IMAGE_REL_SH3_DIRECT8: WORD = 0x0003; +pub const IMAGE_REL_SH3_DIRECT8_WORD: WORD = 0x0004; +pub const IMAGE_REL_SH3_DIRECT8_LONG: WORD = 0x0005; +pub const IMAGE_REL_SH3_DIRECT4: WORD = 0x0006; +pub const IMAGE_REL_SH3_DIRECT4_WORD: WORD = 0x0007; +pub const IMAGE_REL_SH3_DIRECT4_LONG: WORD = 0x0008; +pub const IMAGE_REL_SH3_PCREL8_WORD: WORD = 0x0009; +pub const IMAGE_REL_SH3_PCREL8_LONG: WORD = 0x000A; +pub const IMAGE_REL_SH3_PCREL12_WORD: WORD = 0x000B; +pub const IMAGE_REL_SH3_STARTOF_SECTION: WORD = 0x000C; +pub const IMAGE_REL_SH3_SIZEOF_SECTION: WORD = 0x000D; +pub const IMAGE_REL_SH3_SECTION: WORD = 0x000E; +pub const IMAGE_REL_SH3_SECREL: WORD = 0x000F; +pub const IMAGE_REL_SH3_DIRECT32_NB: WORD = 0x0010; +pub const IMAGE_REL_SH3_GPREL4_LONG: WORD = 0x0011; +pub const IMAGE_REL_SH3_TOKEN: WORD = 0x0012; +pub const IMAGE_REL_SHM_PCRELPT: WORD = 0x0013; +pub const IMAGE_REL_SHM_REFLO: WORD = 0x0014; +pub const IMAGE_REL_SHM_REFHALF: WORD = 0x0015; +pub const IMAGE_REL_SHM_RELLO: WORD = 0x0016; +pub const IMAGE_REL_SHM_RELHALF: WORD = 0x0017; +pub const IMAGE_REL_SHM_PAIR: WORD = 0x0018; +pub const IMAGE_REL_SH_NOMODE: WORD = 0x8000; +pub const IMAGE_REL_ARM_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_ARM_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_ARM_ADDR32NB: WORD = 0x0002; +pub const IMAGE_REL_ARM_BRANCH24: WORD = 0x0003; +pub const IMAGE_REL_ARM_BRANCH11: WORD = 0x0004; +pub const IMAGE_REL_ARM_TOKEN: WORD = 0x0005; +pub const IMAGE_REL_ARM_GPREL12: WORD = 0x0006; +pub const IMAGE_REL_ARM_GPREL7: WORD = 0x0007; +pub const IMAGE_REL_ARM_BLX24: WORD = 0x0008; +pub const IMAGE_REL_ARM_BLX11: WORD = 0x0009; +pub const IMAGE_REL_ARM_SECTION: WORD = 0x000E; +pub const IMAGE_REL_ARM_SECREL: WORD = 0x000F; +pub const IMAGE_REL_ARM_MOV32A: WORD = 0x0010; +pub const IMAGE_REL_ARM_MOV32: WORD = 0x0010; +pub const IMAGE_REL_ARM_MOV32T: WORD = 0x0011; +pub const IMAGE_REL_THUMB_MOV32: WORD = 0x0011; +pub const IMAGE_REL_ARM_BRANCH20T: WORD = 0x0012; +pub const IMAGE_REL_THUMB_BRANCH20: WORD = 0x0012; +pub const IMAGE_REL_ARM_BRANCH24T: WORD = 0x0014; +pub const IMAGE_REL_THUMB_BRANCH24: WORD = 0x0014; +pub const IMAGE_REL_ARM_BLX23T: WORD = 0x0015; +pub const IMAGE_REL_THUMB_BLX23: WORD = 0x0015; +pub const IMAGE_REL_AM_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_AM_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_AM_ADDR32NB: WORD = 0x0002; +pub const IMAGE_REL_AM_CALL32: WORD = 0x0003; +pub const IMAGE_REL_AM_FUNCINFO: WORD = 0x0004; +pub const IMAGE_REL_AM_REL32_1: WORD = 0x0005; +pub const IMAGE_REL_AM_REL32_2: WORD = 0x0006; +pub const IMAGE_REL_AM_SECREL: WORD = 0x0007; +pub const IMAGE_REL_AM_SECTION: WORD = 0x0008; +pub const IMAGE_REL_AM_TOKEN: WORD = 0x0009; +pub const IMAGE_REL_ARM64_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_ARM64_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_ARM64_ADDR32NB: WORD = 0x0002; +pub const IMAGE_REL_ARM64_BRANCH26: WORD = 0x0003; +pub const IMAGE_REL_ARM64_PAGEBASE_REL21: WORD = 0x0004; +pub const IMAGE_REL_ARM64_REL21: WORD = 0x0005; +pub const IMAGE_REL_ARM64_PAGEOFFSET_12A: WORD = 0x0006; +pub const IMAGE_REL_ARM64_PAGEOFFSET_12L: WORD = 0x0007; +pub const IMAGE_REL_ARM64_SECREL: WORD = 0x0008; +pub const IMAGE_REL_ARM64_SECREL_LOW12A: WORD = 0x0009; +pub const IMAGE_REL_ARM64_SECREL_HIGH12A: WORD = 0x000A; +pub const IMAGE_REL_ARM64_SECREL_LOW12L: WORD = 0x000B; +pub const IMAGE_REL_ARM64_TOKEN: WORD = 0x000C; +pub const IMAGE_REL_ARM64_SECTION: WORD = 0x000D; +pub const IMAGE_REL_ARM64_ADDR64: WORD = 0x000E; +pub const IMAGE_REL_ARM64_BRANCH19: WORD = 0x000F; +pub const IMAGE_REL_AMD64_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_AMD64_ADDR64: WORD = 0x0001; +pub const IMAGE_REL_AMD64_ADDR32: WORD = 0x0002; +pub const IMAGE_REL_AMD64_ADDR32NB: WORD = 0x0003; +pub const IMAGE_REL_AMD64_REL32: WORD = 0x0004; +pub const IMAGE_REL_AMD64_REL32_1: WORD = 0x0005; +pub const IMAGE_REL_AMD64_REL32_2: WORD = 0x0006; +pub const IMAGE_REL_AMD64_REL32_3: WORD = 0x0007; +pub const IMAGE_REL_AMD64_REL32_4: WORD = 0x0008; +pub const IMAGE_REL_AMD64_REL32_5: WORD = 0x0009; +pub const IMAGE_REL_AMD64_SECTION: WORD = 0x000A; +pub const IMAGE_REL_AMD64_SECREL: WORD = 0x000B; +pub const IMAGE_REL_AMD64_SECREL7: WORD = 0x000C; +pub const IMAGE_REL_AMD64_TOKEN: WORD = 0x000D; +pub const IMAGE_REL_AMD64_SREL32: WORD = 0x000E; +pub const IMAGE_REL_AMD64_PAIR: WORD = 0x000F; +pub const IMAGE_REL_AMD64_SSPAN32: WORD = 0x0010; +pub const IMAGE_REL_IA64_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_IA64_IMM14: WORD = 0x0001; +pub const IMAGE_REL_IA64_IMM22: WORD = 0x0002; +pub const IMAGE_REL_IA64_IMM64: WORD = 0x0003; +pub const IMAGE_REL_IA64_DIR32: WORD = 0x0004; +pub const IMAGE_REL_IA64_DIR64: WORD = 0x0005; +pub const IMAGE_REL_IA64_PCREL21B: WORD = 0x0006; +pub const IMAGE_REL_IA64_PCREL21M: WORD = 0x0007; +pub const IMAGE_REL_IA64_PCREL21F: WORD = 0x0008; +pub const IMAGE_REL_IA64_GPREL22: WORD = 0x0009; +pub const IMAGE_REL_IA64_LTOFF22: WORD = 0x000A; +pub const IMAGE_REL_IA64_SECTION: WORD = 0x000B; +pub const IMAGE_REL_IA64_SECREL22: WORD = 0x000C; +pub const IMAGE_REL_IA64_SECREL64I: WORD = 0x000D; +pub const IMAGE_REL_IA64_SECREL32: WORD = 0x000E; +pub const IMAGE_REL_IA64_DIR32NB: WORD = 0x0010; +pub const IMAGE_REL_IA64_SREL14: WORD = 0x0011; +pub const IMAGE_REL_IA64_SREL22: WORD = 0x0012; +pub const IMAGE_REL_IA64_SREL32: WORD = 0x0013; +pub const IMAGE_REL_IA64_UREL32: WORD = 0x0014; +pub const IMAGE_REL_IA64_PCREL60X: WORD = 0x0015; +pub const IMAGE_REL_IA64_PCREL60B: WORD = 0x0016; +pub const IMAGE_REL_IA64_PCREL60F: WORD = 0x0017; +pub const IMAGE_REL_IA64_PCREL60I: WORD = 0x0018; +pub const IMAGE_REL_IA64_PCREL60M: WORD = 0x0019; +pub const IMAGE_REL_IA64_IMMGPREL64: WORD = 0x001A; +pub const IMAGE_REL_IA64_TOKEN: WORD = 0x001B; +pub const IMAGE_REL_IA64_GPREL32: WORD = 0x001C; +pub const IMAGE_REL_IA64_ADDEND: WORD = 0x001F; +pub const IMAGE_REL_CEF_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_CEF_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_CEF_ADDR64: WORD = 0x0002; +pub const IMAGE_REL_CEF_ADDR32NB: WORD = 0x0003; +pub const IMAGE_REL_CEF_SECTION: WORD = 0x0004; +pub const IMAGE_REL_CEF_SECREL: WORD = 0x0005; +pub const IMAGE_REL_CEF_TOKEN: WORD = 0x0006; +pub const IMAGE_REL_CEE_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_CEE_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_CEE_ADDR64: WORD = 0x0002; +pub const IMAGE_REL_CEE_ADDR32NB: WORD = 0x0003; +pub const IMAGE_REL_CEE_SECTION: WORD = 0x0004; +pub const IMAGE_REL_CEE_SECREL: WORD = 0x0005; +pub const IMAGE_REL_CEE_TOKEN: WORD = 0x0006; +pub const IMAGE_REL_M32R_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_M32R_ADDR32: WORD = 0x0001; +pub const IMAGE_REL_M32R_ADDR32NB: WORD = 0x0002; +pub const IMAGE_REL_M32R_ADDR24: WORD = 0x0003; +pub const IMAGE_REL_M32R_GPREL16: WORD = 0x0004; +pub const IMAGE_REL_M32R_PCREL24: WORD = 0x0005; +pub const IMAGE_REL_M32R_PCREL16: WORD = 0x0006; +pub const IMAGE_REL_M32R_PCREL8: WORD = 0x0007; +pub const IMAGE_REL_M32R_REFHALF: WORD = 0x0008; +pub const IMAGE_REL_M32R_REFHI: WORD = 0x0009; +pub const IMAGE_REL_M32R_REFLO: WORD = 0x000A; +pub const IMAGE_REL_M32R_PAIR: WORD = 0x000B; +pub const IMAGE_REL_M32R_SECTION: WORD = 0x000C; +pub const IMAGE_REL_M32R_SECREL32: WORD = 0x000D; +pub const IMAGE_REL_M32R_TOKEN: WORD = 0x000E; +pub const IMAGE_REL_EBC_ABSOLUTE: WORD = 0x0000; +pub const IMAGE_REL_EBC_ADDR32NB: WORD = 0x0001; +pub const IMAGE_REL_EBC_REL32: WORD = 0x0002; +pub const IMAGE_REL_EBC_SECTION: WORD = 0x0003; +pub const IMAGE_REL_EBC_SECREL: WORD = 0x0004; +UNION!{union IMAGE_LINENUMBER_Type { + [u32; 1], + SymbolTableIndex SymbolTableIndex_mut: DWORD, + VirtualAddress VirtualAddress_mut: DWORD, +}} +STRUCT!{struct IMAGE_LINENUMBER { + Type: IMAGE_LINENUMBER_Type, + Linenumber: WORD, +}} +pub type PIMAGE_LINENUMBER = *mut IMAGE_LINENUMBER; +STRUCT!{struct IMAGE_BASE_RELOCATION { + VirtualAddress: DWORD, + SizeOfBlock: DWORD, +}} +pub type PIMAGE_BASE_RELOCATION = *mut IMAGE_BASE_RELOCATION; +pub const IMAGE_REL_BASED_ABSOLUTE: WORD = 0; +pub const IMAGE_REL_BASED_HIGH: WORD = 1; +pub const IMAGE_REL_BASED_LOW: WORD = 2; +pub const IMAGE_REL_BASED_HIGHLOW: WORD = 3; +pub const IMAGE_REL_BASED_HIGHADJ: WORD = 4; +pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_5: WORD = 5; +pub const IMAGE_REL_BASED_RESERVED: WORD = 6; +pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_7: WORD = 7; +pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_8: WORD = 8; +pub const IMAGE_REL_BASED_MACHINE_SPECIFIC_9: WORD = 9; +pub const IMAGE_REL_BASED_DIR64: WORD = 10; +pub const IMAGE_REL_BASED_IA64_IMM64: WORD = 9; +pub const IMAGE_REL_BASED_MIPS_JMPADDR: WORD = 5; +pub const IMAGE_REL_BASED_MIPS_JMPADDR16: WORD = 9; +pub const IMAGE_REL_BASED_ARM_MOV32: WORD = 5; +pub const IMAGE_REL_BASED_THUMB_MOV32: WORD = 7; +pub const IMAGE_ARCHIVE_START_SIZE: usize = 8; +pub const IMAGE_ARCHIVE_START: &'static str = "!<arch>\n"; +pub const IMAGE_ARCHIVE_END: &'static str = "`\n"; +pub const IMAGE_ARCHIVE_PAD: &'static str = "\n"; +pub const IMAGE_ARCHIVE_LINKER_MEMBER: &'static str = "/ "; +pub const IMAGE_ARCHIVE_LONGNAMES_MEMBER: &'static str = "// "; +pub const IMAGE_ARCHIVE_HYBRIDMAP_MEMBER: &'static str = "/<HYBRIDMAP>/ "; +STRUCT!{struct IMAGE_ARCHIVE_MEMBER_HEADER { + Name: [BYTE; 16], + Date: [BYTE; 12], + UserID: [BYTE; 6], + GroupID: [BYTE; 6], + Mode: [BYTE; 8], + Size: [BYTE; 10], + EndHeader: [BYTE; 2], +}} +pub type PIMAGE_ARCHIVE_MEMBER_HEADER = *mut IMAGE_ARCHIVE_MEMBER_HEADER; +pub const IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR: usize = 60; +STRUCT!{struct IMAGE_EXPORT_DIRECTORY { + Characteristics: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + Name: DWORD, + Base: DWORD, + NumberOfFunctions: DWORD, + NumberOfNames: DWORD, + AddressOfFunctions: DWORD, + AddressOfNames: DWORD, + AddressOfNameOrdinals: DWORD, +}} +pub type PIMAGE_EXPORT_DIRECTORY = *mut IMAGE_EXPORT_DIRECTORY; +STRUCT!{struct IMAGE_IMPORT_BY_NAME { + Hint: WORD, + Name: [CHAR; 1], +}} +pub type PIMAGE_IMPORT_BY_NAME = *mut IMAGE_IMPORT_BY_NAME; +UNION!{union IMAGE_THUNK_DATA64_u1 { + [u64; 1], + ForwarderString ForwarderString_mut: ULONGLONG, + Function Function_mut: ULONGLONG, + Ordinal Ordinal_mut: ULONGLONG, + AddressOfData AddressOfData_mut: ULONGLONG, +}} +STRUCT!{struct IMAGE_THUNK_DATA64 { + u1: IMAGE_THUNK_DATA64_u1, +}} +pub type PIMAGE_THUNK_DATA64 = *mut IMAGE_THUNK_DATA64; +UNION!{union IMAGE_THUNK_DATA32_u1 { + [u32; 1], + ForwarderString ForwarderString_mut: DWORD, + Function Function_mut: DWORD, + Ordinal Ordinal_mut: DWORD, + AddressOfData AddressOfData_mut: DWORD, +}} +STRUCT!{struct IMAGE_THUNK_DATA32 { + u1: IMAGE_THUNK_DATA32_u1, +}} +pub type PIMAGE_THUNK_DATA32 = *mut IMAGE_THUNK_DATA32; +pub const IMAGE_ORDINAL_FLAG64: ULONGLONG = 0x8000000000000000; +pub const IMAGE_ORDINAL_FLAG32: DWORD = 0x80000000; +#[inline] +pub fn IMAGE_ORDINAL64(Ordinal: ULONGLONG) -> ULONGLONG { + Ordinal & 0xffff +} +#[inline] +pub fn IMAGE_ORDINAL32(Ordinal: DWORD) -> DWORD { + Ordinal & 0xffff +} +#[inline] +pub fn IMAGE_SNAP_BY_ORDINAL64(Ordinal: ULONGLONG) -> bool { + (Ordinal & IMAGE_ORDINAL_FLAG64) != 0 +} +#[inline] +pub fn IMAGE_SNAP_BY_ORDINAL32(Ordinal: DWORD) -> bool { + (Ordinal & IMAGE_ORDINAL_FLAG32) != 0 +} +FN!{stdcall PIMAGE_TLS_CALLBACK( + DllHandle: PVOID, + Reason: DWORD, + Reserved: PVOID, +) -> ()} +STRUCT!{struct IMAGE_TLS_DIRECTORY64 { + StartAddressOfRawData: ULONGLONG, + EndAddressOfRawData: ULONGLONG, + AddressOfIndex: ULONGLONG, + AddressOfCallBacks: ULONGLONG, + SizeOfZeroFill: DWORD, + Characteristics: DWORD, +}} +BITFIELD!{IMAGE_TLS_DIRECTORY64 Characteristics: DWORD [ + Reserved0 set_Reserved0[0..20], + Alignment set_Alignment[20..24], + Reserved1 set_Reserved1[24..32], +]} +pub type PIMAGE_TLS_DIRECTORY64 = *mut IMAGE_TLS_DIRECTORY64; +STRUCT!{struct IMAGE_TLS_DIRECTORY32 { + StartAddressOfRawData: DWORD, + EndAddressOfRawData: DWORD, + AddressOfIndex: DWORD, + AddressOfCallBacks: DWORD, + SizeOfZeroFill: DWORD, + Characteristics: DWORD, +}} +BITFIELD!{IMAGE_TLS_DIRECTORY32 Characteristics: DWORD [ + Reserved0 set_Reserved0[0..20], + Alignment set_Alignment[20..24], + Reserved1 set_Reserved1[24..32], +]} +pub type PIMAGE_TLS_DIRECTORY32 = *mut IMAGE_TLS_DIRECTORY32; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub const IMAGE_ORDINAL_FLAG: ULONGLONG = IMAGE_ORDINAL_FLAG64; +#[inline] +pub fn IMAGE_ORDINAL(Ordinal: ULONGLONG) -> ULONGLONG { + IMAGE_ORDINAL64(Ordinal) +} +pub type IMAGE_THUNK_DATA = IMAGE_THUNK_DATA64; +pub type PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA64; +#[inline] +pub fn IMAGE_SNAP_BY_ORDINAL(Ordinal: ULONGLONG) -> bool { + IMAGE_SNAP_BY_ORDINAL64(Ordinal) +} +pub type IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY64; +pub type PIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY64; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +pub const IMAGE_ORDINAL_FLAG: DWORD = IMAGE_ORDINAL_FLAG32; +#[inline] +pub fn IMAGE_ORDINAL(Ordinal: DWORD) -> DWORD { + IMAGE_ORDINAL32(Ordinal) +} +pub type IMAGE_THUNK_DATA = IMAGE_THUNK_DATA32; +pub type PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA32; +#[inline] +pub fn IMAGE_SNAP_BY_ORDINAL(Ordinal: DWORD) -> bool { + IMAGE_SNAP_BY_ORDINAL32(Ordinal) +} +pub type IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY32; +pub type PIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY32; +} +UNION!{union IMAGE_IMPORT_DESCRIPTOR_u { + [u32; 1], + Characteristics Characteristics_mut: DWORD, + OriginalFirstThunk OriginalFirstThunk_mut: DWORD, +}} +STRUCT!{struct IMAGE_IMPORT_DESCRIPTOR { + u: IMAGE_IMPORT_DESCRIPTOR_u, + TimeDateStamp: DWORD, + ForwarderChain: DWORD, + Name: DWORD, + FirstThunk: DWORD, +}} +pub type PIMAGE_IMPORT_DESCRIPTOR = *mut IMAGE_IMPORT_DESCRIPTOR; +STRUCT!{struct IMAGE_BOUND_IMPORT_DESCRIPTOR { + TimeDateStamp: DWORD, + OffsetModuleName: WORD, + NumberOfModuleForwarderRefs: WORD, +}} +pub type PIMAGE_BOUND_IMPORT_DESCRIPTOR = *mut IMAGE_BOUND_IMPORT_DESCRIPTOR; +STRUCT!{struct IMAGE_BOUND_FORWARDER_REF { + TimeDateStamp: DWORD, + OffsetModuleName: WORD, + Reserved: WORD, +}} +pub type PIMAGE_BOUND_FORWARDER_REF = *mut IMAGE_BOUND_FORWARDER_REF; +STRUCT!{struct IMAGE_DELAYLOAD_DESCRIPTOR_Attributes { + AllAttributes: DWORD, +}} +BITFIELD!{IMAGE_DELAYLOAD_DESCRIPTOR_Attributes AllAttributes: DWORD [ + RvaBased set_RvaBased[0..1], + ReservedAttributes set_ReservedAttributes[1..32], +]} +STRUCT!{struct IMAGE_DELAYLOAD_DESCRIPTOR { + Attributes: IMAGE_DELAYLOAD_DESCRIPTOR_Attributes, + DllNameRVA: DWORD, + ModuleHandleRVA: DWORD, + ImportAddressTableRVA: DWORD, + ImportNameTableRVA: DWORD, + BoundImportAddressTableRVA: DWORD, + UnloadInformationTableRVA: DWORD, + TimeDateStamp: DWORD, +}} +pub type PIMAGE_DELAYLOAD_DESCRIPTOR = *mut IMAGE_DELAYLOAD_DESCRIPTOR; +pub type PCIMAGE_DELAYLOAD_DESCRIPTOR = *const IMAGE_DELAYLOAD_DESCRIPTOR; +STRUCT!{struct IMAGE_RESOURCE_DIRECTORY { + Characteristics: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + NumberOfNamedEntries: WORD, + NumberOfIdEntries: WORD, +}} +pub type PIMAGE_RESOURCE_DIRECTORY = *mut IMAGE_RESOURCE_DIRECTORY; +pub const IMAGE_RESOURCE_NAME_IS_STRING: DWORD = 0x80000000; +pub const IMAGE_RESOURCE_DATA_IS_DIRECTORY: DWORD = 0x80000000; +STRUCT!{struct IMAGE_RESOURCE_DIRECTORY_ENTRY_u_s { + BitFields: DWORD, +}} +BITFIELD!{IMAGE_RESOURCE_DIRECTORY_ENTRY_u_s BitFields: DWORD [ + NameOffset set_NameOffset[0..31], + NameIsString set_NameIsString[31..32], +]} +UNION!{union IMAGE_RESOURCE_DIRECTORY_ENTRY_u { + [u32; 1], + s s_mut: IMAGE_RESOURCE_DIRECTORY_ENTRY_u_s, + Name Name_mut: DWORD, + Id Id_mut: WORD, +}} +STRUCT!{struct IMAGE_RESOURCE_DIRECTORY_ENTRY { + u: IMAGE_RESOURCE_DIRECTORY_ENTRY_u, + OffsetToData: DWORD, +}} +BITFIELD!{IMAGE_RESOURCE_DIRECTORY_ENTRY OffsetToData: DWORD [ + OffsetToDirectory set_OffsetToDirectory[0..31], + DataIsDirectory set_DataIsDirectory[31..32], +]} +pub type PIMAGE_RESOURCE_DIRECTORY_ENTRY = *mut IMAGE_RESOURCE_DIRECTORY_ENTRY; +STRUCT!{struct IMAGE_RESOURCE_DIRECTORY_STRING { + Length: WORD, + NameString: [CHAR; 1], +}} +pub type PIMAGE_RESOURCE_DIRECTORY_STRING = *mut IMAGE_RESOURCE_DIRECTORY_STRING; +STRUCT!{struct IMAGE_RESOURCE_DIR_STRING_U { + Length: WORD, + NameString: [WCHAR; 1], +}} +pub type PIMAGE_RESOURCE_DIR_STRING_U = *mut IMAGE_RESOURCE_DIR_STRING_U; +STRUCT!{struct IMAGE_RESOURCE_DATA_ENTRY { + OffsetToData: DWORD, + Size: DWORD, + CodePage: DWORD, + Reserved: DWORD, +}} +pub type PIMAGE_RESOURCE_DATA_ENTRY = *mut IMAGE_RESOURCE_DATA_ENTRY; +STRUCT!{struct IMAGE_LOAD_CONFIG_CODE_INTEGRITY { + Flags: WORD, + Catalog: WORD, + CatalogOffset: DWORD, + Reserved: DWORD, +}} +pub type PIMAGE_LOAD_CONFIG_CODE_INTEGRITY = *mut IMAGE_LOAD_CONFIG_CODE_INTEGRITY; +STRUCT!{struct IMAGE_DYNAMIC_RELOCATION_TABLE { + Version: DWORD, + Size: DWORD, +}} +pub type PIMAGE_DYNAMIC_RELOCATION_TABLE = *mut IMAGE_DYNAMIC_RELOCATION_TABLE; +STRUCT!{#[repr(packed)] struct IMAGE_DYNAMIC_RELOCATION32 { + Symbol: DWORD, + BaseRelocSize: DWORD, +}} +pub type PIMAGE_DYNAMIC_RELOCATION32 = *mut IMAGE_DYNAMIC_RELOCATION32; +STRUCT!{#[repr(packed)] struct IMAGE_DYNAMIC_RELOCATION64 { + Symbol: ULONGLONG, + BaseRelocSize: DWORD, +}} +pub type PIMAGE_DYNAMIC_RELOCATION64 = *mut IMAGE_DYNAMIC_RELOCATION64; +STRUCT!{#[repr(packed)] struct IMAGE_DYNAMIC_RELOCATION32_V2 { + HeaderSize: DWORD, + FixupInfoSize: DWORD, + Symbol: DWORD, + SymbolGroup: DWORD, + Flags: DWORD, +}} +pub type PIMAGE_DYNAMIC_RELOCATION32_V2 = *mut IMAGE_DYNAMIC_RELOCATION32_V2; +STRUCT!{#[repr(packed)] struct IMAGE_DYNAMIC_RELOCATION64_V2 { + HeaderSize: DWORD, + FixupInfoSize: DWORD, + Symbol: ULONGLONG, + SymbolGroup: DWORD, + Flags: DWORD, +}} +pub type PIMAGE_DYNAMIC_RELOCATION64_V2 = *mut IMAGE_DYNAMIC_RELOCATION64_V2; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub type IMAGE_DYNAMIC_RELOCATION = IMAGE_DYNAMIC_RELOCATION64; +pub type PIMAGE_DYNAMIC_RELOCATION = PIMAGE_DYNAMIC_RELOCATION64; +pub type IMAGE_DYNAMIC_RELOCATION_V2 = IMAGE_DYNAMIC_RELOCATION64_V2; +pub type PIMAGE_DYNAMIC_RELOCATION_V2 = PIMAGE_DYNAMIC_RELOCATION64_V2; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +pub type IMAGE_DYNAMIC_RELOCATION = IMAGE_DYNAMIC_RELOCATION32; +pub type PIMAGE_DYNAMIC_RELOCATION = PIMAGE_DYNAMIC_RELOCATION32; +pub type IMAGE_DYNAMIC_RELOCATION_V2 = IMAGE_DYNAMIC_RELOCATION32_V2; +pub type PIMAGE_DYNAMIC_RELOCATION_V2 = PIMAGE_DYNAMIC_RELOCATION32_V2; +} +pub const IMAGE_DYNAMIC_RELOCATION_GUARD_RF_PROLOGUE: DWORD = 0x00000001; +pub const IMAGE_DYNAMIC_RELOCATION_GUARD_RF_EPILOGUE: DWORD = 0x00000002; +STRUCT!{#[repr(packed)] struct IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER { + PrologueByteCount: BYTE, +}} +pub type PIMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER = *mut IMAGE_PROLOGUE_DYNAMIC_RELOCATION_HEADER; +STRUCT!{#[repr(packed)] struct IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER { + EpilogueCount: DWORD, + EpilogueByteCount: BYTE, + BranchDescriptorElementSize: BYTE, + BranchDescriptorCount: WORD, +}} +pub type PIMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER = *mut IMAGE_EPILOGUE_DYNAMIC_RELOCATION_HEADER; +STRUCT!{struct IMAGE_LOAD_CONFIG_DIRECTORY32 { + Size: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + GlobalFlagsClear: DWORD, + GlobalFlagsSet: DWORD, + CriticalSectionDefaultTimeout: DWORD, + DeCommitFreeBlockThreshold: DWORD, + DeCommitTotalFreeThreshold: DWORD, + LockPrefixTable: DWORD, + MaximumAllocationSize: DWORD, + VirtualMemoryThreshold: DWORD, + ProcessHeapFlags: DWORD, + ProcessAffinityMask: DWORD, + CSDVersion: WORD, + DependentLoadFlags: WORD, + EditList: DWORD, + SecurityCookie: DWORD, + SEHandlerTable: DWORD, + SEHandlerCount: DWORD, + GuardCFCheckFunctionPointer: DWORD, + GuardCFDispatchFunctionPointer: DWORD, + GuardCFFunctionTable: DWORD, + GuardCFFunctionCount: DWORD, + GuardFlags: DWORD, + CodeIntegrity: IMAGE_LOAD_CONFIG_CODE_INTEGRITY, + GuardAddressTakenIatEntryTable: DWORD, + GuardAddressTakenIatEntryCount: DWORD, + GuardLongJumpTargetTable: DWORD, + GuardLongJumpTargetCount: DWORD, + DynamicValueRelocTable: DWORD, + CHPEMetadataPointer: DWORD, + GuardRFFailureRoutine: DWORD, + GuardRFFailureRoutineFunctionPointer: DWORD, + DynamicValueRelocTableOffset: DWORD, + DynamicValueRelocTableSection: WORD, + Reserved2: WORD, + GuardRFVerifyStackPointerFunctionPointer: DWORD, + HotPatchTableOffset: DWORD, + Reserved3: DWORD, + EnclaveConfigurationPointer: DWORD, +}} +pub type PIMAGE_LOAD_CONFIG_DIRECTORY32 = *mut IMAGE_LOAD_CONFIG_DIRECTORY32; +STRUCT!{struct IMAGE_LOAD_CONFIG_DIRECTORY64 { + Size: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + GlobalFlagsClear: DWORD, + GlobalFlagsSet: DWORD, + CriticalSectionDefaultTimeout: DWORD, + DeCommitFreeBlockThreshold: ULONGLONG, + DeCommitTotalFreeThreshold: ULONGLONG, + LockPrefixTable: ULONGLONG, + MaximumAllocationSize: ULONGLONG, + VirtualMemoryThreshold: ULONGLONG, + ProcessAffinityMask: ULONGLONG, + ProcessHeapFlags: DWORD, + CSDVersion: WORD, + DependentLoadFlags: WORD, + EditList: ULONGLONG, + SecurityCookie: ULONGLONG, + SEHandlerTable: ULONGLONG, + SEHandlerCount: ULONGLONG, + GuardCFCheckFunctionPointer: ULONGLONG, + GuardCFDispatchFunctionPointer: ULONGLONG, + GuardCFFunctionTable: ULONGLONG, + GuardCFFunctionCount: ULONGLONG, + GuardFlags: DWORD, + CodeIntegrity: IMAGE_LOAD_CONFIG_CODE_INTEGRITY, + GuardAddressTakenIatEntryTable: ULONGLONG, + GuardAddressTakenIatEntryCount: ULONGLONG, + GuardLongJumpTargetTable: ULONGLONG, + GuardLongJumpTargetCount: ULONGLONG, + DynamicValueRelocTable: ULONGLONG, + CHPEMetadataPointer: ULONGLONG, + GuardRFFailureRoutine: ULONGLONG, + GuardRFFailureRoutineFunctionPointer: ULONGLONG, + DynamicValueRelocTableOffset: DWORD, + DynamicValueRelocTableSection: WORD, + Reserved2: WORD, + GuardRFVerifyStackPointerFunctionPointer: ULONGLONG, + HotPatchTableOffset: DWORD, + Reserved3: DWORD, + EnclaveConfigurationPointer: ULONGLONG, +}} +pub type PIMAGE_LOAD_CONFIG_DIRECTORY64 = *mut IMAGE_LOAD_CONFIG_DIRECTORY64; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +pub type IMAGE_LOAD_CONFIG_DIRECTORY = IMAGE_LOAD_CONFIG_DIRECTORY64; +pub type PIMAGE_LOAD_CONFIG_DIRECTORY = PIMAGE_LOAD_CONFIG_DIRECTORY64; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +pub type IMAGE_LOAD_CONFIG_DIRECTORY = IMAGE_LOAD_CONFIG_DIRECTORY32; +pub type PIMAGE_LOAD_CONFIG_DIRECTORY = PIMAGE_LOAD_CONFIG_DIRECTORY32; +} +STRUCT!{struct IMAGE_HOT_PATCH_INFO { + Version: DWORD, + Size: DWORD, + SequenceNumber: DWORD, + BaseImageList: DWORD, + BaseImageCount: DWORD, + BufferOffset: DWORD, +}} +pub type PIMAGE_HOT_PATCH_INFO = *mut IMAGE_HOT_PATCH_INFO; +STRUCT!{struct IMAGE_HOT_PATCH_BASE { + SequenceNumber: DWORD, + Flags: DWORD, + OriginalTimeDateStamp: DWORD, + OriginalCheckSum: DWORD, + CodeIntegrityInfo: DWORD, + CodeIntegritySize: DWORD, + PatchTable: DWORD, + BufferOffset: DWORD, +}} +pub type PIMAGE_HOT_PATCH_BASE = *mut IMAGE_HOT_PATCH_BASE; +STRUCT!{struct IMAGE_HOT_PATCH_HASHES { + SHA256: [BYTE; 32], + SHA1: [BYTE; 20], +}} +pub type PIMAGE_HOT_PATCH_HASHES = *mut IMAGE_HOT_PATCH_HASHES; +pub const IMAGE_HOT_PATCH_BASE_OBLIGATORY: DWORD = 0x00000001; +pub const IMAGE_HOT_PATCH_CHUNK_INVERSE: DWORD = 0x80000000; +pub const IMAGE_HOT_PATCH_CHUNK_OBLIGATORY: DWORD = 0x40000000; +pub const IMAGE_HOT_PATCH_CHUNK_RESERVED: DWORD = 0x3FF03000; +pub const IMAGE_HOT_PATCH_CHUNK_TYPE: DWORD = 0x000FC000; +pub const IMAGE_HOT_PATCH_CHUNK_SOURCE_RVA: DWORD = 0x00008000; +pub const IMAGE_HOT_PATCH_CHUNK_TARGET_RVA: DWORD = 0x00004000; +pub const IMAGE_HOT_PATCH_CHUNK_SIZE: DWORD = 0x00000FFF; +pub const IMAGE_HOT_PATCH_NONE: DWORD = 0x00000000; +pub const IMAGE_HOT_PATCH_FUNCTION: DWORD = 0x0001C000; +pub const IMAGE_HOT_PATCH_ABSOLUTE: DWORD = 0x0002C000; +pub const IMAGE_HOT_PATCH_REL32: DWORD = 0x0003C000; +pub const IMAGE_HOT_PATCH_CALL_TARGET: DWORD = 0x00044000; +pub const IMAGE_HOT_PATCH_INDIRECT: DWORD = 0x0005C000; +pub const IMAGE_HOT_PATCH_NO_CALL_TARGET: DWORD = 0x00064000; +pub const IMAGE_HOT_PATCH_DYNAMIC_VALUE: DWORD = 0x00078000; +pub const IMAGE_GUARD_CF_INSTRUMENTED: DWORD = 0x00000100; +pub const IMAGE_GUARD_CFW_INSTRUMENTED: DWORD = 0x00000200; +pub const IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT: DWORD = 0x00000400; +pub const IMAGE_GUARD_SECURITY_COOKIE_UNUSED: DWORD = 0x00000800; +pub const IMAGE_GUARD_PROTECT_DELAYLOAD_IAT: DWORD = 0x00001000; +pub const IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION: DWORD = 0x00002000; +pub const IMAGE_GUARD_CF_EXPORT_SUPPRESSION_INFO_PRESENT: DWORD = 0x00004000; +pub const IMAGE_GUARD_CF_ENABLE_EXPORT_SUPPRESSION: DWORD = 0x00008000; +pub const IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT: DWORD = 0x00010000; +pub const IMAGE_GUARD_RF_INSTRUMENTED: DWORD = 0x00020000; +pub const IMAGE_GUARD_RF_ENABLE: DWORD = 0x00040000; +pub const IMAGE_GUARD_RF_STRICT: DWORD = 0x00080000; +pub const IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK: DWORD = 0xF0000000; +pub const IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT: usize = 28; +pub const IMAGE_GUARD_FLAG_FID_SUPPRESSED: DWORD = 0x01; +pub const IMAGE_GUARD_FLAG_EXPORT_SUPPRESSED: DWORD = 0x02; +STRUCT!{struct IMAGE_CE_RUNTIME_FUNCTION_ENTRY { + FuncStart: DWORD, + BitFields: DWORD, +}} +BITFIELD!{IMAGE_CE_RUNTIME_FUNCTION_ENTRY BitFields: DWORD [ + PrologLen set_PrologLen[0..8], + FuncLen set_FuncLen[8..30], + ThirtyTwoBit set_ThirtyTwoBit[30..31], + ExceptionFlag set_ExceptionFlag[31..32], +]} +pub type PIMAGE_CE_RUNTIME_FUNCTION_ENTRY = *mut IMAGE_CE_RUNTIME_FUNCTION_ENTRY; +STRUCT!{struct IMAGE_ARM_RUNTIME_FUNCTION_ENTRY { + BeginAddress: DWORD, + UnwindData: DWORD, +}} +BITFIELD!{IMAGE_ARM_RUNTIME_FUNCTION_ENTRY UnwindData: DWORD [ + Flag set_Flag[0..2], + FunctionLength set_FunctionLength[2..13], + Ret set_Ret[13..15], + H set_H[15..16], + Reg set_Reg[16..19], + R set_R[19..20], + L set_L[20..21], + C set_c[21..22], + StackAdjust set_StackAdjust[22..32], +]} +pub type PIMAGE_ARM_RUNTIME_FUNCTION_ENTRY = *mut IMAGE_ARM_RUNTIME_FUNCTION_ENTRY; +STRUCT!{struct IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY { + BeginAddress: DWORD, + UnwindData: DWORD, +}} +BITFIELD!{IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY UnwindData: DWORD [ + Flag set_Flag[0..2], + FunctionLength set_FunctionLength[2..13], + RegF set_RegF[13..16], + RegI set_RegI[16..20], + H set_H[20..21], + CR set_cR[21..23], + FrameSize set_FrameSize[23..32], +]} +pub type PIMAGE_ARM64_RUNTIME_FUNCTION_ENTRY = *mut IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY; +STRUCT!{struct IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY { + BeginAddress: ULONGLONG, + EndAddress: ULONGLONG, + ExceptionHandler: ULONGLONG, + HandlerData: ULONGLONG, + PrologEndAddress: ULONGLONG, +}} +pub type PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY = *mut IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY; +STRUCT!{struct IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY { + BeginAddress: DWORD, + EndAddress: DWORD, + ExceptionHandler: DWORD, + HandlerData: DWORD, + PrologEndAddress: DWORD, +}} +pub type PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY = *mut IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY; +UNION!{union IMAGE_RUNTIME_FUNCTION_ENTRY_u { + [u32; 1], + UnwindInfoAddress UnwindInfoAddress_mut: DWORD, + UnwindData UnwindData_mut: DWORD, +}} +STRUCT!{struct _IMAGE_RUNTIME_FUNCTION_ENTRY { + BeginAddress: DWORD, + EndAddress: DWORD, + u: IMAGE_RUNTIME_FUNCTION_ENTRY_u, +}} +type _PIMAGE_RUNTIME_FUNCTION_ENTRY = *mut _IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type IMAGE_IA64_RUNTIME_FUNCTION_ENTRY = _IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY = _PIMAGE_RUNTIME_FUNCTION_ENTRY; +#[cfg(target_arch = "aarch64")] +IFDEF!{ +pub type IMAGE_RUNTIME_FUNCTION_ENTRY = IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY; +pub type PIMAGE_RUNTIME_FUNCTION_ENTRY = PIMAGE_ARM64_RUNTIME_FUNCTION_ENTRY; +} +#[cfg(not(target_arch = "aarch64"))] +IFDEF!{ +pub type IMAGE_RUNTIME_FUNCTION_ENTRY = _IMAGE_RUNTIME_FUNCTION_ENTRY; +pub type PIMAGE_RUNTIME_FUNCTION_ENTRY = _PIMAGE_RUNTIME_FUNCTION_ENTRY; +} +STRUCT!{struct IMAGE_DEBUG_DIRECTORY { + Characteristics: DWORD, + TimeDateStamp: DWORD, + MajorVersion: WORD, + MinorVersion: WORD, + Type: DWORD, + SizeOfData: DWORD, + AddressOfRawData: DWORD, + PointerToRawData: DWORD, +}} +pub type PIMAGE_DEBUG_DIRECTORY = *mut IMAGE_DEBUG_DIRECTORY; +pub const IMAGE_DEBUG_TYPE_UNKNOWN: DWORD = 0; +pub const IMAGE_DEBUG_TYPE_COFF: DWORD = 1; +pub const IMAGE_DEBUG_TYPE_CODEVIEW: DWORD = 2; +pub const IMAGE_DEBUG_TYPE_FPO: DWORD = 3; +pub const IMAGE_DEBUG_TYPE_MISC: DWORD = 4; +pub const IMAGE_DEBUG_TYPE_EXCEPTION: DWORD = 5; +pub const IMAGE_DEBUG_TYPE_FIXUP: DWORD = 6; +pub const IMAGE_DEBUG_TYPE_OMAP_TO_SRC: DWORD = 7; +pub const IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: DWORD = 8; +pub const IMAGE_DEBUG_TYPE_BORLAND: DWORD = 9; +pub const IMAGE_DEBUG_TYPE_RESERVED10: DWORD = 10; +pub const IMAGE_DEBUG_TYPE_CLSID: DWORD = 11; +pub const IMAGE_DEBUG_TYPE_VC_FEATURE: DWORD = 12; +pub const IMAGE_DEBUG_TYPE_POGO: DWORD = 13; +pub const IMAGE_DEBUG_TYPE_ILTCG: DWORD = 14; +pub const IMAGE_DEBUG_TYPE_MPX: DWORD = 15; +pub const IMAGE_DEBUG_TYPE_REPRO: DWORD = 16; +STRUCT!{struct IMAGE_COFF_SYMBOLS_HEADER { + NumberOfSymbols: DWORD, + LvaToFirstSymbol: DWORD, + NumberOfLinenumbers: DWORD, + LvaToFirstLinenumber: DWORD, + RvaToFirstByteOfCode: DWORD, + RvaToLastByteOfCode: DWORD, + RvaToFirstByteOfData: DWORD, + RvaToLastByteOfData: DWORD, +}} +pub type PIMAGE_COFF_SYMBOLS_HEADER = *mut IMAGE_COFF_SYMBOLS_HEADER; +pub const FRAME_FPO: WORD = 0; +pub const FRAME_TRAP: WORD = 1; +pub const FRAME_TSS: WORD = 2; +pub const FRAME_NONFPO: WORD = 3; +STRUCT!{struct FPO_DATA { + ulOffStart: DWORD, + cbProcSize: DWORD, + cdwLocals: DWORD, + cdwParams: WORD, + BitFields: WORD, +}} +BITFIELD!{FPO_DATA BitFields: WORD [ + cbProlog set_cbProlog[0..8], + cbRegs set_cbRegs[8..11], + fHasSEH set_fHasSEH[11..12], + fUseBP set_fUseBP[12..13], + reserved set_reserved[13..14], + cbFrame set_cbFrame[14..16], +]} +pub type PFPO_DATA = *mut FPO_DATA; +pub const SIZEOF_RFPO_DATA: usize = 16; +pub const IMAGE_DEBUG_MISC_EXENAME: DWORD = 1; +STRUCT!{struct IMAGE_DEBUG_MISC { + DataType: DWORD, + Length: DWORD, + Unicode: BOOLEAN, + Reserved: [BYTE; 3], + Data: [BYTE; 1], +}} +pub type PIMAGE_DEBUG_MISC = *mut IMAGE_DEBUG_MISC; +STRUCT!{struct IMAGE_FUNCTION_ENTRY { + StartingAddress: DWORD, + EndingAddress: DWORD, + EndOfPrologue: DWORD, +}} +pub type PIMAGE_FUNCTION_ENTRY = *mut IMAGE_FUNCTION_ENTRY; +UNION!{union IMAGE_FUNCTION_ENTRY64_u { + [u64; 1], + EndOfPrologue EndOfPrologue_mut: ULONGLONG, + UnwindInfoAddress UnwindInfoAddress_mut: ULONGLONG, +}} +STRUCT!{struct IMAGE_FUNCTION_ENTRY64 { + StartingAddress: ULONGLONG, + EndingAddress: ULONGLONG, + u: IMAGE_FUNCTION_ENTRY64_u, +}} +pub type PIMAGE_FUNCTION_ENTRY64 = *mut IMAGE_FUNCTION_ENTRY64; +STRUCT!{struct IMAGE_SEPARATE_DEBUG_HEADER { + Signature: WORD, + Flags: WORD, + Machine: WORD, + Characteristics: WORD, + TimeDateStamp: DWORD, + CheckSum: DWORD, + ImageBase: DWORD, + SizeOfImage: DWORD, + NumberOfSections: DWORD, + ExportedNamesSize: DWORD, + DebugDirectorySize: DWORD, + SectionAlignment: DWORD, + Reserved: [DWORD; 2], +}} +pub type PIMAGE_SEPARATE_DEBUG_HEADER = *mut IMAGE_SEPARATE_DEBUG_HEADER; +STRUCT!{struct NON_PAGED_DEBUG_INFO { + Signature: WORD, + Flags: WORD, + Size: DWORD, + Machine: WORD, + Characteristics: WORD, + TimeDateStamp: DWORD, + CheckSum: DWORD, + SizeOfImage: DWORD, + ImageBase: ULONGLONG, +}} +pub type PNON_PAGED_DEBUG_INFO = *mut NON_PAGED_DEBUG_INFO; +pub const IMAGE_SEPARATE_DEBUG_SIGNATURE: WORD = 0x4944; +pub const NON_PAGED_DEBUG_SIGNATURE: WORD = 0x494E; +pub const IMAGE_SEPARATE_DEBUG_FLAGS_MASK: WORD = 0x8000; +pub const IMAGE_SEPARATE_DEBUG_MISMATCH: WORD = 0x8000; +STRUCT!{struct IMAGE_ARCHITECTURE_HEADER { + BitFields: c_uint, + FirstEntryRVA: DWORD, +}} +BITFIELD!{IMAGE_ARCHITECTURE_HEADER BitFields: c_uint [ + AmaskValue set_AmaskValue[0..1], + unused1 set_unused1[1..8], + AmaskShift set_AmaskShift[8..16], + unused2 set_unused2[8..32], +]} +pub type PIMAGE_ARCHITECTURE_HEADER = *mut IMAGE_ARCHITECTURE_HEADER; +STRUCT!{struct IMAGE_ARCHITECTURE_ENTRY { + FixupInstRVA: DWORD, + NewInst: DWORD, +}} +pub type PIMAGE_ARCHITECTURE_ENTRY = *mut IMAGE_ARCHITECTURE_ENTRY; +pub const IMPORT_OBJECT_HDR_SIG2: WORD = 0xffff; +UNION!{union IMPORT_OBJECT_HEADER_u { + [u16; 1], + Ordinal Ordinal_mut: WORD, + Hint Hint_mut: WORD, +}} +STRUCT!{struct IMPORT_OBJECT_HEADER { + Sig1: WORD, + Sig2: WORD, + Version: WORD, + Machine: WORD, + TimeDateStamp: DWORD, + SizeOfData: DWORD, + u: IMPORT_OBJECT_HEADER_u, + BitFields: WORD, +}} +BITFIELD!{IMPORT_OBJECT_HEADER BitFields: WORD [ + Type set_Type[0..2], + NameType set_NameType[2..5], + Reserved set_Reserved[5..16], +]} +ENUM!{enum IMPORT_OBJECT_TYPE { + IMPORT_OBJECT_CODE = 0, + IMPORT_OBJECT_DATA = 1, + IMPORT_OBJECT_CONST = 2, +}} +ENUM!{enum IMPORT_OBJECT_NAME_TYPE { + IMPORT_OBJECT_ORDINAL = 0, + IMPORT_OBJECT_NAME = 1, + IMPORT_OBJECT_NAME_NO_PREFIX = 2, + IMPORT_OBJECT_NAME_UNDECORATE = 3, + IMPORT_OBJECT_NAME_EXPORTAS = 4, +}} +ENUM!{enum ReplacesCorHdrNumericDefines { + COMIMAGE_FLAGS_ILONLY = 0x00000001, + COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002, + COMIMAGE_FLAGS_IL_LIBRARY = 0x00000004, + COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008, + COMIMAGE_FLAGS_NATIVE_ENTRYPOINT = 0x00000010, + COMIMAGE_FLAGS_TRACKDEBUGDATA = 0x00010000, + COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000, + COR_VERSION_MAJOR_V2 = 2, + COR_VERSION_MAJOR = COR_VERSION_MAJOR_V2, + COR_VERSION_MINOR = 5, + COR_DELETED_NAME_LENGTH = 8, + COR_VTABLEGAP_NAME_LENGTH = 8, + NATIVE_TYPE_MAX_CB = 1, + COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE= 0xFF, + IMAGE_COR_MIH_METHODRVA = 0x01, + IMAGE_COR_MIH_EHRVA = 0x02, + IMAGE_COR_MIH_BASICBLOCK = 0x08, + COR_VTABLE_32BIT = 0x01, + COR_VTABLE_64BIT = 0x02, + COR_VTABLE_FROM_UNMANAGED = 0x04, + COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN = 0x08, + COR_VTABLE_CALL_MOST_DERIVED = 0x10, + IMAGE_COR_EATJ_THUNK_SIZE = 32, + MAX_CLASS_NAME = 1024, + MAX_PACKAGE_NAME = 1024, +}} +UNION!{union IMAGE_COR20_HEADER_u { + [u32; 1], + EntryPointToken EntryPointToken_mut: DWORD, + EntryPointRVA EntryPointRVA_mut: DWORD, +}} +STRUCT!{struct IMAGE_COR20_HEADER { + cb: DWORD, + MajorRuntimeVersion: WORD, + MinorRuntimeVersion: WORD, + MetaData: IMAGE_DATA_DIRECTORY, + Flags: DWORD, + u: IMAGE_COR20_HEADER_u, + Resources: IMAGE_DATA_DIRECTORY, + StrongNameSignature: IMAGE_DATA_DIRECTORY, + CodeManagerTable: IMAGE_DATA_DIRECTORY, + VTableFixups: IMAGE_DATA_DIRECTORY, + ExportAddressTableJumps: IMAGE_DATA_DIRECTORY, + ManagedNativeHeader: IMAGE_DATA_DIRECTORY, +}} +pub type PIMAGE_COR20_HEADER = *mut IMAGE_COR20_HEADER; +extern "system" { + pub fn RtlCaptureStackBackTrace( + FramesToSkip: DWORD, + FramesToCapture: DWORD, + BackTrace: *mut PVOID, + BackTraceHash: PDWORD, + ) -> WORD; + pub fn RtlCaptureContext( + ContextRecord: PCONTEXT, + ); + pub fn RtlUnwind( + TargetFrame: PVOID, + TargetIp: PVOID, + ExceptionRecord: PEXCEPTION_RECORD, + ReturnValue: PVOID, + ); +} +#[cfg(target_pointer_width = "64")] +extern "system" { + pub fn RtlAddFunctionTable( + FunctionTable: PRUNTIME_FUNCTION, + EntryCount: DWORD, + BaseAddress: DWORD64, + ) -> BOOLEAN; + pub fn RtlDeleteFunctionTable( + FunctionTable: PRUNTIME_FUNCTION, + ) -> BOOLEAN; + pub fn RtlInstallFunctionTableCallback( + TableIdentifier: DWORD64, + BaseAddress: DWORD64, + Length: DWORD, + Callback: PGET_RUNTIME_FUNCTION_CALLBACK, + Context: PVOID, + OutOfProcessCallbackDll: PCWSTR, + ) -> BOOLEAN; + pub fn RtlAddGrowableFunctionTable( + DynamicTable: *mut PVOID, + FunctionTable: PRUNTIME_FUNCTION, + EntryCount: DWORD, + MaximumEntryCount: DWORD, + RangeBase: ULONG_PTR, + RangeEnd: ULONG_PTR, + ) -> DWORD; + pub fn RtlGrowFunctionTable( + DynamicTable: PVOID, + NewEntryCount: DWORD, + ); + pub fn RtlDeleteGrowableFunctionTable( + DynamicTable: PVOID, + ); + pub fn RtlLookupFunctionEntry( + ControlPc: DWORD64, + ImageBase: PDWORD64, + HistoryTable: PUNWIND_HISTORY_TABLE, + ) -> PRUNTIME_FUNCTION; +} +#[cfg(target_arch = "x86_64")] +IFDEF!{ +extern "C" { + pub fn RtlRestoreContext( + ContextRecord: PCONTEXT, + ExceptionRecord: *mut EXCEPTION_RECORD, + ); +} +extern "system" { + pub fn RtlUnwindEx( + TargetFrame: PVOID, + TargetIp: PVOID, + ExceptionRecord: PEXCEPTION_RECORD, + ReturnValue: PVOID, + ContextRecord: PCONTEXT, + HistoryTable: PUNWIND_HISTORY_TABLE, + ); + pub fn RtlVirtualUnwind( + HandlerType: DWORD, + ImageBase: DWORD64, + ControlPc: DWORD64, + FunctionEntry: PRUNTIME_FUNCTION, + ContextRecord: PCONTEXT, + HandlerData: *mut PVOID, + EstablisherFrame: PDWORD64, + ContextPointers: PKNONVOLATILE_CONTEXT_POINTERS, + ) -> PEXCEPTION_ROUTINE; +} +} +extern "system" { + pub fn RtlPcToFileHeader( + PcValue: PVOID, + BaseOfImage: *mut PVOID, + ) -> PVOID; + pub fn RtlCompareMemory( + Source1: *const VOID, + Source2: *const VOID, + Length: SIZE_T, + ) -> SIZE_T; +} +STRUCT!{struct SLIST_ENTRY { + Next: *mut SLIST_ENTRY, +}} +pub type PSLIST_ENTRY = *mut SLIST_ENTRY; +#[cfg(target_pointer_width = "64")] +IFDEF!{ +STRUCT!{struct SLIST_HEADER_s { + Alignment: ULONGLONG, + Region: ULONGLONG, +}} +STRUCT!{struct SLIST_HEADER_HeaderX64 { + BitFields1: ULONGLONG, + BitFields2: ULONGLONG, +}} +BITFIELD!{SLIST_HEADER_HeaderX64 BitFields1: ULONGLONG [ + Depth set_Depth[0..16], + Sequence set_Sequence[16..64], +]} +BITFIELD!{SLIST_HEADER_HeaderX64 BitFields2: ULONGLONG [ + Reserved set_Reserved[0..4], + NextEntry set_NextEntry[4..64], +]} +UNION!{union SLIST_HEADER { + [u64; 2], + s s_mut: SLIST_HEADER_s, + HeaderX64 HeaderX64_mut: SLIST_HEADER_HeaderX64, +}} +pub type PSLIST_HEADER = *mut SLIST_HEADER; +} +#[cfg(target_arch = "x86")] +IFDEF!{ +STRUCT!{struct SLIST_HEADER_s { + Next: SLIST_ENTRY, + Depth: WORD, + Reserved: WORD, +}} +UNION!{union SLIST_HEADER { + [u64; 1], + Alignment Alignment_mut: ULONGLONG, + s s_mut: SLIST_HEADER_s, +}} +pub type PSLIST_HEADER = *mut SLIST_HEADER; +} +extern "system" { + pub fn RtlInitializeSListHead( + ListHead: PSLIST_HEADER, + ); + pub fn RtlFirstEntrySList( + ListHead: *const SLIST_HEADER, + ) -> PSLIST_ENTRY; + pub fn RtlInterlockedPopEntrySList( + ListHead: PSLIST_HEADER, + ) -> PSLIST_ENTRY; + pub fn RtlInterlockedPushEntrySList( + ListHead: PSLIST_HEADER, + ListEntry: PSLIST_ENTRY, + ) -> PSLIST_ENTRY; + pub fn RtlInterlockedPushListSListEx( + ListHead: PSLIST_HEADER, + ListEntry: PSLIST_ENTRY, + ListEnd: PSLIST_ENTRY, + Count: DWORD, + ) -> PSLIST_ENTRY; + pub fn RtlInterlockedFlushSList( + ListHead: PSLIST_HEADER, + ) -> PSLIST_ENTRY; + pub fn RtlQueryDepthSList( + ListHead: PSLIST_HEADER, + ) -> WORD; +} +pub const RTL_RUN_ONCE_INIT: RTL_RUN_ONCE = RTL_RUN_ONCE { Ptr: 0 as PVOID }; +pub const RTL_RUN_ONCE_CHECK_ONLY: ULONG = 0x00000001; +pub const RTL_RUN_ONCE_ASYNC: ULONG = 0x00000002; +pub const RTL_RUN_ONCE_INIT_FAILED: ULONG = 0x00000004; +STRUCT!{struct RTL_RUN_ONCE { + Ptr: PVOID, +}} +pub type PRTL_RUN_ONCE = *mut RTL_RUN_ONCE; +STRUCT!{struct RTL_BARRIER { + Reserved1: DWORD, + Reserved2: DWORD, + Reserved3: [ULONG_PTR; 2], + Reserved4: DWORD, + Reserved5: DWORD, +}} +pub type PRTL_BARRIER = *mut RTL_BARRIER; +pub const FAST_FAIL_LEGACY_GS_VIOLATION: c_uint = 0; +pub const FAST_FAIL_VTGUARD_CHECK_FAILURE: c_uint = 1; +pub const FAST_FAIL_STACK_COOKIE_CHECK_FAILURE: c_uint = 2; +pub const FAST_FAIL_CORRUPT_LIST_ENTRY: c_uint = 3; +pub const FAST_FAIL_INCORRECT_STACK: c_uint = 4; +pub const FAST_FAIL_INVALID_ARG: c_uint = 5; +pub const FAST_FAIL_GS_COOKIE_INIT: c_uint = 6; +pub const FAST_FAIL_FATAL_APP_EXIT: c_uint = 7; +pub const FAST_FAIL_RANGE_CHECK_FAILURE: c_uint = 8; +pub const FAST_FAIL_UNSAFE_REGISTRY_ACCESS: c_uint = 9; +pub const FAST_FAIL_GUARD_ICALL_CHECK_FAILURE: c_uint = 10; +pub const FAST_FAIL_GUARD_WRITE_CHECK_FAILURE: c_uint = 11; +pub const FAST_FAIL_INVALID_FIBER_SWITCH: c_uint = 12; +pub const FAST_FAIL_INVALID_SET_OF_CONTEXT: c_uint = 13; +pub const FAST_FAIL_INVALID_REFERENCE_COUNT: c_uint = 14; +pub const FAST_FAIL_INVALID_JUMP_BUFFER: c_uint = 18; +pub const FAST_FAIL_MRDATA_MODIFIED: c_uint = 19; +pub const FAST_FAIL_CERTIFICATION_FAILURE: c_uint = 20; +pub const FAST_FAIL_INVALID_EXCEPTION_CHAIN: c_uint = 21; +pub const FAST_FAIL_CRYPTO_LIBRARY: c_uint = 22; +pub const FAST_FAIL_INVALID_CALL_IN_DLL_CALLOUT: c_uint = 23; +pub const FAST_FAIL_INVALID_IMAGE_BASE: c_uint = 24; +pub const FAST_FAIL_DLOAD_PROTECTION_FAILURE: c_uint = 25; +pub const FAST_FAIL_UNSAFE_EXTENSION_CALL: c_uint = 26; +pub const FAST_FAIL_DEPRECATED_SERVICE_INVOKED: c_uint = 27; +pub const FAST_FAIL_INVALID_BUFFER_ACCESS: c_uint = 28; +pub const FAST_FAIL_INVALID_BALANCED_TREE: c_uint = 29; +pub const FAST_FAIL_INVALID_NEXT_THREAD: c_uint = 30; +pub const FAST_FAIL_GUARD_ICALL_CHECK_SUPPRESSED: c_uint = 31; +pub const FAST_FAIL_APCS_DISABLED: c_uint = 32; +pub const FAST_FAIL_INVALID_IDLE_STATE: c_uint = 33; +pub const FAST_FAIL_MRDATA_PROTECTION_FAILURE: c_uint = 34; +pub const FAST_FAIL_UNEXPECTED_HEAP_EXCEPTION: c_uint = 35; +pub const FAST_FAIL_INVALID_LOCK_STATE: c_uint = 36; +pub const FAST_FAIL_GUARD_JUMPTABLE: c_uint = 37; +pub const FAST_FAIL_INVALID_LONGJUMP_TARGET: c_uint = 38; +pub const FAST_FAIL_INVALID_DISPATCH_CONTEXT: c_uint = 39; +pub const FAST_FAIL_INVALID_THREAD: c_uint = 40; +pub const FAST_FAIL_INVALID_SYSCALL_NUMBER: c_uint = 41; +pub const FAST_FAIL_INVALID_FILE_OPERATION: c_uint = 42; +pub const FAST_FAIL_LPAC_ACCESS_DENIED: c_uint = 43; +pub const FAST_FAIL_GUARD_SS_FAILURE: c_uint = 44; +pub const FAST_FAIL_LOADER_CONTINUITY_FAILURE: c_uint = 45; +pub const FAST_FAIL_GUARD_EXPORT_SUPPRESSION_FAILURE: c_uint = 46; +pub const FAST_FAIL_INVALID_CONTROL_STACK: c_uint = 47; +pub const FAST_FAIL_SET_CONTEXT_DENIED: c_uint = 48; +pub const FAST_FAIL_INVALID_FAST_FAIL_CODE: c_uint = 0xFFFFFFFF; +pub const HEAP_NO_SERIALIZE: DWORD = 0x00000001; +pub const HEAP_GROWABLE: DWORD = 0x00000002; +pub const HEAP_GENERATE_EXCEPTIONS: DWORD = 0x00000004; +pub const HEAP_ZERO_MEMORY: DWORD = 0x00000008; +pub const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010; +pub const HEAP_TAIL_CHECKING_ENABLED: DWORD = 0x00000020; +pub const HEAP_FREE_CHECKING_ENABLED: DWORD = 0x00000040; +pub const HEAP_DISABLE_COALESCE_ON_FREE: DWORD = 0x00000080; +pub const HEAP_CREATE_ALIGN_16: DWORD = 0x00010000; +pub const HEAP_CREATE_ENABLE_TRACING: DWORD = 0x00020000; +pub const HEAP_CREATE_ENABLE_EXECUTE: DWORD = 0x00040000; +pub const HEAP_MAXIMUM_TAG: DWORD = 0x0FFF; +pub const HEAP_PSEUDO_TAG_FLAG: DWORD = 0x8000; +pub const HEAP_TAG_SHIFT: usize = 18; +pub const HEAP_CREATE_SEGMENT_HEAP: DWORD = 0x00000100; +pub const HEAP_CREATE_HARDENED: DWORD = 0x00000200; +#[inline] +pub fn HEAP_MAKE_TAG_FLAGS(TagBase: DWORD, Tag: DWORD) -> DWORD { + TagBase + (Tag << HEAP_TAG_SHIFT) +} +pub const IS_TEXT_UNICODE_ASCII16: INT = 0x0001; +pub const IS_TEXT_UNICODE_REVERSE_ASCII16: INT = 0x0010; +pub const IS_TEXT_UNICODE_STATISTICS: INT = 0x0002; +pub const IS_TEXT_UNICODE_REVERSE_STATISTICS: INT = 0x0020; +pub const IS_TEXT_UNICODE_CONTROLS: INT = 0x0004; +pub const IS_TEXT_UNICODE_REVERSE_CONTROLS: INT = 0x0040; +pub const IS_TEXT_UNICODE_SIGNATURE: INT = 0x0008; +pub const IS_TEXT_UNICODE_REVERSE_SIGNATURE: INT = 0x0080; +pub const IS_TEXT_UNICODE_ILLEGAL_CHARS: INT = 0x0100; +pub const IS_TEXT_UNICODE_ODD_LENGTH: INT = 0x0200; +pub const IS_TEXT_UNICODE_DBCS_LEADBYTE: INT = 0x0400; +pub const IS_TEXT_UNICODE_NULL_BYTES: INT = 0x1000; +pub const IS_TEXT_UNICODE_UNICODE_MASK: INT = 0x000F; +pub const IS_TEXT_UNICODE_REVERSE_MASK: INT = 0x00F0; +pub const IS_TEXT_UNICODE_NOT_UNICODE_MASK: INT = 0x0F00; +pub const IS_TEXT_UNICODE_NOT_ASCII_MASK: INT = 0xF000; +pub const COMPRESSION_FORMAT_NONE: USHORT = 0x0000; +pub const COMPRESSION_FORMAT_DEFAULT: USHORT = 0x0001; +pub const COMPRESSION_FORMAT_LZNT1: USHORT = 0x0002; +pub const COMPRESSION_FORMAT_XPRESS: USHORT = 0x0003; +pub const COMPRESSION_FORMAT_XPRESS_HUFF: USHORT = 0x0004; +pub const COMPRESSION_ENGINE_STANDARD: USHORT = 0x0000; +pub const COMPRESSION_ENGINE_MAXIMUM: USHORT = 0x0100; +pub const COMPRESSION_ENGINE_HIBER: USHORT = 0x0200; +// RtlEqualMemory +#[inline] +pub unsafe fn RtlMoveMemory(Destination: *mut c_void, Source: *const c_void, Length: usize) { + use core::ptr::copy; + copy(Source as *const u8, Destination as *mut u8, Length); +} +#[inline] +pub unsafe fn RtlCopyMemory(Destination: *mut c_void, Source: *const c_void, Length: usize) { + use core::ptr::copy_nonoverlapping; + copy_nonoverlapping(Source as *const u8, Destination as *mut u8, Length); +} +#[inline] +pub unsafe fn RtlFillMemory(Destination: *mut c_void, Length: usize, Fill: u8) { + use core::ptr::write_bytes; + write_bytes(Destination as *mut u8, Fill, Length); +} +#[inline] +pub unsafe fn RtlZeroMemory(Destination: *mut c_void, Length: usize) { + use core::ptr::write_bytes; + write_bytes(Destination as *mut u8, 0, Length); +} +pub const SEF_DACL_AUTO_INHERIT: ULONG = 0x01; +pub const SEF_SACL_AUTO_INHERIT: ULONG = 0x02; +pub const SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT: ULONG = 0x04; +pub const SEF_AVOID_PRIVILEGE_CHECK: ULONG = 0x08; +pub const SEF_AVOID_OWNER_CHECK: ULONG = 0x10; +pub const SEF_DEFAULT_OWNER_FROM_PARENT: ULONG = 0x20; +pub const SEF_DEFAULT_GROUP_FROM_PARENT: ULONG = 0x40; +pub const SEF_MACL_NO_WRITE_UP: ULONG = 0x100; +pub const SEF_MACL_NO_READ_UP: ULONG = 0x200; +pub const SEF_MACL_NO_EXECUTE_UP: ULONG = 0x400; +pub const SEF_AI_USE_EXTRA_PARAMS: ULONG = 0x800; +pub const SEF_AVOID_OWNER_RESTRICTION: ULONG = 0x1000; +pub const SEF_MACL_VALID_FLAGS: ULONG = SEF_MACL_NO_WRITE_UP | SEF_MACL_NO_READ_UP + | SEF_MACL_NO_EXECUTE_UP; +STRUCT!{struct MESSAGE_RESOURCE_ENTRY { + Length: WORD, + Flags: WORD, + Text: [BYTE; 1], +}} +pub type PMESSAGE_RESOURCE_ENTRY = *mut MESSAGE_RESOURCE_ENTRY; +pub const MESSAGE_RESOURCE_UNICODE: WORD = 0x0001; +STRUCT!{struct MESSAGE_RESOURCE_BLOCK { + LowId: DWORD, + HighId: DWORD, + OffsetToEntries: DWORD, +}} +pub type PMESSAGE_RESOURCE_BLOCK = *mut MESSAGE_RESOURCE_BLOCK; +STRUCT!{struct MESSAGE_RESOURCE_DATA { + NumberOfBlocks: DWORD, + Blocks: [MESSAGE_RESOURCE_BLOCK; 1], +}} +pub type PMESSAGE_RESOURCE_DATA = *mut MESSAGE_RESOURCE_DATA; +STRUCT!{struct OSVERSIONINFOA { + dwOSVersionInfoSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + dwBuildNumber: DWORD, + dwPlatformId: DWORD, + szCSDVersion: [CHAR; 128], +}} +pub type POSVERSIONINFOA = *mut OSVERSIONINFOA; +pub type LPOSVERSIONINFOA = *mut OSVERSIONINFOA; +STRUCT!{struct OSVERSIONINFOW { + dwOSVersionInfoSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + dwBuildNumber: DWORD, + dwPlatformId: DWORD, + szCSDVersion: [WCHAR; 128], +}} +pub type POSVERSIONINFOW = *mut OSVERSIONINFOW; +pub type LPOSVERSIONINFOW = *mut OSVERSIONINFOW; +pub type RTL_OSVERSIONINFOW = OSVERSIONINFOW; +pub type PRTL_OSVERSIONINFOW = *mut OSVERSIONINFOW; +STRUCT!{struct OSVERSIONINFOEXA { + dwOSVersionInfoSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + dwBuildNumber: DWORD, + dwPlatformId: DWORD, + szCSDVersion: [CHAR; 128], + wServicePackMajor: WORD, + wServicePackMinor: WORD, + wSuiteMask: WORD, + wProductType: BYTE, + wReserved: BYTE, +}} +pub type POSVERSIONINFOEXA = *mut OSVERSIONINFOEXA; +pub type LPOSVERSIONINFOEXA = *mut OSVERSIONINFOEXA; +STRUCT!{struct OSVERSIONINFOEXW { + dwOSVersionInfoSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + dwBuildNumber: DWORD, + dwPlatformId: DWORD, + szCSDVersion: [WCHAR; 128], + wServicePackMajor: WORD, + wServicePackMinor: WORD, + wSuiteMask: WORD, + wProductType: BYTE, + wReserved: BYTE, +}} +pub type POSVERSIONINFOEXW = *mut OSVERSIONINFOEXW; +pub type LPOSVERSIONINFOEXW = *mut OSVERSIONINFOEXW; +pub type RTL_OSVERSIONINFOEXW = OSVERSIONINFOEXW; +pub type PRTL_OSVERSIONINFOEXW = *mut OSVERSIONINFOEXW; +pub const VER_EQUAL: BYTE = 1; +pub const VER_GREATER: BYTE = 2; +pub const VER_GREATER_EQUAL: BYTE = 3; +pub const VER_LESS: BYTE = 4; +pub const VER_LESS_EQUAL: BYTE = 5; +pub const VER_AND: BYTE = 6; +pub const VER_OR: BYTE = 7; +pub const VER_CONDITION_MASK: BYTE = 7; +pub const VER_NUM_BITS_PER_CONDITION_MASK: BYTE = 3; +pub const VER_MINORVERSION: DWORD = 0x0000001; +pub const VER_MAJORVERSION: DWORD = 0x0000002; +pub const VER_BUILDNUMBER: DWORD = 0x0000004; +pub const VER_PLATFORMID: DWORD = 0x0000008; +pub const VER_SERVICEPACKMINOR: DWORD = 0x0000010; +pub const VER_SERVICEPACKMAJOR: DWORD = 0x0000020; +pub const VER_SUITENAME: DWORD = 0x0000040; +pub const VER_PRODUCT_TYPE: DWORD = 0x0000080; +pub const VER_NT_WORKSTATION: BYTE = 0x0000001; +pub const VER_NT_DOMAIN_CONTROLLER: BYTE = 0x0000002; +pub const VER_NT_SERVER: BYTE = 0x0000003; +pub const VER_PLATFORM_WIN32s: DWORD = 0; +pub const VER_PLATFORM_WIN32_WINDOWS: DWORD = 1; +pub const VER_PLATFORM_WIN32_NT: DWORD = 2; +extern "system" { + pub fn VerSetConditionMask( + ConditionMask: ULONGLONG, + TypeMask: DWORD, + Condition: BYTE, + ) -> ULONGLONG; + pub fn RtlGetProductInfo( + OSMajorVersion: DWORD, + OSMinorVersion: DWORD, + SpMajorVersion: DWORD, + SpMinorVersion: DWORD, + ReturnedProductType: PDWORD, + ) -> BOOLEAN; +} +pub const RTL_UMS_VERSION: DWORD = 0x100; +ENUM!{enum RTL_UMS_THREAD_INFO_CLASS { + UmsThreadInvalidInfoClass = 0, + UmsThreadUserContext, + UmsThreadPriority, + UmsThreadAffinity, + UmsThreadTeb, + UmsThreadIsSuspended, + UmsThreadIsTerminated, + UmsThreadMaxInfoClass, +}} +ENUM!{enum RTL_UMS_SCHEDULER_REASON { + UmsSchedulerStartup = 0, + UmsSchedulerThreadBlocked, + UmsSchedulerThreadYield, +}} +FN!{stdcall PRTL_UMS_SCHEDULER_ENTRY_POINT( + Reason: RTL_UMS_SCHEDULER_REASON, + ActivationPayload: ULONG_PTR, + SchedulerParam: PVOID, +) -> ()} +#[inline] +pub fn IS_VALIDATION_ENABLED(C: DWORD, L: DWORD) -> bool { + (L & C) != 0 +} +pub const VRL_PREDEFINED_CLASS_BEGIN: DWORD = 1 << 0; +pub const VRL_CUSTOM_CLASS_BEGIN: DWORD = 1 << 8; +pub const VRL_CLASS_CONSISTENCY: DWORD = VRL_CUSTOM_CLASS_BEGIN << 8; +pub const VRL_ENABLE_KERNEL_BREAKS: DWORD = 1 << 31; +pub const CTMF_INCLUDE_APPCONTAINER: ULONG = 0x00000001; +pub const CTMF_INCLUDE_LPAC: ULONG = 0x00000002; +pub const CTMF_VALID_FLAGS: ULONG = CTMF_INCLUDE_APPCONTAINER | CTMF_INCLUDE_LPAC; +extern "system" { + pub fn RtlCrc32( + Buffer: *const c_void, + Size: size_t, + InitialCrc: DWORD, + ) -> DWORD; + pub fn RtlCrc64( + Buffer: *const c_void, + Size: size_t, + InitialCrc: ULONGLONG, + ) -> ULONGLONG; +} +ENUM!{enum OS_DEPLOYEMENT_STATE_VALUES { + OS_DEPLOYMENT_STANDARD = 1, + OS_DEPLOYMENT_COMPACT, +}} +extern "system" { + pub fn RtlOsDeploymentState( + Flags: DWORD, + ) -> OS_DEPLOYEMENT_STATE_VALUES; +} +#[cfg(target_arch = "x86_64")] +IFDEF!{ +STRUCT!{struct NV_MEMORY_RANGE { + BaseAddress: *mut VOID, + Length: SIZE_T, +}} +pub type PNV_MEMORY_RANGE = *mut NV_MEMORY_RANGE; +pub const FLUSH_NV_MEMORY_IN_FLAG_NO_DRAIN: ULONG = 0x00000001; +pub const FLUSH_NV_MEMORY_DEFAULT_TOKEN: ULONG_PTR = -1isize as usize; +} +STRUCT!{struct RTL_CRITICAL_SECTION_DEBUG { + Type: WORD, + CreatorBackTraceIndex: WORD, + CriticalSection: *mut RTL_CRITICAL_SECTION, + ProcessLocksList: LIST_ENTRY, + EntryCount: DWORD, + ContentionCount: DWORD, + Flags: DWORD, + CreatorBackTraceIndexHigh: WORD, + SpareWORD: WORD, +}} +pub type PRTL_CRITICAL_SECTION_DEBUG = *mut RTL_CRITICAL_SECTION_DEBUG; +pub type RTL_RESOURCE_DEBUG = RTL_CRITICAL_SECTION_DEBUG; +pub type PRTL_RESOURCE_DEBUG = *mut RTL_CRITICAL_SECTION_DEBUG; +pub const RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO: ULONG_PTR = 0x01000000; +pub const RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN: ULONG_PTR = 0x02000000; +pub const RTL_CRITICAL_SECTION_FLAG_STATIC_INIT: ULONG_PTR = 0x04000000; +pub const RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE: ULONG_PTR = 0x08000000; +pub const RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO: ULONG_PTR = 0x10000000; +pub const RTL_CRITICAL_SECTION_ALL_FLAG_BITS: ULONG_PTR = 0xFF000000; +pub const RTL_CRITICAL_SECTION_FLAG_RESERVED: ULONG_PTR = RTL_CRITICAL_SECTION_ALL_FLAG_BITS + & !(RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO | RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN + | RTL_CRITICAL_SECTION_FLAG_STATIC_INIT | RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE + | RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +pub const RTL_CRITICAL_SECTION_DEBUG_FLAG_STATIC_INIT: DWORD = 0x00000001; +STRUCT!{struct RTL_CRITICAL_SECTION { + DebugInfo: PRTL_CRITICAL_SECTION_DEBUG, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR, +}} +pub type PRTL_CRITICAL_SECTION = *mut RTL_CRITICAL_SECTION; +STRUCT!{struct RTL_SRWLOCK { + Ptr: PVOID, +}} +pub type PRTL_SRWLOCK = *mut RTL_SRWLOCK; +pub const RTL_SRWLOCK_INIT: RTL_SRWLOCK = RTL_SRWLOCK { Ptr: 0 as PVOID }; +STRUCT!{struct RTL_CONDITION_VARIABLE { + Ptr: PVOID, +}} +pub type PRTL_CONDITION_VARIABLE = *mut RTL_CONDITION_VARIABLE; +pub const RTL_CONDITION_VARIABLE_INIT: RTL_CONDITION_VARIABLE = RTL_CONDITION_VARIABLE { + Ptr: 0 as PVOID, +}; +pub const RTL_CONDITION_VARIABLE_LOCKMODE_SHARED: DWORD = 0x1; +FN!{stdcall PAPCFUNC( + Parameter: ULONG_PTR, +) -> ()} +FN!{stdcall PVECTORED_EXCEPTION_HANDLER( + ExceptionInfo: *mut EXCEPTION_POINTERS, +) -> LONG} +ENUM!{enum HEAP_INFORMATION_CLASS { + HeapCompatibilityInformation = 0, + HeapEnableTerminationOnCorruption = 1, + HeapOptimizeResources = 3, +}} +pub const HEAP_OPTIMIZE_RESOURCES_CURRENT_VERSION: DWORD = 1; +STRUCT!{struct HEAP_OPTIMIZE_RESOURCES_INFORMATION { + Version: DWORD, + Flags: DWORD, +}} +pub type PHEAP_OPTIMIZE_RESOURCES_INFORMATION = *mut HEAP_OPTIMIZE_RESOURCES_INFORMATION; +pub const WT_EXECUTEDEFAULT: ULONG = 0x00000000; +pub const WT_EXECUTEINIOTHREAD: ULONG = 0x00000001; +pub const WT_EXECUTEINUITHREAD: ULONG = 0x00000002; +pub const WT_EXECUTEINWAITTHREAD: ULONG = 0x00000004; +pub const WT_EXECUTEONLYONCE: ULONG = 0x00000008; +pub const WT_EXECUTEINTIMERTHREAD: ULONG = 0x00000020; +pub const WT_EXECUTELONGFUNCTION: ULONG = 0x00000010; +pub const WT_EXECUTEINPERSISTENTIOTHREAD: ULONG = 0x00000040; +pub const WT_EXECUTEINPERSISTENTTHREAD: ULONG = 0x00000080; +pub const WT_TRANSFER_IMPERSONATION: ULONG = 0x00000100; +#[inline] +pub fn WT_SET_MAX_THREADPOOL_THREADS(Flags: ULONG, Limit: ULONG) -> ULONG { + Flags | (Limit << 16) +} +FN!{stdcall WAITORTIMERCALLBACKFUNC( + PVOID, + BOOLEAN, +) -> ()} +FN!{stdcall WORKERCALLBACKFUNC( + PVOID, +) -> ()} +FN!{stdcall APC_CALLBACK_FUNCTION( + DWORD, + PVOID, + PVOID, +) -> ()} +pub type WAITORTIMERCALLBACK = WAITORTIMERCALLBACKFUNC; +FN!{stdcall PFLS_CALLBACK_FUNCTION( + lpFlsData: PVOID, +) -> ()} +FN!{stdcall PSECURE_MEMORY_CACHE_CALLBACK( + Addr: PVOID, + Range: SIZE_T, +) -> BOOLEAN} +pub const WT_EXECUTEINLONGTHREAD: ULONG = 0x00000010; +pub const WT_EXECUTEDELETEWAIT: ULONG = 0x00000008; +ENUM!{enum ACTIVATION_CONTEXT_INFO_CLASS { + ActivationContextBasicInformation = 1, + ActivationContextDetailedInformation = 2, + AssemblyDetailedInformationInActivationContext = 3, + FileInformationInAssemblyOfAssemblyInActivationContext = 4, + RunlevelInformationInActivationContext = 5, + CompatibilityInformationInActivationContext = 6, + ActivationContextManifestResourceName = 7, + MaxActivationContextInfoClass, + AssemblyDetailedInformationInActivationContxt = 3, + FileInformationInAssemblyOfAssemblyInActivationContxt = 4, +}} +pub type ACTIVATIONCONTEXTINFOCLASS = ACTIVATION_CONTEXT_INFO_CLASS; +STRUCT!{struct ACTIVATION_CONTEXT_QUERY_INDEX { + ulAssemblyIndex: DWORD, + ulFileIndexInAssembly: DWORD, +}} +pub type PACTIVATION_CONTEXT_QUERY_INDEX = *mut ACTIVATION_CONTEXT_QUERY_INDEX; +pub type PCACTIVATION_CONTEXT_QUERY_INDEX = *const ACTIVATION_CONTEXT_QUERY_INDEX; +pub const ACTIVATION_CONTEXT_PATH_TYPE_NONE: DWORD = 1; +pub const ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE: DWORD = 2; +pub const ACTIVATION_CONTEXT_PATH_TYPE_URL: DWORD = 3; +pub const ACTIVATION_CONTEXT_PATH_TYPE_ASSEMBLYREF: DWORD = 4; +STRUCT!{struct ASSEMBLY_FILE_DETAILED_INFORMATION { + ulFlags: DWORD, + ulFilenameLength: DWORD, + ulPathLength: DWORD, + lpFileName: PCWSTR, + lpFilePath: PCWSTR, +}} +pub type PASSEMBLY_FILE_DETAILED_INFORMATION = *mut ASSEMBLY_FILE_DETAILED_INFORMATION; +pub type PCASSEMBLY_FILE_DETAILED_INFORMATION = *const ASSEMBLY_FILE_DETAILED_INFORMATION; +pub type ASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION = ASSEMBLY_FILE_DETAILED_INFORMATION; +pub type PASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION = PASSEMBLY_FILE_DETAILED_INFORMATION; +pub type PCASSEMBLY_DLL_REDIRECTION_DETAILED_INFORMATION = PCASSEMBLY_FILE_DETAILED_INFORMATION; +STRUCT!{struct ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION { + ulFlags: DWORD, + ulEncodedAssemblyIdentityLength: DWORD, + ulManifestPathType: DWORD, + ulManifestPathLength: DWORD, + liManifestLastWriteTime: LARGE_INTEGER, + ulPolicyPathType: DWORD, + ulPolicyPathLength: DWORD, + liPolicyLastWriteTime: LARGE_INTEGER, + ulMetadataSatelliteRosterIndex: DWORD, + ulManifestVersionMajor: DWORD, + ulManifestVersionMinor: DWORD, + ulPolicyVersionMajor: DWORD, + ulPolicyVersionMinor: DWORD, + ulAssemblyDirectoryNameLength: DWORD, + lpAssemblyEncodedAssemblyIdentity: PCWSTR, + lpAssemblyManifestPath: PCWSTR, + lpAssemblyPolicyPath: PCWSTR, + lpAssemblyDirectoryName: PCWSTR, + ulFileCount: DWORD, +}} +pub type PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION + = *mut ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; +pub type PCACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION + = *const ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION; +ENUM!{enum ACTCTX_REQUESTED_RUN_LEVEL { + ACTCTX_RUN_LEVEL_UNSPECIFIED = 0, + ACTCTX_RUN_LEVEL_AS_INVOKER, + ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE, + ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, + ACTCTX_RUN_LEVEL_NUMBERS, +}} +STRUCT!{struct ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION { + ulFlags: DWORD, + RunLevel: ACTCTX_REQUESTED_RUN_LEVEL, + UiAccess: DWORD, +}} +pub type PACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION = *mut ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION; +pub type PCACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION + = *const ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION; +ENUM!{enum ACTCTX_COMPATIBILITY_ELEMENT_TYPE { + ACTCTX_COMPATIBILITY_ELEMENT_TYPE_UNKNOWN = 0, + ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, + ACTCTX_COMPATIBILITY_ELEMENT_TYPE_MITIGATION, +}} +STRUCT!{struct COMPATIBILITY_CONTEXT_ELEMENT { + Id: GUID, + Type: ACTCTX_COMPATIBILITY_ELEMENT_TYPE, +}} +pub type PCOMPATIBILITY_CONTEXT_ELEMENT = *mut COMPATIBILITY_CONTEXT_ELEMENT; +pub type PCCOMPATIBILITY_CONTEXT_ELEMENT = *const COMPATIBILITY_CONTEXT_ELEMENT; +STRUCT!{struct ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION { + ElementCount: DWORD, + Elements: [COMPATIBILITY_CONTEXT_ELEMENT; 0], +}} +pub type PACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION + = *mut ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION; +pub type PCACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION + = *const ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION; +STRUCT!{struct SUPPORTED_OS_INFO { + MajorVersion: WORD, + MinorVersion: WORD, +}} +pub type PSUPPORTED_OS_INFO = *mut SUPPORTED_OS_INFO; +STRUCT!{struct ACTIVATION_CONTEXT_DETAILED_INFORMATION { + dwFlags: DWORD, + ulFormatVersion: DWORD, + ulAssemblyCount: DWORD, + ulRootManifestPathType: DWORD, + ulRootManifestPathChars: DWORD, + ulRootConfigurationPathType: DWORD, + ulRootConfigurationPathChars: DWORD, + ulAppDirPathType: DWORD, + ulAppDirPathChars: DWORD, + lpRootManifestPath: PCWSTR, + lpRootConfigurationPath: PCWSTR, + lpAppDirPath: PCWSTR, +}} +pub type PACTIVATION_CONTEXT_DETAILED_INFORMATION = *mut ACTIVATION_CONTEXT_DETAILED_INFORMATION; +pub type PCACTIVATION_CONTEXT_DETAILED_INFORMATION + = *const ACTIVATION_CONTEXT_DETAILED_INFORMATION; +pub const CREATE_BOUNDARY_DESCRIPTOR_ADD_APPCONTAINER_SID: DWORD = 0x1; +STRUCT!{struct HARDWARE_COUNTER_DATA { + Type: HARDWARE_COUNTER_TYPE, + Reserved: DWORD, + Value: DWORD64, +}} +pub type PHARDWARE_COUNTER_DATA = *mut HARDWARE_COUNTER_DATA; +pub const PERFORMANCE_DATA_VERSION: BYTE = 1; +STRUCT!{struct PERFORMANCE_DATA { + Size: WORD, + Version: BYTE, + HwCountersCount: BYTE, + ContextSwitchCount: DWORD, + WaitReasonBitMap: DWORD64, + CycleTime: DWORD64, + RetryCount: DWORD, + Reserved: DWORD, + HwCounters: [HARDWARE_COUNTER_DATA; MAX_HW_COUNTERS], +}} +pub type PPERFORMANCE_DATA = *mut PERFORMANCE_DATA; +pub const READ_THREAD_PROFILING_FLAG_DISPATCHING: DWORD = 0x00000001; +pub const READ_THREAD_PROFILING_FLAG_HARDWARE_COUNTERS: DWORD = 0x00000002; +pub const UNIFIEDBUILDREVISION_KEY: &'static str + = "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion"; +pub const UNIFIEDBUILDREVISION_VALUE: &'static str = "UBR"; +pub const UNIFIEDBUILDREVISION_MIN: DWORD = 0x00000000; +pub const DEVICEFAMILYDEVICEFORM_KEY: &'static str + = "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\OEM"; +pub const DEVICEFAMILYDEVICEFORM_VALUE: &'static str = "DeviceForm"; +pub const DEVICEFAMILYINFOENUM_UAP: DWORD = 0x00000000; +pub const DEVICEFAMILYINFOENUM_WINDOWS_8X: DWORD = 0x00000001; +pub const DEVICEFAMILYINFOENUM_WINDOWS_PHONE_8X: DWORD = 0x00000002; +pub const DEVICEFAMILYINFOENUM_DESKTOP: DWORD = 0x00000003; +pub const DEVICEFAMILYINFOENUM_MOBILE: DWORD = 0x00000004; +pub const DEVICEFAMILYINFOENUM_XBOX: DWORD = 0x00000005; +pub const DEVICEFAMILYINFOENUM_TEAM: DWORD = 0x00000006; +pub const DEVICEFAMILYINFOENUM_IOT: DWORD = 0x00000007; +pub const DEVICEFAMILYINFOENUM_IOT_HEADLESS: DWORD = 0x00000008; +pub const DEVICEFAMILYINFOENUM_SERVER: DWORD = 0x00000009; +pub const DEVICEFAMILYINFOENUM_HOLOGRAPHIC: DWORD = 0x0000000A; +pub const DEVICEFAMILYINFOENUM_XBOXSRA: DWORD = 0x0000000B; +pub const DEVICEFAMILYINFOENUM_XBOXERA: DWORD = 0x0000000C; +pub const DEVICEFAMILYINFOENUM_SERVER_NANO: DWORD = 0x0000000D; +pub const DEVICEFAMILYINFOENUM_MAX: DWORD = 0x0000000D; +pub const DEVICEFAMILYDEVICEFORM_UNKNOWN: DWORD = 0x00000000; +pub const DEVICEFAMILYDEVICEFORM_PHONE: DWORD = 0x00000001; +pub const DEVICEFAMILYDEVICEFORM_TABLET: DWORD = 0x00000002; +pub const DEVICEFAMILYDEVICEFORM_DESKTOP: DWORD = 0x00000003; +pub const DEVICEFAMILYDEVICEFORM_NOTEBOOK: DWORD = 0x00000004; +pub const DEVICEFAMILYDEVICEFORM_CONVERTIBLE: DWORD = 0x00000005; +pub const DEVICEFAMILYDEVICEFORM_DETACHABLE: DWORD = 0x00000006; +pub const DEVICEFAMILYDEVICEFORM_ALLINONE: DWORD = 0x00000007; +pub const DEVICEFAMILYDEVICEFORM_STICKPC: DWORD = 0x00000008; +pub const DEVICEFAMILYDEVICEFORM_PUCK: DWORD = 0x00000009; +pub const DEVICEFAMILYDEVICEFORM_LARGESCREEN: DWORD = 0x0000000A; +pub const DEVICEFAMILYDEVICEFORM_HMD: DWORD = 0x0000000B; +pub const DEVICEFAMILYDEVICEFORM_INDUSTRY_HANDHELD: DWORD = 0x0000000C; +pub const DEVICEFAMILYDEVICEFORM_INDUSTRY_TABLET: DWORD = 0x0000000D; +pub const DEVICEFAMILYDEVICEFORM_BANKING: DWORD = 0x0000000E; +pub const DEVICEFAMILYDEVICEFORM_BUILDING_AUTOMATION: DWORD = 0x0000000F; +pub const DEVICEFAMILYDEVICEFORM_DIGITAL_SIGNAGE: DWORD = 0x00000010; +pub const DEVICEFAMILYDEVICEFORM_GAMING: DWORD = 0x00000011; +pub const DEVICEFAMILYDEVICEFORM_HOME_AUTOMATION: DWORD = 0x00000012; +pub const DEVICEFAMILYDEVICEFORM_INDUSTRIAL_AUTOMATION: DWORD = 0x00000013; +pub const DEVICEFAMILYDEVICEFORM_KIOSK: DWORD = 0x00000014; +pub const DEVICEFAMILYDEVICEFORM_MAKER_BOARD: DWORD = 0x00000015; +pub const DEVICEFAMILYDEVICEFORM_MEDICAL: DWORD = 0x00000016; +pub const DEVICEFAMILYDEVICEFORM_NETWORKING: DWORD = 0x00000017; +pub const DEVICEFAMILYDEVICEFORM_POINT_OF_SERVICE: DWORD = 0x00000018; +pub const DEVICEFAMILYDEVICEFORM_PRINTING: DWORD = 0x00000019; +pub const DEVICEFAMILYDEVICEFORM_THIN_CLIENT: DWORD = 0x0000001A; +pub const DEVICEFAMILYDEVICEFORM_TOY: DWORD = 0x0000001B; +pub const DEVICEFAMILYDEVICEFORM_VENDING: DWORD = 0x0000001C; +pub const DEVICEFAMILYDEVICEFORM_INDUSTRY_OTHER: DWORD = 0x0000001D; +pub const DEVICEFAMILYDEVICEFORM_MAX: DWORD = 0x0000001D; +extern "system" { + pub fn RtlGetDeviceFamilyInfoEnum( + pullUAPInfo: *mut ULONGLONG, + pulDeviceFamily: *mut DWORD, + pulDeviceForm: *mut DWORD, + ); + pub fn RtlConvertDeviceFamilyInfoToString( + pulDeviceFamilyBufferSize: PDWORD, + pulDeviceFormBufferSize: PDWORD, + DeviceFamily: PWSTR, + DeviceForm: PWSTR, + ) -> DWORD; + pub fn RtlSwitchedVVI( + VersionInfo: PRTL_OSVERSIONINFOEXW, + TypeMask: DWORD, + ConditionMask: ULONGLONG, + ) -> DWORD; +} +pub const DLL_PROCESS_ATTACH: DWORD = 1; +pub const DLL_THREAD_ATTACH: DWORD = 2; +pub const DLL_THREAD_DETACH: DWORD = 3; +pub const DLL_PROCESS_DETACH: DWORD = 0; +pub const EVENTLOG_SEQUENTIAL_READ: DWORD = 0x0001; +pub const EVENTLOG_SEEK_READ: DWORD = 0x0002; +pub const EVENTLOG_FORWARDS_READ: DWORD = 0x0004; +pub const EVENTLOG_BACKWARDS_READ: DWORD = 0x0008; +pub const EVENTLOG_SUCCESS: WORD = 0x0000; +pub const EVENTLOG_ERROR_TYPE: WORD = 0x0001; +pub const EVENTLOG_WARNING_TYPE: WORD = 0x0002; +pub const EVENTLOG_INFORMATION_TYPE: WORD = 0x0004; +pub const EVENTLOG_AUDIT_SUCCESS: WORD = 0x0008; +pub const EVENTLOG_AUDIT_FAILURE: WORD = 0x0010; +pub const EVENTLOG_START_PAIRED_EVENT: WORD = 0x0001; +pub const EVENTLOG_END_PAIRED_EVENT: WORD = 0x0002; +pub const EVENTLOG_END_ALL_PAIRED_EVENTS: WORD = 0x0004; +pub const EVENTLOG_PAIRED_EVENT_ACTIVE: WORD = 0x0008; +pub const EVENTLOG_PAIRED_EVENT_INACTIVE: WORD = 0x0010; +STRUCT!{struct EVENTLOGRECORD { + Length: DWORD, + Reserved: DWORD, + RecordNumber: DWORD, + TimeGenerated: DWORD, + TimeWritten: DWORD, + EventID: DWORD, + EventType: WORD, + NumStrings: WORD, + EventCategory: WORD, + ReservedFlags: WORD, + ClosingRecordNumber: DWORD, + StringOffset: DWORD, + UserSidLength: DWORD, + UserSidOffset: DWORD, + DataLength: DWORD, + DataOffset: DWORD, +}} +pub type PEVENTLOGRECORD = *mut EVENTLOGRECORD; +pub const MAXLOGICALLOGNAMESIZE: usize = 256; +pub type PEVENTSFORLOGFILE = *mut EVENTSFORLOGFILE; +pub type PPACKEDEVENTINFO = *mut PACKEDEVENTINFO; +STRUCT!{struct EVENTSFORLOGFILE { + ulSize: DWORD, + szLogicalLogFile: [WCHAR; MAXLOGICALLOGNAMESIZE], + ulNumRecords: DWORD, + pEventLogRecords: [EVENTLOGRECORD; 0], +}} +STRUCT!{struct PACKEDEVENTINFO { + ulSize: DWORD, + ulNumEventsForLogFile: DWORD, + ulOffsets: [DWORD; 0], +}} +pub const KEY_QUERY_VALUE: u32 = 0x0001; +pub const KEY_SET_VALUE: u32 = 0x0002; +pub const KEY_CREATE_SUB_KEY: u32 = 0x0004; +pub const KEY_ENUMERATE_SUB_KEYS: u32 = 0x0008; +pub const KEY_NOTIFY: u32 = 0x0010; +pub const KEY_CREATE_LINK: u32 = 0x0020; +pub const KEY_WOW64_32KEY: u32 = 0x0200; +pub const KEY_WOW64_64KEY: u32 = 0x0100; +pub const KEY_WOW64_RES: u32 = 0x0300; +pub const KEY_READ: u32 = (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS + | KEY_NOTIFY) & !SYNCHRONIZE; +pub const KEY_WRITE: u32 = (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) + & !SYNCHRONIZE; +pub const KEY_EXECUTE: u32 = KEY_READ & !SYNCHRONIZE; +pub const KEY_ALL_ACCESS: u32 = (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE + | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & !SYNCHRONIZE; +pub const REG_OPTION_RESERVED: DWORD = 0x00000000; +pub const REG_OPTION_NON_VOLATILE: DWORD = 0x00000000; +pub const REG_OPTION_VOLATILE: DWORD = 0x00000001; +pub const REG_OPTION_CREATE_LINK: DWORD = 0x00000002; +pub const REG_OPTION_BACKUP_RESTORE: DWORD = 0x00000004; +pub const REG_OPTION_OPEN_LINK: DWORD = 0x00000008; +pub const REG_OPTION_DONT_VIRTUALIZE: DWORD = 0x00000010; +pub const REG_LEGAL_OPTION: DWORD = REG_OPTION_RESERVED | REG_OPTION_NON_VOLATILE + | REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK | REG_OPTION_BACKUP_RESTORE + | REG_OPTION_OPEN_LINK | REG_OPTION_DONT_VIRTUALIZE; +pub const REG_OPEN_LEGAL_OPTION: DWORD = REG_OPTION_RESERVED | REG_OPTION_BACKUP_RESTORE + | REG_OPTION_OPEN_LINK | REG_OPTION_DONT_VIRTUALIZE; +pub const REG_CREATED_NEW_KEY: DWORD = 0x00000001; +pub const REG_OPENED_EXISTING_KEY: DWORD = 0x00000002; +pub const REG_STANDARD_FORMAT: DWORD = 1; +pub const REG_LATEST_FORMAT: DWORD = 2; +pub const REG_NO_COMPRESSION: DWORD = 4; +pub const REG_WHOLE_HIVE_VOLATILE: DWORD = 0x00000001; +pub const REG_REFRESH_HIVE: DWORD = 0x00000002; +pub const REG_NO_LAZY_FLUSH: DWORD = 0x00000004; +pub const REG_FORCE_RESTORE: DWORD = 0x00000008; +pub const REG_APP_HIVE: DWORD = 0x00000010; +pub const REG_PROCESS_PRIVATE: DWORD = 0x00000020; +pub const REG_START_JOURNAL: DWORD = 0x00000040; +pub const REG_HIVE_EXACT_FILE_GROWTH: DWORD = 0x00000080; +pub const REG_HIVE_NO_RM: DWORD = 0x00000100; +pub const REG_HIVE_SINGLE_LOG: DWORD = 0x00000200; +pub const REG_BOOT_HIVE: DWORD = 0x00000400; +pub const REG_LOAD_HIVE_OPEN_HANDLE: DWORD = 0x00000800; +pub const REG_FLUSH_HIVE_FILE_GROWTH: DWORD = 0x00001000; +pub const REG_OPEN_READ_ONLY: DWORD = 0x00002000; +pub const REG_IMMUTABLE: DWORD = 0x00004000; +pub const REG_APP_HIVE_OPEN_READ_ONLY: DWORD = REG_OPEN_READ_ONLY; +pub const REG_FORCE_UNLOAD: DWORD = 1; +pub const REG_UNLOAD_LEGAL_FLAGS: DWORD = REG_FORCE_UNLOAD; +pub const REG_NOTIFY_CHANGE_NAME: DWORD = 0x00000001; +pub const REG_NOTIFY_CHANGE_ATTRIBUTES: DWORD = 0x00000002; +pub const REG_NOTIFY_CHANGE_LAST_SET: DWORD = 0x00000004; +pub const REG_NOTIFY_CHANGE_SECURITY: DWORD = 0x00000008; +pub const REG_NOTIFY_THREAD_AGNOSTIC: DWORD = 0x10000000; +pub const REG_LEGAL_CHANGE_FILTER: DWORD = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES + | REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY | REG_NOTIFY_THREAD_AGNOSTIC; +pub const REG_NONE: DWORD = 0; +pub const REG_SZ: DWORD = 1; +pub const REG_EXPAND_SZ: DWORD = 2; +pub const REG_BINARY: DWORD = 3; +pub const REG_DWORD: DWORD = 4; +pub const REG_DWORD_LITTLE_ENDIAN: DWORD = 4; +pub const REG_DWORD_BIG_ENDIAN: DWORD = 5; +pub const REG_LINK: DWORD = 6; +pub const REG_MULTI_SZ: DWORD = 7; +pub const REG_RESOURCE_LIST: DWORD = 8; +pub const REG_FULL_RESOURCE_DESCRIPTOR: DWORD = 9; +pub const REG_RESOURCE_REQUIREMENTS_LIST: DWORD = 10; +pub const REG_QWORD: DWORD = 11; +pub const REG_QWORD_LITTLE_ENDIAN: DWORD = 11; +pub const SERVICE_KERNEL_DRIVER: DWORD = 0x00000001; +pub const SERVICE_FILE_SYSTEM_DRIVER: DWORD = 0x00000002; +pub const SERVICE_ADAPTER: DWORD = 0x00000004; +pub const SERVICE_RECOGNIZER_DRIVER: DWORD = 0x00000008; +pub const SERVICE_DRIVER: DWORD = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER + | SERVICE_RECOGNIZER_DRIVER; +pub const SERVICE_WIN32_OWN_PROCESS: DWORD = 0x00000010; +pub const SERVICE_WIN32_SHARE_PROCESS: DWORD = 0x00000020; +pub const SERVICE_WIN32: DWORD = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS; +pub const SERVICE_USER_SERVICE: DWORD = 0x00000040; +pub const SERVICE_USERSERVICE_INSTANCE: DWORD = 0x00000080; +pub const SERVICE_USER_SHARE_PROCESS: DWORD = SERVICE_USER_SERVICE | SERVICE_WIN32_SHARE_PROCESS; +pub const SERVICE_USER_OWN_PROCESS: DWORD = SERVICE_USER_SERVICE | SERVICE_WIN32_OWN_PROCESS; +pub const SERVICE_INTERACTIVE_PROCESS: DWORD = 0x00000100; +pub const SERVICE_PKG_SERVICE: DWORD = 0x00000200; +pub const SERVICE_TYPE_ALL: DWORD = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER + | SERVICE_INTERACTIVE_PROCESS | SERVICE_USER_SERVICE | SERVICE_USERSERVICE_INSTANCE + | SERVICE_PKG_SERVICE; +pub const SERVICE_BOOT_START: DWORD = 0x00000000; +pub const SERVICE_SYSTEM_START: DWORD = 0x00000001; +pub const SERVICE_AUTO_START: DWORD = 0x00000002; +pub const SERVICE_DEMAND_START: DWORD = 0x00000003; +pub const SERVICE_DISABLED: DWORD = 0x00000004; +pub const SERVICE_ERROR_IGNORE: DWORD = 0x00000000; +pub const SERVICE_ERROR_NORMAL: DWORD = 0x00000001; +pub const SERVICE_ERROR_SEVERE: DWORD = 0x00000002; +pub const SERVICE_ERROR_CRITICAL: DWORD = 0x00000003; +ENUM!{enum SERVICE_NODE_TYPE { + DriverType = SERVICE_KERNEL_DRIVER, + FileSystemType = SERVICE_FILE_SYSTEM_DRIVER, + Win32ServiceOwnProcess = SERVICE_WIN32_OWN_PROCESS, + Win32ServiceShareProcess = SERVICE_WIN32_SHARE_PROCESS, + AdapterType = SERVICE_ADAPTER, + RecognizerType = SERVICE_RECOGNIZER_DRIVER, +}} +ENUM!{enum SERVICE_LOAD_TYPE { + BootLoad = SERVICE_BOOT_START, + SystemLoad = SERVICE_SYSTEM_START, + AutoLoad = SERVICE_AUTO_START, + DemandLoad = SERVICE_DEMAND_START, + DisableLoad = SERVICE_DISABLED, +}} +ENUM!{enum SERVICE_ERROR_TYPE { + IgnoreError = SERVICE_ERROR_IGNORE, + NormalError = SERVICE_ERROR_NORMAL, + SevereError = SERVICE_ERROR_SEVERE, + CriticalError = SERVICE_ERROR_CRITICAL, +}} +pub const CM_SERVICE_NETWORK_BOOT_LOAD: DWORD = 0x00000001; +pub const CM_SERVICE_VIRTUAL_DISK_BOOT_LOAD: DWORD = 0x00000002; +pub const CM_SERVICE_USB_DISK_BOOT_LOAD: DWORD = 0x00000004; +pub const CM_SERVICE_SD_DISK_BOOT_LOAD: DWORD = 0x00000008; +pub const CM_SERVICE_USB3_DISK_BOOT_LOAD: DWORD = 0x00000010; +pub const CM_SERVICE_MEASURED_BOOT_LOAD: DWORD = 0x00000020; +pub const CM_SERVICE_VERIFIER_BOOT_LOAD: DWORD = 0x00000040; +pub const CM_SERVICE_WINPE_BOOT_LOAD: DWORD = 0x00000080; +pub const CM_SERVICE_VALID_PROMOTION_MASK: DWORD = CM_SERVICE_NETWORK_BOOT_LOAD + | CM_SERVICE_VIRTUAL_DISK_BOOT_LOAD | CM_SERVICE_USB_DISK_BOOT_LOAD + | CM_SERVICE_SD_DISK_BOOT_LOAD | CM_SERVICE_USB3_DISK_BOOT_LOAD + | CM_SERVICE_MEASURED_BOOT_LOAD | CM_SERVICE_VERIFIER_BOOT_LOAD | CM_SERVICE_WINPE_BOOT_LOAD; +pub const TAPE_ERASE_SHORT: DWORD = 0; +pub const TAPE_ERASE_LONG: DWORD = 1; +STRUCT!{struct TAPE_ERASE { + Type: DWORD, + Immediate: BOOLEAN, +}} +pub type PTAPE_ERASE = *mut TAPE_ERASE; +pub const TAPE_LOAD: DWORD = 0; +pub const TAPE_UNLOAD: DWORD = 1; +pub const TAPE_TENSION: DWORD = 2; +pub const TAPE_LOCK: DWORD = 3; +pub const TAPE_UNLOCK: DWORD = 4; +pub const TAPE_FORMAT: DWORD = 5; +STRUCT!{struct TAPE_PREPARE { + Operation: DWORD, + Immediate: BOOLEAN, +}} +pub type PTAPE_PREPARE = *mut TAPE_PREPARE; +pub const TAPE_SETMARKS: DWORD = 0; +pub const TAPE_FILEMARKS: DWORD = 1; +pub const TAPE_SHORT_FILEMARKS: DWORD = 2; +pub const TAPE_LONG_FILEMARKS: DWORD = 3; +STRUCT!{struct TAPE_WRITE_MARKS { + Type: DWORD, + Count: DWORD, + Immediate: BOOLEAN, +}} +pub type PTAPE_WRITE_MARKS = *mut TAPE_WRITE_MARKS; +pub const TAPE_ABSOLUTE_POSITION: DWORD = 0; +pub const TAPE_LOGICAL_POSITION: DWORD = 1; +pub const TAPE_PSEUDO_LOGICAL_POSITION: DWORD = 2; +STRUCT!{struct TAPE_GET_POSITION { + Type: DWORD, + Partition: DWORD, + Offset: LARGE_INTEGER, +}} +pub type PTAPE_GET_POSITION = *mut TAPE_GET_POSITION; +pub const TAPE_REWIND: DWORD = 0; +pub const TAPE_ABSOLUTE_BLOCK: DWORD = 1; +pub const TAPE_LOGICAL_BLOCK: DWORD = 2; +pub const TAPE_PSEUDO_LOGICAL_BLOCK: DWORD = 3; +pub const TAPE_SPACE_END_OF_DATA: DWORD = 4; +pub const TAPE_SPACE_RELATIVE_BLOCKS: DWORD = 5; +pub const TAPE_SPACE_FILEMARKS: DWORD = 6; +pub const TAPE_SPACE_SEQUENTIAL_FMKS: DWORD = 7; +pub const TAPE_SPACE_SETMARKS: DWORD = 8; +pub const TAPE_SPACE_SEQUENTIAL_SMKS: DWORD = 9; +STRUCT!{struct TAPE_SET_POSITION { + Method: DWORD, + Partition: DWORD, + Offset: LARGE_INTEGER, + Immediate: BOOLEAN, +}} +pub type PTAPE_SET_POSITION = *mut TAPE_SET_POSITION; +pub const TAPE_DRIVE_FIXED: DWORD = 0x00000001; +pub const TAPE_DRIVE_SELECT: DWORD = 0x00000002; +pub const TAPE_DRIVE_INITIATOR: DWORD = 0x00000004; +pub const TAPE_DRIVE_ERASE_SHORT: DWORD = 0x00000010; +pub const TAPE_DRIVE_ERASE_LONG: DWORD = 0x00000020; +pub const TAPE_DRIVE_ERASE_BOP_ONLY: DWORD = 0x00000040; +pub const TAPE_DRIVE_ERASE_IMMEDIATE: DWORD = 0x00000080; +pub const TAPE_DRIVE_TAPE_CAPACITY: DWORD = 0x00000100; +pub const TAPE_DRIVE_TAPE_REMAINING: DWORD = 0x00000200; +pub const TAPE_DRIVE_FIXED_BLOCK: DWORD = 0x00000400; +pub const TAPE_DRIVE_VARIABLE_BLOCK: DWORD = 0x00000800; +pub const TAPE_DRIVE_WRITE_PROTECT: DWORD = 0x00001000; +pub const TAPE_DRIVE_EOT_WZ_SIZE: DWORD = 0x00002000; +pub const TAPE_DRIVE_ECC: DWORD = 0x00010000; +pub const TAPE_DRIVE_COMPRESSION: DWORD = 0x00020000; +pub const TAPE_DRIVE_PADDING: DWORD = 0x00040000; +pub const TAPE_DRIVE_REPORT_SMKS: DWORD = 0x00080000; +pub const TAPE_DRIVE_GET_ABSOLUTE_BLK: DWORD = 0x00100000; +pub const TAPE_DRIVE_GET_LOGICAL_BLK: DWORD = 0x00200000; +pub const TAPE_DRIVE_SET_EOT_WZ_SIZE: DWORD = 0x00400000; +pub const TAPE_DRIVE_EJECT_MEDIA: DWORD = 0x01000000; +pub const TAPE_DRIVE_CLEAN_REQUESTS: DWORD = 0x02000000; +pub const TAPE_DRIVE_SET_CMP_BOP_ONLY: DWORD = 0x04000000; +pub const TAPE_DRIVE_RESERVED_BIT: DWORD = 0x80000000; +pub const TAPE_DRIVE_LOAD_UNLOAD: DWORD = 0x80000001; +pub const TAPE_DRIVE_TENSION: DWORD = 0x80000002; +pub const TAPE_DRIVE_LOCK_UNLOCK: DWORD = 0x80000004; +pub const TAPE_DRIVE_REWIND_IMMEDIATE: DWORD = 0x80000008; +pub const TAPE_DRIVE_SET_BLOCK_SIZE: DWORD = 0x80000010; +pub const TAPE_DRIVE_LOAD_UNLD_IMMED: DWORD = 0x80000020; +pub const TAPE_DRIVE_TENSION_IMMED: DWORD = 0x80000040; +pub const TAPE_DRIVE_LOCK_UNLK_IMMED: DWORD = 0x80000080; +pub const TAPE_DRIVE_SET_ECC: DWORD = 0x80000100; +pub const TAPE_DRIVE_SET_COMPRESSION: DWORD = 0x80000200; +pub const TAPE_DRIVE_SET_PADDING: DWORD = 0x80000400; +pub const TAPE_DRIVE_SET_REPORT_SMKS: DWORD = 0x80000800; +pub const TAPE_DRIVE_ABSOLUTE_BLK: DWORD = 0x80001000; +pub const TAPE_DRIVE_ABS_BLK_IMMED: DWORD = 0x80002000; +pub const TAPE_DRIVE_LOGICAL_BLK: DWORD = 0x80004000; +pub const TAPE_DRIVE_LOG_BLK_IMMED: DWORD = 0x80008000; +pub const TAPE_DRIVE_END_OF_DATA: DWORD = 0x80010000; +pub const TAPE_DRIVE_RELATIVE_BLKS: DWORD = 0x80020000; +pub const TAPE_DRIVE_FILEMARKS: DWORD = 0x80040000; +pub const TAPE_DRIVE_SEQUENTIAL_FMKS: DWORD = 0x80080000; +pub const TAPE_DRIVE_SETMARKS: DWORD = 0x80100000; +pub const TAPE_DRIVE_SEQUENTIAL_SMKS: DWORD = 0x80200000; +pub const TAPE_DRIVE_REVERSE_POSITION: DWORD = 0x80400000; +pub const TAPE_DRIVE_SPACE_IMMEDIATE: DWORD = 0x80800000; +pub const TAPE_DRIVE_WRITE_SETMARKS: DWORD = 0x81000000; +pub const TAPE_DRIVE_WRITE_FILEMARKS: DWORD = 0x82000000; +pub const TAPE_DRIVE_WRITE_SHORT_FMKS: DWORD = 0x84000000; +pub const TAPE_DRIVE_WRITE_LONG_FMKS: DWORD = 0x88000000; +pub const TAPE_DRIVE_WRITE_MARK_IMMED: DWORD = 0x90000000; +pub const TAPE_DRIVE_FORMAT: DWORD = 0xA0000000; +pub const TAPE_DRIVE_FORMAT_IMMEDIATE: DWORD = 0xC0000000; +pub const TAPE_DRIVE_HIGH_FEATURES: DWORD = 0x80000000; +STRUCT!{struct TAPE_GET_DRIVE_PARAMETERS { + ECC: BOOLEAN, + Compression: BOOLEAN, + DataPadding: BOOLEAN, + ReportSetmarks: BOOLEAN, + DefaultBlockSize: DWORD, + MaximumBlockSize: DWORD, + MinimumBlockSize: DWORD, + MaximumPartitionCount: DWORD, + FeaturesLow: DWORD, + FeaturesHigh: DWORD, + EOTWarningZoneSize: DWORD, +}} +pub type PTAPE_GET_DRIVE_PARAMETERS = *mut TAPE_GET_DRIVE_PARAMETERS; +STRUCT!{struct TAPE_SET_DRIVE_PARAMETERS { + ECC: BOOLEAN, + Compression: BOOLEAN, + DataPadding: BOOLEAN, + ReportSetmarks: BOOLEAN, + EOTWarningZoneSize: DWORD, +}} +pub type PTAPE_SET_DRIVE_PARAMETERS = *mut TAPE_SET_DRIVE_PARAMETERS; +STRUCT!{struct TAPE_GET_MEDIA_PARAMETERS { + Capacity: LARGE_INTEGER, + Remaining: LARGE_INTEGER, + BlockSize: DWORD, + PartitionCount: DWORD, + WriteProtected: BOOLEAN, +}} +pub type PTAPE_GET_MEDIA_PARAMETERS = *mut TAPE_GET_MEDIA_PARAMETERS; +STRUCT!{struct TAPE_SET_MEDIA_PARAMETERS { + BlockSize: DWORD, +}} +pub type PTAPE_SET_MEDIA_PARAMETERS = *mut TAPE_SET_MEDIA_PARAMETERS; +pub const TAPE_FIXED_PARTITIONS: DWORD = 0; +pub const TAPE_SELECT_PARTITIONS: DWORD = 1; +pub const TAPE_INITIATOR_PARTITIONS: DWORD = 2; +STRUCT!{struct TAPE_CREATE_PARTITION { + Method: DWORD, + Count: DWORD, + Size: DWORD, +}} +pub type PTAPE_CREATE_PARTITION = *mut TAPE_CREATE_PARTITION; +pub const TAPE_QUERY_DRIVE_PARAMETERS: DWORD = 0; +pub const TAPE_QUERY_MEDIA_CAPACITY: DWORD = 1; +pub const TAPE_CHECK_FOR_DRIVE_PROBLEM: DWORD = 2; +pub const TAPE_QUERY_IO_ERROR_DATA: DWORD = 3; +pub const TAPE_QUERY_DEVICE_ERROR_DATA: DWORD = 4; +STRUCT!{struct TAPE_WMI_OPERATIONS { + Method: DWORD, + DataBufferSize: DWORD, + DataBuffer: PVOID, +}} +pub type PTAPE_WMI_OPERATIONS = *mut TAPE_WMI_OPERATIONS; +ENUM!{enum TAPE_DRIVE_PROBLEM_TYPE { + TapeDriveProblemNone, + TapeDriveReadWriteWarning, + TapeDriveReadWriteError, + TapeDriveReadWarning, + TapeDriveWriteWarning, + TapeDriveReadError, + TapeDriveWriteError, + TapeDriveHardwareError, + TapeDriveUnsupportedMedia, + TapeDriveScsiConnectionError, + TapeDriveTimetoClean, + TapeDriveCleanDriveNow, + TapeDriveMediaLifeExpired, + TapeDriveSnappedTape, +}} +pub const TRANSACTIONMANAGER_QUERY_INFORMATION: DWORD = 0x0001; +pub const TRANSACTIONMANAGER_SET_INFORMATION: DWORD = 0x0002; +pub const TRANSACTIONMANAGER_RECOVER: DWORD = 0x0004; +pub const TRANSACTIONMANAGER_RENAME: DWORD = 0x0008; +pub const TRANSACTIONMANAGER_CREATE_RM: DWORD = 0x0010; +pub const TRANSACTIONMANAGER_BIND_TRANSACTION: DWORD = 0x0020; +pub const TRANSACTIONMANAGER_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ + | TRANSACTIONMANAGER_QUERY_INFORMATION; +pub const TRANSACTIONMANAGER_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE + | TRANSACTIONMANAGER_SET_INFORMATION | TRANSACTIONMANAGER_RECOVER | TRANSACTIONMANAGER_RENAME + | TRANSACTIONMANAGER_CREATE_RM; +pub const TRANSACTIONMANAGER_GENERIC_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE; +pub const TRANSACTIONMANAGER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED + | TRANSACTIONMANAGER_GENERIC_READ | TRANSACTIONMANAGER_GENERIC_WRITE + | TRANSACTIONMANAGER_GENERIC_EXECUTE | TRANSACTIONMANAGER_BIND_TRANSACTION; +pub const TRANSACTION_QUERY_INFORMATION: DWORD = 0x0001; +pub const TRANSACTION_SET_INFORMATION: DWORD = 0x0002; +pub const TRANSACTION_ENLIST: DWORD = 0x0004; +pub const TRANSACTION_COMMIT: DWORD = 0x0008; +pub const TRANSACTION_ROLLBACK: DWORD = 0x0010; +pub const TRANSACTION_PROPAGATE: DWORD = 0x0020; +pub const TRANSACTION_RIGHT_RESERVED1: DWORD = 0x0040; +pub const TRANSACTION_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | TRANSACTION_QUERY_INFORMATION + | SYNCHRONIZE; +pub const TRANSACTION_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | TRANSACTION_SET_INFORMATION + | TRANSACTION_COMMIT | TRANSACTION_ENLIST | TRANSACTION_ROLLBACK | TRANSACTION_PROPAGATE + | SYNCHRONIZE; +pub const TRANSACTION_GENERIC_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | TRANSACTION_COMMIT + | TRANSACTION_ROLLBACK | SYNCHRONIZE; +pub const TRANSACTION_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | TRANSACTION_GENERIC_READ + | TRANSACTION_GENERIC_WRITE | TRANSACTION_GENERIC_EXECUTE; +pub const TRANSACTION_RESOURCE_MANAGER_RIGHTS: DWORD = TRANSACTION_GENERIC_READ + | STANDARD_RIGHTS_WRITE | TRANSACTION_SET_INFORMATION | TRANSACTION_ENLIST + | TRANSACTION_ROLLBACK | TRANSACTION_PROPAGATE | SYNCHRONIZE; +pub const RESOURCEMANAGER_QUERY_INFORMATION: DWORD = 0x0001; +pub const RESOURCEMANAGER_SET_INFORMATION: DWORD = 0x0002; +pub const RESOURCEMANAGER_RECOVER: DWORD = 0x0004; +pub const RESOURCEMANAGER_ENLIST: DWORD = 0x0008; +pub const RESOURCEMANAGER_GET_NOTIFICATION: DWORD = 0x0010; +pub const RESOURCEMANAGER_REGISTER_PROTOCOL: DWORD = 0x0020; +pub const RESOURCEMANAGER_COMPLETE_PROPAGATION: DWORD = 0x0040; +pub const RESOURCEMANAGER_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ + | RESOURCEMANAGER_QUERY_INFORMATION | SYNCHRONIZE; +pub const RESOURCEMANAGER_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE + | RESOURCEMANAGER_SET_INFORMATION | RESOURCEMANAGER_RECOVER | RESOURCEMANAGER_ENLIST + | RESOURCEMANAGER_GET_NOTIFICATION | RESOURCEMANAGER_REGISTER_PROTOCOL + | RESOURCEMANAGER_COMPLETE_PROPAGATION | SYNCHRONIZE; +pub const RESOURCEMANAGER_GENERIC_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE + | RESOURCEMANAGER_RECOVER | RESOURCEMANAGER_ENLIST | RESOURCEMANAGER_GET_NOTIFICATION + | RESOURCEMANAGER_COMPLETE_PROPAGATION | SYNCHRONIZE; +pub const RESOURCEMANAGER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED + | RESOURCEMANAGER_GENERIC_READ | RESOURCEMANAGER_GENERIC_WRITE + | RESOURCEMANAGER_GENERIC_EXECUTE; +pub const ENLISTMENT_QUERY_INFORMATION: DWORD = 0x0001; +pub const ENLISTMENT_SET_INFORMATION: DWORD = 0x0002; +pub const ENLISTMENT_RECOVER: DWORD = 0x0004; +pub const ENLISTMENT_SUBORDINATE_RIGHTS: DWORD = 0x0008; +pub const ENLISTMENT_SUPERIOR_RIGHTS: DWORD = 0x0010; +pub const ENLISTMENT_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | ENLISTMENT_QUERY_INFORMATION; +pub const ENLISTMENT_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | ENLISTMENT_SET_INFORMATION + | ENLISTMENT_RECOVER | ENLISTMENT_SUBORDINATE_RIGHTS | ENLISTMENT_SUPERIOR_RIGHTS; +pub const ENLISTMENT_GENERIC_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | ENLISTMENT_RECOVER + | ENLISTMENT_SUBORDINATE_RIGHTS | ENLISTMENT_SUPERIOR_RIGHTS; +pub const ENLISTMENT_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | ENLISTMENT_GENERIC_READ + | ENLISTMENT_GENERIC_WRITE | ENLISTMENT_GENERIC_EXECUTE; +ENUM!{enum TRANSACTION_OUTCOME { + TransactionOutcomeUndetermined = 1, + TransactionOutcomeCommitted, + TransactionOutcomeAborted, +}} +ENUM!{enum TRANSACTION_STATE { + TransactionStateNormal = 1, + TransactionStateIndoubt, + TransactionStateCommittedNotify, +}} +STRUCT!{struct TRANSACTION_BASIC_INFORMATION { + TransactionId: GUID, + State: DWORD, + Outcome: DWORD, +}} +pub type PTRANSACTION_BASIC_INFORMATION = *mut TRANSACTION_BASIC_INFORMATION; +STRUCT!{struct TRANSACTIONMANAGER_BASIC_INFORMATION { + TmIdentity: GUID, + VirtualClock: LARGE_INTEGER, +}} +pub type PTRANSACTIONMANAGER_BASIC_INFORMATION = *mut TRANSACTIONMANAGER_BASIC_INFORMATION; +STRUCT!{struct TRANSACTIONMANAGER_LOG_INFORMATION { + LogIdentity: GUID, +}} +pub type PTRANSACTIONMANAGER_LOG_INFORMATION = *mut TRANSACTIONMANAGER_LOG_INFORMATION; +STRUCT!{struct TRANSACTIONMANAGER_LOGPATH_INFORMATION { + LogPathLength: DWORD, + LogPath: [WCHAR; 1], +}} +pub type PTRANSACTIONMANAGER_LOGPATH_INFORMATION = *mut TRANSACTIONMANAGER_LOGPATH_INFORMATION; +STRUCT!{struct TRANSACTIONMANAGER_RECOVERY_INFORMATION { + LastRecoveredLsn: ULONGLONG, +}} +pub type PTRANSACTIONMANAGER_RECOVERY_INFORMATION = *mut TRANSACTIONMANAGER_RECOVERY_INFORMATION; +STRUCT!{struct TRANSACTIONMANAGER_OLDEST_INFORMATION { + OldestTransactionGuid: GUID, +}} +pub type PTRANSACTIONMANAGER_OLDEST_INFORMATION = *mut TRANSACTIONMANAGER_OLDEST_INFORMATION; +STRUCT!{struct TRANSACTION_PROPERTIES_INFORMATION { + IsolationLevel: DWORD, + IsolationFlags: DWORD, + Timeout: LARGE_INTEGER, + Outcome: DWORD, + DescriptionLength: DWORD, + Description: [WCHAR; 1], +}} +pub type PTRANSACTION_PROPERTIES_INFORMATION = *mut TRANSACTION_PROPERTIES_INFORMATION; +STRUCT!{struct TRANSACTION_BIND_INFORMATION { + TmHandle: HANDLE, +}} +pub type PTRANSACTION_BIND_INFORMATION = *mut TRANSACTION_BIND_INFORMATION; +STRUCT!{struct TRANSACTION_ENLISTMENT_PAIR { + EnlistmentId: GUID, + ResourceManagerId: GUID, +}} +pub type PTRANSACTION_ENLISTMENT_PAIR = *mut TRANSACTION_ENLISTMENT_PAIR; +STRUCT!{struct TRANSACTION_ENLISTMENTS_INFORMATION { + NumberOfEnlistments: DWORD, + EnlistmentPair: [TRANSACTION_ENLISTMENT_PAIR; 1], +}} +pub type PTRANSACTION_ENLISTMENTS_INFORMATION = *mut TRANSACTION_ENLISTMENTS_INFORMATION; +STRUCT!{struct TRANSACTION_SUPERIOR_ENLISTMENT_INFORMATION { + SuperiorEnlistmentPair: TRANSACTION_ENLISTMENT_PAIR, +}} +pub type PTRANSACTION_SUPERIOR_ENLISTMENT_INFORMATION + = *mut TRANSACTION_SUPERIOR_ENLISTMENT_INFORMATION; +STRUCT!{struct RESOURCEMANAGER_BASIC_INFORMATION { + ResourceManagerId: GUID, + DescriptionLength: DWORD, + Description: [WCHAR; 1], +}} +pub type PRESOURCEMANAGER_BASIC_INFORMATION = *mut RESOURCEMANAGER_BASIC_INFORMATION; +STRUCT!{struct RESOURCEMANAGER_COMPLETION_INFORMATION { + IoCompletionPortHandle: HANDLE, + CompletionKey: ULONG_PTR, +}} +pub type PRESOURCEMANAGER_COMPLETION_INFORMATION = *mut RESOURCEMANAGER_COMPLETION_INFORMATION; +ENUM!{enum TRANSACTION_INFORMATION_CLASS { + TransactionBasicInformation, + TransactionPropertiesInformation, + TransactionEnlistmentInformation, + TransactionSuperiorEnlistmentInformation, + TransactionBindInformation, + TransactionDTCPrivateInformation, +}} +ENUM!{enum TRANSACTIONMANAGER_INFORMATION_CLASS { + TransactionManagerBasicInformation, + TransactionManagerLogInformation, + TransactionManagerLogPathInformation, + TransactionManagerRecoveryInformation = 4, + TransactionManagerOnlineProbeInformation = 3, + TransactionManagerOldestTransactionInformation = 5, +}} +ENUM!{enum RESOURCEMANAGER_INFORMATION_CLASS { + ResourceManagerBasicInformation, + ResourceManagerCompletionInformation, +}} +STRUCT!{struct ENLISTMENT_BASIC_INFORMATION { + EnlistmentId: GUID, + TransactionId: GUID, + ResourceManagerId: GUID, +}} +pub type PENLISTMENT_BASIC_INFORMATION = *mut ENLISTMENT_BASIC_INFORMATION; +STRUCT!{struct ENLISTMENT_CRM_INFORMATION { + CrmTransactionManagerId: GUID, + CrmResourceManagerId: GUID, + CrmEnlistmentId: GUID, +}} +pub type PENLISTMENT_CRM_INFORMATION = *mut ENLISTMENT_CRM_INFORMATION; +ENUM!{enum ENLISTMENT_INFORMATION_CLASS { + EnlistmentBasicInformation, + EnlistmentRecoveryInformation, + EnlistmentCrmInformation, +}} +STRUCT!{struct TRANSACTION_LIST_ENTRY { + UOW: UOW, +}} +pub type PTRANSACTION_LIST_ENTRY = *mut TRANSACTION_LIST_ENTRY; +STRUCT!{struct TRANSACTION_LIST_INFORMATION { + NumberOfTransactions: DWORD, + TransactionInformation: [TRANSACTION_LIST_ENTRY; 1], +}} +pub type PTRANSACTION_LIST_INFORMATION = *mut TRANSACTION_LIST_INFORMATION; +ENUM!{enum KTMOBJECT_TYPE { + KTMOBJECT_TRANSACTION, + KTMOBJECT_TRANSACTION_MANAGER, + KTMOBJECT_RESOURCE_MANAGER, + KTMOBJECT_ENLISTMENT, + KTMOBJECT_INVALID, +}} +pub type PKTMOBJECT_TYPE = *mut KTMOBJECT_TYPE; +STRUCT!{struct KTMOBJECT_CURSOR { + LastQuery: GUID, + ObjectIdCount: DWORD, + ObjectIds: [GUID; 1], +}} +pub type PKTMOBJECT_CURSOR = *mut KTMOBJECT_CURSOR; +pub type TP_VERSION = DWORD; +pub type PTP_VERSION = *mut DWORD; +STRUCT!{struct TP_CALLBACK_INSTANCE { + dummy: *mut c_void, +}} +pub type PTP_CALLBACK_INSTANCE = *mut TP_CALLBACK_INSTANCE; +FN!{stdcall PTP_SIMPLE_CALLBACK( + Instance: PTP_CALLBACK_INSTANCE, + Context: PVOID, +) -> ()} +STRUCT!{struct TP_POOL { + dummy: *mut c_void, +}} +pub type PTP_POOL = *mut TP_POOL; +ENUM!{enum TP_CALLBACK_PRIORITY { + TP_CALLBACK_PRIORITY_HIGH, + TP_CALLBACK_PRIORITY_NORMAL, + TP_CALLBACK_PRIORITY_LOW, + TP_CALLBACK_PRIORITY_INVALID, + TP_CALLBACK_PRIORITY_COUNT = TP_CALLBACK_PRIORITY_INVALID, +}} +STRUCT!{struct TP_POOL_STACK_INFORMATION { + StackReserve: SIZE_T, + StackCommit: SIZE_T, +}} +pub type PTP_POOL_STACK_INFORMATION = *mut TP_POOL_STACK_INFORMATION; +STRUCT!{struct TP_CLEANUP_GROUP { + dummy: *mut c_void, +}} +pub type PTP_CLEANUP_GROUP = *mut TP_CLEANUP_GROUP; +FN!{stdcall PTP_CLEANUP_GROUP_CANCEL_CALLBACK( + ObjectContext: PVOID, + CleanupContext: PVOID, +) -> ()} +STRUCT!{struct TP_CALLBACK_ENVIRON_V3_u_s { + BitFields: DWORD, +}} +BITFIELD!{TP_CALLBACK_ENVIRON_V3_u_s BitFields: DWORD [ + LongFunction set_LongFunction[0..1], + Persistent set_Persistent[1..2], + Private set_Private[2..32], +]} +UNION!{union TP_CALLBACK_ENVIRON_V3_u { + [u32; 1], + Flags Flags_mut: DWORD, + s s_mut: TP_CALLBACK_ENVIRON_V3_u_s, +}} +STRUCT!{struct TP_CALLBACK_ENVIRON_V3 { + Version: TP_VERSION, + Pool: PTP_POOL, + CleanupGroup: PTP_CLEANUP_GROUP, + CleanupGroupCancelCallback: PTP_CLEANUP_GROUP_CANCEL_CALLBACK, + RaceDll: PVOID, + ActivationContext: *mut ACTIVATION_CONTEXT, + FinalizationCallback: PTP_SIMPLE_CALLBACK, + u: TP_CALLBACK_ENVIRON_V3_u, + CallbackPriority: TP_CALLBACK_PRIORITY, + Size: DWORD, +}} +pub type TP_CALLBACK_ENVIRON = TP_CALLBACK_ENVIRON_V3; +pub type PTP_CALLBACK_ENVIRON = *mut TP_CALLBACK_ENVIRON_V3; +STRUCT!{struct TP_WORK { + dummy: *mut c_void, +}} +pub type PTP_WORK = *mut TP_WORK; +FN!{stdcall PTP_WORK_CALLBACK( + Instance: PTP_CALLBACK_INSTANCE, + Context: PVOID, + Work: PTP_WORK, +) -> ()} +STRUCT!{struct TP_TIMER { + dummy: *mut c_void, +}} +pub type PTP_TIMER = *mut TP_TIMER; +FN!{stdcall PTP_TIMER_CALLBACK( + Instance: PTP_CALLBACK_INSTANCE, + Context: PVOID, + Timer: PTP_TIMER, +) -> ()} +pub type TP_WAIT_RESULT = DWORD; +STRUCT!{struct TP_WAIT { + dummy: *mut c_void, +}} +pub type PTP_WAIT = *mut TP_WAIT; +FN!{stdcall PTP_WAIT_CALLBACK( + Instance: PTP_CALLBACK_INSTANCE, + Context: PVOID, + Wait: PTP_WAIT, + WaitResult: TP_WAIT_RESULT, +) -> ()} +STRUCT!{struct TP_IO { + dummy: *mut c_void, +}} +pub type PTP_IO = *mut TP_IO; +pub const ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION: ULONG = 1; +pub const ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION: ULONG = 2; +pub const ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION: ULONG = 3; +pub const ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION: ULONG = 4; +pub const ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION: ULONG = 5; +pub const ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION: ULONG = 6; +pub const ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION: ULONG = 7; +pub const ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE: ULONG = 8; +pub const ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES: ULONG = 9; +pub const ACTIVATION_CONTEXT_SECTION_APPLICATION_SETTINGS: ULONG = 10; +pub const ACTIVATION_CONTEXT_SECTION_COMPATIBILITY_INFO: ULONG = 11; +STRUCT!{struct ACTIVATION_CONTEXT { + dummy: *mut c_void, +}} diff --git a/winapi/src/um/winreg.rs b/winapi/src/um/winreg.rs new file mode 100644 index 000000000..3097ef04c --- /dev/null +++ b/winapi/src/um/winreg.rs @@ -0,0 +1,490 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::DWORD_PTR; +use shared::minwindef::{ + BOOL, BYTE, DWORD, HKEY, LPBYTE, LPCVOID, LPDWORD, PFILETIME, PHKEY, ULONG +}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::winnt::{ACCESS_MASK, HANDLE, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PVOID}; +pub type LSTATUS = LONG; +pub const RRF_RT_REG_NONE: DWORD = 0x00000001; +pub const RRF_RT_REG_SZ: DWORD = 0x00000002; +pub const RRF_RT_REG_EXPAND_SZ: DWORD = 0x00000004; +pub const RRF_RT_REG_BINARY: DWORD = 0x00000008; +pub const RRF_RT_REG_DWORD: DWORD = 0x00000010; +pub const RRF_RT_REG_MULTI_SZ: DWORD = 0x00000020; +pub const RRF_RT_REG_QWORD: DWORD = 0x00000040; +pub const RRF_RT_DWORD: DWORD = RRF_RT_REG_BINARY | RRF_RT_REG_DWORD; +pub const RRF_RT_QWORD: DWORD = RRF_RT_REG_BINARY | RRF_RT_REG_QWORD; +pub const RRF_RT_ANY: DWORD = 0x0000ffff; +pub const RRF_SUBKEY_WOW6464KEY: DWORD = 0x00010000; +pub const RRF_SUBKEY_WOW6432KEY: DWORD = 0x00020000; +pub const RRF_WOW64_MASK: DWORD = 0x00030000; +pub const RRF_NOEXPAND: DWORD = 0x10000000; +pub const RRF_ZEROONFAILURE: DWORD = 0x20000000; +pub const REG_PROCESS_APPKEY: DWORD = 0x00000001; +pub type REGSAM = ACCESS_MASK; +pub const HKEY_CLASSES_ROOT: HKEY = 0x80000000i32 as isize as HKEY; +pub const HKEY_CURRENT_USER: HKEY = 0x80000001i32 as isize as HKEY; +pub const HKEY_LOCAL_MACHINE: HKEY = 0x80000002i32 as isize as HKEY; +pub const HKEY_USERS: HKEY = 0x80000003i32 as isize as HKEY; +pub const HKEY_PERFORMANCE_DATA: HKEY = 0x80000004i32 as isize as HKEY; +pub const HKEY_PERFORMANCE_TEXT: HKEY = 0x80000050i32 as isize as HKEY; +pub const HKEY_PERFORMANCE_NLSTEXT: HKEY = 0x80000060i32 as isize as HKEY; +pub const HKEY_CURRENT_CONFIG: HKEY = 0x80000005i32 as isize as HKEY; +pub const HKEY_DYN_DATA: HKEY = 0x80000006i32 as isize as HKEY; +pub const HKEY_CURRENT_USER_LOCAL_SETTINGS: HKEY = 0x80000007i32 as isize as HKEY; +// PROVIDER_KEEPS_VALUE_LENGTH +// val_context +// PVALUEA +// PVALUEW +// QUERYHANDLER +// REG_PROVIDER +STRUCT!{struct VALENTA { + ve_valuename: LPSTR, + ve_valuelen: DWORD, + ve_valueptr: DWORD_PTR, + ve_type: DWORD, +}} +pub type PVALENTA = *mut VALENTA; +STRUCT!{struct VALENTW { + ve_valuename: LPWSTR, + ve_valuelen: DWORD, + ve_valueptr: DWORD_PTR, + ve_type: DWORD, +}} +pub type PVALENTW = *mut VALENTW; +// WIN31_CLASS +pub const REG_MUI_STRING_TRUNCATE: DWORD = 0x00000001; +pub const REG_SECURE_CONNECTION: DWORD = 1; +extern "system" { + pub fn RegCloseKey( + hKey: HKEY, + ) -> LSTATUS; + pub fn RegOverridePredefKey( + hKey: HKEY, + hNewHKey: HKEY, + ) -> LSTATUS; + pub fn RegOpenUserClassesRoot( + hToken: HANDLE, + dwOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegOpenCurrentUser( + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegDisablePredefinedCache() -> LSTATUS; + pub fn RegDisablePredefinedCacheEx() -> LSTATUS; + pub fn RegConnectRegistryA( + lpMachineName: LPCSTR, + hKey: HKEY, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegConnectRegistryW( + lpMachineName: LPCWSTR, + hKey: HKEY, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegConnectRegistryExA( + lpMachineName: LPCSTR, + hKey: HKEY, + flags: ULONG, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegConnectRegistryExW( + lpMachineName: LPCWSTR, + hKey: HKEY, + flags: ULONG, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegCreateKeyA( + hKey: HKEY, + lpSubKey: LPCSTR, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegCreateKeyW( + hKey: HKEY, + lpSubKey: LPCWSTR, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegCreateKeyExA( + hKey: HKEY, + lpSubKey: LPCSTR, + Reserved: DWORD, + lpClass: LPSTR, + dwOptions: DWORD, + samDesired: REGSAM, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + phkResult: PHKEY, + lpdwDisposition: LPDWORD, + ) -> LSTATUS; + pub fn RegCreateKeyExW( + hKey: HKEY, + lpSubKey: LPCWSTR, + Reserved: DWORD, + lpClass: LPWSTR, + dwOptions: DWORD, + samDesired: REGSAM, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + phkResult: PHKEY, + lpdwDisposition: LPDWORD, + ) -> LSTATUS; + pub fn RegCreateKeyTransactedA( + hKey: HKEY, + lpSubKey: LPCSTR, + Reserved: DWORD, + lpClass: LPSTR, + dwOptions: DWORD, + samDesired: REGSAM, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + phkResult: PHKEY, + lpdwDisposition: LPDWORD, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegCreateKeyTransactedW( + hKey: HKEY, + lpSubKey: LPCWSTR, + Reserved: DWORD, + lpClass: LPWSTR, + dwOptions: DWORD, + samDesired: REGSAM, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + phkResult: PHKEY, + lpdwDisposition: LPDWORD, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegDeleteKeyA( + hKey: HKEY, + lpSubKey: LPCSTR, + ) -> LSTATUS; + pub fn RegDeleteKeyW( + hKey: HKEY, + lpSubKey: LPCWSTR, + ) -> LSTATUS; + pub fn RegDeleteKeyExA( + hKey: HKEY, + lpSubKey: LPCSTR, + samDesired: REGSAM, + Reserved: DWORD, + ) -> LSTATUS; + pub fn RegDeleteKeyExW( + hKey: HKEY, + lpSubKey: LPCWSTR, + samDesired: REGSAM, + Reserved: DWORD, + ) -> LSTATUS; + pub fn RegDeleteKeyTransactedA( + hKey: HKEY, + lpSubKey: LPCSTR, + samDesired: REGSAM, + Reserved: DWORD, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegDeleteKeyTransactedW( + hKey: HKEY, + lpSubKey: LPCWSTR, + samDesired: REGSAM, + Reserved: DWORD, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegDisableReflectionKey( + hBase: HKEY, + ) -> LONG; + pub fn RegEnableReflectionKey( + hBase: HKEY, + ) -> LONG; + pub fn RegQueryReflectionKey( + hBase: HKEY, + bIsReflectionDisabled: *mut BOOL, + ) -> LONG; + pub fn RegDeleteValueA( + hKey: HKEY, + lpValueName: LPCSTR, + ) -> LSTATUS; + pub fn RegDeleteValueW( + hKey: HKEY, + lpValueName: LPCWSTR, + ) -> LSTATUS; + // pub fn RegEnumKeyA(); + // pub fn RegEnumKeyW(); + pub fn RegEnumKeyExA( + hKey: HKEY, + dwIndex: DWORD, + lpName: LPSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LSTATUS; + pub fn RegEnumKeyExW( + hKey: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LSTATUS; + pub fn RegEnumValueA( + hKey: HKEY, + dwIndex: DWORD, + lpValueName: LPSTR, + lpcchValueName: LPDWORD, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LSTATUS; + pub fn RegEnumValueW( + hKey: HKEY, + dwIndex: DWORD, + lpValueName: LPWSTR, + lpcchValueName: LPDWORD, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LSTATUS; + pub fn RegFlushKey( + hKey: HKEY, + ) -> LSTATUS; + // pub fn RegGetKeySecurity(); + // pub fn RegLoadKeyA(); + // pub fn RegLoadKeyW(); + pub fn RegNotifyChangeKeyValue( + hKey: HKEY, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + hEvent: HANDLE, + fAsynchronous: BOOL, + ) -> LSTATUS; + // pub fn RegOpenKeyA(); + // pub fn RegOpenKeyW(); + pub fn RegOpenKeyExA( + hKey: HKEY, + lpSubKey: LPCSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegOpenKeyExW( + hKey: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LSTATUS; + pub fn RegOpenKeyTransactedA( + hKey: HKEY, + lpSubKey: LPCSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegOpenKeyTransactedW( + hKey: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + hTransaction: HANDLE, + pExtendedParemeter: PVOID, + ) -> LSTATUS; + pub fn RegQueryInfoKeyA( + hKey: HKEY, + lpClass: LPSTR, + lpcClass: LPDWORD, + lpReserved: LPDWORD, + lpcSubKeys: LPDWORD, + lpcMaxSubKeyLen: LPDWORD, + lpcMaxClassLen: LPDWORD, + lpcValues: LPDWORD, + lpcMaxValueNameLen: LPDWORD, + lpcMaxValueLen: LPDWORD, + lpcbSecurityDescriptor: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LSTATUS; + pub fn RegQueryInfoKeyW( + hKey: HKEY, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpReserved: LPDWORD, + lpcSubKeys: LPDWORD, + lpcMaxSubKeyLen: LPDWORD, + lpcMaxClassLen: LPDWORD, + lpcValues: LPDWORD, + lpcMaxValueNameLen: LPDWORD, + lpcMaxValueLen: LPDWORD, + lpcbSecurityDescriptor: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LSTATUS; + // pub fn RegQueryValueA(); + // pub fn RegQueryValueW(); + pub fn RegQueryMultipleValuesA( + hKey: HKEY, + val_list: PVALENTA, + num_vals: DWORD, + lpValueBuf: LPSTR, + ldwTotsize: LPDWORD, + ) -> LSTATUS; + pub fn RegQueryMultipleValuesW( + hKey: HKEY, + val_list: PVALENTW, + num_vals: DWORD, + lpValueBuf: LPWSTR, + ldwTotsize: LPDWORD, + ) -> LSTATUS; + pub fn RegQueryValueExA( + hKey: HKEY, + lpValueName: LPCSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LSTATUS; + pub fn RegQueryValueExW( + hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LSTATUS; + // pub fn RegReplaceKeyA(); + // pub fn RegReplaceKeyW(); + // pub fn RegRestoreKeyA(); + // pub fn RegRestoreKeyW(); + // pub fn RegRenameKey(); + // pub fn RegSaveKeyA(); + // pub fn RegSaveKeyW(); + // pub fn RegSetKeySecurity(); + // pub fn RegSetValueA(); + // pub fn RegSetValueW(); + pub fn RegSetValueExA( + hKey: HKEY, + lpValueName: LPCSTR, + Reserved: DWORD, + dwType: DWORD, + lpData: *const BYTE, + cbData: DWORD, + ) -> LSTATUS; + pub fn RegSetValueExW( + hKey: HKEY, + lpValueName: LPCWSTR, + Reserved: DWORD, + dwType: DWORD, + lpData: *const BYTE, + cbData: DWORD, + ) -> LSTATUS; + // pub fn RegUnLoadKeyA(); + // pub fn RegUnLoadKeyW(); + pub fn RegDeleteKeyValueA( + hKey: HKEY, + lpSubKey: LPCSTR, + lpValueName: LPCSTR, + ) -> LSTATUS; + pub fn RegDeleteKeyValueW( + hKey: HKEY, + lpSubKey: LPCWSTR, + lpValueName: LPCWSTR, + ) -> LSTATUS; + pub fn RegSetKeyValueA( + hKey: HKEY, + lpSubKey: LPCSTR, + lpValueName: LPCSTR, + dwType: DWORD, + lpData: LPCVOID, + cbData: DWORD, + ) -> LSTATUS; + pub fn RegSetKeyValueW( + hKey: HKEY, + lpSubKey: LPCWSTR, + lpValueName: LPCWSTR, + dwType: DWORD, + lpData: LPCVOID, + cbData: DWORD, + ) -> LSTATUS; + pub fn RegDeleteTreeA( + hKey: HKEY, + lpSubKey: LPCSTR, + ) -> LSTATUS; + pub fn RegDeleteTreeW( + hKey: HKEY, + lpSubKey: LPCWSTR, + ) -> LSTATUS; + pub fn RegCopyTreeA( + hKeySrc: HKEY, + lpSubKey: LPCSTR, + hKeyDest: HKEY, + ) -> LSTATUS; + pub fn RegGetValueA( + hkey: HKEY, + lpSubKey: LPCSTR, + lpValue: LPCSTR, + dwFlags: DWORD, + pdwType: LPDWORD, + pvData: PVOID, + pcbData: LPDWORD, + ) -> LSTATUS; + pub fn RegGetValueW( + hkey: HKEY, + lpSubKey: LPCWSTR, + lpValue: LPCWSTR, + dwFlags: DWORD, + pdwType: LPDWORD, + pvData: PVOID, + pcbData: LPDWORD, + ) -> LSTATUS; + pub fn RegCopyTreeW( + hKeySrc: HKEY, + lpSubKey: LPCWSTR, + hKeyDest: HKEY, + ) -> LSTATUS; + // pub fn RegLoadMUIStringA(); + pub fn RegLoadMUIStringW( + hKey: HKEY, + pszValue: LPCWSTR, + pszOutBuf: LPWSTR, + cbOutBuf: DWORD, + pcbData: LPDWORD, + Flags: DWORD, + pszDirectory: LPCWSTR, + ) -> LSTATUS; + // pub fn RegLoadAppKeyA(); + // pub fn RegLoadAppKeyW(); + // pub fn InitiateSystemShutdownA(); + // pub fn InitiateSystemShutdownW(); + pub fn AbortSystemShutdownA( + lpMachineName: LPSTR, + ) -> BOOL; + pub fn AbortSystemShutdownW( + lpMachineName: LPWSTR, + ) -> BOOL; +} +// REASON_* +// MAX_SHUTDOWN_TIMEOUT +extern "system" { + // pub fn InitiateSystemShutdownExA(); + // pub fn InitiateSystemShutdownExW(); +} +// SHUTDOWN_* +extern "system" { + // pub fn InitiateShutdownA(); + // pub fn InitiateShutdownW(); + // pub fn CheckForHiberboot(); + // pub fn RegSaveKeyExA(); + // pub fn RegSaveKeyExW(); +} diff --git a/winapi/src/um/winsafer.rs b/winapi/src/um/winsafer.rs new file mode 100644 index 000000000..9607b6772 --- /dev/null +++ b/winapi/src/um/winsafer.rs @@ -0,0 +1,228 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{SIZE_T, ULONG64}; +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, BYTE, DWORD, FILETIME, LPBYTE, LPDWORD, LPVOID, PDWORD}; +use shared::windef::HWND; +use um::wincrypt::ALG_ID; +use um::winnt::{BOOLEAN, HANDLE, LARGE_INTEGER, LPCWSTR, PHANDLE, PVOID, PWCHAR, WCHAR}; +DECLARE_HANDLE!{SAFER_LEVEL_HANDLE, __SAFER_LEVEL_HANDLE} +pub const SAFER_SCOPEID_MACHINE: DWORD = 1; +pub const SAFER_SCOPEID_USER: DWORD = 2; +pub const SAFER_LEVELID_DISALLOWED: DWORD = 0x00000; +pub const SAFER_LEVELID_UNTRUSTED: DWORD = 0x01000; +pub const SAFER_LEVELID_CONSTRAINED: DWORD = 0x10000; +pub const SAFER_LEVELID_NORMALUSER: DWORD = 0x20000; +pub const SAFER_LEVELID_FULLYTRUSTED: DWORD = 0x40000; +pub const SAFER_LEVEL_OPEN: DWORD = 1; +pub const SAFER_MAX_FRIENDLYNAME_SIZE: SIZE_T = 256; +pub const SAFER_MAX_DESCRIPTION_SIZE: SIZE_T = 256; +pub const SAFER_MAX_HASH_SIZE: SIZE_T = 64; +pub const SAFER_TOKEN_NULL_IF_EQUAL: DWORD = 0x00000001; +pub const SAFER_TOKEN_COMPARE_ONLY: DWORD = 0x00000002; +pub const SAFER_TOKEN_MAKE_INERT: DWORD = 0x00000004; +pub const SAFER_TOKEN_WANT_FLAGS: DWORD = 0x00000008; +pub const SAFER_CRITERIA_IMAGEPATH: DWORD = 0x00001; +pub const SAFER_CRITERIA_NOSIGNEDHASH: DWORD = 0x00002; +pub const SAFER_CRITERIA_IMAGEHASH: DWORD = 0x00004; +pub const SAFER_CRITERIA_AUTHENTICODE: DWORD = 0x00008; +pub const SAFER_CRITERIA_URLZONE: DWORD = 0x00010; +pub const SAFER_CRITERIA_APPX_PACKAGE: DWORD = 0x00020; +pub const SAFER_CRITERIA_IMAGEPATH_NT: DWORD = 0x01000; +STRUCT!{struct SAFER_CODE_PROPERTIES_V1 { + cbSize: DWORD, + dwCheckFlags: DWORD, + ImagePath: LPCWSTR, + hImageFileHandle: HANDLE, + UrlZoneId: DWORD, + ImageHash: [BYTE; SAFER_MAX_HASH_SIZE], + dwImageHashSize: DWORD, + ImageSize: LARGE_INTEGER, + HashAlgorithm: ALG_ID, + pByteBlock: LPBYTE, + hWndParent: HWND, + dwWVTUIChoice: DWORD, +}} +pub type PSAFER_CODE_PROPERTIES_V1 = *mut SAFER_CODE_PROPERTIES_V1; +STRUCT!{struct SAFER_CODE_PROPERTIES_V2 { + cbSize: DWORD, + dwCheckFlags: DWORD, + ImagePath: LPCWSTR, + hImageFileHandle: HANDLE, + UrlZoneId: DWORD, + ImageHash: [BYTE; SAFER_MAX_HASH_SIZE], + dwImageHashSize: DWORD, + ImageSize: LARGE_INTEGER, + HashAlgorithm: ALG_ID, + pByteBlock: LPBYTE, + hWndParent: HWND, + dwWVTUIChoice: DWORD, + PackageMoniker: LPCWSTR, + PackagePublisher: LPCWSTR, + PackageName: LPCWSTR, + PackageVersion: ULONG64, + PackageIsFramework: BOOL, +}} +pub type PSAFER_CODE_PROPERTIES_V2 = *mut SAFER_CODE_PROPERTIES_V2; +pub type SAFER_CODE_PROPERTIES = SAFER_CODE_PROPERTIES_V2; +pub type PSAFER_CODE_PROPERTIES = *mut SAFER_CODE_PROPERTIES; +pub const SAFER_POLICY_JOBID_MASK: DWORD = 0xFF000000; +pub const SAFER_POLICY_JOBID_CONSTRAINED: DWORD = 0x04000000; +pub const SAFER_POLICY_JOBID_UNTRUSTED: DWORD = 0x03000000; +pub const SAFER_POLICY_ONLY_EXES: DWORD = 0x00010000; +pub const SAFER_POLICY_SANDBOX_INERT: DWORD = 0x00020000; +pub const SAFER_POLICY_HASH_DUPLICATE: DWORD = 0x00040000; +pub const SAFER_POLICY_ONLY_AUDIT: DWORD = 0x00001000; +pub const SAFER_POLICY_BLOCK_CLIENT_UI: DWORD = 0x00002000; +pub const SAFER_POLICY_UIFLAGS_MASK: DWORD = 0x000000FF; +pub const SAFER_POLICY_UIFLAGS_INFORMATION_PROMPT: DWORD = 0x00000001; +pub const SAFER_POLICY_UIFLAGS_OPTION_PROMPT: DWORD = 0x00000002; +pub const SAFER_POLICY_UIFLAGS_HIDDEN: DWORD = 0x00000004; +ENUM!{enum SAFER_POLICY_INFO_CLASS { + SaferPolicyLevelList = 1, + SaferPolicyEnableTransparentEnforcement, + SaferPolicyDefaultLevel, + SaferPolicyEvaluateUserScope, + SaferPolicyScopeFlags, + SaferPolicyDefaultLevelFlags, + SaferPolicyAuthenticodeEnabled, +}} +ENUM!{enum SAFER_OBJECT_INFO_CLASS { + SaferObjectLevelId = 1, + SaferObjectScopeId, + SaferObjectFriendlyName, + SaferObjectDescription, + SaferObjectBuiltin, + SaferObjectDisallowed, + SaferObjectDisableMaxPrivilege, + SaferObjectInvertDeletedPrivileges, + SaferObjectDeletedPrivileges, + SaferObjectDefaultOwner, + SaferObjectSidsToDisable, + SaferObjectRestrictedSidsInverted, + SaferObjectRestrictedSidsAdded, + SaferObjectAllIdentificationGuids, + SaferObjectSingleIdentification, + SaferObjectExtendedError, +}} +ENUM!{enum SAFER_IDENTIFICATION_TYPES { + SaferIdentityDefault, + SaferIdentityTypeImageName = 1, + SaferIdentityTypeImageHash, + SaferIdentityTypeUrlZone, + SaferIdentityTypeCertificate, +}} +STRUCT!{struct SAFER_IDENTIFICATION_HEADER { + dwIdentificationType: SAFER_IDENTIFICATION_TYPES, + cbStructSize: DWORD, + IdentificationGuid: GUID, + lastModified: FILETIME, +}} +pub type PSAFER_IDENTIFICATION_HEADER = *mut SAFER_IDENTIFICATION_HEADER; +STRUCT!{struct SAFER_PATHNAME_IDENTIFICATION { + header: SAFER_IDENTIFICATION_HEADER, + Description: [WCHAR; SAFER_MAX_DESCRIPTION_SIZE], + ImageName: PWCHAR, + dwSaferFlags: DWORD, +}} +pub type PSAFER_PATHNAME_IDENTIFICATION = *mut SAFER_PATHNAME_IDENTIFICATION; +STRUCT!{struct SAFER_HASH_IDENTIFICATION { + header: SAFER_IDENTIFICATION_HEADER, + Description: [WCHAR; SAFER_MAX_DESCRIPTION_SIZE], + FriendlyName: [WCHAR; SAFER_MAX_DESCRIPTION_SIZE], + HashSize: DWORD, + ImageHash: [BYTE; SAFER_MAX_HASH_SIZE], + HashAlgorithm: ALG_ID, + ImageSize: LARGE_INTEGER, + dwSaferFlags: DWORD, +}} +pub type PSAFER_HASH_IDENTIFICATION = *mut SAFER_HASH_IDENTIFICATION; +STRUCT!{struct SAFER_HASH_IDENTIFICATION2 { + hashIdentification: SAFER_HASH_IDENTIFICATION, + HashSize: DWORD, + ImageHash: [BYTE; SAFER_MAX_HASH_SIZE], + HashAlgorithm: ALG_ID, +}} +pub type PSAFER_HASH_IDENTIFICATION2 = *mut SAFER_HASH_IDENTIFICATION2; +STRUCT!{struct SAFER_URLZONE_IDENTIFICATION { + header: SAFER_IDENTIFICATION_HEADER, + UrlZoneId: DWORD, + dwSaferFlags: DWORD, +}} +pub type PSAFER_URLZONE_IDENTIFICATION = *mut SAFER_URLZONE_IDENTIFICATION; +extern "system" { + pub fn SaferGetPolicyInformation( + dwScopeId: DWORD, + SaferPolicyInfoClass: SAFER_POLICY_INFO_CLASS, + InfoBufferSize: DWORD, + InfoBuffer: PVOID, + InfoBufferRetSize: PDWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferSetPolicyInformation( + dwScopeId: DWORD, + SaferPolicyInfoClass: SAFER_POLICY_INFO_CLASS, + InfoBufferSize: DWORD, + InfoBuffer: PVOID, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferCreateLevel( + dwScopeId: DWORD, + dwLevelId: DWORD, + OpenFlags: DWORD, + pLevelHandle: *mut SAFER_LEVEL_HANDLE, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferCloseLevel( + hLevelHandle: SAFER_LEVEL_HANDLE, + ) -> BOOL; + pub fn SaferIdentifyLevel( + dwNumProperties: DWORD, + pCodeProperties: PSAFER_CODE_PROPERTIES, + pLevelHandle: *mut SAFER_LEVEL_HANDLE, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferComputeTokenFromLevel( + LevelHandle: SAFER_LEVEL_HANDLE, + InAccessToken: HANDLE, + OutAccessToken: PHANDLE, + dwFlags: DWORD, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferGetLevelInformation( + LevelHandle: SAFER_LEVEL_HANDLE, + dwInfoType: SAFER_OBJECT_INFO_CLASS, + lpQueryBuffer: LPVOID, + dwInBufferSize: DWORD, + lpdwOutBufferSize: LPDWORD, + ) -> BOOL; + pub fn SaferSetLevelInformation( + LevelHandle: SAFER_LEVEL_HANDLE, + dwInfoType: SAFER_OBJECT_INFO_CLASS, + lpQueryBuffer: LPVOID, + dwInBufferSize: DWORD, + ) -> BOOL; + pub fn SaferRecordEventLogEntry( + hLevel: SAFER_LEVEL_HANDLE, + szTargetPath: LPCWSTR, + lpReserved: LPVOID, + ) -> BOOL; + pub fn SaferiIsExecutableFileType( + szFullPath: LPCWSTR, + bFromShellExecute: BOOLEAN, + ) -> BOOL; +} +pub const SRP_POLICY_EXE: &'static str = "EXE"; +pub const SRP_POLICY_DLL: &'static str = "DLL"; +pub const SRP_POLICY_MSI: &'static str = "MSI"; +pub const SRP_POLICY_SCRIPT: &'static str = "SCRIPT"; +pub const SRP_POLICY_SHELL: &'static str = "SHELL"; +pub const SRP_POLICY_NOV2: &'static str = "IGNORESRPV2"; +pub const SRP_POLICY_APPX: &'static str = "APPX"; +pub const SRP_POLICY_WLDPMSI: &'static str = "WLDPMSI"; +pub const SRP_POLICY_WLDPSCRIPT: &'static str = "WLDPSCRIPT"; +pub const SRP_POLICY_WLDPCONFIGCI: &'static str = "WLDPCONFIGCI"; +pub const SRP_POLICY_MANAGEDINSTALLER: &'static str = "MANAGEDINSTALLER"; diff --git a/winapi/src/um/winscard.rs b/winapi/src/um/winscard.rs new file mode 100644 index 000000000..5adaec774 --- /dev/null +++ b/winapi/src/um/winscard.rs @@ -0,0 +1,709 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Data Protection API Prototypes and Definitions +// This header file provides the definitions and symbols necessary for an +// Application or Smart Card Service Provider to access the Smartcard Subsystem. +use shared::basetsd::ULONG_PTR; +use shared::guiddef::{LPCGUID, LPGUID}; +use shared::minwindef::{BOOL, BYTE, DWORD, LPBYTE, LPCVOID, LPDWORD, LPVOID, PBYTE}; +use shared::rpcdce::UUID; +use shared::windef::{HICON, HWND}; +use um::winnt::{CHAR, HANDLE, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PVOID, WCHAR}; +use um::winsmcrd::{LPCSCARD_IO_REQUEST, LPSCARD_IO_REQUEST}; +pub type LPCBYTE = *const BYTE; +pub type SCARDCONTEXT = ULONG_PTR; +pub type PSCARDCONTEXT = *mut SCARDCONTEXT; +pub type LPSCARDCONTEXT = *mut SCARDCONTEXT; +pub type SCARDHANDLE = ULONG_PTR; +pub type PSCARDHANDLE = *mut SCARDHANDLE; +pub type LPSCARDHANDLE = *mut SCARDHANDLE; +pub const SCARD_AUTOALLOCATE: DWORD = -1i32 as u32; +pub const SCARD_SCOPE_USER: DWORD = 0; +pub const SCARD_SCOPE_TERMINAL: DWORD = 1; +pub const SCARD_SCOPE_SYSTEM: DWORD = 2; +extern "system" { + pub fn SCardEstablishContext( + dwScope: DWORD, + pvReserved1: LPCVOID, + pvReserved2: LPCVOID, + phContext: LPSCARDCONTEXT, + ) -> LONG; + pub fn SCardReleaseContext( + hContext: SCARDCONTEXT, + ) -> LONG; + pub fn SCardIsValidContext( + hContext: SCARDCONTEXT, + ) -> LONG; +} +pub const SCARD_PROVIDER_PRIMARY: DWORD = 1; +pub const SCARD_PROVIDER_CSP: DWORD = 2; +pub const SCARD_PROVIDER_KSP: DWORD = 3; +extern "system" { + pub fn SCardListReaderGroupsA( + hContext: SCARDCONTEXT, + mszGroups: LPSTR, + pcchGroups: LPDWORD, + ) -> LONG; + pub fn SCardListReaderGroupsW( + hContext: SCARDCONTEXT, + mszGroups: LPWSTR, + pcchGroups: LPDWORD, + ) -> LONG; + pub fn SCardListReadersA( + hContext: SCARDCONTEXT, + mszGroups: LPCSTR, + mszReaders: LPSTR, + pcchReaders: LPDWORD, + ) -> LONG; + pub fn SCardListReadersW( + hContext: SCARDCONTEXT, + mszGroups: LPCWSTR, + mszReaders: LPWSTR, + pcchReaders: LPDWORD, + ) -> LONG; + pub fn SCardListCardsA( + hContext: SCARDCONTEXT, + pbAtr: LPCBYTE, + rgquidInterfaces: LPCGUID, + cguidInterfaceCount: DWORD, + mszCards: *mut CHAR, + pcchCards: LPDWORD, + ) -> LONG; + pub fn SCardListCardsW( + hContext: SCARDCONTEXT, + pbAtr: LPCBYTE, + rgquidInterfaces: LPCGUID, + cguidInterfaceCount: DWORD, + mszCards: *mut WCHAR, + pcchCards: LPDWORD, + ) -> LONG; + pub fn SCardListInterfacesA( + hContext: SCARDCONTEXT, + szCard: LPCSTR, + pguidInterfaces: LPGUID, + pcguidInterfaces: LPDWORD, + ) -> LONG; + pub fn SCardListInterfacesW( + hContext: SCARDCONTEXT, + szCard: LPCWSTR, + pguidInterfaces: LPGUID, + pcguidInterfaces: LPDWORD, + ) -> LONG; + pub fn SCardGetProviderIdA( + hContext: SCARDCONTEXT, + szCard: LPCSTR, + pguidProviderId: LPGUID, + ) -> LONG; + pub fn SCardGetProviderIdW( + hContext: SCARDCONTEXT, + szCard: LPCWSTR, + pguidProviderId: LPGUID, + ) -> LONG; + pub fn SCardGetCardTypeProviderNameA( + hContext: SCARDCONTEXT, + szCardName: LPCSTR, + dwProviderId: DWORD, + szProvider: *mut CHAR, + pcchProvider: LPDWORD, + ) -> LONG; + pub fn SCardGetCardTypeProviderNameW( + hContext: SCARDCONTEXT, + szCardName: LPCWSTR, + dwProviderId: DWORD, + szProvider: *mut WCHAR, + pcchProvider: LPDWORD, + ) -> LONG; + pub fn SCardIntroduceReaderGroupA( + hContext: SCARDCONTEXT, + szGroupName: LPCSTR, + ) -> LONG; + pub fn SCardIntroduceReaderGroupW( + hContext: SCARDCONTEXT, + szGroupName: LPCWSTR, + ) -> LONG; + pub fn SCardForgetReaderGroupA( + hContext: SCARDCONTEXT, + szGroupName: LPCSTR, + ) -> LONG; + pub fn SCardForgetReaderGroupW( + hContext: SCARDCONTEXT, + szGroupName: LPCWSTR, + ) -> LONG; + pub fn SCardIntroduceReaderA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + szDeviceName: LPCSTR, + ) -> LONG; + pub fn SCardIntroduceReaderW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + szDeviceName: LPCWSTR, + ) -> LONG; + pub fn SCardForgetReaderA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + ) -> LONG; + pub fn SCardForgetReaderW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + ) -> LONG; + pub fn SCardAddReaderToGroupA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + szGroupName: LPCSTR, + ) -> LONG; + pub fn SCardAddReaderToGroupW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + szGroupName: LPCWSTR, + ) -> LONG; + pub fn SCardRemoveReaderFromGroupA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + szGroupName: LPCSTR, + ) -> LONG; + pub fn SCardRemoveReaderFromGroupW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + szGroupName: LPCWSTR, + ) -> LONG; + pub fn SCardIntroduceCardTypeA( + hContext: SCARDCONTEXT, + szCardName: LPCSTR, + pguidPrimaryProvider: LPCGUID, + rgguidInterfaces: LPCGUID, + dwInterfaceCount: DWORD, + pbAtr: LPCBYTE, + pbAtrMask: LPCBYTE, + cbAtrLen: DWORD, + ) -> LONG; + pub fn SCardIntroduceCardTypeW( + hContext: SCARDCONTEXT, + szCardName: LPCWSTR, + pguidPrimaryProvider: LPCGUID, + rgguidInterfaces: LPCGUID, + dwInterfaceCount: DWORD, + pbAtr: LPCBYTE, + pbAtrMask: LPCBYTE, + cbAtrLen: DWORD, + ) -> LONG; + pub fn SCardSetCardTypeProviderNameA( + hContext: SCARDCONTEXT, + szCardName: LPCSTR, + dwProviderId: DWORD, + szProvider: LPCSTR, + ) -> LONG; + pub fn SCardSetCardTypeProviderNameW( + hContext: SCARDCONTEXT, + szCardName: LPCWSTR, + dwProviderId: DWORD, + szProvider: LPCWSTR, + ) -> LONG; + pub fn SCardForgetCardTypeA( + hContext: SCARDCONTEXT, + szCardName: LPCSTR, + ) -> LONG; + pub fn SCardForgetCardTypeW( + hContext: SCARDCONTEXT, + szCardName: LPCWSTR, + ) -> LONG; + pub fn SCardFreeMemory( + hContext: SCARDCONTEXT, + pvMem: LPCVOID, + ) -> LONG; + pub fn SCardAccessStartedEvent() -> HANDLE; + pub fn SCardReleaseStartedEvent(); +} +STRUCT!{struct SCARD_READERSTATEA { + szReader: LPCSTR, + pvUserData: LPVOID, + dwCurrentState: DWORD, + dwEventState: DWORD, + cbAtr: DWORD, + rgbAtr: [BYTE; 36], +}} +pub type PSCARD_READERSTATEA = *mut SCARD_READERSTATEA; +pub type LPSCARD_READERSTATEA = *mut SCARD_READERSTATEA; +STRUCT!{struct SCARD_READERSTATEW { + szReader: LPCWSTR, + pvUserData: LPVOID, + dwCurrentState: DWORD, + dwEventState: DWORD, + cbAtr: DWORD, + rgbAtr: [BYTE; 36], +}} +pub type PSCARD_READERSTATEW = *mut SCARD_READERSTATEW; +pub type LPSCARD_READERSTATEW = *mut SCARD_READERSTATEW; +pub type SCARD_READERSTATE_A = SCARD_READERSTATEA; +pub type SCARD_READERSTATE_W = SCARD_READERSTATEW; +pub type PSCARD_READERSTATE_A = PSCARD_READERSTATEA; +pub type PSCARD_READERSTATE_W = PSCARD_READERSTATEW; +pub type LPSCARD_READERSTATE_A = LPSCARD_READERSTATEA; +pub type LPSCARD_READERSTATE_W = LPSCARD_READERSTATEW; +pub const SCARD_STATE_UNAWARE: DWORD = 0x00000000; +pub const SCARD_STATE_IGNORE: DWORD = 0x00000001; +pub const SCARD_STATE_CHANGED: DWORD = 0x00000002; +pub const SCARD_STATE_UNKNOWN: DWORD = 0x00000004; +pub const SCARD_STATE_UNAVAILABLE: DWORD = 0x00000008; +pub const SCARD_STATE_EMPTY: DWORD = 0x00000010; +pub const SCARD_STATE_PRESENT: DWORD = 0x00000020; +pub const SCARD_STATE_ATRMATCH: DWORD = 0x00000040; +pub const SCARD_STATE_EXCLUSIVE: DWORD = 0x00000080; +pub const SCARD_STATE_INUSE: DWORD = 0x00000100; +pub const SCARD_STATE_MUTE: DWORD = 0x00000200; +pub const SCARD_STATE_UNPOWERED: DWORD = 0x00000400; +extern "system" { + pub fn SCardLocateCardsA( + hContext: SCARDCONTEXT, + mszCards: LPCSTR, + rgReaderStates: LPSCARD_READERSTATEA, + cReaders: DWORD, + ) -> LONG; + pub fn SCardLocateCardsW( + hContext: SCARDCONTEXT, + mszCards: LPCWSTR, + rgReaderStates: LPSCARD_READERSTATEW, + cReaders: DWORD, + ) -> LONG; +} +STRUCT!{struct SCARD_ATRMASK { + cbAtr: DWORD, + rgbAtr: [BYTE; 36], + rgbMask: [BYTE; 36], +}} +pub type PSCARD_ATRMASK = *mut SCARD_ATRMASK; +pub type LPSCARD_ATRMASK = *mut SCARD_ATRMASK; +extern "system" { + pub fn SCardLocateCardsByATRA( + hContext: SCARDCONTEXT, + rgAtrMasks: LPSCARD_ATRMASK, + cAtrs: DWORD, + rgReaderStates: LPSCARD_READERSTATEA, + cReaders: DWORD, + ) -> LONG; + pub fn SCardLocateCardsByATRW( + hContext: SCARDCONTEXT, + rgAtrMasks: LPSCARD_ATRMASK, + cAtrs: DWORD, + rgReaderStates: LPSCARD_READERSTATEW, + cReaders: DWORD, + ) -> LONG; + pub fn SCardGetStatusChangeA( + hContext: SCARDCONTEXT, + dwTimeout: DWORD, + rgReaderStates: LPSCARD_READERSTATEA, + cReaders: DWORD, + ) -> LONG; + pub fn SCardGetStatusChangeW( + hContext: SCARDCONTEXT, + dwTimeout: DWORD, + rgReaderStates: LPSCARD_READERSTATEW, + cReaders: DWORD, + ) -> LONG; + pub fn SCardCancel( + hContext: SCARDCONTEXT, + ) -> LONG; +} +pub const SCARD_SHARE_EXCLUSIVE: DWORD = 1; +pub const SCARD_SHARE_SHARED: DWORD = 2; +pub const SCARD_SHARE_DIRECT: DWORD = 3; +pub const SCARD_LEAVE_CARD: DWORD = 0; +pub const SCARD_RESET_CARD: DWORD = 1; +pub const SCARD_UNPOWER_CARD: DWORD = 2; +pub const SCARD_EJECT_CARD: DWORD = 3; +extern "system" { + pub fn SCardConnectA( + hContext: SCARDCONTEXT, + szReader: LPCSTR, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + phCard: LPSCARDHANDLE, + pdwActiveProtocol: LPDWORD, + ) -> LONG; + pub fn SCardConnectW( + hContext: SCARDCONTEXT, + szReader: LPCWSTR, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + phCard: LPSCARDHANDLE, + pdwActiveProtocol: LPDWORD, + ) -> LONG; + pub fn SCardReconnect( + hCard: SCARDHANDLE, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + dwInitialization: DWORD, + pdwActiveProtocol: LPDWORD, + ) -> LONG; + pub fn SCardDisconnect( + hCard: SCARDHANDLE, + dwDisposition: DWORD, + ) -> LONG; + pub fn SCardBeginTransaction( + hCard: SCARDHANDLE, + ) -> LONG; + pub fn SCardEndTransaction( + hCard: SCARDHANDLE, + dwDisposition: DWORD, + ) -> LONG; + pub fn SCardState( + hCard: SCARDHANDLE, + pdwState: LPDWORD, + pdwProtocol: LPDWORD, + pbAtr: LPBYTE, + pcbAtrLen: LPDWORD, + ) -> LONG; + pub fn SCardStatusA( + hCard: SCARDHANDLE, + mszReaderNames: LPSTR, + pcchReaderLen: LPDWORD, + pdwState: LPDWORD, + pdwProtocol: LPDWORD, + pbAtr: LPBYTE, + pcbAtrLen: LPDWORD, + ) -> LONG; + pub fn SCardStatusW( + hCard: SCARDHANDLE, + mszReaderNames: LPWSTR, + pcchReaderLen: LPDWORD, + pdwState: LPDWORD, + pdwProtocol: LPDWORD, + pbAtr: LPBYTE, + pcbAtrLen: LPDWORD, + ) -> LONG; + pub fn SCardTransmit( + hCard: SCARDHANDLE, + pioSendPci: LPCSCARD_IO_REQUEST, + pbSendBuffer: LPCBYTE, + cbSendLength: DWORD, + pioRecvPci: LPSCARD_IO_REQUEST, + pbRecvBuffer: LPBYTE, + pcbRecvLength: LPDWORD, + ) -> LONG; + pub fn SCardGetTransmitCount( + hCard: SCARDHANDLE, + pcTransmitCount: LPDWORD, + ) -> LONG; + pub fn SCardControl( + hCard: SCARDHANDLE, + dwControlCode: DWORD, + lpInBuffer: LPCVOID, + cbInBufferSize: DWORD, + lpOutBuffer: LPVOID, + cbOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + ) -> LONG; + pub fn SCardGetAttrib( + hCard: SCARDHANDLE, + dwAttrId: DWORD, + pbAttr: LPBYTE, + pcbAttrLen: LPDWORD, + ) -> LONG; + pub fn SCardSetAttrib( + hCard: SCARDHANDLE, + dwAttrId: DWORD, + pbAttr: LPCBYTE, + cbAttrLen: DWORD, + ) -> LONG; +} +pub const SC_DLG_MINIMAL_UI: DWORD = 0x01; +pub const SC_DLG_NO_UI: DWORD = 0x02; +pub const SC_DLG_FORCE_UI: DWORD = 0x04; +pub const SCERR_NOCARDNAME: DWORD = 0x4000; +pub const SCERR_NOGUIDS: DWORD = 0x8000; +FN!{stdcall LPOCNCONNPROCA( + SCARDCONTEXT, + LPSTR, + LPSTR, + PVOID, +) -> SCARDHANDLE} +FN!{stdcall LPOCNCONNPROCW( + SCARDCONTEXT, + LPWSTR, + LPWSTR, + PVOID, +) -> SCARDHANDLE} +FN!{stdcall LPOCNCHKPROC( + SCARDCONTEXT, + SCARDHANDLE, + PVOID, +) -> BOOL} +FN!{stdcall LPOCNDSCPROC( + SCARDCONTEXT, + SCARDHANDLE, + PVOID, +) -> ()} +STRUCT!{struct OPENCARD_SEARCH_CRITERIAA { + dwStructSize: DWORD, + lpstrGroupNames: LPSTR, + nMaxGroupNames: DWORD, + rgguidInterfaces: LPCGUID, + cguidInterfaces: DWORD, + lpstrCardNames: LPSTR, + nMaxCardNames: DWORD, + lpfnCheck: LPOCNCHKPROC, + lpfnConnect: LPOCNCONNPROCA, + lpfnDisconnect: LPOCNDSCPROC, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, +}} +pub type POPENCARD_SEARCH_CRITERIAA = *mut OPENCARD_SEARCH_CRITERIAA; +pub type LPOPENCARD_SEARCH_CRITERIAA = *mut OPENCARD_SEARCH_CRITERIAA; +STRUCT!{struct OPENCARD_SEARCH_CRITERIAW { + dwStructSize: DWORD, + lpstrGroupNames: LPWSTR, + nMaxGroupNames: DWORD, + rgguidInterfaces: LPCGUID, + cguidInterfaces: DWORD, + lpstrCardNames: LPWSTR, + nMaxCardNames: DWORD, + lpfnCheck: LPOCNCHKPROC, + lpfnConnect: LPOCNCONNPROCW, + lpfnDisconnect: LPOCNDSCPROC, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, +}} +pub type POPENCARD_SEARCH_CRITERIAW = *mut OPENCARD_SEARCH_CRITERIAW; +pub type LPOPENCARD_SEARCH_CRITERIAW = *mut OPENCARD_SEARCH_CRITERIAW; +STRUCT!{struct OPENCARDNAME_EXA { + dwStructSize: DWORD, + hSCardContext: SCARDCONTEXT, + hwndOwner: HWND, + dwFlags: DWORD, + lpstrTitle: LPCSTR, + lpstrSearchDesc: LPCSTR, + hIcon: HICON, + pOpenCardSearchCriteria: POPENCARD_SEARCH_CRITERIAA, + lpfnConnect: LPOCNCONNPROCA, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + lpstrRdr: LPSTR, + nMaxRdr: DWORD, + lpstrCard: LPSTR, + nMaxCard: DWORD, + dwActiveProtocol: DWORD, + hCardHandle: SCARDHANDLE, +}} +pub type POPENCARDNAME_EXA = *mut OPENCARDNAME_EXA; +pub type LPOPENCARDNAME_EXA = *mut OPENCARDNAME_EXA; +STRUCT!{struct OPENCARDNAME_EXW { + dwStructSize: DWORD, + hSCardContext: SCARDCONTEXT, + hwndOwner: HWND, + dwFlags: DWORD, + lpstrTitle: LPCWSTR, + lpstrSearchDesc: LPCWSTR, + hIcon: HICON, + pOpenCardSearchCriteria: POPENCARD_SEARCH_CRITERIAW, + lpfnConnect: LPOCNCONNPROCW, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + lpstrRdr: LPWSTR, + nMaxRdr: DWORD, + lpstrCard: LPWSTR, + nMaxCard: DWORD, + dwActiveProtocol: DWORD, + hCardHandle: SCARDHANDLE, +}} +pub type POPENCARDNAME_EXW = *mut OPENCARDNAME_EXW; +pub type LPOPENCARDNAME_EXW = *mut OPENCARDNAME_EXW; +pub type OPENCARDNAMEA_EX = OPENCARDNAME_EXA; +pub type OPENCARDNAMEW_EX = OPENCARDNAME_EXW; +pub type POPENCARDNAMEA_EX = POPENCARDNAME_EXA; +pub type POPENCARDNAMEW_EX = POPENCARDNAME_EXW; +pub type LPOPENCARDNAMEA_EX = LPOPENCARDNAME_EXA; +pub type LPOPENCARDNAMEW_EX = LPOPENCARDNAME_EXW; +pub const SCARD_READER_SEL_AUTH_PACKAGE: DWORD = -629i32 as u32; +ENUM!{enum READER_SEL_REQUEST_MATCH_TYPE { + RSR_MATCH_TYPE_READER_AND_CONTAINER = 1, + RSR_MATCH_TYPE_SERIAL_NUMBER, + RSR_MATCH_TYPE_ALL_CARDS, +}} +STRUCT!{struct READER_SEL_REQUEST_ReaderAndContainerParameter { + cbReaderNameOffset: DWORD, + cchReaderNameLength: DWORD, + cbContainerNameOffset: DWORD, + cchContainerNameLength: DWORD, + dwDesiredCardModuleVersion: DWORD, + dwCspFlags: DWORD, +}} +STRUCT!{struct READER_SEL_REQUEST_SerialNumberParameter { + cbSerialNumberOffset: DWORD, + cbSerialNumberLength: DWORD, + dwDesiredCardModuleVersion: DWORD, +}} +UNION!{union READER_SEL_REQUEST_u { + [u32; 6], + ReaderAndContainerParameter ReaderAndContainerParameter_mut: + READER_SEL_REQUEST_ReaderAndContainerParameter, + SerialNumberParameter SerialNumberParameter_mut: READER_SEL_REQUEST_SerialNumberParameter, +}} +STRUCT!{struct READER_SEL_REQUEST { + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + MatchType: READER_SEL_REQUEST_MATCH_TYPE, + u: READER_SEL_REQUEST_u, +}} +pub type PREADER_SEL_REQUEST = *mut READER_SEL_REQUEST; +STRUCT!{struct READER_SEL_RESPONSE { + cbReaderNameOffset: DWORD, + cchReaderNameLength: DWORD, + cbCardNameOffset: DWORD, + cchCardNameLength: DWORD, +}} +pub type PREADER_SEL_RESPONSE = *mut READER_SEL_RESPONSE; +STRUCT!{struct OPENCARDNAMEA { + dwStructSize: DWORD, + hwndOwner: HWND, + hSCardContext: SCARDCONTEXT, + lpstrGroupNames: LPSTR, + nMaxGroupNames: DWORD, + lpstrCardNames: LPSTR, + nMaxCardNames: DWORD, + rgguidInterfaces: LPCGUID, + cguidInterfaces: DWORD, + lpstrRdr: LPSTR, + nMaxRdr: DWORD, + lpstrCard: LPSTR, + nMaxCard: DWORD, + lpstrTitle: LPCSTR, + dwFlags: DWORD, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + dwActiveProtocol: DWORD, + lpfnConnect: LPOCNCONNPROCA, + lpfnCheck: LPOCNCHKPROC, + lpfnDisconnect: LPOCNDSCPROC, + hCardHandle: SCARDHANDLE, +}} +pub type POPENCARDNAMEA = *mut OPENCARDNAMEA; +pub type LPOPENCARDNAMEA = *mut OPENCARDNAMEA; +STRUCT!{struct OPENCARDNAMEW { + dwStructSize: DWORD, + hwndOwner: HWND, + hSCardContext: SCARDCONTEXT, + lpstrGroupNames: LPWSTR, + nMaxGroupNames: DWORD, + lpstrCardNames: LPWSTR, + nMaxCardNames: DWORD, + rgguidInterfaces: LPCGUID, + cguidInterfaces: DWORD, + lpstrRdr: LPWSTR, + nMaxRdr: DWORD, + lpstrCard: LPWSTR, + nMaxCard: DWORD, + lpstrTitle: LPCWSTR, + dwFlags: DWORD, + pvUserData: LPVOID, + dwShareMode: DWORD, + dwPreferredProtocols: DWORD, + dwActiveProtocol: DWORD, + lpfnConnect: LPOCNCONNPROCW, + lpfnCheck: LPOCNCHKPROC, + lpfnDisconnect: LPOCNDSCPROC, + hCardHandle: SCARDHANDLE, +}} +pub type POPENCARDNAMEW = *mut OPENCARDNAMEW; +pub type LPOPENCARDNAMEW = *mut OPENCARDNAMEW; +pub type OPENCARDNAME_A = OPENCARDNAMEA; +pub type OPENCARDNAME_W = OPENCARDNAMEW; +pub type POPENCARDNAME_A = POPENCARDNAMEA; +pub type POPENCARDNAME_W = POPENCARDNAMEW; +pub type LPOPENCARDNAME_A = LPOPENCARDNAMEA; +pub type LPOPENCARDNAME_W = LPOPENCARDNAMEW; +extern "system" { + pub fn SCardReadCacheA( + hContext: SCARDCONTEXT, + CardIdentifier: *mut UUID, + FreshnessCounter: DWORD, + LookupName: LPSTR, + Data: PBYTE, + DataLen: *mut DWORD, + ) -> LONG; + pub fn SCardReadCacheW( + hContext: SCARDCONTEXT, + CardIdentifier: *mut UUID, + FreshnessCounter: DWORD, + LookupName: LPWSTR, + Data: PBYTE, + DataLen: *mut DWORD, + ) -> LONG; + pub fn SCardWriteCacheA( + hContext: SCARDCONTEXT, + CardIdentifier: *mut UUID, + FreshnessCounter: DWORD, + LookupName: LPSTR, + Data: PBYTE, + DataLen: DWORD, + ) -> LONG; + pub fn SCardWriteCacheW( + hContext: SCARDCONTEXT, + CardIdentifier: *mut UUID, + FreshnessCounter: DWORD, + LookupName: LPWSTR, + Data: PBYTE, + DataLen: DWORD, + ) -> LONG; + pub fn SCardGetReaderIconA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + pbIcon: LPBYTE, + pcbIcon: LPDWORD, + ) -> LONG; + pub fn SCardGetReaderIconW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + pbIcon: LPBYTE, + pcbIcon: LPDWORD, + ) -> LONG; + pub fn SCardGetDeviceTypeIdA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + pdwDeviceTypeId: LPDWORD, + ) -> LONG; + pub fn SCardGetDeviceTypeIdW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + pdwDeviceTypeId: LPDWORD, + ) -> LONG; + pub fn SCardGetReaderDeviceInstanceIdA( + hContext: SCARDCONTEXT, + szReaderName: LPCSTR, + szDeviceInstanceId: LPSTR, + pcchDeviceInstanceId: LPDWORD, + ) -> LONG; + pub fn SCardGetReaderDeviceInstanceIdW( + hContext: SCARDCONTEXT, + szReaderName: LPCWSTR, + szDeviceInstanceId: LPWSTR, + pcchDeviceInstanceId: LPDWORD, + ) -> LONG; + pub fn SCardListReadersWithDeviceInstanceIdA( + hContext: SCARDCONTEXT, + szDeviceInstanceId: LPCSTR, + mszReaders: LPSTR, + pcchReaders: LPDWORD, + ) -> LONG; + pub fn SCardListReadersWithDeviceInstanceIdW( + hContext: SCARDCONTEXT, + szDeviceInstanceId: LPCWSTR, + mszReaders: LPWSTR, + pcchReaders: LPDWORD, + ) -> LONG; +} +pub const SCARD_AUDIT_CHV_FAILURE: DWORD = 0x0; +pub const SCARD_AUDIT_CHV_SUCCESS: DWORD = 0x1; +extern "system" { + pub fn SCardAudit( + hContext: SCARDCONTEXT, + dwEvent: DWORD, + ) -> LONG; +} diff --git a/winapi/src/um/winsmcrd.rs b/winapi/src/um/winsmcrd.rs new file mode 100644 index 000000000..227bf7b40 --- /dev/null +++ b/winapi/src/um/winsmcrd.rs @@ -0,0 +1,166 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Smart Card class/port IOCTL codes. +use shared::minwindef::{BYTE, DWORD, ULONG, WORD}; +use um::winioctl::{FILE_ANY_ACCESS, FILE_DEVICE_SMARTCARD, METHOD_BUFFERED}; +pub type UWORD = WORD; +DEFINE_GUID!{GUID_DEVINTERFACE_SMARTCARD_READER, + 0x50DD5230, 0xBA8A, 0x11D1, 0xBF, 0x5D, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30} +pub const SCARD_ATR_LENGTHL: DWORD = 33; +pub const SCARD_PROTOCOL_UNDEFINED: DWORD = 0x00000000; +pub const SCARD_PROTOCOL_T0: DWORD = 0x00000001; +pub const SCARD_PROTOCOL_T1: DWORD = 0x00000002; +pub const SCARD_PROTOCOL_RAW: DWORD = 0x00010000; +pub const SCARD_PROTOCOL_Tx: DWORD = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; +pub const SCARD_PROTOCOL_DEFAULT: DWORD = 0x80000000; +pub const SCARD_PROTOCOL_OPTIMAL: DWORD = 0x00000000; +pub const SCARD_POWER_DOWN: DWORD = 0; +pub const SCARD_COLD_RESET: DWORD = 1; +pub const SCARD_WARM_RESET: DWORD = 2; +pub const IOCTL_SMARTCARD_POWER: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 1, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_GET_ATTRIBUTE: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 2, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_SET_ATTRIBUTE: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 3, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_CONFISCATE: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 4, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_TRANSMIT: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 5, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_EJECT: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 6, METHOD_BUFFERED, + FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_SWALLOW: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 7, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_IS_PRESENT: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 10, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_IS_ABSENT: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 11, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_SET_PROTOCOL: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 12, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_GET_STATE: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 14, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_GET_LAST_ERROR: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 15, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const IOCTL_SMARTCARD_GET_PERF_CNTR: DWORD = CTL_CODE!(FILE_DEVICE_SMARTCARD, 16, + METHOD_BUFFERED, FILE_ANY_ACCESS); +pub const MAXIMUM_ATTR_STRING_LENGTH: DWORD = 32; +pub const MAXIMUM_SMARTCARD_READERS: DWORD = 10; +pub const SCARD_CLASS_VENDOR_INFO: ULONG = 1; +pub const SCARD_CLASS_COMMUNICATIONS: ULONG = 2; +pub const SCARD_CLASS_PROTOCOL: ULONG = 3; +pub const SCARD_CLASS_POWER_MGMT: ULONG = 4; +pub const SCARD_CLASS_SECURITY: ULONG = 5; +pub const SCARD_CLASS_MECHANICAL: ULONG = 6; +pub const SCARD_CLASS_VENDOR_DEFINED: ULONG = 7; +pub const SCARD_CLASS_IFD_PROTOCOL: ULONG = 8; +pub const SCARD_CLASS_ICC_STATE: ULONG = 9; +pub const SCARD_CLASS_PERF: ULONG = 0x7ffe; +pub const SCARD_CLASS_SYSTEM: ULONG = 0x7fff; +pub const SCARD_ATTR_VENDOR_NAME: ULONG = SCARD_CLASS_VENDOR_INFO << 16 | 0x0100; +pub const SCARD_ATTR_VENDOR_IFD_TYPE: ULONG = SCARD_CLASS_VENDOR_INFO << 16 | 0x0101; +pub const SCARD_ATTR_VENDOR_IFD_VERSION: ULONG = SCARD_CLASS_VENDOR_INFO << 16 | 0x0102; +pub const SCARD_ATTR_VENDOR_IFD_SERIAL_NO: ULONG = SCARD_CLASS_VENDOR_INFO << 16 | 0x0103; +pub const SCARD_ATTR_CHANNEL_ID: ULONG = SCARD_CLASS_COMMUNICATIONS << 16 | 0x0110; +pub const SCARD_ATTR_PROTOCOL_TYPES: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0120; +pub const SCARD_ATTR_DEFAULT_CLK: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0121; +pub const SCARD_ATTR_MAX_CLK: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0122; +pub const SCARD_ATTR_DEFAULT_DATA_RATE: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0123; +pub const SCARD_ATTR_MAX_DATA_RATE: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0124; +pub const SCARD_ATTR_MAX_IFSD: ULONG = SCARD_CLASS_PROTOCOL << 16 | 0x0125; +pub const SCARD_ATTR_POWER_MGMT_SUPPORT: ULONG = SCARD_CLASS_POWER_MGMT << 16 | 0x0131; +pub const SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE: ULONG = SCARD_CLASS_SECURITY << 16 | 0x0140; +pub const SCARD_ATTR_USER_AUTH_INPUT_DEVICE: ULONG = SCARD_CLASS_SECURITY << 16 | 0x0142; +pub const SCARD_ATTR_CHARACTERISTICS: ULONG = SCARD_CLASS_MECHANICAL << 16 | 0x0150; +pub const SCARD_ATTR_CURRENT_PROTOCOL_TYPE: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0201; +pub const SCARD_ATTR_CURRENT_CLK: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0202; +pub const SCARD_ATTR_CURRENT_F: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0203; +pub const SCARD_ATTR_CURRENT_D: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0204; +pub const SCARD_ATTR_CURRENT_N: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0205; +pub const SCARD_ATTR_CURRENT_W: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0206; +pub const SCARD_ATTR_CURRENT_IFSC: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0207; +pub const SCARD_ATTR_CURRENT_IFSD: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0208; +pub const SCARD_ATTR_CURRENT_BWT: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x0209; +pub const SCARD_ATTR_CURRENT_CWT: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x020a; +pub const SCARD_ATTR_CURRENT_EBC_ENCODING: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x020b; +pub const SCARD_ATTR_EXTENDED_BWT: ULONG = SCARD_CLASS_IFD_PROTOCOL << 16 | 0x020c; +pub const SCARD_ATTR_ICC_PRESENCE: ULONG = SCARD_CLASS_ICC_STATE << 16 | 0x0300; +pub const SCARD_ATTR_ICC_INTERFACE_STATUS: ULONG = SCARD_CLASS_ICC_STATE << 16 | 0x0301; +pub const SCARD_ATTR_CURRENT_IO_STATE: ULONG = SCARD_CLASS_ICC_STATE << 16 | 0x0302; +pub const SCARD_ATTR_ATR_STRING: ULONG = SCARD_CLASS_ICC_STATE << 16 | 0x0303; +pub const SCARD_ATTR_ICC_TYPE_PER_ATR: ULONG = SCARD_CLASS_ICC_STATE << 16 | 0x0304; +pub const SCARD_ATTR_ESC_RESET: ULONG = SCARD_CLASS_VENDOR_DEFINED << 16 | 0xA000; +pub const SCARD_ATTR_ESC_CANCEL: ULONG = SCARD_CLASS_VENDOR_DEFINED << 16 | 0xA003; +pub const SCARD_ATTR_ESC_AUTHREQUEST: ULONG = SCARD_CLASS_VENDOR_DEFINED << 16 | 0xA005; +pub const SCARD_ATTR_MAXINPUT: ULONG = SCARD_CLASS_VENDOR_DEFINED << 16 | 0xA007; +pub const SCARD_ATTR_DEVICE_UNIT: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0001; +pub const SCARD_ATTR_DEVICE_IN_USE: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0002; +pub const SCARD_ATTR_DEVICE_FRIENDLY_NAME_A: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0003; +pub const SCARD_ATTR_DEVICE_SYSTEM_NAME_A: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0004; +pub const SCARD_ATTR_DEVICE_FRIENDLY_NAME_W: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0005; +pub const SCARD_ATTR_DEVICE_SYSTEM_NAME_W: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0006; +pub const SCARD_ATTR_SUPRESS_T1_IFS_REQUEST: ULONG = SCARD_CLASS_SYSTEM << 16 | 0x0007; +pub const SCARD_PERF_NUM_TRANSMISSIONS: ULONG = SCARD_CLASS_PERF << 16 | 0x0001; +pub const SCARD_PERF_BYTES_TRANSMITTED: ULONG = SCARD_CLASS_PERF << 16 | 0x0002; +pub const SCARD_PERF_TRANSMISSION_TIME: ULONG = SCARD_CLASS_PERF << 16 | 0x0003; +pub const SCARD_T0_HEADER_LENGTH: DWORD = 7; +pub const SCARD_T0_CMD_LENGTH: DWORD = 5; +pub const SCARD_T1_PROLOGUE_LENGTH: DWORD = 3; +pub const SCARD_T1_EPILOGUE_LENGTH: DWORD = 2; +pub const SCARD_T1_MAX_IFS: DWORD = 254; +pub const SCARD_UNKNOWN: ULONG = 0; +pub const SCARD_ABSENT: ULONG = 1; +pub const SCARD_PRESENT: ULONG = 2; +pub const SCARD_SWALLOWED: ULONG = 3; +pub const SCARD_POWERED: ULONG = 4; +pub const SCARD_NEGOTIABLE: ULONG = 5; +pub const SCARD_SPECIFIC: ULONG = 6; +STRUCT!{struct SCARD_IO_REQUEST { + dwProtocol: DWORD, + cbPciLength: DWORD, +}} +pub type PSCARD_IO_REQUEST = *mut SCARD_IO_REQUEST; +pub type LPSCARD_IO_REQUEST = *mut SCARD_IO_REQUEST; +pub type LPCSCARD_IO_REQUEST = *const SCARD_IO_REQUEST; +STRUCT!{struct SCARD_T0_COMMAND { + bCla: BYTE, + bIns: BYTE, + bP1: BYTE, + bP2: BYTE, + bP3: BYTE, +}} +pub type LPSCARD_T0_COMMAND = *mut SCARD_T0_COMMAND; +UNION!{union SCARD_T0_REQUEST_u { + [u8; 5], + CmdBytes CmdBytes_mut: SCARD_T0_COMMAND, + rgbHeader rgbHeader_mut: [BYTE; 5], +}} +STRUCT!{struct SCARD_T0_REQUEST { + ioRequest: SCARD_IO_REQUEST, + bSw1: BYTE, + bSw2: BYTE, + u: SCARD_T0_REQUEST_u, +}} +pub type PSCARD_T0_REQUEST = *mut SCARD_T0_REQUEST; +pub type LPSCARD_T0_REQUEST = *mut SCARD_T0_REQUEST; +STRUCT!{struct SCARD_T1_REQUEST { + ioRequest: SCARD_IO_REQUEST, +}} +pub type PSCARD_T1_REQUEST = *mut SCARD_T1_REQUEST; +pub type LPSCARD_T1_REQUEST = *mut SCARD_T1_REQUEST; +pub const SCARD_READER_SWALLOWS: ULONG = 0x00000001; +pub const SCARD_READER_EJECTS: ULONG = 0x00000002; +pub const SCARD_READER_CONFISCATES: ULONG = 0x00000004; +pub const SCARD_READER_TYPE_SERIAL: ULONG = 0x01; +pub const SCARD_READER_TYPE_PARALELL: ULONG = 0x02; +pub const SCARD_READER_TYPE_KEYBOARD: ULONG = 0x04; +pub const SCARD_READER_TYPE_SCSI: ULONG = 0x08; +pub const SCARD_READER_TYPE_IDE: ULONG = 0x10; +pub const SCARD_READER_TYPE_USB: ULONG = 0x20; +pub const SCARD_READER_TYPE_PCMCIA: ULONG = 0x40; +pub const SCARD_READER_TYPE_TPM: ULONG = 0x80; +pub const SCARD_READER_TYPE_NFC: ULONG = 0x100; +pub const SCARD_READER_TYPE_UICC: ULONG = 0x200; +pub const SCARD_READER_TYPE_VENDOR: ULONG = 0xF0; diff --git a/winapi/src/um/winsock2.rs b/winapi/src/um/winsock2.rs new file mode 100644 index 000000000..a8327e3bb --- /dev/null +++ b/winapi/src/um/winsock2.rs @@ -0,0 +1,1450 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Definitions to be used with the WinSock 2 DLL and WinSock 2 applications. +use ctypes::{ + __uint32, __uint64, c_char, c_double, c_float, c_int, c_long, c_short, c_uchar, c_uint, + c_ulong, c_ushort, +}; +use shared::basetsd::{DWORD_PTR, UINT_PTR, ULONG_PTR}; +use shared::guiddef::{GUID, LPGUID}; +use shared::inaddr::in_addr; +use shared::minwindef::{ + BOOL, DWORD, FARPROC, HIWORD, INT, LOWORD, LPDWORD, LPHANDLE, LPINT, LPVOID, MAKELONG, UINT, + ULONG, WORD, WPARAM, +}; +use shared::qos::FLOWSPEC; +use shared::windef::HWND; +use shared::winerror::{ + ERROR_INVALID_HANDLE, ERROR_INVALID_PARAMETER, ERROR_IO_INCOMPLETE, ERROR_IO_PENDING, + ERROR_NOT_ENOUGH_MEMORY, ERROR_OPERATION_ABORTED, WAIT_TIMEOUT, +}; +use shared::ws2def::{ + AF_APPLETALK, AF_ATM, AF_BAN, AF_BTH, AF_CCITT, AF_CHAOS, AF_DATAKIT, AF_DECnet, AF_DLI, + AF_ECMA, AF_FIREFOX, AF_HYLINK, AF_IMPLINK, AF_INET, AF_INET6, AF_IPX, AF_ISO, AF_LAT, + AF_MAX, AF_NS, AF_OSI, AF_PUP, AF_SNA, AF_UNIX, AF_UNKNOWN1, AF_UNSPEC, AF_VOICEVIEW, + INADDR_ANY, LPCSADDR_INFO, LPSOCKADDR, LPWSABUF, LPWSAMSG, PSOCKET_ADDRESS_LIST, SOCKADDR, + SOCKADDR_IN, WSABUF, +}; +use shared::wtypesbase::{BLOB, LPBLOB}; +use um::minwinbase::OVERLAPPED; +use um::winbase::{INFINITE, WAIT_FAILED, WAIT_IO_COMPLETION, WAIT_OBJECT_0}; +use um::winnt::{ + CHAR, HANDLE, LONG, LPCSTR, LPSTR, LPWSTR, MAXIMUM_WAIT_OBJECTS, PWSTR, SHORT, WCHAR, +}; +pub const WINSOCK_VERSION: WORD = 2 | (2 << 8); +pub type u_char = c_uchar; +pub type u_short = c_ushort; +pub type u_int = c_uint; +pub type u_long = c_ulong; +pub type u_int64 = __uint64; +pub type SOCKET = UINT_PTR; +pub const FD_SETSIZE: usize = 64; +STRUCT!{struct fd_set { + fd_count: u_int, + fd_array: [SOCKET; FD_SETSIZE], +}} +extern "system" { + pub fn __WSAFDIsSet( + fd: SOCKET, + _: *mut fd_set, + ) -> c_int; +} +STRUCT!{struct timeval { + tv_sec: c_long, + tv_usec: c_long, +}} +pub const IOCPARM_MASK: c_long = 0x7f; +pub const IOC_VOID: c_long = 0x20000000; +pub const IOC_OUT: c_long = 0x40000000; +pub const IOC_IN: c_long = 0x80000000; +pub const IOC_INOUT: c_long = IOC_IN | IOC_OUT; +pub const FIONREAD: c_long = IOC_OUT | ((4 & IOCPARM_MASK) << 16) | (0x66 << 8) | 127; +pub const FIONBIO: c_long = IOC_IN | ((4 & IOCPARM_MASK) << 16) | (0x66 << 8) | 126; +pub const FIOASYNC: c_long = IOC_IN | ((4 & IOCPARM_MASK) << 16) | (0x66 << 8) | 125; +pub const SIOCSHIWAT: c_long = IOC_IN | ((4 & IOCPARM_MASK) << 16) | (0x73 << 8) | 0; +pub const SIOCGHIWAT: c_long = IOC_OUT | ((4 & IOCPARM_MASK) << 16) | (0x73 << 8) | 1; +pub const SIOCSLOWAT: c_long = IOC_IN | ((4 & IOCPARM_MASK) << 16) | (0x73 << 8) | 2; +pub const SIOCGLOWAT: c_long = IOC_OUT | ((4 & IOCPARM_MASK) << 16) | (0x73 << 8) | 3; +pub const SIOCATMARK: c_long = IOC_OUT | ((4 & IOCPARM_MASK) << 16) | (0x73 << 8) | 7; +STRUCT!{struct hostent { + h_name: *mut c_char, + h_aliases: *mut *mut c_char, + h_addrtype: c_short, + h_length: c_short, + h_addr_list: *mut *mut c_char, +}} +STRUCT!{struct netent { + n_name: *mut c_char, + n_aliases: *mut *mut c_char, + n_addrtype: c_short, + n_net: u_long, +}} +#[cfg(target_arch = "x86")] +STRUCT!{struct servent { + s_name: *mut c_char, + s_aliases: *mut *mut c_char, + s_port: c_short, + s_proto: *mut c_char, +}} +#[cfg(target_pointer_width = "64")] +STRUCT!{struct servent { + s_name: *mut c_char, + s_aliases: *mut *mut c_char, + s_proto: *mut c_char, + s_port: c_short, +}} +STRUCT!{struct protoent { + p_name: *mut c_char, + p_aliases: *mut *mut c_char, + p_proto: c_short, +}} +pub const IPPORT_ECHO: c_short = 7; +pub const IPPORT_DISCARD: c_short = 9; +pub const IPPORT_SYSTAT: c_short = 11; +pub const IPPORT_DAYTIME: c_short = 13; +pub const IPPORT_NETSTAT: c_short = 15; +pub const IPPORT_FTP: c_short = 21; +pub const IPPORT_TELNET: c_short = 23; +pub const IPPORT_SMTP: c_short = 25; +pub const IPPORT_TIMESERVER: c_short = 37; +pub const IPPORT_NAMESERVER: c_short = 42; +pub const IPPORT_WHOIS: c_short = 43; +pub const IPPORT_MTP: c_short = 57; +pub const IPPORT_TFTP: c_short = 69; +pub const IPPORT_RJE: c_short = 77; +pub const IPPORT_FINGER: c_short = 79; +pub const IPPORT_TTYLINK: c_short = 87; +pub const IPPORT_SUPDUP: c_short = 95; +pub const IPPORT_EXECSERVER: c_short = 512; +pub const IPPORT_LOGINSERVER: c_short = 513; +pub const IPPORT_CMDSERVER: c_short = 514; +pub const IPPORT_EFSSERVER: c_short = 520; +pub const IPPORT_BIFFUDP: c_short = 512; +pub const IPPORT_WHOSERVER: c_short = 513; +pub const IPPORT_ROUTESERVER: c_short = 520; +pub const IPPORT_RESERVED: c_short = 1024; +pub const IMPLINK_IP: c_short = 155; +pub const IMPLINK_LOWEXPER: c_short = 156; +pub const IMPLINK_HIGHEXPER: c_short = 158; +pub const ADDR_ANY: ULONG = INADDR_ANY; +pub const WSADESCRIPTION_LEN: usize = 256; +pub const WSASYS_STATUS_LEN: usize = 128; +#[cfg(target_arch = "x86")] +STRUCT!{struct WSADATA { + wVersion: WORD, + wHighVersion: WORD, + szDescription: [c_char; WSADESCRIPTION_LEN + 1], + szSystemStatus: [c_char; WSASYS_STATUS_LEN + 1], + iMaxSockets: c_ushort, + iMaxUdpDg: c_ushort, + lpVendorInfo: *mut c_char, +}} +#[cfg(target_pointer_width = "64")] +STRUCT!{struct WSADATA { + wVersion: WORD, + wHighVersion: WORD, + iMaxSockets: c_ushort, + iMaxUdpDg: c_ushort, + lpVendorInfo: *mut c_char, + szDescription: [c_char; WSADESCRIPTION_LEN + 1], + szSystemStatus: [c_char; WSASYS_STATUS_LEN + 1], +}} +pub type LPWSADATA = *mut WSADATA; +pub const INVALID_SOCKET: SOCKET = !0; +pub const SOCKET_ERROR: c_int = -1; +pub const FROM_PROTOCOL_INFO: c_int = -1; +pub const SOCK_STREAM: c_int = 1; +pub const SOCK_DGRAM: c_int = 2; +pub const SOCK_RAW: c_int = 3; +pub const SOCK_RDM: c_int = 4; +pub const SOCK_SEQPACKET: c_int = 5; +pub const SO_DEBUG: c_int = 0x0001; +pub const SO_ACCEPTCONN: c_int = 0x0002; +pub const SO_REUSEADDR: c_int = 0x0004; +pub const SO_KEEPALIVE: c_int = 0x0008; +pub const SO_DONTROUTE: c_int = 0x0010; +pub const SO_BROADCAST: c_int = 0x0020; +pub const SO_USELOOPBACK: c_int = 0x0040; +pub const SO_LINGER: c_int = 0x0080; +pub const SO_OOBINLINE: c_int = 0x0100; +pub const SO_DONTLINGER: c_int = !SO_LINGER; +pub const SO_EXCLUSIVEADDRUSE: c_int = !SO_REUSEADDR; +pub const SO_SNDBUF: c_int = 0x1001; +pub const SO_RCVBUF: c_int = 0x1002; +pub const SO_SNDLOWAT: c_int = 0x1003; +pub const SO_RCVLOWAT: c_int = 0x1004; +pub const SO_SNDTIMEO: c_int = 0x1005; +pub const SO_RCVTIMEO: c_int = 0x1006; +pub const SO_ERROR: c_int = 0x1007; +pub const SO_TYPE: c_int = 0x1008; +pub const SO_GROUP_ID: c_int = 0x2001; +pub const SO_GROUP_PRIORITY: c_int = 0x2002; +pub const SO_MAX_MSG_SIZE: c_int = 0x2003; +pub const SO_PROTOCOL_INFOA: c_int = 0x2004; +pub const SO_PROTOCOL_INFOW: c_int = 0x2005; +pub const PVD_CONFIG: c_int = 0x3001; +pub const SO_CONDITIONAL_ACCEPT: c_int = 0x3002; +STRUCT!{struct sockproto { + sp_family: u_short, + sp_protocol: u_short, +}} +pub const PF_UNSPEC: c_int = AF_UNSPEC; +pub const PF_UNIX: c_int = AF_UNIX; +pub const PF_INET: c_int = AF_INET; +pub const PF_IMPLINK: c_int = AF_IMPLINK; +pub const PF_PUP: c_int = AF_PUP; +pub const PF_CHAOS: c_int = AF_CHAOS; +pub const PF_NS: c_int = AF_NS; +pub const PF_IPX: c_int = AF_IPX; +pub const PF_ISO: c_int = AF_ISO; +pub const PF_OSI: c_int = AF_OSI; +pub const PF_ECMA: c_int = AF_ECMA; +pub const PF_DATAKIT: c_int = AF_DATAKIT; +pub const PF_CCITT: c_int = AF_CCITT; +pub const PF_SNA: c_int = AF_SNA; +pub const PF_DECnet: c_int = AF_DECnet; +pub const PF_DLI: c_int = AF_DLI; +pub const PF_LAT: c_int = AF_LAT; +pub const PF_HYLINK: c_int = AF_HYLINK; +pub const PF_APPLETALK: c_int = AF_APPLETALK; +pub const PF_VOICEVIEW: c_int = AF_VOICEVIEW; +pub const PF_FIREFOX: c_int = AF_FIREFOX; +pub const PF_UNKNOWN1: c_int = AF_UNKNOWN1; +pub const PF_BAN: c_int = AF_BAN; +pub const PF_ATM: c_int = AF_ATM; +pub const PF_INET6: c_int = AF_INET6; +pub const PF_BTH: c_int = AF_BTH; +pub const PF_MAX: c_int = AF_MAX; +STRUCT!{struct linger { + l_onoff: u_short, + l_linger: u_short, +}} +pub const SOL_SOCKET: c_int = 0xffff; +pub const SOMAXCONN: c_int = 0x7fffffff; +#[inline] +pub fn SOMAXCONN_HINT(b: c_int) -> c_int { + -b +} +pub const MSG_OOB: c_int = 0x1; +pub const MSG_PEEK: c_int = 0x2; +pub const MSG_DONTROUTE: c_int = 0x4; +pub const MSG_WAITALL: c_int = 0x8; +pub const MSG_PUSH_IMMEDIATE: c_int = 0x20; +pub const MSG_PARTIAL: c_int = 0x8000; +pub const MSG_INTERRUPT: c_int = 0x10; +pub const MSG_MAXIOVLEN: c_int = 16; +pub const MAXGETHOSTSTRUCT: usize = 1024; +pub const FD_READ_BIT: c_long = 0; +pub const FD_READ: c_long = 1 << FD_READ_BIT; +pub const FD_WRITE_BIT: c_long = 1; +pub const FD_WRITE: c_long = 1 << FD_WRITE_BIT; +pub const FD_OOB_BIT: c_long = 2; +pub const FD_OOB: c_long = 1 << FD_OOB_BIT; +pub const FD_ACCEPT_BIT: c_long = 3; +pub const FD_ACCEPT: c_long = 1 << FD_ACCEPT_BIT; +pub const FD_CONNECT_BIT: c_long = 4; +pub const FD_CONNECT: c_long = 1 << FD_CONNECT_BIT; +pub const FD_CLOSE_BIT: c_long = 5; +pub const FD_CLOSE: c_long = 1 << FD_CLOSE_BIT; +pub const FD_QOS_BIT: c_long = 6; +pub const FD_QOS: c_long = 1 << FD_QOS_BIT; +pub const FD_GROUP_QOS_BIT: c_long = 7; +pub const FD_GROUP_QOS: c_long = 1 << FD_GROUP_QOS_BIT; +pub const FD_ROUTING_INTERFACE_CHANGE_BIT: c_long = 8; +pub const FD_ROUTING_INTERFACE_CHANGE: c_long = 1 << FD_ROUTING_INTERFACE_CHANGE_BIT; +pub const FD_ADDRESS_LIST_CHANGE_BIT: c_long = 9; +pub const FD_ADDRESS_LIST_CHANGE: c_long = 1 << FD_ADDRESS_LIST_CHANGE_BIT; +pub const FD_MAX_EVENTS: usize = 10; +pub const FD_ALL_EVENTS: c_long = (1 << FD_MAX_EVENTS) - 1; +pub const WSABASEERR: c_int = 10000; +pub const WSAEINTR: c_int = WSABASEERR+4; +pub const WSAEBADF: c_int = WSABASEERR+9; +pub const WSAEACCES: c_int = WSABASEERR+13; +pub const WSAEFAULT: c_int = WSABASEERR+14; +pub const WSAEINVAL: c_int = WSABASEERR+22; +pub const WSAEMFILE: c_int = WSABASEERR+24; +pub const WSAEWOULDBLOCK: c_int = WSABASEERR+35; +pub const WSAEINPROGRESS: c_int = WSABASEERR+36; +pub const WSAEALREADY: c_int = WSABASEERR+37; +pub const WSAENOTSOCK: c_int = WSABASEERR+38; +pub const WSAEDESTADDRREQ: c_int = WSABASEERR+39; +pub const WSAEMSGSIZE: c_int = WSABASEERR+40; +pub const WSAEPROTOTYPE: c_int = WSABASEERR+41; +pub const WSAENOPROTOOPT: c_int = WSABASEERR+42; +pub const WSAEPROTONOSUPPORT: c_int = WSABASEERR+43; +pub const WSAESOCKTNOSUPPORT: c_int = WSABASEERR+44; +pub const WSAEOPNOTSUPP: c_int = WSABASEERR+45; +pub const WSAEPFNOSUPPORT: c_int = WSABASEERR+46; +pub const WSAEAFNOSUPPORT: c_int = WSABASEERR+47; +pub const WSAEADDRINUSE: c_int = WSABASEERR+48; +pub const WSAEADDRNOTAVAIL: c_int = WSABASEERR+49; +pub const WSAENETDOWN: c_int = WSABASEERR+50; +pub const WSAENETUNREACH: c_int = WSABASEERR+51; +pub const WSAENETRESET: c_int = WSABASEERR+52; +pub const WSAECONNABORTED: c_int = WSABASEERR+53; +pub const WSAECONNRESET: c_int = WSABASEERR+54; +pub const WSAENOBUFS: c_int = WSABASEERR+55; +pub const WSAEISCONN: c_int = WSABASEERR+56; +pub const WSAENOTCONN: c_int = WSABASEERR+57; +pub const WSAESHUTDOWN: c_int = WSABASEERR+58; +pub const WSAETOOMANYREFS: c_int = WSABASEERR+59; +pub const WSAETIMEDOUT: c_int = WSABASEERR+60; +pub const WSAECONNREFUSED: c_int = WSABASEERR+61; +pub const WSAELOOP: c_int = WSABASEERR+62; +pub const WSAENAMETOOLONG: c_int = WSABASEERR+63; +pub const WSAEHOSTDOWN: c_int = WSABASEERR+64; +pub const WSAEHOSTUNREACH: c_int = WSABASEERR+65; +pub const WSAENOTEMPTY: c_int = WSABASEERR+66; +pub const WSAEPROCLIM: c_int = WSABASEERR+67; +pub const WSAEUSERS: c_int = WSABASEERR+68; +pub const WSAEDQUOT: c_int = WSABASEERR+69; +pub const WSAESTALE: c_int = WSABASEERR+70; +pub const WSAEREMOTE: c_int = WSABASEERR+71; +pub const WSASYSNOTREADY: c_int = WSABASEERR+91; +pub const WSAVERNOTSUPPORTED: c_int = WSABASEERR+92; +pub const WSANOTINITIALISED: c_int = WSABASEERR+93; +pub const WSAEDISCON: c_int = WSABASEERR+101; +pub const WSAENOMORE: c_int = WSABASEERR+102; +pub const WSAECANCELLED: c_int = WSABASEERR+103; +pub const WSAEINVALIDPROCTABLE: c_int = WSABASEERR+104; +pub const WSAEINVALIDPROVIDER: c_int = WSABASEERR+105; +pub const WSAEPROVIDERFAILEDINIT: c_int = WSABASEERR+106; +pub const WSASYSCALLFAILURE: c_int = WSABASEERR+107; +pub const WSASERVICE_NOT_FOUND: c_int = WSABASEERR+108; +pub const WSATYPE_NOT_FOUND: c_int = WSABASEERR+109; +pub const WSA_E_NO_MORE: c_int = WSABASEERR+110; +pub const WSA_E_CANCELLED: c_int = WSABASEERR+111; +pub const WSAEREFUSED: c_int = WSABASEERR+112; +pub const WSAHOST_NOT_FOUND: c_int = WSABASEERR+1001; +pub const WSATRY_AGAIN: c_int = WSABASEERR+1002; +pub const WSANO_RECOVERY: c_int = WSABASEERR+1003; +pub const WSANO_DATA: c_int = WSABASEERR+1004; +pub const WSA_QOS_RECEIVERS: c_int = WSABASEERR + 1005; +pub const WSA_QOS_SENDERS: c_int = WSABASEERR + 1006; +pub const WSA_QOS_NO_SENDERS: c_int = WSABASEERR + 1007; +pub const WSA_QOS_NO_RECEIVERS: c_int = WSABASEERR + 1008; +pub const WSA_QOS_REQUEST_CONFIRMED: c_int = WSABASEERR + 1009; +pub const WSA_QOS_ADMISSION_FAILURE: c_int = WSABASEERR + 1010; +pub const WSA_QOS_POLICY_FAILURE: c_int = WSABASEERR + 1011; +pub const WSA_QOS_BAD_STYLE: c_int = WSABASEERR + 1012; +pub const WSA_QOS_BAD_OBJECT: c_int = WSABASEERR + 1013; +pub const WSA_QOS_TRAFFIC_CTRL_ERROR: c_int = WSABASEERR + 1014; +pub const WSA_QOS_GENERIC_ERROR: c_int = WSABASEERR + 1015; +pub const WSA_QOS_ESERVICETYPE: c_int = WSABASEERR + 1016; +pub const WSA_QOS_EFLOWSPEC: c_int = WSABASEERR + 1017; +pub const WSA_QOS_EPROVSPECBUF: c_int = WSABASEERR + 1018; +pub const WSA_QOS_EFILTERSTYLE: c_int = WSABASEERR + 1019; +pub const WSA_QOS_EFILTERTYPE: c_int = WSABASEERR + 1020; +pub const WSA_QOS_EFILTERCOUNT: c_int = WSABASEERR + 1021; +pub const WSA_QOS_EOBJLENGTH: c_int = WSABASEERR + 1022; +pub const WSA_QOS_EFLOWCOUNT: c_int = WSABASEERR + 1023; +pub const WSA_QOS_EUNKOWNPSOBJ: c_int = WSABASEERR + 1024; +pub const WSA_QOS_EPOLICYOBJ: c_int = WSABASEERR + 1025; +pub const WSA_QOS_EFLOWDESC: c_int = WSABASEERR + 1026; +pub const WSA_QOS_EPSFLOWSPEC: c_int = WSABASEERR + 1027; +pub const WSA_QOS_EPSFILTERSPEC: c_int = WSABASEERR + 1028; +pub const WSA_QOS_ESDMODEOBJ: c_int = WSABASEERR + 1029; +pub const WSA_QOS_ESHAPERATEOBJ: c_int = WSABASEERR + 1030; +pub const WSA_QOS_RESERVED_PETYPE: c_int = WSABASEERR + 1031; +#[inline] +pub unsafe fn h_errno() -> c_int { + WSAGetLastError() +} +pub const HOST_NOT_FOUND: c_int = WSAHOST_NOT_FOUND; +pub const TRY_AGAIN: c_int = WSATRY_AGAIN; +pub const NO_RECOVERY: c_int = WSANO_RECOVERY; +pub const NO_DATA: c_int = WSANO_DATA; +pub const WSANO_ADDRESS: c_int = WSANO_DATA; +pub const NO_ADDRESS: c_int = WSANO_ADDRESS; +pub type WSAEVENT = HANDLE; +pub type LPWSAEVENT = LPHANDLE; +pub type WSAOVERLAPPED = OVERLAPPED; +pub type LPWSAOVERLAPPED = *mut OVERLAPPED; +pub const WSA_IO_PENDING: c_int = ERROR_IO_PENDING as i32; +pub const WSA_IO_INCOMPLETE: c_int = ERROR_IO_INCOMPLETE as i32; +pub const WSA_INVALID_HANDLE: c_int = ERROR_INVALID_HANDLE as i32; +pub const WSA_INVALID_PARAMETER: c_int = ERROR_INVALID_PARAMETER as i32; +pub const WSA_NOT_ENOUGH_MEMORY: c_int = ERROR_NOT_ENOUGH_MEMORY as i32; +pub const WSA_OPERATION_ABORTED: c_int = ERROR_OPERATION_ABORTED as i32; +pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; +pub const WSA_MAXIMUM_WAIT_EVENTS: DWORD = MAXIMUM_WAIT_OBJECTS; +pub const WSA_WAIT_FAILED: DWORD = WAIT_FAILED; +pub const WSA_WAIT_EVENT_0: DWORD = WAIT_OBJECT_0; +pub const WSA_WAIT_IO_COMPLETION: DWORD = WAIT_IO_COMPLETION; +pub const WSA_WAIT_TIMEOUT: DWORD = WAIT_TIMEOUT; +pub const WSA_INFINITE: DWORD = INFINITE; +STRUCT!{struct QOS { + SendingFlowspec: FLOWSPEC, + FLOWSPEC: FLOWSPEC, + ProviderSpecific: WSABUF, +}} +pub type LPQOS = *mut QOS; +pub const CF_ACCEPT: c_int = 0x0000; +pub const CF_REJECT: c_int = 0x0001; +pub const CF_DEFER: c_int = 0x0002; +pub const SD_RECEIVE: c_int = 0x00; +pub const SD_SEND: c_int = 0x01; +pub const SD_BOTH: c_int = 0x02; +pub type GROUP = c_uint; +pub const SG_UNCONSTRAINED_GROUP: GROUP = 0x01; +pub const SG_CONSTRAINED_GROUP: GROUP = 0x02; +STRUCT!{struct WSANETWORKEVENTS { + lNetworkEvents: c_long, + iErrorCode: [c_int; FD_MAX_EVENTS], +}} +pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; +pub const MAX_PROTOCOL_CHAIN: usize = 7; +pub const BASE_PROTOCOL: c_int = 1; +pub const LAYERED_PROTOCOL: c_int = 0; +STRUCT!{struct WSAPROTOCOLCHAIN { + ChainLen: c_int, + ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN], +}} +pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN; +pub const WSAPROTOCOL_LEN: usize = 255; +STRUCT!{struct WSAPROTOCOL_INFOA { + dwServiceFlags1: DWORD, + dwServiceFlags2: DWORD, + dwServiceFlags3: DWORD, + dwServiceFlags4: DWORD, + dwServiceFlags5: DWORD, + ProviderId: GUID, + dwCatalogEntryId: DWORD, + ProtocolChain: WSAPROTOCOLCHAIN, + iVersion: c_int, + iAddressFamily: c_int, + iMaxSockAddr: c_int, + iMinSockAddr: c_int, + iSocketType: c_int, + iProtocol: c_int, + iProtocolMaxOffset: c_int, + iNetworkByteOrder: c_int, + iSecurityScheme: c_int, + dwMessageSize: DWORD, + dwProviderReserved: DWORD, + szProtocol: [CHAR; WSAPROTOCOL_LEN + 1], +}} +pub type LPWSAPROTOCOL_INFOA = *mut WSAPROTOCOL_INFOA; +STRUCT!{struct WSAPROTOCOL_INFOW { + dwServiceFlags1: DWORD, + dwServiceFlags2: DWORD, + dwServiceFlags3: DWORD, + dwServiceFlags4: DWORD, + dwServiceFlags5: DWORD, + ProviderId: GUID, + dwCatalogEntryId: DWORD, + ProtocolChain: WSAPROTOCOLCHAIN, + iVersion: c_int, + iAddressFamily: c_int, + iMaxSockAddr: c_int, + iMinSockAddr: c_int, + iSocketType: c_int, + iProtocol: c_int, + iProtocolMaxOffset: c_int, + iNetworkByteOrder: c_int, + iSecurityScheme: c_int, + dwMessageSize: DWORD, + dwProviderReserved: DWORD, + szProtocol: [WCHAR; WSAPROTOCOL_LEN + 1], +}} +pub type LPWSAPROTOCOL_INFOW = *mut WSAPROTOCOL_INFOW; +pub const PFL_MULTIPLE_PROTO_ENTRIES: DWORD = 0x00000001; +pub const PFL_RECOMMENDED_PROTO_ENTRY: DWORD = 0x00000002; +pub const PFL_HIDDEN: DWORD = 0x00000004; +pub const PFL_MATCHES_PROTOCOL_ZERO: DWORD = 0x00000008; +pub const PFL_NETWORKDIRECT_PROVIDER: DWORD = 0x00000010; +pub const XP1_CONNECTIONLESS: DWORD = 0x00000001; +pub const XP1_GUARANTEED_DELIVERY: DWORD = 0x00000002; +pub const XP1_GUARANTEED_ORDER: DWORD = 0x00000004; +pub const XP1_MESSAGE_ORIENTED: DWORD = 0x00000008; +pub const XP1_PSEUDO_STREAM: DWORD = 0x00000010; +pub const XP1_GRACEFUL_CLOSE: DWORD = 0x00000020; +pub const XP1_EXPEDITED_DATA: DWORD = 0x00000040; +pub const XP1_CONNECT_DATA: DWORD = 0x00000080; +pub const XP1_DISCONNECT_DATA: DWORD = 0x00000100; +pub const XP1_SUPPORT_BROADCAST: DWORD = 0x00000200; +pub const XP1_SUPPORT_MULTIPOINT: DWORD = 0x00000400; +pub const XP1_MULTIPOINT_CONTROL_PLANE: DWORD = 0x00000800; +pub const XP1_MULTIPOINT_DATA_PLANE: DWORD = 0x00001000; +pub const XP1_QOS_SUPPORTED: DWORD = 0x00002000; +pub const XP1_INTERRUPT: DWORD = 0x00004000; +pub const XP1_UNI_SEND: DWORD = 0x00008000; +pub const XP1_UNI_RECV: DWORD = 0x00010000; +pub const XP1_IFS_HANDLES: DWORD = 0x00020000; +pub const XP1_PARTIAL_MESSAGE: DWORD = 0x00040000; +pub const XP1_SAN_SUPPORT_SDP: DWORD = 0x00080000; +pub const BIGENDIAN: DWORD = 0x0000; +pub const LITTLEENDIAN: DWORD = 0x0001; +pub const SECURITY_PROTOCOL_NONE: DWORD = 0x0000; +pub const JL_SENDER_ONLY: DWORD = 0x01; +pub const JL_RECEIVER_ONLY: DWORD = 0x02; +pub const JL_BOTH: DWORD = 0x04; +pub const WSA_FLAG_OVERLAPPED: DWORD = 0x01; +pub const WSA_FLAG_MULTIPOINT_C_ROOT: DWORD = 0x02; +pub const WSA_FLAG_MULTIPOINT_C_LEAF: DWORD = 0x04; +pub const WSA_FLAG_MULTIPOINT_D_ROOT: DWORD = 0x08; +pub const WSA_FLAG_MULTIPOINT_D_LEAF: DWORD = 0x10; +pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY: DWORD = 0x40; +pub const WSA_FLAG_NO_HANDLE_INHERIT: DWORD = 0x80; +pub const WSA_FLAG_REGISTERED_IO: DWORD = 0x100; +FN!{stdcall LPCONDITIONPROC( + lpCallerId: LPWSABUF, + lpCallerData: LPWSABUF, + lpSQOS: LPQOS, + lpGQOS: LPQOS, + lpCalleeId: LPWSABUF, + lpCalleeData: LPWSABUF, + g: *mut GROUP, + dwCallbackData: DWORD, +) -> c_int} +FN!{stdcall LPWSAOVERLAPPED_COMPLETION_ROUTINE( + dwError: DWORD, + cbTransferred: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + dwFlags: DWORD, +) -> ()} +ENUM!{enum WSACOMPLETIONTYPE { + NSP_NOTIFY_IMMEDIATELY = 0, + NSP_NOTIFY_HWND, + NSP_NOTIFY_EVENT, + NSP_NOTIFY_PORT, + NSP_NOTIFY_APC, +}} +pub type PWSACOMPLETIONTYPE = *mut WSACOMPLETIONTYPE; +pub type LPWSACOMPLETIONTYPE = *mut WSACOMPLETIONTYPE; +STRUCT!{struct WSACOMPLETION_WindowMessage { + hWnd: HWND, + uMsg: UINT, + context: WPARAM, +}} +STRUCT!{struct WSACOMPLETION_Event { + lpOverlapped: LPWSAOVERLAPPED, +}} +STRUCT!{struct WSACOMPLETION_Apc { + lpOverlapped: LPWSAOVERLAPPED, + lpfnCompletionProc: LPWSAOVERLAPPED_COMPLETION_ROUTINE, +}} +STRUCT!{struct WSACOMPLETION_Port { + lpOverlapped: LPWSAOVERLAPPED, + hPort: HANDLE, + Key: ULONG_PTR, +}} +UNION!{union WSACOMPLETION_Parameter { + [usize; 3], + WindowMessage WindowMessage_mut: WSACOMPLETION_WindowMessage, + Event Event_mut: WSACOMPLETION_Event, + Apc Apc_mut: WSACOMPLETION_Apc, + Port Port_mut: WSACOMPLETION_Port, +}} +STRUCT!{struct WSACOMPLETION { + Type: WSACOMPLETIONTYPE, + Parameters: WSACOMPLETION_Parameter, +}} +pub type PWSACOMPLETION = *mut WSACOMPLETION; +pub type LPWSACOMPLETION = *mut WSACOMPLETION; +pub const TH_NETDEV: DWORD = 0x00000001; +pub const TH_TAPI: DWORD = 0x00000002; +pub const SERVICE_MULTIPLE: DWORD = 0x00000001; +pub const NS_ALL: DWORD = 0; +pub const NS_SAP: DWORD = 1; +pub const NS_NDS: DWORD = 2; +pub const NS_PEER_BROWSE: DWORD = 3; +pub const NS_SLP: DWORD = 5; +pub const NS_DHCP: DWORD = 6; +pub const NS_TCPIP_LOCAL: DWORD = 10; +pub const NS_TCPIP_HOSTS: DWORD = 11; +pub const NS_DNS: DWORD = 12; +pub const NS_NETBT: DWORD = 13; +pub const NS_WINS: DWORD = 14; +pub const NS_NLA: DWORD = 15; +pub const NS_BTH: DWORD = 16; +pub const NS_LOCALNAME: DWORD = 19; +pub const NS_NBP: DWORD = 20; +pub const NS_MS: DWORD = 30; +pub const NS_STDA: DWORD = 31; +pub const NS_NTDS: DWORD = 32; +pub const NS_EMAIL: DWORD = 37; +pub const NS_PNRPNAME: DWORD = 38; +pub const NS_PNRPCLOUD: DWORD = 39; +pub const NS_X500: DWORD = 40; +pub const NS_NIS: DWORD = 41; +pub const NS_NISPLUS: DWORD = 42; +pub const NS_WRQ: DWORD = 50; +pub const NS_NETDES: DWORD = 60; +pub const RES_UNUSED_1: DWORD = 0x00000001; +pub const RES_FLUSH_CACHE: DWORD = 0x00000002; +pub const RES_SERVICE: DWORD = 0x00000004; +pub const SERVICE_TYPE_VALUE_IPXPORT: &'static str = "IpxSocket"; +pub const SERVICE_TYPE_VALUE_SAPID: &'static str = "SapId"; +pub const SERVICE_TYPE_VALUE_TCPPORT: &'static str = "TcpPort"; +pub const SERVICE_TYPE_VALUE_UDPPORT: &'static str = "UdpPort"; +pub const SERVICE_TYPE_VALUE_OBJECTID: &'static str = "ObjectId"; +STRUCT!{struct AFPROTOCOLS { + iAddressFamily: INT, + iProtocol: INT, +}} +pub type PAFPROTOCOLS = *mut AFPROTOCOLS; +pub type LPAFPROTOCOLS = *mut AFPROTOCOLS; +ENUM!{enum WSAECOMPARATOR { + COMP_EQUAL = 0, + COMP_NOTLESS, +}} +pub type PWSAECOMPARATOR = *mut WSAECOMPARATOR; +pub type LPWSAECOMPARATOR = *mut WSAECOMPARATOR; +STRUCT!{struct WSAVERSION { + dwVersion: DWORD, + ecHow: WSAECOMPARATOR, +}} +pub type PWSAVERSION = *mut WSAVERSION; +pub type LPWSAVERSION = *mut WSAVERSION; +STRUCT!{struct WSAQUERYSETA { + dwSize: DWORD, + lpszServiceInstanceName: LPSTR, + lpServiceClassId: LPGUID, + lpVersion: LPWSAVERSION, + lpszComment: LPSTR, + dwNameSpace: DWORD, + lpNSProviderId: LPGUID, + lpszContext: LPSTR, + dwNumberOfProtocols: DWORD, + lpafpProtocols: LPAFPROTOCOLS, + lpszQueryString: LPSTR, + dwNumberOfCsAddrs: DWORD, + lpcsaBuffer: LPCSADDR_INFO, + dwOutputFlags: DWORD, + lpBlob: LPBLOB, +}} +pub type PWSAQUERYSETA = *mut WSAQUERYSETA; +pub type LPWSAQUERYSETA = *mut WSAQUERYSETA; +STRUCT!{struct WSAQUERYSETW { + dwSize: DWORD, + lpszServiceInstanceName: LPWSTR, + lpServiceClassId: LPGUID, + lpVersion: LPWSAVERSION, + lpszComment: LPWSTR, + dwNameSpace: DWORD, + lpNSProviderId: LPGUID, + lpszContext: LPWSTR, + dwNumberOfProtocols: DWORD, + lpafpProtocols: LPAFPROTOCOLS, + lpszQueryString: LPWSTR, + dwNumberOfCsAddrs: DWORD, + lpcsaBuffer: LPCSADDR_INFO, + dwOutputFlags: DWORD, + lpBlob: LPBLOB, +}} +pub type PWSAQUERYSETW = *mut WSAQUERYSETW; +pub type LPWSAQUERYSETW = *mut WSAQUERYSETW; +STRUCT!{struct WSAQUERYSET2A { + dwSize: DWORD, + lpszServiceInstanceName: LPSTR, + lpVersion: LPWSAVERSION, + lpszComment: LPSTR, + dwNameSpace: DWORD, + lpNSProviderId: LPGUID, + lpszContext: LPSTR, + dwNumberOfProtocols: DWORD, + lpafpProtocols: LPAFPROTOCOLS, + lpszQueryString: LPSTR, + dwNumberOfCsAddrs: DWORD, + lpcsaBuffer: LPCSADDR_INFO, + dwOutputFlags: DWORD, + lpBlob: LPBLOB, +}} +pub type PWSAQUERYSET2A = *mut WSAQUERYSET2A; +pub type LPWSAQUERYSET2A = *mut WSAQUERYSET2A; +STRUCT!{struct WSAQUERYSET2W { + dwSize: DWORD, + lpszServiceInstanceName: LPWSTR, + lpVersion: LPWSAVERSION, + lpszComment: LPWSTR, + dwNameSpace: DWORD, + lpNSProviderId: LPGUID, + lpszContext: LPWSTR, + dwNumberOfProtocols: DWORD, + lpafpProtocols: LPAFPROTOCOLS, + lpszQueryString: LPWSTR, + dwNumberOfCsAddrs: DWORD, + lpcsaBuffer: LPCSADDR_INFO, + dwOutputFlags: DWORD, + lpBlob: LPBLOB, +}} +pub type PWSAQUERYSET2W = *mut WSAQUERYSET2W; +pub type LPWSAQUERYSET2W = *mut WSAQUERYSET2W; +pub const LUP_DEEP: DWORD = 0x0001; +pub const LUP_CONTAINERS: DWORD = 0x0002; +pub const LUP_NOCONTAINERS: DWORD = 0x0004; +pub const LUP_NEAREST: DWORD = 0x0008; +pub const LUP_RETURN_NAME: DWORD = 0x0010; +pub const LUP_RETURN_TYPE: DWORD = 0x0020; +pub const LUP_RETURN_VERSION: DWORD = 0x0040; +pub const LUP_RETURN_COMMENT: DWORD = 0x0080; +pub const LUP_RETURN_ADDR: DWORD = 0x0100; +pub const LUP_RETURN_BLOB: DWORD = 0x0200; +pub const LUP_RETURN_ALIASES: DWORD = 0x0400; +pub const LUP_RETURN_QUERY_STRING: DWORD = 0x0800; +pub const LUP_RETURN_ALL: DWORD = 0x0FF0; +pub const LUP_RES_SERVICE: DWORD = 0x8000; +pub const LUP_FLUSHCACHE: DWORD = 0x1000; +pub const LUP_FLUSHPREVIOUS: DWORD = 0x2000; +pub const LUP_NON_AUTHORITATIVE: DWORD = 0x4000; +pub const LUP_SECURE: DWORD = 0x8000; +pub const LUP_RETURN_PREFERRED_NAMES: DWORD = 0x10000; +pub const LUP_DNS_ONLY: DWORD = 0x20000; +pub const LUP_ADDRCONFIG: DWORD = 0x00100000; +pub const LUP_DUAL_ADDR: DWORD = 0x00200000; +pub const LUP_FILESERVER: DWORD = 0x00400000; +pub const LUP_DISABLE_IDN_ENCODING: DWORD = 0x00800000; +pub const LUP_API_ANSI: DWORD = 0x01000000; +pub const LUP_RESOLUTION_HANDLE: DWORD = 0x80000000; +pub const RESULT_IS_ALIAS: DWORD = 0x0001; +pub const RESULT_IS_ADDED: DWORD = 0x0010; +pub const RESULT_IS_CHANGED: DWORD = 0x0020; +pub const RESULT_IS_DELETED: DWORD = 0x0040; +ENUM!{enum WSAESETSERVICEOP { + RNRSERVICE_REGISTER = 0, + RNRSERVICE_DEREGISTER, + RNRSERVICE_DELETE, +}} +pub type PWSAESETSERVICEOP = *mut WSAESETSERVICEOP; +pub type LPWSAESETSERVICEOP = *mut WSAESETSERVICEOP; +STRUCT!{struct WSANSCLASSINFOA { + lpszName: LPSTR, + dwNameSpace: DWORD, + dwValueType: DWORD, + dwValueSize: DWORD, + lpValue: LPVOID, +}} +pub type PWSANSCLASSINFOA = *mut WSANSCLASSINFOA; +pub type LPWSANSCLASSINFOA = *mut WSANSCLASSINFOA; +STRUCT!{struct WSANSCLASSINFOW { + lpszName: LPWSTR, + dwNameSpace: DWORD, + dwValueType: DWORD, + dwValueSize: DWORD, + lpValue: LPVOID, +}} +pub type PWSANSCLASSINFOW = *mut WSANSCLASSINFOW; +pub type LPWSANSCLASSINFOW = *mut WSANSCLASSINFOW; +STRUCT!{struct WSASERVICECLASSINFOA { + lpServiceClassId: LPGUID, + lpszServiceClassName: LPSTR, + dwCount: DWORD, + lpClassInfos: LPWSANSCLASSINFOA, +}} +pub type PWSASERVICECLASSINFOA = *mut WSASERVICECLASSINFOA; +pub type LPWSASERVICECLASSINFOA = *mut WSASERVICECLASSINFOA; +STRUCT!{struct WSASERVICECLASSINFOW { + lpServiceClassId: LPGUID, + lpszServiceClassName: LPWSTR, + dwCount: DWORD, + lpClassInfos: LPWSANSCLASSINFOW, +}} +pub type PWSASERVICECLASSINFOW = *mut WSASERVICECLASSINFOW; +pub type LPWSASERVICECLASSINFOW = *mut WSASERVICECLASSINFOW; +STRUCT!{struct WSANAMESPACE_INFOA { + NSProviderId: GUID, + dwNameSpace: DWORD, + fActive: BOOL, + dwVersion: DWORD, + lpszIdentifier: LPSTR, +}} +pub type PWSANAMESPACE_INFOA = *mut WSANAMESPACE_INFOA; +pub type LPWSANAMESPACE_INFOA = *mut WSANAMESPACE_INFOA; +STRUCT!{struct WSANAMESPACE_INFOW { + NSProviderId: GUID, + dwNameSpace: DWORD, + fActive: BOOL, + dwVersion: DWORD, + lpszIdentifier: LPWSTR, +}} +pub type PWSANAMESPACE_INFOW = *mut WSANAMESPACE_INFOW; +pub type LPWSANAMESPACE_INFOW = *mut WSANAMESPACE_INFOW; +STRUCT!{struct WSANAMESPACE_INFOEXA { + NSProviderId: GUID, + dwNameSpace: DWORD, + fActive: BOOL, + dwVersion: DWORD, + lpszIdentifier: LPSTR, + ProviderSpecific: BLOB, +}} +pub type PWSANAMESPACE_INFOEXA = *mut WSANAMESPACE_INFOEXA; +pub type LPWSANAMESPACE_INFOEXA = *mut WSANAMESPACE_INFOEXA; +STRUCT!{struct WSANAMESPACE_INFOEXW { + NSProviderId: GUID, + dwNameSpace: DWORD, + fActive: BOOL, + dwVersion: DWORD, + lpszIdentifier: LPWSTR, + ProviderSpecific: BLOB, +}} +pub type PWSANAMESPACE_INFOEXW = *mut WSANAMESPACE_INFOEXW; +pub type LPWSANAMESPACE_INFOEXW = *mut WSANAMESPACE_INFOEXW; +pub const POLLRDNORM: SHORT = 0x0100; +pub const POLLRDBAND: SHORT = 0x0200; +pub const POLLIN: SHORT = POLLRDNORM | POLLRDBAND; +pub const POLLPRI: SHORT = 0x0400; +pub const POLLWRNORM: SHORT = 0x0010; +pub const POLLOUT: SHORT = POLLWRNORM; +pub const POLLWRBAND: SHORT = 0x0020; +pub const POLLERR: SHORT = 0x0001; +pub const POLLHUP: SHORT = 0x0002; +pub const POLLNVAL: SHORT = 0x0004; +STRUCT!{struct WSAPOLLFD { + fd: SOCKET, + events: SHORT, + revents: SHORT, +}} +pub type PWSAPOLLFD = *mut WSAPOLLFD; +pub type LPWSAPOLLFD = *mut WSAPOLLFD; +extern "system" { + pub fn accept( + s: SOCKET, + addr: *mut SOCKADDR, + addrlen: *mut c_int, + ) -> SOCKET; + pub fn bind(s: SOCKET, + name: *const SOCKADDR, + namelen: c_int, + ) -> c_int; + pub fn closesocket( + s: SOCKET, + ) -> c_int; + pub fn connect( + s: SOCKET, + name: *const SOCKADDR, + namelen: c_int, + ) -> c_int; + pub fn ioctlsocket( + s: SOCKET, + cmd: c_long, + argp: *mut u_long, + ) -> c_int; + pub fn getpeername( + s: SOCKET, + name: *mut SOCKADDR, + namelen: *mut c_int, + ) -> c_int; + pub fn getsockname( + s: SOCKET, + name: *mut SOCKADDR, + namelen: *mut c_int, + ) -> c_int; + pub fn getsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: *mut c_int, + ) -> c_int; + pub fn htonl( + hostlong: u_long, + ) -> u_long; + pub fn htons( + hostshort: u_short, + ) -> u_short; + pub fn inet_addr( + cp: *const c_char, + ) -> c_ulong; + pub fn inet_ntoa( + _in: in_addr, + ) -> *mut c_char; +} +#[inline] +pub fn _WS2_32_WINSOCK_SWAP_LONG(l: __uint32) -> __uint32 { + ((l >> 24) & 0x000000FF) | ((l >> 8) & 0x0000FF00) | ((l << 8) & 0x00FF0000) + | ((l << 24) & 0xFF000000) +} +#[inline] +pub fn _WS2_32_WINSOCK_SWAP_LONGLONG(l: __uint64) -> __uint64 { + ((l >> 56) & 0x00000000000000FF) | ((l >> 40) & 0x000000000000FF00) + | ((l >> 24) & 0x0000000000FF0000) | ((l >> 8) & 0x00000000FF000000) + | ((l << 8) & 0x000000FF00000000) | ((l << 24) & 0x0000FF0000000000) + | ((l << 40) & 0x00FF000000000000) | ((l << 56) & 0xFF00000000000000) +} +#[inline] +pub fn htonll(Value: __uint64) -> __uint64 { + _WS2_32_WINSOCK_SWAP_LONGLONG(Value) +} +#[inline] +pub fn ntohll(Value: __uint64) -> __uint64 { + _WS2_32_WINSOCK_SWAP_LONGLONG(Value) +} +#[inline] +pub fn htonf(Value: c_float) -> __uint32 { + let Tempval: __uint32 = unsafe { ::core::mem::transmute(Value) }; + _WS2_32_WINSOCK_SWAP_LONG(Tempval) +} +#[inline] +pub fn ntohf(Value: __uint32) -> c_float { + let Tempval = _WS2_32_WINSOCK_SWAP_LONG(Value); + unsafe { ::core::mem::transmute(Tempval) } +} +#[inline] +pub fn htond(Value: c_double) -> __uint64 { + let Tempval: __uint64 = unsafe { ::core::mem::transmute(Value) }; + _WS2_32_WINSOCK_SWAP_LONGLONG(Tempval) +} +#[inline] +pub fn ntohd(Value: __uint64) -> c_double { + let Tempval = _WS2_32_WINSOCK_SWAP_LONGLONG(Value); + unsafe { ::core::mem::transmute(Tempval) } +} +extern "system" { + pub fn listen( + s: SOCKET, + backlog: c_int, + ) -> c_int; + pub fn ntohl( + netlong: u_long, + ) -> u_long; + pub fn ntohs( + netshort: u_short, + ) -> u_short; + pub fn recv( + s: SOCKET, + buf: *mut c_char, + len: c_int, + flags: c_int, + ) -> c_int; + pub fn recvfrom( + s: SOCKET, + buf: *mut c_char, + len: c_int, + flags: c_int, + from: *mut SOCKADDR, + fromlen: *mut c_int, + ) -> c_int; + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *const timeval, + ) -> c_int; + pub fn send( + s: SOCKET, + buf: *const c_char, + len: c_int, + flags: c_int, + ) -> c_int; + pub fn sendto( + s: SOCKET, + buf: *const c_char, + len: c_int, + flags: c_int, + to: *const SOCKADDR, + tolen: c_int, + ) -> c_int; + pub fn setsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_char, + optlen: c_int, + ) -> c_int; + pub fn shutdown( + s: SOCKET, + how: c_int, + ) -> c_int; + pub fn socket( + af: c_int, + _type: c_int, + protocol: c_int, + ) -> SOCKET; + pub fn gethostbyaddr( + addr: *const c_char, + len: c_int, + _type: c_int, + ) -> *mut hostent; + pub fn gethostbyname( + name: *const c_char, + ) -> *mut hostent; + pub fn gethostname( + name: *mut c_char, + namelen: c_int, + ) -> c_int; + pub fn GetHostNameW( + name: PWSTR, + namelen: c_int, + ) -> c_int; + pub fn getservbyport( + port: c_int, + proto: *const c_char, + ) -> *mut servent; + pub fn getservbyname( + name: *const c_char, + proto: *const c_char, + ) -> *mut servent; + pub fn getprotobynumber( + number: c_int, + ) -> *mut protoent; + pub fn getprotobyname( + name: *const c_char, + ) -> *mut protoent; + pub fn WSAStartup( + wVersionRequested: WORD, + lpWSAData: LPWSADATA, + ) -> c_int; + pub fn WSACleanup() -> c_int; + pub fn WSASetLastError( + iError: c_int, + ); + pub fn WSAGetLastError() -> c_int; + pub fn WSAIsBlocking() -> BOOL; + pub fn WSAUnhookBlockingHook() -> c_int; + pub fn WSASetBlockingHook( + lpBlockFunc: FARPROC, + ) -> FARPROC; + pub fn WSACancelBlockingCall() -> c_int; + pub fn WSAAsyncGetServByName( + hWnd: HWND, + wMsg: u_int, + name: *const c_char, + proto: *const c_char, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSAAsyncGetServByPort( + hWnd: HWND, + wMsg: u_int, + port: c_int, + proto: *const c_char, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSAAsyncGetProtoByName( + hWnd: HWND, + wMsg: u_int, + name: *const c_char, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSAAsyncGetProtoByNumber( + hWnd: HWND, + wMsg: u_int, + number: c_int, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSAAsyncGetHostByName( + hWnd: HWND, + wMsg: u_int, + name: *const c_char, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSAAsyncGetHostByAddr( + hWnd: HWND, + wMsg: u_int, + addr: *const c_char, + len: c_int, + _type: c_int, + buf: *mut c_char, + buflen: c_int, + ) -> HANDLE; + pub fn WSACancelAsyncRequest( + hAsyncTaskHandle: HANDLE, + ) -> c_int; + pub fn WSAAsyncSelect( + s: SOCKET, + hWnd: HWND, + wMsg: u_int, + lEvent: c_long, + ) -> c_int; + pub fn WSAAccept( + s: SOCKET, + addr: *mut SOCKADDR, + addrlen: LPINT, + lpfnCondition: LPCONDITIONPROC, + dwCallbackData: DWORD_PTR, + ) -> SOCKET; + pub fn WSACloseEvent( + hEvent: WSAEVENT, + ) -> BOOL; + pub fn WSAConnect( + s: SOCKET, + name: *const SOCKADDR, + namelen: c_int, + lpCallerData: LPWSABUF, + lpCalleeData: LPWSABUF, + lpSQOS: LPQOS, + lpGQOS: LPQOS, + ) -> c_int; + pub fn WSAConnectByNameW( + s: SOCKET, + nodename: LPWSTR, + servicename: LPWSTR, + LocalAddressLength: LPDWORD, + LocalAddress: LPSOCKADDR, + RemoteAddressLength: LPDWORD, + RemoteAddress: LPSOCKADDR, + timeout: *const timeval, + Reserved: LPWSAOVERLAPPED, + ) -> BOOL; + pub fn WSAConnectByNameA( + s: SOCKET, + nodename: LPCSTR, + servicename: LPCSTR, + LocalAddressLength: LPDWORD, + LocalAddress: LPSOCKADDR, + RemoteAddressLength: LPDWORD, + RemoteAddress: LPSOCKADDR, + timeout: *const timeval, + Reserved: LPWSAOVERLAPPED, + ) -> BOOL; + pub fn WSAConnectByList( + s: SOCKET, + SocketAddress: PSOCKET_ADDRESS_LIST, + LocalAddressLength: LPDWORD, + LocalAddress: LPSOCKADDR, + RemoteAddressLength: LPDWORD, + RemoteAddress: LPSOCKADDR, + timeout: *const timeval, + Reserved: LPWSAOVERLAPPED, + ) -> BOOL; + pub fn WSACreateEvent() -> WSAEVENT; + pub fn WSADuplicateSocketA( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOA, + ) -> c_int; + pub fn WSADuplicateSocketW( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + ) -> c_int; + pub fn WSAEnumNetworkEvents( + s: SOCKET, + hEventObject: WSAEVENT, + lpNetworkEvents: LPWSANETWORKEVENTS, + ) -> c_int; + pub fn WSAEnumProtocolsA( + lpiProtocols: LPINT, + lpProtocolBuffer: LPWSAPROTOCOL_INFOA, + lpdwBufferLength: LPDWORD, + ) -> c_int; + pub fn WSAEnumProtocolsW( + lpiProtocols: LPINT, + lpProtocolBuffer: LPWSAPROTOCOL_INFOW, + lpdwBufferLength: LPDWORD, + ) -> c_int; + pub fn WSAEventSelect( + s: SOCKET, + hEventObject: WSAEVENT, + lNetworkEvents: c_long, + ) -> c_int; + pub fn WSAGetOverlappedResult( + s: SOCKET, + lpOverlapped: LPWSAOVERLAPPED, + lpcbTransfer: LPDWORD, + fWait: BOOL, + lpdwFlags: LPDWORD, + ) -> BOOL; + pub fn WSAGetQOSByName( + s: SOCKET, + lpQOSName: LPWSABUF, + lpQOS: LPQOS, + ) -> BOOL; + pub fn WSAHtonl( + s: SOCKET, + hostlong: u_long, + lpnetlong: *mut u_long, + ) -> c_int; + pub fn WSAHtons(s: SOCKET, + hostshort: u_short, + lpnetshort: *mut u_short, + ) -> c_int; + pub fn WSAIoctl( + s: SOCKET, + dwIoControlCode: DWORD, + lpvInBuffer: LPVOID, + cbInBuffer: DWORD, + lpvOutBuffer: LPVOID, + cbOutBuffer: DWORD, + lpcbBytesReturned: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSAJoinLeaf( + s: SOCKET, + name: *const SOCKADDR, + namelen: c_int, + lpCallerData: LPWSABUF, + lpCalleeData: LPWSABUF, + lpSQOS: LPQOS, + lpGQOS: LPQOS, + dwFlags: DWORD, + ) -> SOCKET; + pub fn WSANtohl( + s: SOCKET, + netlong: u_long, + lphostlong: *mut c_long, + ) -> c_int; + pub fn WSANtohs( + s: SOCKET, + netshort: u_short, + lphostshort: *mut c_short, + ) -> c_int; + pub fn WSARecv( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSARecvDisconnect( + s: SOCKET, + lpInboundDisconnectData: LPWSABUF, + ) -> c_int; + pub fn WSARecvFrom( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpFrom: *mut SOCKADDR, + lpFromlen: LPINT, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSAResetEvent( + hEvent: WSAEVENT, + ) -> BOOL; + pub fn WSASend( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASendMsg( + Handle: SOCKET, + lpMsg: LPWSAMSG, + dwFlags: DWORD, + lpNumberOfBytesSent: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASendDisconnect( + s: SOCKET, + lpOutboundDisconnectData: LPWSABUF, + ) -> c_int; + pub fn WSASendTo( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpTo: *const SOCKADDR, + iToLen: c_int, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASetEvent( + hEvent: WSAEVENT, + ) -> BOOL; + pub fn WSASocketA( + af: c_int, + _type: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFOA, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET; + pub fn WSASocketW( + af: c_int, + _type: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET; + pub fn WSAWaitForMultipleEvents( + cEvents: DWORD, + lphEvents: *const WSAEVENT, + fWaitAll: BOOL, + dwTimeout: DWORD, + fAlertable: BOOL, + ) -> DWORD; + pub fn WSAAddressToStringA( + lpsaAddress: LPSOCKADDR, + dwAddressLength: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOA, + lpszAddressString: LPSTR, + lpdwAddressStringLength: LPDWORD, + ) -> INT; + pub fn WSAAddressToStringW( + lpsaAddress: LPSOCKADDR, + dwAddressLength: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + lpszAddressString: LPWSTR, + lpdwAddressStringLength: LPDWORD, + ) -> INT; + pub fn WSAStringToAddressA( + AddressString: LPSTR, + AddressFamily: INT, + lpProtocolInfo: LPWSAPROTOCOL_INFOA, + lpAddress: LPSOCKADDR, + lpAddressLength: LPINT, + ) -> INT; + pub fn WSAStringToAddressW( + AddressString: LPWSTR, + AddressFamily: INT, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + lpAddress: LPSOCKADDR, + lpAddressLength: LPINT, + ) -> INT; + pub fn WSALookupServiceBeginA( + lpqsRestrictions: LPWSAQUERYSETA, + dwControlFlags: DWORD, + lphLookup: LPHANDLE, + ) -> INT; + pub fn WSALookupServiceBeginW( + lpqsRestrictions: LPWSAQUERYSETW, + dwControlFlags: DWORD, + lphLookup: LPHANDLE, + ) -> INT; + pub fn WSALookupServiceNextA( + hLookup: HANDLE, + dwControlFlags: DWORD, + lpdwBufferLength: LPDWORD, + lpqsResults: LPWSAQUERYSETA, + ) -> INT; + pub fn WSALookupServiceNextW( + hLookup: HANDLE, + dwControlFlags: DWORD, + lpdwBufferLength: LPDWORD, + lpqsResults: LPWSAQUERYSETW, + ) -> INT; + pub fn WSANSPIoctl( + hLookup: HANDLE, + dwControlFlags: DWORD, + lpvInBuffer: LPVOID, + cbInBuffer: DWORD, + lpvOutBuffer: LPVOID, + cbOutBuffer: DWORD, + lpcbBytesReturned: LPDWORD, + lpCompletion: LPWSACOMPLETION, + ) -> INT; + pub fn WSALookupServiceEnd( + hLookup: HANDLE, + ) -> INT; + pub fn WSAInstallServiceClassA( + lpServiceClassInfo: LPWSASERVICECLASSINFOA, + ) -> INT; + pub fn WSAInstallServiceClassW( + lpServiceClassInfo: LPWSASERVICECLASSINFOW, + ) -> INT; + pub fn WSARemoveServiceClass( + lpServiceClassId: LPGUID, + ) -> INT; + pub fn WSAGetServiceClassInfoA( + lpProviderId: LPGUID, + lpServiceClassId: LPGUID, + lpdwBufSize: LPDWORD, + lpServiceClassInfo: LPWSASERVICECLASSINFOA, + ) -> INT; + pub fn WSAGetServiceClassInfoW( + lpProviderId: LPGUID, + lpServiceClassId: LPGUID, + lpdwBufSize: LPDWORD, + lpServiceClassInfo: LPWSASERVICECLASSINFOW, + ) -> INT; + pub fn WSAEnumNameSpaceProvidersA( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOA, + ) -> INT; + pub fn WSAEnumNameSpaceProvidersW( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOW, + ) -> INT; + pub fn WSAEnumNameSpaceProvidersExA( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOEXA, + ) -> INT; + pub fn WSAEnumNameSpaceProvidersExW( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOEXW, + ) -> INT; + pub fn WSAGetServiceClassNameByClassIdA( + lpServiceClassId: LPGUID, + lpszServiceClassName: LPSTR, + lpdwBufferLength: LPDWORD, + ) -> INT; + pub fn WSAGetServiceClassNameByClassIdW( + lpServiceClassId: LPGUID, + lpszServiceClassName: LPWSTR, + lpdwBufferLength: LPDWORD, + ) -> INT; + pub fn WSASetServiceA( + lpqsRegInfo: LPWSAQUERYSETA, + essoperation: WSAESETSERVICEOP, + dwControlFlags: DWORD, + ) -> INT; + pub fn WSASetServiceW( + lpqsRegInfo: LPWSAQUERYSETW, + essoperation: WSAESETSERVICEOP, + dwControlFlags: DWORD, + ) -> INT; + pub fn WSAProviderConfigChange( + lpNotificationHandle: LPHANDLE, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> INT; + pub fn WSAPoll( + fdArray: LPWSAPOLLFD, + fds: ULONG, + timeout: INT, + ) -> c_int; +} +pub type LPSOCKADDR_IN = *mut SOCKADDR_IN; +pub type LINGER = linger; +pub type PLINGER = *mut linger; +pub type LPLINGER = *mut linger; +pub type FD_SET = fd_set; +pub type PFD_SET = *mut fd_set; +pub type LPFD_SET = *mut fd_set; +pub type HOSTENT = hostent; +pub type PHOSTENT = *mut hostent; +pub type LPHOSTENT = *mut hostent; +pub type SERVENT = servent; +pub type PSERVENT = *mut servent; +pub type LPSERVENT = *mut servent; +pub type PROTOENT = protoent; +pub type PPROTOENT = *mut protoent; +pub type LPPROTOENT = *mut protoent; +pub type TIMEVAL = timeval; +pub type PTIMEVAL = *mut timeval; +pub type LPTIMEVAL = *mut timeval; +#[inline] +pub fn WSAMAKEASYNCREPLY(buflen: WORD, error: WORD) -> LONG { + MAKELONG(buflen, error) +} +#[inline] +pub fn WSAMAKESELECTREPLY(event: WORD, error: WORD) -> LONG { + MAKELONG(event, error) +} +#[inline] +pub fn WSAGETASYNCBUFLEN(lParam: DWORD) -> WORD { + LOWORD(lParam) +} +#[inline] +pub fn WSAGETASYNCERROR(lParam: DWORD) -> WORD { + HIWORD(lParam) +} +#[inline] +pub fn WSAGETSELECTEVENT(lParam: DWORD) -> WORD { + LOWORD(lParam) +} +#[inline] +pub fn WSAGETSELECTERROR(lParam: DWORD) -> WORD { + HIWORD(lParam) +} diff --git a/winapi/src/um/winspool.rs b/winapi/src/um/winspool.rs new file mode 100644 index 000000000..a4e3302a1 --- /dev/null +++ b/winapi/src/um/winspool.rs @@ -0,0 +1,2433 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Winspool header file +use shared::guiddef::GUID; +use shared::minwindef::{ + BOOL, BYTE, DWORD, FILETIME, FLOAT, LPBYTE, LPDWORD, LPHANDLE, LPVOID, MAX_PATH, PBYTE, PDWORD, + PULONG, PWORD, UINT, ULONG, WORD, +}; +use shared::windef::{HWND, RECTL, SIZEL}; +use shared::winerror::ERROR_NOT_SUPPORTED; +use um::minwinbase::SYSTEMTIME; +use um::wingdi::{LPDEVMODEA, LPDEVMODEW, PDEVMODEA, PDEVMODEW}; +use um::winnt::{ + ACCESS_MASK, CHAR, DWORDLONG, HANDLE, HRESULT, LANGID, LONG, LONGLONG, LPCSTR, LPCWSTR, LPSTR, + LPWSTR, PCWSTR, PSECURITY_DESCRIPTOR, PVOID, PWSTR, STANDARD_RIGHTS_EXECUTE, + STANDARD_RIGHTS_READ, STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_WRITE, WCHAR, +}; +use vc::vcruntime::size_t; +STRUCT!{struct PRINTER_INFO_1A { + Flags: DWORD, + pDescription: LPSTR, + pName: LPSTR, + pComment: LPSTR, +}} +pub type PPRINTER_INFO_1A = *mut PRINTER_INFO_1A; +pub type LPPRINTER_INFO_1A = *mut PRINTER_INFO_1A; +STRUCT!{struct PRINTER_INFO_1W { + Flags: DWORD, + pDescription: LPWSTR, + pName: LPWSTR, + pComment: LPWSTR, +}} +pub type PPRINTER_INFO_1W = *mut PRINTER_INFO_1W; +pub type LPPRINTER_INFO_1W = *mut PRINTER_INFO_1W; +STRUCT!{struct PRINTER_INFO_2A { + pServerName: LPSTR, + pPrinterName: LPSTR, + pShareName: LPSTR, + pPortName: LPSTR, + pDriverName: LPSTR, + pComment: LPSTR, + pLocation: LPSTR, + pDevMode: LPDEVMODEA, + pSepFile: LPSTR, + pPrintProcessor: LPSTR, + pDatatype: LPSTR, + pParameters: LPSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Attributes: DWORD, + Priority: DWORD, + DefaultPriority: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + Status: DWORD, + cJobs: DWORD, + AveragePPM: DWORD, +}} +pub type PPRINTER_INFO_2A = *mut PRINTER_INFO_2A; +pub type LPPRINTER_INFO_2A = *mut PRINTER_INFO_2A; +STRUCT!{struct PRINTER_INFO_2W { + pServerName: LPWSTR, + pPrinterName: LPWSTR, + pShareName: LPWSTR, + pPortName: LPWSTR, + pDriverName: LPWSTR, + pComment: LPWSTR, + pLocation: LPWSTR, + pDevMode: LPDEVMODEW, + pSepFile: LPWSTR, + pPrintProcessor: LPWSTR, + pDatatype: LPWSTR, + pParameters: LPWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Attributes: DWORD, + Priority: DWORD, + DefaultPriority: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + Status: DWORD, + cJobs: DWORD, + AveragePPM: DWORD, +}} +pub type PPRINTER_INFO_2W = *mut PRINTER_INFO_2W; +pub type LPPRINTER_INFO_2W = *mut PRINTER_INFO_2W; +STRUCT!{struct PRINTER_INFO_3 { + pSecurityDescriptor: PSECURITY_DESCRIPTOR, +}} +pub type PPRINTER_INFO_3 = *mut PRINTER_INFO_3; +pub type LPPRINTER_INFO_3 = *mut PRINTER_INFO_3; +STRUCT!{struct PRINTER_INFO_4A { + pPrinterName: LPSTR, + pServerName: LPSTR, + Attributes: DWORD, +}} +pub type PPRINTER_INFO_4A = *mut PRINTER_INFO_4A; +pub type LPPRINTER_INFO_4A = *mut PRINTER_INFO_4A; +STRUCT!{struct PRINTER_INFO_4W { + pPrinterName: LPWSTR, + pServerName: LPWSTR, + Attributes: DWORD, +}} +pub type PPRINTER_INFO_4W = *mut PRINTER_INFO_4W; +pub type LPPRINTER_INFO_4W = *mut PRINTER_INFO_4W; +STRUCT!{struct PRINTER_INFO_5A { + pPrinterName: LPSTR, + pPortName: LPSTR, + Attributes: DWORD, + DeviceNotSelectedTimeout: DWORD, + TransmissionRetryTimeout: DWORD, +}} +pub type PPRINTER_INFO_5A = *mut PRINTER_INFO_5A; +pub type LPPRINTER_INFO_5A = *mut PRINTER_INFO_5A; +STRUCT!{struct PRINTER_INFO_5W { + pPrinterName: LPWSTR, + pPortName: LPWSTR, + Attributes: DWORD, + DeviceNotSelectedTimeout: DWORD, + TransmissionRetryTimeout: DWORD, +}} +pub type PPRINTER_INFO_5W = *mut PRINTER_INFO_5W; +pub type LPPRINTER_INFO_5W = *mut PRINTER_INFO_5W; +STRUCT!{struct PRINTER_INFO_6 { + dwStatus: DWORD, +}} +pub type PPRINTER_INFO_6 = *mut PRINTER_INFO_6; +pub type LPPRINTER_INFO_6 = *mut PRINTER_INFO_6; +STRUCT!{struct PRINTER_INFO_7A { + pszObjectGUID: LPSTR, + dwAction: DWORD, +}} +pub type PPRINTER_INFO_7A = *mut PRINTER_INFO_7A; +pub type LPPRINTER_INFO_7A = *mut PRINTER_INFO_7A; +STRUCT!{struct PRINTER_INFO_7W { + pszObjectGUID: LPWSTR, + dwAction: DWORD, +}} +pub type PPRINTER_INFO_7W = *mut PRINTER_INFO_7W; +pub type LPPRINTER_INFO_7W = *mut PRINTER_INFO_7W; +pub const DSPRINT_PUBLISH: DWORD = 0x00000001; +pub const DSPRINT_UPDATE: DWORD = 0x00000002; +pub const DSPRINT_UNPUBLISH: DWORD = 0x00000004; +pub const DSPRINT_REPUBLISH: DWORD = 0x00000008; +pub const DSPRINT_PENDING: DWORD = 0x80000000; +STRUCT!{struct PRINTER_INFO_8A { + pDevMode: LPDEVMODEA, +}} +pub type PPRINTER_INFO_8A = *mut PRINTER_INFO_8A; +pub type LPPRINTER_INFO_8A = *mut PRINTER_INFO_8A; +STRUCT!{struct PRINTER_INFO_8W { + pDevMode: LPDEVMODEW, +}} +pub type PPRINTER_INFO_8W = *mut PRINTER_INFO_8W; +pub type LPPRINTER_INFO_8W = *mut PRINTER_INFO_8W; +STRUCT!{struct PRINTER_INFO_9A { + pDevMode: LPDEVMODEA, +}} +pub type PPRINTER_INFO_9A = *mut PRINTER_INFO_9A; +pub type LPPRINTER_INFO_9A = *mut PRINTER_INFO_9A; +STRUCT!{struct PRINTER_INFO_9W { + pDevMode: LPDEVMODEA, +}} +pub type PPRINTER_INFO_9W = *mut PRINTER_INFO_9W; +pub type LPPRINTER_INFO_9W = *mut PRINTER_INFO_9W; +pub const PRINTER_CONTROL_PAUSE: DWORD = 1; +pub const PRINTER_CONTROL_RESUME: DWORD = 2; +pub const PRINTER_CONTROL_PURGE: DWORD = 3; +pub const PRINTER_CONTROL_SET_STATUS: DWORD = 4; +pub const PRINTER_STATUS_PAUSED: DWORD = 0x00000001; +pub const PRINTER_STATUS_ERROR: DWORD = 0x00000002; +pub const PRINTER_STATUS_PENDING_DELETION: DWORD = 0x00000004; +pub const PRINTER_STATUS_PAPER_JAM: DWORD = 0x00000008; +pub const PRINTER_STATUS_PAPER_OUT: DWORD = 0x00000010; +pub const PRINTER_STATUS_MANUAL_FEED: DWORD = 0x00000020; +pub const PRINTER_STATUS_PAPER_PROBLEM: DWORD = 0x00000040; +pub const PRINTER_STATUS_OFFLINE: DWORD = 0x00000080; +pub const PRINTER_STATUS_IO_ACTIVE: DWORD = 0x00000100; +pub const PRINTER_STATUS_BUSY: DWORD = 0x00000200; +pub const PRINTER_STATUS_PRINTING: DWORD = 0x00000400; +pub const PRINTER_STATUS_OUTPUT_BIN_FULL: DWORD = 0x00000800; +pub const PRINTER_STATUS_NOT_AVAILABLE: DWORD = 0x00001000; +pub const PRINTER_STATUS_WAITING: DWORD = 0x00002000; +pub const PRINTER_STATUS_PROCESSING: DWORD = 0x00004000; +pub const PRINTER_STATUS_INITIALIZING: DWORD = 0x00008000; +pub const PRINTER_STATUS_WARMING_UP: DWORD = 0x00010000; +pub const PRINTER_STATUS_TONER_LOW: DWORD = 0x00020000; +pub const PRINTER_STATUS_NO_TONER: DWORD = 0x00040000; +pub const PRINTER_STATUS_PAGE_PUNT: DWORD = 0x00080000; +pub const PRINTER_STATUS_USER_INTERVENTION: DWORD = 0x00100000; +pub const PRINTER_STATUS_OUT_OF_MEMORY: DWORD = 0x00200000; +pub const PRINTER_STATUS_DOOR_OPEN: DWORD = 0x00400000; +pub const PRINTER_STATUS_SERVER_UNKNOWN: DWORD = 0x00800000; +pub const PRINTER_STATUS_POWER_SAVE: DWORD = 0x01000000; +pub const PRINTER_STATUS_SERVER_OFFLINE: DWORD = 0x02000000; +pub const PRINTER_STATUS_DRIVER_UPDATE_NEEDED: DWORD = 0x04000000; +pub const PRINTER_ATTRIBUTE_QUEUED: DWORD = 0x00000001; +pub const PRINTER_ATTRIBUTE_DIRECT: DWORD = 0x00000002; +pub const PRINTER_ATTRIBUTE_DEFAULT: DWORD = 0x00000004; +pub const PRINTER_ATTRIBUTE_SHARED: DWORD = 0x00000008; +pub const PRINTER_ATTRIBUTE_NETWORK: DWORD = 0x00000010; +pub const PRINTER_ATTRIBUTE_HIDDEN: DWORD = 0x00000020; +pub const PRINTER_ATTRIBUTE_LOCAL: DWORD = 0x00000040; +pub const PRINTER_ATTRIBUTE_ENABLE_DEVQ: DWORD = 0x00000080; +pub const PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS: DWORD = 0x00000100; +pub const PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST: DWORD = 0x00000200; +pub const PRINTER_ATTRIBUTE_WORK_OFFLINE: DWORD = 0x00000400; +pub const PRINTER_ATTRIBUTE_ENABLE_BIDI: DWORD = 0x00000800; +pub const PRINTER_ATTRIBUTE_RAW_ONLY: DWORD = 0x00001000; +pub const PRINTER_ATTRIBUTE_PUBLISHED: DWORD = 0x00002000; +pub const PRINTER_ATTRIBUTE_FAX: DWORD = 0x00004000; +pub const PRINTER_ATTRIBUTE_TS: DWORD = 0x00008000; +pub const PRINTER_ATTRIBUTE_PUSHED_USER: DWORD = 0x00020000; +pub const PRINTER_ATTRIBUTE_PUSHED_MACHINE: DWORD = 0x00040000; +pub const PRINTER_ATTRIBUTE_MACHINE: DWORD = 0x00080000; +pub const PRINTER_ATTRIBUTE_FRIENDLY_NAME: DWORD = 0x00100000; +pub const PRINTER_ATTRIBUTE_TS_GENERIC_DRIVER: DWORD = 0x00200000; +pub const PRINTER_ATTRIBUTE_PER_USER: DWORD = 0x00400000; +pub const PRINTER_ATTRIBUTE_ENTERPRISE_CLOUD: DWORD = 0x00800000; +pub const NO_PRIORITY: DWORD = 0; +pub const MAX_PRIORITY: DWORD = 99; +pub const MIN_PRIORITY: DWORD = 1; +pub const DEF_PRIORITY: DWORD = 1; +STRUCT!{struct JOB_INFO_1A { + JobId: DWORD, + pPrinterName: LPSTR, + pMachineName: LPSTR, + pUserName: LPSTR, + pDocument: LPSTR, + pDatatype: LPSTR, + pStatus: LPSTR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + TotalPages: DWORD, + PagesPrinted: DWORD, + Submitted: SYSTEMTIME, +}} +pub type PJOB_INFO_1A = *mut JOB_INFO_1A; +pub type LPJOB_INFO_1A = *mut JOB_INFO_1A; +STRUCT!{struct JOB_INFO_1W { + JobId: DWORD, + pPrinterName: LPWSTR, + pMachineName: LPWSTR, + pUserName: LPWSTR, + pDocument: LPWSTR, + pDatatype: LPWSTR, + pStatus: LPWSTR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + TotalPages: DWORD, + PagesPrinted: DWORD, + Submitted: SYSTEMTIME, +}} +pub type PJOB_INFO_1W = *mut JOB_INFO_1W; +pub type LPJOB_INFO_1W = *mut JOB_INFO_1W; +STRUCT!{struct JOB_INFO_2A { + JobId: DWORD, + pPrinterName: LPSTR, + pMachineName: LPSTR, + pUserName: LPSTR, + pDocument: LPSTR, + pNotifyName: LPSTR, + pDatatype: LPSTR, + pPrintProcessor: LPSTR, + pParameters: LPSTR, + pDriverName: LPSTR, + pDevMode: LPDEVMODEA, + pStatus: LPSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + TotalPages: DWORD, + Size: DWORD, + Submitted: SYSTEMTIME, + Time: DWORD, + PagesPrinted: DWORD, +}} +pub type PJOB_INFO_2A = *mut JOB_INFO_2A; +pub type LPJOB_INFO_2A = *mut JOB_INFO_2A; +STRUCT!{struct JOB_INFO_2W { + JobId: DWORD, + pPrinterName: LPWSTR, + pMachineName: LPWSTR, + pUserName: LPWSTR, + pDocument: LPWSTR, + pNotifyName: LPWSTR, + pDatatype: LPWSTR, + pPrintProcessor: LPWSTR, + pParameters: LPWSTR, + pDriverName: LPWSTR, + pDevMode: LPDEVMODEW, + pStatus: LPWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + TotalPages: DWORD, + Size: DWORD, + Submitted: SYSTEMTIME, + Time: DWORD, + PagesPrinted: DWORD, +}} +pub type PJOB_INFO_2W = *mut JOB_INFO_2W; +pub type LPJOB_INFO_2W = *mut JOB_INFO_2W; +STRUCT!{struct JOB_INFO_3 { + JobId: DWORD, + NextJobId: DWORD, + Reserved: DWORD, +}} +pub type PJOB_INFO_3 = *mut JOB_INFO_3; +pub type LPJOB_INFO_3 = *mut JOB_INFO_3; +STRUCT!{struct JOB_INFO_4A { + JobId: DWORD, + pPrinterName: LPSTR, + pMachineName: LPSTR, + pUserName: LPSTR, + pDocument: LPSTR, + pNotifyName: LPSTR, + pDatatype: LPSTR, + pPrintProcessor: LPSTR, + pParameters: LPSTR, + pDriverName: LPSTR, + pDevMode: LPDEVMODEA, + pStatus: LPSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + TotalPages: DWORD, + Size: DWORD, + Submitted: SYSTEMTIME, + Time: DWORD, + PagesPrinted: DWORD, + SizeHigh: LONG, +}} +pub type PJOB_INFO_4A = *mut JOB_INFO_4A; +pub type LPJOB_INFO_4A = *mut JOB_INFO_4A; +STRUCT!{struct JOB_INFO_4W { + JobId: DWORD, + pPrinterName: LPWSTR, + pMachineName: LPWSTR, + pUserName: LPWSTR, + pDocument: LPWSTR, + pNotifyName: LPWSTR, + pDatatype: LPWSTR, + pPrintProcessor: LPWSTR, + pParameters: LPWSTR, + pDriverName: LPWSTR, + pDevMode: LPDEVMODEW, + pStatus: LPWSTR, + pSecurityDescriptor: PSECURITY_DESCRIPTOR, + Status: DWORD, + Priority: DWORD, + Position: DWORD, + StartTime: DWORD, + UntilTime: DWORD, + TotalPages: DWORD, + Size: DWORD, + Submitted: SYSTEMTIME, + Time: DWORD, + PagesPrinted: DWORD, + SizeHigh: LONG, +}} +pub type PJOB_INFO_4W = *mut JOB_INFO_4W; +pub type LPJOB_INFO_4W = *mut JOB_INFO_4W; +pub const JOB_CONTROL_PAUSE: DWORD = 1; +pub const JOB_CONTROL_RESUME: DWORD = 2; +pub const JOB_CONTROL_CANCEL: DWORD = 3; +pub const JOB_CONTROL_RESTART: DWORD = 4; +pub const JOB_CONTROL_DELETE: DWORD = 5; +pub const JOB_CONTROL_SENT_TO_PRINTER: DWORD = 6; +pub const JOB_CONTROL_LAST_PAGE_EJECTED: DWORD = 7; +pub const JOB_STATUS_PAUSED: DWORD = 0x00000001; +pub const JOB_STATUS_ERROR: DWORD = 0x00000002; +pub const JOB_STATUS_DELETING: DWORD = 0x00000004; +pub const JOB_STATUS_SPOOLING: DWORD = 0x00000008; +pub const JOB_STATUS_PRINTING: DWORD = 0x00000010; +pub const JOB_STATUS_OFFLINE: DWORD = 0x00000020; +pub const JOB_STATUS_PAPEROUT: DWORD = 0x00000040; +pub const JOB_STATUS_PRINTED: DWORD = 0x00000080; +pub const JOB_STATUS_DELETED: DWORD = 0x00000100; +pub const JOB_STATUS_BLOCKED_DEVQ: DWORD = 0x00000200; +pub const JOB_STATUS_USER_INTERVENTION: DWORD = 0x00000400; +pub const JOB_STATUS_RESTART: DWORD = 0x00000800; +pub const JOB_POSITION_UNSPECIFIED: DWORD = 0; +STRUCT!{struct ADDJOB_INFO_1A { + Path: LPSTR, + JobId: DWORD, +}} +pub type PADDJOB_INFO_1A = *mut ADDJOB_INFO_1A; +pub type LPADDJOB_INFO_1A = *mut ADDJOB_INFO_1A; +STRUCT!{struct ADDJOB_INFO_1W { + Path: LPWSTR, + JobId: DWORD, +}} +pub type PADDJOB_INFO_1W = *mut ADDJOB_INFO_1W; +pub type LPADDJOB_INFO_1W = *mut ADDJOB_INFO_1W; +STRUCT!{struct DRIVER_INFO_1A { + pName: LPSTR, +}} +pub type PDRIVER_INFO_1A = *mut DRIVER_INFO_1A; +pub type LPDRIVER_INFO_1A = *mut DRIVER_INFO_1A; +STRUCT!{struct DRIVER_INFO_1W { + pName: LPWSTR, +}} +pub type PDRIVER_INFO_1W = *mut DRIVER_INFO_1W; +pub type LPDRIVER_INFO_1W = *mut DRIVER_INFO_1W; +STRUCT!{struct DRIVER_INFO_2A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, +}} +pub type PDRIVER_INFO_2A = *mut DRIVER_INFO_2A; +pub type LPDRIVER_INFO_2A = *mut DRIVER_INFO_2A; +STRUCT!{struct DRIVER_INFO_2W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, +}} +pub type PDRIVER_INFO_2W = *mut DRIVER_INFO_2W; +pub type LPDRIVER_INFO_2W = *mut DRIVER_INFO_2W; +STRUCT!{struct DRIVER_INFO_3A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, + pHelpFile: LPSTR, + pDependentFiles: LPSTR, + pMonitorName: LPSTR, + pDefaultDataType: LPSTR, +}} +pub type PDRIVER_INFO_3A = *mut DRIVER_INFO_3A; +pub type LPDRIVER_INFO_3A = *mut DRIVER_INFO_3A; +STRUCT!{struct DRIVER_INFO_3W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, + pHelpFile: LPWSTR, + pDependentFiles: LPWSTR, + pMonitorName: LPWSTR, + pDefaultDataType: LPWSTR, +}} +pub type PDRIVER_INFO_3W = *mut DRIVER_INFO_3W; +pub type LPDRIVER_INFO_3W = *mut DRIVER_INFO_3W; +STRUCT!{struct DRIVER_INFO_4A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, + pHelpFile: LPSTR, + pDependentFiles: LPSTR, + pMonitorName: LPSTR, + pDefaultDataType: LPSTR, + pszzPreviousNames: LPSTR, +}} +pub type PDRIVER_INFO_4A = *mut DRIVER_INFO_4A; +pub type LPDRIVER_INFO_4A = *mut DRIVER_INFO_4A; +STRUCT!{struct DRIVER_INFO_4W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, + pHelpFile: LPWSTR, + pDependentFiles: LPWSTR, + pMonitorName: LPWSTR, + pDefaultDataType: LPWSTR, + pszzPreviousNames: LPWSTR, +}} +pub type PDRIVER_INFO_4W = *mut DRIVER_INFO_4W; +pub type LPDRIVER_INFO_4W = *mut DRIVER_INFO_4W; +STRUCT!{struct DRIVER_INFO_5A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, + dwDriverAttributes: DWORD, + dwConfigVersion: DWORD, + dwDriverVersion: DWORD, +}} +pub type PDRIVER_INFO_5A = *mut DRIVER_INFO_5A; +pub type LPDRIVER_INFO_5A = *mut DRIVER_INFO_5A; +STRUCT!{struct DRIVER_INFO_5W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, + dwDriverAttributes: DWORD, + dwConfigVersion: DWORD, + dwDriverVersion: DWORD, +}} +pub type PDRIVER_INFO_5W = *mut DRIVER_INFO_5W; +pub type LPDRIVER_INFO_5W = *mut DRIVER_INFO_5W; +STRUCT!{struct DRIVER_INFO_6A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, + pHelpFile: LPSTR, + pDependentFiles: LPSTR, + pMonitorName: LPSTR, + pDefaultDataType: LPSTR, + pszzPreviousNames: LPSTR, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pszMfgName: LPSTR, + pszOEMUrl: LPSTR, + pszHardwareID: LPSTR, + pszProvider: LPSTR, +}} +pub type PDRIVER_INFO_6A = *mut DRIVER_INFO_6A; +pub type LPDRIVER_INFO_6A = *mut DRIVER_INFO_6A; +STRUCT!{struct DRIVER_INFO_6W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, + pHelpFile: LPWSTR, + pDependentFiles: LPWSTR, + pMonitorName: LPWSTR, + pDefaultDataType: LPWSTR, + pszzPreviousNames: LPWSTR, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pszMfgName: LPWSTR, + pszOEMUrl: LPWSTR, + pszHardwareID: LPWSTR, + pszProvider: LPWSTR, +}} +pub type PDRIVER_INFO_6W = *mut DRIVER_INFO_6W; +pub type LPDRIVER_INFO_6W = *mut DRIVER_INFO_6W; +pub const PRINTER_DRIVER_PACKAGE_AWARE: DWORD = 0x00000001; +pub const PRINTER_DRIVER_XPS: DWORD = 0x00000002; +pub const PRINTER_DRIVER_SANDBOX_ENABLED: DWORD = 0x00000004; +pub const PRINTER_DRIVER_CLASS: DWORD = 0x00000008; +pub const PRINTER_DRIVER_DERIVED: DWORD = 0x00000010; +pub const PRINTER_DRIVER_NOT_SHAREABLE: DWORD = 0x00000020; +pub const PRINTER_DRIVER_CATEGORY_FAX: DWORD = 0x00000040; +pub const PRINTER_DRIVER_CATEGORY_FILE: DWORD = 0x00000080; +pub const PRINTER_DRIVER_CATEGORY_VIRTUAL: DWORD = 0x00000100; +pub const PRINTER_DRIVER_CATEGORY_SERVICE: DWORD = 0x00000200; +pub const PRINTER_DRIVER_SOFT_RESET_REQUIRED: DWORD = 0x00000400; +pub const PRINTER_DRIVER_SANDBOX_DISABLED: DWORD = 0x00000800; +pub const PRINTER_DRIVER_CATEGORY_3D: DWORD = 0x00001000; +pub const PRINTER_DRIVER_CATEGORY_CLOUD: DWORD = 0x00002000; +STRUCT!{struct DRIVER_INFO_8A { + cVersion: DWORD, + pName: LPSTR, + pEnvironment: LPSTR, + pDriverPath: LPSTR, + pDataFile: LPSTR, + pConfigFile: LPSTR, + pHelpFile: LPSTR, + pDependentFiles: LPSTR, + pMonitorName: LPSTR, + pDefaultDataType: LPSTR, + pszzPreviousNames: LPSTR, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pszMfgName: LPSTR, + pszOEMUrl: LPSTR, + pszHardwareID: LPSTR, + pszProvider: LPSTR, + pszPrintProcessor: LPSTR, + pszVendorSetup: LPSTR, + pszzColorProfiles: LPSTR, + pszInfPath: LPSTR, + dwPrinterDriverAttributes: DWORD, + pszzCoreDriverDependencies: LPSTR, + ftMinInboxDriverVerDate: FILETIME, + dwlMinInboxDriverVerVersion: DWORDLONG, +}} +pub type PDRIVER_INFO_8A = *mut DRIVER_INFO_8A; +pub type LPDRIVER_INFO_8A = *mut DRIVER_INFO_8A; +STRUCT!{struct DRIVER_INFO_8W { + cVersion: DWORD, + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverPath: LPWSTR, + pDataFile: LPWSTR, + pConfigFile: LPWSTR, + pHelpFile: LPWSTR, + pDependentFiles: LPWSTR, + pMonitorName: LPWSTR, + pDefaultDataType: LPWSTR, + pszzPreviousNames: LPWSTR, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pszMfgName: LPWSTR, + pszOEMUrl: LPWSTR, + pszHardwareID: LPWSTR, + pszProvider: LPWSTR, + pszPrintProcessor: LPWSTR, + pszVendorSetup: LPWSTR, + pszzColorProfiles: LPWSTR, + pszInfPath: LPWSTR, + dwPrinterDriverAttributes: DWORD, + pszzCoreDriverDependencies: LPWSTR, + ftMinInboxDriverVerDate: FILETIME, + dwlMinInboxDriverVerVersion: DWORDLONG, +}} +pub type PDRIVER_INFO_8W = *mut DRIVER_INFO_8W; +pub type LPDRIVER_INFO_8W = *mut DRIVER_INFO_8W; +pub const DRIVER_KERNELMODE: DWORD = 0x00000001; +pub const DRIVER_USERMODE: DWORD = 0x00000002; +pub const DPD_DELETE_UNUSED_FILES: DWORD = 0x00000001; +pub const DPD_DELETE_SPECIFIC_VERSION: DWORD = 0x00000002; +pub const DPD_DELETE_ALL_FILES: DWORD = 0x00000004; +pub const APD_STRICT_UPGRADE: DWORD = 0x00000001; +pub const APD_STRICT_DOWNGRADE: DWORD = 0x00000002; +pub const APD_COPY_ALL_FILES: DWORD = 0x00000004; +pub const APD_COPY_NEW_FILES: DWORD = 0x00000008; +pub const APD_COPY_FROM_DIRECTORY: DWORD = 0x00000010; +STRUCT!{struct DOC_INFO_1A { + pDocName: LPSTR, + pOutputFile: LPSTR, + pDatatype: LPSTR, +}} +pub type PDOC_INFO_1A = *mut DOC_INFO_1A; +pub type LPDOC_INFO_1A = *mut DOC_INFO_1A; +STRUCT!{struct DOC_INFO_1W { + pDocName: LPWSTR, + pOutputFile: LPWSTR, + pDatatype: LPWSTR, +}} +pub type PDOC_INFO_1W = *mut DOC_INFO_1W; +pub type LPDOC_INFO_1W = *mut DOC_INFO_1W; +STRUCT!{struct FORM_INFO_1A { + Flags: DWORD, + pName: LPSTR, + Size: SIZEL, + ImageableArea: RECTL, +}} +pub type PFORM_INFO_1A = *mut FORM_INFO_1A; +pub type LPFORM_INFO_1A = *mut FORM_INFO_1A; +STRUCT!{struct FORM_INFO_1W { + Flags: DWORD, + pName: LPWSTR, + Size: SIZEL, + ImageableArea: RECTL, +}} +pub type PFORM_INFO_1W = *mut FORM_INFO_1W; +pub type LPFORM_INFO_1W = *mut FORM_INFO_1W; +pub const STRING_NONE: DWORD = 0x00000001; +pub const STRING_MUIDLL: DWORD = 0x00000002; +pub const STRING_LANGPAIR: DWORD = 0x00000004; +pub const MAX_FORM_KEYWORD_LENGTH: usize = 63 + 1; +STRUCT!{struct FORM_INFO_2A { + Flags: DWORD, + pName: LPCSTR, + Size: SIZEL, + ImageableArea: RECTL, + pKeyword: LPCSTR, + StringType: DWORD, + pMuiDll: LPCSTR, + dwResourceId: DWORD, + pDisplayName: LPCSTR, + wLangId: LANGID, +}} +pub type PFORM_INFO_2A = *mut FORM_INFO_2A; +pub type LPFORM_INFO_2A = *mut FORM_INFO_2A; +STRUCT!{struct FORM_INFO_2W { + Flags: DWORD, + pName: LPCWSTR, + Size: SIZEL, + ImageableArea: RECTL, + pKeyword: LPCSTR, + StringType: DWORD, + pMuiDll: LPCWSTR, + dwResourceId: DWORD, + pDisplayName: LPCWSTR, + wLangId: LANGID, +}} +pub type PFORM_INFO_2W = *mut FORM_INFO_2W; +pub type LPFORM_INFO_2W = *mut FORM_INFO_2W; +STRUCT!{struct DOC_INFO_2A { + pDocName: LPSTR, + pOutputFile: LPSTR, + pDatatype: LPSTR, + dwMode: DWORD, + JobId: DWORD, +}} +pub type PDOC_INFO_2A = *mut DOC_INFO_2A; +pub type LPDOC_INFO_2A = *mut DOC_INFO_2A; +STRUCT!{struct DOC_INFO_2W { + pDocName: LPWSTR, + pOutputFile: LPWSTR, + pDatatype: LPWSTR, + dwMode: DWORD, + JobId: DWORD, +}} +pub type PDOC_INFO_2W = *mut DOC_INFO_2W; +pub type LPDOC_INFO_2W = *mut DOC_INFO_2W; +pub const DI_CHANNEL: DWORD = 1; +pub const DI_READ_SPOOL_JOB: DWORD = 3; +STRUCT!{struct DOC_INFO_3A { + pDocName: LPSTR, + pOutputFile: LPSTR, + pDatatype: LPSTR, + dwFlags: DWORD, +}} +pub type PDOC_INFO_3A = *mut DOC_INFO_3A; +pub type LPDOC_INFO_3A = *mut DOC_INFO_3A; +STRUCT!{struct DOC_INFO_3W { + pDocName: LPWSTR, + pOutputFile: LPWSTR, + pDatatype: LPWSTR, + dwFlags: DWORD, +}} +pub type PDOC_INFO_3W = *mut DOC_INFO_3W; +pub type LPDOC_INFO_3W = *mut DOC_INFO_3W; +pub const DI_MEMORYMAP_WRITE: DWORD = 0x00000001; +pub const FORM_USER: DWORD = 0x00000000; +pub const FORM_BUILTIN: DWORD = 0x00000001; +pub const FORM_PRINTER: DWORD = 0x00000002; +STRUCT!{struct PRINTPROCESSOR_INFO_1A { + pName: LPSTR, +}} +pub type PPRINTPROCESSOR_INFO_1A = *mut PRINTPROCESSOR_INFO_1A; +pub type LPPRINTPROCESSOR_INFO_1A = *mut PRINTPROCESSOR_INFO_1A; +STRUCT!{struct PRINTPROCESSOR_INFO_1W { + pName: LPWSTR, +}} +pub type PPRINTPROCESSOR_INFO_1W = *mut PRINTPROCESSOR_INFO_1W; +pub type LPPRINTPROCESSOR_INFO_1W = *mut PRINTPROCESSOR_INFO_1W; +STRUCT!{struct PRINTPROCESSOR_CAPS_1 { + dwLevel: DWORD, + dwNupOptions: DWORD, + dwPageOrderFlags: DWORD, + dwNumberOfCopies: DWORD, +}} +pub type PPRINTPROCESSOR_CAPS_1 = *mut PRINTPROCESSOR_CAPS_1; +STRUCT!{struct PRINTPROCESSOR_CAPS_2 { + dwLevel: DWORD, + dwNupOptions: DWORD, + dwPageOrderFlags: DWORD, + dwNumberOfCopies: DWORD, + dwDuplexHandlingCaps: DWORD, + dwNupDirectionCaps: DWORD, + dwNupBorderCaps: DWORD, + dwBookletHandlingCaps: DWORD, + dwScalingCaps: DWORD, +}} +pub type PPRINTPROCESSOR_CAPS_2 = *mut PRINTPROCESSOR_CAPS_2; +pub const PPCAPS_RIGHT_THEN_DOWN: DWORD = 0x00000001; +pub const PPCAPS_DOWN_THEN_RIGHT: DWORD = 0x00000001 << 1; +pub const PPCAPS_LEFT_THEN_DOWN: DWORD = 0x00000001 << 2; +pub const PPCAPS_DOWN_THEN_LEFT: DWORD = 0x00000001 << 3; +pub const PPCAPS_BORDER_PRINT: DWORD = 0x00000001; +pub const PPCAPS_BOOKLET_EDGE: DWORD = 0x00000001; +pub const PPCAPS_REVERSE_PAGES_FOR_REVERSE_DUPLEX: DWORD = 0x00000001; +pub const PPCAPS_DONT_SEND_EXTRA_PAGES_FOR_DUPLEX: DWORD = 0x00000001 << 1; +pub const PPCAPS_SQUARE_SCALING: DWORD = 0x00000001; +STRUCT!{struct PORT_INFO_1A { + pName: LPSTR, +}} +pub type PPORT_INFO_1A = *mut PORT_INFO_1A; +pub type LPPORT_INFO_1A = *mut PORT_INFO_1A; +STRUCT!{struct PORT_INFO_1W { + pName: LPWSTR, +}} +pub type PPORT_INFO_1W = *mut PORT_INFO_1W; +pub type LPPORT_INFO_1W = *mut PORT_INFO_1W; +STRUCT!{struct PORT_INFO_2A { + pPortName: LPSTR, + pMonitorName: LPSTR, + pDescription: LPSTR, + fPortType: DWORD, + Reserved: DWORD, +}} +pub type PPORT_INFO_2A = *mut PORT_INFO_2A; +pub type LPPORT_INFO_2A = *mut PORT_INFO_2A; +STRUCT!{struct PORT_INFO_2W { + pPortName: LPWSTR, + pMonitorName: LPWSTR, + pDescription: LPWSTR, + fPortType: DWORD, + Reserved: DWORD, +}} +pub type PPORT_INFO_2W = *mut PORT_INFO_2W; +pub type LPPORT_INFO_2W = *mut PORT_INFO_2W; +pub const PORT_TYPE_WRITE: DWORD = 0x0001; +pub const PORT_TYPE_READ: DWORD = 0x0002; +pub const PORT_TYPE_REDIRECTED: DWORD = 0x0004; +pub const PORT_TYPE_NET_ATTACHED: DWORD = 0x0008; +STRUCT!{struct PORT_INFO_3A { + dwStatus: DWORD, + pszStatus: LPSTR, + dwSeverity: DWORD, +}} +pub type PPORT_INFO_3A = *mut PORT_INFO_3A; +pub type LPPORT_INFO_3A = *mut PORT_INFO_3A; +STRUCT!{struct PORT_INFO_3W { + dwStatus: DWORD, + pszStatus: LPWSTR, + dwSeverity: DWORD, +}} +pub type PPORT_INFO_3W = *mut PORT_INFO_3W; +pub type LPPORT_INFO_3W = *mut PORT_INFO_3W; +pub const PORT_STATUS_TYPE_ERROR: DWORD = 1; +pub const PORT_STATUS_TYPE_WARNING: DWORD = 2; +pub const PORT_STATUS_TYPE_INFO: DWORD = 3; +pub const PORT_STATUS_OFFLINE: DWORD = 1; +pub const PORT_STATUS_PAPER_JAM: DWORD = 2; +pub const PORT_STATUS_PAPER_OUT: DWORD = 3; +pub const PORT_STATUS_OUTPUT_BIN_FULL: DWORD = 4; +pub const PORT_STATUS_PAPER_PROBLEM: DWORD = 5; +pub const PORT_STATUS_NO_TONER: DWORD = 6; +pub const PORT_STATUS_DOOR_OPEN: DWORD = 7; +pub const PORT_STATUS_USER_INTERVENTION: DWORD = 8; +pub const PORT_STATUS_OUT_OF_MEMORY: DWORD = 9; +pub const PORT_STATUS_TONER_LOW: DWORD = 10; +pub const PORT_STATUS_WARMING_UP: DWORD = 11; +pub const PORT_STATUS_POWER_SAVE: DWORD = 12; +STRUCT!{struct MONITOR_INFO_1A { + pName: LPSTR, +}} +pub type PMONITOR_INFO_1A = *mut MONITOR_INFO_1A; +pub type LPMONITOR_INFO_1A = *mut MONITOR_INFO_1A; +STRUCT!{struct MONITOR_INFO_1W { + pName: LPWSTR, +}} +pub type PMONITOR_INFO_1W = *mut MONITOR_INFO_1W; +pub type LPMONITOR_INFO_1W = *mut MONITOR_INFO_1W; +STRUCT!{struct MONITOR_INFO_2A { + pName: LPSTR, + pEnvironment: LPSTR, + pDLLName: LPSTR, +}} +pub type PMONITOR_INFO_2A = *mut MONITOR_INFO_2A; +pub type LPMONITOR_INFO_2A = *mut MONITOR_INFO_2A; +STRUCT!{struct MONITOR_INFO_2W { + pName: LPWSTR, + pEnvironment: LPWSTR, + pDLLName: LPWSTR, +}} +pub type PMONITOR_INFO_2W = *mut MONITOR_INFO_2W; +pub type LPMONITOR_INFO_2W = *mut MONITOR_INFO_2W; +STRUCT!{struct DATATYPES_INFO_1A { + pName: LPSTR, +}} +pub type PDATATYPES_INFO_1A = *mut DATATYPES_INFO_1A; +pub type LPDATATYPES_INFO_1A = *mut DATATYPES_INFO_1A; +STRUCT!{struct DATATYPES_INFO_1W { + pName: LPWSTR, +}} +pub type PDATATYPES_INFO_1W = *mut DATATYPES_INFO_1W; +pub type LPDATATYPES_INFO_1W = *mut DATATYPES_INFO_1W; +STRUCT!{struct PRINTER_DEFAULTSA { + pDataType: LPSTR, + pDevMode: LPDEVMODEA, + DesiredAccess: ACCESS_MASK, +}} +pub type PPRINTER_DEFAULTSA = *mut PRINTER_DEFAULTSA; +pub type LPPRINTER_DEFAULTSA = *mut PRINTER_DEFAULTSA; +STRUCT!{struct PRINTER_DEFAULTSW { + pDataType: LPWSTR, + pDevMode: LPDEVMODEW, + DesiredAccess: ACCESS_MASK, +}} +pub type PPRINTER_DEFAULTSW = *mut PRINTER_DEFAULTSW; +pub type LPPRINTER_DEFAULTSW = *mut PRINTER_DEFAULTSW; +STRUCT!{struct PRINTER_ENUM_VALUESA { + pValueName: LPSTR, + cbValueName: DWORD, + dwType: DWORD, + pData: LPBYTE, + cbData: DWORD, +}} +pub type PPRINTER_ENUM_VALUESA = *mut PRINTER_ENUM_VALUESA; +pub type LPPRINTER_ENUM_VALUESA = *mut PRINTER_ENUM_VALUESA; +STRUCT!{struct PRINTER_ENUM_VALUESW { + pValueName: LPWSTR, + cbValueName: DWORD, + dwType: DWORD, + pData: LPBYTE, + cbData: DWORD, +}} +pub type PPRINTER_ENUM_VALUESW = *mut PRINTER_ENUM_VALUESW; +pub type LPPRINTER_ENUM_VALUESW = *mut PRINTER_ENUM_VALUESW; +extern "system" { + pub fn EnumPrintersA( + Flags: DWORD, + Name: LPSTR, + Level: DWORD, + pPrinterEnum: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumPrintersW( + Flags: DWORD, + Name: LPWSTR, + Level: DWORD, + pPrinterEnum: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; +} +pub const PRINTER_ENUM_DEFAULT: DWORD = 0x00000001; +pub const PRINTER_ENUM_LOCAL: DWORD = 0x00000002; +pub const PRINTER_ENUM_CONNECTIONS: DWORD = 0x00000004; +pub const PRINTER_ENUM_FAVORITE: DWORD = 0x00000004; +pub const PRINTER_ENUM_NAME: DWORD = 0x00000008; +pub const PRINTER_ENUM_REMOTE: DWORD = 0x00000010; +pub const PRINTER_ENUM_SHARED: DWORD = 0x00000020; +pub const PRINTER_ENUM_NETWORK: DWORD = 0x00000040; +pub const PRINTER_ENUM_EXPAND: DWORD = 0x00004000; +pub const PRINTER_ENUM_CONTAINER: DWORD = 0x00008000; +pub const PRINTER_ENUM_ICONMASK: DWORD = 0x00ff0000; +pub const PRINTER_ENUM_ICON1: DWORD = 0x00010000; +pub const PRINTER_ENUM_ICON2: DWORD = 0x00020000; +pub const PRINTER_ENUM_ICON3: DWORD = 0x00040000; +pub const PRINTER_ENUM_ICON4: DWORD = 0x00080000; +pub const PRINTER_ENUM_ICON5: DWORD = 0x00100000; +pub const PRINTER_ENUM_ICON6: DWORD = 0x00200000; +pub const PRINTER_ENUM_ICON7: DWORD = 0x00400000; +pub const PRINTER_ENUM_ICON8: DWORD = 0x00800000; +pub const PRINTER_ENUM_HIDE: DWORD = 0x01000000; +pub const PRINTER_ENUM_CATEGORY_ALL: DWORD = 0x02000000; +pub const PRINTER_ENUM_CATEGORY_3D: DWORD = 0x04000000; +pub const SPOOL_FILE_PERSISTENT: DWORD = 0x00000001; +pub const SPOOL_FILE_TEMPORARY: DWORD = 0x00000002; +extern "system" { + pub fn GetSpoolFileHandle( + hPrinter: HANDLE, + ) -> HANDLE; + pub fn CommitSpoolData( + hPrinter: HANDLE, + hSpoolFile: HANDLE, + cbCommit: DWORD, + ) -> HANDLE; + pub fn CloseSpoolFileHandle( + hPrinter: HANDLE, + hSpoolFile: HANDLE, + ) -> BOOL; + pub fn OpenPrinterA( + pPrinterName: LPSTR, + phPrinter: LPHANDLE, + pDefault: LPPRINTER_DEFAULTSA, + ) -> BOOL; + pub fn OpenPrinterW( + pPrinterName: LPWSTR, + phPrinter: LPHANDLE, + pDefault: LPPRINTER_DEFAULTSW, + ) -> BOOL; + pub fn ResetPrinterA( + hPrinter: HANDLE, + pDefault: LPPRINTER_DEFAULTSA, + ) -> BOOL; + pub fn ResetPrinterW( + hPrinter: HANDLE, + pDefault: LPPRINTER_DEFAULTSW, + ) -> BOOL; + pub fn SetJobA( + hPrinter: HANDLE, + JobId: DWORD, + Level: DWORD, + pJob: LPBYTE, + Command: DWORD, + ) -> BOOL; + pub fn SetJobW( + hPrinter: HANDLE, + JobId: DWORD, + Level: DWORD, + pJob: LPBYTE, + Command: DWORD, + ) -> BOOL; + pub fn GetJobA( + hPrinter: HANDLE, + JobId: DWORD, + Level: DWORD, + pJob: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetJobW( + hPrinter: HANDLE, + JobId: DWORD, + Level: DWORD, + pJob: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn EnumJobsA( + hPrinter: HANDLE, + FirstJob: DWORD, + NoJobs: DWORD, + Level: DWORD, + pJob: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumJobsW( + hPrinter: HANDLE, + FirstJob: DWORD, + NoJobs: DWORD, + Level: DWORD, + pJob: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn AddPrinterA( + pName: LPSTR, + Level: DWORD, + pPrinter: LPBYTE, + ) -> HANDLE; + pub fn AddPrinterW( + pName: LPWSTR, + Level: DWORD, + pPrinter: LPBYTE, + ) -> HANDLE; + pub fn DeletePrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn SetPrinterA( + hPrinter: HANDLE, + Level: DWORD, + pPrinter: LPBYTE, + Command: DWORD, + ) -> BOOL; + pub fn SetPrinterW( + hPrinter: HANDLE, + Level: DWORD, + pPrinter: LPBYTE, + Command: DWORD, + ) -> BOOL; + pub fn GetPrinterA( + hPrinter: HANDLE, + Level: DWORD, + pPrinter: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrinterW( + hPrinter: HANDLE, + Level: DWORD, + pPrinter: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn AddPrinterDriverA( + pName: LPSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + ) -> BOOL; + pub fn AddPrinterDriverW( + pName: LPWSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + ) -> BOOL; + pub fn AddPrinterDriverExA( + pName: LPSTR, + Level: DWORD, + pDriverInfo: PBYTE, + dwFileCopyFlags: DWORD, + ) -> BOOL; + pub fn AddPrinterDriverExW( + pName: LPWSTR, + Level: DWORD, + pDriverInfo: PBYTE, + dwFileCopyFlags: DWORD, + ) -> BOOL; + pub fn EnumPrinterDriversA( + pName: LPSTR, + pEnvironment: LPSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumPrinterDriversW( + pName: LPWSTR, + pEnvironment: LPWSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn GetPrinterDriverA( + hPrinter: HANDLE, + pEnvironment: LPSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrinterDriverW( + hPrinter: HANDLE, + pEnvironment: LPWSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrinterDriverDirectoryA( + pName: LPSTR, + pEnvironment: LPSTR, + Level: DWORD, + pDriverDirectory: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrinterDriverDirectoryW( + pName: LPWSTR, + pEnvironment: LPWSTR, + Level: DWORD, + pDriverDirectory: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn DeletePrinterDriverA( + pName: LPSTR, + pEnvironment: LPSTR, + pDriverName: LPSTR, + ) -> BOOL; + pub fn DeletePrinterDriverW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverName: LPWSTR, + ) -> BOOL; + pub fn DeletePrinterDriverExA( + pName: LPSTR, + pEnvironment: LPSTR, + pDriverName: LPSTR, + dwDeleteFlag: DWORD, + dwVersionFlag: DWORD, + ) -> BOOL; + pub fn DeletePrinterDriverExW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pDriverName: LPWSTR, + dwDeleteFlag: DWORD, + dwVersionFlag: DWORD, + ) -> BOOL; + pub fn AddPrintProcessorA( + pName: LPSTR, + pEnvironment: LPSTR, + pPathName: LPSTR, + pPrintProcessorName: LPSTR, + ) -> BOOL; + pub fn AddPrintProcessorW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pPathName: LPWSTR, + pPrintProcessorName: LPWSTR, + ) -> BOOL; + pub fn EnumPrintProcessorsA( + pName: LPSTR, + pEnvironment: LPSTR, + Level: DWORD, + pPrintProcessorInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumPrintProcessorsW( + pName: LPWSTR, + pEnvironment: LPWSTR, + Level: DWORD, + pPrintProcessorInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn GetPrintProcessorDirectoryA( + pName: LPSTR, + pEnvironment: LPSTR, + Level: DWORD, + pPrintProcessorInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrintProcessorDirectoryW( + pName: LPWSTR, + pEnvironment: LPWSTR, + Level: DWORD, + pPrintProcessorInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn EnumPrintProcessorDatatypesA( + pName: LPSTR, + pPrintProcessorName: LPSTR, + Level: DWORD, + pDatatypes: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumPrintProcessorDatatypesW( + pName: LPWSTR, + pPrintProcessorName: LPWSTR, + Level: DWORD, + pDatatypes: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn DeletePrintProcessorA( + pName: LPSTR, + pEnvironment: LPSTR, + pPrintProcessorName: LPSTR, + ) -> BOOL; + pub fn DeletePrintProcessorW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pPrintProcessorName: LPWSTR, + ) -> BOOL; + pub fn StartDocPrinterA( + hPrinter: HANDLE, + Level: DWORD, + pDocInfo: LPBYTE, + ) -> DWORD; + pub fn StartDocPrinterW( + hPrinter: HANDLE, + Level: DWORD, + pDocInfo: LPBYTE, + ) -> DWORD; + pub fn StartPagePrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn WritePrinter( + hPrinter: HANDLE, + pBuf: LPVOID, + cbBuf: DWORD, + pcWritten: LPDWORD, + ) -> BOOL; + pub fn FlushPrinter( + hPrinter: HANDLE, + pBuf: LPVOID, + cbBuf: DWORD, + pcWritten: LPDWORD, + cSleep: DWORD, + ) -> BOOL; + pub fn EndPagePrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn AbortPrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn ReadPrinter( + hPrinter: HANDLE, + pBuf: LPVOID, + cbBuf: DWORD, + pNoBytesRead: LPDWORD, + ) -> BOOL; + pub fn EndDocPrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn AddJobA( + hPrinter: HANDLE, + Level: DWORD, + pData: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn AddJobW( + hPrinter: HANDLE, + Level: DWORD, + pData: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn ScheduleJob( + hPrinter: HANDLE, + JobId: DWORD, + ) -> BOOL; + pub fn PrinterProperties( + hWnd: HWND, + hPrinter: HANDLE, + ) -> BOOL; + pub fn DocumentPropertiesA( + hWnd: HWND, + hPrinter: HANDLE, + pDeviceName: LPSTR, + pDevModeOutput: PDEVMODEA, + pDevModeInput: PDEVMODEA, + fMode: DWORD, + ) -> LONG; + pub fn DocumentPropertiesW( + hWnd: HWND, + hPrinter: HANDLE, + pDeviceName: LPWSTR, + pDevModeOutput: PDEVMODEW, + pDevModeInput: PDEVMODEW, + fMode: DWORD, + ) -> LONG; + pub fn AdvancedDocumentPropertiesA( + hWnd: HWND, + hPrinter: HANDLE, + pDeviceName: LPSTR, + pDevModeOutput: PDEVMODEA, + pDevModeInput: PDEVMODEA, + ) -> LONG; + pub fn AdvancedDocumentPropertiesW( + hWnd: HWND, + hPrinter: HANDLE, + pDeviceName: LPWSTR, + pDevModeOutput: PDEVMODEW, + pDevModeInput: PDEVMODEW, + ) -> LONG; + pub fn ExtDeviceMode( + hWnd: HWND, + hInst: HANDLE, + pDevModeOutput: LPDEVMODEA, + pDeviceName: LPSTR, + pPort: LPSTR, + pDevModeInput: LPDEVMODEA, + pProfile: LPSTR, + fMode: DWORD, + ) -> LONG; + pub fn GetPrinterDataA( + hPrinter: HANDLE, + pValueName: LPSTR, + pType: LPDWORD, + pData: LPBYTE, + nSize: DWORD, + pcbNeeded: LPDWORD, + ) -> DWORD; + pub fn GetPrinterDataW( + hPrinter: HANDLE, + pValueName: LPWSTR, + pType: LPDWORD, + pData: LPBYTE, + nSize: DWORD, + pcbNeeded: LPDWORD, + ) -> DWORD; + pub fn GetPrinterDataExA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + pValueName: LPCSTR, + pType: LPDWORD, + pData: LPBYTE, + nSize: DWORD, + pcbNeeded: LPDWORD, + ) -> DWORD; + pub fn GetPrinterDataExW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + pValueName: LPCWSTR, + pType: LPDWORD, + pData: LPBYTE, + nSize: DWORD, + pcbNeeded: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterDataA( + hPrinter: HANDLE, + dwIndex: DWORD, + pValueName: LPSTR, + cbValueName: DWORD, + pcbValueName: LPDWORD, + pType: LPDWORD, + pData: LPBYTE, + cbData: DWORD, + pcbData: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterDataW( + hPrinter: HANDLE, + dwIndex: DWORD, + pValueName: LPWSTR, + cbValueName: DWORD, + pcbValueName: LPDWORD, + pType: LPDWORD, + pData: LPBYTE, + cbData: DWORD, + pcbData: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterDataExA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + pEnumValues: LPBYTE, + cbEnumValues: DWORD, + pcbEnumValues: LPDWORD, + pnEnumValues: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterDataExW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + pEnumValues: LPBYTE, + cbEnumValues: DWORD, + pcbEnumValues: LPDWORD, + pnEnumValues: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterKeyA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + pSubKey: LPSTR, + cbSubkey: DWORD, + pcbSubkey: LPDWORD, + ) -> DWORD; + pub fn EnumPrinterKeyW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + pSubKey: LPWSTR, + cbSubkey: DWORD, + pcbSubkey: LPDWORD, + ) -> DWORD; + pub fn SetPrinterDataA( + hPrinter: HANDLE, + pValueName: LPSTR, + Type: DWORD, + pData: LPBYTE, + cbData: DWORD, + ) -> DWORD; + pub fn SetPrinterDataW( + hPrinter: HANDLE, + pValueName: LPWSTR, + Type: DWORD, + pData: LPBYTE, + cbData: DWORD, + ) -> DWORD; + pub fn SetPrinterDataExA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + pValueName: LPCSTR, + Type: DWORD, + pData: LPBYTE, + cbData: DWORD, + ) -> DWORD; + pub fn SetPrinterDataExW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + pValueName: LPCWSTR, + Type: DWORD, + pData: LPBYTE, + cbData: DWORD, + ) -> DWORD; + pub fn DeletePrinterDataA( + hPrinter: HANDLE, + pValueName: LPSTR, + ) -> DWORD; + pub fn DeletePrinterDataW( + hPrinter: HANDLE, + pValueName: LPWSTR, + ) -> DWORD; + pub fn DeletePrinterDataExA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + pValueName: LPCSTR, + ) -> DWORD; + pub fn DeletePrinterDataExW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + pValueName: LPCWSTR, + ) -> DWORD; + pub fn DeletePrinterKeyA( + hPrinter: HANDLE, + pKeyName: LPCSTR, + ) -> DWORD; + pub fn DeletePrinterKeyW( + hPrinter: HANDLE, + pKeyName: LPCWSTR, + ) -> DWORD; +} +pub const PRINTER_NOTIFY_TYPE: DWORD = 0x00; +pub const JOB_NOTIFY_TYPE: DWORD = 0x01; +pub const SERVER_NOTIFY_TYPE: DWORD = 0x02; +pub const PRINTER_NOTIFY_FIELD_SERVER_NAME: DWORD = 0x00; +pub const PRINTER_NOTIFY_FIELD_PRINTER_NAME: DWORD = 0x01; +pub const PRINTER_NOTIFY_FIELD_SHARE_NAME: DWORD = 0x02; +pub const PRINTER_NOTIFY_FIELD_PORT_NAME: DWORD = 0x03; +pub const PRINTER_NOTIFY_FIELD_DRIVER_NAME: DWORD = 0x04; +pub const PRINTER_NOTIFY_FIELD_COMMENT: DWORD = 0x05; +pub const PRINTER_NOTIFY_FIELD_LOCATION: DWORD = 0x06; +pub const PRINTER_NOTIFY_FIELD_DEVMODE: DWORD = 0x07; +pub const PRINTER_NOTIFY_FIELD_SEPFILE: DWORD = 0x08; +pub const PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR: DWORD = 0x09; +pub const PRINTER_NOTIFY_FIELD_PARAMETERS: DWORD = 0x0A; +pub const PRINTER_NOTIFY_FIELD_DATATYPE: DWORD = 0x0B; +pub const PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR: DWORD = 0x0C; +pub const PRINTER_NOTIFY_FIELD_ATTRIBUTES: DWORD = 0x0D; +pub const PRINTER_NOTIFY_FIELD_PRIORITY: DWORD = 0x0E; +pub const PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY: DWORD = 0x0F; +pub const PRINTER_NOTIFY_FIELD_START_TIME: DWORD = 0x10; +pub const PRINTER_NOTIFY_FIELD_UNTIL_TIME: DWORD = 0x11; +pub const PRINTER_NOTIFY_FIELD_STATUS: DWORD = 0x12; +pub const PRINTER_NOTIFY_FIELD_STATUS_STRING: DWORD = 0x13; +pub const PRINTER_NOTIFY_FIELD_CJOBS: DWORD = 0x14; +pub const PRINTER_NOTIFY_FIELD_AVERAGE_PPM: DWORD = 0x15; +pub const PRINTER_NOTIFY_FIELD_TOTAL_PAGES: DWORD = 0x16; +pub const PRINTER_NOTIFY_FIELD_PAGES_PRINTED: DWORD = 0x17; +pub const PRINTER_NOTIFY_FIELD_TOTAL_BYTES: DWORD = 0x18; +pub const PRINTER_NOTIFY_FIELD_BYTES_PRINTED: DWORD = 0x19; +pub const PRINTER_NOTIFY_FIELD_OBJECT_GUID: DWORD = 0x1A; +pub const PRINTER_NOTIFY_FIELD_FRIENDLY_NAME: DWORD = 0x1B; +pub const PRINTER_NOTIFY_FIELD_BRANCH_OFFICE_PRINTING: DWORD = 0x1C; +pub const JOB_NOTIFY_FIELD_PRINTER_NAME: DWORD = 0x00; +pub const JOB_NOTIFY_FIELD_MACHINE_NAME: DWORD = 0x01; +pub const JOB_NOTIFY_FIELD_PORT_NAME: DWORD = 0x02; +pub const JOB_NOTIFY_FIELD_USER_NAME: DWORD = 0x03; +pub const JOB_NOTIFY_FIELD_NOTIFY_NAME: DWORD = 0x04; +pub const JOB_NOTIFY_FIELD_DATATYPE: DWORD = 0x05; +pub const JOB_NOTIFY_FIELD_PRINT_PROCESSOR: DWORD = 0x06; +pub const JOB_NOTIFY_FIELD_PARAMETERS: DWORD = 0x07; +pub const JOB_NOTIFY_FIELD_DRIVER_NAME: DWORD = 0x08; +pub const JOB_NOTIFY_FIELD_DEVMODE: DWORD = 0x09; +pub const JOB_NOTIFY_FIELD_STATUS: DWORD = 0x0A; +pub const JOB_NOTIFY_FIELD_STATUS_STRING: DWORD = 0x0B; +pub const JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR: DWORD = 0x0C; +pub const JOB_NOTIFY_FIELD_DOCUMENT: DWORD = 0x0D; +pub const JOB_NOTIFY_FIELD_PRIORITY: DWORD = 0x0E; +pub const JOB_NOTIFY_FIELD_POSITION: DWORD = 0x0F; +pub const JOB_NOTIFY_FIELD_SUBMITTED: DWORD = 0x10; +pub const JOB_NOTIFY_FIELD_START_TIME: DWORD = 0x11; +pub const JOB_NOTIFY_FIELD_UNTIL_TIME: DWORD = 0x12; +pub const JOB_NOTIFY_FIELD_TIME: DWORD = 0x13; +pub const JOB_NOTIFY_FIELD_TOTAL_PAGES: DWORD = 0x14; +pub const JOB_NOTIFY_FIELD_PAGES_PRINTED: DWORD = 0x15; +pub const JOB_NOTIFY_FIELD_TOTAL_BYTES: DWORD = 0x16; +pub const JOB_NOTIFY_FIELD_BYTES_PRINTED: DWORD = 0x17; +pub const JOB_NOTIFY_FIELD_REMOTE_JOB_ID: DWORD = 0x18; +pub const SERVER_NOTIFY_FIELD_PRINT_DRIVER_ISOLATION_GROUP: DWORD = 0x00; +pub const PRINTER_NOTIFY_CATEGORY_ALL: DWORD = 0x001000; +pub const PRINTER_NOTIFY_CATEGORY_3D: DWORD = 0x002000; +STRUCT!{struct PRINTER_NOTIFY_OPTIONS_TYPE { + Type: WORD, + Reserved0: WORD, + Reserved1: DWORD, + Reserved2: DWORD, + Count: DWORD, + pFields: PWORD, +}} +pub type PPRINTER_NOTIFY_OPTIONS_TYPE = *mut PRINTER_NOTIFY_OPTIONS_TYPE; +pub type LPPRINTER_NOTIFY_OPTIONS_TYPE = *mut PRINTER_NOTIFY_OPTIONS_TYPE; +pub const PRINTER_NOTIFY_OPTIONS_REFRESH: DWORD = 0x01; +STRUCT!{struct PRINTER_NOTIFY_OPTIONS { + Version: DWORD, + Flags: DWORD, + Count: DWORD, + pTypes: PPRINTER_NOTIFY_OPTIONS_TYPE, +}} +pub type PPRINTER_NOTIFY_OPTIONS = *mut PRINTER_NOTIFY_OPTIONS; +pub type LPPRINTER_NOTIFY_OPTIONS = *mut PRINTER_NOTIFY_OPTIONS; +pub const PRINTER_NOTIFY_INFO_DISCARDED: DWORD = 0x01; +STRUCT!{struct PRINTER_NOTIFY_INFO_DATA_NotifyData_Data { + cbBuf: DWORD, + pBuf: LPVOID, +}} +UNION!{union PRINTER_NOTIFY_INFO_DATA_NotifyData { + [usize; 2], + adwData adwData_mut: [DWORD; 2], + Data Data_mut: PRINTER_NOTIFY_INFO_DATA_NotifyData_Data, +}} +STRUCT!{struct PRINTER_NOTIFY_INFO_DATA { + Type: WORD, + Field: WORD, + Reserved: DWORD, + Id: DWORD, + NotifyData: PRINTER_NOTIFY_INFO_DATA_NotifyData, +}} +pub type PPRINTER_NOTIFY_INFO_DATA = *mut PRINTER_NOTIFY_INFO_DATA; +pub type LPPRINTER_NOTIFY_INFO_DATA = *mut PRINTER_NOTIFY_INFO_DATA; +STRUCT!{struct PRINTER_NOTIFY_INFO { + Version: DWORD, + Flags: DWORD, + Count: DWORD, + aData: [PRINTER_NOTIFY_INFO_DATA; 1], +}} +pub type PPRINTER_NOTIFY_INFO = *mut PRINTER_NOTIFY_INFO; +pub type LPPRINTER_NOTIFY_INFO = *mut PRINTER_NOTIFY_INFO; +STRUCT!{struct BINARY_CONTAINER { + cbBuf: DWORD, + pData: LPBYTE, +}} +pub type PBINARY_CONTAINER = *mut BINARY_CONTAINER; +UNION!{union BIDI_DATA_u { + [usize; 2], + bData bData_mut: BOOL, + iData iData_mut: LONG, + sData sData_mut: LPWSTR, + fData fData_mut: FLOAT, + biData biData_mut: BINARY_CONTAINER, +}} +STRUCT!{struct BIDI_DATA { + dwBidiType: DWORD, + u: BIDI_DATA_u, +}} +pub type PBIDI_DATA = *mut BIDI_DATA; +pub type LPBIDI_DATA = *mut BIDI_DATA; +STRUCT!{struct BIDI_REQUEST_DATA { + dwReqNumber: DWORD, + pSchema: LPWSTR, + data: BIDI_DATA, +}} +pub type PBIDI_REQUEST_DATA = *mut BIDI_REQUEST_DATA; +pub type LPBIDI_REQUEST_DATA = *mut BIDI_REQUEST_DATA; +STRUCT!{struct BIDI_REQUEST_CONTAINER { + Version: DWORD, + Flags: DWORD, + Count: DWORD, + aData: [BIDI_REQUEST_DATA; 1], +}} +pub type PBIDI_REQUEST_CONTAINER = *mut BIDI_REQUEST_CONTAINER; +pub type LPBIDI_REQUEST_CONTAINER = *mut BIDI_REQUEST_CONTAINER; +STRUCT!{struct BIDI_RESPONSE_DATA { + dwResult: DWORD, + dwReqNumber: DWORD, + pSchema: LPWSTR, + data: BIDI_DATA, +}} +pub type PBIDI_RESPONSE_DATA = *mut BIDI_RESPONSE_DATA; +pub type LPBIDI_RESPONSE_DATA = *mut BIDI_RESPONSE_DATA; +STRUCT!{struct BIDI_RESPONSE_CONTAINER { + Version: DWORD, + Flags: DWORD, + Count: DWORD, + aData: [BIDI_RESPONSE_DATA; 1], +}} +pub type PBIDI_RESPONSE_CONTAINER = *mut BIDI_RESPONSE_CONTAINER; +pub type LPBIDI_RESPONSE_CONTAINER = *mut BIDI_RESPONSE_CONTAINER; +pub const BIDI_ACTION_ENUM_SCHEMA: &'static str = "EnumSchema"; +pub const BIDI_ACTION_GET: &'static str = "Get"; +pub const BIDI_ACTION_SET: &'static str = "Set"; +pub const BIDI_ACTION_GET_ALL: &'static str = "GetAll"; +pub const BIDI_ACTION_GET_WITH_ARGUMENT: &'static str = "GetWithArgument"; +ENUM!{enum BIDI_TYPE { + BIDI_NULL = 0, + BIDI_INT = 1, + BIDI_FLOAT = 2, + BIDI_BOOL = 3, + BIDI_STRING = 4, + BIDI_TEXT = 5, + BIDI_ENUM = 6, + BIDI_BLOB = 7, +}} +pub const BIDI_ACCESS_ADMINISTRATOR: DWORD = 0x1; +pub const BIDI_ACCESS_USER: DWORD = 0x2; +pub const ERROR_BIDI_STATUS_OK: DWORD = 0; +pub const ERROR_BIDI_NOT_SUPPORTED: DWORD = ERROR_NOT_SUPPORTED; +pub const ERROR_BIDI_ERROR_BASE: DWORD = 13000; +pub const ERROR_BIDI_STATUS_WARNING: DWORD = ERROR_BIDI_ERROR_BASE + 1; +pub const ERROR_BIDI_SCHEMA_READ_ONLY: DWORD = ERROR_BIDI_ERROR_BASE + 2; +pub const ERROR_BIDI_SERVER_OFFLINE: DWORD = ERROR_BIDI_ERROR_BASE + 3; +pub const ERROR_BIDI_DEVICE_OFFLINE: DWORD = ERROR_BIDI_ERROR_BASE + 4; +pub const ERROR_BIDI_SCHEMA_NOT_SUPPORTED: DWORD = ERROR_BIDI_ERROR_BASE + 5; +pub const ERROR_BIDI_SET_DIFFERENT_TYPE: DWORD = ERROR_BIDI_ERROR_BASE + 6; +pub const ERROR_BIDI_SET_MULTIPLE_SCHEMAPATH: DWORD = ERROR_BIDI_ERROR_BASE + 7; +pub const ERROR_BIDI_SET_INVALID_SCHEMAPATH: DWORD = ERROR_BIDI_ERROR_BASE + 8; +pub const ERROR_BIDI_SET_UNKNOWN_FAILURE: DWORD = ERROR_BIDI_ERROR_BASE + 9; +pub const ERROR_BIDI_SCHEMA_WRITE_ONLY: DWORD = ERROR_BIDI_ERROR_BASE + 10; +pub const ERROR_BIDI_GET_REQUIRES_ARGUMENT: DWORD = ERROR_BIDI_ERROR_BASE + 11; +pub const ERROR_BIDI_GET_ARGUMENT_NOT_SUPPORTED: DWORD = ERROR_BIDI_ERROR_BASE + 12; +pub const ERROR_BIDI_GET_MISSING_ARGUMENT: DWORD = ERROR_BIDI_ERROR_BASE + 13; +pub const ERROR_BIDI_DEVICE_CONFIG_UNCHANGED: DWORD = ERROR_BIDI_ERROR_BASE + 14; +pub const ERROR_BIDI_NO_LOCALIZED_RESOURCES: DWORD = ERROR_BIDI_ERROR_BASE + 15; +pub const ERROR_BIDI_NO_BIDI_SCHEMA_EXTENSIONS: DWORD = ERROR_BIDI_ERROR_BASE + 16; +pub const ERROR_BIDI_UNSUPPORTED_CLIENT_LANGUAGE: DWORD = ERROR_BIDI_ERROR_BASE + 17; +pub const ERROR_BIDI_UNSUPPORTED_RESOURCE_FORMAT: DWORD = ERROR_BIDI_ERROR_BASE + 18; +extern "system" { + pub fn WaitForPrinterChange( + hPrinter: HANDLE, + Flags: DWORD, + ) -> DWORD; + pub fn FindFirstPrinterChangeNotification( + hPrinter: HANDLE, + fdwFilter: DWORD, + fdwOptions: DWORD, + pPrinterNotifyOptions: LPVOID, + ) -> HANDLE; + pub fn FindNextPrinterChangeNotification( + hChange: HANDLE, + pdwChange: PDWORD, + pPrinterNotifyOptions: LPVOID, + ppPrinterNotifyInfo: *mut LPVOID, + ) -> BOOL; + pub fn FreePrinterNotifyInfo( + pPrinterNotifyInfo: PPRINTER_NOTIFY_INFO, + ) -> BOOL; + pub fn FindClosePrinterChangeNotification( + hChange: HANDLE, + ) -> BOOL; +} +pub const PRINTER_CHANGE_ADD_PRINTER: DWORD = 0x00000001; +pub const PRINTER_CHANGE_SET_PRINTER: DWORD = 0x00000002; +pub const PRINTER_CHANGE_DELETE_PRINTER: DWORD = 0x00000004; +pub const PRINTER_CHANGE_FAILED_CONNECTION_PRINTER: DWORD = 0x00000008; +pub const PRINTER_CHANGE_PRINTER: DWORD = 0x000000FF; +pub const PRINTER_CHANGE_ADD_JOB: DWORD = 0x00000100; +pub const PRINTER_CHANGE_SET_JOB: DWORD = 0x00000200; +pub const PRINTER_CHANGE_DELETE_JOB: DWORD = 0x00000400; +pub const PRINTER_CHANGE_WRITE_JOB: DWORD = 0x00000800; +pub const PRINTER_CHANGE_JOB: DWORD = 0x0000FF00; +pub const PRINTER_CHANGE_ADD_FORM: DWORD = 0x00010000; +pub const PRINTER_CHANGE_SET_FORM: DWORD = 0x00020000; +pub const PRINTER_CHANGE_DELETE_FORM: DWORD = 0x00040000; +pub const PRINTER_CHANGE_FORM: DWORD = 0x00070000; +pub const PRINTER_CHANGE_ADD_PORT: DWORD = 0x00100000; +pub const PRINTER_CHANGE_CONFIGURE_PORT: DWORD = 0x00200000; +pub const PRINTER_CHANGE_DELETE_PORT: DWORD = 0x00400000; +pub const PRINTER_CHANGE_PORT: DWORD = 0x00700000; +pub const PRINTER_CHANGE_ADD_PRINT_PROCESSOR: DWORD = 0x01000000; +pub const PRINTER_CHANGE_DELETE_PRINT_PROCESSOR: DWORD = 0x04000000; +pub const PRINTER_CHANGE_PRINT_PROCESSOR: DWORD = 0x07000000; +pub const PRINTER_CHANGE_SERVER: DWORD = 0x08000000; +pub const PRINTER_CHANGE_ADD_PRINTER_DRIVER: DWORD = 0x10000000; +pub const PRINTER_CHANGE_SET_PRINTER_DRIVER: DWORD = 0x20000000; +pub const PRINTER_CHANGE_DELETE_PRINTER_DRIVER: DWORD = 0x40000000; +pub const PRINTER_CHANGE_PRINTER_DRIVER: DWORD = 0x70000000; +pub const PRINTER_CHANGE_TIMEOUT: DWORD = 0x80000000; +pub const PRINTER_CHANGE_ALL: DWORD = 0x7F77FFFF; +extern "system" { + pub fn PrinterMessageBoxA( + hPrinter: HANDLE, + Error: DWORD, + hWnd: HWND, + pText: LPSTR, + pCaption: LPSTR, + dwType: DWORD, + ) -> DWORD; + pub fn PrinterMessageBoxW( + hPrinter: HANDLE, + Error: DWORD, + hWnd: HWND, + pText: LPWSTR, + pCaption: LPWSTR, + dwType: DWORD, + ) -> DWORD; +} +pub const PRINTER_ERROR_INFORMATION: DWORD = 0x80000000; +pub const PRINTER_ERROR_WARNING: DWORD = 0x40000000; +pub const PRINTER_ERROR_SEVERE: DWORD = 0x20000000; +pub const PRINTER_ERROR_OUTOFPAPER: DWORD = 0x00000001; +pub const PRINTER_ERROR_JAM: DWORD = 0x00000002; +pub const PRINTER_ERROR_OUTOFTONER: DWORD = 0x00000004; +extern "system" { + pub fn ClosePrinter( + hPrinter: HANDLE, + ) -> BOOL; + pub fn AddFormA( + hPrinter: HANDLE, + Level: DWORD, + pForm: LPBYTE, + ) -> BOOL; + pub fn AddFormW( + hPrinter: HANDLE, + Level: DWORD, + pForm: LPBYTE, + ) -> BOOL; + pub fn DeleteFormA( + hPrinter: HANDLE, + pFormName: LPSTR, + ) -> BOOL; + pub fn DeleteFormW( + hPrinter: HANDLE, + pFormName: LPWSTR, + ) -> BOOL; + pub fn GetFormA( + hPrinter: HANDLE, + pFormName: LPSTR, + Level: DWORD, + pForm: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetFormW( + hPrinter: HANDLE, + pFormName: LPWSTR, + Level: DWORD, + pForm: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn SetFormA( + hPrinter: HANDLE, + pFormName: LPSTR, + Level: DWORD, + pForm: LPBYTE, + ) -> BOOL; + pub fn SetFormW( + hPrinter: HANDLE, + pFormName: LPWSTR, + Level: DWORD, + pForm: LPBYTE, + ) -> BOOL; + pub fn EnumFormsA( + hPrinter: HANDLE, + Level: DWORD, + pForm: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumFormsW( + hPrinter: HANDLE, + Level: DWORD, + pForm: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumMonitorsA( + pName: LPSTR, + Level: DWORD, + pMonitor: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumMonitorsW( + pName: LPWSTR, + Level: DWORD, + pMonitor: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn AddMonitorA( + pName: LPSTR, + Level: DWORD, + pMonitors: LPBYTE, + ) -> BOOL; + pub fn AddMonitorW( + pName: LPWSTR, + Level: DWORD, + pMonitors: LPBYTE, + ) -> BOOL; + pub fn DeleteMonitorA( + pName: LPSTR, + pEnvironment: LPSTR, + pMonitorName: LPSTR, + ) -> BOOL; + pub fn DeleteMonitorW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pMonitorName: LPWSTR, + ) -> BOOL; + pub fn EnumPortsA( + pName: LPSTR, + Level: DWORD, + pPort: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn EnumPortsW( + pName: LPWSTR, + Level: DWORD, + pPort: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + pcReturned: LPDWORD, + ) -> BOOL; + pub fn AddPortA( + pName: LPSTR, + hWnd: HWND, + pMonitorName: LPSTR, + ) -> BOOL; + pub fn AddPortW( + pName: LPWSTR, + hWnd: HWND, + pMonitorName: LPWSTR, + ) -> BOOL; + pub fn ConfigurePortA( + pName: LPSTR, + hWnd: HWND, + pPortName: LPSTR, + ) -> BOOL; + pub fn ConfigurePortW( + pName: LPWSTR, + hWnd: HWND, + pPortName: LPWSTR, + ) -> BOOL; + pub fn DeletePortA( + pName: LPSTR, + hWnd: HWND, + pPortName: LPSTR, + ) -> BOOL; + pub fn DeletePortW( + pName: LPWSTR, + hWnd: HWND, + pPortName: LPWSTR, + ) -> BOOL; + pub fn XcvDataW( + hXcv: HANDLE, + pszDataName: PCWSTR, + pInputData: PBYTE, + cbInputData: DWORD, + pOutputData: PBYTE, + cbOutputData: DWORD, + pcbOutputNeeded: PDWORD, + pdwStatus: PDWORD, + ) -> BOOL; + pub fn GetDefaultPrinterA( + pszBuffer: LPSTR, + pcchBuffer: LPDWORD, + ) -> BOOL; + pub fn GetDefaultPrinterW( + pszBuffer: LPWSTR, + pcchBuffer: LPDWORD, + ) -> BOOL; + pub fn SetDefaultPrinterA( + pszPrinter: LPCSTR, + ) -> BOOL; + pub fn SetDefaultPrinterW( + pszPrinter: LPCWSTR, + ) -> BOOL; + pub fn SetPortA( + pName: LPSTR, + pPortName: LPSTR, + dwLevel: DWORD, + pPortInfo: LPBYTE, + ) -> BOOL; + pub fn SetPortW(pName: LPWSTR, + pPortName: LPWSTR, + dwLevel: DWORD, + pPortInfo: LPBYTE, + ) -> BOOL; + pub fn AddPrinterConnectionA( + pName: LPSTR, + ) -> BOOL; + pub fn AddPrinterConnectionW( + pName: LPWSTR, + ) -> BOOL; + pub fn DeletePrinterConnectionA( + pName: LPSTR, + ) -> BOOL; + pub fn DeletePrinterConnectionW( + pName: LPWSTR, + ) -> BOOL; + pub fn ConnectToPrinterDlg( + hwnd: HWND, + Flags: DWORD, + ) -> HANDLE; +} +STRUCT!{struct PROVIDOR_INFO_1A { + pName: LPSTR, + pEnvironment: LPSTR, + pDLLName: LPSTR, +}} +pub type PPROVIDOR_INFO_1A = *mut PROVIDOR_INFO_1A; +pub type LPPROVIDOR_INFO_1A = *mut PROVIDOR_INFO_1A; +STRUCT!{struct PROVIDOR_INFO_1W { + pName: LPWSTR, + pEnvironment: LPWSTR, + pDLLName: LPWSTR, +}} +pub type PPROVIDOR_INFO_1W = *mut PROVIDOR_INFO_1W; +pub type LPPROVIDOR_INFO_1W = *mut PROVIDOR_INFO_1W; +STRUCT!{struct PROVIDOR_INFO_2A { + pOrder: LPSTR, +}} +pub type PPROVIDOR_INFO_2A = *mut PROVIDOR_INFO_2A; +pub type LPPROVIDOR_INFO_2A = *mut PROVIDOR_INFO_2A; +STRUCT!{struct PROVIDOR_INFO_2W { + pOrder: LPWSTR, +}} +pub type PPROVIDOR_INFO_2W = *mut PROVIDOR_INFO_2W; +pub type LPPROVIDOR_INFO_2W = *mut PROVIDOR_INFO_2W; +extern "system" { + pub fn AddPrintProvidorA( + pName: LPSTR, + Level: DWORD, + pProvidorInfo: LPBYTE, + ) -> BOOL; + pub fn AddPrintProvidorW( + pName: LPWSTR, + Level: DWORD, + pProvidorInfo: LPBYTE, + ) -> BOOL; + pub fn DeletePrintProvidorA( + pName: LPSTR, + pEnvironment: LPSTR, + pPrintProvidorName: LPSTR, + ) -> BOOL; + pub fn DeletePrintProvidorW( + pName: LPWSTR, + pEnvironment: LPWSTR, + pPrintProvidorName: LPWSTR, + ) -> BOOL; + pub fn IsValidDevmodeA( + pDevmode: PDEVMODEA, + DevmodeSize: size_t, + ) -> BOOL; + pub fn IsValidDevmodeW( + pDevmode: PDEVMODEW, + DevmodeSize: size_t, + ) -> BOOL; +} +pub const SPLREG_DEFAULT_SPOOL_DIRECTORY: &'static str = "DefaultSpoolDirectory"; +pub const SPLREG_PORT_THREAD_PRIORITY_DEFAULT: &'static str = "PortThreadPriorityDefault"; +pub const SPLREG_PORT_THREAD_PRIORITY: &'static str = "PortThreadPriority"; +pub const SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT: &'static str + = "SchedulerThreadPriorityDefault"; +pub const SPLREG_SCHEDULER_THREAD_PRIORITY: &'static str = "SchedulerThreadPriority"; +pub const SPLREG_BEEP_ENABLED: &'static str = "BeepEnabled"; +pub const SPLREG_NET_POPUP: &'static str = "NetPopup"; +pub const SPLREG_RETRY_POPUP: &'static str = "RetryPopup"; +pub const SPLREG_NET_POPUP_TO_COMPUTER: &'static str = "NetPopupToComputer"; +pub const SPLREG_EVENT_LOG: &'static str = "EventLog"; +pub const SPLREG_MAJOR_VERSION: &'static str = "MajorVersion"; +pub const SPLREG_MINOR_VERSION: &'static str = "MinorVersion"; +pub const SPLREG_ARCHITECTURE: &'static str = "Architecture"; +pub const SPLREG_OS_VERSION: &'static str = "OSVersion"; +pub const SPLREG_OS_VERSIONEX: &'static str = "OSVersionEx"; +pub const SPLREG_DS_PRESENT: &'static str = "DsPresent"; +pub const SPLREG_DS_PRESENT_FOR_USER: &'static str = "DsPresentForUser"; +pub const SPLREG_REMOTE_FAX: &'static str = "RemoteFax"; +pub const SPLREG_RESTART_JOB_ON_POOL_ERROR: &'static str = "RestartJobOnPoolError"; +pub const SPLREG_RESTART_JOB_ON_POOL_ENABLED: &'static str = "RestartJobOnPoolEnabled"; +pub const SPLREG_DNS_MACHINE_NAME: &'static str = "DNSMachineName"; +pub const SPLREG_ALLOW_USER_MANAGEFORMS: &'static str = "AllowUserManageForms"; +pub const SPLREG_WEBSHAREMGMT: &'static str = "WebShareMgmt"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_GROUPS_SEPARATOR: &'static str = "\\"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_GROUPS: &'static str = "PrintDriverIsolationGroups"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_TIME_BEFORE_RECYCLE: &'static str + = "PrintDriverIsolationTimeBeforeRecycle"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_MAX_OBJECTS_BEFORE_RECYCLE: &'static str + = "PrintDriverIsolationMaxobjsBeforeRecycle"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_IDLE_TIMEOUT: &'static str + = "PrintDriverIsolationIdleTimeout"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_EXECUTION_POLICY: &'static str + = "PrintDriverIsolationExecutionPolicy"; +pub const SPLREG_PRINT_DRIVER_ISOLATION_OVERRIDE_POLICY: &'static str + = "PrintDriverIsolationOverrideCompat"; +pub const SPLREG_PRINT_QUEUE_V4_DRIVER_DIRECTORY: &'static str = "PrintQueueV4DriverDirectory"; +pub const SERVER_ACCESS_ADMINISTER: DWORD = 0x00000001; +pub const SERVER_ACCESS_ENUMERATE: DWORD = 0x00000002; +pub const PRINTER_ACCESS_ADMINISTER: DWORD = 0x00000004; +pub const PRINTER_ACCESS_USE: DWORD = 0x00000008; +pub const JOB_ACCESS_ADMINISTER: DWORD = 0x00000010; +pub const JOB_ACCESS_READ: DWORD = 0x00000020; +pub const PRINTER_ACCESS_MANAGE_LIMITED: DWORD = 0x00000040; +pub const SERVER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER + | SERVER_ACCESS_ENUMERATE; +pub const SERVER_READ: DWORD = STANDARD_RIGHTS_READ | SERVER_ACCESS_ENUMERATE; +pub const SERVER_WRITE: DWORD = STANDARD_RIGHTS_WRITE | SERVER_ACCESS_ADMINISTER + | SERVER_ACCESS_ENUMERATE; +pub const SERVER_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | SERVER_ACCESS_ENUMERATE; +pub const PRINTER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER + | PRINTER_ACCESS_USE; +pub const PRINTER_READ: DWORD = STANDARD_RIGHTS_READ | PRINTER_ACCESS_USE; +pub const PRINTER_WRITE: DWORD = STANDARD_RIGHTS_WRITE | PRINTER_ACCESS_USE; +pub const PRINTER_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | PRINTER_ACCESS_USE; +pub const JOB_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | JOB_ACCESS_ADMINISTER + | JOB_ACCESS_READ; +pub const JOB_READ: DWORD = STANDARD_RIGHTS_READ | JOB_ACCESS_READ; +pub const JOB_WRITE: DWORD = STANDARD_RIGHTS_WRITE | JOB_ACCESS_ADMINISTER; +pub const JOB_EXECUTE: DWORD = STANDARD_RIGHTS_EXECUTE | JOB_ACCESS_ADMINISTER; +pub const SPLDS_SPOOLER_KEY: &'static str = "DsSpooler"; +pub const SPLDS_DRIVER_KEY: &'static str = "DsDriver"; +pub const SPLDS_USER_KEY: &'static str = "DsUser"; +pub const SPLDS_ASSET_NUMBER: &'static str = "assetNumber"; +pub const SPLDS_BYTES_PER_MINUTE: &'static str = "bytesPerMinute"; +pub const SPLDS_DESCRIPTION: &'static str = "description"; +pub const SPLDS_DRIVER_NAME: &'static str = "driverName"; +pub const SPLDS_DRIVER_VERSION: &'static str = "driverVersion"; +pub const SPLDS_LOCATION: &'static str = "location"; +pub const SPLDS_PORT_NAME: &'static str = "portName"; +pub const SPLDS_PRINT_ATTRIBUTES: &'static str = "printAttributes"; +pub const SPLDS_PRINT_BIN_NAMES: &'static str = "printBinNames"; +pub const SPLDS_PRINT_COLLATE: &'static str = "printCollate"; +pub const SPLDS_PRINT_COLOR: &'static str = "printColor"; +pub const SPLDS_PRINT_DUPLEX_SUPPORTED: &'static str = "printDuplexSupported"; +pub const SPLDS_PRINT_END_TIME: &'static str = "printEndTime"; +pub const SPLDS_PRINTER_CLASS: &'static str = "printQueue"; +pub const SPLDS_PRINTER_NAME: &'static str = "printerName"; +pub const SPLDS_PRINT_KEEP_PRINTED_JOBS: &'static str = "printKeepPrintedJobs"; +pub const SPLDS_PRINT_LANGUAGE: &'static str = "printLanguage"; +pub const SPLDS_PRINT_MAC_ADDRESS: &'static str = "printMACAddress"; +pub const SPLDS_PRINT_MAX_X_EXTENT: &'static str = "printMaxXExtent"; +pub const SPLDS_PRINT_MAX_Y_EXTENT: &'static str = "printMaxYExtent"; +pub const SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED: &'static str = "printMaxResolutionSupported"; +pub const SPLDS_PRINT_MEDIA_READY: &'static str = "printMediaReady"; +pub const SPLDS_PRINT_MEDIA_SUPPORTED: &'static str = "printMediaSupported"; +pub const SPLDS_PRINT_MEMORY: &'static str = "printMemory"; +pub const SPLDS_PRINT_MIN_X_EXTENT: &'static str = "printMinXExtent"; +pub const SPLDS_PRINT_MIN_Y_EXTENT: &'static str = "printMinYExtent"; +pub const SPLDS_PRINT_NETWORK_ADDRESS: &'static str = "printNetworkAddress"; +pub const SPLDS_PRINT_NOTIFY: &'static str = "printNotify"; +pub const SPLDS_PRINT_NUMBER_UP: &'static str = "printNumberUp"; +pub const SPLDS_PRINT_ORIENTATIONS_SUPPORTED: &'static str = "printOrientationsSupported"; +pub const SPLDS_PRINT_OWNER: &'static str = "printOwner"; +pub const SPLDS_PRINT_PAGES_PER_MINUTE: &'static str = "printPagesPerMinute"; +pub const SPLDS_PRINT_RATE: &'static str = "printRate"; +pub const SPLDS_PRINT_RATE_UNIT: &'static str = "printRateUnit"; +pub const SPLDS_PRINT_SEPARATOR_FILE: &'static str = "printSeparatorFile"; +pub const SPLDS_PRINT_SHARE_NAME: &'static str = "printShareName"; +pub const SPLDS_PRINT_SPOOLING: &'static str = "printSpooling"; +pub const SPLDS_PRINT_STAPLING_SUPPORTED: &'static str = "printStaplingSupported"; +pub const SPLDS_PRINT_START_TIME: &'static str = "printStartTime"; +pub const SPLDS_PRINT_STATUS: &'static str = "printStatus"; +pub const SPLDS_PRIORITY: &'static str = "priority"; +pub const SPLDS_SERVER_NAME: &'static str = "serverName"; +pub const SPLDS_SHORT_SERVER_NAME: &'static str = "shortServerName"; +pub const SPLDS_UNC_NAME: &'static str = "uNCName"; +pub const SPLDS_URL: &'static str = "url"; +pub const SPLDS_FLAGS: &'static str = "flags"; +pub const SPLDS_VERSION_NUMBER: &'static str = "versionNumber"; +pub const SPLDS_PRINTER_NAME_ALIASES: &'static str = "printerNameAliases"; +pub const SPLDS_PRINTER_LOCATIONS: &'static str = "printerLocations"; +pub const SPLDS_PRINTER_MODEL: &'static str = "printerModel"; +ENUM!{enum PRINTER_OPTION_FLAGS { + PRINTER_OPTION_NO_CACHE = 1 << 0, + PRINTER_OPTION_CACHE = 1 << 1, + PRINTER_OPTION_CLIENT_CHANGE = 1 << 2, + PRINTER_OPTION_NO_CLIENT_DATA = 1 << 3, +}} +STRUCT!{struct PRINTER_OPTIONSA { + cbSize: UINT, + dwFlags: DWORD, +}} +pub type PPRINTER_OPTIONSA = *mut PRINTER_OPTIONSA; +pub type LPPRINTER_OPTIONSA = *mut PRINTER_OPTIONSA; +STRUCT!{struct PRINTER_OPTIONSW { + cbSize: UINT, + dwFlags: DWORD, +}} +pub type PPRINTER_OPTIONSW = *mut PRINTER_OPTIONSW; +pub type LPPRINTER_OPTIONSW = *mut PRINTER_OPTIONSW; +extern "system" { + pub fn OpenPrinter2A( + pPrinterName: LPCSTR, + phPrinter: LPHANDLE, + pDefault: PPRINTER_DEFAULTSA, + pOptions: PPRINTER_OPTIONSA, + ) -> BOOL; + pub fn OpenPrinter2W( + pPrinterName: LPCWSTR, + phPrinter: LPHANDLE, + pDefault: PPRINTER_DEFAULTSW, + pOptions: PPRINTER_OPTIONSW, + ) -> BOOL; +} +pub const PRINTER_CONNECTION_MISMATCH: DWORD = 0x00000020; +pub const PRINTER_CONNECTION_NO_UI: DWORD = 0x00000040; +STRUCT!{struct PRINTER_CONNECTION_INFO_1A { + dwFlags: DWORD, + pszDriverName: LPSTR, +}} +pub type PPRINTER_CONNECTION_INFO_1A = *mut PRINTER_CONNECTION_INFO_1A; +pub type LPPRINTER_CONNECTION_INFO_1A = *mut PRINTER_CONNECTION_INFO_1A; +STRUCT!{struct PRINTER_CONNECTION_INFO_1W { + dwFlags: DWORD, + pszDriverName: LPWSTR, +}} +pub type PPRINTER_CONNECTION_INFO_1W = *mut PRINTER_CONNECTION_INFO_1W; +pub type LPPRINTER_CONNECTION_INFO_1W = *mut PRINTER_CONNECTION_INFO_1W; +extern "system" { + pub fn AddPrinterConnection2A( + hWnd: HWND, + pszName: LPCSTR, + dwLevel: DWORD, + pConnectionInfo: PVOID, + ) -> BOOL; + pub fn AddPrinterConnection2W( + hWnd: HWND, + pszName: LPCWSTR, + dwLevel: DWORD, + pConnectionInfo: PVOID, + ) -> BOOL; +} +pub const IPDFP_COPY_ALL_FILES: DWORD = 0x00000001; +extern "system" { + pub fn InstallPrinterDriverFromPackageA( + pszServer: LPCSTR, + pszInfPath: LPCSTR, + pszDriverName: LPCSTR, + pszEnvironment: LPCSTR, + dwFlags: DWORD, + ) -> HRESULT; + pub fn InstallPrinterDriverFromPackageW( + pszServer: LPCWSTR, + pszInfPath: LPCWSTR, + pszDriverName: LPCWSTR, + pszEnvironment: LPCWSTR, + dwFlags: DWORD, + ) -> HRESULT; +} +pub const UPDP_SILENT_UPLOAD: DWORD = 0x00000001; +pub const UPDP_UPLOAD_ALWAYS: DWORD = 0x00000002; +pub const UPDP_CHECK_DRIVERSTORE: DWORD = 0x00000004; +extern "system" { + pub fn UploadPrinterDriverPackageA( + pszServer: LPCSTR, + pszInfPath: LPCSTR, + pszEnvironment: LPCSTR, + dwFlags: DWORD, + hwnd: HWND, + pszDestInfPath: LPSTR, + pcchDestInfPath: PULONG, + ) -> HRESULT; + pub fn UploadPrinterDriverPackageW( + pszServer: LPCWSTR, + pszInfPath: LPCWSTR, + pszEnvironment: LPCWSTR, + dwFlags: DWORD, + hwnd: HWND, + pszDestInfPath: LPWSTR, + pcchDestInfPath: PULONG, + ) -> HRESULT; +} +STRUCT!{struct CORE_PRINTER_DRIVERA { + CoreDriverGUID: GUID, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + szPackageID: [CHAR; MAX_PATH], +}} +pub type PCORE_PRINTER_DRIVERA = *mut CORE_PRINTER_DRIVERA; +STRUCT!{struct CORE_PRINTER_DRIVERW { + CoreDriverGUID: GUID, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + szPackageID: [WCHAR; MAX_PATH], +}} +pub type PCORE_PRINTER_DRIVERW = *mut CORE_PRINTER_DRIVERW; +extern "system" { + pub fn GetCorePrinterDriversA( + pszServer: LPCSTR, + pszEnvironment: LPCSTR, + pszzCoreDriverDependencies: LPCSTR, + cCorePrinterDrivers: DWORD, + pCorePrinterDrivers: PCORE_PRINTER_DRIVERA, + ) -> HRESULT; + pub fn GetCorePrinterDriversW( + pszServer: LPCWSTR, + pszEnvironment: LPCWSTR, + pszzCoreDriverDependencies: LPCWSTR, + cCorePrinterDrivers: DWORD, + pCorePrinterDrivers: PCORE_PRINTER_DRIVERW, + ) -> HRESULT; + pub fn CorePrinterDriverInstalledA( + pszServer: LPCSTR, + pszEnvironment: LPCSTR, + CoreDriverGUID: GUID, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pbDriverInstalled: *mut BOOL, + ) -> HRESULT; + pub fn CorePrinterDriverInstalledW( + pszServer: LPCWSTR, + pszEnvironment: LPCWSTR, + CoreDriverGUID: GUID, + ftDriverDate: FILETIME, + dwlDriverVersion: DWORDLONG, + pbDriverInstalled: *mut BOOL, + ) -> HRESULT; + pub fn GetPrinterDriverPackagePathA( + pszServer: LPCSTR, + pszEnvironment: LPCSTR, + pszLanguage: LPCSTR, + pszPackageID: LPCSTR, + pszDriverPackageCab: LPSTR, + cchDriverPackageCab: DWORD, + pcchRequiredSize: LPDWORD, + ) -> HRESULT; + pub fn GetPrinterDriverPackagePathW( + pszServer: LPCWSTR, + pszEnvironment: LPCWSTR, + pszLanguage: LPCWSTR, + pszPackageID: LPCWSTR, + pszDriverPackageCab: LPWSTR, + cchDriverPackageCab: DWORD, + pcchRequiredSize: LPDWORD, + ) -> HRESULT; + pub fn DeletePrinterDriverPackageA( + pszServer: LPCSTR, + pszInfPath: LPCSTR, + pszEnvironment: LPCSTR, + ) -> HRESULT; + pub fn DeletePrinterDriverPackageW( + pszServer: LPCWSTR, + pszInfPath: LPCWSTR, + pszEnvironment: LPCWSTR, + ) -> HRESULT; +} +ENUM!{enum EPrintPropertyType { + kPropertyTypeString = 1, + kPropertyTypeInt32, + kPropertyTypeInt64, + kPropertyTypeByte, + kPropertyTypeTime, + kPropertyTypeDevMode, + kPropertyTypeSD, + kPropertyTypeNotificationReply, + kPropertyTypeNotificationOptions, + kPropertyTypeBuffer, +}} +ENUM!{enum EPrintXPSJobProgress { + kAddingDocumentSequence = 0, + kDocumentSequenceAdded = 1, + kAddingFixedDocument = 2, + kFixedDocumentAdded = 3, + kAddingFixedPage = 4, + kFixedPageAdded = 5, + kResourceAdded = 6, + kFontAdded = 7, + kImageAdded = 8, + kXpsDocumentCommitted = 9, +}} +ENUM!{enum EPrintXPSJobOperation { + kJobProduction = 1, + kJobConsumption, +}} +STRUCT!{struct PrintPropertyValue_value_propertyBlob { + cbBuf: DWORD, + pBuf: LPVOID, +}} +UNION!{union PrintPropertyValue_value { + [u64; 1] [u64; 2], + propertyByte propertyByte_mut: BYTE, + propertyString propertyString_mut: PWSTR, + propertyInt32 propertyInt32_mut: LONG, + propertyInt64 propertyInt64_mut: LONGLONG, + propertyBlob propertyBlob_mut: PrintPropertyValue_value_propertyBlob, +}} +STRUCT!{struct PrintPropertyValue { + ePropertyType: EPrintPropertyType, + value: PrintPropertyValue_value, +}} +STRUCT!{struct PrintNamedProperty { + propertyName: *mut WCHAR, + propertyValue: PrintPropertyValue, +}} +STRUCT!{struct PrintPropertiesCollection { + numberOfProperties: ULONG, + propertiesCollection: *mut PrintNamedProperty, +}} +extern "system" { + pub fn ReportJobProcessingProgress( + printerHandle: HANDLE, + jobId: ULONG, + jobOperation: EPrintXPSJobOperation, + jobProgress: EPrintXPSJobProgress, + ) -> HRESULT; + pub fn GetPrinterDriver2A( + hWnd: HWND, + hPrinter: HANDLE, + pEnvironment: LPSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; + pub fn GetPrinterDriver2W( + hWnd: HWND, + hPrinter: HANDLE, + pEnvironment: LPWSTR, + Level: DWORD, + pDriverInfo: LPBYTE, + cbBuf: DWORD, + pcbNeeded: LPDWORD, + ) -> BOOL; +} +ENUM!{enum PRINT_EXECUTION_CONTEXT { + PRINT_EXECUTION_CONTEXT_APPLICATION = 0, + PRINT_EXECUTION_CONTEXT_SPOOLER_SERVICE = 1, + PRINT_EXECUTION_CONTEXT_SPOOLER_ISOLATION_HOST = 2, + PRINT_EXECUTION_CONTEXT_FILTER_PIPELINE = 3, + PRINT_EXECUTION_CONTEXT_WOW64 = 4, +}} +STRUCT!{struct PRINT_EXECUTION_DATA { + context: PRINT_EXECUTION_CONTEXT, + clientAppPID: DWORD, +}} +extern "system" { + pub fn GetPrintExecutionData( + pData: *mut PRINT_EXECUTION_DATA, + ) -> BOOL; + pub fn GetJobNamedPropertyValue( + hPrinter: HANDLE, + JobId: DWORD, + pszName: PCWSTR, + pValue: *mut PrintPropertyValue, + ) -> DWORD; + pub fn FreePrintPropertyValue( + pValue: *mut PrintPropertyValue, + ); + pub fn FreePrintNamedPropertyArray( + cProperties: DWORD, + ppProperties: *mut *mut PrintNamedProperty, + ); + pub fn SetJobNamedProperty( + hPrinter: HANDLE, + JobId: DWORD, + pProperty: *const PrintNamedProperty, + ) -> DWORD; + pub fn DeleteJobNamedProperty( + hPrinter: HANDLE, + JobId: DWORD, + pszName: PCWSTR, + ) -> DWORD; + pub fn EnumJobNamedProperties( + hPrinter: HANDLE, + JobId: DWORD, + pcProperties: *mut DWORD, + ppProperties: *mut *mut PrintNamedProperty, + ) -> DWORD; + pub fn GetPrintOutputInfo( + hWnd: HWND, + pszPrinter: PCWSTR, + phFile: *mut HANDLE, + ppszOutputFile: *mut PWSTR, + ) -> HRESULT; +} +pub const MS_PRINT_JOB_OUTPUT_FILE: &'static str = "MsPrintJobOutputFile"; diff --git a/winapi/src/um/winsvc.rs b/winapi/src/um/winsvc.rs new file mode 100644 index 000000000..702164ccd --- /dev/null +++ b/winapi/src/um/winsvc.rs @@ -0,0 +1,665 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Header file for the Service Control Manager +use shared::minwindef::{BOOL, DWORD, LPBYTE, LPDWORD, LPVOID}; +use um::winnt::{ + HANDLE, LPCSTR, LPCWSTR, LPSTR, LPWSTR, PSECURITY_DESCRIPTOR, PVOID, + SECURITY_INFORMATION, STANDARD_RIGHTS_REQUIRED +}; +pub const SERVICE_NO_CHANGE: DWORD = 0xffffffff; +pub const SERVICE_ACTIVE: DWORD = 0x00000001; +pub const SERVICE_INACTIVE: DWORD = 0x00000002; +pub const SERVICE_STATE_ALL: DWORD = SERVICE_ACTIVE | SERVICE_INACTIVE; +pub const SERVICE_CONTROL_STOP: DWORD = 0x00000001; +pub const SERVICE_CONTROL_PAUSE: DWORD = 0x00000002; +pub const SERVICE_CONTROL_CONTINUE: DWORD = 0x00000003; +pub const SERVICE_CONTROL_INTERROGATE: DWORD = 0x00000004; +pub const SERVICE_CONTROL_SHUTDOWN: DWORD = 0x00000005; +pub const SERVICE_CONTROL_PARAMCHANGE: DWORD = 0x00000006; +pub const SERVICE_CONTROL_NETBINDADD: DWORD = 0x00000007; +pub const SERVICE_CONTROL_NETBINDREMOVE: DWORD = 0x00000008; +pub const SERVICE_CONTROL_NETBINDENABLE: DWORD = 0x00000009; +pub const SERVICE_CONTROL_NETBINDDISABLE: DWORD = 0x0000000A; +pub const SERVICE_CONTROL_DEVICEEVENT: DWORD = 0x0000000B; +pub const SERVICE_CONTROL_HARDWAREPROFILECHANGE: DWORD = 0x0000000C; +pub const SERVICE_CONTROL_POWEREVENT: DWORD = 0x0000000D; +pub const SERVICE_CONTROL_SESSIONCHANGE: DWORD = 0x0000000E; +pub const SERVICE_CONTROL_PRESHUTDOWN: DWORD = 0x0000000F; +pub const SERVICE_CONTROL_TIMECHANGE: DWORD = 0x00000010; +pub const SERVICE_CONTROL_TRIGGEREVENT: DWORD = 0x00000020; +pub const SERVICE_STOPPED: DWORD = 0x00000001; +pub const SERVICE_START_PENDING: DWORD = 0x00000002; +pub const SERVICE_STOP_PENDING: DWORD = 0x00000003; +pub const SERVICE_RUNNING: DWORD = 0x00000004; +pub const SERVICE_CONTINUE_PENDING: DWORD = 0x00000005; +pub const SERVICE_PAUSE_PENDING: DWORD = 0x00000006; +pub const SERVICE_PAUSED: DWORD = 0x00000007; +pub const SERVICE_ACCEPT_STOP: DWORD = 0x00000001; +pub const SERVICE_ACCEPT_PAUSE_CONTINUE: DWORD = 0x00000002; +pub const SERVICE_ACCEPT_SHUTDOWN: DWORD = 0x00000004; +pub const SERVICE_ACCEPT_PARAMCHANGE: DWORD = 0x00000008; +pub const SERVICE_ACCEPT_NETBINDCHANGE: DWORD = 0x00000010; +pub const SERVICE_ACCEPT_HARDWAREPROFILECHANGE: DWORD = 0x00000020; +pub const SERVICE_ACCEPT_POWEREVENT: DWORD = 0x00000040; +pub const SERVICE_ACCEPT_SESSIONCHANGE: DWORD = 0x00000080; +pub const SERVICE_ACCEPT_PRESHUTDOWN: DWORD = 0x00000100; +pub const SERVICE_ACCEPT_TIMECHANGE: DWORD = 0x00000200; +pub const SERVICE_ACCEPT_TRIGGEREVENT: DWORD = 0x00000400; +// SERVICE_ACCEPT_USER_LOGOFF +pub const SC_MANAGER_CONNECT: DWORD = 0x0001; +pub const SC_MANAGER_CREATE_SERVICE: DWORD = 0x0002; +pub const SC_MANAGER_ENUMERATE_SERVICE: DWORD = 0x0004; +pub const SC_MANAGER_LOCK: DWORD = 0x0008; +pub const SC_MANAGER_QUERY_LOCK_STATUS: DWORD = 0x0010; +pub const SC_MANAGER_MODIFY_BOOT_CONFIG: DWORD = 0x0020; +pub const SC_MANAGER_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT + | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK + | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG; +pub const SERVICE_QUERY_CONFIG: DWORD = 0x0001; +pub const SERVICE_CHANGE_CONFIG: DWORD = 0x0002; +pub const SERVICE_QUERY_STATUS: DWORD = 0x0004; +pub const SERVICE_ENUMERATE_DEPENDENTS: DWORD = 0x0008; +pub const SERVICE_START: DWORD = 0x0010; +pub const SERVICE_STOP: DWORD = 0x0020; +pub const SERVICE_PAUSE_CONTINUE: DWORD = 0x0040; +pub const SERVICE_INTERROGATE: DWORD = 0x0080; +pub const SERVICE_USER_DEFINED_CONTROL: DWORD = 0x0100; +pub const SERVICE_ALL_ACCESS: DWORD = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG + | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START + | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL; +pub const SERVICE_RUNS_IN_SYSTEM_PROCESS: DWORD = 0x00000001; +pub const SERVICE_CONFIG_DESCRIPTION: DWORD = 1; +pub const SERVICE_CONFIG_FAILURE_ACTIONS: DWORD = 2; +pub const SERVICE_CONFIG_DELAYED_AUTO_START_INFO: DWORD = 3; +pub const SERVICE_CONFIG_FAILURE_ACTIONS_FLAG: DWORD = 4; +pub const SERVICE_CONFIG_SERVICE_SID_INFO: DWORD = 5; +pub const SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO: DWORD = 6; +pub const SERVICE_CONFIG_PRESHUTDOWN_INFO: DWORD = 7; +pub const SERVICE_CONFIG_TRIGGER_INFO: DWORD = 8; +pub const SERVICE_CONFIG_PREFERRED_NODE: DWORD = 9; +pub const SERVICE_CONFIG_LAUNCH_PROTECTED: DWORD = 12; +pub const SERVICE_NOTIFY_STATUS_CHANGE_1: DWORD = 1; +pub const SERVICE_NOTIFY_STATUS_CHANGE_2: DWORD = 2; +pub const SERVICE_NOTIFY_STATUS_CHANGE: DWORD = SERVICE_NOTIFY_STATUS_CHANGE_2; +pub const SERVICE_NOTIFY_STOPPED: DWORD = 0x00000001; +pub const SERVICE_NOTIFY_START_PENDING: DWORD = 0x00000002; +pub const SERVICE_NOTIFY_STOP_PENDING: DWORD = 0x00000004; +pub const SERVICE_NOTIFY_RUNNING: DWORD = 0x00000008; +pub const SERVICE_NOTIFY_CONTINUE_PENDING: DWORD = 0x00000010; +pub const SERVICE_NOTIFY_PAUSE_PENDING: DWORD = 0x00000020; +pub const SERVICE_NOTIFY_PAUSED: DWORD = 0x00000040; +pub const SERVICE_NOTIFY_CREATED: DWORD = 0x00000080; +pub const SERVICE_NOTIFY_DELETED: DWORD = 0x00000100; +pub const SERVICE_NOTIFY_DELETE_PENDING: DWORD = 0x00000200; +pub const SERVICE_STOP_REASON_FLAG_MIN: DWORD = 0x00000000; +pub const SERVICE_STOP_REASON_FLAG_UNPLANNED: DWORD = 0x10000000; +pub const SERVICE_STOP_REASON_FLAG_CUSTOM: DWORD = 0x20000000; +pub const SERVICE_STOP_REASON_FLAG_PLANNED: DWORD = 0x40000000; +pub const SERVICE_STOP_REASON_FLAG_MAX: DWORD = 0x80000000; +pub const SERVICE_STOP_REASON_MAJOR_MIN: DWORD = 0x00000000; +pub const SERVICE_STOP_REASON_MAJOR_OTHER: DWORD = 0x00010000; +pub const SERVICE_STOP_REASON_MAJOR_HARDWARE: DWORD = 0x00020000; +pub const SERVICE_STOP_REASON_MAJOR_OPERATINGSYSTEM: DWORD = 0x00030000; +pub const SERVICE_STOP_REASON_MAJOR_SOFTWARE: DWORD = 0x00040000; +pub const SERVICE_STOP_REASON_MAJOR_APPLICATION: DWORD = 0x00050000; +pub const SERVICE_STOP_REASON_MAJOR_NONE: DWORD = 0x00060000; +pub const SERVICE_STOP_REASON_MAJOR_MAX: DWORD = 0x00070000; +pub const SERVICE_STOP_REASON_MAJOR_MIN_CUSTOM: DWORD = 0x00400000; +pub const SERVICE_STOP_REASON_MAJOR_MAX_CUSTOM: DWORD = 0x00ff0000; +pub const SERVICE_STOP_REASON_MINOR_MIN: DWORD = 0x00000000; +pub const SERVICE_STOP_REASON_MINOR_OTHER: DWORD = 0x00000001; +pub const SERVICE_STOP_REASON_MINOR_MAINTENANCE: DWORD = 0x00000002; +pub const SERVICE_STOP_REASON_MINOR_INSTALLATION: DWORD = 0x00000003; +pub const SERVICE_STOP_REASON_MINOR_UPGRADE: DWORD = 0x00000004; +pub const SERVICE_STOP_REASON_MINOR_RECONFIG: DWORD = 0x00000005; +pub const SERVICE_STOP_REASON_MINOR_HUNG: DWORD = 0x00000006; +pub const SERVICE_STOP_REASON_MINOR_UNSTABLE: DWORD = 0x00000007; +pub const SERVICE_STOP_REASON_MINOR_DISK: DWORD = 0x00000008; +pub const SERVICE_STOP_REASON_MINOR_NETWORKCARD: DWORD = 0x00000009; +pub const SERVICE_STOP_REASON_MINOR_ENVIRONMENT: DWORD = 0x0000000a; +pub const SERVICE_STOP_REASON_MINOR_HARDWARE_DRIVER: DWORD = 0x0000000b; +pub const SERVICE_STOP_REASON_MINOR_OTHERDRIVER: DWORD = 0x0000000c; +pub const SERVICE_STOP_REASON_MINOR_SERVICEPACK: DWORD = 0x0000000d; +pub const SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE: DWORD = 0x0000000e; +pub const SERVICE_STOP_REASON_MINOR_SECURITYFIX: DWORD = 0x0000000f; +pub const SERVICE_STOP_REASON_MINOR_SECURITY: DWORD = 0x00000010; +pub const SERVICE_STOP_REASON_MINOR_NETWORK_CONNECTIVITY: DWORD = 0x00000011; +pub const SERVICE_STOP_REASON_MINOR_WMI: DWORD = 0x00000012; +pub const SERVICE_STOP_REASON_MINOR_SERVICEPACK_UNINSTALL: DWORD = 0x00000013; +pub const SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE_UNINSTALL: DWORD = 0x00000014; +pub const SERVICE_STOP_REASON_MINOR_SECURITYFIX_UNINSTALL: DWORD = 0x00000015; +pub const SERVICE_STOP_REASON_MINOR_MMC: DWORD = 0x00000016; +pub const SERVICE_STOP_REASON_MINOR_NONE: DWORD = 0x00000017; +pub const SERVICE_STOP_REASON_MINOR_MAX: DWORD = 0x00000018; +pub const SERVICE_STOP_REASON_MINOR_MIN_CUSTOM: DWORD = 0x00000100; +pub const SERVICE_STOP_REASON_MINOR_MAX_CUSTOM: DWORD = 0x0000FFFF; +pub const SERVICE_CONTROL_STATUS_REASON_INFO: DWORD = 1; +pub const SERVICE_SID_TYPE_NONE: DWORD = 0x00000000; +pub const SERVICE_SID_TYPE_UNRESTRICTED: DWORD = 0x00000001; +pub const SERVICE_SID_TYPE_RESTRICTED: DWORD = 0x00000002 | SERVICE_SID_TYPE_UNRESTRICTED; +pub const SERVICE_TRIGGER_TYPE_DEVICE_INTERFACE_ARRIVAL: DWORD = 1; +pub const SERVICE_TRIGGER_TYPE_IP_ADDRESS_AVAILABILITY: DWORD = 2; +pub const SERVICE_TRIGGER_TYPE_DOMAIN_JOIN: DWORD = 3; +pub const SERVICE_TRIGGER_TYPE_FIREWALL_PORT_EVENT: DWORD = 4; +pub const SERVICE_TRIGGER_TYPE_GROUP_POLICY: DWORD = 5; +pub const SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT: DWORD = 6; +pub const SERVICE_TRIGGER_TYPE_CUSTOM_SYSTEM_STATE_CHANGE: DWORD = 7; +pub const SERVICE_TRIGGER_TYPE_CUSTOM: DWORD = 20; +pub const SERVICE_TRIGGER_DATA_TYPE_BINARY: DWORD = 1; +pub const SERVICE_TRIGGER_DATA_TYPE_STRING: DWORD = 2; +pub const SERVICE_TRIGGER_DATA_TYPE_LEVEL: DWORD = 3; +pub const SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY: DWORD = 4; +pub const SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL: DWORD = 5; +pub const SERVICE_START_REASON_DEMAND: DWORD = 0x00000001; +pub const SERVICE_START_REASON_AUTO: DWORD = 0x00000002; +pub const SERVICE_START_REASON_TRIGGER: DWORD = 0x00000004; +pub const SERVICE_START_REASON_RESTART_ON_FAILURE: DWORD = 0x00000008; +pub const SERVICE_START_REASON_DELAYEDAUTO: DWORD = 0x00000010; +pub const SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON: DWORD = 1; +pub const SERVICE_LAUNCH_PROTECTED_NONE: DWORD = 0; +pub const SERVICE_LAUNCH_PROTECTED_WINDOWS: DWORD = 1; +pub const SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT: DWORD = 2; +pub const SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT: DWORD = 3; +DEFINE_GUID!{NETWORK_MANAGER_FIRST_IP_ADDRESS_ARRIVAL_GUID, + 0x4f27f2de, 0x14e2, 0x430b, 0xa5, 0x49, 0x7c, 0xd4, 0x8c, 0xbc, 0x82, 0x45} +DEFINE_GUID!{NETWORK_MANAGER_LAST_IP_ADDRESS_REMOVAL_GUID, + 0xcc4ba62a, 0x162e, 0x4648, 0x84, 0x7a, 0xb6, 0xbd, 0xf9, 0x93, 0xe3, 0x35} +DEFINE_GUID!{DOMAIN_JOIN_GUID, + 0x1ce20aba, 0x9851, 0x4421, 0x94, 0x30, 0x1d, 0xde, 0xb7, 0x66, 0xe8, 0x09} +DEFINE_GUID!{DOMAIN_LEAVE_GUID, + 0xddaf516e, 0x58c2, 0x4866, 0x95, 0x74, 0xc3, 0xb6, 0x15, 0xd4, 0x2e, 0xa1} +DEFINE_GUID!{FIREWALL_PORT_OPEN_GUID, + 0xb7569e07, 0x8421, 0x4ee0, 0xad, 0x10, 0x86, 0x91, 0x5a, 0xfd, 0xad, 0x09} +DEFINE_GUID!{FIREWALL_PORT_CLOSE_GUID, + 0xa144ed38, 0x8e12, 0x4de4, 0x9d, 0x96, 0xe6, 0x47, 0x40, 0xb1, 0xa5, 0x24} +DEFINE_GUID!{MACHINE_POLICY_PRESENT_GUID, + 0x659fcae6, 0x5bdb, 0x4da9, 0xb1, 0xff, 0xca, 0x2a, 0x17, 0x8d, 0x46, 0xe0} +DEFINE_GUID!{USER_POLICY_PRESENT_GUID, + 0x54fb46c8, 0xf089, 0x464c, 0xb1, 0xfd, 0x59, 0xd1, 0xb6, 0x2c, 0x3b, 0x50} +DEFINE_GUID!{RPC_INTERFACE_EVENT_GUID, + 0xbc90d167, 0x9470, 0x4139, 0xa9, 0xba, 0xbe, 0x0b, 0xbb, 0xf5, 0xb7, 0x4d} +DEFINE_GUID!{NAMED_PIPE_EVENT_GUID, + 0x1f81d131, 0x3fac, 0x4537, 0x9e, 0x0c, 0x7e, 0x7b, 0x0c, 0x2f, 0x4b, 0x55} +DEFINE_GUID!{CUSTOM_SYSTEM_STATE_CHANGE_EVENT_GUID, + 0x2d7a2816, 0x0c5e, 0x45fc, 0x9c, 0xe7, 0x57, 0x0e, 0x5e, 0xcd, 0xe9, 0xc9} +DECLARE_HANDLE!{SC_HANDLE, SC_HANDLE__} +pub type LPSC_HANDLE = *mut SC_HANDLE; +DECLARE_HANDLE!{SERVICE_STATUS_HANDLE, SERVICE_STATUS_HANDLE__} +ENUM!{enum SC_STATUS_TYPE { + SC_STATUS_PROCESS_INFO = 0, +}} +ENUM!{enum SC_ENUM_TYPE { + SC_ENUM_PROCESS_INFO = 0, +}} +STRUCT!{struct SERVICE_STATUS { + dwServiceType: DWORD, + dwCurrentState: DWORD, + dwControlsAccepted: DWORD, + dwWin32ExitCode: DWORD, + dwServiceSpecificExitCode: DWORD, + dwCheckPoint: DWORD, + dwWaitHint: DWORD, +}} +pub type LPSERVICE_STATUS = *mut SERVICE_STATUS; +STRUCT!{struct SERVICE_STATUS_PROCESS { + dwServiceType: DWORD, + dwCurrentState: DWORD, + dwControlsAccepted: DWORD, + dwWin32ExitCode: DWORD, + dwServiceSpecificExitCode: DWORD, + dwCheckPoint: DWORD, + dwWaitHint: DWORD, + dwProcessId: DWORD, + dwServiceFlags: DWORD, +}} +pub type LPSERVICE_STATUS_PROCESS = *mut SERVICE_STATUS_PROCESS; +STRUCT!{struct ENUM_SERVICE_STATUSA { + lpServiceName: LPSTR, + lpDisplayName: LPSTR, + ServiceStatus: SERVICE_STATUS, +}} +pub type LPENUM_SERVICE_STATUSA = *mut ENUM_SERVICE_STATUSA; +STRUCT!{struct ENUM_SERVICE_STATUSW { + lpServiceName: LPWSTR, + lpDisplayName: LPWSTR, + ServiceStatus: SERVICE_STATUS, +}} +pub type LPENUM_SERVICE_STATUSW = *mut ENUM_SERVICE_STATUSW; +STRUCT!{struct ENUM_SERVICE_STATUS_PROCESSA { + lpServiceName: LPSTR, + lpDisplayName: LPSTR, + ServiceStatusProcess: SERVICE_STATUS_PROCESS, +}} +pub type LPENUM_SERVICE_STATUS_PROCESSA = *mut ENUM_SERVICE_STATUS_PROCESSA; +STRUCT!{struct ENUM_SERVICE_STATUS_PROCESSW { + lpServiceName: LPWSTR, + lpDisplayName: LPWSTR, + ServiceStatusProcess: SERVICE_STATUS_PROCESS, +}} +pub type LPENUM_SERVICE_STATUS_PROCESSW = *mut ENUM_SERVICE_STATUS_PROCESSW; +pub type SC_LOCK = LPVOID; +STRUCT!{struct QUERY_SERVICE_LOCK_STATUSA { + fIsLocked: DWORD, + lpLockOwner: LPSTR, + dwLockDuration: DWORD, +}} +pub type LPQUERY_SERVICE_LOCK_STATUSA = *mut QUERY_SERVICE_LOCK_STATUSA; +STRUCT!{struct QUERY_SERVICE_LOCK_STATUSW { + fIsLocked: DWORD, + lpLockOwner: LPWSTR, + dwLockDuration: DWORD, +}} +pub type LPQUERY_SERVICE_LOCK_STATUSW = *mut QUERY_SERVICE_LOCK_STATUSW; +STRUCT!{struct QUERY_SERVICE_CONFIGA { + dwServiceType: DWORD, + dwStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPSTR, + lpLoadOrderGroup: LPSTR, + dwTagId: DWORD, + lpDependencies: LPSTR, + lpServiceStartName: LPSTR, + lpDisplayName: LPSTR, +}} +pub type LPQUERY_SERVICE_CONFIGA = *mut QUERY_SERVICE_CONFIGA; +STRUCT!{struct QUERY_SERVICE_CONFIGW { + dwServiceType: DWORD, + dwStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPWSTR, + lpLoadOrderGroup: LPWSTR, + dwTagId: DWORD, + lpDependencies: LPWSTR, + lpServiceStartName: LPWSTR, + lpDisplayName: LPWSTR, +}} +pub type LPQUERY_SERVICE_CONFIGW = *mut QUERY_SERVICE_CONFIGW; +FN!{stdcall LPSERVICE_MAIN_FUNCTIONW( + dwNumServicesArgs: DWORD, + lpServiceArgVectors: *mut LPWSTR, +) -> ()} +FN!{stdcall LPSERVICE_MAIN_FUNCTIONA( + dwNumServicesArgs: DWORD, + lpServiceArgVectors: *mut LPSTR, +) -> ()} +STRUCT!{struct SERVICE_TABLE_ENTRYA { + lpServiceName: LPCSTR, + lpServiceProc: LPSERVICE_MAIN_FUNCTIONA, +}} +pub type LPSERVICE_TABLE_ENTRYA = *mut SERVICE_TABLE_ENTRYA; +STRUCT!{struct SERVICE_TABLE_ENTRYW { + lpServiceName: LPCWSTR, + lpServiceProc: LPSERVICE_MAIN_FUNCTIONW, +}} +pub type LPSERVICE_TABLE_ENTRYW = *mut SERVICE_TABLE_ENTRYW; +FN!{stdcall LPHANDLER_FUNCTION( + dwControl: DWORD, +) -> ()} +FN!{stdcall LPHANDLER_FUNCTION_EX( + dwControl: DWORD, + dwEventType: DWORD, + lpEventData: LPVOID, + lpContext: LPVOID, +) -> DWORD} +FN!{stdcall PFN_SC_NOTIFY_CALLBACK( + pParameter: PVOID, +) -> ()} +STRUCT!{struct SERVICE_NOTIFY_1 { + dwVersion: DWORD, + pfnNotifyCallback: PFN_SC_NOTIFY_CALLBACK, + pContext: PVOID, + dwNotificationStatus: DWORD, + ServiceStatus: SERVICE_STATUS_PROCESS, +}} +pub type PSERVICE_NOTIFY_1 = *mut SERVICE_NOTIFY_1; +STRUCT!{struct SERVICE_NOTIFY_2A { + dwVersion: DWORD, + pfnNotifyCallback: PFN_SC_NOTIFY_CALLBACK, + pContext: PVOID, + dwNotificationStatus: DWORD, + ServiceStatus: SERVICE_STATUS_PROCESS, + dwNotificationTriggered: DWORD, + pszServiceNames: LPSTR, +}} +pub type PSERVICE_NOTIFY_2A = *mut SERVICE_NOTIFY_2A; +STRUCT!{struct SERVICE_NOTIFY_2W { + dwVersion: DWORD, + pfnNotifyCallback: PFN_SC_NOTIFY_CALLBACK, + pContext: PVOID, + dwNotificationStatus: DWORD, + ServiceStatus: SERVICE_STATUS_PROCESS, + dwNotificationTriggered: DWORD, + pszServiceNames: LPWSTR, +}} +pub type PSERVICE_NOTIFY_2W = *mut SERVICE_NOTIFY_2W; +pub type SERVICE_NOTIFYA = SERVICE_NOTIFY_2A; +pub type PSERVICE_NOTIFYA = PSERVICE_NOTIFY_2A; +pub type SERVICE_NOTIFYW = SERVICE_NOTIFY_2W; +pub type PSERVICE_NOTIFYW = PSERVICE_NOTIFY_2W; +extern "system" { + pub fn ChangeServiceConfigA( + hService: SC_HANDLE, + dwServiceType: DWORD, + dsStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPCSTR, + lpLoadOrderGroup: LPCSTR, + lpdwTagId: LPDWORD, + lpDependencies: LPCSTR, + lpServiceStartName: LPCSTR, + lpPassword: LPCSTR, + lpDisplayName: LPCSTR, + ) -> BOOL; + pub fn ChangeServiceConfigW( + hService: SC_HANDLE, + dwServiceType: DWORD, + dsStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPCWSTR, + lpLoadOrderGroup: LPCWSTR, + lpdwTagId: LPDWORD, + lpDependencies: LPCWSTR, + lpServiceStartName: LPCWSTR, + lpPassword: LPCWSTR, + lpDisplayName: LPCWSTR, + ) -> BOOL; + pub fn ChangeServiceConfig2A( + hService: SC_HANDLE, + dwInfoLevel: DWORD, + lpInfo: LPVOID, + ) -> BOOL; + pub fn ChangeServiceConfig2W( + hService: SC_HANDLE, + dwInfoLevel: DWORD, + lpInfo: LPVOID, + ) -> BOOL; + pub fn CloseServiceHandle( + hSCObject: SC_HANDLE, + ) -> BOOL; + pub fn ControlService( + hService: SC_HANDLE, + dwControl: DWORD, + lpServiceStatus: LPSERVICE_STATUS, + ) -> BOOL; + pub fn CreateServiceA( + hSCManager: SC_HANDLE, + lpServiceName: LPCSTR, + lpDisplayName: LPCSTR, + dwDesiredAccess: DWORD, + dwServiceType: DWORD, + dwStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPCSTR, + lpLoadOrderGroup: LPCSTR, + lpdwTagId: LPDWORD, + lpDependencies: LPCSTR, + lpServiceStartName: LPCSTR, + lpPassword: LPCSTR, + ) -> SC_HANDLE; + pub fn CreateServiceW( + hSCManager: SC_HANDLE, + lpServiceName: LPCWSTR, + lpDisplayName: LPCWSTR, + dwDesiredAccess: DWORD, + dwServiceType: DWORD, + dwStartType: DWORD, + dwErrorControl: DWORD, + lpBinaryPathName: LPCWSTR, + lpLoadOrderGroup: LPCWSTR, + lpdwTagId: LPDWORD, + lpDependencies: LPCWSTR, + lpServiceStartName: LPCWSTR, + lpPassword: LPCWSTR, + ) -> SC_HANDLE; + pub fn DeleteService( + hService: SC_HANDLE, + ) -> BOOL; + pub fn EnumDependentServicesA( + hService: SC_HANDLE, + dwServiceState: DWORD, + lpServices: LPENUM_SERVICE_STATUSA, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + ) -> BOOL; + pub fn EnumDependentServicesW( + hService: SC_HANDLE, + dwServiceState: DWORD, + lpServices: LPENUM_SERVICE_STATUSW, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + ) -> BOOL; + pub fn EnumServicesStatusA( + hSCManager: SC_HANDLE, + dwServiceType: DWORD, + dwServiceState: DWORD, + lpServices: LPENUM_SERVICE_STATUSA, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + lpResumeHandle: LPDWORD, + ) -> BOOL; + pub fn EnumServicesStatusW( + hSCManager: SC_HANDLE, + dwServiceType: DWORD, + dwServiceState: DWORD, + lpServices: LPENUM_SERVICE_STATUSW, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + lpResumeHandle: LPDWORD, + ) -> BOOL; + pub fn EnumServicesStatusExA( + hSCManager: SC_HANDLE, + InfoLevel: SC_ENUM_TYPE, + dwServiceType: DWORD, + dwServiceState: DWORD, + lpServices: LPBYTE, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + lpResumeHandle: LPDWORD, + pszGroupName: LPCSTR, + ) -> BOOL; + pub fn EnumServicesStatusExW( + hSCManager: SC_HANDLE, + InfoLevel: SC_ENUM_TYPE, + dwServiceType: DWORD, + dwServiceState: DWORD, + lpServices: LPBYTE, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + lpServicesReturned: LPDWORD, + lpResumeHandle: LPDWORD, + pszGroupName: LPCWSTR, + ) -> BOOL; + pub fn GetServiceKeyNameA( + hSCManager: SC_HANDLE, + lpDisplayName: LPCSTR, + lpServiceName: LPSTR, + lpcchBuffer: LPDWORD, + ) -> BOOL; + pub fn GetServiceKeyNameW( + hSCManager: SC_HANDLE, + lpDisplayName: LPCWSTR, + lpServiceName: LPWSTR, + lpcchBuffer: LPDWORD, + ) -> BOOL; + pub fn GetServiceDisplayNameA( + hSCManager: SC_HANDLE, + lpServiceName: LPCSTR, + lpDisplayName: LPSTR, + lpcchBuffer: LPDWORD, + ) -> BOOL; + pub fn GetServiceDisplayNameW( + hSCManager: SC_HANDLE, + lpServiceName: LPCWSTR, + lpDisplayName: LPWSTR, + lpcchBuffer: LPDWORD, + ) -> BOOL; + pub fn LockServiceDatabase( + hSCManager: SC_HANDLE, + ) -> SC_LOCK; + pub fn NotifyBootConfigStatus( + BootAcceptable: BOOL, + ) -> BOOL; + pub fn OpenSCManagerA( + lpMachineName: LPCSTR, + lpDatabaseName: LPCSTR, + dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenSCManagerW( + lpMachineName: LPCWSTR, + lpDatabaseName: LPCWSTR, + dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenServiceA( + hSCManager: SC_HANDLE, + lpServiceName: LPCSTR, + dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenServiceW( + hSCManager: SC_HANDLE, + lpServiceName: LPCWSTR, + dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn QueryServiceConfigA( + hService: SC_HANDLE, + lpServiceConfig: LPQUERY_SERVICE_CONFIGA, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceConfigW( + hService: SC_HANDLE, + lpServiceConfig: LPQUERY_SERVICE_CONFIGW, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceConfig2A( + hService: SC_HANDLE, + dwInfoLevel: DWORD, + lpBuffer: LPBYTE, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceConfig2W( + hService: SC_HANDLE, + dwInfoLevel: DWORD, + lpBuffer: LPBYTE, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceLockStatusA( + hSCManager: SC_HANDLE, + lpLockStatus: LPQUERY_SERVICE_LOCK_STATUSA, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceLockStatusW( + hSCManager: SC_HANDLE, + lpLockStatus: LPQUERY_SERVICE_LOCK_STATUSW, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceObjectSecurity( + hService: SC_HANDLE, + dwSecurityInformation: SECURITY_INFORMATION, + lpSecurityDescriptor: PSECURITY_DESCRIPTOR, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn QueryServiceStatus( + hService: SC_HANDLE, + lpServiceStatus: LPSERVICE_STATUS, + ) -> BOOL; + pub fn QueryServiceStatusEx( + hService: SC_HANDLE, + InfoLevel: SC_STATUS_TYPE, + lpBuffer: LPBYTE, + cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + pub fn RegisterServiceCtrlHandlerA( + lpServiceName: LPCSTR, + lpHandlerProc: LPHANDLER_FUNCTION, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerW( + lpServiceName: LPCWSTR, + lpHandlerProc: LPHANDLER_FUNCTION, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerExA( + lpServiceName: LPCSTR, + lpHandlerProc: LPHANDLER_FUNCTION_EX, + lpContext: LPVOID, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerExW( + lpServiceName: LPCWSTR, + lpHandlerProc: LPHANDLER_FUNCTION_EX, + lpContext: LPVOID, + ) -> SERVICE_STATUS_HANDLE; + pub fn SetServiceObjectSecurity( + hService: SC_HANDLE, + dwSecurityInformation: SECURITY_INFORMATION, + lpSecurityDescriptor: PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn SetServiceStatus( + hServiceStatus: SERVICE_STATUS_HANDLE, + lpServiceStatus: LPSERVICE_STATUS, + ) -> BOOL; + pub fn StartServiceCtrlDispatcherA( + lpServiceStartTable: *const SERVICE_TABLE_ENTRYA, + ) -> BOOL; + pub fn StartServiceCtrlDispatcherW( + lpServiceStartTable: *const SERVICE_TABLE_ENTRYW, + ) -> BOOL; + pub fn StartServiceA( + hService: SC_HANDLE, + dwNumServiceArgs: DWORD, + lpServiceArgVectors: *mut LPCSTR, + ) -> BOOL; + pub fn StartServiceW( + hService: SC_HANDLE, + dwNumServiceArgs: DWORD, + lpServiceArgVectors: *mut LPCWSTR, + ) -> BOOL; + pub fn UnlockServiceDatabase( + ScLock: SC_LOCK, + ) -> BOOL; + pub fn NotifyServiceStatusChangeA( + hService: SC_HANDLE, + dwNotifyMask: DWORD, + pNotifyBuffer: PSERVICE_NOTIFYA, + ) -> DWORD; + pub fn NotifyServiceStatusChangeW( + hService: SC_HANDLE, + dwNotifyMask: DWORD, + pNotifyBuffer: PSERVICE_NOTIFYW, + ) -> DWORD; + pub fn ControlServiceExA( + hService: SC_HANDLE, + dwControl: DWORD, + dwInfoLevel: DWORD, + pControlParams: PVOID, + ) -> BOOL; + pub fn ControlServiceExW( + hService: SC_HANDLE, + dwControl: DWORD, + dwInfoLevel: DWORD, + pControlParams: PVOID, + ) -> BOOL; + pub fn QueryServiceDynamicInformation( + hServiceStatus: SERVICE_STATUS_HANDLE, + dwInfoLevel: DWORD, + ppDynamicInfo: *mut PVOID, + ) -> BOOL; + pub fn WaitServiceState ( + hService: SC_HANDLE, + dwNotify: DWORD, + dwTimeout: DWORD, + hCancelEvent: HANDLE, + ) -> DWORD; +} diff --git a/winapi/src/um/winusb.rs b/winapi/src/um/winusb.rs new file mode 100644 index 000000000..c72e36833 --- /dev/null +++ b/winapi/src/um/winusb.rs @@ -0,0 +1,224 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! FFI bindings to winusb. +use shared::minwindef::{BOOL, LPDWORD, PUCHAR, PULONG, UCHAR, ULONG, USHORT}; +use shared::usb::PUSBD_ISO_PACKET_DESCRIPTOR; +use shared::usbspec::PUSB_CONFIGURATION_DESCRIPTOR; +use shared::winusbio::{PWINUSB_PIPE_INFORMATION, PWINUSB_PIPE_INFORMATION_EX}; +use um::minwinbase::LPOVERLAPPED; +use um::winnt::{HANDLE, LARGE_INTEGER, LONG, PVOID}; +pub type WINUSB_INTERFACE_HANDLE = PVOID; +pub type PWINUSB_INTERFACE_HANDLE = *mut PVOID; +pub type WINUSB_ISOCH_BUFFER_HANDLE = PVOID; +pub type PWINUSB_ISOCH_BUFFER_HANDLE = *mut PVOID; +STRUCT!{#[repr(packed)] struct WINUSB_SETUP_PACKET { + RequestType: UCHAR, + Request: UCHAR, + Value: USHORT, + Index: USHORT, + Length: USHORT, +}} +pub type PWINUSB_SETUP_PACKET = *mut WINUSB_SETUP_PACKET; +extern "system" { + pub fn WinUsb_Initialize( + DeviceHandle: HANDLE, + InterfaceHandle: PWINUSB_INTERFACE_HANDLE, + ) -> BOOL; + pub fn WinUsb_Free( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + ) -> BOOL; + pub fn WinUsb_GetAssociatedInterface( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + AssociatedInterfaceIndex: UCHAR, + AssociatedInterfaceHandle: PWINUSB_INTERFACE_HANDLE, + ) -> BOOL; + pub fn WinUsb_GetDescriptor( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + DescriptorType: UCHAR, + Index: UCHAR, + LanguageID: USHORT, + Buffer: PUCHAR, + BufferLength: ULONG, + LengthTransferred: PULONG, + ) -> BOOL; + pub fn WinUsb_QueryInterfaceSettings( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + AlternateInterfaceNumber: UCHAR, + UsbAltInterfaceDescriptor: PUSB_INTERFACE_DESCRIPTOR, + ) -> BOOL; + pub fn WinUsb_QueryDeviceInformation( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + InformationType: ULONG, + BufferLength: PULONG, + Buffer: PVOID, + ) -> BOOL; + pub fn WinUsb_SetCurrentAlternateSetting( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + SettingNumber: UCHAR, + ) -> BOOL; + pub fn WinUsb_GetCurrentAlternateSetting( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + SettingNumber: PUCHAR, + ) -> BOOL; + pub fn WinUsb_QueryPipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + AlternateInterfaceNumber: UCHAR, + PipeIndex: UCHAR, + PipeInformationEx: PWINUSB_PIPE_INFORMATION, + ) -> BOOL; + pub fn WinUsb_QueryPipeEx( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + AlternateInterfaceNumber: UCHAR, + PipeIndex: UCHAR, + PipeInformationEx: PWINUSB_PIPE_INFORMATION_EX, + ) -> BOOL; + pub fn WinUsb_SetPipePolicy( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + PolicyType: ULONG, + ValueLength: ULONG, + Value: PVOID, + ) -> BOOL; + pub fn WinUsb_GetPipePolicy( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + PolicyType: ULONG, + ValueLength: PULONG, + Value: PVOID, + ) -> BOOL; + pub fn WinUsb_ReadPipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + Buffer: PUCHAR, + BufferLength: ULONG, + LengthTransferred: PULONG, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_WritePipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + Buffer: PUCHAR, + BufferLength: ULONG, + LengthTransferred: PULONG, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_ControlTransfer( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + SetupPacket: WINUSB_SETUP_PACKET, + Buffer: PUCHAR, + BufferLength: ULONG, + LengthTransferred: PULONG, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_ResetPipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + ) -> BOOL; + pub fn WinUsb_AbortPipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + ) -> BOOL; + pub fn WinUsb_FlushPipe( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + ) -> BOOL; + pub fn WinUsb_SetPowerPolicy( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PolicyType: ULONG, + ValueLength: ULONG, + Value: PVOID, + ) -> BOOL; + pub fn WinUsb_GetPowerPolicy( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PolicyType: ULONG, + ValueLength: PULONG, + Value: PVOID, + ) -> BOOL; + pub fn WinUsb_GetOverlappedResult( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + lpOverlapped: LPOVERLAPPED, + lpNumberOfBytesTransferred: LPDWORD, + bWait: BOOL, + ) -> BOOL; + pub fn WinUsb_ParseConfigurationDescriptor( + ConfigurationDescriptor: PUSB_CONFIGURATION_DESCRIPTOR, + StartPosition: PVOID, + InterfaceNumber: LONG, + AlternateSetting: LONG, + InterfaceClass: LONG, + InterfaceSubClass: LONG, + InterfaceProtocol: LONG, + ) -> BOOL; + pub fn WinUsb_ParseDescriptors( + DescriptorBuffer: PVOID, + TotalLength: ULONG, + StartPosition: PVOID, + DescriptorType: LONG, + ) -> BOOL; + pub fn WinUsb_GetCurrentFrameNumber( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + CurrentFrameNumber: PULONG, + TimeStamp: *mut LARGE_INTEGER, + ) -> BOOL; + pub fn WinUsb_GetAdjustedFrameNumber( + CurrentFrameNumber: PULONG, + TimeStamp: LARGE_INTEGER, + ) -> BOOL; + pub fn WinUsb_RegisterIsochBuffer( + InterfaceHandle: WINUSB_INTERFACE_HANDLE, + PipeID: UCHAR, + Buffer: PUCHAR, + BufferLength: ULONG, + IsochBufferHandle: PWINUSB_ISOCH_BUFFER_HANDLE, + ) -> BOOL; + pub fn WinUsb_UnregisterIsochBuffer( + IsochBufferHandle: WINUSB_ISOCH_BUFFER_HANDLE, + ) -> BOOL; + pub fn WinUsb_WriteIsochPipe( + BufferHandle: WINUSB_ISOCH_BUFFER_HANDLE, + Offset: ULONG, + Length: ULONG, + FrameNumber: PULONG, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_ReadIsochPipe( + BufferHandle: WINUSB_ISOCH_BUFFER_HANDLE, + Offset: ULONG, + Length: ULONG, + FrameNumber: PULONG, + NumberOfPackets: ULONG, + IsoPacketDescriptors: PUSBD_ISO_PACKET_DESCRIPTOR, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_WriteIsochPipeAsap( + BufferHandle: WINUSB_ISOCH_BUFFER_HANDLE, + Offset: ULONG, + Length: ULONG, + ContinueStream: BOOL, + Overlapped: LPOVERLAPPED, + ) -> BOOL; + pub fn WinUsb_ReadIsochPipeAsap( + BufferHandle: WINUSB_ISOCH_BUFFER_HANDLE, + Offset: ULONG, + Length: ULONG, + ContinueStream: BOOL, + NumberOfPackets: ULONG, + IsoPacketDescriptors: PUSBD_ISO_PACKET_DESCRIPTOR, + Overlapped: LPOVERLAPPED, + ) -> BOOL; +} +STRUCT!{struct USB_INTERFACE_DESCRIPTOR { + bLength: UCHAR, + bDescriptorType: UCHAR, + bInterfaceNumber: UCHAR, + bAlternateSetting: UCHAR, + bNumEndpoints: UCHAR, + bInterfaceClass: UCHAR, + bInterfaceSubClass: UCHAR, + bInterfaceProtocol: UCHAR, + iInterface: UCHAR, +}} +pub type PUSB_INTERFACE_DESCRIPTOR = *mut USB_INTERFACE_DESCRIPTOR; diff --git a/winapi/src/um/winuser.rs b/winapi/src/um/winuser.rs new file mode 100644 index 000000000..53890d138 --- /dev/null +++ b/winapi/src/um/winuser.rs @@ -0,0 +1,7006 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! USER procedure declarations, constant definitions and macros +use ctypes::{c_int, c_long, c_short, c_uint}; +use shared::basetsd::{ + DWORD_PTR, INT32, INT_PTR, PDWORD_PTR, UINT16, UINT32, UINT64, UINT_PTR, ULONG_PTR, +}; +#[cfg(target_pointer_width = "64")] +use shared::basetsd::LONG_PTR; +use shared::guiddef::{GUID, LPCGUID}; +use shared::minwindef::{ + ATOM, BOOL, BYTE, DWORD, HINSTANCE, HIWORD, HKL, HMODULE, HRGN, HWINSTA, INT, LOWORD, LPARAM, + LPBYTE, LPDWORD, LPINT, LPVOID, LPWORD, LRESULT, PBYTE, PUINT, PULONG, TRUE, UCHAR, UINT, + ULONG, USHORT, WORD, WPARAM, +}; +use shared::windef::{ + COLORREF, DPI_AWARENESS, DPI_AWARENESS_CONTEXT, DPI_HOSTING_BEHAVIOR, HACCEL, HBITMAP, HBRUSH, + HCURSOR, HDC, HDESK, HHOOK, HICON, HMENU, HMONITOR, HWINEVENTHOOK, HWND, LPCRECT, LPPOINT, + LPRECT, POINT, RECT, +}; +use um::minwinbase::LPSECURITY_ATTRIBUTES; +use um::wingdi::{ + BLENDFUNCTION, DEVMODEA, DEVMODEW, LOGFONTA, LOGFONTW, PDISPLAY_DEVICEA, PDISPLAY_DEVICEW +}; +use um::winnt::{ + ACCESS_MASK, BOOLEAN, CHAR, HANDLE, LONG, LPCSTR, LPCWSTR, LPSTR, LPWSTR, LUID, + PSECURITY_DESCRIPTOR, PSECURITY_INFORMATION, PVOID, SHORT, VOID, WCHAR, +}; +use vc::limits::UINT_MAX; +use vc::vadefs::va_list; +pub type HDWP = HANDLE; +pub type MENUTEMPLATEA = VOID; +pub type MENUTEMPLATEW = VOID; +pub type LPMENUTEMPLATEA = PVOID; +pub type LPMENUTEMPLATEW = PVOID; +FN!{stdcall WNDPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> LRESULT} +FN!{stdcall DLGPROC( + HWND, + UINT, + WPARAM, + LPARAM, +) -> INT_PTR} +FN!{stdcall TIMERPROC( + HWND, + UINT, + UINT_PTR, + DWORD, +) -> ()} +FN!{stdcall GRAYSTRINGPROC( + HDC, + LPARAM, + c_int, +) -> BOOL} +FN!{stdcall WNDENUMPROC( + HWND, + LPARAM, +) -> BOOL} +FN!{stdcall HOOKPROC( + code: c_int, + wParam: WPARAM, + lParam: LPARAM, +) -> LRESULT} +FN!{stdcall SENDASYNCPROC( + HWND, + UINT, + ULONG_PTR, + LRESULT, +) -> ()} +FN!{stdcall PROPENUMPROCA( + HWND, + LPCSTR, + HANDLE, +) -> BOOL} +FN!{stdcall PROPENUMPROCW( + HWND, + LPCWSTR, + HANDLE, +) -> BOOL} +FN!{stdcall PROPENUMPROCEXA( + HWND, + LPSTR, + HANDLE, + ULONG_PTR, +) -> BOOL} +FN!{stdcall PROPENUMPROCEXW( + HWND, + LPWSTR, + HANDLE, + ULONG_PTR, +) -> BOOL} +FN!{stdcall EDITWORDBREAKPROCA( + lpch: LPSTR, + ichCurrent: c_int, + cch: c_int, + code: c_int, +) -> c_int} +FN!{stdcall EDITWORDBREAKPROCW( + lpch: LPWSTR, + ichCurrent: c_int, + cch: c_int, + code: c_int, +) -> c_int} +FN!{stdcall DRAWSTATEPROC( + hdc: HDC, + lData: LPARAM, + wData: WPARAM, + cx: c_int, + cy: c_int, +) -> BOOL} +FN!{stdcall NAMEENUMPROCA( + LPSTR, + LPARAM, +) -> BOOL} +FN!{stdcall NAMEENUMPROCW( + LPWSTR, + LPARAM, +) -> BOOL} +pub type WINSTAENUMPROCA = NAMEENUMPROCA; +pub type DESKTOPENUMPROCA = NAMEENUMPROCA; +pub type WINSTAENUMPROCW = NAMEENUMPROCW; +pub type DESKTOPENUMPROCW = NAMEENUMPROCW; +#[inline] +pub fn IS_INTRESOURCE(r: ULONG_PTR) -> bool { + (r >> 16) == 0 +} +#[inline] +pub fn MAKEINTRESOURCEA(i: WORD) -> LPSTR { + i as ULONG_PTR as LPSTR +} +#[inline] +pub fn MAKEINTRESOURCEW(i: WORD) -> LPWSTR { + i as ULONG_PTR as LPWSTR +} +pub const RT_CURSOR: LPWSTR = MAKEINTRESOURCE!(1); +pub const RT_BITMAP: LPWSTR = MAKEINTRESOURCE!(2); +pub const RT_ICON: LPWSTR = MAKEINTRESOURCE!(3); +pub const RT_MENU: LPWSTR = MAKEINTRESOURCE!(4); +pub const RT_DIALOG: LPWSTR = MAKEINTRESOURCE!(5); +pub const RT_STRING: LPWSTR = MAKEINTRESOURCE!(6); +pub const RT_FONTDIR: LPWSTR = MAKEINTRESOURCE!(7); +pub const RT_FONT: LPWSTR = MAKEINTRESOURCE!(8); +pub const RT_ACCELERATOR: LPWSTR = MAKEINTRESOURCE!(9); +pub const RT_RCDATA: LPWSTR = MAKEINTRESOURCE!(10); +pub const RT_MESSAGETABLE: LPWSTR = MAKEINTRESOURCE!(11); +pub const DIFFERENCE: WORD = 11; +pub const RT_GROUP_CURSOR: LPWSTR = MAKEINTRESOURCE!(1 + DIFFERENCE); +pub const RT_GROUP_ICON: LPWSTR = MAKEINTRESOURCE!(3 + DIFFERENCE); +pub const RT_VERSION: LPWSTR = MAKEINTRESOURCE!(16); +pub const RT_DLGINCLUDE: LPWSTR = MAKEINTRESOURCE!(17); +pub const RT_PLUGPLAY: LPWSTR = MAKEINTRESOURCE!(19); +pub const RT_VXD: LPWSTR = MAKEINTRESOURCE!(20); +pub const RT_ANICURSOR: LPWSTR = MAKEINTRESOURCE!(21); +pub const RT_ANIICON: LPWSTR = MAKEINTRESOURCE!(22); +pub const RT_HTML: LPWSTR = MAKEINTRESOURCE!(23); +pub const RT_MANIFEST: LPWSTR = MAKEINTRESOURCE!(24); +pub const CREATEPROCESS_MANIFEST_RESOURCE_ID: LPWSTR = MAKEINTRESOURCE!(1); +pub const ISOLATIONAWARE_MANIFEST_RESOURCE_ID: LPWSTR = MAKEINTRESOURCE!(2); +pub const ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID: LPWSTR + = MAKEINTRESOURCE!(3); +pub const MINIMUM_RESERVED_MANIFEST_RESOURCE_ID: LPWSTR = MAKEINTRESOURCE!(1); +pub const MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID: LPWSTR = MAKEINTRESOURCE!(16); +extern "system" { + pub fn wvsprintfA( + _: LPSTR, + _: LPCSTR, + arglist: va_list, + ) -> c_int; + pub fn wvsprintfW( + _: LPWSTR, + _: LPCWSTR, + arglist: va_list, + ) -> c_int; +} +extern "C" { + pub fn wsprintfA( + _: LPSTR, + _: LPCSTR, + ... + ) -> c_int; + pub fn wsprintfW( + _: LPWSTR, + _: LPCWSTR, + ... + ) -> c_int; +} +pub const SETWALLPAPER_DEFAULT: LPWSTR = -1isize as LPWSTR; +pub const SB_HORZ: UINT = 0; +pub const SB_VERT: UINT = 1; +pub const SB_CTL: UINT = 2; +pub const SB_BOTH: UINT = 3; +pub const SB_LINEUP: LPARAM = 0; +pub const SB_LINELEFT: LPARAM = 0; +pub const SB_LINEDOWN: LPARAM = 1; +pub const SB_LINERIGHT: LPARAM = 1; +pub const SB_PAGEUP: LPARAM = 2; +pub const SB_PAGELEFT: LPARAM = 2; +pub const SB_PAGEDOWN: LPARAM = 3; +pub const SB_PAGERIGHT: LPARAM = 3; +pub const SB_THUMBPOSITION: LPARAM = 4; +pub const SB_THUMBTRACK: LPARAM = 5; +pub const SB_TOP: LPARAM = 6; +pub const SB_LEFT: LPARAM = 6; +pub const SB_BOTTOM: LPARAM = 7; +pub const SB_RIGHT: LPARAM = 7; +pub const SB_ENDSCROLL: LPARAM = 8; +pub const SW_HIDE: c_int = 0; +pub const SW_SHOWNORMAL: c_int = 1; +pub const SW_NORMAL: c_int = 1; +pub const SW_SHOWMINIMIZED: c_int = 2; +pub const SW_SHOWMAXIMIZED: c_int = 3; +pub const SW_MAXIMIZE: c_int = 3; +pub const SW_SHOWNOACTIVATE: c_int = 4; +pub const SW_SHOW: c_int = 5; +pub const SW_MINIMIZE: c_int = 6; +pub const SW_SHOWMINNOACTIVE: c_int = 7; +pub const SW_SHOWNA: c_int = 8; +pub const SW_RESTORE: c_int = 9; +pub const SW_SHOWDEFAULT: c_int = 10; +pub const SW_FORCEMINIMIZE: c_int = 11; +pub const SW_MAX: c_int = 11; +pub const HIDE_WINDOW: c_int = 0; +pub const SHOW_OPENWINDOW: c_int = 1; +pub const SHOW_ICONWINDOW: c_int = 2; +pub const SHOW_FULLSCREEN: c_int = 3; +pub const SHOW_OPENNOACTIVATE: c_int = 4; +pub const SW_PARENTCLOSING: LPARAM = 1; +pub const SW_OTHERZOOM: LPARAM = 2; +pub const SW_PARENTOPENING: LPARAM = 3; +pub const SW_OTHERUNZOOM: LPARAM = 4; +pub const AW_HOR_POSITIVE: DWORD = 0x00000001; +pub const AW_HOR_NEGATIVE: DWORD = 0x00000002; +pub const AW_VER_POSITIVE: DWORD = 0x00000004; +pub const AW_VER_NEGATIVE: DWORD = 0x00000008; +pub const AW_CENTER: DWORD = 0x00000010; +pub const AW_HIDE: DWORD = 0x00010000; +pub const AW_ACTIVATE: DWORD = 0x00020000; +pub const AW_SLIDE: DWORD = 0x00040000; +pub const AW_BLEND: DWORD = 0x00080000; +pub const KF_EXTENDED: WORD = 0x0100; +pub const KF_DLGMODE: WORD = 0x0800; +pub const KF_MENUMODE: WORD = 0x1000; +pub const KF_ALTDOWN: WORD = 0x2000; +pub const KF_REPEAT: WORD = 0x4000; +pub const KF_UP: WORD = 0x8000; +pub const VK_LBUTTON: c_int = 0x01; +pub const VK_RBUTTON: c_int = 0x02; +pub const VK_CANCEL: c_int = 0x03; +pub const VK_MBUTTON: c_int = 0x04; +pub const VK_XBUTTON1: c_int = 0x05; +pub const VK_XBUTTON2: c_int = 0x06; +pub const VK_BACK: c_int = 0x08; +pub const VK_TAB: c_int = 0x09; +pub const VK_CLEAR: c_int = 0x0C; +pub const VK_RETURN: c_int = 0x0D; +pub const VK_SHIFT: c_int = 0x10; +pub const VK_CONTROL: c_int = 0x11; +pub const VK_MENU: c_int = 0x12; +pub const VK_PAUSE: c_int = 0x13; +pub const VK_CAPITAL: c_int = 0x14; +pub const VK_KANA: c_int = 0x15; +pub const VK_HANGEUL: c_int = 0x15; +pub const VK_HANGUL: c_int = 0x15; +pub const VK_JUNJA: c_int = 0x17; +pub const VK_FINAL: c_int = 0x18; +pub const VK_HANJA: c_int = 0x19; +pub const VK_KANJI: c_int = 0x19; +pub const VK_ESCAPE: c_int = 0x1B; +pub const VK_CONVERT: c_int = 0x1C; +pub const VK_NONCONVERT: c_int = 0x1D; +pub const VK_ACCEPT: c_int = 0x1E; +pub const VK_MODECHANGE: c_int = 0x1F; +pub const VK_SPACE: c_int = 0x20; +pub const VK_PRIOR: c_int = 0x21; +pub const VK_NEXT: c_int = 0x22; +pub const VK_END: c_int = 0x23; +pub const VK_HOME: c_int = 0x24; +pub const VK_LEFT: c_int = 0x25; +pub const VK_UP: c_int = 0x26; +pub const VK_RIGHT: c_int = 0x27; +pub const VK_DOWN: c_int = 0x28; +pub const VK_SELECT: c_int = 0x29; +pub const VK_PRINT: c_int = 0x2A; +pub const VK_EXECUTE: c_int = 0x2B; +pub const VK_SNAPSHOT: c_int = 0x2C; +pub const VK_INSERT: c_int = 0x2D; +pub const VK_DELETE: c_int = 0x2E; +pub const VK_HELP: c_int = 0x2F; +pub const VK_LWIN: c_int = 0x5B; +pub const VK_RWIN: c_int = 0x5C; +pub const VK_APPS: c_int = 0x5D; +pub const VK_SLEEP: c_int = 0x5F; +pub const VK_NUMPAD0: c_int = 0x60; +pub const VK_NUMPAD1: c_int = 0x61; +pub const VK_NUMPAD2: c_int = 0x62; +pub const VK_NUMPAD3: c_int = 0x63; +pub const VK_NUMPAD4: c_int = 0x64; +pub const VK_NUMPAD5: c_int = 0x65; +pub const VK_NUMPAD6: c_int = 0x66; +pub const VK_NUMPAD7: c_int = 0x67; +pub const VK_NUMPAD8: c_int = 0x68; +pub const VK_NUMPAD9: c_int = 0x69; +pub const VK_MULTIPLY: c_int = 0x6A; +pub const VK_ADD: c_int = 0x6B; +pub const VK_SEPARATOR: c_int = 0x6C; +pub const VK_SUBTRACT: c_int = 0x6D; +pub const VK_DECIMAL: c_int = 0x6E; +pub const VK_DIVIDE: c_int = 0x6F; +pub const VK_F1: c_int = 0x70; +pub const VK_F2: c_int = 0x71; +pub const VK_F3: c_int = 0x72; +pub const VK_F4: c_int = 0x73; +pub const VK_F5: c_int = 0x74; +pub const VK_F6: c_int = 0x75; +pub const VK_F7: c_int = 0x76; +pub const VK_F8: c_int = 0x77; +pub const VK_F9: c_int = 0x78; +pub const VK_F10: c_int = 0x79; +pub const VK_F11: c_int = 0x7A; +pub const VK_F12: c_int = 0x7B; +pub const VK_F13: c_int = 0x7C; +pub const VK_F14: c_int = 0x7D; +pub const VK_F15: c_int = 0x7E; +pub const VK_F16: c_int = 0x7F; +pub const VK_F17: c_int = 0x80; +pub const VK_F18: c_int = 0x81; +pub const VK_F19: c_int = 0x82; +pub const VK_F20: c_int = 0x83; +pub const VK_F21: c_int = 0x84; +pub const VK_F22: c_int = 0x85; +pub const VK_F23: c_int = 0x86; +pub const VK_F24: c_int = 0x87; +pub const VK_NAVIGATION_VIEW: c_int = 0x88; +pub const VK_NAVIGATION_MENU: c_int = 0x89; +pub const VK_NAVIGATION_UP: c_int = 0x8A; +pub const VK_NAVIGATION_DOWN: c_int = 0x8B; +pub const VK_NAVIGATION_LEFT: c_int = 0x8C; +pub const VK_NAVIGATION_RIGHT: c_int = 0x8D; +pub const VK_NAVIGATION_ACCEPT: c_int = 0x8E; +pub const VK_NAVIGATION_CANCEL: c_int = 0x8F; +pub const VK_NUMLOCK: c_int = 0x90; +pub const VK_SCROLL: c_int = 0x91; +pub const VK_OEM_NEC_EQUAL: c_int = 0x92; +pub const VK_OEM_FJ_JISHO: c_int = 0x92; +pub const VK_OEM_FJ_MASSHOU: c_int = 0x93; +pub const VK_OEM_FJ_TOUROKU: c_int = 0x94; +pub const VK_OEM_FJ_LOYA: c_int = 0x95; +pub const VK_OEM_FJ_ROYA: c_int = 0x96; +pub const VK_LSHIFT: c_int = 0xA0; +pub const VK_RSHIFT: c_int = 0xA1; +pub const VK_LCONTROL: c_int = 0xA2; +pub const VK_RCONTROL: c_int = 0xA3; +pub const VK_LMENU: c_int = 0xA4; +pub const VK_RMENU: c_int = 0xA5; +pub const VK_BROWSER_BACK: c_int = 0xA6; +pub const VK_BROWSER_FORWARD: c_int = 0xA7; +pub const VK_BROWSER_REFRESH: c_int = 0xA8; +pub const VK_BROWSER_STOP: c_int = 0xA9; +pub const VK_BROWSER_SEARCH: c_int = 0xAA; +pub const VK_BROWSER_FAVORITES: c_int = 0xAB; +pub const VK_BROWSER_HOME: c_int = 0xAC; +pub const VK_VOLUME_MUTE: c_int = 0xAD; +pub const VK_VOLUME_DOWN: c_int = 0xAE; +pub const VK_VOLUME_UP: c_int = 0xAF; +pub const VK_MEDIA_NEXT_TRACK: c_int = 0xB0; +pub const VK_MEDIA_PREV_TRACK: c_int = 0xB1; +pub const VK_MEDIA_STOP: c_int = 0xB2; +pub const VK_MEDIA_PLAY_PAUSE: c_int = 0xB3; +pub const VK_LAUNCH_MAIL: c_int = 0xB4; +pub const VK_LAUNCH_MEDIA_SELECT: c_int = 0xB5; +pub const VK_LAUNCH_APP1: c_int = 0xB6; +pub const VK_LAUNCH_APP2: c_int = 0xB7; +pub const VK_OEM_1: c_int = 0xBA; +pub const VK_OEM_PLUS: c_int = 0xBB; +pub const VK_OEM_COMMA: c_int = 0xBC; +pub const VK_OEM_MINUS: c_int = 0xBD; +pub const VK_OEM_PERIOD: c_int = 0xBE; +pub const VK_OEM_2: c_int = 0xBF; +pub const VK_OEM_3: c_int = 0xC0; +pub const VK_GAMEPAD_A: c_int = 0xC3; +pub const VK_GAMEPAD_B: c_int = 0xC4; +pub const VK_GAMEPAD_X: c_int = 0xC5; +pub const VK_GAMEPAD_Y: c_int = 0xC6; +pub const VK_GAMEPAD_RIGHT_SHOULDER: c_int = 0xC7; +pub const VK_GAMEPAD_LEFT_SHOULDER: c_int = 0xC8; +pub const VK_GAMEPAD_LEFT_TRIGGER: c_int = 0xC9; +pub const VK_GAMEPAD_RIGHT_TRIGGER: c_int = 0xCA; +pub const VK_GAMEPAD_DPAD_UP: c_int = 0xCB; +pub const VK_GAMEPAD_DPAD_DOWN: c_int = 0xCC; +pub const VK_GAMEPAD_DPAD_LEFT: c_int = 0xCD; +pub const VK_GAMEPAD_DPAD_RIGHT: c_int = 0xCE; +pub const VK_GAMEPAD_MENU: c_int = 0xCF; +pub const VK_GAMEPAD_VIEW: c_int = 0xD0; +pub const VK_GAMEPAD_LEFT_THUMBSTICK_BUTTON: c_int = 0xD1; +pub const VK_GAMEPAD_RIGHT_THUMBSTICK_BUTTON: c_int = 0xD2; +pub const VK_GAMEPAD_LEFT_THUMBSTICK_UP: c_int = 0xD3; +pub const VK_GAMEPAD_LEFT_THUMBSTICK_DOWN: c_int = 0xD4; +pub const VK_GAMEPAD_LEFT_THUMBSTICK_RIGHT: c_int = 0xD5; +pub const VK_GAMEPAD_LEFT_THUMBSTICK_LEFT: c_int = 0xD6; +pub const VK_GAMEPAD_RIGHT_THUMBSTICK_UP: c_int = 0xD7; +pub const VK_GAMEPAD_RIGHT_THUMBSTICK_DOWN: c_int = 0xD8; +pub const VK_GAMEPAD_RIGHT_THUMBSTICK_RIGHT: c_int = 0xD9; +pub const VK_GAMEPAD_RIGHT_THUMBSTICK_LEFT: c_int = 0xDA; +pub const VK_OEM_4: c_int = 0xDB; +pub const VK_OEM_5: c_int = 0xDC; +pub const VK_OEM_6: c_int = 0xDD; +pub const VK_OEM_7: c_int = 0xDE; +pub const VK_OEM_8: c_int = 0xDF; +pub const VK_OEM_AX: c_int = 0xE1; +pub const VK_OEM_102: c_int = 0xE2; +pub const VK_ICO_HELP: c_int = 0xE3; +pub const VK_ICO_00: c_int = 0xE4; +pub const VK_PROCESSKEY: c_int = 0xE5; +pub const VK_ICO_CLEAR: c_int = 0xE6; +pub const VK_PACKET: c_int = 0xE7; +pub const VK_OEM_RESET: c_int = 0xE9; +pub const VK_OEM_JUMP: c_int = 0xEA; +pub const VK_OEM_PA1: c_int = 0xEB; +pub const VK_OEM_PA2: c_int = 0xEC; +pub const VK_OEM_PA3: c_int = 0xED; +pub const VK_OEM_WSCTRL: c_int = 0xEE; +pub const VK_OEM_CUSEL: c_int = 0xEF; +pub const VK_OEM_ATTN: c_int = 0xF0; +pub const VK_OEM_FINISH: c_int = 0xF1; +pub const VK_OEM_COPY: c_int = 0xF2; +pub const VK_OEM_AUTO: c_int = 0xF3; +pub const VK_OEM_ENLW: c_int = 0xF4; +pub const VK_OEM_BACKTAB: c_int = 0xF5; +pub const VK_ATTN: c_int = 0xF6; +pub const VK_CRSEL: c_int = 0xF7; +pub const VK_EXSEL: c_int = 0xF8; +pub const VK_EREOF: c_int = 0xF9; +pub const VK_PLAY: c_int = 0xFA; +pub const VK_ZOOM: c_int = 0xFB; +pub const VK_NONAME: c_int = 0xFC; +pub const VK_PA1: c_int = 0xFD; +pub const VK_OEM_CLEAR: c_int = 0xFE; +pub const WH_MIN: c_int = -1; +pub const WH_MSGFILTER: c_int = -1; +pub const WH_JOURNALRECORD: c_int = 0; +pub const WH_JOURNALPLAYBACK: c_int = 1; +pub const WH_KEYBOARD: c_int = 2; +pub const WH_GETMESSAGE: c_int = 3; +pub const WH_CALLWNDPROC: c_int = 4; +pub const WH_CBT: c_int = 5; +pub const WH_SYSMSGFILTER: c_int = 6; +pub const WH_MOUSE: c_int = 7; +pub const WH_HARDWARE: c_int = 8; +pub const WH_DEBUG: c_int = 9; +pub const WH_SHELL: c_int = 10; +pub const WH_FOREGROUNDIDLE: c_int = 11; +pub const WH_CALLWNDPROCRET: c_int = 12; +pub const WH_KEYBOARD_LL: c_int = 13; +pub const WH_MOUSE_LL: c_int = 14; +pub const WH_MAX: c_int = 14; +pub const WH_MINHOOK: c_int = WH_MIN; +pub const WH_MAXHOOK: c_int = WH_MAX; +pub const HC_ACTION: c_int = 0; +pub const HC_GETNEXT: c_int = 1; +pub const HC_SKIP: c_int = 2; +pub const HC_NOREMOVE: c_int = 3; +pub const HC_NOREM: c_int = HC_NOREMOVE; +pub const HC_SYSMODALON: c_int = 4; +pub const HC_SYSMODALOFF: c_int = 5; +pub const HCBT_MOVESIZE: c_int = 0; +pub const HCBT_MINMAX: c_int = 1; +pub const HCBT_QS: c_int = 2; +pub const HCBT_CREATEWND: c_int = 3; +pub const HCBT_DESTROYWND: c_int = 4; +pub const HCBT_ACTIVATE: c_int = 5; +pub const HCBT_CLICKSKIPPED: c_int = 6; +pub const HCBT_KEYSKIPPED: c_int = 7; +pub const HCBT_SYSCOMMAND: c_int = 8; +pub const HCBT_SETFOCUS: c_int = 9; +STRUCT!{struct CBT_CREATEWNDA { + lpcs: *mut CREATESTRUCTA, + hwndInsertAfter: HWND, +}} +pub type LPCBT_CREATEWNDA = *mut CBT_CREATEWNDA; +STRUCT!{struct CBT_CREATEWNDW { + lpcs: *mut CREATESTRUCTW, + hwndInsertAfter: HWND, +}} +pub type LPCBT_CREATEWNDW = *mut CBT_CREATEWNDW; +STRUCT!{struct CBTACTIVATESTRUCT { + fMouse: BOOL, + hWndActive: HWND, +}} +pub type LPCBTACTIVATESTRUCT = *mut CBTACTIVATESTRUCT; +STRUCT!{struct WTSSESSION_NOTIFICATION { + cbSize: DWORD, + dwSessionId: DWORD, +}} +pub type PWTSSESSION_NOTIFICATION = *mut WTSSESSION_NOTIFICATION; +pub const WTS_CONSOLE_CONNECT: WPARAM = 0x1; +pub const WTS_CONSOLE_DISCONNECT: WPARAM = 0x2; +pub const WTS_REMOTE_CONNECT: WPARAM = 0x3; +pub const WTS_REMOTE_DISCONNECT: WPARAM = 0x4; +pub const WTS_SESSION_LOGON: WPARAM = 0x5; +pub const WTS_SESSION_LOGOFF: WPARAM = 0x6; +pub const WTS_SESSION_LOCK: WPARAM = 0x7; +pub const WTS_SESSION_UNLOCK: WPARAM = 0x8; +pub const WTS_SESSION_REMOTE_CONTROL: WPARAM = 0x9; +pub const WTS_SESSION_CREATE: WPARAM = 0xa; +pub const WTS_SESSION_TERMINATE: WPARAM = 0xb; +pub const MSGF_DIALOGBOX: c_int = 0; +pub const MSGF_MESSAGEBOX: c_int = 1; +pub const MSGF_MENU: c_int = 2; +pub const MSGF_SCROLLBAR: c_int = 5; +pub const MSGF_NEXTWINDOW: c_int = 6; +pub const MSGF_MAX: c_int = 8; +pub const MSGF_USER: c_int = 4096; +pub const HSHELL_WINDOWCREATED: c_int = 1; +pub const HSHELL_WINDOWDESTROYED: c_int = 2; +pub const HSHELL_ACTIVATESHELLWINDOW: c_int = 3; +pub const HSHELL_WINDOWACTIVATED: c_int = 4; +pub const HSHELL_GETMINRECT: c_int = 5; +pub const HSHELL_REDRAW: c_int = 6; +pub const HSHELL_TASKMAN: c_int = 7; +pub const HSHELL_LANGUAGE: c_int = 8; +pub const HSHELL_SYSMENU: c_int = 9; +pub const HSHELL_ENDTASK: c_int = 10; +pub const HSHELL_ACCESSIBILITYSTATE: c_int = 11; +pub const HSHELL_APPCOMMAND: c_int = 12; +pub const HSHELL_WINDOWREPLACED: c_int = 13; +pub const HSHELL_WINDOWREPLACING: c_int = 14; +pub const HSHELL_MONITORCHANGED: c_int = 16; +pub const HSHELL_HIGHBIT: c_int = 0x8000; +pub const HSHELL_FLASH: c_int = HSHELL_REDRAW | HSHELL_HIGHBIT; +pub const HSHELL_RUDEAPPACTIVATED: c_int = HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT; +pub const APPCOMMAND_BROWSER_BACKWARD: c_short = 1; +pub const APPCOMMAND_BROWSER_FORWARD: c_short = 2; +pub const APPCOMMAND_BROWSER_REFRESH: c_short = 3; +pub const APPCOMMAND_BROWSER_STOP: c_short = 4; +pub const APPCOMMAND_BROWSER_SEARCH: c_short = 5; +pub const APPCOMMAND_BROWSER_FAVORITES: c_short = 6; +pub const APPCOMMAND_BROWSER_HOME: c_short = 7; +pub const APPCOMMAND_VOLUME_MUTE: c_short = 8; +pub const APPCOMMAND_VOLUME_DOWN: c_short = 9; +pub const APPCOMMAND_VOLUME_UP: c_short = 10; +pub const APPCOMMAND_MEDIA_NEXTTRACK: c_short = 11; +pub const APPCOMMAND_MEDIA_PREVIOUSTRACK: c_short = 12; +pub const APPCOMMAND_MEDIA_STOP: c_short = 13; +pub const APPCOMMAND_MEDIA_PLAY_PAUSE: c_short = 14; +pub const APPCOMMAND_LAUNCH_MAIL: c_short = 15; +pub const APPCOMMAND_LAUNCH_MEDIA_SELECT: c_short = 16; +pub const APPCOMMAND_LAUNCH_APP1: c_short = 17; +pub const APPCOMMAND_LAUNCH_APP2: c_short = 18; +pub const APPCOMMAND_BASS_DOWN: c_short = 19; +pub const APPCOMMAND_BASS_BOOST: c_short = 20; +pub const APPCOMMAND_BASS_UP: c_short = 21; +pub const APPCOMMAND_TREBLE_DOWN: c_short = 22; +pub const APPCOMMAND_TREBLE_UP: c_short = 23; +pub const APPCOMMAND_MICROPHONE_VOLUME_MUTE: c_short = 24; +pub const APPCOMMAND_MICROPHONE_VOLUME_DOWN: c_short = 25; +pub const APPCOMMAND_MICROPHONE_VOLUME_UP: c_short = 26; +pub const APPCOMMAND_HELP: c_short = 27; +pub const APPCOMMAND_FIND: c_short = 28; +pub const APPCOMMAND_NEW: c_short = 29; +pub const APPCOMMAND_OPEN: c_short = 30; +pub const APPCOMMAND_CLOSE: c_short = 31; +pub const APPCOMMAND_SAVE: c_short = 32; +pub const APPCOMMAND_PRINT: c_short = 33; +pub const APPCOMMAND_UNDO: c_short = 34; +pub const APPCOMMAND_REDO: c_short = 35; +pub const APPCOMMAND_COPY: c_short = 36; +pub const APPCOMMAND_CUT: c_short = 37; +pub const APPCOMMAND_PASTE: c_short = 38; +pub const APPCOMMAND_REPLY_TO_MAIL: c_short = 39; +pub const APPCOMMAND_FORWARD_MAIL: c_short = 40; +pub const APPCOMMAND_SEND_MAIL: c_short = 41; +pub const APPCOMMAND_SPELL_CHECK: c_short = 42; +pub const APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE: c_short = 43; +pub const APPCOMMAND_MIC_ON_OFF_TOGGLE: c_short = 44; +pub const APPCOMMAND_CORRECTION_LIST: c_short = 45; +pub const APPCOMMAND_MEDIA_PLAY: c_short = 46; +pub const APPCOMMAND_MEDIA_PAUSE: c_short = 47; +pub const APPCOMMAND_MEDIA_RECORD: c_short = 48; +pub const APPCOMMAND_MEDIA_FAST_FORWARD: c_short = 49; +pub const APPCOMMAND_MEDIA_REWIND: c_short = 50; +pub const APPCOMMAND_MEDIA_CHANNEL_UP: c_short = 51; +pub const APPCOMMAND_MEDIA_CHANNEL_DOWN: c_short = 52; +pub const APPCOMMAND_DELETE: c_short = 53; +pub const APPCOMMAND_DWM_FLIP3D: c_short = 54; +pub const FAPPCOMMAND_MOUSE: WORD = 0x8000; +pub const FAPPCOMMAND_KEY: WORD = 0; +pub const FAPPCOMMAND_OEM: WORD = 0x1000; +pub const FAPPCOMMAND_MASK: WORD = 0xF000; +#[inline] +pub fn GET_APPCOMMAND_LPARAM(lParam: LPARAM) -> c_short { + (HIWORD(lParam as DWORD) & !FAPPCOMMAND_MASK) as c_short +} +#[inline] +pub fn GET_DEVICE_LPARAM(lParam: LPARAM) -> WORD { + HIWORD(lParam as DWORD) & FAPPCOMMAND_MASK +} +pub use self::GET_DEVICE_LPARAM as GET_MOUSEORKEY_LPARAM; +pub use shared::minwindef::LOWORD as GET_FLAGS_LPARAM; +pub use self::GET_FLAGS_LPARAM as GET_KEYSTATE_LPARAM; +STRUCT!{struct SHELLHOOKINFO { + hwnd: HWND, + rc: RECT, +}} +pub type LPSHELLHOOKINFO = *mut SHELLHOOKINFO; +STRUCT!{struct EVENTMSG { + message: UINT, + paramL: UINT, + paramH: UINT, + time: DWORD, + hwnd: HWND, +}} +pub type PEVENTMSGMSG = *mut EVENTMSG; +pub type NPEVENTMSGMSG = *mut EVENTMSG; +pub type LPEVENTMSGMSG = *mut EVENTMSG; +pub type PEVENTMSG = *mut EVENTMSG; +pub type NPEVENTMSG = *mut EVENTMSG; +pub type LPEVENTMSG = *mut EVENTMSG; +STRUCT!{struct CWPSTRUCT { + lParam: LPARAM, + wParam: WPARAM, + message: UINT, + hwnd: HWND, +}} +pub type PCWPSTRUCT = *mut CWPSTRUCT; +pub type NPCWPSTRUCT = *mut CWPSTRUCT; +pub type LPCWPSTRUCT = *mut CWPSTRUCT; +STRUCT!{struct CWPRETSTRUCT { + lResult: LRESULT, + lParam: LPARAM, + wParam: WPARAM, + message: UINT, + hwnd: HWND, +}} +pub type PCWPRETSTRUCT = *mut CWPRETSTRUCT; +pub type NPCWPRETSTRUCT = *mut CWPRETSTRUCT; +pub type LPCWPRETSTRUCT = *mut CWPRETSTRUCT; +pub const LLKHF_EXTENDED: DWORD = (KF_EXTENDED >> 8) as u32; +pub const LLKHF_INJECTED: DWORD = 0x00000010; +pub const LLKHF_ALTDOWN: DWORD = (KF_ALTDOWN >> 8) as u32; +pub const LLKHF_UP: DWORD = (KF_UP >> 8) as u32; +pub const LLKHF_LOWER_IL_INJECTED: DWORD = 0x00000002; +pub const LLMHF_INJECTED: DWORD = 0x00000001; +pub const LLMHF_LOWER_IL_INJECTED: DWORD = 0x00000002; +STRUCT!{struct KBDLLHOOKSTRUCT { + vkCode: DWORD, + scanCode: DWORD, + flags: DWORD, + time: DWORD, + dwExtraInfo: ULONG_PTR, +}} +pub type LPKBDLLHOOKSTRUCT = *mut KBDLLHOOKSTRUCT; +pub type PKBDLLHOOKSTRUCT = *mut KBDLLHOOKSTRUCT; +STRUCT!{struct MSLLHOOKSTRUCT { + pt: POINT, + mouseData: DWORD, + flags: DWORD, + time: DWORD, + dwExtraInfo: ULONG_PTR, +}} +pub type LPMSLLHOOKSTRUCT = *mut MSLLHOOKSTRUCT; +pub type PMSLLHOOKSTRUCT = *mut MSLLHOOKSTRUCT; +STRUCT!{struct DEBUGHOOKINFO { + idThread: DWORD, + idThreadInstaller: DWORD, + lParam: LPARAM, + wParam: WPARAM, + code: c_int, +}} +pub type PDEBUGHOOKINFO = *mut DEBUGHOOKINFO; +pub type NPDEBUGHOOKINFO = *mut DEBUGHOOKINFO; +pub type LPDEBUGHOOKINFO = *mut DEBUGHOOKINFO; +STRUCT!{struct MOUSEHOOKSTRUCT { + pt: POINT, + hwnd: HWND, + wHitTestCode: UINT, + dwExtraInfo: ULONG_PTR, +}} +pub type LPMOUSEHOOKSTRUCT = *mut MOUSEHOOKSTRUCT; +pub type PMOUSEHOOKSTRUCT = *mut MOUSEHOOKSTRUCT; +STRUCT!{struct MOUSEHOOKSTRUCTEX { + parent: MOUSEHOOKSTRUCT, + mouseData: DWORD, +}} +pub type LPMOUSEHOOKSTRUCTEX = *mut MOUSEHOOKSTRUCTEX; +pub type PMOUSEHOOKSTRUCTEX = *mut MOUSEHOOKSTRUCTEX; +STRUCT!{struct HARDWAREHOOKSTRUCT { + hwnd: HWND, + message: UINT, + wParam: WPARAM, + lParam: LPARAM, +}} +pub type LPHARDWAREHOOKSTRUCT = *mut HARDWAREHOOKSTRUCT; +pub type PHARDWAREHOOKSTRUCT = *mut HARDWAREHOOKSTRUCT; +pub const HKL_PREV: HKL = 0 as HKL; +pub const HKL_NEXT: HKL = 1 as HKL; +pub const KLF_ACTIVATE: UINT = 0x00000001; +pub const KLF_SUBSTITUTE_OK: UINT = 0x00000002; +pub const KLF_REORDER: UINT = 0x00000008; +pub const KLF_REPLACELANG: UINT = 0x00000010; +pub const KLF_NOTELLSHELL: UINT = 0x00000080; +pub const KLF_SETFORPROCESS: UINT = 0x00000100; +pub const KLF_SHIFTLOCK: UINT = 0x00010000; +pub const KLF_RESET: UINT = 0x40000000; +pub const INPUTLANGCHANGE_SYSCHARSET: WPARAM = 0x0001; +pub const INPUTLANGCHANGE_FORWARD: WPARAM = 0x0002; +pub const INPUTLANGCHANGE_BACKWARD: WPARAM = 0x0004; +pub const KL_NAMELENGTH: usize = 9; +extern "system" { + pub fn LoadKeyboardLayoutA( + pwszKLID: LPCSTR, + Flags: DWORD, + ) -> HKL; + pub fn LoadKeyboardLayoutW( + pwszKLID: LPCWSTR, + Flags: DWORD, + ) -> HKL; + pub fn ActivateKeyboardLayout( + hkl: HKL, + Flags: UINT, + ) -> HKL; + pub fn ToUnicodeEx( + wVirtKey: UINT, + wScanCode: UINT, + lpKeyState: *const BYTE, + pwszBuff: LPWSTR, + cchBuff: c_int, + wFlags: UINT, + dwhkl: HKL, + ) -> c_int; + pub fn UnloadKeyboardLayout( + hkl: HKL, + ) -> BOOL; + pub fn GetKeyboardLayoutNameA( + pwszKLID: LPSTR, + ) -> BOOL; + pub fn GetKeyboardLayoutNameW( + pwszKLID: LPWSTR, + ) -> BOOL; + pub fn GetKeyboardLayoutList( + nBuff: c_int, + lpList: *mut HKL, + ) -> c_int; + pub fn GetKeyboardLayout( + idThread: DWORD, + ) -> HKL; +} +STRUCT!{struct MOUSEMOVEPOINT { + x: c_int, + y: c_int, + time: DWORD, + dwExtraInfo: ULONG_PTR, +}} +pub type PMOUSEMOVEPOINT = *mut MOUSEMOVEPOINT; +pub type LPMOUSEMOVEPOINT = *mut MOUSEMOVEPOINT; +pub const GMMP_USE_DISPLAY_POINTS: DWORD = 1; +pub const GMMP_USE_HIGH_RESOLUTION_POINTS: DWORD = 2; +extern "system" { + pub fn GetMouseMovePointsEx( + cbSize: UINT, + lppt: LPMOUSEMOVEPOINT, + lpptBuf: LPMOUSEMOVEPOINT, + nBufPoints: c_int, + resolution: DWORD, + ) -> c_int; +} +pub const DESKTOP_READOBJECTS: DWORD = 0x0001; +pub const DESKTOP_CREATEWINDOW: DWORD = 0x0002; +pub const DESKTOP_CREATEMENU: DWORD = 0x0004; +pub const DESKTOP_HOOKCONTROL: DWORD = 0x0008; +pub const DESKTOP_JOURNALRECORD: DWORD = 0x0010; +pub const DESKTOP_JOURNALPLAYBACK: DWORD = 0x0020; +pub const DESKTOP_ENUMERATE: DWORD = 0x0040; +pub const DESKTOP_WRITEOBJECTS: DWORD = 0x0080; +pub const DESKTOP_SWITCHDESKTOP: DWORD = 0x0100; +pub const DF_ALLOWOTHERACCOUNTHOOK: DWORD = 0x0001; +extern "system" { + pub fn CreateDesktopA( + lpszDesktop: LPCSTR, + lpszDevice: LPCSTR, + pDevmode: *mut DEVMODEA, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ) -> HDESK; + pub fn CreateDesktopW( + lpszDesktop: LPCWSTR, + lpszDevice: LPCWSTR, + pDevmode: *mut DEVMODEW, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ) -> HDESK; + pub fn CreateDesktopExA( + lpszDesktop: LPCSTR, + lpszDevice: LPCSTR, + pDevmode: *mut DEVMODEA, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ulHeapSize: ULONG, + pvoid: PVOID, + ) -> HDESK; + pub fn CreateDesktopExW( + lpszDesktop: LPCWSTR, + lpszDevice: LPCWSTR, + pDevmode: *mut DEVMODEW, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ulHeapSize: ULONG, + pvoid: PVOID, + ) -> HDESK; + pub fn OpenDesktopA( + lpszDesktop: LPCSTR, + dwFlags: DWORD, + fInherit: BOOL, + dwDesiredAccess: ACCESS_MASK, + ) -> HDESK; + pub fn OpenDesktopW( + lpszDesktop: LPCWSTR, + dwFlags: DWORD, + fInherit: BOOL, + dwDesiredAccess: ACCESS_MASK, + ) -> HDESK; + pub fn OpenInputDesktop( + dwFlags: DWORD, + fInherit: BOOL, + dwDesiredAccess: ACCESS_MASK, + ) -> HDESK; + pub fn EnumDesktopsA( + hwinsta: HWINSTA, + lpEnumFunc: DESKTOPENUMPROCA, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumDesktopsW( + hwinsta: HWINSTA, + lpEnumFunc: DESKTOPENUMPROCW, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumDesktopWindows( + hDesktop: HDESK, + lpfn: WNDENUMPROC, + lParam: LPARAM, + ) -> BOOL; + pub fn SwitchDesktop( + hDesktop: HDESK, + ) -> BOOL; + pub fn SetThreadDesktop( + hDesktop: HDESK, + ) -> BOOL; + pub fn CloseDesktop( + hDesktop: HDESK, + ) -> BOOL; + pub fn GetThreadDesktop( + dwThreadId: DWORD, + ) -> HDESK; +} +pub const WINSTA_ENUMDESKTOPS: DWORD = 0x0001; +pub const WINSTA_READATTRIBUTES: DWORD = 0x0002; +pub const WINSTA_ACCESSCLIPBOARD: DWORD = 0x0004; +pub const WINSTA_CREATEDESKTOP: DWORD = 0x0008; +pub const WINSTA_WRITEATTRIBUTES: DWORD = 0x0010; +pub const WINSTA_ACCESSGLOBALATOMS: DWORD = 0x0020; +pub const WINSTA_EXITWINDOWS: DWORD = 0x0040; +pub const WINSTA_ENUMERATE: DWORD = 0x0100; +pub const WINSTA_READSCREEN: DWORD = 0x0200; +pub const WINSTA_ALL_ACCESS: DWORD = WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES + | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES + | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN; +pub const CWF_CREATE_ONLY: DWORD = 0x00000001; +pub const WSF_VISIBLE: DWORD = 0x0001; +extern "system" { + pub fn CreateWindowStationA( + lpwinsta: LPCSTR, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ) -> HWINSTA; + pub fn CreateWindowStationW( + lpwinsta: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: ACCESS_MASK, + lpsa: LPSECURITY_ATTRIBUTES, + ) -> HWINSTA; + pub fn OpenWindowStationA( + lpszWinSta: LPCSTR, + fInherit: BOOL, + dwDesiredAccess: ACCESS_MASK, + ) -> HWINSTA; + pub fn OpenWindowStationW( + lpszWinSta: LPCWSTR, + fInherit: BOOL, + dwDesiredAccess: ACCESS_MASK, + ) -> HWINSTA; + pub fn EnumWindowStationsA( + lpEnumFunc: WINSTAENUMPROCA, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumWindowStationsW( + lpEnumFunc: WINSTAENUMPROCW, + lParam: LPARAM, + ) -> BOOL; + pub fn CloseWindowStation( + hWinSta: HWINSTA, + ) -> BOOL; + pub fn SetProcessWindowStation( + hWinSta: HWINSTA, + ) -> BOOL; + pub fn GetProcessWindowStation() -> HWINSTA; + pub fn SetUserObjectSecurity( + hObj: HANDLE, + pSIRequested: PSECURITY_INFORMATION, + pSID: PSECURITY_DESCRIPTOR, + ) -> BOOL; + pub fn GetUserObjectSecurity( + hObj: HANDLE, + pSIRequested: PSECURITY_INFORMATION, + pSID: PSECURITY_DESCRIPTOR, + nLength: DWORD, + lpnLengthNeeded: LPDWORD, + ) -> BOOL; +} +pub const UOI_FLAGS: DWORD = 1; +pub const UOI_NAME: DWORD = 2; +pub const UOI_TYPE: DWORD = 3; +pub const UOI_USER_SID: DWORD = 4; +pub const UOI_HEAPSIZE: DWORD = 5; +pub const UOI_IO: DWORD = 6; +pub const UOI_TIMERPROC_EXCEPTION_SUPPRESSION: DWORD = 7; +STRUCT!{struct USEROBJECTFLAGS { + fInherit: BOOL, + fReserved: BOOL, + dwFlags: DWORD, +}} +pub type PUSEROBJECTFLAGS = *mut USEROBJECTFLAGS; +extern "system" { + pub fn GetUserObjectInformationA( + hObj: HANDLE, + nIndex: c_int, + pvInfo: PVOID, + nLength: DWORD, + lpnLengthNeeded: LPDWORD, + ) -> BOOL; + pub fn GetUserObjectInformationW( + hObj: HANDLE, + nIndex: c_int, + pvInfo: PVOID, + nLength: DWORD, + lpnLengthNeeded: LPDWORD, + ) -> BOOL; + pub fn SetUserObjectInformationA( + hObj: HANDLE, + nIndex: c_int, + pvInfo: PVOID, + nLength: DWORD, + ) -> BOOL; + pub fn SetUserObjectInformationW( + hObj: HANDLE, + nIndex: c_int, + pvInfo: PVOID, + nLength: DWORD, + ) -> BOOL; +} +STRUCT!{struct WNDCLASSEXA { + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, + hIconSm: HICON, +}} +pub type PWNDCLASSEXA = *mut WNDCLASSEXA; +pub type NPWNDCLASSEXA = *mut WNDCLASSEXA; +pub type LPWNDCLASSEXA = *mut WNDCLASSEXA; +STRUCT!{struct WNDCLASSEXW { + cbSize: UINT, + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, + hIconSm: HICON, +}} +pub type PWNDCLASSEXW = *mut WNDCLASSEXW; +pub type NPWNDCLASSEXW = *mut WNDCLASSEXW; +pub type LPWNDCLASSEXW = *mut WNDCLASSEXW; +STRUCT!{struct WNDCLASSA { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCSTR, + lpszClassName: LPCSTR, +}} +pub type PWNDCLASSA = *mut WNDCLASSA; +pub type NPWNDCLASSA = *mut WNDCLASSA; +pub type LPWNDCLASSA = *mut WNDCLASSA; +STRUCT!{struct WNDCLASSW { + style: UINT, + lpfnWndProc: WNDPROC, + cbClsExtra: c_int, + cbWndExtra: c_int, + hInstance: HINSTANCE, + hIcon: HICON, + hCursor: HCURSOR, + hbrBackground: HBRUSH, + lpszMenuName: LPCWSTR, + lpszClassName: LPCWSTR, +}} +pub type PWNDCLASSW = *mut WNDCLASSW; +pub type NPWNDCLASSW = *mut WNDCLASSW; +pub type LPWNDCLASSW = *mut WNDCLASSW; +extern "system" { + pub fn IsHungAppWindow( + hwnd: HWND, + ) -> BOOL; + pub fn DisableProcessWindowsGhosting(); +} +STRUCT!{struct MSG { + hwnd: HWND, + message: UINT, + wParam: WPARAM, + lParam: LPARAM, + time: DWORD, + pt: POINT, +}} +pub type PMSG = *mut MSG; +pub type NPMSG = *mut MSG; +pub type LPMSG = *mut MSG; +//POINTSTOPOINT +//POINTTOPOINTS +//MAKEWPARAM +//MAKELPARAM +//MAKELRESULT +pub const GWL_WNDPROC: c_int = -4; +pub const GWL_HINSTANCE: c_int = -6; +pub const GWL_HWNDPARENT: c_int = -8; +pub const GWL_STYLE: c_int = -16; +pub const GWL_EXSTYLE: c_int = -20; +pub const GWL_USERDATA: c_int = -21; +pub const GWL_ID: c_int = -12; +pub const GWLP_WNDPROC: c_int = -4; +pub const GWLP_HINSTANCE: c_int = -6; +pub const GWLP_HWNDPARENT: c_int = -8; +pub const GWLP_USERDATA: c_int = -21; +pub const GWLP_ID: c_int = -12; +pub const GCL_MENUNAME: c_int = -8; +pub const GCL_HBRBACKGROUND: c_int = -10; +pub const GCL_HCURSOR: c_int = -12; +pub const GCL_HICON: c_int = -14; +pub const GCL_HMODULE: c_int = -16; +pub const GCL_CBWNDEXTRA: c_int = -18; +pub const GCL_CBCLSEXTRA: c_int = -20; +pub const GCL_WNDPROC: c_int = -24; +pub const GCL_STYLE: c_int = -26; +pub const GCW_ATOM: c_int = -32; +pub const GCL_HICONSM: c_int = -34; +pub const GCLP_MENUNAME: c_int = -8; +pub const GCLP_HBRBACKGROUND: c_int = -10; +pub const GCLP_HCURSOR: c_int = -12; +pub const GCLP_HICON: c_int = -14; +pub const GCLP_HMODULE: c_int = -16; +pub const GCLP_WNDPROC: c_int = -24; +pub const GCLP_HICONSM: c_int = -34; +pub const WM_NULL: UINT = 0x0000; +pub const WM_CREATE: UINT = 0x0001; +pub const WM_DESTROY: UINT = 0x0002; +pub const WM_MOVE: UINT = 0x0003; +pub const WM_SIZE: UINT = 0x0005; +pub const WM_ACTIVATE: UINT = 0x0006; +pub const WA_INACTIVE: WORD = 0; +pub const WA_ACTIVE: WORD = 1; +pub const WA_CLICKACTIVE: WORD = 2; +pub const WM_SETFOCUS: UINT = 0x0007; +pub const WM_KILLFOCUS: UINT = 0x0008; +pub const WM_ENABLE: UINT = 0x000A; +pub const WM_SETREDRAW: UINT = 0x000B; +pub const WM_SETTEXT: UINT = 0x000C; +pub const WM_GETTEXT: UINT = 0x000D; +pub const WM_GETTEXTLENGTH: UINT = 0x000E; +pub const WM_PAINT: UINT = 0x000F; +pub const WM_CLOSE: UINT = 0x0010; +pub const WM_QUERYENDSESSION: UINT = 0x0011; +pub const WM_QUERYOPEN: UINT = 0x0013; +pub const WM_ENDSESSION: UINT = 0x0016; +pub const WM_QUIT: UINT = 0x0012; +pub const WM_ERASEBKGND: UINT = 0x0014; +pub const WM_SYSCOLORCHANGE: UINT = 0x0015; +pub const WM_SHOWWINDOW: UINT = 0x0018; +pub const WM_WININICHANGE: UINT = 0x001A; +pub const WM_SETTINGCHANGE: UINT = WM_WININICHANGE; +pub const WM_DEVMODECHANGE: UINT = 0x001B; +pub const WM_ACTIVATEAPP: UINT = 0x001C; +pub const WM_FONTCHANGE: UINT = 0x001D; +pub const WM_TIMECHANGE: UINT = 0x001E; +pub const WM_CANCELMODE: UINT = 0x001F; +pub const WM_SETCURSOR: UINT = 0x0020; +pub const WM_MOUSEACTIVATE: UINT = 0x0021; +pub const WM_CHILDACTIVATE: UINT = 0x0022; +pub const WM_QUEUESYNC: UINT = 0x0023; +pub const WM_GETMINMAXINFO: UINT = 0x0024; +STRUCT!{struct MINMAXINFO { + ptReserved: POINT, + ptMaxSize: POINT, + ptMaxPosition: POINT, + ptMinTrackSize: POINT, + ptMaxTrackSize: POINT, +}} +pub type PMINMAXINFO = *mut MINMAXINFO; +pub type LPMINMAXINFO = *mut MINMAXINFO; +pub const WM_PAINTICON: UINT = 0x0026; +pub const WM_ICONERASEBKGND: UINT = 0x0027; +pub const WM_NEXTDLGCTL: UINT = 0x0028; +pub const WM_SPOOLERSTATUS: UINT = 0x002A; +pub const WM_DRAWITEM: UINT = 0x002B; +pub const WM_MEASUREITEM: UINT = 0x002C; +pub const WM_DELETEITEM: UINT = 0x002D; +pub const WM_VKEYTOITEM: UINT = 0x002E; +pub const WM_CHARTOITEM: UINT = 0x002F; +pub const WM_SETFONT: UINT = 0x0030; +pub const WM_GETFONT: UINT = 0x0031; +pub const WM_SETHOTKEY: UINT = 0x0032; +pub const WM_GETHOTKEY: UINT = 0x0033; +pub const WM_QUERYDRAGICON: UINT = 0x0037; +pub const WM_COMPAREITEM: UINT = 0x0039; +pub const WM_GETOBJECT: UINT = 0x003D; +pub const WM_COMPACTING: UINT = 0x0041; +pub const WM_COMMNOTIFY: UINT = 0x0044; +pub const WM_WINDOWPOSCHANGING: UINT = 0x0046; +pub const WM_WINDOWPOSCHANGED: UINT = 0x0047; +pub const WM_POWER: UINT = 0x0048; +pub const PWR_OK: WPARAM = 1; +pub const PWR_FAIL: WPARAM = -1isize as usize; +pub const PWR_SUSPENDREQUEST: WPARAM = 1; +pub const PWR_SUSPENDRESUME: WPARAM = 2; +pub const PWR_CRITICALRESUME: WPARAM = 3; +pub const WM_COPYDATA: UINT = 0x004A; +pub const WM_CANCELJOURNAL: UINT = 0x004B; +STRUCT!{struct COPYDATASTRUCT { + dwData: ULONG_PTR, + cbData: DWORD, + lpData: PVOID, +}} +pub type PCOPYDATASTRUCT = *mut COPYDATASTRUCT; +STRUCT!{struct MDINEXTMENU { + hmenuIn: HMENU, + hmenuNext: HMENU, + hwndNext: HWND, +}} +pub type PMDINEXTMENU = *mut MDINEXTMENU; +pub type LPMDINEXTMENU = *mut MDINEXTMENU; +pub const WM_NOTIFY: UINT = 0x004E; +pub const WM_INPUTLANGCHANGEREQUEST: UINT = 0x0050; +pub const WM_INPUTLANGCHANGE: UINT = 0x0051; +pub const WM_TCARD: UINT = 0x0052; +pub const WM_HELP: UINT = 0x0053; +pub const WM_USERCHANGED: UINT = 0x0054; +pub const WM_NOTIFYFORMAT: UINT = 0x0055; +pub const NFR_ANSI: LRESULT = 1; +pub const NFR_UNICODE: LRESULT = 2; +pub const NF_QUERY: LPARAM = 3; +pub const NF_REQUERY: LPARAM = 4; +pub const WM_CONTEXTMENU: UINT = 0x007B; +pub const WM_STYLECHANGING: UINT = 0x007C; +pub const WM_STYLECHANGED: UINT = 0x007D; +pub const WM_DISPLAYCHANGE: UINT = 0x007E; +pub const WM_GETICON: UINT = 0x007F; +pub const WM_SETICON: UINT = 0x0080; +pub const WM_NCCREATE: UINT = 0x0081; +pub const WM_NCDESTROY: UINT = 0x0082; +pub const WM_NCCALCSIZE: UINT = 0x0083; +pub const WM_NCHITTEST: UINT = 0x0084; +pub const WM_NCPAINT: UINT = 0x0085; +pub const WM_NCACTIVATE: UINT = 0x0086; +pub const WM_GETDLGCODE: UINT = 0x0087; +pub const WM_SYNCPAINT: UINT = 0x0088; +pub const WM_NCMOUSEMOVE: UINT = 0x00A0; +pub const WM_NCLBUTTONDOWN: UINT = 0x00A1; +pub const WM_NCLBUTTONUP: UINT = 0x00A2; +pub const WM_NCLBUTTONDBLCLK: UINT = 0x00A3; +pub const WM_NCRBUTTONDOWN: UINT = 0x00A4; +pub const WM_NCRBUTTONUP: UINT = 0x00A5; +pub const WM_NCRBUTTONDBLCLK: UINT = 0x00A6; +pub const WM_NCMBUTTONDOWN: UINT = 0x00A7; +pub const WM_NCMBUTTONUP: UINT = 0x00A8; +pub const WM_NCMBUTTONDBLCLK: UINT = 0x00A9; +pub const WM_NCXBUTTONDOWN: UINT = 0x00AB; +pub const WM_NCXBUTTONUP: UINT = 0x00AC; +pub const WM_NCXBUTTONDBLCLK: UINT = 0x00AD; +pub const WM_INPUT_DEVICE_CHANGE: UINT = 0x00FE; +pub const WM_INPUT: UINT = 0x00FF; +pub const WM_KEYFIRST: UINT = 0x0100; +pub const WM_KEYDOWN: UINT = 0x0100; +pub const WM_KEYUP: UINT = 0x0101; +pub const WM_CHAR: UINT = 0x0102; +pub const WM_DEADCHAR: UINT = 0x0103; +pub const WM_SYSKEYDOWN: UINT = 0x0104; +pub const WM_SYSKEYUP: UINT = 0x0105; +pub const WM_SYSCHAR: UINT = 0x0106; +pub const WM_SYSDEADCHAR: UINT = 0x0107; +pub const WM_UNICHAR: UINT = 0x0109; +pub const WM_KEYLAST: UINT = 0x0109; +pub const UNICODE_NOCHAR: WPARAM = 0xFFFF; +pub const WM_IME_STARTCOMPOSITION: UINT = 0x010D; +pub const WM_IME_ENDCOMPOSITION: UINT = 0x010E; +pub const WM_IME_COMPOSITION: UINT = 0x010F; +pub const WM_IME_KEYLAST: UINT = 0x010F; +pub const WM_INITDIALOG: UINT = 0x0110; +pub const WM_COMMAND: UINT = 0x0111; +pub const WM_SYSCOMMAND: UINT = 0x0112; +pub const WM_TIMER: UINT = 0x0113; +pub const WM_HSCROLL: UINT = 0x0114; +pub const WM_VSCROLL: UINT = 0x0115; +pub const WM_INITMENU: UINT = 0x0116; +pub const WM_INITMENUPOPUP: UINT = 0x0117; +pub const WM_GESTURE: UINT = 0x0119; +pub const WM_GESTURENOTIFY: UINT = 0x011A; +pub const WM_MENUSELECT: UINT = 0x011F; +pub const WM_MENUCHAR: UINT = 0x0120; +pub const WM_ENTERIDLE: UINT = 0x0121; +pub const WM_MENURBUTTONUP: UINT = 0x0122; +pub const WM_MENUDRAG: UINT = 0x0123; +pub const WM_MENUGETOBJECT: UINT = 0x0124; +pub const WM_UNINITMENUPOPUP: UINT = 0x0125; +pub const WM_MENUCOMMAND: UINT = 0x0126; +pub const WM_CHANGEUISTATE: UINT = 0x0127; +pub const WM_UPDATEUISTATE: UINT = 0x0128; +pub const WM_QUERYUISTATE: UINT = 0x0129; +pub const UIS_SET: WORD = 1; +pub const UIS_CLEAR: WORD = 2; +pub const UIS_INITIALIZE: WORD = 3; +pub const UISF_HIDEFOCUS: WORD = 0x1; +pub const UISF_HIDEACCEL: WORD = 0x2; +pub const UISF_ACTIVE: WORD = 0x4; +pub const WM_CTLCOLORMSGBOX: UINT = 0x0132; +pub const WM_CTLCOLOREDIT: UINT = 0x0133; +pub const WM_CTLCOLORLISTBOX: UINT = 0x0134; +pub const WM_CTLCOLORBTN: UINT = 0x0135; +pub const WM_CTLCOLORDLG: UINT = 0x0136; +pub const WM_CTLCOLORSCROLLBAR: UINT = 0x0137; +pub const WM_CTLCOLORSTATIC: UINT = 0x0138; +pub const MN_GETHMENU: UINT = 0x01E1; +pub const WM_MOUSEFIRST: UINT = 0x0200; +pub const WM_MOUSEMOVE: UINT = 0x0200; +pub const WM_LBUTTONDOWN: UINT = 0x0201; +pub const WM_LBUTTONUP: UINT = 0x0202; +pub const WM_LBUTTONDBLCLK: UINT = 0x0203; +pub const WM_RBUTTONDOWN: UINT = 0x0204; +pub const WM_RBUTTONUP: UINT = 0x0205; +pub const WM_RBUTTONDBLCLK: UINT = 0x0206; +pub const WM_MBUTTONDOWN: UINT = 0x0207; +pub const WM_MBUTTONUP: UINT = 0x0208; +pub const WM_MBUTTONDBLCLK: UINT = 0x0209; +pub const WM_MOUSEWHEEL: UINT = 0x020A; +pub const WM_XBUTTONDOWN: UINT = 0x020B; +pub const WM_XBUTTONUP: UINT = 0x020C; +pub const WM_XBUTTONDBLCLK: UINT = 0x020D; +pub const WM_MOUSEHWHEEL: UINT = 0x020E; +pub const WM_MOUSELAST: UINT = 0x020E; +pub const WHEEL_DELTA: c_short = 120; +#[inline] +pub fn GET_WHEEL_DELTA_WPARAM(wParam: WPARAM) -> c_short { + HIWORD(wParam as DWORD) as c_short +} +pub const WHEEL_PAGESCROLL: UINT = UINT_MAX; +#[inline] +pub fn GET_KEYSTATE_WPARAM(wParam: WPARAM) -> WORD { + LOWORD(wParam as DWORD) +} +#[inline] +pub fn GET_NCHITTEST_WPARAM(wParam: WPARAM) -> c_short { + LOWORD(wParam as DWORD) as c_short +} +#[inline] +pub fn GET_XBUTTON_WPARAM(wParam: WPARAM) -> WORD { + HIWORD(wParam as DWORD) +} +pub const XBUTTON1: WORD = 0x0001; +pub const XBUTTON2: WORD = 0x0002; +pub const WM_PARENTNOTIFY: UINT = 0x0210; +pub const WM_ENTERMENULOOP: UINT = 0x0211; +pub const WM_EXITMENULOOP: UINT = 0x0212; +pub const WM_NEXTMENU: UINT = 0x0213; +pub const WM_SIZING: UINT = 0x0214; +pub const WM_CAPTURECHANGED: UINT = 0x0215; +pub const WM_MOVING: UINT = 0x0216; +pub const WM_POWERBROADCAST: UINT = 0x0218; +pub const PBT_APMQUERYSUSPEND: WPARAM = 0x0000; +pub const PBT_APMQUERYSTANDBY: WPARAM = 0x0001; +pub const PBT_APMQUERYSUSPENDFAILED: WPARAM = 0x0002; +pub const PBT_APMQUERYSTANDBYFAILED: WPARAM = 0x0003; +pub const PBT_APMSUSPEND: WPARAM = 0x0004; +pub const PBT_APMSTANDBY: WPARAM = 0x0005; +pub const PBT_APMRESUMECRITICAL: WPARAM = 0x0006; +pub const PBT_APMRESUMESUSPEND: WPARAM = 0x0007; +pub const PBT_APMRESUMESTANDBY: WPARAM = 0x0008; +pub const PBTF_APMRESUMEFROMFAILURE: LPARAM = 0x00000001; +pub const PBT_APMBATTERYLOW: WPARAM = 0x0009; +pub const PBT_APMPOWERSTATUSCHANGE: WPARAM = 0x000A; +pub const PBT_APMOEMEVENT: WPARAM = 0x000B; +pub const PBT_APMRESUMEAUTOMATIC: WPARAM = 0x0012; +pub const PBT_POWERSETTINGCHANGE: WPARAM = 0x8013; +STRUCT!{struct POWERBROADCAST_SETTING { + PowerSetting: GUID, + DataLength: DWORD, + Data: [UCHAR; 1], +}} +pub type PPOWERBROADCAST_SETTING = *mut POWERBROADCAST_SETTING; +pub const WM_DEVICECHANGE: UINT = 0x0219; +pub const WM_MDICREATE: UINT = 0x0220; +pub const WM_MDIDESTROY: UINT = 0x0221; +pub const WM_MDIACTIVATE: UINT = 0x0222; +pub const WM_MDIRESTORE: UINT = 0x0223; +pub const WM_MDINEXT: UINT = 0x0224; +pub const WM_MDIMAXIMIZE: UINT = 0x0225; +pub const WM_MDITILE: UINT = 0x0226; +pub const WM_MDICASCADE: UINT = 0x0227; +pub const WM_MDIICONARRANGE: UINT = 0x0228; +pub const WM_MDIGETACTIVE: UINT = 0x0229; +pub const WM_MDISETMENU: UINT = 0x0230; +pub const WM_ENTERSIZEMOVE: UINT = 0x0231; +pub const WM_EXITSIZEMOVE: UINT = 0x0232; +pub const WM_DROPFILES: UINT = 0x0233; +pub const WM_MDIREFRESHMENU: UINT = 0x0234; +pub const WM_POINTERDEVICECHANGE: UINT = 0x238; +pub const WM_POINTERDEVICEINRANGE: UINT = 0x239; +pub const WM_POINTERDEVICEOUTOFRANGE: UINT = 0x23A; +pub const WM_TOUCH: UINT = 0x0240; +pub const WM_NCPOINTERUPDATE: UINT = 0x0241; +pub const WM_NCPOINTERDOWN: UINT = 0x0242; +pub const WM_NCPOINTERUP: UINT = 0x0243; +pub const WM_POINTERUPDATE: UINT = 0x0245; +pub const WM_POINTERDOWN: UINT = 0x0246; +pub const WM_POINTERUP: UINT = 0x0247; +pub const WM_POINTERENTER: UINT = 0x0249; +pub const WM_POINTERLEAVE: UINT = 0x024A; +pub const WM_POINTERACTIVATE: UINT = 0x024B; +pub const WM_POINTERCAPTURECHANGED: UINT = 0x024C; +pub const WM_TOUCHHITTESTING: UINT = 0x024D; +pub const WM_POINTERWHEEL: UINT = 0x024E; +pub const WM_POINTERHWHEEL: UINT = 0x024F; +pub const DM_POINTERHITTEST: UINT = 0x0250; +pub const WM_POINTERROUTEDTO: UINT = 0x0251; +pub const WM_POINTERROUTEDAWAY: UINT = 0x0252; +pub const WM_POINTERROUTEDRELEASED: UINT = 0x0253; +pub const WM_IME_SETCONTEXT: UINT = 0x0281; +pub const WM_IME_NOTIFY: UINT = 0x0282; +pub const WM_IME_CONTROL: UINT = 0x0283; +pub const WM_IME_COMPOSITIONFULL: UINT = 0x0284; +pub const WM_IME_SELECT: UINT = 0x0285; +pub const WM_IME_CHAR: UINT = 0x0286; +pub const WM_IME_REQUEST: UINT = 0x0288; +pub const WM_IME_KEYDOWN: UINT = 0x0290; +pub const WM_IME_KEYUP: UINT = 0x0291; +pub const WM_MOUSEHOVER: UINT = 0x02A1; +pub const WM_MOUSELEAVE: UINT = 0x02A3; +pub const WM_NCMOUSEHOVER: UINT = 0x02A0; +pub const WM_NCMOUSELEAVE: UINT = 0x02A2; +pub const WM_WTSSESSION_CHANGE: UINT = 0x02B1; +pub const WM_TABLET_FIRST: UINT = 0x02c0; +pub const WM_TABLET_LAST: UINT = 0x02df; +pub const WM_DPICHANGED: UINT = 0x02E0; +pub const WM_DPICHANGED_BEFOREPARENT: UINT = 0x02E2; +pub const WM_DPICHANGED_AFTERPARENT: UINT = 0x02E3; +pub const WM_GETDPISCALEDSIZE: UINT = 0x02E4; +pub const WM_CUT: UINT = 0x0300; +pub const WM_COPY: UINT = 0x0301; +pub const WM_PASTE: UINT = 0x0302; +pub const WM_CLEAR: UINT = 0x0303; +pub const WM_UNDO: UINT = 0x0304; +pub const WM_RENDERFORMAT: UINT = 0x0305; +pub const WM_RENDERALLFORMATS: UINT = 0x0306; +pub const WM_DESTROYCLIPBOARD: UINT = 0x0307; +pub const WM_DRAWCLIPBOARD: UINT = 0x0308; +pub const WM_PAINTCLIPBOARD: UINT = 0x0309; +pub const WM_VSCROLLCLIPBOARD: UINT = 0x030A; +pub const WM_SIZECLIPBOARD: UINT = 0x030B; +pub const WM_ASKCBFORMATNAME: UINT = 0x030C; +pub const WM_CHANGECBCHAIN: UINT = 0x030D; +pub const WM_HSCROLLCLIPBOARD: UINT = 0x030E; +pub const WM_QUERYNEWPALETTE: UINT = 0x030F; +pub const WM_PALETTEISCHANGING: UINT = 0x0310; +pub const WM_PALETTECHANGED: UINT = 0x0311; +pub const WM_HOTKEY: UINT = 0x0312; +pub const WM_PRINT: UINT = 0x0317; +pub const WM_PRINTCLIENT: UINT = 0x0318; +pub const WM_APPCOMMAND: UINT = 0x0319; +pub const WM_THEMECHANGED: UINT = 0x031A; +pub const WM_CLIPBOARDUPDATE: UINT = 0x031D; +pub const WM_DWMCOMPOSITIONCHANGED: UINT = 0x031E; +pub const WM_DWMNCRENDERINGCHANGED: UINT = 0x031F; +pub const WM_DWMCOLORIZATIONCOLORCHANGED: UINT = 0x0320; +pub const WM_DWMWINDOWMAXIMIZEDCHANGE: UINT = 0x0321; +pub const WM_DWMSENDICONICTHUMBNAIL: UINT = 0x0323; +pub const WM_DWMSENDICONICLIVEPREVIEWBITMAP: UINT = 0x0326; +pub const WM_GETTITLEBARINFOEX: UINT = 0x033F; +pub const WM_HANDHELDFIRST: UINT = 0x0358; +pub const WM_HANDHELDLAST: UINT = 0x035F; +pub const WM_AFXFIRST: UINT = 0x0360; +pub const WM_AFXLAST: UINT = 0x037F; +pub const WM_PENWINFIRST: UINT = 0x0380; +pub const WM_PENWINLAST: UINT = 0x038F; +pub const WM_APP: UINT = 0x8000; +pub const WM_USER: UINT = 0x0400; +pub const WMSZ_LEFT: UINT = 1; +pub const WMSZ_RIGHT: UINT = 2; +pub const WMSZ_TOP: UINT = 3; +pub const WMSZ_TOPLEFT: UINT = 4; +pub const WMSZ_TOPRIGHT: UINT = 5; +pub const WMSZ_BOTTOM: UINT = 6; +pub const WMSZ_BOTTOMLEFT: UINT = 7; +pub const WMSZ_BOTTOMRIGHT: UINT = 8; +pub const HTERROR: LRESULT = (-2); +pub const HTTRANSPARENT: LRESULT = (-1); +pub const HTNOWHERE: LRESULT = 0; +pub const HTCLIENT: LRESULT = 1; +pub const HTCAPTION: LRESULT = 2; +pub const HTSYSMENU: LRESULT = 3; +pub const HTGROWBOX: LRESULT = 4; +pub const HTSIZE: LRESULT = HTGROWBOX; +pub const HTMENU: LRESULT = 5; +pub const HTHSCROLL: LRESULT = 6; +pub const HTVSCROLL: LRESULT = 7; +pub const HTMINBUTTON: LRESULT = 8; +pub const HTMAXBUTTON: LRESULT = 9; +pub const HTLEFT: LRESULT = 10; +pub const HTRIGHT: LRESULT = 11; +pub const HTTOP: LRESULT = 12; +pub const HTTOPLEFT: LRESULT = 13; +pub const HTTOPRIGHT: LRESULT = 14; +pub const HTBOTTOM: LRESULT = 15; +pub const HTBOTTOMLEFT: LRESULT = 16; +pub const HTBOTTOMRIGHT: LRESULT = 17; +pub const HTBORDER: LRESULT = 18; +pub const HTREDUCE: LRESULT = HTMINBUTTON; +pub const HTZOOM: LRESULT = HTMAXBUTTON; +pub const HTSIZEFIRST: LRESULT = HTLEFT; +pub const HTSIZELAST: LRESULT = HTBOTTOMRIGHT; +pub const HTOBJECT: LRESULT = 19; +pub const HTCLOSE: LRESULT = 20; +pub const HTHELP: LRESULT = 21; +pub const SMTO_NORMAL: UINT = 0x0000; +pub const SMTO_BLOCK: UINT = 0x0001; +pub const SMTO_ABORTIFHUNG: UINT = 0x0002; +pub const SMTO_NOTIMEOUTIFNOTHUNG: UINT = 0x0008; +pub const SMTO_ERRORONEXIT: UINT = 0x0020; +pub const MA_ACTIVATE: UINT = 1; +pub const MA_ACTIVATEANDEAT: UINT = 2; +pub const MA_NOACTIVATE: UINT = 3; +pub const MA_NOACTIVATEANDEAT: UINT = 4; +pub const ICON_SMALL: UINT = 0; +pub const ICON_BIG: UINT = 1; +pub const ICON_SMALL2: UINT = 2; +extern "system" { + pub fn RegisterWindowMessageA( + lpString: LPCSTR, + ) -> UINT; + pub fn RegisterWindowMessageW( + lpString: LPCWSTR, + ) -> UINT; +} +pub const SIZE_RESTORED: WPARAM = 0; +pub const SIZE_MINIMIZED: WPARAM = 1; +pub const SIZE_MAXIMIZED: WPARAM = 2; +pub const SIZE_MAXSHOW: WPARAM = 3; +pub const SIZE_MAXHIDE: WPARAM = 4; +pub const SIZENORMAL: WPARAM = SIZE_RESTORED; +pub const SIZEICONIC: WPARAM = SIZE_MINIMIZED; +pub const SIZEFULLSCREEN: WPARAM = SIZE_MAXIMIZED; +pub const SIZEZOOMSHOW: WPARAM = SIZE_MAXSHOW; +pub const SIZEZOOMHIDE: WPARAM = SIZE_MAXHIDE; +STRUCT!{struct WINDOWPOS { + hwnd: HWND, + hwndInsertAfter: HWND, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + flags: UINT, +}} +pub type LPWINDOWPOS = *mut WINDOWPOS; +pub type PWINDOWPOS = *mut WINDOWPOS; +STRUCT!{struct NCCALCSIZE_PARAMS { + rgrc: [RECT; 3], + lppos: PWINDOWPOS, +}} +pub type LPNCCALCSIZE_PARAMS = *mut NCCALCSIZE_PARAMS; +pub const WVR_ALIGNTOP: LRESULT = 0x0010; +pub const WVR_ALIGNLEFT: LRESULT = 0x0020; +pub const WVR_ALIGNBOTTOM: LRESULT = 0x0040; +pub const WVR_ALIGNRIGHT: LRESULT = 0x0080; +pub const WVR_HREDRAW: LRESULT = 0x0100; +pub const WVR_VREDRAW: LRESULT = 0x0200; +pub const WVR_REDRAW: LRESULT = WVR_HREDRAW | WVR_VREDRAW; +pub const WVR_VALIDRECTS: LRESULT = 0x0400; +pub const MK_LBUTTON: WPARAM = 0x0001; +pub const MK_RBUTTON: WPARAM = 0x0002; +pub const MK_SHIFT: WPARAM = 0x0004; +pub const MK_CONTROL: WPARAM = 0x0008; +pub const MK_MBUTTON: WPARAM = 0x0010; +pub const MK_XBUTTON1: WPARAM = 0x0020; +pub const MK_XBUTTON2: WPARAM = 0x0040; +pub const TME_HOVER: DWORD = 0x00000001; +pub const TME_LEAVE: DWORD = 0x00000002; +pub const TME_NONCLIENT: DWORD = 0x00000010; +pub const TME_QUERY: DWORD = 0x40000000; +pub const TME_CANCEL: DWORD = 0x80000000; +pub const HOVER_DEFAULT: DWORD = 0xFFFFFFFF; +STRUCT!{struct TRACKMOUSEEVENT { + cbSize: DWORD, + dwFlags: DWORD, + hwndTrack: HWND, + dwHoverTime: DWORD, +}} +pub type LPTRACKMOUSEEVENT = *mut TRACKMOUSEEVENT; +extern "system" { + pub fn TrackMouseEvent( + lpEventTrack: LPTRACKMOUSEEVENT, + ) -> BOOL; +} +pub const WS_OVERLAPPED: DWORD = 0x00000000; +pub const WS_POPUP: DWORD = 0x80000000; +pub const WS_CHILD: DWORD = 0x40000000; +pub const WS_MINIMIZE: DWORD = 0x20000000; +pub const WS_VISIBLE: DWORD = 0x10000000; +pub const WS_DISABLED: DWORD = 0x08000000; +pub const WS_CLIPSIBLINGS: DWORD = 0x04000000; +pub const WS_CLIPCHILDREN: DWORD = 0x02000000; +pub const WS_MAXIMIZE: DWORD = 0x01000000; +pub const WS_CAPTION: DWORD = 0x00C00000; +pub const WS_BORDER: DWORD = 0x00800000; +pub const WS_DLGFRAME: DWORD = 0x00400000; +pub const WS_VSCROLL: DWORD = 0x00200000; +pub const WS_HSCROLL: DWORD = 0x00100000; +pub const WS_SYSMENU: DWORD = 0x00080000; +pub const WS_THICKFRAME: DWORD = 0x00040000; +pub const WS_GROUP: DWORD = 0x00020000; +pub const WS_TABSTOP: DWORD = 0x00010000; +pub const WS_MINIMIZEBOX: DWORD = 0x00020000; +pub const WS_MAXIMIZEBOX: DWORD = 0x00010000; +pub const WS_TILED: DWORD = WS_OVERLAPPED; +pub const WS_ICONIC: DWORD = WS_MINIMIZE; +pub const WS_SIZEBOX: DWORD = WS_THICKFRAME; +pub const WS_TILEDWINDOW: DWORD = WS_OVERLAPPEDWINDOW; +pub const WS_OVERLAPPEDWINDOW: DWORD = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME + | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; +pub const WS_POPUPWINDOW: DWORD = WS_POPUP | WS_BORDER | WS_SYSMENU; +pub const WS_CHILDWINDOW: DWORD = WS_CHILD; +pub const WS_EX_DLGMODALFRAME: DWORD = 0x00000001; +pub const WS_EX_NOPARENTNOTIFY: DWORD = 0x00000004; +pub const WS_EX_TOPMOST: DWORD = 0x00000008; +pub const WS_EX_ACCEPTFILES: DWORD = 0x00000010; +pub const WS_EX_TRANSPARENT: DWORD = 0x00000020; +pub const WS_EX_MDICHILD: DWORD = 0x00000040; +pub const WS_EX_TOOLWINDOW: DWORD = 0x00000080; +pub const WS_EX_WINDOWEDGE: DWORD = 0x00000100; +pub const WS_EX_CLIENTEDGE: DWORD = 0x00000200; +pub const WS_EX_CONTEXTHELP: DWORD = 0x00000400; +pub const WS_EX_RIGHT: DWORD = 0x00001000; +pub const WS_EX_LEFT: DWORD = 0x00000000; +pub const WS_EX_RTLREADING: DWORD = 0x00002000; +pub const WS_EX_LTRREADING: DWORD = 0x00000000; +pub const WS_EX_LEFTSCROLLBAR: DWORD = 0x00004000; +pub const WS_EX_RIGHTSCROLLBAR: DWORD = 0x00000000; +pub const WS_EX_CONTROLPARENT: DWORD = 0x00010000; +pub const WS_EX_STATICEDGE: DWORD = 0x00020000; +pub const WS_EX_APPWINDOW: DWORD = 0x00040000; +pub const WS_EX_OVERLAPPEDWINDOW: DWORD = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE; +pub const WS_EX_PALETTEWINDOW: DWORD = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST; +pub const WS_EX_LAYERED: DWORD = 0x00080000; +pub const WS_EX_NOINHERITLAYOUT: DWORD = 0x00100000; +pub const WS_EX_NOREDIRECTIONBITMAP: DWORD = 0x00200000; +pub const WS_EX_LAYOUTRTL: DWORD = 0x00400000; +pub const WS_EX_COMPOSITED: DWORD = 0x02000000; +pub const WS_EX_NOACTIVATE: DWORD = 0x08000000; +pub const CS_VREDRAW: UINT = 0x0001; +pub const CS_HREDRAW: UINT = 0x0002; +pub const CS_DBLCLKS: UINT = 0x0008; +pub const CS_OWNDC: UINT = 0x0020; +pub const CS_CLASSDC: UINT = 0x0040; +pub const CS_PARENTDC: UINT = 0x0080; +pub const CS_NOCLOSE: UINT = 0x0200; +pub const CS_SAVEBITS: UINT = 0x0800; +pub const CS_BYTEALIGNCLIENT: UINT = 0x1000; +pub const CS_BYTEALIGNWINDOW: UINT = 0x2000; +pub const CS_GLOBALCLASS: UINT = 0x4000; +pub const CS_IME: UINT = 0x00010000; +pub const CS_DROPSHADOW: UINT = 0x00020000; +pub const PRF_CHECKVISIBLE: UINT = 0x00000001; +pub const PRF_NONCLIENT: UINT = 0x00000002; +pub const PRF_CLIENT: UINT = 0x00000004; +pub const PRF_ERASEBKGND: UINT = 0x00000008; +pub const PRF_CHILDREN: UINT = 0x00000010; +pub const PRF_OWNED: UINT = 0x00000020; +pub const BDR_RAISEDOUTER: UINT = 0x0001; +pub const BDR_SUNKENOUTER: UINT = 0x0002; +pub const BDR_RAISEDINNER: UINT = 0x0004; +pub const BDR_SUNKENINNER: UINT = 0x0008; +pub const BDR_OUTER: UINT = BDR_RAISEDOUTER | BDR_SUNKENOUTER; +pub const BDR_INNER: UINT = BDR_RAISEDINNER | BDR_SUNKENINNER; +pub const BDR_RAISED: UINT = BDR_RAISEDOUTER | BDR_RAISEDINNER; +pub const BDR_SUNKEN: UINT = BDR_SUNKENOUTER | BDR_SUNKENINNER; +pub const EDGE_RAISED: UINT = BDR_RAISEDOUTER | BDR_RAISEDINNER; +pub const EDGE_SUNKEN: UINT = BDR_SUNKENOUTER | BDR_SUNKENINNER; +pub const EDGE_ETCHED: UINT = BDR_SUNKENOUTER | BDR_RAISEDINNER; +pub const EDGE_BUMP: UINT = BDR_RAISEDOUTER | BDR_SUNKENINNER; +pub const BF_LEFT: UINT = 0x0001; +pub const BF_TOP: UINT = 0x0002; +pub const BF_RIGHT: UINT = 0x0004; +pub const BF_BOTTOM: UINT = 0x0008; +pub const BF_TOPLEFT: UINT = BF_TOP | BF_LEFT; +pub const BF_TOPRIGHT: UINT = BF_TOP | BF_RIGHT; +pub const BF_BOTTOMLEFT: UINT = BF_BOTTOM | BF_LEFT; +pub const BF_BOTTOMRIGHT: UINT = BF_BOTTOM | BF_RIGHT; +pub const BF_RECT: UINT = BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM; +pub const BF_DIAGONAL: UINT = 0x0010; +pub const BF_DIAGONAL_ENDTOPRIGHT: UINT = BF_DIAGONAL | BF_TOP | BF_RIGHT; +pub const BF_DIAGONAL_ENDTOPLEFT: UINT = BF_DIAGONAL | BF_TOP | BF_LEFT; +pub const BF_DIAGONAL_ENDBOTTOMLEFT: UINT = BF_DIAGONAL | BF_BOTTOM | BF_LEFT; +pub const BF_DIAGONAL_ENDBOTTOMRIGHT: UINT = BF_DIAGONAL | BF_BOTTOM | BF_RIGHT; +pub const BF_MIDDLE: UINT = 0x0800; +pub const BF_SOFT: UINT = 0x1000; +pub const BF_ADJUST: UINT = 0x2000; +pub const BF_FLAT: UINT = 0x4000; +pub const BF_MONO: UINT = 0x8000; +extern "system" { + pub fn DrawEdge( + hdc: HDC, + qrc: LPRECT, + edge: UINT, + grfFlags: UINT, + ) -> BOOL; +} +pub const DFC_CAPTION: UINT = 1; +pub const DFC_MENU: UINT = 2; +pub const DFC_SCROLL: UINT = 3; +pub const DFC_BUTTON: UINT = 4; +pub const DFC_POPUPMENU: UINT = 5; +pub const DFCS_CAPTIONCLOSE: UINT = 0x0000; +pub const DFCS_CAPTIONMIN: UINT = 0x0001; +pub const DFCS_CAPTIONMAX: UINT = 0x0002; +pub const DFCS_CAPTIONRESTORE: UINT = 0x0003; +pub const DFCS_CAPTIONHELP: UINT = 0x0004; +pub const DFCS_MENUARROW: UINT = 0x0000; +pub const DFCS_MENUCHECK: UINT = 0x0001; +pub const DFCS_MENUBULLET: UINT = 0x0002; +pub const DFCS_MENUARROWRIGHT: UINT = 0x0004; +pub const DFCS_SCROLLUP: UINT = 0x0000; +pub const DFCS_SCROLLDOWN: UINT = 0x0001; +pub const DFCS_SCROLLLEFT: UINT = 0x0002; +pub const DFCS_SCROLLRIGHT: UINT = 0x0003; +pub const DFCS_SCROLLCOMBOBOX: UINT = 0x0005; +pub const DFCS_SCROLLSIZEGRIP: UINT = 0x0008; +pub const DFCS_SCROLLSIZEGRIPRIGHT: UINT = 0x0010; +pub const DFCS_BUTTONCHECK: UINT = 0x0000; +pub const DFCS_BUTTONRADIOIMAGE: UINT = 0x0001; +pub const DFCS_BUTTONRADIOMASK: UINT = 0x0002; +pub const DFCS_BUTTONRADIO: UINT = 0x0004; +pub const DFCS_BUTTON3STATE: UINT = 0x0008; +pub const DFCS_BUTTONPUSH: UINT = 0x0010; +pub const DFCS_INACTIVE: UINT = 0x0100; +pub const DFCS_PUSHED: UINT = 0x0200; +pub const DFCS_CHECKED: UINT = 0x0400; +pub const DFCS_TRANSPARENT: UINT = 0x0800; +pub const DFCS_HOT: UINT = 0x1000; +pub const DFCS_ADJUSTRECT: UINT = 0x2000; +pub const DFCS_FLAT: UINT = 0x4000; +pub const DFCS_MONO: UINT = 0x8000; +extern "system" { + pub fn DrawFrameControl( + hdc: HDC, + lprc: LPRECT, + uType: UINT, + uState: UINT, + ) -> BOOL; +} +pub const DC_ACTIVE: UINT = 0x0001; +pub const DC_SMALLCAP: UINT = 0x0002; +pub const DC_ICON: UINT = 0x0004; +pub const DC_TEXT: UINT = 0x0008; +pub const DC_INBUTTON: UINT = 0x0010; +pub const DC_GRADIENT: UINT = 0x0020; +pub const DC_BUTTONS: UINT = 0x1000; +extern "system" { + pub fn DrawCaption( + hwnd: HWND, + hdc: HDC, + lprect: *const RECT, + flags: UINT, + ) -> BOOL; +} +pub const IDANI_OPEN: c_int = 1; +pub const IDANI_CAPTION: c_int = 3; +extern "system" { + pub fn DrawAnimatedRects( + hwnd: HWND, + idAni: c_int, + lprcFrom: *const RECT, + lprcTo: *const RECT, + ) -> BOOL; +} +pub const CF_TEXT: UINT = 1; +pub const CF_BITMAP: UINT = 2; +pub const CF_METAFILEPICT: UINT = 3; +pub const CF_SYLK: UINT = 4; +pub const CF_DIF: UINT = 5; +pub const CF_TIFF: UINT = 6; +pub const CF_OEMTEXT: UINT = 7; +pub const CF_DIB: UINT = 8; +pub const CF_PALETTE: UINT = 9; +pub const CF_PENDATA: UINT = 10; +pub const CF_RIFF: UINT = 11; +pub const CF_WAVE: UINT = 12; +pub const CF_UNICODETEXT: UINT = 13; +pub const CF_ENHMETAFILE: UINT = 14; +pub const CF_HDROP: UINT = 15; +pub const CF_LOCALE: UINT = 16; +pub const CF_DIBV5: UINT = 17; +pub const CF_MAX: UINT = 18; +pub const CF_OWNERDISPLAY: UINT = 0x0080; +pub const CF_DSPTEXT: UINT = 0x0081; +pub const CF_DSPBITMAP: UINT = 0x0082; +pub const CF_DSPMETAFILEPICT: UINT = 0x0083; +pub const CF_DSPENHMETAFILE: UINT = 0x008E; +pub const CF_PRIVATEFIRST: UINT = 0x0200; +pub const CF_PRIVATELAST: UINT = 0x02FF; +pub const CF_GDIOBJFIRST: UINT = 0x0300; +pub const CF_GDIOBJLAST: UINT = 0x03FF; +pub const FVIRTKEY: BYTE = TRUE as u8; +pub const FNOINVERT: BYTE = 0x02; +pub const FSHIFT: BYTE = 0x04; +pub const FCONTROL: BYTE = 0x08; +pub const FALT: BYTE = 0x10; +STRUCT!{struct ACCEL { + fVirt: BYTE, + key: WORD, + cmd: WORD, +}} +pub type LPACCEL = *mut ACCEL; +STRUCT!{struct PAINTSTRUCT { + hdc: HDC, + fErase: BOOL, + rcPaint: RECT, + fRestore: BOOL, + fIncUpdate: BOOL, + rgbReserved: [BYTE; 32], +}} +pub type PPAINTSTRUCT = *mut PAINTSTRUCT; +pub type NPPAINTSTRUCT = *mut PAINTSTRUCT; +pub type LPPAINTSTRUCT = *mut PAINTSTRUCT; +STRUCT!{struct CREATESTRUCTA { + lpCreateParams: LPVOID, + hInstance: HINSTANCE, + hMenu: HMENU, + hwndParent: HWND, + cy: c_int, + cx: c_int, + y: c_int, + x: c_int, + style: LONG, + lpszName: LPCSTR, + lpszClass: LPCSTR, + dwExStyle: DWORD, +}} +pub type LPCREATESTRUCTA = *mut CREATESTRUCTA; +STRUCT!{struct CREATESTRUCTW { + lpCreateParams: LPVOID, + hInstance: HINSTANCE, + hMenu: HMENU, + hwndParent: HWND, + cy: c_int, + cx: c_int, + y: c_int, + x: c_int, + style: LONG, + lpszName: LPCWSTR, + lpszClass: LPCWSTR, + dwExStyle: DWORD, +}} +pub type LPCREATESTRUCTW = *mut CREATESTRUCTW; +STRUCT!{struct WINDOWPLACEMENT { + length: UINT, + flags: UINT, + showCmd: UINT, + ptMinPosition: POINT, + ptMaxPosition: POINT, + rcNormalPosition: RECT, +}} +pub type PWINDOWPLACEMENT = *mut WINDOWPLACEMENT; +pub type LPWINDOWPLACEMENT = *mut WINDOWPLACEMENT; +pub const WPF_SETMINPOSITION: UINT = 0x0001; +pub const WPF_RESTORETOMAXIMIZED: UINT = 0x0002; +pub const WPF_ASYNCWINDOWPLACEMENT: UINT = 0x0004; +STRUCT!{struct NMHDR { + hwndFrom: HWND, + idFrom: UINT_PTR, + code: UINT, +}} +pub type LPNMHDR = *mut NMHDR; +STRUCT!{struct STYLESTRUCT { + styleOld: DWORD, + styleNew: DWORD, +}} +pub type LPSTYLESTRUCT = *mut STYLESTRUCT; +pub const ODT_MENU: UINT = 1; +pub const ODT_LISTBOX: UINT = 2; +pub const ODT_COMBOBOX: UINT = 3; +pub const ODT_BUTTON: UINT = 4; +pub const ODT_STATIC: UINT = 5; +pub const ODA_DRAWENTIRE: UINT = 0x0001; +pub const ODA_SELECT: UINT = 0x0002; +pub const ODA_FOCUS: UINT = 0x0004; +pub const ODS_SELECTED: UINT = 0x0001; +pub const ODS_GRAYED: UINT = 0x0002; +pub const ODS_DISABLED: UINT = 0x0004; +pub const ODS_CHECKED: UINT = 0x0008; +pub const ODS_FOCUS: UINT = 0x0010; +pub const ODS_DEFAULT: UINT = 0x0020; +pub const ODS_COMBOBOXEDIT: UINT = 0x1000; +pub const ODS_HOTLIGHT: UINT = 0x0040; +pub const ODS_INACTIVE: UINT = 0x0080; +pub const ODS_NOACCEL: UINT = 0x0100; +pub const ODS_NOFOCUSRECT: UINT = 0x0200; +STRUCT!{struct MEASUREITEMSTRUCT { + CtlType: UINT, + CtlID: UINT, + itemID: UINT, + itemWidth: UINT, + itemHeight: UINT, + itemData: ULONG_PTR, +}} +pub type PMEASUREITEMSTRUCT = *mut MEASUREITEMSTRUCT; +pub type LPMEASUREITEMSTRUCT = *mut MEASUREITEMSTRUCT; +STRUCT!{struct DRAWITEMSTRUCT { + CtlType: UINT, + CtlID: UINT, + itemID: UINT, + itemAction: UINT, + itemState: UINT, + hwndItem: HWND, + hDC: HDC, + rcItem: RECT, + itemData: ULONG_PTR, +}} +pub type PDRAWITEMSTRUCT = *mut DRAWITEMSTRUCT; +pub type LPDRAWITEMSTRUCT = *mut DRAWITEMSTRUCT; +STRUCT!{struct DELETEITEMSTRUCT { + CtlType: UINT, + CtlID: UINT, + itemID: UINT, + hwndItem: HWND, + itemData: ULONG_PTR, +}} +pub type PDELETEITEMSTRUCT = *mut DELETEITEMSTRUCT; +pub type LPDELETEITEMSTRUCT = *mut DELETEITEMSTRUCT; +STRUCT!{struct COMPAREITEMSTRUCT { + CtlType: UINT, + CtlID: UINT, + hwndItem: HWND, + itemID1: UINT, + itemData1: ULONG_PTR, + itemID2: UINT, + itemData2: ULONG_PTR, + dwLocaleId: DWORD, +}} +pub type PCOMPAREITEMSTRUCT = *mut COMPAREITEMSTRUCT; +pub type LPCOMPAREITEMSTRUCT = *mut COMPAREITEMSTRUCT; +extern "system" { + pub fn GetMessageA( + lpMsg: LPMSG, + hWnd: HWND, + wMsgFilterMin: UINT, + wMsgFilterMax: UINT, + ) -> BOOL; + pub fn GetMessageW( + lpMsg: LPMSG, + hWnd: HWND, + wMsgFilterMin: UINT, + wMsgFilterMax: UINT, + ) -> BOOL; + pub fn TranslateMessage( + lpmsg: *const MSG, + ) -> BOOL; + pub fn DispatchMessageA( + lpmsg: *const MSG, + ) -> LRESULT; + pub fn DispatchMessageW( + lpmsg: *const MSG, + ) -> LRESULT; + pub fn SetMessageQueue( + cMessagesMax: c_int, + ) -> BOOL; + pub fn PeekMessageA( + lpMsg: LPMSG, + hWnd: HWND, + wMsgFilterMin: UINT, + wMsgFilterMax: UINT, + wRemoveMsg: UINT, + ) -> BOOL; + pub fn PeekMessageW( + lpMsg: LPMSG, + hWnd: HWND, + wMsgFilterMin: UINT, + wMsgFilterMax: UINT, + wRemoveMsg: UINT, + ) -> BOOL; +} +pub const PM_NOREMOVE: UINT = 0x0000; +pub const PM_REMOVE: UINT = 0x0001; +pub const PM_NOYIELD: UINT = 0x0002; +pub const PM_QS_INPUT: UINT = QS_INPUT << 16; +pub const PM_QS_POSTMESSAGE: UINT = (QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16; +pub const PM_QS_PAINT: UINT = QS_PAINT << 16; +pub const PM_QS_SENDMESSAGE: UINT = QS_SENDMESSAGE << 16; +extern "system" { + pub fn RegisterHotKey( + hwnd: HWND, + id: c_int, + fsModifiers: UINT, + vk: UINT, + ) -> BOOL; + pub fn UnregisterHotKey( + hWnd: HWND, + id: c_int, + ) -> BOOL; +} +pub const MOD_ALT: LPARAM = 0x0001; +pub const MOD_CONTROL: LPARAM = 0x0002; +pub const MOD_SHIFT: LPARAM = 0x0004; +pub const MOD_WIN: LPARAM = 0x0008; +pub const MOD_NOREPEAT: LPARAM = 0x4000; +pub const IDHOT_SNAPWINDOW: WPARAM = -1isize as usize; +pub const IDHOT_SNAPDESKTOP: WPARAM = -2isize as usize; +pub const ENDSESSION_CLOSEAPP: UINT = 0x00000001; +pub const ENDSESSION_CRITICAL: UINT = 0x40000000; +pub const ENDSESSION_LOGOFF: UINT = 0x80000000; +pub const EWX_LOGOFF: UINT = 0x00000000; +pub const EWX_SHUTDOWN: UINT = 0x00000001; +pub const EWX_REBOOT: UINT = 0x00000002; +pub const EWX_FORCE: UINT = 0x00000004; +pub const EWX_POWEROFF: UINT = 0x00000008; +pub const EWX_FORCEIFHUNG: UINT = 0x00000010; +pub const EWX_QUICKRESOLVE: UINT = 0x00000020; +pub const EWX_RESTARTAPPS: UINT = 0x00000040; +pub const EWX_HYBRID_SHUTDOWN: UINT = 0x00400000; +pub const EWX_BOOTOPTIONS: UINT = 0x01000000; +// ExitWindows +extern "system" { + pub fn ExitWindowsEx( + uFlags: UINT, + dwReason: DWORD, + ) -> BOOL; + pub fn SwapMouseButton( + fSwap: BOOL, + ) -> BOOL; + pub fn GetMessagePos() -> DWORD; + pub fn GetMessageTime() -> LONG; + pub fn GetMessageExtraInfo() -> LPARAM; + pub fn GetUnpredictedMessagePos() -> DWORD; + pub fn IsWow64Message() -> BOOL; + pub fn SetMessageExtraInfo( + lParam: LPARAM, + ) -> LPARAM; + pub fn SendMessageA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn SendMessageW( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn SendMessageTimeoutA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + fuFlags: UINT, + uTimeout: UINT, + lpdwResult: PDWORD_PTR, + ) -> LRESULT; + pub fn SendMessageTimeoutW( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + fuFlags: UINT, + uTimeout: UINT, + lpdwResult: PDWORD_PTR, + ) -> LRESULT; + pub fn SendNotifyMessageA( + hWnd: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn SendNotifyMessageW( + hWnd: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn SendMessageCallbackA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + lpResultCallBack: SENDASYNCPROC, + dwData: ULONG_PTR, + ) -> BOOL; + pub fn SendMessageCallbackW( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + lpResultCallBack: SENDASYNCPROC, + dwData: ULONG_PTR, + ) -> BOOL; +} +STRUCT!{struct BSMINFO { + cbSize: UINT, + hdesk: HDESK, + hwnd: HWND, + luid: LUID, +}} +pub type PBSMINFO = *mut BSMINFO; +extern "system" { + pub fn BroadcastSystemMessageExA( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + pbsmInfo: PBSMINFO, + ) -> c_long; + pub fn BroadcastSystemMessageExW( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + pbsmInfo: PBSMINFO, + ) -> c_long; + pub fn BroadcastSystemMessageA( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LONG; + pub fn BroadcastSystemMessageW( + flags: DWORD, + lpInfo: LPDWORD, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LONG; +} +pub const BSM_ALLCOMPONENTS: DWORD = 0x00000000; +pub const BSM_VXDS: DWORD = 0x00000001; +pub const BSM_NETDRIVER: DWORD = 0x00000002; +pub const BSM_INSTALLABLEDRIVERS: DWORD = 0x00000004; +pub const BSM_APPLICATIONS: DWORD = 0x00000008; +pub const BSM_ALLDESKTOPS: DWORD = 0x00000010; +pub const BSF_QUERY: DWORD = 0x00000001; +pub const BSF_IGNORECURRENTTASK: DWORD = 0x00000002; +pub const BSF_FLUSHDISK: DWORD = 0x00000004; +pub const BSF_NOHANG: DWORD = 0x00000008; +pub const BSF_POSTMESSAGE: DWORD = 0x00000010; +pub const BSF_FORCEIFHUNG: DWORD = 0x00000020; +pub const BSF_NOTIMEOUTIFNOTHUNG: DWORD = 0x00000040; +pub const BSF_ALLOWSFW: DWORD = 0x00000080; +pub const BSF_SENDNOTIFYMESSAGE: DWORD = 0x00000100; +pub const BSF_RETURNHDESK: DWORD = 0x00000200; +pub const BSF_LUID: DWORD = 0x00000400; +pub const BROADCAST_QUERY_DENY: DWORD = 0x424D5144; +pub type HDEVNOTIFY = PVOID; +pub type PHDEVNOTIFY = *mut HDEVNOTIFY; +pub const DEVICE_NOTIFY_WINDOW_HANDLE: DWORD = 0x00000000; +pub const DEVICE_NOTIFY_SERVICE_HANDLE: DWORD = 0x00000001; +pub const DEVICE_NOTIFY_ALL_INTERFACE_CLASSES: DWORD = 0x00000004; +extern "system" { + pub fn RegisterDeviceNotificationA( + hRecipient: HANDLE, + notificationFilter: LPVOID, + flags: DWORD, + ) -> HDEVNOTIFY; + pub fn RegisterDeviceNotificationW( + hRecipient: HANDLE, + notificationFilter: LPVOID, + flags: DWORD, + ) -> HDEVNOTIFY; + pub fn UnregisterDeviceNotification( + Handle: HDEVNOTIFY, + ) -> BOOL; +} +pub type HPOWERNOTIFY = PVOID; +pub type PHPOWERNOTIFY = *mut HPOWERNOTIFY; +extern "system" { + pub fn RegisterPowerSettingNotification( + hRecipient: HANDLE, + PowerSettingGuid: LPCGUID, + Flags: DWORD, + ) -> HPOWERNOTIFY; + pub fn UnregisterPowerSettingNotification( + Handle: HPOWERNOTIFY, + ) -> BOOL; + pub fn RegisterSuspendResumeNotification( + hRecipient: HANDLE, + Flags: DWORD, + ) -> HPOWERNOTIFY; + pub fn UnregisterSuspendResumeNotification( + Handle: HPOWERNOTIFY, + ) -> BOOL; + pub fn PostMessageA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn PostMessageW( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn PostThreadMessageA( + idThread: DWORD, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn PostThreadMessageW( + idThread: DWORD, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; +} +// PostAppMessageA +// PostAppMessageW +pub const HWND_BROADCAST: HWND = 0xffff as HWND; +pub const HWND_MESSAGE: HWND = -3isize as HWND; +extern "system" { + pub fn AttachThreadInput( + idAttach: DWORD, + idAttachTo: DWORD, + fAttach: BOOL, + ) -> BOOL; + pub fn ReplyMessage( + lResult: LRESULT, + ) -> BOOL; + pub fn WaitMessage() -> BOOL; + pub fn WaitForInputIdle( + hProcess: HANDLE, + dwMilliseconds: DWORD, + ) -> DWORD; + pub fn DefWindowProcA( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn DefWindowProcW( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn PostQuitMessage( + nExitCode: c_int, + ); + pub fn CallWindowProcA( + lpPrevWndFunc: WNDPROC, + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn CallWindowProcW( + lpPrevWndFunc: WNDPROC, + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn InSendMessage() -> BOOL; + pub fn InSendMessageEx( + lpReserved: LPVOID, + ) -> DWORD; +} +pub const ISMEX_NOSEND: DWORD = 0x00000000; +pub const ISMEX_SEND: DWORD = 0x00000001; +pub const ISMEX_NOTIFY: DWORD = 0x00000002; +pub const ISMEX_CALLBACK: DWORD = 0x00000004; +pub const ISMEX_REPLIED: DWORD = 0x00000008; +extern "system" { + pub fn GetDoubleClickTime() -> UINT; + pub fn SetDoubleClickTime( + uInterval: UINT, + ) -> BOOL; + pub fn RegisterClassA( + lpWndClass: *const WNDCLASSA, + ) -> ATOM; + pub fn RegisterClassW( + lpWndClass: *const WNDCLASSW, + ) -> ATOM; + pub fn UnregisterClassA( + lpClassName: LPCSTR, + hInstance: HINSTANCE, + ) -> BOOL; + pub fn UnregisterClassW( + lpClassName: LPCWSTR, + hInstance: HINSTANCE, + ) -> BOOL; + pub fn GetClassInfoA( + hInstance: HINSTANCE, + lpClassName: LPCSTR, + lpWndClass: LPWNDCLASSA, + ) -> BOOL; + pub fn GetClassInfoW( + hInstance: HINSTANCE, + lpClassName: LPCWSTR, + lpWndClass: LPWNDCLASSW, + ) -> BOOL; + pub fn RegisterClassExA( + lpWndClass: *const WNDCLASSEXA, + ) -> ATOM; + pub fn RegisterClassExW( + lpWndClass: *const WNDCLASSEXW, + ) -> ATOM; + pub fn GetClassInfoExA( + hinst: HINSTANCE, + lpszClass: LPCSTR, + lpwcx: LPWNDCLASSEXA, + ) -> BOOL; + pub fn GetClassInfoExW( + hinst: HINSTANCE, + lpszClass: LPCWSTR, + lpwcx: LPWNDCLASSEXW, + ) -> BOOL; +} +pub const CW_USEDEFAULT: c_int = 0x80000000; +pub const HWND_DESKTOP: HWND = 0 as HWND; +FN!{stdcall PREGISTERCLASSNAMEW( + LPCWSTR, +) -> BOOLEAN} +extern "system" { + pub fn CreateWindowExA( + dwExStyle: DWORD, + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + x: c_int, + y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND; + pub fn CreateWindowExW( + dwExStyle: DWORD, + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, + x: c_int, + y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hMenu: HMENU, + hInstance: HINSTANCE, + lpParam: LPVOID, + ) -> HWND; +} +// CreateWindowA +// CreateWindowW +extern "system" { + pub fn IsWindow( + hWnd: HWND, + ) -> BOOL; + pub fn IsMenu( + hMenu: HMENU, + ) -> BOOL; + pub fn IsChild( + hWndParent: HWND, + hWnd: HWND, + ) -> BOOL; + pub fn DestroyWindow( + hWnd: HWND, + ) -> BOOL; + pub fn ShowWindow( + hWnd: HWND, + nCmdShow: c_int, + ) -> BOOL; + pub fn AnimateWindow( + hWnd: HWND, + dwTime: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn UpdateLayeredWindow( + hWnd: HWND, + hdcDst: HDC, + pptDst: *mut POINT, + psize: *mut SIZE, + hdcSrc: HDC, + pptSrc: *mut POINT, + crKey: COLORREF, + pblend: *mut BLENDFUNCTION, + dwFlags: DWORD, + ) -> BOOL; +} +STRUCT!{struct UPDATELAYEREDWINDOWINFO { + cbSize: DWORD, + hdcDst: HDC, + pptDst: *const POINT, + psize: *const SIZE, + hdcSrc: HDC, + pptSrc: *const POINT, + crKey: COLORREF, + pblend: *const BLENDFUNCTION, + dwFlags: DWORD, + prcDirty: *const RECT, +}} +pub type PUPDATELAYEREDWINDOWINFO = *mut UPDATELAYEREDWINDOWINFO; +extern "system" { + pub fn UpdateLayeredWindowIndirect( + hWnd: HWND, + pULWInfo: *mut UPDATELAYEREDWINDOWINFO, + ) -> BOOL; + pub fn GetLayeredWindowAttributes( + hwnd: HWND, + pcrKey: *mut COLORREF, + pbAlpha: *mut BYTE, + pdwFlags: *mut DWORD, + ) -> BOOL; +} +pub const PW_CLIENTONLY: DWORD = 0x00000001; +pub const PW_RENDERFULLCONTENT: DWORD = 0x00000002; +extern "system" { + pub fn PrintWindow( + hwnd: HWND, + hdcBlt: HDC, + nFlags: UINT, + ) -> BOOL; + pub fn SetLayeredWindowAttributes( + hwnd: HWND, + crKey: COLORREF, + bAlpha: BYTE, + dwFlags: DWORD, + ) -> BOOL; +} +pub const LWA_COLORKEY: DWORD = 0x00000001; +pub const LWA_ALPHA: DWORD = 0x00000002; +pub const ULW_COLORKEY: DWORD = 0x00000001; +pub const ULW_ALPHA: DWORD = 0x00000002; +pub const ULW_OPAQUE: DWORD = 0x00000004; +pub const ULW_EX_NORESIZE: DWORD = 0x00000008; +extern "system" { + pub fn ShowWindowAsync( + hWnd: HWND, + nCmdShow: c_int, + ) -> BOOL; + pub fn FlashWindow( + hwnd: HWND, + bInvert: BOOL, + ) -> BOOL; +} +STRUCT!{struct FLASHWINFO { + cbSize: UINT, + hwnd: HWND, + dwFlags: DWORD, + uCount: UINT, + dwTimeout: DWORD, +}} +pub type PFLASHWINFO = *mut FLASHWINFO; +extern "system" { + pub fn FlashWindowEx( + pfwi: PFLASHWINFO, + ) -> BOOL; +} +pub const FLASHW_STOP: DWORD = 0; +pub const FLASHW_CAPTION: DWORD = 0x00000001; +pub const FLASHW_TRAY: DWORD = 0x00000002; +pub const FLASHW_ALL: DWORD = FLASHW_CAPTION | FLASHW_TRAY; +pub const FLASHW_TIMER: DWORD = 0x00000004; +pub const FLASHW_TIMERNOFG: DWORD = 0x0000000C; +extern "system" { + pub fn ShowOwnedPopups( + hWnd: HWND, + fShow: BOOL, + ) -> BOOL; + pub fn OpenIcon( + hWnd: HWND, + ) -> BOOL; + pub fn CloseWindow( + hWnd: HWND, + ) -> BOOL; + pub fn MoveWindow( + hWnd: HWND, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + bRepaint: BOOL, + ) -> BOOL; + pub fn SetWindowPos( + hWnd: HWND, + hWndInsertAfter: HWND, + X: c_int, + Y: c_int, + cx: c_int, + cy: c_int, + uFlags: UINT, + ) -> BOOL; + pub fn GetWindowPlacement( + hWnd: HWND, + lpwndpl: *mut WINDOWPLACEMENT, + ) -> BOOL; + pub fn SetWindowPlacement( + hWnd: HWND, + lpwndpl: *const WINDOWPLACEMENT, + ) -> BOOL; +} +pub const WDA_NONE: DWORD = 0x00000000; +pub const WDA_MONITOR: DWORD = 0x00000001; +extern "system" { + pub fn GetWindowDisplayAffinity( + hWnd: HWND, + pdwAffinity: *mut DWORD, + ) -> BOOL; + pub fn SetWindowDisplayAffinity( + hWnd: HWND, + dwAffinity: DWORD, + ) -> BOOL; + pub fn BeginDeferWindowPos( + nNumWindows: c_int, + ) -> HDWP; + pub fn DeferWindowPos( + hWinPosInfo: HDWP, + hWnd: HWND, + hWndInserAfter: HWND, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + uFlags: UINT, + ) -> HDWP; + pub fn EndDeferWindowPos( + hWinPosInfo: HDWP, + ) -> BOOL; + pub fn IsWindowVisible( + hWnd: HWND, + ) -> BOOL; + pub fn IsIconic( + hWnd: HWND, + ) -> BOOL; + pub fn AnyPopup() -> BOOL; + pub fn BringWindowToTop( + hWnd: HWND, + ) -> BOOL; + pub fn IsZoomed( + hwnd: HWND, + ) -> BOOL; +} +pub const SWP_NOSIZE: UINT = 0x0001; +pub const SWP_NOMOVE: UINT = 0x0002; +pub const SWP_NOZORDER: UINT = 0x0004; +pub const SWP_NOREDRAW: UINT = 0x0008; +pub const SWP_NOACTIVATE: UINT = 0x0010; +pub const SWP_FRAMECHANGED: UINT = 0x0020; +pub const SWP_SHOWWINDOW: UINT = 0x0040; +pub const SWP_HIDEWINDOW: UINT = 0x0080; +pub const SWP_NOCOPYBITS: UINT = 0x0100; +pub const SWP_NOOWNERZORDER: UINT = 0x0200; +pub const SWP_NOSENDCHANGING: UINT = 0x0400; +pub const SWP_DRAWFRAME: UINT = SWP_FRAMECHANGED; +pub const SWP_NOREPOSITION: UINT = SWP_NOOWNERZORDER; +pub const SWP_DEFERERASE: UINT = 0x2000; +pub const SWP_ASYNCWINDOWPOS: UINT = 0x4000; +pub const HWND_TOP: HWND = 0 as HWND; +pub const HWND_BOTTOM: HWND = 1 as HWND; +pub const HWND_TOPMOST: HWND = -1isize as HWND; +pub const HWND_NOTOPMOST: HWND = -2isize as HWND; +STRUCT!{struct DLGTEMPLATE { + style: DWORD, + dwExtendedStyle: DWORD, + cdit: WORD, + x: c_short, + y: c_short, + cx: c_short, + cy: c_short, +}} +pub type LPDLGTEMPLATEA = *mut DLGTEMPLATE; +pub type LPDLGTEMPLATEW = *mut DLGTEMPLATE; +pub type LPCDLGTEMPLATEA = *const DLGTEMPLATE; +pub type LPCDLGTEMPLATEW = *const DLGTEMPLATE; +STRUCT!{struct DLGITEMTEMPLATE { + style: DWORD, + dwExtendedStyle: DWORD, + x: c_short, + y: c_short, + cx: c_short, + cy: c_short, + id: WORD, +}} +pub type PDLGITEMTEMPLATEA = *mut DLGITEMTEMPLATE; +pub type PDLGITEMTEMPLATEW = *mut DLGITEMTEMPLATE; +pub type LPDLGITEMTEMPLATEA = *mut DLGITEMTEMPLATE; +pub type LPDLGITEMTEMPLATEW = *mut DLGITEMTEMPLATE; +extern "system" { + pub fn CreateDialogParamA( + hInstance: HINSTANCE, + lpTemplateName: LPCSTR, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> HWND; + pub fn CreateDialogParamW( + hInstance: HINSTANCE, + lpTemplateName: LPCWSTR, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> HWND; + pub fn CreateDialogIndirectParamA( + hInstance: HINSTANCE, + lpTemplate: LPCDLGTEMPLATEA, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> HWND; + pub fn CreateDialogIndirectParamW( + hInstance: HINSTANCE, + lpTemplate: LPCDLGTEMPLATEW, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> HWND; +} +// CreateDialogA +// CreateDialogW +// CreateDialogIndirectA +// CreateDialogIndirectW +extern "system" { + pub fn DialogBoxParamA( + hInstance: HINSTANCE, + lpTemplateName: LPCSTR, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> INT_PTR; + pub fn DialogBoxParamW( + hInstance: HINSTANCE, + lpTemplateName: LPCWSTR, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> INT_PTR; + pub fn DialogBoxIndirectParamA( + hInstance: HINSTANCE, + hDialogTemplate: LPCDLGTEMPLATEA, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> INT_PTR; + pub fn DialogBoxIndirectParamW( + hInstance: HINSTANCE, + hDialogTemplate: LPCDLGTEMPLATEW, + hWndParent: HWND, + lpDialogFunc: DLGPROC, + dwInitParam: LPARAM, + ) -> INT_PTR; +} +// DialogBoxA +// DialogBoxW +// DialogBoxIndirectA +// DialogBoxIndirectW +extern "system" { + pub fn EndDialog( + hDlg: HWND, + nResult: INT_PTR, + ) -> BOOL; + pub fn GetDlgItem( + hDlg: HWND, + nIDDlgItem: c_int, + ) -> HWND; + pub fn SetDlgItemInt( + hDlg: HWND, + nIDDlgItem: c_int, + uValue: UINT, + bSigned: BOOL, + ) -> BOOL; + pub fn GetDlgItemInt( + hDlg: HWND, + nIDDlgItem: c_int, + lpTranslated: *mut BOOL, + bSigned: BOOL, + ) -> UINT; + pub fn SetDlgItemTextA( + hDlg: HWND, + nIDDlgItem: c_int, + lpString: LPCSTR, + ) -> BOOL; + pub fn SetDlgItemTextW( + hDlg: HWND, + nIDDlgItem: c_int, + lpString: LPCWSTR, + ) -> BOOL; + pub fn GetDlgItemTextA( + hDlg: HWND, + nIDDlgItem: c_int, + lpString: LPSTR, + nMaxCount: c_int, + ) -> UINT; + pub fn GetDlgItemTextW( + hDlg: HWND, + nIDDlgItem: c_int, + lpString: LPWSTR, + nMaxCount: c_int, + ) -> UINT; + pub fn CheckDlgButton( + hDlg: HWND, + nIDButton: c_int, + uCheck: UINT, + ) -> BOOL; + pub fn CheckRadioButton( + hDlg: HWND, + nIDFirstButton: c_int, + nIDLasatButton: c_int, + nIDCheckButton: c_int, + ) -> BOOL; + pub fn IsDlgButtonChecked( + hDlg: HWND, + nIDButton: c_int, + ) -> UINT; + pub fn SendDlgItemMessageA( + hDlg: HWND, + nIDDlgItem: c_int, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn SendDlgItemMessageW( + hDlg: HWND, + nIDDlgItem: c_int, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn GetNextDlgGroupItem( + hDlg: HWND, + hCtl: HWND, + bPrevious: BOOL, + ) -> HWND; + pub fn GetNextDlgTabItem( + hDlg: HWND, + hCtl: HWND, + bPrevious: BOOL, + ) -> HWND; + pub fn GetDlgCtrlID( + hwnd: HWND, + ) -> c_int; + pub fn GetDialogBaseUnits() -> LONG; + pub fn DefDlgProcA( + hDlg: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn DefDlgProcW( + hDlg: HWND, + msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; +} +ENUM!{enum DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS { + DCDC_DEFAULT = 0x0000, + DCDC_DISABLE_FONT_UPDATE = 0x0001, + DCDC_DISABLE_RELAYOUT = 0x0002, +}} +extern "system" { + pub fn SetDialogControlDpiChangeBehavior( + hwnd: HWND, + mask: DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS, + values: DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS, + ) -> BOOL; + pub fn GetDialogControlDpiChangeBehavior( + hwnd: HWND, + ) -> DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS; +} +ENUM!{enum DIALOG_DPI_CHANGE_BEHAVIORS { + DDC_DEFAULT = 0x0000, + DDC_DISABLE_ALL = 0x0001, + DDC_DISABLE_RESIZE = 0x0002, + DDC_DISABLE_CONTROL_RELAYOUT = 0x0004, +}} +extern "system" { + pub fn SetDialogDpiChangeBehavior( + hDlg: HWND, + mask: DIALOG_DPI_CHANGE_BEHAVIORS, + values: DIALOG_DPI_CHANGE_BEHAVIORS, + ) -> BOOL; + pub fn GetDialogDpiChangeBehavior( + hDlg: HWND, + ) -> DIALOG_DPI_CHANGE_BEHAVIORS; + pub fn CallMsgFilterA( + lpMsg: LPMSG, + nCode: c_int, + ) -> BOOL; + pub fn CallMsgFilterW( + lpMsg: LPMSG, + nCode: c_int, + ) -> BOOL; + pub fn OpenClipboard( + hWnd: HWND, + ) -> BOOL; + pub fn CloseClipboard() -> BOOL; + pub fn GetClipboardSequenceNumber() -> DWORD; + pub fn GetClipboardOwner() -> HWND; + pub fn SetClipboardViewer( + hWndNewViewer: HWND, + ) -> HWND; + pub fn GetClipboardViewer() -> HWND; + pub fn ChangeClipboardChain( + hwndRemove: HWND, + hwndNewNext: HWND, + ) -> BOOL; + pub fn SetClipboardData( + uFormat: UINT, + hMem: HANDLE, + ) -> HANDLE; + pub fn GetClipboardData( + uFormat: UINT, + ) -> HANDLE; + pub fn RegisterClipboardFormatA( + lpszFormat: LPCSTR, + ) -> UINT; + pub fn RegisterClipboardFormatW( + lpszFormat: LPCWSTR, + ) -> UINT; + pub fn CountClipboardFormats() -> c_int; + pub fn EnumClipboardFormats( + format: UINT, + ) -> UINT; + pub fn GetClipboardFormatNameA( + format: UINT, + lpszFormatName: LPSTR, + cchMaxCount: c_int, + ) -> c_int; + pub fn GetClipboardFormatNameW( + format: UINT, + lpszFormatName: LPWSTR, + cchMaxCount: c_int, + ) -> c_int; + pub fn EmptyClipboard() -> BOOL; + pub fn IsClipboardFormatAvailable( + format: UINT, + ) -> BOOL; + pub fn GetPriorityClipboardFormat( + paFormatPriorityList: *mut UINT, + cFormats: c_int, + ) -> c_int; + pub fn GetOpenClipboardWindow() -> HWND; + pub fn AddClipboardFormatListener( + hWnd: HWND, + ) -> BOOL; + pub fn RemoveClipboardFormatListener( + hWnd: HWND, + ) -> BOOL; + pub fn GetUpdatedClipboardFormats( + lpuiFormats: PUINT, + cFormats: UINT, + pcFormatsOUT: PUINT, + ) -> BOOL; + pub fn CharToOemA( + pSrc: LPCSTR, + pDst: LPSTR, + ) -> BOOL; + pub fn CharToOemW( + pSrc: LPCWSTR, + pDst: LPSTR, + ) -> BOOL; + pub fn OemToCharA( + pSrc: LPCSTR, + pDst: LPSTR, + ) -> BOOL; + pub fn OemToCharW( + pSrc: LPCSTR, + pDst: LPWSTR, + ) -> BOOL; + pub fn CharToOemBuffA( + lpszSrc: LPCSTR, + lpszDst: LPSTR, + cchDstLength: DWORD, + ) -> BOOL; + pub fn CharToOemBuffW( + lpszSrc: LPCWSTR, + lpszDst: LPSTR, + cchDstLength: DWORD, + ) -> BOOL; + pub fn OemToCharBuffA( + lpszSrc: LPCSTR, + lpszDst: LPSTR, + cchDstLength: DWORD, + ) -> BOOL; + pub fn OemToCharBuffW( + lpszSrc: LPCSTR, + lpszDst: LPWSTR, + cchDstLength: DWORD, + ) -> BOOL; + pub fn CharUpperA( + lpsz: LPSTR, + ) -> LPSTR; + pub fn CharUpperW( + lpsz: LPWSTR, + ) -> LPWSTR; + pub fn CharUpperBuffA( + lpsz: LPSTR, + cchLength: DWORD, + ) -> DWORD; + pub fn CharUpperBuffW( + lpsz: LPWSTR, + cchLength: DWORD, + ) -> DWORD; + pub fn CharLowerA( + lpsz: LPSTR, + ) -> LPSTR; + pub fn CharLowerW( + lpsz: LPWSTR, + ) -> LPWSTR; + pub fn CharLowerBuffA( + lpsz: LPSTR, + cchLength: DWORD, + ) -> DWORD; + pub fn CharLowerBuffW( + lpsz: LPWSTR, + cchLength: DWORD, + ) -> DWORD; + pub fn CharNextA( + lpsz: LPCSTR, + ) -> LPSTR; + pub fn CharNextW( + lpsz: LPCWSTR, + ) -> LPWSTR; + pub fn CharPrevA( + lpszStart: LPCSTR, + lpszCurrent: LPCSTR, + ) -> LPSTR; + pub fn CharPrevW( + lpszStart: LPCWSTR, + lpszCurrent: LPCWSTR, + ) -> LPWSTR; + pub fn CharNextExA( + codePage: WORD, + lpCurrentChar: LPSTR, + dwFlags: DWORD, + ) -> LPSTR; + pub fn CharPrevExA( + codePage: WORD, + lpStart: LPCSTR, + lpCurrentChar: LPCSTR, + dwFlags: DWORD, + ) -> LPSTR; +} +// AnsiToOem +// OemToAnsi +// AnsiToOemBuff +// OemToAnsiBuff +// AnsiUpper +// AnsiUpperBuff +// AnsiLower +// AnsiLowerBuff +// AnsiNext +// AnsiPrev +extern "system" { + pub fn IsCharAlphaA( + ch: CHAR, + ) -> BOOL; + pub fn IsCharAlphaW( + ch: WCHAR, + ) -> BOOL; + pub fn IsCharAlphaNumericA( + ch: CHAR, + ) -> BOOL; + pub fn IsCharAlphaNumericW( + ch: WCHAR, + ) -> BOOL; + pub fn IsCharUpperA( + ch: CHAR, + ) -> BOOL; + pub fn IsCharUpperW( + ch: WCHAR, + ) -> BOOL; + pub fn IsCharLowerA( + ch: CHAR, + ) -> BOOL; + pub fn IsCharLowerW( + ch: WCHAR, + ) -> BOOL; + pub fn SetFocus( + hWnd: HWND, + ) -> HWND; + pub fn GetActiveWindow() -> HWND; + pub fn GetFocus() -> HWND; + pub fn GetKBCodePage() -> UINT; + pub fn GetKeyState( + nVirtKey: c_int, + ) -> SHORT; + pub fn GetAsyncKeyState( + vKey: c_int, + ) -> SHORT; + pub fn GetKeyboardState( + lpKeyState: PBYTE, + ) -> BOOL; + pub fn SetKeyboardState( + lpKeyState: LPBYTE, + ) -> BOOL; + pub fn GetKeyNameTextA( + lparam: LONG, + lpString: LPSTR, + cchSize: c_int, + ) -> c_int; + pub fn GetKeyNameTextW( + lParam: LONG, + lpString: LPWSTR, + cchSize: c_int, + ) -> c_int; + pub fn GetKeyboardType( + nTypeFlag: c_int, + ) -> c_int; + pub fn ToAscii( + uVirtKey: UINT, + uScanCode: UINT, + lpKeyState: *const BYTE, + lpChar: LPWORD, + uFlags: UINT, + ) -> c_int; + pub fn ToAsciiEx( + uVirtKey: UINT, + uScanCode: UINT, + lpKeyState: *const BYTE, + lpChar: LPWORD, + uFlags: UINT, + dwhkl: HKL, + ) -> c_int; + pub fn ToUnicode( + wVirtKey: UINT, + wScanCode: UINT, + lpKeyState: *const BYTE, + lwszBuff: LPWSTR, + cchBuff: c_int, + wFlags: UINT, + ) -> c_int; + pub fn OemKeyScan( + wOemChar: WORD, + ) -> DWORD; + pub fn VkKeyScanA( + ch: CHAR, + ) -> SHORT; + pub fn VkKeyScanW( + ch: WCHAR, + ) -> SHORT; + pub fn VkKeyScanExA( + ch: CHAR, + dwhkl: HKL, + ) -> SHORT; + pub fn VkKeyScanExW( + ch: WCHAR, + dwhkl: HKL, + ) -> SHORT; +} +pub const KEYEVENTF_EXTENDEDKEY: DWORD = 0x0001; +pub const KEYEVENTF_KEYUP: DWORD = 0x0002; +pub const KEYEVENTF_UNICODE: DWORD = 0x0004; +pub const KEYEVENTF_SCANCODE: DWORD = 0x0008; +extern "system" { + pub fn keybd_event( + bVk: BYTE, + bScan: BYTE, + dwFlags: DWORD, + dwExtraInfo: ULONG_PTR, + ); +} +pub const MOUSEEVENTF_MOVE: DWORD = 0x0001; +pub const MOUSEEVENTF_LEFTDOWN: DWORD = 0x0002; +pub const MOUSEEVENTF_LEFTUP: DWORD = 0x0004; +pub const MOUSEEVENTF_RIGHTDOWN: DWORD = 0x0008; +pub const MOUSEEVENTF_RIGHTUP: DWORD = 0x0010; +pub const MOUSEEVENTF_MIDDLEDOWN: DWORD = 0x0020; +pub const MOUSEEVENTF_MIDDLEUP: DWORD = 0x0040; +pub const MOUSEEVENTF_XDOWN: DWORD = 0x0080; +pub const MOUSEEVENTF_XUP: DWORD = 0x0100; +pub const MOUSEEVENTF_WHEEL: DWORD = 0x0800; +pub const MOUSEEVENTF_HWHEEL: DWORD = 0x01000; +pub const MOUSEEVENTF_MOVE_NOCOALESCE: DWORD = 0x2000; +pub const MOUSEEVENTF_VIRTUALDESK: DWORD = 0x4000; +pub const MOUSEEVENTF_ABSOLUTE: DWORD = 0x8000; +extern "system" { + pub fn mouse_event( + dwFlags: DWORD, + dx: DWORD, + dy: DWORD, + dwData: DWORD, + dwExtraInfo: ULONG_PTR, + ); +} +STRUCT!{struct MOUSEINPUT { + dx: LONG, + dy: LONG, + mouseData: DWORD, + dwFlags: DWORD, + time: DWORD, + dwExtraInfo: ULONG_PTR, +}} +pub type PMOUSEINPUT = *mut MOUSEINPUT; +pub type LPMOUSEINPUT = *mut MOUSEINPUT; +STRUCT!{struct KEYBDINPUT { + wVk: WORD, + wScan: WORD, + dwFlags: DWORD, + time: DWORD, + dwExtraInfo: ULONG_PTR, +}} +pub type PKEYBDINPUT = *mut KEYBDINPUT; +pub type LPKEYBDINPUT = *mut KEYBDINPUT; +STRUCT!{struct HARDWAREINPUT { + uMsg: DWORD, + wParamL: WORD, + wParamH: WORD, +}} +pub type PHARDWAREINPUT = *mut HARDWAREINPUT; +pub type LPHARDWAREINPUT= *mut HARDWAREINPUT; +pub const INPUT_MOUSE: DWORD = 0; +pub const INPUT_KEYBOARD: DWORD = 1; +pub const INPUT_HARDWARE: DWORD = 2; +UNION!{union INPUT_u { + [u32; 6] [u64; 4], + mi mi_mut: MOUSEINPUT, + ki ki_mut: KEYBDINPUT, + hi hi_mut: HARDWAREINPUT, +}} +STRUCT!{struct INPUT { + type_: DWORD, + u: INPUT_u, +}} +pub type PINPUT = *mut INPUT; +pub type LPINPUT = *mut INPUT; +extern "system" { + pub fn SendInput( + cInputs: UINT, + pInputs: LPINPUT, + cbSize: c_int, + ) -> UINT; +} +DECLARE_HANDLE!{HTOUCHINPUT, HTOUCHINPUT__} +STRUCT!{struct TOUCHINPUT { + x: LONG, + y: LONG, + hSource: HANDLE, + dwID: DWORD, + dwFlags: DWORD, + dwMask: DWORD, + dwTime: DWORD, + dwExtraInfo: ULONG_PTR, + cxContact: DWORD, + cyContact: DWORD, +}} +pub type PTOUCHINPUT = *mut TOUCHINPUT; +pub type PCTOUCHINPUT = *const TOUCHINPUT; +// TOUCH_COORD_TO_PIXEL +pub const TOUCHEVENTF_MOVE: DWORD = 0x0001; +pub const TOUCHEVENTF_DOWN: DWORD = 0x0002; +pub const TOUCHEVENTF_UP: DWORD = 0x0004; +pub const TOUCHEVENTF_INRANGE: DWORD = 0x0008; +pub const TOUCHEVENTF_PRIMARY: DWORD = 0x0010; +pub const TOUCHEVENTF_NOCOALESCE: DWORD = 0x0020; +pub const TOUCHEVENTF_PEN: DWORD = 0x0040; +pub const TOUCHEVENTF_PALM: DWORD = 0x0080; +pub const TOUCHINPUTMASKF_TIMEFROMSYSTEM: DWORD = 0x0001; +pub const TOUCHINPUTMASKF_EXTRAINFO: DWORD = 0x0002; +pub const TOUCHINPUTMASKF_CONTACTAREA: DWORD = 0x0004; +extern "system" { + pub fn GetTouchInputInfo( + hTouchInput: HTOUCHINPUT, + cInputs: c_uint, + pInputs: PTOUCHINPUT, + cbSize: c_int, + ) -> BOOL; + pub fn CloseTouchInputHandle( + hTouchInput: HTOUCHINPUT, + ) -> BOOL; +} +pub const TWF_FINETOUCH: DWORD = 0x00000001; +pub const TWF_WANTPALM: DWORD = 0x00000002; +extern "system" { + pub fn RegisterTouchWindow( + hWnd: HWND, + flags: ULONG, + ) -> BOOL; + pub fn UnregisterTouchWindow( + hwnd: HWND, + ) -> BOOL; + pub fn IsTouchWindow( + hwnd: HWND, + pulFlags: PULONG, + ) -> BOOL; +} +ENUM!{enum POINTER_INPUT_TYPE { + PT_POINTER = 0x00000001, + PT_TOUCH = 0x00000002, + PT_PEN = 0x00000003, + PT_MOUSE = 0x00000004, + PT_TOUCHPAD = 0x00000005, +}} +ENUM!{enum POINTER_FLAGS { + POINTER_FLAG_NONE = 0x00000000, + POINTER_FLAG_NEW = 0x00000001, + POINTER_FLAG_INRANGE = 0x00000002, + POINTER_FLAG_INCONTACT = 0x00000004, + POINTER_FLAG_FIRSTBUTTON = 0x00000010, + POINTER_FLAG_SECONDBUTTON = 0x00000020, + POINTER_FLAG_THIRDBUTTON = 0x00000040, + POINTER_FLAG_FOURTHBUTTON = 0x00000080, + POINTER_FLAG_FIFTHBUTTON = 0x00000100, + POINTER_FLAG_PRIMARY = 0x00002000, + POINTER_FLAG_CONFIDENCE = 0x00004000, + POINTER_FLAG_CANCELED = 0x00008000, + POINTER_FLAG_DOWN = 0x00010000, + POINTER_FLAG_UPDATE = 0x00020000, + POINTER_FLAG_UP = 0x00040000, + POINTER_FLAG_WHEEL = 0x00080000, + POINTER_FLAG_HWHEEL = 0x00100000, + POINTER_FLAG_CAPTURECHANGED = 0x00200000, + POINTER_FLAG_HASTRANSFORM = 0x00400000, +}} +pub const POINTER_MOD_SHIFT: DWORD = 0x0004; +pub const POINTER_MOD_CTRL: DWORD = 0x0008; +ENUM!{enum POINTER_BUTTON_CHANGE_TYPE { + POINTER_CHANGE_NONE, + POINTER_CHANGE_FIRSTBUTTON_DOWN, + POINTER_CHANGE_FIRSTBUTTON_UP, + POINTER_CHANGE_SECONDBUTTON_DOWN, + POINTER_CHANGE_SECONDBUTTON_UP, + POINTER_CHANGE_THIRDBUTTON_DOWN, + POINTER_CHANGE_THIRDBUTTON_UP, + POINTER_CHANGE_FOURTHBUTTON_DOWN, + POINTER_CHANGE_FOURTHBUTTON_UP, + POINTER_CHANGE_FIFTHBUTTON_DOWN, + POINTER_CHANGE_FIFTHBUTTON_UP, +}} +STRUCT!{struct POINTER_INFO { + pointerType: POINTER_INPUT_TYPE, + pointerId: UINT32, + frameId: UINT32, + pointerFlags: POINTER_FLAGS, + sourceDevice: HANDLE, + hwndTarget: HWND, + ptPixelLocation: POINT, + ptHimetricLocation: POINT, + ptPixelLocationRaw: POINT, + ptHimetricLocationRaw: POINT, + dwTime: DWORD, + historyCount: UINT32, + InputData: INT32, + dwKeyStates: DWORD, + PerformanceCount: UINT64, + ButtonChangeType: POINTER_BUTTON_CHANGE_TYPE, +}} +ENUM!{enum TOUCH_FLAGS { + TOUCH_FLAG_NONE = 0x00000000, +}} +ENUM!{enum TOUCH_MASK { + TOUCH_MASK_NONE = 0x00000000, + TOUCH_MASK_CONTACTAREA = 0x00000001, + TOUCH_MASK_ORIENTATION = 0x00000002, + TOUCH_MASK_PRESSURE = 0x00000004, +}} +STRUCT!{struct POINTER_TOUCH_INFO { + pointerInfo: POINTER_INFO, + touchFlags: TOUCH_FLAGS, + touchMask: TOUCH_MASK, + rcContact: RECT, + rcContactRaw: RECT, + orientation: UINT32, + pressure: UINT32, +}} +ENUM!{enum PEN_FLAGS { + PEN_FLAG_NONE = 0x00000000, + PEN_FLAG_BARREL = 0x00000001, + PEN_FLAG_INVERTED = 0x00000002, + PEN_FLAG_ERASER = 0x00000004, +}} +ENUM!{enum PEN_MASK { + PEN_MASK_NONE = 0x00000000, + PEN_MASK_PRESSURE = 0x00000001, + PEN_MASK_ROTATION = 0x00000002, + PEN_MASK_TILT_X = 0x00000004, + PEN_MASK_TILT_Y = 0x00000008, +}} +STRUCT!{struct POINTER_PEN_INFO { + pointerInfo: POINTER_INFO, + penFlags: PEN_FLAGS, + penMask: PEN_MASK, + pressure: UINT32, + rotation: UINT32, + tiltX: INT32, + tiltY: INT32, +}} +pub const POINTER_MESSAGE_FLAG_NEW: DWORD = 0x00000001; +pub const POINTER_MESSAGE_FLAG_INRANGE: DWORD = 0x00000002; +pub const POINTER_MESSAGE_FLAG_INCONTACT: DWORD = 0x00000004; +pub const POINTER_MESSAGE_FLAG_FIRSTBUTTON: DWORD = 0x00000010; +pub const POINTER_MESSAGE_FLAG_SECONDBUTTON: DWORD = 0x00000020; +pub const POINTER_MESSAGE_FLAG_THIRDBUTTON: DWORD = 0x00000040; +pub const POINTER_MESSAGE_FLAG_FOURTHBUTTON: DWORD = 0x00000080; +pub const POINTER_MESSAGE_FLAG_FIFTHBUTTON: DWORD = 0x00000100; +pub const POINTER_MESSAGE_FLAG_PRIMARY: DWORD = 0x00002000; +pub const POINTER_MESSAGE_FLAG_CONFIDENCE: DWORD = 0x00004000; +pub const POINTER_MESSAGE_FLAG_CANCELED: DWORD = 0x00008000; +pub const PA_ACTIVATE: UINT = MA_ACTIVATE; +pub const PA_NOACTIVATE: UINT = MA_NOACTIVATE; +pub const MAX_TOUCH_COUNT: UINT32 = 256; +pub const TOUCH_FEEDBACK_DEFAULT: DWORD = 0x1; +pub const TOUCH_FEEDBACK_INDIRECT: DWORD = 0x2; +pub const TOUCH_FEEDBACK_NONE: DWORD = 0x3; +extern "system" { + pub fn InitializeTouchInjection( + maxCount: UINT32, + dwMode: DWORD, + ) -> BOOL; + pub fn InjectTouchInput( + count: UINT32, + contacts: *const POINTER_TOUCH_INFO, + ) -> BOOL; +} +STRUCT!{struct USAGE_PROPERTIES { + level: USHORT, + page: USHORT, + usage: USHORT, + logicalMinimum: INT32, + logicalMaximum: INT32, + unit: USHORT, + exponent: USHORT, + count: BYTE, + physicalMinimum: INT32, + physicalMaximum: INT32, +}} +pub type PUSAGE_PROPERTIES = *mut USAGE_PROPERTIES; +UNION!{union POINTER_TYPE_INFO_u { + [u64; 17] [u64; 18], + touchInfo touchInfo_mut: POINTER_TOUCH_INFO, + penInfo penInfo_mut: POINTER_PEN_INFO, +}} +STRUCT!{struct POINTER_TYPE_INFO { + type_: POINTER_INPUT_TYPE, + u: POINTER_TYPE_INFO_u, +}} +pub type PPOINTER_TYPE_INFO = *mut POINTER_TYPE_INFO; +STRUCT!{struct INPUT_INJECTION_VALUE { + page: USHORT, + usage: USHORT, + value: INT32, + index: USHORT, +}} +pub type PINPUT_INJECTION_VALUE = *mut INPUT_INJECTION_VALUE; +extern "system" { + pub fn GetPointerType( + pointerId: UINT32, + pointerType: *mut POINTER_INPUT_TYPE, + ) -> BOOL; + pub fn GetPointerCursorId( + pointerId: UINT32, + cursorId: *mut UINT32, + ) -> BOOL; + pub fn GetPointerInfo( + pointerId: UINT32, + pointerInfo: *mut POINTER_INFO, + ) -> BOOL; + pub fn GetPointerInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + pointerInfo: *mut POINTER_INFO, + ) -> BOOL; + pub fn GetPointerFrameInfo( + pointerId: UINT32, + pointerCount: *mut UINT32, + pointerInfo: *mut POINTER_INFO, + ) -> BOOL; + pub fn GetPointerFrameInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + pointerCount: *mut UINT32, + pointerInfo: *mut POINTER_INFO, + ) -> BOOL; + pub fn GetPointerTouchInfo( + pointerId: UINT32, + touchInfo: *mut POINTER_TOUCH_INFO, + ) -> BOOL; + pub fn GetPointerTouchInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + touchInfo: *mut POINTER_TOUCH_INFO, + ) -> BOOL; + pub fn GetPointerFrameTouchInfo( + pointerId: UINT32, + pointerCount: *mut UINT32, + touchInfo: *mut POINTER_TOUCH_INFO, + ) -> BOOL; + pub fn GetPointerFrameTouchInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + pointerCount: *mut UINT32, + touchInfo: *mut POINTER_TOUCH_INFO, + ) -> BOOL; + pub fn GetPointerPenInfo( + pointerId: UINT32, + penInfo: *mut POINTER_PEN_INFO, + ) -> BOOL; + pub fn GetPointerPenInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + penInfo: *mut POINTER_PEN_INFO, + ) -> BOOL; + pub fn GetPointerFramePenInfo( + pointerId: UINT32, + pointerCount: *mut UINT32, + penInfo: *mut POINTER_PEN_INFO, + ) -> BOOL; + pub fn GetPointerFramePenInfoHistory( + pointerId: UINT32, + entriesCount: *mut UINT32, + pointerCount: *mut UINT32, + penInfo: *mut POINTER_PEN_INFO, + ) -> BOOL; + pub fn SkipPointerFrameMessages( + pointerId: UINT32, + ) -> BOOL; + pub fn RegisterPointerInputTarget( + hwnd: HWND, + pointerType: POINTER_INPUT_TYPE, + ) -> BOOL; + pub fn UnregisterPointerInputTarget( + hwnd: HWND, + pointerType: POINTER_INPUT_TYPE, + ) -> BOOL; + pub fn RegisterPointerInputTargetEx( + hwnd: HWND, + pointerType: POINTER_INPUT_TYPE, + fObserve: BOOL, + ) -> BOOL; + pub fn UnregisterPointerInputTargetEx( + hwnd: HWND, + pointerType: POINTER_INPUT_TYPE, + ) -> BOOL; + pub fn EnableMouseInPointer( + fEnable: BOOL, + ) -> BOOL; + pub fn IsMouseInPointerEnabled() -> BOOL; +} +pub const TOUCH_HIT_TESTING_DEFAULT: ULONG = 0x0; +pub const TOUCH_HIT_TESTING_CLIENT: ULONG = 0x1; +pub const TOUCH_HIT_TESTING_NONE: ULONG = 0x2; +extern "system" { + pub fn RegisterTouchHitTestingWindow( + hwnd: HWND, + value: ULONG, + ) -> BOOL; +} +STRUCT!{struct TOUCH_HIT_TESTING_PROXIMITY_EVALUATION { + score: UINT16, + adjustedPoint: POINT, +}} +pub type PTOUCH_HIT_TESTING_PROXIMITY_EVALUATION = *mut TOUCH_HIT_TESTING_PROXIMITY_EVALUATION; +STRUCT!{struct TOUCH_HIT_TESTING_INPUT { + pointerId: UINT32, + point: POINT, + boundingBox: RECT, + nonOccludedBoundingBox: RECT, + orientation: UINT32, +}} +pub type PTOUCH_HIT_TESTING_INPUT = *mut TOUCH_HIT_TESTING_INPUT; +pub const TOUCH_HIT_TESTING_PROXIMITY_CLOSEST: UINT16 = 0x0; +pub const TOUCH_HIT_TESTING_PROXIMITY_FARTHEST: UINT16 = 0xFFF; +extern "system" { + pub fn EvaluateProximityToRect( + controlBoundingBox: *const RECT, + pHitTestingInput: *const TOUCH_HIT_TESTING_INPUT, + pProximityEval: *mut TOUCH_HIT_TESTING_PROXIMITY_EVALUATION, + ) -> BOOL; + pub fn EvaluateProximityToPolygon( + numVertices: UINT32, + controlPolygon: *const POINT, + pHitTestingInput: *const TOUCH_HIT_TESTING_INPUT, + pProximityEval: *mut TOUCH_HIT_TESTING_PROXIMITY_EVALUATION, + ) -> BOOL; + pub fn PackTouchHitTestingProximityEvaluation( + pHitTestingInput: *const TOUCH_HIT_TESTING_INPUT, + pProximityEval: *const TOUCH_HIT_TESTING_PROXIMITY_EVALUATION, + ) -> LRESULT; +} +ENUM!{enum FEEDBACK_TYPE { + FEEDBACK_TOUCH_CONTACTVISUALIZATION = 1, + FEEDBACK_PEN_BARRELVISUALIZATION = 2, + FEEDBACK_PEN_TAP = 3, + FEEDBACK_PEN_DOUBLETAP = 4, + FEEDBACK_PEN_PRESSANDHOLD = 5, + FEEDBACK_PEN_RIGHTTAP = 6, + FEEDBACK_TOUCH_TAP = 7, + FEEDBACK_TOUCH_DOUBLETAP = 8, + FEEDBACK_TOUCH_PRESSANDHOLD = 9, + FEEDBACK_TOUCH_RIGHTTAP = 10, + FEEDBACK_GESTURE_PRESSANDTAP = 11, + FEEDBACK_MAX = 0xFFFFFFFF, +}} +pub const GWFS_INCLUDE_ANCESTORS: DWORD = 0x00000001; +extern "system" { + pub fn GetWindowFeedbackSetting( + hwnd: HWND, + feedback: FEEDBACK_TYPE, + dwFlags: DWORD, + pSize: *mut UINT32, + config: *mut VOID, + ) -> BOOL; + pub fn SetWindowFeedbackSetting( + hwnd: HWND, + feedback: FEEDBACK_TYPE, + dwFlags: DWORD, + size: UINT32, + configuration: *const VOID, + ) -> BOOL; +} +STRUCT!{struct INPUT_TRANSFORM { + m: [[f32; 4]; 4], +}} +extern "system" { + pub fn GetPointerInputTransform( + pointerId: UINT32, + historyCount: UINT32, + inputTransform: *mut INPUT_TRANSFORM, + ) -> BOOL; +} +STRUCT!{struct LASTINPUTINFO { + cbSize: UINT, + dwTime: DWORD, +}} +pub type PLASTINPUTINFO = *mut LASTINPUTINFO; +extern "system" { + pub fn GetLastInputInfo( + plii: PLASTINPUTINFO, + ) -> BOOL; + pub fn MapVirtualKeyA( + nCode: UINT, + uMapType: UINT, + ) -> UINT; + pub fn MapVirtualKeyW( + nCode: UINT, + uMapType: UINT, + ) -> UINT; + pub fn MapVirtualKeyExA( + nCode: UINT, + uMapType: UINT, + dwhkl: HKL, + ) -> UINT; + pub fn MapVirtualKeyExW( + nCode: UINT, + uMapType: UINT, + dwhkl: HKL, + ) -> UINT; +} +pub const MAPVK_VK_TO_VSC: UINT = 0; +pub const MAPVK_VSC_TO_VK: UINT = 1; +pub const MAPVK_VK_TO_CHAR: UINT = 2; +pub const MAPVK_VSC_TO_VK_EX: UINT = 3; +pub const MAPVK_VK_TO_VSC_EX: UINT = 4; +extern "system" { + pub fn GetInputState() -> BOOL; + pub fn GetQueueStatus( + flags: UINT, + ) -> DWORD; + pub fn GetCapture() -> HWND; + pub fn SetCapture( + hWnd: HWND, + ) -> HWND; + pub fn ReleaseCapture() -> BOOL; + pub fn MsgWaitForMultipleObjects( + nCount: DWORD, + pHandles: *const HANDLE, + fWaitAll: BOOL, + dwMilliseconds: DWORD, + dwWakeMask: DWORD, + ) -> DWORD; + pub fn MsgWaitForMultipleObjectsEx( + nCount: DWORD, + pHandles: *const HANDLE, + dwMilliseconds: DWORD, + dwWakeMask: DWORD, + dwFlags: DWORD, + ) -> DWORD; +} +pub const MWMO_WAITALL: UINT = 0x0001; +pub const MWMO_ALERTABLE: UINT = 0x0002; +pub const MWMO_INPUTAVAILABLE: UINT = 0x0004; +pub const QS_KEY: UINT = 0x0001; +pub const QS_MOUSEMOVE: UINT = 0x0002; +pub const QS_MOUSEBUTTON: UINT = 0x0004; +pub const QS_POSTMESSAGE: UINT = 0x0008; +pub const QS_TIMER: UINT = 0x0010; +pub const QS_PAINT: UINT = 0x0020; +pub const QS_SENDMESSAGE: UINT = 0x0040; +pub const QS_HOTKEY: UINT = 0x0080; +pub const QS_ALLPOSTMESSAGE: UINT = 0x0100; +pub const QS_RAWINPUT: UINT = 0x0400; +pub const QS_TOUCH: UINT = 0x0800; +pub const QS_POINTER: UINT = 0x1000; +pub const QS_MOUSE: UINT = QS_MOUSEMOVE | QS_MOUSEBUTTON; +pub const QS_INPUT: UINT = QS_MOUSE | QS_KEY | QS_RAWINPUT | QS_TOUCH | QS_POINTER; +pub const QS_ALLEVENTS: UINT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY; +pub const QS_ALLINPUT: UINT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY + | QS_SENDMESSAGE; +pub const USER_TIMER_MAXIMUM: UINT = 0x7FFFFFFF; +pub const USER_TIMER_MINIMUM: UINT = 0x0000000A; +extern "system" { + pub fn SetTimer( + hWnd: HWND, + nIDEvent: UINT_PTR, + uElapse: UINT, + lpTimerFunc: TIMERPROC, + ) -> UINT_PTR; +} +pub const TIMERV_DEFAULT_COALESCING: ULONG = 0; +pub const TIMERV_NO_COALESCING: ULONG = 0xFFFFFFFF; +pub const TIMERV_COALESCING_MIN: ULONG = 1; +pub const TIMERV_COALESCING_MAX: ULONG = 0x7FFFFFF5; +extern "system" { + pub fn SetCoalescableTimer( + hWnd: HWND, + nIDEvent: UINT_PTR, + uElapse: UINT, + lpTimerFunc: TIMERPROC, + uToleranceDelay: ULONG, + ) -> UINT_PTR; + pub fn KillTimer( + hWnd: HWND, + uIDEvent: UINT_PTR, + ) -> BOOL; + pub fn IsWindowUnicode( + hWnd: HWND, + ) -> BOOL; + pub fn EnableWindow( + hWnd: HWND, + bEnable: BOOL, + ) -> BOOL; + pub fn IsWindowEnabled( + hWnd: HWND, + ) -> BOOL; + pub fn LoadAcceleratorsA( + hInstance: HINSTANCE, + lpTableName: LPCSTR, + ) -> HACCEL; + pub fn LoadAcceleratorsW( + hInstance: HINSTANCE, + lpTableName: LPCWSTR, + ) -> HACCEL; + pub fn CreateAcceleratorTableA( + paccel: LPACCEL, + cAccel: c_int, + ) -> HACCEL; + pub fn CreateAcceleratorTableW( + paccel: LPACCEL, + cAccel: c_int, + ) -> HACCEL; + pub fn DestroyAcceleratorTable( + hAccel: HACCEL, + ) -> BOOL; + pub fn CopyAcceleratorTableA( + hAccelSrc: HACCEL, + lpAccelDst: LPACCEL, + cAccelEntries: c_int, + ) -> c_int; + pub fn CopyAcceleratorTableW( + hAccelSrc: HACCEL, + lpAccelDst: LPACCEL, + cAccelEntries: c_int, + ) -> c_int; + pub fn TranslateAcceleratorA( + hWnd: HWND, + hAccTable: HACCEL, + lpMsg: LPMSG, + ) -> c_int; + pub fn TranslateAcceleratorW( + hWnd: HWND, + hAccTable: HACCEL, + lpMsg: LPMSG, + ) -> c_int; +} +pub const SM_CXSCREEN: c_int = 0; +pub const SM_CYSCREEN: c_int = 1; +pub const SM_CXVSCROLL: c_int = 2; +pub const SM_CYHSCROLL: c_int = 3; +pub const SM_CYCAPTION: c_int = 4; +pub const SM_CXBORDER: c_int = 5; +pub const SM_CYBORDER: c_int = 6; +pub const SM_CXDLGFRAME: c_int = 7; +pub const SM_CYDLGFRAME: c_int = 8; +pub const SM_CYVTHUMB: c_int = 9; +pub const SM_CXHTHUMB: c_int = 10; +pub const SM_CXICON: c_int = 11; +pub const SM_CYICON: c_int = 12; +pub const SM_CXCURSOR: c_int = 13; +pub const SM_CYCURSOR: c_int = 14; +pub const SM_CYMENU: c_int = 15; +pub const SM_CXFULLSCREEN: c_int = 16; +pub const SM_CYFULLSCREEN: c_int = 17; +pub const SM_CYKANJIWINDOW: c_int = 18; +pub const SM_MOUSEPRESENT: c_int = 19; +pub const SM_CYVSCROLL: c_int = 20; +pub const SM_CXHSCROLL: c_int = 21; +pub const SM_DEBUG: c_int = 22; +pub const SM_SWAPBUTTON: c_int = 23; +pub const SM_RESERVED1: c_int = 24; +pub const SM_RESERVED2: c_int = 25; +pub const SM_RESERVED3: c_int = 26; +pub const SM_RESERVED4: c_int = 27; +pub const SM_CXMIN: c_int = 28; +pub const SM_CYMIN: c_int = 29; +pub const SM_CXSIZE: c_int = 30; +pub const SM_CYSIZE: c_int = 31; +pub const SM_CXFRAME: c_int = 32; +pub const SM_CYFRAME: c_int = 33; +pub const SM_CXMINTRACK: c_int = 34; +pub const SM_CYMINTRACK: c_int = 35; +pub const SM_CXDOUBLECLK: c_int = 36; +pub const SM_CYDOUBLECLK: c_int = 37; +pub const SM_CXICONSPACING: c_int = 38; +pub const SM_CYICONSPACING: c_int = 39; +pub const SM_MENUDROPALIGNMENT: c_int = 40; +pub const SM_PENWINDOWS: c_int = 41; +pub const SM_DBCSENABLED: c_int = 42; +pub const SM_CMOUSEBUTTONS: c_int = 43; +pub const SM_CXFIXEDFRAME: c_int = SM_CXDLGFRAME; +pub const SM_CYFIXEDFRAME: c_int = SM_CYDLGFRAME; +pub const SM_CXSIZEFRAME: c_int = SM_CXFRAME; +pub const SM_CYSIZEFRAME: c_int = SM_CYFRAME; +pub const SM_SECURE: c_int = 44; +pub const SM_CXEDGE: c_int = 45; +pub const SM_CYEDGE: c_int = 46; +pub const SM_CXMINSPACING: c_int = 47; +pub const SM_CYMINSPACING: c_int = 48; +pub const SM_CXSMICON: c_int = 49; +pub const SM_CYSMICON: c_int = 50; +pub const SM_CYSMCAPTION: c_int = 51; +pub const SM_CXSMSIZE: c_int = 52; +pub const SM_CYSMSIZE: c_int = 53; +pub const SM_CXMENUSIZE: c_int = 54; +pub const SM_CYMENUSIZE: c_int = 55; +pub const SM_ARRANGE: c_int = 56; +pub const SM_CXMINIMIZED: c_int = 57; +pub const SM_CYMINIMIZED: c_int = 58; +pub const SM_CXMAXTRACK: c_int = 59; +pub const SM_CYMAXTRACK: c_int = 60; +pub const SM_CXMAXIMIZED: c_int = 61; +pub const SM_CYMAXIMIZED: c_int = 62; +pub const SM_NETWORK: c_int = 63; +pub const SM_CLEANBOOT: c_int = 67; +pub const SM_CXDRAG: c_int = 68; +pub const SM_CYDRAG: c_int = 69; +pub const SM_SHOWSOUNDS: c_int = 70; +pub const SM_CXMENUCHECK: c_int = 71; +pub const SM_CYMENUCHECK: c_int = 72; +pub const SM_SLOWMACHINE: c_int = 73; +pub const SM_MIDEASTENABLED: c_int = 74; +pub const SM_MOUSEWHEELPRESENT: c_int = 75; +pub const SM_XVIRTUALSCREEN: c_int = 76; +pub const SM_YVIRTUALSCREEN: c_int = 77; +pub const SM_CXVIRTUALSCREEN: c_int = 78; +pub const SM_CYVIRTUALSCREEN: c_int = 79; +pub const SM_CMONITORS: c_int = 80; +pub const SM_SAMEDISPLAYFORMAT: c_int = 81; +pub const SM_IMMENABLED: c_int = 82; +pub const SM_CXFOCUSBORDER: c_int = 83; +pub const SM_CYFOCUSBORDER: c_int = 84; +pub const SM_TABLETPC: c_int = 86; +pub const SM_MEDIACENTER: c_int = 87; +pub const SM_STARTER: c_int = 88; +pub const SM_SERVERR2: c_int = 89; +pub const SM_MOUSEHORIZONTALWHEELPRESENT: c_int = 91; +pub const SM_CXPADDEDBORDER: c_int = 92; +pub const SM_DIGITIZER: c_int = 94; +pub const SM_MAXIMUMTOUCHES: c_int = 95; +pub const SM_CMETRICS: c_int = 97; +pub const SM_REMOTESESSION: c_int = 0x1000; +pub const SM_SHUTTINGDOWN: c_int = 0x2000; +pub const SM_REMOTECONTROL: c_int = 0x2001; +pub const SM_CARETBLINKINGENABLED: c_int = 0x2002; +pub const SM_CONVERTIBLESLATEMODE: c_int = 0x2003; +pub const SM_SYSTEMDOCKED: c_int = 0x2004; +extern "system" { + pub fn GetSystemMetrics( + nIndex: c_int, + ) -> c_int; + pub fn GetSystemMetricsForDpi( + nIndex: c_int, + dpi: UINT, + ) -> c_int; + pub fn LoadMenuA( + hInstance: HINSTANCE, + lpMenuName: LPCSTR, + ) -> HMENU; + pub fn LoadMenuW( + hInstance: HINSTANCE, + lpMenuName: LPCWSTR, + ) -> HMENU; + pub fn LoadMenuIndirectA( + lpMenuTemplate: *const MENUTEMPLATEA, + ) -> HMENU; + pub fn LoadMenuIndirectW( + lpMenuTemplate: *const MENUTEMPLATEW, + ) -> HMENU; + pub fn GetMenu( + hWnd: HWND, + ) -> HMENU; + pub fn SetMenu( + hWnd: HWND, + hMenu: HMENU, + ) -> BOOL; + pub fn ChangeMenuA( + hMenu: HMENU, + cmd: UINT, + lpszNewItem: LPCSTR, + cmdInsert: UINT, + flags: UINT, + ) -> BOOL; + pub fn ChangeMenuW( + hMenu: HMENU, + cmd: UINT, + lpszNewItem: LPCWSTR, + cmdInsert: UINT, + flags: UINT, + ) -> BOOL; + pub fn HiliteMenuItem( + hWnd: HWND, + hMenu: HMENU, + uIDHiliteItem: UINT, + uHilite: UINT, + ) -> BOOL; + pub fn GetMenuStringA( + hMenu: HMENU, + uIDItem: UINT, + lpString: LPSTR, + cchMax: c_int, + flags: UINT, + ) -> c_int; + pub fn GetMenuStringW( + hMenu: HMENU, + uIDItem: UINT, + lpString: LPWSTR, + cchMax: c_int, + flags: UINT, + ) -> c_int; + pub fn GetMenuState( + hMenu: HMENU, + uId: UINT, + uFlags: UINT, + ) -> UINT; + pub fn DrawMenuBar( + hwnd: HWND, + ) -> BOOL; +} +pub const PMB_ACTIVE: DWORD = 0x00000001; +extern "system" { + pub fn GetSystemMenu( + hWnd: HWND, + bRevert: BOOL, + ) -> HMENU; + pub fn CreateMenu() -> HMENU; + pub fn CreatePopupMenu() ->HMENU; + pub fn DestroyMenu( + hMenu: HMENU, + ) -> BOOL; + pub fn CheckMenuItem( + hMenu: HMENU, + uIDCheckItem: UINT, + uCheck: UINT, + ) -> DWORD; + pub fn EnableMenuItem( + hMenu: HMENU, + uIDEnableItem: UINT, + uEnable: UINT, + ) -> BOOL; + pub fn GetSubMenu( + hMenu: HMENU, + nPos: c_int, + ) -> HMENU; + pub fn GetMenuItemID( + hMenu: HMENU, + nPos: c_int, + ) -> UINT; + pub fn GetMenuItemCount( + hMenu: HMENU, + ) -> c_int; + pub fn InsertMenuA( + hMenu: HMENU, + uPosition: UINT, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCSTR, + ) -> BOOL; + pub fn InsertMenuW( + hMenu: HMENU, + uPosition: UINT, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCWSTR, + ) -> BOOL; + pub fn AppendMenuA( + hMenu: HMENU, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCSTR, + ) -> BOOL; + pub fn AppendMenuW( + hMenu: HMENU, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCWSTR, + ) -> BOOL; + pub fn ModifyMenuA( + hMnu: HMENU, + uPosition: UINT, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCSTR, + ) -> BOOL; + pub fn ModifyMenuW( + hMnu: HMENU, + uPosition: UINT, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCWSTR, + ) -> BOOL; + pub fn RemoveMenu( + hMenu: HMENU, + uPosition: UINT, + uFlags: UINT, + ) -> BOOL; + pub fn DeleteMenu( + hMenu: HMENU, + uPosition: UINT, + uFlags: UINT, + ) -> BOOL; + pub fn SetMenuItemBitmaps( + hMenu: HMENU, + uPosition: UINT, + uFlags: UINT, + hBitmapUnchecked: HBITMAP, + hBitmapChecked: HBITMAP, + ) -> BOOL; + pub fn GetMenuCheckMarkDimensions() -> LONG; + pub fn TrackPopupMenu( + hMenu: HMENU, + uFlags: UINT, + x: c_int, + y: c_int, + nReserved: c_int, + hWnd: HWND, + prcRect: *const RECT, + ) -> BOOL; +} +pub const MNC_IGNORE: DWORD = 0; +pub const MNC_CLOSE: DWORD = 1; +pub const MNC_EXECUTE: DWORD = 2; +pub const MNC_SELECT: DWORD = 3; +STRUCT!{struct TPMPARAMS { + cbSize: UINT, + rcExclude: RECT, +}} +pub type LPTPMPARAMS = *mut TPMPARAMS; +extern "system" { + pub fn TrackPopupMenuEx( + hMenu: HMENU, + uFlags: UINT, + x: INT, + y: INT, + hwnd: HWND, + lptpm: LPTPMPARAMS, + ) -> BOOL; + pub fn CalculatePopupWindowPosition( + anchorPoint: *const POINT, + windowSize: *const SIZE, + flags: UINT, + excludeRect: *mut RECT, + popupWindowPosition: *mut RECT, + ) -> BOOL; +} +pub const MNS_NOCHECK: DWORD = 0x80000000; +pub const MNS_MODELESS: DWORD = 0x40000000; +pub const MNS_DRAGDROP: DWORD = 0x20000000; +pub const MNS_AUTODISMISS: DWORD = 0x10000000; +pub const MNS_NOTIFYBYPOS: DWORD = 0x08000000; +pub const MNS_CHECKORBMP: DWORD = 0x04000000; +pub const MIM_MAXHEIGHT: DWORD = 0x00000001; +pub const MIM_BACKGROUND: DWORD = 0x00000002; +pub const MIM_HELPID: DWORD = 0x00000004; +pub const MIM_MENUDATA: DWORD = 0x00000008; +pub const MIM_STYLE: DWORD = 0x00000010; +pub const MIM_APPLYTOSUBMENUS: DWORD = 0x80000000; +STRUCT!{struct MENUINFO { + cbSize: DWORD, + fMask: DWORD, + dwStyle: DWORD, + cyMax: UINT, + hbrBack: HBRUSH, + dwContextHelpID: DWORD, + dwMenuData: ULONG_PTR, +}} +pub type LPMENUINFO = *mut MENUINFO; +pub type LPCMENUINFO = *const MENUINFO; +extern "system" { + pub fn GetMenuInfo( + hMenu: HMENU, + lpcmi: LPMENUINFO, + ) -> BOOL; + pub fn SetMenuInfo( + hMenu: HMENU, + lpcmi: LPCMENUINFO, + ) -> BOOL; + pub fn EndMenu( + hMenu: HMENU, + uFlags: UINT, + uIDNewItem: UINT_PTR, + lpNewItem: LPCSTR, + ) -> BOOL; +} +pub const MND_CONTINUE: DWORD = 0; +pub const MND_ENDMENU: DWORD = 1; +STRUCT!{struct MENUGETOBJECTINFO { + dwFlags: DWORD, + uPos: UINT, + hmenu: HMENU, + riid: PVOID, + pvObj: PVOID, +}} +pub type PMENUGETOBJECTINFO = *mut MENUGETOBJECTINFO; +pub const MNGOF_TOPGAP: DWORD = 0x00000001; +pub const MNGOF_BOTTOMGAP: DWORD = 0x00000002; +pub const MNGO_NOINTERFACE: DWORD = 0x00000000; +pub const MNGO_NOERROR: DWORD = 0x00000001; +pub const MIIM_STATE: DWORD = 0x00000001; +pub const MIIM_ID: DWORD = 0x00000002; +pub const MIIM_SUBMENU: DWORD = 0x00000004; +pub const MIIM_CHECKMARKS: DWORD = 0x00000008; +pub const MIIM_TYPE: DWORD = 0x00000010; +pub const MIIM_DATA: DWORD = 0x00000020; +pub const MIIM_STRING: DWORD = 0x00000040; +pub const MIIM_BITMAP: DWORD = 0x00000080; +pub const MIIM_FTYPE: DWORD = 0x00000100; +pub const HBMMENU_CALLBACK: HBITMAP = -1isize as HBITMAP; +pub const HBMMENU_SYSTEM: HBITMAP = 1 as HBITMAP; +pub const HBMMENU_MBAR_RESTORE: HBITMAP = 2 as HBITMAP; +pub const HBMMENU_MBAR_MINIMIZE: HBITMAP = 3 as HBITMAP; +pub const HBMMENU_MBAR_CLOSE: HBITMAP = 5 as HBITMAP; +pub const HBMMENU_MBAR_CLOSE_D: HBITMAP = 6 as HBITMAP; +pub const HBMMENU_MBAR_MINIMIZE_D: HBITMAP = 7 as HBITMAP; +pub const HBMMENU_POPUP_CLOSE: HBITMAP = 8 as HBITMAP; +pub const HBMMENU_POPUP_RESTORE: HBITMAP = 9 as HBITMAP; +pub const HBMMENU_POPUP_MAXIMIZE: HBITMAP = 10 as HBITMAP; +pub const HBMMENU_POPUP_MINIMIZE: HBITMAP = 11 as HBITMAP; +STRUCT!{struct MENUITEMINFOA { + cbSize: UINT, + fMask: UINT, + fType: UINT, + fState: UINT, + wID: UINT, + hSubMenu: HMENU, + hbmpChecked: HBITMAP, + hbmpUnchecked: HBITMAP, + dwItemData: ULONG_PTR, + dwTypeData: LPSTR, + cch: UINT, + hbmpItem: HBITMAP, +}} +pub type LPMENUITEMINFOA = *mut MENUITEMINFOA; +pub type LPCMENUITEMINFOA = *const MENUITEMINFOA; +STRUCT!{struct MENUITEMINFOW { + cbSize: UINT, + fMask: UINT, + fType: UINT, + fState: UINT, + wID: UINT, + hSubMenu: HMENU, + hbmpChecked: HBITMAP, + hbmpUnchecked: HBITMAP, + dwItemData: ULONG_PTR, + dwTypeData: LPWSTR, + cch: UINT, + hbmpItem: HBITMAP, +}} +pub type LPMENUITEMINFOW = *mut MENUITEMINFOW; +pub type LPCMENUITEMINFOW = *const MENUITEMINFOW; +extern "system" { + pub fn InsertMenuItemA( + hmenu: HMENU, + item: UINT, + fByPosition: BOOL, + lpmi: LPCMENUITEMINFOA, + ) -> BOOL; + pub fn InsertMenuItemW( + hmenu: HMENU, + item: UINT, + fByPosition: BOOL, + lpmi: LPCMENUITEMINFOW, + ) -> BOOL; + pub fn GetMenuItemInfoA( + hMenu: HMENU, + uItem: UINT, + fByPosition: BOOL, + lpmii: LPMENUITEMINFOA, + ) -> BOOL; + pub fn GetMenuItemInfoW( + hMenu: HMENU, + uItem: UINT, + fByPosition: BOOL, + lpmii: LPMENUITEMINFOW, + ) -> BOOL; + pub fn SetMenuItemInfoA( + hmenu: HMENU, + item: UINT, + fByPositon: BOOL, + lpmii: LPCMENUITEMINFOA, + ) -> BOOL; + pub fn SetMenuItemInfoW( + hmenu: HMENU, + item: UINT, + fByPositon: BOOL, + lpmii: LPCMENUITEMINFOW, + ) -> BOOL; +} +pub const GMDI_USEDISABLED: DWORD = 0x0001; +pub const GMDI_GOINTOPOPUPS: DWORD = 0x0002; +extern "system" { + pub fn GetMenuDefaultItem( + hMenu: HMENU, + fByPos: UINT, + gmdiFlags: UINT, + ) -> UINT; + pub fn SetMenuDefaultItem( + hMenu: HMENU, + uItem: UINT, + fByPos: UINT, + ) -> BOOL; + pub fn GetMenuItemRect( + hWnd: HWND, + hMenu: HMENU, + uItem: UINT, + lprcItem: LPRECT, + ) -> BOOL; + pub fn MenuItemFromPoint( + hWnd: HWND, + hMenu: HMENU, + ptScreen: POINT, + ) -> c_int; +} +pub const TPM_LEFTBUTTON: UINT = 0x0000; +pub const TPM_RIGHTBUTTON: UINT = 0x0002; +pub const TPM_LEFTALIGN: UINT = 0x0000; +pub const TPM_CENTERALIGN: UINT = 0x0004; +pub const TPM_RIGHTALIGN: UINT = 0x0008; +pub const TPM_TOPALIGN: UINT = 0x0000; +pub const TPM_VCENTERALIGN: UINT = 0x0010; +pub const TPM_BOTTOMALIGN: UINT = 0x0020; +pub const TPM_HORIZONTAL: UINT = 0x0000; +pub const TPM_VERTICAL: UINT = 0x0040; +pub const TPM_NONOTIFY: UINT = 0x0080; +pub const TPM_RETURNCMD: UINT = 0x0100; +pub const TPM_RECURSE: UINT = 0x0001; +pub const TPM_HORPOSANIMATION: UINT = 0x0400; +pub const TPM_HORNEGANIMATION: UINT = 0x0800; +pub const TPM_VERPOSANIMATION: UINT = 0x1000; +pub const TPM_VERNEGANIMATION: UINT = 0x2000; +pub const TPM_NOANIMATION: UINT = 0x4000; +pub const TPM_LAYOUTRTL: UINT = 0x8000; +pub const TPM_WORKAREA: UINT = 0x10000; +STRUCT!{struct DROPSTRUCT { + hwndSource: HWND, + hwndSink: HWND, + wFmt: DWORD, + dwData: ULONG_PTR, + ptDrop: POINT, + dwControlData: DWORD, +}} +pub type PDROPSTRUCT = *mut DROPSTRUCT; +pub type LPDROPSTRUCT = *mut DROPSTRUCT; +pub const DOF_EXECUTABLE: DWORD = 0x8001; +pub const DOF_DOCUMENT: DWORD = 0x8002; +pub const DOF_DIRECTORY: DWORD = 0x8003; +pub const DOF_MULTIPLE: DWORD = 0x8004; +pub const DOF_PROGMAN: DWORD = 0x0001; +pub const DOF_SHELLDATA: DWORD = 0x0002; +pub const DO_DROPFILE: DWORD = 0x454C4946; +pub const DO_PRINTFILE: DWORD = 0x544E5250; +extern "system" { + pub fn DragObject( + hwndParent: HWND, + hwndFrom: HWND, + fmt: UINT, + data: ULONG_PTR, + hcur: HCURSOR, + ) -> DWORD; + pub fn DragDetect( + hwnd: HWND, + pt: POINT, + ) -> BOOL; + pub fn DrawIcon( + hDC: HDC, + x: c_int, + y: c_int, + hIcon: HICON, + ) -> BOOL; +} +pub const DT_TOP: UINT = 0x00000000; +pub const DT_LEFT: UINT = 0x00000000; +pub const DT_CENTER: UINT = 0x00000001; +pub const DT_RIGHT: UINT = 0x00000002; +pub const DT_VCENTER: UINT = 0x00000004; +pub const DT_BOTTOM: UINT = 0x00000008; +pub const DT_WORDBREAK: UINT = 0x00000010; +pub const DT_SINGLELINE: UINT = 0x00000020; +pub const DT_EXPANDTABS: UINT = 0x00000040; +pub const DT_TABSTOP: UINT = 0x00000080; +pub const DT_NOCLIP: UINT = 0x00000100; +pub const DT_EXTERNALLEADING: UINT = 0x00000200; +pub const DT_CALCRECT: UINT = 0x00000400; +pub const DT_NOPREFIX: UINT = 0x00000800; +pub const DT_INTERNAL: UINT = 0x00001000; +pub const DT_EDITCONTROL: UINT = 0x00002000; +pub const DT_PATH_ELLIPSIS: UINT = 0x00004000; +pub const DT_END_ELLIPSIS: UINT = 0x00008000; +pub const DT_MODIFYSTRING: UINT = 0x00010000; +pub const DT_RTLREADING: UINT = 0x00020000; +pub const DT_WORD_ELLIPSIS: UINT = 0x00040000; +pub const DT_NOFULLWIDTHCHARBREAK: UINT = 0x00080000; +pub const DT_HIDEPREFIX: UINT = 0x00100000; +pub const DT_PREFIXONLY: UINT = 0x00200000; +STRUCT!{struct DRAWTEXTPARAMS { + cbSize: UINT, + iTabLength: c_int, + iLeftMargin: c_int, + iRightMargin: c_int, + uiLengthDrawn: UINT, +}} +pub type LPDRAWTEXTPARAMS = *mut DRAWTEXTPARAMS; +extern "system" { + pub fn DrawTextA( + hdc: HDC, + lpchText: LPCSTR, + cchText: c_int, + lprc: LPRECT, + format: UINT, + ) -> c_int; + pub fn DrawTextW( + hdc: HDC, + lpchText: LPCWSTR, + cchText: c_int, + lprc: LPRECT, + format: UINT, + ) -> c_int; + pub fn DrawTextExA( + hdc: HDC, + lpchText: LPCSTR, + cchText: c_int, + lprc: LPRECT, + format: UINT, + lpdtp: LPDRAWTEXTPARAMS, + ) -> c_int; + pub fn DrawTextExW( + hdc: HDC, + lpchText: LPCWSTR, + cchText: c_int, + lprc: LPRECT, + format: UINT, + lpdtp: LPDRAWTEXTPARAMS, + ) -> c_int; + pub fn GrayStringA( + hDC: HDC, + hBrush: HBRUSH, + lpOutputFunc: GRAYSTRINGPROC, + lpData: LPARAM, + nCount: c_int, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + ) -> BOOL; + pub fn GrayStringW( + hDC: HDC, + hBrush: HBRUSH, + lpOutputFunc: GRAYSTRINGPROC, + lpData: LPARAM, + nCount: c_int, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + ) -> BOOL; +} +pub const DST_COMPLEX: UINT = 0x0000; +pub const DST_TEXT: UINT = 0x0001; +pub const DST_PREFIXTEXT: UINT = 0x0002; +pub const DST_ICON: UINT = 0x0003; +pub const DST_BITMAP: UINT = 0x0004; +pub const DSS_NORMAL: UINT = 0x0000; +pub const DSS_UNION: UINT = 0x0010; +pub const DSS_DISABLED: UINT = 0x0020; +pub const DSS_MONO: UINT = 0x0080; +pub const DSS_HIDEPREFIX: UINT = 0x0200; +pub const DSS_PREFIXONLY: UINT = 0x0400; +pub const DSS_RIGHT: UINT = 0x8000; +extern "system" { + pub fn DrawStateA( + hdc: HDC, + hbrFore: HBRUSH, + qfnCallBack: DRAWSTATEPROC, + lData: LPARAM, + wData: WPARAM, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + uFlags: UINT, + ) -> BOOL; + pub fn DrawStateW( + hdc: HDC, + hbrFore: HBRUSH, + qfnCallBack: DRAWSTATEPROC, + lData: LPARAM, + wData: WPARAM, + x: c_int, + y: c_int, + cx: c_int, + cy: c_int, + uFlags: UINT, + ) -> BOOL; + pub fn TabbedTextOutA( + hdc: HDC, + x: c_int, + y: c_int, + lpString: LPCSTR, + chCount: c_int, + nTabPositions: c_int, + lpnTabStopPositions: *const INT, + nTabOrigin: c_int, + ) -> LONG; + pub fn TabbedTextOutW( + hdc: HDC, + x: c_int, + y: c_int, + lpString: LPCWSTR, + chCount: c_int, + nTabPositions: c_int, + lpnTabStopPositions: *const INT, + nTabOrigin: c_int, + ) -> LONG; + pub fn GetTabbedTextExtentA( + hdc: HDC, + lpString: LPCSTR, + chCount: c_int, + nTabPositions: c_int, + lpnTabStopPositions: *const INT, + ) -> DWORD; + pub fn GetTabbedTextExtentW( + hdc: HDC, + lpString: LPCWSTR, + chCount: c_int, + nTabPositions: c_int, + lpnTabStopPositions: *const INT, + ) -> DWORD; + pub fn UpdateWindow( + hWnd: HWND, + ) -> BOOL; + pub fn SetActiveWindow( + hWnd: HWND, + ) -> HWND; + pub fn GetForegroundWindow() -> HWND; + pub fn PaintDesktop( + hdc: HDC, + ) -> BOOL; + pub fn SwitchToThisWindow( + hwnd: HWND, + fUnknown: BOOL, + ); + pub fn SetForegroundWindow( + hWnd: HWND, + ) -> BOOL; + pub fn AllowSetForegroundWindow( + dwProcessId: DWORD, + ) -> BOOL; +} +pub const ASFW_ANY: DWORD = -1i32 as u32; +extern "system" { + pub fn LockSetForegroundWindow( + uLockCode: UINT, + ) -> BOOL; +} +pub const LSFW_LOCK: UINT = 1; +pub const LSFW_UNLOCK: UINT = 2; +extern "system" { + pub fn WindowFromDC( + hDC: HDC, + ) -> HWND; + pub fn GetDC( + hWnd: HWND, + ) -> HDC; + pub fn GetDCEx( + hWnd: HWND, + hrgnClip: HRGN, + flags: DWORD, + ) -> HDC; +} +pub const DCX_WINDOW: DWORD = 0x00000001; +pub const DCX_CACHE: DWORD = 0x00000002; +pub const DCX_NORESETATTRS: DWORD = 0x00000004; +pub const DCX_CLIPCHILDREN: DWORD = 0x00000008; +pub const DCX_CLIPSIBLINGS: DWORD = 0x00000010; +pub const DCX_PARENTCLIP: DWORD = 0x00000020; +pub const DCX_EXCLUDERGN: DWORD = 0x00000040; +pub const DCX_INTERSECTRGN: DWORD = 0x00000080; +pub const DCX_EXCLUDEUPDATE: DWORD = 0x00000100; +pub const DCX_INTERSECTUPDATE: DWORD = 0x00000200; +pub const DCX_LOCKWINDOWUPDATE: DWORD = 0x00000400; +pub const DCX_VALIDATE: DWORD = 0x00200000; +extern "system" { + pub fn GetWindowDC( + hWnd: HWND, + ) -> HDC; + pub fn ReleaseDC( + hWnd: HWND, + hDC: HDC, + ) -> c_int; + pub fn BeginPaint( + hwnd: HWND, + lpPaint: LPPAINTSTRUCT, + ) -> HDC; + pub fn EndPaint( + hWnd: HWND, + lpPaint: *const PAINTSTRUCT, + ) -> BOOL; + pub fn GetUpdateRect( + hWnd: HWND, + lpRect: LPRECT, + bErase: BOOL, + ) -> BOOL; + pub fn GetUpdateRgn( + hWnd: HWND, + hRgn: HRGN, + bErase: BOOL, + ) -> c_int; + pub fn SetWindowRgn( + hWnd: HWND, + hRgn: HRGN, + bRedraw: BOOL, + ) -> c_int; + pub fn GetWindowRgn( + hWnd: HWND, + hRgn: HRGN, + ) -> c_int; + pub fn GetWindowRgnBox( + hWnd: HWND, + lprc: LPRECT, + ) -> c_int; + pub fn ExcludeUpdateRgn( + hDC: HDC, + hWnd: HWND, + ) -> c_int; + pub fn InvalidateRect( + hWnd: HWND, + lpRect: *const RECT, + bErase: BOOL, + ) -> BOOL; + pub fn ValidateRect( + hWnd: HWND, + lpRect: *const RECT, + ) -> BOOL; + pub fn InvalidateRgn( + hWnd: HWND, + hRgn: HRGN, + bErase: BOOL, + ) -> BOOL; + pub fn ValidateRgn( + hWnd: HWND, + hRgn: HRGN, + ) -> BOOL; + pub fn RedrawWindow( + hwnd: HWND, + lprcUpdate: *const RECT, + hrgnUpdate: HRGN, + flags: UINT, + ) -> BOOL; +} +pub const RDW_INVALIDATE: UINT = 0x0001; +pub const RDW_INTERNALPAINT: UINT = 0x0002; +pub const RDW_ERASE: UINT = 0x0004; +pub const RDW_VALIDATE: UINT = 0x0008; +pub const RDW_NOINTERNALPAINT: UINT = 0x0010; +pub const RDW_NOERASE: UINT = 0x0020; +pub const RDW_NOCHILDREN: UINT = 0x0040; +pub const RDW_ALLCHILDREN: UINT = 0x0080; +pub const RDW_UPDATENOW: UINT = 0x0100; +pub const RDW_ERASENOW: UINT = 0x0200; +pub const RDW_FRAME: UINT = 0x0400; +pub const RDW_NOFRAME: UINT = 0x0800; +extern "system" { + pub fn LockWindowUpdate( + hWndLock: HWND, + ) -> BOOL; + pub fn ScrollWindow( + hWnd: HWND, + xAmount: c_int, + yAmount: c_int, + lpRect: *const RECT, + lpClipRect: *const RECT, + ) -> BOOL; + pub fn ScrollDC( + hDC: HDC, + dx: c_int, + dy: c_int, + lprcScroll: *const RECT, + lprcClip: *const RECT, + hrgnUpdate: HRGN, + lprcUpdate: LPRECT, + ) -> BOOL; + pub fn ScrollWindowEx( + hWnd: HWND, + dx: c_int, + dy: c_int, + prcScroll: *const RECT, + prcClip: *const RECT, + hrgnUpdate: HRGN, + prcUpdate: LPRECT, + flags: UINT, + ) -> c_int; +} +pub const SW_SCROLLCHILDREN: UINT = 0x0001; +pub const SW_INVALIDATE: UINT = 0x0002; +pub const SW_ERASE: UINT = 0x0004; +pub const SW_SMOOTHSCROLL: UINT = 0x0010; +extern "system" { + pub fn SetScrollPos( + hWnd: HWND, + nBar: c_int, + nPos: c_int, + bRedraw: BOOL, + ) -> c_int; + pub fn GetScrollPos( + hWnd: HWND, + nBar: c_int, + ) -> c_int; + pub fn SetScrollRange( + hWnd: HWND, + nBar: c_int, + nMinPos: c_int, + nMaxPos: c_int, + bRedraw: BOOL, + ) -> BOOL; + pub fn GetScrollRange( + hWnd: HWND, + nBar: c_int, + lpMinPos: LPINT, + lpMaxPos: LPINT, + ) -> BOOL; + pub fn ShowScrollBar( + hWnd: HWND, + wBar: c_int, + bShow: BOOL, + ) -> BOOL; + pub fn EnableScrollBar( + hWnd: HWND, + wSBflags: UINT, + wArrows: UINT, + ) -> BOOL; +} +pub const ESB_ENABLE_BOTH: UINT = 0x0000; +pub const ESB_DISABLE_BOTH: UINT = 0x0003; +pub const ESB_DISABLE_LEFT: UINT = 0x0001; +pub const ESB_DISABLE_RIGHT: UINT = 0x0002; +pub const ESB_DISABLE_UP: UINT = 0x0001; +pub const ESB_DISABLE_DOWN: UINT = 0x0002; +pub const ESB_DISABLE_LTUP: UINT = ESB_DISABLE_LEFT; +pub const ESB_DISABLE_RTDN: UINT = ESB_DISABLE_RIGHT; +extern "system" { + pub fn SetPropA( + hWnd: HWND, + lpString: LPCSTR, + hData: HANDLE, + ) -> BOOL; + pub fn SetPropW( + hWnd: HWND, + lpString: LPCWSTR, + hData: HANDLE, + ) -> BOOL; + pub fn GetPropA( + hwnd: HWND, + lpString: LPCSTR, + ) -> HANDLE; + pub fn GetPropW( + hwnd: HWND, + lpString: LPCWSTR, + ) -> HANDLE; + pub fn RemovePropA( + hWnd: HWND, + lpStr: LPCSTR, + ) -> HANDLE; + pub fn RemovePropW( + hWnd: HWND, + lpStr: LPCWSTR, + ) -> HANDLE; + pub fn EnumPropsExA( + hWnd: HWND, + lpEnumFunc: PROPENUMPROCA, + lParam: LPARAM, + ) -> c_int; + pub fn EnumPropsExW( + hWnd: HWND, + lpEnumFunc: PROPENUMPROCW, + lParam: LPARAM, + ) -> c_int; + pub fn EnumPropsA( + hWnd: HWND, + lpEnumFunc: PROPENUMPROCA, + ) -> c_int; + pub fn EnumPropsW( + hWnd: HWND, + lpEnumFunc: PROPENUMPROCW, + ) -> c_int; + pub fn SetWindowTextA( + hWnd: HWND, + lpString: LPCSTR, + ) -> BOOL; + pub fn SetWindowTextW( + hWnd: HWND, + lpString: LPCWSTR, + ) -> BOOL; + pub fn GetWindowTextA( + hWnd: HWND, + lpString: LPSTR, + nMaxCount: c_int, + ) -> c_int; + pub fn GetWindowTextW( + hWnd: HWND, + lpString: LPWSTR, + nMaxCount: c_int, + ) -> c_int; + pub fn GetWindowTextLengthA( + hWnd: HWND, + ) -> c_int; + pub fn GetWindowTextLengthW( + hWnd: HWND, + ) -> c_int; + pub fn GetClientRect( + hWnd: HWND, + lpRect: LPRECT, + ) -> BOOL; + pub fn GetWindowRect( + hWnd: HWND, + lpRect: LPRECT, + ) -> BOOL; + pub fn AdjustWindowRect( + lpRect: LPRECT, + dwStyle: DWORD, + bMenu: BOOL, + ) -> BOOL; + pub fn AdjustWindowRectEx( + lpRect: LPRECT, + dwStyle: DWORD, + bMenu: BOOL, + dwExStyle: DWORD, + ) -> BOOL; + pub fn AdjustWindowRectExForDpi( + lpRect: LPRECT, + dwStyle: DWORD, + bMenu: BOOL, + dwExStyle: DWORD, + dpi: UINT, + ) -> BOOL; +} +pub const HELPINFO_WINDOW: UINT = 0x0001; +pub const HELPINFO_MENUITEM: UINT = 0x0002; +STRUCT!{struct HELPINFO { + cbSize: UINT, + iContextType: c_int, + iCtrlId: c_int, + hItemHandle: HANDLE, + dwContextId: DWORD, + MousePos: POINT, +}} +pub type LPHELPINFO = *mut HELPINFO; +extern "system" { + pub fn SetWindowContextHelpId( + _: HWND, + _: DWORD, + ) -> BOOL; + pub fn GetWindowContextHelpId( + _: HWND, + ) -> DWORD; + pub fn SetMenuContextHelpId( + _: HMENU, + _: DWORD, + ) -> BOOL; + pub fn GetMenuContextHelpId( + _: HMENU, + ) -> DWORD; +} +pub const MB_OK: UINT = 0x00000000; +pub const MB_OKCANCEL: UINT = 0x00000001; +pub const MB_ABORTRETRYIGNORE: UINT = 0x00000002; +pub const MB_YESNOCANCEL: UINT = 0x00000003; +pub const MB_YESNO: UINT = 0x00000004; +pub const MB_RETRYCANCEL: UINT = 0x00000005; +pub const MB_CANCELTRYCONTINUE: UINT = 0x00000006; +pub const MB_ICONHAND: UINT = 0x00000010; +pub const MB_ICONQUESTION: UINT = 0x00000020; +pub const MB_ICONEXCLAMATION: UINT = 0x00000030; +pub const MB_ICONASTERISK: UINT = 0x00000040; +pub const MB_USERICON: UINT = 0x00000080; +pub const MB_ICONWARNING: UINT = MB_ICONEXCLAMATION; +pub const MB_ICONERROR: UINT = MB_ICONHAND; +pub const MB_ICONINFORMATION: UINT = MB_ICONASTERISK; +pub const MB_ICONSTOP: UINT = MB_ICONHAND; +pub const MB_DEFBUTTON1: UINT = 0x00000000; +pub const MB_DEFBUTTON2: UINT = 0x00000100; +pub const MB_DEFBUTTON3: UINT = 0x00000200; +pub const MB_DEFBUTTON4: UINT = 0x00000300; +pub const MB_APPLMODAL: UINT = 0x00000000; +pub const MB_SYSTEMMODAL: UINT = 0x00001000; +pub const MB_TASKMODAL: UINT = 0x00002000; +pub const MB_HELP: UINT = 0x00004000; +pub const MB_NOFOCUS: UINT = 0x00008000; +pub const MB_SETFOREGROUND: UINT = 0x00010000; +pub const MB_DEFAULT_DESKTOP_ONLY: UINT = 0x00020000; +pub const MB_TOPMOST: UINT = 0x00040000; +pub const MB_RIGHT: UINT = 0x00080000; +pub const MB_RTLREADING: UINT = 0x00100000; +pub const MB_SERVICE_NOTIFICATION: UINT = 0x00200000; +pub const MB_SERVICE_NOTIFICATION_NT3X: UINT = 0x00040000; +pub const MB_TYPEMASK: UINT = 0x0000000F; +pub const MB_ICONMASK: UINT = 0x000000F0; +pub const MB_DEFMASK: UINT = 0x00000F00; +pub const MB_MODEMASK: UINT = 0x00003000; +pub const MB_MISCMASK: UINT = 0x0000C000; +extern "system" { + pub fn MessageBoxA( + hWnd: HWND, + lpText: LPCSTR, + lpCaption: LPCSTR, + uType: UINT, + ) -> c_int; + pub fn MessageBoxW( + hWnd: HWND, + lpText: LPCWSTR, + lpCaption: LPCWSTR, + uType: UINT, + ) -> c_int; + pub fn MessageBoxExA( + hWnd: HWND, + lpText: LPCSTR, + lpCaption: LPCSTR, + uType: UINT, + wLanguageId: WORD, + ) -> c_int; + pub fn MessageBoxExW( + hWnd: HWND, + lpText: LPCWSTR, + lpCaption: LPCWSTR, + uType: UINT, + wLanguageId: WORD, + ) -> c_int; +} +STRUCT!{struct MSGBOXPARAMSA { + cbSize: UINT, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpszText: LPCSTR, + lpszCaption: LPCSTR, + dwStyle: DWORD, + lpszIcon: LPCSTR, + dwContextHelpId: DWORD_PTR, + lpfnMsgBoxCallback: MSGBOXCALLBACK, + dwLanguageId: DWORD, +}} +pub type PMSGBOXPARAMSA = *mut MSGBOXPARAMSA; +pub type LPMSGBOXPARAMSA = *mut MSGBOXPARAMSA; +STRUCT!{struct MSGBOXPARAMSW { + cbSize: UINT, + hwndOwner: HWND, + hInstance: HINSTANCE, + lpszText: LPCWSTR, + lpszCaption: LPCWSTR, + dwStyle: DWORD, + lpszIcon: LPCWSTR, + dwContextHelpId: DWORD_PTR, + lpfnMsgBoxCallback: MSGBOXCALLBACK, + dwLanguageId: DWORD, +}} +pub type PMSGBOXPARAMSW = *mut MSGBOXPARAMSW; +pub type LPMSGBOXPARAMSW = *mut MSGBOXPARAMSW; +extern "system" { + pub fn MessageBoxIndirectA( + lpmbp: *const MSGBOXPARAMSA, + ) -> c_int; + pub fn MessageBoxIndirectW( + lpmbp: *const MSGBOXPARAMSW, + ) -> c_int; + pub fn MessageBeep( + uType: UINT, + ) -> BOOL; + pub fn ShowCursor( + bShow: BOOL, + ) -> c_int; + pub fn SetCursorPos( + X: c_int, + Y: c_int, + ) -> BOOL; + pub fn SetPhysicalCursorPos( + X: c_int, + Y: c_int, + ) -> BOOL; + pub fn SetCursor( + hCursor: HCURSOR, + ) -> HCURSOR; + pub fn GetCursorPos( + lpPoint: LPPOINT, + ) -> BOOL; + pub fn GetPhysicalCursorPos( + lpPoint: LPPOINT, + ) -> BOOL; + pub fn GetClipCursor( + lpRect: LPRECT, + ) -> BOOL; + pub fn GetCursor() -> HCURSOR; + pub fn CreateCaret( + hWnd: HWND, + hBitmap: HBITMAP, + nWidth: c_int, + nHeight: c_int, + ) -> BOOL; + pub fn GetCaretBlinkTime() -> UINT; + pub fn SetCaretBlinkTime( + uMSeconds: UINT, + ) -> BOOL; + pub fn DestroyCaret() -> BOOL; + pub fn HideCaret( + hWnd: HWND, + ) -> BOOL; + pub fn ShowCaret( + hWnd: HWND, + ) -> BOOL; + pub fn SetCaretPos( + X: c_int, + Y: c_int, + ) -> BOOL; + pub fn GetCaretPos( + lpPoint: LPPOINT, + ) -> BOOL; + pub fn ClientToScreen( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn ScreenToClient( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn LogicalToPhysicalPoint( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn PhysicalToLogicalPoint( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn LogicalToPhysicalPointForPerMonitorDPI( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn PhysicalToLogicalPointForPerMonitorDPI( + hWnd: HWND, + lpPoint: LPPOINT, + ) -> BOOL; + pub fn MapWindowPoints( + hWndFrom: HWND, + hWndTo: HWND, + lpPoints: LPPOINT, + cPoints: UINT, + ) -> c_int; + pub fn WindowFromPoint( + Point: POINT, + ) -> HWND; + pub fn WindowFromPhysicalPoint( + Point: POINT, + ) -> HWND; + pub fn ChildWindowFromPoint( + hWndParent: HWND, + point: POINT, + ) -> HWND; + pub fn ClipCursor( + lpRect: *const RECT, + ) -> BOOL; +} +pub const CWP_ALL: UINT = 0x0000; +pub const CWP_SKIPINVISIBLE: UINT = 0x0001; +pub const CWP_SKIPDISABLED: UINT = 0x0002; +pub const CWP_SKIPTRANSPARENT: UINT = 0x0004; +extern "system" { + pub fn ChildWindowFromPointEx( + hwnd: HWND, + pt: POINT, + flags: UINT, + ) -> HWND; +} +pub const CTLCOLOR_MSGBOX: c_int = 0; +pub const CTLCOLOR_EDIT: c_int = 1; +pub const CTLCOLOR_LISTBOX: c_int = 2; +pub const CTLCOLOR_BTN: c_int = 3; +pub const CTLCOLOR_DLG: c_int = 4; +pub const CTLCOLOR_SCROLLBAR: c_int = 5; +pub const CTLCOLOR_STATIC: c_int = 6; +pub const CTLCOLOR_MAX: c_int = 7; +pub const COLOR_SCROLLBAR: c_int = 0; +pub const COLOR_BACKGROUND: c_int = 1; +pub const COLOR_ACTIVECAPTION: c_int = 2; +pub const COLOR_INACTIVECAPTION: c_int = 3; +pub const COLOR_MENU: c_int = 4; +pub const COLOR_WINDOW: c_int = 5; +pub const COLOR_WINDOWFRAME: c_int = 6; +pub const COLOR_MENUTEXT: c_int = 7; +pub const COLOR_WINDOWTEXT: c_int = 8; +pub const COLOR_CAPTIONTEXT: c_int = 9; +pub const COLOR_ACTIVEBORDER: c_int = 10; +pub const COLOR_INACTIVEBORDER: c_int = 11; +pub const COLOR_APPWORKSPACE: c_int = 12; +pub const COLOR_HIGHLIGHT: c_int = 13; +pub const COLOR_HIGHLIGHTTEXT: c_int = 14; +pub const COLOR_BTNFACE: c_int = 15; +pub const COLOR_BTNSHADOW: c_int = 16; +pub const COLOR_GRAYTEXT: c_int = 17; +pub const COLOR_BTNTEXT: c_int = 18; +pub const COLOR_INACTIVECAPTIONTEXT: c_int = 19; +pub const COLOR_BTNHIGHLIGHT: c_int = 20; +pub const COLOR_3DDKSHADOW: c_int = 21; +pub const COLOR_3DLIGHT: c_int = 22; +pub const COLOR_INFOTEXT: c_int = 23; +pub const COLOR_INFOBK: c_int = 24; +pub const COLOR_HOTLIGHT: c_int = 26; +pub const COLOR_GRADIENTACTIVECAPTION: c_int = 27; +pub const COLOR_GRADIENTINACTIVECAPTION: c_int = 28; +pub const COLOR_MENUHILIGHT: c_int = 29; +pub const COLOR_MENUBAR: c_int = 30; +pub const COLOR_DESKTOP: c_int = COLOR_BACKGROUND; +pub const COLOR_3DFACE: c_int = COLOR_BTNFACE; +pub const COLOR_3DSHADOW: c_int = COLOR_BTNSHADOW; +pub const COLOR_3DHIGHLIGHT: c_int = COLOR_BTNHIGHLIGHT; +pub const COLOR_3DHILIGHT: c_int = COLOR_BTNHIGHLIGHT; +pub const COLOR_BTNHILIGHT: c_int = COLOR_BTNHIGHLIGHT; +extern "system" { + pub fn GetSysColor( + nIndex: c_int, + ) -> DWORD; + pub fn GetSysColorBrush( + nIndex: c_int, + ) -> HBRUSH; + pub fn SetSysColors( + cElements: c_int, + lpaElements: *const INT, + lpaRgbValues: *const COLORREF, + ) -> BOOL; + pub fn DrawFocusRect( + hDC: HDC, + lprc: *const RECT, + ) -> BOOL; + pub fn FillRect( + hDC: HDC, + lprc: *const RECT, + hbr: HBRUSH, + ) -> c_int; + pub fn FrameRect( + hDC: HDC, + lprc: *const RECT, + hbr: HBRUSH, + ) -> c_int; + pub fn InvertRect( + hDC: HDC, + lprc: *const RECT, + ) -> BOOL; + pub fn SetRect( + lprc: LPRECT, + xLeft: c_int, + yTop: c_int, + xRight: c_int, + yBottom: c_int, + ) -> BOOL; + pub fn SetRectEmpty( + lprc: LPRECT, + ) -> BOOL; + pub fn CopyRect( + lprcDst: LPRECT, + lprcSrc: *const RECT, + ) -> BOOL; + pub fn InflateRect( + lprc: LPRECT, + dx: c_int, + dy: c_int, + ) -> BOOL; + pub fn IntersectRect( + lprcDst: LPRECT, + lprcSrc1: *const RECT, + lprcSrc2: *const RECT, + ) -> BOOL; + pub fn UnionRect( + lprcDst: LPRECT, + lprcSrc1: *const RECT, + lprcSrc2: *const RECT, + ) -> BOOL; + pub fn SubtractRect( + lprcDst: LPRECT, + lprcSrc1: *const RECT, + lprcSrc2: *const RECT, + ) -> BOOL; + pub fn OffsetRect( + lprc: LPRECT, + dx: c_int, + dy: c_int, + ) -> BOOL; + pub fn IsRectEmpty( + lprc: *const RECT, + ) -> BOOL; + pub fn EqualRect( + lprc1: *const RECT, + lprc2: *const RECT, + ) -> BOOL; + pub fn PtInRect( + lprc: *const RECT, + pt: POINT, + ) -> BOOL; + pub fn GetWindowWord( + hWnd: HWND, + nIndex: c_int, + ) -> WORD; + pub fn SetWindowWord( + hwnd: HWND, + nIndex: c_int, + wNewWord: WORD, + ) -> WORD; + pub fn GetWindowLongA( + hWnd: HWND, + nIndex: c_int, + ) -> LONG; + pub fn GetWindowLongW( + hWnd: HWND, + nIndex: c_int, + ) -> LONG; + pub fn SetWindowLongA( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG, + ) -> LONG; + pub fn SetWindowLongW( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG, + ) -> LONG; + #[cfg(target_pointer_width = "64")] + pub fn GetWindowLongPtrA( + hWnd: HWND, + nIndex: c_int, + ) -> LONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn GetWindowLongPtrW( + hWnd: HWND, + nIndex: c_int, + ) -> LONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn SetWindowLongPtrA( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG_PTR, + ) -> LONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn SetWindowLongPtrW( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG_PTR, + ) -> LONG_PTR; +} +#[cfg(target_arch = "x86")] +pub use self::GetWindowLongA as GetWindowLongPtrA; +#[cfg(target_arch = "x86")] +pub use self::GetWindowLongW as GetWindowLongPtrW; +#[cfg(target_arch = "x86")] +pub use self::SetWindowLongA as SetWindowLongPtrA; +#[cfg(target_arch = "x86")] +pub use self::SetWindowLongW as SetWindowLongPtrW; +extern "system" { + pub fn GetClassWord( + hWnd: HWND, + nIndex: c_int, + ) -> WORD; + pub fn SetClassWord( + hWnd: HWND, + nIndex: c_int, + wNewWord: WORD, + ) -> WORD; + pub fn GetClassLongA( + hWnd: HWND, + nIndex: c_int, + ) -> DWORD; + pub fn GetClassLongW( + hWnd: HWND, + nIndex: c_int, + ) -> DWORD; + pub fn SetClassLongA( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG, + ) -> DWORD; + pub fn SetClassLongW( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG, + ) -> DWORD; + #[cfg(target_pointer_width = "64")] + pub fn GetClassLongPtrA( + hWnd: HWND, + nIndex: c_int, + ) -> ULONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn GetClassLongPtrW( + hWnd: HWND, + nIndex: c_int, + ) -> ULONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn SetClassLongPtrA( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG_PTR, + ) -> ULONG_PTR; + #[cfg(target_pointer_width = "64")] + pub fn SetClassLongPtrW( + hWnd: HWND, + nIndex: c_int, + dwNewLong: LONG_PTR, + ) -> ULONG_PTR; +} +#[cfg(target_arch = "x86")] +pub use self::GetClassLongA as GetClassLongPtrA; +#[cfg(target_arch = "x86")] +pub use self::GetClassLongW as GetClassLongPtrW; +#[cfg(target_arch = "x86")] +pub use self::SetClassLongA as SetClassLongPtrA; +#[cfg(target_arch = "x86")] +pub use self::SetClassLongW as SetClassLongPtrW; +extern "system" { + pub fn GetProcessDefaultLayout( + pdwDefaultLayout: *mut DWORD, + ) -> BOOL; + pub fn SetProcessDefaultLayout( + dwDefaultLayout: DWORD, + ) -> BOOL; + pub fn GetDesktopWindow() -> HWND; + pub fn GetParent( + hWnd: HWND, + ) -> HWND; + pub fn SetParent( + hWndChild: HWND, + hWndNewParent: HWND, + ) -> HWND; + pub fn EnumChildWindows( + hWndParent: HWND, + lpEnumFunc: WNDENUMPROC, + lParam: LPARAM, + ) -> BOOL; + pub fn FindWindowA( + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + ) -> HWND; + pub fn FindWindowW( + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + ) -> HWND; + pub fn FindWindowExA( + hWndParent: HWND, + hWndChildAfter: HWND, + lpszClass: LPCSTR, + lpszWindow: LPCSTR, + ) -> HWND; + pub fn FindWindowExW( + hWndParent: HWND, + hWndChildAfter: HWND, + lpszClass: LPCWSTR, + lpszWindow: LPCWSTR, + ) -> HWND; + pub fn GetShellWindow() -> HWND; + pub fn RegisterShellHookWindow( + hwnd: HWND, + ) -> BOOL; + pub fn DeregisterShellHookWindow( + hwnd: HWND, + ) -> BOOL; + pub fn EnumWindows( + lpEnumFunc: WNDENUMPROC, + lParam: LPARAM, + ) -> BOOL; + pub fn EnumThreadWindows( + dwThreadId: DWORD, + lpfn: WNDENUMPROC, + lParam: LPARAM, + ) -> BOOL; +} +// EnumTaskWindows +extern "system" { + pub fn GetClassNameA( + hWnd: HWND, + lpClassName: LPCSTR, + nMaxCount: c_int, + ) -> c_int; + pub fn GetClassNameW( + hWnd: HWND, + lpClassName: LPCWSTR, + nMaxCount: c_int, + ) -> c_int; + pub fn GetTopWindow( + hWnd: HWND, + ) -> HWND; +} +// GetNextWindow +// GetSysModalWindow +// SetSysModalWindow +extern "system" { + pub fn GetWindowThreadProcessId( + hWnd: HWND, + lpdwProcessId: LPDWORD, + ) -> DWORD; + pub fn IsGUIThread( + bConvert: BOOL, + ) -> BOOL; + pub fn GetLastActivePopup( + hWnd: HWND, + ) -> HWND; +} +pub const GW_HWNDFIRST: UINT = 0; +pub const GW_HWNDLAST: UINT = 1; +pub const GW_HWNDNEXT: UINT = 2; +pub const GW_HWNDPREV: UINT = 3; +pub const GW_OWNER: UINT = 4; +pub const GW_CHILD: UINT = 5; +pub const GW_ENABLEDPOPUP: UINT = 6; +pub const GW_MAX: UINT = 6; +extern "system" { + pub fn GetWindow( + hWnd: HWND, + uCmd: UINT, + ) -> HWND; + pub fn SetWindowsHookA( + nFilterType: c_int, + pfnFilterProc: HOOKPROC, + ) -> HHOOK; + pub fn SetWindowsHookW( + nFilterType: c_int, + pfnFilterProc: HOOKPROC, + ) -> HHOOK; + pub fn UnhookWindowsHook( + nFilterType: c_int, + pfnFilterProc: HOOKPROC, + ) -> BOOL; + pub fn SetWindowsHookExA( + idHook: c_int, + lpfn: HOOKPROC, + hmod: HINSTANCE, + dwThreadId: DWORD, + ) -> HHOOK; + pub fn SetWindowsHookExW( + idHook: c_int, + lpfn: HOOKPROC, + hmod: HINSTANCE, + dwThreadId: DWORD, + ) -> HHOOK; + pub fn UnhookWindowsHookEx( + hhk: HHOOK, + ) -> BOOL; + pub fn CallNextHookEx( + hhk: HHOOK, + nCode: c_int, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; +} +// DefHookProc +pub const MF_INSERT: UINT = 0x00000000; +pub const MF_CHANGE: UINT = 0x00000080; +pub const MF_APPEND: UINT = 0x00000100; +pub const MF_DELETE: UINT = 0x00000200; +pub const MF_REMOVE: UINT = 0x00001000; +pub const MF_BYCOMMAND: UINT = 0x00000000; +pub const MF_BYPOSITION: UINT = 0x00000400; +pub const MF_SEPARATOR: UINT = 0x00000800; +pub const MF_ENABLED: UINT = 0x00000000; +pub const MF_GRAYED: UINT = 0x00000001; +pub const MF_DISABLED: UINT = 0x00000002; +pub const MF_UNCHECKED: UINT = 0x00000000; +pub const MF_CHECKED: UINT = 0x00000008; +pub const MF_USECHECKBITMAPS: UINT = 0x00000200; +pub const MF_STRING: UINT = 0x00000000; +pub const MF_BITMAP: UINT = 0x00000004; +pub const MF_OWNERDRAW: UINT = 0x00000100; +pub const MF_POPUP: UINT = 0x00000010; +pub const MF_MENUBARBREAK: UINT = 0x00000020; +pub const MF_MENUBREAK: UINT = 0x00000040; +pub const MF_UNHILITE: UINT = 0x00000000; +pub const MF_HILITE: UINT = 0x00000080; +pub const MF_DEFAULT: UINT = 0x00001000; +pub const MF_SYSMENU: UINT = 0x00002000; +pub const MF_HELP: UINT = 0x00004000; +pub const MF_RIGHTJUSTIFY: UINT = 0x00004000; +pub const MF_MOUSESELECT: UINT = 0x00008000; +pub const MF_END: UINT = 0x00000080; +pub const MFT_STRING: UINT = MF_STRING; +pub const MFT_BITMAP: UINT = MF_BITMAP; +pub const MFT_MENUBARBREAK: UINT = MF_MENUBARBREAK; +pub const MFT_MENUBREAK: UINT = MF_MENUBREAK; +pub const MFT_OWNERDRAW: UINT = MF_OWNERDRAW; +pub const MFT_RADIOCHECK: UINT = 0x00000200; +pub const MFT_SEPARATOR: UINT = MF_SEPARATOR; +pub const MFT_RIGHTORDER: UINT = 0x00002000; +pub const MFT_RIGHTJUSTIFY: UINT = MF_RIGHTJUSTIFY; +pub const MFS_GRAYED: UINT = 0x00000003; +pub const MFS_DISABLED: UINT = MFS_GRAYED; +pub const MFS_CHECKED: UINT = MF_CHECKED; +pub const MFS_HILITE: UINT = MF_HILITE; +pub const MFS_ENABLED: UINT = MF_ENABLED; +pub const MFS_UNCHECKED: UINT = MF_UNCHECKED; +pub const MFS_UNHILITE: UINT = MF_UNHILITE; +pub const MFS_DEFAULT: UINT = MF_DEFAULT; +extern "system" { + pub fn CheckMenuRadioItem( + hMenu: HMENU, + first: UINT, + last: UINT, + check: UINT, + flags: UINT, + ) -> BOOL; +} +/********* +* CUTOFF * +*********/ +pub const IDOK: c_int = 1; +pub const IDCANCEL: c_int = 2; +pub const IDABORT: c_int = 3; +pub const IDRETRY: c_int = 4; +pub const IDIGNORE: c_int = 5; +pub const IDYES: c_int = 6; +pub const IDNO: c_int = 7; +pub const IDCLOSE: c_int = 8; +pub const IDHELP: c_int = 9; +pub const IDTRYAGAIN: c_int = 10; +pub const IDCONTINUE: c_int = 11; +pub const IDTIMEOUT: c_int = 32000; +// Edit Control Styles +// +pub const ES_LEFT: DWORD = 0x0000; +pub const ES_CENTER: DWORD = 0x0001; +pub const ES_RIGHT: DWORD = 0x0002; +pub const ES_MULTILINE: DWORD = 0x0004; +pub const ES_UPPERCASE: DWORD = 0x0008; +pub const ES_LOWERCASE: DWORD = 0x0010; +pub const ES_PASSWORD: DWORD = 0x0020; +pub const ES_AUTOVSCROLL: DWORD = 0x0040; +pub const ES_AUTOHSCROLL: DWORD = 0x0080; +pub const ES_NOHIDESEL: DWORD = 0x0100; +pub const ES_OEMCONVERT: DWORD = 0x0400; +pub const ES_READONLY: DWORD = 0x0800; +pub const ES_WANTRETURN: DWORD = 0x1000; +pub const ES_NUMBER: DWORD = 0x2000; +// Edit Control Notification Codes +// +pub const EN_SETFOCUS: WORD = 0x0100; +pub const EN_KILLFOCUS: WORD = 0x0200; +pub const EN_CHANGE: WORD = 0x0300; +pub const EN_UPDATE: WORD = 0x0400; +pub const EN_ERRSPACE: WORD = 0x0500; +pub const EN_MAXTEXT: WORD = 0x0501; +pub const EN_HSCROLL: WORD = 0x0601; +pub const EN_VSCROLL: WORD = 0x0602; +pub const EN_ALIGN_LTR_EC: WORD = 0x0700; +pub const EN_ALIGN_RTL_EC: WORD = 0x0701; +// Edit control EM_SETMARGIN parameters +pub const EC_LEFTMARGIN: WORD = 0x0001; +pub const EC_RIGHTMARGIN: WORD = 0x0002; +pub const EC_USEFONTINFO: WORD = 0xffff; +// wParam of EM_GET/SETIMESTATUS +pub const EMSIS_COMPOSITIONSTRING: WORD = 0x0001; +// lParam for EMSIS_COMPOSITIONSTRING +pub const EIMES_GETCOMPSTRATONCE: WORD = 0x0001; +pub const EIMES_CANCELCOMPSTRINFOCUS: WORD = 0x0002; +pub const EIMES_COMPLETECOMPSTRKILLFOCUS: WORD = 0x0004; +// Edit Control Messages +// +pub const EM_GETSEL: WORD = 0x00B0; +pub const EM_SETSEL: WORD = 0x00B1; +pub const EM_GETRECT: WORD = 0x00B2; +pub const EM_SETRECT: WORD = 0x00B3; +pub const EM_SETRECTNP: WORD = 0x00B4; +pub const EM_SCROLL: WORD = 0x00B5; +pub const EM_LINESCROLL: WORD = 0x00B6; +pub const EM_SCROLLCARET: WORD = 0x00B7; +pub const EM_GETMODIFY: WORD = 0x00B8; +pub const EM_SETMODIFY: WORD = 0x00B9; +pub const EM_GETLINECOUNT: WORD = 0x00BA; +pub const EM_LINEINDEX: WORD = 0x00BB; +pub const EM_SETHANDLE: WORD = 0x00BC; +pub const EM_GETHANDLE: WORD = 0x00BD; +pub const EM_GETTHUMB: WORD = 0x00BE; +pub const EM_LINELENGTH: WORD = 0x00C1; +pub const EM_REPLACESEL: WORD = 0x00C2; +pub const EM_GETLINE: WORD = 0x00C4; +pub const EM_LIMITTEXT: WORD = 0x00C5; +pub const EM_CANUNDO: WORD = 0x00C6; +pub const EM_UNDO: WORD = 0x00C7; +pub const EM_FMTLINES: WORD = 0x00C8; +pub const EM_LINEFROMCHAR: WORD = 0x00C9; +pub const EM_SETTABSTOPS: WORD = 0x00CB; +pub const EM_SETPASSWORDCHAR: WORD = 0x00CC; +pub const EM_EMPTYUNDOBUFFER: WORD = 0x00CD; +pub const EM_GETFIRSTVISIBLELINE: WORD = 0x00CE; +pub const EM_SETREADONLY: WORD = 0x00CF; +pub const EM_SETWORDBREAKPROC: WORD = 0x00D0; +pub const EM_GETWORDBREAKPROC: WORD = 0x00D1; +pub const EM_GETPASSWORDCHAR: WORD = 0x00D2; +pub const EM_SETMARGINS: WORD = 0x00D3; +pub const EM_GETMARGINS: WORD = 0x00D4; +pub const EM_SETLIMITTEXT: WORD = EM_LIMITTEXT; +pub const EM_GETLIMITTEXT: WORD = 0x00D5; +pub const EM_POSFROMCHAR: WORD = 0x00D6; +pub const EM_CHARFROMPOS: WORD = 0x00D7; +pub const EM_SETIMESTATUS: WORD = 0x00D8; +pub const EM_GETIMESTATUS: WORD = 0x00D9; +// EDITWORDBREAKPROC code values +// +pub const WB_LEFT: WORD = 0; +pub const WB_RIGHT: WORD = 1; +pub const WB_ISDELIMITER: WORD = 2; +pub const BN_CLICKED: WORD = 0; +pub const BN_PAINT: WORD = 1; +pub const BN_HILITE: WORD = 2; +pub const BN_UNHILITE: WORD = 3; +pub const BN_DISABLE: WORD = 4; +pub const BN_DOUBLECLICKED: WORD = 5; +pub const BN_PUSHED: WORD = BN_HILITE; +pub const BN_UNPUSHED: WORD = BN_UNHILITE; +pub const BN_DBLCLK: WORD = BN_DOUBLECLICKED; +pub const BN_SETFOCUS: WORD = 6; +pub const BN_KILLFOCUS: WORD = 7; +pub const BS_PUSHBUTTON: DWORD = 0x00000000; +pub const BS_DEFPUSHBUTTON: DWORD = 0x00000001; +pub const BS_CHECKBOX: DWORD = 0x00000002; +pub const BS_AUTOCHECKBOX: DWORD = 0x00000003; +pub const BS_RADIOBUTTON: DWORD = 0x00000004; +pub const BS_3STATE: DWORD = 0x00000005; +pub const BS_AUTO3STATE: DWORD = 0x00000006; +pub const BS_GROUPBOX: DWORD = 0x00000007; +pub const BS_USERBUTTON: DWORD = 0x00000008; +pub const BS_AUTORADIOBUTTON: DWORD = 0x00000009; +pub const BS_PUSHBOX: DWORD = 0x0000000A; +pub const BS_OWNERDRAW: DWORD = 0x0000000B; +pub const BS_TYPEMASK: DWORD = 0x0000000F; +pub const BS_LEFTTEXT: DWORD = 0x00000020; +pub const BS_TEXT: DWORD = 0x00000000; +pub const BS_ICON: DWORD = 0x00000040; +pub const BS_BITMAP: DWORD = 0x00000080; +pub const BS_LEFT: DWORD = 0x00000100; +pub const BS_RIGHT: DWORD = 0x00000200; +pub const BS_CENTER: DWORD = 0x00000300; +pub const BS_TOP: DWORD = 0x00000400; +pub const BS_BOTTOM: DWORD = 0x00000800; +pub const BS_VCENTER: DWORD = 0x00000C00; +pub const BS_PUSHLIKE: DWORD = 0x00001000; +pub const BS_MULTILINE: DWORD = 0x00002000; +pub const BS_NOTIFY: DWORD = 0x00004000; +pub const BS_FLAT: DWORD = 0x00008000; +pub const BS_RIGHTBUTTON: DWORD = BS_LEFTTEXT; +pub const BM_GETCHECK: UINT = 0x00F0; +pub const BM_SETCHECK: UINT = 0x00F1; +pub const BM_GETSTATE: UINT = 0x00F2; +pub const BM_SETSTATE: UINT = 0x00F3; +pub const BM_SETSTYLE: UINT = 0x00F4; +pub const BM_CLICK: UINT = 0x00F5; +pub const BM_GETIMAGE: UINT = 0x00F6; +pub const BM_SETIMAGE: UINT = 0x00F7; +pub const BM_SETDONTCLICK: UINT = 0x00F8; +pub const BST_UNCHECKED: WPARAM = 0x0000; +pub const BST_CHECKED: WPARAM = 0x0001; +pub const BST_INDETERMINATE: WPARAM = 0x0002; +pub const BST_PUSHED: LRESULT = 0x0004; +pub const BST_FOCUS: LRESULT = 0x0008; +pub const SS_LEFT: DWORD = 0x00000000; +pub const SS_CENTER: DWORD = 0x00000001; +pub const SS_RIGHT: DWORD = 0x00000002; +pub const SS_ICON: DWORD = 0x00000003; +pub const SS_BLACKRECT: DWORD = 0x00000004; +pub const SS_GRAYRECT: DWORD = 0x00000005; +pub const SS_WHITERECT: DWORD = 0x00000006; +pub const SS_BLACKFRAME: DWORD = 0x00000007; +pub const SS_GRAYFRAME: DWORD = 0x00000008; +pub const SS_WHITEFRAME: DWORD = 0x00000009; +pub const SS_USERITEM: DWORD = 0x0000000A; +pub const SS_SIMPLE: DWORD = 0x0000000B; +pub const SS_LEFTNOWORDWRAP: DWORD = 0x0000000C; +pub const SS_OWNERDRAW: DWORD = 0x0000000D; +pub const SS_BITMAP: DWORD = 0x0000000E; +pub const SS_ENHMETAFILE: DWORD = 0x0000000F; +pub const SS_ETCHEDHORZ: DWORD = 0x00000010; +pub const SS_ETCHEDVERT: DWORD = 0x00000011; +pub const SS_ETCHEDFRAME: DWORD = 0x00000012; +pub const SS_TYPEMASK: DWORD = 0x0000001F; +pub const SS_REALSIZECONTROL: DWORD = 0x00000040; +pub const SS_NOPREFIX: DWORD = 0x00000080; +pub const SS_NOTIFY: DWORD = 0x00000100; +pub const SS_CENTERIMAGE: DWORD = 0x00000200; +pub const SS_RIGHTJUST: DWORD = 0x00000400; +pub const SS_REALSIZEIMAGE: DWORD = 0x00000800; +pub const SS_SUNKEN: DWORD = 0x00001000; +pub const SS_EDITCONTROL: DWORD = 0x00002000; +pub const SS_ENDELLIPSIS: DWORD = 0x00004000; +pub const SS_PATHELLIPSIS: DWORD = 0x00008000; +pub const SS_WORDELLIPSIS: DWORD = 0x0000C000; +pub const SS_ELLIPSISMASK: DWORD = 0x0000C000; +pub const STM_SETICON: UINT = 0x0170; +pub const STM_GETICON: UINT = 0x0171; +pub const STM_SETIMAGE: UINT = 0x0172; +pub const STM_GETIMAGE: UINT = 0x0173; +pub const STN_CLICKED: WORD = 0; +pub const STN_DBLCLK: WORD = 1; +pub const STN_ENABLE: WORD = 2; +pub const STN_DISABLE: WORD = 3; +pub const STM_MSGMAX: WORD = 0x0174; +extern "system" { + pub fn IsDialogMessageA( + hDlg: HWND, + lpMsg: LPMSG, + ) -> BOOL; + pub fn IsDialogMessageW( + hDlg: HWND, + lpMsg: LPMSG, + ) -> BOOL; + pub fn MapDialogRect( + hDlg: HWND, + lpRect: LPRECT, + ) -> BOOL; + pub fn DlgDirListA( + hDlg: HWND, + lpPathSpec: LPSTR, + nIDListBox: c_int, + nIDStaticPath: c_int, + uFileType: UINT, + ) -> c_int; + pub fn DlgDirListW( + hDlg: HWND, + lpPathSpec: LPWSTR, + nIDListBox: c_int, + nIDStaticPath: c_int, + uFileType: UINT, + ) -> c_int; + pub fn DlgDirSelectExA( + hwndDlg: HWND, + lpString: LPSTR, + chCount: c_int, + idListBox: c_int, + ) -> BOOL; + pub fn DlgDirSelectExW( + hwndDlg: HWND, + lpString: LPWSTR, + chCount: c_int, + idListBox: c_int, + ) -> BOOL; + pub fn DlgDirListComboBoxA( + hDlg: HWND, + lpPathSpec: LPSTR, + nIDComboBox: c_int, + nIDStaticPath: c_int, + uFiletype: UINT, + ) -> c_int; + pub fn DlgDirListComboBoxW( + hDlg: HWND, + lpPathSpec: LPWSTR, + nIDComboBox: c_int, + nIDStaticPath: c_int, + uFiletype: UINT, + ) -> c_int; + pub fn DlgDirSelectComboBoxExA( + hwndDlg: HWND, + lpString: LPSTR, + cchOut: c_int, + idComboBox: c_int, + ) -> BOOL; + pub fn DlgDirSelectComboBoxExW( + hwndDlg: HWND, + lpString: LPWSTR, + cchOut: c_int, + idComboBox: c_int, + ) -> BOOL; +} +pub const DS_ABSALIGN: DWORD = 0x01; +pub const DS_SYSMODAL: DWORD = 0x02; +pub const DS_LOCALEDIT: DWORD = 0x20; +pub const DS_SETFONT: DWORD = 0x40; +pub const DS_MODALFRAME: DWORD = 0x80; +pub const DS_NOIDLEMSG: DWORD = 0x100; +pub const DS_SETFOREGROUND: DWORD = 0x200; +pub const DS_3DLOOK: DWORD = 0x0004; +pub const DS_FIXEDSYS: DWORD = 0x0008; +pub const DS_NOFAILCREATE: DWORD = 0x0010; +pub const DS_CONTROL: DWORD = 0x0400; +pub const DS_CENTER: DWORD = 0x0800; +pub const DS_CENTERMOUSE: DWORD = 0x1000; +pub const DS_CONTEXTHELP: DWORD = 0x2000; +pub const DS_SHELLFONT: DWORD = DS_SETFONT | DS_FIXEDSYS; +pub const DS_USEPIXELS: DWORD = 0x8000; +pub const DM_GETDEFID: UINT = WM_USER + 0; +pub const DM_SETDEFID: UINT = WM_USER + 1; +pub const DM_REPOSITION: UINT = WM_USER + 2; +pub const DC_HASDEFID: WORD = 0x534B; +pub const DLGC_WANTARROWS: LRESULT = 0x0001; +pub const DLGC_WANTTAB: LRESULT = 0x0002; +pub const DLGC_WANTALLKEYS: LRESULT = 0x0004; +pub const DLGC_WANTMESSAGE: LRESULT = 0x0004; +pub const DLGC_HASSETSEL: LRESULT = 0x0008; +pub const DLGC_DEFPUSHBUTTON: LRESULT = 0x0010; +pub const DLGC_UNDEFPUSHBUTTON: LRESULT = 0x0020; +pub const DLGC_RADIOBUTTON: LRESULT = 0x0040; +pub const DLGC_WANTCHARS: LRESULT = 0x0080; +pub const DLGC_STATIC: LRESULT = 0x0100; +pub const DLGC_BUTTON: LRESULT = 0x2000; +pub const LB_OKAY: LRESULT = 0; +pub const LB_ERR: LRESULT = -1; +pub const LB_ERRSPACE: LRESULT = -2; +pub const LBN_ERRSPACE: WORD = -2i16 as u16; +pub const LBN_SELCHANGE: WORD = 1; +pub const LBN_DBLCLK: WORD = 2; +pub const LBN_SELCANCEL: WORD = 3; +pub const LBN_SETFOCUS: WORD = 4; +pub const LBN_KILLFOCUS: WORD = 5; +pub const LB_ADDSTRING: UINT = 0x0180; +pub const LB_INSERTSTRING: UINT = 0x0181; +pub const LB_DELETESTRING: UINT = 0x0182; +pub const LB_SELITEMRANGEEX: UINT = 0x0183; +pub const LB_RESETCONTENT: UINT = 0x0184; +pub const LB_SETSEL: UINT = 0x0185; +pub const LB_SETCURSEL: UINT = 0x0186; +pub const LB_GETSEL: UINT = 0x0187; +pub const LB_GETCURSEL: UINT = 0x0188; +pub const LB_GETTEXT: UINT = 0x0189; +pub const LB_GETTEXTLEN: UINT = 0x018A; +pub const LB_GETCOUNT: UINT = 0x018B; +pub const LB_SELECTSTRING: UINT = 0x018C; +pub const LB_DIR: UINT = 0x018D; +pub const LB_GETTOPINDEX: UINT = 0x018E; +pub const LB_FINDSTRING: UINT = 0x018F; +pub const LB_GETSELCOUNT: UINT = 0x0190; +pub const LB_GETSELITEMS: UINT = 0x0191; +pub const LB_SETTABSTOPS: UINT = 0x0192; +pub const LB_GETHORIZONTALEXTENT: UINT = 0x0193; +pub const LB_SETHORIZONTALEXTENT: UINT = 0x0194; +pub const LB_SETCOLUMNWIDTH: UINT = 0x0195; +pub const LB_ADDFILE: UINT = 0x0196; +pub const LB_SETTOPINDEX: UINT = 0x0197; +pub const LB_GETITEMRECT: UINT = 0x0198; +pub const LB_GETITEMDATA: UINT = 0x0199; +pub const LB_SETITEMDATA: UINT = 0x019A; +pub const LB_SELITEMRANGE: UINT = 0x019B; +pub const LB_SETANCHORINDEX: UINT = 0x019C; +pub const LB_GETANCHORINDEX: UINT = 0x019D; +pub const LB_SETCARETINDEX: UINT = 0x019E; +pub const LB_GETCARETINDEX: UINT = 0x019F; +pub const LB_SETITEMHEIGHT: UINT = 0x01A0; +pub const LB_GETITEMHEIGHT: UINT = 0x01A1; +pub const LB_FINDSTRINGEXACT: UINT = 0x01A2; +pub const LB_SETLOCALE: UINT = 0x01A5; +pub const LB_GETLOCALE: UINT = 0x01A6; +pub const LB_SETCOUNT: UINT = 0x01A7; +pub const LB_INITSTORAGE: UINT = 0x01A8; +pub const LB_ITEMFROMPOINT: UINT = 0x01A9; +pub const LB_MULTIPLEADDSTRING: UINT = 0x01B1; +pub const LB_GETLISTBOXINFO: UINT = 0x01B2; +pub const LB_MSGMAX: UINT = 0x01B3; +pub const LBS_NOTIFY: DWORD = 0x0001; +pub const LBS_SORT: DWORD = 0x0002; +pub const LBS_NOREDRAW: DWORD = 0x0004; +pub const LBS_MULTIPLESEL: DWORD = 0x0008; +pub const LBS_OWNERDRAWFIXED: DWORD = 0x0010; +pub const LBS_OWNERDRAWVARIABLE: DWORD = 0x0020; +pub const LBS_HASSTRINGS: DWORD = 0x0040; +pub const LBS_USETABSTOPS: DWORD = 0x0080; +pub const LBS_NOINTEGRALHEIGHT: DWORD = 0x0100; +pub const LBS_MULTICOLUMN: DWORD = 0x0200; +pub const LBS_WANTKEYBOARDINPUT: DWORD = 0x0400; +pub const LBS_EXTENDEDSEL: DWORD = 0x0800; +pub const LBS_DISABLENOSCROLL: DWORD = 0x1000; +pub const LBS_NODATA: DWORD = 0x2000; +pub const LBS_NOSEL: DWORD = 0x4000; +pub const LBS_COMBOBOX: DWORD = 0x8000; +pub const LBS_STANDARD: DWORD = LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER; +pub const CB_OKAY: LRESULT = 0; +pub const CB_ERR: LRESULT = -1; +pub const CB_ERRSPACE: LRESULT = -2; +pub const CBN_ERRSPACE: WORD = -1i16 as u16; +pub const CBN_SELCHANGE: WORD = 1; +pub const CBN_DBLCLK: WORD = 2; +pub const CBN_SETFOCUS: WORD = 3; +pub const CBN_KILLFOCUS: WORD = 4; +pub const CBN_EDITCHANGE: WORD = 5; +pub const CBN_EDITUPDATE: WORD = 6; +pub const CBN_DROPDOWN: WORD = 7; +pub const CBN_CLOSEUP: WORD = 8; +pub const CBN_SELENDOK: WORD = 9; +pub const CBN_SELENDCANCEL: WORD = 10; +pub const CBS_SIMPLE: DWORD = 0x0001; +pub const CBS_DROPDOWN: DWORD = 0x0002; +pub const CBS_DROPDOWNLIST: DWORD = 0x0003; +pub const CBS_OWNERDRAWFIXED: DWORD = 0x0010; +pub const CBS_OWNERDRAWVARIABLE: DWORD = 0x0020; +pub const CBS_AUTOHSCROLL: DWORD = 0x0040; +pub const CBS_OEMCONVERT: DWORD = 0x0080; +pub const CBS_SORT: DWORD = 0x0100; +pub const CBS_HASSTRINGS: DWORD = 0x0200; +pub const CBS_NOINTEGRALHEIGHT: DWORD = 0x0400; +pub const CBS_DISABLENOSCROLL: DWORD = 0x0800; +pub const CBS_UPPERCASE: DWORD = 0x2000; +pub const CBS_LOWERCASE: DWORD = 0x4000; +pub const CB_MULTIPLEADDSTRING: UINT = 0x0163; +pub const CB_GETCOMBOBOXINFO: UINT = 0x0164; +pub const CB_MSGMAX: UINT = 0x0165; +pub const SBS_HORZ: DWORD = 0x0000; +pub const SBS_VERT: DWORD = 0x0001; +pub const SBS_TOPALIGN: DWORD = 0x0002; +pub const SBS_LEFTALIGN: DWORD = 0x0002; +pub const SBS_BOTTOMALIGN: DWORD = 0x0004; +pub const SBS_RIGHTALIGN: DWORD = 0x0004; +pub const SBS_SIZEBOXTOPLEFTALIGN: DWORD = 0x0002; +pub const SBS_SIZEBOXBOTTOMRIGHTALIGN: DWORD = 0x0004; +pub const SBS_SIZEBOX: DWORD = 0x0008; +pub const SBS_SIZEGRIP: DWORD = 0x0010; +pub const SBM_SETPOS: UINT = 0x00E0; +pub const SBM_GETPOS: UINT = 0x00E1; +pub const SBM_SETRANGE: UINT = 0x00E2; +pub const SBM_SETRANGEREDRAW: UINT = 0x00E6; +pub const SBM_GETRANGE: UINT = 0x00E3; +pub const SBM_ENABLE_ARROWS: UINT = 0x00E4; +pub const SBM_SETSCROLLINFO: UINT = 0x00E9; +pub const SBM_GETSCROLLINFO: UINT = 0x00EA; +pub const SBM_GETSCROLLBARINFO: UINT = 0x00EB; +pub const SIF_RANGE: UINT = 0x0001; +pub const SIF_PAGE: UINT = 0x0002; +pub const SIF_POS: UINT = 0x0004; +pub const SIF_DISABLENOSCROLL: UINT = 0x0008; +pub const SIF_TRACKPOS: UINT = 0x0010; +pub const SIF_ALL: UINT = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS; +STRUCT!{struct SCROLLINFO { + cbSize: UINT, + fMask: UINT, + nMin: c_int, + nMax: c_int, + nPage: UINT, + nPos: c_int, + nTrackPos: c_int, +}} +pub type LPSCROLLINFO = *mut SCROLLINFO; +pub type LPCSCROLLINFO = *const SCROLLINFO; +extern "system" { + pub fn SetScrollInfo( + hwnd: HWND, + nBar: c_int, + lpsi: *const SCROLLINFO, + redraw: BOOL, + ) -> c_int; + pub fn GetScrollInfo( + hwnd: HWND, + nBar: c_int, + lpsi: *mut SCROLLINFO, + ) -> BOOL; +} +pub const CCHILDREN_SCROLLBAR: usize = 5; +pub const CDS_UPDATEREGISTRY: DWORD = 0x00000001; +pub const CDS_TEST: DWORD = 0x00000002; +pub const CDS_FULLSCREEN: DWORD = 0x00000004; +pub const CDS_GLOBAL: DWORD = 0x00000008; +pub const CDS_SET_PRIMARY: DWORD = 0x00000010; +pub const CDS_VIDEOPARAMETERS: DWORD = 0x00000020; +pub const CDS_ENABLE_UNSAFE_MODES: DWORD = 0x00000100; +pub const CDS_DISABLE_UNSAFE_MODES: DWORD = 0x00000200; +pub const CDS_RESET: DWORD = 0x40000000; +pub const CDS_RESET_EX: DWORD = 0x20000000; +pub const CDS_NORESET: DWORD = 0x10000000; +pub const DISP_CHANGE_SUCCESSFUL: LONG = 0; +pub const DISP_CHANGE_RESTART: LONG = 1; +pub const DISP_CHANGE_FAILED: LONG = -1; +pub const DISP_CHANGE_BADMODE: LONG = -2; +pub const DISP_CHANGE_NOTUPDATED: LONG = -3; +pub const DISP_CHANGE_BADFLAGS: LONG = -4; +pub const DISP_CHANGE_BADPARAM: LONG = -5; +pub const DISP_CHANGE_BADDUALVIEW: LONG = -6; +extern "system" { + pub fn ChangeDisplaySettingsA( + lpDevMode: *mut DEVMODEA, + dwFlags: DWORD, + ) -> LONG; + pub fn ChangeDisplaySettingsW( + lpDevMode: *mut DEVMODEW, + dwFlags: DWORD, + ) -> LONG; + pub fn ChangeDisplaySettingsExA( + lpszDeviceName: LPCSTR, + lpDevMode: *mut DEVMODEA, + hwnd: HWND, + dwFlags: DWORD, + lParam: LPVOID, + ) -> LONG; + pub fn ChangeDisplaySettingsExW( + lpszDeviceName: LPCWSTR, + lpDevMode: *mut DEVMODEW, + hwnd: HWND, + dwFlags: DWORD, + lParam: LPVOID, + ) -> LONG; + pub fn EnumDisplaySettingsA( + lpszDeviceName: LPCSTR, + iModeNum: DWORD, + lpDevMode: *mut DEVMODEA, + ) -> BOOL; + pub fn EnumDisplaySettingsW( + lpszDeviceName: LPCWSTR, + iModeNum: DWORD, + lpDevMode: *mut DEVMODEW, + ) -> BOOL; + pub fn EnumDisplaySettingsExA( + lpszDeviceName: LPCSTR, + iModeNum: DWORD, + lpDevMode: *mut DEVMODEA, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDisplaySettingsExW( + lpszDeviceName: LPCWSTR, + iModeNum: DWORD, + lpDevMode: *mut DEVMODEW, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDisplayDevicesA( + lpDevice: LPCSTR, + iDevNum: DWORD, + lpDisplayDevice: PDISPLAY_DEVICEA, + dwFlags: DWORD, + ) -> BOOL; + pub fn EnumDisplayDevicesW( + lpDevice: LPCWSTR, + iDevNum: DWORD, + lpDisplayDevice: PDISPLAY_DEVICEW, + dwFlags: DWORD, + ) -> BOOL; +} +pub const EDD_GET_DEVICE_INTERFACE_NAME: DWORD = 0x00000001; +extern "system" { + pub fn SystemParametersInfoA( + uiAction: UINT, + uiParam: UINT, + pvParam: PVOID, + fWinIni: UINT, + ) -> BOOL; + pub fn SystemParametersInfoW( + uiAction: UINT, + uiParam: UINT, + pvParam: PVOID, + fWinIni: UINT, + ) -> BOOL; + pub fn SystemParametersInfoForDpi( + uiAction: UINT, + uiParam: UINT, + pvParam: PVOID, + fWinIni: UINT, + dpi: UINT, + ) -> BOOL; +} +pub const ENUM_CURRENT_SETTINGS: DWORD = 0xFFFFFFFF; +pub const ENUM_REGISTRY_SETTINGS: DWORD = 0xFFFFFFFE; +pub const MDITILE_VERTICAL: UINT = 0x0000; +pub const MDITILE_HORIZONTAL: UINT = 0x0001; +pub const MDITILE_SKIPDISABLED: UINT = 0x0002; +pub const MDITILE_ZORDER: UINT = 0x0004; +extern "system" { + pub fn DefFrameProcA( + hwnd: HWND, + hwndMDIClient: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn DefFrameProcW( + hwnd: HWND, + hwndMDIClient: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn DefMDIChildProcA( + hwnd: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn DefMDIChildProcW( + hwnd: HWND, + uMsg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> LRESULT; + pub fn ArrangeIconicWindows( + hWnd: HWND, + ) -> UINT; + pub fn CreateMDIWindowA( + lpClassName: LPCSTR, + lpWindowName: LPCSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hInstance: HINSTANCE, + lParam: LPARAM, + ) -> HWND; + pub fn CreateMDIWindowW( + lpClassName: LPCWSTR, + lpWindowName: LPCWSTR, + dwStyle: DWORD, + X: c_int, + Y: c_int, + nWidth: c_int, + nHeight: c_int, + hWndParent: HWND, + hInstance: HINSTANCE, + lParam: LPARAM, + ) -> HWND; + pub fn CascadeWindows( + hwndParent: HWND, + wHow: UINT, + lpRect: *const RECT, + cKids: UINT, + lpKids: *const HWND, + ) -> WORD; +} +FN!{stdcall MSGBOXCALLBACK( + LPHELPINFO, +) -> ()} +FN!{stdcall WINEVENTPROC( + HWINEVENTHOOK, + DWORD, + HWND, + LONG, + LONG, + DWORD, + DWORD, +) -> ()} +STRUCT!{struct SCROLLBARINFO { + cbSize: DWORD, + rcScrollBar: RECT, + dxyLineButton: c_int, + xyThumbTop: c_int, + xyThumbBottom: c_int, + reserved: c_int, + rgstate: [DWORD; CCHILDREN_SCROLLBAR + 1], +}} +pub type PSCROLLBARINFO = *mut SCROLLBARINFO; +pub type LPSCROLLBARINFO = *mut SCROLLBARINFO; +STRUCT!{struct SIZE { + cx: LONG, + cy: LONG, +}} +pub type PSIZE = *mut SIZE; +pub type LPSIZE = *mut SIZE; +pub type SIZEL = SIZE; +pub type PSIZEL = *mut SIZEL; +pub type LPSIZEL = *mut SIZEL; +//8855 (Win 7 SDK) +STRUCT!{struct ICONINFO { + fIcon: BOOL, + xHotspot: DWORD, + yHotspot: DWORD, + hbmMask: HBITMAP, + hbmColor: HBITMAP, +}} +pub type PICONINFO = *mut ICONINFO; +//9066 +//10069 +pub const SC_SIZE: WPARAM = 0xF000; +pub const SC_MOVE: WPARAM = 0xF010; +pub const SC_MINIMIZE: WPARAM = 0xF020; +pub const SC_MAXIMIZE: WPARAM = 0xF030; +pub const SC_NEXTWINDOW: WPARAM = 0xF040; +pub const SC_PREVWINDOW: WPARAM = 0xF050; +pub const SC_CLOSE: WPARAM = 0xF060; +pub const SC_VSCROLL: WPARAM = 0xF070; +pub const SC_HSCROLL: WPARAM = 0xF080; +pub const SC_MOUSEMENU: WPARAM = 0xF090; +pub const SC_KEYMENU: WPARAM = 0xF100; +pub const SC_ARRANGE: WPARAM = 0xF110; +pub const SC_RESTORE: WPARAM = 0xF120; +pub const SC_TASKLIST: WPARAM = 0xF130; +pub const SC_SCREENSAVE: WPARAM = 0xF140; +pub const SC_HOTKEY: WPARAM = 0xF150; +pub const SC_DEFAULT: WPARAM = 0xF160; +pub const SC_MONITORPOWER: WPARAM = 0xF170; +pub const SC_CONTEXTHELP: WPARAM = 0xF180; +pub const SC_SEPARATOR: WPARAM = 0xF00F; +extern "system" { + pub fn LoadBitmapA( + hInstance: HINSTANCE, + lpBitmapName: LPCSTR, + ) -> HBITMAP; + pub fn LoadBitmapW( + hInstance: HINSTANCE, + lpBitmapName: LPCWSTR, + ) -> HBITMAP; + pub fn LoadCursorA( + hInstance: HINSTANCE, + lpCursorName: LPCSTR, + ) -> HCURSOR; + pub fn LoadCursorW( + hInstance: HINSTANCE, + lpCursorName: LPCWSTR, + ) -> HCURSOR; + pub fn LoadCursorFromFileA( + lpFileName: LPCSTR, + ) -> HCURSOR; + pub fn LoadCursorFromFileW( + lpFileName: LPCWSTR, + ) -> HCURSOR; + pub fn CreateCursor( + hInst: HINSTANCE, + xHotSpot: c_int, + yHotSpot: c_int, + nWidth: c_int, + nHeight: c_int, + pvAndPlane: *const VOID, + pvXORPlane: *const VOID, + ) -> HCURSOR; + pub fn DestroyCursor( + hCursor: HCURSOR, + ) -> BOOL; +} +pub const IDC_ARROW: LPCWSTR = 32512 as LPCWSTR; +pub const IDC_IBEAM: LPCWSTR = 32513 as LPCWSTR; +pub const IDC_WAIT: LPCWSTR = 32514 as LPCWSTR; +pub const IDC_CROSS: LPCWSTR = 32515 as LPCWSTR; +pub const IDC_UPARROW: LPCWSTR = 32516 as LPCWSTR; +pub const IDC_SIZE: LPCWSTR = 32640 as LPCWSTR; +pub const IDC_ICON: LPCWSTR = 32641 as LPCWSTR; +pub const IDC_SIZENWSE: LPCWSTR = 32642 as LPCWSTR; +pub const IDC_SIZENESW: LPCWSTR = 32643 as LPCWSTR; +pub const IDC_SIZEWE: LPCWSTR = 32644 as LPCWSTR; +pub const IDC_SIZENS: LPCWSTR = 32645 as LPCWSTR; +pub const IDC_SIZEALL: LPCWSTR = 32646 as LPCWSTR; +pub const IDC_NO: LPCWSTR = 32648 as LPCWSTR; +pub const IDC_HAND: LPCWSTR = 32649 as LPCWSTR; +pub const IDC_APPSTARTING: LPCWSTR = 32650 as LPCWSTR; +pub const IDC_HELP: LPCWSTR = 32651 as LPCWSTR; +extern "system" { + pub fn SetSystemCursor( + hcur: HCURSOR, + id: DWORD, + ) -> BOOL; + pub fn CreateIcon( + hInstance: HINSTANCE, + nWidth: c_int, + nHeight: c_int, + cPlanes: BYTE, + cBitsPixel: BYTE, + lpbANDbits: *const BYTE, + lpbXORbits: *const BYTE, + ) -> HICON; + pub fn DestroyIcon( + hIcon: HICON, + ) -> BOOL; + pub fn LookupIconIdFromDirectory( + presbits: PBYTE, + fIcon: BOOL, + ) -> c_int; + pub fn LookupIconIdFromDirectoryEx( + presbits: PBYTE, + fIcon: BOOL, + cxDesired: c_int, + cyDesired: c_int, + Flags: UINT, + ) -> c_int; + pub fn CreateIconFromResource( + presbits: PBYTE, + dwResSize: DWORD, + fIcon: BOOL, + dwVer: DWORD, + ) -> HICON; + pub fn CreateIconFromResourceEx( + presbits: PBYTE, + dwResSize: DWORD, + fIcon: BOOL, + dwVer: DWORD, + cxDesired: c_int, + cyDesired: c_int, + Flags: UINT, + ) -> HICON; +} +pub const IMAGE_BITMAP: UINT = 0; +pub const IMAGE_ICON: UINT = 1; +pub const IMAGE_CURSOR: UINT = 2; +pub const IMAGE_ENHMETAFILE: UINT = 3; +pub const LR_DEFAULTCOLOR: UINT = 0x00000000; +pub const LR_MONOCHROME: UINT = 0x00000001; +pub const LR_COLOR: UINT = 0x00000002; +pub const LR_COPYRETURNORG: UINT = 0x00000004; +pub const LR_COPYDELETEORG: UINT = 0x00000008; +pub const LR_LOADFROMFILE: UINT = 0x00000010; +pub const LR_LOADTRANSPARENT: UINT = 0x00000020; +pub const LR_DEFAULTSIZE: UINT = 0x00000040; +pub const LR_VGACOLOR: UINT = 0x00000080; +pub const LR_LOADMAP3DCOLORS: UINT = 0x00001000; +pub const LR_CREATEDIBSECTION: UINT = 0x00002000; +pub const LR_COPYFROMRESOURCE: UINT = 0x00004000; +pub const LR_SHARED: UINT = 0x00008000; +extern "system" { + pub fn LoadImageA( + hInst: HINSTANCE, + name: LPCSTR, + type_: UINT, + cx: c_int, + cy: c_int, + fuLoad: UINT, + ) -> HANDLE; + pub fn LoadImageW( + hInst: HINSTANCE, + name: LPCWSTR, + type_: UINT, + cx: c_int, + cy: c_int, + fuLoad: UINT, + ) -> HANDLE; + pub fn CopyImage( + h: HANDLE, + type_: UINT, + cx: c_int, + cy: c_int, + flags: UINT, + ) -> HANDLE; + pub fn DrawIconEx( + hdc: HDC, + xLeft: c_int, + yTop: c_int, + hIcon: HICON, + cxWidth: c_int, + cyWidth: c_int, + istepIfAniCur: UINT, + hbrFlickerFreeDraw: HBRUSH, + diFlags: UINT, + ) -> BOOL; + pub fn CreateIconIndirect( + piconinfo: PICONINFO, + ) -> HICON; +} +pub const IDI_APPLICATION: LPCWSTR = 32512 as LPCWSTR; +pub const IDI_HAND: LPCWSTR = 32513 as LPCWSTR; +pub const IDI_QUESTION: LPCWSTR = 32514 as LPCWSTR; +pub const IDI_EXCLAMATION: LPCWSTR = 32515 as LPCWSTR; +pub const IDI_ASTERISK: LPCWSTR = 32516 as LPCWSTR; +pub const IDI_WINLOGO: LPCWSTR = 32517 as LPCWSTR; +pub const IDI_SHIELD: LPCWSTR = 32518 as LPCWSTR; +pub const IDI_WARNING: LPCWSTR = IDI_EXCLAMATION; +pub const IDI_ERROR: LPCWSTR = IDI_HAND; +pub const IDI_INFORMATION: LPCWSTR = IDI_ASTERISK; +extern "system" { + pub fn WinHelpA( + hWndMain: HWND, + lpszHelp: LPCSTR, + uCommand: UINT, + dwData: ULONG_PTR, + ) -> BOOL; + pub fn WinHelpW( + hWndMain: HWND, + lpszHelp: LPCWSTR, + uCommand: UINT, + dwData: ULONG_PTR, + ) -> BOOL; + pub fn CopyIcon( + hIcon: HICON, + ) -> HICON; + pub fn GetIconInfo( + hIcon: HICON, + piconinfo: PICONINFO, + ) -> BOOL; +} +pub const SPI_GETBEEP: UINT = 0x0001; +pub const SPI_SETBEEP: UINT = 0x0002; +pub const SPI_GETMOUSE: UINT = 0x0003; +pub const SPI_SETMOUSE: UINT = 0x0004; +pub const SPI_GETBORDER: UINT = 0x0005; +pub const SPI_SETBORDER: UINT = 0x0006; +pub const SPI_GETKEYBOARDSPEED: UINT = 0x000A; +pub const SPI_SETKEYBOARDSPEED: UINT = 0x000B; +pub const SPI_LANGDRIVER: UINT = 0x000C; +pub const SPI_ICONHORIZONTALSPACING: UINT = 0x000D; +pub const SPI_GETSCREENSAVETIMEOUT: UINT = 0x000E; +pub const SPI_SETSCREENSAVETIMEOUT: UINT = 0x000F; +pub const SPI_GETSCREENSAVEACTIVE: UINT = 0x0010; +pub const SPI_SETSCREENSAVEACTIVE: UINT = 0x0011; +pub const SPI_GETGRIDGRANULARITY: UINT = 0x0012; +pub const SPI_SETGRIDGRANULARITY: UINT = 0x0013; +pub const SPI_SETDESKWALLPAPER: UINT = 0x0014; +pub const SPI_SETDESKPATTERN: UINT = 0x0015; +pub const SPI_GETKEYBOARDDELAY: UINT = 0x0016; +pub const SPI_SETKEYBOARDDELAY: UINT = 0x0017; +pub const SPI_ICONVERTICALSPACING: UINT = 0x0018; +pub const SPI_GETICONTITLEWRAP: UINT = 0x0019; +pub const SPI_SETICONTITLEWRAP: UINT = 0x001A; +pub const SPI_GETMENUDROPALIGNMENT: UINT = 0x001B; +pub const SPI_SETMENUDROPALIGNMENT: UINT = 0x001C; +pub const SPI_SETDOUBLECLKWIDTH: UINT = 0x001D; +pub const SPI_SETDOUBLECLKHEIGHT: UINT = 0x001E; +pub const SPI_GETICONTITLELOGFONT: UINT = 0x001F; +pub const SPI_SETDOUBLECLICKTIME: UINT = 0x0020; +pub const SPI_SETMOUSEBUTTONSWAP: UINT = 0x0021; +pub const SPI_SETICONTITLELOGFONT: UINT = 0x0022; +pub const SPI_GETFASTTASKSWITCH: UINT = 0x0023; +pub const SPI_SETFASTTASKSWITCH: UINT = 0x0024; +pub const SPI_SETDRAGFULLWINDOWS: UINT = 0x0025; +pub const SPI_GETDRAGFULLWINDOWS: UINT = 0x0026; +pub const SPI_GETNONCLIENTMETRICS: UINT = 0x0029; +pub const SPI_SETNONCLIENTMETRICS: UINT = 0x002A; +pub const SPI_GETMINIMIZEDMETRICS: UINT = 0x002B; +pub const SPI_SETMINIMIZEDMETRICS: UINT = 0x002C; +pub const SPI_GETICONMETRICS: UINT = 0x002D; +pub const SPI_SETICONMETRICS: UINT = 0x002E; +pub const SPI_SETWORKAREA: UINT = 0x002F; +pub const SPI_GETWORKAREA: UINT = 0x0030; +pub const SPI_SETPENWINDOWS: UINT = 0x0031; +pub const SPI_GETHIGHCONTRAST: UINT = 0x0042; +pub const SPI_SETHIGHCONTRAST: UINT = 0x0043; +pub const SPI_GETKEYBOARDPREF: UINT = 0x0044; +pub const SPI_SETKEYBOARDPREF: UINT = 0x0045; +pub const SPI_GETSCREENREADER: UINT = 0x0046; +pub const SPI_SETSCREENREADER: UINT = 0x0047; +pub const SPI_GETANIMATION: UINT = 0x0048; +pub const SPI_SETANIMATION: UINT = 0x0049; +pub const SPI_GETFONTSMOOTHING: UINT = 0x004A; +pub const SPI_SETFONTSMOOTHING: UINT = 0x004B; +pub const SPI_SETDRAGWIDTH: UINT = 0x004C; +pub const SPI_SETDRAGHEIGHT: UINT = 0x004D; +pub const SPI_SETHANDHELD: UINT = 0x004E; +pub const SPI_GETLOWPOWERTIMEOUT: UINT = 0x004F; +pub const SPI_GETPOWEROFFTIMEOUT: UINT = 0x0050; +pub const SPI_SETLOWPOWERTIMEOUT: UINT = 0x0051; +pub const SPI_SETPOWEROFFTIMEOUT: UINT = 0x0052; +pub const SPI_GETLOWPOWERACTIVE: UINT = 0x0053; +pub const SPI_GETPOWEROFFACTIVE: UINT = 0x0054; +pub const SPI_SETLOWPOWERACTIVE: UINT = 0x0055; +pub const SPI_SETPOWEROFFACTIVE: UINT = 0x0056; +pub const SPI_SETCURSORS: UINT = 0x0057; +pub const SPI_SETICONS: UINT = 0x0058; +pub const SPI_GETDEFAULTINPUTLANG: UINT = 0x0059; +pub const SPI_SETDEFAULTINPUTLANG: UINT = 0x005A; +pub const SPI_SETLANGTOGGLE: UINT = 0x005B; +pub const SPI_GETWINDOWSEXTENSION: UINT = 0x005C; +pub const SPI_SETMOUSETRAILS: UINT = 0x005D; +pub const SPI_GETMOUSETRAILS: UINT = 0x005E; +pub const SPI_SETSCREENSAVERRUNNING: UINT = 0x0061; +pub const SPI_SCREENSAVERRUNNING: UINT = SPI_SETSCREENSAVERRUNNING; +pub const SPI_GETFILTERKEYS: UINT = 0x0032; +pub const SPI_SETFILTERKEYS: UINT = 0x0033; +pub const SPI_GETTOGGLEKEYS: UINT = 0x0034; +pub const SPI_SETTOGGLEKEYS: UINT = 0x0035; +pub const SPI_GETMOUSEKEYS: UINT = 0x0036; +pub const SPI_SETMOUSEKEYS: UINT = 0x0037; +pub const SPI_GETSHOWSOUNDS: UINT = 0x0038; +pub const SPI_SETSHOWSOUNDS: UINT = 0x0039; +pub const SPI_GETSTICKYKEYS: UINT = 0x003A; +pub const SPI_SETSTICKYKEYS: UINT = 0x003B; +pub const SPI_GETACCESSTIMEOUT: UINT = 0x003C; +pub const SPI_SETACCESSTIMEOUT: UINT = 0x003D; +pub const SPI_GETSERIALKEYS: UINT = 0x003E; +pub const SPI_SETSERIALKEYS: UINT = 0x003F; +pub const SPI_GETSOUNDSENTRY: UINT = 0x0040; +pub const SPI_SETSOUNDSENTRY: UINT = 0x0041; +pub const SPI_GETSNAPTODEFBUTTON: UINT = 0x005F; +pub const SPI_SETSNAPTODEFBUTTON: UINT = 0x0060; +pub const SPI_GETMOUSEHOVERWIDTH: UINT = 0x0062; +pub const SPI_SETMOUSEHOVERWIDTH: UINT = 0x0063; +pub const SPI_GETMOUSEHOVERHEIGHT: UINT = 0x0064; +pub const SPI_SETMOUSEHOVERHEIGHT: UINT = 0x0065; +pub const SPI_GETMOUSEHOVERTIME: UINT = 0x0066; +pub const SPI_SETMOUSEHOVERTIME: UINT = 0x0067; +pub const SPI_GETWHEELSCROLLLINES: UINT = 0x0068; +pub const SPI_SETWHEELSCROLLLINES: UINT = 0x0069; +pub const SPI_GETMENUSHOWDELAY: UINT = 0x006A; +pub const SPI_SETMENUSHOWDELAY: UINT = 0x006B; +pub const SPI_GETWHEELSCROLLCHARS: UINT = 0x006C; +pub const SPI_SETWHEELSCROLLCHARS: UINT = 0x006D; +pub const SPI_GETSHOWIMEUI: UINT = 0x006E; +pub const SPI_SETSHOWIMEUI: UINT = 0x006F; +pub const SPI_GETMOUSESPEED: UINT = 0x0070; +pub const SPI_SETMOUSESPEED: UINT = 0x0071; +pub const SPI_GETSCREENSAVERRUNNING: UINT = 0x0072; +pub const SPI_GETDESKWALLPAPER: UINT = 0x0073; +pub const SPI_GETAUDIODESCRIPTION: UINT = 0x0074; +pub const SPI_SETAUDIODESCRIPTION: UINT = 0x0075; +pub const SPI_GETSCREENSAVESECURE: UINT = 0x0076; +pub const SPI_SETSCREENSAVESECURE: UINT = 0x0077; +pub const SPI_GETHUNGAPPTIMEOUT: UINT = 0x0078; +pub const SPI_SETHUNGAPPTIMEOUT: UINT = 0x0079; +pub const SPI_GETWAITTOKILLTIMEOUT: UINT = 0x007A; +pub const SPI_SETWAITTOKILLTIMEOUT: UINT = 0x007B; +pub const SPI_GETWAITTOKILLSERVICETIMEOUT: UINT = 0x007C; +pub const SPI_SETWAITTOKILLSERVICETIMEOUT: UINT = 0x007D; +pub const SPI_GETMOUSEDOCKTHRESHOLD: UINT = 0x007E; +pub const SPI_SETMOUSEDOCKTHRESHOLD: UINT = 0x007F; +pub const SPI_GETPENDOCKTHRESHOLD: UINT = 0x0080; +pub const SPI_SETPENDOCKTHRESHOLD: UINT = 0x0081; +pub const SPI_GETWINARRANGING: UINT = 0x0082; +pub const SPI_SETWINARRANGING: UINT = 0x0083; +pub const SPI_GETMOUSEDRAGOUTTHRESHOLD: UINT = 0x0084; +pub const SPI_SETMOUSEDRAGOUTTHRESHOLD: UINT = 0x0085; +pub const SPI_GETPENDRAGOUTTHRESHOLD: UINT = 0x0086; +pub const SPI_SETPENDRAGOUTTHRESHOLD: UINT = 0x0087; +pub const SPI_GETMOUSESIDEMOVETHRESHOLD: UINT = 0x0088; +pub const SPI_SETMOUSESIDEMOVETHRESHOLD: UINT = 0x0089; +pub const SPI_GETPENSIDEMOVETHRESHOLD: UINT = 0x008A; +pub const SPI_SETPENSIDEMOVETHRESHOLD: UINT = 0x008B; +pub const SPI_GETDRAGFROMMAXIMIZE: UINT = 0x008C; +pub const SPI_SETDRAGFROMMAXIMIZE: UINT = 0x008D; +pub const SPI_GETSNAPSIZING: UINT = 0x008E; +pub const SPI_SETSNAPSIZING: UINT = 0x008F; +pub const SPI_GETDOCKMOVING: UINT = 0x0090; +pub const SPI_SETDOCKMOVING: UINT = 0x0091; +pub const SPI_GETACTIVEWINDOWTRACKING: UINT = 0x1000; +pub const SPI_SETACTIVEWINDOWTRACKING: UINT = 0x1001; +pub const SPI_GETMENUANIMATION: UINT = 0x1002; +pub const SPI_SETMENUANIMATION: UINT = 0x1003; +pub const SPI_GETCOMBOBOXANIMATION: UINT = 0x1004; +pub const SPI_SETCOMBOBOXANIMATION: UINT = 0x1005; +pub const SPI_GETLISTBOXSMOOTHSCROLLING: UINT = 0x1006; +pub const SPI_SETLISTBOXSMOOTHSCROLLING: UINT = 0x1007; +pub const SPI_GETGRADIENTCAPTIONS: UINT = 0x1008; +pub const SPI_SETGRADIENTCAPTIONS: UINT = 0x1009; +pub const SPI_GETKEYBOARDCUES: UINT = 0x100A; +pub const SPI_SETKEYBOARDCUES: UINT = 0x100B; +pub const SPI_GETMENUUNDERLINES: UINT = SPI_GETKEYBOARDCUES; +pub const SPI_SETMENUUNDERLINES: UINT = SPI_SETKEYBOARDCUES; +pub const SPI_GETACTIVEWNDTRKZORDER: UINT = 0x100C; +pub const SPI_SETACTIVEWNDTRKZORDER: UINT = 0x100D; +pub const SPI_GETHOTTRACKING: UINT = 0x100E; +pub const SPI_SETHOTTRACKING: UINT = 0x100F; +pub const SPI_GETMENUFADE: UINT = 0x1012; +pub const SPI_SETMENUFADE: UINT = 0x1013; +pub const SPI_GETSELECTIONFADE: UINT = 0x1014; +pub const SPI_SETSELECTIONFADE: UINT = 0x1015; +pub const SPI_GETTOOLTIPANIMATION: UINT = 0x1016; +pub const SPI_SETTOOLTIPANIMATION: UINT = 0x1017; +pub const SPI_GETTOOLTIPFADE: UINT = 0x1018; +pub const SPI_SETTOOLTIPFADE: UINT = 0x1019; +pub const SPI_GETCURSORSHADOW: UINT = 0x101A; +pub const SPI_SETCURSORSHADOW: UINT = 0x101B; +pub const SPI_GETMOUSESONAR: UINT = 0x101C; +pub const SPI_SETMOUSESONAR: UINT = 0x101D; +pub const SPI_GETMOUSECLICKLOCK: UINT = 0x101E; +pub const SPI_SETMOUSECLICKLOCK: UINT = 0x101F; +pub const SPI_GETMOUSEVANISH: UINT = 0x1020; +pub const SPI_SETMOUSEVANISH: UINT = 0x1021; +pub const SPI_GETFLATMENU: UINT = 0x1022; +pub const SPI_SETFLATMENU: UINT = 0x1023; +pub const SPI_GETDROPSHADOW: UINT = 0x1024; +pub const SPI_SETDROPSHADOW: UINT = 0x1025; +pub const SPI_GETBLOCKSENDINPUTRESETS: UINT = 0x1026; +pub const SPI_SETBLOCKSENDINPUTRESETS: UINT = 0x1027; +pub const SPI_GETUIEFFECTS: UINT = 0x103E; +pub const SPI_SETUIEFFECTS: UINT = 0x103F; +pub const SPI_GETDISABLEOVERLAPPEDCONTENT: UINT = 0x1040; +pub const SPI_SETDISABLEOVERLAPPEDCONTENT: UINT = 0x1041; +pub const SPI_GETCLIENTAREAANIMATION: UINT = 0x1042; +pub const SPI_SETCLIENTAREAANIMATION: UINT = 0x1043; +pub const SPI_GETCLEARTYPE: UINT = 0x1048; +pub const SPI_SETCLEARTYPE: UINT = 0x1049; +pub const SPI_GETSPEECHRECOGNITION: UINT = 0x104A; +pub const SPI_SETSPEECHRECOGNITION: UINT = 0x104B; +pub const SPI_GETFOREGROUNDLOCKTIMEOUT: UINT = 0x2000; +pub const SPI_SETFOREGROUNDLOCKTIMEOUT: UINT = 0x2001; +pub const SPI_GETACTIVEWNDTRKTIMEOUT: UINT = 0x2002; +pub const SPI_SETACTIVEWNDTRKTIMEOUT: UINT = 0x2003; +pub const SPI_GETFOREGROUNDFLASHCOUNT: UINT = 0x2004; +pub const SPI_SETFOREGROUNDFLASHCOUNT: UINT = 0x2005; +pub const SPI_GETCARETWIDTH: UINT = 0x2006; +pub const SPI_SETCARETWIDTH: UINT = 0x2007; +pub const SPI_GETMOUSECLICKLOCKTIME: UINT = 0x2008; +pub const SPI_SETMOUSECLICKLOCKTIME: UINT = 0x2009; +pub const SPI_GETFONTSMOOTHINGTYPE: UINT = 0x200A; +pub const SPI_SETFONTSMOOTHINGTYPE: UINT = 0x200B; +pub const FE_FONTSMOOTHINGSTANDARD: UINT = 0x0001; +pub const FE_FONTSMOOTHINGCLEARTYPE: UINT = 0x0002; +pub const SPI_GETFONTSMOOTHINGCONTRAST: UINT = 0x200C; +pub const SPI_SETFONTSMOOTHINGCONTRAST: UINT = 0x200D; +pub const SPI_GETFOCUSBORDERWIDTH: UINT = 0x200E; +pub const SPI_SETFOCUSBORDERWIDTH: UINT = 0x200F; +pub const SPI_GETFOCUSBORDERHEIGHT: UINT = 0x2010; +pub const SPI_SETFOCUSBORDERHEIGHT: UINT = 0x2011; +pub const SPI_GETFONTSMOOTHINGORIENTATION: UINT = 0x2012; +pub const SPI_SETFONTSMOOTHINGORIENTATION: UINT = 0x2013; +pub const FE_FONTSMOOTHINGORIENTATIONBGR: UINT = 0x0000; +pub const FE_FONTSMOOTHINGORIENTATIONRGB: UINT = 0x0001; +pub const SPI_GETMINIMUMHITRADIUS: UINT = 0x2014; +pub const SPI_SETMINIMUMHITRADIUS: UINT = 0x2015; +pub const SPI_GETMESSAGEDURATION: UINT = 0x2016; +pub const SPI_SETMESSAGEDURATION: UINT = 0x2017; +//11264 +pub const CB_GETEDITSEL: UINT = 0x0140; +pub const CB_LIMITTEXT: UINT = 0x0141; +pub const CB_SETEDITSEL: UINT = 0x0142; +pub const CB_ADDSTRING: UINT = 0x0143; +pub const CB_DELETESTRING: UINT = 0x0144; +pub const CB_DIR: UINT = 0x0145; +pub const CB_GETCOUNT: UINT = 0x0146; +pub const CB_GETCURSEL: UINT = 0x0147; +pub const CB_GETLBTEXT: UINT = 0x0148; +pub const CB_GETLBTEXTLEN: UINT = 0x0149; +pub const CB_INSERTSTRING: UINT = 0x014A; +pub const CB_RESETCONTENT: UINT = 0x014B; +pub const CB_FINDSTRING: UINT = 0x014C; +pub const CB_SELECTSTRING: UINT = 0x014D; +pub const CB_SETCURSEL: UINT = 0x014E; +pub const CB_SHOWDROPDOWN: UINT = 0x014F; +pub const CB_GETITEMDATA: UINT = 0x0150; +pub const CB_SETITEMDATA: UINT = 0x0151; +pub const CB_GETDROPPEDCONTROLRECT: UINT = 0x0152; +pub const CB_SETITEMHEIGHT: UINT = 0x0153; +pub const CB_GETITEMHEIGHT: UINT = 0x0154; +pub const CB_SETEXTENDEDUI: UINT = 0x0155; +pub const CB_GETEXTENDEDUI: UINT = 0x0156; +pub const CB_GETDROPPEDSTATE: UINT = 0x0157; +pub const CB_FINDSTRINGEXACT: UINT = 0x0158; +pub const CB_SETLOCALE: UINT = 0x0159; +pub const CB_GETLOCALE: UINT = 0x015A; +pub const CB_GETTOPINDEX: UINT = 0x015b; +pub const CB_SETTOPINDEX: UINT = 0x015c; +pub const CB_GETHORIZONTALEXTENT: UINT = 0x015d; +pub const CB_SETHORIZONTALEXTENT: UINT = 0x015e; +pub const CB_GETDROPPEDWIDTH: UINT = 0x015f; +pub const CB_SETDROPPEDWIDTH: UINT = 0x0160; +pub const CB_INITSTORAGE: UINT = 0x0161; +//12141 +STRUCT!{struct NONCLIENTMETRICSA { + cbSize: UINT, + iBorderWidth: c_int, + iScrollWidth: c_int, + iScrollHeight: c_int, + iCaptionWidth: c_int, + iCaptionHeight: c_int, + lfCaptionFont: LOGFONTA, + iSmCaptionWidth: c_int, + iSmCaptionHeight: c_int, + lfSmCaptionFont: LOGFONTA, + iMenuWidth: c_int, + iMenuHeight: c_int, + lfMenuFont: LOGFONTA, + lfStatusFont: LOGFONTA, + lfMessageFont: LOGFONTA, + iPaddedBorderWidth: c_int, +}} +pub type LPNONCLIENTMETRICSA = *mut NONCLIENTMETRICSA; +STRUCT!{struct NONCLIENTMETRICSW { + cbSize: UINT, + iBorderWidth: c_int, + iScrollWidth: c_int, + iScrollHeight: c_int, + iCaptionWidth: c_int, + iCaptionHeight: c_int, + lfCaptionFont: LOGFONTW, + iSmCaptionWidth: c_int, + iSmCaptionHeight: c_int, + lfSmCaptionFont: LOGFONTW, + iMenuWidth: c_int, + iMenuHeight: c_int, + lfMenuFont: LOGFONTW, + lfStatusFont: LOGFONTW, + lfMessageFont: LOGFONTW, + iPaddedBorderWidth: c_int, +}} +pub type LPNONCLIENTMETRICSW = *mut NONCLIENTMETRICSW; +//12869 +extern "system" { + pub fn SetLastErrorEx( + dwErrCode: DWORD, + dwType: DWORD, + ); + pub fn InternalGetWindowText( + hWnd: HWND, + pString: LPWSTR, + cchMaxCount: c_int, + ) -> c_int; + pub fn EndTask( + hWnd: HWND, + fShutDown: BOOL, + fForce: BOOL, + ) -> BOOL; + pub fn CancelShutdown() -> BOOL; +} +pub const MONITOR_DEFAULTTONULL: DWORD = 0x00000000; +pub const MONITOR_DEFAULTTOPRIMARY: DWORD = 0x00000001; +pub const MONITOR_DEFAULTTONEAREST: DWORD = 0x00000002; +//12900 +extern "system" { + pub fn MonitorFromPoint( + pt: POINT, + dwFlags: DWORD, + ) -> HMONITOR; + pub fn MonitorFromRect( + lprc: LPCRECT, + dwFlags: DWORD, + ) -> HMONITOR; + pub fn MonitorFromWindow( + hwnd: HWND, + dwFlags: DWORD, + ) -> HMONITOR; +} +pub const MONITORINFOF_PRIMARY: DWORD = 1; +pub const CCHDEVICENAME: usize = 32; +STRUCT!{struct MONITORINFO { + cbSize: DWORD, + rcMonitor: RECT, + rcWork: RECT, + dwFlags: DWORD, +}} +pub type LPMONITORINFO = *mut MONITORINFO; +STRUCT!{struct MONITORINFOEXA { + cbSize: DWORD, + rcMonitor: RECT, + rcWork: RECT, + dwFlags: DWORD, + szDevice: [CHAR; CCHDEVICENAME], +}} +pub type LPMONITORINFOEXA = *mut MONITORINFOEXA; +STRUCT!{struct MONITORINFOEXW { + cbSize: DWORD, + rcMonitor: RECT, + rcWork: RECT, + dwFlags: DWORD, + szDevice: [WCHAR; CCHDEVICENAME], +}} +pub type LPMONITORINFOEXW = *mut MONITORINFOEXW; +//12971 +extern "system" { + pub fn GetMonitorInfoA( + hMonitor: HMONITOR, + lpmi: LPMONITORINFO, + ) -> BOOL; + pub fn GetMonitorInfoW( + hMonitor: HMONITOR, + lpmi: LPMONITORINFO, + ) -> BOOL; +} +FN!{stdcall MONITORENUMPROC( + HMONITOR, + HDC, + LPRECT, + LPARAM, +) -> BOOL} +extern "system" { + pub fn EnumDisplayMonitors( + hdc: HDC, + lprcClip: LPCRECT, + lpfnEnum: MONITORENUMPROC, + dwData: LPARAM, + ) -> BOOL; + pub fn NotifyWinEvent( + event: DWORD, + hwnd: HWND, + idObject: LONG, + idChild: LONG, + ); + pub fn SetWinEventHook( + eventMin: DWORD, + eventMax: DWORD, + hmodWinEventProc: HMODULE, + pfnWinEventProc: WINEVENTPROC, + idProcess: DWORD, + idThread: DWORD, + dwFlags: DWORD, + ) -> HWINEVENTHOOK; + pub fn IsWinEventHookInstalled( + event: DWORD, + ) -> BOOL; +} +pub const WINEVENT_OUTOFCONTEXT: UINT = 0x0000; +pub const WINEVENT_SKIPOWNTHREAD: UINT = 0x0001; +pub const WINEVENT_SKIPOWNPROCESS: UINT = 0x0002; +pub const WINEVENT_INCONTEXT: UINT = 0x0004; +extern "system" { + pub fn UnhookWinEvent( + hWinEventHook: HWINEVENTHOOK, + ) -> BOOL; +} +pub const CHILDID_SELF: LONG = 0; +pub const INDEXID_OBJECT: LONG = 0; +pub const INDEXID_CONTAINER: LONG = 0; +pub const OBJID_WINDOW: LONG = 0x0000; +pub const OBJID_SYSMENU: LONG = 0xFFFFFFFF; +pub const OBJID_TITLEBAR: LONG = 0xFFFFFFFE; +pub const OBJID_MENU: LONG = 0xFFFFFFFD; +pub const OBJID_CLIENT: LONG = 0xFFFFFFFC; +pub const OBJID_VSCROLL: LONG = 0xFFFFFFFB; +pub const OBJID_HSCROLL: LONG = 0xFFFFFFFA; +pub const OBJID_SIZEGRIP: LONG = 0xFFFFFFF9; +pub const OBJID_CARET: LONG = 0xFFFFFFF8; +pub const OBJID_CURSOR: LONG = 0xFFFFFFF7; +pub const OBJID_ALERT: LONG = 0xFFFFFFF6; +pub const OBJID_SOUND: LONG = 0xFFFFFFF5; +pub const OBJID_QUERYCLASSNAMEIDX: LONG = 0xFFFFFFF4; +pub const OBJID_NATIVEOM: LONG = 0xFFFFFFF0; +pub const EVENT_MIN: UINT = 0x0001; +pub const EVENT_MAX: UINT = 0x7FFFFFFF; +pub const EVENT_SYSTEM_SOUND: UINT = 0x0001; +pub const EVENT_SYSTEM_ALERT: UINT = 0x0002; +pub const EVENT_SYSTEM_FOREGROUND: UINT = 0x0003; +pub const EVENT_SYSTEM_MENUSTART: UINT = 0x0004; +pub const EVENT_SYSTEM_MENUEND: UINT = 0x0005; +pub const EVENT_SYSTEM_MENUPOPUPSTART: UINT = 0x0006; +pub const EVENT_SYSTEM_MENUPOPUPEND: UINT = 0x0007; +pub const EVENT_SYSTEM_CAPTURESTART: UINT = 0x0008; +pub const EVENT_SYSTEM_CAPTUREEND: UINT = 0x0009; +pub const EVENT_SYSTEM_MOVESIZESTART: UINT = 0x000A; +pub const EVENT_SYSTEM_MOVESIZEEND: UINT = 0x000B; +pub const EVENT_SYSTEM_CONTEXTHELPSTART: UINT = 0x000C; +pub const EVENT_SYSTEM_CONTEXTHELPEND: UINT = 0x000D; +pub const EVENT_SYSTEM_DRAGDROPSTART: UINT = 0x000E; +pub const EVENT_SYSTEM_DRAGDROPEND: UINT = 0x000F; +pub const EVENT_SYSTEM_DIALOGSTART: UINT = 0x0010; +pub const EVENT_SYSTEM_DIALOGEND: UINT = 0x0011; +pub const EVENT_SYSTEM_SCROLLINGSTART: UINT = 0x0012; +pub const EVENT_SYSTEM_SCROLLINGEND: UINT = 0x0013; +pub const EVENT_SYSTEM_SWITCHSTART: UINT = 0x0014; +pub const EVENT_SYSTEM_SWITCHEND: UINT = 0x0015; +pub const EVENT_SYSTEM_MINIMIZESTART: UINT = 0x0016; +pub const EVENT_SYSTEM_MINIMIZEEND: UINT = 0x0017; +pub const EVENT_SYSTEM_DESKTOPSWITCH: UINT = 0x0020; +pub const EVENT_SYSTEM_SWITCHER_APPGRABBED: UINT = 0x0024; +pub const EVENT_SYSTEM_SWITCHER_APPOVERTARGET: UINT = 0x0025; +pub const EVENT_SYSTEM_SWITCHER_APPDROPPED: UINT = 0x0026; +pub const EVENT_SYSTEM_SWITCHER_CANCELLED: UINT = 0x0027; +pub const EVENT_SYSTEM_IME_KEY_NOTIFICATION: UINT = 0x0029; +pub const EVENT_SYSTEM_END: UINT = 0x00FF; +pub const EVENT_OEM_DEFINED_START: UINT = 0x0101; +pub const EVENT_OEM_DEFINED_END: UINT = 0x01FF; +pub const EVENT_UIA_EVENTID_START: UINT = 0x4E00; +pub const EVENT_UIA_EVENTID_END: UINT = 0x4EFF; +pub const EVENT_UIA_PROPID_START: UINT = 0x7500; +pub const EVENT_UIA_PROPID_END: UINT = 0x75FF; +pub const EVENT_CONSOLE_CARET: UINT = 0x4001; +pub const EVENT_CONSOLE_UPDATE_REGION: UINT = 0x4002; +pub const EVENT_CONSOLE_UPDATE_SIMPLE: UINT = 0x4003; +pub const EVENT_CONSOLE_UPDATE_SCROLL: UINT = 0x4004; +pub const EVENT_CONSOLE_LAYOUT: UINT = 0x4005; +pub const EVENT_CONSOLE_START_APPLICATION: UINT = 0x4006; +pub const EVENT_CONSOLE_END_APPLICATION: UINT = 0x4007; +#[cfg(target_arch = "x86_64")] +pub const CONSOLE_APPLICATION_16BIT: LONG = 0x0000; +#[cfg(target_arch = "x86")] +pub const CONSOLE_APPLICATION_16BIT: LONG = 0x0001; +pub const CONSOLE_CARET_SELECTION: LONG = 0x0001; +pub const CONSOLE_CARET_VISIBLE: LONG = 0x0002; +pub const EVENT_CONSOLE_END: UINT = 0x40FF; +pub const EVENT_OBJECT_CREATE: UINT = 0x8000; +pub const EVENT_OBJECT_DESTROY: UINT = 0x8001; +pub const EVENT_OBJECT_SHOW: UINT = 0x8002; +pub const EVENT_OBJECT_HIDE: UINT = 0x8003; +pub const EVENT_OBJECT_REORDER: UINT = 0x8004; +pub const EVENT_OBJECT_FOCUS: UINT = 0x8005; +pub const EVENT_OBJECT_SELECTION: UINT = 0x8006; +pub const EVENT_OBJECT_SELECTIONADD: UINT = 0x8007; +pub const EVENT_OBJECT_SELECTIONREMOVE: UINT = 0x8008; +pub const EVENT_OBJECT_SELECTIONWITHIN: UINT = 0x8009; +pub const EVENT_OBJECT_STATECHANGE: UINT = 0x800A; +pub const EVENT_OBJECT_LOCATIONCHANGE: UINT = 0x800B; +pub const EVENT_OBJECT_NAMECHANGE: UINT = 0x800C; +pub const EVENT_OBJECT_DESCRIPTIONCHANGE: UINT = 0x800D; +pub const EVENT_OBJECT_VALUECHANGE: UINT = 0x800E; +pub const EVENT_OBJECT_PARENTCHANGE: UINT = 0x800F; +pub const EVENT_OBJECT_HELPCHANGE: UINT = 0x8010; +pub const EVENT_OBJECT_DEFACTIONCHANGE: UINT = 0x8011; +pub const EVENT_OBJECT_ACCELERATORCHANGE: UINT = 0x8012; +pub const EVENT_OBJECT_INVOKED: UINT = 0x8013; +pub const EVENT_OBJECT_TEXTSELECTIONCHANGED: UINT = 0x8014; +pub const EVENT_OBJECT_CONTENTSCROLLED: UINT = 0x8015; +pub const EVENT_SYSTEM_ARRANGMENTPREVIEW: UINT = 0x8016; +pub const EVENT_OBJECT_CLOAKED: UINT = 0x8017; +pub const EVENT_OBJECT_UNCLOAKED: UINT = 0x8018; +pub const EVENT_OBJECT_LIVEREGIONCHANGED: UINT = 0x8019; +pub const EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED: UINT = 0x8020; +pub const EVENT_OBJECT_DRAGSTART: UINT = 0x8021; +pub const EVENT_OBJECT_DRAGCANCEL: UINT = 0x8022; +pub const EVENT_OBJECT_DRAGCOMPLETE: UINT = 0x8023; +pub const EVENT_OBJECT_DRAGENTER: UINT = 0x8024; +pub const EVENT_OBJECT_DRAGLEAVE: UINT = 0x8025; +pub const EVENT_OBJECT_DRAGDROPPED: UINT = 0x8026; +pub const EVENT_OBJECT_IME_SHOW: UINT = 0x8027; +pub const EVENT_OBJECT_IME_HIDE: UINT = 0x8028; +pub const EVENT_OBJECT_IME_CHANGE: UINT = 0x8029; +pub const EVENT_OBJECT_TEXTEDIT_CONVERSIONTARGETCHANGED: UINT = 0x8030; +pub const EVENT_OBJECT_END: UINT = 0x80FF; +pub const EVENT_AIA_START: UINT = 0xA000; +pub const EVENT_AIA_END: UINT = 0xAFFF; +pub const ALERT_SYSTEM_INFORMATIONAL: LONG = 1; +pub const ALERT_SYSTEM_WARNING: LONG = 2; +pub const ALERT_SYSTEM_ERROR: LONG = 3; +pub const ALERT_SYSTEM_QUERY: LONG = 4; +pub const ALERT_SYSTEM_CRITICAL: LONG = 5; +pub const CALERT_SYSTEM: LONG = 6; +extern "system" { +//14098 + pub fn BlockInput( + fBlockIt: BOOL, + ) -> BOOL; +} +pub const USER_DEFAULT_SCREEN_DPI: LONG = 96; +extern "system" { + pub fn SetProcessDPIAware() -> BOOL; + pub fn IsProcessDPIAware() -> BOOL; + pub fn SetThreadDpiAwarenessContext( + dpiContext: DPI_AWARENESS_CONTEXT, + ) -> DPI_AWARENESS_CONTEXT; + pub fn GetThreadDpiAwarenessContext() -> DPI_AWARENESS_CONTEXT; + pub fn GetWindowDpiAwarenessContext( + hwnd: HWND, + ) -> DPI_AWARENESS_CONTEXT; + pub fn GetAwarenessFromDpiAwarenessContext( + value: DPI_AWARENESS_CONTEXT, + ) -> DPI_AWARENESS; + pub fn GetDpiFromDpiAwarenessContext( + value: DPI_AWARENESS_CONTEXT, + ) -> UINT; + pub fn AreDpiAwarenessContextsEqual( + dpiContextA: DPI_AWARENESS_CONTEXT, + dpiContextB: DPI_AWARENESS_CONTEXT, + ) -> BOOL; + pub fn IsValidDpiAwarenessContext( + value: DPI_AWARENESS_CONTEXT, + ) -> BOOL; + pub fn GetDpiForWindow( + hwnd: HWND, + ) -> UINT; + pub fn GetDpiForSystem() -> UINT; + pub fn GetSystemDpiForProcess( + hProcess: HANDLE, + ) -> UINT; + pub fn EnableNonClientDpiScaling( + hwnd: HWND, + ) -> BOOL; + pub fn SetProcessDpiAwarenessContext( + value: DPI_AWARENESS_CONTEXT, + ) -> BOOL; + pub fn SetThreadDpiHostingBehavior( + value: DPI_HOSTING_BEHAVIOR, + ) -> DPI_HOSTING_BEHAVIOR; + pub fn GetThreadDpiHostingBehavior() -> DPI_HOSTING_BEHAVIOR; + pub fn GetWindowDpiHostingBehavior( + hwnd: HWND, + ) -> DPI_HOSTING_BEHAVIOR; + pub fn GetWindowModuleFileNameA( + hWnd: HWND, + lpszFileName: LPCSTR, + cchFileNameMax: UINT, + ) -> UINT; + pub fn GetWindowModuleFileNameW( + hWnd: HWND, + lpszFileName: LPWSTR, + cchFileNameMax: UINT, + ) -> UINT; + pub fn GetAncestor( + hWnd: HWND, + gaFlags: UINT, + ) -> HWND; + pub fn RealChildWindowFromPoint( + hwndParent: HWND, + ptParentClientCoords: POINT, + ) -> HWND; + pub fn RealGetWindowClassA( + hwnd: HWND, + ptszClassName: LPSTR, + cchClassNameMax: UINT, + ) -> UINT; + pub fn RealGetWindowClassW( + hwnd: HWND, + ptszClassName: LPWSTR, + cchClassNameMax: UINT, + ) -> UINT; + pub fn LockWorkStation() -> BOOL; + pub fn UserHandleGrantAccess( + hUserHandle: HANDLE, + hJob: HANDLE, + bGrant: BOOL, + ) -> BOOL; +} +DECLARE_HANDLE!{HRAWINPUT, HRAWINPUT__} +#[inline] +pub fn GET_RAWINPUT_CODE_WPARAM(wParam: WPARAM) -> WPARAM { wParam & 0xff } +pub const RIM_INPUT: WPARAM = 0; +pub const RIM_INPUTSINK: WPARAM = 1; +STRUCT!{struct RAWINPUTHEADER { + dwType: DWORD, + dwSize: DWORD, + hDevice: HANDLE, + wParam: WPARAM, +}} +pub type PRAWINPUTHEADER = *mut RAWINPUTHEADER; +pub type LPRAWINPUTHEADER = *mut RAWINPUTHEADER; +pub const RIM_TYPEMOUSE: DWORD = 0; +pub const RIM_TYPEKEYBOARD: DWORD = 1; +pub const RIM_TYPEHID: DWORD = 2; +STRUCT!{struct RAWMOUSE { + usFlags: USHORT, + memory_padding: USHORT, // 16bit Padding for 32bit align in following union + usButtonFlags: USHORT, + usButtonData: USHORT, + ulRawButtons: ULONG, + lLastX: LONG, + lLastY: LONG, + ulExtraInformation: ULONG, +}} +pub type PRAWMOUSE = *mut RAWMOUSE; +pub type LPRAWMOUSE = *mut RAWMOUSE; +pub const RI_MOUSE_LEFT_BUTTON_DOWN: USHORT = 0x0001; +pub const RI_MOUSE_LEFT_BUTTON_UP: USHORT = 0x0002; +pub const RI_MOUSE_RIGHT_BUTTON_DOWN: USHORT = 0x0004; +pub const RI_MOUSE_RIGHT_BUTTON_UP: USHORT = 0x0008; +pub const RI_MOUSE_MIDDLE_BUTTON_DOWN: USHORT = 0x0010; +pub const RI_MOUSE_MIDDLE_BUTTON_UP: USHORT = 0x0020; +pub const RI_MOUSE_BUTTON_1_DOWN: USHORT = RI_MOUSE_LEFT_BUTTON_DOWN; +pub const RI_MOUSE_BUTTON_1_UP: USHORT = RI_MOUSE_LEFT_BUTTON_UP; +pub const RI_MOUSE_BUTTON_2_DOWN: USHORT = RI_MOUSE_RIGHT_BUTTON_DOWN; +pub const RI_MOUSE_BUTTON_2_UP: USHORT = RI_MOUSE_RIGHT_BUTTON_UP; +pub const RI_MOUSE_BUTTON_3_DOWN: USHORT = RI_MOUSE_MIDDLE_BUTTON_DOWN; +pub const RI_MOUSE_BUTTON_3_UP: USHORT = RI_MOUSE_MIDDLE_BUTTON_UP; +pub const RI_MOUSE_BUTTON_4_DOWN: USHORT = 0x0040; +pub const RI_MOUSE_BUTTON_4_UP: USHORT = 0x0080; +pub const RI_MOUSE_BUTTON_5_DOWN: USHORT = 0x0100; +pub const RI_MOUSE_BUTTON_5_UP: USHORT = 0x0200; +pub const RI_MOUSE_WHEEL: USHORT = 0x0400; +pub const MOUSE_MOVE_RELATIVE: USHORT = 0; +pub const MOUSE_MOVE_ABSOLUTE: USHORT = 1; +pub const MOUSE_VIRTUAL_DESKTOP: USHORT = 0x02; +pub const MOUSE_ATTRIBUTES_CHANGED: USHORT = 0x04; +pub const MOUSE_MOVE_NOCOALESCE: USHORT = 0x08; +STRUCT!{struct RAWKEYBOARD { + MakeCode: USHORT, + Flags: USHORT, + Reserved: USHORT, + VKey: USHORT, + Message: UINT, + ExtraInformation: ULONG, +}} +pub type PRAWKEYBOARD = *mut RAWKEYBOARD; +pub type LPRAWKEYBOARD = *mut RAWKEYBOARD; +pub const KEYBOARD_OVERRUN_MAKE_CODE: DWORD = 0xFF; +pub const RI_KEY_MAKE: DWORD = 0; +pub const RI_KEY_BREAK: DWORD = 1; +pub const RI_KEY_E0: DWORD = 2; +pub const RI_KEY_E1: DWORD = 4; +pub const RI_KEY_TERMSRV_SET_LED: DWORD = 8; +pub const RI_KEY_TERMSRV_SHADOW: DWORD = 0x10; +STRUCT!{struct RAWHID { + dwSizeHid: DWORD, + dwCount: DWORD, + bRawData: [BYTE; 1], +}} +pub type PRAWHID = *mut RAWHID; +pub type LPRAWHID = *mut RAWHID; +UNION!{union RAWINPUT_data { + [u32; 6], + mouse mouse_mut: RAWMOUSE, + keyboard keyboard_mut: RAWKEYBOARD, + hid hid_mut: RAWHID, +}} +STRUCT!{struct RAWINPUT { + header: RAWINPUTHEADER, + data: RAWINPUT_data, +}} +pub type PRAWINPUT = *mut RAWINPUT; +pub type LPRAWINPUT = *mut RAWINPUT; +pub const RID_INPUT: DWORD = 0x10000003; +pub const RID_HEADER: DWORD = 0x10000005; +extern "system" { + pub fn GetRawInputData( + hRawInput: HRAWINPUT, + uiCommand: UINT, + pData: LPVOID, + pcbSize: PUINT, + cbSizeHeader: UINT, + ) -> UINT; +} +pub const RIDI_PREPARSEDDATA: DWORD = 0x20000005; +pub const RIDI_DEVICENAME: DWORD = 0x20000007; +pub const RIDI_DEVICEINFO: DWORD = 0x2000000b; +STRUCT!{struct RID_DEVICE_INFO_MOUSE { + dwId: DWORD, + dwNumberOfButtons: DWORD, + dwSampleRate: DWORD, + fHasHorizontalWheel: BOOL, +}} +pub type PRID_DEVICE_INFO_MOUSE = *mut RID_DEVICE_INFO_MOUSE; +STRUCT!{struct RID_DEVICE_INFO_KEYBOARD { + dwType: DWORD, + dwSubType: DWORD, + dwKeyboardMode: DWORD, + dwNumberOfFunctionKeys: DWORD, + dwNumberOfIndicators: DWORD, + dwNumberOfKeysTotal: DWORD, +}} +pub type PRID_DEVICE_INFO_KEYBOARD = *mut RID_DEVICE_INFO_KEYBOARD; +STRUCT!{struct RID_DEVICE_INFO_HID { + dwVendorId: DWORD, + dwProductId: DWORD, + dwVersionNumber: DWORD, + usUsagePage: USHORT, + usUsage: USHORT, +}} +pub type PRID_DEVICE_INFO_HID = *mut RID_DEVICE_INFO_HID; +UNION!{union RID_DEVICE_INFO_u { + [u32; 6], + mouse mouse_mut: RID_DEVICE_INFO_MOUSE, + keyboard keyboard_mut: RID_DEVICE_INFO_KEYBOARD, + hid hid_mut: RID_DEVICE_INFO_HID, +}} +STRUCT!{struct RID_DEVICE_INFO { + cbSize: DWORD, + dwType: DWORD, + u: RID_DEVICE_INFO_u, +}} +pub type PRID_DEVICE_INFO = *mut RID_DEVICE_INFO; +pub type LPRID_DEVICE_INFO = *mut RID_DEVICE_INFO; +extern "system" { + pub fn GetRawInputDeviceInfoA( + hDevice: HANDLE, + uiCommand: UINT, + pData: LPVOID, + pcbSize: PUINT, + ) -> UINT; + pub fn GetRawInputDeviceInfoW( + hDevice: HANDLE, + uiCommand: UINT, + pData: LPVOID, + pcbSize: PUINT, + ) -> UINT; + pub fn GetRawInputBuffer( + pData: PRAWINPUT, + pcbSize: PUINT, + cbSizeHeader: UINT, + ) -> UINT; +} +STRUCT!{struct RAWINPUTDEVICE { + usUsagePage: USHORT, + usUsage: USHORT, + dwFlags: DWORD, + hwndTarget: HWND, +}} +pub type PRAWINPUTDEVICE = *mut RAWINPUTDEVICE; +pub type LPRAWINPUTDEVICE = *mut RAWINPUTDEVICE; +pub type PCRAWINPUTDEVICE = *const RAWINPUTDEVICE; +pub const RIDEV_REMOVE: DWORD = 0x00000001; +pub const RIDEV_EXCLUDE: DWORD = 0x00000010; +pub const RIDEV_PAGEONLY: DWORD = 0x00000020; +pub const RIDEV_NOLEGACY: DWORD = 0x00000030; +pub const RIDEV_INPUTSINK: DWORD = 0x00000100; +pub const RIDEV_CAPTUREMOUSE: DWORD = 0x00000200; +pub const RIDEV_NOHOTKEYS: DWORD = 0x00000200; +pub const RIDEV_APPKEYS: DWORD = 0x00000400; +pub const RIDEV_EXINPUTSINK: DWORD = 0x00001000; +pub const RIDEV_DEVNOTIFY: DWORD = 0x00002000; +pub const RIDEV_EXMODEMASK: DWORD = 0x000000F0; +pub const GIDC_ARRIVAL: DWORD = 1; +pub const GIDC_REMOVAL: DWORD = 2; +extern "system" { + pub fn RegisterRawInputDevices( + pRawInputDevices: PCRAWINPUTDEVICE, + uiNumDevices: UINT, + cbSize: UINT, + ) -> BOOL; + pub fn GetRegisteredRawInputDevices( + pRawInputDevices: PRAWINPUTDEVICE, + puiNumDevices: PUINT, + cbSize: UINT, + ) -> UINT; +} +STRUCT!{struct RAWINPUTDEVICELIST { + hDevice: HANDLE, + dwType: DWORD, +}} +pub type PRAWINPUTDEVICELIST = *mut RAWINPUTDEVICELIST; +extern "system" { + pub fn GetRawInputDeviceList( + pRawInputDeviceList: PRAWINPUTDEVICELIST, + puiNumDevices: PUINT, + cbSize: UINT, + ) -> UINT; + pub fn DefRawInputProc( + paRawInput: *mut PRAWINPUT, + nInput: INT, + cbSizeHeader: UINT, + ) -> LRESULT; + pub fn ChangeWindowMessageFilter( + message: UINT, + dwFlag: DWORD, + ) -> BOOL; +} +STRUCT!{struct CHANGEFILTERSTRUCT { + cbSize: DWORD, + ExtStatus: DWORD, +}} +extern "system" { + pub fn ChangeWindowMessageFilterEx( + hwnd: HWND, + message: UINT, + action: DWORD, + pChangeFilterStruct: PCHANGEFILTERSTRUCT, + ) -> BOOL; +} +pub type PCHANGEFILTERSTRUCT = *mut CHANGEFILTERSTRUCT; +// if WINVER >= 0x0601 +// GetSystemMetrics(SM_DIGITIZER) flag values +pub const NID_INTEGRATED_TOUCH: UINT = 0x00000001; +pub const NID_EXTERNAL_TOUCH: UINT = 0x00000002; +pub const NID_INTEGRATED_PEN: UINT = 0x00000004; +pub const NID_EXTERNAL_PEN: UINT = 0x00000008; +pub const NID_MULTI_INPUT: UINT = 0x00000040; +pub const NID_READY: UINT = 0x00000080; +// end if WINVER >= 0x0601 +// System Menu Command Values +// +STRUCT!{struct ANIMATIONINFO { + cbSize: UINT, + iMinAnimate: c_int, +}} +pub type LPANIMATIONINFO = *mut ANIMATIONINFO; +pub const SPIF_UPDATEINIFILE: UINT = 0x0001; +pub const SPIF_SENDWININICHANGE: UINT = 0x0002; +pub const SPIF_SENDCHANGE: UINT = SPIF_SENDWININICHANGE; +extern "system" { + pub fn LoadIconA( + hInstance: HINSTANCE, + lpIconName: LPCSTR, + ) -> HICON; + pub fn LoadIconW( + hInstance: HINSTANCE, + lpIconName: LPCWSTR, + ) -> HICON; + pub fn IsImmersiveProcess( + hProcess: HANDLE, + ) -> BOOL; +} +pub const MAX_STR_BLOCKREASON: usize = 256; +extern "system" { + pub fn ShutdownBlockReasonCreate( + hWnd: HWND, + pwszReason: LPCWSTR, + ) -> BOOL; + pub fn ShutdownBlockReasonQuery( + hWnd: HWND, + pwszBuff: LPWSTR, + pcchBuff: *mut DWORD, + ) -> BOOL; + pub fn ShutdownBlockReasonDestroy( + hWnd: HWND, + ) -> BOOL; +} diff --git a/winapi/src/um/winver.rs b/winapi/src/um/winver.rs new file mode 100644 index 000000000..5d25c678f --- /dev/null +++ b/winapi/src/um/winver.rs @@ -0,0 +1,53 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! Version management functions, types, and definitions +use ctypes::c_void; +use shared::minwindef::{BOOL, DWORD, LPCVOID, LPVOID, PUINT}; +use um::winnt::{LPCSTR, LPCWSTR, LPSTR, LPWSTR}; +extern "system" { + pub fn GetFileVersionInfoSizeA( + lptstrFilename: LPCSTR, + lpdwHandle: *mut DWORD, + ) -> DWORD; + pub fn GetFileVersionInfoSizeW( + lptstrFilename: LPCWSTR, + lpdwHandle: *mut DWORD, + ) -> DWORD; + pub fn GetFileVersionInfoA( + lptstrFilename: LPCSTR, + dwHandle: DWORD, + dwLen: DWORD, + lpData: *mut c_void, + ) -> BOOL; + pub fn GetFileVersionInfoW( + lptstrFilename: LPCWSTR, + dwHandle: DWORD, + dwLen: DWORD, + lpData: *mut c_void, + ) -> BOOL; + pub fn VerQueryValueA( + pBlock: LPCVOID, + lpSubBlock: LPCSTR, + lplpBuffer: &mut LPVOID, + puLen: PUINT, + ) -> BOOL; + pub fn VerQueryValueW( + pBlock: LPCVOID, + lpSubBlock: LPCWSTR, + lplpBuffer: &mut LPVOID, + puLen: PUINT, + ) -> BOOL; + pub fn VerLanguageNameA( + wLang: DWORD, + szLang: LPSTR, + cchLang: DWORD, + ) -> DWORD; + pub fn VerLanguageNameW( + wLang: DWORD, + szLang: LPWSTR, + cchLang: DWORD, + ) -> DWORD; +} diff --git a/winapi/src/um/wow64apiset.rs b/winapi/src/um/wow64apiset.rs new file mode 100644 index 000000000..b8ce4aaff --- /dev/null +++ b/winapi/src/um/wow64apiset.rs @@ -0,0 +1,27 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::minwindef::{BOOL, PBOOL, UINT}; +use um::winnt::{HANDLE, LPSTR, LPWSTR, PVOID}; +extern "system" { + pub fn Wow64DisableWow64FsRedirection( + OldValue: *mut PVOID, + ) -> BOOL; + pub fn Wow64RevertWow64FsRedirection( + OlValue: PVOID, + ) -> BOOL; + pub fn IsWow64Process( + hProcess: HANDLE, + Wow64Process: PBOOL, + ) -> BOOL; + pub fn GetSystemWow64DirectoryA( + lpBuffer: LPSTR, + uSize: UINT, + ) -> UINT; + pub fn GetSystemWow64DirectoryW( + lpBuffer: LPWSTR, + uSize: UINT, + ) -> UINT; +} diff --git a/winapi/src/um/wpdmtpextensions.rs b/winapi/src/um/wpdmtpextensions.rs new file mode 100644 index 000000000..f760e9936 --- /dev/null +++ b/winapi/src/um/wpdmtpextensions.rs @@ -0,0 +1,59 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +DEFINE_GUID!{WPD_CATEGORY_MTP_EXT_VENDOR_OPERATIONS, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_GET_SUPPORTED_VENDOR_OPCODES, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 11} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITHOUT_DATA_PHASE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 12} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITH_DATA_TO_READ, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 13} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_EXECUTE_COMMAND_WITH_DATA_TO_WRITE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 14} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_READ_DATA, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 15} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_WRITE_DATA, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 16} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_END_DATA_TRANSFER, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 17} +DEFINE_PROPERTYKEY!{WPD_COMMAND_MTP_EXT_GET_VENDOR_EXTENSION_DESCRIPTION, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 18} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_OPERATION_CODE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1001} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_OPERATION_PARAMS, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1002} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_RESPONSE_CODE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1003} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_RESPONSE_PARAMS, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1004} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_VENDOR_OPERATION_CODES, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1005} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_CONTEXT, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1006} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_TOTAL_DATA_SIZE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1007} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_TO_READ, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1008} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_READ, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1009} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_TO_WRITE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1010} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_NUM_BYTES_WRITTEN, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1011} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_TRANSFER_DATA, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1012} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_OPTIMAL_TRANSFER_BUFFER_SIZE, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1013} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_VENDOR_EXTENSION_DESCRIPTION, + 0x4d545058, 0x1a2e, 0x4106, 0xa3, 0x57, 0x77, 0x1e, 0x08, 0x19, 0xfc, 0x56, 1014} +DEFINE_GUID!{WPD_PROPERTIES_MTP_VENDOR_EXTENDED_OBJECT_PROPS, + 0x4d545058, 0x4fce, 0x4578, 0x95, 0xc8, 0x86, 0x98, 0xa9, 0xbc, 0x0f, 0x49} +DEFINE_GUID!{WPD_PROPERTIES_MTP_VENDOR_EXTENDED_DEVICE_PROPS, + 0x4d545058, 0x8900, 0x40b3, 0x8f, 0x1d, 0xdc, 0x24, 0x6e, 0x1e, 0x83, 0x70} +DEFINE_GUID!{WPD_EVENT_MTP_VENDOR_EXTENDED_EVENTS, + 0x00000000, 0x5738, 0x4ff2, 0x84, 0x45, 0xbe, 0x31, 0x26, 0x69, 0x10, 0x59} +DEFINE_PROPERTYKEY!{WPD_PROPERTY_MTP_EXT_EVENT_PARAMS, + 0x4d545058, 0xef88, 0x4e4d, 0x95, 0xc3, 0x4f, 0x32, 0x7f, 0x72, 0x8a, 0x96, 1011} diff --git a/winapi/src/um/ws2spi.rs b/winapi/src/um/ws2spi.rs new file mode 100644 index 000000000..2b9136ea3 --- /dev/null +++ b/winapi/src/um/ws2spi.rs @@ -0,0 +1,909 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Definitions to be used with the WinSock service provider. +use ctypes::{c_char, c_int, c_long, c_uint}; +use shared::basetsd::{DWORD_PTR, PDWORD_PTR, ULONG_PTR}; +use shared::guiddef::{GUID, LPGUID}; +use shared::minwindef::{ + BOOL, DWORD, INT, LPARAM, LPDWORD, LPHANDLE, LPINT, LPVOID, PBYTE, UINT, WORD, WPARAM, +}; +use shared::windef::HWND; +use shared::ws2def::{LPSOCKADDR, LPWSABUF, SOCKADDR}; +use shared::wtypesbase::LPBLOB; +use um::winnt::{HANDLE, LPCWSTR, LPWSTR, PVOID, WCHAR}; +use um::winsock2::{ + GROUP, LPCONDITIONPROC, LPQOS, LPWSACOMPLETION, LPWSANETWORKEVENTS, LPWSAOVERLAPPED, + LPWSAOVERLAPPED_COMPLETION_ROUTINE, LPWSAPROTOCOL_INFOW, LPWSAQUERYSET2W, LPWSAQUERYSETW, + LPWSASERVICECLASSINFOW, SOCKET, WSAESETSERVICEOP, WSAEVENT, fd_set, timeval, +}; +#[cfg(target_pointer_width = "64")] +use um::winsock2::{LPWSANAMESPACE_INFOEXW, LPWSANAMESPACE_INFOW}; +use vc::vcruntime::size_t; +pub const WSPDESCRIPTION_LEN: usize = 255; +pub const WSS_OPERATION_IN_PROGRESS: ULONG_PTR = 0x00000103; +STRUCT!{struct WSPDATA { + wVersion: WORD, + wHighVersion: WORD, + szDescription: [WCHAR; WSPDESCRIPTION_LEN + 1], +}} +pub type LPWSPDATA = *mut WSPDATA; +STRUCT!{struct WSATHREADID { + ThreadHandle: HANDLE, + Reserved: DWORD_PTR, +}} +pub type LPWSATHREADID = *mut WSATHREADID; +FN!{stdcall LPBLOCKINGCALLBACK( + dwContext: DWORD_PTR, +) -> BOOL} +FN!{stdcall LPWSAUSERAPC( + dwContext: DWORD_PTR, +) -> ()} +FN!{stdcall LPWSPACCEPT( + s: SOCKET, + addr: *mut SOCKADDR, + addrlen: LPINT, + lpfnCondition: LPCONDITIONPROC, + dwCallbackData: DWORD_PTR, + lpErrno: LPINT, +) -> SOCKET} +FN!{stdcall LPWSPADDRESSTOSTRING( + lpsaAddress: LPSOCKADDR, + dwAddressLength: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + lpszAddressString: LPWSTR, + lpdwAddressStringLength: LPDWORD, + lpErrno: LPINT, +) -> INT} +FN!{stdcall LPWSPASYNCSELECT( + s: SOCKET, + hWnd: HWND, + wMsg: c_uint, + lEvent: c_long, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPBIND( + s: SOCKET, + name: *mut SOCKADDR, + namelen: c_int, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPCANCELBLOCKINGCALL( + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPCLEANUP( + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPCLOSESOCKET( + s: SOCKET, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPCONNECT( + s: SOCKET, + name: *mut SOCKADDR, + namelen: c_int, + lpCallerData: LPWSABUF, + lpCalleeData: LPWSABUF, + lpSQOS: LPQOS, + lpGQOS: LPQOS, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPDUPLICATESOCKET( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPENUMNETWORKEVENTS( + s: SOCKET, + hEventObject: WSAEVENT, + lpNetworkEvents: LPWSANETWORKEVENTS, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPEVENTSELECT( + s: SOCKET, + hEventObject: WSAEVENT, + lNetworkEvents: c_long, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPGETOVERLAPPEDRESULT( + s: SOCKET, + lpOverlapped: LPWSAOVERLAPPED, + lpcbTransfer: LPDWORD, + fWait: BOOL, + lpdwFlags: LPDWORD, + lpErrno: LPINT, +) -> BOOL} +FN!{stdcall LPWSPGETPEERNAME( + s: SOCKET, + name: *mut SOCKADDR, + namelen: LPINT, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPGETSOCKNAME( + s: SOCKET, + name: *mut SOCKADDR, + namelen: LPINT, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPGETSOCKOPT( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: LPINT, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPGETQOSBYNAME( + s: SOCKET, + lpQOSName: LPWSABUF, + lpQOS: LPQOS, + lpErrno: LPINT, +) -> BOOL} +FN!{stdcall LPWSPIOCTL( + s: SOCKET, + dwIoControlCode: DWORD, + lpvInBuffer: LPVOID, + cbInBuffer: DWORD, + lpvOutBuffer: LPVOID, + cbOutBuffer: DWORD, + lpcbBytesReturned: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPJOINLEAF( + s: SOCKET, + name: *mut SOCKADDR, + namelen: c_int, + lpCallerData: LPWSABUF, + lpCalleeData: LPWSABUF, + lpSQOS: LPQOS, + lpGQOS: LPQOS, + dwFlags: DWORD, + lpErrno: LPINT, +) -> SOCKET} +FN!{stdcall LPWSPLISTEN( + s: SOCKET, + backlog: c_int, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPRECV( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPRECVDISCONNECT( + s: SOCKET, + lpInboundDisconnectData: LPWSABUF, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPRECVFROM( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpFrom: *mut SOCKADDR, + lpFromlen: LPINT, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSELECT( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *const timeval, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSEND( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSENDDISCONNECT( + s: SOCKET, + lpOutboundDisconnectData: LPWSABUF, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSENDTO( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpTo: *const SOCKADDR, + iTolen: c_int, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSETSOCKOPT( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_char, + optlen: c_int, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSHUTDOWN( + s: SOCKET, + how: c_int, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWSPSOCKET( + af: c_int, + _type: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + g: GROUP, + dwFlags: DWORD, + lpErrno: LPINT, +) -> SOCKET} +FN!{stdcall LPWSPSTRINGTOADDRESS( + AddressString: LPWSTR, + AddressFamily: INT, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + lpAddress: LPSOCKADDR, + lpAddressLength: LPINT, + lpErrno: LPINT, +) -> c_int} +STRUCT!{struct WSPPROC_TABLE { + lpWSPAccept: LPWSPACCEPT, + lpWSPAddressToString: LPWSPADDRESSTOSTRING, + lpWSPAsyncSelect: LPWSPASYNCSELECT, + lpWSPBind: LPWSPBIND, + lpWSPCancelBlockingCall: LPWSPCANCELBLOCKINGCALL, + lpWSPCleanup: LPWSPCLEANUP, + lpWSPCloseSocket: LPWSPCLOSESOCKET, + lpWSPConnect: LPWSPCONNECT, + lpWSPDuplicateSocket: LPWSPDUPLICATESOCKET, + lpWSPEnumNetworkEvents: LPWSPENUMNETWORKEVENTS, + lpWSPEventSelect: LPWSPEVENTSELECT, + lpWSPGetOverlappedResult: LPWSPGETOVERLAPPEDRESULT, + lpWSPGetPeerName: LPWSPGETPEERNAME, + lpWSPGetSockName: LPWSPGETSOCKNAME, + lpWSPGetSockOpt: LPWSPGETSOCKOPT, + lpWSPGetQOSByName: LPWSPGETQOSBYNAME, + lpWSPIoctl: LPWSPIOCTL, + lpWSPJoinLeaf: LPWSPJOINLEAF, + lpWSPListen: LPWSPLISTEN, + lpWSPRecv: LPWSPRECV, + lpWSPRecvDisconnect: LPWSPRECVDISCONNECT, + lpWSPRecvFrom: LPWSPRECVFROM, + lpWSPSelect: LPWSPSELECT, + lpWSPSend: LPWSPSEND, + lpWSPSendDisconnect: LPWSPSENDDISCONNECT, + lpWSPSendTo: LPWSPSENDTO, + lpWSPSetSockOpt: LPWSPSETSOCKOPT, + lpWSPShutdown: LPWSPSHUTDOWN, + lpWSPSocket: LPWSPSOCKET, + lpWSPStringToAddress: LPWSPSTRINGTOADDRESS, +}} +pub type LPWSPPROC_TABLE = *mut WSPPROC_TABLE; +FN!{stdcall LPWPUCLOSEEVENT( + hEvent: WSAEVENT, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUCLOSESOCKETHANDLE( + s: SOCKET, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUCREATEEVENT( + lpErrno: LPINT, +) -> WSAEVENT} +FN!{stdcall LPWPUCREATESOCKETHANDLE( + dwCatalogEntryId: DWORD, + dwContext: DWORD_PTR, + lpErrno: LPINT, +) -> SOCKET} +FN!{stdcall LPWPUFDISSET( + s: SOCKET, + fdset: *mut fd_set, +) -> c_int} +FN!{stdcall LPWPUGETPROVIDERPATH( + lpProviderId: LPGUID, + lpszProviderDllPath: *mut WCHAR, + lpProviderDllPathLen: LPINT, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUMODIFYIFSHANDLE( + dwCatalogEntryId: DWORD, + ProposedHandle: SOCKET, + lpErrno: LPINT, +) -> SOCKET} +FN!{stdcall LPWPUPOSTMESSAGE( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, +) -> BOOL} +FN!{stdcall LPWPUQUERYBLOCKINGCALLBACK( + dwCatalogEntryId: DWORD, + lplpfnCallback: *mut LPBLOCKINGCALLBACK, + lpdwContext: PDWORD_PTR, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUQUERYSOCKETHANDLECONTEXT( + s: SOCKET, + lpContext: PDWORD_PTR, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUQUEUEAPC( + lpThreadId: LPWSATHREADID, + lpfnUserApc: LPWSAUSERAPC, + dwContext: DWORD_PTR, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPURESETEVENT( + hEvent: WSAEVENT, + lpErrno: LPINT, +) -> BOOL} +FN!{stdcall LPWPUSETEVENT( + hEvent: WSAEVENT, + lpErrno: LPINT, +) -> BOOL} +FN!{stdcall LPWPUOPENCURRENTTHREAD( + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUCLOSETHREAD( + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, +) -> c_int} +FN!{stdcall LPWPUCOMPLETEOVERLAPPEDREQUEST( + s: SOCKET, + lpOverlapped: LPWSAOVERLAPPED, + dwError: DWORD, + cbTransferred: DWORD, + lpErrno: LPINT, +) -> c_int} +STRUCT!{struct WSPUPCALLTABLE { + lpWPUCloseEvent: LPWPUCLOSEEVENT, + lpWPUCloseSocketHandle: LPWPUCLOSESOCKETHANDLE, + lpWPUCreateEvent: LPWPUCREATEEVENT, + lpWPUCreateSocketHandle: LPWPUCREATESOCKETHANDLE, + lpWPUFDIsSet: LPWPUFDISSET, + lpWPUGetProviderPath: LPWPUGETPROVIDERPATH, + lpWPUModifyIFSHandle: LPWPUMODIFYIFSHANDLE, + lpWPUPostMessage: LPWPUPOSTMESSAGE, + lpWPUQueryBlockingCallback: LPWPUQUERYBLOCKINGCALLBACK, + lpWPUQuerySocketHandleContext: LPWPUQUERYSOCKETHANDLECONTEXT, + lpWPUQueueApc: LPWPUQUEUEAPC, + lpWPUResetEvent: LPWPURESETEVENT, + lpWPUSetEvent: LPWPUSETEVENT, + lpWPUOpenCurrentThread: LPWPUOPENCURRENTTHREAD, + lpWPUCloseThread: LPWPUCLOSETHREAD, +}} +pub type LPWSPUPCALLTABLE = *mut WSPUPCALLTABLE; +extern "system" { + pub fn WSPStartup( + wVersionRequested: WORD, + lpWSPData: LPWSPDATA, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + UpcallTable: WSPUPCALLTABLE, + lpProcTable: LPWSPPROC_TABLE, + ) -> c_int; +} +FN!{stdcall LPWSPSTARTUP( + wVersionRequested: WORD, + lpWSPData: LPWSPDATA, + lpProtocolInfo: LPWSAPROTOCOL_INFOW, + UpcallTable: WSPUPCALLTABLE, + lpProcTable: LPWSPPROC_TABLE, +) -> c_int} +extern "system" { + pub fn WSCEnumProtocols( + lpiProtocols: LPINT, + lpProtocolBuffer: LPWSAPROTOCOL_INFOW, + lpdwBufferLength: LPDWORD, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPWSCENUMPROTOCOLS( + lpiProtocols: LPINT, + lpProtocolBuffer: LPWSAPROTOCOL_INFOW, + lpdwBufferLength: LPDWORD, + lpErrno: LPINT, +) -> c_int} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCEnumProtocols32( + lpiProtocols: LPINT, + lpProtocolBuffer: LPWSAPROTOCOL_INFOW, + lpdwBufferLength: LPDWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCDeinstallProvider( + lpProviderId: LPGUID, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPWSCDEINSTALLPROVIDER( + lpProviderId: LPGUID, + lpErrno: LPINT, +) -> c_int} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCDeinstallProvider32( + lpProviderId: LPGUID, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCInstallProvider( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPWSCINSTALLPROVIDER( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, +) -> c_int} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCInstallProvider64_32( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCGetProviderPath( + lpProviderId: LPGUID, + lpszProviderDllPath: *mut WCHAR, + lpProviderDllPathLen: LPINT, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPWSCGETPROVIDERPATH( + lpProviderId: LPGUID, + lpszProviderDllPath: *mut WCHAR, + lpProviderDllPathLen: LPINT, + lpErrno: LPINT, +) -> c_int} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCGetProviderPath32( + lpProviderId: LPGUID, + lpszProviderDllPath: *mut WCHAR, + lpProviderDllPathLen: LPINT, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCUpdateProvider( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPWSCUPDATEPROVIDER( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, +) -> c_int} +#[cfg(target_pointer_width = "64")] +extern "system" { + pub fn WSCUpdateProvider32( + lpProviderId: LPGUID, + lpszProviderDllPath: *const WCHAR, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpErrno: LPINT, + ) -> c_int; +} +pub const LSP_SYSTEM: DWORD = 0x80000000; +pub const LSP_INSPECTOR: DWORD = 0x00000001; +pub const LSP_REDIRECTOR: DWORD = 0x00000002; +pub const LSP_PROXY: DWORD = 0x00000004; +pub const LSP_FIREWALL: DWORD = 0x00000008; +pub const LSP_INBOUND_MODIFY: DWORD = 0x00000010; +pub const LSP_OUTBOUND_MODIFY: DWORD = 0x00000020; +pub const LSP_CRYPTO_COMPRESS: DWORD = 0x00000040; +pub const LSP_LOCAL_CACHE: DWORD = 0x00000080; +ENUM!{enum WSC_PROVIDER_INFO_TYPE { + ProviderInfoLspCategories, + ProviderInfoAudit, +}} +STRUCT!{struct WSC_PROVIDER_AUDIT_INFO { + RecordSize: DWORD, + Reserved: PVOID, +}} +extern "system" { + pub fn WSCSetProviderInfo( + lpProviderId: LPGUID, + InfoType: WSC_PROVIDER_INFO_TYPE, + Info: PBYTE, + InfoSize: size_t, + Flags: DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCGetProviderInfo( + lpProviderId: LPGUID, + InfoType: WSC_PROVIDER_INFO_TYPE, + Info: PBYTE, + InfoSize: *mut size_t, + Flags: DWORD, + lpErrno: LPINT, + ) -> c_int; + #[cfg(target_pointer_width = "64")] + pub fn WSCSetProviderInfo32( + lpProviderId: LPGUID, + InfoType: WSC_PROVIDER_INFO_TYPE, + Info: PBYTE, + InfoSize: size_t, + Flags: DWORD, + lpErrno: LPINT, + ) -> c_int; + #[cfg(target_pointer_width = "64")] + pub fn WSCGetProviderInfo32( + lpProviderId: LPGUID, + InfoType: WSC_PROVIDER_INFO_TYPE, + Info: PBYTE, + InfoSize: *mut size_t, + Flags: DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCSetApplicationCategory( + Path: LPCWSTR, + PathLength: DWORD, + Extra: LPCWSTR, + ExtraLength: DWORD, + PermittedLspCategories: DWORD, + pPrevPermLspCat: *mut DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WSCGetApplicationCategory( + Path: LPCWSTR, + PathLength: DWORD, + Extra: LPCWSTR, + ExtraLength: DWORD, + pPermittedLspCategories: *mut DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUCloseEvent( + hEvent: WSAEVENT, + lpErrno: LPINT, + ) -> BOOL; + pub fn WPUCloseSocketHandle( + s: SOCKET, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUCreateEvent( + lpErrno: LPINT, + ) -> WSAEVENT; + pub fn WPUCreateSocketHandle( + dwCatalogEntryId: DWORD, + dwContext: DWORD_PTR, + lpErrno: LPINT, + ) -> SOCKET; + pub fn WPUFDIsSet( + s: SOCKET, + fdset: *mut fd_set, + ) -> c_int; + pub fn WPUGetProviderPath( + lpProviderId: LPGUID, + lpszProviderDllPath: *mut WCHAR, + lpProviderDllPathLen: LPINT, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUModifyIFSHandle( + dwCatalogEntryId: DWORD, + ProposedHandle: SOCKET, + lpErrno: LPINT, + ) -> SOCKET; + pub fn WPUPostMessage( + hWnd: HWND, + Msg: UINT, + wParam: WPARAM, + lParam: LPARAM, + ) -> BOOL; + pub fn WPUQueryBlockingCallback( + dwCatalogEntryId: DWORD, + lplpfnCallback: *mut LPBLOCKINGCALLBACK, + lpdwContext: PDWORD_PTR, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUQuerySocketHandleContext( + s: SOCKET, + lpContext: PDWORD_PTR, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUQueueApc( + lpThreadId: LPWSATHREADID, + lpfnUserApc: LPWSAUSERAPC, + dwContext: DWORD_PTR, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUResetEvent( + hEvent: WSAEVENT, + lpErrno: LPINT, + ) -> BOOL; + pub fn WPUSetEvent( + hEvent: WSAEVENT, + lpErrno: LPINT, + ) -> BOOL; + pub fn WPUCompleteOverlappedRequest( + s: SOCKET, + lpOverlapped: LPWSAOVERLAPPED, + dwError: DWORD, + cbTransferred: DWORD, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUOpenCurrentThread( + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, + ) -> c_int; + pub fn WPUCloseThread( + lpThreadId: LPWSATHREADID, + lpErrno: LPINT, + ) -> c_int; + #[cfg(target_pointer_width = "64")] + pub fn WSCEnumNameSpaceProviders32( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOW, + ) -> INT; + #[cfg(target_pointer_width = "64")] + pub fn WSCEnumNameSpaceProvidersEx32( + lpdwBufferLength: LPDWORD, + lpnspBuffer: LPWSANAMESPACE_INFOEXW, + ) -> INT; + pub fn WSCInstallNameSpace( + lpszIdentifier: LPWSTR, + lpszPathName: LPWSTR, + dwNameSpace: DWORD, + dwVersion: DWORD, + lpProviderId: LPGUID, + ) -> INT; +} +FN!{stdcall LPWSCINSTALLNAMESPACE( + lpszIdentifier: LPWSTR, + lpszPathName: LPWSTR, + dwNameSpace: DWORD, + dwVersion: DWORD, + lpProviderId: LPGUID, +) -> INT} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCInstallNameSpace32( + lpszIdentifier: LPWSTR, + lpszPathName: LPWSTR, + dwNameSpace: DWORD, + dwVersion: DWORD, + lpProviderId: LPGUID, + ) -> INT; + pub fn WSCUnInstallNameSpace( + lpProviderId: LPGUID, + ) -> INT; +} +FN!{stdcall LPWSCUNINSTALLNAMESPACE( + lpProviderId: LPGUID, +) -> INT} +extern "system" { + pub fn WSCInstallNameSpaceEx( + lpszIdentifier: LPWSTR, + lpszPathName: LPWSTR, + dwNameSpace: DWORD, + dwVersion: DWORD, + lpProviderId: LPGUID, + lpProviderSpecific: LPBLOB, + ) -> INT; + #[cfg(target_pointer_width = "64")] + pub fn WSCInstallNameSpaceEx32( + lpszIdentifier: LPWSTR, + lpszPathName: LPWSTR, + dwNameSpace: DWORD, + dwVersion: DWORD, + lpProviderId: LPGUID, + lpProviderSpecific: LPBLOB, + ) -> INT; + #[cfg(target_pointer_width = "64")] + pub fn WSCUnInstallNameSpace32( + lpProviderId: LPGUID, + ) -> INT; + pub fn WSCEnableNSProvider( + lpProviderId: LPGUID, + fEnable: BOOL, + ) -> INT; +} +FN!{stdcall LPWSCENABLENSPROVIDER( + lpProviderId: LPGUID, + fEnable: BOOL, +) -> INT} +extern "system" { + #[cfg(target_pointer_width = "64")] + pub fn WSCEnableNSProvider32( + lpProviderId: LPGUID, + fEnable: BOOL, + ) -> INT; + #[cfg(target_pointer_width = "64")] + pub fn WSCInstallProviderAndChains64_32( + lpProviderId: LPGUID, + lpszProviderDllPath: LPWSTR, + lpszProviderDllPath32: LPWSTR, + lpszLspName: LPWSTR, + dwServiceFlags: DWORD, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpdwCatalogEntryId: LPDWORD, + lpErrno: LPINT, + ) -> c_int; + #[cfg(any(target_arch = "x86", target_arch = "arm"))] + pub fn WSCInstallProviderAndChains( + lpProviderId: LPGUID, + lpszProviderDllPath: LPWSTR, + lpszLspName: LPWSTR, + dwServiceFlags: DWORD, + lpProtocolInfoList: LPWSAPROTOCOL_INFOW, + dwNumberOfEntries: DWORD, + lpdwCatalogEntryId: LPDWORD, + lpErrno: LPINT, + ) -> c_int; +} +FN!{stdcall LPNSPCLEANUP( + lpProviderId: LPGUID, +) -> INT} +FN!{stdcall LPNSPLOOKUPSERVICEBEGIN( + lpProviderId: LPGUID, + lpqsRestrictions: LPWSAQUERYSETW, + lpServiceClassInfo: LPWSASERVICECLASSINFOW, + dwControlFlags: DWORD, + lphLookup: LPHANDLE, +) -> INT} +FN!{stdcall LPNSPLOOKUPSERVICENEXT( + hLookup: HANDLE, + dwControlFlags: DWORD, + lpdwBufferLength: LPDWORD, + lpqsResults: LPWSAQUERYSETW, +) -> INT} +FN!{stdcall LPNSPIOCTL( + hLookup: HANDLE, + dwControlCode: DWORD, + lpvInBuffer: LPVOID, + cbInBuffer: DWORD, + lpvOutBuffer: LPVOID, + cbOutBuffer: DWORD, + lpcbBytesReturned: LPDWORD, + lpCompletion: LPWSACOMPLETION, + lpThreadId: LPWSATHREADID, +) -> INT} +FN!{stdcall LPNSPLOOKUPSERVICEEND( + hLookup: HANDLE, +) -> INT} +FN!{stdcall LPNSPSETSERVICE( + lpProviderId: LPGUID, + lpServiceClassInfo: LPWSASERVICECLASSINFOW, + lpqsRegInfo: LPWSAQUERYSETW, + essOperation: WSAESETSERVICEOP, + dwControlFlags: DWORD, +) -> INT} +FN!{stdcall LPNSPINSTALLSERVICECLASS( + lpProviderId: LPGUID, + lpServiceClassInfo: LPWSASERVICECLASSINFOW, +) -> INT} +FN!{stdcall LPNSPREMOVESERVICECLASS( + lpProviderId: LPGUID, + lpServiceClassId: LPGUID, +) -> INT} +FN!{stdcall LPNSPGETSERVICECLASSINFO( + lpProviderId: LPGUID, + lpdwBufSize: LPDWORD, + lpServiceClassInfo: LPWSASERVICECLASSINFOW, +) -> INT} +STRUCT!{struct NSP_ROUTINE { + cbSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + NSPCleanup: LPNSPCLEANUP, + NSPLookupServiceBegin: LPNSPLOOKUPSERVICEBEGIN, + NSPLookupServiceNext: LPNSPLOOKUPSERVICENEXT, + NSPLookupServiceEnd: LPNSPLOOKUPSERVICEEND, + NSPSetService: LPNSPSETSERVICE, + NSPInstallServiceClass: LPNSPINSTALLSERVICECLASS, + NSPRemoveServiceClass: LPNSPREMOVESERVICECLASS, + NSPGetServiceClassInfo: LPNSPGETSERVICECLASSINFO, + NSPIoctl: LPNSPIOCTL, +}} +pub type LPNSP_ROUTINE = *mut NSP_ROUTINE; +extern "system" { + pub fn NSPStartup( + lpProviderId: LPGUID, + lpnspRoutines: LPNSP_ROUTINE, + ) -> INT; +} +FN!{stdcall LPNSPSTARTUP( + lpProviderId: LPGUID, + lpnspRoutines: LPNSP_ROUTINE, +) -> INT} +FN!{stdcall LPNSPV2STARTUP( + lpProviderId: LPGUID, + ppvClientSessionArg: *mut LPVOID, +) -> INT} +FN!{stdcall LPNSPV2CLEANUP( + lpProviderId: LPGUID, + pvClientSessionArg: LPVOID, +) -> INT} +FN!{stdcall LPNSPV2LOOKUPSERVICEBEGIN( + lpProviderId: LPGUID, + lpqsRestrictions: LPWSAQUERYSET2W, + dwControlFlags: DWORD, + lpvClientSessionArg: LPVOID, + lphLookup: LPHANDLE, +) -> INT} +FN!{stdcall LPNSPV2LOOKUPSERVICENEXTEX( + hAsyncCall: HANDLE, + hLookup: HANDLE, + dwControlFlags: DWORD, + lpdwBufferLength: LPDWORD, + lpqsResults: LPWSAQUERYSET2W, +) -> ()} +FN!{stdcall LPNSPV2LOOKUPSERVICEEND( + hLookup: HANDLE, +) -> INT} +FN!{stdcall LPNSPV2SETSERVICEEX( + hAsyncCall: HANDLE, + lpProviderId: LPGUID, + lpqsRegInfo: LPWSAQUERYSET2W, + essOperation: WSAESETSERVICEOP, + dwControlFlags: DWORD, + lpvClientSessionArg: LPVOID, +) -> ()} +FN!{stdcall LPNSPV2CLIENTSESSIONRUNDOWN( + lpProviderId: LPGUID, + pvClientSessionArg: LPVOID, +) -> ()} +STRUCT!{struct NSPV2_ROUTINE { + cbSize: DWORD, + dwMajorVersion: DWORD, + dwMinorVersion: DWORD, + NSPv2Startup: LPNSPV2STARTUP, + NSPv2Cleanup: LPNSPV2CLEANUP, + NSPv2LookupServiceBegin: LPNSPV2LOOKUPSERVICEBEGIN, + NSPv2LookupServiceNextEx: LPNSPV2LOOKUPSERVICENEXTEX, + NSPv2LookupServiceEnd: LPNSPV2LOOKUPSERVICEEND, + NSPv2SetServiceEx: LPNSPV2SETSERVICEEX, + NSPv2ClientSessionRundown: LPNSPV2CLIENTSESSIONRUNDOWN, +}} +pub type PNSPV2_ROUTINE = *mut NSPV2_ROUTINE; +pub type LPNSPV2_ROUTINE = *mut NSPV2_ROUTINE; +pub type PCNSPV2_ROUTINE = *const NSPV2_ROUTINE; +pub type LPCNSPV2_ROUTINE = *const NSPV2_ROUTINE; +extern "system" { + pub fn WSAAdvertiseProvider( + puuidProviderId: *const GUID, + pNSPv2Routine: *const LPCNSPV2_ROUTINE, + ) -> INT; + pub fn WSAUnadvertiseProvider( + puuidProviderId: *const GUID, + ) -> INT; + pub fn WSAProviderCompleteAsyncCall( + hAsyncCall: HANDLE, + iRetCode: INT, + ) -> INT; +} diff --git a/winapi/src/um/ws2tcpip.rs b/winapi/src/um/ws2tcpip.rs new file mode 100644 index 000000000..4867c74a2 --- /dev/null +++ b/winapi/src/um/ws2tcpip.rs @@ -0,0 +1,346 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms +//! WinSock2 Extension for TCP/IP protocols +use ctypes::c_int; +use shared::guiddef::LPGUID; +use shared::minwindef::{DWORD, INT, LPHANDLE, ULONG}; +use shared::mstcpip::{ + SOCKET_PEER_TARGET_NAME, SOCKET_SECURITY_QUERY_INFO, SOCKET_SECURITY_QUERY_TEMPLATE, + SOCKET_SECURITY_SETTINGS, +}; +use shared::winerror::{ + WSAEAFNOSUPPORT, WSAEINVAL, WSAESOCKTNOSUPPORT, WSAHOST_NOT_FOUND, WSANO_RECOVERY, + WSATRY_AGAIN, WSATYPE_NOT_FOUND, WSA_IPSEC_NAME_POLICY_ERROR, WSA_SECURE_HOST_NOT_FOUND, +}; +use shared::ws2def::{ + ADDRINFOA, ADDRINFOEXA, ADDRINFOEXW, ADDRINFOW, PADDRINFOA, PADDRINFOEXA, PADDRINFOEXW, + PADDRINFOW, SOCKADDR, SOCKET_ADDRESS, +}; +use shared::wtypesbase::LPBLOB; +use um::minwinbase::LPOVERLAPPED; +use um::winnt::{PCHAR, PCSTR, PCWSTR, PSTR, PVOID, PWCHAR, PWSTR, VOID}; +use um::winsock2::{ + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE, SOCKET, WSA_NOT_ENOUGH_MEMORY, timeval, +}; +use vc::vcruntime::size_t; +pub const UDP_NOCHECKSUM: c_int = 1; +pub const UDP_CHECKSUM_COVERAGE: c_int = 20; +pub const EAI_AGAIN: DWORD = WSATRY_AGAIN; +pub const EAI_BADFLAGS: DWORD = WSAEINVAL; +pub const EAI_FAIL: DWORD = WSANO_RECOVERY; +pub const EAI_FAMILY: DWORD = WSAEAFNOSUPPORT; +pub const EAI_MEMORY: DWORD = WSA_NOT_ENOUGH_MEMORY as u32; +pub const EAI_NOSECURENAME: DWORD = WSA_SECURE_HOST_NOT_FOUND; +pub const EAI_NONAME: DWORD = WSAHOST_NOT_FOUND; +pub const EAI_SERVICE: DWORD = WSATYPE_NOT_FOUND; +pub const EAI_SOCKTYPE: DWORD = WSAESOCKTNOSUPPORT; +pub const EAI_IPSECPOLICY: DWORD = WSA_IPSEC_NAME_POLICY_ERROR; +pub const EAI_NODATA: DWORD = EAI_NONAME; +pub type ADDRINFO = ADDRINFOA; +pub type LPADDRINFO = *mut ADDRINFOA; +extern "system" { + pub fn getaddrinfo( + pNodeName: PCSTR, + pServiceName: PCSTR, + pHints: *const ADDRINFOA, + ppResult: *mut PADDRINFOA, + ) -> INT; + pub fn GetAddrInfoW( + pNodeName: PCWSTR, + pServiceName: PCWSTR, + pHints: *const ADDRINFOW, + ppResult: *mut PADDRINFOW, + ) -> INT; +} +FN!{stdcall LPFN_GETADDRINFO( + pNodeName: PCSTR, + pServiceName: PCSTR, + pHints: *const ADDRINFOA, + ppResult: *mut PADDRINFOA, +) -> INT} +FN!{stdcall LPFN_GETADDRINFOW( + pNodeName: PCWSTR, + pServiceName: PCWSTR, + pHints: *const ADDRINFOW, + ppResult: *mut PADDRINFOW, +) -> INT} +FN!{stdcall LPLOOKUPSERVICE_COMPLETION_ROUTINE( + dwError: DWORD, + dwBytes: DWORD, + lpOverlapped: LPWSAOVERLAPPED, +) -> ()} +extern "system" { + pub fn GetAddrInfoExA( + pName: PCSTR, + pServiceName: PCSTR, + dwNameSpace: DWORD, + lpNspId: LPGUID, + hints: *const ADDRINFOEXA, + ppResult: *mut PADDRINFOEXA, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, + ) -> INT; + pub fn GetAddrInfoExW( + pName: PCWSTR, + pServiceName: PCWSTR, + dwNameSpace: DWORD, + lpNspId: LPGUID, + hints: *const ADDRINFOEXW, + ppResult: *mut PADDRINFOEXW, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, + ) -> INT; + pub fn GetAddrInfoExCancel( + lpHandle: LPHANDLE, + ) -> INT; + pub fn GetAddrInfoExOverlappedResult( + lpOverlapped: LPOVERLAPPED, + ) -> INT; +} +FN!{stdcall LPFN_GETADDRINFOEXA( + pName: PCSTR, + pServiceName: PCSTR, + dwNameSpace: DWORD, + lpNspId: LPGUID, + hints: *const ADDRINFOEXA, + ppResult: *mut PADDRINFOEXA, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, +) -> INT} +FN!{stdcall LPFN_GETADDRINFOEXW( + pName: PCWSTR, + pServiceName: PCWSTR, + dwNameSpace: DWORD, + lpNspId: LPGUID, + hints: *const ADDRINFOEXW, + ppResult: *mut PADDRINFOEXW, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, +) -> INT} +FN!{stdcall LPFN_GETADDRINFOEXCANCEL( + lpHandle: LPHANDLE, +) -> INT} +FN!{stdcall LPFN_GETADDRINFOEXOVERLAPPEDRESULT( + lpOverlapped: LPOVERLAPPED, +) -> INT} +extern "system" { + pub fn SetAddrInfoExA( + pName: PCSTR, + pServiceName: PCSTR, + pAddresses: *mut SOCKET_ADDRESS, + dwAddressCount: DWORD, + lpBlob: LPBLOB, + dwFlags: DWORD, + dwNameSpace: DWORD, + lpNspId: LPGUID, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, + ) -> INT; + pub fn SetAddrInfoExW( + pName: PCWSTR, + pServiceName: PCWSTR, + pAddresses: *mut SOCKET_ADDRESS, + dwAddressCount: DWORD, + lpBlob: LPBLOB, + dwFlags: DWORD, + dwNameSpace: DWORD, + lpNspId: LPGUID, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, + ) -> INT; +} +FN!{stdcall LPFN_SETADDRINFOEXA( + pName: PCSTR, + pServiceName: PCSTR, + pAddresses: *mut SOCKET_ADDRESS, + dwAddressCount: DWORD, + lpBlob: LPBLOB, + dwFlags: DWORD, + dwNameSpace: DWORD, + lpNspId: LPGUID, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, +) -> INT} +FN!{stdcall LPFN_SETADDRINFOEXW( + pName: PCWSTR, + pServiceName: PCWSTR, + pAddresses: *mut SOCKET_ADDRESS, + dwAddressCount: DWORD, + lpBlob: LPBLOB, + dwFlags: DWORD, + dwNameSpace: DWORD, + lpNspId: LPGUID, + timeout: *mut timeval, + lpOverlapped: LPOVERLAPPED, + lpCompletionRoutine: LPLOOKUPSERVICE_COMPLETION_ROUTINE, + lpNameHandle: LPHANDLE, +) -> INT} +extern "system" { + pub fn freeaddrinfo( + pAddrInfo: PADDRINFOA, + ); + pub fn FreeAddrInfoW( + pAddrInfo: PADDRINFOW, + ); +} +FN!{stdcall LPFN_FREEADDRINFO( + pAddrInfo: PADDRINFOA, +) -> ()} +FN!{stdcall LPFN_FREEADDRINFOW( + pAddrInfo: PADDRINFOW, +) -> ()} +extern "system" { + pub fn FreeAddrInfoEx( + pAddrInfoEx: PADDRINFOEXA, + ); + pub fn FreeAddrInfoExW( + pAddrInfoEx: PADDRINFOEXW, + ); +} +FN!{stdcall LPFN_FREEADDRINFOEXA( + pAddrInfoEx: PADDRINFOEXA, +) -> ()} +FN!{stdcall LPFN_FREEADDRINFOEXW( + pAddrInfoEx: PADDRINFOEXW, +) -> ()} +pub type socklen_t = c_int; +extern "system" { + pub fn getnameinfo( + pSockaddr: *const SOCKADDR, + SockaddrLength: socklen_t, + pNodeBuffer: PCHAR, + NodeBufferSize: DWORD, + pServiceBuffer: PCHAR, + ServiceBufferSize: DWORD, + Flags: INT, + ) -> INT; + pub fn GetNameInfoW( + pSockaddr: *const SOCKADDR, + SockaddrLength: socklen_t, + pNodeBuffer: PWCHAR, + NodeBufferSize: DWORD, + pServiceBuffer: PWCHAR, + ServiceBufferSize: DWORD, + Flags: INT, + ) -> INT; +} +FN!{stdcall LPFN_GETNAMEINFO( + pSockaddr: *const SOCKADDR, + SockaddrLength: socklen_t, + pNodeBuffer: PCHAR, + NodeBufferSize: DWORD, + pServiceBuffer: PCHAR, + ServiceBufferSize: DWORD, + Flags: INT, +) -> c_int} +FN!{stdcall LPFN_GETNAMEINFOW( + pSockaddr: *const SOCKADDR, + SockaddrLength: socklen_t, + pNodeBuffer: PWCHAR, + NodeBufferSize: DWORD, + pServiceBuffer: PWCHAR, + ServiceBufferSize: DWORD, + Flags: INT, +) -> INT} +extern "system" { + pub fn inet_pton( + Family: INT, + pszAddrString: PCSTR, + pAddrBuf: PVOID, + ) -> INT; + pub fn InetPtonW( + Family: INT, + pszAddrString: PCWSTR, + pAddrBuf: PVOID, + ) -> INT; + pub fn inet_ntop( + Family: INT, + pAddr: *const VOID, + pStringBuf: PSTR, + StringBufSize: size_t, + ) -> PCSTR; + pub fn InetNtopW( + Family: INT, + pAddr: *const VOID, + pStringBuf: PWSTR, + StringBufSize: size_t, + ) -> PCWSTR; +} +FN!{stdcall LPFN_INET_PTONA( + Family: INT, + pszAddrString: PCSTR, + pAddrBuf: PVOID, +) -> INT} +FN!{stdcall LPFN_INET_PTONW( + Family: INT, + pszAddrString: PCWSTR, + pAddrBuf: PVOID, +) -> INT} +FN!{stdcall LPFN_INET_NTOPA( + Family: INT, + pAddr: *const VOID, + pStringBuf: PSTR, + StringBufSize: size_t, +) -> PCSTR} +FN!{stdcall LPFN_INET_NTOPW( + Family: INT, + pAddr: *const VOID, + pStringBuf: PWSTR, + StringBufSize: size_t, +) -> PCWSTR} +pub const GAI_STRERROR_BUFFER_SIZE: usize = 1024; +extern "system" { + pub fn WSASetSocketSecurity( + Socket: SOCKET, + SecuritySettings: *const SOCKET_SECURITY_SETTINGS, + SecuritySettingsLen: ULONG, + Overlapped: LPWSAOVERLAPPED, + CompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> INT; + pub fn WSAQuerySocketSecurity( + Socket: SOCKET, + SecurityQueryTemplate: *const SOCKET_SECURITY_QUERY_TEMPLATE, + SecurityQueryTemplateLen: ULONG, + SecurityQueryInfo: *mut SOCKET_SECURITY_QUERY_INFO, + SecurityQueryInfoLen: *mut ULONG, + Overlapped: LPWSAOVERLAPPED, + CompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> INT; + pub fn WSASetSocketPeerTargetName( + Socket: SOCKET, + PeerTargetName: *const SOCKET_PEER_TARGET_NAME, + PeerTargetNameLen: ULONG, + Overlapped: LPWSAOVERLAPPED, + CompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> INT; + pub fn WSADeleteSocketPeerTargetName( + Socket: SOCKET, + PeerAddr: *const SOCKADDR, + PeerAddrLen: ULONG, + Overlapped: LPWSAOVERLAPPED, + CompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> INT; + pub fn WSAImpersonateSocketPeer( + Socket: SOCKET, + PeerAddr: *const SOCKADDR, + PeerAddrLen: ULONG, + ) -> INT; + pub fn WSARevertImpersonation(); +} diff --git a/winapi/src/um/xinput.rs b/winapi/src/um/xinput.rs new file mode 100644 index 000000000..e583c1e1f --- /dev/null +++ b/winapi/src/um/xinput.rs @@ -0,0 +1,165 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! XInput procedure declarations, constant definitions and macros +use shared::guiddef::GUID; +use shared::minwindef::{BOOL, BYTE, DWORD, UINT, WORD}; +use um::winnt::{LPWSTR, SHORT, WCHAR}; +pub const XINPUT_DEVTYPE_GAMEPAD: BYTE = 0x01; +pub const XINPUT_DEVSUBTYPE_GAMEPAD: BYTE = 0x01; +pub const XINPUT_DEVSUBTYPE_WHEEL: BYTE = 0x02; +pub const XINPUT_DEVSUBTYPE_ARCADE_STICK: BYTE = 0x03; +pub const XINPUT_DEVSUBTYPE_FLIGHT_SICK: BYTE = 0x04; +pub const XINPUT_DEVSUBTYPE_DANCE_PAD: BYTE = 0x05; +pub const XINPUT_DEVSUBTYPE_GUITAR: BYTE = 0x06; +pub const XINPUT_DEVSUBTYPE_DRUM_KIT: BYTE = 0x08; +pub const XINPUT_CAPS_VOICE_SUPPORTED: WORD = 0x0004; +pub const XINPUT_GAMEPAD_DPAD_UP: WORD = 0x0001; +pub const XINPUT_GAMEPAD_DPAD_DOWN: WORD = 0x0002; +pub const XINPUT_GAMEPAD_DPAD_LEFT: WORD = 0x0004; +pub const XINPUT_GAMEPAD_DPAD_RIGHT: WORD = 0x0008; +pub const XINPUT_GAMEPAD_START: WORD = 0x0010; +pub const XINPUT_GAMEPAD_BACK: WORD = 0x0020; +pub const XINPUT_GAMEPAD_LEFT_THUMB: WORD = 0x0040; +pub const XINPUT_GAMEPAD_RIGHT_THUMB: WORD = 0x0080; +pub const XINPUT_GAMEPAD_LEFT_SHOULDER: WORD = 0x0100; +pub const XINPUT_GAMEPAD_RIGHT_SHOULDER: WORD = 0x0200; +pub const XINPUT_GAMEPAD_A: WORD = 0x1000; +pub const XINPUT_GAMEPAD_B: WORD = 0x2000; +pub const XINPUT_GAMEPAD_X: WORD = 0x4000; +pub const XINPUT_GAMEPAD_Y: WORD = 0x8000; +pub const XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE: SHORT = 7849; +pub const XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE: SHORT = 8689; +pub const XINPUT_GAMEPAD_TRIGGER_THRESHOLD: BYTE = 30; +pub const XINPUT_FLAG_GAMEPAD: DWORD = 0x00000001; +pub const BATTERY_DEVTYPE_GAMEPAD: BYTE = 0x00; +pub const BATTERY_DEVTYPE_HEADSET: BYTE = 0x01; +pub const BATTERY_TYPE_DISCONNECTED: BYTE = 0x00; +pub const BATTERY_TYPE_WIRED: BYTE = 0x01; +pub const BATTERY_TYPE_ALKALINE: BYTE = 0x02; +pub const BATTERY_TYPE_NIMH: BYTE = 0x03; +pub const BATTERY_TYPE_UNKNOWN: BYTE = 0xFF; +pub const BATTERY_LEVEL_EMPTY: BYTE = 0x00; +pub const BATTERY_LEVEL_LOW: BYTE = 0x01; +pub const BATTERY_LEVEL_MEDIUM: BYTE = 0x02; +pub const BATTERY_LEVEL_FULL: BYTE = 0x03; +pub const XUSER_MAX_COUNT: DWORD = 4; +pub const XUSER_INDEX_ANY: DWORD = 0x000000FF; +pub const VK_PAD_A: WORD = 0x5800; +pub const VK_PAD_B: WORD = 0x5801; +pub const VK_PAD_X: WORD = 0x5802; +pub const VK_PAD_Y: WORD = 0x5803; +pub const VK_PAD_RSHOULDER: WORD = 0x5804; +pub const VK_PAD_LSHOULDER: WORD = 0x5805; +pub const VK_PAD_LTRIGGER: WORD = 0x5806; +pub const VK_PAD_RTRIGGER: WORD = 0x5807; +pub const VK_PAD_DPAD_UP: WORD = 0x5810; +pub const VK_PAD_DPAD_DOWN: WORD = 0x5811; +pub const VK_PAD_DPAD_LEFT: WORD = 0x5812; +pub const VK_PAD_DPAD_RIGHT: WORD = 0x5813; +pub const VK_PAD_START: WORD = 0x5814; +pub const VK_PAD_BACK: WORD = 0x5815; +pub const VK_PAD_LTHUMB_PRESS: WORD = 0x5816; +pub const VK_PAD_RTHUMB_PRESS: WORD = 0x5817; +pub const VK_PAD_LTHUMB_UP: WORD = 0x5820; +pub const VK_PAD_LTHUMB_DOWN: WORD = 0x5821; +pub const VK_PAD_LTHUMB_RIGHT: WORD = 0x5822; +pub const VK_PAD_LTHUMB_LEFT: WORD = 0x5823; +pub const VK_PAD_LTHUMB_UPLEFT: WORD = 0x5824; +pub const VK_PAD_LTHUMB_UPRIGHT: WORD = 0x5825; +pub const VK_PAD_LTHUMB_DOWNRIGHT: WORD = 0x5826; +pub const VK_PAD_LTHUMB_DOWNLEFT: WORD = 0x5827; +pub const VK_PAD_RTHUMB_UP: WORD = 0x5830; +pub const VK_PAD_RTHUMB_DOWN: WORD = 0x5831; +pub const VK_PAD_RTHUMB_RIGHT: WORD = 0x5832; +pub const VK_PAD_RTHUMB_LEFT: WORD = 0x5833; +pub const VK_PAD_RTHUMB_UPLEFT: WORD = 0x5834; +pub const VK_PAD_RTHUMB_UPRIGHT: WORD = 0x5835; +pub const VK_PAD_RTHUMB_DOWNRIGHT: WORD = 0x5836; +pub const VK_PAD_RTHUMB_DOWNLEFT: WORD = 0x5837; +pub const XINPUT_KEYSTROKE_KEYDOWN: WORD = 0x0001; +pub const XINPUT_KEYSTROKE_KEYUP: WORD = 0x0002; +pub const XINPUT_KEYSTROKE_REPEAT: WORD = 0x0004; +STRUCT!{struct XINPUT_GAMEPAD { + wButtons: WORD, + bLeftTrigger: BYTE, + bRightTrigger: BYTE, + sThumbLX: SHORT, + sThumbLY: SHORT, + sThumbRX: SHORT, + sThumbRY: SHORT, +}} +pub type PXINPUT_GAMEPAD = *mut XINPUT_GAMEPAD; +STRUCT!{struct XINPUT_STATE { + dwPacketNumber: DWORD, + Gamepad: XINPUT_GAMEPAD, +}} +pub type PXINPUT_STATE = *mut XINPUT_STATE; +STRUCT!{struct XINPUT_VIBRATION { + wLeftMotorSpeed: WORD, + wRightMotorSpeed: WORD, +}} +pub type PXINPUT_VIBRATION = *mut XINPUT_VIBRATION; +STRUCT!{struct XINPUT_CAPABILITIES { + Type: BYTE, + SubType: BYTE, + Flags: WORD, + Gamepad: XINPUT_GAMEPAD, + Vibration: XINPUT_VIBRATION, +}} +pub type PXINPUT_CAPABILITIES = *mut XINPUT_CAPABILITIES; +STRUCT!{struct XINPUT_BATTERY_INFORMATION { + BatteryType: BYTE, + BatteryLevel: BYTE, +}} +pub type PXINPUT_BATTERY_INFORMATION = *mut XINPUT_BATTERY_INFORMATION; +STRUCT!{struct XINPUT_KEYSTROKE { + VirtualKey: WORD, + Unicode: WCHAR, + Flags: WORD, + UserIndex: BYTE, + HidCode: BYTE, +}} +pub type PXINPUT_KEYSTROKE = *mut XINPUT_KEYSTROKE; +extern "system" { + pub fn XInputGetState( + dwUserIndex: DWORD, + pState: *mut XINPUT_STATE, + ) -> DWORD; + pub fn XInputSetState( + dwUserIndex: DWORD, + pVibration: *mut XINPUT_VIBRATION, + ) -> DWORD; + pub fn XInputGetCapabilities( + dwUserIndex: DWORD, + dwFlags: DWORD, + pCapabilities: *mut XINPUT_CAPABILITIES, + ) -> DWORD; + pub fn XInputEnable( + enable: BOOL, + ); + pub fn XInputGetAudioDeviceIds( + dwUserIndex: DWORD, + pRenderDeviceId: LPWSTR, + pRenderCount: *mut UINT, + pCaptureDeviceId: LPWSTR, + pCaptureCount: *mut UINT, + ) -> DWORD; + pub fn XInputGetBatteryInformation( + dwUserIndex: DWORD, + devType: BYTE, + pBatteryInformation: *mut XINPUT_BATTERY_INFORMATION, + ) -> DWORD; + pub fn XInputGetKeystroke( + dwUserIndex: DWORD, + dwReserved: DWORD, + pKeystroke: PXINPUT_KEYSTROKE, + ) -> DWORD; + pub fn XInputGetDSoundAudioDeviceGuids( + dwUserIndex: DWORD, + pDSoundRenderGuid: *mut GUID, + pDSoundCaptureGuid: *mut GUID, + ) -> DWORD; +} diff --git a/winapi/src/vc/excpt.rs b/winapi/src/vc/excpt.rs new file mode 100644 index 000000000..a4f4d91e4 --- /dev/null +++ b/winapi/src/vc/excpt.rs @@ -0,0 +1,18 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! The declarations of the compiler-dependent intrinsics, support functions, and keywords which +//! implement the structured exception handling extensions. +ENUM!{enum EXCEPTION_DISPOSITION { + ExceptionContinueExecution, + ExceptionContinueSearch, + ExceptionNestedException, + ExceptionCollidedUnwind, +}} +// While there are functions defined here in `excpt.h`, they are actually intrinsics which have +// special black magic in the msvc compiler. Thus bindings cannot be provided for them. +pub const EXCEPTION_EXECUTE_HANDLER: i32 = 1; +pub const EXCEPTION_CONTINUE_SEARCH: i32 = 0; +pub const EXCEPTION_CONTINUE_EXECUTION: i32 = -1; diff --git a/winapi/src/vc/limits.rs b/winapi/src/vc/limits.rs new file mode 100644 index 000000000..31509adee --- /dev/null +++ b/winapi/src/vc/limits.rs @@ -0,0 +1,7 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_uint; +pub const UINT_MAX: c_uint = 0xffffffff; diff --git a/winapi/src/vc/mod.rs b/winapi/src/vc/mod.rs new file mode 100644 index 000000000..0c0606bd9 --- /dev/null +++ b/winapi/src/vc/mod.rs @@ -0,0 +1,10 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Headers that come with VC. Notably, these are not part of the Windows SDK. +#[cfg(feature = "excpt")] pub mod excpt; +#[cfg(feature = "limits")] pub mod limits; +#[cfg(feature = "vadefs")] pub mod vadefs; +#[cfg(feature = "vcruntime")] pub mod vcruntime; diff --git a/winapi/src/vc/vadefs.rs b/winapi/src/vc/vadefs.rs new file mode 100644 index 000000000..d44cc04db --- /dev/null +++ b/winapi/src/vc/vadefs.rs @@ -0,0 +1,8 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use ctypes::c_char; +pub type uintptr_t = usize; +pub type va_list = *mut c_char; diff --git a/winapi/src/vc/vcruntime.rs b/winapi/src/vc/vcruntime.rs new file mode 100644 index 000000000..63c671b36 --- /dev/null +++ b/winapi/src/vc/vcruntime.rs @@ -0,0 +1,9 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! Declarations used throughout the VCRuntime library. +pub type size_t = usize; +pub type ptrdiff_t = isize; +pub type intptr_t = isize; diff --git a/winapi/src/winrt/activation.rs b/winapi/src/winrt/activation.rs new file mode 100644 index 000000000..dca597bd1 --- /dev/null +++ b/winapi/src/winrt/activation.rs @@ -0,0 +1,13 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use um::winnt::HRESULT; +use winrt::inspectable::{IInspectable, IInspectableVtbl}; +RIDL!{#[uuid(0x00000035, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IActivationFactory(IActivationFactoryVtbl): IInspectable(IInspectableVtbl) { + fn ActivateInstance( + instance: *mut *mut IInspectable, + ) -> HRESULT, +}} diff --git a/winapi/src/winrt/hstring.rs b/winapi/src/winrt/hstring.rs new file mode 100644 index 000000000..98314e361 --- /dev/null +++ b/winapi/src/winrt/hstring.rs @@ -0,0 +1,25 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +//! This interface definition contains typedefs for Windows Runtime data types. +use ctypes::c_char; +use um::winnt::PVOID; +DECLARE_HANDLE!{HSTRING, HSTRING__} +#[cfg(target_arch = "x86")] +UNION!{union HSTRING_HEADER_Reserved { + [u32; 5], + Reserved1 Reserved1_mut: PVOID, + Reserved2 Reserved2_mut: [c_char; 20], +}} +#[cfg(target_pointer_width = "64")] +UNION!{union HSTRING_HEADER_Reserved { + [u64; 3], + Reserved1 Reserved1_mut: PVOID, + Reserved2 Reserved2_mut: [c_char; 24], +}} +STRUCT!{struct HSTRING_HEADER { + Reserved: HSTRING_HEADER_Reserved, +}} +DECLARE_HANDLE!{HSTRING_BUFFER, HSTRING_BUFFER__} diff --git a/winapi/src/winrt/inspectable.rs b/winapi/src/winrt/inspectable.rs new file mode 100644 index 000000000..fb1e43315 --- /dev/null +++ b/winapi/src/winrt/inspectable.rs @@ -0,0 +1,29 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::guiddef::IID; +use shared::minwindef::ULONG; +use um::unknwnbase::{IUnknown, IUnknownVtbl}; +use um::winnt::HRESULT; +use winrt::hstring::HSTRING; +pub type LPINSPECTABLE = *mut IInspectable; +ENUM!{enum TrustLevel { + BaseTrust = 0, + PartialTrust, + FullTrust, +}} +RIDL!{#[uuid(0xaf86e2e0, 0xb12d, 0x4c6a, 0x9c, 0x5a, 0xd7, 0xaa, 0x65, 0x10, 0x1e, 0x90)] +interface IInspectable(IInspectableVtbl): IUnknown(IUnknownVtbl) { + fn GetIids( + iidCount: *mut ULONG, + iids: *mut *mut IID, + ) -> HRESULT, + fn GetRuntimeClassName( + className: *mut HSTRING, + ) -> HRESULT, + fn GetTrustLevel( + trustLevel: *mut TrustLevel, + ) -> HRESULT, +}} diff --git a/winapi/src/winrt/mod.rs b/winapi/src/winrt/mod.rs new file mode 100644 index 000000000..47e38676f --- /dev/null +++ b/winapi/src/winrt/mod.rs @@ -0,0 +1,12 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +#[cfg(feature = "activation")] pub mod activation; +#[cfg(feature = "hstring")] pub mod hstring; +#[cfg(feature = "inspectable")] pub mod inspectable; +#[cfg(feature = "roapi")] pub mod roapi; +#[cfg(feature = "robuffer")] pub mod robuffer; +#[cfg(feature = "roerrorapi")] pub mod roerrorapi; +#[cfg(feature = "winstring")] pub mod winstring; diff --git a/winapi/src/winrt/roapi.rs b/winapi/src/winrt/roapi.rs new file mode 100644 index 000000000..47b988062 --- /dev/null +++ b/winapi/src/winrt/roapi.rs @@ -0,0 +1,60 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{UINT32, UINT64}; +use shared::guiddef::REFIID; +use um::objidl::IApartmentShutdown; +use um::winnt::{HRESULT, VOID}; +use winrt::activation::IActivationFactory; +use winrt::hstring::HSTRING; +use winrt::inspectable::IInspectable; +ENUM!{enum RO_INIT_TYPE { + RO_INIT_SINGLETHREADED = 0, + RO_INIT_MULTITHREADED = 1, +}} +pub enum RO_REGISTRATION_COOKIE__ {} +pub type RO_REGISTRATION_COOKIE = *mut RO_REGISTRATION_COOKIE__; +FN!{stdcall PFNGETACTIVATIONFACTORY( + HSTRING, + *mut *mut IActivationFactory, +) -> HRESULT} +extern "system" { + pub fn RoInitialize( + initType: RO_INIT_TYPE, + ) -> HRESULT; + pub fn RoUninitialize(); + pub fn RoActivateInstance( + activatableClassId: HSTRING, + instance: *mut *mut IInspectable, + ) -> HRESULT; + pub fn RoRegisterActivationFactories( + activatableClassIds: *const HSTRING, + activationFactoryCallbacks: *const PFNGETACTIVATIONFACTORY, + count: UINT32, + cookie: *mut RO_REGISTRATION_COOKIE, + ) -> HRESULT; + pub fn RoRevokeActivationFactories( + cookie: RO_REGISTRATION_COOKIE, + ); + pub fn RoGetActivationFactory( + activatableClassId: HSTRING, + iid: REFIID, + factory: *mut *mut VOID, + ) -> HRESULT; +} +DECLARE_HANDLE!{APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, APARTMENT_SHUTDOWN_REGISTRATION_COOKIE__} +extern "system" { + pub fn RoRegisterForApartmentShutdown( + callbackObject: *const IApartmentShutdown, + apartmentIdentifier: *mut UINT64, + regCookie: *mut APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, + ) -> HRESULT; + pub fn RoUnregisterForApartmentShutdown( + regCookie: APARTMENT_SHUTDOWN_REGISTRATION_COOKIE, + ) -> HRESULT; + pub fn RoGetApartmentIdentifier( + apartmentIdentifier: *mut UINT64, + ) -> HRESULT; +} diff --git a/winapi/src/winrt/robuffer.rs b/winapi/src/winrt/robuffer.rs new file mode 100644 index 000000000..b0192fbe2 --- /dev/null +++ b/winapi/src/winrt/robuffer.rs @@ -0,0 +1,12 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use um::objidl::IMarshal; +use um::winnt::HRESULT; +extern "system" { + pub fn RoGetBufferMarshaler( + bufferMarshaler: *mut *mut IMarshal, + ) -> HRESULT; +} diff --git a/winapi/src/winrt/roerrorapi.rs b/winapi/src/winrt/roerrorapi.rs new file mode 100644 index 000000000..aa9f683a5 --- /dev/null +++ b/winapi/src/winrt/roerrorapi.rs @@ -0,0 +1,103 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{UINT32, UINT_PTR}; +use shared::minwindef::{BOOL, BYTE, UINT, USHORT}; +use um::restrictederrorinfo::IRestrictedErrorInfo; +use um::unknwnbase::IUnknown; +use um::winnt::{HRESULT, PCWSTR, PVOID, VOID}; +use winrt::hstring::HSTRING; +ENUM!{enum RO_ERROR_REPORTING_FLAGS { + RO_ERROR_REPORTING_NONE = 0x00000000, + RO_ERROR_REPORTING_SUPPRESSEXCEPTIONS = 0x00000001, + RO_ERROR_REPORTING_FORCEEXCEPTIONS = 0x00000002, + RO_ERROR_REPORTING_USESETERRORINFO = 0x00000004, + RO_ERROR_REPORTING_SUPPRESSSETERRORINFO = 0x00000008, +}} +extern "system" { + pub fn RoGetErrorReportingFlags( + pflags: *mut UINT32, + ) -> HRESULT; + pub fn RoSetErrorReportingFlags( + flags: UINT32, + ) -> HRESULT; + pub fn RoResolveRestrictedErrorInfoReference( + reference: PCWSTR, + ppRestrictedErrorInfo: *mut *mut IRestrictedErrorInfo , + ) -> HRESULT; + pub fn SetRestrictedErrorInfo( + pRestrictedErrorInfo: *const IRestrictedErrorInfo, + ) -> HRESULT; + pub fn GetRestrictedErrorInfo( + ppRestrictedErrorInfo: *mut *mut IRestrictedErrorInfo, + ) -> HRESULT; + pub fn RoOriginateErrorW( + error: HRESULT, + cchMax: UINT, + message: PCWSTR, + ) -> BOOL; + pub fn RoOriginateError( + error: HRESULT, + message: HSTRING, + ) -> BOOL; + pub fn RoTransformErrorW( + oldError: HRESULT, + newError: HRESULT, + cchMax: UINT, + message: PCWSTR, + ) -> BOOL; + pub fn RoTransformError( + oldError: HRESULT, + newError: HRESULT, + message: HSTRING, + ) -> BOOL; + pub fn RoCaptureErrorContext( + hr: HRESULT, + ) -> HRESULT; + pub fn RoFailFastWithErrorContext( + hrError: HRESULT, + ); + pub fn RoOriginateLanguageException( + error: HRESULT, + message: HSTRING, + languageException: *const IUnknown, + ) -> BOOL; + pub fn RoClearError(); + pub fn RoReportUnhandledError( + pRestrictedErrorInfo: *const IRestrictedErrorInfo, + ) -> HRESULT; +} +FN!{stdcall PINSPECT_MEMORY_CALLBACK( + *const VOID, + UINT_PTR, + UINT32, + *mut BYTE, +) -> HRESULT} +extern "system" { + pub fn RoInspectThreadErrorInfo( + targetTebAddress: UINT_PTR, + machine: USHORT, + readMemoryCallback: PINSPECT_MEMORY_CALLBACK, + context: PVOID, + targetErrorInfoAddress: *mut UINT_PTR, + ) -> HRESULT; + pub fn RoInspectCapturedStackBackTrace( + targetErrorInfoAddress: UINT_PTR, + machine: USHORT, + readMemoryCallback: PINSPECT_MEMORY_CALLBACK, + context: PVOID, + frameCount: *mut UINT32, + targetBackTraceAddress: *mut UINT_PTR, + ) -> HRESULT; + pub fn RoGetMatchingRestrictedErrorInfo( + hrIn: HRESULT, + ppRestrictedErrorInfo: *mut *mut IRestrictedErrorInfo, + ) -> HRESULT; + pub fn RoReportFailedDelegate( + punkDelegate: *const IUnknown, + pRestrictedErrorInfo: *const IRestrictedErrorInfo, + ) -> HRESULT; + pub fn IsErrorPropagationEnabled() -> BOOL; +} diff --git a/winapi/src/winrt/winstring.rs b/winapi/src/winrt/winstring.rs new file mode 100644 index 000000000..ecbfcdf2a --- /dev/null +++ b/winapi/src/winrt/winstring.rs @@ -0,0 +1,150 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. +use shared::basetsd::{INT32, UINT32, UINT_PTR}; +use shared::minwindef::{BOOL, BYTE, UCHAR, ULONG, USHORT}; +use um::winnt::{HRESULT, PCWSTR, VOID, WCHAR}; +use winrt::hstring::{HSTRING, HSTRING_BUFFER, HSTRING_HEADER}; +extern "system" { + pub fn WindowsCreateString( + sourceString: PCWSTR, + length: UINT32, + string: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsCreateStringReference( + sourceString: PCWSTR, + length: UINT32, + hstringHeader: *mut HSTRING_HEADER, + string: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsDeleteString( + string: HSTRING, + ) -> HRESULT; + pub fn WindowsDuplicateString( + string: HSTRING, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsGetStringLen( + string: HSTRING, + ) -> UINT32; + pub fn WindowsGetStringRawBuffer( + string: HSTRING, + length: *mut UINT32, + ) -> PCWSTR; + pub fn WindowsIsStringEmpty( + string: HSTRING, + ) -> BOOL; + pub fn WindowsStringHasEmbeddedNull( + string: HSTRING, + hasEmbedNull: *mut BOOL, + ) -> HRESULT; + pub fn WindowsCompareStringOrdinal( + string1: HSTRING, + string2: HSTRING, + result: *mut INT32, + ) -> HRESULT; + pub fn WindowsSubstring( + string: HSTRING, + startIndex: UINT32, + newString: *mut HSTRING, + ) -> HSTRING; + pub fn WindowsSubstringWithSpecifiedLength( + string: HSTRING, + startIndex: UINT32, + length: UINT32, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsConcatString( + string1: HSTRING, + string2: HSTRING, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsReplaceString( + string: HSTRING, + stringReplaced: HSTRING, + stringReplaceWith: HSTRING, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsTrimStringStart( + string: HSTRING, + trimString: HSTRING, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsTrimStringEnd( + string: HSTRING, + trimString: HSTRING, + newString: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsPreallocateStringBuffer( + length: UINT32, + charBuffer: *mut *mut WCHAR, + bufferHandle: *mut HSTRING_BUFFER, + ) -> HRESULT; + pub fn WindowsPromoteStringBuffer( + bufferHandle: HSTRING_BUFFER, + string: *mut HSTRING, + ) -> HRESULT; + pub fn WindowsDeleteStringBuffer( + bufferHandle: HSTRING_BUFFER, + ) -> HRESULT; +} +FN!{stdcall PINSPECT_HSTRING_CALLBACK( + *const VOID, + UINT_PTR, + UINT32, + *mut BYTE, +) -> HRESULT} +extern "system" { + pub fn WindowsInspectString( + targetHString: UINT_PTR, + machine: USHORT, + callback: PINSPECT_HSTRING_CALLBACK, + context: *const VOID, + length: *mut UINT32, + targetStringAddress: *mut UINT_PTR, + ) -> HRESULT; + pub fn HSTRING_UserSize( + pFlags: *const ULONG, + StartingSize: ULONG, + ppidl: *const HSTRING, + ) -> ULONG; + pub fn HSTRING_UserMarshal( + pFlags: *const ULONG, + pBuffer: *mut UCHAR, + ppidl: *const HSTRING, + ) -> *mut UCHAR; + pub fn HSTRING_UserUnmarshal( + pFlags: *const ULONG, + pBuffer: *const UCHAR, + ppidl: *mut HSTRING, + ) -> *mut UCHAR; + pub fn HSTRING_UserFree( + pFlags: *const ULONG, + ppidl: *const HSTRING, + ); + #[cfg(target_arch = "x86_64")] + pub fn HSTRING_UserSize64( + pFlags: *const ULONG, + StartingSize: ULONG, + ppidl: *const HSTRING, + ) -> ULONG; + #[cfg(target_arch = "x86_64")] + pub fn HSTRING_UserMarshal64( + pFlags: *const ULONG, + pBuffer: *mut UCHAR, + ppidl: *const HSTRING, + ) -> *mut UCHAR; + #[cfg(target_arch = "x86_64")] + pub fn HSTRING_UserUnmarshal64( + pFlags: *const ULONG, + pBuffer: *const UCHAR, + ppidl: *mut HSTRING, + ) -> *mut UCHAR; + #[cfg(target_arch = "x86_64")] + pub fn HSTRING_UserFree64( + pFlags: *const ULONG, + ppidl: *const HSTRING, + ); +} diff --git a/wincolor/.cargo-checksum.json b/wincolor/.cargo-checksum.json new file mode 100644 index 000000000..fc9fc4222 --- /dev/null +++ b/wincolor/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"} \ No newline at end of file diff --git a/wincolor/COPYING b/wincolor/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/wincolor/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/wincolor/Cargo.toml b/wincolor/Cargo.toml new file mode 100644 index 000000000..b1ab58fea --- /dev/null +++ b/wincolor/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "wincolor" +version = "1.0.1" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +description = "A simple Windows specific API for controlling text color in a Windows console.\n" +homepage = "https://github.com/BurntSushi/termcolor/tree/master/wincolor" +documentation = "https://docs.rs/wincolor" +readme = "README.md" +keywords = ["windows", "win", "color", "ansi", "console"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/termcolor/tree/master/wincolor" + +[lib] +name = "wincolor" +bench = false +[dependencies.winapi] +version = "0.3" +features = ["minwindef", "wincon"] + +[dependencies.winapi-util] +version = "0.1.1" diff --git a/wincolor/LICENSE-MIT b/wincolor/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/wincolor/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wincolor/README.md b/wincolor/README.md new file mode 100644 index 000000000..cc780340e --- /dev/null +++ b/wincolor/README.md @@ -0,0 +1,44 @@ +wincolor +======== +A simple Windows specific API for controlling text color in a Windows console. +The purpose of this crate is to expose the full inflexibility of the Windows +console without any platform independent abstraction. + +[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) +[![](https://img.shields.io/crates/v/wincolor.svg)](https://crates.io/crates/wincolor) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + +### Documentation + +[https://docs.rs/wincolor](https://docs.rs/wincolor) + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +wincolor = "0.1" +``` + +and this to your crate root: + +```rust +extern crate wincolor; +``` + +### Example + +This is a simple example that shows how to write text with a foreground color +of cyan and the intense attribute set: + +```rust +use wincolor::{Console, Color, Intense}; + +let mut con = Console::stdout().unwrap(); +con.fg(Intense::Yes, Color::Cyan).unwrap(); +println!("This text will be intense cyan."); +con.reset().unwrap(); +println!("This text will be normal."); +``` diff --git a/wincolor/UNLICENSE b/wincolor/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/wincolor/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/wincolor/src/lib.rs b/wincolor/src/lib.rs new file mode 100644 index 000000000..58dbbb6ef --- /dev/null +++ b/wincolor/src/lib.rs @@ -0,0 +1,35 @@ +/*! +This crate provides a safe and simple Windows specific API to control +text attributes in the Windows console. Text attributes are limited to +foreground/background colors, as well as whether to make colors intense or not. + +Note that on non-Windows platforms, this crate is empty but will compile. + +# Example + +```no_run +# #[cfg(windows)] +# { +use wincolor::{Console, Color, Intense}; + +let mut con = Console::stdout().unwrap(); +con.fg(Intense::Yes, Color::Cyan).unwrap(); +println!("This text will be intense cyan."); +con.reset().unwrap(); +println!("This text will be normal."); +# } +``` +*/ + +#![deny(missing_docs)] + +#[cfg(windows)] +extern crate winapi; +#[cfg(windows)] +extern crate winapi_util; + +#[cfg(windows)] +pub use win::*; + +#[cfg(windows)] +mod win; diff --git a/wincolor/src/win.rs b/wincolor/src/win.rs new file mode 100644 index 000000000..2115d1275 --- /dev/null +++ b/wincolor/src/win.rs @@ -0,0 +1,261 @@ +use std::io; + +use winapi::shared::minwindef::{WORD}; +use winapi::um::wincon::{ + self, + FOREGROUND_BLUE as FG_BLUE, + FOREGROUND_GREEN as FG_GREEN, + FOREGROUND_RED as FG_RED, + FOREGROUND_INTENSITY as FG_INTENSITY, +}; +use winapi_util as winutil; + +const FG_CYAN: WORD = FG_BLUE | FG_GREEN; +const FG_MAGENTA: WORD = FG_BLUE | FG_RED; +const FG_YELLOW: WORD = FG_GREEN | FG_RED; +const FG_WHITE: WORD = FG_BLUE | FG_GREEN | FG_RED; + +/// A Windows console. +/// +/// This represents a very limited set of functionality available to a Windows +/// console. In particular, it can only change text attributes such as color +/// and intensity. +/// +/// There is no way to "write" to this console. Simply write to +/// stdout or stderr instead, while interleaving instructions to the console +/// to change text attributes. +/// +/// A common pitfall when using a console is to forget to flush writes to +/// stdout before setting new text attributes. +#[derive(Debug)] +pub struct Console { + kind: HandleKind, + start_attr: TextAttributes, + cur_attr: TextAttributes, +} + +#[derive(Clone, Copy, Debug)] +enum HandleKind { + Stdout, + Stderr, +} + +impl HandleKind { + fn handle(&self) -> winutil::HandleRef { + match *self { + HandleKind::Stdout => winutil::HandleRef::stdout(), + HandleKind::Stderr => winutil::HandleRef::stderr(), + } + } +} + +impl Console { + /// Get a console for a standard I/O stream. + fn create_for_stream(kind: HandleKind) -> io::Result<Console> { + let h = kind.handle(); + let info = winutil::console::screen_buffer_info(&h)?; + let attr = TextAttributes::from_word(info.attributes()); + Ok(Console { + kind: kind, + start_attr: attr, + cur_attr: attr, + }) + } + + /// Create a new Console to stdout. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stdout() -> io::Result<Console> { + Self::create_for_stream(HandleKind::Stdout) + } + + /// Create a new Console to stderr. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stderr() -> io::Result<Console> { + Self::create_for_stream(HandleKind::Stderr) + } + + /// Applies the current text attributes. + fn set(&mut self) -> io::Result<()> { + winutil::console::set_text_attributes( + self.kind.handle(), + self.cur_attr.to_word(), + ) + } + + /// Apply the given intensity and color attributes to the console + /// foreground. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.fg_color = color; + self.cur_attr.fg_intense = intense; + self.set() + } + + /// Apply the given intensity and color attributes to the console + /// background. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.bg_color = color; + self.cur_attr.bg_intense = intense; + self.set() + } + + /// Reset the console text attributes to their original settings. + /// + /// The original settings correspond to the text attributes on the console + /// when this `Console` value was created. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn reset(&mut self) -> io::Result<()> { + self.cur_attr = self.start_attr; + self.set() + } + + /// Toggle virtual terminal processing. + /// + /// This method attempts to toggle virtual terminal processing for this + /// console. If there was a problem toggling it, then an error returned. + /// On success, the caller may assume that toggling it was successful. + /// + /// When virtual terminal processing is enabled, characters emitted to the + /// console are parsed for VT100 and similar control character sequences + /// that control color and other similar operations. + pub fn set_virtual_terminal_processing( + &mut self, + yes: bool, + ) -> io::Result<()> { + let vt = wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + let handle = self.kind.handle(); + let old_mode = winutil::console::mode(&handle)?; + let new_mode = + if yes { + old_mode | vt + } else { + old_mode & !vt + }; + if old_mode == new_mode { + return Ok(()); + } + winutil::console::set_mode(&handle, new_mode) + } +} + +/// A representation of text attributes for the Windows console. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct TextAttributes { + fg_color: Color, + fg_intense: Intense, + bg_color: Color, + bg_intense: Intense, +} + +impl TextAttributes { + fn to_word(&self) -> WORD { + let mut w = 0; + w |= self.fg_color.to_fg(); + w |= self.fg_intense.to_fg(); + w |= self.bg_color.to_bg(); + w |= self.bg_intense.to_bg(); + w + } + + fn from_word(word: WORD) -> TextAttributes { + TextAttributes { + fg_color: Color::from_fg(word), + fg_intense: Intense::from_fg(word), + bg_color: Color::from_bg(word), + bg_intense: Intense::from_bg(word), + } + } +} + +/// Whether to use intense colors or not. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Intense { + Yes, + No, +} + +impl Intense { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Intense { + Intense::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Intense::No => 0, + Intense::Yes => FG_INTENSITY, + } + } + + fn from_fg(word: WORD) -> Intense { + if word & FG_INTENSITY > 0 { + Intense::Yes + } else { + Intense::No + } + } +} + +/// The set of available colors for use with a Windows console. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Color { + Black, + Blue, + Green, + Red, + Cyan, + Magenta, + Yellow, + White, +} + +impl Color { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Color { + Color::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Color::Black => 0, + Color::Blue => FG_BLUE, + Color::Green => FG_GREEN, + Color::Red => FG_RED, + Color::Cyan => FG_CYAN, + Color::Magenta => FG_MAGENTA, + Color::Yellow => FG_YELLOW, + Color::White => FG_WHITE, + } + } + + fn from_fg(word: WORD) -> Color { + match word & 0b111 { + FG_BLUE => Color::Blue, + FG_GREEN => Color::Green, + FG_RED => Color::Red, + FG_CYAN => Color::Cyan, + FG_MAGENTA => Color::Magenta, + FG_YELLOW => Color::Yellow, + FG_WHITE => Color::White, + _ => Color::Black, + } + } +} -- 2.30.2